N°2847 - Add Title component

* Add id to button factory
 * Rework of Configuration File Editor page
This commit is contained in:
Eric
2020-09-18 18:15:03 +02:00
parent 08eada82f4
commit 74160d2447
13 changed files with 287 additions and 215 deletions

View File

@@ -24,6 +24,10 @@
* @license http://opensource.org/licenses/AGPL-3.0
*/
use Combodo\iTop\Application\UI\Component\Alert\AlertFactory;
use Combodo\iTop\Application\UI\Component\Button\ButtonFactory;
use Combodo\iTop\Application\UI\Component\Html\Html;
use Combodo\iTop\Application\UI\Component\Title\TitleFactory;
use Combodo\iTop\Config\Validator\iTopConfigAstValidator;
use Combodo\iTop\Config\Validator\iTopConfigSyntaxValidator;
@@ -59,8 +63,7 @@ function DBPasswordInNewConfigIsOk($sSafeContent)
{
$bIsWindows = (array_key_exists('WINDIR', $_SERVER) || array_key_exists('windir', $_SERVER));
if ($bIsWindows && (preg_match("@'db_pwd' => '[^%!\"]+',@U", $sSafeContent) === 0))
{
if ($bIsWindows && (preg_match("@'db_pwd' => '[^%!\"]+',@U", $sSafeContent) === 0)) {
return false;
}
return true;
@@ -82,112 +85,108 @@ $oP->add_linked_script(utils::GetAbsoluteUrlAppRoot().'/js/ace/mode-php.js');
$oP->add_linked_script(utils::GetAbsoluteUrlAppRoot().'/js/ace/theme-eclipse.js');
$oP->add_linked_script(utils::GetAbsoluteUrlAppRoot().'/js/ace/ext-searchbox.js');
try
{
try {
$sOperation = utils::ReadParam('operation', '');
$iEditorTopMargin = 0;
$iEditorTopMargin = 2;
$oP->add("<h1>".Dict::S('config-edit-title')."</h1>");
$oP->AddUiBlock(TitleFactory::MakeForPage(Dict::S('config-edit-title')));
if (MetaModel::GetConfig()->Get('demo_mode'))
{
$oP->add("<div class=\"header_message message_info\">Sorry, iTop is in <b>demonstration mode</b>: the configuration file cannot be edited.</div>");
}
else if (MetaModel::GetModuleSetting('itop-config', 'config_editor', '') == 'disabled')
{
$oP->add("<div class=\"header_message message_info\">iTop interactive edition of the configuration as been disabled. See <tt>'config_editor' => 'disabled'</tt> in the configuration file.</div>");
}
else
{
$sConfigFile = APPROOT.'conf/'.utils::GetCurrentEnvironment().'/config-itop.php';
if (MetaModel::GetConfig()->Get('demo_mode')) {
$oAlert = AlertFactory::MakeForInformation('', "Sorry, iTop is in <b>demonstration mode</b>: the configuration file cannot be edited.");
$oP->AddUiBlock($oAlert);
} else {
if (MetaModel::GetModuleSetting('itop-config', 'config_editor', '') == 'disabled') {
$oAlert = AlertFactory::MakeForWarning('', "iTop interactive edition of the configuration as been disabled. See <tt>'config_editor' => 'disabled'</tt> in the configuration file.");
$oP->AddUiBlock($oAlert);
} else {
$sConfigFile = APPROOT.'conf/'.utils::GetCurrentEnvironment().'/config-itop.php';
$iEditorTopMargin += 9;
$sConfig = str_replace("\r\n", "\n", file_get_contents($sConfigFile));
$sOriginalConfig = $sConfig;
$iEditorTopMargin += 9;
$sConfig = str_replace("\r\n", "\n", file_get_contents($sConfigFile));
$sOriginalConfig = $sConfig;
if (!empty($sOperation))
{
$iEditorTopMargin += 5;
$sConfig = utils::ReadParam('new_config', '', false, 'raw_data');
$sOriginalConfig = utils::ReadParam('prev_config', '', false, 'raw_data');
}
if (!empty($sOperation)) {
$iEditorTopMargin += 5;
$sConfig = utils::ReadParam('new_config', '', false, 'raw_data');
$sOriginalConfig = utils::ReadParam('prev_config', '', false, 'raw_data');
}
if ($sOperation == 'revert')
{
$oP->add('<div id="save_result" class="header_message message_info">'.Dict::S('config-reverted').'</div>');
}
if ($sOperation == 'save')
{
$sTransactionId = utils::ReadParam('transaction_id', '', false, 'transaction_id');
if (!utils::IsTransactionValid($sTransactionId, true))
{
$oP->add("<div class=\"header_message message_info\">Error: invalid Transaction ID. The configuration was <b>NOT</b> modified.</div>");
}
else
{
if ($sConfig == $sOriginalConfig)
{
$oP->add('<div id="save_result" class="header_message">'.Dict::S('config-no-change').'</div>');
}
else
{
try
{
TestConfig($sConfig, $oP); // throws exceptions
if ($sOperation == 'revert') {
$oAlert = AlertFactory::MakeForWarning('', Dict::S('config-reverted'));
$oP->AddUiBlock($oAlert);
}
if ($sOperation == 'save') {
$sTransactionId = utils::ReadParam('transaction_id', '', false, 'transaction_id');
if (!utils::IsTransactionValid($sTransactionId, true)) {
$oAlert = AlertFactory::MakeForFailure('', 'Error: invalid Transaction ID. The configuration was <b>NOT</b> modified.');
$oP->AddUiBlock($oAlert);
} else {
if ($sConfig == $sOriginalConfig) {
$oAlert = AlertFactory::MakeForInformation('', Dict::S('config-no-change'));
$oP->AddUiBlock($oAlert);
} else {
try {
TestConfig($sConfig, $oP); // throws exceptions
@chmod($sConfigFile, 0770); // Allow overwriting the file
$sTmpFile = tempnam(SetupUtils::GetTmpDir(), 'itop-cfg-');
// Don't write the file as-is since it would allow to inject any kind of PHP code.
// Instead write the interpreted version of the file
// Note:
// The actual raw PHP code will anyhow be interpreted exactly twice: once in TestConfig() above
// and a second time during the load of the Config object below.
// If you are really concerned about an iTop administrator crafting some malicious
// PHP code inside the config file, then turn off the interactive configuration
// editor by adding the configuration parameter:
// 'itop-config' => array(
// 'config_editor' => 'disabled',
// )
file_put_contents($sTmpFile, $sConfig);
$oTempConfig = new Config($sTmpFile, true);
$oTempConfig->WriteToFile($sConfigFile);
@unlink($sTmpFile);
@chmod($sConfigFile, 0440); // Read-only
@chmod($sConfigFile, 0770); // Allow overwriting the file
$sTmpFile = tempnam(SetupUtils::GetTmpDir(), 'itop-cfg-');
// Don't write the file as-is since it would allow to inject any kind of PHP code.
// Instead write the interpreted version of the file
// Note:
// The actual raw PHP code will anyhow be interpreted exactly twice: once in TestConfig() above
// and a second time during the load of the Config object below.
// If you are really concerned about an iTop administrator crafting some malicious
// PHP code inside the config file, then turn off the interactive configuration
// editor by adding the configuration parameter:
// 'itop-config' => array(
// 'config_editor' => 'disabled',
// )
file_put_contents($sTmpFile, $sConfig);
$oTempConfig = new Config($sTmpFile, true);
$oTempConfig->WriteToFile($sConfigFile);
@unlink($sTmpFile);
@chmod($sConfigFile, 0440); // Read-only
if (DBPasswordInNewConfigIsOk($sConfig))
{
$oP->p('<div id="save_result" class="header_message message_ok">'.Dict::S('config-saved').'</div>');
}
else
{
$oP->p('<div id="save_result" class="header_message message_info">'.Dict::S('config-saved-warning-db-password').'</div>');
}
$sOriginalConfig = str_replace("\r\n", "\n", file_get_contents($sConfigFile));
}
catch (Exception $e)
{
$oP->p('<div id="save_result" class="header_message message_error">'.$e->getMessage().'</div>');
}
}
}
}
if (DBPasswordInNewConfigIsOk($sConfig)) {
$oAlert = AlertFactory::MakeForSuccess('', Dict::S('config-saved'));
} else {
$oAlert = AlertFactory::MakeForInformation('', Dict::S('config-saved-warning-db-password'));
}
$oP->AddUiBlock($oAlert);
$sOriginalConfig = str_replace("\r\n", "\n", file_get_contents($sConfigFile));
} catch (Exception $e) {
$oAlert = AlertFactory::MakeForDanger('', $e->getMessage());
$oP->AddUiBlock($oAlert);
}
}
}
}
$sConfigEscaped = htmlentities($sConfig, ENT_QUOTES, 'UTF-8');
$sOriginalConfigEscaped = htmlentities($sOriginalConfig, ENT_QUOTES, 'UTF-8');
$oP->p(Dict::S('config-edit-intro'));
$oP->add("<form method=\"POST\">");
$oP->add("<input id=\"operation\" type=\"hidden\" name=\"operation\" value=\"save\">");
$oP->add("<input type=\"hidden\" name=\"transaction_id\" value=\"".utils::GetNewTransactionId()."\">");
$oP->add("<input id=\"submit_button\" type=\"submit\" value=\"".Dict::S('config-apply')."\" title=\"".Dict::S('config-apply-title')."\"><button id=\"cancel_button\" disabled=\"disabled\" onclick=\"return ResetConfig();\">".Dict::S('config-cancel')."</button>");
$oP->add("<input type=\"hidden\" id=\"prev_config\" name=\"prev_config\" value=\"$sOriginalConfigEscaped\">");
$oP->add("<input type=\"hidden\" name=\"new_config\" value=\"$sConfigEscaped\">");
$oP->add("<div id =\"new_config\" style=\"position: absolute; top: ".$iEditorTopMargin."em; bottom: 0; left: 5px; right: 5px;\"></div>");
$oP->add("</form>");
$sConfirmCancel = addslashes(Dict::S('config-confirm-cancel'));
$oP->add_script(
<<<'JS'
$sConfigEscaped = htmlentities($sConfig, ENT_QUOTES, 'UTF-8');
$sOriginalConfigEscaped = htmlentities($sOriginalConfig, ENT_QUOTES, 'UTF-8');
$oP->AddUiBlock(new Html('<p>'.Dict::S('config-edit-intro').'</p>'));
$oP->add("<form method=\"POST\">");
$oP->add("<input id=\"operation\" type=\"hidden\" name=\"operation\" value=\"save\">");
$oP->add("<input type=\"hidden\" name=\"transaction_id\" value=\"".utils::GetNewTransactionId()."\">");
// - Cancel button
$oCancelButton = ButtonFactory::MakeForSecondaryAction(Dict::S('config-cancel'), 'cancel_button', null, true, 'cancel_button');
$oCancelButton->SetOnClickJsCode("return ResetConfig();");
$oP->AddUiBlock($oCancelButton);
// - Submit button
$oSubmitButton = ButtonFactory::MakeForValidationAction(Dict::S('config-apply'), null, Dict::S('config-apply'), true, 'submit_button');
$oP->AddUiBlock($oSubmitButton);
$oP->add("<input type=\"hidden\" id=\"prev_config\" name=\"prev_config\" value=\"$sOriginalConfigEscaped\">");
$oP->add("<input type=\"hidden\" name=\"new_config\" value=\"$sConfigEscaped\">");
$oP->add("<div id =\"new_config\" style=\"position: absolute; top: ".$iEditorTopMargin."em; bottom: 0; left: 5px; right: 5px;\"></div>");
$oP->add("</form>");
$oP->add_script(
<<<'JS'
var EditorUtils = (function() {
var STORAGE_RANGE_KEY = 'cfgEditorRange';
var STORAGE_LINE_KEY = 'cfgEditorFirstline';
@@ -301,30 +300,30 @@ $editorForm.submit(function() {
EditorUtils.restoreEditorDisplay(editor);
editor.focus();
JS
);
);
$oP->add_script(
<<<EOF
$sConfirmCancel = addslashes(Dict::S('config-confirm-cancel'));
$oP->add_script(<<<JS
function ResetConfig()
{
var editor = ace.edit("new_config");
$("#operation").attr('value', 'revert');
if (editor.getValue() != $('#prev_config').val())
var prevConfig = $('#prev_config');
if (editor.getValue() != prevConfig.val())
{
if (confirm('$sConfirmCancel'))
{
$('input[name="new_config"]').val($('#prev_config').val());
$('input[name="new_config"]').val(prevConfig.val());
return true;
}
}
return false;
}
EOF
);
JS
);
}
}
}
catch(Exception $e)
{
} catch (Exception $e) {
$oP->p('<b>'.$e->getMessage().'</b>');
}