mirror of
https://github.com/Combodo/iTop.git
synced 2026-04-26 20:18:52 +02:00
Improved way to track the choices made during the installation in order to:
1) Be able to proerly report this information 2) Make sure that the same (proper) choices are proposed upon update SVN:trunk[4815]
This commit is contained in:
@@ -1962,3 +1962,11 @@ span.refresh-button {
|
||||
.object-ref-link {
|
||||
background: none;
|
||||
}
|
||||
.extension-source {
|
||||
display: inline-block;
|
||||
background-color: #555;
|
||||
padding: 3px;
|
||||
font-size: 10px;
|
||||
color: #fff;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
@@ -2163,3 +2163,11 @@ span.refresh-button {
|
||||
.object-ref-link {
|
||||
background: none;
|
||||
}
|
||||
.extension-source {
|
||||
display:inline-block;
|
||||
background-color: $grey-color;
|
||||
padding:3px;
|
||||
font-size:10px;
|
||||
color:#fff;
|
||||
border-radius: 4px;
|
||||
}
|
||||
@@ -1305,7 +1305,10 @@ When associated with a trigger, each action is given an "order" number, specifyi
|
||||
'UI:About:DataModel' => 'Data model',
|
||||
'UI:About:Support' => 'Support information',
|
||||
'UI:About:Licenses' => 'Licenses',
|
||||
'UI:About:Modules' => 'Installed modules',
|
||||
'UI:About:InstallationOptions' => 'Installation options',
|
||||
'UI:About:ManualExtensionSource' => 'Extension',
|
||||
'UI:About:Extension_Version' => 'Version: %1$s',
|
||||
'UI:About:RemoteExtensionSource' => 'Data',
|
||||
|
||||
'UI:DisconnectedDlgMessage' => 'You are disconnected. You must identify yourself to continue using the application.',
|
||||
'UI:DisconnectedDlgTitle' => 'Warning!',
|
||||
|
||||
@@ -1148,7 +1148,10 @@ Lors de l\'association à un déclencheur, on attribue à chaque action un numé
|
||||
'UI:About:DataModel' => 'Modèle de données',
|
||||
'UI:About:Support' => 'Informations pour le support',
|
||||
'UI:About:Licenses' => 'Licences',
|
||||
'UI:About:Modules' => 'Modules installés',
|
||||
'UI:About:InstallationOptions' => 'Options d\'installation',
|
||||
'UI:About:Extension_Version' => 'Version: %1$s',
|
||||
'UI:About:ManualExtensionSource' => 'Extension',
|
||||
|
||||
|
||||
'UI:DisconnectedDlgMessage' => 'Vous êtes déconnecté(e). Vous devez vous identifier pour pouvoir continuer à utiliser l\'application.',
|
||||
'UI:DisconnectedDlgTitle' => 'Attention !',
|
||||
|
||||
@@ -1231,16 +1231,30 @@ EOF
|
||||
$oPage->add("</div>");
|
||||
|
||||
$oPage->add('<fieldset>');
|
||||
$oPage->add('<legend>'.Dict::S('UI:About:Modules').'</legend>');
|
||||
//$oPage->add(print_r($aAvailableModules, true));
|
||||
$oPage->add("<div style=\"height: 150px; overflow: auto; font-size: smaller;\">");
|
||||
$oPage->add('<legend>'.Dict::S('UI:About:InstallationOptions').'</legend>');
|
||||
$oPage->add("<div style=\"max-height: 150px; overflow: auto; font-size: smaller;\">");
|
||||
$oPage->add('<ul style="margin: 0;">');
|
||||
foreach ($aAvailableModules as $sModuleId => $aModuleData)
|
||||
|
||||
require_once(APPROOT.'setup/extensionsmap.class.inc.php');
|
||||
$oExtensionsMap = new iTopExtensionsMap();
|
||||
$oExtensionsMap->LoadChoicesFromDatabase(MetaModel::GetConfig());
|
||||
$aChoices = $oExtensionsMap->GetChoices();
|
||||
foreach ($aChoices as $oExtension)
|
||||
{
|
||||
if ($sModuleId == '_Root_') continue;
|
||||
if (!$aModuleData['visible']) continue;
|
||||
if ($aModuleData['version_db'] == '') continue;
|
||||
$oPage->add('<li>'.$aModuleData['label'].' ('.$aModuleData['version_db'].')</li>');
|
||||
switch($oExtension->sSource)
|
||||
{
|
||||
case iTopExtension::SOURCE_REMOTE:
|
||||
$sSource = ' <span class="extension-source">'.Dict::S('UI:About:RemoteExtensionSource').'</span>';
|
||||
break;
|
||||
|
||||
case iTopExtension::SOURCE_MANUAL:
|
||||
$sSource = ' <span class="extension-source">'.Dict::S('UI:About:ManualExtensionSource').'</span>';
|
||||
break;
|
||||
|
||||
default:
|
||||
$sSource = '';
|
||||
}
|
||||
$oPage->add('<li title="'.Dict::Format('UI:About:Extension_Version', $oExtension->sInstalledVersion).'">'.$oExtension->sLabel.$sSource.'</li>');
|
||||
}
|
||||
$oPage->add('</ul>');
|
||||
$oPage->add("</div>");
|
||||
@@ -1280,6 +1294,25 @@ EOF
|
||||
|
||||
$oPage->add('InstallDate: '.$sLastInstallDate."\n");
|
||||
$oPage->add('InstallPath: '.APPROOT."\n");
|
||||
$oPage->add("---- Installation choices ----\n");
|
||||
foreach ($aChoices as $oExtension)
|
||||
{
|
||||
switch($oExtension->sSource)
|
||||
{
|
||||
case iTopExtension::SOURCE_REMOTE:
|
||||
$sSource = ' ('.Dict::S('UI:About:RemoteExtensionSource').')';
|
||||
break;
|
||||
|
||||
case iTopExtension::SOURCE_MANUAL:
|
||||
$sSource = ' ('.Dict::S('UI:About:ManualExtensionSource').')';
|
||||
break;
|
||||
|
||||
default:
|
||||
$sSource = '';
|
||||
}
|
||||
$oPage->add('InstalledExtension/'.$oExtension->sCode.'/'.$oExtension->sVersion.$sSource."\n");
|
||||
}
|
||||
$oPage->add("---- Actual modules installed ----\n");
|
||||
foreach ($aAvailableModules as $sModuleId => $aModuleData)
|
||||
{
|
||||
if ($sModuleId == '_Root_') continue;
|
||||
|
||||
@@ -198,7 +198,6 @@ class ApplicationInstaller
|
||||
$sTargetEnvironment = 'production';
|
||||
}
|
||||
$sTargetDir = 'env-'.$sTargetEnvironment;
|
||||
$sWorkspaceDir = $this->oParams->Get('workspace_dir', 'workspace');
|
||||
$bUseSymbolicLinks = false;
|
||||
$aMiscOptions = $this->oParams->Get('options', array());
|
||||
if (isset($aMiscOptions['symlinks']) && $aMiscOptions['symlinks'] )
|
||||
@@ -299,7 +298,6 @@ class ApplicationInstaller
|
||||
$sDBPwd = $aDBParams['pwd'];
|
||||
$sDBName = $aDBParams['name'];
|
||||
$sDBPrefix = $aDBParams['prefix'];
|
||||
$aFiles = $this->oParams->Get('files', array());
|
||||
$bOldAddon = $this->oParams->Get('old_addon', false);
|
||||
$bSampleData = ($this->oParams->Get('sample_data', 0) == 1);
|
||||
|
||||
@@ -331,13 +329,14 @@ class ApplicationInstaller
|
||||
$sUrl = $this->oParams->Get('url', '');
|
||||
$sGraphvizPath = $this->oParams->Get('graphviz_path', '');
|
||||
$sLanguage = $this->oParams->Get('language', '');
|
||||
$aSelectedModules = $this->oParams->Get('selected_modules', array());
|
||||
$aSelectedModuleCodes = $this->oParams->Get('selected_modules', array());
|
||||
$aSelectedExtensionCodes = $this->oParams->Get('selected_extensions', array());
|
||||
$bOldAddon = $this->oParams->Get('old_addon', false);
|
||||
$sSourceDir = $this->oParams->Get('source_dir', '');
|
||||
$sPreviousConfigFile = $this->oParams->Get('previous_configuration_file', '');
|
||||
$sDataModelVersion = $this->oParams->Get('datamodel_version', '0.0.0');
|
||||
|
||||
self::DoCreateConfig($sMode, $sTargetDir, $sDBServer, $sDBUser, $sDBPwd, $sDBName, $sDBPrefix, $sUrl, $sLanguage, $aSelectedModules, $sTargetEnvironment, $bOldAddon, $sSourceDir, $sPreviousConfigFile, $sDataModelVersion, $sGraphvizPath);
|
||||
self::DoCreateConfig($sMode, $sTargetDir, $sDBServer, $sDBUser, $sDBPwd, $sDBName, $sDBPrefix, $sUrl, $sLanguage, $aSelectedModuleCodes, $aSelectedExtensionCodes, $sTargetEnvironment, $bOldAddon, $sSourceDir, $sPreviousConfigFile, $sDataModelVersion, $sGraphvizPath);
|
||||
|
||||
$aResult = array(
|
||||
'status' => self::INFO,
|
||||
@@ -491,7 +490,7 @@ class ApplicationInstaller
|
||||
|
||||
$aModules = $oFactory->FindModules();
|
||||
|
||||
foreach($aModules as $foo => $oModule)
|
||||
foreach($aModules as $oModule)
|
||||
{
|
||||
$sModule = $oModule->GetName();
|
||||
if (in_array($sModule, $aSelectedModules))
|
||||
@@ -531,8 +530,8 @@ class ApplicationInstaller
|
||||
SetupPage::log_info("Data model successfully compiled to '$sTargetPath'.");
|
||||
|
||||
$sCacheDir = APPROOT.'/data/cache-'.$sEnvironment.'/';
|
||||
Setuputils::builddir($sCacheDir);
|
||||
Setuputils::tidydir($sCacheDir);
|
||||
SetupUtils::builddir($sCacheDir);
|
||||
SetupUtils::tidydir($sCacheDir);
|
||||
}
|
||||
|
||||
// Special case to patch a ugly patch in itop-config-mgmt
|
||||
@@ -548,7 +547,7 @@ class ApplicationInstaller
|
||||
|
||||
// Set an "Instance UUID" identifying this machine based on a file located in the data directory
|
||||
$sInstanceUUIDFile = APPROOT.'data/instance.txt';
|
||||
Setuputils::builddir(APPROOT.'data');
|
||||
SetupUtils::builddir(APPROOT.'data');
|
||||
if (!file_exists($sInstanceUUIDFile))
|
||||
{
|
||||
$sIntanceUUID = utils::CreateUUID('filesystem');
|
||||
@@ -690,7 +689,8 @@ class ApplicationInstaller
|
||||
// Syncho data sources were identified by the comment at the end
|
||||
// Unfortunately the comment is localized, so we have to search for all possible patterns
|
||||
$sCurrentLanguage = Dict::GetUserLanguage();
|
||||
foreach(Dict::GetLanguages() as $sLangCode => $aLang)
|
||||
$aSuffixes = array();
|
||||
foreach(array_keys(Dict::GetLanguages()) as $sLangCode)
|
||||
{
|
||||
Dict::SetUserLanguage($sLangCode);
|
||||
$sSuffix = CMDBSource::Quote('%'.Dict::S('Core:SyncDataExchangeComment'));
|
||||
@@ -966,7 +966,7 @@ class ApplicationInstaller
|
||||
SetupPage::log_info("ending data load session");
|
||||
}
|
||||
|
||||
protected static function DoCreateConfig($sMode, $sModulesDir, $sDBServer, $sDBUser, $sDBPwd, $sDBName, $sDBPrefix, $sUrl, $sLanguage, $aSelectedModules, $sTargetEnvironment, $bOldAddon, $sSourceDir, $sPreviousConfigFile, $sDataModelVersion, $sGraphvizPath)
|
||||
protected static function DoCreateConfig($sMode, $sModulesDir, $sDBServer, $sDBUser, $sDBPwd, $sDBName, $sDBPrefix, $sUrl, $sLanguage, $aSelectedModuleCodes, $aSelectedExtensionCodes, $sTargetEnvironment, $bOldAddon, $sSourceDir, $sPreviousConfigFile, $sDataModelVersion, $sGraphvizPath)
|
||||
{
|
||||
$aParamValues = array(
|
||||
'mode' => $sMode,
|
||||
@@ -979,7 +979,7 @@ class ApplicationInstaller
|
||||
'application_path' => $sUrl,
|
||||
'language' => $sLanguage,
|
||||
'graphviz_path' => $sGraphvizPath,
|
||||
'selected_modules' => implode(',', $aSelectedModules),
|
||||
'selected_modules' => implode(',', $aSelectedModuleCodes)
|
||||
);
|
||||
|
||||
$bPreserveModuleSettings = false;
|
||||
@@ -1024,8 +1024,7 @@ class ApplicationInstaller
|
||||
// Record which modules are installed...
|
||||
$oProductionEnv = new RunTimeEnvironment($sTargetEnvironment);
|
||||
$oProductionEnv->InitDataModel($oConfig, true); // load data model and connect to the database
|
||||
$aAvailableModules = $oProductionEnv->AnalyzeInstallation(MetaModel::GetConfig(), APPROOT.$sModulesDir);
|
||||
if (!$oProductionEnv->RecordInstallation($oConfig, $sDataModelVersion, $aSelectedModules, $sModulesDir))
|
||||
if (!$oProductionEnv->RecordInstallation($oConfig, $sDataModelVersion, $aSelectedModuleCodes, $aSelectedExtensionCodes, $sModulesDir))
|
||||
{
|
||||
throw new Exception("Failed to record the installation information");
|
||||
}
|
||||
|
||||
458
setup/extensionsmap.class.inc.php
Normal file
458
setup/extensionsmap.class.inc.php
Normal file
@@ -0,0 +1,458 @@
|
||||
<?php
|
||||
require_once(APPROOT.'/setup/parameters.class.inc.php');
|
||||
require_once(APPROOT.'/core/cmdbsource.class.inc.php');
|
||||
|
||||
/**
|
||||
* Basic helper class to describe an extension, with some characteristics and a list of modules
|
||||
*/
|
||||
class iTopExtension
|
||||
{
|
||||
const SOURCE_WIZARD = 'datamodels';
|
||||
const SOURCE_MANUAL = 'extensions';
|
||||
const SOURCE_REMOTE = 'data';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
public $sCode;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
public $sVersion;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
public $sInstalledVersion;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
public $sLabel;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
public $sDescription;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
public $sSource;
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
public $bMandatory;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
public $sMoreInfoUrl;
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
public $bMarkedAsChosen;
|
||||
|
||||
|
||||
/**
|
||||
* @var string[]
|
||||
*/
|
||||
public $aModules;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->sCode = '';
|
||||
$this->sLabel = '';
|
||||
$this->sDescription = '';
|
||||
$this->sSource = self::SOURCE_WIZARD;
|
||||
$this->bMandatory = false;
|
||||
$this->sMoreInfoUrl = '';
|
||||
$this->bMarkedAsChosen = false;
|
||||
$this->sVersion = ITOP_VERSION;
|
||||
$this->sInstalledVersion = '';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper class to discover all available extensions on a given iTop system
|
||||
*/
|
||||
class iTopExtensionsMap
|
||||
{
|
||||
/**
|
||||
* The list of all discovered extensions
|
||||
* @var iTopExtension[]
|
||||
*/
|
||||
protected $aExtensions;
|
||||
|
||||
public function __construct($sFromEnvironment = 'production')
|
||||
{
|
||||
$this->aExtensions = array();
|
||||
$this->ScanDisk($sFromEnvironment);
|
||||
}
|
||||
|
||||
/**
|
||||
* Populate the list of available (pseudo)extensions by scanning the disk
|
||||
* where the iTop files are located
|
||||
* @param string $sEnvironment
|
||||
* @return void
|
||||
*/
|
||||
protected function ScanDisk($sEnvironment)
|
||||
{
|
||||
if (!$this->ReadInstallationWizard(APPROOT.'/datamodels/2.x') && !$this->ReadInstallationWizard(APPROOT.'/datamodels/2.x'))
|
||||
{
|
||||
if(!$this->ReadDir(APPROOT.'/datamodels/2.x', iTopExtension::SOURCE_WIZARD)) $this->ReadDir(APPROOT.'/datamodels/1.x', iTopExtension::SOURCE_WIZARD);
|
||||
}
|
||||
$this->ReadDir(APPROOT.'/extensions', iTopExtension::SOURCE_MANUAL);
|
||||
$this->ReadDir(APPROOT.'/data/'.$sEnvironment.'-modules', iTopExtension::SOURCE_REMOTE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Read the information contained in the "installation.xml" file in the given directory
|
||||
* and create pseudo extensions from the list of choices described in this file
|
||||
* @param string $sDir
|
||||
* @return boolean Return true if the installation.xml file exists and is readable
|
||||
*/
|
||||
protected function ReadInstallationWizard($sDir)
|
||||
{
|
||||
if (!is_readable($sDir.'/installation.xml')) return false;
|
||||
|
||||
$oXml = new XMLParameters($sDir.'/installation.xml');
|
||||
foreach($oXml->Get('steps') as $aStepInfo)
|
||||
{
|
||||
if (array_key_exists('options', $aStepInfo))
|
||||
{
|
||||
$this->ProcessWizardChoices($aStepInfo['options']);
|
||||
}
|
||||
if (array_key_exists('alternatives', $aStepInfo))
|
||||
{
|
||||
$this->ProcessWizardChoices($aStepInfo['alternatives']);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper to process a "choice" array read from the installation.xml file
|
||||
* @param array $aChoices
|
||||
* @return void
|
||||
*/
|
||||
protected function ProcessWizardChoices($aChoices)
|
||||
{
|
||||
foreach($aChoices as $aChoiceInfo)
|
||||
{
|
||||
if (array_key_exists('extension_code', $aChoiceInfo))
|
||||
{
|
||||
$oExtension = new iTopExtension();
|
||||
$oExtension->sCode = $aChoiceInfo['extension_code'];
|
||||
$oExtension->sLabel = $aChoiceInfo['title'];
|
||||
if (array_key_exists('modules', $aChoiceInfo))
|
||||
{
|
||||
// Some wizard choices are not associated with any module
|
||||
$oExtension->aModules = $aChoiceInfo['modules'];
|
||||
}
|
||||
if (array_key_exists('sub_options', $aChoiceInfo))
|
||||
{
|
||||
if (array_key_exists('options', $aChoiceInfo['sub_options']))
|
||||
{
|
||||
$this->ProcessWizardChoices($aChoiceInfo['sub_options']['options']);
|
||||
}
|
||||
if (array_key_exists('alternatives', $aChoiceInfo['sub_options']))
|
||||
{
|
||||
$this->ProcessWizardChoices($aChoiceInfo['sub_options']['alternatives']);
|
||||
}
|
||||
}
|
||||
$this->AddExtension($oExtension);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add an extension to the list of existing extensions, taking care of removing duplicates
|
||||
* (only the latest/greatest version is kept)
|
||||
* @param iTopExtension $oNewExtension
|
||||
* @return void
|
||||
*/
|
||||
protected function AddExtension(iTopExtension $oNewExtension)
|
||||
{
|
||||
foreach($this->aExtensions as $key => $oExtension)
|
||||
{
|
||||
if ($oExtension->sCode == $oNewExtension->sCode)
|
||||
{
|
||||
if (version_compare($oNewExtension->sVersion, $oExtension->sVersion, '>'))
|
||||
{
|
||||
// This "new" extension is "newer" than the previous one, let's replace the previous one
|
||||
unset($this->aExtensions[$key]);
|
||||
$this->aExtensions[$oNewExtension->sCode.'/'.$oNewExtension->sVersion] = $oNewExtension;
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
// This "new" extension is not "newer" than the previous one, let's ignore it
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Finally it's not a duplicate, let's add it to the list
|
||||
$this->aExtensions[$oNewExtension->sCode.'/'.$oNewExtension->sVersion] = $oNewExtension;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read (recursively) a directory to find if it contains extensions (or modules)
|
||||
* @param string $sSearchDir The directory to scan
|
||||
* @param string $sSource The 'source' value for the extensions found in this directory
|
||||
* @param string|null $sParentExtensionId Not null if the directory is under a declared extension
|
||||
* @return boolean
|
||||
*/
|
||||
protected function ReadDir($sSearchDir, $sSource, $sParentExtensionId = null)
|
||||
{
|
||||
if (!is_readable($sSearchDir)) return false;
|
||||
$hDir = opendir($sSearchDir);
|
||||
if ($hDir !== false)
|
||||
{
|
||||
$sExtensionId = null;
|
||||
$aSubDirectories = array();
|
||||
|
||||
// First check if there is an extension.xml file in this directory
|
||||
if (is_readable($sSearchDir.'/extension.xml'))
|
||||
{
|
||||
$oXml = new XMLParameters($sSearchDir.'/extension.xml');
|
||||
$oExtension = new iTopExtension();
|
||||
$oExtension->sCode = $oXml->Get('extension_code');
|
||||
$oExtension->sLabel = $oXml->Get('label');
|
||||
$oExtension->sDescription = $oXml->Get('description');
|
||||
$oExtension->sVersion = $oXml->Get('version');
|
||||
$oExtension->bMandatory = ($oXml->Get('mandatory') == 'true');
|
||||
$oExtension->sMoreInfoUrl = $oXml->Get('more_info_url');
|
||||
$oExtension->sVersion = $oXml->Get('version');
|
||||
$oExtension->sSource = $sSource;
|
||||
|
||||
$sParentExtensionId = $sExtensionId = $oExtension->sCode.'/'.$oExtension->sVersion;
|
||||
$this->AddExtension($oExtension);
|
||||
}
|
||||
// Then scan the other files and subdirectories
|
||||
while (($sFile = readdir($hDir)) !== false)
|
||||
{
|
||||
if (($sFile !== '.') && ($sFile !== '..'))
|
||||
{
|
||||
$aMatches = array();
|
||||
if (is_dir($sSearchDir.'/'.$sFile))
|
||||
{
|
||||
// Recurse after parsing all the regular files
|
||||
$aSubDirectories[] = $sSearchDir.'/'.$sFile;
|
||||
}
|
||||
else if (preg_match('/^module\.(.*).php$/i', $sFile, $aMatches))
|
||||
{
|
||||
// Found a module
|
||||
$aModuleInfo = $this->GetModuleInfo($sSearchDir.'/'.$sFile);
|
||||
// If we are not already inside a formal extension, then the module itself is considered
|
||||
// as an extension, otherwise, the module is just added to the list of modules belonging
|
||||
// to this extension
|
||||
$sModuleId = $aModuleInfo[1];
|
||||
list($sModuleName, $sModuleVersion) = ModuleDiscovery::GetModuleName($sModuleId);
|
||||
|
||||
if ($sParentExtensionId !== null)
|
||||
{
|
||||
// Already inside an extension, let's add this module the list of modules belonging to this extension
|
||||
$this->aExtensions[$sParentExtensionId]->aModules[] = $sModuleName;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Not already inside an folder containing an 'extension.xml' file
|
||||
|
||||
// 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;
|
||||
|
||||
// Let's create a "fake" extension from this module (containing just this module) for backwards compatibility
|
||||
$sExtensionId = $sModuleId;
|
||||
|
||||
$oExtension = new iTopExtension();
|
||||
$oExtension->sCode = $sModuleName;
|
||||
$oExtension->sLabel = $aModuleInfo[2]['label'];
|
||||
$oExtension->sDescription = '';
|
||||
$oExtension->sVersion = $sModuleVersion;
|
||||
$oExtension->sSource = $sSource;
|
||||
$oExtension->bMandatory = $aModuleInfo[2]['mandatory'];
|
||||
$oExtension->sMoreInfoUrl = $aModuleInfo[2]['doc.more_information'];
|
||||
$oExtension->aModules = array($sModuleName);
|
||||
|
||||
$this->AddExtension($oExtension);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
closedir($hDir);
|
||||
foreach($aSubDirectories as $sDir)
|
||||
{
|
||||
// Recurse inside the subdirectories
|
||||
$this->ReadDir($sDir, $sSource, $sExtensionId);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read the information from a module file (module.xxx.php)
|
||||
* Closely inspired (almost copied/pasted !!) from ModuleDiscovery::ListModuleFiles
|
||||
* @param string $sModuleFile
|
||||
* @return array
|
||||
*/
|
||||
protected function GetModuleInfo($sModuleFile)
|
||||
{
|
||||
static $iDummyClassIndex = 0;
|
||||
|
||||
$aModuleInfo = array(); // will be filled by the "eval" line below...
|
||||
try
|
||||
{
|
||||
$aMatches = array();
|
||||
$sModuleFileContents = file_get_contents($sModuleFile);
|
||||
$sModuleFileContents = str_replace(array('<?php', '?>'), '', $sModuleFileContents);
|
||||
$sModuleFileContents = str_replace('__FILE__', "'".addslashes($sModuleFile)."'", $sModuleFileContents);
|
||||
preg_match_all('/class ([A-Za-z0-9_]+) extends ([A-Za-z0-9_]+)/', $sModuleFileContents, $aMatches);
|
||||
//print_r($aMatches);
|
||||
$idx = 0;
|
||||
foreach($aMatches[1] as $sClassName)
|
||||
{
|
||||
if (class_exists($sClassName))
|
||||
{
|
||||
// rename any class declaration inside the code to prevent a "duplicate class" declaration
|
||||
// and change its parent class as well so that nobody will find it and try to execute it
|
||||
$sModuleFileContents = str_replace($sClassName.' extends '.$aMatches[2][$idx], $sClassName.'_'.($iDummyClassIndex++).' extends DummyHandler', $sModuleFileContents);
|
||||
}
|
||||
$idx++;
|
||||
}
|
||||
// Replace the main function call by an assignment to a variable, as an array...
|
||||
$sModuleFileContents = str_replace(array('SetupWebPage::AddModule', 'ModuleDiscovery::AddModule'), '$aModuleInfo = array', $sModuleFileContents);
|
||||
|
||||
eval($sModuleFileContents); // Assigns $aModuleInfo
|
||||
|
||||
if (count($aModuleInfo) === 0)
|
||||
{
|
||||
SetupPage::log_warning("Eval of $sModuleFile did not return the expected information...");
|
||||
}
|
||||
}
|
||||
catch(Exception $e)
|
||||
{
|
||||
// Continue...
|
||||
SetupPage::log_warning("Eval of $sModuleFile caused an exception: ".$e->getMessage());
|
||||
}
|
||||
return $aModuleInfo;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all available extensions
|
||||
* @return iTopExtension[]
|
||||
*/
|
||||
public function GetAllExtensions()
|
||||
{
|
||||
return $this->aExtensions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Mark the given extension as chosen
|
||||
* @param string $sExtensionCode The code of the extension (code without verison number)
|
||||
* @param bool $bMark The value to set for the bmarkAschosen flag
|
||||
* @return void
|
||||
*/
|
||||
public function MarkAsChosen($sExtensionCode, $bMark = true)
|
||||
{
|
||||
foreach($this->aExtensions as $oExtension)
|
||||
{
|
||||
if ($oExtension->sCode == $sExtensionCode)
|
||||
{
|
||||
$oExtension->bMarkedAsChosen = $bMark;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tells if a given extension(code) is marked as chosen
|
||||
* @param string $sExtensionCode
|
||||
* @return boolean
|
||||
*/
|
||||
public function IsMarkedAsChosen($sExtensionCode)
|
||||
{
|
||||
foreach($this->aExtensions as $oExtension)
|
||||
{
|
||||
if ($oExtension->sCode == $sExtensionCode)
|
||||
{
|
||||
return $oExtension->bMarkedAsChosen;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the 'installed_version' of the given extension(code)
|
||||
* @param string $sExtensionCode
|
||||
* @param string $sInstalledVersion
|
||||
* @return void
|
||||
*/
|
||||
protected function SetInstalledVersion($sExtensionCode, $sInstalledVersion)
|
||||
{
|
||||
foreach($this->aExtensions as $oExtension)
|
||||
{
|
||||
if ($oExtension->sCode == $sExtensionCode)
|
||||
{
|
||||
$oExtension->sInstalledVersion = $sInstalledVersion;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the list of the "chosen" extensions
|
||||
* @return iTopExtension[]
|
||||
*/
|
||||
public function GetChoices()
|
||||
{
|
||||
$aResult = array();
|
||||
foreach($this->aExtensions as $oExtension)
|
||||
{
|
||||
if ($oExtension->bMarkedAsChosen)
|
||||
{
|
||||
$aResult[] = $oExtension;
|
||||
}
|
||||
}
|
||||
return $aResult;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load the choices (i.e. MarkedAsChosen) from the database defined in the supplied Config
|
||||
* @param Config $oConfig
|
||||
* @return bool
|
||||
*/
|
||||
public function LoadChoicesFromDatabase(Config $oConfig)
|
||||
{
|
||||
$aInstalledExtensions = array();
|
||||
try
|
||||
{
|
||||
if (CMDBSource::DBName() === null)
|
||||
{
|
||||
CMDBSource::Init($oConfig->GetDBHost(), $oConfig->GetDBUser(), $oConfig->GetDBPwd(), $oConfig->GetDBName());
|
||||
CMDBSource::SetCharacterSet($oConfig->GetDBCharacterSet(), $oConfig->GetDBCollation());
|
||||
}
|
||||
$sLatestInstallationDate = CMDBSource::QueryToScalar("SELECT max(installed) FROM ".$oConfig->GetDBSubname()."priv_extension_install");
|
||||
$aInstalledExtensions = CMDBSource::QueryToArray("SELECT * FROM ".$oConfig->GetDBSubname()."priv_extension_install WHERE installed = '".$sLatestInstallationDate."'");
|
||||
}
|
||||
catch (MySQLException $e)
|
||||
{
|
||||
// No database or erroneous information
|
||||
$aInstalledExtensions = array();
|
||||
return false;
|
||||
}
|
||||
|
||||
foreach($aInstalledExtensions as $aDBInfo)
|
||||
{
|
||||
$this->MarkAsChosen($aDBInfo['code']);
|
||||
$this->SetInstalledVersion($aDBInfo['code'], $aDBInfo['version']);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -220,13 +220,19 @@ class MFModule
|
||||
|
||||
public function SetFilesToInclude($aFiles, $sCategory)
|
||||
{
|
||||
// Now ModuleDiscovery provides us directly with relative paths... nothing to do
|
||||
$this->aFilesToInclude[$sCategory] = $aFiles;
|
||||
|
||||
/*
|
||||
$sDir = basename($this->sRootDir);
|
||||
$iLen = strlen($sDir.'/');
|
||||
foreach($aFiles as $sFile)
|
||||
{
|
||||
$iPos = strpos($sFile, $sDir.'/');
|
||||
$this->aFilesToInclude[$sCategory][] = substr($sFile, $iPos+$iLen);
|
||||
//$this->aFilesToInclude[$sCategory][] = substr($sFile, $iPos+$iLen);
|
||||
$this->aFilesToInclude[$sCategory][] = $sFile;
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
public function GetFilesToInclude($sCategory)
|
||||
|
||||
@@ -67,7 +67,7 @@ class ModuleDiscovery
|
||||
// Assume 1.0.2
|
||||
$aArgs['itop_version'] = '1.0.2';
|
||||
}
|
||||
foreach (self::$m_aModuleArgs as $sArgName => $sArgDesc)
|
||||
foreach (array_keys(self::$m_aModuleArgs) as $sArgName)
|
||||
{
|
||||
if (!array_key_exists($sArgName, $aArgs))
|
||||
{
|
||||
@@ -110,6 +110,8 @@ class ModuleDiscovery
|
||||
|
||||
self::$m_aModules[$sId] = $aArgs;
|
||||
|
||||
// Now keep the relative paths, as provided
|
||||
/*
|
||||
foreach(self::$m_aFilesList as $sAttribute)
|
||||
{
|
||||
if (isset(self::$m_aModules[$sId][$sAttribute]))
|
||||
@@ -122,7 +124,9 @@ class ModuleDiscovery
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
// Populate automatically the list of dictionary files
|
||||
$aMatches = array();
|
||||
if(preg_match('|^([^/]+)|', $sId, $aMatches)) // ModuleName = everything before the first forward slash
|
||||
{
|
||||
$sModuleName = $aMatches[1];
|
||||
@@ -240,6 +244,7 @@ class ModuleDiscovery
|
||||
// Separate the module names from their version for an easier comparison later
|
||||
foreach($aOrderedModules as $sModuleId)
|
||||
{
|
||||
$aMatches = array();
|
||||
if (preg_match('|^([^/]+)/(.*)$|', $sModuleId, $aMatches))
|
||||
{
|
||||
$aModuleVersions[$aMatches[1]] = $aMatches[2];
|
||||
@@ -260,6 +265,7 @@ class ModuleDiscovery
|
||||
{
|
||||
// $sModuleId in the dependency string is made of a <name>/<optional_operator><version>
|
||||
// where the operator is < <= = > >= (by default >=)
|
||||
$aModuleMatches = array();
|
||||
if(preg_match('|^([^/]+)/(<?>?=?)([^><=]+)$|', $sModuleId, $aModuleMatches))
|
||||
{
|
||||
$sModuleName = $aModuleMatches[1];
|
||||
@@ -295,7 +301,7 @@ class ModuleDiscovery
|
||||
}
|
||||
}
|
||||
$bMissingPrerequisite = false;
|
||||
foreach ($aPotentialPrerequisites as $sModuleName => $void)
|
||||
foreach (array_keys($aPotentialPrerequisites) as $sModuleName)
|
||||
{
|
||||
if (array_key_exists($sModuleName, $aSelectedModules))
|
||||
{
|
||||
@@ -378,6 +384,7 @@ class ModuleDiscovery
|
||||
*/
|
||||
public static function GetModuleName($sModuleId)
|
||||
{
|
||||
$aMatches = array();
|
||||
if (preg_match('!^(.*)/(.*)$!', $sModuleId, $aMatches))
|
||||
{
|
||||
$sName = $aMatches[1];
|
||||
@@ -394,12 +401,12 @@ class ModuleDiscovery
|
||||
/**
|
||||
* Helper function to browse a directory and get the modules
|
||||
* @param $sRelDir string Directory to start from
|
||||
* @param $sRootDir string The root directory path
|
||||
* @return array(name, version)
|
||||
*/
|
||||
protected static function ListModuleFiles($sRelDir, $sRootDir)
|
||||
{
|
||||
static $iDummyClassIndex = 0;
|
||||
static $aDefinedClasses = array();
|
||||
$sDirectory = $sRootDir.'/'.$sRelDir;
|
||||
|
||||
if ($hDir = opendir($sDirectory))
|
||||
@@ -504,3 +511,4 @@ class SetupWebPage extends ModuleDiscovery
|
||||
*/
|
||||
class DummyHandler {
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<?php
|
||||
// Copyright (C) 2010-2012 Combodo SARL
|
||||
// Copyright (C) 2010-2017 Combodo SARL
|
||||
//
|
||||
// This file is part of iTop.
|
||||
//
|
||||
@@ -18,10 +18,10 @@
|
||||
|
||||
|
||||
/**
|
||||
* Persistent class Event and derived
|
||||
* Persistent class ModuleInstallation to record the installed modules
|
||||
* Log of module installations
|
||||
*
|
||||
* @copyright Copyright (C) 2010-2012 Combodo SARL
|
||||
* @copyright Copyright (C) 2010-2017 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
@@ -59,4 +59,44 @@ class ModuleInstallation extends cmdbAbstractObject
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
/**
|
||||
* Persistent class ExtensionInstallation to record the installed extensions
|
||||
* Log of extensions installations
|
||||
*
|
||||
* @copyright Copyright (C) 2017 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
class ExtensionInstallation extends cmdbAbstractObject
|
||||
{
|
||||
public static function Init()
|
||||
{
|
||||
$aParams = array
|
||||
(
|
||||
"category" => "core,view_in_gui",
|
||||
"key_type" => "autoincrement",
|
||||
"name_attcode" => "",
|
||||
"state_attcode" => "",
|
||||
"reconc_keys" => array(),
|
||||
"db_table" => "priv_extension_install",
|
||||
"db_key_field" => "id",
|
||||
"db_finalclass_field" => "",
|
||||
"display_template" => "",
|
||||
);
|
||||
MetaModel::Init_Params($aParams);
|
||||
//MetaModel::Init_InheritAttributes();
|
||||
MetaModel::Init_AddAttribute(new AttributeString("code", array("allowed_values"=>null, "sql"=>"code", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeString("label", array("allowed_values"=>null, "sql"=>"label", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeString("version", array("allowed_values"=>null, "sql"=>"version", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeString("source", array("allowed_values"=>null, "sql"=>"source", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeDateTime("installed", array("allowed_values"=>null, "sql"=>"installed", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array())));
|
||||
|
||||
|
||||
// Display lists
|
||||
MetaModel::Init_SetZListItems('details', array('code', 'label', 'version', 'installed', 'source')); // Attributes to be displayed for the complete details
|
||||
MetaModel::Init_SetZListItems('list', array('code', 'label', 'version', 'installed', 'source')); // Attributes to be displayed for a list
|
||||
MetaModel::Init_SetZListItems('standard_search', array('code', 'label', 'version', 'installed', 'source')); // Attributes to be displayed in the search form
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
require_once(APPROOT."setup/modulediscovery.class.inc.php");
|
||||
require_once(APPROOT.'setup/modelfactory.class.inc.php');
|
||||
require_once(APPROOT.'setup/compiler.class.inc.php');
|
||||
require_once(APPROOT.'setup/extensionsmap.class.inc.php');
|
||||
require_once(APPROOT.'core/metamodel.class.php');
|
||||
|
||||
define ('MODULE_ACTION_OPTIONAL', 1);
|
||||
@@ -41,9 +42,16 @@ class RunTimeEnvironment
|
||||
{
|
||||
protected $sTargetEnv;
|
||||
|
||||
/**
|
||||
* Extensions map of the source environment
|
||||
* @var iTopExtensionsMap
|
||||
*/
|
||||
protected $oExtensionsMap;
|
||||
|
||||
public function __construct($sEnvironment = 'production')
|
||||
{
|
||||
$this->sTargetEnv = $sEnvironment;
|
||||
$this->oExtensionsMap = null;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -104,6 +112,11 @@ class RunTimeEnvironment
|
||||
}
|
||||
|
||||
MetaModel::Startup($oConfig, $bModelOnly, $bUseCache, false /* $bTraceSourceFiles */, $this->sTargetEnv);
|
||||
|
||||
if ($this->oExtensionsMap === null)
|
||||
{
|
||||
$this->oExtensionsMap = new iTopExtensionsMap($this->sTargetEnv);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -333,12 +346,27 @@ class RunTimeEnvironment
|
||||
|
||||
$aRet = array();
|
||||
|
||||
// Determine the installed modules
|
||||
// Determine the installed modules and extensions
|
||||
//
|
||||
$oSourceConfig = new Config(APPCONF.$sSourceEnv.'/'.ITOP_CONFIG_FILE);
|
||||
$oSourceEnv = new RunTimeEnvironment($sSourceEnv);
|
||||
$aAvailableModules = $oSourceEnv->AnalyzeInstallation($oSourceConfig, $aDirsToCompile);
|
||||
|
||||
// Actually read the modules available for the target environment,
|
||||
// but get the selection from the source environment and finally
|
||||
// mark as (automatically) chosen alll the "remote" modules present in the
|
||||
// target environment (data/<target-env>-modules)
|
||||
// The actual choices will be recorded by RecordInstallation below
|
||||
$this->oExtensionsMap = new iTopExtensionsMap($this->sTargetEnv);
|
||||
$this->oExtensionsMap->LoadChoicesFromDatabase($oSourceConfig);
|
||||
foreach($this->oExtensionsMap->GetAllExtensions() as $oExtension)
|
||||
{
|
||||
if($oExtension->sSource == iTopExtension::SOURCE_REMOTE)
|
||||
{
|
||||
$this->oExtensionsMap->MarkAsChosen($oExtension->sCode);
|
||||
}
|
||||
}
|
||||
|
||||
// Do load the required modules
|
||||
//
|
||||
$oDictModule = new MFDictModule('dictionaries', 'iTop Dictionaries', APPROOT.'dictionaries');
|
||||
@@ -359,7 +387,7 @@ class RunTimeEnvironment
|
||||
}
|
||||
|
||||
$aModules = $oFactory->FindModules();
|
||||
foreach($aModules as $foo => $oModule)
|
||||
foreach($aModules as $oModule)
|
||||
{
|
||||
$sModule = $oModule->GetName();
|
||||
$sModuleRootDir = $oModule->GetRootDir();
|
||||
@@ -378,7 +406,7 @@ class RunTimeEnvironment
|
||||
{
|
||||
// Loop while new modules are added...
|
||||
$bModuleAdded = false;
|
||||
foreach($aModules as $foo => $oModule)
|
||||
foreach($aModules as $oModule)
|
||||
{
|
||||
if (!array_key_exists($oModule->GetName(), $aRet) && $oModule->IsAutoSelect())
|
||||
{
|
||||
@@ -437,7 +465,6 @@ class RunTimeEnvironment
|
||||
// in case there is no delta the operation will be done after the end of the loop
|
||||
$oFactory->SaveToFile(APPROOT.'data/datamodel-'.$this->sTargetEnv.'.xml');
|
||||
}
|
||||
$sModule = $oModule->GetName();
|
||||
$oFactory->LoadModule($oModule);
|
||||
if ($oFactory->HasLoadErrors())
|
||||
{
|
||||
@@ -475,8 +502,8 @@ class RunTimeEnvironment
|
||||
$oMFCompiler->Compile($sTargetDir, null, $bUseSymLinks);
|
||||
|
||||
$sCacheDir = APPROOT.'data/cache-'.$this->sTargetEnv;
|
||||
Setuputils::builddir($sCacheDir);
|
||||
Setuputils::tidydir($sCacheDir);
|
||||
SetupUtils::builddir($sCacheDir);
|
||||
SetupUtils::tidydir($sCacheDir);
|
||||
|
||||
require_once(APPROOT.'/core/dict.class.inc.php');
|
||||
MetaModel::ResetCache(md5(APPROOT).'-'.$this->sTargetEnv);
|
||||
@@ -627,12 +654,19 @@ class RunTimeEnvironment
|
||||
$oConfig->Set('access_mode', $iPrevAccessMode);
|
||||
}
|
||||
|
||||
public function RecordInstallation(Config $oConfig, $sDataModelVersion, $aSelectedModules, $sModulesRelativePath, $sShortComment = null)
|
||||
public function RecordInstallation(Config $oConfig, $sDataModelVersion, $aSelectedModuleCodes, $aSelectedExtensionCodes, $sModulesRelativePath, $sShortComment = null)
|
||||
{
|
||||
// Have it work fine even if the DB has been set in read-only mode for the users
|
||||
$iPrevAccessMode = $oConfig->Get('access_mode');
|
||||
$oConfig->Set('access_mode', ACCESS_FULL);
|
||||
|
||||
if (CMDBSource::DBName() == '')
|
||||
{
|
||||
// In case this has not yet been done
|
||||
CMDBSource::Init($oConfig->GetDBHost(), $oConfig->GetDBUser(), $oConfig->GetDBPwd(), $oConfig->GetDBName());
|
||||
CMDBSource::SetCharacterSet($oConfig->GetDBCharacterSet(), $oConfig->GetDBCollation());
|
||||
}
|
||||
|
||||
if ($sShortComment === null)
|
||||
{
|
||||
$sShortComment = 'Done by the setup program';
|
||||
@@ -662,10 +696,11 @@ class RunTimeEnvironment
|
||||
$iMainItopRecord = $oInstallRec->DBInsertNoReload();
|
||||
|
||||
|
||||
// Record installed modules
|
||||
// Record installed modules and extensions
|
||||
//
|
||||
$aAvailableExtensions = array();
|
||||
$aAvailableModules = $this->AnalyzeInstallation($oConfig, APPROOT.$sModulesRelativePath);
|
||||
foreach($aSelectedModules as $sModuleId)
|
||||
foreach($aSelectedModuleCodes as $sModuleId)
|
||||
{
|
||||
$aModuleData = $aAvailableModules[$sModuleId];
|
||||
$sName = $sModuleId;
|
||||
@@ -703,6 +738,30 @@ class RunTimeEnvironment
|
||||
$oInstallRec->DBInsertNoReload();
|
||||
}
|
||||
|
||||
if ($this->oExtensionsMap)
|
||||
{
|
||||
// Mark as chosen the selected extensions code passed to us
|
||||
// Note: some other extensions may already be marked as chosen
|
||||
foreach($this->oExtensionsMap->GetAllExtensions() as $oExtension)
|
||||
{
|
||||
if (in_array($oExtension->sCode, $aSelectedExtensionCodes))
|
||||
{
|
||||
$this->oExtensionsMap->MarkAsChosen($oExtension->sCode);
|
||||
}
|
||||
}
|
||||
|
||||
foreach($this->oExtensionsMap->GetChoices() as $oExtension)
|
||||
{
|
||||
$oInstallRec = new ExtensionInstallation();
|
||||
$oInstallRec->Set('code', $oExtension->sCode);
|
||||
$oInstallRec->Set('label', $oExtension->sLabel);
|
||||
$oInstallRec->Set('version', $oExtension->sVersion);
|
||||
$oInstallRec->Set('source', $oExtension->sSource);
|
||||
$oInstallRec->Set('installed', $iInstallationTime);
|
||||
$oInstallRec->DBInsertNoReload();
|
||||
}
|
||||
}
|
||||
|
||||
// Restore the previous access mode
|
||||
$oConfig->Set('access_mode', $iPrevAccessMode);
|
||||
|
||||
|
||||
@@ -27,6 +27,7 @@ require_once(APPROOT.'setup/parameters.class.inc.php');
|
||||
require_once(APPROOT.'setup/applicationinstaller.class.inc.php');
|
||||
require_once(APPROOT.'setup/parameters.class.inc.php');
|
||||
require_once(APPROOT.'core/mutex.class.inc.php');
|
||||
require_once(APPROOT.'setup/extensionsmap.class.inc.php');
|
||||
|
||||
/**
|
||||
* First step of the iTop Installation Wizard: Welcome screen
|
||||
@@ -1173,6 +1174,42 @@ class WizStepModulesChoice extends WizardStep
|
||||
{
|
||||
static protected $SEP = '_';
|
||||
protected $bUpgrade = false;
|
||||
|
||||
/**
|
||||
*
|
||||
* @var iTopExtensionsMap
|
||||
*/
|
||||
protected $oExtensionsMap;
|
||||
|
||||
/**
|
||||
* Whether we were able to load the choices from the database or not
|
||||
* @var bool
|
||||
*/
|
||||
protected $bChoicesFromDatabase;
|
||||
|
||||
public function __construct(WizardController $oWizard, $sCurrentState)
|
||||
{
|
||||
parent::__construct($oWizard, $sCurrentState);
|
||||
$this->bChoicesFromDatabase = false;
|
||||
$this->oExtensionsMap = new iTopExtensionsMap();
|
||||
$sPreviousSourceDir = $this->oWizard->GetParameter('previous_version_dir', '');
|
||||
$sConfigPath = null;
|
||||
if (($sPreviousSourceDir !== '') && is_readable($sPreviousSourceDir.'/conf/production/config-itop.php'))
|
||||
{
|
||||
$sConfigPath = $sPreviousSourceDir.'/conf/production/config-itop.php';
|
||||
}
|
||||
else if (is_readable(utils::GetConfigFilePath('production')))
|
||||
{
|
||||
$sConfigPath = utils::GetConfigFilePath('production');
|
||||
}
|
||||
if ($sConfigPath !== null)
|
||||
{
|
||||
$oConfig = new Config($sConfigPath);
|
||||
$this->bChoicesFromDatabase = $this->oExtensionsMap->LoadChoicesFromDatabase($oConfig);
|
||||
}
|
||||
//echo '<div style="display:block;position:fixed;width:100px;height:20px;top:0;left:0;font-size:10pt;">Default: '.($this->bChoicesFromDatabase ? 'DB' : 'Guess').'</div>';
|
||||
}
|
||||
|
||||
public function GetTitle()
|
||||
{
|
||||
$aStepInfo = $this->GetStepInfo();
|
||||
@@ -1210,11 +1247,12 @@ class WizStepModulesChoice extends WizardStep
|
||||
{
|
||||
// Exiting this step of the wizard, let's convert the selection into a list of modules
|
||||
$aModules = array();
|
||||
$aExtensions = array();
|
||||
$sDisplayChoices = '<ul>';
|
||||
for($i = 0; $i <= $index; $i++)
|
||||
{
|
||||
$aStepInfo = $this->GetStepInfo($i);
|
||||
$sDisplayChoices .= $this->GetSelectedModules($aStepInfo, $aSelectedChoices[$i], $aModules);
|
||||
$sDisplayChoices .= $this->GetSelectedModules($aStepInfo, $aSelectedChoices[$i], $aModules, '', '', $aExtensions);
|
||||
}
|
||||
$sDisplayChoices .= '</ul>';
|
||||
if (class_exists('CreateITILProfilesInstaller'))
|
||||
@@ -1222,6 +1260,7 @@ class WizStepModulesChoice extends WizardStep
|
||||
$this->oWizard->SetParameter('old_addon', true);
|
||||
}
|
||||
$this->oWizard->SetParameter('selected_modules', json_encode(array_keys($aModules)));
|
||||
$this->oWizard->SetParameter('selected_extensions', json_encode($aExtensions));
|
||||
$this->oWizard->SetParameter('display_choices', $sDisplayChoices);
|
||||
return array('class' => 'WizStepSummary', 'state' => '');
|
||||
}
|
||||
@@ -1277,7 +1316,7 @@ class WizStepModulesChoice extends WizardStep
|
||||
// Build the default choices
|
||||
$aDefaults = array();
|
||||
$aModules = SetupUtils::AnalyzeInstallation($this->oWizard);
|
||||
$this->GetDefaults($aStepInfo, $aDefaults, $aModules);
|
||||
$aDefaults = $this->GetDefaults($aStepInfo, $aModules);
|
||||
//echo "<pre>aStepInfo:\n ".print_r($aStepInfo, true)."</pre>";
|
||||
//echo "<pre>aDefaults:\n ".print_r($aDefaults, true)."</pre>";
|
||||
|
||||
@@ -1352,7 +1391,81 @@ EOF
|
||||
);
|
||||
}
|
||||
|
||||
protected function GetDefaults($aInfo, &$aDefaults, $aModules, $sParentId = '')
|
||||
protected function GetDefaults($aInfo, $aModules, $sParentId = '')
|
||||
{
|
||||
$aDefaults = array();
|
||||
if (!$this->bChoicesFromDatabase)
|
||||
{
|
||||
$this->GuessDefaultsFromModules($aInfo, $aDefaults, $aModules, $sParentId);
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->GetDefaultsFromDatabase($aInfo, $aDefaults, $sParentId);
|
||||
}
|
||||
return $aDefaults;
|
||||
}
|
||||
|
||||
protected function GetDefaultsFromDatabase($aInfo, &$aDefaults, $sParentId)
|
||||
{
|
||||
$aOptions = isset($aInfo['options']) ? $aInfo['options'] : array();
|
||||
foreach($aOptions as $index => $aChoice)
|
||||
{
|
||||
$sChoiceId = $sParentId.self::$SEP.$index;
|
||||
if ($this->bUpgrade)
|
||||
{
|
||||
if ($this->oExtensionsMap->IsMarkedAsChosen($aChoice['extension_code']))
|
||||
{
|
||||
$aDefaults[$sChoiceId] = $sChoiceId;
|
||||
}
|
||||
}
|
||||
else if (isset($aChoice['default']) && $aChoice['default'])
|
||||
{
|
||||
$aDefaults[$sChoiceId] = $sChoiceId;
|
||||
}
|
||||
// Recurse for sub_options (if any)
|
||||
if (isset($aChoice['sub_options']))
|
||||
{
|
||||
$this->GetDefaultsFromDatabase($aChoice['sub_options'], $aDefaults, $sChoiceId);
|
||||
}
|
||||
}
|
||||
|
||||
$aAlternatives = isset($aInfo['alternatives']) ? $aInfo['alternatives'] : array();
|
||||
$sChoiceName = null;
|
||||
foreach($aAlternatives as $index => $aChoice)
|
||||
{
|
||||
$sChoiceId = $sParentId.self::$SEP.$index;
|
||||
if ($sChoiceName == null)
|
||||
{
|
||||
$sChoiceName = $sChoiceId; // All radios share the same name
|
||||
}
|
||||
if ($this->bUpgrade)
|
||||
{
|
||||
if ($this->oExtensionsMap->IsMarkedAsChosen($aChoice['extension_code']))
|
||||
{
|
||||
$aDefaults[$sChoiceName] = $sChoiceId;
|
||||
}
|
||||
}
|
||||
else if (isset($aChoice['default']) && $aChoice['default'])
|
||||
{
|
||||
$aDefaults[$sChoiceName] = $sChoiceId;
|
||||
}
|
||||
// Recurse for sub_options (if any)
|
||||
if (isset($aChoice['sub_options']))
|
||||
{
|
||||
$this->GetDefaultsFromDatabase($aChoice['sub_options'], $aDefaults, $sChoiceId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Try to guess the user choices based on the current list of installed modules...
|
||||
* @param array $aInfo
|
||||
* @param array $aDefaults
|
||||
* @param array $aModules
|
||||
* @param string $sParentId
|
||||
* @return array
|
||||
*/
|
||||
protected function GuessDefaultsFromModules($aInfo, &$aDefaults, $aModules, $sParentId = '')
|
||||
{
|
||||
$aRetScore = array();
|
||||
$aScores = array();
|
||||
@@ -1387,7 +1500,7 @@ EOF
|
||||
|
||||
if (isset($aChoice['sub_options']))
|
||||
{
|
||||
$aScores[$sChoiceId] = array_merge($aScores[$sChoiceId], $this->GetDefaults($aChoice['sub_options'], $aDefaults, $sChoiceId));
|
||||
$aScores[$sChoiceId] = array_merge($aScores[$sChoiceId], $this->GuessDefaultsFromModules($aChoice['sub_options'], $aDefaults, $sChoiceId));
|
||||
}
|
||||
$index++;
|
||||
}
|
||||
@@ -1409,7 +1522,11 @@ EOF
|
||||
}
|
||||
if (isset($aChoice['sub_options']))
|
||||
{
|
||||
$aScores[$sChoiceId] = $this->GetDefaults($aChoice['sub_options'], $aDefaults, $aModules, $sChoiceId);
|
||||
// By default (i.e. install-mode), sub options can only be checked if the parent option is checked by default
|
||||
if ($this->bUpgrade || (isset($aChoice['default']) && $aChoice['default']))
|
||||
{
|
||||
$aScores[$sChoiceId] = $this->GuessDefaultsFromModules($aChoice['sub_options'], $aDefaults, $aModules, $sChoiceId);
|
||||
}
|
||||
}
|
||||
$index++;
|
||||
}
|
||||
@@ -1474,9 +1591,9 @@ EOF
|
||||
* @param hash $aSelectedChoices List of selected choices array('name' => 'selected_value_id')
|
||||
* @param hash $aModules Return parameter: List of selected modules array('module_id' => true)
|
||||
* @param string $sParentId Used for recursion
|
||||
* @return void
|
||||
* @return string A text representation of what will be installed
|
||||
*/
|
||||
protected function GetSelectedModules($aInfo, $aSelectedChoices, &$aModules, $sParentId = '', $sDisplayChoices = '')
|
||||
protected function GetSelectedModules($aInfo, $aSelectedChoices, &$aModules, $sParentId = '', $sDisplayChoices = '', &$aSelectedExtensions = null)
|
||||
{
|
||||
if ($sParentId == '')
|
||||
{
|
||||
@@ -1508,11 +1625,16 @@ EOF
|
||||
$aModules[$sModuleId] = true; // store the Id of the selected module
|
||||
}
|
||||
}
|
||||
$sChoiceType = isset($aChoice['type']) ? $aChoice['type'] : 'wizard_option';
|
||||
if ($aSelectedExtensions !== null)
|
||||
{
|
||||
$aSelectedExtensions[] = $aChoice['extension_code'];
|
||||
}
|
||||
// Recurse only for selected choices
|
||||
if (isset($aChoice['sub_options']))
|
||||
{
|
||||
$sDisplayChoices .= '<ul>';
|
||||
$sDisplayChoices = $this->GetSelectedModules($aChoice['sub_options'], $aSelectedChoices, $aModules, $sChoiceId, $sDisplayChoices);
|
||||
$sDisplayChoices = $this->GetSelectedModules($aChoice['sub_options'], $aSelectedChoices, $aModules, $sChoiceId, $sDisplayChoices, $aSelectedExtensions);
|
||||
$sDisplayChoices .= '</ul>';
|
||||
}
|
||||
$sDisplayChoices .= '</li>';
|
||||
@@ -1533,6 +1655,10 @@ EOF
|
||||
(isset($aSelectedChoices[$sChoiceName]) && ($aSelectedChoices[$sChoiceName] == $sChoiceId)) )
|
||||
{
|
||||
$sDisplayChoices .= '<li>'.$aChoice['title'].'</li>';
|
||||
if ($aSelectedExtensions !== null)
|
||||
{
|
||||
$aSelectedExtensions[] = $aChoice['extension_code'];
|
||||
}
|
||||
if (isset($aChoice['modules']))
|
||||
{
|
||||
foreach($aChoice['modules'] as $sModuleId)
|
||||
@@ -1544,7 +1670,7 @@ EOF
|
||||
if (isset($aChoice['sub_options']))
|
||||
{
|
||||
$sDisplayChoices .= '<ul>';
|
||||
$sDisplayChoices = $this->GetSelectedModules($aChoice['sub_options'], $aSelectedChoices, $aModules, $sChoiceId, $sDisplayChoices);
|
||||
$sDisplayChoices = $this->GetSelectedModules($aChoice['sub_options'], $aSelectedChoices, $aModules, $sChoiceId, $sDisplayChoices, $aSelectedExtensions);
|
||||
$sDisplayChoices .= '</ul>';
|
||||
}
|
||||
$sDisplayChoices .= '</li>';
|
||||
@@ -1619,79 +1745,68 @@ EOF
|
||||
$aSteps = array();
|
||||
if (@file_exists($this->GetSourceFilePath()))
|
||||
{
|
||||
// Found an "installation.xml" file, let's us tis definition for the wizard
|
||||
$aParams = new XMLParameters($this->GetSourceFilePath());
|
||||
$aSteps = $aParams->Get('steps', array());
|
||||
$bAddExtensionsOnly = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// No wizard configuration provided, build a standard one:
|
||||
$bAddExtensionsOnly = false;
|
||||
$aSteps[] = array(
|
||||
'title' => 'Modules Selection',
|
||||
'description' => '<h2>Select the modules to install. You can launch the installation again to install new modules, but you cannot remove already installed modules.</h2>',
|
||||
'banner' => '/images/modules.png',
|
||||
'options' => array()
|
||||
);
|
||||
}
|
||||
|
||||
// Additional step for the extensions
|
||||
$aSteps[] = array(
|
||||
// Additional step for the "extensions"
|
||||
$aStepDefinition = array(
|
||||
'title' => 'Extensions',
|
||||
'description' => '<h2>Select additional extensions to install. You can launch the installation again to install new extensions, but you cannot remove already installed extensions.</h2>',
|
||||
'banner' => '/images/extension.png',
|
||||
'options' => array()
|
||||
);
|
||||
|
||||
try
|
||||
foreach($this->oExtensionsMap->GetAllExtensions() as $oExtension)
|
||||
{
|
||||
$sDefaultAppPath = utils::GetDefaultUrlAppRoot();
|
||||
}
|
||||
catch(Exception $e)
|
||||
if ($oExtension->sSource !== iTopExtension::SOURCE_WIZARD)
|
||||
{
|
||||
$sDefaultAppPath = '..';
|
||||
}
|
||||
|
||||
$aAvailableModules = SetupUtils::AnalyzeInstallation($this->oWizard);
|
||||
foreach($aAvailableModules as $sModuleId => $aModule)
|
||||
{
|
||||
if ($sModuleId == ROOT_MODULE) continue; // Convention: the version number of the application (and datamodel) are stored as a module named ROOT_MODULE
|
||||
|
||||
$sModuleLabel = $aModule['label'];
|
||||
$sModuleHelp = $aModule['doc.more_information'];
|
||||
$sMoreInfo = (!empty($aModule['doc.more_information'])) ? "<a href=\"$sDefaultAppPath{$aModule['doc.more_information']}\" target=\"_blank\">more info</a>": '';
|
||||
if (($aModule['category'] != 'authentication') && ($aModule['visible'] && !isset($aModule['auto_select'])))
|
||||
{
|
||||
if (($bAddExtensionsOnly) && (!$this->IsExtension($aModule))) continue;
|
||||
|
||||
if ($this->IsExtension($aModule))
|
||||
{
|
||||
$iStepIndex = count($aSteps) - 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
$iStepIndex = 0;
|
||||
}
|
||||
$aSteps[$iStepIndex]['options'][] = array(
|
||||
'title' => $sModuleLabel,
|
||||
'description' => '',
|
||||
'more_info' => $sMoreInfo,
|
||||
$aStepDefinition['options'][] = array(
|
||||
'extension_code' => $oExtension->sCode,
|
||||
'title' => $oExtension->sLabel,
|
||||
'description' => $oExtension->sDescription,
|
||||
'more_info' => $oExtension->sMoreInfoUrl,
|
||||
'default' => true, // by default offer to install all modules
|
||||
'modules' => array($sModuleId),
|
||||
'mandatory' => ($aModule['install']['flag'] & MODULE_ACTION_MANDATORY) ? true : false,
|
||||
'modules' => $oExtension->aModules,
|
||||
'mandatory' => $oExtension->bMandatory || ($oExtension->sSource === iTopExtension::SOURCE_REMOTE),
|
||||
'source_label' => $this->GetExtensionSourceLabel($oExtension->sSource),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (count($aSteps[count($aSteps) - 1]['options']) == 0)
|
||||
// Display this step of the wizard only if there is something to display
|
||||
if (count($aStepDefinition['options']) !== 0)
|
||||
{
|
||||
// No extensions at all, remove the last step
|
||||
$this->oWizard->SetParameter('additional_extensions_modules', '[]');
|
||||
array_pop($aSteps);
|
||||
$aSteps[] = $aStepDefinition;
|
||||
$this->oWizard->SetParameter('additional_extensions_modules', json_encode($aStepDefinition['options']));
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->oWizard->SetParameter('additional_extensions_modules', json_encode($aSteps[count($aSteps) - 1]['options']));
|
||||
// No wizard configuration provided, build a standard one with just one big list
|
||||
$aStepDefinition = array(
|
||||
'title' => 'Modules Selection',
|
||||
'description' => '<h2>Select the modules to install. You can launch the installation again to install new modules, but you cannot remove already installed modules.</h2>',
|
||||
'banner' => '/images/modules.png',
|
||||
'options' => array()
|
||||
);
|
||||
foreach($this->oExtensionsMap->GetAllExtensions() as $oExtension)
|
||||
{
|
||||
if ($oExtension->sSource)
|
||||
{
|
||||
$aStepDefinition['options'][] = array(
|
||||
'extension_code' => $oExtension->sCode,
|
||||
'title' => $oExtension->sLabel,
|
||||
'description' => $oExtension->sDescription,
|
||||
'more_info' => $oExtension->sMoreInfoUrl,
|
||||
'default' => true, // by default offer to install all modules
|
||||
'modules' => $oExtension->aModules,
|
||||
'mandatory' => $oExtension->bMandatory || ($oExtension->sSource !== iTopExtension::SOURCE_REMOTE),
|
||||
'source_label' => $this->GetExtensionSourceLabel($oExtension->sSource),
|
||||
);
|
||||
}
|
||||
}
|
||||
$aSteps[] = $aStepDefinition;
|
||||
}
|
||||
|
||||
if (array_key_exists($index, $aSteps))
|
||||
@@ -1702,52 +1817,70 @@ EOF
|
||||
return $aStepInfo;
|
||||
}
|
||||
|
||||
protected function GetExtensionsStepInfo()
|
||||
protected function GetExtensionSourceLabel($sSource)
|
||||
{
|
||||
// let the user select from the list of modules located in the "extensions" folder
|
||||
switch($sSource)
|
||||
{
|
||||
case iTopExtension::SOURCE_MANUAL:
|
||||
$sResult = 'Extension';
|
||||
break;
|
||||
|
||||
case iTopExtension::SOURCE_REMOTE:
|
||||
$sResult = (ITOP_APPLICATION == 'iTop') ? 'iTop-Hub' : 'ITSM-Designer';
|
||||
break;
|
||||
|
||||
default:
|
||||
$sResult = '';
|
||||
}
|
||||
if ($sResult == '')
|
||||
{
|
||||
return '';
|
||||
}
|
||||
return '<span style="display:inline-block;font-size:8pt;padding:3px;border-radius:4px;color:#fff;background-color:#1c94c4;margin-left:0.5em;margin-right:0.5em">'.$sResult.'</span>';
|
||||
}
|
||||
|
||||
protected function IsExtension($aModule)
|
||||
{
|
||||
// root_dir is the directory containing the module, check if its parent is "extensions"
|
||||
if (basename(dirname($aModule['root_dir'])) == 'extensions')
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
protected function DisplayOptions($oPage, $aStepInfo, $aSelectedComponents, $aDefaults, $sParentId = '')
|
||||
protected function DisplayOptions($oPage, $aStepInfo, $aSelectedComponents, $aDefaults, $sParentId = '', $bAllDisabled = false)
|
||||
{
|
||||
$aOptions = isset($aStepInfo['options']) ? $aStepInfo['options'] : array();
|
||||
$aAlternatives = isset($aStepInfo['alternatives']) ? $aStepInfo['alternatives'] : array();
|
||||
$index = 0;
|
||||
|
||||
$sAllDisabled = '';
|
||||
if ($bAllDisabled)
|
||||
{
|
||||
$sAllDisabled = 'disabled data-disabled="disabled" ';
|
||||
}
|
||||
|
||||
foreach($aOptions as $index => $aChoice)
|
||||
{
|
||||
$sAttributes = '';
|
||||
$sChoiceId = $sParentId.self::$SEP.$index;
|
||||
$sDataId = 'data-id="'.htmlentities($aChoice['extension_code'], ENT_QUOTES, 'UTF-8').'"';
|
||||
$sId = htmlentities($aChoice['extension_code'], ENT_QUOTES, 'UTF-8');
|
||||
$bIsDefault = array_key_exists($sChoiceId, $aDefaults);
|
||||
$bSelected = isset($aSelectedComponents[$sChoiceId]) && ($aSelectedComponents[$sChoiceId] == $sChoiceId);
|
||||
$bMandatory = (isset($aChoice['mandatory']) && $aChoice['mandatory']) || ($this->bUpgrade && $bIsDefault);
|
||||
$bDisabled = false;
|
||||
if ($bMandatory)
|
||||
{
|
||||
$oPage->add('<div class="choice"><input id="choice'.$sChoiceId.'" checked disabled data-disabled="disabled" type="checkbox"'.$sAttributes.'/><input type="hidden" name="choice['.$sChoiceId.']" value="'.$sChoiceId.'"> ');
|
||||
$oPage->add('<div class="choice" '.$sDataId.'><input id="'.$sId.'" checked disabled data-disabled="disabled" type="checkbox"'.$sAttributes.'/><input type="hidden" name="choice['.$sChoiceId.']" value="'.$sChoiceId.'"> ');
|
||||
$bDisabled = true;
|
||||
}
|
||||
else if ($bSelected)
|
||||
{
|
||||
$oPage->add('<div class="choice"><input class="wiz-choice" id="choice'.$sChoiceId.'" name="choice['.$sChoiceId.']" type="checkbox" checked value="'.$sChoiceId.'"/> ');
|
||||
$oPage->add('<div class="choice" '.$sDataId.'><input class="wiz-choice" '.$sAllDisabled.'id="'.$sId.'" name="choice['.$sChoiceId.']" type="checkbox" checked value="'.$sChoiceId.'"/> ');
|
||||
}
|
||||
else
|
||||
{
|
||||
$oPage->add('<div class="choice"><input class="wiz-choice" id="choice'.$sChoiceId.'" name="choice['.$sChoiceId.']" type="checkbox" value="'.$sChoiceId.'"/> ');
|
||||
$oPage->add('<div class="choice" '.$sDataId.'><input class="wiz-choice" '.$sAllDisabled.'id="'.$sId.'" name="choice['.$sChoiceId.']" type="checkbox" value="'.$sChoiceId.'"/> ');
|
||||
}
|
||||
$this->DisplayChoice($oPage, $aChoice, $aSelectedComponents, $aDefaults, $sChoiceId);
|
||||
$this->DisplayChoice($oPage, $aChoice, $aSelectedComponents, $aDefaults, $sChoiceId, $bDisabled);
|
||||
$oPage->add('</div>');
|
||||
$index++;
|
||||
}
|
||||
$sChoiceName = null;
|
||||
$sDisabled = '';
|
||||
$bDisabled = false;
|
||||
$sChoiceIdNone = null;
|
||||
foreach($aAlternatives as $index => $aChoice)
|
||||
{
|
||||
@@ -1758,10 +1891,11 @@ EOF
|
||||
}
|
||||
$bIsDefault = array_key_exists($sChoiceName, $aDefaults) && ($aDefaults[$sChoiceName] == $sChoiceId);
|
||||
$bMandatory = (isset($aChoice['mandatory']) && $aChoice['mandatory']) || ($this->bUpgrade && $bIsDefault);
|
||||
if ($bMandatory)
|
||||
if ($bMandatory || $bAllDisabled)
|
||||
{
|
||||
// One choice is mandatory, all alternatives are disabled
|
||||
$sDisabled = ' disabled data-disabled="disabled"';
|
||||
$bDisabled = true;
|
||||
}
|
||||
if ( (!isset($aChoice['sub_options']) || (count($aChoice['sub_options']) == 0)) && (!isset($aChoice['modules']) || (count($aChoice['modules']) == 0)) )
|
||||
{
|
||||
@@ -1769,10 +1903,20 @@ EOF
|
||||
}
|
||||
}
|
||||
|
||||
if (!array_key_exists($sChoiceName, $aDefaults) || ($aDefaults[$sChoiceName] == $sChoiceIdNone))
|
||||
{
|
||||
// The "none" choice does not disable the selection !!
|
||||
$sDisabled = '';
|
||||
$bDisabled = false;
|
||||
}
|
||||
|
||||
foreach($aAlternatives as $index => $aChoice)
|
||||
{
|
||||
$sAttributes = '';
|
||||
$sChoiceId = $sParentId.self::$SEP.$index;
|
||||
$sDataId = 'data-id="'.htmlentities($aChoice['extension_code'], ENT_QUOTES, 'UTF-8').'"';
|
||||
$sId = htmlentities($aChoice['extension_code'], ENT_QUOTES, 'UTF-8');
|
||||
|
||||
if ($sChoiceName == null)
|
||||
{
|
||||
$sChoiceName = $sChoiceId; // All radios share the same name
|
||||
@@ -1796,22 +1940,24 @@ EOF
|
||||
$sAttributes = ' checked ';
|
||||
$sHidden = '<input type="hidden" name="choice['.$sChoiceName.']" value="'.$sChoiceId.'"/>';
|
||||
}
|
||||
$oPage->add('<div class="choice"><input class="wiz-choice" id="choice'.$sChoiceId.'" name="choice['.$sChoiceName.']" type="radio"'.$sAttributes.' value="'.$sChoiceId.'"'.$sDisabled.'/>'.$sHidden.' ');
|
||||
$this->DisplayChoice($oPage, $aChoice, $aSelectedComponents, $aDefaults, $sChoiceId);
|
||||
$oPage->add('<div class="choice" '.$sDataId.'><input class="wiz-choice" id="'.$sId.'" name="choice['.$sChoiceName.']" type="radio"'.$sAttributes.' value="'.$sChoiceId.'"'.$sDisabled.'/>'.$sHidden.' ');
|
||||
$this->DisplayChoice($oPage, $aChoice, $aSelectedComponents, $aDefaults, $sChoiceId, $bDisabled);
|
||||
$oPage->add('</div>');
|
||||
$index++;
|
||||
}
|
||||
}
|
||||
|
||||
protected function DisplayChoice($oPage, $aChoice, $aSelectedComponents, $aDefaults, $sChoiceId)
|
||||
protected function DisplayChoice($oPage, $aChoice, $aSelectedComponents, $aDefaults, $sChoiceId, $bDisabled = false)
|
||||
{
|
||||
$sMoreInfo = isset($aChoice['more_info']) ? $aChoice['more_info'] : '';
|
||||
$oPage->add('<label for="choice'.$sChoiceId.'"><b>'.htmlentities($aChoice['title'], ENT_QUOTES, 'UTF-8').'</b></label> '.$sMoreInfo);
|
||||
$sMoreInfo = (isset($aChoice['more_info']) && ($aChoice['more_info'] != '')) ? '<a target="_blank" href="'.$aChoice['more_info'].'">More information</a>' : '';
|
||||
$sSourceLabel = isset($aChoice['source_label']) ? $aChoice['source_label'] : '';
|
||||
$sId = htmlentities($aChoice['extension_code'], ENT_QUOTES, 'UTF-8');
|
||||
$oPage->add('<label for="'.$sId.'"><b>'.htmlentities($aChoice['title'], ENT_QUOTES, 'UTF-8').'</b>'.$sSourceLabel.'</label> '.$sMoreInfo);
|
||||
$sDescription = isset($aChoice['description']) ? htmlentities($aChoice['description'], ENT_QUOTES, 'UTF-8') : '';
|
||||
$oPage->add('<div class="description">'.$sDescription.'<span id="sub_choices'.$sChoiceId.'">');
|
||||
if (isset($aChoice['sub_options']))
|
||||
{
|
||||
$this->DisplayOptions($oPage, $aChoice['sub_options'], $aSelectedComponents, $aDefaults, $sChoiceId);
|
||||
$this->DisplayOptions($oPage, $aChoice['sub_options'], $aSelectedComponents, $aDefaults, $sChoiceId, $bDisabled);
|
||||
}
|
||||
$oPage->add('</span></div>');
|
||||
}
|
||||
@@ -1947,8 +2093,6 @@ EOF
|
||||
|
||||
$sMode = $aInstallParams['mode'];
|
||||
|
||||
$sPreinstallationPhase = '';
|
||||
|
||||
$sDestination = ITOP_APPLICATION.(($sMode == 'install') ? ' version '.ITOP_VERSION.' is about to be installed ' : ' is about to be upgraded ');
|
||||
$sDBDescription = ' <b>existing</b> database <b>'.$aInstallParams['database']['name'].'</b>';
|
||||
if (($sMode == 'install') && ($this->oWizard->GetParameter('create_db') == 'yes'))
|
||||
@@ -2081,6 +2225,7 @@ EOF
|
||||
{
|
||||
$sMode = $this->oWizard->GetParameter('install_mode', 'install');
|
||||
$aSelectedModules = json_decode($this->oWizard->GetParameter('selected_modules'), true);
|
||||
$aSelectedExtensions = json_decode($this->oWizard->GetParameter('selected_extensions'), true);
|
||||
$sBackupDestination = '';
|
||||
$sPreviousConfigurationFile = '';
|
||||
$sDBName = $this->oWizard->GetParameter('db_name');
|
||||
@@ -2165,6 +2310,7 @@ EOF
|
||||
),
|
||||
'language' => $this->oWizard->GetParameter('default_language'),
|
||||
'selected_modules' => $aSelectedModules,
|
||||
'selected_extensions' => $aSelectedExtensions,
|
||||
'sample_data' => ($this->oWizard->GetParameter('sample_data', '') == 'yes') ? true : false ,
|
||||
'old_addon' => $this->oWizard->GetParameter('old_addon', false), // whether or not to use the "old" userrights profile addon
|
||||
'options' => json_decode($this->oWizard->GetParameter('misc_options', '[]'), true),
|
||||
@@ -2318,11 +2464,31 @@ class WizStepDone extends WizardStep
|
||||
}
|
||||
|
||||
// Form goes here.. No back button since the job is done !
|
||||
$oPage->add('<table style="width:600px;border:0;padding:0;"><tr>');
|
||||
$oPage->add('<table id="placeholder" style="width:600px;border:0;padding:0;"><tr>');
|
||||
$oPage->add("<td><a style=\"background:transparent;padding:0;\" title=\"Free: Register your iTop version.\" href=\"http://www.combodo.com/register?product=iTop&version=".urlencode(ITOP_VERSION." revision ".ITOP_REVISION)."\" target=\"_blank\"><img style=\"border:0\" src=\"../images/setup-register.gif\"/></td></a>");
|
||||
$oPage->add("<td><a style=\"background:transparent;padding:0;\" title=\"Get Professional Support from Combodo\" href=\"http://www.combodo.com/itopsupport\" target=\"_blank\"><img style=\"border:0\" src=\"../images/setup-support.gif\"/></td></a>");
|
||||
$oPage->add("<td><a style=\"background:transparent;padding:0;\" title=\"Get Professional Training from Combodo\" href=\"http://www.combodo.com/itoptraining\" target=\"_blank\"><img style=\"border:0\" src=\"../images/setup-training.gif\"/></td></a>");
|
||||
$oPage->add('</tr></table>');
|
||||
|
||||
$oConfig = new Config(utils::GetConfigFilePath());
|
||||
$sIframeUrl = $oConfig->GetModuleSetting('itop-hub-connector', 'setup_url', '');
|
||||
|
||||
if ($sIframeUrl != '')
|
||||
{
|
||||
$sIframeUrl .= '?';
|
||||
$oPage->add('<iframe id="fresh_content" style="border:0; width:100%; display:none;" src="'.$sIframeUrl.'"></iframe>');
|
||||
|
||||
$oPage->add_script("window.addEventListener('message', function(event) {
|
||||
if (event.data === 'itophub_load_completed')
|
||||
{
|
||||
$('#fresh_content').height($('#placeholder').height());
|
||||
$('#placeholder').hide();
|
||||
$('#fresh_content').show();
|
||||
}
|
||||
}, false);
|
||||
");
|
||||
}
|
||||
|
||||
$sForm = '<form method="post" action="'.$this->oWizard->GetParameter('application_url').'pages/UI.php">';
|
||||
$sForm .= '<input type="hidden" name="auth_user" value="'.htmlentities($this->oWizard->GetParameter('admin_user'), ENT_QUOTES, 'UTF-8').'">';
|
||||
$sForm .= '<input type="hidden" name="auth_pwd" value="'.htmlentities($this->oWizard->GetParameter('admin_pwd'), ENT_QUOTES, 'UTF-8').'">';
|
||||
@@ -2380,7 +2546,11 @@ class WizStepDone extends WizardStep
|
||||
{
|
||||
if (in_array('_'.$idx, $aParameters[count($aParameters)-1]))
|
||||
{
|
||||
$aAdditionalModules[] = $aModuleInfo['modules'][0]; // Extensions "choices" are always made of one module
|
||||
// Extensions "choices" can now have more than one module
|
||||
foreach($aModuleInfo['modules'] as $sModuleName)
|
||||
{
|
||||
$aAdditionalModules[] = $sModuleName;
|
||||
}
|
||||
}
|
||||
}
|
||||
$idx = 0;
|
||||
@@ -2417,7 +2587,7 @@ class WizStepDone extends WizardStep
|
||||
|
||||
public function AsyncAction(WebPage $oPage, $sCode, $aParameters)
|
||||
{
|
||||
// For security reasons: add the extension now so that this action can be used to read *only* .zip files from the disk...
|
||||
// For security reasons: add the extension now so that this action can be used to read *only* .tar.gz files from the disk...
|
||||
$sBackupFile = $aParameters['backup'].'.tar.gz';
|
||||
if (file_exists($sBackupFile))
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user