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 6648ad60a..39791fa86 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 23a10ec6b..d1bf9378e 100644 --- a/datamodels/2.x/itop-config/config.php +++ b/datamodels/2.x/itop-config/config.php @@ -189,14 +189,16 @@ try { $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 d3afe6a06..a0bd40fdc 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 @@ Dict::Add('EN US', 'English', 'English', array( '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 @@ Dict::Add('EN US', 'English', 'English', array( + '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 11a1f7dbb..9cda7be83 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 Dict; use Exception; use IssueLog; use MetaModel; +use SecurityException; use SetupUtils; use utils; @@ -211,8 +212,7 @@ class AjaxController extends Controller 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 @@ class AjaxController extends Controller $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 0c6872610..ba9eb3620 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 @@ class UpdateController extends Controller $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 6ffaea734..393f074da 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 a7ed94e22..956c92eaa 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 61a673425..c50fd8cbb 100644 --- a/index.php +++ b/index.php @@ -25,9 +25,11 @@ if (file_exists(dirname(__FILE__).'/'.$sConfigFile)) } 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 93ed2f95e..7275a115f 100644 --- a/setup/wizardcontroller.class.inc.php +++ b/setup/wizardcontroller.class.inc.php @@ -182,7 +182,12 @@ class WizardController $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;