mirror of
https://github.com/Combodo/iTop.git
synced 2026-02-25 05:14:12 +01:00
Compare commits
526 Commits
issue/6218
...
faf/improv
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
470ccd72f5 | ||
|
|
2d5cd7042a | ||
|
|
7b01108c91 | ||
|
|
3b9ca4ad18 | ||
|
|
59129bc3ce | ||
|
|
eddc750ca8 | ||
|
|
f3abe1ff13 | ||
|
|
473cf004b6 | ||
|
|
90a5a7a9a7 | ||
|
|
5574952033 | ||
|
|
1a8de82be5 | ||
|
|
d15a0a0070 | ||
|
|
76167a3d54 | ||
|
|
46273dfc12 | ||
|
|
24f1cf8ca1 | ||
|
|
2a5337d84c | ||
|
|
fbe7f559d2 | ||
|
|
c8810708ef | ||
|
|
e8c11f38d2 | ||
|
|
1394bc221d | ||
|
|
baa05ba8d4 | ||
|
|
e7b493dafa | ||
|
|
940833a66f | ||
|
|
2b172d6e19 | ||
|
|
69677954b4 | ||
|
|
9c35cddfc0 | ||
|
|
86bf6ba0b0 | ||
|
|
82e19f6eca | ||
|
|
8f1d8b1dc2 | ||
|
|
b67057c863 | ||
|
|
0546a7b82b | ||
|
|
3d360e99da | ||
|
|
3cc3f0e4ff | ||
|
|
b6230ed486 | ||
|
|
123dfd8dd3 | ||
|
|
e9bd76f2cd | ||
|
|
47f7dfeb47 | ||
|
|
405919f204 | ||
|
|
b7f43ba22b | ||
|
|
b813a32225 | ||
|
|
b13e0c92a5 | ||
|
|
a6e5f95ff4 | ||
|
|
2e5f0b064c | ||
|
|
a9f6e86381 | ||
|
|
c6548ace61 | ||
|
|
aa81c94dad | ||
|
|
478afb88e3 | ||
|
|
7c17957ec7 | ||
|
|
ba0a585256 | ||
|
|
f41f2a063d | ||
|
|
d7e9ae1a77 | ||
|
|
dd6a138ea1 | ||
|
|
b6caa51552 | ||
|
|
8a67ceff57 | ||
|
|
095c94a917 | ||
|
|
102a4a0c75 | ||
|
|
f6fec506b1 | ||
|
|
829d82dfe3 | ||
|
|
5fdf8d7687 | ||
|
|
1ddf8b419a | ||
|
|
7d0801f74f | ||
|
|
3b9f281afd | ||
|
|
c718fcf176 | ||
|
|
bcba666483 | ||
|
|
ec465174f7 | ||
|
|
2982911df7 | ||
|
|
9f675fef02 | ||
|
|
c7cb7c0b68 | ||
|
|
68f229f91c | ||
|
|
1d106eb33a | ||
|
|
31bd763b90 | ||
|
|
5c12151c26 | ||
|
|
ceba1ad1e9 | ||
|
|
efe5f004a1 | ||
|
|
b716a3965c | ||
|
|
15fa495458 | ||
|
|
1dfb2e0a1a | ||
|
|
d775658980 | ||
|
|
2bd40bef47 | ||
|
|
961315cf34 | ||
|
|
67d43c19ec | ||
|
|
2695aeb64b | ||
|
|
95fef002a6 | ||
|
|
9777ac1a5c | ||
|
|
9e24447835 | ||
|
|
296250b20f | ||
|
|
38601bf0cf | ||
|
|
9f46aad80a | ||
|
|
ba0020fa63 | ||
|
|
1e83f2eb60 | ||
|
|
dd27a3ebb4 | ||
|
|
54439ad529 | ||
|
|
a492f7a664 | ||
|
|
85a49262e9 | ||
|
|
2c61ac4949 | ||
|
|
8f7bf00551 | ||
|
|
0483cea226 | ||
|
|
922a842e96 | ||
|
|
955d04252e | ||
|
|
95c4a93f2e | ||
|
|
e4f068a518 | ||
|
|
c020de59a7 | ||
|
|
85dac470aa | ||
|
|
3c2350961d | ||
|
|
391c78ae42 | ||
|
|
aa53de467d | ||
|
|
bc6efc99ed | ||
|
|
bb3ab76205 | ||
|
|
0b1bdfff55 | ||
|
|
77c0cdf5aa | ||
|
|
af9fb74c54 | ||
|
|
5d6c4939f6 | ||
|
|
41eb927480 | ||
|
|
5663c61e51 | ||
|
|
bec5e250a5 | ||
|
|
51d0d16a11 | ||
|
|
9fe45e9472 | ||
|
|
78133418d7 | ||
|
|
8275de8fa7 | ||
|
|
ba7c154e84 | ||
|
|
d2b0140fa4 | ||
|
|
5c4ba74237 | ||
|
|
848528567e | ||
|
|
b0634c9fbc | ||
|
|
7f4b50ca7f | ||
|
|
fabeea8dba | ||
|
|
c951a33646 | ||
|
|
e7687a0fe6 | ||
|
|
5dd5986b88 | ||
|
|
8f250e82f4 | ||
|
|
ed694b09b0 | ||
|
|
3e0ca6a70a | ||
|
|
3b08ed5f51 | ||
|
|
41dcb26283 | ||
|
|
d4879b9bd8 | ||
|
|
87856fe382 | ||
|
|
205a37a879 | ||
|
|
e830c90314 | ||
|
|
5308b49cd2 | ||
|
|
216ea34a3c | ||
|
|
0a9c5250f8 | ||
|
|
0e91c75dc2 | ||
|
|
cf996dda0b | ||
|
|
21638e6a9e | ||
|
|
272d6e9b66 | ||
|
|
87b08669d7 | ||
|
|
de86682562 | ||
|
|
25c2e34eed | ||
|
|
e92b006f70 | ||
|
|
962eb08e40 | ||
|
|
6342e0065a | ||
|
|
ac44ffcdff | ||
|
|
dfb5a4875a | ||
|
|
ddce3058be | ||
|
|
9235c395b4 | ||
|
|
e1296105f9 | ||
|
|
38cdcf4f61 | ||
|
|
5623decdb3 | ||
|
|
0f39ea8ac7 | ||
|
|
f3d3ec6ef7 | ||
|
|
fde01d5004 | ||
|
|
71d9710322 | ||
|
|
7a5ce8cd6b | ||
|
|
18deb79068 | ||
|
|
16b3e62587 | ||
|
|
6c1edadc55 | ||
|
|
8928a87b14 | ||
|
|
8eca200023 | ||
|
|
865b6d14f0 | ||
|
|
b63af9b919 | ||
|
|
4d4cdf9e60 | ||
|
|
3868d57d28 | ||
|
|
1b3a2c8470 | ||
|
|
618d8e6468 | ||
|
|
53a2a7a8e2 | ||
|
|
9a26c37ffd | ||
|
|
1e3ef6846d | ||
|
|
31225b9e23 | ||
|
|
436b6808b5 | ||
|
|
cc5e105d7f | ||
|
|
7f62bd61e3 | ||
|
|
aecc34a78b | ||
|
|
72bbc31cd9 | ||
|
|
f54d1273c9 | ||
|
|
01a955a16f | ||
|
|
ed99433448 | ||
|
|
669e6f93fa | ||
|
|
a5aac0caad | ||
|
|
31e29506fa | ||
|
|
df9d71e2f5 | ||
|
|
3005bc1234 | ||
|
|
3f3b0cbe55 | ||
|
|
cff50f8732 | ||
|
|
a8cd9566ac | ||
|
|
dab03e5b5d | ||
|
|
5935800b21 | ||
|
|
87582a021b | ||
|
|
200cdefa1a | ||
|
|
8ef04bedf2 | ||
|
|
9eeb4b8751 | ||
|
|
ae3d0f9444 | ||
|
|
9ddb82073c | ||
|
|
1fa4fe6d35 | ||
|
|
2ed0666c3b | ||
|
|
51fdd04881 | ||
|
|
9b5988133b | ||
|
|
a61b117f71 | ||
|
|
9830178a47 | ||
|
|
83ac219ec9 | ||
|
|
c140ebcb6b | ||
|
|
d721632f2b | ||
|
|
fddf9e36c7 | ||
|
|
b181914d25 | ||
|
|
7a0a4e377b | ||
|
|
7fffbb60e9 | ||
|
|
dfd5a5bebc | ||
|
|
490f8600e5 | ||
|
|
03b095f246 | ||
|
|
b3be796277 | ||
|
|
b3f2232ba4 | ||
|
|
ef083d5e8f | ||
|
|
73c989ee67 | ||
|
|
bfb05d331e | ||
|
|
e8c371174c | ||
|
|
b8892e9651 | ||
|
|
8cde0ce5c5 | ||
|
|
2fd9523c16 | ||
|
|
18887bf7f9 | ||
|
|
a32dd779cb | ||
|
|
fad5571d9b | ||
|
|
48c4e2d13d | ||
|
|
3607748f49 | ||
|
|
5b2b9c92e1 | ||
|
|
a4f6f6e877 | ||
|
|
68fa3d0236 | ||
|
|
abb3ea3272 | ||
|
|
1de390a24d | ||
|
|
96d4aac650 | ||
|
|
20478958ad | ||
|
|
5726a61861 | ||
|
|
5619586645 | ||
|
|
773762bb99 | ||
|
|
34499a719f | ||
|
|
26f600542b | ||
|
|
ba99f8f5a4 | ||
|
|
8092f566a5 | ||
|
|
6724658181 | ||
|
|
379062f1f7 | ||
|
|
3f365885f0 | ||
|
|
48fe808adf | ||
|
|
c61fa7b92f | ||
|
|
135d410a6b | ||
|
|
6042e7f74d | ||
|
|
cb64dbe79f | ||
|
|
5e233f4bec | ||
|
|
f1d5f8635c | ||
|
|
19c93249e3 | ||
|
|
a1e2b648f4 | ||
|
|
9af08fa693 | ||
|
|
05db99aa69 | ||
|
|
2681abbeed | ||
|
|
94c604a6af | ||
|
|
031c90e797 | ||
|
|
34f0053db7 | ||
|
|
f84e2060be | ||
|
|
6995a3c641 | ||
|
|
afbdff928d | ||
|
|
e007e09155 | ||
|
|
4ee70cb95a | ||
|
|
9865bf0779 | ||
|
|
34ad18eee8 | ||
|
|
e73fcc5903 | ||
|
|
2144933927 | ||
|
|
0c467e7115 | ||
|
|
300ec74f76 | ||
|
|
326a115936 | ||
|
|
b962488954 | ||
|
|
b5c8c75c4e | ||
|
|
e2574a0738 | ||
|
|
3fb5c05467 | ||
|
|
0c100ea2de | ||
|
|
be99a7c02d | ||
|
|
17d131a9b1 | ||
|
|
4a164f9c01 | ||
|
|
45c50995e3 | ||
|
|
fb29ff29cf | ||
|
|
fc2be85c95 | ||
|
|
e748d72c03 | ||
|
|
62d7e10257 | ||
|
|
9ac823c0ba | ||
|
|
797aae58e3 | ||
|
|
f63f3bb547 | ||
|
|
d5449cca42 | ||
|
|
1c09a7c38e | ||
|
|
8e2e155e65 | ||
|
|
3f8017f43d | ||
|
|
45a806ac77 | ||
|
|
4846532368 | ||
|
|
427646a0c3 | ||
|
|
90d28c1f90 | ||
|
|
8cc1970931 | ||
|
|
75732faf1d | ||
|
|
c13d0a60e8 | ||
|
|
34e6e921ec | ||
|
|
66d1ffa00f | ||
|
|
181c180824 | ||
|
|
5d38d22c50 | ||
|
|
a41c58ebb4 | ||
|
|
beb015b082 | ||
|
|
4dfd9b062e | ||
|
|
27ce51ab07 | ||
|
|
863ab4560c | ||
|
|
c27c99b245 | ||
|
|
d1531c5a80 | ||
|
|
75f8c428b3 | ||
|
|
c8d2cff0ff | ||
|
|
974c155855 | ||
|
|
99d69493d1 | ||
|
|
c9bb628c30 | ||
|
|
08e8d15d78 | ||
|
|
4fb581c784 | ||
|
|
7b15103880 | ||
|
|
be699b4358 | ||
|
|
ed12495ec5 | ||
|
|
d79bbca8ce | ||
|
|
bf3de38214 | ||
|
|
ad8922861b | ||
|
|
57671f336c | ||
|
|
fdf48b8338 | ||
|
|
f0ea97850b | ||
|
|
9b1cdd3581 | ||
|
|
8c4c2b2ee4 | ||
|
|
2d96cf34d4 | ||
|
|
bed1db9c51 | ||
|
|
7e3e8e43a8 | ||
|
|
7b59df216b | ||
|
|
cb5eab812e | ||
|
|
add500193b | ||
|
|
8dff590fe2 | ||
|
|
675affb7f2 | ||
|
|
484a0bb6b6 | ||
|
|
c9b73a7fe2 | ||
|
|
ccfc29a6a9 | ||
|
|
f0ce091809 | ||
|
|
5aaaeda6c5 | ||
|
|
9266458cba | ||
|
|
6f1de11c59 | ||
|
|
3bdb883f1c | ||
|
|
a18f50615a | ||
|
|
fbd69f6d3a | ||
|
|
e02b6ee14a | ||
|
|
0d388cb3e7 | ||
|
|
5283df5ae9 | ||
|
|
f736634c3e | ||
|
|
8e0d6d1f00 | ||
|
|
f72d8f4955 | ||
|
|
ea845dc6eb | ||
|
|
3b2da39469 | ||
|
|
9a59bc7890 | ||
|
|
4b19911e12 | ||
|
|
88008b3925 | ||
|
|
e73f2c9a30 | ||
|
|
8484bee269 | ||
|
|
c5b43f3157 | ||
|
|
fc22d91232 | ||
|
|
87bb3d17a9 | ||
|
|
cfe73699cf | ||
|
|
fa830bdd7f | ||
|
|
33596249a1 | ||
|
|
26beeb6a80 | ||
|
|
2c1df77f4d | ||
|
|
3068a6a360 | ||
|
|
982b3aa5f3 | ||
|
|
47e7c35c2b | ||
|
|
083a0b79bf | ||
|
|
e22220b4fe | ||
|
|
b10bcb976d | ||
|
|
8e179f0563 | ||
|
|
a2181b3478 | ||
|
|
154a20b757 | ||
|
|
79c24dfc96 | ||
|
|
95e0f02cae | ||
|
|
c0b1e877ad | ||
|
|
403c369ea0 | ||
|
|
d5875047fa | ||
|
|
444c9e0589 | ||
|
|
6955f74c97 | ||
|
|
fb0f692c73 | ||
|
|
6bf9ce3237 | ||
|
|
5726f9f81a | ||
|
|
90a0e50e75 | ||
|
|
be93b41363 | ||
|
|
d33d82bcd8 | ||
|
|
b9d960e89e | ||
|
|
8540ec644a | ||
|
|
5b19593ede | ||
|
|
ad0795da02 | ||
|
|
57b70e48bd | ||
|
|
0915081f50 | ||
|
|
7798df0d53 | ||
|
|
a23d629e31 | ||
|
|
47ccd7589f | ||
|
|
7521fc3006 | ||
|
|
65674b9cc4 | ||
|
|
8f61c02cbe | ||
|
|
ad0fa6636b | ||
|
|
e3e8b25cfc | ||
|
|
c955fe00b7 | ||
|
|
5a43448644 | ||
|
|
67650012ce | ||
|
|
d00137026a | ||
|
|
12a1321bc1 | ||
|
|
c41ecb1b9d | ||
|
|
770bf4c42a | ||
|
|
d5f054b739 | ||
|
|
473c4cf3fa | ||
|
|
347156f900 | ||
|
|
76b70684cd | ||
|
|
336b5da2a7 | ||
|
|
6f39ae5d76 | ||
|
|
078fc7bfb8 | ||
|
|
a67d095c70 | ||
|
|
647f43882b | ||
|
|
ca47f5458c | ||
|
|
3027bb5092 | ||
|
|
893efa8e2d | ||
|
|
1ea9659227 | ||
|
|
31e58d7597 | ||
|
|
3b21ed8fe8 | ||
|
|
0ad8db565d | ||
|
|
a1a83a1ba3 | ||
|
|
e7d11e4bec | ||
|
|
e3c26c97f2 | ||
|
|
d6e132fbda | ||
|
|
74c4c642eb | ||
|
|
af3be19175 | ||
|
|
ee49d64120 | ||
|
|
58257fa25e | ||
|
|
cb3d8120bd | ||
|
|
ace88cb709 | ||
|
|
8ca20e3135 | ||
|
|
4e13cce770 | ||
|
|
f408e14d4b | ||
|
|
543daac06d | ||
|
|
800d1b03c1 | ||
|
|
9b970a472f | ||
|
|
593131a7ea | ||
|
|
148f708360 | ||
|
|
7d0feab078 | ||
|
|
aae2db8ad8 | ||
|
|
f3d488de26 | ||
|
|
ebc15db75e | ||
|
|
dd28aca260 | ||
|
|
2a6e5b21a9 | ||
|
|
14f6ce3626 | ||
|
|
34a2a6ce03 | ||
|
|
db940e3bba | ||
|
|
9f3a6be255 | ||
|
|
b6ac92d192 | ||
|
|
ce1c517a9f | ||
|
|
75b6a3ede8 | ||
|
|
3818bc3f98 | ||
|
|
d8ec900933 | ||
|
|
29ba5e73fa | ||
|
|
acf449c03a | ||
|
|
ecb4cb7435 | ||
|
|
3200b5dc86 | ||
|
|
e20d4cecd5 | ||
|
|
36177e09f7 | ||
|
|
9ae62adff1 | ||
|
|
73a2c935a7 | ||
|
|
42acbe66c3 | ||
|
|
22a9299d97 | ||
|
|
b9acd0a9a6 | ||
|
|
c761364bed | ||
|
|
d79dacf8a3 | ||
|
|
efc36e12bc | ||
|
|
5a0b12f078 | ||
|
|
22d04cb9fc | ||
|
|
d8da119c56 | ||
|
|
a24d50d7e3 | ||
|
|
e5716e66bb | ||
|
|
c6c2bb33ed | ||
|
|
0d0ef86550 | ||
|
|
ca0bd674a7 | ||
|
|
260b2e0bd6 | ||
|
|
90413ae4fe | ||
|
|
b7466e3206 | ||
|
|
f2812cdbe5 | ||
|
|
95a2fdec99 | ||
|
|
6880c49a32 | ||
|
|
1b48b4a1e1 | ||
|
|
0516100aae | ||
|
|
5b4079ab7e | ||
|
|
d284d629a4 | ||
|
|
c52195e6cd | ||
|
|
a61734a6f8 | ||
|
|
750ecd4804 | ||
|
|
781c15d1ee | ||
|
|
a1499a04d4 | ||
|
|
fb23bddeb2 | ||
|
|
aa6fa4c674 | ||
|
|
19e7fc9cb9 | ||
|
|
a0a66f3b54 | ||
|
|
3c9c13a371 | ||
|
|
96d04e35f9 | ||
|
|
629a8412dc | ||
|
|
19a83bc944 | ||
|
|
a59dacf679 | ||
|
|
8b93a404ef | ||
|
|
ded204344d | ||
|
|
b3121d46c4 | ||
|
|
f60d03ddd3 | ||
|
|
3d8345b92c | ||
|
|
9ab928e92e | ||
|
|
ea56939b7a | ||
|
|
6caddb65e9 | ||
|
|
8df0d66fb6 | ||
|
|
a80aa20b23 | ||
|
|
fd336ffd92 | ||
|
|
be1c559ad4 | ||
|
|
2dce37f289 | ||
|
|
22b5eef4ce | ||
|
|
63426e459a | ||
|
|
8393172ad2 | ||
|
|
cc06afc6df |
@@ -1,7 +1,14 @@
|
||||
# iTop version history
|
||||
|
||||
```mermaid
|
||||
%%{init: { 'logLevel': 'debug', 'theme': 'base', 'gitGraph': {'showBranches': true,'mainBranchName': 'develop','rotateCommitLabel': true}} }%%
|
||||
%%{init: { 'logLevel': 'debug', 'theme': 'base', 'themeVariables': {
|
||||
'git0': 'lawngreen',
|
||||
'git3': 'dodgerblue',
|
||||
'git4': 'grey',
|
||||
'git5': 'grey',
|
||||
'git6': 'grey',
|
||||
'git7': 'grey'
|
||||
}, 'gitGraph': {'showBranches': true,'mainBranchName': 'develop','rotateCommitLabel': true}} }%%
|
||||
gitGraph
|
||||
commit id: "2016-07-06" tag: "2.3.0" type: HIGHLIGHT
|
||||
branch support/2.3 order: 900
|
||||
@@ -68,6 +75,10 @@ gitGraph
|
||||
branch support/3.1 order: 840
|
||||
checkout support/3.1
|
||||
commit id: "2023-08-09" tag: "3.1.0-2"
|
||||
checkout support/2.7
|
||||
commit id: "2023-08-10" tag: "2.7.9"
|
||||
checkout support/3.1
|
||||
commit id: "2023-12-20" tag: "3.1.1"
|
||||
```
|
||||
|
||||
To learn more, check the [iTop community versions history on the official wiki](https://www.itophub.io/wiki/page?id=latest:release:start).
|
||||
|
||||
83
.github/pull_request_template.md
vendored
Normal file
83
.github/pull_request_template.md
vendored
Normal file
@@ -0,0 +1,83 @@
|
||||
<!--
|
||||
|
||||
IMPORTANT: Please follow the guidelines within this PR template before submitting it, it will greatly help us process your PR. 🙏
|
||||
|
||||
Any PRs not following the guidelines or with missing information will not be considered.
|
||||
|
||||
-->
|
||||
|
||||
## Base information
|
||||
| Question | Answer
|
||||
|---------------------------------------------------------------|--------
|
||||
| Related to a SourceForge thead / Another PR / Combodo ticket? | <!-- Put the URL -->
|
||||
| Type of change? | Bug fix / Enhancement / Translations
|
||||
|
||||
|
||||
## Symptom (bug) / Objective (enhancement)
|
||||
<!--
|
||||
If it's a bug
|
||||
- Explain the symptom in details
|
||||
- If possible put error messages, logs or screenshots (you can paste image directly in this editor).
|
||||
|
||||
If it's an enhancement
|
||||
- Describe what is blocking you, what is the objective with as much details as possible.
|
||||
- Add screenshots if it's related to UI.
|
||||
-->
|
||||
|
||||
|
||||
## Reproduction procedure (bug)
|
||||
<!--
|
||||
Remove this section only if it's NOT a bug.
|
||||
|
||||
Otherwise, explain step by step how to reproduce the issue on a standard iTop Community.
|
||||
|
||||
If it requires a custom datamodel, provide the minimal XML delta to reproduce it on a standard iTop Community.
|
||||
-->
|
||||
|
||||
1. On iTop x.y.z <!-- Put complete iTop version (eg. 3.1.0-2) -->
|
||||
2. With PHP x.y.z <!-- Put complete PHP version (eg. 8.1.24) -->
|
||||
2. First go there
|
||||
2. Then do that
|
||||
3. ...
|
||||
4. Finally, see that...
|
||||
|
||||
|
||||
## Cause (bug)
|
||||
<!--
|
||||
Remove this section only if it's NOT a bug.
|
||||
|
||||
Otherwise, explain what is the cause of the issue (where in the code and why)
|
||||
-->
|
||||
|
||||
|
||||
## Proposed solution (bug and enhancement)
|
||||
<!--
|
||||
Explain in details how you are proposing to solve this:
|
||||
- What did you do in the code and why
|
||||
- If you changed something in the UI, put before / after screenshots (you can paste image directly in this editor)
|
||||
-->
|
||||
|
||||
|
||||
## Checklist before requesting a review
|
||||
<!--
|
||||
Don't remove these lines, check them once done.
|
||||
-->
|
||||
- [ ] I have performed a self-review of my code
|
||||
- [ ] I have tested all changes I made on an iTop instance
|
||||
- [ ] I have added a unit test, otherwise I have explained why I couldn't
|
||||
- [ ] Is the PR clear and detailled enough so anyone can understand digging in the code?
|
||||
|
||||
## Checklist of things to do before PR is ready to merge
|
||||
<!--
|
||||
Things that needs to be done in the PR before it can be considered as ready to be merged
|
||||
|
||||
Examples:
|
||||
- Changes requested in the review
|
||||
- Unit test to add
|
||||
- Dictionary entries to translate
|
||||
- ...
|
||||
-->
|
||||
|
||||
- [ ] ...
|
||||
- [ ] ...
|
||||
- [ ] ...
|
||||
@@ -22,13 +22,13 @@ $iElapsed = time() - $iBeginTime;
|
||||
|
||||
if (count($aFailedCommands))
|
||||
{
|
||||
fwrite(STDERR, "\nafterBuild execution failed! (in ${iElapsed}s)\n");
|
||||
fwrite(STDERR, "\nafterBuild execution failed! (in {$iElapsed}s)\n");
|
||||
fwrite(STDERR, "List of failling commands:\n - " . implode("\n - ", $aFailedCommands) . "\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
|
||||
echo "\nDone (${iElapsed}s)\n";
|
||||
echo "\nDone ({$iElapsed}s)\n";
|
||||
exit(0);
|
||||
|
||||
/**
|
||||
@@ -74,7 +74,7 @@ function ExecCommand($cmd) {
|
||||
}
|
||||
else
|
||||
{
|
||||
echo "| elapsed:${iElapsed}s \n";
|
||||
echo "| elapsed:{$iElapsed}s \n";
|
||||
}
|
||||
|
||||
if (!empty($stderr))
|
||||
|
||||
56
.make/composer/tcpdf/tcpdfDefaultFontsToKeepInItop.txt
Normal file
56
.make/composer/tcpdf/tcpdfDefaultFontsToKeepInItop.txt
Normal file
@@ -0,0 +1,56 @@
|
||||
courier.php
|
||||
courierb.php
|
||||
courierbi.php
|
||||
courieri.php
|
||||
dejavusans.ctg.z
|
||||
dejavusans.php
|
||||
dejavusans.z
|
||||
dejavusansb.ctg.z
|
||||
dejavusansb.php
|
||||
dejavusansb.z
|
||||
dejavusansbi.ctg.z
|
||||
dejavusansbi.php
|
||||
dejavusansbi.z
|
||||
dejavusanscondensed.ctg.z
|
||||
dejavusanscondensed.php
|
||||
dejavusanscondensed.z
|
||||
dejavusanscondensedb.ctg.z
|
||||
dejavusanscondensedb.php
|
||||
dejavusanscondensedb.z
|
||||
dejavusanscondensedbi.ctg.z
|
||||
dejavusanscondensedbi.php
|
||||
dejavusanscondensedbi.z
|
||||
dejavusanscondensedi.ctg.z
|
||||
dejavusanscondensedi.php
|
||||
dejavusanscondensedi.z
|
||||
dejavusansextralight.ctg.z
|
||||
dejavusansextralight.php
|
||||
dejavusansextralight.z
|
||||
dejavusansi.ctg.z
|
||||
dejavusansi.php
|
||||
dejavusansi.z
|
||||
dejavusansmono.ctg.z
|
||||
dejavusansmono.php
|
||||
dejavusansmono.z
|
||||
dejavusansmonob.ctg.z
|
||||
dejavusansmonob.php
|
||||
dejavusansmonob.z
|
||||
dejavusansmonobi.ctg.z
|
||||
dejavusansmonobi.php
|
||||
dejavusansmonobi.z
|
||||
dejavusansmonoi.ctg.z
|
||||
dejavusansmonoi.php
|
||||
dejavusansmonoi.z
|
||||
droidsansfallback.ctg.z
|
||||
droidsansfallback.php
|
||||
droidsansfallback.z
|
||||
helvetica.php
|
||||
helveticab.php
|
||||
helveticabi.php
|
||||
helveticai.php
|
||||
symbol.php
|
||||
times.php
|
||||
timesb.php
|
||||
timesbi.php
|
||||
timesi.php
|
||||
zapfdingbats.php
|
||||
101
.make/composer/tcpdf/tcpdfUpdateFonts.php
Normal file
101
.make/composer/tcpdf/tcpdfUpdateFonts.php
Normal file
@@ -0,0 +1,101 @@
|
||||
<?php
|
||||
/**
|
||||
* This script will copy custom fonts in the TCPDF lib fonts directory.
|
||||
* If you need to add other files :
|
||||
* - add the corresponding files in this script directory
|
||||
* - modify this script to copy also your files
|
||||
*
|
||||
* @since 2.7.0 N°1947 add DroidSansFallback font (see also PR #49 in the links below)
|
||||
* @since 2.7.0 N°2435 TCPPDF lib forked and added in composer.json (at that time the lib was announced as deprecated and rewritten in tecnickcom/tc-lib-pdf)
|
||||
* @since 3.2.0 N°7175 switch back to TCPDF original lib (which is finally still maintained, tecnickcom/tc-lib-pdf us still under dev), script creation to keep custom DroidSansFallback font
|
||||
*
|
||||
* @link https://github.com/Combodo/iTop/pull/49 add DroidSansFallback font
|
||||
* @link https://github.com/tecnickcom/TCPDF?tab=readme-ov-file#note TCPDF is in support only mode
|
||||
*/
|
||||
|
||||
$sItopRootFolder = realpath(__DIR__ . "/../../../");
|
||||
$sCurrentScriptFileName = basename(__FILE__);
|
||||
|
||||
|
||||
require_once ("$sItopRootFolder/lib/autoload.php");
|
||||
|
||||
|
||||
$sTcPdfRootFolder = $sItopRootFolder.'/lib/tecnickcom/tcpdf';
|
||||
if (false === file_exists($sTcPdfRootFolder)) {
|
||||
echo $sCurrentScriptFileName.": No TCPDF lib detected, exiting !\n";
|
||||
return;
|
||||
}
|
||||
$sTcPdfFontsFolder = $sTcPdfRootFolder.'/Fonts/';
|
||||
|
||||
|
||||
/**
|
||||
* 1) Cleaning up the fonts directory to keep only the ones we want in iTop
|
||||
*/
|
||||
echo $sCurrentScriptFileName.": ---1) Cleaning up the fonts files\n";
|
||||
$aTcpdfDefaultFontsToKeepInItop = file(__DIR__.'/tcpdfDefaultFontsToKeepInItop.txt', FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
|
||||
|
||||
$aTcpdfFontsDirContent = scandir($sTcPdfFontsFolder);
|
||||
foreach ($aTcpdfFontsDirContent as $sTcpdfFontResourceName) {
|
||||
if ($sTcpdfFontResourceName === '.') {
|
||||
continue;
|
||||
}
|
||||
if ($sTcpdfFontResourceName === '..') {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!in_array($sTcpdfFontResourceName, $aTcpdfDefaultFontsToKeepInItop, true)) {
|
||||
echo $sCurrentScriptFileName.": Removing $sTcpdfFontResourceName !\n";
|
||||
|
||||
$sTcpdfFontResourceFullPath = $sTcPdfFontsFolder.$sTcpdfFontResourceName;
|
||||
if (is_file($sTcpdfFontResourceFullPath)) {
|
||||
unlink($sTcpdfFontResourceFullPath);
|
||||
} elseif (is_dir($sTcpdfFontResourceFullPath)) {
|
||||
rrmdir($sTcpdfFontResourceFullPath);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 2) Then adding the DroidSansFallback font (useful for CJK data for example)
|
||||
*/
|
||||
echo $sCurrentScriptFileName.": ---2) Copying font files to TCPDF ($sTcPdfFontsFolder)...\n";
|
||||
$aFontFilesToCopy = glob(__DIR__.'\droidsansfallback.*');
|
||||
foreach ($aFontFilesToCopy as $sFontFileToCopy) {
|
||||
$sFontFileName = basename($sFontFileToCopy);
|
||||
echo $sCurrentScriptFileName.': copying '.$sFontFileName."\n";
|
||||
copy($sFontFileToCopy, $sTcPdfFontsFolder.$sFontFileName);
|
||||
}
|
||||
echo $sCurrentScriptFileName.": Done !\n";
|
||||
|
||||
|
||||
|
||||
/*-----------------------------------------------------------------------------------------------*/
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Recursively delete a directory and its content
|
||||
*
|
||||
* @param $sDirToRemovePath
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function rrmdir($sDirToRemovePath):void
|
||||
{
|
||||
if (is_dir($sDirToRemovePath)) {
|
||||
$objects = scandir($sDirToRemovePath);
|
||||
foreach ($objects as $object) {
|
||||
if ($object != "." && $object != "..") {
|
||||
if (filetype($sDirToRemovePath."/".$object) == "dir") {
|
||||
rrmdir($sDirToRemovePath."/".$object);
|
||||
} else {
|
||||
unlink($sDirToRemovePath."/".$object);
|
||||
}
|
||||
}
|
||||
}
|
||||
reset($objects);
|
||||
rmdir($sDirToRemovePath);
|
||||
}
|
||||
}
|
||||
@@ -140,7 +140,7 @@ When your code is working, please:
|
||||
* Pull request description: mind to add all the information useful to understand why you're suggesting this modification and anything necessary to dive into your work. Especially:
|
||||
- Bugfixes: exact steps to reproduce the bug (given/when/then), description of the bug cause and what solution is implemented
|
||||
- Enhancements: use cases, implementation details if needed
|
||||
* Mind to check the "[Allow edits from maintainers](https://docs.github.com/en/github-ae@latest/pull-requests/collaborating-with-pull-requests/working-with-forks/allowing-changes-to-a-pull-request-branch-created-from-a-fork)" option !
|
||||
* Mind to check the "[Allow edits from maintainers](https://docs.github.com/en/github-ae@latest/pull-requests/collaborating-with-pull-requests/working-with-forks/allowing-changes-to-a-pull-request-branch-created-from-a-fork)" option ! (note that if you are working with an org fork, this option [won't be available](https://github.com/orgs/community/discussions/5634))
|
||||
|
||||
|
||||
## 🙏 We are thankful
|
||||
|
||||
@@ -87,9 +87,11 @@ We would like to give a special thank you 🤗 to the people from the community
|
||||
- Castro, Randall Badilla
|
||||
- Colantoni, Maria Laura
|
||||
- Couronné, Guy
|
||||
- Dejin, Bie (a.k.a [@bdejin](https://github.com/bdejin))
|
||||
- Dvořák, Lukáš
|
||||
- Goethals, Stefan
|
||||
- Gumble, David
|
||||
- Ji, Leeb (冀利斌) (a.k.a [@chileeb](https://github.com/chileeb))
|
||||
- Kaltefleiter, Lars (a.k.a [@larhip](https://www.github.com/larhip))
|
||||
- Khamit, Shamil
|
||||
- Kincel, Martin
|
||||
@@ -105,9 +107,12 @@ We would like to give a special thank you 🤗 to the people from the community
|
||||
- Roháč, Richard (a.k.a [@RohacRichard](https://github.com/RohacRichard))
|
||||
- Rosenke, Stephan
|
||||
- Rudner, Björn (a.k.a [@rudnerbjoern](https://github.com/rudnerbjoern))
|
||||
- Šafránek, Jaroslav (a.k.a [jkcinik](https://sourceforge.net/u/jkcinik/profile/) on SourceForge)
|
||||
- Seki, Shoji
|
||||
- Shilov, Vladimir
|
||||
- Stetina, Pavel (a.k.a [@Stetinac](https://github.com/Stetinac))
|
||||
- Stukalov, Ilya (a.k.a [@ilya](https://www.github.com/ilya)-stukalov)
|
||||
- Tarjányi, Csaba (a.k.a [@tacsaby](https://github.com/tacsaby))
|
||||
- Tulio, Marco
|
||||
- Turrubiates, Miguel
|
||||
|
||||
|
||||
@@ -4,6 +4,8 @@
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
use Combodo\iTop\Application\WebPage\WebPage;
|
||||
|
||||
define('ADMIN_PROFILE_NAME', 'Administrator');
|
||||
define('PORTAL_PROFILE_NAME', 'Portal user');
|
||||
|
||||
@@ -933,8 +935,9 @@ class UserRightsProfile extends UserRightsAddOnAPI
|
||||
}
|
||||
|
||||
/**
|
||||
* Find out which attribute is corresponding the the dimension 'owner org'
|
||||
* returns null if no such attribute has been found (no filtering should occur)
|
||||
* @param string $sClass
|
||||
* @return string|null Find out which attribute is corresponding the dimension 'owner org'
|
||||
* returns null if no such attribute has been found (no filtering should occur)
|
||||
*/
|
||||
public static function GetOwnerOrganizationAttCode($sClass)
|
||||
{
|
||||
|
||||
@@ -17,6 +17,8 @@
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
*/
|
||||
|
||||
use Combodo\iTop\Application\WebPage\WebPage;
|
||||
|
||||
define('ADMIN_PROFILE_NAME', 'Administrator');
|
||||
define('PORTAL_PROFILE_NAME', 'Portal user');
|
||||
|
||||
@@ -580,10 +582,10 @@ class UserRightsProfile extends UserRightsAddOnAPI
|
||||
/**
|
||||
* Read and cache organizations allowed to the given user
|
||||
*
|
||||
* @param $oUser
|
||||
* @param $sClass (not used here but can be used in overloads)
|
||||
* @param User $oUser
|
||||
* @param string $sClass (not used here but can be used in overloads)
|
||||
*
|
||||
* @return array
|
||||
* @return array keys of the User allowed org
|
||||
* @throws \CoreException
|
||||
* @throws \Exception
|
||||
*/
|
||||
|
||||
@@ -17,6 +17,8 @@
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
*/
|
||||
|
||||
use Combodo\iTop\Application\WebPage\WebPage;
|
||||
|
||||
define('ADMIN_PROFILE_ID', 1);
|
||||
|
||||
class UserRightsBaseClass extends cmdbAbstractObject
|
||||
|
||||
29
app.php
Normal file
29
app.php
Normal file
@@ -0,0 +1,29 @@
|
||||
<?php
|
||||
/**
|
||||
* Copyright (C) 2013-2023 Combodo SARL
|
||||
*
|
||||
* This file is part of iTop.
|
||||
*
|
||||
* iTop is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* iTop is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
*/
|
||||
|
||||
use Combodo\iTop\Kernel;
|
||||
|
||||
require_once __DIR__.'/lib/autoload_runtime.php';
|
||||
|
||||
require_once('approot.inc.php');
|
||||
require_once('application/startup.inc.php');
|
||||
|
||||
return function (array $context) {
|
||||
return new Kernel($context['APP_ENV'], (bool) $context['APP_DEBUG']);
|
||||
};
|
||||
@@ -7,6 +7,7 @@
|
||||
|
||||
// cannot notify depreciation for now as this is still load in autoloader
|
||||
//DeprecatedCallsLog::NotifyDeprecatedFile('moved to sources/Application/WebPage/AjaxPage.php, now loadable using autoloader');
|
||||
use Combodo\iTop\Application\WebPage\AjaxPage;
|
||||
|
||||
/**
|
||||
* Class ajax_page
|
||||
|
||||
@@ -19,6 +19,8 @@
|
||||
*/
|
||||
|
||||
use Combodo\iTop\Application\UI\Base\iUIBlock;
|
||||
use Combodo\iTop\Application\WebPage\iTopWebPage;
|
||||
use Combodo\iTop\Application\WebPage\WebPage;
|
||||
use Symfony\Component\DependencyInjection\Container;
|
||||
|
||||
require_once(APPROOT.'application/newsroomprovider.class.inc.php');
|
||||
@@ -270,14 +272,14 @@ interface iPreferencesExtension
|
||||
{
|
||||
/**
|
||||
* @api
|
||||
* @param \WebPage $oPage
|
||||
* @param WebPage $oPage
|
||||
*
|
||||
*/
|
||||
public function DisplayPreferences(WebPage $oPage);
|
||||
|
||||
/**
|
||||
* @api
|
||||
* @param \WebPage $oPage
|
||||
* @param WebPage $oPage
|
||||
* @param string $sOperation
|
||||
*
|
||||
* @return bool true if the operation has been used
|
||||
@@ -1272,8 +1274,6 @@ abstract class AbstractPageUIExtension implements iPageUIExtension
|
||||
*/
|
||||
public function GetNorthPaneHtml(iTopWebPage $oPage)
|
||||
{
|
||||
DeprecatedCallsLog::NotifyDeprecatedPhpMethod('use iPageUIBlockExtension instead');
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
@@ -1282,8 +1282,6 @@ abstract class AbstractPageUIExtension implements iPageUIExtension
|
||||
*/
|
||||
public function GetSouthPaneHtml(iTopWebPage $oPage)
|
||||
{
|
||||
DeprecatedCallsLog::NotifyDeprecatedPhpMethod('use iPageUIBlockExtension instead');
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
@@ -1292,8 +1290,6 @@ abstract class AbstractPageUIExtension implements iPageUIExtension
|
||||
*/
|
||||
public function GetBannerHtml(iTopWebPage $oPage)
|
||||
{
|
||||
DeprecatedCallsLog::NotifyDeprecatedPhpMethod('use iPageUIBlockExtension instead');
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
@@ -2015,6 +2011,8 @@ class RestUtils
|
||||
*
|
||||
* @return DBObject The object found
|
||||
* @throws Exception If the input structure is not valid or it could not find exactly one object
|
||||
*
|
||||
* @see DBObject::CheckChangedExtKeysValues() generic method to check that we can access the linked object isn't used in that use case because values can be literal, OQL, friendlyname
|
||||
*/
|
||||
public static function FindObjectFromKey($sClass, $key, $bAllowNullValue = false)
|
||||
{
|
||||
|
||||
@@ -86,7 +86,7 @@ class lnkAuditCategoryToAuditDomain extends cmdbAbstractObject
|
||||
{
|
||||
$aParams = array
|
||||
(
|
||||
"category" => "application, grant_by_profile",
|
||||
"category" => "application,grant_by_profile",
|
||||
"key_type" => "autoincrement",
|
||||
"name_attcode" => "",
|
||||
"state_attcode" => "",
|
||||
|
||||
@@ -26,7 +26,7 @@ use Combodo\iTop\Application\UI\Base\Component\Html\Html;
|
||||
use Combodo\iTop\Application\UI\Base\Component\Html\HtmlFactory;
|
||||
use Combodo\iTop\Application\UI\Base\Component\Input\InputUIBlockFactory;
|
||||
use Combodo\iTop\Application\UI\Base\Component\Input\Select\SelectOptionUIBlockFactory;
|
||||
use Combodo\iTop\Application\UI\Base\Component\Input\SelectUIBlockFactory;
|
||||
use Combodo\iTop\Application\UI\Base\Component\Input\Select\SelectUIBlockFactory;
|
||||
use Combodo\iTop\Application\UI\Base\Component\Panel\PanelUIBlockFactory;
|
||||
use Combodo\iTop\Application\UI\Base\Component\PopoverMenu\PopoverMenu;
|
||||
use Combodo\iTop\Application\UI\Base\Component\PopoverMenu\PopoverMenuItem\JsPopoverMenuItem;
|
||||
@@ -42,6 +42,9 @@ use Combodo\iTop\Application\UI\Base\Layout\UIContentBlockUIBlockFactory;
|
||||
use Combodo\iTop\Application\UI\Links\Direct\BlockDirectLinkSetViewTable;
|
||||
use Combodo\iTop\Application\UI\Links\Indirect\BlockIndirectLinkSetViewTable;
|
||||
use Combodo\iTop\Application\UI\Links\Set\LinkSetUIBlockFactory;
|
||||
use Combodo\iTop\Application\WebPage\AjaxPage;
|
||||
use Combodo\iTop\Application\WebPage\iTopWebPage;
|
||||
use Combodo\iTop\Application\WebPage\WebPage;
|
||||
use Combodo\iTop\Renderer\BlockRenderer;
|
||||
use Combodo\iTop\Renderer\Console\ConsoleBlockRenderer;
|
||||
use Combodo\iTop\Renderer\Console\ConsoleFormRenderer;
|
||||
@@ -134,6 +137,8 @@ abstract class cmdbAbstractObject extends CMDBObject implements iDisplay
|
||||
/** @var string */
|
||||
public const ENUM_INPUT_TYPE_TAGSET = 'tagset';
|
||||
/** @var string */
|
||||
public const ENUM_INPUT_TYPE_TAGSET_LINKEDSET = 'tagset_linkedset';
|
||||
/** @var string */
|
||||
public const ENUM_INPUT_TYPE_RADIO = 'radio';
|
||||
/** @var string */
|
||||
public const ENUM_INPUT_TYPE_CHECKBOX = 'checkbox';
|
||||
@@ -285,7 +290,7 @@ abstract class cmdbAbstractObject extends CMDBObject implements iDisplay
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \WebPage $oPage
|
||||
* @param WebPage $oPage
|
||||
* @param \cmdbAbstractObject $oObj
|
||||
* @param array $aParams
|
||||
*
|
||||
@@ -354,7 +359,7 @@ JS
|
||||
* @param int $iKey The identifier of the object
|
||||
* @param string $sMessageId Your id or one of the well-known ids: 'create', 'update' and 'apply_stimulus'
|
||||
* @param string $sMessage The HTML message (must be correctly escaped)
|
||||
* @param string $sSeverity Any of the \WebPage::ENUM_SESSION_MESSAGE_SEVERITY_XXX constants
|
||||
* @param string $sSeverity Any of the WebPage::ENUM_SESSION_MESSAGE_SEVERITY_XXX constants
|
||||
* @param float $fRank Ordering of the message: smallest displayed first (can be negative)
|
||||
* @param bool $bMustNotExist Do not alter any existing message (considering the id)
|
||||
*
|
||||
@@ -376,7 +381,7 @@ JS
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \WebPage $oPage Warning, since 3.0.0 this parameter was kept for compatibility reason. You shouldn't write directly on the page!
|
||||
* @param WebPage $oPage Warning, since 3.0.0 this parameter was kept for compatibility reason. You shouldn't write directly on the page!
|
||||
* When writing to the page, markup will be put above the real header of the panel.
|
||||
* To insert something IN the panel, we now need to add UIBlocks in either the "subtitle" or "toolbar" sections of the array that will be returned.
|
||||
* @param bool $bEditMode Deprecated parameter in iTop 3.0.0, use {@see GetDisplayMode()} and ENUM_DISPLAY_MODE_* constants instead
|
||||
@@ -554,7 +559,7 @@ HTML
|
||||
/**
|
||||
* Display properties tab of an object
|
||||
*
|
||||
* @param \WebPage $oPage
|
||||
* @param WebPage $oPage
|
||||
* @param bool $bEditMode Note that this parameter is no longer used in this method. Use {@see static::$sDisplayMode} instead
|
||||
* @param string $sPrefix
|
||||
* @param array $aExtraParams
|
||||
@@ -593,7 +598,7 @@ HTML
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \WebPage $oPage
|
||||
* @param WebPage $oPage
|
||||
* @param $sAttCode
|
||||
*
|
||||
* @throws \Exception
|
||||
@@ -634,7 +639,7 @@ HTML
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \WebPage $oPage
|
||||
* @param WebPage $oPage
|
||||
* @param bool $bEditMode Note that this parameter is no longer used in this method. Use {@see static::$sDisplayMode} instead
|
||||
*
|
||||
* @throws \CoreException
|
||||
@@ -861,7 +866,7 @@ HTML
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \WebPage $oPage
|
||||
* @param WebPage $oPage
|
||||
* @param bool $bEditMode Note that this parameter is no longer used in this method. Use {@see static::$sDisplayMode} instead
|
||||
* @param string $sPrefix
|
||||
* @param array $aExtraParams
|
||||
@@ -1065,7 +1070,7 @@ HTML
|
||||
|
||||
|
||||
/**
|
||||
* @param \WebPage $oPage
|
||||
* @param WebPage $oPage
|
||||
* @param bool $bEditMode Note that this parameter is no longer used in this method, {@see static::$sDisplayMode} is used instead, but we cannot remove it as it part of the base interface (iDisplay)...
|
||||
*
|
||||
* @throws \ApplicationException
|
||||
@@ -1112,7 +1117,7 @@ HTML
|
||||
}
|
||||
|
||||
// Note: DisplayBareHeader is called before adding $oObjectDetails to the page, so it can inject HTML before it through $oPage.
|
||||
/** @var \iTopWebPage $oPage */
|
||||
/** @var iTopWebPage $oPage */
|
||||
$aHeadersBlocks = $this->DisplayBareHeader($oPage, $bEditMode);
|
||||
if (false === empty($aHeadersBlocks['subtitle'])) {
|
||||
$oObjectDetails->AddSubTitleBlocks($aHeadersBlocks['subtitle']);
|
||||
@@ -1147,7 +1152,7 @@ HTML
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \WebPage $oPage
|
||||
* @param WebPage $oPage
|
||||
*
|
||||
* @throws \ArchivedObjectException
|
||||
* @throws \CoreException
|
||||
@@ -1170,7 +1175,7 @@ HTML
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \WebPage $oPage
|
||||
* @param WebPage $oPage
|
||||
* @param \CMDBObjectSet $oSet
|
||||
* @param array $aExtraParams See possible values in {@see DataTableUIBlockFactory::RenderDataTable()}
|
||||
*
|
||||
@@ -1232,7 +1237,7 @@ HTML
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \WebPage $oPage
|
||||
* @param WebPage $oPage
|
||||
* @param \DBObjectSet $oSet
|
||||
* @param array $aExtraParams
|
||||
*
|
||||
@@ -1404,7 +1409,7 @@ HTML
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \WebPage $oPage
|
||||
* @param WebPage $oPage
|
||||
* @param \CMDBObjectSet $oSet
|
||||
* @param array $aExtraParams key used :
|
||||
* <ul>
|
||||
@@ -1527,7 +1532,7 @@ HTML
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \WebPage $oPage
|
||||
* @param WebPage $oPage
|
||||
* @param \CMDBObjectSet $oSet
|
||||
* @param array $aParams
|
||||
* @param string $sCharset
|
||||
@@ -1686,7 +1691,7 @@ HTML
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \WebPage $oPage
|
||||
* @param WebPage $oPage
|
||||
* @param \CMDBObjectSet $oSet
|
||||
* @param array $aParams
|
||||
*
|
||||
@@ -1899,7 +1904,7 @@ HTML
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \WebPage $oPage
|
||||
* @param WebPage $oPage
|
||||
* @param \CMDBObjectSet $oSet
|
||||
* @param array $aParams
|
||||
*
|
||||
@@ -1977,7 +1982,7 @@ HTML
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \WebPage $oPage
|
||||
* @param WebPage $oPage
|
||||
* @param \CMDBObjectSet $oSet
|
||||
* @param array $aExtraParams
|
||||
*
|
||||
@@ -2008,7 +2013,7 @@ HTML
|
||||
|
||||
|
||||
/**
|
||||
* @param \WebPage $oPage
|
||||
* @param WebPage $oPage
|
||||
* @param string $sClass
|
||||
* @param string $sAttCode
|
||||
* @param \AttributeDefinition $oAttDef
|
||||
@@ -2359,6 +2364,7 @@ EOF
|
||||
|
||||
case 'LinkedSet':
|
||||
if ($oAttDef->GetDisplayStyle() === LINKSET_DISPLAY_STYLE_PROPERTY) {
|
||||
$sInputType = self::ENUM_INPUT_TYPE_TAGSET_LINKEDSET;
|
||||
if (array_key_exists('bulk_context', $aArgs)) {
|
||||
$oTagSetBlock = LinkSetUIBlockFactory::MakeForBulkLinkSet($iId, $oAttDef, $value, $sWizardHelperJsVarName, $aArgs['bulk_context']);
|
||||
} else {
|
||||
@@ -2746,7 +2752,7 @@ JS
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \WebPage $oPage
|
||||
* @param WebPage $oPage
|
||||
* @param array $aExtraParams
|
||||
*
|
||||
* @throws \ArchivedObjectException
|
||||
@@ -3151,7 +3157,7 @@ EOF
|
||||
/**
|
||||
* Select the derived class to create
|
||||
* @param string $sClass
|
||||
* @param \WebPage $oP
|
||||
* @param WebPage $oP
|
||||
* @param \ApplicationContext $oAppContext
|
||||
* @param array $aPossibleClasses
|
||||
* @param array $aHiddenFields
|
||||
@@ -3246,7 +3252,7 @@ EOF
|
||||
return $oBlock;
|
||||
}
|
||||
/**
|
||||
* @param \WebPage $oPage
|
||||
* @param WebPage $oPage
|
||||
* @param string $sClass
|
||||
* @param \DBObject|null $oSourceObject Object to use for the creation form, can be either the class to instantiate, an object to clone or an object to use (eg. already prefilled / modeled object)
|
||||
* @param array $aArgs
|
||||
@@ -3331,7 +3337,7 @@ EOF
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \WebPage $oPage
|
||||
* @param WebPage $oPage
|
||||
* @param string $sStimulus
|
||||
* @param array|null $aPrefillFormParam
|
||||
* @param bool $bDisplayBareProperties Whether to display the object details or not
|
||||
@@ -3586,16 +3592,26 @@ EOF
|
||||
$oPage->add_ready_script(InlineImage::EnableCKEditorImageUpload($this, $sTempId));
|
||||
} else {
|
||||
//we can directly apply the stimuli
|
||||
$sExceptionMessage = null;
|
||||
try {
|
||||
$bApplyStimulus = $this->ApplyStimulus($sStimulus); // will write the object in the DB
|
||||
if (!$bApplyStimulus) {
|
||||
throw new ApplicationException(Dict::S('UI:FailedToApplyStimuli'));
|
||||
} else {
|
||||
}
|
||||
catch (Exception $oException) {
|
||||
// Catch any exception happening during the stimulus
|
||||
$bApplyStimulus = false;
|
||||
$sExceptionMessage = ($oException instanceof CoreCannotSaveObjectException) ? $oException->getHtmlMessage() : $oException->getMessage();
|
||||
}
|
||||
finally {
|
||||
if ($sOwnershipToken !== null) {
|
||||
// Release the concurrent lock, if any
|
||||
iTopOwnershipLock::ReleaseLock($sClass, $iKey, $sOwnershipToken);
|
||||
}
|
||||
|
||||
return true;
|
||||
if (!$bApplyStimulus) {
|
||||
// Throw an application oriented exception if necessary
|
||||
throw new ApplicationException($sExceptionMessage ?? Dict::S('UI:FailedToApplyStimuli'));
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3709,7 +3725,7 @@ HTML;
|
||||
if ($oAttDef->GetEditClass() == 'Document') {
|
||||
/** @var \ormDocument $oDocument */
|
||||
$oDocument = $this->Get($sAttCode);
|
||||
if (!$oDocument->IsEmpty()) {
|
||||
if (is_object($oDocument) && !$oDocument->IsEmpty()) {
|
||||
$sFieldAsHtml = $this->GetAsHTML($sAttCode);
|
||||
|
||||
$sDisplayLabel = Dict::S('UI:OpenDocumentInNewWindow_');
|
||||
@@ -3744,7 +3760,7 @@ HTML;
|
||||
/**
|
||||
* Displays a blob document *inline* (if possible, depending on the type of the document)
|
||||
*
|
||||
* @param \WebPage $oPage
|
||||
* @param WebPage $oPage
|
||||
* @param $sAttCode
|
||||
*
|
||||
* @return string
|
||||
@@ -4544,7 +4560,7 @@ HTML;
|
||||
return $res;
|
||||
}
|
||||
|
||||
public function PostInsertActions(): void
|
||||
protected function PostInsertActions(): void
|
||||
{
|
||||
parent::PostInsertActions();
|
||||
|
||||
@@ -4568,6 +4584,9 @@ HTML;
|
||||
InlineImage::FinalizeInlineImages($this);
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated 3.1.1 3.2.0 N°6966 We will have only one DBClone method in the future
|
||||
*/
|
||||
protected function DBCloneTracked_Internal($newKey = null)
|
||||
{
|
||||
/** @var cmdbAbstractObject $oNewObj */
|
||||
@@ -4588,6 +4607,7 @@ HTML;
|
||||
public function DBUpdate()
|
||||
{
|
||||
$this->LogCRUDEnter(__METHOD__);
|
||||
$res = 0;
|
||||
|
||||
try {
|
||||
if (count($this->ListChanges()) === 0) {
|
||||
@@ -4607,7 +4627,7 @@ HTML;
|
||||
return $res;
|
||||
}
|
||||
|
||||
public function PostUpdateActions(array $aChanges): void
|
||||
protected function PostUpdateActions(array $aChanges): void
|
||||
{
|
||||
parent::PostUpdateActions($aChanges);
|
||||
|
||||
@@ -4648,6 +4668,7 @@ HTML;
|
||||
if (static::IsCrudStackEmpty()) {
|
||||
// Avoid signaling the current object that links were modified
|
||||
static::RemoveObjectAwaitingEventDbLinksChanged(get_class($this), $this->GetKey());
|
||||
$this->LogCRUDDebug(__METHOD__, var_export(self::$aObjectsAwaitingEventDbLinksChanged, true));
|
||||
static::FireEventDbLinksChangedForAllObjects();
|
||||
}
|
||||
}
|
||||
@@ -4656,7 +4677,15 @@ HTML;
|
||||
return $oDeletionPlan;
|
||||
}
|
||||
|
||||
protected function DBDeleteTracked_Internal(&$oDeletionPlan = null)
|
||||
protected function PostDeleteActions(): void
|
||||
{
|
||||
parent::PostDeleteActions();
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated 3.1.1 3.2.0 N°6967 We will have only one DBDelete method in the future
|
||||
*/
|
||||
protected function DBDeleteTracked_Internal(&$oDeletionPlan = null)
|
||||
{
|
||||
// Invoke extensions before the deletion (the deletion will do some cleanup and we might loose some information
|
||||
/** @var \iApplicationObjectExtension $oExtensionInstance */
|
||||
@@ -4819,7 +4848,7 @@ HTML;
|
||||
/**
|
||||
* Special display where the case log uses the whole "screen" at the bottom of the "Properties" tab
|
||||
*
|
||||
* @param \WebPage $oPage
|
||||
* @param WebPage $oPage
|
||||
* @param string $sAttCode
|
||||
* @param string $sComment
|
||||
* @param string $sPrefix
|
||||
@@ -4923,7 +4952,7 @@ HTML
|
||||
/**
|
||||
* Special display where the case log uses the whole "screen" at the bottom of the "Properties" tab
|
||||
*
|
||||
* @param \WebPage $oPage
|
||||
* @param WebPage $oPage
|
||||
* @param string $sAttCode
|
||||
* @param string $sComment
|
||||
* @param string $sPrefix
|
||||
@@ -5048,7 +5077,7 @@ HTML
|
||||
* Display a form for modifying several objects at once
|
||||
* The form will be submitted to the current page, with the specified additional values
|
||||
*
|
||||
* @param \iTopWebPage $oP
|
||||
* @param iTopWebPage $oP
|
||||
* @param string $sClass
|
||||
* @param array $aSelectedObj
|
||||
* @param string $sCustomOperation
|
||||
@@ -5292,7 +5321,7 @@ EOF
|
||||
/**
|
||||
* Process the reply made from a form built with DisplayBulkModifyForm
|
||||
*
|
||||
* @param \WebPage $oP
|
||||
* @param WebPage $oP
|
||||
* @param string $sClass
|
||||
* @param array $aSelectedObj
|
||||
* @param string $sCustomOperation
|
||||
@@ -5348,7 +5377,7 @@ EOF
|
||||
$aErrors = $oObj->UpdateObjectFromPostedForm('');
|
||||
$bResult = (count($aErrors) == 0);
|
||||
if ($bResult) {
|
||||
list($bResult, $aErrors) = $oObj->CheckToWrite();
|
||||
[$bResult, $aErrors] = $oObj->CheckToWrite();
|
||||
}
|
||||
if ($bPreview) {
|
||||
$sStatus = $bResult ? Dict::S('UI:BulkModifyStatusOk') : Dict::S('UI:BulkModifyStatusError');
|
||||
@@ -5365,6 +5394,11 @@ EOF
|
||||
'errors' => '<p>'.($bResult ? '' : implode('</p><p>', $aErrorsToDisplay)).'</p>',
|
||||
);
|
||||
if ($bResult && (!$bPreview)) {
|
||||
// doing the check will load multiple times same objects :/
|
||||
// but it shouldn't cost too much on execution time
|
||||
// user can mitigate by selecting less extkeys/lnk to set and/or less objects to update 🤷♂️
|
||||
$oObj->CheckChangedExtKeysValues();
|
||||
|
||||
$oObj->DBUpdate();
|
||||
}
|
||||
}
|
||||
@@ -5427,7 +5461,7 @@ EOF
|
||||
/**
|
||||
* Perform all the needed checks to delete one (or more) objects
|
||||
*
|
||||
* @param \WebPage $oP
|
||||
* @param WebPage $oP
|
||||
* @param $sClass
|
||||
* @param \DBObject[] $aObjects
|
||||
* @param $bPreview
|
||||
@@ -5933,6 +5967,16 @@ JS
|
||||
$this->FireEvent(EVENT_DB_CHECK_TO_DELETE, ['deletion_plan' => $oDeletionPlan]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
* @throws \CoreException
|
||||
* @since 3.1.2
|
||||
*/
|
||||
final protected function FireEventAboutToDelete(): void
|
||||
{
|
||||
$this->FireEvent(EVENT_DB_ABOUT_TO_DELETE);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
* @throws \CoreException
|
||||
@@ -5942,47 +5986,63 @@ JS
|
||||
final protected function FireEventAfterDelete(): void
|
||||
{
|
||||
$this->NotifyAttachedObjectsOnLinkClassModification();
|
||||
$this->FireEventDbLinksChangedForCurrentObject();
|
||||
$this->FireEvent(EVENT_DB_AFTER_DELETE);
|
||||
}
|
||||
|
||||
/**
|
||||
* If the passed object is an instance of a link class, then will register each remote object for modification using {@see static::RegisterObjectAwaitingEventDbLinksChanged()}
|
||||
* Possibility for linked classes to be notified of current class modification
|
||||
*
|
||||
* If an external key was modified, register also the previous object that was linked previously.
|
||||
*
|
||||
* @throws \ArchivedObjectException
|
||||
* @throws \CoreException
|
||||
* @throws \Exception
|
||||
* @uses static::RegisterObjectAwaitingEventDbLinksChanged()
|
||||
*
|
||||
* @since 3.1.0 N°5906
|
||||
* @throws ArchivedObjectException
|
||||
* @throws CoreException
|
||||
* @throws Exception
|
||||
*
|
||||
* @since 3.1.0 N°5906 method creation
|
||||
* @since 3.1.1 3.2.0 N°6228 now just notify attributes having `with_php_computation`
|
||||
*/
|
||||
final protected function NotifyAttachedObjectsOnLinkClassModification(): void
|
||||
{
|
||||
$sClass = get_class($this);
|
||||
if (false === MetaModel::IsLinkClass($sClass)) {
|
||||
return;
|
||||
}
|
||||
// previous values in case of link change
|
||||
$aPreviousValues = $this->ListPreviousValuesForUpdatedAttributes();
|
||||
$sClass = get_class($this);
|
||||
$aClassExtKeyAttCodes = MetaModel::GetAttributesList($sClass, [AttributeExternalKey::class]);
|
||||
foreach ($aClassExtKeyAttCodes as $sExternalKeyAttCode) {
|
||||
/** @var AttributeExternalKey $oAttDef */
|
||||
$oAttDef = MetaModel::GetAttributeDef($sClass, $sExternalKeyAttCode);
|
||||
|
||||
$aLnkClassExternalKeys = MetaModel::GetAttributesList($sClass, [AttributeExternalKey::class]);
|
||||
foreach ($aLnkClassExternalKeys as $sExternalKeyAttCode) {
|
||||
/** @var \AttributeExternalKey $oExternalKeyAttDef */
|
||||
$oExternalKeyAttDef = MetaModel::GetAttributeDef($sClass, $sExternalKeyAttCode);
|
||||
$sRemoteClassName = $oExternalKeyAttDef->GetTargetClass();
|
||||
|
||||
$sRemoteObjectId = $this->Get($sExternalKeyAttCode);
|
||||
if ($sRemoteObjectId > 0) {
|
||||
self::RegisterObjectAwaitingEventDbLinksChanged($sRemoteClassName, $sRemoteObjectId);
|
||||
if (false === $this->DoesTargetObjectHavePhpComputation($oAttDef)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$sPreviousRemoteObjectId = $aPreviousValues[$sExternalKeyAttCode] ?? 0;
|
||||
if ($sPreviousRemoteObjectId > 0) {
|
||||
self::RegisterObjectAwaitingEventDbLinksChanged($sRemoteClassName, $sPreviousRemoteObjectId);
|
||||
$sTargetObjectId = $this->Get($sExternalKeyAttCode);
|
||||
$sTargetClass = $oAttDef->GetTargetClass();
|
||||
if ($sTargetObjectId > 0) {
|
||||
$this->LogCRUDDebug(__METHOD__, "Add $sTargetClass:$sTargetObjectId for DBLINKS_CHANGED");
|
||||
self::RegisterObjectAwaitingEventDbLinksChanged($sTargetClass, $sTargetObjectId);
|
||||
}
|
||||
|
||||
$sPreviousTargetObjectId = $aPreviousValues[$sExternalKeyAttCode] ?? 0;
|
||||
if ($sPreviousTargetObjectId > 0) {
|
||||
$this->LogCRUDDebug(__METHOD__, "Add $sTargetClass:$sPreviousTargetObjectId for DBLINKS_CHANGED");
|
||||
self::RegisterObjectAwaitingEventDbLinksChanged($sTargetClass, $sPreviousTargetObjectId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private function DoesTargetObjectHavePhpComputation(AttributeExternalKey $oAttDef): bool
|
||||
{
|
||||
/** @var AttributeLinkedSet $oAttDefMirrorLink */
|
||||
$oAttDefMirrorLink = $oAttDef->GetMirrorLinkAttribute();
|
||||
if (is_null($oAttDefMirrorLink) || false === $oAttDefMirrorLink->HasPHPComputation()){
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Register one object for later EVENT_DB_LINKS_CHANGED event.
|
||||
*
|
||||
@@ -6017,7 +6077,12 @@ JS
|
||||
|
||||
$sClass = get_class($this);
|
||||
$sId = $this->GetKey();
|
||||
self::FireEventDbLinksChangedForClassId($sClass, $sId);
|
||||
$bIsObjectAwaitingEventDbLinksChanged = self::RemoveObjectAwaitingEventDbLinksChanged($sClass, $sId);
|
||||
if (false === $bIsObjectAwaitingEventDbLinksChanged) {
|
||||
return;
|
||||
}
|
||||
self::FireEventDbLinksChangedForObject($this);
|
||||
self::RemoveObjectAwaitingEventDbLinksChanged($sClass, $sId);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -6049,9 +6114,15 @@ JS
|
||||
// We want to avoid launching the listener twice, first here, and secondly after saving the Ticket in the listener
|
||||
// By disabling the event to be fired, we can remove the current object from the attribute !
|
||||
$oObject = MetaModel::GetObject($sClass, $sId, false);
|
||||
self::FireEventDbLinksChangedForObject($oObject);
|
||||
self::RemoveObjectAwaitingEventDbLinksChanged($sClass, $sId);
|
||||
}
|
||||
|
||||
private static function FireEventDbLinksChangedForObject(DBObject $oObject)
|
||||
{
|
||||
self::SetEventDBLinksChangedBlocked(true);
|
||||
// N°6408 The object can have been deleted
|
||||
if (!is_null($oObject)) {
|
||||
self::SetEventDBLinksChangedBlocked(true);
|
||||
MetaModel::StartReentranceProtection($oObject);
|
||||
$oObject->FireEvent(EVENT_DB_LINKS_CHANGED);
|
||||
MetaModel::StopReentranceProtection($oObject);
|
||||
@@ -6059,7 +6130,6 @@ JS
|
||||
$oObject->DBUpdate();
|
||||
}
|
||||
}
|
||||
self::RemoveObjectAwaitingEventDbLinksChanged($sClass, $sId);
|
||||
cmdbAbstractObject::SetEventDBLinksChangedBlocked(false);
|
||||
}
|
||||
|
||||
|
||||
@@ -9,6 +9,8 @@ use Combodo\iTop\Application\UI\Base\Component\DataTable\DataTableSettings;
|
||||
use Combodo\iTop\Application\UI\Base\Component\PopoverMenu\PopoverMenu;
|
||||
use Combodo\iTop\Application\UI\Base\Component\Toolbar\ToolbarUIBlockFactory;
|
||||
use Combodo\iTop\Application\UI\Base\Layout\Dashboard\DashboardLayout as DashboardLayoutUIBlock;
|
||||
use Combodo\iTop\Application\WebPage\iTopWebPage;
|
||||
use Combodo\iTop\Application\WebPage\WebPage;
|
||||
|
||||
require_once(APPROOT.'application/dashboardlayout.class.inc.php');
|
||||
require_once(APPROOT.'application/dashlet.class.inc.php');
|
||||
@@ -422,7 +424,7 @@ abstract class Dashboard
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \WebPage $oPage *
|
||||
* @param WebPage $oPage *
|
||||
* @param array $aExtraParams
|
||||
*
|
||||
* @throws \ReflectionException
|
||||
@@ -513,7 +515,7 @@ EOF
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \WebPage $oPage
|
||||
* @param WebPage $oPage
|
||||
* @param bool $bEditMode
|
||||
* @param array $aExtraParams
|
||||
* @param bool $bCanEdit
|
||||
@@ -569,7 +571,7 @@ JS
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \WebPage $oPage
|
||||
* @param WebPage $oPage
|
||||
*
|
||||
* @throws \ReflectionException
|
||||
* @throws \Exception
|
||||
@@ -592,7 +594,7 @@ JS
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \WebPage $oPage
|
||||
* @param WebPage $oPage
|
||||
* @param array $aExtraParams
|
||||
*/
|
||||
public function RenderDashletsProperties(WebPage $oPage, $aExtraParams = array())
|
||||
@@ -1109,7 +1111,7 @@ JS
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \WebPage $oPage
|
||||
* @param WebPage $oPage
|
||||
* @param array $aExtraParams
|
||||
*
|
||||
* @throws \Exception
|
||||
@@ -1228,7 +1230,7 @@ EOF
|
||||
|
||||
|
||||
/**
|
||||
* @param \WebPage $oPage
|
||||
* @param WebPage $oPage
|
||||
*
|
||||
* @param array $aExtraParams
|
||||
*
|
||||
@@ -1488,7 +1490,7 @@ JS
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \WebPage $oPage
|
||||
* @param WebPage $oPage
|
||||
* @param $sOQL
|
||||
*
|
||||
* @throws \DictExceptionMissingString
|
||||
|
||||
@@ -19,6 +19,7 @@ use Combodo\iTop\Application\UI\Base\Component\Html\Html;
|
||||
use Combodo\iTop\Application\UI\Base\Layout\Dashboard\DashboardColumn;
|
||||
use Combodo\iTop\Application\UI\Base\Layout\Dashboard\DashboardLayout as DashboardLayoutUIBlock;
|
||||
use Combodo\iTop\Application\UI\Base\Layout\Dashboard\DashboardRow;
|
||||
use Combodo\iTop\Application\WebPage\WebPage;
|
||||
|
||||
/**
|
||||
* Dashboard presentation
|
||||
@@ -106,7 +107,7 @@ abstract class DashboardLayoutMultiCol extends DashboardLayout
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \WebPage $oPage
|
||||
* @param WebPage $oPage
|
||||
* @param $aCells
|
||||
* @param bool $bEditMode
|
||||
* @param array $aExtraParams
|
||||
|
||||
@@ -23,6 +23,7 @@ use Combodo\iTop\Application\UI\Base\Component\Html\Html;
|
||||
use Combodo\iTop\Application\UI\Base\Component\Panel\PanelUIBlockFactory;
|
||||
use Combodo\iTop\Application\UI\Base\iUIBlock;
|
||||
use Combodo\iTop\Application\UI\Base\UIBlock;
|
||||
use Combodo\iTop\Application\WebPage\WebPage;
|
||||
|
||||
require_once(APPROOT.'application/forms.class.inc.php');
|
||||
|
||||
@@ -222,7 +223,7 @@ abstract class Dashlet
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \WebPage $oPage
|
||||
* @param WebPage $oPage
|
||||
* @param bool $bEditMode
|
||||
* @param bool $bEnclosingDiv
|
||||
* @param array $aExtraParams
|
||||
@@ -298,7 +299,7 @@ EOF
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \WebPage $oPage
|
||||
* @param WebPage $oPage
|
||||
* @param bool $bEditMode
|
||||
* @param array $aExtraParams
|
||||
*
|
||||
@@ -309,7 +310,7 @@ EOF
|
||||
/**
|
||||
* Rendering without the real data
|
||||
*
|
||||
* @param \WebPage $oPage
|
||||
* @param WebPage $oPage
|
||||
* @param bool $bEditMode
|
||||
* @param array $aExtraParams
|
||||
*
|
||||
|
||||
@@ -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.2">
|
||||
<classes>
|
||||
<class id="AbstractResource" _delta="define">
|
||||
<parent>cmdbAbstractObject</parent>
|
||||
@@ -270,6 +270,23 @@
|
||||
</event_datum>
|
||||
</event_data>
|
||||
</event>
|
||||
<event id="EVENT_DB_ABOUT_TO_DELETE" _delta="define">
|
||||
<description>An object is about to be deleted from the database</description>
|
||||
<sources>
|
||||
<source id="cmdbAbstractObject">cmdbAbstractObject</source>
|
||||
</sources>
|
||||
<replaces>cmdbAbstractObject::OnDelete</replaces>
|
||||
<event_data>
|
||||
<event_datum id="object">
|
||||
<description>The object about to be deleted</description>
|
||||
<type>DBObject</type>
|
||||
</event_datum>
|
||||
<event_datum id="debug_info">
|
||||
<description>Debug string</description>
|
||||
<type>string</type>
|
||||
</event_datum>
|
||||
</event_data>
|
||||
</event>
|
||||
<event id="EVENT_DB_AFTER_DELETE" _delta="define">
|
||||
<description>An object has been deleted into the database</description>
|
||||
<sources>
|
||||
@@ -287,8 +304,8 @@
|
||||
</event_datum>
|
||||
</event_data>
|
||||
</event>
|
||||
<event id="EVENT_DB_BEFORE_APPLY_STIMULUS" _delta="define">
|
||||
<description>A stimulus is about to be applied to an object</description>
|
||||
<event id="EVENT_ENUM_TRANSITIONS" _delta="define">
|
||||
<description>Manage the allowed transitions in current object state. The only action allowed is to deny transitions with DBObject::DenyTransition()</description>
|
||||
<sources>
|
||||
<source id="cmdbAbstractObject">cmdbAbstractObject</source>
|
||||
</sources>
|
||||
@@ -297,89 +314,9 @@
|
||||
<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_DB_AFTER_APPLY_STIMULUS" _delta="define">
|
||||
<description>A stimulus has been applied to an object</description>
|
||||
<sources>
|
||||
<source id="cmdbAbstractObject">cmdbAbstractObject</source>
|
||||
</sources>
|
||||
<event_data>
|
||||
<event_datum id="object">
|
||||
<description>The object where the stimulus is targeted</description>
|
||||
<type>DBObject</type>
|
||||
</event_datum>
|
||||
<event_datum id="stimulus">
|
||||
<description>Current stimulus applied</description>
|
||||
<type>string</type>
|
||||
</event_datum>
|
||||
<event_datum id="previous_state">
|
||||
<description>Object previous state</description>
|
||||
<type>string</type>
|
||||
</event_datum>
|
||||
<event_datum id="new_state">
|
||||
<description>Object new state</description>
|
||||
<type>string</type>
|
||||
</event_datum>
|
||||
<event_datum id="save_object">
|
||||
<description>The object is asked to be saved in the database</description>
|
||||
<type>boolean</type>
|
||||
</event_datum>
|
||||
<event_datum id="debug_info">
|
||||
<description>Debug string</description>
|
||||
<type>string</type>
|
||||
</event_datum>
|
||||
</event_data>
|
||||
</event>
|
||||
<event id="EVENT_DB_APPLY_STIMULUS_FAILED" _delta="define">
|
||||
<description>A stimulus has failed</description>
|
||||
<sources>
|
||||
<source id="cmdbAbstractObject">cmdbAbstractObject</source>
|
||||
</sources>
|
||||
<event_data>
|
||||
<event_datum id="action">
|
||||
<description>The action that failed to apply the stimulus</description>
|
||||
<type>string</type>
|
||||
</event_datum>
|
||||
<event_datum id="object">
|
||||
<description>The object where the stimulus is targeted</description>
|
||||
<type>DBObject</type>
|
||||
</event_datum>
|
||||
<event_datum id="stimulus">
|
||||
<description>Current stimulus applied</description>
|
||||
<type>string</type>
|
||||
</event_datum>
|
||||
<event_datum id="previous_state">
|
||||
<description>Object previous state</description>
|
||||
<type>string</type>
|
||||
</event_datum>
|
||||
<event_datum id="new_state">
|
||||
<description>Object new state</description>
|
||||
<type>string</type>
|
||||
</event_datum>
|
||||
<event_datum id="save_object">
|
||||
<description>The object must be saved in the database</description>
|
||||
<type>boolean</type>
|
||||
<event_datum id="allowed_stimuli">
|
||||
<description>The list of available stimuli in the current state</description>
|
||||
<type>array</type>
|
||||
</event_datum>
|
||||
<event_datum id="debug_info">
|
||||
<description>Debug string</description>
|
||||
@@ -514,10 +451,18 @@
|
||||
<description>The object containing the document</description>
|
||||
<type>DBObject</type>
|
||||
</event_datum>
|
||||
<event_datum id="att_code">
|
||||
<description>The optional object attribute code hosting the document</description>
|
||||
<type>string</type>
|
||||
</event_datum>
|
||||
<event_datum id="document">
|
||||
<description>The document downloaded</description>
|
||||
<type>ormDocument</type>
|
||||
</event_datum>
|
||||
<event_datum id="content_disposition">
|
||||
<description>The content disposition of the document ("inline" or "attachment")</description>
|
||||
<type>string</type>
|
||||
</event_datum>
|
||||
<event_datum id="debug_info">
|
||||
<description>Debug string</description>
|
||||
<type>string</type>
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
<?php
|
||||
|
||||
use Combodo\iTop\Application\UI\Base\Component\DataTable\DataTableSettings;
|
||||
use Combodo\iTop\Application\WebPage\WebPage;
|
||||
use Combodo\iTop\Renderer\Console\ConsoleBlockRenderer;
|
||||
|
||||
/**
|
||||
@@ -61,8 +63,8 @@ class DataTable
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \WebPage $oPage
|
||||
* @param \DataTableSettings $oSettings
|
||||
* @param WebPage $oPage
|
||||
* @param DataTableSettings $oSettings
|
||||
* @param $bActionsMenu
|
||||
* @param $sSelectMode
|
||||
* @param $bViewLink
|
||||
@@ -141,7 +143,7 @@ class DataTable
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \WebPage $oPage
|
||||
* @param WebPage $oPage
|
||||
* @param $iPageSize
|
||||
* @param $iDefaultPageSize
|
||||
* @param $iPageIndex
|
||||
@@ -236,7 +238,7 @@ class DataTable
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \WebPage $oPage
|
||||
* @param WebPage $oPage
|
||||
* @param $sSelectMode
|
||||
*
|
||||
* @return string
|
||||
@@ -255,7 +257,7 @@ class DataTable
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \WebPage $oPage
|
||||
* @param WebPage $oPage
|
||||
* @param $iPageSize
|
||||
* @param $iDefaultPageSize
|
||||
* @param $iPageIndex
|
||||
@@ -348,7 +350,7 @@ EOF;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \WebPage $oPage
|
||||
* @param WebPage $oPage
|
||||
* @param $aExtraParams
|
||||
*
|
||||
* @return string
|
||||
@@ -375,7 +377,7 @@ EOF;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \WebPage $oPage
|
||||
* @param WebPage $oPage
|
||||
* @param $aExtraParams
|
||||
*
|
||||
* @return string
|
||||
@@ -405,7 +407,7 @@ EOF;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \WebPage $oPage
|
||||
* @param WebPage $oPage
|
||||
* @param $aColumns
|
||||
* @param $bViewLink
|
||||
* @param $iDefaultPageSize
|
||||
@@ -658,7 +660,7 @@ EOF;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \WebPage $oPage
|
||||
* @param WebPage $oPage
|
||||
* @param $aColumns
|
||||
* @param $sSelectMode
|
||||
* @param $iPageSize
|
||||
@@ -790,7 +792,7 @@ JS
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \WebPage $oPage
|
||||
* @param WebPage $oPage
|
||||
* @param $iDefaultPageSize
|
||||
* @param $iStart
|
||||
*/
|
||||
@@ -818,7 +820,7 @@ JS
|
||||
class PrintableDataTable extends DataTable
|
||||
{
|
||||
/**
|
||||
* @param \WebPage $oPage
|
||||
* @param WebPage $oPage
|
||||
* @param $iPageSize
|
||||
* @param $iDefaultPageSize
|
||||
* @param $iPageIndex
|
||||
@@ -844,7 +846,7 @@ class PrintableDataTable extends DataTable
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \WebPage $oPage
|
||||
* @param WebPage $oPage
|
||||
* @param $aColumns
|
||||
* @param $sSelectMode
|
||||
* @param $iPageSize
|
||||
|
||||
@@ -24,6 +24,8 @@ use Combodo\iTop\Application\UI\DisplayBlock\BlockChartAjaxBars\BlockChartAjaxBa
|
||||
use Combodo\iTop\Application\UI\DisplayBlock\BlockChartAjaxPie\BlockChartAjaxPie;
|
||||
use Combodo\iTop\Application\UI\DisplayBlock\BlockCsv\BlockCsv;
|
||||
use Combodo\iTop\Application\UI\DisplayBlock\BlockList\BlockList;
|
||||
use Combodo\iTop\Application\WebPage\iTopWebPage;
|
||||
use Combodo\iTop\Application\WebPage\WebPage;
|
||||
use Combodo\iTop\Service\Router\Router;
|
||||
|
||||
require_once(APPROOT.'/application/utils.inc.php');
|
||||
@@ -595,7 +597,7 @@ class DisplayBlock
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \WebPage $oPage
|
||||
* @param WebPage $oPage
|
||||
* @param array $aExtraParams
|
||||
*
|
||||
* @throws \ApplicationException
|
||||
@@ -1354,7 +1356,7 @@ JS
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \WebPage $oPage
|
||||
* @param WebPage $oPage
|
||||
* @param array $aExtraParams
|
||||
*
|
||||
* @return \Combodo\iTop\Application\UI\Base\iUIBlock
|
||||
@@ -1378,7 +1380,7 @@ JS
|
||||
|
||||
/**
|
||||
* @param array $aExtraParams
|
||||
* @param \WebPage $oPage
|
||||
* @param WebPage $oPage
|
||||
*
|
||||
* @throws \ArchivedObjectException
|
||||
* @throws \ConfigException
|
||||
@@ -1456,7 +1458,7 @@ JS
|
||||
|
||||
/**
|
||||
* @param array $aExtraParams
|
||||
* @param \WebPage $oPage
|
||||
* @param WebPage $oPage
|
||||
*
|
||||
* @return \Combodo\iTop\Application\UI\Base\Layout\UIContentBlock
|
||||
* @throws \ApplicationException
|
||||
@@ -1564,7 +1566,7 @@ JS
|
||||
/**
|
||||
* @deprecated 3.1.0 N°5957
|
||||
*
|
||||
* @param \WebPage $oPage
|
||||
* @param WebPage $oPage
|
||||
* @param array $aExtraParams
|
||||
*
|
||||
* @return \Combodo\iTop\Application\UI\Base\Component\Html\Html|\Combodo\iTop\Application\UI\Base\Layout\UIContentBlock|string
|
||||
@@ -1664,7 +1666,7 @@ JS
|
||||
|
||||
/**
|
||||
* @param array $aExtraParams
|
||||
* @param \WebPage $oPage
|
||||
* @param WebPage $oPage
|
||||
*
|
||||
* @throws \ArchivedObjectException
|
||||
* @throws \CoreException
|
||||
@@ -1830,7 +1832,7 @@ class MenuBlock extends DisplayBlock
|
||||
* an object in with the same tab active by default as the tab that was active when selecting
|
||||
* the "Modify..." action.
|
||||
*
|
||||
* @param \WebPage $oPage
|
||||
* @param WebPage $oPage
|
||||
* @param array $aExtraParams
|
||||
* @param string|null $sId
|
||||
*
|
||||
|
||||
@@ -1,4 +1,8 @@
|
||||
<?php
|
||||
|
||||
use Combodo\iTop\Application\WebPage\CLIPage;
|
||||
use Combodo\iTop\Application\WebPage\Page;
|
||||
|
||||
require_once('xlsxwriter.class.php');
|
||||
|
||||
class ExcelExporter
|
||||
|
||||
36
application/exceptions/InvalidExternalKeyValueException.php
Normal file
36
application/exceptions/InvalidExternalKeyValueException.php
Normal file
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @since 2.7.10 3.0.4 3.1.1 3.2.0 N°6458 object creation
|
||||
*/
|
||||
class InvalidExternalKeyValueException extends CoreUnexpectedValue
|
||||
{
|
||||
private const ENUM_PARAMS_OBJECT = 'current_object';
|
||||
private const ENUM_PARAMS_ATTCODE = 'attcode';
|
||||
private const ENUM_PARAMS_ATTVALUE = 'attvalue';
|
||||
private const ENUM_PARAMS_USER = 'current_user';
|
||||
|
||||
public function __construct($oObject, $sAttCode, $aContextData = null, $oPrevious = null)
|
||||
{
|
||||
$aContextData[self::ENUM_PARAMS_OBJECT] = get_class($oObject) . '::' . $oObject->GetKey();
|
||||
$aContextData[self::ENUM_PARAMS_ATTCODE] = $sAttCode;
|
||||
$aContextData[self::ENUM_PARAMS_ATTVALUE] = $oObject->Get($sAttCode);
|
||||
|
||||
$oCurrentUser = UserRights::GetUserObject();
|
||||
if (false === is_null($oCurrentUser)) {
|
||||
$aContextData[self::ENUM_PARAMS_USER] = get_class($oCurrentUser) . '::' . $oCurrentUser->GetKey();
|
||||
}
|
||||
|
||||
parent::__construct('Attribute pointing to an object that is either non existing or not readable by the current user', $aContextData, '', $oPrevious);
|
||||
}
|
||||
|
||||
public function GetAttCode(): string
|
||||
{
|
||||
return $this->getContextData()[self::ENUM_PARAMS_ATTCODE];
|
||||
}
|
||||
|
||||
public function GetAttValue(): string
|
||||
{
|
||||
return $this->getContextData()[self::ENUM_PARAMS_ATTVALUE];
|
||||
}
|
||||
}
|
||||
@@ -15,6 +15,7 @@
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with iTop. If not, see <http://www.gnu.org/licenses/>
|
||||
use Combodo\iTop\Application\WebPage\WebPage;
|
||||
|
||||
/**
|
||||
* Helper class to build interactive forms to be used either in stand-alone
|
||||
@@ -828,7 +829,7 @@ class DesignerFormField
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \WebPage $oP
|
||||
* @param WebPage $oP
|
||||
* @param string $sFormId
|
||||
* @param string $sRenderMode
|
||||
*
|
||||
|
||||
@@ -119,6 +119,11 @@ class LoginDefaultAfter extends AbstractLoginFSMExtension implements iLogoutExte
|
||||
protected function OnConnected(&$iErrorCode)
|
||||
{
|
||||
Session::Unset('login_temp_auth_user');
|
||||
if (is_null(UserRights::GetUserObject())){
|
||||
//N°7085 avoid infinite loop
|
||||
IssueLog::Error("No user logged in. exit");
|
||||
exit(-1);
|
||||
}
|
||||
return LoginWebPage::LOGIN_FSM_CONTINUE;
|
||||
}
|
||||
|
||||
@@ -134,4 +139,4 @@ class LoginDefaultAfter extends AbstractLoginFSMExtension implements iLogoutExte
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -140,7 +140,11 @@ class LoginForm extends AbstractLoginFSMExtension implements iLoginUIExtension
|
||||
$oLoginContext->AddBlockExtension('login_form_footer', new LoginBlockExtension('extensionblock/loginformfooter.html.twig'));
|
||||
|
||||
$bEnableResetPassword = MetaModel::GetConfig()->Get('forgot_password');
|
||||
$sResetPasswordUrl = utils::GetAbsoluteUrlAppRoot() . 'pages/UI.php?loginop=forgot_pwd';
|
||||
$sResetPasswordUrl = MetaModel::GetConfig()->Get('forgot_password.url');
|
||||
if ($sResetPasswordUrl == '')
|
||||
{
|
||||
$sResetPasswordUrl = utils::GetAbsoluteUrlAppRoot() . 'pages/UI.php?loginop=forgot_pwd';
|
||||
}
|
||||
$aData = array(
|
||||
'bEnableResetPassword' => $bEnableResetPassword,
|
||||
'sResetPasswordUrl' => $sResetPasswordUrl,
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
|
||||
use Combodo\iTop\Application\Branding;
|
||||
use Combodo\iTop\Application\TwigBase\Twig\Extension;
|
||||
use Combodo\iTop\Application\WebPage\NiceWebPage;
|
||||
use Twig\Environment;
|
||||
use Twig\Loader\ChainLoader;
|
||||
use Twig\Loader\FilesystemLoader;
|
||||
|
||||
@@ -26,6 +26,8 @@
|
||||
|
||||
use Combodo\iTop\Application\Branding;
|
||||
use Combodo\iTop\Application\Helper\Session;
|
||||
use Combodo\iTop\Application\WebPage\ErrorPage;
|
||||
use Combodo\iTop\Application\WebPage\NiceWebPage;
|
||||
use Combodo\iTop\Service\Events\EventData;
|
||||
use Combodo\iTop\Service\Events\EventService;
|
||||
|
||||
@@ -80,7 +82,7 @@ class LoginWebPage extends NiceWebPage
|
||||
}
|
||||
|
||||
protected static $m_sLoginFailedMessage = '';
|
||||
|
||||
|
||||
public function __construct($sTitle = null)
|
||||
{
|
||||
if ($sTitle === null) {
|
||||
@@ -90,7 +92,7 @@ class LoginWebPage extends NiceWebPage
|
||||
parent::__construct($sTitle);
|
||||
$this->SetStyleSheet();
|
||||
$this->no_cache();
|
||||
$this->add_xframe_options();
|
||||
$this->add_http_headers();
|
||||
}
|
||||
|
||||
public function SetStyleSheet()
|
||||
@@ -99,6 +101,15 @@ class LoginWebPage extends NiceWebPage
|
||||
$this->add_linked_stylesheet(utils::GetAbsoluteUrlAppRoot().'css/font-awesome/css/all.min.css');
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
* @since 3.2.0
|
||||
*/
|
||||
protected function GetFaviconAbsoluteUrl()
|
||||
{
|
||||
return Branding::GetLoginFavIconAbsoluteUrl();
|
||||
}
|
||||
|
||||
public static function SetLoginFailedMessage($sMessage)
|
||||
{
|
||||
self::$m_sLoginFailedMessage = $sMessage;
|
||||
@@ -908,13 +919,13 @@ class LoginWebPage extends NiceWebPage
|
||||
$aAllProfiles = array();
|
||||
while ($oProfile = $oProfilesSet->Fetch())
|
||||
{
|
||||
$aAllProfiles[strtolower($oProfile->GetName())] = $oProfile->GetKey();
|
||||
$aAllProfiles[mb_strtolower($oProfile->GetName())] = $oProfile->GetKey();
|
||||
}
|
||||
|
||||
$aProfiles = array();
|
||||
foreach ($aRequestedProfiles as $sRequestedProfile)
|
||||
{
|
||||
$sRequestedProfile = strtolower($sRequestedProfile);
|
||||
$sRequestedProfile = mb_strtolower($sRequestedProfile);
|
||||
if (isset($aAllProfiles[$sRequestedProfile]))
|
||||
{
|
||||
$aProfiles[] = $aAllProfiles[$sRequestedProfile];
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
// Maintenance message display functions
|
||||
// Only included by approot.inc.php
|
||||
//
|
||||
use Combodo\iTop\Application\WebPage\ErrorPage;
|
||||
|
||||
/**
|
||||
* Use a setup page to display the maintenance message
|
||||
|
||||
@@ -5,6 +5,9 @@
|
||||
*/
|
||||
|
||||
use Combodo\iTop\Application\Helper\WebResourcesHelper;
|
||||
use Combodo\iTop\Application\WebPage\ErrorPage;
|
||||
use Combodo\iTop\Application\WebPage\iTopWebPage;
|
||||
use Combodo\iTop\Application\WebPage\WebPage;
|
||||
|
||||
require_once(APPROOT.'/application/utils.inc.php');
|
||||
require_once(APPROOT.'/application/template.class.inc.php');
|
||||
@@ -103,7 +106,7 @@ class ApplicationMenu
|
||||
{
|
||||
self::$sFavoriteSiloQuery = $sOQL;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the query used to limit the list of displayed organizations in the drop-down menu
|
||||
* @return string The OQL query returning a list of Organization objects
|
||||
@@ -345,7 +348,7 @@ class ApplicationMenu
|
||||
|
||||
/**
|
||||
* Entry point to display the whole menu into the web page, used by iTopWebPage
|
||||
* @param \WebPage $oPage
|
||||
* @param WebPage $oPage
|
||||
* @param array $aExtraParams
|
||||
* @throws DictExceptionMissingString
|
||||
*
|
||||
@@ -419,7 +422,7 @@ EOF
|
||||
/**
|
||||
* Handles the display of the sub-menus (called recursively if necessary)
|
||||
*
|
||||
* @param \WebPage $oPage
|
||||
* @param WebPage $oPage
|
||||
* @param array $aMenus
|
||||
* @param array $aExtraParams
|
||||
* @param int $iActiveMenu
|
||||
@@ -536,7 +539,7 @@ EOF
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Retrieves the currently active menu (if any, otherwise the first menu is the default)
|
||||
* @return string The Id of the currently active menu
|
||||
@@ -544,7 +547,7 @@ EOF
|
||||
public static function GetActiveNodeId()
|
||||
{
|
||||
$oAppContext = new ApplicationContext();
|
||||
$sMenuId = $oAppContext->GetCurrentValue('menu', null);
|
||||
$sMenuId = $oAppContext->GetCurrentValue('menu', null);
|
||||
if ($sMenuId === null)
|
||||
{
|
||||
$sMenuId = self::GetDefaultMenuId();
|
||||
@@ -654,7 +657,7 @@ abstract class MenuNode
|
||||
|
||||
/**
|
||||
* Stimulus to check: if the user can 'apply' this stimulus, then she/he can see this menu
|
||||
*/
|
||||
*/
|
||||
protected $m_aEnableStimuli;
|
||||
|
||||
/**
|
||||
@@ -814,7 +817,7 @@ abstract class MenuNode
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Add a limiting display condition for the same menu node. The conditions will be combined with a AND
|
||||
* @param $oMenuNode MenuNode Another definition of the same menu node, with potentially different access restriction
|
||||
@@ -987,7 +990,7 @@ class TemplateMenuNode extends MenuNode
|
||||
* @var string
|
||||
*/
|
||||
protected $sTemplateFile;
|
||||
|
||||
|
||||
/**
|
||||
* Create a menu item based on a custom template and inserts it into the application's main menu
|
||||
* @param string $sMenuId Unique identifier of the menu (used to identify the menu for bookmarking, and for getting the labels from the dictionary)
|
||||
@@ -1058,7 +1061,7 @@ class OQLMenuNode extends MenuNode
|
||||
* @var bool|null
|
||||
*/
|
||||
protected $bSearchFormOpen;
|
||||
|
||||
|
||||
/**
|
||||
* Extra parameters to be passed to the display block to fine tune its appearence
|
||||
*/
|
||||
@@ -1091,7 +1094,7 @@ class OQLMenuNode extends MenuNode
|
||||
// Enhancement: we could set as the "enable" condition that the user has enough rights to "read" the objects
|
||||
// of the class specified by the OQL...
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set some extra parameters to be passed to the display block to fine tune its appearence
|
||||
* @param array $aParams paramCode => value. See DisplayBlock::GetDisplay for the meaning of the parameters
|
||||
@@ -1111,7 +1114,7 @@ class OQLMenuNode extends MenuNode
|
||||
*/
|
||||
public function RenderContent(WebPage $oPage, $aExtraParams = array())
|
||||
{
|
||||
ContextTag::AddContext(ContextTag::TAG_OBJECT_SEARCH);
|
||||
$oTag = new ContextTag(ContextTag::TAG_OBJECT_SEARCH);
|
||||
ApplicationMenu::CheckMenuIdEnabled($this->GetMenuId());
|
||||
OQLMenuNode::RenderOQLSearch
|
||||
(
|
||||
@@ -1120,7 +1123,7 @@ class OQLMenuNode extends MenuNode
|
||||
'Menu_'.$this->GetMenuId(),
|
||||
$this->bSearch, // Search pane
|
||||
$this->bSearchFormOpen, // Search open
|
||||
$oPage,
|
||||
$oPage,
|
||||
array_merge($this->m_aParams, $aExtraParams),
|
||||
true
|
||||
);
|
||||
@@ -1354,10 +1357,10 @@ class NewObjectMenuNode extends MenuNode
|
||||
{
|
||||
// Enable this menu, only if the current user has enough rights to create such an object, or an object of
|
||||
// any child class
|
||||
|
||||
|
||||
$aSubClasses = MetaModel::EnumChildClasses($this->sClass, ENUM_CHILD_CLASSES_ALL); // Including the specified class itself
|
||||
$bActionIsAllowed = false;
|
||||
|
||||
|
||||
foreach($aSubClasses as $sCandidateClass)
|
||||
{
|
||||
if (!MetaModel::IsAbstract($sCandidateClass) && (UserRights::IsActionAllowed($sCandidateClass, UR_ACTION_MODIFY) == UR_ALLOWED_YES))
|
||||
@@ -1366,7 +1369,7 @@ class NewObjectMenuNode extends MenuNode
|
||||
break; // Enough for now
|
||||
}
|
||||
}
|
||||
return $bActionIsAllowed;
|
||||
return $bActionIsAllowed;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1508,7 +1511,7 @@ class DashboardMenuNode extends MenuNode
|
||||
throw new Exception("Error: failed to load dashboard file: '{$this->sDashboardFile}'");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1549,7 +1552,7 @@ class ShortcutContainerMenuNode extends MenuNode
|
||||
$sName = $this->GetMenuId().'_'.$oShortcut->GetKey();
|
||||
new ShortcutMenuNode($sName, $oShortcut, $this->GetIndex(), $fRank++);
|
||||
}
|
||||
|
||||
|
||||
// Complete the tree
|
||||
//
|
||||
parent::PopulateChildMenus();
|
||||
|
||||
@@ -21,6 +21,7 @@ use Combodo\iTop\Application\UI\Base\Component\Alert\AlertUIBlockFactory;
|
||||
use Combodo\iTop\Application\UI\Base\Component\FieldSet\FieldSetUIBlockFactory;
|
||||
use Combodo\iTop\Application\UI\Base\Component\Html\Html;
|
||||
use Combodo\iTop\Application\UI\Base\Component\Input\TextArea;
|
||||
use Combodo\iTop\Application\WebPage\WebPage;
|
||||
|
||||
abstract class Query extends cmdbAbstractObject
|
||||
{
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with iTop. If not, see <http://www.gnu.org/licenses/>
|
||||
use Combodo\iTop\Application\UI\Base\Component\DataTable\DataTableSettings;
|
||||
use Combodo\iTop\Application\WebPage\WebPage;
|
||||
|
||||
|
||||
/**
|
||||
|
||||
@@ -17,6 +17,9 @@
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
*/
|
||||
|
||||
use Combodo\iTop\Application\WebPage\iTopWebPage;
|
||||
use Combodo\iTop\Application\WebPage\WebPage;
|
||||
|
||||
require_once(APPROOT.'/application/displayblock.class.inc.php');
|
||||
/**
|
||||
* This class manages the special template format used internally to build the iTop web pages
|
||||
|
||||
@@ -536,7 +536,7 @@ CSS;
|
||||
if (static::HasImageExtension($sImg)
|
||||
&& ! array_key_exists($sImg, $aImages))
|
||||
{
|
||||
$sFilePath = realpath($sImg);
|
||||
$sFilePath = utils::RealPath($sImg, APPROOT);
|
||||
if ($sFilePath !== false) {
|
||||
$sFilePathWithSlashes = str_replace('\\', '/', $sFilePath);
|
||||
$aImages[$sImg] = $sFilePathWithSlashes;
|
||||
@@ -544,7 +544,7 @@ CSS;
|
||||
}
|
||||
|
||||
$sCanonicalPath = static::CanonicalizePath($sTargetThemeFolderPath.'/'.$sImg);
|
||||
$sFilePath = realpath($sCanonicalPath);
|
||||
$sFilePath = utils::RealPath($sCanonicalPath, APPROOT);
|
||||
if ($sFilePath !== false) {
|
||||
$sFilePathWithSlashes = str_replace('\\', '/', $sFilePath);
|
||||
$aImages[$sImg] = $sFilePathWithSlashes;
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
use Combodo\iTop\Application\Helper\FormHelper;
|
||||
use Combodo\iTop\Application\UI\Base\Component\Form\FormUIBlockFactory;
|
||||
use Combodo\iTop\Application\UI\Base\Layout\UIContentBlockUIBlockFactory;
|
||||
use Combodo\iTop\Application\WebPage\WebPage;
|
||||
use Combodo\iTop\Core\MetaModel\FriendlyNameType;
|
||||
|
||||
require_once(APPROOT.'/application/displayblock.class.inc.php');
|
||||
@@ -65,7 +66,7 @@ class UIExtKeyWidget
|
||||
//public function __construct($sAttCode, $sClass, $sTitle, $oAllowedValues, $value, $iInputId, $bMandatory, $sNameSuffix = '', $sFieldPrefix = '', $sFormPrefix = '')
|
||||
|
||||
/**
|
||||
* @param \WebPage $oPage
|
||||
* @param WebPage $oPage
|
||||
* @param string $sAttCode
|
||||
* @param string $sClass
|
||||
* @param string $sTitle
|
||||
@@ -132,7 +133,7 @@ class UIExtKeyWidget
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \WebPage $oPage
|
||||
* @param WebPage $oPage
|
||||
* @param int $iMaxComboLength
|
||||
* @param bool $bAllowTargetCreation
|
||||
* @param string $sTitle
|
||||
@@ -444,7 +445,7 @@ JS
|
||||
/**
|
||||
* Get the HTML fragment corresponding to the ext key editing widget
|
||||
*
|
||||
* @param \WebPage $oPage
|
||||
* @param WebPage $oPage
|
||||
* @param int $iMaxComboLength
|
||||
* @param boolean $bAllowTargetCreation
|
||||
* @param string $sTitle
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with iTop. If not, see <http://www.gnu.org/licenses/>
|
||||
use Combodo\iTop\Application\Helper\WebResourcesHelper;
|
||||
use Combodo\iTop\Application\WebPage\WebPage;
|
||||
|
||||
/**
|
||||
* Class UIHTMLEditorWidget
|
||||
@@ -71,15 +72,16 @@ class UIHTMLEditorWidget
|
||||
// To change the default settings of the editor,
|
||||
// a) edit the file /js/ckeditor/config.js
|
||||
// b) or override some of the configuration settings, using the second parameter of ckeditor()
|
||||
$sJSDefineWidth = '';
|
||||
$aConfig = utils::GetCkeditorPref();
|
||||
$sWidthSpec = addslashes(trim($this->m_oAttDef->GetWidth()));
|
||||
if ($sWidthSpec != '')
|
||||
{
|
||||
$aConfig['width'] = $sWidthSpec;
|
||||
if ($sWidthSpec != '') {
|
||||
/*N°6543 - the function min allow to keep text inside the column when width is defined*/
|
||||
$aConfig['width'] = "min($sWidthSpec,100%)";
|
||||
$sJSDefineWidth = '$("#cke_'.$iId.' iframe").contents().find("body").css("width", "'.$sWidthSpec.'")';
|
||||
}
|
||||
$sHeightSpec = addslashes(trim($this->m_oAttDef->GetHeight()));
|
||||
if ($sHeightSpec != '')
|
||||
{
|
||||
if ($sHeightSpec != '') {
|
||||
$aConfig['height'] = $sHeightSpec;
|
||||
}
|
||||
$sConfigJS = json_encode($aConfig);
|
||||
@@ -110,6 +112,7 @@ $('#$iId').on('update', function(evt){
|
||||
else
|
||||
{
|
||||
oMe.data('ckeditorInstance').setReadOnly(oMe.prop('disabled'));
|
||||
$sJSDefineWidth
|
||||
}
|
||||
};
|
||||
setTimeout(delayedSetReadOnly, 50);
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
|
||||
use Combodo\iTop\Application\Helper\FormHelper;
|
||||
use Combodo\iTop\Application\UI\Links\Direct\BlockDirectLinkSetEditTable;
|
||||
use Combodo\iTop\Application\WebPage\WebPage;
|
||||
use Combodo\iTop\Renderer\Console\ConsoleBlockRenderer;
|
||||
|
||||
/**
|
||||
|
||||
@@ -8,6 +8,8 @@ use Combodo\iTop\Application\UI\Base\Component\DataTable\DataTableUIBlockFactory
|
||||
use Combodo\iTop\Application\UI\Base\Component\DataTable\StaticTable\FormTableRow\FormTableRow;
|
||||
use Combodo\iTop\Application\UI\Links\Indirect\BlockIndirectLinkSetEditTable;
|
||||
use Combodo\iTop\Application\UI\Links\Indirect\BlockObjectPickerDialog;
|
||||
use Combodo\iTop\Application\WebPage\JsonPage;
|
||||
use Combodo\iTop\Application\WebPage\WebPage;
|
||||
use Combodo\iTop\Renderer\Console\ConsoleBlockRenderer;
|
||||
|
||||
require_once(APPROOT.'application/displayblock.class.inc.php');
|
||||
|
||||
@@ -24,6 +24,8 @@
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
use Combodo\iTop\Application\WebPage\WebPage;
|
||||
|
||||
require_once(APPROOT.'/application/displayblock.class.inc.php');
|
||||
|
||||
class UIPasswordWidget
|
||||
|
||||
@@ -21,6 +21,8 @@
|
||||
*/
|
||||
|
||||
|
||||
use Combodo\iTop\Application\WebPage\WebPage;
|
||||
|
||||
require_once(APPROOT.'/application/displayblock.class.inc.php');
|
||||
|
||||
class UISearchFormForeignKeys
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with iTop. If not, see <http://www.gnu.org/licenses/>
|
||||
use Combodo\iTop\Application\WebPage\iTopWebPage;
|
||||
|
||||
|
||||
/**
|
||||
|
||||
@@ -20,7 +20,10 @@
|
||||
use Combodo\iTop\Application\Helper\Session;
|
||||
use Combodo\iTop\Application\UI\Base\iUIBlock;
|
||||
use Combodo\iTop\Application\UI\Base\Layout\UIContentBlock;
|
||||
use Combodo\iTop\Application\UI\Hook\iKeyboardShortcut;
|
||||
use Combodo\iTop\Application\WebPage\WebPage;
|
||||
use Combodo\iTop\Service\Module\ModuleService;
|
||||
use Combodo\iTop\Test\UnitTest\Application\utilsTest;
|
||||
use ScssPhp\ScssPhp\Compiler;
|
||||
use ScssPhp\ScssPhp\OutputStyle;
|
||||
use ScssPhp\ScssPhp\ValueConverter;
|
||||
@@ -165,7 +168,11 @@ class utils
|
||||
|
||||
private static $iNextId = 0;
|
||||
|
||||
private static $m_sAppRootUrl = null;
|
||||
/**
|
||||
* @var ?string
|
||||
* @used-by GetAbsoluteUrlAppRoot
|
||||
*/
|
||||
private static $sAbsoluteUrlAppRootCache = null;
|
||||
|
||||
protected static function LoadParamFile($sParamFile)
|
||||
{
|
||||
@@ -1035,28 +1042,27 @@ class utils
|
||||
return $bTrustProxies;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the absolute URL to the application root path
|
||||
*
|
||||
* @param bool $bForceTrustProxy
|
||||
*
|
||||
* @return string The absolute URL to the application root, without the first slash
|
||||
*
|
||||
* @throws \Exception
|
||||
*
|
||||
* @since 2.7.4 $bForceTrustProxy param added
|
||||
*/
|
||||
/**
|
||||
* Returns the absolute URL to the application root path
|
||||
*
|
||||
* @param bool $bForceTrustProxy
|
||||
*
|
||||
* @return string The absolute URL to the application root, without the first slash
|
||||
*
|
||||
* @throws \Exception
|
||||
*
|
||||
* @since 2.7.4 $bForceTrustProxy param added
|
||||
*/
|
||||
public static function GetAbsoluteUrlAppRoot($bForceTrustProxy = false)
|
||||
{
|
||||
$sUrl = static::$m_sAppRootUrl;
|
||||
if ($sUrl === null || $bForceTrustProxy)
|
||||
if (static::$sAbsoluteUrlAppRootCache === null || $bForceTrustProxy)
|
||||
{
|
||||
$sUrl = self::GetConfig()->Get('app_root_url');
|
||||
if ($sUrl == '')
|
||||
static::$sAbsoluteUrlAppRootCache = self::GetConfig()->Get('app_root_url');
|
||||
if (static::$sAbsoluteUrlAppRootCache == '')
|
||||
{
|
||||
$sUrl = self::GetDefaultUrlAppRoot($bForceTrustProxy);
|
||||
static::$sAbsoluteUrlAppRootCache = self::GetDefaultUrlAppRoot($bForceTrustProxy);
|
||||
}
|
||||
elseif (strpos($sUrl, SERVER_NAME_PLACEHOLDER) > -1)
|
||||
elseif (strpos(static::$sAbsoluteUrlAppRootCache, SERVER_NAME_PLACEHOLDER) > -1)
|
||||
{
|
||||
if (isset($_SERVER['SERVER_NAME']))
|
||||
{
|
||||
@@ -1067,11 +1073,10 @@ class utils
|
||||
// CLI mode ?
|
||||
$sServerName = php_uname('n');
|
||||
}
|
||||
$sUrl = str_replace(SERVER_NAME_PLACEHOLDER, $sServerName, $sUrl);
|
||||
static::$sAbsoluteUrlAppRootCache = str_replace(SERVER_NAME_PLACEHOLDER, $sServerName, static::$sAbsoluteUrlAppRootCache);
|
||||
}
|
||||
static::$m_sAppRootUrl = $sUrl;
|
||||
}
|
||||
return static::$m_sAppRootUrl;
|
||||
return static::$sAbsoluteUrlAppRootCache;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1453,7 +1458,7 @@ class utils
|
||||
/**
|
||||
* Merge standard menu items with plugin provided menus items
|
||||
*
|
||||
* @param \WebPage $oPage
|
||||
* @param WebPage $oPage
|
||||
* @param int $iMenuId
|
||||
* @param \DBObjectSet $param
|
||||
* @param array $aActions
|
||||
@@ -2499,15 +2504,17 @@ SQL;
|
||||
$aHeaders = static::ParseHeaders($http_response_header);
|
||||
$sMimeType = array_key_exists('Content-Type', $aHeaders) ? strtolower($aHeaders['Content-Type']) : 'application/x-octet-stream';
|
||||
// Compute the file extension from the MIME Type
|
||||
foreach($aKnownExtensions as $sExtValue => $sMime)
|
||||
{
|
||||
if ($sMime === $sMimeType)
|
||||
{
|
||||
foreach ($aKnownExtensions as $sExtValue => $sMime) {
|
||||
if ($sMime === $sMimeType) {
|
||||
$sExtension = '.'.$sExtValue;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
$sPathName = pathinfo($sPath, PATHINFO_FILENAME);
|
||||
if (utils::IsNotNullOrEmptyString($sPathName)) {
|
||||
$sFileName = $sPathName;
|
||||
}
|
||||
$sFileName .= $sExtension;
|
||||
}
|
||||
$oUploadedDoc = new ormDocument($sData, $sMimeType, $sFileName);
|
||||
@@ -2954,7 +2961,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[\\\\/]', '[\\\\/]tests[\\\\/]'));
|
||||
$aShortcutClasses = utils::GetClassesForInterface(iKeyboardShortcut::class, '', array('[\\\\/]lib[\\\\/]', '[\\\\/]node_modules[\\\\/]', '[\\\\/]test[\\\\/]', '[\\\\/]tests[\\\\/]'));
|
||||
|
||||
foreach ($aShortcutClasses as $cShortcutPlugin) {
|
||||
$sTriggeredElement = $cShortcutPlugin::GetShortcutTriggeredElementSelector();
|
||||
@@ -3029,6 +3036,7 @@ HTML;
|
||||
*
|
||||
* @return bool if string null or empty
|
||||
* @since 3.0.2 N°5302
|
||||
* @since 2.7.10 N°6458 add method in the 2.7 branch
|
||||
*/
|
||||
public static function IsNullOrEmptyString(?string $sString): bool
|
||||
{
|
||||
@@ -3044,6 +3052,7 @@ HTML;
|
||||
*
|
||||
* @return bool if string is not null and not empty
|
||||
* @since 3.0.2 N°5302
|
||||
* @since 2.7.10 N°6458 add method in the 2.7 branch
|
||||
*/
|
||||
public static function IsNotNullOrEmptyString(?string $sString): bool
|
||||
{
|
||||
|
||||
@@ -24,6 +24,8 @@
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
use Combodo\iTop\Application\WebPage\WebPage;
|
||||
|
||||
require_once(APPROOT.'/application/uiwizard.class.inc.php');
|
||||
|
||||
class WizardHelper
|
||||
@@ -367,7 +369,7 @@ JS;
|
||||
/**
|
||||
* Add necessary JS snippets (to the page) to be executed for fields update
|
||||
*
|
||||
* @param \WebPage $oPage
|
||||
* @param WebPage $oPage
|
||||
* @return void
|
||||
* @since 3.0.3-2 3.0.4 3.1.1 3.2.0 N°6766
|
||||
*/
|
||||
|
||||
@@ -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.2');
|
||||
|
||||
/**
|
||||
* Constant containing the iTop core version, whatever application was built
|
||||
@@ -23,11 +23,13 @@ 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.2.0');
|
||||
|
||||
/**
|
||||
* @since 3.0.4 N°6274 Allow to test if PHPUnit is currently running. Starting with PHPUnit 9.5 we'll be able to replace it with $GLOBALS['phpunit_version']
|
||||
* @var string
|
||||
* @since 3.0.4 3.1.0 3.2.0 N°6274 Allow to test if PHPUnit is currently running. Starting with PHPUnit 9.5 we'll be able to replace it with $GLOBALS['phpunit_version']
|
||||
* @since 3.0.4 3.1.1 3.2.0 N°6976 Fix constant name (DeprecatedCallsLog error handler was never set)
|
||||
*/
|
||||
define('ITOP_PHPUNIT_RUNNING_CONSTANT_NAME', 'ITOP_PHPUNIT_RUNNING');
|
||||
const ITOP_PHPUNIT_RUNNING_CONSTANT_NAME = 'ITOP_PHPUNIT_RUNNING';
|
||||
|
||||
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": ">=8.1.0 <8.4.0",
|
||||
"ext-ctype": "*",
|
||||
"ext-dom": "*",
|
||||
"ext-gd": "*",
|
||||
@@ -13,28 +13,32 @@
|
||||
"ext-mysqli": "*",
|
||||
"ext-soap": "*",
|
||||
"apereo/phpcas": "~1.6.0",
|
||||
"combodo/tcpdf": "~6.4.4",
|
||||
"firebase/php-jwt": "~6.4.0",
|
||||
"firebase/php-jwt": "^6.4.0",
|
||||
"guzzlehttp/guzzle": "^7.5.1",
|
||||
"laminas/laminas-mail": "^2.11",
|
||||
"laminas/laminas-servicemanager": "^3.5",
|
||||
"league/oauth2-google": "^3.0",
|
||||
"nikic/php-parser": "~4.14.0",
|
||||
"league/oauth2-google": "^4.0.1",
|
||||
"nikic/php-parser": "^4.14.0",
|
||||
"pear/archive_tar": "~1.4.14",
|
||||
"pelago/emogrifier": "^6.0.0",
|
||||
"scssphp/scssphp": "^1.10.3",
|
||||
"symfony/console": "5.4.*",
|
||||
"symfony/dotenv": "5.4.*",
|
||||
"symfony/framework-bundle": "5.4.*",
|
||||
"symfony/http-foundation": "5.4.*",
|
||||
"symfony/http-kernel": "5.4.*",
|
||||
"symfony/twig-bundle": "5.4.*",
|
||||
"symfony/yaml": "5.4.*",
|
||||
"pelago/emogrifier": "^7.2.0",
|
||||
"psr/log": "^3.0.0",
|
||||
"scssphp/scssphp": "^1.12.1",
|
||||
"symfony/console": "~6.4.0",
|
||||
"symfony/dotenv": "~6.4.0",
|
||||
"symfony/framework-bundle": "~6.4.0",
|
||||
"symfony/http-foundation": "~6.4.0",
|
||||
"symfony/http-kernel": "~6.4.0",
|
||||
"symfony/runtime": "~6.4.0",
|
||||
"symfony/twig-bundle": "~6.4.0",
|
||||
"symfony/var-dumper": "~6.4.0",
|
||||
"symfony/yaml": "~6.4.0",
|
||||
"tecnickcom/tcpdf": "^6.6.0",
|
||||
"thenetworg/oauth2-azure": "^2.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"symfony/stopwatch": "5.4.*",
|
||||
"symfony/web-profiler-bundle": "5.4.*"
|
||||
"symfony/debug-bundle": "~6.4.0",
|
||||
"symfony/stopwatch": "~6.4.0",
|
||||
"symfony/web-profiler-bundle": "~6.4.0"
|
||||
},
|
||||
"suggest": {
|
||||
"ext-libsodium": "Required to use the AttributeEncryptedString.",
|
||||
@@ -46,7 +50,7 @@
|
||||
},
|
||||
"config": {
|
||||
"platform": {
|
||||
"php": "7.4.0"
|
||||
"php": "8.1.0"
|
||||
},
|
||||
"vendor-dir": "lib",
|
||||
"preferred-install": {
|
||||
@@ -54,7 +58,10 @@
|
||||
},
|
||||
"sort-packages": true,
|
||||
"classmap-authoritative": true,
|
||||
"platform-check": true
|
||||
"platform-check": true,
|
||||
"allow-plugins": {
|
||||
"symfony/runtime": true
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"classmap": [
|
||||
@@ -72,6 +79,9 @@
|
||||
"application/logindefault.class.inc.php",
|
||||
"application/loginexternal.class.inc.php",
|
||||
"application/loginurl.class.inc.php"
|
||||
],
|
||||
"files": [
|
||||
"sources/alias.php"
|
||||
]
|
||||
},
|
||||
"conflict": {
|
||||
@@ -81,11 +91,15 @@
|
||||
"symfony": {
|
||||
"allow-contrib": false,
|
||||
"require": "3.4.*"
|
||||
},
|
||||
"runtime": {
|
||||
"dotenv_path": "symfony/.env"
|
||||
}
|
||||
},
|
||||
"scripts": {
|
||||
"post-install-cmd": ["@rmDeniedTestDir"],
|
||||
"post-update-cmd": ["@rmDeniedTestDir"],
|
||||
"rmDeniedTestDir": "@php .make/composer/rmDeniedTestDir.php"
|
||||
"post-install-cmd": ["@rmDeniedTestDir", "@tcpdfCustomFonts"],
|
||||
"post-update-cmd": ["@rmDeniedTestDir", "@tcpdfCustomFonts"],
|
||||
"rmDeniedTestDir": "@php .make/composer/rmDeniedTestDir.php",
|
||||
"tcpdfCustomFonts": "@php .make/composer/tcpdf/tcpdfUpdateFonts.php"
|
||||
}
|
||||
}
|
||||
|
||||
2073
composer.lock
generated
2073
composer.lock
generated
File diff suppressed because it is too large
Load Diff
@@ -521,6 +521,6 @@ class Str
|
||||
|
||||
public static function islowcase($sString)
|
||||
{
|
||||
return (strtolower($sString) == $sString);
|
||||
return (mb_strtolower($sString) == $sString);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,6 +17,11 @@
|
||||
// along with iTop. If not, see <http://www.gnu.org/licenses/>
|
||||
|
||||
use Combodo\iTop\Application\TwigBase\Twig\TwigHelper;
|
||||
use Combodo\iTop\Application\UI\Base\Component\DataTable\DataTableUIBlockFactory;
|
||||
use Combodo\iTop\Application\WebPage\WebPage;
|
||||
use Combodo\iTop\Service\Notification\NotificationsRepository;
|
||||
use Combodo\iTop\Service\Notification\NotificationsService;
|
||||
use Combodo\iTop\Service\Router\Router;
|
||||
|
||||
/**
|
||||
* Persistent classes (internal): user defined actions
|
||||
@@ -76,6 +81,7 @@ abstract class Action extends cmdbAbstractObject
|
||||
|
||||
MetaModel::Init_AddAttribute(new AttributeLinkedSetIndirect("trigger_list",
|
||||
array("linked_class" => "lnkTriggerAction", "ext_key_to_me" => "action_id", "ext_key_to_remote" => "trigger_id", "allowed_values" => null, "count_min" => 0, "count_max" => 0, "depends_on" => array(), "display_style" => 'property')));
|
||||
MetaModel::Init_AddAttribute(new AttributeEnum("asynchronous", array("allowed_values" => new ValueSetEnum(['use_global_setting' => 'Use global settings','yes' => 'Yes' ,'no' => 'No']), "sql" => "asynchronous", "default_value" => 'use_global_setting', "is_null_allowed" => false, "depends_on" => array())));
|
||||
|
||||
// Display lists
|
||||
// - Attributes to be displayed for the complete details
|
||||
@@ -167,6 +173,100 @@ abstract class Action extends cmdbAbstractObject
|
||||
$this->m_aCheckWarnings[] = Dict::S('Action:WarningNoTriggerLinked');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 3.2.0 N°5472 method creation
|
||||
*/
|
||||
public function DisplayBareRelations(WebPage $oPage, $bEditMode = false)
|
||||
{
|
||||
parent::DisplayBareRelations($oPage, false);
|
||||
|
||||
if ($oPage instanceof iTopWebPage) {
|
||||
$this->GenerateLastExecutionsTab($oPage, $bEditMode);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 3.2.0 N°5472 method creation
|
||||
*/
|
||||
protected function GenerateLastExecutionsTab(iTopWebPage $oPage, $bEditMode)
|
||||
{
|
||||
$oRouter = Router::GetInstance();
|
||||
$sActionLastExecutionsPageUrl = $oRouter->GenerateUrl('notifications.action.last_executions_tab', ['action_id' => $this->GetKey()]);
|
||||
$oPage->AddAjaxTab('action_errors', $sActionLastExecutionsPageUrl, false, Dict::S('Action:last_executions_tab'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \Combodo\iTop\Application\WebPage\WebPage $oPage
|
||||
*
|
||||
* @throws \ApplicationException
|
||||
* @throws \ArchivedObjectException
|
||||
* @throws \ConfigException
|
||||
* @throws \CoreException
|
||||
* @throws \CoreUnexpectedValue
|
||||
* @throws \DictExceptionMissingString
|
||||
* @throws \InvalidConfigParamException
|
||||
* @throws \MissingQueryArgument
|
||||
* @throws \MySQLException
|
||||
* @throws \MySQLHasGoneAwayException
|
||||
* @throws \OQLException
|
||||
* @throws \ReflectionException
|
||||
* @since 3.2.0 N°5472 method creation
|
||||
*/
|
||||
public function GetLastExecutionsTabContent(WebPage $oPage): void
|
||||
{
|
||||
$oConfig = utils::GetConfig();
|
||||
$sLastExecutionDaysConfigParamName = 'notifications.last_executions_days';
|
||||
$iLastExecutionDays = $oConfig->Get($sLastExecutionDaysConfigParamName);
|
||||
|
||||
if ($iLastExecutionDays < 0) {
|
||||
throw new InvalidConfigParamException("Invalid value for {$sLastExecutionDaysConfigParamName} config parameter. Param desc: " . $oConfig->GetDescription($sLastExecutionDaysConfigParamName));
|
||||
}
|
||||
|
||||
$sActionQueryOql = 'SELECT EventNotification WHERE action_id = :action_id';
|
||||
$aActionQueryParams = ['action_id' => $this->GetKey()];
|
||||
if ($iLastExecutionDays > 0) {
|
||||
$sActionQueryOql .= ' AND date > DATE_SUB(NOW(), INTERVAL :days DAY)';
|
||||
$aActionQueryParams['days'] = $iLastExecutionDays;
|
||||
$sActionQueryLimit = Dict::Format('Action:last_executions_tab_limit_days', $iLastExecutionDays);
|
||||
} else {
|
||||
$sActionQueryLimit = Dict::S('Action:last_executions_tab_limit_none');
|
||||
}
|
||||
|
||||
$oActionFilter = DBObjectSearch::FromOQL($sActionQueryOql, $aActionQueryParams);
|
||||
$oSet = new DBObjectSet($oActionFilter, ['date' => false]);
|
||||
|
||||
$sPanelTitle = Dict::Format('Action:last_executions_tab_panel_title', $sActionQueryLimit);
|
||||
$oExecutionsListBlock = DataTableUIBlockFactory::MakeForResult($oPage, 'action_executions_list', $oSet, ['panel_title' => $sPanelTitle]);
|
||||
|
||||
$oPage->AddUiBlock($oExecutionsListBlock);
|
||||
}
|
||||
|
||||
/**
|
||||
* Will be overloaded by the children classes to return the value of their global asynchronous setting (eg. `email_asynchronous` for `\ActionEmail`, `prefer_asynchronous` for `\ActionWebhook`, ...)
|
||||
*
|
||||
* @return bool true if the global setting for this kind of action if to be executed asynchronously, false otherwise.
|
||||
* @since 3.2.0
|
||||
*/
|
||||
public static function GetAsynchronousGlobalSetting(): bool
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool true if that action instance should be executed asynchronously, otherwise false
|
||||
* @throws \ArchivedObjectException
|
||||
* @throws \CoreException
|
||||
* @since 3.2.0
|
||||
*/
|
||||
public function IsAsynchronous(): bool
|
||||
{
|
||||
$sAsynchronous = $this->Get('asynchronous');
|
||||
if ($sAsynchronous === 'use_global_setting') {
|
||||
return static::GetAsynchronousGlobalSetting();
|
||||
}
|
||||
return $sAsynchronous === 'yes';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -201,12 +301,39 @@ abstract class ActionNotification extends Action
|
||||
MetaModel::Init_SetZListItems('details', array('name', 'description', 'status', 'trigger_list'));
|
||||
// - Attributes to be displayed for a list
|
||||
MetaModel::Init_SetZListItems('list', array('finalclass', 'description', 'status'));
|
||||
MetaModel::Init_AddAttribute(new AttributeApplicationLanguage("language", array("sql"=>"language", "default_value"=>null, "is_null_allowed"=>true, "depends_on"=>array())));
|
||||
|
||||
// Search criteria
|
||||
// - Criteria of the std search form
|
||||
// MetaModel::Init_SetZListItems('standard_search', array('name'));
|
||||
// - Default criteria of the search form
|
||||
// MetaModel::Init_SetZListItems('default_search', array('name'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $sLanguage
|
||||
* @param $sLanguageCode
|
||||
*
|
||||
* @return array [$sPreviousLanguage, $aPreviousPluginProperties]
|
||||
* @throws \ArchivedObjectException
|
||||
* @throws \CoreException
|
||||
* @throws \DictExceptionUnknownLanguage
|
||||
* @since 3.2.0
|
||||
*/
|
||||
public function SetNotificationLanguage($sLanguage = null, $sLanguageCode = null){
|
||||
$sPreviousLanguage = Dict::GetUserLanguage();
|
||||
$aPreviousPluginProperties = ApplicationContext::GetPluginProperties('QueryLocalizerPlugin');
|
||||
$sLanguage = $sLanguage ?? $this->Get('language');
|
||||
$sLanguageCode = $sLanguageCode ?? $sLanguage;
|
||||
if (!utils::IsNullOrEmptyString($sLanguage)) {
|
||||
// If a language is specified for this action, force this language
|
||||
// when rendering all placeholders inside this message
|
||||
Dict::SetUserLanguage($sLanguage);
|
||||
AttributeDateTime::LoadFormatFromConfig();
|
||||
ApplicationContext::SetPluginProperty('QueryLocalizerPlugin', 'language_code', $sLanguageCode);
|
||||
}
|
||||
return [$sPreviousLanguage, $aPreviousPluginProperties];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -257,6 +384,7 @@ class ActionEmail extends ActionNotification
|
||||
"db_table" => "priv_action_email",
|
||||
"db_key_field" => "id",
|
||||
"db_finalclass_field" => "",
|
||||
'style' => new ormStyle(null, null, null, null, null, '../images/icons/icons8-mailing.svg'),
|
||||
);
|
||||
MetaModel::Init_Params($aParams);
|
||||
MetaModel::Init_InheritAttributes();
|
||||
@@ -273,7 +401,6 @@ class ActionEmail extends ActionNotification
|
||||
MetaModel::Init_AddAttribute(new AttributeTemplateString("subject", array("allowed_values" => null, "sql" => "subject", "default_value" => null, "is_null_allowed" => false, "depends_on" => array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeTemplateHTML("body", array("allowed_values" => null, "sql" => "body", "default_value" => null, "is_null_allowed" => false, "depends_on" => array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeEnum("importance", array("allowed_values" => new ValueSetEnum('low,normal,high'), "sql" => "importance", "default_value" => 'normal', "is_null_allowed" => false, "depends_on" => array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeApplicationLanguage("language", array("sql"=>"language", "default_value"=>null, "is_null_allowed"=>true, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeBlob("html_template", array("is_null_allowed"=>true, "depends_on"=>array(), "always_load_in_tables"=>false)));
|
||||
MetaModel::Init_AddAttribute(new AttributeEnum("ignore_notify", array("allowed_values" => new ValueSetEnum('yes,no'), "sql" => "ignore_notify", "default_value" => 'yes', "is_null_allowed" => false, "depends_on" => array())));
|
||||
|
||||
@@ -294,6 +421,7 @@ class ActionEmail extends ActionNotification
|
||||
),
|
||||
'fieldset:ActionEmail:trigger' => array(
|
||||
0 => 'trigger_list',
|
||||
1 => 'asynchronous'
|
||||
),
|
||||
),
|
||||
'col:col2' => array(
|
||||
@@ -328,27 +456,33 @@ class ActionEmail extends ActionNotification
|
||||
protected $m_aMailErrors; //array of strings explaining the issue
|
||||
|
||||
/**
|
||||
* Return a the list of emails as a string, or a detailed error description
|
||||
* Return the list of emails as a string, or a detailed error description
|
||||
*
|
||||
* @param string $sRecipAttCode
|
||||
* @param array $aArgs
|
||||
*
|
||||
* @return string
|
||||
* @throws \ArchivedObjectException
|
||||
* @throws \CoreCannotSaveObjectException
|
||||
* @throws \CoreException
|
||||
* @throws \CoreUnexpectedValue
|
||||
* @throws \CoreWarning
|
||||
* @throws \MissingQueryArgument
|
||||
* @throws \MySQLException
|
||||
* @throws \MySQLHasGoneAwayException
|
||||
* @throws \OQLException
|
||||
*/
|
||||
protected function FindRecipients($sRecipAttCode, $aArgs)
|
||||
{
|
||||
$oTrigger = $aArgs['trigger->object()'] ?? null;
|
||||
$sOQL = $this->Get($sRecipAttCode);
|
||||
if (strlen($sOQL) === 0) return '';
|
||||
if (utils::IsNullOrEmptyString($sOQL)) return '';
|
||||
|
||||
try
|
||||
{
|
||||
$oSearch = DBObjectSearch::FromOQL($sOQL);
|
||||
if ($this->Get('ignore_notify') === 'no') {
|
||||
// In theory it is possible to notify *any* kind of object,
|
||||
// In theory, it is possible to notify *any* kind of object,
|
||||
// as long as there is an email attribute in the class
|
||||
// So let's not assume that the selected class is a Person
|
||||
$sFirstSelectedClass = $oSearch->GetClass();
|
||||
@@ -381,16 +515,29 @@ class ActionEmail extends ActionNotification
|
||||
return "The objects of the class '$sClass' do not have any email attribute";
|
||||
}
|
||||
|
||||
if($oTrigger !== null && in_array('Contact', MetaModel::EnumParentClasses($sClass, ENUM_CHILD_CLASSES_ALL), true)) {
|
||||
$aArgs['trigger_id'] = $oTrigger->GetKey();
|
||||
$aArgs['action_id'] = $this->GetKey();
|
||||
|
||||
$sSubscribedContactsOQL = NotificationsRepository::GetInstance()->GetSearchOQLContactUnsubscribedByTriggerAndAction();
|
||||
$sSubscribedContactsOQL->ApplyParameters($aArgs);
|
||||
$sAlias = $oSearch->GetClassAlias();
|
||||
$oSearch->AddConditionExpression(Expression::FromOQL("`$sAlias`.id NOT IN ($sSubscribedContactsOQL)"));
|
||||
}
|
||||
|
||||
$oSet = new DBObjectSet($oSearch, array() /* order */, $aArgs);
|
||||
$aRecipients = array();
|
||||
while ($oObj = $oSet->Fetch())
|
||||
{
|
||||
$sAddress = trim($oObj->Get($sEmailAttCode));
|
||||
if (strlen($sAddress) > 0)
|
||||
if (utils::IsNotNullOrEmptyString($sAddress))
|
||||
{
|
||||
$aRecipients[] = $sAddress;
|
||||
$this->m_iRecipients++;
|
||||
}
|
||||
if ($oTrigger !== null && in_array('Contact', MetaModel::EnumParentClasses($sClass, ENUM_CHILD_CLASSES_ALL), true)) {
|
||||
NotificationsService::GetInstance()->RegisterSubscription($oTrigger, $this, $oObj);
|
||||
}
|
||||
}
|
||||
return implode(', ', $aRecipients);
|
||||
}
|
||||
@@ -510,7 +657,7 @@ class ActionEmail extends ActionNotification
|
||||
else
|
||||
{
|
||||
$aErrors = [];
|
||||
$iRes = $oEmail->Send($aErrors, false, $oLog); // allow asynchronous mode
|
||||
$iRes = $oEmail->Send($aErrors, $this->IsAsynchronous() ? Email::ENUM_SEND_FORCE_ASYNCHRONOUS : Email::ENUM_SEND_FORCE_SYNCHRONOUS, $oLog);
|
||||
switch ($iRes)
|
||||
{
|
||||
case EMAIL_SEND_OK:
|
||||
@@ -539,8 +686,17 @@ class ActionEmail extends ActionNotification
|
||||
* @param \EventNotification $oLog
|
||||
*
|
||||
* @return array
|
||||
* @throws \ArchivedObjectException
|
||||
* @throws \CoreCannotSaveObjectException
|
||||
* @throws \CoreException
|
||||
* @throws \Exception
|
||||
* @throws \CoreUnexpectedValue
|
||||
* @throws \CoreWarning
|
||||
* @throws \DictExceptionMissingString
|
||||
* @throws \DictExceptionUnknownLanguage
|
||||
* @throws \MissingQueryArgument
|
||||
* @throws \MySQLException
|
||||
* @throws \MySQLHasGoneAwayException
|
||||
* @throws \OQLException
|
||||
* @since 3.1.0 N°918
|
||||
*/
|
||||
protected function PrepareMessageContent($aContextArgs, &$oLog): array
|
||||
@@ -561,15 +717,7 @@ class ActionEmail extends ActionNotification
|
||||
'attachments' => [],
|
||||
];
|
||||
$sPreviousUrlMaker = ApplicationContext::SetUrlMakerClass();
|
||||
$sPreviousLanguage = Dict::GetUserLanguage();
|
||||
$aPreviousPluginProperties = ApplicationContext::GetPluginProperties('QueryLocalizerPlugin');
|
||||
if ($this->Get('language') !== '') {
|
||||
// If a language is specified for this action, force this language
|
||||
// when rendering all placeholders inside this message
|
||||
Dict::SetUserLanguage($this->Get('language'));
|
||||
AttributeDateTime::LoadFormatFromConfig();
|
||||
ApplicationContext::SetPluginProperty('QueryLocalizerPlugin', 'language_code', $this->Get('language'));
|
||||
}
|
||||
[$sPreviousLanguage, $aPreviousPluginProperties] = $this->SetNotificationLanguage();
|
||||
|
||||
try
|
||||
{
|
||||
@@ -601,9 +749,7 @@ class ActionEmail extends ActionNotification
|
||||
}
|
||||
finally {
|
||||
ApplicationContext::SetUrlMakerClass($sPreviousUrlMaker);
|
||||
Dict::SetUserLanguage($sPreviousLanguage);
|
||||
AttributeDateTime::LoadFormatFromConfig();
|
||||
ApplicationContext::SetPluginProperty('QueryLocalizerPlugin', 'language_code', $aPreviousPluginProperties['language_code'] ?? null);
|
||||
$this->SetNotificationLanguage($sPreviousLanguage, $aPreviousPluginProperties['language_code'] ?? null);
|
||||
}
|
||||
|
||||
if (!is_null($oLog)) {
|
||||
@@ -629,9 +775,7 @@ class ActionEmail extends ActionNotification
|
||||
$oLog->Set('body', HTMLSanitizer::Sanitize($aMessageContent['body']));
|
||||
}
|
||||
}
|
||||
$sStyles = file_get_contents(APPROOT.'css/email.css');
|
||||
$sStyles .= MetaModel::GetConfig()->Get('email_css');
|
||||
|
||||
|
||||
if ($this->IsBeingTested()) {
|
||||
$sTestBody = $aMessageContent['body'];
|
||||
$sTestBody .= "<div style=\"border: dashed;\">\n";
|
||||
@@ -660,10 +804,11 @@ class ActionEmail extends ActionNotification
|
||||
if (isset($aContextArgs['attachments']))
|
||||
{
|
||||
$aAttachmentReport = array();
|
||||
/** @var \ormDocument $oDocument */
|
||||
foreach($aContextArgs['attachments'] as $oDocument)
|
||||
{
|
||||
$aMessageContent['attachments'][] = ['data' => $oDocument->GetData(), 'filename' => $oDocument->GetFileName(), 'mime_type' => $oDocument->GetMimeType()];
|
||||
$aAttachmentReport[] = array($oDocument->GetFileName(), $oDocument->GetMimeType(), strlen($oDocument->GetData()));
|
||||
$aAttachmentReport[] = array($oDocument->GetFileName(), $oDocument->GetMimeType(), strlen($oDocument->GetData() ?? ''));
|
||||
}
|
||||
$oLog->Set('attachments', $aAttachmentReport);
|
||||
}
|
||||
@@ -773,4 +918,13 @@ class ActionEmail extends ActionNotification
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
* @since 3.2.0
|
||||
*/
|
||||
public static function GetAsynchronousGlobalSetting(): bool
|
||||
{
|
||||
return utils::GetConfig()->Get('email_asynchronous');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -97,6 +97,31 @@ function apc_delete($key)
|
||||
return $bRet1 || $bRet2;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if APCu emulation key exists
|
||||
*
|
||||
* @param string|string[] $keys A string, or an array of strings, that contain keys.
|
||||
*
|
||||
* @return bool|string[] Returns TRUE if the key exists, otherwise FALSE
|
||||
* Or if an array was passed to keys, then an array is returned that
|
||||
* contains all existing keys, or an empty array if none exist.
|
||||
* @since 3.2.0 N°7068
|
||||
*/
|
||||
function apc_exists($keys)
|
||||
{
|
||||
if (is_array($keys)) {
|
||||
$aExistingKeys = [];
|
||||
foreach ($keys as $sKey) {
|
||||
if (apcFile::ExistsOneFile($sKey)) {
|
||||
$aExistingKeys[] = $sKey;
|
||||
}
|
||||
}
|
||||
return $aExistingKeys;
|
||||
} else {
|
||||
return apcFile::ExistsOneFile($keys);
|
||||
}
|
||||
}
|
||||
|
||||
class apcFile
|
||||
{
|
||||
// Check only once per request
|
||||
@@ -183,6 +208,16 @@ class apcFile
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if cache key exists
|
||||
* @param $sKey
|
||||
* @return bool
|
||||
* @since 3.2.0 N°7068
|
||||
*/
|
||||
static public function ExistsOneFile($sKey) {
|
||||
return is_file(self::GetCacheFileName('-' . $sKey)) || is_file(self::GetCacheFileName($sKey));
|
||||
}
|
||||
|
||||
/** Get one cache entry content.
|
||||
* @param $sKey
|
||||
* @return bool|mixed
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with iTop. If not, see <http://www.gnu.org/licenses/>
|
||||
use Combodo\iTop\Service\Notification\Event\EventiTopNotificationService;
|
||||
|
||||
|
||||
/**
|
||||
@@ -457,3 +458,87 @@ class AsyncSendEmail extends AsyncTask
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An async notification to be sent to iTop users
|
||||
* @since 3.2.0
|
||||
*/
|
||||
class AsyncSendiTopNotifications extends AsyncTask {
|
||||
|
||||
public static function Init()
|
||||
{
|
||||
$aParams = array
|
||||
(
|
||||
"category" => "core/cmdb",
|
||||
"key_type" => "autoincrement",
|
||||
"name_attcode" => "created",
|
||||
"state_attcode" => "",
|
||||
"reconc_keys" => array(),
|
||||
"db_table" => "priv_async_send_itop_notifications",
|
||||
"db_key_field" => "id",
|
||||
"db_finalclass_field" => "",
|
||||
);
|
||||
MetaModel::Init_Params($aParams);
|
||||
MetaModel::Init_InheritAttributes();
|
||||
|
||||
MetaModel::Init_AddAttribute(new AttributeText("recipients", array("allowed_values"=>null, "sql"=>"recipients", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeExternalKey("action_id", array("targetclass"=>"Action", "allowed_values"=>null, "sql"=>"action_id", "default_value"=>null, "is_null_allowed"=>false, "on_target_delete"=>DEL_AUTO, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeExternalKey("trigger_id", array("targetclass"=>"Trigger", "allowed_values"=>null, "sql"=>"trigger_id", "default_value"=>null, "is_null_allowed"=>false, "on_target_delete"=>DEL_AUTO, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeText("title", array("allowed_values"=>null, "sql"=>"title", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeText("message", array("allowed_values"=>null, "sql"=>"message", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeInteger("object_id", array("allowed_values"=>null, "sql"=>"object_id", "default_value"=>null, "is_null_allowed"=>false, "on_target_delete"=>DEL_AUTO, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeString("object_class", array("allowed_values"=>null, "sql"=>"object_class", "default_value"=>null, "is_null_allowed"=>false, "on_target_delete"=>DEL_AUTO, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeText("url", array("allowed_values"=>null, "sql"=>"url", "default_value"=>null, "is_null_allowed"=>false, "on_target_delete"=>DEL_AUTO, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeDateTime("date", array("allowed_values"=>null, "sql"=>"date", "default_value"=>null, "is_null_allowed"=>false, "on_target_delete"=>DEL_AUTO, "depends_on"=>array())));
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws \ArchivedObjectException
|
||||
* @throws \CoreCannotSaveObjectException
|
||||
* @throws \CoreException
|
||||
* @throws \CoreUnexpectedValue
|
||||
* @throws \CoreWarning
|
||||
* @throws \MySQLException
|
||||
* @throws \OQLException
|
||||
*/
|
||||
public static function AddToQueue(int $iActionId, int $iTriggerId, array $aRecipients, string $sMessage, string $sTitle, string $sUrl, int $iObjectId, ?string $sObjectClass): void
|
||||
{
|
||||
$oNew = new static();
|
||||
$oNew->Set('action_id', $iActionId);
|
||||
$oNew->Set('trigger_id', $iTriggerId);
|
||||
$oNew->Set('recipients', json_encode($aRecipients));
|
||||
$oNew->Set('message', $sMessage);
|
||||
$oNew->Set('title', $sTitle);
|
||||
$oNew->Set('url', $sUrl);
|
||||
$oNew->Set('object_id', $iObjectId);
|
||||
$oNew->Set('object_class', $sObjectClass);
|
||||
$oNew->SetCurrentDate('date');
|
||||
|
||||
$oNew->DBInsert();
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function DoProcess()
|
||||
{
|
||||
$oAction = MetaModel::GetObject('Action', $this->Get('action_id'));
|
||||
$iTriggerId = $this->Get('trigger_id');
|
||||
$aRecipients = json_decode($this->Get('recipients'));
|
||||
$sMessage = $this->Get('message');
|
||||
$sTitle = $this->Get('title');
|
||||
$sUrl = $this->Get('url');
|
||||
$iObjectId = $this->Get('object_id');
|
||||
$sObjectClass = $this->Get('object_class');
|
||||
$sDate = $this->Get('date');
|
||||
|
||||
foreach ($aRecipients as $iRecipientId)
|
||||
{
|
||||
$oEvent = EventiTopNotificationService::MakeEventFromAction($oAction, $iRecipientId, $iTriggerId, $sMessage, $sTitle, $sUrl, $iObjectId, $sObjectClass, $sDate);
|
||||
$oEvent->DBInsertNoReload();
|
||||
}
|
||||
|
||||
return "Sent";
|
||||
}
|
||||
}
|
||||
@@ -6,6 +6,7 @@
|
||||
|
||||
use Combodo\iTop\Application\UI\Base\Component\FieldBadge\FieldBadgeUIBlockFactory;
|
||||
use Combodo\iTop\Application\UI\Links\Set\BlockLinkSetDisplayAsProperty;
|
||||
use Combodo\iTop\Application\WebPage\WebPage;
|
||||
use Combodo\iTop\Form\Field\LabelField;
|
||||
use Combodo\iTop\Form\Field\TextAreaField;
|
||||
use Combodo\iTop\Form\Form;
|
||||
@@ -1739,11 +1740,20 @@ class AttributeLinkedSet extends AttributeDefinition
|
||||
* @return bool true if Attribute has constraints
|
||||
* @since 3.1.0 N°6228
|
||||
*/
|
||||
public function GetHasConstraint()
|
||||
public function HasPHPConstraint(): bool
|
||||
{
|
||||
return $this->GetOptional('with_php_constraint', false);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool true if Attribute has computation (DB_LINKS_CHANGED event propagation, `with_php_computation` attribute xml property), false otherwise
|
||||
* @since 3.1.1 3.2.0 N°6228
|
||||
*/
|
||||
public function HasPHPComputation(): bool
|
||||
{
|
||||
return $this->GetOptional('with_php_computation', false);
|
||||
}
|
||||
|
||||
public function GetLinkedClass()
|
||||
{
|
||||
return $this->Get('linked_class');
|
||||
@@ -3052,6 +3062,11 @@ class AttributeObjectKey extends AttributeDBFieldVoid
|
||||
return ((int) $proposedValue) !== 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*
|
||||
* @param int|DBObject $proposedValue Object key or valid ({@see MetaModel::IsValidObject()}) datamodel object
|
||||
*/
|
||||
public function MakeRealValue($proposedValue, $oHostObj)
|
||||
{
|
||||
if (is_null($proposedValue))
|
||||
@@ -3064,7 +3079,6 @@ class AttributeObjectKey extends AttributeDBFieldVoid
|
||||
}
|
||||
if (MetaModel::IsValidObject($proposedValue))
|
||||
{
|
||||
/** @var \DBObject $proposedValue */
|
||||
return $proposedValue->GetKey();
|
||||
}
|
||||
|
||||
@@ -3496,7 +3510,7 @@ class AttributeBoolean extends AttributeInteger
|
||||
$sProposedValue, $bLocalizedValue = false, $sSepItem = null, $sSepAttribute = null, $sSepValue = null,
|
||||
$sAttributeQualifier = null
|
||||
) {
|
||||
$sInput = strtolower(trim($sProposedValue));
|
||||
$sInput = mb_strtolower(trim($sProposedValue));
|
||||
if ($bLocalizedValue)
|
||||
{
|
||||
switch ($sInput)
|
||||
@@ -4521,7 +4535,6 @@ class AttributeText extends AttributeString
|
||||
$sStyle = '';
|
||||
if (count($aStyles) > 0)
|
||||
{
|
||||
$aStyles[] = 'overflow:auto';
|
||||
$sStyle = 'style="'.implode(';', $aStyles).'"';
|
||||
}
|
||||
|
||||
@@ -6501,6 +6514,11 @@ class AttributeDateTime extends AttributeDBField
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*
|
||||
* @param int|string $proposedValue timestamp ({@see DateTime::getTimestamp()) or date as string, following the {@see GetInternalFormat} format.
|
||||
*/
|
||||
public function MakeRealValue($proposedValue, $oHostObj)
|
||||
{
|
||||
if (is_null($proposedValue))
|
||||
@@ -8290,9 +8308,9 @@ class AttributeBlob extends AttributeDefinition
|
||||
}
|
||||
|
||||
/**
|
||||
* Users can provide the document from an URL (including an URL on iTop itself)
|
||||
* for CSV import. Administrators can even provide the path to a local file
|
||||
* {@inheritDoc}
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @param string $proposedValue Can be an URL (including an URL to iTop itself), or a local path (CSV import)
|
||||
*
|
||||
* @see AttributeDefinition::MakeRealValue()
|
||||
*/
|
||||
@@ -8533,7 +8551,7 @@ class AttributeBlob extends AttributeDefinition
|
||||
$sFingerprint = '';
|
||||
if ($value instanceOf ormDocument)
|
||||
{
|
||||
$sFingerprint = md5($value->GetData());
|
||||
$sFingerprint = $value->GetSignature();
|
||||
}
|
||||
|
||||
return $sFingerprint;
|
||||
@@ -8644,6 +8662,20 @@ class AttributeImage extends AttributeBlob
|
||||
parent::__construct($sCode, $aParams);
|
||||
}
|
||||
|
||||
public function Get($sParamName)
|
||||
{
|
||||
$oParamValue = parent::Get($sParamName);
|
||||
|
||||
if ($sParamName === 'default_image') {
|
||||
/** @noinspection NestedPositiveIfStatementsInspection */
|
||||
if (!empty($oParamValue)) {
|
||||
return utils::GetAbsoluteUrlModulesRoot() . $oParamValue;
|
||||
}
|
||||
}
|
||||
|
||||
return $oParamValue;
|
||||
}
|
||||
|
||||
public function GetEditClass()
|
||||
{
|
||||
return "Image";
|
||||
@@ -12987,7 +13019,7 @@ class AttributeRedundancySettings extends AttributeDBField
|
||||
* Display an option (form, or current value)
|
||||
*
|
||||
* @param string $sCurrentValue
|
||||
* @param \WebPage $oPage
|
||||
* @param WebPage $oPage
|
||||
* @param string $sFormPrefix
|
||||
* @param bool $bEditMode
|
||||
* @param string $sUserOption
|
||||
|
||||
@@ -25,6 +25,7 @@ MetaModel::IncludeModule('application/audit.domain.class.inc.php');
|
||||
MetaModel::IncludeModule('application/query.class.inc.php');
|
||||
MetaModel::IncludeModule('setup/moduleinstallation.class.inc.php');
|
||||
|
||||
|
||||
MetaModel::IncludeModule('core/event.class.inc.php');
|
||||
MetaModel::IncludeModule('core/action.class.inc.php');
|
||||
MetaModel::IncludeModule('core/trigger.class.inc.php');
|
||||
|
||||
@@ -6,6 +6,9 @@
|
||||
|
||||
// The BOM is added at the head of exported UTF-8 CSV data, and removed (if present) from input UTF-8 data.
|
||||
// This helps MS-Excel (Version > 2007, Windows only) in changing its interpretation of a CSV file (by default Excel reads data as ISO-8859-1 -not 100% sure!)
|
||||
use Combodo\iTop\Application\WebPage\iTopWebPage;
|
||||
use Combodo\iTop\Application\WebPage\WebPage;
|
||||
|
||||
define('UTF8_BOM', chr(239).chr(187).chr(191)); // 0xEF, 0xBB, 0xBF
|
||||
|
||||
|
||||
@@ -160,7 +163,7 @@ class CellStatus_SearchIssue extends CellStatus_Issue
|
||||
* @param null $sAllowedValues : used for additional message that provides allowed values $sAllowedValues for current class
|
||||
* @param string|null $sAllowedValuesSearch : used to search all allowed values
|
||||
*/
|
||||
public function __construct($sSerializedSearch, $sReason, $sClass=null, $sAllowedValues=null, string $sAllowedValuesSearch=null)
|
||||
public function __construct($sSerializedSearch, $sReason, $sClass = null, $sAllowedValues = null, string $sAllowedValuesSearch = null)
|
||||
{
|
||||
parent::__construct(null, null, $sReason);
|
||||
$this->sSerializedSearch = $sSerializedSearch;
|
||||
@@ -195,7 +198,7 @@ class CellStatus_SearchIssue extends CellStatus_Issue
|
||||
public function GetSearchLinkUrl()
|
||||
{
|
||||
return sprintf("UI.php?operation=search&filter=%s",
|
||||
rawurlencode($this->sSerializedSearch)
|
||||
rawurlencode($this->sSerializedSearch ?? "")
|
||||
);
|
||||
}
|
||||
|
||||
@@ -206,7 +209,7 @@ class CellStatus_SearchIssue extends CellStatus_Issue
|
||||
public function GetAllowedValuesLinkUrl(): ?string
|
||||
{
|
||||
return sprintf("UI.php?operation=search&filter=%s",
|
||||
rawurlencode($this->sAllowedValuesSearch)
|
||||
rawurlencode($this->sAllowedValuesSearch ?? "")
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -262,7 +265,7 @@ class CellStatus_Ambiguous extends CellStatus_Issue
|
||||
public function GetSearchLinkUrl()
|
||||
{
|
||||
return sprintf("UI.php?operation=search&filter=%s",
|
||||
rawurlencode($this->sSerializedSearch)
|
||||
rawurlencode($this->sSerializedSearch ?? "")
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,6 +17,9 @@
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
*/
|
||||
|
||||
use Combodo\iTop\Application\WebPage\Page;
|
||||
use Combodo\iTop\Application\WebPage\WebPage;
|
||||
|
||||
define('EXPORTER_DEFAULT_CHUNK_SIZE', 1000);
|
||||
|
||||
class BulkExportException extends Exception
|
||||
@@ -391,7 +394,7 @@ abstract class BulkExport
|
||||
|
||||
|
||||
/**
|
||||
* @param \WebPage $oP
|
||||
* @param WebPage $oP
|
||||
* @param $sPartId
|
||||
*
|
||||
* @return UIContentBlock
|
||||
|
||||
@@ -335,7 +335,7 @@ abstract class CMDBObject extends DBObject
|
||||
$oMyChangeOp->Set("objclass", MetaModel::GetRootClass(get_class($this)));
|
||||
$oMyChangeOp->Set("objkey", $objkey);
|
||||
$oMyChangeOp->Set("fclass", get_class($this));
|
||||
$oMyChangeOp->Set("fname", substr($this->GetRawName(), 0, 255)); // Protect against very long friendly names
|
||||
$oMyChangeOp->SetTrim("fname", $this->GetRawName()); // Protect against very long friendly names
|
||||
$iId = $oMyChangeOp->DBInsertNoReload();
|
||||
}
|
||||
|
||||
@@ -438,7 +438,8 @@ abstract class CMDBObject extends DBObject
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated 3.1.0 N°5232 not used
|
||||
* @deprecated 3.1.0 N°5232 N°6966 simply use {@see DBObject::DBClone()} instead, that will automatically create and persist a CMDBChange object.
|
||||
* If you need to persist your own, call {@see CMDBObject::SetCurrentChange()} before.
|
||||
*/
|
||||
public function DBCloneTracked(CMDBChange $oChange, $newKey = null)
|
||||
{
|
||||
@@ -446,6 +447,9 @@ abstract class CMDBObject extends DBObject
|
||||
$this->DBCloneTracked_Internal($newKey);
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated 3.1.1 3.2.0 N°6966 We will have only one DBClone method in the future
|
||||
*/
|
||||
protected function DBCloneTracked_Internal($newKey = null)
|
||||
{
|
||||
$newKey = parent::DBClone($newKey);
|
||||
@@ -470,23 +474,13 @@ abstract class CMDBObject extends DBObject
|
||||
public function DBDelete(&$oDeletionPlan = null)
|
||||
{
|
||||
$this->LogCRUDEnter(__METHOD__);
|
||||
$oDeletionPlan = $this->DBDeleteTracked_Internal($oDeletionPlan);
|
||||
$oDeletionPlan = parent::DBDelete($oDeletionPlan);
|
||||
$this->LogCRUDExit(__METHOD__);
|
||||
return $oDeletionPlan;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param null $oDeletionPlan
|
||||
*
|
||||
* @return \DeletionPlan|null
|
||||
* @throws \ArchivedObjectException
|
||||
* @throws \CoreCannotSaveObjectException
|
||||
* @throws \CoreException
|
||||
* @throws \CoreUnexpectedValue
|
||||
* @throws \DeleteException
|
||||
* @throws \MySQLException
|
||||
* @throws \MySQLHasGoneAwayException
|
||||
* @throws \OQLException
|
||||
* @deprecated 3.1.1 3.2.0 N°6967 We will have only one DBDelete method in the future
|
||||
*/
|
||||
protected function DBDeleteTracked_Internal(&$oDeletionPlan = null)
|
||||
{
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
//
|
||||
// This file is part of iTop.
|
||||
//
|
||||
// iTop is free software; you can redistribute it and/or modify
|
||||
// iTop is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
@@ -42,6 +42,12 @@ class CMDBSource
|
||||
const ENUM_DB_VENDOR_MARIADB = 'MariaDB';
|
||||
const ENUM_DB_VENDOR_PERCONA = 'Percona';
|
||||
|
||||
/**
|
||||
* @since 2.7.10 3.0.4 3.1.2 3.0.2 N°6889 constant creation
|
||||
* @internal will be removed in a future version
|
||||
*/
|
||||
const MYSQL_DEFAULT_PORT = 3306;
|
||||
|
||||
/**
|
||||
* Error: 1205 SQLSTATE: HY000 (ER_LOCK_WAIT_TIMEOUT)
|
||||
* Message: Lock wait timeout exceeded; try restarting transaction
|
||||
@@ -212,16 +218,19 @@ class CMDBSource
|
||||
/**
|
||||
* @param string $sDbHost initial value ("p:domain:port" syntax)
|
||||
* @param string $sServer server variable to update
|
||||
* @param int $iPort port variable to update
|
||||
* @param int|null $iPort port variable to update, will return null if nothing is specified in $sDbHost
|
||||
*
|
||||
* @since 2.7.10 3.0.4 3.1.2 3.2.0 N°6889 will return null in $iPort if port isn't present in $sDbHost. Use {@see MYSQL_DEFAULT_PORT} if needed
|
||||
*
|
||||
* @link http://php.net/manual/en/mysqli.persistconns.php documentation for the "p:" prefix (persistent connexion)
|
||||
*/
|
||||
public static function InitServerAndPort($sDbHost, &$sServer, &$iPort)
|
||||
{
|
||||
$aConnectInfo = explode(':', $sDbHost);
|
||||
|
||||
$bUsePersistentConnection = false;
|
||||
if (strcasecmp($aConnectInfo[0], 'p') == 0)
|
||||
if (strcasecmp($aConnectInfo[0], 'p') === 0)
|
||||
{
|
||||
// we might have "p:" prefix to use persistent connections (see http://php.net/manual/en/mysqli.persistconns.php)
|
||||
$bUsePersistentConnection = true;
|
||||
$sServer = $aConnectInfo[0].':'.$aConnectInfo[1];
|
||||
}
|
||||
@@ -239,10 +248,6 @@ class CMDBSource
|
||||
{
|
||||
$iPort = (int)($aConnectInfo[1]);
|
||||
}
|
||||
else
|
||||
{
|
||||
$iPort = 3306;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -380,7 +385,7 @@ class CMDBSource
|
||||
public static function GetDBVendor()
|
||||
{
|
||||
$sDBVendor = static::ENUM_DB_VENDOR_MYSQL;
|
||||
|
||||
|
||||
$sVersionComment = static::GetServerVariable('version') . ' - ' . static::GetServerVariable('version_comment');
|
||||
if(preg_match('/mariadb/i', $sVersionComment) === 1)
|
||||
{
|
||||
@@ -390,7 +395,7 @@ class CMDBSource
|
||||
{
|
||||
$sDBVendor = static::ENUM_DB_VENDOR_PERCONA;
|
||||
}
|
||||
|
||||
|
||||
return $sDBVendor;
|
||||
}
|
||||
|
||||
@@ -934,7 +939,7 @@ class CMDBSource
|
||||
{
|
||||
throw new MySQLException('Failed to issue SQL query', array('query' => $sSql));
|
||||
}
|
||||
|
||||
|
||||
while ($aRow = $oResult->fetch_array($iMode))
|
||||
{
|
||||
$aData[] = $aRow;
|
||||
@@ -1088,7 +1093,7 @@ class CMDBSource
|
||||
if (!array_key_exists($iKey, $aTableInfo["Fields"])) return false;
|
||||
$aFieldData = $aTableInfo["Fields"][$iKey];
|
||||
if (!array_key_exists("Key", $aFieldData)) return false;
|
||||
return ($aFieldData["Key"] == "PRI");
|
||||
return ($aFieldData["Key"] == "PRI");
|
||||
}
|
||||
|
||||
public static function IsAutoIncrement($sTable, $sField)
|
||||
@@ -1099,7 +1104,7 @@ class CMDBSource
|
||||
$aFieldData = $aTableInfo["Fields"][$sField];
|
||||
if (!array_key_exists("Extra", $aFieldData)) return false;
|
||||
//MyHelpers::debug_breakpoint($aFieldData);
|
||||
return (strstr($aFieldData["Extra"], "auto_increment"));
|
||||
return (strstr($aFieldData["Extra"], "auto_increment"));
|
||||
}
|
||||
|
||||
public static function IsField($sTable, $sField)
|
||||
@@ -1366,13 +1371,13 @@ class CMDBSource
|
||||
public static function GetTableFieldsList($sTable)
|
||||
{
|
||||
assert(!empty($sTable));
|
||||
|
||||
|
||||
$aTableInfo = self::GetTableInfo($sTable);
|
||||
if (empty($aTableInfo)) return array(); // #@# or an error ?
|
||||
|
||||
return array_keys($aTableInfo["Fields"]);
|
||||
}
|
||||
|
||||
|
||||
// Cache the information about existing tables, and their fields
|
||||
private static $m_aTablesInfo = array();
|
||||
private static function _TablesInfoCacheReset($sTableName = null)
|
||||
@@ -1505,7 +1510,7 @@ class CMDBSource
|
||||
{
|
||||
throw new MySQLException('Failed to issue SQL query', array('query' => $sSql));
|
||||
}
|
||||
|
||||
|
||||
$aRows = array();
|
||||
while ($aRow = $oResult->fetch_array(MYSQLI_ASSOC))
|
||||
{
|
||||
@@ -1514,7 +1519,7 @@ class CMDBSource
|
||||
$oResult->free();
|
||||
return $aRows;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the value of the specified server variable
|
||||
* @param string $sVarName Name of the server variable
|
||||
@@ -1530,7 +1535,7 @@ class CMDBSource
|
||||
/**
|
||||
* Returns the privileges of the current user
|
||||
* @return string privileges in a raw format
|
||||
*/
|
||||
*/
|
||||
public static function GetRawPrivileges()
|
||||
{
|
||||
try
|
||||
@@ -1556,8 +1561,8 @@ class CMDBSource
|
||||
|
||||
/**
|
||||
* Determine the slave status of the server
|
||||
* @return bool true if the server is slave
|
||||
*/
|
||||
* @return bool true if the server is slave
|
||||
*/
|
||||
public static function IsSlaveServer()
|
||||
{
|
||||
try
|
||||
|
||||
@@ -29,7 +29,7 @@ define('ITOP_APPLICATION_SHORT', 'iTop');
|
||||
*
|
||||
* @see ITOP_CORE_VERSION to get iTop core version
|
||||
*/
|
||||
define('ITOP_VERSION', '3.1.1-dev');
|
||||
define('ITOP_VERSION', '3.2.0-dev');
|
||||
|
||||
define('ITOP_VERSION_NAME', 'Fullmoon');
|
||||
define('ITOP_REVISION', 'svn');
|
||||
@@ -447,14 +447,14 @@ class Config
|
||||
'show_in_conf_sample' => true,
|
||||
],
|
||||
'export_pdf_font' => [ // @since 2.7.0 PR #49 / N°1947
|
||||
'type' => 'string',
|
||||
'description' => 'Font used when generating a PDF file',
|
||||
'default' => 'DejaVuSans', // DejaVuSans is a UTF-8 Unicode font, embedded in the TCPPDF lib we're using
|
||||
// Standard PDF fonts like helvetica or times newroman are NOT Unicode
|
||||
// A new DroidSansFallback can be used to improve CJK support (se PR #49)
|
||||
'value' => '',
|
||||
'source_of_value' => '',
|
||||
'show_in_conf_sample' => false,
|
||||
'type' => 'string',
|
||||
'description' => 'Font used when generating a PDF file',
|
||||
'default' => 'DejaVuSans', // DejaVuSans is a UTF-8 Unicode font, embedded in the TCPPDF lib we're using
|
||||
// Standard PDF fonts like helvetica or times newroman are NOT Unicode
|
||||
// A new DroidSansFallback can be used to improve CJK support (se PR #49)
|
||||
'value' => '',
|
||||
'source_of_value' => '',
|
||||
'show_in_conf_sample' => false,
|
||||
],
|
||||
'access_mode' => [
|
||||
'type' => 'integer',
|
||||
@@ -889,6 +889,14 @@ class Config
|
||||
'source_of_value' => '',
|
||||
'show_in_conf_sample' => false,
|
||||
],
|
||||
'forgot_password.url' => [
|
||||
'type' => 'string',
|
||||
'description' => 'Set this value to your "forgot password" service URL if it should be handled out of '.ITOP_APPLICATION_SHORT.'. Note that it will apply to all users (iTop users, LDAP users, ...)',
|
||||
'default' => '',
|
||||
'value' => '',
|
||||
'source_of_value' => '',
|
||||
'show_in_conf_sample' => false,
|
||||
],
|
||||
'deadline_format' => [
|
||||
'type' => 'string',
|
||||
'description' => 'The format used for displaying "deadline" attributes: any string with the following placeholders: $date$, $difference$',
|
||||
@@ -1111,6 +1119,14 @@ class Config
|
||||
'source_of_value' => '',
|
||||
'show_in_conf_sample' => false,
|
||||
],
|
||||
'purge_data.max_chunk_size' => [
|
||||
'type' => 'integer',
|
||||
'description' => 'Maximum number of items deleted per loop. Used in function MetaModel::PurgeData',
|
||||
'default' => 1000,
|
||||
'value' => 1000,
|
||||
'source_of_value' => '',
|
||||
'show_in_conf_sample' => false,
|
||||
],
|
||||
'max_history_length' => [
|
||||
'type' => 'integer',
|
||||
'description' => 'Maximum length of the history table (in the "History" tab on each object) before it gets truncated. Latest modifications are displayed first.',
|
||||
@@ -1193,6 +1209,30 @@ class Config
|
||||
'source_of_value' => '',
|
||||
'show_in_conf_sample' => false,
|
||||
],
|
||||
'sessions_tracking.enabled' => [
|
||||
'type' => 'bool',
|
||||
'description' => 'Whether or not the whole mechanism to track active sessions is enabled. See PHP session.gc_maxlifetime setting to configure session expiration.',
|
||||
'default' => false,
|
||||
'value' => '',
|
||||
'source_of_value' => '',
|
||||
'show_in_conf_sample' => false,
|
||||
],
|
||||
'sessions_tracking.gc_threshold' => [
|
||||
'type' => 'integer',
|
||||
'description' => 'fallback in case cron is not active: probability in percent that session files are cleanup during any itop request (100 means always)',
|
||||
'default' => 1,
|
||||
'value' => '',
|
||||
'source_of_value' => '',
|
||||
'show_in_conf_sample' => false,
|
||||
],
|
||||
'sessions_tracking.gc_duration_in_seconds' => [
|
||||
'type' => 'integer',
|
||||
'description' => 'fallback in case cron is not active: when a cleanup is triggered cleanup duration will not exceed this duration (in seconds).',
|
||||
'default' => 1,
|
||||
'value' => '',
|
||||
'source_of_value' => '',
|
||||
'show_in_conf_sample' => false,
|
||||
],
|
||||
'transaction_storage' => [
|
||||
'type' => 'string',
|
||||
'description' => 'The type of mechanism to use for storing the unique identifiers for transactions (Session|File).',
|
||||
@@ -1292,9 +1332,9 @@ class Config
|
||||
'draft_attachments_lifetime' => [
|
||||
'type' => 'integer',
|
||||
'description' => 'Lifetime (in seconds) of drafts\' attachments and inline images: after this duration, the garbage collector will delete them.',
|
||||
'default' => 86400,
|
||||
'value' => '',
|
||||
'source_of_value' => '',
|
||||
'default' => 86400,
|
||||
'value' => '',
|
||||
'source_of_value' => '',
|
||||
'show_in_conf_sample' => false,
|
||||
],
|
||||
'date_and_time_format' => [
|
||||
@@ -1571,6 +1611,38 @@ class Config
|
||||
'source_of_value' => '',
|
||||
'show_in_conf_sample' => false,
|
||||
],
|
||||
'notifications.itop.read_notification_retention' => [
|
||||
'type' => 'integer',
|
||||
'description' => 'Duration in days after which iTop read notifications will be deleted',
|
||||
'default' => 182,
|
||||
'value' => 182,
|
||||
'source_of_value' => '',
|
||||
'show_in_conf_sample' => false,
|
||||
],
|
||||
'notifications.itop.send_asynchronously' => [
|
||||
'type' => 'bool',
|
||||
'description' => 'If true then iTop notifications will be sent asynchronously',
|
||||
'default' => false,
|
||||
'value' => false,
|
||||
'source_of_value' => '',
|
||||
'show_in_conf_sample' => false,
|
||||
],
|
||||
'notifications.itop.newsroom_cache_time' => [
|
||||
'type' => 'integer',
|
||||
'description' => 'Duration in min between each fetch for notifications in newsroom',
|
||||
'default' => 5,
|
||||
'value' => 5,
|
||||
'source_of_value' => '',
|
||||
'show_in_conf_sample' => false,
|
||||
],
|
||||
'notifications.last_executions_days' => [
|
||||
'type' => 'integer',
|
||||
'description' => 'Number of days to display in the Action\'s last executions tab (0 means no limit)',
|
||||
'default' => 30 + 31, // 2 months
|
||||
'value' => 61,
|
||||
'source_of_value' => '',
|
||||
'show_in_conf_sample' => false,
|
||||
],
|
||||
'regenerate_session_id_enabled' => [
|
||||
'type' => 'bool',
|
||||
'description' => 'If true then session id will be regenerated on each login, to prevent session fixation.',
|
||||
@@ -1619,6 +1691,14 @@ class Config
|
||||
'source_of_value' => '',
|
||||
'show_in_conf_sample' => false,
|
||||
],
|
||||
'security.enable_header_xcontent_type_options' => [
|
||||
'type' => 'bool',
|
||||
'description' => 'If set to false, iTop will stop sending the X-Content-Type-Options HTTP header. This header could trigger CORB protection on certain resources (JSON, XML, HTML, text) therefore blocking them.',
|
||||
'default' => true,
|
||||
'value' => '',
|
||||
'source_of_value' => '',
|
||||
'show_in_conf_sample' => false,
|
||||
],
|
||||
'security.disable_inline_documents_sandbox' => [
|
||||
'type' => 'bool',
|
||||
'description' => 'If true then the sandbox for documents displayed in a browser tab will be disabled; enabling scripts and other interactive content. Note that setting this to true will open the application to potential XSS attacks!',
|
||||
@@ -1683,6 +1763,14 @@ class Config
|
||||
'source_of_value' => '',
|
||||
'show_in_conf_sample' => false,
|
||||
],
|
||||
'application.secret' => [
|
||||
'type' => 'string',
|
||||
'description' => 'Application secret, uses this value for encrypting the cookies used in the remember me functionality and for creating signed URIs when using ESI (Edge Side Includes).',
|
||||
'default' => '',
|
||||
'value' => '',
|
||||
'source_of_value' => '',
|
||||
'show_in_conf_sample' => false,
|
||||
],
|
||||
];
|
||||
|
||||
public function IsProperty($sPropCode)
|
||||
@@ -1810,6 +1898,7 @@ class Config
|
||||
* @var integer Number of seconds between two reloads of the display (standard)
|
||||
*/
|
||||
protected $m_iStandardReloadInterval;
|
||||
|
||||
/**
|
||||
* @var integer Number of seconds between two reloads of the display (fast)
|
||||
*/
|
||||
@@ -1862,6 +1951,15 @@ class Config
|
||||
*/
|
||||
protected $m_iPasswordHashAlgo;
|
||||
|
||||
/**
|
||||
* Symfony uses this value for encrypting the cookies used in the remember me functionality and for creating signed URIs when using ESI (Edge Side Includes).
|
||||
*
|
||||
* @see https://symfony.com/doc/current/reference/configuration/framework.html#secret
|
||||
* @since 3.2.0 - N°6934 - Symfony 6.4 - upgrade Symfony bundles to 6.4
|
||||
* @var string
|
||||
*/
|
||||
protected $m_sAppSecret;
|
||||
|
||||
/**
|
||||
* Config constructor.
|
||||
*
|
||||
@@ -1906,6 +2004,7 @@ class Config
|
||||
$this->m_aCharsets = array();
|
||||
$this->m_bQueryCacheEnabled = DEFAULT_QUERY_CACHE_ENABLED;
|
||||
$this->m_iPasswordHashAlgo = DEFAULT_HASH_ALGO;
|
||||
$this->m_sAppSecret = bin2hex(random_bytes(16));
|
||||
|
||||
//define default encryption params according to php install
|
||||
$aEncryptParams = SimpleCrypt::GetNewDefaultParams();
|
||||
@@ -2066,6 +2165,7 @@ class Config
|
||||
$this->m_sEncryptionLibrary = isset($MySettings['encryption_library']) ? trim($MySettings['encryption_library']) : $this->m_sEncryptionLibrary;
|
||||
$this->m_aCharsets = isset($MySettings['csv_import_charsets']) ? $MySettings['csv_import_charsets'] : array();
|
||||
$this->m_iPasswordHashAlgo = isset($MySettings['password_hash_algo']) ? $MySettings['password_hash_algo'] : $this->m_iPasswordHashAlgo;
|
||||
$this->m_sAppSecret = isset($MySettings['application.secret']) ? trim($MySettings['application.secret']) : $this->m_sAppSecret;
|
||||
}
|
||||
|
||||
protected function Verify()
|
||||
@@ -2201,6 +2301,11 @@ class Config
|
||||
return $this->m_sEncryptionKey;
|
||||
}
|
||||
|
||||
public function GetAppSecret()
|
||||
{
|
||||
return $this->m_sAppSecret;
|
||||
}
|
||||
|
||||
public function GetEncryptionLibrary()
|
||||
{
|
||||
return $this->m_sEncryptionLibrary;
|
||||
@@ -2289,6 +2394,24 @@ class Config
|
||||
$this->m_sAllowedLoginTypes = implode('|', $aAllowedLoginTypes);
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 2.7.11 N°7085
|
||||
* Add login mode if not configured already
|
||||
* @param string $sLoginMode
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function AddAllowedLoginTypes($sLoginMode)
|
||||
{
|
||||
$aAllowedLoginTypes = $this->GetAllowedLoginTypes();
|
||||
if (in_array($sLoginMode, $aAllowedLoginTypes)){
|
||||
return;
|
||||
}
|
||||
|
||||
$aAllowedLoginTypes[] = $sLoginMode;
|
||||
$this->SetAllowedLoginTypes($aAllowedLoginTypes);
|
||||
}
|
||||
|
||||
public function SetExternalAuthenticationVariable($sExtAuthVariable)
|
||||
{
|
||||
$this->m_sExtAuthVariable = $sExtAuthVariable;
|
||||
@@ -2299,6 +2422,12 @@ class Config
|
||||
$this->m_sEncryptionKey = $sKey;
|
||||
}
|
||||
|
||||
public function SetAppSecret($sKey)
|
||||
{
|
||||
$this->m_sAppSecret = $sKey;
|
||||
}
|
||||
|
||||
|
||||
public function SetCSVImportCharsets($aCharsets)
|
||||
{
|
||||
$this->m_aCharsets = $aCharsets;
|
||||
@@ -2350,6 +2479,7 @@ class Config
|
||||
$aSettings['encryption_library'] = $this->m_sEncryptionLibrary;
|
||||
$aSettings['csv_import_charsets'] = $this->m_aCharsets;
|
||||
$aSettings['password_hash_algo'] = $this->m_iPasswordHashAlgo;
|
||||
$aSettings['application.secret'] = $this->m_sAppSecret;
|
||||
|
||||
foreach ($this->m_aModuleSettings as $sModule => $aProperties)
|
||||
{
|
||||
@@ -2440,9 +2570,9 @@ class Config
|
||||
|
||||
// Old fashioned integer settings
|
||||
$aIntValues = array(
|
||||
'fast_reload_interval' => $this->m_iFastReloadInterval,
|
||||
'max_display_limit' => $this->m_iMaxDisplayLimit,
|
||||
'min_display_limit' => $this->m_iMinDisplayLimit,
|
||||
'fast_reload_interval' => $this->m_iFastReloadInterval,
|
||||
'max_display_limit' => $this->m_iMaxDisplayLimit,
|
||||
'min_display_limit' => $this->m_iMinDisplayLimit,
|
||||
'standard_reload_interval' => $this->m_iStandardReloadInterval,
|
||||
);
|
||||
foreach ($aIntValues as $sKey => $iValue)
|
||||
@@ -2462,7 +2592,8 @@ class Config
|
||||
'encryption_key' => $this->m_sEncryptionKey,
|
||||
'encryption_library' => $this->m_sEncryptionLibrary,
|
||||
'csv_import_charsets' => $this->m_aCharsets,
|
||||
'password_hash_algo' => $this->m_iPasswordHashAlgo
|
||||
'password_hash_algo' => $this->m_iPasswordHashAlgo,
|
||||
'application.secret' => $this->m_sAppSecret,
|
||||
);
|
||||
foreach ($aOtherValues as $sKey => $value)
|
||||
{
|
||||
|
||||
@@ -8,10 +8,13 @@ use Combodo\iTop\Application\UI\Base\Component\FieldSet\FieldSetUIBlockFactory;
|
||||
use Combodo\iTop\Application\UI\Base\Component\Html\Html;
|
||||
use Combodo\iTop\Application\UI\Base\Component\Input\InputUIBlockFactory;
|
||||
use Combodo\iTop\Application\UI\Base\Component\Input\Select\SelectOptionUIBlockFactory;
|
||||
use Combodo\iTop\Application\UI\Base\Component\Input\SelectUIBlockFactory;
|
||||
use Combodo\iTop\Application\UI\Base\Component\Input\Select\SelectUIBlockFactory;
|
||||
use Combodo\iTop\Application\UI\Base\Component\Panel\PanelUIBlockFactory;
|
||||
use Combodo\iTop\Application\UI\Base\Layout\MultiColumn\Column\ColumnUIBlockFactory;
|
||||
use Combodo\iTop\Application\UI\Base\Layout\MultiColumn\MultiColumnUIBlockFactory;
|
||||
use Combodo\iTop\Application\Helper\ExportHelper;
|
||||
use Combodo\iTop\Application\WebPage\Page;
|
||||
use Combodo\iTop\Application\WebPage\WebPage;
|
||||
|
||||
/**
|
||||
* Bulk export: CSV export
|
||||
@@ -100,7 +103,7 @@ class CSVBulkExport extends TabularBulkExport
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \WebPage $oP
|
||||
* @param WebPage $oP
|
||||
* @param $sPartId
|
||||
*
|
||||
* @return UIContentBlock
|
||||
@@ -114,6 +117,7 @@ class CSVBulkExport extends TabularBulkExport
|
||||
|
||||
case 'csv_options':
|
||||
$oPanel = PanelUIBlockFactory::MakeNeutral(Dict::S('Core:BulkExport:CSVOptions'));
|
||||
$oPanel->AddSubBlock(ExportHelper::GetAlertForExcelMaliciousInjection());
|
||||
|
||||
$oMulticolumn = MultiColumnUIBlockFactory::MakeStandard();
|
||||
$oPanel->AddSubBlock($oMulticolumn);
|
||||
|
||||
@@ -1,5 +1,416 @@
|
||||
<?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.2">
|
||||
<classes>
|
||||
<class id="lnkActionNotificationToContact" _delta="define">
|
||||
<parent>cmdbAbstractObject</parent>
|
||||
<properties>
|
||||
<category>core/cmdb,application</category>
|
||||
<abstract>false</abstract>
|
||||
<key_type>autoincrement</key_type>
|
||||
<db_table>priv_lnk_action_notif_to_contact</db_table>
|
||||
<db_key_field>id</db_key_field>
|
||||
<db_final_class_field/>
|
||||
<naming>
|
||||
<attributes>
|
||||
<attribute id="action_id"/>
|
||||
<attribute id="contact_id"/>
|
||||
</attributes>
|
||||
</naming>
|
||||
<uniqueness_rules>
|
||||
<rule>
|
||||
<attributes>
|
||||
<attribute id="action_id"/>
|
||||
<attribute id="contact_id"/>
|
||||
<attribute id="trigger_id"/>
|
||||
</attributes>
|
||||
<filter/>
|
||||
<disabled>false</disabled>
|
||||
<is_blocking>true</is_blocking>
|
||||
</rule>
|
||||
</uniqueness_rules>
|
||||
</properties>
|
||||
<fields>
|
||||
<field id="action_id" xsi:type="AttributeExternalKey">
|
||||
<sql>action_id</sql>
|
||||
<target_class>ActionNotification</target_class>
|
||||
<default_value/>
|
||||
<is_null_allowed>false</is_null_allowed>
|
||||
</field>
|
||||
<field id="contact_id" xsi:type="AttributeExternalKey">
|
||||
<sql>contact_id</sql>
|
||||
<target_class>Contact</target_class>
|
||||
<default_value/>
|
||||
<is_null_allowed>false</is_null_allowed>
|
||||
</field>
|
||||
<field id="trigger_id" xsi:type="AttributeExternalKey">
|
||||
<sql>trigger_id</sql>
|
||||
<target_class>Trigger</target_class>
|
||||
<default_value/>
|
||||
<is_null_allowed>false</is_null_allowed>
|
||||
</field>
|
||||
<field id="subscribed" xsi:type="AttributeBoolean">
|
||||
<sql>subscribed</sql>
|
||||
<default_value>true</default_value>
|
||||
<is_null_allowed>false</is_null_allowed>
|
||||
</field>
|
||||
</fields>
|
||||
<presentation>
|
||||
<details>
|
||||
<items>
|
||||
<item id="col:col1">
|
||||
<items>
|
||||
<item id="fieldset:lnkActionNotificationToContact:content">
|
||||
<items>
|
||||
<item id="action_id">
|
||||
<rank>10</rank>
|
||||
</item>
|
||||
<item id="contact_id">
|
||||
<rank>20</rank>
|
||||
</item>
|
||||
<item id="title">
|
||||
<rank>30</rank>
|
||||
</item>
|
||||
</items>
|
||||
</item>
|
||||
</items>
|
||||
</item>
|
||||
</items>
|
||||
</details>
|
||||
<list>
|
||||
<items>
|
||||
<item id="action_id">
|
||||
<rank>10</rank>
|
||||
</item>
|
||||
<item id="contact_id">
|
||||
<rank>20</rank>
|
||||
</item>
|
||||
<item id="title">
|
||||
<rank>30</rank>
|
||||
</item>
|
||||
</items>
|
||||
</list>
|
||||
</presentation>
|
||||
<methods/>
|
||||
</class>
|
||||
<class id="ActioniTopNotification" _delta="define">
|
||||
<php_parent>
|
||||
<name>ActionNotification</name>
|
||||
</php_parent>
|
||||
<parent>cmdbAbstractObject</parent>
|
||||
<properties>
|
||||
<category>grant_by_profile,core/cmdb,application</category>
|
||||
<abstract>false</abstract>
|
||||
<key_type>autoincrement</key_type>
|
||||
<db_table>priv_action_itop_notif</db_table>
|
||||
<db_key_field>id</db_key_field>
|
||||
<db_final_class_field/>
|
||||
<naming>
|
||||
<attributes>
|
||||
<attribute id="name"/>
|
||||
</attributes>
|
||||
</naming>
|
||||
<style>
|
||||
<icon>../../images/icons/icons8-notification.svg</icon>
|
||||
</style>
|
||||
</properties>
|
||||
<fields>
|
||||
<field id="title" xsi:type="AttributeString">
|
||||
<sql>title</sql>
|
||||
<default_value/>
|
||||
<is_null_allowed>false</is_null_allowed>
|
||||
</field>
|
||||
<field id="message" xsi:type="AttributeText">
|
||||
<sql>message</sql>
|
||||
<default_value/>
|
||||
<is_null_allowed>true</is_null_allowed>
|
||||
</field>
|
||||
<field id="icon" xsi:type="AttributeImage">
|
||||
<sql>icon</sql>
|
||||
<default_value/>
|
||||
<is_null_allowed>true</is_null_allowed>
|
||||
<display_max_width>96</display_max_width>
|
||||
<display_max_height>96</display_max_height>
|
||||
<storage_max_width>256</storage_max_width>
|
||||
<storage_max_height>256</storage_max_height>
|
||||
<default_image />
|
||||
</field>
|
||||
<field id="priority" xsi:type="AttributeEnum">
|
||||
<sql>priority</sql>
|
||||
<values>
|
||||
<value id="1">
|
||||
<code>1</code>
|
||||
</value>
|
||||
<value id="2">
|
||||
<code>2</code>
|
||||
</value>
|
||||
<value id="3">
|
||||
<code>3</code>
|
||||
</value>
|
||||
<value id="4">
|
||||
<code>4</code>
|
||||
</value>
|
||||
</values>
|
||||
<default_value>4</default_value>
|
||||
<is_null_allowed>false</is_null_allowed>
|
||||
</field>
|
||||
<field id="recipients" xsi:type="AttributeOQL">
|
||||
<sql>recipients</sql>
|
||||
<default_value/>
|
||||
<is_null_allowed>false</is_null_allowed>
|
||||
</field>
|
||||
<field id="url" xsi:type="AttributeString">
|
||||
<sql>url</sql>
|
||||
<default_value>$this->url()$</default_value>
|
||||
<is_null_allowed>false</is_null_allowed>
|
||||
</field>
|
||||
</fields>
|
||||
<presentation>
|
||||
<details>
|
||||
<items>
|
||||
<item id="col:col1">
|
||||
<items>
|
||||
<item id="fieldset:ActioniTopNotification:content">
|
||||
<items>
|
||||
<item id="name">
|
||||
<rank>10</rank>
|
||||
</item>
|
||||
<item id="status">
|
||||
<rank>20</rank>
|
||||
</item>
|
||||
<item id="language">
|
||||
<rank>30</rank>
|
||||
</item>
|
||||
<item id="title">
|
||||
<rank>40</rank>
|
||||
</item>
|
||||
<item id="message">
|
||||
<rank>50</rank>
|
||||
</item>
|
||||
</items>
|
||||
</item>
|
||||
<item id="fieldset:ActioniTopNotification:trigger">
|
||||
<items>
|
||||
<item id="trigger_list">
|
||||
<rank>10</rank>
|
||||
</item>
|
||||
<item id="asynchronous">
|
||||
<rank>20</rank>
|
||||
</item>
|
||||
</items>
|
||||
</item>
|
||||
</items>
|
||||
</item>
|
||||
<item id="col:col2">
|
||||
<items>
|
||||
<item id="fieldset:ActioniTopNotification:settings">
|
||||
<items>
|
||||
<item id="priority">
|
||||
<rank>10</rank>
|
||||
</item>
|
||||
<item id="icon">
|
||||
<rank>20</rank>
|
||||
</item>
|
||||
<item id="recipients">
|
||||
<rank>30</rank>
|
||||
</item>
|
||||
<item id="url">
|
||||
<rank>40</rank>
|
||||
</item>
|
||||
</items>
|
||||
</item>
|
||||
</items>
|
||||
</item>
|
||||
</items>
|
||||
</details>
|
||||
<list>
|
||||
<items>
|
||||
<item id="title">
|
||||
<rank>10</rank>
|
||||
</item>
|
||||
<item id="status">
|
||||
<rank>20</rank>
|
||||
</item>
|
||||
<item id="language">
|
||||
<rank>30</rank>
|
||||
</item>
|
||||
</items>
|
||||
</list>
|
||||
</presentation>
|
||||
<methods>
|
||||
<method id="DoExecute">
|
||||
<comment> /**
|
||||
*
|
||||
* Create EventiTopNotification for each recipient
|
||||
* @param $oTrigger
|
||||
* @param $aContextArgs
|
||||
*
|
||||
* @return void
|
||||
* @throws \ArchivedObjectException
|
||||
* @throws \CoreCannotSaveObjectException
|
||||
* @throws \CoreException
|
||||
* @throws \CoreUnexpectedValue
|
||||
* @throws \CoreWarning
|
||||
* @throws \MySQLException
|
||||
* @throws \OQLException
|
||||
*/</comment>
|
||||
<static>false</static>
|
||||
<access>public</access>
|
||||
<code><![CDATA[
|
||||
public function DoExecute($oTrigger, $aContextArgs)
|
||||
{
|
||||
$oRecipientsSearch = DBObjectSearch::FromOQL($this->Get('recipients'));
|
||||
$oRecipientsSearch->AllowAllData();
|
||||
$oRecipientsSet = new DBObjectSet($oRecipientsSearch);
|
||||
$bIsAsync = $this->IsAsynchronous();
|
||||
[$sPreviousLanguage, $aPreviousPluginProperties] = $this->SetNotificationLanguage();
|
||||
|
||||
if($bIsAsync === true){
|
||||
$aRecipients = [];
|
||||
}
|
||||
|
||||
$sMessage = MetaModel::ApplyParams($this->Get('message'), $aContextArgs);
|
||||
$sTitle = MetaModel::ApplyParams($this->Get('title'), $aContextArgs);
|
||||
$sUrl = MetaModel::ApplyParams($this->Get('url'), $aContextArgs);
|
||||
$iObjectId = 0;
|
||||
$sObjectClass = null;
|
||||
if (array_key_exists('this->object()', $aContextArgs)) {
|
||||
$iObjectId = $aContextArgs['this->object()']->GetKey();
|
||||
$sObjectClass = get_class($aContextArgs['this->object()']);
|
||||
}
|
||||
|
||||
while ($oRecipient = $oRecipientsSet->Fetch()) {
|
||||
// Skip recipients that have no users
|
||||
if (get_class($oRecipient) === Person::class && UserRights::GetUserFromPerson($oRecipient) === null) {
|
||||
continue;
|
||||
}
|
||||
if (!\Combodo\iTop\Service\Notification\NotificationsService::GetInstance()->IsSubscribed($oTrigger, $this, $oRecipient)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if($bIsAsync === true) {
|
||||
$aRecipients[] = $oRecipient->GetKey();
|
||||
} else {
|
||||
$oEvent = Combodo\iTop\Service\Notification\Event\EventiTopNotificationService::MakeEventFromAction($this, $oRecipient->GetKey(), $oTrigger->GetKey(), $sMessage, $sTitle, $sUrl, $iObjectId, $sObjectClass);
|
||||
$oEvent->DBInsertNoReload();
|
||||
}
|
||||
|
||||
\Combodo\iTop\Service\Notification\NotificationsService::GetInstance()->RegisterSubscription($oTrigger, $this, $oRecipient);
|
||||
}
|
||||
if ($bIsAsync === true) {
|
||||
AsyncSendiTopNotifications::AddToQueue($this->GetKey(), $oTrigger->GetKey(), $aRecipients, $sMessage, $sTitle, $sUrl, $iObjectId, $sObjectClass);
|
||||
}
|
||||
$this->SetNotificationLanguage($sPreviousLanguage, $aPreviousPluginProperties['language_code'] ?? null);
|
||||
}
|
||||
]]></code>
|
||||
</method>
|
||||
<method id="GetAsynchronousGlobalSetting">
|
||||
<comment></comment>
|
||||
<static>true</static>
|
||||
<access>public</access>
|
||||
<code><![CDATA[
|
||||
public static function GetAsynchronousGlobalSetting(): bool
|
||||
{
|
||||
return utils::GetConfig()->Get('notifications.itop.send_asynchronously');
|
||||
}
|
||||
]]></code>
|
||||
</method>
|
||||
</methods>
|
||||
</class>
|
||||
<class id="EventiTopNotification" _delta="define">
|
||||
<php_parent>
|
||||
<name>EventNotification</name>
|
||||
</php_parent>
|
||||
<parent>cmdbAbstractObject</parent>
|
||||
<properties>
|
||||
<category>core/cmdb,view_in_gui</category>
|
||||
<abstract>false</abstract>
|
||||
<key_type>autoincrement</key_type>
|
||||
<db_table>priv_event_itop_notif</db_table>
|
||||
<db_key_field>id</db_key_field>
|
||||
<db_final_class_field/>
|
||||
<naming>
|
||||
<attributes>
|
||||
<attribute id="title"/>
|
||||
</attributes>
|
||||
</naming>
|
||||
</properties>
|
||||
<fields>
|
||||
<field id="title" xsi:type="AttributeString">
|
||||
<sql>title</sql>
|
||||
<default_value/>
|
||||
<is_null_allowed>false</is_null_allowed>
|
||||
</field>
|
||||
<field id="icon" xsi:type="AttributeImage">
|
||||
<sql>icon</sql>
|
||||
<default_value/>
|
||||
<is_null_allowed>true</is_null_allowed>
|
||||
<default_image />
|
||||
</field>
|
||||
<field id="priority" xsi:type="AttributeEnum">
|
||||
<sql>priority</sql>
|
||||
<values>
|
||||
<value id="1">
|
||||
<code>1</code>
|
||||
</value>
|
||||
<value id="2">
|
||||
<code>2</code>
|
||||
</value>
|
||||
<value id="3">
|
||||
<code>3</code>
|
||||
</value>
|
||||
<value id="4">
|
||||
<code>4</code>
|
||||
</value>
|
||||
</values>
|
||||
<default_value>4</default_value>
|
||||
<is_null_allowed>false</is_null_allowed>
|
||||
</field>
|
||||
<field id="url" xsi:type="AttributeURL">
|
||||
<sql>url</sql>
|
||||
<default_value/>
|
||||
<is_null_allowed>false</is_null_allowed>
|
||||
<target>_blank</target>
|
||||
</field>
|
||||
<field id="read" xsi:type="AttributeEnum">
|
||||
<sql>read</sql>
|
||||
<values>
|
||||
<value id="yes">
|
||||
<code>yes</code>
|
||||
</value>
|
||||
<value id="no">
|
||||
<code>no</code>
|
||||
</value>
|
||||
</values>
|
||||
<default_value>no</default_value>
|
||||
<is_null_allowed>false</is_null_allowed>
|
||||
</field>
|
||||
<field id="read_date" xsi:type="AttributeDateTime">
|
||||
<sql>read_date</sql>
|
||||
<default_value/>
|
||||
<is_null_allowed>true</is_null_allowed>
|
||||
</field>
|
||||
<field id="contact_id" xsi:type="AttributeExternalKey">
|
||||
<sql>contact_id</sql>
|
||||
<target_class>Contact</target_class>
|
||||
<default_value/>
|
||||
<is_null_allowed>false</is_null_allowed>
|
||||
</field>
|
||||
</fields>
|
||||
<presentation>
|
||||
<summary>
|
||||
<items>
|
||||
<item id="date">
|
||||
<rank>10</rank>
|
||||
</item>
|
||||
<item id="message">
|
||||
<rank>20</rank>
|
||||
</item>
|
||||
</items>
|
||||
</summary>
|
||||
</presentation>
|
||||
<methods/>
|
||||
</class>
|
||||
</classes>
|
||||
<user_rights>
|
||||
<profiles>
|
||||
<profile id="1024" _delta="define">
|
||||
@@ -282,8 +693,50 @@
|
||||
<field id="obj_attcode" xsi:type="AttributeString"/>
|
||||
</fields>
|
||||
</class>
|
||||
<class id="DefaultWorkingTimeComputer" _delta="define">
|
||||
<interfaces>
|
||||
<interface id="iWorkingTimeComputer"/>
|
||||
</interfaces>
|
||||
</class>
|
||||
<class id="ActionNotification" _delta="define">
|
||||
<!-- Generated by toolkit/export-class-to-meta.php -->
|
||||
<parent>Action</parent>
|
||||
<properties>
|
||||
<category>grant_by_profile,core/cmdb</category>
|
||||
</properties>
|
||||
<fields>
|
||||
<field id="name" xsi:type="AttributeString"/>
|
||||
<field id="description" xsi:type="AttributeString"/>
|
||||
<field id="status" xsi:type="AttributeEnum"/>
|
||||
<field id="trigger_list" xsi:type="AttributeLinkedSetIndirect"/>
|
||||
<field id="language" xsi:type="AttributeApplicationLanguage"/>
|
||||
</fields>
|
||||
</class>
|
||||
<class id="EventNotification" _delta="define">
|
||||
<!-- Generated by toolkit/export-class-to-meta.php -->
|
||||
<parent>Event</parent>
|
||||
<properties>
|
||||
<category>core/cmdb,view_in_gui</category>
|
||||
</properties>
|
||||
<fields>
|
||||
<field id="message" xsi:type="AttributeText"/>
|
||||
<field id="date" xsi:type="AttributeDateTime"/>
|
||||
<field id="userinfo" xsi:type="AttributeString"/>
|
||||
<field id="trigger_id" xsi:type="AttributeExternalKey">
|
||||
<target_class>Trigger</target_class>
|
||||
</field>
|
||||
<field id="action_id" xsi:type="AttributeExternalKey">
|
||||
<target_class>Action</target_class>
|
||||
</field>
|
||||
<field id="object_id" xsi:type="AttributeInteger"/>
|
||||
<field id="trigger_id_friendlyname" xsi:type="AttributeExternalField"/>
|
||||
<field id="trigger_id_finalclass_recall" xsi:type="AttributeExternalField"/>
|
||||
<field id="action_id_friendlyname" xsi:type="AttributeExternalField"/>
|
||||
<field id="action_id_finalclass_recall" xsi:type="AttributeExternalField"/>
|
||||
</fields>
|
||||
</class>
|
||||
</classes>
|
||||
<attribute_properties_definition _delta="define">
|
||||
<attribute_properties_definition _delta="define">
|
||||
<properties>
|
||||
<property id="sql">
|
||||
<php_param>sql</php_param>
|
||||
@@ -502,6 +955,12 @@
|
||||
<type>boolean</type>
|
||||
<default>false</default>
|
||||
</property>
|
||||
<property id="with_php_computation">
|
||||
<php_param>with_php_computation</php_param>
|
||||
<mandatory>false</mandatory>
|
||||
<type>boolean</type>
|
||||
<default>false</default>
|
||||
</property>
|
||||
<property id="create_temporary_object">
|
||||
<php_param>create_temporary_object</php_param>
|
||||
<mandatory>false</mandatory>
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -6,7 +6,102 @@
|
||||
|
||||
/** @internal Dev hack for disabling some query build optimizations (Folding/Merging) */
|
||||
define('ENABLE_OPT', true);
|
||||
class DBSharedSearch extends DBObjectSearch {
|
||||
|
||||
public function MakeSelectQuery($aOrderBy = array(), $aArgs = array(), $aAttToLoad = null, $aExtendedDataSpec = null, $iLimitCount = 0, $iLimitStart = 0, $bGetCount = false, $bBeautifulSQL = true)
|
||||
{
|
||||
// Check the order by specification, and prefix with the class alias
|
||||
// and make sure that the ordering columns are going to be selected
|
||||
//
|
||||
$sClass = $this->GetClass();
|
||||
$sClassAlias = $this->GetClassAlias();
|
||||
$aOrderSpec = array();
|
||||
foreach ($aOrderBy as $sFieldAlias => $bAscending)
|
||||
{
|
||||
if (!is_bool($bAscending))
|
||||
{
|
||||
throw new CoreException("Wrong direction in ORDER BY spec, found '$bAscending' and expecting a boolean value");
|
||||
}
|
||||
|
||||
$iDotPos = strpos($sFieldAlias, '.');
|
||||
if ($iDotPos === false)
|
||||
{
|
||||
$sAttClass = $sClass;
|
||||
$sAttClassAlias = $sClassAlias;
|
||||
$sAttCode = $sFieldAlias;
|
||||
}
|
||||
else
|
||||
{
|
||||
$sAttClassAlias = substr($sFieldAlias, 0, $iDotPos);
|
||||
$sAttClass = $this->GetClassName($sAttClassAlias);
|
||||
$sAttCode = substr($sFieldAlias, $iDotPos + 1);
|
||||
}
|
||||
|
||||
if ($sAttCode != 'id')
|
||||
{
|
||||
MyHelpers::CheckValueInArray('field name in ORDER BY spec', $sAttCode, MetaModel::GetAttributesList($sAttClass));
|
||||
|
||||
$oAttDef = MetaModel::GetAttributeDef($sAttClass, $sAttCode);
|
||||
foreach($oAttDef->GetOrderBySQLExpressions($sAttClassAlias) as $sSQLExpression)
|
||||
{
|
||||
$aOrderSpec[$sSQLExpression] = $bAscending;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$aOrderSpec['`'.$sAttClassAlias.$sAttCode.'`'] = $bAscending;
|
||||
}
|
||||
|
||||
// Make sure that the columns used for sorting are present in the loaded columns
|
||||
if (!is_null($aAttToLoad) && !isset($aAttToLoad[$sAttClassAlias][$sAttCode]))
|
||||
{
|
||||
$aAttToLoad[$sAttClassAlias][$sAttCode] = MetaModel::GetAttributeDef($sAttClass, $sAttCode);
|
||||
}
|
||||
}
|
||||
/*******START difference with MakeSelectQuery **************/
|
||||
$sClass = key($aAttToLoad);
|
||||
$sKey = $aAttToLoad[$sClass][0];
|
||||
$oObjId = new FieldExpression($sKey, $sClass);
|
||||
|
||||
$oSQLQuery = $this->GetSQLQuery($aOrderBy, $aArgs, [], $aExtendedDataSpec, $iLimitCount, $iLimitStart, $bGetCount, null, [$oObjId] );
|
||||
/********END difference with MakeSelectQuery*************/
|
||||
|
||||
if ($this->m_bNoContextParameters)
|
||||
{
|
||||
// Only internal parameters
|
||||
$aScalarArgs = $this->GetInternalParams();
|
||||
}
|
||||
else
|
||||
{
|
||||
// The complete list of arguments will include magic arguments (e.g. current_user->attcode)
|
||||
$aScalarArgs = MetaModel::PrepareQueryArguments($aArgs, $this->GetInternalParams(), $this->GetExpectedArguments());
|
||||
}
|
||||
try
|
||||
{
|
||||
$sRes = $oSQLQuery->RenderSelect($aOrderSpec, $aScalarArgs, $iLimitCount, $iLimitStart, $bGetCount, $bBeautifulSQL);
|
||||
if ($sClassAlias == '_itop_')
|
||||
{
|
||||
IssueLog::Info('SQL Query (_itop_): '.$sRes);
|
||||
}
|
||||
}
|
||||
catch (MissingQueryArgument $e)
|
||||
{
|
||||
// Add some information...
|
||||
$e->addInfo('OQL', $this->ToOQL());
|
||||
throw $e;
|
||||
}
|
||||
$this->AddQueryTraceSelect($oSQLQuery->GetSourceOQL(), $aOrderBy, $aScalarArgs, $aAttToLoad, $aExtendedDataSpec, $iLimitCount, $iLimitStart, $bGetCount, $sRes);
|
||||
return $sRes;
|
||||
}
|
||||
protected function GetSQLQuery($aOrderBy, $aArgs, $aAttToLoad, $aExtendedDataSpec, $iLimitCount, $iLimitStart, $bGetCount, $aGroupByExpr = null, $aSelectExpr = null)
|
||||
{
|
||||
$oSQLQuery = parent::GetSQLQuery($aOrderBy, $aArgs, $aAttToLoad, $aExtendedDataSpec, $iLimitCount, $iLimitStart, $bGetCount, $aGroupByExpr, $aSelectExpr);
|
||||
|
||||
$oSQLQuery->SetSelect($aSelectExpr);
|
||||
return $oSQLQuery;
|
||||
}
|
||||
|
||||
}
|
||||
/**
|
||||
* A search over a DBObject
|
||||
*
|
||||
@@ -909,15 +1004,15 @@ class DBObjectSearch extends DBSearch
|
||||
*/
|
||||
public function AddCondition_PointingTo(DBObjectSearch $oFilter, $sExtKeyAttCode, $iOperatorCode = TREE_OPERATOR_EQUALS, &$aRealiasingMap = null)
|
||||
{
|
||||
if (!MetaModel::IsValidKeyAttCode($this->GetClass(), $sExtKeyAttCode))
|
||||
if (!MetaModel::IsValidKeyAttCode($this->GetClass(), $sExtKeyAttCode))
|
||||
{
|
||||
throw new CoreWarning("The attribute code '$sExtKeyAttCode' is not an external key of the class '{$this->GetClass()}'");
|
||||
}
|
||||
$oAttExtKey = MetaModel::GetAttributeDef($this->GetClass(), $sExtKeyAttCode);
|
||||
if(!MetaModel::IsSameFamilyBranch($oFilter->GetClass(), $oAttExtKey->GetTargetClass()))
|
||||
{
|
||||
throw new CoreException("The specified filter (pointing to {$oFilter->GetClass()}) is not compatible with the key '{$this->GetClass()}::$sExtKeyAttCode', which is pointing to {$oAttExtKey->GetTargetClass()}");
|
||||
}
|
||||
throw new CoreException("The specified filter (pointing to {$oFilter->GetClass()}) is not compatible with the key '{$this->GetClass()}::$sExtKeyAttCode', which is pointing to {$oAttExtKey->GetTargetClass()}");
|
||||
}
|
||||
if(($iOperatorCode != TREE_OPERATOR_EQUALS) && !($oAttExtKey instanceof AttributeHierarchicalKey))
|
||||
{
|
||||
throw new CoreException("The specified tree operator $iOperatorCode is not applicable to the key '{$this->GetClass()}::$sExtKeyAttCode', which is not a HierarchicalKey");
|
||||
@@ -1616,6 +1711,10 @@ class DBObjectSearch extends DBSearch
|
||||
{
|
||||
return NestedQueryExpression::FromOQLObjectQuery($oExpression->GetOQLObjectQuery());
|
||||
}
|
||||
elseif ($oExpression instanceof SharedQueryExpression)
|
||||
{
|
||||
return SharedQueryExpression::FromOQLObjectQuery($oExpression->GetOQLObjectQuery());
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new CoreException('Unknown expression type', array('class'=>get_class($oExpression), 'query'=>$sQuery));
|
||||
|
||||
@@ -851,11 +851,11 @@ abstract class DBSearch
|
||||
return;
|
||||
}
|
||||
|
||||
if (count($aColumns) == 0)
|
||||
{
|
||||
$aColumns = array_keys(MetaModel::ListAttributeDefs($this->GetClass()));
|
||||
// Add the standard id (as first column)
|
||||
array_unshift($aColumns, 'id');
|
||||
if (count($aColumns) == 0)
|
||||
{
|
||||
$aColumns = array_keys(MetaModel::ListAttributeDefs($this->GetClass()));
|
||||
// Add the standard id (as first column)
|
||||
array_unshift($aColumns, 'id');
|
||||
}
|
||||
|
||||
$aQueryCols = CMDBSource::GetColumns($resQuery, $sSQL);
|
||||
@@ -885,6 +885,55 @@ abstract class DBSearch
|
||||
return $aRes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Selects a column ($sAttCode) from the specified class ($sClassAlias - default main class) of the DBsearch object and gives the result as an array
|
||||
* @param string $sAttCode
|
||||
* @param string|null $sClassAlias
|
||||
*
|
||||
* @return array
|
||||
* @throws ConfigException
|
||||
* @throws CoreException
|
||||
* @throws MissingQueryArgument
|
||||
* @throws MySQLException
|
||||
* @throws MySQLHasGoneAwayException
|
||||
*/
|
||||
public function SelectAttributeToArray(string $sAttCode, ?string $sClassAlias = null):array
|
||||
{
|
||||
if(is_null($sClassAlias)) {
|
||||
$sClassAlias = $this->GetClassAlias();
|
||||
}
|
||||
|
||||
$sClass = $this->GetClass();
|
||||
if($sAttCode === 'id'){
|
||||
$aAttToLoad[$sClassAlias]=[];
|
||||
} else {
|
||||
$aAttToLoad[$sClassAlias][$sAttCode] = MetaModel::GetAttributeDef($sClass, $sAttCode);
|
||||
}
|
||||
|
||||
$sSQL = $this->MakeSelectQuery([], [], $aAttToLoad);
|
||||
$resQuery = CMDBSource::Query($sSQL);
|
||||
if (!$resQuery)
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
$sColName = $sClassAlias.$sAttCode;
|
||||
|
||||
$aRes = [];
|
||||
while ($aRow = CMDBSource::FetchArray($resQuery))
|
||||
{
|
||||
$aMappedRow = array();
|
||||
if($sAttCode === 'id') {
|
||||
$aMappedRow[$sAttCode] = $aRow[$sColName];
|
||||
} else {
|
||||
$aMappedRow[$sAttCode] = $aAttToLoad[$sClassAlias][$sAttCode]->FromSQLToValue($aRow, $sColName);
|
||||
}
|
||||
$aRes[] = $aMappedRow;
|
||||
}
|
||||
CMDBSource::FreeResult($resQuery);
|
||||
return $aRes;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Construction of the SQL queries
|
||||
|
||||
@@ -64,16 +64,22 @@ class DesignDocument extends DOMDocument
|
||||
/**
|
||||
* Overload of the standard API
|
||||
*
|
||||
* @param $filename
|
||||
* @param string $filename
|
||||
* @param int $options
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function load($filename, $options = null)
|
||||
public function load(string $filename, int $options = 0): bool
|
||||
{
|
||||
libxml_clear_errors();
|
||||
if (parent::load($filename, LIBXML_NOBLANKS) === false) {
|
||||
$aErrors = libxml_get_errors();
|
||||
IssueLog::Error("Error loading $filename", LogAPI::CHANNEL_DEFAULT, $aErrors);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -16,8 +16,14 @@
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with iTop. If not, see <http://www.gnu.org/licenses/>
|
||||
use Combodo\iTop\Application\Helper\WebResourcesHelper;
|
||||
use Combodo\iTop\Application\UI\Base\Component\Html\Html;
|
||||
use Combodo\iTop\Application\UI\Base\Component\MedallionIcon\MedallionIcon;
|
||||
use Combodo\iTop\Application\UI\Base\Component\Panel\Panel;
|
||||
use Combodo\iTop\Application\UI\Base\Layout\UIContentBlock;
|
||||
use Combodo\iTop\Application\UI\Base\Layout\UIContentBlockUIBlockFactory;
|
||||
use Combodo\iTop\Application\WebPage\iTopPDF;
|
||||
use Combodo\iTop\Application\WebPage\PDFPage;
|
||||
use Combodo\iTop\Application\WebPage\WebPage;
|
||||
use Combodo\iTop\Renderer\BlockRenderer;
|
||||
|
||||
/**
|
||||
@@ -31,6 +37,7 @@ class DisplayableNode extends GraphNode
|
||||
{
|
||||
public $x;
|
||||
public $y;
|
||||
public bool $bFiltered;
|
||||
|
||||
/**
|
||||
* Create a new node inside a graph
|
||||
@@ -59,7 +66,7 @@ class DisplayableNode extends GraphNode
|
||||
|
||||
public function GetWidth()
|
||||
{
|
||||
return max(32, 5*strlen($this->GetProperty('label'))); // approximation of the text's bounding box
|
||||
return max(32, 5 * mb_strlen($this->GetProperty('label'))); // approximation of the text's bounding box
|
||||
}
|
||||
|
||||
public function GetHeight()
|
||||
@@ -488,7 +495,7 @@ class DisplayableNode extends GraphNode
|
||||
if ($bNoLabel)
|
||||
{
|
||||
// simulate a fake label with the approximate same size as the true label
|
||||
$sLabel = str_repeat('x',strlen($this->GetProperty('label', $this->GetId())));
|
||||
$sLabel = str_repeat('x', mb_strlen($this->GetProperty('label', $this->GetId())));
|
||||
$sDot = 'label="'.$sLabel.'"';
|
||||
}
|
||||
else
|
||||
@@ -1412,6 +1419,8 @@ class DisplayableGraph extends SimpleGraph
|
||||
/**
|
||||
* Display the graph inside the given page, with the "filter" drawer above it
|
||||
*
|
||||
* @deprecated 3.1.1 3.2.0 N°3767 Use \DisplayableGraph::DisplayFilterBox() and \DisplayableGraph::DisplayGraph() instead
|
||||
*
|
||||
* @param WebPage $oP
|
||||
* @param array $aResults
|
||||
* @param string $sRelation
|
||||
@@ -1425,10 +1434,35 @@ class DisplayableGraph extends SimpleGraph
|
||||
*
|
||||
* @throws \CoreException
|
||||
* @throws \DictExceptionMissingString
|
||||
*
|
||||
*/
|
||||
function Display(WebPage $oP, $aResults, $sRelation, ApplicationContext $oAppContext, $aExcludedObjects, $sObjClass, $iObjKey, $sContextKey, $aContextParams = array(), bool $bLazyLoading = false)
|
||||
{
|
||||
list($aExcludedByClass, $aAdditionalContexts) = $this->DisplayFiltering($sContextKey, $aContextParams, $aExcludedObjects, $oP, $aResults, $bLazyLoading);
|
||||
$oP->AddSubBlock($this->DisplayFilterBox($oP, $aResults, $bLazyLoading));
|
||||
$this->DisplayGraph($oP, $sRelation, $oAppContext, $aExcludedObjects, $sObjClass, $iObjKey, $sContextKey, $aContextParams, $bLazyLoading);
|
||||
}
|
||||
|
||||
/**
|
||||
* Display only the graph inside the given page, with the parameters of filter box draw with DisplayFilterBox
|
||||
*
|
||||
* @param WebPage $oP
|
||||
* @param string $sRelation
|
||||
* @param ApplicationContext $oAppContext
|
||||
* @param array $aExcludedObjects
|
||||
* @param string $sObjClass
|
||||
* @param int $iObjKey
|
||||
* @param string $sContextKey
|
||||
* @param array $aContextParams
|
||||
* @param bool $bLazyLoading
|
||||
*
|
||||
* @throws \CoreException
|
||||
* @throws \DictExceptionMissingString
|
||||
*
|
||||
* @since 3.1.1 3.2.0 N°3767
|
||||
*/
|
||||
function DisplayGraph(WebPage $oP, $sRelation, ApplicationContext $oAppContext, $aExcludedObjects, $sObjClass, $iObjKey, $sContextKey, $aContextParams = array(), bool $bLazyLoading = false): void
|
||||
{
|
||||
list($aExcludedByClass, $aAdditionalContexts) = $this->GetFilteringData($sContextKey, $aContextParams, $aExcludedObjects);
|
||||
|
||||
$iGroupingThreshold = utils::ReadParam('g', 5);
|
||||
|
||||
@@ -1513,12 +1547,10 @@ class DisplayableGraph extends SimpleGraph
|
||||
$oP->add_ready_script(" $('#$sId').simple_graph(".json_encode($aParams).");");
|
||||
} else {
|
||||
$oP->add_script("function Load(){var aExcluded = []; $('input[name^=excluded]').each( function() {if (!$(this).prop('checked')) { aExcluded.push($(this).val()); }} ); var params= $.extend(".json_encode($aParams).", {excluded_classes: aExcluded}); $('#$sId').simple_graph(params);}");
|
||||
$oP->add_ready_script("$('#impacted_objects_lists').html('".utils::TextToHtml(Dict::S('Relation:impacts/NoFilteredData'))."');$('#impacted_groups').html('".utils::TextToHtml(Dict::S('Relation:impacts/NoFilteredData'))."');");
|
||||
|
||||
$oP->add_ready_script("$('#graph').html('".utils::TextToHtml(Dict::S('Relation:impacts/NoFilteredData'))."');$('#impacted_objects_lists').html('".utils::TextToHtml(Dict::S('Relation:impacts/NoFilteredData'))."');$('#impacted_groups').html('".utils::TextToHtml(Dict::S('Relation:impacts/NoFilteredData'))."');");
|
||||
}
|
||||
}
|
||||
catch(Exception $e)
|
||||
{
|
||||
catch (Exception $e) {
|
||||
$oP->add('<div>'.$e->getMessage().'</div>');
|
||||
}
|
||||
$oP->add_script(
|
||||
@@ -1552,7 +1584,7 @@ EOF
|
||||
* @param string $sContextKey
|
||||
* @param array $aContextParams
|
||||
* @param array $aExcludedObjects
|
||||
* @param \WebPage $oP
|
||||
* @param WebPage $oP
|
||||
* @param array $aResults
|
||||
* @param bool $bLazyLoading
|
||||
*
|
||||
@@ -1563,23 +1595,41 @@ EOF
|
||||
* @throws \Twig\Error\LoaderError
|
||||
* @throws \Twig\Error\RuntimeError
|
||||
* @throws \Twig\Error\SyntaxError
|
||||
*
|
||||
* @deprecated 3.1.1 3.2.0 N°3767 Use \DisplayableGraph::DisplayFilterBox() and \DisplayableGraph::GetFilteringData() instead
|
||||
*/
|
||||
public function DisplayFiltering(string $sContextKey, array $aContextParams, array $aExcludedObjects, WebPage $oP, array $aResults, bool $bLazyLoading = false): array
|
||||
{
|
||||
$aContextDefs = static::GetContextDefinitions($sContextKey, true, $aContextParams);
|
||||
$aExcludedByClass = array();
|
||||
foreach ($aExcludedObjects as $oObj) {
|
||||
if (!array_key_exists(get_class($oObj), $aExcludedByClass)) {
|
||||
$aExcludedByClass[get_class($oObj)] = array();
|
||||
}
|
||||
$aExcludedByClass[get_class($oObj)][] = $oObj->GetKey();
|
||||
}
|
||||
$oP->Add($this->DisplayFilterBox($oP, $aResults, $bLazyLoading));
|
||||
|
||||
return $this->GetFilteringData($sContextKey, $aContextParams, $aExcludedObjects);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param WebPage $oP
|
||||
* @param array $aResults
|
||||
* @param bool $bLazyLoading
|
||||
*
|
||||
* @return UIContentBlock
|
||||
* @throws \CoreException
|
||||
* @throws \DictExceptionMissingString
|
||||
* @throws \ReflectionException
|
||||
* @throws \Twig\Error\LoaderError
|
||||
* @throws \Twig\Error\RuntimeError
|
||||
* @throws \Twig\Error\SyntaxError
|
||||
*
|
||||
* @since 3.1.1 3.2.0 N°3767
|
||||
*/
|
||||
public function DisplayFilterBox(WebPage $oP, array $aResults, bool $bLazyLoading = false): UIContentBlock
|
||||
{
|
||||
$sSftShort = Dict::S('UI:ElementsDisplayed');
|
||||
$oP->add("<div class=\"not-printable\">\n");
|
||||
$oBlock = UIContentBlockUIBlockFactory::MakeStandard(null, ['not-printable']);
|
||||
|
||||
$oUiSearchBlock = new Panel($sSftShort, [], Panel::ENUM_COLOR_SCHEME_CYAN, 'dh_flash');
|
||||
$oUiSearchBlock->SetCSSClasses(["ibo-search-form-panel", "display_block"]);
|
||||
$oUiSearchBlock->SetIsCollapsible(true);
|
||||
$oUiHtmlBlock = new Combodo\iTop\Application\UI\Base\Component\Html\Html(
|
||||
$oUiSearchBlock->SetCSSClasses(["ibo-search-form-panel", "display_block"])
|
||||
->SetIsCollapsible(true);
|
||||
|
||||
$oUiHtmlBlock = new Html(
|
||||
<<<EOF
|
||||
|
||||
<div id="ds_flash" class="search_box ibo-display-graph--search-box">
|
||||
@@ -1626,11 +1676,23 @@ EOF
|
||||
$oUiHtmlBlock->AddHtml("<button type=\"button\" id=\"ReloadMovieBtn\" class=\"ibo-button ibo-is-neutral ibo-is-regular\" onClick=\"$sOnCLick\">".Dict::S('UI:Button:Refresh')."</button></div></form>");
|
||||
}
|
||||
$oUiHtmlBlock->AddHtml("</div>\n");
|
||||
$oUiHtmlBlock->AddHtml("</div>\n"); // class="not-printable"
|
||||
|
||||
$oUiSearchBlock->AddSubBlock($oUiHtmlBlock);
|
||||
$oP->AddUiBlock($oUiSearchBlock);
|
||||
$oBlock->AddSubBlock($oUiSearchBlock);
|
||||
|
||||
return $oBlock;
|
||||
}
|
||||
|
||||
public function GetFilteringData(string $sContextKey, array $aContextParams, array $aExcludedObjects): array
|
||||
{
|
||||
$aContextDefs = static::GetContextDefinitions($sContextKey, true, $aContextParams);
|
||||
$aExcludedByClass = array();
|
||||
foreach ($aExcludedObjects as $oObj) {
|
||||
if (!array_key_exists(get_class($oObj), $aExcludedByClass)) {
|
||||
$aExcludedByClass[get_class($oObj)] = array();
|
||||
}
|
||||
$aExcludedByClass[get_class($oObj)][] = $oObj->GetKey();
|
||||
}
|
||||
$aAdditionalContexts = array();
|
||||
foreach ($aContextDefs as $sKey => $aDefinition) {
|
||||
$aAdditionalContexts[] = array('key' => $sKey, 'label' => Dict::S($aDefinition['dict']), 'oql' => $aDefinition['oql'], 'default' => (array_key_exists('default', $aDefinition) && ($aDefinition['default'] == 'yes')));
|
||||
|
||||
@@ -46,6 +46,15 @@ class EMail implements iEMail
|
||||
const ORIGINAL_FORMAT = 1; // Original format, consisting in serializing the whole object, inculding the Swift Mailer's object.
|
||||
// Did not work with attachements since their binary representation cannot be stored as a valid UTF-8 string
|
||||
const FORMAT_V2 = 2; // New format, only the raw data are serialized (base64 encoded if needed)
|
||||
|
||||
/** @var int ENUM_SEND_DEFAULT This option can be used when sending an e-mail to respect the default configuration parameter. */
|
||||
const ENUM_SEND_DEFAULT = 0;
|
||||
|
||||
/** @var int ENUM_SEND_FORCE_SYNCHRONOUS This option can be used when sending an e-mail to ignore the default and force synchronous sending instead. Example of a use case: instant e-mail test. */
|
||||
const ENUM_SEND_FORCE_SYNCHRONOUS = 1;
|
||||
|
||||
/** @var int ENUM_SEND_FORCE_ASYNCHRONOUS This option can be used when sending an e-mail to ignore the default and force synchronous sending instead. Example of a use case: Bulk mails. */
|
||||
const ENUM_SEND_FORCE_ASYNCHRONOUS = 2;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
<?php
|
||||
|
||||
use Combodo\iTop\Application\WebPage\WebPage;
|
||||
|
||||
/**
|
||||
* Copyright (C) 2013-2023 Combodo SARL
|
||||
*
|
||||
@@ -242,44 +245,33 @@ class EventIssue extends Event
|
||||
{
|
||||
if (is_string($sValue))
|
||||
{
|
||||
if (strlen($sValue) < 256)
|
||||
{
|
||||
if (mb_strlen($sValue) < 256) {
|
||||
$aPost[$sKey] = $sValue;
|
||||
} else {
|
||||
$aPost[$sKey] = "!long string: ".mb_strlen($sValue)." chars";
|
||||
}
|
||||
else
|
||||
{
|
||||
$aPost[$sKey] = "!long string: ".strlen($sValue). " chars";
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
// Not a string (avoid warnings in case the value cannot be easily casted into a string)
|
||||
$aPost[$sKey] = @(string) $sValue;
|
||||
$aPost[$sKey] = @(string)$sValue;
|
||||
}
|
||||
}
|
||||
$this->Set('arguments_post', $aPost);
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
$this->Set('arguments_post', array());
|
||||
}
|
||||
|
||||
$sLength = strlen($this->Get('issue'));
|
||||
if ($sLength > 255)
|
||||
{
|
||||
$this->Set('issue', substr($this->Get('issue'), 0, 200)." -truncated ($sLength chars)");
|
||||
$sLength = mb_strlen($this->Get('issue'));
|
||||
if ($sLength > 255) {
|
||||
$this->Set('issue', mb_substr($this->Get('issue'), 0, 210)." -truncated ($sLength chars)");
|
||||
}
|
||||
|
||||
$sLength = strlen($this->Get('impact'));
|
||||
if ($sLength > 255)
|
||||
{
|
||||
$this->Set('impact', substr($this->Get('impact'), 0, 200)." -truncated ($sLength chars)");
|
||||
$sLength = mb_strlen($this->Get('impact'));
|
||||
if ($sLength > 255) {
|
||||
$this->Set('impact', mb_substr($this->Get('impact'), 0, 210)." -truncated ($sLength chars)");
|
||||
}
|
||||
|
||||
$sLength = strlen($this->Get('page'));
|
||||
if ($sLength > 255)
|
||||
{
|
||||
$this->Set('page', substr($this->Get('page'), 0, 200)." -truncated ($sLength chars)");
|
||||
$sLength = mb_strlen($this->Get('page'));
|
||||
if ($sLength > 255) {
|
||||
$this->Set('page', mb_substr($this->Get('page'), 0, 210)." -truncated ($sLength chars)");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,6 +10,9 @@ use Combodo\iTop\Application\UI\Base\Component\Input\InputUIBlockFactory;
|
||||
use Combodo\iTop\Application\UI\Base\Component\Panel\PanelUIBlockFactory;
|
||||
use Combodo\iTop\Application\UI\Base\Layout\MultiColumn\Column\ColumnUIBlockFactory;
|
||||
use Combodo\iTop\Application\UI\Base\Layout\MultiColumn\MultiColumnUIBlockFactory;
|
||||
use Combodo\iTop\Application\Helper\ExportHelper;
|
||||
use Combodo\iTop\Application\WebPage\Page;
|
||||
use Combodo\iTop\Application\WebPage\WebPage;
|
||||
|
||||
require_once(APPROOT.'application/xlsxwriter.class.php');
|
||||
|
||||
@@ -68,7 +71,7 @@ class ExcelBulkExport extends TabularBulkExport
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \WebPage $oP
|
||||
* @param WebPage $oP
|
||||
* @param $sPartId
|
||||
*
|
||||
* @return UIContentBlock
|
||||
@@ -82,6 +85,7 @@ class ExcelBulkExport extends TabularBulkExport
|
||||
|
||||
case 'xlsx_options':
|
||||
$oPanel = PanelUIBlockFactory::MakeNeutral(Dict::S('Core:BulkExport:XLSXOptions'));
|
||||
$oPanel->AddSubBlock(ExportHelper::GetAlertForExcelMaliciousInjection());
|
||||
|
||||
$oMulticolumn = MultiColumnUIBlockFactory::MakeStandard();
|
||||
$oPanel->AddSubBlock($oMulticolumn);
|
||||
|
||||
@@ -101,7 +101,7 @@ EOF;
|
||||
EOF;
|
||||
|
||||
SetupUtils::builddir(dirname($sFilePath));
|
||||
file_put_contents($sFilePath, $content);
|
||||
file_put_contents($sFilePath, $content, LOCK_EX);
|
||||
}
|
||||
}
|
||||
Dict::SetUserLanguage($sUserLang);
|
||||
|
||||
@@ -15,6 +15,8 @@
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with iTop. If not, see <http://www.gnu.org/licenses/>
|
||||
use Combodo\iTop\Application\WebPage\Page;
|
||||
use Combodo\iTop\Application\WebPage\WebPage;
|
||||
|
||||
/**
|
||||
* Bulk export: HTML export
|
||||
@@ -37,7 +39,7 @@ class HTMLBulkExport extends TabularBulkExport
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \WebPage $oP
|
||||
* @param WebPage $oP
|
||||
* @param $sPartId
|
||||
*
|
||||
* @return UIContentBlock
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
//
|
||||
// This file is part of iTop.
|
||||
//
|
||||
// iTop is free software; you can redistribute it and/or modify
|
||||
// iTop is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
@@ -576,6 +576,11 @@ class LogChannels
|
||||
public const DATATABLE = 'Datatable';
|
||||
|
||||
public const DEADLOCK = 'DeadLock';
|
||||
/**
|
||||
* @var string Everything related to PHP sessions tracking
|
||||
* @since 3.1.1 3.2.0 N°6901
|
||||
*/
|
||||
public const SESSIONTRACKER = 'SessionTracker';
|
||||
|
||||
/**
|
||||
* @var string Everything related to the datamodel CRUD
|
||||
@@ -1085,6 +1090,11 @@ class DeadLockLog extends LogAPI
|
||||
*/
|
||||
class DeprecatedCallsLog extends LogAPI
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
* @since 3.2.0 N°4897
|
||||
*/
|
||||
public const ENUM_CHANNEL_PHP_API = 'deprecated-php-api';
|
||||
public const ENUM_CHANNEL_PHP_METHOD = 'deprecated-php-method';
|
||||
/**
|
||||
* @var string
|
||||
@@ -1138,9 +1148,13 @@ class DeprecatedCallsLog extends LogAPI
|
||||
parent::Enable($sTargetFile);
|
||||
|
||||
if (
|
||||
(false === defined('ITOP_PHPUNIT_RUNNING_CONSTANT_NAME'))
|
||||
(
|
||||
(false === defined(ITOP_PHPUNIT_RUNNING_CONSTANT_NAME))
|
||||
|| (defined(ITOP_PHPUNIT_RUNNING_CONSTANT_NAME) && (constant(ITOP_PHPUNIT_RUNNING_CONSTANT_NAME) !== true))
|
||||
)
|
||||
&& static::IsLogLevelEnabledSafe(self::LEVEL_WARNING, self::ENUM_CHANNEL_PHP_LIBMETHOD)
|
||||
) {
|
||||
IssueLog::Trace('Setting '.static::class.' error handler to catch DEPRECATED', static::ENUM_CHANNEL_PHP_LIBMETHOD);
|
||||
set_error_handler([static::class, 'DeprecatedNoticesErrorHandler'], E_DEPRECATED | E_USER_DEPRECATED);
|
||||
}
|
||||
}
|
||||
@@ -1274,6 +1288,35 @@ class DeprecatedCallsLog extends LogAPI
|
||||
static::Warning($sMessage, static::ENUM_CHANNEL_FILE);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $sImplementationClass Class implementing the deprecated API
|
||||
* @param string $sDeprecatedApi Class name of the deprecated API
|
||||
* @param string $sDeprecatedMethod Method name of the deprecated API
|
||||
* @param string|null $sAdditionalMessage Additional message, mostly used to explain what API to use instead
|
||||
*
|
||||
* @return void
|
||||
* @since 3.2.0 N°4897
|
||||
*/
|
||||
public static function NotifyDeprecatedPhpApi(string $sImplementationClass, string $sDeprecatedApi, string $sDeprecatedMethod, ?string $sAdditionalMessage = null): void
|
||||
{
|
||||
try {
|
||||
if (!static::IsLogLevelEnabled(self::LEVEL_WARNING, self::ENUM_CHANNEL_PHP_API)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
catch (ConfigException $oException) {
|
||||
return;
|
||||
}
|
||||
|
||||
$sMessage = "Implementation of {$sDeprecatedApi}::{$sDeprecatedMethod}() in class {$sImplementationClass}";
|
||||
|
||||
if (!is_null($sAdditionalMessage)) {
|
||||
$sMessage .= " : $sAdditionalMessage";
|
||||
}
|
||||
|
||||
static::Warning($sMessage, self::ENUM_CHANNEL_PHP_API);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string|null $sAdditionalMessage
|
||||
*
|
||||
|
||||
@@ -1445,8 +1445,10 @@ abstract class MetaModel
|
||||
*
|
||||
* @return AttributeDefinition[]
|
||||
* @throws \CoreException
|
||||
*
|
||||
* @see GetAttributesList for attcode list
|
||||
*/
|
||||
final static public function ListAttributeDefs($sClass)
|
||||
final public static function ListAttributeDefs($sClass)
|
||||
{
|
||||
self::_check_subclass($sClass);
|
||||
return self::$m_aAttribDefs[$sClass];
|
||||
@@ -1459,8 +1461,10 @@ abstract class MetaModel
|
||||
* @param string[] $aDesiredAttTypes Array of AttributeDefinition classes to filter the list on
|
||||
* @param string|null $sListCode If provided, attributes will be limited to those in this zlist
|
||||
*
|
||||
* @return array
|
||||
* @return string[] list of attcodes
|
||||
* @throws \CoreException
|
||||
*
|
||||
* @see ListAttributeDefs to get AttributeDefinition array instead
|
||||
*/
|
||||
final public static function GetAttributesList(string $sClass, array $aDesiredAttTypes = [], ?string $sListCode = null)
|
||||
{
|
||||
@@ -4263,16 +4267,17 @@ abstract class MetaModel
|
||||
];
|
||||
IssueLog::Warning("Unresolved placeholders due to null object in current context", null,
|
||||
$aContext);
|
||||
$aPlaceholders[$sPlaceHolderKey] = \Dict::Format("Core:Placeholder:CannotBeResolved", $sPlaceHolderKey);
|
||||
$aPlaceholders[$sPlaceHolderKey] = Dict::Format("Core:Placeholder:CannotBeResolved", $sPlaceHolderKey);
|
||||
foreach ($aCurrentUser as $sField) {
|
||||
$sPlaceHolderKey = $sPlaceHolderPrefix . "->$sField";
|
||||
$aPlaceholders[$sPlaceHolderKey] = \Dict::Format("Core:Placeholder:CannotBeResolved", $sPlaceHolderKey);
|
||||
$aPlaceholders[$sPlaceHolderKey] = Dict::Format("Core:Placeholder:CannotBeResolved", $sPlaceHolderKey);
|
||||
}
|
||||
} else {
|
||||
$aPlaceholders[$sPlaceHolderKey] = $oObject;
|
||||
foreach ($aCurrentUser as $sField) {
|
||||
$sPlaceHolderKey = $sPlaceHolderPrefix . "->$sField";
|
||||
if (false === MetaModel::IsValidAttCode(get_class($oObject), $sField)){
|
||||
// Mind that the "id" is not viewed as a valid att. code by \MetaModel::IsValidAttCode() so we have to test it manually
|
||||
if ($sField !== "id" && false === MetaModel::IsValidAttCode(get_class($oObject), $sField)){
|
||||
$aContext = [
|
||||
"current_user_id" => UserRights::GetUserId(),
|
||||
"obj_class" => get_class($oObject),
|
||||
@@ -4281,7 +4286,7 @@ abstract class MetaModel
|
||||
];
|
||||
IssueLog::Warning("Unresolved placeholder due to invalid attribute", null,
|
||||
$aContext);
|
||||
$aPlaceholders[$sPlaceHolderKey] = \Dict::Format("Core:Placeholder:CannotBeResolved", $sPlaceHolderKey);
|
||||
$aPlaceholders[$sPlaceHolderKey] = Dict::Format("Core:Placeholder:CannotBeResolved", $sPlaceHolderKey);
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -5151,7 +5156,7 @@ abstract class MetaModel
|
||||
*/
|
||||
protected static function DBCreateTables($aCallback = null)
|
||||
{
|
||||
list($aErrors, $aSugFix, $aCondensedQueries) = self::DBCheckFormat();
|
||||
[$aErrors, $aSugFix, $aCondensedQueries] = self::DBCheckFormat();
|
||||
|
||||
//$sSQL = implode('; ', $aCondensedQueries); Does not work - multiple queries not allowed
|
||||
foreach($aCondensedQueries as $sQuery)
|
||||
@@ -5173,7 +5178,7 @@ abstract class MetaModel
|
||||
*/
|
||||
protected static function DBCreateViews()
|
||||
{
|
||||
list($aErrors, $aSugFix) = self::DBCheckViews();
|
||||
[$aErrors, $aSugFix] = self::DBCheckViews();
|
||||
|
||||
foreach($aSugFix as $sClass => $aTarget)
|
||||
{
|
||||
@@ -6841,18 +6846,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($sClass, $iKey);
|
||||
if ($oObject !== false) {
|
||||
return $oObject;
|
||||
}
|
||||
}
|
||||
|
||||
return new $sClass($aRow, $sClassAlias, $aAttToLoad, $aExtendedDataSpec);
|
||||
}
|
||||
|
||||
@@ -6922,6 +6915,22 @@ abstract class MetaModel
|
||||
return $iCount === 1;
|
||||
}
|
||||
|
||||
public static function GetFinalClassName(string $sClass, int $iKey): string
|
||||
{
|
||||
if (MetaModel::IsStandaloneClass($sClass)) {
|
||||
return $sClass;
|
||||
}
|
||||
|
||||
$sRootClass = MetaModel::GetRootClass($sClass);
|
||||
$sTable = MetaModel::DBGetTable($sRootClass);
|
||||
$sKeyCol = MetaModel::DBGetKey($sRootClass);
|
||||
$sEscapedKey = CMDBSource::Quote($iKey);
|
||||
$sFinalClassField = Metamodel::DBGetClassField($sRootClass);
|
||||
|
||||
$sQuery = "SELECT `{$sFinalClassField}` FROM `{$sTable}` WHERE `{$sKeyCol}` = {$sEscapedKey}";
|
||||
return CMDBSource::QueryToScalar($sQuery);
|
||||
}
|
||||
|
||||
/**
|
||||
* Search for the specified class and id. If the object is archived it will be returned anyway (this is for pre-2.4
|
||||
* module compatibility, see N.1108)
|
||||
@@ -7159,32 +7168,45 @@ abstract class MetaModel
|
||||
*/
|
||||
public static function PurgeData($oFilter)
|
||||
{
|
||||
$iMaxChunkSize = MetaModel::GetConfig()->Get('purge_data.max_chunk_size');
|
||||
$sTargetClass = $oFilter->GetClass();
|
||||
$oSet = new DBObjectSet($oFilter);
|
||||
$oSet->OptimizeColumnLoad(array($sTargetClass => array('finalclass')));
|
||||
$aIdToClass = $oSet->GetColumnAsArray('finalclass', true);
|
||||
$iNbIdsDeleted = 0;
|
||||
$bExecuteQuery = true;
|
||||
|
||||
$aIds = array_keys($aIdToClass);
|
||||
if (count($aIds) > 0)
|
||||
{
|
||||
$aQuotedIds = CMDBSource::Quote($aIds);
|
||||
$sIdList = implode(',', $aQuotedIds);
|
||||
$aTargetClasses = array_merge(
|
||||
self::EnumChildClasses($sTargetClass, ENUM_CHILD_CLASSES_ALL),
|
||||
self::EnumParentClasses($sTargetClass, ENUM_PARENT_CLASSES_EXCLUDELEAF)
|
||||
);
|
||||
foreach($aTargetClasses as $sSomeClass)
|
||||
{
|
||||
$sTable = MetaModel::DBGetTable($sSomeClass);
|
||||
$sPKField = MetaModel::DBGetKey($sSomeClass);
|
||||
// This loop allows you to delete objects in batches of $iMaxChunkSize elements
|
||||
while ($bExecuteQuery) {
|
||||
$oSet = new DBObjectSet($oFilter);
|
||||
$oSet->SetLimit($iMaxChunkSize);
|
||||
$oSet->OptimizeColumnLoad(array($sTargetClass => array('finalclass')));
|
||||
$aIdToClass = $oSet->GetColumnAsArray('finalclass', true);
|
||||
|
||||
$sDeleteSQL = "DELETE FROM `$sTable` WHERE `$sPKField` IN ($sIdList)";
|
||||
CMDBSource::DeleteFrom($sDeleteSQL);
|
||||
$aIds = array_keys($aIdToClass);
|
||||
$iNbIds = count($aIds);
|
||||
if ($iNbIds > 0) {
|
||||
$aQuotedIds = CMDBSource::Quote($aIds);
|
||||
$sIdList = implode(',', $aQuotedIds);
|
||||
$aTargetClasses = array_merge(
|
||||
self::EnumChildClasses($sTargetClass, ENUM_CHILD_CLASSES_ALL),
|
||||
self::EnumParentClasses($sTargetClass, ENUM_PARENT_CLASSES_EXCLUDELEAF)
|
||||
);
|
||||
foreach ($aTargetClasses as $sSomeClass) {
|
||||
$sTable = MetaModel::DBGetTable($sSomeClass);
|
||||
$sPKField = MetaModel::DBGetKey($sSomeClass);
|
||||
|
||||
$sDeleteSQL = "DELETE FROM `$sTable` WHERE `$sPKField` IN ($sIdList)";
|
||||
CMDBSource::DeleteFrom($sDeleteSQL);
|
||||
}
|
||||
$iNbIdsDeleted += $iNbIds;
|
||||
}
|
||||
|
||||
// stop loop if query returned fewer objects than $iMaxChunkSize. In this case, all objects have been deleted.
|
||||
if ($iNbIds < $iMaxChunkSize) {
|
||||
$bExecuteQuery = false;
|
||||
}
|
||||
}
|
||||
return count($aIds);
|
||||
}
|
||||
|
||||
return $iNbIdsDeleted;
|
||||
}
|
||||
// Links
|
||||
//
|
||||
//
|
||||
|
||||
@@ -22,7 +22,9 @@
|
||||
* A class to serialize the execution of some code sections
|
||||
* Emulates the API of PECL Mutex class
|
||||
* Relies on MySQL locks because the API sem_get is not always present in the
|
||||
* installed PHP.
|
||||
* installed PHP.
|
||||
*
|
||||
* @link https://dev.mysql.com/doc/refman/5.7/en/locking-functions.html MySQL locking functions documentation
|
||||
*
|
||||
* @copyright Copyright (C) 2013-2023 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
|
||||
@@ -739,7 +739,7 @@ class PHP_ParserGenerator
|
||||
while (isset($errmsg[$restart]) && $errmsg[$restart] == ' ') {
|
||||
$restart++;
|
||||
}
|
||||
printf("%s%.${end}s\n", $prefix, $errmsg);
|
||||
printf("%s%.{$end}s\n", $prefix, $errmsg);
|
||||
$errmsg = substr($errmsg, $restart);
|
||||
}
|
||||
}
|
||||
@@ -771,7 +771,7 @@ class PHP_ParserGenerator
|
||||
for ($j = $i; $j < $this->nsymbol; $j += $skip) {
|
||||
$sp = $this->symbols[$j];
|
||||
//assert( sp->index==j );
|
||||
printf(" %3d %-${maxlen}.${maxlen}s", $j, $sp->name);
|
||||
printf(" %3d %-{$maxlen}.{$maxlen}s", $j, $sp->name);
|
||||
}
|
||||
print "\n";
|
||||
}
|
||||
|
||||
@@ -231,19 +231,19 @@ class PHP_ParserGenerator_Action
|
||||
switch ($this->type)
|
||||
{
|
||||
case self::SHIFT:
|
||||
fprintf($fp, "%${indent}s shift %d", $this->sp->name, $this->x->statenum);
|
||||
fprintf($fp, "%{$indent}s shift %d", $this->sp->name, $this->x->statenum);
|
||||
break;
|
||||
case self::REDUCE:
|
||||
fprintf($fp, "%${indent}s reduce %d", $this->sp->name, $this->x->index);
|
||||
fprintf($fp, "%{$indent}s reduce %d", $this->sp->name, $this->x->index);
|
||||
break;
|
||||
case self::ACCEPT:
|
||||
fprintf($fp, "%${indent}s accept", $this->sp->name);
|
||||
fprintf($fp, "%{$indent}s accept", $this->sp->name);
|
||||
break;
|
||||
case self::ERROR:
|
||||
fprintf($fp, "%${indent}s error", $this->sp->name);
|
||||
fprintf($fp, "%{$indent}s error", $this->sp->name);
|
||||
break;
|
||||
case self::CONFLICT:
|
||||
fprintf($fp, "%${indent}s reduce %-3d ** Parsing conflict **", $this->sp->name, $this->x->index);
|
||||
fprintf($fp, "%{$indent}s reduce %-3d ** Parsing conflict **", $this->sp->name, $this->x->index);
|
||||
break;
|
||||
case self::SH_RESOLVED:
|
||||
case self::RD_RESOLVED:
|
||||
|
||||
@@ -20,6 +20,7 @@ use Combodo\iTop\Application\UI\Base\Component\CollapsibleSection\CollapsibleSec
|
||||
use Combodo\iTop\Application\UI\Base\Component\Html\Html;
|
||||
use Combodo\iTop\Application\UI\Base\iUIBlock;
|
||||
use Combodo\iTop\Application\UI\Base\Layout\UIContentBlockUIBlockFactory;
|
||||
use Combodo\iTop\Application\WebPage\WebPage;
|
||||
use Combodo\iTop\Renderer\BlockRenderer;
|
||||
|
||||
define('CASELOG_VISIBLE_ITEMS', 2);
|
||||
@@ -169,7 +170,7 @@ class ormCaseLog {
|
||||
}
|
||||
|
||||
// Process the case of an eventual remainder (quick migration of AttributeText fields)
|
||||
if ($iPos < (strlen($this->m_sLog) - 1))
|
||||
if ($iPos < (utils::StrLen($this->m_sLog) - 1))
|
||||
{
|
||||
$sTextEntry = substr($this->m_sLog, $iPos);
|
||||
|
||||
@@ -292,7 +293,7 @@ class ormCaseLog {
|
||||
}
|
||||
|
||||
// Process the case of an eventual remainder (quick migration of AttributeText fields)
|
||||
if ($iPos < (strlen($this->m_sLog) - 1)) {
|
||||
if ($iPos < (utils::StrLen($this->m_sLog) - 1)) {
|
||||
$sTextEntry = substr($this->m_sLog, $iPos);
|
||||
$sTextEntry = str_replace(array("\r\n", "\n", "\r"), "<br/>", utils::EscapeHtml($sTextEntry));
|
||||
|
||||
@@ -373,7 +374,7 @@ class ormCaseLog {
|
||||
}
|
||||
|
||||
// Process the case of an eventual remainder (quick migration of AttributeText fields)
|
||||
if ($iPos < (strlen($this->m_sLog) - 1)) {
|
||||
if ($iPos < (utils::StrLen($this->m_sLog) - 1)) {
|
||||
$sTextEntry = substr($this->m_sLog, $iPos);
|
||||
$sTextEntry = str_replace(array("\r\n", "\n", "\r"), "<br/>", utils::EscapeHtml($sTextEntry));
|
||||
|
||||
@@ -467,7 +468,7 @@ 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 < (utils::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));
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
*/
|
||||
|
||||
use Combodo\iTop\Application\WebPage\WebPage;
|
||||
use Combodo\iTop\Service\Events\EventData;
|
||||
use Combodo\iTop\Service\Events\EventService;
|
||||
|
||||
@@ -343,6 +344,6 @@ class ormDocument
|
||||
*/
|
||||
public function GetSignature(): string
|
||||
{
|
||||
return md5($this->GetData());
|
||||
return md5($this->GetData() ?? '');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,10 +8,13 @@ use Combodo\iTop\Application\UI\Base\Component\FieldSet\FieldSetUIBlockFactory;
|
||||
use Combodo\iTop\Application\UI\Base\Component\Html\Html;
|
||||
use Combodo\iTop\Application\UI\Base\Component\Input\InputUIBlockFactory;
|
||||
use Combodo\iTop\Application\UI\Base\Component\Input\Select\SelectOptionUIBlockFactory;
|
||||
use Combodo\iTop\Application\UI\Base\Component\Input\SelectUIBlockFactory;
|
||||
use Combodo\iTop\Application\UI\Base\Component\Input\Select\SelectUIBlockFactory;
|
||||
use Combodo\iTop\Application\UI\Base\Component\Panel\PanelUIBlockFactory;
|
||||
use Combodo\iTop\Application\UI\Base\Layout\MultiColumn\Column\ColumnUIBlockFactory;
|
||||
use Combodo\iTop\Application\UI\Base\Layout\MultiColumn\MultiColumnUIBlockFactory;
|
||||
use Combodo\iTop\Application\WebPage\Page;
|
||||
use Combodo\iTop\Application\WebPage\PDFPage;
|
||||
use Combodo\iTop\Application\WebPage\WebPage;
|
||||
|
||||
/**
|
||||
* Bulk export: PDF export, based on the HTML export converted to PDF
|
||||
@@ -49,7 +52,7 @@ class PDFBulkExport extends HTMLBulkExport
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \WebPage $oP
|
||||
* @param WebPage $oP
|
||||
* @param $sPartId
|
||||
*
|
||||
* @return UIContentBlock
|
||||
@@ -68,8 +71,6 @@ class PDFBulkExport extends HTMLBulkExport
|
||||
|
||||
//page format
|
||||
$oSelectFormat = SelectUIBlockFactory::MakeForSelectWithLabel("page_size", Dict::S('Core:BulkExport:PDFPageSize'));
|
||||
$oSelectFormat->SetIsLabelBefore(false);
|
||||
//$oSelectFormat->AddCSSClass('ibo-input-checkbox');
|
||||
$oFieldSetFormat->AddSubBlock($oSelectFormat);
|
||||
|
||||
$aPossibleFormat = ['A3', 'A4', 'Letter'];
|
||||
@@ -79,10 +80,7 @@ class PDFBulkExport extends HTMLBulkExport
|
||||
}
|
||||
$oFieldSetFormat->AddSubBlock(new Html('</br>'));
|
||||
|
||||
$oSelectOrientation = SelectUIBlockFactory::MakeForSelectWithLabel("page_orientation",
|
||||
Dict::S('Core:BulkExport:PDFPageOrientation'));
|
||||
$oSelectOrientation->SetIsLabelBefore(false);
|
||||
//$oSelectOrientation->AddCSSClass('ibo-input-checkbox');
|
||||
$oSelectOrientation = SelectUIBlockFactory::MakeForSelectWithLabel("page_orientation", Dict::S('Core:BulkExport:PDFPageOrientation'));
|
||||
$oFieldSetFormat->AddSubBlock($oSelectOrientation);
|
||||
|
||||
$aPossibleOrientation = ['P', 'L'];
|
||||
|
||||
@@ -10,6 +10,8 @@ use Combodo\iTop\Application\UI\Base\Component\Input\InputUIBlockFactory;
|
||||
use Combodo\iTop\Application\UI\Base\Component\Panel\PanelUIBlockFactory;
|
||||
use Combodo\iTop\Application\UI\Base\Layout\MultiColumn\Column\ColumnUIBlockFactory;
|
||||
use Combodo\iTop\Application\UI\Base\Layout\MultiColumn\MultiColumnUIBlockFactory;
|
||||
use Combodo\iTop\Application\WebPage\Page;
|
||||
use Combodo\iTop\Application\WebPage\WebPage;
|
||||
|
||||
/**
|
||||
* Bulk export: "spreadsheet" export: a simplified HTML export in which the date/time columns are split in two column: date AND time
|
||||
@@ -34,7 +36,7 @@ class SpreadsheetBulkExport extends TabularBulkExport
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \WebPage $oP
|
||||
* @param WebPage $oP
|
||||
* @param $sPartId
|
||||
*
|
||||
* @return UIContentBlock
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
|
||||
use Combodo\iTop\Application\UI\Base\Component\Input\InputUIBlockFactory;
|
||||
use Combodo\iTop\Application\UI\Base\Layout\UIContentBlockUIBlockFactory;
|
||||
use Combodo\iTop\Application\WebPage\WebPage;
|
||||
|
||||
/**
|
||||
* Bulk export: Tabular export: abstract base class for all "tabular" exports.
|
||||
@@ -22,7 +23,7 @@ abstract class TabularBulkExport extends BulkExport
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \WebPage $oP
|
||||
* @param WebPage $oP
|
||||
* @param $sPartId
|
||||
*
|
||||
* @return UIContentBlock
|
||||
|
||||
@@ -17,6 +17,8 @@
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
*/
|
||||
|
||||
use Combodo\iTop\Application\WebPage\WebPage;
|
||||
|
||||
|
||||
/**
|
||||
* <p>Stores data for {@link AttributeTagSet} fields
|
||||
@@ -296,7 +298,7 @@ abstract class TagSetFieldData extends cmdbAbstractObject
|
||||
/**
|
||||
* Display Tag Usage
|
||||
*
|
||||
* @param \WebPage $oPage
|
||||
* @param WebPage $oPage
|
||||
* @param bool $bEditMode
|
||||
*
|
||||
* @throws \CoreException
|
||||
|
||||
@@ -53,9 +53,10 @@ abstract class Trigger extends cmdbAbstractObject
|
||||
MetaModel::Init_AddAttribute(new AttributeEnumSet("context", array("allowed_values" => null, "possible_values" => new ValueSetEnumPadded($aTags, true), "sql" => "context", "depends_on" => array(), "is_null_allowed" => true, "max_items" => 12)));
|
||||
// "complement" is a computed field, fed by Trigger sub-classes, in general in ComputeValues method, for eg. the TriggerOnObject fed it with target_class info
|
||||
MetaModel::Init_AddAttribute(new AttributeString("complement", array("allowed_values" => null, "sql" => "complement", "default_value" => null, "is_null_allowed" => true, "depends_on" => array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeEnum("subscription_policy", array("allowed_values" => new ValueSetEnum('allow_no_channel,force_at_least_one_channel,force_all_channels'), "sql" => "subscription_policy", "default_value" => 'allow_no_channel', "is_null_allowed" => false, "depends_on" => array())));
|
||||
|
||||
// Display lists
|
||||
MetaModel::Init_SetZListItems('details', array('finalclass', 'description', 'context', 'action_list', 'complement')); // Attributes to be displayed for the complete details
|
||||
MetaModel::Init_SetZListItems('details', array('finalclass', 'description', 'context', 'subscription_policy', 'action_list', 'complement')); // Attributes to be displayed for the complete details
|
||||
MetaModel::Init_SetZListItems('list', array('finalclass', 'complement')); // Attributes to be displayed for a list
|
||||
// Search criteria
|
||||
// MetaModel::Init_SetZListItems('standard_search', array('name')); // Criteria of the std search form
|
||||
@@ -111,19 +112,31 @@ abstract class Trigger extends cmdbAbstractObject
|
||||
return;
|
||||
}
|
||||
|
||||
$aContextArgs['trigger->object()'] = $this;
|
||||
|
||||
// Find the related actions
|
||||
$oLinkedActions = $this->Get('action_list');
|
||||
while ($oLink = $oLinkedActions->Fetch())
|
||||
{
|
||||
/** @var \DBObject $oLink */
|
||||
$iActionId = $oLink->Get('action_id');
|
||||
/** @var \Action $oAction */
|
||||
$oAction = MetaModel::GetObject('Action', $iActionId);
|
||||
if ($oAction->IsActive())
|
||||
{
|
||||
$oKPI = new ExecutionKPI();
|
||||
$oAction->DoExecute($this, $aContextArgs);
|
||||
$oKPI->ComputeStatsForExtension($oAction, 'DoExecute');
|
||||
|
||||
// Order actions as expected
|
||||
$aActionListOrdered = [];
|
||||
while ($oLink = $oLinkedActions->Fetch()) {
|
||||
$aActionListOrdered[(int) $oLink->Get('order')][] = $oLink;
|
||||
}
|
||||
ksort($aActionListOrdered);
|
||||
|
||||
// Execute actions
|
||||
foreach ($aActionListOrdered as $aActionSubList) {
|
||||
foreach ($aActionSubList as $oLink) /** @var \DBObject $oLink */ {
|
||||
/** @var \DBObject $oLink */
|
||||
$iActionId = $oLink->Get('action_id');
|
||||
/** @var \Action $oAction */
|
||||
$oAction = MetaModel::GetObject('Action', $iActionId);
|
||||
if ($oAction->IsActive()) {
|
||||
$oKPI = new ExecutionKPI();
|
||||
$aContextArgs['action->object()'] = $oAction;
|
||||
$oAction->DoExecute($this, $aContextArgs);
|
||||
$oKPI->ComputeStatsForExtension($oAction, 'DoExecute');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -256,6 +269,38 @@ abstract class TriggerOnObject extends Trigger
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Activate trigger based on attribute list given instead of changed attributes
|
||||
*
|
||||
* @param array $aContextArgs
|
||||
* @param array|null $aAttributes if null default to changed attributes
|
||||
*
|
||||
* @throws \ArchivedObjectException
|
||||
* @throws \CoreException
|
||||
* @throws \MissingQueryArgument
|
||||
* @throws \MySQLException
|
||||
* @throws \MySQLHasGoneAwayException
|
||||
* @throws \OQLException
|
||||
* @since 3.1.1 3.2.0 N°6228
|
||||
*/
|
||||
public function DoActivateForSpecificAttributes(array $aContextArgs, ?array $aAttributes)
|
||||
{
|
||||
if (isset($aContextArgs['this->object()']))
|
||||
{
|
||||
/** @var \DBObject $oObject */
|
||||
$oObject = $aContextArgs['this->object()'];
|
||||
if (is_null($aAttributes)) {
|
||||
$aChanges = $oObject->ListPreviousValuesForUpdatedAttributes();
|
||||
} else {
|
||||
$aChanges = array_fill_keys($aAttributes, true);
|
||||
}
|
||||
if (false === $this->IsTargetObject($oObject->GetKey(), $aChanges)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
parent::DoActivate($aContextArgs);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $iObjectId
|
||||
* @param array $aChanges
|
||||
@@ -406,7 +451,7 @@ class TriggerOnStateEnter extends TriggerOnStateChange
|
||||
MetaModel::Init_InheritAttributes();
|
||||
|
||||
// Display lists
|
||||
MetaModel::Init_SetZListItems('details', array('description', 'context', 'target_class', 'filter', 'state', 'action_list')); // Attributes to be displayed for the complete details
|
||||
MetaModel::Init_SetZListItems('details', array('description', 'context', 'target_class', 'filter', 'state', 'subscription_policy', 'action_list')); // Attributes to be displayed for the complete details
|
||||
MetaModel::Init_SetZListItems('list', array('target_class', 'state')); // Attributes to be displayed for a list
|
||||
// Search criteria
|
||||
MetaModel::Init_SetZListItems('standard_search', array('description', 'target_class', 'state')); // Criteria of the std search form
|
||||
@@ -439,7 +484,7 @@ class TriggerOnStateLeave extends TriggerOnStateChange
|
||||
MetaModel::Init_InheritAttributes();
|
||||
|
||||
// Display lists
|
||||
MetaModel::Init_SetZListItems('details', array('description', 'context', 'target_class', 'filter', 'state', 'action_list')); // Attributes to be displayed for the complete details
|
||||
MetaModel::Init_SetZListItems('details', array('description', 'context', 'target_class', 'filter', 'state', 'subscription_policy', 'action_list')); // Attributes to be displayed for the complete details
|
||||
MetaModel::Init_SetZListItems('list', array('target_class', 'state')); // Attributes to be displayed for a list
|
||||
// Search criteria
|
||||
MetaModel::Init_SetZListItems('standard_search', array('description', 'target_class', 'state')); // Criteria of the std search form
|
||||
@@ -472,7 +517,7 @@ class TriggerOnObjectCreate extends TriggerOnObject
|
||||
MetaModel::Init_InheritAttributes();
|
||||
|
||||
// Display lists
|
||||
MetaModel::Init_SetZListItems('details', array('description', 'context', 'target_class', 'filter', 'action_list')); // Attributes to be displayed for the complete details
|
||||
MetaModel::Init_SetZListItems('details', array('description', 'context', 'target_class', 'filter', 'subscription_policy', 'action_list')); // Attributes to be displayed for the complete details
|
||||
MetaModel::Init_SetZListItems('list', array('finalclass', 'target_class')); // Attributes to be displayed for a list
|
||||
// Search criteria
|
||||
MetaModel::Init_SetZListItems('standard_search', array('description', 'target_class')); // Criteria of the std search form
|
||||
@@ -505,7 +550,7 @@ class TriggerOnObjectDelete extends TriggerOnObject
|
||||
MetaModel::Init_InheritAttributes();
|
||||
|
||||
// Display lists
|
||||
MetaModel::Init_SetZListItems('details', array('description', 'context', 'target_class', 'filter', 'action_list')); // Attributes to be displayed for the complete details
|
||||
MetaModel::Init_SetZListItems('details', array('description', 'context', 'target_class', 'filter', 'subscription_policy', 'action_list')); // Attributes to be displayed for the complete details
|
||||
MetaModel::Init_SetZListItems('list', array('finalclass', 'target_class')); // Attributes to be displayed for a list
|
||||
// Search criteria
|
||||
MetaModel::Init_SetZListItems('standard_search', array('description', 'target_class')); // Criteria of the std search form
|
||||
@@ -540,7 +585,7 @@ class TriggerOnObjectUpdate extends TriggerOnObject
|
||||
MetaModel::Init_AddAttribute(new AttributeClassAttCodeSet('target_attcodes', array("allowed_values" => null, "class_field" => "target_class", "sql" => "target_attcodes", "default_value" => null, "is_null_allowed" => true, "max_items" => 20, "min_items" => 0, "attribute_definition_exclusion_list" => "AttributeDashboard,AttributeExternalField,AttributeFinalClass,AttributeFriendlyName,AttributeObsolescenceDate,AttributeObsolescenceFlag,AttributeSubItem", "attribute_definition_list" => null, "depends_on" => array('target_class'))));
|
||||
|
||||
// Display lists
|
||||
MetaModel::Init_SetZListItems('details', array('description', 'context', 'target_class', 'filter', 'target_attcodes', 'action_list')); // Attributes to be displayed for the complete details
|
||||
MetaModel::Init_SetZListItems('details', array('description', 'context', 'target_class', 'filter', 'target_attcodes', 'subscription_policy', 'action_list')); // Attributes to be displayed for the complete details
|
||||
MetaModel::Init_SetZListItems('list', array('finalclass', 'target_class')); // Attributes to be displayed for a list
|
||||
// Search criteria
|
||||
MetaModel::Init_SetZListItems('standard_search', array('description', 'target_class')); // Criteria of the std search form
|
||||
@@ -636,7 +681,7 @@ class TriggerOnObjectMention extends TriggerOnObject
|
||||
MetaModel::Init_AddAttribute(new AttributeOQL("mentioned_filter", array("allowed_values" => null, "sql" => "mentioned_filter", "default_value" => null, "is_null_allowed" => true, "depends_on" => array())));
|
||||
|
||||
// Display lists
|
||||
MetaModel::Init_SetZListItems('details', array('description', 'context', 'target_class', 'filter', 'mentioned_filter', 'action_list')); // Attributes to be displayed for the complete details
|
||||
MetaModel::Init_SetZListItems('details', array('description', 'context', 'target_class', 'filter', 'mentioned_filter', 'subscription_policy', 'action_list')); // Attributes to be displayed for the complete details
|
||||
MetaModel::Init_SetZListItems('list', array('finalclass', 'target_class')); // Attributes to be displayed for a list
|
||||
// Search criteria
|
||||
MetaModel::Init_SetZListItems('standard_search', array('description', 'target_class')); // Criteria of the std search form
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
<?php
|
||||
|
||||
use Combodo\iTop\Application\Helper\Session;
|
||||
use Combodo\iTop\Application\WebPage\WebPage;
|
||||
|
||||
define('UR_ALLOWED_NO', 0);
|
||||
define('UR_ALLOWED_YES', 1);
|
||||
@@ -161,7 +162,7 @@ abstract class UserRightsAddOnAPI
|
||||
$oSearchSharers->AllowAllData();
|
||||
$oSearchSharers->AddCondition_ReferencedBy($oShareSearch, 'sharing_org_id');
|
||||
$aSharers = array();
|
||||
foreach($oSearchSharers->ToDataArray(array('id')) as $aRow)
|
||||
foreach($oSearchSharers->SelectAttributeToArray('id') as $aRow)
|
||||
{
|
||||
$aSharers[] = $aRow['id'];
|
||||
}
|
||||
@@ -179,23 +180,17 @@ abstract class UserRightsAddOnAPI
|
||||
$sShareClass = $aShareProperties['share_class'];
|
||||
$sShareAttCode = $aShareProperties['attcode'];
|
||||
|
||||
$oSearchShares = new DBObjectSearch($sShareClass);
|
||||
$oSearchShares->AllowAllData();
|
||||
$oSearchShares = new DBSharedSearch($sShareClass);
|
||||
$oSearchShares->AllowAllData();
|
||||
|
||||
$sHierarchicalKeyCode = MetaModel::IsHierarchicalClass('Organization');
|
||||
$oOrgField = new FieldExpression('org_id', $sShareClass);
|
||||
$oSearchShares->AddConditionExpression(new BinaryExpression($oOrgField, 'IN', $oListExpr));
|
||||
$aShared = array();
|
||||
foreach($oSearchShares->ToDataArray(array($sShareAttCode)) as $aRow)
|
||||
{
|
||||
$aShared[] = $aRow[$sShareAttCode];
|
||||
}
|
||||
if (count($aShared) > 0)
|
||||
{
|
||||
$oObjId = new FieldExpression('id', $sClass);
|
||||
$oSharedIdList = ListExpression::FromScalars($aShared);
|
||||
$oFilter->MergeConditionExpression(new BinaryExpression($oObjId, 'IN', $oSharedIdList));
|
||||
}
|
||||
|
||||
$oNested = SharedQueryExpression::FromOQLObjectQuery($oSearchShares, [$sShareClass =>[$sShareAttCode]]);
|
||||
$oObjId = new FieldExpression('id', $sClass);
|
||||
$oFilter->MergeConditionExpression(new BinaryExpression($oObjId, 'IN', $oNested));
|
||||
|
||||
}
|
||||
} // if HasSharing
|
||||
|
||||
@@ -248,7 +243,7 @@ abstract class User extends cmdbAbstractObject
|
||||
"depends_on" => array(),
|
||||
)));
|
||||
|
||||
MetaModel::Init_AddAttribute(new AttributeLinkedSetIndirect("profile_list",array("linked_class" => "URP_UserProfile", "ext_key_to_me" => "userid", "ext_key_to_remote" => "profileid", "allowed_values" => null, "count_min" => 1, "count_max" => 0, "depends_on" => array(), "display_style" => 'property', "with_php_constraint" => true)));
|
||||
MetaModel::Init_AddAttribute(new AttributeLinkedSetIndirect("profile_list",array("linked_class" => "URP_UserProfile", "ext_key_to_me" => "userid", "ext_key_to_remote" => "profileid", "allowed_values" => null, "count_min" => 1, "count_max" => 0, "depends_on" => array(), "display_style" => 'property', "with_php_constraint" => true, "with_php_computation" => true)));
|
||||
MetaModel::Init_AddAttribute(new AttributeLinkedSetIndirect("allowed_org_list", array("linked_class" => "URP_UserOrg", "ext_key_to_me" => "userid", "ext_key_to_remote" => "allowed_org_id", "allowed_values" => null, "count_min" => 1, "count_max" => 0, "depends_on" => array(), 'with_php_constraint' => true)));
|
||||
MetaModel::Init_AddAttribute(new AttributeCaseLog("log", array("sql" => 'log', "is_null_allowed" => true, "default_value" => '', "allowed_values" => null, "depends_on" => array(), "always_load_in_tables" => false)));
|
||||
|
||||
@@ -867,6 +862,8 @@ class UserRights
|
||||
*/
|
||||
public static function Login($sLogin, $sAuthentication = 'any')
|
||||
{
|
||||
self::ResetCurrentUserData();
|
||||
|
||||
$oUser = self::FindUser($sLogin, $sAuthentication);
|
||||
if (is_null($oUser))
|
||||
{
|
||||
@@ -1121,9 +1118,7 @@ class UserRights
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the current user login or an empty string if nobody connected.
|
||||
*
|
||||
* @return string
|
||||
* @return string connected {@see User} login field value, otherwise empty string
|
||||
*/
|
||||
public static function GetUser()
|
||||
{
|
||||
@@ -1571,9 +1566,9 @@ class UserRights
|
||||
|
||||
/**
|
||||
* @param string $sClass
|
||||
* @param int $iActionCode
|
||||
* @param \DBObjectSet $oInstanceSet
|
||||
* @param \User $oUser
|
||||
* @param int $iActionCode see UR_ACTION_* constants
|
||||
* @param DBObjectSet $oInstanceSet
|
||||
* @param User $oUser
|
||||
*
|
||||
* @return int (UR_ALLOWED_YES|UR_ALLOWED_NO|UR_ALLOWED_DEPENDS)
|
||||
* @throws \CoreException
|
||||
|
||||
@@ -8,6 +8,8 @@ use Combodo\iTop\Application\UI\Base\Component\Input\InputUIBlockFactory;
|
||||
use Combodo\iTop\Application\UI\Base\Component\Panel\PanelUIBlockFactory;
|
||||
use Combodo\iTop\Application\UI\Base\Layout\MultiColumn\Column\ColumnUIBlockFactory;
|
||||
use Combodo\iTop\Application\UI\Base\Layout\MultiColumn\MultiColumnUIBlockFactory;
|
||||
use Combodo\iTop\Application\WebPage\Page;
|
||||
use Combodo\iTop\Application\WebPage\WebPage;
|
||||
|
||||
/**
|
||||
* Bulk export: XML export
|
||||
@@ -30,7 +32,7 @@ class XMLBulkExport extends BulkExport
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \WebPage $oP
|
||||
* @param WebPage $oP
|
||||
* @param $sPartId
|
||||
*
|
||||
* @return UIContentBlock
|
||||
|
||||
@@ -49,3 +49,63 @@
|
||||
.ibo-navigation-menu.ibo-is-active .ibo-navigation-menu--drawer{
|
||||
transform: translate3d(0,0,0);
|
||||
}
|
||||
|
||||
// Toggler legacy CSS that has somehow been added to iTop 3.0 and that is now used by some extensions
|
||||
// Round Toggle
|
||||
/* The switch - the box around the slider */
|
||||
.switch {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
width: 36px;
|
||||
height: 20px;
|
||||
vertical-align: baseline;
|
||||
}
|
||||
|
||||
/* Hide default HTML checkbox */
|
||||
.switch input {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* The slider */
|
||||
.slider {
|
||||
position: absolute;
|
||||
cursor: pointer;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background-color: $ibo-color-secondary-600;
|
||||
transition: .4s;
|
||||
}
|
||||
|
||||
.slider:before {
|
||||
position: absolute;
|
||||
content: "";
|
||||
height: 15px;
|
||||
width: 15px;
|
||||
left: 3px;
|
||||
bottom: 3px;
|
||||
background-color: $ibo-color-secondary-300;
|
||||
transition: .4s;
|
||||
}
|
||||
|
||||
input:checked + .slider {
|
||||
background-color: $ibo-color-primary-600;
|
||||
}
|
||||
|
||||
input:focus + .slider {
|
||||
box-shadow: 0 0 1px $ibo-color-primary-600;
|
||||
}
|
||||
|
||||
input:checked + .slider:before {
|
||||
transform: translateX(14.5px);
|
||||
}
|
||||
|
||||
/* Rounded sliders */
|
||||
.slider.round {
|
||||
border-radius: 20px;
|
||||
}
|
||||
|
||||
.slider.round:before {
|
||||
border-radius: 7px;
|
||||
}
|
||||
|
||||
@@ -11,10 +11,6 @@ $ibo-scrollbar--scrollbar-thumb-background-color: $ibo-color-grey-300 !default;
|
||||
$ibo-scrollbar--scrollbar-thumb-border: none !default;
|
||||
$ibo-scrollbar--scrollbar-thumb-border-radius: $ibo-border-radius-500 !default;
|
||||
|
||||
$ibo-hyperlink-color: $ibo-color-primary-700 !default;
|
||||
$ibo-hyperlink-color--on-hover: $ibo-color-primary-800 !default;
|
||||
$ibo-hyperlink-color--on-active: $ibo-color-primary-900 !default;
|
||||
|
||||
$ibo-svg-illustration--fill: $ibo-color-primary-500 !default;
|
||||
|
||||
$ibo-content-block--background-color: $ibo-color-white-100 !default;
|
||||
@@ -29,10 +25,6 @@ $ibo-content-block--border: 1px solid $ibo-color-grey-400 !default;
|
||||
--ibo-scrollbar--scrollbar-thumb-background-color: #{$ibo-scrollbar--scrollbar-thumb-background-color};
|
||||
--ibo-scrollbar--scrollbar-thumb-border: #{$ibo-scrollbar--scrollbar-thumb-border};
|
||||
--ibo-scrollbar--scrollbar-thumb-border-radius: #{$ibo-scrollbar--scrollbar-thumb-border-radius};
|
||||
|
||||
--ibo-hyperlink-color: #{$ibo-hyperlink-color};
|
||||
--ibo-hyperlink-color--on-hover: #{$ibo-hyperlink-color--on-hover};
|
||||
--ibo-hyperlink-color--on-active: #{$ibo-hyperlink-color--on-active};
|
||||
}
|
||||
|
||||
/* Box sizing reset */
|
||||
@@ -73,17 +65,19 @@ html{
|
||||
/* Hyperlinks reset, ensure that they are of the right color and without decoration everywhere (of course this can be overloaded in some components) */
|
||||
a{
|
||||
color: var(--ibo-hyperlink-color);
|
||||
text-decoration: none;
|
||||
text-decoration: var(--ibo-hyperlink-text-decoration);
|
||||
|
||||
&:hover,
|
||||
&:active,
|
||||
&:visited{
|
||||
text-decoration: none;
|
||||
text-decoration: var(--ibo-hyperlink-text-decoration);
|
||||
}
|
||||
&:hover{
|
||||
color: var(--ibo-hyperlink-color--on-hover);
|
||||
text-decoration: var(--ibo-hyperlink-text-decoration--on-hover);
|
||||
}
|
||||
&:active{
|
||||
color: var(--ibo-hyperlink-color--on-active);
|
||||
text-decoration: var(--ibo-hyperlink-text-decoration--on-active);
|
||||
}
|
||||
}
|
||||
@@ -41,7 +41,7 @@ $ibo-alert-colors: (
|
||||
$bg-color: nth($aColorValues, 1);
|
||||
$highlight-color: nth($aColorValues, 2);
|
||||
$text-color: nth($aColorValues, 3);
|
||||
.ibo-alert.ibo-is-#{$sColor} {
|
||||
%ibo-alert-#{$sColor}, .ibo-alert.ibo-is-#{$sColor} {
|
||||
background-color: $bg-color;
|
||||
color: $text-color;
|
||||
a {
|
||||
|
||||
@@ -32,4 +32,5 @@
|
||||
@import "search-form";
|
||||
@import "field-badge";
|
||||
@import "file-select";
|
||||
@import "medallion-icon";
|
||||
@import "medallion-icon";
|
||||
@import "toast";
|
||||
@@ -80,16 +80,29 @@ $ibo-field--enable-bulk--checkbox--margin-left: $ibo-spacing-300 !default;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*N°6543 - We need the rule to keep text inside the column when width is defined*/
|
||||
&[data-attribute-type="AttributeHtml"],
|
||||
&[data-attribute-type="AttributeText"] {
|
||||
&[data-attribute-flag-read-only="true"] {
|
||||
display: grid;
|
||||
|
||||
> .ibo-field--value {
|
||||
max-width: 100%;
|
||||
overflow: auto;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Large field = Label on top, value below */
|
||||
.ibo-field-large {
|
||||
display: block;
|
||||
/* Large field = Label on top, value below */
|
||||
.ibo-field-large {
|
||||
display: block;
|
||||
|
||||
.ibo-field--label {
|
||||
position: relative; /* Necessary for fullscreen toggler */
|
||||
display: flex;
|
||||
align-items: center;
|
||||
.ibo-field--label {
|
||||
position: relative; /* Necessary for fullscreen toggler */
|
||||
display: flex;
|
||||
align-items: center;
|
||||
max-width: initial;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
@@ -36,31 +36,30 @@ $ibo-popover-menu--item--no-message--image--svg--padding : 15px !default;
|
||||
#ibo-navigation-menu--notifications-menu {
|
||||
flex-flow: column;
|
||||
min-width: $ibo-navigation-menu--notifications-menu--min-width;
|
||||
.ibo-navigation-menu--notifications--messages-section{
|
||||
.ibo-navigation-menu--notifications--messages-section {
|
||||
overflow: auto;
|
||||
}
|
||||
}
|
||||
.ibo-navigation-menu--notifications--show-all-messages, .ibo-navigation-menu--notifications-dismiss-all, .ibo-navigation-menu--notifications-show-all-multiple{
|
||||
.ibo-navigation-menu--notifications--show-all-messages, .ibo-navigation-menu--notifications-dismiss-all, .ibo-navigation-menu--notifications-show-all-multiple {
|
||||
overflow-x: inherit;
|
||||
text-align: center;
|
||||
min-height: 45px;
|
||||
}
|
||||
|
||||
.ibo-navigation-menu--notifications--item--image{
|
||||
.ibo-navigation-menu--notifications--item--image {
|
||||
max-width: $ibo-navigation-menu--notifications--item--image--max-width;
|
||||
max-height: $ibo-navigation-menu--notifications--item--image--max-height;
|
||||
margin: $ibo-navigation-menu--notifications--item--image--margin-y $ibo-navigation-menu--notifications--item--image--margin-x;
|
||||
border-radius: $ibo-navigation-menu--notifications--item--image--border-radius;
|
||||
}
|
||||
|
||||
img.ibo-navigation-menu--notifications--item--image[src=""]{
|
||||
.ibo-navigation-menu--notifications--item--image[src=""] {
|
||||
display: none;
|
||||
}
|
||||
img.ibo-navigation-menu--notifications--item--image:not([src=""]) ~ i.ibo-navigation-menu--notifications--item--image
|
||||
{
|
||||
.ibo-navigation-menu--notifications--item--image:not([src=""]) ~ .ibo-navigation-menu--notifications--item--image {
|
||||
display: none;
|
||||
}
|
||||
.ibo-navigation-menu--notifications--item--bottom-text{
|
||||
.ibo-navigation-menu--notifications--item--bottom-text {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
@@ -68,18 +67,23 @@ img.ibo-navigation-menu--notifications--item--image:not([src=""]) ~ i.ibo-naviga
|
||||
align-self: center;
|
||||
margin-left: $ibo-navigation-menu--notifications--item--bottom-text--margin-left;
|
||||
}
|
||||
.ibo-navigation-menu--notifications--item--content{
|
||||
.ibo-navigation-menu--notifications--item--content {
|
||||
padding: $ibo-navigation-menu--notifications--item--content--padding-y $ibo-navigation-menu--notifications--item--content--padding-x;
|
||||
img{
|
||||
|
||||
img {
|
||||
max-height: $ibo-navigation-menu--notifications--item--content--img--max-height;
|
||||
padding: $ibo-navigation-menu--notifications--item--content--img--padding;
|
||||
}
|
||||
}
|
||||
.ibo-navigation-menu--notifications-item{
|
||||
.ibo-navigation-menu--notifications-item {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
|
||||
.ibo-navigation-menu--notifications--item--content a {
|
||||
@extend %ibo-hyperlink-forced-colors;
|
||||
}
|
||||
}
|
||||
.ibo-navigation-menu--notifications--item--new-message-indicator{
|
||||
.ibo-navigation-menu--notifications--item--new-message-indicator {
|
||||
width: $ibo-navigation-menu--notifications--item--new-message-indicator--width;
|
||||
height: $ibo-navigation-menu--notifications--item--new-message-indicator--height;
|
||||
background-color: $ibo-navigation-menu--notifications--item--new-message-indicator--background-color;
|
||||
@@ -87,22 +91,22 @@ img.ibo-navigation-menu--notifications--item--image:not([src=""]) ~ i.ibo-naviga
|
||||
margin-top: $ibo-navigation-menu--notifications--item--new-message-indicator--margin-top;
|
||||
}
|
||||
|
||||
.ibo-navigation-menu--notifications-show-all-multiple ~ .ibo-popover-menu{
|
||||
.ibo-navigation-menu--notifications--item--new-message-indicator{
|
||||
.ibo-navigation-menu--notifications-show-all-multiple ~ .ibo-popover-menu {
|
||||
.ibo-navigation-menu--notifications--item--new-message-indicator {
|
||||
display: inline-block;
|
||||
margin-right: $ibo-navigation-menu--notifications-show-all-multiple--ibo-popover-menu--indicator--margin-right;
|
||||
}
|
||||
.ibo-navigation-menu--notifications-show-all-multiple--counter{
|
||||
.ibo-navigation-menu--notifications-show-all-multiple--counter {
|
||||
@extend %ibo-font-weight-600;
|
||||
}
|
||||
}
|
||||
.ibo-navigation-menu--notifications-dismiss-all--icon{
|
||||
.ibo-navigation-menu--notifications-dismiss-all--icon {
|
||||
margin: $ibo-navigation-menu--notifications-dismiss-all--icon--margin;
|
||||
}
|
||||
.ibo-popover-menu--item--no-message{
|
||||
.ibo-popover-menu--item--no-message {
|
||||
text-align: center;
|
||||
}
|
||||
.ibo-popover-menu--item--no-message--image>svg{
|
||||
.ibo-popover-menu--item--no-message--image > svg {
|
||||
display: flex;
|
||||
width: $ibo-popover-menu--item--no-message--image--svg--width;
|
||||
height: $ibo-popover-menu--item--no-message--image--svg--height;
|
||||
|
||||
@@ -85,6 +85,9 @@ $ibo-panel--collapsible-toggler--margin-right: $ibo-spacing-300 !default;
|
||||
$ibo-panel--collapsible-toggler--font-size: $ibo-font-size-250 !default;
|
||||
$ibo-panel--collapsible-toggler--color: $ibo-color-grey-700 !default;
|
||||
|
||||
$ibo-panel--is-selectable--body--after--z-index: $ibo-panel--header--z-index + 1 !default;
|
||||
$ibo-panel--is-selectable--body--after--font-size: $ibo-font-size-700 !default;
|
||||
|
||||
/* Rules */
|
||||
.ibo-panel {
|
||||
--ibo-main-color: #{map-get($ibo-panel-colors, 'neutral')}; /* --ibo-main-color is to allow overload from custom dynamic value from the DM. The overload will be done through an additional CSS class of a particular DM class or DM attribute */
|
||||
@@ -128,6 +131,30 @@ $ibo-panel--collapsible-toggler--color: $ibo-color-grey-700 !default;
|
||||
}
|
||||
}
|
||||
}
|
||||
&.ibo-is-selectable .ibo-panel--body::after {
|
||||
@include ibo-selectable;
|
||||
position: absolute;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
z-index: $ibo-panel--is-selectable--body--after--z-index;
|
||||
font-size: $ibo-panel--is-selectable--body--after--font-size;
|
||||
}
|
||||
&.ibo-is-selectable:hover .ibo-panel--body::after {
|
||||
@include ibo-selectable-hover;
|
||||
display: flex;
|
||||
}
|
||||
&.ibo-is-selected .ibo-panel--body::after {
|
||||
@include ibo-selected;
|
||||
display: flex;
|
||||
}
|
||||
&.ibo-is-selected:hover .ibo-panel--body::after {
|
||||
@include ibo-selected-hover;
|
||||
display: flex;
|
||||
}
|
||||
}
|
||||
|
||||
.ibo-panel--header {
|
||||
|
||||
62
css/backoffice/components/_toast.scss
Normal file
62
css/backoffice/components/_toast.scss
Normal file
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* @copyright Copyright (C) 2010-2024 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
/* SCSS variables */
|
||||
$ibo-toast--padding-y: $ibo-spacing-400 !default;
|
||||
$ibo-toast--padding-right: $ibo-spacing-300 !default;
|
||||
$ibo-toast--padding-left: $ibo-spacing-500 !default;
|
||||
$ibo-toast--border-radius: $ibo-border-radius-300 !default;
|
||||
$ibo-toast--box-shadow: $ibo-elevation-200 !default;
|
||||
$ibo-toast--max-width: calc(50% - 20px) !default;
|
||||
|
||||
@keyframes decreaseHighlight {
|
||||
0% {
|
||||
height: 100%;
|
||||
}
|
||||
8%{
|
||||
border-radius: 0 0 0 3px;
|
||||
}
|
||||
100% {
|
||||
height: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.ibo-toast {
|
||||
display: inline-flex;
|
||||
position: fixed;
|
||||
align-items: center;
|
||||
|
||||
max-width: $ibo-toast--max-width ;
|
||||
padding: $ibo-toast--padding-y $ibo-toast--padding-right $ibo-toast--padding-y $ibo-toast--padding-left;
|
||||
border-radius: $ibo-toast--border-radius;
|
||||
|
||||
box-shadow: $ibo-toast--box-shadow;
|
||||
transition: all 0.4s cubic-bezier(0.215, 0.61, 0.355, 1);
|
||||
z-index: 2147483647;
|
||||
&::before {
|
||||
@include ibo-vertical-highlight;
|
||||
top: initial;
|
||||
bottom: 0;
|
||||
border-radius: $ibo-toast--border-radius 0 0 $ibo-toast--border-radius;
|
||||
}
|
||||
&.ibo-is-auto-closeable::before{
|
||||
animation: decreaseHighlight 5s linear forwards;
|
||||
}
|
||||
&:hover::before {
|
||||
animation: none; /* Pause animation on hover */
|
||||
}
|
||||
&.ibo-is-error{
|
||||
@extend %ibo-alert-danger;
|
||||
}
|
||||
&.ibo-is-warning{
|
||||
@extend %ibo-alert-warning;
|
||||
}
|
||||
&.ibo-is-success{
|
||||
@extend %ibo-alert-success;
|
||||
}
|
||||
&.ibo-is-information{
|
||||
@extend %ibo-alert-information;
|
||||
}
|
||||
}
|
||||
@@ -123,6 +123,13 @@ $ibo-fieldsorter--selected--background-color: $ibo-color-blue-200 !default;
|
||||
.ibo-datatable--row-actions-toolbar{
|
||||
justify-content: end;
|
||||
}
|
||||
/* N°6543 - We need the rule to keep text inside the column when width is defined */
|
||||
> [data-attribute-type="AttributeHtml"],
|
||||
> [data-attribute-type="AttributeText"] {
|
||||
max-width: 100%;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -22,6 +22,9 @@ $ibo-datatableconfig--settings-panel--option--margin-right: $ibo-spacing-200 !de
|
||||
}
|
||||
.ibo-datatableconfig--attributes-panel--per-page--input{
|
||||
margin: $ibo-datatableconfig--attributes-panel--per-page--input--margin-y $ibo-datatableconfig--attributes-panel--per-page--input--margin-x;
|
||||
max-width: 4em;
|
||||
@extend .ibo-input;
|
||||
display: initial;
|
||||
}
|
||||
|
||||
.ibo-datatableconfig--settings-panel .ibo-panel--body{
|
||||
|
||||
@@ -16,3 +16,4 @@
|
||||
@import "input-one-way-password";
|
||||
@import "input-set";
|
||||
@import "input-text";
|
||||
@import "input-toggler";
|
||||
|
||||
@@ -224,7 +224,11 @@ $ibo-input-select--autocomplete-item-image--border: 1px solid $ibo-color-grey-60
|
||||
margin-right: $ibo-input-select--autocomplete-item-image--margin-right;
|
||||
background-color: $ibo-input-select--autocomplete-item-image--background-color;
|
||||
border: $ibo-input-select--autocomplete-item-image--border;
|
||||
|
||||
&.ibo-is-not-medallion{
|
||||
border: unset;
|
||||
border-radius: 0;
|
||||
background-color: unset;
|
||||
}
|
||||
@extend %ibo-fully-centered-content;
|
||||
}
|
||||
|
||||
|
||||
72
css/backoffice/components/input/_input-toggler.scss
Normal file
72
css/backoffice/components/input/_input-toggler.scss
Normal file
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
* @copyright Copyright (C) 2010-2024 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
$ibo-toggler--wrapper--width: 36px !default;
|
||||
$ibo-toggler--wrapper--height: 20px !default;
|
||||
|
||||
$ibo-toggler--slider--border-radius: $ibo-border-radius-900 !default;
|
||||
$ibo-toggler--slider--background-color: $ibo-color-secondary-600 !default;
|
||||
|
||||
$ibo-toggler--slider--before--height: 15px !default;
|
||||
$ibo-toggler--slider--before--width: 15px !default;
|
||||
$ibo-toggler--slider--before--border-radius: $ibo-border-radius-full !default;
|
||||
$ibo-toggler--slider--before--background-color: $ibo-color-grey-100 !default;
|
||||
|
||||
$ibo-toggler--slider--checked--background-color: $ibo-color-primary-600 !default;
|
||||
$ibo-toggler--slider--focus--box-shadow: 0 0 1px $ibo-color-primary-600 !default;
|
||||
|
||||
$ibo-toggler--label--margin-left: 4px !default;
|
||||
|
||||
|
||||
.ibo-toggler--wrapper {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
width: $ibo-toggler--wrapper--width;
|
||||
height: $ibo-toggler--wrapper--height;
|
||||
vertical-align: baseline;
|
||||
.ibo-toggler {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
.ibo-toggler--slider{
|
||||
position: absolute;
|
||||
cursor: pointer;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
border-radius: $ibo-toggler--slider--border-radius;
|
||||
background-color: $ibo-toggler--slider--background-color;
|
||||
transition: .4s;
|
||||
}
|
||||
|
||||
.ibo-toggler--slider:before {
|
||||
content: "";
|
||||
position: absolute;
|
||||
left: 3px;
|
||||
bottom: 3px;
|
||||
height: $ibo-toggler--slider--before--height;
|
||||
width: $ibo-toggler--slider--before--width;
|
||||
border-radius: $ibo-toggler--slider--before--border-radius;
|
||||
background-color: $ibo-toggler--slider--before--background-color;
|
||||
transition: .4s;
|
||||
}
|
||||
|
||||
.ibo-toggler--wrapper input:checked + .ibo-toggler--slider {
|
||||
background-color: $ibo-toggler--slider--checked--background-color;
|
||||
}
|
||||
|
||||
input:focus + .ibo-toggler--slider {
|
||||
box-shadow: $ibo-toggler--slider--focus--box-shadow;
|
||||
}
|
||||
|
||||
input:checked + .ibo-toggler--slider:before {
|
||||
transform: translateX(14.5px);
|
||||
}
|
||||
|
||||
label ~ .ibo-toggler--wrapper {
|
||||
margin-left: $ibo-toggler--label--margin-left;
|
||||
}
|
||||
@@ -62,63 +62,4 @@ $ibo-top-bar--toolbar-dashboard-title--max-width: 350px !default;
|
||||
@extend %ibo-full-height-content;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
// Round Toggle
|
||||
/* The switch - the box around the slider */
|
||||
.switch {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
width: 36px;
|
||||
height: 20px;
|
||||
vertical-align: baseline;
|
||||
}
|
||||
|
||||
/* Hide default HTML checkbox */
|
||||
.switch input {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* The slider */
|
||||
.slider {
|
||||
position: absolute;
|
||||
cursor: pointer;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background-color: $ibo-color-secondary-600;
|
||||
transition: .4s;
|
||||
}
|
||||
|
||||
.slider:before {
|
||||
position: absolute;
|
||||
content: "";
|
||||
height: 15px;
|
||||
width: 15px;
|
||||
left: 3px;
|
||||
bottom: 3px;
|
||||
background-color: $ibo-color-secondary-300;
|
||||
transition: .4s;
|
||||
}
|
||||
|
||||
input:checked + .slider {
|
||||
background-color: $ibo-color-primary-600;
|
||||
}
|
||||
|
||||
input:focus + .slider {
|
||||
box-shadow: 0 0 1px $ibo-color-primary-600;
|
||||
}
|
||||
|
||||
input:checked + .slider:before {
|
||||
transform: translateX(14.5px);
|
||||
}
|
||||
|
||||
/* Rounded sliders */
|
||||
.slider.round {
|
||||
border-radius: 20px;
|
||||
}
|
||||
|
||||
.slider.round:before {
|
||||
border-radius: 7px;
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user