Compare commits

..

2 Commits

Author SHA1 Message Date
Eric Espie
8bd72409f1 N°6716 - High memory Consomption and performance issue 2023-09-14 15:16:11 +02:00
Eric Espie
3eb06f8ada N°6716 - High memory Consomption and performance issue 2023-09-14 14:38:17 +02:00
2790 changed files with 57087 additions and 85009 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.0 MiB

View File

@@ -1,14 +1,7 @@
# iTop version history
```mermaid
%%{init: { 'logLevel': 'debug', 'theme': 'base', 'themeVariables': {
'git0': 'lawngreen',
'git3': 'dodgerblue',
'git4': 'grey',
'git5': 'grey',
'git6': 'grey',
'git7': 'grey'
}, 'gitGraph': {'showBranches': true,'mainBranchName': 'develop','rotateCommitLabel': true}} }%%
%%{init: { 'logLevel': 'debug', 'theme': 'base', 'gitGraph': {'showBranches': true,'mainBranchName': 'develop','rotateCommitLabel': true}} }%%
gitGraph
commit id: "2016-07-06" tag: "2.3.0" type: HIGHLIGHT
branch support/2.3 order: 900
@@ -75,10 +68,6 @@ gitGraph
branch support/3.1 order: 840
checkout support/3.1
commit id: "2023-08-09" tag: "3.1.0-2"
checkout support/2.7
commit id: "2023-08-10" tag: "2.7.9"
checkout support/3.1
commit id: "2023-12-20" tag: "3.1.1"
```
To learn more, check the [iTop community versions history on the official wiki](https://www.itophub.io/wiki/page?id=latest:release:start).

View File

@@ -1,83 +0,0 @@
<!--
IMPORTANT: Please follow the guidelines within this PR template before submitting it, it will greatly help us process your PR. 🙏
Any PRs not following the guidelines or with missing information will not be considered.
-->
## Base information
| Question | Answer
|---------------------------------------------------------------|--------
| Related to a SourceForge thead / Another PR / Combodo ticket? | <!-- Put the URL -->
| Type of change? | Bug fix / Enhancement / Translations
## Symptom (bug) / Objective (enhancement)
<!--
If it's a bug
- Explain the symptom in details
- If possible put error messages, logs or screenshots (you can paste image directly in this editor).
If it's an enhancement
- Describe what is blocking you, what is the objective with as much details as possible.
- Add screenshots if it's related to UI.
-->
## Reproduction procedure (bug)
<!--
Remove this section only if it's NOT a bug.
Otherwise, explain step by step how to reproduce the issue on a standard iTop Community.
If it requires a custom datamodel, provide the minimal XML delta to reproduce it on a standard iTop Community.
-->
1. On iTop x.y.z <!-- Put complete iTop version (eg. 3.1.0-2) -->
2. With PHP x.y.z <!-- Put complete PHP version (eg. 8.1.24) -->
2. First go there
2. Then do that
3. ...
4. Finally, see that...
## Cause (bug)
<!--
Remove this section only if it's NOT a bug.
Otherwise, explain what is the cause of the issue (where in the code and why)
-->
## Proposed solution (bug and enhancement)
<!--
Explain in details how you are proposing to solve this:
- What did you do in the code and why
- If you changed something in the UI, put before / after screenshots (you can paste image directly in this editor)
-->
## Checklist before requesting a review
<!--
Don't remove these lines, check them once done.
-->
- [ ] I have performed a self-review of my code
- [ ] I have tested all changes I made on an iTop instance
- [ ] I have added a unit test, otherwise I have explained why I couldn't
- [ ] Is the PR clear and detailled enough so anyone can understand digging in the code?
## Checklist of things to do before PR is ready to merge
<!--
Things that needs to be done in the PR before it can be considered as ready to be merged
Examples:
- Changes requested in the review
- Unit test to add
- Dictionary entries to translate
- ...
-->
- [ ] ...
- [ ] ...
- [ ] ...

6
.gitignore vendored
View File

@@ -37,9 +37,7 @@ tests/*/vendor/*
# iTop extensions
/extensions/**
!/extensions/.htaccess
!/extensions/readme.txt
!/extensions/web.config
# all logs but listing prevention
/log/**
@@ -47,10 +45,8 @@ tests/*/vendor/*
!/log/index.php
!/log/web.config
# PHPUnit: Cache file, local XML working copies
# PHPUnit cache file
/tests/php-unit-tests/.phpunit.result.cache
/tests/php-unit-tests/phpunit.xml
/tests/php-unit-tests/postbuild_integration.xml
# Jetbrains

View File

@@ -22,13 +22,13 @@ $iElapsed = time() - $iBeginTime;
if (count($aFailedCommands))
{
fwrite(STDERR, "\nafterBuild execution failed! (in {$iElapsed}s)\n");
fwrite(STDERR, "\nafterBuild execution failed! (in ${iElapsed}s)\n");
fwrite(STDERR, "List of failling commands:\n - " . implode("\n - ", $aFailedCommands) . "\n");
exit(1);
}
echo "\nDone ({$iElapsed}s)\n";
echo "\nDone (${iElapsed}s)\n";
exit(0);
/**
@@ -74,7 +74,7 @@ function ExecCommand($cmd) {
}
else
{
echo "| elapsed:{$iElapsed}s \n";
echo "| elapsed:${iElapsed}s \n";
}
if (!empty($stderr))

View File

@@ -1,56 +0,0 @@
courier.php
courierb.php
courierbi.php
courieri.php
dejavusans.ctg.z
dejavusans.php
dejavusans.z
dejavusansb.ctg.z
dejavusansb.php
dejavusansb.z
dejavusansbi.ctg.z
dejavusansbi.php
dejavusansbi.z
dejavusanscondensed.ctg.z
dejavusanscondensed.php
dejavusanscondensed.z
dejavusanscondensedb.ctg.z
dejavusanscondensedb.php
dejavusanscondensedb.z
dejavusanscondensedbi.ctg.z
dejavusanscondensedbi.php
dejavusanscondensedbi.z
dejavusanscondensedi.ctg.z
dejavusanscondensedi.php
dejavusanscondensedi.z
dejavusansextralight.ctg.z
dejavusansextralight.php
dejavusansextralight.z
dejavusansi.ctg.z
dejavusansi.php
dejavusansi.z
dejavusansmono.ctg.z
dejavusansmono.php
dejavusansmono.z
dejavusansmonob.ctg.z
dejavusansmonob.php
dejavusansmonob.z
dejavusansmonobi.ctg.z
dejavusansmonobi.php
dejavusansmonobi.z
dejavusansmonoi.ctg.z
dejavusansmonoi.php
dejavusansmonoi.z
droidsansfallback.ctg.z
droidsansfallback.php
droidsansfallback.z
helvetica.php
helveticab.php
helveticabi.php
helveticai.php
symbol.php
times.php
timesb.php
timesbi.php
timesi.php
zapfdingbats.php

View File

@@ -1,101 +0,0 @@
<?php
/**
* This script will copy custom fonts in the TCPDF lib fonts directory.
* If you need to add other files :
* - add the corresponding files in this script directory
* - modify this script to copy also your files
*
* @since 2.7.0 N°1947 add DroidSansFallback font (see also PR #49 in the links below)
* @since 2.7.0 N°2435 TCPPDF lib forked and added in composer.json (at that time the lib was announced as deprecated and rewritten in tecnickcom/tc-lib-pdf)
* @since 3.2.0 N°7175 switch back to TCPDF original lib (which is finally still maintained, tecnickcom/tc-lib-pdf us still under dev), script creation to keep custom DroidSansFallback font
*
* @link https://github.com/Combodo/iTop/pull/49 add DroidSansFallback font
* @link https://github.com/tecnickcom/TCPDF?tab=readme-ov-file#note TCPDF is in support only mode
*/
$sItopRootFolder = realpath(__DIR__ . "/../../../");
$sCurrentScriptFileName = basename(__FILE__);
require_once ("$sItopRootFolder/lib/autoload.php");
$sTcPdfRootFolder = $sItopRootFolder.'/lib/tecnickcom/tcpdf';
if (false === file_exists($sTcPdfRootFolder)) {
echo $sCurrentScriptFileName.": No TCPDF lib detected, exiting !\n";
return;
}
$sTcPdfFontsFolder = $sTcPdfRootFolder.'/Fonts/';
/**
* 1) Cleaning up the fonts directory to keep only the ones we want in iTop
*/
echo $sCurrentScriptFileName.": ---1) Cleaning up the fonts files\n";
$aTcpdfDefaultFontsToKeepInItop = file(__DIR__.'/tcpdfDefaultFontsToKeepInItop.txt', FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
$aTcpdfFontsDirContent = scandir($sTcPdfFontsFolder);
foreach ($aTcpdfFontsDirContent as $sTcpdfFontResourceName) {
if ($sTcpdfFontResourceName === '.') {
continue;
}
if ($sTcpdfFontResourceName === '..') {
continue;
}
if (!in_array($sTcpdfFontResourceName, $aTcpdfDefaultFontsToKeepInItop, true)) {
echo $sCurrentScriptFileName.": Removing $sTcpdfFontResourceName !\n";
$sTcpdfFontResourceFullPath = $sTcPdfFontsFolder.$sTcpdfFontResourceName;
if (is_file($sTcpdfFontResourceFullPath)) {
unlink($sTcpdfFontResourceFullPath);
} elseif (is_dir($sTcpdfFontResourceFullPath)) {
rrmdir($sTcpdfFontResourceFullPath);
}
}
}
/**
* 2) Then adding the DroidSansFallback font (useful for CJK data for example)
*/
echo $sCurrentScriptFileName.": ---2) Copying font files to TCPDF ($sTcPdfFontsFolder)...\n";
$aFontFilesToCopy = glob(__DIR__.'\droidsansfallback.*');
foreach ($aFontFilesToCopy as $sFontFileToCopy) {
$sFontFileName = basename($sFontFileToCopy);
echo $sCurrentScriptFileName.': copying '.$sFontFileName."\n";
copy($sFontFileToCopy, $sTcPdfFontsFolder.$sFontFileName);
}
echo $sCurrentScriptFileName.": Done !\n";
/*-----------------------------------------------------------------------------------------------*/
/**
* Recursively delete a directory and its content
*
* @param $sDirToRemovePath
*
* @return void
*/
function rrmdir($sDirToRemovePath):void
{
if (is_dir($sDirToRemovePath)) {
$objects = scandir($sDirToRemovePath);
foreach ($objects as $object) {
if ($object != "." && $object != "..") {
if (filetype($sDirToRemovePath."/".$object) == "dir") {
rrmdir($sDirToRemovePath."/".$object);
} else {
unlink($sDirToRemovePath."/".$object);
}
}
}
reset($objects);
rmdir($sDirToRemovePath);
}
}

View File

@@ -140,7 +140,7 @@ When your code is working, please:
* Pull request description: mind to add all the information useful to understand why you're suggesting this modification and anything necessary to dive into your work. Especially:
- Bugfixes: exact steps to reproduce the bug (given/when/then), description of the bug cause and what solution is implemented
- Enhancements: use cases, implementation details if needed
* Mind to check the "[Allow edits from maintainers](https://docs.github.com/en/github-ae@latest/pull-requests/collaborating-with-pull-requests/working-with-forks/allowing-changes-to-a-pull-request-branch-created-from-a-fork)" option ! (note that if you are working with an org fork, this option [won't be available](https://github.com/orgs/community/discussions/5634))
* Mind to check the "[Allow edits from maintainers](https://docs.github.com/en/github-ae@latest/pull-requests/collaborating-with-pull-requests/working-with-forks/allowing-changes-to-a-pull-request-branch-created-from-a-fork)" option !
## 🙏 We are thankful
@@ -161,4 +161,4 @@ We have one sticker per contribution type. You might get multiple stickers with
Here is the design of each stickers for year 2022:
![iTop stickers 2023](.doc/contributing-guide/2023.contributing-stickers-side-by-side.png)
![iTop stickers 2022](.doc/contributing-guide/2022.contributing-stickers-side-by-side.png)

View File

@@ -87,11 +87,9 @@ We would like to give a special thank you 🤗 to the people from the community
- Castro, Randall Badilla
- Colantoni, Maria Laura
- Couronné, Guy
- Dejin, Bie (a.k.a [@bdejin](https://github.com/bdejin))
- Dvořák, Lukáš
- Goethals, Stefan
- Gumble, David
- Ji, Leeb (冀利斌) (a.k.a [@chileeb](https://github.com/chileeb))
- Kaltefleiter, Lars (a.k.a [@larhip](https://www.github.com/larhip))
- Khamit, Shamil
- Kincel, Martin
@@ -107,12 +105,9 @@ We would like to give a special thank you 🤗 to the people from the community
- Roháč, Richard (a.k.a [@RohacRichard](https://github.com/RohacRichard))
- Rosenke, Stephan
- Rudner, Björn (a.k.a [@rudnerbjoern](https://github.com/rudnerbjoern))
- Šafránek, Jaroslav (a.k.a [jkcinik](https://sourceforge.net/u/jkcinik/profile/) on SourceForge)
- Seki, Shoji
- Shilov, Vladimir
- Stetina, Pavel (a.k.a [@Stetinac](https://github.com/Stetinac))
- Stukalov, Ilya (a.k.a [@ilya](https://www.github.com/ilya)-stukalov)
- Tarjányi, Csaba (a.k.a [@tacsaby](https://github.com/tacsaby))
- Tulio, Marco
- Turrubiates, Miguel

View File

@@ -4,8 +4,6 @@
* @license http://opensource.org/licenses/AGPL-3.0
*/
use Combodo\iTop\Application\WebPage\WebPage;
define('ADMIN_PROFILE_NAME', 'Administrator');
define('PORTAL_PROFILE_NAME', 'Portal user');
@@ -448,12 +446,6 @@ class UserRightsProfile extends UserRightsAddOnAPI
UR_ACTION_BULK_DELETE => 'bd',
);
/**
* @var array $aUsersProfilesList Cache of users' profiles. Hash array of user ID => [profile ID => profile friendlyname, profile ID => profile friendlyname, ...]
* @since 2.7.10 3.0.4 3.1.1 3.2.0 N°6887
*/
private $aUsersProfilesList = [];
// Installation: create the very first user
public function CreateAdministrator($sAdminUser, $sAdminPwd, $sLanguage = 'EN US')
{
@@ -510,7 +502,6 @@ class UserRightsProfile extends UserRightsAddOnAPI
}
protected $m_aUserOrgs = array(); // userid -> array of orgid
protected $m_aAdministrators = null; // [user id]
// Built on demand, could be optimized if necessary (doing a query for each attribute that needs to be read)
protected $m_aObjectActionGrants = array();
@@ -567,7 +558,6 @@ class UserRightsProfile extends UserRightsAddOnAPI
// Cache
$this->m_aObjectActionGrants = array();
$this->m_aAdministrators = null;
}
public function LoadCache()
@@ -710,10 +700,12 @@ class UserRightsProfile extends UserRightsAddOnAPI
*/
private function GetAdministrators()
{
if ($this->m_aAdministrators === null)
static $aAdministrators = null;
if ($aAdministrators === null)
{
// Find all administrators
$this->m_aAdministrators = array();
$aAdministrators = array();
$oAdministratorsFilter = new DBObjectSearch('User');
$oLnkFilter = new DBObjectSearch('URP_UserProfile');
$oExpression = new FieldExpression('profileid', 'URP_UserProfile');
@@ -726,10 +718,10 @@ class UserRightsProfile extends UserRightsAddOnAPI
$oSet->OptimizeColumnLoad(array('User' => array('login')));
while($oUser = $oSet->Fetch())
{
$this->m_aAdministrators[] = $oUser->GetKey();
$aAdministrators[] = $oUser->GetKey();
}
}
return $this->m_aAdministrators;
return $aAdministrators;
}
/**
@@ -766,12 +758,8 @@ class UserRightsProfile extends UserRightsAddOnAPI
$sAction = self::$m_aActionCodes[$iActionCode];
$bStatus = null;
// Cache user's profiles
if(false === array_key_exists($iUser, $this->aUsersProfilesList)){
$this->aUsersProfilesList[$iUser] = UserRights::ListProfiles($oUser);
}
// Call the API of UserRights because it caches the list for us
foreach($this->aUsersProfilesList[$iUser] as $iProfile => $oProfile)
foreach(UserRights::ListProfiles($oUser) as $iProfile => $oProfile)
{
$bGrant = $this->GetProfileActionGrant($iProfile, $sClass, $sAction);
if (!is_null($bGrant))
@@ -897,16 +885,11 @@ class UserRightsProfile extends UserRightsAddOnAPI
// Note: this code is VERY close to the code of IsActionAllowed()
$iUser = $oUser->GetKey();
// Cache user's profiles
if(false === array_key_exists($iUser, $this->aUsersProfilesList)){
$this->aUsersProfilesList[$iUser] = UserRights::ListProfiles($oUser);
}
// Note: The object set is ignored because it was interesting to optimize for huge data sets
// and acceptable to consider only the root class of the object set
$bStatus = null;
// Call the API of UserRights because it caches the list for us
foreach($this->aUsersProfilesList[$iUser] as $iProfile => $oProfile)
foreach(UserRights::ListProfiles($oUser) as $iProfile => $oProfile)
{
$bGrant = $this->GetClassStimulusGrant($iProfile, $sClass, $sStimulusCode);
if (!is_null($bGrant))
@@ -935,9 +918,8 @@ class UserRightsProfile extends UserRightsAddOnAPI
}
/**
* @param string $sClass
* @return string|null Find out which attribute is corresponding the dimension 'owner org'
* returns null if no such attribute has been found (no filtering should occur)
* Find out which attribute is corresponding the the dimension 'owner org'
* returns null if no such attribute has been found (no filtering should occur)
*/
public static function GetOwnerOrganizationAttCode($sClass)
{

View File

@@ -17,8 +17,6 @@
* You should have received a copy of the GNU Affero General Public License
*/
use Combodo\iTop\Application\WebPage\WebPage;
define('ADMIN_PROFILE_NAME', 'Administrator');
define('PORTAL_PROFILE_NAME', 'Portal user');
@@ -582,10 +580,10 @@ class UserRightsProfile extends UserRightsAddOnAPI
/**
* Read and cache organizations allowed to the given user
*
* @param User $oUser
* @param string $sClass (not used here but can be used in overloads)
* @param $oUser
* @param $sClass (not used here but can be used in overloads)
*
* @return array keys of the User allowed org
* @return array
* @throws \CoreException
* @throws \Exception
*/

View File

@@ -17,8 +17,6 @@
* You should have received a copy of the GNU Affero General Public License
*/
use Combodo\iTop\Application\WebPage\WebPage;
define('ADMIN_PROFILE_ID', 1);
class UserRightsBaseClass extends cmdbAbstractObject

29
app.php
View File

@@ -1,29 +0,0 @@
<?php
/**
* Copyright (C) 2013-2023 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
*/
use Combodo\iTop\Kernel;
require_once __DIR__.'/lib/autoload_runtime.php';
require_once('approot.inc.php');
require_once('application/startup.inc.php');
return function (array $context) {
return new Kernel($context['APP_ENV'], (bool) $context['APP_DEBUG']);
};

View File

@@ -1,13 +1,12 @@
<?php
/**
* @deprecated 3.0.0 will be removed in 3.1.0 - moved to sources/Application/WebPage/AjaxPage.php, now loadable using autoloader
* @deprecated will be removed in 3.1.0 - moved to sources/Application/WebPage/AjaxPage.php, now loadable using autoloader
* @license http://opensource.org/licenses/AGPL-3.0
* @copyright Copyright (C) 2010-2023 Combodo SARL
*/
// cannot notify depreciation for now as this is still load in autoloader
//DeprecatedCallsLog::NotifyDeprecatedFile('moved to sources/Application/WebPage/AjaxPage.php, now loadable using autoloader');
use Combodo\iTop\Application\WebPage\AjaxPage;
/**
* Class ajax_page

View File

@@ -19,8 +19,6 @@
*/
use Combodo\iTop\Application\UI\Base\iUIBlock;
use Combodo\iTop\Application\WebPage\iTopWebPage;
use Combodo\iTop\Application\WebPage\WebPage;
use Symfony\Component\DependencyInjection\Container;
require_once(APPROOT.'application/newsroomprovider.class.inc.php');
@@ -272,14 +270,14 @@ interface iPreferencesExtension
{
/**
* @api
* @param WebPage $oPage
* @param \WebPage $oPage
*
*/
public function DisplayPreferences(WebPage $oPage);
/**
* @api
* @param WebPage $oPage
* @param \WebPage $oPage
* @param string $sOperation
*
* @return bool true if the operation has been used
@@ -337,6 +335,7 @@ abstract class AbstractPreferencesExtension implements iPreferencesExtension
* A recommended pattern is to cache data by the mean of static members.
*
* @api
* @deprecated 3.1.0 N°4756 use the new event service instead, see {@see DBObject::FireEvent()} method
* @package UIExtensibilityAPI
*/
interface iApplicationUIExtension
@@ -488,6 +487,7 @@ interface iApplicationUIExtension
* @api
* @package UIExtensibilityAPI
* @since 2.7.0
* @deprecated
*/
abstract class AbstractApplicationUIExtension implements iApplicationUIExtension
{
@@ -560,7 +560,6 @@ abstract class AbstractApplicationUIExtension implements iApplicationUIExtension
* or through the GUI.
*
* @api
* @deprecated 3.1.0 N°4756 use the new event service instead, see {@see DBObject::FireEvent()} method. More details on each method PHPDoc.
* @package ORMExtensibilityAPI
*/
interface iApplicationObjectExtension
@@ -575,7 +574,6 @@ interface iApplicationObjectExtension
* Otherwise, the answer is definitively "yes, the object has changed".
*
* @api
* @deprecated 3.1.0 N°4756 No alternative available, this API was unstable and is abandoned
* @param \cmdbAbstractObject $oObject The target object
*
* @return boolean True if something has changed for the target object
@@ -589,7 +587,6 @@ interface iApplicationObjectExtension
* Anyhow, this API can be called in other contexts such as the CSV import tool.
*
* @api
* @deprecated 3.1.0 N°4756 Use EVENT_DB_CHECK_TO_WRITE event instead
* @param \cmdbAbstractObject $oObject The target object
*
* @return string[] A list of errors message. An error message is made of one line and it can be displayed to the end-user.
@@ -604,7 +601,6 @@ interface iApplicationObjectExtension
* Please not that it is not possible to cascade deletion by this mean: only stopper issues can be handled.
*
* @api
* @deprecated 3.1.0 N°4756 Use EVENT_DB_CHECK_TO_DELETE event instead
* @param \cmdbAbstractObject $oObject The target object
*
* @return string[] A list of errors message. An error message is made of one line and it can be displayed to the end-user.
@@ -621,7 +617,6 @@ interface iApplicationObjectExtension
* * {@see DBObject::Get()} : for a given attribute the new value that was persisted
*
* @api
* @deprecated 3.1.0 N°4756 Use EVENT_DB_AFTER_WRITE event instead
* @param \cmdbAbstractObject $oObject The target object
* @param CMDBChange|null $oChange A change context. Since 2.0 it is fine to ignore it, as the framework does maintain this information
* once for all the changes made within the current page
@@ -638,7 +633,6 @@ interface iApplicationObjectExtension
* The method is called right <b>after</b> the object has been written to the database.
*
* @api
* @deprecated 3.1.0 N°4756 Use EVENT_DB_AFTER_WRITE event instead
* @param \cmdbAbstractObject $oObject The target object
* @param CMDBChange|null $oChange A change context. Since 2.0 it is fine to ignore it, as the framework does maintain this information
* once for all the changes made within the current page
@@ -653,7 +647,6 @@ interface iApplicationObjectExtension
* The method is called right <b>before</b> the object will be deleted from the database.
*
* @api
* @deprecated 3.1.0 N°4756 Use EVENT_DB_AFTER_DELETE event instead
* @param \cmdbAbstractObject $oObject The target object
* @param CMDBChange|null $oChange A change context. Since 2.0 it is fine to ignore it, as the framework does maintain this information
* once for all the changes made within the current page
@@ -667,7 +660,6 @@ interface iApplicationObjectExtension
* Extend this class instead of iApplicationObjectExtension if you don't need to overload all methods
*
* @api
* @deprecated 3.1.0 N°4756 use the new event service instead, see {@see DBObject::FireEvent()} method
* @package ORMExtensibilityAPI
* @since 2.7.0
*/
@@ -1274,6 +1266,8 @@ abstract class AbstractPageUIExtension implements iPageUIExtension
*/
public function GetNorthPaneHtml(iTopWebPage $oPage)
{
DeprecatedCallsLog::NotifyDeprecatedPhpMethod('use iPageUIBlockExtension instead');
return '';
}
@@ -1282,6 +1276,8 @@ abstract class AbstractPageUIExtension implements iPageUIExtension
*/
public function GetSouthPaneHtml(iTopWebPage $oPage)
{
DeprecatedCallsLog::NotifyDeprecatedPhpMethod('use iPageUIBlockExtension instead');
return '';
}
@@ -1290,6 +1286,8 @@ abstract class AbstractPageUIExtension implements iPageUIExtension
*/
public function GetBannerHtml(iTopWebPage $oPage)
{
DeprecatedCallsLog::NotifyDeprecatedPhpMethod('use iPageUIBlockExtension instead');
return '';
}
@@ -2011,8 +2009,6 @@ class RestUtils
*
* @return DBObject The object found
* @throws Exception If the input structure is not valid or it could not find exactly one object
*
* @see DBObject::CheckChangedExtKeysValues() generic method to check that we can access the linked object isn't used in that use case because values can be literal, OQL, friendlyname
*/
public static function FindObjectFromKey($sClass, $key, $bAllowNullValue = false)
{

View File

@@ -86,7 +86,7 @@ class lnkAuditCategoryToAuditDomain extends cmdbAbstractObject
{
$aParams = array
(
"category" => "application,grant_by_profile",
"category" => "application, grant_by_profile",
"key_type" => "autoincrement",
"name_attcode" => "",
"state_attcode" => "",

View File

@@ -1,6 +1,6 @@
<?php
/**
* @deprecated 3.0.0 will be removed in 3.1.0 - moved to sources/Application/WebPage/CaptureWebPage.php, now loadable using autoloader
* @deprecated will be removed in 3.1.0 - moved to sources/Application/WebPage/CaptureWebPage.php, now loadable using autoloader
* @license http://opensource.org/licenses/AGPL-3.0
* @copyright Copyright (C) 2010-2023 Combodo SARL
*/

View File

@@ -1,6 +1,6 @@
<?php
/**
* @deprecated 3.0.0 will be removed in 3.1.0 - moved to sources/Application/WebPage/CLIPage.php, now loadable using autoloader
* @deprecated will be removed in 3.1.0 - moved to sources/Application/WebPage/CLIPage.php, now loadable using autoloader
* @license http://opensource.org/licenses/AGPL-3.0
* @copyright Copyright (C) 2010-2023 Combodo SARL
*/

View File

@@ -26,7 +26,7 @@ use Combodo\iTop\Application\UI\Base\Component\Html\Html;
use Combodo\iTop\Application\UI\Base\Component\Html\HtmlFactory;
use Combodo\iTop\Application\UI\Base\Component\Input\InputUIBlockFactory;
use Combodo\iTop\Application\UI\Base\Component\Input\Select\SelectOptionUIBlockFactory;
use Combodo\iTop\Application\UI\Base\Component\Input\Select\SelectUIBlockFactory;
use Combodo\iTop\Application\UI\Base\Component\Input\SelectUIBlockFactory;
use Combodo\iTop\Application\UI\Base\Component\Panel\PanelUIBlockFactory;
use Combodo\iTop\Application\UI\Base\Component\PopoverMenu\PopoverMenu;
use Combodo\iTop\Application\UI\Base\Component\PopoverMenu\PopoverMenuItem\JsPopoverMenuItem;
@@ -42,9 +42,6 @@ use Combodo\iTop\Application\UI\Base\Layout\UIContentBlockUIBlockFactory;
use Combodo\iTop\Application\UI\Links\Direct\BlockDirectLinkSetViewTable;
use Combodo\iTop\Application\UI\Links\Indirect\BlockIndirectLinkSetViewTable;
use Combodo\iTop\Application\UI\Links\Set\LinkSetUIBlockFactory;
use Combodo\iTop\Application\WebPage\AjaxPage;
use Combodo\iTop\Application\WebPage\iTopWebPage;
use Combodo\iTop\Application\WebPage\WebPage;
use Combodo\iTop\Renderer\BlockRenderer;
use Combodo\iTop\Renderer\Console\ConsoleBlockRenderer;
use Combodo\iTop\Renderer\Console\ConsoleFormRenderer;
@@ -137,8 +134,6 @@ abstract class cmdbAbstractObject extends CMDBObject implements iDisplay
/** @var string */
public const ENUM_INPUT_TYPE_TAGSET = 'tagset';
/** @var string */
public const ENUM_INPUT_TYPE_TAGSET_LINKEDSET = 'tagset_linkedset';
/** @var string */
public const ENUM_INPUT_TYPE_RADIO = 'radio';
/** @var string */
public const ENUM_INPUT_TYPE_CHECKBOX = 'checkbox';
@@ -290,7 +285,7 @@ abstract class cmdbAbstractObject extends CMDBObject implements iDisplay
}
/**
* @param WebPage $oPage
* @param \WebPage $oPage
* @param \cmdbAbstractObject $oObj
* @param array $aParams
*
@@ -359,7 +354,7 @@ JS
* @param int $iKey The identifier of the object
* @param string $sMessageId Your id or one of the well-known ids: 'create', 'update' and 'apply_stimulus'
* @param string $sMessage The HTML message (must be correctly escaped)
* @param string $sSeverity Any of the WebPage::ENUM_SESSION_MESSAGE_SEVERITY_XXX constants
* @param string $sSeverity Any of the \WebPage::ENUM_SESSION_MESSAGE_SEVERITY_XXX constants
* @param float $fRank Ordering of the message: smallest displayed first (can be negative)
* @param bool $bMustNotExist Do not alter any existing message (considering the id)
*
@@ -381,7 +376,7 @@ JS
}
/**
* @param WebPage $oPage Warning, since 3.0.0 this parameter was kept for compatibility reason. You shouldn't write directly on the page!
* @param \WebPage $oPage Warning, since 3.0.0 this parameter was kept for compatibility reason. You shouldn't write directly on the page!
* When writing to the page, markup will be put above the real header of the panel.
* To insert something IN the panel, we now need to add UIBlocks in either the "subtitle" or "toolbar" sections of the array that will be returned.
* @param bool $bEditMode Deprecated parameter in iTop 3.0.0, use {@see GetDisplayMode()} and ENUM_DISPLAY_MODE_* constants instead
@@ -559,7 +554,7 @@ HTML
/**
* Display properties tab of an object
*
* @param WebPage $oPage
* @param \WebPage $oPage
* @param bool $bEditMode Note that this parameter is no longer used in this method. Use {@see static::$sDisplayMode} instead
* @param string $sPrefix
* @param array $aExtraParams
@@ -598,7 +593,7 @@ HTML
}
/**
* @param WebPage $oPage
* @param \WebPage $oPage
* @param $sAttCode
*
* @throws \Exception
@@ -639,7 +634,7 @@ HTML
}
/**
* @param WebPage $oPage
* @param \WebPage $oPage
* @param bool $bEditMode Note that this parameter is no longer used in this method. Use {@see static::$sDisplayMode} instead
*
* @throws \CoreException
@@ -749,13 +744,7 @@ HTML
$oPage->SetCurrentTab($sTabCode, $oAttDef->GetLabel().$sCount, $sTabDescription);
$aArgs = array('this' => $this);
$sEditWhen = $oAttDef->GetEditWhen();
// Calculate if edit_when allows to edit based on current $bEditMode
$bIsEditableBasedOnEditWhen = ($sEditWhen === LINKSET_EDITWHEN_ALWAYS) ||
($bEditMode ? $sEditWhen === LINKSET_EDITWHEN_ON_HOST_EDITION : $sEditWhen === LINKSET_EDITWHEN_ON_HOST_DISPLAY);
$bReadOnly = ($iFlags & (OPT_ATT_READONLY | OPT_ATT_SLAVE)) || !$bIsEditableBasedOnEditWhen;
$bReadOnly = ($iFlags & (OPT_ATT_READONLY | OPT_ATT_SLAVE));
if ($bEditMode && (!$bReadOnly)) {
$sInputId = $this->m_iFormId.'_'.$sAttCode;
$sDisplayValue = ''; // not used
@@ -765,9 +754,9 @@ HTML
$oPage->add($sHTMLValue);
} else {
if ($oAttDef->IsIndirect()) {
$oBlockLinkSetViewTable = new BlockIndirectLinkSetViewTable($oPage, $this, $sClass, $sAttCode, $oAttDef, $bReadOnly);
$oBlockLinkSetViewTable = new BlockIndirectLinkSetViewTable($oPage, $this, $sClass, $sAttCode, $oAttDef);
} else {
$oBlockLinkSetViewTable = new BlockDirectLinkSetViewTable($oPage, $this, $sClass, $sAttCode, $oAttDef, $bReadOnly);
$oBlockLinkSetViewTable = new BlockDirectLinkSetViewTable($oPage, $this, $sClass, $sAttCode, $oAttDef);
}
$oPage->AddUiBlock($oBlockLinkSetViewTable);
}
@@ -866,7 +855,7 @@ HTML
}
/**
* @param WebPage $oPage
* @param \WebPage $oPage
* @param bool $bEditMode Note that this parameter is no longer used in this method. Use {@see static::$sDisplayMode} instead
* @param string $sPrefix
* @param array $aExtraParams
@@ -1070,7 +1059,7 @@ HTML
/**
* @param WebPage $oPage
* @param \WebPage $oPage
* @param bool $bEditMode Note that this parameter is no longer used in this method, {@see static::$sDisplayMode} is used instead, but we cannot remove it as it part of the base interface (iDisplay)...
*
* @throws \ApplicationException
@@ -1117,7 +1106,7 @@ HTML
}
// Note: DisplayBareHeader is called before adding $oObjectDetails to the page, so it can inject HTML before it through $oPage.
/** @var iTopWebPage $oPage */
/** @var \iTopWebPage $oPage */
$aHeadersBlocks = $this->DisplayBareHeader($oPage, $bEditMode);
if (false === empty($aHeadersBlocks['subtitle'])) {
$oObjectDetails->AddSubTitleBlocks($aHeadersBlocks['subtitle']);
@@ -1152,7 +1141,7 @@ HTML
}
/**
* @param WebPage $oPage
* @param \WebPage $oPage
*
* @throws \ArchivedObjectException
* @throws \CoreException
@@ -1175,7 +1164,7 @@ HTML
}
/**
* @param WebPage $oPage
* @param \WebPage $oPage
* @param \CMDBObjectSet $oSet
* @param array $aExtraParams See possible values in {@see DataTableUIBlockFactory::RenderDataTable()}
*
@@ -1237,7 +1226,7 @@ HTML
}
/**
* @param WebPage $oPage
* @param \WebPage $oPage
* @param \DBObjectSet $oSet
* @param array $aExtraParams
*
@@ -1409,7 +1398,7 @@ HTML
}
/**
* @param WebPage $oPage
* @param \WebPage $oPage
* @param \CMDBObjectSet $oSet
* @param array $aExtraParams key used :
* <ul>
@@ -1532,7 +1521,7 @@ HTML
}
/**
* @param WebPage $oPage
* @param \WebPage $oPage
* @param \CMDBObjectSet $oSet
* @param array $aParams
* @param string $sCharset
@@ -1691,7 +1680,7 @@ HTML
}
/**
* @param WebPage $oPage
* @param \WebPage $oPage
* @param \CMDBObjectSet $oSet
* @param array $aParams
*
@@ -1904,7 +1893,7 @@ HTML
}
/**
* @param WebPage $oPage
* @param \WebPage $oPage
* @param \CMDBObjectSet $oSet
* @param array $aParams
*
@@ -1982,7 +1971,7 @@ HTML
}
/**
* @param WebPage $oPage
* @param \WebPage $oPage
* @param \CMDBObjectSet $oSet
* @param array $aExtraParams
*
@@ -2013,7 +2002,7 @@ HTML
/**
* @param WebPage $oPage
* @param \WebPage $oPage
* @param string $sClass
* @param string $sAttCode
* @param \AttributeDefinition $oAttDef
@@ -2364,7 +2353,6 @@ EOF
case 'LinkedSet':
if ($oAttDef->GetDisplayStyle() === LINKSET_DISPLAY_STYLE_PROPERTY) {
$sInputType = self::ENUM_INPUT_TYPE_TAGSET_LINKEDSET;
if (array_key_exists('bulk_context', $aArgs)) {
$oTagSetBlock = LinkSetUIBlockFactory::MakeForBulkLinkSet($iId, $oAttDef, $value, $sWizardHelperJsVarName, $aArgs['bulk_context']);
} else {
@@ -2752,7 +2740,7 @@ JS
}
/**
* @param WebPage $oPage
* @param \WebPage $oPage
* @param array $aExtraParams
*
* @throws \ArchivedObjectException
@@ -3157,7 +3145,7 @@ EOF
/**
* Select the derived class to create
* @param string $sClass
* @param WebPage $oP
* @param \WebPage $oP
* @param \ApplicationContext $oAppContext
* @param array $aPossibleClasses
* @param array $aHiddenFields
@@ -3252,7 +3240,7 @@ EOF
return $oBlock;
}
/**
* @param WebPage $oPage
* @param \WebPage $oPage
* @param string $sClass
* @param \DBObject|null $oSourceObject Object to use for the creation form, can be either the class to instantiate, an object to clone or an object to use (eg. already prefilled / modeled object)
* @param array $aArgs
@@ -3337,7 +3325,7 @@ EOF
}
/**
* @param WebPage $oPage
* @param \WebPage $oPage
* @param string $sStimulus
* @param array|null $aPrefillFormParam
* @param bool $bDisplayBareProperties Whether to display the object details or not
@@ -3592,26 +3580,16 @@ EOF
$oPage->add_ready_script(InlineImage::EnableCKEditorImageUpload($this, $sTempId));
} else {
//we can directly apply the stimuli
$sExceptionMessage = null;
try {
$bApplyStimulus = $this->ApplyStimulus($sStimulus); // will write the object in the DB
}
catch (Exception $oException) {
// Catch any exception happening during the stimulus
$bApplyStimulus = false;
$sExceptionMessage = ($oException instanceof CoreCannotSaveObjectException) ? $oException->getHtmlMessage() : $oException->getMessage();
}
finally {
if (!$bApplyStimulus) {
throw new ApplicationException(Dict::S('UI:FailedToApplyStimuli'));
} else {
if ($sOwnershipToken !== null) {
// Release the concurrent lock, if any
iTopOwnershipLock::ReleaseLock($sClass, $iKey, $sOwnershipToken);
}
if (!$bApplyStimulus) {
// Throw an application oriented exception if necessary
throw new ApplicationException($sExceptionMessage ?? Dict::S('UI:FailedToApplyStimuli'));
} else {
return true;
}
return true;
}
}
@@ -3725,7 +3703,7 @@ HTML;
if ($oAttDef->GetEditClass() == 'Document') {
/** @var \ormDocument $oDocument */
$oDocument = $this->Get($sAttCode);
if (is_object($oDocument) && !$oDocument->IsEmpty()) {
if (!$oDocument->IsEmpty()) {
$sFieldAsHtml = $this->GetAsHTML($sAttCode);
$sDisplayLabel = Dict::S('UI:OpenDocumentInNewWindow_');
@@ -3760,7 +3738,7 @@ HTML;
/**
* Displays a blob document *inline* (if possible, depending on the type of the document)
*
* @param WebPage $oPage
* @param \WebPage $oPage
* @param $sAttCode
*
* @return string
@@ -4560,7 +4538,7 @@ HTML;
return $res;
}
protected function PostInsertActions(): void
public function PostInsertActions(): void
{
parent::PostInsertActions();
@@ -4584,9 +4562,6 @@ HTML;
InlineImage::FinalizeInlineImages($this);
}
/**
* @deprecated 3.1.1 3.2.0 N°6966 We will have only one DBClone method in the future
*/
protected function DBCloneTracked_Internal($newKey = null)
{
/** @var cmdbAbstractObject $oNewObj */
@@ -4607,7 +4582,6 @@ HTML;
public function DBUpdate()
{
$this->LogCRUDEnter(__METHOD__);
$res = 0;
try {
if (count($this->ListChanges()) === 0) {
@@ -4627,7 +4601,7 @@ HTML;
return $res;
}
protected function PostUpdateActions(array $aChanges): void
public function PostUpdateActions(array $aChanges): void
{
parent::PostUpdateActions($aChanges);
@@ -4668,7 +4642,6 @@ HTML;
if (static::IsCrudStackEmpty()) {
// Avoid signaling the current object that links were modified
static::RemoveObjectAwaitingEventDbLinksChanged(get_class($this), $this->GetKey());
$this->LogCRUDDebug(__METHOD__, var_export(self::$aObjectsAwaitingEventDbLinksChanged, true));
static::FireEventDbLinksChangedForAllObjects();
}
}
@@ -4677,15 +4650,7 @@ HTML;
return $oDeletionPlan;
}
protected function PostDeleteActions(): void
{
parent::PostDeleteActions();
}
/**
* @deprecated 3.1.1 3.2.0 N°6967 We will have only one DBDelete method in the future
*/
protected function DBDeleteTracked_Internal(&$oDeletionPlan = null)
protected function DBDeleteTracked_Internal(&$oDeletionPlan = null)
{
// Invoke extensions before the deletion (the deletion will do some cleanup and we might loose some information
/** @var \iApplicationObjectExtension $oExtensionInstance */
@@ -4848,7 +4813,7 @@ HTML;
/**
* Special display where the case log uses the whole "screen" at the bottom of the "Properties" tab
*
* @param WebPage $oPage
* @param \WebPage $oPage
* @param string $sAttCode
* @param string $sComment
* @param string $sPrefix
@@ -4952,7 +4917,7 @@ HTML
/**
* Special display where the case log uses the whole "screen" at the bottom of the "Properties" tab
*
* @param WebPage $oPage
* @param \WebPage $oPage
* @param string $sAttCode
* @param string $sComment
* @param string $sPrefix
@@ -5077,7 +5042,7 @@ HTML
* Display a form for modifying several objects at once
* The form will be submitted to the current page, with the specified additional values
*
* @param iTopWebPage $oP
* @param \iTopWebPage $oP
* @param string $sClass
* @param array $aSelectedObj
* @param string $sCustomOperation
@@ -5321,7 +5286,7 @@ EOF
/**
* Process the reply made from a form built with DisplayBulkModifyForm
*
* @param WebPage $oP
* @param \WebPage $oP
* @param string $sClass
* @param array $aSelectedObj
* @param string $sCustomOperation
@@ -5377,7 +5342,7 @@ EOF
$aErrors = $oObj->UpdateObjectFromPostedForm('');
$bResult = (count($aErrors) == 0);
if ($bResult) {
[$bResult, $aErrors] = $oObj->CheckToWrite();
list($bResult, $aErrors) = $oObj->CheckToWrite();
}
if ($bPreview) {
$sStatus = $bResult ? Dict::S('UI:BulkModifyStatusOk') : Dict::S('UI:BulkModifyStatusError');
@@ -5394,11 +5359,6 @@ EOF
'errors' => '<p>'.($bResult ? '' : implode('</p><p>', $aErrorsToDisplay)).'</p>',
);
if ($bResult && (!$bPreview)) {
// doing the check will load multiple times same objects :/
// but it shouldn't cost too much on execution time
// user can mitigate by selecting less extkeys/lnk to set and/or less objects to update 🤷‍♂️
$oObj->CheckChangedExtKeysValues();
$oObj->DBUpdate();
}
}
@@ -5461,7 +5421,7 @@ EOF
/**
* Perform all the needed checks to delete one (or more) objects
*
* @param WebPage $oP
* @param \WebPage $oP
* @param $sClass
* @param \DBObject[] $aObjects
* @param $bPreview
@@ -5967,16 +5927,6 @@ JS
$this->FireEvent(EVENT_DB_CHECK_TO_DELETE, ['deletion_plan' => $oDeletionPlan]);
}
/**
* @return void
* @throws \CoreException
* @since 3.1.2
*/
final protected function FireEventAboutToDelete(): void
{
$this->FireEvent(EVENT_DB_ABOUT_TO_DELETE);
}
/**
* @return void
* @throws \CoreException
@@ -5986,63 +5936,47 @@ JS
final protected function FireEventAfterDelete(): void
{
$this->NotifyAttachedObjectsOnLinkClassModification();
$this->FireEventDbLinksChangedForCurrentObject();
$this->FireEvent(EVENT_DB_AFTER_DELETE);
}
/**
* Possibility for linked classes to be notified of current class modification
*
* If the passed object is an instance of a link class, then will register each remote object for modification using {@see static::RegisterObjectAwaitingEventDbLinksChanged()}
* If an external key was modified, register also the previous object that was linked previously.
*
* @uses static::RegisterObjectAwaitingEventDbLinksChanged()
* @throws \ArchivedObjectException
* @throws \CoreException
* @throws \Exception
*
* @throws ArchivedObjectException
* @throws CoreException
* @throws Exception
*
* @since 3.1.0 N°5906 method creation
* @since 3.1.1 3.2.0 N°6228 now just notify attributes having `with_php_computation`
* @since 3.1.0 N°5906
*/
final protected function NotifyAttachedObjectsOnLinkClassModification(): void
{
$sClass = get_class($this);
if (false === MetaModel::IsLinkClass($sClass)) {
return;
}
// previous values in case of link change
$aPreviousValues = $this->ListPreviousValuesForUpdatedAttributes();
$sClass = get_class($this);
$aClassExtKeyAttCodes = MetaModel::GetAttributesList($sClass, [AttributeExternalKey::class]);
foreach ($aClassExtKeyAttCodes as $sExternalKeyAttCode) {
/** @var AttributeExternalKey $oAttDef */
$oAttDef = MetaModel::GetAttributeDef($sClass, $sExternalKeyAttCode);
if (false === $this->DoesTargetObjectHavePhpComputation($oAttDef)) {
continue;
$aLnkClassExternalKeys = MetaModel::GetAttributesList($sClass, [AttributeExternalKey::class]);
foreach ($aLnkClassExternalKeys as $sExternalKeyAttCode) {
/** @var \AttributeExternalKey $oExternalKeyAttDef */
$oExternalKeyAttDef = MetaModel::GetAttributeDef($sClass, $sExternalKeyAttCode);
$sRemoteClassName = $oExternalKeyAttDef->GetTargetClass();
$sRemoteObjectId = $this->Get($sExternalKeyAttCode);
if ($sRemoteObjectId > 0) {
self::RegisterObjectAwaitingEventDbLinksChanged($sRemoteClassName, $sRemoteObjectId);
}
$sTargetObjectId = $this->Get($sExternalKeyAttCode);
$sTargetClass = $oAttDef->GetTargetClass();
if ($sTargetObjectId > 0) {
$this->LogCRUDDebug(__METHOD__, "Add $sTargetClass:$sTargetObjectId for DBLINKS_CHANGED");
self::RegisterObjectAwaitingEventDbLinksChanged($sTargetClass, $sTargetObjectId);
}
$sPreviousTargetObjectId = $aPreviousValues[$sExternalKeyAttCode] ?? 0;
if ($sPreviousTargetObjectId > 0) {
$this->LogCRUDDebug(__METHOD__, "Add $sTargetClass:$sPreviousTargetObjectId for DBLINKS_CHANGED");
self::RegisterObjectAwaitingEventDbLinksChanged($sTargetClass, $sPreviousTargetObjectId);
$sPreviousRemoteObjectId = $aPreviousValues[$sExternalKeyAttCode] ?? 0;
if ($sPreviousRemoteObjectId > 0) {
self::RegisterObjectAwaitingEventDbLinksChanged($sRemoteClassName, $sPreviousRemoteObjectId);
}
}
}
private function DoesTargetObjectHavePhpComputation(AttributeExternalKey $oAttDef): bool
{
/** @var AttributeLinkedSet $oAttDefMirrorLink */
$oAttDefMirrorLink = $oAttDef->GetMirrorLinkAttribute();
if (is_null($oAttDefMirrorLink) || false === $oAttDefMirrorLink->HasPHPComputation()){
return false;
}
return true;
}
/**
* Register one object for later EVENT_DB_LINKS_CHANGED event.
*
@@ -6077,12 +6011,7 @@ JS
$sClass = get_class($this);
$sId = $this->GetKey();
$bIsObjectAwaitingEventDbLinksChanged = self::RemoveObjectAwaitingEventDbLinksChanged($sClass, $sId);
if (false === $bIsObjectAwaitingEventDbLinksChanged) {
return;
}
self::FireEventDbLinksChangedForObject($this);
self::RemoveObjectAwaitingEventDbLinksChanged($sClass, $sId);
self::FireEventDbLinksChangedForClassId($sClass, $sId);
}
/**
@@ -6114,15 +6043,9 @@ JS
// We want to avoid launching the listener twice, first here, and secondly after saving the Ticket in the listener
// By disabling the event to be fired, we can remove the current object from the attribute !
$oObject = MetaModel::GetObject($sClass, $sId, false);
self::FireEventDbLinksChangedForObject($oObject);
self::RemoveObjectAwaitingEventDbLinksChanged($sClass, $sId);
}
private static function FireEventDbLinksChangedForObject(DBObject $oObject)
{
self::SetEventDBLinksChangedBlocked(true);
// N°6408 The object can have been deleted
if (!is_null($oObject)) {
self::SetEventDBLinksChangedBlocked(true);
MetaModel::StartReentranceProtection($oObject);
$oObject->FireEvent(EVENT_DB_LINKS_CHANGED);
MetaModel::StopReentranceProtection($oObject);
@@ -6130,6 +6053,7 @@ JS
$oObject->DBUpdate();
}
}
self::RemoveObjectAwaitingEventDbLinksChanged($sClass, $sId);
cmdbAbstractObject::SetEventDBLinksChangedBlocked(false);
}

View File

@@ -1,6 +1,6 @@
<?php
/**
* @deprecated 3.0.0 will be removed in 3.1.0 - moved to sources/Application/WebPage/CSVPage.php, now loadable using autoloader
* @deprecated will be removed in 3.1.0 - moved to sources/Application/WebPage/CSVPage.php, now loadable using autoloader
* @license http://opensource.org/licenses/AGPL-3.0
* @copyright Copyright (C) 2010-2023 Combodo SARL
*/

View File

@@ -9,8 +9,6 @@ use Combodo\iTop\Application\UI\Base\Component\DataTable\DataTableSettings;
use Combodo\iTop\Application\UI\Base\Component\PopoverMenu\PopoverMenu;
use Combodo\iTop\Application\UI\Base\Component\Toolbar\ToolbarUIBlockFactory;
use Combodo\iTop\Application\UI\Base\Layout\Dashboard\DashboardLayout as DashboardLayoutUIBlock;
use Combodo\iTop\Application\WebPage\iTopWebPage;
use Combodo\iTop\Application\WebPage\WebPage;
require_once(APPROOT.'application/dashboardlayout.class.inc.php');
require_once(APPROOT.'application/dashlet.class.inc.php');
@@ -424,7 +422,7 @@ abstract class Dashboard
}
/**
* @param WebPage $oPage *
* @param \WebPage $oPage *
* @param array $aExtraParams
*
* @throws \ReflectionException
@@ -515,7 +513,7 @@ EOF
}
/**
* @param WebPage $oPage
* @param \WebPage $oPage
* @param bool $bEditMode
* @param array $aExtraParams
* @param bool $bCanEdit
@@ -571,7 +569,7 @@ JS
}
/**
* @param WebPage $oPage
* @param \WebPage $oPage
*
* @throws \ReflectionException
* @throws \Exception
@@ -594,7 +592,7 @@ JS
}
/**
* @param WebPage $oPage
* @param \WebPage $oPage
* @param array $aExtraParams
*/
public function RenderDashletsProperties(WebPage $oPage, $aExtraParams = array())
@@ -920,7 +918,7 @@ class RuntimeDashboard extends Dashboard
{
$bCustomized = false;
$sDashboardFileSanitized = utils::RealPath(APPROOT.$sDashboardFile, APPROOT);
$sDashboardFileSanitized = utils::RealPath($sDashboardFile, APPROOT);
if (false === $sDashboardFileSanitized) {
throw new SecurityException('Invalid dashboard file !');
}
@@ -1111,7 +1109,7 @@ JS
}
/**
* @param WebPage $oPage
* @param \WebPage $oPage
* @param array $aExtraParams
*
* @throws \Exception
@@ -1143,7 +1141,7 @@ JS
$oToolbar->AddSubBlock($oActionButton);
$aActions = array();
$sFile = addslashes(utils::LocalPath($this->sDefinitionFile));
$sFile = addslashes($this->sDefinitionFile);
$sJSExtraParams = json_encode($aExtraParams);
if ($this->HasCustomDashboard()) {
$oEdit = new JSPopupMenuItem('UI:Dashboard:Edit', Dict::S('UI:Dashboard:EditCustom'), "return EditDashboard('{$this->sId}', '$sFile', $sJSExtraParams)");
@@ -1230,7 +1228,7 @@ EOF
/**
* @param WebPage $oPage
* @param \WebPage $oPage
*
* @param array $aExtraParams
*
@@ -1266,12 +1264,12 @@ EOF
$sOkButtonLabel = Dict::S('UI:Button:Save');
$sCancelButtonLabel = Dict::S('UI:Button:Cancel');
$sId = utils::HtmlEntities($this->sId);
$sLayoutClass = utils::HtmlEntities($this->sLayoutClass);
$sId = addslashes($this->sId);
$sLayoutClass = addslashes($this->sLayoutClass);
$sAutoReload = $this->bAutoReload ? 'true' : 'false';
$sAutoReloadSec = (string) $this->iAutoReloadSec;
$sTitle = utils::HtmlEntities($this->sTitle);
$sFile = utils::HtmlEntities($this->GetDefinitionFile());
$sTitle = addslashes($this->sTitle);
$sFile = addslashes($this->GetDefinitionFile());
$sUrl = utils::GetAbsoluteUrlAppRoot().'pages/ajax.render.php';
$sReloadURL = $this->GetReloadURL();
@@ -1490,7 +1488,7 @@ JS
}
/**
* @param WebPage $oPage
* @param \WebPage $oPage
* @param $sOQL
*
* @throws \DictExceptionMissingString

View File

@@ -19,7 +19,6 @@ use Combodo\iTop\Application\UI\Base\Component\Html\Html;
use Combodo\iTop\Application\UI\Base\Layout\Dashboard\DashboardColumn;
use Combodo\iTop\Application\UI\Base\Layout\Dashboard\DashboardLayout as DashboardLayoutUIBlock;
use Combodo\iTop\Application\UI\Base\Layout\Dashboard\DashboardRow;
use Combodo\iTop\Application\WebPage\WebPage;
/**
* Dashboard presentation
@@ -107,7 +106,7 @@ abstract class DashboardLayoutMultiCol extends DashboardLayout
}
/**
* @param WebPage $oPage
* @param \WebPage $oPage
* @param $aCells
* @param bool $bEditMode
* @param array $aExtraParams

View File

@@ -23,7 +23,6 @@ use Combodo\iTop\Application\UI\Base\Component\Html\Html;
use Combodo\iTop\Application\UI\Base\Component\Panel\PanelUIBlockFactory;
use Combodo\iTop\Application\UI\Base\iUIBlock;
use Combodo\iTop\Application\UI\Base\UIBlock;
use Combodo\iTop\Application\WebPage\WebPage;
require_once(APPROOT.'application/forms.class.inc.php');
@@ -223,7 +222,7 @@ abstract class Dashlet
}
/**
* @param WebPage $oPage
* @param \WebPage $oPage
* @param bool $bEditMode
* @param bool $bEnclosingDiv
* @param array $aExtraParams
@@ -299,7 +298,7 @@ EOF
}
/**
* @param WebPage $oPage
* @param \WebPage $oPage
* @param bool $bEditMode
* @param array $aExtraParams
*
@@ -310,7 +309,7 @@ EOF
/**
* Rendering without the real data
*
* @param WebPage $oPage
* @param \WebPage $oPage
* @param bool $bEditMode
* @param array $aExtraParams
*

View File

@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<itop_design xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="3.2">
<itop_design xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="3.1">
<classes>
<class id="AbstractResource" _delta="define">
<parent>cmdbAbstractObject</parent>
@@ -270,23 +270,6 @@
</event_datum>
</event_data>
</event>
<event id="EVENT_DB_ABOUT_TO_DELETE" _delta="define">
<description>An object is about to be deleted from the database</description>
<sources>
<source id="cmdbAbstractObject">cmdbAbstractObject</source>
</sources>
<replaces>cmdbAbstractObject::OnDelete</replaces>
<event_data>
<event_datum id="object">
<description>The object about to be deleted</description>
<type>DBObject</type>
</event_datum>
<event_datum id="debug_info">
<description>Debug string</description>
<type>string</type>
</event_datum>
</event_data>
</event>
<event id="EVENT_DB_AFTER_DELETE" _delta="define">
<description>An object has been deleted into the database</description>
<sources>
@@ -304,8 +287,8 @@
</event_datum>
</event_data>
</event>
<event id="EVENT_ENUM_TRANSITIONS" _delta="define">
<description>Manage the allowed transitions in current object state. The only action allowed is to deny transitions with DBObject::DenyTransition()</description>
<event id="EVENT_DB_BEFORE_APPLY_STIMULUS" _delta="define">
<description>A stimulus is about to be applied to an object</description>
<sources>
<source id="cmdbAbstractObject">cmdbAbstractObject</source>
</sources>
@@ -314,9 +297,89 @@
<description>The object where the stimulus is targeted</description>
<type>DBObject</type>
</event_datum>
<event_datum id="allowed_stimuli">
<description>The list of available stimuli in the current state</description>
<type>array</type>
<event_datum id="stimulus">
<description>Current stimulus applied</description>
<type>string</type>
</event_datum>
<event_datum id="previous_state">
<description>Object previous state</description>
<type>string</type>
</event_datum>
<event_datum id="new_state">
<description>Object new state</description>
<type>string</type>
</event_datum>
<event_datum id="save_object">
<description>The object must be saved in the database</description>
<type>boolean</type>
</event_datum>
<event_datum id="debug_info">
<description>Debug string</description>
<type>string</type>
</event_datum>
</event_data>
</event>
<event id="EVENT_DB_AFTER_APPLY_STIMULUS" _delta="define">
<description>A stimulus has been applied to an object</description>
<sources>
<source id="cmdbAbstractObject">cmdbAbstractObject</source>
</sources>
<event_data>
<event_datum id="object">
<description>The object where the stimulus is targeted</description>
<type>DBObject</type>
</event_datum>
<event_datum id="stimulus">
<description>Current stimulus applied</description>
<type>string</type>
</event_datum>
<event_datum id="previous_state">
<description>Object previous state</description>
<type>string</type>
</event_datum>
<event_datum id="new_state">
<description>Object new state</description>
<type>string</type>
</event_datum>
<event_datum id="save_object">
<description>The object is asked to be saved in the database</description>
<type>boolean</type>
</event_datum>
<event_datum id="debug_info">
<description>Debug string</description>
<type>string</type>
</event_datum>
</event_data>
</event>
<event id="EVENT_DB_APPLY_STIMULUS_FAILED" _delta="define">
<description>A stimulus has failed</description>
<sources>
<source id="cmdbAbstractObject">cmdbAbstractObject</source>
</sources>
<event_data>
<event_datum id="action">
<description>The action that failed to apply the stimulus</description>
<type>string</type>
</event_datum>
<event_datum id="object">
<description>The object where the stimulus is targeted</description>
<type>DBObject</type>
</event_datum>
<event_datum id="stimulus">
<description>Current stimulus applied</description>
<type>string</type>
</event_datum>
<event_datum id="previous_state">
<description>Object previous state</description>
<type>string</type>
</event_datum>
<event_datum id="new_state">
<description>Object new state</description>
<type>string</type>
</event_datum>
<event_datum id="save_object">
<description>The object must be saved in the database</description>
<type>boolean</type>
</event_datum>
<event_datum id="debug_info">
<description>Debug string</description>
@@ -451,18 +514,10 @@
<description>The object containing the document</description>
<type>DBObject</type>
</event_datum>
<event_datum id="att_code">
<description>The optional object attribute code hosting the document</description>
<type>string</type>
</event_datum>
<event_datum id="document">
<description>The document downloaded</description>
<type>ormDocument</type>
</event_datum>
<event_datum id="content_disposition">
<description>The content disposition of the document ("inline" or "attachment")</description>
<type>string</type>
</event_datum>
<event_datum id="debug_info">
<description>Debug string</description>
<type>string</type>

View File

@@ -1,7 +1,5 @@
<?php
use Combodo\iTop\Application\UI\Base\Component\DataTable\DataTableSettings;
use Combodo\iTop\Application\WebPage\WebPage;
use Combodo\iTop\Renderer\Console\ConsoleBlockRenderer;
/**
@@ -63,8 +61,8 @@ class DataTable
}
/**
* @param WebPage $oPage
* @param DataTableSettings $oSettings
* @param \WebPage $oPage
* @param \DataTableSettings $oSettings
* @param $bActionsMenu
* @param $sSelectMode
* @param $bViewLink
@@ -143,7 +141,7 @@ class DataTable
}
/**
* @param WebPage $oPage
* @param \WebPage $oPage
* @param $iPageSize
* @param $iDefaultPageSize
* @param $iPageIndex
@@ -238,7 +236,7 @@ class DataTable
}
/**
* @param WebPage $oPage
* @param \WebPage $oPage
* @param $sSelectMode
*
* @return string
@@ -257,7 +255,7 @@ class DataTable
}
/**
* @param WebPage $oPage
* @param \WebPage $oPage
* @param $iPageSize
* @param $iDefaultPageSize
* @param $iPageIndex
@@ -350,7 +348,7 @@ EOF;
}
/**
* @param WebPage $oPage
* @param \WebPage $oPage
* @param $aExtraParams
*
* @return string
@@ -377,7 +375,7 @@ EOF;
}
/**
* @param WebPage $oPage
* @param \WebPage $oPage
* @param $aExtraParams
*
* @return string
@@ -407,7 +405,7 @@ EOF;
}
/**
* @param WebPage $oPage
* @param \WebPage $oPage
* @param $aColumns
* @param $bViewLink
* @param $iDefaultPageSize
@@ -660,7 +658,7 @@ EOF;
}
/**
* @param WebPage $oPage
* @param \WebPage $oPage
* @param $aColumns
* @param $sSelectMode
* @param $iPageSize
@@ -792,7 +790,7 @@ JS
}
/**
* @param WebPage $oPage
* @param \WebPage $oPage
* @param $iDefaultPageSize
* @param $iStart
*/
@@ -820,7 +818,7 @@ JS
class PrintableDataTable extends DataTable
{
/**
* @param WebPage $oPage
* @param \WebPage $oPage
* @param $iPageSize
* @param $iDefaultPageSize
* @param $iPageIndex
@@ -846,7 +844,7 @@ class PrintableDataTable extends DataTable
}
/**
* @param WebPage $oPage
* @param \WebPage $oPage
* @param $aColumns
* @param $sSelectMode
* @param $iPageSize

View File

@@ -24,8 +24,6 @@ use Combodo\iTop\Application\UI\DisplayBlock\BlockChartAjaxBars\BlockChartAjaxBa
use Combodo\iTop\Application\UI\DisplayBlock\BlockChartAjaxPie\BlockChartAjaxPie;
use Combodo\iTop\Application\UI\DisplayBlock\BlockCsv\BlockCsv;
use Combodo\iTop\Application\UI\DisplayBlock\BlockList\BlockList;
use Combodo\iTop\Application\WebPage\iTopWebPage;
use Combodo\iTop\Application\WebPage\WebPage;
use Combodo\iTop\Service\Router\Router;
require_once(APPROOT.'/application/utils.inc.php');
@@ -597,7 +595,7 @@ class DisplayBlock
}
/**
* @param WebPage $oPage
* @param \WebPage $oPage
* @param array $aExtraParams
*
* @throws \ApplicationException
@@ -1356,7 +1354,7 @@ JS
}
/**
* @param WebPage $oPage
* @param \WebPage $oPage
* @param array $aExtraParams
*
* @return \Combodo\iTop\Application\UI\Base\iUIBlock
@@ -1380,7 +1378,7 @@ JS
/**
* @param array $aExtraParams
* @param WebPage $oPage
* @param \WebPage $oPage
*
* @throws \ArchivedObjectException
* @throws \ConfigException
@@ -1458,7 +1456,7 @@ JS
/**
* @param array $aExtraParams
* @param WebPage $oPage
* @param \WebPage $oPage
*
* @return \Combodo\iTop\Application\UI\Base\Layout\UIContentBlock
* @throws \ApplicationException
@@ -1566,7 +1564,7 @@ JS
/**
* @deprecated 3.1.0 N°5957
*
* @param WebPage $oPage
* @param \WebPage $oPage
* @param array $aExtraParams
*
* @return \Combodo\iTop\Application\UI\Base\Component\Html\Html|\Combodo\iTop\Application\UI\Base\Layout\UIContentBlock|string
@@ -1666,7 +1664,7 @@ JS
/**
* @param array $aExtraParams
* @param WebPage $oPage
* @param \WebPage $oPage
*
* @throws \ArchivedObjectException
* @throws \CoreException
@@ -1832,7 +1830,7 @@ class MenuBlock extends DisplayBlock
* an object in with the same tab active by default as the tab that was active when selecting
* the "Modify..." action.
*
* @param WebPage $oPage
* @param \WebPage $oPage
* @param array $aExtraParams
* @param string|null $sId
*
@@ -2044,7 +2042,7 @@ class MenuBlock extends DisplayBlock
}
//----------------------------------------------------
// Any style but NOT \DisplayBlock::ENUM_STYLE_LIST_IN_OBJECT (linksets) actions
// Any style but NOT "listInObject" (linksets) actions
//----------------------------------------------------
if ($this->m_sStyle !== static::ENUM_STYLE_LIST_IN_OBJECT) {
switch ($iSetCount) {

View File

@@ -1,6 +1,6 @@
<?php
/**
* @deprecated 3.0.0 will be removed in 3.1.0 - moved to sources/Application/WebPage/ErrorPage.php, now loadable using autoloader
* @deprecated will be removed in 3.1.0 - moved to sources/Application/WebPage/ErrorPage.php, now loadable using autoloader
* @license http://opensource.org/licenses/AGPL-3.0
* @copyright Copyright (C) 2010-2023 Combodo SARL
*/

View File

@@ -1,8 +1,4 @@
<?php
use Combodo\iTop\Application\WebPage\CLIPage;
use Combodo\iTop\Application\WebPage\Page;
require_once('xlsxwriter.class.php');
class ExcelExporter

View File

@@ -1,36 +0,0 @@
<?php
/**
* @since 2.7.10 3.0.4 3.1.1 3.2.0 N°6458 object creation
*/
class InvalidExternalKeyValueException extends CoreUnexpectedValue
{
private const ENUM_PARAMS_OBJECT = 'current_object';
private const ENUM_PARAMS_ATTCODE = 'attcode';
private const ENUM_PARAMS_ATTVALUE = 'attvalue';
private const ENUM_PARAMS_USER = 'current_user';
public function __construct($oObject, $sAttCode, $aContextData = null, $oPrevious = null)
{
$aContextData[self::ENUM_PARAMS_OBJECT] = get_class($oObject) . '::' . $oObject->GetKey();
$aContextData[self::ENUM_PARAMS_ATTCODE] = $sAttCode;
$aContextData[self::ENUM_PARAMS_ATTVALUE] = $oObject->Get($sAttCode);
$oCurrentUser = UserRights::GetUserObject();
if (false === is_null($oCurrentUser)) {
$aContextData[self::ENUM_PARAMS_USER] = get_class($oCurrentUser) . '::' . $oCurrentUser->GetKey();
}
parent::__construct('Attribute pointing to an object that is either non existing or not readable by the current user', $aContextData, '', $oPrevious);
}
public function GetAttCode(): string
{
return $this->getContextData()[self::ENUM_PARAMS_ATTCODE];
}
public function GetAttValue(): string
{
return $this->getContextData()[self::ENUM_PARAMS_ATTVALUE];
}
}

View File

@@ -15,7 +15,6 @@
//
// You should have received a copy of the GNU Affero General Public License
// along with iTop. If not, see <http://www.gnu.org/licenses/>
use Combodo\iTop\Application\WebPage\WebPage;
/**
* Helper class to build interactive forms to be used either in stand-alone
@@ -829,7 +828,7 @@ class DesignerFormField
}
/**
* @param WebPage $oP
* @param \WebPage $oP
* @param string $sFormId
* @param string $sRenderMode
*

View File

@@ -1,6 +1,6 @@
<?php
/**
* @deprecated 3.0.0 will be removed in 3.1.0 - moved to sources/Application/WebPage/iTopWebPage.php, now loadable using autoloader
* @deprecated will be removed in 3.1.0 - moved to sources/Application/WebPage/iTopWebPage.php, now loadable using autoloader
* @license http://opensource.org/licenses/AGPL-3.0
* @copyright Copyright (C) 2010-2023 Combodo SARL
*/

View File

@@ -1,6 +1,6 @@
<?php
/**
* @deprecated 3.0.0 will be removed in 3.1.0 - moved to sources/Application/WebPage/iTopWizardWebPage.php, now loadable using autoloader
* @deprecated will be removed in 3.1.0 - moved to sources/Application/WebPage/iTopWizardWebPage.php, now loadable using autoloader
* @license http://opensource.org/licenses/AGPL-3.0
* @copyright Copyright (C) 2010-2023 Combodo SARL
*/

View File

@@ -119,11 +119,6 @@ class LoginDefaultAfter extends AbstractLoginFSMExtension implements iLogoutExte
protected function OnConnected(&$iErrorCode)
{
Session::Unset('login_temp_auth_user');
if (is_null(UserRights::GetUserObject())){
//N°7085 avoid infinite loop
IssueLog::Error("No user logged in. exit");
exit(-1);
}
return LoginWebPage::LOGIN_FSM_CONTINUE;
}
@@ -139,4 +134,4 @@ class LoginDefaultAfter extends AbstractLoginFSMExtension implements iLogoutExte
}
}
}
}
}

View File

@@ -140,11 +140,7 @@ class LoginForm extends AbstractLoginFSMExtension implements iLoginUIExtension
$oLoginContext->AddBlockExtension('login_form_footer', new LoginBlockExtension('extensionblock/loginformfooter.html.twig'));
$bEnableResetPassword = MetaModel::GetConfig()->Get('forgot_password');
$sResetPasswordUrl = MetaModel::GetConfig()->Get('forgot_password.url');
if ($sResetPasswordUrl == '')
{
$sResetPasswordUrl = utils::GetAbsoluteUrlAppRoot() . 'pages/UI.php?loginop=forgot_pwd';
}
$sResetPasswordUrl = utils::GetAbsoluteUrlAppRoot() . 'pages/UI.php?loginop=forgot_pwd';
$aData = array(
'bEnableResetPassword' => $bEnableResetPassword,
'sResetPasswordUrl' => $sResetPasswordUrl,

View File

@@ -9,7 +9,6 @@
use Combodo\iTop\Application\Branding;
use Combodo\iTop\Application\TwigBase\Twig\Extension;
use Combodo\iTop\Application\WebPage\NiceWebPage;
use Twig\Environment;
use Twig\Loader\ChainLoader;
use Twig\Loader\FilesystemLoader;

View File

@@ -26,8 +26,6 @@
use Combodo\iTop\Application\Branding;
use Combodo\iTop\Application\Helper\Session;
use Combodo\iTop\Application\WebPage\ErrorPage;
use Combodo\iTop\Application\WebPage\NiceWebPage;
use Combodo\iTop\Service\Events\EventData;
use Combodo\iTop\Service\Events\EventService;
@@ -82,7 +80,7 @@ class LoginWebPage extends NiceWebPage
}
protected static $m_sLoginFailedMessage = '';
public function __construct($sTitle = null)
{
if ($sTitle === null) {
@@ -92,7 +90,7 @@ class LoginWebPage extends NiceWebPage
parent::__construct($sTitle);
$this->SetStyleSheet();
$this->no_cache();
$this->add_http_headers();
$this->add_xframe_options();
}
public function SetStyleSheet()
@@ -101,15 +99,6 @@ class LoginWebPage extends NiceWebPage
$this->add_linked_stylesheet(utils::GetAbsoluteUrlAppRoot().'css/font-awesome/css/all.min.css');
}
/**
* @inheritDoc
* @since 3.2.0
*/
protected function GetFaviconAbsoluteUrl()
{
return Branding::GetLoginFavIconAbsoluteUrl();
}
public static function SetLoginFailedMessage($sMessage)
{
self::$m_sLoginFailedMessage = $sMessage;
@@ -259,7 +248,6 @@ class LoginWebPage extends NiceWebPage
$oEmail = new Email();
$oEmail->SetRecipientTO($sTo);
$sFrom = MetaModel::GetConfig()->Get('forgot_password_from');
$sFrom = utils::IsNullOrEmptyString($sFrom) ? MetaModel::GetConfig()->Get('email_default_sender_address') : $sFrom;
$oEmail->SetRecipientFrom($sFrom);
$oEmail->SetSubject(Dict::S('UI:ResetPwd-EmailSubject', $oUser->Get('login')));
$sResetUrl = utils::GetAbsoluteUrlAppRoot().'pages/UI.php?loginop=reset_pwd&auth_user='.urlencode($oUser->Get('login')).'&token='.urlencode($sToken);
@@ -919,13 +907,13 @@ class LoginWebPage extends NiceWebPage
$aAllProfiles = array();
while ($oProfile = $oProfilesSet->Fetch())
{
$aAllProfiles[mb_strtolower($oProfile->GetName())] = $oProfile->GetKey();
$aAllProfiles[strtolower($oProfile->GetName())] = $oProfile->GetKey();
}
$aProfiles = array();
foreach ($aRequestedProfiles as $sRequestedProfile)
{
$sRequestedProfile = mb_strtolower($sRequestedProfile);
$sRequestedProfile = strtolower($sRequestedProfile);
if (isset($aAllProfiles[$sRequestedProfile]))
{
$aProfiles[] = $aAllProfiles[$sRequestedProfile];

View File

@@ -22,7 +22,6 @@
// Maintenance message display functions
// Only included by approot.inc.php
//
use Combodo\iTop\Application\WebPage\ErrorPage;
/**
* Use a setup page to display the maintenance message

View File

@@ -5,9 +5,6 @@
*/
use Combodo\iTop\Application\Helper\WebResourcesHelper;
use Combodo\iTop\Application\WebPage\ErrorPage;
use Combodo\iTop\Application\WebPage\iTopWebPage;
use Combodo\iTop\Application\WebPage\WebPage;
require_once(APPROOT.'/application/utils.inc.php');
require_once(APPROOT.'/application/template.class.inc.php');
@@ -106,7 +103,7 @@ class ApplicationMenu
{
self::$sFavoriteSiloQuery = $sOQL;
}
/**
* Get the query used to limit the list of displayed organizations in the drop-down menu
* @return string The OQL query returning a list of Organization objects
@@ -348,7 +345,7 @@ class ApplicationMenu
/**
* Entry point to display the whole menu into the web page, used by iTopWebPage
* @param WebPage $oPage
* @param \WebPage $oPage
* @param array $aExtraParams
* @throws DictExceptionMissingString
*
@@ -422,7 +419,7 @@ EOF
/**
* Handles the display of the sub-menus (called recursively if necessary)
*
* @param WebPage $oPage
* @param \WebPage $oPage
* @param array $aMenus
* @param array $aExtraParams
* @param int $iActiveMenu
@@ -539,7 +536,7 @@ EOF
return -1;
}
/**
* Retrieves the currently active menu (if any, otherwise the first menu is the default)
* @return string The Id of the currently active menu
@@ -547,7 +544,7 @@ EOF
public static function GetActiveNodeId()
{
$oAppContext = new ApplicationContext();
$sMenuId = $oAppContext->GetCurrentValue('menu', null);
$sMenuId = $oAppContext->GetCurrentValue('menu', null);
if ($sMenuId === null)
{
$sMenuId = self::GetDefaultMenuId();
@@ -657,7 +654,7 @@ abstract class MenuNode
/**
* Stimulus to check: if the user can 'apply' this stimulus, then she/he can see this menu
*/
*/
protected $m_aEnableStimuli;
/**
@@ -817,7 +814,7 @@ abstract class MenuNode
{
return false;
}
/**
* Add a limiting display condition for the same menu node. The conditions will be combined with a AND
* @param $oMenuNode MenuNode Another definition of the same menu node, with potentially different access restriction
@@ -990,7 +987,7 @@ class TemplateMenuNode extends MenuNode
* @var string
*/
protected $sTemplateFile;
/**
* Create a menu item based on a custom template and inserts it into the application's main menu
* @param string $sMenuId Unique identifier of the menu (used to identify the menu for bookmarking, and for getting the labels from the dictionary)
@@ -1061,7 +1058,7 @@ class OQLMenuNode extends MenuNode
* @var bool|null
*/
protected $bSearchFormOpen;
/**
* Extra parameters to be passed to the display block to fine tune its appearence
*/
@@ -1094,7 +1091,7 @@ class OQLMenuNode extends MenuNode
// Enhancement: we could set as the "enable" condition that the user has enough rights to "read" the objects
// of the class specified by the OQL...
}
/**
* Set some extra parameters to be passed to the display block to fine tune its appearence
* @param array $aParams paramCode => value. See DisplayBlock::GetDisplay for the meaning of the parameters
@@ -1114,7 +1111,7 @@ class OQLMenuNode extends MenuNode
*/
public function RenderContent(WebPage $oPage, $aExtraParams = array())
{
$oTag = new ContextTag(ContextTag::TAG_OBJECT_SEARCH);
ContextTag::AddContext(ContextTag::TAG_OBJECT_SEARCH);
ApplicationMenu::CheckMenuIdEnabled($this->GetMenuId());
OQLMenuNode::RenderOQLSearch
(
@@ -1123,7 +1120,7 @@ class OQLMenuNode extends MenuNode
'Menu_'.$this->GetMenuId(),
$this->bSearch, // Search pane
$this->bSearchFormOpen, // Search open
$oPage,
$oPage,
array_merge($this->m_aParams, $aExtraParams),
true
);
@@ -1357,10 +1354,10 @@ class NewObjectMenuNode extends MenuNode
{
// Enable this menu, only if the current user has enough rights to create such an object, or an object of
// any child class
$aSubClasses = MetaModel::EnumChildClasses($this->sClass, ENUM_CHILD_CLASSES_ALL); // Including the specified class itself
$bActionIsAllowed = false;
foreach($aSubClasses as $sCandidateClass)
{
if (!MetaModel::IsAbstract($sCandidateClass) && (UserRights::IsActionAllowed($sCandidateClass, UR_ACTION_MODIFY) == UR_ALLOWED_YES))
@@ -1369,7 +1366,7 @@ class NewObjectMenuNode extends MenuNode
break; // Enough for now
}
}
return $bActionIsAllowed;
return $bActionIsAllowed;
}
/**
@@ -1511,7 +1508,7 @@ class DashboardMenuNode extends MenuNode
throw new Exception("Error: failed to load dashboard file: '{$this->sDashboardFile}'");
}
}
}
/**
@@ -1552,7 +1549,7 @@ class ShortcutContainerMenuNode extends MenuNode
$sName = $this->GetMenuId().'_'.$oShortcut->GetKey();
new ShortcutMenuNode($sName, $oShortcut, $this->GetIndex(), $fRank++);
}
// Complete the tree
//
parent::PopulateChildMenus();

View File

@@ -1,6 +1,6 @@
<?php
/**
* @deprecated 3.0.0 will be removed in 3.1.0 - moved to sources/Application/WebPage/NiceWebPage.php, now loadable using autoloader
* @deprecated will be removed in 3.1.0 - moved to sources/Application/WebPage/NiceWebPage.php, now loadable using autoloader
* @license http://opensource.org/licenses/AGPL-3.0
* @copyright Copyright (C) 2010-2023 Combodo SARL
*/

View File

@@ -1,6 +1,6 @@
<?php
/**
* @deprecated 3.0.0 will be removed in 3.1.0 - moved to sources/Application/WebPage/PDFPage.php, now loadable using autoloader
* @deprecated will be removed in 3.1.0 - moved to sources/Application/WebPage/PDFPage.php, now loadable using autoloader
* @license http://opensource.org/licenses/AGPL-3.0
* @copyright Copyright (C) 2010-2023 Combodo SARL
*/

View File

@@ -21,7 +21,6 @@ use Combodo\iTop\Application\UI\Base\Component\Alert\AlertUIBlockFactory;
use Combodo\iTop\Application\UI\Base\Component\FieldSet\FieldSetUIBlockFactory;
use Combodo\iTop\Application\UI\Base\Component\Html\Html;
use Combodo\iTop\Application\UI\Base\Component\Input\TextArea;
use Combodo\iTop\Application\WebPage\WebPage;
abstract class Query extends cmdbAbstractObject
{

View File

@@ -16,7 +16,6 @@
// You should have received a copy of the GNU Affero General Public License
// along with iTop. If not, see <http://www.gnu.org/licenses/>
use Combodo\iTop\Application\UI\Base\Component\DataTable\DataTableSettings;
use Combodo\iTop\Application\WebPage\WebPage;
/**

View File

@@ -17,9 +17,6 @@
* You should have received a copy of the GNU Affero General Public License
*/
use Combodo\iTop\Application\WebPage\iTopWebPage;
use Combodo\iTop\Application\WebPage\WebPage;
require_once(APPROOT.'/application/displayblock.class.inc.php');
/**
* This class manages the special template format used internally to build the iTop web pages

View File

@@ -536,7 +536,7 @@ CSS;
if (static::HasImageExtension($sImg)
&& ! array_key_exists($sImg, $aImages))
{
$sFilePath = utils::RealPath($sImg, APPROOT);
$sFilePath = realpath($sImg);
if ($sFilePath !== false) {
$sFilePathWithSlashes = str_replace('\\', '/', $sFilePath);
$aImages[$sImg] = $sFilePathWithSlashes;
@@ -544,7 +544,7 @@ CSS;
}
$sCanonicalPath = static::CanonicalizePath($sTargetThemeFolderPath.'/'.$sImg);
$sFilePath = utils::RealPath($sCanonicalPath, APPROOT);
$sFilePath = realpath($sCanonicalPath);
if ($sFilePath !== false) {
$sFilePathWithSlashes = str_replace('\\', '/', $sFilePath);
$aImages[$sImg] = $sFilePathWithSlashes;

View File

@@ -7,7 +7,6 @@
use Combodo\iTop\Application\Helper\FormHelper;
use Combodo\iTop\Application\UI\Base\Component\Form\FormUIBlockFactory;
use Combodo\iTop\Application\UI\Base\Layout\UIContentBlockUIBlockFactory;
use Combodo\iTop\Application\WebPage\WebPage;
use Combodo\iTop\Core\MetaModel\FriendlyNameType;
require_once(APPROOT.'/application/displayblock.class.inc.php');
@@ -66,7 +65,7 @@ class UIExtKeyWidget
//public function __construct($sAttCode, $sClass, $sTitle, $oAllowedValues, $value, $iInputId, $bMandatory, $sNameSuffix = '', $sFieldPrefix = '', $sFormPrefix = '')
/**
* @param WebPage $oPage
* @param \WebPage $oPage
* @param string $sAttCode
* @param string $sClass
* @param string $sTitle
@@ -133,7 +132,7 @@ class UIExtKeyWidget
}
/**
* @param WebPage $oPage
* @param \WebPage $oPage
* @param int $iMaxComboLength
* @param bool $bAllowTargetCreation
* @param string $sTitle
@@ -164,7 +163,7 @@ class UIExtKeyWidget
$oPage->add_linked_script('../js/extkeywidget.js');
$oPage->add_linked_script('../js/forms-json-utils.js');
$bCreate = (!$this->bSearchMode) && (UserRights::IsActionAllowed($this->sTargetClass, UR_ACTION_MODIFY) && $bAllowTargetCreation);
$bCreate = (!$this->bSearchMode) && (UserRights::IsActionAllowed($this->sTargetClass, UR_ACTION_BULK_MODIFY) && $bAllowTargetCreation);
$bExtensions = true;
$sMessage = Dict::S('UI:Message:EmptyList:UseSearchForm');
$sAttrFieldPrefix = ($this->bSearchMode) ? '' : 'attr_';
@@ -445,7 +444,7 @@ JS
/**
* Get the HTML fragment corresponding to the ext key editing widget
*
* @param WebPage $oPage
* @param \WebPage $oPage
* @param int $iMaxComboLength
* @param boolean $bAllowTargetCreation
* @param string $sTitle
@@ -976,10 +975,6 @@ HTML
// Remove blob edition from creation form @see N°5863 to allow blob edition in modal context
FormHelper::DisableAttributeBlobInputs($this->sTargetClass, $aFormExtraParams);
if(FormHelper::HasMandatoryAttributeBlobInputs($oNewObj)){
$oPage->AddUiBlock(FormHelper::GetAlertForMandatoryAttributeBlobInputsInModal(FormHelper::ENUM_MANDATORY_BLOB_MODE_CREATE));
}
cmdbAbstractObject::DisplayCreationForm($oPage, $this->sTargetClass, $oNewObj, array(), $aFormExtraParams);
$oPage->add(<<<HTML
</div>

View File

@@ -16,7 +16,6 @@
// You should have received a copy of the GNU Affero General Public License
// along with iTop. If not, see <http://www.gnu.org/licenses/>
use Combodo\iTop\Application\Helper\WebResourcesHelper;
use Combodo\iTop\Application\WebPage\WebPage;
/**
* Class UIHTMLEditorWidget
@@ -72,16 +71,15 @@ class UIHTMLEditorWidget
// To change the default settings of the editor,
// a) edit the file /js/ckeditor/config.js
// b) or override some of the configuration settings, using the second parameter of ckeditor()
$sJSDefineWidth = '';
$aConfig = utils::GetCkeditorPref();
$sWidthSpec = addslashes(trim($this->m_oAttDef->GetWidth()));
if ($sWidthSpec != '') {
/*N°6543 - the function min allow to keep text inside the column when width is defined*/
$aConfig['width'] = "min($sWidthSpec,100%)";
$sJSDefineWidth = '$("#cke_'.$iId.' iframe").contents().find("body").css("width", "'.$sWidthSpec.'")';
if ($sWidthSpec != '')
{
$aConfig['width'] = $sWidthSpec;
}
$sHeightSpec = addslashes(trim($this->m_oAttDef->GetHeight()));
if ($sHeightSpec != '') {
if ($sHeightSpec != '')
{
$aConfig['height'] = $sHeightSpec;
}
$sConfigJS = json_encode($aConfig);
@@ -112,7 +110,6 @@ $('#$iId').on('update', function(evt){
else
{
oMe.data('ckeditorInstance').setReadOnly(oMe.prop('disabled'));
$sJSDefineWidth
}
};
setTimeout(delayedSetReadOnly, 50);

View File

@@ -6,7 +6,6 @@
use Combodo\iTop\Application\Helper\FormHelper;
use Combodo\iTop\Application\UI\Links\Direct\BlockDirectLinkSetEditTable;
use Combodo\iTop\Application\WebPage\WebPage;
use Combodo\iTop\Renderer\Console\ConsoleBlockRenderer;
/**
@@ -144,10 +143,6 @@ JS
// Remove blob edition from creation form @see N°5863 to allow blob edition in modal context
FormHelper::DisableAttributeBlobInputs($sRealClass, $aFormExtraParams);
if(FormHelper::HasMandatoryAttributeBlobInputs($oObj)){
$oPage->AddUiBlock(FormHelper::GetAlertForMandatoryAttributeBlobInputsInModal(FormHelper::ENUM_MANDATORY_BLOB_MODE_CREATE));
}
cmdbAbstractObject::DisplayCreationForm($oPage, $sRealClass, $oObj, array(), $aFormExtraParams);
}

View File

@@ -8,8 +8,6 @@ use Combodo\iTop\Application\UI\Base\Component\DataTable\DataTableUIBlockFactory
use Combodo\iTop\Application\UI\Base\Component\DataTable\StaticTable\FormTableRow\FormTableRow;
use Combodo\iTop\Application\UI\Links\Indirect\BlockIndirectLinkSetEditTable;
use Combodo\iTop\Application\UI\Links\Indirect\BlockObjectPickerDialog;
use Combodo\iTop\Application\WebPage\JsonPage;
use Combodo\iTop\Application\WebPage\WebPage;
use Combodo\iTop\Renderer\Console\ConsoleBlockRenderer;
require_once(APPROOT.'application/displayblock.class.inc.php');

View File

@@ -24,8 +24,6 @@
* @license http://opensource.org/licenses/AGPL-3.0
*/
use Combodo\iTop\Application\WebPage\WebPage;
require_once(APPROOT.'/application/displayblock.class.inc.php');
class UIPasswordWidget

View File

@@ -21,8 +21,6 @@
*/
use Combodo\iTop\Application\WebPage\WebPage;
require_once(APPROOT.'/application/displayblock.class.inc.php');
class UISearchFormForeignKeys

View File

@@ -15,7 +15,6 @@
//
// You should have received a copy of the GNU Affero General Public License
// along with iTop. If not, see <http://www.gnu.org/licenses/>
use Combodo\iTop\Application\WebPage\iTopWebPage;
/**

View File

@@ -20,10 +20,7 @@
use Combodo\iTop\Application\Helper\Session;
use Combodo\iTop\Application\UI\Base\iUIBlock;
use Combodo\iTop\Application\UI\Base\Layout\UIContentBlock;
use Combodo\iTop\Application\UI\Hook\iKeyboardShortcut;
use Combodo\iTop\Application\WebPage\WebPage;
use Combodo\iTop\Service\Module\ModuleService;
use Combodo\iTop\Test\UnitTest\Application\utilsTest;
use ScssPhp\ScssPhp\Compiler;
use ScssPhp\ScssPhp\OutputStyle;
use ScssPhp\ScssPhp\ValueConverter;
@@ -55,31 +52,22 @@ class utils
{
/**
* @var string
* @since 2.7.10 3.0.0
* @since 3.0.0
*/
public const ENUM_SANITIZATION_FILTER_INTEGER = 'integer';
/**
* Datamodel class
* @var string
* @since 2.7.10 3.0.0
* @since 2.7.10 3.0.4 3.1.1 3.2.0 N°6606 update PHPDoc
* @uses MetaModel::IsValidClass()
* @since 3.0.0
*/
public const ENUM_SANITIZATION_FILTER_CLASS = 'class';
/**
* @var string
* @since 2.7.10 3.0.4 3.1.1 3.2.0 N°6606
* @uses class_exists()
*/
public const ENUM_SANITIZATION_FILTER_PHP_CLASS = 'php_class';
/**
* @var string
* @since 2.7.10 3.0.0
* @since 3.0.0
*/
public const ENUM_SANITIZATION_FILTER_STRING = 'string';
/**
* @var string
* @since 2.7.10 3.0.0
* @since 3.0.0
*/
public const ENUM_SANITIZATION_FILTER_CONTEXT_PARAM = 'context_param';
/**
@@ -94,22 +82,22 @@ class utils
public const ENUM_SANITIZATION_FILTER_OPERATION = 'operation';
/**
* @var string
* @since 2.7.10 3.0.0
* @since 3.0.0
*/
public const ENUM_SANITIZATION_FILTER_PARAMETER = 'parameter';
/**
* @var string
* @since 2.7.10 3.0.0
* @since 3.0.0
*/
public const ENUM_SANITIZATION_FILTER_FIELD_NAME = 'field_name';
/**
* @var string
* @since 2.7.10 3.0.0
* @since 3.0.0
*/
public const ENUM_SANITIZATION_FILTER_TRANSACTION_ID = 'transaction_id';
/**
* @var string For XML / HTML node identifiers
* @since 2.7.10 3.0.0
* @since 3.0.0
*/
public const ENUM_SANITIZATION_FILTER_ELEMENT_IDENTIFIER = 'element_identifier';
/**
@@ -119,13 +107,12 @@ class utils
public const ENUM_SANITIZATION_FILTER_VARIABLE_NAME = 'variable_name';
/**
* @var string
* @since 2.7.10 3.0.0
* @since 3.0.0
*/
public const ENUM_SANITIZATION_FILTER_RAW_DATA = 'raw_data';
/**
* @var string
* @since 3.0.2 3.1.0 N°4899
* @since 2.7.10 N°6606
* @since 3.0.2, 3.1.0 N°4899
*/
public const ENUM_SANITIZATION_FILTER_URL = 'url';
@@ -168,12 +155,6 @@ class utils
private static $iNextId = 0;
/**
* @var ?string
* @used-by GetAbsoluteUrlAppRoot
*/
private static $sAbsoluteUrlAppRootCache = null;
protected static function LoadParamFile($sParamFile)
{
if (!file_exists($sParamFile)) {
@@ -415,10 +396,6 @@ class utils
* @since 2.7.0 new 'element_identifier' filter
* @since 3.0.0 new utils::ENUM_SANITIZATION_* const
* @since 2.7.7, 3.0.2, 3.1.0 N°4899 - new 'url' filter
* @since 2.7.10 N°6606 use the utils::ENUM_SANITIZATION_* const
* @since 2.7.10 N°6606 new case for ENUM_SANITIZATION_FILTER_PHP_CLASS
*
* @link https://www.php.net/manual/en/filter.filters.sanitize.php PHP sanitization filters
*/
protected static function Sanitize_Internal($value, $sSanitizationFilter)
{
@@ -439,13 +416,6 @@ class utils
$retValue = filter_var($value, FILTER_SANITIZE_SPECIAL_CHARS);
break;
case static::ENUM_SANITIZATION_FILTER_PHP_CLASS:
$retValue = $value;
if (!class_exists($value)) {
$retValue = false;
}
break;
case static::ENUM_SANITIZATION_FILTER_CONTEXT_PARAM:
case static::ENUM_SANITIZATION_FILTER_ROUTE:
case static::ENUM_SANITIZATION_FILTER_OPERATION:
@@ -511,7 +481,6 @@ class utils
// For URL
case static::ENUM_SANITIZATION_FILTER_URL:
// N°6350 - returns only valid URLs
$retValue = filter_var($value, FILTER_VALIDATE_URL);
break;
@@ -1042,27 +1011,28 @@ class utils
return $bTrustProxies;
}
/**
* Returns the absolute URL to the application root path
*
* @param bool $bForceTrustProxy
*
* @return string The absolute URL to the application root, without the first slash
*
* @throws \Exception
*
* @since 2.7.4 $bForceTrustProxy param added
*/
/**
* Returns the absolute URL to the application root path
*
* @param bool $bForceTrustProxy
*
* @return string The absolute URL to the application root, without the first slash
*
* @throws \Exception
*
* @since 2.7.4 $bForceTrustProxy param added
*/
public static function GetAbsoluteUrlAppRoot($bForceTrustProxy = false)
{
if (static::$sAbsoluteUrlAppRootCache === null || $bForceTrustProxy)
static $sUrl = null;
if ($sUrl === null || $bForceTrustProxy)
{
static::$sAbsoluteUrlAppRootCache = self::GetConfig()->Get('app_root_url');
if (static::$sAbsoluteUrlAppRootCache == '')
$sUrl = self::GetConfig()->Get('app_root_url');
if ($sUrl == '')
{
static::$sAbsoluteUrlAppRootCache = self::GetDefaultUrlAppRoot($bForceTrustProxy);
$sUrl = self::GetDefaultUrlAppRoot($bForceTrustProxy);
}
elseif (strpos(static::$sAbsoluteUrlAppRootCache, SERVER_NAME_PLACEHOLDER) > -1)
elseif (strpos($sUrl, SERVER_NAME_PLACEHOLDER) > -1)
{
if (isset($_SERVER['SERVER_NAME']))
{
@@ -1073,10 +1043,10 @@ class utils
// CLI mode ?
$sServerName = php_uname('n');
}
static::$sAbsoluteUrlAppRootCache = str_replace(SERVER_NAME_PLACEHOLDER, $sServerName, static::$sAbsoluteUrlAppRootCache);
$sUrl = str_replace(SERVER_NAME_PLACEHOLDER, $sServerName, $sUrl);
}
}
return static::$sAbsoluteUrlAppRootCache;
return $sUrl;
}
/**
@@ -1458,7 +1428,7 @@ class utils
/**
* Merge standard menu items with plugin provided menus items
*
* @param WebPage $oPage
* @param \WebPage $oPage
* @param int $iMenuId
* @param \DBObjectSet $param
* @param array $aActions
@@ -2504,17 +2474,15 @@ SQL;
$aHeaders = static::ParseHeaders($http_response_header);
$sMimeType = array_key_exists('Content-Type', $aHeaders) ? strtolower($aHeaders['Content-Type']) : 'application/x-octet-stream';
// Compute the file extension from the MIME Type
foreach ($aKnownExtensions as $sExtValue => $sMime) {
if ($sMime === $sMimeType) {
foreach($aKnownExtensions as $sExtValue => $sMime)
{
if ($sMime === $sMimeType)
{
$sExtension = '.'.$sExtValue;
break;
}
}
}
$sPathName = pathinfo($sPath, PATHINFO_FILENAME);
if (utils::IsNotNullOrEmptyString($sPathName)) {
$sFileName = $sPathName;
}
$sFileName .= $sExtension;
}
$oUploadedDoc = new ormDocument($sData, $sMimeType, $sFileName);
@@ -2961,7 +2929,7 @@ HTML;
$aResultPref = [];
$aShortcutPrefs = appUserPreferences::GetPref('keyboard_shortcuts', []);
// Note: Mind the 4 blackslashes, see utils::GetClassesForInterface()
$aShortcutClasses = utils::GetClassesForInterface(iKeyboardShortcut::class, '', array('[\\\\/]lib[\\\\/]', '[\\\\/]node_modules[\\\\/]', '[\\\\/]test[\\\\/]', '[\\\\/]tests[\\\\/]'));
$aShortcutClasses = utils::GetClassesForInterface('iKeyboardShortcut', '', array('[\\\\/]lib[\\\\/]', '[\\\\/]node_modules[\\\\/]', '[\\\\/]test[\\\\/]', '[\\\\/]tests[\\\\/]'));
foreach ($aShortcutClasses as $cShortcutPlugin) {
$sTriggeredElement = $cShortcutPlugin::GetShortcutTriggeredElementSelector();
@@ -3036,7 +3004,6 @@ HTML;
*
* @return bool if string null or empty
* @since 3.0.2 N°5302
* @since 2.7.10 N°6458 add method in the 2.7 branch
*/
public static function IsNullOrEmptyString(?string $sString): bool
{
@@ -3052,7 +3019,6 @@ HTML;
*
* @return bool if string is not null and not empty
* @since 3.0.2 N°5302
* @since 2.7.10 N°6458 add method in the 2.7 branch
*/
public static function IsNotNullOrEmptyString(?string $sString): bool
{

View File

@@ -1,6 +1,6 @@
<?php
/**
* @deprecated 3.0.0 will be removed in 3.1.0 - moved to sources/Application/WebPage/WebPage.php, now loadable using autoloader
* @deprecated will be removed in 3.1.0 - moved to sources/Application/WebPage/WebPage.php, now loadable using autoloader
* @license http://opensource.org/licenses/AGPL-3.0
* @copyright Copyright (C) 2010-2023 Combodo SARL
*/

View File

@@ -24,8 +24,6 @@
* @license http://opensource.org/licenses/AGPL-3.0
*/
use Combodo\iTop\Application\WebPage\WebPage;
require_once(APPROOT.'/application/uiwizard.class.inc.php');
class WizardHelper
@@ -353,7 +351,6 @@ class WizardHelper
/**
* @return string JS code to be executed for fields update
* @since 3.0.0 N°3198
* @deprecated 3.0.3-2 3.0.4 3.1.1 3.2.0 Use {@see \WizardHelper::AddJsForUpdateFields()} instead
*/
public function GetJsForUpdateFields()
{
@@ -366,32 +363,6 @@ class WizardHelper
JS;
}
/**
* Add necessary JS snippets (to the page) to be executed for fields update
*
* @param WebPage $oPage
* @return void
* @since 3.0.3-2 3.0.4 3.1.1 3.2.0 N°6766
*/
public function AddJsForUpdateFields(WebPage $oPage)
{
$sWizardHelperJsVar = (!is_null($this->m_aData['m_sWizHelperJsVarName'])) ? utils::Sanitize($this->m_aData['m_sWizHelperJsVarName'], '', utils::ENUM_SANITIZATION_FILTER_PARAMETER) : 'oWizardHelper'.$this->GetFormPrefix();
$sWizardHelperJson = $this->ToJSON();
$oPage->add_script(<<<JS
{$sWizardHelperJsVar}.m_oData = {$sWizardHelperJson};
{$sWizardHelperJsVar}.UpdateFields();
JS
);
$oPage->add_ready_script(<<<JS
if ({$sWizardHelperJsVar}.m_oDependenciesUpdatedPromiseResolve !== null){
{$sWizardHelperJsVar}.m_oDependenciesUpdatedPromiseResolve();
}
JS
);
}
/*
* Function with an old pattern of code
* @deprecated 3.1.0
@@ -400,9 +371,11 @@ JS
{
$aSet = json_decode($sJsonSet, true); // true means hash array instead of object
$oSet = CMDBObjectSet::FromScratch($sLinkClass);
foreach ($aSet as $aLinkObj) {
foreach ($aSet as $aLinkObj)
{
$oLink = MetaModel::NewObject($sLinkClass);
foreach ($aLinkObj as $sAttCode => $value) {
foreach ($aLinkObj as $sAttCode => $value)
{
$oAttDef = MetaModel::GetAttributeDef($sLinkClass, $sAttCode);
if (($oAttDef->IsExternalKey()) && ($value != '') && ($value > 0))
{

View File

@@ -1,6 +1,6 @@
<?php
/**
* @deprecated 3.0.0 will be removed in 3.1.0 - moved to sources/Application/WebPage/XMLPage.php, now loadable using autoloader
* @deprecated will be removed in 3.1.0 - moved to sources/Application/WebPage/XMLPage.php, now loadable using autoloader
* @license http://opensource.org/licenses/AGPL-3.0
* @copyright Copyright (C) 2010-2023 Combodo SARL
*/

View File

@@ -11,7 +11,7 @@ define('APPCONF', APPROOT.'conf/');
*
* @see ITOP_CORE_VERSION to get full iTop core version
*/
define('ITOP_DESIGN_LATEST_VERSION', '3.2');
define('ITOP_DESIGN_LATEST_VERSION', '3.1');
/**
* Constant containing the iTop core version, whatever application was built
@@ -23,13 +23,11 @@ define('ITOP_DESIGN_LATEST_VERSION', '3.2');
* @used-by utils::GetItopVersionWikiSyntax()
* @used-by iTopModulesPhpVersionIntegrationTest
*/
define('ITOP_CORE_VERSION', '3.2.0');
define('ITOP_CORE_VERSION', '3.1.0');
/**
* @var string
* @since 3.0.4 3.1.0 3.2.0 N°6274 Allow to test if PHPUnit is currently running. Starting with PHPUnit 9.5 we'll be able to replace it with $GLOBALS['phpunit_version']
* @since 3.0.4 3.1.1 3.2.0 N°6976 Fix constant name (DeprecatedCallsLog error handler was never set)
* @since 3.0.4 N°6274 Allow to test if PHPUnit is currently running. Starting with PHPUnit 9.5 we'll be able to replace it with $GLOBALS['phpunit_version']
*/
const ITOP_PHPUNIT_RUNNING_CONSTANT_NAME = 'ITOP_PHPUNIT_RUNNING';
define('ITOP_PHPUNIT_RUNNING_CONSTANT_NAME', 'ITOP_PHPUNIT_RUNNING');
require_once APPROOT.'bootstrap.inc.php';

View File

@@ -4,7 +4,7 @@
"type": "project",
"license": "AGPL-3.0-only",
"require": {
"php": ">=8.1.0 <8.4.0",
"php": ">=7.4.0 <8.2.0",
"ext-ctype": "*",
"ext-dom": "*",
"ext-gd": "*",
@@ -13,32 +13,28 @@
"ext-mysqli": "*",
"ext-soap": "*",
"apereo/phpcas": "~1.6.0",
"firebase/php-jwt": "^6.4.0",
"combodo/tcpdf": "~6.4.4",
"firebase/php-jwt": "~6.4.0",
"guzzlehttp/guzzle": "^7.5.1",
"laminas/laminas-mail": "^2.11",
"laminas/laminas-servicemanager": "^3.5",
"league/oauth2-google": "^4.0.1",
"nikic/php-parser": "^4.14.0",
"league/oauth2-google": "^3.0",
"nikic/php-parser": "~4.14.0",
"pear/archive_tar": "~1.4.14",
"pelago/emogrifier": "^7.2.0",
"psr/log": "^3.0.0",
"scssphp/scssphp": "^1.12.1",
"symfony/console": "~6.4.0",
"symfony/dotenv": "~6.4.0",
"symfony/framework-bundle": "~6.4.0",
"symfony/http-foundation": "~6.4.0",
"symfony/http-kernel": "~6.4.0",
"symfony/runtime": "~6.4.0",
"symfony/twig-bundle": "~6.4.0",
"symfony/var-dumper": "~6.4.0",
"symfony/yaml": "~6.4.0",
"tecnickcom/tcpdf": "^6.6.0",
"pelago/emogrifier": "^6.0.0",
"scssphp/scssphp": "^1.10.3",
"symfony/console": "5.4.*",
"symfony/dotenv": "5.4.*",
"symfony/framework-bundle": "5.4.*",
"symfony/http-foundation": "5.4.*",
"symfony/http-kernel": "5.4.*",
"symfony/twig-bundle": "5.4.*",
"symfony/yaml": "5.4.*",
"thenetworg/oauth2-azure": "^2.0"
},
"require-dev": {
"symfony/debug-bundle": "~6.4.0",
"symfony/stopwatch": "~6.4.0",
"symfony/web-profiler-bundle": "~6.4.0"
"symfony/stopwatch": "5.4.*",
"symfony/web-profiler-bundle": "5.4.*"
},
"suggest": {
"ext-libsodium": "Required to use the AttributeEncryptedString.",
@@ -50,7 +46,7 @@
},
"config": {
"platform": {
"php": "8.1.0"
"php": "7.4.0"
},
"vendor-dir": "lib",
"preferred-install": {
@@ -58,10 +54,7 @@
},
"sort-packages": true,
"classmap-authoritative": true,
"platform-check": true,
"allow-plugins": {
"symfony/runtime": true
}
"platform-check": true
},
"autoload": {
"classmap": [
@@ -79,9 +72,6 @@
"application/logindefault.class.inc.php",
"application/loginexternal.class.inc.php",
"application/loginurl.class.inc.php"
],
"files": [
"sources/alias.php"
]
},
"conflict": {
@@ -91,15 +81,11 @@
"symfony": {
"allow-contrib": false,
"require": "3.4.*"
},
"runtime": {
"dotenv_path": "symfony/.env"
}
},
"scripts": {
"post-install-cmd": ["@rmDeniedTestDir", "@tcpdfCustomFonts"],
"post-update-cmd": ["@rmDeniedTestDir", "@tcpdfCustomFonts"],
"rmDeniedTestDir": "@php .make/composer/rmDeniedTestDir.php",
"tcpdfCustomFonts": "@php .make/composer/tcpdf/tcpdfUpdateFonts.php"
"post-install-cmd": ["@rmDeniedTestDir"],
"post-update-cmd": ["@rmDeniedTestDir"],
"rmDeniedTestDir": "@php .make/composer/rmDeniedTestDir.php"
}
}

2073
composer.lock generated

File diff suppressed because it is too large Load Diff

View File

@@ -60,7 +60,6 @@ class DbConnectionWrapper
*
* @param \mysqli|null $oMysqli
* @since 3.0.4 3.1.1 3.2.0 Param $oMysqli becomes nullable
* @since 3.1.0-4 N°6848 backport of restoring cnx on null parameter value
*/
public static function SetDbConnectionMockForQuery(?mysqli $oMysqli = null): void
{

View File

@@ -521,6 +521,6 @@ class Str
public static function islowcase($sString)
{
return (mb_strtolower($sString) == $sString);
return (strtolower($sString) == $sString);
}
}

View File

@@ -17,11 +17,6 @@
// along with iTop. If not, see <http://www.gnu.org/licenses/>
use Combodo\iTop\Application\TwigBase\Twig\TwigHelper;
use Combodo\iTop\Application\UI\Base\Component\DataTable\DataTableUIBlockFactory;
use Combodo\iTop\Application\WebPage\WebPage;
use Combodo\iTop\Service\Notification\NotificationsRepository;
use Combodo\iTop\Service\Notification\NotificationsService;
use Combodo\iTop\Service\Router\Router;
/**
* Persistent classes (internal): user defined actions
@@ -81,7 +76,6 @@ abstract class Action extends cmdbAbstractObject
MetaModel::Init_AddAttribute(new AttributeLinkedSetIndirect("trigger_list",
array("linked_class" => "lnkTriggerAction", "ext_key_to_me" => "action_id", "ext_key_to_remote" => "trigger_id", "allowed_values" => null, "count_min" => 0, "count_max" => 0, "depends_on" => array(), "display_style" => 'property')));
MetaModel::Init_AddAttribute(new AttributeEnum("asynchronous", array("allowed_values" => new ValueSetEnum(['use_global_setting' => 'Use global settings','yes' => 'Yes' ,'no' => 'No']), "sql" => "asynchronous", "default_value" => 'use_global_setting', "is_null_allowed" => false, "depends_on" => array())));
// Display lists
// - Attributes to be displayed for the complete details
@@ -173,100 +167,6 @@ abstract class Action extends cmdbAbstractObject
$this->m_aCheckWarnings[] = Dict::S('Action:WarningNoTriggerLinked');
}
}
/**
* @since 3.2.0 N°5472 method creation
*/
public function DisplayBareRelations(WebPage $oPage, $bEditMode = false)
{
parent::DisplayBareRelations($oPage, false);
if ($oPage instanceof iTopWebPage) {
$this->GenerateLastExecutionsTab($oPage, $bEditMode);
}
}
/**
* @since 3.2.0 N°5472 method creation
*/
protected function GenerateLastExecutionsTab(iTopWebPage $oPage, $bEditMode)
{
$oRouter = Router::GetInstance();
$sActionLastExecutionsPageUrl = $oRouter->GenerateUrl('notifications.action.last_executions_tab', ['action_id' => $this->GetKey()]);
$oPage->AddAjaxTab('action_errors', $sActionLastExecutionsPageUrl, false, Dict::S('Action:last_executions_tab'));
}
/**
* @param \Combodo\iTop\Application\WebPage\WebPage $oPage
*
* @throws \ApplicationException
* @throws \ArchivedObjectException
* @throws \ConfigException
* @throws \CoreException
* @throws \CoreUnexpectedValue
* @throws \DictExceptionMissingString
* @throws \InvalidConfigParamException
* @throws \MissingQueryArgument
* @throws \MySQLException
* @throws \MySQLHasGoneAwayException
* @throws \OQLException
* @throws \ReflectionException
* @since 3.2.0 N°5472 method creation
*/
public function GetLastExecutionsTabContent(WebPage $oPage): void
{
$oConfig = utils::GetConfig();
$sLastExecutionDaysConfigParamName = 'notifications.last_executions_days';
$iLastExecutionDays = $oConfig->Get($sLastExecutionDaysConfigParamName);
if ($iLastExecutionDays < 0) {
throw new InvalidConfigParamException("Invalid value for {$sLastExecutionDaysConfigParamName} config parameter. Param desc: " . $oConfig->GetDescription($sLastExecutionDaysConfigParamName));
}
$sActionQueryOql = 'SELECT EventNotification WHERE action_id = :action_id';
$aActionQueryParams = ['action_id' => $this->GetKey()];
if ($iLastExecutionDays > 0) {
$sActionQueryOql .= ' AND date > DATE_SUB(NOW(), INTERVAL :days DAY)';
$aActionQueryParams['days'] = $iLastExecutionDays;
$sActionQueryLimit = Dict::Format('Action:last_executions_tab_limit_days', $iLastExecutionDays);
} else {
$sActionQueryLimit = Dict::S('Action:last_executions_tab_limit_none');
}
$oActionFilter = DBObjectSearch::FromOQL($sActionQueryOql, $aActionQueryParams);
$oSet = new DBObjectSet($oActionFilter, ['date' => false]);
$sPanelTitle = Dict::Format('Action:last_executions_tab_panel_title', $sActionQueryLimit);
$oExecutionsListBlock = DataTableUIBlockFactory::MakeForResult($oPage, 'action_executions_list', $oSet, ['panel_title' => $sPanelTitle]);
$oPage->AddUiBlock($oExecutionsListBlock);
}
/**
* Will be overloaded by the children classes to return the value of their global asynchronous setting (eg. `email_asynchronous` for `\ActionEmail`, `prefer_asynchronous` for `\ActionWebhook`, ...)
*
* @return bool true if the global setting for this kind of action if to be executed asynchronously, false otherwise.
* @since 3.2.0
*/
public static function GetAsynchronousGlobalSetting(): bool
{
return false;
}
/**
* @return bool true if that action instance should be executed asynchronously, otherwise false
* @throws \ArchivedObjectException
* @throws \CoreException
* @since 3.2.0
*/
public function IsAsynchronous(): bool
{
$sAsynchronous = $this->Get('asynchronous');
if ($sAsynchronous === 'use_global_setting') {
return static::GetAsynchronousGlobalSetting();
}
return $sAsynchronous === 'yes';
}
}
/**
@@ -301,39 +201,12 @@ abstract class ActionNotification extends Action
MetaModel::Init_SetZListItems('details', array('name', 'description', 'status', 'trigger_list'));
// - Attributes to be displayed for a list
MetaModel::Init_SetZListItems('list', array('finalclass', 'description', 'status'));
MetaModel::Init_AddAttribute(new AttributeApplicationLanguage("language", array("sql"=>"language", "default_value"=>null, "is_null_allowed"=>true, "depends_on"=>array())));
// Search criteria
// - Criteria of the std search form
// MetaModel::Init_SetZListItems('standard_search', array('name'));
// - Default criteria of the search form
// MetaModel::Init_SetZListItems('default_search', array('name'));
}
/**
* @param $sLanguage
* @param $sLanguageCode
*
* @return array [$sPreviousLanguage, $aPreviousPluginProperties]
* @throws \ArchivedObjectException
* @throws \CoreException
* @throws \DictExceptionUnknownLanguage
* @since 3.2.0
*/
public function SetNotificationLanguage($sLanguage = null, $sLanguageCode = null){
$sPreviousLanguage = Dict::GetUserLanguage();
$aPreviousPluginProperties = ApplicationContext::GetPluginProperties('QueryLocalizerPlugin');
$sLanguage = $sLanguage ?? $this->Get('language');
$sLanguageCode = $sLanguageCode ?? $sLanguage;
if (!utils::IsNullOrEmptyString($sLanguage)) {
// If a language is specified for this action, force this language
// when rendering all placeholders inside this message
Dict::SetUserLanguage($sLanguage);
AttributeDateTime::LoadFormatFromConfig();
ApplicationContext::SetPluginProperty('QueryLocalizerPlugin', 'language_code', $sLanguageCode);
}
return [$sPreviousLanguage, $aPreviousPluginProperties];
}
}
/**
@@ -384,7 +257,6 @@ class ActionEmail extends ActionNotification
"db_table" => "priv_action_email",
"db_key_field" => "id",
"db_finalclass_field" => "",
'style' => new ormStyle(null, null, null, null, null, '../images/icons/icons8-mailing.svg'),
);
MetaModel::Init_Params($aParams);
MetaModel::Init_InheritAttributes();
@@ -401,6 +273,7 @@ class ActionEmail extends ActionNotification
MetaModel::Init_AddAttribute(new AttributeTemplateString("subject", array("allowed_values" => null, "sql" => "subject", "default_value" => null, "is_null_allowed" => false, "depends_on" => array())));
MetaModel::Init_AddAttribute(new AttributeTemplateHTML("body", array("allowed_values" => null, "sql" => "body", "default_value" => null, "is_null_allowed" => false, "depends_on" => array())));
MetaModel::Init_AddAttribute(new AttributeEnum("importance", array("allowed_values" => new ValueSetEnum('low,normal,high'), "sql" => "importance", "default_value" => 'normal', "is_null_allowed" => false, "depends_on" => array())));
MetaModel::Init_AddAttribute(new AttributeApplicationLanguage("language", array("sql"=>"language", "default_value"=>null, "is_null_allowed"=>true, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeBlob("html_template", array("is_null_allowed"=>true, "depends_on"=>array(), "always_load_in_tables"=>false)));
MetaModel::Init_AddAttribute(new AttributeEnum("ignore_notify", array("allowed_values" => new ValueSetEnum('yes,no'), "sql" => "ignore_notify", "default_value" => 'yes', "is_null_allowed" => false, "depends_on" => array())));
@@ -421,7 +294,6 @@ class ActionEmail extends ActionNotification
),
'fieldset:ActionEmail:trigger' => array(
0 => 'trigger_list',
1 => 'asynchronous'
),
),
'col:col2' => array(
@@ -456,33 +328,27 @@ class ActionEmail extends ActionNotification
protected $m_aMailErrors; //array of strings explaining the issue
/**
* Return the list of emails as a string, or a detailed error description
* Return a the list of emails as a string, or a detailed error description
*
* @param string $sRecipAttCode
* @param array $aArgs
*
* @return string
* @throws \ArchivedObjectException
* @throws \CoreCannotSaveObjectException
* @throws \CoreException
* @throws \CoreUnexpectedValue
* @throws \CoreWarning
* @throws \MissingQueryArgument
* @throws \MySQLException
* @throws \MySQLHasGoneAwayException
* @throws \OQLException
*/
protected function FindRecipients($sRecipAttCode, $aArgs)
{
$oTrigger = $aArgs['trigger->object()'] ?? null;
$sOQL = $this->Get($sRecipAttCode);
if (utils::IsNullOrEmptyString($sOQL)) return '';
if (strlen($sOQL) === 0) return '';
try
{
$oSearch = DBObjectSearch::FromOQL($sOQL);
if ($this->Get('ignore_notify') === 'no') {
// In theory, it is possible to notify *any* kind of object,
// In theory it is possible to notify *any* kind of object,
// as long as there is an email attribute in the class
// So let's not assume that the selected class is a Person
$sFirstSelectedClass = $oSearch->GetClass();
@@ -515,29 +381,16 @@ class ActionEmail extends ActionNotification
return "The objects of the class '$sClass' do not have any email attribute";
}
if($oTrigger !== null && in_array('Contact', MetaModel::EnumParentClasses($sClass, ENUM_CHILD_CLASSES_ALL), true)) {
$aArgs['trigger_id'] = $oTrigger->GetKey();
$aArgs['action_id'] = $this->GetKey();
$sSubscribedContactsOQL = NotificationsRepository::GetInstance()->GetSearchOQLContactUnsubscribedByTriggerAndAction();
$sSubscribedContactsOQL->ApplyParameters($aArgs);
$sAlias = $oSearch->GetClassAlias();
$oSearch->AddConditionExpression(Expression::FromOQL("`$sAlias`.id NOT IN ($sSubscribedContactsOQL)"));
}
$oSet = new DBObjectSet($oSearch, array() /* order */, $aArgs);
$aRecipients = array();
while ($oObj = $oSet->Fetch())
{
$sAddress = trim($oObj->Get($sEmailAttCode));
if (utils::IsNotNullOrEmptyString($sAddress))
if (strlen($sAddress) > 0)
{
$aRecipients[] = $sAddress;
$this->m_iRecipients++;
}
if ($oTrigger !== null && in_array('Contact', MetaModel::EnumParentClasses($sClass, ENUM_CHILD_CLASSES_ALL), true)) {
NotificationsService::GetInstance()->RegisterSubscription($oTrigger, $this, $oObj);
}
}
return implode(', ', $aRecipients);
}
@@ -657,7 +510,7 @@ class ActionEmail extends ActionNotification
else
{
$aErrors = [];
$iRes = $oEmail->Send($aErrors, $this->IsAsynchronous() ? Email::ENUM_SEND_FORCE_ASYNCHRONOUS : Email::ENUM_SEND_FORCE_SYNCHRONOUS, $oLog);
$iRes = $oEmail->Send($aErrors, false, $oLog); // allow asynchronous mode
switch ($iRes)
{
case EMAIL_SEND_OK:
@@ -686,17 +539,8 @@ class ActionEmail extends ActionNotification
* @param \EventNotification $oLog
*
* @return array
* @throws \ArchivedObjectException
* @throws \CoreCannotSaveObjectException
* @throws \CoreException
* @throws \CoreUnexpectedValue
* @throws \CoreWarning
* @throws \DictExceptionMissingString
* @throws \DictExceptionUnknownLanguage
* @throws \MissingQueryArgument
* @throws \MySQLException
* @throws \MySQLHasGoneAwayException
* @throws \OQLException
* @throws \Exception
* @since 3.1.0 N°918
*/
protected function PrepareMessageContent($aContextArgs, &$oLog): array
@@ -717,7 +561,15 @@ class ActionEmail extends ActionNotification
'attachments' => [],
];
$sPreviousUrlMaker = ApplicationContext::SetUrlMakerClass();
[$sPreviousLanguage, $aPreviousPluginProperties] = $this->SetNotificationLanguage();
$sPreviousLanguage = Dict::GetUserLanguage();
$aPreviousPluginProperties = ApplicationContext::GetPluginProperties('QueryLocalizerPlugin');
if ($this->Get('language') !== '') {
// If a language is specified for this action, force this language
// when rendering all placeholders inside this message
Dict::SetUserLanguage($this->Get('language'));
AttributeDateTime::LoadFormatFromConfig();
ApplicationContext::SetPluginProperty('QueryLocalizerPlugin', 'language_code', $this->Get('language'));
}
try
{
@@ -749,7 +601,9 @@ class ActionEmail extends ActionNotification
}
finally {
ApplicationContext::SetUrlMakerClass($sPreviousUrlMaker);
$this->SetNotificationLanguage($sPreviousLanguage, $aPreviousPluginProperties['language_code'] ?? null);
Dict::SetUserLanguage($sPreviousLanguage);
AttributeDateTime::LoadFormatFromConfig();
ApplicationContext::SetPluginProperty('QueryLocalizerPlugin', 'language_code', $aPreviousPluginProperties['language_code'] ?? null);
}
if (!is_null($oLog)) {
@@ -775,7 +629,9 @@ class ActionEmail extends ActionNotification
$oLog->Set('body', HTMLSanitizer::Sanitize($aMessageContent['body']));
}
}
$sStyles = file_get_contents(APPROOT.'css/email.css');
$sStyles .= MetaModel::GetConfig()->Get('email_css');
if ($this->IsBeingTested()) {
$sTestBody = $aMessageContent['body'];
$sTestBody .= "<div style=\"border: dashed;\">\n";
@@ -804,11 +660,10 @@ class ActionEmail extends ActionNotification
if (isset($aContextArgs['attachments']))
{
$aAttachmentReport = array();
/** @var \ormDocument $oDocument */
foreach($aContextArgs['attachments'] as $oDocument)
{
$aMessageContent['attachments'][] = ['data' => $oDocument->GetData(), 'filename' => $oDocument->GetFileName(), 'mime_type' => $oDocument->GetMimeType()];
$aAttachmentReport[] = array($oDocument->GetFileName(), $oDocument->GetMimeType(), strlen($oDocument->GetData() ?? ''));
$aAttachmentReport[] = array($oDocument->GetFileName(), $oDocument->GetMimeType(), strlen($oDocument->GetData()));
}
$oLog->Set('attachments', $aAttachmentReport);
}
@@ -918,13 +773,4 @@ class ActionEmail extends ActionNotification
}
}
}
/**
* @inheritDoc
* @since 3.2.0
*/
public static function GetAsynchronousGlobalSetting(): bool
{
return utils::GetConfig()->Get('email_asynchronous');
}
}

View File

@@ -97,31 +97,6 @@ function apc_delete($key)
return $bRet1 || $bRet2;
}
/**
* Checks if APCu emulation key exists
*
* @param string|string[] $keys A string, or an array of strings, that contain keys.
*
* @return bool|string[] Returns TRUE if the key exists, otherwise FALSE
* Or if an array was passed to keys, then an array is returned that
* contains all existing keys, or an empty array if none exist.
* @since 3.2.0 N°7068
*/
function apc_exists($keys)
{
if (is_array($keys)) {
$aExistingKeys = [];
foreach ($keys as $sKey) {
if (apcFile::ExistsOneFile($sKey)) {
$aExistingKeys[] = $sKey;
}
}
return $aExistingKeys;
} else {
return apcFile::ExistsOneFile($keys);
}
}
class apcFile
{
// Check only once per request
@@ -208,16 +183,6 @@ class apcFile
return true;
}
/**
* Check if cache key exists
* @param $sKey
* @return bool
* @since 3.2.0 N°7068
*/
static public function ExistsOneFile($sKey) {
return is_file(self::GetCacheFileName('-' . $sKey)) || is_file(self::GetCacheFileName($sKey));
}
/** Get one cache entry content.
* @param $sKey
* @return bool|mixed

View File

@@ -15,7 +15,6 @@
//
// You should have received a copy of the GNU Affero General Public License
// along with iTop. If not, see <http://www.gnu.org/licenses/>
use Combodo\iTop\Service\Notification\Event\EventiTopNotificationService;
/**
@@ -458,87 +457,3 @@ class AsyncSendEmail extends AsyncTask
return '';
}
}
/**
* An async notification to be sent to iTop users
* @since 3.2.0
*/
class AsyncSendiTopNotifications extends AsyncTask {
public static function Init()
{
$aParams = array
(
"category" => "core/cmdb",
"key_type" => "autoincrement",
"name_attcode" => "created",
"state_attcode" => "",
"reconc_keys" => array(),
"db_table" => "priv_async_send_itop_notifications",
"db_key_field" => "id",
"db_finalclass_field" => "",
);
MetaModel::Init_Params($aParams);
MetaModel::Init_InheritAttributes();
MetaModel::Init_AddAttribute(new AttributeText("recipients", array("allowed_values"=>null, "sql"=>"recipients", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeExternalKey("action_id", array("targetclass"=>"Action", "allowed_values"=>null, "sql"=>"action_id", "default_value"=>null, "is_null_allowed"=>false, "on_target_delete"=>DEL_AUTO, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeExternalKey("trigger_id", array("targetclass"=>"Trigger", "allowed_values"=>null, "sql"=>"trigger_id", "default_value"=>null, "is_null_allowed"=>false, "on_target_delete"=>DEL_AUTO, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeText("title", array("allowed_values"=>null, "sql"=>"title", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeText("message", array("allowed_values"=>null, "sql"=>"message", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeInteger("object_id", array("allowed_values"=>null, "sql"=>"object_id", "default_value"=>null, "is_null_allowed"=>false, "on_target_delete"=>DEL_AUTO, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeString("object_class", array("allowed_values"=>null, "sql"=>"object_class", "default_value"=>null, "is_null_allowed"=>false, "on_target_delete"=>DEL_AUTO, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeText("url", array("allowed_values"=>null, "sql"=>"url", "default_value"=>null, "is_null_allowed"=>false, "on_target_delete"=>DEL_AUTO, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeDateTime("date", array("allowed_values"=>null, "sql"=>"date", "default_value"=>null, "is_null_allowed"=>false, "on_target_delete"=>DEL_AUTO, "depends_on"=>array())));
}
/**
* @throws \ArchivedObjectException
* @throws \CoreCannotSaveObjectException
* @throws \CoreException
* @throws \CoreUnexpectedValue
* @throws \CoreWarning
* @throws \MySQLException
* @throws \OQLException
*/
public static function AddToQueue(int $iActionId, int $iTriggerId, array $aRecipients, string $sMessage, string $sTitle, string $sUrl, int $iObjectId, ?string $sObjectClass): void
{
$oNew = new static();
$oNew->Set('action_id', $iActionId);
$oNew->Set('trigger_id', $iTriggerId);
$oNew->Set('recipients', json_encode($aRecipients));
$oNew->Set('message', $sMessage);
$oNew->Set('title', $sTitle);
$oNew->Set('url', $sUrl);
$oNew->Set('object_id', $iObjectId);
$oNew->Set('object_class', $sObjectClass);
$oNew->SetCurrentDate('date');
$oNew->DBInsert();
}
/**
* @inheritDoc
*/
public function DoProcess()
{
$oAction = MetaModel::GetObject('Action', $this->Get('action_id'));
$iTriggerId = $this->Get('trigger_id');
$aRecipients = json_decode($this->Get('recipients'));
$sMessage = $this->Get('message');
$sTitle = $this->Get('title');
$sUrl = $this->Get('url');
$iObjectId = $this->Get('object_id');
$sObjectClass = $this->Get('object_class');
$sDate = $this->Get('date');
foreach ($aRecipients as $iRecipientId)
{
$oEvent = EventiTopNotificationService::MakeEventFromAction($oAction, $iRecipientId, $iTriggerId, $sMessage, $sTitle, $sUrl, $iObjectId, $sObjectClass, $sDate);
$oEvent->DBInsertNoReload();
}
return "Sent";
}
}

View File

@@ -6,7 +6,6 @@
use Combodo\iTop\Application\UI\Base\Component\FieldBadge\FieldBadgeUIBlockFactory;
use Combodo\iTop\Application\UI\Links\Set\BlockLinkSetDisplayAsProperty;
use Combodo\iTop\Application\WebPage\WebPage;
use Combodo\iTop\Form\Field\LabelField;
use Combodo\iTop\Form\Field\TextAreaField;
use Combodo\iTop\Form\Form;
@@ -92,12 +91,6 @@ define('LINKSET_EDITMODE_ACTIONS', 2); // Show the usual 'Actions' popup menu
define('LINKSET_EDITMODE_INPLACE', 3); // The "linked" objects can be created/modified/deleted in place
define('LINKSET_EDITMODE_ADDREMOVE', 4); // The "linked" objects can be added/removed in place
define('LINKSET_EDITWHEN_NEVER', 0); // The linkset cannot be edited at all from inside this object
define('LINKSET_EDITWHEN_ON_HOST_EDITION', 1); // The only possible action is to open a new window to create a new object
define('LINKSET_EDITWHEN_ON_HOST_DISPLAY', 2); // Show the usual 'Actions' popup menu
define('LINKSET_EDITWHEN_ALWAYS', 3); // Show the usual 'Actions' popup menu
define('LINKSET_DISPLAY_STYLE_PROPERTY', 'property');
define('LINKSET_DISPLAY_STYLE_TAB', 'tab');
@@ -798,7 +791,7 @@ abstract class AttributeDefinition
public function HasAValue($proposedValue): bool
{
// Default implementation, we don't really know what type $proposedValue will be
return !(is_null($proposedValue));
return is_null($proposedValue);
}
/**
@@ -1710,15 +1703,6 @@ class AttributeLinkedSet extends AttributeDefinition
public function GetEditMode()
{
return $this->GetOptional('edit_mode', LINKSET_EDITMODE_ACTIONS);
}
/**
* @return int see LINKSET_EDITWHEN_* constants
* @since 3.1.1 3.2.0 N°6385
*/
public function GetEditWhen(): int
{
return $this->GetOptional('edit_when', LINKSET_EDITWHEN_ALWAYS);
}
/**
@@ -1740,20 +1724,11 @@ class AttributeLinkedSet extends AttributeDefinition
* @return bool true if Attribute has constraints
* @since 3.1.0 N°6228
*/
public function HasPHPConstraint(): bool
public function GetHasConstraint()
{
return $this->GetOptional('with_php_constraint', false);
}
/**
* @return bool true if Attribute has computation (DB_LINKS_CHANGED event propagation, `with_php_computation` attribute xml property), false otherwise
* @since 3.1.1 3.2.0 N°6228
*/
public function HasPHPComputation(): bool
{
return $this->GetOptional('with_php_computation', false);
}
public function GetLinkedClass()
{
return $this->Get('linked_class');
@@ -3062,11 +3037,6 @@ class AttributeObjectKey extends AttributeDBFieldVoid
return ((int) $proposedValue) !== 0;
}
/**
* @inheritDoc
*
* @param int|DBObject $proposedValue Object key or valid ({@see MetaModel::IsValidObject()}) datamodel object
*/
public function MakeRealValue($proposedValue, $oHostObj)
{
if (is_null($proposedValue))
@@ -3079,6 +3049,7 @@ class AttributeObjectKey extends AttributeDBFieldVoid
}
if (MetaModel::IsValidObject($proposedValue))
{
/** @var \DBObject $proposedValue */
return $proposedValue->GetKey();
}
@@ -3510,7 +3481,7 @@ class AttributeBoolean extends AttributeInteger
$sProposedValue, $bLocalizedValue = false, $sSepItem = null, $sSepAttribute = null, $sSepValue = null,
$sAttributeQualifier = null
) {
$sInput = mb_strtolower(trim($sProposedValue));
$sInput = strtolower(trim($sProposedValue));
if ($bLocalizedValue)
{
switch ($sInput)
@@ -4535,6 +4506,7 @@ class AttributeText extends AttributeString
$sStyle = '';
if (count($aStyles) > 0)
{
$aStyles[] = 'overflow:auto';
$sStyle = 'style="'.implode(';', $aStyles).'"';
}
@@ -6514,11 +6486,6 @@ class AttributeDateTime extends AttributeDBField
}
}
/**
* @inheritDoc
*
* @param int|string $proposedValue timestamp ({@see DateTime::getTimestamp()) or date as string, following the {@see GetInternalFormat} format.
*/
public function MakeRealValue($proposedValue, $oHostObj)
{
if (is_null($proposedValue))
@@ -8308,9 +8275,9 @@ class AttributeBlob extends AttributeDefinition
}
/**
* {@inheritDoc}
*
* @param string $proposedValue Can be an URL (including an URL to iTop itself), or a local path (CSV import)
* Users can provide the document from an URL (including an URL on iTop itself)
* for CSV import. Administrators can even provide the path to a local file
* {@inheritDoc}
*
* @see AttributeDefinition::MakeRealValue()
*/
@@ -8551,7 +8518,7 @@ class AttributeBlob extends AttributeDefinition
$sFingerprint = '';
if ($value instanceOf ormDocument)
{
$sFingerprint = $value->GetSignature();
$sFingerprint = md5($value->GetData());
}
return $sFingerprint;
@@ -8617,7 +8584,7 @@ class AttributeBlob extends AttributeDefinition
public function RecordAttChange(DBObject $oObject, $original, $value): void
{
// N°6502 Don't record history if only the download count has changed
if ((null !== $original) && (null !== $value) && $original->EqualsExceptDownloadsCount($value)) {
if ($original->EqualsExceptDownloadsCount($value)) {
return;
}
@@ -8662,20 +8629,6 @@ class AttributeImage extends AttributeBlob
parent::__construct($sCode, $aParams);
}
public function Get($sParamName)
{
$oParamValue = parent::Get($sParamName);
if ($sParamName === 'default_image') {
/** @noinspection NestedPositiveIfStatementsInspection */
if (!empty($oParamValue)) {
return utils::GetAbsoluteUrlModulesRoot() . $oParamValue;
}
}
return $oParamValue;
}
public function GetEditClass()
{
return "Image";
@@ -13019,7 +12972,7 @@ class AttributeRedundancySettings extends AttributeDBField
* Display an option (form, or current value)
*
* @param string $sCurrentValue
* @param WebPage $oPage
* @param \WebPage $oPage
* @param string $sFormPrefix
* @param bool $bEditMode
* @param string $sUserOption

View File

@@ -25,7 +25,6 @@ MetaModel::IncludeModule('application/audit.domain.class.inc.php');
MetaModel::IncludeModule('application/query.class.inc.php');
MetaModel::IncludeModule('setup/moduleinstallation.class.inc.php');
MetaModel::IncludeModule('core/event.class.inc.php');
MetaModel::IncludeModule('core/action.class.inc.php');
MetaModel::IncludeModule('core/trigger.class.inc.php');

View File

@@ -6,9 +6,6 @@
// The BOM is added at the head of exported UTF-8 CSV data, and removed (if present) from input UTF-8 data.
// This helps MS-Excel (Version > 2007, Windows only) in changing its interpretation of a CSV file (by default Excel reads data as ISO-8859-1 -not 100% sure!)
use Combodo\iTop\Application\WebPage\iTopWebPage;
use Combodo\iTop\Application\WebPage\WebPage;
define('UTF8_BOM', chr(239).chr(187).chr(191)); // 0xEF, 0xBB, 0xBF
@@ -163,7 +160,7 @@ class CellStatus_SearchIssue extends CellStatus_Issue
* @param null $sAllowedValues : used for additional message that provides allowed values $sAllowedValues for current class
* @param string|null $sAllowedValuesSearch : used to search all allowed values
*/
public function __construct($sSerializedSearch, $sReason, $sClass = null, $sAllowedValues = null, string $sAllowedValuesSearch = null)
public function __construct($sSerializedSearch, $sReason, $sClass=null, $sAllowedValues=null, string $sAllowedValuesSearch=null)
{
parent::__construct(null, null, $sReason);
$this->sSerializedSearch = $sSerializedSearch;
@@ -198,7 +195,7 @@ class CellStatus_SearchIssue extends CellStatus_Issue
public function GetSearchLinkUrl()
{
return sprintf("UI.php?operation=search&filter=%s",
rawurlencode($this->sSerializedSearch ?? "")
rawurlencode($this->sSerializedSearch)
);
}
@@ -209,7 +206,7 @@ class CellStatus_SearchIssue extends CellStatus_Issue
public function GetAllowedValuesLinkUrl(): ?string
{
return sprintf("UI.php?operation=search&filter=%s",
rawurlencode($this->sAllowedValuesSearch ?? "")
rawurlencode($this->sAllowedValuesSearch)
);
}
}
@@ -265,7 +262,7 @@ class CellStatus_Ambiguous extends CellStatus_Issue
public function GetSearchLinkUrl()
{
return sprintf("UI.php?operation=search&filter=%s",
rawurlencode($this->sSerializedSearch ?? "")
rawurlencode($this->sSerializedSearch)
);
}
}

View File

@@ -17,9 +17,6 @@
* You should have received a copy of the GNU Affero General Public License
*/
use Combodo\iTop\Application\WebPage\Page;
use Combodo\iTop\Application\WebPage\WebPage;
define('EXPORTER_DEFAULT_CHUNK_SIZE', 1000);
class BulkExportException extends Exception
@@ -152,9 +149,7 @@ abstract class BulkExport
$this->oSearch = null;
$this->iChunkSize = 0;
$this->sFormatCode = null;
$this->aStatusInfo = [
'show_obsolete_data' => utils::ShowObsoleteData(),
];
$this->aStatusInfo = array();
$this->oBulkExportResult = null;
$this->sTmpFile = '';
$this->bLocalizeOutput = false;
@@ -208,17 +203,15 @@ abstract class BulkExport
if ($oInfo && ($oInfo->Get('user_id') == UserRights::GetUserId()))
{
$sFormatCode = $oInfo->Get('format');
$aStatusInfo = json_decode($oInfo->Get('status_info'),true);
$oSearch = DBObjectSearch::unserialize($oInfo->Get('search'));
$oSearch->SetShowObsoleteData($aStatusInfo['show_obsolete_data']);
$oBulkExporter = self::FindExporter($sFormatCode, $oSearch);
if ($oBulkExporter)
{
$oBulkExporter->SetFormat($sFormatCode);
$oBulkExporter->SetObjectList($oSearch);
$oBulkExporter->SetChunkSize($oInfo->Get('chunk_size'));
$oBulkExporter->SetStatusInfo($aStatusInfo);
$oBulkExporter->SetStatusInfo(json_decode($oInfo->Get('status_info'), true));
$oBulkExporter->SetLocalizeOutput($oInfo->Get('localize_output'));
@@ -296,7 +289,6 @@ abstract class BulkExport
*/
public function SetObjectList(DBSearch $oSearch)
{
$oSearch->SetShowObsoleteData($this->aStatusInfo['show_obsolete_data']);
$this->oSearch = $oSearch;
}
@@ -394,7 +386,7 @@ abstract class BulkExport
/**
* @param WebPage $oP
* @param \WebPage $oP
* @param $sPartId
*
* @return UIContentBlock

View File

@@ -335,7 +335,7 @@ abstract class CMDBObject extends DBObject
$oMyChangeOp->Set("objclass", MetaModel::GetRootClass(get_class($this)));
$oMyChangeOp->Set("objkey", $objkey);
$oMyChangeOp->Set("fclass", get_class($this));
$oMyChangeOp->SetTrim("fname", $this->GetRawName()); // Protect against very long friendly names
$oMyChangeOp->Set("fname", substr($this->GetRawName(), 0, 255)); // Protect against very long friendly names
$iId = $oMyChangeOp->DBInsertNoReload();
}
@@ -438,8 +438,7 @@ abstract class CMDBObject extends DBObject
}
/**
* @deprecated 3.1.0 N°5232 N°6966 simply use {@see DBObject::DBClone()} instead, that will automatically create and persist a CMDBChange object.
* If you need to persist your own, call {@see CMDBObject::SetCurrentChange()} before.
* @deprecated 3.1.0 N°5232 not used
*/
public function DBCloneTracked(CMDBChange $oChange, $newKey = null)
{
@@ -447,9 +446,6 @@ abstract class CMDBObject extends DBObject
$this->DBCloneTracked_Internal($newKey);
}
/**
* @deprecated 3.1.1 3.2.0 N°6966 We will have only one DBClone method in the future
*/
protected function DBCloneTracked_Internal($newKey = null)
{
$newKey = parent::DBClone($newKey);
@@ -474,13 +470,23 @@ abstract class CMDBObject extends DBObject
public function DBDelete(&$oDeletionPlan = null)
{
$this->LogCRUDEnter(__METHOD__);
$oDeletionPlan = parent::DBDelete($oDeletionPlan);
$oDeletionPlan = $this->DBDeleteTracked_Internal($oDeletionPlan);
$this->LogCRUDExit(__METHOD__);
return $oDeletionPlan;
}
/**
* @deprecated 3.1.1 3.2.0 N°6967 We will have only one DBDelete method in the future
* @param null $oDeletionPlan
*
* @return \DeletionPlan|null
* @throws \ArchivedObjectException
* @throws \CoreCannotSaveObjectException
* @throws \CoreException
* @throws \CoreUnexpectedValue
* @throws \DeleteException
* @throws \MySQLException
* @throws \MySQLHasGoneAwayException
* @throws \OQLException
*/
protected function DBDeleteTracked_Internal(&$oDeletionPlan = null)
{

View File

@@ -3,7 +3,7 @@
//
// This file is part of iTop.
//
// iTop is free software; you can redistribute it and/or modify
// 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.
@@ -42,12 +42,6 @@ class CMDBSource
const ENUM_DB_VENDOR_MARIADB = 'MariaDB';
const ENUM_DB_VENDOR_PERCONA = 'Percona';
/**
* @since 2.7.10 3.0.4 3.1.2 3.0.2 N°6889 constant creation
* @internal will be removed in a future version
*/
const MYSQL_DEFAULT_PORT = 3306;
/**
* Error: 1205 SQLSTATE: HY000 (ER_LOCK_WAIT_TIMEOUT)
* Message: Lock wait timeout exceeded; try restarting transaction
@@ -218,19 +212,16 @@ class CMDBSource
/**
* @param string $sDbHost initial value ("p:domain:port" syntax)
* @param string $sServer server variable to update
* @param int|null $iPort port variable to update, will return null if nothing is specified in $sDbHost
*
* @since 2.7.10 3.0.4 3.1.2 3.2.0 N°6889 will return null in $iPort if port isn't present in $sDbHost. Use {@see MYSQL_DEFAULT_PORT} if needed
*
* @link http://php.net/manual/en/mysqli.persistconns.php documentation for the "p:" prefix (persistent connexion)
* @param int $iPort port variable to update
*/
public static function InitServerAndPort($sDbHost, &$sServer, &$iPort)
{
$aConnectInfo = explode(':', $sDbHost);
$bUsePersistentConnection = false;
if (strcasecmp($aConnectInfo[0], 'p') === 0)
if (strcasecmp($aConnectInfo[0], 'p') == 0)
{
// we might have "p:" prefix to use persistent connections (see http://php.net/manual/en/mysqli.persistconns.php)
$bUsePersistentConnection = true;
$sServer = $aConnectInfo[0].':'.$aConnectInfo[1];
}
@@ -248,6 +239,10 @@ class CMDBSource
{
$iPort = (int)($aConnectInfo[1]);
}
else
{
$iPort = 3306;
}
}
/**
@@ -385,7 +380,7 @@ class CMDBSource
public static function GetDBVendor()
{
$sDBVendor = static::ENUM_DB_VENDOR_MYSQL;
$sVersionComment = static::GetServerVariable('version') . ' - ' . static::GetServerVariable('version_comment');
if(preg_match('/mariadb/i', $sVersionComment) === 1)
{
@@ -395,7 +390,7 @@ class CMDBSource
{
$sDBVendor = static::ENUM_DB_VENDOR_PERCONA;
}
return $sDBVendor;
}
@@ -939,7 +934,7 @@ class CMDBSource
{
throw new MySQLException('Failed to issue SQL query', array('query' => $sSql));
}
while ($aRow = $oResult->fetch_array($iMode))
{
$aData[] = $aRow;
@@ -1093,7 +1088,7 @@ class CMDBSource
if (!array_key_exists($iKey, $aTableInfo["Fields"])) return false;
$aFieldData = $aTableInfo["Fields"][$iKey];
if (!array_key_exists("Key", $aFieldData)) return false;
return ($aFieldData["Key"] == "PRI");
return ($aFieldData["Key"] == "PRI");
}
public static function IsAutoIncrement($sTable, $sField)
@@ -1104,7 +1099,7 @@ class CMDBSource
$aFieldData = $aTableInfo["Fields"][$sField];
if (!array_key_exists("Extra", $aFieldData)) return false;
//MyHelpers::debug_breakpoint($aFieldData);
return (strstr($aFieldData["Extra"], "auto_increment"));
return (strstr($aFieldData["Extra"], "auto_increment"));
}
public static function IsField($sTable, $sField)
@@ -1371,13 +1366,13 @@ class CMDBSource
public static function GetTableFieldsList($sTable)
{
assert(!empty($sTable));
$aTableInfo = self::GetTableInfo($sTable);
if (empty($aTableInfo)) return array(); // #@# or an error ?
return array_keys($aTableInfo["Fields"]);
}
// Cache the information about existing tables, and their fields
private static $m_aTablesInfo = array();
private static function _TablesInfoCacheReset($sTableName = null)
@@ -1510,7 +1505,7 @@ class CMDBSource
{
throw new MySQLException('Failed to issue SQL query', array('query' => $sSql));
}
$aRows = array();
while ($aRow = $oResult->fetch_array(MYSQLI_ASSOC))
{
@@ -1519,7 +1514,7 @@ class CMDBSource
$oResult->free();
return $aRows;
}
/**
* Returns the value of the specified server variable
* @param string $sVarName Name of the server variable
@@ -1535,7 +1530,7 @@ class CMDBSource
/**
* Returns the privileges of the current user
* @return string privileges in a raw format
*/
*/
public static function GetRawPrivileges()
{
try
@@ -1561,8 +1556,8 @@ class CMDBSource
/**
* Determine the slave status of the server
* @return bool true if the server is slave
*/
* @return bool true if the server is slave
*/
public static function IsSlaveServer()
{
try

View File

@@ -29,7 +29,7 @@ define('ITOP_APPLICATION_SHORT', 'iTop');
*
* @see ITOP_CORE_VERSION to get iTop core version
*/
define('ITOP_VERSION', '3.2.0-dev');
define('ITOP_VERSION', '3.1.1-dev');
define('ITOP_VERSION_NAME', 'Fullmoon');
define('ITOP_REVISION', 'svn');
@@ -447,14 +447,14 @@ class Config
'show_in_conf_sample' => true,
],
'export_pdf_font' => [ // @since 2.7.0 PR #49 / N°1947
'type' => 'string',
'description' => 'Font used when generating a PDF file',
'default' => 'DejaVuSans', // DejaVuSans is a UTF-8 Unicode font, embedded in the TCPPDF lib we're using
// Standard PDF fonts like helvetica or times newroman are NOT Unicode
// A new DroidSansFallback can be used to improve CJK support (se PR #49)
'value' => '',
'source_of_value' => '',
'show_in_conf_sample' => false,
'type' => 'string',
'description' => 'Font used when generating a PDF file',
'default' => 'DejaVuSans', // DejaVuSans is a UTF-8 Unicode font, embedded in the TCPPDF lib we're using
// Standard PDF fonts like helvetica or times newroman are NOT Unicode
// A new DroidSansFallback can be used to improve CJK support (se PR #49)
'value' => '',
'source_of_value' => '',
'show_in_conf_sample' => false,
],
'access_mode' => [
'type' => 'integer',
@@ -889,14 +889,6 @@ class Config
'source_of_value' => '',
'show_in_conf_sample' => false,
],
'forgot_password.url' => [
'type' => 'string',
'description' => 'Set this value to your "forgot password" service URL if it should be handled out of '.ITOP_APPLICATION_SHORT.'. Note that it will apply to all users (iTop users, LDAP users, ...)',
'default' => '',
'value' => '',
'source_of_value' => '',
'show_in_conf_sample' => false,
],
'deadline_format' => [
'type' => 'string',
'description' => 'The format used for displaying "deadline" attributes: any string with the following placeholders: $date$, $difference$',
@@ -1119,14 +1111,6 @@ class Config
'source_of_value' => '',
'show_in_conf_sample' => false,
],
'purge_data.max_chunk_size' => [
'type' => 'integer',
'description' => 'Maximum number of items deleted per loop. Used in function MetaModel::PurgeData',
'default' => 1000,
'value' => 1000,
'source_of_value' => '',
'show_in_conf_sample' => false,
],
'max_history_length' => [
'type' => 'integer',
'description' => 'Maximum length of the history table (in the "History" tab on each object) before it gets truncated. Latest modifications are displayed first.',
@@ -1209,30 +1193,6 @@ class Config
'source_of_value' => '',
'show_in_conf_sample' => false,
],
'sessions_tracking.enabled' => [
'type' => 'bool',
'description' => 'Whether or not the whole mechanism to track active sessions is enabled. See PHP session.gc_maxlifetime setting to configure session expiration.',
'default' => false,
'value' => '',
'source_of_value' => '',
'show_in_conf_sample' => false,
],
'sessions_tracking.gc_threshold' => [
'type' => 'integer',
'description' => 'fallback in case cron is not active: probability in percent that session files are cleanup during any itop request (100 means always)',
'default' => 1,
'value' => '',
'source_of_value' => '',
'show_in_conf_sample' => false,
],
'sessions_tracking.gc_duration_in_seconds' => [
'type' => 'integer',
'description' => 'fallback in case cron is not active: when a cleanup is triggered cleanup duration will not exceed this duration (in seconds).',
'default' => 1,
'value' => '',
'source_of_value' => '',
'show_in_conf_sample' => false,
],
'transaction_storage' => [
'type' => 'string',
'description' => 'The type of mechanism to use for storing the unique identifiers for transactions (Session|File).',
@@ -1332,9 +1292,9 @@ class Config
'draft_attachments_lifetime' => [
'type' => 'integer',
'description' => 'Lifetime (in seconds) of drafts\' attachments and inline images: after this duration, the garbage collector will delete them.',
'default' => 86400,
'value' => '',
'source_of_value' => '',
'default' => 86400,
'value' => '',
'source_of_value' => '',
'show_in_conf_sample' => false,
],
'date_and_time_format' => [
@@ -1611,38 +1571,6 @@ class Config
'source_of_value' => '',
'show_in_conf_sample' => false,
],
'notifications.itop.read_notification_retention' => [
'type' => 'integer',
'description' => 'Duration in days after which iTop read notifications will be deleted',
'default' => 182,
'value' => 182,
'source_of_value' => '',
'show_in_conf_sample' => false,
],
'notifications.itop.send_asynchronously' => [
'type' => 'bool',
'description' => 'If true then iTop notifications will be sent asynchronously',
'default' => false,
'value' => false,
'source_of_value' => '',
'show_in_conf_sample' => false,
],
'notifications.itop.newsroom_cache_time' => [
'type' => 'integer',
'description' => 'Duration in min between each fetch for notifications in newsroom',
'default' => 5,
'value' => 5,
'source_of_value' => '',
'show_in_conf_sample' => false,
],
'notifications.last_executions_days' => [
'type' => 'integer',
'description' => 'Number of days to display in the Action\'s last executions tab (0 means no limit)',
'default' => 30 + 31, // 2 months
'value' => 61,
'source_of_value' => '',
'show_in_conf_sample' => false,
],
'regenerate_session_id_enabled' => [
'type' => 'bool',
'description' => 'If true then session id will be regenerated on each login, to prevent session fixation.',
@@ -1691,14 +1619,6 @@ class Config
'source_of_value' => '',
'show_in_conf_sample' => false,
],
'security.enable_header_xcontent_type_options' => [
'type' => 'bool',
'description' => 'If set to false, iTop will stop sending the X-Content-Type-Options HTTP header. This header could trigger CORB protection on certain resources (JSON, XML, HTML, text) therefore blocking them.',
'default' => true,
'value' => '',
'source_of_value' => '',
'show_in_conf_sample' => false,
],
'security.disable_inline_documents_sandbox' => [
'type' => 'bool',
'description' => 'If true then the sandbox for documents displayed in a browser tab will be disabled; enabling scripts and other interactive content. Note that setting this to true will open the application to potential XSS attacks!',
@@ -1763,14 +1683,6 @@ class Config
'source_of_value' => '',
'show_in_conf_sample' => false,
],
'application.secret' => [
'type' => 'string',
'description' => 'Application secret, uses this value for encrypting the cookies used in the remember me functionality and for creating signed URIs when using ESI (Edge Side Includes).',
'default' => '',
'value' => '',
'source_of_value' => '',
'show_in_conf_sample' => false,
],
];
public function IsProperty($sPropCode)
@@ -1898,7 +1810,6 @@ class Config
* @var integer Number of seconds between two reloads of the display (standard)
*/
protected $m_iStandardReloadInterval;
/**
* @var integer Number of seconds between two reloads of the display (fast)
*/
@@ -1951,15 +1862,6 @@ class Config
*/
protected $m_iPasswordHashAlgo;
/**
* Symfony uses this value for encrypting the cookies used in the remember me functionality and for creating signed URIs when using ESI (Edge Side Includes).
*
* @see https://symfony.com/doc/current/reference/configuration/framework.html#secret
* @since 3.2.0 - N°6934 - Symfony 6.4 - upgrade Symfony bundles to 6.4
* @var string
*/
protected $m_sAppSecret;
/**
* Config constructor.
*
@@ -2004,7 +1906,6 @@ class Config
$this->m_aCharsets = array();
$this->m_bQueryCacheEnabled = DEFAULT_QUERY_CACHE_ENABLED;
$this->m_iPasswordHashAlgo = DEFAULT_HASH_ALGO;
$this->m_sAppSecret = bin2hex(random_bytes(16));
//define default encryption params according to php install
$aEncryptParams = SimpleCrypt::GetNewDefaultParams();
@@ -2165,7 +2066,6 @@ class Config
$this->m_sEncryptionLibrary = isset($MySettings['encryption_library']) ? trim($MySettings['encryption_library']) : $this->m_sEncryptionLibrary;
$this->m_aCharsets = isset($MySettings['csv_import_charsets']) ? $MySettings['csv_import_charsets'] : array();
$this->m_iPasswordHashAlgo = isset($MySettings['password_hash_algo']) ? $MySettings['password_hash_algo'] : $this->m_iPasswordHashAlgo;
$this->m_sAppSecret = isset($MySettings['application.secret']) ? trim($MySettings['application.secret']) : $this->m_sAppSecret;
}
protected function Verify()
@@ -2301,11 +2201,6 @@ class Config
return $this->m_sEncryptionKey;
}
public function GetAppSecret()
{
return $this->m_sAppSecret;
}
public function GetEncryptionLibrary()
{
return $this->m_sEncryptionLibrary;
@@ -2394,24 +2289,6 @@ class Config
$this->m_sAllowedLoginTypes = implode('|', $aAllowedLoginTypes);
}
/**
* @since 2.7.11 N°7085
* Add login mode if not configured already
* @param string $sLoginMode
*
* @return void
*/
public function AddAllowedLoginTypes($sLoginMode)
{
$aAllowedLoginTypes = $this->GetAllowedLoginTypes();
if (in_array($sLoginMode, $aAllowedLoginTypes)){
return;
}
$aAllowedLoginTypes[] = $sLoginMode;
$this->SetAllowedLoginTypes($aAllowedLoginTypes);
}
public function SetExternalAuthenticationVariable($sExtAuthVariable)
{
$this->m_sExtAuthVariable = $sExtAuthVariable;
@@ -2422,12 +2299,6 @@ class Config
$this->m_sEncryptionKey = $sKey;
}
public function SetAppSecret($sKey)
{
$this->m_sAppSecret = $sKey;
}
public function SetCSVImportCharsets($aCharsets)
{
$this->m_aCharsets = $aCharsets;
@@ -2479,7 +2350,6 @@ class Config
$aSettings['encryption_library'] = $this->m_sEncryptionLibrary;
$aSettings['csv_import_charsets'] = $this->m_aCharsets;
$aSettings['password_hash_algo'] = $this->m_iPasswordHashAlgo;
$aSettings['application.secret'] = $this->m_sAppSecret;
foreach ($this->m_aModuleSettings as $sModule => $aProperties)
{
@@ -2570,9 +2440,9 @@ class Config
// Old fashioned integer settings
$aIntValues = array(
'fast_reload_interval' => $this->m_iFastReloadInterval,
'max_display_limit' => $this->m_iMaxDisplayLimit,
'min_display_limit' => $this->m_iMinDisplayLimit,
'fast_reload_interval' => $this->m_iFastReloadInterval,
'max_display_limit' => $this->m_iMaxDisplayLimit,
'min_display_limit' => $this->m_iMinDisplayLimit,
'standard_reload_interval' => $this->m_iStandardReloadInterval,
);
foreach ($aIntValues as $sKey => $iValue)
@@ -2592,8 +2462,7 @@ class Config
'encryption_key' => $this->m_sEncryptionKey,
'encryption_library' => $this->m_sEncryptionLibrary,
'csv_import_charsets' => $this->m_aCharsets,
'password_hash_algo' => $this->m_iPasswordHashAlgo,
'application.secret' => $this->m_sAppSecret,
'password_hash_algo' => $this->m_iPasswordHashAlgo
);
foreach ($aOtherValues as $sKey => $value)
{

View File

@@ -8,13 +8,10 @@ use Combodo\iTop\Application\UI\Base\Component\FieldSet\FieldSetUIBlockFactory;
use Combodo\iTop\Application\UI\Base\Component\Html\Html;
use Combodo\iTop\Application\UI\Base\Component\Input\InputUIBlockFactory;
use Combodo\iTop\Application\UI\Base\Component\Input\Select\SelectOptionUIBlockFactory;
use Combodo\iTop\Application\UI\Base\Component\Input\Select\SelectUIBlockFactory;
use Combodo\iTop\Application\UI\Base\Component\Input\SelectUIBlockFactory;
use Combodo\iTop\Application\UI\Base\Component\Panel\PanelUIBlockFactory;
use Combodo\iTop\Application\UI\Base\Layout\MultiColumn\Column\ColumnUIBlockFactory;
use Combodo\iTop\Application\UI\Base\Layout\MultiColumn\MultiColumnUIBlockFactory;
use Combodo\iTop\Application\Helper\ExportHelper;
use Combodo\iTop\Application\WebPage\Page;
use Combodo\iTop\Application\WebPage\WebPage;
/**
* Bulk export: CSV export
@@ -103,7 +100,7 @@ class CSVBulkExport extends TabularBulkExport
}
/**
* @param WebPage $oP
* @param \WebPage $oP
* @param $sPartId
*
* @return UIContentBlock
@@ -117,7 +114,6 @@ class CSVBulkExport extends TabularBulkExport
case 'csv_options':
$oPanel = PanelUIBlockFactory::MakeNeutral(Dict::S('Core:BulkExport:CSVOptions'));
$oPanel->AddSubBlock(ExportHelper::GetAlertForExcelMaliciousInjection());
$oMulticolumn = MultiColumnUIBlockFactory::MakeStandard();
$oPanel->AddSubBlock($oMulticolumn);

View File

@@ -1,416 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<itop_design xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="3.2">
<classes>
<class id="lnkActionNotificationToContact" _delta="define">
<parent>cmdbAbstractObject</parent>
<properties>
<category>core/cmdb,application</category>
<abstract>false</abstract>
<key_type>autoincrement</key_type>
<db_table>priv_lnk_action_notif_to_contact</db_table>
<db_key_field>id</db_key_field>
<db_final_class_field/>
<naming>
<attributes>
<attribute id="action_id"/>
<attribute id="contact_id"/>
</attributes>
</naming>
<uniqueness_rules>
<rule>
<attributes>
<attribute id="action_id"/>
<attribute id="contact_id"/>
<attribute id="trigger_id"/>
</attributes>
<filter/>
<disabled>false</disabled>
<is_blocking>true</is_blocking>
</rule>
</uniqueness_rules>
</properties>
<fields>
<field id="action_id" xsi:type="AttributeExternalKey">
<sql>action_id</sql>
<target_class>ActionNotification</target_class>
<default_value/>
<is_null_allowed>false</is_null_allowed>
</field>
<field id="contact_id" xsi:type="AttributeExternalKey">
<sql>contact_id</sql>
<target_class>Contact</target_class>
<default_value/>
<is_null_allowed>false</is_null_allowed>
</field>
<field id="trigger_id" xsi:type="AttributeExternalKey">
<sql>trigger_id</sql>
<target_class>Trigger</target_class>
<default_value/>
<is_null_allowed>false</is_null_allowed>
</field>
<field id="subscribed" xsi:type="AttributeBoolean">
<sql>subscribed</sql>
<default_value>true</default_value>
<is_null_allowed>false</is_null_allowed>
</field>
</fields>
<presentation>
<details>
<items>
<item id="col:col1">
<items>
<item id="fieldset:lnkActionNotificationToContact:content">
<items>
<item id="action_id">
<rank>10</rank>
</item>
<item id="contact_id">
<rank>20</rank>
</item>
<item id="title">
<rank>30</rank>
</item>
</items>
</item>
</items>
</item>
</items>
</details>
<list>
<items>
<item id="action_id">
<rank>10</rank>
</item>
<item id="contact_id">
<rank>20</rank>
</item>
<item id="title">
<rank>30</rank>
</item>
</items>
</list>
</presentation>
<methods/>
</class>
<class id="ActioniTopNotification" _delta="define">
<php_parent>
<name>ActionNotification</name>
</php_parent>
<parent>cmdbAbstractObject</parent>
<properties>
<category>grant_by_profile,core/cmdb,application</category>
<abstract>false</abstract>
<key_type>autoincrement</key_type>
<db_table>priv_action_itop_notif</db_table>
<db_key_field>id</db_key_field>
<db_final_class_field/>
<naming>
<attributes>
<attribute id="name"/>
</attributes>
</naming>
<style>
<icon>../../images/icons/icons8-notification.svg</icon>
</style>
</properties>
<fields>
<field id="title" xsi:type="AttributeString">
<sql>title</sql>
<default_value/>
<is_null_allowed>false</is_null_allowed>
</field>
<field id="message" xsi:type="AttributeText">
<sql>message</sql>
<default_value/>
<is_null_allowed>true</is_null_allowed>
</field>
<field id="icon" xsi:type="AttributeImage">
<sql>icon</sql>
<default_value/>
<is_null_allowed>true</is_null_allowed>
<display_max_width>96</display_max_width>
<display_max_height>96</display_max_height>
<storage_max_width>256</storage_max_width>
<storage_max_height>256</storage_max_height>
<default_image />
</field>
<field id="priority" xsi:type="AttributeEnum">
<sql>priority</sql>
<values>
<value id="1">
<code>1</code>
</value>
<value id="2">
<code>2</code>
</value>
<value id="3">
<code>3</code>
</value>
<value id="4">
<code>4</code>
</value>
</values>
<default_value>4</default_value>
<is_null_allowed>false</is_null_allowed>
</field>
<field id="recipients" xsi:type="AttributeOQL">
<sql>recipients</sql>
<default_value/>
<is_null_allowed>false</is_null_allowed>
</field>
<field id="url" xsi:type="AttributeString">
<sql>url</sql>
<default_value>$this->url()$</default_value>
<is_null_allowed>false</is_null_allowed>
</field>
</fields>
<presentation>
<details>
<items>
<item id="col:col1">
<items>
<item id="fieldset:ActioniTopNotification:content">
<items>
<item id="name">
<rank>10</rank>
</item>
<item id="status">
<rank>20</rank>
</item>
<item id="language">
<rank>30</rank>
</item>
<item id="title">
<rank>40</rank>
</item>
<item id="message">
<rank>50</rank>
</item>
</items>
</item>
<item id="fieldset:ActioniTopNotification:trigger">
<items>
<item id="trigger_list">
<rank>10</rank>
</item>
<item id="asynchronous">
<rank>20</rank>
</item>
</items>
</item>
</items>
</item>
<item id="col:col2">
<items>
<item id="fieldset:ActioniTopNotification:settings">
<items>
<item id="priority">
<rank>10</rank>
</item>
<item id="icon">
<rank>20</rank>
</item>
<item id="recipients">
<rank>30</rank>
</item>
<item id="url">
<rank>40</rank>
</item>
</items>
</item>
</items>
</item>
</items>
</details>
<list>
<items>
<item id="title">
<rank>10</rank>
</item>
<item id="status">
<rank>20</rank>
</item>
<item id="language">
<rank>30</rank>
</item>
</items>
</list>
</presentation>
<methods>
<method id="DoExecute">
<comment> /**
*
* Create EventiTopNotification for each recipient
* @param $oTrigger
* @param $aContextArgs
*
* @return void
* @throws \ArchivedObjectException
* @throws \CoreCannotSaveObjectException
* @throws \CoreException
* @throws \CoreUnexpectedValue
* @throws \CoreWarning
* @throws \MySQLException
* @throws \OQLException
*/</comment>
<static>false</static>
<access>public</access>
<code><![CDATA[
public function DoExecute($oTrigger, $aContextArgs)
{
$oRecipientsSearch = DBObjectSearch::FromOQL($this->Get('recipients'));
$oRecipientsSearch->AllowAllData();
$oRecipientsSet = new DBObjectSet($oRecipientsSearch);
$bIsAsync = $this->IsAsynchronous();
[$sPreviousLanguage, $aPreviousPluginProperties] = $this->SetNotificationLanguage();
if($bIsAsync === true){
$aRecipients = [];
}
$sMessage = MetaModel::ApplyParams($this->Get('message'), $aContextArgs);
$sTitle = MetaModel::ApplyParams($this->Get('title'), $aContextArgs);
$sUrl = MetaModel::ApplyParams($this->Get('url'), $aContextArgs);
$iObjectId = 0;
$sObjectClass = null;
if (array_key_exists('this->object()', $aContextArgs)) {
$iObjectId = $aContextArgs['this->object()']->GetKey();
$sObjectClass = get_class($aContextArgs['this->object()']);
}
while ($oRecipient = $oRecipientsSet->Fetch()) {
// Skip recipients that have no users
if (get_class($oRecipient) === Person::class && UserRights::GetUserFromPerson($oRecipient) === null) {
continue;
}
if (!\Combodo\iTop\Service\Notification\NotificationsService::GetInstance()->IsSubscribed($oTrigger, $this, $oRecipient)) {
continue;
}
if($bIsAsync === true) {
$aRecipients[] = $oRecipient->GetKey();
} else {
$oEvent = Combodo\iTop\Service\Notification\Event\EventiTopNotificationService::MakeEventFromAction($this, $oRecipient->GetKey(), $oTrigger->GetKey(), $sMessage, $sTitle, $sUrl, $iObjectId, $sObjectClass);
$oEvent->DBInsertNoReload();
}
\Combodo\iTop\Service\Notification\NotificationsService::GetInstance()->RegisterSubscription($oTrigger, $this, $oRecipient);
}
if ($bIsAsync === true) {
AsyncSendiTopNotifications::AddToQueue($this->GetKey(), $oTrigger->GetKey(), $aRecipients, $sMessage, $sTitle, $sUrl, $iObjectId, $sObjectClass);
}
$this->SetNotificationLanguage($sPreviousLanguage, $aPreviousPluginProperties['language_code'] ?? null);
}
]]></code>
</method>
<method id="GetAsynchronousGlobalSetting">
<comment></comment>
<static>true</static>
<access>public</access>
<code><![CDATA[
public static function GetAsynchronousGlobalSetting(): bool
{
return utils::GetConfig()->Get('notifications.itop.send_asynchronously');
}
]]></code>
</method>
</methods>
</class>
<class id="EventiTopNotification" _delta="define">
<php_parent>
<name>EventNotification</name>
</php_parent>
<parent>cmdbAbstractObject</parent>
<properties>
<category>core/cmdb,view_in_gui</category>
<abstract>false</abstract>
<key_type>autoincrement</key_type>
<db_table>priv_event_itop_notif</db_table>
<db_key_field>id</db_key_field>
<db_final_class_field/>
<naming>
<attributes>
<attribute id="title"/>
</attributes>
</naming>
</properties>
<fields>
<field id="title" xsi:type="AttributeString">
<sql>title</sql>
<default_value/>
<is_null_allowed>false</is_null_allowed>
</field>
<field id="icon" xsi:type="AttributeImage">
<sql>icon</sql>
<default_value/>
<is_null_allowed>true</is_null_allowed>
<default_image />
</field>
<field id="priority" xsi:type="AttributeEnum">
<sql>priority</sql>
<values>
<value id="1">
<code>1</code>
</value>
<value id="2">
<code>2</code>
</value>
<value id="3">
<code>3</code>
</value>
<value id="4">
<code>4</code>
</value>
</values>
<default_value>4</default_value>
<is_null_allowed>false</is_null_allowed>
</field>
<field id="url" xsi:type="AttributeURL">
<sql>url</sql>
<default_value/>
<is_null_allowed>false</is_null_allowed>
<target>_blank</target>
</field>
<field id="read" xsi:type="AttributeEnum">
<sql>read</sql>
<values>
<value id="yes">
<code>yes</code>
</value>
<value id="no">
<code>no</code>
</value>
</values>
<default_value>no</default_value>
<is_null_allowed>false</is_null_allowed>
</field>
<field id="read_date" xsi:type="AttributeDateTime">
<sql>read_date</sql>
<default_value/>
<is_null_allowed>true</is_null_allowed>
</field>
<field id="contact_id" xsi:type="AttributeExternalKey">
<sql>contact_id</sql>
<target_class>Contact</target_class>
<default_value/>
<is_null_allowed>false</is_null_allowed>
</field>
</fields>
<presentation>
<summary>
<items>
<item id="date">
<rank>10</rank>
</item>
<item id="message">
<rank>20</rank>
</item>
</items>
</summary>
</presentation>
<methods/>
</class>
</classes>
<itop_design xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="3.1">
<user_rights>
<profiles>
<profile id="1024" _delta="define">
@@ -693,50 +282,8 @@
<field id="obj_attcode" xsi:type="AttributeString"/>
</fields>
</class>
<class id="DefaultWorkingTimeComputer" _delta="define">
<interfaces>
<interface id="iWorkingTimeComputer"/>
</interfaces>
</class>
<class id="ActionNotification" _delta="define">
<!-- Generated by toolkit/export-class-to-meta.php -->
<parent>Action</parent>
<properties>
<category>grant_by_profile,core/cmdb</category>
</properties>
<fields>
<field id="name" xsi:type="AttributeString"/>
<field id="description" xsi:type="AttributeString"/>
<field id="status" xsi:type="AttributeEnum"/>
<field id="trigger_list" xsi:type="AttributeLinkedSetIndirect"/>
<field id="language" xsi:type="AttributeApplicationLanguage"/>
</fields>
</class>
<class id="EventNotification" _delta="define">
<!-- Generated by toolkit/export-class-to-meta.php -->
<parent>Event</parent>
<properties>
<category>core/cmdb,view_in_gui</category>
</properties>
<fields>
<field id="message" xsi:type="AttributeText"/>
<field id="date" xsi:type="AttributeDateTime"/>
<field id="userinfo" xsi:type="AttributeString"/>
<field id="trigger_id" xsi:type="AttributeExternalKey">
<target_class>Trigger</target_class>
</field>
<field id="action_id" xsi:type="AttributeExternalKey">
<target_class>Action</target_class>
</field>
<field id="object_id" xsi:type="AttributeInteger"/>
<field id="trigger_id_friendlyname" xsi:type="AttributeExternalField"/>
<field id="trigger_id_finalclass_recall" xsi:type="AttributeExternalField"/>
<field id="action_id_friendlyname" xsi:type="AttributeExternalField"/>
<field id="action_id_finalclass_recall" xsi:type="AttributeExternalField"/>
</fields>
</class>
</classes>
<attribute_properties_definition _delta="define">
<attribute_properties_definition _delta="define">
<properties>
<property id="sql">
<php_param>sql</php_param>
@@ -955,12 +502,6 @@
<type>boolean</type>
<default>false</default>
</property>
<property id="with_php_computation">
<php_param>with_php_computation</php_param>
<mandatory>false</mandatory>
<type>boolean</type>
<default>false</default>
</property>
<property id="create_temporary_object">
<php_param>create_temporary_object</php_param>
<mandatory>false</mandatory>

File diff suppressed because it is too large Load Diff

View File

@@ -6,102 +6,7 @@
/** @internal Dev hack for disabling some query build optimizations (Folding/Merging) */
define('ENABLE_OPT', true);
class DBSharedSearch extends DBObjectSearch {
public function MakeSelectQuery($aOrderBy = array(), $aArgs = array(), $aAttToLoad = null, $aExtendedDataSpec = null, $iLimitCount = 0, $iLimitStart = 0, $bGetCount = false, $bBeautifulSQL = true)
{
// Check the order by specification, and prefix with the class alias
// and make sure that the ordering columns are going to be selected
//
$sClass = $this->GetClass();
$sClassAlias = $this->GetClassAlias();
$aOrderSpec = array();
foreach ($aOrderBy as $sFieldAlias => $bAscending)
{
if (!is_bool($bAscending))
{
throw new CoreException("Wrong direction in ORDER BY spec, found '$bAscending' and expecting a boolean value");
}
$iDotPos = strpos($sFieldAlias, '.');
if ($iDotPos === false)
{
$sAttClass = $sClass;
$sAttClassAlias = $sClassAlias;
$sAttCode = $sFieldAlias;
}
else
{
$sAttClassAlias = substr($sFieldAlias, 0, $iDotPos);
$sAttClass = $this->GetClassName($sAttClassAlias);
$sAttCode = substr($sFieldAlias, $iDotPos + 1);
}
if ($sAttCode != 'id')
{
MyHelpers::CheckValueInArray('field name in ORDER BY spec', $sAttCode, MetaModel::GetAttributesList($sAttClass));
$oAttDef = MetaModel::GetAttributeDef($sAttClass, $sAttCode);
foreach($oAttDef->GetOrderBySQLExpressions($sAttClassAlias) as $sSQLExpression)
{
$aOrderSpec[$sSQLExpression] = $bAscending;
}
}
else
{
$aOrderSpec['`'.$sAttClassAlias.$sAttCode.'`'] = $bAscending;
}
// Make sure that the columns used for sorting are present in the loaded columns
if (!is_null($aAttToLoad) && !isset($aAttToLoad[$sAttClassAlias][$sAttCode]))
{
$aAttToLoad[$sAttClassAlias][$sAttCode] = MetaModel::GetAttributeDef($sAttClass, $sAttCode);
}
}
/*******START difference with MakeSelectQuery **************/
$sClass = key($aAttToLoad);
$sKey = $aAttToLoad[$sClass][0];
$oObjId = new FieldExpression($sKey, $sClass);
$oSQLQuery = $this->GetSQLQuery($aOrderBy, $aArgs, [], $aExtendedDataSpec, $iLimitCount, $iLimitStart, $bGetCount, null, [$oObjId] );
/********END difference with MakeSelectQuery*************/
if ($this->m_bNoContextParameters)
{
// Only internal parameters
$aScalarArgs = $this->GetInternalParams();
}
else
{
// The complete list of arguments will include magic arguments (e.g. current_user->attcode)
$aScalarArgs = MetaModel::PrepareQueryArguments($aArgs, $this->GetInternalParams(), $this->GetExpectedArguments());
}
try
{
$sRes = $oSQLQuery->RenderSelect($aOrderSpec, $aScalarArgs, $iLimitCount, $iLimitStart, $bGetCount, $bBeautifulSQL);
if ($sClassAlias == '_itop_')
{
IssueLog::Info('SQL Query (_itop_): '.$sRes);
}
}
catch (MissingQueryArgument $e)
{
// Add some information...
$e->addInfo('OQL', $this->ToOQL());
throw $e;
}
$this->AddQueryTraceSelect($oSQLQuery->GetSourceOQL(), $aOrderBy, $aScalarArgs, $aAttToLoad, $aExtendedDataSpec, $iLimitCount, $iLimitStart, $bGetCount, $sRes);
return $sRes;
}
protected function GetSQLQuery($aOrderBy, $aArgs, $aAttToLoad, $aExtendedDataSpec, $iLimitCount, $iLimitStart, $bGetCount, $aGroupByExpr = null, $aSelectExpr = null)
{
$oSQLQuery = parent::GetSQLQuery($aOrderBy, $aArgs, $aAttToLoad, $aExtendedDataSpec, $iLimitCount, $iLimitStart, $bGetCount, $aGroupByExpr, $aSelectExpr);
$oSQLQuery->SetSelect($aSelectExpr);
return $oSQLQuery;
}
}
/**
* A search over a DBObject
*
@@ -1004,15 +909,15 @@ class DBObjectSearch extends DBSearch
*/
public function AddCondition_PointingTo(DBObjectSearch $oFilter, $sExtKeyAttCode, $iOperatorCode = TREE_OPERATOR_EQUALS, &$aRealiasingMap = null)
{
if (!MetaModel::IsValidKeyAttCode($this->GetClass(), $sExtKeyAttCode))
if (!MetaModel::IsValidKeyAttCode($this->GetClass(), $sExtKeyAttCode))
{
throw new CoreWarning("The attribute code '$sExtKeyAttCode' is not an external key of the class '{$this->GetClass()}'");
}
$oAttExtKey = MetaModel::GetAttributeDef($this->GetClass(), $sExtKeyAttCode);
if(!MetaModel::IsSameFamilyBranch($oFilter->GetClass(), $oAttExtKey->GetTargetClass()))
{
throw new CoreException("The specified filter (pointing to {$oFilter->GetClass()}) is not compatible with the key '{$this->GetClass()}::$sExtKeyAttCode', which is pointing to {$oAttExtKey->GetTargetClass()}");
}
throw new CoreException("The specified filter (pointing to {$oFilter->GetClass()}) is not compatible with the key '{$this->GetClass()}::$sExtKeyAttCode', which is pointing to {$oAttExtKey->GetTargetClass()}");
}
if(($iOperatorCode != TREE_OPERATOR_EQUALS) && !($oAttExtKey instanceof AttributeHierarchicalKey))
{
throw new CoreException("The specified tree operator $iOperatorCode is not applicable to the key '{$this->GetClass()}::$sExtKeyAttCode', which is not a HierarchicalKey");
@@ -1711,10 +1616,6 @@ class DBObjectSearch extends DBSearch
{
return NestedQueryExpression::FromOQLObjectQuery($oExpression->GetOQLObjectQuery());
}
elseif ($oExpression instanceof SharedQueryExpression)
{
return SharedQueryExpression::FromOQLObjectQuery($oExpression->GetOQLObjectQuery());
}
else
{
throw new CoreException('Unknown expression type', array('class'=>get_class($oExpression), 'query'=>$sQuery));

View File

@@ -851,11 +851,11 @@ abstract class DBSearch
return;
}
if (count($aColumns) == 0)
{
$aColumns = array_keys(MetaModel::ListAttributeDefs($this->GetClass()));
// Add the standard id (as first column)
array_unshift($aColumns, 'id');
if (count($aColumns) == 0)
{
$aColumns = array_keys(MetaModel::ListAttributeDefs($this->GetClass()));
// Add the standard id (as first column)
array_unshift($aColumns, 'id');
}
$aQueryCols = CMDBSource::GetColumns($resQuery, $sSQL);
@@ -885,55 +885,6 @@ abstract class DBSearch
return $aRes;
}
/**
* Selects a column ($sAttCode) from the specified class ($sClassAlias - default main class) of the DBsearch object and gives the result as an array
* @param string $sAttCode
* @param string|null $sClassAlias
*
* @return array
* @throws ConfigException
* @throws CoreException
* @throws MissingQueryArgument
* @throws MySQLException
* @throws MySQLHasGoneAwayException
*/
public function SelectAttributeToArray(string $sAttCode, ?string $sClassAlias = null):array
{
if(is_null($sClassAlias)) {
$sClassAlias = $this->GetClassAlias();
}
$sClass = $this->GetClass();
if($sAttCode === 'id'){
$aAttToLoad[$sClassAlias]=[];
} else {
$aAttToLoad[$sClassAlias][$sAttCode] = MetaModel::GetAttributeDef($sClass, $sAttCode);
}
$sSQL = $this->MakeSelectQuery([], [], $aAttToLoad);
$resQuery = CMDBSource::Query($sSQL);
if (!$resQuery)
{
return [];
}
$sColName = $sClassAlias.$sAttCode;
$aRes = [];
while ($aRow = CMDBSource::FetchArray($resQuery))
{
$aMappedRow = array();
if($sAttCode === 'id') {
$aMappedRow[$sAttCode] = $aRow[$sColName];
} else {
$aMappedRow[$sAttCode] = $aAttToLoad[$sClassAlias][$sAttCode]->FromSQLToValue($aRow, $sColName);
}
$aRes[] = $aMappedRow;
}
CMDBSource::FreeResult($resQuery);
return $aRes;
}
////////////////////////////////////////////////////////////////////////////
//
// Construction of the SQL queries

View File

@@ -64,22 +64,16 @@ class DesignDocument extends DOMDocument
/**
* Overload of the standard API
*
* @param string $filename
* @param $filename
* @param int $options
*
* @return bool
*/
public function load(string $filename, int $options = 0): bool
public function load($filename, $options = null)
{
libxml_clear_errors();
if (parent::load($filename, LIBXML_NOBLANKS) === false) {
$aErrors = libxml_get_errors();
IssueLog::Error("Error loading $filename", LogAPI::CHANNEL_DEFAULT, $aErrors);
return false;
}
return true;
}
/**

View File

@@ -16,14 +16,8 @@
// You should have received a copy of the GNU Affero General Public License
// along with iTop. If not, see <http://www.gnu.org/licenses/>
use Combodo\iTop\Application\Helper\WebResourcesHelper;
use Combodo\iTop\Application\UI\Base\Component\Html\Html;
use Combodo\iTop\Application\UI\Base\Component\MedallionIcon\MedallionIcon;
use Combodo\iTop\Application\UI\Base\Component\Panel\Panel;
use Combodo\iTop\Application\UI\Base\Layout\UIContentBlock;
use Combodo\iTop\Application\UI\Base\Layout\UIContentBlockUIBlockFactory;
use Combodo\iTop\Application\WebPage\iTopPDF;
use Combodo\iTop\Application\WebPage\PDFPage;
use Combodo\iTop\Application\WebPage\WebPage;
use Combodo\iTop\Renderer\BlockRenderer;
/**
@@ -37,7 +31,6 @@ class DisplayableNode extends GraphNode
{
public $x;
public $y;
public bool $bFiltered;
/**
* Create a new node inside a graph
@@ -66,7 +59,7 @@ class DisplayableNode extends GraphNode
public function GetWidth()
{
return max(32, 5 * mb_strlen($this->GetProperty('label'))); // approximation of the text's bounding box
return max(32, 5*strlen($this->GetProperty('label'))); // approximation of the text's bounding box
}
public function GetHeight()
@@ -495,7 +488,7 @@ class DisplayableNode extends GraphNode
if ($bNoLabel)
{
// simulate a fake label with the approximate same size as the true label
$sLabel = str_repeat('x', mb_strlen($this->GetProperty('label', $this->GetId())));
$sLabel = str_repeat('x',strlen($this->GetProperty('label', $this->GetId())));
$sDot = 'label="'.$sLabel.'"';
}
else
@@ -1419,8 +1412,6 @@ class DisplayableGraph extends SimpleGraph
/**
* Display the graph inside the given page, with the "filter" drawer above it
*
* @deprecated 3.1.1 3.2.0 N°3767 Use \DisplayableGraph::DisplayFilterBox() and \DisplayableGraph::DisplayGraph() instead
*
* @param WebPage $oP
* @param array $aResults
* @param string $sRelation
@@ -1434,35 +1425,10 @@ class DisplayableGraph extends SimpleGraph
*
* @throws \CoreException
* @throws \DictExceptionMissingString
*
*/
function Display(WebPage $oP, $aResults, $sRelation, ApplicationContext $oAppContext, $aExcludedObjects, $sObjClass, $iObjKey, $sContextKey, $aContextParams = array(), bool $bLazyLoading = false)
{
$oP->AddSubBlock($this->DisplayFilterBox($oP, $aResults, $bLazyLoading));
$this->DisplayGraph($oP, $sRelation, $oAppContext, $aExcludedObjects, $sObjClass, $iObjKey, $sContextKey, $aContextParams, $bLazyLoading);
}
/**
* Display only the graph inside the given page, with the parameters of filter box draw with DisplayFilterBox
*
* @param WebPage $oP
* @param string $sRelation
* @param ApplicationContext $oAppContext
* @param array $aExcludedObjects
* @param string $sObjClass
* @param int $iObjKey
* @param string $sContextKey
* @param array $aContextParams
* @param bool $bLazyLoading
*
* @throws \CoreException
* @throws \DictExceptionMissingString
*
* @since 3.1.1 3.2.0 N°3767
*/
function DisplayGraph(WebPage $oP, $sRelation, ApplicationContext $oAppContext, $aExcludedObjects, $sObjClass, $iObjKey, $sContextKey, $aContextParams = array(), bool $bLazyLoading = false): void
{
list($aExcludedByClass, $aAdditionalContexts) = $this->GetFilteringData($sContextKey, $aContextParams, $aExcludedObjects);
list($aExcludedByClass, $aAdditionalContexts) = $this->DisplayFiltering($sContextKey, $aContextParams, $aExcludedObjects, $oP, $aResults, $bLazyLoading);
$iGroupingThreshold = utils::ReadParam('g', 5);
@@ -1547,10 +1513,12 @@ class DisplayableGraph extends SimpleGraph
$oP->add_ready_script(" $('#$sId').simple_graph(".json_encode($aParams).");");
} else {
$oP->add_script("function Load(){var aExcluded = []; $('input[name^=excluded]').each( function() {if (!$(this).prop('checked')) { aExcluded.push($(this).val()); }} ); var params= $.extend(".json_encode($aParams).", {excluded_classes: aExcluded}); $('#$sId').simple_graph(params);}");
$oP->add_ready_script("$('#graph').html('".utils::TextToHtml(Dict::S('Relation:impacts/NoFilteredData'))."');$('#impacted_objects_lists').html('".utils::TextToHtml(Dict::S('Relation:impacts/NoFilteredData'))."');$('#impacted_groups').html('".utils::TextToHtml(Dict::S('Relation:impacts/NoFilteredData'))."');");
$oP->add_ready_script("$('#impacted_objects_lists').html('".utils::TextToHtml(Dict::S('Relation:impacts/NoFilteredData'))."');$('#impacted_groups').html('".utils::TextToHtml(Dict::S('Relation:impacts/NoFilteredData'))."');");
}
}
catch (Exception $e) {
catch(Exception $e)
{
$oP->add('<div>'.$e->getMessage().'</div>');
}
$oP->add_script(
@@ -1584,7 +1552,7 @@ EOF
* @param string $sContextKey
* @param array $aContextParams
* @param array $aExcludedObjects
* @param WebPage $oP
* @param \WebPage $oP
* @param array $aResults
* @param bool $bLazyLoading
*
@@ -1595,41 +1563,23 @@ EOF
* @throws \Twig\Error\LoaderError
* @throws \Twig\Error\RuntimeError
* @throws \Twig\Error\SyntaxError
*
* @deprecated 3.1.1 3.2.0 N°3767 Use \DisplayableGraph::DisplayFilterBox() and \DisplayableGraph::GetFilteringData() instead
*/
public function DisplayFiltering(string $sContextKey, array $aContextParams, array $aExcludedObjects, WebPage $oP, array $aResults, bool $bLazyLoading = false): array
{
$oP->Add($this->DisplayFilterBox($oP, $aResults, $bLazyLoading));
return $this->GetFilteringData($sContextKey, $aContextParams, $aExcludedObjects);
}
/**
* @param WebPage $oP
* @param array $aResults
* @param bool $bLazyLoading
*
* @return UIContentBlock
* @throws \CoreException
* @throws \DictExceptionMissingString
* @throws \ReflectionException
* @throws \Twig\Error\LoaderError
* @throws \Twig\Error\RuntimeError
* @throws \Twig\Error\SyntaxError
*
* @since 3.1.1 3.2.0 N°3767
*/
public function DisplayFilterBox(WebPage $oP, array $aResults, bool $bLazyLoading = false): UIContentBlock
{
$aContextDefs = static::GetContextDefinitions($sContextKey, true, $aContextParams);
$aExcludedByClass = array();
foreach ($aExcludedObjects as $oObj) {
if (!array_key_exists(get_class($oObj), $aExcludedByClass)) {
$aExcludedByClass[get_class($oObj)] = array();
}
$aExcludedByClass[get_class($oObj)][] = $oObj->GetKey();
}
$sSftShort = Dict::S('UI:ElementsDisplayed');
$oBlock = UIContentBlockUIBlockFactory::MakeStandard(null, ['not-printable']);
$oP->add("<div class=\"not-printable\">\n");
$oUiSearchBlock = new Panel($sSftShort, [], Panel::ENUM_COLOR_SCHEME_CYAN, 'dh_flash');
$oUiSearchBlock->SetCSSClasses(["ibo-search-form-panel", "display_block"])
->SetIsCollapsible(true);
$oUiHtmlBlock = new Html(
$oUiSearchBlock->SetCSSClasses(["ibo-search-form-panel", "display_block"]);
$oUiSearchBlock->SetIsCollapsible(true);
$oUiHtmlBlock = new Combodo\iTop\Application\UI\Base\Component\Html\Html(
<<<EOF
<div id="ds_flash" class="search_box ibo-display-graph--search-box">
@@ -1676,23 +1626,11 @@ EOF
$oUiHtmlBlock->AddHtml("<button type=\"button\" id=\"ReloadMovieBtn\" class=\"ibo-button ibo-is-neutral ibo-is-regular\" onClick=\"$sOnCLick\">".Dict::S('UI:Button:Refresh')."</button></div></form>");
}
$oUiHtmlBlock->AddHtml("</div>\n");
$oUiHtmlBlock->AddHtml("</div>\n"); // class="not-printable"
$oUiSearchBlock->AddSubBlock($oUiHtmlBlock);
$oBlock->AddSubBlock($oUiSearchBlock);
$oP->AddUiBlock($oUiSearchBlock);
return $oBlock;
}
public function GetFilteringData(string $sContextKey, array $aContextParams, array $aExcludedObjects): array
{
$aContextDefs = static::GetContextDefinitions($sContextKey, true, $aContextParams);
$aExcludedByClass = array();
foreach ($aExcludedObjects as $oObj) {
if (!array_key_exists(get_class($oObj), $aExcludedByClass)) {
$aExcludedByClass[get_class($oObj)] = array();
}
$aExcludedByClass[get_class($oObj)][] = $oObj->GetKey();
}
$aAdditionalContexts = array();
foreach ($aContextDefs as $sKey => $aDefinition) {
$aAdditionalContexts[] = array('key' => $sKey, 'label' => Dict::S($aDefinition['dict']), 'oql' => $aDefinition['oql'], 'default' => (array_key_exists('default', $aDefinition) && ($aDefinition['default'] == 'yes')));

View File

@@ -46,15 +46,6 @@ class EMail implements iEMail
const ORIGINAL_FORMAT = 1; // Original format, consisting in serializing the whole object, inculding the Swift Mailer's object.
// Did not work with attachements since their binary representation cannot be stored as a valid UTF-8 string
const FORMAT_V2 = 2; // New format, only the raw data are serialized (base64 encoded if needed)
/** @var int ENUM_SEND_DEFAULT This option can be used when sending an e-mail to respect the default configuration parameter. */
const ENUM_SEND_DEFAULT = 0;
/** @var int ENUM_SEND_FORCE_SYNCHRONOUS This option can be used when sending an e-mail to ignore the default and force synchronous sending instead. Example of a use case: instant e-mail test. */
const ENUM_SEND_FORCE_SYNCHRONOUS = 1;
/** @var int ENUM_SEND_FORCE_ASYNCHRONOUS This option can be used when sending an e-mail to ignore the default and force synchronous sending instead. Example of a use case: Bulk mails. */
const ENUM_SEND_FORCE_ASYNCHRONOUS = 2;
public function __construct()
{

View File

@@ -1,7 +1,4 @@
<?php
use Combodo\iTop\Application\WebPage\WebPage;
/**
* Copyright (C) 2013-2023 Combodo SARL
*
@@ -245,33 +242,44 @@ class EventIssue extends Event
{
if (is_string($sValue))
{
if (mb_strlen($sValue) < 256) {
if (strlen($sValue) < 256)
{
$aPost[$sKey] = $sValue;
} else {
$aPost[$sKey] = "!long string: ".mb_strlen($sValue)." chars";
}
} else {
else
{
$aPost[$sKey] = "!long string: ".strlen($sValue). " chars";
}
}
else
{
// Not a string (avoid warnings in case the value cannot be easily casted into a string)
$aPost[$sKey] = @(string)$sValue;
$aPost[$sKey] = @(string) $sValue;
}
}
$this->Set('arguments_post', $aPost);
} else {
}
else
{
$this->Set('arguments_post', array());
}
$sLength = mb_strlen($this->Get('issue'));
if ($sLength > 255) {
$this->Set('issue', mb_substr($this->Get('issue'), 0, 210)." -truncated ($sLength chars)");
$sLength = strlen($this->Get('issue'));
if ($sLength > 255)
{
$this->Set('issue', substr($this->Get('issue'), 0, 200)." -truncated ($sLength chars)");
}
$sLength = mb_strlen($this->Get('impact'));
if ($sLength > 255) {
$this->Set('impact', mb_substr($this->Get('impact'), 0, 210)." -truncated ($sLength chars)");
$sLength = strlen($this->Get('impact'));
if ($sLength > 255)
{
$this->Set('impact', substr($this->Get('impact'), 0, 200)." -truncated ($sLength chars)");
}
$sLength = mb_strlen($this->Get('page'));
if ($sLength > 255) {
$this->Set('page', mb_substr($this->Get('page'), 0, 210)." -truncated ($sLength chars)");
$sLength = strlen($this->Get('page'));
if ($sLength > 255)
{
$this->Set('page', substr($this->Get('page'), 0, 200)." -truncated ($sLength chars)");
}
}
}

View File

@@ -10,9 +10,6 @@ use Combodo\iTop\Application\UI\Base\Component\Input\InputUIBlockFactory;
use Combodo\iTop\Application\UI\Base\Component\Panel\PanelUIBlockFactory;
use Combodo\iTop\Application\UI\Base\Layout\MultiColumn\Column\ColumnUIBlockFactory;
use Combodo\iTop\Application\UI\Base\Layout\MultiColumn\MultiColumnUIBlockFactory;
use Combodo\iTop\Application\Helper\ExportHelper;
use Combodo\iTop\Application\WebPage\Page;
use Combodo\iTop\Application\WebPage\WebPage;
require_once(APPROOT.'application/xlsxwriter.class.php');
@@ -71,7 +68,7 @@ class ExcelBulkExport extends TabularBulkExport
}
/**
* @param WebPage $oP
* @param \WebPage $oP
* @param $sPartId
*
* @return UIContentBlock
@@ -85,7 +82,6 @@ class ExcelBulkExport extends TabularBulkExport
case 'xlsx_options':
$oPanel = PanelUIBlockFactory::MakeNeutral(Dict::S('Core:BulkExport:XLSXOptions'));
$oPanel->AddSubBlock(ExportHelper::GetAlertForExcelMaliciousInjection());
$oMulticolumn = MultiColumnUIBlockFactory::MakeStandard();
$oPanel->AddSubBlock($oMulticolumn);

View File

@@ -101,7 +101,7 @@ EOF;
EOF;
SetupUtils::builddir(dirname($sFilePath));
file_put_contents($sFilePath, $content, LOCK_EX);
file_put_contents($sFilePath, $content);
}
}
Dict::SetUserLanguage($sUserLang);

View File

@@ -15,8 +15,6 @@
//
// You should have received a copy of the GNU Affero General Public License
// along with iTop. If not, see <http://www.gnu.org/licenses/>
use Combodo\iTop\Application\WebPage\Page;
use Combodo\iTop\Application\WebPage\WebPage;
/**
* Bulk export: HTML export
@@ -39,7 +37,7 @@ class HTMLBulkExport extends TabularBulkExport
}
/**
* @param WebPage $oP
* @param \WebPage $oP
* @param $sPartId
*
* @return UIContentBlock

View File

@@ -3,7 +3,6 @@
* @copyright Copyright (C) 2010-2023 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
use Combodo\iTop\Core\Kpi\KpiLogData;
use Combodo\iTop\Service\Module\ModuleService;
@@ -405,31 +404,16 @@ class ExecutionKPI
$this->ResetCounters();
}
/**
* Compute statistics for a call to an extension
* Note: not working in dev mode (with links to env-production)
*
* @param object|string $object object called
* @param string $sMethod method called on the object
* @param string $sMessage additional message
*
* @return bool true if an extension was found for this object::method
* @throws \ReflectionException
*/
public function ComputeStatsForExtension($object, string $sMethod, string $sMessage = ''): bool
public function ComputeStatsForExtension($object, $sMethod)
{
if (!self::IsEnabled()) {
return true;
return;
}
$sSignature = ModuleService::GetInstance()->GetModuleMethodSignature($object, $sMethod);
if (utils::StartsWith($sSignature, '[')) {
$this->ComputeStats('Extension', "$sSignature $sMessage");
return true;
$this->ComputeStats('Extension', $sSignature);
}
return false;
}
public function ComputeStats($sOperation, $sArguments)

View File

@@ -3,7 +3,7 @@
//
// This file is part of iTop.
//
// iTop is free software; you can redistribute it and/or modify
// 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.
@@ -576,11 +576,6 @@ class LogChannels
public const DATATABLE = 'Datatable';
public const DEADLOCK = 'DeadLock';
/**
* @var string Everything related to PHP sessions tracking
* @since 3.1.1 3.2.0 N°6901
*/
public const SESSIONTRACKER = 'SessionTracker';
/**
* @var string Everything related to the datamodel CRUD
@@ -1090,11 +1085,6 @@ class DeadLockLog extends LogAPI
*/
class DeprecatedCallsLog extends LogAPI
{
/**
* @var string
* @since 3.2.0 N°4897
*/
public const ENUM_CHANNEL_PHP_API = 'deprecated-php-api';
public const ENUM_CHANNEL_PHP_METHOD = 'deprecated-php-method';
/**
* @var string
@@ -1148,13 +1138,9 @@ class DeprecatedCallsLog extends LogAPI
parent::Enable($sTargetFile);
if (
(
(false === defined(ITOP_PHPUNIT_RUNNING_CONSTANT_NAME))
|| (defined(ITOP_PHPUNIT_RUNNING_CONSTANT_NAME) && (constant(ITOP_PHPUNIT_RUNNING_CONSTANT_NAME) !== true))
)
(false === defined('ITOP_PHPUNIT_RUNNING_CONSTANT_NAME'))
&& static::IsLogLevelEnabledSafe(self::LEVEL_WARNING, self::ENUM_CHANNEL_PHP_LIBMETHOD)
) {
IssueLog::Trace('Setting '.static::class.' error handler to catch DEPRECATED', static::ENUM_CHANNEL_PHP_LIBMETHOD);
set_error_handler([static::class, 'DeprecatedNoticesErrorHandler'], E_DEPRECATED | E_USER_DEPRECATED);
}
}
@@ -1288,35 +1274,6 @@ class DeprecatedCallsLog extends LogAPI
static::Warning($sMessage, static::ENUM_CHANNEL_FILE);
}
/**
* @param string $sImplementationClass Class implementing the deprecated API
* @param string $sDeprecatedApi Class name of the deprecated API
* @param string $sDeprecatedMethod Method name of the deprecated API
* @param string|null $sAdditionalMessage Additional message, mostly used to explain what API to use instead
*
* @return void
* @since 3.2.0 N°4897
*/
public static function NotifyDeprecatedPhpApi(string $sImplementationClass, string $sDeprecatedApi, string $sDeprecatedMethod, ?string $sAdditionalMessage = null): void
{
try {
if (!static::IsLogLevelEnabled(self::LEVEL_WARNING, self::ENUM_CHANNEL_PHP_API)) {
return;
}
}
catch (ConfigException $oException) {
return;
}
$sMessage = "Implementation of {$sDeprecatedApi}::{$sDeprecatedMethod}() in class {$sImplementationClass}";
if (!is_null($sAdditionalMessage)) {
$sMessage .= " : $sAdditionalMessage";
}
static::Warning($sMessage, self::ENUM_CHANNEL_PHP_API);
}
/**
* @param string|null $sAdditionalMessage
*
@@ -1714,8 +1671,6 @@ class ExceptionLog extends LogAPI
*/
private static function GetLastEventIssue()
{
$oRet = self::$oLastEventIssue;
self::$oLastEventIssue = null;
return $oRet;
return self::$oLastEventIssue;
}
}

View File

@@ -1241,7 +1241,7 @@ abstract class MetaModel
}
$sTable = self::DBGetTable($sClass);
// Could be completed later with all the classes that are using a given table
// Could be completed later with all the classes that are using a given table
if (!array_key_exists($sTable, $aTables)) {
$aTables[$sTable] = array();
}
@@ -1445,10 +1445,8 @@ abstract class MetaModel
*
* @return AttributeDefinition[]
* @throws \CoreException
*
* @see GetAttributesList for attcode list
*/
final public static function ListAttributeDefs($sClass)
final static public function ListAttributeDefs($sClass)
{
self::_check_subclass($sClass);
return self::$m_aAttribDefs[$sClass];
@@ -1461,10 +1459,8 @@ abstract class MetaModel
* @param string[] $aDesiredAttTypes Array of AttributeDefinition classes to filter the list on
* @param string|null $sListCode If provided, attributes will be limited to those in this zlist
*
* @return string[] list of attcodes
* @return array
* @throws \CoreException
*
* @see ListAttributeDefs to get AttributeDefinition array instead
*/
final public static function GetAttributesList(string $sClass, array $aDesiredAttTypes = [], ?string $sListCode = null)
{
@@ -3526,7 +3522,7 @@ abstract class MetaModel
}
// Set the "host class" as soon as possible, since HierarchicalKeys use it for their 'target class' as well
// and this needs to be know early (for Init_IsKnowClass 19 lines below)
// and this needs to be know early (for Init_IsKnowClass 19 lines below)
$oAtt->SetHostClass($sTargetClass);
// Some attributes could refer to a class
@@ -3568,7 +3564,7 @@ abstract class MetaModel
self::$m_aAttribDefs[$sTargetClass][$oAtt->GetCode()] = $oAtt;
self::$m_aAttribOrigins[$sTargetClass][$oAtt->GetCode()] = $sTargetClass;
// Note: it looks redundant to put targetclass there, but a mix occurs when inheritance is used
// Note: it looks redundant to put targetclass there, but a mix occurs when inheritance is used
}
/**
@@ -3768,7 +3764,7 @@ abstract class MetaModel
self::$m_aStimuli[$sTargetClass][$oStimulus->GetCode()] = $oStimulus;
// I wanted to simplify the syntax of the declaration of objects in the biz model
// Therefore, the reference to the host class is set there
// Therefore, the reference to the host class is set there
$oStimulus->SetHostClass($sTargetClass);
}
@@ -4223,78 +4219,40 @@ abstract class MetaModel
}
else
{
$aCurrentUser = [];
$aCurrentContact = [];
$aCurrentUser = array();
$aCurrentContact = array();
foreach ($aExpectedArgs as $expression)
{
$aName = explode('->', $expression->GetName());
if ($aName[0] == 'current_contact_id') {
$aPlaceholders['current_contact_id'] = UserRights::GetContactId();
} else if ($aName[0] == 'current_user') {
}
if ($aName[0] == 'current_user') {
array_push($aCurrentUser, $aName[1]);
} else if ($aName[0] == 'current_contact') {
}
if ($aName[0] == 'current_contact') {
array_push($aCurrentContact, $aName[1]);
}
}
if (count($aCurrentUser) > 0) {
static::FillObjectPlaceholders($aPlaceholders, 'current_user', UserRights::GetUserObject(), $aCurrentUser);
$oUser = UserRights::GetUserObject();
$aPlaceholders['current_user->object()'] = $oUser;
foreach ($aCurrentUser as $sField) {
$aPlaceholders['current_user->'.$sField] = $oUser->Get($sField);
}
}
if (count($aCurrentContact) > 0) {
static::FillObjectPlaceholders($aPlaceholders, 'current_contact', UserRights::GetContactObject(), $aCurrentContact);
$oPerson = UserRights::GetContactObject();
$aPlaceholders['current_contact->object()'] = $oPerson;
foreach ($aCurrentContact as $sField) {
$aPlaceholders['current_contact->'.$sField] = $oPerson->Get($sField);
}
}
}
return $aPlaceholders;
}
/**
* @since 3.1.1 N°6824
* @param array $aPlaceholders
* @param string $sPlaceHolderPrefix
* @param ?\DBObject $oObject
* @param array $aCurrentUser
*
* @return void
*
*/
private static function FillObjectPlaceholders(array &$aPlaceholders, string $sPlaceHolderPrefix, ?\DBObject $oObject, array $aCurrentUser) : void {
$sPlaceHolderKey = $sPlaceHolderPrefix."->object()";
if (is_null($oObject)){
$aContext = [
"current_user_id" => UserRights::GetUserId(),
"null object type" => $sPlaceHolderPrefix,
"fields" => $aCurrentUser,
];
IssueLog::Warning("Unresolved placeholders due to null object in current context", null,
$aContext);
$aPlaceholders[$sPlaceHolderKey] = Dict::Format("Core:Placeholder:CannotBeResolved", $sPlaceHolderKey);
foreach ($aCurrentUser as $sField) {
$sPlaceHolderKey = $sPlaceHolderPrefix . "->$sField";
$aPlaceholders[$sPlaceHolderKey] = Dict::Format("Core:Placeholder:CannotBeResolved", $sPlaceHolderKey);
}
} else {
$aPlaceholders[$sPlaceHolderKey] = $oObject;
foreach ($aCurrentUser as $sField) {
$sPlaceHolderKey = $sPlaceHolderPrefix . "->$sField";
// Mind that the "id" is not viewed as a valid att. code by \MetaModel::IsValidAttCode() so we have to test it manually
if ($sField !== "id" && false === MetaModel::IsValidAttCode(get_class($oObject), $sField)){
$aContext = [
"current_user_id" => UserRights::GetUserId(),
"obj_class" => get_class($oObject),
"placeholder" => $sPlaceHolderKey,
"invalid_field" => $sField,
];
IssueLog::Warning("Unresolved placeholder due to invalid attribute", null,
$aContext);
$aPlaceholders[$sPlaceHolderKey] = Dict::Format("Core:Placeholder:CannotBeResolved", $sPlaceHolderKey);
continue;
}
$aPlaceholders[$sPlaceHolderKey] = $oObject->Get($sField);
}
}
}
/**
* @param \DBSearch $oFilter
*
@@ -5156,7 +5114,7 @@ abstract class MetaModel
*/
protected static function DBCreateTables($aCallback = null)
{
[$aErrors, $aSugFix, $aCondensedQueries] = self::DBCheckFormat();
list($aErrors, $aSugFix, $aCondensedQueries) = self::DBCheckFormat();
//$sSQL = implode('; ', $aCondensedQueries); Does not work - multiple queries not allowed
foreach($aCondensedQueries as $sQuery)
@@ -5178,7 +5136,7 @@ abstract class MetaModel
*/
protected static function DBCreateViews()
{
[$aErrors, $aSugFix] = self::DBCheckViews();
list($aErrors, $aSugFix) = self::DBCheckViews();
foreach($aSugFix as $sClass => $aTarget)
{
@@ -6521,7 +6479,7 @@ abstract class MetaModel
$aCache['m_aExtensionClassNames'] = self::$m_aExtensionClassNames;
$aCache['m_Category2Class'] = self::$m_Category2Class;
$aCache['m_aRootClasses'] = self::$m_aRootClasses; // array of "classname" => "rootclass"
$aCache['m_aParentClasses'] = self::$m_aParentClasses; // array of ("classname" => array of "parentclass")
$aCache['m_aParentClasses'] = self::$m_aParentClasses; // array of ("classname" => array of "parentclass")
$aCache['m_aChildClasses'] = self::$m_aChildClasses; // array of ("classname" => array of "childclass")
$aCache['m_aClassParams'] = self::$m_aClassParams; // array of ("classname" => array of class information)
$aCache['m_aAttribDefs'] = self::$m_aAttribDefs; // array of ("classname" => array of attributes)
@@ -6779,13 +6737,7 @@ abstract class MetaModel
if ($bMustBeFound && empty($aRow))
{
$sNotFoundErrorMessage = "No result for the single row query";
IssueLog::Info($sNotFoundErrorMessage, LogChannels::CMDB_SOURCE, [
'class' => $sClass,
'key' => $iKey,
'sql_query' => $sSQL,
]);
throw new CoreException($sNotFoundErrorMessage);
throw new CoreException("No result for the single row query: '$sSQL'");
}
return $aRow;
@@ -6846,6 +6798,18 @@ abstract class MetaModel
$sClass = $aRow[$sClassAlias."finalclass"];
}
// if an object is already being updated, then this method will return this object instead of recreating a new one.
// At this point the method DBUpdate of a new object with the same class and id won't do anything due to reentrance protection,
// so to ensure that the potential modifications are correctly saved, the object currently being updated is returned.
// DBUpdate() method then will take care that all the modifications will be saved.
if (array_key_exists($sClassAlias.'id', $aRow)) {
$iKey = $aRow[$sClassAlias."id"];
$oObject = self::GetReentranceObject($sClass, $iKey);
if ($oObject !== false) {
return $oObject;
}
}
return new $sClass($aRow, $sClassAlias, $aAttToLoad, $aExtendedDataSpec);
}
@@ -6915,22 +6879,6 @@ abstract class MetaModel
return $iCount === 1;
}
public static function GetFinalClassName(string $sClass, int $iKey): string
{
if (MetaModel::IsStandaloneClass($sClass)) {
return $sClass;
}
$sRootClass = MetaModel::GetRootClass($sClass);
$sTable = MetaModel::DBGetTable($sRootClass);
$sKeyCol = MetaModel::DBGetKey($sRootClass);
$sEscapedKey = CMDBSource::Quote($iKey);
$sFinalClassField = Metamodel::DBGetClassField($sRootClass);
$sQuery = "SELECT `{$sFinalClassField}` FROM `{$sTable}` WHERE `{$sKeyCol}` = {$sEscapedKey}";
return CMDBSource::QueryToScalar($sQuery);
}
/**
* Search for the specified class and id. If the object is archived it will be returned anyway (this is for pre-2.4
* module compatibility, see N.1108)
@@ -7168,45 +7116,32 @@ abstract class MetaModel
*/
public static function PurgeData($oFilter)
{
$iMaxChunkSize = MetaModel::GetConfig()->Get('purge_data.max_chunk_size');
$sTargetClass = $oFilter->GetClass();
$iNbIdsDeleted = 0;
$bExecuteQuery = true;
$oSet = new DBObjectSet($oFilter);
$oSet->OptimizeColumnLoad(array($sTargetClass => array('finalclass')));
$aIdToClass = $oSet->GetColumnAsArray('finalclass', true);
// This loop allows you to delete objects in batches of $iMaxChunkSize elements
while ($bExecuteQuery) {
$oSet = new DBObjectSet($oFilter);
$oSet->SetLimit($iMaxChunkSize);
$oSet->OptimizeColumnLoad(array($sTargetClass => array('finalclass')));
$aIdToClass = $oSet->GetColumnAsArray('finalclass', true);
$aIds = array_keys($aIdToClass);
if (count($aIds) > 0)
{
$aQuotedIds = CMDBSource::Quote($aIds);
$sIdList = implode(',', $aQuotedIds);
$aTargetClasses = array_merge(
self::EnumChildClasses($sTargetClass, ENUM_CHILD_CLASSES_ALL),
self::EnumParentClasses($sTargetClass, ENUM_PARENT_CLASSES_EXCLUDELEAF)
);
foreach($aTargetClasses as $sSomeClass)
{
$sTable = MetaModel::DBGetTable($sSomeClass);
$sPKField = MetaModel::DBGetKey($sSomeClass);
$aIds = array_keys($aIdToClass);
$iNbIds = count($aIds);
if ($iNbIds > 0) {
$aQuotedIds = CMDBSource::Quote($aIds);
$sIdList = implode(',', $aQuotedIds);
$aTargetClasses = array_merge(
self::EnumChildClasses($sTargetClass, ENUM_CHILD_CLASSES_ALL),
self::EnumParentClasses($sTargetClass, ENUM_PARENT_CLASSES_EXCLUDELEAF)
);
foreach ($aTargetClasses as $sSomeClass) {
$sTable = MetaModel::DBGetTable($sSomeClass);
$sPKField = MetaModel::DBGetKey($sSomeClass);
$sDeleteSQL = "DELETE FROM `$sTable` WHERE `$sPKField` IN ($sIdList)";
CMDBSource::DeleteFrom($sDeleteSQL);
}
$iNbIdsDeleted += $iNbIds;
}
// stop loop if query returned fewer objects than $iMaxChunkSize. In this case, all objects have been deleted.
if ($iNbIds < $iMaxChunkSize) {
$bExecuteQuery = false;
$sDeleteSQL = "DELETE FROM `$sTable` WHERE `$sPKField` IN ($sIdList)";
CMDBSource::DeleteFrom($sDeleteSQL);
}
}
return $iNbIdsDeleted;
return count($aIds);
}
// Links
//
//

View File

@@ -22,9 +22,7 @@
* A class to serialize the execution of some code sections
* Emulates the API of PECL Mutex class
* Relies on MySQL locks because the API sem_get is not always present in the
* installed PHP.
*
* @link https://dev.mysql.com/doc/refman/5.7/en/locking-functions.html MySQL locking functions documentation
* installed PHP.
*
* @copyright Copyright (C) 2013-2023 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0

View File

@@ -739,7 +739,7 @@ class PHP_ParserGenerator
while (isset($errmsg[$restart]) && $errmsg[$restart] == ' ') {
$restart++;
}
printf("%s%.{$end}s\n", $prefix, $errmsg);
printf("%s%.${end}s\n", $prefix, $errmsg);
$errmsg = substr($errmsg, $restart);
}
}
@@ -771,7 +771,7 @@ class PHP_ParserGenerator
for ($j = $i; $j < $this->nsymbol; $j += $skip) {
$sp = $this->symbols[$j];
//assert( sp->index==j );
printf(" %3d %-{$maxlen}.{$maxlen}s", $j, $sp->name);
printf(" %3d %-${maxlen}.${maxlen}s", $j, $sp->name);
}
print "\n";
}

View File

@@ -231,19 +231,19 @@ class PHP_ParserGenerator_Action
switch ($this->type)
{
case self::SHIFT:
fprintf($fp, "%{$indent}s shift %d", $this->sp->name, $this->x->statenum);
fprintf($fp, "%${indent}s shift %d", $this->sp->name, $this->x->statenum);
break;
case self::REDUCE:
fprintf($fp, "%{$indent}s reduce %d", $this->sp->name, $this->x->index);
fprintf($fp, "%${indent}s reduce %d", $this->sp->name, $this->x->index);
break;
case self::ACCEPT:
fprintf($fp, "%{$indent}s accept", $this->sp->name);
fprintf($fp, "%${indent}s accept", $this->sp->name);
break;
case self::ERROR:
fprintf($fp, "%{$indent}s error", $this->sp->name);
fprintf($fp, "%${indent}s error", $this->sp->name);
break;
case self::CONFLICT:
fprintf($fp, "%{$indent}s reduce %-3d ** Parsing conflict **", $this->sp->name, $this->x->index);
fprintf($fp, "%${indent}s reduce %-3d ** Parsing conflict **", $this->sp->name, $this->x->index);
break;
case self::SH_RESOLVED:
case self::RD_RESOLVED:

View File

@@ -20,7 +20,6 @@ use Combodo\iTop\Application\UI\Base\Component\CollapsibleSection\CollapsibleSec
use Combodo\iTop\Application\UI\Base\Component\Html\Html;
use Combodo\iTop\Application\UI\Base\iUIBlock;
use Combodo\iTop\Application\UI\Base\Layout\UIContentBlockUIBlockFactory;
use Combodo\iTop\Application\WebPage\WebPage;
use Combodo\iTop\Renderer\BlockRenderer;
define('CASELOG_VISIBLE_ITEMS', 2);
@@ -170,7 +169,7 @@ class ormCaseLog {
}
// Process the case of an eventual remainder (quick migration of AttributeText fields)
if ($iPos < (utils::StrLen($this->m_sLog) - 1))
if ($iPos < (strlen($this->m_sLog) - 1))
{
$sTextEntry = substr($this->m_sLog, $iPos);
@@ -293,7 +292,7 @@ class ormCaseLog {
}
// Process the case of an eventual remainder (quick migration of AttributeText fields)
if ($iPos < (utils::StrLen($this->m_sLog) - 1)) {
if ($iPos < (strlen($this->m_sLog) - 1)) {
$sTextEntry = substr($this->m_sLog, $iPos);
$sTextEntry = str_replace(array("\r\n", "\n", "\r"), "<br/>", utils::EscapeHtml($sTextEntry));
@@ -374,7 +373,7 @@ class ormCaseLog {
}
// Process the case of an eventual remainder (quick migration of AttributeText fields)
if ($iPos < (utils::StrLen($this->m_sLog) - 1)) {
if ($iPos < (strlen($this->m_sLog) - 1)) {
$sTextEntry = substr($this->m_sLog, $iPos);
$sTextEntry = str_replace(array("\r\n", "\n", "\r"), "<br/>", utils::EscapeHtml($sTextEntry));
@@ -468,7 +467,7 @@ class ormCaseLog {
$oBlock->AddSubBlock($oCollapsibleBlock);
}
// Process the case of an eventual remainder (quick migration of AttributeText fields)
if ($iPos < (utils::StrLen($this->m_sLog) - 1)) {
if ($iPos < (strlen($this->m_sLog) - 1)) {
// In this case the format is always "text"
$sTextEntry = substr($this->m_sLog, $iPos);
$sTextEntry = str_replace(array("\r\n", "\n", "\r"), "<br/>", utils::EscapeHtml($sTextEntry));

View File

@@ -17,7 +17,6 @@
* You should have received a copy of the GNU Affero General Public License
*/
use Combodo\iTop\Application\WebPage\WebPage;
use Combodo\iTop\Service\Events\EventData;
use Combodo\iTop\Service\Events\EventService;
@@ -344,6 +343,6 @@ class ormDocument
*/
public function GetSignature(): string
{
return md5($this->GetData() ?? '');
return md5($this->GetData());
}
}

View File

@@ -8,13 +8,10 @@ use Combodo\iTop\Application\UI\Base\Component\FieldSet\FieldSetUIBlockFactory;
use Combodo\iTop\Application\UI\Base\Component\Html\Html;
use Combodo\iTop\Application\UI\Base\Component\Input\InputUIBlockFactory;
use Combodo\iTop\Application\UI\Base\Component\Input\Select\SelectOptionUIBlockFactory;
use Combodo\iTop\Application\UI\Base\Component\Input\Select\SelectUIBlockFactory;
use Combodo\iTop\Application\UI\Base\Component\Input\SelectUIBlockFactory;
use Combodo\iTop\Application\UI\Base\Component\Panel\PanelUIBlockFactory;
use Combodo\iTop\Application\UI\Base\Layout\MultiColumn\Column\ColumnUIBlockFactory;
use Combodo\iTop\Application\UI\Base\Layout\MultiColumn\MultiColumnUIBlockFactory;
use Combodo\iTop\Application\WebPage\Page;
use Combodo\iTop\Application\WebPage\PDFPage;
use Combodo\iTop\Application\WebPage\WebPage;
/**
* Bulk export: PDF export, based on the HTML export converted to PDF
@@ -52,7 +49,7 @@ class PDFBulkExport extends HTMLBulkExport
}
/**
* @param WebPage $oP
* @param \WebPage $oP
* @param $sPartId
*
* @return UIContentBlock
@@ -71,6 +68,8 @@ class PDFBulkExport extends HTMLBulkExport
//page format
$oSelectFormat = SelectUIBlockFactory::MakeForSelectWithLabel("page_size", Dict::S('Core:BulkExport:PDFPageSize'));
$oSelectFormat->SetIsLabelBefore(false);
//$oSelectFormat->AddCSSClass('ibo-input-checkbox');
$oFieldSetFormat->AddSubBlock($oSelectFormat);
$aPossibleFormat = ['A3', 'A4', 'Letter'];
@@ -80,7 +79,10 @@ class PDFBulkExport extends HTMLBulkExport
}
$oFieldSetFormat->AddSubBlock(new Html('</br>'));
$oSelectOrientation = SelectUIBlockFactory::MakeForSelectWithLabel("page_orientation", Dict::S('Core:BulkExport:PDFPageOrientation'));
$oSelectOrientation = SelectUIBlockFactory::MakeForSelectWithLabel("page_orientation",
Dict::S('Core:BulkExport:PDFPageOrientation'));
$oSelectOrientation->SetIsLabelBefore(false);
//$oSelectOrientation->AddCSSClass('ibo-input-checkbox');
$oFieldSetFormat->AddSubBlock($oSelectOrientation);
$aPossibleOrientation = ['P', 'L'];

View File

@@ -10,8 +10,6 @@ use Combodo\iTop\Application\UI\Base\Component\Input\InputUIBlockFactory;
use Combodo\iTop\Application\UI\Base\Component\Panel\PanelUIBlockFactory;
use Combodo\iTop\Application\UI\Base\Layout\MultiColumn\Column\ColumnUIBlockFactory;
use Combodo\iTop\Application\UI\Base\Layout\MultiColumn\MultiColumnUIBlockFactory;
use Combodo\iTop\Application\WebPage\Page;
use Combodo\iTop\Application\WebPage\WebPage;
/**
* Bulk export: "spreadsheet" export: a simplified HTML export in which the date/time columns are split in two column: date AND time
@@ -36,7 +34,7 @@ class SpreadsheetBulkExport extends TabularBulkExport
}
/**
* @param WebPage $oP
* @param \WebPage $oP
* @param $sPartId
*
* @return UIContentBlock

View File

@@ -6,7 +6,6 @@
use Combodo\iTop\Application\UI\Base\Component\Input\InputUIBlockFactory;
use Combodo\iTop\Application\UI\Base\Layout\UIContentBlockUIBlockFactory;
use Combodo\iTop\Application\WebPage\WebPage;
/**
* Bulk export: Tabular export: abstract base class for all "tabular" exports.
@@ -23,7 +22,7 @@ abstract class TabularBulkExport extends BulkExport
}
/**
* @param WebPage $oP
* @param \WebPage $oP
* @param $sPartId
*
* @return UIContentBlock

View File

@@ -17,8 +17,6 @@
* You should have received a copy of the GNU Affero General Public License
*/
use Combodo\iTop\Application\WebPage\WebPage;
/**
* <p>Stores data for {@link AttributeTagSet} fields
@@ -298,7 +296,7 @@ abstract class TagSetFieldData extends cmdbAbstractObject
/**
* Display Tag Usage
*
* @param WebPage $oPage
* @param \WebPage $oPage
* @param bool $bEditMode
*
* @throws \CoreException

View File

@@ -53,10 +53,9 @@ abstract class Trigger extends cmdbAbstractObject
MetaModel::Init_AddAttribute(new AttributeEnumSet("context", array("allowed_values" => null, "possible_values" => new ValueSetEnumPadded($aTags, true), "sql" => "context", "depends_on" => array(), "is_null_allowed" => true, "max_items" => 12)));
// "complement" is a computed field, fed by Trigger sub-classes, in general in ComputeValues method, for eg. the TriggerOnObject fed it with target_class info
MetaModel::Init_AddAttribute(new AttributeString("complement", array("allowed_values" => null, "sql" => "complement", "default_value" => null, "is_null_allowed" => true, "depends_on" => array())));
MetaModel::Init_AddAttribute(new AttributeEnum("subscription_policy", array("allowed_values" => new ValueSetEnum('allow_no_channel,force_at_least_one_channel,force_all_channels'), "sql" => "subscription_policy", "default_value" => 'allow_no_channel', "is_null_allowed" => false, "depends_on" => array())));
// Display lists
MetaModel::Init_SetZListItems('details', array('finalclass', 'description', 'context', 'subscription_policy', 'action_list', 'complement')); // Attributes to be displayed for the complete details
MetaModel::Init_SetZListItems('details', array('finalclass', 'description', 'context', 'action_list', 'complement')); // Attributes to be displayed for the complete details
MetaModel::Init_SetZListItems('list', array('finalclass', 'complement')); // Attributes to be displayed for a list
// Search criteria
// MetaModel::Init_SetZListItems('standard_search', array('name')); // Criteria of the std search form
@@ -112,31 +111,19 @@ abstract class Trigger extends cmdbAbstractObject
return;
}
$aContextArgs['trigger->object()'] = $this;
// Find the related actions
$oLinkedActions = $this->Get('action_list');
// Order actions as expected
$aActionListOrdered = [];
while ($oLink = $oLinkedActions->Fetch()) {
$aActionListOrdered[(int) $oLink->Get('order')][] = $oLink;
}
ksort($aActionListOrdered);
// Execute actions
foreach ($aActionListOrdered as $aActionSubList) {
foreach ($aActionSubList as $oLink) /** @var \DBObject $oLink */ {
/** @var \DBObject $oLink */
$iActionId = $oLink->Get('action_id');
/** @var \Action $oAction */
$oAction = MetaModel::GetObject('Action', $iActionId);
if ($oAction->IsActive()) {
$oKPI = new ExecutionKPI();
$aContextArgs['action->object()'] = $oAction;
$oAction->DoExecute($this, $aContextArgs);
$oKPI->ComputeStatsForExtension($oAction, 'DoExecute');
}
while ($oLink = $oLinkedActions->Fetch())
{
/** @var \DBObject $oLink */
$iActionId = $oLink->Get('action_id');
/** @var \Action $oAction */
$oAction = MetaModel::GetObject('Action', $iActionId);
if ($oAction->IsActive())
{
$oKPI = new ExecutionKPI();
$oAction->DoExecute($this, $aContextArgs);
$oKPI->ComputeStatsForExtension($oAction, 'DoExecute');
}
}
}
@@ -269,38 +256,6 @@ abstract class TriggerOnObject extends Trigger
}
}
/**
* Activate trigger based on attribute list given instead of changed attributes
*
* @param array $aContextArgs
* @param array|null $aAttributes if null default to changed attributes
*
* @throws \ArchivedObjectException
* @throws \CoreException
* @throws \MissingQueryArgument
* @throws \MySQLException
* @throws \MySQLHasGoneAwayException
* @throws \OQLException
* @since 3.1.1 3.2.0 N°6228
*/
public function DoActivateForSpecificAttributes(array $aContextArgs, ?array $aAttributes)
{
if (isset($aContextArgs['this->object()']))
{
/** @var \DBObject $oObject */
$oObject = $aContextArgs['this->object()'];
if (is_null($aAttributes)) {
$aChanges = $oObject->ListPreviousValuesForUpdatedAttributes();
} else {
$aChanges = array_fill_keys($aAttributes, true);
}
if (false === $this->IsTargetObject($oObject->GetKey(), $aChanges)) {
return;
}
}
parent::DoActivate($aContextArgs);
}
/**
* @param $iObjectId
* @param array $aChanges
@@ -451,7 +406,7 @@ class TriggerOnStateEnter extends TriggerOnStateChange
MetaModel::Init_InheritAttributes();
// Display lists
MetaModel::Init_SetZListItems('details', array('description', 'context', 'target_class', 'filter', 'state', 'subscription_policy', 'action_list')); // Attributes to be displayed for the complete details
MetaModel::Init_SetZListItems('details', array('description', 'context', 'target_class', 'filter', 'state', 'action_list')); // Attributes to be displayed for the complete details
MetaModel::Init_SetZListItems('list', array('target_class', 'state')); // Attributes to be displayed for a list
// Search criteria
MetaModel::Init_SetZListItems('standard_search', array('description', 'target_class', 'state')); // Criteria of the std search form
@@ -484,7 +439,7 @@ class TriggerOnStateLeave extends TriggerOnStateChange
MetaModel::Init_InheritAttributes();
// Display lists
MetaModel::Init_SetZListItems('details', array('description', 'context', 'target_class', 'filter', 'state', 'subscription_policy', 'action_list')); // Attributes to be displayed for the complete details
MetaModel::Init_SetZListItems('details', array('description', 'context', 'target_class', 'filter', 'state', 'action_list')); // Attributes to be displayed for the complete details
MetaModel::Init_SetZListItems('list', array('target_class', 'state')); // Attributes to be displayed for a list
// Search criteria
MetaModel::Init_SetZListItems('standard_search', array('description', 'target_class', 'state')); // Criteria of the std search form
@@ -517,7 +472,7 @@ class TriggerOnObjectCreate extends TriggerOnObject
MetaModel::Init_InheritAttributes();
// Display lists
MetaModel::Init_SetZListItems('details', array('description', 'context', 'target_class', 'filter', 'subscription_policy', 'action_list')); // Attributes to be displayed for the complete details
MetaModel::Init_SetZListItems('details', array('description', 'context', 'target_class', 'filter', 'action_list')); // Attributes to be displayed for the complete details
MetaModel::Init_SetZListItems('list', array('finalclass', 'target_class')); // Attributes to be displayed for a list
// Search criteria
MetaModel::Init_SetZListItems('standard_search', array('description', 'target_class')); // Criteria of the std search form
@@ -550,7 +505,7 @@ class TriggerOnObjectDelete extends TriggerOnObject
MetaModel::Init_InheritAttributes();
// Display lists
MetaModel::Init_SetZListItems('details', array('description', 'context', 'target_class', 'filter', 'subscription_policy', 'action_list')); // Attributes to be displayed for the complete details
MetaModel::Init_SetZListItems('details', array('description', 'context', 'target_class', 'filter', 'action_list')); // Attributes to be displayed for the complete details
MetaModel::Init_SetZListItems('list', array('finalclass', 'target_class')); // Attributes to be displayed for a list
// Search criteria
MetaModel::Init_SetZListItems('standard_search', array('description', 'target_class')); // Criteria of the std search form
@@ -585,7 +540,7 @@ class TriggerOnObjectUpdate extends TriggerOnObject
MetaModel::Init_AddAttribute(new AttributeClassAttCodeSet('target_attcodes', array("allowed_values" => null, "class_field" => "target_class", "sql" => "target_attcodes", "default_value" => null, "is_null_allowed" => true, "max_items" => 20, "min_items" => 0, "attribute_definition_exclusion_list" => "AttributeDashboard,AttributeExternalField,AttributeFinalClass,AttributeFriendlyName,AttributeObsolescenceDate,AttributeObsolescenceFlag,AttributeSubItem", "attribute_definition_list" => null, "depends_on" => array('target_class'))));
// Display lists
MetaModel::Init_SetZListItems('details', array('description', 'context', 'target_class', 'filter', 'target_attcodes', 'subscription_policy', 'action_list')); // Attributes to be displayed for the complete details
MetaModel::Init_SetZListItems('details', array('description', 'context', 'target_class', 'filter', 'target_attcodes', 'action_list')); // Attributes to be displayed for the complete details
MetaModel::Init_SetZListItems('list', array('finalclass', 'target_class')); // Attributes to be displayed for a list
// Search criteria
MetaModel::Init_SetZListItems('standard_search', array('description', 'target_class')); // Criteria of the std search form
@@ -681,7 +636,7 @@ class TriggerOnObjectMention extends TriggerOnObject
MetaModel::Init_AddAttribute(new AttributeOQL("mentioned_filter", array("allowed_values" => null, "sql" => "mentioned_filter", "default_value" => null, "is_null_allowed" => true, "depends_on" => array())));
// Display lists
MetaModel::Init_SetZListItems('details', array('description', 'context', 'target_class', 'filter', 'mentioned_filter', 'subscription_policy', 'action_list')); // Attributes to be displayed for the complete details
MetaModel::Init_SetZListItems('details', array('description', 'context', 'target_class', 'filter', 'mentioned_filter', 'action_list')); // Attributes to be displayed for the complete details
MetaModel::Init_SetZListItems('list', array('finalclass', 'target_class')); // Attributes to be displayed for a list
// Search criteria
MetaModel::Init_SetZListItems('standard_search', array('description', 'target_class')); // Criteria of the std search form

View File

@@ -1,7 +1,6 @@
<?php
use Combodo\iTop\Application\Helper\Session;
use Combodo\iTop\Application\WebPage\WebPage;
define('UR_ALLOWED_NO', 0);
define('UR_ALLOWED_YES', 1);
@@ -162,7 +161,7 @@ abstract class UserRightsAddOnAPI
$oSearchSharers->AllowAllData();
$oSearchSharers->AddCondition_ReferencedBy($oShareSearch, 'sharing_org_id');
$aSharers = array();
foreach($oSearchSharers->SelectAttributeToArray('id') as $aRow)
foreach($oSearchSharers->ToDataArray(array('id')) as $aRow)
{
$aSharers[] = $aRow['id'];
}
@@ -180,17 +179,23 @@ abstract class UserRightsAddOnAPI
$sShareClass = $aShareProperties['share_class'];
$sShareAttCode = $aShareProperties['attcode'];
$oSearchShares = new DBSharedSearch($sShareClass);
$oSearchShares->AllowAllData();
$oSearchShares = new DBObjectSearch($sShareClass);
$oSearchShares->AllowAllData();
$sHierarchicalKeyCode = MetaModel::IsHierarchicalClass('Organization');
$oOrgField = new FieldExpression('org_id', $sShareClass);
$oSearchShares->AddConditionExpression(new BinaryExpression($oOrgField, 'IN', $oListExpr));
$oNested = SharedQueryExpression::FromOQLObjectQuery($oSearchShares, [$sShareClass =>[$sShareAttCode]]);
$oObjId = new FieldExpression('id', $sClass);
$oFilter->MergeConditionExpression(new BinaryExpression($oObjId, 'IN', $oNested));
$aShared = array();
foreach($oSearchShares->ToDataArray(array($sShareAttCode)) as $aRow)
{
$aShared[] = $aRow[$sShareAttCode];
}
if (count($aShared) > 0)
{
$oObjId = new FieldExpression('id', $sClass);
$oSharedIdList = ListExpression::FromScalars($aShared);
$oFilter->MergeConditionExpression(new BinaryExpression($oObjId, 'IN', $oSharedIdList));
}
}
} // if HasSharing
@@ -243,7 +248,7 @@ abstract class User extends cmdbAbstractObject
"depends_on" => array(),
)));
MetaModel::Init_AddAttribute(new AttributeLinkedSetIndirect("profile_list",array("linked_class" => "URP_UserProfile", "ext_key_to_me" => "userid", "ext_key_to_remote" => "profileid", "allowed_values" => null, "count_min" => 1, "count_max" => 0, "depends_on" => array(), "display_style" => 'property', "with_php_constraint" => true, "with_php_computation" => true)));
MetaModel::Init_AddAttribute(new AttributeLinkedSetIndirect("profile_list",array("linked_class" => "URP_UserProfile", "ext_key_to_me" => "userid", "ext_key_to_remote" => "profileid", "allowed_values" => null, "count_min" => 1, "count_max" => 0, "depends_on" => array(), "display_style" => 'property', "with_php_constraint" => true)));
MetaModel::Init_AddAttribute(new AttributeLinkedSetIndirect("allowed_org_list", array("linked_class" => "URP_UserOrg", "ext_key_to_me" => "userid", "ext_key_to_remote" => "allowed_org_id", "allowed_values" => null, "count_min" => 1, "count_max" => 0, "depends_on" => array(), 'with_php_constraint' => true)));
MetaModel::Init_AddAttribute(new AttributeCaseLog("log", array("sql" => 'log', "is_null_allowed" => true, "default_value" => '', "allowed_values" => null, "depends_on" => array(), "always_load_in_tables" => false)));
@@ -851,8 +856,6 @@ class UserRights
}
/**
* Set the current user (as part of the login process)
*
* @param string $sLogin Login of the concerned user
* @param string $sAuthentication
*
@@ -862,7 +865,7 @@ class UserRights
*/
public static function Login($sLogin, $sAuthentication = 'any')
{
self::ResetCurrentUserData();
static::Logoff();
$oUser = self::FindUser($sLogin, $sAuthentication);
if (is_null($oUser))
@@ -882,8 +885,6 @@ class UserRights
}
/**
* Reset current user and cleanup associated SESSION data
*
* @return void
* @since 3.0.4 3.1.1 3.2.0
*/
@@ -1118,7 +1119,9 @@ class UserRights
}
/**
* @return string connected {@see User} login field value, otherwise empty string
* Return the current user login or an empty string if nobody connected.
*
* @return string
*/
public static function GetUser()
{
@@ -1566,9 +1569,9 @@ class UserRights
/**
* @param string $sClass
* @param int $iActionCode see UR_ACTION_* constants
* @param DBObjectSet $oInstanceSet
* @param User $oUser
* @param int $iActionCode
* @param \DBObjectSet $oInstanceSet
* @param \User $oUser
*
* @return int (UR_ALLOWED_YES|UR_ALLOWED_NO|UR_ALLOWED_DEPENDS)
* @throws \CoreException

View File

@@ -8,8 +8,6 @@ use Combodo\iTop\Application\UI\Base\Component\Input\InputUIBlockFactory;
use Combodo\iTop\Application\UI\Base\Component\Panel\PanelUIBlockFactory;
use Combodo\iTop\Application\UI\Base\Layout\MultiColumn\Column\ColumnUIBlockFactory;
use Combodo\iTop\Application\UI\Base\Layout\MultiColumn\MultiColumnUIBlockFactory;
use Combodo\iTop\Application\WebPage\Page;
use Combodo\iTop\Application\WebPage\WebPage;
/**
* Bulk export: XML export
@@ -32,7 +30,7 @@ class XMLBulkExport extends BulkExport
}
/**
* @param WebPage $oP
* @param \WebPage $oP
* @param $sPartId
*
* @return UIContentBlock

View File

@@ -49,63 +49,3 @@
.ibo-navigation-menu.ibo-is-active .ibo-navigation-menu--drawer{
transform: translate3d(0,0,0);
}
// Toggler legacy CSS that has somehow been added to iTop 3.0 and that is now used by some extensions
// Round Toggle
/* The switch - the box around the slider */
.switch {
position: relative;
display: inline-block;
width: 36px;
height: 20px;
vertical-align: baseline;
}
/* Hide default HTML checkbox */
.switch input {
display: none;
}
/* The slider */
.slider {
position: absolute;
cursor: pointer;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: $ibo-color-secondary-600;
transition: .4s;
}
.slider:before {
position: absolute;
content: "";
height: 15px;
width: 15px;
left: 3px;
bottom: 3px;
background-color: $ibo-color-secondary-300;
transition: .4s;
}
input:checked + .slider {
background-color: $ibo-color-primary-600;
}
input:focus + .slider {
box-shadow: 0 0 1px $ibo-color-primary-600;
}
input:checked + .slider:before {
transform: translateX(14.5px);
}
/* Rounded sliders */
.slider.round {
border-radius: 20px;
}
.slider.round:before {
border-radius: 7px;
}

View File

@@ -11,6 +11,10 @@ $ibo-scrollbar--scrollbar-thumb-background-color: $ibo-color-grey-300 !default;
$ibo-scrollbar--scrollbar-thumb-border: none !default;
$ibo-scrollbar--scrollbar-thumb-border-radius: $ibo-border-radius-500 !default;
$ibo-hyperlink-color: $ibo-color-primary-700 !default;
$ibo-hyperlink-color--on-hover: $ibo-color-primary-800 !default;
$ibo-hyperlink-color--on-active: $ibo-color-primary-900 !default;
$ibo-svg-illustration--fill: $ibo-color-primary-500 !default;
$ibo-content-block--background-color: $ibo-color-white-100 !default;
@@ -25,6 +29,10 @@ $ibo-content-block--border: 1px solid $ibo-color-grey-400 !default;
--ibo-scrollbar--scrollbar-thumb-background-color: #{$ibo-scrollbar--scrollbar-thumb-background-color};
--ibo-scrollbar--scrollbar-thumb-border: #{$ibo-scrollbar--scrollbar-thumb-border};
--ibo-scrollbar--scrollbar-thumb-border-radius: #{$ibo-scrollbar--scrollbar-thumb-border-radius};
--ibo-hyperlink-color: #{$ibo-hyperlink-color};
--ibo-hyperlink-color--on-hover: #{$ibo-hyperlink-color--on-hover};
--ibo-hyperlink-color--on-active: #{$ibo-hyperlink-color--on-active};
}
/* Box sizing reset */
@@ -65,19 +73,17 @@ html{
/* Hyperlinks reset, ensure that they are of the right color and without decoration everywhere (of course this can be overloaded in some components) */
a{
color: var(--ibo-hyperlink-color);
text-decoration: var(--ibo-hyperlink-text-decoration);
text-decoration: none;
&:hover,
&:active,
&:visited{
text-decoration: var(--ibo-hyperlink-text-decoration);
text-decoration: none;
}
&:hover{
color: var(--ibo-hyperlink-color--on-hover);
text-decoration: var(--ibo-hyperlink-text-decoration--on-hover);
}
&:active{
color: var(--ibo-hyperlink-color--on-active);
text-decoration: var(--ibo-hyperlink-text-decoration--on-active);
}
}

View File

@@ -41,7 +41,7 @@ $ibo-alert-colors: (
$bg-color: nth($aColorValues, 1);
$highlight-color: nth($aColorValues, 2);
$text-color: nth($aColorValues, 3);
%ibo-alert-#{$sColor}, .ibo-alert.ibo-is-#{$sColor} {
.ibo-alert.ibo-is-#{$sColor} {
background-color: $bg-color;
color: $text-color;
a {

Some files were not shown because too many files have changed in this diff Show More