Merge branch 'bugfix/rebuild-form-builder-5525' into bugfix/commands-6593

This commit is contained in:
Eric Lippmann 2014-09-02 17:09:36 +02:00
commit 0b1d2bf685
29 changed files with 901 additions and 1002 deletions

View File

@ -2,8 +2,7 @@
// {{{ICINGA_LICENSE_HEADER}}} // {{{ICINGA_LICENSE_HEADER}}}
// {{{ICINGA_LICENSE_HEADER}}} // {{{ICINGA_LICENSE_HEADER}}}
use Icinga\Web\Controller\BaseConfigController; use Icinga\Web\Controller\ActionController;
use Icinga\Web\Widget\AlertMessageBox;
use Icinga\Web\Notification; use Icinga\Web\Notification;
use Icinga\Application\Modules\Module; use Icinga\Application\Modules\Module;
use Icinga\Web\Widget; use Icinga\Web\Widget;
@ -12,16 +11,15 @@ use Icinga\Application\Config as IcingaConfig;
use Icinga\Form\Config\GeneralConfigForm; use Icinga\Form\Config\GeneralConfigForm;
use Icinga\Form\Config\AuthenticationBackendReorderForm; use Icinga\Form\Config\AuthenticationBackendReorderForm;
use Icinga\Form\Config\AuthenticationBackendConfigForm; use Icinga\Form\Config\AuthenticationBackendConfigForm;
use Icinga\Form\Config\ResourceForm; use Icinga\Form\Config\ResourceConfigForm;
use Icinga\Form\ConfirmRemovalForm; use Icinga\Form\ConfirmRemovalForm;
use Icinga\Config\PreservingIniWriter;
use Icinga\Data\ResourceFactory; use Icinga\Data\ResourceFactory;
/** /**
* Application wide controller for application preferences * Application wide controller for application preferences
*/ */
class ConfigController extends BaseConfigController class ConfigController extends ActionController
{ {
public function init() public function init()
{ {
@ -210,14 +208,12 @@ class ConfigController extends BaseConfigController
} }
/** /**
* Display all available resources and a link to create a new one * Display all available resources and a link to create a new one and to remove existing ones
*/ */
public function resourceAction() public function resourceAction()
{ {
$this->view->messageBox = new AlertMessageBox(true);
$this->view->tabs->activate('resources');
$this->view->resources = IcingaConfig::app('resources', true)->toArray(); $this->view->resources = IcingaConfig::app('resources', true)->toArray();
$this->view->tabs->activate('resources');
} }
/** /**
@ -225,26 +221,12 @@ class ConfigController extends BaseConfigController
*/ */
public function createresourceAction() public function createresourceAction()
{ {
$this->view->messageBox = new AlertMessageBox(true); $form = new ResourceConfigForm();
$form->setConfig(IcingaConfig::app('resources'));
$form = new ResourceForm(); $form->setRedirectUrl('config/resource');
$request = $this->getRequest(); $form->handleRequest();
if ($request->isPost() && $form->isValid($request->getPost())) {
list($name, $config) = $form->getResourceConfig();
$resources = IcingaConfig::app('resources')->toArray();
if (array_key_exists($name, $resources)) {
$this->addErrorMessage(sprintf($this->translate('Resource name "%s" already in use.'), $name));
} else {
$resources[$name] = $config;
if ($this->writeConfigFile($resources, 'resources')) {
$this->addSuccessMessage(sprintf($this->translate('Resource "%s" successfully created.'), $name));
$this->redirectNow('config/resource');
}
}
}
$this->view->form = $form; $this->view->form = $form;
$this->view->messageBox->addForm($form);
$this->render('resource/create'); $this->render('resource/create');
} }
@ -253,39 +235,12 @@ class ConfigController extends BaseConfigController
*/ */
public function editresourceAction() public function editresourceAction()
{ {
$this->view->messageBox = new AlertMessageBox(true); $form = new ResourceConfigForm();
$form->setConfig(IcingaConfig::app('resources'));
// Fetch the resource to be edited $form->setRedirectUrl('config/resource');
$resources = IcingaConfig::app('resources')->toArray(); $form->handleRequest();
$name = $this->getParam('resource');
if (false === array_key_exists($name, $resources)) {
$this->addErrorMessage(sprintf($this->translate('Cannot edit "%s". Resource not found.'), $name));
$this->redirectNow('config/configurationerror');
}
$form = new ResourceForm();
$request = $this->getRequest();
if ($request->isPost()) {
if ($form->isValid($request->getPost())) {
list($newName, $config) = $form->getResourceConfig();
if ($newName !== $name) {
// Resource name has changed
unset($resources[$name]); // We can safely use unset as all values are part of the form
}
$resources[$newName] = $config;
if ($this->writeConfigFile($resources, 'resources')) {
$this->addSuccessMessage(sprintf($this->translate('Resource "%s" successfully edited.'), $name));
$this->redirectNow('config/resource');
}
}
} else {
$form->setResourceConfig($name, $resources[$name]);
}
$this->view->form = $form; $this->view->form = $form;
$this->view->messageBox->addForm($form);
$this->render('resource/modify'); $this->render('resource/modify');
} }
@ -294,104 +249,46 @@ class ConfigController extends BaseConfigController
*/ */
public function removeresourceAction() public function removeresourceAction()
{ {
$this->view->messageBox = new AlertMessageBox(true); $form = new ConfirmRemovalForm(array(
'onSuccess' => function ($request) {
$configForm = new ResourceConfigForm();
$configForm->setConfig(IcingaConfig::app('resources'));
$resource = $request->getQuery('resource');
// Fetch the resource to be removed try {
$resources = IcingaConfig::app('resources')->toArray(); $configForm->remove($resource);
$name = $this->getParam('resource'); } catch (InvalidArgumentException $e) {
if (false === array_key_exists($name, $resources)) { Notification::error($e->getMessage());
$this->addErrorMessage(sprintf($this->translate('Cannot remove "%s". Resource not found.'), $name)); return;
$this->redirectNow('config/configurationerror'); }
}
if ($configForm->save()) {
Notification::success(sprintf(t('Resource "%s" has been successfully removed'), $resource));
} else {
return false;
}
}
));
$form->setRedirectUrl('config/resource');
$form->handleRequest();
// Check if selected resource is currently used for authentication // Check if selected resource is currently used for authentication
$resource = $this->getRequest()->getQuery('resource');
$authConfig = IcingaConfig::app('authentication')->toArray(); $authConfig = IcingaConfig::app('authentication')->toArray();
foreach ($authConfig as $backendName => $config) { foreach ($authConfig as $backendName => $config) {
if (array_key_exists('resource', $config) && $config['resource'] === $name) { if (array_key_exists('resource', $config) && $config['resource'] === $resource) {
$this->addWarningMessage( $form->addError(sprintf(
sprintf( $this->translate(
$this->translate( 'The resource "%s" is currently in use by the authentication backend "%s". ' .
'The resource "%s" is currently in use by the authentication backend "%s". ' . 'Removing the resource can result in noone being able to log in any longer.'
'Removing the resource can result in noone being able to log in any longer.' ),
), $resource,
$name, $backendName
$backendName ));
)
);
}
}
$form = new ConfirmRemovalForm();
$request = $this->getRequest();
if ($request->isPost() && $form->isValid($request->getPost())) {
unset($resources[$name]);
if ($this->writeConfigFile($resources, 'resources')) {
$this->addSuccessMessage(sprintf($this->translate('Resource "%s" successfully removed.'), $name));
$this->redirectNow('config/resource');
} }
} }
$this->view->form = $form; $this->view->form = $form;
$this->view->messageBox->addForm($form);
$this->render('resource/remove'); $this->render('resource/remove');
} }
/**
* Redirect target only for error-states
*
* When an error is opened in the side-pane, redirecting this request to the index or the overview will look
* weird. This action returns a clear page containing only an AlertMessageBox.
*/
public function configurationerrorAction()
{
$this->view->messageBox = new AlertMessageBox(true);
$this->render('error/error', null, true);
}
/**
* Write changes to an authentication file
*
* @param array $config The configuration changes
*
* @return bool True when persisting succeeded, otherwise false
*
* @see writeConfigFile()
*/
private function writeAuthenticationFile($config) {
return $this->writeConfigFile($config, 'authentication');
}
/**
* Write changes to a configuration file $file, using the supplied writer or PreservingIniWriter if none is set
*
* @param array|Zend_Config $config The configuration to write
* @param string $file The filename to write to (without .ini)
* @param Zend_Config_Writer $writer An optional writer to use for persisting changes
*
* @return bool True when persisting succeeded, otherwise false
*/
private function writeConfigFile($config, $file, $writer = null)
{
if (is_array($config)) {
$config = new Zend_Config($config);
}
if ($writer === null) {
$writer = new PreservingIniWriter(
array(
'config' => $config,
'filename' => IcingaConfig::app($file)->getConfigFile()
)
);
}
try {
$writer->write();
return true;
} catch (Exception $exc) {
$this->view->exceptionMessage = $exc->getMessage();
$this->view->iniConfigurationString = $writer->render();
$this->view->file = $file;
$this->render('show-configuration');
return false;
}
}
} }

