From 19b7f851f722dd3771b32e5a3e8e37a803547f65 Mon Sep 17 00:00:00 2001 From: Timothee Date: Thu, 4 Dec 2025 16:09:07 +0100 Subject: [PATCH 1/4] =?UTF-8?q?N=C2=B08864=20List=20extensions=20added=20o?= =?UTF-8?q?r=20removed=20in=20recap?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- setup/wizardsteps.class.inc.php | 43 +++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/setup/wizardsteps.class.inc.php b/setup/wizardsteps.class.inc.php index 148da3011e..c990a47432 100644 --- a/setup/wizardsteps.class.inc.php +++ b/setup/wizardsteps.class.inc.php @@ -1397,9 +1397,44 @@ public function ProcessParams($bMoveForward = true) if (class_exists('CreateITILProfilesInstaller')) { $this->oWizard->SetParameter('old_addon', true); } + + $aExtensionsAdded = []; + $aExtensionsRemoved = []; + foreach ($this->oExtensionsMap->GetAllExtensionsWithPreviouslyInstalled() as $oExtension) { + /* @var \iTopExtension $oExtension */ + $bSelected = in_array($oExtension->sCode, $aExtensions); + if($oExtension->bInstalled && !$bSelected){ + $aExtensionsRemoved[] = $oExtension->sLabel; + } + else if(!$oExtension->bInstalled && $bSelected) { + $aExtensionsAdded[] = $oExtension->sLabel; + } + } + + $sExtensionsAdded = 'No extension added.'; + if (count($aExtensionsAdded) > 0) { + $sExtensionsAdded = ''; + } + + $sExtensionsRemoved = 'No extension removed.'; + if (count($aExtensionsRemoved) > 0) { + $sExtensionsRemoved = ''; + } + + $this->oWizard->SetParameter('selected_modules', json_encode(array_keys($aModules))); $this->oWizard->SetParameter('selected_extensions', json_encode($aExtensions)); $this->oWizard->SetParameter('display_choices', $sDisplayChoices); + $this->oWizard->SetParameter('extensions_added', $sExtensionsAdded); + $this->oWizard->SetParameter('extensions_removed', $sExtensionsRemoved); return ['class' => 'WizStepSummary', 'state' => '']; } @@ -2217,6 +2252,14 @@ public function Display(WebPage $oPage) $oPage->add('
Installation Parameters'); $oPage->add('
'); + + $oPage->add('
Extensions Added'); + $oPage->add($this->oWizard->GetParameter('extensions_added')); + $oPage->add('
'); + $oPage->add('
Extensions Removed'); + $oPage->add($this->oWizard->GetParameter('extensions_removed')); + $oPage->add('
'); + $oPage->add('
Database Parameters
    '); $oPage->add('
  • Server Name: '.$aInstallParams['database']['server'].'
  • '); $oPage->add('
  • DB User Name: '.$aInstallParams['database']['user'].'
  • '); From 00e071228ecad5cc7cba01df14f3b32f0290cb5d Mon Sep 17 00:00:00 2001 From: Timothee Date: Thu, 4 Dec 2025 17:09:33 +0100 Subject: [PATCH 2/4] =?UTF-8?q?N=C2=B08864=20List=20forced=20uninstall?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- setup/wizardsteps.class.inc.php | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/setup/wizardsteps.class.inc.php b/setup/wizardsteps.class.inc.php index c990a47432..4f7247aaf8 100644 --- a/setup/wizardsteps.class.inc.php +++ b/setup/wizardsteps.class.inc.php @@ -1400,18 +1400,22 @@ public function ProcessParams($bMoveForward = true) $aExtensionsAdded = []; $aExtensionsRemoved = []; + $aExtensionsNotUninstallable = []; foreach ($this->oExtensionsMap->GetAllExtensionsWithPreviouslyInstalled() as $oExtension) { /* @var \iTopExtension $oExtension */ $bSelected = in_array($oExtension->sCode, $aExtensions); if($oExtension->bInstalled && !$bSelected){ - $aExtensionsRemoved[] = $oExtension->sLabel; + $aExtensionsRemoved[$oExtension->sCode] = $oExtension->sLabel; } else if(!$oExtension->bInstalled && $bSelected) { - $aExtensionsAdded[] = $oExtension->sLabel; + $aExtensionsAdded[$oExtension->sCode] = $oExtension->sLabel; + } + if(!$oExtension->CanBeUninstalled()){ + $aExtensionsNotUninstallable[$oExtension->sCode] = true; } } - $sExtensionsAdded = 'No extension added.'; + $sExtensionsAdded = '
    • No extension added.
    '; if (count($aExtensionsAdded) > 0) { $sExtensionsAdded = '
      '; foreach ($aExtensionsAdded as $sExtensionCode) { @@ -1420,16 +1424,19 @@ public function ProcessParams($bMoveForward = true) $sExtensionsAdded .= '
    '; } - $sExtensionsRemoved = 'No extension removed.'; + $sExtensionsRemoved = '
    • No extension removed.
    '; if (count($aExtensionsRemoved) > 0) { $sExtensionsRemoved = '
      '; - foreach ($aExtensionsRemoved as $sExtensionCode) { - $sExtensionsRemoved .= '
    • '.$sExtensionCode.'
    • '; + foreach ($aExtensionsRemoved as $sCode => $sExtensionCode) { + $sForcedUninstall = ''; + if (isset($aExtensionsNotUninstallable[$sCode])) { + $sForcedUninstall = ' (forced uninstallation)'; + } + $sExtensionsRemoved .= '
    • '.$sExtensionCode.$sForcedUninstall.'
    • '; } $sExtensionsRemoved .= '
    '; } - $this->oWizard->SetParameter('selected_modules', json_encode(array_keys($aModules))); $this->oWizard->SetParameter('selected_extensions', json_encode($aExtensions)); $this->oWizard->SetParameter('display_choices', $sDisplayChoices); @@ -2253,10 +2260,10 @@ public function Display(WebPage $oPage) $oPage->add('
    Installation Parameters'); $oPage->add('
    '); - $oPage->add('
    Extensions Added'); + $oPage->add('
    Extensions to be installed'); $oPage->add($this->oWizard->GetParameter('extensions_added')); $oPage->add('
    '); - $oPage->add('
    Extensions Removed'); + $oPage->add('
    Extensions to be uninstalled'); $oPage->add($this->oWizard->GetParameter('extensions_removed')); $oPage->add('
    '); From f668d94bd9b74657853e50230924a4397da08579 Mon Sep 17 00:00:00 2001 From: Timothee Date: Tue, 9 Dec 2025 15:58:52 +0100 Subject: [PATCH 3/4] =?UTF-8?q?N=C2=B08864=20Style=20fix?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- setup/wizardsteps.class.inc.php | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/setup/wizardsteps.class.inc.php b/setup/wizardsteps.class.inc.php index 4f7247aaf8..cdad225a8e 100644 --- a/setup/wizardsteps.class.inc.php +++ b/setup/wizardsteps.class.inc.php @@ -1404,13 +1404,12 @@ public function ProcessParams($bMoveForward = true) foreach ($this->oExtensionsMap->GetAllExtensionsWithPreviouslyInstalled() as $oExtension) { /* @var \iTopExtension $oExtension */ $bSelected = in_array($oExtension->sCode, $aExtensions); - if($oExtension->bInstalled && !$bSelected){ + if ($oExtension->bInstalled && !$bSelected) { $aExtensionsRemoved[$oExtension->sCode] = $oExtension->sLabel; - } - else if(!$oExtension->bInstalled && $bSelected) { + } elseif (!$oExtension->bInstalled && $bSelected) { $aExtensionsAdded[$oExtension->sCode] = $oExtension->sLabel; } - if(!$oExtension->CanBeUninstalled()){ + if (!$oExtension->CanBeUninstalled()) { $aExtensionsNotUninstallable[$oExtension->sCode] = true; } } From 8aac64cc19f6e2d75fcf496c757f71e3fc682713 Mon Sep 17 00:00:00 2001 From: Timothee Date: Mon, 5 Jan 2026 10:34:42 +0100 Subject: [PATCH 4/4] =?UTF-8?q?N=C2=B08864=20Added=20tests?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- setup/runtimeenv.class.inc.php | 2 +- setup/wizardsteps.class.inc.php | 84 ++++++++-------- .../ConfigTest/config-itop-joker.php | 16 ++-- .../ConfigTest/config-itop-var.php | 18 ++-- .../setup/WizStepModulesChoiceTest.php | 95 +++++++++++++++++++ .../setup/iTopExtensionsMapFake.php | 2 + 6 files changed, 158 insertions(+), 59 deletions(-) diff --git a/setup/runtimeenv.class.inc.php b/setup/runtimeenv.class.inc.php index 945e913225..2dd8a66d39 100644 --- a/setup/runtimeenv.class.inc.php +++ b/setup/runtimeenv.class.inc.php @@ -1029,4 +1029,4 @@ public function CheckMetaModel() return sprintf("Checked %d classes in %.1f ms. No error found.\n", $iCount, $fDuration * 1000.0); } -} // End of class \ No newline at end of file +} // End of class diff --git a/setup/wizardsteps.class.inc.php b/setup/wizardsteps.class.inc.php index cdad225a8e..88ce73756a 100644 --- a/setup/wizardsteps.class.inc.php +++ b/setup/wizardsteps.class.inc.php @@ -1368,6 +1368,52 @@ public function GetPossibleSteps() return ['WizStepModulesChoice', 'WizStepSummary']; } + public function GetAddedAndRemovedExtensions($aSelectedExtensions) + { + $aExtensionsAdded = []; + $aExtensionsRemoved = []; + $aExtensionsNotUninstallable = []; + foreach ($this->oExtensionsMap->GetAllExtensionsWithPreviouslyInstalled() as $oExtension) { + /* @var \iTopExtension $oExtension */ + $bSelected = in_array($oExtension->sCode, $aSelectedExtensions); + if ($oExtension->bInstalled && !$bSelected) { + $aExtensionsRemoved[$oExtension->sCode] = $oExtension->sLabel; + if (!$oExtension->CanBeUninstalled()) { + $aExtensionsNotUninstallable[$oExtension->sCode] = true; + } + } elseif (!$oExtension->bInstalled && $bSelected) { + $aExtensionsAdded[$oExtension->sCode] = $oExtension->sLabel; + } + } + + $sExtensionsAdded = ''; + if (count($aExtensionsAdded) > 0) { + $sExtensionsAdded = '
      '; + foreach ($aExtensionsAdded as $sExtensionCode) { + $sExtensionsAdded .= '
    • '.$sExtensionCode.'
    • '; + } + $sExtensionsAdded .= '
    '; + } else { + $sExtensionsAdded = '
    • No extension added.
    '; + } + + $sExtensionsRemoved = ''; + if (count($aExtensionsRemoved) > 0) { + $sExtensionsRemoved = '
      '; + foreach ($aExtensionsRemoved as $sCode => $sExtensionCode) { + $sForcedUninstall = ''; + if (isset($aExtensionsNotUninstallable[$sCode])) { + $sForcedUninstall = ' (forced uninstallation)'; + } + $sExtensionsRemoved .= '
    • '.$sExtensionCode.$sForcedUninstall.'
    • '; + } + $sExtensionsRemoved .= '
    '; + } else { + $sExtensionsRemoved = '
    • No extension removed.
    '; + } + return [$sExtensionsAdded, $sExtensionsRemoved]; + } + public function ProcessParams($bMoveForward = true) { // Accumulates the selected modules: @@ -1398,43 +1444,7 @@ public function ProcessParams($bMoveForward = true) $this->oWizard->SetParameter('old_addon', true); } - $aExtensionsAdded = []; - $aExtensionsRemoved = []; - $aExtensionsNotUninstallable = []; - foreach ($this->oExtensionsMap->GetAllExtensionsWithPreviouslyInstalled() as $oExtension) { - /* @var \iTopExtension $oExtension */ - $bSelected = in_array($oExtension->sCode, $aExtensions); - if ($oExtension->bInstalled && !$bSelected) { - $aExtensionsRemoved[$oExtension->sCode] = $oExtension->sLabel; - } elseif (!$oExtension->bInstalled && $bSelected) { - $aExtensionsAdded[$oExtension->sCode] = $oExtension->sLabel; - } - if (!$oExtension->CanBeUninstalled()) { - $aExtensionsNotUninstallable[$oExtension->sCode] = true; - } - } - - $sExtensionsAdded = '
    • No extension added.
    '; - if (count($aExtensionsAdded) > 0) { - $sExtensionsAdded = '
      '; - foreach ($aExtensionsAdded as $sExtensionCode) { - $sExtensionsAdded .= '
    • '.$sExtensionCode.'
    • '; - } - $sExtensionsAdded .= '
    '; - } - - $sExtensionsRemoved = '
    • No extension removed.
    '; - if (count($aExtensionsRemoved) > 0) { - $sExtensionsRemoved = '
      '; - foreach ($aExtensionsRemoved as $sCode => $sExtensionCode) { - $sForcedUninstall = ''; - if (isset($aExtensionsNotUninstallable[$sCode])) { - $sForcedUninstall = ' (forced uninstallation)'; - } - $sExtensionsRemoved .= '
    • '.$sExtensionCode.$sForcedUninstall.'
    • '; - } - $sExtensionsRemoved .= '
    '; - } + [$sExtensionsAdded, $sExtensionsRemoved] = $this->GetAddedAndRemovedExtensions($aExtensions); $this->oWizard->SetParameter('selected_modules', json_encode(array_keys($aModules))); $this->oWizard->SetParameter('selected_extensions', json_encode($aExtensions)); diff --git a/tests/php-unit-tests/unitary-tests/datamodels/2.x/itop-config/ConfigTest/config-itop-joker.php b/tests/php-unit-tests/unitary-tests/datamodels/2.x/itop-config/ConfigTest/config-itop-joker.php index 7c4a359c28..cbce0bb87d 100644 --- a/tests/php-unit-tests/unitary-tests/datamodels/2.x/itop-config/ConfigTest/config-itop-joker.php +++ b/tests/php-unit-tests/unitary-tests/datamodels/2.x/itop-config/ConfigTest/config-itop-joker.php @@ -7,30 +7,26 @@ * * */ -$MySettings = array( - - +$MySettings = [ // app_root_url: Root URL used for navigating within the application, or from an email to the application (you can put $SERVER_NAME$ as a placeholder for the server's name) // default: '' 'app_root_url' => 'http://%server(SERVER_NAME)?:localhost%/itop/iTop/', - -); +]; /** * * Modules specific settings * */ -$MyModuleSettings = array( -); +$MyModuleSettings = [ +]; /** * * Data model modules to be loaded. Names are specified as relative paths * */ -$MyModules = array( -); -?> \ No newline at end of file +$MyModules = [ +]; diff --git a/tests/php-unit-tests/unitary-tests/datamodels/2.x/itop-config/ConfigTest/config-itop-var.php b/tests/php-unit-tests/unitary-tests/datamodels/2.x/itop-config/ConfigTest/config-itop-var.php index a9e41ee35f..3dc1986cd1 100644 --- a/tests/php-unit-tests/unitary-tests/datamodels/2.x/itop-config/ConfigTest/config-itop-var.php +++ b/tests/php-unit-tests/unitary-tests/datamodels/2.x/itop-config/ConfigTest/config-itop-var.php @@ -7,30 +7,26 @@ * * */ -$MySettings = array( - - +$MySettings = [ // app_root_url: Root URL used for navigating within the application, or from an email to the application (you can put $SERVER_NAME$ as a placeholder for the server's name) // default: '' - 'app_root_url' => 'http://' . (isset($_SERVER['SERVER_NAME']) ? $_SERVER['SERVER_NAME'] : 'localhost') . '/itop/iTop/', - + 'app_root_url' => 'http://'.(isset($_SERVER['SERVER_NAME']) ? $_SERVER['SERVER_NAME'] : 'localhost').'/itop/iTop/', -); +]; /** * * Modules specific settings * */ -$MyModuleSettings = array( -); +$MyModuleSettings = [ +]; /** * * Data model modules to be loaded. Names are specified as relative paths * */ -$MyModules = array( -); -?> \ No newline at end of file +$MyModules = [ +]; diff --git a/tests/php-unit-tests/unitary-tests/setup/WizStepModulesChoiceTest.php b/tests/php-unit-tests/unitary-tests/setup/WizStepModulesChoiceTest.php index 11a11fd46c..7bdeac6afc 100644 --- a/tests/php-unit-tests/unitary-tests/setup/WizStepModulesChoiceTest.php +++ b/tests/php-unit-tests/unitary-tests/setup/WizStepModulesChoiceTest.php @@ -257,4 +257,99 @@ public function testComputeChoiceFlags($aExtensions, $bUpgrade, $bDisableUninsta $this->assertEquals($aExpectedFlags, $aFlags); } + public function ProviderGetAddedAndRemovedExtensions() + { + return [ + 'no extensions' => [ + 'aExtensions' => [], + + 'aSelected' => [], + 'sExpectedAddedList' => '
    • No extension added.
    ', + 'sExpectedRemovedList' => '
    • No extension removed.
    ', + ], + 'no extensions selected' => [ + 'aExtensions' => [ + 'itop-ext1' => [ + 'installed' => false, + ], + ], + 'aSelected' => [], + 'sExpectedAddedList' => '
    • No extension added.
    ', + 'sExpectedRemovedList' => '
    • No extension removed.
    ', + ], + 'no extensions removed' => [ + 'aExtensions' => [ + 'itop-ext1' => [ + 'installed' => true, + ], + ], + 'aSelected' => ['itop-ext1'], + 'sExpectedAddedList' => '
    • No extension added.
    ', + 'sExpectedRemovedList' => '
    • No extension removed.
    ', + ], + 'One added extension' => [ + 'aExtensions' => [ + 'itop-ext1' => [ + 'installed' => false, + ], + ], + 'aSelected' => ['itop-ext1'], + 'sExpectedAddedList' => '
    • itop-ext1
    ', + 'sExpectedRemovedList' => '
    • No extension removed.
    ', + ], + 'One removed extension' => [ + 'aExtensions' => [ + 'itop-ext1' => [ + 'installed' => true, + ], + ], + 'aSelected' => [], + 'sExpectedAddedList' => '
    • No extension added.
    ', + 'sExpectedRemovedList' => '
    • itop-ext1
    ', + ], + 'Forced removed extension' => [ + 'aExtensions' => [ + 'itop-ext1' => [ + 'installed' => true, + 'uninstallable' => false, + ], + ], + 'aSelected' => [], + 'sExpectedAddedList' => '
    • No extension added.
    ', + 'sExpectedRemovedList' => '
    • itop-ext1 (forced uninstallation)
    ', + ], + 'added and removed extensions' => [ + 'aExtensions' => [ + 'itop-ext-added1' => [ + 'installed' => false, + ], + 'itop-ext-added2' => [ + 'installed' => false, + ], + 'itop-ext-removed1' => [ + 'installed' => true, + ], + 'itop-ext-removed2' => [ + 'installed' => true, + ], + ], + 'aSelected' => ['itop-ext-added1', 'itop-ext-added2'], + 'sExpectedAddedList' => '
    • itop-ext-added1
    • itop-ext-added2
    ', + 'sExpectedRemovedList' => '
    • itop-ext-removed1
    • itop-ext-removed2
    ', + ], + + ]; + } + + /** + * @dataProvider ProviderGetAddedAndRemovedExtensions + */ + public function testGetAddedAndRemovedExtensions($aExtensions, $aSelectedExtensions, $sExpectedAddedList, $sExpectedRemovedList) + { + $this->oStep->setExtensionMap(iTopExtensionsMapFake::createFromArray($aExtensions)); + [$sAddedList, $sRemovedList] = $this->oStep->GetAddedAndRemovedExtensions($aSelectedExtensions); + $this->assertEquals($sExpectedAddedList, $sAddedList); + $this->assertEquals($sExpectedRemovedList, $sRemovedList); + } + } diff --git a/tests/php-unit-tests/unitary-tests/setup/iTopExtensionsMapFake.php b/tests/php-unit-tests/unitary-tests/setup/iTopExtensionsMapFake.php index e80b88eb6e..ff1a204afd 100644 --- a/tests/php-unit-tests/unitary-tests/setup/iTopExtensionsMapFake.php +++ b/tests/php-unit-tests/unitary-tests/setup/iTopExtensionsMapFake.php @@ -12,9 +12,11 @@ public function __construct($sFromEnvironment = 'production', $aExtraDirs = []) public static function createFromArray($aExtensions) { $oMap = new static(); + foreach ($aExtensions as $sCode => $aExtension) { $oExtension = new iTopExtension(); $oExtension->sCode = $sCode; + $oExtension->sLabel = $sCode; $oExtension->bInstalled = $aExtension['installed']; $oExtension->aModules = $aExtension['modules'] ?? []; $oExtension->bCanBeUninstalled = $aExtension['uninstallable'] ?? null;