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.

-

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.