N°9567 - Extension Mgmt : Run setup

This commit is contained in:
Eric Espie
2026-05-18 16:20:49 +02:00
parent 39b131e102
commit 908e11d507
9 changed files with 200 additions and 53 deletions

View File

@@ -112,10 +112,30 @@ class DataFeatureRemovalController extends Controller
} }
// Display changed extensions // Display changed extensions
$aAddedExtensions = utils::ReadPostedParam('aAddedExtensions', []); $aHiddenInputNames = [
$aRemovedExtensions = utils::ReadPostedParam('aRemovedExtensions', []); 'selected_modules',
'selected_extensions',
'display_choices',
'added_extensions',
'removed_extensions',
'extensions_not_uninstallable',
];
IssueLog::Info(__METHOD__.' Extensions given in parameter', null, ['aAddedExtensions' => $aAddedExtensions, 'aRemovedExtensions' => $aRemovedExtensions]); $aHiddenInputs = [];
foreach ($aHiddenInputNames as $sInputName) {
$aHiddenInputs[$sInputName] = utils::ReadPostedParam($sInputName, "[]", utils::ENUM_SANITIZATION_FILTER_RAW_DATA);
}
$aParams['aHiddenInputs'] = $aHiddenInputs;
$aAddedExtensions = json_decode($aHiddenInputs['added_extensions'], true);
$aRemovedExtensions = json_decode($aHiddenInputs['removed_extensions'], true);
$aParams['aAddedExtensions'] = $aAddedExtensions;
$aParams['aRemovedExtensions'] = $aRemovedExtensions;
IssueLog::Info(__METHOD__.' Extensions given in parameter', null, [
'added_extensions' => $aAddedExtensions,
'removed_extensions' => $aRemovedExtensions]);
$this->Compile(array_keys($aRemovedExtensions), false); $this->Compile(array_keys($aRemovedExtensions), false);
@@ -126,23 +146,15 @@ class DataFeatureRemovalController extends Controller
$aParams['sTransactionId'] = utils::GetNewTransactionId(); $aParams['sTransactionId'] = utils::GetNewTransactionId();
$aParams['aClasses'] = $aGetRemovedClasses; $aParams['aClasses'] = $aGetRemovedClasses;
$aParams['aAddedExtensions'] = $aAddedExtensions;
$aParams['aRemovedExtensions'] = $aRemovedExtensions;
$aParams['aExtensions'] = $this->GetExtensionsTableDiff($aAddedExtensions, $aRemovedExtensions); $aParams['aExtensions'] = $this->GetExtensionsTableDiff($aAddedExtensions, $aRemovedExtensions);
new ContextTag(ContextTag::TAG_SETUP); new ContextTag(ContextTag::TAG_SETUP);
$aParams['sLaunchSetupUrl'] = utils::GetAbsoluteUrlAppRoot().'setup/wizard.php'; $aParams['sLaunchSetupUrl'] = utils::GetAbsoluteUrlAppRoot().'setup/wizard.php';
$aParams['aSetupParams'] = [ $aParams['aSetupParams'] = array_merge([
"_class" => "WizStepLandingBeforeAudit", "_class" => "WizStepLandingBeforeAudit",
"_params[authent]" => SetupUtils::CreateSetupToken(), "_params[authent]" => SetupUtils::CreateSetupToken(),
'_params[previous_version_dir]' => APPROOT,
"_params[install_mode]" => "upgrade",
'_params[source_dir]' => APPROOT.'datamodels/2.x/',
"_params[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"}]',
'_steps' => '[{"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"}]',
"operation" => "next", "operation" => "next",
]; ], $aHiddenInputs);
[$aParams['aDeletionPlanSummary'], $aParams['iQueryCount'], $aParams['bDeletionPossible']] = $this->GetDeletionPlanSummaryTable($aGetRemovedClasses); [$aParams['aDeletionPlanSummary'], $aParams['iQueryCount'], $aParams['bDeletionPossible']] = $this->GetDeletionPlanSummaryTable($aGetRemovedClasses);
[$aParams['aDeletionExecutionSummary'], $aParams['bHasDeletionExecution']] = $this->GetExecutionSummaryTable(); [$aParams['aDeletionExecutionSummary'], $aParams['bHasDeletionExecution']] = $this->GetExecutionSummaryTable();

View File

