mirror of
https://github.com/Combodo/iTop.git
synced 2026-05-18 06:48:50 +02:00
N°9567 - fix extension map init of installation choices
This commit is contained in:
@@ -43,48 +43,53 @@ class iTopExtensionsMap
|
||||
*
|
||||
* @param string $sFromEnvironment The environment to scan
|
||||
* @param array $aExtraDirs extensions dir to scan
|
||||
* @param array $aExtraDirs extensions dir to scan
|
||||
* @param string|null $sAppRootForTests
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(string $sFromEnvironment = ITOP_DEFAULT_ENV, array $aExtraDirs = [])
|
||||
public function __construct(string $sFromEnvironment = ITOP_DEFAULT_ENV, array $aExtraDirs = [], ?string $sAppRootForTests = null)
|
||||
{
|
||||
$this->aExtensions = [];
|
||||
$this->aExtensionsByCode = [];
|
||||
$this->aScannedDirs = [];
|
||||
$this->ScanDisk($sFromEnvironment);
|
||||
|
||||
$sAppRoot = $sAppRootForTests ?? APPROOT;
|
||||
$this->ScanDisk($sFromEnvironment, $sAppRoot);
|
||||
|
||||
$this->aExtraDirs = $aExtraDirs;
|
||||
if (is_dir(APPROOT.'extensions')) {
|
||||
$this->aExtraDirs [] = APPROOT.'extensions';
|
||||
if (is_dir($sAppRoot.'extensions')) {
|
||||
$this->aExtraDirs [] = $sAppRoot.'extensions';
|
||||
}
|
||||
if (is_dir(APPROOT.'data/'.$sFromEnvironment.'-modules')) {
|
||||
$this->aExtraDirs [] = APPROOT.'data/'.$sFromEnvironment.'-modules';
|
||||
if (is_dir($sAppRoot.'data/'.$sFromEnvironment.'-modules')) {
|
||||
$this->aExtraDirs [] = $sAppRoot.'data/'.$sFromEnvironment.'-modules';
|
||||
}
|
||||
|
||||
foreach ($aExtraDirs as $sDir) {
|
||||
$this->ReadDir($sDir, iTopExtension::SOURCE_REMOTE);
|
||||
}
|
||||
$this->CheckDependencies();
|
||||
$this->CheckDependencies($sAppRoot);
|
||||
}
|
||||
|
||||
/**
|
||||
* Populate the list of available (pseudo)extensions by scanning the disk
|
||||
* where the iTop files are located
|
||||
* @param string $sEnvironment
|
||||
* @param string $sAppRoot
|
||||
* @return void
|
||||
*/
|
||||
protected function ScanDisk($sEnvironment)
|
||||
protected function ScanDisk($sEnvironment, string $sAppRoot)
|
||||
{
|
||||
if (!$this->ReadInstallationWizard(APPROOT.'/datamodels/2.x')) {
|
||||
if (!$this->ReadInstallationWizard($sAppRoot.'/datamodels/2.x')) {
|
||||
$this->bHasXmlInstallationFile = false;
|
||||
//no installation xml found in 2.x: let's read all extensions in 2.x first
|
||||
if (!$this->ReadDir(APPROOT.'datamodels/2.x', iTopExtension::SOURCE_WIZARD)) {
|
||||
if (!$this->ReadDir($sAppRoot.'datamodels/2.x', iTopExtension::SOURCE_WIZARD)) {
|
||||
//nothing found in 2.x : fallback read in 1.x (flat structure)
|
||||
$this->ReadDir(APPROOT.'datamodels/1.x', iTopExtension::SOURCE_WIZARD);
|
||||
$this->ReadDir($sAppRoot.'datamodels/1.x', iTopExtension::SOURCE_WIZARD);
|
||||
}
|
||||
}
|
||||
$this->ReadDir(APPROOT.'extensions', iTopExtension::SOURCE_MANUAL);
|
||||
$this->ReadDir(APPROOT.'data/'.$sEnvironment.'-modules', iTopExtension::SOURCE_REMOTE);
|
||||
$this->ReadDir($sAppRoot.'extensions', iTopExtension::SOURCE_MANUAL);
|
||||
$this->ReadDir($sAppRoot.'data/'.$sEnvironment.'-modules', iTopExtension::SOURCE_REMOTE);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -99,25 +104,58 @@ class iTopExtensionsMap
|
||||
return false;
|
||||
}
|
||||
|
||||
$aModuleConfigs = [];
|
||||
$this->ListModuleFiles(basename($sDir), dirname($sDir), $aModuleConfigs);
|
||||
|
||||
$oXml = new XMLParameters($sDir.'/installation.xml');
|
||||
foreach ($oXml->Get('steps') as $aStepInfo) {
|
||||
if (array_key_exists('options', $aStepInfo)) {
|
||||
$this->ProcessWizardChoices($aStepInfo['options']);
|
||||
$this->ProcessWizardChoices($aStepInfo['options'], $aModuleConfigs);
|
||||
}
|
||||
if (array_key_exists('alternatives', $aStepInfo)) {
|
||||
$this->ProcessWizardChoices($aStepInfo['alternatives']);
|
||||
$this->ProcessWizardChoices($aStepInfo['alternatives'], $aModuleConfigs);
|
||||
}
|
||||
}
|
||||
// TODO Add aModuleVersion from module definition on disk in extensions
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private function ListModuleFiles(string $sRelDir, string $sRootDir, array &$aRes): void
|
||||
{
|
||||
$sDirectory = $sRootDir.'/'.$sRelDir;
|
||||
|
||||
if ($hDir = opendir($sDirectory)) {
|
||||
// This is the correct way to loop over the directory. (according to the documentation)
|
||||
while (($sFile = readdir($hDir)) !== false) {
|
||||
$aMatches = [];
|
||||
if (is_dir($sDirectory.'/'.$sFile)) {
|
||||
if (($sFile != '.') && ($sFile != '..') && ($sFile != '.svn') && ($sFile != 'vendor')) {
|
||||
$this->ListModuleFiles($sRelDir.'/'.$sFile, $sRootDir, $aRes);
|
||||
}
|
||||
} elseif (preg_match('/^module\.(.*).php$/i', $sFile, $aMatches)) {
|
||||
try {
|
||||
$aModuleInfo = ModuleFileReader::GetInstance()->ReadModuleFileInformation($sDirectory.'/'.$sFile);
|
||||
$sModuleId = $aModuleInfo[ModuleFileReader::MODULE_INFO_ID];
|
||||
list($sModuleName, $sModuleVersion) = ModuleDiscovery::GetModuleName($sModuleId);
|
||||
$aModuleConfig = $aModuleInfo[ModuleFileReader::MODULE_INFO_CONFIG];
|
||||
$aModuleConfig['module_version'] = $sModuleVersion;
|
||||
$aRes[$sModuleName] = $aModuleConfig;
|
||||
} catch (ModuleFileReaderException $e) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
closedir($hDir);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper to process a "choice" array read from the installation.xml file
|
||||
* @param array $aChoices
|
||||
* @param array $aModuleConfigs
|
||||
* @return void
|
||||
*/
|
||||
protected function ProcessWizardChoices($aChoices)
|
||||
protected function ProcessWizardChoices($aChoices, $aModuleConfigs)
|
||||
{
|
||||
foreach ($aChoices as $aChoiceInfo) {
|
||||
if (array_key_exists('extension_code', $aChoiceInfo)) {
|
||||
@@ -129,13 +167,23 @@ class iTopExtensionsMap
|
||||
if (array_key_exists('modules', $aChoiceInfo)) {
|
||||
// Some wizard choices are not associated with any module
|
||||
$oExtension->aModules = $aChoiceInfo['modules'];
|
||||
foreach ($oExtension->aModules as $sModuleName) {
|
||||
$aCurrentModuleConfig = $aModuleConfigs[$sModuleName] ?? null;
|
||||
if (is_null($aCurrentModuleConfig)) {
|
||||
IssueLog::Info("Installation choice comes with missing module file", null, ["choice" => $oExtension->sCode, 'module' => $sModuleName]);
|
||||
continue;
|
||||
}
|
||||
$oExtension->aModuleVersion[$sModuleName] = $aCurrentModuleConfig['module_version'];
|
||||
unset($aCurrentModuleConfig['module_version']);
|
||||
$oExtension->aModuleInfo[$sModuleName] = $aCurrentModuleConfig;
|
||||
}
|
||||
}
|
||||
if (array_key_exists('sub_options', $aChoiceInfo)) {
|
||||
if (array_key_exists('options', $aChoiceInfo['sub_options'])) {
|
||||
$this->ProcessWizardChoices($aChoiceInfo['sub_options']['options']);
|
||||
$this->ProcessWizardChoices($aChoiceInfo['sub_options']['options'], $aModuleConfigs);
|
||||
}
|
||||
if (array_key_exists('alternatives', $aChoiceInfo['sub_options'])) {
|
||||
$this->ProcessWizardChoices($aChoiceInfo['sub_options']['alternatives']);
|
||||
$this->ProcessWizardChoices($aChoiceInfo['sub_options']['alternatives'], $aModuleConfigs);
|
||||
}
|
||||
}
|
||||
$this->AddExtension($oExtension);
|
||||
@@ -335,19 +383,19 @@ class iTopExtensionsMap
|
||||
/**
|
||||
* Check if some extension contains a module with missing dependencies...
|
||||
* If so, populate the aMissingDepenencies array
|
||||
* @param string $sAppRoot
|
||||
* @return void
|
||||
*/
|
||||
protected function CheckDependencies()
|
||||
protected function CheckDependencies(string $sAppRoot)
|
||||
{
|
||||
$aSearchDirs = [];
|
||||
|
||||
if (is_dir(APPROOT.'/datamodels/2.x')) {
|
||||
$aSearchDirs[] = APPROOT.'/datamodels/2.x';
|
||||
} elseif (is_dir(APPROOT.'/datamodels/1.x')) {
|
||||
$aSearchDirs[] = APPROOT.'/datamodels/1.x';
|
||||
if (is_dir($sAppRoot.'/datamodels/2.x')) {
|
||||
$aSearchDirs[] = $sAppRoot.'/datamodels/2.x';
|
||||
} elseif (is_dir($sAppRoot.'/datamodels/1.x')) {
|
||||
$aSearchDirs[] = $sAppRoot.'/datamodels/1.x';
|
||||
}
|
||||
$aSearchDirs = array_merge($aSearchDirs, $this->aScannedDirs);
|
||||
|
||||
try {
|
||||
ModuleDiscovery::GetModulesOrderedByDependencies($aSearchDirs, true);
|
||||
} catch (MissingDependencyException $e) {
|
||||
|
||||
@@ -141,4 +141,32 @@ class iTopExtension
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public function __serialize(): array
|
||||
{
|
||||
return [
|
||||
'sCode' => $this->sCode,
|
||||
'sSource' => $this->sSource,
|
||||
'sVersion' => $this->sVersion,
|
||||
'aModules' => $this->aModules,
|
||||
'aModuleVersion' => $this->aModuleVersion,
|
||||
'aModuleInfo' => $this->aModuleInfo,
|
||||
];
|
||||
}
|
||||
|
||||
public function __unserialize(array $aData): void
|
||||
{
|
||||
$this->sCode = $aData['sCode'] ?? '';
|
||||
$this->sSource = $aData['sSource'] ?? '';
|
||||
$this->sVersion = $aData['sVersion'] ?? '';
|
||||
$this->aModules = $aData['aModules'] ?? '';
|
||||
$this->aModuleVersion = $aData['aModuleVersion'] ?? '';
|
||||
$this->aModuleInfo = $aData['aModuleInfo'] ?? '';
|
||||
}
|
||||
|
||||
public function __toString(): string
|
||||
{
|
||||
return json_encode($this->__serialize(), JSON_PRETTY_PRINT);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -355,7 +355,6 @@ class ModuleDiscovery
|
||||
*/
|
||||
protected static function ListModuleFiles($sRelDir, $sRootDir)
|
||||
{
|
||||
static $iDummyClassIndex = 0;
|
||||
$sDirectory = $sRootDir.'/'.$sRelDir;
|
||||
|
||||
if ($hDir = opendir($sDirectory)) {
|
||||
|
||||
@@ -151,4 +151,31 @@ class ExtensionsMapTest extends ItopTestCase
|
||||
$this->SetNonPublicProperty($oExtensionsMap, $mapKeyInItopExtensionMap, $aMap);
|
||||
}
|
||||
|
||||
public function testiTopExtensionsMapInit()
|
||||
{
|
||||
$oiTopExtensionsMap = new iTopExtensionsMap(sAppRootForTests:__DIR__."/ressources");
|
||||
|
||||
//file_put_contents(__DIR__.'/ressources/all_extensions_from_datamodels.json', json_encode($this->SerializeExtensionMap($oiTopExtensionsMap), JSON_PRETTY_PRINT));
|
||||
|
||||
$sExpected = file_get_contents(__DIR__.'/ressources/all_extensions_from_datamodels.json');
|
||||
$sExpected = str_replace('"sVersion": "ITOP_VERSION"', '"sVersion": "'.ITOP_VERSION.'"', $sExpected);
|
||||
$this->assertEquals($sExpected, json_encode($this->SerializeExtensionMap($oiTopExtensionsMap), JSON_PRETTY_PRINT));
|
||||
}
|
||||
|
||||
public function SerializeExtensionMap(iTopExtensionsMap $oiTopExtensionsMap): array
|
||||
{
|
||||
$aRes = [];
|
||||
foreach ($oiTopExtensionsMap->GetAllExtensions() as $oExtension) {
|
||||
$aRes[] = [
|
||||
'sCode' => $oExtension->sCode,
|
||||
'sSource' => $oExtension->sSource,
|
||||
'sVersion' => $oExtension->sVersion,
|
||||
'aModules' => $oExtension->aModules,
|
||||
'aModuleVersion' => $oExtension->aModuleVersion,
|
||||
'aModuleInfo' => $oExtension->aModuleInfo,
|
||||
];
|
||||
}
|
||||
|
||||
return $aRes;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,316 @@
|
||||
[
|
||||
{
|
||||
"sCode": "itop-config-mgmt-core",
|
||||
"sSource": "datamodels",
|
||||
"sVersion": "ITOP_VERSION",
|
||||
"aModules": [
|
||||
"itop-structure",
|
||||
"itop-config-mgmt",
|
||||
"itop-attachments",
|
||||
"itop-profiles-itil",
|
||||
"itop-welcome-itil",
|
||||
"itop-tickets",
|
||||
"itop-files-information",
|
||||
"combodo-db-tools",
|
||||
"itop-core-update",
|
||||
"itop-hub-connector",
|
||||
"itop-oauth-client",
|
||||
"combodo-backoffice-darkmoon-theme",
|
||||
"combodo-backoffice-fullmoon-high-contrast-theme",
|
||||
"combodo-backoffice-fullmoon-protanopia-deuteranopia-theme",
|
||||
"combodo-backoffice-fullmoon-tritanopia-theme",
|
||||
"itop-themes-compat",
|
||||
"combodo-my-account",
|
||||
"combodo-my-account-user-info",
|
||||
"combodo-oauth2-client",
|
||||
"itop-attribute-class-set",
|
||||
"itop-attribute-encrypted-password",
|
||||
"itop-ui-copypaste"
|
||||
],
|
||||
"aModuleVersion": {
|
||||
"itop-structure": "3.3.0",
|
||||
"itop-config-mgmt": "3.3.0"
|
||||
},
|
||||
"aModuleInfo": {
|
||||
"itop-structure": {
|
||||
"label": "Core iTop Structure",
|
||||
"category": "business",
|
||||
"dependencies": [],
|
||||
"mandatory": true,
|
||||
"visible": false,
|
||||
"installer": "StructureInstaller",
|
||||
"datamodel": [
|
||||
"main.itop-structure.php"
|
||||
],
|
||||
"data.struct": [],
|
||||
"data.sample": [
|
||||
"data\/data.sample.organizations.xml",
|
||||
"data\/data.sample.locations.xml",
|
||||
"data\/data.sample.persons.xml",
|
||||
"data\/data.sample.teams.xml",
|
||||
"data\/data.sample.contactteam.xml",
|
||||
"data\/data.sample.contacttype.xml"
|
||||
],
|
||||
"doc.manual_setup": "",
|
||||
"doc.more_information": "",
|
||||
"settings": [],
|
||||
"module_file_path": "\/var\/www\/html\/iTopLegacy\/tests\/php-unit-tests\/unitary-tests\/setup\/ressources\/datamodels\/2.x\/itop-structure\/module.itop-structure.php"
|
||||
},
|
||||
"itop-config-mgmt": {
|
||||
"label": "Configuration Management (CMDB)",
|
||||
"category": "business",
|
||||
"dependencies": [
|
||||
"itop-structure\/2.7.1"
|
||||
],
|
||||
"mandatory": false,
|
||||
"visible": true,
|
||||
"installer": "ConfigMgmtInstaller",
|
||||
"datamodel": [
|
||||
"model.itop-config-mgmt.php",
|
||||
"main.itop-config-mgmt.php"
|
||||
],
|
||||
"data.struct": [
|
||||
"data\/en_us.data.itop-brand.xml",
|
||||
"data\/en_us.data.itop-networkdevicetype.xml",
|
||||
"data\/en_us.data.itop-osfamily.xml",
|
||||
"data\/en_us.data.itop-osversion.xml"
|
||||
],
|
||||
"data.sample": [
|
||||
"data\/data.sample.model.xml",
|
||||
"data\/data.sample.networkdevicetype.xml",
|
||||
"data\/data.sample.servers.xml",
|
||||
"data\/data.sample.nw-devices.xml",
|
||||
"data\/data.sample.software.xml",
|
||||
"data\/data.sample.dbserver.xml",
|
||||
"data\/data.sample.dbschema.xml",
|
||||
"data\/data.sample.webserver.xml",
|
||||
"data\/data.sample.webapp.xml",
|
||||
"data\/data.sample.applications.xml",
|
||||
"data\/data.sample.applicationsolutionci.xml"
|
||||
],
|
||||
"doc.manual_setup": "",
|
||||
"doc.more_information": "",
|
||||
"settings": [],
|
||||
"module_file_path": "\/var\/www\/html\/iTopLegacy\/tests\/php-unit-tests\/unitary-tests\/setup\/ressources\/datamodels\/2.x\/itop-config-mgmt\/module.itop-config-mgmt.php"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"sCode": "itop-config-mgmt-datacenter",
|
||||
"sSource": "datamodels",
|
||||
"sVersion": "ITOP_VERSION",
|
||||
"aModules": [
|
||||
"itop-datacenter-mgmt"
|
||||
],
|
||||
"aModuleVersion": [],
|
||||
"aModuleInfo": []
|
||||
},
|
||||
{
|
||||
"sCode": "itop-config-mgmt-end-user",
|
||||
"sSource": "datamodels",
|
||||
"sVersion": "ITOP_VERSION",
|
||||
"aModules": [
|
||||
"itop-endusers-devices"
|
||||
],
|
||||
"aModuleVersion": [],
|
||||
"aModuleInfo": []
|
||||
},
|
||||
{
|
||||
"sCode": "itop-config-mgmt-storage",
|
||||
"sSource": "datamodels",
|
||||
"sVersion": "ITOP_VERSION",
|
||||
"aModules": [
|
||||
"itop-storage-mgmt"
|
||||
],
|
||||
"aModuleVersion": [],
|
||||
"aModuleInfo": []
|
||||
},
|
||||
{
|
||||
"sCode": "itop-container-mgmt",
|
||||
"sSource": "datamodels",
|
||||
"sVersion": "ITOP_VERSION",
|
||||
"aModules": [
|
||||
"itop-container-mgmt"
|
||||
],
|
||||
"aModuleVersion": [],
|
||||
"aModuleInfo": []
|
||||
},
|
||||
{
|
||||
"sCode": "itop-config-mgmt-virtualization",
|
||||
"sSource": "datamodels",
|
||||
"sVersion": "ITOP_VERSION",
|
||||
"aModules": [
|
||||
"itop-virtualization-mgmt"
|
||||
],
|
||||
"aModuleVersion": [],
|
||||
"aModuleInfo": []
|
||||
},
|
||||
{
|
||||
"sCode": "itop-service-mgmt-enterprise",
|
||||
"sSource": "datamodels",
|
||||
"sVersion": "ITOP_VERSION",
|
||||
"aModules": [
|
||||
"itop-service-mgmt"
|
||||
],
|
||||
"aModuleVersion": {
|
||||
"itop-service-mgmt": "3.3.0"
|
||||
},
|
||||
"aModuleInfo": {
|
||||
"itop-service-mgmt": {
|
||||
"label": "Service Management",
|
||||
"category": "business",
|
||||
"dependencies": [
|
||||
"itop-tickets\/2.0.0"
|
||||
],
|
||||
"mandatory": false,
|
||||
"visible": true,
|
||||
"installer": "ServiceMgmtInstaller",
|
||||
"datamodel": [],
|
||||
"data.struct": [],
|
||||
"data.sample": [
|
||||
"data\/data.sample.organizations.xml",
|
||||
"data\/data.sample.contracts.xml",
|
||||
"data\/data.sample.servicefamilies.xml",
|
||||
"data\/data.sample.services.xml",
|
||||
"data\/data.sample.serviceelements.xml",
|
||||
"data\/data.sample.sla.xml",
|
||||
"data\/data.sample.slt.xml",
|
||||
"data\/data.sample.sltsla.xml",
|
||||
"data\/data.sample.contractservice.xml",
|
||||
"data\/data.sample.deliverymodelcontact.xml"
|
||||
],
|
||||
"doc.manual_setup": "",
|
||||
"doc.more_information": "",
|
||||
"settings": [],
|
||||
"module_file_path": "\/var\/www\/html\/iTopLegacy\/tests\/php-unit-tests\/unitary-tests\/setup\/ressources\/datamodels\/2.x\/itop-service-mgmt\/module.itop-service-mgmt.php"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"sCode": "itop-service-mgmt-service-provider",
|
||||
"sSource": "datamodels",
|
||||
"sVersion": "ITOP_VERSION",
|
||||
"aModules": [
|
||||
"itop-service-mgmt-provider"
|
||||
],
|
||||
"aModuleVersion": [],
|
||||
"aModuleInfo": []
|
||||
},
|
||||
{
|
||||
"sCode": "itop-ticket-mgmt-simple-ticket-enhanced-portal",
|
||||
"sSource": "datamodels",
|
||||
"sVersion": "ITOP_VERSION",
|
||||
"aModules": [
|
||||
"itop-portal",
|
||||
"itop-portal-base"
|
||||
],
|
||||
"aModuleVersion": [],
|
||||
"aModuleInfo": []
|
||||
},
|
||||
{
|
||||
"sCode": "itop-ticket-mgmt-simple-ticket",
|
||||
"sSource": "datamodels",
|
||||
"sVersion": "ITOP_VERSION",
|
||||
"aModules": [
|
||||
"itop-request-mgmt"
|
||||
],
|
||||
"aModuleVersion": [],
|
||||
"aModuleInfo": []
|
||||
},
|
||||
{
|
||||
"sCode": "itop-ticket-mgmt-itil-user-request",
|
||||
"sSource": "datamodels",
|
||||
"sVersion": "ITOP_VERSION",
|
||||
"aModules": [
|
||||
"itop-request-mgmt-itil"
|
||||
],
|
||||
"aModuleVersion": [],
|
||||
"aModuleInfo": []
|
||||
},
|
||||
{
|
||||
"sCode": "itop-ticket-mgmt-itil-incident",
|
||||
"sSource": "datamodels",
|
||||
"sVersion": "ITOP_VERSION",
|
||||
"aModules": [
|
||||
"itop-incident-mgmt-itil"
|
||||
],
|
||||
"aModuleVersion": [],
|
||||
"aModuleInfo": []
|
||||
},
|
||||
{
|
||||
"sCode": "itop-ticket-mgmt-itil-enhanced-portal",
|
||||
"sSource": "datamodels",
|
||||
"sVersion": "ITOP_VERSION",
|
||||
"aModules": [
|
||||
"itop-portal",
|
||||
"itop-portal-base"
|
||||
],
|
||||
"aModuleVersion": [],
|
||||
"aModuleInfo": []
|
||||
},
|
||||
{
|
||||
"sCode": "itop-ticket-mgmt-itil",
|
||||
"sSource": "datamodels",
|
||||
"sVersion": "ITOP_VERSION",
|
||||
"aModules": [],
|
||||
"aModuleVersion": [],
|
||||
"aModuleInfo": []
|
||||
},
|
||||
{
|
||||
"sCode": "itop-ticket-mgmt-none",
|
||||
"sSource": "datamodels",
|
||||
"sVersion": "ITOP_VERSION",
|
||||
"aModules": [],
|
||||
"aModuleVersion": [],
|
||||
"aModuleInfo": []
|
||||
},
|
||||
{
|
||||
"sCode": "itop-change-mgmt-simple",
|
||||
"sSource": "datamodels",
|
||||
"sVersion": "ITOP_VERSION",
|
||||
"aModules": [
|
||||
"itop-change-mgmt"
|
||||
],
|
||||
"aModuleVersion": [],
|
||||
"aModuleInfo": []
|
||||
},
|
||||
{
|
||||
"sCode": "itop-change-mgmt-itil",
|
||||
"sSource": "datamodels",
|
||||
"sVersion": "ITOP_VERSION",
|
||||
"aModules": [
|
||||
"itop-change-mgmt-itil"
|
||||
],
|
||||
"aModuleVersion": [],
|
||||
"aModuleInfo": []
|
||||
},
|
||||
{
|
||||
"sCode": "itop-change-mgmt-none",
|
||||
"sSource": "datamodels",
|
||||
"sVersion": "ITOP_VERSION",
|
||||
"aModules": [],
|
||||
"aModuleVersion": [],
|
||||
"aModuleInfo": []
|
||||
},
|
||||
{
|
||||
"sCode": "itop-kown-error-mgmt",
|
||||
"sSource": "datamodels",
|
||||
"sVersion": "ITOP_VERSION",
|
||||
"aModules": [
|
||||
"itop-faq-light",
|
||||
"itop-knownerror-mgmt"
|
||||
],
|
||||
"aModuleVersion": [],
|
||||
"aModuleInfo": []
|
||||
},
|
||||
{
|
||||
"sCode": "itop-problem-mgmt",
|
||||
"sSource": "datamodels",
|
||||
"sVersion": "ITOP_VERSION",
|
||||
"aModules": [
|
||||
"itop-problem-mgmt"
|
||||
],
|
||||
"aModuleVersion": [],
|
||||
"aModuleInfo": []
|
||||
}
|
||||
]
|
||||
@@ -0,0 +1,243 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<installation>
|
||||
<steps type="array">
|
||||
<step>
|
||||
<title>Configuration Management options</title>
|
||||
<description><![CDATA[<h2>The options below allow you to configure the type of elements that are to be managed inside iTop.</h2>]]></description>
|
||||
<banner>/images/icons/icons8-apps-tab.svg</banner>
|
||||
<options type="array">
|
||||
<choice>
|
||||
<extension_code>itop-config-mgmt-core</extension_code>
|
||||
<title>Configuration Management Core</title>
|
||||
<description>All the base objects that are mandatory in the iTop CMDB: Organizations, Locations, Teams, Persons, etc.</description>
|
||||
<modules type="array">
|
||||
<module>itop-structure</module>
|
||||
<module>itop-config-mgmt</module>
|
||||
<module>itop-attachments</module>
|
||||
<module>itop-profiles-itil</module>
|
||||
<module>itop-welcome-itil</module>
|
||||
<module>itop-tickets</module>
|
||||
<module>itop-files-information</module>
|
||||
<module>combodo-db-tools</module>
|
||||
<module>itop-core-update</module>
|
||||
<module>itop-hub-connector</module>
|
||||
<module>itop-oauth-client</module>
|
||||
<module>combodo-backoffice-darkmoon-theme</module>
|
||||
<module>combodo-backoffice-fullmoon-high-contrast-theme</module>
|
||||
<module>combodo-backoffice-fullmoon-protanopia-deuteranopia-theme</module>
|
||||
<module>combodo-backoffice-fullmoon-tritanopia-theme</module>
|
||||
<module>itop-themes-compat</module>
|
||||
<module>combodo-my-account</module>
|
||||
<module>combodo-my-account-user-info</module>
|
||||
<module>combodo-oauth2-client</module>
|
||||
<module>itop-attribute-class-set</module>
|
||||
<module>itop-attribute-encrypted-password</module>
|
||||
<module>itop-ui-copypaste</module>
|
||||
</modules>
|
||||
<mandatory>true</mandatory>
|
||||
</choice>
|
||||
<choice>
|
||||
<extension_code>itop-config-mgmt-datacenter</extension_code>
|
||||
<title>Data Center Devices</title>
|
||||
<description>Manage Data Center devices such as Racks, Enclosures, PDUs, etc.</description>
|
||||
<modules type="array">
|
||||
<module>itop-datacenter-mgmt</module>
|
||||
</modules>
|
||||
<default>true</default>
|
||||
</choice>
|
||||
<choice>
|
||||
<extension_code>itop-config-mgmt-end-user</extension_code>
|
||||
<title>End-User Devices</title>
|
||||
<description>Manage devices related to end-users: PCs, Phones, Tablets, etc.</description>
|
||||
<modules type="array">
|
||||
<module>itop-endusers-devices</module>
|
||||
</modules>
|
||||
<default>true</default>
|
||||
</choice>
|
||||
<choice>
|
||||
<extension_code>itop-config-mgmt-storage</extension_code>
|
||||
<title>Storage Devices</title>
|
||||
<description>Manage storage devices such as NAS, SAN Switches, Tape Libraries and Tapes, etc.</description>
|
||||
<modules type="array">
|
||||
<module>itop-storage-mgmt</module>
|
||||
</modules>
|
||||
<default>true</default>
|
||||
</choice>
|
||||
<choice>
|
||||
<extension_code>itop-config-mgmt-virtualization</extension_code>
|
||||
<title>Virtualization</title>
|
||||
<description>Manage Hypervisors, Virtual Machines and Farms.</description>
|
||||
<modules type="array">
|
||||
<module>itop-virtualization-mgmt</module>
|
||||
</modules>
|
||||
<default>true</default>
|
||||
<sub_options>
|
||||
<options type="array">
|
||||
<choice>
|
||||
<extension_code>itop-container-mgmt</extension_code>
|
||||
<title>Containerization</title>
|
||||
<description><![CDATA[Manage Container Images, Applications and Hosts]]></description>
|
||||
<modules type="array">
|
||||
<module>itop-container-mgmt</module>
|
||||
</modules>
|
||||
<default>false</default>
|
||||
</choice>
|
||||
</options>
|
||||
</sub_options>
|
||||
</choice>
|
||||
</options>
|
||||
</step>
|
||||
<step>
|
||||
<title>Service Management options</title>
|
||||
<description><![CDATA[<h2>Select the choice that best describes the relationships between the services and the IT infrastructure in your IT environment.</h2>]]></description>
|
||||
<banner>/images/icons/icons8-services.svg</banner>
|
||||
<alternatives type="array">
|
||||
<choice>
|
||||
<extension_code>itop-service-mgmt-enterprise</extension_code>
|
||||
<title>Service Management for Enterprises</title>
|
||||
<description>Select this option if the IT delivers services based on a shared infrastructure. For example if different organizations within your company subscribe to services (like Mail and Print services) delivered by a single shared backend.</description>
|
||||
<modules type="array">
|
||||
<module>itop-service-mgmt</module>
|
||||
</modules>
|
||||
<default>true</default>
|
||||
</choice>
|
||||
<choice>
|
||||
<extension_code>itop-service-mgmt-service-provider</extension_code>
|
||||
<title>Service Management for Service Providers</title>
|
||||
<description>Select this option if the IT manages the infrastructure of independent customers. This is the most flexible model, since the services can be delivered with a mix of shared and customer specific infrastructure devices.</description>
|
||||
<modules type="array">
|
||||
<module>itop-service-mgmt-provider</module>
|
||||
</modules>
|
||||
</choice>
|
||||
</alternatives>
|
||||
</step>
|
||||
<step>
|
||||
<title>Tickets Management options</title>
|
||||
<description><![CDATA[<h2>Select the type of tickets you want to use in order to respond to user requests and incidents.</h2>]]></description>
|
||||
<banner>/images/icons/icons8-discussion-forum.svg</banner>
|
||||
<alternatives type="array">
|
||||
<choice>
|
||||
<extension_code>itop-ticket-mgmt-simple-ticket</extension_code>
|
||||
<title>Simple Ticket Management</title>
|
||||
<description>Select this option to use one single type of tickets for all kind of requests.</description>
|
||||
<modules type="array">
|
||||
<module>itop-request-mgmt</module>
|
||||
</modules>
|
||||
<default>true</default>
|
||||
<sub_options>
|
||||
<options type="array">
|
||||
<choice>
|
||||
<extension_code>itop-ticket-mgmt-simple-ticket-enhanced-portal</extension_code>
|
||||
<title>Customer Portal</title>
|
||||
<description><![CDATA[Modern & responsive portal for the end-users]]></description>
|
||||
<modules type="array">
|
||||
<module>itop-portal</module>
|
||||
<module>itop-portal-base</module>
|
||||
</modules>
|
||||
<default>true</default>
|
||||
</choice>
|
||||
</options>
|
||||
</sub_options>
|
||||
</choice>
|
||||
<choice>
|
||||
<extension_code>itop-ticket-mgmt-itil</extension_code>
|
||||
<title>ITIL Compliant Tickets Management</title>
|
||||
<description>Select this option to have different types of ticket for managing user requests and incidents. Each type of ticket has a specific life cycle and specific fields</description>
|
||||
<sub_options>
|
||||
<options type="array">
|
||||
<choice>
|
||||
<extension_code>itop-ticket-mgmt-itil-user-request</extension_code>
|
||||
<title>User Request Management</title>
|
||||
<description>Manage User Request tickets in iTop</description>
|
||||
<modules type="array">
|
||||
<module>itop-request-mgmt-itil</module>
|
||||
</modules>
|
||||
</choice>
|
||||
<choice>
|
||||
<extension_code>itop-ticket-mgmt-itil-incident</extension_code>
|
||||
<title>Incident Management</title>
|
||||
<description>Manage Incidents tickets in iTop</description>
|
||||
<modules type="array">
|
||||
<module>itop-incident-mgmt-itil</module>
|
||||
</modules>
|
||||
</choice>
|
||||
<choice>
|
||||
<extension_code>itop-ticket-mgmt-itil-enhanced-portal</extension_code>
|
||||
<title>Customer Portal</title>
|
||||
<description><![CDATA[Modern & responsive portal for the end-users]]></description>
|
||||
<modules type="array">
|
||||
<module>itop-portal</module>
|
||||
<module>itop-portal-base</module>
|
||||
</modules>
|
||||
<default>true</default>
|
||||
</choice>
|
||||
</options>
|
||||
</sub_options>
|
||||
</choice>
|
||||
<choice>
|
||||
<extension_code>itop-ticket-mgmt-none</extension_code>
|
||||
<title>No Tickets Management</title>
|
||||
<description>Don't manage incidents or user requests in iTop</description>
|
||||
<modules type="array">
|
||||
</modules>
|
||||
</choice>
|
||||
</alternatives>
|
||||
</step>
|
||||
<step>
|
||||
<title>Change Management options</title>
|
||||
<description><![CDATA[<h2>Select the type of tickets you want to use in order to manage changes to the IT infrastructure.</h2>]]></description>
|
||||
<banner>/images/icons/icons8-change.svg</banner>
|
||||
<alternatives type="array">
|
||||
<choice>
|
||||
<extension_code>itop-change-mgmt-simple</extension_code>
|
||||
<title>Simple Change Management</title>
|
||||
<description>Select this option to use one type of ticket for all kind of changes.</description>
|
||||
<modules type="array">
|
||||
<module>itop-change-mgmt</module>
|
||||
</modules>
|
||||
<default>true</default>
|
||||
</choice>
|
||||
<choice>
|
||||
<extension_code>itop-change-mgmt-itil</extension_code>
|
||||
<title>ITIL Change Management</title>
|
||||
<description>Select this option to use Normal/Routine/Emergency change tickets.</description>
|
||||
<modules type="array">
|
||||
<module>itop-change-mgmt-itil</module>
|
||||
</modules>
|
||||
</choice>
|
||||
<choice>
|
||||
<extension_code>itop-change-mgmt-none</extension_code>
|
||||
<title>No Change Management</title>
|
||||
<description>Don't manage changes in iTop</description>
|
||||
<modules type="array">
|
||||
</modules>
|
||||
</choice>
|
||||
</alternatives>
|
||||
</step>
|
||||
<step>
|
||||
<title>Additional ITIL tickets</title>
|
||||
<description><![CDATA[<h2>Pick from the list below the additional ITIL processes that are to be implemented in iTop.</h2>]]></description>
|
||||
<banner>/images/icons/icons8-important-book.svg</banner>
|
||||
<options type="array">
|
||||
<choice>
|
||||
<!-- Extension code has a typo but fixing it would remove that setup option for all existing iTop -->
|
||||
<extension_code>itop-kown-error-mgmt</extension_code>
|
||||
<title>Known Errors Management and FAQ</title>
|
||||
<description>Select this option to track "Known Errors" and FAQs in iTop.</description>
|
||||
<modules type="array">
|
||||
<module>itop-faq-light</module>
|
||||
<module>itop-knownerror-mgmt</module>
|
||||
</modules>
|
||||
</choice>
|
||||
<choice>
|
||||
<extension_code>itop-problem-mgmt</extension_code>
|
||||
<title>Problem Management</title>
|
||||
<description>Select this option to track "Problems" in iTop.</description>
|
||||
<modules type="array">
|
||||
<module>itop-problem-mgmt</module>
|
||||
</modules>
|
||||
</choice>
|
||||
</options>
|
||||
</step>
|
||||
</steps>
|
||||
</installation>
|
||||
@@ -0,0 +1,107 @@
|
||||
<?php
|
||||
|
||||
SetupWebPage::AddModule(
|
||||
__FILE__, // Path to the current file, all other file names are relative to the directory containing this file
|
||||
'itop-config-mgmt/3.3.0',
|
||||
[
|
||||
// Identification
|
||||
//
|
||||
'label' => 'Configuration Management (CMDB)',
|
||||
'category' => 'business',
|
||||
|
||||
// Setup
|
||||
//
|
||||
'dependencies' => [
|
||||
'itop-structure/2.7.1',
|
||||
],
|
||||
'mandatory' => false,
|
||||
'visible' => true,
|
||||
'installer' => 'ConfigMgmtInstaller',
|
||||
|
||||
// Components
|
||||
//
|
||||
'datamodel' => [
|
||||
'model.itop-config-mgmt.php',
|
||||
'main.itop-config-mgmt.php',
|
||||
],
|
||||
'data.struct' => [
|
||||
'data/en_us.data.itop-brand.xml',
|
||||
'data/en_us.data.itop-networkdevicetype.xml',
|
||||
'data/en_us.data.itop-osfamily.xml',
|
||||
'data/en_us.data.itop-osversion.xml',
|
||||
],
|
||||
'data.sample' => [
|
||||
'data/data.sample.model.xml',
|
||||
'data/data.sample.networkdevicetype.xml',
|
||||
'data/data.sample.servers.xml',
|
||||
'data/data.sample.nw-devices.xml',
|
||||
'data/data.sample.software.xml',
|
||||
'data/data.sample.dbserver.xml',
|
||||
'data/data.sample.dbschema.xml',
|
||||
'data/data.sample.webserver.xml',
|
||||
'data/data.sample.webapp.xml',
|
||||
'data/data.sample.applications.xml',
|
||||
'data/data.sample.applicationsolutionci.xml',
|
||||
],
|
||||
|
||||
// Documentation
|
||||
//
|
||||
'doc.manual_setup' => '',
|
||||
'doc.more_information' => '',
|
||||
|
||||
// Default settings
|
||||
//
|
||||
'settings' => [
|
||||
],
|
||||
]
|
||||
);
|
||||
|
||||
if (!class_exists('ConfigMgmtInstaller')) {
|
||||
// Module installation handler
|
||||
//
|
||||
class ConfigMgmtInstaller extends ModuleInstallerAPI
|
||||
{
|
||||
public static function BeforeWritingConfig(Config $oConfiguration)
|
||||
{
|
||||
// If you want to override/force some configuration values, do it here
|
||||
return $oConfiguration;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handler called before creating or upgrading the database schema
|
||||
* @param $oConfiguration Config The new configuration of the application
|
||||
* @param $sPreviousVersion string PRevious version number of the module (empty string in case of first install)
|
||||
* @param $sCurrentVersion string Current version number of the module
|
||||
*/
|
||||
public static function BeforeDatabaseCreation(Config $oConfiguration, $sPreviousVersion, $sCurrentVersion)
|
||||
{
|
||||
if (strlen($sPreviousVersion) > 0) {
|
||||
// If you want to migrate data from one format to another, do it here
|
||||
self::RenameEnumValueInDB('Software', 'type', 'DBserver', 'DBServer');
|
||||
self::RenameEnumValueInDB('Software', 'type', 'Webserver', 'WebServer');
|
||||
self::RenameEnumValueInDB('Model', 'type', 'SANswitch', 'SANSwitch');
|
||||
self::RenameEnumValueInDB('Model', 'type', 'IpPhone', 'IPPhone');
|
||||
self::RenameEnumValueInDB('Model', 'type', 'Telephone', 'Phone');
|
||||
self::RenameClassInDB('DBserver', 'DBServer');
|
||||
self::RenameClassInDB('OSfamily', 'OSFamily');
|
||||
self::RenameClassInDB('OSversion', 'OSVersion');
|
||||
self::RenameClassInDB('Webserver', 'WebServer');
|
||||
self::RenameClassInDB('OSpatch', 'OSPatch');
|
||||
self::RenameClassInDB('lnkFunctionalCIToOSpatch', 'lnkFunctionalCIToOSPatch');
|
||||
self::RenameClassInDB('OsLicence', 'OSLicence');
|
||||
self::RenameClassInDB('IOSversion', 'IOSVersion');
|
||||
self::RenameClassInDB('IPinterface', 'IPInterface');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handler called after the creation/update of the database schema
|
||||
* @param $oConfiguration Config The new configuration of the application
|
||||
* @param $sPreviousVersion string PRevious version number of the module (empty string in case of first install)
|
||||
* @param $sCurrentVersion string Current version number of the module
|
||||
*/
|
||||
public static function AfterDatabaseCreation(Config $oConfiguration, $sPreviousVersion, $sCurrentVersion)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
<?php
|
||||
|
||||
SetupWebPage::AddModule(
|
||||
__FILE__, // Path to the current file, all other file names are relative to the directory containing this file
|
||||
'itop-service-mgmt/3.3.0',
|
||||
[
|
||||
// Identification
|
||||
//
|
||||
'label' => 'Service Management',
|
||||
'category' => 'business',
|
||||
|
||||
// Setup
|
||||
//
|
||||
'dependencies' => [
|
||||
'itop-tickets/2.0.0',
|
||||
],
|
||||
'mandatory' => false,
|
||||
'visible' => true,
|
||||
'installer' => 'ServiceMgmtInstaller',
|
||||
|
||||
// Components
|
||||
//
|
||||
'datamodel' => [
|
||||
],
|
||||
'data.struct' => [
|
||||
//'data.struct.itop-service-mgmt.xml',
|
||||
],
|
||||
'data.sample' => [
|
||||
'data/data.sample.organizations.xml',
|
||||
'data/data.sample.contracts.xml',
|
||||
'data/data.sample.servicefamilies.xml',
|
||||
'data/data.sample.services.xml',
|
||||
'data/data.sample.serviceelements.xml',
|
||||
'data/data.sample.sla.xml',
|
||||
'data/data.sample.slt.xml',
|
||||
'data/data.sample.sltsla.xml',
|
||||
// 'data/data.sample.coveragewindows.xml',
|
||||
'data/data.sample.contractservice.xml',
|
||||
// 'data/data.sample.deliverymodel.xml',
|
||||
'data/data.sample.deliverymodelcontact.xml',
|
||||
],
|
||||
|
||||
// Documentation
|
||||
//
|
||||
'doc.manual_setup' => '',
|
||||
'doc.more_information' => '',
|
||||
|
||||
// Default settings
|
||||
//
|
||||
'settings' => [
|
||||
],
|
||||
]
|
||||
);
|
||||
|
||||
if (!class_exists('ServiceMgmtInstaller')) {
|
||||
// Module installation handler
|
||||
//
|
||||
class ServiceMgmtInstaller extends ModuleInstallerAPI
|
||||
{
|
||||
public static function BeforeWritingConfig(Config $oConfiguration)
|
||||
{
|
||||
// If you want to override/force some configuration values, do it here
|
||||
return $oConfiguration;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handler called before creating or upgrading the database schema
|
||||
* @param $oConfiguration Config The new configuration of the application
|
||||
* @param $sPreviousVersion string PRevious version number of the module (empty string in case of first install)
|
||||
* @param $sCurrentVersion string Current version number of the module
|
||||
*/
|
||||
public static function BeforeDatabaseCreation(Config $oConfiguration, $sPreviousVersion, $sCurrentVersion)
|
||||
{
|
||||
if (strlen($sPreviousVersion) > 0) {
|
||||
self::RenameEnumValueInDB('SLT', 'request_type', 'servicerequest', 'service_request');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handler called after the creation/update of the database schema
|
||||
* @param $oConfiguration Config The new configuration of the application
|
||||
* @param $sPreviousVersion string PRevious version number of the module (empty string in case of first install)
|
||||
* @param $sCurrentVersion string Current version number of the module
|
||||
*/
|
||||
public static function AfterDatabaseCreation(Config $oConfiguration, $sPreviousVersion, $sCurrentVersion)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,449 @@
|
||||
<?php
|
||||
|
||||
SetupWebPage::AddModule(
|
||||
__FILE__, // Path to the current file, all other file names are relative to the directory containing this file
|
||||
'itop-structure/3.3.0',
|
||||
[
|
||||
// Identification
|
||||
//
|
||||
'label' => 'Core iTop Structure',
|
||||
'category' => 'business',
|
||||
|
||||
// Setup
|
||||
//
|
||||
'dependencies' => [
|
||||
],
|
||||
'mandatory' => true,
|
||||
'visible' => false,
|
||||
'installer' => 'StructureInstaller',
|
||||
|
||||
// Components
|
||||
//
|
||||
'datamodel' => [
|
||||
'main.itop-structure.php',
|
||||
],
|
||||
'data.struct' => [
|
||||
],
|
||||
'data.sample' => [
|
||||
'data/data.sample.organizations.xml',
|
||||
'data/data.sample.locations.xml',
|
||||
'data/data.sample.persons.xml',
|
||||
'data/data.sample.teams.xml',
|
||||
'data/data.sample.contactteam.xml',
|
||||
'data/data.sample.contacttype.xml',
|
||||
],
|
||||
|
||||
// Documentation
|
||||
//
|
||||
'doc.manual_setup' => '',
|
||||
'doc.more_information' => '',
|
||||
|
||||
// Default settings
|
||||
//
|
||||
'settings' => [
|
||||
],
|
||||
]
|
||||
);
|
||||
|
||||
if (!class_exists('StructureInstaller')) {
|
||||
// Module installation handler
|
||||
//
|
||||
class StructureInstaller extends ModuleInstallerAPI
|
||||
{
|
||||
public static function BeforeWritingConfig(Config $oConfiguration)
|
||||
{
|
||||
// If you want to override/force some configuration values, do it here
|
||||
return $oConfiguration;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handler called before creating or upgrading the database schema
|
||||
* @param $oConfiguration Config The new configuration of the application
|
||||
* @param $sPreviousVersion string PRevious version number of the module (empty string in case of first install)
|
||||
* @param $sCurrentVersion string Current version number of the module
|
||||
*/
|
||||
public static function BeforeDatabaseCreation(Config $oConfiguration, $sPreviousVersion, $sCurrentVersion)
|
||||
{
|
||||
if (strlen($sPreviousVersion) > 0) {
|
||||
// Search for existing ActionEmail where the language attribute was defined on its child
|
||||
if (version_compare($sPreviousVersion, '3.2.0', '<')) {
|
||||
SetupLog::Info("| Migrate ActionEmail language attribute values to its parent.");
|
||||
$sTableToRead = MetaModel::DBGetTable('ActionEmail');
|
||||
$sTableToSet = MetaModel::DBGetTable('ActionNotification');
|
||||
self::MoveColumnInDB($sTableToRead, 'language', $sTableToSet, 'language', true);
|
||||
SetupLog::Info("| ActionEmail migration done.");
|
||||
}
|
||||
// If you want to migrate data from one format to another, do it here
|
||||
self::RenameEnumValueInDB('Software', 'type', 'DBserver', 'DBServer');
|
||||
self::RenameEnumValueInDB('Software', 'type', 'Webserver', 'WebServer');
|
||||
self::RenameEnumValueInDB('Model', 'type', 'SANswitch', 'SANSwitch');
|
||||
self::RenameEnumValueInDB('Model', 'type', 'IpPhone', 'IPPhone');
|
||||
self::RenameEnumValueInDB('Model', 'type', 'Telephone', 'Phone');
|
||||
self::RenameClassInDB('DBserver', 'DBServer');
|
||||
self::RenameClassInDB('OSfamily', 'OSFamily');
|
||||
self::RenameClassInDB('OSversion', 'OSVersion');
|
||||
self::RenameClassInDB('Webserver', 'WebServer');
|
||||
self::RenameClassInDB('OSpatch', 'OSPatch');
|
||||
self::RenameClassInDB('lnkFunctionalCIToOSpatch', 'lnkFunctionalCIToOSPatch');
|
||||
self::RenameClassInDB('OsLicence', 'OSLicence');
|
||||
self::RenameClassInDB('IOSversion', 'IOSVersion');
|
||||
self::RenameClassInDB('IPinterface', 'IPInterface');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handler called after the creation/update of the database schema
|
||||
* @param $oConfiguration Config The new configuration of the application
|
||||
* @param $sPreviousVersion string PRevious version number of the module (empty string in case of first install)
|
||||
* @param $sCurrentVersion string Current version number of the module
|
||||
*/
|
||||
public static function AfterDatabaseCreation(Config $oConfiguration, $sPreviousVersion, $sCurrentVersion)
|
||||
{
|
||||
// Default language will be used for actions
|
||||
// Note: There is a issue when upgrading, default language cannot be retrieved from the passed configuration, we have to read it from the disk
|
||||
if (utils::IsNullOrEmptyString($sPreviousVersion)) {
|
||||
// Fresh install
|
||||
$sDefaultLanguage = $oConfiguration->GetDefaultLanguage();
|
||||
} else {
|
||||
// Upgrade
|
||||
$sDefaultLanguage = utils::GetConfig(true)->GetDefaultLanguage();
|
||||
}
|
||||
// Fallback language on english if not french
|
||||
$sDefaultLanguage = $sDefaultLanguage === 'FR FR' ? 'FR FR' : 'EN US';
|
||||
SetupLog::Info("Default app language used for actions: $sDefaultLanguage");
|
||||
|
||||
// Search for existing TriggerOnObject where the Trigger string complement is empty and fed it with target_class field value
|
||||
if (version_compare($sPreviousVersion, '3.1.0', '<')) {
|
||||
SetupLog::Info("| Feed computed field triggering_class on existing Triggers.");
|
||||
|
||||
$sTableToSet = MetaModel::DBGetTable('Trigger', 'complement');
|
||||
$sTableToRead = MetaModel::DBGetTable('TriggerOnObject', 'target_class');
|
||||
$oAttDefToSet = MetaModel::GetAttributeDef('Trigger', 'complement');
|
||||
$oAttDefToRead = MetaModel::GetAttributeDef('TriggerOnObject', 'target_class');
|
||||
|
||||
$aColumnsToSets = array_keys($oAttDefToSet->GetSQLColumns());
|
||||
$sColumnToSet = $aColumnsToSets[0]; // We know that a string has only one column
|
||||
$aColumnsToReads = array_keys($oAttDefToRead->GetSQLColumns());
|
||||
$sColumnToRead = $aColumnsToReads[0]; // We know that a string has only one column
|
||||
|
||||
$sRepair = "UPDATE $sTableToSet JOIN $sTableToRead ON $sTableToSet.id = $sTableToRead.id SET $sTableToSet.$sColumnToSet = CONCAT('class restriction: ',$sTableToRead.$sColumnToRead) WHERE $sTableToSet.$sColumnToSet = ''";
|
||||
SetupLog::Debug(" | | Query: ".$sRepair);
|
||||
CMDBSource::Query($sRepair);
|
||||
$iNbProcessed = CMDBSource::AffectedRows();
|
||||
SetupLog::Info("| | ".$iNbProcessed." triggers processed.");
|
||||
}
|
||||
|
||||
// Add notifications by email to Persons if mentioned on any log
|
||||
if (version_compare($sPreviousVersion, '3.0.0', '<')) {
|
||||
SetupLog::Info("Adding default triggers/action for Person objects mentions. All DM classes with at least 1 log attribute will be concerned...");
|
||||
|
||||
$sPersonClass = 'Person';
|
||||
$sPersonStateAttCode = MetaModel::GetStateAttributeCode($sPersonClass);
|
||||
$sPersonOwnerOrgAttCode = UserRightsProfile::GetOwnerOrganizationAttCode($sPersonClass);
|
||||
|
||||
$iClassesWithLogCount = 0;
|
||||
$aCreatedTriggerIds = [];
|
||||
foreach (MetaModel::EnumRootClasses() as $sRootClass) {
|
||||
foreach (MetaModel::EnumChildClasses($sRootClass, ENUM_CHILD_CLASSES_ALL, true) as $sClass) {
|
||||
$aLogAttCodes = MetaModel::GetAttributesList($sClass, ['AttributeCaseLog']);
|
||||
|
||||
// Skip class with no log attribute
|
||||
if (count($aLogAttCodes) === 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Prepare the mentioned_filter OQL
|
||||
$oPersonSearch = DBObjectSearch::FromOQL("SELECT $sPersonClass");
|
||||
|
||||
// - Add status condition if attribute present
|
||||
if (empty($sPersonStateAttCode) === false) {
|
||||
$oPersonSearch->AddConditionExpression(new BinaryExpression(
|
||||
new FieldExpression($sPersonStateAttCode),
|
||||
'=',
|
||||
new ScalarExpression('active')
|
||||
));
|
||||
}
|
||||
|
||||
// - Check if the classes have a silo attribute so we can use them in the mentioned_filter
|
||||
if (empty($sPersonOwnerOrgAttCode) === false) {
|
||||
// Filter on current contact org.
|
||||
$oCurrentContactExpr = new BinaryExpression(
|
||||
new FieldExpression($sPersonOwnerOrgAttCode),
|
||||
'=',
|
||||
new VariableExpression("current_contact->org_id")
|
||||
);
|
||||
|
||||
// Filter on class owner org. if any
|
||||
$sClassOwnerOrgAttCode = UserRightsProfile::GetOwnerOrganizationAttCode($sClass);
|
||||
$oOwnerOrgExpr = empty($sClassOwnerOrgAttCode) ? null : new BinaryExpression(
|
||||
new FieldExpression($sPersonOwnerOrgAttCode),
|
||||
'=',
|
||||
new VariableExpression("this->$sClassOwnerOrgAttCode")
|
||||
);
|
||||
|
||||
// No owner org, simple condition
|
||||
if ($oOwnerOrgExpr === null) {
|
||||
$oPersonSearch->AddConditionExpression($oCurrentContactExpr);
|
||||
}
|
||||
// Owner org, condition is either from owner org or current contact's
|
||||
else {
|
||||
$oOrExpr = new BinaryExpression($oCurrentContactExpr, 'OR', $oOwnerOrgExpr);
|
||||
$oPersonSearch->AddConditionExpression($oOrExpr);
|
||||
}
|
||||
}
|
||||
|
||||
// Build the trigger
|
||||
$oTrigger = MetaModel::NewObject(TriggerOnObjectMention::class);
|
||||
$oTrigger->Set('description', 'Person mentioned on '.$sClass);
|
||||
$oTrigger->Set('target_class', $sClass);
|
||||
$oTrigger->Set('mentioned_filter', $oPersonSearch->ToOQL());
|
||||
$oTrigger->DBInsert();
|
||||
|
||||
SetupLog::Info("|- Created trigger \"{$oTrigger->Get('description')}\" for class $sClass.");
|
||||
$aCreatedTriggerIds[] = $oTrigger->GetKey();
|
||||
$iClassesWithLogCount++;
|
||||
// Note: We break because we only have to create one trigger/action for the class hierarchy as it will be for all their log attributes
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Build the corresponding action and link it to the triggers
|
||||
if (count($aCreatedTriggerIds) > 0) {
|
||||
// Actions data for english and french
|
||||
$aActionsData = [
|
||||
'EN US' => [
|
||||
'name' => 'Notification to persons mentioned in logs',
|
||||
'subject' => 'You have been mentioned in "$this->friendlyname$"',
|
||||
'body' => '<p>Hello $mentioned->first_name$,</p>
|
||||
<p>You have been mentioned by $current_contact->friendlyname$ in $this->hyperlink()$</p>',
|
||||
],
|
||||
'FR FR' => [
|
||||
'name' => 'Notification aux personnes mentionnées dans les journaux',
|
||||
'subject' => 'Vous avez été mentionné dans "$this->friendlyname$"',
|
||||
'body' => '<p>Bonjour $mentioned->first_name$,</p>
|
||||
<p>Vous avez été mentionné par $current_contact->friendlyname$ dans $this->hyperlink()$</p>',
|
||||
],
|
||||
];
|
||||
|
||||
// Create action in app. default language and link it to the triggers
|
||||
$aData = $aActionsData[$sDefaultLanguage];
|
||||
$oAction = MetaModel::NewObject(ActionEmail::class);
|
||||
$oAction->Set('name', $aData['name']);
|
||||
$oAction->Set('status', 'enabled');
|
||||
$oAction->Set('language', $sDefaultLanguage);
|
||||
$oAction->Set('from', '$current_contact->email$');
|
||||
$oAction->Set('to', 'SELECT Person WHERE id = :mentioned->id');
|
||||
$oAction->Set('subject', $aData['subject']);
|
||||
$oAction->Set('body', $aData['body']);
|
||||
|
||||
/** @var \ormLinkSet $oOrm */
|
||||
$oOrm = $oAction->Get('trigger_list');
|
||||
foreach ($aCreatedTriggerIds as $sTriggerId) {
|
||||
$oLink = new lnkTriggerAction();
|
||||
$oLink->Set('trigger_id', $sTriggerId);
|
||||
$oOrm->AddItem($oLink);
|
||||
}
|
||||
$oAction->Set('trigger_list', $oOrm);
|
||||
$oAction->DBInsert();
|
||||
|
||||
SetupLog::Info("|- Created action \"{$oAction->Get('name')}\" and linked it to the previously created triggers.");
|
||||
}
|
||||
|
||||
if ($iClassesWithLogCount === 0) {
|
||||
SetupLog::Info("... no trigger/action created as there is no DM class with a log attribute.");
|
||||
} else {
|
||||
SetupLog::Info("... default triggers/action successfully created for $iClassesWithLogCount classes.");
|
||||
}
|
||||
}
|
||||
|
||||
// Add notifications by newsroom to Persons if mentioned on any log
|
||||
if (version_compare($sPreviousVersion, '3.2.0', '<')) {
|
||||
SetupLog::Info("Adding default newsroom actions for Person objects mentions. All existing TriggerOnObjectMention mentioning the Person class will be concerned...");
|
||||
|
||||
$sPersonClass = Person::class;
|
||||
$iExistingTriggersCount = 0;
|
||||
|
||||
// Actions data for english and french
|
||||
$aActionsData = [
|
||||
'EN US' => [
|
||||
'name' => 'Notification to persons mentioned in logs',
|
||||
'message' => 'You have been mentioned by $current_contact->friendlyname$',
|
||||
],
|
||||
'FR FR' => [
|
||||
'name' => 'Notification aux personnes mentionnées dans les journaux',
|
||||
'message' => 'Vous avez été mentionné par $current_contact->friendlyname$',
|
||||
],
|
||||
];
|
||||
|
||||
// Start by creating the default action no matter what (even if there is no relevant trigger, it will be there for future use)
|
||||
$aData = $aActionsData[$sDefaultLanguage];
|
||||
$oAction = MetaModel::NewObject(ActionNewsroom::class);
|
||||
$oAction->Set('name', $aData['name']);
|
||||
$oAction->Set('status', 'enabled');
|
||||
$oAction->Set('language', $sDefaultLanguage);
|
||||
$oAction->Set('priority', 3); // Important priority as a mention is probably more important than a simple notification
|
||||
$oAction->Set('recipients', 'SELECT Person WHERE id = :mentioned->id');
|
||||
$oAction->Set('title', '$this->friendlyname$');
|
||||
$oAction->Set('message', $aData['message']);
|
||||
$oAction->DBWrite();
|
||||
|
||||
SetupLog::Info("|- Created newsroom action \"{$oAction->Get('name')}\".");
|
||||
|
||||
// Retrieve all triggers and find those with a mentioned_filter on the Person class
|
||||
$oTriggersSearch = DBObjectSearch::FromOQL("SELECT ".TriggerOnObjectMention::class);
|
||||
$oTriggersSearch->AllowAllData();
|
||||
|
||||
$oTriggersSet = new DBObjectSet($oTriggersSearch);
|
||||
while ($oTrigger = $oTriggersSet->Fetch()) {
|
||||
// If mentioned class is not a Person, ignore
|
||||
$oMentionedFilter = DBSearch::FromOQL($oTrigger->Get('mentioned_filter'));
|
||||
if (!is_null($oMentionedFilter) && is_a($oMentionedFilter->GetClass(), $sPersonClass, true) === false) {
|
||||
SetupLog::Info("|- Action \"{$oAction->GetName()}\" NOT LINKED to existing trigger \"{$oTrigger->GetName()}\". (mentioned class \"{$oMentionedFilter->GetClass()}\")");
|
||||
continue;
|
||||
}
|
||||
|
||||
// Link the trigger to the action
|
||||
/** @var \ormLinkSet $oOrm */
|
||||
$oOrm = $oTrigger->Get('action_list');
|
||||
$oLink = new lnkTriggerAction();
|
||||
$oLink->Set('action_id', $oAction->GetKey());
|
||||
$oOrm->AddItem($oLink);
|
||||
|
||||
$oTrigger->Set('action_list', $oOrm);
|
||||
$oTrigger->DBUpdate();
|
||||
$iExistingTriggersCount++;
|
||||
|
||||
SetupLog::Info("|- Linked newsroom action \"{$oAction->GetName()}\" to existing trigger \"{$oTrigger->GetName()}\".");
|
||||
}
|
||||
|
||||
if ($iExistingTriggersCount === 0) {
|
||||
SetupLog::Info("... no action created as there is no existing trigger on mention for the $sPersonClass class.");
|
||||
} else {
|
||||
SetupLog::Info("... default newsroom action successfully created and linked to $iExistingTriggersCount triggers on mention.");
|
||||
}
|
||||
}
|
||||
|
||||
// Force subscription policy to ForceAtLeastOneChannel for all existing TriggerOnObjectMention
|
||||
if (version_compare($sPreviousVersion, '3.2.0', '<')) {
|
||||
SetupLog::Info("Forcing subscription policy to ForceAtLeastOneChannel for all existing TriggerOnObjectMention...");
|
||||
|
||||
$oTriggersSearch = DBObjectSearch::FromOQL("SELECT ".TriggerOnObjectMention::class);
|
||||
$oTriggersSearch->AllowAllData();
|
||||
|
||||
$oTriggersSet = new DBObjectSet($oTriggersSearch);
|
||||
while ($oTrigger = $oTriggersSet->Fetch()) {
|
||||
$oTrigger->Set('subscription_policy', \Combodo\iTop\Core\Trigger\Enum\SubscriptionPolicy::ForceAtLeastOneChannel->value);
|
||||
$oTrigger->DBUpdate();
|
||||
|
||||
SetupLog::Info("|- Trigger \"{$oTrigger->GetName()}\" updated.");
|
||||
}
|
||||
|
||||
SetupLog::Info("... all existing TriggerOnObjectMention updated.");
|
||||
}
|
||||
|
||||
// Add notifications by newsroom (not linked to any trigger yet) for TriggerOnPortalUpdate and TriggerOnReachingState
|
||||
if (version_compare($sPreviousVersion, '3.2.0', '<')) {
|
||||
// TriggerOnPortalUpdate
|
||||
SetupLog::Info("Adding default newsroom action for TriggerOnPortalUpdate (not linked to any trigger yet)...");
|
||||
|
||||
// - Actions data for english and french
|
||||
$aActionsData = [
|
||||
'EN US' => [
|
||||
'name' => 'Notification on public log update through the portal',
|
||||
'message' => 'New message from $current_contact->friendlyname$',
|
||||
],
|
||||
'FR FR' => [
|
||||
'name' => 'Notification sur MAJ du journal public via le portail',
|
||||
'message' => 'Nouveau message de $current_contact->friendlyname$',
|
||||
],
|
||||
];
|
||||
|
||||
// - Create action in app. default language and link it to the triggers
|
||||
$aData = $aActionsData[$sDefaultLanguage];
|
||||
$oAction = MetaModel::NewObject(ActionNewsroom::class);
|
||||
$oAction->Set('name', $aData['name']);
|
||||
$oAction->Set('status', 'enabled');
|
||||
$oAction->Set('language', $sDefaultLanguage);
|
||||
$oAction->Set('priority', 4); // Standard priority
|
||||
$oAction->Set('recipients', 'SELECT Person WHERE id = :this->agent_id');
|
||||
$oAction->Set('title', '$this->friendlyname$');
|
||||
$oAction->Set('message', $aData['message']);
|
||||
$oAction->DBWrite();
|
||||
|
||||
// TriggerOnReachingState
|
||||
SetupLog::Info("Adding default newsroom action for TriggerOnReachingState (not linked to any trigger yet)...");
|
||||
|
||||
// Actions data for english and french
|
||||
$aActionsData = [
|
||||
'EN US' => [
|
||||
'name' => 'Notification to agent when ticket assigned',
|
||||
'message' => 'Ticket has been assigned to you',
|
||||
],
|
||||
'FR FR' => [
|
||||
'name' => 'Notification à l\'agent à l\'assignation du ticket',
|
||||
'message' => 'Le ticket vous a été assigné',
|
||||
],
|
||||
];
|
||||
|
||||
// Create action in app. default language and link it to the triggers
|
||||
$aData = $aActionsData[$sDefaultLanguage];
|
||||
$oAction = MetaModel::NewObject(ActionNewsroom::class);
|
||||
$oAction->Set('name', $aData['name']);
|
||||
$oAction->Set('status', 'enabled');
|
||||
$oAction->Set('language', $sDefaultLanguage);
|
||||
$oAction->Set('priority', 3); // Important priority
|
||||
$oAction->Set('recipients', 'SELECT Person WHERE id = :this->agent_id');
|
||||
$oAction->Set('title', '$this->friendlyname$');
|
||||
$oAction->Set('message', $aData['message']);
|
||||
$oAction->DBWrite();
|
||||
}
|
||||
|
||||
//N°824 - Fill object_class in EventNotification from the Triggers target_class
|
||||
if (version_compare($sPreviousVersion, '3.2.0', '<')) {
|
||||
SetupLog::Info("Filling object_class in EventNotification from the Triggers target_class");
|
||||
$iNbProcessed = 0;
|
||||
|
||||
$sTableToSet = MetaModel::DBGetTable('EventNotification', 'object_class');
|
||||
$oAttDefToSet = MetaModel::GetAttributeDef('EventNotification', 'object_class');
|
||||
$oAttDefObjectId = MetaModel::GetAttributeDef('EventNotification', 'object_id');
|
||||
$oAttDefTriggerId = MetaModel::GetAttributeDef('EventNotification', 'trigger_id');
|
||||
|
||||
$aColumnsToSets = array_keys($oAttDefToSet->GetSQLColumns());
|
||||
$sColumnToSet = $aColumnsToSets[0]; // We know that a string has only one column
|
||||
$aColumnsTriggerId = array_keys($oAttDefTriggerId->GetSQLColumns());
|
||||
$sColumnTriggerId = $aColumnsTriggerId[0]; // We know that a string has only one column
|
||||
$aColumnsObjectd = array_keys($oAttDefObjectId->GetSQLColumns());
|
||||
$sColumnObjectId = $aColumnsObjectd[0]; // We know that a string has only one column
|
||||
|
||||
$oSearch = DBObjectSearch::FromOQL('SELECT TriggerOnObject');
|
||||
$oSet = new DBObjectSet($oSearch);
|
||||
$aTriggerIdToTargetClass = [];
|
||||
while ($oTrigger = $oSet->Fetch()) {
|
||||
$aTriggerIdToTargetClass[$oTrigger->GetKey()] = $oTrigger->Get('target_class');
|
||||
}
|
||||
|
||||
foreach ($aTriggerIdToTargetClass as $sKey => $sTargetClass) {
|
||||
|
||||
if (MetaModel::HasChildrenClasses($sTargetClass)) {
|
||||
//in this case, we have toget the name of the final class
|
||||
$sTableToRead = MetaModel::DBGetTable($sTargetClass, 'finalclass');
|
||||
$oAttDefToRead = MetaModel::GetAttributeDef($sTargetClass, 'finalclass');
|
||||
$aColumnsToReads = array_keys($oAttDefToRead->GetSQLColumns());
|
||||
$sColumnToRead = $aColumnsToReads[0]; // We know that a string has only one column
|
||||
$sObjectPrimaryKey = MetaModel::DBGetKey($sTargetClass);
|
||||
|
||||
$sRepair = "UPDATE `$sTableToSet` JOIN `$sTableToRead` ON `$sTableToSet`.`$sColumnObjectId` = `$sTableToRead`.`$sObjectPrimaryKey` SET `$sTableToSet`.`$sColumnToSet` = `$sTableToRead`.`$sColumnToRead` WHERE `$sTableToSet`.`$sColumnTriggerId` = '".$sKey."' AND `$sTableToSet`.`$sColumnToSet` = ''";
|
||||
} else {
|
||||
|
||||
$sRepair = "UPDATE `$sTableToSet` SET `$sTableToSet`.`$sColumnToSet` = '".$sTargetClass."' WHERE `$sTableToSet`.`$sColumnTriggerId` = '".$sKey."' AND `$sTableToSet`.`$sColumnToSet` = ''";
|
||||
}
|
||||
|
||||
SetupLog::Info(" | | Query: ".$sRepair);
|
||||
CMDBSource::Query($sRepair);
|
||||
$iNbProcessed += CMDBSource::AffectedRows();
|
||||
}
|
||||
SetupLog::Info("| | ".$iNbProcessed." EventNotification processed.");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user