diff --git a/.editorconfig b/.editorconfig
index d095a35cf..b30c0b63e 100644
--- a/.editorconfig
+++ b/.editorconfig
@@ -321,7 +321,7 @@ ij_php_call_parameters_right_paren_on_new_line = false
ij_php_call_parameters_wrap = normal
ij_php_catch_on_new_line = true
ij_php_category_weight = 28
-ij_php_class_brace_style = next_line
+ij_php_class_brace_style = end_of_line
ij_php_comma_after_last_array_element = true
ij_php_concat_spaces = false
ij_php_copyright_weight = 28
@@ -372,7 +372,7 @@ ij_php_link_weight = 28
ij_php_lower_case_boolean_const = true
ij_php_lower_case_keywords = true
ij_php_lower_case_null_const = true
-ij_php_method_brace_style = next_line
+ij_php_method_brace_style = end_of_line
ij_php_method_call_chain_wrap = off
ij_php_method_parameters_new_line_after_left_paren = true
ij_php_method_parameters_right_paren_on_new_line = true
diff --git a/.gitignore b/.gitignore
index 6c2d20941..abbd016ec 100644
--- a/.gitignore
+++ b/.gitignore
@@ -40,11 +40,6 @@ test/vendor/*
# Jetbrains
/.idea/**
-!/.idea/encodings.xml
-!/.idea/codeStyles
-!/.idea/codeStyles/*
-!/.idea/inspectionProfiles
-!/.idea/inspectionProfiles/*
# doc. generation
/.doc/vendor
diff --git a/.idea/codeStyles/Project.xml b/.idea/codeStyles/Project.xml
deleted file mode 100644
index 6af43b87d..000000000
--- a/.idea/codeStyles/Project.xml
+++ /dev/null
@@ -1,74 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/codeStyles/codeStyleConfig.xml b/.idea/codeStyles/codeStyleConfig.xml
deleted file mode 100644
index a55e7a179..000000000
--- a/.idea/codeStyles/codeStyleConfig.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/encodings.xml b/.idea/encodings.xml
deleted file mode 100644
index c2bae49d7..000000000
--- a/.idea/encodings.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/inspectionProfiles/Combodo.xml b/.idea/inspectionProfiles/Combodo.xml
deleted file mode 100644
index f28cfada7..000000000
--- a/.idea/inspectionProfiles/Combodo.xml
+++ /dev/null
@@ -1,209 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml
deleted file mode 100644
index b9013fdbd..000000000
--- a/.idea/inspectionProfiles/Project_Default.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/inspectionProfiles/profiles_settings.xml b/.idea/inspectionProfiles/profiles_settings.xml
deleted file mode 100644
index 7f3af8c75..000000000
--- a/.idea/inspectionProfiles/profiles_settings.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-
-
-
-
-
-
\ No newline at end of file
diff --git a/application/ajaxwebpage.class.inc.php b/application/ajaxwebpage.class.inc.php
index 82ddaf0d1..12f47ffa3 100644
--- a/application/ajaxwebpage.class.inc.php
+++ b/application/ajaxwebpage.class.inc.php
@@ -24,31 +24,34 @@ class ajax_page extends WebPage implements iTabbedPage
/**
* Jquery style ready script
* @var array
- */
+ */
protected $m_sReadyScript;
protected $m_oTabs;
private $m_sMenu; // If set, then the menu will be updated
-
- /**
- * constructor for the web page
- * @param string $s_title Not used
- */
- function __construct($s_title)
- {
+
+ /**
+ * constructor for the web page
+ *
+ * @param string $s_title Not used
+ */
+ function __construct($s_title) {
$sPrintable = utils::ReadParam('printable', '0');
$bPrintable = ($sPrintable == '1');
- parent::__construct($s_title, $bPrintable);
- $this->m_sReadyScript = "";
+ parent::__construct($s_title, $bPrintable);
+ $this->m_sReadyScript = "";
//$this->add_header("Content-type: text/html; charset=utf-8");
- $this->add_header("Cache-control: no-cache");
+ $this->add_header('Cache-control: no-cache, no-store, must-revalidate');
+ $this->add_header('Pragma: no-cache');
+ $this->add_header('Expires: 0');
+ $this->add_header('X-Frame-Options: deny');
$this->m_oTabs = new TabManager();
$this->sContentType = 'text/html';
$this->sContentDisposition = 'inline';
$this->m_sMenu = "";
utils::InitArchiveMode();
- }
+ }
/**
* @inheritDoc
diff --git a/application/cmdbabstract.class.inc.php b/application/cmdbabstract.class.inc.php
index 949cfc09e..c1a23f249 100644
--- a/application/cmdbabstract.class.inc.php
+++ b/application/cmdbabstract.class.inc.php
@@ -558,12 +558,6 @@ EOF
$oLinkSet = $oOrmLinkSet->ToDBObjectSet(utils::ShowObsoleteData());
$iCount = $oLinkSet->Count();
- $sCount = '';
- if ($iCount != 0)
- {
- $sCount = " ($iCount)";
- }
- $oPage->SetCurrentTab('Class:'.$sClass.'/Attribute:'.$sAttCode, $oAttDef->GetLabel().$sCount);
if ($this->IsNew())
{
$iFlags = $this->GetInitialStateAttributeFlags($sAttCode);
@@ -609,6 +603,9 @@ EOF
continue;
}
+ $sCount = ($iCount != 0) ? " ($iCount)" : "";
+ $oPage->SetCurrentTab('Class:'.$sClass.'/Attribute:'.$sAttCode, $oAttDef->GetLabel().$sCount);
+
$aArgs = array('this' => $this);
$bReadOnly = ($iFlags & (OPT_ATT_READONLY | OPT_ATT_SLAVE));
if ($bEditMode && (!$bReadOnly))
diff --git a/application/csvpage.class.inc.php b/application/csvpage.class.inc.php
index 8ff526b77..f6a4639bd 100644
--- a/application/csvpage.class.inc.php
+++ b/application/csvpage.class.inc.php
@@ -29,13 +29,15 @@ require_once(APPROOT."/application/webpage.class.inc.php");
class CSVPage extends WebPage
{
- function __construct($s_title)
- {
- parent::__construct($s_title);
- $this->add_header("Content-type: text/plain; charset=".self::PAGES_CHARSET);
- $this->add_header("Cache-control: no-cache");
+ function __construct($s_title) {
+ parent::__construct($s_title);
+ $this->add_header("Content-type: text/plain; charset=".self::PAGES_CHARSET);
+ $this->add_header('Cache-control: no-cache, no-store, must-revalidate');
+ $this->add_header('Pragma: no-cache');
+ $this->add_header('Expires: 0');
+ $this->add_header('X-Frame-Options: deny');
//$this->add_header("Content-Transfer-Encoding: binary");
- }
+ }
public function output()
{
diff --git a/application/itopwebpage.class.inc.php b/application/itopwebpage.class.inc.php
index 1c6e2c9f0..b45d5d5bc 100644
--- a/application/itopwebpage.class.inc.php
+++ b/application/itopwebpage.class.inc.php
@@ -71,7 +71,10 @@ class iTopWebPage extends NiceWebPage implements iTabbedPage
$this->m_aMessages = array();
$this->SetRootUrl(utils::GetAbsoluteUrlAppRoot());
$this->add_header("Content-type: text/html; charset=".self::PAGES_CHARSET);
- $this->add_header("Cache-control: no-cache");
+ $this->add_header('Cache-control: no-cache, no-store, must-revalidate');
+ $this->add_header('Pragma: no-cache');
+ $this->add_header('Expires: 0');
+ $this->add_header('X-Frame-Options: deny');
$this->add_linked_stylesheet("../css/jquery.treeview.css");
$this->add_linked_stylesheet("../css/jquery-ui-timepicker-addon.css");
$this->add_linked_stylesheet("../css/jquery.multiselect.css");
diff --git a/application/loginwebpage.class.inc.php b/application/loginwebpage.class.inc.php
index 02caac304..0d1c6dba6 100644
--- a/application/loginwebpage.class.inc.php
+++ b/application/loginwebpage.class.inc.php
@@ -78,14 +78,16 @@ class LoginWebPage extends NiceWebPage
public function __construct($sTitle = null)
{
- if($sTitle === null)
- {
- $sTitle = Dict::S('UI:Login:Title');
- }
+ if ($sTitle === null) {
+ $sTitle = Dict::S('UI:Login:Title');
+ }
parent::__construct($sTitle);
$this->SetStyleSheet();
- $this->add_header("Cache-control: no-cache");
+ $this->add_header('Cache-control: no-cache, no-store, must-revalidate');
+ $this->add_header('Pragma: no-cache');
+ $this->add_header('Expires: 0');
+ $this->add_header('X-Frame-Options: deny');
}
public function SetStyleSheet()
diff --git a/application/utils.inc.php b/application/utils.inc.php
index 012645ef1..3bd95f39f 100644
--- a/application/utils.inc.php
+++ b/application/utils.inc.php
@@ -2319,4 +2319,26 @@ class utils
{
return str_replace(' ', '', ucwords(strtr($sInput, '_-', ' ')));
}
+
+ /**
+ * @param \cmdbAbstractObject $oCmdbAbstract
+ * @param \Exception $oException
+ *
+ * @throws \Exception
+ * @since 2.7.2/ 2.8.0
+ */
+ public static function EnrichRaisedException($oCmdbAbstract, $oException)
+ {
+ if (is_null($oCmdbAbstract) ||
+ ! is_a($oCmdbAbstract, \cmdbAbstractObject::class))
+ {
+ throw $oException;
+ }
+
+ $sCmdbAbstractInfo = str_replace("\n", '', "" . $oCmdbAbstract);
+ $sMessage = $oException->getMessage() . " (" . $sCmdbAbstractInfo . ")";
+
+ $e = new CoreException($sMessage, null, '', $oException);
+ throw $e;
+ }
}
diff --git a/application/webpage.class.inc.php b/application/webpage.class.inc.php
index d6bb972de..344d91542 100644
--- a/application/webpage.class.inc.php
+++ b/application/webpage.class.inc.php
@@ -487,8 +487,10 @@ class WebPage implements Page
*/
public function no_cache()
{
- $this->add_header("Cache-Control: no-cache, must-revalidate"); // HTTP/1.1
- $this->add_header("Expires: Fri, 17 Jul 1970 05:00:00 GMT"); // Date in the past
+ $this->add_header('Cache-control: no-cache, no-store, must-revalidate');
+ $this->add_header('Pragma: no-cache');
+ $this->add_header('Expires: 0');
+ $this->add_header('X-Frame-Options: deny');
}
/**
@@ -1546,6 +1548,12 @@ class TabManager
{
unset($aTabs['tabs'][$sTabCode]);
}
+
+ // N°3320: Do not display empty tabs
+ if (empty($aTabData['html']) && empty($aTabData['url']))
+ {
+ unset($aTabs['tabs'][$sTabCode]);
+ }
}
// Render tabs
diff --git a/application/xmlpage.class.inc.php b/application/xmlpage.class.inc.php
index 3e08316a4..3310f3772 100644
--- a/application/xmlpage.class.inc.php
+++ b/application/xmlpage.class.inc.php
@@ -43,9 +43,12 @@ class XMLPage extends WebPage
$this->m_bPassThrough = $bPassThrough;
$this->m_bHeaderSent = false;
$this->add_header("Content-type: text/xml; charset=".self::PAGES_CHARSET);
- $this->add_header("Cache-control: no-cache");
+ $this->add_header('Cache-control: no-cache, no-store, must-revalidate');
+ $this->add_header('Pragma: no-cache');
+ $this->add_header('Expires: 0');
+ $this->add_header('X-Frame-Options: deny');
$this->add_header("Content-location: export.xml");
- }
+ }
public function output()
{
diff --git a/composer.json b/composer.json
index f29a0ec03..a32515d49 100644
--- a/composer.json
+++ b/composer.json
@@ -12,7 +12,7 @@
"ext-soap": "*",
"combodo/tcpdf": "6.3.5",
"nikic/php-parser": "^3.1",
- "pear/archive_tar": "1.4.9",
+ "pear/archive_tar": "1.4.10",
"pelago/emogrifier": "2.1.0",
"scssphp/scssphp": "1.0.6",
"swiftmailer/swiftmailer": "5.4.12",
diff --git a/composer.lock b/composer.lock
index 3a08b7f7d..2aef21e81 100644
--- a/composer.lock
+++ b/composer.lock
@@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
- "content-hash": "ad359769d05acd25a9fc31d69acbe43a",
+ "content-hash": "27af144ea2acf2c138f587052a4ceddc",
"packages": [
{
"name": "combodo/tcpdf",
@@ -12,12 +12,12 @@
"source": {
"type": "git",
"url": "https://github.com/combodo-itop-libs/TCPDF.git",
- "reference": "abbfedb8ca59843dec11c97ca3f308742265c3fc"
+ "reference": "aedd4b7b8cf7fcc24e617c405c9d3304150f4b94"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/combodo-itop-libs/TCPDF/zipball/abbfedb8ca59843dec11c97ca3f308742265c3fc",
- "reference": "abbfedb8ca59843dec11c97ca3f308742265c3fc",
+ "url": "https://api.github.com/repos/combodo-itop-libs/TCPDF/zipball/aedd4b7b8cf7fcc24e617c405c9d3304150f4b94",
+ "reference": "aedd4b7b8cf7fcc24e617c405c9d3304150f4b94",
"shasum": ""
},
"require": {
@@ -64,7 +64,7 @@
],
"description": "TCPDF fork adding requirements for iTop: Specific fonts.",
"homepage": "https://github.com/combodo-itop-libs/TCPDF",
- "time": "2020-06-05T13:06:44+00:00"
+ "time": "2020-09-28T12:19:09+00:00"
},
{
"name": "nikic/php-parser",
@@ -168,16 +168,16 @@
},
{
"name": "pear/archive_tar",
- "version": "1.4.9",
+ "version": "1.4.10",
"source": {
"type": "git",
"url": "https://github.com/pear/Archive_Tar.git",
- "reference": "c5b00053770e1d72128252c62c2c1a12c26639f0"
+ "reference": "bbb4f10f71a1da2715ec6d9a683f4f23c507a49b"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/pear/Archive_Tar/zipball/c5b00053770e1d72128252c62c2c1a12c26639f0",
- "reference": "c5b00053770e1d72128252c62c2c1a12c26639f0",
+ "url": "https://api.github.com/repos/pear/Archive_Tar/zipball/bbb4f10f71a1da2715ec6d9a683f4f23c507a49b",
+ "reference": "bbb4f10f71a1da2715ec6d9a683f4f23c507a49b",
"shasum": ""
},
"require": {
@@ -230,7 +230,7 @@
"archive",
"tar"
],
- "time": "2019-12-04T10:17:28+00:00"
+ "time": "2020-09-15T14:13:23+00:00"
},
{
"name": "pear/console_getopt",
diff --git a/core/coreexception.class.inc.php b/core/coreexception.class.inc.php
index 81ba9efef..7188446c7 100644
--- a/core/coreexception.class.inc.php
+++ b/core/coreexception.class.inc.php
@@ -28,7 +28,7 @@
class CoreException extends Exception
{
- public function __construct($sIssue, $aContextData = null, $sImpact = '')
+ public function __construct($sIssue, $aContextData = null, $sImpact = '', $oPrevious = null)
{
$this->m_sIssue = $sIssue;
$this->m_sImpact = $sImpact;
@@ -66,7 +66,7 @@ class CoreException extends Exception
}
$sMessage .= implode(', ', $aContextItems);
}
- parent::__construct($sMessage, 0);
+ parent::__construct($sMessage, 0, $oPrevious);
}
/**
@@ -81,6 +81,16 @@ class CoreException extends Exception
return $this->getMessage();
}
+ /**
+ * getTraceAsString() cannot be overrided and it is limited as only current exception stack is returned.
+ * we need stack of all previous exceptions
+ * @uses __tostring() already does the work.
+ * @since 2.7.2/ 2.8.0
+ */
+ public function getFullStackTraceAsString(){
+ return "" . $this;
+ }
+
public function getTraceAsHtml()
{
$aBackTrace = $this->getTrace();
diff --git a/core/dbobject.class.php b/core/dbobject.class.php
index a12a0882e..b8184778e 100644
--- a/core/dbobject.class.php
+++ b/core/dbobject.class.php
@@ -2847,7 +2847,14 @@ abstract class DBObject implements iDisplay
while ($oTrigger = $oSet->Fetch())
{
/** @var \Trigger $oTrigger */
- $oTrigger->DoActivate($this->ToArgs('this'));
+ try
+ {
+ $oTrigger->DoActivate($this->ToArgs('this'));
+ }
+ catch(Exception $e)
+ {
+ utils::EnrichRaisedException($oTrigger, $e);
+ }
}
$this->RecordObjCreation();
@@ -3119,7 +3126,14 @@ abstract class DBObject implements iDisplay
while ($oTrigger = $oSet->Fetch())
{
/** @var \Trigger $oTrigger */
- $oTrigger->DoActivate($this->ToArgs('this'));
+ try
+ {
+ $oTrigger->DoActivate($this->ToArgs('this'));
+ }
+ catch(Exception $e)
+ {
+ utils::EnrichRaisedException($oTrigger, $e);
+ }
}
$bHasANewExternalKeyValue = false;
@@ -3416,7 +3430,14 @@ abstract class DBObject implements iDisplay
while ($oTrigger = $oSet->Fetch())
{
/** @var \Trigger $oTrigger */
- $oTrigger->DoActivate($this->ToArgs('this'));
+ try
+ {
+ $oTrigger->DoActivate($this->ToArgs('this'));
+ }
+ catch(Exception $e)
+ {
+ utils::EnrichRaisedException($oTrigger, $e);
+ }
}
$this->RecordObjDeletion($this->m_iKey); // May cause a reload for storing history information
@@ -3795,14 +3816,27 @@ abstract class DBObject implements iDisplay
while ($oTrigger = $oSet->Fetch())
{
/** @var \Trigger $oTrigger */
- $oTrigger->DoActivate($this->ToArgs('this'));
+ try
+ {
+ $oTrigger->DoActivate($this->ToArgs('this'));
+ }
+ catch(Exception $e)
+ {
+ utils::EnrichRaisedException($oTrigger, $e);
+ }
}
$oSet = new DBObjectSet(DBObjectSearch::FromOQL("SELECT TriggerOnStateEnter AS t WHERE t.target_class IN (:class_list) AND t.state=:new_state"), array(), $aParams);
while ($oTrigger = $oSet->Fetch())
{
/** @var \Trigger $oTrigger */
- $oTrigger->DoActivate($this->ToArgs('this'));
+ try{
+ $oTrigger->DoActivate($this->ToArgs('this'));
+ }
+ catch(Exception $e)
+ {
+ utils::EnrichRaisedException($oTrigger, $e);
+ }
}
}
else
diff --git a/core/dbobjectsearch.class.php b/core/dbobjectsearch.class.php
index 6da35c091..c4c612008 100644
--- a/core/dbobjectsearch.class.php
+++ b/core/dbobjectsearch.class.php
@@ -63,9 +63,15 @@ class DBObjectSearch extends DBSearch
{
parent::__construct();
- if (is_null($sClassAlias)) $sClassAlias = $sClass;
- if(!is_string($sClass)) throw new Exception('DBObjectSearch::__construct called with a non-string parameter: $sClass = '.print_r($sClass, true));
- if(!MetaModel::IsValidClass($sClass)) throw new Exception('DBObjectSearch::__construct called for an invalid class: "'.$sClass.'"');
+ if (is_null($sClassAlias)) {
+ $sClassAlias = $sClass;
+ }
+ if (!is_string($sClass)) {
+ throw new Exception('DBObjectSearch::__construct called with a non-string parameter: $sClass = '.print_r($sClass, true));
+ }
+ if (!MetaModel::IsValidClass($sClass)) {
+ throw new Exception('DBObjectSearch::__construct called for an invalid class: "'.$sClass.'"');
+ }
$this->m_aSelectedClasses = array($sClassAlias => $sClass);
$this->m_aClasses = array($sClassAlias => $sClass);
@@ -75,30 +81,43 @@ class DBObjectSearch extends DBSearch
$this->m_aReferencedBy = array();
}
- public function AllowAllData($bAllowAllData = true) {$this->m_bAllowAllData = $bAllowAllData;}
- public function IsAllDataAllowed() {return $this->m_bAllowAllData;}
- protected function IsDataFiltered() {return $this->m_bDataFiltered; }
- protected function SetDataFiltered() {$this->m_bDataFiltered = true;}
+ public function AllowAllData($bAllowAllData = true) {
+ $this->m_bAllowAllData = $bAllowAllData;
+
+ $this->m_oSearchCondition->Browse(function ($oThisExpression) use ($bAllowAllData) {
+ ExpressionHelper::ExpressionAllowAllDataCallback($oThisExpression, $bAllowAllData);
+ });
+ }
+
+ public function IsAllDataAllowed() {
+ return $this->m_bAllowAllData;
+ }
+
+ protected function IsDataFiltered() {
+ return $this->m_bDataFiltered;
+ }
+
+ protected function SetDataFiltered() {
+ $this->m_bDataFiltered = true;
+ }
// Create a search definition that leads to 0 result, still a valid search object
- static public function FromEmptySet($sClass)
- {
+ public static function FromEmptySet($sClass) {
$oResultFilter = new DBObjectSearch($sClass);
$oResultFilter->m_oSearchCondition = new FalseExpression;
+
return $oResultFilter;
}
- public function GetJoinedClasses() {return $this->m_aClasses;}
+ public function GetJoinedClasses() {
+ return $this->m_aClasses;
+ }
- public function GetClassName($sAlias)
- {
- if (array_key_exists($sAlias, $this->m_aSelectedClasses))
- {
+ public function GetClassName($sAlias) {
+ if (array_key_exists($sAlias, $this->m_aSelectedClasses)) {
return $this->m_aSelectedClasses[$sAlias];
- }
- else
- {
+ } else {
throw new CoreException("Invalid class alias '$sAlias'");
}
}
@@ -358,37 +377,35 @@ class DBObjectSearch extends DBSearch
}
foreach($this->m_aReferencedBy as $sForeignClass => $aReferences)
{
- foreach($aReferences as $sForeignExtKeyAttCode => $aFiltersByOperator)
- {
- foreach ($aFiltersByOperator as $iOperatorCode => $aFilters)
- {
- foreach ($aFilters as $oForeignFilter)
- {
+ foreach($aReferences as $sForeignExtKeyAttCode => $aFiltersByOperator) {
+ foreach ($aFiltersByOperator as $iOperatorCode => $aFilters) {
+ foreach ($aFilters as $oForeignFilter) {
$oForeignFilter->RenameParam($sOldName, $sNewName);
}
}
}
}
}
-
- public function ResetCondition()
- {
+
+ public function ResetCondition() {
$this->m_oSearchCondition = new TrueExpression();
// ? is that usefull/enough, do I need to rebuild the list after the subqueries ?
}
- public function MergeConditionExpression($oExpression)
- {
- $this->m_oSearchCondition = $this->m_oSearchCondition->LogOr($oExpression);
+ public function MergeConditionExpression($oExpression) {
+ $this->m_oSearchCondition = $this->m_oSearchCondition->LogOr($oExpression);
}
- public function AddConditionExpression($oExpression)
- {
- $this->m_oSearchCondition = $this->m_oSearchCondition->LogAnd($oExpression);
+ public function AddConditionExpression($oExpression) {
+ $this->m_oSearchCondition = $this->m_oSearchCondition->LogAnd($oExpression);
+
+ $bRootSearchAllowAllData = $this->IsAllDataAllowed();
+ $oExpression->Browse(function ($oThisExpression) use ($bRootSearchAllowAllData) {
+ ExpressionHelper::ExpressionAllowAllDataCallback($oThisExpression, $bRootSearchAllowAllData);
+ });
}
- public function AddNameCondition($sName)
- {
+ public function AddNameCondition($sName) {
$oValueExpr = new ScalarExpression($sName);
$oNameExpr = new FieldExpression('friendlyname', $this->GetClassAlias());
$oNewCondition = new BinaryExpression($oNameExpr, '=', $oValueExpr);
diff --git a/core/dbsearch.class.php b/core/dbsearch.class.php
index e5ce11999..e59493d80 100644
--- a/core/dbsearch.class.php
+++ b/core/dbsearch.class.php
@@ -97,42 +97,40 @@ abstract class DBSearch
/**
* Perform a deep clone (as opposed to "clone" which does copy a reference to the underlying objects)
*
- * @internal
- *
+ * @internal
+ *
* @return \DBSearch
- **/
+ **/
public function DeepClone()
{
return unserialize(serialize($this)); // Beware this serializes/unserializes the search and its parameters as well
}
- /**
- * whether or not some information should be hidden to the current user.
- *
- * @api
- * @see IsAllDataAllowed()
- *
- * @return mixed
- */
- abstract public function AllowAllData();
+ /**
+ * @api
+ * @see IsAllDataAllowed()
+ *
+ * @param bool $bAllowAllData whether or not some information should be hidden to the current user.
+ */
+ abstract public function AllowAllData($bAllowAllData = true);
- /**
- * Current state of AllowAllData
- *
- * @internal
- * @see AllowAllData()
- *
- * @return mixed
- */
+ /**
+ * Current state of AllowAllData
+ *
+ * @internal
+ * @see AllowAllData()
+ *
+ * @return mixed
+ */
abstract public function IsAllDataAllowed();
- /**
- * Should the archives be fetched
- *
- * @internal
- *
- * @param $bEnable
- */
+ /**
+ * Should the archives be fetched
+ *
+ * @internal
+ *
+ * @param $bEnable
+ */
public function SetArchiveMode($bEnable)
{
$this->m_bArchiveMode = $bEnable;
diff --git a/core/dbunionsearch.class.php b/core/dbunionsearch.class.php
index 721191bd3..a574af4b7 100644
--- a/core/dbunionsearch.class.php
+++ b/core/dbunionsearch.class.php
@@ -65,9 +65,7 @@ class DBUnionSearch extends DBSearch
{
$this->aSearches[] = $oSubSearch->DeepClone();
}
- }
- else
- {
+ } else {
$this->aSearches[] = $oSearch->DeepClone();
}
}
@@ -75,17 +73,16 @@ class DBUnionSearch extends DBSearch
$this->ComputeSelectedClasses();
}
- public function AllowAllData()
+ public function AllowAllData($bAllowAllData = true)
{
- foreach ($this->aSearches as $oSearch)
- {
+ foreach ($this->aSearches as $oSearch) {
$oSearch->AllowAllData();
}
}
+
public function IsAllDataAllowed()
{
- foreach ($this->aSearches as $oSearch)
- {
+ foreach ($this->aSearches as $oSearch) {
if ($oSearch->IsAllDataAllowed() === false) return false;
}
return true;
diff --git a/core/oql/expression.class.inc.php b/core/oql/expression.class.inc.php
index d67928a97..1c7773f90 100644
--- a/core/oql/expression.class.inc.php
+++ b/core/oql/expression.class.inc.php
@@ -1,24 +1,45 @@
-//
+/*
+ * Copyright (C) 2010-2020 Combodo SARL
+ *
+ * This file is part of iTop.
+ *
+ * iTop is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * iTop is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ */
-class MissingQueryArgument extends CoreException
-{
+class MissingQueryArgument extends CoreException {
+}
+
+
+class ExpressionHelper {
+ /**
+ * Callback to be used with {@link Expression::Browse}, to update the AllowAllData attribute in the NestedQueryExpression that are
+ * present in the Expression tree
+ *
+ * @param \Expression $oExpression
+ * @param boolean $bAllowAllData
+ *
+ * @uses \DBSearch::AllowAllData()
+ *
+ * @since 2.7.2 2.8.0 N°3324
+ */
+ public static function ExpressionAllowAllDataCallback($oExpression, $bAllowAllData) {
+ if (!($oExpression instanceof NestedQueryExpression)) {
+ return;
+ }
+
+ $oExpression->AllowAllData($bAllowAllData);
+ }
}
class NotYetEvaluatedExpression extends CoreException
@@ -28,8 +49,7 @@ class NotYetEvaluatedExpression extends CoreException
/**
* @method Check($oModelReflection, array $aAliases, $sSourceQuery)
*/
-abstract class Expression
-{
+abstract class Expression {
const OPERATOR_BINARY = 'binary';
const OPERATOR_BOOLEAN = 'boolean_binary';
const OPERATOR_FIELD = 'field';
@@ -183,9 +203,13 @@ abstract class Expression
}
/**
- * Recursively browse the expression tree
- * @param Closure $callback
- * @return mixed
+ * Recursively browse the expression tree.
+ *
+ * To access variables, specify them using the `use` keyword and the `&` to pass by reference if necessary
+ *
+ * @see https://www.php.net/manual/fr/functions.anonymous.php
+ *
+ * @param Closure $callback with current expression as parameter
*/
abstract public function Browse(Closure $callback);
@@ -197,6 +221,9 @@ abstract class Expression
// recursively list field parents ($aTable = array of sParent => dummy)
abstract public function CollectUsedParents(&$aTable);
+ /**
+ * @return boolean true if the expression's value is constant and evaluates to true, false otherwise
+ */
abstract public function IsTrue();
// recursively builds an array of [classAlias][fieldName] => value
@@ -205,8 +232,7 @@ abstract class Expression
// recursively builds an array of parameters to give to current request
abstract public function ListParameters();
- public function RequiresField($sClass, $sFieldName)
- {
+ public function RequiresField($sClass, $sFieldName) {
// #@# todo - optimize : this is called quite often when building a single query !
$aRequired = $this->ListRequiredFields();
if (!in_array($sClass.'.'.$sFieldName, $aRequired)) return false;
@@ -1036,12 +1062,15 @@ class MatchExpression extends BinaryExpression
* MatchExpression constructor.
*
* @param \FieldExpression $oLeftExpr
- * @param \ScalarExpression $oRightExpr
+ * @param \Expression $oRightExpr
*
* @throws \CoreException
*/
- public function __construct(FieldExpression $oLeftExpr, ScalarExpression $oRightExpr)
+ public function __construct(FieldExpression $oLeftExpr, Expression $oRightExpr)
{
+ if (!$oRightExpr instanceof ScalarExpression && !$oRightExpr instanceof VariableExpression) {
+ throw new CoreException('Only instance of ScalarExpression or VariableExpression are allowed in MATCHES '.get_class( $oRightExpr).' found', $oRightExpr);
+ }
parent::__construct($oLeftExpr, 'MATCHES', $oRightExpr);
}
@@ -2427,60 +2456,62 @@ class NestedQueryExpression extends Expression
}
/**/
- public function ApplyParameters($aArgs)
- {
+ public function ApplyParameters($aArgs) {
$this->m_oNestedQuery->ApplyParameters($aArgs);
}
/**/
- public function GetUnresolvedFields($sAlias, &$aUnresolved)
- {
+ public function GetUnresolvedFields($sAlias, &$aUnresolved) {
}
/**/
- public function Translate($aTranslationData, $bMatchAll = true, $bMarkFieldsAsResolved = true)
- {
+ public function Translate($aTranslationData, $bMatchAll = true, $bMarkFieldsAsResolved = true) {
// Check and prepare the select information
- $this->m_oNestedQuery->TranslateConditions($aTranslationData, $bMatchAll , $bMarkFieldsAsResolved );
+ $this->m_oNestedQuery->TranslateConditions($aTranslationData, $bMatchAll, $bMarkFieldsAsResolved);
+
return clone $this;
}
- public function ListRequiredFields()
- {
+ public function ListRequiredFields() {
return array();
}
- public function CollectUsedParents(&$aTable)
- {
+ public function CollectUsedParents(&$aTable) {
}
- public function ListConstantFields()
- {
+ public function ListConstantFields() {
return $this->m_oNestedQuery->ListConstantFields();
}
- public function ListParameters()
- {
+ public function ListParameters() {
return $this->m_oNestedQuery->ListParameters();
}
- public function RenameParam($sOldName, $sNewName)
- {
+ public function RenameParam($sOldName, $sNewName) {
$this->m_oNestedQuery->RenameParam($sOldName, $sNewName);
}
- public function RenameAlias($sOldName, $sNewName)
- {
+ public function RenameAlias($sOldName, $sNewName) {
$this->m_oNestedQuery->RenameAlias($sOldName, $sNewName);
}
/**
* @inheritDoc
*/
- public function ToJSON(&$aArgs = null, $bRetrofitParams = false)
- {
+ public function ToJSON(&$aArgs = null, $bRetrofitParams = false) {
return $this->m_oNestedQuery->ToJSON();
}
+
+ /**
+ * Simple indirection to {@link \DBObjectSearch::AllowAllData()}
+ *
+ * @param bool $bAllowAllData
+ *
+ * @uses \DBSearch::AllowAllData()
+ */
+ public function AllowAllData($bAllowAllData = true) {
+ $this->m_oNestedQuery->AllowAllData($bAllowAllData);
+ }
}
class FunctionExpression extends Expression
diff --git a/core/oql/oql-parser.php b/core/oql/oql-parser.php
index d2f752da4..c67ffff7a 100644
--- a/core/oql/oql-parser.php
+++ b/core/oql/oql-parser.php
@@ -1600,38 +1600,38 @@ static public $yy_action = array(
$this->_retvalue = new ListOqlExpression($this->yystack[$this->yyidx + -1]->minor);
}
#line 1606 "..\oql-parser.php"
-#line 132 "..\oql-parser.y"
+#line 131 "..\oql-parser.y"
function yy_r43(){
$this->_retvalue = new NestedQueryOqlExpression($this->yystack[$this->yyidx + -1]->minor);
}
#line 1611 "..\oql-parser.php"
-#line 147 "..\oql-parser.y"
+#line 146 "..\oql-parser.y"
function yy_r47(){
$this->_retvalue = array();
}
#line 1616 "..\oql-parser.php"
-#line 158 "..\oql-parser.y"
+#line 157 "..\oql-parser.y"
function yy_r51(){ $this->_retvalue = new IntervalOqlExpression($this->yystack[$this->yyidx + -1]->minor, $this->yystack[$this->yyidx + 0]->minor); }
#line 1619 "..\oql-parser.php"
-#line 171 "..\oql-parser.y"
+#line 170 "..\oql-parser.y"
function yy_r61(){ $this->_retvalue = new ScalarOqlExpression($this->yystack[$this->yyidx + 0]->minor); }
#line 1622 "..\oql-parser.php"
-#line 173 "..\oql-parser.y"
+#line 172 "..\oql-parser.y"
function yy_r63(){ $this->_retvalue = new ScalarOqlExpression(null); }
#line 1625 "..\oql-parser.php"
-#line 175 "..\oql-parser.y"
+#line 174 "..\oql-parser.y"
function yy_r64(){ $this->_retvalue = new FieldOqlExpression($this->yystack[$this->yyidx + 0]->minor); }
#line 1628 "..\oql-parser.php"
-#line 176 "..\oql-parser.y"
+#line 175 "..\oql-parser.y"
function yy_r65(){ $this->_retvalue = new FieldOqlExpression($this->yystack[$this->yyidx + 0]->minor, $this->yystack[$this->yyidx + -2]->minor); }
#line 1631 "..\oql-parser.php"
-#line 177 "..\oql-parser.y"
+#line 176 "..\oql-parser.y"
function yy_r66(){ $this->_retvalue=$this->yystack[$this->yyidx + 0]->minor; }
#line 1634 "..\oql-parser.php"
-#line 180 "..\oql-parser.y"
+#line 179 "..\oql-parser.y"
function yy_r67(){ $this->_retvalue = new VariableOqlExpression(substr($this->yystack[$this->yyidx + 0]->minor, 1)); }
#line 1637 "..\oql-parser.php"
-#line 182 "..\oql-parser.y"
+#line 181 "..\oql-parser.y"
function yy_r68(){
if ($this->yystack[$this->yyidx + 0]->minor[0] == '`')
{
@@ -1644,19 +1644,19 @@ static public $yy_action = array(
$this->_retvalue = new OqlName($name, $this->m_iColPrev);
}
#line 1650 "..\oql-parser.php"
-#line 193 "..\oql-parser.y"
+#line 192 "..\oql-parser.y"
function yy_r69(){$this->_retvalue=(int)$this->yystack[$this->yyidx + 0]->minor; }
#line 1653 "..\oql-parser.php"
-#line 194 "..\oql-parser.y"
+#line 193 "..\oql-parser.y"
function yy_r70(){$this->_retvalue=(int)-$this->yystack[$this->yyidx + 0]->minor; }
#line 1656 "..\oql-parser.php"
-#line 195 "..\oql-parser.y"
+#line 194 "..\oql-parser.y"
function yy_r71(){$this->_retvalue=new OqlHexValue($this->yystack[$this->yyidx + 0]->minor); }
#line 1659 "..\oql-parser.php"
-#line 196 "..\oql-parser.y"
+#line 195 "..\oql-parser.y"
function yy_r72(){$this->_retvalue=stripslashes(substr($this->yystack[$this->yyidx + 0]->minor, 1, strlen($this->yystack[$this->yyidx + 0]->minor) - 2)); }
#line 1662 "..\oql-parser.php"
-#line 199 "..\oql-parser.y"
+#line 198 "..\oql-parser.y"
function yy_r73(){$this->_retvalue=$this->yystack[$this->yyidx + 0]->minor; }
#line 1665 "..\oql-parser.php"
@@ -1940,7 +1940,7 @@ throw new OQLParserException($this->m_sSourceQuery, $this->m_iLine, $this->m_iCo
} while ($yymajor != self::YYNOCODE && $this->yyidx >= 0);
}
}
-#line 264 "..\oql-parser.y"
+#line 263 "..\oql-parser.y"
class OQLParserException extends OQLException
diff --git a/core/oql/oqlquery.class.inc.php b/core/oql/oqlquery.class.inc.php
index bc357c0c5..6a4bd5cd8 100644
--- a/core/oql/oqlquery.class.inc.php
+++ b/core/oql/oqlquery.class.inc.php
@@ -173,7 +173,7 @@ class MatchOqlExpression extends MatchExpression implements CheckableExpression
throw new OqlNormalizeException('Only "field MATCHES string" syntax is allowed', $sSourceQuery, new OqlName($this->m_oLeftExpr->RenderExpression(true), 0));
}
// Only field MATCHES scalar is allowed
- if (!$this->m_oRightExpr instanceof ScalarExpression)
+ if (!$this->m_oRightExpr instanceof ScalarExpression && !$this->m_oRightExpr instanceof VariableOqlExpression)
{
throw new OqlNormalizeException('Only "field MATCHES string" syntax is allowed', $sSourceQuery, new OqlName($this->m_oRightExpr->RenderExpression(true), 0));
}
diff --git a/core/oql/version.txt b/core/oql/version.txt
index 3c8103be0..26a3e601d 100644
--- a/core/oql/version.txt
+++ b/core/oql/version.txt
@@ -1 +1 @@
-2019-12-03
\ No newline at end of file
+2020-09-29
\ No newline at end of file
diff --git a/core/ormstopwatch.class.inc.php b/core/ormstopwatch.class.inc.php
index 3af604e2c..7bbe8e815 100644
--- a/core/ormstopwatch.class.inc.php
+++ b/core/ormstopwatch.class.inc.php
@@ -607,14 +607,22 @@ class CheckStopWatchThresholds implements iBackgroundProcess
// Activate any existing trigger
//
$sClassList = implode("', '", MetaModel::EnumParentClasses($sClass, ENUM_PARENT_CLASSES_ALL));
+
$oTriggerSet = new DBObjectSet(
- DBObjectSearch::FromOQL("SELECT TriggerOnThresholdReached AS t WHERE t.target_class IN ('$sClassList') AND stop_watch_code=:stop_watch_code AND threshold_index = :threshold_index"),
+ DBObjectSearch::FromOQL("SELECT TriggerOnThresholdReached AS t WHERE t.target_class IN ('$sClassList') AND stop_watch_code MATCHES :stop_watch_code AND threshold_index = :threshold_index"),
array(), // order by
array('stop_watch_code' => $sAttCode, 'threshold_index' => $iThreshold)
);
while ($oTrigger = $oTriggerSet->Fetch())
{
- $oTrigger->DoActivate($oObj->ToArgs('this'));
+ try
+ {
+ $oTrigger->DoActivate($oObj->ToArgs('this'));
+ }
+ catch(Exception $e)
+ {
+ utils::EnrichRaisedException($oTrigger, $e);
+ }
}
}
}
diff --git a/core/userrights.class.inc.php b/core/userrights.class.inc.php
index 68f48bb99..d2ffff0a1 100644
--- a/core/userrights.class.inc.php
+++ b/core/userrights.class.inc.php
@@ -1344,9 +1344,8 @@ class UserRights
// The bug has been fixed in PHP 7.2, but in case session_regenerate_id()
// fails we just silently ignore the error and keep the same session id...
$old_error_handler = set_error_handler(array(__CLASS__, 'VoidErrorHandler'));
- session_regenerate_id();
- if ($old_error_handler !== null)
- {
+ session_regenerate_id(true);
+ if ($old_error_handler !== null) {
set_error_handler($old_error_handler);
}
}
diff --git a/datamodels/2.x/itop-backup/ajax.backup.php b/datamodels/2.x/itop-backup/ajax.backup.php
index 7196242c3..528a48916 100644
--- a/datamodels/2.x/itop-backup/ajax.backup.php
+++ b/datamodels/2.x/itop-backup/ajax.backup.php
@@ -213,6 +213,9 @@ JS
break;
case 'download':
+ while (ob_get_level() > 0) {
+ ob_end_clean();
+ }
$sFile = utils::ReadParam('file', '', false, 'raw_data');
$oBackup = new DBBackupScheduled();
$sBackupDir = APPROOT.'data/backups/';
diff --git a/datamodels/2.x/itop-backup/dictionaries/de.dict.itop-backup.php b/datamodels/2.x/itop-backup/dictionaries/de.dict.itop-backup.php
index d6145c39b..b60f0cb1d 100644
--- a/datamodels/2.x/itop-backup/dictionaries/de.dict.itop-backup.php
+++ b/datamodels/2.x/itop-backup/dictionaries/de.dict.itop-backup.php
@@ -31,8 +31,8 @@ Dict::Add('DE DE', 'German', 'Deutsch', array(
'bkp-status-title' => 'Geplante Backups',
'bkp-status-checks' => 'Einstellungen und Prüfungen',
'bkp-mysqldump-ok' => 'mysqldump ist vorhanden: %1$s',
- 'bkp-mysqldump-notfound' => 'mysqldump wurde nicht gefunden: %1$s - Stellen sie sicher, das er eingespielt und im Pfad verfügbar ist oder editieren sie die Konfigurationsdatei um das MySQL bindir anzupassen.',
- 'bkp-mysqldump-issue' => 'mysqldump konnte nicht eingespielt werden (retcode=%1$d): Stellen sie sicher, das es installiert und im Pfad verfügbar ist oder editieren sie die Konfigurationsdatei um das MySQL bindir anzupassen.',
+ 'bkp-mysqldump-notfound' => 'mysqldump wurde nicht gefunden: %1$s - Stellen Sie sicher, das er eingespielt und im Pfad verfügbar ist oder editieren Sie die Konfigurationsdatei um das MySQL bindir anzupassen.',
+ 'bkp-mysqldump-issue' => 'mysqldump konnte nicht eingespielt werden (retcode=%1$d): Stellen Sie sicher, das es installiert und im Pfad verfügbar ist oder editieren Sie die Konfigurationsdatei um das MySQL bindir anzupassen.',
'bkp-missing-dir' => 'Zielverzeichniss %1$s nicht gefunden',
'bkp-free-disk-space' => '%1$s frei in %2$s',
'bkp-dir-not-writeable' => '%1$s ist nicht schreibbar',
@@ -53,8 +53,8 @@ Dict::Add('DE DE', 'German', 'Deutsch', array(
'bkp-next-backup' => 'Das nächste Backup wird am %1$s (%2$s) um %3$s durchgeführt',
'bkp-button-backup-now' => 'Starte Backup',
'bkp-button-restore-now' => 'Wiederherstellen!',
- 'bkp-confirm-backup' => 'Bitte bestätigen sie, dass sie jetzt ein Backup erstellen wollen now.',
- 'bkp-confirm-restore' => 'Bitte bestätigen sie, dass sie mit Backup %1$s eine Wiederherstellung durchführen wollen.',
+ 'bkp-confirm-backup' => 'Bitte bestätigen Sie, dass Sie jetzt ein Backup erstellen wollen.',
+ 'bkp-confirm-restore' => 'Bitte bestätigen Sie, dass Sie mit Backup %1$s eine Wiederherstellung durchführen wollen.',
'bkp-wait-backup' => 'Bitte warten, bis das Backup abgeschlossen ist ...',
'bkp-wait-restore' => 'Bitte warten, bis die Wiederherstellung abgeschlossen ist ...',
'bkp-success-restore' => 'Wiederherstellung erfolgreich.',
diff --git a/datamodels/2.x/itop-change-mgmt-itil/dictionaries/fr.dict.itop-change-mgmt-itil.php b/datamodels/2.x/itop-change-mgmt-itil/dictionaries/fr.dict.itop-change-mgmt-itil.php
index 4008350df..68c09c732 100644
--- a/datamodels/2.x/itop-change-mgmt-itil/dictionaries/fr.dict.itop-change-mgmt-itil.php
+++ b/datamodels/2.x/itop-change-mgmt-itil/dictionaries/fr.dict.itop-change-mgmt-itil.php
@@ -146,11 +146,11 @@ Dict::Add('FR FR', 'French', 'Français', array(
'Class:Change/Stimulus:ev_assign+' => '',
'Class:Change/Stimulus:ev_reopen' => 'Réouvrir',
'Class:Change/Stimulus:ev_reopen+' => '',
- 'Class:Change/Stimulus:ev_plan' => 'Plannifier',
+ 'Class:Change/Stimulus:ev_plan' => 'Planifier',
'Class:Change/Stimulus:ev_plan+' => '',
'Class:Change/Stimulus:ev_approve' => 'Approuver',
'Class:Change/Stimulus:ev_approve+' => '',
- 'Class:Change/Stimulus:ev_replan' => 'Replannifier',
+ 'Class:Change/Stimulus:ev_replan' => 'Replanifier',
'Class:Change/Stimulus:ev_replan+' => '',
'Class:Change/Stimulus:ev_notapprove' => 'Ne pas approuver',
'Class:Change/Stimulus:ev_notapprove+' => '',
@@ -177,11 +177,11 @@ Dict::Add('FR FR', 'French', 'Français', array(
'Class:RoutineChange/Stimulus:ev_assign+' => '',
'Class:RoutineChange/Stimulus:ev_reopen' => 'Réouvrir',
'Class:RoutineChange/Stimulus:ev_reopen+' => '',
- 'Class:RoutineChange/Stimulus:ev_plan' => 'Plannifier',
+ 'Class:RoutineChange/Stimulus:ev_plan' => 'Planifier',
'Class:RoutineChange/Stimulus:ev_plan+' => '',
'Class:RoutineChange/Stimulus:ev_approve' => 'Approver',
'Class:RoutineChange/Stimulus:ev_approve+' => '',
- 'Class:RoutineChange/Stimulus:ev_replan' => 'Replannifier',
+ 'Class:RoutineChange/Stimulus:ev_replan' => 'Replanifier',
'Class:RoutineChange/Stimulus:ev_replan+' => '',
'Class:RoutineChange/Stimulus:ev_notapprove' => 'Ne pas approver',
'Class:RoutineChange/Stimulus:ev_notapprove+' => '',
@@ -212,11 +212,11 @@ Dict::Add('FR FR', 'French', 'Français', array(
'Class:ApprovedChange/Stimulus:ev_assign+' => '',
'Class:ApprovedChange/Stimulus:ev_reopen' => 'Réouvrir',
'Class:ApprovedChange/Stimulus:ev_reopen+' => '',
- 'Class:ApprovedChange/Stimulus:ev_plan' => 'Plannifier',
+ 'Class:ApprovedChange/Stimulus:ev_plan' => 'Planifier',
'Class:ApprovedChange/Stimulus:ev_plan+' => '',
'Class:ApprovedChange/Stimulus:ev_approve' => 'Approuver',
'Class:ApprovedChange/Stimulus:ev_approve+' => '',
- 'Class:ApprovedChange/Stimulus:ev_replan' => 'Replannifier',
+ 'Class:ApprovedChange/Stimulus:ev_replan' => 'Replanifier',
'Class:ApprovedChange/Stimulus:ev_replan+' => '',
'Class:ApprovedChange/Stimulus:ev_notapprove' => 'Ne pas approuver',
'Class:ApprovedChange/Stimulus:ev_notapprove+' => '',
@@ -247,11 +247,11 @@ Dict::Add('FR FR', 'French', 'Français', array(
'Class:NormalChange/Stimulus:ev_assign+' => '',
'Class:NormalChange/Stimulus:ev_reopen' => 'Réouvrir',
'Class:NormalChange/Stimulus:ev_reopen+' => '',
- 'Class:NormalChange/Stimulus:ev_plan' => 'Plannifier',
+ 'Class:NormalChange/Stimulus:ev_plan' => 'Planifier',
'Class:NormalChange/Stimulus:ev_plan+' => '',
'Class:NormalChange/Stimulus:ev_approve' => 'Approuver',
'Class:NormalChange/Stimulus:ev_approve+' => '',
- 'Class:NormalChange/Stimulus:ev_replan' => 'Replannifier',
+ 'Class:NormalChange/Stimulus:ev_replan' => 'Replanifier',
'Class:NormalChange/Stimulus:ev_replan+' => '',
'Class:NormalChange/Stimulus:ev_notapprove' => 'Ne pas approuver',
'Class:NormalChange/Stimulus:ev_notapprove+' => '',
@@ -278,11 +278,11 @@ Dict::Add('FR FR', 'French', 'Français', array(
'Class:EmergencyChange/Stimulus:ev_assign+' => '',
'Class:EmergencyChange/Stimulus:ev_reopen' => 'Réouvrir',
'Class:EmergencyChange/Stimulus:ev_reopen+' => '',
- 'Class:EmergencyChange/Stimulus:ev_plan' => 'Plannifier',
+ 'Class:EmergencyChange/Stimulus:ev_plan' => 'Planifier',
'Class:EmergencyChange/Stimulus:ev_plan+' => '',
'Class:EmergencyChange/Stimulus:ev_approve' => 'Approuver',
'Class:EmergencyChange/Stimulus:ev_approve+' => '',
- 'Class:EmergencyChange/Stimulus:ev_replan' => 'Replannifier',
+ 'Class:EmergencyChange/Stimulus:ev_replan' => 'Replanifier',
'Class:EmergencyChange/Stimulus:ev_replan+' => '',
'Class:EmergencyChange/Stimulus:ev_notapprove' => 'Ne pas approuver',
'Class:EmergencyChange/Stimulus:ev_notapprove+' => '',
diff --git a/datamodels/2.x/itop-hub-connector/hubconnectorpage.class.inc.php b/datamodels/2.x/itop-hub-connector/hubconnectorpage.class.inc.php
index f1782e9e6..9bbb2da35 100644
--- a/datamodels/2.x/itop-hub-connector/hubconnectorpage.class.inc.php
+++ b/datamodels/2.x/itop-hub-connector/hubconnectorpage.class.inc.php
@@ -5,9 +5,12 @@ class HubConnectorPage extends NiceWebPage
public function __construct($sTitle)
{
parent::__construct($sTitle);
-
- $this->add_header("Cache-control: no-cache");
-
+
+ $this->add_header('Cache-control: no-cache, no-store, must-revalidate');
+ $this->add_header('Pragma: no-cache');
+ $this->add_header('Expires: 0');
+ $this->add_header('X-Frame-Options: deny');
+
$sImagesDir = utils::GetAbsoluteUrlAppRoot().'images';
$sModuleImagesDir = utils::GetAbsoluteUrlModulesRoot().'itop-hub-connector/images';
diff --git a/datamodels/2.x/itop-portal-base/portal/config/legacy_silex_compat_layer.php b/datamodels/2.x/itop-portal-base/portal/config/legacy_silex_compat_layer.php
index 06e69d1d7..a92e34260 100644
--- a/datamodels/2.x/itop-portal-base/portal/config/legacy_silex_compat_layer.php
+++ b/datamodels/2.x/itop-portal-base/portal/config/legacy_silex_compat_layer.php
@@ -34,23 +34,30 @@ $oModuleDesign = new ModuleDesign($_ENV['PORTAL_ID']);
// Load portal conf. such as properties, themes, templates, ...
// Append into %combodo.portal.instance.conf%
+$oKPI = new ExecutionKPI();
$oBasicCompat = new Basic($oModuleDesign);
$oBasicCompat->Process($container);
+$oKPI->ComputeAndReport('Load portal conf. such as properties, themes, templates, ...');
// Load portal forms definition
// Append into %combodo.portal.instance.conf%
+$oKPI = new ExecutionKPI();
$oFormsCompat = new Forms($oModuleDesign);
$oFormsCompat->Process($container);
+$oKPI->ComputeAndReport('Load portal forms definition');
// Load portal lists definition
// Append into %combodo.portal.instance.conf%
+$oKPI = new ExecutionKPI();
$oListsCompat = new Lists($oModuleDesign);
$oListsCompat->Process($container);
+$oKPI->ComputeAndReport('Load portal lists definition');
// Generating CSS files
// Note: We do this here as it is not user dependent and therefore can be cached for everyone.
// A dedicated listener 'CssFromSassCompiler' exists to compile files again when by-passing HTTP cache.
// This is to keep developers comfort when tuning the SCSS files.
+$oKPI = new ExecutionKPI();
$aImportPaths = array($_ENV['COMBODO_PORTAL_BASE_ABSOLUTE_PATH'].'css/');
$aPortalConf = $container->getParameter('combodo.portal.instance.conf');
foreach ($aPortalConf['properties']['themes'] as $sKey => $value)
@@ -71,4 +78,6 @@ foreach ($aPortalConf['properties']['themes'] as $sKey => $value)
$aPortalConf['properties']['themes'][$sKey] = $aValues;
}
}
+$oKPI->ComputeAndReport('Generating CSS files');
+
$container->setParameter('combodo.portal.instance.conf', $aPortalConf);
\ No newline at end of file
diff --git a/datamodels/2.x/itop-portal-base/portal/public/index.php b/datamodels/2.x/itop-portal-base/portal/public/index.php
index 04d090984..b9b7539d2 100644
--- a/datamodels/2.x/itop-portal-base/portal/public/index.php
+++ b/datamodels/2.x/itop-portal-base/portal/public/index.php
@@ -24,23 +24,38 @@ require_once MODULESROOT.'itop-portal-base/portal/config/bootstrap.php';
// Stacking context tag so it knows we are in the portal
$oContext = new ContextTag(ContextTag::TAG_PORTAL);
-$oContext2 = new ContextTag('Portal:' . $_ENV['PORTAL_ID']);
+$oContext2 = new ContextTag('Portal:'.$_ENV['PORTAL_ID']);
+
+
+$oKPI = new ExecutionKPI();
// Note: Manually refactored ternary condition to be PHP 5.x compatible
-if ($trustedProxies = isset($_SERVER['TRUSTED_PROXIES']) ? $_SERVER['TRUSTED_PROXIES'] : (isset($_ENV['TRUSTED_PROXIES']) ? $_ENV['TRUSTED_PROXIES'] : false))
-{
+if ($trustedProxies = isset($_SERVER['TRUSTED_PROXIES']) ? $_SERVER['TRUSTED_PROXIES'] : (isset($_ENV['TRUSTED_PROXIES']) ? $_ENV['TRUSTED_PROXIES'] : false)) {
Request::setTrustedProxies(explode(',', $trustedProxies), Request::HEADER_X_FORWARDED_ALL ^ Request::HEADER_X_FORWARDED_HOST);
}
// Note: Manually refactored ternary condition to be PHP 5.x compatible
-if ($trustedHosts = isset($_SERVER['TRUSTED_HOSTS']) ? $_SERVER['TRUSTED_HOSTS'] : (isset($_ENV['TRUSTED_HOSTS']) ? $_ENV['TRUSTED_HOSTS'] : false))
-{
+if ($trustedHosts = isset($_SERVER['TRUSTED_HOSTS']) ? $_SERVER['TRUSTED_HOSTS'] : (isset($_ENV['TRUSTED_HOSTS']) ? $_ENV['TRUSTED_HOSTS'] : false)) {
Request::setTrustedHosts([$trustedHosts]);
}
$oKernel = new Kernel($_SERVER['APP_ENV'], (bool)$_SERVER['APP_DEBUG']);
+$oKPI->ComputeAndReport('Symfony kernel init');
+
+$oKPI = new ExecutionKPI();
$oRequest = Request::createFromGlobals();
+$oKPI->ComputeAndReport('Symfony request parsing/creation');
+
+$oKPI = new ExecutionKPI();
/** @noinspection PhpUnhandledExceptionInspection */
$oResponse = $oKernel->handle($oRequest);
$oResponse->send();
+$oKPI->ComputeAndReport('Page execution and rendering');
+
+
+$oKPI = new ExecutionKPI();
$oKernel->terminate($oRequest, $oResponse);
+$oKPI->ComputeAndReport('Symfony kernel termination');
+
+
+ExecutionKPI::ReportStats();
\ No newline at end of file
diff --git a/datamodels/2.x/itop-portal-base/portal/src/EventListener/ExceptionListener.php b/datamodels/2.x/itop-portal-base/portal/src/EventListener/ExceptionListener.php
index 0dd8638bd..633acea61 100644
--- a/datamodels/2.x/itop-portal-base/portal/src/EventListener/ExceptionListener.php
+++ b/datamodels/2.x/itop-portal-base/portal/src/EventListener/ExceptionListener.php
@@ -93,7 +93,7 @@ class ExceptionListener implements ContainerAwareInterface
'exception' => $oFlattenException,
'code' => $iStatusCode,
'error_title' => $sErrorTitle,
- 'error_message' => $sErrorMessage,
+ 'error_message' => '',
);
// Generate the response
diff --git a/datamodels/2.x/itop-portal-base/portal/src/Form/ObjectFormManager.php b/datamodels/2.x/itop-portal-base/portal/src/Form/ObjectFormManager.php
index 835099838..11c9f3995 100644
--- a/datamodels/2.x/itop-portal-base/portal/src/Form/ObjectFormManager.php
+++ b/datamodels/2.x/itop-portal-base/portal/src/Form/ObjectFormManager.php
@@ -1139,7 +1139,14 @@ class ObjectFormManager extends FormManager
/** @var \Trigger $oTrigger */
while ($oTrigger = $oTriggerSet->Fetch())
{
- $oTrigger->DoActivate($this->oObject->ToArgs('this'));
+ try
+ {
+ $oTrigger->DoActivate($this->oObject->ToArgs('this'));
+ }
+ catch(Exception $e)
+ {
+ utils::EnrichRaisedException($oTrigger, $e);
+ }
}
}
}
diff --git a/datamodels/2.x/itop-tickets/module.itop-tickets.php b/datamodels/2.x/itop-tickets/module.itop-tickets.php
index 478b6e0e7..4fc4e1c2d 100755
--- a/datamodels/2.x/itop-tickets/module.itop-tickets.php
+++ b/datamodels/2.x/itop-tickets/module.itop-tickets.php
@@ -55,9 +55,16 @@ class TicketsInstaller extends ModuleInstallerAPI
$oSet = new DBObjectSet($oSearch);
while($oTrigger = $oSet->Fetch())
{
- if (!MetaModel::IsValidClass($oTrigger->Get('target_class')))
+ try
{
- $oTrigger->DBDelete();
+ if (!MetaModel::IsValidClass($oTrigger->Get('target_class')))
+ {
+ $oTrigger->DBDelete();
+ }
+ }
+ catch(Exception $e)
+ {
+ utils::EnrichRaisedException($oTrigger, $e);
}
}
}
diff --git a/dictionaries/fr.dictionary.itop.ui.php b/dictionaries/fr.dictionary.itop.ui.php
index 662c8d3f4..296d3ab2e 100644
--- a/dictionaries/fr.dictionary.itop.ui.php
+++ b/dictionaries/fr.dictionary.itop.ui.php
@@ -339,7 +339,7 @@ Dict::Add('FR FR', 'French', 'Français', array(
'UI:WelcomeMenu:LeftBlock' => '
iTop est un portail opérationnel complet et libre pour gérer votre SI.
il contient:
-- Une base de gestion des configuration (CMDB - Configuration management database) pour documenter et gérer votre parc informatique.
+- Une base de gestion des configurations (CMDB - Configuration management database) pour documenter et gérer votre parc informatique.
- Un module de gestion des incidents pour suivre les incidents d\'exploitation et gérer la communication à propos de ces incidents.
- Un module de gestion des changements pour planifier et suivre les modifications de votre SI.
- Une base des erreurs connues, pour accélérer la résolution des incidents.
@@ -355,7 +355,7 @@ Dict::Add('FR FR', 'French', 'Français', array(
- Améliorer la satisfaction client et fournir aux responsables des vues sur la performance interne du SI.
-iTop est complètement ouvert pour s\'intéger avec votre environnement informatique.
+iTop est complètement ouvert pour s\'intégrer avec votre environnement informatique.