mirror of
https://github.com/Combodo/iTop.git
synced 2026-04-12 13:18:44 +02:00
Compare commits
203 Commits
feature/41
...
3.0.3-desi
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
78d8829d65 | ||
|
|
307edd3f7a | ||
|
|
6bf906a72f | ||
|
|
0f016d7511 | ||
|
|
d782987f50 | ||
|
|
b1fd7716f6 | ||
|
|
ac7abb3049 | ||
|
|
3689f3d026 | ||
|
|
5ee6223434 | ||
|
|
4bfc1747b7 | ||
|
|
15f32bf843 | ||
|
|
0ba386c0bc | ||
|
|
0c3cdb202b | ||
|
|
03ac3d4e7c | ||
|
|
6510dc5c51 | ||
|
|
01faf39372 | ||
|
|
176e373d6c | ||
|
|
a34274b883 | ||
|
|
03fb78c38c | ||
|
|
c9e656f7a0 | ||
|
|
976566ec71 | ||
|
|
d908827787 | ||
|
|
93c0b98eb7 | ||
|
|
98ab5aa1a4 | ||
|
|
f117a2912b | ||
|
|
6594072617 | ||
|
|
6bed56b34e | ||
|
|
94e8151519 | ||
|
|
75b350f638 | ||
|
|
14cd60dd17 | ||
|
|
08f1e5a041 | ||
|
|
4c117d1a33 | ||
|
|
f91dfbcf23 | ||
|
|
58497b380b | ||
|
|
03bff9f2c2 | ||
|
|
a34d3f91be | ||
|
|
05753f174a | ||
|
|
d0c89343b4 | ||
|
|
3021234895 | ||
|
|
bccdb1bc3a | ||
|
|
143410f4cd | ||
|
|
4cea418517 | ||
|
|
759b1825fe | ||
|
|
370c1345d9 | ||
|
|
af8f06c8c3 | ||
|
|
bfe55183d0 | ||
|
|
939771aa15 | ||
|
|
b174e4cab3 | ||
|
|
61bd8b6bb4 | ||
|
|
5c9eb7fa38 | ||
|
|
e960a4ad53 | ||
|
|
7aad60ed1b | ||
|
|
97965277c7 | ||
|
|
93aee5883b | ||
|
|
18ed5ed526 | ||
|
|
bbf6476570 | ||
|
|
94c4f8c929 | ||
|
|
d40cf7fe3b | ||
|
|
6997c0fd83 | ||
|
|
822922df5c | ||
|
|
cb2be0eccd | ||
|
|
f55fc8d264 | ||
|
|
ea2140258c | ||
|
|
31f2666941 | ||
|
|
cac7e94a67 | ||
|
|
da02a05fa3 | ||
|
|
6d019615d0 | ||
|
|
ccdd315357 | ||
|
|
9f81e4875a | ||
|
|
4f102d764a | ||
|
|
dbd58cfeb6 | ||
|
|
99b7d66cf2 | ||
|
|
12ef74ec42 | ||
|
|
3ca4122673 | ||
|
|
efa20e77d0 | ||
|
|
effc4141c7 | ||
|
|
f75a51d59e | ||
|
|
9dc54d6e4c | ||
|
|
640b1b9176 | ||
|
|
3459dc5997 | ||
|
|
de7c9d965e | ||
|
|
4c127b6f61 | ||
|
|
61be903eb2 | ||
|
|
a50ed02057 | ||
|
|
0a7c8f9fd1 | ||
|
|
f65e14397c | ||
|
|
d7b94fb123 | ||
|
|
80a9ded404 | ||
|
|
c696a81c3a | ||
|
|
b9ed00d53f | ||
|
|
c4508ea80c | ||
|
|
16390c9b00 | ||
|
|
1271a895d1 | ||
|
|
030f1e2463 | ||
|
|
5729d6a9cd | ||
|
|
a5efef900c | ||
|
|
c851a10982 | ||
|
|
845adf43c6 | ||
|
|
5916e4ea39 | ||
|
|
7f37de777e | ||
|
|
bcf880f327 | ||
|
|
b593beb8c7 | ||
|
|
6aa9aa2831 | ||
|
|
d177ee4a7f | ||
|
|
fbc0a898ae | ||
|
|
36f8e58e25 | ||
|
|
6a7dbb06b0 | ||
|
|
5721a324c1 | ||
|
|
7de6c72154 | ||
|
|
c0cee02351 | ||
|
|
bb674fb873 | ||
|
|
6136eadd31 | ||
|
|
87cb73c038 | ||
|
|
11d8547cef | ||
|
|
0998c73a1a | ||
|
|
471f66649a | ||
|
|
e8bf9cf688 | ||
|
|
4f88a0e7d2 | ||
|
|
c6b0e273e6 | ||
|
|
d9539f9d01 | ||
|
|
a3e309acb5 | ||
|
|
c06cbfd4a9 | ||
|
|
1d7e4e1a42 | ||
|
|
524e65a29b | ||
|
|
df7d7c877d | ||
|
|
4bcad431aa | ||
|
|
5fe32aac15 | ||
|
|
88d9a29599 | ||
|
|
92a36dcfdd | ||
|
|
23b4d4cb6b | ||
|
|
b37e74b407 | ||
|
|
cb6232cc05 | ||
|
|
0d49c605e2 | ||
|
|
6d47b0f4f8 | ||
|
|
e1c28a5c22 | ||
|
|
296ee019a0 | ||
|
|
7c2f8f4d93 | ||
|
|
1f76ff940d | ||
|
|
bb26e48d38 | ||
|
|
26042b990f | ||
|
|
cf433f2f80 | ||
|
|
ae94e58a43 | ||
|
|
f66692d5cf | ||
|
|
2b917f6647 | ||
|
|
cda017fa4f | ||
|
|
dad22f6f83 | ||
|
|
9474f43d61 | ||
|
|
9077f7ba37 | ||
|
|
4d365c8a44 | ||
|
|
957ff40f30 | ||
|
|
7bb12c35ea | ||
|
|
aff9c7748b | ||
|
|
e518d34bc9 | ||
|
|
51a305b445 | ||
|
|
5577f4a62e | ||
|
|
f0141530b9 | ||
|
|
92a802947d | ||
|
|
ce5096a896 | ||
|
|
5efd45eafc | ||
|
|
23e0ed5e56 | ||
|
|
d412a52fcc | ||
|
|
cf5745b985 | ||
|
|
3e18ad590f | ||
|
|
b174aa9aeb | ||
|
|
34f03715b6 | ||
|
|
6a0cdb8705 | ||
|
|
22111bf667 | ||
|
|
6d0c46595d | ||
|
|
1e2205ecb0 | ||
|
|
d292a6b0c3 | ||
|
|
74702c8d06 | ||
|
|
df4a205ba0 | ||
|
|
e9c91d986d | ||
|
|
feafd5e2c9 | ||
|
|
70a6b276ca | ||
|
|
f77361ceb2 | ||
|
|
75f4751b82 | ||
|
|
65b6c0f4ea | ||
|
|
c05684945f | ||
|
|
6b1c033ec1 | ||
|
|
4f14d1fb23 | ||
|
|
8c95bd5a65 | ||
|
|
b56f2f56f1 | ||
|
|
282d47aed4 | ||
|
|
2f8f0b658c | ||
|
|
e4884470ad | ||
|
|
68d44fa981 | ||
|
|
7e5307bd96 | ||
|
|
5839d0e8e3 | ||
|
|
cd010afb48 | ||
|
|
be5a252be7 | ||
|
|
073488a7bd | ||
|
|
0cf8d731bb | ||
|
|
4e7df37931 | ||
|
|
4b670cfa90 | ||
|
|
87db88254b | ||
|
|
5ddc006f51 | ||
|
|
85a72d6a10 | ||
|
|
189ca3c555 | ||
|
|
c02b36a00c | ||
|
|
1e1f1f78bf | ||
|
|
1494604740 | ||
|
|
59b20ac1ee |
Binary file not shown.
|
Before Width: | Height: | Size: 983 KiB |
|
Before Width: | Height: | Size: 1.4 MiB After Width: | Height: | Size: 1.4 MiB |
@@ -1,61 +0,0 @@
|
||||
# iTop version history
|
||||
|
||||
```mermaid
|
||||
%%{init: { 'logLevel': 'debug', 'theme': 'base', 'gitGraph': {'showBranches': true,'mainBranchName': 'develop','rotateCommitLabel': true}} }%%
|
||||
gitGraph
|
||||
commit id: "2016-07-06" tag: "2.3.0"
|
||||
branch support/2.3 order: 900
|
||||
commit id: "2016-07-08" tag: "2.3.1"
|
||||
commit id: "2016-12-22" tag: "2.3.3"
|
||||
commit id: "2017-04-14" tag: "2.3.4"
|
||||
checkout develop
|
||||
commit id: "2017-07-12" tag: "2.4.0-beta" type: REVERSE
|
||||
commit id: "2017-11-16" tag: "2.4.0"
|
||||
branch support/2.4 order: 890
|
||||
commit id: "2018-02-14" tag: "2.4.1"
|
||||
checkout develop
|
||||
commit id: "2018-04-25" tag: "2.5.0-beta" type: REVERSE
|
||||
checkout support/2.4
|
||||
commit id: "2018-06-14" tag: "2.4.2"
|
||||
checkout develop
|
||||
commit id: "2018-06-27" tag: "2.5.0"
|
||||
branch support/2.5 order: 880
|
||||
checkout develop
|
||||
commit id: "2019-01-09" tag: "2.6.0"
|
||||
branch support/2.6 order: 870
|
||||
commit id: "2019-03-28" tag: "2.6.1"
|
||||
checkout develop
|
||||
commit id: "2019-12-18" tag: "2.7.0-beta" type: REVERSE
|
||||
checkout support/2.5
|
||||
commit id: "2020-01-22" tag: "2.5.4"
|
||||
checkout support/2.6
|
||||
commit id: "2020-01-23" tag: "2.6.3"
|
||||
checkout develop
|
||||
commit id: "2020-01-29" tag: "2.7.0-beta2" type: REVERSE
|
||||
branch support/2.7 order: 860
|
||||
commit id: "2020-04-01" tag: "2.7.0-1"
|
||||
checkout support/2.6
|
||||
commit id: "2020-04-22" tag: "2.6.4"
|
||||
checkout support/2.7
|
||||
commit id: "2020-06-26" tag: "2.7.1"
|
||||
checkout support/2.7
|
||||
commit id: "2020-12-09" tag: "2.7.3"
|
||||
commit id: "2021-03-31" tag: "2.7.4"
|
||||
checkout develop
|
||||
commit id: "2021-04-06" tag: "3.0.0-beta" type: REVERSE
|
||||
checkout support/2.7
|
||||
commit id: "2021-07-05" tag: "2.7.5"
|
||||
checkout develop
|
||||
commit id: "2021-07-05." tag: "3.0.0-beta2" type: REVERSE
|
||||
checkout support/2.7
|
||||
commit id: "2021-12-17" tag: "2.7.6"
|
||||
checkout develop
|
||||
commit id: "2022-01-04" tag: "3.0.0"
|
||||
branch support/3.0 order: 850
|
||||
commit id: "2022-04-08" tag: "3.0.1"
|
||||
checkout support/2.7
|
||||
commit id: "2022-07-11" tag: "2.7.7"
|
||||
checkout support/3.0
|
||||
commit id: "2022-09-12" tag: "3.0.2-1"
|
||||
checkout develop
|
||||
```
|
||||
4
.gitignore
vendored
4
.gitignore
vendored
@@ -19,7 +19,7 @@
|
||||
|
||||
# composer reserver directory, from sources, populate/update using "composer install"
|
||||
vendor/*
|
||||
test/vendor/*
|
||||
tests/*/vendor/*
|
||||
|
||||
# all conf but listing prevention
|
||||
/conf/**
|
||||
@@ -46,7 +46,7 @@ test/vendor/*
|
||||
!/log/web.config
|
||||
|
||||
# PHPUnit cache file
|
||||
/test/.phpunit.result.cache
|
||||
/tests/php-unit-tests/.phpunit.result.cache
|
||||
|
||||
|
||||
# Jetbrains
|
||||
|
||||
@@ -19,23 +19,16 @@
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* Alias for `composer show -loD`
|
||||
* You can also use `composer outdated -D`
|
||||
*
|
||||
* @link https://getcomposer.org/doc/03-cli.md#show
|
||||
*/
|
||||
$iTopFolder = __DIR__ . "/../../" ;
|
||||
|
||||
$iTopFolder = __DIR__."/../../";
|
||||
|
||||
require_once("$iTopFolder/approot.inc.php");
|
||||
require_once ("$iTopFolder/approot.inc.php");
|
||||
$sApproot = APPROOT;
|
||||
$aTrace = array();
|
||||
|
||||
$aParamsConfig = array(
|
||||
'composer-path' => array(
|
||||
'default' => 'composer',
|
||||
),
|
||||
'default' => 'composer.phar',
|
||||
)
|
||||
);
|
||||
$aParamsConfigNotFound = array_flip(array_keys($aParamsConfig));
|
||||
$aGivenArgs = $argv;
|
||||
|
||||
@@ -27,14 +27,11 @@ If you have an idea you're sure would benefit to all of iTop users, you may
|
||||
[create a corresponding ticket](https://sourceforge.net/p/itop/tickets/new/) to submit it, but be warned that there are lots of good
|
||||
reasons to refuse such changes.
|
||||
|
||||
### 📄 License and copyright
|
||||
iTop is distributed under the AGPL-3.0 license (see the [license.txt] file).
|
||||
### 📄 License
|
||||
iTop is distributed under the AGPL-3.0 license (see the [license.txt] file),
|
||||
your code must comply with this license.
|
||||
|
||||
The iTop repository is divided in three parts: iTop (mainly PHP/JS/XML sources and dictionaries), images, and third-party libraries.
|
||||
Combodo has the copyright on most of the source files in the iTop part of the repository: please do not modify the existing file copyrights.
|
||||
Anyhow, you are encouraged to signal your contribution by the mean of `@author` annotations.
|
||||
|
||||
If you want to use another license or keep the code ownership (copyright), you may [create an extension][wiki new ext].
|
||||
If you want to use another license, you may [create an extension][wiki new ext].
|
||||
|
||||
[license.txt]: https://github.com/Combodo/iTop/blob/develop/license.txt
|
||||
[wiki new ext]: https://www.itophub.io/wiki/page?id=latest%3Acustomization%3Astart#by_writing_your_own_extension
|
||||
@@ -55,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.1.0 version
|
||||
- `support/3.0`: 3.0.x maintenance version
|
||||
- `develop` containing future 3.0.0 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.1.0-beta is shipped that will become:
|
||||
In this example, when 3.0.0-beta is shipped that will become:
|
||||
|
||||
- `develop`: future 3.2.0 version
|
||||
- `release/3.1.0`: 3.1.0-beta
|
||||
- `support/3.0`: 3.0.x maintenance version
|
||||
- `develop`: future 3.1.0 version
|
||||
- `release/3.0.0`: 3.0.0-beta
|
||||
- `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.1.0 final will be out:
|
||||
And when 3.0.0 final will be out:
|
||||
|
||||
- `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
|
||||
- `develop`: future 3.1.0 version
|
||||
- `support/3.0`: 3.0.x maintenance version (will host developments for 3.0.1)
|
||||
- `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.
|
||||
@@ -134,19 +131,21 @@ Our tests are located in the `test/` directory, containing a PHPUnit config file
|
||||
|
||||
When your code is working, please:
|
||||
|
||||
* stash as much as possible your commits,
|
||||
* squash as much as possible your commits,
|
||||
* rebase your branch on our repo last commit,
|
||||
* create a pull request
|
||||
* mind to check the "[Allow edits from maintainers](https://docs.github.com/en/github-ae@latest/pull-requests/collaborating-with-pull-requests/working-with-forks/allowing-changes-to-a-pull-request-branch-created-from-a-fork)" option !
|
||||
* create a pull request.
|
||||
|
||||
Detailed procedure to work on fork and create PR is available [in GitHub help pages](https://help.github.com/articles/creating-a-pull-request-from-a-fork/).
|
||||
|
||||
You might check the ["Allow edits from maintainers" PR checkbox][allow_edits_checkbox] to ease review.
|
||||
|
||||
[allow_edits_checkbox]: https://docs.github.com/en/github/collaborating-with-issues-and-pull-requests/working-with-forks/allowing-changes-to-a-pull-request-branch-created-from-a-fork#enabling-repository-maintainer-permissions-on-existing-pull-requests
|
||||
|
||||
### 🙏 We are thankful
|
||||
|
||||
We are thankful for all your contributions to the iTop universe! As a thank you gift, we will send stickers to every iTop (& extensions) contributors!
|
||||
We are thankful for all your contributions to the iTop universe! As a thank you gift, we will send stickers to every iTop (& extensions) contributors!
|
||||
|
||||
We have one sticker per contribution type. You might get multiple stickers with one contribution though :)
|
||||
Stickers' design might change from one year to another. For the first year we wanted to try a "craft beer label" look, see examples below:
|
||||
|
||||
* Bug hunter: Fix a bug
|
||||
* Translator: Add/update translations
|
||||
@@ -158,6 +157,4 @@ We have one sticker per contribution type. You might get multiple stickers with
|
||||
* Beta tester: Test and give feedback on beta releases
|
||||
* Extension developer: Develop and publish an extension
|
||||
|
||||
Here is the design of each stickers for year 2022:
|
||||
|
||||

|
||||

|
||||
|
||||
8
Jenkinsfile
vendored
8
Jenkinsfile
vendored
@@ -1,6 +1,14 @@
|
||||
def infra
|
||||
|
||||
node(){
|
||||
properties([
|
||||
buildDiscarder(
|
||||
logRotator(
|
||||
daysToKeepStr: "28",
|
||||
numToKeepStr: "500")
|
||||
)
|
||||
])
|
||||
|
||||
checkout scm
|
||||
|
||||
infra = load '/var/lib/jenkins/workspace/itop-test-infra_master/src/Infra.groovy'
|
||||
|
||||
@@ -37,19 +37,17 @@ iTop also offers mass import tools to help you being even more efficient.
|
||||
- [iTop Forums][1]: community support
|
||||
- [iTop Tickets][2]: for feature requests and bug reports
|
||||
- [Releases download][3]
|
||||
- [Software requirements][4]
|
||||
- [iTop requirements][4]
|
||||
- [Documentation][5] covering both iTop and its official extensions
|
||||
- [iTop Hub][6] : discover and install extensions !
|
||||
- [iTop versions history][7]
|
||||
|
||||
|
||||
[1]: https://sourceforge.net/p/itop/discussion/
|
||||
[2]: https://sourceforge.net/p/itop/tickets/
|
||||
[3]: https://sourceforge.net/projects/itop/files/itop/
|
||||
[4]: https://www.itophub.io/wiki/page?id=latest:install:upgrading_itop
|
||||
[4]: https://www.itophub.io/wiki/page?id=latest:install:requirements
|
||||
[5]: https://www.itophub.io/wiki
|
||||
[6]: https://store.itophub.io/en_US/
|
||||
[7]: .doc/itop-version-history.md
|
||||
|
||||
[10]: https://www.itophub.io/wiki/page?id=latest%3Adatamodel%3Astart#configuration_management_cmdb
|
||||
[11]: https://www.itophub.io/wiki/page?id=latest%3Adatamodel%3Astart#ticketing
|
||||
@@ -100,11 +98,8 @@ We would like to give a special thank you 🤗 to the people from the community
|
||||
- Lucas, Jonathan
|
||||
- Malik, Remie
|
||||
- Mindêllo de Andrade, Lucas (a.k.a [@rokam](https://www.github.com/rokam))
|
||||
- Mozart de Oliveira, Eduardo (a.k.a [@eduardomozart](https://github.com/eduardomozart))
|
||||
- Raenker, Martin
|
||||
- Roháč, Richard (a.k.a [@RohacRichard](https://github.com/RohacRichard))
|
||||
- Rosenke, Stephan
|
||||
- Rudner, Björn (a.k.a [@rudnerbjoern](https://github.com/rudnerbjoern))
|
||||
- Seki, Shoji
|
||||
- Shilov, Vladimir
|
||||
- Stukalov, Ilya (a.k.a [@ilya](https://www.github.com/ilya)-stukalov)
|
||||
|
||||
@@ -121,6 +121,7 @@ class UserRightsMatrix extends UserRightsAddOnAPI
|
||||
public function CreateAdministrator($sAdminUser, $sAdminPwd, $sLanguage = 'EN US')
|
||||
{
|
||||
// Maybe we should check that no other user with userid == 0 exists
|
||||
CMDBObject::SetTrackInfo('Initialization');
|
||||
$oUser = new UserLocal();
|
||||
$oUser->Set('login', $sAdminUser);
|
||||
$oUser->Set('password', $sAdminPwd);
|
||||
|
||||
@@ -124,7 +124,7 @@ class URP_Profiles extends UserRightsBaseClassGUI
|
||||
$bGrant = $oUserRights->GetClassStimulusGrant($this->GetKey(), $sClass, $sStimulusCode);
|
||||
if ($bGrant === true)
|
||||
{
|
||||
$aStimuli[] = '<span title="'.$sStimulusCode.': '.utils::EscapeHtml($oStimulus->GetDescription()).'">'.utils::EscapeHtml($oStimulus->GetLabel()).'</span>';
|
||||
$aStimuli[] = '<span title="'.$sStimulusCode.': '.htmlentities($oStimulus->GetDescription(), ENT_QUOTES, 'UTF-8').'">'.htmlentities($oStimulus->GetLabel(), ENT_QUOTES, 'UTF-8').'</span>';
|
||||
}
|
||||
}
|
||||
$sStimuli = implode(', ', $aStimuli);
|
||||
@@ -435,18 +435,20 @@ class UserRightsProfile extends UserRightsAddOnAPI
|
||||
// Installation: create the very first user
|
||||
public function CreateAdministrator($sAdminUser, $sAdminPwd, $sLanguage = 'EN US')
|
||||
{
|
||||
CMDBObject::SetCurrentChangeFromParams('Initialization create administrator');
|
||||
CMDBObject::SetTrackInfo('Initialization');
|
||||
|
||||
$iContactId = 0;
|
||||
// Support drastic data model changes: no organization class (or not writable)!
|
||||
if (MetaModel::IsValidClass('Organization') && !MetaModel::IsAbstract('Organization')) {
|
||||
if (MetaModel::IsValidClass('Organization') && !MetaModel::IsAbstract('Organization'))
|
||||
{
|
||||
$oOrg = MetaModel::NewObject('Organization');
|
||||
$oOrg->Set('name', 'My Company/Department');
|
||||
$oOrg->Set('code', 'SOMECODE');
|
||||
$iOrgId = $oOrg->DBInsertNoReload();
|
||||
|
||||
// Support drastic data model changes: no Person class (or not writable)!
|
||||
if (MetaModel::IsValidClass('Person') && !MetaModel::IsAbstract('Person')) {
|
||||
if (MetaModel::IsValidClass('Person') && !MetaModel::IsAbstract('Person'))
|
||||
{
|
||||
$oContact = MetaModel::NewObject('Person');
|
||||
$oContact->Set('name', 'My last name');
|
||||
$oContact->Set('first_name', 'My first name');
|
||||
|
||||
@@ -278,8 +278,8 @@ class URP_Profiles extends UserRightsBaseClassGUI
|
||||
{
|
||||
$oGrant = $oUserRights->GetClassStimulusGrant($this->GetKey(), $sClass, $sStimulusCode);
|
||||
if (is_object($oGrant) && ($oGrant->Get('permission') == 'yes'))
|
||||
{
|
||||
$aStimuli[] = '<span title="'.$sStimulusCode.': '.utils::EscapeHtml($oStimulus->GetDescription()).'">'.utils::EscapeHtml($oStimulus->GetLabel()).'</span>';
|
||||
{
|
||||
$aStimuli[] = '<span title="'.$sStimulusCode.': '.htmlentities($oStimulus->GetDescription(), ENT_QUOTES, 'UTF-8').'">'.htmlentities($oStimulus->GetLabel(), ENT_QUOTES, 'UTF-8').'</span>';
|
||||
}
|
||||
}
|
||||
$sStimuli = implode(', ', $aStimuli);
|
||||
@@ -508,18 +508,24 @@ class UserRightsProfile extends UserRightsAddOnAPI
|
||||
public function CreateAdministrator($sAdminUser, $sAdminPwd, $sLanguage = 'EN US')
|
||||
{
|
||||
// Create a change to record the history of the User object
|
||||
CMDBObject::SetCurrentChangeFromParams('Initialization : create first user admin profile');
|
||||
/** @var \CMDBChange $oChange */
|
||||
$oChange = MetaModel::NewObject("CMDBChange");
|
||||
$oChange->Set("date", time());
|
||||
$oChange->Set("userinfo", "Initialization");
|
||||
|
||||
$iContactId = 0;
|
||||
// Support drastic data model changes: no organization class (or not writable)!
|
||||
if (MetaModel::IsValidClass('Organization') && !MetaModel::IsAbstract('Organization')) {
|
||||
if (MetaModel::IsValidClass('Organization') && !MetaModel::IsAbstract('Organization'))
|
||||
{
|
||||
$oOrg = MetaModel::NewObject('Organization');
|
||||
$oOrg->Set('name', 'My Company/Department');
|
||||
$oOrg->Set('code', 'SOMECODE');
|
||||
$oOrg::SetCurrentChange($oChange);
|
||||
$iOrgId = $oOrg->DBInsertNoReload();
|
||||
|
||||
// Support drastic data model changes: no Person class (or not writable)!
|
||||
if (MetaModel::IsValidClass('Person') && !MetaModel::IsAbstract('Person')) {
|
||||
if (MetaModel::IsValidClass('Person') && !MetaModel::IsAbstract('Person'))
|
||||
{
|
||||
$oContact = MetaModel::NewObject('Person');
|
||||
$oContact->Set('name', 'My last name');
|
||||
$oContact->Set('first_name', 'My first name');
|
||||
@@ -528,6 +534,7 @@ class UserRightsProfile extends UserRightsAddOnAPI
|
||||
$oContact->Set('org_id', $iOrgId);
|
||||
}
|
||||
$oContact->Set('email', 'my.email@foo.org');
|
||||
$oContact::SetCurrentChange($oChange);
|
||||
$iContactId = $oContact->DBInsertNoReload();
|
||||
}
|
||||
}
|
||||
@@ -536,22 +543,24 @@ class UserRightsProfile extends UserRightsAddOnAPI
|
||||
$oUser = new UserLocal();
|
||||
$oUser->Set('login', $sAdminUser);
|
||||
$oUser->Set('password', $sAdminPwd);
|
||||
if (MetaModel::IsValidAttCode('UserLocal', 'contactid') && ($iContactId != 0)) {
|
||||
if (MetaModel::IsValidAttCode('UserLocal', 'contactid') && ($iContactId != 0))
|
||||
{
|
||||
$oUser->Set('contactid', $iContactId);
|
||||
}
|
||||
$oUser->Set('language', $sLanguage); // Language was chosen during the installation
|
||||
|
||||
// Add this user to the very specific 'admin' profile
|
||||
$oAdminProfile = MetaModel::GetObjectFromOQL("SELECT URP_Profiles WHERE name = :name", array('name' => ADMIN_PROFILE_NAME), true /*all data*/);
|
||||
if (is_object($oAdminProfile)) {
|
||||
if (is_object($oAdminProfile))
|
||||
{
|
||||
$oUserProfile = new URP_UserProfile();
|
||||
$oUserProfile->Set('profileid', $oAdminProfile->GetKey());
|
||||
$oUserProfile->Set('reason', 'By definition, the administrator must have the administrator profile');
|
||||
$oSet = DBObjectSet::FromObject($oUserProfile);
|
||||
$oUser->Set('profile_list', $oSet);
|
||||
}
|
||||
$oUser->DBInsertNoReload();
|
||||
|
||||
$oUser::SetCurrentChange($oChange);
|
||||
$iUserId = $oUser->DBInsertNoReload();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -110,8 +110,8 @@ class URP_Profiles extends UserRightsBaseClass
|
||||
{
|
||||
$oGrant = $oUserRights->GetClassStimulusGrant($this->GetKey(), $sClass, $sStimulusCode);
|
||||
if (is_object($oGrant) && ($oGrant->Get('permission') == 'yes'))
|
||||
{
|
||||
$aStimuli[] = '<span title="'.$sStimulusCode.': '.utils::EscapeHtml($oStimulus->GetDescription()).'">'.utils::EscapeHtml($oStimulus->GetLabel()).'</span>';
|
||||
{
|
||||
$aStimuli[] = '<span title="'.$sStimulusCode.': '.htmlentities($oStimulus->GetDescription(), ENT_QUOTES, 'UTF-8').'">'.htmlentities($oStimulus->GetLabel(), ENT_QUOTES, 'UTF-8').'</span>';
|
||||
}
|
||||
}
|
||||
$sStimuli = implode(', ', $aStimuli);
|
||||
@@ -568,11 +568,14 @@ class UserRightsProjection extends UserRightsAddOnAPI
|
||||
public function CreateAdministrator($sAdminUser, $sAdminPwd, $sLanguage = 'EN US')
|
||||
{
|
||||
// Create a change to record the history of the User object
|
||||
CMDBObject::SetCurrentChangeFromParams('Initialization : create first user admin');
|
||||
$oChange = MetaModel::NewObject("CMDBChange");
|
||||
$oChange->Set("date", time());
|
||||
$oChange->Set("userinfo", "Initialization");
|
||||
|
||||
$oOrg = new Organization();
|
||||
$oOrg->Set('name', 'My Company/Department');
|
||||
$oOrg->Set('code', 'SOMECODE');
|
||||
$oOrg::SetCurrentChange($oChange);
|
||||
$iOrgId = $oOrg->DBInsertNoReload();
|
||||
|
||||
$oContact = new Person();
|
||||
@@ -581,6 +584,7 @@ class UserRightsProjection extends UserRightsAddOnAPI
|
||||
//$oContact->Set('status', 'available');
|
||||
$oContact->Set('org_id', $iOrgId);
|
||||
$oContact->Set('email', 'my.email@foo.org');
|
||||
$oContact::SetCurrentChange($oChange);
|
||||
$iContactId = $oContact->DBInsertNoReload();
|
||||
|
||||
$oUser = new UserLocal();
|
||||
@@ -588,6 +592,7 @@ class UserRightsProjection extends UserRightsAddOnAPI
|
||||
$oUser->Set('password', $sAdminPwd);
|
||||
$oUser->Set('contactid', $iContactId);
|
||||
$oUser->Set('language', $sLanguage); // Language was chosen during the installation
|
||||
$oUser::SetCurrentChange($oChange);
|
||||
$iUserId = $oUser->DBInsertNoReload();
|
||||
|
||||
// Add this user to the very specific 'admin' profile
|
||||
@@ -595,6 +600,7 @@ class UserRightsProjection extends UserRightsAddOnAPI
|
||||
$oUserProfile->Set('userid', $iUserId);
|
||||
$oUserProfile->Set('profileid', ADMIN_PROFILE_ID);
|
||||
$oUserProfile->Set('reason', 'By definition, the administrator must have the administrator profile');
|
||||
$oUserProfile::SetCurrentChange($oChange);
|
||||
$oUserProfile->DBInsertNoReload();
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -1,24 +1,20 @@
|
||||
<?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 load in autoloader
|
||||
//DeprecatedCallsLog::NotifyDeprecatedFile('moved to sources/Application/WebPage/AjaxPage.php, now loadable using autoloader');
|
||||
// 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');
|
||||
|
||||
/**
|
||||
* Class ajax_page
|
||||
*
|
||||
* @deprecated 3.0.0 will be removed in 3.1.0 - moved to AjaxPage
|
||||
* @deprecated will be removed in 3.1.0 - moved to AjaxPage
|
||||
*/
|
||||
class ajax_page extends AjaxPage
|
||||
{
|
||||
function __construct($s_title)
|
||||
{
|
||||
DeprecatedCallsLog::NotifyDeprecatedPhpMethod('ajax_page is deprecated. Please use AjaxPage instead');
|
||||
parent::__construct($s_title);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -224,7 +224,7 @@ class ApplicationContext
|
||||
{
|
||||
$sContext = "";
|
||||
foreach ($this->aValues as $sName => $sValue) {
|
||||
$sContext .= "<input type=\"hidden\" name=\"c[$sName]\" value=\"".utils::EscapeHtml($sValue)."\" />\n";
|
||||
$sContext .= "<input type=\"hidden\" name=\"c[$sName]\" value=\"".htmlentities($sValue, ENT_QUOTES, 'UTF-8')."\" />\n";
|
||||
}
|
||||
return $sContext;
|
||||
}
|
||||
@@ -238,7 +238,7 @@ class ApplicationContext
|
||||
{
|
||||
$aContextInputBlocks = [];
|
||||
foreach ($this->aValues as $sName => $sValue) {
|
||||
$aContextInputBlocks[] = InputUIBlockFactory::MakeForHidden("c[$sName]", utils::EscapeHtml($sValue));
|
||||
$aContextInputBlocks[] = InputUIBlockFactory::MakeForHidden("c[$sName]", htmlentities($sValue, ENT_QUOTES, 'UTF-8'));
|
||||
}
|
||||
return $aContextInputBlocks;
|
||||
}
|
||||
@@ -376,26 +376,19 @@ class ApplicationContext
|
||||
{
|
||||
$oAppContext = new ApplicationContext();
|
||||
|
||||
if (is_null($sUrlMakerClass))
|
||||
{
|
||||
$sUrlMakerClass = self::GetUrlMakerClass();
|
||||
}
|
||||
if (is_null($sUrlMakerClass)) {
|
||||
$sUrlMakerClass = self::GetUrlMakerClass();
|
||||
}
|
||||
$sUrl = call_user_func(array($sUrlMakerClass, 'MakeObjectUrl'), $sObjClass, $sObjKey);
|
||||
if (strlen($sUrl) > 0)
|
||||
{
|
||||
if ($bWithNavigationContext)
|
||||
{
|
||||
return $sUrl."&".$oAppContext->GetForLink();
|
||||
}
|
||||
else
|
||||
{
|
||||
return $sUrl;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return '';
|
||||
}
|
||||
if (utils::StrLen($sUrl) > 0) {
|
||||
if ($bWithNavigationContext) {
|
||||
return $sUrl."&".$oAppContext->GetForLink();
|
||||
} else {
|
||||
return $sUrl;
|
||||
}
|
||||
} else {
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -30,9 +30,9 @@ require_once(APPROOT.'application/newsroomprovider.class.inc.php');
|
||||
* You may implement such interfaces in a module file (e.g. main.mymodule.php)
|
||||
*
|
||||
* @api
|
||||
* @package LoginExtensibilityAPI
|
||||
* @copyright Copyright (C) 2010-2021 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
* @package Extensibility
|
||||
* @since 2.7.0
|
||||
*/
|
||||
interface iLoginExtension
|
||||
@@ -40,12 +40,16 @@ interface iLoginExtension
|
||||
/**
|
||||
* Return the list of supported login modes for this plugin
|
||||
*
|
||||
* @api
|
||||
*
|
||||
* @return array of supported login modes
|
||||
*/
|
||||
public function ListSupportedLoginModes();
|
||||
}
|
||||
|
||||
/**
|
||||
* @api
|
||||
* @package LoginExtensibilityAPI
|
||||
* @since 2.7.0
|
||||
*/
|
||||
interface iLoginFSMExtension extends iLoginExtension
|
||||
@@ -57,6 +61,7 @@ interface iLoginFSMExtension extends iLoginExtension
|
||||
* if LoginWebPage::LOGIN_FSM_RETURN_OK is returned then the login is OK and terminated
|
||||
* if LoginWebPage::LOGIN_FSM_RETURN_IGNORE is returned then the FSM will proceed to next plugin or state
|
||||
*
|
||||
* @api
|
||||
* @param string $sLoginState (see LoginWebPage::LOGIN_STATE_...)
|
||||
* @param int $iErrorCode (see LoginWebPage::EXIT_CODE_...)
|
||||
*
|
||||
@@ -66,6 +71,8 @@ interface iLoginFSMExtension extends iLoginExtension
|
||||
}
|
||||
|
||||
/**
|
||||
* @api
|
||||
* @package LoginExtensibilityAPI
|
||||
* @since 2.7.0
|
||||
*/
|
||||
abstract class AbstractLoginFSMExtension implements iLoginFSMExtension
|
||||
@@ -112,6 +119,7 @@ abstract class AbstractLoginFSMExtension implements iLoginFSMExtension
|
||||
/**
|
||||
* Initialization
|
||||
*
|
||||
* @api
|
||||
* @param int $iErrorCode (see LoginWebPage::EXIT_CODE_...)
|
||||
*
|
||||
* @return int LoginWebPage::LOGIN_FSM_RETURN_ERROR, LoginWebPage::LOGIN_FSM_RETURN_OK or LoginWebPage::LOGIN_FSM_RETURN_IGNORE
|
||||
@@ -125,6 +133,7 @@ abstract class AbstractLoginFSMExtension implements iLoginFSMExtension
|
||||
* Detect login mode explicitly without respecting configured order (legacy mode)
|
||||
* In most case do nothing here
|
||||
*
|
||||
* @api
|
||||
* @param int $iErrorCode (see LoginWebPage::EXIT_CODE_...)
|
||||
*
|
||||
* @return int LoginWebPage::LOGIN_FSM_RETURN_ERROR, LoginWebPage::LOGIN_FSM_RETURN_OK or LoginWebPage::LOGIN_FSM_RETURN_IGNORE
|
||||
@@ -141,6 +150,7 @@ abstract class AbstractLoginFSMExtension implements iLoginFSMExtension
|
||||
* 1 - display login form
|
||||
* 2 - read the values posted by the user
|
||||
*
|
||||
* @api
|
||||
* @param int $iErrorCode (see LoginWebPage::EXIT_CODE_...)
|
||||
*
|
||||
* @return int LoginWebPage::LOGIN_FSM_RETURN_ERROR, LoginWebPage::LOGIN_FSM_RETURN_OK or LoginWebPage::LOGIN_FSM_RETURN_IGNORE
|
||||
@@ -154,6 +164,7 @@ abstract class AbstractLoginFSMExtension implements iLoginFSMExtension
|
||||
* Control the validity of the data provided by the user
|
||||
* Automatic user provisioning can be done here
|
||||
*
|
||||
* @api
|
||||
* @param int $iErrorCode (see LoginWebPage::EXIT_CODE_...)
|
||||
*
|
||||
* @return int LoginWebPage::LOGIN_FSM_RETURN_ERROR, LoginWebPage::LOGIN_FSM_RETURN_OK or LoginWebPage::LOGIN_FSM_RETURN_IGNORE
|
||||
@@ -164,6 +175,7 @@ abstract class AbstractLoginFSMExtension implements iLoginFSMExtension
|
||||
}
|
||||
|
||||
/**
|
||||
* @api
|
||||
* @param int $iErrorCode (see LoginWebPage::EXIT_CODE_...)
|
||||
*
|
||||
* @return int LoginWebPage::LOGIN_FSM_RETURN_ERROR, LoginWebPage::LOGIN_FSM_RETURN_OK or LoginWebPage::LOGIN_FSM_RETURN_IGNORE
|
||||
@@ -174,6 +186,7 @@ abstract class AbstractLoginFSMExtension implements iLoginFSMExtension
|
||||
}
|
||||
|
||||
/**
|
||||
* @api
|
||||
* @param int $iErrorCode (see LoginWebPage::EXIT_CODE_...)
|
||||
*
|
||||
* @return int LoginWebPage::LOGIN_FSM_RETURN_ERROR, LoginWebPage::LOGIN_FSM_RETURN_OK or LoginWebPage::LOGIN_FSM_RETURN_IGNORE
|
||||
@@ -184,6 +197,7 @@ abstract class AbstractLoginFSMExtension implements iLoginFSMExtension
|
||||
}
|
||||
|
||||
/**
|
||||
* @api
|
||||
* @param int $iErrorCode (see LoginWebPage::EXIT_CODE_...)
|
||||
*
|
||||
* @return int LoginWebPage::LOGIN_FSM_RETURN_ERROR, LoginWebPage::LOGIN_FSM_RETURN_OK or LoginWebPage::LOGIN_FSM_RETURN_IGNORE
|
||||
@@ -194,6 +208,7 @@ abstract class AbstractLoginFSMExtension implements iLoginFSMExtension
|
||||
}
|
||||
|
||||
/**
|
||||
* @api
|
||||
* @param int $iErrorCode (see LoginWebPage::EXIT_CODE_...)
|
||||
*
|
||||
* @return int LoginWebPage::LOGIN_FSM_RETURN_ERROR, LoginWebPage::LOGIN_FSM_RETURN_OK or LoginWebPage::LOGIN_FSM_RETURN_IGNORE
|
||||
@@ -205,22 +220,28 @@ abstract class AbstractLoginFSMExtension implements iLoginFSMExtension
|
||||
}
|
||||
|
||||
/**
|
||||
* @api
|
||||
* @package LoginExtensibilityAPI
|
||||
* @since 2.7.0
|
||||
*/
|
||||
interface iLogoutExtension extends iLoginExtension
|
||||
{
|
||||
/**
|
||||
* Execute all actions to log out properly
|
||||
* @api
|
||||
*/
|
||||
public function LogoutAction();
|
||||
}
|
||||
|
||||
/**
|
||||
* @api
|
||||
* @package UIExtensibilityAPI
|
||||
* @since 2.7.0
|
||||
*/
|
||||
interface iLoginUIExtension extends iLoginExtension
|
||||
{
|
||||
/**
|
||||
* @api
|
||||
* @return LoginTwigContext
|
||||
*/
|
||||
public function GetTwigContext();
|
||||
@@ -228,18 +249,20 @@ interface iLoginUIExtension extends iLoginExtension
|
||||
|
||||
/**
|
||||
* @api
|
||||
* @package Extensibility
|
||||
* @package PreferencesExtensibilityAPI
|
||||
* @since 2.7.0
|
||||
*/
|
||||
interface iPreferencesExtension
|
||||
{
|
||||
/**
|
||||
* @api
|
||||
* @param \WebPage $oPage
|
||||
*
|
||||
*/
|
||||
public function DisplayPreferences(WebPage $oPage);
|
||||
|
||||
/**
|
||||
* @api
|
||||
* @param \WebPage $oPage
|
||||
* @param string $sOperation
|
||||
*
|
||||
@@ -252,7 +275,7 @@ interface iPreferencesExtension
|
||||
* Extend this class instead of implementing iPreferencesExtension if you don't need to overload all methods
|
||||
*
|
||||
* @api
|
||||
* @package Extensibility
|
||||
* @package PreferencesExtensibilityAPI
|
||||
* @since 2.7.0
|
||||
*/
|
||||
abstract class AbstractPreferencesExtension implements iPreferencesExtension
|
||||
@@ -298,8 +321,7 @@ abstract class AbstractPreferencesExtension implements iPreferencesExtension
|
||||
* A recommended pattern is to cache data by the mean of static members.
|
||||
*
|
||||
* @api
|
||||
* @package Extensibility
|
||||
* @deprecated
|
||||
* @package UIExtensibilityAPI
|
||||
*/
|
||||
interface iApplicationUIExtension
|
||||
{
|
||||
@@ -321,6 +343,7 @@ interface iApplicationUIExtension
|
||||
* }
|
||||
* </code>
|
||||
*
|
||||
* @api
|
||||
* @param DBObject $oObject The object being displayed
|
||||
* @param WebPage $oPage The output context
|
||||
* @param boolean $bEditMode True if the edition form is being displayed
|
||||
@@ -334,6 +357,7 @@ interface iApplicationUIExtension
|
||||
*
|
||||
* The method is called rigth after all the tabs have been displayed
|
||||
*
|
||||
* @api
|
||||
* @param DBObject $oObject The object being displayed
|
||||
* @param WebPage $oPage The output context
|
||||
* @param boolean $bEditMode True if the edition form is being displayed
|
||||
@@ -348,6 +372,7 @@ interface iApplicationUIExtension
|
||||
* The method is called after the changes from the standard form have been
|
||||
* taken into account, and before saving the changes into the database.
|
||||
*
|
||||
* @api
|
||||
* @param DBObject $oObject The object being edited
|
||||
* @param string $sFormPrefix Prefix given to the HTML form inputs
|
||||
*
|
||||
@@ -362,6 +387,7 @@ interface iApplicationUIExtension
|
||||
* javascript into the edition form, and if that code requires to store temporary data
|
||||
* (this is the case when a file must be uploaded).
|
||||
*
|
||||
* @api
|
||||
* @param string $sTempId Unique temporary identifier made of session_id and transaction_id. It identifies the object in a unique way.
|
||||
*
|
||||
* @return void
|
||||
@@ -373,6 +399,7 @@ interface iApplicationUIExtension
|
||||
*
|
||||
* Sorry, the verb has been reserved. You must implement it, but it is not called as of now.
|
||||
*
|
||||
* @api
|
||||
* @param DBObject $oObject The object being displayed
|
||||
*
|
||||
* @return string[] desc
|
||||
@@ -384,6 +411,7 @@ interface iApplicationUIExtension
|
||||
*
|
||||
* Sorry, the verb has been reserved. You must implement it, but it is not called as of now.
|
||||
*
|
||||
* @api
|
||||
* @param DBObject $oObject The object being displayed
|
||||
*
|
||||
* @return string Path of the icon, relative to the modules directory.
|
||||
@@ -403,6 +431,7 @@ interface iApplicationUIExtension
|
||||
* * HILIGHT_CLASS_OK
|
||||
* * HILIGHT_CLASS_NONE
|
||||
*
|
||||
* @api
|
||||
* @param DBObject $oObject The object being displayed
|
||||
*
|
||||
* @return integer The value representing the mood of the object
|
||||
@@ -429,6 +458,7 @@ interface iApplicationUIExtension
|
||||
*
|
||||
* See also iPopupMenuExtension for greater flexibility
|
||||
*
|
||||
* @api
|
||||
* @param DBObjectSet $oSet A set of persistent objects (DBObject)
|
||||
*
|
||||
* @return array
|
||||
@@ -440,9 +470,8 @@ interface iApplicationUIExtension
|
||||
* Extend this class instead of implementing iApplicationUIExtension if you don't need to overload
|
||||
*
|
||||
* @api
|
||||
* @package Extensibility
|
||||
* @package UIExtensibilityAPI
|
||||
* @since 2.7.0
|
||||
* @deprecated
|
||||
*/
|
||||
abstract class AbstractApplicationUIExtension implements iApplicationUIExtension
|
||||
{
|
||||
@@ -515,7 +544,7 @@ abstract class AbstractApplicationUIExtension implements iApplicationUIExtension
|
||||
* or through the GUI.
|
||||
*
|
||||
* @api
|
||||
* @package Extensibility
|
||||
* @package ORMExtensibilityAPI
|
||||
*/
|
||||
interface iApplicationObjectExtension
|
||||
{
|
||||
@@ -528,6 +557,7 @@ interface iApplicationObjectExtension
|
||||
* If the extension returns false, then the framework will perform the usual evaluation.
|
||||
* Otherwise, the answer is definitively "yes, the object has changed".
|
||||
*
|
||||
* @api
|
||||
* @param \cmdbAbstractObject $oObject The target object
|
||||
*
|
||||
* @return boolean True if something has changed for the target object
|
||||
@@ -540,6 +570,7 @@ interface iApplicationObjectExtension
|
||||
* The GUI calls this verb and reports any issue.
|
||||
* Anyhow, this API can be called in other contexts such as the CSV import tool.
|
||||
*
|
||||
* @api
|
||||
* @param \cmdbAbstractObject $oObject The target object
|
||||
*
|
||||
* @return string[] A list of errors message. An error message is made of one line and it can be displayed to the end-user.
|
||||
@@ -553,6 +584,7 @@ interface iApplicationObjectExtension
|
||||
*
|
||||
* Please not that it is not possible to cascade deletion by this mean: only stopper issues can be handled.
|
||||
*
|
||||
* @api
|
||||
* @param \cmdbAbstractObject $oObject The target object
|
||||
*
|
||||
* @return string[] A list of errors message. An error message is made of one line and it can be displayed to the end-user.
|
||||
@@ -568,6 +600,7 @@ interface iApplicationObjectExtension
|
||||
* * {@see DBObject::ListPreviousValuesForUpdatedAttributes()} : list of changed attributes and their values before the change
|
||||
* * {@see DBObject::Get()} : for a given attribute the new value that was persisted
|
||||
*
|
||||
* @api
|
||||
* @param \cmdbAbstractObject $oObject The target object
|
||||
* @param CMDBChange|null $oChange A change context. Since 2.0 it is fine to ignore it, as the framework does maintain this information
|
||||
* once for all the changes made within the current page
|
||||
@@ -583,6 +616,7 @@ interface iApplicationObjectExtension
|
||||
*
|
||||
* The method is called right <b>after</b> the object has been written to the database.
|
||||
*
|
||||
* @api
|
||||
* @param \cmdbAbstractObject $oObject The target object
|
||||
* @param CMDBChange|null $oChange A change context. Since 2.0 it is fine to ignore it, as the framework does maintain this information
|
||||
* once for all the changes made within the current page
|
||||
@@ -596,6 +630,7 @@ interface iApplicationObjectExtension
|
||||
*
|
||||
* The method is called right <b>before</b> the object will be deleted from the database.
|
||||
*
|
||||
* @api
|
||||
* @param \cmdbAbstractObject $oObject The target object
|
||||
* @param CMDBChange|null $oChange A change context. Since 2.0 it is fine to ignore it, as the framework does maintain this information
|
||||
* once for all the changes made within the current page
|
||||
@@ -609,7 +644,7 @@ interface iApplicationObjectExtension
|
||||
* Extend this class instead of iApplicationObjectExtension if you don't need to overload all methods
|
||||
*
|
||||
* @api
|
||||
* @package Extensibility
|
||||
* @package ORMExtensibilityAPI
|
||||
* @since 2.7.0
|
||||
*/
|
||||
abstract class AbstractApplicationObjectExtension implements iApplicationObjectExtension
|
||||
@@ -669,7 +704,7 @@ abstract class AbstractApplicationObjectExtension implements iApplicationObjectE
|
||||
* by the application, as long as the class definition is included somewhere in the code
|
||||
*
|
||||
* @api
|
||||
* @package Extensibility
|
||||
* @package UIExtensibilityAPI
|
||||
* @since 2.0
|
||||
*/
|
||||
interface iPopupMenuExtension
|
||||
@@ -678,18 +713,21 @@ interface iPopupMenuExtension
|
||||
* Insert an item into the Actions menu of a list
|
||||
*
|
||||
* $param is a DBObjectSet containing the list of objects
|
||||
* @api
|
||||
*/
|
||||
const MENU_OBJLIST_ACTIONS = 1;
|
||||
/**
|
||||
* Insert an item into the Toolkit menu of a list
|
||||
*
|
||||
* $param is a DBObjectSet containing the list of objects
|
||||
* @api
|
||||
*/
|
||||
const MENU_OBJLIST_TOOLKIT = 2;
|
||||
/**
|
||||
* Insert an item into the Actions menu on an object details page
|
||||
*
|
||||
* $param is a DBObject instance: the object currently displayed
|
||||
* @api
|
||||
*/
|
||||
const MENU_OBJDETAILS_ACTIONS = 3;
|
||||
/**
|
||||
@@ -699,12 +737,14 @@ interface iPopupMenuExtension
|
||||
* is being displayed.
|
||||
*
|
||||
* $param is a Dashboard instance: the dashboard currently displayed
|
||||
* @api
|
||||
*/
|
||||
const MENU_DASHBOARD_ACTIONS = 4;
|
||||
/**
|
||||
* Insert an item into the User menu (upper right corner)
|
||||
*
|
||||
* $param is null
|
||||
* @api
|
||||
*/
|
||||
const MENU_USER_ACTIONS = 5;
|
||||
/**
|
||||
@@ -712,6 +752,7 @@ interface iPopupMenuExtension
|
||||
*
|
||||
* $param is an array('portal_id' => $sPortalId, 'object' => $oObject) containing the portal id and a DBObject instance (the object on
|
||||
* the current line)
|
||||
* @api
|
||||
*/
|
||||
const PORTAL_OBJLISTITEM_ACTIONS = 7;
|
||||
/**
|
||||
@@ -719,6 +760,7 @@ interface iPopupMenuExtension
|
||||
*
|
||||
* $param is an array('portal_id' => $sPortalId, 'object' => $oObject) containing the portal id and a DBObject instance (the object
|
||||
* currently displayed)
|
||||
* @api
|
||||
*/
|
||||
const PORTAL_OBJDETAILS_ACTIONS = 8;
|
||||
|
||||
@@ -756,6 +798,7 @@ interface iPopupMenuExtension
|
||||
* This method is called by the framework for each menu.
|
||||
* The items will be inserted in the menu in the order of the returned array.
|
||||
*
|
||||
* @api
|
||||
* @param int $iMenuId The identifier of the type of menu, as listed by the constants MENU_xxx
|
||||
* @param mixed $param Depends on $iMenuId, see the constants defined above
|
||||
*
|
||||
@@ -768,7 +811,7 @@ interface iPopupMenuExtension
|
||||
* Base class for the various types of custom menus
|
||||
*
|
||||
* @api
|
||||
* @package Extensibility
|
||||
* @package UIExtensibilityAPI
|
||||
* @since 2.0
|
||||
*/
|
||||
abstract class ApplicationPopupMenuItem
|
||||
@@ -778,7 +821,7 @@ abstract class ApplicationPopupMenuItem
|
||||
/** @ignore */
|
||||
protected $sLabel;
|
||||
/** @ignore */
|
||||
protected $sTooltip;
|
||||
protected $sTooltip;
|
||||
/** @ignore */
|
||||
protected $sIconClass;
|
||||
/** @ignore */
|
||||
@@ -835,6 +878,7 @@ abstract class ApplicationPopupMenuItem
|
||||
}
|
||||
|
||||
/**
|
||||
* @api
|
||||
* @param $aCssClasses
|
||||
*/
|
||||
public function SetCssClasses($aCssClasses)
|
||||
@@ -845,6 +889,7 @@ abstract class ApplicationPopupMenuItem
|
||||
/**
|
||||
* Adds a CSS class to the CSS classes that will be put on the menu item
|
||||
*
|
||||
* @api
|
||||
* @param $sCssClass
|
||||
*/
|
||||
public function AddCssClass($sCssClass)
|
||||
@@ -855,7 +900,7 @@ abstract class ApplicationPopupMenuItem
|
||||
|
||||
/**
|
||||
* @param $sTooltip
|
||||
*
|
||||
*
|
||||
* @since 3.0.0
|
||||
*/
|
||||
public function SetTooltip($sTooltip)
|
||||
@@ -865,24 +910,24 @@ abstract class ApplicationPopupMenuItem
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*
|
||||
*
|
||||
* @since 3.0.0
|
||||
*/
|
||||
public function GetTooltip()
|
||||
{
|
||||
return $this->sTooltip;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $sIconClass
|
||||
*
|
||||
*
|
||||
* @since 3.0.0
|
||||
*/
|
||||
public function SetIconClass($sIconClass)
|
||||
{
|
||||
$this->sIconClass = $sIconClass;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*
|
||||
@@ -892,7 +937,7 @@ abstract class ApplicationPopupMenuItem
|
||||
{
|
||||
return $this->sIconClass;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the components to create a popup menu item in HTML
|
||||
*
|
||||
@@ -914,7 +959,7 @@ abstract class ApplicationPopupMenuItem
|
||||
* Note: This works only in the backoffice, {@see \URLButtonItem} for the end-user portal
|
||||
*
|
||||
* @api
|
||||
* @package Extensibility
|
||||
* @package UIExtensibilityAPI
|
||||
* @since 2.0
|
||||
*/
|
||||
class URLPopupMenuItem extends ApplicationPopupMenuItem
|
||||
@@ -927,6 +972,7 @@ class URLPopupMenuItem extends ApplicationPopupMenuItem
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @api
|
||||
* @param string $sUID The unique identifier of this menu in iTop... make sure you pass something unique enough
|
||||
* @param string $sLabel The display label of the menu (must be localized)
|
||||
* @param string $sUrl If the menu is an hyperlink, provide the absolute hyperlink here
|
||||
@@ -950,7 +996,7 @@ class URLPopupMenuItem extends ApplicationPopupMenuItem
|
||||
'tooltip' => $this->sTooltip
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/** @ignore */
|
||||
public function GetUrl()
|
||||
{
|
||||
@@ -970,7 +1016,7 @@ class URLPopupMenuItem extends ApplicationPopupMenuItem
|
||||
* Note: This works only in the backoffice, {@see \JSButtonItem} for the end-user portal
|
||||
*
|
||||
* @api
|
||||
* @package Extensibility
|
||||
* @package UIExtensibilityAPI
|
||||
* @since 2.0
|
||||
*/
|
||||
class JSPopupMenuItem extends ApplicationPopupMenuItem
|
||||
@@ -1020,13 +1066,13 @@ class JSPopupMenuItem extends ApplicationPopupMenuItem
|
||||
{
|
||||
return $this->aIncludeJSFiles;
|
||||
}
|
||||
|
||||
|
||||
/** @ignore */
|
||||
public function GetJsCode()
|
||||
{
|
||||
return $this->sJsCode;
|
||||
}
|
||||
|
||||
|
||||
/** @ignore */
|
||||
public function GetUrl()
|
||||
{
|
||||
@@ -1039,7 +1085,7 @@ class JSPopupMenuItem extends ApplicationPopupMenuItem
|
||||
* will automatically reduce several consecutive separators to just one
|
||||
*
|
||||
* @api
|
||||
* @package Extensibility
|
||||
* @package UIExtensibilityAPI
|
||||
* @since 2.0
|
||||
*/
|
||||
class SeparatorPopupMenuItem extends ApplicationPopupMenuItem
|
||||
@@ -1048,6 +1094,7 @@ class SeparatorPopupMenuItem extends ApplicationPopupMenuItem
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
* @api
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
@@ -1065,7 +1112,7 @@ class SeparatorPopupMenuItem extends ApplicationPopupMenuItem
|
||||
* Class for adding an item as a button that browses to the given URL
|
||||
*
|
||||
* @api
|
||||
* @package Extensibility
|
||||
* @package UIExtensibilityAPI
|
||||
* @since 2.0
|
||||
*/
|
||||
class URLButtonItem extends URLPopupMenuItem
|
||||
@@ -1077,7 +1124,7 @@ class URLButtonItem extends URLPopupMenuItem
|
||||
* Class for adding an item as a button that runs some JS code
|
||||
*
|
||||
* @api
|
||||
* @package Extensibility
|
||||
* @package UIExtensibilityAPI
|
||||
* @since 2.0
|
||||
*/
|
||||
class JSButtonItem extends JSPopupMenuItem
|
||||
@@ -1101,7 +1148,7 @@ class JSButtonItem extends JSPopupMenuItem
|
||||
* the specified place and can use the passed iTopWebPage object to add javascript or CSS definitions
|
||||
*
|
||||
* @api
|
||||
* @package Extensibility
|
||||
* @package UIExtensibilityAPI
|
||||
* @since 2.0
|
||||
* @deprecated 3.0.0 If you need to include:
|
||||
* * JS/CSS files/snippets, use {@see \iBackofficeLinkedScriptsExtension}, {@see \iBackofficeLinkedStylesheetsExtension}, etc instead
|
||||
@@ -1112,6 +1159,7 @@ interface iPageUIExtension
|
||||
/**
|
||||
* Add content to the header of the page
|
||||
*
|
||||
* @api
|
||||
* @param iTopWebPage $oPage The page to insert stuff into.
|
||||
*
|
||||
* @return string The HTML content to add into the page
|
||||
@@ -1121,6 +1169,7 @@ interface iPageUIExtension
|
||||
/**
|
||||
* Add content to the footer of the page
|
||||
*
|
||||
* @api
|
||||
* @param iTopWebPage $oPage The page to insert stuff into.
|
||||
*
|
||||
* @return string The HTML content to add into the page
|
||||
@@ -1130,6 +1179,7 @@ interface iPageUIExtension
|
||||
/**
|
||||
* Add content to the "admin banner"
|
||||
*
|
||||
* @api
|
||||
* @param iTopWebPage $oPage The page to insert stuff into.
|
||||
*
|
||||
* @return string The HTML content to add into the page
|
||||
@@ -1153,7 +1203,7 @@ interface iPageUIExtension
|
||||
* the specified place and can use the passed iTopWebPage object to add javascript or CSS definitions
|
||||
*
|
||||
* @api
|
||||
* @package Extensibility
|
||||
* @package UIBlockExtensibilityAPI
|
||||
* @since 3.0.0
|
||||
*/
|
||||
interface iPageUIBlockExtension
|
||||
@@ -1184,9 +1234,9 @@ interface iPageUIBlockExtension
|
||||
* Extend this class instead of iPageUIExtension if you don't need to overload all methods
|
||||
*
|
||||
* @api
|
||||
* @package Extensibility
|
||||
* @package UIExtensibilityAPI
|
||||
* @since 2.7.0
|
||||
* @deprecated 3.0.0 use AbstractPageUIBlockExtension instead
|
||||
* @deprecated since 3.0.0 use AbstractPageUIBlockExtension instead
|
||||
*/
|
||||
abstract class AbstractPageUIExtension implements iPageUIExtension
|
||||
{
|
||||
@@ -1226,7 +1276,7 @@ abstract class AbstractPageUIExtension implements iPageUIExtension
|
||||
* Extend this class instead of iPageUIExtension if you don't need to overload all methods
|
||||
*
|
||||
* @api
|
||||
* @package Extensibility
|
||||
* @package UIBlockExtensibilityAPI
|
||||
* @since 3.0.0
|
||||
*/
|
||||
abstract class AbstractPageUIBlockExtension implements iPageUIBlockExtension
|
||||
@@ -1261,6 +1311,7 @@ abstract class AbstractPageUIBlockExtension implements iPageUIBlockExtension
|
||||
*
|
||||
* @see \iTopWebPage::$a_linked_scripts
|
||||
* @api
|
||||
* @package BackofficeUIExtensibilityAPI
|
||||
* @since 3.0.0
|
||||
*/
|
||||
interface iBackofficeLinkedScriptsExtension
|
||||
@@ -1278,6 +1329,7 @@ interface iBackofficeLinkedScriptsExtension
|
||||
*
|
||||
* @see \iTopWebPage::$a_early_scripts
|
||||
* @api
|
||||
* @package BackofficeUIExtensibilityAPI
|
||||
* @since 3.0.0
|
||||
*/
|
||||
interface iBackofficeEarlyScriptExtension
|
||||
@@ -1294,6 +1346,7 @@ interface iBackofficeEarlyScriptExtension
|
||||
*
|
||||
* @see \iTopWebPage::$a_scripts
|
||||
* @api
|
||||
* @package BackofficeUIExtensibilityAPI
|
||||
* @since 3.0.0
|
||||
*/
|
||||
interface iBackofficeScriptExtension
|
||||
@@ -1310,6 +1363,7 @@ interface iBackofficeScriptExtension
|
||||
*
|
||||
* @see \iTopWebPage::$a_init_scripts
|
||||
* @api
|
||||
* @package BackofficeUIExtensibilityAPI
|
||||
* @since 3.0.0
|
||||
*/
|
||||
interface iBackofficeInitScriptExtension
|
||||
@@ -1326,6 +1380,7 @@ interface iBackofficeInitScriptExtension
|
||||
*
|
||||
* @see \iTopWebPage::$a_ready_scripts
|
||||
* @api
|
||||
* @package BackofficeUIExtensibilityAPI
|
||||
* @since 3.0.0
|
||||
*/
|
||||
interface iBackofficeReadyScriptExtension
|
||||
@@ -1342,6 +1397,7 @@ interface iBackofficeReadyScriptExtension
|
||||
*
|
||||
* @see \iTopWebPage::$a_linked_stylesheets
|
||||
* @api
|
||||
* @package BackofficeUIExtensibilityAPI
|
||||
* @since 3.0.0
|
||||
*/
|
||||
interface iBackofficeLinkedStylesheetsExtension
|
||||
@@ -1358,6 +1414,7 @@ interface iBackofficeLinkedStylesheetsExtension
|
||||
*
|
||||
* @see \iTopWebPage::$a_styles
|
||||
* @api
|
||||
* @package BackofficeUIExtensibilityAPI
|
||||
* @since 3.0.0
|
||||
*/
|
||||
interface iBackofficeStyleExtension
|
||||
@@ -1374,6 +1431,7 @@ interface iBackofficeStyleExtension
|
||||
*
|
||||
* @see \iTopWebPage::$a_dict_entries
|
||||
* @api
|
||||
* @package BackofficeUIExtensibilityAPI
|
||||
* @since 3.0.0
|
||||
*/
|
||||
interface iBackofficeDictEntriesExtension
|
||||
@@ -1390,6 +1448,7 @@ interface iBackofficeDictEntriesExtension
|
||||
*
|
||||
* @see \iTopWebPage::$a_dict_entries_prefixes
|
||||
* @api
|
||||
* @package BackofficeUIExtensibilityAPI
|
||||
* @since 3.0.0
|
||||
*/
|
||||
interface iBackofficeDictEntriesPrefixesExtension
|
||||
@@ -1405,7 +1464,7 @@ interface iBackofficeDictEntriesPrefixesExtension
|
||||
* Implement this interface to add content to any enhanced portal page
|
||||
*
|
||||
* @api
|
||||
* @package Extensibility
|
||||
* @package PortalExtensibilityAPI
|
||||
*
|
||||
* @since 2.4.0 interface creation
|
||||
* @since 2.7.0 change method signatures due to Silex to Symfony migration
|
||||
@@ -1419,6 +1478,7 @@ interface iPortalUIExtension
|
||||
/**
|
||||
* Returns an array of CSS file urls
|
||||
*
|
||||
* @api
|
||||
* @param \Symfony\Component\DependencyInjection\Container $oContainer
|
||||
*
|
||||
* @return array
|
||||
@@ -1428,6 +1488,7 @@ interface iPortalUIExtension
|
||||
/**
|
||||
* Returns inline (raw) CSS
|
||||
*
|
||||
* @api
|
||||
* @param \Symfony\Component\DependencyInjection\Container $oContainer
|
||||
*
|
||||
* @return string
|
||||
@@ -1437,6 +1498,7 @@ interface iPortalUIExtension
|
||||
/**
|
||||
* Returns an array of JS file urls
|
||||
*
|
||||
* @api
|
||||
* @param \Symfony\Component\DependencyInjection\Container $oContainer
|
||||
*
|
||||
* @return array
|
||||
@@ -1446,6 +1508,7 @@ interface iPortalUIExtension
|
||||
/**
|
||||
* Returns raw JS code
|
||||
*
|
||||
* @api
|
||||
* @param \Symfony\Component\DependencyInjection\Container $oContainer
|
||||
*
|
||||
* @return string
|
||||
@@ -1455,6 +1518,7 @@ interface iPortalUIExtension
|
||||
/**
|
||||
* Returns raw HTML code to put at the end of the <body> tag
|
||||
*
|
||||
* @api
|
||||
* @param \Symfony\Component\DependencyInjection\Container $oContainer
|
||||
*
|
||||
* @return string
|
||||
@@ -1464,6 +1528,7 @@ interface iPortalUIExtension
|
||||
/**
|
||||
* Returns raw HTML code to put at the end of the #main-wrapper element
|
||||
*
|
||||
* @api
|
||||
* @param \Symfony\Component\DependencyInjection\Container $oContainer
|
||||
*
|
||||
* @return string
|
||||
@@ -1473,6 +1538,7 @@ interface iPortalUIExtension
|
||||
/**
|
||||
* Returns raw HTML code to put at the end of the #topbar and #sidebar elements
|
||||
*
|
||||
* @api
|
||||
* @param \Symfony\Component\DependencyInjection\Container $oContainer
|
||||
*
|
||||
* @return string
|
||||
@@ -1484,7 +1550,7 @@ interface iPortalUIExtension
|
||||
* Extend this class instead of iPortalUIExtension if you don't need to overload all methods
|
||||
*
|
||||
* @api
|
||||
* @package Extensibility
|
||||
* @package PortalExtensibilityAPI
|
||||
* @since 2.4.0
|
||||
*/
|
||||
abstract class AbstractPortalUIExtension implements iPortalUIExtension
|
||||
@@ -1550,7 +1616,7 @@ abstract class AbstractPortalUIExtension implements iPortalUIExtension
|
||||
* Implement this interface to add new operations to the REST/JSON web service
|
||||
*
|
||||
* @api
|
||||
* @package Extensibility
|
||||
* @package RESTExtensibilityAPI
|
||||
* @since 2.0.1
|
||||
*/
|
||||
interface iRestServiceProvider
|
||||
@@ -1558,6 +1624,7 @@ interface iRestServiceProvider
|
||||
/**
|
||||
* Enumerate services delivered by this class
|
||||
*
|
||||
* @api
|
||||
* @param string $sVersion The version (e.g. 1.0) supported by the services
|
||||
*
|
||||
* @return array An array of hash 'verb' => verb, 'description' => description
|
||||
@@ -1567,6 +1634,7 @@ interface iRestServiceProvider
|
||||
/**
|
||||
* Enumerate services delivered by this class
|
||||
*
|
||||
* @api
|
||||
* @param string $sVersion The version (e.g. 1.0) supported by the services
|
||||
* @param string $sVerb
|
||||
* @param array $aParams
|
||||
@@ -1580,69 +1648,90 @@ interface iRestServiceProvider
|
||||
* Minimal REST response structure. Derive this structure to add response data and error codes.
|
||||
*
|
||||
* @api
|
||||
* @package Extensibility
|
||||
* @package RESTExtensibilityAPI
|
||||
* @since 2.0.1
|
||||
*/
|
||||
class RestResult
|
||||
{
|
||||
/**
|
||||
* Result: no issue has been encountered
|
||||
* @api
|
||||
*/
|
||||
const OK = 0;
|
||||
/**
|
||||
* Result: missing/wrong credentials or the user does not have enough rights to perform the requested operation
|
||||
* @api
|
||||
*/
|
||||
const UNAUTHORIZED = 1;
|
||||
/**
|
||||
* Result: the parameter 'version' is missing
|
||||
* @api
|
||||
*/
|
||||
const MISSING_VERSION = 2;
|
||||
/**
|
||||
* Result: the parameter 'json_data' is missing
|
||||
* @api
|
||||
*/
|
||||
const MISSING_JSON = 3;
|
||||
/**
|
||||
* Result: the input structure is not a valid JSON string
|
||||
* @api
|
||||
*/
|
||||
const INVALID_JSON = 4;
|
||||
/**
|
||||
* Result: the parameter 'auth_user' is missing, authentication aborted
|
||||
* @api
|
||||
*/
|
||||
const MISSING_AUTH_USER = 5;
|
||||
/**
|
||||
* Result: the parameter 'auth_pwd' is missing, authentication aborted
|
||||
* @api
|
||||
*/
|
||||
const MISSING_AUTH_PWD = 6;
|
||||
/**
|
||||
* Result: no operation is available for the specified version
|
||||
* @api
|
||||
*/
|
||||
const UNSUPPORTED_VERSION = 10;
|
||||
/**
|
||||
* Result: the requested operation is not valid for the specified version
|
||||
* @api
|
||||
*/
|
||||
const UNKNOWN_OPERATION = 11;
|
||||
/**
|
||||
* Result: the requested operation cannot be performed because it can cause data (integrity) loss
|
||||
* @api
|
||||
*/
|
||||
const UNSAFE = 12;
|
||||
/**
|
||||
* Result: the request page number is not valid. It must be an integer greater than 0
|
||||
* @api
|
||||
*/
|
||||
const INVALID_PAGE = 13;
|
||||
/**
|
||||
* Result: the operation could not be performed, see the message for troubleshooting
|
||||
* @api
|
||||
*/
|
||||
const INTERNAL_ERROR = 100;
|
||||
|
||||
/**
|
||||
* Default constructor - ok!
|
||||
* @api
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->code = RestResult::OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @var int
|
||||
* @api
|
||||
*/
|
||||
public $code;
|
||||
/**
|
||||
* @var string
|
||||
* @api
|
||||
*/
|
||||
public $message;
|
||||
}
|
||||
|
||||
@@ -1650,7 +1739,7 @@ class RestResult
|
||||
* Helpers for implementing REST services
|
||||
*
|
||||
* @api
|
||||
* @package Extensibility
|
||||
* @package RESTExtensibilityAPI
|
||||
*/
|
||||
class RestUtils
|
||||
{
|
||||
@@ -1799,6 +1888,7 @@ class RestUtils
|
||||
/**
|
||||
* Read and interpret object search criteria from a Rest/Json structure
|
||||
*
|
||||
* @api
|
||||
* @param string $sClass Name of the class
|
||||
* @param StdClass $oCriteria Hash of attribute code => value (can be a substructure or a scalar, depending on the nature of the
|
||||
* attriute)
|
||||
@@ -1908,6 +1998,7 @@ class RestUtils
|
||||
/**
|
||||
* Search objects from a polymorph search specification (Rest/Json)
|
||||
*
|
||||
* @api
|
||||
* @param string $sClass Name of the class
|
||||
* @param mixed $key Either search criteria (substructure), or an object or an OQL string.
|
||||
* @param int $iLimit The limit of results to return
|
||||
@@ -2094,4 +2185,4 @@ class RestUtils
|
||||
interface iModuleExtension
|
||||
{
|
||||
public function __construct();
|
||||
}
|
||||
}
|
||||
@@ -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');
|
||||
@@ -1,6 +1,6 @@
|
||||
<?php
|
||||
/*
|
||||
* @copyright Copyright (C) 2010-2022 Combodo SARL
|
||||
* @copyright Copyright (C) 2010-2021 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
@@ -42,7 +42,6 @@ use Combodo\iTop\Application\UI\Base\Layout\UIContentBlockUIBlockFactory;
|
||||
use Combodo\iTop\Renderer\BlockRenderer;
|
||||
use Combodo\iTop\Renderer\Console\ConsoleFormRenderer;
|
||||
|
||||
|
||||
define('OBJECT_PROPERTIES_TAB', 'ObjectProperties');
|
||||
|
||||
define('HILIGHT_CLASS_CRITICAL', 'red');
|
||||
@@ -61,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
|
||||
@@ -517,6 +516,32 @@ 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
|
||||
*
|
||||
@@ -677,26 +702,33 @@ HTML
|
||||
$sTargetClass = $oLinkingAttDef->GetTargetClass();
|
||||
// n:n links => must be allowed to modify the linking class AND read the target class in order to edit the linkedset
|
||||
if (!UserRights::IsActionAllowed($sLinkedClass,
|
||||
UR_ACTION_MODIFY) || !UserRights::IsActionAllowed($sTargetClass, UR_ACTION_READ)) {
|
||||
UR_ACTION_MODIFY) || !UserRights::IsActionAllowed($sTargetClass, UR_ACTION_READ))
|
||||
{
|
||||
$iFlags |= OPT_ATT_READONLY;
|
||||
}
|
||||
// n:n links => must be allowed to read the linking class AND the target class in order to display the linkedset
|
||||
if (!UserRights::IsActionAllowed($sLinkedClass,
|
||||
UR_ACTION_READ) || !UserRights::IsActionAllowed($sTargetClass, UR_ACTION_READ)) {
|
||||
UR_ACTION_READ) || !UserRights::IsActionAllowed($sTargetClass, UR_ACTION_READ))
|
||||
{
|
||||
$iFlags |= OPT_ATT_HIDDEN;
|
||||
}
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
// 1:n links => must be allowed to modify the linked class in order to edit the linkedset
|
||||
if (!UserRights::IsActionAllowed($sLinkedClass, UR_ACTION_MODIFY)) {
|
||||
if (!UserRights::IsActionAllowed($sLinkedClass, UR_ACTION_MODIFY))
|
||||
{
|
||||
$iFlags |= OPT_ATT_READONLY;
|
||||
}
|
||||
// 1:n links => must be allowed to read the linked class in order to display the linkedset
|
||||
if (!UserRights::IsActionAllowed($sLinkedClass, UR_ACTION_READ)) {
|
||||
if (!UserRights::IsActionAllowed($sLinkedClass, UR_ACTION_READ))
|
||||
{
|
||||
$iFlags |= OPT_ATT_HIDDEN;
|
||||
}
|
||||
}
|
||||
// Non-readable/hidden linkedset... don't display anything
|
||||
if ($iFlags & OPT_ATT_HIDDEN) {
|
||||
if ($iFlags & OPT_ATT_HIDDEN)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -705,13 +737,17 @@ HTML
|
||||
|
||||
$aArgs = array('this' => $this);
|
||||
$bReadOnly = ($iFlags & (OPT_ATT_READONLY | OPT_ATT_SLAVE));
|
||||
if ($bEditMode && (!$bReadOnly)) {
|
||||
if ($bEditMode && (!$bReadOnly))
|
||||
{
|
||||
$sInputId = $this->m_iFormId.'_'.$sAttCode;
|
||||
|
||||
if ($oAttDef->IsIndirect()) {
|
||||
if ($oAttDef->IsIndirect())
|
||||
{
|
||||
$oLinkingAttDef = MetaModel::GetAttributeDef($sLinkedClass, $oAttDef->GetExtKeyToRemote());
|
||||
$sTargetClass = $oLinkingAttDef->GetTargetClass();
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
$sTargetClass = $sLinkedClass;
|
||||
}
|
||||
|
||||
@@ -721,7 +757,7 @@ HTML
|
||||
|
||||
$sDisplayValue = ''; // not used
|
||||
$sHTMLValue = "<span id=\"field_{$sInputId}\">".self::GetFormElementForField($oPage, $sClass, $sAttCode,
|
||||
$oAttDef, $oOrmLinkSet, $sDisplayValue, $sInputId, '', $iFlags, $aArgs).'</span>';
|
||||
$oAttDef, $oLinkSet, $sDisplayValue, $sInputId, '', $iFlags, $aArgs).'</span>';
|
||||
$this->AddToFieldsMap($sAttCode, $sInputId);
|
||||
$oPage->add($sHTMLValue);
|
||||
}
|
||||
@@ -977,8 +1013,10 @@ HTML
|
||||
$this->GetSynchroReplicaFlags($sAttCode, $aReasons);
|
||||
$sTip = '';
|
||||
foreach ($aReasons as $aRow) {
|
||||
$sDescription = utils::EscapeHtml($aRow['description']);
|
||||
$sDescription = str_replace(array("\r\n", "\n"), "<br/>", $sDescription);
|
||||
$sDescription = htmlentities($aRow['description'], ENT_QUOTES,
|
||||
'UTF-8');
|
||||
$sDescription = str_replace(array("\r\n", "\n"), "<br/>",
|
||||
$sDescription);
|
||||
$sTip .= "<div class='synchro-source'>";
|
||||
$sTip .= "<div class='synchro-source-title'>Synchronized with {$aRow['name']}</div>";
|
||||
$sTip .= "<div class='synchro-source-description'>$sDescription</div>";
|
||||
@@ -1155,6 +1193,8 @@ 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.
|
||||
@@ -1391,7 +1431,7 @@ HTML
|
||||
} else {
|
||||
if ($oAttDef instanceof AttributeCaseLog) {
|
||||
$rawValue = $oObj->Get($sAttCodeEx);
|
||||
$outputValue = str_replace("\n", "<br/>", utils::EscapeHtml($rawValue->__toString()));
|
||||
$outputValue = str_replace("\n", "<br/>", htmlentities($rawValue->__toString(), ENT_QUOTES, 'UTF-8'));
|
||||
// Trick for Excel: treat the content as text even if it begins with an equal sign
|
||||
$aRow[$oAttDef->GetCode()] = $outputValue;
|
||||
} else {
|
||||
@@ -1405,9 +1445,9 @@ HTML
|
||||
}
|
||||
}
|
||||
if ($bLocalize) {
|
||||
$outputValue = utils::EscapeHtml($oFinalAttDef->GetEditValue($rawValue));
|
||||
$outputValue = htmlentities($oFinalAttDef->GetEditValue($rawValue), ENT_QUOTES, 'UTF-8');
|
||||
} else {
|
||||
$outputValue = utils::EscapeHtml($rawValue);
|
||||
$outputValue = htmlentities($rawValue, ENT_QUOTES, 'UTF-8');
|
||||
}
|
||||
$aRow[$oAttDef->GetCode()] = $outputValue;
|
||||
}
|
||||
@@ -1443,7 +1483,7 @@ HTML
|
||||
* @throws \MissingQueryArgument
|
||||
* @throws \MySQLException
|
||||
* @throws \MySQLHasGoneAwayException
|
||||
* @deprecated 3.0.0
|
||||
* @deprecated since 3.0.0
|
||||
*/
|
||||
public static function GetDisplayExtendedSet(WebPage $oPage, CMDBObjectSet $oSet, $aExtraParams = array())
|
||||
{
|
||||
@@ -1883,7 +1923,7 @@ HTML
|
||||
{
|
||||
$rawValue = $oObj->Get($sAttCodeEx);
|
||||
$outputValue = str_replace("\n", "<br/>",
|
||||
utils::EscapeHtml($rawValue->__toString()));
|
||||
htmlentities($rawValue->__toString(), ENT_QUOTES, 'UTF-8'));
|
||||
// Trick for Excel: treat the content as text even if it begins with an equal sign
|
||||
$aRow[] = '<td x:str>'.$outputValue.'</td>';
|
||||
}
|
||||
@@ -1900,11 +1940,14 @@ HTML
|
||||
$rawValue = '';
|
||||
}
|
||||
}
|
||||
if ($bLocalize) {
|
||||
$outputValue = utils::EscapeHtml($oFinalAttDef->GetEditValue($rawValue));
|
||||
if ($bLocalize)
|
||||
{
|
||||
$outputValue = htmlentities($oFinalAttDef->GetEditValue($rawValue), ENT_QUOTES,
|
||||
'UTF-8');
|
||||
}
|
||||
else {
|
||||
$outputValue = utils::EscapeHtml($rawValue);
|
||||
else
|
||||
{
|
||||
$outputValue = htmlentities($rawValue, ENT_QUOTES, 'UTF-8');
|
||||
}
|
||||
$aRow[] = '<td>'.$outputValue.'</td>';
|
||||
}
|
||||
@@ -2141,7 +2184,7 @@ HTML;
|
||||
$sHours = "<input class=\"ibo-input ibo-input-duration\" title=\"$sHelpText\" type=\"text\" size=\"2\" name=\"attr_{$sFieldPrefix}{$sAttCode}[h]{$sNameSuffix}\" value=\"{$aVal['hours']}\" id=\"{$iId}_h\"/>";
|
||||
$sMinutes = "<input class=\"ibo-input ibo-input-duration\" title=\"$sHelpText\" type=\"text\" size=\"2\" name=\"attr_{$sFieldPrefix}{$sAttCode}[m]{$sNameSuffix}\" value=\"{$aVal['minutes']}\" id=\"{$iId}_m\"/>";
|
||||
$sSeconds = "<input class=\"ibo-input ibo-input-duration\" title=\"$sHelpText\" type=\"text\" size=\"2\" name=\"attr_{$sFieldPrefix}{$sAttCode}[s]{$sNameSuffix}\" value=\"{$aVal['seconds']}\" id=\"{$iId}_s\"/>";
|
||||
$sHidden = "<input type=\"hidden\" id=\"{$iId}\" value=\"".utils::EscapeHtml($value)."\"/>";
|
||||
$sHidden = "<input type=\"hidden\" id=\"{$iId}\" value=\"".htmlentities($value, ENT_QUOTES, 'UTF-8')."\"/>";
|
||||
$sHTMLValue = Dict::Format('UI:DurationForm_Days_Hours_Minutes_Seconds', $sDays, $sHours, $sMinutes, $sSeconds).$sHidden." ".$sValidationSpan.$sReloadSpan;
|
||||
$oPage->add_ready_script("$('#{$iId}').on('update', function(evt, sFormId) { return ToggleDurationField('$iId'); });");
|
||||
break;
|
||||
@@ -2151,7 +2194,8 @@ HTML;
|
||||
$aEventsList[] = 'validate';
|
||||
$aEventsList[] = 'keyup';
|
||||
$aEventsList[] = 'change';
|
||||
$sHTMLValue = "<div class=\"field_input_zone field_input_password ibo-input-wrapper ibo-input-password-wrapper\" data-validation=\"untouched\"><input class=\"ibo-input ibo-input-password\" title=\"$sHelpText\" type=\"password\" name=\"attr_{$sFieldPrefix}{$sAttCode}{$sNameSuffix}\" value=\"".utils::EscapeHtml($value)."\" id=\"$iId\"/></div>{$sValidationSpan}{$sReloadSpan}";
|
||||
$sHTMLValue = "<div class=\"field_input_zone field_input_password ibo-input-wrapper ibo-input-password-wrapper\" data-validation=\"untouched\"><input class=\"ibo-input ibo-input-password\" title=\"$sHelpText\" type=\"password\" name=\"attr_{$sFieldPrefix}{$sAttCode}{$sNameSuffix}\" value=\"".htmlentities($value,
|
||||
ENT_QUOTES, 'UTF-8')."\" id=\"$iId\"/></div>{$sValidationSpan}{$sReloadSpan}";
|
||||
break;
|
||||
|
||||
case 'OQLExpression':
|
||||
@@ -2303,13 +2347,13 @@ EOF
|
||||
|
||||
$sHeader = '<div class="ibo-caselog-entry-form--actions"><div class="""ibo-caselog-entry-form--actions" data-role="ibo-caselog-entry-form--action-buttons--extra-actions"></div></div>'; // will be hidden in CSS (via :empty) if it remains empty
|
||||
$sEditValue = is_object($value) ? $value->GetModifiedEntry('html') : '';
|
||||
$sPreviousLog = is_object($value) ? $value->GetAsHTML($oPage, true /* bEditMode */, array('AttributeText', 'RenderWikiHtml')) : '';
|
||||
$sPreviousLog = is_object($value) ? $value->GetAsHTML($oPage, true /* bEditMode */, array('AttributeText', 'RenderWikiHtml')) : '';
|
||||
$iEntriesCount = is_object($value) ? count($value->GetIndex()) : 0;
|
||||
$sHidden = "<input type=\"hidden\" id=\"{$iId}_count\" value=\"$iEntriesCount\"/>"; // To know how many entries the case log already contains
|
||||
|
||||
$sHTMLValue = "$sHeader<div class=\"ibo-caselog-entry-form--text-input\" $sStyle data-role=\"ibo-caselog-entry-form--text-input\">";
|
||||
$sHTMLValue .= "<textarea class=\"htmlEditor ibo-input-richtext-placeholder\" style=\"border:0;width:100%\" title=\"$sHelpText\" name=\"attr_{$sFieldPrefix}{$sAttCode}{$sNameSuffix}\" rows=\"8\" cols=\"40\" id=\"$iId\">".utils::EscapeHtml($sEditValue)."</textarea>";
|
||||
$sHTMLValue .= "$sPreviousLog</div>{$sValidationSpan}{$sReloadSpan}$sHidden";
|
||||
$sHTMLValue .= "<textarea class=\"htmlEditor ibo-input-richtext-placeholder\" style=\"border:0;width:100%\" title=\"$sHelpText\" name=\"attr_{$sFieldPrefix}{$sAttCode}{$sNameSuffix}\" rows=\"8\" cols=\"40\" id=\"$iId\">".htmlentities($sEditValue,ENT_QUOTES,'UTF-8')."</textarea>";
|
||||
$sHTMLValue .= "$sPreviousLog</div>{$sValidationSpan}{$sReloadSpan}$sHidden";
|
||||
|
||||
// Note: This should be refactored for all types of attribute (see at the end of this function) but as we are doing this for a maintenance release, we are scheduling it for the next main release in to order to avoid regressions as much as possible.
|
||||
$sNullValue = $oAttDef->GetNullValue();
|
||||
@@ -2366,7 +2410,8 @@ EOF
|
||||
case 'LinkedSet':
|
||||
$sInputType = self::ENUM_INPUT_TYPE_LINKEDSET;
|
||||
if ($oAttDef->IsIndirect()) {
|
||||
$oWidget = new UILinksWidget($sClass, $sAttCode, $iId, $sNameSuffix, $oAttDef->DuplicatesAllowed());
|
||||
$oWidget = new UILinksWidget($sClass, $sAttCode, $iId, $sNameSuffix,
|
||||
$oAttDef->DuplicatesAllowed());
|
||||
} else {
|
||||
$oWidget = new UILinksWidgetDirect($sClass, $sAttCode, $iId, $sNameSuffix);
|
||||
}
|
||||
@@ -2553,16 +2598,16 @@ JS
|
||||
|
||||
case 'Set':
|
||||
case 'TagSet':
|
||||
$sInputType = self::ENUM_INPUT_TYPE_TAGSET;
|
||||
$oPage->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/selectize.min.js');
|
||||
$oPage->add_linked_stylesheet(utils::GetAbsoluteUrlAppRoot().'css/selectize.default.css');
|
||||
$oPage->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/jquery.itop-set-widget.js');
|
||||
$sInputType = self::ENUM_INPUT_TYPE_TAGSET;
|
||||
$oPage->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/selectize.min.js');
|
||||
$oPage->add_linked_stylesheet(utils::GetAbsoluteUrlAppRoot().'css/selectize.default.css');
|
||||
$oPage->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/jquery.itop-set-widget.js');
|
||||
|
||||
$oPage->add_dict_entry('Core:AttributeSet:placeholder');
|
||||
$oPage->add_dict_entry('Core:AttributeSet:placeholder');
|
||||
|
||||
/** @var \ormSet $value */
|
||||
/** @var \ormSet $value */
|
||||
$sJson = $oAttDef->GetJsonForWidget($value, $aArgs);
|
||||
$sEscapedJson = utils::EscapeHtml($sJson);
|
||||
$sEscapedJson = htmlentities($sJson, ENT_QUOTES, 'UTF-8');
|
||||
$sSetInputName = "attr_{$sFormPrefix}{$sAttCode}";
|
||||
|
||||
// handle form validation
|
||||
@@ -3329,13 +3374,14 @@ EOF
|
||||
// Consider only the "expected" fields for the target state
|
||||
if (array_key_exists($sAttCode, $aExpectedAttributes)) {
|
||||
$iExpectCode = $aExpectedAttributes[$sAttCode];
|
||||
|
||||
// Prompt for an attribute if
|
||||
// - the attribute must be changed or must be displayed to the user for confirmation
|
||||
// - or the field is mandatory and currently empty
|
||||
if (($iExpectCode & (OPT_ATT_MUSTCHANGE | OPT_ATT_MUSTPROMPT)) ||
|
||||
(($iExpectCode & OPT_ATT_MANDATORY) && ($this->Get($sAttCode) == ''))) {
|
||||
$oAttDef = MetaModel::GetAttributeDef($sClass, $sAttCode);
|
||||
(($iExpectCode & OPT_ATT_MANDATORY) && (false === $this->HasAValue($sAttCode)))) {
|
||||
$aArgs = array('this' => $this);
|
||||
$oAttDef = MetaModel::GetAttributeDef($sClass, $sAttCode);
|
||||
// If the field is mandatory, set it to the only possible value
|
||||
if ((!$oAttDef->IsNullAllowed()) || ($iExpectCode & OPT_ATT_MANDATORY)) {
|
||||
if ($oAttDef->IsExternalKey()) {
|
||||
@@ -3364,32 +3410,35 @@ EOF
|
||||
}
|
||||
}
|
||||
}
|
||||
$sInputType = '';
|
||||
$sInputId = 'att_'.$iFieldIndex;
|
||||
$sHTMLValue = cmdbAbstractObject::GetFormElementForField($oPage, $sClass, $sAttCode, $oAttDef,
|
||||
$this->Get($sAttCode), $this->GetEditValue($sAttCode), 'att_'.$iFieldIndex, '', $iExpectCode,
|
||||
$aArgs);
|
||||
$aAttrib = array(
|
||||
$this->Get($sAttCode), $this->GetEditValue($sAttCode), $sInputId, '', $iExpectCode,
|
||||
$aArgs, true, $sInputType);
|
||||
$aAttrib = array(
|
||||
'label' => '<span>'.$oAttDef->GetLabel().'</span>',
|
||||
'value' => "<span id=\"field_att_$iFieldIndex\">$sHTMLValue</span>",
|
||||
);
|
||||
|
||||
//add attrib for data-attribute
|
||||
// Prepare metadata attributes
|
||||
$sAttCode = $oAttDef->GetCode();
|
||||
$oAttDef = MetaModel::GetAttributeDef($sClass, $sAttCode);
|
||||
$sAttCode = $oAttDef->GetCode();
|
||||
$oAttDef = MetaModel::GetAttributeDef($sClass, $sAttCode);
|
||||
$sAttDefClass = get_class($oAttDef);
|
||||
$sAttLabel = MetaModel::GetLabel($sClass, $sAttCode);
|
||||
$sAttLabel = MetaModel::GetLabel($sClass, $sAttCode);
|
||||
|
||||
$aAttrib['attcode'] = $sAttCode;
|
||||
$aAttrib['atttype'] = $sAttDefClass;
|
||||
$aAttrib['attcode'] = $sAttCode;
|
||||
$aAttrib['atttype'] = $sAttDefClass;
|
||||
$aAttrib['attlabel'] = $sAttLabel;
|
||||
// - Attribute flags
|
||||
$aAttrib['attflags'] = $this->GetFormAttributeFlags($sAttCode) ;
|
||||
$aAttrib['attflags'] = $this->GetFormAttributeFlags($sAttCode);
|
||||
// - How the field should be rendered
|
||||
$aAttrib['layout'] = (in_array($oAttDef->GetEditClass(), static::GetAttEditClassesToRenderAsLargeField())) ? 'large' : 'small';
|
||||
$aAttrib['layout'] = (in_array($oAttDef->GetEditClass(), static::GetAttEditClassesToRenderAsLargeField())) ? 'large' : 'small';
|
||||
$aAttrib['inputid'] = $sInputId;
|
||||
$aAttrib['inputtype'] = $sInputType;
|
||||
// - For simple fields, we get the raw (stored) value as well
|
||||
$bExcludeRawValue = false;
|
||||
foreach (static::GetAttDefClassesToExcludeFromMarkupMetadataRawValue() as $sAttDefClassToExclude)
|
||||
{
|
||||
foreach (static::GetAttDefClassesToExcludeFromMarkupMetadataRawValue() as $sAttDefClassToExclude) {
|
||||
if (is_a($sAttDefClass, $sAttDefClassToExclude, true)) {
|
||||
$bExcludeRawValue = true;
|
||||
break;
|
||||
@@ -3397,8 +3446,8 @@ EOF
|
||||
}
|
||||
$aAttrib['value_raw'] = ($bExcludeRawValue === false) ? $this->Get($sAttCode) : '';
|
||||
|
||||
$aDetails[] = $aAttrib;
|
||||
$aFieldsMap[$sAttCode] = 'att_'.$iFieldIndex;
|
||||
$aDetails[] = $aAttrib;
|
||||
$aFieldsMap[$sAttCode] = $sInputId;
|
||||
$iFieldIndex++;
|
||||
$bExistFieldToDisplay = true;
|
||||
}
|
||||
@@ -3622,7 +3671,7 @@ HTML;
|
||||
$sDisplayLabel = Dict::S('UI:OpenDocumentInNewWindow_');
|
||||
$sDisplayUrl = $oDocument->GetDisplayURL(get_class($this), $this->GetKey(), $sAttCode);
|
||||
|
||||
$sDownloadLabel = Dict::Format('UI:DownloadDocument_');
|
||||
$sDownloadLabel = Dict::S('UI:DownloadDocument_');
|
||||
$sDownloadUrl = $oDocument->GetDownloadURL(get_class($this), $this->GetKey(), $sAttCode);
|
||||
|
||||
$sDisplayValue = <<<HTML
|
||||
@@ -3675,7 +3724,8 @@ HTML;
|
||||
break;
|
||||
|
||||
default:
|
||||
$oPage->add("<pre>".utils::EscapeHtml(MyHelpers::beautifulstr($data, 1000, true))."</pre>\n");
|
||||
$oPage->add("<pre>".htmlentities(MyHelpers::beautifulstr($data, 1000, true), ENT_QUOTES,
|
||||
'UTF-8')."</pre>\n");
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -4013,14 +4063,18 @@ HTML;
|
||||
$this->Set($sAttCode, $value);
|
||||
break;
|
||||
case 'LinkedSet':
|
||||
if ($this->IsValueModified($value)) {
|
||||
if ($this->IsValueModified($value))
|
||||
{
|
||||
$oLinkSet = $this->Get($sAttCode);
|
||||
$sLinkedClass = $oAttDef->GetLinkedClass();
|
||||
if (array_key_exists('to_be_created', $value) && (count($value['to_be_created']) > 0)) {
|
||||
if (array_key_exists('to_be_created', $value) && (count($value['to_be_created']) > 0))
|
||||
{
|
||||
// Now handle the links to be created
|
||||
foreach ($value['to_be_created'] as $aData) {
|
||||
foreach ($value['to_be_created'] as $aData)
|
||||
{
|
||||
$sSubClass = $aData['class'];
|
||||
if (($sLinkedClass == $sSubClass) || (is_subclass_of($sSubClass, $sLinkedClass))) {
|
||||
if (($sLinkedClass == $sSubClass) || (is_subclass_of($sSubClass, $sLinkedClass)))
|
||||
{
|
||||
$aObjData = $aData['data'];
|
||||
$oLink = MetaModel::NewObject($sSubClass);
|
||||
$oLink->UpdateObjectFromArray($aObjData);
|
||||
@@ -4232,20 +4286,28 @@ HTML;
|
||||
|
||||
case 'LinkedSet':
|
||||
/** @var AttributeLinkedSet $oAttDef */
|
||||
$aRawToBeCreated = json_decode(utils::ReadPostedParam("attr_{$sFormPrefix}{$sAttCode}_tbc", '{}', 'raw_data'), true);
|
||||
$aRawToBeCreated = json_decode(utils::ReadPostedParam("attr_{$sFormPrefix}{$sAttCode}_tbc", '{}',
|
||||
'raw_data'), true);
|
||||
$aToBeCreated = array();
|
||||
foreach ($aRawToBeCreated as $aData) {
|
||||
foreach($aRawToBeCreated as $aData)
|
||||
{
|
||||
$sSubFormPrefix = $aData['formPrefix'];
|
||||
$sObjClass = isset($aData['class']) ? $aData['class'] : $oAttDef->GetLinkedClass();
|
||||
$aObjData = array();
|
||||
foreach ($aData as $sKey => $value) {
|
||||
if (preg_match("/^attr_$sSubFormPrefix(.*)$/", $sKey, $aMatches)) {
|
||||
foreach($aData as $sKey => $value)
|
||||
{
|
||||
if (preg_match("/^attr_$sSubFormPrefix(.*)$/", $sKey, $aMatches))
|
||||
{
|
||||
$oLinkAttDef = MetaModel::GetAttributeDef($sObjClass, $aMatches[1]);
|
||||
// Recursing over n:n link datetime attributes
|
||||
// Note: We might need to do it with other attribute types, like Document or redundancy setting.
|
||||
if ($oLinkAttDef instanceof AttributeDateTime) {
|
||||
$aObjData[$aMatches[1]] = $this->PrepareValueFromPostedForm($sSubFormPrefix, $aMatches[1], $sObjClass, $aData);
|
||||
} else {
|
||||
if ($oLinkAttDef instanceof AttributeDateTime)
|
||||
{
|
||||
$aObjData[$aMatches[1]] = $this->PrepareValueFromPostedForm($sSubFormPrefix,
|
||||
$aMatches[1], $sObjClass, $aData);
|
||||
}
|
||||
else
|
||||
{
|
||||
$aObjData[$aMatches[1]] = $value;
|
||||
}
|
||||
}
|
||||
@@ -4253,20 +4315,28 @@ HTML;
|
||||
$aToBeCreated[] = array('class' => $sObjClass, 'data' => $aObjData);
|
||||
}
|
||||
|
||||
$aRawToBeModified = json_decode(utils::ReadPostedParam("attr_{$sFormPrefix}{$sAttCode}_tbm", '{}', 'raw_data'), true);
|
||||
$aRawToBeModified = json_decode(utils::ReadPostedParam("attr_{$sFormPrefix}{$sAttCode}_tbm", '{}',
|
||||
'raw_data'), true);
|
||||
$aToBeModified = array();
|
||||
foreach ($aRawToBeModified as $iObjKey => $aData) {
|
||||
foreach($aRawToBeModified as $iObjKey => $aData)
|
||||
{
|
||||
$sSubFormPrefix = $aData['formPrefix'];
|
||||
$sObjClass = isset($aData['class']) ? $aData['class'] : $oAttDef->GetLinkedClass();
|
||||
$aObjData = array();
|
||||
foreach ($aData as $sKey => $value) {
|
||||
if (preg_match("/^attr_$sSubFormPrefix(.*)$/", $sKey, $aMatches)) {
|
||||
foreach($aData as $sKey => $value)
|
||||
{
|
||||
if (preg_match("/^attr_$sSubFormPrefix(.*)$/", $sKey, $aMatches))
|
||||
{
|
||||
$oLinkAttDef = MetaModel::GetAttributeDef($sObjClass, $aMatches[1]);
|
||||
// Recursing over n:n link datetime attributes
|
||||
// Note: We might need to do it with other attribute types, like Document or redundancy setting.
|
||||
if ($oLinkAttDef instanceof AttributeDateTime) {
|
||||
$aObjData[$aMatches[1]] = $this->PrepareValueFromPostedForm($sSubFormPrefix, $aMatches[1], $sObjClass, $aData);
|
||||
} else {
|
||||
if ($oLinkAttDef instanceof AttributeDateTime)
|
||||
{
|
||||
$aObjData[$aMatches[1]] = $this->PrepareValueFromPostedForm($sSubFormPrefix,
|
||||
$aMatches[1], $sObjClass, $aData);
|
||||
}
|
||||
else
|
||||
{
|
||||
$aObjData[$aMatches[1]] = $value;
|
||||
}
|
||||
}
|
||||
@@ -4275,11 +4345,14 @@ HTML;
|
||||
}
|
||||
|
||||
$value = array(
|
||||
'to_be_created' => $aToBeCreated,
|
||||
'to_be_created' => $aToBeCreated,
|
||||
'to_be_modified' => $aToBeModified,
|
||||
'to_be_deleted' => json_decode(utils::ReadPostedParam("attr_{$sFormPrefix}{$sAttCode}_tbd", '[]', 'raw_data'), true),
|
||||
'to_be_added' => json_decode(utils::ReadPostedParam("attr_{$sFormPrefix}{$sAttCode}_tba", '[]', 'raw_data'), true),
|
||||
'to_be_removed' => json_decode(utils::ReadPostedParam("attr_{$sFormPrefix}{$sAttCode}_tbr", '[]', 'raw_data'), true),
|
||||
'to_be_deleted' => json_decode(utils::ReadPostedParam("attr_{$sFormPrefix}{$sAttCode}_tbd", '[]',
|
||||
'raw_data'), true),
|
||||
'to_be_added' => json_decode(utils::ReadPostedParam("attr_{$sFormPrefix}{$sAttCode}_tba", '[]',
|
||||
'raw_data'), true),
|
||||
'to_be_removed' => json_decode(utils::ReadPostedParam("attr_{$sFormPrefix}{$sAttCode}_tbr", '[]',
|
||||
'raw_data'), true),
|
||||
);
|
||||
break;
|
||||
|
||||
@@ -4445,13 +4518,13 @@ HTML;
|
||||
|
||||
// Protection against reentrance (e.g. cascading the update of ticket logs)
|
||||
// Note: This is based on the fix made on r 3190 in DBObject::DBUpdate()
|
||||
if (!MetaModel::StartReentranceProtection(Metamodel::REENTRANCE_TYPE_UPDATE, $this)) {
|
||||
$sClass = get_class($this);
|
||||
$sKey = $this->GetKey();
|
||||
IssueLog::Debug("CRUD: DBUpdate $sClass::$sKey Rejected (reentrance)", LogChannels::DM_CRUD);
|
||||
|
||||
static $aUpdateReentrance = array();
|
||||
$sKey = get_class($this).'::'.$this->GetKey();
|
||||
if (array_key_exists($sKey, $aUpdateReentrance))
|
||||
{
|
||||
return $res;
|
||||
}
|
||||
$aUpdateReentrance[$sKey] = true;
|
||||
|
||||
try
|
||||
{
|
||||
@@ -4462,13 +4535,13 @@ HTML;
|
||||
$oExtensionInstance->OnDBUpdate($this, self::GetCurrentChange());
|
||||
}
|
||||
}
|
||||
catch (Exception $e)
|
||||
{
|
||||
throw $e;
|
||||
}
|
||||
finally
|
||||
{
|
||||
MetaModel::StopReentranceProtection(Metamodel::REENTRANCE_TYPE_UPDATE, $this);
|
||||
}
|
||||
|
||||
if ($this->IsModified()) {
|
||||
return $this->DBUpdate();
|
||||
unset($aUpdateReentrance[$sKey]);
|
||||
}
|
||||
|
||||
return $res;
|
||||
@@ -4481,9 +4554,11 @@ HTML;
|
||||
*/
|
||||
protected function SetWarningsAsSessionMessages($sMessageIdPrefix)
|
||||
{
|
||||
if (!empty($this->m_aCheckWarnings) && is_array($this->m_aCheckWarnings)) {
|
||||
if (!empty($this->m_aCheckWarnings) && is_array($this->m_aCheckWarnings))
|
||||
{
|
||||
$iMsgNb = 0;
|
||||
foreach ($this->m_aCheckWarnings as $sWarningMessage) {
|
||||
foreach ($this->m_aCheckWarnings as $sWarningMessage)
|
||||
{
|
||||
$iMsgNb++;
|
||||
$sMessageId = "$sMessageIdPrefix-$iMsgNb"; // each message must have its own messageId !
|
||||
$this->SetSessionMessageFromInstance($sMessageId, $sWarningMessage, 'warning', 0);
|
||||
@@ -4491,6 +4566,12 @@ HTML;
|
||||
}
|
||||
}
|
||||
|
||||
protected static function BulkUpdateTracked_Internal(DBSearch $oFilter, array $aValues)
|
||||
{
|
||||
// Todo - invoke the extension
|
||||
return parent::BulkUpdateTracked_Internal($oFilter, $aValues);
|
||||
}
|
||||
|
||||
protected function DBDeleteTracked_Internal(&$oDeletionPlan = null)
|
||||
{
|
||||
// Invoke extensions before the deletion (the deletion will do some cleanup and we might loose some information
|
||||
@@ -4693,8 +4774,9 @@ HTML;
|
||||
{
|
||||
$aReasons = array();
|
||||
$sTip = '';
|
||||
foreach($aReasons as $aRow) {
|
||||
$sDescription = utils::EscapeHtml($aRow['description']);
|
||||
foreach($aReasons as $aRow)
|
||||
{
|
||||
$sDescription = htmlentities($aRow['description'], ENT_QUOTES, 'UTF-8');
|
||||
$sDescription = str_replace(array("\r\n", "\n"), "<br/>", $sDescription);
|
||||
$sTip .= "<div class=\"synchro-source\">";
|
||||
$sTip .= "<div class=\"synchro-source-title\">Synchronized with {$aRow['name']}</div>";
|
||||
@@ -4706,7 +4788,8 @@ HTML;
|
||||
|
||||
// Attribute is read-only
|
||||
$sHTMLValue = $this->GetAsHTML($sAttCode);
|
||||
$sHTMLValue .= '<input type="hidden" id="'.$sInputId.'" name="attr_'.$sPrefix.$sAttCode.'" value="'.utils::EscapeHtml($this->GetEditValue($sAttCode)).'"/>';
|
||||
$sHTMLValue .= '<input type="hidden" id="'.$sInputId.'" name="attr_'.$sPrefix.$sAttCode.'" value="'.htmlentities($this->GetEditValue($sAttCode),
|
||||
ENT_QUOTES, 'UTF-8').'"/>';
|
||||
$aFieldsMap[$sAttCode] = $sInputId;
|
||||
}
|
||||
else
|
||||
@@ -5674,117 +5757,4 @@ JS
|
||||
'AttributeOneWayPassword',
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
* @throws \CoreException
|
||||
*/
|
||||
final protected function EventInsertRequested()
|
||||
{
|
||||
$this->FireEvent(EVENT_SERVICE_DB_INSERT_REQUESTED);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
* @throws \CoreException
|
||||
*/
|
||||
final protected function EventInsertBefore()
|
||||
{
|
||||
$this->FireEvent(EVENT_SERVICE_DB_ABOUT_TO_INSERT);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
* @throws \CoreException
|
||||
*/
|
||||
final protected function EventInsertAfter()
|
||||
{
|
||||
$this->FireEvent(EVENT_SERVICE_DB_INSERT_DONE);
|
||||
}
|
||||
|
||||
final protected function EventComputeValues()
|
||||
{
|
||||
$this->FireEvent(EVENT_SERVICE_DB_COMPUTE_VALUES);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $aEventData
|
||||
*
|
||||
* @return void
|
||||
* @throws \CoreException
|
||||
*/
|
||||
final protected function EventCheckToWrite(array $aEventData)
|
||||
{
|
||||
$this->FireEvent(EVENT_SERVICE_DB_CHECK_TO_WRITE, $aEventData);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $aEventData
|
||||
*
|
||||
* @return void
|
||||
* @throws \CoreException
|
||||
*/
|
||||
final protected function EventCheckToDelete(array $aEventData)
|
||||
{
|
||||
$this->FireEvent(EVENT_SERVICE_DB_CHECK_TO_DELETE, $aEventData);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
* @throws \CoreException
|
||||
*/
|
||||
final protected function EventUpdateRequested()
|
||||
{
|
||||
$this->FireEvent(EVENT_SERVICE_DB_UPDATE_REQUESTED);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
* @throws \CoreException
|
||||
*/
|
||||
final protected function EventUpdateBefore()
|
||||
{
|
||||
$this->FireEvent(EVENT_SERVICE_DB_ABOUT_TO_UPDATE);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $aEventData
|
||||
*
|
||||
* @return void
|
||||
* @throws \CoreException
|
||||
*/
|
||||
final protected function EventUpdateAfter(array $aEventData)
|
||||
{
|
||||
$this->FireEvent(EVENT_SERVICE_DB_UPDATE_DONE, $aEventData);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
* @throws \CoreException
|
||||
*/
|
||||
final protected function EventDeleteBefore()
|
||||
{
|
||||
$this->FireEvent(EVENT_SERVICE_DB_ABOUT_TO_DELETE);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
* @throws \CoreException
|
||||
*/
|
||||
final protected function EventDeleteAfter()
|
||||
{
|
||||
$this->FireEvent(EVENT_SERVICE_DB_DELETE_DONE);
|
||||
}
|
||||
|
||||
|
||||
final protected function EventArchive()
|
||||
{
|
||||
$this->FireEvent(EVENT_SERVICE_DB_ARCHIVE);
|
||||
}
|
||||
|
||||
final protected function EventUnarchive()
|
||||
{
|
||||
$this->FireEvent(EVENT_SERVICE_DB_UNARCHIVE);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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');
|
||||
@@ -1549,6 +1549,29 @@ JS
|
||||
return $this->sDefinitionFile;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $sDashboardFileRelative can also be an absolute path (compatibility with old URL)
|
||||
*
|
||||
* @return string full path to the Dashboard file
|
||||
* @throws \SecurityException if path isn't under approot
|
||||
* @uses utils::RealPath()
|
||||
* @since 2.7.8 3.0.3 3.1.0 N°4449 remove FPD
|
||||
*/
|
||||
public static function GetDashboardFileFromRelativePath($sDashboardFileRelative)
|
||||
{
|
||||
if (utils::RealPath($sDashboardFileRelative, APPROOT)) {
|
||||
// compatibility with old URL containing absolute path !
|
||||
return $sDashboardFileRelative;
|
||||
}
|
||||
|
||||
$sDashboardFile = APPROOT.$sDashboardFileRelative;
|
||||
if (false === utils::RealPath($sDashboardFile, APPROOT)) {
|
||||
throw new SecurityException('Invalid dashboard file !');
|
||||
}
|
||||
|
||||
return $sDashboardFile;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $sDefinitionFile
|
||||
*/
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<itop_design xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="3.1">
|
||||
<itop_design xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="3.0">
|
||||
<classes>
|
||||
<class id="AbstractResource" _delta="define">
|
||||
<parent>cmdbAbstractObject</parent>
|
||||
@@ -185,384 +185,6 @@
|
||||
</style>
|
||||
</menu>
|
||||
</menus>
|
||||
<events>
|
||||
<event id="EVENT_SERVICE_DB_INSERT_REQUESTED" _delta="define">
|
||||
<description>An object insert in the database has been requested. All changes to the object will be persisted automatically.</description>
|
||||
<sources>
|
||||
<source id="cmdbAbstractObject">cmdbAbstractObject</source>
|
||||
</sources>
|
||||
<replaces>DBObject::OnInsert</replaces>
|
||||
<event_data>
|
||||
<event_datum id="object">
|
||||
<description>The object inserted</description>
|
||||
<type>DBObject</type>
|
||||
</event_datum>
|
||||
<event_datum id="debug_info">
|
||||
<description>Debug string</description>
|
||||
<type>string</type>
|
||||
</event_datum>
|
||||
</event_data>
|
||||
</event>
|
||||
<event id="EVENT_SERVICE_DB_ABOUT_TO_INSERT" _delta="define">
|
||||
<description>An object is about to be inserted in the database (no change possible)</description>
|
||||
<sources>
|
||||
<source id="cmdbAbstractObject">cmdbAbstractObject</source>
|
||||
</sources>
|
||||
<replaces>DBObject::OnInsert</replaces>
|
||||
<event_data>
|
||||
<event_datum id="object">
|
||||
<description>The object inserted</description>
|
||||
<type>DBObject</type>
|
||||
</event_datum>
|
||||
<event_datum id="debug_info">
|
||||
<description>Debug string</description>
|
||||
<type>string</type>
|
||||
</event_datum>
|
||||
</event_data>
|
||||
</event>
|
||||
<event id="EVENT_SERVICE_DB_INSERT_DONE" _delta="define">
|
||||
<description>An object has been inserted into the database (but not reloaded). All changes to the object will be persisted automatically.</description>
|
||||
<sources>
|
||||
<source id="cmdbAbstractObject">cmdbAbstractObject</source>
|
||||
</sources>
|
||||
<replaces>DBObject::AfterInsert</replaces>
|
||||
<event_data>
|
||||
<event_datum id="object">
|
||||
<description>The object inserted</description>
|
||||
<type>DBObject</type>
|
||||
</event_datum>
|
||||
<event_datum id="debug_info">
|
||||
<description>Debug string</description>
|
||||
<type>string</type>
|
||||
</event_datum>
|
||||
</event_data>
|
||||
</event>
|
||||
<event id="EVENT_SERVICE_DB_UPDATE_REQUESTED" _delta="define">
|
||||
<description>An object update has been requested. All changes to the object will be persisted automatically.</description>
|
||||
<sources>
|
||||
<source id="cmdbAbstractObject">cmdbAbstractObject</source>
|
||||
</sources>
|
||||
<replaces>DBObject::OnUpdate, DBObject::DoComputeValues</replaces>
|
||||
<event_data>
|
||||
<event_datum id="object">
|
||||
<description>The object updated</description>
|
||||
<type>DBObject</type>
|
||||
</event_datum>
|
||||
<event_datum id="debug_info">
|
||||
<description>Debug string</description>
|
||||
<type>string</type>
|
||||
</event_datum>
|
||||
</event_data>
|
||||
</event>
|
||||
<event id="EVENT_SERVICE_DB_ABOUT_TO_UPDATE" _delta="define">
|
||||
<description>An object is about to be updated in the database (no change possible)</description>
|
||||
<sources>
|
||||
<source id="cmdbAbstractObject">cmdbAbstractObject</source>
|
||||
</sources>
|
||||
<replaces>DBObject::OnUpdate</replaces>
|
||||
<event_data>
|
||||
<event_datum id="object">
|
||||
<description>The object updated</description>
|
||||
<type>DBObject</type>
|
||||
</event_datum>
|
||||
<event_datum id="debug_info">
|
||||
<description>Debug string</description>
|
||||
<type>string</type>
|
||||
</event_datum>
|
||||
</event_data>
|
||||
</event>
|
||||
<event id="EVENT_SERVICE_DB_UPDATE_DONE" _delta="define">
|
||||
<description>An object has been updated into the database and reloaded. All changes to the object will be persisted automatically.</description>
|
||||
<sources>
|
||||
<source id="cmdbAbstractObject">cmdbAbstractObject</source>
|
||||
</sources>
|
||||
<replaces>DBObject::AfterUpdate</replaces>
|
||||
<event_data>
|
||||
<event_datum id="object">
|
||||
<description>The object updated</description>
|
||||
<type>DBObject</type>
|
||||
</event_datum>
|
||||
<event_datum id="debug_info">
|
||||
<description>Debug string</description>
|
||||
<type>string</type>
|
||||
</event_datum>
|
||||
</event_data>
|
||||
</event>
|
||||
<event id="EVENT_SERVICE_DB_ABOUT_TO_DELETE" _delta="define">
|
||||
<description>An object is about to be deleted in the database</description>
|
||||
<sources>
|
||||
<source id="cmdbAbstractObject">cmdbAbstractObject</source>
|
||||
</sources>
|
||||
<replaces>DBObject::OnDelete</replaces>
|
||||
<event_data>
|
||||
<event_datum id="object">
|
||||
<description>The object deleted</description>
|
||||
<type>DBObject</type>
|
||||
</event_datum>
|
||||
<event_datum id="debug_info">
|
||||
<description>Debug string</description>
|
||||
<type>string</type>
|
||||
</event_datum>
|
||||
</event_data>
|
||||
</event>
|
||||
<event id="EVENT_SERVICE_DB_DELETE_DONE" _delta="define">
|
||||
<description>An object has been deleted into the database</description>
|
||||
<sources>
|
||||
<source id="cmdbAbstractObject">cmdbAbstractObject</source>
|
||||
</sources>
|
||||
<replaces>DBObject::AfterDelete</replaces>
|
||||
<event_data>
|
||||
<event_datum id="object">
|
||||
<description>The object deleted</description>
|
||||
<type>DBObject</type>
|
||||
</event_datum>
|
||||
<event_datum id="debug_info">
|
||||
<description>Debug string</description>
|
||||
<type>string</type>
|
||||
</event_datum>
|
||||
</event_data>
|
||||
</event>
|
||||
<event id="EVENT_SERVICE_DB_BEFORE_APPLY_STIMULUS" _delta="define">
|
||||
<description>A stimulus is about to be applied to an object</description>
|
||||
<sources>
|
||||
<source id="cmdbAbstractObject">cmdbAbstractObject</source>
|
||||
</sources>
|
||||
<event_data>
|
||||
<event_datum id="object">
|
||||
<description>The object where the stimulus is targeted</description>
|
||||
<type>DBObject</type>
|
||||
</event_datum>
|
||||
<event_datum id="stimulus">
|
||||
<description>Current stimulus applied</description>
|
||||
<type>string</type>
|
||||
</event_datum>
|
||||
<event_datum id="previous_state">
|
||||
<description>Object previous state</description>
|
||||
<type>string</type>
|
||||
</event_datum>
|
||||
<event_datum id="new_state">
|
||||
<description>Object new state</description>
|
||||
<type>string</type>
|
||||
</event_datum>
|
||||
<event_datum id="save_object">
|
||||
<description>The object must be saved in the database</description>
|
||||
<type>boolean</type>
|
||||
</event_datum>
|
||||
<event_datum id="debug_info">
|
||||
<description>Debug string</description>
|
||||
<type>string</type>
|
||||
</event_datum>
|
||||
</event_data>
|
||||
</event>
|
||||
<event id="EVENT_SERVICE_DB_AFTER_APPLY_STIMULUS" _delta="define">
|
||||
<description>A stimulus has been applied to an object</description>
|
||||
<sources>
|
||||
<source id="cmdbAbstractObject">cmdbAbstractObject</source>
|
||||
</sources>
|
||||
<event_data>
|
||||
<event_datum id="object">
|
||||
<description>The object where the stimulus is targeted</description>
|
||||
<type>DBObject</type>
|
||||
</event_datum>
|
||||
<event_datum id="stimulus">
|
||||
<description>Current stimulus applied</description>
|
||||
<type>string</type>
|
||||
</event_datum>
|
||||
<event_datum id="previous_state">
|
||||
<description>Object previous state</description>
|
||||
<type>string</type>
|
||||
</event_datum>
|
||||
<event_datum id="new_state">
|
||||
<description>Object new state</description>
|
||||
<type>string</type>
|
||||
</event_datum>
|
||||
<event_datum id="save_object">
|
||||
<description>The object is asked to be saved in the database</description>
|
||||
<type>boolean</type>
|
||||
</event_datum>
|
||||
<event_datum id="debug_info">
|
||||
<description>Debug string</description>
|
||||
<type>string</type>
|
||||
</event_datum>
|
||||
</event_data>
|
||||
</event>
|
||||
<event id="EVENT_SERVICE_DB_APPLY_STIMULUS_FAILED" _delta="define">
|
||||
<description>A stimulus has failed</description>
|
||||
<sources>
|
||||
<source id="cmdbAbstractObject">cmdbAbstractObject</source>
|
||||
</sources>
|
||||
<event_data>
|
||||
<event_datum id="action">
|
||||
<description>The action that failed to apply the stimulus</description>
|
||||
<type>string</type>
|
||||
</event_datum>
|
||||
<event_datum id="object">
|
||||
<description>The object where the stimulus is targeted</description>
|
||||
<type>DBObject</type>
|
||||
</event_datum>
|
||||
<event_datum id="stimulus">
|
||||
<description>Current stimulus applied</description>
|
||||
<type>string</type>
|
||||
</event_datum>
|
||||
<event_datum id="previous_state">
|
||||
<description>Object previous state</description>
|
||||
<type>string</type>
|
||||
</event_datum>
|
||||
<event_datum id="new_state">
|
||||
<description>Object new state</description>
|
||||
<type>string</type>
|
||||
</event_datum>
|
||||
<event_datum id="save_object">
|
||||
<description>The object must be saved in the database</description>
|
||||
<type>boolean</type>
|
||||
</event_datum>
|
||||
<event_datum id="debug_info">
|
||||
<description>Debug string</description>
|
||||
<type>string</type>
|
||||
</event_datum>
|
||||
</event_data>
|
||||
</event>
|
||||
<event id="EVENT_SERVICE_DB_OBJECT_RELOAD" _delta="define">
|
||||
<description>An object has been re-loaded from the database</description>
|
||||
<sources>
|
||||
<source id="cmdbAbstractObject">cmdbAbstractObject</source>
|
||||
</sources>
|
||||
<event_data>
|
||||
<event_datum id="object">
|
||||
<description>The object re-loaded</description>
|
||||
<type>DBObject</type>
|
||||
</event_datum>
|
||||
<event_datum id="debug_info">
|
||||
<description>Debug string</description>
|
||||
<type>string</type>
|
||||
</event_datum>
|
||||
</event_data>
|
||||
</event>
|
||||
<event id="EVENT_SERVICE_DB_COMPUTE_VALUES" _delta="define">
|
||||
<description>An object needs to be recomputed after changes</description>
|
||||
<sources>
|
||||
<source id="cmdbAbstractObject">cmdbAbstractObject</source>
|
||||
</sources>
|
||||
<replaces>DBObject::ComputeValues</replaces>
|
||||
<event_data>
|
||||
<event_datum id="object">
|
||||
<description>The object inserted</description>
|
||||
<type>DBObject</type>
|
||||
</event_datum>
|
||||
<event_datum id="debug_info">
|
||||
<description>Debug string</description>
|
||||
<type>string</type>
|
||||
</event_datum>
|
||||
</event_data>
|
||||
</event>
|
||||
<event id="EVENT_SERVICE_DB_CHECK_TO_WRITE" _delta="define">
|
||||
<description>Check an object before it is written into the database (no change possible)</description>
|
||||
<sources>
|
||||
<source id="cmdbAbstractObject">cmdbAbstractObject</source>
|
||||
</sources>
|
||||
<replaces>cmdbAbstractObject::DoCheckToWrite</replaces>
|
||||
<event_data>
|
||||
<event_datum id="object">
|
||||
<description>The object to check</description>
|
||||
<type>DBObject</type>
|
||||
</event_datum>
|
||||
<event_datum id="error_messages">
|
||||
<description>Array of strings where all the errors found during the object checking are added</description>
|
||||
<type>array</type>
|
||||
</event_datum>
|
||||
<event_datum id="debug_info">
|
||||
<description>Debug string</description>
|
||||
<type>string</type>
|
||||
</event_datum>
|
||||
</event_data>
|
||||
</event>
|
||||
<event id="EVENT_SERVICE_DB_CHECK_TO_DELETE" _delta="define">
|
||||
<description>Check an object before it is deleted from the database (no change possible)</description>
|
||||
<sources>
|
||||
<source id="cmdbAbstractObject">cmdbAbstractObject</source>
|
||||
</sources>
|
||||
<replaces>cmdbAbstractObject::DoCheckToDelete</replaces>
|
||||
<event_data>
|
||||
<event_datum id="object">
|
||||
<description>The object to check</description>
|
||||
<type>DBObject</type>
|
||||
</event_datum>
|
||||
<event_datum id="error_messages">
|
||||
<description>Array of strings where all the errors found during the object checking are added</description>
|
||||
<type>array</type>
|
||||
</event_datum>
|
||||
<event_datum id="debug_info">
|
||||
<description>Debug string</description>
|
||||
<type>string</type>
|
||||
</event_datum>
|
||||
</event_data>
|
||||
</event>
|
||||
<event id="EVENT_SERVICE_DB_ARCHIVE" _delta="define">
|
||||
<description>An object has been archived</description>
|
||||
<sources>
|
||||
<source id="cmdbAbstractObject">cmdbAbstractObject</source>
|
||||
</sources>
|
||||
<event_data>
|
||||
<event_datum id="object">
|
||||
<description>The object archived</description>
|
||||
<type>DBObject</type>
|
||||
</event_datum>
|
||||
<event_datum id="debug_info">
|
||||
<description>Debug string</description>
|
||||
<type>string</type>
|
||||
</event_datum>
|
||||
</event_data>
|
||||
</event>
|
||||
<event id="EVENT_SERVICE_DB_UNARCHIVE" _delta="define">
|
||||
<description>An object has been unarchived</description>
|
||||
<sources>
|
||||
<source id="cmdbAbstractObject">cmdbAbstractObject</source>
|
||||
</sources>
|
||||
<event_data>
|
||||
<event_datum id="object">
|
||||
<description>The object unarchived</description>
|
||||
<type>DBObject</type>
|
||||
</event_datum>
|
||||
<event_datum id="debug_info">
|
||||
<description>Debug string</description>
|
||||
<type>string</type>
|
||||
</event_datum>
|
||||
</event_data>
|
||||
</event>
|
||||
<event id="EVENT_SERVICE_DOWNLOAD_DOCUMENT" _delta="define">
|
||||
<description>A document has been downloaded from the GUI</description>
|
||||
<sources>
|
||||
<source id="Document">Document</source>
|
||||
</sources>
|
||||
<event_data>
|
||||
<event_datum id="object">
|
||||
<description>The object containing the document</description>
|
||||
<type>DBObject</type>
|
||||
</event_datum>
|
||||
<event_datum id="document">
|
||||
<description>The document downloaded</description>
|
||||
<type>ormDocument</type>
|
||||
</event_datum>
|
||||
<event_datum id="debug_info">
|
||||
<description>Debug string</description>
|
||||
<type>string</type>
|
||||
</event_datum>
|
||||
</event_data>
|
||||
</event>
|
||||
<event id="EVENT_SERVICE_LOGIN" _delta="define">
|
||||
<description>Inform the listeners about the connection states</description>
|
||||
<event_data>
|
||||
<event_datum id="code">
|
||||
<description>The login step result code (LoginWebPage::EXIT_CODE_...) </description>
|
||||
<type>integer</type>
|
||||
</event_datum>
|
||||
<event_datum id="state">
|
||||
<description>Current login state (LoginWebPage::LOGIN_STATE_CONNECTED...)</description>
|
||||
<type>string</type>
|
||||
</event_datum>
|
||||
</event_data>
|
||||
</event>
|
||||
</events>
|
||||
<meta>
|
||||
<classes>
|
||||
<class id="cmdbAbstractObject" _delta="define">
|
||||
|
||||
@@ -19,7 +19,7 @@ use Combodo\iTop\Renderer\Console\ConsoleBlockRenderer;
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
*
|
||||
* @deprecated 3.0.0 use Combodo\iTop\Application\UI\Base\Component\DataTable\Datatable
|
||||
* @deprecated since 3.0.0 use Combodo\iTop\Application\UI\Base\Component\DataTable\Datatable
|
||||
*/
|
||||
|
||||
class DataTable
|
||||
|
||||
@@ -476,7 +476,7 @@ class DisplayBlock
|
||||
$oExceptionAlert = AlertUIBlockFactory::MakeForFailure('Cannot display results', $sExceptionContent);
|
||||
$oHtml->AddSubBlock($oExceptionAlert);
|
||||
}
|
||||
ExceptionLog::LogException($e);
|
||||
IssueLog::Error('Exception during GetDisplay: '.$e->getMessage());
|
||||
}
|
||||
} else {
|
||||
// render it as an Ajax (asynchronous) call
|
||||
@@ -566,7 +566,7 @@ class DisplayBlock
|
||||
if (($this->m_sStyle != 'links') && ($this->m_sStyle != 'search') && ($this->m_sStyle != 'list_search')) {
|
||||
$oAppContext = new ApplicationContext();
|
||||
$sClass = $this->m_oFilter->GetClass();
|
||||
$aFilterCodes = MetaModel::GetFiltersList($sClass);
|
||||
$aFilterCodes = array_keys(MetaModel::GetClassFilterDefs($sClass));
|
||||
$aCallSpec = array($sClass, 'MapContextParam');
|
||||
if (is_callable($aCallSpec)) {
|
||||
foreach ($oAppContext->GetNames() as $sContextParam) {
|
||||
@@ -1045,9 +1045,19 @@ JS
|
||||
$aCount = $aCounts[$sStateValue];
|
||||
$sHyperlink = $aCount['link'];
|
||||
$sCountLabel = $aCount['label'];
|
||||
$oPill = PillFactory::MakeForState($sClass, $sStateValue)
|
||||
->SetTooltip($sStateLabel)
|
||||
->AddHtml("<span class=\"ibo-dashlet-header-dynamic--count\">$sCountLabel</span><span class=\"ibo-dashlet-header-dynamic--label ibo-text-truncated-with-ellipsis\">".utils::HtmlEntities($sStateLabel)."</span>");
|
||||
|
||||
$oPill = PillFactory::MakeForState($sClass, $sStateValue);
|
||||
// N°5849 - Unencode label for ExternalKey attribute because friendlyname is already html encoded thanks to DBObject::GetName() in AttributeExternalKey::GetAllowedValues(). (A fix in this function may have too much impact).
|
||||
if ($oAttDef instanceof AttributeExternalKey) {
|
||||
$sPillTooltip = utils::HtmlEntityDecode($sStateLabel);
|
||||
$sPillLabel = $sStateLabel;
|
||||
} else {
|
||||
$sPillTooltip = $sStateLabel;
|
||||
$sPillLabel = utils::HtmlEntities($sStateLabel);
|
||||
}
|
||||
$oPill->SetTooltip($sPillTooltip)
|
||||
->AddHtml("<span class=\"ibo-dashlet-header-dynamic--count\">$sCountLabel</span><span class=\"ibo-dashlet-header-dynamic--label ibo-text-truncated-with-ellipsis\">".$sPillLabel."</span>");
|
||||
|
||||
if ($sHyperlink != '-') {
|
||||
$oPill->SetUrl($sHyperlink);
|
||||
}
|
||||
@@ -1706,6 +1716,162 @@ 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \WebPage $oPage
|
||||
* @param array $aExtraParams
|
||||
* @param string $sId
|
||||
*
|
||||
* @return string
|
||||
* @throws \ArchivedObjectException
|
||||
* @throws \CoreException
|
||||
* @throws \CoreUnexpectedValue
|
||||
* @throws \DictExceptionMissingString
|
||||
* @throws \MissingQueryArgument
|
||||
* @throws \MySQLException
|
||||
* @throws \MySQLHasGoneAwayException
|
||||
*
|
||||
* @since 2.7.7 3.0.1 3.1.0 N°3129 Remove default value for $aExtraParams and add type hinting for PHP 8.0 compatibility
|
||||
* (var is unused, and all calls were already made using a default value)
|
||||
*/
|
||||
public function GetRenderContent(WebPage $oPage, array $aExtraParams, string $sId)
|
||||
{
|
||||
$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'
|
||||
|
||||
@@ -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');
|
||||
@@ -838,8 +838,7 @@ class DesignerFormField
|
||||
{
|
||||
$sId = $this->oForm->GetFieldId($this->sCode);
|
||||
$sName = $this->oForm->GetFieldName($this->sCode);
|
||||
|
||||
return array('label' => $this->sLabel, 'value' => "<input type=\"text\" id=\"$sId\" name=\"$sName\" value=\"".utils::EscapeHtml($this->defaultValue)."\">");
|
||||
return array('label' => $this->sLabel, 'value' => "<input type=\"text\" id=\"$sId\" name=\"$sName\" value=\"".htmlentities($this->defaultValue, ENT_QUOTES, 'UTF-8')."\">");
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1013,8 +1012,9 @@ class DesignerTextField extends DesignerFormField
|
||||
$sId = $this->oForm->GetFieldId($this->sCode);
|
||||
|
||||
$sName = $this->oForm->GetFieldName($this->sCode);
|
||||
if ($this->IsReadOnly()) {
|
||||
$sHtmlValue = "<span>".utils::EscapeHtml($this->defaultValue)."<input type=\"hidden\" id=\"$sId\" name=\"$sName\" value=\"".utils::EscapeHtml($this->defaultValue)."\"/></span>";
|
||||
if ($this->IsReadOnly())
|
||||
{
|
||||
$sHtmlValue = "<span>".htmlentities($this->defaultValue, ENT_QUOTES, 'UTF-8')."<input type=\"hidden\" id=\"$sId\" name=\"$sName\" value=\"".htmlentities($this->defaultValue, ENT_QUOTES, 'UTF-8')."\"/></span>";
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1038,10 +1038,11 @@ $('#$sId').on('change keyup validate', function() { ValidateWithPattern('$sId',
|
||||
EOF
|
||||
);
|
||||
$sCSSClasses = '';
|
||||
if (count($this->aCSSClasses) > 0) {
|
||||
if (count($this->aCSSClasses) > 0)
|
||||
{
|
||||
$sCSSClasses = 'class="'.implode(' ', $this->aCSSClasses).'"';
|
||||
}
|
||||
$sHtmlValue = "<input type=\"text\" $sCSSClasses id=\"$sId\" name=\"$sName\" value=\"".utils::EscapeHtml($this->defaultValue)."\">";
|
||||
$sHtmlValue = "<input type=\"text\" $sCSSClasses id=\"$sId\" name=\"$sName\" value=\"".htmlentities($this->defaultValue, ENT_QUOTES, 'UTF-8')."\">";
|
||||
}
|
||||
return array('label' => $this->sLabel, 'value' => $sHtmlValue);
|
||||
}
|
||||
@@ -1100,9 +1101,10 @@ class DesignerLongTextField extends DesignerTextField
|
||||
{
|
||||
$sCSSClasses = 'class="'.implode(' ', $this->aCSSClasses).'"';
|
||||
}
|
||||
if (!$this->IsReadOnly()) {
|
||||
if (!$this->IsReadOnly())
|
||||
{
|
||||
$oP->add_ready_script(
|
||||
<<<EOF
|
||||
<<<EOF
|
||||
$('#$sId').on('change keyup validate', function() { ValidateWithPattern('$sId', $sMandatory, '$sPattern', $(this).closest('form').attr('id'), $sForbiddenValues); } );
|
||||
{
|
||||
var myTimer = null;
|
||||
@@ -1110,10 +1112,11 @@ $('#$sId').on('change keyup validate', function() { ValidateWithPattern('$sId',
|
||||
}
|
||||
EOF
|
||||
);
|
||||
$sValue = "<textarea $sCSSClasses id=\"$sId\" name=\"$sName\">".utils::EscapeHtml($this->defaultValue)."</textarea>";
|
||||
$sValue = "<textarea $sCSSClasses id=\"$sId\" name=\"$sName\">".htmlentities($this->defaultValue, ENT_QUOTES, 'UTF-8')."</textarea>";
|
||||
}
|
||||
else {
|
||||
$sValue = "<div $sCSSClasses id=\"$sId\">".utils::EscapeHtml($this->defaultValue)."</div>";
|
||||
else
|
||||
{
|
||||
$sValue = "<div $sCSSClasses id=\"$sId\">".htmlentities($this->defaultValue, ENT_QUOTES, 'UTF-8')."</div>";
|
||||
}
|
||||
return array('label' => $this->sLabel, 'value' => $sValue);
|
||||
}
|
||||
@@ -1142,8 +1145,9 @@ class DesignerIntegerField extends DesignerFormField
|
||||
$sId = $this->oForm->GetFieldId($this->sCode);
|
||||
|
||||
$sName = $this->oForm->GetFieldName($this->sCode);
|
||||
if ($this->IsReadOnly()) {
|
||||
$sHtmlValue = "<span>".utils::EscapeHtml($this->defaultValue)."<input type=\"hidden\" id=\"$sId\" name=\"$sName\" value=\"".utils::EscapeHtml($this->defaultValue)."\"/></span>";
|
||||
if ($this->IsReadOnly())
|
||||
{
|
||||
$sHtmlValue = "<span>".htmlentities($this->defaultValue, ENT_QUOTES, 'UTF-8')."<input type=\"hidden\" id=\"$sId\" name=\"$sName\" value=\"".htmlentities($this->defaultValue, ENT_QUOTES, 'UTF-8')."\"/></span>";
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1160,10 +1164,11 @@ $('#$sId').on('change keyup validate', function() { ValidateInteger('$sId', $sMa
|
||||
EOF
|
||||
);
|
||||
$sCSSClasses = '';
|
||||
if (count($this->aCSSClasses) > 0) {
|
||||
if (count($this->aCSSClasses) > 0)
|
||||
{
|
||||
$sCSSClasses = 'class="'.implode(' ', $this->aCSSClasses).'"';
|
||||
}
|
||||
$sHtmlValue = "<input type=\"text\" $sCSSClasses id=\"$sId\" name=\"$sName\" value=\"".utils::EscapeHtml($this->defaultValue)."\">";
|
||||
$sHtmlValue = "<input type=\"text\" $sCSSClasses id=\"$sId\" name=\"$sName\" value=\"".htmlentities($this->defaultValue, ENT_QUOTES, 'UTF-8')."\">";
|
||||
}
|
||||
return array('label' => $this->sLabel, 'value' => $sHtmlValue);
|
||||
}
|
||||
@@ -1284,18 +1289,22 @@ class DesignerComboField extends DesignerFormField
|
||||
{
|
||||
if ($this->bMultipleSelection)
|
||||
{
|
||||
if(in_array($sKey, $this->defaultValue)) {
|
||||
if(in_array($sKey, $this->defaultValue))
|
||||
{
|
||||
$aSelected[] = $sDisplayValue;
|
||||
$aHiddenValues[] = "<input type=\"hidden\" name=\"{$sName}[]\" value=\"".utils::EscapeHtml($sKey)."\"/>";
|
||||
$aHiddenValues[] = "<input type=\"hidden\" name=\"{$sName}[]\" value=\"".htmlentities($sKey, ENT_QUOTES, 'UTF-8')."\"/>";
|
||||
}
|
||||
} else {
|
||||
if ($sKey == $this->defaultValue) {
|
||||
}
|
||||
else
|
||||
{
|
||||
if ($sKey == $this->defaultValue)
|
||||
{
|
||||
$aSelected[] = $sDisplayValue;
|
||||
$aHiddenValues[] = "<input type=\"hidden\" id=\"$sId\" name=\"$sName\" value=\"".utils::EscapeHtml($sKey)."\"/>";
|
||||
$aHiddenValues[] = "<input type=\"hidden\" id=\"$sId\" name=\"$sName\" value=\"".htmlentities($sKey, ENT_QUOTES, 'UTF-8')."\"/>";
|
||||
}
|
||||
}
|
||||
}
|
||||
$sHtml = "<span $sCSSClasses>".utils::EscapeHtml(implode(', ', $aSelected)).implode($aHiddenValues)."</span>";
|
||||
$sHtml = "<span $sCSSClasses>".htmlentities(implode(', ', $aSelected), ENT_QUOTES, 'UTF-8').implode($aHiddenValues)."</span>";
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1319,7 +1328,7 @@ class DesignerComboField extends DesignerFormField
|
||||
}
|
||||
// Quick and dirty: display the menu parents as a tree
|
||||
$sHtmlValue = str_replace(' ', ' ', $sDisplayValue);
|
||||
$sHtml .= "<option value=\"".utils::EscapeHtml($sKey)."\" $sSelected>$sHtmlValue</option>";
|
||||
$sHtml .= "<option value=\"".htmlentities($sKey, ENT_QUOTES, 'UTF-8')."\" $sSelected>$sHtmlValue</option>";
|
||||
}
|
||||
$sHtml .= "</select></span>";
|
||||
if ($this->bOtherChoices)
|
||||
@@ -1370,9 +1379,10 @@ class DesignerBooleanField extends DesignerFormField
|
||||
$sId = $this->oForm->GetFieldId($this->sCode);
|
||||
$sName = $this->oForm->GetFieldName($this->sCode);
|
||||
$sChecked = $this->defaultValue ? 'checked' : '';
|
||||
if ($this->IsReadOnly()) {
|
||||
if ($this->IsReadOnly())
|
||||
{
|
||||
$sLabel = $this->defaultValue ? Dict::S('UI:UserManagement:ActionAllowed:Yes') : Dict::S('UI:UserManagement:ActionAllowed:No'); //TODO use our own yes/no translations
|
||||
$sHtmlValue = "<span>".utils::EscapeHtml($sLabel)."<input type=\"hidden\" id=\"$sId\" name=\"$sName\" value=\"".utils::EscapeHtml($this->defaultValue)."\"/></span>";
|
||||
$sHtmlValue = "<span>".htmlentities($sLabel)."<input type=\"hidden\" id=\"$sId\" name=\"$sName\" value=\"".htmlentities($this->defaultValue, ENT_QUOTES, 'UTF-8')."\"/></span>";
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1440,8 +1450,8 @@ class DesignerHiddenField extends DesignerFormField
|
||||
{
|
||||
$sId = $this->oForm->GetFieldId($this->sCode);
|
||||
$sName = $this->oForm->GetFieldName($this->sCode);
|
||||
|
||||
return array('label' => '', 'value' => "<input type=\"hidden\" id=\"$sId\" name=\"$sName\" value=\"".utils::EscapeHtml($this->defaultValue)."\">");
|
||||
$sChecked = $this->defaultValue ? 'checked' : '';
|
||||
return array('label' =>'', 'value' => "<input type=\"hidden\" id=\"$sId\" name=\"$sName\" value=\"".htmlentities($this->defaultValue, ENT_QUOTES, 'UTF-8')."\">");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1508,7 +1518,7 @@ class DesignerIconSelectionField extends DesignerFormField
|
||||
EOF
|
||||
);
|
||||
} else {
|
||||
$sValue = '<span style="display:inline-block;line-height:48px;height:48px;"><span><img style="vertical-align:middle" src="'.$this->aAllowedValues[$idx]['icon'].'" /> '.utils::EscapeHtml($this->aAllowedValues[$idx]['label']).'</span></span>';
|
||||
$sValue = '<span style="display:inline-block;line-height:48px;height:48px;"><span><img style="vertical-align:middle" src="'.$this->aAllowedValues[$idx]['icon'].'" /> '.htmlentities($this->aAllowedValues[$idx]['label'], ENT_QUOTES, 'UTF-8').'</span></span>';
|
||||
}
|
||||
$sReadOnly = $this->IsReadOnly() ? 'disabled' : '';
|
||||
return array('label' => $this->sLabel, 'value' => $sValue);
|
||||
@@ -1655,14 +1665,14 @@ class DesignerSortableField extends DesignerFormField
|
||||
$sId = $this->oForm->GetFieldId($this->sCode);
|
||||
$sName = $this->oForm->GetFieldName($this->sCode);
|
||||
$sReadOnly = $this->IsReadOnly() ? 'readonly="readonly"' : '';
|
||||
$aResult = array('label' => $this->sLabel, 'value' => "<input type=\"hidden\" id=\"$sId\" name=\"$sName\" $sReadOnly value=\"".utils::EscapeHtml($this->defaultValue)."\">");
|
||||
|
||||
$aResult = array('label' => $this->sLabel, 'value' => "<input type=\"hidden\" id=\"$sId\" name=\"$sName\" $sReadOnly value=\"".htmlentities($this->defaultValue, ENT_QUOTES, 'UTF-8')."\">");
|
||||
|
||||
|
||||
$sJSFields = json_encode(array_keys($this->aAllowedValues));
|
||||
$oP->add_ready_script(
|
||||
"$('#$sId').sortable_field({aAvailableFields: $sJSFields});"
|
||||
);
|
||||
|
||||
|
||||
return $aResult;
|
||||
}
|
||||
}
|
||||
@@ -1751,8 +1761,8 @@ class DesignerFormSelectorField extends DesignerFormField
|
||||
foreach ($this->aSubForms as $iKey => $aFormData) {
|
||||
if ($iKey == $this->defaultValue) // Default value is actually the index
|
||||
{
|
||||
$sDisplayValue = utils::EscapeHtml($aFormData['label']);
|
||||
$sHiddenValue = "<input type=\"hidden\" id=\"$sId\" name=\"$sName\" value=\"".utils::EscapeHtml($iKey)."\"/>";
|
||||
$sDisplayValue = htmlentities($aFormData['label'], ENT_QUOTES, 'UTF-8');
|
||||
$sHiddenValue = "<input type=\"hidden\" id=\"$sId\" name=\"$sName\" value=\"".htmlentities($iKey, ENT_QUOTES, 'UTF-8')."\"/>";
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -1760,8 +1770,8 @@ class DesignerFormSelectorField extends DesignerFormField
|
||||
} else {
|
||||
$sHtml = "<span class=\"ibo-input-select-wrapper\"><select $sCSSClasses id=\"$sId\" name=\"$sName\" $sReadOnly>";
|
||||
foreach ($this->aSubForms as $iKey => $aFormData) {
|
||||
$sDisplayValue = utils::EscapeHtml($aFormData['label']);
|
||||
$sValue = utils::EscapeHtml($aFormData['value']);
|
||||
$sDisplayValue = htmlentities($aFormData['label'], ENT_QUOTES, 'UTF-8');
|
||||
$sValue = htmlentities($aFormData['value'], ENT_QUOTES, 'UTF-8');
|
||||
$sSelected = ($iKey == $this->defaultValue) ? 'selected' : '';
|
||||
$sHtml .= "<option data-value=\"$sValue\" value=\"$iKey\" $sSelected>".$sDisplayValue."</option>";
|
||||
}
|
||||
|
||||
@@ -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');
|
||||
@@ -59,7 +59,6 @@ class LoginBasic extends AbstractLoginFSMExtension
|
||||
list($sAuthUser, $sAuthPwd) = $this->GetAuthUserAndPassword();
|
||||
if (!UserRights::CheckCredentials($sAuthUser, $sAuthPwd, Session::Get('login_mode'), 'internal'))
|
||||
{
|
||||
$_SESSION['auth_user'] = $sAuthUser;
|
||||
$iErrorCode = LoginWebPage::EXIT_CODE_WRONGCREDENTIALS;
|
||||
return LoginWebPage::LOGIN_FSM_ERROR;
|
||||
}
|
||||
|
||||
@@ -42,7 +42,6 @@ class LoginExternal extends AbstractLoginFSMExtension
|
||||
$sAuthUser = $this->GetAuthUser();
|
||||
if (!UserRights::CheckCredentials($sAuthUser, '', Session::Get('login_mode'), 'external'))
|
||||
{
|
||||
$_SESSION['auth_user'] = $sAuthUser;
|
||||
$iErrorCode = LoginWebPage::EXIT_CODE_WRONGCREDENTIALS;
|
||||
return LoginWebPage::LOGIN_FSM_ERROR;
|
||||
}
|
||||
@@ -89,4 +88,4 @@ class LoginExternal extends AbstractLoginFSMExtension
|
||||
/** @var string $sAuthUser */
|
||||
return $sAuthUser; // Retrieve the value
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -68,7 +68,6 @@ class LoginForm extends AbstractLoginFSMExtension implements iLoginUIExtension
|
||||
$sAuthPwd = utils::ReadPostedParam('auth_pwd', null, 'raw_data');
|
||||
if (!UserRights::CheckCredentials($sAuthUser, $sAuthPwd, Session::Get('login_mode'), 'internal'))
|
||||
{
|
||||
$_SESSION['auth_user'] = $sAuthUser;
|
||||
$iErrorCode = LoginWebPage::EXIT_CODE_WRONGCREDENTIALS;
|
||||
return LoginWebPage::LOGIN_FSM_ERROR;
|
||||
}
|
||||
|
||||
@@ -8,10 +8,7 @@
|
||||
|
||||
|
||||
use Combodo\iTop\Application\Branding;
|
||||
use Combodo\iTop\Application\TwigBase\Twig\Extension;
|
||||
use Twig\Environment;
|
||||
use Twig\Loader\ChainLoader;
|
||||
use Twig\Loader\FilesystemLoader;
|
||||
use Combodo\iTop\TwigExtension;
|
||||
|
||||
/**
|
||||
* Twig context for modules extending the login screen
|
||||
@@ -220,14 +217,14 @@ class LoginTwigRenderer
|
||||
$sTwigLoaderPath = $oLoginContext->GetTwigLoaderPath();
|
||||
if ($sTwigLoaderPath != null)
|
||||
{
|
||||
$oExtensionLoader = new FilesystemLoader();
|
||||
$oExtensionLoader = new Twig_Loader_Filesystem();
|
||||
$oExtensionLoader->setPaths($sTwigLoaderPath);
|
||||
$aTwigLoaders[] = $oExtensionLoader;
|
||||
}
|
||||
$this->aPostedVars = array_merge($this->aPostedVars, $oLoginContext->GetPostedVars());
|
||||
}
|
||||
|
||||
$oCoreLoader = new FilesystemLoader(array(), APPROOT.'templates');
|
||||
$oCoreLoader = new Twig_Loader_Filesystem(array(), APPROOT.'templates');
|
||||
$aCoreTemplatesPaths = array('pages/login', 'pages/login/password');
|
||||
// Having this path declared after the plugins let the plugins replace the core templates
|
||||
$oCoreLoader->setPaths($aCoreTemplatesPaths);
|
||||
@@ -235,9 +232,9 @@ class LoginTwigRenderer
|
||||
$oCoreLoader->setPaths($aCoreTemplatesPaths, 'ItopCore');
|
||||
$aTwigLoaders[] = $oCoreLoader;
|
||||
|
||||
$oLoader = new ChainLoader($aTwigLoaders);
|
||||
$this->oTwig = new Environment($oLoader);
|
||||
Extension::RegisterTwigExtensions($this->oTwig);
|
||||
$oLoader = new Twig_Loader_Chain($aTwigLoaders);
|
||||
$this->oTwig = new Twig_Environment($oLoader);
|
||||
TwigExtension::RegisterTwigExtensions($this->oTwig);
|
||||
}
|
||||
|
||||
public function GetDefaultVars()
|
||||
@@ -309,7 +306,7 @@ class LoginTwigRenderer
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Twig\Environment
|
||||
* @return \Twig_Environment
|
||||
*/
|
||||
public function GetTwig()
|
||||
{
|
||||
|
||||
@@ -57,7 +57,6 @@ class LoginURL extends AbstractLoginFSMExtension
|
||||
$sAuthPwd = utils::ReadParam('auth_pwd', null, false, 'raw_data');
|
||||
if (!UserRights::CheckCredentials($sAuthUser, $sAuthPwd, Session::Get('login_mode'), 'internal'))
|
||||
{
|
||||
$_SESSION['auth_user'] = $sAuthUser;
|
||||
$iErrorCode = LoginWebPage::EXIT_CODE_WRONGCREDENTIALS;
|
||||
return LoginWebPage::LOGIN_FSM_ERROR;
|
||||
}
|
||||
@@ -93,4 +92,4 @@ class LoginURL extends AbstractLoginFSMExtension
|
||||
}
|
||||
return LoginWebPage::LOGIN_FSM_CONTINUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -26,8 +26,6 @@
|
||||
|
||||
use Combodo\iTop\Application\Branding;
|
||||
use Combodo\iTop\Application\Helper\Session;
|
||||
use Combodo\iTop\Service\EventData;
|
||||
use Combodo\iTop\Service\EventService;
|
||||
|
||||
/**
|
||||
* Web page used for displaying the login form
|
||||
@@ -133,6 +131,10 @@ class LoginWebPage extends NiceWebPage
|
||||
//add profiles not already linked with user
|
||||
foreach ($aProfiles as $iProfileId)
|
||||
{
|
||||
$oLink = new URP_UserProfile();
|
||||
$oLink->Set('profileid', $iProfileId);
|
||||
$oLink->Set('reason', $sOrigin);
|
||||
|
||||
$oProfilesSet->AddItem(MetaModel::NewObject('URP_UserProfile', array('profileid' => $iProfileId, 'reason' => $sOrigin)));
|
||||
}
|
||||
$oUser->Set('profile_list', $oProfilesSet);
|
||||
@@ -481,13 +483,11 @@ class LoginWebPage extends NiceWebPage
|
||||
$iResponse = $oLoginFSMExtensionInstance->LoginAction($sLoginState, $iErrorCode);
|
||||
if ($iResponse == self::LOGIN_FSM_RETURN)
|
||||
{
|
||||
EventService::FireEvent(new EventData(EVENT_SERVICE_LOGIN, null, ['code' => $iErrorCode, 'state' => $sLoginState]));
|
||||
Session::WriteClose();
|
||||
return $iErrorCode; // Asked to exit FSM, generally login OK
|
||||
}
|
||||
if ($iResponse == self::LOGIN_FSM_ERROR)
|
||||
{
|
||||
EventService::FireEvent(new EventData(EVENT_SERVICE_LOGIN, null, ['code' => $iErrorCode, 'state' => $sLoginState]));
|
||||
$sLoginState = self::LOGIN_STATE_SET_ERROR; // Next state will be error
|
||||
// An error was detected, skip the other plugins turn
|
||||
break;
|
||||
@@ -501,7 +501,6 @@ class LoginWebPage extends NiceWebPage
|
||||
}
|
||||
catch (Exception $e)
|
||||
{
|
||||
EventService::FireEvent(new EventData(EVENT_SERVICE_LOGIN, null, ['state' => $_SESSION['login_state']]));
|
||||
IssueLog::Error($e->getTraceAsString());
|
||||
static::ResetSession();
|
||||
die($e->getMessage());
|
||||
|
||||
@@ -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,7 +18,8 @@
|
||||
*/
|
||||
|
||||
use Combodo\iTop\Application\UI\Base\Component\Alert\AlertUIBlockFactory;
|
||||
use Combodo\iTop\Application\UI\Base\Component\FieldSet\FieldSetUIBlockFactory;
|
||||
use Combodo\iTop\Application\UI\Base\Component\Field\Field;
|
||||
use Combodo\iTop\Application\UI\Base\Component\Field\FieldUIBlockFactory;
|
||||
use Combodo\iTop\Application\UI\Base\Component\Html\Html;
|
||||
use Combodo\iTop\Application\UI\Base\Component\Input\TextArea;
|
||||
|
||||
@@ -50,7 +51,6 @@ 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,41 +68,6 @@ 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
|
||||
@@ -113,54 +78,6 @@ 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
|
||||
@@ -199,51 +116,13 @@ class QueryOQL extends Query
|
||||
|
||||
// Display lists
|
||||
MetaModel::Init_SetZListItems('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
|
||||
array('name', 'is_template', 'description', 'oql', 'fields')); // 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);
|
||||
@@ -273,11 +152,9 @@ 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);
|
||||
$oFieldSet->AddSubBlock($oTextArea);
|
||||
$oPage->AddSubBlock($oFieldSet);
|
||||
$oFieldUrl = FieldUIBlockFactory::MakeFromObject(Dict::S('UI:Query:UrlForExcel'), $oTextArea, Field::ENUM_FIELD_LAYOUT_LARGE);
|
||||
$oPage->AddSubBlock($oFieldUrl);
|
||||
|
||||
if (count($aParameters) == 0) {
|
||||
$oBlock = new DisplayBlock($oSearch, 'list');
|
||||
@@ -301,7 +178,6 @@ class QueryOQL extends Query
|
||||
return $aFieldsMap;
|
||||
}
|
||||
|
||||
|
||||
// Rolled back until 'fields' can be properly managed by AttributeQueryAttCodeSet
|
||||
//
|
||||
// public function ComputeValues()
|
||||
|
||||
@@ -229,10 +229,12 @@ class DisplayTemplate
|
||||
static public function UnitTest()
|
||||
{
|
||||
require_once(APPROOT.'/application/startup.inc.php');
|
||||
require_once(APPROOT."/application/itopwebpage.class.inc.php");
|
||||
|
||||
$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>
|
||||
@@ -351,7 +353,7 @@ class ObjectDetailsTemplate extends DisplayTemplate
|
||||
$sTip = '';
|
||||
foreach($aReasons as $aRow)
|
||||
{
|
||||
$sDescription = utils::EscapeHtml($aRow['description']);
|
||||
$sDescription = htmlentities($aRow['description'], ENT_QUOTES, 'UTF-8');
|
||||
$sDescription = str_replace(array("\r\n", "\n"), "<br/>", $sDescription);
|
||||
$sTip .= "<div class='synchro-source'>";
|
||||
$sTip .= "<div class='synchro-source-title'>Synchronized with {$aRow['name']}</div>";
|
||||
@@ -359,10 +361,10 @@ class ObjectDetailsTemplate extends DisplayTemplate
|
||||
}
|
||||
$oPage->add_ready_script("$('#synchro_$iInputId').qtip( { content: '$sTip', show: 'mouseover', hide: 'mouseout', style: { name: 'dark', tip: 'leftTop' }, position: { corner: { target: 'rightMiddle', tooltip: 'leftTop' }} } );");
|
||||
}
|
||||
|
||||
|
||||
// Attribute is read-only
|
||||
$sHTMLValue = "<span id=\"field_{$iInputId}\">".$this->m_oObj->GetAsHTML($sAttCode);
|
||||
$sHTMLValue .= '<input type="hidden" id="'.$iInputId.'" name="attr_'.$sAttCode.'" value="'.utils::EscapeHtml($this->m_oObj->Get($sAttCode)).'"/></span>';
|
||||
$sHTMLValue .= '<input type="hidden" id="'.$iInputId.'" name="attr_'.$sAttCode.'" value="'.htmlentities($this->m_oObj->Get($sAttCode), ENT_QUOTES, 'UTF-8').'"/></span>';
|
||||
$aFieldsMap[$sAttCode] = $iInputId;
|
||||
$aParams['this->comments('.$sAttCode.')'] = $sSynchroIcon;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
<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>
|
||||
|
||||
@@ -4,17 +4,13 @@ namespace Combodo\iTop;
|
||||
|
||||
use AttributeDate;
|
||||
use AttributeDateTime;
|
||||
use DeprecatedCallsLog;
|
||||
use Dict;
|
||||
use Exception;
|
||||
use MetaModel;
|
||||
use Twig\Environment;
|
||||
use Twig\TwigFilter;
|
||||
use Twig\TwigFunction;
|
||||
use Twig_Environment;
|
||||
use Twig_SimpleFilter;
|
||||
use Twig_SimpleFunction;
|
||||
use utils;
|
||||
|
||||
DeprecatedCallsLog::NotifyDeprecatedFile('instead use sources/Application/TwigBase/Twig/Extension.php, which is loaded by the autoloader');
|
||||
|
||||
/**
|
||||
* Class TwigExtension
|
||||
*
|
||||
@@ -28,13 +24,13 @@ class TwigExtension
|
||||
* Registers Twig extensions such as filters or functions.
|
||||
* It allows us to access some stuff directly in twig.
|
||||
*
|
||||
* @param Environment $oTwigEnv
|
||||
* @param \Twig_Environment $oTwigEnv
|
||||
*/
|
||||
public static function RegisterTwigExtensions(Environment &$oTwigEnv)
|
||||
public static function RegisterTwigExtensions(Twig_Environment &$oTwigEnv)
|
||||
{
|
||||
// Filter to translate a string via the Dict::S function
|
||||
// Usage in twig: {{ 'String:ToTranslate'|dict_s }}
|
||||
$oTwigEnv->addFilter(new TwigFilter('dict_s',
|
||||
$oTwigEnv->addFilter(new Twig_SimpleFilter('dict_s',
|
||||
function ($sStringCode, $sDefault = null, $bUserLanguageOnly = false) {
|
||||
return Dict::S($sStringCode, $sDefault, $bUserLanguageOnly);
|
||||
})
|
||||
@@ -42,7 +38,7 @@ class TwigExtension
|
||||
|
||||
// Filter to format a string via the Dict::Format function
|
||||
// Usage in twig: {{ 'String:ToTranslate'|dict_format() }}
|
||||
$oTwigEnv->addFilter(new TwigFilter('dict_format',
|
||||
$oTwigEnv->addFilter(new Twig_SimpleFilter('dict_format',
|
||||
function ($sStringCode, $sParam01 = null, $sParam02 = null, $sParam03 = null, $sParam04 = null) {
|
||||
return Dict::Format($sStringCode, $sParam01, $sParam02, $sParam03, $sParam04);
|
||||
})
|
||||
@@ -51,13 +47,16 @@ class TwigExtension
|
||||
// Filter to format output
|
||||
// example a DateTime is converted to user format
|
||||
// Usage in twig: {{ 'String:ToFormat'|output_format }}
|
||||
$oTwigEnv->addFilter(new TwigFilter('date_format',
|
||||
$oTwigEnv->addFilter(new Twig_SimpleFilter('date_format',
|
||||
function ($sDate) {
|
||||
try {
|
||||
if (preg_match('@^\d\d\d\d-\d\d-\d\d \d\d:\d\d:\d\d$@', trim($sDate))) {
|
||||
try
|
||||
{
|
||||
if (preg_match('@^\d\d\d\d-\d\d-\d\d \d\d:\d\d:\d\d$@', trim($sDate)))
|
||||
{
|
||||
return AttributeDateTime::GetFormat()->Format($sDate);
|
||||
}
|
||||
if (preg_match('@^\d\d\d\d-\d\d-\d\d$@', trim($sDate))) {
|
||||
if (preg_match('@^\d\d\d\d-\d\d-\d\d$@', trim($sDate)))
|
||||
{
|
||||
return AttributeDate::GetFormat()->Format($sDate);
|
||||
}
|
||||
}
|
||||
@@ -72,7 +71,7 @@ class TwigExtension
|
||||
// Filter to format output
|
||||
// example a DateTime is converted to user format
|
||||
// Usage in twig: {{ 'String:ToFormat'|output_format }}
|
||||
$oTwigEnv->addFilter(new TwigFilter('size_format',
|
||||
$oTwigEnv->addFilter(new Twig_SimpleFilter('size_format',
|
||||
function ($sSize) {
|
||||
return utils::BytesToFriendlyFormat($sSize);
|
||||
})
|
||||
@@ -80,25 +79,24 @@ class TwigExtension
|
||||
|
||||
// Filter to enable base64 encode/decode
|
||||
// Usage in twig: {{ 'String to encode'|base64_encode }}
|
||||
$oTwigEnv->addFilter(new TwigFilter('base64_encode', 'base64_encode'));
|
||||
$oTwigEnv->addFilter(new TwigFilter('base64_decode', 'base64_decode'));
|
||||
$oTwigEnv->addFilter(new Twig_SimpleFilter('base64_encode', 'base64_encode'));
|
||||
$oTwigEnv->addFilter(new Twig_SimpleFilter('base64_decode', 'base64_decode'));
|
||||
|
||||
// Filter to enable json decode (encode already exists)
|
||||
// Usage in twig: {{ aSomeArray|json_decode }}
|
||||
$oTwigEnv->addFilter(new TwigFilter('json_decode', function ($sJsonString, $bAssoc = false) {
|
||||
$oTwigEnv->addFilter(new Twig_SimpleFilter('json_decode', function ($sJsonString, $bAssoc = false) {
|
||||
return json_decode($sJsonString, $bAssoc);
|
||||
})
|
||||
);
|
||||
|
||||
// Filter to add itopversion to an url
|
||||
$oTwigEnv->addFilter(new TwigFilter('add_itop_version', function ($sUrl) {
|
||||
$oTwigEnv->addFilter(new Twig_SimpleFilter('add_itop_version', function ($sUrl) {
|
||||
$sUrl = utils::AddParameterToUrl($sUrl, 'itopversion', ITOP_VERSION);
|
||||
|
||||
return $sUrl;
|
||||
}));
|
||||
|
||||
// Filter to add a module's version to an url
|
||||
$oTwigEnv->addFilter(new TwigFilter('add_module_version', function ($sUrl, $sModuleName) {
|
||||
$oTwigEnv->addFilter(new Twig_SimpleFilter('add_module_version', function ($sUrl, $sModuleName) {
|
||||
$sModuleVersion = utils::GetCompiledModuleVersion($sModuleName);
|
||||
$sUrl = utils::AddParameterToUrl($sUrl, 'moduleversion', $sModuleVersion);
|
||||
|
||||
@@ -107,36 +105,22 @@ class TwigExtension
|
||||
|
||||
// Function to check our current environment
|
||||
// Usage in twig: {% if is_development_environment() %}
|
||||
$oTwigEnv->addFunction(new TwigFunction('is_development_environment', function () {
|
||||
$oTwigEnv->addFunction(new Twig_SimpleFunction('is_development_environment', function()
|
||||
{
|
||||
return utils::IsDevelopmentEnvironment();
|
||||
}));
|
||||
|
||||
// Function to get configuration parameter
|
||||
// Usage in twig: {{ get_config_parameter('foo') }}
|
||||
$oTwigEnv->addFunction(new TwigFunction('get_config_parameter', function ($sParamName) {
|
||||
$oConfig = MetaModel::GetConfig();
|
||||
|
||||
return $oConfig->Get($sParamName);
|
||||
}));
|
||||
|
||||
// Function to get a module setting
|
||||
// Usage in twig: {{ get_module_setting(<MODULE_CODE>, <PROPERTY_CODE> [, <DEFAULT_VALUE>]) }}
|
||||
// since 3.0.0, but see N°4034 for upcoming evolutions in the 3.1
|
||||
$oTwigEnv->addFunction(new TwigFunction('get_module_setting', function (string $sModuleCode, string $sPropertyCode, $defaultValue = null) {
|
||||
$oConfig = MetaModel::GetConfig();
|
||||
|
||||
return $oConfig->GetModuleSetting($sModuleCode, $sPropertyCode, $defaultValue);
|
||||
}));
|
||||
|
||||
// Function to get the URL of a static page in a module
|
||||
// Usage in twig: {{ get_static_page_module_url('itop-my-module', 'path-to-my-page') }}
|
||||
$oTwigEnv->addFunction(new TwigFunction('get_static_page_module_url', function ($sModuleName, $sPage) {
|
||||
$oTwigEnv->addFunction(new Twig_SimpleFunction('get_static_page_module_url', function($sModuleName, $sPage)
|
||||
{
|
||||
return utils::GetAbsoluteUrlModulesRoot().$sModuleName.'/'.$sPage;
|
||||
}));
|
||||
|
||||
// Function to get the URL of a php page in a module
|
||||
// Usage in twig: {{ get_page_module_url('itop-my-module', 'path-to-my-my-page.php') }}
|
||||
$oTwigEnv->addFunction(new TwigFunction('get_page_module_url', function ($sModuleName, $sPage) {
|
||||
$oTwigEnv->addFunction(new Twig_SimpleFunction('get_page_module_url', function($sModuleName, $sPage)
|
||||
{
|
||||
return utils::GetAbsoluteUrlModulePage($sModuleName, $sPage);
|
||||
}));
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
*/
|
||||
|
||||
use Combodo\iTop\Application\UI\Base\Component\Form\FormUIBlockFactory;
|
||||
use Combodo\iTop\Application\UI\Base\Component\Input\InputUIBlockFactory;
|
||||
use Combodo\iTop\Application\UI\Base\Layout\UIContentBlockUIBlockFactory;
|
||||
use Combodo\iTop\Core\MetaModel\FriendlyNameType;
|
||||
|
||||
@@ -307,7 +308,7 @@ EOF
|
||||
$sHTMLValue .= "<input class=\"field_autocomplete ibo-input ibo-input-select ibo-input-select-autocomplete\" type=\"text\" id=\"label_$this->iId\" value=\"$sDisplayValue\" placeholder='...'/>";
|
||||
|
||||
// another hidden input to store & pass the object's Id
|
||||
$sHTMLValue .= "<input type=\"hidden\" id=\"$this->iId\" name=\"{$sAttrFieldPrefix}{$sFieldName}\" value=\"".utils::HtmlEntities($value)."\" />\n";
|
||||
$sHTMLValue .= "<input type=\"hidden\" id=\"$this->iId\" name=\"{$sAttrFieldPrefix}{$sFieldName}\" value=\"".htmlentities($value, ENT_QUOTES, 'UTF-8')."\" />\n";
|
||||
|
||||
$JSSearchMode = $this->bSearchMode ? 'true' : 'false';
|
||||
// Scripts to start the autocomplete and bind some events to it
|
||||
@@ -323,12 +324,12 @@ EOF
|
||||
EOF
|
||||
);
|
||||
$sHTMLValue .= "<div class=\"ibo-input-select--action-buttons\">";
|
||||
$sHTMLValue .= " <div class=\"ibo-input-select--action-button ibo-input-select--action-button--clear ibo-is-hidden\" id=\"mini_clear_{$this->iId}\" onClick=\"oACWidget_{$this->iId}.Clear();\" data-tooltip-content='".Dict::S('UI:Button:Clear')."'><i class=\"fas fa-times\"></i></div>";
|
||||
$sHTMLValue .= " <a href=\"#\" class=\"ibo-input-select--action-button ibo-input-select--action-button--clear ibo-is-hidden\" id=\"mini_clear_{$this->iId}\" onClick=\"oACWidget_{$this->iId}.Clear();\" data-tooltip-content='".Dict::S('UI:Button:Clear')."'><i class=\"fas fa-times\"></i></a>";
|
||||
}
|
||||
if ($bCreate && $bExtensions) {
|
||||
$sCallbackName = (MetaModel::IsAbstract($this->sTargetClass)) ? 'SelectObjectClass' : 'CreateObject';
|
||||
|
||||
$sHTMLValue .= "<div class=\"ibo-input-select--action-button ibo-input-select--action-button--create\" id=\"mini_add_{$this->iId}\" onClick=\"oACWidget_{$this->iId}.{$sCallbackName}();\" data-tooltip-content='".Dict::S('UI:Button:Create')."'><i class=\"fas fa-plus\"></i></div>";
|
||||
$sHTMLValue .= "<a href=\"#\" class=\"ibo-input-select--action-button ibo-input-select--action-button--create\" id=\"mini_add_{$this->iId}\" onClick=\"oACWidget_{$this->iId}.{$sCallbackName}();\" data-tooltip-content='".Dict::S('UI:Button:Create')."'><i class=\"fas fa-plus\"></i></a>";
|
||||
$oPage->add_ready_script(
|
||||
<<<JS
|
||||
if ($('#ajax_{$this->iId}').length == 0)
|
||||
@@ -339,7 +340,7 @@ JS
|
||||
);
|
||||
}
|
||||
if ($bExtensions && MetaModel::IsHierarchicalClass($this->sTargetClass) !== false) {
|
||||
$sHTMLValue .= "<div class=\"ibo-input-select--action-button ibo-input-select--action-button--hierarchy\" id=\"mini_tree_{$this->iId}\" onClick=\"oACWidget_{$this->iId}.HKDisplay();\" data-tooltip-content='".Dict::S('UI:Button:SearchInHierarchy')."'><i class=\"fas fa-sitemap\"></i></div>";
|
||||
$sHTMLValue .= "<a href=\"#\" class=\"ibo-input-select--action-button ibo-input-select--action-button--hierarchy\" id=\"mini_tree_{$this->iId}\" onClick=\"oACWidget_{$this->iId}.HKDisplay();\" data-tooltip-content='".Dict::S('UI:Button:SearchInHierarchy')."'><i class=\"fas fa-sitemap\"></i></a>";
|
||||
$oPage->add_ready_script(
|
||||
<<<JS
|
||||
if ($('#ac_tree_{$this->iId}').length == 0)
|
||||
@@ -350,7 +351,7 @@ JS
|
||||
);
|
||||
}
|
||||
if ($oAllowedValues->CountExceeds($iMaxComboLength)) {
|
||||
$sHTMLValue .= " <div class=\"ibo-input-select--action-button ibo-input-select--action-button--search\" id=\"mini_search_{$this->iId}\" onClick=\"oACWidget_{$this->iId}.Search();\" data-tooltip-content='".Dict::S('UI:Button:Search')."'><i class=\"fas fa-search\"></i></div>";
|
||||
$sHTMLValue .= " <a href=\"#\" class=\"ibo-input-select--action-button ibo-input-select--action-button--search\" id=\"mini_search_{$this->iId}\" onClick=\"oACWidget_{$this->iId}.Search();\" data-tooltip-content='".Dict::S('UI:Button:Search')."'><i class=\"fas fa-search\"></i></a>";
|
||||
}
|
||||
$sHTMLValue .= "</div>";
|
||||
$sHTMLValue .= "</div>";
|
||||
@@ -619,7 +620,7 @@ EOF
|
||||
$sHTMLValue .= "<div class=\"ibo-input-select--action-buttons\"><span class=\"field_input_btn\"><div class=\"mini_button ibo-input-select--action-button\" id=\"mini_search_{$this->iId}\" onClick=\"oACWidget_{$this->iId}.Search();\"><i class=\"fas fa-search\"></i></div></span></div>";
|
||||
|
||||
// another hidden input to store & pass the object's Id
|
||||
$sHTMLValue .= "<input type=\"hidden\" id=\"$this->iId\" name=\"{$sAttrFieldPrefix}{$sFieldName}\" value=\"".utils::EscapeHtml($value)."\" />\n";
|
||||
$sHTMLValue .= "<input type=\"hidden\" id=\"$this->iId\" name=\"{$sAttrFieldPrefix}{$sFieldName}\" value=\"".htmlentities($value, ENT_QUOTES, 'UTF-8')."\" />\n";
|
||||
|
||||
$JSSearchMode = $this->bSearchMode ? 'true' : 'false';
|
||||
// Scripts to start the autocomplete and bind some events to it
|
||||
@@ -904,7 +905,7 @@ JS
|
||||
{
|
||||
// For security reasons: check that the "proposed" class is actually a subclass of the linked class
|
||||
// and that the current user is allowed to create objects of this class
|
||||
$aSubClasses = MetaModel::EnumChildClasses($this->sTargetClass);
|
||||
$aSubClasses = MetaModel::EnumChildClasses($this->sTargetClass, ENUM_CHILD_CLASSES_ALL);
|
||||
$aPossibleClasses = array();
|
||||
foreach($aSubClasses as $sCandidateClass)
|
||||
{
|
||||
@@ -924,6 +925,7 @@ JS
|
||||
$sDialogTitleEscaped = addslashes($sDialogTitle);
|
||||
$oPage->add_ready_script("$('#ac_create_$this->iId').dialog({ width: 'auto', height: 'auto', maxHeight: $(window).height() - 50, autoOpen: false, modal: true, title: '$sDialogTitleEscaped'});\n");
|
||||
$oPage->add_ready_script("$('#ac_create_{$this->iId} form').removeAttr('onsubmit');");
|
||||
$oPage->add_ready_script("$('#ac_create_{$this->iId} form').find('select').attr('id', 'ac_create_{$this->iId}_select');");
|
||||
$oPage->add_ready_script("$('#ac_create_{$this->iId} form').on('submit.uilinksWizard', oACWidget_{$this->iId}.DoSelectObjectClass);");
|
||||
}
|
||||
|
||||
@@ -971,7 +973,7 @@ HTML
|
||||
foreach (MetaModel::ListAttributeDefs($this->sTargetClass) as $sAttCode => $oAttDef) {
|
||||
if (($oAttDef instanceof AttributeBlob) || (false)) {
|
||||
$aFieldsFlags[$sAttCode] = OPT_ATT_READONLY;
|
||||
$aFieldsComments[$sAttCode] = ' <img src="../images/transp-lock.png" style="vertical-align:middle" title="'.utils::EscapeHtml(Dict::S('UI:UploadNotSupportedInThisMode')).'"/>';
|
||||
$aFieldsComments[$sAttCode] = ' <img src="../images/transp-lock.png" style="vertical-align:middle" title="'.htmlentities(Dict::S('UI:UploadNotSupportedInThisMode')).'"/>';
|
||||
}
|
||||
}
|
||||
cmdbAbstractObject::DisplayCreationForm($oPage, $this->sTargetClass, $oNewObj, array(), array('formPrefix' => $this->iId, 'noRelations' => true, 'fieldsFlags' => $aFieldsFlags, 'fieldsComments' => $aFieldsComments));
|
||||
@@ -984,7 +986,7 @@ HTML
|
||||
$oPage->add_ready_script(<<<JS
|
||||
$('#ac_create_{$this->iId}').dialog({ width: $(window).width() * 0.6, height: 'auto', maxHeight: $(window).height() - 50, autoOpen: false, modal: true});
|
||||
$('#dcr_{$this->iId} form').removeAttr('onsubmit');
|
||||
$('#dcr_{$this->iId} form').find('button[type="submit"]').on('click', oACWidget_{$this->iId}.DoCreateObject);
|
||||
$('#dcr_{$this->iId} form').on('submit.uilinksWizard', oACWidget_{$this->iId}.DoCreateObject);
|
||||
JS
|
||||
);
|
||||
}
|
||||
|
||||
@@ -255,7 +255,7 @@ class UILinksWidgetDirect
|
||||
$oDiv = UIContentBlockUIBlockFactory::MakeStandard($this->sInputid, ['listContainer']);
|
||||
$oPage->AddSubBlock($oDiv);
|
||||
$oDatatable = DataTableUIBlockFactory::MakeForForm($this->sInputid, $aAttribs, $aData);
|
||||
$oDatatable->SetOptions(['select_mode' => 'custom', 'disable_hyperlinks' => true]);
|
||||
$oDatatable->SetOptions(['select_mode' => 'custom']);
|
||||
$oDiv->AddSubBlock($oDatatable);
|
||||
$sInputName = $sFormPrefix.'attr_'.$this->sAttCode;
|
||||
$aLabels = array(
|
||||
|
||||
@@ -108,14 +108,15 @@ class UILinksWidget
|
||||
* @throws \CoreUnexpectedValue
|
||||
* @throws \Exception
|
||||
*/
|
||||
protected function GetFormRow(WebPage $oP, DBObject $oLinkedObj, $linkObjOrId, $aArgs, $oCurrentObj, $iUniqueId, $bReadOnly = false, $bModified = false)
|
||||
protected function GetFormRow(WebPage $oP, DBObject $oLinkedObj, $linkObjOrId, $aArgs, $oCurrentObj, $iUniqueId, $bReadOnly = false)
|
||||
{
|
||||
$sPrefix = "$this->m_sAttCode{$this->m_sNameSuffix}";
|
||||
$aRow = array();
|
||||
$aFieldsMap = array();
|
||||
$iKey = 0;
|
||||
|
||||
if (is_object($linkObjOrId) && (!$linkObjOrId->IsNew())) {
|
||||
if (is_object($linkObjOrId) && (!$linkObjOrId->IsNew()))
|
||||
{
|
||||
$iKey = $linkObjOrId->GetKey();
|
||||
$iRemoteObjKey = $linkObjOrId->Get($this->m_sExtKeyToRemote);
|
||||
$sPrefix .= "[$iKey][";
|
||||
@@ -124,44 +125,49 @@ class UILinksWidget
|
||||
$aArgs['wizHelper'] = "oWizardHelper{$this->m_iInputId}{$iKey}";
|
||||
$aArgs['this'] = $linkObjOrId;
|
||||
|
||||
if ($bReadOnly) {
|
||||
if ($bReadOnly)
|
||||
{
|
||||
$aRow['form::checkbox'] = "";
|
||||
foreach ($this->m_aEditableFields as $sFieldCode) {
|
||||
foreach ($this->m_aEditableFields as $sFieldCode)
|
||||
{
|
||||
$sDisplayValue = $linkObjOrId->GetEditValue($sFieldCode);
|
||||
$aRow[$sFieldCode] = $sDisplayValue;
|
||||
}
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
$aRow['form::checkbox'] = "<input class=\"selection\" data-remote-id=\"$iRemoteObjKey\" data-link-id=\"$iKey\" data-unique-id=\"$iUniqueId\" type=\"checkbox\" onClick=\"oWidget".$this->m_iInputId.".OnSelectChange();\" value=\"$iKey\">";
|
||||
foreach ($this->m_aEditableFields as $sFieldCode) {
|
||||
foreach ($this->m_aEditableFields as $sFieldCode)
|
||||
{
|
||||
$sSafeFieldId = $this->GetFieldId($linkObjOrId->GetKey(), $sFieldCode);
|
||||
$this->AddRowForFieldCode($aRow, $sFieldCode, $aArgs, $linkObjOrId, $oP, $sNameSuffix, $sSafeFieldId);
|
||||
$aFieldsMap[$sFieldCode] = $sSafeFieldId;
|
||||
|
||||
if ($bModified) {
|
||||
$oP->add_ready_script(
|
||||
<<<EOF
|
||||
oWidget{$this->m_iInputId}.AddModified($iUniqueId, {$this->m_iInputId}, $sFieldCode, {$linkObjOrId->Get($sFieldCode)});
|
||||
EOF
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$sState = $linkObjOrId->GetState();
|
||||
$sRemoteKeySafeFieldId = $this->GetFieldId($aArgs['this']->GetKey(), $this->m_sExtKeyToRemote);;
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
// form for creating a new record
|
||||
if (is_object($linkObjOrId)) {
|
||||
if (is_object($linkObjOrId))
|
||||
{
|
||||
// New link existing only in memory
|
||||
$oNewLinkObj = $linkObjOrId;
|
||||
$iRemoteObjKey = $oNewLinkObj->Get($this->m_sExtKeyToRemote);
|
||||
$oNewLinkObj->Set($this->m_sExtKeyToMe, $oCurrentObj); // Setting the extkey with the object also fills the related external fields
|
||||
} else {
|
||||
$oNewLinkObj->Set($this->m_sExtKeyToMe,
|
||||
$oCurrentObj); // Setting the extkey with the object also fills the related external fields
|
||||
}
|
||||
else
|
||||
{
|
||||
$iRemoteObjKey = $linkObjOrId;
|
||||
$oNewLinkObj = MetaModel::NewObject($this->m_sLinkedClass);
|
||||
$oRemoteObj = MetaModel::GetObject($this->m_sRemoteClass, $iRemoteObjKey);
|
||||
$oNewLinkObj->Set($this->m_sExtKeyToRemote, $oRemoteObj); // Setting the extkey with the object alsoo fills the related external fields
|
||||
$oNewLinkObj->Set($this->m_sExtKeyToMe, $oCurrentObj); // Setting the extkey with the object also fills the related external fields
|
||||
$oNewLinkObj->Set($this->m_sExtKeyToRemote,
|
||||
$oRemoteObj); // Setting the extkey with the object alsoo fills the related external fields
|
||||
$oNewLinkObj->Set($this->m_sExtKeyToMe,
|
||||
$oCurrentObj); // Setting the extkey with the object also fills the related external fields
|
||||
}
|
||||
$sPrefix .= "[-$iUniqueId][";
|
||||
$sNameSuffix = "]"; // To make a tabular form
|
||||
@@ -171,7 +177,8 @@ EOF
|
||||
$sInputValue = $iUniqueId > 0 ? "-$iUniqueId" : "$iUniqueId";
|
||||
$aRow['form::checkbox'] = "<input class=\"selection\" data-remote-id=\"$iRemoteObjKey\" data-link-id=\"0\" data-unique-id=\"$iUniqueId\" type=\"checkbox\" onClick=\"oWidget".$this->m_iInputId.".OnSelectChange();\" value=\"$sInputValue\">";
|
||||
|
||||
if ($iUniqueId > 0) {
|
||||
if ($iUniqueId > 0)
|
||||
{
|
||||
// Rows created with ajax call need OnLinkAdded call.
|
||||
//
|
||||
$oP->add_ready_script(
|
||||
@@ -180,7 +187,9 @@ PrepareWidgets();
|
||||
oWidget{$this->m_iInputId}.OnLinkAdded($iUniqueId, $iRemoteObjKey);
|
||||
EOF
|
||||
);
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
// Rows added before loading the form don't have to call OnLinkAdded.
|
||||
// Listeners are already present and DOM is not recreated
|
||||
$iPositiveUniqueId = -$iUniqueId;
|
||||
@@ -368,42 +377,33 @@ JS
|
||||
$aForm = array();
|
||||
$iMaxAddedId = 0;
|
||||
$iAddedId = -1; // Unique id for new links
|
||||
$oBlock->aRemoved = json_decode(utils::ReadPostedParam("attr_{$sFormPrefix}{$this->m_sAttCode}_tbd", '[]', 'raw_data'));
|
||||
$oModified = $oValue->GetModified($this->m_sExtKeyToRemote);
|
||||
while ($oCurrentLink = $oValue->Fetch()) {
|
||||
while ($oCurrentLink = $oValue->Fetch())
|
||||
{
|
||||
// We try to retrieve the remote object as usual
|
||||
if (!in_array($oCurrentLink->GetKey(), $oBlock->aRemoved)) {
|
||||
$bModified = false;
|
||||
if (array_key_exists($oCurrentLink->GetKey(), $oModified)) {
|
||||
$oLinkedObj = MetaModel::GetObject($this->m_sRemoteClass, $oModified[$oCurrentLink->GetKey()], false /* Must not be found */);
|
||||
$bModified = true;
|
||||
} else {
|
||||
$oLinkedObj = MetaModel::GetObject($this->m_sRemoteClass, $oCurrentLink->Get($this->m_sExtKeyToRemote), false /* Must not be found */);
|
||||
}
|
||||
// If successful, it means that we can edit its link
|
||||
if ($oLinkedObj !== null) {
|
||||
$bReadOnly = false;
|
||||
} // Else we retrieve it without restrictions (silos) and will display its link as readonly
|
||||
else {
|
||||
$bReadOnly = true;
|
||||
$oLinkedObj = MetaModel::GetObject($this->m_sRemoteClass, $oCurrentLink->Get($this->m_sExtKeyToRemote), false /* Must not be found */, true);
|
||||
}
|
||||
|
||||
if ($oCurrentLink->IsNew()) {
|
||||
$key = $iAddedId--;
|
||||
} else {
|
||||
$key = $oCurrentLink->GetKey();
|
||||
}
|
||||
|
||||
$iMaxAddedId = max($iMaxAddedId, $key);
|
||||
$aForm[$key] = $this->GetFormRow($oPage, $oLinkedObj, $oCurrentLink, $aArgs, $oCurrentObj, $key, $bReadOnly, $bModified);
|
||||
$oLinkedObj = MetaModel::GetObject($this->m_sRemoteClass, $oCurrentLink->Get($this->m_sExtKeyToRemote),
|
||||
false /* Must not be found */);
|
||||
// If successful, it means that we can edit its link
|
||||
if ($oLinkedObj !== null) {
|
||||
$bReadOnly = false;
|
||||
} // Else we retrieve it without restrictions (silos) and will display its link as readonly
|
||||
else {
|
||||
$bReadOnly = true;
|
||||
$oLinkedObj = MetaModel::GetObject($this->m_sRemoteClass, $oCurrentLink->Get($this->m_sExtKeyToRemote), false /* Must not be found */, true);
|
||||
}
|
||||
}
|
||||
$oBlock->iMaxAddedId = (int)$iMaxAddedId;
|
||||
|
||||
if ($oCurrentLink->IsNew()) {
|
||||
$key = $iAddedId--;
|
||||
} else {
|
||||
$key = $oCurrentLink->GetKey();
|
||||
}
|
||||
|
||||
$iMaxAddedId = max($iMaxAddedId, $key);
|
||||
$aForm[$key] = $this->GetFormRow($oPage, $oLinkedObj, $oCurrentLink, $aArgs, $oCurrentObj, $key, $bReadOnly);
|
||||
}
|
||||
$oBlock->iMaxAddedId = (int) $iMaxAddedId;
|
||||
|
||||
$oDataTable = DataTableUIBlockFactory::MakeForForm("{$this->m_sAttCode}{$this->m_sNameSuffix}", $this->m_aTableConfig, $aForm);
|
||||
$oDataTable->SetOptions(['select_mode' => 'custom', 'disable_hyperlinks' => true]);
|
||||
$oDataTable->SetOptions(['select_mode' => 'custom']);
|
||||
$oBlock->AddSubBlock($oDataTable);
|
||||
|
||||
$oBlock->AddControls();
|
||||
|
||||
@@ -60,8 +60,8 @@ class UIPasswordWidget
|
||||
$sChangedValue = (($sPasswordValue != '*****') || ($sConfirmPasswordValue != '*****')) ? 1 : 0;
|
||||
$sHtmlValue = '';
|
||||
$sHtmlValue .= '<div class="field_input_zone field_input_onewaypassword ibo-input-wrapper ibo-input-one-way-password-wrapper">';
|
||||
$sHtmlValue .= '<input class="ibo-input" type="password" maxlength="255" name="attr_'.$sCode.'[value]" id="'.$this->iId.'" value="'.utils::EscapeHtml($sPasswordValue).'"/>';
|
||||
$sHtmlValue .= '<div class="ibo-input-wrapper ibo-input-wrapper--with-buttons"><input class="ibo-input" type="password" maxlength="255" id="'.$this->iId.'_confirm" value="'.utils::EscapeHtml($sConfirmPasswordValue).'" name="attr_'.$sCode.'[confirm]"/>';
|
||||
$sHtmlValue .= '<input class="ibo-input" type="password" maxlength="255" name="attr_'.$sCode.'[value]" id="'.$this->iId.'" value="'.htmlentities($sPasswordValue, ENT_QUOTES, 'UTF-8').'"/>';
|
||||
$sHtmlValue .= '<div class="ibo-input-wrapper ibo-input-wrapper--with-buttons"><input class="ibo-input" type="password" maxlength="255" id="'.$this->iId.'_confirm" value="'.htmlentities($sConfirmPasswordValue, ENT_QUOTES, 'UTF-8').'" name="attr_'.$sCode.'[confirm]"/>';
|
||||
$sHtmlValue .= '<div class="ibo-input-select--action-buttons"><div class="ibo-input-select--action-button ibo-input-select--action-button--create" data-tooltip-content="'.Dict::S('UI:PasswordConfirm').'"><i class="fas fa-question-circle"></i></div></div></div>';
|
||||
$sHtmlValue .= '<button id="'.$this->iId.'_reset" class="ibo-button ibo-is-regular ibo-is-neutral" onClick="ResetPwd(\''.$this->iId.'\');">';
|
||||
$sHtmlValue .= '<span class="ibo-button--icon fas fa-undo"></span><span class="ibo-button--label">'.Dict::S('UI:Button:ResetPassword').'</span></button>';
|
||||
|
||||
@@ -60,7 +60,7 @@ class UISearchFormForeignKeys
|
||||
|
||||
$oPage->add(<<<HTML
|
||||
<form id="ObjectsAddForm_{$this->m_iInputId}">
|
||||
<div id="SearchResultsToAdd_{$this->m_iInputId}" style="vertical-align:top;background: #fff;height:100%;overflow:auto;padding:0;border:0;">
|
||||
<div id="SearchResultsToAdd_{$this->m_iInputId}" style="vertical-align:top;height:100%;overflow:auto;padding:0;border:0;">
|
||||
<div style="background: #fff; border:0; text-align:center; vertical-align:middle;"><p>{$sEmptyList}</p></div>
|
||||
</div>
|
||||
<input type="hidden" id="count_{$this->m_iInputId}" value="0"/>
|
||||
|
||||
@@ -158,7 +158,7 @@ class utils
|
||||
self::$m_aParamsFromFile = array();
|
||||
}
|
||||
|
||||
$aParamLines = explode("\n", $sParams);
|
||||
$aParamLines = explode("\n", $sParams ?? '');
|
||||
foreach ($aParamLines as $sLine)
|
||||
{
|
||||
$sLine = trim($sLine);
|
||||
@@ -813,20 +813,21 @@ class utils
|
||||
*/
|
||||
public static function StringToTime($sDate, $sFormat)
|
||||
{
|
||||
// Source: http://php.net/manual/fr/function.strftime.php
|
||||
// Source: http://php.net/manual/fr/function.strftime.php
|
||||
// (alternative: http://www.php.net/manual/fr/datetime.formats.date.php)
|
||||
static $aDateTokens = null;
|
||||
static $aDateRegexps = null;
|
||||
if (is_null($aDateTokens)) {
|
||||
$aSpec = array(
|
||||
'%d' => '(?<day>[0-9]{2})',
|
||||
if (is_null($aDateTokens))
|
||||
{
|
||||
$aSpec = array(
|
||||
'%d' =>'(?<day>[0-9]{2})',
|
||||
'%m' => '(?<month>[0-9]{2})',
|
||||
'%y' => '(?<year>[0-9]{2})',
|
||||
'%Y' => '(?<year>[0-9]{4})',
|
||||
'%H' => '(?<hour>[0-2][0-9])',
|
||||
'%i' => '(?<minute>[0-5][0-9])',
|
||||
'%s' => '(?<second>[0-5][0-9])',
|
||||
);
|
||||
);
|
||||
$aDateTokens = array_keys($aSpec);
|
||||
$aDateRegexps = array_values($aSpec);
|
||||
}
|
||||
@@ -1466,19 +1467,19 @@ class utils
|
||||
$oDashboard = $param;
|
||||
$sDashboardId = $oDashboard->GetId();
|
||||
$sDashboardFile = $oDashboard->GetDefinitionFile();
|
||||
$sDashboardFileRelative = utils::LocalPath($sDashboardFile);
|
||||
$sDlgTitle = addslashes(Dict::S('UI:ImportDashboardTitle'));
|
||||
$sDlgText = addslashes(Dict::S('UI:ImportDashboardText'));
|
||||
$sCloseBtn = addslashes(Dict::S('UI:Button:Cancel'));
|
||||
$sDashboardFileJS = addslashes($sDashboardFile);
|
||||
$sDashboardFileURL = urlencode($sDashboardFile);
|
||||
$sDashboardFileJS = addslashes($sDashboardFileRelative);
|
||||
$sDashboardFileURL = urlencode($sDashboardFileRelative);
|
||||
$sUploadDashboardTransactId = utils::GetNewTransactionId();
|
||||
$aResult = array(
|
||||
new SeparatorPopupMenuItem(),
|
||||
new URLPopupMenuItem('UI:ExportDashboard', Dict::S('UI:ExportDashBoard'), utils::GetAbsoluteUrlAppRoot().'pages/ajax.render.php?operation=export_dashboard&id='.$sDashboardId.'&file='.$sDashboardFileURL),
|
||||
new JSPopupMenuItem('UI:ImportDashboard', Dict::S('UI:ImportDashBoard'), "UploadDashboard({dashboard_id: '$sDashboardId', file: '$sDashboardFileJS', title: '$sDlgTitle', text: '$sDlgText', close_btn: '$sCloseBtn', transaction: '$sUploadDashboardTransactId' })"),
|
||||
);
|
||||
if ($oDashboard->GetReloadURL())
|
||||
{
|
||||
if ($oDashboard->GetReloadURL()) {
|
||||
$aResult[] = new SeparatorPopupMenuItem();
|
||||
$aResult[] = new URLPopupMenuItem('UI:Menu:PrintableVersion', Dict::S('UI:Menu:PrintableVersion'), $oDashboard->GetReloadURL().'&printable=1', '_blank');
|
||||
}
|
||||
@@ -1686,7 +1687,7 @@ class utils
|
||||
// If cURL is available, let's use it, since it provides a greater control over the various HTTP/SSL options
|
||||
// For instance fopen does not allow to work around the bug: http://stackoverflow.com/questions/18191672/php-curl-ssl-routinesssl23-get-server-helloreason1112
|
||||
// by setting the SSLVERSION to 3 as done below.
|
||||
$aHeaders = explode("\n", $sOptionnalHeaders);
|
||||
$aHeaders = explode("\n", $sOptionnalHeaders ?? '');
|
||||
// N°3267 - Webservices: Fix optional headers not being taken into account
|
||||
// See https://www.php.net/curl_setopt CURLOPT_HTTPHEADER
|
||||
$aHTTPHeaders = array();
|
||||
@@ -1826,7 +1827,7 @@ class utils
|
||||
*/
|
||||
public static function HtmlEntities($sValue)
|
||||
{
|
||||
return htmlentities($sValue ?? '', ENT_QUOTES, 'UTF-8');
|
||||
return htmlentities($sValue, ENT_QUOTES, 'UTF-8');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1842,7 +1843,7 @@ class utils
|
||||
public static function EscapeHtml($sValue)
|
||||
{
|
||||
return htmlspecialchars(
|
||||
$sValue ?? '',
|
||||
$sValue,
|
||||
ENT_QUOTES | ENT_DISALLOWED | ENT_HTML5,
|
||||
WebPage::PAGES_CHARSET,
|
||||
false
|
||||
@@ -1863,20 +1864,37 @@ class utils
|
||||
return html_entity_decode($sValue, ENT_QUOTES, 'UTF-8');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $sValue value encoded with {@see self::EscapeHtml()}
|
||||
*
|
||||
* @return string decoded value
|
||||
*
|
||||
* @uses \htmlspecialchars_decode()
|
||||
* @link https://www.php.net/manual/en/function.htmlspecialchars-decode.php
|
||||
* @since 3.0.3 3.1.0 N°6020 method creation
|
||||
*/
|
||||
public static function EscapedHtmlDecode($sValue)
|
||||
{
|
||||
return htmlspecialchars_decode(
|
||||
$sValue,
|
||||
ENT_QUOTES | ENT_DISALLOWED | ENT_HTML5
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a string containing some (valid) HTML markup to plain text
|
||||
*
|
||||
* @param string $sHtml
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function HtmlToText($sHtml)
|
||||
{
|
||||
try
|
||||
{
|
||||
try {
|
||||
//return '<?xml encoding="UTF-8">'.$sHtml;
|
||||
return \Html2Text\Html2Text::convert('<?xml encoding="UTF-8">'.$sHtml);
|
||||
}
|
||||
catch(Exception $e)
|
||||
{
|
||||
catch (Exception $e) {
|
||||
return $e->getMessage();
|
||||
}
|
||||
}
|
||||
@@ -1891,8 +1909,7 @@ class utils
|
||||
{
|
||||
$sText = str_replace("\r\n", "\n", $sText);
|
||||
$sText = str_replace("\r", "\n", $sText);
|
||||
|
||||
return str_replace("\n", '<br/>', utils::EscapeHtml($sText));
|
||||
return str_replace("\n", '<br/>', htmlentities($sText, ENT_QUOTES, 'UTF-8'));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1956,23 +1973,33 @@ class utils
|
||||
$iCurrentMaxExecTime = (int) ini_get('max_execution_time');
|
||||
set_time_limit(0);
|
||||
// Compiling SASS
|
||||
$oCompilationRes = $oSass->compileString($sSassContent);
|
||||
$sCss = $oSass->compileString($sSassContent);
|
||||
set_time_limit(intval($iCurrentMaxExecTime));
|
||||
|
||||
return $oCompilationRes->getCss();
|
||||
return $sCss->getCss();
|
||||
}
|
||||
|
||||
/**
|
||||
* 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)
|
||||
{
|
||||
return @getimagesizefromstring($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;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2244,7 +2271,7 @@ class utils
|
||||
$aParams = array();
|
||||
foreach(explode('&', $sQuery) as $sChunk)
|
||||
{
|
||||
$aParts = explode('=', $sChunk);
|
||||
$aParts = explode('=', $sChunk ?? '');
|
||||
if (count($aParts) != 2) continue;
|
||||
$aParams[$aParts[0]] = urldecode($aParts[1]);
|
||||
}
|
||||
@@ -2391,7 +2418,7 @@ class utils
|
||||
$aCleanHeaders = array();
|
||||
foreach( $aHeaders as $sKey => $sValue )
|
||||
{
|
||||
$aTokens = explode(':', $sValue, 2);
|
||||
$aTokens = explode(':', $sValue ?? '', 2);
|
||||
if(isset($aTokens[1]))
|
||||
{
|
||||
$aCleanHeaders[trim($aTokens[0])] = trim($aTokens[1]);
|
||||
@@ -2718,24 +2745,10 @@ HTML;
|
||||
$aAutoloadClassMaps = array_merge($aAutoloadClassMaps, glob(APPROOT.'env-'.utils::GetCurrentEnvironment().'/*/vendor/composer/autoload_classmap.php'));
|
||||
|
||||
$aClassMap = [];
|
||||
$aAutoloaderErrors = [];
|
||||
foreach ($aAutoloadClassMaps as $sAutoloadFile) {
|
||||
if (false === static::RealPath($sAutoloadFile, APPROOT)) {
|
||||
// can happen when we still have the autoloader symlink in env-*, but it points to a file that no longer exists
|
||||
$aAutoloaderErrors[] = $sAutoloadFile;
|
||||
continue;
|
||||
}
|
||||
$aTmpClassMap = include $sAutoloadFile;
|
||||
/** @noinspection SlowArrayOperationsInLoopInspection we are getting an associative array so the documented workarounds cannot be used */
|
||||
$aClassMap = array_merge($aClassMap, $aTmpClassMap);
|
||||
}
|
||||
if (count($aAutoloaderErrors) > 0) {
|
||||
IssueLog::Debug(
|
||||
"\utils::GetClassesForInterface cannot load some of the autoloader files",
|
||||
LogChannels::CORE,
|
||||
['autoloader_errors' => $aAutoloaderErrors]
|
||||
);
|
||||
}
|
||||
|
||||
// Add already loaded classes
|
||||
$aCurrentClasses = array_fill_keys(get_declared_classes(), '');
|
||||
@@ -2743,18 +2756,24 @@ HTML;
|
||||
|
||||
foreach ($aClassMap as $sPHPClass => $sPHPFile) {
|
||||
$bSkipped = false;
|
||||
|
||||
|
||||
// Check if our class matches name filter, or is in an excluded path
|
||||
if ($sClassNameFilter !== '' && strpos($sPHPClass, $sClassNameFilter) === false) {
|
||||
$bSkipped = true;
|
||||
}
|
||||
else {
|
||||
foreach ($aExcludedPath as $sExcludedPath) {
|
||||
// Note: We use '#' as delimiters as usual '/' is often used in paths.
|
||||
if ($sExcludedPath !== '' && preg_match('#'.$sExcludedPath.'#', $sPHPFile) === 1) {
|
||||
$bSkipped = true;
|
||||
break;
|
||||
$sPHPFile = self::LocalPath($sPHPFile);
|
||||
if ($sPHPFile !== false) {
|
||||
$sPHPFile = '/'.$sPHPFile; // for regex
|
||||
foreach ($aExcludedPath as $sExcludedPath) {
|
||||
// Note: We use '#' as delimiters as usual '/' is often used in paths.
|
||||
if ($sExcludedPath !== '' && preg_match('#'.$sExcludedPath.'#', $sPHPFile) === 1) {
|
||||
$bSkipped = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$bSkipped = true; // file not found
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2792,7 +2811,7 @@ HTML;
|
||||
$aResultPref = [];
|
||||
$aShortcutPrefs = appUserPreferences::GetPref('keyboard_shortcuts', []);
|
||||
// Note: Mind the 4 blackslashes, see utils::GetClassesForInterface()
|
||||
$aShortcutClasses = utils::GetClassesForInterface('iKeyboardShortcut', '', array('[\\\\/]lib[\\\\/]', '[\\\\/]node_modules[\\\\/]', '[\\\\/]test[\\\\/]'));
|
||||
$aShortcutClasses = utils::GetClassesForInterface('iKeyboardShortcut', '', array('[\\\\/]lib[\\\\/]', '[\\\\/]node_modules[\\\\/]', '[\\\\/]test[\\\\/]', '[\\\\/]tests[\\\\/]'));
|
||||
|
||||
foreach ($aShortcutClasses as $cShortcutPlugin) {
|
||||
$sTriggeredElement = $cShortcutPlugin::GetShortcutTriggeredElementSelector();
|
||||
@@ -2800,7 +2819,7 @@ HTML;
|
||||
$sKey = isset($aShortcutPrefs[$aShortcutKey['id']]) ? $aShortcutPrefs[$aShortcutKey['id']] : $aShortcutKey['key'];
|
||||
|
||||
// Format key for display
|
||||
$aKeyParts = explode('+', $sKey);
|
||||
$aKeyParts = explode('+', $sKey ?? '');
|
||||
$aFormattedKeyParts = [];
|
||||
foreach ($aKeyParts as $sKeyPart) {
|
||||
$aFormattedKeyParts[] = ucfirst(trim($sKeyPart));
|
||||
@@ -3143,55 +3162,15 @@ HTML;
|
||||
*/
|
||||
public static function AddParameterToUrl(string $sUrl, string $sParamName, string $sParamValue): string
|
||||
{
|
||||
if (strpos($sUrl, '?') === false) {
|
||||
if (strpos($sUrl, '?') === false)
|
||||
{
|
||||
$sUrl = $sUrl.'?'.urlencode($sParamName).'='.urlencode($sParamValue);
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
$sUrl = $sUrl.'&'.urlencode($sParamName).'='.urlencode($sParamValue);
|
||||
}
|
||||
|
||||
return $sUrl;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return traits array used by a class and by parent classes hierarchy.
|
||||
*
|
||||
* @see https://www.php.net/manual/en/function.class-uses.php#110752
|
||||
*
|
||||
* @param string $sClass Class to scan
|
||||
* @param bool $bAutoload Autoload flag
|
||||
*
|
||||
* @return array traits used
|
||||
* @since 3.1.0
|
||||
*/
|
||||
public static function TraitsUsedByClass(string $sClass, bool $bAutoload = true): array
|
||||
{
|
||||
$aTraits = [];
|
||||
do {
|
||||
$aTraits = array_merge(class_uses($sClass, $bAutoload), $aTraits);
|
||||
} while ($sClass = get_parent_class($sClass));
|
||||
foreach ($aTraits as $sTrait => $same) {
|
||||
$aTraits = array_merge(class_uses($sTrait, $bAutoload), $aTraits);
|
||||
}
|
||||
|
||||
return array_unique($aTraits);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test trait usage by a class or by parent classes hierarchy.
|
||||
*
|
||||
* @param string $sTrait Trait to search for
|
||||
* @param string $sClass Class to check
|
||||
*
|
||||
* @return bool
|
||||
* @since 3.1.0
|
||||
*/
|
||||
public static function IsTraitUsedByClass(string $sTrait, string $sClass): bool
|
||||
{
|
||||
return in_array($sTrait, self::TraitsUsedByClass($sClass, true));
|
||||
}
|
||||
|
||||
public static function GetUniqId()
|
||||
{
|
||||
return hash('sha256', uniqid(sprintf('%x', rand()), true).sprintf('%x', rand()));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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');
|
||||
@@ -359,10 +359,6 @@ class WizardHelper
|
||||
JS;
|
||||
}
|
||||
|
||||
/*
|
||||
* Function with an old pattern of code
|
||||
* @deprecated 3.1.0
|
||||
*/
|
||||
static function ParseJsonSet($oMe, $sLinkClass, $sExtKeyToMe, $sJsonSet)
|
||||
{
|
||||
$aSet = json_decode($sJsonSet, true); // true means hash array instead of object
|
||||
|
||||
@@ -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');
|
||||
@@ -11,7 +11,7 @@ define('APPCONF', APPROOT.'conf/');
|
||||
*
|
||||
* @see ITOP_CORE_VERSION to get full iTop core version
|
||||
*/
|
||||
define('ITOP_DESIGN_LATEST_VERSION', '3.1');
|
||||
define('ITOP_DESIGN_LATEST_VERSION', '3.0');
|
||||
|
||||
/**
|
||||
* Constant containing the iTop core version, whatever application was built
|
||||
@@ -23,6 +23,6 @@ define('ITOP_DESIGN_LATEST_VERSION', '3.1');
|
||||
* @used-by utils::GetItopVersionWikiSyntax()
|
||||
* @used-by iTopModulesPhpVersionIntegrationTest
|
||||
*/
|
||||
define('ITOP_CORE_VERSION', '3.1.0');
|
||||
define('ITOP_CORE_VERSION', '3.0.3');
|
||||
|
||||
require_once APPROOT.'bootstrap.inc.php';
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
"type": "project",
|
||||
"license": "AGPL-3.0-only",
|
||||
"require": {
|
||||
"php": ">=7.4.0 <8.2.0",
|
||||
"php": ">=7.1.3 <8.1.0",
|
||||
"ext-ctype": "*",
|
||||
"ext-dom": "*",
|
||||
"ext-gd": "*",
|
||||
@@ -12,26 +12,28 @@
|
||||
"ext-json": "*",
|
||||
"ext-mysqli": "*",
|
||||
"ext-soap": "*",
|
||||
"apereo/phpcas" : "~1.3",
|
||||
"combodo/tcpdf": "~6.4.4",
|
||||
"guzzlehttp/guzzle": "^7.4.5",
|
||||
"firebase/php-jwt": "~6.4.0",
|
||||
"guzzlehttp/guzzle": "^6.5.8",
|
||||
"laminas/laminas-mail": "^2.11",
|
||||
"laminas/laminas-servicemanager": "^3.5",
|
||||
"league/oauth2-google": "^3.0",
|
||||
"nikic/php-parser": "~4.14.0",
|
||||
"nikic/php-parser": "~4.13.2",
|
||||
"pear/archive_tar": "~1.4.14",
|
||||
"pelago/emogrifier": "^6.0.0",
|
||||
"pelago/emogrifier": "~3.1.0",
|
||||
"scssphp/scssphp": "^1.10.3",
|
||||
"symfony/console": "5.4.*",
|
||||
"symfony/dotenv": "5.4.*",
|
||||
"symfony/framework-bundle": "5.4.*",
|
||||
"symfony/twig-bundle": "5.4.*",
|
||||
"symfony/yaml": "5.4.*",
|
||||
"thenetworg/oauth2-azure": "^2.0"
|
||||
"swiftmailer/swiftmailer": "~6.3.0",
|
||||
"symfony/console": "~3.4.47",
|
||||
"symfony/dotenv": "~3.4.47",
|
||||
"symfony/framework-bundle": "~3.4.47",
|
||||
"symfony/twig-bundle": "~3.4.47",
|
||||
"symfony/yaml": "~3.4.47",
|
||||
"thenetworg/oauth2-azure": "^2.0",
|
||||
"twig/twig": "~1.43.1"
|
||||
},
|
||||
"require-dev": {
|
||||
"symfony/stopwatch": "5.4.*",
|
||||
"symfony/web-profiler-bundle": "5.4.*"
|
||||
"symfony/stopwatch": "~3.4.47",
|
||||
"symfony/web-profiler-bundle": "~3.4.47"
|
||||
},
|
||||
"suggest": {
|
||||
"ext-libsodium": "Required to use the AttributeEncryptedString.",
|
||||
@@ -43,7 +45,7 @@
|
||||
},
|
||||
"config": {
|
||||
"platform": {
|
||||
"php": "7.4.0"
|
||||
"php": "7.1.3"
|
||||
},
|
||||
"vendor-dir": "lib",
|
||||
"preferred-install": {
|
||||
@@ -60,7 +62,6 @@
|
||||
"sources"
|
||||
],
|
||||
"exclude-from-classmap": [
|
||||
"application/twigextension.class.inc.php",
|
||||
"core/oql/build/PHP/",
|
||||
"core/apc-emulation.php",
|
||||
"application/startup.inc.php",
|
||||
|
||||
3467
composer.lock
generated
3467
composer.lock
generated
File diff suppressed because it is too large
Load Diff
@@ -470,9 +470,9 @@ class Str
|
||||
public static function pure2html($pure, $maxLength = false)
|
||||
{
|
||||
// Check for HTML entities, but be careful the DB is in UTF-8
|
||||
return $maxLength
|
||||
? utils::EscapeHtml(substr($pure, 0, $maxLength))
|
||||
: utils::EscapeHtml($pure);
|
||||
return $maxLength
|
||||
? htmlentities(substr($pure, 0, $maxLength), ENT_QUOTES, 'UTF-8')
|
||||
: htmlentities($pure, ENT_QUOTES, 'UTF-8');
|
||||
}
|
||||
public static function pure2sql($pure, $maxLength = false)
|
||||
{
|
||||
|
||||
@@ -110,7 +110,7 @@ class apcFile
|
||||
*/
|
||||
static public function GetCacheFileName($sKey = '')
|
||||
{
|
||||
$sPath = str_replace(array(' ', '/', '\\', '.'), '-', $sKey);
|
||||
$sPath = str_replace(array(' ', '/', '\\', '.'), '-', $sKey ?? '');
|
||||
return utils::GetCachePath().'apc-emul/'.$sPath;
|
||||
}
|
||||
|
||||
|
||||
@@ -181,7 +181,7 @@ abstract class AsyncTask extends DBObject
|
||||
if (is_array($aRetries) && array_key_exists(get_class($this), $aRetries))
|
||||
{
|
||||
$aConfig = $aRetries[get_class($this)];
|
||||
$bExponential = (bool)$aConfig['exponential_delay'] ?? $bExponential;
|
||||
$bExponential = (bool) ($aConfig['exponential_delay'] ?? $bExponential);
|
||||
}
|
||||
return $bExponential;
|
||||
}
|
||||
@@ -409,6 +409,8 @@ 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);
|
||||
|
||||
@@ -705,6 +705,18 @@ abstract class AttributeDefinition
|
||||
return is_null($proposedValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $proposedValue
|
||||
*
|
||||
* @return bool True if $proposedValue is an actual value set in the attribute, false is the attribute remains "empty"
|
||||
* @since 3.0.3, 3.1.0 N°5784
|
||||
*/
|
||||
public function HasAValue($proposedValue): bool
|
||||
{
|
||||
// Default implementation, we don't really know what type $proposedValue will be
|
||||
return is_null($proposedValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* force an allowed value (type conversion and possibly forces a value as mySQL would do upon writing!
|
||||
*
|
||||
@@ -854,11 +866,6 @@ abstract class AttributeDefinition
|
||||
//abstract protected GetBasicFilterHTMLInput();
|
||||
abstract public function GetBasicFilterSQLExpr($sOpCode, $value);
|
||||
|
||||
/**
|
||||
* since 3.1.0 return has changed (N°4690 - Deprecate "FilterCodes")
|
||||
*
|
||||
* @return array filtercode => attributecode
|
||||
*/
|
||||
public function GetFilterDefinitions()
|
||||
{
|
||||
return array();
|
||||
@@ -1389,6 +1396,15 @@ class AttributeDashboard extends AttributeDefinition
|
||||
{
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function HasAValue($proposedValue): bool
|
||||
{
|
||||
// Always return false for now, we don't consider a custom version of a dashboard
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2238,6 +2254,22 @@ class AttributeLinkedSet extends AttributeDefinition
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
* @param \ormLinkSet $proposedValue
|
||||
*/
|
||||
public function HasAValue($proposedValue): bool
|
||||
{
|
||||
// Protection against wrong value type
|
||||
if (false === ($proposedValue instanceof ormLinkSet))
|
||||
{
|
||||
return parent::HasAValue($proposedValue);
|
||||
}
|
||||
|
||||
// We test if there is at least 1 item in the linkset (new or existing), not if an item is being added to it.
|
||||
return $proposedValue->Count() > 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2457,7 +2489,7 @@ class AttributeDBFieldVoid extends AttributeDefinition
|
||||
|
||||
public function GetFilterDefinitions()
|
||||
{
|
||||
return array($this->GetCode() => $this->GetCode());
|
||||
return array($this->GetCode() => new FilterFromAttribute($this));
|
||||
}
|
||||
|
||||
public function GetBasicFilterOperators()
|
||||
@@ -2619,6 +2651,14 @@ class AttributeInteger extends AttributeDBField
|
||||
return is_null($proposedValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function HasAValue($proposedValue): bool
|
||||
{
|
||||
return utils::IsNotNullOrEmptyString($proposedValue);
|
||||
}
|
||||
|
||||
public function MakeRealValue($proposedValue, $oHostObj)
|
||||
{
|
||||
if (is_null($proposedValue))
|
||||
@@ -2718,6 +2758,14 @@ class AttributeObjectKey extends AttributeDBFieldVoid
|
||||
return ($proposedValue == 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function HasAValue($proposedValue): bool
|
||||
{
|
||||
return ((int) $proposedValue) !== 0;
|
||||
}
|
||||
|
||||
public function MakeRealValue($proposedValue, $oHostObj)
|
||||
{
|
||||
if (is_null($proposedValue))
|
||||
@@ -2917,6 +2965,14 @@ class AttributeDecimal extends AttributeDBField
|
||||
return is_null($proposedValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function HasAValue($proposedValue): bool
|
||||
{
|
||||
return utils::IsNotNullOrEmptyString($proposedValue);
|
||||
}
|
||||
|
||||
public function MakeRealValue($proposedValue, $oHostObj)
|
||||
{
|
||||
if (is_null($proposedValue))
|
||||
@@ -3328,6 +3384,14 @@ class AttributeString extends AttributeDBField
|
||||
return ($proposedValue == '');
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function HasAValue($proposedValue): bool
|
||||
{
|
||||
return utils::IsNotNullOrEmptyString($proposedValue);
|
||||
}
|
||||
|
||||
public function MakeRealValue($proposedValue, $oHostObj)
|
||||
{
|
||||
if (is_null($proposedValue))
|
||||
@@ -4179,21 +4243,20 @@ class AttributeText extends AttributeString
|
||||
|
||||
public function GetEditValue($sValue, $oHostObj = null)
|
||||
{
|
||||
// N°4517 - PHP 8.1 compatibility: str_replace call with null cause deprecated message
|
||||
if ($sValue == null) {
|
||||
return '';
|
||||
}
|
||||
|
||||
if ($this->GetFormat() == 'text') {
|
||||
if (preg_match_all(WIKI_OBJECT_REGEXP, $sValue, $aAllMatches, PREG_SET_ORDER)) {
|
||||
foreach ($aAllMatches as $iPos => $aMatches) {
|
||||
if ($this->GetFormat() == 'text')
|
||||
{
|
||||
if (preg_match_all(WIKI_OBJECT_REGEXP, $sValue, $aAllMatches, PREG_SET_ORDER))
|
||||
{
|
||||
foreach($aAllMatches as $iPos => $aMatches)
|
||||
{
|
||||
$sClass = trim($aMatches[1]);
|
||||
$sName = trim($aMatches[2]);
|
||||
$sLabel = (!empty($aMatches[4])) ? trim($aMatches[4]) : null;
|
||||
|
||||
if (MetaModel::IsValidClass($sClass)) {
|
||||
if (MetaModel::IsValidClass($sClass))
|
||||
{
|
||||
$sClassLabel = MetaModel::GetName($sClass);
|
||||
$sReplacement = "[[$sClassLabel:$sName".(!empty($sLabel) ? " | $sLabel" : "")."]]";
|
||||
$sReplacement = "[[$sClassLabel:$sName" . (!empty($sLabel) ? " | $sLabel" : "") . "]]";
|
||||
$sValue = str_replace($aMatches[0], $sReplacement, $sValue);
|
||||
}
|
||||
}
|
||||
@@ -4230,31 +4293,31 @@ class AttributeText extends AttributeString
|
||||
public function MakeRealValue($proposedValue, $oHostObj)
|
||||
{
|
||||
$sValue = $proposedValue;
|
||||
|
||||
// N°4517 - PHP 8.1 compatibility: str_replace call with null cause deprecated message
|
||||
if ($sValue == null) {
|
||||
return '';
|
||||
}
|
||||
|
||||
switch ($this->GetFormat()) {
|
||||
switch ($this->GetFormat())
|
||||
{
|
||||
case 'html':
|
||||
if (($sValue !== null) && ($sValue !== '')) {
|
||||
if (($sValue !== null) && ($sValue !== ''))
|
||||
{
|
||||
$sValue = HTMLSanitizer::Sanitize($sValue);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'text':
|
||||
default:
|
||||
if (preg_match_all(WIKI_OBJECT_REGEXP, $sValue, $aAllMatches, PREG_SET_ORDER)) {
|
||||
foreach ($aAllMatches as $iPos => $aMatches) {
|
||||
if (preg_match_all(WIKI_OBJECT_REGEXP, $sValue, $aAllMatches, PREG_SET_ORDER))
|
||||
{
|
||||
foreach($aAllMatches as $iPos => $aMatches)
|
||||
{
|
||||
$sClassLabel = trim($aMatches[1]);
|
||||
$sName = trim($aMatches[2]);
|
||||
$sLabel = (!empty($aMatches[4])) ? trim($aMatches[4]) : null;
|
||||
$sLabel = (!empty($aMatches[4])) ? trim($aMatches[4]) : null;
|
||||
|
||||
if (!MetaModel::IsValidClass($sClassLabel)) {
|
||||
if (!MetaModel::IsValidClass($sClassLabel))
|
||||
{
|
||||
$sClass = MetaModel::GetClassFromLabel($sClassLabel);
|
||||
if ($sClass) {
|
||||
$sReplacement = "[[$sClassLabel:$sName".(!empty($sLabel) ? " | $sLabel" : "")."]]";
|
||||
if ($sClass)
|
||||
{
|
||||
$sReplacement = "[[$sClassLabel:$sName" . (!empty($sLabel) ? " | $sLabel" : "") . "]]";
|
||||
$sValue = str_replace($aMatches[0], $sReplacement, $sValue);
|
||||
}
|
||||
}
|
||||
@@ -4484,6 +4547,22 @@ class AttributeCaseLog extends AttributeLongText
|
||||
return ($proposedValue->GetText() == '');
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
* @param \ormCaseLog $proposedValue
|
||||
*/
|
||||
public function HasAValue($proposedValue): bool
|
||||
{
|
||||
// Protection against wrong value type
|
||||
if (false === ($proposedValue instanceof ormCaseLog)) {
|
||||
return parent::HasAValue($proposedValue);
|
||||
}
|
||||
|
||||
// We test if there is at least 1 entry in the log, not if the user is adding one
|
||||
return $proposedValue->GetEntryCount() > 0;
|
||||
}
|
||||
|
||||
|
||||
public function ScalarToSQL($value)
|
||||
{
|
||||
if (!is_string($value) && !is_null($value))
|
||||
@@ -6022,9 +6101,7 @@ class AttributeDateTime extends AttributeDBField
|
||||
|
||||
public function GetDefaultValue(DBObject $oHostObject = null)
|
||||
{
|
||||
if (!$this->IsNullAllowed()) {
|
||||
return date($this->GetInternalFormat());
|
||||
}
|
||||
// null value will be replaced by the current date, if not already set, in DoComputeValues
|
||||
return $this->GetNullValue();
|
||||
}
|
||||
|
||||
@@ -6806,6 +6883,14 @@ class AttributeExternalKey extends AttributeDBFieldVoid
|
||||
return ($proposedValue == 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function HasAValue($proposedValue): bool
|
||||
{
|
||||
return ((int) $proposedValue) !== 0;
|
||||
}
|
||||
|
||||
public function MakeRealValue($proposedValue, $oHostObj)
|
||||
{
|
||||
if (is_null($proposedValue))
|
||||
@@ -7500,7 +7585,7 @@ class AttributeExternalField extends AttributeDefinition
|
||||
|
||||
public function GetFilterDefinitions()
|
||||
{
|
||||
return array($this->GetCode() => $this->GetCode());
|
||||
return array($this->GetCode() => new FilterFromAttribute($this));
|
||||
}
|
||||
|
||||
public function GetBasicFilterOperators()
|
||||
@@ -7538,6 +7623,16 @@ class AttributeExternalField extends AttributeDefinition
|
||||
return $oExtAttDef->IsNull($proposedValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function HasAValue($proposedValue): bool
|
||||
{
|
||||
$oExtAttDef = $this->GetExtAttDef();
|
||||
|
||||
return $oExtAttDef->HasAValue($proposedValue);
|
||||
}
|
||||
|
||||
public function MakeRealValue($proposedValue, $oHostObj)
|
||||
{
|
||||
$oExtAttDef = $this->GetExtAttDef();
|
||||
@@ -7672,6 +7767,17 @@ class AttributeExternalField extends AttributeDefinition
|
||||
*/
|
||||
class AttributeURL extends AttributeString
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
* 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
|
||||
* @link http://www.php.net/manual/fr/function.preg-match.php#93824 regexp source
|
||||
* @since 3.0.1 N°4515 handle Alfresco and Sharepoint URLs
|
||||
* @since 3.0.3 moved from Config to AttributeURL constant
|
||||
*/
|
||||
public const DEFAULT_VALIDATION_PATTERN = /** @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+\$_.-]*)?';
|
||||
|
||||
/**
|
||||
* Useless constructor, but if not present PHP 7.4.0/7.4.1 is crashing :( (N°2329)
|
||||
*
|
||||
@@ -7814,7 +7920,7 @@ class AttributeBlob extends AttributeDefinition
|
||||
|
||||
public function GetDefaultValue(DBObject $oHostObject = null)
|
||||
{
|
||||
return new ormDocument('', '', '');
|
||||
return "";
|
||||
}
|
||||
|
||||
public function IsNullAllowed(DBObject $oHostObject = null)
|
||||
@@ -8113,6 +8219,20 @@ class AttributeBlob extends AttributeDefinition
|
||||
return $oFormField;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function HasAValue($proposedValue): bool
|
||||
{
|
||||
if (false === ($proposedValue instanceof ormDocument)) {
|
||||
return parent::HasAValue($proposedValue);
|
||||
}
|
||||
|
||||
// Empty file (no content, just a filename) are supported since PR {@link https://github.com/Combodo/combodo-email-synchro/pull/17}, so we check for both empty content and empty filename to determine that a document has no value
|
||||
return utils::IsNotNullOrEmptyString($proposedValue->GetData()) && utils::IsNotNullOrEmptyString($proposedValue->GetFileName());
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -8163,11 +8283,6 @@ class AttributeImage extends AttributeBlob
|
||||
return $oDoc;
|
||||
}
|
||||
|
||||
public function GetDefaultValue(DBObject $oHostObject = null)
|
||||
{
|
||||
return new ormDocument('', '', '');
|
||||
}
|
||||
|
||||
/**
|
||||
* Check that the supplied ormDocument actually contains an image
|
||||
* {@inheritDoc}
|
||||
@@ -8542,17 +8657,18 @@ class AttributeStopWatch extends AttributeDefinition
|
||||
public function GetFilterDefinitions()
|
||||
{
|
||||
$aRes = array(
|
||||
$this->GetCode() => $this->GetCode(),
|
||||
$this->GetCode().'_started' => $this->GetCode(),
|
||||
$this->GetCode().'_laststart' => $this->GetCode(),
|
||||
$this->GetCode().'_stopped' => $this->GetCode(),
|
||||
$this->GetCode() => new FilterFromAttribute($this),
|
||||
$this->GetCode().'_started' => new FilterFromAttribute($this, '_started'),
|
||||
$this->GetCode().'_laststart' => new FilterFromAttribute($this, '_laststart'),
|
||||
$this->GetCode().'_stopped' => new FilterFromAttribute($this, '_stopped')
|
||||
);
|
||||
foreach ($this->ListThresholds() as $iThreshold => $aFoo) {
|
||||
foreach($this->ListThresholds() as $iThreshold => $aFoo)
|
||||
{
|
||||
$sPrefix = $this->GetCode().'_'.$iThreshold;
|
||||
$aRes[$sPrefix.'_deadline'] = $this->GetCode();
|
||||
$aRes[$sPrefix.'_passed'] = $this->GetCode();
|
||||
$aRes[$sPrefix.'_triggered'] = $this->GetCode();
|
||||
$aRes[$sPrefix.'_overrun'] = $this->GetCode();
|
||||
$aRes[$sPrefix.'_deadline'] = new FilterFromAttribute($this, '_deadline');
|
||||
$aRes[$sPrefix.'_passed'] = new FilterFromAttribute($this, '_passed');
|
||||
$aRes[$sPrefix.'_triggered'] = new FilterFromAttribute($this, '_triggered');
|
||||
$aRes[$sPrefix.'_overrun'] = new FilterFromAttribute($this, '_overrun');
|
||||
}
|
||||
|
||||
return $aRes;
|
||||
@@ -9143,6 +9259,17 @@ class AttributeStopWatch extends AttributeDefinition
|
||||
|
||||
return $sRet;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function HasAValue($proposedValue): bool
|
||||
{
|
||||
// A stopwatch always has a value
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -9294,7 +9421,7 @@ class AttributeSubItem extends AttributeDefinition
|
||||
|
||||
public function GetFilterDefinitions()
|
||||
{
|
||||
return array($this->GetCode() => $this->GetCode());
|
||||
return array($this->GetCode() => new FilterFromAttribute($this));
|
||||
}
|
||||
|
||||
public function GetBasicFilterOperators()
|
||||
@@ -9628,6 +9755,23 @@ class AttributeOneWayPassword extends AttributeDefinition implements iAttributeN
|
||||
return '*****';
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function HasAValue($proposedValue): bool
|
||||
{
|
||||
// Protection against wrong value type
|
||||
if (false === ($proposedValue instanceof ormPassword)) {
|
||||
// On object creation, the attribute value is "" instead of an ormPassword...
|
||||
if (is_string($proposedValue)) {
|
||||
return utils::IsNotNullOrEmptyString($proposedValue);
|
||||
}
|
||||
return parent::HasAValue($proposedValue);
|
||||
}
|
||||
|
||||
return $proposedValue->IsEmpty() === false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Indexed array having two dimensions
|
||||
@@ -9677,6 +9821,15 @@ class AttributeTable extends AttributeDBField
|
||||
return (count($proposedValue) == 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function HasAValue($proposedValue): bool
|
||||
{
|
||||
return count($proposedValue) > 0;
|
||||
}
|
||||
|
||||
|
||||
public function GetEditValue($sValue, $oHostObj = null)
|
||||
{
|
||||
return '';
|
||||
@@ -10198,6 +10351,18 @@ abstract class AttributeSet extends AttributeDBFieldVoid
|
||||
return $proposedValue->Count() == 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function HasAValue($proposedValue): bool
|
||||
{
|
||||
if (false === ($proposedValue instanceof ormSet)) {
|
||||
return parent::HasAValue($proposedValue);
|
||||
}
|
||||
|
||||
return $proposedValue->Count() > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* To be overloaded for localized enums
|
||||
*
|
||||
@@ -11359,13 +11524,6 @@ class AttributeTagSet extends AttributeSet
|
||||
return new ormTagSet(MetaModel::GetAttributeOrigin($this->GetHostClass(), $this->GetCode()), $this->GetCode(), $this->GetMaxItems());
|
||||
}
|
||||
|
||||
public function GetDefaultValue(DBObject $oHostObject = null)
|
||||
{
|
||||
$oTagSet = new ormTagSet(MetaModel::GetAttributeOrigin($this->GetHostClass(), $this->GetCode()), $this->GetCode(), $this->GetMaxItems());
|
||||
$oTagSet->SetValues([]);
|
||||
return $oTagSet;
|
||||
}
|
||||
|
||||
public function IsNull($proposedValue)
|
||||
{
|
||||
if (is_null($proposedValue))
|
||||
@@ -11960,7 +12118,7 @@ class AttributeFriendlyName extends AttributeDefinition
|
||||
|
||||
public function GetFilterDefinitions()
|
||||
{
|
||||
return array($this->GetCode() => $this->GetCode());
|
||||
return array($this->GetCode() => new FilterFromAttribute($this));
|
||||
}
|
||||
|
||||
public function GetBasicFilterOperators()
|
||||
@@ -12797,7 +12955,7 @@ class AttributeCustomFields extends AttributeDefinition
|
||||
$sRet = $value->GetAsHTML($bLocalize);
|
||||
} catch (Exception $e)
|
||||
{
|
||||
$sRet = 'Custom field error: '.utils::EscapeHtml($e->getMessage());
|
||||
$sRet = 'Custom field error: '.htmlentities($e->getMessage(), ENT_QUOTES, 'UTF-8');
|
||||
}
|
||||
|
||||
return $sRet;
|
||||
@@ -12912,6 +13070,21 @@ class AttributeCustomFields extends AttributeDefinition
|
||||
|
||||
return $bEquals;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function HasAValue($proposedValue): bool
|
||||
{
|
||||
// Protection against wrong value type
|
||||
if (false === ($proposedValue instanceof ormCustomFieldsValue)) {
|
||||
return parent::HasAValue($proposedValue);
|
||||
}
|
||||
|
||||
return count($proposedValue->GetValues()) > 0;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
class AttributeArchiveFlag extends AttributeBoolean
|
||||
@@ -13097,7 +13270,7 @@ class AttributeObsolescenceFlag extends AttributeBoolean
|
||||
|
||||
public function GetDefaultValue(DBObject $oHostObject = null)
|
||||
{
|
||||
return $this->MakeRealValue(false, $oHostObject);
|
||||
return $this->MakeRealValue("", $oHostObject);
|
||||
}
|
||||
|
||||
public function IsNullAllowed()
|
||||
|
||||
@@ -42,17 +42,6 @@ abstract class CellChangeSpec
|
||||
return $this->m_sOql;
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 3.1.0 N°5305
|
||||
*/
|
||||
public function GetDisplayableValueAndDescription(): string
|
||||
{
|
||||
return sprintf("%s%s",
|
||||
$this->GetDisplayableValue(),
|
||||
$this->GetDescription()
|
||||
);
|
||||
}
|
||||
|
||||
abstract public function GetDescription();
|
||||
}
|
||||
|
||||
@@ -97,90 +86,26 @@ class CellStatus_Issue extends CellStatus_Modify
|
||||
parent::__construct($proposedValue, $previousValue);
|
||||
}
|
||||
|
||||
public function GetDisplayableValue()
|
||||
public function GetDescription()
|
||||
{
|
||||
if (is_null($this->m_proposedValue))
|
||||
{
|
||||
return Dict::Format('UI:CSVReport-Value-SetIssue');
|
||||
return Dict::Format('UI:CSVReport-Value-SetIssue', $this->m_sReason);
|
||||
}
|
||||
return Dict::Format('UI:CSVReport-Value-ChangeIssue', \utils::EscapeHtml($this->m_proposedValue));
|
||||
}
|
||||
|
||||
public function GetDescription()
|
||||
{
|
||||
return $this->m_sReason;
|
||||
}
|
||||
/*
|
||||
* @since 3.1.0 N°5305
|
||||
*/
|
||||
public function GetDisplayableValueAndDescription(): string
|
||||
{
|
||||
return sprintf("%s. %s",
|
||||
$this->GetDisplayableValue(),
|
||||
$this->GetDescription()
|
||||
);
|
||||
return Dict::Format('UI:CSVReport-Value-ChangeIssue', $this->m_proposedValue, $this->m_sReason);
|
||||
}
|
||||
}
|
||||
|
||||
class CellStatus_SearchIssue extends CellStatus_Issue
|
||||
{
|
||||
/** @var string|null $m_sAllowedValues */
|
||||
private $m_sAllowedValues;
|
||||
|
||||
/**
|
||||
* @since 3.1.0 N°5305
|
||||
* @var string $sSerializedSearch
|
||||
*/
|
||||
private $sSerializedSearch;
|
||||
|
||||
/** @var string|null $m_sTargetClass */
|
||||
private $m_sTargetClass;
|
||||
|
||||
/**
|
||||
* CellStatus_SearchIssue constructor.
|
||||
* @since 3.1.0 N°5305
|
||||
*
|
||||
* @param string $sOql : main message
|
||||
* @param string $sReason : main message
|
||||
* @param null $sClass : used for additional message that provides allowed values for current class $sClass
|
||||
* @param null $sAllowedValues : used for additional message that provides allowed values $sAllowedValues for current class
|
||||
*/
|
||||
public function __construct($sSerializedSearch, $sReason, $sClass=null, $sAllowedValues=null)
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct(null, null, $sReason);
|
||||
$this->sSerializedSearch = $sSerializedSearch;
|
||||
$this->m_sAllowedValues = $sAllowedValues;
|
||||
$this->m_sTargetClass = $sClass;
|
||||
}
|
||||
|
||||
public function GetDisplayableValue()
|
||||
{
|
||||
if (null === $this->m_sReason) {
|
||||
return Dict::Format('UI:CSVReport-Value-NoMatch', '');
|
||||
}
|
||||
|
||||
return $this->m_sReason;
|
||||
parent::__construct(null, null, null);
|
||||
}
|
||||
|
||||
public function GetDescription()
|
||||
{
|
||||
if (\utils::IsNullOrEmptyString($this->m_sAllowedValues) ||
|
||||
\utils::IsNullOrEmptyString($this->m_sTargetClass)) {
|
||||
return '';
|
||||
}
|
||||
|
||||
return Dict::Format('UI:CSVReport-Value-NoMatch-PossibleValues', $this->m_sTargetClass, $this->m_sAllowedValues);
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 3.1.0 N°5305
|
||||
* @return string
|
||||
*/
|
||||
public function GetSearchLinkUrl()
|
||||
{
|
||||
return sprintf("UI.php?operation=search&filter=%s",
|
||||
rawurlencode($this->sSerializedSearch)
|
||||
);
|
||||
return Dict::S('UI:CSVReport-Value-NoMatch');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -201,24 +126,11 @@ class CellStatus_NullIssue extends CellStatus_Issue
|
||||
class CellStatus_Ambiguous extends CellStatus_Issue
|
||||
{
|
||||
protected $m_iCount;
|
||||
/**
|
||||
* @since 3.1.0 N°5305
|
||||
* @var string
|
||||
*/
|
||||
protected $sSerializedSearch;
|
||||
|
||||
/**
|
||||
* @since 3.1.0 N°5305
|
||||
*
|
||||
* @param $previousValue
|
||||
* @param int $iCount
|
||||
* @param string $sSerializedSearch
|
||||
*
|
||||
*/
|
||||
public function __construct($previousValue, $iCount, $sSerializedSearch)
|
||||
public function __construct($previousValue, $iCount, $sOql)
|
||||
{
|
||||
$this->m_iCount = $iCount;
|
||||
$this->sSerializedSearch = $sSerializedSearch;
|
||||
$this->m_sQuery = $sOql;
|
||||
parent::__construct(null, $previousValue, '');
|
||||
}
|
||||
|
||||
@@ -227,17 +139,6 @@ class CellStatus_Ambiguous extends CellStatus_Issue
|
||||
$sCount = $this->m_iCount;
|
||||
return Dict::Format('UI:CSVReport-Value-Ambiguous', $sCount);
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 3.1.0 N°5305
|
||||
* @return string
|
||||
*/
|
||||
public function GetSearchLinkUrl()
|
||||
{
|
||||
return sprintf("UI.php?operation=search&filter=%s",
|
||||
rawurlencode($this->sSerializedSearch)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -310,26 +211,6 @@ class RowStatus_Issue extends RowStatus
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* class dedicated to testability
|
||||
* not used/ignored in csv imports UI/CLI
|
||||
* @since 3.1.0 N°5305
|
||||
*/
|
||||
class RowStatus_Error extends RowStatus
|
||||
{
|
||||
/** @var string */
|
||||
protected $m_sError;
|
||||
|
||||
public function __construct($sError)
|
||||
{
|
||||
$this->m_sError = $sError;
|
||||
}
|
||||
|
||||
public function GetDescription()
|
||||
{
|
||||
return $this->m_sError;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* BulkChange
|
||||
@@ -339,35 +220,17 @@ class RowStatus_Error extends RowStatus
|
||||
*/
|
||||
class BulkChange
|
||||
{
|
||||
/** @var string */
|
||||
protected $m_sClass;
|
||||
protected $m_aData; // Note: hereafter, iCol maybe actually be any acceptable key (string)
|
||||
// #@# todo: rename the variables to sColIndex
|
||||
/** @var array<string, string> attcode as key, iCol as value */
|
||||
protected $m_aAttList;
|
||||
/** @var array<string, array<string, string>> sExtKeyAttCode as key, array of sExtReconcKeyAttCode/iCol as value */
|
||||
protected $m_aExtKeys;
|
||||
/** @var string[] list of attcode (attcode = 'id' for the pkey) */
|
||||
protected $m_aReconcilKeys;
|
||||
/** @var string OQL - if specified, then the missing items will be reported */
|
||||
protected $m_sSynchroScope;
|
||||
/**
|
||||
* @var array<string, mixed> attcode as key, attvalue as value. Values to be set when an object gets out of scope
|
||||
* (ignored if no scope has been defined)
|
||||
*/
|
||||
protected $m_aOnDisappear;
|
||||
/**
|
||||
* @see DateTime::createFromFormat
|
||||
* @var string Date format specification
|
||||
*/
|
||||
protected $m_sDateFormat;
|
||||
/**
|
||||
* @see AttributeEnum
|
||||
* @var boolean true if Values in the data set are localized
|
||||
*/
|
||||
protected $m_bLocalizedValues;
|
||||
/** @var array Cache for resolving external keys based on the given search criterias */
|
||||
protected $m_aExtKeysMappingCache;
|
||||
protected $m_aAttList; // attcode => iCol
|
||||
protected $m_aExtKeys; // aExtKeys[sExtKeyAttCode][sExtReconcKeyAttCode] = iCol;
|
||||
protected $m_aReconcilKeys; // attcode (attcode = 'id' for the pkey)
|
||||
protected $m_sSynchroScope; // OQL - if specified, then the missing items will be reported
|
||||
protected $m_aOnDisappear; // array of attcode => value, values to be set when an object gets out of scope (ignored if no scope has been defined)
|
||||
protected $m_sDateFormat; // Date format specification, see DateTime::createFromFormat
|
||||
protected $m_bLocalizedValues; // Values in the data set are localized (see AttributeEnum)
|
||||
protected $m_aExtKeysMappingCache; // Cache for resolving external keys based on the given search criterias
|
||||
|
||||
public function __construct($sClass, $aData, $aAttList, $aExtKeys, $aReconcilKeys, $sSynchroScope = null, $aOnDisappear = null, $sDateFormat = null, $bLocalize = false)
|
||||
{
|
||||
@@ -403,25 +266,25 @@ class BulkChange
|
||||
{
|
||||
$oExtKey = MetaModel::GetAttributeDef($this->m_sClass, $sAttCode);
|
||||
$oReconFilter = new DBObjectSearch($oExtKey->GetTargetClass());
|
||||
foreach ($this->m_aExtKeys[$sAttCode] as $sReconKeyAttCode => $iCol)
|
||||
foreach ($this->m_aExtKeys[$sAttCode] as $sForeignAttCode => $iCol)
|
||||
{
|
||||
if ($sReconKeyAttCode == 'id')
|
||||
if ($sForeignAttCode == 'id')
|
||||
{
|
||||
$value = (int) $aRowData[$iCol];
|
||||
}
|
||||
else
|
||||
{
|
||||
// The foreign attribute is one of our reconciliation key
|
||||
$oForeignAtt = MetaModel::GetAttributeDef($oExtKey->GetTargetClass(), $sReconKeyAttCode);
|
||||
$oForeignAtt = MetaModel::GetAttributeDef($oExtKey->GetTargetClass(), $sForeignAttCode);
|
||||
$value = $oForeignAtt->MakeValueFromString($aRowData[$iCol], $this->m_bLocalizedValues);
|
||||
}
|
||||
$oReconFilter->AddCondition($sReconKeyAttCode, $value, '=');
|
||||
$oReconFilter->AddCondition($sForeignAttCode, $value, '=');
|
||||
$aResults[$iCol] = new CellStatus_Void(utils::HtmlEntities($aRowData[$iCol]));
|
||||
}
|
||||
|
||||
$oExtObjects = new CMDBObjectSet($oReconFilter);
|
||||
$aKeys = $oExtObjects->ToArray();
|
||||
return array($oReconFilter, $aKeys);
|
||||
return array($oReconFilter->ToOql(), $aKeys);
|
||||
}
|
||||
|
||||
// Returns true if the CSV data specifies that the external key must be left undefined
|
||||
@@ -458,7 +321,7 @@ class BulkChange
|
||||
|
||||
// External keys reconciliation
|
||||
//
|
||||
foreach($this->m_aExtKeys as $sAttCode => $aReconKeys)
|
||||
foreach($this->m_aExtKeys as $sAttCode => $aKeyConfig)
|
||||
{
|
||||
// Skip external keys used for the reconciliation process
|
||||
// if (!array_key_exists($sAttCode, $this->m_aAttList)) continue;
|
||||
@@ -467,7 +330,7 @@ class BulkChange
|
||||
|
||||
if ($this->IsNullExternalKeySpec($aRowData, $sAttCode))
|
||||
{
|
||||
foreach ($aReconKeys as $sReconKeyAttCode => $iCol)
|
||||
foreach ($aKeyConfig as $sForeignAttCode => $iCol)
|
||||
{
|
||||
// Default reporting
|
||||
// $aRowData[$iCol] is always null
|
||||
@@ -489,24 +352,25 @@ class BulkChange
|
||||
$oReconFilter = new DBObjectSearch($oExtKey->GetTargetClass());
|
||||
|
||||
$aCacheKeys = array();
|
||||
foreach ($aReconKeys as $sReconKeyAttCode => $iCol)
|
||||
foreach ($aKeyConfig as $sForeignAttCode => $iCol)
|
||||
{
|
||||
// The foreign attribute is one of our reconciliation key
|
||||
if ($sReconKeyAttCode == 'id')
|
||||
if ($sForeignAttCode == 'id')
|
||||
{
|
||||
$value = $aRowData[$iCol];
|
||||
}
|
||||
else
|
||||
{
|
||||
$oForeignAtt = MetaModel::GetAttributeDef($oExtKey->GetTargetClass(), $sReconKeyAttCode);
|
||||
$oForeignAtt = MetaModel::GetAttributeDef($oExtKey->GetTargetClass(), $sForeignAttCode);
|
||||
$value = $oForeignAtt->MakeValueFromString($aRowData[$iCol], $this->m_bLocalizedValues);
|
||||
}
|
||||
$aCacheKeys[] = $value;
|
||||
$oReconFilter->AddCondition($sReconKeyAttCode, $value, '=');
|
||||
$oReconFilter->AddCondition($sForeignAttCode, $value, '=');
|
||||
$aResults[$iCol] = new CellStatus_Void(utils::HtmlEntities($aRowData[$iCol]));
|
||||
}
|
||||
$sCacheKey = implode('_|_', $aCacheKeys); // Unique key for this query...
|
||||
$iForeignKey = null;
|
||||
$sOQL = '';
|
||||
// TODO: check if *too long* keys can lead to collisions... and skip the cache in such a case...
|
||||
if (!array_key_exists($sAttCode, $this->m_aExtKeysMappingCache))
|
||||
{
|
||||
@@ -515,8 +379,9 @@ class BulkChange
|
||||
if (array_key_exists($sCacheKey, $this->m_aExtKeysMappingCache[$sAttCode]))
|
||||
{
|
||||
// Cache hit
|
||||
$iObjectFoundCount = $this->m_aExtKeysMappingCache[$sAttCode][$sCacheKey]['c'];
|
||||
$iCount = $this->m_aExtKeysMappingCache[$sAttCode][$sCacheKey]['c'];
|
||||
$iForeignKey = $this->m_aExtKeysMappingCache[$sAttCode][$sCacheKey]['k'];
|
||||
$sOQL = $this->m_aExtKeysMappingCache[$sAttCode][$sCacheKey]['oql'];
|
||||
// Record the hit
|
||||
$this->m_aExtKeysMappingCache[$sAttCode][$sCacheKey]['h']++;
|
||||
}
|
||||
@@ -524,35 +389,34 @@ class BulkChange
|
||||
{
|
||||
// Cache miss, let's initialize it
|
||||
$oExtObjects = new CMDBObjectSet($oReconFilter);
|
||||
$iObjectFoundCount = $oExtObjects->Count();
|
||||
if ($iObjectFoundCount == 1)
|
||||
$iCount = $oExtObjects->Count();
|
||||
if ($iCount == 1)
|
||||
{
|
||||
$oForeignObj = $oExtObjects->Fetch();
|
||||
$iForeignKey = $oForeignObj->GetKey();
|
||||
}
|
||||
$this->m_aExtKeysMappingCache[$sAttCode][$sCacheKey] = array(
|
||||
'c' => $iObjectFoundCount,
|
||||
'c' => $iCount,
|
||||
'k' => $iForeignKey,
|
||||
'oql' => $oReconFilter->ToOql(),
|
||||
'h' => 0, // number of hits on this cache entry
|
||||
);
|
||||
}
|
||||
switch($iObjectFoundCount)
|
||||
switch($iCount)
|
||||
{
|
||||
case 0:
|
||||
$oCellStatus_SearchIssue = $this->GetCellSearchIssue($oReconFilter);
|
||||
$aResults[$sAttCode] = $oCellStatus_SearchIssue;
|
||||
$aErrors[$sAttCode] = Dict::S('UI:CSVReport-Value-Issue-NotFound');
|
||||
break;
|
||||
$aErrors[$sAttCode] = Dict::S('UI:CSVReport-Value-Issue-NotFound');
|
||||
$aResults[$sAttCode]= new CellStatus_SearchIssue();
|
||||
break;
|
||||
|
||||
case 1:
|
||||
// Do change the external key attribute
|
||||
$oTargetObj->Set($sAttCode, $iForeignKey);
|
||||
break;
|
||||
// Do change the external key attribute
|
||||
$oTargetObj->Set($sAttCode, $iForeignKey);
|
||||
break;
|
||||
|
||||
default:
|
||||
$aErrors[$sAttCode] = Dict::Format('UI:CSVReport-Value-Issue-FoundMany', $iObjectFoundCount);
|
||||
$aResults[$sAttCode]= new CellStatus_Ambiguous($oTargetObj->Get($sAttCode), $iObjectFoundCount, $oReconFilter->serialize());
|
||||
$aErrors[$sAttCode] = Dict::Format('UI:CSVReport-Value-Issue-FoundMany', $iCount);
|
||||
$aResults[$sAttCode]= new CellStatus_Ambiguous($oTargetObj->Get($sAttCode), $iCount, $sOQL);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -569,7 +433,7 @@ class BulkChange
|
||||
else
|
||||
{
|
||||
$aResults[$sAttCode]= new CellStatus_Modify($iForeignObj, $oTargetObj->GetOriginal($sAttCode));
|
||||
foreach ($aReconKeys as $sReconKeyAttCode => $iCol)
|
||||
foreach ($aKeyConfig as $sForeignAttCode => $iCol)
|
||||
{
|
||||
// Report the change on reconciliation values as well
|
||||
$aResults[$iCol] = new CellStatus_Modify(utils::HtmlEntities($aRowData[$iCol]));
|
||||
@@ -603,36 +467,21 @@ class BulkChange
|
||||
$iFlags = ($oTargetObj->IsNew())
|
||||
? $oTargetObj->GetInitialStateAttributeFlags($sAttCode, $aReasons)
|
||||
: $oTargetObj->GetAttributeFlags($sAttCode, $aReasons);
|
||||
if ( (($iFlags & OPT_ATT_READONLY) == OPT_ATT_READONLY) && ( $oTargetObj->Get($sAttCode) != $aRowData[$iCol]) ) {
|
||||
if ((($iFlags & OPT_ATT_READONLY) == OPT_ATT_READONLY) && ($oTargetObj->Get($sAttCode) != $oAttDef->MakeValueFromString($aRowData[$iCol], $this->m_bLocalizedValues))) {
|
||||
$aErrors[$sAttCode] = Dict::Format('UI:CSVReport-Value-Issue-Readonly', $sAttCode, $oTargetObj->Get($sAttCode), $aRowData[$iCol]);
|
||||
}
|
||||
else if ($oAttDef->IsLinkSet() && $oAttDef->IsIndirect())
|
||||
{
|
||||
try
|
||||
{
|
||||
} else if ($oAttDef->IsLinkSet() && $oAttDef->IsIndirect()) {
|
||||
try {
|
||||
$oSet = $oAttDef->MakeValueFromString($aRowData[$iCol], $this->m_bLocalizedValues);
|
||||
$oTargetObj->Set($sAttCode, $oSet);
|
||||
}
|
||||
catch(CoreException $e)
|
||||
{
|
||||
catch (CoreException $e) {
|
||||
$aErrors[$sAttCode] = Dict::Format('UI:CSVReport-Value-Issue-Format', $e->getMessage());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
$value = $oAttDef->MakeValueFromString($aRowData[$iCol], $this->m_bLocalizedValues);
|
||||
if (is_null($value) && (strlen($aRowData[$iCol]) > 0))
|
||||
{
|
||||
if ($oAttDef instanceof AttributeEnum || $oAttDef instanceof AttributeTagSet){
|
||||
/** @var AttributeDefinition $oAttributeDefinition */
|
||||
$oAttributeDefinition = $oAttDef;
|
||||
$aErrors[$sAttCode] = Dict::Format('UI:CSVReport-Value-Issue-AllowedValues', $sAttCode, implode(',', $oAttributeDefinition->GetAllowedValues()));
|
||||
} else {
|
||||
$aErrors[$sAttCode] = Dict::Format('UI:CSVReport-Value-Issue-NoMatch', $sAttCode);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (is_null($value) && (strlen($aRowData[$iCol]) > 0)) {
|
||||
$aErrors[$sAttCode] = Dict::Format('UI:CSVReport-Value-Issue-NoMatch', $sAttCode);
|
||||
} else {
|
||||
$res = $oTargetObj->CheckValue($sAttCode, $value);
|
||||
if ($res === true)
|
||||
{
|
||||
@@ -710,95 +559,6 @@ class BulkChange
|
||||
return $aResults;
|
||||
}
|
||||
|
||||
/**
|
||||
* search with current permissions did not match
|
||||
* let's search why and give some more feedbacks to the user through proper labels
|
||||
*
|
||||
* @param DBObjectSearch $oDbSearchWithConditions search used to find external key
|
||||
*
|
||||
* @return \CellStatus_SearchIssue
|
||||
* @throws \CoreException
|
||||
* @throws \MissingQueryArgument
|
||||
* @throws \MySQLException
|
||||
* @throws \MySQLHasGoneAwayException
|
||||
*
|
||||
* @since 3.1.0 N°5305
|
||||
*/
|
||||
protected function GetCellSearchIssue($oDbSearchWithConditions) : CellStatus_SearchIssue {
|
||||
//current search with current permissions did not match
|
||||
//let's search why and give some more feedback to the user
|
||||
|
||||
$sSerializedSearch = $oDbSearchWithConditions->serialize();
|
||||
|
||||
// Count all objects with all permissions without any condition
|
||||
$oDbSearchWithoutAnyCondition = new DBObjectSearch($oDbSearchWithConditions->GetClass());
|
||||
$oDbSearchWithoutAnyCondition->AllowAllData(true);
|
||||
$oExtObjectSet = new CMDBObjectSet($oDbSearchWithoutAnyCondition);
|
||||
$iAllowAllDataObjectCount = $oExtObjectSet->Count();
|
||||
|
||||
if ($iAllowAllDataObjectCount === 0) {
|
||||
$sReason = Dict::Format('UI:CSVReport-Value-NoMatch-NoObject', $oDbSearchWithConditions->GetClass());
|
||||
return new CellStatus_SearchIssue($sSerializedSearch, $sReason);
|
||||
}
|
||||
|
||||
// Count all objects with current user permissions
|
||||
$oDbSearchWithoutAnyCondition->AllowAllData(false);
|
||||
$oExtObjectSetWithCurrentUserPermissions = new CMDBObjectSet($oDbSearchWithoutAnyCondition);
|
||||
$iCurrentUserRightsObjectCount = $oExtObjectSetWithCurrentUserPermissions->Count();
|
||||
|
||||
if ($iCurrentUserRightsObjectCount === 0){
|
||||
// No objects visible by current user
|
||||
$sReason = Dict::Format('UI:CSVReport-Value-NoMatch-NoObject-ForCurrentUser', $oDbSearchWithConditions->GetClass());
|
||||
return new CellStatus_SearchIssue($sSerializedSearch, $sReason);
|
||||
}
|
||||
|
||||
try{
|
||||
$aDisplayedAllowedValues = [];
|
||||
// Possibles values are displayed to UI user. we have to limit the amount of displayed values
|
||||
$oExtObjectSetWithCurrentUserPermissions->SetLimit(4);
|
||||
for($i = 0; $i < 3; $i++){
|
||||
/** @var \DBObject $oVisibleObject */
|
||||
$oVisibleObject = $oExtObjectSetWithCurrentUserPermissions->Fetch();
|
||||
if (is_null($oVisibleObject)){
|
||||
break;
|
||||
}
|
||||
|
||||
$aCurrentAllowedValueFields = [];
|
||||
foreach ($oDbSearchWithConditions->GetInternalParams() as $sForeignAttCode => $sValue){
|
||||
$aCurrentAllowedValueFields[] = $oVisibleObject->Get($sForeignAttCode);
|
||||
}
|
||||
$aDisplayedAllowedValues[] = implode(" ", $aCurrentAllowedValueFields);
|
||||
|
||||
}
|
||||
$allowedValues = implode(", ", $aDisplayedAllowedValues);
|
||||
if ($oExtObjectSetWithCurrentUserPermissions->Count() > 3){
|
||||
$allowedValues .= "...";
|
||||
}
|
||||
} catch(Exception $e) {
|
||||
IssueLog::Error("failure during CSV import when fetching few visible objects: ", null,
|
||||
[ 'target_class' => $oDbSearchWithConditions->GetClass(), 'criteria' => $oDbSearchWithConditions->GetCriteria(), 'message' => $e->getMessage()]
|
||||
);
|
||||
$sReason = Dict::Format('UI:CSVReport-Value-NoMatch-NoObject-ForCurrentUser', $oDbSearchWithConditions->GetClass());
|
||||
return new CellStatus_SearchIssue($sSerializedSearch, $sReason);
|
||||
}
|
||||
|
||||
if ($iAllowAllDataObjectCount != $iCurrentUserRightsObjectCount) {
|
||||
// No match and some objects NOT visible by current user. including current search maybe...
|
||||
$sReason = Dict::Format('UI:CSVReport-Value-NoMatch-SomeObjectNotVisibleForCurrentUser', $oDbSearchWithConditions->GetClass());
|
||||
return new CellStatus_SearchIssue($sSerializedSearch, $sReason, $oDbSearchWithConditions->GetClass(), $allowedValues);
|
||||
}
|
||||
|
||||
// No match. This is not linked to any right issue
|
||||
// Possible values: DD,DD
|
||||
$aCurrentValueFields = [];
|
||||
foreach ($oDbSearchWithConditions->GetInternalParams() as $sValue){
|
||||
$aCurrentValueFields[] = $sValue;
|
||||
}
|
||||
$value =implode(" ", $aCurrentValueFields);
|
||||
$sReason = Dict::Format('UI:CSVReport-Value-NoMatch', $value);
|
||||
return new CellStatus_SearchIssue($sSerializedSearch, $sReason, $oDbSearchWithConditions->GetClass(), $allowedValues);
|
||||
}
|
||||
|
||||
protected function PrepareMissingObject(&$oTargetObj, &$aErrors)
|
||||
{
|
||||
$aResults = array();
|
||||
@@ -910,8 +670,6 @@ class BulkChange
|
||||
{
|
||||
$sErrors = implode(', ', $aErrors);
|
||||
$aResult[$iRow]["__STATUS__"] = new RowStatus_Issue(Dict::S('UI:CSVReport-Row-Issue-Attribute'));
|
||||
//__ERRORS__ used by tests only
|
||||
$aResult[$iRow]["__ERRORS__"] = new RowStatus_Error($sErrors);
|
||||
return $oTargetObj;
|
||||
}
|
||||
|
||||
@@ -978,8 +736,6 @@ class BulkChange
|
||||
{
|
||||
$sErrors = implode(', ', $aErrors);
|
||||
$aResult[$iRow]["__STATUS__"] = new RowStatus_Issue(Dict::S('UI:CSVReport-Row-Issue-Attribute'));
|
||||
//__ERRORS__ used by tests only
|
||||
$aResult[$iRow]["__ERRORS__"] = new RowStatus_Error($sErrors);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1029,8 +785,6 @@ class BulkChange
|
||||
{
|
||||
$sErrors = implode(', ', $aErrors);
|
||||
$aResult[$iRow]["__STATUS__"] = new RowStatus_Issue(Dict::S('UI:CSVReport-Row-Issue-Attribute'));
|
||||
//__ERRORS__ used by tests only
|
||||
$aResult[$iRow]["__ERRORS__"] = new RowStatus_Error($sErrors);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1118,18 +872,14 @@ class BulkChange
|
||||
$sFormat = $sDateFormat;
|
||||
}
|
||||
$oFormat = new DateTimeFormat($sFormat);
|
||||
$sDateExample = $oFormat->Format(new DateTime('2022-10-23 16:25:33'));
|
||||
$sRegExp = $oFormat->ToRegExpr('/');
|
||||
$sErrorMsg = Dict::Format('UI:CSVReport-Row-Issue-ExpectedDateFormat', $sDateExample);
|
||||
if (!preg_match($sRegExp, $sValue))
|
||||
if (!preg_match($sRegExp, $this->m_aData[$iRow][$iCol]))
|
||||
{
|
||||
$aResult[$iRow]["__STATUS__"]= new RowStatus_Issue(Dict::S('UI:CSVReport-Row-Issue-DateFormat'));
|
||||
$aResult[$iRow][$iCol] = new CellStatus_Issue(utils::HtmlEntities($sValue), null, $sErrorMsg);
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
$oDate = DateTime::createFromFormat($sFormat, $sValue);
|
||||
$oDate = DateTime::createFromFormat($sFormat, $this->m_aData[$iRow][$iCol]);
|
||||
if ($oDate !== false)
|
||||
{
|
||||
$sNewDate = $oDate->format($oAttDef->GetInternalFormat());
|
||||
@@ -1139,7 +889,7 @@ class BulkChange
|
||||
{
|
||||
// Leave the cell unchanged
|
||||
$aResult[$iRow]["__STATUS__"]= new RowStatus_Issue(Dict::S('UI:CSVReport-Row-Issue-DateFormat'));
|
||||
$aResult[$iRow][$iCol] = new CellStatus_Issue($sValue, null, $sErrorMsg);
|
||||
$aResult[$iRow][$sAttCode] = new CellStatus_Issue(null, utils::HtmlEntities($this->m_aData[$iRow][$iCol]), Dict::S('UI:CSVReport-Row-Issue-DateFormat'));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1193,9 +943,7 @@ class BulkChange
|
||||
else
|
||||
{
|
||||
// The value has to be found or verified
|
||||
|
||||
/** var DBObjectSearch $oReconFilter */
|
||||
list($oReconFilter, $aMatches) = $this->ResolveExternalKey($aRowData, $sAttCode, $aResult[$iRow]);
|
||||
list($sQuery, $aMatches) = $this->ResolveExternalKey($aRowData, $sAttCode, $aResult[$iRow]);
|
||||
|
||||
if (count($aMatches) == 1)
|
||||
{
|
||||
@@ -1205,12 +953,11 @@ class BulkChange
|
||||
}
|
||||
elseif (count($aMatches) == 0)
|
||||
{
|
||||
$oCellStatus_SearchIssue = $this->GetCellSearchIssue($oReconFilter);
|
||||
$aResult[$iRow][$sAttCode] = $oCellStatus_SearchIssue;
|
||||
$aResult[$iRow][$sAttCode] = new CellStatus_SearchIssue();
|
||||
}
|
||||
else
|
||||
{
|
||||
$aResult[$iRow][$sAttCode] = new CellStatus_Ambiguous(null, count($aMatches), $oReconFilter->serialize());
|
||||
$aResult[$iRow][$sAttCode] = new CellStatus_Ambiguous(null, count($aMatches), $sQuery);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1234,7 +981,7 @@ class BulkChange
|
||||
}
|
||||
else
|
||||
{
|
||||
$oReconciliationFilter->AddCondition($sAttCode, $valuecondition, '=');
|
||||
$oReconciliationFilter->AddCondition($sAttCode, $valuecondition, '=', true);
|
||||
}
|
||||
}
|
||||
if ($bSkipQuery)
|
||||
@@ -1263,7 +1010,7 @@ class BulkChange
|
||||
default:
|
||||
// Found several matches, ambiguous
|
||||
$aResult[$iRow]["__STATUS__"]= new RowStatus_Issue(Dict::S('UI:CSVReport-Row-Issue-Ambiguous'));
|
||||
$aResult[$iRow]["id"]= new CellStatus_Ambiguous(0, $oReconciliationSet->Count(), $oReconciliationFilter->serialize());
|
||||
$aResult[$iRow]["id"]= new CellStatus_Ambiguous(0, $oReconciliationSet->Count(), $oReconciliationFilter->ToOql());
|
||||
$aResult[$iRow]["finalclass"]= 'n/a';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -472,7 +472,7 @@ class CMDBChangeOpSetAttributeBlob extends CMDBChangeOpSetAttribute
|
||||
$sDisplayLabel = Dict::S('UI:OpenDocumentInNewWindow_');
|
||||
$sDisplayUrl = $oPrevDoc->GetDisplayURL(get_class($this), $this->GetKey(), 'prevdata');
|
||||
|
||||
$sDownloadLabel = Dict::Format('UI:DownloadDocument_');
|
||||
$sDownloadLabel = Dict::S('UI:DownloadDocument_');
|
||||
$sDownloadUrl = $oPrevDoc->GetDownloadURL(get_class($this), $this->GetKey(), 'prevdata');
|
||||
|
||||
$sDocView = <<<HTML
|
||||
@@ -885,7 +885,7 @@ class CMDBChangeOpSetAttributeCaseLog extends CMDBChangeOpSetAttribute
|
||||
*/
|
||||
protected function ToHtml($sRawText)
|
||||
{
|
||||
return str_replace(array("\r\n", "\n", "\r"), "<br/>", utils::EscapeHtml($sRawText));
|
||||
return str_replace(array("\r\n", "\n", "\r"), "<br/>", htmlentities($sRawText, ENT_QUOTES, 'UTF-8'));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1177,8 +1177,9 @@ class CMDBChangeOpSetAttributeCustomFields extends CMDBChangeOpSetAttribute
|
||||
$oHandler = $oAttDef->GetHandler($aValues);
|
||||
$sValueDesc = $oHandler->GetAsHTML($aValues);
|
||||
}
|
||||
catch (Exception $e) {
|
||||
$sValueDesc = 'Custom field error: '.utils::EscapeHtml($e->getMessage());
|
||||
catch (Exception $e)
|
||||
{
|
||||
$sValueDesc = 'Custom field error: '.htmlentities($e->getMessage(), ENT_QUOTES, 'UTF-8');
|
||||
}
|
||||
$sTextView = '<div>'.$sValueDesc.'</div>';
|
||||
|
||||
|
||||
@@ -499,7 +499,7 @@ abstract class CMDBObject extends DBObject
|
||||
$oMyChangeOp->Set("objkey", $this->GetKey());
|
||||
$oMyChangeOp->Set("attcode", $sAttCode);
|
||||
$oMyChangeOp->Set("oldvalue", $original);
|
||||
$oMyChangeOp->Set("newvalue", $value);
|
||||
$oMyChangeOp->Set("newvalue", $value[$sAttCode]);
|
||||
$iId = $oMyChangeOp->DBInsertNoReload();
|
||||
}
|
||||
elseif ($oAttDef instanceOf AttributeCustomFields)
|
||||
@@ -623,9 +623,6 @@ abstract class CMDBObject extends DBObject
|
||||
return $this->DBCloneTracked_Internal();
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated 3.1.0 N°5232 not used
|
||||
*/
|
||||
public function DBCloneTracked(CMDBChange $oChange, $newKey = null)
|
||||
{
|
||||
self::SetCurrentChange($oChange);
|
||||
@@ -640,6 +637,20 @@ abstract class CMDBObject extends DBObject
|
||||
return $newKey;
|
||||
}
|
||||
|
||||
public function DBUpdate()
|
||||
{
|
||||
// Copy the changes list before the update (the list should be reset afterwards)
|
||||
$aChanges = $this->ListChanges();
|
||||
if (count($aChanges) == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
$ret = parent::DBUpdate();
|
||||
return $ret;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param null $oDeletionPlan
|
||||
*
|
||||
@@ -674,7 +685,46 @@ abstract class CMDBObject extends DBObject
|
||||
protected function DBDeleteTracked_Internal(&$oDeletionPlan = null)
|
||||
{
|
||||
$ret = parent::DBDelete($oDeletionPlan);
|
||||
return $ret;
|
||||
}
|
||||
|
||||
public static function BulkUpdate(DBSearch $oFilter, array $aValues)
|
||||
{
|
||||
return static::BulkUpdateTracked_Internal($oFilter, $aValues);
|
||||
}
|
||||
|
||||
public static function BulkUpdateTracked(CMDBChange $oChange, DBSearch $oFilter, array $aValues)
|
||||
{
|
||||
self::SetCurrentChange($oChange);
|
||||
static::BulkUpdateTracked_Internal($oFilter, $aValues);
|
||||
}
|
||||
|
||||
protected static function BulkUpdateTracked_Internal(DBSearch $oFilter, array $aValues)
|
||||
{
|
||||
// $aValues is an array of $sAttCode => $value
|
||||
|
||||
// Get the list of objects to update (and load it before doing the change)
|
||||
$oObjSet = new CMDBObjectSet($oFilter);
|
||||
$oObjSet->Load();
|
||||
|
||||
// Keep track of the previous values (will be overwritten when the objects are synchronized with the DB)
|
||||
$aOriginalValues = array();
|
||||
$oObjSet->Rewind();
|
||||
while ($oItem = $oObjSet->Fetch())
|
||||
{
|
||||
$aOriginalValues[$oItem->GetKey()] = $oItem->m_aOrigValues;
|
||||
}
|
||||
|
||||
// Update in one single efficient query
|
||||
$ret = parent::BulkUpdate($oFilter, $aValues);
|
||||
|
||||
// Record... in many queries !!!
|
||||
$oObjSet->Rewind();
|
||||
while ($oItem = $oObjSet->Fetch())
|
||||
{
|
||||
$aChangedValues = $oItem->ListChangedValues($aValues);
|
||||
$oItem->RecordAttChanges($aChangedValues, $aOriginalValues[$oItem->GetKey()]);
|
||||
}
|
||||
return $ret;
|
||||
}
|
||||
|
||||
|
||||
@@ -157,7 +157,7 @@ class CMDBSource
|
||||
$iPort = null;
|
||||
self::InitServerAndPort($sDbHost, $sServer, $iPort);
|
||||
|
||||
$iFlags = 0;
|
||||
$iFlags = null;
|
||||
|
||||
// *some* errors (like connection errors) will throw mysqli_sql_exception instead of generating warnings printed to the output
|
||||
// but some other errors will still cause the query() method to return false !!!
|
||||
@@ -166,6 +166,7 @@ class CMDBSource
|
||||
try
|
||||
{
|
||||
$oMysqli = new mysqli();
|
||||
$oMysqli->init();
|
||||
|
||||
if ($bTlsEnabled)
|
||||
{
|
||||
@@ -350,21 +351,19 @@ class CMDBSource
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the version of the database server.
|
||||
*
|
||||
* @return string
|
||||
* @throws \MySQLException
|
||||
*
|
||||
* @uses \CMDBSource::QueryToScalar() so needs a connection opened !
|
||||
* @uses \CMDBSource::QueryToCol() so needs a connection opened !
|
||||
*/
|
||||
public static function GetDBVersion()
|
||||
{
|
||||
return static::QueryToScalar('SELECT VERSION()', 0);
|
||||
$aVersions = self::QueryToCol('SELECT Version() as version', 'version');
|
||||
return $aVersions[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Use `CMDBSource::GetDBVersion` instead.
|
||||
* @uses mysqli_get_server_info
|
||||
* @return string
|
||||
*/
|
||||
public static function GetServerInfo()
|
||||
{
|
||||
@@ -1508,14 +1507,20 @@ 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)
|
||||
{
|
||||
$sSql = 'SELECT @@'.$sVarName;
|
||||
return static::QueryToScalar($sSql, 0) ?: '';
|
||||
$result = '';
|
||||
$sSql = "SELECT @@$sVarName as theVar";
|
||||
$aRows = self::QueryToArray($sSql);
|
||||
if (count($aRows) > 0)
|
||||
{
|
||||
$result = $aRows[0]['theVar'];
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the privileges of the current user
|
||||
* @return string privileges in a raw format
|
||||
|
||||
@@ -29,7 +29,7 @@ define('ITOP_APPLICATION_SHORT', 'iTop');
|
||||
*
|
||||
* @see ITOP_CORE_VERSION to get iTop core version
|
||||
*/
|
||||
define('ITOP_VERSION', '3.1.0-dev');
|
||||
define('ITOP_VERSION', '3.0.3-dev');
|
||||
|
||||
define('ITOP_VERSION_NAME', 'Fullmoon');
|
||||
define('ITOP_REVISION', 'svn');
|
||||
@@ -129,22 +129,6 @@ class Config
|
||||
'source_of_value' => '',
|
||||
'show_in_conf_sample' => false,
|
||||
],
|
||||
'event_service.debug.filter_events' => [
|
||||
'type' => 'array',
|
||||
'description' => 'Filter Event Service debug by events',
|
||||
'default' => '',
|
||||
'value' => '',
|
||||
'source_of_value' => '',
|
||||
'show_in_conf_sample' => false,
|
||||
],
|
||||
'event_service.debug.filter_sources' => [
|
||||
'type' => 'array',
|
||||
'description' => 'Filter Event Service debug by event sources',
|
||||
'default' => '',
|
||||
'value' => '',
|
||||
'source_of_value' => '',
|
||||
'show_in_conf_sample' => false,
|
||||
],
|
||||
'app_env_label' => [
|
||||
'type' => 'string',
|
||||
'description' => 'Label displayed to describe the current application environment, defaults to the environment name (e.g. "production")',
|
||||
@@ -592,13 +576,29 @@ class Config
|
||||
'source_of_value' => '',
|
||||
'show_in_conf_sample' => false,
|
||||
],
|
||||
'email_css' => [
|
||||
'type' => 'string',
|
||||
'description' => 'CSS that will override the standard stylesheet used for the notifications',
|
||||
'default' => "",
|
||||
'value' => "",
|
||||
'email_transport_smtp.allow_self_signed' => array(
|
||||
'type' => 'bool',
|
||||
'description' => 'Allow self signed peer certificates',
|
||||
'default' => false,
|
||||
'value' => false,
|
||||
'source_of_value' => '',
|
||||
'show_in_conf_sample' => false,
|
||||
),
|
||||
'email_transport_smtp.verify_peer' => array(
|
||||
'type' => 'bool',
|
||||
'description' => 'Verify peer certificate',
|
||||
'default' => true,
|
||||
'value' => true,
|
||||
'source_of_value' => '',
|
||||
'show_in_conf_sample' => false,
|
||||
),
|
||||
'email_css' => [
|
||||
'type' => 'string',
|
||||
'description' => 'CSS that will override the standard stylesheet used for the notifications',
|
||||
'default' => "",
|
||||
'value' => "",
|
||||
'source_of_value' => '',
|
||||
'show_in_conf_sample' => false,
|
||||
],
|
||||
'email_default_sender_address' => [
|
||||
'type' => 'string',
|
||||
@@ -899,16 +899,11 @@ class Config
|
||||
'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' => /** @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
|
||||
// RegExp source: http://www.php.net/manual/fr/function.preg-match.php#93824
|
||||
// Update with N°4515
|
||||
'value' => '',
|
||||
'source_of_value' => '',
|
||||
'type' => 'string',
|
||||
'description' => 'Regular expression to validate/detect the format of an URL (URL attributes and Wiki formatting for Text attributes)',
|
||||
'default' => AttributeURL::DEFAULT_VALIDATION_PATTERN,
|
||||
'value' => '',
|
||||
'source_of_value' => '',
|
||||
'show_in_conf_sample' => true,
|
||||
],
|
||||
'email_validation_pattern' => [
|
||||
@@ -1560,14 +1555,6 @@ 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)
|
||||
@@ -1887,7 +1874,7 @@ class Config
|
||||
{
|
||||
// Note: sNoise is an html output, but so far it was ok for me (e.g. showing the entire call stack)
|
||||
throw new ConfigException('Syntax error in configuration file',
|
||||
array('file' => $sConfigFile, 'error' => '<tt>'.utils::EscapeHtml($sNoise, ENT_QUOTES).'</tt>'));
|
||||
array('file' => $sConfigFile, 'error' => '<tt>'.htmlentities($sNoise, ENT_QUOTES, 'UTF-8').'</tt>'));
|
||||
}
|
||||
|
||||
if (!isset($MySettings) || !is_array($MySettings))
|
||||
|
||||
@@ -125,8 +125,8 @@ class CSVBulkExport extends TabularBulkExport
|
||||
$sRawSeparator = utils::ReadParam('separator', ',', true, 'raw_data');
|
||||
$sCustomDateTimeFormat = utils::ReadParam('', ',', true, 'raw_data');
|
||||
$aSep = array(
|
||||
';' => Dict::S('UI:CSVImport:SeparatorSemicolon+'),
|
||||
',' => Dict::S('UI:CSVImport:SeparatorComma+'),
|
||||
';' => Dict::S('UI:CSVImport:SeparatorSemicolon+'),
|
||||
',' => Dict::S('UI:CSVImport:SeparatorComma+'),
|
||||
'tab' => Dict::S('UI:CSVImport:SeparatorTab+'),
|
||||
);
|
||||
$sOtherSeparator = '';
|
||||
@@ -134,10 +134,10 @@ class CSVBulkExport extends TabularBulkExport
|
||||
$sOtherSeparator = $sRawSeparator;
|
||||
$sRawSeparator = 'other';
|
||||
}
|
||||
$aSep['other'] = Dict::S('UI:CSVImport:SeparatorOther').' <input type="text" size="3" name="other-separator" value="'.utils::EscapeHtml($sOtherSeparator).'"/>';
|
||||
$aSep['other'] = Dict::S('UI:CSVImport:SeparatorOther').' <input type="text" size="3" name="other-separator" value="'.htmlentities($sOtherSeparator, ENT_QUOTES, 'UTF-8').'"/>';
|
||||
|
||||
foreach ($aSep as $sVal => $sLabel) {
|
||||
$oRadio = InputUIBlockFactory::MakeForInputWithLabel($sLabel, "separator", utils::EscapeHtml($sVal), $sLabel, "radio");
|
||||
$oRadio = InputUIBlockFactory::MakeForInputWithLabel($sLabel, "separator", htmlentities($sVal, ENT_QUOTES, 'UTF-8'), $sLabel, "radio");
|
||||
$oRadio->GetInput()->SetIsChecked(($sVal == $sRawSeparator));
|
||||
$oRadio->SetBeforeInput(false);
|
||||
$oRadio->GetInput()->AddCSSClass('ibo-input--label-right');
|
||||
@@ -152,7 +152,7 @@ class CSVBulkExport extends TabularBulkExport
|
||||
|
||||
$sRawQualifier = utils::ReadParam('text-qualifier', '"', true, 'raw_data');
|
||||
$aQualifiers = array(
|
||||
'"' => Dict::S('UI:CSVImport:QualifierDoubleQuote+'),
|
||||
'"' => Dict::S('UI:CSVImport:QualifierDoubleQuote+'),
|
||||
'\'' => Dict::S('UI:CSVImport:QualifierSimpleQuote+'),
|
||||
);
|
||||
$sOtherQualifier = '';
|
||||
@@ -160,10 +160,10 @@ class CSVBulkExport extends TabularBulkExport
|
||||
$sOtherQualifier = $sRawQualifier;
|
||||
$sRawQualifier = 'other';
|
||||
}
|
||||
$aQualifiers['other'] = Dict::S('UI:CSVImport:QualifierOther').' <input type="text" size="3" name="other-text-qualifier" value="'.utils::EscapeHtml($sOtherQualifier).'"/>';
|
||||
$aQualifiers['other'] = Dict::S('UI:CSVImport:QualifierOther').' <input type="text" size="3" name="other-text-qualifier" value="'.htmlentities($sOtherQualifier, ENT_QUOTES, 'UTF-8').'"/>';
|
||||
|
||||
foreach ($aQualifiers as $sVal => $sLabel) {
|
||||
$oRadio = InputUIBlockFactory::MakeForInputWithLabel($sLabel, "text-qualifier", utils::EscapeHtml($sVal), $sLabel, "radio");
|
||||
$oRadio = InputUIBlockFactory::MakeForInputWithLabel($sLabel, "text-qualifier", htmlentities($sVal, ENT_QUOTES, 'UTF-8'), $sLabel, "radio");
|
||||
$oRadio->GetInput()->SetIsChecked(($sVal == $sRawSeparator));
|
||||
$oRadio->SetBeforeInput(false);
|
||||
$oRadio->GetInput()->AddCSSClass('ibo-input--label-right');
|
||||
@@ -209,8 +209,8 @@ class CSVBulkExport extends TabularBulkExport
|
||||
|
||||
$sDateTimeFormat = utils::ReadParam('date_format', (string)AttributeDateTime::GetFormat(), true, 'raw_data');
|
||||
|
||||
$sDefaultFormat = utils::EscapeHtml((string)AttributeDateTime::GetFormat());
|
||||
$sExample = utils::EscapeHtml(date((string)AttributeDateTime::GetFormat()));
|
||||
$sDefaultFormat = htmlentities((string)AttributeDateTime::GetFormat(), ENT_QUOTES, 'UTF-8');
|
||||
$sExample = htmlentities(date((string)AttributeDateTime::GetFormat()), ENT_QUOTES, 'UTF-8');
|
||||
$oRadioDefault = InputUIBlockFactory::MakeForInputWithLabel(Dict::Format('Core:BulkExport:DateTimeFormatDefault_Example', $sDefaultFormat, $sExample), "csv_date_format_radio", "default", "csv_date_time_format_default", "radio");
|
||||
$oRadioDefault->GetInput()->SetIsChecked(($sDateTimeFormat == (string)AttributeDateTime::GetFormat()));
|
||||
$oRadioDefault->SetBeforeInput(false);
|
||||
@@ -218,7 +218,7 @@ class CSVBulkExport extends TabularBulkExport
|
||||
$oFieldSetDate->AddSubBlock($oRadioDefault);
|
||||
$oFieldSetDate->AddSubBlock(new Html('</br>'));
|
||||
|
||||
$sFormatInput = '<input type="text" size="15" name="date_format" id="csv_custom_date_time_format" title="" value="'.utils::EscapeHtml($sDateTimeFormat).'"/>';
|
||||
$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());
|
||||
@@ -246,18 +246,17 @@ EOF
|
||||
}
|
||||
|
||||
protected function GetSampleData($oObj, $sAttCode)
|
||||
{
|
||||
if ($sAttCode != 'id') {
|
||||
{
|
||||
if ($sAttCode != 'id')
|
||||
{
|
||||
$oAttDef = MetaModel::GetAttributeDef(get_class($oObj), $sAttCode);
|
||||
if ($oAttDef instanceof AttributeDateTime) // AttributeDate is derived from AttributeDateTime
|
||||
{
|
||||
$sClass = (get_class($oAttDef) == 'AttributeDateTime') ? 'user-formatted-date-time' : 'user-formatted-date';
|
||||
|
||||
return '<div class="'.$sClass.'" data-date="'.$oObj->Get($sAttCode).'">'.utils::EscapeHtml($oAttDef->GetEditValue($oObj->Get($sAttCode), $oObj)).'</div>';
|
||||
return '<div class="'.$sClass.'" data-date="'.$oObj->Get($sAttCode).'">'.htmlentities($oAttDef->GetEditValue($oObj->Get($sAttCode), $oObj), ENT_QUOTES, 'UTF-8').'</div>';
|
||||
}
|
||||
}
|
||||
|
||||
return '<div class="text-preview">'.utils::EscapeHtml($this->GetValue($oObj, $sAttCode)).'</div>';
|
||||
return '<div class="text-preview">'.htmlentities($this->GetValue($oObj, $sAttCode), ENT_QUOTES, 'UTF-8').'</div>';
|
||||
}
|
||||
|
||||
protected function GetValue($oObj, $sAttCode)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<itop_design xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="3.1">
|
||||
<itop_design xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="3.0">
|
||||
<user_rights>
|
||||
<profiles>
|
||||
<profile id="1024" _delta="define">
|
||||
@@ -270,4 +270,4 @@
|
||||
</class>
|
||||
</classes>
|
||||
</meta>
|
||||
</itop_design>
|
||||
</itop_design>
|
||||
File diff suppressed because it is too large
Load Diff
@@ -38,7 +38,7 @@ interface iDBObjectSetIterator extends Countable
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function Count(): int;
|
||||
public function Count();
|
||||
|
||||
/**
|
||||
* Reset the cursor to the first item in the collection. Equivalent to Seek(0)
|
||||
@@ -52,7 +52,7 @@ interface iDBObjectSetIterator extends Countable
|
||||
*
|
||||
* @param int $iRow
|
||||
*/
|
||||
public function Seek($iPosition): void;
|
||||
public function Seek($iPosition);
|
||||
|
||||
/**
|
||||
* Fetch the object at the current position in the collection and move the cursor to the next position.
|
||||
|
||||
@@ -413,10 +413,6 @@ 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', ...
|
||||
@@ -427,16 +423,22 @@ class DBObjectSearch extends DBSearch
|
||||
* @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)
|
||||
{
|
||||
MyHelpers::CheckKeyInArray('filter code in class: '.$this->GetClass(), $sFilterCode, MetaModel::GetFilterAttribList($this->GetClass()));
|
||||
MyHelpers::CheckKeyInArray('filter code in class: '.$this->GetClass(), $sFilterCode, MetaModel::GetClassFilterDefs($this->GetClass()));
|
||||
|
||||
$oField = new FieldExpression($sFilterCode, $this->GetClassAlias());
|
||||
if (empty($sOpCode)) {
|
||||
if ($sFilterCode == 'id') {
|
||||
if (empty($sOpCode))
|
||||
{
|
||||
if ($sFilterCode == 'id')
|
||||
{
|
||||
$sOpCode = '=';
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
$oAttDef = MetaModel::GetAttributeDef($this->GetClass(), $sFilterCode);
|
||||
$oNewCondition = $oAttDef->GetSmartConditionExpression($value, $oField, $this->m_aParams);
|
||||
$this->AddConditionExpression($oNewCondition);
|
||||
@@ -1898,13 +1900,16 @@ class DBObjectSearch extends DBSearch
|
||||
// Hide objects that are not visible to the current user
|
||||
//
|
||||
$oSearch = $this;
|
||||
if (!$this->IsAllDataAllowed() && !$this->IsDataFiltered()) {
|
||||
if (!$this->IsAllDataAllowed() && !$this->IsDataFiltered())
|
||||
{
|
||||
$oVisibleObjects = UserRights::GetSelectFilter($this->GetClass(), $this->GetModifierProperties('UserRightsGetSelectFilter'));
|
||||
if ($oVisibleObjects === false) {
|
||||
if ($oVisibleObjects === false)
|
||||
{
|
||||
// Make sure this is a valid search object, saying NO for all
|
||||
$oVisibleObjects = DBObjectSearch::FromEmptySet($this->GetClass());
|
||||
}
|
||||
if (is_object($oVisibleObjects)) {
|
||||
if (is_object($oVisibleObjects))
|
||||
{
|
||||
$oVisibleObjects->AllowAllData();
|
||||
$oSearch = $this->Intersect($oVisibleObjects);
|
||||
$oSearch->SetDataFiltered();
|
||||
@@ -1924,49 +1929,63 @@ class DBObjectSearch extends DBSearch
|
||||
if (isset($_SERVER['REQUEST_URI']))
|
||||
{
|
||||
$aContextData['sRequestUri'] = $_SERVER['REQUEST_URI'];
|
||||
} else if (isset($_SERVER['SCRIPT_NAME'])) {
|
||||
}
|
||||
else if (isset($_SERVER['SCRIPT_NAME']))
|
||||
{
|
||||
$aContextData['sRequestUri'] = $_SERVER['SCRIPT_NAME'];
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
$aContextData['sRequestUri'] = '';
|
||||
}
|
||||
|
||||
// Need to identify the query
|
||||
$sOqlQuery = $oSearch->ToOql(false, null, true);
|
||||
if ((strpos($sOqlQuery, '`id` IN (') !== false) || (strpos($sOqlQuery, '`id` NOT IN (') !== false)) {
|
||||
if ((strpos($sOqlQuery, '`id` IN (') !== false) || (strpos($sOqlQuery, '`id` NOT IN (') !== false))
|
||||
{
|
||||
// Requests containing "id IN" are not worth caching
|
||||
$bCanCache = false;
|
||||
}
|
||||
|
||||
$aContextData['sOqlQuery'] = $sOqlQuery;
|
||||
|
||||
if (count($aModifierProperties)) {
|
||||
if (count($aModifierProperties))
|
||||
{
|
||||
array_multisort($aModifierProperties);
|
||||
$sModifierProperties = json_encode($aModifierProperties);
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
$sModifierProperties = '';
|
||||
}
|
||||
$aContextData['sModifierProperties'] = $sModifierProperties;
|
||||
|
||||
$sRawId = Dict::GetUserLanguage().'-'.$sOqlQuery.$sModifierProperties;
|
||||
if (!is_null($aAttToLoad)) {
|
||||
if (!is_null($aAttToLoad))
|
||||
{
|
||||
$sRawId .= json_encode($aAttToLoad);
|
||||
}
|
||||
$aContextData['aAttToLoad'] = $aAttToLoad;
|
||||
if (!is_null($aGroupByExpr)) {
|
||||
foreach ($aGroupByExpr as $sAlias => $oExpr) {
|
||||
$sRawId .= 'g:'.$sAlias.'!'.$oExpr->RenderExpression();
|
||||
if (!is_null($aGroupByExpr))
|
||||
{
|
||||
foreach($aGroupByExpr as $sAlias => $oExpr)
|
||||
{
|
||||
$sRawId .= 'g:'.$sAlias.'!'.$oExpr->Render();
|
||||
}
|
||||
}
|
||||
if (!is_null($aSelectExpr)) {
|
||||
foreach ($aSelectExpr as $sAlias => $oExpr) {
|
||||
$sRawId .= 'se:'.$sAlias.'!'.$oExpr->RenderExpression();
|
||||
if (!is_null($aSelectExpr))
|
||||
{
|
||||
foreach($aSelectExpr as $sAlias => $oExpr)
|
||||
{
|
||||
$sRawId .= 'se:'.$sAlias.'!'.$oExpr->Render();
|
||||
}
|
||||
}
|
||||
$aContextData['aGroupByExpr'] = $aGroupByExpr;
|
||||
$aContextData['aSelectExpr'] = $aSelectExpr;
|
||||
$sRawId .= $bGetCount;
|
||||
$aContextData['bGetCount'] = $bGetCount;
|
||||
if (is_array($aSelectedClasses)) {
|
||||
if (is_array($aSelectedClasses))
|
||||
{
|
||||
$sRawId .= implode(',', $aSelectedClasses); // Unions may alter the list of selected columns
|
||||
}
|
||||
$aContextData['aSelectedClasses'] = $aSelectedClasses;
|
||||
@@ -2077,13 +2096,17 @@ class DBObjectSearch extends DBSearch
|
||||
// 3rd step - position the attributes in the hierarchy of classes
|
||||
//
|
||||
$oSubClassExp->Browse(function($oNode) use ($sSubClass) {
|
||||
if ($oNode instanceof FieldExpression) {
|
||||
if ($oNode instanceof FieldExpression)
|
||||
{
|
||||
$sAttCode = $oNode->GetName();
|
||||
$oAttDef = MetaModel::GetAttributeDef($sSubClass, $sAttCode);
|
||||
if ($oAttDef->IsExternalField()) {
|
||||
if ($oAttDef->IsExternalField())
|
||||
{
|
||||
$sKeyAttCode = $oAttDef->GetKeyAttCode();
|
||||
$sClassOfAttribute = MetaModel::GetAttributeOrigin($sSubClass, $sKeyAttCode);
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
$sClassOfAttribute = MetaModel::GetAttributeOrigin($sSubClass, $sAttCode);
|
||||
}
|
||||
$sParent = MetaModel::GetAttributeOrigin($sClassOfAttribute, $oNode->GetName());
|
||||
@@ -2091,11 +2114,12 @@ class DBObjectSearch extends DBSearch
|
||||
}
|
||||
});
|
||||
|
||||
$sSignature = $oSubClassExp->RenderExpression();
|
||||
if (!array_key_exists($sSignature, $aExpressions)) {
|
||||
$sSignature = $oSubClassExp->Render();
|
||||
if (!array_key_exists($sSignature, $aExpressions))
|
||||
{
|
||||
$aExpressions[$sSignature] = array(
|
||||
'expression' => $oSubClassExp,
|
||||
'classes' => array(),
|
||||
'classes' => array(),
|
||||
);
|
||||
}
|
||||
$aExpressions[$sSignature]['classes'][] = $sSubClass;
|
||||
|
||||
@@ -141,7 +141,7 @@ class DBObjectSet implements iDBObjectSetIterator
|
||||
{
|
||||
$sRet = '';
|
||||
$this->Rewind();
|
||||
$sRet .= "Set (".$this->m_oFilter->ToOQL().")<br/>\n";
|
||||
$sRet .= "Set (".$this->m_oFilter->ToOQL(true).")<br/>\n";
|
||||
$sRet .= "Query: <pre style=\"font-size: smaller; display:inline;\">".$this->m_oFilter->MakeSelectQuery().")</pre>\n";
|
||||
|
||||
$sRet .= $this->Count()." records<br/>\n";
|
||||
@@ -154,6 +154,7 @@ class DBObjectSet implements iDBObjectSetIterator
|
||||
}
|
||||
$sRet .= "</ul>\n";
|
||||
}
|
||||
$this->Rewind();
|
||||
return $sRet;
|
||||
}
|
||||
|
||||
@@ -842,7 +843,7 @@ class DBObjectSet implements iDBObjectSetIterator
|
||||
* @throws \MySQLException
|
||||
* @throws \MySQLHasGoneAwayException
|
||||
*/
|
||||
public function Count(): int
|
||||
public function Count()
|
||||
{
|
||||
if (is_null($this->m_iNumTotalDBRows))
|
||||
{
|
||||
@@ -1077,13 +1078,14 @@ class DBObjectSet implements iDBObjectSetIterator
|
||||
*
|
||||
* @param int $iRow
|
||||
*
|
||||
* @return int|mixed
|
||||
*
|
||||
* @throws \CoreException
|
||||
* @throws \MissingQueryArgument
|
||||
* @throws \MySQLException
|
||||
* @throws \MySQLHasGoneAwayException
|
||||
* @since 3.1.0 N°4517 Now returns void for return type to match parent class and be compatible with PHP 8.1
|
||||
*/
|
||||
public function Seek($iRow): void
|
||||
public function Seek($iRow)
|
||||
{
|
||||
if (!$this->m_bLoaded) $this->Load();
|
||||
|
||||
@@ -1092,6 +1094,7 @@ class DBObjectSet implements iDBObjectSetIterator
|
||||
{
|
||||
$this->m_oSQLResult->data_seek($this->m_iCurrRow);
|
||||
}
|
||||
return $this->m_iCurrRow;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -773,14 +773,14 @@ abstract class DBSearch
|
||||
* @see DBSearch::ToOQL()
|
||||
*
|
||||
* @param string $sQuery The OQL to convert to a DBSearch
|
||||
* @param mixed[string] $aParams array of <mixed> params index by <string> name
|
||||
* @param array $aParams array of <mixed> params index by <string> name
|
||||
* @param ModelReflection|null $oMetaModel The MetaModel to use when checking the consistency of the OQL
|
||||
*
|
||||
* @return DBObjectSearch|DBUnionSearch
|
||||
*
|
||||
* @throws OQLException
|
||||
*/
|
||||
static public function FromOQL($sQuery, $aParams = null, ModelReflection $oMetaModel=null)
|
||||
public static function FromOQL($sQuery, $aParams = null, ModelReflection $oMetaModel=null)
|
||||
{
|
||||
if (empty($sQuery))
|
||||
{
|
||||
@@ -1717,6 +1717,6 @@ abstract class DBSearch
|
||||
*/
|
||||
public function __toString()
|
||||
{
|
||||
return $this->ToOQL();
|
||||
return $this->ToOQL(true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -83,8 +83,6 @@ class DesignDocument extends DOMDocument
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
// Return type union is not supported by PHP 7.4, we can remove the following PHP attribute and add the return type once iTop min PHP version is PHP 8.0+
|
||||
#[\ReturnTypeWillChange]
|
||||
public function save($filename, $options = null)
|
||||
{
|
||||
$this->documentElement->setAttribute('xmlns:xsi', "http://www.w3.org/2001/XMLSchema-instance");
|
||||
@@ -99,12 +97,13 @@ class DesignDocument extends DOMDocument
|
||||
public function Dump($bReturnRes = false)
|
||||
{
|
||||
$sXml = $this->saveXML();
|
||||
if ($bReturnRes) {
|
||||
if ($bReturnRes)
|
||||
{
|
||||
return $sXml;
|
||||
}
|
||||
|
||||
echo "<pre>\n";
|
||||
echo utils::EscapeHtml($sXml);
|
||||
echo htmlentities($sXml);
|
||||
echo "</pre>\n";
|
||||
|
||||
return '';
|
||||
@@ -182,26 +181,6 @@ class DesignElement extends \DOMElement
|
||||
return $this->ownerDocument->GetNodes($sXPath, $this);
|
||||
}
|
||||
|
||||
public static function ToArray(DesignElement $oNode)
|
||||
{
|
||||
$aRes = [];
|
||||
|
||||
if ($oNode->GetNodes('./*')->length == 0) {
|
||||
return $oNode->GetText('');
|
||||
}
|
||||
foreach ($oNode->GetNodes('./*') as $oSubNode) {
|
||||
/** @var \Combodo\iTop\DesignElement $oSubNode */
|
||||
$aSubArray = DesignElement::ToArray($oSubNode);
|
||||
if ($oSubNode->hasAttribute('id')) {
|
||||
$aRes[$oSubNode->getAttribute('id')] = $aSubArray;
|
||||
} else {
|
||||
$aRes[$oSubNode->tagName] = $aSubArray;
|
||||
}
|
||||
}
|
||||
|
||||
return $aRes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an HTML representation of the DOM, for debugging purposes
|
||||
*
|
||||
@@ -217,13 +196,13 @@ class DesignElement extends \DOMElement
|
||||
$oDoc->appendChild($oClone);
|
||||
|
||||
$sXml = $oDoc->saveXML($oClone);
|
||||
if ($bReturnRes) {
|
||||
if ($bReturnRes)
|
||||
{
|
||||
return $sXml;
|
||||
}
|
||||
echo "<pre>\n";
|
||||
echo utils::EscapeHtml($sXml);
|
||||
echo htmlentities($sXml);
|
||||
echo "</pre>\n";
|
||||
|
||||
return '';
|
||||
}
|
||||
/**
|
||||
|
||||
@@ -459,10 +459,11 @@ class DisplayableNode extends GraphNode
|
||||
{
|
||||
$aContext = $aContextDefs[$key];
|
||||
$aRootCauses = array();
|
||||
foreach ($aObjects as $oRootCause) {
|
||||
foreach($aObjects as $oRootCause)
|
||||
{
|
||||
$aRootCauses[] = $oRootCause->GetHyperlink();
|
||||
}
|
||||
$sHtml .= '<p><img style="max-height: 24px; vertical-align:bottom;" class="ibo-class-icon ibo-is-small" src="'.utils::GetAbsoluteUrlModulesRoot().$aContext['icon'].'" title="'.utils::EscapeHtml(Dict::S($aContext['dict'])).'"> '.implode(', ', $aRootCauses).'</p>';
|
||||
$sHtml .= '<p><img style="max-height: 24px; vertical-align:bottom;" class="ibo-class-icon ibo-is-small" src="'.utils::GetAbsoluteUrlModulesRoot().$aContext['icon'].'" title="'.htmlentities(Dict::S($aContext['dict'])).'"> '.implode(', ', $aRootCauses).'</p>';
|
||||
}
|
||||
$sHtml .= '<hr/>';
|
||||
}
|
||||
@@ -1334,17 +1335,18 @@ class DisplayableGraph extends SimpleGraph
|
||||
}
|
||||
$oPdf->Rect($xMin, $yMin, $fMaxWidth + $fIconSize + 3*$fPadding, $yMax - $yMin, 'D');
|
||||
|
||||
if ($sComments != '') {
|
||||
if ($sComments != '')
|
||||
{
|
||||
// Draw the comment text (surrounded by a rectangle)
|
||||
$xPos = $xMin + $fMaxWidth + $fIconSize + 4 * $fPadding;
|
||||
$w = $xMax - $xPos - 2 * $fPadding;
|
||||
$xPos = $xMin + $fMaxWidth + $fIconSize + 4*$fPadding;
|
||||
$w = $xMax - $xPos - 2*$fPadding;
|
||||
$iNbLines = 1;
|
||||
$sText = '<p>'.str_replace("\n", '<br/>', utils::EscapeHtml($sComments), $iNbLines).'</p>';
|
||||
$sText = '<p>'.str_replace("\n", '<br/>', htmlentities($sComments, ENT_QUOTES, 'UTF-8'), $iNbLines).'</p>';
|
||||
$fLineHeight = $oPdf->getStringHeight($w, $sText);
|
||||
$h = (1 + $iNbLines) * $fLineHeight;
|
||||
$yPos = $yMax - 2 * $fPadding - $h;
|
||||
$h = (1+$iNbLines) * $fLineHeight;
|
||||
$yPos = $yMax - 2*$fPadding - $h;
|
||||
$oPdf->writeHTMLCell($w, $h, $xPos + $fPadding, $yPos + $fPadding, $sText, 0 /* border */, 1 /* ln */);
|
||||
$oPdf->Rect($xPos, $yPos, $w + 2 * $fPadding, $h + 2 * $fPadding, 'D');
|
||||
$oPdf->Rect($xPos, $yPos, $w + 2*$fPadding, $h + 2*$fPadding, 'D');
|
||||
$yMax = $yPos - $fPadding;
|
||||
}
|
||||
|
||||
|
||||
@@ -27,6 +27,9 @@
|
||||
use Combodo\iTop\Core\Email\EmailFactory;
|
||||
use Combodo\iTop\Core\Email\iEMail;
|
||||
|
||||
Swift_Preferences::getInstance()->setCharset('UTF-8');
|
||||
|
||||
|
||||
define ('EMAIL_SEND_OK', 0);
|
||||
define ('EMAIL_SEND_PENDING', 1);
|
||||
define ('EMAIL_SEND_ERROR', 2);
|
||||
@@ -109,7 +112,7 @@ class EMail implements iEMail
|
||||
* @throws \CoreException
|
||||
* @throws \Symfony\Component\CssSelector\Exception\SyntaxErrorException
|
||||
*/
|
||||
public static function UnSerializeV2($sSerializedMessage)
|
||||
static public function UnSerializeV2($sSerializedMessage)
|
||||
{
|
||||
return EmailFactory::GetMailer()::UnSerializeV2($sSerializedMessage);
|
||||
}
|
||||
@@ -151,7 +154,7 @@ class EMail implements iEMail
|
||||
public function SetBody($sBody, $sMimeType = 'text/html', $sCustomStyles = null)
|
||||
{
|
||||
$this->oMailer->SetBody($sBody, $sMimeType, $sCustomStyles);
|
||||
}
|
||||
}
|
||||
|
||||
public function AddPart($sText, $sMimeType = 'text/html')
|
||||
{
|
||||
|
||||
@@ -100,8 +100,8 @@ class ExcelBulkExport extends TabularBulkExport
|
||||
|
||||
$sDateTimeFormat = utils::ReadParam('date_format', (string)AttributeDateTime::GetFormat(), true, 'raw_data');
|
||||
|
||||
$sDefaultFormat = utils::EscapeHtml((string)AttributeDateTime::GetFormat());
|
||||
$sExample = utils::EscapeHtml(date((string)AttributeDateTime::GetFormat()));
|
||||
$sDefaultFormat = htmlentities((string)AttributeDateTime::GetFormat(), ENT_QUOTES, 'UTF-8');
|
||||
$sExample = htmlentities(date((string)AttributeDateTime::GetFormat()), ENT_QUOTES, 'UTF-8');
|
||||
$oRadioDefault = InputUIBlockFactory::MakeForInputWithLabel(Dict::Format('Core:BulkExport:DateTimeFormatDefault_Example', $sDefaultFormat, $sExample), "excel_date_format_radio", "default", "excel_date_time_format_default", "radio");
|
||||
$oRadioDefault->GetInput()->SetIsChecked(($sDateTimeFormat == (string)AttributeDateTime::GetFormat()));
|
||||
$oRadioDefault->SetBeforeInput(false);
|
||||
@@ -109,7 +109,7 @@ class ExcelBulkExport extends TabularBulkExport
|
||||
$oFieldSetDate->AddSubBlock($oRadioDefault);
|
||||
$oFieldSetDate->AddSubBlock(new Html('</br>'));
|
||||
|
||||
$sFormatInput = '<input type="text" size="15" name="date_format" id="excel_custom_date_time_format" title="" value="'.utils::EscapeHtml($sDateTimeFormat).'"/>';
|
||||
$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());
|
||||
@@ -156,17 +156,16 @@ EOF
|
||||
|
||||
protected function GetSampleData($oObj, $sAttCode)
|
||||
{
|
||||
if ($sAttCode != 'id') {
|
||||
if ($sAttCode != 'id')
|
||||
{
|
||||
$oAttDef = MetaModel::GetAttributeDef(get_class($oObj), $sAttCode);
|
||||
if ($oAttDef instanceof AttributeDateTime) // AttributeDate is derived from AttributeDateTime
|
||||
{
|
||||
$sClass = (get_class($oAttDef) == 'AttributeDateTime') ? 'user-formatted-date-time' : 'user-formatted-date';
|
||||
|
||||
return '<div class="'.$sClass.'" data-date="'.$oObj->Get($sAttCode).'">'.utils::EscapeHtml($oAttDef->GetEditValue($oObj->Get($sAttCode), $oObj)).'</div>';
|
||||
return '<div class="'.$sClass.'" data-date="'.$oObj->Get($sAttCode).'">'.htmlentities($oAttDef->GetEditValue($oObj->Get($sAttCode), $oObj), ENT_QUOTES, 'UTF-8').'</div>';
|
||||
}
|
||||
}
|
||||
|
||||
return '<div class="text-preview">'.utils::EscapeHtml($this->GetValue($oObj, $sAttCode)).'</div>';
|
||||
return '<div class="text-preview">'.htmlentities($this->GetValue($oObj, $sAttCode), ENT_QUOTES, 'UTF-8').'</div>';
|
||||
}
|
||||
|
||||
protected function GetValue($oObj, $sAttCode)
|
||||
|
||||
@@ -1,8 +1,4 @@
|
||||
<?php
|
||||
// The file has been moved in iTop 2.2.0+ (revision 3803)
|
||||
// Preserve backward compatibility with some external tools (Cf. toolkit)
|
||||
|
||||
// @deprecated 3.1.0
|
||||
DeprecatedCallsLog::NotifyDeprecatedPhpMethod('use core/oql/expression.class.inc.php instead');
|
||||
|
||||
require_once(APPROOT.'core/oql/expression.class.inc.php');
|
||||
|
||||
@@ -31,9 +31,8 @@ require_once('MyHelpers.class.inc.php');
|
||||
|
||||
|
||||
/**
|
||||
* Definition of a filter (could be made out of an existing attribute, or from an expression)
|
||||
* Definition of a filter (could be made out of an existing attribute, or from an expression)
|
||||
*
|
||||
* @deprecated 3.1.0 not used N°4690 - Deprecate "FilterCodes"
|
||||
* @package iTopORM
|
||||
*/
|
||||
abstract class FilterDefinition
|
||||
@@ -47,7 +46,6 @@ abstract class FilterDefinition
|
||||
|
||||
public function __construct($sCode, $aParams = array())
|
||||
{
|
||||
DeprecatedCallsLog::NotifyDeprecatedPhpMethod("Deprecated class ".$this->GetClass().". Do not use. Will be removed in next version.");
|
||||
$this->m_sCode = $sCode;
|
||||
$this->m_aParams = $aParams;
|
||||
$this->ConsistencyCheck();
|
||||
@@ -100,9 +98,8 @@ abstract class FilterDefinition
|
||||
}
|
||||
|
||||
/**
|
||||
* Match against the object unique identifier
|
||||
* Match against the object unique identifier
|
||||
*
|
||||
* @deprecated 3.1.0 N°4690 - Deprecate "FilterCodes"
|
||||
* @package iTopORM
|
||||
*/
|
||||
class FilterPrivateKey extends FilterDefinition
|
||||
@@ -148,9 +145,8 @@ class FilterPrivateKey extends FilterDefinition
|
||||
}
|
||||
|
||||
/**
|
||||
* Match against an existing attribute (the attribute type will determine the available operators)
|
||||
* Match against an existing attribute (the attribute type will determine the available operators)
|
||||
*
|
||||
* @deprecated 3.1.0 N°4690 - Deprecate "FilterCodes"
|
||||
* @package iTopORM
|
||||
*/
|
||||
class FilterFromAttribute extends FilterDefinition
|
||||
|
||||
@@ -62,8 +62,7 @@ class HTMLBulkExport extends TabularBulkExport
|
||||
if ($oAttDef instanceof AttributeDateTime) // AttributeDate is derived from AttributeDateTime
|
||||
{
|
||||
$sClass = (get_class($oAttDef) == 'AttributeDateTime') ? 'user-formatted-date-time' : 'user-formatted-date';
|
||||
|
||||
return '<div class="'.$sClass.'" data-date="'.$oObj->Get($sAttCode).'">'.utils::EscapeHtml($oAttDef->GetEditValue($oObj->Get($sAttCode), $oObj)).'</div>';
|
||||
return '<div class="'.$sClass.'" data-date="'.$oObj->Get($sAttCode).'">'.htmlentities($oAttDef->GetEditValue($oObj->Get($sAttCode), $oObj), ENT_QUOTES, 'UTF-8').'</div>';
|
||||
}
|
||||
}
|
||||
return $this->GetValue($oObj, $sAttCode);
|
||||
|
||||
@@ -34,32 +34,36 @@ abstract class HTMLSanitizer
|
||||
|
||||
/**
|
||||
* Sanitize an HTML string with the configured sanitizer, falling back to HTMLDOMSanitizer in case of Exception or invalid configuration
|
||||
*
|
||||
* @param string $sHTML
|
||||
* @param string $sConfigKey eg. 'html_sanitizer', 'svg_sanitizer'
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function Sanitize($sHTML)
|
||||
public static function Sanitize($sHTML, $sConfigKey = 'html_sanitizer')
|
||||
{
|
||||
$sSanitizerClass = MetaModel::GetConfig()->Get('html_sanitizer');
|
||||
if(!class_exists($sSanitizerClass))
|
||||
{
|
||||
IssueLog::Warning('The configured "html_sanitizer" class "'.$sSanitizerClass.'" is not a valid class. Will use HTMLDOMSanitizer as the default sanitizer.');
|
||||
$sSanitizerClass = 'HTMLDOMSanitizer';
|
||||
}
|
||||
else if(!is_subclass_of($sSanitizerClass, 'HTMLSanitizer'))
|
||||
{
|
||||
IssueLog::Warning('The configured "html_sanitizer" class "'.$sSanitizerClass.'" is not a subclass of HTMLSanitizer. Will use HTMLDOMSanitizer as the default sanitizer.');
|
||||
$sSanitizerClass = utils::GetConfig()->Get($sConfigKey);
|
||||
if (!class_exists($sSanitizerClass)) {
|
||||
IssueLog::Warning('The configured "'.$sConfigKey.'" class "'.$sSanitizerClass.'" is not a valid class. Will use HTMLDOMSanitizer as the default sanitizer.');
|
||||
$sSanitizerClass = 'HTMLDOMSanitizer';
|
||||
} else if (!is_subclass_of($sSanitizerClass, 'HTMLSanitizer')) {
|
||||
if ($sConfigKey === 'html_sanitizer') {
|
||||
IssueLog::Warning('The configured "'.$sConfigKey.'" class "'.$sSanitizerClass.'" is not a subclass of HTMLSanitizer. Will use HTMLDOMSanitizer as the default sanitizer.');
|
||||
$sSanitizerClass = 'HTMLDOMSanitizer';
|
||||
}
|
||||
if ($sConfigKey === 'svg_sanitizer') {
|
||||
IssueLog::Error('The configured "'.$sConfigKey.'" class "'.$sSanitizerClass.'" is not a subclass of '.HTMLSanitizer::class.' ! Won\'t sanitize string.');
|
||||
|
||||
return $sHTML;
|
||||
}
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
try {
|
||||
$oSanitizer = new $sSanitizerClass();
|
||||
$sCleanHTML = $oSanitizer->DoSanitize($sHTML);
|
||||
}
|
||||
catch(Exception $e)
|
||||
{
|
||||
if($sSanitizerClass != 'HTMLDOMSanitizer')
|
||||
{
|
||||
catch (Exception $e) {
|
||||
if ($sSanitizerClass != 'HTMLDOMSanitizer') {
|
||||
IssueLog::Warning('Failed to sanitize an HTML string with "'.$sSanitizerClass.'". The following exception occured: '.$e->getMessage());
|
||||
IssueLog::Warning('Will try to sanitize with HTMLDOMSanitizer.');
|
||||
// try again with the HTMLDOMSanitizer
|
||||
|
||||
@@ -242,7 +242,7 @@ class InlineImage extends DBObject
|
||||
public static function OnFormCancel($sTempId): bool
|
||||
{
|
||||
// Protection against unfortunate massive delete of inline images when a null temp ID is passed
|
||||
if (strlen($sTempId) === 0) {
|
||||
if (utils::IsNullOrEmptyString($sTempId)) {
|
||||
IssueLog::Trace('OnFormCancel "error" $sTempId is null or empty', LogChannels::INLINE_IMAGE, array(
|
||||
'$sTempId' => $sTempId,
|
||||
'$sUser' => UserRights::GetUser(),
|
||||
@@ -295,12 +295,13 @@ class InlineImage extends DBObject
|
||||
{
|
||||
$sImgTag = $aImgInfo[0][0];
|
||||
$sSecret = '';
|
||||
if (preg_match('/data-img-secret="([0-9a-f]+)"/', $sImgTag, $aSecretMatches)) {
|
||||
if (preg_match('/data-img-secret="([0-9a-f]+)"/', $sImgTag, $aSecretMatches))
|
||||
{
|
||||
$sSecret = '&s='.$aSecretMatches[1];
|
||||
}
|
||||
$sAttId = $aImgInfo[2][0];
|
||||
|
||||
$sNewImgTag = preg_replace('/src="[^"]+"/', 'src="'.utils::EscapeHtml($sUrl.$sAttId.$sSecret).'"', $sImgTag); // preserve other attributes, must convert & to & to be idempotent with CKEditor
|
||||
|
||||
$sNewImgTag = preg_replace('/src="[^"]+"/', 'src="'.htmlentities($sUrl.$sAttId.$sSecret, ENT_QUOTES, 'UTF-8').'"', $sImgTag); // preserve other attributes, must convert & to & to be idempotent with CKEditor
|
||||
$aNeedles[] = $sImgTag;
|
||||
$aReplacements[] = $sNewImgTag;
|
||||
}
|
||||
@@ -535,8 +536,8 @@ JS
|
||||
$iObjKey = $oObject->GetKey();
|
||||
|
||||
$sAbsoluteUrlAppRoot = utils::GetAbsoluteUrlAppRoot();
|
||||
$sToggleFullScreen = utils::EscapeHtml(Dict::S('UI:ToggleFullScreen'));
|
||||
|
||||
$sToggleFullScreen = htmlentities(Dict::S('UI:ToggleFullScreen'), ENT_QUOTES, 'UTF-8');
|
||||
|
||||
return
|
||||
<<<JS
|
||||
// Hook the file upload of all CKEditor instances
|
||||
|
||||
@@ -299,7 +299,7 @@ class ExecutionKPI
|
||||
*/
|
||||
private static function Push(ExecutionKPI $oExecutionKPI)
|
||||
{
|
||||
self::$m_aExecutionStack[] = $oExecutionKPI;
|
||||
array_push(self::$m_aExecutionStack, $oExecutionKPI);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -449,3 +449,4 @@ class ExecutionKPI
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -545,12 +545,8 @@ class LogChannels
|
||||
public const APC = 'apc';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
* @since 3.0.1 N°4849
|
||||
* @since 2.7.7 N°4635
|
||||
* @since 3.0.0
|
||||
*/
|
||||
public const NOTIFICATIONS = 'notifications';
|
||||
|
||||
public const CLI = 'CLI';
|
||||
|
||||
/**
|
||||
@@ -560,23 +556,31 @@ class LogChannels
|
||||
*/
|
||||
public const CMDB_SOURCE = 'cmdbsource';
|
||||
|
||||
public const CONSOLE = 'console';
|
||||
/**
|
||||
* @since 3.0.0
|
||||
*/
|
||||
public const CONSOLE = 'console';
|
||||
|
||||
public const CORE = 'core';
|
||||
public const CORE = 'core';
|
||||
|
||||
public const DEADLOCK = 'DeadLock';
|
||||
|
||||
public const INLINE_IMAGE = 'InlineImage';
|
||||
|
||||
public const PORTAL = 'portal';
|
||||
public const DEADLOCK = 'DeadLock';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
* @since 3.1.0 specific channel for event service
|
||||
* @since 2.7.9 3.0.3 3.1.0 N°5588
|
||||
*/
|
||||
public const EVENT_SERVICE = 'EventService';
|
||||
public const EXPORT = 'export';
|
||||
|
||||
public const DM_CRUD = 'DMCRUD';
|
||||
public const INLINE_IMAGE = 'InlineImage';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
* @since 3.0.1 N°4849
|
||||
* @since 2.7.7 N°4635
|
||||
*/
|
||||
public const NOTIFICATIONS = 'notifications';
|
||||
|
||||
public const PORTAL = 'portal';
|
||||
}
|
||||
|
||||
|
||||
@@ -1020,15 +1024,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;
|
||||
|
||||
/** @var string Warning this constant won't be used directly ! To see the real default level check {@see GetLevelDefault()} */
|
||||
public const LEVEL_DEFAULT = self::LEVEL_ERROR;
|
||||
|
||||
/** @var \FileLog we want our own instance ! */
|
||||
@@ -1103,7 +1103,12 @@ class DeprecatedCallsLog extends LogAPI
|
||||
}
|
||||
|
||||
$aStack = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 4);
|
||||
$iStackDeprecatedMethodLevel = 2; // level 0 = current method, level 1 = @trigger_error, level 2 = method containing the `trigger_error` call
|
||||
$iStackDeprecatedMethodLevel = 2; // level 0 = current method, level 1 = @trigger_error, level 2 = method containing the `trigger_error` call (can be either 'trigger_deprecation' or the faulty method), level 3 = In some cases, method containing the 'trigger_deprecation' call
|
||||
// In case current level is actually a 'trigger_deprecation' call, try to go one level further to get the real deprecated method
|
||||
if (array_key_exists($iStackDeprecatedMethodLevel, $aStack) && ($aStack[$iStackDeprecatedMethodLevel]['function'] === 'trigger_deprecation') && array_key_exists($iStackDeprecatedMethodLevel + 1, $aStack)) {
|
||||
$iStackDeprecatedMethodLevel++;
|
||||
}
|
||||
|
||||
$sDeprecatedObject = $aStack[$iStackDeprecatedMethodLevel]['class'];
|
||||
$sDeprecatedMethod = $aStack[$iStackDeprecatedMethodLevel]['function'];
|
||||
if (($sDeprecatedObject === __CLASS__) && ($sDeprecatedMethod === 'Log')) {
|
||||
@@ -1148,7 +1153,6 @@ class DeprecatedCallsLog extends LogAPI
|
||||
* - else call parent method
|
||||
*
|
||||
* In other words, when in dev mode all deprecated calls will be logged to file
|
||||
*
|
||||
*/
|
||||
protected static function GetLevelDefault(string $sConfigKey)
|
||||
{
|
||||
@@ -1237,35 +1241,6 @@ 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()) {
|
||||
|
||||
@@ -128,10 +128,6 @@ abstract class MetaModel
|
||||
/** @var string */
|
||||
protected static $m_sEnvironment = 'production';
|
||||
|
||||
public const REENTRANCE_TYPE_UPDATE = 'update';
|
||||
|
||||
protected static $m_aReentranceProtection = [];
|
||||
|
||||
/**
|
||||
* MetaModel constructor.
|
||||
*/
|
||||
@@ -471,7 +467,7 @@ abstract class MetaModel
|
||||
return self::GetClassIcon($sParentClass, $bImgTag, $sMoreStyles);
|
||||
}
|
||||
}
|
||||
$sIcon = str_replace('/modules/', '/env-'.self::$m_sEnvironment.'/', $sIcon ?? ''); // Support of pre-2.0 modules
|
||||
$sIcon = str_replace('/modules/', '/env-'.self::$m_sEnvironment.'/', $sIcon); // Support of pre-2.0 modules
|
||||
if ($bImgTag && ($sIcon != '')) {
|
||||
$sIcon = "<img src=\"$sIcon\" style=\"vertical-align:middle;$sMoreStyles\"/>";
|
||||
}
|
||||
@@ -1123,7 +1119,9 @@ abstract class MetaModel
|
||||
return self::$m_aAttribOrigins[$sClass][$sAttCode];
|
||||
}
|
||||
|
||||
/** *
|
||||
/**
|
||||
* @deprecated do not use : dead code, will be removed in the future
|
||||
*
|
||||
* @param string $sClass
|
||||
* @param string $sAttCode
|
||||
*
|
||||
@@ -1132,11 +1130,9 @@ abstract class MetaModel
|
||||
*/
|
||||
final public static function GetFilterCodeOrigin($sClass, $sAttCode)
|
||||
{
|
||||
if ($sAttCode == 'id') {
|
||||
return MetaModel::GetRootClass($sClass);
|
||||
}
|
||||
self::_check_subclass($sClass);
|
||||
|
||||
return MetaModel::GetAttributeOrigin($sClass, self::$m_aFilterAttribList[$sClass][$sAttCode]);
|
||||
return self::$m_aFilterOrigins[$sClass][$sAttCode];
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1485,6 +1481,7 @@ abstract class MetaModel
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated do not use : dead code, will be removed in the future
|
||||
*
|
||||
* @param string $sClass
|
||||
*
|
||||
@@ -1493,9 +1490,11 @@ abstract class MetaModel
|
||||
*/
|
||||
final public static function GetFiltersList($sClass)
|
||||
{
|
||||
// cannot notify depreciation for now as this is still MASSIVELY used in iTop core !
|
||||
//DeprecatedCallsLog::NotifyDeprecatedPhpMethod('do not use : dead code, will be removed in the future');
|
||||
self::_check_subclass($sClass);
|
||||
|
||||
return array_keys(self::$m_aFilterAttribList[$sClass]);
|
||||
return array_keys(self::$m_aFilterDefs[$sClass]);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1565,7 +1564,9 @@ abstract class MetaModel
|
||||
$oKeyAttDef = MetaModel::GetAttributeDef($sClass, $sExtKeyAttCode);
|
||||
$sRemoteClass = $oKeyAttDef->GetTargetClass();
|
||||
$bRes = MetaModel::IsValidAttCode($sRemoteClass, $sRemoteAttCode, true);
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
$bRes = false;
|
||||
}
|
||||
}
|
||||
@@ -1590,6 +1591,7 @@ abstract class MetaModel
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated do not use : dead code, will be removed in the future
|
||||
*
|
||||
* @param string $sClass
|
||||
* @param string $sFilterCode
|
||||
@@ -1598,11 +1600,13 @@ abstract class MetaModel
|
||||
*/
|
||||
final public static function IsValidFilterCode($sClass, $sFilterCode)
|
||||
{
|
||||
if (!array_key_exists($sClass, self::$m_aFilterAttribList)) {
|
||||
// cannot notify depreciation for now as this is still MASSIVELY used in iTop core !
|
||||
//DeprecatedCallsLog::NotifyDeprecatedPhpMethod('do not use : dead code, will be removed in the future');
|
||||
if (!array_key_exists($sClass, self::$m_aFilterDefs)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return (array_key_exists($sFilterCode, self::$m_aFilterAttribList[$sClass]));
|
||||
return (array_key_exists($sFilterCode, self::$m_aFilterDefs[$sClass]));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1876,21 +1880,31 @@ abstract class MetaModel
|
||||
public static function GetDescription($sClass, $sAttCode)
|
||||
{
|
||||
$oAttDef = self::GetAttributeDef($sClass, $sAttCode);
|
||||
if ($oAttDef) {
|
||||
if ($oAttDef)
|
||||
{
|
||||
return $oAttDef->GetDescription();
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
/**
|
||||
* @var array array of (FilterCode => AttributeCode)
|
||||
* Filters of a given class may contain filters defined in a parent class
|
||||
* - Some filters are a copy of the definition
|
||||
* - Some filters correspond to the upper class table definition (compound objects)
|
||||
* (see also attributes definition)
|
||||
*
|
||||
* @deprecated do not use : dead code, will be removed in the future
|
||||
* @var array array of ("classname" => array filterdef)
|
||||
*/
|
||||
private static $m_aFilterAttribList = array();
|
||||
private static $m_aFilterDefs = array();
|
||||
/**
|
||||
* @deprecated do not use : dead code, will be removed in the future
|
||||
* @var array array of ("classname" => array of ("attcode"=>"sourceclass"))
|
||||
*/
|
||||
private static $m_aFilterOrigins = array();
|
||||
|
||||
/**
|
||||
* @deprecated 3.0.0 do not use : dead code, will be removed in the future N°4690 - Deprecate "FilterCodes"
|
||||
* instead of array_keys(MetaModel::GetClassFilterDefs($sClass)); use MetaModel::GetFiltersList($sClass)
|
||||
* @deprecated do not use : dead code, will be removed in the future
|
||||
*
|
||||
* @param string $sClass
|
||||
*
|
||||
@@ -1900,25 +1914,34 @@ abstract class MetaModel
|
||||
public static function GetClassFilterDefs($sClass)
|
||||
{
|
||||
// cannot notify depreciation for now as this is still MASSIVELY used in iTop core !
|
||||
DeprecatedCallsLog::NotifyDeprecatedPhpMethod('do not use MetaModel::GetClassFilterDefs: dead code, will be removed in the future. Use MetaModel::GetFiltersList or MetaModel::GetFiltersAttributes');
|
||||
//DeprecatedCallsLog::NotifyDeprecatedPhpMethod('do not use : dead code, will be removed in the future');
|
||||
self::_check_subclass($sClass);
|
||||
|
||||
return self::$m_aFilterAttribList[$sClass];
|
||||
return self::$m_aFilterDefs[$sClass];
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated do not use : dead code, will be removed in the future
|
||||
*
|
||||
* @param string $sClass
|
||||
* @param string $sFilterCode
|
||||
*
|
||||
* @return array ($sFilterCode=>$sAttributeCode) + id=>id
|
||||
* @return mixed
|
||||
* @throws \CoreException
|
||||
*/
|
||||
public static function GetFilterAttribList($sClass)
|
||||
final public static function GetClassFilterDef($sClass, $sFilterCode)
|
||||
{
|
||||
return self::$m_aFilterAttribList[$sClass];
|
||||
DeprecatedCallsLog::NotifyDeprecatedPhpMethod('do not use : dead code, will be removed in the future');
|
||||
self::_check_subclass($sClass);
|
||||
if (!array_key_exists($sFilterCode, self::$m_aFilterDefs[$sClass])) {
|
||||
throw new CoreException("Unknown filter code '$sFilterCode' for class '$sClass'");
|
||||
}
|
||||
|
||||
return self::$m_aFilterDefs[$sClass][$sFilterCode];
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated 3.0.0 do not use : dead code, will be removed in the future use GetLabel instead N°4690 - Deprecate "FilterCodes"
|
||||
* @deprecated do not use : dead code, will be removed in the future
|
||||
*
|
||||
* @param string $sClass
|
||||
* @param string $sFilterCode
|
||||
@@ -1928,9 +1951,103 @@ abstract class MetaModel
|
||||
*/
|
||||
public static function GetFilterLabel($sClass, $sFilterCode)
|
||||
{
|
||||
DeprecatedCallsLog::NotifyDeprecatedPhpMethod('do not use MetaModel::GetFilterLabel : dead code, will be removed in the future. Use MetaModel::GetLabel instead');
|
||||
DeprecatedCallsLog::NotifyDeprecatedPhpMethod('do not use : dead code, will be removed in the future');
|
||||
$oFilter = self::GetClassFilterDef($sClass, $sFilterCode);
|
||||
if ($oFilter) {
|
||||
return $oFilter->GetLabel();
|
||||
}
|
||||
|
||||
return this::GetLabel($sClass, $sFilterCode);
|
||||
return "";
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated do not use : dead code, will be removed in the future
|
||||
* @param string $sClass
|
||||
* @param string $sFilterCode
|
||||
*
|
||||
* @return string
|
||||
* @throws \CoreException
|
||||
*/
|
||||
public static function GetFilterDescription($sClass, $sFilterCode)
|
||||
{
|
||||
DeprecatedCallsLog::NotifyDeprecatedPhpMethod('do not use : dead code, will be removed in the future');
|
||||
$oFilter = self::GetClassFilterDef($sClass, $sFilterCode);
|
||||
if ($oFilter) {
|
||||
return $oFilter->GetDescription();
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated do not use : dead code, will be removed in the future
|
||||
* @param string $sClass
|
||||
* @param string $sFilterCode
|
||||
*
|
||||
* @return array
|
||||
* @throws \CoreException
|
||||
*/
|
||||
public static function GetFilterOperators($sClass, $sFilterCode)
|
||||
{
|
||||
DeprecatedCallsLog::NotifyDeprecatedPhpMethod('do not use : dead code, will be removed in the future');
|
||||
$oFilter = self::GetClassFilterDef($sClass, $sFilterCode);
|
||||
if ($oFilter) {
|
||||
return $oFilter->GetOperators();
|
||||
}
|
||||
|
||||
return array();
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated do not use : dead code, will be removed in the future
|
||||
* @param string $sClass
|
||||
* @param string $sFilterCode
|
||||
*
|
||||
* @return array
|
||||
* @throws \CoreException
|
||||
*/
|
||||
public static function GetFilterLooseOperator($sClass, $sFilterCode)
|
||||
{
|
||||
DeprecatedCallsLog::NotifyDeprecatedPhpMethod('do not use : dead code, will be removed in the future');
|
||||
$oFilter = self::GetClassFilterDef($sClass, $sFilterCode);
|
||||
if ($oFilter) {
|
||||
return $oFilter->GetLooseOperator();
|
||||
}
|
||||
|
||||
return array();
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated do not use : dead code, will be removed in the future
|
||||
* @param string $sClass
|
||||
* @param string $sFilterCode
|
||||
* @param string $sOpCode
|
||||
*
|
||||
* @return string
|
||||
* @throws \CoreException
|
||||
*/
|
||||
public static function GetFilterOpDescription($sClass, $sFilterCode, $sOpCode)
|
||||
{
|
||||
DeprecatedCallsLog::NotifyDeprecatedPhpMethod('do not use : dead code, will be removed in the future');
|
||||
$oFilter = self::GetClassFilterDef($sClass, $sFilterCode);
|
||||
if ($oFilter) {
|
||||
return $oFilter->GetOpDescription($sOpCode);
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated do not use : dead code, will be removed in the future
|
||||
* @param string $sFilterCode
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function GetFilterHTMLInput($sFilterCode)
|
||||
{
|
||||
DeprecatedCallsLog::NotifyDeprecatedPhpMethod('do not use : dead code, will be removed in the future');
|
||||
|
||||
return "<INPUT name=\"$sFilterCode\">";
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2250,14 +2367,17 @@ abstract class MetaModel
|
||||
$aNeighbourData['sFromClass'] = $aNeighbourData['sDefinedInClass'];
|
||||
try
|
||||
{
|
||||
if (Utils::StrLen($aNeighbourData['sQueryDown']) == 0) {
|
||||
if (strlen($aNeighbourData['sQueryDown']) == 0)
|
||||
{
|
||||
$oAttDef = self::GetAttributeDef($sClass, $aNeighbourData['sAttribute']);
|
||||
if ($oAttDef instanceof AttributeExternalKey) {
|
||||
if ($oAttDef instanceof AttributeExternalKey)
|
||||
{
|
||||
$sTargetClass = $oAttDef->GetTargetClass();
|
||||
$aNeighbourData['sToClass'] = $sTargetClass;
|
||||
$aNeighbourData['sQueryDown'] = 'SELECT '.$sTargetClass.' AS o WHERE o.id = :this->'.$aNeighbourData['sAttribute'];
|
||||
$aNeighbourData['sQueryUp'] = 'SELECT '.$aNeighbourData['sFromClass'].' AS o WHERE o.'.$aNeighbourData['sAttribute'].' = :this->id';
|
||||
} elseif ($oAttDef instanceof AttributeLinkedSet)
|
||||
}
|
||||
elseif ($oAttDef instanceof AttributeLinkedSet)
|
||||
{
|
||||
$sLinkedClass = $oAttDef->GetLinkedClass();
|
||||
$sExtKeyToMe = $oAttDef->GetExtKeyToMe();
|
||||
@@ -2769,8 +2889,6 @@ abstract class MetaModel
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated 3.1.0 use GetAllowedValues_att N°4690 - Deprecate "FilterCodes"
|
||||
*
|
||||
* @param string $sClass
|
||||
* @param string $sFltCode
|
||||
* @param array $aArgs
|
||||
@@ -2781,12 +2899,10 @@ abstract class MetaModel
|
||||
*/
|
||||
public static function GetAllowedValues_flt($sClass, $sFltCode, $aArgs = array(), $sContains = '')
|
||||
{
|
||||
DeprecatedCallsLog::NotifyDeprecatedPhpMethod('do not use MetaModel::GetAllowedValues_flt: dead code, will be removed in the future. Use MetaModel::GetAllowedValues');
|
||||
|
||||
return self::GetAllowedValues_att($sClass, $sFltCode);
|
||||
$oFltDef = self::GetClassFilterDef($sClass, $sFltCode);
|
||||
return $oFltDef->GetAllowedValues($aArgs, $sContains);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param string $sClass
|
||||
* @param string $sAttCode
|
||||
@@ -2853,14 +2969,17 @@ abstract class MetaModel
|
||||
private static function AddMagicAttribute(AttributeDefinition $oAttribute, $sTargetClass, $sOriginClass = null)
|
||||
{
|
||||
$sCode = $oAttribute->GetCode();
|
||||
if (is_null($sOriginClass)) {
|
||||
if (is_null($sOriginClass))
|
||||
{
|
||||
$sOriginClass = $sTargetClass;
|
||||
}
|
||||
$oAttribute->SetHostClass($sTargetClass);
|
||||
self::$m_aAttribDefs[$sTargetClass][$sCode] = $oAttribute;
|
||||
self::$m_aAttribOrigins[$sTargetClass][$sCode] = $sOriginClass;
|
||||
|
||||
self::$m_aFilterAttribList[$sTargetClass][$sCode] = $sCode;
|
||||
$oFlt = new FilterFromAttribute($oAttribute);
|
||||
self::$m_aFilterDefs[$sTargetClass][$sCode] = $oFlt;
|
||||
self::$m_aFilterOrigins[$sTargetClass][$sCode] = $sOriginClass;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -3052,38 +3171,44 @@ abstract class MetaModel
|
||||
self::$m_aClassParams[$sRootClass]["db_finalclass_field"] = 'finalclass';
|
||||
}
|
||||
$oClassAtt = new AttributeFinalClass('finalclass', array(
|
||||
"sql" => $sDbFinalClassField,
|
||||
"default_value" => $sRootClass,
|
||||
"sql" => $sDbFinalClassField,
|
||||
"default_value" => $sRootClass,
|
||||
"is_null_allowed" => false,
|
||||
"depends_on" => array(),
|
||||
"depends_on" => array()
|
||||
));
|
||||
self::AddMagicAttribute($oClassAtt, $sRootClass);
|
||||
|
||||
$bObsoletable = array_key_exists($sRootClass, $aObsoletableRootClasses);
|
||||
if ($bObsoletable && is_null(self::$m_aClassParams[$sRootClass]['obsolescence_expression'])) {
|
||||
if ($bObsoletable && is_null(self::$m_aClassParams[$sRootClass]['obsolescence_expression']))
|
||||
{
|
||||
self::$m_aClassParams[$sRootClass]['obsolescence_expression'] = '0';
|
||||
}
|
||||
|
||||
|
||||
foreach (self::EnumChildClasses($sRootClass, ENUM_CHILD_CLASSES_EXCLUDETOP) as $sChildClass) {
|
||||
if (array_key_exists('finalclass', self::$m_aAttribDefs[$sChildClass])) {
|
||||
foreach(self::EnumChildClasses($sRootClass, ENUM_CHILD_CLASSES_EXCLUDETOP) as $sChildClass)
|
||||
{
|
||||
if (array_key_exists('finalclass', self::$m_aAttribDefs[$sChildClass]))
|
||||
{
|
||||
throw new CoreException("Class $sChildClass, 'finalclass' is a reserved keyword, it cannot be used as an attribute code");
|
||||
}
|
||||
if (array_key_exists('finalclass', self::$m_aFilterAttribList[$sChildClass])) {
|
||||
if (array_key_exists('finalclass', self::$m_aFilterDefs[$sChildClass]))
|
||||
{
|
||||
throw new CoreException("Class $sChildClass, 'finalclass' is a reserved keyword, it cannot be used as a filter code");
|
||||
}
|
||||
$oCloned = clone $oClassAtt;
|
||||
$oCloned->SetFixedValue($sChildClass);
|
||||
self::AddMagicAttribute($oCloned, $sChildClass, $sRootClass);
|
||||
|
||||
if ($bObsoletable && is_null(self::$m_aClassParams[$sChildClass]['obsolescence_expression'])) {
|
||||
if ($bObsoletable && is_null(self::$m_aClassParams[$sChildClass]['obsolescence_expression']))
|
||||
{
|
||||
self::$m_aClassParams[$sChildClass]['obsolescence_expression'] = '0';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Add magic attributes to the classes
|
||||
foreach (self::GetClasses() as $sClass) {
|
||||
foreach(self::GetClasses() as $sClass)
|
||||
{
|
||||
$sRootClass = self::$m_aRootClasses[$sClass];
|
||||
|
||||
// Create the friendly name attribute
|
||||
@@ -3091,35 +3216,40 @@ abstract class MetaModel
|
||||
$oFriendlyName = new AttributeFriendlyName($sFriendlyNameAttCode);
|
||||
self::AddMagicAttribute($oFriendlyName, $sClass);
|
||||
|
||||
if (self::$m_aClassParams[$sClass]["archive_root"]) {
|
||||
if (self::$m_aClassParams[$sClass]["archive_root"])
|
||||
{
|
||||
// Create archive attributes on top the archivable hierarchy
|
||||
$oArchiveFlag = new AttributeArchiveFlag('archive_flag');
|
||||
self::AddMagicAttribute($oArchiveFlag, $sClass);
|
||||
|
||||
$oArchiveDate = new AttributeArchiveDate('archive_date', array('magic' => true, "allowed_values" => null, "sql" => 'archive_date', "default_value" => '', "is_null_allowed" => true, "depends_on" => array()));
|
||||
self::AddMagicAttribute($oArchiveDate, $sClass);
|
||||
} elseif (self::$m_aClassParams[$sClass]["archive"]) {
|
||||
}
|
||||
elseif (self::$m_aClassParams[$sClass]["archive"])
|
||||
{
|
||||
$sArchiveRoot = self::$m_aClassParams[$sClass]['archive_root_class'];
|
||||
// Inherit archive attributes
|
||||
$oArchiveFlag = clone self::$m_aAttribDefs[$sArchiveRoot]['archive_flag'];
|
||||
$oArchiveFlag->SetHostClass($sClass);
|
||||
self::$m_aAttribDefs[$sClass]['archive_flag'] = $oArchiveFlag;
|
||||
self::$m_aAttribOrigins[$sClass]['archive_flag'] = $sArchiveRoot;
|
||||
|
||||
$oArchiveDate = clone self::$m_aAttribDefs[$sArchiveRoot]['archive_date'];
|
||||
$oArchiveDate->SetHostClass($sClass);
|
||||
self::$m_aAttribDefs[$sClass]['archive_date'] = $oArchiveDate;
|
||||
self::$m_aAttribOrigins[$sClass]['archive_date'] = $sArchiveRoot;
|
||||
|
||||
}
|
||||
if (!is_null(self::$m_aClassParams[$sClass]['obsolescence_expression'])) {
|
||||
if (!is_null(self::$m_aClassParams[$sClass]['obsolescence_expression']))
|
||||
{
|
||||
$oObsolescenceFlag = new AttributeObsolescenceFlag('obsolescence_flag');
|
||||
self::AddMagicAttribute($oObsolescenceFlag, $sClass);
|
||||
|
||||
if (self::$m_aRootClasses[$sClass] == $sClass) {
|
||||
if (self::$m_aRootClasses[$sClass] == $sClass)
|
||||
{
|
||||
$oObsolescenceDate = new AttributeObsolescenceDate('obsolescence_date', array('magic' => true, "allowed_values" => null, "sql" => 'obsolescence_date', "default_value" => '', "is_null_allowed" => true, "depends_on" => array()));
|
||||
self::AddMagicAttribute($oObsolescenceDate, $sClass);
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
$oObsolescenceDate = clone self::$m_aAttribDefs[$sRootClass]['obsolescence_date'];
|
||||
$oObsolescenceDate->SetHostClass($sClass);
|
||||
self::$m_aAttribDefs[$sClass]['obsolescence_date'] = $oObsolescenceDate;
|
||||
@@ -3131,24 +3261,40 @@ abstract class MetaModel
|
||||
// Prepare external fields and filters
|
||||
// Add final class to external keys
|
||||
// Add magic attributes to external keys (finalclass, friendlyname, archive_flag, obsolescence_flag)
|
||||
foreach (self::GetClasses() as $sClass) {
|
||||
foreach (self::$m_aAttribDefs[$sClass] as $sAttCode => $oAttDef) {
|
||||
foreach(self::GetClasses() as $sClass)
|
||||
{
|
||||
foreach(self::$m_aAttribDefs[$sClass] as $sAttCode => $oAttDef)
|
||||
{
|
||||
// Compute the filter codes
|
||||
//
|
||||
foreach ($oAttDef->GetFilterDefinitions() as $sFilterCode => $sCode) {
|
||||
self::$m_aFilterAttribList[$sClass][$sFilterCode] = $sCode;
|
||||
foreach($oAttDef->GetFilterDefinitions() as $sFilterCode => $oFilterDef)
|
||||
{
|
||||
self::$m_aFilterDefs[$sClass][$sFilterCode] = $oFilterDef;
|
||||
|
||||
if ($oAttDef->IsExternalField())
|
||||
{
|
||||
$sKeyAttCode = $oAttDef->GetKeyAttCode();
|
||||
$oKeyDef = self::GetAttributeDef($sClass, $sKeyAttCode);
|
||||
self::$m_aFilterOrigins[$sClass][$sFilterCode] = $oKeyDef->GetTargetClass();
|
||||
}
|
||||
else
|
||||
{
|
||||
self::$m_aFilterOrigins[$sClass][$sFilterCode] = self::$m_aAttribOrigins[$sClass][$sAttCode];
|
||||
}
|
||||
}
|
||||
|
||||
// Compute the fields that will be used to display a pointer to another object
|
||||
//
|
||||
if ($oAttDef->IsExternalKey(EXTKEY_ABSOLUTE)) {
|
||||
if ($oAttDef->IsExternalKey(EXTKEY_ABSOLUTE))
|
||||
{
|
||||
// oAttDef is either
|
||||
// - an external KEY / FIELD (direct),
|
||||
// - an external field pointing to an external KEY / FIELD
|
||||
// - an external field pointing to an external field pointing to....
|
||||
$sRemoteClass = $oAttDef->GetTargetClass(EXTKEY_ABSOLUTE);
|
||||
|
||||
if ($oAttDef->IsExternalField()) {
|
||||
if ($oAttDef->IsExternalField())
|
||||
{
|
||||
// This is a key, but the value comes from elsewhere
|
||||
// Create an external field pointing to the remote friendly name attribute
|
||||
$sKeyAttCode = $oAttDef->GetKeyAttCode();
|
||||
@@ -3156,21 +3302,24 @@ abstract class MetaModel
|
||||
$sFriendlyNameAttCode = $sAttCode.'_friendlyname';
|
||||
$oFriendlyName = new AttributeExternalField($sFriendlyNameAttCode, array("allowed_values" => null, "extkey_attcode" => $sKeyAttCode, "target_attcode" => $sRemoteAttCode, "depends_on" => array()));
|
||||
self::AddMagicAttribute($oFriendlyName, $sClass, self::$m_aAttribOrigins[$sClass][$sKeyAttCode]);
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
// Create the friendly name attribute
|
||||
$sFriendlyNameAttCode = $sAttCode.'_friendlyname';
|
||||
$oFriendlyName = new AttributeExternalField($sFriendlyNameAttCode, array('allowed_values' => null, 'extkey_attcode' => $sAttCode, "target_attcode" => 'friendlyname', 'depends_on' => array()));
|
||||
self::AddMagicAttribute($oFriendlyName, $sClass, self::$m_aAttribOrigins[$sClass][$sAttCode]);
|
||||
|
||||
if (self::HasChildrenClasses($sRemoteClass)) {
|
||||
if (self::HasChildrenClasses($sRemoteClass))
|
||||
{
|
||||
// First, create an external field attribute, that gets the final class
|
||||
$sClassRecallAttCode = $sAttCode.'_finalclass_recall';
|
||||
$oClassRecall = new AttributeExternalField($sClassRecallAttCode, array(
|
||||
"allowed_values" => null,
|
||||
"extkey_attcode" => $sAttCode,
|
||||
"target_attcode" => "finalclass",
|
||||
"allowed_values" => null,
|
||||
"extkey_attcode" => $sAttCode,
|
||||
"target_attcode" => "finalclass",
|
||||
"is_null_allowed" => true,
|
||||
"depends_on" => array(),
|
||||
"depends_on" => array()
|
||||
));
|
||||
self::AddMagicAttribute($oClassRecall, $sClass, self::$m_aAttribOrigins[$sClass][$sAttCode]);
|
||||
|
||||
@@ -3201,14 +3350,18 @@ abstract class MetaModel
|
||||
}
|
||||
}
|
||||
|
||||
if (self::IsArchivable($sRemoteClass)) {
|
||||
if (self::IsArchivable($sRemoteClass))
|
||||
{
|
||||
$sCode = $sAttCode.'_archive_flag';
|
||||
if ($oAttDef->IsExternalField()) {
|
||||
if ($oAttDef->IsExternalField())
|
||||
{
|
||||
// This is a key, but the value comes from elsewhere
|
||||
// Create an external field pointing to the remote attribute
|
||||
$sKeyAttCode = $oAttDef->GetKeyAttCode();
|
||||
$sRemoteAttCode = $oAttDef->GetExtAttCode().'_archive_flag';
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
$sKeyAttCode = $sAttCode;
|
||||
$sRemoteAttCode = 'archive_flag';
|
||||
}
|
||||
@@ -3216,14 +3369,18 @@ abstract class MetaModel
|
||||
self::AddMagicAttribute($oMagic, $sClass, self::$m_aAttribOrigins[$sClass][$sKeyAttCode]);
|
||||
|
||||
}
|
||||
if (self::IsObsoletable($sRemoteClass)) {
|
||||
if (self::IsObsoletable($sRemoteClass))
|
||||
{
|
||||
$sCode = $sAttCode.'_obsolescence_flag';
|
||||
if ($oAttDef->IsExternalField()) {
|
||||
if ($oAttDef->IsExternalField())
|
||||
{
|
||||
// This is a key, but the value comes from elsewhere
|
||||
// Create an external field pointing to the remote attribute
|
||||
$sKeyAttCode = $oAttDef->GetKeyAttCode();
|
||||
$sRemoteAttCode = $oAttDef->GetExtAttCode().'_obsolescence_flag';
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
$sKeyAttCode = $sAttCode;
|
||||
$sRemoteAttCode = 'obsolescence_flag';
|
||||
}
|
||||
@@ -3231,9 +3388,11 @@ abstract class MetaModel
|
||||
self::AddMagicAttribute($oMagic, $sClass, self::$m_aAttribOrigins[$sClass][$sKeyAttCode]);
|
||||
}
|
||||
}
|
||||
if ($oAttDef instanceof AttributeMetaEnum) {
|
||||
if ($oAttDef instanceof AttributeMetaEnum)
|
||||
{
|
||||
$aMappingData = $oAttDef->GetMapRule($sClass);
|
||||
if ($aMappingData != null) {
|
||||
if ($aMappingData != null)
|
||||
{
|
||||
$sEnumAttCode = $aMappingData['attcode'];
|
||||
self::$m_aEnumToMeta[$sClass][$sEnumAttCode][$sAttCode] = $oAttDef;
|
||||
}
|
||||
@@ -3242,10 +3401,17 @@ abstract class MetaModel
|
||||
|
||||
// Add a 'id' filter
|
||||
//
|
||||
if (array_key_exists('id', self::$m_aAttribDefs[$sClass])) {
|
||||
if (array_key_exists('id', self::$m_aAttribDefs[$sClass]))
|
||||
{
|
||||
throw new CoreException("Class $sClass, 'id' is a reserved keyword, it cannot be used as an attribute code");
|
||||
}
|
||||
self::$m_aFilterAttribList[$sClass]['id'] = 'id';
|
||||
if (array_key_exists('id', self::$m_aFilterDefs[$sClass]))
|
||||
{
|
||||
throw new CoreException("Class $sClass, 'id' is a reserved keyword, it cannot be used as a filter code");
|
||||
}
|
||||
$oFilter = new FilterPrivateKey('id', array('id_field' => self::DBGetKey($sClass)));
|
||||
self::$m_aFilterDefs[$sClass]['id'] = $oFilter;
|
||||
self::$m_aFilterOrigins[$sClass]['id'] = $sClass;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3405,7 +3571,8 @@ abstract class MetaModel
|
||||
|
||||
self::$m_aAttribDefs[$sClass] = array();
|
||||
self::$m_aAttribOrigins[$sClass] = array();
|
||||
self::$m_aFilterAttribList[$sClass] = array();
|
||||
self::$m_aFilterDefs[$sClass] = array();
|
||||
self::$m_aFilterOrigins[$sClass] = array();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -3435,20 +3602,25 @@ abstract class MetaModel
|
||||
public static function Init_InheritAttributes($sSourceClass = null)
|
||||
{
|
||||
$sTargetClass = self::GetCallersPHPClass("Init");
|
||||
if (empty($sSourceClass)) {
|
||||
if (empty($sSourceClass))
|
||||
{
|
||||
// Default: inherit from parent class
|
||||
$sSourceClass = self::GetParentPersistentClass($sTargetClass);
|
||||
if (empty($sSourceClass)) {
|
||||
if (empty($sSourceClass))
|
||||
{
|
||||
return;
|
||||
} // no attributes for the mother of all classes
|
||||
}
|
||||
if (isset(self::$m_aAttribDefs[$sSourceClass])) {
|
||||
if (!isset(self::$m_aAttribDefs[$sTargetClass])) {
|
||||
if (isset(self::$m_aAttribDefs[$sSourceClass]))
|
||||
{
|
||||
if (!isset(self::$m_aAttribDefs[$sTargetClass]))
|
||||
{
|
||||
self::$m_aAttribDefs[$sTargetClass] = array();
|
||||
self::$m_aAttribOrigins[$sTargetClass] = array();
|
||||
}
|
||||
self::$m_aAttribDefs[$sTargetClass] = self::object_array_mergeclone(self::$m_aAttribDefs[$sTargetClass], self::$m_aAttribDefs[$sSourceClass]);
|
||||
foreach (self::$m_aAttribDefs[$sTargetClass] as $sAttCode => $oAttDef) {
|
||||
foreach(self::$m_aAttribDefs[$sTargetClass] as $sAttCode => $oAttDef)
|
||||
{
|
||||
$oAttDef->SetHostClass($sTargetClass);
|
||||
}
|
||||
self::$m_aAttribOrigins[$sTargetClass] = array_merge(self::$m_aAttribOrigins[$sTargetClass], self::$m_aAttribOrigins[$sSourceClass]);
|
||||
@@ -3503,18 +3675,22 @@ abstract class MetaModel
|
||||
*/
|
||||
public static function Init_AddAttribute(AttributeDefinition $oAtt, $sTargetClass = null)
|
||||
{
|
||||
if (!$sTargetClass) {
|
||||
if (!$sTargetClass)
|
||||
{
|
||||
$sTargetClass = self::GetCallersPHPClass("Init");
|
||||
}
|
||||
|
||||
$sAttCode = $oAtt->GetCode();
|
||||
if ($sAttCode == 'finalclass') {
|
||||
if ($sAttCode == 'finalclass')
|
||||
{
|
||||
throw new Exception("Declaration of $sTargetClass: using the reserved keyword '$sAttCode' in attribute declaration");
|
||||
}
|
||||
if ($sAttCode == 'friendlyname') {
|
||||
if ($sAttCode == 'friendlyname')
|
||||
{
|
||||
throw new Exception("Declaration of $sTargetClass: using the reserved keyword '$sAttCode' in attribute declaration");
|
||||
}
|
||||
if (array_key_exists($sAttCode, self::$m_aAttribDefs[$sTargetClass])) {
|
||||
if (array_key_exists($sAttCode, self::$m_aAttribDefs[$sTargetClass]))
|
||||
{
|
||||
throw new Exception("Declaration of $sTargetClass: attempting to redeclare the inherited attribute '$sAttCode', originally declared in ".self::$m_aAttribOrigins[$sTargetClass][$sAttCode]);
|
||||
}
|
||||
|
||||
@@ -3551,7 +3727,6 @@ abstract class MetaModel
|
||||
{
|
||||
// The corresponding external key has already been ignored
|
||||
self::$m_aIgnoredAttributes[$sTargetClass][$oAtt->GetCode()] = self::$m_aIgnoredAttributes[$sTargetClass][$sExtKeyAttCode];
|
||||
|
||||
return;
|
||||
}
|
||||
//TODO Check if the target attribute is still there
|
||||
@@ -4814,6 +4989,18 @@ abstract class MetaModel
|
||||
}
|
||||
}
|
||||
}
|
||||
foreach(self::GetClassFilterDefs($sClass) as $sFltCode => $oFilterDef)
|
||||
{
|
||||
if (method_exists($oFilterDef, '__GetRefAttribute'))
|
||||
{
|
||||
$oAttDef = $oFilterDef->__GetRefAttribute();
|
||||
if (!self::IsValidAttCode($sClass, $oAttDef->GetCode()))
|
||||
{
|
||||
$aErrors[$sClass][] = "Wrong attribute code '".$oAttDef->GetCode()."' (wrong class) for the \"basic\" filter $sFltCode";
|
||||
$aSugFix[$sClass][] = "Expecting a value in {".implode(", ", self::GetAttributesList($sClass))."}";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Lifecycle
|
||||
//
|
||||
@@ -5001,23 +5188,27 @@ abstract class MetaModel
|
||||
*/
|
||||
public static function DBShowApplyForm($sRepairUrl, $sSQLStatementArgName, $aSQLFixes)
|
||||
{
|
||||
if (empty($sRepairUrl)) {
|
||||
if (empty($sRepairUrl))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// By design, some queries might be blank, we have to ignore them
|
||||
$aCleanFixes = array();
|
||||
foreach ($aSQLFixes as $sSQLFix) {
|
||||
if (!empty($sSQLFix)) {
|
||||
foreach($aSQLFixes as $sSQLFix)
|
||||
{
|
||||
if (!empty($sSQLFix))
|
||||
{
|
||||
$aCleanFixes[] = $sSQLFix;
|
||||
}
|
||||
}
|
||||
if (count($aCleanFixes) == 0) {
|
||||
if (count($aCleanFixes) == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
echo "<form action=\"$sRepairUrl\" method=\"POST\">\n";
|
||||
echo " <input type=\"hidden\" name=\"$sSQLStatementArgName\" value=\"".utils::EscapeHtml(implode("##SEP##", $aCleanFixes))."\">\n";
|
||||
echo " <input type=\"hidden\" name=\"$sSQLStatementArgName\" value=\"".htmlentities(implode("##SEP##", $aCleanFixes), ENT_QUOTES, 'UTF-8')."\">\n";
|
||||
echo " <input type=\"submit\" value=\" Apply changes (".count($aCleanFixes)." queries) \">\n";
|
||||
echo "</form>\n";
|
||||
}
|
||||
@@ -5263,21 +5454,24 @@ abstract class MetaModel
|
||||
$sRes = '';
|
||||
|
||||
$sRes .= "// Dictionnay conventions\n";
|
||||
$sRes .= utils::EscapeHtml("// Class:<class_name>\n");
|
||||
$sRes .= utils::EscapeHtml("// Class:<class_name>+\n");
|
||||
$sRes .= utils::EscapeHtml("// Class:<class_name>/Attribute:<attribute_code>\n");
|
||||
$sRes .= utils::EscapeHtml("// Class:<class_name>/Attribute:<attribute_code>+\n");
|
||||
$sRes .= utils::EscapeHtml("// Class:<class_name>/Attribute:<attribute_code>/Value:<value>\n");
|
||||
$sRes .= utils::EscapeHtml("// Class:<class_name>/Attribute:<attribute_code>/Value:<value>+\n");
|
||||
$sRes .= utils::EscapeHtml("// Class:<class_name>/Stimulus:<stimulus_code>\n");
|
||||
$sRes .= utils::EscapeHtml("// Class:<class_name>/Stimulus:<stimulus_code>+\n");
|
||||
$sRes .= htmlentities("// Class:<class_name>\n", ENT_QUOTES, 'UTF-8');
|
||||
$sRes .= htmlentities("// Class:<class_name>+\n", ENT_QUOTES, 'UTF-8');
|
||||
$sRes .= htmlentities("// Class:<class_name>/Attribute:<attribute_code>\n", ENT_QUOTES, 'UTF-8');
|
||||
$sRes .= htmlentities("// Class:<class_name>/Attribute:<attribute_code>+\n", ENT_QUOTES, 'UTF-8');
|
||||
$sRes .= htmlentities("// Class:<class_name>/Attribute:<attribute_code>/Value:<value>\n", ENT_QUOTES, 'UTF-8');
|
||||
$sRes .= htmlentities("// Class:<class_name>/Attribute:<attribute_code>/Value:<value>+\n", ENT_QUOTES, 'UTF-8');
|
||||
$sRes .= htmlentities("// Class:<class_name>/Stimulus:<stimulus_code>\n", ENT_QUOTES, 'UTF-8');
|
||||
$sRes .= htmlentities("// Class:<class_name>/Stimulus:<stimulus_code>+\n", ENT_QUOTES, 'UTF-8');
|
||||
$sRes .= "\n";
|
||||
|
||||
// Note: I did not use EnumCategories(), because a given class maybe found in several categories
|
||||
// Need to invent the "module", to characterize the origins of a class
|
||||
if (strlen($sModules) == 0) {
|
||||
if (strlen($sModules) == 0)
|
||||
{
|
||||
$aModules = array('bizmodel', 'core/cmdb', 'gui', 'application', 'addon/userrights');
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
$aModules = explode(', ', $sModules);
|
||||
}
|
||||
|
||||
@@ -5285,14 +5479,17 @@ abstract class MetaModel
|
||||
$sRes .= "// Note: The classes have been grouped by categories: ".implode(', ', $aModules)."\n";
|
||||
$sRes .= "//////////////////////////////////////////////////////////////////////\n";
|
||||
|
||||
foreach ($aModules as $sCategory) {
|
||||
foreach($aModules as $sCategory)
|
||||
{
|
||||
$sRes .= "//////////////////////////////////////////////////////////////////////\n";
|
||||
$sRes .= "// Classes in '<em>$sCategory</em>'\n";
|
||||
$sRes .= "//////////////////////////////////////////////////////////////////////\n";
|
||||
$sRes .= "//\n";
|
||||
$sRes .= "\n";
|
||||
foreach (self::GetClasses($sCategory) as $sClass) {
|
||||
if (!self::HasTable($sClass)) {
|
||||
foreach(self::GetClasses($sCategory) as $sClass)
|
||||
{
|
||||
if (!self::HasTable($sClass))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -6422,14 +6619,16 @@ abstract class MetaModel
|
||||
// classes have to be derived from cmdbabstract (to be editable in the UI)
|
||||
require_once(APPROOT.'/application/cmdbabstract.class.inc.php');
|
||||
|
||||
if (!defined('MODULESROOT')) {
|
||||
if (!defined('MODULESROOT'))
|
||||
{
|
||||
define('MODULESROOT', APPROOT.'env-'.self::$m_sEnvironment.'/');
|
||||
}
|
||||
|
||||
require_once(APPROOT.'core/autoload.php');
|
||||
require_once(APPROOT.'env-'.self::$m_sEnvironment.'/autoload.php');
|
||||
|
||||
foreach (self::$m_oConfig->GetAddons() as $sModule => $sToInclude) {
|
||||
foreach(self::$m_oConfig->GetAddons() as $sModule => $sToInclude)
|
||||
{
|
||||
self::IncludeModule($sToInclude, 'addons');
|
||||
}
|
||||
|
||||
@@ -6437,14 +6636,16 @@ abstract class MetaModel
|
||||
$sTablePrefix = self::$m_oConfig->Get('db_subname');
|
||||
$oKPI->ComputeAndReport('Load config');
|
||||
|
||||
if (self::$m_bUseAPCCache) {
|
||||
if (self::$m_bUseAPCCache)
|
||||
{
|
||||
$oKPI = new ExecutionKPI();
|
||||
// Note: For versions of APC older than 3.0.17, fetch() accepts only one parameter
|
||||
//
|
||||
$sOqlAPCCacheId = 'itop-'.MetaModel::GetEnvironmentId().'-metamodel';
|
||||
$result = apc_fetch($sOqlAPCCacheId);
|
||||
|
||||
if (is_array($result)) {
|
||||
if (is_array($result))
|
||||
{
|
||||
// todo - verifier que toutes les classes mentionnees ici sont chargees dans InitClasses()
|
||||
self::$m_aExtensionClassNames = $result['m_aExtensionClassNames'];
|
||||
self::$m_Category2Class = $result['m_Category2Class'];
|
||||
@@ -6455,7 +6656,8 @@ abstract class MetaModel
|
||||
self::$m_aAttribDefs = $result['m_aAttribDefs'];
|
||||
self::$m_aAttribOrigins = $result['m_aAttribOrigins'];
|
||||
self::$m_aIgnoredAttributes = $result['m_aIgnoredAttributes'];
|
||||
self::$m_aFilterAttribList = $result['m_aFilterList'];
|
||||
self::$m_aFilterDefs = $result['m_aFilterDefs'];
|
||||
self::$m_aFilterOrigins = $result['m_aFilterOrigins'];
|
||||
self::$m_aListInfos = $result['m_aListInfos'];
|
||||
self::$m_aListData = $result['m_aListData'];
|
||||
self::$m_aRelationInfos = $result['m_aRelationInfos'];
|
||||
@@ -6491,7 +6693,8 @@ abstract class MetaModel
|
||||
$aCache['m_aAttribDefs'] = self::$m_aAttribDefs; // array of ("classname" => array of attributes)
|
||||
$aCache['m_aAttribOrigins'] = self::$m_aAttribOrigins; // array of ("classname" => array of ("attcode"=>"sourceclass"))
|
||||
$aCache['m_aIgnoredAttributes'] = self::$m_aIgnoredAttributes; //array of ("classname" => array of ("attcode")
|
||||
$aCache['m_aFilterList'] = self::$m_aFilterAttribList; // array of ("classname" => array filterdef)
|
||||
$aCache['m_aFilterDefs'] = self::$m_aFilterDefs; // array of ("classname" => array filterdef)
|
||||
$aCache['m_aFilterOrigins'] = self::$m_aFilterOrigins; // array of ("classname" => array of ("attcode"=>"sourceclass"))
|
||||
$aCache['m_aListInfos'] = self::$m_aListInfos; // array of ("listcode" => various info on the list, common to every classes)
|
||||
$aCache['m_aListData'] = self::$m_aListData; // array of ("classname" => array of "listcode" => list)
|
||||
$aCache['m_aRelationInfos'] = self::$m_aRelationInfos; // array of ("relcode" => various info on the list, common to every classes)
|
||||
@@ -6789,19 +6992,6 @@ abstract class MetaModel
|
||||
}
|
||||
$sClass = $aRow[$sClassAlias."finalclass"];
|
||||
}
|
||||
|
||||
// if an object is already being updated, then this method will return this object instead of recreating a new one.
|
||||
// At this point the method DBUpdate of a new object with the same class and id won't do anything due to reentrance protection,
|
||||
// so to ensure that the potential modifications are correctly saved, the object currently being updated is returned.
|
||||
// DBUpdate() method then will take care that all the modifications will be saved.
|
||||
if (array_key_exists($sClassAlias.'id', $aRow)) {
|
||||
$iKey = $aRow[$sClassAlias."id"];
|
||||
$oObject = self::GetReentranceObject(Metamodel::REENTRANCE_TYPE_UPDATE, $sClass, $iKey);
|
||||
if ($oObject !== false) {
|
||||
return $oObject;
|
||||
}
|
||||
}
|
||||
|
||||
return new $sClass($aRow, $sClassAlias, $aAttToLoad, $aExtendedDataSpec);
|
||||
}
|
||||
|
||||
@@ -6955,28 +7145,20 @@ abstract class MetaModel
|
||||
/**
|
||||
* @param string $sClass
|
||||
* @param string $sAttCode
|
||||
* @param mixed $value
|
||||
* @param $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 \CoreUnexpectedValue
|
||||
* @throws \MissingQueryArgument
|
||||
* @throws \MySQLException
|
||||
* @throws \MySQLHasGoneAwayException
|
||||
*
|
||||
* @since 2.7.7 Add new $bAllowAllData parameter
|
||||
* @throws \Exception
|
||||
*/
|
||||
public static function GetObjectByColumn($sClass, $sAttCode, $value, $bMustBeFoundUnique = true, $bAllowAllData = false)
|
||||
public static function GetObjectByColumn($sClass, $sAttCode, $value, $bMustBeFoundUnique = true)
|
||||
{
|
||||
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)
|
||||
@@ -7029,26 +7211,30 @@ abstract class MetaModel
|
||||
*/
|
||||
public static function GetHyperLink($sTargetClass, $iKey)
|
||||
{
|
||||
if ($iKey < 0) {
|
||||
if ($iKey < 0)
|
||||
{
|
||||
return "$sTargetClass: $iKey (invalid value)";
|
||||
}
|
||||
$oObj = self::GetObject($sTargetClass, $iKey, false);
|
||||
if (is_null($oObj)) {
|
||||
if (is_null($oObj))
|
||||
{
|
||||
// Whatever we are looking for, the root class is the key to search for
|
||||
$sRootClass = self::GetRootClass($sTargetClass);
|
||||
$oSearch = DBObjectSearch::FromOQL('SELECT CMDBChangeOpDelete WHERE objclass = :objclass AND objkey = :objkey', array('objclass' => $sRootClass, 'objkey' => $iKey));
|
||||
$oSet = new DBObjectSet($oSearch);
|
||||
$oRecord = $oSet->Fetch();
|
||||
// An empty fname is obtained with iTop < 2.0
|
||||
if (is_null($oRecord) || (strlen(trim($oRecord->Get('fname'))) == 0)) {
|
||||
if (is_null($oRecord) || (strlen(trim($oRecord->Get('fname'))) == 0))
|
||||
{
|
||||
$sName = Dict::Format('Core:UnknownObjectLabel', $sTargetClass, $iKey);
|
||||
$sTitle = Dict::S('Core:UnknownObjectTip');
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
$sName = $oRecord->Get('fname');
|
||||
$sTitle = Dict::Format('Core:DeletedObjectTip', $oRecord->Get('date'), $oRecord->Get('userinfo'));
|
||||
}
|
||||
|
||||
return '<span class="itop-deleted-object" title="'.utils::EscapeHtml($sTitle).'">'.utils::EscapeHtml($sName).'</span>';
|
||||
return '<span class="itop-deleted-object" title="'.htmlentities($sTitle, ENT_QUOTES, 'UTF-8').'">'.htmlentities($sName, ENT_QUOTES, 'UTF-8').'</span>';
|
||||
}
|
||||
return $oObj->GetHyperLink();
|
||||
}
|
||||
@@ -7080,11 +7266,38 @@ abstract class MetaModel
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* Deletion of records, bypassing {@link DBObject::DBDelete} !!!
|
||||
* It is NOT recommended to use this shortcut
|
||||
* In particular, it will not work
|
||||
* - if the class is not a final class
|
||||
* - if the class has a hierarchical key (need to rebuild the indexes)
|
||||
* - if the class overload DBDelete !
|
||||
*
|
||||
* @param array $aValues array of attcode => value
|
||||
* @deprecated do not use : dead code, will be removed in the future
|
||||
* @experimental
|
||||
*
|
||||
* @param \DBObjectSearch $oFilter
|
||||
*
|
||||
* @throws \MySQLException
|
||||
* @throws \MySQLHasGoneAwayException
|
||||
* @todo: protect it against forbidden usages (in such a case, delete objects one by one)
|
||||
*
|
||||
*/
|
||||
public static function BulkDelete(DBObjectSearch $oFilter)
|
||||
{
|
||||
DeprecatedCallsLog::NotifyDeprecatedPhpMethod('do not use : dead code, will be removed in the future');
|
||||
$sSQL = $oFilter->MakeDeleteQuery();
|
||||
if (!self::DBIsReadOnly()) {
|
||||
CMDBSource::Query($sSQL);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param DBObjectSearch $oFilter
|
||||
* @param array $aValues array of attcode => value
|
||||
*
|
||||
* @deprecated do not use : dead code, will be removed in the future
|
||||
* @experimental
|
||||
* @return int Modified objects
|
||||
* @throws \MySQLException
|
||||
* @throws \MySQLHasGoneAwayException
|
||||
@@ -7560,36 +7773,6 @@ abstract class MetaModel
|
||||
/** @var AttributeEnum $oAttDef */
|
||||
return $oAttDef->GetStyle($sValue);
|
||||
}
|
||||
|
||||
protected static function GetReentranceObject($sType, $sClass, $sKey)
|
||||
{
|
||||
if (isset(self::$m_aReentranceProtection[$sType][$sClass][$sKey])) {
|
||||
return self::$m_aReentranceProtection[$sType][$sClass][$sKey];
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $sType
|
||||
* @param \DBObject $oObject
|
||||
*
|
||||
* @return bool true if reentry possible
|
||||
*/
|
||||
public static function StartReentranceProtection($sType, DBObject $oObject)
|
||||
{
|
||||
if (isset(self::$m_aReentranceProtection[$sType][get_class($oObject)][$oObject->GetKey()])) {
|
||||
return false;
|
||||
}
|
||||
self::$m_aReentranceProtection[$sType][get_class($oObject)][$oObject->GetKey()] = $oObject;
|
||||
return true;
|
||||
}
|
||||
|
||||
public static function StopReentranceProtection($sType, DBObject $oObject)
|
||||
{
|
||||
if (isset(self::$m_aReentranceProtection[$sType][get_class($oObject)][$oObject->GetKey()])) {
|
||||
unset(self::$m_aReentranceProtection[$sType][get_class($oObject)][$oObject->GetKey()]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -107,7 +107,7 @@ abstract class Expression {
|
||||
/**
|
||||
* recursive rendering
|
||||
*
|
||||
* @deprecated 3.0.0 use RenderExpression
|
||||
* @deprecated use RenderExpression
|
||||
*
|
||||
* @param array $aArgs used as input by default, or used as output if bRetrofitParams set to True
|
||||
* @param bool $bRetrofitParams
|
||||
@@ -118,7 +118,7 @@ abstract class Expression {
|
||||
public function Render(&$aArgs = null, $bRetrofitParams = false)
|
||||
{
|
||||
// cannot notify depreciation for now as this is still MASSIVELY used in iTop core !
|
||||
DeprecatedCallsLog::NotifyDeprecatedPhpMethod('use RenderExpression');
|
||||
//DeprecatedCallsLog::NotifyDeprecatedPhpMethod('use RenderExpression');
|
||||
|
||||
return $this->RenderExpression(false, $aArgs, $bRetrofitParams);
|
||||
}
|
||||
@@ -1765,7 +1765,6 @@ class FieldExpression extends UnaryExpression
|
||||
*/
|
||||
public function MakeValueLabel($oFilter, $sValue, $sDefault)
|
||||
{
|
||||
|
||||
$sAttCode = $this->GetName();
|
||||
$sParentAlias = $this->GetParent();
|
||||
|
||||
@@ -3050,7 +3049,8 @@ class FunctionExpression extends Expression
|
||||
public function MakeValueLabel($oFilter, $sValue, $sDefault)
|
||||
{
|
||||
static $aWeekDayToString = null;
|
||||
if (is_null($aWeekDayToString)) {
|
||||
if (is_null($aWeekDayToString))
|
||||
{
|
||||
// Init the correspondance table
|
||||
$aWeekDayToString = array(
|
||||
0 => Dict::S('DayOfWeek-Sunday'),
|
||||
@@ -3059,7 +3059,7 @@ class FunctionExpression extends Expression
|
||||
3 => Dict::S('DayOfWeek-Wednesday'),
|
||||
4 => Dict::S('DayOfWeek-Thursday'),
|
||||
5 => Dict::S('DayOfWeek-Friday'),
|
||||
6 => Dict::S('DayOfWeek-Saturday'),
|
||||
6 => Dict::S('DayOfWeek-Saturday')
|
||||
);
|
||||
}
|
||||
static $aMonthToString = null;
|
||||
@@ -3067,15 +3067,15 @@ class FunctionExpression extends Expression
|
||||
{
|
||||
// Init the correspondance table
|
||||
$aMonthToString = array(
|
||||
1 => Dict::S('Month-01'),
|
||||
2 => Dict::S('Month-02'),
|
||||
3 => Dict::S('Month-03'),
|
||||
4 => Dict::S('Month-04'),
|
||||
5 => Dict::S('Month-05'),
|
||||
6 => Dict::S('Month-06'),
|
||||
7 => Dict::S('Month-07'),
|
||||
8 => Dict::S('Month-08'),
|
||||
9 => Dict::S('Month-09'),
|
||||
1 => Dict::S('Month-01'),
|
||||
2 => Dict::S('Month-02'),
|
||||
3 => Dict::S('Month-03'),
|
||||
4 => Dict::S('Month-04'),
|
||||
5 => Dict::S('Month-05'),
|
||||
6 => Dict::S('Month-06'),
|
||||
7 => Dict::S('Month-07'),
|
||||
8 => Dict::S('Month-08'),
|
||||
9 => Dict::S('Month-09'),
|
||||
10 => Dict::S('Month-10'),
|
||||
11 => Dict::S('Month-11'),
|
||||
12 => Dict::S('Month-12'),
|
||||
@@ -3083,22 +3083,30 @@ class FunctionExpression extends Expression
|
||||
}
|
||||
|
||||
$sRes = $sDefault;
|
||||
if (strtolower($this->m_sVerb) == 'date_format') {
|
||||
if (strtolower($this->m_sVerb) == 'date_format')
|
||||
{
|
||||
$oFormatExpr = $this->m_aArgs[1];
|
||||
|
||||
if ($oFormatExpr->RenderExpression() == "'%w'") {
|
||||
if (isset($aWeekDayToString[(int)$sValue])) {
|
||||
if ($oFormatExpr->Render() == "'%w'")
|
||||
{
|
||||
if (isset($aWeekDayToString[(int)$sValue]))
|
||||
{
|
||||
$sRes = $aWeekDayToString[(int)$sValue];
|
||||
}
|
||||
} elseif ($oFormatExpr->RenderExpression() == "'%Y-%m'") {
|
||||
}
|
||||
elseif ($oFormatExpr->Render() == "'%Y-%m'")
|
||||
{
|
||||
// yyyy-mm => "yyyy month"
|
||||
$iMonth = (int)substr($sValue, -2); // the two last chars
|
||||
$iMonth = (int) substr($sValue, -2); // the two last chars
|
||||
$sRes = substr($sValue, 0, 4).' '.$aMonthToString[$iMonth];
|
||||
} elseif ($oFormatExpr->RenderExpression() == "'%Y-%m-%d'") {
|
||||
}
|
||||
elseif ($oFormatExpr->Render() == "'%Y-%m-%d'")
|
||||
{
|
||||
// yyyy-mm-dd => "month d"
|
||||
$iMonth = (int)substr($sValue, 5, 2);
|
||||
$iMonth = (int) substr($sValue, 5, 2);
|
||||
$sRes = $aMonthToString[$iMonth].' '.(int)substr($sValue, -2);
|
||||
} elseif ($oFormatExpr->RenderExpression() == "'%H'") {
|
||||
}
|
||||
elseif ($oFormatExpr->Render() == "'%H'")
|
||||
{
|
||||
// H => "H Hour(s)"
|
||||
$sRes = $sValue.':00';
|
||||
}
|
||||
|
||||
@@ -33,19 +33,17 @@ class OQLParser_yyToken implements ArrayAccess
|
||||
return $this->string;
|
||||
}
|
||||
|
||||
function offsetExists($offset): bool
|
||||
function offsetExists($offset)
|
||||
{
|
||||
return isset($this->metadata[$offset]);
|
||||
}
|
||||
|
||||
// Return type mixed is not supported by PHP 7.4, we can remove the following PHP attribute and add the return type once iTop min PHP version is PHP 8.0+
|
||||
#[\ReturnTypeWillChange]
|
||||
function offsetGet($offset)
|
||||
{
|
||||
return $this->metadata[$offset];
|
||||
}
|
||||
|
||||
function offsetSet($offset, $value): void
|
||||
function offsetSet($offset, $value)
|
||||
{
|
||||
if ($offset === null) {
|
||||
if (isset($value[0])) {
|
||||
@@ -68,7 +66,7 @@ class OQLParser_yyToken implements ArrayAccess
|
||||
}
|
||||
}
|
||||
|
||||
function offsetUnset($offset): void
|
||||
function offsetUnset($offset)
|
||||
{
|
||||
unset($this->metadata[$offset]);
|
||||
}
|
||||
|
||||
@@ -58,19 +58,22 @@ class OQLException extends CoreException
|
||||
|
||||
public function getHtmlDesc($sHighlightHtmlBegin = '<span style="font-weight: bolder">', $sHighlightHtmlEnd = '</span>')
|
||||
{
|
||||
$sRet = utils::EscapeHtml($this->m_MyIssue.", found '".$this->m_sUnexpected."' in: ");
|
||||
$sRet .= utils::EscapeHtml(substr($this->m_sInput, 0, $this->m_iCol));
|
||||
$sRet .= $sHighlightHtmlBegin.utils::EscapeHtml(substr($this->m_sInput, $this->m_iCol, strlen($this->m_sUnexpected))).$sHighlightHtmlEnd;
|
||||
$sRet .= utils::EscapeHtml(substr($this->m_sInput, $this->m_iCol + strlen($this->m_sUnexpected)));
|
||||
$sRet = htmlentities($this->m_MyIssue.", found '".$this->m_sUnexpected."' in: ", ENT_QUOTES, 'UTF-8');
|
||||
$sRet .= htmlentities(substr($this->m_sInput, 0, $this->m_iCol), ENT_QUOTES, 'UTF-8');
|
||||
$sRet .= $sHighlightHtmlBegin.htmlentities(substr($this->m_sInput, $this->m_iCol, strlen($this->m_sUnexpected)), ENT_QUOTES, 'UTF-8').$sHighlightHtmlEnd;
|
||||
$sRet .= htmlentities(substr($this->m_sInput, $this->m_iCol + strlen($this->m_sUnexpected)), ENT_QUOTES, 'UTF-8');
|
||||
|
||||
if (!is_null($this->m_aExpecting) && (count($this->m_aExpecting) > 0)) {
|
||||
if (count($this->m_aExpecting) < 30) {
|
||||
if (!is_null($this->m_aExpecting) && (count($this->m_aExpecting) > 0))
|
||||
{
|
||||
if (count($this->m_aExpecting) < 30)
|
||||
{
|
||||
$sExpectations = '{'.implode(', ', $this->m_aExpecting).'}';
|
||||
$sRet .= ", expecting ".utils::EscapeHtml($sExpectations);
|
||||
}
|
||||
$sRet .= ", expecting ".htmlentities($sExpectations, ENT_QUOTES, 'UTF-8');
|
||||
}
|
||||
$sSuggest = self::FindClosestString($this->m_sUnexpected, $this->m_aExpecting);
|
||||
if (strlen($sSuggest) > 0) {
|
||||
$sRet .= ", I would suggest to use '$sHighlightHtmlBegin".utils::EscapeHtml($sSuggest)."$sHighlightHtmlEnd'";
|
||||
if (strlen($sSuggest) > 0)
|
||||
{
|
||||
$sRet .= ", I would suggest to use '$sHighlightHtmlBegin".htmlentities($sSuggest, ENT_QUOTES, 'UTF-8')."$sHighlightHtmlEnd'";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -252,7 +252,7 @@ class ormCaseLog {
|
||||
if (!array_key_exists('format', $aIndex[$index]) || ($aIndex[$index]['format'] == static::ENUM_FORMAT_TEXT))
|
||||
{
|
||||
$sCSSClass = 'caselog_entry';
|
||||
$sTextEntry = str_replace(array("\r\n", "\n", "\r"), "<br/>", utils::EscapeHtml($sTextEntry));
|
||||
$sTextEntry = str_replace(array("\r\n", "\n", "\r"), "<br/>", htmlentities($sTextEntry, ENT_QUOTES, 'UTF-8'));
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -292,15 +292,19 @@ class ormCaseLog {
|
||||
}
|
||||
|
||||
// Process the case of an eventual remainder (quick migration of AttributeText fields)
|
||||
if ($iPos < (strlen($this->m_sLog) - 1)) {
|
||||
if ($iPos < (strlen($this->m_sLog) - 1))
|
||||
{
|
||||
$sTextEntry = substr($this->m_sLog, $iPos);
|
||||
$sTextEntry = str_replace(array("\r\n", "\n", "\r"), "<br/>", utils::EscapeHtml($sTextEntry));
|
||||
$sTextEntry = str_replace(array("\r\n", "\n", "\r"), "<br/>", htmlentities($sTextEntry, ENT_QUOTES, 'UTF-8'));
|
||||
|
||||
if (count($this->m_aIndex) == 0) {
|
||||
if (count($this->m_aIndex) == 0)
|
||||
{
|
||||
$sHtml .= '<div class="caselog_entry" style="'.$sStyleCaseLogEntry.'"">';
|
||||
$sHtml .= $sTextEntry;
|
||||
$sHtml .= '</div>';
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
$sHtml .= '<div class="caselog_header" style="'.$sStyleCaseLogHeader.'">';
|
||||
$sHtml .= Dict::S('UI:CaseLog:InitialValue');
|
||||
$sHtml .= '</div>';
|
||||
@@ -323,18 +327,24 @@ class ormCaseLog {
|
||||
$sHtml = '<ul class="case_log_simple_html">';
|
||||
$iPos = 0;
|
||||
$aIndex = $this->m_aIndex;
|
||||
for($index=count($aIndex)-1 ; $index >= 0 ; $index--) {
|
||||
for($index=count($aIndex)-1 ; $index >= 0 ; $index--)
|
||||
{
|
||||
$iPos += $aIndex[$index]['separator_length'];
|
||||
$sTextEntry = substr($this->m_sLog, $iPos, $aIndex[$index]['text_length']);
|
||||
$sCSSClass = 'case_log_simple_html_entry_html';
|
||||
if (!array_key_exists('format', $aIndex[$index]) || ($aIndex[$index]['format'] == static::ENUM_FORMAT_TEXT)) {
|
||||
if (!array_key_exists('format', $aIndex[$index]) || ($aIndex[$index]['format'] == static::ENUM_FORMAT_TEXT))
|
||||
{
|
||||
$sCSSClass = 'case_log_simple_html_entry';
|
||||
$sTextEntry = str_replace(array("\r\n", "\n", "\r"), "<br/>", utils::EscapeHtml($sTextEntry));
|
||||
if (!is_null($aTransfoHandler)) {
|
||||
$sTextEntry = str_replace(array("\r\n", "\n", "\r"), "<br/>", htmlentities($sTextEntry, ENT_QUOTES, 'UTF-8'));
|
||||
if (!is_null($aTransfoHandler))
|
||||
{
|
||||
$sTextEntry = call_user_func($aTransfoHandler, $sTextEntry);
|
||||
}
|
||||
} else {
|
||||
if (!is_null($aTransfoHandler)) {
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!is_null($aTransfoHandler))
|
||||
{
|
||||
$sTextEntry = call_user_func($aTransfoHandler, $sTextEntry, true /* wiki "links" only */);
|
||||
}
|
||||
$sTextEntry = InlineImage::FixUrls($sTextEntry);
|
||||
@@ -373,15 +383,19 @@ class ormCaseLog {
|
||||
}
|
||||
|
||||
// Process the case of an eventual remainder (quick migration of AttributeText fields)
|
||||
if ($iPos < (strlen($this->m_sLog) - 1)) {
|
||||
if ($iPos < (strlen($this->m_sLog) - 1))
|
||||
{
|
||||
$sTextEntry = substr($this->m_sLog, $iPos);
|
||||
$sTextEntry = str_replace(array("\r\n", "\n", "\r"), "<br/>", utils::EscapeHtml($sTextEntry));
|
||||
$sTextEntry = str_replace(array("\r\n", "\n", "\r"), "<br/>", htmlentities($sTextEntry, ENT_QUOTES, 'UTF-8'));
|
||||
|
||||
if (count($this->m_aIndex) == 0) {
|
||||
if (count($this->m_aIndex) == 0)
|
||||
{
|
||||
$sHtml .= '<li>';
|
||||
$sHtml .= $sTextEntry;
|
||||
$sHtml .= '</li>';
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
$sHtml .= '<li>';
|
||||
$sHtml .= Dict::S('UI:CaseLog:InitialValue');
|
||||
$sHtml .= '<div class="case_log_simple_html_entry" style="'.$sStyleCaseLogEntry.'">';
|
||||
@@ -423,9 +437,11 @@ class ormCaseLog {
|
||||
}
|
||||
$iPos += $aIndex[$index]['separator_length'];
|
||||
$sTextEntry = substr($this->m_sLog, $iPos, $aIndex[$index]['text_length']);
|
||||
if (!array_key_exists('format', $aIndex[$index]) || ($aIndex[$index]['format'] == static::ENUM_FORMAT_TEXT)) {
|
||||
$sTextEntry = str_replace(array("\r\n", "\n", "\r"), "<br/>", utils::EscapeHtml($sTextEntry));
|
||||
if (!is_null($aTransfoHandler)) {
|
||||
if (!array_key_exists('format', $aIndex[$index]) || ($aIndex[$index]['format'] == static::ENUM_FORMAT_TEXT))
|
||||
{
|
||||
$sTextEntry = str_replace(array("\r\n", "\n", "\r"), "<br/>", htmlentities($sTextEntry, ENT_QUOTES, 'UTF-8'));
|
||||
if (!is_null($aTransfoHandler))
|
||||
{
|
||||
$sTextEntry = call_user_func($aTransfoHandler, $sTextEntry);
|
||||
}
|
||||
}
|
||||
@@ -467,16 +483,19 @@ class ormCaseLog {
|
||||
$oBlock->AddSubBlock($oCollapsibleBlock);
|
||||
}
|
||||
// Process the case of an eventual remainder (quick migration of AttributeText fields)
|
||||
if ($iPos < (strlen($this->m_sLog) - 1)) {
|
||||
if ($iPos < (strlen($this->m_sLog) - 1))
|
||||
{
|
||||
// In this case the format is always "text"
|
||||
$sTextEntry = substr($this->m_sLog, $iPos);
|
||||
$sTextEntry = str_replace(array("\r\n", "\n", "\r"), "<br/>", utils::EscapeHtml($sTextEntry));
|
||||
if (!is_null($aTransfoHandler)) {
|
||||
$sTextEntry = str_replace(array("\r\n", "\n", "\r"), "<br/>", htmlentities($sTextEntry, ENT_QUOTES, 'UTF-8'));
|
||||
if (!is_null($aTransfoHandler))
|
||||
{
|
||||
$sTextEntry = call_user_func($aTransfoHandler, $sTextEntry);
|
||||
}
|
||||
|
||||
if (count($this->m_aIndex) == 0) {
|
||||
$oCollapsibleBlock = CollapsibleSectionUIBlockFactory::MakeStandard('');
|
||||
if (count($this->m_aIndex) == 0)
|
||||
{
|
||||
$oCollapsibleBlock = CollapsibleSectionUIBlockFactory::MakeStandard( '');
|
||||
$oCollapsibleBlock->AddSubBlock(new Html($sTextEntry));
|
||||
$oCollapsibleBlock->SetOpenedByDefault(true);
|
||||
$oBlock->AddSubBlock($oCollapsibleBlock);
|
||||
|
||||
@@ -25,9 +25,6 @@
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
use Combodo\iTop\Service\EventData;
|
||||
use Combodo\iTop\Service\EventService;
|
||||
|
||||
|
||||
/**
|
||||
* ormDocument
|
||||
@@ -112,14 +109,17 @@ class ormDocument
|
||||
public function GetAsHTML()
|
||||
{
|
||||
$sResult = '';
|
||||
if ($this->IsEmpty()) {
|
||||
if ($this->IsEmpty())
|
||||
{
|
||||
// If the filename is not empty, display it, this is used
|
||||
// by the creation wizard while the file has not yet been uploaded
|
||||
$sResult = utils::EscapeHtml($this->GetFileName());
|
||||
} else {
|
||||
$sResult = htmlentities($this->GetFileName(), ENT_QUOTES, 'UTF-8');
|
||||
}
|
||||
else
|
||||
{
|
||||
$data = $this->GetData();
|
||||
$sSize = utils::BytesToFriendlyFormat(strlen($data));
|
||||
$sResult = utils::EscapeHtml($this->GetFileName()).' ('.$sSize.')<br/>';
|
||||
$sResult = htmlentities($this->GetFileName(), ENT_QUOTES, 'UTF-8').' ('.$sSize.')<br/>';
|
||||
}
|
||||
return $sResult;
|
||||
}
|
||||
@@ -131,8 +131,7 @@ class ormDocument
|
||||
public function GetDisplayLink($sClass, $Id, $sAttCode)
|
||||
{
|
||||
$sUrl = $this->GetDisplayURL($sClass, $Id, $sAttCode);
|
||||
|
||||
return "<a href=\"$sUrl\" target=\"_blank\" >".utils::EscapeHtml($this->GetFileName())."</a>\n";
|
||||
return "<a href=\"$sUrl\" target=\"_blank\" >".htmlentities($this->GetFileName(), ENT_QUOTES, 'UTF-8')."</a>\n";
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -142,8 +141,7 @@ class ormDocument
|
||||
public function GetDownloadLink($sClass, $Id, $sAttCode)
|
||||
{
|
||||
$sUrl = $this->GetDownloadURL($sClass, $Id, $sAttCode);
|
||||
|
||||
return "<a href=\"$sUrl\">".utils::EscapeHtml($this->GetFileName())."</a>\n";
|
||||
return "<a href=\"$sUrl\">".htmlentities($this->GetFileName(), ENT_QUOTES, 'UTF-8')."</a>\n";
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -196,6 +194,7 @@ class ormDocument
|
||||
* @param string $sContentDisposition Either 'inline' or 'attachment'
|
||||
* @param string $sSecretField The attcode of the field containing a "secret" to be provided in order to retrieve the file
|
||||
* @param string $sSecretValue The value of the secret to be compared with the value of the attribute $sSecretField
|
||||
* @return none
|
||||
*/
|
||||
public static function DownloadDocument(WebPage $oPage, $sClass, $id, $sAttCode, $sContentDisposition = 'attachment', $sSecretField = null, $sSecretValue = null)
|
||||
{
|
||||
@@ -214,12 +213,6 @@ class ormDocument
|
||||
$oDocument = $oObj->Get($sAttCode);
|
||||
if (is_object($oDocument))
|
||||
{
|
||||
$aEventData = array(
|
||||
'debug_info' => $oDocument->GetFileName(),
|
||||
'object' => $oObj,
|
||||
'document' => $oDocument,
|
||||
);
|
||||
EventService::FireEvent(new EventData(EVENT_SERVICE_DOWNLOAD_DOCUMENT, $sClass, $aEventData));
|
||||
$oPage->TrashUnexpectedOutput();
|
||||
$oPage->SetContentType($oDocument->GetMimeType());
|
||||
$oPage->SetContentDisposition($sContentDisposition,$oDocument->GetFileName());
|
||||
|
||||
@@ -153,7 +153,8 @@ class ormLinkSet implements iDBObjectSetIterator, Iterator, SeekableIterator
|
||||
*/
|
||||
public function AddObject(DBObject $oObject, $sClassAlias = '')
|
||||
{
|
||||
DeprecatedCallsLog::NotifyDeprecatedPhpMethod('use \ormLinkSet::AddItem() instead');
|
||||
// cannot notify depreciation for now as this is still MASSIVELY used in iTop core !
|
||||
//DeprecatedCallsLog::NotifyDeprecatedPhpMethod('use \ormLinkSet::AddItem() instead');
|
||||
$this->AddItem($oObject);
|
||||
}
|
||||
|
||||
@@ -311,7 +312,7 @@ class ormLinkSet implements iDBObjectSetIterator, Iterator, SeekableIterator
|
||||
* @throws \CoreUnexpectedValue
|
||||
* @throws \MySQLException
|
||||
*/
|
||||
public function Count(): int
|
||||
public function Count()
|
||||
{
|
||||
$this->LoadOriginalIds();
|
||||
$iRet = count($this->aPreserved) + count($this->aAdded) + count($this->aModified);
|
||||
@@ -326,7 +327,7 @@ class ormLinkSet implements iDBObjectSetIterator, Iterator, SeekableIterator
|
||||
* @throws Exception
|
||||
* @internal param int $iRow
|
||||
*/
|
||||
public function Seek($iPosition): void
|
||||
public function Seek($iPosition)
|
||||
{
|
||||
$this->LoadOriginalIds();
|
||||
|
||||
@@ -374,8 +375,6 @@ class ormLinkSet implements iDBObjectSetIterator, Iterator, SeekableIterator
|
||||
* @throws \MySQLException
|
||||
* @throws \MySQLHasGoneAwayException
|
||||
*/
|
||||
// Return type mixed is not supported by PHP 7.4, we can remove the following PHP attribute and add the return type once iTop min PHP version is PHP 8.0+
|
||||
#[\ReturnTypeWillChange]
|
||||
public function current()
|
||||
{
|
||||
$this->LoadOriginalIds();
|
||||
@@ -383,8 +382,9 @@ class ormLinkSet implements iDBObjectSetIterator, Iterator, SeekableIterator
|
||||
$iPreservedCount = count($this->aPreserved);
|
||||
if ($this->iCursor < $iPreservedCount)
|
||||
{
|
||||
$sId = key($this->aPreserved);
|
||||
$oRet = MetaModel::GetObject($this->sClass, $sId);
|
||||
$iRet = current($this->aPreserved);
|
||||
$this->oOriginalSet->Seek($iRet);
|
||||
$oRet = $this->oOriginalSet->Fetch();
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -410,7 +410,7 @@ class ormLinkSet implements iDBObjectSetIterator, Iterator, SeekableIterator
|
||||
* @throws \CoreUnexpectedValue
|
||||
* @throws \MySQLException
|
||||
*/
|
||||
public function next(): void
|
||||
public function next()
|
||||
{
|
||||
$this->LoadOriginalIds();
|
||||
|
||||
@@ -440,8 +440,6 @@ class ormLinkSet implements iDBObjectSetIterator, Iterator, SeekableIterator
|
||||
* @link http://php.net/manual/en/iterator.key.php
|
||||
* @return mixed scalar on success, or null on failure.
|
||||
*/
|
||||
// Return type mixed is not supported by PHP 7.4, we can remove the following PHP attribute and add the return type once iTop min PHP version is PHP 8.0+
|
||||
#[\ReturnTypeWillChange]
|
||||
public function key()
|
||||
{
|
||||
return $this->iCursor;
|
||||
@@ -457,7 +455,7 @@ class ormLinkSet implements iDBObjectSetIterator, Iterator, SeekableIterator
|
||||
* @throws \CoreUnexpectedValue
|
||||
* @throws \MySQLException
|
||||
*/
|
||||
public function valid(): bool
|
||||
public function valid()
|
||||
{
|
||||
$this->LoadOriginalIds();
|
||||
|
||||
@@ -475,7 +473,7 @@ class ormLinkSet implements iDBObjectSetIterator, Iterator, SeekableIterator
|
||||
* @throws \CoreUnexpectedValue
|
||||
* @throws \MySQLException
|
||||
*/
|
||||
public function rewind(): void
|
||||
public function rewind()
|
||||
{
|
||||
$this->LoadOriginalIds();
|
||||
|
||||
@@ -608,32 +606,16 @@ class ormLinkSet implements iDBObjectSetIterator, Iterator, SeekableIterator
|
||||
$aAdded = $this->aAdded;
|
||||
$aModified = $this->aModified;
|
||||
$aRemoved = array();
|
||||
if (count($this->aRemoved) > 0) {
|
||||
if (count($this->aRemoved) > 0)
|
||||
{
|
||||
$oSearch = new DBObjectSearch($this->sClass);
|
||||
$oSearch->AddCondition('id', $this->aRemoved, 'IN');
|
||||
$oSet = new DBObjectSet($oSearch);
|
||||
$aRemoved = $oSet->ToArray();
|
||||
}
|
||||
|
||||
return array_merge($aAdded, $aModified, $aRemoved);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the list of all modified (added, modified and removed) links
|
||||
*
|
||||
* @return array of link objects
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function GetModified($sExtKeyToMe)
|
||||
{
|
||||
$aModified = [];
|
||||
foreach ($this->aModified as $oObj) {
|
||||
$aModified[$oObj->GetKey()] = $oObj->Get($sExtKeyToMe);
|
||||
}
|
||||
|
||||
return $aModified;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param DBObject $oHostObject
|
||||
*
|
||||
@@ -677,7 +659,8 @@ class ormLinkSet implements iDBObjectSetIterator, Iterator, SeekableIterator
|
||||
{
|
||||
$aCheckLinks[] = $iLinkId;
|
||||
}
|
||||
foreach ($this->aModified as $iLinkId => $oLink) {
|
||||
foreach ($this->aModified as $iLinkId => $oLink)
|
||||
{
|
||||
$aCheckLinks[] = $oLink->GetKey();
|
||||
}
|
||||
|
||||
@@ -713,7 +696,8 @@ class ormLinkSet implements iDBObjectSetIterator, Iterator, SeekableIterator
|
||||
|
||||
// Write the links according to the existing links
|
||||
//
|
||||
foreach ($this->aAdded as $oLink) {
|
||||
foreach ($this->aAdded as $oLink)
|
||||
{
|
||||
// Make sure that the objects in the set point to "this"
|
||||
$oLink->Set($sExtKeyToMe, $oHostObject->GetKey());
|
||||
|
||||
@@ -749,7 +733,6 @@ class ormLinkSet implements iDBObjectSetIterator, Iterator, SeekableIterator
|
||||
$oLink->DBClone();
|
||||
}
|
||||
}
|
||||
$oLink->SetLinkHostObject($oHostObject);
|
||||
$oLink->DBWrite();
|
||||
|
||||
$this->aPreserved[$oLink->GetKey()] = $oLink;
|
||||
|
||||
@@ -66,7 +66,7 @@ class ormPassword
|
||||
|
||||
public function IsEmpty()
|
||||
{
|
||||
return ($this->m_hashed == null);
|
||||
return utils::IsNullOrEmptyString($this->m_sHashed);
|
||||
}
|
||||
|
||||
public function GetHash()
|
||||
|
||||
@@ -242,7 +242,7 @@ class ormStopWatch
|
||||
foreach ($aProperties as $sProperty => $sValue)
|
||||
{
|
||||
$sRes .= "<TR>";
|
||||
$sCell = str_replace("\n", "<br>\n", $sValue ?? '');
|
||||
$sCell = str_replace("\n", "<br>\n", $sValue);
|
||||
$sRes .= "<TD class=\"label\">$sProperty</TD><TD>$sCell</TD>";
|
||||
$sRes .= "</TR>";
|
||||
}
|
||||
@@ -596,9 +596,10 @@ class CheckStopWatchThresholds implements iBackgroundProcess
|
||||
$oSW = $oObj->Get($sAttCode);
|
||||
$oSW->MarkThresholdAsTriggered($iThreshold);
|
||||
$oObj->Set($sAttCode, $oSW);
|
||||
|
||||
if ($oObj->IsModified()) {
|
||||
CMDBObject::SetCurrentChangeFromParams("Automatic - threshold triggered");
|
||||
|
||||
if($oObj->IsModified())
|
||||
{
|
||||
CMDBObject::SetTrackInfo("Automatic - threshold triggered");
|
||||
|
||||
$oObj->DBUpdate();
|
||||
}
|
||||
|
||||
@@ -21,6 +21,19 @@ use Combodo\iTop\Application\UI\Base\Layout\MultiColumn\MultiColumnUIBlockFactor
|
||||
*/
|
||||
class PDFBulkExport extends HTMLBulkExport
|
||||
{
|
||||
/**
|
||||
* @var string For sample purposes
|
||||
* @internal
|
||||
* @since 2.7.8
|
||||
*/
|
||||
const ENUM_OUTPUT_TYPE_SAMPLE = 'sample';
|
||||
/**
|
||||
* @var string For the real export
|
||||
* @internal
|
||||
* @since 2.7.8
|
||||
*/
|
||||
const ENUM_OUTPUT_TYPE_REAL = 'real';
|
||||
|
||||
public function DisplayUsage(Page $oP)
|
||||
{
|
||||
$oP->p(" * pdf format options:");
|
||||
@@ -62,7 +75,7 @@ class PDFBulkExport extends HTMLBulkExport
|
||||
$aPossibleFormat = ['A3', 'A4', 'Letter'];
|
||||
$sDefaultFormat = 'A4';
|
||||
foreach ($aPossibleFormat as $sVal) {
|
||||
$oSelectFormat->AddSubBlock(SelectOptionUIBlockFactory::MakeForSelectOption($sVal, utils::EscapeHtml(Dict::S('Core:BulkExport:PageSize-'.$sVal)), ($sVal == $sDefaultFormat)));
|
||||
$oSelectFormat->AddSubBlock(SelectOptionUIBlockFactory::MakeForSelectOption($sVal, htmlentities(Dict::S('Core:BulkExport:PageSize-'.$sVal), ENT_QUOTES, 'UTF-8'), ($sVal == $sDefaultFormat)));
|
||||
}
|
||||
$oFieldSetFormat->AddSubBlock(new Html('</br>'));
|
||||
|
||||
@@ -75,7 +88,7 @@ class PDFBulkExport extends HTMLBulkExport
|
||||
$aPossibleOrientation = ['P', 'L'];
|
||||
$sDefaultOrientation = 'L';
|
||||
foreach ($aPossibleOrientation as $sVal) {
|
||||
$oSelectOrientation->AddSubBlock(SelectOptionUIBlockFactory::MakeForSelectOption($sVal, utils::EscapeHtml(Dict::S('Core:BulkExport:PageOrientation-'.$sVal)), ($sVal == $sDefaultOrientation)));
|
||||
$oSelectOrientation->AddSubBlock(SelectOptionUIBlockFactory::MakeForSelectOption($sVal, htmlentities(Dict::S('Core:BulkExport:PageOrientation-'.$sVal), ENT_QUOTES, 'UTF-8'), ($sVal == $sDefaultOrientation)));
|
||||
}
|
||||
|
||||
//date format
|
||||
@@ -84,8 +97,8 @@ class PDFBulkExport extends HTMLBulkExport
|
||||
|
||||
$sDateTimeFormat = utils::ReadParam('date_format', (string)AttributeDateTime::GetFormat(), true, 'raw_data');
|
||||
|
||||
$sDefaultFormat = utils::EscapeHtml((string)AttributeDateTime::GetFormat());
|
||||
$sExample = utils::EscapeHtml(date((string)AttributeDateTime::GetFormat()));
|
||||
$sDefaultFormat = htmlentities((string)AttributeDateTime::GetFormat(), ENT_QUOTES, 'UTF-8');
|
||||
$sExample = htmlentities(date((string)AttributeDateTime::GetFormat()), ENT_QUOTES, 'UTF-8');
|
||||
$oRadioDefault = InputUIBlockFactory::MakeForInputWithLabel(Dict::Format('Core:BulkExport:DateTimeFormatDefault_Example', $sDefaultFormat, $sExample), "pdf_date_format_radio", "default", "pdf_date_time_format_default", "radio");
|
||||
$oRadioDefault->GetInput()->SetIsChecked(($sDateTimeFormat == (string)AttributeDateTime::GetFormat()));
|
||||
$oRadioDefault->SetBeforeInput(false);
|
||||
@@ -93,7 +106,7 @@ class PDFBulkExport extends HTMLBulkExport
|
||||
$oFieldSetDate->AddSubBlock($oRadioDefault);
|
||||
$oFieldSetDate->AddSubBlock(new Html('</br>'));
|
||||
|
||||
$sFormatInput = '<input type="text" size="15" name="date_format" id="pdf_custom_date_time_format" title="" value="'.utils::EscapeHtml($sDateTimeFormat).'"/>';
|
||||
$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());
|
||||
@@ -197,46 +210,46 @@ EOF
|
||||
return $sPDF;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
* @since 2.7.8
|
||||
*/
|
||||
protected function GetSampleData($oObj, $sAttCode)
|
||||
{
|
||||
if ($sAttCode !== 'id')
|
||||
{
|
||||
$oAttDef = MetaModel::GetAttributeDef(get_class($oObj), $sAttCode);
|
||||
|
||||
// As sample data will be displayed in the web browser, AttributeImage needs to be rendered with a regular HTML format, meaning its "src" looking like "data:image/png;base64,iVBORw0KGgoAAAANSUh..."
|
||||
// Whereas for the PDF generation it needs to be rendered with a TCPPDF-compatible format, meaning its "src" looking like "@iVBORw0KGgoAAAANSUh..."
|
||||
if ($oAttDef instanceof AttributeImage) {
|
||||
return $this->GetAttributeImageValue($oObj, $sAttCode, static::ENUM_OUTPUT_TYPE_SAMPLE);
|
||||
}
|
||||
}
|
||||
return parent::GetSampleData($oObj, $sAttCode);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \DBObject $oObj
|
||||
* @param string $sAttCode
|
||||
*
|
||||
* @return int|string
|
||||
* @throws \Exception
|
||||
*/
|
||||
protected function GetValue($oObj, $sAttCode)
|
||||
{
|
||||
switch($sAttCode)
|
||||
{
|
||||
switch ($sAttCode) {
|
||||
case 'id':
|
||||
$sRet = parent::GetValue($oObj, $sAttCode);
|
||||
break;
|
||||
|
||||
default:
|
||||
$value = $oObj->Get($sAttCode);
|
||||
if ($value instanceof ormDocument)
|
||||
{
|
||||
if ($value instanceof ormDocument) {
|
||||
$oAttDef = MetaModel::GetAttributeDef(get_class($oObj), $sAttCode);
|
||||
if ($oAttDef instanceof AttributeImage)
|
||||
{
|
||||
// To limit the image size in the PDF output, we have to enforce the size as height/width because max-width/max-height have no effect
|
||||
//
|
||||
$iDefaultMaxWidthPx = 48;
|
||||
$iDefaultMaxHeightPx = 48;
|
||||
if ($value->IsEmpty())
|
||||
{
|
||||
$iNewWidth = $iDefaultMaxWidthPx;
|
||||
$iNewHeight = $iDefaultMaxHeightPx;
|
||||
|
||||
$sUrl = $oAttDef->Get('default_image');
|
||||
}
|
||||
else
|
||||
{
|
||||
list($iWidth, $iHeight) = utils::GetImageSize($value->GetData());
|
||||
$iMaxWidthPx = min($iDefaultMaxWidthPx, $oAttDef->Get('display_max_width'));
|
||||
$iMaxHeightPx = min($iDefaultMaxHeightPx, $oAttDef->Get('display_max_height'));
|
||||
|
||||
$fScale = min($iMaxWidthPx / $iWidth, $iMaxHeightPx / $iHeight);
|
||||
$iNewWidth = $iWidth * $fScale;
|
||||
$iNewHeight = $iHeight * $fScale;
|
||||
|
||||
$sUrl = 'data:'.$value->GetMimeType().';base64,'.base64_encode($value->GetData());
|
||||
}
|
||||
$sRet = ($sUrl !== null) ? '<img src="'.$sUrl.'" style="width: '.$iNewWidth.'px; height: '.$iNewHeight.'px">' : '';
|
||||
$sRet = '<div class="ibo-input-image--image-view">'.$sRet.'</div>';
|
||||
$sRet = $this->GetAttributeImageValue($oObj, $sAttCode, static::ENUM_OUTPUT_TYPE_REAL);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -251,6 +264,76 @@ EOF
|
||||
return $sRet;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \DBObject $oObj
|
||||
* @param string $sAttCode
|
||||
* @param string $sOutputType {@see \PDFBulkExport::ENUM_OUTPUT_TYPE_SAMPLE}, {@see \PDFBulkExport::ENUM_OUTPUT_TYPE_REAL}
|
||||
*
|
||||
* @return string Rendered value of $oAttDef / $oValue according to the desired $sOutputType
|
||||
* @throws \ArchivedObjectException
|
||||
* @throws \CoreException
|
||||
*
|
||||
* @since 2.7.8 N°2244 method creation
|
||||
* @since 2.7.9 N°5588 signature change to get the object so that we can log all the needed information
|
||||
*/
|
||||
protected function GetAttributeImageValue(DBObject $oObj, string $sAttCode, string $sOutputType)
|
||||
{
|
||||
$oValue = $oObj->Get($sAttCode);
|
||||
$oAttDef = MetaModel::GetAttributeDef(get_class($oObj), $sAttCode);
|
||||
|
||||
// To limit the image size in the PDF output, we have to enforce the size as height/width because max-width/max-height have no effect
|
||||
//
|
||||
$iDefaultMaxWidthPx = 48;
|
||||
$iDefaultMaxHeightPx = 48;
|
||||
if ($oValue->IsEmpty()) {
|
||||
$iNewWidth = $iDefaultMaxWidthPx;
|
||||
$iNewHeight = $iDefaultMaxHeightPx;
|
||||
|
||||
$sUrl = $oAttDef->Get('default_image');
|
||||
} else {
|
||||
$iMaxWidthPx = min($iDefaultMaxWidthPx, $oAttDef->Get('display_max_width'));
|
||||
$iMaxHeightPx = min($iDefaultMaxHeightPx, $oAttDef->Get('display_max_height'));
|
||||
|
||||
list($iWidth, $iHeight) = utils::GetImageSize($oValue->GetData());
|
||||
if ((is_null($iWidth)) || (is_null($iHeight)) || ($iWidth === 0) || ($iHeight === 0)) {
|
||||
// Avoid division by zero exception (SVGs, corrupted images, ...)
|
||||
$iNewWidth = $iDefaultMaxWidthPx;
|
||||
$iNewHeight = $iDefaultMaxHeightPx;
|
||||
|
||||
$sAttCode = $oAttDef->GetCode();
|
||||
IssueLog::Warning('AttributeImage: Cannot read image size', LogChannels::EXPORT, [
|
||||
'ObjClass' => get_class($oObj),
|
||||
'ObjKey' => $oObj->GetKey(),
|
||||
'ObjFriendlyName' => $oObj->GetName(),
|
||||
'AttCode' => $sAttCode,
|
||||
]);
|
||||
} else {
|
||||
$fScale = min($iMaxWidthPx / $iWidth, $iMaxHeightPx / $iHeight);
|
||||
$iNewWidth = $iWidth * $fScale;
|
||||
$iNewHeight = $iHeight * $fScale;
|
||||
}
|
||||
|
||||
$sValueAsBase64 = base64_encode($oValue->GetData());
|
||||
switch ($sOutputType) {
|
||||
case static::ENUM_OUTPUT_TYPE_SAMPLE:
|
||||
$sUrl = 'data:'.$oValue->GetMimeType().';base64,'.$sValueAsBase64;
|
||||
break;
|
||||
|
||||
case static::ENUM_OUTPUT_TYPE_REAL:
|
||||
default:
|
||||
// TCPDF requires base64-encoded images to be rendered without the usual "data:<MIMETYPE>;base64" header but with an "@"
|
||||
// @link https://tcpdf.org/examples/example_009/
|
||||
$sUrl = '@'.$sValueAsBase64;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
$sRet = ($sUrl !== null) ? '<img src="'.$sUrl.'" style="width: '.$iNewWidth.'px; height: '.$iNewHeight.'px;">' : '';
|
||||
$sRet = '<div class="ibo-input-image--image-view">'.$sRet.'</div>';
|
||||
|
||||
return $sRet;
|
||||
}
|
||||
|
||||
public function GetSupportedFormats()
|
||||
{
|
||||
return array('pdf' => Dict::S('Core:BulkExport:PDFFormat'));
|
||||
|
||||
@@ -30,18 +30,40 @@
|
||||
/**
|
||||
* Element of the response formed by RestResultWithObjects
|
||||
*
|
||||
* @package REST Services
|
||||
* @package RESTExtensibilityAPI
|
||||
* @api
|
||||
*/
|
||||
class ObjectResult
|
||||
{
|
||||
/**
|
||||
* @var int
|
||||
* @api
|
||||
*/
|
||||
public $code;
|
||||
/**
|
||||
* @var string
|
||||
* @api
|
||||
*/
|
||||
public $message;
|
||||
/**
|
||||
* @var mixed|null
|
||||
* @api
|
||||
*/
|
||||
public $class;
|
||||
/**
|
||||
* @var mixed|null
|
||||
* @api
|
||||
*/
|
||||
public $key;
|
||||
/**
|
||||
* @var array
|
||||
* @api
|
||||
*/
|
||||
public $fields;
|
||||
|
||||
/**
|
||||
* Default constructor
|
||||
* @api
|
||||
*/
|
||||
public function __construct($sClass = null, $iId = null)
|
||||
{
|
||||
@@ -54,11 +76,17 @@ class ObjectResult
|
||||
|
||||
/**
|
||||
* Helper to make an output value for a given attribute
|
||||
*
|
||||
*
|
||||
* @api
|
||||
* @param DBObject $oObject The object being reported
|
||||
* @param string $sAttCode The attribute code (must be valid)
|
||||
* @param boolean $bExtendedOutput Output all of the link set attributes ?
|
||||
*
|
||||
* @return string A scalar representation of the value
|
||||
* @throws \ArchivedObjectException
|
||||
* @throws \CoreException
|
||||
* @throws \CoreUnexpectedValue
|
||||
* @throws \MySQLException
|
||||
*/
|
||||
protected function MakeResultValue(DBObject $oObject, $sAttCode, $bExtendedOutput = false)
|
||||
{
|
||||
@@ -112,11 +140,17 @@ class ObjectResult
|
||||
|
||||
/**
|
||||
* Report the value for the given object attribute
|
||||
*
|
||||
*
|
||||
* @api
|
||||
* @param DBObject $oObject The object being reported
|
||||
* @param string $sAttCode The attribute code (must be valid)
|
||||
* @param boolean $bExtendedOutput Output all of the link set attributes ?
|
||||
*
|
||||
* @return void
|
||||
* @throws \ArchivedObjectException
|
||||
* @throws \CoreException
|
||||
* @throws \CoreUnexpectedValue
|
||||
* @throws \MySQLException
|
||||
*/
|
||||
public function AddField(DBObject $oObject, $sAttCode, $bExtendedOutput = false)
|
||||
{
|
||||
@@ -129,24 +163,28 @@ class ObjectResult
|
||||
/**
|
||||
* REST response for services managing objects. Derive this structure to add information and/or constants
|
||||
*
|
||||
* @package Extensibility
|
||||
* @package REST Services
|
||||
* @package RESTExtensibilityAPI
|
||||
* @api
|
||||
*/
|
||||
class RestResultWithObjects extends RestResult
|
||||
{
|
||||
/** @var array "DBObject_class:DBObject_key" as key, {@see \ObjectResult} as value */
|
||||
public $objects;
|
||||
|
||||
/**
|
||||
* Report the given object
|
||||
*
|
||||
* @param int An error code (RestResult::OK is no issue has been found)
|
||||
*
|
||||
* @api
|
||||
* @param int $iCode An error code (RestResult::OK is no issue has been found)
|
||||
* @param string $sMessage Description of the error if any, an empty string otherwise
|
||||
* @param DBObject $oObject The object being reported
|
||||
* @param array $aFieldSpec An array of class => attribute codes (Cf. RestUtils::GetFieldList). List of the attributes to be reported.
|
||||
* @param array|null $aFieldSpec An array of class => attribute codes (Cf. RestUtils::GetFieldList). List of the attributes to be reported.
|
||||
* @param boolean $bExtendedOutput Output all of the link set attributes ?
|
||||
*
|
||||
* @return void
|
||||
* @throws \ArchivedObjectException
|
||||
* @throws \CoreException
|
||||
* @throws \CoreUnexpectedValue
|
||||
* @throws \MySQLException
|
||||
*/
|
||||
public function AddObject($iCode, $sMessage, $oObject, $aFieldSpec = null, $bExtendedOutput = false)
|
||||
{
|
||||
@@ -184,16 +222,30 @@ class RestResultWithObjects extends RestResult
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @package RESTExtensibilityAPI
|
||||
* @api
|
||||
*/
|
||||
class RestResultWithRelations extends RestResultWithObjects
|
||||
{
|
||||
public $relations;
|
||||
|
||||
|
||||
/**
|
||||
* @api
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
$this->relations = array();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $sSrcKey
|
||||
* @param $sDestKey
|
||||
*
|
||||
* @return void
|
||||
* @api
|
||||
*/
|
||||
public function AddRelation($sSrcKey, $sDestKey)
|
||||
{
|
||||
if (!array_key_exists($sSrcKey, $this->relations))
|
||||
@@ -207,7 +259,7 @@ class RestResultWithRelations extends RestResultWithObjects
|
||||
/**
|
||||
* Deletion result codes for a target object (either deleted or updated)
|
||||
*
|
||||
* @package Extensibility
|
||||
* @package RESTExtensibilityAPI
|
||||
* @api
|
||||
* @since 2.0.1
|
||||
*/
|
||||
@@ -215,30 +267,37 @@ class RestDelete
|
||||
{
|
||||
/**
|
||||
* Result: Object deleted as per the initial request
|
||||
* @api
|
||||
*/
|
||||
const OK = 0;
|
||||
/**
|
||||
* Result: general issue (user rights or ... ?)
|
||||
* Result: general issue (user rights or ... ?)
|
||||
* @api
|
||||
*/
|
||||
const ISSUE = 1;
|
||||
/**
|
||||
* Result: Must be deleted to preserve database integrity
|
||||
* Result: Must be deleted to preserve database integrity
|
||||
* @api
|
||||
*/
|
||||
const AUTO_DELETE = 2;
|
||||
/**
|
||||
* Result: Must be deleted to preserve database integrity, but that is NOT possible
|
||||
* Result: Must be deleted to preserve database integrity, but that is NOT possible
|
||||
* @api
|
||||
*/
|
||||
const AUTO_DELETE_ISSUE = 3;
|
||||
/**
|
||||
* Result: Must be deleted to preserve database integrity, but this must be requested explicitely
|
||||
* Result: Must be deleted to preserve database integrity, but this must be requested explicitly
|
||||
* @api
|
||||
*/
|
||||
const REQUEST_EXPLICITELY = 4;
|
||||
/**
|
||||
* Result: Must be updated to preserve database integrity
|
||||
* @api
|
||||
*/
|
||||
const AUTO_UPDATE = 5;
|
||||
/**
|
||||
* Result: Must be updated to preserve database integrity, but that is NOT possible
|
||||
* @api
|
||||
*/
|
||||
const AUTO_UPDATE_ISSUE = 6;
|
||||
}
|
||||
@@ -575,7 +634,7 @@ class CoreServices implements iRestServiceProvider
|
||||
$oObject = $oElement->GetProperty('object');
|
||||
if ($oObject)
|
||||
{
|
||||
if ($bEnableRedundancy)
|
||||
if ($bEnableRedundancy && $sDirection == 'down')
|
||||
{
|
||||
// Add only the "reached" objects
|
||||
if ($oElement->GetProperty('is_reached'))
|
||||
|
||||
@@ -745,30 +745,26 @@ class RelationTypeIterator implements Iterator
|
||||
}
|
||||
}
|
||||
|
||||
public function rewind(): void
|
||||
public function rewind()
|
||||
{
|
||||
$this->iCurrentIdx = 0;
|
||||
}
|
||||
|
||||
public function valid(): bool
|
||||
public function valid()
|
||||
{
|
||||
return array_key_exists($this->iCurrentIdx, $this->aList);
|
||||
}
|
||||
|
||||
public function next(): void
|
||||
public function next()
|
||||
{
|
||||
$this->iCurrentIdx++;
|
||||
}
|
||||
|
||||
// Return type mixed is not supported by PHP 7.4, we can remove the following PHP attribute and add the return type once iTop min PHP version is PHP 8.0+
|
||||
#[\ReturnTypeWillChange]
|
||||
public function current()
|
||||
{
|
||||
return $this->aList[$this->iCurrentIdx];
|
||||
}
|
||||
|
||||
// Return type mixed is not supported by PHP 7.4, we can remove the following PHP attribute and add the return type once iTop min PHP version is PHP 8.0+
|
||||
#[\ReturnTypeWillChange]
|
||||
public function key()
|
||||
{
|
||||
return $this->iCurrentIdx;
|
||||
|
||||
@@ -73,8 +73,8 @@ class SpreadsheetBulkExport extends TabularBulkExport
|
||||
|
||||
$sDateTimeFormat = utils::ReadParam('date_format', (string)AttributeDateTime::GetFormat(), true, 'raw_data');
|
||||
|
||||
$sDefaultFormat = utils::EscapeHtml((string)AttributeDateTime::GetFormat());
|
||||
$sExample = utils::EscapeHtml(date((string)AttributeDateTime::GetFormat()));
|
||||
$sDefaultFormat = htmlentities((string)AttributeDateTime::GetFormat(), ENT_QUOTES, 'UTF-8');
|
||||
$sExample = htmlentities(date((string)AttributeDateTime::GetFormat()), ENT_QUOTES, 'UTF-8');
|
||||
$oRadioDefault = InputUIBlockFactory::MakeForInputWithLabel(Dict::Format('Core:BulkExport:DateTimeFormatDefault_Example', $sDefaultFormat, $sExample), "spreadsheet_date_format_radio", "default", "spreadsheet_date_time_format_default", "radio");
|
||||
$oRadioDefault->GetInput()->SetIsChecked(($sDateTimeFormat == (string)AttributeDateTime::GetFormat()));
|
||||
$oRadioDefault->GetInput()->AddCSSClass('ibo-input-checkbox');
|
||||
@@ -82,7 +82,7 @@ class SpreadsheetBulkExport extends TabularBulkExport
|
||||
$oFieldSetDate->AddSubBlock($oRadioDefault);
|
||||
$oFieldSetDate->AddSubBlock(new Html('</br>'));
|
||||
|
||||
$sFormatInput = '<input type="text" size="15" name="date_format" id="spreadsheet_custom_date_time_format" title="" value="'.utils::EscapeHtml($sDateTimeFormat).'"/>';
|
||||
$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());
|
||||
@@ -140,8 +140,7 @@ EOF
|
||||
if ($oAttDef instanceof AttributeDateTime) // AttributeDate is derived from AttributeDateTime
|
||||
{
|
||||
$sClass = (get_class($oAttDef) == 'AttributeDateTime') ? 'user-formatted-date-time' : 'user-formatted-date';
|
||||
|
||||
return '<div class="'.$sClass.'" data-date="'.$oObj->Get($sAttCode).'">'.utils::EscapeHtml($oAttDef->GetEditValue($oObj->Get($sAttCode), $oObj)).'</div>';
|
||||
return '<div class="'.$sClass.'" data-date="'.$oObj->Get($sAttCode).'">'.htmlentities($oAttDef->GetEditValue($oObj->Get($sAttCode), $oObj), ENT_QUOTES, 'UTF-8').'</div>';
|
||||
}
|
||||
}
|
||||
return $this->GetValue($oObj, $sAttCode);
|
||||
@@ -159,13 +158,19 @@ EOF
|
||||
default:
|
||||
$value = $oObj->Get($sAttCode);
|
||||
$oAttDef = MetaModel::GetAttributeDef(get_class($oObj), $sAttCode);
|
||||
if ($value instanceof ormCaseLog) {
|
||||
$sRet = str_replace("\n", "<br/>", utils::EscapeHtml($value->__toString()));
|
||||
} elseif ($value instanceof ormStopWatch) {
|
||||
if ($value instanceof ormCaseLog)
|
||||
{
|
||||
$sRet = str_replace("\n", "<br/>", htmlentities($value->__toString(), ENT_QUOTES, 'UTF-8'));
|
||||
}
|
||||
elseif ($value instanceof ormStopWatch)
|
||||
{
|
||||
$sRet = $value->GetTimeSpent();
|
||||
} elseif ($value instanceof ormDocument) {
|
||||
}
|
||||
elseif ($value instanceof ormDocument)
|
||||
{
|
||||
$sRet = '';
|
||||
} elseif ($oAttDef instanceof AttributeText)
|
||||
}
|
||||
elseif ($oAttDef instanceof AttributeText)
|
||||
{
|
||||
if ($bFormattedText)
|
||||
{
|
||||
@@ -186,11 +191,15 @@ EOF
|
||||
// Stick to the weird implementation made in GetNextChunk
|
||||
$sRet = utils::TextToHtml($oObj->GetEditValue($sAttCode));
|
||||
}
|
||||
else {
|
||||
if ($this->bLocalizeOutput) {
|
||||
$sRet = utils::EscapeHtml($oObj->GetEditValue());
|
||||
} else {
|
||||
$sRet = utils::EscapeHtml((string)$value);
|
||||
else
|
||||
{
|
||||
if ($this->bLocalizeOutput)
|
||||
{
|
||||
$sRet = htmlentities($oObj->GetEditValue(), ENT_QUOTES, 'UTF-8');
|
||||
}
|
||||
else
|
||||
{
|
||||
$sRet = htmlentities((string)$value, ENT_QUOTES, 'UTF-8');
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -305,16 +314,22 @@ EOF
|
||||
$sData .= "<td>$sDate</td>";
|
||||
$sData .= "<td>$sTime</td>";
|
||||
}
|
||||
else if (get_class($oFinalAttDef) == 'AttributeDate') {
|
||||
else if (get_class($oFinalAttDef) == 'AttributeDate')
|
||||
{
|
||||
$sDate = $oDateFormat->Format($oObj->Get($sAttCode));
|
||||
$sData .= "<td>$sDate</td>";
|
||||
} else if ($oAttDef instanceof AttributeCaseLog) {
|
||||
}
|
||||
else if($oAttDef instanceof AttributeCaseLog)
|
||||
{
|
||||
$rawValue = $oObj->Get($sAttCode);
|
||||
$sField = str_replace("\n", "<br/>", utils::EscapeHtml($rawValue->__toString()));
|
||||
$sField = str_replace("\n", "<br/>", htmlentities($rawValue->__toString(), ENT_QUOTES, 'UTF-8'));
|
||||
// Trick for Excel: treat the content as text even if it begins with an equal sign
|
||||
$sData .= "<td x:str>$sField</td>";
|
||||
} elseif ($oAttDef instanceof AttributeText) {
|
||||
if ($bFormattedText) {
|
||||
}
|
||||
elseif ($oAttDef instanceof AttributeText)
|
||||
{
|
||||
if ($bFormattedText)
|
||||
{
|
||||
// Replace paragraphs (<p...>...</p>, etc) by line breaks (<br/>) since Excel (pre-2016) splits the cells when there is a paragraph
|
||||
$sField = static::HtmlToSpreadsheet($oObj->GetAsHTML($sAttCode));
|
||||
}
|
||||
@@ -341,12 +356,16 @@ EOF
|
||||
$sField = utils::HtmlEntities($oObj->GetAsCSV($sAttCode, $this->bLocalizeOutput, ''));
|
||||
$sData .= "<td x:str>$sField</td>";
|
||||
}
|
||||
else {
|
||||
else
|
||||
{
|
||||
$rawValue = $oObj->Get($sAttCode);
|
||||
if ($this->bLocalizeOutput) {
|
||||
$sField = utils::EscapeHtml($oFinalAttDef->GetEditValue($rawValue));
|
||||
} else {
|
||||
$sField = utils::EscapeHtml($rawValue);
|
||||
if ($this->bLocalizeOutput)
|
||||
{
|
||||
$sField = htmlentities($oFinalAttDef->GetEditValue($rawValue), ENT_QUOTES, 'UTF-8');
|
||||
}
|
||||
else
|
||||
{
|
||||
$sField = htmlentities($rawValue, ENT_QUOTES, 'UTF-8');
|
||||
}
|
||||
$sData .= "<td>$sField</td>";
|
||||
}
|
||||
|
||||
@@ -250,21 +250,48 @@ abstract class TriggerOnObject extends Trigger
|
||||
public function IsTargetObject($iObjectId, $aChanges = array())
|
||||
{
|
||||
$sFilter = trim($this->Get('filter'));
|
||||
if (strlen($sFilter) > 0)
|
||||
{
|
||||
if (strlen($sFilter) > 0) {
|
||||
$oSearch = DBObjectSearch::FromOQL($sFilter);
|
||||
$oSearch->AddCondition('id', $iObjectId, '=');
|
||||
$oSearch->AllowAllData();
|
||||
$oSet = new DBObjectSet($oSearch);
|
||||
$bRet = ($oSet->Count() > 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
$bRet = true;
|
||||
}
|
||||
|
||||
return $bRet;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Exception $oException
|
||||
* @param \DBObject $oObject
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @uses \IssueLog::Error()
|
||||
*
|
||||
* @since 2.7.9 3.0.3 3.1.0 N°5893
|
||||
*/
|
||||
public function LogException($oException, $oObject)
|
||||
{
|
||||
$sObjectKey = $oObject->GetKey(); // if object wasn't persisted yet, then we'll have a negative value
|
||||
|
||||
$aContext = [
|
||||
'exception.class' => get_class($oException),
|
||||
'exception.message' => $oException->getMessage(),
|
||||
'trigger.class' => get_class($this),
|
||||
'trigger.id' => $this->GetKey(),
|
||||
'trigger.friendlyname' => $this->GetRawName(),
|
||||
'object.class' => get_class($oObject),
|
||||
'object.id' => $sObjectKey,
|
||||
'object.friendlyname' => $oObject->GetRawName(),
|
||||
'current_user' => UserRights::GetUser(),
|
||||
'exception.stack' => $oException->getTraceAsString(),
|
||||
];
|
||||
|
||||
IssueLog::Error('A trigger did throw an exception', null, $aContext);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -528,7 +528,7 @@ abstract class User extends cmdbAbstractObject
|
||||
{
|
||||
if (UserRights::IsStimulusAllowed($sClass, $sStimulusCode, null, $this))
|
||||
{
|
||||
$aStimuli[] = '<span title="'.$sStimulusCode.': '.utils::EscapeHtml($oStimulus->GetDescription()).'">'.utils::EscapeHtml($oStimulus->GetLabel()).'</span>';
|
||||
$aStimuli[] = '<span title="'.$sStimulusCode.': '.htmlentities($oStimulus->GetDescription(), ENT_QUOTES, 'UTF-8').'">'.htmlentities($oStimulus->GetLabel(), ENT_QUOTES, 'UTF-8').'</span>';
|
||||
}
|
||||
}
|
||||
$sStimuli = implode(', ', $aStimuli);
|
||||
@@ -1936,7 +1936,7 @@ class UserRights
|
||||
// The bug has been fixed in PHP 7.2, but in case session_regenerate_id()
|
||||
// fails we just silently ignore the error and keep the same session id...
|
||||
$old_error_handler = set_error_handler(array(__CLASS__, 'VoidErrorHandler'));
|
||||
session_regenerate_id(true);
|
||||
Session::RegenerateId(true);
|
||||
if ($old_error_handler !== null) {
|
||||
set_error_handler($old_error_handler);
|
||||
}
|
||||
|
||||
@@ -225,108 +225,106 @@ class ValueSetObjects extends ValueSetDefinition
|
||||
|
||||
$this->m_aValues = array();
|
||||
|
||||
if ($this->m_bAllowAllData)
|
||||
{
|
||||
$oFilter = DBObjectSearch::FromOQL_AllData($this->m_sFilterExpr);
|
||||
$oFilter = $this->GetFilter($sOperation, $sContains);
|
||||
|
||||
$oObjects = new DBObjectSet($oFilter, $this->m_aOrderBy, $aArgs, null, $this->m_iLimit, 0, $this->m_bSort);
|
||||
if (empty($this->m_sValueAttCode)) {
|
||||
$aAttToLoad = array($oFilter->GetClassAlias() => array('friendlyname'));
|
||||
} else {
|
||||
$aAttToLoad = array($oFilter->GetClassAlias() => array($this->m_sValueAttCode));
|
||||
}
|
||||
else
|
||||
{
|
||||
$oObjects->OptimizeColumnLoad($aAttToLoad);
|
||||
while ($oObject = $oObjects->Fetch()) {
|
||||
if (empty($this->m_sValueAttCode)) {
|
||||
$this->m_aValues[$oObject->GetKey()] = $oObject->GetName();
|
||||
} else {
|
||||
$this->m_aValues[$oObject->GetKey()] = $oObject->Get($this->m_sValueAttCode);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get filter for functions LoadValues and LoadValuesForAutocomplete
|
||||
*
|
||||
* @param $sOperation
|
||||
* @param $sContains
|
||||
*
|
||||
* @return \DBObjectSearch|\DBSearch|\DBUnionSearch|false|mixed
|
||||
* @throws \CoreException
|
||||
* @throws \OQLException
|
||||
* @since 3.0.3 3.1.0
|
||||
*/
|
||||
protected function GetFilter($sOperation, $sContains)
|
||||
{
|
||||
$this->m_sContains = $sContains;
|
||||
$this->m_sOperation = $sOperation;
|
||||
|
||||
if ($this->m_bAllowAllData) {
|
||||
$oFilter = DBObjectSearch::FromOQL_AllData($this->m_sFilterExpr);
|
||||
} else {
|
||||
$oFilter = DBObjectSearch::FromOQL($this->m_sFilterExpr);
|
||||
$oFilter->SetShowObsoleteData(utils::ShowObsoleteData());
|
||||
}
|
||||
if (!$oFilter) return false;
|
||||
if (!is_null($this->m_oExtraCondition))
|
||||
{
|
||||
if (!$oFilter) {
|
||||
return false;
|
||||
}
|
||||
if (!is_null($this->m_oExtraCondition)) {
|
||||
$oFilter = $oFilter->Intersect($this->m_oExtraCondition);
|
||||
}
|
||||
foreach($this->m_aModifierProperties as $sPluginClass => $aProperties)
|
||||
{
|
||||
foreach ($aProperties as $sProperty => $value)
|
||||
{
|
||||
foreach ($this->m_aModifierProperties as $sPluginClass => $aProperties) {
|
||||
foreach ($aProperties as $sProperty => $value) {
|
||||
$oFilter->SetModifierProperty($sPluginClass, $sProperty, $value);
|
||||
}
|
||||
}
|
||||
|
||||
$oExpression = DBObjectSearch::GetPolymorphicExpression($oFilter->GetClass(), 'friendlyname');
|
||||
$aFields = $oExpression->ListRequiredFields();
|
||||
$sClass = $oFilter->GetClass();
|
||||
/*foreach($aFields as $sField)
|
||||
{
|
||||
$aFieldItems = explode('.', $sField);
|
||||
if ($aFieldItems[0] != $sClass)
|
||||
{
|
||||
$sOperation = 'contains';
|
||||
break;
|
||||
}
|
||||
}*/
|
||||
|
||||
switch ($sOperation)
|
||||
{
|
||||
switch ($this->m_sOperation) {
|
||||
case 'equals':
|
||||
$aAttributes = MetaModel::GetFriendlyNameAttributeCodeList($sClass);
|
||||
$sClassAlias = $oFilter->GetClassAlias();
|
||||
$aFilters = array();
|
||||
$oValueExpr = new ScalarExpression($sContains);
|
||||
foreach($aAttributes as $sAttribute)
|
||||
{
|
||||
$oNewFilter = $oFilter->DeepClone();
|
||||
$oNameExpr = new FieldExpression($sAttribute, $sClassAlias);
|
||||
$oCondition = new BinaryExpression($oNameExpr, '=', $oValueExpr);
|
||||
$oNewFilter->AddConditionExpression($oCondition);
|
||||
$aFilters[] = $oNewFilter;
|
||||
case 'start_with':
|
||||
if ($this->m_sOperation === 'start_with') {
|
||||
$this->m_sContains .= '%';
|
||||
$sOperator = 'LIKE';
|
||||
} else {
|
||||
$sOperator = '=';
|
||||
}
|
||||
|
||||
$aAttributes = MetaModel::GetFriendlyNameAttributeCodeList($sClass);
|
||||
if (count($aAttributes) > 0) {
|
||||
$sClassAlias = $oFilter->GetClassAlias();
|
||||
$aFilters = array();
|
||||
$oValueExpr = new ScalarExpression($this->m_sContains);
|
||||
foreach ($aAttributes as $sAttribute) {
|
||||
$oNewFilter = $oFilter->DeepClone();
|
||||
$oNameExpr = new FieldExpression($sAttribute, $sClassAlias);
|
||||
$oCondition = new BinaryExpression($oNameExpr, $sOperator, $oValueExpr);
|
||||
$oNewFilter->AddConditionExpression($oCondition);
|
||||
$aFilters[] = $oNewFilter;
|
||||
}
|
||||
// Unions are much faster than OR conditions
|
||||
$oFilter = new DBUnionSearch($aFilters);
|
||||
} else {
|
||||
$oValueExpr = new ScalarExpression($this->m_sContains);
|
||||
$oNameExpr = new FieldExpression('friendlyname', $oFilter->GetClassAlias());
|
||||
$oNewCondition = new BinaryExpression($oNameExpr, $sOperator, $oValueExpr);
|
||||
$oFilter->AddConditionExpression($oNewCondition);
|
||||
}
|
||||
// Unions are much faster than OR conditions
|
||||
$oFilter = new DBUnionSearch($aFilters);
|
||||
break;
|
||||
case 'start_with':
|
||||
$aAttributes = MetaModel::GetFriendlyNameAttributeCodeList($sClass);
|
||||
$sClassAlias = $oFilter->GetClassAlias();
|
||||
$aFilters = array();
|
||||
$oValueExpr = new ScalarExpression($sContains.'%');
|
||||
foreach($aAttributes as $sAttribute)
|
||||
{
|
||||
$oNewFilter = $oFilter->DeepClone();
|
||||
$oNameExpr = new FieldExpression($sAttribute, $sClassAlias);
|
||||
$oCondition = new BinaryExpression($oNameExpr, 'LIKE', $oValueExpr);
|
||||
$oNewFilter->AddConditionExpression($oCondition);
|
||||
$aFilters[] = $oNewFilter;
|
||||
}
|
||||
// Unions are much faster than OR conditions
|
||||
$oFilter = new DBUnionSearch($aFilters);
|
||||
break;
|
||||
|
||||
default:
|
||||
$oValueExpr = new ScalarExpression('%'.$sContains.'%');
|
||||
$oValueExpr = new ScalarExpression('%'.$this->m_sContains.'%');
|
||||
$oNameExpr = new FieldExpression('friendlyname', $oFilter->GetClassAlias());
|
||||
$oNewCondition = new BinaryExpression($oNameExpr, 'LIKE', $oValueExpr);
|
||||
$oFilter->AddConditionExpression($oNewCondition);
|
||||
break;
|
||||
}
|
||||
|
||||
$oObjects = new DBObjectSet($oFilter, $this->m_aOrderBy, $aArgs, null, $this->m_iLimit, 0, $this->m_bSort);
|
||||
if (empty($this->m_sValueAttCode))
|
||||
{
|
||||
$aAttToLoad = array($oFilter->GetClassAlias() => array('friendlyname'));
|
||||
}
|
||||
else
|
||||
{
|
||||
$aAttToLoad = array($oFilter->GetClassAlias() => array($this->m_sValueAttCode));
|
||||
}
|
||||
$oObjects->OptimizeColumnLoad($aAttToLoad);
|
||||
while ($oObject = $oObjects->Fetch())
|
||||
{
|
||||
if (empty($this->m_sValueAttCode))
|
||||
{
|
||||
$this->m_aValues[$oObject->GetKey()] = $oObject->GetName();
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->m_aValues[$oObject->GetKey()] = $oObject->Get($this->m_sValueAttCode);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
return $oFilter;
|
||||
}
|
||||
|
||||
|
||||
public function GetValuesDescription()
|
||||
{
|
||||
return 'Filter: '.$this->m_sFilterExpr;
|
||||
@@ -376,73 +374,12 @@ class ValueSetObjects extends ValueSetDefinition
|
||||
*/
|
||||
protected function LoadValuesForAutocomplete($aArgs, $sContains = '', $sOperation = 'contains')
|
||||
{
|
||||
$this->m_sContains = $sContains;
|
||||
$this->m_sOperation = $sOperation;
|
||||
|
||||
$this->m_aValues = array();
|
||||
|
||||
if ($this->m_bAllowAllData) {
|
||||
$oFilter = DBObjectSearch::FromOQL_AllData($this->m_sFilterExpr);
|
||||
} else {
|
||||
$oFilter = DBObjectSearch::FromOQL($this->m_sFilterExpr);
|
||||
$oFilter->SetShowObsoleteData(utils::ShowObsoleteData());
|
||||
}
|
||||
|
||||
if (!$oFilter) {
|
||||
return false;
|
||||
}
|
||||
if (!is_null($this->m_oExtraCondition)) {
|
||||
$oFilter = $oFilter->Intersect($this->m_oExtraCondition);
|
||||
}
|
||||
foreach ($this->m_aModifierProperties as $sPluginClass => $aProperties) {
|
||||
foreach ($aProperties as $sProperty => $value) {
|
||||
$oFilter->SetModifierProperty($sPluginClass, $sProperty, $value);
|
||||
}
|
||||
}
|
||||
|
||||
//$oExpression = DBObjectSearch::GetPolymorphicExpression($oFilter->GetClass(), 'friendlyname');
|
||||
$oFilter = $this->GetFilter($sOperation, $sContains);
|
||||
$sClass = $oFilter->GetClass();
|
||||
$sClassAlias = $oFilter->GetClassAlias();
|
||||
|
||||
switch ($sOperation) {
|
||||
case 'equals':
|
||||
$aAttributes = MetaModel::GetFriendlyNameAttributeCodeList($sClass);
|
||||
$aFilters = array();
|
||||
$oValueExpr = new ScalarExpression($sContains);
|
||||
foreach ($aAttributes as $sAttribute) {
|
||||
$oNewFilter = $oFilter->DeepClone();
|
||||
$oNameExpr = new FieldExpression($sAttribute, $sClassAlias);
|
||||
$oCondition = new BinaryExpression($oNameExpr, '=', $oValueExpr);
|
||||
$oNewFilter->AddConditionExpression($oCondition);
|
||||
$aFilters[] = $oNewFilter;
|
||||
}
|
||||
// Unions are much faster than OR conditions
|
||||
$oFilter = new DBUnionSearch($aFilters);
|
||||
break;
|
||||
case 'start_with':
|
||||
$aAttributes = MetaModel::GetFriendlyNameAttributeCodeList($sClass);
|
||||
$aFilters = array();
|
||||
$oValueExpr = new ScalarExpression($sContains.'%');
|
||||
foreach($aAttributes as $sAttribute)
|
||||
{
|
||||
$oNewFilter = $oFilter->DeepClone();
|
||||
$oNameExpr = new FieldExpression($sAttribute, $sClassAlias);
|
||||
$oCondition = new BinaryExpression($oNameExpr, 'LIKE', $oValueExpr);
|
||||
$oNewFilter->AddConditionExpression($oCondition);
|
||||
$aFilters[] = $oNewFilter;
|
||||
}
|
||||
// Unions are much faster than OR conditions
|
||||
$oFilter = new DBUnionSearch($aFilters);
|
||||
break;
|
||||
|
||||
default:
|
||||
$oValueExpr = new ScalarExpression('%'.$sContains.'%');
|
||||
$oNameExpr = new FieldExpression('friendlyname', $sClassAlias);
|
||||
$oNewCondition = new BinaryExpression($oNameExpr, 'LIKE', $oValueExpr);
|
||||
$oFilter->AddConditionExpression($oNewCondition);
|
||||
break;
|
||||
}
|
||||
|
||||
$oObjects = new DBObjectSet($oFilter, $this->m_aOrderBy, $aArgs, null, $this->m_iLimit, 0, $this->m_bSort);
|
||||
if (empty($this->m_sValueAttCode)) {
|
||||
$aAttToLoad = ['friendlyname'];
|
||||
|
||||
@@ -43,3 +43,23 @@
|
||||
.ibo-svg-illustration--container > svg *[fill="#6c63ff"]{
|
||||
fill: $ibo-svg-illustration--fill;
|
||||
}
|
||||
|
||||
// N°4481 - Restore HTML tables style identical between edition and visualization
|
||||
// This is a hack to compensate missing variables in the bulma lib, PR has been made here: https://github.com/jgthms/bulma/pull/3455
|
||||
// The following can't be reset to it's original value (from the browser stylesheet), so we have to hardcode it even though it might change in future browser versions...
|
||||
.ibo-is-html-content table {
|
||||
&:not(:last-child) {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
tbody {
|
||||
tr {
|
||||
&:last-child {
|
||||
td,
|
||||
th {
|
||||
border-bottom-width: 1px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,46 +1,60 @@
|
||||
/*
|
||||
* @copyright Copyright (C) 2010-2021 Combodo SARL
|
||||
* @copyright Copyright (C) 2010-2023 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
$ibo-table-preview--header-cell--padding: $ibo-spacing-200 $ibo-spacing-600 $ibo-spacing-200 $ibo-spacing-200 !default;
|
||||
$ibo-table-preview--header-cell--background-color: $ibo-color-white-200 !default;
|
||||
$ibo-table-preview--header-cell--border-width: 1px 1px 0 !default;
|
||||
|
||||
$ibo-table-preview--body-cell--padding-x: $ibo-spacing-200 !default;
|
||||
$ibo-table-preview--body-cell--border-width: 0 1px !default;
|
||||
$ibo-table-preview--body-cell--last--border-bottom-width: 1px !default;
|
||||
|
||||
$ibo-preview-header--margin-bottom: $ibo-spacing-200 !default;
|
||||
$ibo-table-preview--remove-column--top: $ibo-spacing-300 !default;
|
||||
$ibo-table-preview--remove-column--right: $ibo-spacing-300 !default;
|
||||
$ibo-table-preview--remove-column--font-size: 8px !default;
|
||||
|
||||
$ibo-form-part-interactive-fields--margin-top: $ibo-spacing-600 !default;
|
||||
|
||||
.ibo-table-preview {
|
||||
margin-top: 20px;
|
||||
overflow-x: auto;
|
||||
|
||||
th {
|
||||
position: relative;
|
||||
padding: 5px;
|
||||
padding-right: $ibo-spacing-600;
|
||||
border-width: 1px 1px 0;
|
||||
padding: $ibo-table-preview--header-cell--padding;
|
||||
border-width: $ibo-table-preview--header-cell--border-width;
|
||||
border-style: groove groove none;
|
||||
background: $ibo-color-white-200;
|
||||
background: $ibo-table-preview--header-cell--background-color;
|
||||
}
|
||||
|
||||
td {
|
||||
padding-right: 5px;
|
||||
padding-left: 5px;
|
||||
border-width: 0 1px;
|
||||
padding-right: $ibo-table-preview--body-cell--padding-x;
|
||||
padding-left: $ibo-table-preview--body-cell--padding-x;
|
||||
border-width: $ibo-table-preview--body-cell--border-width;
|
||||
border-style: none groove;
|
||||
}
|
||||
|
||||
tr:last-child td {
|
||||
border-bottom-width: 1px;
|
||||
border-bottom-width: $ibo-table-preview--body-cell--last--border-bottom-width;
|
||||
border-bottom-style: groove;
|
||||
}
|
||||
}
|
||||
|
||||
.ibo-preview-header {
|
||||
margin-bottom: 5px;
|
||||
margin-bottom: $ibo-preview-header--margin-bottom;
|
||||
}
|
||||
.ibo-table-preview--remove-column {
|
||||
position: absolute;
|
||||
top: $ibo-spacing-300;
|
||||
right: $ibo-spacing-300;
|
||||
top: $ibo-table-preview--remove-column--top;
|
||||
right: $ibo-table-preview--remove-column--right;
|
||||
display: inline-block;
|
||||
cursor: pointer;
|
||||
font-size: 8px;
|
||||
font-size: $ibo-table-preview--remove-column--font-size;
|
||||
}
|
||||
|
||||
#form_part_interactive_fields_xlsx, #form_part_interactive_fields_csv, #form_part_interactive_fields_pdf {
|
||||
margin-top: $ibo-spacing-600;
|
||||
margin-top: $ibo-form-part-interactive-fields--margin-top;
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@ $ibo-datatable--row--background-color--is-selected: $ibo-color-primary-300 !defa
|
||||
$ibo-datatable--selection-validation-buttons-toolbar--margin-top: 10px !default;
|
||||
$ibo-list-column--max-height: 150px !default;
|
||||
|
||||
$ibo-datatable--sort-order--color: $ibo-color-orange-600 !default;
|
||||
$ibo-datatable--sort-order--color: $ibo-color-primary-600 !default;
|
||||
|
||||
$ibo-fieldsorter--selected--background-color: $ibo-color-blue-200 !default;
|
||||
|
||||
@@ -119,10 +119,6 @@ $ibo-fieldsorter--selected--background-color: $ibo-color-blue-200 !default;
|
||||
&.selected {
|
||||
background-color: $ibo-datatable--row--background-color--is-selected;
|
||||
}
|
||||
|
||||
.ibo-datatable--row-actions-toolbar{
|
||||
justify-content: end;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -253,3 +253,6 @@ $ibo-field--enable-bulk--checkbox--margin-left: $ibo-spacing-300 !default;
|
||||
margin-left: $ibo-field--enable-bulk--checkbox--margin-left;
|
||||
}
|
||||
|
||||
.ibo-input-select--action-buttons a {
|
||||
@extend %ibo-hyperlink-inherited-colors;
|
||||
}
|
||||
34
css/backoffice/pages/_csv-import.scss
vendored
34
css/backoffice/pages/_csv-import.scss
vendored
@@ -3,7 +3,14 @@
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
$ibo-csv-import--cell-message-padding:3px;
|
||||
$ibo-csv-import--cell-message--padding-top: 3px !default;
|
||||
$ibo-csv-import--cell-modified--color: $ibo-color-blue-700 !default;
|
||||
$ibo-csv-import--cell-error--color: $ibo-color-red-700 !default;
|
||||
$ibo-csv-import--row--border-color: $ibo-color-grey-400 !default;
|
||||
$ibo-csv-import--row-error--background-color: $ibo-color-red-200 !default;
|
||||
$ibo-csv-import--download-file--color: $ibo-color-primary-400 !default;
|
||||
$ibo-csv-import--download-file--font-size: 4em !default;
|
||||
$ibo-csv-import--download-file--margin: 20px !default;
|
||||
|
||||
#tabs1-import .ibo-field--label {
|
||||
max-width: 50%;
|
||||
@@ -11,32 +18,37 @@ $ibo-csv-import--cell-message-padding:3px;
|
||||
|
||||
div.ibo-csv-import--cell-modified {
|
||||
font-weight: bold;
|
||||
color: $ibo-color-blue-700;
|
||||
color: $ibo-csv-import--cell-modified--color;
|
||||
}
|
||||
|
||||
div.ibo-csv-import--cell-error {
|
||||
font-weight: bold;
|
||||
color: $ibo-color-red-700;
|
||||
color: $ibo-csv-import--cell-error--color;
|
||||
}
|
||||
|
||||
div.ibo-csv-import--cell-message {
|
||||
padding-top: $ibo-csv-import--cell-message-padding;
|
||||
padding-top: $ibo-csv-import--cell-message--padding-top;
|
||||
}
|
||||
|
||||
tr.ibo-csv-import--row-unchanged td {
|
||||
border-bottom: 1px $ibo-color-grey-400 solid;
|
||||
border-bottom: 1px $ibo-csv-import--row--border-color solid;
|
||||
}
|
||||
|
||||
.wizContainer table tr.ibo-csv-import--row-error td {
|
||||
border-bottom: 1px $ibo-csv-import--row--border-color solid;
|
||||
background-color: $ibo-csv-import--row-error--background-color;
|
||||
}
|
||||
|
||||
tr.ibo-csv-import--row-modified td {
|
||||
border-bottom: 1px $ibo-color-grey-400 solid;
|
||||
border-bottom: 1px $ibo-csv-import--row--border-color solid;
|
||||
}
|
||||
|
||||
tr.ibo-csv-import--row-added td {
|
||||
border-bottom: 1px $ibo-color-grey-400 solid;
|
||||
border-bottom: 1px $ibo-csv-import--row--border-color solid;
|
||||
}
|
||||
|
||||
.ibo-csv-import--download-file {
|
||||
font-size: 4em;
|
||||
color: $ibo-color-primary-400;
|
||||
margin: 20px;
|
||||
}
|
||||
font-size: $ibo-csv-import--download-file--font-size;
|
||||
color: $ibo-csv-import--download-file--color;
|
||||
margin: $ibo-csv-import--download-file--margin;
|
||||
}
|
||||
@@ -6,6 +6,10 @@
|
||||
$ibo-datamodel-viewer--parent--spacer--padding-y: $ibo-spacing-0 !default;
|
||||
$ibo-datamodel-viewer--parent--spacer--padding-x: $ibo-spacing-300 !default;
|
||||
|
||||
$ibo-datamodel-viewer--classes-list--selectize-input--background-color: $ibo-color-white-100 !default;
|
||||
$ibo-datamodel-viewer--classes-list--selectize-input--color: $ibo-color-grey-800 !default;
|
||||
$ibo-datamodel-viewer--classes-list--selectize-input--border-color: $ibo-color-grey-500 !default;
|
||||
|
||||
$ibo-datamodel-viewer--attributes-table--first-column--width: 3px !default;
|
||||
|
||||
$ibo-datamodel-viewer--origin-cell--diameter: 8px !default;
|
||||
@@ -45,6 +49,15 @@ $ibo-datamodel-viewer--lifecycle-image--margin-bottom: $ibo-spacing-500 !default
|
||||
padding: $ibo-datamodel-viewer--parent--spacer--padding-y $ibo-datamodel-viewer--parent--spacer--padding-x;
|
||||
}
|
||||
|
||||
// Overwrite selectize rules with !important
|
||||
.ibo-datamodel-viewer--classes-list .selectize-input{
|
||||
background-color: $ibo-datamodel-viewer--classes-list--selectize-input--background-color !important;
|
||||
background-image: none !important;
|
||||
color: $ibo-datamodel-viewer--classes-list--selectize-input--color;
|
||||
box-shadow: none !important;
|
||||
border-color: $ibo-datamodel-viewer--classes-list--selectize-input--border-color !important;
|
||||
}
|
||||
|
||||
#ibo-datamodel-viewer--attributes-table{
|
||||
> tbody tr td:first-child{
|
||||
width: $ibo-datamodel-viewer--attributes-table--first-column--width;
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user