@@ -357,6 +357,9 @@ class ModuleDiscovery
{ {
$sDirectory = $sRootDir.'/'.$sRelDir; $sDirectory = $sRootDir.'/'.$sRelDir;
if (!is_dir(utils::RealPath($sDirectory, APPROOT))) {
throw new Exception('Data directory ('.$sDirectory.') Does not exist or is outside iTop.');
}
if ($hDir = opendir($sDirectory)) { if ($hDir = opendir($sDirectory)) {
// This is the correct way to loop over the directory. (according to the documentation) // This is the correct way to loop over the directory. (according to the documentation)
while (($sFile = readdir($hDir)) !== false) { while (($sFile = readdir($hDir)) !== false) {

View File

@@ -1576,11 +1576,13 @@ JS
* @return array * @return array
* @throws Exception * @throws Exception
*/ */
public static function AnalyzeInstallation($oWizard, $bAbortOnMissingDependency = false, $aModulesToLoad = null) public static function AnalyzeInstallation($oWizard, $bAbortOnMissingDependency = false, $aModulesToLoad = null, Config $oConfig = null)
{ {
require_once(APPROOT.'/setup/moduleinstaller.class.inc.php'); require_once(APPROOT.'/setup/moduleinstaller.class.inc.php');
if (is_null($oConfig)) {
$oConfig = self::GetConfig($oWizard); $oConfig = self::GetConfig($oWizard);
}
$aDirsToScan = [$oWizard->GetParameter('source_dir', '')]; $aDirsToScan = [$oWizard->GetParameter('source_dir', '')];

View File

@@ -296,7 +296,7 @@ on the page's parameters
$sOperation = utils::ReadParam('operation'); $sOperation = utils::ReadParam('operation');
$this->aParameters = utils::ReadParam('_params', [], false, 'raw_data'); $this->aParameters = utils::ReadParam('_params', [], false, 'raw_data');
$this->aSteps = json_decode(utils::ReadParam('_steps', '[]', false, 'raw_data'), true /* bAssoc */); $this->SetSteps(json_decode(utils::ReadParam('_steps', '[]', false, 'raw_data'), true));
switch ($sOperation) { switch ($sOperation) {
case 'next': case 'next':
@@ -371,6 +371,11 @@ on the page's parameters
return $sOutput; return $sOutput;
} }
public function SetSteps(array $aSteps): void
{
$this->aSteps = $aSteps;
}
/** /**
* @param string $sCurrentStepClass * @param string $sCurrentStepClass
* @param string $sCurrentState * @param string $sCurrentState

View File

@@ -100,39 +100,29 @@ JS);
{ {
$sApplicationUrl = utils::GetAbsoluteUrlModulePage('combodo-data-feature-removal', 'index.php'); $sApplicationUrl = utils::GetAbsoluteUrlModulePage('combodo-data-feature-removal', 'index.php');
$aRemovedExtensions = json_decode($this->oWizard->GetParameter('removed_extensions', '[]'), true); $aParams = [
$aHiddenRemovedExtensionInputs = ''; 'selected_modules',
if (!is_array($aRemovedExtensions)) { 'selected_extensions',
IssueLog::Warning('Posted removed_extensions is not an array'); 'display_choices',
$aRemovedExtensions = []; 'added_extensions',
} 'removed_extensions',
foreach ($aRemovedExtensions as $sExtCode => $sExtLabel) { 'extensions_not_uninstallable',
$sSafeExtCode = utils::HtmlEntities($sExtCode); ];
$aHiddenRemovedExtensionInputs .= <<<INPUT $aHiddenInputs = '';
<input type="hidden" name="aRemovedExtensions[$sSafeExtCode]" value="$sExtLabel"/> foreach ($aParams as $sParamName) {
$sElements = $this->oWizard->GetParameter($sParamName, '[]');
$aHiddenInputs .= <<<INPUT
<input type="hidden" name="$sParamName" value="$sElements"/>
INPUT; INPUT;
} }
$aAddedExtensions = json_decode($this->oWizard->GetParameter('extensions_added', "[]"), true);
$aHiddenAddedExtensionInputs = "";
if (!is_array($aAddedExtensions)) {
IssueLog::Warning('Posted extensions_added is not an array');
$aAddedExtensions = [];
}
foreach ($aAddedExtensions as $sExtCode => $sExtLabel) {
$sSafeExtCode = utils::HtmlEntities($sExtCode);
$aHiddenAddedExtensionInputs .= <<<INPUT
<input type="hidden" name="aAddedExtensions[$sSafeExtCode]" value="$sExtLabel"/>
INPUT;
}
$sUID = Session::Get('setup_token'); $sUID = Session::Get('setup_token');
$oPage->add( $oPage->add(
<<<HTML <<<HTML
<form id="data-feature-removal" class="ibo-setup--wizard ibo-is-hidden" method="post" action="$sApplicationUrl"> <form id="data-feature-removal" class="ibo-setup--wizard ibo-is-hidden" method="post" action="$sApplicationUrl">
<input type="hidden" name="operation" value="AnalysisResult"/> <input type="hidden" name="operation" value="AnalysisResult"/>
<input type="hidden" name="setup_token" value="$sUID"/> <input type="hidden" name="setup_token" value="$sUID"/>
$aHiddenRemovedExtensionInputs $aHiddenInputs
$aHiddenAddedExtensionInputs
</form> </form>
HTML HTML
); );

View File

@@ -5,8 +5,29 @@
* @license http://opensource.org/licenses/AGPL-3.0 * @license http://opensource.org/licenses/AGPL-3.0
*/ */
class WizStepLandingBeforeAudit extends WizardStep class WizStepLandingBeforeAudit extends WizStepModulesChoice
{ {
public function __construct(WizardController $oWizard, $sCurrentState)
{
$oProductionEnv = new RunTimeEnvironment();
$sBuildConfigFile = APPCONF.$oProductionEnv->GetBuildEnv().'/'.ITOP_CONFIG_FILE;
$this->oConfig = new Config($sBuildConfigFile);
$oWizard->SetParameter('previous_version_dir', APPROOT);
$oWizard->SetParameter('install_mode', 'upgrade');
$oWizard->SetParameter('source_dir', APPROOT.$this->oConfig->Get('source_dir'));
$oWizard->SetParameter('graphviz_path', $this->oConfig->Get('graphviz_path'));
$oWizard->SetParameter('application_url', $this->oConfig->Get('app_root_url'));
$oWizard->SetParameter('datamodel_version', ITOP_CORE_VERSION);
$oWizard->SetParameter('upgrade_type', 'use-compatible');
$oWizard->SaveParameter('use_symbolic_links', MFCompiler::UseSymbolicLinks());
$oWizard->SaveParameter('force-uninstall', '');
// should be done at the end
parent::__construct($oWizard, $sCurrentState, false);
}
/** /**
* @inheritDoc * @inheritDoc
*/ */
@@ -17,15 +38,54 @@ class WizStepLandingBeforeAudit extends WizardStep
/** /**
* @inheritDoc * @inheritDoc
*/ */
public function UpdateWizardStateAndGetNextStep(bool $bMoveForward = true): WizardState 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
$oConfig = new Config($sBuildConfigFile);
$this->oWizard->SetParameter('db_server', $oConfig->Get('db_host'));
$this->oWizard->SetParameter('db_user', $oConfig->Get('db_user'));
$this->oWizard->SetParameter('db_pwd', $oConfig->Get('db_pwd'));
$this->oWizard->SetParameter('db_name', $oConfig->Get('db_name'));
$this->oWizard->SetParameter('db_prefix', $oConfig->Get('db_subname'));
$this->oWizard->SetParameter('db_tls_enabled', $oConfig->Get('db_tls.enabled'));
$this->oWizard->SetParameter('db_tls_ca', $oConfig->Get('db_tls.ca') ?? '');
$this->oWizard->SaveParameter('selected_modules', []);
$this->oWizard->SaveParameter('selected_extensions', []);
$this->oWizard->SaveParameter('display_choices', []);
$this->oWizard->SaveParameter('added_extensions', []);
$this->oWizard->SaveParameter('removed_extensions', []);
$this->oWizard->SaveParameter('extensions_not_uninstallable', []);
return new WizardState(WizStepDataAudit::class); return new WizardState(WizStepDataAudit::class);
} }
/** /**
* @inheritDoc * @inheritDoc
*/ */
public function GetTitle() public function GetTitle(): string
{ {
return 'Before checking compatibility'; return 'Before checking compatibility';
} }

View File

@@ -38,7 +38,7 @@ class WizStepModulesChoice extends AbstractWizStepInstall
*/ */
protected iTopExtensionsMap $oExtensionsMap; protected iTopExtensionsMap $oExtensionsMap;
private ?array $aSteps = null; protected ?array $aSteps = null;
protected PhpExpressionEvaluator $oPhpExpressionEvaluator; protected PhpExpressionEvaluator $oPhpExpressionEvaluator;
@@ -51,7 +51,7 @@ class WizStepModulesChoice extends AbstractWizStepInstall
private array $aAnalyzeInstallationModules = []; private array $aAnalyzeInstallationModules = [];
private ?MissingDependencyException $oMissingDependencyException = null; private ?MissingDependencyException $oMissingDependencyException = null;
public function __construct(WizardController $oWizard, $sCurrentState) public function __construct(WizardController $oWizard, $sCurrentState, bool $bOverWriteConfig = true)
{ {
parent::__construct($oWizard, $sCurrentState); parent::__construct($oWizard, $sCurrentState);
$this->bChoicesFromDatabase = false; $this->bChoicesFromDatabase = false;
@@ -69,8 +69,10 @@ class WizStepModulesChoice extends AbstractWizStepInstall
if ($sConfigPath !== null) { if ($sConfigPath !== null) {
$this->oConfig = new Config($sConfigPath); $this->oConfig = new Config($sConfigPath);
if ($bOverWriteConfig) {
$aParamValues = $oWizard->GetParamForConfigArray(); $aParamValues = $oWizard->GetParamForConfigArray();
$this->oConfig->UpdateFromParams($aParamValues); $this->oConfig->UpdateFromParams($aParamValues);
}
$this->oExtensionsMap->LoadChoicesFromDatabase($this->oConfig); $this->oExtensionsMap->LoadChoicesFromDatabase($this->oConfig);
$this->bChoicesFromDatabase = true; $this->bChoicesFromDatabase = true;
@@ -78,7 +80,7 @@ class WizStepModulesChoice extends AbstractWizStepInstall
// Sanity check (not stopper, to let developers go further...) // Sanity check (not stopper, to let developers go further...)
try { try {
$this->aAnalyzeInstallationModules = SetupUtils::AnalyzeInstallation($this->oWizard, true); $this->aAnalyzeInstallationModules = SetupUtils::AnalyzeInstallation($this->oWizard, true, null, $this->oConfig);
} catch (MissingDependencyException $e) { } catch (MissingDependencyException $e) {
$this->oMissingDependencyException = $e; $this->oMissingDependencyException = $e;
$this->aAnalyzeInstallationModules = SetupUtils::AnalyzeInstallation($this->oWizard); $this->aAnalyzeInstallationModules = SetupUtils::AnalyzeInstallation($this->oWizard);
@@ -192,7 +194,7 @@ class WizStepModulesChoice extends AbstractWizStepInstall
$this->oWizard->SetParameter('selected_modules', json_encode(array_keys($aModules))); $this->oWizard->SetParameter('selected_modules', json_encode(array_keys($aModules)));
$this->oWizard->SetParameter('selected_extensions', json_encode($aExtensions)); $this->oWizard->SetParameter('selected_extensions', json_encode($aExtensions));
$this->oWizard->SetParameter('display_choices', $sDisplayChoices); $this->oWizard->SetParameter('display_choices', $sDisplayChoices);
$this->oWizard->SetParameter('extensions_added', json_encode($aExtensionsAdded)); $this->oWizard->SetParameter('added_extensions', json_encode($aExtensionsAdded));
$this->oWizard->SetParameter('removed_extensions', json_encode($aExtensionsRemoved)); $this->oWizard->SetParameter('removed_extensions', json_encode($aExtensionsRemoved));
$this->oWizard->SetParameter('extensions_not_uninstallable', json_encode(array_keys($aExtensionsNotUninstallable))); $this->oWizard->SetParameter('extensions_not_uninstallable', json_encode(array_keys($aExtensionsNotUninstallable)));

View File

@@ -17,7 +17,6 @@
* *
* You should have received a copy of the GNU Affero General Public License * You should have received a copy of the GNU Affero General Public License
*/ */
use Combodo\iTop\Application\WebPage\WebPage;
/** /**
* Summary of the installation tasks * Summary of the installation tasks
@@ -84,7 +83,7 @@ class WizStepSummary extends AbstractWizStepInstall
$oPage->add('<div id="params_summary">'); $oPage->add('<div id="params_summary">');
$oPage->add('<div class="closed"><a class="title ibo-setup-summary-title" href="#" aria-label="Extensions to be installed">Extensions to be installed</a>'); $oPage->add('<div class="closed"><a class="title ibo-setup-summary-title" href="#" aria-label="Extensions to be installed">Extensions to be installed</a>');
$aExtensionsAdded = json_decode($this->oWizard->GetParameter('extensions_added'), true); $aExtensionsAdded = json_decode($this->oWizard->GetParameter('added_extensions'), true);
if (count($aExtensionsAdded) > 0) { if (count($aExtensionsAdded) > 0) {
$sExtensionsAdded = '<ul>'; $sExtensionsAdded = '<ul>';

View File

@@ -15,13 +15,87 @@ $aParams = [
new ContextTag(ContextTag::TAG_SETUP); new ContextTag(ContextTag::TAG_SETUP);
$sToken = SetupUtils::CreateSetupToken(); $sToken = SetupUtils::CreateSetupToken();
$aSelectedModules = [
'authent-cas',
'authent-external',
'authent-ldap',
'authent-local',
'combodo-backoffice-darkmoon-theme',
'combodo-backoffice-fullmoon-high-contrast-theme',
'combodo-backoffice-fullmoon-protanopia-deuteranopia-theme',
'combodo-backoffice-fullmoon-tritanopia-theme',
'combodo-data-feature-removal',
'itop-backup',
'itop-config',
'itop-files-information',
'itop-portal-base',
'itop-profiles-itil',
'itop-sla-computation',
'itop-structure',
'itop-welcome-itil',
'itop-config-mgmt',
'itop-attachments',
'itop-tickets',
'combodo-db-tools',
'itop-core-update',
'itop-hub-connector',
'itop-oauth-client',
'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',
'itop-datacenter-mgmt',
'itop-endusers-devices',
'itop-storage-mgmt',
'itop-virtualization-mgmt',
'itop-bridge-cmdb-ticket',
'itop-bridge-virtualization-storage',
'itop-service-mgmt',
'itop-bridge-cmdb-services',
'itop-bridge-datacenter-mgmt-services',
'itop-bridge-endusers-devices-services',
'itop-bridge-storage-mgmt-services',
'itop-bridge-virtualization-mgmt-services',
'itop-request-mgmt',
'itop-portal',
'itop-change-mgmt',
'itop-faq-light',
'itop-knownerror-mgmt',
'itop-problem-mgmt',
'itop-system-information',
'itop-log-mgmt',
];
$aSelectedExtensions = [
'itop-config-mgmt-core',
'itop-config-mgmt-datacenter',
'itop-config-mgmt-end-user',
'itop-config-mgmt-storage',
'itop-config-mgmt-virtualization',
'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',
'itop-system-information',
'itop-log-mgmt',
];
$aRemovedExtensions = ['itop-container-mgmt' => 'Containerization'];
$aPostParams = [ $aPostParams = [
"auth_user" => 'admin', "auth_user" => 'admin',
"auth_pwd" => 'admin', "auth_pwd" => 'admin',
'login_mode' => 'form', 'login_mode' => 'form',
'operation' => 'AnalysisResult', 'operation' => 'AnalysisResult',
'aRemovedExtensions[itop-container-mgmt]' => 'Containerization',
'setup_token' => $sToken, 'setup_token' => $sToken,
'selected_modules' => utils::HtmlEntities(json_encode($aSelectedModules)),
'selected_extensions' => utils::HtmlEntities(json_encode($aSelectedExtensions)),
'removed_extensions' => utils::HtmlEntities(json_encode($aRemovedExtensions)),
]; ];
$sHiddenPostedInput = ""; $sHiddenPostedInput = "";
@@ -45,7 +119,7 @@ $sReadyJs = <<<JS
$("#_form").trigger("submit"); $("#_form").trigger("submit");
JS; JS;
$oP = new NiceWebPage("TEST"); $oP = new NiceWebPage("Simulate Audit From Setup");
$oP->add($sDiv); $oP->add($sDiv);
$oP->add_ready_script($sReadyJs); $oP->add_ready_script($sReadyJs);
$oP->output(); $oP->output();