From 8fcd4544451a406dca1734fff9dd414be92461a4 Mon Sep 17 00:00:00 2001 From: Pierre Goiffon Date: Tue, 19 Apr 2022 14:36:15 +0200 Subject: [PATCH] =?UTF-8?q?N=C2=B04919=20New=20'Launch=20setup"=20in=20App?= =?UTF-8?q?lication=20Upgrade=20(#244)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Admin will now be able to re-launch the iTop setup directly from the administration console in the Administration / Application Upgrade screen. Before the only way to launch setup on an existing iTop instance was to change permissions on the configuration file. This button will be enabled depending on the isDevEnv (if true it will be displayed) and `setup.launch_button.enabled` new configuration parameter (not present by default ; if set to false will always hide the button, if set to true will always display it, if not set will display button depending on isDevEnv only). Co-authored-by: Molkobain --- core/config.class.inc.php | 8 ++++++++ datamodels/2.x/itop-config/config.php | 6 ++++-- .../dictionaries/en.dict.itop-core-update.php | 4 ++++ .../src/Controller/AjaxController.php | 20 +++++++++++++++++-- .../src/Controller/UpdateController.php | 19 ++++++++++++++++++ .../view/SelectUpdateFile.html.twig | 8 ++++++++ .../view/SelectUpdateFile.ready.js.twig | 4 ++++ index.php | 8 +++++--- setup/wizardcontroller.class.inc.php | 7 ++++++- 9 files changed, 76 insertions(+), 8 deletions(-) diff --git a/core/config.class.inc.php b/core/config.class.inc.php index 6648ad60a4..39791fa86e 100644 --- a/core/config.class.inc.php +++ b/core/config.class.inc.php @@ -1552,6 +1552,14 @@ class Config 'source_of_value' => '', 'show_in_conf_sample' => false, ], + 'setup.launch_button.enabled' => [ + 'type' => 'bool', + 'description' => 'If true displays in the Application Upgrade screen a button allowing to launch the setup in a single click (no more manual config file permission change needed)', + 'default' => null, + 'value' => false, + 'source_of_value' => '', + 'show_in_conf_sample' => false, + ], ]; public function IsProperty($sPropCode) diff --git a/datamodels/2.x/itop-config/config.php b/datamodels/2.x/itop-config/config.php index 23a10ec6b5..d1bf9378e3 100644 --- a/datamodels/2.x/itop-config/config.php +++ b/datamodels/2.x/itop-config/config.php @@ -189,14 +189,16 @@ function CheckAsyncTasksRetryConfig(Config $oTempConfig, iTopWebPage $oP) $oForm->AddSubBlock(InputUIBlockFactory::MakeForHidden('operation', 'save')); $oForm->AddSubBlock(InputUIBlockFactory::MakeForHidden('transaction_id', utils::GetNewTransactionId())); - // - Cancel button + //--- Cancel button $oCancelButton = ButtonUIBlockFactory::MakeForCancel(Dict::S('config-cancel'), 'cancel_button', null, true, 'cancel_button'); $oCancelButton->SetOnClickJsCode("return ResetConfig();"); $oForm->AddSubBlock($oCancelButton); - // - Submit button + //--- Submit button $oSubmitButton = ButtonUIBlockFactory::MakeForPrimaryAction(Dict::S('config-apply'), null, Dict::S('config-apply'), true, 'submit_button'); $oForm->AddSubBlock($oSubmitButton); + + //--- Config editor $oForm->AddSubBlock(InputUIBlockFactory::MakeForHidden('prev_config', $sOriginalConfigEscaped, 'prev_config')); $oForm->AddSubBlock(InputUIBlockFactory::MakeForHidden('new_config', $sConfigEscaped)); $oForm->AddHtml("
"); diff --git a/datamodels/2.x/itop-core-update/dictionaries/en.dict.itop-core-update.php b/datamodels/2.x/itop-core-update/dictionaries/en.dict.itop-core-update.php index d3afe6a064..a0bd40fdc3 100644 --- a/datamodels/2.x/itop-core-update/dictionaries/en.dict.itop-core-update.php +++ b/datamodels/2.x/itop-core-update/dictionaries/en.dict.itop-core-update.php @@ -54,6 +54,7 @@ 'iTopUpdate:UI:Status' => 'Status', 'iTopUpdate:UI:Action' => 'Update', + 'iTopUpdate:UI:Setup' => ITOP_APPLICATION_SHORT.' Setup', 'iTopUpdate:UI:History' => 'Versions History', 'iTopUpdate:UI:Progress' => 'Progress of the upgrade', @@ -81,6 +82,9 @@ + 'iTopUpdate:UI:SetupLaunch' => 'Launch '.ITOP_APPLICATION_SHORT.' Setup', + 'iTopUpdate:UI:SetupLaunchConfirm' => 'This will launch '.ITOP_APPLICATION_SHORT.' setup, are you sure?', + // Setup Messages 'iTopUpdate:UI:SetupMessage:Ready' => 'Ready to start', 'iTopUpdate:UI:SetupMessage:EnterMaintenance' => 'Entering maintenance mode', diff --git a/datamodels/2.x/itop-core-update/src/Controller/AjaxController.php b/datamodels/2.x/itop-core-update/src/Controller/AjaxController.php index 11a1f7dbbc..9cda7be83f 100644 --- a/datamodels/2.x/itop-core-update/src/Controller/AjaxController.php +++ b/datamodels/2.x/itop-core-update/src/Controller/AjaxController.php @@ -17,6 +17,7 @@ use Exception; use IssueLog; use MetaModel; +use SecurityException; use SetupUtils; use utils; @@ -211,8 +212,7 @@ public function OperationUpdateDatabase() CoreUpdater::UpdateDatabase(); $iResponseCode = 200; } - catch (Exception $e) - { + catch (Exception $e) { IssueLog::Error("Compile: ".$e->getMessage()); $aParams['sError'] = $e->getMessage(); $iResponseCode = 500; @@ -220,4 +220,20 @@ public function OperationUpdateDatabase() $this->DisplayJSONPage($aParams, $iResponseCode); } + + /** + * @throws \SecurityException if CSRF token invalid + */ + public function OperationLaunchSetup() + { + $sTransactionId = utils::ReadParam('transaction_id', '', false, 'transaction_id'); + if (false === utils::IsTransactionValid($sTransactionId)) { + throw new SecurityException('Access forbidden'); + } + + $sConfigFile = APPCONF.'production/config-itop.php'; + @chmod($sConfigFile, 0770); // Allow overwriting the file + + header('Location: ../setup/'); + } } diff --git a/datamodels/2.x/itop-core-update/src/Controller/UpdateController.php b/datamodels/2.x/itop-core-update/src/Controller/UpdateController.php index 0c68726107..ba9eb36203 100644 --- a/datamodels/2.x/itop-core-update/src/Controller/UpdateController.php +++ b/datamodels/2.x/itop-core-update/src/Controller/UpdateController.php @@ -35,6 +35,25 @@ public function OperationSelectUpdateFile() $oSet = new DBObjectSet($oFilter, ['installed' => false]); // Most recent first $aParams['oSet'] = $oSet; + $oConfig = utils::GetConfig(); + $bConfigParamSetupLaunchButtonEnabled = $oConfig->Get('setup.launch_button.enabled'); + if (is_null($bConfigParamSetupLaunchButtonEnabled)) { + $bIsSetupLaunchButtonEnabled = utils::IsDevelopmentEnvironment(); + } else if (false === $bConfigParamSetupLaunchButtonEnabled) { + $bIsSetupLaunchButtonEnabled = false; + } else { + $bIsSetupLaunchButtonEnabled = $bConfigParamSetupLaunchButtonEnabled || utils::IsDevelopmentEnvironment(); + } + $aParams['bIsSetupLaunchButtonEnabled'] = $bIsSetupLaunchButtonEnabled; + if ($bIsSetupLaunchButtonEnabled) { + $sLaunchSetupUrl = utils::GetAbsoluteUrlModulePage('itop-core-update', 'ajax.php', + [ + 'operation' => 'LaunchSetup', + 'transaction_id' => $sTransactionId, + ]);; + $aParams['sLaunchSetupUrl'] = $sLaunchSetupUrl; + } + $this->DisplayPage($aParams); } diff --git a/datamodels/2.x/itop-core-update/view/SelectUpdateFile.html.twig b/datamodels/2.x/itop-core-update/view/SelectUpdateFile.html.twig index 6ffaea7349..393f074dad 100644 --- a/datamodels/2.x/itop-core-update/view/SelectUpdateFile.html.twig +++ b/datamodels/2.x/itop-core-update/view/SelectUpdateFile.html.twig @@ -87,6 +87,14 @@ {% EndUIFieldSet %} + {% if bIsSetupLaunchButtonEnabled %} + {% UIFieldSet Standard {'sLegend':'iTopUpdate:UI:Setup'|dict_s} %} + {% UIForm Standard {'sId':'launch-setup-form', Action:sLaunchSetupUrl} %} + {% UIButton ForDestructiveAction {'sLabel':'iTopUpdate:UI:SetupLaunch'|dict_s, 'sName':'launch-setup', 'sValue':'launch-setup', 'bIsSubmit':true, 'sId':'launch-setup'} %} + {% EndUIForm %} + {% EndUIFieldSet %} + {% endif %} + {% UIFieldSet Standard {'sLegend':'iTopUpdate:UI:History'|dict_s} %} {% UIDataTable ForRendering {'sListId':'iboupdatehistory', 'oSet':oSet} %}{% EndUIDataTable %} {% EndUIFieldSet %} diff --git a/datamodels/2.x/itop-core-update/view/SelectUpdateFile.ready.js.twig b/datamodels/2.x/itop-core-update/view/SelectUpdateFile.ready.js.twig index a7ed94e228..956c92eaa9 100644 --- a/datamodels/2.x/itop-core-update/view/SelectUpdateFile.ready.js.twig +++ b/datamodels/2.x/itop-core-update/view/SelectUpdateFile.ready.js.twig @@ -101,3 +101,7 @@ $("#check-update").on("click", function(e) { e.stopPropagation(); return false; }); + +$("#launch-setup-form").on("submit", function () { + return window.confirm("{{ 'iTopUpdate:UI:SetupLaunchConfirm'|dict_s }}"); +}); \ No newline at end of file diff --git a/index.php b/index.php index 61a6734258..c50fd8cbb6 100644 --- a/index.php +++ b/index.php @@ -25,9 +25,11 @@ } else { - echo "

Security Warning: the configuration file '$sConfigFile' should be read-only.

"; - echo "

Please modify the access rights to this file.

"; - echo "

Click here to ignore this warning and continue to run iTop.

"; + echo <<Security Warning: the configuration file '{$sConfigFile}' should be read-only.

+

Please modify the access rights to this file.

+

Click here to ignore this warning and continue to run iTop.

+HTML; } } else diff --git a/setup/wizardcontroller.class.inc.php b/setup/wizardcontroller.class.inc.php index 93ed2f95ef..7275a115f9 100644 --- a/setup/wizardcontroller.class.inc.php +++ b/setup/wizardcontroller.class.inc.php @@ -182,7 +182,12 @@ protected function DisplayStep(WizardStep $oStep) $oP->add("

Fatal error

\n"); $oP->error("Error: the configuration file '".$sRelativePath."' already exists and cannot be overwritten."); $oP->p("The wizard cannot modify the configuration file for you. If you want to upgrade ".ITOP_APPLICATION.", make sure that the file '".$sRelativePath."' can be modified by the web server."); - $oP->p(''); + + $sButtonsHtml = <<Reload +HTML; + $oP->p($sButtonsHtml); + $oP->output(); // Prevent token creation exit;