mirror of
https://github.com/Combodo/iTop.git
synced 2026-02-21 19:34:12 +01:00
Compare commits
412 Commits
3.0.0-rc
...
feature/51
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
05b69208a8 | ||
|
|
c0f0e354dd | ||
|
|
d6f58d04f1 | ||
|
|
cc88ee1de0 | ||
|
|
8008e4d840 | ||
|
|
a4390fbb57 | ||
|
|
f4170ade8a | ||
|
|
e81587470d | ||
|
|
fc6df1063c | ||
|
|
5a37bc338a | ||
|
|
f4a027b474 | ||
|
|
d0ba0d193b | ||
|
|
1d9a9bcb28 | ||
|
|
178ba60973 | ||
|
|
8e6e2432d3 | ||
|
|
83ec19dfca | ||
|
|
6e619f2c35 | ||
|
|
163ba41e8d | ||
|
|
ec143c43db | ||
|
|
cacf0004a5 | ||
|
|
cb39541e2a | ||
|
|
b9ddadeb44 | ||
|
|
dabd2a3f4d | ||
|
|
11e811cc4b | ||
|
|
c47f224566 | ||
|
|
8fcd454445 | ||
|
|
e422adb0d0 | ||
|
|
b03e28efb9 | ||
|
|
7b3d859522 | ||
|
|
ba9d5f0c4b | ||
|
|
e02d9f3f0e | ||
|
|
e831d66b76 | ||
|
|
0efc978004 | ||
|
|
6fa2d47780 | ||
|
|
e691454339 | ||
|
|
079b406f18 | ||
|
|
dbe02a42c2 | ||
|
|
b026e5ab87 | ||
|
|
1e75154cc7 | ||
|
|
94365ea40e | ||
|
|
e4a04de9f4 | ||
|
|
645e612e8b | ||
|
|
26a78a10bc | ||
|
|
1feb5e6ad6 | ||
|
|
2716f9d24c | ||
|
|
bac2918ceb | ||
|
|
92997e3e57 | ||
|
|
604837c770 | ||
|
|
f32c283c9c | ||
|
|
27d06a712b | ||
|
|
b15050487c | ||
|
|
46f232d561 | ||
|
|
63976df2e1 | ||
|
|
42599eae64 | ||
|
|
3514e21772 | ||
|
|
3463b1715a | ||
|
|
b75f29b8d7 | ||
|
|
81d285a143 | ||
|
|
631b38a160 | ||
|
|
0287500feb | ||
|
|
e4cbaf7096 | ||
|
|
ad4442ae78 | ||
|
|
73c6b4be20 | ||
|
|
fde2103659 | ||
|
|
24500216f6 | ||
|
|
2039b872d3 | ||
|
|
b368c593e5 | ||
|
|
c9c731a2a5 | ||
|
|
8204723b5b | ||
|
|
f93218a80f | ||
|
|
4f5a9c898c | ||
|
|
7ce5712b71 | ||
|
|
90b41e0b81 | ||
|
|
9d2c89f118 | ||
|
|
61137a6f65 | ||
|
|
a26c8fbd48 | ||
|
|
0080a2e733 | ||
|
|
992ee3a74b | ||
|
|
e45013891c | ||
|
|
1db4b9a12e | ||
|
|
ea043960ff | ||
|
|
d0f83046cd | ||
|
|
7f4fddb378 | ||
|
|
9cd076131f | ||
|
|
a71cb97db3 | ||
|
|
0c80a4e430 | ||
|
|
779211e638 | ||
|
|
4c99f497cc | ||
|
|
d1e2be97d2 | ||
|
|
93c6cfffda | ||
|
|
b50ba0ad49 | ||
|
|
0205cdf713 | ||
|
|
39fc59a8b2 | ||
|
|
107c9adf60 | ||
|
|
143c30b099 | ||
|
|
d29880b1b8 | ||
|
|
3edfc2016d | ||
|
|
5f80be75ed | ||
|
|
0d4796ae2b | ||
|
|
2d156bd77b | ||
|
|
5908ec5197 | ||
|
|
d122dbfdd6 | ||
|
|
46d58e6512 | ||
|
|
6cf781da33 | ||
|
|
0f2cbaf186 | ||
|
|
7ddb47dc83 | ||
|
|
f4ecdf116a | ||
|
|
304e379c01 | ||
|
|
93a138606f | ||
|
|
70074ee1cb | ||
|
|
d28ccb264f | ||
|
|
8d4545f008 | ||
|
|
9f95d45f51 | ||
|
|
8ab38854a8 | ||
|
|
bceb570d84 | ||
|
|
138fa569f2 | ||
|
|
1f65ab5a92 | ||
|
|
7cfac7300b | ||
|
|
5854c199d0 | ||
|
|
ede720c9b9 | ||
|
|
684efee5d2 | ||
|
|
e347989dcb | ||
|
|
e1051e7a47 | ||
|
|
7e8eb26866 | ||
|
|
6775a3e928 | ||
|
|
faa38155e5 | ||
|
|
558bbc3357 | ||
|
|
cd7f9e478f | ||
|
|
e3586cff65 | ||
|
|
106127e6b7 | ||
|
|
2299983db3 | ||
|
|
2fab7de34b | ||
|
|
c0ab79971c | ||
|
|
03ed9c9deb | ||
|
|
7152277760 | ||
|
|
14d05da9f6 | ||
|
|
69a0bd0c34 | ||
|
|
c09cee994a | ||
|
|
50ee0b3eed | ||
|
|
84169a864c | ||
|
|
9f27cf2b84 | ||
|
|
f78986009f | ||
|
|
a937d08655 | ||
|
|
4bdf84bf6c | ||
|
|
4fdbec72d4 | ||
|
|
94d31827e7 | ||
|
|
45a8eb93e7 | ||
|
|
6ac3539373 | ||
|
|
a5d8425fe7 | ||
|
|
3608c6b8ab | ||
|
|
2b1e583dc7 | ||
|
|
3081aa473a | ||
|
|
809ea2eb49 | ||
|
|
2f98a3e7ac | ||
|
|
c737fc46ff | ||
|
|
619c0d34e8 | ||
|
|
bdc7ed6f8e | ||
|
|
d9819d9c2a | ||
|
|
f24f8a2f34 | ||
|
|
3890b1a020 | ||
|
|
2e08cff9ee | ||
|
|
968a0e5f3a | ||
|
|
4694e8152e | ||
|
|
4b731dd336 | ||
|
|
5e0c7c211b | ||
|
|
9ce88699ca | ||
|
|
815870fe6b | ||
|
|
33ceab86fb | ||
|
|
fe1bf3bfc1 | ||
|
|
3727223db3 | ||
|
|
5b96d9f778 | ||
|
|
162b15236d | ||
|
|
83e98ef2b8 | ||
|
|
d783954d13 | ||
|
|
7207dc657c | ||
|
|
f1cce8e430 | ||
|
|
3da49e6603 | ||
|
|
5048421bfa | ||
|
|
b9c5f2c523 | ||
|
|
ec75195a2f | ||
|
|
e971d628dd | ||
|
|
bbd50ba73b | ||
|
|
ba71c1bcd5 | ||
|
|
16be8fd3d3 | ||
|
|
cacae0a2b3 | ||
|
|
f9e8bf88c8 | ||
|
|
b1ed15f31c | ||
|
|
788caf9c50 | ||
|
|
1728dcc40c | ||
|
|
35165568af | ||
|
|
bddf7a11c8 | ||
|
|
cb5554ddb1 | ||
|
|
ee7fb15fc2 | ||
|
|
6a5840ed82 | ||
|
|
4a67819f87 | ||
|
|
8473df0f0c | ||
|
|
81c39c35cd | ||
|
|
4caf52f1ae | ||
|
|
0c5b845c8a | ||
|
|
cdfdb1f2ca | ||
|
|
f29a8792af | ||
|
|
b494ff2ce6 | ||
|
|
a65c55fc48 | ||
|
|
01b94f42fe | ||
|
|
df1e19dc43 | ||
|
|
cbef9bb267 | ||
|
|
9ad341f73a | ||
|
|
03e9bcd47a | ||
|
|
55effea0a3 | ||
|
|
dfaa973359 | ||
|
|
2e45b20fc4 | ||
|
|
e89090f0ec | ||
|
|
c9d02826a0 | ||
|
|
47db04bcb7 | ||
|
|
a49c451ae4 | ||
|
|
25c3704990 | ||
|
|
3000659e86 | ||
|
|
ce36c00b83 | ||
|
|
2a3e6384d9 | ||
|
|
dd7e73e413 | ||
|
|
1709082e39 | ||
|
|
41f6e85673 | ||
|
|
3ef3166bd5 | ||
|
|
7eab003f3c | ||
|
|
d437e2d662 | ||
|
|
0d26211dbe | ||
|
|
3b99006159 | ||
|
|
299ad7e753 | ||
|
|
94a2421186 | ||
|
|
923c3a27a3 | ||
|
|
c1a1186bf7 | ||
|
|
b360514646 | ||
|
|
541794ca9c | ||
|
|
5fbcae1f55 | ||
|
|
0f6e0e5085 | ||
|
|
3541a9e1db | ||
|
|
1f95a4ee21 | ||
|
|
af5a0d5006 | ||
|
|
84280a3b5f | ||
|
|
e3bce622e5 | ||
|
|
ef9392a8d5 | ||
|
|
15087ab848 | ||
|
|
7bb7445c91 | ||
|
|
60c372f535 | ||
|
|
6a4ce3c3b1 | ||
|
|
7df27de5c1 | ||
|
|
b4fc647845 | ||
|
|
de053eed72 | ||
|
|
17612f88d3 | ||
|
|
e14845728c | ||
|
|
4e80fc0f76 | ||
|
|
fcfcf85e0d | ||
|
|
f0715baf7d | ||
|
|
2733e7966f | ||
|
|
52327d1086 | ||
|
|
81cf3df5e2 | ||
|
|
45b5c39af7 | ||
|
|
4463e91d85 | ||
|
|
ce87bf9e23 | ||
|
|
dbc3da7bc3 | ||
|
|
ebc9fa684a | ||
|
|
606bdc1909 | ||
|
|
7495fb9af4 | ||
|
|
75dbad7406 | ||
|
|
c95064b76d | ||
|
|
f0933eaf1e | ||
|
|
b9ea7d4913 | ||
|
|
22f9d16743 | ||
|
|
3d3d94e837 | ||
|
|
9c75a705f3 | ||
|
|
3381c085f4 | ||
|
|
3bec96abe1 | ||
|
|
b89d181125 | ||
|
|
44c18395b3 | ||
|
|
09ff052c1f | ||
|
|
c3a2713bba | ||
|
|
99b73fe1ee | ||
|
|
151f42ceef | ||
|
|
627c0070c1 | ||
|
|
3a56824cde | ||
|
|
9b6f7d94f4 | ||
|
|
9a6d40e9db | ||
|
|
64e8aa5fee | ||
|
|
a839b1c4ae | ||
|
|
b58df7150f | ||
|
|
1cd230a543 | ||
|
|
fc47e031b6 | ||
|
|
477128ad53 | ||
|
|
3b4ba2aafd | ||
|
|
70f67068f4 | ||
|
|
4fec344799 | ||
|
|
cc5f7608e3 | ||
|
|
468de06fe1 | ||
|
|
9ef5fd70c0 | ||
|
|
3b599a40f3 | ||
|
|
aa20289dfe | ||
|
|
4449fdbbc5 | ||
|
|
04a690caff | ||
|
|
0156eb0dda | ||
|
|
e8448332f4 | ||
|
|
e8e6ceb29e | ||
|
|
1f42f897d8 | ||
|
|
aa66bec783 | ||
|
|
1da52a8517 | ||
|
|
cbd2181862 | ||
|
|
1495ab992f | ||
|
|
102528195b | ||
|
|
7def094291 | ||
|
|
d89dc1aa4d | ||
|
|
ffb3edced5 | ||
|
|
17e8c53236 | ||
|
|
910638d93f | ||
|
|
d005ff0099 | ||
|
|
4fdf8803a5 | ||
|
|
06af788480 | ||
|
|
7aa1719514 | ||
|
|
81c0951c2a | ||
|
|
1fac2ae787 | ||
|
|
ff7d1f2d6a | ||
|
|
89ecdeb13b | ||
|
|
c6211cde09 | ||
|
|
739001eca4 | ||
|
|
7243da3576 | ||
|
|
c9d547030f | ||
|
|
4923ac7015 | ||
|
|
91d4da85e1 | ||
|
|
c1c264d6d8 | ||
|
|
0940741568 | ||
|
|
041a938fc0 | ||
|
|
839048fab2 | ||
|
|
4180a41f27 | ||
|
|
8ada56fc53 | ||
|
|
6c5ca614e0 | ||
|
|
4ddee0b624 | ||
|
|
135ddbf37d | ||
|
|
a43adcd202 | ||
|
|
e8e170fb06 | ||
|
|
5ac5d649aa | ||
|
|
ec0c98bb0f | ||
|
|
decb802df4 | ||
|
|
cacc3a3085 | ||
|
|
0fd2ea6a47 | ||
|
|
dcd52d6919 | ||
|
|
9a75ca2c21 | ||
|
|
ab7e73ef9b | ||
|
|
812606db78 | ||
|
|
31e7a5383c | ||
|
|
64afa07ff5 | ||
|
|
656bbfe46d | ||
|
|
426f275c03 | ||
|
|
b55ba2ac7f | ||
|
|
693a861e7d | ||
|
|
0ee6c60e94 | ||
|
|
a663e9fded | ||
|
|
b3bf516b20 | ||
|
|
c2408b74cd | ||
|
|
6855c2f83a | ||
|
|
b11bf30881 | ||
|
|
64736f1463 | ||
|
|
930b224ca2 | ||
|
|
c17ceb1702 | ||
|
|
c87de1024d | ||
|
|
24e6840a8b | ||
|
|
06ed048983 | ||
|
|
937313495d | ||
|
|
9493e31a5d | ||
|
|
92b61c7491 | ||
|
|
3a4c4cd33d | ||
|
|
9aa399894c | ||
|
|
bde5dc825d | ||
|
|
8578d18e7f | ||
|
|
9b0e55210d | ||
|
|
e530cbb4f2 | ||
|
|
ddb8378fe6 | ||
|
|
47db23d91c | ||
|
|
fc1f701bf6 | ||
|
|
ece31855af | ||
|
|
d57ef77758 | ||
|
|
365c7bb89e | ||
|
|
bf2c4dee1b | ||
|
|
11b812b5fc | ||
|
|
b073e4385c | ||
|
|
c37c46a4a8 | ||
|
|
ce01dad875 | ||
|
|
f592d94af3 | ||
|
|
f9359431fe | ||
|
|
25e560fdaa | ||
|
|
9ca106d889 | ||
|
|
5f575d524a | ||
|
|
0ce805b192 | ||
|
|
6bf25f90bc | ||
|
|
30d36fca81 | ||
|
|
ffd0bbb1a4 | ||
|
|
16142bd979 | ||
|
|
c1e2ba8abc | ||
|
|
3db20e8028 | ||
|
|
cc2efe432e | ||
|
|
e879ae2f11 | ||
|
|
ed12f98075 | ||
|
|
19eef5bd72 | ||
|
|
8bcd2ce571 | ||
|
|
7b2bcd1055 | ||
|
|
108c1fcb2b | ||
|
|
d301562ffe | ||
|
|
caed22ea8d | ||
|
|
ced29dea8e | ||
|
|
20a07d61c6 | ||
|
|
682c821d0e | ||
|
|
5f382ee053 | ||
|
|
dc81630b16 | ||
|
|
f84c095b22 | ||
|
|
b190d0e385 |
Binary file not shown.
|
Before Width: | Height: | Size: 2.1 MiB After Width: | Height: | Size: 1.4 MiB |
3
.gitignore
vendored
3
.gitignore
vendored
@@ -45,6 +45,9 @@ test/vendor/*
|
||||
!/log/index.php
|
||||
!/log/web.config
|
||||
|
||||
# PHPUnit cache file
|
||||
/test/.phpunit.result.cache
|
||||
|
||||
|
||||
# Jetbrains
|
||||
/.idea/**
|
||||
|
||||
@@ -36,18 +36,24 @@ clearstatcache();
|
||||
$oiTopComposer = new iTopComposer();
|
||||
$aDeniedButStillPresent = $oiTopComposer->ListDeniedButStillPresent();
|
||||
|
||||
echo "\n";
|
||||
foreach ($aDeniedButStillPresent as $sDir)
|
||||
{
|
||||
if (! preg_match('#[tT]ests?/?$#', $sDir))
|
||||
if (false === iTopComposer::IsTestDir($sDir))
|
||||
{
|
||||
echo "\nfound INVALID denied test dir: '$sDir'\n";
|
||||
echo "ERROR found INVALID denied test dir: '$sDir'\n";
|
||||
throw new \Exception("$sDir must end with /Test/ or /test/");
|
||||
}
|
||||
|
||||
if (false === file_exists($sDir)) {
|
||||
echo "INFO $sDir is in denied list, but not existing on disk => skipping !\n";
|
||||
continue;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
SetupUtils::rrmdir($sDir);
|
||||
echo "Remove denied test dir: '$sDir'\n";
|
||||
echo "OK Remove denied test dir: '$sDir'\n";
|
||||
}
|
||||
catch (\Exception $e)
|
||||
{
|
||||
|
||||
@@ -26,6 +26,7 @@ require_once (__DIR__.DIRECTORY_SEPARATOR.'update.classes.inc.php');
|
||||
$aFilesUpdaters = array(
|
||||
new iTopVersionFileUpdater(),
|
||||
new DatamodelsModulesFiles(),
|
||||
new ConstantFileUpdater('ITOP_CORE_VERSION', 'approot.inc.php'),
|
||||
);
|
||||
|
||||
if (count($argv) === 1)
|
||||
|
||||
@@ -69,6 +69,40 @@ abstract class AbstractSingleFileVersionUpdater extends FileVersionUpdater
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 2.7.7 3.0.1 3.1.0 N°4714
|
||||
*/
|
||||
class ConstantFileUpdater extends AbstractSingleFileVersionUpdater {
|
||||
/** @var string */
|
||||
private $sConstantName;
|
||||
|
||||
/**
|
||||
* @param $sConstantName constant to search, for example `ITOP_CORE_VERSION`
|
||||
* @param $sFileToUpdate file containing constant definition
|
||||
*/
|
||||
public function __construct($sConstantName, $sFileToUpdate)
|
||||
{
|
||||
$this->sConstantName = $sConstantName;
|
||||
parent::__construct($sFileToUpdate);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function UpdateFileContent($sVersionLabel, $sFileContent, $sFileFullPath)
|
||||
{
|
||||
$sConstantSearchPattern = <<<REGEXP
|
||||
/define\('{$this->sConstantName}', ?'[^']+'\);/
|
||||
REGEXP;
|
||||
|
||||
return preg_replace(
|
||||
$sConstantSearchPattern,
|
||||
"define('{$this->sConstantName}', '{$sVersionLabel}');",
|
||||
$sFileContent
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class iTopVersionFileUpdater extends AbstractSingleFileVersionUpdater
|
||||
{
|
||||
public function __construct()
|
||||
|
||||
@@ -52,26 +52,26 @@ Here are the branches we use and their meaning :
|
||||
|
||||
For example, if no version is currently prepared for shipping we could have:
|
||||
|
||||
- `develop` containing future 3.0.0 version
|
||||
- `develop` containing future 3.1.0 version
|
||||
- `support/3.0`: 3.0.x maintenance version
|
||||
- `support/2.7`: 2.7.x maintenance version
|
||||
- `support/2.6`: 2.6.x maintenance version
|
||||
- `support/2.5`: 2.5.x maintenance version
|
||||
|
||||
In this example, when 3.0.0-beta is shipped that will become:
|
||||
In this example, when 3.1.0-beta is shipped that will become:
|
||||
|
||||
- `develop`: future 3.1.0 version
|
||||
- `release/3.0.0`: 3.0.0-beta
|
||||
- `develop`: future 3.2.0 version
|
||||
- `release/3.1.0`: 3.1.0-beta
|
||||
- `support/3.0`: 3.0.x maintenance version
|
||||
- `support/2.7`: 2.7.x maintenance version
|
||||
- `support/2.6`: 2.6.x maintenance version
|
||||
- `support/2.5`: 2.5.x maintenance version
|
||||
|
||||
And when 3.0.0 final will be out:
|
||||
|
||||
- `develop`: future 3.1.0 version
|
||||
- `support/3.0`: 3.0.x maintenance version (will host developments for 3.0.1)
|
||||
- `develop`: future 3.2.0 version
|
||||
- `support/3.1`: 3.1.x maintenance version (will host developments for 3.1.1)
|
||||
- `support/3.0`: 3.0.x maintenance version
|
||||
- `support/2.7`: 2.7.x maintenance version
|
||||
- `support/2.6`: 2.6.x maintenance version
|
||||
- `support/2.5`: 2.5.x maintenance version
|
||||
|
||||
Also note that we have a "micro-version" concept : each of those versions have a very small amount of modifications. They are made from
|
||||
`support/*` branches as well. For example 2.6.2-1 and 2.6.2-2 were made from the `support/2.6.2` branch.
|
||||
|
||||
11
README.md
11
README.md
@@ -78,18 +78,19 @@ We would like to give a special thank you 🤗 to the people from the community
|
||||
|
||||
- Alves, David
|
||||
- Beck, Pedro
|
||||
- Beer, Christian (a.k.a [@ChristianBeer](https://www.github.com/ChristianBeer))
|
||||
- Bilger, Jean-François
|
||||
- Bostoen, Jeffrey (a.k.a @jbostoen)
|
||||
- Bostoen, Jeffrey (a.k.a [@jbostoen](https://www.github.com/jbostoen))
|
||||
- Cardoso, Anderson
|
||||
- Cassaro, Bruno
|
||||
- Casteleyn, Thomas (a.k.a @Hipska)
|
||||
- Casteleyn, Thomas (a.k.a [@Hipska](https://www.github.com/Hipska))
|
||||
- Castro, Randall Badilla
|
||||
- Colantoni, Maria Laura
|
||||
- Couronné, Guy
|
||||
- Dvořák, Lukáš
|
||||
- Goethals, Stefan
|
||||
- Gumble, David
|
||||
- Kaltefleiter, Lars (a.k.a @larhip)
|
||||
- Kaltefleiter, Lars (a.k.a [@larhip](https://www.github.com/larhip))
|
||||
- Khamit, Shamil
|
||||
- Kincel, Martin
|
||||
- Konečný, Kamil
|
||||
@@ -98,12 +99,12 @@ We would like to give a special thank you 🤗 to the people from the community
|
||||
- Lazcano, Federico
|
||||
- Lucas, Jonathan
|
||||
- Malik, Remie
|
||||
- Mindêllo de Andrade, Lucas (a.k.a @rokam)
|
||||
- Mindêllo de Andrade, Lucas (a.k.a [@rokam](https://www.github.com/rokam))
|
||||
- Raenker, Martin
|
||||
- Rosenke, Stephan
|
||||
- Seki, Shoji
|
||||
- Shilov, Vladimir
|
||||
- Stukalov, Ilya (a.k.a @ilya-stukalov)
|
||||
- Stukalov, Ilya (a.k.a [@ilya](https://www.github.com/ilya)-stukalov)
|
||||
- Tulio, Marco
|
||||
- Turrubiates, Miguel
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ define('PORTAL_PROFILE_NAME', 'Portal user');
|
||||
class UserRightsBaseClassGUI extends cmdbAbstractObject
|
||||
{
|
||||
// Whenever something changes, reload the privileges
|
||||
|
||||
|
||||
protected function AfterInsert()
|
||||
{
|
||||
UserRights::FlushPrivileges();
|
||||
@@ -59,7 +59,7 @@ class URP_Profiles extends UserRightsBaseClassGUI
|
||||
}
|
||||
|
||||
protected static $m_aCacheProfiles = null;
|
||||
|
||||
|
||||
public static function DoCreateProfile($sName, $sDescription)
|
||||
{
|
||||
if (is_null(self::$m_aCacheProfiles))
|
||||
@@ -71,7 +71,7 @@ class URP_Profiles extends UserRightsBaseClassGUI
|
||||
{
|
||||
self::$m_aCacheProfiles[$oProfile->Get('name')] = $oProfile->GetKey();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$sCacheKey = $sName;
|
||||
if (isset(self::$m_aCacheProfiles[$sCacheKey]))
|
||||
@@ -82,10 +82,10 @@ class URP_Profiles extends UserRightsBaseClassGUI
|
||||
$oNewObj->Set('name', $sName);
|
||||
$oNewObj->Set('description', $sDescription);
|
||||
$iId = $oNewObj->DBInsertNoReload();
|
||||
self::$m_aCacheProfiles[$sCacheKey] = $iId;
|
||||
self::$m_aCacheProfiles[$sCacheKey] = $iId;
|
||||
return $iId;
|
||||
}
|
||||
|
||||
|
||||
function GetGrantAsHtml($oUserRights, $sClass, $sAction)
|
||||
{
|
||||
$bGrant = $oUserRights->GetProfileActionGrant($this->GetKey(), $sClass, $sAction);
|
||||
@@ -102,7 +102,7 @@ class URP_Profiles extends UserRightsBaseClassGUI
|
||||
return '<span style="background-color: #ffdddd;">'.Dict::S('UI:UserManagement:ActionAllowed:No').'</span>';
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function DoShowGrantSumary($oPage)
|
||||
{
|
||||
if ($this->GetRawName() == "Administrator")
|
||||
@@ -114,7 +114,7 @@ class URP_Profiles extends UserRightsBaseClassGUI
|
||||
|
||||
// Note: for sure, we assume that the instance is derived from UserRightsProfile
|
||||
$oUserRights = UserRights::GetModuleInstance();
|
||||
|
||||
|
||||
$aDisplayData = array();
|
||||
foreach (MetaModel::GetClasses('bizmodel,grant_by_profile') as $sClass)
|
||||
{
|
||||
@@ -123,12 +123,12 @@ class URP_Profiles extends UserRightsBaseClassGUI
|
||||
{
|
||||
$bGrant = $oUserRights->GetClassStimulusGrant($this->GetKey(), $sClass, $sStimulusCode);
|
||||
if ($bGrant === true)
|
||||
{
|
||||
{
|
||||
$aStimuli[] = '<span title="'.$sStimulusCode.': '.htmlentities($oStimulus->GetDescription(), ENT_QUOTES, 'UTF-8').'">'.htmlentities($oStimulus->GetLabel(), ENT_QUOTES, 'UTF-8').'</span>';
|
||||
}
|
||||
}
|
||||
$sStimuli = implode(', ', $aStimuli);
|
||||
|
||||
|
||||
$aDisplayData[] = array(
|
||||
'class' => MetaModel::GetName($sClass),
|
||||
'read' => $this->GetGrantAsHtml($oUserRights, $sClass, 'r'),
|
||||
@@ -140,7 +140,7 @@ class URP_Profiles extends UserRightsBaseClassGUI
|
||||
'stimuli' => $sStimuli,
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
$aDisplayConfig = array();
|
||||
$aDisplayConfig['class'] = array('label' => Dict::S('UI:UserManagement:Class'), 'description' => Dict::S('UI:UserManagement:Class+'));
|
||||
$aDisplayConfig['read'] = array('label' => Dict::S('UI:UserManagement:Action:Read'), 'description' => Dict::S('UI:UserManagement:Action:Read+'));
|
||||
@@ -198,7 +198,7 @@ class URP_Profiles extends UserRightsBaseClassGUI
|
||||
* @param $aReasons array To store the reasons why the attribute is read-only (info about the synchro replicas)
|
||||
* @param $sTargetState string The target state in which to evalutate the flags, if empty the current state will be used
|
||||
* @return integer Flags: the binary combination of the flags applicable to this attribute
|
||||
*/
|
||||
*/
|
||||
public function GetAttributeFlags($sAttCode, &$aReasons = array(), $sTargetState = '')
|
||||
{
|
||||
$iFlags = parent::GetAttributeFlags($sAttCode, $aReasons, $sTargetState);
|
||||
@@ -404,7 +404,7 @@ class URP_UserOrg extends UserRightsBaseClassGUI
|
||||
{
|
||||
if (!UserRights::IsLoggedIn() || UserRights::IsAdministrator()) { return; }
|
||||
|
||||
$oUser = UserRights::GetUserObject();
|
||||
$oUser = UserRights::GetUserObject();
|
||||
$oAddon = UserRights::GetModuleInstance();
|
||||
$aOrgs = $oAddon->GetUserOrgs($oUser, '');
|
||||
if (count($aOrgs) > 0)
|
||||
@@ -528,7 +528,7 @@ class UserRightsProfile extends UserRightsAddOnAPI
|
||||
$oSearch->AllowAllData();
|
||||
$oCondition = new BinaryExpression(new FieldExpression('userid'), '=', new VariableExpression('userid'));
|
||||
$oSearch->AddConditionExpression($oCondition);
|
||||
|
||||
|
||||
$oUserOrgSet = new DBObjectSet($oSearch, array(), array('userid' => $iUser));
|
||||
while ($oUserOrg = $oUserOrgSet->Fetch())
|
||||
{
|
||||
@@ -738,8 +738,10 @@ class UserRightsProfile extends UserRightsAddOnAPI
|
||||
// load and cache permissions for the current user on the given class
|
||||
//
|
||||
$iUser = $oUser->GetKey();
|
||||
$aTest = @$this->m_aObjectActionGrants[$iUser][$sClass][$iActionCode];
|
||||
if (is_array($aTest)) return $aTest;
|
||||
if (isset($this->m_aObjectActionGrants[$iUser][$sClass][$iActionCode])){
|
||||
$aTest = $this->m_aObjectActionGrants[$iUser][$sClass][$iActionCode];
|
||||
if (is_array($aTest)) return $aTest;
|
||||
}
|
||||
|
||||
$sAction = self::$m_aActionCodes[$iActionCode];
|
||||
|
||||
@@ -905,8 +907,8 @@ class UserRightsProfile extends UserRightsAddOnAPI
|
||||
|
||||
/**
|
||||
* Find out which attribute is corresponding the the dimension 'owner org'
|
||||
* returns null if no such attribute has been found (no filtering should occur)
|
||||
*/
|
||||
* returns null if no such attribute has been found (no filtering should occur)
|
||||
*/
|
||||
public static function GetOwnerOrganizationAttCode($sClass)
|
||||
{
|
||||
$sAttCode = null;
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
<?php
|
||||
/**
|
||||
* @deprecated 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-2021 Combodo SARL
|
||||
*/
|
||||
|
||||
// cannot notify depreciation for now as this is still MASSIVELY used in iTop core !
|
||||
//DeprecatedCallsLog::NotifyDeprecatedFile('moved to sources/application/WebPage/AjaxPage.php, now loadable using autoloader');
|
||||
//DeprecatedCallsLog::NotifyDeprecatedFile('moved to sources/Application/WebPage/AjaxPage.php, now loadable using autoloader');
|
||||
|
||||
/**
|
||||
* Class ajax_page
|
||||
|
||||
@@ -1402,11 +1402,11 @@ interface iBackofficeDictEntriesPrefixesExtension
|
||||
/**
|
||||
* Implement this interface to add content to any enhanced portal page
|
||||
*
|
||||
* IMPORTANT! Experimental API, may be removed at anytime, we don't recommend to use it just now!
|
||||
*
|
||||
* @api
|
||||
* @package Extensibility
|
||||
* @since 2.4.0
|
||||
*
|
||||
* @since 2.4.0 interface creation
|
||||
* @since 2.7.0 change method signatures due to Silex to Symfony migration
|
||||
*/
|
||||
interface iPortalUIExtension
|
||||
{
|
||||
@@ -1479,7 +1479,11 @@ interface iPortalUIExtension
|
||||
}
|
||||
|
||||
/**
|
||||
* IMPORTANT! Experimental API, may be removed at anytime, we don't recommend to use it just now!
|
||||
* Extend this class instead of iPortalUIExtension if you don't need to overload all methods
|
||||
*
|
||||
* @api
|
||||
* @package Extensibility
|
||||
* @since 2.4.0
|
||||
*/
|
||||
abstract class AbstractPortalUIExtension implements iPortalUIExtension
|
||||
{
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
<?php
|
||||
/**
|
||||
* @deprecated 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-2021 Combodo SARL
|
||||
*/
|
||||
|
||||
DeprecatedCallsLog::NotifyDeprecatedFile('moved to sources/application/WebPage/CaptureWebPage.php, now loadable using autoloader');
|
||||
DeprecatedCallsLog::NotifyDeprecatedFile('moved to sources/Application/WebPage/CaptureWebPage.php, now loadable using autoloader');
|
||||
@@ -1,8 +1,8 @@
|
||||
<?php
|
||||
/**
|
||||
* @deprecated 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-2021 Combodo SARL
|
||||
*/
|
||||
|
||||
DeprecatedCallsLog::NotifyDeprecatedFile('moved to sources/application/WebPage/CLIPage.php, now loadable using autoloader');
|
||||
DeprecatedCallsLog::NotifyDeprecatedFile('moved to sources/Application/WebPage/CLIPage.php, now loadable using autoloader');
|
||||
@@ -60,11 +60,11 @@ require_once(APPROOT.'application/ui.linksdirectwidget.class.inc.php');
|
||||
require_once(APPROOT.'application/ui.passwordwidget.class.inc.php');
|
||||
require_once(APPROOT.'application/ui.extkeywidget.class.inc.php');
|
||||
require_once(APPROOT.'application/ui.htmleditorwidget.class.inc.php');
|
||||
require_once(APPROOT.'sources/application/search/searchform.class.inc.php');
|
||||
require_once(APPROOT.'sources/application/search/criterionparser.class.inc.php');
|
||||
require_once(APPROOT.'sources/application/search/criterionconversionabstract.class.inc.php');
|
||||
require_once(APPROOT.'sources/application/search/criterionconversion/criteriontooql.class.inc.php');
|
||||
require_once(APPROOT.'sources/application/search/criterionconversion/criteriontosearchform.class.inc.php');
|
||||
require_once(APPROOT.'sources/Application/Search/searchform.class.inc.php');
|
||||
require_once(APPROOT.'sources/Application/Search/criterionparser.class.inc.php');
|
||||
require_once(APPROOT.'sources/Application/Search/criterionconversionabstract.class.inc.php');
|
||||
require_once(APPROOT.'sources/Application/Search/CriterionConversion/criteriontooql.class.inc.php');
|
||||
require_once(APPROOT.'sources/Application/Search/CriterionConversion/criteriontosearchform.class.inc.php');
|
||||
|
||||
/**
|
||||
* Class cmdbAbstractObject
|
||||
@@ -391,7 +391,8 @@ JS
|
||||
$oSingletonFilter = new DBObjectSearch(get_class($this));
|
||||
$oSingletonFilter->AddCondition('id', $this->GetKey(), '=');
|
||||
$oBlock = new MenuBlock($oSingletonFilter, 'details', false);
|
||||
$oActionMenuBlock = $oBlock->GetRenderContent($oPage);
|
||||
$sActionMenuId = utils::Sanitize(uniqid('', true), '', utils::ENUM_SANITIZATION_FILTER_ELEMENT_IDENTIFIER);
|
||||
$oActionMenuBlock = $oBlock->GetRenderContent($oPage, [], $sActionMenuId);
|
||||
$aHeaderBlocks['toolbar'][$oActionMenuBlock->GetId()] = $oActionMenuBlock;
|
||||
}
|
||||
|
||||
@@ -508,32 +509,6 @@ HTML
|
||||
return $aHeaderBlocks;
|
||||
}
|
||||
|
||||
/**
|
||||
* Display history tab of an object
|
||||
*
|
||||
* @deprecated 3.0.0 will be removed in 3.1, see N°3824
|
||||
*
|
||||
* @param bool $bEditMode
|
||||
* @param int $iLimitCount
|
||||
* @param int $iLimitStart
|
||||
*
|
||||
* @param \WebPage $oPage
|
||||
*
|
||||
* @throws \CoreException
|
||||
*
|
||||
*/
|
||||
public function DisplayBareHistory(WebPage $oPage, $bEditMode = false, $iLimitCount = 0, $iLimitStart = 0)
|
||||
{
|
||||
DeprecatedCallsLog::NotifyDeprecatedPhpMethod();
|
||||
// history block (with as a tab)
|
||||
$oHistoryFilter = new DBObjectSearch('CMDBChangeOp');
|
||||
$oHistoryFilter->AddCondition('objkey', $this->GetKey(), '=');
|
||||
$oHistoryFilter->AddCondition('objclass', get_class($this), '=');
|
||||
$oBlock = new HistoryBlock($oHistoryFilter, 'table', false);
|
||||
$oBlock->SetLimit($iLimitCount, $iLimitStart);
|
||||
$oBlock->Display($oPage, 'history');
|
||||
}
|
||||
|
||||
/**
|
||||
* Display properties tab of an object
|
||||
*
|
||||
@@ -649,11 +624,17 @@ HTML
|
||||
if ($oAttDef instanceof AttributeDashboard) {
|
||||
if (!$this->IsNew()) {
|
||||
$sHostContainerInEditionUrlParam = ($bEditMode) ? '&host_container_in_edition=true' : '';
|
||||
$oPage->AddAjaxTab($oAttDef->GetLabel(),
|
||||
utils::GetAbsoluteUrlAppRoot().'pages/ajax.render.php?operation=dashboard&class='.get_class($this).'&id='.$this->GetKey().'&attcode='.$oAttDef->GetCode().$sHostContainerInEditionUrlParam,
|
||||
true,
|
||||
$oPage->AddAjaxTab(
|
||||
'Class:'.$sClass.'/Attribute:'.$sAttCode,
|
||||
AjaxTab::ENUM_TAB_PLACEHOLDER_DASHBOARD);
|
||||
utils::GetAbsoluteUrlAppRoot().'pages/ajax.render.php?operation=dashboard&class='
|
||||
.get_class($this)
|
||||
.'&id='.$this->GetKey()
|
||||
.'&attcode='.$oAttDef->GetCode()
|
||||
.$sHostContainerInEditionUrlParam,
|
||||
true,
|
||||
$oAttDef->GetLabel(),
|
||||
AjaxTab::ENUM_TAB_PLACEHOLDER_DASHBOARD
|
||||
);
|
||||
// Add graphs dependencies
|
||||
WebResourcesHelper::EnableC3JSToWebPage($oPage);
|
||||
}
|
||||
@@ -1179,8 +1160,6 @@ HTML
|
||||
$oPage->SetCurrentTab('UI:PropertiesTab');
|
||||
$this->DisplayBareProperties($oPage, $bEditMode);
|
||||
$this->DisplayBareRelations($oPage, $bEditMode);
|
||||
// TODO 3.0.0: What to do with this?
|
||||
//$this->DisplayBareHistory($oPage, $bEditMode);
|
||||
|
||||
// Note: Adding the JS snippet which enables the image upload should have been done directly by the ActivityPanel which would have kept the independance principle
|
||||
// of the UIBlock. For now we keep it this way in order to move on and trace this known limitation in N°3736.
|
||||
@@ -1739,6 +1718,9 @@ HTML
|
||||
* @param array $aParams
|
||||
*
|
||||
* @throws \Exception
|
||||
* only used in old and deprecated export.php
|
||||
*
|
||||
* @internal Only to be used by `/webservices/export.php` : this is a legacy method that produces wrong HTML (no TR on table body rows)
|
||||
*/
|
||||
public static function DisplaySetAsHTMLSpreadsheet(WebPage $oPage, CMDBObjectSet $oSet, $aParams = array())
|
||||
{
|
||||
@@ -1759,6 +1741,8 @@ HTML
|
||||
* @throws \MySQLException
|
||||
* @throws \MySQLHasGoneAwayException
|
||||
* @throws \Exception
|
||||
*
|
||||
* @internal Only to be used by `/webservices/export.php` : this is a legacy method that produces wrong HTML (no TR on table body rows)
|
||||
*/
|
||||
public static function GetSetAsHTMLSpreadsheet(DBObjectSet $oSet, $aParams = array())
|
||||
{
|
||||
@@ -4231,13 +4215,20 @@ HTML;
|
||||
if (!is_null($oImage->GetData()))
|
||||
{
|
||||
$aSize = utils::GetImageSize($oImage->GetData());
|
||||
$oImage = utils::ResizeImageToFit(
|
||||
$oImage,
|
||||
$aSize[0],
|
||||
$aSize[1],
|
||||
$oAttDef->Get('storage_max_width'),
|
||||
$oAttDef->Get('storage_max_height')
|
||||
);
|
||||
if (is_array($aSize) && $aSize[0] > 0 && $aSize[1] > 0)
|
||||
{
|
||||
$oImage = utils::ResizeImageToFit(
|
||||
$oImage,
|
||||
$aSize[0],
|
||||
$aSize[1],
|
||||
$oAttDef->Get('storage_max_width'),
|
||||
$oAttDef->Get('storage_max_height')
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
IssueLog::Warning($sClass . ':' . $this->GetKey() . '/' . $sAttCode . ': Image could not be resized. Mimetype: ' . $oImage->GetMimeType() . ', filename: ' . $oImage->GetFileName());
|
||||
}
|
||||
}
|
||||
$aOtherData = utils::ReadPostedParam("attr_{$sFormPrefix}{$sAttCode}", null, 'raw_data');
|
||||
if (is_array($aOtherData))
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
<?php
|
||||
/**
|
||||
* @deprecated 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-2021 Combodo SARL
|
||||
*/
|
||||
|
||||
DeprecatedCallsLog::NotifyDeprecatedFile('moved to sources/application/WebPage/CSVPage.php, now loadable using autoloader');
|
||||
DeprecatedCallsLog::NotifyDeprecatedFile('moved to sources/Application/WebPage/CSVPage.php, now loadable using autoloader');
|
||||
@@ -583,7 +583,7 @@ JS
|
||||
$oPage->add('<div id="select_dashlet" class="ibo-dashboard--available-dashlets--list" data-role="ibo-dashboard--available-dashlets--list">');
|
||||
$aAvailableDashlets = $this->GetAvailableDashlets();
|
||||
foreach ($aAvailableDashlets as $sDashletClass => $aInfo) {
|
||||
$oPage->add('<span dashlet_class="'.$sDashletClass.'" class="ibo-dashboard-editor--available-dashlet-icon dashlet_icon ui-widget-content ui-corner-all" data-role="ibo-dashboard-editor--available-dashlet-icon" id="dashlet_'.$sDashletClass.'" title="'.$aInfo['label'].'"><img src="'.$sUrl.$aInfo['icon'].'" /></span>');
|
||||
$oPage->add('<span dashlet_class="'.$sDashletClass.'" class="ibo-dashboard-editor--available-dashlet-icon dashlet_icon ui-widget-content ui-corner-all" data-role="ibo-dashboard-editor--available-dashlet-icon" id="dashlet_'.$sDashletClass.'" data-tooltip-content="'.$aInfo['label'].'" title="'.$aInfo['label'].'"><img src="'.$sUrl.$aInfo['icon'].'" /></span>');
|
||||
}
|
||||
$oPage->add('</div>');
|
||||
|
||||
@@ -789,6 +789,7 @@ class RuntimeDashboard extends Dashboard
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
* @return bool $bIsNew
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function Save()
|
||||
@@ -798,6 +799,7 @@ class RuntimeDashboard extends Dashboard
|
||||
$oUDSearch->AddCondition('user_id', UserRights::GetUserId(), '=');
|
||||
$oUDSearch->AddCondition('menu_code', $this->sId, '=');
|
||||
$oUDSet = new DBObjectSet($oUDSearch);
|
||||
$bIsNew = false;
|
||||
if ($oUDSet->Count() > 0)
|
||||
{
|
||||
// Assuming there is at most one couple {user, menu}!
|
||||
@@ -811,10 +813,12 @@ class RuntimeDashboard extends Dashboard
|
||||
$oUserDashboard->Set('user_id', UserRights::GetUserId());
|
||||
$oUserDashboard->Set('menu_code', $this->sId);
|
||||
$oUserDashboard->Set('contents', $sXml);
|
||||
$bIsNew = true;
|
||||
}
|
||||
utils::PushArchiveMode(false);
|
||||
$oUserDashboard->DBWrite();
|
||||
utils::PopArchiveMode();
|
||||
return $bIsNew;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1066,11 +1070,11 @@ EOF
|
||||
dashboard.html(data);
|
||||
dashboard.unblock();
|
||||
if ($('#ibo-dashboard-selector$sDivId input').prop("checked")) {
|
||||
$('#ibo-dashboard-selector$sDivId').data('tooltip-content', '$sSwitchToStandard');
|
||||
$('#ibo-dashboard-selector$sDivId').attr('data-tooltip-content', '$sSwitchToStandard');
|
||||
} else {
|
||||
$('#ibo-dashboard-selector$sDivId').data('tooltip-content', '$sSwitchToCustom');
|
||||
$('#ibo-dashboard-selector$sDivId').attr('data-tooltip-content', '$sSwitchToCustom');
|
||||
}
|
||||
CombodoTooltip.InitAllNonInstantiatedTooltips($('#ibo-dashboard-selector$sDivId').parent());
|
||||
CombodoTooltip.InitAllNonInstantiatedTooltips($('#ibo-dashboard-selector$sDivId').parent(), true);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<itop_design xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="3.0">
|
||||
<itop_design xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="3.1">
|
||||
<classes>
|
||||
<class id="AbstractResource" _delta="define">
|
||||
<parent>cmdbAbstractObject</parent>
|
||||
|
||||
@@ -476,7 +476,7 @@ class DisplayBlock
|
||||
$oExceptionAlert = AlertUIBlockFactory::MakeForFailure('Cannot display results', $sExceptionContent);
|
||||
$oHtml->AddSubBlock($oExceptionAlert);
|
||||
}
|
||||
IssueLog::Error('Exception during GetDisplay: '.$e->getMessage());
|
||||
ExceptionLog::LogException($e);
|
||||
}
|
||||
} else {
|
||||
// render it as an Ajax (asynchronous) call
|
||||
@@ -539,8 +539,10 @@ class DisplayBlock
|
||||
* @throws DictExceptionMissingString
|
||||
* @throws MySQLException
|
||||
* @throws Exception
|
||||
*
|
||||
* @since 2.7.7 3.0.1 3.1.0 N°3129 add type hinting to $aExtraParams
|
||||
*/
|
||||
public function GetRenderContent(WebPage $oPage, array $aExtraParams = [], string $sId = null)
|
||||
public function GetRenderContent(WebPage $oPage, array $aExtraParams, string $sId)
|
||||
{
|
||||
$sHtml = '';
|
||||
$oBlock = null;
|
||||
@@ -853,7 +855,7 @@ JS
|
||||
{
|
||||
$oField = new FieldExpression($sFilterCode, $oFilter->GetClassAlias());
|
||||
$sListExpr = '('.implode(', ', CMDBSource::Quote($condition)).')';
|
||||
$sOQLCondition = $oField->Render()." IN $sListExpr";
|
||||
$sOQLCondition = $oField->RenderExpression()." IN $sListExpr";
|
||||
$oNewCondition = Expression::FromOQL($sOQLCondition);
|
||||
return $oNewCondition;
|
||||
}
|
||||
@@ -1052,6 +1054,11 @@ JS
|
||||
$oBlock->AddSubBlock($oPill);
|
||||
}
|
||||
$aExtraParams['query_params'] = $this->m_oFilter->GetInternalParams();
|
||||
if(isset($aExtraParams['query_params']['this->object()'])){
|
||||
$aExtraParams['query_params']['this->class'] = get_class($aExtraParams['query_params']['this->object()']);
|
||||
$aExtraParams['query_params']['this->id'] = $aExtraParams['query_params']['this->object()']->GetKey();
|
||||
unset($aExtraParams['query_params']['this->object()']);
|
||||
}
|
||||
$aRefreshParams = ['filter' => $this->m_oFilter->ToOQL(), "extra_params" => json_encode($aExtraParams)];
|
||||
$oBlock->SetJSRefresh(
|
||||
"$('#".$oBlock->GetId()."').block();
|
||||
@@ -1698,145 +1705,6 @@ JS
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper class to manage 'blocks' of HTML pieces that are parts of a page and contain some list of cmdb objects
|
||||
*
|
||||
* Each block is actually rendered as a <div></div> tag that can be rendered synchronously
|
||||
* or as a piece of Javascript/JQuery/Ajax that will get its content from another page (ajax.render.php).
|
||||
* The list of cmdbObjects to be displayed into the block is defined by a filter
|
||||
* Right now the type of display is either: list, count or details
|
||||
* - list produces a table listing the objects
|
||||
* - count produces a paragraphs with a sentence saying 'cont' objects found
|
||||
* - details display (as table) the details of each object found (best if only one)
|
||||
*
|
||||
* @deprecated 3.0.0 will be removed in 3.1, see N°3824
|
||||
*/
|
||||
class HistoryBlock extends DisplayBlock
|
||||
{
|
||||
protected $iLimitCount;
|
||||
protected $iLimitStart;
|
||||
|
||||
public function __construct(DBSearch $oFilter, $sStyle = 'list', $bAsynchronous = false, $aParams = array(), $oSet = null)
|
||||
{
|
||||
DeprecatedCallsLog::NotifyDeprecatedPhpMethod();
|
||||
parent::__construct($oFilter, $sStyle, $bAsynchronous, $aParams, $oSet);
|
||||
$this->iLimitStart = 0;
|
||||
$this->iLimitCount = 0;
|
||||
}
|
||||
|
||||
public function SetLimit($iCount, $iStart = 0)
|
||||
{
|
||||
$this->iLimitStart = $iStart;
|
||||
$this->iLimitCount = $iCount;
|
||||
}
|
||||
|
||||
public function GetRenderContent(WebPage $oPage, array $aExtraParams = [], string $sId = null)
|
||||
{
|
||||
$sHtml = '';
|
||||
$bTruncated = false;
|
||||
$oSet = new CMDBObjectSet($this->m_oFilter, array('date' => false));
|
||||
if (!$oPage->IsPrintableVersion()) {
|
||||
if (($this->iLimitStart > 0) || ($this->iLimitCount > 0)) {
|
||||
$oSet->SetLimit($this->iLimitCount, $this->iLimitStart);
|
||||
if (($this->iLimitCount - $this->iLimitStart) < $oSet->Count()) {
|
||||
$bTruncated = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
$sHtml .= "<!-- filter: ".($this->m_oFilter->ToOQL())."-->\n";
|
||||
switch ($this->m_sStyle) {
|
||||
case 'toggle':
|
||||
// First the latest change that the user is allowed to see
|
||||
do {
|
||||
$oLatestChangeOp = $oSet->Fetch();
|
||||
} while (is_object($oLatestChangeOp) && ($oLatestChangeOp->GetDescription() == ''));
|
||||
|
||||
if (is_object($oLatestChangeOp)) {
|
||||
// There is one change in the list... only when the object has been created !
|
||||
$sDate = $oLatestChangeOp->GetAsHTML('date');
|
||||
$oChange = MetaModel::GetObject('CMDBChange', $oLatestChangeOp->Get('change'));
|
||||
$sUserInfo = $oChange->GetAsHTML('userinfo');
|
||||
$sHtml .= $oPage->GetStartCollapsibleSection(Dict::Format('UI:History:LastModified_On_By', $sDate, $sUserInfo));
|
||||
$sHtml .= $this->GetHistoryTable($oPage, $oSet);
|
||||
$sHtml .= $oPage->GetEndCollapsibleSection();
|
||||
}
|
||||
break;
|
||||
|
||||
case 'table':
|
||||
default:
|
||||
if ($bTruncated)
|
||||
{
|
||||
$sFilter = htmlentities($this->m_oFilter->serialize(), ENT_QUOTES, 'UTF-8');
|
||||
$sHtml .= '<div id="history_container"><p>';
|
||||
$sHtml .= Dict::Format('UI:TruncatedResults', $this->iLimitCount, $oSet->Count());
|
||||
$sHtml .= ' ';
|
||||
$sHtml .= '<a href="#" onclick="DisplayHistory(\'#history_container\', \''.$sFilter.'\', 0, 0); return false;">'.Dict::S('UI:DisplayAll').'</a>';
|
||||
$sHtml .= $this->GetHistoryTable($oPage, $oSet);
|
||||
$sHtml .= '</p></div>';
|
||||
$oPage->add_ready_script("$('#{$sId} table.listResults tr:last td').addClass('truncated');");
|
||||
}
|
||||
else
|
||||
{
|
||||
$sHtml .= $this->GetHistoryTable($oPage, $oSet);
|
||||
}
|
||||
$oPage->add_ready_script(InlineImage::FixImagesWidth());
|
||||
|
||||
$oPage->add_ready_script("$('.case-log-history-entry-toggle').on('click', function () { $(this).closest('.case-log-history-entry').toggleClass('expanded');});");
|
||||
$oPage->add_ready_script(
|
||||
<<<EOF
|
||||
$('.history_entry').each(function() {
|
||||
var jMe = $(this);
|
||||
var oContent = $(this).find('.history_html_content');
|
||||
if (jMe.height() < oContent.height())
|
||||
{
|
||||
jMe.prepend('<span class="history_truncated_toggler"></span>');
|
||||
jMe.find('.history_truncated_toggler').on('click', function() {
|
||||
jMe.toggleClass('history_entry_truncated');
|
||||
});
|
||||
}
|
||||
});
|
||||
EOF
|
||||
);
|
||||
}
|
||||
return new Html($sHtml);
|
||||
}
|
||||
|
||||
protected function GetHistoryTable(WebPage $oPage, DBObjectSet $oSet)
|
||||
{
|
||||
$sHtml = '';
|
||||
// First the latest change that the user is allowed to see
|
||||
$oSet->Rewind(); // Reset the pointer to the beginning of the set
|
||||
$aChanges = array();
|
||||
while($oChangeOp = $oSet->Fetch())
|
||||
{
|
||||
$sChangeDescription = $oChangeOp->GetDescription();
|
||||
if ($sChangeDescription != '')
|
||||
{
|
||||
// The change is visible for the current user
|
||||
$changeId = $oChangeOp->Get('change');
|
||||
$aChanges[$changeId]['date'] = $oChangeOp->Get('date');
|
||||
$aChanges[$changeId]['userinfo'] = $oChangeOp->Get('userinfo');
|
||||
if (!isset($aChanges[$changeId]['log']))
|
||||
{
|
||||
$aChanges[$changeId]['log'] = array();
|
||||
}
|
||||
$aChanges[$changeId]['log'][] = $sChangeDescription;
|
||||
}
|
||||
}
|
||||
$aAttribs = array('date' => array('label' => Dict::S('UI:History:Date'), 'description' => Dict::S('UI:History:Date+')),
|
||||
'userinfo' => array('label' => Dict::S('UI:History:User'), 'description' => Dict::S('UI:History:User+')),
|
||||
'log' => array('label' => Dict::S('UI:History:Changes') , 'description' => Dict::S('UI:History:Changes+')),
|
||||
);
|
||||
$aValues = array();
|
||||
foreach($aChanges as $aChange)
|
||||
{
|
||||
$aValues[] = array('date' => AttributeDateTime::GetFormat()->Format($aChange['date']), 'userinfo' => htmlentities($aChange['userinfo'], ENT_QUOTES, 'UTF-8'), 'log' => "<ul><li>".implode('</li><li>', $aChange['log'])."</li></ul>");
|
||||
}
|
||||
$sHtml .= $oPage->GetTable($aAttribs, $aValues);
|
||||
return $sHtml;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays the 'Actions' menu for a given (list of) object(s)
|
||||
* The 'style' of the list (see constructor of DisplayBlock) can be either 'list' or 'details'
|
||||
@@ -1871,11 +1739,10 @@ class MenuBlock extends DisplayBlock
|
||||
* @throws \DictExceptionMissingString
|
||||
* @throws \MissingQueryArgument
|
||||
* @throws \MySQLException
|
||||
* @throws \MySQLHasGoneAwayException
|
||||
* @throws \OQLException
|
||||
* @throws \ReflectionException
|
||||
*
|
||||
* @since 2.7.7 3.0.1 3.1.0 N°3129 Remove default value and add type hinting on $aExtraParams for PHP 8.0 compatibility
|
||||
*/
|
||||
public function GetRenderContent(WebPage $oPage, array $aExtraParams = [], string $sId = null)
|
||||
public function GetRenderContent(WebPage $oPage, array $aExtraParams, string $sId)
|
||||
{
|
||||
$oRenderBlock = new UIContentBlock();
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
<?php
|
||||
/**
|
||||
* @deprecated 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-2021 Combodo SARL
|
||||
*/
|
||||
|
||||
DeprecatedCallsLog::NotifyDeprecatedFile('moved to sources/application/WebPage/ErrorPage.php, now loadable using autoloader');
|
||||
DeprecatedCallsLog::NotifyDeprecatedFile('moved to sources/Application/WebPage/ErrorPage.php, now loadable using autoloader');
|
||||
@@ -1272,7 +1272,7 @@ class DesignerComboField extends DesignerFormField
|
||||
$sChecked = $this->defaultValue ? 'checked' : '';
|
||||
$sMandatory = $this->bMandatory ? 'true' : 'false';
|
||||
$sReadOnly = $this->IsReadOnly() ? 'disabled="disabled"' : '';
|
||||
if ($this->IsSorted())
|
||||
if ($this->IsSorted() && isset($this->aAllowedValues) )
|
||||
{
|
||||
asort($this->aAllowedValues);
|
||||
}
|
||||
@@ -1320,19 +1320,17 @@ class DesignerComboField extends DesignerFormField
|
||||
$sHtml .= "<option value=\"\">".$this->sNullLabel."</option>";
|
||||
}
|
||||
}
|
||||
foreach($this->aAllowedValues as $sKey => $sDisplayValue)
|
||||
{
|
||||
if ($this->bMultipleSelection)
|
||||
{
|
||||
$sSelected = in_array($sKey, $this->defaultValue) ? 'selected' : '';
|
||||
if ( isset($this->aAllowedValues) ) {
|
||||
foreach ($this->aAllowedValues as $sKey => $sDisplayValue) {
|
||||
if ($this->bMultipleSelection) {
|
||||
$sSelected = in_array($sKey, $this->defaultValue) ? 'selected' : '';
|
||||
} else {
|
||||
$sSelected = ($sKey == $this->defaultValue) ? 'selected' : '';
|
||||
}
|
||||
// Quick and dirty: display the menu parents as a tree
|
||||
$sHtmlValue = str_replace(' ', ' ', $sDisplayValue);
|
||||
$sHtml .= "<option value=\"".htmlentities($sKey, ENT_QUOTES, 'UTF-8')."\" $sSelected>$sHtmlValue</option>";
|
||||
}
|
||||
else
|
||||
{
|
||||
$sSelected = ($sKey == $this->defaultValue) ? 'selected' : '';
|
||||
}
|
||||
// Quick and dirty: display the menu parents as a tree
|
||||
$sHtmlValue = str_replace(' ', ' ', htmlentities($sDisplayValue, ENT_QUOTES, 'UTF-8'));
|
||||
$sHtml .= "<option value=\"".htmlentities($sKey, ENT_QUOTES, 'UTF-8')."\" $sSelected>$sHtmlValue</option>";
|
||||
}
|
||||
$sHtml .= "</select></span>";
|
||||
if ($this->bOtherChoices)
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
<?php
|
||||
/**
|
||||
* @deprecated 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-2021 Combodo SARL
|
||||
*/
|
||||
|
||||
// cannot notify depreciation for now as this is still MASSIVELY used in iTop core !
|
||||
//DeprecatedCallsLog::NotifyDeprecatedFile('moved to sources/application/WebPage/iTopWebPage.php, now loadable using autoloader');
|
||||
//DeprecatedCallsLog::NotifyDeprecatedFile('moved to sources/Application/WebPage/iTopWebPage.php, now loadable using autoloader');
|
||||
@@ -1,8 +1,8 @@
|
||||
<?php
|
||||
/**
|
||||
* @deprecated 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-2021 Combodo SARL
|
||||
*/
|
||||
|
||||
DeprecatedCallsLog::NotifyDeprecatedFile('moved to sources/application/WebPage/iTopWizardWebPage.php, now loadable using autoloader');
|
||||
DeprecatedCallsLog::NotifyDeprecatedFile('moved to sources/Application/WebPage/iTopWizardWebPage.php, now loadable using autoloader');
|
||||
@@ -483,6 +483,7 @@ class LoginWebPage extends NiceWebPage
|
||||
$iResponse = $oLoginFSMExtensionInstance->LoginAction($sLoginState, $iErrorCode);
|
||||
if ($iResponse == self::LOGIN_FSM_RETURN)
|
||||
{
|
||||
Session::WriteClose();
|
||||
return $iErrorCode; // Asked to exit FSM, generally login OK
|
||||
}
|
||||
if ($iResponse == self::LOGIN_FSM_ERROR)
|
||||
|
||||
@@ -77,17 +77,28 @@ function _MaintenanceHtmlMessage($sMessage)
|
||||
*/
|
||||
function _MaintenanceJsonMessage($sTitle, $sMessage)
|
||||
{
|
||||
@include_once(APPROOT."/application/ajaxwebpage.class.inc.php");
|
||||
if (class_exists('ajax_page'))
|
||||
if (class_exists('JsonPage'))
|
||||
{
|
||||
$oP = new ajax_page($sTitle);
|
||||
$oP = new JsonPage($sTitle);
|
||||
$oP->add_header('Access-Control-Allow-Origin: *');
|
||||
$oP->SetContentType('application/json');
|
||||
$oP->add('{"code":100, "message":"'.$sMessage.'"}');
|
||||
|
||||
$aMessage = [
|
||||
'code' => 100,
|
||||
'message' =>$sMessage
|
||||
];
|
||||
|
||||
$oP->AddData($aMessage);
|
||||
$oP->Output();
|
||||
}
|
||||
else
|
||||
{
|
||||
_MaintenanceTextMessage($sMessage);
|
||||
} else {
|
||||
@include_once(APPROOT."/application/ajaxwebpage.class.inc.php");
|
||||
if (class_exists('ajax_page')) {
|
||||
$oP = new ajax_page($sTitle);
|
||||
$oP->add_header('Access-Control-Allow-Origin: *');
|
||||
$oP->SetContentType('application/json');
|
||||
$oP->add('{"code":100, "message":"'.$sMessage.'"}');
|
||||
$oP->Output();
|
||||
} else {
|
||||
_MaintenanceTextMessage($sMessage);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
*/
|
||||
|
||||
use Combodo\iTop\Application\Helper\WebResourcesHelper;
|
||||
use Combodo\iTop\Application\UI\Base\Component\Title\Title;
|
||||
use Combodo\iTop\Application\UI\Base\Component\Title\TitleUIBlockFactory;
|
||||
|
||||
require_once(APPROOT.'/application/utils.inc.php');
|
||||
@@ -1126,16 +1127,20 @@ class OQLMenuNode extends MenuNode
|
||||
{
|
||||
$sUsageId = utils::GetSafeId($sUsageId);
|
||||
$oSearch = DBObjectSearch::FromOQL($sOql);
|
||||
|
||||
$sClass= $oSearch->GetClass();
|
||||
$sIcon = MetaModel::GetClassIcon($sClass, false);
|
||||
if ($bSearchPane) {
|
||||
$aParams = array_merge(['open' => $bSearchOpen, 'table_id' => $sUsageId, 'submit_on_load' => false], $aExtraParams);
|
||||
$oBlock = new DisplayBlock($oSearch, 'search', false /* Asynchronous */, $aParams);
|
||||
$oBlock->Display($oPage, 0);
|
||||
$oPage->add("<div class='sf_results_area ibo-add-margin-top-250' data-target='search_results'>");
|
||||
}
|
||||
|
||||
$oPage->add("<div class='sf_results_area' data-target='search_results'>");
|
||||
$oTitle = TitleUIBlockFactory::MakeForPage($sTitle);
|
||||
$oPage->AddUiBlock($oTitle);
|
||||
else {
|
||||
$oPage->add("<div class='sf_results_area' data-target='search_results'>");
|
||||
}
|
||||
$aExtraParams['panel_class'] =$sClass;
|
||||
$aExtraParams['panel_title'] = $sTitle;
|
||||
$aExtraParams['panel_icon'] = $sIcon;
|
||||
|
||||
$aParams = array_merge(array('table_id' => $sUsageId), $aExtraParams);
|
||||
$oBlock = new DisplayBlock($oSearch, 'list', false /* Asynchronous */, $aParams);
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
<?php
|
||||
/**
|
||||
* @deprecated 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-2021 Combodo SARL
|
||||
*/
|
||||
|
||||
DeprecatedCallsLog::NotifyDeprecatedFile('moved to sources/application/WebPage/NiceWebPage.php, now loadable using autoloader');
|
||||
DeprecatedCallsLog::NotifyDeprecatedFile('moved to sources/Application/WebPage/NiceWebPage.php, now loadable using autoloader');
|
||||
@@ -1,8 +1,8 @@
|
||||
<?php
|
||||
/**
|
||||
* @deprecated 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-2021 Combodo SARL
|
||||
*/
|
||||
|
||||
DeprecatedCallsLog::NotifyDeprecatedFile('moved to sources/application/WebPage/PDFPage.php, now loadable using autoloader');
|
||||
DeprecatedCallsLog::NotifyDeprecatedFile('moved to sources/Application/WebPage/PDFPage.php, now loadable using autoloader');
|
||||
@@ -18,8 +18,7 @@
|
||||
*/
|
||||
|
||||
use Combodo\iTop\Application\UI\Base\Component\Alert\AlertUIBlockFactory;
|
||||
use Combodo\iTop\Application\UI\Base\Component\Field\Field;
|
||||
use Combodo\iTop\Application\UI\Base\Component\Field\FieldUIBlockFactory;
|
||||
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;
|
||||
|
||||
@@ -51,6 +50,7 @@ abstract class Query extends cmdbAbstractObject
|
||||
"is_null_allowed" => false,
|
||||
"depends_on" => array(),
|
||||
)));
|
||||
|
||||
MetaModel::Init_AddAttribute(new AttributeText("description", array(
|
||||
"allowed_values" => null,
|
||||
"sql" => "description",
|
||||
@@ -68,6 +68,41 @@ abstract class Query extends cmdbAbstractObject
|
||||
'display_style' => 'radio_horizontal',
|
||||
)));
|
||||
|
||||
MetaModel::Init_AddAttribute(new AttributeInteger("export_count", array(
|
||||
"allowed_values" => null,
|
||||
"sql" => "export_count",
|
||||
"default_value" => 0,
|
||||
"is_null_allowed" => false,
|
||||
"depends_on" => array(),
|
||||
)));
|
||||
|
||||
MetaModel::Init_AddAttribute(new AttributeDateTime("export_last_date", array(
|
||||
"allowed_values" => null,
|
||||
"sql" => "export_last_date",
|
||||
"default_value" => null,
|
||||
"is_null_allowed" => true,
|
||||
"depends_on" => array(),
|
||||
)));
|
||||
|
||||
MetaModel::Init_AddAttribute(new AttributeExternalKey("export_last_user_id",
|
||||
array(
|
||||
"targetclass"=>'User',
|
||||
"allowed_values"=>null,
|
||||
"sql"=>'user_id',
|
||||
"is_null_allowed"=>true,
|
||||
"depends_on"=>array(),
|
||||
"display_style"=>'select',
|
||||
"always_load_in_tables"=>false,
|
||||
"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"
|
||||
)));
|
||||
|
||||
// Display lists
|
||||
MetaModel::Init_SetZListItems('details',
|
||||
array('name', 'is_template', 'description')); // Attributes to be displayed for the complete details
|
||||
@@ -78,6 +113,54 @@ abstract class Query extends cmdbAbstractObject
|
||||
array('name', 'description', 'is_template')); // Criteria of the default search form
|
||||
// MetaModel::Init_SetZListItems('advanced_search', array('name')); // Criteria of the advanced search form
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*
|
||||
* @since 3.1.0
|
||||
*/
|
||||
public function GetAttributeFlags($sAttCode, &$aReasons = array(), $sTargetState = '')
|
||||
{
|
||||
// read only attribute
|
||||
if (in_array($sAttCode, ['export_count', 'export_last_date', 'export_last_user_id'])){
|
||||
return OPT_ATT_READONLY;
|
||||
}
|
||||
|
||||
return parent::GetAttributeFlags($sAttCode, $aReasons, $sTargetState);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return export url.
|
||||
*
|
||||
* @param array|null $aValues optional values for the query
|
||||
*
|
||||
* @return string|null
|
||||
* @since 3.1.0
|
||||
*/
|
||||
abstract public function GetExportUrl(array $aValues = null) : ?string;
|
||||
|
||||
/**
|
||||
* Update last export information.
|
||||
*
|
||||
* @return void
|
||||
* @throws \ArchivedObjectException
|
||||
* @throws \CoreException
|
||||
* @throws \CoreUnexpectedValue
|
||||
* @throws \MySQLException
|
||||
* @since 3.1.0
|
||||
*/
|
||||
public function UpdateLastExportInformation() : void
|
||||
{
|
||||
// last export information
|
||||
$this->Set('export_last_date', date(AttributeDateTime::GetSQLFormat()));
|
||||
$this->Set('export_last_user_id', UserRights::GetUserObject());
|
||||
$this->DBUpdate();
|
||||
|
||||
// increment usage counter
|
||||
$this->DBIncrement('export_count');
|
||||
}
|
||||
}
|
||||
|
||||
class QueryOQL extends Query
|
||||
@@ -116,13 +199,51 @@ class QueryOQL extends Query
|
||||
|
||||
// Display lists
|
||||
MetaModel::Init_SetZListItems('details',
|
||||
array('name', 'is_template', 'description', 'oql', 'fields')); // Attributes to be displayed for the complete details
|
||||
array(
|
||||
'col:col1' => array('fieldset:Query:baseinfo' => array('name', 'is_template', 'description', 'oql', 'fields')),
|
||||
'col:col2' => array('fieldset:Query:exportInfo' => array('export_count', 'export_last_date', 'export_last_user_id', 'export_last_user_contact'))
|
||||
)
|
||||
); // Attributes to be displayed for the complete details
|
||||
MetaModel::Init_SetZListItems('list', array('description')); // Attributes to be displayed for a list
|
||||
// Search criteria
|
||||
MetaModel::Init_SetZListItems('standard_search',
|
||||
array('name', 'description', 'is_template', 'fields', 'oql')); // Criteria of the std search form
|
||||
}
|
||||
|
||||
/** @inheritdoc */
|
||||
public function GetExportUrl(array $aValues = null) : ?string
|
||||
{
|
||||
try{
|
||||
// retrieve attributes
|
||||
$sFields = trim($this->Get('fields'));
|
||||
$sOql = $this->Get('oql');
|
||||
|
||||
// construct base url depending on version
|
||||
$bExportV1Recommended = ($sFields == '');
|
||||
if ($bExportV1Recommended) {
|
||||
$sUrl = utils::GetAbsoluteUrlAppRoot().'webservices/export.php?format=spreadsheet&login_mode=basic&query='.$this->GetKey();
|
||||
}
|
||||
else{
|
||||
$sUrl = utils::GetAbsoluteUrlAppRoot().'webservices/export-v2.php?format=spreadsheet&login_mode=basic&date_format='.urlencode((string)AttributeDateTime::GetFormat()).'&query='.$this->GetKey();
|
||||
}
|
||||
|
||||
// search object from OQL
|
||||
$oSearch = DBObjectSearch::FromOQL($sOql);
|
||||
|
||||
// inject parameters
|
||||
$aParameters = $oSearch->GetQueryParams();
|
||||
foreach ($aParameters as $sParam => $val) {
|
||||
$paramValue = ($aValues === null || $aValues[$sParam] === null) ? $sParam : $aValues[$sParam];
|
||||
$sUrl .= '&arg_' . $sParam . '=' . $paramValue;
|
||||
}
|
||||
|
||||
return $sUrl;
|
||||
}
|
||||
catch(Exception $e){
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
function DisplayBareProperties(WebPage $oPage, $bEditMode = false, $sPrefix = '', $aExtraParams = array())
|
||||
{
|
||||
$aFieldsMap = parent::DisplayBareProperties($oPage, $bEditMode, $sPrefix, $aExtraParams);
|
||||
@@ -152,9 +273,11 @@ class QueryOQL extends Query
|
||||
$sUrl .= '&arg_'.$sParam.'=["'.$sParam.'"]';
|
||||
}
|
||||
|
||||
// add text area inside field set
|
||||
$oFieldSet = FieldSetUIBlockFactory::MakeStandard(Dict::S('UI:Query:UrlForExcel'));
|
||||
$oTextArea = new TextArea("", $sUrl, null, 80, 3);
|
||||
$oFieldUrl = FieldUIBlockFactory::MakeFromObject(Dict::S('UI:Query:UrlForExcel'), $oTextArea, Field::ENUM_FIELD_LAYOUT_LARGE);
|
||||
$oPage->AddSubBlock($oFieldUrl);
|
||||
$oFieldSet->AddSubBlock($oTextArea);
|
||||
$oPage->AddSubBlock($oFieldSet);
|
||||
|
||||
if (count($aParameters) == 0) {
|
||||
$oBlock = new DisplayBlock($oSearch, 'list');
|
||||
@@ -178,6 +301,7 @@ class QueryOQL extends Query
|
||||
return $aFieldsMap;
|
||||
}
|
||||
|
||||
|
||||
// Rolled back until 'fields' can be properly managed by AttributeQueryAttCodeSet
|
||||
//
|
||||
// public function ComputeValues()
|
||||
|
||||
@@ -288,7 +288,8 @@ class ShortcutOQL extends Shortcut
|
||||
$oPage->add_ready_script(
|
||||
<<<JS
|
||||
// Note: the title gets deleted by the validation mechanism
|
||||
$("#attr_auto_reload_sec").tooltip({items: 'input', content: '$sRateTitle'});
|
||||
$("#attr_auto_reload_sec").attr('data-tooltip-content', '$sRateTitle');
|
||||
CombodoTooltip.InitTooltipFromMarkup($("#attr_auto_reload_sec"));
|
||||
$("#attr_auto_reload_sec").prop('disabled', !$('#attr_auto_reload').is(':checked'));
|
||||
|
||||
$('#attr_auto_reload').change( function(ev) {
|
||||
|
||||
@@ -66,7 +66,6 @@ register_shutdown_function(function()
|
||||
});
|
||||
$oKPI = new ExecutionKPI();
|
||||
Session::Start();
|
||||
Session::WriteClose();
|
||||
$oKPI->ComputeAndReport("Session Start");
|
||||
|
||||
$sSwitchEnv = utils::ReadParam('switch_env', null);
|
||||
|
||||
@@ -234,7 +234,6 @@ class DisplayTemplate
|
||||
$sTemplate = '<div class="page_header">
|
||||
<div class="actions_details"><a href="#"><span>Actions</span></a></div>
|
||||
<h1>$class$: <span class="hilite">$name$</span></h1>
|
||||
<itopblock blockclass="HistoryBlock" type="toggle" encoding="text/oql">SELECT CMDBChangeOp WHERE objkey = $id$ AND objclass = \'$class$\'</itopblock>
|
||||
</div>
|
||||
<img src="../../images/connect_to_network.png" style="margin-top:-10px; margin-right:10px; float:right">
|
||||
<itoptabs>
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
<div class="page_header">
|
||||
<itopblock blockclass="MenuBlock" type="popup" encoding="text/oql" label="Actions">SELECT $class$ WHERE id = $id$</itopblock>
|
||||
<h1>$class$: <span class="hilite">$name$</span></h1>
|
||||
<itopblock blockclass="HistoryBlock" type="toggle" encoding="text/oql">SELECT CMDBChangeOp WHERE objkey = $id$ AND objclass = '$class$'</itopblock>
|
||||
</div>
|
||||
<img src="../../images/clean.png" style="margin-top:-20px; margin-right:10px; float:right">
|
||||
<itopblock blockclass="DisplayBlock" asynchronous="false" type="bare_details" encoding="text/oql">SELECT $class$ WHERE id = $id$</itopblock>
|
||||
|
||||
@@ -29,7 +29,7 @@ class ThemeHandlerService
|
||||
{
|
||||
}
|
||||
|
||||
public function CompileTheme($sThemeId, $bSetup = false, $sSetupCompilationTimestamp="", $aThemeParameters = null, $aImportsPaths = null, $sWorkingPath = null){
|
||||
return ThemeHandler::CompileTheme($sThemeId, $bSetup, $sSetupCompilationTimestamp="", $aThemeParameters, $aImportsPaths, $sWorkingPath);
|
||||
public function CompileTheme($sThemeId, $bSetup = false, $sSetupCompilationTimestamp = "", $aThemeParameters = null, $aImportsPaths = null, $sWorkingPath = null){
|
||||
return ThemeHandler::CompileTheme($sThemeId, $bSetup, $sSetupCompilationTimestamp, $aThemeParameters, $aImportsPaths, $sWorkingPath);
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
namespace Combodo\iTop;
|
||||
|
||||
use AttributeDate;
|
||||
use AttributeDateTime;
|
||||
use Dict;
|
||||
use Exception;
|
||||
@@ -55,6 +56,10 @@ class TwigExtension
|
||||
{
|
||||
return AttributeDateTime::GetFormat()->Format($sDate);
|
||||
}
|
||||
if (preg_match('@^\d\d\d\d-\d\d-\d\d$@', trim($sDate)))
|
||||
{
|
||||
return AttributeDate::GetFormat()->Format($sDate);
|
||||
}
|
||||
}
|
||||
catch (Exception $e)
|
||||
{
|
||||
|
||||
@@ -61,6 +61,8 @@ class UIExtKeyWidget
|
||||
protected $sAttCode;
|
||||
protected $bSearchMode;
|
||||
|
||||
//public function __construct($sAttCode, $sClass, $sTitle, $oAllowedValues, $value, $iInputId, $bMandatory, $sNameSuffix = '', $sFieldPrefix = '', $sFormPrefix = '')
|
||||
|
||||
/**
|
||||
* @param \WebPage $oPage
|
||||
* @param string $sAttCode
|
||||
@@ -80,18 +82,13 @@ class UIExtKeyWidget
|
||||
* @throws \Exception
|
||||
*
|
||||
* @since 3.0.0 N°3750 new $sInputType parameter
|
||||
* @since 2.7.7 3.0.1 3.1.0 N°3129 Add default value for $aArgs for PHP 8.0 compat
|
||||
*/
|
||||
public static function DisplayFromAttCode(
|
||||
$oPage, $sAttCode, $sClass, $sTitle, $oAllowedValues, $value, $iInputId, $bMandatory, $sFieldName = '', $sFormPrefix = '',
|
||||
$aArgs = [], $bSearchMode = false, &$sInputType = ''
|
||||
)
|
||||
{
|
||||
// we will only use key & name, so let's reduce fields loaded !
|
||||
$aAttToLoad = [
|
||||
$sClass => [], // nothing, id and friendlyname are automatically added by the API
|
||||
];
|
||||
$oAllowedValues->OptimizeColumnLoad($aAttToLoad);
|
||||
|
||||
$oAttDef = MetaModel::GetAttributeDef($sClass, $sAttCode);
|
||||
$sTargetClass = $oAttDef->GetTargetClass();
|
||||
$iMaxComboLength = $oAttDef->GetMaximumComboLength();
|
||||
@@ -254,7 +251,7 @@ class UIExtKeyWidget
|
||||
$aOption['picture_url'] = $oImage->GetDisplayURL($sClassAllowed, $oObj->GetKey(), $sObjectImageAttCode);
|
||||
$aOption['initials'] = '';
|
||||
} else {
|
||||
$aOption['initials'] = utils::ToAcronym($oObj->Get('friendlyname'));
|
||||
$aOption['initials'] = utils::FormatInitialsForMedallion(utils::ToAcronym($oObj->Get('friendlyname')));
|
||||
}
|
||||
}
|
||||
array_push($aOptions, $aOption);
|
||||
@@ -776,9 +773,11 @@ JS
|
||||
*
|
||||
* @throws CoreException
|
||||
* @throws OQLException
|
||||
*
|
||||
* @since 2.7.7 3.0.1 3.1.0 N°3129 Remove default value for $oObj for PHP 8.0 compatibility
|
||||
*/
|
||||
public function AutoComplete(
|
||||
WebPage $oP, $sFilter, $oObj = null, $sContains = '', $sOutputFormat = self::ENUM_OUTPUT_FORMAT_CSV, $sOperation = null
|
||||
WebPage $oP, $sFilter, $oObj, $sContains, $sOutputFormat = self::ENUM_OUTPUT_FORMAT_CSV, $sOperation = null
|
||||
)
|
||||
{
|
||||
if (is_null($sFilter)) {
|
||||
@@ -830,7 +829,7 @@ JS
|
||||
}
|
||||
|
||||
if (array_key_exists('initials', $aValue)) {
|
||||
$aElt['initials'] = $aValue['initials'];
|
||||
$aElt['initials'] = utils::FormatInitialsForMedallion($aValue['initials']);
|
||||
if (array_key_exists('picture_url', $aValue)) {
|
||||
$aElt['picture_url'] = $aValue['picture_url'];
|
||||
}
|
||||
@@ -976,7 +975,7 @@ HTML
|
||||
$oPage->add_ready_script(<<<JS
|
||||
$('#ac_create_{$this->iId}').dialog({ width: 'auto', height: 'auto', maxHeight: $(window).height() - 50, autoOpen: false, modal: true});
|
||||
$('#dcr_{$this->iId} form').removeAttr('onsubmit');
|
||||
$('#dcr_{$this->iId} form').on('submit.uilinksWizard', oACWidget_{$this->iId}.DoCreateObject);
|
||||
$('#dcr_{$this->iId} form').find('button[type="submit"]').on('click', oACWidget_{$this->iId}.DoCreateObject);
|
||||
JS
|
||||
);
|
||||
}
|
||||
|
||||
@@ -75,9 +75,15 @@ class UILinksWidgetDirect
|
||||
* @param array $aArgs
|
||||
* @param string $sFormPrefix
|
||||
* @param DBObject $oCurrentObj
|
||||
*
|
||||
* @since 2.7.7 3.0.1 3.1.0 N°3129 Remove default value for $aArgs for PHP 8.0 compatibility (handling wrong values at method start)
|
||||
*/
|
||||
public function Display(WebPage $oPage, $oValue, $aArgs = array(), $sFormPrefix, $oCurrentObj)
|
||||
public function Display(WebPage $oPage, $oValue, $aArgs, $sFormPrefix, $oCurrentObj)
|
||||
{
|
||||
if (empty($aArgs)) {
|
||||
$aArgs = [];
|
||||
}
|
||||
|
||||
$oLinksetDef = MetaModel::GetAttributeDef($this->sClass, $this->sAttCode);
|
||||
switch($oLinksetDef->GetEditMode())
|
||||
{
|
||||
@@ -127,8 +133,10 @@ class UILinksWidgetDirect
|
||||
* @param string $sFormPrefix
|
||||
* @param DBObject $oCurrentObj
|
||||
* @param bool $bDisplayMenu
|
||||
*
|
||||
* @since 2.7.7 3.0.1 3.1.0 N°3129 Remove default value for $aArgs for PHP 8.0 compatibility (protected method, always called with default value)
|
||||
*/
|
||||
protected function DisplayAsBlock(WebPage $oPage, $oValue, $aArgs = array(), $sFormPrefix, $oCurrentObj, $bDisplayMenu)
|
||||
protected function DisplayAsBlock(WebPage $oPage, $oValue, $aArgs, $sFormPrefix, $oCurrentObj, $bDisplayMenu)
|
||||
{
|
||||
$oLinksetDef = MetaModel::GetAttributeDef($this->sClass, $this->sAttCode);
|
||||
$sTargetClass = $oLinksetDef->GetLinkedClass();
|
||||
@@ -228,8 +236,10 @@ class UILinksWidgetDirect
|
||||
* @param string $sFormPrefix
|
||||
* @param DBObject $oCurrentObj
|
||||
* @param array $aButtons
|
||||
*
|
||||
* @since 2.7.7 3.0.1 3.1.0 N°3129 Remove default value for $aArgs for PHP 8.0 compatibility (protected method, caller already handles it)
|
||||
*/
|
||||
protected function DisplayEditInPlace(WebPage $oPage, $oValue, $aArgs = array(), $sFormPrefix, $oCurrentObj, $aButtons = array('create', 'delete'))
|
||||
protected function DisplayEditInPlace(WebPage $oPage, $oValue, $aArgs, $sFormPrefix, $oCurrentObj, $aButtons = array('create', 'delete'))
|
||||
{
|
||||
$aAttribs = $this->GetTableConfig();
|
||||
$oValue->Rewind();
|
||||
@@ -296,7 +306,7 @@ class UILinksWidgetDirect
|
||||
}
|
||||
$oHiddenCriteria = $oHiddenFilter->GetCriteria();
|
||||
$aArgs = $oHiddenFilter->GetInternalParams();
|
||||
$sHiddenCriteria = $oHiddenCriteria->Render($aArgs);
|
||||
$sHiddenCriteria = $oHiddenCriteria->RenderExpression(false, $aArgs);
|
||||
|
||||
$oLinkSetDef = MetaModel::GetAttributeDef($this->sClass, $this->sAttCode);
|
||||
$valuesDef = $oLinkSetDef->GetValuesDef();
|
||||
|
||||
@@ -1944,28 +1944,18 @@ class utils
|
||||
|
||||
return $sCss;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the size of an image from a string.
|
||||
*
|
||||
* @see \getimagesizefromstring()
|
||||
* @param $sImageData string The image data, as a string.
|
||||
*
|
||||
* @return array|false
|
||||
*/
|
||||
public static function GetImageSize($sImageData)
|
||||
{
|
||||
if (function_exists('getimagesizefromstring')) // PHP 5.4.0 or higher
|
||||
{
|
||||
$aRet = @getimagesizefromstring($sImageData);
|
||||
}
|
||||
else if(ini_get('allow_url_fopen'))
|
||||
{
|
||||
// work around to avoid creating a tmp file
|
||||
$sUri = 'data://application/octet-stream;base64,'.base64_encode($sImageData);
|
||||
$aRet = @getimagesize($sUri);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Damned, need to create a tmp file
|
||||
$sTempFile = tempnam(SetupUtils::GetTmpDir(), 'img-');
|
||||
@file_put_contents($sTempFile, $sImageData);
|
||||
$aRet = @getimagesize($sTempFile);
|
||||
@unlink($sTempFile);
|
||||
}
|
||||
return $aRet;
|
||||
return @getimagesizefromstring($sImageData);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2118,11 +2108,21 @@ class utils
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the relative (to MODULESROOT) path of the root directory of the module containing the file where the call to
|
||||
* this function is made
|
||||
* or an empty string if no such module is found (or not called within a module file)
|
||||
* @param number $iCallDepth The depth of the module in the callstack. Zero when called directly from within the module
|
||||
* @return string
|
||||
* **Warning** : returned result can be invalid as we're using backtrace to find the module dir name
|
||||
*
|
||||
* @param int $iCallDepth The depth of the module in the callstack. Zero when called directly from within the module
|
||||
*
|
||||
* @return string the relative (to MODULESROOT) path of the root directory of the module containing the file where the call to
|
||||
* this function is made
|
||||
* or an empty string if no such module is found (or not called within a module file)
|
||||
*
|
||||
* @uses \debug_backtrace()
|
||||
*
|
||||
* @since 3.0.0 Before writing model.*.php file, compiler will now always delete it.
|
||||
* If you have symlinks enabled, base dir will be original module dir, but since this behavior change this won't be true anymore for model.*.php
|
||||
* In consequence the backtrace analysis won't be possible for this file
|
||||
* See N°4854
|
||||
* @link https://www.itophub.io/wiki/page?id=3_0_0%3Arelease%3A3_0_whats_new#compiler_always_generate_new_model_php compiler behavior change documentation
|
||||
*/
|
||||
public static function GetCurrentModuleDir($iCallDepth)
|
||||
{
|
||||
@@ -2147,9 +2147,14 @@ class utils
|
||||
}
|
||||
|
||||
/**
|
||||
* **Warning** : as this method uses {@see GetCurrentModuleDir} it produces hazardous results.
|
||||
* You should better uses directly {@see GetAbsoluteUrlModulesRoot} and add the module dir name yourself ! See N°4573
|
||||
*
|
||||
* @return string the base URL for all files in the current module from which this method is called
|
||||
* or an empty string if no such module is found (or not called within a module file)
|
||||
* @throws \Exception
|
||||
*
|
||||
* @uses GetCurrentModuleDir
|
||||
*/
|
||||
public static function GetCurrentModuleUrl()
|
||||
{
|
||||
@@ -2404,43 +2409,19 @@ class utils
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string eg : '2_7_0' ITOP_VERSION is '2.7.1-dev'
|
||||
* @return string eg : '2_7_0' if iTop core version is '2.7.5-2'
|
||||
* @throws \ApplicationException if constant value is invalid
|
||||
* @uses ITOP_CORE_VERSION
|
||||
*/
|
||||
public static function GetItopVersionWikiSyntax() {
|
||||
$sMinorVersion = self::GetItopMinorVersion();
|
||||
public static function GetItopVersionWikiSyntax($sItopVersion = ITOP_CORE_VERSION)
|
||||
{
|
||||
$aExplodedVersion = explode('.', $sItopVersion);
|
||||
|
||||
return str_replace('.', '_', $sMinorVersion).'_0';
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $sPatchVersion if non provided, will call GetItopPatchVersion
|
||||
*
|
||||
* @return string eg 2.7 if ITOP_VERSION is '2.7.0-dev'
|
||||
* @throws \Exception
|
||||
*/
|
||||
public static function GetItopMinorVersion($sPatchVersion = null) {
|
||||
if (is_null($sPatchVersion)) {
|
||||
$sPatchVersion = self::GetItopPatchVersion();
|
||||
}
|
||||
$aExplodedVersion = explode('.', $sPatchVersion);
|
||||
|
||||
if (count($aExplodedVersion) < 2) {
|
||||
throw new Exception('iTop version is wrongfully configured!');
|
||||
}
|
||||
if (($aExplodedVersion[0] == '') || ($aExplodedVersion[1] == '')) {
|
||||
throw new Exception('iTop version is wrongfully configured!');
|
||||
if ((false === isset($aExplodedVersion[0])) || (false === isset($aExplodedVersion[1]))) {
|
||||
throw new ApplicationException('iTop version is wrongfully configured!');
|
||||
}
|
||||
|
||||
return sprintf('%d.%d', $aExplodedVersion[0], $aExplodedVersion[1]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string eg '2.7.0' if ITOP_VERSION is '2.7.0-dev'
|
||||
*/
|
||||
public static function GetItopPatchVersion() {
|
||||
$aExplodedVersion = explode('-', ITOP_VERSION);
|
||||
|
||||
return $aExplodedVersion[0];
|
||||
return "{$aExplodedVersion[0]}_{$aExplodedVersion[1]}_0";
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -3059,6 +3040,20 @@ HTML;
|
||||
return $aMentionedObjects;
|
||||
}
|
||||
|
||||
/**
|
||||
* Note: This method is not ideal, but other solutions seemed even less ideal:
|
||||
* * Add a "$sMaxLength" param. to utils::ToAcronym(): Does not work for every use cases (see corresponding ticket) as in some parts utils::ToAcronym isn't necessarly meant to be used in a medallion.
|
||||
*
|
||||
* @param string $sInitials
|
||||
*
|
||||
* @return string Truncates $sInitials so it can fit in medallions
|
||||
* @since 3.0.1 N°4913
|
||||
*/
|
||||
public static function FormatInitialsForMedallion(string $sInitials): string
|
||||
{
|
||||
return mb_substr($sInitials, 0, 3);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $sUrl
|
||||
* @param string $sParamName
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
<?php
|
||||
/**
|
||||
* @deprecated 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-2021 Combodo SARL
|
||||
*/
|
||||
|
||||
DeprecatedCallsLog::NotifyDeprecatedFile('moved to sources/application/WebPage/WebPage.php, now loadable using autoloader');
|
||||
DeprecatedCallsLog::NotifyDeprecatedFile('moved to sources/Application/WebPage/WebPage.php, now loadable using autoloader');
|
||||
@@ -1,8 +1,8 @@
|
||||
<?php
|
||||
/**
|
||||
* @deprecated 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-2021 Combodo SARL
|
||||
*/
|
||||
|
||||
DeprecatedCallsLog::NotifyDeprecatedFile('moved to sources/application/WebPage/XMLPage.php, now loadable using autoloader');
|
||||
DeprecatedCallsLog::NotifyDeprecatedFile('moved to sources/Application/WebPage/XMLPage.php, now loadable using autoloader');
|
||||
@@ -4,8 +4,25 @@ define('APPROOT', dirname(__FILE__).'/');
|
||||
define('APPCONF', APPROOT.'conf/');
|
||||
|
||||
/**
|
||||
* iTop framework Version
|
||||
* iTop Datamodel XML format version
|
||||
*
|
||||
* It was also used in iTop 3.0.0 to get iTop core version (instead of {@see ITOP_VERSION} which gives the application version).
|
||||
* To address this need you should now use {@see ITOP_CORE_VERSION}
|
||||
*
|
||||
* @see ITOP_CORE_VERSION to get full iTop core version
|
||||
*/
|
||||
define('ITOP_DESIGN_LATEST_VERSION', '3.0');
|
||||
define('ITOP_DESIGN_LATEST_VERSION', '3.1');
|
||||
|
||||
/**
|
||||
* Constant containing the iTop core version, whatever application was built
|
||||
*
|
||||
* Note that in iTop 3.0.0 we used {@see ITOP_DESIGN_LATEST_VERSION} to get core version.
|
||||
* When releasing, both constants should be updated : see `.make/release/update-versions.php` for that !
|
||||
*
|
||||
* @since 2.7.7 3.0.1 3.1.0 N°4714 constant creation
|
||||
* @used-by utils::GetItopVersionWikiSyntax()
|
||||
* @used-by iTopModulesPhpVersionIntegrationTest
|
||||
*/
|
||||
define('ITOP_CORE_VERSION', '3.1.0');
|
||||
|
||||
require_once APPROOT.'bootstrap.inc.php';
|
||||
|
||||
@@ -11,21 +11,22 @@
|
||||
"ext-mysqli": "*",
|
||||
"ext-soap": "*",
|
||||
"combodo/tcpdf": "6.3.5",
|
||||
"laminas/laminas-mail": "^2.12",
|
||||
"laminas/laminas-servicemanager": "^3.5",
|
||||
"nikic/php-parser": "^4.12.0",
|
||||
"pear/archive_tar": "1.4.14",
|
||||
"pelago/emogrifier": "3.1.0",
|
||||
"scssphp/scssphp": "1.0.6",
|
||||
"swiftmailer/swiftmailer": "5.4.12",
|
||||
"symfony/console": "3.4.*",
|
||||
"symfony/dotenv": "3.4.*",
|
||||
"symfony/framework-bundle": "3.4.*",
|
||||
"symfony/console": "~3.4.47",
|
||||
"symfony/dotenv": "~3.4.47",
|
||||
"symfony/framework-bundle": "~3.4.47",
|
||||
"symfony/polyfill-php70": "1.*",
|
||||
"symfony/twig-bundle": "3.4.*",
|
||||
"symfony/yaml": "3.4.*"
|
||||
"symfony/twig-bundle": "~3.4.47",
|
||||
"symfony/yaml": "~3.4.47"
|
||||
},
|
||||
"require-dev": {
|
||||
"symfony/stopwatch": "3.4.*",
|
||||
"symfony/web-profiler-bundle": "3.4.*"
|
||||
"symfony/stopwatch": "~3.4.47",
|
||||
"symfony/web-profiler-bundle": "~3.4.47"
|
||||
},
|
||||
"suggest": {
|
||||
"ext-libsodium": "Required to use the AttributeEncryptedString.",
|
||||
|
||||
1537
composer.lock
generated
1537
composer.lock
generated
File diff suppressed because it is too large
Load Diff
@@ -200,6 +200,17 @@ abstract class ActionNotification extends Action
|
||||
*/
|
||||
class ActionEmail extends ActionNotification
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
* @since 3.0.1
|
||||
*/
|
||||
const ENUM_HEADER_NAME_MESSAGE_ID = 'Message-ID';
|
||||
/**
|
||||
* @var string
|
||||
* @since 3.0.1
|
||||
*/
|
||||
const ENUM_HEADER_NAME_REFERENCES = 'References';
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
@@ -207,13 +218,13 @@ class ActionEmail extends ActionNotification
|
||||
{
|
||||
$aParams = array
|
||||
(
|
||||
"category" => "grant_by_profile,core/cmdb,application",
|
||||
"key_type" => "autoincrement",
|
||||
"name_attcode" => "name",
|
||||
"state_attcode" => "",
|
||||
"reconc_keys" => array('name'),
|
||||
"db_table" => "priv_action_email",
|
||||
"db_key_field" => "id",
|
||||
"category" => "grant_by_profile,core/cmdb,application",
|
||||
"key_type" => "autoincrement",
|
||||
"name_attcode" => "name",
|
||||
"state_attcode" => "",
|
||||
"reconc_keys" => array('name'),
|
||||
"db_table" => "priv_action_email",
|
||||
"db_key_field" => "id",
|
||||
"db_finalclass_field" => "",
|
||||
);
|
||||
MetaModel::Init_Params($aParams);
|
||||
@@ -416,9 +427,8 @@ class ActionEmail extends ActionNotification
|
||||
$sBody = MetaModel::ApplyParams($this->Get('body'), $aContextArgs);
|
||||
|
||||
$oObj = $aContextArgs['this->object()'];
|
||||
$sMessageId = sprintf('iTop_%s_%d_%f@%s.openitop.org', get_class($oObj), $oObj->GetKey(), microtime(true /* get as float*/),
|
||||
MetaModel::GetEnvironmentId());
|
||||
$sReference = '<'.$sMessageId.'>';
|
||||
$sMessageId = $this->GenerateIdentifierForHeaders($oObj, static::ENUM_HEADER_NAME_MESSAGE_ID);
|
||||
$sReference = $this->GenerateIdentifierForHeaders($oObj, static::ENUM_HEADER_NAME_REFERENCES);
|
||||
}
|
||||
catch (Exception $e) {
|
||||
/** @noinspection PhpUnhandledExceptionInspection */
|
||||
@@ -456,8 +466,7 @@ class ActionEmail extends ActionNotification
|
||||
|
||||
$oEmail = new EMail();
|
||||
|
||||
if ($this->IsBeingTested())
|
||||
{
|
||||
if ($this->IsBeingTested()) {
|
||||
$oEmail->SetSubject('TEST['.$sSubject.']');
|
||||
$sTestBody = $sBody;
|
||||
$sTestBody .= "<div style=\"border: dashed;\">\n";
|
||||
@@ -467,8 +476,8 @@ class ActionEmail extends ActionNotification
|
||||
$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 .= 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";
|
||||
@@ -478,9 +487,9 @@ class ActionEmail extends ActionNotification
|
||||
$oEmail->SetRecipientFrom($sFrom, $sFromLabel);
|
||||
$oEmail->SetReferences($sReference);
|
||||
$oEmail->SetMessageId($sMessageId);
|
||||
}
|
||||
else
|
||||
{
|
||||
// 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);
|
||||
@@ -490,6 +499,8 @@ class ActionEmail extends ActionNotification
|
||||
$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']))
|
||||
@@ -516,26 +527,64 @@ class ActionEmail extends ActionNotification
|
||||
{
|
||||
case EMAIL_SEND_OK:
|
||||
return "Sent";
|
||||
|
||||
|
||||
case EMAIL_SEND_PENDING:
|
||||
return "Pending";
|
||||
|
||||
|
||||
case EMAIL_SEND_ERROR:
|
||||
return "Errors: ".implode(', ', $aErrors);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (is_array($this->m_aMailErrors) && count($this->m_aMailErrors) > 0)
|
||||
{
|
||||
} else {
|
||||
if (is_array($this->m_aMailErrors) && count($this->m_aMailErrors) > 0) {
|
||||
$sError = implode(', ', $this->m_aMailErrors);
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
$sError = 'Unknown reason';
|
||||
}
|
||||
|
||||
return 'Notification was not sent: '.$sError;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @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.0.1 N°4849
|
||||
*/
|
||||
protected function GenerateIdentifierForHeaders(DBObject $oObject, string $sHeaderName): string
|
||||
{
|
||||
$sObjClass = get_class($oObject);
|
||||
$sObjId = $oObject->GetKey();
|
||||
$sAppName = utils::Sanitize(ITOP_APPLICATION_SHORT, '', utils::ENUM_SANITIZATION_FILTER_VARIABLE_NAME);
|
||||
|
||||
switch ($sHeaderName) {
|
||||
case static::ENUM_HEADER_NAME_MESSAGE_ID:
|
||||
case static::ENUM_HEADER_NAME_REFERENCES:
|
||||
// Prefix
|
||||
$sPrefix = sprintf('%s_%s_%d', $sAppName, $sObjClass, $sObjId);
|
||||
if ($sHeaderName === static::ENUM_HEADER_NAME_MESSAGE_ID) {
|
||||
$sPrefix .= sprintf('_%f', microtime(true /* get as float*/));
|
||||
}
|
||||
// Suffix
|
||||
$sSuffix = sprintf('@%s.openitop.org', MetaModel::GetEnvironmentId());
|
||||
// Identifier
|
||||
$sIdentifier = $sPrefix.$sSuffix;
|
||||
if ($sHeaderName === static::ENUM_HEADER_NAME_REFERENCES) {
|
||||
$sIdentifier = "<$sIdentifier>";
|
||||
}
|
||||
|
||||
return $sIdentifier;
|
||||
}
|
||||
|
||||
// Requested header name invalid
|
||||
$sErrorMessage = sprintf('%s: Could not generate identifier for header "%s", only %s are supported', static::class, $sHeaderName, implode(' / ', [static::ENUM_HEADER_NAME_MESSAGE_ID, static::ENUM_HEADER_NAME_REFERENCES]));
|
||||
IssueLog::Error($sErrorMessage, LogChannels::NOTIFICATIONS, [
|
||||
'Object' => $sObjClass.'::'.$sObjId.' ('.$oObject->GetRawName().')',
|
||||
'Action' => get_class($this).'::'.$this->GetKey().' ('.$this->GetRawName().')',
|
||||
]);
|
||||
throw new Exception($sErrorMessage);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -409,8 +409,6 @@ class AsyncSendEmail extends AsyncTask
|
||||
$oNew->Set('to', $oEMail->GetRecipientTO(true /* string */));
|
||||
$oNew->Set('subject', $oEMail->GetSubject());
|
||||
|
||||
// $oNew->Set('version', 1);
|
||||
// $sMessage = serialize($oEMail);
|
||||
$oNew->Set('version', 2);
|
||||
$sMessage = $oEMail->SerializeV2();
|
||||
$oNew->Set('message', $sMessage);
|
||||
|
||||
@@ -5717,7 +5717,7 @@ class AttributeMetaEnum extends AttributeEnum
|
||||
$aLocalizedValues = array();
|
||||
foreach($aRawValues as $sKey => $sValue)
|
||||
{
|
||||
$aLocalizedValues[$sKey] = Str::pure2html($this->GetValueLabel($sKey));
|
||||
$aLocalizedValues[$sKey] = $this->GetValueLabel($sKey);
|
||||
}
|
||||
|
||||
return $aLocalizedValues;
|
||||
|
||||
@@ -78,23 +78,31 @@ class CMDBChangeOp extends DBObject implements iCMDBChangeOp
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
* Describe (as a text string) the modifications corresponding to this change
|
||||
*/
|
||||
public function GetDescription()
|
||||
{
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Safety net: in case the change is not given, let's guarantee that it will
|
||||
* be set to the current ongoing change (or create a new one)
|
||||
*/
|
||||
* Safety net:
|
||||
* * if change isn't persisted yet, use the current change and persist it if needed
|
||||
* * in case the change is not given, let's guarantee that it will be set to the current ongoing change (or create a new one)
|
||||
*
|
||||
* @since 2.7.7 3.0.2 3.1.0 N°3717 do persist the current change if needed
|
||||
*/
|
||||
protected function OnInsert()
|
||||
{
|
||||
if ($this->Get('change') <= 0)
|
||||
{
|
||||
$this->Set('change', CMDBObject::GetCurrentChange());
|
||||
$iChange = $this->Get('change');
|
||||
if (($iChange <= 0) || (is_null($iChange))) {
|
||||
$oChange = CMDBObject::GetCurrentChange();
|
||||
if ($oChange->IsNew()) {
|
||||
$oChange->DBWrite();
|
||||
}
|
||||
$this->Set('change', $oChange);
|
||||
}
|
||||
|
||||
parent::OnInsert();
|
||||
}
|
||||
}
|
||||
@@ -1077,7 +1085,7 @@ class CMDBChangeOpSetAttributeLinksTune extends CMDBChangeOpSetAttributeLinks
|
||||
{
|
||||
$oField = new FieldExpression('objclass', $oSearch->GetClassAlias());
|
||||
$sListExpr = '('.implode(', ', CMDBSource::Quote($aLinkClasses)).')';
|
||||
$sOQLCondition = $oField->Render()." IN $sListExpr";
|
||||
$sOQLCondition = $oField->RenderExpression()." IN $sListExpr";
|
||||
$oNewCondition = Expression::FromOQL($sOQLCondition);
|
||||
$oSearch->AddConditionExpression($oNewCondition);
|
||||
}
|
||||
|
||||
@@ -113,6 +113,26 @@ abstract class CMDBObject extends DBObject
|
||||
self::$m_oCurrChange = $oChange;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $sUserInfo
|
||||
* @param string $sOrigin
|
||||
* @param \DateTime $oDate
|
||||
*
|
||||
* @throws \CoreException
|
||||
*
|
||||
* @since 2.7.7 3.0.2 3.1.0 N°3717 new method to reset current change
|
||||
*/
|
||||
public static function SetCurrentChangeFromParams($sUserInfo, $sOrigin = null, $oDate = null)
|
||||
{
|
||||
static::SetTrackInfo($sUserInfo);
|
||||
static::SetTrackOrigin($sOrigin);
|
||||
static::CreateChange();
|
||||
|
||||
if (!is_null($oDate)) {
|
||||
static::$m_oCurrChange->Set("date", $oDate);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Todo: simplify the APIs and do not pass the current change as an argument anymore
|
||||
// SetTrackInfo to be invoked in very few cases (UI.php, CSV import, Data synchro)
|
||||
@@ -144,6 +164,8 @@ abstract class CMDBObject extends DBObject
|
||||
* $oMyChange->Set("userinfo", 'this is done by ... for ...');
|
||||
* $iChangeId = $oMyChange->DBInsert();
|
||||
*
|
||||
* **warning** : this will do nothing if current change already exists !
|
||||
*
|
||||
* @see SetCurrentChange to specify a CMDBObject instance instead
|
||||
*
|
||||
* @param string $sInfo
|
||||
@@ -161,7 +183,7 @@ abstract class CMDBObject extends DBObject
|
||||
*
|
||||
* @param string $sId ID of the user doing the change, null if not done by a user (eg. background task)
|
||||
*
|
||||
* @since 3.0.0
|
||||
* @since 3.0.0 N°2847 following the addition of CMDBChange.user_id
|
||||
*/
|
||||
public static function SetTrackUserId($sId)
|
||||
{
|
||||
@@ -171,6 +193,8 @@ abstract class CMDBObject extends DBObject
|
||||
/**
|
||||
* Provides information about the origin of the change
|
||||
*
|
||||
* **warning** : this will do nothing if current change already exists !
|
||||
*
|
||||
* @see SetTrackInfo
|
||||
* @see SetCurrentChange to specify a CMDBObject instance instead
|
||||
*
|
||||
@@ -181,18 +205,15 @@ abstract class CMDBObject extends DBObject
|
||||
{
|
||||
self::$m_sOrigin = $sOrigin;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the additional information (defaulting to user name)
|
||||
*/
|
||||
protected static function GetTrackInfo()
|
||||
*/
|
||||
public static function GetTrackInfo()
|
||||
{
|
||||
if (is_null(self::$m_sInfo))
|
||||
{
|
||||
if (is_null(self::$m_sInfo)) {
|
||||
return CMDBChange::GetCurrentUserName();
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
return self::$m_sInfo;
|
||||
}
|
||||
}
|
||||
@@ -243,6 +264,9 @@ abstract class CMDBObject extends DBObject
|
||||
* @throws \CoreWarning
|
||||
* @throws \MySQLException
|
||||
* @throws \OQLException
|
||||
*
|
||||
* @since 2.7.7 3.0.2 3.1.0 N°3717 {@see CMDBChange} **will be persisted later** in {@see \CMDBChangeOp::OnInsert} (was done previously directly here)
|
||||
* This will avoid creating in DB CMDBChange lines without any corresponding CMDBChangeOp
|
||||
*/
|
||||
protected static function CreateChange()
|
||||
{
|
||||
@@ -251,7 +275,6 @@ abstract class CMDBObject extends DBObject
|
||||
self::$m_oCurrChange->Set("userinfo", self::GetTrackInfo());
|
||||
self::$m_oCurrChange->Set("user_id", self::GetTrackUserId());
|
||||
self::$m_oCurrChange->Set("origin", self::GetTrackOrigin());
|
||||
self::$m_oCurrChange->DBInsert();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -350,14 +350,22 @@ class CMDBSource
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the version of the database server.
|
||||
*
|
||||
* @return string
|
||||
* @throws \MySQLException
|
||||
*
|
||||
* @uses \CMDBSource::QueryToScalar() so needs a connection opened !
|
||||
*/
|
||||
public static function GetDBVersion()
|
||||
{
|
||||
$aVersions = self::QueryToCol('SELECT Version() as version', 'version');
|
||||
return $aVersions[0];
|
||||
return static::QueryToScalar('SELECT VERSION()', 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
* @deprecated Use `CMDBSource::GetDBVersion` instead.
|
||||
* @uses mysqli_get_server_info
|
||||
*/
|
||||
public static function GetServerInfo()
|
||||
{
|
||||
@@ -367,8 +375,10 @@ class CMDBSource
|
||||
/**
|
||||
* Get the DB vendor between MySQL and its main forks
|
||||
* @return string
|
||||
*
|
||||
* @uses \CMDBSource::GetServerVariable() so needs a connection opened !
|
||||
*/
|
||||
static public function GetDBVendor()
|
||||
public static function GetDBVendor()
|
||||
{
|
||||
$sDBVendor = static::ENUM_DB_VENDOR_MYSQL;
|
||||
|
||||
@@ -672,13 +682,13 @@ class CMDBSource
|
||||
private static function StartTransaction()
|
||||
{
|
||||
$aStackTrace = debug_backtrace(DEBUG_BACKTRACE_PROVIDE_OBJECT , 3);
|
||||
$sCaller = 'From '.$aStackTrace[1]['file'].'('.$aStackTrace[1]['line'].'): '.$aStackTrace[2]['class'].'->'.$aStackTrace[2]['function'].'()';
|
||||
|
||||
$bHasExistingTransactions = self::IsInsideTransaction();
|
||||
if (!$bHasExistingTransactions) {
|
||||
IssueLog::Trace("START TRANSACTION $sCaller", LogChannels::CMDB_SOURCE);
|
||||
IssueLog::Trace("START TRANSACTION was sent to the DB", LogChannels::CMDB_SOURCE, ['stacktrace' => $aStackTrace]);
|
||||
self::DBQuery('START TRANSACTION');
|
||||
} else {
|
||||
IssueLog::Trace("Ignore nested (".self::$m_iTransactionLevel.") START TRANSACTION $sCaller", LogChannels::CMDB_SOURCE);
|
||||
IssueLog::Trace("START TRANSACTION ignored as a transaction is already opened", LogChannels::CMDB_SOURCE, ['stacktrace' => $aStackTrace]);
|
||||
}
|
||||
|
||||
self::AddTransactionLevel();
|
||||
@@ -1491,20 +1501,14 @@ class CMDBSource
|
||||
* Returns the value of the specified server variable
|
||||
* @param string $sVarName Name of the server variable
|
||||
* @return mixed Current value of the variable
|
||||
*/
|
||||
* @throws \MySQLQueryHasNoResultException|\MySQLException
|
||||
*/
|
||||
public static function GetServerVariable($sVarName)
|
||||
{
|
||||
$result = '';
|
||||
$sSql = "SELECT @@$sVarName as theVar";
|
||||
$aRows = self::QueryToArray($sSql);
|
||||
if (count($aRows) > 0)
|
||||
{
|
||||
$result = $aRows[0]['theVar'];
|
||||
}
|
||||
return $result;
|
||||
$sSql = 'SELECT @@'.$sVarName;
|
||||
return static::QueryToScalar($sSql, 0) ?: '';
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the privileges of the current user
|
||||
* @return string privileges in a raw format
|
||||
|
||||
@@ -22,7 +22,15 @@
|
||||
|
||||
define('ITOP_APPLICATION', 'iTop');
|
||||
define('ITOP_APPLICATION_SHORT', 'iTop');
|
||||
define('ITOP_VERSION', '3.0.0-dev');
|
||||
|
||||
/**
|
||||
* Constant containing the application version
|
||||
* Warning: this might be different from iTop core version!
|
||||
*
|
||||
* @see ITOP_CORE_VERSION to get iTop core version
|
||||
*/
|
||||
define('ITOP_VERSION', '3.1.0-dev');
|
||||
|
||||
define('ITOP_VERSION_NAME', 'Fullmoon');
|
||||
define('ITOP_REVISION', 'svn');
|
||||
define('ITOP_BUILD_DATE', '$WCNOW$');
|
||||
@@ -481,13 +489,21 @@ class Config
|
||||
'show_in_conf_sample' => true,
|
||||
],
|
||||
'cron_max_execution_time' => [
|
||||
'type' => 'integer',
|
||||
'description' => 'Duration (seconds) of the page cron.php, must be shorter than php setting max_execution_time and shorter than the web server response timeout',
|
||||
'default' => 600,
|
||||
'value' => 600,
|
||||
'source_of_value' => '',
|
||||
'type' => 'integer',
|
||||
'description' => 'Duration (seconds) of the cron.php script : if exceeded the script will exit even if there are remaining tasks to process. Must be shorter than php max_execution_time setting (note than when using CLI, this is set to 0 by default which means unlimited). If cron.php is ran via web, it must be shorter than the web server response timeout.',
|
||||
'default' => 600,
|
||||
'value' => 600,
|
||||
'source_of_value' => '',
|
||||
'show_in_conf_sample' => true,
|
||||
],
|
||||
'cron_task_max_execution_time' => [
|
||||
'type' => 'integer',
|
||||
'description' => 'Background tasks will use this value (integer) multiplicated by its periodicity (in seconds) as max duration per cron execution. 0 is unlimited time',
|
||||
'default' => 0,
|
||||
'value' => 0,
|
||||
'source_of_value' => '',
|
||||
'show_in_conf_sample' => false,
|
||||
],
|
||||
'cron_sleep' => [
|
||||
'type' => 'integer',
|
||||
'description' => 'Duration (seconds) before cron.php checks again if something must be done',
|
||||
@@ -608,6 +624,13 @@ class Config
|
||||
'source_of_value' => '',
|
||||
'show_in_conf_sample' => false,
|
||||
],
|
||||
/**
|
||||
* The timezone is automatically set using this parameter in \utils::InitTimeZone
|
||||
* This method is called almost everywhere, cause it's called in \MetaModel::LoadConfig and exec.php... but you might
|
||||
* need to get it yourself !
|
||||
*
|
||||
* @used-by utils::InitTimeZone()
|
||||
*/
|
||||
'timezone' => [
|
||||
'type' => 'string',
|
||||
'description' => 'Timezone (reference: http://php.net/manual/en/timezones.php). If empty, it will be left unchanged and MUST be explicitly configured in PHP',
|
||||
@@ -851,13 +874,23 @@ class Config
|
||||
'source_of_value' => '',
|
||||
'show_in_conf_sample' => false,
|
||||
],
|
||||
'impact_analysis_lazy_loading' => [
|
||||
'type' => 'bool',
|
||||
'description' => 'In the impact analysis view: display the analysis or filter before display',
|
||||
'default' => false,
|
||||
'value' => '',
|
||||
'source_of_value' => '',
|
||||
'show_in_conf_sample' => false,
|
||||
],
|
||||
'url_validation_pattern' => [
|
||||
'type' => 'string',
|
||||
'description' => 'Regular expression to validate/detect the format of an URL (URL attributes and Wiki formatting for Text attributes)',
|
||||
'default' => '(https?|ftp)\://([a-zA-Z0-9+!*(),;?&=\$_.-]+(\:[a-zA-Z0-9+!*(),;?&=\$_.-]+)?@)?([a-zA-Z0-9-.]{3,})(\:[0-9]{2,5})?(/([a-zA-Z0-9%+\$_-]\.?)+)*/?(\?[a-zA-Z+&\$_.-][a-zA-Z0-9;:[\]@&%=+/\$_.-]*)?(#[a-zA-Z_.-][a-zA-Z0-9+\$_.-]*)?',
|
||||
// SHEME.......... USER....................... PASSWORD.......................... HOST/IP........... PORT.......... PATH........................ GET............................................ ANCHOR............................
|
||||
'default' => /** @lang RegExp */
|
||||
'(https?|ftp)\://([a-zA-Z0-9+!*(),;?&=\$_.-]+(\:[a-zA-Z0-9+!*(),;?&=\$_.-]+)?@)?([a-zA-Z0-9-.]{3,})(\:[0-9]{2,5})?(/([a-zA-Z0-9:%+\$_-]\.?)+)*/?(\?[a-zA-Z+&\$_.-][a-zA-Z0-9;:[\]@&%=+/\$_.-]*)?(#[a-zA-Z0-9_.-][a-zA-Z0-9+\$_.-]*)?',
|
||||
// SCHEME....... USER....................... PASSWORD.......................... HOST/IP........... PORT.......... PATH......................... GET............................................ ANCHOR..........................
|
||||
// Example: http://User:passWord@127.0.0.1:8888/patH/Page.php?arrayArgument[2]=something:blah20#myAnchor
|
||||
// Origin of this regexp: http://www.php.net/manual/fr/function.preg-match.php#93824
|
||||
// RegExp source: http://www.php.net/manual/fr/function.preg-match.php#93824
|
||||
// Update with N°4515
|
||||
'value' => '',
|
||||
'source_of_value' => '',
|
||||
'show_in_conf_sample' => true,
|
||||
@@ -1175,7 +1208,7 @@ class Config
|
||||
],
|
||||
'compatibility.include_deprecated_js_files' => [
|
||||
'type' => 'bool',
|
||||
'description' => 'Include the deprecated JS files to ease usage of not migrated extensions',
|
||||
'description' => 'Include the deprecated JS files (in iTop previous version) to ease usage of not migrated extensions',
|
||||
'default' => false,
|
||||
'value' => false,
|
||||
'source_of_value' => '',
|
||||
@@ -1191,7 +1224,7 @@ class Config
|
||||
],
|
||||
'compatibility.include_deprecated_css_files' => [
|
||||
'type' => 'bool',
|
||||
'description' => 'Include the deprecated CSS files to ease usage of not migrated extensions',
|
||||
'description' => 'Include the deprecated CSS files (in iTop previous version) to ease usage of not migrated extensions',
|
||||
'default' => false,
|
||||
'value' => false,
|
||||
'source_of_value' => '',
|
||||
@@ -1519,6 +1552,14 @@ class Config
|
||||
'source_of_value' => '',
|
||||
'show_in_conf_sample' => false,
|
||||
],
|
||||
'setup.launch_button.enabled' => [
|
||||
'type' => 'bool',
|
||||
'description' => 'If true displays in the Application Upgrade screen a button allowing to launch the setup in a single click (no more manual config file permission change needed)',
|
||||
'default' => null,
|
||||
'value' => false,
|
||||
'source_of_value' => '',
|
||||
'show_in_conf_sample' => false,
|
||||
],
|
||||
];
|
||||
|
||||
public function IsProperty($sPropCode)
|
||||
@@ -1600,6 +1641,16 @@ class Config
|
||||
return $this->m_aSettings[$sPropCode]['value'];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*
|
||||
* @since 3.0.1 N°4515
|
||||
*/
|
||||
public function GetDefault(string $sPropCode)
|
||||
{
|
||||
return $this->m_aSettings[$sPropCode]['default'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether the $sPropCode parameter has a custom value or the default one.
|
||||
*
|
||||
|
||||
@@ -220,16 +220,15 @@ class CSVBulkExport extends TabularBulkExport
|
||||
|
||||
$sFormatInput = '<input type="text" size="15" name="date_format" id="csv_custom_date_time_format" title="" value="'.htmlentities($sDateTimeFormat, ENT_QUOTES, 'UTF-8').'"/>';
|
||||
$oRadioCustom = InputUIBlockFactory::MakeForInputWithLabel(Dict::Format('Core:BulkExport:DateTimeFormatCustom_Format', $sFormatInput), "csv_date_format_radio", "custom", "csv_date_time_format_custom", "radio");
|
||||
$oRadioCustom->SetDescription(Dict::S('UI:CSVImport:CustomDateTimeFormatTooltip'));
|
||||
$oRadioCustom->GetInput()->SetIsChecked($sDateTimeFormat !== (string)AttributeDateTime::GetFormat());
|
||||
$oRadioCustom->SetBeforeInput(false);
|
||||
$oRadioCustom->GetInput()->AddCSSClass('ibo-input-checkbox');
|
||||
$oFieldSetDate->AddSubBlock($oRadioCustom);
|
||||
|
||||
$sJSTooltip = json_encode('<div class="date_format_tooltip">'.Dict::S('UI:CSVImport:CustomDateTimeFormatTooltip').'</div>');
|
||||
|
||||
$oP->add_ready_script(
|
||||
<<<EOF
|
||||
$('#csv_custom_date_time_format').tooltip({content: function() { return $sJSTooltip; } });
|
||||
$('#form_part_csv_options').on('preview_updated', function() { FormatDatesInPreview('csv', 'csv'); });
|
||||
$('#csv_date_time_format_default').on('click', function() { FormatDatesInPreview('csv', 'csv'); });
|
||||
$('#csv_date_time_format_custom').on('click', function() { FormatDatesInPreview('csv', 'csv'); });
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<itop_design xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="3.0">
|
||||
<itop_design xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="3.1">
|
||||
<user_rights>
|
||||
<profiles>
|
||||
<profile id="1024" _delta="define">
|
||||
|
||||
@@ -1732,6 +1732,7 @@ abstract class DBObject implements iDisplay
|
||||
$iFlags = 0; // By default (if no life cycle) no flag at all
|
||||
$sClass = get_class($this);
|
||||
|
||||
// The code below prevents to hide a DashboardAttribute for eg.
|
||||
$aReadOnlyAtts = $this->GetReadOnlyAttributes();
|
||||
if (($aReadOnlyAtts != null) && (in_array($sAttCode, $aReadOnlyAtts)))
|
||||
{
|
||||
@@ -2934,6 +2935,9 @@ abstract class DBObject implements iDisplay
|
||||
utils::EnrichRaisedException($oTrigger, $e);
|
||||
}
|
||||
}
|
||||
|
||||
// - TriggerOnObjectMention
|
||||
$this->ActivateOnMentionTriggers(true);
|
||||
|
||||
return $this->m_iKey;
|
||||
}
|
||||
@@ -3197,50 +3201,7 @@ abstract class DBObject implements iDisplay
|
||||
// Activate any existing trigger
|
||||
$sClass = get_class($this);
|
||||
// - TriggerOnObjectMention
|
||||
// 1 - Check if any caselog updated
|
||||
$aUpdatedLogAttCodes = array();
|
||||
foreach($aChanges as $sAttCode => $value)
|
||||
{
|
||||
$oAttDef = MetaModel::GetAttributeDef($sClass, $sAttCode);
|
||||
if($oAttDef instanceof AttributeCaseLog)
|
||||
{
|
||||
$aUpdatedLogAttCodes[] = $sAttCode;
|
||||
}
|
||||
}
|
||||
// 2 - Find mentioned objects
|
||||
$aMentionedObjects = array();
|
||||
foreach ($aUpdatedLogAttCodes as $sAttCode) {
|
||||
/** @var \ormCaseLog $oUpdatedCaseLog */
|
||||
$oUpdatedCaseLog = $this->Get($sAttCode);
|
||||
$aMentionedObjects = array_merge_recursive($aMentionedObjects, utils::GetMentionedObjectsFromText($oUpdatedCaseLog->GetModifiedEntry()));
|
||||
}
|
||||
// 3 - Trigger for those objects
|
||||
// TODO: This should be refactored and moved into the caselogs loop, otherwise, we won't be able to know which case log triggered the action.
|
||||
foreach ($aMentionedObjects as $sMentionedClass => $aMentionedIds) {
|
||||
foreach ($aMentionedIds as $sMentionedId) {
|
||||
/** @var \DBObject $oMentionedObject */
|
||||
$oMentionedObject = MetaModel::GetObject($sMentionedClass, $sMentionedId);
|
||||
$aTriggerArgs = $this->ToArgs('this') + array('mentioned->object()' => $oMentionedObject);
|
||||
|
||||
$aParams = array('class_list' => MetaModel::EnumParentClasses($sClass, ENUM_PARENT_CLASSES_ALL));
|
||||
$oSet = new DBObjectSet(DBObjectSearch::FromOQL("SELECT TriggerOnObjectMention AS t WHERE t.target_class IN (:class_list)"), array(), $aParams);
|
||||
while ($oTrigger = $oSet->Fetch())
|
||||
{
|
||||
/** @var \TriggerOnObjectMention $oTrigger */
|
||||
try {
|
||||
// Ensure to handle only mentioned object in the trigger's scope
|
||||
if ($oTrigger->IsMentionedObjectInScope($oMentionedObject) === false) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$oTrigger->DoActivate($aTriggerArgs);
|
||||
}
|
||||
catch (Exception $e) {
|
||||
utils::EnrichRaisedException($oTrigger, $e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
$this->ActivateOnMentionTriggers(false);
|
||||
|
||||
$bHasANewExternalKeyValue = false;
|
||||
$aHierarchicalKeys = array();
|
||||
@@ -3453,6 +3414,122 @@ abstract class DBObject implements iDisplay
|
||||
return $this->m_iKey;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Increment attribute with specified value.
|
||||
* This function is only applicable with AttributeInteger.
|
||||
*
|
||||
* @api
|
||||
*
|
||||
* @param string $sAttCode attribute code
|
||||
* @param int $iValue value to increment (default value 1)
|
||||
*
|
||||
* @return int incremented value
|
||||
*
|
||||
* @throws \ArchivedObjectException
|
||||
* @throws \CoreException
|
||||
* @throws \MySQLException
|
||||
* @throws \MySQLHasGoneAwayException
|
||||
*/
|
||||
public function DBIncrement(string $sAttCode, int $iValue = 1)
|
||||
{
|
||||
// retrieve instance class
|
||||
$sClass = get_class($this);
|
||||
|
||||
// dirty object not allowed
|
||||
if($this->m_bDirty){
|
||||
throw new CoreException("Invalid DBIncrement usage, dirty objects are not allowed. Call DBUpdate before calling DBIncrement.");
|
||||
}
|
||||
|
||||
// ensure attribute type is AttributeInteger
|
||||
$oAttr = MetaModel::GetAttributeDef($sClass, $sAttCode);
|
||||
if(!$oAttr instanceof AttributeInteger){
|
||||
throw new CoreException(sprintf("Invalid DBIncrement usage, attribute type of {$sAttCode} is %s. Only AttributeInteger are compatibles with DBIncrement.", get_class($oAttr)));
|
||||
}
|
||||
|
||||
// prepare SQL statement
|
||||
$sTable = MetaModel::DBGetTable($sClass, $sAttCode);
|
||||
$sPKField = '`'.MetaModel::DBGetKey($sClass).'`';
|
||||
$sKey = CMDBSource::Quote($this->m_iKey);
|
||||
$sUpdateSQL = "UPDATE `{$sTable}` SET `{$sAttCode}` = `{$sAttCode}`+{$iValue} WHERE {$sPKField} = {$sKey}";
|
||||
|
||||
// execute SQL query
|
||||
CMDBSource::Query($sUpdateSQL);
|
||||
|
||||
// reload instance with new value
|
||||
$this->Reload();
|
||||
|
||||
return $this->Get($sAttCode);
|
||||
}
|
||||
|
||||
/**
|
||||
* Activate TriggerOnObjectMention triggers for the current object
|
||||
*
|
||||
* @param bool $bNewlyCreatedObject
|
||||
*
|
||||
* @throws \ArchivedObjectException
|
||||
* @throws \CoreException
|
||||
* @throws \CoreUnexpectedValue
|
||||
* @throws \MySQLException
|
||||
* @throws \OQLException
|
||||
* @since 3.0.1 N°4741
|
||||
*/
|
||||
private function ActivateOnMentionTriggers(bool $bNewlyCreatedObject): void
|
||||
{
|
||||
$sClass = get_class($this);
|
||||
$aChanges = $bNewlyCreatedObject ? $this->m_aOrigValues : $this->ListChanges();
|
||||
|
||||
// 1 - Check if any caselog updated
|
||||
$aUpdatedLogAttCodes = [];
|
||||
foreach ($aChanges as $sAttCode => $value) {
|
||||
$oAttDef = MetaModel::GetAttributeDef($sClass, $sAttCode);
|
||||
if ($oAttDef instanceof AttributeCaseLog) {
|
||||
// Skip empty log on creation
|
||||
if ($bNewlyCreatedObject && $value->GetModifiedEntry() === '') {
|
||||
continue;
|
||||
}
|
||||
|
||||
$aUpdatedLogAttCodes[] = $sAttCode;
|
||||
}
|
||||
}
|
||||
|
||||
// 2 - Find mentioned objects
|
||||
$aMentionedObjects = [];
|
||||
foreach ($aUpdatedLogAttCodes as $sAttCode) {
|
||||
/** @var \ormCaseLog $oUpdatedCaseLog */
|
||||
$oUpdatedCaseLog = $this->Get($sAttCode);
|
||||
$aMentionedObjects = array_merge_recursive($aMentionedObjects, utils::GetMentionedObjectsFromText($oUpdatedCaseLog->GetModifiedEntry()));
|
||||
}
|
||||
|
||||
// 3 - Trigger for those objects
|
||||
// TODO: This should be refactored and moved into the caselogs loop, otherwise, we won't be able to know which case log triggered the action.
|
||||
foreach ($aMentionedObjects as $sMentionedClass => $aMentionedIds) {
|
||||
foreach ($aMentionedIds as $sMentionedId) {
|
||||
/** @var \DBObject $oMentionedObject */
|
||||
$oMentionedObject = MetaModel::GetObject($sMentionedClass, $sMentionedId);
|
||||
$aTriggerArgs = $this->ToArgs('this') + ['mentioned->object()' => $oMentionedObject];
|
||||
|
||||
$aParams = ['class_list' => MetaModel::EnumParentClasses($sClass, ENUM_PARENT_CLASSES_ALL)];
|
||||
$oSet = new DBObjectSet(DBObjectSearch::FromOQL("SELECT TriggerOnObjectMention AS t WHERE t.target_class IN (:class_list)"), [], $aParams);
|
||||
while ($oTrigger = $oSet->Fetch())
|
||||
{
|
||||
/** @var \TriggerOnObjectMention $oTrigger */
|
||||
try {
|
||||
// Ensure to handle only mentioned object in the trigger's scope
|
||||
if ($oTrigger->IsMentionedObjectInScope($oMentionedObject) === false) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$oTrigger->DoActivate($aTriggerArgs);
|
||||
}
|
||||
catch (Exception $e) {
|
||||
utils::EnrichRaisedException($oTrigger, $e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* Save updated fields previous values for {@see DBObject::DBUpdate()} callbacks
|
||||
@@ -4358,14 +4435,22 @@ abstract class DBObject implements iDisplay
|
||||
$sAttCode = $sPlaceholderAttCode;
|
||||
}
|
||||
|
||||
if ($sVerb == 'hyperlink')
|
||||
if (in_array($sVerb, ['hyperlink', 'url']))
|
||||
{
|
||||
$sPortalId = ($sAttCode === '') ? 'console' : $sAttCode;
|
||||
if (!array_key_exists($sPortalId, self::$aPortalToURLMaker))
|
||||
{
|
||||
throw new Exception("Unknown portal id '$sPortalId' in placeholder '$sPlaceholderAttCode''");
|
||||
}
|
||||
$ret = $this->GetHyperlink(self::$aPortalToURLMaker[$sPortalId], false);
|
||||
|
||||
if($sVerb == 'hyperlink')
|
||||
{
|
||||
$ret = $this->GetHyperlink(self::$aPortalToURLMaker[$sPortalId], false);
|
||||
}
|
||||
else
|
||||
{
|
||||
$ret = ApplicationContext::MakeObjectUrl(get_class($this), $this->GetKey(), self::$aPortalToURLMaker[$sPortalId], false);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -5378,7 +5463,7 @@ abstract class DBObject implements iDisplay
|
||||
}
|
||||
$oLnk->Set($sRoleAttCode, $sRoleValue);
|
||||
}
|
||||
$oLinkSet->AddObject($oLnk);
|
||||
$oLinkSet->AddItem($oLnk);
|
||||
$this->Set($sTargetListAttCode, $oLinkSet);
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -413,14 +413,20 @@ 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 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
|
||||
*
|
||||
* @param string $sFilterCode
|
||||
* @param mixed $value
|
||||
* @param string $sOpCode operator to use : 'IN', 'NOT IN', 'Contains',' Begins with', 'Finishes with', ...
|
||||
* If no operator is specified then :
|
||||
* * for id field we will use "="
|
||||
* * for other fields we will call the corresponding {@link AttributeDefinition::GetSmartConditionExpression} method impl
|
||||
* to generate the expression
|
||||
* @param bool $bParseSearchString
|
||||
*
|
||||
* @throws \CoreException
|
||||
*
|
||||
* @see AddConditionForInOperatorUsingParam for IN/NOT IN queries with lots of params
|
||||
*/
|
||||
public function AddCondition($sFilterCode, $value, $sOpCode = null, $bParseSearchString = false)
|
||||
{
|
||||
@@ -465,14 +471,14 @@ class DBObjectSearch extends DBSearch
|
||||
if (!is_array($value)) $value = array($value);
|
||||
if (count($value) === 0) throw new Exception('AddCondition '.$sOpCode.': Value cannot be an empty array.');
|
||||
$sListExpr = '('.implode(', ', CMDBSource::Quote($value)).')';
|
||||
$sOQLCondition = $oField->Render()." IN $sListExpr";
|
||||
$sOQLCondition = $oField->RenderExpression()." IN $sListExpr";
|
||||
break;
|
||||
|
||||
case 'NOTIN':
|
||||
if (!is_array($value)) $value = array($value);
|
||||
if (count($value) === 0) throw new Exception('AddCondition '.$sOpCode.': Value cannot be an empty array.');
|
||||
$sListExpr = '('.implode(', ', CMDBSource::Quote($value)).')';
|
||||
$sOQLCondition = $oField->Render()." NOT IN $sListExpr";
|
||||
$sOQLCondition = $oField->RenderExpression()." NOT IN $sListExpr";
|
||||
break;
|
||||
|
||||
case 'Contains':
|
||||
@@ -1232,7 +1238,7 @@ class DBObjectSearch extends DBSearch
|
||||
elseif (MetaModel::IsParentClass($oRightFilter->GetFirstJoinedClass(), $oLeftFilter->GetClass()))
|
||||
{
|
||||
// Specialize $oRightFilter
|
||||
$oRightFilter->ChangeClass($oLeftFilter->GetClass());
|
||||
$oRightFilter->ChangeClass($oLeftFilter->GetFirstJoinedClass());
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1368,7 +1374,7 @@ class DBObjectSearch extends DBSearch
|
||||
public function GetQueryParams($bExcludeMagicParams = true)
|
||||
{
|
||||
$aParams = array();
|
||||
$this->m_oSearchCondition->Render($aParams, true);
|
||||
$this->m_oSearchCondition->RenderExpression(false, $aParams, true);
|
||||
|
||||
if ($bExcludeMagicParams)
|
||||
{
|
||||
@@ -1457,7 +1463,7 @@ class DBObjectSearch extends DBSearch
|
||||
|
||||
$sRes .= ' ' . $this->GetFirstJoinedClass() . ' AS `' . $this->GetFirstJoinedClassAlias() . '`';
|
||||
$sRes .= $this->ToOQL_Joins();
|
||||
$sRes .= " WHERE ".$this->m_oSearchCondition->Render($aParams, $bRetrofitParams);
|
||||
$sRes .= " WHERE ".$this->m_oSearchCondition->RenderExpression(false, $aParams, $bRetrofitParams);
|
||||
|
||||
if ($bWithAllowAllFlag && $this->m_bAllowAllData)
|
||||
{
|
||||
|
||||
@@ -416,7 +416,11 @@ class DBUnionSearch extends DBSearch
|
||||
$aSearches = array();
|
||||
foreach ($this->aSearches as $oSearch)
|
||||
{
|
||||
$aSearches[] = $oSearch->Filter($sClassAlias, $oFilter);
|
||||
if (!$oSearch->IsAllDataAllowed()) {
|
||||
$aSearches[] = $oSearch->Filter($sClassAlias, $oFilter);
|
||||
} else {
|
||||
$aSearches[] = $oSearch;
|
||||
}
|
||||
}
|
||||
return new DBUnionSearch($aSearches);
|
||||
}
|
||||
|
||||
@@ -302,13 +302,12 @@ class Dict
|
||||
*
|
||||
* @param $sSourceCode
|
||||
* @param $sDestCode
|
||||
* @since 3.0.1 Not clone sSourceCode entry if sDestCode entry already exist
|
||||
*/
|
||||
public static function CloneString($sSourceCode, $sDestCode)
|
||||
{
|
||||
foreach(self::$m_aLanguages as $sLanguageCode => $foo)
|
||||
{
|
||||
if (isset(self::$m_aData[$sLanguageCode][$sSourceCode]))
|
||||
{
|
||||
foreach(self::$m_aLanguages as $sLanguageCode => $foo) {
|
||||
if (isset(self::$m_aData[$sLanguageCode][$sSourceCode]) && !isset(self::$m_aData[$sLanguageCode][$sDestCode] )) {
|
||||
self::$m_aData[$sLanguageCode][$sDestCode] = self::$m_aData[$sLanguageCode][$sSourceCode];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,7 +31,7 @@ class DisplayableNode extends GraphNode
|
||||
{
|
||||
public $x;
|
||||
public $y;
|
||||
|
||||
|
||||
/**
|
||||
* Create a new node inside a graph
|
||||
* @param SimpleGraph $oGraph
|
||||
@@ -51,27 +51,27 @@ class DisplayableNode extends GraphNode
|
||||
{
|
||||
return $this->GetProperty('icon_url', '');
|
||||
}
|
||||
|
||||
|
||||
public function GetLabel()
|
||||
{
|
||||
return $this->GetProperty('label', $this->sId);
|
||||
}
|
||||
|
||||
|
||||
public function GetWidth()
|
||||
{
|
||||
return max(32, 5*strlen($this->GetProperty('label'))); // approximation of the text's bounding box
|
||||
}
|
||||
|
||||
|
||||
public function GetHeight()
|
||||
{
|
||||
return 32;
|
||||
}
|
||||
|
||||
|
||||
public function Distance2(DisplayableNode $oNode)
|
||||
{
|
||||
$dx = $this->x - $oNode->x;
|
||||
$dy = $this->y - $oNode->y;
|
||||
|
||||
|
||||
$d2 = $dx*$dx + $dy*$dy - $this->GetHeight()*$this->GetHeight();
|
||||
if ($d2 < 40)
|
||||
{
|
||||
@@ -79,12 +79,12 @@ class DisplayableNode extends GraphNode
|
||||
}
|
||||
return $d2;
|
||||
}
|
||||
|
||||
|
||||
public function Distance(DisplayableNode $oNode)
|
||||
{
|
||||
return sqrt($this->Distance2($oNode));
|
||||
}
|
||||
|
||||
|
||||
public function GetForRaphael($aContextDefs)
|
||||
{
|
||||
$aNode = array();
|
||||
@@ -100,7 +100,7 @@ class DisplayableNode extends GraphNode
|
||||
$aNode['label'] = $this->GetLabel();
|
||||
$aNode['id'] = $this->GetId();
|
||||
$fOpacity = ($this->GetProperty('is_reached') ? 1 : 0.4);
|
||||
$aNode['icon_attr'] = array('opacity' => $fOpacity);
|
||||
$aNode['icon_attr'] = array('opacity' => $fOpacity);
|
||||
$aNode['text_attr'] = array('opacity' => $fOpacity);
|
||||
$aNode['tooltip'] = $this->GetTooltip($aContextDefs);
|
||||
$aNode['context_icons'] = array();
|
||||
@@ -114,7 +114,7 @@ class DisplayableNode extends GraphNode
|
||||
}
|
||||
return $aNode;
|
||||
}
|
||||
|
||||
|
||||
public function RenderAsPDF(iTopPDF $oPdf, DisplayableGraph $oGraph, $fScale, $aContextDefs)
|
||||
{
|
||||
$Alpha = 1.0;
|
||||
@@ -170,7 +170,7 @@ class DisplayableNode extends GraphNode
|
||||
$oPdf->SetTextColor(0, 0, 0);
|
||||
$oPdf->Text($this->x*$fScale - $width/2, ($this->y + 18)*$fScale, $this->GetProperty('label'));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Create a "whitened" version of the icon (retaining the transparency) to be used a background for masking the underlying lines
|
||||
* @param string $sIconFile The path to the file containing the icon
|
||||
@@ -179,35 +179,35 @@ class DisplayableNode extends GraphNode
|
||||
protected function CreateWhiteIcon(DisplayableGraph $oGraph, $sIconFile)
|
||||
{
|
||||
$aInfo = getimagesize($sIconFile);
|
||||
|
||||
|
||||
$im = null;
|
||||
switch($aInfo['mime'])
|
||||
{
|
||||
case 'image/png':
|
||||
if (function_exists('imagecreatefrompng'))
|
||||
{
|
||||
$im = imagecreatefrompng($sIconFile);
|
||||
}
|
||||
break;
|
||||
|
||||
if (function_exists('imagecreatefrompng'))
|
||||
{
|
||||
$im = imagecreatefrompng($sIconFile);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'image/gif':
|
||||
if (function_exists('imagecreatefromgif'))
|
||||
{
|
||||
$im = imagecreatefromgif($sIconFile);
|
||||
}
|
||||
break;
|
||||
|
||||
if (function_exists('imagecreatefromgif'))
|
||||
{
|
||||
$im = imagecreatefromgif($sIconFile);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'image/jpeg':
|
||||
case 'image/jpg':
|
||||
if (function_exists('imagecreatefromjpeg'))
|
||||
{
|
||||
$im = imagecreatefromjpeg($sIconFile);
|
||||
}
|
||||
break;
|
||||
|
||||
if (function_exists('imagecreatefromjpeg'))
|
||||
{
|
||||
$im = imagecreatefromjpeg($sIconFile);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
return null;
|
||||
|
||||
return null;
|
||||
|
||||
}
|
||||
if($im && imagefilter($im, IMG_FILTER_COLORIZE, 255, 255, 255))
|
||||
{
|
||||
@@ -222,17 +222,17 @@ class DisplayableNode extends GraphNode
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public function GetObjectCount()
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
public function GetObjectClass()
|
||||
{
|
||||
return is_object($this->GetProperty('object', null)) ? get_class($this->GetProperty('object', null)) : null;
|
||||
}
|
||||
|
||||
|
||||
protected function AddToStats($oNode, &$aNodesPerClass)
|
||||
{
|
||||
$sClass = $oNode->GetObjectClass();
|
||||
@@ -256,9 +256,9 @@ class DisplayableNode extends GraphNode
|
||||
{
|
||||
$aNodesPerClass[$sClass][$sKey]['nodes'][$oNode->GetId()] = $oNode;
|
||||
$aNodesPerClass[$sClass][$sKey]['count'] += $oNode->GetObjectCount();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Retrieves the list of neighbour nodes, in the given direction: 'up' or 'down'
|
||||
* @param bool $bDirectionDown
|
||||
@@ -279,11 +279,11 @@ class DisplayableNode extends GraphNode
|
||||
foreach($this->GetIncomingEdges() as $oEdge)
|
||||
{
|
||||
$aNextNodes[] = $oEdge->GetSourceNode();
|
||||
}
|
||||
}
|
||||
}
|
||||
return $aNextNodes;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Replaces the next neighbour node (in the given direction: 'up' or 'down') by the supplied group node
|
||||
* preserving the connectivity of the graph
|
||||
@@ -351,7 +351,7 @@ class DisplayableNode extends GraphNode
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if ($oGraph->GetNode($oNextNode->GetId()))
|
||||
{
|
||||
$oGraph->_RemoveNode($oNextNode);
|
||||
@@ -367,9 +367,9 @@ class DisplayableNode extends GraphNode
|
||||
{
|
||||
$oNewNode->AddObject($oNextNode->GetProperty('object'));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Group together (as a special kind of nodes) all the similar neighbours of the current node
|
||||
* @param DisplayableGraph $oGraph
|
||||
@@ -381,7 +381,7 @@ class DisplayableNode extends GraphNode
|
||||
{
|
||||
if ($this->GetProperty('grouped') === true) return;
|
||||
$this->SetProperty('grouped', true);
|
||||
|
||||
|
||||
$aNodesPerClass = array();
|
||||
foreach($this->GetNextNodes($bDirectionDown) as $oNode)
|
||||
{
|
||||
@@ -412,7 +412,7 @@ class DisplayableNode extends GraphNode
|
||||
$oNewNode->SetProperty('is_reached', ($sStatus == 'reached'));
|
||||
$oNewNode->SetProperty('count', $aGroupProps['count']);
|
||||
}
|
||||
|
||||
|
||||
try
|
||||
{
|
||||
if ($bDirectionDown)
|
||||
@@ -427,8 +427,8 @@ class DisplayableNode extends GraphNode
|
||||
catch(Exception $e)
|
||||
{
|
||||
// Ignore this redundant egde
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
foreach($aGroupProps['nodes'] as $oNextNode)
|
||||
{
|
||||
$this->ReplaceNextNodeBy($oGraph, $oNextNode, $oNewNode, $bDirectionDown);
|
||||
@@ -445,7 +445,7 @@ class DisplayableNode extends GraphNode
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public function GetTooltip($aContextDefs)
|
||||
{
|
||||
$sHtml = '';
|
||||
@@ -474,9 +474,9 @@ class DisplayableNode extends GraphNode
|
||||
$sHtml .= '<tr><td>'.$oAttDef->GetLabel().': </td><td>'.$oCurrObj->GetAsHtml($sAttCode).'</td></tr>';
|
||||
}
|
||||
$sHtml .= '</tbody></table>';
|
||||
return $sHtml;
|
||||
return $sHtml;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the description of the node in "dot" language
|
||||
* Used to generate the positions in the graph, but we'd better use fake label
|
||||
@@ -508,7 +508,7 @@ class DisplayableRedundancyNode extends DisplayableNode
|
||||
{
|
||||
return 24;
|
||||
}
|
||||
|
||||
|
||||
public function GetForRaphael($aContextDefs)
|
||||
{
|
||||
$aNode = array();
|
||||
@@ -519,7 +519,7 @@ class DisplayableRedundancyNode extends DisplayableNode
|
||||
$aNode['x'] = $this->x;
|
||||
$aNode['y']= $this->y;
|
||||
$aNode['label'] = $this->GetLabel();
|
||||
$aNode['id'] = $this->GetId();
|
||||
$aNode['id'] = $this->GetId();
|
||||
$fDiscOpacity = ($this->GetProperty('is_reached') ? 1 : 0.2);
|
||||
$sColor = ($this->GetProperty('is_reached_count') > $this->GetProperty('threshold')) ? '#c33' : '#999';
|
||||
$aNode['disc_attr'] = array('stroke-width' => 2, 'stroke' => '#000', 'fill' => $sColor, 'opacity' => $fDiscOpacity);
|
||||
@@ -550,35 +550,35 @@ class DisplayableRedundancyNode extends DisplayableNode
|
||||
$height = $oPdf->GetStringHeight(1000, $sLabel);
|
||||
$xPos = (float)$this->x*$fScale - $width/2;
|
||||
$yPos = (float)$this->y*$fScale - $height/2;
|
||||
|
||||
|
||||
$oPdf->SetXY(($this->x - 16)*$fScale, ($this->y - 16)*$fScale);
|
||||
|
||||
|
||||
$oPdf->Cell(32*$fScale, 32*$fScale, $sLabel, 0, 0, 'C', 0, '', 0, false, 'T', 'C');
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @see DisplayableNode::GroupSimilarNeighbours()
|
||||
*/
|
||||
public function GroupSimilarNeighbours(DisplayableGraph $oGraph, $iThresholdCount, $bDirectionUp = false, $bDirectionDown = true)
|
||||
{
|
||||
parent::GroupSimilarNeighbours($oGraph, $iThresholdCount, $bDirectionUp, $bDirectionDown);
|
||||
|
||||
|
||||
if ($bDirectionUp)
|
||||
{
|
||||
$aNodesPerClass = array();
|
||||
foreach($this->GetIncomingEdges() as $oEdge)
|
||||
{
|
||||
$oNode = $oEdge->GetSourceNode();
|
||||
|
||||
|
||||
if (($oNode->GetObjectClass() !== null) && (!$oNode->GetProperty('is_reached')))
|
||||
{
|
||||
{
|
||||
$this->AddToStats($oNode, $aNodesPerClass);
|
||||
}
|
||||
else
|
||||
{
|
||||
//$oNode->GroupSimilarNeighbours($oGraph, $iThresholdCount, $bDirectionUp, $bDirectionDown);
|
||||
}
|
||||
}
|
||||
}
|
||||
foreach($aNodesPerClass as $sClass => $aDefs)
|
||||
{
|
||||
foreach($aDefs as $sStatus => $aGroupProps)
|
||||
@@ -591,8 +591,8 @@ class DisplayableRedundancyNode extends DisplayableNode
|
||||
$oNewNode->SetProperty('is_reached', ($sStatus == 'is_reached'));
|
||||
$oNewNode->SetProperty('class', $sClass);
|
||||
$oNewNode->SetProperty('count', count($aGroupProps['nodes']));
|
||||
|
||||
|
||||
|
||||
|
||||
$sNewId = $this->GetId().'::'.$sClass.'/'.(($sStatus == 'reached') ? '_reached': '');
|
||||
$oNewNode = $oGraph->GetNode($sNewId);
|
||||
if ($oNewNode == null)
|
||||
@@ -604,7 +604,7 @@ class DisplayableRedundancyNode extends DisplayableNode
|
||||
$oNewNode->SetProperty('is_reached', ($sStatus == 'reached'));
|
||||
$oNewNode->SetProperty('count', $aGroupProps['count']);
|
||||
}
|
||||
|
||||
|
||||
try
|
||||
{
|
||||
$oOutgoingEdge = new DisplayableEdge($oGraph, '-'.$this->GetId().'-'.$oNewNode->GetId().'/'.$sStatus, $oNewNode, $this);
|
||||
@@ -613,7 +613,7 @@ class DisplayableRedundancyNode extends DisplayableNode
|
||||
{
|
||||
// Ignore this redundant egde
|
||||
}
|
||||
|
||||
|
||||
foreach($aGroupProps['nodes'] as $oNextNode)
|
||||
{
|
||||
$this->ReplaceNextNodeBy($oGraph, $oNextNode, $oNewNode, !$bDirectionUp);
|
||||
@@ -631,7 +631,7 @@ class DisplayableRedundancyNode extends DisplayableNode
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public function GetTooltip($aContextDefs)
|
||||
{
|
||||
$sHtml = '';
|
||||
@@ -640,9 +640,9 @@ class DisplayableRedundancyNode extends DisplayableNode
|
||||
$sHtml .= "<tr><td>".Dict::Format('UI:RelationTooltip:ImpactedItems_N_of_M' , $this->GetProperty('is_reached_count'), $this->GetProperty('min_up') + $this->GetProperty('threshold'))."</td></tr>";
|
||||
$sHtml .= "<tr><td>".Dict::Format('UI:RelationTooltip:CriticalThreshold_N_of_M' , $this->GetProperty('threshold'), $this->GetProperty('min_up') + $this->GetProperty('threshold'))."</td></tr>";
|
||||
$sHtml .= '</tbody></table>';
|
||||
return $sHtml;
|
||||
return $sHtml;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public function GetObjectCount()
|
||||
{
|
||||
@@ -666,7 +666,7 @@ class DisplayableEdge extends GraphEdge
|
||||
}
|
||||
$xStart = $oSourceNode->x * $fScale;
|
||||
$yStart = $oSourceNode->y * $fScale;
|
||||
|
||||
|
||||
$oSinkNode = $this->GetSinkNode();
|
||||
if (($oSinkNode->x == null) || ($oSinkNode->y == null))
|
||||
{
|
||||
@@ -674,9 +674,9 @@ class DisplayableEdge extends GraphEdge
|
||||
}
|
||||
$xEnd = $oSinkNode->x * $fScale;
|
||||
$yEnd = $oSinkNode->y * $fScale;
|
||||
|
||||
|
||||
$bReached = ($this->GetSourceNode()->GetProperty('is_reached') && $this->GetSinkNode()->GetProperty('is_reached'));
|
||||
|
||||
|
||||
$oPdf->setAlpha(1);
|
||||
if ($bReached)
|
||||
{
|
||||
@@ -688,8 +688,8 @@ class DisplayableEdge extends GraphEdge
|
||||
}
|
||||
$oPdf->SetLineStyle(array('width' => 2*$fScale, 'cap' => 'round', 'join' => 'miter', 'dash' => 0, 'color' => $aColor));
|
||||
$oPdf->Line($xStart, $yStart, $xEnd, $yEnd);
|
||||
|
||||
|
||||
|
||||
|
||||
$vx = $xEnd - $xStart;
|
||||
$vy = $yEnd - $yStart;
|
||||
$l = sqrt($vx*$vx + $vy*$vy);
|
||||
@@ -699,24 +699,24 @@ class DisplayableEdge extends GraphEdge
|
||||
$uy = $vx;
|
||||
$lPos = max($l/2, $l - 40*$fScale);
|
||||
$iArrowSize = 5*$fScale;
|
||||
|
||||
|
||||
$x = $xStart + $lPos * $vx;
|
||||
$y = $yStart + $lPos * $vy;
|
||||
$oPdf->Line($x, $y, $x + $iArrowSize * ($ux-$vx), $y + $iArrowSize * ($uy-$vy));
|
||||
$oPdf->Line($x, $y, $x - $iArrowSize * ($ux+$vx), $y - $iArrowSize * ($uy+$vy));
|
||||
$oPdf->Line($x, $y, $x - $iArrowSize * ($ux+$vx), $y - $iArrowSize * ($uy+$vy));
|
||||
}
|
||||
}
|
||||
|
||||
class DisplayableGroupNode extends DisplayableNode
|
||||
{
|
||||
protected $aObjects;
|
||||
|
||||
|
||||
public function __construct(SimpleGraph $oGraph, $sId, $x = 0, $y = 0)
|
||||
{
|
||||
parent::__construct($oGraph, $sId, $x, $y);
|
||||
$this->aObjects = array();
|
||||
}
|
||||
|
||||
|
||||
public function AddObject(DBObject $oObj = null)
|
||||
{
|
||||
if (is_object($oObj))
|
||||
@@ -729,12 +729,12 @@ class DisplayableGroupNode extends DisplayableNode
|
||||
$this->aObjects[$oObj->GetKey()] = $oObj;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public function GetObjects()
|
||||
{
|
||||
return $this->aObjects;
|
||||
}
|
||||
|
||||
|
||||
public function GetWidth()
|
||||
{
|
||||
return 50;
|
||||
@@ -760,7 +760,7 @@ class DisplayableGroupNode extends DisplayableNode
|
||||
$aNode['tooltip'] = $this->GetTooltip($aContextDefs);
|
||||
return $aNode;
|
||||
}
|
||||
|
||||
|
||||
public function RenderAsPDF(iTopPDF $oPdf, DisplayableGraph $oGraph, $fScale, $aContextDefs)
|
||||
{
|
||||
$bReached = $this->GetProperty('is_reached');
|
||||
@@ -790,7 +790,7 @@ class DisplayableGroupNode extends DisplayableNode
|
||||
$oPdf->SetTextColor(0, 0, 0);
|
||||
$oPdf->Text($this->x * $fScale - $width / 2, ($this->y + 25) * $fScale, $this->GetProperty('label'));
|
||||
}
|
||||
|
||||
|
||||
public function GetTooltip($aContextDefs)
|
||||
{
|
||||
$iGroupIdx = $this->GetProperty('group_index');
|
||||
@@ -823,7 +823,7 @@ class DisplayableGraph extends SimpleGraph
|
||||
protected $aTempImages;
|
||||
protected $aSourceObjects;
|
||||
protected $aSinkObjects;
|
||||
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
@@ -831,14 +831,14 @@ class DisplayableGraph extends SimpleGraph
|
||||
$this->aSourceObjects = array();
|
||||
$this->aSinkObjects = array();
|
||||
}
|
||||
|
||||
|
||||
public function GetTempImageName()
|
||||
{
|
||||
$sNewTempName = tempnam(APPROOT.'data', 'img-');
|
||||
$this->aTempImages[] = $sNewTempName;
|
||||
return $sNewTempName;
|
||||
}
|
||||
|
||||
|
||||
public function __destruct()
|
||||
{
|
||||
foreach($this->aTempImages as $sTempFile)
|
||||
@@ -918,7 +918,7 @@ class DisplayableGraph extends SimpleGraph
|
||||
$oSinkNode = $oNewGraph->GetNode($oEdge->GetSinkNode()->GetId());
|
||||
$oNewEdge = new DisplayableEdge($oNewGraph, $oEdge->GetId(), $oSourceNode, $oSinkNode);
|
||||
}
|
||||
|
||||
|
||||
// Remove duplicate edges between two nodes
|
||||
$oEdgesIter = new RelationTypeIterator($oNewGraph, 'Edge');
|
||||
$aEdgeKeys = array();
|
||||
@@ -946,7 +946,7 @@ class DisplayableGraph extends SimpleGraph
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
$oNodesIter = new RelationTypeIterator($oNewGraph, 'Node');
|
||||
foreach($oNodesIter as $oNode)
|
||||
{
|
||||
@@ -981,7 +981,7 @@ class DisplayableGraph extends SimpleGraph
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Remove duplicate edges between two nodes
|
||||
$oEdgesIter = new RelationTypeIterator($oNewGraph, 'Edge');
|
||||
$aEdgeKeys = array();
|
||||
@@ -1010,10 +1010,10 @@ class DisplayableGraph extends SimpleGraph
|
||||
}
|
||||
}
|
||||
set_time_limit(intval($iPreviousTimeLimit));
|
||||
|
||||
|
||||
return $oNewGraph;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Initializes the positions by rendering using Graphviz in xdot format
|
||||
* and parsing the output.
|
||||
@@ -1026,7 +1026,7 @@ class DisplayableGraph extends SimpleGraph
|
||||
{
|
||||
throw new Exception($sDot);
|
||||
}
|
||||
|
||||
|
||||
$aChunks = explode(";", $sDot);
|
||||
foreach($aChunks as $sChunk)
|
||||
{
|
||||
@@ -1035,7 +1035,7 @@ class DisplayableGraph extends SimpleGraph
|
||||
$sId = $aMatches[1];
|
||||
$xPos = $aMatches[2];
|
||||
$yPos = $aMatches[3];
|
||||
|
||||
|
||||
$oNode = $this->GetNode($sId);
|
||||
if ($oNode !== null)
|
||||
{
|
||||
@@ -1049,7 +1049,7 @@ class DisplayableGraph extends SimpleGraph
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public function GetBoundingBox()
|
||||
{
|
||||
$xMin = null;
|
||||
@@ -1074,10 +1074,10 @@ class DisplayableGraph extends SimpleGraph
|
||||
$yMax = max($yMax, $oNode->y + $oNode->GetHeight() / 2);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return array('xmin' => $xMin, 'xmax' => $xMax, 'ymin' => $yMin, 'ymax' => $yMax);
|
||||
}
|
||||
|
||||
|
||||
function Translate($dx, $dy)
|
||||
{
|
||||
$oIterator = new RelationTypeIterator($this, 'Node');
|
||||
@@ -1085,9 +1085,9 @@ class DisplayableGraph extends SimpleGraph
|
||||
{
|
||||
$oNode->x += $dx;
|
||||
$oNode->y += $dy;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public function UpdatePositions($aPositions)
|
||||
{
|
||||
foreach($aPositions as $sNodeId => $aPos)
|
||||
@@ -1107,7 +1107,7 @@ class DisplayableGraph extends SimpleGraph
|
||||
function GetAsJSON($sContextKey)
|
||||
{
|
||||
$aContextDefs = static::GetContextDefinitions($sContextKey, false);
|
||||
|
||||
|
||||
$aData = array('nodes' => array(), 'edges' => array(), 'groups' => array(), 'lists' => array());
|
||||
$iGroupIdx = 0;
|
||||
$oIterator = new RelationTypeIterator($this, 'Node');
|
||||
@@ -1131,7 +1131,7 @@ class DisplayableGraph extends SimpleGraph
|
||||
$aData['groups'][$iGroupIdx] = array('class' => $sClass, 'keys' => $aKeys);
|
||||
$oNode->SetProperty('group_index', $iGroupIdx);
|
||||
$iGroupIdx++;
|
||||
|
||||
|
||||
if ($oNode->GetProperty('is_reached'))
|
||||
{
|
||||
// Also add the objects from this group into the 'list' tab
|
||||
@@ -1139,11 +1139,11 @@ class DisplayableGraph extends SimpleGraph
|
||||
{
|
||||
$aData['lists'][$sClass] = $aKeys;
|
||||
}
|
||||
else
|
||||
else
|
||||
{
|
||||
$aData['lists'][$sClass] = array_merge($aData['lists'][$sClass], $aKeys);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
if (($oNode instanceof DisplayableNode) && $oNode->GetProperty('is_reached') && is_object($oNode->GetProperty('object')))
|
||||
@@ -1157,9 +1157,9 @@ class DisplayableGraph extends SimpleGraph
|
||||
}
|
||||
$aData['nodes'][] = $oNode->GetForRaphael($aContextDefs);
|
||||
}
|
||||
|
||||
|
||||
uksort($aData['lists'], array(get_class($this), 'SortOnClassLabel')); // sort on the localized names of the classes to provide a consistent and stable order
|
||||
|
||||
|
||||
$oIterator = new RelationTypeIterator($this, 'Edge');
|
||||
foreach($oIterator as $sId => $oEdge)
|
||||
{
|
||||
@@ -1171,7 +1171,7 @@ class DisplayableGraph extends SimpleGraph
|
||||
$aEdge['attr'] = array('opacity' => $fOpacity, 'stroke' => '#000');
|
||||
$aData['edges'][] = $aEdge;
|
||||
}
|
||||
|
||||
|
||||
return json_encode($aData);
|
||||
}
|
||||
|
||||
@@ -1200,12 +1200,12 @@ class DisplayableGraph extends SimpleGraph
|
||||
{
|
||||
$aContextDefs = static::GetContextDefinitions($sContextKey, false); // No need to develop the parameters
|
||||
$oPdf = $oPage->get_tcpdf();
|
||||
|
||||
|
||||
$aBB = $this->GetBoundingBox();
|
||||
$this->Translate(-$aBB['xmin'], -$aBB['ymin']);
|
||||
|
||||
|
||||
$aMargins = $oPdf->getMargins();
|
||||
|
||||
|
||||
if ($xMin == -1)
|
||||
{
|
||||
$xMin = $aMargins['left'];
|
||||
@@ -1222,7 +1222,7 @@ class DisplayableGraph extends SimpleGraph
|
||||
{
|
||||
$yMax = $oPdf->getPageHeight() - $aMargins['bottom'];
|
||||
}
|
||||
|
||||
|
||||
$fBreakMargin = $oPdf->getBreakMargin();
|
||||
$oPdf->SetAutoPageBreak(false);
|
||||
$aRemainingArea = $this->RenderKey($oPdf, $sComments, $xMin, $yMin, $xMax, $yMax, $aContextDefs);
|
||||
@@ -1230,19 +1230,19 @@ class DisplayableGraph extends SimpleGraph
|
||||
$xMax = $aRemainingArea['xmax'];
|
||||
$yMin = $aRemainingArea['ymin'];
|
||||
$yMax = $aRemainingArea['ymax'];
|
||||
|
||||
|
||||
//$oPdf->Rect($xMin, $yMin, $xMax - $xMin, $yMax - $yMin, 'D', array(), array(225, 50, 50));
|
||||
|
||||
|
||||
$fPageW = $xMax - $xMin;
|
||||
$fPageH = $yMax - $yMin;
|
||||
|
||||
$w = $aBB['xmax'] - $aBB['xmin'];
|
||||
|
||||
$w = $aBB['xmax'] - $aBB['xmin'];
|
||||
$h = $aBB['ymax'] - $aBB['ymin'] + 10; // Extra space for the labels which may appear "below" the icons
|
||||
|
||||
|
||||
$fScale = min($fPageW / $w, $fPageH / $h);
|
||||
$dx = ($fPageW - $fScale * $w) / 2;
|
||||
$dy = ($fPageH - $fScale * $h) / 2;
|
||||
|
||||
|
||||
$this->Translate(($xMin + $dx)/$fScale, ($yMin + $dy)/$fScale);
|
||||
|
||||
$oIterator = new RelationTypeIterator($this, 'Edge');
|
||||
@@ -1264,7 +1264,7 @@ class DisplayableGraph extends SimpleGraph
|
||||
$oPdf->SetAlpha(1);
|
||||
$oPdf->SetTextColor(0, 0, 0);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Renders (in PDF) the key (legend) of the graphics vertically to the left of the specified zone (xmin,ymin, xmax,ymax),
|
||||
* and the comment (if any) at the bottom of the page. Returns the position of remaining area.
|
||||
@@ -1332,7 +1332,7 @@ class DisplayableGraph extends SimpleGraph
|
||||
$yPos += $fIconSize + 2 * $fPadding;
|
||||
}
|
||||
$oPdf->Rect($xMin, $yMin, $fMaxWidth + $fIconSize + 3*$fPadding, $yMax - $yMin, 'D');
|
||||
|
||||
|
||||
if ($sComments != '')
|
||||
{
|
||||
// Draw the comment text (surrounded by a rectangle)
|
||||
@@ -1347,10 +1347,10 @@ class DisplayableGraph extends SimpleGraph
|
||||
$oPdf->Rect($xPos, $yPos, $w + 2*$fPadding, $h + 2*$fPadding, 'D');
|
||||
$yMax = $yPos - $fPadding;
|
||||
}
|
||||
|
||||
|
||||
return array('xmin' => $xMin + $fMaxWidth + $fIconSize + 4*$fPadding, 'xmax' => $xMax, 'ymin' => $yMin, 'ymax' => $yMax);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the context definitions from the parameters / configuration. The format of the "key" string is:
|
||||
* <module>/relation_context/<class>/<relation>/<direction>
|
||||
@@ -1372,7 +1372,7 @@ class DisplayableGraph extends SimpleGraph
|
||||
else
|
||||
{
|
||||
$sLeafClass = $aLevels[2];
|
||||
|
||||
|
||||
if (!MetaModel::IsValidClass($sLeafClass))
|
||||
{
|
||||
IssueLog::Warning("GetContextDefinitions: invalid 'sLeafClass' = '$sLeafClass'. A valid class name is expected in 3rd position inside '$sContextKey' !");
|
||||
@@ -1387,7 +1387,7 @@ class DisplayableGraph extends SimpleGraph
|
||||
$aContextDefs = array_merge($aContextDefs, $aRelationContext[$sClass][$aLevels[3]][$aLevels[4]]['items']);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Check if the queries are valid
|
||||
foreach($aContextDefs as $sKey => $sDefs)
|
||||
{
|
||||
@@ -1421,172 +1421,108 @@ class DisplayableGraph extends SimpleGraph
|
||||
* @param int $iObjKey
|
||||
* @param string $sContextKey
|
||||
* @param array $aContextParams
|
||||
* @param bool $bLazyLoading since 2.7.7 3.0.1
|
||||
*
|
||||
* @throws \CoreException
|
||||
* @throws \DictExceptionMissingString
|
||||
*/
|
||||
function Display(WebPage $oP, $aResults, $sRelation, ApplicationContext $oAppContext, $aExcludedObjects, $sObjClass, $iObjKey, $sContextKey, $aContextParams = 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();
|
||||
}
|
||||
$sSftShort = Dict::S('UI:ElementsDisplayed');
|
||||
$sSearchToggle = Dict::S('UI:Search:Toggle');
|
||||
$oP->add("<div class=\"not-printable\">\n");
|
||||
$oUiSearchBlock = new Panel($sSftShort, [],Panel::ENUM_COLOR_SCHEME_CYAN, 'ds_flash');
|
||||
$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">
|
||||
<div id="dh_flash_criterion_outer" class="sf_criterion_area"><div class="sf_criterion_row">
|
||||
EOF
|
||||
);
|
||||
$oP->add_ready_script(
|
||||
<<<EOF
|
||||
$("#dh_flash > .sf_title").on('click', function() {
|
||||
$("#dh_flash").toggleClass('closed');
|
||||
});
|
||||
$('#ReloadMovieBtn').button().button('disable');
|
||||
EOF
|
||||
);
|
||||
$aSortedElements = array();
|
||||
foreach($aResults as $sClassIdx => $aObjects)
|
||||
{
|
||||
foreach($aObjects as $oCurrObj)
|
||||
{
|
||||
$sSubClass = get_class($oCurrObj);
|
||||
$aSortedElements[$sSubClass] = MetaModel::GetName($sSubClass);
|
||||
}
|
||||
}
|
||||
|
||||
asort($aSortedElements);
|
||||
$idx = 0;
|
||||
foreach($aSortedElements as $sSubClass => $sClassName)
|
||||
{
|
||||
$oUiHtmlBlock->AddHtml("<div><input type=\"checkbox\" id=\"exclude_$idx\" name=\"excluded[]\" value=\"$sSubClass\" checked onChange=\"$('#ReloadMovieBtn').button('enable')\"><label for=\"exclude_$idx\">");
|
||||
$oUiMedallionBlock= new MedallionIcon(MetaModel::GetClassIcon($sSubClass, false));
|
||||
$oUiMedallionBlock->SetDescription($sClassName);
|
||||
$oUiHtmlBlock->AddHtml(BlockRenderer::RenderBlockTemplates($oUiMedallionBlock));
|
||||
$oUiHtmlBlock->AddHtml("</label></div>");
|
||||
$idx++;
|
||||
}
|
||||
$oUiHtmlBlock->AddHtml("</div>");
|
||||
$oUiHtmlBlock->AddHtml("<button type=\"button\" id=\"ReloadMovieBtn\" class=\"ibo-button ibo-is-neutral ibo-is-regular\" onClick=\"DoReload()\">".Dict::S('UI:Button:Refresh')."</button></div></form>");
|
||||
$oUiHtmlBlock->AddHtml("</div>\n");
|
||||
$oUiHtmlBlock->AddHtml("</div>\n"); // class="not-printable"
|
||||
function Display(WebPage $oP, $aResults, $sRelation, ApplicationContext $oAppContext, $aExcludedObjects, $sObjClass, $iObjKey, $sContextKey, $aContextParams = array(), bool $bLazyLoading = false)
|
||||
{
|
||||
list($aExcludedByClass, $aAdditionalContexts) = $this->DisplayFiltering($sContextKey, $aContextParams, $aExcludedObjects, $oP, $aResults, $bLazyLoading);
|
||||
|
||||
$oUiSearchBlock->AddSubBlock($oUiHtmlBlock);
|
||||
$oP->AddUiBlock($oUiSearchBlock);
|
||||
$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')));
|
||||
}
|
||||
|
||||
$sDirection = utils::ReadParam('d', 'horizontal');
|
||||
$iGroupingThreshold = utils::ReadParam('g', 5);
|
||||
|
||||
WebResourcesHelper::EnableSimpleGraphInWebPage($oP);
|
||||
try
|
||||
{
|
||||
try {
|
||||
$this->InitFromGraphviz();
|
||||
$sExportAsPdfURL = '';
|
||||
$sExportAsPdfURL = utils::GetAbsoluteUrlAppRoot().'pages/ajax.render.php?operation=relation_pdf&relation='.$sRelation.'&direction='.($this->bDirectionDown ? 'down' : 'up');
|
||||
$oAppcontext = new ApplicationContext();
|
||||
$sContext = $oAppContext->GetForLink();
|
||||
$sDrillDownURL = utils::GetAbsoluteUrlAppRoot().'pages/UI.php?operation=details&class=%1$s&id=%2$s&'.$sContext;
|
||||
$sExportAsDocumentURL = utils::GetAbsoluteUrlAppRoot().'pages/ajax.render.php?operation=relation_attachment&relation='.$sRelation.'&direction='.($this->bDirectionDown ? 'down' : 'up');
|
||||
$sLoadFromURL = utils::GetAbsoluteUrlAppRoot().'pages/ajax.render.php?operation=relation_json&relation='.$sRelation.'&direction='.($this->bDirectionDown ? 'down' : 'up');
|
||||
$sAttachmentExportTitle = '';
|
||||
if (($sObjClass != null) && ($iObjKey != null))
|
||||
{
|
||||
if (($sObjClass != null) && ($iObjKey != null)) {
|
||||
$oTargetObj = MetaModel::GetObject($sObjClass, $iObjKey, false);
|
||||
if ($oTargetObj)
|
||||
{
|
||||
if ($oTargetObj) {
|
||||
$sAttachmentExportTitle = Dict::Format('UI:Relation:AttachmentExportOptions_Name', $oTargetObj->GetName());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
$sId = 'graph';
|
||||
$sStyle = '';
|
||||
if ($oP->IsPrintableVersion())
|
||||
{
|
||||
if ($oP->IsPrintableVersion()) {
|
||||
// Optimize for printing on A4/Letter vertically
|
||||
$sStyle = 'margin-left:auto; margin-right:auto;';
|
||||
$oP->add_ready_script("$('.simple-graph').width(18/2.54*96).resizable({ stop: function() { $(window).trigger('resized'); }});"); // Default width about 18 cm, since most browsers assume 96 dpi
|
||||
}
|
||||
$oP->add('<div id="'.$sId.'" class="simple-graph" style="'.$sStyle.'"></div>');
|
||||
$aParams = array(
|
||||
'source_url' => $sLoadFromURL,
|
||||
'sources' => ($this->bDirectionDown ? $this->aSourceObjects : $this->aSinkObjects),
|
||||
'excluded' => $aExcludedByClass,
|
||||
'grouping_threshold' => $iGroupingThreshold,
|
||||
'export_as_pdf' => array('url' => $sExportAsPdfURL, 'label' => Dict::S('UI:Relation:ExportAsPDF')),
|
||||
'source_url' => $sLoadFromURL,
|
||||
'sources' => ($this->bDirectionDown ? $this->aSourceObjects : $this->aSinkObjects),
|
||||
'excluded' => $aExcludedByClass,
|
||||
'grouping_threshold' => $iGroupingThreshold,
|
||||
'export_as_pdf' => array('url' => $sExportAsPdfURL, 'label' => Dict::S('UI:Relation:ExportAsPDF')),
|
||||
'export_as_attachment' => array('url' => $sExportAsDocumentURL, 'label' => Dict::S('UI:Relation:ExportAsAttachment'), 'obj_class' => $sObjClass, 'obj_key' => $iObjKey),
|
||||
'drill_down' => array('url' => $sDrillDownURL, 'label' => Dict::S('UI:Relation:DrillDown')),
|
||||
'labels' => array(
|
||||
'export_pdf_title' => Dict::S('UI:Relation:PDFExportOptions'),
|
||||
'drill_down' => array('url' => $sDrillDownURL, 'label' => Dict::S('UI:Relation:DrillDown')),
|
||||
'labels' => array(
|
||||
'export_pdf_title' => Dict::S('UI:Relation:PDFExportOptions'),
|
||||
'export_as_attachment_title' => $sAttachmentExportTitle,
|
||||
'export' => Dict::S('UI:Button:Export'),
|
||||
'cancel' => Dict::S('UI:Button:Cancel'),
|
||||
'title' => Dict::S('UI:RelationOption:Title'),
|
||||
'untitled' => Dict::S('UI:RelationOption:Untitled'),
|
||||
'include_list' => Dict::S('UI:RelationOption:IncludeList'),
|
||||
'comments' => Dict::S('UI:RelationOption:Comments'),
|
||||
'grouping_threshold' => Dict::S('UI:RelationOption:GroupingThreshold'),
|
||||
'refresh' => Dict::S('UI:Button:Refresh'),
|
||||
'check_all' => Dict::S('UI:SearchValue:CheckAll'),
|
||||
'uncheck_all' => Dict::S('UI:SearchValue:UncheckAll'),
|
||||
'none_selected' => Dict::S('UI:Relation:NoneSelected'),
|
||||
'nb_selected' => Dict::S('UI:SearchValue:NbSelected'),
|
||||
'additional_context_info' => Dict::S('UI:Relation:AdditionalContextInfo'),
|
||||
'zoom' => Dict::S('UI:Relation:Zoom'),
|
||||
'loading' => Dict::S('UI:Loading'),
|
||||
'export' => Dict::S('UI:Button:Export'),
|
||||
'cancel' => Dict::S('UI:Button:Cancel'),
|
||||
'title' => Dict::S('UI:RelationOption:Title'),
|
||||
'untitled' => Dict::S('UI:RelationOption:Untitled'),
|
||||
'include_list' => Dict::S('UI:RelationOption:IncludeList'),
|
||||
'comments' => Dict::S('UI:RelationOption:Comments'),
|
||||
'grouping_threshold' => Dict::S('UI:RelationOption:GroupingThreshold'),
|
||||
'refresh' => Dict::S('UI:Button:Refresh'),
|
||||
'check_all' => Dict::S('UI:SearchValue:CheckAll'),
|
||||
'uncheck_all' => Dict::S('UI:SearchValue:UncheckAll'),
|
||||
'none_selected' => Dict::S('UI:Relation:NoneSelected'),
|
||||
'nb_selected' => Dict::S('UI:SearchValue:NbSelected'),
|
||||
'additional_context_info' => Dict::S('UI:Relation:AdditionalContextInfo'),
|
||||
'zoom' => Dict::S('UI:Relation:Zoom'),
|
||||
'loading' => Dict::S('UI:Loading'),
|
||||
),
|
||||
'page_format' => array(
|
||||
'label' => Dict::S('UI:Relation:PDFExportPageFormat'),
|
||||
'page_format' => array(
|
||||
'label' => Dict::S('UI:Relation:PDFExportPageFormat'),
|
||||
'values' => array(
|
||||
'A3' => Dict::S('UI:PageFormat_A3'),
|
||||
'A4' => Dict::S('UI:PageFormat_A4'),
|
||||
'A3' => Dict::S('UI:PageFormat_A3'),
|
||||
'A4' => Dict::S('UI:PageFormat_A4'),
|
||||
'Letter' => Dict::S('UI:PageFormat_Letter'),
|
||||
),
|
||||
),
|
||||
'page_orientation' => array(
|
||||
'label' => Dict::S('UI:Relation:PDFExportPageOrientation'),
|
||||
'page_orientation' => array(
|
||||
'label' => Dict::S('UI:Relation:PDFExportPageOrientation'),
|
||||
'values' => array(
|
||||
'P' => Dict::S('UI:PageOrientation_Portrait'),
|
||||
'L' => Dict::S('UI:PageOrientation_Landscape'),
|
||||
),
|
||||
),
|
||||
'additional_contexts' => $aAdditionalContexts,
|
||||
'context_key' => $sContextKey,
|
||||
'additional_contexts' => $aAdditionalContexts,
|
||||
'context_key' => $sContextKey,
|
||||
);
|
||||
if (!extension_loaded('gd'))
|
||||
{
|
||||
if (!extension_loaded('gd')) {
|
||||
// PDF export requires GD
|
||||
unset($aParams['export_as_pdf']);
|
||||
}
|
||||
if (!extension_loaded('gd') || is_null($sObjClass) || is_null($iObjKey))
|
||||
{
|
||||
if (!extension_loaded('gd') || is_null($sObjClass) || is_null($iObjKey)) {
|
||||
// Export as Attachment requires GD (for building the PDF) AND a valid objclass/objkey couple
|
||||
unset($aParams['export_as_attachment']);
|
||||
}
|
||||
$oP->add_ready_script("$('#$sId').simple_graph(".json_encode($aParams).");");
|
||||
if ($oP->IsPrintableVersion() || !$bLazyLoading) {
|
||||
$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("$('#impacted_objects_lists').html('".utils::TextToHtml(Dict::S('Relation:impacts/NoFilteredData'))."');$('#impacted_groups').html('".utils::TextToHtml(Dict::S('Relation:impacts/NoFilteredData'))."');");
|
||||
|
||||
}
|
||||
}
|
||||
catch(Exception $e)
|
||||
{
|
||||
$oP->add('<div>'.$e->getMessage().'</div>');
|
||||
}
|
||||
$oP->add_script(
|
||||
<<<EOF
|
||||
<<<EOF
|
||||
|
||||
function DoReload()
|
||||
{
|
||||
@@ -1611,5 +1547,96 @@ EOF
|
||||
EOF
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param string $sContextKey
|
||||
* @param array $aContextParams
|
||||
* @param array $aExcludedObjects
|
||||
* @param \WebPage $oP
|
||||
* @param array $aResults
|
||||
* @param bool $bLazyLoading
|
||||
*
|
||||
* @return array
|
||||
* @throws \CoreException
|
||||
* @throws \DictExceptionMissingString
|
||||
* @throws \ReflectionException
|
||||
* @throws \Twig\Error\LoaderError
|
||||
* @throws \Twig\Error\RuntimeError
|
||||
* @throws \Twig\Error\SyntaxError
|
||||
*/
|
||||
public function DisplayFiltering(string $sContextKey, array $aContextParams, array $aExcludedObjects, WebPage $oP, array $aResults, bool $bLazyLoading = false): 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();
|
||||
}
|
||||
$sSftShort = Dict::S('UI:ElementsDisplayed');
|
||||
$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"]);
|
||||
$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">
|
||||
<div id="dh_flash_criterion_outer" class="sf_criterion_area"><div class="sf_criterion_row">
|
||||
EOF
|
||||
);
|
||||
$oP->add_ready_script(
|
||||
<<<EOF
|
||||
$("#dh_flash > .sf_title").on("click", function() {
|
||||
$("#dh_flash").toggleClass("closed");
|
||||
});
|
||||
$("#ReloadMovieBtn").button().button("disable");
|
||||
EOF
|
||||
);
|
||||
if ($bLazyLoading) {
|
||||
$oP->add_ready_script("$('#ReloadMovieBtn').button('enable');");
|
||||
} else {
|
||||
$oP->add_ready_script("$('#dh_flash').addClass('closed');");
|
||||
}
|
||||
$aSortedElements = array();
|
||||
foreach ($aResults as $sClassIdx => $aObjects) {
|
||||
foreach ($aObjects as $oCurrObj) {
|
||||
$sSubClass = get_class($oCurrObj);
|
||||
$aSortedElements[$sSubClass] = MetaModel::GetName($sSubClass);
|
||||
}
|
||||
}
|
||||
|
||||
asort($aSortedElements);
|
||||
$idx = 0;
|
||||
foreach ($aSortedElements as $sSubClass => $sClassName) {
|
||||
$oUiHtmlBlock->AddHtml("<div><input type=\"checkbox\" id=\"exclude_$idx\" name=\"excluded[]\" value=\"$sSubClass\" checked onChange=\"$('#ReloadMovieBtn').button('enable')\"><label for=\"exclude_$idx\">");
|
||||
$oUiMedallionBlock = new MedallionIcon(MetaModel::GetClassIcon($sSubClass, false));
|
||||
$oUiMedallionBlock->SetDescription($sClassName);
|
||||
$oUiHtmlBlock->AddHtml(BlockRenderer::RenderBlockTemplates($oUiMedallionBlock));
|
||||
$oUiHtmlBlock->AddHtml("</label></div>");
|
||||
$idx++;
|
||||
}
|
||||
$oUiHtmlBlock->AddHtml("</div>");
|
||||
if ($bLazyLoading) {
|
||||
$sOnCLick = "Load(); $('#ReloadMovieBtn').attr('onclick','DoReload()');$('#ReloadMovieBtn').html('".Dict::S('UI:Button:Refresh')."');";
|
||||
$oUiHtmlBlock->AddHtml("<button type=\"button\" id=\"ReloadMovieBtn\" class=\"ibo-button ibo-is-neutral ibo-is-regular\" onClick=\"$sOnCLick\">".Dict::S('Relation:impacts/LoadData')."</button></div></form>");
|
||||
} else {
|
||||
$sOnCLick = "DoReload()";
|
||||
$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);
|
||||
$oP->AddUiBlock($oUiSearchBlock);
|
||||
|
||||
$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')));
|
||||
}
|
||||
|
||||
return array($aExcludedByClass, $aAdditionalContexts);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -24,13 +24,18 @@
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
use Laminas\Mail\Header\ContentType;
|
||||
use Laminas\Mail\Message;
|
||||
use Laminas\Mail\Transport\File;
|
||||
use Laminas\Mail\Transport\FileOptions;
|
||||
use Laminas\Mail\Transport\SmtpOptions;
|
||||
use Laminas\Mail\Transport\Smtp;
|
||||
use Laminas\Mime\Mime;
|
||||
use Laminas\Mime\Part;
|
||||
use Pelago\Emogrifier\CssInliner;
|
||||
use Pelago\Emogrifier\HtmlProcessor\CssToAttributeConverter;
|
||||
use Pelago\Emogrifier\HtmlProcessor\HtmlPruner;
|
||||
|
||||
Swift_Preferences::getInstance()->setCharset('UTF-8');
|
||||
|
||||
|
||||
define ('EMAIL_SEND_OK', 0);
|
||||
define ('EMAIL_SEND_PENDING', 1);
|
||||
define ('EMAIL_SEND_ERROR', 2);
|
||||
@@ -58,7 +63,8 @@ class EMail
|
||||
public function __construct()
|
||||
{
|
||||
$this->m_aData = array();
|
||||
$this->m_oMessage = Swift_Message::newInstance();
|
||||
$this->m_oMessage = new Message();
|
||||
$this->m_oMessage->setEncoding('UTF-8');
|
||||
$this->SetRecipientFrom(MetaModel::GetConfig()->Get('email_default_sender_address'), MetaModel::GetConfig()->Get('email_default_sender_label'));
|
||||
}
|
||||
|
||||
@@ -72,12 +78,18 @@ class EMail
|
||||
{
|
||||
return serialize($this->m_aData);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Custom de-serialization method
|
||||
*
|
||||
* @param string $sSerializedMessage The serialized representation of the message
|
||||
*
|
||||
* @return \EMail
|
||||
* @throws \ArchivedObjectException
|
||||
* @throws \CoreException
|
||||
* @throws \Symfony\Component\CssSelector\Exception\SyntaxErrorException
|
||||
*/
|
||||
static public function UnSerializeV2($sSerializedMessage)
|
||||
public static function UnSerializeV2($sSerializedMessage)
|
||||
{
|
||||
$aData = unserialize($sSerializedMessage);
|
||||
$oMessage = new Email();
|
||||
@@ -115,7 +127,6 @@ class EMail
|
||||
$oMessage->SetSubject($aData['subject']);
|
||||
}
|
||||
|
||||
|
||||
if (array_key_exists('headers', $aData))
|
||||
{
|
||||
foreach($aData['headers'] as $sKey => $sValue)
|
||||
@@ -155,10 +166,11 @@ class EMail
|
||||
return EMAIL_SEND_PENDING;
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws \Exception
|
||||
*/
|
||||
protected function SendSynchronous(&$aIssues, $oLog = null)
|
||||
{
|
||||
// If the body of the message is in HTML, embed all images based on attachments
|
||||
$this->EmbedInlineImages();
|
||||
|
||||
$this->LoadConfig();
|
||||
|
||||
@@ -172,50 +184,54 @@ class EMail
|
||||
$sUserName = self::$m_oConfig->Get('email_transport_smtp.username');
|
||||
$sPassword = self::$m_oConfig->Get('email_transport_smtp.password');
|
||||
|
||||
$oTransport = Swift_SmtpTransport::newInstance($sHost, $sPort, $sEncryption);
|
||||
$oTransport = new Smtp();
|
||||
$aOptions= [
|
||||
'host' => $sHost,
|
||||
'port' => $sPort,
|
||||
'connection_class' => 'login',
|
||||
'connection_config' => [
|
||||
'ssl' => $sEncryption,
|
||||
],
|
||||
];
|
||||
if (strlen($sUserName) > 0)
|
||||
{
|
||||
$oTransport->setUsername($sUserName);
|
||||
$oTransport->setPassword($sPassword);
|
||||
$aOptions['connection_config']['username'] = $sUserName;
|
||||
$aOptions['connection_config']['password'] = $sPassword;
|
||||
}
|
||||
$oOptions = new SmtpOptions($aOptions);
|
||||
$oTransport->setOptions($oOptions);
|
||||
break;
|
||||
|
||||
case 'Null':
|
||||
$oTransport = Swift_NullTransport::newInstance();
|
||||
$oTransport = new Smtp();
|
||||
break;
|
||||
|
||||
case 'LogFile':
|
||||
$oTransport = Swift_LogFileTransport::newInstance();
|
||||
$oTransport->setLogFile(APPROOT.'log/mail.log');
|
||||
$oTransport = new File();
|
||||
$aOptions = new FileOptions([
|
||||
'path' => APPROOT.'log/mail.log',
|
||||
]);
|
||||
$oTransport->setOptions($aOptions);
|
||||
break;
|
||||
|
||||
case 'PHPMail':
|
||||
default:
|
||||
$oTransport = Swift_MailTransport::newInstance();
|
||||
$oTransport = new Smtp();
|
||||
}
|
||||
|
||||
$oMailer = Swift_Mailer::newInstance($oTransport);
|
||||
|
||||
$aFailedRecipients = array();
|
||||
$this->m_oMessage->setMaxLineLength(0);
|
||||
|
||||
$oKPI = new ExecutionKPI();
|
||||
try
|
||||
{
|
||||
$iSent = $oMailer->send($this->m_oMessage, $aFailedRecipients);
|
||||
if ($iSent === 0)
|
||||
{
|
||||
// Beware: it seems that $aFailedRecipients sometimes contains the recipients that actually received the message !!!
|
||||
IssueLog::Warning('Email sending failed: Some recipients were invalid, aFailedRecipients contains: '.implode(', ', $aFailedRecipients));
|
||||
$aIssues = array('Some recipients were invalid.');
|
||||
$oKPI->ComputeStats('Email Sent', 'Error received');
|
||||
return EMAIL_SEND_ERROR;
|
||||
}
|
||||
else
|
||||
{
|
||||
$aIssues = array();
|
||||
$oKPI->ComputeStats('Email Sent', 'Succeded');
|
||||
return EMAIL_SEND_OK;
|
||||
}
|
||||
$oTransport->send($this->m_oMessage);
|
||||
$aIssues = array();
|
||||
$oKPI->ComputeStats('Email Sent', 'Succeded');
|
||||
return EMAIL_SEND_OK;
|
||||
}
|
||||
catch(Laminas\Mail\Transport\Exception\RuntimeException $e){
|
||||
IssueLog::Warning('Email sending failed: Some recipients were invalid');
|
||||
$aIssues = array('Some recipients were invalid.');
|
||||
$oKPI->ComputeStats('Email Sent', 'Error received');
|
||||
return EMAIL_SEND_ERROR;
|
||||
}
|
||||
catch (Exception $e)
|
||||
{
|
||||
@@ -223,51 +239,65 @@ class EMail
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Reprocess the body of the message (if it is an HTML message)
|
||||
* to replace the URL of images based on attachments by a link
|
||||
* to an embedded image (i.e. cid:....)
|
||||
* to an embedded image (i.e. cid:....) and returns images to be attached as an array
|
||||
*
|
||||
* @param string $sBody Email body to process/alter
|
||||
*
|
||||
* @return array Array of Part that needs to be added as inline attachment later to render as embed
|
||||
* @throws \ArchivedObjectException
|
||||
* @throws \CoreException
|
||||
*/
|
||||
protected function EmbedInlineImages()
|
||||
protected function EmbedInlineImages(string &$sBody)
|
||||
{
|
||||
if ($this->m_aData['body']['mimeType'] == 'text/html')
|
||||
$oDOMDoc = new DOMDocument();
|
||||
$oDOMDoc->preserveWhitespace = true;
|
||||
@$oDOMDoc->loadHTML('<?xml encoding="UTF-8"?>'.$sBody); // For loading HTML chunks where the character set is not specified
|
||||
|
||||
$oXPath = new DOMXPath($oDOMDoc);
|
||||
$sXPath = '//img[@'.InlineImage::DOM_ATTR_ID.']';
|
||||
$oImagesList = $oXPath->query($sXPath);
|
||||
$oImagesContent = new \Laminas\Mime\Message();
|
||||
$aImagesParts = [];
|
||||
if ($oImagesList->length != 0)
|
||||
{
|
||||
$oDOMDoc = new DOMDocument();
|
||||
$oDOMDoc->preserveWhitespace = true;
|
||||
@$oDOMDoc->loadHTML('<?xml encoding="UTF-8"?>'.$this->m_aData['body']['body']); // For loading HTML chunks where the character set is not specified
|
||||
|
||||
$oXPath = new DOMXPath($oDOMDoc);
|
||||
$sXPath = '//img[@'.InlineImage::DOM_ATTR_ID.']';
|
||||
$oImagesList = $oXPath->query($sXPath);
|
||||
|
||||
if ($oImagesList->length != 0)
|
||||
foreach($oImagesList as $oImg)
|
||||
{
|
||||
foreach($oImagesList as $oImg)
|
||||
$iAttId = $oImg->getAttribute(InlineImage::DOM_ATTR_ID);
|
||||
$oAttachment = MetaModel::GetObject('InlineImage', $iAttId, false, true /* Allow All Data */);
|
||||
if ($oAttachment)
|
||||
{
|
||||
$iAttId = $oImg->getAttribute(InlineImage::DOM_ATTR_ID);
|
||||
$oAttachment = MetaModel::GetObject('InlineImage', $iAttId, false, true /* Allow All Data */);
|
||||
if ($oAttachment)
|
||||
$sImageSecret = $oImg->getAttribute('data-img-secret');
|
||||
$sAttachmentSecret = $oAttachment->Get('secret');
|
||||
if ($sImageSecret !== $sAttachmentSecret)
|
||||
{
|
||||
$sImageSecret = $oImg->getAttribute('data-img-secret');
|
||||
$sAttachmentSecret = $oAttachment->Get('secret');
|
||||
if ($sImageSecret !== $sAttachmentSecret)
|
||||
{
|
||||
// @see N°1921
|
||||
// If copying from another iTop we could get an IMG pointing to an InlineImage with wrong secret
|
||||
continue;
|
||||
}
|
||||
|
||||
$oDoc = $oAttachment->Get('contents');
|
||||
$oSwiftImage = new Swift_Image($oDoc->GetData(), $oDoc->GetFileName(), $oDoc->GetMimeType());
|
||||
$sCid = $this->m_oMessage->embed($oSwiftImage);
|
||||
$oImg->setAttribute('src', $sCid);
|
||||
// @see N°1921
|
||||
// If copying from another iTop we could get an IMG pointing to an InlineImage with wrong secret
|
||||
continue;
|
||||
}
|
||||
|
||||
$oDoc = $oAttachment->Get('contents');
|
||||
|
||||
$sCid = uniqid('', true);
|
||||
|
||||
$oNewAttachment = new Part($oDoc->GetData());
|
||||
$oNewAttachment->id = $sCid;
|
||||
$oNewAttachment->type = $oDoc->GetMimeType();
|
||||
$oNewAttachment->filename = $oDoc->GetFileName();
|
||||
$oNewAttachment->disposition = Mime::DISPOSITION_INLINE;
|
||||
$oNewAttachment->encoding = Mime::ENCODING_BASE64;
|
||||
|
||||
$oImagesContent->addPart($oNewAttachment);
|
||||
$oImg->setAttribute('src', 'cid:'.$sCid);
|
||||
$aImagesParts[] = $oNewAttachment;
|
||||
}
|
||||
}
|
||||
$sHtmlBody = $oDOMDoc->saveHTML();
|
||||
$this->m_oMessage->setBody($sHtmlBody, 'text/html', 'UTF-8');
|
||||
}
|
||||
$sBody = $oDOMDoc->saveHTML();
|
||||
return $aImagesParts;
|
||||
}
|
||||
|
||||
public function Send(&$aIssues, $bForceSynchronous = false, $oLog = null)
|
||||
@@ -313,7 +343,7 @@ class EMail
|
||||
break;
|
||||
|
||||
default:
|
||||
$oHeaders->addTextHeader($sKey, $sValue);
|
||||
$oHeaders->addHeaderLine($sKey, $sValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -325,46 +355,146 @@ class EMail
|
||||
// Note: Swift will add the angle brackets for you
|
||||
// so let's remove the angle brackets if present, for historical reasons
|
||||
$sId = str_replace(array('<', '>'), '', $sId);
|
||||
|
||||
$oMsgId = $this->m_oMessage->getHeaders()->get('Message-ID');
|
||||
$oMsgId->SetId($sId);
|
||||
|
||||
$this->m_oMessage->getHeaders()->addHeaderLine('Message-ID', $sId);
|
||||
}
|
||||
|
||||
|
||||
public function SetReferences($sReferences)
|
||||
{
|
||||
$this->AddToHeader('References', $sReferences);
|
||||
}
|
||||
|
||||
public function SetBody($sBody, $sMimeType = 'text/html', $sCustomStyles = null)
|
||||
/**
|
||||
* Set the "In-Reply-To" header to allow emails to group as a conversation in modern mail clients (GMail, Outlook 2016+, ...)
|
||||
*
|
||||
* @link https://en.wikipedia.org/wiki/Email#Header_fields
|
||||
*
|
||||
* @param string $sMessageId
|
||||
*
|
||||
* @since 3.0.1 N°4849
|
||||
*/
|
||||
public function SetInReplyTo(string $sMessageId)
|
||||
{
|
||||
if (($sMimeType === 'text/html') && ($sCustomStyles !== null))
|
||||
{
|
||||
$this->AddToHeader('In-Reply-To', $sMessageId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set current Email body and process inline images.
|
||||
*
|
||||
* @param $sBody
|
||||
* @param string $sMimeType
|
||||
* @param $sCustomStyles
|
||||
*
|
||||
* @return void
|
||||
* @throws \ArchivedObjectException
|
||||
* @throws \CoreException
|
||||
* @throws \Symfony\Component\CssSelector\Exception\SyntaxErrorException
|
||||
*/
|
||||
public function SetBody($sBody, string $sMimeType = Mime::TYPE_HTML, $sCustomStyles = null)
|
||||
{
|
||||
$oBody = new Laminas\Mime\Message();
|
||||
$aAdditionalParts = [];
|
||||
|
||||
if (($sMimeType === Mime::TYPE_HTML) && ($sCustomStyles !== null)) {
|
||||
$oDomDocument = CssInliner::fromHtml($sBody)->inlineCss($sCustomStyles)->getDomDocument();
|
||||
HtmlPruner::fromDomDocument($oDomDocument)->removeElementsWithDisplayNone();
|
||||
$sBody = CssToAttributeConverter::fromDomDocument($oDomDocument)->convertCssToVisualAttributes()->render(); // Adds html/body tags if not already present
|
||||
}
|
||||
$this->m_aData['body'] = array('body' => $sBody, 'mimeType' => $sMimeType);
|
||||
$this->m_oMessage->setBody($sBody, $sMimeType);
|
||||
|
||||
// We don't want these modifications in m_aData['body'], otherwise it'll ruin asynchronous mail as they go through this method twice
|
||||
if ($sMimeType === Mime::TYPE_HTML){
|
||||
$aAdditionalParts = $this->EmbedInlineImages($sBody);
|
||||
}
|
||||
|
||||
// Add body content to as a new part
|
||||
$oNewPart = new Part($sBody);
|
||||
$oNewPart->encoding = Mime::ENCODING_8BIT;
|
||||
$oNewPart->type = $sMimeType;
|
||||
$oBody->addPart($oNewPart);
|
||||
|
||||
// Add additional images as new body parts
|
||||
foreach ($aAdditionalParts as $oAdditionalPart) {
|
||||
$oBody->addPart($oAdditionalPart);
|
||||
}
|
||||
|
||||
if($oBody->isMultiPart()){
|
||||
$oContentTypeHeader = $this->m_oMessage->getHeaders();
|
||||
foreach ($oContentTypeHeader as $oHeader) {
|
||||
if (!$oHeader instanceof ContentType) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$oHeader->setType(Mime::MULTIPART_MIXED);
|
||||
$oHeader->addParameter('boundary', $oBody->getMime()->boundary());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
$this->m_oMessage->setBody($oBody);
|
||||
}
|
||||
|
||||
public function AddPart($sText, $sMimeType = 'text/html')
|
||||
/**
|
||||
* Add a new part to the existing body
|
||||
* @param $sText
|
||||
* @param string $sMimeType
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function AddPart($sText, string $sMimeType = Mime::TYPE_HTML)
|
||||
{
|
||||
if (!array_key_exists('parts', $this->m_aData))
|
||||
{
|
||||
$this->m_aData['parts'] = array();
|
||||
}
|
||||
$this->m_aData['parts'][] = array('text' => $sText, 'mimeType' => $sMimeType);
|
||||
$this->m_oMessage->addPart($sText, $sMimeType);
|
||||
$oNewPart = new Part($sText);
|
||||
$oNewPart->encoding = Mime::ENCODING_8BIT;
|
||||
$oNewPart->type = $sMimeType;
|
||||
$this->m_oMessage->getBody()->addPart($oNewPart);
|
||||
}
|
||||
|
||||
public function AddAttachment($data, $sFileName, $sMimeType)
|
||||
{
|
||||
$oBody = $this->m_oMessage->getBody();
|
||||
|
||||
if(!$oBody->isMultiPart()){
|
||||
$multipart_content = new Part($oBody->generateMessage());
|
||||
$multipart_content->setType($oBody->getParts()[0]->getType());
|
||||
$multipart_content->setBoundary($oBody->getMime()->boundary());
|
||||
|
||||
$oBody = new Laminas\Mime\Message();
|
||||
$oBody->addPart($multipart_content);
|
||||
}
|
||||
|
||||
if (!array_key_exists('attachments', $this->m_aData))
|
||||
{
|
||||
$this->m_aData['attachments'] = array();
|
||||
}
|
||||
$this->m_aData['attachments'][] = array('data' => base64_encode($data), 'filename' => $sFileName, 'mimeType' => $sMimeType);
|
||||
$this->m_oMessage->attach(Swift_Attachment::newInstance($data, $sFileName, $sMimeType));
|
||||
$oNewAttachment = new Part($data);
|
||||
$oNewAttachment->type = $sMimeType;
|
||||
$oNewAttachment->filename = $sFileName;
|
||||
$oNewAttachment->disposition = Mime::DISPOSITION_ATTACHMENT;
|
||||
$oNewAttachment->encoding = Mime::ENCODING_BASE64;
|
||||
|
||||
|
||||
$oBody->addPart($oNewAttachment);
|
||||
|
||||
if($oBody->isMultiPart()){
|
||||
$oContentTypeHeader = $this->m_oMessage->getHeaders();
|
||||
foreach ($oContentTypeHeader as $oHeader) {
|
||||
if (!$oHeader instanceof ContentType) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$oHeader->setType(Mime::MULTIPART_MIXED);
|
||||
$oHeader->addParameter('boundary', $oBody->getMime()->boundary());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
$this->m_oMessage->setBody($oBody);
|
||||
}
|
||||
|
||||
public function SetSubject($sSubject)
|
||||
@@ -409,7 +539,7 @@ class EMail
|
||||
public function GetRecipientTO($bAsString = false)
|
||||
{
|
||||
$aRes = $this->m_oMessage->getTo();
|
||||
if ($aRes === null)
|
||||
if ($aRes === null || $aRes->count() === 0)
|
||||
{
|
||||
// There is no "To" header field
|
||||
$aRes = array();
|
||||
@@ -417,8 +547,10 @@ class EMail
|
||||
if ($bAsString)
|
||||
{
|
||||
$aStrings = array();
|
||||
foreach ($aRes as $sEmail => $sName)
|
||||
foreach ($aRes as $oEmail)
|
||||
{
|
||||
$sName = $oEmail->getName();
|
||||
$sEmail = $oEmail->getEmail();
|
||||
if (is_null($sName))
|
||||
{
|
||||
$aStrings[] = $sEmail;
|
||||
@@ -483,77 +615,4 @@ class EMail
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/**
|
||||
* Extension to SwiftMailer: "debug" transport that pretends messages have been sent,
|
||||
* but just log them to a file.
|
||||
*
|
||||
* @package Swift
|
||||
* @author Denis Flaven
|
||||
*/
|
||||
class Swift_Transport_LogFileTransport extends Swift_Transport_NullTransport
|
||||
{
|
||||
protected $sLogFile;
|
||||
|
||||
/**
|
||||
* Sends the given message.
|
||||
*
|
||||
* @param Swift_Mime_Message $message
|
||||
* @param string[] $failedRecipients An array of failures by-reference
|
||||
*
|
||||
* @return int The number of sent emails
|
||||
*/
|
||||
public function send(Swift_Mime_Message $message, &$failedRecipients = null)
|
||||
{
|
||||
$hFile = @fopen($this->sLogFile, 'a');
|
||||
if ($hFile)
|
||||
{
|
||||
$sTxt = "================== ".date('Y-m-d H:i:s')." ==================\n";
|
||||
$sTxt .= $message->toString()."\n";
|
||||
|
||||
@fwrite($hFile, $sTxt);
|
||||
@fclose($hFile);
|
||||
}
|
||||
|
||||
return parent::send($message, $failedRecipients);
|
||||
}
|
||||
|
||||
public function setLogFile($sFilename)
|
||||
{
|
||||
$this->sLogFile = $sFilename;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Pretends messages have been sent, but just log them to a file.
|
||||
*
|
||||
* @package Swift
|
||||
* @author Denis Flaven
|
||||
*/
|
||||
class Swift_LogFileTransport extends Swift_Transport_LogFileTransport
|
||||
{
|
||||
/**
|
||||
* Create a new LogFileTransport.
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
call_user_func_array(
|
||||
array($this, 'Swift_Transport_LogFileTransport::__construct'),
|
||||
Swift_DependencyContainer::getInstance()
|
||||
->createDependenciesFor('transport.null')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new LogFileTransport instance.
|
||||
*
|
||||
* @return Swift_LogFileTransport
|
||||
*/
|
||||
public static function newInstance()
|
||||
{
|
||||
return new self();
|
||||
}
|
||||
}
|
||||
@@ -111,16 +111,15 @@ class ExcelBulkExport extends TabularBulkExport
|
||||
|
||||
$sFormatInput = '<input type="text" size="15" name="date_format" id="excel_custom_date_time_format" title="" value="'.htmlentities($sDateTimeFormat, ENT_QUOTES, 'UTF-8').'"/>';
|
||||
$oRadioCustom = InputUIBlockFactory::MakeForInputWithLabel(Dict::Format('Core:BulkExport:DateTimeFormatCustom_Format', $sFormatInput), "excel_date_format_radio", "custom", "excel_date_time_format_custom", "radio");
|
||||
$oRadioCustom->SetDescription(Dict::S('UI:CSVImport:CustomDateTimeFormatTooltip'));
|
||||
$oRadioCustom->GetInput()->SetIsChecked($sDateTimeFormat !== (string)AttributeDateTime::GetFormat());
|
||||
$oRadioCustom->SetBeforeInput(false);
|
||||
$oRadioCustom->GetInput()->AddCSSClass('ibo-input-checkbox');
|
||||
$oFieldSetDate->AddSubBlock($oRadioCustom);
|
||||
|
||||
|
||||
$sJSTooltip = json_encode('<div class="date_format_tooltip">'.Dict::S('UI:CSVImport:CustomDateTimeFormatTooltip').'</div>');
|
||||
$oP->add_ready_script(
|
||||
<<<EOF
|
||||
$('#excel_custom_date_time_format').tooltip({content: function() { return $sJSTooltip; } });
|
||||
$('#form_part_xlsx_options').on('preview_updated', function() { FormatDatesInPreview('excel', 'xlsx'); });
|
||||
$('#excel_date_time_format_default').on('click', function() { FormatDatesInPreview('excel', 'xlsx'); });
|
||||
$('#excel_date_time_format_custom').on('click', function() { FormatDatesInPreview('excel', 'xlsx'); });
|
||||
|
||||
@@ -542,14 +542,32 @@ class FileLog
|
||||
*/
|
||||
class LogChannels
|
||||
{
|
||||
public const CLI = 'CLI';
|
||||
public const CONSOLE = 'console';
|
||||
public const DEADLOCK = 'DeadLock';
|
||||
public const INLINE_IMAGE = 'InlineImage';
|
||||
public const PORTAL = 'portal';
|
||||
public const CMDB_SOURCE = 'cmdbsource';
|
||||
public const CORE = 'core';
|
||||
public const APC = 'apc';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
* @since 3.0.1 N°4849
|
||||
*/
|
||||
public const NOTIFICATIONS = 'notifications';
|
||||
|
||||
public const CLI = 'CLI';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
* @since 2.7.7 N°4558 use this new channel when logging DB transactions
|
||||
* @since 3.0.0 logs info in CMDBSource (see commit a117906f)
|
||||
*/
|
||||
public const CMDB_SOURCE = 'cmdbsource';
|
||||
|
||||
public const CONSOLE = 'console';
|
||||
|
||||
public const CORE = 'core';
|
||||
|
||||
public const DEADLOCK = 'DeadLock';
|
||||
|
||||
public const INLINE_IMAGE = 'InlineImage';
|
||||
|
||||
public const PORTAL = 'portal';
|
||||
}
|
||||
|
||||
|
||||
@@ -992,6 +1010,11 @@ class DeadLockLog extends LogAPI
|
||||
class DeprecatedCallsLog extends LogAPI
|
||||
{
|
||||
public const ENUM_CHANNEL_PHP_METHOD = 'deprecated-php-method';
|
||||
/**
|
||||
* @var string
|
||||
* @since 3.1.0
|
||||
*/
|
||||
public const ENUM_CHANNEL_PHP_ENDPOINT = 'deprecated-php-endpoint';
|
||||
public const ENUM_CHANNEL_PHP_LIBMETHOD = 'deprecated-php-libmethod';
|
||||
public const ENUM_CHANNEL_FILE = 'deprecated-file';
|
||||
public const CHANNEL_DEFAULT = self::ENUM_CHANNEL_PHP_METHOD;
|
||||
@@ -1137,7 +1160,12 @@ class DeprecatedCallsLog extends LogAPI
|
||||
*/
|
||||
public static function NotifyDeprecatedFile(?string $sAdditionalMessage = null): void
|
||||
{
|
||||
if (!static::IsLogLevelEnabled(self::LEVEL_WARNING, self::ENUM_CHANNEL_FILE)) {
|
||||
try {
|
||||
if (!static::IsLogLevelEnabled(self::LEVEL_WARNING, self::ENUM_CHANNEL_FILE)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
catch (ConfigException $e) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1199,6 +1227,35 @@ class DeprecatedCallsLog extends LogAPI
|
||||
static::Warning($sMessage, self::ENUM_CHANNEL_PHP_METHOD);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string|null $sAdditionalMessage
|
||||
* @since 3.1.0
|
||||
*/
|
||||
public static function NotifyDeprecatedPhpEndpoint(?string $sAdditionalMessage = null): void
|
||||
{
|
||||
try {
|
||||
if (!static::IsLogLevelEnabled(self::LEVEL_WARNING, self::ENUM_CHANNEL_PHP_ENDPOINT)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
catch (ConfigException $e) {
|
||||
return;
|
||||
}
|
||||
|
||||
$aStack = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 3);
|
||||
$iStackDeprecatedMethodLevel = 0; // level 0 = current method, level 1 = method containing the `NotifyDeprecatedPhpMethod` call
|
||||
$sDeprecatedUrl = $_SERVER['REQUEST_URI'];
|
||||
$sCallerFile = $aStack[$iStackDeprecatedMethodLevel]['file'];
|
||||
$sCallerLine = $aStack[$iStackDeprecatedMethodLevel]['line'];
|
||||
$sMessage = "Call to endpoint {$sDeprecatedUrl} in {$sCallerFile}#L{$sCallerLine}";
|
||||
|
||||
if (!is_null($sAdditionalMessage)) {
|
||||
$sMessage .= ' : '.$sAdditionalMessage;
|
||||
}
|
||||
|
||||
static::Warning($sMessage, self::ENUM_CHANNEL_PHP_ENDPOINT);
|
||||
}
|
||||
|
||||
public static function Log($sLevel, $sMessage, $sChannel = null, $aContext = array()): void
|
||||
{
|
||||
if (true === utils::IsDevelopmentEnvironment()) {
|
||||
|
||||
@@ -655,7 +655,7 @@ abstract class MetaModel
|
||||
* @param string $sRuleId
|
||||
*
|
||||
* @throws \CoreException
|
||||
* @since 2.6.1 N°1918 (sous les pavés, la plage) initialize in 'root_class' property the class that has the first
|
||||
* @since 2.6.1 N°1968 (sous les pavés, la plage) initialize in 'root_class' property the class that has the first
|
||||
* definition of the rule in the hierarchy
|
||||
*/
|
||||
private static function SetUniquenessRuleRootClass($sRootClass, $sRuleId)
|
||||
@@ -7145,20 +7145,28 @@ abstract class MetaModel
|
||||
/**
|
||||
* @param string $sClass
|
||||
* @param string $sAttCode
|
||||
* @param $value
|
||||
* @param mixed $value
|
||||
* @param bool $bMustBeFoundUnique
|
||||
* @param bool $bAllowAllData
|
||||
*
|
||||
* @return \DBObject if $bMustBeFoundUnique=true and no object or multiple objects found will throw a CoreException
|
||||
* else will return null
|
||||
*
|
||||
* @return \DBObject
|
||||
* @throws \CoreException
|
||||
* @throws \Exception
|
||||
* @throws \CoreUnexpectedValue
|
||||
* @throws \MissingQueryArgument
|
||||
* @throws \MySQLException
|
||||
* @throws \MySQLHasGoneAwayException
|
||||
*
|
||||
* @since 2.7.7 Add new $bAllowAllData parameter
|
||||
*/
|
||||
public static function GetObjectByColumn($sClass, $sAttCode, $value, $bMustBeFoundUnique = true)
|
||||
public static function GetObjectByColumn($sClass, $sAttCode, $value, $bMustBeFoundUnique = true, $bAllowAllData = false)
|
||||
{
|
||||
if (!isset(self::$m_aCacheObjectByColumn[$sClass][$sAttCode][$value]))
|
||||
{
|
||||
if (!isset(self::$m_aCacheObjectByColumn[$sClass][$sAttCode][$value])) {
|
||||
self::_check_subclass($sClass);
|
||||
|
||||
$oObjSearch = new DBObjectSearch($sClass);
|
||||
$oObjSearch->AllowAllData($bAllowAllData);
|
||||
$oObjSearch->AddCondition($sAttCode, $value, '=');
|
||||
$oSet = new DBObjectSet($oObjSearch);
|
||||
if ($oSet->Count() == 1)
|
||||
|
||||
@@ -31,13 +31,13 @@ class iTopOwnershipToken extends DBObject
|
||||
{
|
||||
$aParams = array
|
||||
(
|
||||
'category' => 'application',
|
||||
'key_type' => 'autoincrement',
|
||||
'name_attcode' => array('obj_class', 'obj_key'),
|
||||
'state_attcode' => '',
|
||||
'reconc_keys' => array(''),
|
||||
'db_table' => 'priv_ownership_token',
|
||||
'db_key_field' => 'id',
|
||||
'category' => '',
|
||||
'key_type' => 'autoincrement',
|
||||
'name_attcode' => array('obj_class', 'obj_key'),
|
||||
'state_attcode' => '',
|
||||
'reconc_keys' => array(''),
|
||||
'db_table' => 'priv_ownership_token',
|
||||
'db_key_field' => 'id',
|
||||
'db_finalclass_field' => '',
|
||||
);
|
||||
MetaModel::Init_Params($aParams);
|
||||
|
||||
@@ -95,15 +95,14 @@ class PDFBulkExport extends HTMLBulkExport
|
||||
|
||||
$sFormatInput = '<input type="text" size="15" name="date_format" id="pdf_custom_date_time_format" title="" value="'.htmlentities($sDateTimeFormat, ENT_QUOTES, 'UTF-8').'"/>';
|
||||
$oRadioCustom = InputUIBlockFactory::MakeForInputWithLabel(Dict::Format('Core:BulkExport:DateTimeFormatCustom_Format', $sFormatInput), "pdf_date_format_radio", "custom", "pdf_date_time_format_custom", "radio");
|
||||
$oRadioCustom->SetDescription(Dict::S('UI:CSVImport:CustomDateTimeFormatTooltip'));
|
||||
$oRadioCustom->GetInput()->SetIsChecked($sDateTimeFormat !== (string)AttributeDateTime::GetFormat());
|
||||
$oRadioCustom->SetBeforeInput(false);
|
||||
$oRadioCustom->GetInput()->AddCSSClass('ibo-input-checkbox');
|
||||
$oFieldSetDate->AddSubBlock($oRadioCustom);
|
||||
|
||||
$sJSTooltip = json_encode('<div id="date_format_tooltip">'.Dict::S('UI:CSVImport:CustomDateTimeFormatTooltip').'</div>');
|
||||
$oP->add_ready_script(
|
||||
<<<EOF
|
||||
$('#pdf_custom_date_time_format').tooltip({content: function() { return $sJSTooltip; } });
|
||||
$('#form_part_pdf_options').on('preview_updated', function() { FormatDatesInPreview('pdf', 'html'); });
|
||||
$('#pdf_date_time_format_default').on('click', function() { FormatDatesInPreview('pdf', 'html'); });
|
||||
$('#pdf_date_time_format_custom').on('click', function() { FormatDatesInPreview('pdf', 'html'); });
|
||||
|
||||
@@ -135,6 +135,7 @@ class ObjectResult
|
||||
*/
|
||||
class RestResultWithObjects extends RestResult
|
||||
{
|
||||
/** @var array "DBObject_class:DBObject_key" as key, {@see \ObjectResult} as value */
|
||||
public $objects;
|
||||
|
||||
/**
|
||||
|
||||
@@ -84,15 +84,14 @@ class SpreadsheetBulkExport extends TabularBulkExport
|
||||
|
||||
$sFormatInput = '<input type="text" size="15" name="date_format" id="spreadsheet_custom_date_time_format" title="" value="'.htmlentities($sDateTimeFormat, ENT_QUOTES, 'UTF-8').'"/>';
|
||||
$oRadioCustom = InputUIBlockFactory::MakeForInputWithLabel(Dict::Format('Core:BulkExport:DateTimeFormatCustom_Format', $sFormatInput), "spreadsheet_date_format_radio", "custom", "spreadsheet_date_time_format_custom", "radio");
|
||||
$oRadioCustom->SetDescription(Dict::S('UI:CSVImport:CustomDateTimeFormatTooltip'));
|
||||
$oRadioCustom->GetInput()->SetIsChecked($sDateTimeFormat !== (string)AttributeDateTime::GetFormat());
|
||||
$oRadioCustom->GetInput()->AddCSSClass('ibo-input-checkbox');
|
||||
$oRadioCustom->SetBeforeInput(false);
|
||||
$oFieldSetDate->AddSubBlock($oRadioCustom);
|
||||
|
||||
$sJSTooltip = json_encode('<div class="date_format_tooltip">'.Dict::S('UI:CSVImport:CustomDateTimeFormatTooltip').'</div>');
|
||||
$oP->add_ready_script(
|
||||
<<<EOF
|
||||
$('#spreadsheet_custom_date_time_format').tooltip({content: function() { return $sJSTooltip; } });
|
||||
$('#form_part_spreadsheet_options').on('preview_updated', function() { FormatDatesInPreview('spreadsheet', 'spreadsheet'); });
|
||||
$('#spreadsheet_date_time_format_default').on('click', function() { FormatDatesInPreview('spreadsheet', 'spreadsheet'); });
|
||||
$('#spreadsheet_date_time_format_custom').on('click', function() { FormatDatesInPreview('spreadsheet', 'spreadsheet'); });
|
||||
|
||||
@@ -494,7 +494,17 @@ class SQLObjectQuery extends SQLQuery
|
||||
}
|
||||
}
|
||||
|
||||
private function PrepareSingleTable(SQLObjectQuery $oRootQuery, &$aFrom, $sCallerAlias = '', $aJoinData)
|
||||
/**
|
||||
* @param \SQLObjectQuery $oRootQuery
|
||||
* @param $aFrom
|
||||
* @param $sCallerAlias
|
||||
* @param $aJoinData
|
||||
*
|
||||
* @return string
|
||||
*
|
||||
* @since 2.7.7 3.0.1 3.1.0 N°3129 Remove default value for $sCallerAlias for PHP 8.0 compat (Private method with only 2 calls in the class, both providing the optional parameter)
|
||||
*/
|
||||
private function PrepareSingleTable(SQLObjectQuery $oRootQuery, &$aFrom, $sCallerAlias, $aJoinData)
|
||||
{
|
||||
$aTranslationTable[$this->m_sTable]['*'] = $this->m_sTableAlias;
|
||||
$sJoinCond = '';
|
||||
@@ -613,6 +623,7 @@ class SQLObjectQuery extends SQLQuery
|
||||
$aTempFrom = array(); // temporary subset of 'from' specs, to be grouped in the final query
|
||||
foreach ($this->m_aJoinSelects as $aJoinData)
|
||||
{
|
||||
/** @var \SQLObjectQuery $oRightSelect */
|
||||
$oRightSelect = $aJoinData["select"];
|
||||
|
||||
$oRightSelect->PrepareSingleTable($oRootQuery, $aTempFrom, $this->m_sTableAlias, $aJoinData);
|
||||
|
||||
@@ -4,4 +4,5 @@
|
||||
*/
|
||||
|
||||
@import "collapsible-section-with-blocks";
|
||||
@import "collapsible-section-within-caselog-list";
|
||||
@import "collapsible-section-within-caselog-list";
|
||||
@import "collapsible-section-within-alert";
|
||||
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
* @copyright Copyright (C) 2010-2022 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
/* SCSS variables */
|
||||
$ibo-collapsible-section-within-alert--body--padding: $ibo-spacing-300 !default;
|
||||
$ibo-collapsible-section-within-alert--body--text-color: $ibo-color-grey-900 !default;
|
||||
|
||||
.ibo-alert--body {
|
||||
.ibo-collapsible-section {
|
||||
.ibo-collapsible-section--header .ibo-collapsible-section--title,
|
||||
.ibo-collapsible-section--body {
|
||||
@extend %ibo-font-size-150;
|
||||
}
|
||||
|
||||
.ibo-collapsible-section--body {
|
||||
color: $ibo-collapsible-section-within-alert--body--text-color;
|
||||
padding: $ibo-collapsible-section-within-alert--body--padding;
|
||||
}
|
||||
}
|
||||
> * + .ibo-collapsible-section {
|
||||
margin-top: 8px;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,4 +3,5 @@
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
@import "field-with-field";
|
||||
@import "field-with-field";
|
||||
@import "field-with-fieldset";
|
||||
@@ -0,0 +1,10 @@
|
||||
/*
|
||||
* @copyright Copyright (C) 2010-2021 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
$ibo-field--spacing-top--with-fieldset: $ibo-spacing-700 !default;
|
||||
|
||||
.ibo-fieldset + .ibo-field {
|
||||
margin-top: $ibo-field--spacing-top--with-fieldset;
|
||||
}
|
||||
@@ -3,5 +3,6 @@
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
@import "fieldset-with-field";
|
||||
@import "fieldset-with-fieldset";
|
||||
@import "fieldset-with-multicolumn";
|
||||
@@ -0,0 +1,10 @@
|
||||
/*
|
||||
* @copyright Copyright (C) 2010-2021 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
$ibo-fieldset--spacing-top--with-field: $ibo-spacing-700 !default;
|
||||
|
||||
.ibo-field + .ibo-fieldset:not(.ibo-column) {
|
||||
margin-top: $ibo-fieldset--spacing-top--with-field;
|
||||
}
|
||||
@@ -3,8 +3,8 @@
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
$ibo-fieldset--spacing-left--with-fieldset: $ibo-spacing-800 !default;
|
||||
$ibo-fieldset--spacing-top--with-fieldset: $ibo-spacing-800 !default;
|
||||
|
||||
.ibo-fieldset + .ibo-fieldset:not(.ibo-column) {
|
||||
margin-top: $ibo-fieldset--spacing-left--with-fieldset;
|
||||
margin-top: $ibo-fieldset--spacing-top--with-fieldset;
|
||||
}
|
||||
@@ -3,9 +3,9 @@
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
$ibo-fieldset--spacing-left--with-multicolumn: $ibo-spacing-800 !default;
|
||||
$ibo-fieldset--spacing-top--with-multicolumn: $ibo-spacing-800 !default;
|
||||
|
||||
|
||||
.ibo-multi-column + .ibo-fieldset {
|
||||
margin-top: $ibo-fieldset--spacing-left--with-multicolumn;
|
||||
margin-top: $ibo-fieldset--spacing-top--with-multicolumn;
|
||||
}
|
||||
|
||||
@@ -11,4 +11,18 @@ $ibo-input--spacing-left--with-label: $ibo-spacing-300 !default;
|
||||
select + label, label + select, label > select,
|
||||
input + label, label + input, label > input {
|
||||
margin-left: $ibo-input--spacing-left--with-label;
|
||||
}
|
||||
|
||||
.ibo-input-with-label--label {
|
||||
&.ibo-has-description {
|
||||
&::after {
|
||||
content: $ibo-field--label--description--content;
|
||||
padding-left: $ibo-field--label--description--padding-left;
|
||||
vertical-align: top;
|
||||
|
||||
cursor: pointer;
|
||||
color: $ibo-field--label--description--color;
|
||||
@extend %ibo-font-ral-bol-50;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -479,6 +479,22 @@ $ibo-button-colors: (
|
||||
&.ibo-action-button {
|
||||
float: right;
|
||||
}
|
||||
|
||||
.ibo-button--loading-icon {
|
||||
display: none;
|
||||
}
|
||||
|
||||
&.ibo-is-loading {
|
||||
.ibo-button--icon{
|
||||
display: none;
|
||||
}
|
||||
.ibo-button--loading-icon {
|
||||
display: inline-block;
|
||||
&+ .ibo-button--label{
|
||||
margin-left: $ibo-button--label--margin-left;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.ibo-button--label {
|
||||
|
||||
@@ -122,6 +122,7 @@ $ibo-fieldsorter--selected--background-color: $ibo-color-blue-200 !default;
|
||||
}
|
||||
}
|
||||
|
||||
.ibo-datatable--selected-count{
|
||||
.ibo-datatable--selected-count, .ibo-datatable--result-count{
|
||||
padding-right: 0.2em;
|
||||
padding-left: 0.1em;
|
||||
}
|
||||
@@ -345,6 +345,7 @@ $ibo-search-results-area--datatable-scrollhead--border--is-sticking: $ibo-search
|
||||
/* Form group (operators) is displayed only when the criteria is toggled to opened state */
|
||||
display: none;
|
||||
max-width: 450px;
|
||||
width: max-content;
|
||||
max-height: 520px;
|
||||
overflow-x: auto;
|
||||
overflow-y: hidden;
|
||||
@@ -374,7 +375,7 @@ $ibo-search-results-area--datatable-scrollhead--border--is-sticking: $ibo-search
|
||||
}
|
||||
|
||||
.sfc_op_name {
|
||||
width: 90px;
|
||||
width: 96px;
|
||||
}
|
||||
|
||||
.sfc_op_content {
|
||||
|
||||
@@ -8,6 +8,8 @@ $ibo-title--padding-y: $ibo-spacing-400 !default;
|
||||
$ibo-title--padding-x: $ibo-spacing-0 !default;
|
||||
|
||||
$ibo-title--icon--size: 90px !default;
|
||||
$ibo-title--icon--size-2: 80px !default;
|
||||
$ibo-title--icon--size-3: 70px !default;
|
||||
|
||||
$ibo-title--icon-background--size--must-contain: contain !default;
|
||||
$ibo-title--icon-background--size--must-cover: cover !default;
|
||||
@@ -29,6 +31,18 @@ $ibo-title--icon-background--size--must-zoomout: 66.67% !default;
|
||||
min-height: $ibo-title--icon--size;
|
||||
overflow: hidden;
|
||||
}
|
||||
.ibo-title--icon > .ibo-title--icon-level-2{
|
||||
width: $ibo-title--icon--size-2;
|
||||
height: $ibo-title--icon--size-2;
|
||||
min-width: $ibo-title--icon--size-2;
|
||||
min-height: $ibo-title--icon--size-2;
|
||||
}
|
||||
.ibo-title--icon > .ibo-title--icon-level-3{
|
||||
width: $ibo-title--icon--size-3;
|
||||
height: $ibo-title--icon--size-3;
|
||||
min-width: $ibo-title--icon--size-3;
|
||||
min-height: $ibo-title--icon--size-3;
|
||||
}
|
||||
|
||||
.ibo-title--icon-background {
|
||||
width: 100%;
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
$ibo-input-image--image-view--min-height: 96px !default;
|
||||
$ibo-input-image--image-view--background-color: $ibo-color-grey-200 !default;
|
||||
$ibo-input-image--image-view--border-radius: $ibo-border-radius-500 !default;
|
||||
|
||||
@@ -18,6 +19,7 @@ $ibo-input-image--edit-buttons--elements-spacing: $ibo-input-image--edit-buttons
|
||||
.ibo-input-image--image-view {
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
min-height: $ibo-input-image--image-view--min-height;
|
||||
background-color: $ibo-input-image--image-view--background-color;
|
||||
border-radius: $ibo-input-image--image-view--border-radius;
|
||||
@extend %ibo-fully-centered-content;
|
||||
|
||||
@@ -64,6 +64,8 @@ $ibo-input-select--autocomplete-item-image--border: 1px solid $ibo-color-grey-60
|
||||
color: inherit;
|
||||
border-color: $ibo-color-white-100;
|
||||
padding-left: $ibo-input-select--padding-x;
|
||||
|
||||
@extend %ibo-font-ral-nor-150;
|
||||
}
|
||||
|
||||
> [data-value] {
|
||||
@@ -102,6 +104,13 @@ $ibo-input-select--autocomplete-item-image--border: 1px solid $ibo-color-grey-60
|
||||
> input {
|
||||
background-color: unset;
|
||||
border: unset;
|
||||
&:focus{
|
||||
outline: none !important; /* Overwrite browsers default focus outline */
|
||||
}
|
||||
}
|
||||
|
||||
&.input-active{
|
||||
border: 1px solid $ibo-input--focus--border-color;
|
||||
}
|
||||
}
|
||||
.ibo-input-select-wrapper{
|
||||
|
||||
@@ -22,7 +22,6 @@ $ibo-input--placeholder--color: $ibo-color-grey-600 !default;
|
||||
$ibo-input--disabled--background-color: $ibo-color-grey-300 !default;
|
||||
$ibo-input--placeholder--color: $ibo-color-grey-700 !default;
|
||||
|
||||
$ibo-input-wrapper--is-error--background-color: $ibo-color-red-200 !default;
|
||||
$ibo-input-wrapper--is-error--border-color: $ibo-color-red-600 !default;
|
||||
$ibo-field-validation: $ibo-color-red-700 !default;
|
||||
|
||||
@@ -38,6 +37,8 @@ $ibo-input--margin-x: $ibo-spacing-200 !default;
|
||||
border: 1px solid $ibo-input--border-color;
|
||||
border-radius: $ibo-input--border-radius;
|
||||
|
||||
@extend %ibo-font-ral-nor-150;
|
||||
|
||||
&:focus{
|
||||
border: 1px solid $ibo-input--focus--border-color;
|
||||
}
|
||||
@@ -55,7 +56,6 @@ textarea.ibo-input{
|
||||
.ibo-input-wrapper.is-error, .ibo-input-field-wrapper.is-error {
|
||||
.ibo-input, .ibo-input-vanilla, .cke, textarea {
|
||||
border: 1px solid $ibo-input-wrapper--is-error--border-color;
|
||||
background-color: $ibo-input-wrapper--is-error--background-color;
|
||||
}
|
||||
.ibo-input-vanilla input{
|
||||
border: 0;
|
||||
|
||||
@@ -14,7 +14,7 @@ $ibo-navigation-menu--body--background-color: $ibo-color-blue-grey-900 !default;
|
||||
$ibo-navigation-menu--body--text-color: $ibo-color-grey-300 !default;
|
||||
|
||||
$ibo-navigation-menu--top-part--height: 120px !default;
|
||||
$ibo-navigation-menu--top-part--padding-y: $ibo-navigation-menu--body--padding-y !default;
|
||||
$ibo-navigation-menu--top-part--padding-y: $ibo-spacing-400 !default;
|
||||
$ibo-navigation-menu--top-part--padding-x: $ibo-navigation-menu--body--padding-x !default;
|
||||
$ibo-navigation-menu--top-part--elements-spacing: 20px !default;
|
||||
|
||||
@@ -70,13 +70,13 @@ $ibo-navigation-menu--square-company-logo--width: 38px !default;
|
||||
$ibo-navigation-menu--square-company-logo--height: 38px !default;
|
||||
$ibo-navigation-menu--square-company-logo--margin-top: $ibo-spacing-0 !default;
|
||||
$ibo-navigation-menu--square-company-logo--margin-x: -5px !default;
|
||||
$ibo-navigation-menu--square-company-logo--margin-bottom: $ibo-navigation-menu--body--padding-y * 2 !default;
|
||||
$ibo-navigation-menu--square-company-logo--margin-bottom: ($ibo-navigation-menu--body--padding-y * 2) + 12px !default; /* +12px to keep burger & menu groups icons align in both expanded and collapsed mode */
|
||||
|
||||
$ibo-navigation-menu--full-company-logo--width: $ibo-navigation-menu--body--width-expanded !default;
|
||||
$ibo-navigation-menu--full-company-logo--height: 70px !default;
|
||||
$ibo-navigation-menu--full-company-logo--margin-top: $ibo-spacing-0 !default;
|
||||
$ibo-navigation-menu--full-company-logo--margin-right: $ibo-spacing-0 !default;
|
||||
$ibo-navigation-menu--full-company-logo--margin-bottom: $ibo-spacing-0 !default;
|
||||
$ibo-navigation-menu--full-company-logo--margin-bottom: $ibo-spacing-400 !default;
|
||||
$ibo-navigation-menu--full-company-logo--margin-left: -$ibo-navigation-menu--body--padding-y !default;
|
||||
$ibo-navigation-menu--full-company-logo--image--margin-x: auto !default;
|
||||
$ibo-navigation-menu--full-company-logo--image--margin-y: $ibo-spacing-0 !default;
|
||||
|
||||
@@ -41,6 +41,12 @@ $ibo-activity-panel--tab-title-decoration--border-radius: $ibo-border-radius-300
|
||||
|
||||
$ibo-activity-panel--tab-title-draft-indicator--margin-x: $ibo-activity-panel--tab-title-decoration--margin-right !default;
|
||||
|
||||
$ibo-activity-panel--tab-title-messages-count--margin-left: $ibo-activity-panel--tab-title-draft-indicator--margin-x !default;
|
||||
$ibo-activity-panel--tab-title-messages-count--background-color: $ibo-color-grey-200 !default;
|
||||
$ibo-activity-panel--tab-title-messages-count--padding-x: $ibo-spacing-200 !default;
|
||||
$ibo-activity-panel--tab-title-messages-count--padding-y: $ibo-spacing-0 !default;
|
||||
$ibo-activity-panel--tab-title-messages-count--border-radius: $ibo-border-radius-300 !default;
|
||||
|
||||
$ibo-activity-panel--tab-title-text--max-width: 100px !default;
|
||||
|
||||
/* - Tab toolbar */
|
||||
@@ -180,6 +186,9 @@ $ibo-activity-panel--open-icon--margin-left: 0.75rem !default;
|
||||
.ibo-activity-panel--tab-title{
|
||||
background-color: $ibo-activity-panel--tab-title--is-active--background-color;
|
||||
}
|
||||
.ibo-activity-panel--tab-title-messages-count{
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
&.ibo-is-draft{
|
||||
.ibo-activity-panel--tab-title-draft-indicator{
|
||||
@@ -213,6 +222,17 @@ $ibo-activity-panel--open-icon--margin-left: 0.75rem !default;
|
||||
border-radius: $ibo-activity-panel--tab-title-decoration--border-radius;
|
||||
@extend %ibo-depression-100;
|
||||
}
|
||||
.ibo-activity-panel--tab-title-messages-count{
|
||||
display: inline-block;
|
||||
margin-left: $ibo-activity-panel--tab-title-messages-count--margin-left;
|
||||
background-color: $ibo-activity-panel--tab-title-messages-count--background-color;
|
||||
padding: $ibo-activity-panel--tab-title-messages-count--padding-y $ibo-activity-panel--tab-title-messages-count--padding-x;
|
||||
border-radius: $ibo-activity-panel--tab-title-messages-count--border-radius;
|
||||
|
||||
&[data-messages-count="0"]{
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
.ibo-activity-panel--tab-title-draft-indicator{
|
||||
display: none;
|
||||
margin-left: $ibo-activity-panel--tab-title-draft-indicator--margin-x;
|
||||
|
||||
20
css/backoffice/pages/_about.scss
Normal file
20
css/backoffice/pages/_about.scss
Normal file
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
* @copyright Copyright (C) 2010-2021 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
$ibo-about-box--top-part--children--padding-y: $ibo-spacing-500 !default;
|
||||
$ibo-about-box--top-part--children--padding-x: $ibo-spacing-400 !default;
|
||||
$ibo-about-box--top-part--children--margin-y: auto !default;
|
||||
$ibo-about-box--top-part--children--margin-x: auto !default;
|
||||
$ibo-about-box--top-part--children--width: 50% !default;
|
||||
|
||||
.ibo-about-box--top-part{
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-content: center;
|
||||
> div{
|
||||
padding: $ibo-about-box--top-part--children--padding-y $ibo-about-box--top-part--children--padding-x;
|
||||
margin: $ibo-about-box--top-part--children--margin-y $ibo-about-box--top-part--children--margin-x;
|
||||
width: $ibo-about-box--top-part--children--width;
|
||||
}
|
||||
}
|
||||
@@ -3,6 +3,7 @@
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
@import "about";
|
||||
@import "base";
|
||||
@import "preferences";
|
||||
@import "attachments";
|
||||
@@ -12,4 +13,5 @@
|
||||
@import "datamodel-viewer";
|
||||
@import "csv-import";
|
||||
@import "global-search";
|
||||
@import "run-query";
|
||||
@import "welcome-popup";
|
||||
10
css/backoffice/pages/_run-query.scss
Normal file
10
css/backoffice/pages/_run-query.scss
Normal file
@@ -0,0 +1,10 @@
|
||||
/*
|
||||
* @copyright Copyright (C) 2010-2021 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
$ibo-run-query--highlight--background-color: $ibo-color-primary-300 !default;
|
||||
|
||||
.ibo-run-query--highlight{
|
||||
background-color: $ibo-run-query--highlight--background-color;
|
||||
}
|
||||
@@ -134,6 +134,9 @@ body.ibo-has-fullscreen-descendant {
|
||||
@extend %ibo-font-code-150;
|
||||
}
|
||||
|
||||
.ibo-add-margin-top-250{
|
||||
margin-top: $ibo-spacing-400;
|
||||
}
|
||||
/*
|
||||
* A single class to handle WYSIWYG generated content, where only HTML tags are available
|
||||
* See https://bulma.io/documentation/elements/content/
|
||||
@@ -158,7 +161,7 @@ body.ibo-has-fullscreen-descendant {
|
||||
|
||||
/* Preserve original text color in code blocks, except for the Highlight.js blocks which have their own colors */
|
||||
& > code,
|
||||
:not(pre.hljs) code {
|
||||
code:not(.hljs) {
|
||||
color: inherit;
|
||||
}
|
||||
}
|
||||
|
||||
6
css/backoffice/vendors/_ckeditor.scss
vendored
6
css/backoffice/vendors/_ckeditor.scss
vendored
@@ -49,7 +49,11 @@ $ibo-vendors-ckeditor--autocomplete-item-title--text-color: #3A3A3A !default;
|
||||
padding: $ibo-vendors-highlightjs--padding !important;
|
||||
box-shadow: 0 0px 3px 2px inset rgba(0, 0, 0, 0.4);
|
||||
border-radius: $ibo-vendors-highlightjs--border-radius;
|
||||
white-space: pre-line;
|
||||
white-space: pre-wrap;
|
||||
}
|
||||
|
||||
.ibo-hljs-container{
|
||||
padding: 0 !important;
|
||||
}
|
||||
|
||||
/* Mentions in caselogs */
|
||||
|
||||
@@ -15,6 +15,9 @@
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
*/
|
||||
|
||||
// Beware the version number MUST be enclosed with quotes otherwise v2.3.0 becomes v2 0.3 .0
|
||||
$version: "v2.7.7";
|
||||
$approot-relative: "../../../../" !default; // relative to env-***/branding/themes/***/main.css
|
||||
|
||||
// Base colors
|
||||
|
||||
@@ -2582,6 +2582,12 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&[data-attribute-type="AttributeDuration"] {
|
||||
.field_value_container {
|
||||
white-space: nowrap;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.one-col-details .details .field_container.field_small {
|
||||
|
||||
@@ -59,8 +59,8 @@ a:hover {
|
||||
padding-right: 20px;
|
||||
padding-top: 10px;
|
||||
padding-bottom: 10px;
|
||||
height: 54px;
|
||||
margin-top: 150px;
|
||||
height: 94px;
|
||||
margin-top: 110px;
|
||||
}
|
||||
|
||||
#login-content {
|
||||
@@ -75,9 +75,10 @@ a:hover {
|
||||
{
|
||||
#login-logo {
|
||||
margin-top: 0;
|
||||
padding-top: 0;
|
||||
}
|
||||
#login-content {
|
||||
margin-top: 74px;
|
||||
margin-top: 94px;
|
||||
}
|
||||
h1 {
|
||||
margin-top: 0;
|
||||
@@ -86,7 +87,7 @@ a:hover {
|
||||
|
||||
#login-logo img {
|
||||
border: 0;
|
||||
max-height: 54px;
|
||||
max-height: 94px;
|
||||
}
|
||||
|
||||
#login-form {
|
||||
|
||||
@@ -14,34 +14,4 @@
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
*/
|
||||
body {
|
||||
display: block;
|
||||
}
|
||||
/* Landing page */
|
||||
#uwp-main-container {
|
||||
margin-top: 40px;
|
||||
}
|
||||
#uwp-main-container #uwp-logo, #uwp-main-container #uwp-title {
|
||||
vertical-align: middle;
|
||||
}
|
||||
#uwp-main-container #uwp-title {
|
||||
margin-left: 25px;
|
||||
font-size: 20px;
|
||||
font-weight: bold;
|
||||
}
|
||||
#uwp-main-container #uwp-description {
|
||||
margin-bottom: 25px;
|
||||
}
|
||||
#uwp-main-container .uwp-text-hint--icon {
|
||||
font-size: 12px;
|
||||
margin-left: 5px;
|
||||
color: #939191;
|
||||
}
|
||||
#uwp-main-container #uwp-bottom-buttons {
|
||||
margin-top: 25px;
|
||||
text-align: right;
|
||||
}
|
||||
#uwp-main-container #uwp-bottom-buttons .btn ~ .btn {
|
||||
margin-left: 8px;
|
||||
}
|
||||
*/body{display:block}#uwp-main-container{margin-top:40px}#uwp-main-container #uwp-logo,#uwp-main-container #uwp-title{vertical-align:middle;max-height:74px}#uwp-main-container #uwp-title{margin-left:25px;font-size:20px;font-weight:bold}#uwp-main-container #uwp-description{margin-bottom:25px}#uwp-main-container .uwp-text-hint--icon{font-size:12px;margin-left:5px;color:#939191}#uwp-main-container #uwp-bottom-buttons{margin-top:25px;text-align:right}#uwp-main-container #uwp-bottom-buttons .btn~.btn{margin-left:8px}
|
||||
@@ -29,6 +29,7 @@ body{
|
||||
#uwp-logo,
|
||||
#uwp-title{
|
||||
vertical-align: middle;
|
||||
max-height: 74px;
|
||||
}
|
||||
#uwp-title{
|
||||
margin-left: 25px;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<itop_design xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="3.0">
|
||||
<itop_design xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="3.1">
|
||||
<constants>
|
||||
</constants>
|
||||
<classes>
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
SetupWebPage::AddModule(
|
||||
__FILE__, // Path to the current file, all other file names are relative to the directory containing this file
|
||||
'authent-cas/3.0.0',
|
||||
'authent-cas/3.1.0',
|
||||
array(
|
||||
// Identification
|
||||
//
|
||||
|
||||
@@ -29,6 +29,8 @@ use utils;
|
||||
*/
|
||||
class CASLoginExtension extends AbstractLoginFSMExtension implements iLogoutExtension, iLoginUIExtension
|
||||
{
|
||||
const LOGIN_MODE = 'cas';
|
||||
|
||||
/**
|
||||
* Return the list of supported login modes for this plugin
|
||||
*
|
||||
@@ -36,7 +38,7 @@ class CASLoginExtension extends AbstractLoginFSMExtension implements iLogoutExte
|
||||
*/
|
||||
public function ListSupportedLoginModes()
|
||||
{
|
||||
return array('cas');
|
||||
return array(static::LOGIN_MODE);
|
||||
}
|
||||
|
||||
protected function OnStart(&$iErrorCode)
|
||||
@@ -47,12 +49,12 @@ class CASLoginExtension extends AbstractLoginFSMExtension implements iLogoutExte
|
||||
|
||||
protected function OnReadCredentials(&$iErrorCode)
|
||||
{
|
||||
if (Session::Get('login_mode') == 'cas')
|
||||
if (empty(Session::Get('login_mode')) || Session::Get('login_mode') == static::LOGIN_MODE)
|
||||
{
|
||||
static::InitCASClient();
|
||||
if (phpCAS::isAuthenticated())
|
||||
{
|
||||
Session::Set('login_mode', 'cas');
|
||||
Session::Set('login_mode', static::LOGIN_MODE);
|
||||
Session::Set('auth_user', phpCAS::getUser());
|
||||
Session::Unset('login_will_redirect');
|
||||
}
|
||||
@@ -68,7 +70,7 @@ class CASLoginExtension extends AbstractLoginFSMExtension implements iLogoutExte
|
||||
$iErrorCode = LoginWebPage::EXIT_CODE_MISSINGLOGIN;
|
||||
return LoginWebPage::LOGIN_FSM_ERROR;
|
||||
}
|
||||
Session::Set('login_mode', 'cas');
|
||||
Session::Set('login_mode', static::LOGIN_MODE);
|
||||
phpCAS::forceAuthentication(); // Redirect to CAS and exit
|
||||
}
|
||||
}
|
||||
@@ -77,7 +79,7 @@ class CASLoginExtension extends AbstractLoginFSMExtension implements iLogoutExte
|
||||
|
||||
protected function OnCheckCredentials(&$iErrorCode)
|
||||
{
|
||||
if (Session::Get('login_mode') == 'cas')
|
||||
if (Session::Get('login_mode') == static::LOGIN_MODE)
|
||||
{
|
||||
if (!Session::IsSet('auth_user'))
|
||||
{
|
||||
@@ -94,7 +96,7 @@ class CASLoginExtension extends AbstractLoginFSMExtension implements iLogoutExte
|
||||
|
||||
protected function OnCredentialsOK(&$iErrorCode)
|
||||
{
|
||||
if (Session::Get('login_mode') == 'cas')
|
||||
if (Session::Get('login_mode') == static::LOGIN_MODE)
|
||||
{
|
||||
$sAuthUser = Session::Get('auth_user');
|
||||
if (!LoginWebPage::CheckUser($sAuthUser))
|
||||
@@ -109,7 +111,7 @@ class CASLoginExtension extends AbstractLoginFSMExtension implements iLogoutExte
|
||||
|
||||
protected function OnError(&$iErrorCode)
|
||||
{
|
||||
if (Session::Get('login_mode') == 'cas')
|
||||
if (Session::Get('login_mode') == static::LOGIN_MODE)
|
||||
{
|
||||
Session::Unset('phpCAS');
|
||||
if ($iErrorCode != LoginWebPage::EXIT_CODE_MISSINGLOGIN)
|
||||
@@ -124,7 +126,7 @@ class CASLoginExtension extends AbstractLoginFSMExtension implements iLogoutExte
|
||||
|
||||
protected function OnConnected(&$iErrorCode)
|
||||
{
|
||||
if (Session::Get('login_mode') == 'cas')
|
||||
if (Session::Get('login_mode') == static::LOGIN_MODE)
|
||||
{
|
||||
Session::Set('can_logoff', true);
|
||||
return LoginWebPage::CheckLoggedUser($iErrorCode);
|
||||
@@ -205,7 +207,7 @@ class CASLoginExtension extends AbstractLoginFSMExtension implements iLogoutExte
|
||||
$oLoginContext->SetLoaderPath(APPROOT.'env-'.utils::GetCurrentEnvironment().'/authent-cas/view');
|
||||
|
||||
$aData = array(
|
||||
'sLoginMode' => 'cas',
|
||||
'sLoginMode' => static::LOGIN_MODE,
|
||||
'sLabel' => Dict::S('CAS:Login:SignIn'),
|
||||
'sTooltip' => Dict::S('CAS:Login:SignInTooltip'),
|
||||
);
|
||||
|
||||
@@ -20,9 +20,9 @@
|
||||
|
||||
* @copyright Copyright (C) 2021 Combodo SARL
|
||||
* @licence http://opensource.org/licenses/AGPL-3.0
|
||||
*
|
||||
*
|
||||
*/
|
||||
Dict::Add('DE DE', 'German', 'Deutsch', array(
|
||||
'Class:UserExternal' => 'Externer Benutzer',
|
||||
'Class:UserExternal+' => 'Externe authentifizierter '.ITOP_APPLICATION_SHORT.'-Benutzer',
|
||||
'Class:UserExternal+' => 'Extern authentifizierter '.ITOP_APPLICATION_SHORT.'-Benutzer',
|
||||
));
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
|
||||
SetupWebPage::AddModule(
|
||||
__FILE__, // Path to the current file, all other file names are relative to the directory containing this file
|
||||
'authent-external/3.0.0',
|
||||
'authent-external/3.1.0',
|
||||
array(
|
||||
// Identification
|
||||
//
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<itop_design xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="3.0">
|
||||
<itop_design xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="3.1">
|
||||
<classes>
|
||||
<class id="UserLDAP" _delta="define">
|
||||
<parent>cmdbAbstractObject</parent>
|
||||
|
||||
@@ -9,7 +9,7 @@ if (function_exists('ldap_connect'))
|
||||
|
||||
SetupWebPage::AddModule(
|
||||
__FILE__, // Path to the current file, all other file names are relative to the directory containing this file
|
||||
'authent-ldap/3.0.0',
|
||||
'authent-ldap/3.1.0',
|
||||
array(
|
||||
// Identification
|
||||
//
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<itop_design xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="3.0">
|
||||
<itop_design xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="3.1">
|
||||
|
||||
<module_parameters>
|
||||
<parameters id="authent-local" _delta="define">
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user