mirror of
https://github.com/Combodo/iTop.git
synced 2026-02-19 02:14:10 +01:00
Compare commits
654 Commits
3.1.0-2
...
feature/70
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9f70d0e4b3 | ||
|
|
0923f199a0 | ||
|
|
e831a21354 | ||
|
|
4d5444b585 | ||
|
|
368b440f15 | ||
|
|
ac32cb0886 | ||
|
|
138da3a107 | ||
|
|
098461d4da | ||
|
|
df9d71e2f5 | ||
|
|
3005bc1234 | ||
|
|
3f3b0cbe55 | ||
|
|
cff50f8732 | ||
|
|
a8cd9566ac | ||
|
|
dab03e5b5d | ||
|
|
5935800b21 | ||
|
|
87582a021b | ||
|
|
200cdefa1a | ||
|
|
8ef04bedf2 | ||
|
|
9eeb4b8751 | ||
|
|
ae3d0f9444 | ||
|
|
77a81c6d6a | ||
|
|
816ab41e27 | ||
|
|
7963690a10 | ||
|
|
9ddb82073c | ||
|
|
1fa4fe6d35 | ||
|
|
2ed0666c3b | ||
|
|
51fdd04881 | ||
|
|
9b5988133b | ||
|
|
a61b117f71 | ||
|
|
9830178a47 | ||
|
|
83ac219ec9 | ||
|
|
c140ebcb6b | ||
|
|
d721632f2b | ||
|
|
fddf9e36c7 | ||
|
|
b181914d25 | ||
|
|
7a0a4e377b | ||
|
|
7fffbb60e9 | ||
|
|
dfd5a5bebc | ||
|
|
e55f1f1d66 | ||
|
|
490f8600e5 | ||
|
|
03b095f246 | ||
|
|
a50f579793 | ||
|
|
9dde675aef | ||
|
|
021159a2c2 | ||
|
|
b3be796277 | ||
|
|
b3f2232ba4 | ||
|
|
c7281a5cfc | ||
|
|
ef083d5e8f | ||
|
|
54d98ba4f7 | ||
|
|
5213e205af | ||
|
|
153027434d | ||
|
|
cc367fa19e | ||
|
|
73c989ee67 | ||
|
|
0461cd7d51 | ||
|
|
00f241e4cf | ||
|
|
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 | ||
|
|
75fde4c9a3 | ||
|
|
2bcc4d9989 | ||
|
|
d6970f6486 | ||
|
|
5edf092a24 | ||
|
|
9af08fa693 | ||
|
|
3b7cad5cbd | ||
|
|
05db99aa69 | ||
|
|
2681abbeed | ||
|
|
0cf480d824 | ||
|
|
94c604a6af | ||
|
|
031c90e797 | ||
|
|
34f0053db7 | ||
|
|
f84e2060be | ||
|
|
6995a3c641 | ||
|
|
b35151f421 | ||
|
|
afbdff928d | ||
|
|
e007e09155 | ||
|
|
4ee70cb95a | ||
|
|
9865bf0779 | ||
|
|
68b7e9ee65 | ||
|
|
12f3e5ed4c | ||
|
|
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 | ||
|
|
f5a0b4bf8e | ||
|
|
a2b9583379 | ||
|
|
77409eed99 | ||
|
|
770bf4c42a | ||
|
|
eb7c971091 | ||
|
|
4d5a704d9a | ||
|
|
b758113752 | ||
|
|
d5f054b739 | ||
|
|
5465287089 | ||
|
|
09be84f69d | ||
|
|
473c4cf3fa | ||
|
|
347156f900 | ||
|
|
3b987f97eb | ||
|
|
d9bdcfeae3 | ||
|
|
76b70684cd | ||
|
|
8df7c22464 | ||
|
|
d725ba3d84 | ||
|
|
336b5da2a7 | ||
|
|
2d8ecd465b | ||
|
|
34ba4fa0ce | ||
|
|
6f39ae5d76 | ||
|
|
08d22219f4 | ||
|
|
8a3d81c430 | ||
|
|
83a70daf68 | ||
|
|
078fc7bfb8 | ||
|
|
d5a8a3bb09 | ||
|
|
eaeb114754 | ||
|
|
a67d095c70 | ||
|
|
cfd32581b7 | ||
|
|
85a6bd0a05 | ||
|
|
92cd1e3f19 | ||
|
|
647f43882b | ||
|
|
b54022e2ad | ||
|
|
eaa80c5396 | ||
|
|
ca47f5458c | ||
|
|
3aec6bff79 | ||
|
|
3027bb5092 | ||
|
|
83313ce1d5 | ||
|
|
893efa8e2d | ||
|
|
8aa3dcdaa7 | ||
|
|
1ea9659227 | ||
|
|
306d8136ef | ||
|
|
cbb37f27d7 | ||
|
|
e78fa18359 | ||
|
|
31e58d7597 | ||
|
|
1385a3dc03 | ||
|
|
3b21ed8fe8 | ||
|
|
789f0c826b | ||
|
|
0ad8db565d | ||
|
|
ac070b0cbe | ||
|
|
e21dc4d21c | ||
|
|
a49a4e6c2b | ||
|
|
95aa4afe75 | ||
|
|
74004fa375 | ||
|
|
d2fc87c6f9 | ||
|
|
a1a83a1ba3 | ||
|
|
e7d11e4bec | ||
|
|
5264a1f10d | ||
|
|
f0199a4cf2 | ||
|
|
f8877ef3e7 | ||
|
|
00b1156526 | ||
|
|
39d2ba8d1b | ||
|
|
322adcb180 | ||
|
|
77e7685c90 | ||
|
|
3c14e5e032 | ||
|
|
f58ec7e38e | ||
|
|
73fd0b06b2 | ||
|
|
8fa9336568 | ||
|
|
15148f7d1d | ||
|
|
7e8589ba95 | ||
|
|
fba668207f | ||
|
|
798cd10d6b | ||
|
|
442721bcb5 | ||
|
|
1a9049d277 | ||
|
|
c0931af91a | ||
|
|
29e9a06dc1 | ||
|
|
d6415042ae | ||
|
|
90006667fe | ||
|
|
fd351df08b | ||
|
|
7419749ba6 | ||
|
|
e3c26c97f2 | ||
|
|
d6e132fbda | ||
|
|
73bed04555 | ||
|
|
8893cdac1d | ||
|
|
7f245a15be | ||
|
|
b5c46ccd4a | ||
|
|
7fbc211c43 | ||
|
|
cf774cdb90 | ||
|
|
722a58491c | ||
|
|
037dfe1df6 | ||
|
|
0b26d45014 | ||
|
|
44e826543d | ||
|
|
74c4c642eb | ||
|
|
af3be19175 | ||
|
|
50f5ab6be4 | ||
|
|
941412a365 | ||
|
|
a9bd62dc43 | ||
|
|
4f336abeb8 | ||
|
|
ee49d64120 | ||
|
|
40d1ae0b1c | ||
|
|
b9c566238a | ||
|
|
4fd8177165 | ||
|
|
58257fa25e | ||
|
|
c597c34e5c | ||
|
|
0cc0f39d9e | ||
|
|
a2cdf214f0 | ||
|
|
cb3d8120bd | ||
|
|
189fd1d9e3 | ||
|
|
4f75d012e5 | ||
|
|
013173019f | ||
|
|
ace88cb709 | ||
|
|
ed8d4df5ef | ||
|
|
8ca20e3135 | ||
|
|
4e13cce770 | ||
|
|
31a1370028 | ||
|
|
f36f3aa05b | ||
|
|
f408e14d4b | ||
|
|
d0d90d7c69 | ||
|
|
aa618468d1 | ||
|
|
fadfd94bac | ||
|
|
9469681a0c | ||
|
|
543daac06d | ||
|
|
800d1b03c1 | ||
|
|
d4ab55dd9a | ||
|
|
da27ddba82 | ||
|
|
c72cb7e70e | ||
|
|
9df92665e0 | ||
|
|
9b970a472f | ||
|
|
819baa3951 | ||
|
|
c78024394e | ||
|
|
593131a7ea | ||
|
|
4267f2b855 | ||
|
|
ba8f18e1d4 | ||
|
|
ba13d24206 | ||
|
|
148f708360 | ||
|
|
239c51bb53 | ||
|
|
ab3a4a2468 | ||
|
|
3647291475 | ||
|
|
7d0feab078 | ||
|
|
a472d83e3d | ||
|
|
6dc6392fab | ||
|
|
e793b02f8b | ||
|
|
aae2db8ad8 | ||
|
|
c5cb84f976 | ||
|
|
f3d488de26 | ||
|
|
12c0edc530 | ||
|
|
ebc15db75e | ||
|
|
61565b25a3 | ||
|
|
dd28aca260 | ||
|
|
7619d055dd | ||
|
|
2a6e5b21a9 | ||
|
|
f01997f2ad | ||
|
|
fc6e98b534 | ||
|
|
8ecebee511 | ||
|
|
b5e26061e1 | ||
|
|
14f6ce3626 | ||
|
|
14fa20b428 | ||
|
|
2690fa3315 | ||
|
|
35cd965360 | ||
|
|
34a2a6ce03 | ||
|
|
133fc29ad5 | ||
|
|
83a5b98f82 | ||
|
|
e5dd51f637 | ||
|
|
db940e3bba | ||
|
|
2f6bcc3534 | ||
|
|
4923418f58 | ||
|
|
0a6c82dfe1 | ||
|
|
9f3a6be255 | ||
|
|
f89d843ab3 | ||
|
|
2dd7f5cada | ||
|
|
24c0f4950f | ||
|
|
d4dbbc59d4 | ||
|
|
dc0cd44c79 | ||
|
|
b6ac92d192 | ||
|
|
d7df249586 | ||
|
|
f3c4fcb0f5 | ||
|
|
9a8e9a0b01 | ||
|
|
f6a7e6b4e1 | ||
|
|
ce1c517a9f | ||
|
|
2829fb291f | ||
|
|
6110abfc7f | ||
|
|
6046f44f56 | ||
|
|
6c6131ce03 | ||
|
|
178c922407 | ||
|
|
343e87a8d4 | ||
|
|
d7e5d6fb7f | ||
|
|
75b6a3ede8 | ||
|
|
993606f102 | ||
|
|
bdf0b4daa9 | ||
|
|
44c189223e | ||
|
|
7fdbb59c30 | ||
|
|
5acf38ac36 | ||
|
|
e76728b2bf | ||
|
|
3e258f32cc | ||
|
|
3c51d6fb98 | ||
|
|
7cfe1389aa | ||
|
|
7292a8540b | ||
|
|
f65c690462 | ||
|
|
ecf8bc42fa | ||
|
|
3818bc3f98 | ||
|
|
faba812fc1 | ||
|
|
add433d702 | ||
|
|
9c99cb35e5 | ||
|
|
d8ec900933 | ||
|
|
9d392ad167 | ||
|
|
ea8509db1f | ||
|
|
df25ce76b6 | ||
|
|
e946fc65fc | ||
|
|
29ba5e73fa | ||
|
|
acf449c03a | ||
|
|
d203e075a8 | ||
|
|
dbe2f66539 | ||
|
|
ecb4cb7435 | ||
|
|
3200b5dc86 | ||
|
|
e20d4cecd5 | ||
|
|
0d8ff7bbac | ||
|
|
36177e09f7 | ||
|
|
48eb022824 | ||
|
|
03c9ffc033 | ||
|
|
61a9a4ac65 | ||
|
|
9ae62adff1 | ||
|
|
38962e68ee | ||
|
|
483dbb4a5d | ||
|
|
1f4dcc4f9e | ||
|
|
e86309669e | ||
|
|
6d6f55acf7 | ||
|
|
6ebcd44bb1 | ||
|
|
f8fb51fea0 | ||
|
|
bf768311c2 | ||
|
|
d797436786 | ||
|
|
73a2c935a7 | ||
|
|
b508c0d983 | ||
|
|
351893bbdd | ||
|
|
59e4bb028f | ||
|
|
6d895371ec | ||
|
|
42acbe66c3 | ||
|
|
ab91631e68 | ||
|
|
22a9299d97 | ||
|
|
b9acd0a9a6 | ||
|
|
c761364bed | ||
|
|
cc4af0a027 | ||
|
|
3366bae0ab | ||
|
|
d79dacf8a3 | ||
|
|
03b484c349 | ||
|
|
70081ecf33 | ||
|
|
575ba1cd7b | ||
|
|
d130959692 | ||
|
|
a8c689c6c0 | ||
|
|
1990ccb5d8 | ||
|
|
e107be56e4 | ||
|
|
0f8e87e001 | ||
|
|
d92d2b5e9e | ||
|
|
ebd0136773 | ||
|
|
f6653e1594 | ||
|
|
65bb76b9e3 | ||
|
|
efc36e12bc | ||
|
|
5a0b12f078 | ||
|
|
22d04cb9fc | ||
|
|
d8da119c56 | ||
|
|
a24d50d7e3 | ||
|
|
e5716e66bb | ||
|
|
f238593966 | ||
|
|
d951d3b872 | ||
|
|
ccceb870e3 | ||
|
|
ed6df77cbb | ||
|
|
1ad28312ec | ||
|
|
f002aa04cd | ||
|
|
b86d70623e | ||
|
|
fe3467309d | ||
|
|
851ab9c356 | ||
|
|
aef3c2e609 | ||
|
|
c6c2bb33ed | ||
|
|
0d0ef86550 | ||
|
|
5212e15cc4 | ||
|
|
f04fc546b5 | ||
|
|
ca0bd674a7 | ||
|
|
caf3076b12 | ||
|
|
260b2e0bd6 | ||
|
|
90413ae4fe | ||
|
|
c4c400d852 | ||
|
|
b7466e3206 | ||
|
|
f2812cdbe5 | ||
|
|
6cc4cc4fb6 | ||
|
|
95a2fdec99 | ||
|
|
d7495af207 | ||
|
|
13ad98b9b3 | ||
|
|
4be54fdd65 | ||
|
|
6d13397ba1 | ||
|
|
48e7e0309a | ||
|
|
6880c49a32 | ||
|
|
2ce9b2afaf | ||
|
|
d64a91d4ce | ||
|
|
c0c8a13864 | ||
|
|
1b48b4a1e1 | ||
|
|
5ffa41bc16 | ||
|
|
d2eef06276 | ||
|
|
0516100aae | ||
|
|
77b14c516e | ||
|
|
880a824f2f | ||
|
|
5b4079ab7e | ||
|
|
f7f1b5f399 | ||
|
|
d284d629a4 | ||
|
|
18efbfa803 | ||
|
|
7aa478d6ff | ||
|
|
c52195e6cd | ||
|
|
97700dbf15 | ||
|
|
c25c69d746 | ||
|
|
734a788340 | ||
|
|
a61734a6f8 | ||
|
|
eb1eb15791 | ||
|
|
750ecd4804 | ||
|
|
781c15d1ee | ||
|
|
a84077782d | ||
|
|
26048150d3 | ||
|
|
e5b6e2eb8c | ||
|
|
a1499a04d4 | ||
|
|
87b6ea4def | ||
|
|
fb23bddeb2 | ||
|
|
aa6fa4c674 | ||
|
|
72873a3343 | ||
|
|
19e7fc9cb9 | ||
|
|
a0a66f3b54 | ||
|
|
5ef25ccb77 | ||
|
|
1682a85cc0 | ||
|
|
cd9beec313 | ||
|
|
8295eaed90 | ||
|
|
3c9c13a371 | ||
|
|
86a7cefa68 | ||
|
|
829b648dd2 | ||
|
|
5475b9fbbe | ||
|
|
6f8e7c7002 | ||
|
|
96d04e35f9 | ||
|
|
67ca554261 | ||
|
|
629a8412dc | ||
|
|
f89953f39e | ||
|
|
772368ef8a | ||
|
|
19a83bc944 | ||
|
|
2e049aa244 | ||
|
|
a57b6471c9 | ||
|
|
bc7c1b4744 | ||
|
|
a59dacf679 | ||
|
|
8b93a404ef | ||
|
|
ded204344d | ||
|
|
12c78697f4 | ||
|
|
046e857768 | ||
|
|
4d8246c4d8 | ||
|
|
5c61d725e1 | ||
|
|
b3121d46c4 | ||
|
|
0c7195f1a3 | ||
|
|
00b070b3cf | ||
|
|
2c4cad4dac | ||
|
|
f60d03ddd3 | ||
|
|
9c37d5c23e | ||
|
|
89145593ef | ||
|
|
b2e80d37dd | ||
|
|
6432678de9 | ||
|
|
3d8345b92c | ||
|
|
952194b385 | ||
|
|
bfb452dd69 | ||
|
|
9ab928e92e | ||
|
|
64baeba1c7 | ||
|
|
71ed784c60 | ||
|
|
da45651121 | ||
|
|
d388ce9a06 | ||
|
|
47e71d8838 | ||
|
|
2b5973ec67 | ||
|
|
e58918f53e | ||
|
|
ea56939b7a | ||
|
|
6caddb65e9 | ||
|
|
125715af3f | ||
|
|
8df0d66fb6 | ||
|
|
ea8e7c5131 | ||
|
|
a80aa20b23 | ||
|
|
06e5e0b102 | ||
|
|
fd336ffd92 | ||
|
|
be1c559ad4 | ||
|
|
2dce37f289 | ||
|
|
22b5eef4ce | ||
|
|
63426e459a | ||
|
|
8393172ad2 | ||
|
|
cc06afc6df | ||
|
|
5247f5b3ea | ||
|
|
78396d8e4a | ||
|
|
f1ee22cbed | ||
|
|
39305468f8 | ||
|
|
32fd75bc4b | ||
|
|
efadf2cc79 | ||
|
|
40d63a2fa4 | ||
|
|
baa6dedbcf | ||
|
|
556b9ad89a | ||
|
|
9afc22bd8f | ||
|
|
ef0b0f88c9 | ||
|
|
a010239efb | ||
|
|
264a8cd70a | ||
|
|
aa1834170b | ||
|
|
f94d67ab35 | ||
|
|
3048c8c41f | ||
|
|
246e4a9f50 | ||
|
|
0001e8ffc4 |
Binary file not shown.
|
After Width: | Height: | Size: 3.0 MiB |
@@ -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
|
||||
@@ -62,6 +69,16 @@ gitGraph
|
||||
commit id: "2022-12-28" tag: "2.7.8"
|
||||
checkout support/3.0
|
||||
commit id: "2023-04-12" tag: "3.0.3"
|
||||
checkout develop
|
||||
commit id: "2023-06-19" tag: "3.1.0-beta" type: REVERSE
|
||||
commit id: "2023-07-26" tag: "3.1.0-1" type: HIGHLIGHT
|
||||
branch support/3.1 order: 840
|
||||
checkout support/3.1
|
||||
commit id: "2023-08-09" tag: "3.1.0-2"
|
||||
checkout support/2.7
|
||||
commit id: "2023-08-10" tag: "2.7.9"
|
||||
checkout support/3.1
|
||||
commit id: "2023-12-20" tag: "3.1.1"
|
||||
```
|
||||
|
||||
To learn more, check the [iTop community versions history on the official wiki](https://www.itophub.io/wiki/page?id=latest:release:start).
|
||||
To learn more, check the [iTop community versions history on the official wiki](https://www.itophub.io/wiki/page?id=latest:release:start).
|
||||
|
||||
6
.gitignore
vendored
6
.gitignore
vendored
@@ -37,7 +37,9 @@ tests/*/vendor/*
|
||||
|
||||
# iTop extensions
|
||||
/extensions/**
|
||||
!/extensions/.htaccess
|
||||
!/extensions/readme.txt
|
||||
!/extensions/web.config
|
||||
|
||||
# all logs but listing prevention
|
||||
/log/**
|
||||
@@ -45,8 +47,10 @@ tests/*/vendor/*
|
||||
!/log/index.php
|
||||
!/log/web.config
|
||||
|
||||
# PHPUnit cache file
|
||||
# PHPUnit: Cache file, local XML working copies
|
||||
/tests/php-unit-tests/.phpunit.result.cache
|
||||
/tests/php-unit-tests/phpunit.xml
|
||||
/tests/php-unit-tests/postbuild_integration.xml
|
||||
|
||||
|
||||
# Jetbrains
|
||||
|
||||
@@ -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
|
||||
@@ -161,4 +161,4 @@ We have one sticker per contribution type. You might get multiple stickers with
|
||||
|
||||
Here is the design of each stickers for year 2022:
|
||||
|
||||

|
||||

|
||||
|
||||
@@ -87,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');
|
||||
|
||||
@@ -446,6 +448,12 @@ class UserRightsProfile extends UserRightsAddOnAPI
|
||||
UR_ACTION_BULK_DELETE => 'bd',
|
||||
);
|
||||
|
||||
/**
|
||||
* @var array $aUsersProfilesList Cache of users' profiles. Hash array of user ID => [profile ID => profile friendlyname, profile ID => profile friendlyname, ...]
|
||||
* @since 2.7.10 3.0.4 3.1.1 3.2.0 N°6887
|
||||
*/
|
||||
private $aUsersProfilesList = [];
|
||||
|
||||
// Installation: create the very first user
|
||||
public function CreateAdministrator($sAdminUser, $sAdminPwd, $sLanguage = 'EN US')
|
||||
{
|
||||
@@ -502,6 +510,7 @@ class UserRightsProfile extends UserRightsAddOnAPI
|
||||
}
|
||||
|
||||
protected $m_aUserOrgs = array(); // userid -> array of orgid
|
||||
protected $m_aAdministrators = null; // [user id]
|
||||
|
||||
// Built on demand, could be optimized if necessary (doing a query for each attribute that needs to be read)
|
||||
protected $m_aObjectActionGrants = array();
|
||||
@@ -558,6 +567,7 @@ class UserRightsProfile extends UserRightsAddOnAPI
|
||||
|
||||
// Cache
|
||||
$this->m_aObjectActionGrants = array();
|
||||
$this->m_aAdministrators = null;
|
||||
}
|
||||
|
||||
public function LoadCache()
|
||||
@@ -700,12 +710,10 @@ class UserRightsProfile extends UserRightsAddOnAPI
|
||||
*/
|
||||
private function GetAdministrators()
|
||||
{
|
||||
static $aAdministrators = null;
|
||||
|
||||
if ($aAdministrators === null)
|
||||
if ($this->m_aAdministrators === null)
|
||||
{
|
||||
// Find all administrators
|
||||
$aAdministrators = array();
|
||||
$this->m_aAdministrators = array();
|
||||
$oAdministratorsFilter = new DBObjectSearch('User');
|
||||
$oLnkFilter = new DBObjectSearch('URP_UserProfile');
|
||||
$oExpression = new FieldExpression('profileid', 'URP_UserProfile');
|
||||
@@ -718,10 +726,10 @@ class UserRightsProfile extends UserRightsAddOnAPI
|
||||
$oSet->OptimizeColumnLoad(array('User' => array('login')));
|
||||
while($oUser = $oSet->Fetch())
|
||||
{
|
||||
$aAdministrators[] = $oUser->GetKey();
|
||||
$this->m_aAdministrators[] = $oUser->GetKey();
|
||||
}
|
||||
}
|
||||
return $aAdministrators;
|
||||
return $this->m_aAdministrators;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -758,8 +766,12 @@ class UserRightsProfile extends UserRightsAddOnAPI
|
||||
$sAction = self::$m_aActionCodes[$iActionCode];
|
||||
|
||||
$bStatus = null;
|
||||
// Cache user's profiles
|
||||
if(false === array_key_exists($iUser, $this->aUsersProfilesList)){
|
||||
$this->aUsersProfilesList[$iUser] = UserRights::ListProfiles($oUser);
|
||||
}
|
||||
// Call the API of UserRights because it caches the list for us
|
||||
foreach(UserRights::ListProfiles($oUser) as $iProfile => $oProfile)
|
||||
foreach($this->aUsersProfilesList[$iUser] as $iProfile => $oProfile)
|
||||
{
|
||||
$bGrant = $this->GetProfileActionGrant($iProfile, $sClass, $sAction);
|
||||
if (!is_null($bGrant))
|
||||
@@ -885,11 +897,16 @@ class UserRightsProfile extends UserRightsAddOnAPI
|
||||
// Note: this code is VERY close to the code of IsActionAllowed()
|
||||
$iUser = $oUser->GetKey();
|
||||
|
||||
// Cache user's profiles
|
||||
if(false === array_key_exists($iUser, $this->aUsersProfilesList)){
|
||||
$this->aUsersProfilesList[$iUser] = UserRights::ListProfiles($oUser);
|
||||
}
|
||||
|
||||
// Note: The object set is ignored because it was interesting to optimize for huge data sets
|
||||
// and acceptable to consider only the root class of the object set
|
||||
$bStatus = null;
|
||||
// Call the API of UserRights because it caches the list for us
|
||||
foreach(UserRights::ListProfiles($oUser) as $iProfile => $oProfile)
|
||||
foreach($this->aUsersProfilesList[$iUser] as $iProfile => $oProfile)
|
||||
{
|
||||
$bGrant = $this->GetClassStimulusGrant($iProfile, $sClass, $sStimulusCode);
|
||||
if (!is_null($bGrant))
|
||||
@@ -918,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']);
|
||||
};
|
||||
@@ -1,12 +1,13 @@
|
||||
<?php
|
||||
/**
|
||||
* @deprecated will be removed in 3.1.0 - moved to sources/Application/WebPage/AjaxPage.php, now loadable using autoloader
|
||||
* @deprecated 3.0.0 will be removed in 3.1.0 - moved to sources/Application/WebPage/AjaxPage.php, now loadable using autoloader
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
* @copyright Copyright (C) 2010-2023 Combodo SARL
|
||||
*/
|
||||
|
||||
// cannot notify depreciation for now as this is still load in autoloader
|
||||
//DeprecatedCallsLog::NotifyDeprecatedFile('moved to sources/Application/WebPage/AjaxPage.php, now loadable using autoloader');
|
||||
use Combodo\iTop\Application\WebPage\AjaxPage;
|
||||
|
||||
/**
|
||||
* Class ajax_page
|
||||
|
||||
@@ -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
|
||||
@@ -335,7 +337,6 @@ abstract class AbstractPreferencesExtension implements iPreferencesExtension
|
||||
* A recommended pattern is to cache data by the mean of static members.
|
||||
*
|
||||
* @api
|
||||
* @deprecated 3.1.0 N°4756 use the new event service instead, see {@see DBObject::FireEvent()} method
|
||||
* @package UIExtensibilityAPI
|
||||
*/
|
||||
interface iApplicationUIExtension
|
||||
@@ -487,7 +488,6 @@ interface iApplicationUIExtension
|
||||
* @api
|
||||
* @package UIExtensibilityAPI
|
||||
* @since 2.7.0
|
||||
* @deprecated
|
||||
*/
|
||||
abstract class AbstractApplicationUIExtension implements iApplicationUIExtension
|
||||
{
|
||||
@@ -560,6 +560,7 @@ abstract class AbstractApplicationUIExtension implements iApplicationUIExtension
|
||||
* or through the GUI.
|
||||
*
|
||||
* @api
|
||||
* @deprecated 3.1.0 N°4756 use the new event service instead, see {@see DBObject::FireEvent()} method. More details on each method PHPDoc.
|
||||
* @package ORMExtensibilityAPI
|
||||
*/
|
||||
interface iApplicationObjectExtension
|
||||
@@ -574,6 +575,7 @@ interface iApplicationObjectExtension
|
||||
* Otherwise, the answer is definitively "yes, the object has changed".
|
||||
*
|
||||
* @api
|
||||
* @deprecated 3.1.0 N°4756 No alternative available, this API was unstable and is abandoned
|
||||
* @param \cmdbAbstractObject $oObject The target object
|
||||
*
|
||||
* @return boolean True if something has changed for the target object
|
||||
@@ -587,6 +589,7 @@ interface iApplicationObjectExtension
|
||||
* Anyhow, this API can be called in other contexts such as the CSV import tool.
|
||||
*
|
||||
* @api
|
||||
* @deprecated 3.1.0 N°4756 Use EVENT_DB_CHECK_TO_WRITE event instead
|
||||
* @param \cmdbAbstractObject $oObject The target object
|
||||
*
|
||||
* @return string[] A list of errors message. An error message is made of one line and it can be displayed to the end-user.
|
||||
@@ -601,6 +604,7 @@ interface iApplicationObjectExtension
|
||||
* Please not that it is not possible to cascade deletion by this mean: only stopper issues can be handled.
|
||||
*
|
||||
* @api
|
||||
* @deprecated 3.1.0 N°4756 Use EVENT_DB_CHECK_TO_DELETE event instead
|
||||
* @param \cmdbAbstractObject $oObject The target object
|
||||
*
|
||||
* @return string[] A list of errors message. An error message is made of one line and it can be displayed to the end-user.
|
||||
@@ -617,6 +621,7 @@ interface iApplicationObjectExtension
|
||||
* * {@see DBObject::Get()} : for a given attribute the new value that was persisted
|
||||
*
|
||||
* @api
|
||||
* @deprecated 3.1.0 N°4756 Use EVENT_DB_AFTER_WRITE event instead
|
||||
* @param \cmdbAbstractObject $oObject The target object
|
||||
* @param CMDBChange|null $oChange A change context. Since 2.0 it is fine to ignore it, as the framework does maintain this information
|
||||
* once for all the changes made within the current page
|
||||
@@ -633,6 +638,7 @@ interface iApplicationObjectExtension
|
||||
* The method is called right <b>after</b> the object has been written to the database.
|
||||
*
|
||||
* @api
|
||||
* @deprecated 3.1.0 N°4756 Use EVENT_DB_AFTER_WRITE event instead
|
||||
* @param \cmdbAbstractObject $oObject The target object
|
||||
* @param CMDBChange|null $oChange A change context. Since 2.0 it is fine to ignore it, as the framework does maintain this information
|
||||
* once for all the changes made within the current page
|
||||
@@ -647,6 +653,7 @@ interface iApplicationObjectExtension
|
||||
* The method is called right <b>before</b> the object will be deleted from the database.
|
||||
*
|
||||
* @api
|
||||
* @deprecated 3.1.0 N°4756 Use EVENT_DB_AFTER_DELETE event instead
|
||||
* @param \cmdbAbstractObject $oObject The target object
|
||||
* @param CMDBChange|null $oChange A change context. Since 2.0 it is fine to ignore it, as the framework does maintain this information
|
||||
* once for all the changes made within the current page
|
||||
@@ -660,6 +667,7 @@ interface iApplicationObjectExtension
|
||||
* Extend this class instead of iApplicationObjectExtension if you don't need to overload all methods
|
||||
*
|
||||
* @api
|
||||
* @deprecated 3.1.0 N°4756 use the new event service instead, see {@see DBObject::FireEvent()} method
|
||||
* @package ORMExtensibilityAPI
|
||||
* @since 2.7.0
|
||||
*/
|
||||
@@ -2009,6 +2017,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)
|
||||
{
|
||||
@@ -2246,3 +2256,27 @@ interface iModuleExtension
|
||||
*/
|
||||
public function __construct();
|
||||
}
|
||||
|
||||
/**
|
||||
* KPI logging extensibility point
|
||||
*
|
||||
* KPI Logger extension
|
||||
*/
|
||||
interface iKPILoggerExtension
|
||||
{
|
||||
/**
|
||||
* Init the statistics collected
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function InitStats();
|
||||
|
||||
/**
|
||||
* Add a new KPI to the stats
|
||||
*
|
||||
* @param \Combodo\iTop\Core\Kpi\KpiLogData $oKpiLogData
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function LogOperation($oKpiLogData);
|
||||
}
|
||||
@@ -34,15 +34,15 @@ class AuditCategory extends cmdbAbstractObject
|
||||
{
|
||||
$aParams = array
|
||||
(
|
||||
"category" => "application, grant_by_profile",
|
||||
"key_type" => "autoincrement",
|
||||
"name_attcode" => "name",
|
||||
"state_attcode" => "",
|
||||
"reconc_keys" => array('name'),
|
||||
"db_table" => "priv_auditcategory",
|
||||
"db_key_field" => "id",
|
||||
"category" => "application,grant_by_profile",
|
||||
"key_type" => "autoincrement",
|
||||
"name_attcode" => "name",
|
||||
"state_attcode" => "",
|
||||
"reconc_keys" => array('name'),
|
||||
"db_table" => "priv_auditcategory",
|
||||
"db_key_field" => "id",
|
||||
"db_finalclass_field" => "",
|
||||
'style' => new ormStyle(null, null, null, null, null, '../images/icons/icons8-audit-folder.svg'),
|
||||
'style' => new ormStyle(null, null, null, null, null, '../images/icons/icons8-audit-folder.svg'),
|
||||
);
|
||||
MetaModel::Init_Params($aParams);
|
||||
MetaModel::Init_AddAttribute(new AttributeString("name", array("description"=>"Short name for this category", "allowed_values"=>null, "sql"=>"name", "default_value"=>"", "is_null_allowed"=>false, "depends_on"=>array())));
|
||||
|
||||
@@ -35,7 +35,7 @@ class AuditDomain extends cmdbAbstractObject
|
||||
{
|
||||
$aParams = array
|
||||
(
|
||||
"category" => "application, grant_by_profile",
|
||||
"category" => "application,grant_by_profile",
|
||||
"key_type" => "autoincrement",
|
||||
"name_attcode" => "name",
|
||||
"complementary_name_attcode" => array('description'),
|
||||
|
||||
@@ -35,7 +35,7 @@ class AuditRule extends cmdbAbstractObject
|
||||
{
|
||||
$aParams = array
|
||||
(
|
||||
"category" => "application, grant_by_profile",
|
||||
"category" => "application,grant_by_profile",
|
||||
"key_type" => "autoincrement",
|
||||
"name_attcode" => "name",
|
||||
"state_attcode" => "",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?php
|
||||
/**
|
||||
* @deprecated will be removed in 3.1.0 - moved to sources/Application/WebPage/CaptureWebPage.php, now loadable using autoloader
|
||||
* @deprecated 3.0.0 will be removed in 3.1.0 - moved to sources/Application/WebPage/CaptureWebPage.php, now loadable using autoloader
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
* @copyright Copyright (C) 2010-2023 Combodo SARL
|
||||
*/
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?php
|
||||
/**
|
||||
* @deprecated will be removed in 3.1.0 - moved to sources/Application/WebPage/CLIPage.php, now loadable using autoloader
|
||||
* @deprecated 3.0.0 will be removed in 3.1.0 - moved to sources/Application/WebPage/CLIPage.php, now loadable using autoloader
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
* @copyright Copyright (C) 2010-2023 Combodo SARL
|
||||
*/
|
||||
|
||||
@@ -26,7 +26,7 @@ use Combodo\iTop\Application\UI\Base\Component\Html\Html;
|
||||
use Combodo\iTop\Application\UI\Base\Component\Html\HtmlFactory;
|
||||
use Combodo\iTop\Application\UI\Base\Component\Input\InputUIBlockFactory;
|
||||
use Combodo\iTop\Application\UI\Base\Component\Input\Select\SelectOptionUIBlockFactory;
|
||||
use Combodo\iTop\Application\UI\Base\Component\Input\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;
|
||||
@@ -285,7 +288,7 @@ abstract class cmdbAbstractObject extends CMDBObject implements iDisplay
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \WebPage $oPage
|
||||
* @param WebPage $oPage
|
||||
* @param \cmdbAbstractObject $oObj
|
||||
* @param array $aParams
|
||||
*
|
||||
@@ -354,7 +357,7 @@ JS
|
||||
* @param int $iKey The identifier of the object
|
||||
* @param string $sMessageId Your id or one of the well-known ids: 'create', 'update' and 'apply_stimulus'
|
||||
* @param string $sMessage The HTML message (must be correctly escaped)
|
||||
* @param string $sSeverity Any of the \WebPage::ENUM_SESSION_MESSAGE_SEVERITY_XXX constants
|
||||
* @param string $sSeverity Any of the WebPage::ENUM_SESSION_MESSAGE_SEVERITY_XXX constants
|
||||
* @param float $fRank Ordering of the message: smallest displayed first (can be negative)
|
||||
* @param bool $bMustNotExist Do not alter any existing message (considering the id)
|
||||
*
|
||||
@@ -376,7 +379,7 @@ JS
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \WebPage $oPage Warning, since 3.0.0 this parameter was kept for compatibility reason. You shouldn't write directly on the page!
|
||||
* @param WebPage $oPage Warning, since 3.0.0 this parameter was kept for compatibility reason. You shouldn't write directly on the page!
|
||||
* When writing to the page, markup will be put above the real header of the panel.
|
||||
* To insert something IN the panel, we now need to add UIBlocks in either the "subtitle" or "toolbar" sections of the array that will be returned.
|
||||
* @param bool $bEditMode Deprecated parameter in iTop 3.0.0, use {@see GetDisplayMode()} and ENUM_DISPLAY_MODE_* constants instead
|
||||
@@ -554,7 +557,7 @@ HTML
|
||||
/**
|
||||
* Display properties tab of an object
|
||||
*
|
||||
* @param \WebPage $oPage
|
||||
* @param WebPage $oPage
|
||||
* @param bool $bEditMode Note that this parameter is no longer used in this method. Use {@see static::$sDisplayMode} instead
|
||||
* @param string $sPrefix
|
||||
* @param array $aExtraParams
|
||||
@@ -593,7 +596,7 @@ HTML
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \WebPage $oPage
|
||||
* @param WebPage $oPage
|
||||
* @param $sAttCode
|
||||
*
|
||||
* @throws \Exception
|
||||
@@ -634,7 +637,7 @@ HTML
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \WebPage $oPage
|
||||
* @param WebPage $oPage
|
||||
* @param bool $bEditMode Note that this parameter is no longer used in this method. Use {@see static::$sDisplayMode} instead
|
||||
*
|
||||
* @throws \CoreException
|
||||
@@ -744,7 +747,13 @@ HTML
|
||||
$oPage->SetCurrentTab($sTabCode, $oAttDef->GetLabel().$sCount, $sTabDescription);
|
||||
|
||||
$aArgs = array('this' => $this);
|
||||
$bReadOnly = ($iFlags & (OPT_ATT_READONLY | OPT_ATT_SLAVE));
|
||||
|
||||
$sEditWhen = $oAttDef->GetEditWhen();
|
||||
// Calculate if edit_when allows to edit based on current $bEditMode
|
||||
$bIsEditableBasedOnEditWhen = ($sEditWhen === LINKSET_EDITWHEN_ALWAYS) ||
|
||||
($bEditMode ? $sEditWhen === LINKSET_EDITWHEN_ON_HOST_EDITION : $sEditWhen === LINKSET_EDITWHEN_ON_HOST_DISPLAY);
|
||||
|
||||
$bReadOnly = ($iFlags & (OPT_ATT_READONLY | OPT_ATT_SLAVE)) || !$bIsEditableBasedOnEditWhen;
|
||||
if ($bEditMode && (!$bReadOnly)) {
|
||||
$sInputId = $this->m_iFormId.'_'.$sAttCode;
|
||||
$sDisplayValue = ''; // not used
|
||||
@@ -754,9 +763,9 @@ HTML
|
||||
$oPage->add($sHTMLValue);
|
||||
} else {
|
||||
if ($oAttDef->IsIndirect()) {
|
||||
$oBlockLinkSetViewTable = new BlockIndirectLinkSetViewTable($oPage, $this, $sClass, $sAttCode, $oAttDef);
|
||||
$oBlockLinkSetViewTable = new BlockIndirectLinkSetViewTable($oPage, $this, $sClass, $sAttCode, $oAttDef, $bReadOnly);
|
||||
} else {
|
||||
$oBlockLinkSetViewTable = new BlockDirectLinkSetViewTable($oPage, $this, $sClass, $sAttCode, $oAttDef);
|
||||
$oBlockLinkSetViewTable = new BlockDirectLinkSetViewTable($oPage, $this, $sClass, $sAttCode, $oAttDef, $bReadOnly);
|
||||
}
|
||||
$oPage->AddUiBlock($oBlockLinkSetViewTable);
|
||||
}
|
||||
@@ -855,7 +864,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
|
||||
@@ -1059,7 +1068,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
|
||||
@@ -1106,7 +1115,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']);
|
||||
@@ -1141,7 +1150,7 @@ HTML
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \WebPage $oPage
|
||||
* @param WebPage $oPage
|
||||
*
|
||||
* @throws \ArchivedObjectException
|
||||
* @throws \CoreException
|
||||
@@ -1164,9 +1173,9 @@ HTML
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \WebPage $oPage
|
||||
* @param WebPage $oPage
|
||||
* @param \CMDBObjectSet $oSet
|
||||
* @param array $aExtraParams
|
||||
* @param array $aExtraParams See possible values in {@see DataTableUIBlockFactory::RenderDataTable()}
|
||||
*
|
||||
* @throws \ApplicationException
|
||||
* @throws \CoreException
|
||||
@@ -1226,7 +1235,7 @@ HTML
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \WebPage $oPage
|
||||
* @param WebPage $oPage
|
||||
* @param \DBObjectSet $oSet
|
||||
* @param array $aExtraParams
|
||||
*
|
||||
@@ -1398,7 +1407,7 @@ HTML
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \WebPage $oPage
|
||||
* @param WebPage $oPage
|
||||
* @param \CMDBObjectSet $oSet
|
||||
* @param array $aExtraParams key used :
|
||||
* <ul>
|
||||
@@ -1521,7 +1530,7 @@ HTML
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \WebPage $oPage
|
||||
* @param WebPage $oPage
|
||||
* @param \CMDBObjectSet $oSet
|
||||
* @param array $aParams
|
||||
* @param string $sCharset
|
||||
@@ -1680,7 +1689,7 @@ HTML
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \WebPage $oPage
|
||||
* @param WebPage $oPage
|
||||
* @param \CMDBObjectSet $oSet
|
||||
* @param array $aParams
|
||||
*
|
||||
@@ -1893,7 +1902,7 @@ HTML
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \WebPage $oPage
|
||||
* @param WebPage $oPage
|
||||
* @param \CMDBObjectSet $oSet
|
||||
* @param array $aParams
|
||||
*
|
||||
@@ -1971,7 +1980,7 @@ HTML
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \WebPage $oPage
|
||||
* @param WebPage $oPage
|
||||
* @param \CMDBObjectSet $oSet
|
||||
* @param array $aExtraParams
|
||||
*
|
||||
@@ -2002,7 +2011,7 @@ HTML
|
||||
|
||||
|
||||
/**
|
||||
* @param \WebPage $oPage
|
||||
* @param WebPage $oPage
|
||||
* @param string $sClass
|
||||
* @param string $sAttCode
|
||||
* @param \AttributeDefinition $oAttDef
|
||||
@@ -2740,7 +2749,7 @@ JS
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \WebPage $oPage
|
||||
* @param WebPage $oPage
|
||||
* @param array $aExtraParams
|
||||
*
|
||||
* @throws \ArchivedObjectException
|
||||
@@ -3145,7 +3154,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
|
||||
@@ -3240,7 +3249,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
|
||||
@@ -3325,7 +3334,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
|
||||
@@ -3703,7 +3712,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_');
|
||||
@@ -3738,7 +3747,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
|
||||
@@ -4538,7 +4547,7 @@ HTML;
|
||||
return $res;
|
||||
}
|
||||
|
||||
public function PostInsertActions(): void
|
||||
protected function PostInsertActions(): void
|
||||
{
|
||||
parent::PostInsertActions();
|
||||
|
||||
@@ -4547,7 +4556,9 @@ HTML;
|
||||
foreach (MetaModel::EnumPlugins(iApplicationObjectExtension::class) as $oExtensionInstance) {
|
||||
$sExtensionClass = get_class($oExtensionInstance);
|
||||
$this->LogCRUDDebug(__METHOD__, "Calling $sExtensionClass::OnDBInsert()");
|
||||
$oKPI = new ExecutionKPI();
|
||||
$oExtensionInstance->OnDBInsert($this, self::GetCurrentChange());
|
||||
$oKPI->ComputeStatsForExtension($oExtensionInstance, 'OnDBInsert');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4560,15 +4571,21 @@ 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)
|
||||
{
|
||||
$oNewObj = parent::DBCloneTracked_Internal($newKey);
|
||||
/** @var cmdbAbstractObject $oNewObj */
|
||||
$oNewObj = MetaModel::GetObject(get_class($this), parent::DBCloneTracked_Internal($newKey));
|
||||
|
||||
// Invoke extensions after insertion (the object must exist, have an id, etc.)
|
||||
/** @var \iApplicationObjectExtension $oExtensionInstance */
|
||||
foreach(MetaModel::EnumPlugins('iApplicationObjectExtension') as $oExtensionInstance)
|
||||
{
|
||||
$oKPI = new ExecutionKPI();
|
||||
$oExtensionInstance->OnDBInsert($oNewObj, self::GetCurrentChange());
|
||||
$oKPI->ComputeStatsForExtension($oExtensionInstance, 'OnDBInsert');
|
||||
}
|
||||
|
||||
return $oNewObj;
|
||||
@@ -4577,6 +4594,7 @@ HTML;
|
||||
public function DBUpdate()
|
||||
{
|
||||
$this->LogCRUDEnter(__METHOD__);
|
||||
$res = 0;
|
||||
|
||||
try {
|
||||
if (count($this->ListChanges()) === 0) {
|
||||
@@ -4596,7 +4614,7 @@ HTML;
|
||||
return $res;
|
||||
}
|
||||
|
||||
public function PostUpdateActions(array $aChanges): void
|
||||
protected function PostUpdateActions(array $aChanges): void
|
||||
{
|
||||
parent::PostUpdateActions($aChanges);
|
||||
|
||||
@@ -4605,7 +4623,9 @@ HTML;
|
||||
foreach (MetaModel::EnumPlugins(iApplicationObjectExtension::class) as $oExtensionInstance) {
|
||||
$sExtensionClass = get_class($oExtensionInstance);
|
||||
$this->LogCRUDDebug(__METHOD__, "Calling $sExtensionClass::OnDBUpdate()");
|
||||
$oKPI = new ExecutionKPI();
|
||||
$oExtensionInstance->OnDBUpdate($this, self::GetCurrentChange());
|
||||
$oKPI->ComputeStatsForExtension($oExtensionInstance, 'OnDBUpdate');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4635,6 +4655,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();
|
||||
}
|
||||
}
|
||||
@@ -4643,13 +4664,23 @@ 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 */
|
||||
foreach(MetaModel::EnumPlugins('iApplicationObjectExtension') as $oExtensionInstance)
|
||||
{
|
||||
$oKPI = new ExecutionKPI();
|
||||
$oExtensionInstance->OnDBDelete($this, self::GetCurrentChange());
|
||||
$oKPI->ComputeStatsForExtension($oExtensionInstance, 'OnDBDelete');
|
||||
}
|
||||
|
||||
return parent::DBDeleteTracked_Internal($oDeletionPlan);
|
||||
@@ -4668,7 +4699,10 @@ HTML;
|
||||
foreach(MetaModel::EnumPlugins('iApplicationObjectExtension') as $oExtensionInstance)
|
||||
{
|
||||
$sExtensionClass = get_class($oExtensionInstance);
|
||||
if ($oExtensionInstance->OnIsModified($this)) {
|
||||
$oKPI = new ExecutionKPI();
|
||||
$bIsModified = $oExtensionInstance->OnIsModified($this);
|
||||
$oKPI->ComputeStatsForExtension($oExtensionInstance, 'OnIsModified');
|
||||
if ($bIsModified) {
|
||||
$this->LogCRUDDebug(__METHOD__, "Calling $sExtensionClass::OnIsModified() -> true");
|
||||
return true;
|
||||
} else {
|
||||
@@ -4724,7 +4758,9 @@ HTML;
|
||||
/** @var \iApplicationObjectExtension $oExtensionInstance */
|
||||
foreach(MetaModel::EnumPlugins('iApplicationObjectExtension') as $oExtensionInstance)
|
||||
{
|
||||
$oKPI = new ExecutionKPI();
|
||||
$aNewIssues = $oExtensionInstance->OnCheckToWrite($this);
|
||||
$oKPI->ComputeStatsForExtension($oExtensionInstance, 'OnCheckToWrite');
|
||||
if (is_array($aNewIssues) && (count($aNewIssues) > 0)) // Some extensions return null instead of an empty array
|
||||
{
|
||||
$this->m_aCheckIssues = array_merge($this->m_aCheckIssues, $aNewIssues);
|
||||
@@ -4772,7 +4808,9 @@ HTML;
|
||||
/** @var \iApplicationObjectExtension $oExtensionInstance */
|
||||
foreach(MetaModel::EnumPlugins('iApplicationObjectExtension') as $oExtensionInstance)
|
||||
{
|
||||
$oKPI = new ExecutionKPI();
|
||||
$aNewIssues = $oExtensionInstance->OnCheckToDelete($this);
|
||||
$oKPI->ComputeStatsForExtension($oExtensionInstance, 'OnCheckToDelete');
|
||||
if (is_array($aNewIssues) && count($aNewIssues) > 0)
|
||||
{
|
||||
$this->m_aDeleteIssues = array_merge($this->m_aDeleteIssues, $aNewIssues);
|
||||
@@ -4797,7 +4835,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
|
||||
@@ -4901,7 +4939,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
|
||||
@@ -5026,7 +5064,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
|
||||
@@ -5270,7 +5308,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
|
||||
@@ -5326,7 +5364,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');
|
||||
@@ -5343,6 +5381,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();
|
||||
}
|
||||
}
|
||||
@@ -5405,7 +5448,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
|
||||
@@ -5911,6 +5954,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
|
||||
@@ -5920,47 +5973,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.
|
||||
*
|
||||
@@ -5995,7 +6064,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);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -6027,9 +6101,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);
|
||||
@@ -6037,7 +6117,6 @@ JS
|
||||
$oObject->DBUpdate();
|
||||
}
|
||||
}
|
||||
self::RemoveObjectAwaitingEventDbLinksChanged($sClass, $sId);
|
||||
cmdbAbstractObject::SetEventDBLinksChangedBlocked(false);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?php
|
||||
/**
|
||||
* @deprecated will be removed in 3.1.0 - moved to sources/Application/WebPage/CSVPage.php, now loadable using autoloader
|
||||
* @deprecated 3.0.0 will be removed in 3.1.0 - moved to sources/Application/WebPage/CSVPage.php, now loadable using autoloader
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
* @copyright Copyright (C) 2010-2023 Combodo SARL
|
||||
*/
|
||||
|
||||
@@ -9,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())
|
||||
@@ -918,6 +920,11 @@ class RuntimeDashboard extends Dashboard
|
||||
{
|
||||
$bCustomized = false;
|
||||
|
||||
$sDashboardFileSanitized = utils::RealPath(APPROOT.$sDashboardFile, APPROOT);
|
||||
if (false === $sDashboardFileSanitized) {
|
||||
throw new SecurityException('Invalid dashboard file !');
|
||||
}
|
||||
|
||||
// Search for an eventual user defined dashboard
|
||||
$oUDSearch = new DBObjectSearch('UserDashboard');
|
||||
$oUDSearch->AddCondition('user_id', UserRights::GetUserId(), '=');
|
||||
@@ -929,7 +936,7 @@ class RuntimeDashboard extends Dashboard
|
||||
$sDashboardDefinition = $oUserDashboard->Get('contents');
|
||||
$bCustomized = true;
|
||||
} else {
|
||||
$sDashboardDefinition = @file_get_contents($sDashboardFile);
|
||||
$sDashboardDefinition = @file_get_contents($sDashboardFileSanitized);
|
||||
}
|
||||
|
||||
|
||||
@@ -937,7 +944,7 @@ class RuntimeDashboard extends Dashboard
|
||||
$oDashboard = new RuntimeDashboard($sDashBoardId);
|
||||
$oDashboard->FromXml($sDashboardDefinition);
|
||||
$oDashboard->SetCustomFlag($bCustomized);
|
||||
$oDashboard->SetDefinitionFile($sDashboardFile);
|
||||
$oDashboard->SetDefinitionFile($sDashboardFileSanitized);
|
||||
} else {
|
||||
$oDashboard = null;
|
||||
}
|
||||
@@ -1104,7 +1111,7 @@ JS
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \WebPage $oPage
|
||||
* @param WebPage $oPage
|
||||
* @param array $aExtraParams
|
||||
*
|
||||
* @throws \Exception
|
||||
@@ -1136,7 +1143,7 @@ JS
|
||||
$oToolbar->AddSubBlock($oActionButton);
|
||||
|
||||
$aActions = array();
|
||||
$sFile = addslashes($this->sDefinitionFile);
|
||||
$sFile = addslashes(utils::LocalPath($this->sDefinitionFile));
|
||||
$sJSExtraParams = json_encode($aExtraParams);
|
||||
if ($this->HasCustomDashboard()) {
|
||||
$oEdit = new JSPopupMenuItem('UI:Dashboard:Edit', Dict::S('UI:Dashboard:EditCustom'), "return EditDashboard('{$this->sId}', '$sFile', $sJSExtraParams)");
|
||||
@@ -1223,7 +1230,7 @@ EOF
|
||||
|
||||
|
||||
/**
|
||||
* @param \WebPage $oPage
|
||||
* @param WebPage $oPage
|
||||
*
|
||||
* @param array $aExtraParams
|
||||
*
|
||||
@@ -1259,12 +1266,12 @@ EOF
|
||||
$sOkButtonLabel = Dict::S('UI:Button:Save');
|
||||
$sCancelButtonLabel = Dict::S('UI:Button:Cancel');
|
||||
|
||||
$sId = addslashes($this->sId);
|
||||
$sLayoutClass = addslashes($this->sLayoutClass);
|
||||
$sId = utils::HtmlEntities($this->sId);
|
||||
$sLayoutClass = utils::HtmlEntities($this->sLayoutClass);
|
||||
$sAutoReload = $this->bAutoReload ? 'true' : 'false';
|
||||
$sAutoReloadSec = (string) $this->iAutoReloadSec;
|
||||
$sTitle = addslashes($this->sTitle);
|
||||
$sFile = addslashes($this->GetDefinitionFile());
|
||||
$sTitle = utils::HtmlEntities($this->sTitle);
|
||||
$sFile = utils::HtmlEntities($this->GetDefinitionFile());
|
||||
$sUrl = utils::GetAbsoluteUrlAppRoot().'pages/ajax.render.php';
|
||||
$sReloadURL = $this->GetReloadURL();
|
||||
|
||||
@@ -1483,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>
|
||||
@@ -514,10 +531,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
|
||||
@@ -1246,6 +1248,10 @@ JS
|
||||
} else {
|
||||
$oBlock = DashletFactory::MakeForDashletBadge($sClassIconUrl, $sHyperlink, $iCount, $sClassLabel, null, null, $aRefreshParams);
|
||||
}
|
||||
$sClassDescription = MetaModel::GetClassDescription($sClass);
|
||||
if (utils::IsNotNullOrEmptyString($sClassDescription)) {
|
||||
$oBlock->SetClassDescription($sClassDescription);
|
||||
}
|
||||
|
||||
return $oBlock;
|
||||
}
|
||||
@@ -1350,7 +1356,7 @@ JS
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \WebPage $oPage
|
||||
* @param WebPage $oPage
|
||||
* @param array $aExtraParams
|
||||
*
|
||||
* @return \Combodo\iTop\Application\UI\Base\iUIBlock
|
||||
@@ -1374,7 +1380,7 @@ JS
|
||||
|
||||
/**
|
||||
* @param array $aExtraParams
|
||||
* @param \WebPage $oPage
|
||||
* @param WebPage $oPage
|
||||
*
|
||||
* @throws \ArchivedObjectException
|
||||
* @throws \ConfigException
|
||||
@@ -1452,7 +1458,7 @@ JS
|
||||
|
||||
/**
|
||||
* @param array $aExtraParams
|
||||
* @param \WebPage $oPage
|
||||
* @param WebPage $oPage
|
||||
*
|
||||
* @return \Combodo\iTop\Application\UI\Base\Layout\UIContentBlock
|
||||
* @throws \ApplicationException
|
||||
@@ -1560,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
|
||||
@@ -1660,7 +1666,7 @@ JS
|
||||
|
||||
/**
|
||||
* @param array $aExtraParams
|
||||
* @param \WebPage $oPage
|
||||
* @param WebPage $oPage
|
||||
*
|
||||
* @throws \ArchivedObjectException
|
||||
* @throws \CoreException
|
||||
@@ -1826,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
|
||||
*
|
||||
@@ -2038,7 +2044,7 @@ class MenuBlock extends DisplayBlock
|
||||
}
|
||||
|
||||
//----------------------------------------------------
|
||||
// Any style but NOT "listInObject" (linksets) actions
|
||||
// Any style but NOT \DisplayBlock::ENUM_STYLE_LIST_IN_OBJECT (linksets) actions
|
||||
//----------------------------------------------------
|
||||
if ($this->m_sStyle !== static::ENUM_STYLE_LIST_IN_OBJECT) {
|
||||
switch ($iSetCount) {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?php
|
||||
/**
|
||||
* @deprecated will be removed in 3.1.0 - moved to sources/Application/WebPage/ErrorPage.php, now loadable using autoloader
|
||||
* @deprecated 3.0.0 will be removed in 3.1.0 - moved to sources/Application/WebPage/ErrorPage.php, now loadable using autoloader
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
* @copyright Copyright (C) 2010-2023 Combodo SARL
|
||||
*/
|
||||
|
||||
@@ -1,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
|
||||
*
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?php
|
||||
/**
|
||||
* @deprecated will be removed in 3.1.0 - moved to sources/Application/WebPage/iTopWebPage.php, now loadable using autoloader
|
||||
* @deprecated 3.0.0 will be removed in 3.1.0 - moved to sources/Application/WebPage/iTopWebPage.php, now loadable using autoloader
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
* @copyright Copyright (C) 2010-2023 Combodo SARL
|
||||
*/
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?php
|
||||
/**
|
||||
* @deprecated will be removed in 3.1.0 - moved to sources/Application/WebPage/iTopWizardWebPage.php, now loadable using autoloader
|
||||
* @deprecated 3.0.0 will be removed in 3.1.0 - moved to sources/Application/WebPage/iTopWizardWebPage.php, now loadable using autoloader
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
* @copyright Copyright (C) 2010-2023 Combodo SARL
|
||||
*/
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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()
|
||||
@@ -248,6 +250,7 @@ class LoginWebPage extends NiceWebPage
|
||||
$oEmail = new Email();
|
||||
$oEmail->SetRecipientTO($sTo);
|
||||
$sFrom = MetaModel::GetConfig()->Get('forgot_password_from');
|
||||
$sFrom = utils::IsNullOrEmptyString($sFrom) ? MetaModel::GetConfig()->Get('email_default_sender_address') : $sFrom;
|
||||
$oEmail->SetRecipientFrom($sFrom);
|
||||
$oEmail->SetSubject(Dict::S('UI:ResetPwd-EmailSubject', $oUser->Get('login')));
|
||||
$sResetUrl = utils::GetAbsoluteUrlAppRoot().'pages/UI.php?loginop=reset_pwd&auth_user='.urlencode($oUser->Get('login')).'&token='.urlencode($sToken);
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?php
|
||||
/**
|
||||
* @deprecated will be removed in 3.1.0 - moved to sources/Application/WebPage/NiceWebPage.php, now loadable using autoloader
|
||||
* @deprecated 3.0.0 will be removed in 3.1.0 - moved to sources/Application/WebPage/NiceWebPage.php, now loadable using autoloader
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
* @copyright Copyright (C) 2010-2023 Combodo SARL
|
||||
*/
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?php
|
||||
/**
|
||||
* @deprecated will be removed in 3.1.0 - moved to sources/Application/WebPage/PDFPage.php, now loadable using autoloader
|
||||
* @deprecated 3.0.0 will be removed in 3.1.0 - moved to sources/Application/WebPage/PDFPage.php, now loadable using autoloader
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
* @copyright Copyright (C) 2010-2023 Combodo SARL
|
||||
*/
|
||||
|
||||
@@ -21,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
|
||||
{
|
||||
@@ -296,7 +297,7 @@ class QueryOQL extends Query
|
||||
}
|
||||
catch
|
||||
(OQLException $e) {
|
||||
$oAlert = AlertUIBlockFactory::MakeForFailure(Dict::Format('UI:RunQuery:Error'), $e->getHtmlDesc())
|
||||
$oAlert = AlertUIBlockFactory::MakeForFailure(Dict::S('UI:RunQuery:Error'), $e->getHtmlDesc())
|
||||
->SetIsClosable(false)
|
||||
->SetIsCollapsible(false);
|
||||
$oAlert->AddCSSClass('mb-5');
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
/**
|
||||
|
||||
@@ -99,4 +99,10 @@ else
|
||||
Session::Set('itop_env', ITOP_DEFAULT_ENV);
|
||||
}
|
||||
$sConfigFile = APPCONF.$sEnv.'/'.ITOP_CONFIG_FILE;
|
||||
MetaModel::Startup($sConfigFile, false /* $bModelOnly */, $bAllowCache, false /* $bTraceSourceFiles */, $sEnv);
|
||||
try {
|
||||
MetaModel::Startup($sConfigFile, false /* $bModelOnly */, $bAllowCache, false /* $bTraceSourceFiles */, $sEnv);
|
||||
}
|
||||
catch (MySQLException $e) {
|
||||
IssueLog::Debug($e->getMessage());
|
||||
throw new MySQLException('Could not connect to the DB server', []);
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -163,7 +164,7 @@ class UIExtKeyWidget
|
||||
$oPage->add_linked_script('../js/extkeywidget.js');
|
||||
$oPage->add_linked_script('../js/forms-json-utils.js');
|
||||
|
||||
$bCreate = (!$this->bSearchMode) && (UserRights::IsActionAllowed($this->sTargetClass, UR_ACTION_BULK_MODIFY) && $bAllowTargetCreation);
|
||||
$bCreate = (!$this->bSearchMode) && (UserRights::IsActionAllowed($this->sTargetClass, UR_ACTION_MODIFY) && $bAllowTargetCreation);
|
||||
$bExtensions = true;
|
||||
$sMessage = Dict::S('UI:Message:EmptyList:UseSearchForm');
|
||||
$sAttrFieldPrefix = ($this->bSearchMode) ? '' : 'attr_';
|
||||
@@ -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
|
||||
@@ -975,6 +976,10 @@ HTML
|
||||
// Remove blob edition from creation form @see N°5863 to allow blob edition in modal context
|
||||
FormHelper::DisableAttributeBlobInputs($this->sTargetClass, $aFormExtraParams);
|
||||
|
||||
if(FormHelper::HasMandatoryAttributeBlobInputs($oNewObj)){
|
||||
$oPage->AddUiBlock(FormHelper::GetAlertForMandatoryAttributeBlobInputsInModal(FormHelper::ENUM_MANDATORY_BLOB_MODE_CREATE));
|
||||
}
|
||||
|
||||
cmdbAbstractObject::DisplayCreationForm($oPage, $this->sTargetClass, $oNewObj, array(), $aFormExtraParams);
|
||||
$oPage->add(<<<HTML
|
||||
</div>
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
/**
|
||||
@@ -143,6 +144,10 @@ JS
|
||||
|
||||
// Remove blob edition from creation form @see N°5863 to allow blob edition in modal context
|
||||
FormHelper::DisableAttributeBlobInputs($sRealClass, $aFormExtraParams);
|
||||
|
||||
if(FormHelper::HasMandatoryAttributeBlobInputs($oObj)){
|
||||
$oPage->AddUiBlock(FormHelper::GetAlertForMandatoryAttributeBlobInputsInModal(FormHelper::ENUM_MANDATORY_BLOB_MODE_CREATE));
|
||||
}
|
||||
|
||||
cmdbAbstractObject::DisplayCreationForm($oPage, $sRealClass, $oObj, array(), $aFormExtraParams);
|
||||
}
|
||||
|
||||
@@ -8,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');
|
||||
@@ -178,17 +180,18 @@ class UILinksWidget
|
||||
|
||||
$oDisplayBlock = new DisplayBlock($oFilter, 'search', false);
|
||||
$oBlock->AddSubBlock($oDisplayBlock->GetDisplay($oPage, "SearchFormToAdd_{$sLinkedSetId}",
|
||||
array(
|
||||
'menu' => false,
|
||||
[
|
||||
'menu' => false,
|
||||
'result_list_outer_selector' => "SearchResultsToAdd_{$sLinkedSetId}",
|
||||
'table_id' => "add_{$sLinkedSetId}",
|
||||
'table_inner_id' => "ResultsToAdd_{$sLinkedSetId}",
|
||||
'selection_mode' => true,
|
||||
'json' => $sJson,
|
||||
'cssCount' => '#count_'.$this->m_sAttCode.$this->m_sNameSuffix,
|
||||
'query_params' => $oFilter->GetInternalParams(),
|
||||
'hidden_criteria' => $sAlreadyLinkedExpression,
|
||||
)));
|
||||
'table_id' => "add_{$sLinkedSetId}",
|
||||
'table_inner_id' => "ResultsToAdd_{$sLinkedSetId}",
|
||||
'selection_mode' => true,
|
||||
'json' => $sJson,
|
||||
'cssCount' => '#count_'.$this->m_sAttCode.$this->m_sNameSuffix,
|
||||
'query_params' => $oFilter->GetInternalParams(),
|
||||
'hidden_criteria' => $sAlreadyLinkedExpression,
|
||||
'submit_on_load' => false,
|
||||
]));
|
||||
|
||||
$oBlock->AddForm();
|
||||
}
|
||||
|
||||
@@ -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,6 +20,9 @@
|
||||
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 ScssPhp\ScssPhp\Compiler;
|
||||
use ScssPhp\ScssPhp\OutputStyle;
|
||||
use ScssPhp\ScssPhp\ValueConverter;
|
||||
@@ -51,22 +54,31 @@ class utils
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
* @since 3.0.0
|
||||
* @since 2.7.10 3.0.0
|
||||
*/
|
||||
public const ENUM_SANITIZATION_FILTER_INTEGER = 'integer';
|
||||
/**
|
||||
* Datamodel class
|
||||
* @var string
|
||||
* @since 3.0.0
|
||||
* @since 2.7.10 3.0.0
|
||||
* @since 2.7.10 3.0.4 3.1.1 3.2.0 N°6606 update PHPDoc
|
||||
* @uses MetaModel::IsValidClass()
|
||||
*/
|
||||
public const ENUM_SANITIZATION_FILTER_CLASS = 'class';
|
||||
/**
|
||||
* @var string
|
||||
* @since 3.0.0
|
||||
* @since 2.7.10 3.0.4 3.1.1 3.2.0 N°6606
|
||||
* @uses class_exists()
|
||||
*/
|
||||
public const ENUM_SANITIZATION_FILTER_PHP_CLASS = 'php_class';
|
||||
/**
|
||||
* @var string
|
||||
* @since 2.7.10 3.0.0
|
||||
*/
|
||||
public const ENUM_SANITIZATION_FILTER_STRING = 'string';
|
||||
/**
|
||||
* @var string
|
||||
* @since 3.0.0
|
||||
* @since 2.7.10 3.0.0
|
||||
*/
|
||||
public const ENUM_SANITIZATION_FILTER_CONTEXT_PARAM = 'context_param';
|
||||
/**
|
||||
@@ -81,22 +93,22 @@ class utils
|
||||
public const ENUM_SANITIZATION_FILTER_OPERATION = 'operation';
|
||||
/**
|
||||
* @var string
|
||||
* @since 3.0.0
|
||||
* @since 2.7.10 3.0.0
|
||||
*/
|
||||
public const ENUM_SANITIZATION_FILTER_PARAMETER = 'parameter';
|
||||
/**
|
||||
* @var string
|
||||
* @since 3.0.0
|
||||
* @since 2.7.10 3.0.0
|
||||
*/
|
||||
public const ENUM_SANITIZATION_FILTER_FIELD_NAME = 'field_name';
|
||||
/**
|
||||
* @var string
|
||||
* @since 3.0.0
|
||||
* @since 2.7.10 3.0.0
|
||||
*/
|
||||
public const ENUM_SANITIZATION_FILTER_TRANSACTION_ID = 'transaction_id';
|
||||
/**
|
||||
* @var string For XML / HTML node identifiers
|
||||
* @since 3.0.0
|
||||
* @since 2.7.10 3.0.0
|
||||
*/
|
||||
public const ENUM_SANITIZATION_FILTER_ELEMENT_IDENTIFIER = 'element_identifier';
|
||||
/**
|
||||
@@ -106,12 +118,13 @@ class utils
|
||||
public const ENUM_SANITIZATION_FILTER_VARIABLE_NAME = 'variable_name';
|
||||
/**
|
||||
* @var string
|
||||
* @since 3.0.0
|
||||
* @since 2.7.10 3.0.0
|
||||
*/
|
||||
public const ENUM_SANITIZATION_FILTER_RAW_DATA = 'raw_data';
|
||||
/**
|
||||
* @var string
|
||||
* @since 3.0.2, 3.1.0 N°4899
|
||||
* @since 3.0.2 3.1.0 N°4899
|
||||
* @since 2.7.10 N°6606
|
||||
*/
|
||||
public const ENUM_SANITIZATION_FILTER_URL = 'url';
|
||||
|
||||
@@ -154,6 +167,8 @@ class utils
|
||||
|
||||
private static $iNextId = 0;
|
||||
|
||||
private static $m_sAppRootUrl = null;
|
||||
|
||||
protected static function LoadParamFile($sParamFile)
|
||||
{
|
||||
if (!file_exists($sParamFile)) {
|
||||
@@ -395,6 +410,10 @@ class utils
|
||||
* @since 2.7.0 new 'element_identifier' filter
|
||||
* @since 3.0.0 new utils::ENUM_SANITIZATION_* const
|
||||
* @since 2.7.7, 3.0.2, 3.1.0 N°4899 - new 'url' filter
|
||||
* @since 2.7.10 N°6606 use the utils::ENUM_SANITIZATION_* const
|
||||
* @since 2.7.10 N°6606 new case for ENUM_SANITIZATION_FILTER_PHP_CLASS
|
||||
*
|
||||
* @link https://www.php.net/manual/en/filter.filters.sanitize.php PHP sanitization filters
|
||||
*/
|
||||
protected static function Sanitize_Internal($value, $sSanitizationFilter)
|
||||
{
|
||||
@@ -415,6 +434,13 @@ class utils
|
||||
$retValue = filter_var($value, FILTER_SANITIZE_SPECIAL_CHARS);
|
||||
break;
|
||||
|
||||
case static::ENUM_SANITIZATION_FILTER_PHP_CLASS:
|
||||
$retValue = $value;
|
||||
if (!class_exists($value)) {
|
||||
$retValue = false;
|
||||
}
|
||||
break;
|
||||
|
||||
case static::ENUM_SANITIZATION_FILTER_CONTEXT_PARAM:
|
||||
case static::ENUM_SANITIZATION_FILTER_ROUTE:
|
||||
case static::ENUM_SANITIZATION_FILTER_OPERATION:
|
||||
@@ -480,6 +506,7 @@ class utils
|
||||
|
||||
// For URL
|
||||
case static::ENUM_SANITIZATION_FILTER_URL:
|
||||
// N°6350 - returns only valid URLs
|
||||
$retValue = filter_var($value, FILTER_VALIDATE_URL);
|
||||
break;
|
||||
|
||||
@@ -1023,7 +1050,7 @@ class utils
|
||||
*/
|
||||
public static function GetAbsoluteUrlAppRoot($bForceTrustProxy = false)
|
||||
{
|
||||
static $sUrl = null;
|
||||
$sUrl = static::$m_sAppRootUrl;
|
||||
if ($sUrl === null || $bForceTrustProxy)
|
||||
{
|
||||
$sUrl = self::GetConfig()->Get('app_root_url');
|
||||
@@ -1044,8 +1071,9 @@ class utils
|
||||
}
|
||||
$sUrl = str_replace(SERVER_NAME_PLACEHOLDER, $sServerName, $sUrl);
|
||||
}
|
||||
static::$m_sAppRootUrl = $sUrl;
|
||||
}
|
||||
return $sUrl;
|
||||
return static::$m_sAppRootUrl;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1396,13 +1424,23 @@ class utils
|
||||
return APPROOT . 'env-' . MetaModel::GetEnvironment() . '/';
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string A path to the folder into which data can be written
|
||||
* @internal
|
||||
* @since N°6097 2.7.10 3.0.4 3.1.1
|
||||
*/
|
||||
public static function GetDataPath(): string
|
||||
{
|
||||
return APPROOT.'data/';
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string A path to a folder into which any module can store cache data
|
||||
* The corresponding folder is created or cleaned upon code compilation
|
||||
*/
|
||||
public static function GetCachePath()
|
||||
{
|
||||
return APPROOT.'data/cache-'.MetaModel::GetEnvironment().'/';
|
||||
return static::GetDataPath().'cache-'.MetaModel::GetEnvironment().'/';
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1417,7 +1455,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
|
||||
@@ -2265,24 +2303,7 @@ SQL;
|
||||
*/
|
||||
public static function GetCurrentModuleName($iCallDepth = 0)
|
||||
{
|
||||
$sCurrentModuleName = '';
|
||||
$aCallStack = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS);
|
||||
$sCallerFile = realpath($aCallStack[$iCallDepth]['file']);
|
||||
|
||||
foreach(GetModulesInfo() as $sModuleName => $aInfo)
|
||||
{
|
||||
if ($aInfo['root_dir'] !== '')
|
||||
{
|
||||
$sRootDir = realpath(APPROOT.$aInfo['root_dir']);
|
||||
|
||||
if(substr($sCallerFile, 0, strlen($sRootDir)) === $sRootDir)
|
||||
{
|
||||
$sCurrentModuleName = $sModuleName;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return $sCurrentModuleName;
|
||||
return ModuleService::GetInstance()->GetCurrentModuleName($iCallDepth + 1);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2304,24 +2325,7 @@ SQL;
|
||||
*/
|
||||
public static function GetCurrentModuleDir($iCallDepth)
|
||||
{
|
||||
$sCurrentModuleDir = '';
|
||||
$aCallStack = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS);
|
||||
$sCallerFile = realpath($aCallStack[$iCallDepth]['file']);
|
||||
|
||||
foreach(GetModulesInfo() as $sModuleName => $aInfo)
|
||||
{
|
||||
if ($aInfo['root_dir'] !== '')
|
||||
{
|
||||
$sRootDir = realpath(APPROOT.$aInfo['root_dir']);
|
||||
|
||||
if(substr($sCallerFile, 0, strlen($sRootDir)) === $sRootDir)
|
||||
{
|
||||
$sCurrentModuleDir = basename($sRootDir);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return $sCurrentModuleDir;
|
||||
return ModuleService::GetInstance()->GetCurrentModuleDir($iCallDepth);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2336,12 +2340,7 @@ SQL;
|
||||
*/
|
||||
public static function GetCurrentModuleUrl()
|
||||
{
|
||||
$sDir = static::GetCurrentModuleDir(1);
|
||||
if ( $sDir !== '')
|
||||
{
|
||||
return static::GetAbsoluteUrlModulesRoot().'/'.$sDir;
|
||||
}
|
||||
return '';
|
||||
return ModuleService::GetInstance()->GetCurrentModuleUrl(1);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2351,8 +2350,7 @@ SQL;
|
||||
*/
|
||||
public static function GetCurrentModuleSetting($sProperty, $defaultvalue = null)
|
||||
{
|
||||
$sModuleName = static::GetCurrentModuleName(1);
|
||||
return MetaModel::GetModuleSetting($sModuleName, $sProperty, $defaultvalue);
|
||||
return ModuleService::GetInstance()->GetCurrentModuleSetting($sProperty, $defaultvalue);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2361,12 +2359,7 @@ SQL;
|
||||
*/
|
||||
public static function GetCompiledModuleVersion($sModuleName)
|
||||
{
|
||||
$aModulesInfo = GetModulesInfo();
|
||||
if (array_key_exists($sModuleName, $aModulesInfo))
|
||||
{
|
||||
return $aModulesInfo[$sModuleName]['version'];
|
||||
}
|
||||
return null;
|
||||
return ModuleService::GetInstance()->GetCompiledModuleVersion($sModuleName);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2508,15 +2501,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);
|
||||
@@ -2691,24 +2686,26 @@ SQL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the local path relative to the iTop installation of an existing file
|
||||
* Returns the local path relative to the iTop installation (APPROOT or the given base path)
|
||||
* Dir separator is changed to '/' for consistency among the different OS
|
||||
*
|
||||
* @param string $sAbsolutePath absolute path
|
||||
* @param string $sBasePath Base path for the resulting local path (default APPROOT)
|
||||
*
|
||||
* @return false|string
|
||||
* @return false|string The generated local path or false if absolute path is not under the base path
|
||||
* @since 3.1.1 Added base path defaulted to previous version APPROOT
|
||||
*/
|
||||
final public static function LocalPath($sAbsolutePath)
|
||||
final public static function LocalPath($sAbsolutePath, string $sBasePath = APPROOT)
|
||||
{
|
||||
$sRootPath = realpath(APPROOT);
|
||||
$sRootPath = realpath($sBasePath);
|
||||
$sFullPath = realpath($sAbsolutePath);
|
||||
if (($sFullPath === false) || !self::StartsWith($sFullPath, $sRootPath))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
$sLocalPath = substr($sFullPath, strlen($sRootPath.DIRECTORY_SEPARATOR));
|
||||
$sLocalPath = str_replace(DIRECTORY_SEPARATOR, '/', $sLocalPath);
|
||||
return $sLocalPath;
|
||||
|
||||
return str_replace(DIRECTORY_SEPARATOR, '/', $sLocalPath);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2900,7 +2897,7 @@ HTML;
|
||||
|
||||
// Add already loaded classes
|
||||
$aCurrentClasses = array_fill_keys(get_declared_classes(), '');
|
||||
$aClassMap = array_merge($aClassMap, $aCurrentClasses);
|
||||
$aClassMap = array_merge($aCurrentClasses, $aClassMap);
|
||||
|
||||
foreach ($aClassMap as $sPHPClass => $sPHPFile) {
|
||||
$bSkipped = false;
|
||||
@@ -2925,11 +2922,12 @@ HTML;
|
||||
$bSkipped = true; // file not found
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if(!$bSkipped){
|
||||
try {
|
||||
$oRefClass = new ReflectionClass($sPHPClass);
|
||||
if ($oRefClass->implementsInterface($sInterface) && $oRefClass->isInstantiable()) {
|
||||
if ($oRefClass->implementsInterface($sInterface) &&
|
||||
!$oRefClass->isInterface() && !$oRefClass->isAbstract() && !$oRefClass->isTrait()) {
|
||||
$aMatchingClasses[] = $sPHPClass;
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
@@ -2960,7 +2958,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();
|
||||
@@ -3035,6 +3033,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
|
||||
{
|
||||
@@ -3050,6 +3049,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
|
||||
{
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?php
|
||||
/**
|
||||
* @deprecated will be removed in 3.1.0 - moved to sources/Application/WebPage/WebPage.php, now loadable using autoloader
|
||||
* @deprecated 3.0.0 will be removed in 3.1.0 - moved to sources/Application/WebPage/WebPage.php, now loadable using autoloader
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
* @copyright Copyright (C) 2010-2023 Combodo SARL
|
||||
*/
|
||||
|
||||
@@ -24,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
|
||||
@@ -351,6 +353,7 @@ class WizardHelper
|
||||
/**
|
||||
* @return string JS code to be executed for fields update
|
||||
* @since 3.0.0 N°3198
|
||||
* @deprecated 3.0.3-2 3.0.4 3.1.1 3.2.0 Use {@see \WizardHelper::AddJsForUpdateFields()} instead
|
||||
*/
|
||||
public function GetJsForUpdateFields()
|
||||
{
|
||||
@@ -363,6 +366,32 @@ class WizardHelper
|
||||
JS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add necessary JS snippets (to the page) to be executed for fields update
|
||||
*
|
||||
* @param WebPage $oPage
|
||||
* @return void
|
||||
* @since 3.0.3-2 3.0.4 3.1.1 3.2.0 N°6766
|
||||
*/
|
||||
public function AddJsForUpdateFields(WebPage $oPage)
|
||||
{
|
||||
$sWizardHelperJsVar = (!is_null($this->m_aData['m_sWizHelperJsVarName'])) ? utils::Sanitize($this->m_aData['m_sWizHelperJsVarName'], '', utils::ENUM_SANITIZATION_FILTER_PARAMETER) : 'oWizardHelper'.$this->GetFormPrefix();
|
||||
$sWizardHelperJson = $this->ToJSON();
|
||||
|
||||
$oPage->add_script(<<<JS
|
||||
{$sWizardHelperJsVar}.m_oData = {$sWizardHelperJson};
|
||||
{$sWizardHelperJsVar}.UpdateFields();
|
||||
JS
|
||||
);
|
||||
$oPage->add_ready_script(<<<JS
|
||||
if ({$sWizardHelperJsVar}.m_oDependenciesUpdatedPromiseResolve !== null){
|
||||
{$sWizardHelperJsVar}.m_oDependenciesUpdatedPromiseResolve();
|
||||
}
|
||||
JS
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* Function with an old pattern of code
|
||||
* @deprecated 3.1.0
|
||||
@@ -371,11 +400,9 @@ JS;
|
||||
{
|
||||
$aSet = json_decode($sJsonSet, true); // true means hash array instead of object
|
||||
$oSet = CMDBObjectSet::FromScratch($sLinkClass);
|
||||
foreach ($aSet as $aLinkObj)
|
||||
{
|
||||
foreach ($aSet as $aLinkObj) {
|
||||
$oLink = MetaModel::NewObject($sLinkClass);
|
||||
foreach ($aLinkObj as $sAttCode => $value)
|
||||
{
|
||||
foreach ($aLinkObj as $sAttCode => $value) {
|
||||
$oAttDef = MetaModel::GetAttributeDef($sLinkClass, $sAttCode);
|
||||
if (($oAttDef->IsExternalKey()) && ($value != '') && ($value > 0))
|
||||
{
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?php
|
||||
/**
|
||||
* @deprecated will be removed in 3.1.0 - moved to sources/Application/WebPage/XMLPage.php, now loadable using autoloader
|
||||
* @deprecated 3.0.0 will be removed in 3.1.0 - moved to sources/Application/WebPage/XMLPage.php, now loadable using autoloader
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
* @copyright Copyright (C) 2010-2023 Combodo SARL
|
||||
*/
|
||||
|
||||
@@ -11,7 +11,7 @@ define('APPCONF', APPROOT.'conf/');
|
||||
*
|
||||
* @see ITOP_CORE_VERSION to get full iTop core version
|
||||
*/
|
||||
define('ITOP_DESIGN_LATEST_VERSION', '3.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';
|
||||
|
||||
@@ -45,6 +45,7 @@ define('MAINTENANCE_MODE_FILE', APPROOT.'data/.maintenance');
|
||||
define('READONLY_MODE_FILE', APPROOT.'data/.readonly');
|
||||
|
||||
$fItopStarted = microtime(true);
|
||||
$iItopInitialMemory = memory_get_usage(true);
|
||||
|
||||
if (!isset($GLOBALS['bBypassAutoload']) || $GLOBALS['bBypassAutoload'] == false) {
|
||||
require_once APPROOT.'/lib/autoload.php';
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
"type": "project",
|
||||
"license": "AGPL-3.0-only",
|
||||
"require": {
|
||||
"php": ">=7.4.0 <8.2.0",
|
||||
"php": ">=8.1.0 <8.2.0",
|
||||
"ext-ctype": "*",
|
||||
"ext-dom": "*",
|
||||
"ext-gd": "*",
|
||||
@@ -23,18 +23,24 @@
|
||||
"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.*",
|
||||
"symfony/console": "~6.4.0",
|
||||
"symfony/dotenv": "~6.4.0",
|
||||
"symfony/form": "~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/serializer": "^6.4",
|
||||
"symfony/twig-bundle": "~6.4.0",
|
||||
"symfony/validator": "~6.4.0",
|
||||
"symfony/var-dumper": "~6.4.0",
|
||||
"symfony/yaml": "~6.4.0",
|
||||
"thenetworg/oauth2-azure": "^2.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"symfony/stopwatch": "5.4.*",
|
||||
"symfony/web-profiler-bundle": "5.4.*"
|
||||
"symfony/stopwatch": "~6.4.0",
|
||||
"symfony/web-profiler-bundle": "~6.4.0",
|
||||
"symfony/debug-bundle": "~6.4.0"
|
||||
},
|
||||
"suggest": {
|
||||
"ext-libsodium": "Required to use the AttributeEncryptedString.",
|
||||
@@ -46,7 +52,7 @@
|
||||
},
|
||||
"config": {
|
||||
"platform": {
|
||||
"php": "7.4.0"
|
||||
"php": "8.1.0"
|
||||
},
|
||||
"vendor-dir": "lib",
|
||||
"preferred-install": {
|
||||
@@ -54,7 +60,10 @@
|
||||
},
|
||||
"sort-packages": true,
|
||||
"classmap-authoritative": true,
|
||||
"platform-check": true
|
||||
"platform-check": true,
|
||||
"allow-plugins": {
|
||||
"symfony/runtime": true
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"classmap": [
|
||||
@@ -72,6 +81,9 @@
|
||||
"application/logindefault.class.inc.php",
|
||||
"application/loginexternal.class.inc.php",
|
||||
"application/loginurl.class.inc.php"
|
||||
],
|
||||
"files": [
|
||||
"sources/alias.php"
|
||||
]
|
||||
},
|
||||
"conflict": {
|
||||
@@ -81,6 +93,9 @@
|
||||
"symfony": {
|
||||
"allow-contrib": false,
|
||||
"require": "3.4.*"
|
||||
},
|
||||
"runtime": {
|
||||
"dotenv_path": "symfony/.env"
|
||||
}
|
||||
},
|
||||
"scripts": {
|
||||
|
||||
2089
composer.lock
generated
2089
composer.lock
generated
File diff suppressed because it is too large
Load Diff
@@ -59,9 +59,17 @@ class DbConnectionWrapper
|
||||
* Use this to register a mock that will handle {@see mysqli::query()}
|
||||
*
|
||||
* @param \mysqli|null $oMysqli
|
||||
* @since 3.0.4 3.1.1 3.2.0 Param $oMysqli becomes nullable
|
||||
* @since 3.1.0-4 N°6848 backport of restoring cnx on null parameter value
|
||||
*/
|
||||
public static function SetDbConnectionMockForQuery(?mysqli $oMysqli): void
|
||||
public static function SetDbConnectionMockForQuery(?mysqli $oMysqli = null): void
|
||||
{
|
||||
static::$oDbCnxMockableForQuery = $oMysqli;
|
||||
if (is_null($oMysqli)) {
|
||||
// Reset to standard connection
|
||||
static::$oDbCnxMockableForQuery = static::$oDbCnxStandard;
|
||||
}
|
||||
else {
|
||||
static::$oDbCnxMockableForQuery = $oMysqli;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -419,6 +419,7 @@ class MyHelpers
|
||||
//}
|
||||
return $sOutput;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -523,5 +524,3 @@ class Str
|
||||
return (strtolower($sString) == $sString);
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
// along with iTop. If not, see <http://www.gnu.org/licenses/>
|
||||
|
||||
use Combodo\iTop\Application\TwigBase\Twig\TwigHelper;
|
||||
use Combodo\iTop\Application\WebPage\WebPage;
|
||||
|
||||
/**
|
||||
* Persistent classes (internal): user defined actions
|
||||
@@ -201,12 +202,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];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -273,7 +301,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())));
|
||||
|
||||
@@ -561,15 +588,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 +620,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)) {
|
||||
@@ -650,6 +667,9 @@ class ActionEmail extends ActionNotification
|
||||
$aMessageContent['subject'] = 'TEST['.$aMessageContent['subject'].']';
|
||||
$aMessageContent['body'] = $sTestBody;
|
||||
$aMessageContent['to'] = $this->Get('test_recipient');
|
||||
// N°6677 Ensure emails in test are never sent to cc'd and bcc'd addresses
|
||||
$aMessageContent['cc'] = '';
|
||||
$aMessageContent['bcc'] = '';
|
||||
}
|
||||
// Note: N°4849 We pass the "References" identifier instead of the "Message-ID" on purpose as we want notifications emails to group around the triggering iTop object, not just the users' replies to the notification
|
||||
$aMessageContent['in_reply_to'] = $aMessageContent['references'];
|
||||
|
||||
@@ -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;
|
||||
@@ -91,6 +92,12 @@ define('LINKSET_EDITMODE_ACTIONS', 2); // Show the usual 'Actions' popup menu
|
||||
define('LINKSET_EDITMODE_INPLACE', 3); // The "linked" objects can be created/modified/deleted in place
|
||||
define('LINKSET_EDITMODE_ADDREMOVE', 4); // The "linked" objects can be added/removed in place
|
||||
|
||||
define('LINKSET_EDITWHEN_NEVER', 0); // The linkset cannot be edited at all from inside this object
|
||||
define('LINKSET_EDITWHEN_ON_HOST_EDITION', 1); // The only possible action is to open a new window to create a new object
|
||||
define('LINKSET_EDITWHEN_ON_HOST_DISPLAY', 2); // Show the usual 'Actions' popup menu
|
||||
define('LINKSET_EDITWHEN_ALWAYS', 3); // Show the usual 'Actions' popup menu
|
||||
|
||||
|
||||
define('LINKSET_DISPLAY_STYLE_PROPERTY', 'property');
|
||||
define('LINKSET_DISPLAY_STYLE_TAB', 'tab');
|
||||
|
||||
@@ -791,7 +798,7 @@ abstract class AttributeDefinition
|
||||
public function HasAValue($proposedValue): bool
|
||||
{
|
||||
// Default implementation, we don't really know what type $proposedValue will be
|
||||
return is_null($proposedValue);
|
||||
return !(is_null($proposedValue));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1703,6 +1710,15 @@ class AttributeLinkedSet extends AttributeDefinition
|
||||
public function GetEditMode()
|
||||
{
|
||||
return $this->GetOptional('edit_mode', LINKSET_EDITMODE_ACTIONS);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int see LINKSET_EDITWHEN_* constants
|
||||
* @since 3.1.1 3.2.0 N°6385
|
||||
*/
|
||||
public function GetEditWhen(): int
|
||||
{
|
||||
return $this->GetOptional('edit_when', LINKSET_EDITWHEN_ALWAYS);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1724,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');
|
||||
@@ -8584,7 +8609,7 @@ class AttributeBlob extends AttributeDefinition
|
||||
public function RecordAttChange(DBObject $oObject, $original, $value): void
|
||||
{
|
||||
// N°6502 Don't record history if only the download count has changed
|
||||
if ($original->EqualsExceptDownloadsCount($value)) {
|
||||
if ((null !== $original) && (null !== $value) && $original->EqualsExceptDownloadsCount($value)) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -12972,7 +12997,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
|
||||
|
||||
|
||||
|
||||
@@ -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
|
||||
@@ -149,7 +152,9 @@ abstract class BulkExport
|
||||
$this->oSearch = null;
|
||||
$this->iChunkSize = 0;
|
||||
$this->sFormatCode = null;
|
||||
$this->aStatusInfo = array();
|
||||
$this->aStatusInfo = [
|
||||
'show_obsolete_data' => utils::ShowObsoleteData(),
|
||||
];
|
||||
$this->oBulkExportResult = null;
|
||||
$this->sTmpFile = '';
|
||||
$this->bLocalizeOutput = false;
|
||||
@@ -203,15 +208,17 @@ abstract class BulkExport
|
||||
if ($oInfo && ($oInfo->Get('user_id') == UserRights::GetUserId()))
|
||||
{
|
||||
$sFormatCode = $oInfo->Get('format');
|
||||
$oSearch = DBObjectSearch::unserialize($oInfo->Get('search'));
|
||||
$aStatusInfo = json_decode($oInfo->Get('status_info'),true);
|
||||
|
||||
$oSearch = DBObjectSearch::unserialize($oInfo->Get('search'));
|
||||
$oSearch->SetShowObsoleteData($aStatusInfo['show_obsolete_data']);
|
||||
$oBulkExporter = self::FindExporter($sFormatCode, $oSearch);
|
||||
if ($oBulkExporter)
|
||||
{
|
||||
$oBulkExporter->SetFormat($sFormatCode);
|
||||
$oBulkExporter->SetObjectList($oSearch);
|
||||
$oBulkExporter->SetChunkSize($oInfo->Get('chunk_size'));
|
||||
$oBulkExporter->SetStatusInfo(json_decode($oInfo->Get('status_info'), true));
|
||||
$oBulkExporter->SetStatusInfo($aStatusInfo);
|
||||
|
||||
$oBulkExporter->SetLocalizeOutput($oInfo->Get('localize_output'));
|
||||
|
||||
@@ -289,6 +296,7 @@ abstract class BulkExport
|
||||
*/
|
||||
public function SetObjectList(DBSearch $oSearch)
|
||||
{
|
||||
$oSearch->SetShowObsoleteData($this->aStatusInfo['show_obsolete_data']);
|
||||
$this->oSearch = $oSearch;
|
||||
}
|
||||
|
||||
@@ -386,7 +394,7 @@ abstract class BulkExport
|
||||
|
||||
|
||||
/**
|
||||
* @param \WebPage $oP
|
||||
* @param WebPage $oP
|
||||
* @param $sPartId
|
||||
*
|
||||
* @return UIContentBlock
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -431,6 +436,7 @@ class CMDBSource
|
||||
{
|
||||
self::$m_sDBName = '';
|
||||
}
|
||||
self::_TablesInfoCacheReset(); // reset the table info cache!
|
||||
}
|
||||
|
||||
public static function CreateTable($sQuery)
|
||||
@@ -607,8 +613,9 @@ class CMDBSource
|
||||
{
|
||||
self::LogDeadLock($e, true);
|
||||
throw new MySQLException('Failed to issue SQL query', array('query' => $sSql, $e));
|
||||
}
|
||||
$oKPI->ComputeStats('Query exec (mySQL)', $sSql);
|
||||
} finally {
|
||||
$oKPI->ComputeStats('Query exec (mySQL)', $sSql);
|
||||
}
|
||||
if ($oResult === false) {
|
||||
$aContext = array('query' => $sSql);
|
||||
|
||||
@@ -626,18 +633,24 @@ class CMDBSource
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \Exception $e
|
||||
* @param Exception $e
|
||||
* @param bool $bForQuery to get the proper DB connection
|
||||
* @param bool $bCheckMysqliErrno if false won't try to check for mysqli::errno value
|
||||
*
|
||||
* @since 2.7.1
|
||||
* @since 3.0.0 N°4325 add new optional parameter to use the correct DB connection
|
||||
* @since 3.0.4 3.1.1 3.2.0 N°6643 new bCheckMysqliErrno parameter as a workaround for mysqli::errno cannot be mocked
|
||||
*/
|
||||
private static function LogDeadLock(Exception $e, $bForQuery = false)
|
||||
private static function LogDeadLock(Exception $e, $bForQuery = false, $bCheckMysqliErrno = true)
|
||||
{
|
||||
// checks MySQL error code
|
||||
$iMySqlErrorNo = DbConnectionWrapper::GetDbConnection($bForQuery)->errno;
|
||||
if (!in_array($iMySqlErrorNo, array(self::MYSQL_ERRNO_WAIT_TIMEOUT, self::MYSQL_ERRNO_DEADLOCK))) {
|
||||
return;
|
||||
if ($bCheckMysqliErrno) {
|
||||
$iMySqlErrorNo = DbConnectionWrapper::GetDbConnection($bForQuery)->errno;
|
||||
if (!in_array($iMySqlErrorNo, array(self::MYSQL_ERRNO_WAIT_TIMEOUT, self::MYSQL_ERRNO_DEADLOCK))) {
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
$iMySqlErrorNo = "N/A";
|
||||
}
|
||||
|
||||
// Get error info
|
||||
@@ -664,7 +677,10 @@ class CMDBSource
|
||||
);
|
||||
DeadLockLog::Info($sMessage, $iMySqlErrorNo, $aLogContext);
|
||||
|
||||
IssueLog::Error($sMessage, LogChannels::DEADLOCK, $e->getMessage());
|
||||
IssueLog::Error($sMessage, LogChannels::DEADLOCK, [
|
||||
'exception.class' => get_class($e),
|
||||
'exception.message' => $e->getMessage(),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -923,7 +939,7 @@ class CMDBSource
|
||||
{
|
||||
throw new MySQLException('Failed to issue SQL query', array('query' => $sSql));
|
||||
}
|
||||
|
||||
|
||||
while ($aRow = $oResult->fetch_array($iMode))
|
||||
{
|
||||
$aData[] = $aRow;
|
||||
@@ -1077,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)
|
||||
@@ -1088,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)
|
||||
@@ -1355,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)
|
||||
@@ -1494,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))
|
||||
{
|
||||
@@ -1503,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
|
||||
@@ -1519,7 +1535,7 @@ class CMDBSource
|
||||
/**
|
||||
* Returns the privileges of the current user
|
||||
* @return string privileges in a raw format
|
||||
*/
|
||||
*/
|
||||
public static function GetRawPrivileges()
|
||||
{
|
||||
try
|
||||
@@ -1545,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.0-dev');
|
||||
define('ITOP_VERSION', '3.2.0-dev');
|
||||
|
||||
define('ITOP_VERSION_NAME', 'Fullmoon');
|
||||
define('ITOP_REVISION', 'svn');
|
||||
@@ -656,22 +656,22 @@ class Config
|
||||
'source_of_value' => '',
|
||||
'show_in_conf_sample' => false,
|
||||
],
|
||||
'email_transport_smtp.allow_self_signed' => array(
|
||||
'email_transport_smtp.allow_self_signed' => [
|
||||
'type' => 'bool',
|
||||
'description' => 'Allow self signed peer certificates',
|
||||
'default' => false,
|
||||
'value' => false,
|
||||
'source_of_value' => '',
|
||||
'show_in_conf_sample' => false,
|
||||
),
|
||||
'email_transport_smtp.verify_peer' => array(
|
||||
],
|
||||
'email_transport_smtp.verify_peer' => [
|
||||
'type' => 'bool',
|
||||
'description' => 'Verify peer certificate',
|
||||
'default' => true,
|
||||
'value' => true,
|
||||
'source_of_value' => '',
|
||||
'show_in_conf_sample' => false,
|
||||
),
|
||||
],
|
||||
'email_css' => [
|
||||
'type' => 'string',
|
||||
'description' => 'CSS that will override the standard stylesheet used for the notifications',
|
||||
@@ -889,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$',
|
||||
@@ -1069,6 +1077,14 @@ class Config
|
||||
'source_of_value' => '',
|
||||
'show_in_conf_sample' => false,
|
||||
],
|
||||
'log_kpi_generate_legacy_report' => [
|
||||
'type' => 'bool',
|
||||
'description' => 'Generate the legacy KPI report (kpi.html)',
|
||||
'default' => true,
|
||||
'value' => '',
|
||||
'source_of_value' => '',
|
||||
'show_in_conf_sample' => false,
|
||||
],
|
||||
'max_linkset_output' => [
|
||||
'type' => 'integer',
|
||||
'description' => 'Maximum number of items shown when getting a list of related items in an email, using the form $this->some_list$. 0 means no limit.',
|
||||
@@ -1185,6 +1201,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).',
|
||||
@@ -1563,6 +1603,22 @@ 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.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,
|
||||
],
|
||||
'regenerate_session_id_enabled' => [
|
||||
'type' => 'bool',
|
||||
'description' => 'If true then session id will be regenerated on each login, to prevent session fixation.',
|
||||
@@ -1611,6 +1667,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!',
|
||||
@@ -1675,6 +1739,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)
|
||||
@@ -1854,6 +1926,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.
|
||||
*
|
||||
@@ -1898,6 +1979,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();
|
||||
@@ -2058,6 +2140,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()
|
||||
@@ -2193,6 +2276,11 @@ class Config
|
||||
return $this->m_sEncryptionKey;
|
||||
}
|
||||
|
||||
public function GetAppSecret()
|
||||
{
|
||||
return $this->m_sAppSecret;
|
||||
}
|
||||
|
||||
public function GetEncryptionLibrary()
|
||||
{
|
||||
return $this->m_sEncryptionLibrary;
|
||||
@@ -2281,6 +2369,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;
|
||||
@@ -2291,6 +2397,12 @@ class Config
|
||||
$this->m_sEncryptionKey = $sKey;
|
||||
}
|
||||
|
||||
public function SetAppSecret($sKey)
|
||||
{
|
||||
$this->m_sAppSecret = $sKey;
|
||||
}
|
||||
|
||||
|
||||
public function SetCSVImportCharsets($aCharsets)
|
||||
{
|
||||
$this->m_aCharsets = $aCharsets;
|
||||
@@ -2342,6 +2454,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)
|
||||
{
|
||||
@@ -2454,7 +2567,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)
|
||||
{
|
||||
|
||||
@@ -1,8 +1,11 @@
|
||||
<?php
|
||||
/**
|
||||
* This file is only here for compatibility issues. Will be removed in iTop 3.1.0 (N°3664)
|
||||
* This file is only here for compatibility reasons.
|
||||
* It will be removed in future iTop versions (N°6533)
|
||||
*
|
||||
* @deprecated 3.0.0 N°3663 Exception classes were moved to `/application/exceptions`, use autoloader instead of require !
|
||||
*/
|
||||
require_once '../approot.inc.php';
|
||||
DeprecatedCallsLog::NotifyDeprecatedFile('Classes were moved to /application/exceptions');
|
||||
|
||||
require_once __DIR__ . '/../approot.inc.php';
|
||||
|
||||
DeprecatedCallsLog::NotifyDeprecatedFile('Classes were moved to /application/exceptions and can be used directly with the autoloader');
|
||||
|
||||
@@ -188,8 +188,8 @@ final class ItopCounter
|
||||
|
||||
if (!$hDBLink)
|
||||
{
|
||||
throw new Exception("Could not connect to the DB server (host=$sDBHost, user=$sDBUser): ".mysqli_connect_error().' (mysql errno: '.mysqli_connect_errno().')');
|
||||
}
|
||||
throw new MySQLException('Could not connect to the DB server '.mysqli_connect_error().' (mysql errno: '.mysqli_connect_errno(), array('host' => $sDBHost, 'user' => $sDBUser));
|
||||
}
|
||||
|
||||
return $hDBLink;
|
||||
}
|
||||
|
||||
@@ -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,268 @@
|
||||
<?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="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="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="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>null</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>
|
||||
</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);
|
||||
[$sPreviousLanguage, $aPreviousPluginProperties] = $this->SetNotificationLanguage();
|
||||
while ($oRecipient = $oRecipientsSet->Fetch()) {
|
||||
$oEvent = new EventiTopNotification();
|
||||
$oEvent->Set('title', MetaModel::ApplyParams($this->Get('title'), $aContextArgs));
|
||||
$oEvent->Set('message', MetaModel::ApplyParams($this->Get('message'), $aContextArgs));
|
||||
$oIcon = !$this->Get('icon')->IsEmpty() ? $this->Get('icon') : MetaModel::GetAttributeDef('EventiTopNotification', 'icon')->MakeRealValue(Combodo\iTop\Application\Branding::GetCompactMainLogoAbsoluteUrl(), $oEvent);
|
||||
$oEvent->Set('icon', $oIcon);
|
||||
$oEvent->Set('priority', $this->Get('priority'));
|
||||
$oEvent->Set('contact_id', $oRecipient->GetKey());
|
||||
$oEvent->Set('trigger_id', $oTrigger->GetKey());
|
||||
$oEvent->Set('action_id', $this->GetKey());
|
||||
$iObjectId = array_key_exists('this->object()', $aContextArgs) ? $aContextArgs['this->object()']->GetKey() : 0;
|
||||
$oEvent->Set('object_id', $iObjectId);
|
||||
$oEvent->Set('url', MetaModel::ApplyParams($this->Get('url'), $aContextArgs));
|
||||
$oEvent->DBInsertNoReload();
|
||||
}
|
||||
$this->SetNotificationLanguage($sPreviousLanguage, $aPreviousPluginProperties['language_code'] ?? null);
|
||||
}
|
||||
]]></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>null</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/>
|
||||
<methods/>
|
||||
</class>
|
||||
</classes>
|
||||
<user_rights>
|
||||
<profiles>
|
||||
<profile id="1024" _delta="define">
|
||||
@@ -219,6 +482,19 @@
|
||||
<field id="friendlyname" xsi:type="AttributeFriendlyName"/>
|
||||
</fields>
|
||||
</class>
|
||||
<class id="AuditDomain" _delta="define">
|
||||
<parent>cmdbAbstractObject</parent>
|
||||
<properties>
|
||||
<category>application, grant_by_profile</category>
|
||||
</properties>
|
||||
<fields>
|
||||
<field id="name" xsi:type="AttributeString"/>
|
||||
<field id="description" xsi:type="AttributeString"/>
|
||||
<field id="icon" xsi:type="AttributeImage"/>
|
||||
<field id="categories_list" xsi:type="AttributeLinkedSet"/>
|
||||
<field id="friendlyname" xsi:type="AttributeFriendlyName"/>
|
||||
</fields>
|
||||
</class>
|
||||
<class id="Query" _delta="define">
|
||||
<!-- Generated by toolkit/export-class-to-meta.php -->
|
||||
<parent>cmdbAbstractObject</parent>
|
||||
@@ -269,8 +545,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>
|
||||
@@ -489,6 +807,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
@@ -767,7 +767,10 @@ class DBObjectSet implements iDBObjectSetIterator
|
||||
|
||||
try
|
||||
{
|
||||
$oKPI = new ExecutionKPI();
|
||||
$this->m_oSQLResult = CMDBSource::Query($sSQL);
|
||||
$sOQL = $this->GetPseudoOQL($this->m_oFilter, $this->GetRealSortOrder(), $this->m_iLimitCount, $this->m_iLimitStart, false);
|
||||
$oKPI->ComputeStats('OQL Query Exec', $sOQL);
|
||||
} catch (MySQLException $e)
|
||||
{
|
||||
// 1116 = ER_TOO_MANY_TABLES
|
||||
@@ -847,8 +850,11 @@ class DBObjectSet implements iDBObjectSetIterator
|
||||
{
|
||||
if (is_null($this->m_iNumTotalDBRows))
|
||||
{
|
||||
$oKPI = new ExecutionKPI();
|
||||
$sSQL = $this->m_oFilter->MakeSelectQuery(array(), $this->m_aArgs, null, null, 0, 0, true);
|
||||
$resQuery = CMDBSource::Query($sSQL);
|
||||
$sOQL = $this->GetPseudoOQL($this->m_oFilter, array(), 0, 0, true);
|
||||
$oKPI->ComputeStats('OQL Query Exec', $sOQL);
|
||||
if (!$resQuery) return 0;
|
||||
|
||||
$aRow = CMDBSource::FetchArray($resQuery);
|
||||
@@ -859,6 +865,42 @@ class DBObjectSet implements iDBObjectSetIterator
|
||||
return $this->m_iNumTotalDBRows + count($this->m_aAddedObjects); // Does it fix Trac #887 ??
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \DBSearch $oFilter
|
||||
* @param array $aOrder
|
||||
* @param int $iLimitCount
|
||||
* @param int $iLimitStart
|
||||
* @param bool $bCount
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function GetPseudoOQL($oFilter, $aOrder, $iLimitCount, $iLimitStart, $bCount)
|
||||
{
|
||||
$sOQL = '';
|
||||
if ($bCount) {
|
||||
$sOQL .= 'COUNT ';
|
||||
}
|
||||
$sOQL .= $oFilter->ToOQL();
|
||||
|
||||
if ($iLimitCount > 0) {
|
||||
$sOQL .= ' LIMIT ';
|
||||
if ($iLimitStart > 0) {
|
||||
$sOQL .= "$iLimitStart, ";
|
||||
}
|
||||
$sOQL .= "$iLimitCount";
|
||||
}
|
||||
|
||||
if (count($aOrder) > 0) {
|
||||
$sOQL .= ' ORDER BY ';
|
||||
$aOrderBy = [];
|
||||
foreach ($aOrder as $sAttCode => $bAsc) {
|
||||
$aOrderBy[] = $sAttCode.' '.($bAsc ? 'ASC' : 'DESC');
|
||||
}
|
||||
$sOQL .= implode(', ', $aOrderBy);
|
||||
}
|
||||
return $sOQL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the count exceeds a given limit
|
||||
*
|
||||
@@ -875,8 +917,11 @@ class DBObjectSet implements iDBObjectSetIterator
|
||||
{
|
||||
if (is_null($this->m_iNumTotalDBRows))
|
||||
{
|
||||
$oKPI = new ExecutionKPI();
|
||||
$sSQL = $this->m_oFilter->MakeSelectQuery(array(), $this->m_aArgs, null, null, $iLimit + 2, 0, true);
|
||||
$resQuery = CMDBSource::Query($sSQL);
|
||||
$sOQL = $this->GetPseudoOQL($this->m_oFilter, array(), $iLimit + 2, 0, true);
|
||||
$oKPI->ComputeStats('OQL Query Exec', $sOQL);
|
||||
if ($resQuery)
|
||||
{
|
||||
$aRow = CMDBSource::FetchArray($resQuery);
|
||||
@@ -887,7 +932,7 @@ class DBObjectSet implements iDBObjectSetIterator
|
||||
{
|
||||
$iCount = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$iCount = $this->m_iNumTotalDBRows;
|
||||
@@ -912,8 +957,11 @@ class DBObjectSet implements iDBObjectSetIterator
|
||||
{
|
||||
if (is_null($this->m_iNumTotalDBRows))
|
||||
{
|
||||
$oKPI = new ExecutionKPI();
|
||||
$sSQL = $this->m_oFilter->MakeSelectQuery(array(), $this->m_aArgs, null, null, $iLimit + 2, 0, true);
|
||||
$resQuery = CMDBSource::Query($sSQL);
|
||||
$sOQL = $this->GetPseudoOQL($this->m_oFilter, array(), $iLimit + 2, 0, true);
|
||||
$oKPI->ComputeStats('OQL Query Exec', $sOQL);
|
||||
if ($resQuery)
|
||||
{
|
||||
$aRow = CMDBSource::FetchArray($resQuery);
|
||||
@@ -924,7 +972,7 @@ class DBObjectSet implements iDBObjectSetIterator
|
||||
{
|
||||
$iCount = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$iCount = $this->m_iNumTotalDBRows;
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
//
|
||||
// This file is part of iTop.
|
||||
//
|
||||
// iTop is free software; you can redistribute it and/or modify
|
||||
// iTop is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
@@ -56,10 +56,11 @@ class Dict
|
||||
* @param $sLanguageCode
|
||||
*
|
||||
* @throws \DictExceptionUnknownLanguage
|
||||
* @since 3.0.4 3.1.1 3.2.0 Param $sLanguageCode becomes nullable
|
||||
*/
|
||||
public static function SetUserLanguage($sLanguageCode)
|
||||
public static function SetUserLanguage($sLanguageCode = null)
|
||||
{
|
||||
if (!array_key_exists($sLanguageCode, self::$m_aLanguages))
|
||||
if (!is_null($sLanguageCode) && !array_key_exists($sLanguageCode, self::$m_aLanguages))
|
||||
{
|
||||
throw new DictExceptionUnknownLanguage($sLanguageCode);
|
||||
}
|
||||
@@ -115,33 +116,50 @@ class Dict
|
||||
* @return string
|
||||
*/
|
||||
public static function S($sStringCode, $sDefault = null, $bUserLanguageOnly = false)
|
||||
{
|
||||
$aInfo = self::GetLabelAndLangCode($sStringCode, $sDefault, $bUserLanguageOnly);
|
||||
return $aInfo['label'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a localised string from the dictonary with its associated lang code
|
||||
*
|
||||
* @param string $sStringCode The code identifying the dictionary entry
|
||||
* @param string $sDefault Default value if there is no match in the dictionary
|
||||
* @param bool $bUserLanguageOnly True to allow the use of the default language as a fallback, false otherwise
|
||||
*
|
||||
* @return array{
|
||||
* lang: string, label: string
|
||||
* } with localized label string and used lang code
|
||||
*/
|
||||
private static function GetLabelAndLangCode($sStringCode, $sDefault = null, $bUserLanguageOnly = false)
|
||||
{
|
||||
// Attempt to find the string in the user language
|
||||
//
|
||||
$sLangCode = self::GetUserLanguage();
|
||||
self::InitLangIfNeeded($sLangCode);
|
||||
|
||||
if (!array_key_exists($sLangCode, self::$m_aData))
|
||||
if (! array_key_exists($sLangCode, self::$m_aData))
|
||||
{
|
||||
IssueLog::Warning("Cannot find $sLangCode in dictionnaries. default labels displayed");
|
||||
IssueLog::Warning("Cannot find $sLangCode in all registered dictionaries.");
|
||||
// It may happen, when something happens before the dictionaries get loaded
|
||||
return $sStringCode;
|
||||
return [ 'label' => $sStringCode, 'lang' => $sLangCode ];
|
||||
}
|
||||
$aCurrentDictionary = self::$m_aData[$sLangCode];
|
||||
if (is_array($aCurrentDictionary) && array_key_exists($sStringCode, $aCurrentDictionary))
|
||||
{
|
||||
return $aCurrentDictionary[$sStringCode];
|
||||
return [ 'label' => $aCurrentDictionary[$sStringCode], 'lang' => $sLangCode ];
|
||||
}
|
||||
if (!$bUserLanguageOnly)
|
||||
{
|
||||
// Attempt to find the string in the default language
|
||||
//
|
||||
self::InitLangIfNeeded(self::$m_sDefaultLanguage);
|
||||
|
||||
|
||||
$aDefaultDictionary = self::$m_aData[self::$m_sDefaultLanguage];
|
||||
if (is_array($aDefaultDictionary) && array_key_exists($sStringCode, $aDefaultDictionary))
|
||||
{
|
||||
return $aDefaultDictionary[$sStringCode];
|
||||
return [ 'label' => $aDefaultDictionary[$sStringCode], 'lang' => self::$m_sDefaultLanguage ];
|
||||
}
|
||||
// Attempt to find the string in english
|
||||
//
|
||||
@@ -150,17 +168,17 @@ class Dict
|
||||
$aDefaultDictionary = self::$m_aData['EN US'];
|
||||
if (is_array($aDefaultDictionary) && array_key_exists($sStringCode, $aDefaultDictionary))
|
||||
{
|
||||
return $aDefaultDictionary[$sStringCode];
|
||||
return [ 'label' => $aDefaultDictionary[$sStringCode], 'lang' => 'EN US' ];
|
||||
}
|
||||
}
|
||||
// Could not find the string...
|
||||
//
|
||||
if (is_null($sDefault))
|
||||
{
|
||||
return $sStringCode;
|
||||
return [ 'label' => $sStringCode, 'lang' => null ];
|
||||
}
|
||||
|
||||
return $sDefault;
|
||||
return [ 'label' => $sDefault, 'lang' => null ];
|
||||
}
|
||||
|
||||
|
||||
@@ -176,19 +194,25 @@ class Dict
|
||||
*/
|
||||
public static function Format($sFormatCode /*, ... arguments ... */)
|
||||
{
|
||||
$sLocalizedFormat = self::S($sFormatCode);
|
||||
['label' => $sLocalizedFormat, 'lang' => $sLangCode] = self::GetLabelAndLangCode($sFormatCode);
|
||||
|
||||
$aArguments = func_get_args();
|
||||
array_shift($aArguments);
|
||||
|
||||
|
||||
if ($sLocalizedFormat == $sFormatCode)
|
||||
{
|
||||
// Make sure the information will be displayed (ex: an error occuring before the dictionary gets loaded)
|
||||
return $sFormatCode.' - '.implode(', ', $aArguments);
|
||||
}
|
||||
|
||||
return vsprintf($sLocalizedFormat, $aArguments);
|
||||
try{
|
||||
return vsprintf($sLocalizedFormat, $aArguments);
|
||||
} catch(\Throwable $e){
|
||||
\IssueLog::Error("Cannot format dict key", null, ["sFormatCode" => $sFormatCode, "sLangCode" => $sLangCode, 'exception_msg' => $e->getMessage() ]);
|
||||
return $sFormatCode.' - '.implode(', ', $aArguments);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Initialize a the entries for a given language (replaces the former Add() method)
|
||||
* @param string $sLanguageCode Code identifying the language i.e. 'FR-FR', 'EN-US'
|
||||
@@ -198,7 +222,7 @@ class Dict
|
||||
{
|
||||
self::$m_aData[$sLanguageCode] = $aEntries;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set the list of available languages
|
||||
* @param hash $aLanguagesList
|
||||
@@ -259,7 +283,7 @@ class Dict
|
||||
{
|
||||
$sDictFile = APPROOT.'env-'.utils::GetCurrentEnvironment().'/dictionaries/'.str_replace(' ', '-', strtolower($sLangCode)).'.dict.php';
|
||||
require_once($sDictFile);
|
||||
|
||||
|
||||
if (self::GetApcService()->function_exists('apc_store')
|
||||
&& (self::$m_sApplicationPrefix !== null))
|
||||
{
|
||||
@@ -269,7 +293,7 @@ class Dict
|
||||
}
|
||||
return $bResult;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Enable caching (cached using APC)
|
||||
* @param string $sApplicationPrefix The prefix for uniquely identiying this iTop instance
|
||||
@@ -312,14 +336,14 @@ class Dict
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static function MakeStats($sLanguageCode, $sLanguageRef = 'EN US')
|
||||
{
|
||||
$aMissing = array(); // Strings missing for the target language
|
||||
$aUnexpected = array(); // Strings defined for the target language, but not found in the reference dictionary
|
||||
$aNotTranslated = array(); // Strings having the same value in both dictionaries
|
||||
$aOK = array(); // Strings having different values in both dictionaries
|
||||
|
||||
|
||||
foreach (self::$m_aData[$sLanguageRef] as $sStringCode => $sValue)
|
||||
{
|
||||
if (!array_key_exists($sStringCode, self::$m_aData[$sLanguageCode]))
|
||||
@@ -327,7 +351,7 @@ class Dict
|
||||
$aMissing[$sStringCode] = $sValue;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
foreach (self::$m_aData[$sLanguageCode] as $sStringCode => $sValue)
|
||||
{
|
||||
if (!array_key_exists($sStringCode, self::$m_aData[$sLanguageRef]))
|
||||
@@ -350,7 +374,7 @@ class Dict
|
||||
}
|
||||
return array($aMissing, $aUnexpected, $aNotTranslated, $aOK);
|
||||
}
|
||||
|
||||
|
||||
public static function Dump()
|
||||
{
|
||||
MyHelpers::var_dump_html(self::$m_aData);
|
||||
@@ -373,7 +397,7 @@ class Dict
|
||||
// No need to actually load the strings since it's only used to know the list of languages
|
||||
// at setup time !!
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Export all the dictionary entries - of the given language - whose code matches the given prefix
|
||||
* missing entries in the current language will be replaced by entries in the default language
|
||||
@@ -386,7 +410,7 @@ class Dict
|
||||
self::InitLangIfNeeded(self::$m_sDefaultLanguage);
|
||||
$aEntries = array();
|
||||
$iLength = strlen($sStartingWith);
|
||||
|
||||
|
||||
// First prefill the array with entries from the default language
|
||||
foreach(self::$m_aData[self::$m_sDefaultLanguage] as $sCode => $sEntry)
|
||||
{
|
||||
@@ -395,7 +419,7 @@ class Dict
|
||||
$aEntries[$sCode] = $sEntry;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Now put (overwrite) the entries for the user language
|
||||
foreach(self::$m_aData[self::GetUserLanguage()] as $sCode => $sEntry)
|
||||
{
|
||||
|
||||
@@ -16,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;
|
||||
|
||||
/**
|
||||
@@ -59,7 +65,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 +494,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 +1418,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 +1433,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 +1546,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 +1583,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 +1594,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 +1675,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
|
||||
|
||||
@@ -1,27 +1,15 @@
|
||||
<?php
|
||||
// Copyright (C) 2010-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
|
||||
// along with iTop. If not, see <http://www.gnu.org/licenses/>
|
||||
/**
|
||||
* @copyright Copyright (C) 2010-2023 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
use Combodo\iTop\Core\Kpi\KpiLogData;
|
||||
use Combodo\iTop\Service\Module\ModuleService;
|
||||
|
||||
|
||||
/**
|
||||
* Measures operations duration, memory usage, etc. (and some other KPIs)
|
||||
*
|
||||
* @copyright Copyright (C) 2010-2023 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
class ExecutionKPI
|
||||
@@ -30,6 +18,8 @@ class ExecutionKPI
|
||||
static protected $m_bEnabled_Memory = false;
|
||||
static protected $m_bBlameCaller = false;
|
||||
static protected $m_sAllowedUser = '*';
|
||||
static protected $m_bGenerateLegacyReport = true;
|
||||
static protected $m_fSlowQueries = 0;
|
||||
|
||||
static protected $m_aStats = []; // Recurrent operations
|
||||
static protected $m_aExecData = []; // One shot operations
|
||||
@@ -86,14 +76,39 @@ class ExecutionKPI
|
||||
return false;
|
||||
}
|
||||
|
||||
static public function SetGenerateLegacyReport($bReportExtensionsOnly)
|
||||
{
|
||||
self::$m_bGenerateLegacyReport = $bReportExtensionsOnly;
|
||||
}
|
||||
|
||||
static public function SetSlowQueries($fSlowQueries)
|
||||
{
|
||||
self::$m_fSlowQueries = $fSlowQueries;
|
||||
}
|
||||
|
||||
static public function GetDescription()
|
||||
{
|
||||
$aFeatures = array();
|
||||
if (self::$m_bEnabled_Duration) $aFeatures[] = 'Duration';
|
||||
if (self::$m_bEnabled_Memory) $aFeatures[] = 'Memory usage';
|
||||
$sFeatures = implode(', ', $aFeatures);
|
||||
$sFeatures = 'Measures: '.implode(', ', $aFeatures);
|
||||
$sFor = self::$m_sAllowedUser == '*' ? 'EVERYBODY' : "'".trim(self::$m_sAllowedUser)."'";
|
||||
return "KPI logging is active for $sFor. Measures: $sFeatures";
|
||||
$sSlowQueries = '';
|
||||
if (self::$m_fSlowQueries > 0) {
|
||||
$sSlowQueries = ". Slow Queries: ".self::$m_fSlowQueries."s";
|
||||
}
|
||||
|
||||
$aExtensions = [];
|
||||
/** @var \iKPILoggerExtension $oExtensionInstance */
|
||||
foreach (MetaModel::EnumPlugins('iKPILoggerExtension') as $oExtensionInstance) {
|
||||
$aExtensions[] = ModuleService::GetInstance()->GetModuleNameFromObject($oExtensionInstance);
|
||||
}
|
||||
$sExtensions = '';
|
||||
if (count($aExtensions) > 0) {
|
||||
$sExtensions = '. KPI Extensions: ['.implode(', ', $aExtensions).']';
|
||||
}
|
||||
|
||||
return "KPI logging is active for $sFor. $sFeatures$sSlowQueries$sExtensions";
|
||||
}
|
||||
|
||||
static public function ReportStats()
|
||||
@@ -101,7 +116,28 @@ class ExecutionKPI
|
||||
if (!self::IsEnabled()) return;
|
||||
|
||||
global $fItopStarted;
|
||||
global $iItopInitialMemory;
|
||||
$sExecId = microtime(); // id to differentiate the hrefs!
|
||||
$sRequest = $_SERVER['REQUEST_URI'].' ('.$_SERVER['REQUEST_METHOD'].')';
|
||||
if (isset($_POST['operation'])) {
|
||||
$sRequest .= ' operation: '.$_POST['operation'];
|
||||
}
|
||||
|
||||
$fStop = MyHelpers::getmicrotime();
|
||||
if (($fStop - $fItopStarted) > self::$m_fSlowQueries) {
|
||||
// Invoke extensions to log the KPI operation
|
||||
/** @var \iKPILoggerExtension $oExtensionInstance */
|
||||
$iCurrentMemory = self::memory_get_usage();
|
||||
$iPeakMemory = self::memory_get_peak_usage();
|
||||
foreach (MetaModel::EnumPlugins('iKPILoggerExtension') as $oExtensionInstance) {
|
||||
$oKPILogData = new KpiLogData(KpiLogData::TYPE_REQUEST, 'Page', $sRequest, $fItopStarted, $fStop, '', $iItopInitialMemory, $iCurrentMemory, $iPeakMemory);
|
||||
$oExtensionInstance->LogOperation($oKPILogData);
|
||||
}
|
||||
}
|
||||
|
||||
if (!self::$m_bGenerateLegacyReport) {
|
||||
return;
|
||||
}
|
||||
|
||||
$aBeginTimes = array();
|
||||
foreach (self::$m_aExecData as $aOpStats)
|
||||
@@ -114,9 +150,9 @@ class ExecutionKPI
|
||||
|
||||
$sHtml = "<hr/>";
|
||||
$sHtml .= "<div style=\"background-color: grey; padding: 10px;\">";
|
||||
$sHtml .= "<h3><a name=\"".md5($sExecId)."\">KPIs</a> - ".$_SERVER['REQUEST_URI']." (".$_SERVER['REQUEST_METHOD'].")</h3>";
|
||||
$sHtml .= "<h3><a name=\"".md5($sExecId)."\">KPIs</a> - $sRequest</h3>";
|
||||
$oStarted = DateTime::createFromFormat('U.u', $fItopStarted);
|
||||
$sHtml .= "<p>".$oStarted->format('Y-m-d H:i:s.u')."</p>";
|
||||
$sHtml .= '<p>'.$oStarted->format('Y-m-d H:i:s.u').'</p>';
|
||||
$sHtml .= "<p>log_kpi_user_id: ".UserRights::GetUserId()."</p>";
|
||||
$sHtml .= "<div>";
|
||||
$sHtml .= "<table border=\"1\" style=\"$sTableStyle\">";
|
||||
@@ -257,7 +293,7 @@ class ExecutionKPI
|
||||
$sTotalInter = round($fTotalInter, 3);
|
||||
$sMinInter = round($fMinInter, 3);
|
||||
$sMaxInter = round($fMaxInter, 3);
|
||||
if (($fTotalInter >= $fSlowQueries))
|
||||
if (($fTotalInter >= self::$m_fSlowQueries))
|
||||
{
|
||||
if ($bDisplayHeader)
|
||||
{
|
||||
@@ -285,37 +321,19 @@ class ExecutionKPI
|
||||
self::Report($sHtml);
|
||||
}
|
||||
|
||||
public static function InitStats()
|
||||
{
|
||||
// Invoke extensions to initialize the KPI statistics
|
||||
/** @var \iKPILoggerExtension $oExtensionInstance */
|
||||
foreach (MetaModel::EnumPlugins('iKPILoggerExtension') as $oExtensionInstance) {
|
||||
$oExtensionInstance->InitStats();
|
||||
}
|
||||
}
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->ResetCounters();
|
||||
self::Push($this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Stack executions to remove children duration from stats
|
||||
*
|
||||
* @param \ExecutionKPI $oExecutionKPI
|
||||
*/
|
||||
private static function Push(ExecutionKPI $oExecutionKPI)
|
||||
{
|
||||
self::$m_aExecutionStack[] = $oExecutionKPI;
|
||||
}
|
||||
|
||||
/**
|
||||
* Pop current child and count its duration in its parent
|
||||
*
|
||||
* @param float|int $fChildDuration
|
||||
*/
|
||||
private static function Pop(float $fChildDuration = 0)
|
||||
{
|
||||
array_pop(self::$m_aExecutionStack);
|
||||
// Update the parent's children duration
|
||||
$oPrevExecutionKPI = end(self::$m_aExecutionStack);
|
||||
if ($oPrevExecutionKPI) {
|
||||
$oPrevExecutionKPI->m_fChildrenDuration += $fChildDuration;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Get the duration since startup, and reset the counter for the next measure
|
||||
//
|
||||
@@ -323,9 +341,15 @@ class ExecutionKPI
|
||||
{
|
||||
global $fItopStarted;
|
||||
|
||||
if (!self::IsEnabled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
$aNewEntry = null;
|
||||
|
||||
if (self::$m_bEnabled_Duration) {
|
||||
$fStarted = $this->m_fStarted;
|
||||
$fStopped = $this->m_fStarted;
|
||||
if (self::$m_bEnabled_Duration) {
|
||||
$fStopped = MyHelpers::getmicrotime();
|
||||
$aNewEntry = array(
|
||||
'op' => $sOperationDesc,
|
||||
@@ -336,6 +360,9 @@ class ExecutionKPI
|
||||
$this->m_fStarted = $fStopped;
|
||||
}
|
||||
|
||||
$iInitialMemory = is_null($this->m_iInitialMemory) ? 0 : $this->m_iInitialMemory;
|
||||
$iCurrentMemory = 0;
|
||||
$iPeakMemory = 0;
|
||||
if (self::$m_bEnabled_Memory)
|
||||
{
|
||||
$iCurrentMemory = self::memory_get_usage();
|
||||
@@ -345,40 +372,118 @@ class ExecutionKPI
|
||||
}
|
||||
$aNewEntry['mem_begin'] = $this->m_iInitialMemory;
|
||||
$aNewEntry['mem_end'] = $iCurrentMemory;
|
||||
if (function_exists('memory_get_peak_usage'))
|
||||
{
|
||||
$aNewEntry['mem_peak'] = memory_get_peak_usage();
|
||||
}
|
||||
$iPeakMemory = self::memory_get_peak_usage();
|
||||
$aNewEntry['mem_peak'] = $iPeakMemory;
|
||||
// Reset for the next operation (if the object is recycled)
|
||||
$this->m_iInitialMemory = $iCurrentMemory;
|
||||
}
|
||||
|
||||
if (!is_null($aNewEntry))
|
||||
if (self::$m_bEnabled_Duration || self::$m_bEnabled_Memory) {
|
||||
// Invoke extensions to log the KPI operation
|
||||
/** @var \iKPILoggerExtension $oExtensionInstance */
|
||||
foreach(MetaModel::EnumPlugins('iKPILoggerExtension') as $oExtensionInstance)
|
||||
{
|
||||
$sExtension = ModuleService::GetInstance()->GetModuleNameFromCallStack(1);
|
||||
$oKPILogData = new KpiLogData(
|
||||
KpiLogData::TYPE_REPORT,
|
||||
'Step',
|
||||
$sOperationDesc,
|
||||
$fStarted,
|
||||
$fStopped,
|
||||
$sExtension,
|
||||
$iInitialMemory,
|
||||
$iCurrentMemory,
|
||||
$iPeakMemory);
|
||||
$oExtensionInstance->LogOperation($oKPILogData);
|
||||
}
|
||||
}
|
||||
|
||||
if (!is_null($aNewEntry) && self::$m_bGenerateLegacyReport)
|
||||
{
|
||||
self::$m_aExecData[] = $aNewEntry;
|
||||
}
|
||||
$this->ResetCounters();
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute statistics for a call to an extension
|
||||
* Note: not working in dev mode (with links to env-production)
|
||||
*
|
||||
* @param object|string $object object called
|
||||
* @param string $sMethod method called on the object
|
||||
* @param string $sMessage additional message
|
||||
*
|
||||
* @return bool true if an extension was found for this object::method
|
||||
* @throws \ReflectionException
|
||||
*/
|
||||
public function ComputeStatsForExtension($object, string $sMethod, string $sMessage = ''): bool
|
||||
{
|
||||
if (!self::IsEnabled()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
$sSignature = ModuleService::GetInstance()->GetModuleMethodSignature($object, $sMethod);
|
||||
if (utils::StartsWith($sSignature, '[')) {
|
||||
$this->ComputeStats('Extension', "$sSignature $sMessage");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public function ComputeStats($sOperation, $sArguments)
|
||||
{
|
||||
if (!self::IsEnabled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
$fDuration = 0;
|
||||
if (self::$m_bEnabled_Duration) {
|
||||
$fStopped = MyHelpers::getmicrotime();
|
||||
$fDuration = $fStopped - $this->m_fStarted;
|
||||
$fSelfDuration = $fDuration - $this->m_fChildrenDuration;
|
||||
if (self::$m_bBlameCaller) {
|
||||
self::$m_aStats[$sOperation][$sArguments][] = array(
|
||||
'time' => $fSelfDuration,
|
||||
'callers' => MyHelpers::get_callstack(1),
|
||||
);
|
||||
} else {
|
||||
self::$m_aStats[$sOperation][$sArguments][] = array(
|
||||
'time' => $fSelfDuration,
|
||||
);
|
||||
}
|
||||
}
|
||||
self::Pop($fDuration);
|
||||
$aCallstack = [];
|
||||
if (self::$m_bGenerateLegacyReport) {
|
||||
if (self::$m_bBlameCaller) {
|
||||
$aCallstack = MyHelpers::get_callstack(1);
|
||||
self::$m_aStats[$sOperation][$sArguments][] = [
|
||||
'time' => $fDuration,
|
||||
'callers' => $aCallstack,
|
||||
];
|
||||
} else {
|
||||
self::$m_aStats[$sOperation][$sArguments][] = [
|
||||
'time' => $fDuration
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
$iInitialMemory = is_null($this->m_iInitialMemory) ? 0 : $this->m_iInitialMemory;
|
||||
$iCurrentMemory = 0;
|
||||
$iPeakMemory = 0;
|
||||
if (self::$m_bEnabled_Memory)
|
||||
{
|
||||
$iCurrentMemory = self::memory_get_usage();
|
||||
$iPeakMemory = self::memory_get_peak_usage();
|
||||
}
|
||||
|
||||
// Invoke extensions to log the KPI operation
|
||||
/** @var \iKPILoggerExtension $oExtensionInstance */
|
||||
foreach (MetaModel::EnumPlugins('iKPILoggerExtension') as $oExtensionInstance) {
|
||||
$sExtension = ModuleService::GetInstance()->GetModuleNameFromCallStack(1);
|
||||
$oKPILogData = new KpiLogData(
|
||||
KpiLogData::TYPE_STATS,
|
||||
$sOperation,
|
||||
$sArguments,
|
||||
$this->m_fStarted,
|
||||
$fStopped,
|
||||
$sExtension,
|
||||
$iInitialMemory,
|
||||
$iCurrentMemory,
|
||||
$iPeakMemory,
|
||||
$aCallstack);
|
||||
$oExtensionInstance->LogOperation($oKPILogData);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected function ResetCounters()
|
||||
@@ -408,35 +513,7 @@ class ExecutionKPI
|
||||
|
||||
static protected function memory_get_usage()
|
||||
{
|
||||
if (function_exists('memory_get_usage'))
|
||||
{
|
||||
return memory_get_usage(true);
|
||||
}
|
||||
|
||||
// Copied from the PHP manual
|
||||
//
|
||||
//If its Windows
|
||||
//Tested on Win XP Pro SP2. Should work on Win 2003 Server too
|
||||
//Doesn't work for 2000
|
||||
//If you need it to work for 2000 look at http://us2.php.net/manual/en/function.memory-get-usage.php#54642
|
||||
if (substr(PHP_OS,0,3) == 'WIN')
|
||||
{
|
||||
$output = array();
|
||||
exec('tasklist /FI "PID eq ' . getmypid() . '" /FO LIST', $output);
|
||||
|
||||
return preg_replace( '/[\D]/', '', $output[5] ) * 1024;
|
||||
}
|
||||
else
|
||||
{
|
||||
//We now assume the OS is UNIX
|
||||
//Tested on Mac OS X 10.4.6 and Linux Red Hat Enterprise 4
|
||||
//This should work on most UNIX systems
|
||||
$pid = getmypid();
|
||||
exec("ps -eo%mem,rss,pid | grep $pid", $output);
|
||||
$output = explode(" ", $output[0]);
|
||||
//rss is given in 1024 byte units
|
||||
return $output[1] * 1024;
|
||||
}
|
||||
return memory_get_usage(true);
|
||||
}
|
||||
|
||||
static public function memory_get_peak_usage($bRealUsage = false)
|
||||
|
||||
@@ -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
|
||||
@@ -1138,9 +1143,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);
|
||||
}
|
||||
}
|
||||
@@ -1671,6 +1680,8 @@ class ExceptionLog extends LogAPI
|
||||
*/
|
||||
private static function GetLastEventIssue()
|
||||
{
|
||||
return self::$oLastEventIssue;
|
||||
$oRet = self::$oLastEventIssue;
|
||||
self::$oLastEventIssue = null;
|
||||
return $oRet;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1241,7 +1241,7 @@ abstract class MetaModel
|
||||
}
|
||||
$sTable = self::DBGetTable($sClass);
|
||||
|
||||
// Could be completed later with all the classes that are using a given table
|
||||
// Could be completed later with all the classes that are using a given table
|
||||
if (!array_key_exists($sTable, $aTables)) {
|
||||
$aTables[$sTable] = array();
|
||||
}
|
||||
@@ -1445,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)
|
||||
{
|
||||
@@ -3522,7 +3526,7 @@ abstract class MetaModel
|
||||
}
|
||||
|
||||
// Set the "host class" as soon as possible, since HierarchicalKeys use it for their 'target class' as well
|
||||
// and this needs to be know early (for Init_IsKnowClass 19 lines below)
|
||||
// and this needs to be know early (for Init_IsKnowClass 19 lines below)
|
||||
$oAtt->SetHostClass($sTargetClass);
|
||||
|
||||
// Some attributes could refer to a class
|
||||
@@ -3564,7 +3568,7 @@ abstract class MetaModel
|
||||
|
||||
self::$m_aAttribDefs[$sTargetClass][$oAtt->GetCode()] = $oAtt;
|
||||
self::$m_aAttribOrigins[$sTargetClass][$oAtt->GetCode()] = $sTargetClass;
|
||||
// Note: it looks redundant to put targetclass there, but a mix occurs when inheritance is used
|
||||
// Note: it looks redundant to put targetclass there, but a mix occurs when inheritance is used
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -3764,7 +3768,7 @@ abstract class MetaModel
|
||||
self::$m_aStimuli[$sTargetClass][$oStimulus->GetCode()] = $oStimulus;
|
||||
|
||||
// I wanted to simplify the syntax of the declaration of objects in the biz model
|
||||
// Therefore, the reference to the host class is set there
|
||||
// Therefore, the reference to the host class is set there
|
||||
$oStimulus->SetHostClass($sTargetClass);
|
||||
}
|
||||
|
||||
@@ -4219,40 +4223,78 @@ abstract class MetaModel
|
||||
}
|
||||
else
|
||||
{
|
||||
$aCurrentUser = array();
|
||||
$aCurrentContact = array();
|
||||
$aCurrentUser = [];
|
||||
$aCurrentContact = [];
|
||||
foreach ($aExpectedArgs as $expression)
|
||||
{
|
||||
$aName = explode('->', $expression->GetName());
|
||||
if ($aName[0] == 'current_contact_id') {
|
||||
$aPlaceholders['current_contact_id'] = UserRights::GetContactId();
|
||||
}
|
||||
if ($aName[0] == 'current_user') {
|
||||
} else if ($aName[0] == 'current_user') {
|
||||
array_push($aCurrentUser, $aName[1]);
|
||||
}
|
||||
if ($aName[0] == 'current_contact') {
|
||||
} else if ($aName[0] == 'current_contact') {
|
||||
array_push($aCurrentContact, $aName[1]);
|
||||
}
|
||||
}
|
||||
if (count($aCurrentUser) > 0) {
|
||||
$oUser = UserRights::GetUserObject();
|
||||
$aPlaceholders['current_user->object()'] = $oUser;
|
||||
foreach ($aCurrentUser as $sField) {
|
||||
$aPlaceholders['current_user->'.$sField] = $oUser->Get($sField);
|
||||
}
|
||||
static::FillObjectPlaceholders($aPlaceholders, 'current_user', UserRights::GetUserObject(), $aCurrentUser);
|
||||
}
|
||||
if (count($aCurrentContact) > 0) {
|
||||
$oPerson = UserRights::GetContactObject();
|
||||
$aPlaceholders['current_contact->object()'] = $oPerson;
|
||||
foreach ($aCurrentContact as $sField) {
|
||||
$aPlaceholders['current_contact->'.$sField] = $oPerson->Get($sField);
|
||||
}
|
||||
static::FillObjectPlaceholders($aPlaceholders, 'current_contact', UserRights::GetContactObject(), $aCurrentContact);
|
||||
}
|
||||
}
|
||||
|
||||
return $aPlaceholders;
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 3.1.1 N°6824
|
||||
* @param array $aPlaceholders
|
||||
* @param string $sPlaceHolderPrefix
|
||||
* @param ?\DBObject $oObject
|
||||
* @param array $aCurrentUser
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
*/
|
||||
private static function FillObjectPlaceholders(array &$aPlaceholders, string $sPlaceHolderPrefix, ?\DBObject $oObject, array $aCurrentUser) : void {
|
||||
$sPlaceHolderKey = $sPlaceHolderPrefix."->object()";
|
||||
if (is_null($oObject)){
|
||||
$aContext = [
|
||||
"current_user_id" => UserRights::GetUserId(),
|
||||
"null object type" => $sPlaceHolderPrefix,
|
||||
"fields" => $aCurrentUser,
|
||||
];
|
||||
IssueLog::Warning("Unresolved placeholders due to null object in current context", null,
|
||||
$aContext);
|
||||
$aPlaceholders[$sPlaceHolderKey] = Dict::Format("Core:Placeholder:CannotBeResolved", $sPlaceHolderKey);
|
||||
foreach ($aCurrentUser as $sField) {
|
||||
$sPlaceHolderKey = $sPlaceHolderPrefix . "->$sField";
|
||||
$aPlaceholders[$sPlaceHolderKey] = Dict::Format("Core:Placeholder:CannotBeResolved", $sPlaceHolderKey);
|
||||
}
|
||||
} else {
|
||||
$aPlaceholders[$sPlaceHolderKey] = $oObject;
|
||||
foreach ($aCurrentUser as $sField) {
|
||||
$sPlaceHolderKey = $sPlaceHolderPrefix . "->$sField";
|
||||
// Mind that the "id" is not viewed as a valid att. code by \MetaModel::IsValidAttCode() so we have to test it manually
|
||||
if ($sField !== "id" && false === MetaModel::IsValidAttCode(get_class($oObject), $sField)){
|
||||
$aContext = [
|
||||
"current_user_id" => UserRights::GetUserId(),
|
||||
"obj_class" => get_class($oObject),
|
||||
"placeholder" => $sPlaceHolderKey,
|
||||
"invalid_field" => $sField,
|
||||
];
|
||||
IssueLog::Warning("Unresolved placeholder due to invalid attribute", null,
|
||||
$aContext);
|
||||
$aPlaceholders[$sPlaceHolderKey] = Dict::Format("Core:Placeholder:CannotBeResolved", $sPlaceHolderKey);
|
||||
continue;
|
||||
}
|
||||
|
||||
$aPlaceholders[$sPlaceHolderKey] = $oObject->Get($sField);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \DBSearch $oFilter
|
||||
*
|
||||
@@ -5114,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)
|
||||
@@ -5136,7 +5178,7 @@ abstract class MetaModel
|
||||
*/
|
||||
protected static function DBCreateViews()
|
||||
{
|
||||
list($aErrors, $aSugFix) = self::DBCheckViews();
|
||||
[$aErrors, $aSugFix] = self::DBCheckViews();
|
||||
|
||||
foreach($aSugFix as $sClass => $aTarget)
|
||||
{
|
||||
@@ -6298,6 +6340,13 @@ abstract class MetaModel
|
||||
*/
|
||||
public static function Startup($config, $bModelOnly = false, $bAllowCache = true, $bTraceSourceFiles = false, $sEnvironment = 'production')
|
||||
{
|
||||
// Startup on a new environment is not supported
|
||||
static $bStarted = false;
|
||||
if ($bStarted) {
|
||||
return;
|
||||
}
|
||||
$bStarted = true;
|
||||
|
||||
self::$m_sEnvironment = $sEnvironment;
|
||||
|
||||
try {
|
||||
@@ -6376,7 +6425,9 @@ abstract class MetaModel
|
||||
|
||||
ExecutionKPI::EnableDuration(self::$m_oConfig->Get('log_kpi_duration'));
|
||||
ExecutionKPI::EnableMemory(self::$m_oConfig->Get('log_kpi_memory'));
|
||||
ExecutionKPI::SetAllowedUser(self::$m_oConfig->Get('log_kpi_user_id'));
|
||||
ExecutionKPI::SetAllowedUser(self::$m_oConfig->Get('log_kpi_user_id'));
|
||||
ExecutionKPI::SetGenerateLegacyReport(self::$m_oConfig->Get('log_kpi_generate_legacy_report'));
|
||||
ExecutionKPI::SetSlowQueries(self::$m_oConfig->Get('log_kpi_slow_queries'));
|
||||
|
||||
self::$m_bSkipCheckToWrite = self::$m_oConfig->Get('skip_check_to_write');
|
||||
self::$m_bSkipCheckExtKeys = self::$m_oConfig->Get('skip_check_ext_keys');
|
||||
@@ -6470,7 +6521,7 @@ abstract class MetaModel
|
||||
$aCache['m_aExtensionClassNames'] = self::$m_aExtensionClassNames;
|
||||
$aCache['m_Category2Class'] = self::$m_Category2Class;
|
||||
$aCache['m_aRootClasses'] = self::$m_aRootClasses; // array of "classname" => "rootclass"
|
||||
$aCache['m_aParentClasses'] = self::$m_aParentClasses; // array of ("classname" => array of "parentclass")
|
||||
$aCache['m_aParentClasses'] = self::$m_aParentClasses; // array of ("classname" => array of "parentclass")
|
||||
$aCache['m_aChildClasses'] = self::$m_aChildClasses; // array of ("classname" => array of "childclass")
|
||||
$aCache['m_aClassParams'] = self::$m_aClassParams; // array of ("classname" => array of class information)
|
||||
$aCache['m_aAttribDefs'] = self::$m_aAttribDefs; // array of ("classname" => array of attributes)
|
||||
@@ -6495,6 +6546,7 @@ abstract class MetaModel
|
||||
|
||||
CMDBSource::InitFromConfig(self::$m_oConfig);
|
||||
// Later when timezone implementation is correctly done: CMDBSource::SetTimezone($sDBTimezone);
|
||||
ExecutionKPI::InitStats();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -6526,6 +6578,19 @@ abstract class MetaModel
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal Used for resetting the configuration during automated tests
|
||||
|
||||
* @param \Config $oConfiguration
|
||||
*
|
||||
* @return void
|
||||
* @since 3.0.4 3.1.1 3.2.0
|
||||
*/
|
||||
public static function SetConfig(Config $oConfiguration)
|
||||
{
|
||||
self::$m_oConfig = $oConfiguration;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Config
|
||||
*/
|
||||
@@ -6714,7 +6779,13 @@ abstract class MetaModel
|
||||
|
||||
if ($bMustBeFound && empty($aRow))
|
||||
{
|
||||
throw new CoreException("No result for the single row query: '$sSQL'");
|
||||
$sNotFoundErrorMessage = "No result for the single row query";
|
||||
IssueLog::Info($sNotFoundErrorMessage, LogChannels::CMDB_SOURCE, [
|
||||
'class' => $sClass,
|
||||
'key' => $iKey,
|
||||
'sql_query' => $sSQL,
|
||||
]);
|
||||
throw new CoreException($sNotFoundErrorMessage);
|
||||
}
|
||||
|
||||
return $aRow;
|
||||
@@ -6807,25 +6878,21 @@ abstract class MetaModel
|
||||
* $bMustBeFound=false)
|
||||
* @throws CoreException if no result found and $bMustBeFound=true
|
||||
* @throws ArchivedObjectException if archive mode disabled and result is archived and $bMustBeFound=true
|
||||
* @throws \Exception
|
||||
*
|
||||
*/
|
||||
public static function GetObject($sClass, $iKey, $bMustBeFound = true, $bAllowAllData = false, $aModifierProperties = null)
|
||||
{
|
||||
$oObject = self::GetObjectWithArchive($sClass, $iKey, $bMustBeFound, $bAllowAllData, $aModifierProperties);
|
||||
|
||||
if (empty($oObject))
|
||||
{
|
||||
if (empty($oObject)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!utils::IsArchiveMode() && $oObject->IsArchived())
|
||||
{
|
||||
if (!utils::IsArchiveMode() && $oObject->IsArchived()) {
|
||||
if ($bMustBeFound) {
|
||||
throw new ArchivedObjectException("The object $sClass::$iKey is archived");
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
return $oObject;
|
||||
@@ -6860,6 +6927,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)
|
||||
@@ -7608,14 +7691,12 @@ abstract class MetaModel
|
||||
// Build the list of available extensions
|
||||
//
|
||||
$aInterfaces = [
|
||||
'iApplicationUIExtension',
|
||||
'iPreferencesExtension',
|
||||
'iApplicationObjectExtension',
|
||||
'iLoginFSMExtension',
|
||||
'iLoginUIExtension',
|
||||
'iLogoutExtension',
|
||||
'iQueryModifier',
|
||||
'iOnClassInitialization',
|
||||
'iLoginUIExtension',
|
||||
'iPreferencesExtension',
|
||||
'iApplicationUIExtension',
|
||||
'iApplicationObjectExtension',
|
||||
'iPopupMenuExtension',
|
||||
'iPageUIExtension',
|
||||
'iPageUIBlockExtension',
|
||||
@@ -7629,9 +7710,12 @@ abstract class MetaModel
|
||||
'iBackofficeDictEntriesExtension',
|
||||
'iBackofficeDictEntriesPrefixesExtension',
|
||||
'iPortalUIExtension',
|
||||
'iQueryModifier',
|
||||
'iOnClassInitialization',
|
||||
'iModuleExtension',
|
||||
'iKPILoggerExtension',
|
||||
'ModuleHandlerApiInterface',
|
||||
'iNewsroomProvider',
|
||||
'iModuleExtension',
|
||||
];
|
||||
foreach ($aInterfaces as $sInterface) {
|
||||
self::$m_aExtensionClassNames[$sInterface] = array();
|
||||
|
||||
@@ -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
|
||||
@@ -257,7 +259,7 @@ class iTopMutex
|
||||
$this->hDBLink = CMDBSource::GetMysqliInstance($sServer, $sUser, $sPwd, $sSource, $bTlsEnabled, $sTlsCA, false);
|
||||
|
||||
if (!$this->hDBLink) {
|
||||
throw new Exception("Could not connect to the DB server (host=$sServer, user=$sUser): ".mysqli_connect_error().' (mysql errno: '.mysqli_connect_errno().')');
|
||||
throw new MySQLException('Could not connect to the DB server '.mysqli_connect_error().' (mysql errno: '.mysqli_connect_errno(), array('host' => $sDBHost, 'user' => $sDBUser));
|
||||
}
|
||||
|
||||
// Make sure that the server variable `wait_timeout` is at least 86400 seconds for this connection,
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -121,7 +121,9 @@ abstract class Trigger extends cmdbAbstractObject
|
||||
$oAction = MetaModel::GetObject('Action', $iActionId);
|
||||
if ($oAction->IsActive())
|
||||
{
|
||||
$oKPI = new ExecutionKPI();
|
||||
$oAction->DoExecute($this, $aContextArgs);
|
||||
$oKPI->ComputeStatsForExtension($oAction, 'DoExecute');
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -254,6 +256,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
|
||||
|
||||
@@ -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);
|
||||
@@ -248,7 +249,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)));
|
||||
|
||||
@@ -761,14 +762,25 @@ class UserRights
|
||||
protected static $m_aCacheContactPictureAbsUrl = [];
|
||||
/** @var UserRightsAddOnAPI $m_oAddOn */
|
||||
protected static $m_oAddOn;
|
||||
protected static $m_oUser;
|
||||
protected static $m_oRealUser;
|
||||
protected static $m_oUser = null;
|
||||
protected static $m_oRealUser = null;
|
||||
protected static $m_sSelfRegisterAddOn = null;
|
||||
protected static $m_aAdmins = array();
|
||||
protected static $m_aPortalUsers = array();
|
||||
/** @var array array('sName' => $sName, 'bSuccess' => $bSuccess); */
|
||||
private static $m_sLastLoginStatus = null;
|
||||
|
||||
/**
|
||||
* @return void
|
||||
* @since 3.0.4 3.1.1 3.2.0
|
||||
*/
|
||||
protected static function ResetCurrentUserData()
|
||||
{
|
||||
self::$m_oUser = null;
|
||||
self::$m_oRealUser = null;
|
||||
self::$m_sLastLoginStatus = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $sModuleName
|
||||
*
|
||||
@@ -787,8 +799,7 @@ class UserRights
|
||||
}
|
||||
self::$m_oAddOn = new $sModuleName;
|
||||
self::$m_oAddOn->Init();
|
||||
self::$m_oUser = null;
|
||||
self::$m_oRealUser = null;
|
||||
self::ResetCurrentUserData();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -846,6 +857,8 @@ class UserRights
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the current user (as part of the login process)
|
||||
*
|
||||
* @param string $sLogin Login of the concerned user
|
||||
* @param string $sAuthentication
|
||||
*
|
||||
@@ -855,6 +868,8 @@ class UserRights
|
||||
*/
|
||||
public static function Login($sLogin, $sAuthentication = 'any')
|
||||
{
|
||||
self::ResetCurrentUserData();
|
||||
|
||||
$oUser = self::FindUser($sLogin, $sAuthentication);
|
||||
if (is_null($oUser))
|
||||
{
|
||||
@@ -872,6 +887,19 @@ class UserRights
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset current user and cleanup associated SESSION data
|
||||
*
|
||||
* @return void
|
||||
* @since 3.0.4 3.1.1 3.2.0
|
||||
*/
|
||||
public static function Logoff()
|
||||
{
|
||||
self::ResetCurrentUserData();
|
||||
Dict::SetUserLanguage(null);
|
||||
self::_ResetSessionCache();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $sLogin Login of the user to check the credentials for
|
||||
* @param string $sPassword
|
||||
@@ -1096,9 +1124,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()
|
||||
{
|
||||
@@ -1546,9 +1572,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
|
||||
|
||||
@@ -20,6 +20,8 @@ $ibo-dashlet-badge--icon--size: 48px !default;
|
||||
|
||||
$ibo-dashlet-badge--action-icon--margin-right: $ibo-spacing-300 !default;
|
||||
|
||||
$ibo-dashlet-badge--body--tooltip-title--margin-bottom: $ibo-spacing-500 !default;
|
||||
|
||||
/* CSS variables (can be changed directly from the browser) */
|
||||
:root {
|
||||
--ibo-dashlet-badge--min-width: #{$ibo-dashlet-badge--min-width};
|
||||
@@ -74,18 +76,27 @@ $ibo-dashlet-badge--action-icon--margin-right: $ibo-spacing-300 !default;
|
||||
@extend %ibo-hyperlink-inherited-colors;
|
||||
}
|
||||
}
|
||||
.ibo-dashlet-badge--action-list-count{
|
||||
margin-right: $ibo-dashlet-badge--action-list-count--margin-right;
|
||||
@extend %ibo-font-ral-bol-450;
|
||||
|
||||
.ibo-dashlet-badge--action-list-count {
|
||||
margin-right: $ibo-dashlet-badge--action-list-count--margin-right;
|
||||
@extend %ibo-font-ral-bol-450;
|
||||
}
|
||||
.ibo-dashlet-badge--action-list-label{
|
||||
display: inline-block;
|
||||
@extend %ibo-text-truncated-with-ellipsis;
|
||||
|
||||
.ibo-dashlet-badge--action-list-label {
|
||||
display: inline-block;
|
||||
@extend %ibo-text-truncated-with-ellipsis;
|
||||
}
|
||||
.ibo-dashlet-badge--action-create{
|
||||
@extend %ibo-baseline-centered-content;
|
||||
@extend %ibo-font-size-150;
|
||||
|
||||
.ibo-dashlet-badge--action-create {
|
||||
@extend %ibo-baseline-centered-content;
|
||||
@extend %ibo-font-size-150;
|
||||
}
|
||||
.ibo-dashlet-badge--action-create-icon{
|
||||
margin-right: $ibo-dashlet-badge--action-icon--margin-right;
|
||||
|
||||
.ibo-dashlet-badge--action-create-icon {
|
||||
margin-right: $ibo-dashlet-badge--action-icon--margin-right;
|
||||
}
|
||||
|
||||
.ibo-dashlet-badge--body--tooltip-title {
|
||||
@extend %ibo-font-weight-600;
|
||||
margin-bottom: $ibo-dashlet-badge--body--tooltip-title--margin-bottom;
|
||||
}
|
||||
|
||||
@@ -13,6 +13,9 @@ $body-overflow-x: hidden !default;
|
||||
$body-overflow-y: auto !default;
|
||||
|
||||
|
||||
/*N°5786 - Avoid strong text to always be grey (default Bulma color for this var.) so strong text can keep its color. This is mostly for text within the .ibo-is-html-content. */
|
||||
$text-strong: inherit !default;
|
||||
|
||||
/**
|
||||
* customize Bulma content variables
|
||||
* See https://bulma.io/documentation/elements/content/
|
||||
|
||||
75
css/form-sdk/form.css
Normal file
75
css/form-sdk/form.css
Normal file
@@ -0,0 +1,75 @@
|
||||
/**
|
||||
* Widgets Factory.
|
||||
*
|
||||
* @package FormSDK
|
||||
* @since 3.2.0
|
||||
*/
|
||||
|
||||
/* debug purpose */
|
||||
.form-type-pictograms{
|
||||
display: inline-block;
|
||||
float: right;
|
||||
margin-left: 5px;
|
||||
color: grey;
|
||||
cursor: pointer;
|
||||
padding: 0px 5px;
|
||||
border-radius: 8px;
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
.form-type-pictograms i{
|
||||
width: 15px;
|
||||
}
|
||||
.complete .form-type-pictograms .pattern:after{
|
||||
content: '\f00c';
|
||||
font-family: "Font Awesome 6 Free";
|
||||
font-weight: 900;
|
||||
background-color: #20b220;
|
||||
border-radius: 50%;
|
||||
font-size: 7px;
|
||||
color: white;
|
||||
position: relative;
|
||||
top: -10px;
|
||||
padding: 2px;
|
||||
}
|
||||
|
||||
/* form label */
|
||||
.form-label.required:after{
|
||||
content: '*';
|
||||
color: #e63535;
|
||||
margin-left: 3px;
|
||||
}
|
||||
|
||||
.cke_focus .cke_contents{
|
||||
border: 1px #86b7fe solid;
|
||||
outline: 0;
|
||||
border-radius: 6px;
|
||||
box-shadow: 0 0 0 0.25rem rgba(13,110,253,.25);
|
||||
}
|
||||
|
||||
.form_interval_horizontal{
|
||||
display: flex;
|
||||
}
|
||||
.form_interval_horizontal > div{
|
||||
margin-right: 8px;
|
||||
}
|
||||
|
||||
.form-compound-fieldset{
|
||||
padding: 8px;
|
||||
border-radius: 10px;
|
||||
border: 1px dashed lightgrey;
|
||||
}
|
||||
|
||||
.form-layout-row{
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
}
|
||||
.form-layout-column{
|
||||
margin: 10px;
|
||||
}
|
||||
.form-layout-column:first-child{
|
||||
margin-left: 0px;
|
||||
}
|
||||
.form-layout-column:last-child{
|
||||
margin-right: 0px;
|
||||
}
|
||||
|
||||
88
css/form-sdk/test.css
Normal file
88
css/form-sdk/test.css
Normal file
@@ -0,0 +1,88 @@
|
||||
.layout-grow{
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
||||
.custom-container{
|
||||
position: relative;
|
||||
border-radius: 10px;
|
||||
padding: 40px 20px 0px;
|
||||
}
|
||||
|
||||
.custom-container:before{
|
||||
content: 'Custom Layout CSS';
|
||||
font-weight: 500;
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
top: -10px;
|
||||
transform: translateX(-50%);
|
||||
/*border: 1px solid #9c21af;*/
|
||||
background-color: white;
|
||||
padding: 5px 15px;
|
||||
border-radius: 10px;
|
||||
}
|
||||
|
||||
.container-flower{
|
||||
background-color: #f3deff;
|
||||
background-size: 500px;
|
||||
background-repeat: no-repeat;
|
||||
background-position-x: right;
|
||||
background-position-y: bottom;
|
||||
background: linear-gradient( to right bottom, rgb(248 242 251) 50%, rgb(241 187 255) );
|
||||
padding-bottom: 200px;
|
||||
}
|
||||
.container-flower fieldset{
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
}
|
||||
.container-flower:after{
|
||||
content: '';
|
||||
width: 300px;
|
||||
height: 200px;
|
||||
background-image: url('../../sources/FormImplementation/Resources/6662396.png');
|
||||
background-size: 300px;
|
||||
position: absolute;
|
||||
bottom: 0px;
|
||||
right: 0px;
|
||||
border-radius: 10px;
|
||||
}
|
||||
|
||||
.container-flower .col-form-label{
|
||||
color: #8d63b7;
|
||||
}
|
||||
.container-flower .form-compound-fieldset{
|
||||
border: 1px solid #8d63b7;
|
||||
}
|
||||
|
||||
.container-color{
|
||||
position: relative;
|
||||
border-radius: 10px;
|
||||
background-color: #faf7ff;
|
||||
}
|
||||
|
||||
.container-color .form-compound-fieldset{
|
||||
background-color: #ebe4f6;
|
||||
border: none;
|
||||
}
|
||||
|
||||
.container-color2{
|
||||
position: relative;
|
||||
border-radius: 10px;
|
||||
background-color: #f7f9ff;
|
||||
}
|
||||
|
||||
.container-color2 .form-compound-fieldset{
|
||||
background-color: #e8edf9;
|
||||
border: none;
|
||||
}
|
||||
|
||||
.error-label{
|
||||
color: #d32f2f;
|
||||
}
|
||||
|
||||
.container-color2 .form-compound-fieldset fieldset{
|
||||
border-bottom: 1px dashed #a3adc5;
|
||||
}
|
||||
|
||||
.container-color2 .form-compound-fieldset fieldset:last-child{
|
||||
border-bottom: none;
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
@@ -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">
|
||||
<constants>
|
||||
</constants>
|
||||
<classes>
|
||||
|
||||
@@ -7,6 +7,6 @@
|
||||
*/
|
||||
Dict::Add('ZH CN', 'Chinese', '简体中文', array(
|
||||
'CAS:Error:UserNotAllowed' => '用户被禁止登录',
|
||||
'CAS:Login:SignIn' => '使用CAS 登录',
|
||||
'CAS:Login:SignInTooltip' => '点击这里使用CAS 服务器认证',
|
||||
'CAS:Login:SignIn' => '使用CAS登录',
|
||||
'CAS:Login:SignInTooltip' => '点击这里使用CAS服务器认证',
|
||||
));
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user