View File

@ -32,7 +32,7 @@ class AutologinBackendForm extends Form
array( array(
'required' => true, 'required' => true,
'label' => t('Backend Name'), 'label' => t('Backend Name'),
'helptext' => t('The name of this authentication backend'), 'description' => t('The name of this authentication backend'),
'validators' => array( 'validators' => array(
array( array(
'Regex', 'Regex',
@ -53,7 +53,7 @@ class AutologinBackendForm extends Form
array( array(
'required' => true, 'required' => true,
'label' => t('Backend Domain Pattern'), 'label' => t('Backend Domain Pattern'),
'helptext' => t('The domain pattern of this authentication backend'), 'description' => t('The domain pattern of this authentication backend'),
'value' => '/\@[^$]+$/', 'value' => '/\@[^$]+$/',
'validators' => array( 'validators' => array(
new Zend_Validate_Callback(function ($value) { new Zend_Validate_Callback(function ($value) {

View File

@ -55,7 +55,7 @@ class DbBackendForm extends Form
array( array(
'required' => true, 'required' => true,
'label' => t('Backend Name'), 'label' => t('Backend Name'),
'helptext' => t('The name of this authentication provider'), 'description' => t('The name of this authentication provider'),
) )
), ),
$this->createElement( $this->createElement(
@ -64,7 +64,7 @@ class DbBackendForm extends Form
array( array(
'required' => true, 'required' => true,
'label' => t('Database Connection'), 'label' => t('Database Connection'),
'helptext' => t('The database connection to use for authenticating with this provider'), 'description' => t('The database connection to use for authenticating with this provider'),
'multiOptions' => false === empty($this->resources) 'multiOptions' => false === empty($this->resources)
? array_combine($this->resources, $this->resources) ? array_combine($this->resources, $this->resources)
: array() : array()

View File

@ -54,7 +54,7 @@ class LdapBackendForm extends Form
array( array(
'required' => true, 'required' => true,
'label' => t('Backend Name'), 'label' => t('Backend Name'),
'helptext' => t('The name of this authentication backend') 'description' => t('The name of this authentication backend')
) )
), ),
$this->createElement( $this->createElement(
@ -63,7 +63,7 @@ class LdapBackendForm extends Form
array( array(
'required' => true, 'required' => true,
'label' => t('LDAP Resource'), 'label' => t('LDAP Resource'),
'helptext' => t('The resource to use for authenticating with this provider'), 'description' => t('The resource to use for authenticating with this provider'),
'multiOptions' => false === empty($this->resources) 'multiOptions' => false === empty($this->resources)
? array_combine($this->resources, $this->resources) ? array_combine($this->resources, $this->resources)
: array() : array()
@ -73,20 +73,20 @@ class LdapBackendForm extends Form
'text', 'text',
'user_class', 'user_class',
array( array(
'required' => true, 'required' => true,
'label' => t('LDAP User Object Class'), 'label' => t('LDAP User Object Class'),
'helptext' => t('The object class used for storing users on the ldap server'), 'description' => t('The object class used for storing users on the ldap server'),
'value' => 'inetOrgPerson' 'value' => 'inetOrgPerson'
) )
), ),
$this->createElement( $this->createElement(
'text', 'text',
'user_name_attribute', 'user_name_attribute',
array( array(
'required' => true, 'required' => true,
'label' => t('LDAP User Name Attribute'), 'label' => t('LDAP User Name Attribute'),
'helptext' => t('The attribute name used for storing the user name on the ldap server'), 'description' => t('The attribute name used for storing the user name on the ldap server'),
'value' => 'uid' 'value' => 'uid'
) )
), ),
$this->createElement( $this->createElement(

View File

@ -202,7 +202,7 @@ class AuthenticationBackendConfigForm extends ConfigForm
if (($el = $this->getElement('force_creation')) === null || false === $el->isChecked()) { if (($el = $this->getElement('force_creation')) === null || false === $el->isChecked()) {
$backendForm = $this->getBackendForm($this->getElement('type')->getValue()); $backendForm = $this->getBackendForm($this->getElement('type')->getValue());
if (false === $backendForm->isValidAuthenticationBackend($this)) { if (false === $backendForm->isValidAuthenticationBackend($this)) {
$this->addForceCreationCheckbox(); $this->addElement($this->getForceCreationCheckbox());
return false; return false;
} }
} }
@ -231,11 +231,11 @@ class AuthenticationBackendConfigForm extends ConfigForm
/** /**
* Populate the form in case an authentication backend is being edited * Populate the form in case an authentication backend is being edited
* *
* @see Form::onShow() * @see Form::onRequest()
* *
* @throws ConfigurationError In case the backend name is missing in the request or is invalid * @throws ConfigurationError In case the backend name is missing in the request or is invalid
*/ */
public function onShow(Request $request) public function onRequest(Request $request)
{ {
$authBackend = $request->getQuery('auth_backend'); $authBackend = $request->getQuery('auth_backend');
if ($authBackend !== null) { if ($authBackend !== null) {
@ -255,19 +255,21 @@ class AuthenticationBackendConfigForm extends ConfigForm
} }
/** /**
* Add a checkbox to be displayed at the beginning of the form * Return a checkbox to be displayed at the beginning of the form
* which allows the user to skip the connection validation * which allows the user to skip the connection validation
*
* @return Zend_Form_Element
*/ */
protected function addForceCreationCheckbox() protected function getForceCreationCheckbox()
{ {
$this->addElement( return $this->createElement(
'checkbox', 'checkbox',
'force_creation', 'force_creation',
array( array(
'order' => 0, 'order' => 0,
'ignore' => true, 'ignore' => true,
'label' => t('Force Changes'), 'label' => t('Force Changes'),
'helptext' => t('Check this box to enforce changes without connectivity validation') 'description' => t('Check this box to enforce changes without connectivity validation')
) )
); );
} }
@ -297,22 +299,25 @@ class AuthenticationBackendConfigForm extends ConfigForm
$backendTypes['autologin'] = t('Autologin'); $backendTypes['autologin'] = t('Autologin');
} }
$typeSelection = $this->createElement( $elements = array();
$elements[] = $this->createElement(
'select', 'select',
'type', 'type',
array( array(
'ignore' => true, 'ignore' => true,
'required' => true, 'required' => true,
'autosubmit' => true, 'autosubmit' => true,
'label' => t('Backend Type'), 'label' => t('Backend Type'),
'helptext' => t('The type of the resource to use for this authenticaton backend'), 'description' => t('The type of the resource to use for this authenticaton backend'),
'multiOptions' => $backendTypes 'multiOptions' => $backendTypes
) )
); );
return array_merge( if (isset($formData['force_creation']) && $formData['force_creation']) {
array($typeSelection), // In case another error occured and the checkbox was displayed before
$this->getBackendForm($backendType)->createElements($formData) $elements[] = $this->getForceCreationCheckbox();
); }
return array_merge($elements, $this->getBackendForm($backendType)->createElements($formData));
} }
} }

View File

@ -41,7 +41,7 @@ class ApplicationConfigForm extends Form
'label' => t('Default Language'), 'label' => t('Default Language'),
'required' => true, 'required' => true,
'multiOptions' => $languages, 'multiOptions' => $languages,
'helptext' => t( 'description' => t(
'Select the language to use by default. Can be overwritten by a user in his preferences.' 'Select the language to use by default. Can be overwritten by a user in his preferences.'
) )
) )
@ -59,7 +59,7 @@ class ApplicationConfigForm extends Form
'label' => t('Default Application Timezone'), 'label' => t('Default Application Timezone'),
'required' => true, 'required' => true,
'multiOptions' => $tzList, 'multiOptions' => $tzList,
'helptext' => t( 'description' => t(
'Select the timezone to be used as the default. User\'s can set their own timezone if' 'Select the timezone to be used as the default. User\'s can set their own timezone if'
. ' they like to, but this is the timezone to be used as the default setting .' . ' they like to, but this is the timezone to be used as the default setting .'
), ),
@ -71,9 +71,9 @@ class ApplicationConfigForm extends Form
'text', 'text',
'global_modulePath', 'global_modulePath',
array( array(
'label' => t('Module Path'), 'label' => t('Module Path'),
'required' => true, 'required' => true,
'helptext' => t( 'description' => t(
'Contains the directories that will be searched for available modules, separated by ' 'Contains the directories that will be searched for available modules, separated by '
. 'colons. Modules that don\'t exist in these directories can still be symlinked in ' . 'colons. Modules that don\'t exist in these directories can still be symlinked in '
. 'the module folder, but won\'t show up in the list of disabled modules.' . 'the module folder, but won\'t show up in the list of disabled modules.'

View File

@ -31,7 +31,7 @@ class LoggingConfigForm extends Form
array( array(
'required' => true, 'required' => true,
'label' => t('Logging Level'), 'label' => t('Logging Level'),
'helptext' => t('The maximum loglevel to emit.'), 'description' => t('The maximum loglevel to emit.'),
'multiOptions' => array( 'multiOptions' => array(
0 => t('None'), 0 => t('None'),
1 => t('Error'), 1 => t('Error'),
@ -48,7 +48,7 @@ class LoggingConfigForm extends Form
'required' => true, 'required' => true,
'class' => 'autosubmit', 'class' => 'autosubmit',
'label' => t('Logging Type'), 'label' => t('Logging Type'),
'helptext' => t('The type of logging to utilize.'), 'description' => t('The type of logging to utilize.'),
'multiOptions' => array( 'multiOptions' => array(
'syslog' => 'Syslog', 'syslog' => 'Syslog',
'file' => t('File') 'file' => t('File')
@ -63,7 +63,7 @@ class LoggingConfigForm extends Form
array( array(
'required' => true, 'required' => true,
'label' => t('Application Prefix'), 'label' => t('Application Prefix'),
'helptext' => t('The name of the application by which to prefix syslog messages.'), 'description' => t('The name of the application by which to prefix syslog messages.'),
'value' => 'icingaweb', 'value' => 'icingaweb',
'validators' => array( 'validators' => array(
array( array(
@ -85,7 +85,7 @@ class LoggingConfigForm extends Form
array( array(
'required' => true, 'required' => true,
'label' => t('Facility'), 'label' => t('Facility'),
'helptext' => t('The Syslog facility to utilize.'), 'description' => t('The Syslog facility to utilize.'),
'multiOptions' => array( 'multiOptions' => array(
'LOG_USER' => 'LOG_USER' 'LOG_USER' => 'LOG_USER'
) )
@ -98,7 +98,7 @@ class LoggingConfigForm extends Form
array( array(
'required' => true, 'required' => true,
'label' => t('Filepath'), 'label' => t('Filepath'),
'helptext' => t('The logfile to write messages to.'), 'description' => t('The logfile to write messages to.'),
'value' => $this->getDefaultLogDir(), 'value' => $this->getDefaultLogDir(),
'validators' => array(new WritablePathValidator()) 'validators' => array(new WritablePathValidator())
) )

View File

@ -60,9 +60,9 @@ class GeneralConfigForm extends ConfigForm
} }
/** /**
* @see Form::onShow() * @see Form::onRequest()
*/ */
public function onShow(Request $request) public function onRequest(Request $request)
{ {
$values = array(); $values = array();
foreach ($this->config as $section => $properties) { foreach ($this->config as $section => $properties) {

View File

@ -0,0 +1,128 @@
<?php
// {{{ICINGA_LICENSE_HEADER}}}
// {{{ICINGA_LICENSE_HEADER}}}
namespace Icinga\Form\Config\Resource;
use Exception;
use Zend_Config;
use Icinga\Web\Form;
use Icinga\Web\Request;
use Icinga\Web\Form\Element\Number;
use Icinga\Data\ResourceFactory;
/**
* Form class for adding/modifying database resources
*/
class DbResourceForm extends Form
{
/**
* Initialize this form
*/
public function init()
{
$this->setName('form_config_resource_db');
}
/**
* @see Form::createElements()
*/
public function createElements(array $formData)
{
return array(
$this->createElement(
'select',
'db',
array(
'required' => true,
'label' => t('Database Type'),
'description' => t('The type of SQL database'),
'multiOptions' => array(
'mysql' => 'MySQL',
'pgsql' => 'PostgreSQL'
//'oracle' => 'Oracle'
)
)
),
$this->createElement(
'text',
'host',
array (
'required' => true,
'label' => t('Host'),
'description' => t('The hostname of the database'),
'value' => 'localhost'
)
),
new Number(
array(
'required' => true,
'name' => 'port',
'label' => t('Port'),
'description' => t('The port to use'),
'value' => 3306
)
),
$this->createElement(
'text',
'dbname',
array(
'required' => true,
'label' => t('Database Name'),
'description' => t('The name of the database to use')
)
),
$this->createElement(
'text',
'username',
array (
'required' => true,
'label' => t('Username'),
'description' => t('The user name to use for authentication')
)
),
$this->createElement(
'password',
'password',
array(
'required' => true,
'renderPassword' => true,
'label' => t('Password'),
'description' => t('The password to use for authentication')
)
)
);
}
/**
* Validate that the current configuration points to a valid resource
*
* @see Form::onSuccess()
*/
public function onSuccess(Request $request)
{
if (false === $this->isValidResource($this)) {
return false;
}
}
/**
* Validate the resource configuration by trying to connect with it
*
* @param Form $form The form to fetch the configuration values from
*
* @return bool Whether validation succeeded or not
*/
public function isValidResource(Form $form)
{
try {
$resource = ResourceFactory::createResource(new Zend_Config($form->getValues()));
$resource->getConnection()->getConnection();
} catch (Exception $e) {
$form->addError(t('Connectivity validation failed, connection to the given resource not possible.'));
return false;
}
return true;
}
}

View File

@ -0,0 +1,50 @@
<?php
// {{{ICINGA_LICENSE_HEADER}}}
// {{{ICINGA_LICENSE_HEADER}}}
namespace Icinga\Form\Config\Resource;
use Icinga\Web\Form;
use Icinga\Web\Form\Validator\ReadablePathValidator;
/**
* Form class for adding/modifying file resources
*/
class FileResourceForm extends Form
{
/**
* Initialize this form
*/
public function init()
{
$this->setName('form_config_resource_file');
}
/**
* @see Form::createElements()
*/
public function createElements(array $formData)
{
return array(
$this->createElement(
'text',
'filename',
array(
'required' => true,
'label' => t('Filepath'),
'description' => t('The filename to fetch information from'),
'validators' => array(new ReadablePathValidator())
)
),
$this->createElement(
'text',
'fields',
array(
'required' => true,
'label' => t('Pattern'),
'description' => t('The regular expression by which to identify columns')
)
)
);
}
}

View File

@ -0,0 +1,114 @@
<?php
// {{{ICINGA_LICENSE_HEADER}}}
// {{{ICINGA_LICENSE_HEADER}}}
namespace Icinga\Form\Config\Resource;
use Exception;
use Zend_Config;
use Icinga\Web\Form;
use Icinga\Web\Request;
use Icinga\Web\Form\Element\Number;
use Icinga\Data\ResourceFactory;
/**
* Form class for adding/modifying ldap resources
*/
class LdapResourceForm extends Form
{
/**
* Initialize this form
*/
public function init()
{
$this->setName('form_config_resource_ldap');
}
/**
* @see Form::createElements()
*/
public function createElements(array $formData)
{
return array(
$this->createElement(
'text',
'hostname',
array(
'required' => true,
'label' => t('Host'),
'description' => t('The hostname or address of the LDAP server to use for authentication'),
'value' => 'localhost'
)
),
new Number(
array(
'required' => true,
'name' => 'port',
'label' => t('Port'),
'description' => t('The port of the LDAP server to use for authentication'),
'value' => 389
)
),
$this->createElement(
'text',
'root_dn',
array(
'required' => true,
'label' => t('Root DN'),
'description' => t('The path where users can be found on the ldap server')
)
),
$this->createElement(
'text',
'bind_dn',
array(
'required' => true,
'label' => t('Bind DN'),
'description' => t('The user dn to use for querying the ldap server')
)
),
$this->createElement(
'password',
'bind_pw',
array(
'required' => true,
'renderPassword' => true,
'label' => t('Bind Password'),
'description' => t('The password to use for querying the ldap server')
)
)
);
}
/**
* Validate that the current configuration points to a valid resource
*
* @see Form::onSuccess()
*/
public function onSuccess(Request $request)
{
if (false === $this->isValidResource($this)) {
return false;
}
}
/**
* Validate the resource configuration by trying to connect with it
*
* @param Form $form The form to fetch the configuration values from
*
* @return bool Whether validation succeeded or not
*/
public function isValidResource(Form $form)
{
try {
$resource = ResourceFactory::createResource(new Zend_Config($form->getValues()));
$resource->connect();
} catch (Exception $e) {
$form->addError(t('Connectivity validation failed, connection to the given resource not possible.'));
return false;
}
return true;
}
}

View File

@ -0,0 +1,77 @@
<?php
// {{{ICINGA_LICENSE_HEADER}}}
// {{{ICINGA_LICENSE_HEADER}}}
namespace Icinga\Form\Config\Resource;
use Exception;
use Zend_Config;
use Icinga\Web\Form;
use Icinga\Web\Request;
use Icinga\Application\Icinga;
use Icinga\Data\ResourceFactory;
/**
* Form class for adding/modifying livestatus resources
*/
class LivestatusResourceForm extends Form
{
/**
* Initialize this form
*/
public function init()
{
$this->setName('form_config_resource_livestatus');
}
/**
* @see Form::createElements()
*/
public function createElements(array $formData)
{
return array(
$this->createElement(
'text',
'socket',
array(
'required' => true,
'label' => t('Socket'),
'description' => t('The path to your livestatus socket used for querying monitoring data'),
'value' => realpath(Icinga::app()->getApplicationDir() . '/../var/rw/livestatus')
)
)
);
}
/**
* Validate that the current configuration points to a valid resource
*
* @see Form::onSuccess()
*/
public function onSuccess(Request $request)
{
if (false === $this->isValidResource($this)) {
return false;
}
}
/**
* Validate the resource configuration by trying to connect with it
*
* @param Form $form The form to fetch the configuration values from
*
* @return bool Whether validation succeeded or not
*/
public function isValidResource(Form $form)
{
try {
$resource = ResourceFactory::createResource(new Zend_Config($form->getValues()));
$resource->connect()->disconnect();
} catch (Exception $e) {
$form->addError(t('Connectivity validation failed, connection to the given resource not possible.'));
return false;
}
return true;
}
}

View File

@ -0,0 +1,54 @@
<?php
// {{{ICINGA_LICENSE_HEADER}}}
// {{{ICINGA_LICENSE_HEADER}}}
namespace Icinga\Form\Config\Resource;
use Icinga\Web\Form;
use Icinga\Application\Icinga;
use Icinga\Web\Form\Validator\ReadablePathValidator;
/**
* Form class for adding/modifying statusdat resources
*/
class StatusdatResourceForm extends Form
{
/**
* Initialize this form
*/
public function init()
{
$this->setName('form_config_resource_statusdat');
}
/**
* @see Form::createElements()
*/
public function createElements(array $formData)
{
return array(
$this->createElement(
'text',
'status_file',
array(
'required' => true,
'label' => t('Filepath'),
'description' => t('Location of your icinga status.dat file'),
'value' => realpath(Icinga::app()->getApplicationDir() . '/../var/status.dat'),
'validators' => array(new ReadablePathValidator())
)
),
$this->createElement(
'text',
'object_file',
array(
'required' => true,
'label' => t('Filepath'),
'description' => t('Location of your icinga objects.cache file'),
'value' => realpath(Icinga::app()->getApplicationDir() . '/../var/objects.cache'),
'validators' => array(new ReadablePathValidator())
)
)
);
}
}

View File

@ -0,0 +1,258 @@
<?php
// {{{ICINGA_LICENSE_HEADER}}}
// {{{ICINGA_LICENSE_HEADER}}}
namespace Icinga\Form\Config;
use InvalidArgumentException;
use Icinga\Web\Request;
use Icinga\Web\Notification;
use Icinga\Form\ConfigForm;
use Icinga\Form\Config\Resource\DbResourceForm;
use Icinga\Form\Config\Resource\FileResourceForm;
use Icinga\Form\Config\Resource\LdapResourceForm;
use Icinga\Form\Config\Resource\LivestatusResourceForm;
use Icinga\Form\Config\Resource\StatusdatResourceForm;
use Icinga\Application\Platform;
use Icinga\Exception\ConfigurationError;
class ResourceConfigForm extends ConfigForm
{
/**
* Initialize this form
*/
public function init()
{
$this->setName('form_config_resource');
$this->setSubmitLabel(t('Save Changes'));
}
/**
* Return a form object for the given resource type
*
* @param string $type The resource type for which to return a form
*
* @return Form
*/
public function getResourceForm($type)
{
if ($type === 'db') {
return new DbResourceForm();
} elseif ($type === 'ldap') {
return new LdapResourceForm();
} elseif ($type === 'livestatus') {
return new LivestatusResourceForm();
} elseif ($type === 'statusdat') {
return new StatusdatResourceForm();
} elseif ($type === 'file') {
return new FileResourceForm();
} else {
throw new InvalidArgumentException(sprintf(t('Invalid resource type "%s" provided'), $type));
}
}
/**
* Add a particular resource
*
* The backend to add is identified by the array-key `name'.
*
* @param array $values The values to extend the configuration with
*
* @return self
*
* @thrwos InvalidArgumentException In case the resource does already exist
*/
public function add(array $values)
{
$name = isset($values['name']) ? $values['name'] : '';
if (! $name) {
throw new InvalidArgumentException(t('Resource name missing'));
} elseif ($this->config->{$name} !== null) {
throw new InvalidArgumentException(t('Resource already exists'));
}
unset($values['name']);
$this->config->{$name} = $values;
return $this;
}
/**
* Edit a particular resource
*
* @param string $name The name of the resource to edit
* @param array $values The values to edit the configuration with
*
* @return array The edited configuration
*
* @throws InvalidArgumentException In case the resource does not exist
*/
public function edit($name, array $values)
{
if (! $name) {
throw new InvalidArgumentException(t('Old resource name missing'));
} elseif (! ($newName = isset($values['name']) ? $values['name'] : '')) {
throw new InvalidArgumentException(t('New resource name missing'));
} elseif (($resourceConfig = $this->config->get($name)) === null) {
throw new InvalidArgumentException(t('Unknown resource provided'));
}
unset($values['name']);
unset($this->config->{$name});
$this->config->{$newName} = array_merge($resourceConfig->toArray(), $values);
return $this->config->{$newName};
}
/**
* Remove a particular resource
*
* @param string $name The name of the resource to remove
*
* @return array The removed resource configuration
*
* @throws InvalidArgumentException In case the resource does not exist
*/
public function remove($name)
{
if (! $name) {
throw new InvalidArgumentException(t('Resource name missing'));
} elseif (($resourceConfig = $this->config->get($name)) === null) {
throw new InvalidArgumentException(t('Unknown resource provided'));
}
unset($this->config->{$name});
return $resourceConfig;
}
/**
* Add or edit a resource and save the configuration
*
* Performs a connectivity validation using the submitted values. A checkbox is
* added to the form to skip the check if it fails and redirection is aborted.
*
* @see Form::onSuccess()
*/
public function onSuccess(Request $request)
{
if (($el = $this->getElement('force_creation')) === null || false === $el->isChecked()) {
$resourceForm = $this->getResourceForm($this->getElement('type')->getValue());
if (method_exists($resourceForm, 'isValidResource') && false === $resourceForm->isValidResource($this)) {
$this->addElement($this->getForceCreationCheckbox());
return false;
}
}
$resource = $request->getQuery('resource');
try {
if ($resource === null) { // create new resource
$this->add($this->getValues());
$message = t('Resource "%s" has been successfully created');
} else { // edit existing resource
$this->edit($resource, $this->getValues());
$message = t('Resource "%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 resource 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)
{
$resource = $request->getQuery('resource');
if ($resource !== null) {
if ($resource === '') {
throw new ConfigurationError(t('Resource name missing'));
} elseif (false === isset($this->config->{$resource})) {
throw new ConfigurationError(t('Unknown resource provided'));
}
$configValues = $this->config->{$resource}->toArray();
$configValues['name'] = $resource;
$this->populate($configValues);
}
}
/**
* Return a checkbox to be displayed at the beginning of the form
* which allows the user to skip the connection validation
*
* @return Zend_Form_Element
*/
protected function getForceCreationCheckbox()
{
return $this->createElement(
'checkbox',
'force_creation',
array(
'order' => 0,
'ignore' => true,
'label' => t('Force Changes'),
'description' => t('Check this box to enforce changes without connectivity validation')
)
);
}
/**
* @see Form::createElemeents()
*/
public function createElements(array $formData)
{
$resourceType = isset($formData['type']) ? $formData['type'] : 'db';
$resourceTypes = array(
'file' => t('File'),
'statusdat' => 'Status.dat',
'livestatus' => 'Livestatus',
);
if ($resourceType === 'ldap' || Platform::extensionLoaded('ldap')) {
$resourceTypes['ldap'] = 'LDAP';
}
if ($resourceType === 'db' || Platform::extensionLoaded('mysql') || Platform::extensionLoaded('pgsql')) {
$resourceTypes['db'] = t('SQL Database');
}
$elements = array(
$this->createElement(
'text',
'name',
array(
'required' => true,
'label' => t('Resource Name'),
'description' => t('The unique name of this resource')
)
),
$this->createElement(
'select',
'type',
array(
'required' => true,
'autosubmit' => true,
'label' => t('Resource Type'),
'description' => t('The type of resource'),
'multiOptions' => $resourceTypes,
'value' => $resourceType
)
)
);
if (isset($formData['force_creation']) && $formData['force_creation']) {
// In case another error occured and the checkbox was displayed before
$elements[] = $this->getForceCreationCheckbox();
}
return array_merge($elements, $this->getResourceForm($resourceType)->createElements($formData));
}
}

View File

@ -1,444 +0,0 @@
<?php
// {{{ICINGA_LICENSE_HEADER}}}
// {{{ICINGA_LICENSE_HEADER}}}
namespace Icinga\Form\Config;
use Exception;
use Icinga\Application\Platform;
use Zend_Config;
use Icinga\Web\Form;
use Icinga\Application\Icinga;
use Icinga\Data\ResourceFactory;
use Icinga\Web\Form\Element\Number;
use Icinga\Web\Form\Decorator\HelpText;
use Icinga\Web\Form\Decorator\ElementWrapper;
class ResourceForm extends Form
{
/**
* Initialize this form
*/
public function init()
{
$this->setName('form_config_resource');
$this->setSubmitLabel(t('Save Changes'));
}
/**
* @see Form::createElemeents()
*/
public function createElements(array $formData)
{
$elements = array();
$elements[] = $this->createElement(
'text',
'name',
array(
'required' => true,
'label' => t('Resource Name'),
'helptext' => t('The unique name of this resource')
)
);
$elements[] = $this->createElement(
'select',
'type',
array(
'required' => true,
'class' => 'autosubmit',
'label' => t('Resource Type'),
'helptext' => t('The type of resource'),
'multiOptions' => array(
'db' => t('SQL Database'),
'ldap' => 'LDAP',
'statusdat' => 'Status.dat',
'livestatus' => 'Livestatus',
'file' => t('File')
)
)
);
if (isset($formData['force_creation']) && $formData['force_creation']) {
// In case the resource name already exists and the checkbox was displayed before
$elements[] = $this->getForceCreationCheckbox();
}
if (false === isset($formData['type']) || $formData['type'] === 'db') {
return array_merge($elements, $this->getDbElements());
} elseif ($formData['type'] === 'statusdat') {
return array_merge($elements, $this->getStatusdatElements());
} elseif ($formData['type'] === 'livestatus') {
return array_merge($elements, $this->getLivestatusElements());
} elseif ($formData['type'] === 'ldap') {
return array_merge($elements, $this->getLdapElements());
} elseif ($formData['type'] === 'file') {
return array_merge($elements, $this->getFileElements());
}
}
/**
* Return whether the given values are complete/valid and check whether it is possible to connect to the resource
*
* If connection validation fails, a checkbox is prepended to the form to allow users to skip it.
*
* @param array $data The data to validate
*
* @return bool Whether the validation succeeded or not
*/
public function isValid($data)
{
if (false === parent::isValid($data)) {
return false;
}
if (
(false === isset($data['force_creation']) || false == $data['force_creation'])
&& false === $this->isValidResource()
) {
$this->addElement($this->getForceCreationCheckbox());
return false;
}
return true;
}
/**
* Return whether a connection can be established with the current resource configuration values
*
* @return bool Whether the connection validation was successful or not
*/
public function isValidResource()
{
list($name, $config) = $this->getResourceConfig();
try {
switch ($config['type']) {
case 'db':
/*
* It should be possible to run icingaweb without the pgsql or mysql extension or Zend-Pdo-Classes,
* in case they aren't actually used. When the user tries to create a resource that depends on an
* uninstalled extension, an error should be displayed.
*/
if ($config['db'] === 'mysql' && false === Platform::extensionLoaded('mysql')) {
$this->addErrorMessage(
t('You need to install the php extension "mysql" and the ' .
'Zend_Pdo_Mysql classes to use MySQL database resources.')
);
return false;
}
if ($config['db'] === 'pgsql' && false === Platform::extensionLoaded('pgsql')) {
$this->addErrorMessage(
t('You need to install the php extension "pgsql" and the ' .
'Zend_Pdo_Pgsql classes to use PostgreSQL database resources.')
);
return false;
}
$resource = ResourceFactory::createResource(new Zend_Config($config));
$resource->getConnection()->getConnection();
break;
case 'statusdat':
if (
false === file_exists($config['object_file'])
|| false === file_exists($config['status_file'])
) {
$this->addErrorMessage(
t('Connectivity validation failed. At least one of the provided files does not exist.')
);
return false;
}
break;
case 'livestatus':
$resource = ResourceFactory::createResource(new Zend_Config($config));
$resource->connect()->disconnect();
break;
case 'ldap':
$resource = ResourceFactory::createResource(new Zend_Config($config));
$resource->connect();
break;
case 'file':
if (false === file_exists($config['filename'])) {
$this->addErrorMessage(t('Connectivity validation failed. The provided file does not exist.'));
return false;
}
break;
}
} catch (Exception $e) {
$this->addErrorMessage(t('Connectivity validation failed, connection to the given resource not possible.'));
return false;
}
return true;
}
/**
* Return the resource configuration values and its name
*
* The first value is the name and the second one the values as array.
*
* @return array
*/
public function getResourceConfig()
{
$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 resource
* @param array $config The configuration values
*/
public function setResourceConfig($name, array $config)
{
$config['name'] = $name;
$this->populate($config);
}
/**
* Return a checkbox to be displayed at the beginning of the form
* which allows the user to skip the connection validation
*
* @return Zend_Form_Element
*/
protected function getForceCreationCheckbox()
{
return $this->createElement(
'checkbox',
'force_creation',
array(
'order' => 0,
'ignore' => true,
'label' => t('Force Changes'),
'helptext' => t('Check this box to enforce changes without connectivity validation')
)
);
}
/**
* Return all required elements to define a resource of type "db"
*
* @return array
*/
protected function getDbElements()
{
return array(
$this->createElement(
'select',
'db',
array(
'required' => true,
'label' => t('Database Type'),
'helptext' => t('The type of SQL database'),
'multiOptions' => array(
'mysql' => 'MySQL',
'pgsql' => 'PostgreSQL'
//'oracle' => 'Oracle'
)
)
),
$this->createElement(
'text',
'host',
array (
'required' => true,
'label' => t('Host'),
'helptext' => t('The hostname of the database'),
'value' => 'localhost'
)
),
new Number(
array(
'required' => true,
'name' => 'port',
'label' => t('Port'),
'helptext' => t('The port to use'),
'value' => 3306,
'decorators' => array( // The order is important!
'ViewHelper',
'Errors',
new ElementWrapper(),
new HelpText()
)
)
),
$this->createElement(
'text',
'dbname',
array(
'required' => true,
'label' => t('Database Name'),
'helptext' => t('The name of the database to use')
)
),
$this->createElement(
'text',
'username',
array (
'required' => true,
'label' => t('Username'),
'helptext' => t('The user name to use for authentication')
)
),
$this->createElement(
'password',
'password',
array(
'required' => true,
'renderPassword' => true,
'label' => t('Password'),
'helptext' => t('The password to use for authentication')
)
)
);
}
/**
* Return all required elements to define a resource of type "statusdat"
*
* @return array
*/
protected function getStatusdatElements()
{
return array(
$this->createElement(
'text',
'status_file',
array(
'required' => true,
'label' => t('Filepath'),
'helptext' => t('Location of your icinga status.dat file'),
'value' => realpath(Icinga::app()->getApplicationDir() . '/../var/status.dat')
)
),
$this->createElement(
'text',
'object_file',
array(
'required' => true,
'label' => t('Filepath'),
'helptext' => t('Location of your icinga objects.cache file'),
'value' => realpath(Icinga::app()->getApplicationDir() . '/../var/objects.cache')
)
)
);
}
/**
* Return all required elements to define a resource of type "livestatus"
*
* @return array
*/
protected function getLivestatusElements()
{
return array(
$this->createElement(
'text',
'socket',
array(
'required' => true,
'label' => t('Socket'),
'helptext' => t('The path to your livestatus socket used for querying monitoring data'),
'value' => realpath(Icinga::app()->getApplicationDir() . '/../var/rw/livestatus')
)
)
);
}
/**
* Return all required elements to define a resource of type "ldap"
*
* @return array
*/
protected function getLdapElements()
{
return array(
$this->createElement(
'text',
'hostname',
array(
'required' => true,
'allowEmpty' => false,
'label' => t('Host'),
'helptext' => t('The hostname or address of the LDAP server to use for authentication'),
'value' => 'localhost'
)
),
new Number(
array(
'required' => true,
'name' => 'port',
'label' => t('Port'),
'helptext' => t('The port of the LDAP server to use for authentication'),
'value' => 389,
'decorators' => array( // The order is important!
'ViewHelper',
'Errors',
new ElementWrapper(),
new HelpText()
)
)
),
$this->createElement(
'text',
'root_dn',
array(
'required' => true,
'label' => t('Root DN'),
'helptext' => t('The path where users can be found on the ldap server')
)
),
$this->createElement(
'text',
'bind_dn',
array(
'required' => true,
'label' => t('Bind DN'),
'helptext' => t('The user dn to use for querying the ldap server')
)
),
$this->createElement(
'password',
'bind_pw',
array(
'required' => true,
'renderPassword' => true,
'label' => t('Bind Password'),
'helptext' => t('The password to use for querying the ldap server')
)
)
);
}
/**
* Return all required elements to define a resource of type "file"
*
* @return array
*/
protected function getFileElements()
{
return array(
$this->createElement(
'text',
'filename',
array(
'required' => true,
'label' => t('Filepath'),
'helptext' => t('The filename to fetch information from')
)
),
$this->createElement(
'text',
'fields',
array(
'required' => true,
'label' => t('Pattern'),
'helptext' => t('The regular expression by which to identify columns')
)
)
);
}
}

View File

@ -486,7 +486,7 @@ msgstr "Die Objekt-Klasse welche benutzt wird, um Benutzer auf diesem LDAP-Serve
#: /usr/local/src/bugfix.master/application/forms/Config/ResourceForm.php:182 #: /usr/local/src/bugfix.master/application/forms/Config/ResourceForm.php:182
msgid "The password to use for authentication" msgid "The password to use for authentication"
msgstr "Das Kennwort welche zur Authentifizierung benutzt werden soll" msgstr "Das Kennwort welches zur Authentifizierung benutzt werden soll"
#: /usr/local/src/bugfix.master/application/forms/Config/ResourceForm.php:270 #: /usr/local/src/bugfix.master/application/forms/Config/ResourceForm.php:270
msgid "The password to use for querying the ldap server" msgid "The password to use for querying the ldap server"

View File

@ -2,29 +2,41 @@
// {{{ICINGA_LICENSE_HEADER}}} // {{{ICINGA_LICENSE_HEADER}}}
// {{{ICINGA_LICENSE_HEADER}}} // {{{ICINGA_LICENSE_HEADER}}}
use \Zend_View_Helper_FormElement;
/** /**
* Helper to generate a number input * Render number input controls
*/ */
class Zend_View_Helper_FormNumber extends \Zend_View_Helper_FormText class Zend_View_Helper_FormNumber extends Zend_View_Helper_FormElement
{ {
/** /**
* Generates a html number input * Render the number input control
* *
* @access public * @param string $name
* @param int $value
* @param array $attribs
* *
* @param string $name The element name. * @return string The rendered number input control
* @param string $value The default value.
* @param array $attribs Attributes which should be added to the input tag.
*
* @return string The input tag and options XHTML.
*/ */
public function formNumber($name, $value = null, $attribs = null) public function formNumber($name, $value = null, $attribs = null)
{ {
return '<input type="number"' $info = $this->_getInfo($name, $value, $attribs);
. ' name="' . $this->view->escape($name) . '"' extract($info); // name, id, value, attribs, options, listsep, disable
. ' value="' . $this->view->escape($value) . '"' /** @var string $id */
. ' id="' . $this->view->escape($name) . '"' /** @var bool $disable */
. $this->_htmlAttribs($attribs) $disabled = '';
. $this->getClosingBracket(); if ($disable) {
$disabled = ' disabled="disabled"';
}
$html5 = sprintf(
'<input type="number" name="%s" id="%s" value="%s"%s%s%s',
$this->view->escape($name),
$this->view->escape($id),
$this->view->escape($value),
$disabled,
$this->_htmlAttribs($attribs),
$this->getClosingBracket()
);
return $html5;
} }
} }

View File

@ -2,10 +2,9 @@
<?= $tabs; ?> <?= $tabs; ?>
</div> </div>
<div class="content" data-base-target="_next"> <div class="content" data-base-target="_next">
<?= $messageBox; ?>
<p> <p>
<a href="<?= $this->href('/config/createresource') ?>"> <a href="<?= $this->href('/config/createresource'); ?>">
<?= $this->icon('create.png'); ?> <?= $this->translate('Create a new resource'); ?> <?= $this->icon('create.png'); ?> <?= $this->translate('Create A New Resource'); ?>
</a> </a>
</p> </p>
<table class="action"> <table class="action">
@ -17,12 +16,12 @@
<?php foreach ($this->resources as $name => $resource): ?> <?php foreach ($this->resources as $name => $resource): ?>
<tr> <tr>
<td> <td>
<a href="<?= $this->href('config/editresource', array('resource' => $name)) ?>"> <a href="<?= $this->href('config/editresource', array('resource' => $name)); ?>">
<?= $this->icon('edit.png') ?> <?= $this->escape($name); ?> <?= $this->icon('edit.png'); ?> <?= $this->escape($name); ?>
</a> </a>
</td> </td>
<td style="text-align: center"> <td style="text-align: center">
<a href="<?= $this->href('config/removeresource', array('resource' => $name)) ?>"> <a href="<?= $this->href('config/removeresource', array('resource' => $name)); ?>">
<?= $this->icon('remove.png'); ?> <?= $this->icon('remove.png'); ?>
</a> </a>
</td> </td>

View File

@ -1,4 +1,3 @@
<?= $messageBox; ?> <h4><?= $this->translate('Create A New Resource'); ?></h4>
<h4><?= $this->translate('Create a new resource'); ?></h4> <p><?= $this->translate('Resources are entities that provide data to Icinga Web 2.'); ?></p>
<p><?= $this->translate('Resources are entities that provide data to Icingaweb.'); ?></p>
<?= $form; ?> <?= $form; ?>

View File

@ -1,3 +1,2 @@
<h4><?= $this->translate('Edit Existing Resource'); ?></h4> <h4><?= $this->translate('Edit Existing Resource'); ?></h4>
<?= $messageBox; ?>
<?= $form; ?> <?= $form; ?>

View File

@ -1,3 +1,2 @@
<h4><?= $this->translate('Remove Existing Resource'); ?></h4> <h4><?= $this->translate('Remove Existing Resource'); ?></h4>
<?= $messageBox; ?>
<?= $form; ?> <?= $form; ?>

View File

@ -11,7 +11,4 @@
<hr /> <hr />
<pre><?= $this->escape($stackTrace) ?></pre> <pre><?= $this->escape($stackTrace) ?></pre>
<?php endif ?> <?php endif ?>
<?php if (isset($this->messageBox)) : ?>
<?= $this->messageBox->render(); ?>
<? endif ?>
</div> </div>

View File

@ -7,7 +7,6 @@ namespace Icinga;
use DateTimeZone; use DateTimeZone;
use InvalidArgumentException; use InvalidArgumentException;
use Icinga\User\Preferences; use Icinga\User\Preferences;
use Icinga\User\Message;
/** /**
* This class represents an authorized user * This class represents an authorized user
@ -98,13 +97,6 @@ class User
*/ */
protected $preferences; protected $preferences;
/**
* Queued notifications for this user.
*
* @var array()
*/
protected $messages;
/** /**
* Creates a user object given the provided information * Creates a user object given the provided information
* *
@ -382,38 +374,6 @@ class User
return new DateTimeZone($tz); return new DateTimeZone($tz);
} }
/**
* Add a message that can be accessed from future requests, to this user.
*
* This function does NOT automatically write to the session, messages will not be persisted until you do.
*
* @param Message $msg The message
*/
public function addMessage(Message $msg)
{
$this->messages[] = $msg;
}
/**
* Get all currently pending messages
*
* @return array The messages
*/
public function getMessages()
{
return isset($this->messages) ? $this->messages : array();
}
/**
* Remove all messages from this user
*
* This function does NOT automatically write the session, messages will not be persisted until you do.
*/
public function clearMessages()
{
$this->messages = null;
}
/** /**
* Set additional remote user information * Set additional remote user information
* *

View File

@ -1,59 +0,0 @@
<?php
// {{{ICINGA_LICENSE_HEADER}}}
// {{{ICINGA_LICENSE_HEADER}}}
namespace Icinga\User;
use Zend_Log;
/**
* Class Message
*
* A Message with an additional logging level to indicate the type.
*
* @package Icinga\User
*/
class Message
{
/**
* The content of this message
*
* @var string
*/
private $message;
/**
* The logging-level of this message
*/
private $level;
/**
* Create a new Message
*
* @param string $message The message content
* @param $level The status of the message
* * Zend_Log::INFO
* * Zend_Log::ERR
*/
public function __construct($message, $level = Zend_Log::INFO)
{
$this->message = $message;
$this->level = $level;
}
/**
* @return string
*/
public function getMessage()
{
return $this->message;
}
/**
* @return The
*/
public function getLevel()
{
return $this->level;
}
}

View File

@ -1,75 +0,0 @@
<?php
// {{{ICINGA_LICENSE_HEADER}}}
// {{{ICINGA_LICENSE_HEADER}}}
namespace Icinga\Web\Controller;
use Zend_Log;
use Icinga\Web\Session;
use Icinga\User\Message;
use Icinga\Authentication\Manager as AuthenticationManager;
/**
* Base class for Configuration Controllers
*
* Module preferences use this class to make sure they are automatically
* added to the application's configuration dialog. If you create a subclass of
* BasePreferenceController and overwrite @see init(), make sure you call
* parent::init(), otherwise you won't have the $tabs property in your view.
*/
class BaseConfigController extends ActionController
{
/**
* Send a message with the logging level Zend_Log::INFO to the current user and
* commit the changes to the underlying session.
*
* @param $msg The message content
*/
protected function addSuccessMessage($msg)
{
AuthenticationManager::getInstance()->getUser()->addMessage(
new Message($msg, Zend_Log::INFO)
);
Session::getSession()->write();
}
/**
* Send a message with the logging level Zend_Log::ERR to the current user and
* commit the changes to the underlying session.
*
* @param $msg The message content
*/
protected function addErrorMessage($msg)
{
AuthenticationManager::getInstance()->getUser()->addMessage(
new Message($msg, Zend_Log::ERR)
);
Session::getSession()->write();
}
/**
* Send a message with the logging level Zend_Log::WARN to the current user and
* commit the changes to the underlying session.
*
* @param $msg The message content
*/
protected function addWarningMessage($msg)
{
AuthenticationManager::getInstance()->getUser()->addMessage(
new Message($msg, Zend_Log::WARN)
);
Session::getSession()->write();
}
/*
* Return an array of tabs provided by this configuration controller.
*
* Those tabs will automatically be added to the application's configuration dialog
*
* @return array
*/
public static function createProvidedTabs()
{
return array();
}
}

View File

@ -8,9 +8,7 @@ use LogicException;
use Zend_Form; use Zend_Form;
use Zend_View_Interface; use Zend_View_Interface;
use Icinga\Application\Icinga; use Icinga\Application\Icinga;
use Icinga\Web\Form\Decorator\HelpText;
use Icinga\Web\Form\Decorator\NoScriptApply; use Icinga\Web\Form\Decorator\NoScriptApply;
use Icinga\Web\Form\Decorator\ElementWrapper;
use Icinga\Web\Form\Element\CsrfCounterMeasure; use Icinga\Web\Form\Element\CsrfCounterMeasure;
/** /**
@ -99,6 +97,7 @@ class Form extends Zend_Form
if ($this->onSuccess !== null && false === is_callable($this->onSuccess)) { if ($this->onSuccess !== null && false === is_callable($this->onSuccess)) {
throw new LogicException('The option `onSuccess\' is not callable'); throw new LogicException('The option `onSuccess\' is not callable');
} }
if (! isset($options['elementDecorators'])) { if (! isset($options['elementDecorators'])) {
$options['elementDecorators'] = array( $options['elementDecorators'] = array(
'ViewHelper', 'ViewHelper',
@ -108,6 +107,7 @@ class Form extends Zend_Form
array('HtmlTag', array('tag' => 'div')) array('HtmlTag', array('tag' => 'div'))
); );
} }
parent::__construct($options); parent::__construct($options);
} }
@ -321,7 +321,7 @@ class Form extends Zend_Form
* *
* @param Request $request The current request * @param Request $request The current request
*/ */
public function onShow(Request $request) public function onRequest(Request $request)
{ {
} }
@ -372,6 +372,7 @@ class Form extends Zend_Form
if (is_array($options) && ! isset($options['disableLoadDefaultDecorators'])) { if (is_array($options) && ! isset($options['disableLoadDefaultDecorators'])) {
$options['disableLoadDefaultDecorators'] = true; $options['disableLoadDefaultDecorators'] = true;
} }
$el = parent::createElement($type, $name, $options); $el = parent::createElement($type, $name, $options);
if ($el && $el->getAttrib('autosubmit')) { if ($el && $el->getAttrib('autosubmit')) {
$el->addDecorator(new NoScriptApply()); // Non-JS environments $el->addDecorator(new NoScriptApply()); // Non-JS environments
@ -386,6 +387,7 @@ class Form extends Zend_Form
$el->setAttrib('class', $class); // JS environments $el->setAttrib('class', $class); // JS environments
unset($el->autosubmit); unset($el->autosubmit);
} }
return $el; return $el;
} }
@ -439,7 +441,7 @@ class Form extends Zend_Form
* Process the given request using this form * Process the given request using this form
* *
* Redirects to the url set with setRedirectUrl() upon success. See onSuccess() * Redirects to the url set with setRedirectUrl() upon success. See onSuccess()
* and onShow() wherewith you can customize the processing logic. * and onRequest() wherewith you can customize the processing logic.
* *
* @param Request $request The request to be processed * @param Request $request The request to be processed
* *
@ -465,7 +467,7 @@ class Form extends Zend_Form
$this->isValidPartial($formData); $this->isValidPartial($formData);
} }
} else { } else {
$this->onShow($request); $this->onRequest($request);
} }
return $request; return $request;
@ -555,6 +557,7 @@ class Form extends Zend_Form
if ($this->loadDefaultDecoratorsIsDisabled()) { if ($this->loadDefaultDecoratorsIsDisabled()) {
return $this; return $this;
} }
$decorators = $this->getDecorators(); $decorators = $this->getDecorators();
if (empty($decorators)) { if (empty($decorators)) {
if ($this->viewScript) { if ($this->viewScript) {
@ -563,11 +566,13 @@ class Form extends Zend_Form
'form' => $this 'form' => $this
)); ));
} else { } else {
$this $this->addDecorator('FormErrors', array('onlyCustomFormErrors' => true))
->addDecorator('FormElements') ->addDecorator('FormElements')
//->addDecorator('HtmlTag', array('tag' => 'dl', 'class' => 'zend_form'))
->addDecorator('Form'); ->addDecorator('Form');
} }
} }
return $this; return $this;
} }

View File

@ -4,38 +4,37 @@
namespace Icinga\Web\Form\Element; namespace Icinga\Web\Form\Element;
use Zend_Form_Element_Xhtml; use Zend_Form_Element;
/** /**
* Number form element * A number input control
*/ */
class Number extends Zend_Form_Element_Xhtml class Number extends Zend_Form_Element
{ {
/** /**
* Default form view helper to use for rendering * Disable default decorators
*
* \Icinga\Web\Form sets default decorators for elements.
*
* @var bool
*
* @see \Icinga\Web\Form::__construct() For default element decorators.
*/
protected $_disableLoadDefaultDecorators = true;
/**
* Form view helper to use for rendering
* *
* @var string * @var string
*/ */
public $helper = "formNumber"; public $helper = 'formNumber';
/** /**
* Check whether $value is of type integer * (non-PHPDoc)
* * @see \Zend_Form_Element::init() For the method documentation.
* @param string $value The value to check
* @param mixed $context Context to use
*
* @return bool
*/ */
public function isValid($value, $context = null) public function init()
{ {
if (parent::isValid($value, $context)) { $this->addValidator('Int');
if (is_numeric($value)) {
return true;
}
$this->addError(t('Please enter a number.'));
}
return false;
} }
} }

View File

@ -0,0 +1,58 @@
<?php
// {{{ICINGA_LICENSE_HEADER}}}
// {{{ICINGA_LICENSE_HEADER}}}
namespace Icinga\Web\Form\Validator;
use Zend_Validate_Abstract;
/**
* Validator that interprets the value as a filepath and checks if it's readable
*
* This validator should be preferred due to Zend_Validate_File_Exists is
* getting confused if there is another element in the form called `name'.
*/
class ReadablePathValidator extends Zend_Validate_Abstract
{
/**
* The messages to write on different error states
*
* @var array
*
* @see Zend_Validate_Abstract::$_messageTemplates
*/
protected $_messageTemplates;
/**
* Initialize this validator
*/
public function __construct()
{
$this->_messageTemplates = array(
'NOT_READABLE' => t('Path is not readable'),
'DOES_NOT_EXIST' => t('Path does not exist')
);
}
/**
* Check whether the given value is a readable filepath
*
* @param string $value The value submitted in the form
* @param mixed $context The context of the form
*
* @return bool Whether the value was successfully validated
*/
public function isValid($value, $context = null)
{
if (false === file_exists($value)) {
$this->_error('DOES_NOT_EXIST');
return false;
}
if (false === is_readable($value)) {
$this->_error('NOT_READABLE');
}
return true;
}
}

View File

@ -1,133 +0,0 @@
<?php
// {{{ICINGA_LICENSE_HEADER}}}
// {{{ICINGA_LICENSE_HEADER}}}
namespace Icinga\Web\Widget;
use Zend_Log;
use Zend_Form;
use Zend_View_Abstract;
use Icinga\User;
use Icinga\User\Message;
use Icinga\Web\Session;
use Icinga\Authentication\Manager as AuthenticationManager;
/**
* Displays a set of alert messages to the user.
*
* The messages are fetched automatically from the current AuthenticationManager,
* but this is done lazily when render() is called, to ensure that messages will
* always be displayed before they are cleared.
*/
class AlertMessageBox extends AbstractWidget
{
/**
* Remove all messages from the current user, return them and commit
* changes to the underlying session.
*
* @return array The messages
*/
protected function getAndClearMessages()
{
$messages = $this->user->getMessages();
$this->user->clearMessages();
Session::getSession()->write();
return $messages;
}
/**
* The displayed alert messages
*
* @var array
*/
private $messages = array();
/**
* The user to fetch the messages from
*
* @var User
*/
private $user;
/**
* The available states.
*
* @var array
*/
private $states = array(
Zend_Log::INFO => array(
'state' => 'alert-success',
'icon' => 'success.png'
),
Zend_Log::NOTICE => array(
'state' => 'alert-info',
'icon' => 'info.png'
),
Zend_Log::WARN => array(
'state' => 'alert-warning',
'icon' => 'warning.png'
),
Zend_Log::ERR => array(
'state' => 'alert-danger',
'icon' => 'error.png'
)
);
/**
* Create a new AlertBox
*
* @param boolean showUserMessages If the current user messages should be displayed
* in this AlertMessageBox. Defaults to false
*/
public function __construct($showUserMessages = false)
{
if ($showUserMessages) {
$this->user = AuthenticationManager::getInstance()->getUser();
}
}
/**
* Add a new error
*
* @param $error
*/
public function addError($error)
{
$this->messages[] = new Message($error, Zend_Log::ERR);
}
/**
* Add the error messages of the given Zend_Form
*/
public function addForm(Zend_Form $form)
{
foreach ($form->getErrorMessages() as $error) {
$this->addError($error);
}
}
/**
* Output the HTML of the AlertBox
*
* @return string
*/
public function render(Zend_View_Abstract $view = null)
{
$html = '';
if (isset($this->user)) {
$this->messages = array_merge($this->messages, $this->getAndClearMessages());
}
foreach ($this->messages as $message) {
$level = $message->getLevel();
if (!array_key_exists($level, $this->states)) {
continue;
}
$alert = $this->states[$level];
$html .= '<div class="alert ' . $alert['state']. '">' .
$this->view()->icon($alert['icon']) .
'<strong>' . htmlspecialchars($message->getMessage()) . '</strong>' .
'</div>';
}
return $html;
}
}