diff --git a/setup/extensionsmap.class.inc.php b/setup/extensionsmap.class.inc.php index 4f136cb1f..a02dbe77f 100644 --- a/setup/extensionsmap.class.inc.php +++ b/setup/extensionsmap.class.inc.php @@ -1,6 +1,7 @@ bMarkedAsChosen = false; $this->sVersion = ITOP_VERSION; $this->sInstalledVersion = ''; + $this->bVisible = true; } } @@ -83,14 +89,20 @@ class iTopExtensionsMap { /** * The list of all discovered extensions - * @var iTopExtension[] + * @param string $sFromEnvironment The environment to scan + * @param bool $bNormailizeOldExtension true to "magically" convert some well-known old extensions (i.e. a set of modules) to the new iTopExtension format + * @return void */ protected $aExtensions; - public function __construct($sFromEnvironment = 'production') + public function __construct($sFromEnvironment = 'production', $bNormalizeOldExtensions = true) { $this->aExtensions = array(); $this->ScanDisk($sFromEnvironment); + if ($bNormalizeOldExtensions) + { + $this->NormalizeOldExtensions(); + } } /** @@ -269,7 +281,11 @@ class iTopExtensionsMap // Ignore non-visible modules and auto-select ones, since these are never prompted // as a choice to the end-user - if (!$aModuleInfo[2]['visible'] || isset($aModuleInfo[2]['auto_select'])) continue; + $bVisible = true; + if (!$aModuleInfo[2]['visible'] || isset($aModuleInfo[2]['auto_select'])) + { + $bVisible = false; + } // Let's create a "fake" extension from this module (containing just this module) for backwards compatibility $sExtensionId = $sModuleId; @@ -283,6 +299,7 @@ class iTopExtensionsMap $oExtension->bMandatory = $aModuleInfo[2]['mandatory']; $oExtension->sMoreInfoUrl = $aModuleInfo[2]['doc.more_information']; $oExtension->aModules = array($sModuleName); + $oExtension->bVisible = $bVisible; $this->AddExtension($oExtension); @@ -461,4 +478,624 @@ class iTopExtensionsMap } return true; } + + /** + * Search for multi-module extensions that are NOT deployed as an extension (i.e. shipped with an extension.xml file) + * but as a bunch of un-related modules based on the signature of some well-known extensions. If such an extension is found, + * replace the stand-alone modules by an "extension" with the appropriate label/description/version containing the same modules. + * @param string $sInSourceOnly The source directory to scan (datamodel|extensions|data) + */ + public function NormalizeOldExtensions($sInSourceOnly = iTopExtension::SOURCE_MANUAL) + { + $aSignatures = $this->GetOldExtensionsSignatures(); + foreach($aSignatures as $sExtensionCode => $aExtensionSignatures) + { + $bFound = false; + foreach($aExtensionSignatures['versions'] as $sVersion => $aModules) + { + $bInstalled = true; + foreach($aModules as $sModuleId) + { + if(!$this->ModuleIsPresent($sModuleId, $sInSourceOnly)) + { + $bFound = false; + break; // One missing module is enough to determine that the extension/version is not present + } + else + { + $bInstalled = $bInstalled && (!$this->ModuleIsInstalled($sModuleId, $sInSourceOnly)); + $bFound = true; + } + } + if ($bFound) break; // The current version matches the signature + } + + if ($bFound) + { + $oExtension = new iTopExtension(); + $oExtension->sCode = $sExtensionCode; + $oExtension->sLabel = $aExtensionSignatures['label']; + $oExtension->sSource = $sInSourceOnly; + $oExtension->sDescription = $aExtensionSignatures['description']; + $oExtension->sVersion = $sVersion; + $oExtension->aModules = array(); + if ($bInstalled) + { + $oExtension->sInstalledVersion = $sVersion; + $oExtension->bMarkedAsChosen = true; + } + foreach($aModules as $sModuleId) + { + list($sModuleName, $sModuleVersion) = ModuleDiscovery::GetModuleName($sModuleId); + $oExtension->aModules[] = $sModuleName; + } + $this->ReplaceModulesByNormalizedExtension($aExtensionSignatures['versions'][$sVersion], $oExtension); + } + } + } + + /** + * Check if the given module-code/version is present on the disk + * @param string $sModuleIdToFind The module ID (code/version) to search for + * @param string $sInSourceOnly The origin (=source) to search in (datamodel|extensions|data) + * @return boolean + */ + protected function ModuleIsPresent($sModuleIdToFind, $sInSourceOnly) + { + return (array_key_exists($sModuleIdToFind, $this->aExtensions) && ($this->aExtensions[$sModuleIdToFind]->sSource == $sInSourceOnly)); + } + + /** + * Check if the given module-code/version is currently installed + * @param string $sModuleIdToFind The module ID (code/version) to search for + * @param string $sInSourceOnly The origin (=source) to search in (datamodel|extensions|data) + * @return boolean + */ + protected function ModuleIsInstalled($sModuleIdToFind, $sInSourceOnly) + { + return (array_key_exists($sModuleIdToFind, $this->aExtensions) && + ($this->aExtensions[$sModuleIdToFind]->sSource == $sInSourceOnly) && + ($this->aExtensions[$sModuleIdToFind]->sInstalledVersion !== '') ); + } + + /** + * Replace a given set of stand-alone modules by one single "extension" + * @param string[] $aModules + * @param iTopExtension $oNewExtension + */ + protected function ReplaceModulesByNormalizedExtension($aModules, iTopExtension $oNewExtension) + { + foreach($aModules as $sModuleId) + { + unset($this->aExtensions[$sModuleId]); + } + $this->AddExtension($oNewExtension); + } + + /** + * Get the list of signatures of some well-known multi-module extensions + * @return string[][]|string[][][][] + */ + protected function GetOldExtensionsSignatures() + { + // Generated by the Factory using the page export_component_versions_for_normalisation.php + return array ( + 'combodo-approval-process-light' => + array ( + 'label' => 'Approval process light', + 'description' => 'Approve a request via a simple email', + 'versions' => + array ( + '1.0.1' => + array ( + 0 => 'approval-base/2.1.0', + 1 => 'combodo-approval-light/1.0.1', + ), + '1.0.2' => + array ( + 0 => 'approval-base/2.1.1', + 1 => 'combodo-approval-light/1.0.2', + ), + '1.0.3' => + array ( + 0 => 'approval-base/2.1.2', + 1 => 'combodo-approval-light/1.0.2', + ), + '1.1.0' => + array ( + 0 => 'approval-base/2.2.2', + 1 => 'combodo-approval-light/1.0.2', + ), + '1.1.1' => + array ( + 0 => 'approval-base/2.2.3', + 1 => 'combodo-approval-light/1.0.2', + ), + '1.1.2' => + array ( + 0 => 'approval-base/2.2.6', + 1 => 'combodo-approval-light/1.0.2', + ), + '1.1.3' => + array ( + 0 => 'approval-base/2.2.6', + 1 => 'combodo-approval-light/1.0.3', + ), + '1.2.0' => + array ( + 0 => 'approval-base/2.3.0', + 1 => 'combodo-approval-light/1.0.3', + ), + '1.2.1' => + array ( + 0 => 'approval-base/2.4.0', + 1 => 'combodo-approval-light/1.0.4', + ), + '1.3.0' => + array ( + 0 => 'approval-base/2.4.2', + 1 => 'combodo-approval-light/1.1.1', + ), + '1.3.1' => + array ( + 0 => 'approval-base/2.5.0', + 1 => 'combodo-approval-light/1.1.1', + ), + '1.3.2' => + array ( + 0 => 'approval-base/2.5.0', + 1 => 'combodo-approval-light/1.1.2', + ), + '1.2.2' => + array ( + 0 => 'approval-base/2.4.2', + 1 => 'combodo-approval-light/1.0.5', + ), + '1.3.3' => + array ( + 0 => 'approval-base/2.5.1', + 1 => 'combodo-approval-light/1.1.2', + ), + '1.3.4' => + array ( + 0 => 'approval-base/2.5.2', + 1 => 'combodo-approval-light/1.1.2', + ), + '1.3.5' => + array ( + 0 => 'approval-base/2.5.3', + 1 => 'combodo-approval-light/1.1.2', + ), + '1.4.0' => + array ( + 0 => 'approval-base/2.5.3', + 1 => 'combodo-approval-light/1.1.2', + 2 => 'itop-approval-portal/1.0.0', + ), + ), + ), + 'combodo-approval-process-automation' => + array ( + 'label' => 'Approval process automation', + 'description' => 'Control your approval process with predefined rules based on service catalog', + 'versions' => + array ( + '1.0.1' => + array ( + 0 => 'approval-base/2.1.0', + 1 => 'combodo-approval-extended/1.0.2', + ), + '1.0.2' => + array ( + 0 => 'approval-base/2.1.1', + 1 => 'combodo-approval-extended/1.0.4', + ), + '1.0.3' => + array ( + 0 => 'approval-base/2.1.2', + 1 => 'combodo-approval-extended/1.0.4', + ), + '1.1.0' => + array ( + 0 => 'approval-base/2.2.2', + 1 => 'combodo-approval-extended/1.0.4', + ), + '1.1.1' => + array ( + 0 => 'approval-base/2.2.3', + 1 => 'combodo-approval-extended/1.0.4', + ), + '1.1.2' => + array ( + 0 => 'approval-base/2.2.6', + 1 => 'combodo-approval-extended/1.0.5', + ), + '1.1.3' => + array ( + 0 => 'approval-base/2.2.6', + 1 => 'combodo-approval-extended/1.0.6', + ), + '1.2.0' => + array ( + 0 => 'approval-base/2.3.0', + 1 => 'combodo-approval-extended/1.0.7', + ), + '1.2.1' => + array ( + 0 => 'approval-base/2.4.0', + 1 => 'combodo-approval-extended/1.0.8', + ), + '1.3.0' => + array ( + 0 => 'approval-base/2.4.2', + 1 => 'combodo-approval-extended/1.2.1', + ), + '1.3.1' => + array ( + 0 => 'approval-base/2.5.0', + 1 => 'combodo-approval-extended/1.2.1', + ), + '1.3.2' => + array ( + 0 => 'approval-base/2.5.0', + 1 => 'combodo-approval-extended/1.2.2', + ), + '1.2.2' => + array ( + 0 => 'approval-base/2.4.2', + 1 => 'combodo-approval-extended/1.0.9', + ), + '1.3.3' => + array ( + 0 => 'approval-base/2.5.1', + 1 => 'combodo-approval-extended/1.2.3', + ), + '1.3.4' => + array ( + 0 => 'approval-base/2.5.2', + 1 => 'combodo-approval-extended/1.2.3', + ), + '1.3.5' => + array ( + 0 => 'approval-base/2.5.3', + 1 => 'combodo-approval-extended/1.2.3', + ), + '1.4.0' => + array ( + 0 => 'approval-base/2.5.3', + 1 => 'combodo-approval-extended/1.2.3', + 3 => 'itop-approval-portal/1.0.0', + ), + ), + ), + 'combodo-predefined-response-models' => + array ( + 'label' => 'Predefined response models', + 'description' => 'Pick common answers from a list of predefined replies grouped by categories to update tickets log', + 'versions' => + array ( + '1.0.0' => + array ( + 0 => 'precanned-replies/1.0.0', + 1 => 'precanned-replies-pro/1.0.0', + ), + '1.0.1' => + array ( + 0 => 'precanned-replies/1.0.1', + 1 => 'precanned-replies-pro/1.0.1', + ), + '1.0.2' => + array ( + 0 => 'precanned-replies/1.0.2', + 1 => 'precanned-replies-pro/1.0.1', + ), + '1.0.3' => + array ( + 0 => 'precanned-replies/1.0.3', + 1 => 'precanned-replies-pro/1.0.1', + ), + '1.0.4' => + array ( + 0 => 'precanned-replies/1.0.3', + 1 => 'precanned-replies-pro/1.0.2', + ), + '1.0.5' => + array ( + 0 => 'precanned-replies/1.0.4', + 1 => 'precanned-replies-pro/1.0.2', + ), + '1.1.0' => + array ( + 0 => 'precanned-replies/1.1.0', + 1 => 'precanned-replies-pro/1.0.2', + ), + '1.1.1' => + array ( + 0 => 'precanned-replies/1.1.1', + 1 => 'precanned-replies-pro/1.0.2', + ), + ), + ), + 'combodo-customized-request-forms' => + array ( + 'label' => 'Customized request forms', + 'description' => 'Define personalized request forms based on the service catalog. Add extra fields for a given type of request.', + 'versions' => + array ( + '1.0.1' => + array ( + 0 => 'templates-base/2.1.1', + 1 => 'itop-request-template/1.0.0', + ), + '1.0.2' => + array ( + 0 => 'templates-base/2.1.2', + 1 => 'itop-request-template/1.0.0', + ), + '1.0.3' => + array ( + 0 => 'templates-base/2.1.2', + 1 => 'itop-request-template/1.0.1', + ), + '1.0.4' => + array ( + 0 => 'templates-base/2.1.3', + 1 => 'itop-request-template/1.0.1', + ), + '1.0.5' => + array ( + 0 => 'templates-base/2.1.4', + 1 => 'itop-request-template/1.0.1', + ), + '2.0.0' => + array ( + 0 => 'templates-base/3.0.0', + 1 => 'itop-request-template/2.0.0', + 2 => 'itop-request-template-portal/1.0.0', + ), + '2.0.1' => + array ( + 0 => 'templates-base/3.0.1', + 1 => 'itop-request-template/2.0.0', + 2 => 'itop-request-template-portal/1.0.0', + ), + '2.0.2' => + array ( + 0 => 'templates-base/3.0.2', + 1 => 'itop-request-template/2.0.0', + 2 => 'itop-request-template-portal/1.0.0', + ), + '2.0.3' => + array ( + 0 => 'templates-base/3.0.4', + 1 => 'itop-request-template/2.0.0', + 2 => 'itop-request-template-portal/1.0.0', + ), + '2.0.4' => + array ( + 0 => 'templates-base/3.0.5', + 1 => 'itop-request-template/2.0.0', + 2 => 'itop-request-template-portal/1.0.0', + ), + '2.0.5' => + array ( + 0 => 'templates-base/3.0.6', + 1 => 'itop-request-template/2.0.0', + 2 => 'itop-request-template-portal/1.0.0', + ), + '2.0.6' => + array ( + 0 => 'templates-base/3.0.8', + 1 => 'itop-request-template/2.0.0', + 2 => 'itop-request-template-portal/1.0.0', + ), + '2.0.7' => + array ( + 0 => 'templates-base/3.0.9', + 1 => 'itop-request-template/2.0.0', + 2 => 'itop-request-template-portal/1.0.0', + ), + '2.0.8' => + array ( + 0 => 'templates-base/3.0.12', + 1 => 'itop-request-template/2.0.0', + 2 => 'itop-request-template-portal/1.0.0', + ), + ), + ), + 'combodo-sla-considering-business-hours' => + array ( + 'label' => 'SLA considering business hours', + 'description' => 'Compute SLAs taking into account service coverage window and holidays', + 'versions' => + array ( + '2.0.1' => + array ( + 0 => 'combodo-sla-computation/2.0.1', + 1 => 'combodo-coverage-windows-computation/2.0.0', + ), + '2.1.0' => + array ( + 0 => 'combodo-sla-computation/2.1.0', + 1 => 'combodo-coverage-windows-computation/2.0.0', + ), + '2.1.1' => + array ( + 0 => 'combodo-sla-computation/2.1.1', + 1 => 'combodo-coverage-windows-computation/2.0.0', + ), + '2.1.2' => + array ( + 0 => 'combodo-sla-computation/2.1.2', + 1 => 'combodo-coverage-windows-computation/2.0.0', + ), + '2.1.3' => + array ( + 0 => 'combodo-sla-computation/2.1.2', + 1 => 'combodo-coverage-windows-computation/2.0.1', + ), + '2.0.2' => + array ( + 0 => 'combodo-sla-computation/2.0.1', + 1 => 'combodo-coverage-windows-computation/2.0.1', + ), + '2.1.4' => + array ( + 0 => 'combodo-sla-computation/2.1.3', + 1 => 'combodo-coverage-windows-computation/2.0.1', + ), + '2.1.5' => + array ( + 0 => 'combodo-sla-computation/2.1.5', + 1 => 'combodo-coverage-windows-computation/2.0.1', + ), + '2.1.6' => + array ( + 0 => 'combodo-sla-computation/2.1.5', + 1 => 'combodo-coverage-windows-computation/2.0.2', + ), + '2.1.7' => + array ( + 0 => 'combodo-sla-computation/2.1.6', + 1 => 'combodo-coverage-windows-computation/2.0.2', + ), + '2.1.8' => + array ( + 0 => 'combodo-sla-computation/2.1.7', + 1 => 'combodo-coverage-windows-computation/2.0.2', + ), + '2.1.9' => + array ( + 0 => 'combodo-sla-computation/2.1.8', + 1 => 'combodo-coverage-windows-computation/2.0.2', + ), + ), + ), + 'combodo-mail-to-ticket-automation' => + array ( + 'label' => 'Mail to ticket automation', + 'description' => 'Scan several mailboxes to create or update tickets.', + 'versions' => + array ( + '2.6.0' => + array ( + 0 => 'combodo-email-synchro/2.6.0', + 1 => 'itop-standard-email-synchro/2.6.0', + ), + '2.6.1' => + array ( + 0 => 'combodo-email-synchro/2.6.1', + 1 => 'itop-standard-email-synchro/2.6.0', + ), + '2.6.2' => + array ( + 0 => 'combodo-email-synchro/2.6.2', + 1 => 'itop-standard-email-synchro/2.6.0', + ), + '2.6.3' => + array ( + 0 => 'combodo-email-synchro/2.6.2', + 1 => 'itop-standard-email-synchro/2.6.1', + ), + '2.6.4' => + array ( + 0 => 'combodo-email-synchro/2.6.3', + 1 => 'itop-standard-email-synchro/2.6.2', + ), + '2.6.5' => + array ( + 0 => 'combodo-email-synchro/2.6.4', + 1 => 'itop-standard-email-synchro/2.6.2', + ), + '2.6.6' => + array ( + 0 => 'combodo-email-synchro/2.6.5', + 1 => 'itop-standard-email-synchro/2.6.3', + ), + '2.6.7' => + array ( + 0 => 'combodo-email-synchro/2.6.6', + 1 => 'itop-standard-email-synchro/2.6.4', + ), + '2.6.8' => + array ( + 0 => 'combodo-email-synchro/2.6.7', + 1 => 'itop-standard-email-synchro/2.6.4', + ), + '2.6.9' => + array ( + 0 => 'combodo-email-synchro/2.6.8', + 1 => 'itop-standard-email-synchro/2.6.5', + ), + '2.6.10' => + array ( + 0 => 'combodo-email-synchro/2.6.9', + 1 => 'itop-standard-email-synchro/2.6.6', + ), + '2.6.11' => + array ( + 0 => 'combodo-email-synchro/2.6.10', + 1 => 'itop-standard-email-synchro/2.6.6', + ), + '2.6.12' => + array ( + 0 => 'combodo-email-synchro/2.6.11', + 1 => 'itop-standard-email-synchro/2.6.6', + ), + '3.0.0' => + array ( + 0 => 'combodo-email-synchro/3.0.0', + 1 => 'itop-standard-email-synchro/3.0.0', + ), + '3.0.1' => + array ( + 0 => 'combodo-email-synchro/3.0.1', + 1 => 'itop-standard-email-synchro/3.0.1', + ), + '3.0.2' => + array ( + 0 => 'combodo-email-synchro/3.0.2', + 1 => 'itop-standard-email-synchro/3.0.1', + ), + '3.0.3' => + array ( + 0 => 'combodo-email-synchro/3.0.3', + 1 => 'itop-standard-email-synchro/3.0.3', + ), + '3.0.4' => + array ( + 0 => 'combodo-email-synchro/3.0.3', + 1 => 'itop-standard-email-synchro/3.0.4', + ), + '3.0.5' => + array ( + 0 => 'combodo-email-synchro/3.0.4', + 1 => 'itop-standard-email-synchro/3.0.4', + ), + '3.0.6' => + array ( + 0 => 'combodo-email-synchro/3.0.5', + 1 => 'itop-standard-email-synchro/3.0.4', + ), + '3.0.7' => + array ( + 0 => 'combodo-email-synchro/3.0.5', + 1 => 'itop-standard-email-synchro/3.0.5', + ), + ), + ), + 'combodo-configurator-for-automatic-object-creation' => + array ( + 'label' => 'Configurator for automatic object creation', + 'description' => 'Templating based on existing objects.', + 'versions' => + array ( + '1.0.13' => + array ( + 1 => 'itop-stencils/1.0.6', + ), + ), + ), + ); + } } \ No newline at end of file diff --git a/setup/wizardsteps.class.inc.php b/setup/wizardsteps.class.inc.php index cd78cc867..292f3ab5a 100644 --- a/setup/wizardsteps.class.inc.php +++ b/setup/wizardsteps.class.inc.php @@ -1768,7 +1768,7 @@ EOF foreach($this->oExtensionsMap->GetAllExtensions() as $oExtension) { - if ($oExtension->sSource !== iTopExtension::SOURCE_WIZARD) + if (($oExtension->sSource !== iTopExtension::SOURCE_WIZARD) && ($oExtension->bVisible)) { $aStepDefinition['options'][] = array( 'extension_code' => $oExtension->sCode,