mirror of
https://github.com/Combodo/iTop.git
synced 2026-03-06 17:44:12 +01:00
Compare commits
7 Commits
faf/improv
...
feature/13
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0e76db8c93 | ||
|
|
49cf6f5fe2 | ||
|
|
b852e72088 | ||
|
|
9ebcbf2459 | ||
|
|
1df7c3d8f3 | ||
|
|
f4545615cb | ||
|
|
d4e64bc479 |
Binary file not shown.
|
Before Width: | Height: | Size: 3.0 MiB |
@@ -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
|
||||
@@ -69,16 +62,6 @@ gitGraph
|
||||
commit id: "2022-12-28" tag: "2.7.8"
|
||||
checkout support/3.0
|
||||
commit id: "2023-04-12" tag: "3.0.3"
|
||||
checkout develop
|
||||
commit id: "2023-06-19" tag: "3.1.0-beta" type: REVERSE
|
||||
commit id: "2023-07-26" tag: "3.1.0-1" type: HIGHLIGHT
|
||||
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).
|
||||
To learn more, check the [iTop community versions history on the official wiki](https://www.itophub.io/wiki/page?id=latest:release:start).
|
||||
83
.github/pull_request_template.md
vendored
83
.github/pull_request_template.md
vendored
@@ -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
6
.gitignore
vendored
@@ -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
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -19,24 +19,17 @@
|
||||
* The target license file path is in `$xmlFilePath`
|
||||
*/
|
||||
|
||||
$iTopFolder = __DIR__."/../../";
|
||||
$xmlFilePath = $iTopFolder."setup/licenses/community-licenses.xml";
|
||||
$iTopFolder = __DIR__ . "/../../" ;
|
||||
$xmlFilePath = $iTopFolder . "setup/licenses/community-licenses.xml";
|
||||
|
||||
$jqExec = shell_exec("jq -V"); // a param is mandatory otherwise the script will freeze
|
||||
if ((null === $jqExec) || (false === $jqExec)) {
|
||||
echo "/!\ JQ is required but cannot be launched :( \n";
|
||||
echo "Check this script PHPDoc block for instructions\n";
|
||||
die(-1);
|
||||
}
|
||||
|
||||
|
||||
function get_scope($product_node) {
|
||||
function get_scope($product_node)
|
||||
{
|
||||
$scope = $product_node->getAttribute("scope");
|
||||
|
||||
if ($scope === "") { //put iTop first
|
||||
if ($scope === "")
|
||||
{ //put iTop first
|
||||
return "aaaaaaaaa";
|
||||
}
|
||||
|
||||
return $scope;
|
||||
}
|
||||
|
||||
|
||||
@@ -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:
|
||||
|
||||

|
||||

|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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');
|
||||
|
||||
@@ -230,7 +228,6 @@ class URP_UserProfile extends UserRightsBaseClassGUI
|
||||
"db_table" => "priv_urp_userprofile",
|
||||
"db_key_field" => "id",
|
||||
"db_finalclass_field" => "",
|
||||
"is_link" => true, /** @since 3.1.0 N°6482 */
|
||||
'uniqueness_rules' => array(
|
||||
'no_duplicate' => array(
|
||||
'attributes' => array(
|
||||
@@ -448,12 +445,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 +501,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 +557,6 @@ class UserRightsProfile extends UserRightsAddOnAPI
|
||||
|
||||
// Cache
|
||||
$this->m_aObjectActionGrants = array();
|
||||
$this->m_aAdministrators = null;
|
||||
}
|
||||
|
||||
public function LoadCache()
|
||||
@@ -710,10 +699,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 +717,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 +757,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 +884,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 +917,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)
|
||||
{
|
||||
|
||||
@@ -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');
|
||||
|
||||
@@ -336,7 +334,6 @@ class URP_UserProfile extends UserRightsBaseClassGUI
|
||||
"db_table" => "priv_urp_userprofile",
|
||||
"db_key_field" => "id",
|
||||
"db_finalclass_field" => "",
|
||||
"is_link" => true, /** @since 3.1.0 N°6482 */
|
||||
);
|
||||
MetaModel::Init_Params($aParams);
|
||||
//MetaModel::Init_InheritAttributes();
|
||||
@@ -582,10 +579,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
|
||||
*/
|
||||
|
||||
@@ -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
|
||||
@@ -279,7 +277,6 @@ class URP_UserProfile extends UserRightsBaseClass
|
||||
"db_table" => "priv_urp_userprofile",
|
||||
"db_key_field" => "id",
|
||||
"db_finalclass_field" => "",
|
||||
"is_link" => true, /** @since 3.1.0 N°6482 */
|
||||
);
|
||||
MetaModel::Init_Params($aParams);
|
||||
//MetaModel::Init_InheritAttributes();
|
||||
|
||||
29
app.php
29
app.php
@@ -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']);
|
||||
};
|
||||
@@ -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
|
||||
|
||||
@@ -238,7 +238,7 @@ class ApplicationContext
|
||||
{
|
||||
$aContextInputBlocks = [];
|
||||
foreach ($this->aValues as $sName => $sValue) {
|
||||
$aContextInputBlocks[] = InputUIBlockFactory::MakeForHidden("c[$sName]", $sValue);
|
||||
$aContextInputBlocks[] = InputUIBlockFactory::MakeForHidden("c[$sName]", utils::EscapeHtml($sValue));
|
||||
}
|
||||
return $aContextInputBlocks;
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
@@ -2250,27 +2246,3 @@ interface iModuleExtension
|
||||
*/
|
||||
public function __construct();
|
||||
}
|
||||
|
||||
/**
|
||||
* KPI logging extensibility point
|
||||
*
|
||||
* KPI Logger extension
|
||||
*/
|
||||
interface iKPILoggerExtension
|
||||
{
|
||||
/**
|
||||
* Init the statistics collected
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function InitStats();
|
||||
|
||||
/**
|
||||
* Add a new KPI to the stats
|
||||
*
|
||||
* @param \Combodo\iTop\Core\Kpi\KpiLogData $oKpiLogData
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function LogOperation($oKpiLogData);
|
||||
}
|
||||
@@ -34,15 +34,15 @@ class AuditCategory extends cmdbAbstractObject
|
||||
{
|
||||
$aParams = array
|
||||
(
|
||||
"category" => "application,grant_by_profile",
|
||||
"key_type" => "autoincrement",
|
||||
"name_attcode" => "name",
|
||||
"state_attcode" => "",
|
||||
"reconc_keys" => array('name'),
|
||||
"db_table" => "priv_auditcategory",
|
||||
"db_key_field" => "id",
|
||||
"category" => "application, grant_by_profile",
|
||||
"key_type" => "autoincrement",
|
||||
"name_attcode" => "name",
|
||||
"state_attcode" => "",
|
||||
"reconc_keys" => array('name'),
|
||||
"db_table" => "priv_auditcategory",
|
||||
"db_key_field" => "id",
|
||||
"db_finalclass_field" => "",
|
||||
'style' => new ormStyle(null, null, null, null, null, '../images/icons/icons8-audit-folder.svg'),
|
||||
'style' => new ormStyle(null, null, null, null, null, '../images/icons/icons8-audit-folder.svg'),
|
||||
);
|
||||
MetaModel::Init_Params($aParams);
|
||||
MetaModel::Init_AddAttribute(new AttributeString("name", array("description"=>"Short name for this category", "allowed_values"=>null, "sql"=>"name", "default_value"=>"", "is_null_allowed"=>false, "depends_on"=>array())));
|
||||
@@ -74,23 +74,15 @@ class AuditCategory extends cmdbAbstractObject
|
||||
public function GetReportColor($iTotal, $iErrors)
|
||||
{
|
||||
$sResult = 'red';
|
||||
if ( ($iTotal == 0) || ($iErrors / $iTotal) <= ($this->Get('ok_error_tolerance') / 100) ) {
|
||||
if ( ($iTotal == 0) || ($iErrors / $iTotal) <= ($this->Get('ok_error_tolerance') / 100) )
|
||||
{
|
||||
$sResult = 'green';
|
||||
} else if (($iErrors / $iTotal) <= ($this->Get('warning_error_tolerance') / 100)) {
|
||||
}
|
||||
else if ( ($iErrors / $iTotal) <= ($this->Get('warning_error_tolerance') / 100) )
|
||||
{
|
||||
$sResult = 'orange';
|
||||
}
|
||||
|
||||
return $sResult;
|
||||
}
|
||||
|
||||
public static function GetShortcutActions($sFinalClass)
|
||||
{
|
||||
$aShortcutActions = parent::GetShortcutActions($sFinalClass);
|
||||
if (!in_array('UI:Menu:RunAudit', $aShortcutActions)) {
|
||||
$aShortcutActions[] = 'UI:Menu:RunAudit';
|
||||
}
|
||||
|
||||
return $aShortcutActions;
|
||||
}
|
||||
}
|
||||
?>
|
||||
|
||||
@@ -35,42 +35,30 @@ class AuditDomain extends cmdbAbstractObject
|
||||
{
|
||||
$aParams = array
|
||||
(
|
||||
"category" => "application,grant_by_profile",
|
||||
"key_type" => "autoincrement",
|
||||
"name_attcode" => "name",
|
||||
"complementary_name_attcode" => array('description'),
|
||||
"state_attcode" => "",
|
||||
"reconc_keys" => array('name'),
|
||||
"db_table" => "priv_auditdomain",
|
||||
"db_key_field" => "id",
|
||||
"db_finalclass_field" => "",
|
||||
'style' => new ormStyle(null, null, null, null, null, '../images/icons/icons8-audit-album.svg'),
|
||||
"category" => "application, grant_by_profile",
|
||||
"key_type" => "autoincrement",
|
||||
"name_attcode" => "name",
|
||||
"state_attcode" => "",
|
||||
"reconc_keys" => array('name'),
|
||||
"db_table" => "priv_auditdomain",
|
||||
"db_key_field" => "id",
|
||||
"db_finalclass_field" => "",
|
||||
'style' => new ormStyle(null, null, null, null, null, '../images/icons/icons8-audit-album.svg'),
|
||||
);
|
||||
MetaModel::Init_Params($aParams);
|
||||
MetaModel::Init_AddAttribute(new AttributeString("name", array("description" => "Short name for this category", "allowed_values" => null, "sql" => "name", "default_value" => "", "is_null_allowed" => false, "depends_on" => array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeString("description", array("allowed_values" => null, "sql" => "description", "default_value" => "", "is_null_allowed" => true, "depends_on" => array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeImage("icon", array("is_null_allowed" => true, "depends_on" => array(), "display_max_width" => 96, "display_max_height" => 96, "storage_max_width" => 256, "storage_max_height" => 256, "default_image" => null, "always_load_in_tables" => false)));
|
||||
MetaModel::Init_AddAttribute(new AttributeLinkedSetIndirect("categories_list",
|
||||
array("linked_class" => "lnkAuditCategoryToAuditDomain", "ext_key_to_me" => "domain_id", "ext_key_to_remote" => "category_id", "allowed_values" => null, "count_min" => 0, "count_max" => 0, "depends_on" => array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeString("name", array("description"=>"Short name for this category", "allowed_values"=>null, "sql"=>"name", "default_value"=>"", "is_null_allowed"=>false, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeString("description", array("allowed_values"=>null, "sql"=>"description", "default_value"=>"", "is_null_allowed"=>true, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeImage("icon", array("is_null_allowed"=>true, "depends_on"=>array(), "display_max_width"=>96, "display_max_height"=>96, "storage_max_width"=>256, "storage_max_height"=>256, "default_image"=>null, "always_load_in_tables"=>false)));
|
||||
MetaModel::Init_AddAttribute(new AttributeLinkedSetIndirect("categories_list", array("linked_class" => "lnkAuditCategoryToAuditDomain", "ext_key_to_me" => "domain_id", "ext_key_to_remote" => "category_id", "allowed_values" => null, "count_min" => 0, "count_max" => 0, "depends_on" => array())));
|
||||
|
||||
// Display lists
|
||||
MetaModel::Init_SetZListItems('details', array('name', 'description', 'icon', 'categories_list')); // Attributes to be displayed for the complete details
|
||||
MetaModel::Init_SetZListItems('list', array('description',)); // Attributes to be displayed for a list
|
||||
MetaModel::Init_SetZListItems('list', array('description', )); // Attributes to be displayed for a list
|
||||
// Search criteria
|
||||
MetaModel::Init_SetZListItems('standard_search', array('description')); // Criteria of the std search form
|
||||
MetaModel::Init_SetZListItems('default_search', array('name', 'description')); // Criteria of the default search form
|
||||
}
|
||||
|
||||
public static function GetShortcutActions($sFinalClass)
|
||||
{
|
||||
$aShortcutActions = parent::GetShortcutActions($sFinalClass);
|
||||
if (!in_array('UI:Menu:RunAudit', $aShortcutActions)) {
|
||||
$aShortcutActions[] = 'UI:Menu:RunAudit';
|
||||
}
|
||||
|
||||
return $aShortcutActions;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -86,26 +74,15 @@ class lnkAuditCategoryToAuditDomain extends cmdbAbstractObject
|
||||
{
|
||||
$aParams = array
|
||||
(
|
||||
"category" => "application,grant_by_profile",
|
||||
"key_type" => "autoincrement",
|
||||
"name_attcode" => "",
|
||||
"state_attcode" => "",
|
||||
"reconc_keys" => array('category_id', 'domain_id'),
|
||||
"db_table" => "priv_link_audit_category_domain",
|
||||
"db_key_field" => "id",
|
||||
"category" => "application, grant_by_profile",
|
||||
"key_type" => "autoincrement",
|
||||
"name_attcode" => "",
|
||||
"state_attcode" => "",
|
||||
"reconc_keys" => array('category_id', 'domain_id'),
|
||||
"db_table" => "priv_link_audit_category_domain",
|
||||
"db_key_field" => "id",
|
||||
"db_finalclass_field" => "",
|
||||
"is_link" => true,
|
||||
'uniqueness_rules' => array(
|
||||
'no_duplicate' => array(
|
||||
'attributes' => array(
|
||||
0 => 'category_id',
|
||||
1 => 'domain_id',
|
||||
),
|
||||
'filter' => '',
|
||||
'disabled' => false,
|
||||
'is_blocking' => true,
|
||||
),
|
||||
),
|
||||
"is_link" => true,
|
||||
);
|
||||
MetaModel::Init_Params($aParams);
|
||||
MetaModel::Init_AddAttribute(new AttributeExternalKey("category_id", array("targetclass" => "AuditCategory", "jointype" => '', "allowed_values" => null, "sql" => "category_id", "is_null_allowed" => false, "on_target_delete" => DEL_AUTO, "depends_on" => array())));
|
||||
|
||||
@@ -35,23 +35,23 @@ class AuditRule extends cmdbAbstractObject
|
||||
{
|
||||
$aParams = array
|
||||
(
|
||||
"category" => "application,grant_by_profile",
|
||||
"key_type" => "autoincrement",
|
||||
"name_attcode" => "name",
|
||||
"state_attcode" => "",
|
||||
"reconc_keys" => array('name'),
|
||||
"db_table" => "priv_auditrule",
|
||||
"db_key_field" => "id",
|
||||
"category" => "application, grant_by_profile",
|
||||
"key_type" => "autoincrement",
|
||||
"name_attcode" => "name",
|
||||
"state_attcode" => "",
|
||||
"reconc_keys" => array('name'),
|
||||
"db_table" => "priv_auditrule",
|
||||
"db_key_field" => "id",
|
||||
"db_finalclass_field" => "",
|
||||
'style' => new ormStyle(null, null, null, null, null, '../images/icons/icons8-audit.svg'),
|
||||
'style' => new ormStyle(null, null, null, null, null, '../images/icons/icons8-audit.svg'),
|
||||
);
|
||||
MetaModel::Init_Params($aParams);
|
||||
MetaModel::Init_AddAttribute(new AttributeString("name", array("allowed_values" => null, "sql" => "name", "default_value" => "", "is_null_allowed" => false, "depends_on" => array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeString("description", array("allowed_values" => null, "sql" => "description", "default_value" => "", "is_null_allowed" => true, "depends_on" => array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeOQL("query", array("allowed_values" => null, "sql" => "query", "default_value" => "", "is_null_allowed" => false, "depends_on" => array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeEnum("valid_flag", array("allowed_values" => new ValueSetEnum('true,false'), "sql" => "valid_flag", "default_value" => "true", "is_null_allowed" => false, "depends_on" => array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeExternalKey("category_id", array("allowed_values" => null, "sql" => "category_id", "targetclass" => "AuditCategory", "is_null_allowed" => false, "on_target_delete" => DEL_MANUAL, "depends_on" => array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeExternalField("category_name", array("allowed_values" => null, "extkey_attcode" => 'category_id', "target_attcode" => "name")));
|
||||
MetaModel::Init_AddAttribute(new AttributeString("name", array("allowed_values"=>null, "sql"=>"name", "default_value"=>"", "is_null_allowed"=>false, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeString("description", array("allowed_values"=>null, "sql"=>"description", "default_value"=>"", "is_null_allowed"=>true, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeOQL("query", array("allowed_values"=>null, "sql"=>"query", "default_value"=>"", "is_null_allowed"=>false, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeEnum("valid_flag", array("allowed_values"=>new ValueSetEnum('true,false'), "sql"=>"valid_flag", "default_value"=>"true", "is_null_allowed"=>false, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeExternalKey("category_id", array("allowed_values"=>null, "sql"=>"category_id", "targetclass"=>"AuditCategory", "is_null_allowed"=>false, "on_target_delete"=>DEL_MANUAL, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeExternalField("category_name", array("allowed_values"=>null, "extkey_attcode"=> 'category_id', "target_attcode"=>"name")));
|
||||
|
||||
// Display lists
|
||||
MetaModel::Init_SetZListItems('details', array('category_id', 'name', 'description', 'query', 'valid_flag')); // Attributes to be displayed for the complete details
|
||||
@@ -60,16 +60,5 @@ class AuditRule extends cmdbAbstractObject
|
||||
MetaModel::Init_SetZListItems('standard_search', array('category_id', 'name', 'description', 'valid_flag', 'query')); // Criteria of the std search form
|
||||
MetaModel::Init_SetZListItems('default_search', array('name', 'description', 'category_id')); // Criteria of the advanced search form
|
||||
}
|
||||
|
||||
|
||||
public static function GetShortcutActions($sFinalClass)
|
||||
{
|
||||
$aShortcutActions = parent::GetShortcutActions($sFinalClass);
|
||||
if (!in_array('UI:Menu:RunAudit', $aShortcutActions)) {
|
||||
$aShortcutActions[] = 'UI:Menu:RunAudit';
|
||||
}
|
||||
|
||||
return $aShortcutActions;
|
||||
}
|
||||
}
|
||||
?>
|
||||
|
||||
@@ -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
|
||||
*/
|
||||
|
||||
@@ -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
|
||||
*/
|
||||
|
||||
@@ -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,15 +42,11 @@ 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;
|
||||
use Combodo\iTop\Service\Links\LinkSetDataTransformer;
|
||||
use Combodo\iTop\Service\Links\LinkSetModel;
|
||||
use Combodo\iTop\Service\TemporaryObjects\TemporaryObjectHelper;
|
||||
|
||||
|
||||
define('OBJECT_PROPERTIES_TAB', 'ObjectProperties');
|
||||
@@ -137,8 +133,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';
|
||||
@@ -193,6 +187,9 @@ abstract class cmdbAbstractObject extends CMDBObject implements iDisplay
|
||||
/** @var array initial attributes flags cache [attcode]['flags'] */
|
||||
protected $aInitialAttributesFlags;
|
||||
|
||||
protected $iUpdateLoopCount;
|
||||
|
||||
const MAX_UPDATE_LOOP_COUNT = 10;
|
||||
|
||||
/**
|
||||
* @var array First level classname, second level id, value number of calls done
|
||||
@@ -230,6 +227,7 @@ abstract class cmdbAbstractObject extends CMDBObject implements iDisplay
|
||||
$this->sDisplayMode = static::DEFAULT_DISPLAY_MODE;
|
||||
$this->bAllowWrite = false;
|
||||
$this->bAllowDelete = false;
|
||||
$this->iUpdateLoopCount = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -290,7 +288,7 @@ abstract class cmdbAbstractObject extends CMDBObject implements iDisplay
|
||||
}
|
||||
|
||||
/**
|
||||
* @param WebPage $oPage
|
||||
* @param \WebPage $oPage
|
||||
* @param \cmdbAbstractObject $oObj
|
||||
* @param array $aParams
|
||||
*
|
||||
@@ -359,7 +357,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 +379,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 +557,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 +596,7 @@ HTML
|
||||
}
|
||||
|
||||
/**
|
||||
* @param WebPage $oPage
|
||||
* @param \WebPage $oPage
|
||||
* @param $sAttCode
|
||||
*
|
||||
* @throws \Exception
|
||||
@@ -639,7 +637,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 +747,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 +757,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 +858,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 +1062,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 +1109,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 +1144,7 @@ HTML
|
||||
}
|
||||
|
||||
/**
|
||||
* @param WebPage $oPage
|
||||
* @param \WebPage $oPage
|
||||
*
|
||||
* @throws \ArchivedObjectException
|
||||
* @throws \CoreException
|
||||
@@ -1175,9 +1167,9 @@ HTML
|
||||
}
|
||||
|
||||
/**
|
||||
* @param WebPage $oPage
|
||||
* @param \WebPage $oPage
|
||||
* @param \CMDBObjectSet $oSet
|
||||
* @param array $aExtraParams See possible values in {@see DataTableUIBlockFactory::RenderDataTable()}
|
||||
* @param array $aExtraParams
|
||||
*
|
||||
* @throws \ApplicationException
|
||||
* @throws \CoreException
|
||||
@@ -1237,7 +1229,7 @@ HTML
|
||||
}
|
||||
|
||||
/**
|
||||
* @param WebPage $oPage
|
||||
* @param \WebPage $oPage
|
||||
* @param \DBObjectSet $oSet
|
||||
* @param array $aExtraParams
|
||||
*
|
||||
@@ -1409,7 +1401,7 @@ HTML
|
||||
}
|
||||
|
||||
/**
|
||||
* @param WebPage $oPage
|
||||
* @param \WebPage $oPage
|
||||
* @param \CMDBObjectSet $oSet
|
||||
* @param array $aExtraParams key used :
|
||||
* <ul>
|
||||
@@ -1532,7 +1524,7 @@ HTML
|
||||
}
|
||||
|
||||
/**
|
||||
* @param WebPage $oPage
|
||||
* @param \WebPage $oPage
|
||||
* @param \CMDBObjectSet $oSet
|
||||
* @param array $aParams
|
||||
* @param string $sCharset
|
||||
@@ -1691,7 +1683,7 @@ HTML
|
||||
}
|
||||
|
||||
/**
|
||||
* @param WebPage $oPage
|
||||
* @param \WebPage $oPage
|
||||
* @param \CMDBObjectSet $oSet
|
||||
* @param array $aParams
|
||||
*
|
||||
@@ -1904,7 +1896,7 @@ HTML
|
||||
}
|
||||
|
||||
/**
|
||||
* @param WebPage $oPage
|
||||
* @param \WebPage $oPage
|
||||
* @param \CMDBObjectSet $oSet
|
||||
* @param array $aParams
|
||||
*
|
||||
@@ -1982,7 +1974,7 @@ HTML
|
||||
}
|
||||
|
||||
/**
|
||||
* @param WebPage $oPage
|
||||
* @param \WebPage $oPage
|
||||
* @param \CMDBObjectSet $oSet
|
||||
* @param array $aExtraParams
|
||||
*
|
||||
@@ -2013,7 +2005,7 @@ HTML
|
||||
|
||||
|
||||
/**
|
||||
* @param WebPage $oPage
|
||||
* @param \WebPage $oPage
|
||||
* @param string $sClass
|
||||
* @param string $sAttCode
|
||||
* @param \AttributeDefinition $oAttDef
|
||||
@@ -2364,7 +2356,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 +2743,7 @@ JS
|
||||
}
|
||||
|
||||
/**
|
||||
* @param WebPage $oPage
|
||||
* @param \WebPage $oPage
|
||||
* @param array $aExtraParams
|
||||
*
|
||||
* @throws \ArchivedObjectException
|
||||
@@ -2831,33 +2822,33 @@ JS
|
||||
}
|
||||
}
|
||||
// Custom operation for the form ?
|
||||
if (isset($aExtraParams['custom_operation'])) {
|
||||
$sOperation = $aExtraParams['custom_operation'];
|
||||
} else {
|
||||
if ($this->GetDisplayMode() === static::ENUM_DISPLAY_MODE_EDIT) {
|
||||
$sOperation = 'apply_modify';
|
||||
} else {
|
||||
$sOperation = 'apply_new';
|
||||
}
|
||||
}
|
||||
if (isset($aExtraParams['custom_operation'])) {
|
||||
$sOperation = $aExtraParams['custom_operation'];
|
||||
} else {
|
||||
if ($this->GetDisplayMode() === static::ENUM_DISPLAY_MODE_EDIT) {
|
||||
$sOperation = 'apply_modify';
|
||||
} else {
|
||||
$sOperation = 'apply_new';
|
||||
}
|
||||
}
|
||||
|
||||
$oContentBlock = new UIContentBlock();
|
||||
$oPage->AddUiBlock($oContentBlock);
|
||||
$oContentBlock = new UIContentBlock();
|
||||
$oPage->AddUiBlock($oContentBlock);
|
||||
|
||||
$oForm = new Form("form_{$this->m_iFormId}");
|
||||
$oForm->SetAction($sFormAction);
|
||||
$sOnSubmitForm = "let bOnSubmitForm = OnSubmit('form_{$this->m_iFormId}');";
|
||||
if (isset($aExtraParams['js_handlers']['form_on_submit'])) {
|
||||
$oForm->SetOnSubmitJsCode($sOnSubmitForm . $aExtraParams['js_handlers']['form_on_submit']);
|
||||
} else {
|
||||
$oForm->SetOnSubmitJsCode($sOnSubmitForm . "return bOnSubmitForm;");
|
||||
}
|
||||
$oContentBlock->AddSubBlock($oForm);
|
||||
$oForm = new Form("form_{$this->m_iFormId}");
|
||||
$oForm->SetAction($sFormAction);
|
||||
$sOnSubmitForm = "let bOnSubmitForm = OnSubmit('form_{$this->m_iFormId}');";
|
||||
if (isset($aExtraParams['js_handlers']['form_on_submit'])) {
|
||||
$oForm->SetOnSubmitJsCode($sOnSubmitForm.$aExtraParams['js_handlers']['form_on_submit']);
|
||||
} else {
|
||||
$oForm->SetOnSubmitJsCode($sOnSubmitForm."return bOnSubmitForm;");
|
||||
}
|
||||
$oContentBlock->AddSubBlock($oForm);
|
||||
|
||||
if ($this->GetDisplayMode() === static::ENUM_DISPLAY_MODE_EDIT) {
|
||||
// The object already exists in the database, it's a modification
|
||||
$oForm->AddSubBlock(InputUIBlockFactory::MakeForHidden('id', $iKey, "{$sPrefix}_id"));
|
||||
}
|
||||
if ($this->GetDisplayMode() === static::ENUM_DISPLAY_MODE_EDIT) {
|
||||
// The object already exists in the database, it's a modification
|
||||
$oForm->AddSubBlock(InputUIBlockFactory::MakeForHidden('id', $iKey, "{$sPrefix}_id"));
|
||||
}
|
||||
$oForm->AddSubBlock(InputUIBlockFactory::MakeForHidden('operation', $sOperation));
|
||||
$oForm->AddSubBlock(InputUIBlockFactory::MakeForHidden('class', $sClass));
|
||||
|
||||
@@ -2866,11 +2857,6 @@ JS
|
||||
$oPage->SetTransactionId($iTransactionId);
|
||||
$oForm->AddSubBlock(InputUIBlockFactory::MakeForHidden('transaction_id', $iTransactionId));
|
||||
|
||||
// Add temporary object watchdog (only on root form)
|
||||
if (!utils::IsXmlHttpRequest()) {
|
||||
$oPage->add_ready_script(TemporaryObjectHelper::GetWatchDogJS($iTransactionId));
|
||||
}
|
||||
|
||||
// TODO 3.0.0: Is this (the if condition, not the code inside) still necessary?
|
||||
if (isset($aExtraParams['wizard_container']) && $aExtraParams['wizard_container']) {
|
||||
$sClassLabel = MetaModel::GetName($sClass);
|
||||
@@ -2881,34 +2867,34 @@ JS
|
||||
}
|
||||
}
|
||||
|
||||
$oToolbarButtons = ToolbarUIBlockFactory::MakeStandard(null);
|
||||
$oToolbarButtons = ToolbarUIBlockFactory::MakeStandard(null);
|
||||
|
||||
$oCancelButton = ButtonUIBlockFactory::MakeForCancel();
|
||||
$oCancelButton->AddCSSClasses(['action', 'cancel']);
|
||||
$oToolbarButtons->AddSubBlock($oCancelButton);
|
||||
$oApplyButton = ButtonUIBlockFactory::MakeForPrimaryAction($sApplyButton, null, null, true);
|
||||
$oApplyButton->AddCSSClass('action');
|
||||
$oToolbarButtons->AddSubBlock($oApplyButton);
|
||||
$bAreTransitionsHidden = isset($aExtraParams['hide_transitions']) && $aExtraParams['hide_transitions'] === true;
|
||||
$aTransitions = $this->EnumTransitions();
|
||||
if (!isset($aExtraParams['custom_operation']) && !$bAreTransitionsHidden && count($aTransitions)) {
|
||||
// Transitions are displayed only for the standard new/modify actions, not for modify_all or any other case...
|
||||
$oSetToCheckRights = DBObjectSet::FromObject($this);
|
||||
$oCancelButton = ButtonUIBlockFactory::MakeForCancel();
|
||||
$oCancelButton->AddCSSClasses(['action', 'cancel']);
|
||||
$oToolbarButtons->AddSubBlock($oCancelButton);
|
||||
$oApplyButton = ButtonUIBlockFactory::MakeForPrimaryAction($sApplyButton, null, null, true);
|
||||
$oApplyButton->AddCSSClass('action');
|
||||
$oToolbarButtons->AddSubBlock($oApplyButton);
|
||||
$bAreTransitionsHidden = isset($aExtraParams['hide_transitions']) && $aExtraParams['hide_transitions'] === true;
|
||||
$aTransitions = $this->EnumTransitions();
|
||||
if (!isset($aExtraParams['custom_operation']) && !$bAreTransitionsHidden && count($aTransitions)) {
|
||||
// Transitions are displayed only for the standard new/modify actions, not for modify_all or any other case...
|
||||
$oSetToCheckRights = DBObjectSet::FromObject($this);
|
||||
|
||||
$oTransitionPopoverMenu = new PopoverMenu();
|
||||
$sTPMSectionId = 'transitions';
|
||||
$oTransitionPopoverMenu->AddSection($sTPMSectionId);
|
||||
$aStimuli = Metamodel::EnumStimuli($sClass);
|
||||
foreach ($aTransitions as $sStimulusCode => $aTransitionDef) {
|
||||
$iActionAllowed = (get_class($aStimuli[$sStimulusCode]) == 'StimulusUserAction') ? UserRights::IsStimulusAllowed($sClass,
|
||||
$sStimulusCode, $oSetToCheckRights) : UR_ALLOWED_NO;
|
||||
switch ($iActionAllowed) {
|
||||
case UR_ALLOWED_YES:
|
||||
// Button to be displayed on its own on large screens
|
||||
$oButton = ButtonUIBlockFactory::MakeForPrimaryAction($aStimuli[$sStimulusCode]->GetLabel(), 'next_action', $sStimulusCode, true);
|
||||
$oButton->AddCSSClass('action');
|
||||
$oButton->SetColor(Button::ENUM_COLOR_SCHEME_NEUTRAL);
|
||||
$oToolbarButtons->AddSubBlock($oButton);
|
||||
$oTransitionPopoverMenu = new PopoverMenu();
|
||||
$sTPMSectionId = 'transitions';
|
||||
$oTransitionPopoverMenu->AddSection($sTPMSectionId);
|
||||
$aStimuli = Metamodel::EnumStimuli($sClass);
|
||||
foreach ($aTransitions as $sStimulusCode => $aTransitionDef) {
|
||||
$iActionAllowed = (get_class($aStimuli[$sStimulusCode]) == 'StimulusUserAction') ? UserRights::IsStimulusAllowed($sClass,
|
||||
$sStimulusCode, $oSetToCheckRights) : UR_ALLOWED_NO;
|
||||
switch ($iActionAllowed) {
|
||||
case UR_ALLOWED_YES:
|
||||
// Button to be displayed on its own on large screens
|
||||
$oButton = ButtonUIBlockFactory::MakeForPrimaryAction($aStimuli[$sStimulusCode]->GetLabel(), 'next_action', $sStimulusCode, true);
|
||||
$oButton->AddCSSClass('action');
|
||||
$oButton->SetColor(Button::ENUM_COLOR_SCHEME_NEUTRAL);
|
||||
$oToolbarButtons->AddSubBlock($oButton);
|
||||
|
||||
// Button to be displayed in a grouped button on smaller screens
|
||||
$oTPMPopupMenuItem = new JSPopupMenuItem('next_action--'.$oButton->GetId(), $oButton->GetLabel(), "$(`#{$oButton->GetId()}`).trigger(`click`);");
|
||||
@@ -2963,7 +2949,8 @@ JS
|
||||
}
|
||||
|
||||
// Prepare blocker protection to avoid loosing data
|
||||
$sBlockerId = $sClass.':'.$iKey; // Important: This must have the synthax format as in js/layouts/activity-panel/activity-panel.js
|
||||
$sBlockerId = uniqid($sClass.':'.$iKey.':', true);
|
||||
$sConfirmationMessage = addslashes(Dict::S('UI:NavigateAwayConfirmationMessage'));
|
||||
$sJSToken = json_encode($sOwnershipToken);
|
||||
$oPage->add_ready_script(<<<JS
|
||||
// Try to release concurrent lock when leaving the page
|
||||
@@ -3020,7 +3007,7 @@ JS
|
||||
$oToolbarButtons->AddCSSClass('ibo-toolbar-top');
|
||||
$oObjectDetails->AddToolbarBlock($oToolbarButtons);
|
||||
// Allow form title customization
|
||||
if (array_key_exists('form_title', $aExtraParams) && $aExtraParams['form_title'] !== null) {
|
||||
if (array_key_exists('form_title', $aExtraParams)) {
|
||||
$oObjectDetails->SetTitle($aExtraParams['form_title']);
|
||||
}
|
||||
}
|
||||
@@ -3063,21 +3050,16 @@ JS
|
||||
|
||||
$oPage->SetCurrentTab('');
|
||||
|
||||
// Static fields values for wizard helper serialization
|
||||
$aWizardHelperStaticValues = [];
|
||||
|
||||
// Add as hidden inputs values that we want displayed if they're readonly
|
||||
if(isset($aExtraParams['forceFieldsSubmission'])){
|
||||
$aExtraFlags = $aExtraParams['fieldsFlags'] ?? [];
|
||||
foreach ($aExtraParams['forceFieldsSubmission'] as $sAttCode) {
|
||||
if(FormHelper::GetAttributeFlagsForObject($this, $sAttCode, $aExtraFlags) & OPT_ATT_READONLY) {
|
||||
$oForm->AddSubBlock(InputUIBlockFactory::MakeForHidden('attr_'.$sPrefix.$sAttCode, $this->Get($sAttCode)));
|
||||
$aWizardHelperStaticValues[$sAttCode] = $this->Get($sAttCode);
|
||||
}
|
||||
}
|
||||
}
|
||||
$sWizardHelperStaticValues = json_encode($aWizardHelperStaticValues);
|
||||
|
||||
|
||||
$oForm->AddSubBlock(InputUIBlockFactory::MakeForHidden('class', $sClass));
|
||||
$oForm->AddSubBlock(InputUIBlockFactory::MakeForHidden('transaction_id', $iTransactionId));
|
||||
foreach ($aExtraParams as $sName => $value) {
|
||||
@@ -3104,10 +3086,7 @@ JS
|
||||
|
||||
$iFieldsCount = count($aFieldsMap);
|
||||
$sJsonFieldsMap = json_encode($aFieldsMap);
|
||||
$sLifecycleStateForWizardHelper = '';
|
||||
if (MetaModel::HasLifecycle($sClass)) {
|
||||
$sLifecycleStateForWizardHelper = $this->GetState();
|
||||
}
|
||||
$sState = $this->GetState();
|
||||
$sSessionStorageKey = $sClass.'_'.$iKey;
|
||||
$sTempId = utils::GetUploadTempId($iTransactionId);
|
||||
$oPage->add_ready_script(InlineImage::EnableCKEditorImageUpload($this, $sTempId));
|
||||
@@ -3117,10 +3096,9 @@ JS
|
||||
sessionStorage.removeItem('$sSessionStorageKey');
|
||||
|
||||
// Create the object once at the beginning of the page...
|
||||
var oWizardHelper$sPrefix = new WizardHelper('$sClass', '$sPrefix', '$sLifecycleStateForWizardHelper');
|
||||
var oWizardHelper$sPrefix = new WizardHelper('$sClass', '$sPrefix', '$sState');
|
||||
oWizardHelper$sPrefix.SetFieldsMap($sJsonFieldsMap);
|
||||
oWizardHelper$sPrefix.SetFieldsCount($iFieldsCount);
|
||||
oWizardHelper$sPrefix.SetStaticValues($sWizardHelperStaticValues);
|
||||
EOF
|
||||
);
|
||||
$oPage->add_ready_script(
|
||||
@@ -3157,7 +3135,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 +3230,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 +3315,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
|
||||
@@ -3412,15 +3390,22 @@ EOF
|
||||
];
|
||||
|
||||
// The list of candidate fields is made of the ordered list of "details" attributes + other attributes
|
||||
// First attributes from the "details" zlist as they were sorted...
|
||||
$aList = $this->FlattenZList(MetaModel::GetZListItems($sClass, 'details'));
|
||||
|
||||
// ... then append forgotten attributes
|
||||
$aAttributes = array();
|
||||
foreach ($this->FlattenZList(MetaModel::GetZListItems($sClass, 'details')) as $sAttCode) {
|
||||
$aAttributes[$sAttCode] = true;
|
||||
}
|
||||
foreach (MetaModel::GetAttributesList($sClass) as $sAttCode) {
|
||||
if (!in_array($sAttCode, $aList)) {
|
||||
$aList[] = $sAttCode;
|
||||
if (!array_key_exists($sAttCode, $aAttributes)) {
|
||||
$aAttributes[$sAttCode] = true;
|
||||
}
|
||||
}
|
||||
// Order the fields based on their dependencies, set the fields for which there is only one possible value
|
||||
// and perform this in the order of dependencies to avoid dead-ends
|
||||
$aDeps = array();
|
||||
foreach ($aAttributes as $sAttCode => $trash) {
|
||||
$aDeps[$sAttCode] = MetaModel::GetPrerequisiteAttributes($sClass, $sAttCode);
|
||||
}
|
||||
$aList = $this->OrderDependentFields($aDeps);
|
||||
|
||||
$bExistFieldToDisplay = false;
|
||||
foreach ($aList as $sAttCode) {
|
||||
@@ -3592,26 +3577,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 +3700,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 +3735,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
|
||||
@@ -4543,12 +4518,16 @@ HTML;
|
||||
*/
|
||||
public function DBInsertNoReload()
|
||||
{
|
||||
$this->LogCRUDEnter(__METHOD__);
|
||||
try {
|
||||
$res = parent::DBInsertNoReload();
|
||||
|
||||
$this->SetWarningsAsSessionMessages('create');
|
||||
|
||||
// Invoke extensions after insertion (the object must exist, have an id, etc.)
|
||||
/** @var \iApplicationObjectExtension $oExtensionInstance */
|
||||
foreach (MetaModel::EnumPlugins('iApplicationObjectExtension') as $oExtensionInstance) {
|
||||
$oExtensionInstance->OnDBInsert($this, self::GetCurrentChange());
|
||||
}
|
||||
} finally {
|
||||
if (static::IsCrudStackEmpty()) {
|
||||
// Avoid signaling the current object that links were modified
|
||||
@@ -4556,25 +4535,9 @@ HTML;
|
||||
static::FireEventDbLinksChangedForAllObjects();
|
||||
}
|
||||
}
|
||||
$this->LogCRUDExit(__METHOD__);
|
||||
return $res;
|
||||
}
|
||||
|
||||
protected function PostInsertActions(): void
|
||||
{
|
||||
parent::PostInsertActions();
|
||||
|
||||
// Invoke extensions after insertion (the object must exist, have an id, etc.)
|
||||
/** @var \iApplicationObjectExtension $oExtensionInstance */
|
||||
foreach (MetaModel::EnumPlugins(iApplicationObjectExtension::class) as $oExtensionInstance) {
|
||||
$sExtensionClass = get_class($oExtensionInstance);
|
||||
$this->LogCRUDDebug(__METHOD__, "Calling $sExtensionClass::OnDBInsert()");
|
||||
$oKPI = new ExecutionKPI();
|
||||
$oExtensionInstance->OnDBInsert($this, self::GetCurrentChange());
|
||||
$oKPI->ComputeStatsForExtension($oExtensionInstance, 'OnDBInsert');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
* Attaches InlineImages to the current object
|
||||
@@ -4584,21 +4547,15 @@ 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 */
|
||||
$oNewObj = MetaModel::GetObject(get_class($this), parent::DBCloneTracked_Internal($newKey));
|
||||
$oNewObj = parent::DBCloneTracked_Internal($newKey);
|
||||
|
||||
// Invoke extensions after insertion (the object must exist, have an id, etc.)
|
||||
/** @var \iApplicationObjectExtension $oExtensionInstance */
|
||||
foreach(MetaModel::EnumPlugins('iApplicationObjectExtension') as $oExtensionInstance)
|
||||
{
|
||||
$oKPI = new ExecutionKPI();
|
||||
$oExtensionInstance->OnDBInsert($oNewObj, self::GetCurrentChange());
|
||||
$oKPI->ComputeStatsForExtension($oExtensionInstance, 'OnDBInsert');
|
||||
}
|
||||
|
||||
return $oNewObj;
|
||||
@@ -4606,42 +4563,57 @@ HTML;
|
||||
|
||||
public function DBUpdate()
|
||||
{
|
||||
$this->LogCRUDEnter(__METHOD__);
|
||||
$res = 0;
|
||||
|
||||
try {
|
||||
if (count($this->ListChanges()) === 0) {
|
||||
$this->LogCRUDExit(__METHOD__);
|
||||
return $this->GetKey();
|
||||
}
|
||||
$res = parent::DBUpdate();
|
||||
|
||||
$this->SetWarningsAsSessionMessages('update');
|
||||
|
||||
// Protection against reentrance (e.g. cascading the update of ticket logs)
|
||||
// Note: This is based on the fix made on r 3190 in DBObject::DBUpdate()
|
||||
if (!MetaModel::StartReentranceProtection($this)) {
|
||||
$sClass = get_class($this);
|
||||
$sKey = $this->GetKey();
|
||||
IssueLog::Debug("CRUD: DBUpdate $sClass::$sKey Rejected (reentrance)", LogChannels::DM_CRUD);
|
||||
|
||||
return $res;
|
||||
}
|
||||
|
||||
try {
|
||||
// Invoke extensions after the update (could be before)
|
||||
/** @var \iApplicationObjectExtension $oExtensionInstance */
|
||||
foreach (MetaModel::EnumPlugins('iApplicationObjectExtension') as $oExtensionInstance) {
|
||||
$oExtensionInstance->OnDBUpdate($this, self::GetCurrentChange());
|
||||
}
|
||||
}
|
||||
finally {
|
||||
MetaModel::StopReentranceProtection($this);
|
||||
}
|
||||
|
||||
$aChanges = $this->ListChanges();
|
||||
if (count($aChanges) != 0) {
|
||||
$this->iUpdateLoopCount++;
|
||||
if ($this->iUpdateLoopCount > self::MAX_UPDATE_LOOP_COUNT) {
|
||||
$sClass = get_class($this);
|
||||
$sKey = $this->GetKey();
|
||||
$aPlugins = [];
|
||||
foreach (MetaModel::EnumPlugins('iApplicationObjectExtension') as $oExtensionInstance) {
|
||||
$aPlugins[] = get_class($oExtensionInstance);
|
||||
}
|
||||
$sPlugins = implode(', ', $aPlugins);
|
||||
IssueLog::Error("CRUD: DBUpdate $sClass::$sKey Update loop detected plugins: $sPlugins", LogChannels::DM_CRUD);
|
||||
} else {
|
||||
return $this->DBUpdate();
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
if (static::IsCrudStackEmpty()) {
|
||||
static::FireEventDbLinksChangedForAllObjects();
|
||||
}
|
||||
}
|
||||
$this->LogCRUDExit(__METHOD__);
|
||||
|
||||
return $res;
|
||||
}
|
||||
|
||||
protected function PostUpdateActions(array $aChanges): void
|
||||
{
|
||||
parent::PostUpdateActions($aChanges);
|
||||
|
||||
// Invoke extensions after the update (could be before)
|
||||
/** @var \iApplicationObjectExtension $oExtensionInstance */
|
||||
foreach (MetaModel::EnumPlugins(iApplicationObjectExtension::class) as $oExtensionInstance) {
|
||||
$sExtensionClass = get_class($oExtensionInstance);
|
||||
$this->LogCRUDDebug(__METHOD__, "Calling $sExtensionClass::OnDBUpdate()");
|
||||
$oKPI = new ExecutionKPI();
|
||||
$oExtensionInstance->OnDBUpdate($this, self::GetCurrentChange());
|
||||
$oKPI->ComputeStatsForExtension($oExtensionInstance, 'OnDBUpdate');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $sMessageIdPrefix
|
||||
*
|
||||
@@ -4661,39 +4633,26 @@ HTML;
|
||||
|
||||
public function DBDelete(&$oDeletionPlan = null)
|
||||
{
|
||||
$this->LogCRUDEnter(__METHOD__);
|
||||
try {
|
||||
parent::DBDelete($oDeletionPlan);
|
||||
} finally {
|
||||
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();
|
||||
}
|
||||
}
|
||||
$this->LogCRUDExit(__METHOD__);
|
||||
|
||||
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 */
|
||||
foreach(MetaModel::EnumPlugins('iApplicationObjectExtension') as $oExtensionInstance)
|
||||
{
|
||||
$oKPI = new ExecutionKPI();
|
||||
$oExtensionInstance->OnDBDelete($this, self::GetCurrentChange());
|
||||
$oKPI->ComputeStatsForExtension($oExtensionInstance, 'OnDBDelete');
|
||||
}
|
||||
|
||||
return parent::DBDeleteTracked_Internal($oDeletionPlan);
|
||||
@@ -4711,15 +4670,9 @@ HTML;
|
||||
/** @var \iApplicationObjectExtension $oExtensionInstance */
|
||||
foreach(MetaModel::EnumPlugins('iApplicationObjectExtension') as $oExtensionInstance)
|
||||
{
|
||||
$sExtensionClass = get_class($oExtensionInstance);
|
||||
$oKPI = new ExecutionKPI();
|
||||
$bIsModified = $oExtensionInstance->OnIsModified($this);
|
||||
$oKPI->ComputeStatsForExtension($oExtensionInstance, 'OnIsModified');
|
||||
if ($bIsModified) {
|
||||
$this->LogCRUDDebug(__METHOD__, "Calling $sExtensionClass::OnIsModified() -> true");
|
||||
if ($oExtensionInstance->OnIsModified($this))
|
||||
{
|
||||
return true;
|
||||
} else {
|
||||
$this->LogCRUDDebug(__METHOD__, "Calling $sExtensionClass::OnIsModified() -> false");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4771,9 +4724,7 @@ HTML;
|
||||
/** @var \iApplicationObjectExtension $oExtensionInstance */
|
||||
foreach(MetaModel::EnumPlugins('iApplicationObjectExtension') as $oExtensionInstance)
|
||||
{
|
||||
$oKPI = new ExecutionKPI();
|
||||
$aNewIssues = $oExtensionInstance->OnCheckToWrite($this);
|
||||
$oKPI->ComputeStatsForExtension($oExtensionInstance, 'OnCheckToWrite');
|
||||
if (is_array($aNewIssues) && (count($aNewIssues) > 0)) // Some extensions return null instead of an empty array
|
||||
{
|
||||
$this->m_aCheckIssues = array_merge($this->m_aCheckIssues, $aNewIssues);
|
||||
@@ -4821,9 +4772,7 @@ HTML;
|
||||
/** @var \iApplicationObjectExtension $oExtensionInstance */
|
||||
foreach(MetaModel::EnumPlugins('iApplicationObjectExtension') as $oExtensionInstance)
|
||||
{
|
||||
$oKPI = new ExecutionKPI();
|
||||
$aNewIssues = $oExtensionInstance->OnCheckToDelete($this);
|
||||
$oKPI->ComputeStatsForExtension($oExtensionInstance, 'OnCheckToDelete');
|
||||
if (is_array($aNewIssues) && count($aNewIssues) > 0)
|
||||
{
|
||||
$this->m_aDeleteIssues = array_merge($this->m_aDeleteIssues, $aNewIssues);
|
||||
@@ -4848,7 +4797,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 +4901,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 +5026,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 +5270,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 +5326,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 +5343,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 +5405,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
|
||||
@@ -5927,28 +5871,39 @@ JS
|
||||
*/
|
||||
final protected function FireEventCheckToWrite(): void
|
||||
{
|
||||
$this->FireEvent(EVENT_DB_CHECK_TO_WRITE, ['is_new' => $this->IsNew()]);
|
||||
}
|
||||
|
||||
final protected function FireEventBeforeWrite()
|
||||
{
|
||||
$this->FireEvent(EVENT_DB_BEFORE_WRITE, ['is_new' => $this->IsNew()]);
|
||||
$this->FireEvent(EVENT_DB_CHECK_TO_WRITE);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
* @throws \CoreException
|
||||
*
|
||||
* @since 3.1.0
|
||||
*/
|
||||
final protected function FireEventCreateDone(): void
|
||||
{
|
||||
$this->NotifyAttachedObjectsOnLinkClassModification();
|
||||
$this->FireEventDbLinksChangedForCurrentObject();
|
||||
$this->FireEvent(EVENT_DB_CREATE_DONE);
|
||||
}
|
||||
|
||||
/////////////
|
||||
/// UPDATE
|
||||
///
|
||||
|
||||
/**
|
||||
* @param array $aChanges
|
||||
* @param bool $bIsNew
|
||||
*
|
||||
* @return void
|
||||
* @throws \ArchivedObjectException
|
||||
* @throws \CoreException
|
||||
* @since 3.1.0
|
||||
*/
|
||||
final protected function FireEventAfterWrite(array $aChanges, bool $bIsNew): void
|
||||
final protected function FireEventUpdateDone(array $aChanges): void
|
||||
{
|
||||
$this->NotifyAttachedObjectsOnLinkClassModification();
|
||||
$this->FireEventDbLinksChangedForCurrentObject();
|
||||
$this->FireEvent(EVENT_DB_AFTER_WRITE, ['is_new' => $bIsNew, 'changes' => $aChanges]);
|
||||
$this->FireEvent(EVENT_DB_UPDATE_DONE, ['changes' => $aChanges]);
|
||||
}
|
||||
|
||||
//////////////
|
||||
@@ -5967,82 +5922,56 @@ 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
|
||||
*
|
||||
* @since 3.1.0
|
||||
*/
|
||||
final protected function FireEventAfterDelete(): void
|
||||
final protected function FireEventDeleteDone(): void
|
||||
{
|
||||
$this->NotifyAttachedObjectsOnLinkClassModification();
|
||||
$this->FireEvent(EVENT_DB_AFTER_DELETE);
|
||||
$this->FireEventDbLinksChangedForCurrentObject();
|
||||
$this->FireEvent(EVENT_DB_DELETE_DONE);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 +6006,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);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -6113,23 +6037,16 @@ JS
|
||||
// - we have a EVENT_DB_LINKS_CHANGED listener on Ticket that will update impacted items, so it will create new lnkApplicationSolutionToFunctionalCI
|
||||
// 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)
|
||||
{
|
||||
/** @noinspection PhpRedundantOptionalArgumentInspection */
|
||||
$oObject = MetaModel::GetObject($sClass, $sId, true);
|
||||
self::SetEventDBLinksChangedBlocked(true);
|
||||
// N°6408 The object can have been deleted
|
||||
if (!is_null($oObject)) {
|
||||
MetaModel::StartReentranceProtection($oObject);
|
||||
$oObject->FireEvent(EVENT_DB_LINKS_CHANGED);
|
||||
MetaModel::StopReentranceProtection($oObject);
|
||||
if (count($oObject->ListChanges()) !== 0) {
|
||||
$oObject->DBUpdate();
|
||||
}
|
||||
MetaModel::StartReentranceProtection($oObject);
|
||||
$oObject->FireEvent(EVENT_DB_LINKS_CHANGED);
|
||||
MetaModel::StopReentranceProtection($oObject);
|
||||
if ($oObject->IsModified()) {
|
||||
$oObject->DBUpdate();
|
||||
}
|
||||
self::RemoveObjectAwaitingEventDbLinksChanged($sClass, $sId);
|
||||
cmdbAbstractObject::SetEventDBLinksChangedBlocked(false);
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
*/
|
||||
|
||||
@@ -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,11 +918,6 @@ class RuntimeDashboard extends Dashboard
|
||||
{
|
||||
$bCustomized = false;
|
||||
|
||||
$sDashboardFileSanitized = utils::RealPath(APPROOT.$sDashboardFile, APPROOT);
|
||||
if (false === $sDashboardFileSanitized) {
|
||||
throw new SecurityException('Invalid dashboard file !');
|
||||
}
|
||||
|
||||
// Search for an eventual user defined dashboard
|
||||
$oUDSearch = new DBObjectSearch('UserDashboard');
|
||||
$oUDSearch->AddCondition('user_id', UserRights::GetUserId(), '=');
|
||||
@@ -936,7 +929,7 @@ class RuntimeDashboard extends Dashboard
|
||||
$sDashboardDefinition = $oUserDashboard->Get('contents');
|
||||
$bCustomized = true;
|
||||
} else {
|
||||
$sDashboardDefinition = @file_get_contents($sDashboardFileSanitized);
|
||||
$sDashboardDefinition = @file_get_contents($sDashboardFile);
|
||||
}
|
||||
|
||||
|
||||
@@ -944,7 +937,7 @@ class RuntimeDashboard extends Dashboard
|
||||
$oDashboard = new RuntimeDashboard($sDashBoardId);
|
||||
$oDashboard->FromXml($sDashboardDefinition);
|
||||
$oDashboard->SetCustomFlag($bCustomized);
|
||||
$oDashboard->SetDefinitionFile($sDashboardFileSanitized);
|
||||
$oDashboard->SetDefinitionFile($sDashboardFile);
|
||||
} else {
|
||||
$oDashboard = null;
|
||||
}
|
||||
@@ -1111,7 +1104,7 @@ JS
|
||||
}
|
||||
|
||||
/**
|
||||
* @param WebPage $oPage
|
||||
* @param \WebPage $oPage
|
||||
* @param array $aExtraParams
|
||||
*
|
||||
* @throws \Exception
|
||||
@@ -1143,7 +1136,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 +1223,7 @@ EOF
|
||||
|
||||
|
||||
/**
|
||||
* @param WebPage $oPage
|
||||
* @param \WebPage $oPage
|
||||
*
|
||||
* @param array $aExtraParams
|
||||
*
|
||||
@@ -1266,12 +1259,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 +1483,7 @@ JS
|
||||
}
|
||||
|
||||
/**
|
||||
* @param WebPage $oPage
|
||||
* @param \WebPage $oPage
|
||||
* @param $sOQL
|
||||
*
|
||||
* @throws \DictExceptionMissingString
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
*
|
||||
@@ -668,7 +667,7 @@ class DashletUnknown extends Dashlet
|
||||
*/
|
||||
public function GetPropertiesFields(DesignerForm $oForm)
|
||||
{
|
||||
$oField = new DesignerXMLField('xml', Dict::S('UI:DashletUnknown:Prop-XMLConfiguration'), $this->sOriginalDashletXML);
|
||||
$oField = new DesignerLongTextField('xml', Dict::S('UI:DashletUnknown:Prop-XMLConfiguration'), $this->sOriginalDashletXML);
|
||||
$oForm->AddField($oField);
|
||||
}
|
||||
|
||||
@@ -870,7 +869,7 @@ class DashletPlainText extends Dashlet
|
||||
public function Render($oPage, $bEditMode = false, $aExtraParams = array())
|
||||
{
|
||||
$sText = $this->aProperties['text'];
|
||||
$sText = utils::EscapeHtml(Dict::S($sText));
|
||||
$sText = utils::EscapeHtml($sText);
|
||||
$sText = str_replace(array("\r\n", "\n", "\r"), "<br/>", $sText);
|
||||
|
||||
$sId = 'plaintext_'.($bEditMode ? 'edit_' : '').$this->sId;
|
||||
|
||||
@@ -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>
|
||||
@@ -186,27 +186,6 @@
|
||||
</menu>
|
||||
</menus>
|
||||
<events>
|
||||
<event id="EVENT_DB_BEFORE_WRITE" _delta="define">
|
||||
<description>An object is about to be written into the database. The object can be modified.</description>
|
||||
<sources>
|
||||
<source id="cmdbAbstractObject">cmdbAbstractObject</source>
|
||||
</sources>
|
||||
<replaces>DBObject::OnInsert</replaces>
|
||||
<event_data>
|
||||
<event_datum id="object">
|
||||
<description>The object inserted</description>
|
||||
<type>DBObject</type>
|
||||
</event_datum>
|
||||
<event_datum id="is_new">
|
||||
<description>Creation flag</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_CHECK_TO_WRITE" _delta="define">
|
||||
<description>Check an object before it is written into the database (no change possible). Call DBObject::AddCheckIssue() to signal an issue</description>
|
||||
<sources>
|
||||
@@ -218,18 +197,14 @@
|
||||
<description>The object to check</description>
|
||||
<type>DBObject</type>
|
||||
</event_datum>
|
||||
<event_datum id="is_new">
|
||||
<description>Creation flag</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_WRITE" _delta="define">
|
||||
<description>An object has been written into the database. The modifications can be propagated to other objects.</description>
|
||||
<event id="EVENT_DB_CREATE_DONE" _delta="define">
|
||||
<description>An object has been created into the database. The modifications can be propagated to other objects.</description>
|
||||
<sources>
|
||||
<source id="cmdbAbstractObject">cmdbAbstractObject</source>
|
||||
</sources>
|
||||
@@ -239,13 +214,22 @@
|
||||
<description>The object inserted</description>
|
||||
<type>DBObject</type>
|
||||
</event_datum>
|
||||
<event_datum id="is_new">
|
||||
<description>Creation flag</description>
|
||||
<type>boolean</type>
|
||||
<event_datum id="debug_info">
|
||||
<description>Debug string</description>
|
||||
<type>string</type>
|
||||
</event_datum>
|
||||
<event_datum id="changes">
|
||||
<description>For updates, the list of changes done during this operation</description>
|
||||
<type>array</type>
|
||||
</event_data>
|
||||
</event>
|
||||
<event id="EVENT_DB_UPDATE_DONE" _delta="define">
|
||||
<description>An object has been updated into the database and reloaded.</description>
|
||||
<sources>
|
||||
<source id="cmdbAbstractObject">cmdbAbstractObject</source>
|
||||
</sources>
|
||||
<replaces>DBObject::AfterUpdate</replaces>
|
||||
<event_data>
|
||||
<event_datum id="object">
|
||||
<description>The object updated</description>
|
||||
<type>DBObject</type>
|
||||
</event_datum>
|
||||
<event_datum id="debug_info">
|
||||
<description>Debug string</description>
|
||||
@@ -270,24 +254,7 @@
|
||||
</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">
|
||||
<event id="EVENT_DB_DELETE_DONE" _delta="define">
|
||||
<description>An object has been deleted into the database</description>
|
||||
<sources>
|
||||
<source id="cmdbAbstractObject">cmdbAbstractObject</source>
|
||||
@@ -304,8 +271,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 +281,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 +498,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>
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -1085,7 +1083,6 @@ JS
|
||||
$this->m_oSet = new CMDBObjectSet($this->m_oFilter, array(), $aQueryParams);
|
||||
$this->m_oSet->SetShowObsoleteData($this->m_bShowObsoleteData);
|
||||
}
|
||||
|
||||
// Summary details
|
||||
$aCounts = array();
|
||||
$aStateLabels = array();
|
||||
@@ -1132,18 +1129,6 @@ JS
|
||||
}
|
||||
|
||||
$oBlock = new UIContentBlockWithJSRefreshCallback(null, ["ibo-dashlet-header-dynamic--container"]);
|
||||
|
||||
// N°6394 Make sure to sort elements as defined in the datamodel
|
||||
if (utils::IsNotNullOrEmptyString($sStateAttrCode)) {
|
||||
$oAttDef = MetaModel::GetAttributeDef($sClass, $sStateAttrCode);
|
||||
$aAllowedValues = $oAttDef->GetAllowedValues() ?? [];
|
||||
$AllowedValuesKeys = array_keys($aAllowedValues);
|
||||
|
||||
uksort($aStateLabels, function ($sKey1, $sKey2) use ($AllowedValuesKeys) {
|
||||
return array_search($sKey1, $AllowedValuesKeys) > array_search($sKey2, $AllowedValuesKeys) ? 1 : -1;
|
||||
});
|
||||
}
|
||||
|
||||
foreach ($aStateLabels as $sStateValue => $sStateLabel) {
|
||||
$aCount = $aCounts[$sStateValue];
|
||||
$sHyperlink = $aCount['link'];
|
||||
@@ -1248,10 +1233,6 @@ JS
|
||||
} else {
|
||||
$oBlock = DashletFactory::MakeForDashletBadge($sClassIconUrl, $sHyperlink, $iCount, $sClassLabel, null, null, $aRefreshParams);
|
||||
}
|
||||
$sClassDescription = MetaModel::GetClassDescription($sClass);
|
||||
if (utils::IsNotNullOrEmptyString($sClassDescription)) {
|
||||
$oBlock->SetClassDescription($sClassDescription);
|
||||
}
|
||||
|
||||
return $oBlock;
|
||||
}
|
||||
@@ -1356,7 +1337,7 @@ JS
|
||||
}
|
||||
|
||||
/**
|
||||
* @param WebPage $oPage
|
||||
* @param \WebPage $oPage
|
||||
* @param array $aExtraParams
|
||||
*
|
||||
* @return \Combodo\iTop\Application\UI\Base\iUIBlock
|
||||
@@ -1380,7 +1361,7 @@ JS
|
||||
|
||||
/**
|
||||
* @param array $aExtraParams
|
||||
* @param WebPage $oPage
|
||||
* @param \WebPage $oPage
|
||||
*
|
||||
* @throws \ArchivedObjectException
|
||||
* @throws \ConfigException
|
||||
@@ -1458,7 +1439,7 @@ JS
|
||||
|
||||
/**
|
||||
* @param array $aExtraParams
|
||||
* @param WebPage $oPage
|
||||
* @param \WebPage $oPage
|
||||
*
|
||||
* @return \Combodo\iTop\Application\UI\Base\Layout\UIContentBlock
|
||||
* @throws \ApplicationException
|
||||
@@ -1566,7 +1547,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 +1647,7 @@ JS
|
||||
|
||||
/**
|
||||
* @param array $aExtraParams
|
||||
* @param WebPage $oPage
|
||||
* @param \WebPage $oPage
|
||||
*
|
||||
* @throws \ArchivedObjectException
|
||||
* @throws \CoreException
|
||||
@@ -1832,7 +1813,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
|
||||
*
|
||||
@@ -1877,13 +1858,7 @@ class MenuBlock extends DisplayBlock
|
||||
/** @var array $aToolkitActions Any "legacy" toolkit menu item, which are now displayed in the same menu as the $aRegularActions, after them */
|
||||
$aToolkitActions = [];
|
||||
|
||||
// Display menu actions only if...
|
||||
if (
|
||||
// ... NOT in a selection mode
|
||||
(!isset($aExtraParams['selection_mode']) || ($aExtraParams['selection_mode'] == ""))
|
||||
// ... "menu" parameter is NOT EXPLICITLY disabled
|
||||
&& (!isset($aExtraParams['menu']) || $aExtraParams['menu'] === "1" || $aExtraParams['menu'] === true)
|
||||
) {
|
||||
if (!isset($aExtraParams['selection_mode']) || ($aExtraParams['selection_mode'] == "")) {
|
||||
$oAppContext = new ApplicationContext();
|
||||
$sContext = $oAppContext->GetForLink();
|
||||
if (utils::IsNotNullOrEmptyString($sContext)) {
|
||||
@@ -2044,7 +2019,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) {
|
||||
@@ -2346,15 +2321,10 @@ class MenuBlock extends DisplayBlock
|
||||
false
|
||||
);
|
||||
|
||||
// creation form title
|
||||
if (array_key_exists('creation_in_modal_form_title', $aExtraParams) && $aExtraParams['creation_in_modal_form_title'] !== null) {
|
||||
$oAddLinkActionButton->AddDataAttribute('modal-title', $aExtraParams['creation_in_modal_form_title']);
|
||||
}
|
||||
|
||||
// - If we are used in a Datatable, 'datatable_' will be prefixed to our $sId, so we do the same here
|
||||
$sRealId = $sId;
|
||||
if (in_array($this->m_sStyle, [static::ENUM_STYLE_LIST, 'links', static::ENUM_STYLE_LIST_IN_OBJECT])) {
|
||||
$sRealId = 'datatable_'.$sId;
|
||||
if(in_array($this->m_sStyle, [static::ENUM_STYLE_LIST, 'links', static::ENUM_STYLE_LIST_IN_OBJECT])){
|
||||
$sRealId = 'datatable_' . $sId;
|
||||
}
|
||||
$oAddLinkActionButton->AddCSSClasses(['ibo-action-button', 'ibo-regular-action-button'])
|
||||
->SetOnClickJsCode("$('#$sRealId').trigger('open_creation_modal.object.itop');");
|
||||
|
||||
@@ -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
|
||||
*/
|
||||
|
||||
@@ -1,8 +1,4 @@
|
||||
<?php
|
||||
|
||||
use Combodo\iTop\Application\WebPage\CLIPage;
|
||||
use Combodo\iTop\Application\WebPage\Page;
|
||||
|
||||
require_once('xlsxwriter.class.php');
|
||||
|
||||
class ExcelExporter
|
||||
|
||||
@@ -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];
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
*
|
||||
@@ -1111,41 +1110,13 @@ $('#$sId').on('change keyup validate', function() { ValidateWithPattern('$sId',
|
||||
}
|
||||
EOF
|
||||
);
|
||||
$sValue = "<textarea $sCSSClasses id=\"$sId\" name=\"$sName\">".$this->PrepareValueForRendering()."</textarea>";
|
||||
$sValue = "<textarea $sCSSClasses id=\"$sId\" name=\"$sName\">".utils::EscapeHtml($this->defaultValue)."</textarea>";
|
||||
}
|
||||
else {
|
||||
$sValue = "<div $sCSSClasses id=\"$sId\">".$this->PrepareValueForRendering()."</div>";
|
||||
$sValue = "<div $sCSSClasses id=\"$sId\">".utils::EscapeHtml($this->defaultValue)."</div>";
|
||||
}
|
||||
return array('label' => $this->sLabel, 'value' => $sValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string|null The value itself as expected for rendering. May it be encoded, escaped or else.
|
||||
* @since 3.1.0 N°6405
|
||||
*/
|
||||
protected function PrepareValueForRendering(): ?string
|
||||
{
|
||||
return utils::EscapeHtml($this->defaultValue);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Class DesignerXMLField
|
||||
*
|
||||
* Field to display XML content
|
||||
*
|
||||
* @author Guillaume Lajarige <guillaume.lajarige@combodo.com>
|
||||
* @since 3.1.0 N°6405
|
||||
*/
|
||||
class DesignerXMLField extends DesignerLongTextField
|
||||
{
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
protected function PrepareValueForRendering(): ?string
|
||||
{
|
||||
return utils::EscapeHtml($this->defaultValue, true);
|
||||
}
|
||||
}
|
||||
|
||||
class DesignerIntegerField extends DesignerFormField
|
||||
|
||||
@@ -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
|
||||
*/
|
||||
|
||||
@@ -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
|
||||
*/
|
||||
|
||||
@@ -80,11 +80,6 @@ class LoginBasic extends AbstractLoginFSMExtension
|
||||
{
|
||||
if (Session::Get('login_mode') == 'basic')
|
||||
{
|
||||
$iOnExit = LoginWebPage::getIOnExit();
|
||||
if ($iOnExit === LoginWebPage::EXIT_RETURN)
|
||||
{
|
||||
return LoginWebPage::LOGIN_FSM_RETURN; // Error, exit FSM
|
||||
}
|
||||
LoginWebPage::HTTP401Error();
|
||||
}
|
||||
return LoginWebPage::LOGIN_FSM_CONTINUE;
|
||||
|
||||
@@ -79,7 +79,7 @@ class LoginDefaultAfter extends AbstractLoginFSMExtension implements iLogoutExte
|
||||
{
|
||||
self::ResetLoginSession();
|
||||
$iOnExit = LoginWebPage::getIOnExit();
|
||||
if ($iOnExit === LoginWebPage::EXIT_RETURN)
|
||||
if ($iOnExit == LoginWebPage::EXIT_RETURN)
|
||||
{
|
||||
return LoginWebPage::LOGIN_FSM_RETURN; // Error, exit FSM
|
||||
}
|
||||
@@ -95,12 +95,6 @@ class LoginDefaultAfter extends AbstractLoginFSMExtension implements iLogoutExte
|
||||
{
|
||||
if (!Session::IsSet('login_mode'))
|
||||
{
|
||||
// N°6358 - if EXIT_RETURN was asked, send an error
|
||||
if (LoginWebPage::getIOnExit() === LoginWebPage::EXIT_RETURN) {
|
||||
$iErrorCode = LoginWebPage::EXIT_CODE_WRONGCREDENTIALS;
|
||||
return LoginWebPage::LOGIN_FSM_ERROR;
|
||||
}
|
||||
|
||||
// If no plugin validated the user, exit
|
||||
self::ResetLoginSession();
|
||||
exit();
|
||||
@@ -119,11 +113,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 +128,4 @@ class LoginDefaultAfter extends AbstractLoginFSMExtension implements iLogoutExte
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -73,11 +73,6 @@ class LoginExternal extends AbstractLoginFSMExtension
|
||||
{
|
||||
if (Session::Get('login_mode') == 'external')
|
||||
{
|
||||
$iOnExit = LoginWebPage::getIOnExit();
|
||||
if ($iOnExit === LoginWebPage::EXIT_RETURN)
|
||||
{
|
||||
return LoginWebPage::LOGIN_FSM_RETURN; // Error, exit FSM
|
||||
}
|
||||
LoginWebPage::HTTP401Error();
|
||||
}
|
||||
return LoginWebPage::LOGIN_FSM_CONTINUE;
|
||||
|
||||
@@ -44,10 +44,6 @@ class LoginForm extends AbstractLoginFSMExtension implements iLoginUIExtension
|
||||
exit;
|
||||
}
|
||||
|
||||
if (LoginWebPage::getIOnExit() === LoginWebPage::EXIT_RETURN) {
|
||||
return LoginWebPage::LOGIN_FSM_CONTINUE;
|
||||
}
|
||||
|
||||
// No credentials yet, display the form
|
||||
$oPage = LoginWebPage::NewLoginWebPage();
|
||||
$oPage->DisplayLoginForm($this->bForceFormOnError);
|
||||
@@ -140,11 +136,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,
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
@@ -403,11 +391,6 @@ class LoginWebPage extends NiceWebPage
|
||||
Session::Unset('can_logoff');
|
||||
Session::Unset('archive_mode');
|
||||
Session::Unset('impersonate_user');
|
||||
Session::Unset('PluginProperties');
|
||||
Session::Unset('UrlMakerClass');
|
||||
Session::Unset('itop_env');
|
||||
Session::Unset('obj_messages');
|
||||
Session::Unset('profile_list');
|
||||
UserRights::_ResetSessionCache();
|
||||
// If it's desired to kill the session, also delete the session cookie.
|
||||
// Note: This will destroy the session, and not just the session data!
|
||||
@@ -919,13 +902,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];
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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
|
||||
*/
|
||||
|
||||
@@ -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
|
||||
*/
|
||||
|
||||
@@ -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
|
||||
{
|
||||
@@ -75,7 +74,6 @@ abstract class Query extends cmdbAbstractObject
|
||||
"default_value" => 0,
|
||||
"is_null_allowed" => false,
|
||||
"depends_on" => array(),
|
||||
"tracking_level" => ATTRIBUTE_TRACKING_NONE,
|
||||
)));
|
||||
|
||||
MetaModel::Init_AddAttribute(new AttributeDateTime("export_last_date", array(
|
||||
@@ -84,7 +82,6 @@ abstract class Query extends cmdbAbstractObject
|
||||
"default_value" => null,
|
||||
"is_null_allowed" => true,
|
||||
"depends_on" => array(),
|
||||
"tracking_level" => ATTRIBUTE_TRACKING_NONE,
|
||||
)));
|
||||
|
||||
MetaModel::Init_AddAttribute(new AttributeExternalKey("export_last_user_id",
|
||||
@@ -96,16 +93,14 @@ abstract class Query extends cmdbAbstractObject
|
||||
"depends_on"=>array(),
|
||||
"display_style"=>'select',
|
||||
"always_load_in_tables"=>false,
|
||||
"on_target_delete"=>DEL_SILENT,
|
||||
"tracking_level" => ATTRIBUTE_TRACKING_NONE,
|
||||
"on_target_delete"=>DEL_SILENT
|
||||
)));
|
||||
|
||||
MetaModel::Init_AddAttribute(new AttributeExternalField("export_last_user_contact",
|
||||
array(
|
||||
"allowed_values"=>null,
|
||||
"extkey_attcode"=> "export_last_user_id",
|
||||
"target_attcode"=>"contactid",
|
||||
"tracking_level" => ATTRIBUTE_TRACKING_NONE,
|
||||
"target_attcode"=>"contactid"
|
||||
)));
|
||||
|
||||
// Display lists
|
||||
@@ -297,7 +292,7 @@ class QueryOQL extends Query
|
||||
}
|
||||
catch
|
||||
(OQLException $e) {
|
||||
$oAlert = AlertUIBlockFactory::MakeForFailure(Dict::S('UI:RunQuery:Error'), $e->getHtmlDesc())
|
||||
$oAlert = AlertUIBlockFactory::MakeForFailure(Dict::Format('UI:RunQuery:Error'), $e->getHtmlDesc())
|
||||
->SetIsClosable(false)
|
||||
->SetIsCollapsible(false);
|
||||
$oAlert->AddCSSClass('mb-5');
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
/**
|
||||
|
||||
@@ -15,7 +15,10 @@
|
||||
//
|
||||
// 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\EventRegister\ApplicationEvents;
|
||||
use Combodo\iTop\Application\Helper\Session;
|
||||
use Combodo\iTop\Service\Events\EventData;
|
||||
use Combodo\iTop\Service\Events\EventService;
|
||||
|
||||
require_once(APPROOT.'core/cmdbobject.class.inc.php');
|
||||
require_once(APPROOT.'application/utils.inc.php');
|
||||
@@ -99,10 +102,7 @@ else
|
||||
Session::Set('itop_env', ITOP_DEFAULT_ENV);
|
||||
}
|
||||
$sConfigFile = APPCONF.$sEnv.'/'.ITOP_CONFIG_FILE;
|
||||
try {
|
||||
MetaModel::Startup($sConfigFile, false /* $bModelOnly */, $bAllowCache, false /* $bTraceSourceFiles */, $sEnv);
|
||||
}
|
||||
catch (MySQLException $e) {
|
||||
IssueLog::Debug($e->getMessage());
|
||||
throw new MySQLException('Could not connect to the DB server', []);
|
||||
}
|
||||
MetaModel::Startup($sConfigFile, false /* $bModelOnly */, $bAllowCache, false /* $bTraceSourceFiles */, $sEnv);
|
||||
// Event service must be initialized after the MetaModel startup, otherwise it cannot discover classes implementing the iEventServiceSetup interface
|
||||
EventService::InitService();
|
||||
EventService::FireEvent(new EventData(ApplicationEvents::APPLICATION_EVENT_METAMODEL_STARTED));
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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,11 +163,13 @@ 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_';
|
||||
|
||||
|
||||
|
||||
$sFilter = addslashes($oAllowedValues->GetFilter()->ToOQL());
|
||||
if ($this->bSearchMode) {
|
||||
$sWizHelper = 'null';
|
||||
@@ -445,7 +446,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 +977,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>
|
||||
@@ -1073,27 +1070,18 @@ JS
|
||||
{
|
||||
$oObj = MetaModel::NewObject($this->sTargetClass);
|
||||
$aErrors = $oObj->UpdateObjectFromPostedForm($this->iId);
|
||||
if (count($aErrors) == 0) {
|
||||
|
||||
// Retrieve JSON data
|
||||
$sJSON = utils::ReadParam('json', '{}', false, utils::ENUM_SANITIZATION_FILTER_RAW_DATA);
|
||||
$oJSON = json_decode($sJSON);
|
||||
|
||||
$oObj->SetContextSection('temporary_objects', [
|
||||
'create' => [
|
||||
'transaction_id' => utils::ReadParam('root_transaction_id', '', false, utils::ENUM_SANITIZATION_FILTER_TRANSACTION_ID),
|
||||
'host_class' => $oJSON->m_sClass,
|
||||
'host_att_code' => $this->sAttCode,
|
||||
],
|
||||
]);
|
||||
$oObj->DBInsertNoReload();
|
||||
|
||||
if (count($aErrors) == 0)
|
||||
{
|
||||
$oObj->DBInsert();
|
||||
return array('name' => $oObj->GetName(), 'id' => $oObj->GetKey());
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
return array('error' => implode(' ', $aErrors), 'id' => 0);
|
||||
}
|
||||
}
|
||||
catch (Exception $e) {
|
||||
catch(Exception $e)
|
||||
{
|
||||
return array('error' => $e->getMessage(), 'id' => 0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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');
|
||||
@@ -180,18 +178,17 @@ class UILinksWidget
|
||||
|
||||
$oDisplayBlock = new DisplayBlock($oFilter, 'search', false);
|
||||
$oBlock->AddSubBlock($oDisplayBlock->GetDisplay($oPage, "SearchFormToAdd_{$sLinkedSetId}",
|
||||
[
|
||||
'menu' => false,
|
||||
array(
|
||||
'menu' => false,
|
||||
'result_list_outer_selector' => "SearchResultsToAdd_{$sLinkedSetId}",
|
||||
'table_id' => "add_{$sLinkedSetId}",
|
||||
'table_inner_id' => "ResultsToAdd_{$sLinkedSetId}",
|
||||
'selection_mode' => true,
|
||||
'json' => $sJson,
|
||||
'cssCount' => '#count_'.$this->m_sAttCode.$this->m_sNameSuffix,
|
||||
'query_params' => $oFilter->GetInternalParams(),
|
||||
'hidden_criteria' => $sAlreadyLinkedExpression,
|
||||
'submit_on_load' => false,
|
||||
]));
|
||||
'table_id' => "add_{$sLinkedSetId}",
|
||||
'table_inner_id' => "ResultsToAdd_{$sLinkedSetId}",
|
||||
'selection_mode' => true,
|
||||
'json' => $sJson,
|
||||
'cssCount' => '#count_'.$this->m_sAttCode.$this->m_sNameSuffix,
|
||||
'query_params' => $oFilter->GetInternalParams(),
|
||||
'hidden_criteria' => $sAlreadyLinkedExpression,
|
||||
)));
|
||||
|
||||
$oBlock->AddForm();
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -21,8 +21,6 @@
|
||||
*/
|
||||
|
||||
|
||||
use Combodo\iTop\Application\WebPage\WebPage;
|
||||
|
||||
require_once(APPROOT.'/application/displayblock.class.inc.php');
|
||||
|
||||
class UISearchFormForeignKeys
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
/**
|
||||
|
||||
@@ -20,10 +20,6 @@
|
||||
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 +51,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 +81,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 +106,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 +154,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 +395,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 +415,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,8 +480,7 @@ class utils
|
||||
|
||||
// For URL
|
||||
case static::ENUM_SANITIZATION_FILTER_URL:
|
||||
// N°6350 - returns only valid URLs
|
||||
$retValue = filter_var($value, FILTER_VALIDATE_URL);
|
||||
$retValue = filter_var($value, FILTER_SANITIZE_URL);
|
||||
break;
|
||||
|
||||
default:
|
||||
@@ -1042,27 +1010,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 +1042,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;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1427,23 +1396,13 @@ class utils
|
||||
return APPROOT . 'env-' . MetaModel::GetEnvironment() . '/';
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string A path to the folder into which data can be written
|
||||
* @internal
|
||||
* @since N°6097 2.7.10 3.0.4 3.1.1
|
||||
*/
|
||||
public static function GetDataPath(): string
|
||||
{
|
||||
return APPROOT.'data/';
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string A path to a folder into which any module can store cache data
|
||||
* The corresponding folder is created or cleaned upon code compilation
|
||||
*/
|
||||
public static function GetCachePath()
|
||||
{
|
||||
return static::GetDataPath().'cache-'.MetaModel::GetEnvironment().'/';
|
||||
return APPROOT.'data/cache-'.MetaModel::GetEnvironment().'/';
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1458,7 +1417,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
|
||||
@@ -2011,7 +1970,6 @@ SQL;
|
||||
|
||||
/**
|
||||
* @param string $sValue
|
||||
* @param bool $bDoubleEncode Whether to double encode the value or not
|
||||
*
|
||||
* @return string passed value with only characters having a special meaning in HTML escaped as entities
|
||||
* Since 3.0.0 we were using for this {@link HtmlEntities} but it was overkill and leads to double escaping !
|
||||
@@ -2019,15 +1977,14 @@ SQL;
|
||||
* @uses \htmlspecialchars()
|
||||
* @link https://www.php.net/manual/fr/function.htmlspecialchars.php
|
||||
* @since 3.0.0 N°3623
|
||||
* @since 3.1.0 N°6405 Add $bDoubleEncode parameter
|
||||
*/
|
||||
public static function EscapeHtml($sValue, bool $bDoubleEncode = false)
|
||||
public static function EscapeHtml($sValue)
|
||||
{
|
||||
return htmlspecialchars(
|
||||
$sValue ?? '',
|
||||
ENT_QUOTES | ENT_DISALLOWED | ENT_HTML5,
|
||||
WebPage::PAGES_CHARSET,
|
||||
$bDoubleEncode
|
||||
false
|
||||
);
|
||||
}
|
||||
|
||||
@@ -2088,9 +2045,6 @@ SQL;
|
||||
*/
|
||||
public static function TextToHtml($sText)
|
||||
{
|
||||
if (static::IsNullOrEmptyString($sText)){
|
||||
return '';
|
||||
}
|
||||
$sText = str_replace("\r\n", "\n", $sText);
|
||||
$sText = str_replace("\r", "\n", $sText);
|
||||
|
||||
@@ -2306,7 +2260,24 @@ SQL;
|
||||
*/
|
||||
public static function GetCurrentModuleName($iCallDepth = 0)
|
||||
{
|
||||
return ModuleService::GetInstance()->GetCurrentModuleName($iCallDepth + 1);
|
||||
$sCurrentModuleName = '';
|
||||
$aCallStack = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS);
|
||||
$sCallerFile = realpath($aCallStack[$iCallDepth]['file']);
|
||||
|
||||
foreach(GetModulesInfo() as $sModuleName => $aInfo)
|
||||
{
|
||||
if ($aInfo['root_dir'] !== '')
|
||||
{
|
||||
$sRootDir = realpath(APPROOT.$aInfo['root_dir']);
|
||||
|
||||
if(substr($sCallerFile, 0, strlen($sRootDir)) === $sRootDir)
|
||||
{
|
||||
$sCurrentModuleName = $sModuleName;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return $sCurrentModuleName;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2328,7 +2299,24 @@ SQL;
|
||||
*/
|
||||
public static function GetCurrentModuleDir($iCallDepth)
|
||||
{
|
||||
return ModuleService::GetInstance()->GetCurrentModuleDir($iCallDepth);
|
||||
$sCurrentModuleDir = '';
|
||||
$aCallStack = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS);
|
||||
$sCallerFile = realpath($aCallStack[$iCallDepth]['file']);
|
||||
|
||||
foreach(GetModulesInfo() as $sModuleName => $aInfo)
|
||||
{
|
||||
if ($aInfo['root_dir'] !== '')
|
||||
{
|
||||
$sRootDir = realpath(APPROOT.$aInfo['root_dir']);
|
||||
|
||||
if(substr($sCallerFile, 0, strlen($sRootDir)) === $sRootDir)
|
||||
{
|
||||
$sCurrentModuleDir = basename($sRootDir);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return $sCurrentModuleDir;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2343,7 +2331,12 @@ SQL;
|
||||
*/
|
||||
public static function GetCurrentModuleUrl()
|
||||
{
|
||||
return ModuleService::GetInstance()->GetCurrentModuleUrl(1);
|
||||
$sDir = static::GetCurrentModuleDir(1);
|
||||
if ( $sDir !== '')
|
||||
{
|
||||
return static::GetAbsoluteUrlModulesRoot().'/'.$sDir;
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2353,7 +2346,8 @@ SQL;
|
||||
*/
|
||||
public static function GetCurrentModuleSetting($sProperty, $defaultvalue = null)
|
||||
{
|
||||
return ModuleService::GetInstance()->GetCurrentModuleSetting($sProperty, $defaultvalue);
|
||||
$sModuleName = static::GetCurrentModuleName(1);
|
||||
return MetaModel::GetModuleSetting($sModuleName, $sProperty, $defaultvalue);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2362,7 +2356,12 @@ SQL;
|
||||
*/
|
||||
public static function GetCompiledModuleVersion($sModuleName)
|
||||
{
|
||||
return ModuleService::GetInstance()->GetCompiledModuleVersion($sModuleName);
|
||||
$aModulesInfo = GetModulesInfo();
|
||||
if (array_key_exists($sModuleName, $aModulesInfo))
|
||||
{
|
||||
return $aModulesInfo[$sModuleName]['version'];
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2504,17 +2503,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);
|
||||
@@ -2689,26 +2686,24 @@ SQL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the local path relative to the iTop installation (APPROOT or the given base path)
|
||||
* Returns the local path relative to the iTop installation of an existing file
|
||||
* Dir separator is changed to '/' for consistency among the different OS
|
||||
*
|
||||
* @param string $sAbsolutePath absolute path
|
||||
* @param string $sBasePath Base path for the resulting local path (default APPROOT)
|
||||
*
|
||||
* @return false|string The generated local path or false if absolute path is not under the base path
|
||||
* @since 3.1.1 Added base path defaulted to previous version APPROOT
|
||||
* @return false|string
|
||||
*/
|
||||
final public static function LocalPath($sAbsolutePath, string $sBasePath = APPROOT)
|
||||
final public static function LocalPath($sAbsolutePath)
|
||||
{
|
||||
$sRootPath = realpath($sBasePath);
|
||||
$sRootPath = realpath(APPROOT);
|
||||
$sFullPath = realpath($sAbsolutePath);
|
||||
if (($sFullPath === false) || !self::StartsWith($sFullPath, $sRootPath))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
$sLocalPath = substr($sFullPath, strlen($sRootPath.DIRECTORY_SEPARATOR));
|
||||
|
||||
return str_replace(DIRECTORY_SEPARATOR, '/', $sLocalPath);
|
||||
$sLocalPath = str_replace(DIRECTORY_SEPARATOR, '/', $sLocalPath);
|
||||
return $sLocalPath;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2900,7 +2895,7 @@ HTML;
|
||||
|
||||
// Add already loaded classes
|
||||
$aCurrentClasses = array_fill_keys(get_declared_classes(), '');
|
||||
$aClassMap = array_merge($aCurrentClasses, $aClassMap);
|
||||
$aClassMap = array_merge($aClassMap, $aCurrentClasses);
|
||||
|
||||
foreach ($aClassMap as $sPHPClass => $sPHPFile) {
|
||||
$bSkipped = false;
|
||||
@@ -2909,8 +2904,7 @@ HTML;
|
||||
if ($sClassNameFilter !== '' && strpos($sPHPClass, $sClassNameFilter) === false) {
|
||||
$bSkipped = true;
|
||||
}
|
||||
// For some PHP classes we don't have their file path as they are already in memory, so we never filter on their paths
|
||||
elseif (utils::IsNotNullOrEmptyString($sPHPFile)) {
|
||||
else {
|
||||
$sPHPFile = self::LocalPath($sPHPFile);
|
||||
if ($sPHPFile !== false) {
|
||||
$sPHPFile = '/'.$sPHPFile; // for regex
|
||||
@@ -2925,12 +2919,11 @@ HTML;
|
||||
$bSkipped = true; // file not found
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if(!$bSkipped){
|
||||
try {
|
||||
$oRefClass = new ReflectionClass($sPHPClass);
|
||||
if ($oRefClass->implementsInterface($sInterface) &&
|
||||
!$oRefClass->isInterface() && !$oRefClass->isAbstract() && !$oRefClass->isTrait()) {
|
||||
if ($oRefClass->implementsInterface($sInterface) && $oRefClass->isInstantiable()) {
|
||||
$aMatchingClasses[] = $sPHPClass;
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
@@ -2961,7 +2954,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 +3029,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 +3044,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
|
||||
{
|
||||
@@ -3377,22 +3368,5 @@ HTML;
|
||||
{
|
||||
return in_array($sTrait, self::TraitsUsedByClass($sClass, true));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get stack trace as string array.
|
||||
*
|
||||
* @return array
|
||||
* @since 3.1.0
|
||||
*/
|
||||
public static function GetStackTraceAsArray(): array
|
||||
{
|
||||
$e = new Exception();
|
||||
$aTrace = explode("\n", $e->getTraceAsString());
|
||||
// Remove call to this method
|
||||
array_shift($aTrace);
|
||||
// Remove Main
|
||||
array_pop($aTrace);
|
||||
|
||||
return $aTrace;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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
|
||||
*/
|
||||
|
||||
@@ -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))
|
||||
{
|
||||
|
||||
@@ -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
|
||||
*/
|
||||
|
||||
@@ -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';
|
||||
|
||||
@@ -45,7 +45,6 @@ define('MAINTENANCE_MODE_FILE', APPROOT.'data/.maintenance');
|
||||
define('READONLY_MODE_FILE', APPROOT.'data/.readonly');
|
||||
|
||||
$fItopStarted = microtime(true);
|
||||
$iItopInitialMemory = memory_get_usage(true);
|
||||
|
||||
if (!isset($GLOBALS['bBypassAutoload']) || $GLOBALS['bBypassAutoload'] == false) {
|
||||
require_once APPROOT.'/lib/autoload.php';
|
||||
|
||||
@@ -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": "*",
|
||||
@@ -12,33 +12,29 @@
|
||||
"ext-json": "*",
|
||||
"ext-mysqli": "*",
|
||||
"ext-soap": "*",
|
||||
"apereo/phpcas": "~1.6.0",
|
||||
"firebase/php-jwt": "^6.4.0",
|
||||
"guzzlehttp/guzzle": "^7.5.1",
|
||||
"apereo/phpcas" : "~1.6.0",
|
||||
"combodo/tcpdf": "~6.4.4",
|
||||
"firebase/php-jwt": "~6.4.0",
|
||||
"guzzlehttp/guzzle": "^7.4.5",
|
||||
"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"
|
||||
}
|
||||
}
|
||||
|
||||
2135
composer.lock
generated
2135
composer.lock
generated
File diff suppressed because it is too large
Load Diff
@@ -59,17 +59,9 @@ class DbConnectionWrapper
|
||||
* Use this to register a mock that will handle {@see mysqli::query()}
|
||||
*
|
||||
* @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
|
||||
public static function SetDbConnectionMockForQuery(?mysqli $oMysqli): void
|
||||
{
|
||||
if (is_null($oMysqli)) {
|
||||
// Reset to standard connection
|
||||
static::$oDbCnxMockableForQuery = static::$oDbCnxStandard;
|
||||
}
|
||||
else {
|
||||
static::$oDbCnxMockableForQuery = $oMysqli;
|
||||
}
|
||||
static::$oDbCnxMockableForQuery = $oMysqli;
|
||||
}
|
||||
}
|
||||
@@ -419,7 +419,6 @@ class MyHelpers
|
||||
//}
|
||||
return $sOutput;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -521,6 +520,8 @@ class Str
|
||||
|
||||
public static function islowcase($sString)
|
||||
{
|
||||
return (mb_strtolower($sString) == $sString);
|
||||
return (strtolower($sString) == $sString);
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
|
||||
@@ -1,101 +0,0 @@
|
||||
<?php
|
||||
/*
|
||||
* @copyright Copyright (C) 2010-2023 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* Class TemporaryObjectDescriptor
|
||||
*
|
||||
* Descriptor to track a temporary object.
|
||||
*
|
||||
* @experimental do not use, this feature will be part of a future version
|
||||
*
|
||||
* @since 3.1
|
||||
*/
|
||||
class TemporaryObjectDescriptor extends DBObject
|
||||
{
|
||||
public static function Init()
|
||||
{
|
||||
$aParams = array(
|
||||
'category' => 'core',
|
||||
'key_type' => 'autoincrement',
|
||||
'name_attcode' => array('item_class', 'temp_id'),
|
||||
'image_attcode' => '',
|
||||
'state_attcode' => '',
|
||||
'reconc_keys' => array(''),
|
||||
'db_table' => 'priv_temporary_object_descriptor',
|
||||
'db_key_field' => 'id',
|
||||
'db_finalclass_field' => '',
|
||||
'style' => new ormStyle(null, null, null, null, null, null),
|
||||
'indexes' => array(
|
||||
1 =>
|
||||
array(
|
||||
0 => 'temp_id',
|
||||
),
|
||||
2 =>
|
||||
array(
|
||||
0 => 'item_class',
|
||||
1 => 'item_id',
|
||||
),
|
||||
),
|
||||
);
|
||||
MetaModel::Init_Params($aParams);
|
||||
MetaModel::Init_InheritAttributes();
|
||||
MetaModel::Init_AddAttribute(new AttributeDateTime('expiration_date', array('sql' => 'expiration_date', 'is_null_allowed' => false, 'default_value' => '', 'allowed_values' => null, 'depends_on' => array(), 'always_load_in_tables' => false)));
|
||||
MetaModel::Init_AddAttribute(new AttributeString('temp_id', array('sql' => 'temp_id', 'is_null_allowed' => true, 'default_value' => '', 'allowed_values' => null, 'depends_on' => array(), 'always_load_in_tables' => false)));
|
||||
MetaModel::Init_AddAttribute(new AttributeString('item_class', array('sql' => 'item_class', 'is_null_allowed' => false, 'default_value' => '', 'allowed_values' => null, 'depends_on' => array(), 'always_load_in_tables' => false)));
|
||||
MetaModel::Init_AddAttribute(new AttributeObjectKey('item_id', array('class_attcode' => 'item_class', 'sql' => 'item_id', 'is_null_allowed' => true, 'allowed_values' => null, 'depends_on' => array(), 'always_load_in_tables' => false)));
|
||||
MetaModel::Init_AddAttribute(new AttributeDateTime('creation_date', array('sql' => 'creation_date', 'is_null_allowed' => true, 'default_value' => '', 'allowed_values' => null, 'depends_on' => array(), 'always_load_in_tables' => false)));
|
||||
MetaModel::Init_AddAttribute(new AttributeString('host_class', array('sql' => 'host_class', 'is_null_allowed' => true, 'default_value' => '', 'allowed_values' => null, 'depends_on' => array(), 'always_load_in_tables' => false)));
|
||||
MetaModel::Init_AddAttribute(new AttributeObjectKey('host_id', array('class_attcode' => 'host_class', 'sql' => 'host_id', 'is_null_allowed' => true, 'allowed_values' => null, 'depends_on' => array(), 'always_load_in_tables' => false)));
|
||||
MetaModel::Init_AddAttribute(new AttributeString('host_att_code', array('sql' => 'host_att_code', 'is_null_allowed' => true, 'default_value' => '', 'allowed_values' => null, 'depends_on' => array(), 'always_load_in_tables' => false)));
|
||||
MetaModel::Init_AddAttribute(new AttributeEnum("operation", array("allowed_values" => new ValueSetEnum('create,delete'), "sql" => "operation", "default_value" => "create", "is_null_allowed" => true, "depends_on" => array())));
|
||||
|
||||
MetaModel::Init_SetZListItems('details', array(
|
||||
0 => 'temp_id',
|
||||
1 => 'item_class',
|
||||
2 => 'item_id',
|
||||
3 => 'creation_date',
|
||||
4 => 'expiration_date',
|
||||
5 => 'meta',
|
||||
));
|
||||
MetaModel::Init_SetZListItems('standard_search', array(
|
||||
0 => 'temp_id',
|
||||
1 => 'item_class',
|
||||
2 => 'item_id',
|
||||
));
|
||||
MetaModel::Init_SetZListItems('list', array(
|
||||
0 => 'temp_id',
|
||||
1 => 'item_class',
|
||||
2 => 'item_id',
|
||||
3 => 'creation_date',
|
||||
4 => 'expiration_date',
|
||||
));;
|
||||
}
|
||||
|
||||
|
||||
public function DBInsertNoReload()
|
||||
{
|
||||
$this->SetCurrentDateIfNull('creation_date');
|
||||
|
||||
return parent::DBInsertNoReload();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set/Update all of the '_item' fields
|
||||
*
|
||||
* @param object $oItem Container item
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function SetItem($oItem, $bUpdateOnChange = false)
|
||||
{
|
||||
$sClass = get_class($oItem);
|
||||
$iItemId = $oItem->GetKey();
|
||||
|
||||
$this->Set('item_class', $sClass);
|
||||
$this->Set('item_id', $iItemId);
|
||||
}
|
||||
}
|
||||
@@ -16,12 +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\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 +75,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 +166,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 +200,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];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -353,22 +225,7 @@ class ActionEmail extends ActionNotification
|
||||
* @since 3.0.1
|
||||
*/
|
||||
const ENUM_HEADER_NAME_REFERENCES = 'References';
|
||||
/**
|
||||
* @var string
|
||||
* @since 3.1.0
|
||||
*/
|
||||
const TEMPLATE_BODY_CONTENT = '$content$';
|
||||
/**
|
||||
* Wraps the 'body' of the message for previewing inside an IFRAME -- i.e. without any of the iTop stylesheets being applied
|
||||
* @var string
|
||||
* @since 3.1.0
|
||||
*/
|
||||
const CONTENT_HIGHLIGHT = '<div style="border:2px dashed #6800ff;position:relative;padding:2px;margin-top:14px;"><div style="background-color:#6800ff;color:#fff;font-family:Courier New, sans-serif;font-size:14px;line-height:16px;padding:3px;display:block;position:absolute;top:-22px;right:0;">$content$</div>%s</div>';
|
||||
/**
|
||||
* Wraps a placeholder of the email's body for previewing inside an IFRAME -- i.e. without any of the iTop stylesheets being applied
|
||||
* @var string
|
||||
*/
|
||||
const FIELD_HIGHLIGHT = '<span style="background-color:#6800ff;color:#fff;font-size:smaller;font-family:Courier New, sans-serif;padding:2px;">\\$$1\\$</span>';
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
@@ -384,7 +241,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,9 +257,6 @@ 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 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())));
|
||||
|
||||
|
||||
// Display lists
|
||||
// - Attributes to be displayed for the complete details
|
||||
@@ -413,15 +266,12 @@ class ActionEmail extends ActionNotification
|
||||
0 => 'name',
|
||||
1 => 'description',
|
||||
2 => 'status',
|
||||
3 => 'language',
|
||||
4 => 'html_template',
|
||||
5 => 'subject',
|
||||
6 => 'body',
|
||||
3 => 'subject',
|
||||
4 => 'body',
|
||||
// 5 => 'importance', not handled when sending the mail, better hide it then
|
||||
),
|
||||
'fieldset:ActionEmail:trigger' => array(
|
||||
0 => 'trigger_list',
|
||||
1 => 'asynchronous'
|
||||
),
|
||||
),
|
||||
'col:col2' => array(
|
||||
@@ -431,21 +281,20 @@ class ActionEmail extends ActionNotification
|
||||
2 => 'reply_to',
|
||||
3 => 'reply_to_label',
|
||||
4 => 'test_recipient',
|
||||
5 => 'ignore_notify',
|
||||
6 => 'to',
|
||||
7 => 'cc',
|
||||
8 => 'bcc',
|
||||
5 => 'to',
|
||||
6 => 'cc',
|
||||
7 => 'bcc',
|
||||
),
|
||||
),
|
||||
));
|
||||
|
||||
// - Attributes to be displayed for a list
|
||||
MetaModel::Init_SetZListItems('list', array('status', 'to', 'subject', 'language'));
|
||||
MetaModel::Init_SetZListItems('list', array('status', 'to', 'subject'));
|
||||
// Search criteria
|
||||
// - Standard criteria of the search
|
||||
MetaModel::Init_SetZListItems('standard_search', array('name', 'description', 'status', 'subject', 'language'));
|
||||
MetaModel::Init_SetZListItems('standard_search', array('name', 'description', 'status', 'subject'));
|
||||
// - Default criteria for the search
|
||||
MetaModel::Init_SetZListItems('default_search', array('name', 'description', 'status', 'subject', 'language'));
|
||||
MetaModel::Init_SetZListItems('default_search', array('name', 'description', 'status', 'subject'));
|
||||
}
|
||||
|
||||
// count the recipients found
|
||||
@@ -456,40 +305,25 @@ 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,
|
||||
// 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();
|
||||
if (MetaModel::IsValidAttCode($sFirstSelectedClass, 'notify')) {
|
||||
$oSearch->AddCondition('notify', 'yes');
|
||||
}
|
||||
}
|
||||
$oSearch->AllowAllData();
|
||||
}
|
||||
catch (OQLException $e)
|
||||
@@ -515,29 +349,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);
|
||||
}
|
||||
@@ -627,27 +448,114 @@ class ActionEmail extends ActionNotification
|
||||
*/
|
||||
protected function _DoExecute($oTrigger, $aContextArgs, &$oLog)
|
||||
{
|
||||
$sPreviousUrlMaker = ApplicationContext::SetUrlMakerClass();
|
||||
try
|
||||
{
|
||||
$this->m_iRecipients = 0;
|
||||
$this->m_aMailErrors = array();
|
||||
|
||||
// Determine recipients
|
||||
//
|
||||
$sTo = $this->FindRecipients('to', $aContextArgs);
|
||||
$sCC = $this->FindRecipients('cc', $aContextArgs);
|
||||
$sBCC = $this->FindRecipients('bcc', $aContextArgs);
|
||||
|
||||
$sFrom = MetaModel::ApplyParams($this->Get('from'), $aContextArgs);
|
||||
$sFromLabel = MetaModel::ApplyParams($this->Get('from_label'), $aContextArgs);
|
||||
$sReplyTo = MetaModel::ApplyParams($this->Get('reply_to'), $aContextArgs);
|
||||
$sReplyToLabel = MetaModel::ApplyParams($this->Get('reply_to_label'), $aContextArgs);
|
||||
|
||||
$sSubject = MetaModel::ApplyParams($this->Get('subject'), $aContextArgs);
|
||||
$sBody = MetaModel::ApplyParams($this->Get('body'), $aContextArgs);
|
||||
|
||||
$oObj = $aContextArgs['this->object()'];
|
||||
$sMessageId = $this->GenerateIdentifierForHeaders($oObj, static::ENUM_HEADER_NAME_MESSAGE_ID);
|
||||
$sReference = $this->GenerateIdentifierForHeaders($oObj, static::ENUM_HEADER_NAME_REFERENCES);
|
||||
}
|
||||
catch (Exception $e) {
|
||||
/** @noinspection PhpUnhandledExceptionInspection */
|
||||
throw $e;
|
||||
}
|
||||
finally {
|
||||
ApplicationContext::SetUrlMakerClass($sPreviousUrlMaker);
|
||||
}
|
||||
|
||||
if (!is_null($oLog)) {
|
||||
// Note: we have to secure this because those values are calculated
|
||||
// inside the try statement, and we would like to keep track of as
|
||||
// many data as we could while some variables may still be undefined
|
||||
if (isset($sTo)) {
|
||||
$oLog->Set('to', $sTo);
|
||||
}
|
||||
if (isset($sCC)) {
|
||||
$oLog->Set('cc', $sCC);
|
||||
}
|
||||
if (isset($sBCC)) {
|
||||
$oLog->Set('bcc', $sBCC);
|
||||
}
|
||||
if (isset($sFrom)) {
|
||||
$oLog->Set('from', $sFrom);
|
||||
}
|
||||
if (isset($sSubject)) {
|
||||
$oLog->Set('subject', $sSubject);
|
||||
}
|
||||
if (isset($sBody)) {
|
||||
$oLog->Set('body', $sBody);
|
||||
}
|
||||
}
|
||||
$sStyles = file_get_contents(APPROOT.'css/email.css');
|
||||
$sStyles .= MetaModel::GetConfig()->Get('email_css');
|
||||
|
||||
|
||||
$oEmail = new EMail();
|
||||
|
||||
$aEmailContent = $this->PrepareMessageContent($aContextArgs, $oLog);
|
||||
$oEmail->SetSubject($aEmailContent['subject']);
|
||||
$oEmail->SetBody($aEmailContent['body'], 'text/html', $sStyles);
|
||||
$oEmail->SetRecipientTO($aEmailContent['to']);
|
||||
$oEmail->SetRecipientCC($aEmailContent['cc']);
|
||||
$oEmail->SetRecipientBCC($aEmailContent['bcc']);
|
||||
$oEmail->SetRecipientFrom($aEmailContent['from'], $aEmailContent['from_label']);
|
||||
$oEmail->SetRecipientReplyTo($aEmailContent['reply_to'], $aEmailContent['reply_to_label']);
|
||||
$oEmail->SetReferences($aEmailContent['references']);
|
||||
$oEmail->SetMessageId($aEmailContent['message_id']);
|
||||
$oEmail->SetInReplyTo($aEmailContent['in_reply_to']);
|
||||
|
||||
foreach($aEmailContent['attachments'] as $aAttachment) {
|
||||
$oEmail->AddAttachment($aAttachment['data'], $aAttachment['filename'], $aAttachment['mime_type']);
|
||||
|
||||
if ($this->IsBeingTested()) {
|
||||
$oEmail->SetSubject('TEST['.$sSubject.']');
|
||||
$sTestBody = $sBody;
|
||||
$sTestBody .= "<div style=\"border: dashed;\">\n";
|
||||
$sTestBody .= "<h1>Testing email notification ".$this->GetHyperlink()."</h1>\n";
|
||||
$sTestBody .= "<p>The email should be sent with the following properties\n";
|
||||
$sTestBody .= "<ul>\n";
|
||||
$sTestBody .= "<li>TO: $sTo</li>\n";
|
||||
$sTestBody .= "<li>CC: $sCC</li>\n";
|
||||
$sTestBody .= "<li>BCC: $sBCC</li>\n";
|
||||
$sTestBody .= empty($sFromLabel) ? "<li>From: $sFrom</li>\n" : "<li>From: $sFromLabel <$sFrom></li>\n";
|
||||
$sTestBody .= empty($sReplyToLabel) ? "<li>Reply-To: $sReplyTo</li>\n" : "<li>Reply-To: $sReplyToLabel <$sReplyTo></li>\n";
|
||||
$sTestBody .= "<li>References: $sReference</li>\n";
|
||||
$sTestBody .= "</ul>\n";
|
||||
$sTestBody .= "</p>\n";
|
||||
$sTestBody .= "</div>\n";
|
||||
$oEmail->SetBody($sTestBody, 'text/html', $sStyles);
|
||||
$oEmail->SetRecipientTO($this->Get('test_recipient'));
|
||||
$oEmail->SetRecipientFrom($sFrom, $sFromLabel);
|
||||
$oEmail->SetReferences($sReference);
|
||||
$oEmail->SetMessageId($sMessageId);
|
||||
// Note: N°4849 We pass the "References" identifier instead of the "Message-ID" on purpose as we want notifications emails to group around the triggering iTop object, not just the users' replies to the notification
|
||||
$oEmail->SetInReplyTo($sReference);
|
||||
} else {
|
||||
$oEmail->SetSubject($sSubject);
|
||||
$oEmail->SetBody($sBody, 'text/html', $sStyles);
|
||||
$oEmail->SetRecipientTO($sTo);
|
||||
$oEmail->SetRecipientCC($sCC);
|
||||
$oEmail->SetRecipientBCC($sBCC);
|
||||
$oEmail->SetRecipientFrom($sFrom, $sFromLabel);
|
||||
$oEmail->SetRecipientReplyTo($sReplyTo, $sReplyToLabel);
|
||||
$oEmail->SetReferences($sReference);
|
||||
$oEmail->SetMessageId($sMessageId);
|
||||
// Note: N°4849 We pass the "References" identifier instead of the "Message-ID" on purpose as we want notifications emails to group around the triggering iTop object, not just the users' replies to the notification
|
||||
$oEmail->SetInReplyTo($sReference);
|
||||
}
|
||||
|
||||
|
||||
if (isset($aContextArgs['attachments']))
|
||||
{
|
||||
$aAttachmentReport = array();
|
||||
foreach($aContextArgs['attachments'] as $oDocument)
|
||||
{
|
||||
$oEmail->AddAttachment($oDocument->GetData(), $oDocument->GetFileName(), $oDocument->GetMimeType());
|
||||
$aAttachmentReport[] = array($oDocument->GetFileName(), $oDocument->GetMimeType(), strlen($oDocument->GetData()));
|
||||
}
|
||||
$oLog->Set('attachments', $aAttachmentReport);
|
||||
}
|
||||
|
||||
if (empty($this->m_aMailErrors))
|
||||
{
|
||||
if ($this->m_iRecipients == 0)
|
||||
@@ -656,8 +564,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:
|
||||
@@ -681,148 +588,13 @@ class ActionEmail extends ActionNotification
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $aContextArgs
|
||||
* @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
|
||||
* @since 3.1.0 N°918
|
||||
*/
|
||||
protected function PrepareMessageContent($aContextArgs, &$oLog): array
|
||||
{
|
||||
$aMessageContent = [
|
||||
'to' => '',
|
||||
'cc' => '',
|
||||
'bcc' => '',
|
||||
'from' => '',
|
||||
'from_label' => '',
|
||||
'reply_to' => '',
|
||||
'reply_to_label' => '',
|
||||
'subject' => '',
|
||||
'body' => '',
|
||||
'references' => '',
|
||||
'message_id' => '',
|
||||
'in_reply_to' => '',
|
||||
'attachments' => [],
|
||||
];
|
||||
$sPreviousUrlMaker = ApplicationContext::SetUrlMakerClass();
|
||||
[$sPreviousLanguage, $aPreviousPluginProperties] = $this->SetNotificationLanguage();
|
||||
|
||||
try
|
||||
{
|
||||
$this->m_iRecipients = 0;
|
||||
$this->m_aMailErrors = array();
|
||||
|
||||
// Determine recipients
|
||||
//
|
||||
$aMessageContent['to'] = $this->FindRecipients('to', $aContextArgs);
|
||||
$aMessageContent['cc'] = $this->FindRecipients('cc', $aContextArgs);
|
||||
$aMessageContent['bcc'] = $this->FindRecipients('bcc', $aContextArgs);
|
||||
|
||||
$aMessageContent['from'] = MetaModel::ApplyParams($this->Get('from'), $aContextArgs);
|
||||
$aMessageContent['from_label'] = MetaModel::ApplyParams($this->Get('from_label'), $aContextArgs);
|
||||
$aMessageContent['reply_to'] = MetaModel::ApplyParams($this->Get('reply_to'), $aContextArgs);
|
||||
$aMessageContent['reply_to_label'] = MetaModel::ApplyParams($this->Get('reply_to_label'), $aContextArgs);
|
||||
|
||||
$aMessageContent['subject'] = MetaModel::ApplyParams($this->Get('subject'), $aContextArgs);
|
||||
$sBody = $this->BuildMessageBody(false);
|
||||
$aMessageContent['body'] = MetaModel::ApplyParams($sBody, $aContextArgs);
|
||||
|
||||
$oObj = $aContextArgs['this->object()'];
|
||||
$aMessageContent['message_id'] = $this->GenerateIdentifierForHeaders($oObj, static::ENUM_HEADER_NAME_MESSAGE_ID);
|
||||
$aMessageContent['references'] = $this->GenerateIdentifierForHeaders($oObj, static::ENUM_HEADER_NAME_REFERENCES);
|
||||
}
|
||||
catch (Exception $e) {
|
||||
/** @noinspection PhpUnhandledExceptionInspection */
|
||||
throw $e;
|
||||
}
|
||||
finally {
|
||||
ApplicationContext::SetUrlMakerClass($sPreviousUrlMaker);
|
||||
$this->SetNotificationLanguage($sPreviousLanguage, $aPreviousPluginProperties['language_code'] ?? null);
|
||||
}
|
||||
|
||||
if (!is_null($oLog)) {
|
||||
// Note: we have to secure this because those values are calculated
|
||||
// inside the try statement, and we would like to keep track of as
|
||||
// many data as we could while some variables may still be undefined
|
||||
if (isset($aMessageContent['to'])) {
|
||||
$oLog->Set('to', $aMessageContent['to']);
|
||||
}
|
||||
if (isset($aMessageContent['cc'])) {
|
||||
$oLog->Set('cc', $aMessageContent['cc']);
|
||||
}
|
||||
if (isset($aMessageContent['bcc'])) {
|
||||
$oLog->Set('bcc', $aMessageContent['bcc']);
|
||||
}
|
||||
if (isset($aMessageContent['from'])) {
|
||||
$oLog->Set('from', $aMessageContent['from']);
|
||||
}
|
||||
if (isset($aMessageContent['subject'])) {
|
||||
$oLog->Set('subject', $aMessageContent['subject']);
|
||||
}
|
||||
if (isset($aMessageContent['body'])) {
|
||||
$oLog->Set('body', HTMLSanitizer::Sanitize($aMessageContent['body']));
|
||||
}
|
||||
}
|
||||
|
||||
if ($this->IsBeingTested()) {
|
||||
$sTestBody = $aMessageContent['body'];
|
||||
$sTestBody .= "<div style=\"border: dashed;\">\n";
|
||||
$sTestBody .= "<h1>Testing email notification ".$this->GetHyperlink()."</h1>\n";
|
||||
$sTestBody .= "<p>The email should be sent with the following properties\n";
|
||||
$sTestBody .= "<ul>\n";
|
||||
$sTestBody .= "<li>TO: {$aMessageContent['to']}</li>\n";
|
||||
$sTestBody .= "<li>CC: {$aMessageContent['cc']}</li>\n";
|
||||
$sTestBody .= "<li>BCC: {$aMessageContent['bcc']}</li>\n";
|
||||
$sTestBody .= empty($aMessageContent['from_label']) ? "<li>From: {$aMessageContent['from']}</li>\n" : "<li>From: {$aMessageContent['from_label']} <{$aMessageContent['from']}></li>\n";
|
||||
$sTestBody .= empty($aMessageContent['reply_to_label']) ? "<li>Reply-To: {$aMessageContent['reply_to']}</li>\n" : "<li>Reply-To: {$aMessageContent['reply_to_label']} <{$aMessageContent['reply_to']}></li>\n";
|
||||
$sTestBody .= "<li>References: {$aMessageContent['references']}</li>\n";
|
||||
$sTestBody .= "</ul>\n";
|
||||
$sTestBody .= "</p>\n";
|
||||
$sTestBody .= "</div>\n";
|
||||
$aMessageContent['subject'] = 'TEST['.$aMessageContent['subject'].']';
|
||||
$aMessageContent['body'] = $sTestBody;
|
||||
$aMessageContent['to'] = $this->Get('test_recipient');
|
||||
// N°6677 Ensure emails in test are never sent to cc'd and bcc'd addresses
|
||||
$aMessageContent['cc'] = '';
|
||||
$aMessageContent['bcc'] = '';
|
||||
}
|
||||
// Note: N°4849 We pass the "References" identifier instead of the "Message-ID" on purpose as we want notifications emails to group around the triggering iTop object, not just the users' replies to the notification
|
||||
$aMessageContent['in_reply_to'] = $aMessageContent['references'];
|
||||
|
||||
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() ?? ''));
|
||||
}
|
||||
$oLog->Set('attachments', $aAttachmentReport);
|
||||
}
|
||||
|
||||
return $aMessageContent;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \DBObject $oObject
|
||||
* @param string $sHeaderName {@see \ActionEmail::ENUM_HEADER_NAME_REFERENCES}, {@see \ActionEmail::ENUM_HEADER_NAME_MESSAGE_ID}
|
||||
*
|
||||
* @return string The formatted identifier for $sHeaderName based on $oObject
|
||||
* @throws \Exception
|
||||
* @since 3.1.0 N°4849
|
||||
* @since 3.0.1 N°4849
|
||||
*/
|
||||
protected function GenerateIdentifierForHeaders(DBObject $oObject, string $sHeaderName): string
|
||||
{
|
||||
@@ -857,74 +629,4 @@ class ActionEmail extends ActionNotification
|
||||
]);
|
||||
throw new Exception($sErrorMessage);
|
||||
}
|
||||
|
||||
/**
|
||||
* Compose the body of the message from the 'body' attribute and the HTML template (if any)
|
||||
* @since 3.1.0 N°4849
|
||||
* @param bool $bHighlightPlaceholders If true add some extra HTML around placeholders to highlight them
|
||||
* @return string
|
||||
*/
|
||||
protected function BuildMessageBody(bool $bHighlightPlaceholders = false): string
|
||||
{
|
||||
$sBody = $this->Get('body');
|
||||
/** @var ormDocument $oHtmlTemplate */
|
||||
$oHtmlTemplate = $this->Get('html_template');
|
||||
if ($oHtmlTemplate && !$oHtmlTemplate->IsEmpty()) {
|
||||
$sHtmlTemplate = $oHtmlTemplate->GetData();
|
||||
if (false !== mb_strpos($sHtmlTemplate, static::TEMPLATE_BODY_CONTENT)) {
|
||||
if ($bHighlightPlaceholders) {
|
||||
// Highlight the $content$ block
|
||||
$sBody = sprintf(static::CONTENT_HIGHLIGHT, $sBody);
|
||||
}
|
||||
$sBody = str_replace(static::TEMPLATE_BODY_CONTENT, $sBody, $oHtmlTemplate->GetData()); // str_replace is ok as long as both strings are well-formed UTF-8
|
||||
} else {
|
||||
$sBody = $oHtmlTemplate->GetData();
|
||||
}
|
||||
}
|
||||
if($bHighlightPlaceholders) {
|
||||
// Highlight all placeholders
|
||||
$sBody = preg_replace('/\\$([^$]+)\\$/', static::FIELD_HIGHLIGHT, $sBody);
|
||||
}
|
||||
return $sBody;
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 3.1.0 N°4849
|
||||
* @inheritDoc
|
||||
* @see cmdbAbstractObject::DisplayBareRelations()
|
||||
*/
|
||||
public function DisplayBareRelations(WebPage $oPage, $bEditMode = false)
|
||||
{
|
||||
parent::DisplayBareRelations($oPage, false);
|
||||
if (!$bEditMode) {
|
||||
$oPage->SetCurrentTab('action_email__preview', Dict::S('ActionEmail:preview_tab'), Dict::S('ActionEmail:preview_tab+'));
|
||||
$sBody = $this->BuildMessageBody(true);
|
||||
TwigHelper::RenderIntoPage($oPage, APPROOT.'/', 'templates/datamodel/ActionEmail/email-notification-preview', ['iframe_content' => $sBody]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 3.1.0
|
||||
* @inheritDoc
|
||||
* @see cmdbAbstractObject::DoCheckToWrite()
|
||||
*/
|
||||
public function DoCheckToWrite()
|
||||
{
|
||||
parent::DoCheckToWrite();
|
||||
$oHtmlTemplate = $this->Get('html_template');
|
||||
if ($oHtmlTemplate && !$oHtmlTemplate->IsEmpty()) {
|
||||
if (false === mb_strpos($oHtmlTemplate->GetData(), static::TEMPLATE_BODY_CONTENT)) {
|
||||
$this->m_aCheckWarnings[] = Dict::Format('ActionEmail:content_placeholder_missing', static::TEMPLATE_BODY_CONTENT, Dict::S('Class:ActionEmail/Attribute:body'));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
* @since 3.2.0
|
||||
*/
|
||||
public static function GetAsynchronousGlobalSetting(): bool
|
||||
{
|
||||
return utils::GetConfig()->Get('email_asynchronous');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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";
|
||||
}
|
||||
}
|
||||
@@ -6,11 +6,11 @@
|
||||
|
||||
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;
|
||||
use Combodo\iTop\Form\Validator\CustomRegexpValidator;
|
||||
use Combodo\iTop\Form\Validator\NotEmptyExtKeyValidator;
|
||||
use Combodo\iTop\Form\Validator\Validator;
|
||||
use Combodo\iTop\Renderer\BlockRenderer;
|
||||
use Combodo\iTop\Renderer\Console\ConsoleBlockRenderer;
|
||||
use Combodo\iTop\Service\Links\LinkSetModel;
|
||||
@@ -92,11 +92,8 @@ 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_RELATIONTYPE_PROPERTY', 'property');
|
||||
define('LINKSET_RELATIONTYPE_LINK', 'link');
|
||||
|
||||
define('LINKSET_DISPLAY_STYLE_PROPERTY', 'property');
|
||||
define('LINKSET_DISPLAY_STYLE_TAB', 'tab');
|
||||
@@ -798,14 +795,14 @@ 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);
|
||||
}
|
||||
|
||||
/**
|
||||
* force an allowed value (type conversion and possibly forces a value as mySQL would do upon writing!
|
||||
*
|
||||
* @param mixed $proposedValue
|
||||
* @param \DBObject $oHostObj
|
||||
* @param $proposedValue
|
||||
* @param $oHostObj
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
@@ -995,21 +992,17 @@ abstract class AttributeDefinition
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper to form a value, given JSON decoded data. This way the attribute itself handles the transformation from the JSON structure to the expected data (the one that
|
||||
* needs to be used in the {@see \DBObject::Set()} method).
|
||||
*
|
||||
* Note that for CSV and XML this isn't done yet (no delegation to the attribute but switch/case inside controllers) :/
|
||||
*
|
||||
* @see GetForJSON for the reverse operation
|
||||
* Helper to form a value, given JSON decoded data
|
||||
*
|
||||
* @param string $json JSON encoded value
|
||||
*
|
||||
* @return mixed JSON decoded data, depending on the attribute type
|
||||
* @return mixed JSON decoded data
|
||||
*
|
||||
* @see GetForJSON for the reverse operation
|
||||
*/
|
||||
public function FromJSONToValue($json)
|
||||
{
|
||||
// Pass-through in most of the cases
|
||||
// Passthrough in most of the cases
|
||||
return $json;
|
||||
}
|
||||
|
||||
@@ -1128,7 +1121,7 @@ abstract class AttributeDefinition
|
||||
|
||||
// Validation pattern
|
||||
if ($this->GetValidationPattern() !== '') {
|
||||
$oFormField->AddValidator(new CustomRegexpValidator($this->GetValidationPattern()));
|
||||
$oFormField->AddValidator(new Validator($this->GetValidationPattern()));
|
||||
}
|
||||
|
||||
// Description
|
||||
@@ -1157,13 +1150,6 @@ abstract class AttributeDefinition
|
||||
$oFormField->AddMetadata('value-raw', (string)$oObject->Get($this->GetCode()));
|
||||
}
|
||||
|
||||
// We don't want to invalidate field because of old untouched values that are no longer valid
|
||||
$aModifiedAttCodes = $oObject->ListChanges();
|
||||
$bAttributeHasBeenModified = array_key_exists($this->GetCode(), $aModifiedAttCodes);
|
||||
if (false === $bAttributeHasBeenModified) {
|
||||
$oFormField->SetValidationDisabled(true);
|
||||
}
|
||||
|
||||
return $oFormField;
|
||||
}
|
||||
|
||||
@@ -1706,19 +1692,20 @@ class AttributeLinkedSet extends AttributeDefinition
|
||||
|
||||
/**
|
||||
* @return string see LINKSET_EDITMODE_* constants
|
||||
* @since 3.1.0 N°5563 relations are edited using new attributes in details mode, but as nothing changed in edit mode we are still using edit_mode attribute
|
||||
*/
|
||||
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
|
||||
* @return string see LINKSET_RELATIONTYPE_* constants
|
||||
* @since 3.1.0 N°5563
|
||||
*/
|
||||
public function GetEditWhen(): int
|
||||
public function GetRelationType()
|
||||
{
|
||||
return $this->GetOptional('edit_when', LINKSET_EDITWHEN_ALWAYS);
|
||||
return $this->GetOptional('relation_type', LINKSET_RELATIONTYPE_LINK);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1736,24 +1723,14 @@ class AttributeLinkedSet extends AttributeDefinition
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates if the current Attribute has constraints (php constraints or datamodel constraints)
|
||||
* @return bool true if Attribute has constraints
|
||||
* @since 3.1.0 N°6228
|
||||
* @return boolean
|
||||
* @since 3.1.0 N°5563
|
||||
*/
|
||||
public function HasPHPConstraint(): bool
|
||||
public function GetReadOnly()
|
||||
{
|
||||
return $this->GetOptional('with_php_constraint', false);
|
||||
return $this->GetOptional('read_only', 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');
|
||||
@@ -1780,58 +1757,12 @@ class AttributeLinkedSet extends AttributeDefinition
|
||||
}
|
||||
|
||||
/** @inheritDoc * */
|
||||
public function GetAsHTML($sValue, $oHostObject = null, $bLocalize = true)
|
||||
{
|
||||
if($this->GetDisplayStyle() === LINKSET_DISPLAY_STYLE_TAB){
|
||||
return $this->GetAsHTMLForTab($sValue, $oHostObject, $bLocalize);
|
||||
}
|
||||
else{
|
||||
return $this->GetAsHTMLForProperty($sValue, $oHostObject, $bLocalize);
|
||||
}
|
||||
}
|
||||
|
||||
public function GetAsHTMLForTab($sValue, $oHostObject = null, $bLocalize = true)
|
||||
{
|
||||
if (is_object($sValue) && ($sValue instanceof ormLinkSet))
|
||||
{
|
||||
$sValue->Rewind();
|
||||
$aItems = array();
|
||||
while ($oObj = $sValue->Fetch())
|
||||
{
|
||||
// Show only relevant information (hide the external key to the current object)
|
||||
$aAttributes = array();
|
||||
foreach(MetaModel::ListAttributeDefs($this->GetLinkedClass()) as $sAttCode => $oAttDef)
|
||||
{
|
||||
if ($sAttCode == $this->GetExtKeyToMe())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if ($oAttDef->IsExternalField())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
$sAttValue = $oObj->GetAsHTML($sAttCode);
|
||||
if (strlen($sAttValue) > 0)
|
||||
{
|
||||
$aAttributes[] = $sAttValue;
|
||||
}
|
||||
}
|
||||
$sAttributes = implode(', ', $aAttributes);
|
||||
$aItems[] = $sAttributes;
|
||||
}
|
||||
|
||||
return implode('<br/>', $aItems);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public function GetAsHTMLForProperty($sValue, $oHostObject = null, $bLocalize = true): string
|
||||
public function GetAsHTML($sValue, $oHostObject = null, $bLocalize = true): string
|
||||
{
|
||||
try {
|
||||
|
||||
/** @var ormLinkSet $sValue */
|
||||
if (is_null($sValue) || $sValue->Count() === 0) {
|
||||
if ($sValue->Count() === 0) {
|
||||
return '';
|
||||
}
|
||||
|
||||
@@ -2450,61 +2381,43 @@ class AttributeLinkedSet extends AttributeDefinition
|
||||
{
|
||||
if ($oFormField === null)
|
||||
{
|
||||
$sFormFieldClass = static::GetFormFieldClass();
|
||||
$oFormField = new $sFormFieldClass($this->GetCode());
|
||||
}
|
||||
$sFormFieldClass = static::GetFormFieldClass();
|
||||
$oFormField = new $sFormFieldClass($this->GetCode());
|
||||
}
|
||||
|
||||
// Setting target class
|
||||
// Setting target class
|
||||
if (!$this->IsIndirect()) {
|
||||
$sTargetClass = $this->GetLinkedClass();
|
||||
} else {
|
||||
/** @var \AttributeExternalKey $oRemoteAttDef */
|
||||
/** @var \AttributeLinkedSetIndirect $this */
|
||||
$oRemoteAttDef = MetaModel::GetAttributeDef($this->GetLinkedClass(), $this->GetExtKeyToRemote());
|
||||
$sTargetClass = $oRemoteAttDef->GetTargetClass();
|
||||
$sTargetClass = $this->GetLinkedClass();
|
||||
} else {
|
||||
/** @var \AttributeExternalKey $oRemoteAttDef */
|
||||
/** @var \AttributeLinkedSetIndirect $this */
|
||||
$oRemoteAttDef = MetaModel::GetAttributeDef($this->GetLinkedClass(), $this->GetExtKeyToRemote());
|
||||
$sTargetClass = $oRemoteAttDef->GetTargetClass();
|
||||
|
||||
/** @var \AttributeLinkedSetIndirect $this */
|
||||
$oFormField->SetExtKeyToRemote($this->GetExtKeyToRemote());
|
||||
}
|
||||
$oFormField->SetTargetClass($sTargetClass);
|
||||
$oFormField->SetLinkedClass($this->GetLinkedClass());
|
||||
$oFormField->SetIndirect($this->IsIndirect());
|
||||
// Setting attcodes to display
|
||||
$aAttCodesToDisplay = MetaModel::FlattenZList(MetaModel::GetZListItems($sTargetClass, 'list'));
|
||||
// - Adding friendlyname attribute to the list is not already in it
|
||||
$sTitleAttCode = MetaModel::GetFriendlyNameAttributeCode($sTargetClass);
|
||||
if (($sTitleAttCode !== null) && !in_array($sTitleAttCode, $aAttCodesToDisplay)) {
|
||||
$aAttCodesToDisplay = array_merge(array($sTitleAttCode), $aAttCodesToDisplay);
|
||||
}
|
||||
// - Adding attribute properties
|
||||
$aAttributesToDisplay = array();
|
||||
foreach ($aAttCodesToDisplay as $sAttCodeToDisplay) {
|
||||
$oAttDefToDisplay = MetaModel::GetAttributeDef($sTargetClass, $sAttCodeToDisplay);
|
||||
$aAttributesToDisplay[$sAttCodeToDisplay] = [
|
||||
'att_code' => $sAttCodeToDisplay,
|
||||
'label' => $oAttDefToDisplay->GetLabel(),
|
||||
];
|
||||
}
|
||||
$oFormField->SetAttributesToDisplay($aAttributesToDisplay);
|
||||
/** @var \AttributeLinkedSetIndirect $this */
|
||||
$oFormField->SetExtKeyToRemote($this->GetExtKeyToRemote());
|
||||
}
|
||||
$oFormField->SetTargetClass($sTargetClass);
|
||||
$oFormField->SetIndirect($this->IsIndirect());
|
||||
// Setting attcodes to display
|
||||
$aAttCodesToDisplay = MetaModel::FlattenZList(MetaModel::GetZListItems($sTargetClass, 'list'));
|
||||
// - Adding friendlyname attribute to the list is not already in it
|
||||
$sTitleAttCode = MetaModel::GetFriendlyNameAttributeCode($sTargetClass);
|
||||
if (($sTitleAttCode !== null) && !in_array($sTitleAttCode, $aAttCodesToDisplay)) {
|
||||
$aAttCodesToDisplay = array_merge(array($sTitleAttCode), $aAttCodesToDisplay);
|
||||
}
|
||||
// - Adding attribute labels
|
||||
$aAttributesToDisplay = array();
|
||||
foreach ($aAttCodesToDisplay as $sAttCodeToDisplay) {
|
||||
$oAttDefToDisplay = MetaModel::GetAttributeDef($sTargetClass, $sAttCodeToDisplay);
|
||||
$aAttributesToDisplay[$sAttCodeToDisplay] = $oAttDefToDisplay->GetLabel();
|
||||
}
|
||||
$oFormField->SetAttributesToDisplay($aAttributesToDisplay);
|
||||
|
||||
// Append lnk attributes (filtered from zlist)
|
||||
if ($this->IsIndirect()) {
|
||||
$aLnkAttDefToDisplay = MetaModel::GetZListAttDefsFilteredForIndirectLinkClass($this->m_sHostClass, $this->m_sCode);
|
||||
$aLnkAttributesToDisplay = array();
|
||||
foreach ($aLnkAttDefToDisplay as $oLnkAttDefToDisplay) {
|
||||
$aLnkAttributesToDisplay[$oLnkAttDefToDisplay->GetCode()] = [
|
||||
'att_code' => $oLnkAttDefToDisplay->GetCode(),
|
||||
'label' => $oLnkAttDefToDisplay->GetLabel(),
|
||||
'mandatory' => !$oLnkAttDefToDisplay->IsNullAllowed(),
|
||||
];
|
||||
}
|
||||
$oFormField->SetLnkAttributesToDisplay($aLnkAttributesToDisplay);
|
||||
}
|
||||
parent::MakeFormField($oObject, $oFormField);
|
||||
|
||||
parent::MakeFormField($oObject, $oFormField);
|
||||
|
||||
return $oFormField;
|
||||
}
|
||||
return $oFormField;
|
||||
}
|
||||
|
||||
public function IsPartOfFingerprint()
|
||||
{
|
||||
@@ -2610,6 +2523,15 @@ class AttributeLinkedSetIndirect extends AttributeLinkedSet
|
||||
return $this->GetOptional("duplicates", false);
|
||||
} // The same object may be linked several times... or not...
|
||||
|
||||
/**
|
||||
* @return boolean
|
||||
* @since 3.1.0 N°5563
|
||||
*/
|
||||
public function GetReadOnly()
|
||||
{
|
||||
return $this->GetOptional('read_only', false);
|
||||
}
|
||||
|
||||
public function GetTrackingLevel()
|
||||
{
|
||||
return $this->GetOptional('tracking_level',
|
||||
@@ -3062,11 +2984,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 +2996,7 @@ class AttributeObjectKey extends AttributeDBFieldVoid
|
||||
}
|
||||
if (MetaModel::IsValidObject($proposedValue))
|
||||
{
|
||||
/** @var \DBObject $proposedValue */
|
||||
return $proposedValue->GetKey();
|
||||
}
|
||||
|
||||
@@ -3198,7 +3116,7 @@ class AttributeDecimal extends AttributeDBField
|
||||
$iPrecision = $this->Get('decimals');
|
||||
$iNbIntegerDigits = $iNbDigits - $iPrecision - 1; // -1 because the first digit is treated separately in the pattern below
|
||||
|
||||
return "^[\-\+]?[0-9]\d{0,$iNbIntegerDigits}(\.\d{0,$iPrecision})?$";
|
||||
return "^[-+]?[0-9]\d{0,$iNbIntegerDigits}(\.\d{0,$iPrecision})?$";
|
||||
}
|
||||
|
||||
public function GetBasicFilterOperators()
|
||||
@@ -3510,7 +3428,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)
|
||||
@@ -3920,12 +3838,6 @@ class AttributeApplicationLanguage extends AttributeString
|
||||
{
|
||||
$aLanguageCodes[$sLangCode] = $aInfo['description'].' ('.$aInfo['localized_description'].')';
|
||||
}
|
||||
|
||||
// N°6462 This should be sorted directly in \Dict during the compilation but we can't for 2 reasons:
|
||||
// - Additional languages can be added on the fly even though it is not recommended
|
||||
// - Formatting is done at run time (just above)
|
||||
natcasesort($aLanguageCodes);
|
||||
|
||||
$aParams["allowed_values"] = new ValueSetEnum($aLanguageCodes);
|
||||
parent::__construct($sCode, $aParams);
|
||||
}
|
||||
@@ -4216,7 +4128,7 @@ class AttributePassword extends AttributeString implements iAttributeNoGroupBy
|
||||
|
||||
public function GetAsHTML($sValue, $oHostObject = null, $bLocalize = true)
|
||||
{
|
||||
if (utils::IsNullOrEmptyString($sValue))
|
||||
if (strlen($sValue) == 0)
|
||||
{
|
||||
return '';
|
||||
}
|
||||
@@ -4535,6 +4447,7 @@ class AttributeText extends AttributeString
|
||||
$sStyle = '';
|
||||
if (count($aStyles) > 0)
|
||||
{
|
||||
$aStyles[] = 'overflow:auto';
|
||||
$sStyle = 'style="'.implode(';', $aStyles).'"';
|
||||
}
|
||||
|
||||
@@ -5983,14 +5896,6 @@ class AttributeEnum extends AttributeString
|
||||
$aLocalizedValues[$sKey] = $this->GetValueLabel($sKey);
|
||||
}
|
||||
|
||||
// Sort by label only if necessary
|
||||
// See N°1646 and {@see \MFCompiler::CompileAttributeEnumValues()} for complete information as for why sort on labels is done at runtime while other sorting are done at compile time
|
||||
/** @var \ValueSetEnum $oValueSetDef */
|
||||
$oValueSetDef = $this->GetValuesDef();
|
||||
if ($oValueSetDef->IsSortedByValues()) {
|
||||
asort($aLocalizedValues);
|
||||
}
|
||||
|
||||
return $aLocalizedValues;
|
||||
}
|
||||
|
||||
@@ -6266,7 +6171,7 @@ class AttributeDateTime extends AttributeDBField
|
||||
/**
|
||||
* Load the 3 settings: date format, time format and data_time format from the configuration
|
||||
*/
|
||||
public static function LoadFormatFromConfig()
|
||||
protected static function LoadFormatFromConfig()
|
||||
{
|
||||
$aFormats = MetaModel::GetConfig()->Get('date_and_time_format');
|
||||
$sLang = Dict::GetUserLanguage();
|
||||
@@ -6514,11 +6419,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))
|
||||
@@ -7253,27 +7153,14 @@ class AttributeExternalKey extends AttributeDBFieldVoid
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
if (MetaModel::IsValidObject($proposedValue)) {
|
||||
if (MetaModel::IsValidObject($proposedValue))
|
||||
{
|
||||
return $proposedValue->GetKey();
|
||||
}
|
||||
|
||||
return (int)$proposedValue;
|
||||
}
|
||||
|
||||
/** @inheritdoc @since 3.1 */
|
||||
public function WriteExternalValues(DBObject $oHostObject): void
|
||||
{
|
||||
$sTargetKey = $oHostObject->Get($this->GetCode());
|
||||
$oFilter = DBSearch::FromOQL('SELECT `'.TemporaryObjectDescriptor::class.'` WHERE item_class=:class AND item_id=:id');
|
||||
$oSet = new DBObjectSet($oFilter, [], ['class' => $this->GetTargetClass(), 'id' => $sTargetKey]);
|
||||
while ($oTemporaryObjectDescriptor = $oSet->Fetch()) {
|
||||
$oTemporaryObjectDescriptor->Set('host_class', get_class($oHostObject));
|
||||
$oTemporaryObjectDescriptor->Set('host_id', $oHostObject->GetKey());
|
||||
$oTemporaryObjectDescriptor->Set('host_att_code', $this->GetCode());
|
||||
$oTemporaryObjectDescriptor->DBUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
public function GetMaximumComboLength()
|
||||
{
|
||||
return $this->GetOptional('max_combo_length', MetaModel::GetConfig()->Get('max_combo_length'));
|
||||
@@ -7337,7 +7224,6 @@ class AttributeExternalKey extends AttributeDBFieldVoid
|
||||
|
||||
public function MakeFormField(DBObject $oObject, $oFormField = null)
|
||||
{
|
||||
/** @var \Combodo\iTop\Form\Field\Field $oFormField */
|
||||
if ($oFormField === null) {
|
||||
// Later : We should check $this->Get('display_style') and create a Radio / Select / ... regarding its value
|
||||
$sFormFieldClass = static::GetFormFieldClass();
|
||||
@@ -7368,12 +7254,19 @@ class AttributeExternalKey extends AttributeDBFieldVoid
|
||||
}
|
||||
});
|
||||
}
|
||||
else {
|
||||
else
|
||||
{
|
||||
$oSearch = DBSearch::FromOQL($this->GetValuesDef()->GetFilterExpression());
|
||||
$oSearch->SetInternalParams(array('this' => $oObject));
|
||||
$oFormField->SetSearch($oSearch);
|
||||
}
|
||||
|
||||
// If ExtKey is mandatory, we add a validator to ensure that the value 0 is not selected
|
||||
if ($oObject->GetAttributeFlags($this->GetCode()) & OPT_ATT_MANDATORY)
|
||||
{
|
||||
$oFormField->AddValidator(new NotEmptyExtKeyValidator());
|
||||
}
|
||||
|
||||
parent::MakeFormField($oObject, $oFormField);
|
||||
|
||||
return $oFormField;
|
||||
@@ -7999,17 +7892,6 @@ class AttributeExternalField extends AttributeDefinition
|
||||
return $oExtAttDef->MakeRealValue($proposedValue, $oHostObj);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
* @since 3.1.0 N°6271 Delegate to remote attribute to ensure cascading computed values
|
||||
*/
|
||||
public function GetSQLValues($value)
|
||||
{
|
||||
$oExtAttDef = $this->GetExtAttDef();
|
||||
|
||||
return $oExtAttDef->GetSQLValues($value);
|
||||
}
|
||||
|
||||
public function ScalarToSQL($value)
|
||||
{
|
||||
// This one could be used in case of filtering only
|
||||
@@ -8308,9 +8190,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()
|
||||
*/
|
||||
@@ -8418,7 +8300,7 @@ class AttributeBlob extends AttributeDefinition
|
||||
$aValues[$this->GetCode().'_data'] = '';
|
||||
$aValues[$this->GetCode().'_mimetype'] = '';
|
||||
$aValues[$this->GetCode().'_filename'] = '';
|
||||
$aValues[$this->GetCode().'_downloads_count'] = ormDocument::DEFAULT_DOWNLOADS_COUNT;
|
||||
$aValues[$this->GetCode().'_downloads_count'] = ''; // Note: Should this be set to \ormDocument::DEFAULT_DOWNLOADS_COUNT ?
|
||||
}
|
||||
|
||||
return $aValues;
|
||||
@@ -8551,7 +8433,7 @@ class AttributeBlob extends AttributeDefinition
|
||||
$sFingerprint = '';
|
||||
if ($value instanceOf ormDocument)
|
||||
{
|
||||
$sFingerprint = $value->GetSignature();
|
||||
$sFingerprint = md5($value->GetData());
|
||||
}
|
||||
|
||||
return $sFingerprint;
|
||||
@@ -8608,22 +8490,6 @@ class AttributeBlob extends AttributeDefinition
|
||||
return utils::IsNotNullOrEmptyString($proposedValue->GetData()) && utils::IsNotNullOrEmptyString($proposedValue->GetFileName());
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
* @param \ormDocument $original
|
||||
* @param \ormDocument $value
|
||||
* @since N°6502
|
||||
*/
|
||||
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)) {
|
||||
return;
|
||||
}
|
||||
|
||||
parent::RecordAttChange($oObject, $original, $value);
|
||||
}
|
||||
|
||||
protected function GetChangeRecordAdditionalData(CMDBChangeOp $oMyChangeOp, DBObject $oObject, $original, $value): void
|
||||
{
|
||||
if (is_null($original)) {
|
||||
@@ -8662,20 +8528,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";
|
||||
@@ -8755,7 +8607,7 @@ class AttributeImage extends AttributeBlob
|
||||
$sCssClasses .= ' '.(($bIsCustomImage) ? 'attribute-image-custom' : 'attribute-image-default');
|
||||
|
||||
// Important: If you change this, mind updating edit_image.js as well
|
||||
return '<div class="'.$sCssClasses.'" style="max-width: min('.$sMaxWidthPx.',100%); max-height: min('.$sMaxHeightPx.',100%); aspect-ratio: '.$iMaxWidth.' / '.$iMaxHeight.'">'.$sRet.'</div>';
|
||||
return '<div class="'.$sCssClasses.'" style="max-width: '.$sMaxWidthPx.'; max-height: '.$sMaxHeightPx.'; aspect-ratio: '.$iMaxWidth.' / '.$iMaxHeight.'">'.$sRet.'</div>';
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -8769,7 +8621,7 @@ class AttributeImage extends AttributeBlob
|
||||
* @since 2.7.0 change visibility to protected
|
||||
*/
|
||||
protected function GetHtmlForImageUrl($sUrl, $iMaxWidthPx, $iMaxHeightPx) {
|
||||
return '<img src="'.$sUrl.'" style="max-width: min('.$iMaxWidthPx.',100%); max-height: min('.$iMaxHeightPx.',100%)">';
|
||||
return '<img src="'.$sUrl.'" style="max-width: '.$iMaxWidthPx.'; max-height: '.$iMaxHeightPx.'">';
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -8797,7 +8649,7 @@ class AttributeImage extends AttributeBlob
|
||||
return 'data:'.$value->GetMimeType().';base64,'.base64_encode($value->GetData());
|
||||
}
|
||||
|
||||
return $value->GetDisplayURL(get_class($oHostObject), $oHostObject->GetKey(), $this->GetCode());
|
||||
return $value->GetDownloadURL(get_class($oHostObject), $oHostObject->GetKey(), $this->GetCode());
|
||||
}
|
||||
|
||||
public static function GetFormFieldClass()
|
||||
@@ -8824,11 +8676,8 @@ class AttributeImage extends AttributeBlob
|
||||
}
|
||||
else
|
||||
{
|
||||
$oDefaultImage = $this->Get('default_image');
|
||||
if (is_object($oDefaultImage) && !$oDefaultImage->IsEmpty()) {
|
||||
$oFormField->SetDownloadUrl($oDefaultImage);
|
||||
$oFormField->SetDisplayUrl($oDefaultImage);
|
||||
}
|
||||
$oFormField->SetDownloadUrl($this->Get('default_image'));
|
||||
$oFormField->SetDisplayUrl($this->Get('default_image'));
|
||||
}
|
||||
|
||||
return $oFormField;
|
||||
@@ -11407,9 +11256,6 @@ class AttributeClassAttCodeSet extends AttributeSet
|
||||
}
|
||||
$aAllowedAttributes[$sAttCode] = $sLabel;
|
||||
}
|
||||
// N°6460 Always sort on the labels, not on the datamodel definition order
|
||||
natcasesort($aAllowedAttributes);
|
||||
|
||||
return $aAllowedAttributes;
|
||||
}
|
||||
|
||||
@@ -13019,7 +12865,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
|
||||
@@ -13202,7 +13048,6 @@ class AttributeCustomFields extends AttributeDefinition
|
||||
public function GetHandler($aValues = null)
|
||||
{
|
||||
$sHandlerClass = $this->Get('handler_class');
|
||||
/** @var \TemplateFieldsHandler $oHandler */
|
||||
$oHandler = new $sHandlerClass($this->GetCode());
|
||||
if (!is_null($aValues))
|
||||
{
|
||||
@@ -13227,50 +13072,36 @@ class AttributeCustomFields extends AttributeDefinition
|
||||
/**
|
||||
* Makes the string representation out of the values given by the form defined in GetDisplayForm
|
||||
*/
|
||||
public function ReadValueFromPostedForm($oHostObject, $sFormPrefix) {
|
||||
$aRawData = json_decode(utils::ReadPostedParam("attr_{$sFormPrefix}{$this->GetCode()}", '{}', 'raw_data'), true);
|
||||
public function ReadValueFromPostedForm($oHostObject, $sFormPrefix)
|
||||
{
|
||||
$aRawData = json_decode(utils::ReadPostedParam("attr_{$sFormPrefix}{$this->GetCode()}", '{}', 'raw_data'), true);
|
||||
if ($aRawData != null) {
|
||||
return new ormCustomFieldsValue($oHostObject, $this->GetCode(), $aRawData);
|
||||
}
|
||||
else {
|
||||
} else{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public function MakeRealValue($proposedValue, $oHostObject) {
|
||||
if (is_object($proposedValue) && ($proposedValue instanceof ormCustomFieldsValue)) {
|
||||
if (false === $oHostObject->IsNew()) {
|
||||
// In that case we need additional keys : see \TemplateFieldsHandler::DoBuildForm
|
||||
$aRequestTemplateValues = $proposedValue->GetValues();
|
||||
if (false === array_key_exists('current_template_id', $aRequestTemplateValues)) {
|
||||
$aRequestTemplateValues['current_template_id'] = $aRequestTemplateValues['template_id'];
|
||||
$aRequestTemplateValues['current_template_data'] = $aRequestTemplateValues['template_data'];
|
||||
$proposedValue = new ormCustomFieldsValue($oHostObject, $this->GetCode(), $aRequestTemplateValues);
|
||||
}
|
||||
}
|
||||
|
||||
if (is_null($proposedValue->GetHostObject())) {
|
||||
// the object might not be set : for example in \AttributeCustomFields::FromJSONToValue we don't have the object available :(
|
||||
$proposedValue->SetHostObject($oHostObject);
|
||||
}
|
||||
|
||||
public function MakeRealValue($proposedValue, $oHostObject)
|
||||
{
|
||||
if (is_object($proposedValue) && ($proposedValue instanceof ormCustomFieldsValue))
|
||||
{
|
||||
return $proposedValue;
|
||||
}
|
||||
|
||||
if (is_string($proposedValue)) {
|
||||
elseif (is_string($proposedValue))
|
||||
{
|
||||
$aValues = json_decode($proposedValue, true);
|
||||
|
||||
return new ormCustomFieldsValue($oHostObject, $this->GetCode(), $aValues);
|
||||
}
|
||||
|
||||
if (is_array($proposedValue)) {
|
||||
elseif (is_array($proposedValue))
|
||||
{
|
||||
return new ormCustomFieldsValue($oHostObject, $this->GetCode(), $proposedValue);
|
||||
}
|
||||
|
||||
if (is_null($proposedValue)) {
|
||||
elseif (is_null($proposedValue))
|
||||
{
|
||||
return new ormCustomFieldsValue($oHostObject, $this->GetCode());
|
||||
}
|
||||
|
||||
throw new Exception('Unexpected type for the value of a custom fields attribute: '.gettype($proposedValue));
|
||||
}
|
||||
|
||||
@@ -13395,11 +13226,27 @@ class AttributeCustomFields extends AttributeDefinition
|
||||
*/
|
||||
public function CheckValue(DBObject $oHostObject, $value)
|
||||
{
|
||||
try {
|
||||
try
|
||||
{
|
||||
$oHandler = $this->GetHandler($value->GetValues());
|
||||
$oHandler->BuildForm($oHostObject, '');
|
||||
$ret = $oHandler->Validate($oHostObject);
|
||||
} catch (Exception $e) {
|
||||
$oForm = $oHandler->GetForm();
|
||||
$oForm->Validate();
|
||||
if ($oForm->GetValid())
|
||||
{
|
||||
$ret = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
$aMessages = array();
|
||||
foreach($oForm->GetErrorMessages() as $sFieldId => $aFieldMessages)
|
||||
{
|
||||
$aMessages[] = $sFieldId.': '.implode(', ', $aFieldMessages);
|
||||
}
|
||||
$ret = 'Invalid value: '.implode(', ', $aMessages);
|
||||
}
|
||||
} catch (Exception $e)
|
||||
{
|
||||
$ret = $e->getMessage();
|
||||
}
|
||||
|
||||
@@ -13541,13 +13388,11 @@ class AttributeCustomFields extends AttributeDefinition
|
||||
/**
|
||||
* @inheritDoc
|
||||
*
|
||||
* @return ?\ormCustomFieldsValue with empty host object as we don't have it here (most consumers don't have an object in their context, for example in \RestUtils::GetObjectSetFromKey)
|
||||
* The host object will be set in {@see MakeRealValue}
|
||||
* All the necessary checks will be done in {@see CheckValue}
|
||||
* @return ?\ormCustomFieldsValue
|
||||
*/
|
||||
public function FromJSONToValue($json)
|
||||
{
|
||||
return ormCustomFieldsValue::FromJSONToValue($json, $this);
|
||||
return null;
|
||||
}
|
||||
|
||||
public function Equals($val1, $val2)
|
||||
|
||||
@@ -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');
|
||||
@@ -36,7 +35,6 @@ MetaModel::IncludeModule('synchro/synchrodatasource.class.inc.php');
|
||||
MetaModel::IncludeModule('core/backgroundtask.class.inc.php');
|
||||
MetaModel::IncludeModule('core/inlineimage.class.inc.php');
|
||||
MetaModel::IncludeModule('core/counter.class.inc.php');
|
||||
MetaModel::IncludeModule('core/TemporaryObjectDescriptor.php');
|
||||
|
||||
MetaModel::IncludeModule('webservices/webservices.basic.php');
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -40,14 +37,6 @@ abstract class CellChangeSpec
|
||||
return $this->m_proposedValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 3.1.0 N°5305
|
||||
*/
|
||||
public function SetDisplayableValue(string $sDisplayableValue)
|
||||
{
|
||||
$this->m_proposedValue = $sDisplayableValue;
|
||||
}
|
||||
|
||||
public function GetOql()
|
||||
{
|
||||
return $this->m_sOql;
|
||||
@@ -147,12 +136,6 @@ class CellStatus_SearchIssue extends CellStatus_Issue
|
||||
/** @var string|null $m_sTargetClass */
|
||||
private $m_sTargetClass;
|
||||
|
||||
/**
|
||||
* @since 3.1.0 N°5305
|
||||
* @var string $sAllowedValuesSearch
|
||||
*/
|
||||
private $sAllowedValuesSearch;
|
||||
|
||||
/**
|
||||
* CellStatus_SearchIssue constructor.
|
||||
* @since 3.1.0 N°5305
|
||||
@@ -161,15 +144,13 @@ class CellStatus_SearchIssue extends CellStatus_Issue
|
||||
* @param string $sReason : main message
|
||||
* @param null $sClass : used for additional message that provides allowed values for current class $sClass
|
||||
* @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)
|
||||
{
|
||||
parent::__construct(null, null, $sReason);
|
||||
$this->sSerializedSearch = $sSerializedSearch;
|
||||
$this->m_sAllowedValues = $sAllowedValues;
|
||||
$this->m_sTargetClass = $sClass;
|
||||
$this->sAllowedValuesSearch = $sAllowedValuesSearch;
|
||||
}
|
||||
|
||||
public function GetDisplayableValue()
|
||||
@@ -198,18 +179,7 @@ class CellStatus_SearchIssue extends CellStatus_Issue
|
||||
public function GetSearchLinkUrl()
|
||||
{
|
||||
return sprintf("UI.php?operation=search&filter=%s",
|
||||
rawurlencode($this->sSerializedSearch ?? "")
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 3.1.0 N°5305
|
||||
* @return null|string
|
||||
*/
|
||||
public function GetAllowedValuesLinkUrl(): ?string
|
||||
{
|
||||
return sprintf("UI.php?operation=search&filter=%s",
|
||||
rawurlencode($this->sAllowedValuesSearch ?? "")
|
||||
rawurlencode($this->sSerializedSearch)
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -265,7 +235,7 @@ class CellStatus_Ambiguous extends CellStatus_Issue
|
||||
public function GetSearchLinkUrl()
|
||||
{
|
||||
return sprintf("UI.php?operation=search&filter=%s",
|
||||
rawurlencode($this->sSerializedSearch ?? "")
|
||||
rawurlencode($this->sSerializedSearch)
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -775,7 +745,6 @@ class BulkChange
|
||||
$oDbSearchWithoutAnyCondition->AllowAllData(false);
|
||||
$oExtObjectSetWithCurrentUserPermissions = new CMDBObjectSet($oDbSearchWithoutAnyCondition);
|
||||
$iCurrentUserRightsObjectCount = $oExtObjectSetWithCurrentUserPermissions->Count();
|
||||
$sAllowedValuesOql = $oDbSearchWithoutAnyCondition->serialize();
|
||||
|
||||
if ($iCurrentUserRightsObjectCount === 0){
|
||||
// No objects visible by current user
|
||||
@@ -816,7 +785,7 @@ class BulkChange
|
||||
if ($iAllowAllDataObjectCount != $iCurrentUserRightsObjectCount) {
|
||||
// No match and some objects NOT visible by current user. including current search maybe...
|
||||
$sReason = Dict::Format('UI:CSVReport-Value-NoMatch-SomeObjectNotVisibleForCurrentUser', $oDbSearchWithConditions->GetClass());
|
||||
return new CellStatus_SearchIssue($sSerializedSearch, $sReason, $oDbSearchWithConditions->GetClass(), $allowedValues, $sAllowedValuesOql);
|
||||
return new CellStatus_SearchIssue($sSerializedSearch, $sReason, $oDbSearchWithConditions->GetClass(), $allowedValues);
|
||||
}
|
||||
|
||||
// No match. This is not linked to any right issue
|
||||
@@ -827,7 +796,7 @@ class BulkChange
|
||||
}
|
||||
$value =implode(" ", $aCurrentValueFields);
|
||||
$sReason = Dict::Format('UI:CSVReport-Value-NoMatch', $value);
|
||||
return new CellStatus_SearchIssue($sSerializedSearch, $sReason, $oDbSearchWithConditions->GetClass(), $allowedValues, $sAllowedValuesOql);
|
||||
return new CellStatus_SearchIssue($sSerializedSearch, $sReason, $oDbSearchWithConditions->GetClass(), $allowedValues);
|
||||
}
|
||||
|
||||
protected function PrepareMissingObject(&$oTargetObj, &$aErrors)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -19,17 +19,17 @@ class CMDBChange extends DBObject
|
||||
{
|
||||
$aParams = array
|
||||
(
|
||||
"category" => "core/cmdb, grant_by_profile",
|
||||
"key_type" => "autoincrement",
|
||||
"name_attcode" => "date",
|
||||
"state_attcode" => "",
|
||||
"reconc_keys" => array(),
|
||||
"db_table" => "priv_change",
|
||||
"db_key_field" => "id",
|
||||
"category" => "core/cmdb",
|
||||
"key_type" => "autoincrement",
|
||||
"name_attcode" => "date",
|
||||
"state_attcode" => "",
|
||||
"reconc_keys" => array(),
|
||||
"db_table" => "priv_change",
|
||||
"db_key_field" => "id",
|
||||
"db_finalclass_field" => "",
|
||||
'indexes' => array(
|
||||
'indexes' => array(
|
||||
array('origin'),
|
||||
),
|
||||
)
|
||||
);
|
||||
MetaModel::Init_Params($aParams);
|
||||
//MetaModel::Init_InheritAttributes();
|
||||
|
||||
@@ -52,17 +52,17 @@ class CMDBChangeOp extends DBObject implements iCMDBChangeOp
|
||||
{
|
||||
$aParams = array
|
||||
(
|
||||
"category" => "core/cmdb, grant_by_profile",
|
||||
"key_type" => "autoincrement",
|
||||
"name_attcode" => "change",
|
||||
"state_attcode" => "",
|
||||
"reconc_keys" => array(),
|
||||
"db_table" => "priv_changeop",
|
||||
"db_key_field" => "id",
|
||||
"category" => "core/cmdb",
|
||||
"key_type" => "autoincrement",
|
||||
"name_attcode" => "change",
|
||||
"state_attcode" => "",
|
||||
"reconc_keys" => array(),
|
||||
"db_table" => "priv_changeop",
|
||||
"db_key_field" => "id",
|
||||
"db_finalclass_field" => "optype",
|
||||
'indexes' => array(
|
||||
'indexes' => array(
|
||||
array('objclass', 'objkey'),
|
||||
),
|
||||
)
|
||||
);
|
||||
MetaModel::Init_Params($aParams);
|
||||
//MetaModel::Init_InheritAttributes();
|
||||
@@ -121,13 +121,13 @@ class CMDBChangeOpCreate extends CMDBChangeOp
|
||||
{
|
||||
$aParams = array
|
||||
(
|
||||
"category" => "core/cmdb, grant_by_profile",
|
||||
"key_type" => "",
|
||||
"name_attcode" => "change",
|
||||
"state_attcode" => "",
|
||||
"reconc_keys" => array(),
|
||||
"db_table" => "priv_changeop_create",
|
||||
"db_key_field" => "id",
|
||||
"category" => "core/cmdb",
|
||||
"key_type" => "",
|
||||
"name_attcode" => "change",
|
||||
"state_attcode" => "",
|
||||
"reconc_keys" => array(),
|
||||
"db_table" => "priv_changeop_create",
|
||||
"db_key_field" => "id",
|
||||
"db_finalclass_field" => "",
|
||||
);
|
||||
MetaModel::Init_Params($aParams);
|
||||
@@ -157,13 +157,13 @@ class CMDBChangeOpDelete extends CMDBChangeOp
|
||||
{
|
||||
$aParams = array
|
||||
(
|
||||
"category" => "core/cmdb, grant_by_profile",
|
||||
"key_type" => "",
|
||||
"name_attcode" => "change",
|
||||
"state_attcode" => "",
|
||||
"reconc_keys" => array(),
|
||||
"db_table" => "priv_changeop_delete",
|
||||
"db_key_field" => "id",
|
||||
"category" => "core/cmdb",
|
||||
"key_type" => "",
|
||||
"name_attcode" => "change",
|
||||
"state_attcode" => "",
|
||||
"reconc_keys" => array(),
|
||||
"db_table" => "priv_changeop_delete",
|
||||
"db_key_field" => "id",
|
||||
"db_finalclass_field" => "",
|
||||
);
|
||||
MetaModel::Init_Params($aParams);
|
||||
@@ -198,13 +198,13 @@ class CMDBChangeOpSetAttribute extends CMDBChangeOp
|
||||
{
|
||||
$aParams = array
|
||||
(
|
||||
"category" => "core/cmdb, grant_by_profile",
|
||||
"key_type" => "",
|
||||
"name_attcode" => "change",
|
||||
"state_attcode" => "",
|
||||
"reconc_keys" => array(),
|
||||
"db_table" => "priv_changeop_setatt",
|
||||
"db_key_field" => "id",
|
||||
"category" => "core/cmdb",
|
||||
"key_type" => "",
|
||||
"name_attcode" => "change",
|
||||
"state_attcode" => "",
|
||||
"reconc_keys" => array(),
|
||||
"db_table" => "priv_changeop_setatt",
|
||||
"db_key_field" => "id",
|
||||
"db_finalclass_field" => "",
|
||||
);
|
||||
MetaModel::Init_Params($aParams);
|
||||
@@ -231,13 +231,13 @@ class CMDBChangeOpSetAttributeScalar extends CMDBChangeOpSetAttribute
|
||||
{
|
||||
$aParams = array
|
||||
(
|
||||
"category" => "core/cmdb, grant_by_profile",
|
||||
"key_type" => "",
|
||||
"name_attcode" => "change",
|
||||
"state_attcode" => "",
|
||||
"reconc_keys" => array(),
|
||||
"db_table" => "priv_changeop_setatt_scalar",
|
||||
"db_key_field" => "id",
|
||||
"category" => "core/cmdb",
|
||||
"key_type" => "",
|
||||
"name_attcode" => "change",
|
||||
"state_attcode" => "",
|
||||
"reconc_keys" => array(),
|
||||
"db_table" => "priv_changeop_setatt_scalar",
|
||||
"db_key_field" => "id",
|
||||
"db_finalclass_field" => "",
|
||||
);
|
||||
MetaModel::Init_Params($aParams);
|
||||
@@ -290,14 +290,14 @@ class CMDBChangeOpSetAttributeTagSet extends CMDBChangeOpSetAttribute
|
||||
{
|
||||
$aParams = array
|
||||
(
|
||||
"category" => "core/cmdb, grant_by_profile",
|
||||
"key_type" => "",
|
||||
"name_attcode" => "change",
|
||||
"state_attcode" => "",
|
||||
"reconc_keys" => array(),
|
||||
"db_table" => "priv_changeop_setatt_tagset",
|
||||
"db_key_field" => "id",
|
||||
"db_finalclass_field" => "",
|
||||
"category" => "core/cmdb",
|
||||
"key_type" => "",
|
||||
"name_attcode" => "change",
|
||||
"state_attcode" => "",
|
||||
"reconc_keys" => array(),
|
||||
"db_table" => "priv_changeop_setatt_tagset",
|
||||
"db_key_field" => "id",
|
||||
"db_finalclass_field" => "",
|
||||
);
|
||||
MetaModel::Init_Params($aParams);
|
||||
MetaModel::Init_InheritAttributes();
|
||||
@@ -350,7 +350,7 @@ class CMDBChangeOpSetAttributeURL extends CMDBChangeOpSetAttribute
|
||||
{
|
||||
$aParams = array
|
||||
(
|
||||
"category" => "core/cmdb, grant_by_profile",
|
||||
"category" => "core/cmdb",
|
||||
"key_type" => "",
|
||||
"name_attcode" => "change",
|
||||
"state_attcode" => "",
|
||||
@@ -419,13 +419,13 @@ class CMDBChangeOpSetAttributeBlob extends CMDBChangeOpSetAttribute
|
||||
{
|
||||
$aParams = array
|
||||
(
|
||||
"category" => "core/cmdb, grant_by_profile",
|
||||
"key_type" => "",
|
||||
"name_attcode" => "change",
|
||||
"state_attcode" => "",
|
||||
"reconc_keys" => array(),
|
||||
"db_table" => "priv_changeop_setatt_data",
|
||||
"db_key_field" => "id",
|
||||
"category" => "core/cmdb",
|
||||
"key_type" => "",
|
||||
"name_attcode" => "change",
|
||||
"state_attcode" => "",
|
||||
"reconc_keys" => array(),
|
||||
"db_table" => "priv_changeop_setatt_data",
|
||||
"db_key_field" => "id",
|
||||
"db_finalclass_field" => "",
|
||||
);
|
||||
MetaModel::Init_Params($aParams);
|
||||
@@ -498,13 +498,13 @@ class CMDBChangeOpSetAttributeOneWayPassword extends CMDBChangeOpSetAttribute
|
||||
{
|
||||
$aParams = array
|
||||
(
|
||||
"category" => "core/cmdb, grant_by_profile",
|
||||
"key_type" => "",
|
||||
"name_attcode" => "change",
|
||||
"state_attcode" => "",
|
||||
"reconc_keys" => array(),
|
||||
"db_table" => "priv_changeop_setatt_pwd",
|
||||
"db_key_field" => "id",
|
||||
"category" => "core/cmdb",
|
||||
"key_type" => "",
|
||||
"name_attcode" => "change",
|
||||
"state_attcode" => "",
|
||||
"reconc_keys" => array(),
|
||||
"db_table" => "priv_changeop_setatt_pwd",
|
||||
"db_key_field" => "id",
|
||||
"db_finalclass_field" => "",
|
||||
);
|
||||
MetaModel::Init_Params($aParams);
|
||||
@@ -561,13 +561,13 @@ class CMDBChangeOpSetAttributeEncrypted extends CMDBChangeOpSetAttribute
|
||||
{
|
||||
$aParams = array
|
||||
(
|
||||
"category" => "core/cmdb, grant_by_profile",
|
||||
"key_type" => "",
|
||||
"name_attcode" => "change",
|
||||
"state_attcode" => "",
|
||||
"reconc_keys" => array(),
|
||||
"db_table" => "priv_changeop_setatt_encrypted",
|
||||
"db_key_field" => "id",
|
||||
"category" => "core/cmdb",
|
||||
"key_type" => "",
|
||||
"name_attcode" => "change",
|
||||
"state_attcode" => "",
|
||||
"reconc_keys" => array(),
|
||||
"db_table" => "priv_changeop_setatt_encrypted",
|
||||
"db_key_field" => "id",
|
||||
"db_finalclass_field" => "",
|
||||
);
|
||||
MetaModel::Init_Params($aParams);
|
||||
@@ -627,13 +627,13 @@ class CMDBChangeOpSetAttributeText extends CMDBChangeOpSetAttribute
|
||||
{
|
||||
$aParams = array
|
||||
(
|
||||
"category" => "core/cmdb, grant_by_profile",
|
||||
"key_type" => "",
|
||||
"name_attcode" => "change",
|
||||
"state_attcode" => "",
|
||||
"reconc_keys" => array(),
|
||||
"db_table" => "priv_changeop_setatt_text",
|
||||
"db_key_field" => "id",
|
||||
"category" => "core/cmdb",
|
||||
"key_type" => "",
|
||||
"name_attcode" => "change",
|
||||
"state_attcode" => "",
|
||||
"reconc_keys" => array(),
|
||||
"db_table" => "priv_changeop_setatt_text",
|
||||
"db_key_field" => "id",
|
||||
"db_finalclass_field" => "",
|
||||
);
|
||||
MetaModel::Init_Params($aParams);
|
||||
@@ -695,13 +695,13 @@ class CMDBChangeOpSetAttributeLongText extends CMDBChangeOpSetAttribute
|
||||
{
|
||||
$aParams = array
|
||||
(
|
||||
"category" => "core/cmdb, grant_by_profile",
|
||||
"key_type" => "",
|
||||
"name_attcode" => "change",
|
||||
"state_attcode" => "",
|
||||
"reconc_keys" => array(),
|
||||
"db_table" => "priv_changeop_setatt_longtext",
|
||||
"db_key_field" => "id",
|
||||
"category" => "core/cmdb",
|
||||
"key_type" => "",
|
||||
"name_attcode" => "change",
|
||||
"state_attcode" => "",
|
||||
"reconc_keys" => array(),
|
||||
"db_table" => "priv_changeop_setatt_longtext",
|
||||
"db_key_field" => "id",
|
||||
"db_finalclass_field" => "",
|
||||
);
|
||||
MetaModel::Init_Params($aParams);
|
||||
@@ -760,13 +760,13 @@ class CMDBChangeOpSetAttributeHTML extends CMDBChangeOpSetAttributeLongText
|
||||
{
|
||||
$aParams = array
|
||||
(
|
||||
"category" => "core/cmdb, grant_by_profile",
|
||||
"key_type" => "",
|
||||
"name_attcode" => "change",
|
||||
"state_attcode" => "",
|
||||
"reconc_keys" => array(),
|
||||
"db_table" => "priv_changeop_setatt_html",
|
||||
"db_key_field" => "id",
|
||||
"category" => "core/cmdb",
|
||||
"key_type" => "",
|
||||
"name_attcode" => "change",
|
||||
"state_attcode" => "",
|
||||
"reconc_keys" => array(),
|
||||
"db_table" => "priv_changeop_setatt_html",
|
||||
"db_key_field" => "id",
|
||||
"db_finalclass_field" => "",
|
||||
);
|
||||
MetaModel::Init_Params($aParams);
|
||||
@@ -824,13 +824,13 @@ class CMDBChangeOpSetAttributeCaseLog extends CMDBChangeOpSetAttribute
|
||||
{
|
||||
$aParams = array
|
||||
(
|
||||
"category" => "core/cmdb, grant_by_profile",
|
||||
"key_type" => "",
|
||||
"name_attcode" => "change",
|
||||
"state_attcode" => "",
|
||||
"reconc_keys" => array(),
|
||||
"db_table" => "priv_changeop_setatt_log",
|
||||
"db_key_field" => "id",
|
||||
"category" => "core/cmdb",
|
||||
"key_type" => "",
|
||||
"name_attcode" => "change",
|
||||
"state_attcode" => "",
|
||||
"reconc_keys" => array(),
|
||||
"db_table" => "priv_changeop_setatt_log",
|
||||
"db_key_field" => "id",
|
||||
"db_finalclass_field" => "",
|
||||
);
|
||||
MetaModel::Init_Params($aParams);
|
||||
@@ -903,13 +903,13 @@ class CMDBChangeOpPlugin extends CMDBChangeOp
|
||||
{
|
||||
$aParams = array
|
||||
(
|
||||
"category" => "core/cmdb, grant_by_profile",
|
||||
"key_type" => "",
|
||||
"name_attcode" => "change",
|
||||
"state_attcode" => "",
|
||||
"reconc_keys" => array(),
|
||||
"db_table" => "priv_changeop_plugin",
|
||||
"db_key_field" => "id",
|
||||
"category" => "core/cmdb",
|
||||
"key_type" => "",
|
||||
"name_attcode" => "change",
|
||||
"state_attcode" => "",
|
||||
"reconc_keys" => array(),
|
||||
"db_table" => "priv_changeop_plugin",
|
||||
"db_key_field" => "id",
|
||||
"db_finalclass_field" => "",
|
||||
);
|
||||
MetaModel::Init_Params($aParams);
|
||||
@@ -944,13 +944,13 @@ abstract class CMDBChangeOpSetAttributeLinks extends CMDBChangeOpSetAttribute
|
||||
{
|
||||
$aParams = array
|
||||
(
|
||||
"category" => "core/cmdb, grant_by_profile",
|
||||
"key_type" => "",
|
||||
"name_attcode" => "change",
|
||||
"state_attcode" => "",
|
||||
"reconc_keys" => array(),
|
||||
"db_table" => "priv_changeop_links",
|
||||
"db_key_field" => "id",
|
||||
"category" => "core/cmdb",
|
||||
"key_type" => "",
|
||||
"name_attcode" => "change",
|
||||
"state_attcode" => "",
|
||||
"reconc_keys" => array(),
|
||||
"db_table" => "priv_changeop_links",
|
||||
"db_key_field" => "id",
|
||||
"db_finalclass_field" => "",
|
||||
);
|
||||
MetaModel::Init_Params($aParams);
|
||||
@@ -977,13 +977,13 @@ class CMDBChangeOpSetAttributeLinksAddRemove extends CMDBChangeOpSetAttributeLin
|
||||
{
|
||||
$aParams = array
|
||||
(
|
||||
"category" => "core/cmdb, grant_by_profile",
|
||||
"key_type" => "",
|
||||
"name_attcode" => "change",
|
||||
"state_attcode" => "",
|
||||
"reconc_keys" => array(),
|
||||
"db_table" => "priv_changeop_links_addremove",
|
||||
"db_key_field" => "id",
|
||||
"category" => "core/cmdb",
|
||||
"key_type" => "",
|
||||
"name_attcode" => "change",
|
||||
"state_attcode" => "",
|
||||
"reconc_keys" => array(),
|
||||
"db_table" => "priv_changeop_links_addremove",
|
||||
"db_key_field" => "id",
|
||||
"db_finalclass_field" => "",
|
||||
);
|
||||
MetaModel::Init_Params($aParams);
|
||||
@@ -1044,13 +1044,13 @@ class CMDBChangeOpSetAttributeLinksTune extends CMDBChangeOpSetAttributeLinks
|
||||
{
|
||||
$aParams = array
|
||||
(
|
||||
"category" => "core/cmdb, grant_by_profile",
|
||||
"key_type" => "",
|
||||
"name_attcode" => "change",
|
||||
"state_attcode" => "",
|
||||
"reconc_keys" => array(),
|
||||
"db_table" => "priv_changeop_links_tune",
|
||||
"db_key_field" => "id",
|
||||
"category" => "core/cmdb",
|
||||
"key_type" => "",
|
||||
"name_attcode" => "change",
|
||||
"state_attcode" => "",
|
||||
"reconc_keys" => array(),
|
||||
"db_table" => "priv_changeop_links_tune",
|
||||
"db_key_field" => "id",
|
||||
"db_finalclass_field" => "",
|
||||
);
|
||||
MetaModel::Init_Params($aParams);
|
||||
@@ -1134,13 +1134,13 @@ class CMDBChangeOpSetAttributeCustomFields extends CMDBChangeOpSetAttribute
|
||||
{
|
||||
$aParams = array
|
||||
(
|
||||
"category" => "core/cmdb, grant_by_profile",
|
||||
"key_type" => "",
|
||||
"name_attcode" => "change",
|
||||
"state_attcode" => "",
|
||||
"reconc_keys" => array(),
|
||||
"db_table" => "priv_changeop_setatt_custfields",
|
||||
"db_key_field" => "id",
|
||||
"category" => "core/cmdb",
|
||||
"key_type" => "",
|
||||
"name_attcode" => "change",
|
||||
"state_attcode" => "",
|
||||
"reconc_keys" => array(),
|
||||
"db_table" => "priv_changeop_setatt_custfields",
|
||||
"db_key_field" => "id",
|
||||
"db_finalclass_field" => "",
|
||||
);
|
||||
MetaModel::Init_Params($aParams);
|
||||
|
||||
@@ -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);
|
||||
@@ -473,14 +469,21 @@ abstract class CMDBObject extends DBObject
|
||||
*/
|
||||
public function DBDelete(&$oDeletionPlan = null)
|
||||
{
|
||||
$this->LogCRUDEnter(__METHOD__);
|
||||
$oDeletionPlan = parent::DBDelete($oDeletionPlan);
|
||||
$this->LogCRUDExit(__METHOD__);
|
||||
return $oDeletionPlan;
|
||||
return $this->DBDeleteTracked_Internal($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)
|
||||
{
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -436,7 +431,6 @@ class CMDBSource
|
||||
{
|
||||
self::$m_sDBName = '';
|
||||
}
|
||||
self::_TablesInfoCacheReset(); // reset the table info cache!
|
||||
}
|
||||
|
||||
public static function CreateTable($sQuery)
|
||||
@@ -613,9 +607,8 @@ class CMDBSource
|
||||
{
|
||||
self::LogDeadLock($e, true);
|
||||
throw new MySQLException('Failed to issue SQL query', array('query' => $sSql, $e));
|
||||
} finally {
|
||||
$oKPI->ComputeStats('Query exec (mySQL)', $sSql);
|
||||
}
|
||||
}
|
||||
$oKPI->ComputeStats('Query exec (mySQL)', $sSql);
|
||||
if ($oResult === false) {
|
||||
$aContext = array('query' => $sSql);
|
||||
|
||||
@@ -633,24 +626,18 @@ class CMDBSource
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Exception $e
|
||||
* @param \Exception $e
|
||||
* @param bool $bForQuery to get the proper DB connection
|
||||
* @param bool $bCheckMysqliErrno if false won't try to check for mysqli::errno value
|
||||
*
|
||||
* @since 2.7.1
|
||||
* @since 3.0.0 N°4325 add new optional parameter to use the correct DB connection
|
||||
* @since 3.0.4 3.1.1 3.2.0 N°6643 new bCheckMysqliErrno parameter as a workaround for mysqli::errno cannot be mocked
|
||||
*/
|
||||
private static function LogDeadLock(Exception $e, $bForQuery = false, $bCheckMysqliErrno = true)
|
||||
private static function LogDeadLock(Exception $e, $bForQuery = false)
|
||||
{
|
||||
// checks MySQL error code
|
||||
if ($bCheckMysqliErrno) {
|
||||
$iMySqlErrorNo = DbConnectionWrapper::GetDbConnection($bForQuery)->errno;
|
||||
if (!in_array($iMySqlErrorNo, array(self::MYSQL_ERRNO_WAIT_TIMEOUT, self::MYSQL_ERRNO_DEADLOCK))) {
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
$iMySqlErrorNo = "N/A";
|
||||
$iMySqlErrorNo = DbConnectionWrapper::GetDbConnection($bForQuery)->errno;
|
||||
if (!in_array($iMySqlErrorNo, array(self::MYSQL_ERRNO_WAIT_TIMEOUT, self::MYSQL_ERRNO_DEADLOCK))) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Get error info
|
||||
@@ -677,10 +664,7 @@ class CMDBSource
|
||||
);
|
||||
DeadLockLog::Info($sMessage, $iMySqlErrorNo, $aLogContext);
|
||||
|
||||
IssueLog::Error($sMessage, LogChannels::DEADLOCK, [
|
||||
'exception.class' => get_class($e),
|
||||
'exception.message' => $e->getMessage(),
|
||||
]);
|
||||
IssueLog::Error($sMessage, LogChannels::DEADLOCK, $e->getMessage());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -939,7 +923,7 @@ class CMDBSource
|
||||
{
|
||||
throw new MySQLException('Failed to issue SQL query', array('query' => $sSql));
|
||||
}
|
||||
|
||||
|
||||
while ($aRow = $oResult->fetch_array($iMode))
|
||||
{
|
||||
$aData[] = $aRow;
|
||||
@@ -1093,7 +1077,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 +1088,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 +1355,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 +1494,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 +1503,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 +1519,7 @@ class CMDBSource
|
||||
/**
|
||||
* Returns the privileges of the current user
|
||||
* @return string privileges in a raw format
|
||||
*/
|
||||
*/
|
||||
public static function GetRawPrivileges()
|
||||
{
|
||||
try
|
||||
@@ -1561,8 +1545,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
|
||||
|
||||
@@ -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.0-dev');
|
||||
|
||||
define('ITOP_VERSION_NAME', 'Fullmoon');
|
||||
define('ITOP_REVISION', 'svn');
|
||||
@@ -137,7 +137,7 @@ class Config
|
||||
'source_of_value' => '',
|
||||
'show_in_conf_sample' => false,
|
||||
],
|
||||
'log_purge.max_keep_days' => [
|
||||
'log_purge.max_keep_days' => [
|
||||
'type' => 'integer',
|
||||
'description' => 'Optional purge number of days to keep logs.',
|
||||
'default' => 365,
|
||||
@@ -145,7 +145,7 @@ class Config
|
||||
'source_of_value' => '',
|
||||
'show_in_conf_sample' => false,
|
||||
],
|
||||
'event_service.debug.filter_events' => [
|
||||
'event_service.debug.filter_events' => [
|
||||
'type' => 'array',
|
||||
'description' => 'List of events name to filter Event Service debug messages',
|
||||
'default' => [],
|
||||
@@ -153,7 +153,7 @@ class Config
|
||||
'source_of_value' => '',
|
||||
'show_in_conf_sample' => false,
|
||||
],
|
||||
'event_service.debug.filter_sources' => [
|
||||
'event_service.debug.filter_sources' => [
|
||||
'type' => 'array',
|
||||
'description' => 'List of event sources to filter Event Service debug messages',
|
||||
'default' => '',
|
||||
@@ -161,38 +161,6 @@ class Config
|
||||
'source_of_value' => '',
|
||||
'show_in_conf_sample' => false,
|
||||
],
|
||||
'temporary_object.force_creation' => [
|
||||
'type' => 'bool',
|
||||
'description' => 'If true, all the objects created by the external key are temporary',
|
||||
'default' => false,
|
||||
'value' => false,
|
||||
'source_of_value' => '',
|
||||
'show_in_conf_sample' => false,
|
||||
],
|
||||
'temporary_object.lifetime' => [
|
||||
'type' => 'integer',
|
||||
'description' => 'Seconds for temporary objects created',
|
||||
'default' => 300,
|
||||
'value' => 300,
|
||||
'source_of_value' => '',
|
||||
'show_in_conf_sample' => false,
|
||||
],
|
||||
'temporary_object.watchdog_interval' => [
|
||||
'type' => 'integer',
|
||||
'description' => 'Seconds between watchdog signals',
|
||||
'default' => 60,
|
||||
'value' => false,
|
||||
'source_of_value' => '',
|
||||
'show_in_conf_sample' => false,
|
||||
],
|
||||
'temporary_object.garbage_interval' => [
|
||||
'type' => 'integer',
|
||||
'description' => 'Seconds between garbage collections',
|
||||
'default' => 60,
|
||||
'value' => false,
|
||||
'source_of_value' => '',
|
||||
'show_in_conf_sample' => false,
|
||||
],
|
||||
'app_env_label' => [
|
||||
'type' => 'string',
|
||||
'description' => 'Label displayed to describe the current application environment, defaults to the environment name (e.g. "production")',
|
||||
@@ -217,7 +185,7 @@ class Config
|
||||
'source_of_value' => '',
|
||||
'show_in_conf_sample' => false,
|
||||
],
|
||||
'db_host' => [
|
||||
'db_host' => [
|
||||
'type' => 'string',
|
||||
'default' => null,
|
||||
'value' => '',
|
||||
@@ -447,14 +415,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',
|
||||
@@ -515,7 +483,7 @@ class Config
|
||||
'synchro_obsolete_replica_locks_object' => [
|
||||
'type' => 'bool',
|
||||
'description' => 'Obsolete synchro replicas prevent object modification by any mean (eg. anonymization)',
|
||||
'default' => true,
|
||||
'default' => 'true',
|
||||
'value' => '',
|
||||
'source_of_value' => '',
|
||||
'show_in_conf_sample' => true,
|
||||
@@ -656,22 +624,22 @@ class Config
|
||||
'source_of_value' => '',
|
||||
'show_in_conf_sample' => false,
|
||||
],
|
||||
'email_transport_smtp.allow_self_signed' => [
|
||||
'email_transport_smtp.allow_self_signed' => array(
|
||||
'type' => 'bool',
|
||||
'description' => 'Allow self signed peer certificates',
|
||||
'default' => false,
|
||||
'value' => false,
|
||||
'source_of_value' => '',
|
||||
'show_in_conf_sample' => false,
|
||||
],
|
||||
'email_transport_smtp.verify_peer' => [
|
||||
),
|
||||
'email_transport_smtp.verify_peer' => array(
|
||||
'type' => 'bool',
|
||||
'description' => 'Verify peer certificate',
|
||||
'default' => true,
|
||||
'value' => true,
|
||||
'source_of_value' => '',
|
||||
'show_in_conf_sample' => false,
|
||||
],
|
||||
),
|
||||
'email_css' => [
|
||||
'type' => 'string',
|
||||
'description' => 'CSS that will override the standard stylesheet used for the notifications',
|
||||
@@ -889,14 +857,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$',
|
||||
@@ -986,14 +946,6 @@ class Config
|
||||
'source_of_value' => '',
|
||||
'show_in_conf_sample' => false,
|
||||
],
|
||||
'lifecycle.transitions_sort_type' => [
|
||||
'type' => 'string',
|
||||
'description' => 'How transitions will be sorted in the GUI. Possible values are "xml", "alphabetical", "fixed" or "relative"',
|
||||
'default' => DBObject::DEFAULT_TRANSITIONS_SORT_TYPE,
|
||||
'value' => DBObject::DEFAULT_TRANSITIONS_SORT_TYPE,
|
||||
'source_of_value' => '',
|
||||
'show_in_conf_sample' => true,
|
||||
],
|
||||
'url_validation_pattern' => [
|
||||
'type' => 'string',
|
||||
'description' => 'Regular expression to validate/detect the format of an URL (URL attributes and Wiki formatting for Text attributes)',
|
||||
@@ -1077,14 +1029,6 @@ class Config
|
||||
'source_of_value' => '',
|
||||
'show_in_conf_sample' => false,
|
||||
],
|
||||
'log_kpi_generate_legacy_report' => [
|
||||
'type' => 'bool',
|
||||
'description' => 'Generate the legacy KPI report (kpi.html)',
|
||||
'default' => true,
|
||||
'value' => '',
|
||||
'source_of_value' => '',
|
||||
'show_in_conf_sample' => false,
|
||||
],
|
||||
'max_linkset_output' => [
|
||||
'type' => 'integer',
|
||||
'description' => 'Maximum number of items shown when getting a list of related items in an email, using the form $this->some_list$. 0 means no limit.',
|
||||
@@ -1119,14 +1063,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 +1145,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 +1244,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 +1523,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 +1571,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!',
|
||||
@@ -1758,16 +1630,8 @@ class Config
|
||||
'audit.enable_selection_landing_page' => [
|
||||
'type' => 'bool',
|
||||
'description' => 'If true audit categories must be selected before results are computed (use this setting in case of a lot of audit categories)',
|
||||
'default' => true,
|
||||
'value' => true,
|
||||
'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' => '',
|
||||
'default' => false,
|
||||
'value' => false,
|
||||
'source_of_value' => '',
|
||||
'show_in_conf_sample' => false,
|
||||
],
|
||||
@@ -1898,7 +1762,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 +1814,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 +1858,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 +2018,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 +2153,6 @@ class Config
|
||||
return $this->m_sEncryptionKey;
|
||||
}
|
||||
|
||||
public function GetAppSecret()
|
||||
{
|
||||
return $this->m_sAppSecret;
|
||||
}
|
||||
|
||||
public function GetEncryptionLibrary()
|
||||
{
|
||||
return $this->m_sEncryptionLibrary;
|
||||
@@ -2394,24 +2241,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 +2251,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 +2302,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 +2392,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 +2414,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)
|
||||
{
|
||||
|
||||
@@ -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.
|
||||
@@ -58,16 +58,6 @@ class ContextTag
|
||||
public const TAG_SETUP = 'Setup';
|
||||
public const TAG_SYNCHRO = 'Synchro';
|
||||
public const TAG_REST = 'REST/JSON';
|
||||
|
||||
/**
|
||||
* @since 3.1.0 N°6047
|
||||
*/
|
||||
public const TAG_IMPORT = 'Import';
|
||||
/**
|
||||
* @since 3.1.0 N°6047
|
||||
*/
|
||||
public const TAG_EXPORT = 'Export';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
* @since 3.1.0 N°3200
|
||||
@@ -85,7 +75,7 @@ class ContextTag
|
||||
{
|
||||
static::$aStack[] = $sTag;
|
||||
}
|
||||
|
||||
|
||||
public static function AddContext($sTag)
|
||||
{
|
||||
static::$aStack[] = $sTag;
|
||||
|
||||
@@ -1,11 +1,8 @@
|
||||
<?php
|
||||
/**
|
||||
* This file is only here for compatibility reasons.
|
||||
* It will be removed in future iTop versions (N°6533)
|
||||
* This file is only here for compatibility issues. Will be removed in iTop 3.1.0 (N°3664)
|
||||
*
|
||||
* @deprecated 3.0.0 N°3663 Exception classes were moved to `/application/exceptions`, use autoloader instead of require !
|
||||
*/
|
||||
|
||||
require_once __DIR__ . '/../approot.inc.php';
|
||||
|
||||
DeprecatedCallsLog::NotifyDeprecatedFile('Classes were moved to /application/exceptions and can be used directly with the autoloader');
|
||||
require_once '../approot.inc.php';
|
||||
DeprecatedCallsLog::NotifyDeprecatedFile('Classes were moved to /application/exceptions');
|
||||
|
||||
@@ -188,8 +188,8 @@ final class ItopCounter
|
||||
|
||||
if (!$hDBLink)
|
||||
{
|
||||
throw new MySQLException('Could not connect to the DB server '.mysqli_connect_error().' (mysql errno: '.mysqli_connect_errno(), array('host' => $sDBHost, 'user' => $sDBUser));
|
||||
}
|
||||
throw new Exception("Could not connect to the DB server (host=$sDBHost, user=$sDBUser): ".mysqli_connect_error().' (mysql errno: '.mysqli_connect_errno().')');
|
||||
}
|
||||
|
||||
return $hDBLink;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
@@ -141,7 +137,7 @@ class CSVBulkExport extends TabularBulkExport
|
||||
$aSep['other'] = Dict::S('UI:CSVImport:SeparatorOther').' <input type="text" size="3" name="other-separator" value="'.utils::EscapeHtml($sOtherSeparator).'"/>';
|
||||
|
||||
foreach ($aSep as $sVal => $sLabel) {
|
||||
$oRadio = InputUIBlockFactory::MakeForInputWithLabel($sLabel, "separator", $sVal, $sLabel, "radio");
|
||||
$oRadio = InputUIBlockFactory::MakeForInputWithLabel($sLabel, "separator", utils::EscapeHtml($sVal), $sLabel, "radio");
|
||||
$oRadio->GetInput()->SetIsChecked(($sVal == $sRawSeparator));
|
||||
$oRadio->SetBeforeInput(false);
|
||||
$oRadio->GetInput()->AddCSSClass('ibo-input--label-right');
|
||||
@@ -167,8 +163,8 @@ class CSVBulkExport extends TabularBulkExport
|
||||
$aQualifiers['other'] = Dict::S('UI:CSVImport:QualifierOther').' <input type="text" size="3" name="other-text-qualifier" value="'.utils::EscapeHtml($sOtherQualifier).'"/>';
|
||||
|
||||
foreach ($aQualifiers as $sVal => $sLabel) {
|
||||
$oRadio = InputUIBlockFactory::MakeForInputWithLabel($sLabel, "text-qualifier", $sVal, $sLabel, "radio");
|
||||
$oRadio->GetInput()->SetIsChecked(($sVal == $sRawQualifier));
|
||||
$oRadio = InputUIBlockFactory::MakeForInputWithLabel($sLabel, "text-qualifier", utils::EscapeHtml($sVal), $sLabel, "radio");
|
||||
$oRadio->GetInput()->SetIsChecked(($sVal == $sRawSeparator));
|
||||
$oRadio->SetBeforeInput(false);
|
||||
$oRadio->GetInput()->AddCSSClass('ibo-input--label-right');
|
||||
$oRadio->GetInput()->AddCSSClass('ibo-input-checkbox');
|
||||
|
||||
@@ -23,22 +23,10 @@
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
abstract class CustomFieldsHandler {
|
||||
/** @var string $sAttCode */
|
||||
abstract class CustomFieldsHandler
|
||||
{
|
||||
protected $sAttCode;
|
||||
/** @var array{
|
||||
* legacy: int,
|
||||
* extradata_id: string,
|
||||
* _template_name: string,
|
||||
* template_id: string,
|
||||
* template_data: string,
|
||||
* user_data: array<string, mixed>,
|
||||
* current_template_id: string,
|
||||
* current_template_data: string,
|
||||
* } $aValues same as {@see \ormCustomFieldsValue::$aCurrentValues}
|
||||
*/
|
||||
protected $aValues;
|
||||
/** @var \Combodo\iTop\Form\Form $oForm */
|
||||
protected $oForm;
|
||||
|
||||
/**
|
||||
@@ -47,47 +35,20 @@ abstract class CustomFieldsHandler {
|
||||
*
|
||||
* @param $sAttCode
|
||||
*/
|
||||
final public function __construct($sAttCode) {
|
||||
final public function __construct($sAttCode)
|
||||
{
|
||||
$this->sAttCode = $sAttCode;
|
||||
$this->aValues = null;
|
||||
}
|
||||
|
||||
abstract public function BuildForm(DBObject $oHostObject, $sFormId);
|
||||
|
||||
/**
|
||||
* @returns true|string true if no error found, error message otherwise
|
||||
* @throws \ApplicationException if {@link static::$oForm} attribute not initialized yet
|
||||
* @since 3.1.0 N°6322 N°1150 Add template_id checks
|
||||
*/
|
||||
public function Validate(DBObject $oHostObject) {
|
||||
if (false === isset($this->oForm)) {
|
||||
throw new ApplicationException('oForm attribute not init yet. You must call BuildForm before this method !');
|
||||
}
|
||||
|
||||
try {
|
||||
$this->oForm->Validate();
|
||||
if ($this->oForm->GetValid()) {
|
||||
$ret = true;
|
||||
}
|
||||
else {
|
||||
$aMessages = array();
|
||||
foreach ($this->oForm->GetErrorMessages() as $sFieldId => $aFieldMessages) {
|
||||
$aMessages[] = $sFieldId.': '.implode(', ', $aFieldMessages);
|
||||
}
|
||||
$ret = 'Invalid value: '.implode(', ', $aMessages);
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
$ret = $e->getMessage();
|
||||
}
|
||||
|
||||
return $ret;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return \Combodo\iTop\Form\Form
|
||||
*/
|
||||
public function GetForm() {
|
||||
public function GetForm()
|
||||
{
|
||||
return $this->oForm;
|
||||
}
|
||||
|
||||
@@ -96,14 +57,16 @@ abstract class CustomFieldsHandler {
|
||||
$this->aValues = $aValues;
|
||||
}
|
||||
|
||||
public static function GetPrerequisiteAttributes($sClass = null) {
|
||||
static public function GetPrerequisiteAttributes($sClass = null)
|
||||
{
|
||||
return array();
|
||||
}
|
||||
|
||||
/**
|
||||
* List the available verbs for 'GetForTemplate'
|
||||
*/
|
||||
public static function EnumTemplateVerbs() {
|
||||
static public function EnumTemplateVerbs()
|
||||
{
|
||||
return array();
|
||||
}
|
||||
|
||||
@@ -155,21 +118,6 @@ abstract class CustomFieldsHandler {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \stdClass|null $json
|
||||
* @param string $sAttCode
|
||||
*
|
||||
* @return \ormCustomFieldsValue|null
|
||||
*
|
||||
* @since 3.1.0 N°1150 Method creation
|
||||
*/
|
||||
public function FromJSONToValue(?stdClass $json, string $sAttCode): ?ormCustomFieldsValue
|
||||
{
|
||||
// Default impl doing nothing, to avoid errors on children not having this method
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param DBObject $oHostObject
|
||||
*
|
||||
|
||||
@@ -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">
|
||||
@@ -469,7 +58,6 @@
|
||||
<parent>cmdbAbstractObject</parent>
|
||||
<properties>
|
||||
<category>addon/userrights,grant_by_profile</category>
|
||||
<is_link>1</is_link>
|
||||
</properties>
|
||||
<fields>
|
||||
<field id="userid" xsi:type="AttributeExternalKey">
|
||||
@@ -630,19 +218,6 @@
|
||||
<field id="friendlyname" xsi:type="AttributeFriendlyName"/>
|
||||
</fields>
|
||||
</class>
|
||||
<class id="AuditDomain" _delta="define">
|
||||
<parent>cmdbAbstractObject</parent>
|
||||
<properties>
|
||||
<category>application, grant_by_profile</category>
|
||||
</properties>
|
||||
<fields>
|
||||
<field id="name" xsi:type="AttributeString"/>
|
||||
<field id="description" xsi:type="AttributeString"/>
|
||||
<field id="icon" xsi:type="AttributeImage"/>
|
||||
<field id="categories_list" xsi:type="AttributeLinkedSet"/>
|
||||
<field id="friendlyname" xsi:type="AttributeFriendlyName"/>
|
||||
</fields>
|
||||
</class>
|
||||
<class id="Query" _delta="define">
|
||||
<!-- Generated by toolkit/export-class-to-meta.php -->
|
||||
<parent>cmdbAbstractObject</parent>
|
||||
@@ -693,50 +268,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>
|
||||
@@ -949,24 +482,6 @@
|
||||
<type>boolean</type>
|
||||
<default>true</default>
|
||||
</property>
|
||||
<property id="with_php_constraint">
|
||||
<php_param>with_php_constraint</php_param>
|
||||
<mandatory>false</mandatory>
|
||||
<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>
|
||||
<type>boolean</type>
|
||||
<default>false</default>
|
||||
</property>
|
||||
<property id="on_target_delete">
|
||||
<php_param>on_target_delete</php_param>
|
||||
<mandatory>false</mandatory>
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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
|
||||
*
|
||||
@@ -495,7 +400,7 @@ class DBObjectSearch extends DBSearch
|
||||
}
|
||||
|
||||
/**
|
||||
* Important: If you need to add a condition on the same $sFilterCode several times with different $value values; do not use this method as the previous $value occurrences will be replaced by the last. Instead use:
|
||||
* Important: If you need to add a condition on the same $sFilterCode several times with different $value values; do not use this method as the previous $value occurences will be replaced by the last. Instead use:
|
||||
* * {@see \DBObjectSearch::AddConditionExpression()} in loops to add conditions one by one
|
||||
* * {@see \DBObjectSearch::AddConditionForInOperatorUsingParam()} for IN/NOT IN queries with lots of params at once
|
||||
*
|
||||
@@ -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));
|
||||
|
||||
@@ -767,10 +767,7 @@ class DBObjectSet implements iDBObjectSetIterator
|
||||
|
||||
try
|
||||
{
|
||||
$oKPI = new ExecutionKPI();
|
||||
$this->m_oSQLResult = CMDBSource::Query($sSQL);
|
||||
$sOQL = $this->GetPseudoOQL($this->m_oFilter, $this->GetRealSortOrder(), $this->m_iLimitCount, $this->m_iLimitStart, false);
|
||||
$oKPI->ComputeStats('OQL Query Exec', $sOQL);
|
||||
} catch (MySQLException $e)
|
||||
{
|
||||
// 1116 = ER_TOO_MANY_TABLES
|
||||
@@ -850,11 +847,8 @@ class DBObjectSet implements iDBObjectSetIterator
|
||||
{
|
||||
if (is_null($this->m_iNumTotalDBRows))
|
||||
{
|
||||
$oKPI = new ExecutionKPI();
|
||||
$sSQL = $this->m_oFilter->MakeSelectQuery(array(), $this->m_aArgs, null, null, 0, 0, true);
|
||||
$resQuery = CMDBSource::Query($sSQL);
|
||||
$sOQL = $this->GetPseudoOQL($this->m_oFilter, array(), 0, 0, true);
|
||||
$oKPI->ComputeStats('OQL Query Exec', $sOQL);
|
||||
if (!$resQuery) return 0;
|
||||
|
||||
$aRow = CMDBSource::FetchArray($resQuery);
|
||||
@@ -865,42 +859,6 @@ class DBObjectSet implements iDBObjectSetIterator
|
||||
return $this->m_iNumTotalDBRows + count($this->m_aAddedObjects); // Does it fix Trac #887 ??
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \DBSearch $oFilter
|
||||
* @param array $aOrder
|
||||
* @param int $iLimitCount
|
||||
* @param int $iLimitStart
|
||||
* @param bool $bCount
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function GetPseudoOQL($oFilter, $aOrder, $iLimitCount, $iLimitStart, $bCount)
|
||||
{
|
||||
$sOQL = '';
|
||||
if ($bCount) {
|
||||
$sOQL .= 'COUNT ';
|
||||
}
|
||||
$sOQL .= $oFilter->ToOQL();
|
||||
|
||||
if ($iLimitCount > 0) {
|
||||
$sOQL .= ' LIMIT ';
|
||||
if ($iLimitStart > 0) {
|
||||
$sOQL .= "$iLimitStart, ";
|
||||
}
|
||||
$sOQL .= "$iLimitCount";
|
||||
}
|
||||
|
||||
if (count($aOrder) > 0) {
|
||||
$sOQL .= ' ORDER BY ';
|
||||
$aOrderBy = [];
|
||||
foreach ($aOrder as $sAttCode => $bAsc) {
|
||||
$aOrderBy[] = $sAttCode.' '.($bAsc ? 'ASC' : 'DESC');
|
||||
}
|
||||
$sOQL .= implode(', ', $aOrderBy);
|
||||
}
|
||||
return $sOQL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the count exceeds a given limit
|
||||
*
|
||||
@@ -917,11 +875,8 @@ class DBObjectSet implements iDBObjectSetIterator
|
||||
{
|
||||
if (is_null($this->m_iNumTotalDBRows))
|
||||
{
|
||||
$oKPI = new ExecutionKPI();
|
||||
$sSQL = $this->m_oFilter->MakeSelectQuery(array(), $this->m_aArgs, null, null, $iLimit + 2, 0, true);
|
||||
$resQuery = CMDBSource::Query($sSQL);
|
||||
$sOQL = $this->GetPseudoOQL($this->m_oFilter, array(), $iLimit + 2, 0, true);
|
||||
$oKPI->ComputeStats('OQL Query Exec', $sOQL);
|
||||
if ($resQuery)
|
||||
{
|
||||
$aRow = CMDBSource::FetchArray($resQuery);
|
||||
@@ -932,7 +887,7 @@ class DBObjectSet implements iDBObjectSetIterator
|
||||
{
|
||||
$iCount = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$iCount = $this->m_iNumTotalDBRows;
|
||||
@@ -957,11 +912,8 @@ class DBObjectSet implements iDBObjectSetIterator
|
||||
{
|
||||
if (is_null($this->m_iNumTotalDBRows))
|
||||
{
|
||||
$oKPI = new ExecutionKPI();
|
||||
$sSQL = $this->m_oFilter->MakeSelectQuery(array(), $this->m_aArgs, null, null, $iLimit + 2, 0, true);
|
||||
$resQuery = CMDBSource::Query($sSQL);
|
||||
$sOQL = $this->GetPseudoOQL($this->m_oFilter, array(), $iLimit + 2, 0, true);
|
||||
$oKPI->ComputeStats('OQL Query Exec', $sOQL);
|
||||
if ($resQuery)
|
||||
{
|
||||
$aRow = CMDBSource::FetchArray($resQuery);
|
||||
@@ -972,7 +924,7 @@ class DBObjectSet implements iDBObjectSetIterator
|
||||
{
|
||||
$iCount = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$iCount = $this->m_iNumTotalDBRows;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -224,10 +224,6 @@ class DBUnionSearch extends DBSearch
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the selected classes for this query.
|
||||
* The selected classes can be either in the selected classes of all the queries,
|
||||
* or they should exist in all the sub-queries of the union.
|
||||
*
|
||||
* @param array $aSelectedClasses array of aliases
|
||||
*
|
||||
* @throws \Exception
|
||||
@@ -240,31 +236,22 @@ class DBUnionSearch extends DBSearch
|
||||
$aAliasesToColumn = array_flip(array_keys($oFirstSearch->GetSelectedClasses()));
|
||||
foreach ($aSelectedClasses as $sSelectedAlias) {
|
||||
if (!isset($aAliasesToColumn[$sSelectedAlias])) {
|
||||
// The selected class is not in the selected classes of the union,
|
||||
// try to delegate the feature to the sub-queries
|
||||
$aSelectedColumns = [];
|
||||
break;
|
||||
throw new CoreException("SetSelectedClasses: Invalid class alias $sSelectedAlias");
|
||||
}
|
||||
$aSelectedColumns[] = $aAliasesToColumn[$sSelectedAlias];
|
||||
}
|
||||
|
||||
// 1 - change for each search
|
||||
foreach ($this->aSearches as $iPos => $oSearch) {
|
||||
foreach ($this->aSearches as $iPos => $oSearch)
|
||||
{
|
||||
$aCurrentSelectedAliases = [];
|
||||
if (count($aSelectedColumns) === 0) {
|
||||
// Default to the list of aliases given
|
||||
$aCurrentSelectedAliases = $aSelectedClasses;
|
||||
} else {
|
||||
// Map the aliases for each query
|
||||
foreach ($aSelectedColumns as $iColumn) {
|
||||
$aCurrentSelectedAliases[] = $this->aColumnToAliases[$iColumn][$iPos];
|
||||
}
|
||||
foreach ($aSelectedColumns as $iColumn) {
|
||||
$aCurrentSelectedAliases[] = $this->aColumnToAliases[$iColumn][$iPos];
|
||||
}
|
||||
|
||||
// Throws an exception if not valid
|
||||
$oSearch->SetSelectedClasses($aCurrentSelectedAliases);
|
||||
}
|
||||
|
||||
// 2 - update the lowest common ancestors
|
||||
$this->ComputeSelectedClasses();
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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.
|
||||
@@ -56,11 +56,10 @@ class Dict
|
||||
* @param $sLanguageCode
|
||||
*
|
||||
* @throws \DictExceptionUnknownLanguage
|
||||
* @since 3.0.4 3.1.1 3.2.0 Param $sLanguageCode becomes nullable
|
||||
*/
|
||||
public static function SetUserLanguage($sLanguageCode = null)
|
||||
public static function SetUserLanguage($sLanguageCode)
|
||||
{
|
||||
if (!is_null($sLanguageCode) && !array_key_exists($sLanguageCode, self::$m_aLanguages))
|
||||
if (!array_key_exists($sLanguageCode, self::$m_aLanguages))
|
||||
{
|
||||
throw new DictExceptionUnknownLanguage($sLanguageCode);
|
||||
}
|
||||
@@ -107,59 +106,42 @@ class Dict
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a localised string from the dictionary
|
||||
* Returns a localised string from the dictonary
|
||||
*
|
||||
* @param string $sStringCode The code identifying the dictionary entry
|
||||
* @param string $sDefault Default value if there is no match in the dictionary, if no default provided, returns $sStringCode unchanged
|
||||
* @param string $sDefault Default value if there is no match in the dictionary
|
||||
* @param bool $bUserLanguageOnly False to allow the use of the default language as a fallback, true otherwise
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function S($sStringCode, $sDefault = null, $bUserLanguageOnly = false)
|
||||
{
|
||||
$aInfo = self::GetLabelAndLangCode($sStringCode, $sDefault, $bUserLanguageOnly);
|
||||
return $aInfo['label'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a localised string from the dictonary with its associated lang code
|
||||
*
|
||||
* @param string $sStringCode The code identifying the dictionary entry
|
||||
* @param string $sDefault Default value if there is no match in the dictionary
|
||||
* @param bool $bUserLanguageOnly True to allow the use of the default language as a fallback, false otherwise
|
||||
*
|
||||
* @return array{
|
||||
* lang: string, label: string
|
||||
* } with localized label string and used lang code
|
||||
*/
|
||||
private static function GetLabelAndLangCode($sStringCode, $sDefault = null, $bUserLanguageOnly = false)
|
||||
{
|
||||
// Attempt to find the string in the user language
|
||||
//
|
||||
$sLangCode = self::GetUserLanguage();
|
||||
self::InitLangIfNeeded($sLangCode);
|
||||
|
||||
if (! array_key_exists($sLangCode, self::$m_aData))
|
||||
if (!array_key_exists($sLangCode, self::$m_aData))
|
||||
{
|
||||
IssueLog::Warning("Cannot find $sLangCode in all registered dictionaries.");
|
||||
IssueLog::Warning("Cannot find $sLangCode in dictionnaries. default labels displayed");
|
||||
// It may happen, when something happens before the dictionaries get loaded
|
||||
return [ 'label' => $sStringCode, 'lang' => $sLangCode ];
|
||||
return $sStringCode;
|
||||
}
|
||||
$aCurrentDictionary = self::$m_aData[$sLangCode];
|
||||
if (is_array($aCurrentDictionary) && array_key_exists($sStringCode, $aCurrentDictionary))
|
||||
{
|
||||
return [ 'label' => $aCurrentDictionary[$sStringCode], 'lang' => $sLangCode ];
|
||||
return $aCurrentDictionary[$sStringCode];
|
||||
}
|
||||
if (!$bUserLanguageOnly)
|
||||
{
|
||||
// Attempt to find the string in the default language
|
||||
//
|
||||
self::InitLangIfNeeded(self::$m_sDefaultLanguage);
|
||||
|
||||
|
||||
$aDefaultDictionary = self::$m_aData[self::$m_sDefaultLanguage];
|
||||
if (is_array($aDefaultDictionary) && array_key_exists($sStringCode, $aDefaultDictionary))
|
||||
{
|
||||
return [ 'label' => $aDefaultDictionary[$sStringCode], 'lang' => self::$m_sDefaultLanguage ];
|
||||
return $aDefaultDictionary[$sStringCode];
|
||||
}
|
||||
// Attempt to find the string in english
|
||||
//
|
||||
@@ -168,17 +150,17 @@ class Dict
|
||||
$aDefaultDictionary = self::$m_aData['EN US'];
|
||||
if (is_array($aDefaultDictionary) && array_key_exists($sStringCode, $aDefaultDictionary))
|
||||
{
|
||||
return [ 'label' => $aDefaultDictionary[$sStringCode], 'lang' => 'EN US' ];
|
||||
return $aDefaultDictionary[$sStringCode];
|
||||
}
|
||||
}
|
||||
// Could not find the string...
|
||||
//
|
||||
if (is_null($sDefault))
|
||||
{
|
||||
return [ 'label' => $sStringCode, 'lang' => null ];
|
||||
return $sStringCode;
|
||||
}
|
||||
|
||||
return [ 'label' => $sDefault, 'lang' => null ];
|
||||
return $sDefault;
|
||||
}
|
||||
|
||||
|
||||
@@ -194,25 +176,19 @@ class Dict
|
||||
*/
|
||||
public static function Format($sFormatCode /*, ... arguments ... */)
|
||||
{
|
||||
['label' => $sLocalizedFormat, 'lang' => $sLangCode] = self::GetLabelAndLangCode($sFormatCode);
|
||||
|
||||
$sLocalizedFormat = self::S($sFormatCode);
|
||||
$aArguments = func_get_args();
|
||||
array_shift($aArguments);
|
||||
|
||||
|
||||
if ($sLocalizedFormat == $sFormatCode)
|
||||
{
|
||||
// Make sure the information will be displayed (ex: an error occuring before the dictionary gets loaded)
|
||||
return $sFormatCode.' - '.implode(', ', $aArguments);
|
||||
}
|
||||
|
||||
try{
|
||||
return vsprintf($sLocalizedFormat, $aArguments);
|
||||
} catch(\Throwable $e){
|
||||
\IssueLog::Error("Cannot format dict key", null, ["sFormatCode" => $sFormatCode, "sLangCode" => $sLangCode, 'exception_msg' => $e->getMessage() ]);
|
||||
return $sFormatCode.' - '.implode(', ', $aArguments);
|
||||
}
|
||||
return vsprintf($sLocalizedFormat, $aArguments);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Initialize a the entries for a given language (replaces the former Add() method)
|
||||
* @param string $sLanguageCode Code identifying the language i.e. 'FR-FR', 'EN-US'
|
||||
@@ -222,7 +198,7 @@ class Dict
|
||||
{
|
||||
self::$m_aData[$sLanguageCode] = $aEntries;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set the list of available languages
|
||||
* @param hash $aLanguagesList
|
||||
@@ -283,7 +259,7 @@ class Dict
|
||||
{
|
||||
$sDictFile = APPROOT.'env-'.utils::GetCurrentEnvironment().'/dictionaries/'.str_replace(' ', '-', strtolower($sLangCode)).'.dict.php';
|
||||
require_once($sDictFile);
|
||||
|
||||
|
||||
if (self::GetApcService()->function_exists('apc_store')
|
||||
&& (self::$m_sApplicationPrefix !== null))
|
||||
{
|
||||
@@ -293,7 +269,7 @@ class Dict
|
||||
}
|
||||
return $bResult;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Enable caching (cached using APC)
|
||||
* @param string $sApplicationPrefix The prefix for uniquely identiying this iTop instance
|
||||
@@ -336,14 +312,14 @@ class Dict
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static function MakeStats($sLanguageCode, $sLanguageRef = 'EN US')
|
||||
{
|
||||
$aMissing = array(); // Strings missing for the target language
|
||||
$aUnexpected = array(); // Strings defined for the target language, but not found in the reference dictionary
|
||||
$aNotTranslated = array(); // Strings having the same value in both dictionaries
|
||||
$aOK = array(); // Strings having different values in both dictionaries
|
||||
|
||||
|
||||
foreach (self::$m_aData[$sLanguageRef] as $sStringCode => $sValue)
|
||||
{
|
||||
if (!array_key_exists($sStringCode, self::$m_aData[$sLanguageCode]))
|
||||
@@ -351,7 +327,7 @@ class Dict
|
||||
$aMissing[$sStringCode] = $sValue;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
foreach (self::$m_aData[$sLanguageCode] as $sStringCode => $sValue)
|
||||
{
|
||||
if (!array_key_exists($sStringCode, self::$m_aData[$sLanguageRef]))
|
||||
@@ -374,7 +350,7 @@ class Dict
|
||||
}
|
||||
return array($aMissing, $aUnexpected, $aNotTranslated, $aOK);
|
||||
}
|
||||
|
||||
|
||||
public static function Dump()
|
||||
{
|
||||
MyHelpers::var_dump_html(self::$m_aData);
|
||||
@@ -397,7 +373,7 @@ class Dict
|
||||
// No need to actually load the strings since it's only used to know the list of languages
|
||||
// at setup time !!
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Export all the dictionary entries - of the given language - whose code matches the given prefix
|
||||
* missing entries in the current language will be replaced by entries in the default language
|
||||
@@ -410,7 +386,7 @@ class Dict
|
||||
self::InitLangIfNeeded(self::$m_sDefaultLanguage);
|
||||
$aEntries = array();
|
||||
$iLength = strlen($sStartingWith);
|
||||
|
||||
|
||||
// First prefill the array with entries from the default language
|
||||
foreach(self::$m_aData[self::$m_sDefaultLanguage] as $sCode => $sEntry)
|
||||
{
|
||||
@@ -419,7 +395,7 @@ class Dict
|
||||
$aEntries[$sCode] = $sEntry;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Now put (overwrite) the entries for the user language
|
||||
foreach(self::$m_aData[self::GetUserLanguage()] as $sCode => $sEntry)
|
||||
{
|
||||
|
||||
@@ -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')));
|
||||
|
||||
@@ -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()
|
||||
{
|
||||
|
||||
@@ -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)");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user