diff --git a/application/cmdbabstract.class.inc.php b/application/cmdbabstract.class.inc.php index d6e522352..c7db07a77 100644 --- a/application/cmdbabstract.class.inc.php +++ b/application/cmdbabstract.class.inc.php @@ -546,6 +546,7 @@ abstract class cmdbAbstractObject extends CMDBObject implements iDisplay { $sTip .= "

Synchronized with {$aRow['name']} - {$aRow['description']}

"; } + $sTip = addslashes($sTip); $oPage->add_ready_script("$('#synchro_$sInputId').qtip( { content: '$sTip', show: 'mouseover', hide: 'mouseout', style: { name: 'dark', tip: 'leftTop' }, position: { corner: { target: 'rightMiddle', tooltip: 'leftTop' }} } );"); } @@ -2832,6 +2833,7 @@ EOF { $sTip .= "

Synchronized with {$aRow['name']} - {$aRow['description']}

"; } + $sTip = addslashes($sTip); $oPage->add_ready_script("$('#synchro_$sInputId').qtip( { content: '$sTip', show: 'mouseover', hide: 'mouseout', style: { name: 'dark', tip: 'leftTop' }, position: { corner: { target: 'rightMiddle', tooltip: 'leftTop' }} } );"); } diff --git a/application/displayblock.class.inc.php b/application/displayblock.class.inc.php index 627fbb245..43ad17ef1 100644 --- a/application/displayblock.class.inc.php +++ b/application/displayblock.class.inc.php @@ -395,7 +395,7 @@ class DisplayBlock $aGroupBy = array(); $aGroupBy['grouped_by_1'] = $oGroupByExp; - $sSql = MetaModel::MakeGroupByQuery($this->m_oFilter, $aQueryParams, $aGroupBy); + $sSql = MetaModel::MakeGroupByQuery($this->m_oFilter, $aQueryParams, $aGroupBy, true); $aRes = CMDBSource::QueryToArray($sSql); $aGroupBy = array(); @@ -893,7 +893,7 @@ EOF $aGroupBy = array(); $aGroupBy['grouped_by_1'] = $oGroupByExp; - $sSql = MetaModel::MakeGroupByQuery($this->m_oFilter, $aQueryParams, $aGroupBy); + $sSql = MetaModel::MakeGroupByQuery($this->m_oFilter, $aQueryParams, $aGroupBy, true); $aRes = CMDBSource::QueryToArray($sSql); $aGroupBy = array(); @@ -968,7 +968,7 @@ EOF $aGroupBy = array(); $aGroupBy['grouped_by_1'] = $oGroupByExp; - $sSql = MetaModel::MakeGroupByQuery($this->m_oFilter, $aQueryParams, $aGroupBy); + $sSql = MetaModel::MakeGroupByQuery($this->m_oFilter, $aQueryParams, $aGroupBy, true); $aRes = CMDBSource::QueryToArray($sSql); $aGroupBy = array(); @@ -1049,7 +1049,8 @@ EOF $aGroupBy = array(); $aGroupBy['grouped_by_1'] = $oGroupByExp; - $sSql = MetaModel::MakeGroupByQuery($this->m_oFilter, $aQueryParams, $aGroupBy); + + $sSql = MetaModel::MakeGroupByQuery($this->m_oFilter, $aQueryParams, $aGroupBy, true); $aRes = CMDBSource::QueryToArray($sSql); $aGroupBy = array(); diff --git a/core/metamodel.class.php b/core/metamodel.class.php index 26ea4d7e2..5aaecbd5c 100644 --- a/core/metamodel.class.php +++ b/core/metamodel.class.php @@ -2076,10 +2076,27 @@ abstract class MetaModel return $aScalarArgs; } - public static function MakeGroupByQuery(DBObjectSearch $oFilter, $aArgs, $aGroupByExpr) + public static function MakeGroupByQuery(DBObjectSearch $oFilter, $aArgs, $aGroupByExpr, $bExcludeNullValues = false) { $aAttToLoad = array(); - $oSelect = self::MakeSelectStructure($oFilter, array(), $aArgs, $aAttToLoad, null, 0, 0, false, $aGroupByExpr); + + if ($bExcludeNullValues) + { + // Null values are not handled (though external keys set to 0 are allowed) + $oQueryFilter = $oFilter->DeepClone(); + foreach ($aGroupByExpr as $oGroupByExp) + { + $oNull = new FunctionExpression('ISNULL', array($oGroupByExp)); + $oNotNull = new BinaryExpression($oNull, '!=', new TrueExpression()); + $oQueryFilter->AddConditionExpression($oNotNull); + } + } + else + { + $oQueryFilter = $oFilter; + } + + $oSelect = self::MakeSelectStructure($oQueryFilter, array(), $aArgs, $aAttToLoad, null, 0, 0, false, $aGroupByExpr); $aScalarArgs = array_merge(self::PrepareQueryArguments($aArgs), $oFilter->GetInternalParams()); try @@ -5148,7 +5165,7 @@ abstract class MetaModel } $aEntries = array(); $aCacheUserData = @apc_cache_info('user'); - if (is_array($aCacheUserData)) + if (is_array($aCacheUserData) && isset($aCacheUserData['cache_list'])) { $sPrefix = 'itop-'.$sEnvironment.'-'; diff --git a/datamodels/2.x/itop-config-mgmt/datamodel.itop-config-mgmt.xml b/datamodels/2.x/itop-config-mgmt/datamodel.itop-config-mgmt.xml index f1b21a7d6..3a74599ca 100755 --- a/datamodels/2.x/itop-config-mgmt/datamodel.itop-config-mgmt.xml +++ b/datamodels/2.x/itop-config-mgmt/datamodel.itop-config-mgmt.xml @@ -2327,6 +2327,9 @@ 40 + + 45 + 50 @@ -2395,6 +2398,9 @@ 50 + + 55 + 60 @@ -2647,6 +2653,9 @@ 40 + + 45 + 50 @@ -2721,6 +2730,9 @@ 50 + + 55 + 60 @@ -4409,6 +4421,8 @@ + + diff --git a/datamodels/2.x/itop-storage-mgmt/datamodel.itop-storage-mgmt.xml b/datamodels/2.x/itop-storage-mgmt/datamodel.itop-storage-mgmt.xml index 779d45cb8..ce190aac5 100644 --- a/datamodels/2.x/itop-storage-mgmt/datamodel.itop-storage-mgmt.xml +++ b/datamodels/2.x/itop-storage-mgmt/datamodel.itop-storage-mgmt.xml @@ -127,6 +127,9 @@ 20 + + 25 + 30 @@ -198,6 +201,9 @@ 70 + + 75 + 80 @@ -373,6 +379,9 @@ 20 + + 35 + 30 @@ -444,6 +453,9 @@ 70 + + 75 + 80 @@ -618,6 +630,9 @@ 20 + + 25 + 30 @@ -689,6 +704,9 @@ 70 + + 75 + 80 @@ -863,6 +881,9 @@ 20 + + 25 + 30 @@ -934,6 +955,9 @@ 70 + + 75 + 80 diff --git a/datamodels/2.x/itop-virtualization-mgmt/datamodel.itop-virtualization-mgmt.xml b/datamodels/2.x/itop-virtualization-mgmt/datamodel.itop-virtualization-mgmt.xml index 8e2a482bf..57ea490eb 100644 --- a/datamodels/2.x/itop-virtualization-mgmt/datamodel.itop-virtualization-mgmt.xml +++ b/datamodels/2.x/itop-virtualization-mgmt/datamodel.itop-virtualization-mgmt.xml @@ -877,6 +877,9 @@
+ + 5 + 10 @@ -902,6 +905,9 @@
+ + 5 + 10 diff --git a/js/jquery.autocomplete.js b/js/jquery.autocomplete.js index 99ee44bc9..c18949789 100644 --- a/js/jquery.autocomplete.js +++ b/js/jquery.autocomplete.js @@ -361,6 +361,7 @@ $.Autocompleter = function(input, options) { $.ajax({ // try to leverage ajaxQueue plugin to abort previous requests mode: "abort", + type: "POST", // limit abortion to this input port: "autocomplete" + input.name, dataType: options.dataType, diff --git a/js/wizardhelper.js b/js/wizardhelper.js index 46a16ff30..26efa921d 100644 --- a/js/wizardhelper.js +++ b/js/wizardhelper.js @@ -134,6 +134,9 @@ function WizardHelper(sClass, sFormPrefix, sState) //console.log(sFieldCode); this.UpdateCurrentValue(sCleanFieldCode); } + // Remove unnecessary stuff + this.m_oData.m_oDefaultValue = {}; + this.m_oData.m_oAllowedValues = {}; } this.UpdateWizardToJSON = function () diff --git a/setup/ajax.dataloader.php b/setup/ajax.dataloader.php index df538561a..42e6a9a8e 100644 --- a/setup/ajax.dataloader.php +++ b/setup/ajax.dataloader.php @@ -79,6 +79,7 @@ function FatalErrorCatcher($sOutput) if ( preg_match('|.*|s', $sOutput, $aMatches) ) { header("HTTP/1.0 500 Internal server error."); + $errors = ''; foreach ($aMatches as $sMatch) { $errors .= strip_tags($sMatch)."\n"; diff --git a/setup/applicationinstaller.class.inc.php b/setup/applicationinstaller.class.inc.php index 36c795023..94af89145 100644 --- a/setup/applicationinstaller.class.inc.php +++ b/setup/applicationinstaller.class.inc.php @@ -375,11 +375,17 @@ class ApplicationInstaller SetupPage::log_error('An exception occurred: '.$e->getMessage().' at line '.$e->getLine().' in file '.$e->getFile()); $idx = 0; - // Log the call stack, but log the parameters since they may contain passwords or other sensitive data + // Log the call stack, but not the parameters since they may contain passwords or other sensitive data SetupPage::log("Call stack:"); foreach($e->getTrace() as $aTrace) { - SetupPage::log("#$idx {$aTrace['file']}({$aTrace['line']}): {$aTrace['function']}(...)"); + $sLine = empty($aTrace['line']) ? "" : $aTrace['line']; + $sFile = empty($aTrace['file']) ? "" : $aTrace['file']; + $sClass = empty($aTrace['class']) ? "" : $aTrace['class']; + $sType = empty($aTrace['type']) ? "" : $aTrace['type']; + $sFunction = empty($aTrace['function']) ? "" : $aTrace['function']; + $sVerb = empty($sClass) ? $sFunction : "$sClass{$sType}$sFunction"; + SetupPage::log("#$idx $sFile($sLine): $sVerb(...)"); $idx++; } } @@ -548,18 +554,18 @@ class ApplicationInstaller // Starting 2.0, all table names must be lowercase if ($sMode != 'install') { - SetupPage::log_info("Renaming 'priv_internalUser' into 'priv_internaluser' (lowercase)"); + SetupPage::log_info("Renaming '{$sDBPrefix}priv_internalUser' into '{$sDBPrefix}priv_internaluser' (lowercase)"); // This command will have no effect under Windows... // and it has been written in two steps so as to make it work under windows! CMDBSource::SelectDB($sDBName); try { - $sRepair = "RENAME TABLE `priv_internalUser` TO `priv_internaluser_other`, `priv_internaluser_other` TO `priv_internaluser`"; + $sRepair = "RENAME TABLE `{$sDBPrefix}priv_internalUser` TO `{$sDBPrefix}priv_internaluser_other`, `{$sDBPrefix}priv_internaluser_other` TO `{$sDBPrefix}priv_internaluser`"; CMDBSource::Query($sRepair); } catch (Exception $e) { - SetupPage::log_info("Renaming 'priv_internalUser' failed (already done in a previous upgrade?)"); + SetupPage::log_info("Renaming '{$sDBPrefix}priv_internalUser' failed (already done in a previous upgrade?)"); } } diff --git a/setup/modelfactory.class.inc.php b/setup/modelfactory.class.inc.php index 97c9109c0..6d6d1277d 100644 --- a/setup/modelfactory.class.inc.php +++ b/setup/modelfactory.class.inc.php @@ -213,7 +213,7 @@ class ModelFactory { echo "Dumping target doc - looking for '$sParentId'
\n"; $this->oDOMDocument->firstChild->Dump(); - throw new Exception("XML datamodel loader: could not find parent node for $oSourceNode->tagName / ".$oSourceNode->getAttribute('id')." with parent id $sParentId"); + throw new Exception("could not find parent node for $oSourceNode->tagName(id:".$oSourceNode->getAttribute('id').") with parent id $sParentId"); } } else @@ -223,7 +223,7 @@ class ModelFactory { echo "Dumping target doc - looking for '".$oSourceNode->getAttribute('id')."'
\n"; $this->oDOMDocument->firstChild->Dump(); - throw new Exception("XML datamodel loader: could not find node for $oSourceNode->tagName/".$oSourceNode->getAttribute('id')); + throw new Exception("could not find node for $oSourceNode->tagName(id:".$oSourceNode->getAttribute('id').")"); } else { @@ -297,59 +297,71 @@ class ModelFactory */ public function LoadModule(MFModule $oModule) { - $aDataModels = $oModule->GetDataModelFiles(); - $sModuleName = $oModule->GetName(); - $aClasses = array(); - self::$aLoadedModules[] = $oModule; - - // For persistence in the cache - $oModuleNode = $this->oDOMDocument->CreateElement('module'); - $oModuleNode->setAttribute('id', $oModule->GetId()); - $oModuleNode->AppendChild($this->oDOMDocument->CreateElement('root_dir', $oModule->GetRootDir())); - $oModuleNode->AppendChild($this->oDOMDocument->CreateElement('label', $oModule->GetLabel())); - $this->oModules->AppendChild($oModuleNode); - - foreach($aDataModels as $sXmlFile) + try { - $oDocument = new MFDocument(); - libxml_clear_errors(); - $oDocument->load($sXmlFile); - //$bValidated = $oDocument->schemaValidate(APPROOT.'setup/itop_design.xsd'); - $aErrors = libxml_get_errors(); - if (count($aErrors) > 0) + $aDataModels = $oModule->GetDataModelFiles(); + $sModuleName = $oModule->GetName(); + $aClasses = array(); + self::$aLoadedModules[] = $oModule; + + // For persistence in the cache + $oModuleNode = $this->oDOMDocument->CreateElement('module'); + $oModuleNode->setAttribute('id', $oModule->GetId()); + $oModuleNode->AppendChild($this->oDOMDocument->CreateElement('root_dir', $oModule->GetRootDir())); + $oModuleNode->AppendChild($this->oDOMDocument->CreateElement('label', $oModule->GetLabel())); + $this->oModules->AppendChild($oModuleNode); + + foreach($aDataModels as $sXmlFile) { - self::$aLoadErrors[$sModuleName] = $aErrors; - return; - } - - $oXPath = new DOMXPath($oDocument); - $oNodeList = $oXPath->query('/itop_design/classes//class'); - foreach($oNodeList as $oNode) - { - if ($oNode->getAttribute('_created_in') == '') + $oDocument = new MFDocument(); + libxml_clear_errors(); + $oDocument->load($sXmlFile); + //$bValidated = $oDocument->schemaValidate(APPROOT.'setup/itop_design.xsd'); + $aErrors = libxml_get_errors(); + if (count($aErrors) > 0) { - $oNode->SetAttribute('_created_in', $sModuleName); + self::$aLoadErrors[$sModuleName] = $aErrors; + return; } - } - $oNodeList = $oXPath->query('/itop_design/menus/menu'); - foreach($oNodeList as $oNode) - { - if ($oNode->getAttribute('_created_in') == '') + + $oXPath = new DOMXPath($oDocument); + $oNodeList = $oXPath->query('/itop_design/classes//class'); + foreach($oNodeList as $oNode) { - $oNode->SetAttribute('_created_in', $sModuleName); + if ($oNode->getAttribute('_created_in') == '') + { + $oNode->SetAttribute('_created_in', $sModuleName); + } } - } - $oUserRightsNode = $oXPath->query('/itop_design/user_rights')->item(0); - if ($oUserRightsNode) - { - if ($oUserRightsNode->getAttribute('_created_in') == '') + $oNodeList = $oXPath->query('/itop_design/menus/menu'); + foreach($oNodeList as $oNode) { - $oUserRightsNode->SetAttribute('_created_in', $sModuleName); + if ($oNode->getAttribute('_created_in') == '') + { + $oNode->SetAttribute('_created_in', $sModuleName); + } } + $oUserRightsNode = $oXPath->query('/itop_design/user_rights')->item(0); + if ($oUserRightsNode) + { + if ($oUserRightsNode->getAttribute('_created_in') == '') + { + $oUserRightsNode->SetAttribute('_created_in', $sModuleName); + } + } + + $oDeltaRoot = $oDocument->childNodes->item(0); + $this->LoadDelta($oDocument, $oDeltaRoot, $this->oDOMDocument); } - - $oDeltaRoot = $oDocument->childNodes->item(0); - $this->LoadDelta($oDocument, $oDeltaRoot, $this->oDOMDocument); + } + catch(Exception $e) + { + $aLoadedModuleNames = array(); + foreach (self::$aLoadedModules as $oModule) + { + $aLoadedModuleNames[] = $oModule->GetName(); + } + throw new Exception('Error loading module "'.$oModule->GetName().'": '.$e->getMessage().' - Loaded modules: '.implode(',', $aLoadedModuleNames)); } } @@ -1282,6 +1294,14 @@ EOF; } +/** + * Allow the setup page to load and perform its checks (including the check about the required extensions) + */ +if (!class_exists('DOMElement')) +{ +class DOMElement {function __construct(){throw new Exception('The dom extension is not enabled');}} +} + /** * MFElement: helper to read/change the DOM * @package ModelFactory @@ -1684,7 +1704,7 @@ class MFElement extends DOMElement { if ($bMustExist) { - throw new Exception("XML datamodel loader: found mandatory node $this->tagName/$sSearchId marked as deleted in $oContainer->tagName"); + throw new Exception("found mandatory node $this->tagName(id:$sSearchId) marked as deleted in ".$oContainer->getNodePath()); } // Beware: ImportNode(xxx, false) DOES NOT copy the node's attribute on *some* PHP versions (<5.2.17) // So use this workaround to import a node and its attributes on *any* PHP version @@ -1698,7 +1718,7 @@ class MFElement extends DOMElement { echo "Dumping parent node
\n"; $oContainer->Dump(); - throw new Exception("XML datamodel loader: could not find $this->tagName/$sSearchId in $oContainer->tagName"); + throw new Exception("could not find $this->tagName(id:$sSearchId) in ".$oContainer->getNodePath()); } // Beware: ImportNode(xxx, false) DOES NOT copy the node's attribute on *some* PHP versions (<5.2.17) // So use this workaround to import a node and its attributes on *any* PHP version @@ -1767,6 +1787,14 @@ class MFElement extends DOMElement } } +/** + * Allow the setup page to load and perform its checks (including the check about the required extensions) + */ +if (!class_exists('DOMDocument')) +{ +class DOMDocument {function __construct(){throw new Exception('The dom extension is not enabled');}} +} + /** * MFDocument - formating rules for XML input/output * @package ModelFactory diff --git a/setup/modulediscovery.class.inc.php b/setup/modulediscovery.class.inc.php index c8e761d81..9e28bbce3 100644 --- a/setup/modulediscovery.class.inc.php +++ b/setup/modulediscovery.class.inc.php @@ -114,6 +114,7 @@ class ModuleDiscovery { $aDependencies[$sId] = $aModule['dependencies']; } + ksort($aDependencies); $aOrderedModules = array(); $iLoopCount = 1; while(($iLoopCount < count(self::$m_aModules)) && (count($aDependencies) > 0) ) diff --git a/setup/setuputils.class.inc.php b/setup/setuputils.class.inc.php index eb3d81d14..183eaf628 100644 --- a/setup/setuputils.class.inc.php +++ b/setup/setuputils.class.inc.php @@ -535,6 +535,10 @@ class SetupUtils { if (function_exists('symlink')) { + if (file_exists($sDest.'/'.$sFile)) + { + unlink($sDest.'/'.$sFile); + } symlink($sSource.'/'.$sFile, $sDest.'/'.$sFile); } else @@ -544,6 +548,10 @@ class SetupUtils } else { + if (is_link($sDest.'/'.$sFile)) + { + unlink($sDest.'/'.$sFile); + } copy($sSource.'/'.$sFile, $sDest.'/'.$sFile); } } @@ -738,7 +746,7 @@ function ValidateField(sFieldId, bUsed) { if (sValue != "") { - if (sValue.match(/^[A-Za-z][A-Za-z0-9_]*$/)) + if (sValue.match(/^[A-Za-z0-9_]*$/)) { var bCollision = false; if (sFieldId == 'db_new_name') diff --git a/setup/wizardsteps.class.inc.php b/setup/wizardsteps.class.inc.php index 9341e9648..8383cd698 100644 --- a/setup/wizardsteps.class.inc.php +++ b/setup/wizardsteps.class.inc.php @@ -480,7 +480,7 @@ EOF { // Special case for upgrading some development versions (temporary) $sCompatibleDMDir = SetupUtils::GetLatestDataModelDir(); - $sInstalledDataModelVersion = SetupUtils::GetDataModelVersion($sLatestDMDir); + $sInstalledDataModelVersion = SetupUtils::GetDataModelVersion($sCompatibleDMDir); } else { @@ -1209,6 +1209,7 @@ EOF foreach($aOptions as $index => $aChoice) { $sChoiceId = $sParentId.self::$SEP.$index; + $aScores[$sChoiceId] = 0; if (!$this->bUpgrade && isset($aChoice['default']) && $aChoice['default']) { $aDefaults[$sChoiceId] = $sChoiceId; @@ -1272,7 +1273,6 @@ EOF { $sChoiceName = $sChoiceId; } - $aScores[$sChoiceId] = 0; if (array_key_exists('modules', $aChoice)) { foreach($aChoice['modules'] as $sModuleId) @@ -1286,7 +1286,8 @@ EOF $iScore = 99; // The whole parent choice is selected } } - } + } + $iMaxScore = max($iMaxScore, isset($aScores[$sChoiceId]) ? $aScores[$sChoiceId] : 0); } } if ($iMaxScore > 0)