From 1ab035ffaa5c4d4fb832877cbb5dcb074ce53040 Mon Sep 17 00:00:00 2001 From: odain Date: Tue, 19 May 2026 10:46:56 +0200 Subject: [PATCH] =?UTF-8?q?N=C2=B09567=20-=20Extension=20Mgmt=20:=20Run=20?= =?UTF-8?q?setup?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- setup/wizardcontroller.class.inc.php | 18 +- .../wizardsteps/WizStepLandingBeforeAudit.php | 26 +- setup/wizardsteps/WizStepModulesChoice.php | 120 ++++++--- .../unitary-tests/setup/ExtensionsMapTest.php | 4 +- .../setup/WizStepModulesChoiceTest.php | 12 +- .../setup/ressources/installation_330.xml | 243 ++++++++++++++++++ 6 files changed, 349 insertions(+), 74 deletions(-) create mode 100644 tests/php-unit-tests/unitary-tests/setup/ressources/installation_330.xml diff --git a/setup/wizardcontroller.class.inc.php b/setup/wizardcontroller.class.inc.php index 2f2fd3258d..eace6760da 100644 --- a/setup/wizardcontroller.class.inc.php +++ b/setup/wizardcontroller.class.inc.php @@ -38,7 +38,7 @@ require_once(APPROOT.'setup/extensionsmap.class.inc.php'); class WizardController { - protected $aSteps; + protected $aWizardSteps; protected $sInitialStepClass; protected $sInitialState; protected $aParameters; @@ -53,7 +53,7 @@ class WizardController $this->sInitialStepClass = $sInitialStepClass; $this->sInitialState = $sInitialState; $this->aParameters = []; - $this->aSteps = []; + $this->aWizardSteps = []; } /** @@ -62,7 +62,7 @@ class WizardController */ protected function PushStep($aStepInfo) { - array_push($this->aSteps, $aStepInfo); + array_push($this->aWizardSteps, $aStepInfo); } /** @@ -71,7 +71,7 @@ class WizardController */ protected function PopStep() { - return array_pop($this->aSteps); + return array_pop($this->aWizardSteps); } /** @@ -235,9 +235,9 @@ HTML; $oPage->add(''); } - $oPage->add(''); + $oPage->add(''); $oPage->add(''); - if ((count($this->aSteps) > 0) && ($oStep->CanMoveBackward())) { + if ((count($this->aWizardSteps) > 0) && ($oStep->CanMoveBackward())) { $oPage->add(''); } if ($oStep->CanMoveForward()) { @@ -296,7 +296,7 @@ on the page's parameters $sOperation = utils::ReadParam('operation'); $this->aParameters = utils::ReadParam('_params', [], false, 'raw_data'); - $this->SetSteps(json_decode(utils::ReadParam('_steps', '[]', false, 'raw_data'), true)); + $this->SetWizardSteps(json_decode(utils::ReadParam('_steps', '[]', false, 'raw_data'), true)); switch ($sOperation) { case 'next': @@ -371,9 +371,9 @@ on the page's parameters return $sOutput; } - public function SetSteps(array $aSteps): void + public function SetWizardSteps(array $aWizardSteps): void { - $this->aSteps = $aSteps; + $this->aWizardSteps = $aWizardSteps; } /** diff --git a/setup/wizardsteps/WizStepLandingBeforeAudit.php b/setup/wizardsteps/WizStepLandingBeforeAudit.php index d2bf47fc01..a848f372cc 100644 --- a/setup/wizardsteps/WizStepLandingBeforeAudit.php +++ b/setup/wizardsteps/WizStepLandingBeforeAudit.php @@ -40,25 +40,6 @@ class WizStepLandingBeforeAudit extends WizStepModulesChoice */ public function UpdateWizardStateAndGetNextStep($bMoveForward = true): WizardState { - $this->oWizard->SetParameter('selected_components', '[{"_0":"_0","_1":"_1","_2":"_2","_3":"_3","_4":"_4"},{"_0":"_0"},{"_0":"_0","_0_0":"_0_0"},{"_0":"_0"},{"_0":"_0","_1":"_1"},{"_0":"_0","_1":"_1"}]'); - $aSteps = json_decode( - '[ - {"class":"WizStepWelcome","state":""}, - {"class":"WizStepInstallOrUpgrade","state":""}, - {"class":"WizStepDetectedInfo","state":""}, - {"class":"WizStepUpgradeMiscParams","state":""}, - {"class":"WizStepModulesChoice","state":"start_upgrade"}, - {"class":"WizStepModulesChoice","state":"1"}, - {"class":"WizStepModulesChoice","state":"2"}, - {"class":"WizStepModulesChoice","state":"3"}]', - true - ); - $this->oWizard->SetSteps($aSteps); - $this->aSteps = $aSteps; - - $this->sCurrentState = count($aSteps) - 1; - //parent::UpdateWizardStateAndGetNextStep(true); - $oProductionEnv = new RunTimeEnvironment(); $sBuildConfigFile = APPCONF.$oProductionEnv->GetBuildEnv().'/'.ITOP_CONFIG_FILE; @chmod($sBuildConfigFile, 0770); // In case it exists: RWX for owner and group, nothing for others @@ -79,6 +60,13 @@ class WizStepLandingBeforeAudit extends WizStepModulesChoice $this->oWizard->SaveParameter('removed_extensions', []); $this->oWizard->SaveParameter('extensions_not_uninstallable', []); + $aWizardSteps = $this->GetWizardSteps(); + $this->oWizard->SetWizardSteps($aWizardSteps); + $this->sCurrentState = count($aWizardSteps) - 1; + + $aSelectedComponents = $this->GetSelectedComponents($this->aSteps, $this->oWizard->GetParameter('selected_extensions')); + $this->oWizard->SetParameter('selected_components', json_encode($aSelectedComponents)); + return new WizardState(WizStepDataAudit::class); } diff --git a/setup/wizardsteps/WizStepModulesChoice.php b/setup/wizardsteps/WizStepModulesChoice.php index 1ca139445c..e32d82231c 100644 --- a/setup/wizardsteps/WizStepModulesChoice.php +++ b/setup/wizardsteps/WizStepModulesChoice.php @@ -120,46 +120,6 @@ class WizStepModulesChoice extends AbstractWizStepInstall return [$aExtensionsAdded, $aExtensionsRemoved, $aExtensionsNotUninstallable]; } - public static function GetSetupComponentsFromExtensions(Config $oConfig, array $aSelectedExtensions): array - { - $sSourceFile = APPROOT.'datamodels/2.x/installation.xml'; - $oExtensionsMap = new iTopExtensionsMap(); - $oExtensionsMap->LoadChoicesFromDatabase($oConfig); - $aOptions = $oExtensionsMap->GetAllExtensionsOptionInfo(false); - - if (is_file($sSourceFile)) { - $aParams = new XMLParameters($sSourceFile); - $aSteps = $aParams->Get('steps', []); - - // Display this step of the wizard only if there is something to display - if (count($aOptions) > 0) { - $aSteps[] = [ - 'title' => 'Extensions', - 'description' => '

Select additional extensions to install. You can launch the installation again to install new extensions or remove installed ones.

', - 'banner' => '/images/icons/icons8-puzzle.svg', - 'options' => $aOptions, - ]; - } - } else { - //legacy package - $aSteps = [ - [ - 'title' => 'Modules Selection', - 'description' => '

Select the modules to install. You can launch the installation again to install new modules, but you cannot remove already installed modules.

', - 'banner' => '/images/icons/icons8-apps-tab.svg', - 'options' => $aOptions, - ], - ]; - } - - $aRes = []; - foreach ($aSteps as $aStep) { - - } - - return []; - } - public function UpdateWizardStateAndGetNextStep($bMoveForward = true): WizardState { // Accumulates the selected modules: @@ -206,6 +166,86 @@ class WizStepModulesChoice extends AbstractWizStepInstall return new WizardState(WizStepModulesChoice::class, (string)($index - 1)); } + public function GetWizardSteps(): array + { + $aSteps = [ + ["class" => "WizStepWelcome","state" => ""], + ["class" => "WizStepInstallOrUpgrade","state" => ""], + ["class" => "WizStepDetectedInfo","state" => ""], + ["class" => "WizStepUpgradeMiscParams","state" => ""], + ]; + $i = 0; + while (null != $this->GetStepInfo($i)) { + $aSteps [] = ["class" => "WizStepModulesChoice","state" => "$i"]; + $i++; + } + + return $aSteps; + } + + public function GetSelectedComponents(array $aSteps, string $sSelectedExtensionJson): array + { + SetupLog::Error(__METHOD__, null, $aSteps); + $aExtensions = json_decode($sSelectedExtensionJson, true); + $aRes = []; + foreach ($aSteps as $i => $aStepInfo) { + $aStepRes = []; + $this->ProcessOptions("", $aStepInfo, $aExtensions, $aStepRes); + $this->ProcessAlternatives("", $aStepInfo, $aExtensions, $aStepRes); + $aRes [] = $aStepRes; + } + + return $aRes; + } + + public function ProcessOptions(string $sCurrentIndex, array $aInfo, array $aExtensions, array &$aStepRes) + { + $aOptions = $aInfo["options"] ?? null; + if (is_null($aOptions) || !is_array($aOptions)) { + return; + } + + foreach ($aOptions as $i => $aOptionsInfo) { + $sExtensionCode = $aOptionsInfo["extension_code"] ?? null; + + if (in_array($sExtensionCode, $aExtensions)) { + $sNextIndex = "{$sCurrentIndex}_{$i}"; + $aStepRes[$sNextIndex] = $sNextIndex; + + $aSubOptions = $aOptionsInfo['sub_options'] ?? null; + if (!is_null($aSubOptions) && is_array($aSubOptions)) { + $this->ProcessOptions($sNextIndex, $aSubOptions, $aExtensions, $aStepRes); + } + + $this->ProcessAlternatives($sNextIndex, $aOptionsInfo, $aExtensions, $aStepRes); + } + } + } + + public function ProcessAlternatives(string $sCurrentIndex, array $aInfo, array $aExtensions, array &$aStepRes) + { + $aAlternatives = $aInfo["alternatives"] ?? null; + if (is_null($aAlternatives) || ! is_array($aAlternatives)) { + return; + } + + foreach ($aAlternatives as $i => $aAlternativeInfo) { + $sExtensionCode = $aAlternativeInfo["extension_code"] ?? null; + + if (in_array($sExtensionCode, $aExtensions)) { + $sNextIndex = "{$sCurrentIndex}_{$i}"; + $aStepRes [$sNextIndex] = $sNextIndex; + + $aSubOptions = $aAlternativeInfo['sub_options'] ?? null; + if (!is_null($aSubOptions) && is_array($aSubOptions)) { + $this->ProcessOptions($sNextIndex, $aSubOptions, $aExtensions, $aStepRes); + } + + break; + } + } + } + public function Display(SetupPage $oPage): void { $this->DisplayStep($oPage); diff --git a/tests/php-unit-tests/unitary-tests/setup/ExtensionsMapTest.php b/tests/php-unit-tests/unitary-tests/setup/ExtensionsMapTest.php index e7afc8c512..0dec4dc9d5 100644 --- a/tests/php-unit-tests/unitary-tests/setup/ExtensionsMapTest.php +++ b/tests/php-unit-tests/unitary-tests/setup/ExtensionsMapTest.php @@ -159,10 +159,10 @@ class ExtensionsMapTest extends ItopTestCase $sExpected = file_get_contents(__DIR__.'/ressources/all_extensions_from_datamodels.json'); $sExpected = str_replace('"sVersion": "ITOP_VERSION"', '"sVersion": "'.ITOP_VERSION.'"', $sExpected); - $sExpected = preg_replace('/"module_file_path": .*/', '"module_file_path": ANYPATH', $sExpected); + $sExpected = preg_replace('/"module_file_path": .*/', '"module_file_path": ANYPATH', $sExpected); $actual = json_encode($this->SerializeExtensionMap($oiTopExtensionsMap), JSON_PRETTY_PRINT); - $actual = preg_replace('/"module_file_path": .*/', '"module_file_path": ANYPATH', $actual); + $actual = preg_replace('/"module_file_path": .*/', '"module_file_path": ANYPATH', $actual); $this->assertEquals($sExpected, $actual); } diff --git a/tests/php-unit-tests/unitary-tests/setup/WizStepModulesChoiceTest.php b/tests/php-unit-tests/unitary-tests/setup/WizStepModulesChoiceTest.php index 3be3f45907..d04cb0221c 100644 --- a/tests/php-unit-tests/unitary-tests/setup/WizStepModulesChoiceTest.php +++ b/tests/php-unit-tests/unitary-tests/setup/WizStepModulesChoiceTest.php @@ -1392,11 +1392,15 @@ HTML, $this->assertEquals($sExpectedHTML, $oPage->sContent); } - public function testGetSetupComponentsFromExtensions() + public function testGetSelectedComponents() { + $aParams = new XMLParameters(__DIR__.'/ressources/installation_330.xml'); + $aSteps = $aParams->Get('steps', []); + $aSelectedExtensions = ["itop-config-mgmt-core","itop-config-mgmt-datacenter","itop-config-mgmt-end-user","itop-config-mgmt-storage","itop-config-mgmt-virtualization","itop-container-mgmt","itop-service-mgmt-enterprise","itop-ticket-mgmt-simple-ticket","itop-ticket-mgmt-simple-ticket-enhanced-portal","itop-change-mgmt-simple","itop-kown-error-mgmt","itop-problem-mgmt","combodo-oauth2-client","combodo-mfa-extended","combodo-data-replication","combodo-api-playground","combodo-snapshot"]; - $aExpected = json_decode('[{"_0":"_0","_1":"_1","_2":"_2","_3":"_3","_4":"_4","_4_0":"_4_0"},{"_0":"_0"},{"_0":"_0","_0_0":"_0_0"},{"_0":"_0"},{"_0":"_0","_1":"_1"},{"_0":"_0","_1":"_1","_3":"_3","_4":"_4","_5":"_5"}]', true); - // $this->assertEquals($aExpected, \WizStepModulesChoice::GetSetupComponentsFromExtensions($aSelectedExtensions)); - $this->assertTrue(true); + $aRes = $this->oStep->GetSelectedComponents($aSteps, json_encode($aSelectedExtensions)); + + $aExpected = json_decode('[{"_0":"_0","_1":"_1","_2":"_2","_3":"_3","_4":"_4","_4_0":"_4_0"},{"_0":"_0"},{"_0":"_0","_0_0":"_0_0"},{"_0":"_0"},{"_0":"_0","_1":"_1"}]', true); + $this->assertEquals($aExpected, $aRes); } } diff --git a/tests/php-unit-tests/unitary-tests/setup/ressources/installation_330.xml b/tests/php-unit-tests/unitary-tests/setup/ressources/installation_330.xml new file mode 100644 index 0000000000..82f159e521 --- /dev/null +++ b/tests/php-unit-tests/unitary-tests/setup/ressources/installation_330.xml @@ -0,0 +1,243 @@ + + + + + Configuration Management options + The options below allow you to configure the type of elements that are to be managed inside iTop.]]> + /images/icons/icons8-apps-tab.svg + + + itop-config-mgmt-core + Configuration Management Core + All the base objects that are mandatory in the iTop CMDB: Organizations, Locations, Teams, Persons, etc. + + itop-structure + itop-config-mgmt + itop-attachments + itop-profiles-itil + itop-welcome-itil + itop-tickets + itop-files-information + combodo-db-tools + itop-core-update + itop-hub-connector + itop-oauth-client + combodo-backoffice-darkmoon-theme + combodo-backoffice-fullmoon-high-contrast-theme + combodo-backoffice-fullmoon-protanopia-deuteranopia-theme + combodo-backoffice-fullmoon-tritanopia-theme + itop-themes-compat + combodo-my-account + combodo-my-account-user-info + combodo-oauth2-client + itop-attribute-class-set + itop-attribute-encrypted-password + itop-ui-copypaste + + true + + + itop-config-mgmt-datacenter + Data Center Devices + Manage Data Center devices such as Racks, Enclosures, PDUs, etc. + + itop-datacenter-mgmt + + true + + + itop-config-mgmt-end-user + End-User Devices + Manage devices related to end-users: PCs, Phones, Tablets, etc. + + itop-endusers-devices + + true + + + itop-config-mgmt-storage + Storage Devices + Manage storage devices such as NAS, SAN Switches, Tape Libraries and Tapes, etc. + + itop-storage-mgmt + + true + + + itop-config-mgmt-virtualization + Virtualization + Manage Hypervisors, Virtual Machines and Farms. + + itop-virtualization-mgmt + + true + + + + itop-container-mgmt + Containerization + + + itop-container-mgmt + + false + + + + + + + + Service Management options + Select the choice that best describes the relationships between the services and the IT infrastructure in your IT environment.]]> + /images/icons/icons8-services.svg + + + itop-service-mgmt-enterprise + Service Management for Enterprises + Select this option if the IT delivers services based on a shared infrastructure. For example if different organizations within your company subscribe to services (like Mail and Print services) delivered by a single shared backend. + + itop-service-mgmt + + true + + + itop-service-mgmt-service-provider + Service Management for Service Providers + Select this option if the IT manages the infrastructure of independent customers. This is the most flexible model, since the services can be delivered with a mix of shared and customer specific infrastructure devices. + + itop-service-mgmt-provider + + + + + + Tickets Management options + Select the type of tickets you want to use in order to respond to user requests and incidents.]]> + /images/icons/icons8-discussion-forum.svg + + + itop-ticket-mgmt-simple-ticket + Simple Ticket Management + Select this option to use one single type of tickets for all kind of requests. + + itop-request-mgmt + + true + + + + itop-ticket-mgmt-simple-ticket-enhanced-portal + Customer Portal + + + itop-portal + itop-portal-base + + true + + + + + + itop-ticket-mgmt-itil + ITIL Compliant Tickets Management + Select this option to have different types of ticket for managing user requests and incidents. Each type of ticket has a specific life cycle and specific fields + + + + itop-ticket-mgmt-itil-user-request + User Request Management + Manage User Request tickets in iTop + + itop-request-mgmt-itil + + + + itop-ticket-mgmt-itil-incident + Incident Management + Manage Incidents tickets in iTop + + itop-incident-mgmt-itil + + + + itop-ticket-mgmt-itil-enhanced-portal + Customer Portal + + + itop-portal + itop-portal-base + + true + + + + + + itop-ticket-mgmt-none + No Tickets Management + Don't manage incidents or user requests in iTop + + + + + + + Change Management options + Select the type of tickets you want to use in order to manage changes to the IT infrastructure.]]> + /images/icons/icons8-change.svg + + + itop-change-mgmt-simple + Simple Change Management + Select this option to use one type of ticket for all kind of changes. + + itop-change-mgmt + + true + + + itop-change-mgmt-itil + ITIL Change Management + Select this option to use Normal/Routine/Emergency change tickets. + + itop-change-mgmt-itil + + + + itop-change-mgmt-none + No Change Management + Don't manage changes in iTop + + + + + + + Additional ITIL tickets + Pick from the list below the additional ITIL processes that are to be implemented in iTop.]]> + /images/icons/icons8-important-book.svg + + + + itop-kown-error-mgmt + Known Errors Management and FAQ + Select this option to track "Known Errors" and FAQs in iTop. + + itop-faq-light + itop-knownerror-mgmt + + + + itop-problem-mgmt + Problem Management + Select this option to track "Problems" in iTop. + + itop-problem-mgmt + + + + + +