diff --git a/application/controllers/ConfigController.php b/application/controllers/ConfigController.php index 39051011c..559d8f3f9 100644 --- a/application/controllers/ConfigController.php +++ b/application/controllers/ConfigController.php @@ -46,7 +46,7 @@ class ConfigController extends ActionController public function indexAction() { $form = new GeneralConfigForm(); - $form->setConfig(IcingaConfig::app()); + $form->setIniConfig(IcingaConfig::app()); $form->handleRequest(); $this->view->form = $form; @@ -131,7 +131,7 @@ class ConfigController extends ActionController public function authenticationAction() { $form = new AuthenticationBackendReorderForm(); - $form->setConfig(IcingaConfig::app('authentication')); + $form->setIniConfig(IcingaConfig::app('authentication')); $form->handleRequest(); $this->view->form = $form; @@ -145,7 +145,7 @@ class ConfigController extends ActionController public function createauthenticationbackendAction() { $form = new AuthenticationBackendConfigForm(); - $form->setConfig(IcingaConfig::app('authentication')); + $form->setIniConfig(IcingaConfig::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->setConfig(IcingaConfig::app('authentication')); + $form->setIniConfig(IcingaConfig::app('authentication')); $form->setResourceConfig(ResourceFactory::getResourceConfigs()); $form->setRedirectUrl('config/authentication'); $form->handleRequest(); @@ -179,7 +179,7 @@ class ConfigController extends ActionController $form = new ConfirmRemovalForm(array( 'onSuccess' => function ($request) { $configForm = new AuthenticationBackendConfigForm(); - $configForm->setConfig(IcingaConfig::app('authentication')); + $configForm->setIniConfig(IcingaConfig::app('authentication')); $authBackend = $request->getQuery('auth_backend'); try { @@ -222,7 +222,7 @@ class ConfigController extends ActionController public function createresourceAction() { $form = new ResourceConfigForm(); - $form->setConfig(IcingaConfig::app('resources')); + $form->setIniConfig(IcingaConfig::app('resources')); $form->setRedirectUrl('config/resource'); $form->handleRequest(); @@ -236,7 +236,7 @@ class ConfigController extends ActionController public function editresourceAction() { $form = new ResourceConfigForm(); - $form->setConfig(IcingaConfig::app('resources')); + $form->setIniConfig(IcingaConfig::app('resources')); $form->setRedirectUrl('config/resource'); $form->handleRequest(); @@ -252,7 +252,7 @@ class ConfigController extends ActionController $form = new ConfirmRemovalForm(array( 'onSuccess' => function ($request) { $configForm = new ResourceConfigForm(); - $configForm->setConfig(IcingaConfig::app('resources')); + $configForm->setIniConfig(IcingaConfig::app('resources')); $resource = $request->getQuery('resource'); try { diff --git a/application/controllers/DashboardController.php b/application/controllers/DashboardController.php index e8629f865..4942f5cdb 100644 --- a/application/controllers/DashboardController.php +++ b/application/controllers/DashboardController.php @@ -96,7 +96,7 @@ class DashboardController extends ActionController if ($this->writeConfiguration(new Zend_Config($dashboard->toArray()), $configFile)) { $this->redirectNow(Url::fromPath('dashboard', array('pane' => $form->getValue('pane')))); } else { - $this->render('show-configuration'); + $this->render('showConfiguration'); return; } } @@ -164,9 +164,9 @@ class DashboardController extends ActionController $writer->write(); } catch (Exception $e) { Logger::error(new ConfiguationError("Cannot write dashboard to $target", 0, $e)); - $this->view->iniConfigurationString = $writer->render(); - $this->view->exceptionMessage = $e->getMessage(); - $this->view->file = $target; + $this->view->configString = $writer->render(); + $this->view->errorMessage = $e->getMessage(); + $this->view->filePath = $target; return false; } diff --git a/application/controllers/LayoutController.php b/application/controllers/LayoutController.php index 6c1355fc1..b2a260884 100644 --- a/application/controllers/LayoutController.php +++ b/application/controllers/LayoutController.php @@ -18,10 +18,12 @@ class LayoutController extends ActionController */ public function menuAction() { + $this->setAutorefreshInterval(15); $this->_helper->layout()->disableLayout(); - $this->view->menuRenderer = new MenuRenderer( - Menu::load(), Url::fromRequest()->without('renderLayout')->getRelativeUrl() - ); + + $url = Url::fromRequest(); + $menu = new MenuRenderer(Menu::load(), $url->getRelativeUrl()); + $this->view->menuRenderer = $menu->useCustomRenderer(); } /** diff --git a/application/controllers/PreferenceController.php b/application/controllers/PreferenceController.php index 0eb45dca0..bd76b2466 100644 --- a/application/controllers/PreferenceController.php +++ b/application/controllers/PreferenceController.php @@ -3,10 +3,12 @@ // {{{ICINGA_LICENSE_HEADER}}} use Icinga\Web\Controller\BasePreferenceController; -use Icinga\Web\Widget\Tab; use Icinga\Web\Url; -use Icinga\Form\Preference\GeneralForm; -use Icinga\Web\Notification; +use Icinga\Web\Widget\Tab; +use Icinga\Application\Config; +use Icinga\Form\PreferenceForm; +use Icinga\Exception\ConfigurationError; +use Icinga\User\Preferences\PreferencesStore; /** * Application wide preference controller for user preferences @@ -33,33 +35,22 @@ class PreferenceController extends BasePreferenceController } /** - * General settings for date and time + * Show form to adjust user preferences */ public function indexAction() { - $this->getTabs()->activate('general'); - - $form = new GeneralForm(); - $request = $this->getRequest(); - if ($request->isPost()) { - if ($form->isValid($request->getPost())) { - try { - $this->savePreferences($form->getPreferences()->toArray()); - Notification::success($this->translate('Preferences updated successfully')); - $this->redirectNow('preference'); - } catch (Exception $e) { - Notification::error( - sprintf( - $this->translate('Failed to persist preferences. (%s)'), - $e->getMessage() - ) - ); - } - } - } else { - $form->setPreferences($request->getUser()->getPreferences()); + $storeConfig = Config::app()->preferences; + if ($storeConfig === null) { + throw new ConfigurationError(t('You need to configure how to store preferences first.')); } + $user = $this->getRequest()->getUser(); + $form = new PreferenceForm(); + $form->setPreferences($user->getPreferences()); + $form->setStore(PreferencesStore::create($storeConfig, $user)); + $form->handleRequest(); + $this->view->form = $form; + $this->getTabs()->activate('general'); } } diff --git a/application/controllers/StaticController.php b/application/controllers/StaticController.php index fec60a624..c8b1d9b73 100644 --- a/application/controllers/StaticController.php +++ b/application/controllers/StaticController.php @@ -59,13 +59,12 @@ class StaticController extends ActionController public function imgAction() { $module = $this->_getParam('module_name'); - // TODO: This is more than dangerous, must be fixed!! $file = $this->_getParam('file'); - $basedir = Icinga::app()->getModuleManager()->getModule($module)->getBaseDir(); - $filePath = $basedir . '/public/img/' . $file; - if (! file_exists($filePath)) { + $filePath = realpath($basedir . '/public/img/' . $file); + + if (! $filePath || strpos($filePath, $basedir) !== 0) { throw new ActionException(sprintf( '%s does not exist', $filePath diff --git a/application/forms/Authentication/LoginForm.php b/application/forms/Authentication/LoginForm.php index 0d9b8dedc..d878475f2 100644 --- a/application/forms/Authentication/LoginForm.php +++ b/application/forms/Authentication/LoginForm.php @@ -53,7 +53,5 @@ class LoginForm extends Form 'value' => Url::fromRequest()->getParam('redirect') ) ); - - return $this; } } diff --git a/application/forms/Config/Authentication/LdapBackendForm.php b/application/forms/Config/Authentication/LdapBackendForm.php index 9db773708..6056b0911 100644 --- a/application/forms/Config/Authentication/LdapBackendForm.php +++ b/application/forms/Config/Authentication/LdapBackendForm.php @@ -6,6 +6,7 @@ namespace Icinga\Form\Config\Authentication; use Exception; use Icinga\Web\Form; +use Icinga\Web\Request; use Icinga\Data\ResourceFactory; use Icinga\Authentication\Backend\LdapUserBackend; diff --git a/application/forms/Config/AuthenticationBackendConfigForm.php b/application/forms/Config/AuthenticationBackendConfigForm.php index 9068ed25a..e81382cd4 100644 --- a/application/forms/Config/AuthenticationBackendConfigForm.php +++ b/application/forms/Config/AuthenticationBackendConfigForm.php @@ -318,7 +318,5 @@ class AuthenticationBackendConfigForm extends ConfigForm } $this->addElements($this->getBackendForm($backendType)->createElements($formData)->getElements()); - - return $this; } } diff --git a/application/forms/Config/AuthenticationBackendReorderForm.php b/application/forms/Config/AuthenticationBackendReorderForm.php index d4be16c30..3b5e70866 100644 --- a/application/forms/Config/AuthenticationBackendReorderForm.php +++ b/application/forms/Config/AuthenticationBackendReorderForm.php @@ -62,7 +62,7 @@ class AuthenticationBackendReorderForm extends ConfigForm protected function getConfigForm() { $form = new AuthenticationBackendConfigForm(); - $form->setConfig($this->config); + $form->setIniConfig($this->config); return $form; } } diff --git a/application/forms/Config/GeneralConfigForm.php b/application/forms/Config/GeneralConfigForm.php index ffb0a7d1c..550fe4cfb 100644 --- a/application/forms/Config/GeneralConfigForm.php +++ b/application/forms/Config/GeneralConfigForm.php @@ -33,8 +33,6 @@ class GeneralConfigForm extends ConfigForm $loggingConfigForm = new LoggingConfigForm(); $this->addElements($appConfigForm->createElements($formData)->getElements()); $this->addElements($loggingConfigForm->createElements($formData)->getElements()); - - return $this; } /** diff --git a/application/forms/Config/ResourceConfigForm.php b/application/forms/Config/ResourceConfigForm.php index d9ec4dad3..8e677cf8b 100644 --- a/application/forms/Config/ResourceConfigForm.php +++ b/application/forms/Config/ResourceConfigForm.php @@ -252,7 +252,5 @@ class ResourceConfigForm extends ConfigForm } $this->addElements($this->getResourceForm($resourceType)->createElements($formData)->getElements()); - - return $this; } } diff --git a/application/forms/ConfigForm.php b/application/forms/ConfigForm.php index 1f3692473..86790d618 100644 --- a/application/forms/ConfigForm.php +++ b/application/forms/ConfigForm.php @@ -28,7 +28,7 @@ class ConfigForm extends Form * * @return self */ - public function setConfig(Config $config) + public function setIniConfig(Config $config) { $this->config = $config; return $this; @@ -54,6 +54,7 @@ class ConfigForm extends Form $writer->write(); } catch (Exception $e) { $this->addDecorator('ViewScript', array( + 'viewModule' => 'default', 'viewScript' => 'showConfiguration.phtml', 'errorMessage' => $e->getMessage(), 'configString' => $writer->render(), diff --git a/application/forms/Dashboard/AddUrlForm.php b/application/forms/Dashboard/AddUrlForm.php index 67452a84f..88195654d 100644 --- a/application/forms/Dashboard/AddUrlForm.php +++ b/application/forms/Dashboard/AddUrlForm.php @@ -27,15 +27,13 @@ class AddUrlForm extends Form */ public function createElements(array $formData) { - $elements = array( - $this->createElement( - 'text', - 'url', - array( - 'required' => true, - 'label' => t('Url'), - 'helptext' => t('The url being loaded in the dashlet') - ) + $this->addElement( + 'text', + 'url', + array( + 'required' => true, + 'label' => t('Url'), + 'helptext' => t('The url being loaded in the dashlet') ) ); @@ -44,7 +42,7 @@ class AddUrlForm extends Form ((isset($formData['create_new_pane']) && $formData['create_new_pane'] != false) && (false === isset($formData['use_existing_dashboard']) || $formData['use_existing_dashboard'] != true)) ) { - $elements[] = $this->createElement( + $this->addElement( 'text', 'pane', array( @@ -53,7 +51,7 @@ class AddUrlForm extends Form 'style' => 'display: inline-block' ) ); - $elements[] = $this->createElement( // Prevent the button from being displayed again on validation errors + $this->addElement( // Prevent the button from being displayed again on validation errors 'hidden', 'create_new_pane', array( @@ -61,7 +59,7 @@ class AddUrlForm extends Form ) ); if (false === empty($paneSelectionValues)) { - $elements[] = $this->createElement( + $this->addElement( 'submit', 'use_existing_dashboard', array( @@ -72,7 +70,7 @@ class AddUrlForm extends Form ); } } else { - $elements[] = $this->createElement( + $this->addElement( 'select', 'pane', array( @@ -82,7 +80,7 @@ class AddUrlForm extends Form 'multiOptions' => $paneSelectionValues ) ); - $elements[] = $this->createElement( + $this->addElement( 'submit', 'create_new_pane', array( @@ -93,7 +91,7 @@ class AddUrlForm extends Form ); } - $elements[] = $this->createElement( + $this->addElement( 'text', 'component', array( @@ -102,7 +100,6 @@ class AddUrlForm extends Form 'helptext' => t('The title for the dashlet') ) ); - return $elements; } /** diff --git a/application/forms/Preference/GeneralForm.php b/application/forms/Preference/GeneralForm.php deleted file mode 100644 index b9ce5e9e2..000000000 --- a/application/forms/Preference/GeneralForm.php +++ /dev/null @@ -1,171 +0,0 @@ -setName('form_config_preferences'); - $this->setSubmitLabel(t('Save Changes')); - } - - /** - * Add a select field for setting the user's language - * - * Possible values are determined by Translator::getAvailableLocaleCodes. - * Also, a 'use browser language' checkbox is added in order to allow a user to discard his setting - * - * @param array $formData The data sent by the user - */ - protected function getLanguageElements(array $formData) - { - $languages = array(); - foreach (Translator::getAvailableLocaleCodes() as $language) { - $languages[$language] = $language; - } - - $useBrowserLanguage = isset($formData['browser_language']) ? $formData['browser_language'] == 1 : true; - $selectOptions = array( - 'label' => t('Your Current Language'), - 'required' => false === $useBrowserLanguage, - 'multiOptions' => $languages, - 'helptext' => t('Use the following language to display texts and messages'), - 'value' => substr(setlocale(LC_ALL, 0), 0, 5) - ); - if ($useBrowserLanguage) { - $selectOptions['disabled'] = 'disabled'; - } - - return array( - $this->createElement( - 'checkbox', - 'browser_language', - array( - 'required' => true, - 'class' => 'autosubmit', - 'label' => t('Use your browser\'s language suggestions'), - 'value' => $useBrowserLanguage - ) - ), - $this->createElement('select', 'language', $selectOptions) - ); - } - - /** - * Add a select field for setting the user's timezone - * - * Possible values are determined by DateTimeZone::listIdentifiers. - * Also, a 'use local timezone' checkbox is added in order to allow a user to discard his overwritten setting - * - * @param array $formData The data sent by the user - */ - protected function getTimezoneElements(array $formData) - { - $tzList = array(); - foreach (DateTimeZone::listIdentifiers() as $tz) { - $tzList[$tz] = $tz; - } - - $useLocalTimezone = isset($formData['local_timezone']) ? $formData['local_timezone'] == 1 : true; - $selectOptions = array( - 'label' => 'Your Current Timezone', - 'required' => false === $useLocalTimezone, - 'multiOptions' => $tzList, - 'helptext' => t('Use the following timezone for dates and times'), - 'value' => date_default_timezone_get() - ); - if ($useLocalTimezone) { - $selectOptions['disabled'] = 'disabled'; - } - - return array( - $this->createElement( - 'checkbox', - 'local_timezone', - array( - 'required' => true, - 'class' => 'autosubmit', - 'label' => t('Use your local timezone'), - 'value' => $useLocalTimezone, - ) - ), - $this->createElement('select', 'timezone', $selectOptions) - ); - } - - /** - * @see Form::createElements() - */ - public function createElements(array $formData) - { - $elements = array_merge($this->getLanguageElements($formData), $this->getTimezoneElements($formData)); - $elements[] = $this->createElement( - 'checkbox', - 'show_benchmark', - array( - 'label' => t('Use benchmark') - ) - ); - - return $elements; - } - - /** - * Populate the form with the given preferences - * - * @param Preferences $preferences The preferences to populate the form with - * - * @return self - */ - public function setPreferences(Preferences $preferences) - { - $defaults = array( - 'browser_language' => $preferences->get('app.language') === null, - 'local_timezone' => $preferences->get('app.timezone') === null - ); - - if ($preferences->get('app.language') !== null) { - $defaults['language'] = $preferences->get('app.language'); - } - if ($preferences->get('app.timezone') !== null) { - $defaults['timezone'] = $preferences->get('app.timezone'); - } - if ($preferences->get('app.show_benchmark')) { - $defaults['show_benchmark'] = $preferences->get('app.show_benchmark'); - } - - $this->setDefaults($defaults); - return $this; - } - - /** - * Return the configured preferences - * - * @return Preferences - */ - public function getPreferences() - { - $values = $this->getValues(); - return new Preferences( - array( - 'app.language' => $values['browser_language'] ? null : $values['language'], - 'app.timezone' => $values['local_timezone'] ? null : $values['timezone'], - 'app.show_benchmark' => $values['show_benchmark'] ? $values['show_benchmark'] : null - ) - ); - } -} diff --git a/application/forms/PreferenceForm.php b/application/forms/PreferenceForm.php new file mode 100644 index 000000000..cdb6ff288 --- /dev/null +++ b/application/forms/PreferenceForm.php @@ -0,0 +1,225 @@ +setName('form_config_preferences'); + $this->setSubmitLabel(t('Save Changes')); + } + + /** + * Set preferences to work with + * + * @param Preferences $preferences The preferences to work with + * + * @return self + */ + public function setPreferences(Preferences $preferences) + { + $this->preferences = $preferences; + return $this; + } + + /** + * Set the preference store to use + * + * @param PreferencesStore $store The preference store to use + * + * @return self + */ + public function setStore(PreferencesStore $store) + { + $this->store = $store; + } + + /** + * Persist preferences + * + * @return self + */ + public function save() + { + $this->store->load(); // Necessary for patching existing preferences + $this->store->save($this->preferences); + return $this; + } + + /** + * Adjust preferences and persist them + * + * @see Form::onSuccess() + */ + public function onSuccess(Request $request) + { + $webPreferences = $this->preferences->get('icingaweb', array()); + foreach ($this->getValues() as $key => $value) { + if ($value === null) { + if (isset($webPreferences[$key])) { + unset($webPreferences[$key]); + } + } else { + $webPreferences[$key] = $value; + } + } + $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(); + + try { + $this->save(); + Notification::success(t('Preferences successfully saved')); + } catch (Exception $e) { + Notification::error($e->getMessage()); + } + } + + /** + * Populate preferences + * + * @see Form::onRequest() + */ + public function onRequest(Request $request) + { + $values = $this->preferences->get('icingaweb', array()); + $values['browser_language'] = false === isset($values['language']); + $values['local_timezone'] = false === isset($values['timezone']); + $this->populate($values); + } + + /** + * @see Form::createElements() + */ + public function createElements(array $formData) + { + $languages = array(); + foreach (Translator::getAvailableLocaleCodes() as $language) { + $languages[$language] = $language; + } + + $tzList = array(); + 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, + '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, + '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', + 'show_benchmark', + array( + 'required' => true, + 'label' => t('Use benchmark') + ) + ); + } + + /** + * Return the current default timezone + * + * @return string + */ + protected function getDefaultTimezone() + { + $detect = new TimezoneDetect(); + if ($detect->success()) { + return $detect->getTimezoneName(); + } else { + return date_default_timezone_get(); + } + } +} diff --git a/application/layouts/scripts/parts/navigation.phtml b/application/layouts/scripts/parts/navigation.phtml index 5dedc75aa..da02a02de 100644 --- a/application/layouts/scripts/parts/navigation.phtml +++ b/application/layouts/scripts/parts/navigation.phtml @@ -11,11 +11,15 @@ if (! $this->auth()->isAuthenticated()) { } ?> - \ No newline at end of file diff --git a/doc/components.md b/doc/components.md deleted file mode 100644 index a46afc2eb..000000000 --- a/doc/components.md +++ /dev/null @@ -1,130 +0,0 @@ -# Frontend components - -Frontend components are JavaScript modules that can be required directly through the HTML markup of -your view, to provide additional functionality for the user. Although its best practice to -make all features available without JavaScript, these components can be used to provide a richer -and more comfortable user experience in case JavaScript is available. - -There is a certain set of frontend components which come directly with the Icinga2-Web core application, -but it is also possible to define new components directly in Icinga2-Web modules. - - -## How do components work? - -Components are defined in JavaScript files that provide a set of functionality that will be added to the -targeted HTML node. Icinga2-Web uses [RequireJS](http://requirejs.org) to load -all frontend components, so each frontend component is in fact -[defined exactly like a RequireJS-Module](http://requirejs.org/docs/api.html#define) . - -The important difference to plain RequireJS is, that the loading and execution of these components is -done automatically through the HTML markup. The attribute *data-icinga-component* in a DIV -element will indicate that this element is a container for a frontend component and will trigger -the component loader to create a component instance for this HTML node. The component loader -keeps track of all available components and makes it possible to retrieve this instance when needed. - - -### Component names - -A component name consists of two parts: the namespace and the name of the component itself. The component -is named exactly like its JavaScript file, while the namespace is the name of the Icinga2-Web module that contains -the component. Each Icinga2-Web module can contain its own components in the folder *public/js*. - - / - - -NOTE: The namespace used for modules defined in the Icinga2-Web core application is "app". In opposition to -the modules the core application keeps its modules located in *public/js/icinga/components* -instead of *public/js*. - - -#### Example Names - - -The full name for the component *modules/monitoring/public/js/someComponent.js* in the module "monitoring" would be: - - "monitoring/someComponent" - - -The full component name for the component *public/js/icinga/components/datetime.js* in the Icinga2-Web core application -would: - - "app/datetime" - - -## Creating a component - -As described in the chapters above, components are defined exactly like RequireJS modules, but -with the additional requirement that they must always return a class constructor. The component below will -search all date pickers, set the time format and create a JavaScript date picker when there is no native one -available. - - /** - * Ensures that our date/time controls will work on every browser (natively or javascript based) - */ - define(['jquery', 'datetimepicker'], function($) { - "use strict"; - - var DateTimePicker = function(target) { - $(target).find('.datetime input') - .attr('data-format', 'yyyy-MM-dd hh:mm:ss'); - - $(target).find('.datetime') - .addClass('input-append') - .append('' + - '') - .datetimepicker(); - }; - return DateTimePicker; - }); - - -## Loading a component - -The following code will load the module *datetime*, which will ensure that there is always a datetime-picker -with right time-format available. - -
- -
- -
- -
- - -### Component ids - -When an ID is assigned to the HTML element, it will be used by the component loader to reference this -component. Otherwise an ID in the form "icinga-component-<ID>" will be created and the ID attribute in the -HTML Element will be updated accordingly. - - -### Component "target" - -The div-element with the *data-icinga-component* will be used as the "target" for the loaded component, -which means that the component will perform its actions on this HTML node. - - - -# Retrieving a component - -Sometimes it can be necessary to retrieve the instances of the components itself, for example when they implement -additional functions that can be called. The component loader is available in the Icinga object and can be used -to retrieve component instances using their ID or their full component name. - - -## By component id - - var component = Icinga.components.getById("component-id"); - component.doSomething(); - - -## By full component name - - var components = Icinga.components.getByType("app/datetime"); - // ... do something with every component of the type app/datetime - -## All components - - var components = Icinga.components.getComponents(); - // ... do something with every component diff --git a/library/Icinga/Application/Modules/Module.php b/library/Icinga/Application/Modules/Module.php index c0c6b1f6f..6d66412e6 100644 --- a/library/Icinga/Application/Modules/Module.php +++ b/library/Icinga/Application/Modules/Module.php @@ -8,6 +8,7 @@ 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; @@ -821,12 +822,15 @@ class Module ); $router->addRoute( $this->name . '_img', - new Route( - 'img/' . $this->name . '/:file', + new RegexRoute( + 'img/' . $this->name . '/(.+)', array( 'controller' => 'static', 'action' => 'img', 'module_name' => $this->name + ), + array( + 1 => 'file' ) ) ); diff --git a/library/Icinga/Chart/Graph/Tooltip.php b/library/Icinga/Chart/Graph/Tooltip.php index b630c7c61..4457e04e2 100644 --- a/library/Icinga/Chart/Graph/Tooltip.php +++ b/library/Icinga/Chart/Graph/Tooltip.php @@ -67,7 +67,7 @@ class Tooltip */ public function __construct ( $data = array(), - $format = '{title}
{value} of {sum} {label}' + $format = '{title}
{value} of {sum} {label}' ) { $this->data = array_merge($this->data, $data); $this->defaultFormat = $format; diff --git a/library/Icinga/Test/BaseTestCase.php b/library/Icinga/Test/BaseTestCase.php index 9cc8ba519..a735550cb 100644 --- a/library/Icinga/Test/BaseTestCase.php +++ b/library/Icinga/Test/BaseTestCase.php @@ -25,20 +25,16 @@ namespace Icinga\Test { use RuntimeException; use Mockery; use Zend_Config; - use Zend_Controller_Request_Abstract; - use Zend_Controller_Request_HttpTestCase; use PHPUnit_Framework_TestCase; use Icinga\Application\Icinga; use Icinga\Util\DateTimeFactory; use Icinga\Data\ResourceFactory; use Icinga\Data\Db\DbConnection; - use Icinga\User\Preferences; - use Icinga\Web\Form; /** * Class BaseTestCase */ - class BaseTestCase extends PHPUnit_Framework_TestCase implements DbTest, FormTest + class BaseTestCase extends PHPUnit_Framework_TestCase implements DbTest { /** * Path to application/ @@ -82,13 +78,6 @@ namespace Icinga\Test { */ public static $moduleDir; - /** - * Store request for form tests - * - * @var Zend_Controller_Request_HttpTestCase - */ - private $request; - /** * Resource configuration for different database types * @@ -151,28 +140,54 @@ namespace Icinga\Test { public function setUp() { parent::setUp(); - - $requestMock = Mockery::mock('Icinga\Web\Request'); - $requestMock->shouldReceive('getPathInfo')->andReturn('') - ->shouldReceive('getBaseUrl')->andReturn('/') - ->shouldReceive('getQuery')->andReturn(array()); - $this->setupIcingaMock($requestMock); + $this->setupIcingaMock(); } /** * Setup mock object for the application's bootstrap * - * @param Zend_Controller_Request_Abstract $request The request to be returned by - * Icinga::app()->getFrontController()->getRequest() + * @return Mockery\Mock */ - protected function setupIcingaMock(Zend_Controller_Request_Abstract $request) + protected function setupIcingaMock() { + $requestMock = Mockery::mock('Icinga\Web\Request')->shouldDeferMissing(); + $requestMock->shouldReceive('getPathInfo')->andReturn('')->byDefault() + ->shouldReceive('getBaseUrl')->andReturn('/')->byDefault() + ->shouldReceive('getQuery')->andReturn(array())->byDefault() + ->shouldReceive('getParam')->with(Mockery::type('string'), Mockery::type('string')) + ->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(); - $bootstrapMock->shouldReceive('getFrontController->getRequest')->andReturnUsing( - function () use ($request) { return $request; } - )->shouldReceive('getApplicationDir')->andReturn(self::$appDir); + $bootstrapMock->shouldReceive('getFrontController')->andReturn($bootstrapMock) + ->shouldReceive('getApplicationDir')->andReturn(self::$appDir) + ->shouldReceive('getRequest')->andReturn($requestMock) + ->shouldReceive('getResponse')->andReturn($responseMock); Icinga::setApp($bootstrapMock, true); + return $bootstrapMock; + } + + /** + * Return the currently active request mock object + * + * @return Icinga\Web\Request + */ + public function getRequestMock() + { + return Icinga::app()->getFrontController()->getRequest(); + } + + /** + * Return the currently active response mock object + * + * @return Icinga\Web\Response + */ + public function getResponseMock() + { + return Icinga::app()->getFrontController()->getResponse(); } /** @@ -298,51 +313,6 @@ namespace Icinga\Test { $adapter->exec('DROP TABLE ' . $table . ';'); } } - - /** - * Instantiate a form - * - * If the form has CSRF protection enabled, creates the form's token element and adds the generated token to the - * request data - * - * @param string $formClass Qualified class name of the form to create. Note that the class has to be - * defined as no attempt is made to require the class before instantiating. - * @param array $requestData Request data for the form - * - * @return Form - * @throws RuntimeException - */ - public function createForm($formClass, array $requestData = array()) - { - $form = new $formClass; - $form->setTokenDisabled(); // Disable CSRF protection else all calls to isSubmittedAndValid will fail - $request = $this->getRequest(); - $request->setMethod('POST'); - $request->setPost($requestData); - $form->setRequest($request); - $form->setUserPreferences( - new Preferences( - array() - ) - ); - return $form; - } - - /** - * Retrieve test case request object - * - * This is a mock methods borrowed from Zend Controller Test Case to handle form tests properly (#6106) - * - * @return Zend_Controller_Request_HttpTestCase - */ - public function getRequest() - { - if (null === $this->request) { - require_once 'Zend/Controller/Request/HttpTestCase.php'; - $this->request = new Zend_Controller_Request_HttpTestCase; - } - return $this->request; - } } BaseTestCase::setupTimezone(); diff --git a/library/Icinga/Test/FormTest.php b/library/Icinga/Test/FormTest.php deleted file mode 100644 index e8b070483..000000000 --- a/library/Icinga/Test/FormTest.php +++ /dev/null @@ -1,23 +0,0 @@ -view->tabs = ControllerTabCollector::collectControllerTabs('PreferenceController'); } - - protected function savePreferences(array $preferences) - { - $session = Session::getSession(); - $currentPreferences = $session->user->getPreferences(); - foreach ($preferences as $key => $value) { - if ($value === null) { - $currentPreferences->remove($key); - } else { - $currentPreferences->{$key} = $value; - } - } - $session->write(); - - if (($preferencesConfig = IcingaConfig::app()->preferences) === null) { - throw new ConfigurationError( - 'Cannot save preferences changes since you\'ve not configured a preferences backend' - ); - } - $store = PreferencesStore::create($preferencesConfig, $session->user); - $store->load(); // Necessary for patching existing preferences - $store->save($currentPreferences); - } } diff --git a/library/Icinga/Web/Form.php b/library/Icinga/Web/Form.php index 13ed535e3..f0695242e 100644 --- a/library/Icinga/Web/Form.php +++ b/library/Icinga/Web/Form.php @@ -67,6 +67,13 @@ class Form extends Zend_Form */ protected $tokenElementName = 'CSRFToken'; + /** + * Whether this form should add a UID element being used to distinct different forms posting to the same action + * + * @var bool + */ + protected $uidDisabled = false; + /** * Name of the form identification element * @@ -155,8 +162,9 @@ class Form extends Zend_Form public function getRedirectUrl() { if ($this->redirectUrl === null) { + $url = Url::fromRequest(array(), $this->getRequest()); // Be sure to remove all form dependent params because we do not want to submit it again - $this->redirectUrl = Url::fromRequest()->without(array_keys($this->getElements())); + $this->redirectUrl = $url->without(array_keys($this->getElements())); } return $this->redirectUrl; @@ -236,6 +244,34 @@ class Form extends Zend_Form return $this->tokenElementName; } + /** + * Disable form identification and remove its field if already added + * + * @param bool $disabled Set true in order to disable identification for this form, otherwise false + * + * @return self + */ + public function setUidDisabled($disabled = true) + { + $this->uidDisabled = (bool) $disabled; + + if ($disabled && $this->getElement($this->uidElementName) !== null) { + $this->removeElement($this->uidElementName); + } + + return $this; + } + + /** + * Return whether identification is disabled for this form + * + * @return bool + */ + public function getUidDisabled() + { + return $this->uidDisabled; + } + /** * Set the name to use for the form identification element * @@ -269,15 +305,15 @@ class Form extends Zend_Form public function create(array $formData = array()) { if (false === $this->created) { - $this->createElements($formData) - ->addFormIdentification() + $this->createElements($formData); + $this->addFormIdentification() ->addCsrfCounterMeasure() ->addSubmitButton(); if ($this->getAction() === '') { // We MUST set an action as JS gets confused otherwise, if // this form is being displayed in an additional column - $this->setAction(Url::fromRequest()->getUrlWithout(array_keys($this->getElements()))); + $this->setAction(Url::fromRequest()->without(array_keys($this->getElements()))); } $this->created = true; @@ -292,12 +328,10 @@ class Form extends Zend_Form * Intended to be implemented by concrete form classes. * * @param array $formData The data sent by the user - * - * @return self */ public function createElements(array $formData) { - return $this; + } /** @@ -336,7 +370,7 @@ class Form extends Zend_Form */ public function addSubmitButton() { - if ($this->submitLabel !== null) { + if ($this->submitLabel) { $this->addElement( 'submit', 'btn_submit', @@ -354,6 +388,31 @@ class Form extends Zend_Form return $this; } + /** + * Add a subform + * + * @param Zend_Form $form The subform to add + * @param string $name The name of the subform or null to use the name of $form + * @param int $order The location where to insert the form + * + * @return Zend_Form + */ + public function addSubForm(Zend_Form $form, $name = null, $order = null) + { + if ($form instanceof self) { + $form->removeDecorator('Form'); + $form->setSubmitLabel(''); + $form->setTokenDisabled(); + $form->setUidDisabled(); + } + + if ($name === null) { + $name = $form->getName(); + } + + return parent::addSubForm($form, $name, $order); + } + /** * Create a new element * @@ -398,14 +457,17 @@ class Form extends Zend_Form */ public function addFormIdentification() { - $this->addElement( - 'hidden', - $this->uidElementName, - array( - 'ignore' => true, - 'value' => $this->getName() - ) - ); + if (false === $this->uidDisabled && $this->getElement($this->uidElementName) === null) { + $this->addElement( + 'hidden', + $this->uidElementName, + array( + 'ignore' => true, + 'value' => $this->getName(), + 'decorators' => array('ViewHelper') + ) + ); + } return $this; } @@ -431,7 +493,7 @@ class Form extends Zend_Form * * @param array $defaults The values to populate the elements with */ - public function setDefaults(array $defaults) + public function setDefaults($defaults) { $this->create($defaults); return parent::setDefaults($defaults); @@ -454,7 +516,7 @@ class Form extends Zend_Form } $formData = $this->getRequestData($request); - if ($this->wasSent($formData)) { + if ($this->getUidDisabled() || $this->wasSent($formData)) { $this->populate($formData); // Necessary to get isSubmitted() to work if (! $this->getSubmitLabel() || $this->isSubmitted()) { if ($this->isValid($formData) diff --git a/library/Icinga/Web/Menu/UnhandledHostMenuItemRenderer.php b/library/Icinga/Web/Menu/UnhandledHostMenuItemRenderer.php index b66709422..c7e6036fb 100644 --- a/library/Icinga/Web/Menu/UnhandledHostMenuItemRenderer.php +++ b/library/Icinga/Web/Menu/UnhandledHostMenuItemRenderer.php @@ -22,7 +22,8 @@ class UnhandledHostMenuItemRenderer implements MenuItemRenderer { $badge = ''; if ($statusSummary->hosts_down_unhandled) { $badge = sprintf( - '
%s
', + '
%s
', + t(sprintf('%d unhandled host problems', $statusSummary->hosts_down_unhandled)), $statusSummary->hosts_down_unhandled ); } diff --git a/library/Icinga/Web/Menu/UnhandledServiceMenuItemRenderer.php b/library/Icinga/Web/Menu/UnhandledServiceMenuItemRenderer.php index cdac34c04..b677a4935 100644 --- a/library/Icinga/Web/Menu/UnhandledServiceMenuItemRenderer.php +++ b/library/Icinga/Web/Menu/UnhandledServiceMenuItemRenderer.php @@ -22,7 +22,8 @@ class UnhandledServiceMenuItemRenderer implements MenuItemRenderer { $badge = ''; if ($statusSummary->services_critical_unhandled) { $badge = sprintf( - '
%s
', + '
%s
', + t(sprintf('%d unhandled service problems', $statusSummary->services_critical_unhandled)), $statusSummary->services_critical_unhandled ); } diff --git a/library/Icinga/Web/MenuRenderer.php b/library/Icinga/Web/MenuRenderer.php index 1bba54239..c026e5553 100644 --- a/library/Icinga/Web/MenuRenderer.php +++ b/library/Icinga/Web/MenuRenderer.php @@ -25,6 +25,11 @@ class MenuRenderer extends RecursiveIteratorIterator */ protected $tags = array(); + /** + * @var bool + */ + protected $useCustomRenderer = false; + /** * Create a new MenuRenderer * @@ -41,6 +46,15 @@ class MenuRenderer extends RecursiveIteratorIterator parent::__construct($menu, RecursiveIteratorIterator::CHILD_FIRST); } + /** + * @param bool $value + */ + public function useCustomRenderer($value = true) + { + $this->useCustomRenderer = $value; + return $this; + } + /** * Register the outer ul opening html-tag */ @@ -91,7 +105,7 @@ class MenuRenderer extends RecursiveIteratorIterator */ public function renderChild(Menu $child) { - if ($child->getRenderer() !== null) { + if ($child->getRenderer() !== null && $this->useCustomRenderer) { return $child->getRenderer()->render($child); } return sprintf( diff --git a/library/Icinga/Web/StyleSheet.php b/library/Icinga/Web/StyleSheet.php index 90fb314a8..3c4baf943 100644 --- a/library/Icinga/Web/StyleSheet.php +++ b/library/Icinga/Web/StyleSheet.php @@ -24,7 +24,6 @@ class StyleSheet 'css/icinga/monitoring-colors.less', 'css/icinga/selection-toolbar.less', 'css/icinga/login.less', - 'css/icinga/charts.less', 'css/vendor/tipsy.css' ); diff --git a/library/Icinga/Web/Widget/SortBox.php b/library/Icinga/Web/Widget/SortBox.php index 557469966..42e7110cc 100644 --- a/library/Icinga/Web/Widget/SortBox.php +++ b/library/Icinga/Web/Widget/SortBox.php @@ -119,15 +119,15 @@ class SortBox extends AbstractWidget 'label' => 'Sort By', 'multiOptions' => $this->sortFields, 'style' => 'width: 12em', - 'class' => 'autosubmit', + 'autosubmit' => true )); $form->addElement('select', 'dir', array( 'multiOptions' => array( 'asc' => 'Asc', 'desc' => 'Desc', ), - 'style' => 'width: 5em', - 'class' => 'autosubmit' + 'style' => 'width: 5em', + 'autosubmit' => true )); $sort = $form->getElement('sort')->setDecorators(array('ViewHelper')); $dir = $form->getElement('dir')->setDecorators(array('ViewHelper')); diff --git a/library/IcingaVendor/dompdf/lib/fonts/log.htm b/library/IcingaVendor/dompdf/lib/fonts/log.htm deleted file mode 100644 index b1c46f075..000000000 --- a/library/IcingaVendor/dompdf/lib/fonts/log.htm +++ /dev/null @@ -1,324 +0,0 @@ -1084 frames 64,000 KB 12,219.54 ms ON

- - - - - - - - - - - - - - - - - - - - - -
( ! ) Notice: Undefined offset: 1 in /vagrant/library/vendor/dompdf/include/table_frame_reflower.cls.php on line 396
Call Stack
#TimeMemoryFunctionLocation
10.0015634696{main}( )../index.php:0
20.66637155080Icinga\Application\Web->dispatch( )../index.php:17
30.66637155080Zend_Controller_Front->dispatch( )../Web.php:177
40.67187339544Zend_Controller_Dispatcher_Standard->dispatch( )../Front.php:954
50.75449789672Zend_Controller_Action->dispatch( )../Standard.php:308
60.854711070736Icinga\Web\Controller\ActionController->postDispatch( )../Action.php:521
70.855011071712Icinga\Web\Controller\ActionController->sendAsPdfAndDie( )../ActionController.php:244
81.993023228752Icinga\File\Pdf->renderPage( )../ActionController.php:279
92.066823495800DOMPDF->render( )../Pdf.php:62
109.090249430472Frame_Decorator->reflow( )../dompdf.cls.php:817
119.090249430520Page_Frame_Reflower->reflow( )../frame_decorator.cls.php:556
129.091049432912Frame_Decorator->reflow( )../page_frame_reflower.cls.php:138
139.091049432960Block_Frame_Reflower->reflow( )../frame_decorator.cls.php:556
149.096249449768Frame_Decorator->reflow( )../block_frame_reflower.cls.php:722
159.096249449768Block_Frame_Reflower->reflow( )../frame_decorator.cls.php:556
169.098749466560Frame_Decorator->reflow( )../block_frame_reflower.cls.php:722
179.098749466560Table_Frame_Reflower->reflow( )../frame_decorator.cls.php:556
-
- - - - - - - - - - - - - - - - - - - - - -
( ! ) Notice: Undefined offset: 1 in /vagrant/library/vendor/dompdf/include/table_frame_reflower.cls.php on line 396
Call Stack
#TimeMemoryFunctionLocation
10.0015634696{main}( )../index.php:0
20.66637155080Icinga\Application\Web->dispatch( )../index.php:17
30.66637155080Zend_Controller_Front->dispatch( )../Web.php:177
40.67187339544Zend_Controller_Dispatcher_Standard->dispatch( )../Front.php:954
50.75449789672Zend_Controller_Action->dispatch( )../Standard.php:308
60.854711070736Icinga\Web\Controller\ActionController->postDispatch( )../Action.php:521
70.855011071712Icinga\Web\Controller\ActionController->sendAsPdfAndDie( )../ActionController.php:244
81.993023228752Icinga\File\Pdf->renderPage( )../ActionController.php:279
92.066823495800DOMPDF->render( )../Pdf.php:62
109.090249430472Frame_Decorator->reflow( )../dompdf.cls.php:817
119.090249430520Page_Frame_Reflower->reflow( )../frame_decorator.cls.php:556
129.091049432912Frame_Decorator->reflow( )../page_frame_reflower.cls.php:138
139.091049432960Block_Frame_Reflower->reflow( )../frame_decorator.cls.php:556
149.096249449768Frame_Decorator->reflow( )../block_frame_reflower.cls.php:722
159.096249449768Block_Frame_Reflower->reflow( )../frame_decorator.cls.php:556
169.213549818768Frame_Decorator->reflow( )../block_frame_reflower.cls.php:722
179.213649818768Table_Frame_Reflower->reflow( )../frame_decorator.cls.php:556
-
- - - - - - - - - - - - - - - - - - - - - - - -
( ! ) Notice: Undefined offset: 1 in /vagrant/library/vendor/dompdf/include/table_frame_reflower.cls.php on line 396
Call Stack
#TimeMemoryFunctionLocation
10.0015634696{main}( )../index.php:0
20.66637155080Icinga\Application\Web->dispatch( )../index.php:17
30.66637155080Zend_Controller_Front->dispatch( )../Web.php:177
40.67187339544Zend_Controller_Dispatcher_Standard->dispatch( )../Front.php:954
50.75449789672Zend_Controller_Action->dispatch( )../Standard.php:308
60.854711070736Icinga\Web\Controller\ActionController->postDispatch( )../Action.php:521
70.855011071712Icinga\Web\Controller\ActionController->sendAsPdfAndDie( )../ActionController.php:244
81.993023228752Icinga\File\Pdf->renderPage( )../ActionController.php:279
92.066823495800DOMPDF->render( )../Pdf.php:62
109.090249430472Frame_Decorator->reflow( )../dompdf.cls.php:817
119.090249430520Page_Frame_Reflower->reflow( )../frame_decorator.cls.php:556
129.091049432912Frame_Decorator->reflow( )../page_frame_reflower.cls.php:138
139.091049432960Block_Frame_Reflower->reflow( )../frame_decorator.cls.php:556
149.229149850600Frame_Decorator->reflow( )../block_frame_reflower.cls.php:722
159.229149850600Block_Frame_Reflower->reflow( )../frame_decorator.cls.php:556
169.233849873816Frame_Decorator->reflow( )../block_frame_reflower.cls.php:722
179.233849873816Block_Frame_Reflower->reflow( )../frame_decorator.cls.php:556
189.235549886736Frame_Decorator->reflow( )../block_frame_reflower.cls.php:722
199.235649886736Table_Frame_Reflower->reflow( )../frame_decorator.cls.php:556
-
- - - - - - - - - - - - - - - - - - - - - - - - - -
( ! ) Notice: Undefined offset: 1 in /vagrant/library/vendor/dompdf/include/table_frame_reflower.cls.php on line 396
Call Stack
#TimeMemoryFunctionLocation
10.0015634696{main}( )../index.php:0
20.66637155080Icinga\Application\Web->dispatch( )../index.php:17
30.66637155080Zend_Controller_Front->dispatch( )../Web.php:177
40.67187339544Zend_Controller_Dispatcher_Standard->dispatch( )../Front.php:954
50.75449789672Zend_Controller_Action->dispatch( )../Standard.php:308
60.854711070736Icinga\Web\Controller\ActionController->postDispatch( )../Action.php:521
70.855011071712Icinga\Web\Controller\ActionController->sendAsPdfAndDie( )../ActionController.php:244
81.993023228752Icinga\File\Pdf->renderPage( )../ActionController.php:279
92.066823495800DOMPDF->render( )../Pdf.php:62
109.090249430472Frame_Decorator->reflow( )../dompdf.cls.php:817
119.090249430520Page_Frame_Reflower->reflow( )../frame_decorator.cls.php:556
129.091049432912Frame_Decorator->reflow( )../page_frame_reflower.cls.php:138
139.091049432960Block_Frame_Reflower->reflow( )../frame_decorator.cls.php:556
149.229149850600Frame_Decorator->reflow( )../block_frame_reflower.cls.php:722
159.229149850600Block_Frame_Reflower->reflow( )../frame_decorator.cls.php:556
169.233849873816Frame_Decorator->reflow( )../block_frame_reflower.cls.php:722
179.233849873816Block_Frame_Reflower->reflow( )../frame_decorator.cls.php:556
189.243149918440Frame_Decorator->reflow( )../block_frame_reflower.cls.php:722
199.243149918440Block_Frame_Reflower->reflow( )../frame_decorator.cls.php:556
209.245949935336Frame_Decorator->reflow( )../block_frame_reflower.cls.php:722
219.245949935336Table_Frame_Reflower->reflow( )../frame_decorator.cls.php:556
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
( ! ) Notice: Undefined offset: 1 in /vagrant/library/vendor/dompdf/include/table_frame_reflower.cls.php on line 396
Call Stack
#TimeMemoryFunctionLocation
10.0015634696{main}( )../index.php:0
20.66637155080Icinga\Application\Web->dispatch( )../index.php:17
30.66637155080Zend_Controller_Front->dispatch( )../Web.php:177
40.67187339544Zend_Controller_Dispatcher_Standard->dispatch( )../Front.php:954
50.75449789672Zend_Controller_Action->dispatch( )../Standard.php:308
60.854711070736Icinga\Web\Controller\ActionController->postDispatch( )../Action.php:521
70.855011071712Icinga\Web\Controller\ActionController->sendAsPdfAndDie( )../ActionController.php:244
81.993023228752Icinga\File\Pdf->renderPage( )../ActionController.php:279
92.066823495800DOMPDF->render( )../Pdf.php:62
109.090249430472Frame_Decorator->reflow( )../dompdf.cls.php:817
119.090249430520Page_Frame_Reflower->reflow( )../frame_decorator.cls.php:556
129.091049432912Frame_Decorator->reflow( )../page_frame_reflower.cls.php:138
139.091049432960Block_Frame_Reflower->reflow( )../frame_decorator.cls.php:556
149.229149850600Frame_Decorator->reflow( )../block_frame_reflower.cls.php:722
159.229149850600Block_Frame_Reflower->reflow( )../frame_decorator.cls.php:556
169.233849873816Frame_Decorator->reflow( )../block_frame_reflower.cls.php:722
179.233849873816Block_Frame_Reflower->reflow( )../frame_decorator.cls.php:556
189.243149918440Frame_Decorator->reflow( )../block_frame_reflower.cls.php:722
199.243149918440Block_Frame_Reflower->reflow( )../frame_decorator.cls.php:556
209.251949965624Frame_Decorator->reflow( )../block_frame_reflower.cls.php:722
219.251949965624Block_Frame_Reflower->reflow( )../frame_decorator.cls.php:556
229.257549989664Frame_Decorator->reflow( )../block_frame_reflower.cls.php:722
239.257549989664Block_Frame_Reflower->reflow( )../frame_decorator.cls.php:556
249.259350005472Frame_Decorator->reflow( )../block_frame_reflower.cls.php:722
259.259450005472Block_Frame_Reflower->reflow( )../frame_decorator.cls.php:556
269.261150020048Frame_Decorator->reflow( )../block_frame_reflower.cls.php:722
279.261150020048Table_Frame_Reflower->reflow( )../frame_decorator.cls.php:556
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
( ! ) Notice: Undefined offset: 1 in /vagrant/library/vendor/dompdf/include/table_frame_reflower.cls.php on line 396
Call Stack
#TimeMemoryFunctionLocation
10.0015634696{main}( )../index.php:0
20.66637155080Icinga\Application\Web->dispatch( )../index.php:17
30.66637155080Zend_Controller_Front->dispatch( )../Web.php:177
40.67187339544Zend_Controller_Dispatcher_Standard->dispatch( )../Front.php:954
50.75449789672Zend_Controller_Action->dispatch( )../Standard.php:308
60.854711070736Icinga\Web\Controller\ActionController->postDispatch( )../Action.php:521
70.855011071712Icinga\Web\Controller\ActionController->sendAsPdfAndDie( )../ActionController.php:244
81.993023228752Icinga\File\Pdf->renderPage( )../ActionController.php:279
92.066823495800DOMPDF->render( )../Pdf.php:62
109.090249430472Frame_Decorator->reflow( )../dompdf.cls.php:817
119.090249430520Page_Frame_Reflower->reflow( )../frame_decorator.cls.php:556
129.091049432912Frame_Decorator->reflow( )../page_frame_reflower.cls.php:138
139.091049432960Block_Frame_Reflower->reflow( )../frame_decorator.cls.php:556
149.229149850600Frame_Decorator->reflow( )../block_frame_reflower.cls.php:722
159.229149850600Block_Frame_Reflower->reflow( )../frame_decorator.cls.php:556
169.233849873816Frame_Decorator->reflow( )../block_frame_reflower.cls.php:722
179.233849873816Block_Frame_Reflower->reflow( )../frame_decorator.cls.php:556
189.243149918440Frame_Decorator->reflow( )../block_frame_reflower.cls.php:722
199.243149918440Block_Frame_Reflower->reflow( )../frame_decorator.cls.php:556
209.251949965624Frame_Decorator->reflow( )../block_frame_reflower.cls.php:722
219.251949965624Block_Frame_Reflower->reflow( )../frame_decorator.cls.php:556
229.257549989664Frame_Decorator->reflow( )../block_frame_reflower.cls.php:722
239.257549989664Block_Frame_Reflower->reflow( )../frame_decorator.cls.php:556
249.259350005472Frame_Decorator->reflow( )../block_frame_reflower.cls.php:722
259.259450005472Block_Frame_Reflower->reflow( )../frame_decorator.cls.php:556
269.272250061408Frame_Decorator->reflow( )../block_frame_reflower.cls.php:722
279.272250061408Table_Frame_Reflower->reflow( )../frame_decorator.cls.php:556
-
- - - - - - - - - - - - - - - - - - - - - - - - - -
( ! ) Notice: Undefined offset: 1 in /vagrant/library/vendor/dompdf/include/table_frame_reflower.cls.php on line 396
Call Stack
#TimeMemoryFunctionLocation
10.0015634696{main}( )../index.php:0
20.66637155080Icinga\Application\Web->dispatch( )../index.php:17
30.66637155080Zend_Controller_Front->dispatch( )../Web.php:177
40.67187339544Zend_Controller_Dispatcher_Standard->dispatch( )../Front.php:954
50.75449789672Zend_Controller_Action->dispatch( )../Standard.php:308
60.854711070736Icinga\Web\Controller\ActionController->postDispatch( )../Action.php:521
70.855011071712Icinga\Web\Controller\ActionController->sendAsPdfAndDie( )../ActionController.php:244
81.993023228752Icinga\File\Pdf->renderPage( )../ActionController.php:279
92.066823495800DOMPDF->render( )../Pdf.php:62
109.090249430472Frame_Decorator->reflow( )../dompdf.cls.php:817
119.090249430520Page_Frame_Reflower->reflow( )../frame_decorator.cls.php:556
129.091049432912Frame_Decorator->reflow( )../page_frame_reflower.cls.php:138
139.091049432960Block_Frame_Reflower->reflow( )../frame_decorator.cls.php:556
149.229149850600Frame_Decorator->reflow( )../block_frame_reflower.cls.php:722
159.229149850600Block_Frame_Reflower->reflow( )../frame_decorator.cls.php:556
169.233849873816Frame_Decorator->reflow( )../block_frame_reflower.cls.php:722
179.233849873816Block_Frame_Reflower->reflow( )../frame_decorator.cls.php:556
189.243149918440Frame_Decorator->reflow( )../block_frame_reflower.cls.php:722
199.243149918440Block_Frame_Reflower->reflow( )../frame_decorator.cls.php:556
209.299950176560Frame_Decorator->reflow( )../block_frame_reflower.cls.php:722
219.299950176560Table_Frame_Reflower->reflow( )../frame_decorator.cls.php:556
-
- - - - - - - - - - - - - - - - - - - - - - - - - -
( ! ) Notice: Undefined offset: 1 in /vagrant/library/vendor/dompdf/include/table_frame_reflower.cls.php on line 396
Call Stack
#TimeMemoryFunctionLocation
10.0015634696{main}( )../index.php:0
20.66637155080Icinga\Application\Web->dispatch( )../index.php:17
30.66637155080Zend_Controller_Front->dispatch( )../Web.php:177
40.67187339544Zend_Controller_Dispatcher_Standard->dispatch( )../Front.php:954
50.75449789672Zend_Controller_Action->dispatch( )../Standard.php:308
60.854711070736Icinga\Web\Controller\ActionController->postDispatch( )../Action.php:521
70.855011071712Icinga\Web\Controller\ActionController->sendAsPdfAndDie( )../ActionController.php:244
81.993023228752Icinga\File\Pdf->renderPage( )../ActionController.php:279
92.066823495800DOMPDF->render( )../Pdf.php:62
109.090249430472Frame_Decorator->reflow( )../dompdf.cls.php:817
119.090249430520Page_Frame_Reflower->reflow( )../frame_decorator.cls.php:556
129.091049432912Frame_Decorator->reflow( )../page_frame_reflower.cls.php:138
139.091049432960Block_Frame_Reflower->reflow( )../frame_decorator.cls.php:556
149.229149850600Frame_Decorator->reflow( )../block_frame_reflower.cls.php:722
159.229149850600Block_Frame_Reflower->reflow( )../frame_decorator.cls.php:556
169.233849873816Frame_Decorator->reflow( )../block_frame_reflower.cls.php:722
179.233849873816Block_Frame_Reflower->reflow( )../frame_decorator.cls.php:556
189.308350220200Frame_Decorator->reflow( )../block_frame_reflower.cls.php:722
199.308350220200Block_Frame_Reflower->reflow( )../frame_decorator.cls.php:556
209.310350235768Frame_Decorator->reflow( )../block_frame_reflower.cls.php:722
219.310350235768Table_Frame_Reflower->reflow( )../frame_decorator.cls.php:556
-
- - - - - - - - - - - - - - - - - - - - - - - - - -
( ! ) Notice: Undefined offset: 1 in /vagrant/library/vendor/dompdf/include/table_frame_reflower.cls.php on line 396
Call Stack
#TimeMemoryFunctionLocation
10.0015634696{main}( )../index.php:0
20.66637155080Icinga\Application\Web->dispatch( )../index.php:17
30.66637155080Zend_Controller_Front->dispatch( )../Web.php:177
40.67187339544Zend_Controller_Dispatcher_Standard->dispatch( )../Front.php:954
50.75449789672Zend_Controller_Action->dispatch( )../Standard.php:308
60.854711070736Icinga\Web\Controller\ActionController->postDispatch( )../Action.php:521
70.855011071712Icinga\Web\Controller\ActionController->sendAsPdfAndDie( )../ActionController.php:244
81.993023228752Icinga\File\Pdf->renderPage( )../ActionController.php:279
92.066823495800DOMPDF->render( )../Pdf.php:62
109.090249430472Frame_Decorator->reflow( )../dompdf.cls.php:817
119.090249430520Page_Frame_Reflower->reflow( )../frame_decorator.cls.php:556
129.091049432912Frame_Decorator->reflow( )../page_frame_reflower.cls.php:138
139.091049432960Block_Frame_Reflower->reflow( )../frame_decorator.cls.php:556
149.229149850600Frame_Decorator->reflow( )../block_frame_reflower.cls.php:722
159.229149850600Block_Frame_Reflower->reflow( )../frame_decorator.cls.php:556
169.233849873816Frame_Decorator->reflow( )../block_frame_reflower.cls.php:722
179.233849873816Block_Frame_Reflower->reflow( )../frame_decorator.cls.php:556
189.308350220200Frame_Decorator->reflow( )../block_frame_reflower.cls.php:722
199.308350220200Block_Frame_Reflower->reflow( )../frame_decorator.cls.php:556
209.317050278592Frame_Decorator->reflow( )../block_frame_reflower.cls.php:722
219.317050278592Table_Frame_Reflower->reflow( )../frame_decorator.cls.php:556
-
- - - - - - - - - - - - - - - - - - - - - - - - - -
( ! ) Notice: Undefined offset: 1 in /vagrant/library/vendor/dompdf/include/table_frame_reflower.cls.php on line 396
Call Stack
#TimeMemoryFunctionLocation
10.0015634696{main}( )../index.php:0
20.66637155080Icinga\Application\Web->dispatch( )../index.php:17
30.66637155080Zend_Controller_Front->dispatch( )../Web.php:177
40.67187339544Zend_Controller_Dispatcher_Standard->dispatch( )../Front.php:954
50.75449789672Zend_Controller_Action->dispatch( )../Standard.php:308
60.854711070736Icinga\Web\Controller\ActionController->postDispatch( )../Action.php:521
70.855011071712Icinga\Web\Controller\ActionController->sendAsPdfAndDie( )../ActionController.php:244
81.993023228752Icinga\File\Pdf->renderPage( )../ActionController.php:279
92.066823495800DOMPDF->render( )../Pdf.php:62
109.090249430472Frame_Decorator->reflow( )../dompdf.cls.php:817
119.090249430520Page_Frame_Reflower->reflow( )../frame_decorator.cls.php:556
129.091049432912Frame_Decorator->reflow( )../page_frame_reflower.cls.php:138
139.091049432960Block_Frame_Reflower->reflow( )../frame_decorator.cls.php:556
149.229149850600Frame_Decorator->reflow( )../block_frame_reflower.cls.php:722
159.229149850600Block_Frame_Reflower->reflow( )../frame_decorator.cls.php:556
169.233849873816Frame_Decorator->reflow( )../block_frame_reflower.cls.php:722
179.233849873816Block_Frame_Reflower->reflow( )../frame_decorator.cls.php:556
189.324650312056Frame_Decorator->reflow( )../block_frame_reflower.cls.php:722
199.324750312056Block_Frame_Reflower->reflow( )../frame_decorator.cls.php:556
209.326650326968Frame_Decorator->reflow( )../block_frame_reflower.cls.php:722
219.326650326968Table_Frame_Reflower->reflow( )../frame_decorator.cls.php:556
-
- - - - - - - - - - - - - - - - - - - - - - - - - -
( ! ) Notice: Undefined offset: 1 in /vagrant/library/vendor/dompdf/include/table_frame_reflower.cls.php on line 396
Call Stack
#TimeMemoryFunctionLocation
10.0015634696{main}( )../index.php:0
20.66637155080Icinga\Application\Web->dispatch( )../index.php:17
30.66637155080Zend_Controller_Front->dispatch( )../Web.php:177
40.67187339544Zend_Controller_Dispatcher_Standard->dispatch( )../Front.php:954
50.75449789672Zend_Controller_Action->dispatch( )../Standard.php:308
60.854711070736Icinga\Web\Controller\ActionController->postDispatch( )../Action.php:521
70.855011071712Icinga\Web\Controller\ActionController->sendAsPdfAndDie( )../ActionController.php:244
81.993023228752Icinga\File\Pdf->renderPage( )../ActionController.php:279
92.066823495800DOMPDF->render( )../Pdf.php:62
109.090249430472Frame_Decorator->reflow( )../dompdf.cls.php:817
119.090249430520Page_Frame_Reflower->reflow( )../frame_decorator.cls.php:556
129.091049432912Frame_Decorator->reflow( )../page_frame_reflower.cls.php:138
139.091049432960Block_Frame_Reflower->reflow( )../frame_decorator.cls.php:556
149.229149850600Frame_Decorator->reflow( )../block_frame_reflower.cls.php:722
159.229149850600Block_Frame_Reflower->reflow( )../frame_decorator.cls.php:556
169.233849873816Frame_Decorator->reflow( )../block_frame_reflower.cls.php:722
179.233849873816Block_Frame_Reflower->reflow( )../frame_decorator.cls.php:556
189.324650312056Frame_Decorator->reflow( )../block_frame_reflower.cls.php:722
199.324750312056Block_Frame_Reflower->reflow( )../frame_decorator.cls.php:556
209.336750378088Frame_Decorator->reflow( )../block_frame_reflower.cls.php:722
219.336750378088Table_Frame_Reflower->reflow( )../frame_decorator.cls.php:556
-
- - - - - - - - - - - - - - - - - - - - - - - -
( ! ) Notice: Undefined offset: 1 in /vagrant/library/vendor/dompdf/include/table_frame_reflower.cls.php on line 396
Call Stack
#TimeMemoryFunctionLocation
10.0015634696{main}( )../index.php:0
20.66637155080Icinga\Application\Web->dispatch( )../index.php:17
30.66637155080Zend_Controller_Front->dispatch( )../Web.php:177
40.67187339544Zend_Controller_Dispatcher_Standard->dispatch( )../Front.php:954
50.75449789672Zend_Controller_Action->dispatch( )../Standard.php:308
60.854711070736Icinga\Web\Controller\ActionController->postDispatch( )../Action.php:521
70.855011071712Icinga\Web\Controller\ActionController->sendAsPdfAndDie( )../ActionController.php:244
81.993023228752Icinga\File\Pdf->renderPage( )../ActionController.php:279
92.066823495800DOMPDF->render( )../Pdf.php:62
109.090249430472Frame_Decorator->reflow( )../dompdf.cls.php:817
119.090249430520Page_Frame_Reflower->reflow( )../frame_decorator.cls.php:556
129.091049432912Frame_Decorator->reflow( )../page_frame_reflower.cls.php:138
139.091049432960Block_Frame_Reflower->reflow( )../frame_decorator.cls.php:556
149.229149850600Frame_Decorator->reflow( )../block_frame_reflower.cls.php:722
159.229149850600Block_Frame_Reflower->reflow( )../frame_decorator.cls.php:556
169.233849873816Frame_Decorator->reflow( )../block_frame_reflower.cls.php:722
179.233849873816Block_Frame_Reflower->reflow( )../frame_decorator.cls.php:556
189.344250422280Frame_Decorator->reflow( )../block_frame_reflower.cls.php:722
199.344250422280Table_Frame_Reflower->reflow( )../frame_decorator.cls.php:556
diff --git a/modules/monitoring/application/controllers/ChartController.php b/modules/monitoring/application/controllers/ChartController.php index c3d80b59f..bf41ab5eb 100644 --- a/modules/monitoring/application/controllers/ChartController.php +++ b/modules/monitoring/application/controllers/ChartController.php @@ -147,7 +147,7 @@ class Monitoring_ChartController extends Controller ->setXAxis(new StaticAxis()) ->setAxisMin(null, 0); - $tooltip = t('{title}:
{value} of {sum} services are {label}'); + $tooltip = t('{title}:
{value} of {sum} services are {label}'); $this->view->chart->drawBars( array( 'label' => t('Ok'), @@ -199,7 +199,7 @@ class Monitoring_ChartController extends Controller $hostgroup->hosts_unreachable_unhandled ); } - $tooltip = t('{title}:
{value} of {sum} hosts are {label}'); + $tooltip = t('{title}:
{value} of {sum} hosts are {label}'); $this->view->chart = new GridChart(); $this->view->chart->alignTopLeft(); $this->view->chart->setAxisLabel('', t('Hosts')) diff --git a/modules/monitoring/application/controllers/ConfigController.php b/modules/monitoring/application/controllers/ConfigController.php index ce22d73df..de9c65b04 100644 --- a/modules/monitoring/application/controllers/ConfigController.php +++ b/modules/monitoring/application/controllers/ConfigController.php @@ -2,14 +2,13 @@ // {{{ICINGA_LICENSE_HEADER}}} // {{{ICINGA_LICENSE_HEADER}}} -use Icinga\Config\PreservingIniWriter; -use Icinga\Web\Controller\ModuleActionController; use Icinga\Web\Notification; +use Icinga\Data\ResourceFactory; use Icinga\Form\ConfirmRemovalForm; -use Icinga\Module\Monitoring\Form\Config\BackendForm; -use Icinga\Module\Monitoring\Form\Config\InstanceForm; -use Icinga\Module\Monitoring\Form\Config\SecurityForm; -use Icinga\Exception\NotReadableError; +use Icinga\Web\Controller\ModuleActionController; +use Icinga\Module\Monitoring\Form\Config\BackendConfigForm; +use Icinga\Module\Monitoring\Form\Config\InstanceConfigForm; +use Icinga\Module\Monitoring\Form\Config\SecurityConfigForm; /** * Configuration controller for editing monitoring resources @@ -21,19 +20,9 @@ class Monitoring_ConfigController extends ModuleActionController */ public function indexAction() { + $this->view->backendsConfig = $this->Config('backends'); + $this->view->instancesConfig = $this->Config('instances'); $this->view->tabs = $this->Module()->getConfigTabs()->activate('backends'); - foreach (array('backends', 'instances') as $element) { - try { - $elementConfig = $this->Config($element); - if ($elementConfig === null) { - $this->view->{$element} = array(); - } else { - $this->view->{$element} = $elementConfig->toArray(); - } - } catch (NotReadableError $e) { - $this->view->{$element} = $e; - } - } } /** @@ -41,38 +30,11 @@ class Monitoring_ConfigController extends ModuleActionController */ public function editbackendAction() { - // Fetch the backend to be edited - $backend = $this->getParam('backend'); - $backendsConfig = $this->Config('backends')->toArray(); - if (false === array_key_exists($backend, $backendsConfig)) { - // TODO: Should behave as in the app's config controller (Specific redirect to an error action) - Notification::error(sprintf($this->translate('Cannot edit "%s". Backend not found.'), $backend)); - $this->redirectNow('monitoring/config'); - } - - $form = new BackendForm(); - $request = $this->getRequest(); - if ($request->isPost()) { - if ($form->isValid($request->getPost())) { - list($newName, $config) = $form->getBackendConfig(); - - if ($newName !== $backend) { - // Backend name has changed - unset($backendsConfig[$backend]); // We can safely use unset as all values are part of the form - } - - $backendsConfig[$newName] = $config; - if ($this->writeConfiguration($backendsConfig, 'backends')) { - Notification::success(sprintf($this->translate('Backend "%s" successfully modified.'), $backend)); - $this->redirectNow('monitoring/config'); - } else { - $this->render('show-configuration'); - return; - } - } - } else { - $form->setBackendConfig($backend, $backendsConfig[$backend]); - } + $form = new BackendConfigForm(); + $form->setIniConfig($this->Config('backends')); + $form->setResourceConfig(ResourceFactory::getResourceConfigs()); + $form->setRedirectUrl('monitoring/config'); + $form->handleRequest(); $this->view->form = $form; } @@ -82,20 +44,11 @@ class Monitoring_ConfigController extends ModuleActionController */ public function createbackendAction() { - $form = new BackendForm(); - $request = $this->getRequest(); - if ($request->isPost() && $form->isValid($request->getPost())) { - list($name, $config) = $form->getBackendConfig(); - $backendsConfig = $this->Config('backends')->toArray(); - $backendsConfig[$name] = $config; - if ($this->writeConfiguration($backendsConfig, 'backends')) { - Notification::success(sprintf($this->translate('Backend "%s" created successfully.'), $name)); - $this->redirectNow('monitoring/config'); - } else { - $this->render('show-configuration'); - return; - } - } + $form = new BackendConfigForm(); + $form->setIniConfig($this->Config('backends')); + $form->setResourceConfig(ResourceFactory::getResourceConfigs()); + $form->setRedirectUrl('monitoring/config'); + $form->handleRequest(); $this->view->form = $form; } @@ -105,26 +58,29 @@ class Monitoring_ConfigController extends ModuleActionController */ public function removebackendAction() { - $backend = $this->getParam('backend'); - $backendsConfig = $this->Config('backends')->toArray(); - if (false === array_key_exists($backend, $backendsConfig)) { - // TODO: Should behave as in the app's config controller (Specific redirect to an error action) - Notification::error(sprintf($this->translate('Cannot remove "%s". Backend not found.'), $backend)); - $this->redirectNow('monitoring/config'); - } + $config = $this->Config('backends'); + $form = new ConfirmRemovalForm(array( + 'onSuccess' => function ($request) use ($config) { + $backendName = $request->getQuery('backend'); + $configForm = new BackendConfigForm(); + $configForm->setIniConfig($config); - $form = new ConfirmRemovalForm(); - $request = $this->getRequest(); - if ($request->isPost() && $form->isValid($request->getPost())) { - unset($backendsConfig[$backend]); - if ($this->writeConfiguration($backendsConfig, 'backends')) { - Notification::success(sprintf($this->translate('Backend "%s" successfully removed.'), $backend)); - $this->redirectNow('monitoring/config'); - } else { - $this->render('show-configuration'); - return; + try { + $configForm->remove($backendName); + } catch (InvalidArgumentException $e) { + Notification::error($e->getMessage()); + return; + } + + if ($configForm->save()) { + Notification::success(sprintf(t('Backend "%s" successfully removed.'), $backendName)); + } else { + return false; + } } - } + )); + $form->setRedirectUrl('monitoring/config'); + $form->handleRequest(); $this->view->form = $form; } @@ -134,29 +90,31 @@ class Monitoring_ConfigController extends ModuleActionController */ public function removeinstanceAction() { - $instance = $this->getParam('instance'); - $instancesConfig = $this->Config('instances')->toArray(); - if (false === array_key_exists($instance, $instancesConfig)) { - // TODO: Should behave as in the app's config controller (Specific redirect to an error action) - Notification::error(sprintf($this->translate('Cannot remove "%s". Instance not found.'), $instance)); - $this->redirectNow('monitoring/config'); - } + $config = $this->Config('instances'); + $form = new ConfirmRemovalForm(array( + 'onSuccess' => function ($request) use ($config) { + $instanceName = $request->getQuery('instance'); + $configForm = new InstanceConfigForm(); + $configForm->setIniConfig($config); - $form = new ConfirmRemovalForm(); - $request = $this->getRequest(); - if ($request->isPost() && $form->isValid($request->getPost())) { - unset($instancesConfig[$instance]); - if ($this->writeConfiguration($instancesConfig, 'instances')) { - Notification::success(sprintf($this->translate('Instance "%s" successfully removed.'), $instance)); - $this->redirectNow('monitoring/config'); - } else { - $this->render('show-configuration'); - return; + try { + $configForm->remove($instanceName); + } catch (InvalidArgumentException $e) { + Notification::error($e->getMessage()); + return; + } + + if ($configForm->save()) { + Notification::success(sprintf(t('Instance "%s" successfully removed.'), $instanceName)); + } else { + return false; + } } - } + )); + $form->setRedirectUrl('monitoring/config'); + $form->handleRequest(); $this->view->form = $form; - $this->view->name = $instance; } /** @@ -164,36 +122,10 @@ class Monitoring_ConfigController extends ModuleActionController */ public function editinstanceAction() { - $instance = $this->getParam('instance'); - $instancesConfig = $this->Config('instances')->toArray(); - if (false === array_key_exists($instance, $instancesConfig)) { - // TODO: Should behave as in the app's config controller (Specific redirect to an error action) - Notification::error(sprintf($this->translate('Cannot edit "%s". Instance not found.'), $instance)); - $this->redirectNow('monitoring/config'); - } - - $form = new InstanceForm(); - $request = $this->getRequest(); - if ($request->isPost()) { - if ($form->isValid($request->getPost())) { - list($newName, $config) = $form->getInstanceConfig(); - - if ($newName !== $instance) { - unset($instancesConfig[$instance]); // We can safely use unset as all values are part of the form - } - - $instancesConfig[$newName] = $config; - if ($this->writeConfiguration($instancesConfig, 'instances')) { - Notification::success(sprintf($this->translate('Instance "%s" successfully modified.'), $instance)); - $this->redirectNow('monitoring/config'); - } else { - $this->render('show-configuration'); - return; - } - } - } else { - $form->setInstanceConfig($instance, $instancesConfig[$instance]); - } + $form = new InstanceConfigForm(); + $form->setIniConfig($this->Config('instances')); + $form->setRedirectUrl('monitoring/config'); + $form->handleRequest(); $this->view->form = $form; } @@ -203,77 +135,24 @@ class Monitoring_ConfigController extends ModuleActionController */ public function createinstanceAction() { - $form = new InstanceForm(); - $request = $this->getRequest(); - if ($request->isPost() && $form->isValid($request->getPost())) { - list($name, $config) = $form->getInstanceConfig(); - $instancesConfig = $this->Config('instances')->toArray(); - $instancesConfig[$name] = $config; - if ($this->writeConfiguration($instancesConfig, 'instances')) { - Notification::success(sprintf($this->translate('Instance "%s" created successfully.'), $name)); - $this->redirectNow('monitoring/config'); - } else { - $this->render('show-configuration'); - return; - } - } + $form = new InstanceConfigForm(); + $form->setIniConfig($this->Config('instances')); + $form->setRedirectUrl('monitoring/config'); + $form->handleRequest(); $this->view->form = $form; } - /** - * Write configuration to an ini file - * - * @param Zend_Config $config The configuration to write - * @param string $file The config file to write to - * - * @return bool Whether the configuration was written or not - */ - protected function writeConfiguration($config, $file = null) - { - if (is_array($config)) { - $config = new Zend_Config($config); - } - $target = $this->Config($file)->getConfigFile(); - $writer = new PreservingIniWriter(array('filename' => $target, 'config' => $config)); - - try { - $writer->write(); - } catch (Exception $exc) { - $this->view->exceptionMessage = $exc->getMessage(); - $this->view->iniConfigurationString = $writer->render(); - $this->view->file = $target; - return false; - } - - return true; - } - /** * Display a form to adjust security relevant settings */ public function securityAction() { - $this->view->tabs = $this->Module()->getConfigTabs()->activate('security'); - - $form = new SecurityForm(); - $request = $this->getRequest(); - $config = $this->Config()->toArray(); - if ($request->isPost()) { - if ($form->isValid($request->getPost())) { - $config['security'] = $form->getValues(); - if ($this->writeConfiguration(new Zend_Config($config))) { - Notification::success('Configuration modified successfully'); - $this->redirectNow('monitoring/config/security'); - } else { - $this->render('show-configuration'); - return; - } - } - } elseif (isset($config['security'])) { - $form->populate($config['security']); - } + $form = new SecurityConfigForm(); + $form->setIniConfig($this->Config()); + $form->handleRequest(); $this->view->form = $form; + $this->view->tabs = $this->Module()->getConfigTabs()->activate('security'); } } diff --git a/modules/monitoring/application/controllers/TimelineController.php b/modules/monitoring/application/controllers/TimelineController.php index 2da29a0b9..a67615b1c 100644 --- a/modules/monitoring/application/controllers/TimelineController.php +++ b/modules/monitoring/application/controllers/TimelineController.php @@ -13,7 +13,6 @@ use Icinga\Module\Monitoring\Controller; use Icinga\Module\Monitoring\Timeline\TimeLine; use Icinga\Module\Monitoring\Timeline\TimeRange; use Icinga\Module\Monitoring\Web\Widget\TimelineIntervalBox; -use Icinga\Module\Monitoring\DataView\EventHistory as EventHistoryView; class Monitoring_TimelineController extends Controller { diff --git a/modules/monitoring/application/forms/Config/BackendConfigForm.php b/modules/monitoring/application/forms/Config/BackendConfigForm.php new file mode 100644 index 000000000..e2cdf210c --- /dev/null +++ b/modules/monitoring/application/forms/Config/BackendConfigForm.php @@ -0,0 +1,242 @@ +setName('form_config_monitoring_backends'); + $this->setSubmitLabel(t('Save Changes')); + } + + /** + * Set the resource configuration to use + * + * @param Config $resources The resource configuration + * + * @return self + * + * @throws ConfigurationError In case there are no valid monitoring backend resources + */ + public function setResourceConfig(Config $resourceConfig) + { + $resources = array(); + foreach ($resourceConfig as $name => $resource) { + if ($resource->type === 'db' || $resource->type === 'statusdat' || $resource->type === 'livestatus') { + $resources[$resource->type === 'db' ? 'ido' : strtolower($resource->type)][] = $name; + } + } + + if (empty($resources)) { + throw new ConfigurationError(t('Could not find any valid monitoring backend resources')); + } + + $this->resources = $resources; + return $this; + } + + /** + * Add a particular monitoring backend + * + * The backend to add is identified by the array-key `name'. + * + * @param array $values The values to extend the configuration with + * + * @return self + * + * @throws InvalidArgumentException In case the backend does already exist + */ + public function add(array $values) + { + $name = isset($values['name']) ? $values['name'] : ''; + if (! $name) { + throw new InvalidArgumentException(t('Monitoring backend name missing')); + } elseif ($this->config->get($name) !== null) { + throw new InvalidArgumentException(t('Monitoring backend already exists')); + } + + unset($values['name']); + $this->config->{$name} = $values; + return $this; + } + + /** + * Edit a particular monitoring backend + * + * @param string $name The name of the backend to edit + * @param array $values The values to edit the configuration with + * + * @return array The edited backend configuration + * + * @throws InvalidArgumentException In case the backend does not exist + */ + public function edit($name, array $values) + { + if (! $name) { + throw new InvalidArgumentException(t('Old monitoring backend name missing')); + } elseif (! ($newName = isset($values['name']) ? $values['name'] : '')) { + throw new InvalidArgumentException(t('New monitoring backend name missing')); + } elseif (($backendConfig = $this->config->get($name)) === null) { + throw new InvalidArgumentException(t('Unknown monitoring backend provided')); + } + + unset($values['name']); + unset($this->config->{$name}); + $this->config->{$newName} = $values; + return $this->config->{$newName}; + } + + /** + * Remove the given monitoring backend + * + * @param string $name The name of the backend to remove + * + * @return array The removed backend configuration + * + * @throws InvalidArgumentException In case the backend does not exist + */ + public function remove($name) + { + if (! $name) { + throw new InvalidArgumentException(t('Monitoring backend name missing')); + } elseif (($backendConfig = $this->config->get($name)) === null) { + throw new InvalidArgumentException(t('Unknown monitoring backend provided')); + } + + unset($this->config->{$name}); + return $backendConfig; + } + + /** + * Add or edit a monitoring backend and save the configuration + * + * @see Form::onSuccess() + */ + public function onSuccess(Request $request) + { + $monitoringBackend = $request->getQuery('backend'); + try { + if ($monitoringBackend === null) { // create new backend + $this->add($this->getValues()); + $message = t('Monitoring backend "%s" has been successfully created'); + } else { // edit existing backend + $this->edit($monitoringBackend, $this->getValues()); + $message = t('Monitoring backend "%s" has been successfully changed'); + } + } catch (InvalidArgumentException $e) { + Notification::error($e->getMessage()); + return; + } + + if ($this->save()) { + Notification::success(sprintf($message, $this->getElement('name')->getValue())); + } else { + return false; + } + } + + /** + * Populate the form in case a monitoring backend is being edited + * + * @see Form::onRequest() + * + * @throws ConfigurationError In case the backend name is missing in the request or is invalid + */ + public function onRequest(Request $request) + { + $monitoringBackend = $request->getQuery('backend'); + if ($monitoringBackend !== null) { + if ($monitoringBackend === '') { + throw new ConfigurationError(t('Monitoring backend name missing')); + } elseif (false === isset($this->config->{$monitoringBackend})) { + throw new ConfigurationError(t('Unknown monitoring backend provided')); + } + + $backendConfig = $this->config->{$monitoringBackend}->toArray(); + $backendConfig['name'] = $monitoringBackend; + $this->populate($backendConfig); + } + } + + /** + * @see Form::createElements() + */ + public function createElements(array $formData) + { + $resourceType = isset($formData['type']) ? $formData['type'] : key($this->resources); + + $resourceTypes = array(); + if ($resourceType === 'ido' || array_key_exists('ido', $this->resources)) { + $resourceTypes['ido'] = 'IDO Backend'; + } + if ($resourceType === 'statusdat' || array_key_exists('statusdat', $this->resources)) { + $resourceTypes['statusdat'] = 'Status.dat'; + } + if ($resourceType === 'livestatus' || array_key_exists('livestatus', $this->resources)) { + $resourceTypes['livestatus'] = 'Livestatus'; + } + + $this->addElement( + 'checkbox', + 'disabled', + array( + 'required' => true, + 'label' => t('Disable This Backend') + ) + ); + $this->addElement( + 'text', + 'name', + array( + 'required' => true, + 'label' => t('Backend Name'), + 'description' => t('The identifier of this backend') + ) + ); + $this->addElement( + 'select', + 'type', + array( + 'required' => true, + 'autosubmit' => true, + 'label' => t('Backend Type'), + 'description' => t('The data source used for retrieving monitoring information'), + 'multiOptions' => $resourceTypes, + 'value' => $resourceType + ) + ); + $this->addElement( + 'select', + 'resource', + array( + 'required' => true, + 'label' => t('Resource'), + 'description' => t('The resource to use'), + 'multiOptions' => $this->resources[$resourceType] + ) + ); + } +} diff --git a/modules/monitoring/application/forms/Config/BackendForm.php b/modules/monitoring/application/forms/Config/BackendForm.php deleted file mode 100644 index f74c9bbaf..000000000 --- a/modules/monitoring/application/forms/Config/BackendForm.php +++ /dev/null @@ -1,125 +0,0 @@ -setName('form_config_monitoring_backends'); - $this->setSubmitLabel(t('Save Changes')); - } - - /** - * @see Form::createElements() - */ - public function createElements(array $formData) - { - return array( - $this->createElement( - 'text', - 'name', - array( - 'required' => true, - 'label' => t('Backend Name'), - 'helptext' => t('The identifier of this backend') - ) - ), - $this->createElement( - 'select', - 'type', - array( - 'required' => true, - 'class' => 'autosubmit', - 'label' => t('Backend Type'), - 'helptext' => t('The data source used for retrieving monitoring information'), - 'multiOptions' => array( - 'ido' => 'IDO Backend', - 'statusdat' => 'Status.dat', - 'livestatus' => 'Livestatus' - ) - ) - ), - $this->createElement( - 'select', - 'resource', - array( - 'required' => true, - 'label' => t('Resource'), - 'helptext' => t('The resource to use'), - 'multiOptions' => $this->getResourcesByType( - false === isset($formData['type']) || $formData['type'] === 'ido' ? 'db' : $formData['type'] - ) - ) - ), - $this->createElement( - 'checkbox', - 'disabled', - array( - 'required' => true, - 'label' => t('Disable This Backend') - ) - ) - ); - } - - /** - * Return the backend configuration values and its name - * - * The first value is the name and the second one the values as array. - * - * @return array - */ - public function getBackendConfig() - { - $values = $this->getValues(); - $name = $values['name']; - - if ($values['disabled'] == '0') { - unset($values['disabled']); - } - - unset($values['name']); - return array($name, $values); - } - - /** - * Populate the form with the given configuration values - * - * @param string $name The name of the backend - * @param array $config The configuration values - */ - public function setBackendConfig($name, array $config) - { - $config['name'] = $name; - $this->populate($config); - } - - /** - * Return a list of all resources of the given type ready to be used as content for a select input - * - * @param string $type The type of resources to return - * - * @return array - */ - protected function getResourcesByType($type) - { - $backends = array(); - foreach (array_keys(ResourceFactory::getResourceConfigs($type)->toArray()) as $name) { - $backends[$name] = $name; - } - - return $backends; - } -} diff --git a/modules/monitoring/application/forms/Config/Instance/LocalInstanceForm.php b/modules/monitoring/application/forms/Config/Instance/LocalInstanceForm.php new file mode 100644 index 000000000..513ba2433 --- /dev/null +++ b/modules/monitoring/application/forms/Config/Instance/LocalInstanceForm.php @@ -0,0 +1,37 @@ +setName('form_config_monitoring_instance_local'); + } + + /** + * @see Form::createElements() + */ + public function createElements(array $formData) + { + $this->addElement( + 'text', + 'path', + array( + 'required' => true, + 'label' => t('Local Filepath'), + 'value' => '/usr/local/icinga/var/rw/icinga.cmd', + 'description' => t('The file path where the icinga commandpipe can be found') + ) + ); + + return $this; + } +} diff --git a/modules/monitoring/application/forms/Config/Instance/RemoteInstanceForm.php b/modules/monitoring/application/forms/Config/Instance/RemoteInstanceForm.php new file mode 100644 index 000000000..0e78a0aec --- /dev/null +++ b/modules/monitoring/application/forms/Config/Instance/RemoteInstanceForm.php @@ -0,0 +1,68 @@ +setName('form_config_monitoring_instance_remote'); + } + + /** + * @see Form::createElements() + */ + public function createElements(array $formData) + { + $this->addElement( + 'text', + 'host', + array( + 'required' => true, + 'label' => t('Remote Host'), + 'description' => t( + 'Enter the hostname or address of the machine on which the icinga instance is running' + ) + ) + ); + $this->addElement( + new Number( + array( + 'required' => true, + 'name' => 'port', + 'label' => t('Remote SSH Port'), + 'description' => t('Enter the ssh port to use for connecting to the remote icinga instance'), + 'value' => 22 + ) + ) + ); + $this->addElement( + 'text', + 'user', + array( + 'required' => true, + 'label' => t('Remote SSH User'), + 'description' => t( + 'Enter the username to use for connecting to the remote machine or leave blank for default' + ) + ) + ); + $this->addElement( + 'text', + 'path', + array( + 'required' => true, + 'label' => t('Remote Filepath'), + 'value' => '/usr/local/icinga/var/rw/icinga.cmd', + 'description' => t('The file path where the icinga commandpipe can be found') + ) + ); + + return $this; + } +} diff --git a/modules/monitoring/application/forms/Config/InstanceConfigForm.php b/modules/monitoring/application/forms/Config/InstanceConfigForm.php new file mode 100644 index 000000000..6f8d04764 --- /dev/null +++ b/modules/monitoring/application/forms/Config/InstanceConfigForm.php @@ -0,0 +1,209 @@ +setName('form_config_monitoring_instance'); + $this->setSubmitLabel(t('Save Changes')); + } + + /** + * Return a form object for the given instance type + * + * @param string $type The instance type for which to return a form + * + * @return Form + * + * @throws InvalidArgumentException In case the given instance type is invalid + */ + public function getInstanceForm($type) + { + if ($type === 'local') { + return new LocalInstanceForm(); + } elseif ($type === 'remote') { + return new RemoteInstanceForm(); + } else { + throw new InvalidArgumentException(sprintf(t('Invalid instance type "%s" provided'), $type)); + } + } + + /** + * Add a new instance + * + * The resource to add is identified by the array-key `name'. + * + * @param array $values The values to extend the configuration with + * + * @return self + * + * @throws InvalidArgumentException In case the resource already exists + */ + public function add(array $values) + { + $name = isset($values['name']) ? $values['name'] : ''; + if (! $name) { + throw new InvalidArgumentException(t('Instance name missing')); + } elseif ($this->config->get($name) !== null) { + throw new InvalidArgumentException(t('Instance already exists')); + } + + unset($values['name']); + $this->config->{$name} = $values; + return $this; + } + + /** + * Edit an existing instance + * + * @param string $name The name of the resource to edit + * @param array $values The values to edit the configuration with + * + * @return array The edited resource configuration + * + * @throws InvalidArgumentException In case the resource name is missing or invalid + */ + public function edit($name, array $values) + { + if (! $name) { + throw new InvalidArgumentException(t('Old instance name missing')); + } elseif (! ($newName = isset($values['name']) ? $values['name'] : '')) { + throw new InvalidArgumentException(t('New instance name missing')); + } elseif (! ($instanceConfig = $this->config->get($name))) { + throw new InvalidArgumentException(t('Unknown instance name provided')); + } + + unset($values['name']); + unset($this->config->{$name}); + $this->config->{$newName} = array_merge($instanceConfig->toArray(), $values); + return $this->config->{$newName}; + } + + /** + * Remove a instance + * + * @param string $name The name of the resource to remove + * + * @return array The removed resource confguration + * + * @throws InvalidArgumentException In case the resource name is missing or invalid + */ + public function remove($name) + { + if (! $name) { + throw new InvalidArgumentException(t('Instance name missing')); + } elseif (! ($instanceConfig = $this->config->get($name))) { + throw new InvalidArgumentException(t('Unknown instance name provided')); + } + + unset($this->config->{$name}); + return $instanceConfig; + } + + /** + * @see Form::onSuccess() + */ + public function onSuccess(Request $request) + { + $instanceName = $request->getQuery('instance'); + + try { + if ($instanceName === null) { // create new instance + $this->add($this->getValues()); + $message = t('Instance "%s" created successfully.'); + } else { // edit existing instance + $this->edit($instanceName, $this->getValues()); + $message = t('Instance "%s" edited successfully.'); + } + } catch (InvalidArgumentException $e) { + Notification::error($e->getMessage()); + return; + } + + if ($this->save()) { + Notification::success(sprintf($message, $this->getElement('name')->getValue())); + } else { + return false; + } + } + + /** + * @see Form::onRequest() + * + * @throws ConfigurationError In case the instance name is missing or invalid + */ + public function onRequest(Request $request) + { + $instanceName = $request->getQuery('instance'); + if ($instanceName !== null) { + if (! $instanceName) { + throw new ConfigurationError(t('Instance name missing')); + } elseif (false === isset($this->config->{$instanceName})) { + throw new ConfigurationError(t('Unknown instance name provided')); + } + + $instanceConfig = $this->config->{$instanceName}->toArray(); + $instanceConfig['name'] = $instanceName; + if (isset($instanceConfig['host'])) { + // Necessary as we have no config directive for setting the instance's type + $instanceConfig['type'] = 'remote'; + } + $this->populate($instanceConfig); + } + } + + /** + * @see Form::createElements() + */ + public function createElements(array $formData) + { + $instanceType = isset($formData['type']) ? $formData['type'] : 'local'; + + $this->addElement( + 'text', + 'name', + array( + 'required' => true, + 'label' => t('Instance Name') + ) + ); + $this->addElement( + 'select', + 'type', + array( + 'required' => true, + 'ignore' => true, + 'autosubmit' => true, + 'label' => t('Instance Type'), + 'description' => t( + 'When configuring a remote host, you need to setup passwordless key authentication' + ), + 'multiOptions' => array( + 'local' => t('Local Command Pipe'), + 'remote' => t('Remote Command Pipe') + ), + 'value' => $instanceType + ) + ); + + $this->addElements($this->getInstanceForm($instanceType)->createElements($formData)->getElements()); + } +} diff --git a/modules/monitoring/application/forms/Config/InstanceForm.php b/modules/monitoring/application/forms/Config/InstanceForm.php deleted file mode 100644 index 3794e3c54..000000000 --- a/modules/monitoring/application/forms/Config/InstanceForm.php +++ /dev/null @@ -1,156 +0,0 @@ -setName('form_config_monitoring_instances'); - $this->setSubmitLabel(t('Save Changes')); - } - - /** - * @see Form::createElements() - */ - public function createElements(array $formData) - { - $elements = array( - $this->createElement( - 'text', - 'name', - array( - 'required' => true, - 'label' => t('Instance Name') - ) - ), - $this->createElement( - 'select', - 'type', - array( - 'required' => true, - 'ignore' => true, - 'label' => t('Instance Type'), - 'class' => 'autosubmit', - 'helptext' => t( - 'When configuring a remote host, you need to setup passwordless key authentication' - ), - 'multiOptions' => array( - 'local' => t('Local Command Pipe'), - 'remote' => t('Remote Command Pipe') - ) - ) - ) - ); - - if (isset($formData['type']) && $formData['type'] === 'remote') { - $elements[] = $this->createElement( - 'text', - 'host', - array( - 'required' => true, - 'label' => t('Remote Host'), - 'helptext' => t( - 'Enter the hostname or address of the machine on which the icinga instance is running' - ) - ) - ); - $elements[] = new Number( - array( - 'required' => true, - 'name' => 'port', - 'label' => t('Remote SSH Port'), - 'helptext' => t('Enter the ssh port to use for connecting to the remote icinga instance'), - 'value' => 22, - 'decorators' => array( // The order is important! - 'ViewHelper', - 'Errors', - new ElementWrapper(), - new HelpText() - ) - ) - ); - $elements[] = $this->createElement( - 'text', - 'user', - array( - 'required' => true, - 'label' => t('Remote SSH User'), - 'helptext' => t( - 'Enter the username to use for connecting to the remote machine or leave blank for default' - ) - ) - ); - } else { - // TODO(5967,5525): Without this element, switching the type to "local" causes - // the form to be processed as it's complete in that case. - $elements[] = $this->createElement( - 'hidden', - 'hitchhiker', - array( - 'required' => true, - 'ignore' => true, - 'value' => 'Arthur' - ) - ); - } - - $elements[] = $this->createElement( - 'text', - 'path', - array( - 'required' => true, - 'label' => t('Pipe Filepath'), - 'value' => '/usr/local/icinga/var/rw/icinga.cmd', - 'helptext' => t('The file path where the icinga commandpipe can be found') - ) - ); - return $elements; - } - - /** - * Return the instance configuration values and its name - * - * The first value is the name and the second one the values as array. - * - * @return array - */ - public function getInstanceConfig() - { - $values = $this->getValues(); - $name = $values['name']; - unset($values['name']); - return array($name, $values); - } - - /** - * Populate the form with the given configuration values - * - * @param string $name The name of the instance - * @param array $config The configuration values - */ - public function setInstanceConfig($name, array $config) - { - $config['name'] = $name; - - if (isset($config['host'])) { - // Necessary as we have no config directive for setting the instance's type - $config['type'] = 'remote'; - } - - $this->populate($config); - } -} diff --git a/modules/monitoring/application/forms/Config/SecurityConfigForm.php b/modules/monitoring/application/forms/Config/SecurityConfigForm.php new file mode 100644 index 000000000..a164766cc --- /dev/null +++ b/modules/monitoring/application/forms/Config/SecurityConfigForm.php @@ -0,0 +1,66 @@ +setName('form_config_monitoring_security'); + $this->setSubmitLabel(t('Save Changes')); + } + + /** + * @see Form::onSuccess() + */ + public function onSuccess(Request $request) + { + $this->config->security = $this->getValues(); + + if ($this->save()) { + Notification::success(t('New security configuration has successfully been stored')); + } else { + return false; + } + } + + /** + * @see Form::onRequest() + */ + public function onRequest(Request $request) + { + if (isset($this->config->security)) { + $this->populate($this->config->security->toArray()); + } + } + + /** + * @see Form::createElements() + */ + public function createElements(array $formData) + { + $this->addElement( + 'text', + 'protected_customvars', + array( + 'required' => true, + 'label' => 'Protected Custom Variables', + 'description' => 'Comma separated case insensitive list of protected custom variables.' + . ' Use * as a placeholder for zero or more wildcard characters.' + . ' Existance of those custom variables will be shown, but their values will be masked.' + ) + ); + } +} diff --git a/modules/monitoring/application/forms/Config/SecurityForm.php b/modules/monitoring/application/forms/Config/SecurityForm.php deleted file mode 100644 index 48368d0f1..000000000 --- a/modules/monitoring/application/forms/Config/SecurityForm.php +++ /dev/null @@ -1,42 +0,0 @@ -setName('form_config_monitoring_security'); - $this->setSubmitLabel(t('Save Changes')); - } - - /** - * @see Form::createElements() - */ - public function createElements(array $formData) - { - return array( - $this->createElement( - 'text', - 'protected_customvars', - array( - 'label' => 'Protected Custom Variables', - 'required' => true, - 'helptext' => 'Comma separated case insensitive list of protected custom variables.' - . ' Use * as a placeholder for zero or more wildcard characters.' - . ' Existance of those custom variables will be shown, but their values will be masked.' - ) - ) - ); - } -} diff --git a/modules/monitoring/application/views/scripts/config/index.phtml b/modules/monitoring/application/views/scripts/config/index.phtml index 41d2748d5..34f47a0b4 100644 --- a/modules/monitoring/application/views/scripts/config/index.phtml +++ b/modules/monitoring/application/views/scripts/config/index.phtml @@ -1,99 +1,70 @@ -{$element}) && - get_class($this->{$element}) === 'Icinga\Exception\NotReadableError') { - $fileNotReadable[$element] = $this->{$element}->getMessage(); - } else { - $fileNotReadable[$element] = false; - } -} -?> -
- tabs->render($this); ?> +
- -

Monitoring Backends

- - messageBox)): ?> - messageBox->render() ?> - - -

- - icon('create.png'); ?> Create New Monitoring Backend - -

- - - - - - - - backends as $backendName => $config): ?> - $backendName)); - $editUrl = Url::fromPath('/monitoring/config/editbackend', array('backend' => $backendName)); - ?> - - - - - - -
Monitoring BackendRemove
- icon('edit.png'); ?> escape($backendName); ?> - (Type: escape($config['type'] === 'ido' ? 'IDO' : ucfirst($config['type'])); ?>) - - icon('remove.png'); ?> -
- -

- escape($fileNotReadable['backends']) ?> -

- - - -

Monitoring Instances

- -

- - icon('create.png'); ?> Create New Instance - -

- - - - - - - - instances as $instanceName => $config): ?> - $instanceName)); - $editUrl = Url::fromPath('/monitoring/config/editinstance', array('instance' => $instanceName)); - ?> - - - - - - -
InstanceRemove
- icon('edit.png'); ?> escape($instanceName); ?> - (Type: ) - - icon('remove.png'); ?> -
- -

- escape($fileNotReadable['instances']) ?> -

- -
+

Monitoring Backends

+

+ + icon('create.png'); ?> translate('Create New Monitoring Backend'); ?> + +

+ + + + + + +backendsConfig as $backendName => $config): ?> + + + + + + +
translate('Monitoring Backend'); ?>translate('Remove'); ?>
+ + icon('edit.png'); ?> escape($backendName); ?> + + (translate('Type: %s'), + $this->escape($config->type === 'ido' ? 'IDO' : ucfirst($config->type)) + ); ?>) + + + icon('remove.png'); ?> + +
+

Monitoring Instances

+

+ + icon('create.png'); ?> translate('Create New Instance'); ?> + +

+ + + + + + +instancesConfig as $instanceName => $config): ?> + + + + + + +
translate('Instance'); ?>translate('Remove'); ?>
+ + icon('edit.png'); ?> escape($instanceName); ?> + + (translate('Type: %s'), + $config->host !== null ? $this->translate('Remote') : $this->translate('Local') + ); ?>) + + + icon('remove.png'); ?> + +
+ \ No newline at end of file diff --git a/modules/monitoring/application/views/scripts/config/removeinstance.phtml b/modules/monitoring/application/views/scripts/config/removeinstance.phtml index 586452173..306d41815 100644 --- a/modules/monitoring/application/views/scripts/config/removeinstance.phtml +++ b/modules/monitoring/application/views/scripts/config/removeinstance.phtml @@ -1,4 +1,4 @@

translate('Remove Existing Instance'); ?>

-

Are you sure you want to remove the instance escape($name); ?>?

-

If you have still any environments or views referring to this instance, you won't be able to send commands anymore after deletion.

+

translate('Are you sure you want to remove this instance?'); ?>

+

translate('If you have still any environments or views referring to this instance, you won\'t be able to send commands anymore after deletion.'); ?>

\ No newline at end of file diff --git a/modules/monitoring/library/Monitoring/Timeline/TimeLine.php b/modules/monitoring/library/Monitoring/Timeline/TimeLine.php index be3820e19..3a795df32 100644 --- a/modules/monitoring/library/Monitoring/Timeline/TimeLine.php +++ b/modules/monitoring/library/Monitoring/Timeline/TimeLine.php @@ -11,7 +11,6 @@ use Icinga\Exception\IcingaException; use IteratorAggregate; use Icinga\Data\Filter\Filter; use Icinga\Web\Hook; -use Icinga\Web\Session; use Icinga\Web\Session\SessionNamespace; use Icinga\Module\Monitoring\DataView\DataView; diff --git a/modules/monitoring/library/Monitoring/Web/Widget/TimelineIntervalBox.php b/modules/monitoring/library/Monitoring/Web/Widget/TimelineIntervalBox.php index 4cab3517d..4d6dbdad5 100644 --- a/modules/monitoring/library/Monitoring/Web/Widget/TimelineIntervalBox.php +++ b/modules/monitoring/library/Monitoring/Web/Widget/TimelineIntervalBox.php @@ -84,6 +84,7 @@ class TimelineIntervalBox extends AbstractWidget $form = new Form(); $form->setAttrib('class', 'inline'); $form->setMethod('GET'); + $form->setUidDisabled(); $form->setTokenDisabled(); $form->setName($this->name); $form->addElement( @@ -92,7 +93,7 @@ class TimelineIntervalBox extends AbstractWidget array( 'label' => 'Timeline Interval', 'multiOptions' => $this->values, - 'class' => 'autosubmit' + 'autosubmit' => true ) ); diff --git a/modules/monitoring/test/php/application/forms/Command/AcknowledgeFormTest.php b/modules/monitoring/test/php/application/forms/Command/AcknowledgeFormTest.php deleted file mode 100644 index 32d8e35d3..000000000 --- a/modules/monitoring/test/php/application/forms/Command/AcknowledgeFormTest.php +++ /dev/null @@ -1,111 +0,0 @@ -createForm( - self::FORM_CLASS, - array( - 'author' => 'Author', - 'comment' => 'Comment', - 'persistent' => '0', - 'expire' => '0', - 'sticky' => '0', - 'notify' => '0', - 'btn_submit' => 'Submit' - ) - ); - $this->assertTrue( - $form->isSubmittedAndValid(), - 'Legal request data without expire time must be considered valid' - ); - - $formWithExpireTime = $this->createForm( - self::FORM_CLASS, - array( - 'author' => 'Author', - 'comment' => 'Comment', - 'persistent' => '0', - 'expire' => '1', - 'expiretime' => '10/07/2013 5:32 PM', - 'sticky' => '0', - 'notify' => '0', - 'btn_submit' => 'Submit' - ) - ); - $this->assertTrue( - $formWithExpireTime->isSubmittedAndValid(), - 'Legal request data with expire time must be considered valid' - ); - } - - public function testFormInvalidWhenCommentMissing() - { - $form = $this->createForm( - self::FORM_CLASS, - array( - 'author' => 'Author', - 'comment' => '', - 'persistent' => '0', - 'expire' => '0', - 'sticky' => '0', - 'notify' => '0', - 'btn_submit' => 'Submit' - ) - ); - $this->assertFalse( - $form->isSubmittedAndValid(), - 'Missing comment must be considered not valid' - ); - } - - public function testFormInvalidWhenExpireTimeMissingAndExpireSet() - { - $form = $this->createForm( - self::FORM_CLASS, - array( - 'author' => 'Author', - 'comment' => 'Comment', - 'persistent' => '0', - 'expire' => '1', - 'sticky' => '0', - 'notify' => '0', - 'btn_submit' => 'Submit' - ) - ); - $this->assertFalse( - $form->isSubmittedAndValid(), - 'If expire is set and expire time is missing, the form must not be valid' - ); - } - - public function testFormInvalidWhenExpireTimeIsIncorrectAndExpireSet() - { - $form = $this->createForm( - self::FORM_CLASS, - array( - 'author' => 'Author', - 'comment' => 'Comment', - 'persistent' => '0', - 'expire' => '1', - 'expiretime' => 'Not a date', - 'sticky' => '0', - 'notify' => '0', - 'btn_submit' => 'Submit' - ) - ); - $this->assertFalse( - $form->isSubmittedAndValid(), - 'If expire is set and expire time is incorrect, the form must not be valid' - ); - } -} diff --git a/modules/monitoring/test/php/application/forms/Command/CommentFormTest.php b/modules/monitoring/test/php/application/forms/Command/CommentFormTest.php deleted file mode 100644 index 3228af399..000000000 --- a/modules/monitoring/test/php/application/forms/Command/CommentFormTest.php +++ /dev/null @@ -1,64 +0,0 @@ -createForm( - self::FORM_CLASS, - array( - 'author' => 'Author', - 'comment' => 'Comment', - 'sticky' => '0', - 'btn_submit' => 'Submit' - ) - ); - $this->assertTrue( - $form->isSubmittedAndValid(), - 'Legal request data must be considered valid' - ); - } - - public function testFormInvalidWhenCommentMissing() - { - $form = $this->createForm( - self::FORM_CLASS, - array( - 'author' => 'Author', - 'comment' => '', - 'sticky' => '0', - 'btn_submit' => 'Submit' - - ) - ); - $this->assertFalse( - $form->isSubmittedAndValid(), - 'Missing comment must be considered not valid' - ); - } - - public function testFormInvalidWhenAuthorMissing() - { - $form = $this->createForm( - self::FORM_CLASS, - array( - 'author' => '', - 'comment' => 'Comment', - 'sticky' => '0', - 'btn_submit' => 'Submit' - ) - ); - $this->assertFalse( - $form->isSubmittedAndValid(), - 'Missing author must be considered not valid' - ); - } -} diff --git a/modules/monitoring/test/php/application/forms/Command/CustomNotificationFormTest.php b/modules/monitoring/test/php/application/forms/Command/CustomNotificationFormTest.php deleted file mode 100644 index 9c03ff3ec..000000000 --- a/modules/monitoring/test/php/application/forms/Command/CustomNotificationFormTest.php +++ /dev/null @@ -1,28 +0,0 @@ -createForm( - self::FORM_CLASS, - array( - 'author' => 'Author', - 'comment' => '', - 'btn_submit' => 'Submit' - ) - ); - $this->assertFalse( - $form->isSubmittedAndValid(), - 'Missing comment must be considered not valid' - ); - } -} diff --git a/modules/monitoring/test/php/application/forms/Command/DelayNotificationFormTest.php b/modules/monitoring/test/php/application/forms/Command/DelayNotificationFormTest.php deleted file mode 100644 index 3a955f191..000000000 --- a/modules/monitoring/test/php/application/forms/Command/DelayNotificationFormTest.php +++ /dev/null @@ -1,58 +0,0 @@ -createForm( - self::FORM_CLASS, - array( - 'minutes' => '', - 'btn_submit' => 'Submit' - ) - ); - $this->assertFalse( - $form->isSubmittedAndValid(), - 'Missing notification delay must be considered invalid' - ); - } - - public function testFormInvalidWhenNotificationDelayNaN() - { - $form = $this->createForm( - self::FORM_CLASS, - array( - 'minutes' => 'A String', - 'btn_submit' => 'Submit' - ) - ); - $this->assertFalse( - $form->isSubmittedAndValid(), - 'Incorrect notification delay, i.e. NaN must be considered invalid' - ); - } - - public function testFormInvalidWhenNotificationDelayOverflows() - { - $form = $this->createForm( - self::FORM_CLASS, - array( - 'minutes' => DelayNotificationForm::MAX_DELAY + 1, - 'btn_submit' => 'Submit' - ) - ); - $this->assertFalse( - $form->isSubmittedAndValid(), - 'Notification delay bigger than constant "DelayNotificationForm::MAX_DELAY" must be considered invalid' - ); - } -} diff --git a/modules/monitoring/test/php/application/forms/Command/RescheduleNextCheckFormTest.php b/modules/monitoring/test/php/application/forms/Command/RescheduleNextCheckFormTest.php deleted file mode 100644 index 72a4914f5..000000000 --- a/modules/monitoring/test/php/application/forms/Command/RescheduleNextCheckFormTest.php +++ /dev/null @@ -1,54 +0,0 @@ -createForm( - self::FORM_CLASS, - array( - 'checktime' => '2013-24-12 17:30:00', - 'forcecheck' => 0, - 'btn_submit' => 'Submit' - ) - ); - $this->assertFalse( - $form->isSubmittedAndValid(), - 'Asserting a logically incorrect checktime as invalid' - ); - - $form2 = $this->createForm( - self::FORM_CLASS, - array( - 'checktime' => 'Captain Morgan', - 'forcecheck' => 1, - 'btn_submit' => 'Submit' - ) - ); - $this->assertFalse( - $form2->isSubmittedAndValid(), - 'Providing arbitrary strings as checktime must be considered invalid' - ); - - $form3 = $this->createForm( - self::FORM_CLASS, - array( - 'checktime' => '', - 'forcecheck' => 0, - 'btn_submit' => 'Submit' - ) - ); - $this->assertFalse( - $form3->isSubmittedAndValid(), - 'Missing checktime must be considered invalid' - ); - } -} diff --git a/modules/monitoring/test/php/application/forms/Command/ScheduleDowntimeFormTest.php b/modules/monitoring/test/php/application/forms/Command/ScheduleDowntimeFormTest.php deleted file mode 100644 index 5c7138b17..000000000 --- a/modules/monitoring/test/php/application/forms/Command/ScheduleDowntimeFormTest.php +++ /dev/null @@ -1,356 +0,0 @@ -createForm(self::FORM_CLASS); - $formFixed->setCurrentDowntimes(array('foo')); - $formFixed->buildForm(); - $formFlexible = $this->createForm( - self::FORM_CLASS, - array( - 'type' => 'flexible' - ) - ); - $formFlexible->setCurrentDowntimes(array('foo')); - $formFlexible->buildForm(); - - $form = $this->createForm(self::FORM_CLASS); - $form->setCurrentDowntimes(array('foo')); - $form->setWithChildren(true); - $form->buildForm(); - } - - public function testCorrectValidationWithChildrend() - { - $form = $this->createForm( - self::FORM_CLASS, - array( - 'author' => 'TEST_AUTHOR', - 'comment' => 'DING DING', - 'triggered' => '0', - 'starttime' => '17/07/2013 10:30 AM', - 'endtime' => '18/07/2013 10:30 AM', - 'type' => ScheduleDowntimeForm::TYPE_FIXED, - 'hours' => '', - 'minutes' => '', - 'btn_submit' => 'foo', - ) - ); - $form->setWithChildren(true); - $form->setCurrentDowntimes(array('foo')); - - $this->assertTrue( - $form->isSubmittedAndValid(), - 'Asserting a correct fixed downtime form to be considered valid' - ); - $form = $this->createForm( - self::FORM_CLASS, - array( - 'author' => 'TEST_AUTHOR', - 'comment' => 'DING DING', - 'triggered' => '0', - 'starttime' => '17/07/2013 10:30 AM', - 'endtime' => '18/07/2013 10:30 AM', - 'type' => ScheduleDowntimeForm::TYPE_FLEXIBLE, - 'hours' => '10', - 'minutes' => '10', - 'btn_submit' => 'foo' - ) - ); - $form->setWithChildren(true); - $form->setCurrentDowntimes(array('foo')); - - $this->assertTrue( - $form->isSubmittedAndValid(), - 'Asserting a correct flexible downtime form to be considered valid' - ); - } - - public function testMissingFlexibleDurationRecognition() - { - $form = $this->createForm( - self::FORM_CLASS, - array( - 'author' => 'TEST_AUTHOR', - 'comment' => 'DING DING', - 'triggered' => '0', - 'starttime' => '17/07/2013 10:30 AM', - 'endtime' => '18/07/2013 10:30 AM', - 'type' => ScheduleDowntimeForm::TYPE_FLEXIBLE, - 'hours' => '', - 'minutes' => '', - ) - ); - $form->setWithChildren(true); - $form->setCurrentDowntimes(array('foo')); - - $this->assertFalse( - $form->isSubmittedAndValid(), - 'Assert missing hours and minutes in downtime form to cause failing validation' - ); - } - - public function testMissingAuthorRecognition() - { - $form = $this->createForm( - self::FORM_CLASS, - array( - 'author' => '', - 'comment' => 'DING DING', - 'triggered' => '0', - 'starttime' => '17/07/2013 10:30 AM', - 'endtime' => '18/07/2013 10:30 AM', - 'type' => ScheduleDowntimeForm::TYPE_FIXED, - 'hours' => '', - 'minutes' => '', - ) - ); - $form->setWithChildren(true); - $form->setCurrentDowntimes(array('foo')); - - $this->assertFalse( - $form->isSubmittedAndValid(), - 'Assert missing author to cause validation errors in fixed downtime' - ); - } - - public function testMissingCommentRecognition() - { - $form = $this->createForm( - self::FORM_CLASS, - array( - 'author' => 'OK', - 'comment' => '', - 'triggered' => '0', - 'starttime' => '17/07/2013 10:30 AM', - 'endtime' => '18/07/2013 10:30 AM', - 'type' => ScheduleDowntimeForm::TYPE_FIXED, - 'hours' => '', - 'minutes' => '', - ) - ); - $form->setWithChildren(true); - $form->setCurrentDowntimes(array('foo')); - - $this->assertFalse( - $form->isSubmittedAndValid(), - 'Assert missing comment to cause validation errors in fixed downtime' - ); - } - - public function testInvalidTriggeredFieldValueRecognition() - { - $form = $this->createForm( - self::FORM_CLASS, - array( - 'author' => 'OK', - 'comment' => 'OK', - 'triggered' => 'HAHA', - 'starttime' => '17/07/2013 10:30 AM', - 'endtime' => '18/07/2013 10:30 AM', - 'type' => ScheduleDowntimeForm::TYPE_FIXED, - 'hours' => '', - 'minutes' => '', - ) - ); - $form->setWithChildren(true); - $form->setCurrentDowntimes(array('foo')); - - $this->assertFalse( - $form->isSubmittedAndValid(), - 'Assert invalid trigger field to cause validation to fail' - ); - } - - public function testInvalidStartTimeRecognition() - { - $form = $this->createForm( - self::FORM_CLASS, - array( - 'author' => 'OK', - 'comment' => 'OK', - 'triggered' => '0', - 'starttime' => '17/07/2013', - 'endtime' => '18/07/2013 10:30 AM', - 'type' => ScheduleDowntimeForm::TYPE_FIXED, - 'hours' => '', - 'minutes' => '', - ) - ); - $form->setWithChildren(true); - $form->setCurrentDowntimes(array('foo')); - - $this->assertFalse( - $form->isSubmittedAndValid(), - 'Assert incorrect start time to cause validation errors in fixed downtime' - ); - } - - public function testInvalidEndTimeRecognition() - { - $form = $this->createForm( - self::FORM_CLASS, - array( - 'author' => 'OK', - 'comment' => 'OK', - 'triggered' => '0', - 'starttime' => '17/07/2013 10:30 AM', - 'endtime' => 'DING', - 'type' => ScheduleDowntimeForm::TYPE_FIXED, - 'hours' => '', - 'minutes' => '', - ) - ); - $form->setWithChildren(true); - $form->setCurrentDowntimes(array('foo')); - - $this->assertFalse( - $form->isSubmittedAndValid(), - 'Assert invalid endtime to cause validation errors in fixed downtime' - ); - } - - public function testInvalidHoursValueRecognitionInFlexibleDowntime() - { - $form = $this->createForm( - self::FORM_CLASS, - array( - 'author' => 'OK', - 'comment' => 'OK', - 'triggered' => '0', - 'starttime' => '17/07/2013 10:30 AM', - 'endtime' => '18/07/2013 10:30 AM', - 'type' => ScheduleDowntimeForm::TYPE_FLEXIBLE, - 'hours' => '-1', - 'minutes' => '12', - ) - ); - $form->setWithChildren(true); - $form->setCurrentDowntimes(array('foo')); - - $this->assertFalse( - $form->isSubmittedAndValid(), - 'Assert negative hours to cause validation errors in flexible downtime' - ); - } - - public function testInvalidMinutesValueRecognitionInFlexibleDowntime() - { - $form = $this->createForm( - self::FORM_CLASS, - array( - 'author' => 'OK', - 'comment' => 'OK', - 'triggered' => '0', - 'starttime' => '17/07/2013 10:30 AM', - 'endtime' => '18/07/2013 10:30 AM', - 'type' => ScheduleDowntimeForm::TYPE_FLEXIBLE, - 'hours' => '12', - 'minutes' => 'DING', - ) - ); - $form->setWithChildren(true); - $form->setCurrentDowntimes(array('foo')); - - $this->assertFalse( - $form->isSubmittedAndValid(), - 'Assert non numeric valud to cause validation errors in flexible downtime ' - ); - - } - - public function testCorrectScheduleDowntimeWithoutChildrenForm() - { - $form = $this->createForm( - self::FORM_CLASS, - array( - 'author' => 'TEST_AUTHOR', - 'comment' => 'DING DING', - 'triggered' => '0', - 'starttime' => '17/07/2013 10:30 AM', - 'endtime' => '18/07/2013 10:30 AM', - 'type' => ScheduleDowntimeForm::TYPE_FIXED, - 'hours' => '', - 'minutes' => '', - 'btn_submit' => 'foo', - 'childobjects' => '0', - ) - ); - $form->setWithChildren(false); - $form->setCurrentDowntimes(array('foo')); - - $this->assertTrue( - $form->isSubmittedAndValid(), - 'Assert a correct schedule downtime without children form to be considered valid' - ); - } - - public function testIncorrectChildObjectsRecognition() { - $form = $this->createForm( - self::FORM_CLASS, - array( - 'author' => 'TEST_AUTHOR', - 'comment' => 'DING DING', - 'triggered' => '0', - 'starttime' => '17/07/2013 10:30 AM', - 'endtime' => '18/07/2013 10:30 AM', - 'type' => ScheduleDowntimeForm::TYPE_FIXED, - 'hours' => '', - 'minutes' => '', - 'childobjects' => 'AHA', - ) - ); - $form->setWithChildren(false); - $form->setCurrentDowntimes(array('foo')); - - $this->assertFalse( - $form->isSubmittedAndValid(), - 'Assert and incorrect (non-numeric) childobjects value to cause validation errors' - ); - - $form = $this->createForm( - self::FORM_CLASS, - array( - 'author' => 'TEST_AUTHOR', - 'comment' => 'DING DING', - 'triggered' => '0', - 'starttime' => '17/07/2013 10:30 AM', - 'endtime' => '18/07/2013 10:30 AM', - 'type' => ScheduleDowntimeForm::TYPE_FIXED, - 'hours' => '', - 'minutes' => '', - 'childobjects' => '4', - ) - ); - $form->setWithChildren(false); - $form->setCurrentDowntimes(array('foo')); - - $this->assertFalse( - $form->isSubmittedAndValid(), - 'Assert and incorrect (numeric) childobjects value to cause validation errors' - ); - } - - public function testTimeRange() - { - $form = $this->createForm(self::FORM_CLASS); - $form->setCurrentDowntimes(array('foo')); - $form->buildForm(); - - $time1 = $form->getElement('starttime')->getValue(); - $time2 = $form->getElement('endtime')->getValue(); - - $this->assertEquals(3600, ($time2 - $time1)); - } -} diff --git a/modules/monitoring/test/php/application/forms/Command/SubmitPassiveCheckResultTest.php b/modules/monitoring/test/php/application/forms/Command/SubmitPassiveCheckResultTest.php deleted file mode 100644 index 4c83294df..000000000 --- a/modules/monitoring/test/php/application/forms/Command/SubmitPassiveCheckResultTest.php +++ /dev/null @@ -1,117 +0,0 @@ -createForm(self::FORM_CLASS, array()); - - $form->setType(SubmitPassiveCheckResultForm::TYPE_SERVICE); - $options = $form->getOptions(); - $this->assertCount(4, $options, 'Assert correct number of states in service passive checks form'); - $this->assertEquals('OK', $options[0], 'Assert OK state to be available in service passive check form'); - $this->assertEquals( - 'WARNING', - $options[1], - 'Assert WARNING state to be available in service passive check form' - ); - $this->assertEquals( - 'CRITICAL', - $options[2], - 'Assert CRITICAL state to be available in service passive check form' - ); - $this->assertEquals( - 'UNKNOWN', - $options[3], - 'Assert UNKNOWN state to be available in service passive check form' - ); - $form->setType(SubmitPassiveCheckResultForm::TYPE_HOST); - $options = $form->getOptions(); - $this->assertCount(3, $options, 'Assert correct number of states in host passive checks form'); - $this->assertEquals('UP', $options[0], 'Assert UP state to be available in host passive check form'); - $this->assertEquals('DOWN', $options[1], 'Assert DOWN state to be available in host passive check form'); - $this->assertEquals( - 'UNREACHABLE', - $options[2], - 'Assert UNREACHABLE state to be available in host passive check form' - ); - } - - /** - * @expectedException Icinga\Exception\ProgrammingError - * @expectedExceptionMessage Type is not valid - */ - public function testMissingTypeThrowingException() - { - $form = $this->createForm(self::FORM_CLASS, array()); - $form->buildForm(); - } - - public function testCorrectFormCreation() - { - $form = $this->createForm(self::FORM_CLASS, array()); - $form->setType(SubmitPassiveCheckResultForm::TYPE_SERVICE); - $form->buildForm(); - } - - public function testCorrectServicePassiveCheckSubmission() - { - $form = $this->createForm( - self::FORM_CLASS, - array( - 'pluginstate' => 0, - 'checkoutput' => 'DING', - 'performancedata' => '', - 'btn_submit' => 'foo' - ) - ); - $form->setType(SubmitPassiveCheckResultForm::TYPE_SERVICE); - $this->assertTrue( - $form->isSubmittedAndValid(), - 'Assert a correct passive service check form to pass form validation' - ); - } - - public function testIncorrectCheckoutputRecognition() - { - $form = $this->createForm( - self::FORM_CLASS, - array( - 'pluginstate' => 0, - 'checkoutput' => '', - 'performancedata' => '' - ) - ); - $form->setType(SubmitPassiveCheckResultForm::TYPE_SERVICE); - $this->assertFalse( - $form->isSubmittedAndValid(), - 'Assert empty checkoutput to cause validation errors in passive service check ' - ); - } - - public function testIncorrectStateRecognition() - { - $form = $this->createForm( - self::FORM_CLASS, - array( - 'pluginstate' => 'LA', - 'checkoutput' => 'DING', - 'performancedata' => '' - ) - ); - $form->setType(SubmitPassiveCheckResultForm::TYPE_SERVICE); - $this->assertFalse( - $form->isSubmittedAndValid(), - 'Assert invalid (non-numeric) state to cause validation errors in passive service check' - ); - } -} diff --git a/modules/translation/library/Translation/Util/GettextTranslationHelper.php b/modules/translation/library/Translation/Util/GettextTranslationHelper.php index 68e07fbcd..be0497a31 100644 --- a/modules/translation/library/Translation/Util/GettextTranslationHelper.php +++ b/modules/translation/library/Translation/Util/GettextTranslationHelper.php @@ -271,6 +271,7 @@ class GettextTranslationHelper 'po_revision_date' => 'YEAR-MO-DA HO:MI+ZONE', 'translator_name' => 'FULL NAME', 'translator_mail' => 'EMAIL@ADDRESS', + 'language' => $this->locale, 'language_team_name' => 'LANGUAGE', 'language_team_url' => 'LL@li.org', 'charset' => self::FILE_ENCODING @@ -298,6 +299,9 @@ class GettextTranslationHelper $headerInfo['language_team_name'] = $languageInfo[1]; $headerInfo['language_team_url'] = $languageInfo[2]; } + if (preg_match('@Language: ([a-z]{2}_[A-Z]{2})@', $content, $languageInfo)) { + $headerInfo['language'] = $languageInfo[1]; + } } file_put_contents( @@ -321,6 +325,7 @@ class GettextTranslationHelper '"PO-Revision-Date: ' . $headerInfo['po_revision_date'] . '\n"', '"Last-Translator: ' . $headerInfo['translator_name'] . ' <' . $headerInfo['translator_mail'] . '>\n"', + '"Language: ' . $headerInfo['language'] . '\n"', '"Language-Team: ' . $headerInfo['language_team_name'] . ' <' . $headerInfo['language_team_url'] . '>\n"', '"MIME-Version: 1.0\n"', diff --git a/public/css/icinga/charts.less b/public/css/icinga/charts.less deleted file mode 100644 index 6164921df..000000000 --- a/public/css/icinga/charts.less +++ /dev/null @@ -1,11 +0,0 @@ -// {{{ICINGA_LICENSE_HEADER}}} -// {{{ICINGA_LICENSE_HEADER}}} - -/* Add hover effects to chart data */ -.chart-data:hover { - opacity: 0.85; -} - -.pie-data:hover { - opacity: 0.6; -} \ No newline at end of file diff --git a/public/css/icinga/widgets.less b/public/css/icinga/widgets.less index 761c2ca0e..f546443c4 100644 --- a/public/css/icinga/widgets.less +++ b/public/css/icinga/widgets.less @@ -174,6 +174,15 @@ ul.tree li a.error:hover { color: @colorCritical; } +/* Add hover effect to chart data */ +.chart-data:hover { + opacity: 0.85; +} + +.pie-data:hover { + opacity: 0.6; +} + /* charts should grow as much as possible but never beyond the current viewport's size */ .svg-container-responsive { padding: 1.5em; diff --git a/public/js/icinga/events.js b/public/js/icinga/events.js index 685b50423..a48336147 100644 --- a/public/js/icinga/events.js +++ b/public/js/icinga/events.js @@ -10,6 +10,8 @@ 'use strict'; + var activeMenuId; + var mouseX, mouseY; Icinga.Events = function (icinga) { @@ -133,22 +135,37 @@ if (!icinga.utils.elementsOverlap(arrow, el)) { return; } - var title = $(this).find('.tipsy-inner').html(); var atMouse = document.elementFromPoint(mouseX, mouseY); var nearestTip = $(atMouse) .closest('[original-title="' + title + '"]')[0]; if (nearestTip) { - console.log ('migrating orphan...'); var tipsy = $.data(nearestTip, 'tipsy'); tipsy.$tip = $(this); $.data(this, 'tipsy-pointee', nearestTip); } else { // doesn't match delete - console.log ('deleting orphan...'); $(this).remove(); } }); + + // restore menu state + if (activeMenuId) { + $('li.active', el).removeClass('active'); + + var $selectedMenu = $('#' + activeMenuId, el); + var $outerMenu = $selectedMenu.parent().closest('li'); + if ($outerMenu.size()) { + $selectedMenu = $outerMenu; + } + $selectedMenu.addClass('active'); + } else { + // store menu state + var $menus = $('[role="navigation"] li.active', el); + if ($menus.size()) { + activeMenuId = $menus[0].id; + } + } }, /** @@ -569,6 +586,7 @@ $li = $a.closest('li'); $('#menu .active').removeClass('active'); $li.addClass('active'); + activeMenuId = $($li).attr('id'); if ($li.hasClass('hover')) { $li.removeClass('hover'); } @@ -594,14 +612,22 @@ return false; } } else { + if (isMenuLink) { + activeMenuId = $(event.target).closest('li').attr('id'); + } $target = self.getLinkTargetFor($a); } // Load link URL icinga.loader.loadUrl(href, $target); - // Menu links should remove all but the first layout column if (isMenuLink) { + // update target url of the menu container to the clicked link + var menuDataUrl = icinga.utils.parseUrl($('#menu').data('icinga-url')); + menuDataUrl = icinga.utils.addUrlParams(menuDataUrl.path, { url: href }); + $('#menu').data('icinga-url', menuDataUrl); + + // Menu links should remove all but the first layout column icinga.ui.layout1col(); } @@ -687,6 +713,7 @@ $(document).off('mouseenter', 'li.dropdown', this.dropdownHover); $(document).off('mouseleave', 'li.dropdown', this.dropdownLeave); $(document).off('click', 'div.tristate .tristate-dummy', this.clickTriState); + $(document).off('mousemove'); }, destroy: function() { diff --git a/public/js/icinga/loader.js b/public/js/icinga/loader.js index f70bc0522..9d14ebb7f 100644 --- a/public/js/icinga/loader.js +++ b/public/js/icinga/loader.js @@ -673,8 +673,12 @@ } var origFocus = document.activeElement; - if (typeof containerId !== 'undefined' && autorefresh && origFocus && $(origFocus).closest('form').length && $container.has($(origFocus)) && $(origFocus).closest('#' + containerId).length && ! $(origFocus).hasClass('autosubmit')) { - this.icinga.logger.debug('Not changing content, form has focus'); + if ( + // Do not reload menu when search field has content + (containerId === 'menu' && $(origFocus).length && $(origFocus).val().length) + // TODO: remove once #7146 is solved + || (containerId !== 'menu' && typeof containerId !== 'undefined' && autorefresh && origFocus && $(origFocus).closest('form').length && $container.has($(origFocus)) && $(origFocus).closest('#' + containerId).length && ! $(origFocus).hasClass('autosubmit'))) { + this.icinga.logger.debug('Not changing content for ', containerId, ' form has focus'); return; } diff --git a/public/js/icinga/ui.js b/public/js/icinga/ui.js index d933844c9..f6ae29b35 100644 --- a/public/js/icinga/ui.js +++ b/public/js/icinga/ui.js @@ -10,9 +10,6 @@ 'use strict'; - // The currently hovered tooltip - var tooltip = null; - // Stores the icinga-data-url of the last focused table. var focusedTableDataUrl = null; diff --git a/public/js/icinga/utils.js b/public/js/icinga/utils.js index 1a6759d87..ba4d7a040 100644 --- a/public/js/icinga/utils.js +++ b/public/js/icinga/utils.js @@ -217,9 +217,9 @@ return false; } var at = aoff.top; - var ah = a.offsetHeight; + var ah = a.offsetHeight || (a.getBBox && a.getBBox().height); var al = aoff.left; - var aw = a.offsetWidth; + var aw = a.offsetWidth || (a.getBBox && a.getBBox().width); // b bounds var boff = $(b).offset(); @@ -227,9 +227,9 @@ return false; } var bt = boff.top; - var bh = b.offsetHeight; + var bh = b.offsetHeight || (b.getBBox && b.getBBox().height); var bl = boff.left; - var bw = b.offsetWidth; + var bw = b.offsetWidth || (b.getBBox && b.getBBox().width); return !(at > (bt + bh) || bt > (at + ah)) && !(bl > (al + aw) || al > (bl + bw)); }, diff --git a/test/php/application/forms/Config/Authentication/BaseBackendFormTest.php b/test/php/application/forms/Config/Authentication/BaseBackendFormTest.php deleted file mode 100644 index ca32a1dae..000000000 --- a/test/php/application/forms/Config/Authentication/BaseBackendFormTest.php +++ /dev/null @@ -1,61 +0,0 @@ -is_valid; - } -} - -class BaseBackendFormTest extends BaseTestCase -{ - public function testIsForceCreationCheckboxBeingAdded() - { - $form = new BackendForm(); - $form->is_valid = false; - - $this->assertFalse($form->isValid(array())); - $this->assertNotNull( - $form->getElement('backend_force_creation'), - 'Checkbox to force a backend\'s creation is not being added though the backend is invalid' - ); - } - - public function testIsForceCreationCheckboxNotBeingAdded() - { - $form = new BackendForm(); - $form->is_valid = true; - - $this->assertTrue($form->isValid(array())); - $this->assertNull( - $form->getElement('backend_force_creation'), - 'Checkbox to force a backend\'s creation is being added though the backend is valid' - ); - } - - public function testIsTheFormValidIfForceCreationTrue() - { - $form = new BackendForm(); - $form->is_valid = false; - - $this->assertTrue( - $form->isValid(array('backend_force_creation' => 1)), - 'BaseBackendForm with invalid backend is not valid though force creation is set' - ); - } -} diff --git a/test/php/application/forms/Config/Authentication/DbBackendFormTest.php b/test/php/application/forms/Config/Authentication/DbBackendFormTest.php index 51bec896f..3364dff60 100644 --- a/test/php/application/forms/Config/Authentication/DbBackendFormTest.php +++ b/test/php/application/forms/Config/Authentication/DbBackendFormTest.php @@ -32,13 +32,12 @@ class DbBackendFormTest extends BaseTestCase ->andReturn(2); $form = new DbBackendForm(); - $form->setBackendName('test'); - $form->setResources(array('test_db_backend' => null)); - $form->create(); - $form->populate(array('backend_test_resource' => 'test_db_backend')); + $form->setTokenDisabled(); + $form->setResources(array('test_db_backend')); + $form->populate(array('resource' => 'test_db_backend')); $this->assertTrue( - $form->isValidAuthenticationBackend(), + $form->isValidAuthenticationBackend($form), 'DbBackendForm claims that a valid authentication backend with users is not valid' ); } @@ -55,13 +54,12 @@ class DbBackendFormTest extends BaseTestCase ->andReturn(0); $form = new DbBackendForm(); - $form->setBackendName('test'); - $form->setResources(array('test_db_backend' => null)); - $form->create(); - $form->populate(array('backend_test_resource' => 'test_db_backend')); + $form->setTokenDisabled(); + $form->setResources(array('test_db_backend')); + $form->populate(array('resource' => 'test_db_backend')); $this->assertFalse( - $form->isValidAuthenticationBackend(), + $form->isValidAuthenticationBackend($form), 'DbBackendForm claims that an invalid authentication backend without users is valid' ); } diff --git a/test/php/application/forms/Config/Authentication/LdapBackendFormTest.php b/test/php/application/forms/Config/Authentication/LdapBackendFormTest.php index 209b7a675..0335d1f82 100644 --- a/test/php/application/forms/Config/Authentication/LdapBackendFormTest.php +++ b/test/php/application/forms/Config/Authentication/LdapBackendFormTest.php @@ -29,16 +29,15 @@ class LdapBackendFormTest extends BaseTestCase { $this->setUpResourceFactoryMock(); Mockery::mock('overload:Icinga\Authentication\Backend\LdapUserBackend') - ->shouldReceive('assertAuthenticationPossible')->andReturn(null); + ->shouldReceive('assertAuthenticationPossible')->andReturnNull(); $form = new LdapBackendForm(); - $form->setBackendName('test'); - $form->setResources(array('test_ldap_backend' => null)); - $form->create(); - $form->populate(array('backend_test_resource' => 'test_ldap_backend')); + $form->setTokenDisabled(); + $form->setResources(array('test_ldap_backend')); + $form->populate(array('resource' => 'test_ldap_backend')); $this->assertTrue( - $form->isValidAuthenticationBackend(), + $form->isValidAuthenticationBackend($form), 'LdapBackendForm claims that a valid authentication backend with users is not valid' ); } @@ -54,13 +53,12 @@ class LdapBackendFormTest extends BaseTestCase ->shouldReceive('assertAuthenticationPossible')->andThrow(new AuthenticationException); $form = new LdapBackendForm(); - $form->setBackendName('test'); - $form->setResources(array('test_ldap_backend' => null)); - $form->create(); - $form->populate(array('backend_test_resource' => 'test_ldap_backend')); + $form->setTokenDisabled(); + $form->setResources(array('test_ldap_backend')); + $form->populate(array('resource' => 'test_ldap_backend')); $this->assertFalse( - $form->isValidAuthenticationBackend(), + $form->isValidAuthenticationBackend($form), 'LdapBackendForm claims that an invalid authentication backend without users is valid' ); } diff --git a/test/php/application/forms/Config/Authentication/ReorderFormTest.php b/test/php/application/forms/Config/Authentication/ReorderFormTest.php deleted file mode 100644 index 808806f1a..000000000 --- a/test/php/application/forms/Config/Authentication/ReorderFormTest.php +++ /dev/null @@ -1,80 +0,0 @@ - $this->order); - } -} - -class ReorderFormTest extends BaseTestCase -{ - public function setUp() - { - parent::setUp(); - $this->viewMock = Mockery::mock('\Zend_View'); - $this->viewMock->shouldReceive('icon')->andReturn(''); - } - - public function testMoveBackendUp() - { - $config = new Zend_Config( - array( - 'test1' => '', - 'test2' => '', - 'test3' => '' - ) - ); - $oldOrder = array_keys($config->toArray()); - - $form = new RequestLessReorderForm(); - $form->setCurrentOrder($oldOrder); - $form->setBackendName('test3'); - $form->setView($this->viewMock); - $form->create(); - - $form->order = $form->getSubForm('btn_reorder_up')->getElement('form_backend_order')->getValue(); - $this->assertSame( - $form->getReorderedConfig($config), - array('test1' => '', 'test3' => '', 'test2' => ''), - 'Moving elements up with ReorderForm does not seem to properly work' - ); - } - - public function testMoveBackendDown() - { - $config = new Zend_Config( - array( - 'test1' => '', - 'test2' => '', - 'test3' => '' - ) - ); - $oldOrder = array_keys($config->toArray()); - - $form = new RequestLessReorderForm(); - $form->setCurrentOrder($oldOrder); - $form->setBackendName('test1'); - $form->setView($this->viewMock); - $form->create(); - - $form->order = $form->getSubForm('btn_reorder_down')->getElement('form_backend_order')->getValue(); - $this->assertSame( - $form->getReorderedConfig($config), - array('test2' => '', 'test1' => '', 'test3' => ''), - 'Moving elements down with ReorderForm does not seem to properly work' - ); - } -} diff --git a/test/php/application/forms/Config/AuthenticationBackendReorderFormTest.php b/test/php/application/forms/Config/AuthenticationBackendReorderFormTest.php new file mode 100644 index 000000000..c79b12fd9 --- /dev/null +++ b/test/php/application/forms/Config/AuthenticationBackendReorderFormTest.php @@ -0,0 +1,61 @@ +config; + return false; + } +} + +class AuthenticationBackendReorderFormProvidingConfigFormWithoutSave extends AuthenticationBackendReorderForm +{ + public function getConfigForm() + { + $form = new AuthenticationBackendConfigFormWithoutSave(); + $form->setIniConfig($this->config); + return $form; + } +} + +class AuthenticationBackendReorderFormTest extends BaseTestCase +{ + public function testMoveBackend() + { + $config = new Config( + array( + 'test1' => '', + 'test2' => '', + 'test3' => '' + ) + ); + + $this->getRequestMock()->shouldReceive('getMethod')->andReturn('POST') + ->shouldReceive('isPost')->andReturn(true) + ->shouldReceive('getPost')->andReturn(array('backend_newpos' => 'test3|1')); + + $form = new AuthenticationBackendReorderFormProvidingConfigFormWithoutSave(); + $form->setIniConfig($config); + $form->setTokenDisabled(); + $form->setUidDisabled(); + $form->handleRequest(); + + $this->assertEquals( + array('test1', 'test3', 'test2'), + AuthenticationBackendConfigFormWithoutSave::$newConfig->keys(), + 'Moving elements with AuthenticationBackendReorderForm does not seem to properly work' + ); + } +} diff --git a/test/php/application/forms/Config/Resource/DbResourceFormTest.php b/test/php/application/forms/Config/Resource/DbResourceFormTest.php new file mode 100644 index 000000000..1b624c49f --- /dev/null +++ b/test/php/application/forms/Config/Resource/DbResourceFormTest.php @@ -0,0 +1,66 @@ +setUpResourceFactoryMock( + Mockery::mock()->shouldReceive('getConnection')->atMost()->twice()->andReturn(Mockery::self())->getMock() + ); + + $form = new DbResourceForm(); + + $this->assertTrue( + $form->isValidResource($form), + 'ResourceForm claims that a valid db resource is not valid' + ); + } + + /** + * @runInSeparateProcess + * @preserveGlobalState disabled + */ + public function testInvalidDbResourceIsNotValid() + { + $this->setUpResourceFactoryMock( + Mockery::mock()->shouldReceive('getConnection')->once()->andThrow('\Exception')->getMock() + ); + + $form = new DbResourceForm(); + + $this->assertFalse( + $form->isValidResource($form), + 'ResourceForm claims that an invalid db resource is valid' + ); + } + + protected function setUpResourceFactoryMock($resourceMock) + { + Mockery::mock('alias:Icinga\Data\ResourceFactory') + ->shouldReceive('createResource') + ->with(Mockery::type('\Zend_Config')) + ->andReturn($resourceMock); + } +} diff --git a/test/php/application/forms/Config/Resource/LdapResourceFormTest.php b/test/php/application/forms/Config/Resource/LdapResourceFormTest.php new file mode 100644 index 000000000..078a11146 --- /dev/null +++ b/test/php/application/forms/Config/Resource/LdapResourceFormTest.php @@ -0,0 +1,66 @@ +setUpResourceFactoryMock( + Mockery::mock()->shouldReceive('connect')->getMock() + ); + + $form = new LdapResourceForm(); + + $this->assertTrue( + $form->isValidResource($form), + 'ResourceForm claims that a valid ldap resource is not valid' + ); + } + + /** + * @runInSeparateProcess + * @preserveGlobalState disabled + */ + public function testInvalidLdapResourceIsNotValid() + { + $this->setUpResourceFactoryMock( + Mockery::mock()->shouldReceive('connect')->once()->andThrow('\Exception')->getMock() + ); + + $form = new LdapResourceForm(); + + $this->assertFalse( + $form->isValidResource($form), + 'ResourceForm claims that an invalid ldap resource is valid' + ); + } + + protected function setUpResourceFactoryMock($resourceMock) + { + Mockery::mock('alias:Icinga\Data\ResourceFactory') + ->shouldReceive('createResource') + ->with(Mockery::type('\Zend_Config')) + ->andReturn($resourceMock); + } +} diff --git a/test/php/application/forms/Config/Resource/LivestatusResourceFormTest.php b/test/php/application/forms/Config/Resource/LivestatusResourceFormTest.php new file mode 100644 index 000000000..300adebed --- /dev/null +++ b/test/php/application/forms/Config/Resource/LivestatusResourceFormTest.php @@ -0,0 +1,67 @@ +setUpResourceFactoryMock( + Mockery::mock()->shouldReceive('connect')->andReturn(Mockery::self()) + ->shouldReceive('disconnect')->getMock() + ); + + $form = new LivestatusResourceForm(); + + $this->assertTrue( + $form->isValidResource($form), + 'ResourceForm claims that a valid livestatus resource is not valid' + ); + } + + /** + * @runInSeparateProcess + * @preserveGlobalState disabled + */ + public function testInvalidLivestatusResourceIsNotValid() + { + $this->setUpResourceFactoryMock( + Mockery::mock()->shouldReceive('connect')->once()->andThrow('\Exception')->getMock() + ); + + $form = new LivestatusResourceForm(); + + $this->assertFalse( + $form->isValidResource($form), + 'ResourceForm claims that an invalid livestatus resource is valid' + ); + } + + protected function setUpResourceFactoryMock($resourceMock) + { + Mockery::mock('alias:Icinga\Data\ResourceFactory') + ->shouldReceive('createResource') + ->with(Mockery::type('\Zend_Config')) + ->andReturn($resourceMock); + } +} diff --git a/test/php/application/forms/Config/Resource/ResourceFormTestBroken.php b/test/php/application/forms/Config/Resource/ResourceFormTestBroken.php deleted file mode 100644 index 6dba6ce54..000000000 --- a/test/php/application/forms/Config/Resource/ResourceFormTestBroken.php +++ /dev/null @@ -1,268 +0,0 @@ -is_valid; - } -} - -class ResourceFormTest extends BaseTestCase -{ - public function tearDown() - { - parent::tearDown(); - Mockery::close(); // Necessary because some tests run in a separate process - } - - public function testIsForceCreationCheckboxBeingAdded() - { - $form = new TestResourceForm(); - $form->is_valid = false; - - $this->assertFalse($form->isValid(array())); - $this->assertNotNull( - $form->getElement('resource_force_creation'), - 'Checkbox to force the creation of a resource is not being added though the resource is invalid' - ); - } - - public function testIsForceCreationCheckboxNotBeingAdded() - { - $form = new TestResourceForm(); - $form->is_valid = true; - - $this->assertTrue($form->isValid(array())); - $this->assertNull( - $form->getElement('resource_force_creation'), - 'Checkbox to force the creation of a resource is being added though the resource is valid' - ); - } - - public function testIsTheFormValidIfForceCreationTrue() - { - $form = new TestResourceForm(); - $form->is_valid = false; - - $this->assertTrue( - $form->isValid(array('resource_force_creation' => 1)), - 'ResourceForm with invalid resource is not valid though force creation is set' - ); - } - - /** - * @runInSeparateProcess - * @preserveGlobalState disabled - */ - public function testValidDbResourceIsValid() - { - $this->setUpResourceFactoryMock( - Mockery::mock()->shouldReceive('getConnection')->atMost()->twice()->andReturn(Mockery::self())->getMock() - ); - $form = $this->buildResourceForm(new Zend_Config(array('type' => 'db'))); - - $this->assertTrue( - $form->isValidResource(), - 'ResourceForm claims that a valid db resource is not valid' - ); - } - - /** - * @runInSeparateProcess - * @preserveGlobalState disabled - */ - public function testInvalidDbResourceIsNotValid() - { - $this->setUpResourceFactoryMock( - Mockery::mock()->shouldReceive('getConnection')->once()->andThrow('\Exception')->getMock() - ); - $form = $this->buildResourceForm(new Zend_Config(array('type' => 'db'))); - - $this->assertFalse( - $form->isValidResource(), - 'ResourceForm claims that an invalid db resource is valid' - ); - } - - /** - * @runInSeparateProcess - * @preserveGlobalState disabled - */ - public function testValidLdapResourceIsValid() - { - $this->setUpResourceFactoryMock( - Mockery::mock()->shouldReceive('connect')->getMock() - ); - $form = $this->buildResourceForm(new Zend_Config(array('type' => 'ldap'))); - - $this->assertTrue( - $form->isValidResource(), - 'ResourceForm claims that a valid ldap resource is not valid' - ); - } - - /** - * @runInSeparateProcess - * @preserveGlobalState disabled - */ - public function testInvalidLdapResourceIsNotValid() - { - $this->setUpResourceFactoryMock( - Mockery::mock()->shouldReceive('connect')->once()->andThrow('\Exception')->getMock() - ); - $form = $this->buildResourceForm(new Zend_Config(array('type' => 'ldap'))); - - $this->assertFalse( - $form->isValidResource(), - 'ResourceForm claims that an invalid ldap resource is valid' - ); - } - - /** - * @runInSeparateProcess - * @preserveGlobalState disabled - */ - public function testValidLivestatusResourceIsValid() - { - $this->setUpResourceFactoryMock( - Mockery::mock()->shouldReceive('connect')->andReturn(Mockery::self()) - ->shouldReceive('disconnect')->getMock() - ); - $form = $this->buildResourceForm(new Zend_Config(array('type' => 'livestatus'))); - - $this->assertTrue( - $form->isValidResource(), - 'ResourceForm claims that a valid livestatus resource is not valid' - ); - } - - /** - * @runInSeparateProcess - * @preserveGlobalState disabled - */ - public function testInvalidLivestatusResourceIsNotValid() - { - $this->setUpResourceFactoryMock( - Mockery::mock()->shouldReceive('connect')->once()->andThrow('\Exception')->getMock() - ); - $form = $this->buildResourceForm(new Zend_Config(array('type' => 'livestatus'))); - - $this->assertFalse( - $form->isValidResource(), - 'ResourceForm claims that an invalid livestatus resource is valid' - ); - } - - public function testValidFileResourceIsValid() - { - $form = $this->buildResourceForm( - new Zend_Config( - array( - 'type' => 'file', - 'filename' => BaseTestCase::$testDir . '/res/status/icinga.status.dat' - ) - ) - ); - - $this->assertTrue( - $form->isValidResource(), - 'ResourceForm claims that a valid file resource is not valid' - ); - } - - public function testInvalidFileResourceIsNotValid() - { - $form = $this->buildResourceForm( - new Zend_Config( - array( - 'type' => 'file', - 'filename' => 'not_existing' - ) - ) - ); - - $this->assertFalse( - $form->isValidResource(), - 'ResourceForm claims that an invalid file resource is valid' - ); - } - - public function testValidStatusdatResourceIsValid() - { - $form = $this->buildResourceForm( - new Zend_Config( - array( - 'type' => 'statusdat', - 'status_file' => BaseTestCase::$testDir . '/res/status/icinga.status.dat', - 'object_file' => BaseTestCase::$testDir . '/res/status/icinga.objects.cache', - ) - ) - ); - - $this->assertTrue( - $form->isValidResource(), - 'ResourceForm claims that a valid statusdat resource is not valid' - ); - } - - public function testInvalidStatusdatResourceIsNotValid() - { - $form = $this->buildResourceForm( - new Zend_Config( - array( - 'type' => 'statusdat', - 'status_file' => 'not_existing', - 'object_file' => 'not_existing' - ) - ) - ); - - $this->assertFalse( - $form->isValidResource(), - 'ResourceForm claims that an invalid statusdat resource is valid' - ); - } - - protected function buildResourceForm($resourceConfig) - { - $form = new ResourceForm(); - $form->setRequest($this->getRequestMock()); - $form->setResource($resourceConfig); - $form->create(); - - return $form; - } - - protected function getRequestMock() - { - return Mockery::mock('\Zend_Controller_Request_Abstract') - ->shouldReceive('getParam') - ->with(Mockery::type('string'), Mockery::type('string')) - ->andReturnUsing(function ($name, $default) { return $default; }) - ->getMock(); - } - - protected function setUpResourceFactoryMock($resourceMock) - { - Mockery::mock('alias:Icinga\Data\ResourceFactory') - ->shouldReceive('createResource') - ->with(Mockery::type('\Zend_Config')) - ->andReturn($resourceMock); - } -} diff --git a/test/php/library/Icinga/Web/FormTest.php b/test/php/library/Icinga/Web/FormTest.php index 4e6ec5d92..a2fc9c8b1 100644 --- a/test/php/library/Icinga/Web/FormTest.php +++ b/test/php/library/Icinga/Web/FormTest.php @@ -4,58 +4,285 @@ namespace Tests\Icinga\Web; +use Mockery; use Icinga\Web\Form; +use Icinga\Web\Request; use Icinga\Test\BaseTestCase; +class SuccessfulForm extends Form +{ + public function onSuccess(Request $request) + { + return true; + } +} + class FormTest extends BaseTestCase { - public function testWhetherAddElementDoesNotAddSpecificDecorators() + public function tearDown() + { + Mockery::close(); // Necessary as some tests are running isolated + } + + public function testWhetherASubmitButtonIsAddedWithASubmitLabelBeingSet() { $form = new Form(); - $form->addElement('text', 'someText'); - $element = $form->getElement('someText'); + $form->setTokenDisabled(); + $form->setSubmitLabel('test'); + $form->create(); - $this->assertFalse( - $element->getDecorator('HtmlTag'), - 'Form::addElement does not remove the HtmlTag-Decorator' - ); - $this->assertFalse( - $element->getDecorator('Label'), - 'Form::addElement does not remove the Label-Decorator' - ); - $this->assertFalse( - $element->getDecorator('DtDdWrapper'), - 'Form::addElement does not remove the DtDdWrapper-Decorator' + $this->assertInstanceOf( + '\Zend_Form_Element', + $form->getElement('btn_submit'), + 'Form::create() does not add a submit button in case a submit label is set' ); } - public function testWhetherAddElementDoesNotAddAnyOptionalDecoratorsToHiddenElements() + public function testWhetherNoSubmitButtonIsAddedWithoutASubmitLabelBeingSet() { $form = new Form(); - $form->addElement('hidden', 'somethingHidden'); - $element = $form->getElement('somethingHidden'); + $form->setTokenDisabled(); + $form->create(); + + $this->assertNull( + $form->getElement('btn_submit'), + 'Form::create() adds a submit button in case no submit label is set' + ); + } + + /** + * @depends testWhetherASubmitButtonIsAddedWithASubmitLabelBeingSet + */ + public function testWhetherIsSubmittedReturnsTrueWithASubmitLabelBeingSet() + { + $form = new Form(); + $form->setTokenDisabled(); + $form->setSubmitLabel('test'); + $form->populate(array('btn_submit' => true)); + + $this->assertTrue( + $form->isSubmitted(), + 'Form::isSubmitted() does not return true in case a submit label is set' + ); + } + + /** + * @depends testWhetherNoSubmitButtonIsAddedWithoutASubmitLabelBeingSet + */ + public function testWhetherIsSubmittedReturnsFalseWithoutASubmitLabelBeingSet() + { + $form = new Form(); + + $this->assertFalse( + $form->isSubmitted(), + 'Form::isSubmitted() does not return false in case no submit label is set' + ); + } + + public function testWhetherTheCurrentLocationIsUsedAsDefaultRedirection() + { + $this->getRequestMock()->shouldReceive('getPathInfo')->andReturn('default/route'); + $this->getResponseMock()->shouldReceive('redirectAndExit')->atLeast()->once() + ->with(Mockery::on(function ($url) { return $url->getRelativeUrl() === 'default/route'; })); + + $form = new SuccessfulForm(); + $form->setTokenDisabled(); + $form->setUidDisabled(); + $form->handleRequest(); + } + + public function testWhetherAnExplicitlySetRedirectUrlIsUsedForRedirection() + { + $this->getResponseMock()->shouldReceive('redirectAndExit')->atLeast()->once()->with('special/route'); + + $form = new SuccessfulForm(); + $form->setTokenDisabled(); + $form->setUidDisabled(); + $form->setRedirectUrl('special/route'); + $form->handleRequest(); + } + + /** + * @runInSeparateProcess + */ + public function testWhetherACsrfCounterMeasureIsBeingAdded() + { + Mockery::mock('alias:Icinga\Web\Session')->shouldReceive('getSession->getId')->andReturn('1234567890'); + + $form = new Form(); + $form->create(); + + $this->assertInstanceOf( + '\Zend_Form_Element', + $form->getElement($form->getTokenElementName()), + 'Form::create() does not add a csrf counter measure element' + ); + } + + public function testWhetherACsrfCounterMeasureIsNotBeingAdded() + { + $form = new Form(); + $form->setTokenDisabled(); + $form->create(); + + $this->assertNull( + $form->getElement($form->getTokenElementName()), + 'Form::create() adds a csrf counter measure element in case it\'s disabled' + ); + } + + public function testWhetherAUniqueFormIdIsBeingAdded() + { + $form = new Form(); + $form->setTokenDisabled(); + $form->create(); + + $this->assertInstanceOf( + '\Zend_Form_Element', + $form->getElement($form->getUidElementName()), + 'Form::create() does not add a form identification element' + ); + } + + public function testWhetherAUniqueFormIdIsNotBeingAdded() + { + $form = new Form(); + $form->setTokenDisabled(); + $form->setUidDisabled(); + $form->create(); + + $this->assertNull( + $form->getElement($form->getUidElementName()), + 'Form::create() adds a form identification element in case it\'s disabled' + ); + } + + /** + * @depends testWhetherAUniqueFormIdIsBeingAdded + */ + public function testWhetherAFormIsSentWithAUniqueFormIdBeingAdded() + { + $form = new Form(); + $form->setTokenDisabled(); + $form->create(); + + $this->assertTrue( + $form->wasSent( + array( + $form->getUidElementName() => $form->getElement($form->getUidElementName())->getValue() + ) + ), + 'Form::wasSent() does not return true in case a the form identification value is being sent' + ); + } + + /** + * @depends testWhetherAUniqueFormIdIsNotBeingAdded + */ + public function testWhetherAFormIsNotSentWithoutAUniqueFormIdBeingAdded() + { + $form = new Form(); + $form->setTokenDisabled(); + $form->setUidDisabled(); + $form->create(); + + $this->assertFalse( + $form->wasSent(array()), + 'Form::wasSent() does not return false in case no form identification element was added' + ); + } + + public function testWhetherADefaultActionIsBeingSetOnFormCreation() + { + $this->getRequestMock()->shouldReceive('getPathInfo')->andReturn('some/route'); + + $form = new Form(); + $form->setTokenDisabled(); + $form->create(); + + $this->assertEquals( + '/some/route', + $form->getAction(), + 'Form::create() does not set a default action if none was set explicitly' + ); + } + + /** + * @depends testWhetherAUniqueFormIdIsBeingAdded + * @depends testWhetherASubmitButtonIsAddedWithASubmitLabelBeingSet + */ + public function testWhetherItIsPossibleToRecreateAForm() + { + $form = new Form(); + $form->setTokenDisabled(); + $form->setSubmitLabel('test'); + $form->create(); // sets the flag $this->created to true + $form->clearElements(); // should reset the flag.. + $form->create(); // ..so that we can recreate the form $this->assertCount( - 1, - $element->getDecorators(), - 'Form::addElement adds more decorators than necessary to hidden elements' - ); - $this->assertInstanceOf( - '\Zend_Form_Decorator_ViewHelper', - $element->getDecorator('ViewHelper'), - 'Form::addElement does not add the ViewHelper-Decorator to hidden elements' + 2, + $form->getElements(), + 'Form::clearElements() does not fully reset the form' ); } - public function testWhetherLoadDefaultDecoratorsDoesNotAddTheHtmlTagDecorator() + public function testWhetherGetNameReturnsTheEscapedClassNameByDefault() { $form = new Form(); - $form->loadDefaultDecorators(); - $this->assertArrayNotHasKey( - 'HtmlTag', - $form->getDecorators(), - 'Form::loadDefaultDecorators adds the HtmlTag-Decorator' + $this->assertEquals( + $form->filterName(get_class($form)), + $form->getName(), + 'Form::getName() does not return the escaped class name in case no name was explicitly set' + ); + } + + public function testWhetherGetRequestDataOnlyReturnsFormRelevantData() + { + $form = new Form(); + $form->setMethod('POST'); + + $expectedResult = array('expected_key' => 'expected_value'); + $request = $this->getRequestMock(); + $request->shouldReceive('getMethod')->andReturn('POST') + ->shouldReceive('isPost')->andReturn(true) + ->shouldReceive('getPost')->andReturn($expectedResult); + + $this->assertEquals( + $expectedResult, + $form->getRequestData($request), + 'Form::getRequestData() does not (only) return form relevant data' + ); + } + + /** + * @expectedException LogicException + */ + public function testWhetherTheOnSuccessOptionMustBeCallable() + { + new Form(array('onSuccess' => '_invalid_')); + } + + /** + * @depends testWhetherACsrfCounterMeasureIsNotBeingAdded + * @depends testWhetherAUniqueFormIdIsNotBeingAdded + * @depends testWhetherNoSubmitButtonIsAddedWithoutASubmitLabelBeingSet + */ + public function testWhetherAClosureCanBePassedAsOnSuccessCallback() + { + $request = new Request(); + $form = new Form(array( + 'onSuccess' => function ($req) { $req->setParam('test', 'tset'); return false; } + )); + $form->setTokenDisabled(); + $form->setUidDisabled(); + $form->handleRequest($request); + + $this->assertEquals( + 'tset', + $request->getParam('test'), + 'Form does not utilize the onSuccess callback set with form options on instantiation' ); } } diff --git a/test/php/library/Icinga/Web/UrlTest.php b/test/php/library/Icinga/Web/UrlTest.php index 5da50c3f8..68206beee 100644 --- a/test/php/library/Icinga/Web/UrlTest.php +++ b/test/php/library/Icinga/Web/UrlTest.php @@ -12,11 +12,9 @@ class UrlTest extends BaseTestCase { public function testWhetherFromRequestWorksWithoutARequest() { - $request = Mockery::mock('Icinga\Web\Request'); - $request->shouldReceive('getPathInfo')->andReturn('my/test/url.html') - ->shouldReceive('getBaseUrl')->andReturn('/path/to') + $this->getRequestMock()->shouldReceive('getBaseUrl')->andReturn('/path/to') + ->shouldReceive('getPathInfo')->andReturn('my/test/url.html') ->shouldReceive('getQuery')->andReturn(array('param1' => 'value1', 'param2' => 'value2')); - $this->setupIcingaMock($request); $url = Url::fromRequest(); $this->assertEquals( diff --git a/test/php/library/Icinga/Web/Widget/DashboardTest.php b/test/php/library/Icinga/Web/Widget/DashboardTest.php index 9114a8f90..be11c42fe 100644 --- a/test/php/library/Icinga/Web/Widget/DashboardTest.php +++ b/test/php/library/Icinga/Web/Widget/DashboardTest.php @@ -47,7 +47,7 @@ class DashboardTest extends BaseTestCase Mockery::close(); // Necessary because some tests run in a separate process } - protected function setupIcingaMock(\Zend_Controller_Request_Abstract $request) + public function setUp() { $moduleMock = Mockery::mock('Icinga\Application\Modules\Module'); $moduleMock->shouldReceive('getPaneItems')->andReturn(array( @@ -59,14 +59,8 @@ class DashboardTest extends BaseTestCase 'test-module' => $moduleMock )); - $bootstrapMock = Mockery::mock('Icinga\Application\ApplicationBootstrap')->shouldDeferMissing(); - $bootstrapMock->shouldReceive('getFrontController->getRequest')->andReturnUsing( - function () use ($request) { return $request; } - )->shouldReceive('getApplicationDir')->andReturn(self::$appDir); - + $bootstrapMock = $this->setupIcingaMock(); $bootstrapMock->shouldReceive('getModuleManager')->andReturn($moduleManagerMock); - - Icinga::setApp($bootstrapMock, true); } public function testWhetherCreatePaneCreatesAPane() diff --git a/test/php/library/Icinga/Web/Widget/SearchDashboardTest.php b/test/php/library/Icinga/Web/Widget/SearchDashboardTest.php index d42862ff6..d9323c00a 100644 --- a/test/php/library/Icinga/Web/Widget/SearchDashboardTest.php +++ b/test/php/library/Icinga/Web/Widget/SearchDashboardTest.php @@ -5,19 +5,12 @@ namespace Tests\Icinga\Web; use Mockery; -use Icinga\Application\Icinga; -use Icinga\Web\Widget\SearchDashboard; use Icinga\Test\BaseTestCase; +use Icinga\Web\Widget\SearchDashboard; class SearchDashboardTest extends BaseTestCase { - public function tearDown() - { - parent::tearDown(); - Mockery::close(); - } - - protected function setupIcingaMock(\Zend_Controller_Request_Abstract $request) + public function setUp() { $moduleMock = Mockery::mock('Icinga\Application\Modules\Module'); $searchUrl = (object) array( @@ -33,14 +26,8 @@ class SearchDashboardTest extends BaseTestCase 'test-module' => $moduleMock )); - $bootstrapMock = Mockery::mock('Icinga\Application\ApplicationBootstrap')->shouldDeferMissing(); - $bootstrapMock->shouldReceive('getFrontController->getRequest')->andReturnUsing( - function () use ($request) { return $request; } - )->shouldReceive('getApplicationDir')->andReturn(self::$appDir); - + $bootstrapMock = $this->setupIcingaMock(); $bootstrapMock->shouldReceive('getModuleManager')->andReturn($moduleManagerMock); - - Icinga::setApp($bootstrapMock, true); } /**