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)