mirror of
https://github.com/Combodo/iTop.git
synced 2026-02-27 06:04:12 +01:00
Compare commits
700 Commits
feature/86
...
develop
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
94a36c0066 | ||
|
|
62e09f1224 | ||
|
|
57a0b5691f | ||
|
|
f82389d156 | ||
|
|
9e21976424 | ||
|
|
f558093f5d | ||
|
|
5201a1ed3b | ||
|
|
dad39c3ebe | ||
|
|
29920bfeb7 | ||
|
|
2313ee2bbd | ||
|
|
22b0c431a0 | ||
|
|
499b3bca88 | ||
|
|
aede5ea7b8 | ||
|
|
da6c443a35 | ||
|
|
9c39efd9af | ||
|
|
d5f2303ed2 | ||
|
|
48e584503e | ||
|
|
454a1b26eb | ||
|
|
4853ca444e | ||
|
|
330539abd2 | ||
|
|
5357a0c060 | ||
|
|
fc22cce037 | ||
|
|
34c8a57814 | ||
|
|
b91e6c384a | ||
|
|
2247691e58 | ||
|
|
f014b43761 | ||
|
|
076d49abc2 | ||
|
|
9fd0ffd84e | ||
|
|
0f11fd9919 | ||
|
|
2b828f8a22 | ||
|
|
d2f67dcb3c | ||
|
|
d5706fcbef | ||
|
|
807f2a88bc | ||
|
|
9d3311e623 | ||
|
|
9bf2cb7e1d | ||
|
|
0134ead5dd | ||
|
|
54909520e9 | ||
|
|
d124f8ee58 | ||
|
|
3fdbcbc0fb | ||
|
|
a5296e11e1 | ||
|
|
3b62597092 | ||
|
|
b085147f23 | ||
|
|
38fccf85e3 | ||
|
|
c0a2771d4e | ||
|
|
6bd5a7b634 | ||
|
|
82b7ef86c7 | ||
|
|
f8cf14cbad | ||
|
|
a5dededfb4 | ||
|
|
4f878536a8 | ||
|
|
d937ec0350 | ||
|
|
1cdcaac3d0 | ||
|
|
985db46960 | ||
|
|
01adaadfad | ||
|
|
3f807a64bb | ||
|
|
1d4a155e8f | ||
|
|
643752f8e7 | ||
|
|
0e0c09c420 | ||
|
|
2b6fa8b381 | ||
|
|
7d2dc5e36a | ||
|
|
f87df8f28b | ||
|
|
cc9e64616f | ||
|
|
f34373be6d | ||
|
|
a39234f438 | ||
|
|
ac8937105d | ||
|
|
fb6f892244 | ||
|
|
0a04c83c7b | ||
|
|
cc8252bebf | ||
|
|
3e879c64a7 | ||
|
|
5c6369b9b8 | ||
|
|
154fb5c737 | ||
|
|
efb1bd765b | ||
|
|
b39af74d07 | ||
|
|
904cd0b518 | ||
|
|
4c1ad0f4f2 | ||
|
|
3955b4eb22 | ||
|
|
3d46fe6ef1 | ||
|
|
4dba47798c | ||
|
|
9480c4053d | ||
|
|
9ea197148c | ||
|
|
49a7f3118d | ||
|
|
bf80b5dca2 | ||
|
|
09afcb229c | ||
|
|
92f843f676 | ||
|
|
3df4ddc696 | ||
|
|
d552727c55 | ||
|
|
1fe401c102 | ||
|
|
a4b0b6e855 | ||
|
|
545028d68a | ||
|
|
6cb08ba361 | ||
|
|
b3cd79605d | ||
|
|
f9db405343 | ||
|
|
4f1f144c51 | ||
|
|
ef8ade5d20 | ||
|
|
cef4a52081 | ||
|
|
dc9fb2d693 | ||
|
|
e9ffbe5b09 | ||
|
|
9c792a601f | ||
|
|
cda6c1dfa8 | ||
|
|
0b242d872a | ||
|
|
c144c80663 | ||
|
|
d9261b8342 | ||
|
|
df567fb9fe | ||
|
|
028767768c | ||
|
|
11ec80830e | ||
|
|
edf992ef2b | ||
|
|
7c8fb1a51d | ||
|
|
aa27b3601b | ||
|
|
73f868ac83 | ||
|
|
5a2157ba21 | ||
|
|
03e25a226e | ||
|
|
24048d2b9c | ||
|
|
d8121b563a | ||
|
|
f266f5ff36 | ||
|
|
4a6b129eb8 | ||
|
|
4187f552a9 | ||
|
|
7f7ce0837e | ||
|
|
bc4d50dd0b | ||
|
|
e21a541b70 | ||
|
|
ed360edb83 | ||
|
|
53de040934 | ||
|
|
b8345de553 | ||
|
|
fd10887849 | ||
|
|
7df09541ac | ||
|
|
e09987e442 | ||
|
|
6d5660ca67 | ||
|
|
0013b8cfee | ||
|
|
7fb0ae48f9 | ||
|
|
e89a8edae0 | ||
|
|
262cc3c206 | ||
|
|
b5fe12ca3c | ||
|
|
6d279647f1 | ||
|
|
299c468eaa | ||
|
|
7bbcc388ea | ||
|
|
5b7a5e14a3 | ||
|
|
2b1ecf15b4 | ||
|
|
f6366057c9 | ||
|
|
41a90b5033 | ||
|
|
67018b9b17 | ||
|
|
fa8ecb956e | ||
|
|
58eae4dde3 | ||
|
|
d098a5eb87 | ||
|
|
8597dea398 | ||
|
|
a6972af266 | ||
|
|
066b27c982 | ||
|
|
283de1ef7c | ||
|
|
8b00016115 | ||
|
|
b5c79e1d75 | ||
|
|
dd82950eee | ||
|
|
2e8b48ce47 | ||
|
|
80d4e65a81 | ||
|
|
b0a792afab | ||
|
|
7681c157ec | ||
|
|
4a9a85458d | ||
|
|
890a2568c8 | ||
|
|
12f23113f5 | ||
|
|
6cf6e7dd8d | ||
|
|
d4183acfde | ||
|
|
26f21ee6eb | ||
|
|
c5fb116052 | ||
|
|
bdc8fdd02f | ||
|
|
adfa800063 | ||
|
|
5df936c587 | ||
|
|
8056a63e82 | ||
|
|
775ac3df77 | ||
|
|
83927af8ed | ||
|
|
f1609168b7 | ||
|
|
4f845c63cf | ||
|
|
d029039d22 | ||
|
|
10a7fafe59 | ||
|
|
700b95e8c6 | ||
|
|
600a6185a3 | ||
|
|
354a7cabab | ||
|
|
0802e5abb5 | ||
|
|
8ade0a6e85 | ||
|
|
6226ac8746 | ||
|
|
e661e0bdbb | ||
|
|
1d52665012 | ||
|
|
4aa0c19183 | ||
|
|
809d4cd665 | ||
|
|
0c3bc7f35b | ||
|
|
bfc583e6b5 | ||
|
|
5bc453bca6 | ||
|
|
5dd450e9bf | ||
|
|
82395727bf | ||
|
|
318b792b31 | ||
|
|
0fe2183369 | ||
|
|
8f038d2f95 | ||
|
|
fbf3dd8cf7 | ||
|
|
01c9e73020 | ||
|
|
0736045b90 | ||
|
|
778c16da86 | ||
|
|
86776edfb3 | ||
|
|
5045ec4afa | ||
|
|
d78805d8ae | ||
|
|
03e1d46586 | ||
|
|
f3deb8be11 | ||
|
|
e000befc0f | ||
|
|
2eba58998b | ||
|
|
fa5cad0fdb | ||
|
|
5d28de1636 | ||
|
|
6be9255ca0 | ||
|
|
edbe4974ac | ||
|
|
7e515e7216 | ||
|
|
d589d9d05a | ||
|
|
c0c9ea9287 | ||
|
|
fae2bcc6e9 | ||
|
|
53047d35fe | ||
|
|
909469ce97 | ||
|
|
dacb54285c | ||
|
|
5af93ca92a | ||
|
|
3fa500c9c1 | ||
|
|
f0adbbba29 | ||
|
|
bbdb30f421 | ||
|
|
897b5d452e | ||
|
|
fdd1479c8e | ||
|
|
7851109794 | ||
|
|
810e6c1bda | ||
|
|
d164f48cfe | ||
|
|
506def4340 | ||
|
|
08b8e919b7 | ||
|
|
696e2c9565 | ||
|
|
d728be119c | ||
|
|
463869b89d | ||
|
|
1d4c0b8e7f | ||
|
|
bf1b2a5104 | ||
|
|
15103dc49f | ||
|
|
2ee68ff819 | ||
|
|
44972f34e5 | ||
|
|
a104310379 | ||
|
|
f5cce23bb4 | ||
|
|
0f39106b56 | ||
|
|
ee993ef80a | ||
|
|
0a4180f7fc | ||
|
|
b56113aada | ||
|
|
c82c150411 | ||
|
|
00818f411f | ||
|
|
a6a459967e | ||
|
|
2ba4109343 | ||
|
|
738664e560 | ||
|
|
88e0f17164 | ||
|
|
d48bc15211 | ||
|
|
32f0cfb091 | ||
|
|
20393b55b9 | ||
|
|
f03b008ebf | ||
|
|
7f98ef3478 | ||
|
|
d80e26791d | ||
|
|
e6a0d95cba | ||
|
|
965c9dba14 | ||
|
|
8bca3ac830 | ||
|
|
a975f67bd5 | ||
|
|
f5b86ff4d9 | ||
|
|
0deeeeb587 | ||
|
|
2011570b84 | ||
|
|
1458ba877b | ||
|
|
71386198cf | ||
|
|
5b9e0a1d4f | ||
|
|
1667f834b9 | ||
|
|
cdbcd14767 | ||
|
|
603340b852 | ||
|
|
820087e4d1 | ||
|
|
c5ee123f88 | ||
|
|
69d5015a24 | ||
|
|
1d1365d951 | ||
|
|
3da33c4c64 | ||
|
|
7b95d65f60 | ||
|
|
d3e450c54e | ||
|
|
5a50398dba | ||
|
|
387ca19ec2 | ||
|
|
c0651edaa1 | ||
|
|
b06f3cd13e | ||
|
|
5aeb408edd | ||
|
|
7456383d72 | ||
|
|
9c6b8f90f0 | ||
|
|
e6ea2fd541 | ||
|
|
7d94e6f1f8 | ||
|
|
2bd7c7a01a | ||
|
|
f1762845f0 | ||
|
|
3eb8437c32 | ||
|
|
9acc6a8bd4 | ||
|
|
4d794fe656 | ||
|
|
c9f88a16ef | ||
|
|
95f84a98cc | ||
|
|
6cb10ab13a | ||
|
|
048aaeb854 | ||
|
|
2b18ab9690 | ||
|
|
36dc71fdce | ||
|
|
db2ad86c70 | ||
|
|
56616ab08e | ||
|
|
f339498497 | ||
|
|
b24a359b36 | ||
|
|
78c63f7502 | ||
|
|
2f8b35c153 | ||
|
|
271a1f66c1 | ||
|
|
738c7e1b8e | ||
|
|
54278f8c02 | ||
|
|
00e117b05f | ||
|
|
504261a2c2 | ||
|
|
14a1a4e9c7 | ||
|
|
cfc4a43d0b | ||
|
|
503a5ec25a | ||
|
|
09364ccf84 | ||
|
|
4bbd1fea5c | ||
|
|
3c27847a04 | ||
|
|
8523da3329 | ||
|
|
de54676b9f | ||
|
|
8580cb70a4 | ||
|
|
e5129c9618 | ||
|
|
d0f816109b | ||
|
|
05642cdf84 | ||
|
|
bfbc939bac | ||
|
|
dffce3f2f7 | ||
|
|
e96095e02d | ||
|
|
8330582f86 | ||
|
|
5a4ad7b8c3 | ||
|
|
a116967b0a | ||
|
|
a13f353721 | ||
|
|
bd254e56d1 | ||
|
|
346bd5de47 | ||
|
|
599e08f150 | ||
|
|
0462298cd3 | ||
|
|
80abaec9a6 | ||
|
|
a7877dc6a6 | ||
|
|
031305cfbf | ||
|
|
a2d6423f32 | ||
|
|
57d610fc16 | ||
|
|
d2d422afcf | ||
|
|
278ac66637 | ||
|
|
471422b274 | ||
|
|
87db141c3c | ||
|
|
5573a222c8 | ||
|
|
83eb2b81e3 | ||
|
|
86d2a3424d | ||
|
|
f062f994f0 | ||
|
|
fb81e54ed9 | ||
|
|
cd1c6f5ec5 | ||
|
|
916467ea61 | ||
|
|
8a4ad87b06 | ||
|
|
2086052d60 | ||
|
|
0a4f9e95c5 | ||
|
|
282fb13973 | ||
|
|
0b92535fda | ||
|
|
a0f4c62bcc | ||
|
|
cd4e2608ee | ||
|
|
d6c9a6d318 | ||
|
|
2ee30692ff | ||
|
|
ca937b829b | ||
|
|
9aa13f57d8 | ||
|
|
e0b8ee2143 | ||
|
|
20a7a945fc | ||
|
|
0640c1e9b6 | ||
|
|
cad40ed758 | ||
|
|
11d23ac99b | ||
|
|
1eeb98d2e2 | ||
|
|
92e2d22248 | ||
|
|
5811dc06e3 | ||
|
|
f9d9fcc440 | ||
|
|
a4a05a2579 | ||
|
|
6bd11fb9bf | ||
|
|
624573d088 | ||
|
|
b21a02dcb8 | ||
|
|
3b60e63c97 | ||
|
|
adc8b47945 | ||
|
|
5e6d96019d | ||
|
|
06cc64f6d6 | ||
|
|
a5c14c3a48 | ||
|
|
8f6f243716 | ||
|
|
3c574819b2 | ||
|
|
5b1ea20407 | ||
|
|
4d88ef6ed4 | ||
|
|
5cb1102e6e | ||
|
|
bf23e4d98d | ||
|
|
8645b28baa | ||
|
|
eff6fcff49 | ||
|
|
994b08f94a | ||
|
|
19495d8acf | ||
|
|
48a3ea1945 | ||
|
|
a11b2845f7 | ||
|
|
ee72325451 | ||
|
|
ebb59d3ddc | ||
|
|
0193db609d | ||
|
|
ea2caed98a | ||
|
|
09c092782c | ||
|
|
a4166f874e | ||
|
|
96382377ee | ||
|
|
84708fb327 | ||
|
|
02adca0a1f | ||
|
|
f44468b7a1 | ||
|
|
90370fce3b | ||
|
|
fe913524fd | ||
|
|
9f2375999a | ||
|
|
4b86639d71 | ||
|
|
911a204f37 | ||
|
|
69f9a0b369 | ||
|
|
25e8ec38d6 | ||
|
|
1574993a28 | ||
|
|
43120bfb60 | ||
|
|
9c1a1d08a1 | ||
|
|
f095f93326 | ||
|
|
c9c3b6c108 | ||
|
|
5caddf81b8 | ||
|
|
73fe07a745 | ||
|
|
1760727879 | ||
|
|
d982652228 | ||
|
|
1d26cac8e3 | ||
|
|
cc47d27fd8 | ||
|
|
1e5334ab2b | ||
|
|
05419f3d7f | ||
|
|
534b087a2c | ||
|
|
e85ec6bb47 | ||
|
|
533fe0ae01 | ||
|
|
efd117eac7 | ||
|
|
01a17b5f9b | ||
|
|
92d49c6c47 | ||
|
|
623d2823ff | ||
|
|
5d5849b724 | ||
|
|
902e2259a9 | ||
|
|
b87fb65ac4 | ||
|
|
ab929571c7 | ||
|
|
8e0e01ad40 | ||
|
|
8a604c643e | ||
|
|
f1594ad974 | ||
|
|
805e208e32 | ||
|
|
9e3f99a150 | ||
|
|
e9d21bca39 | ||
|
|
807283505d | ||
|
|
71244e5c15 | ||
|
|
72e0750c1b | ||
|
|
ac8004561b | ||
|
|
766d3b51ad | ||
|
|
3215bffbcb | ||
|
|
51bb0add8e | ||
|
|
4c8392b332 | ||
|
|
fb180e8370 | ||
|
|
2dd1224219 | ||
|
|
e7b87128b1 | ||
|
|
d0bdde30ad | ||
|
|
3fe8b6c696 | ||
|
|
6539687f16 | ||
|
|
e0b12144cb | ||
|
|
79a46581ef | ||
|
|
5a59d16c99 | ||
|
|
a63a3d3d9c | ||
|
|
ed6e4f612a | ||
|
|
16279233e0 | ||
|
|
07964cc404 | ||
|
|
ea5473ad77 | ||
|
|
2a888cf5af | ||
|
|
548131482a | ||
|
|
5ac6c84813 | ||
|
|
0c3a35fc43 | ||
|
|
881dbd3c01 | ||
|
|
81887f480a | ||
|
|
d25bf4ef66 | ||
|
|
90f58721b1 | ||
|
|
b20b4b7e82 | ||
|
|
eeabad895d | ||
|
|
9fdf183851 | ||
|
|
96414dcc98 | ||
|
|
6ab19d29b9 | ||
|
|
5c5c5d769f | ||
|
|
ecce0a3376 | ||
|
|
f8e761abe0 | ||
|
|
d3a9e30178 | ||
|
|
0fd2cf85a2 | ||
|
|
a64fed66a3 | ||
|
|
261106fa9d | ||
|
|
1556b95653 | ||
|
|
324cb5eb6c | ||
|
|
eedbf3d266 | ||
|
|
3b197692ec | ||
|
|
ecfc26f1ec | ||
|
|
a34baf840a | ||
|
|
6f9bd9bae5 | ||
|
|
c32b2f9dfe | ||
|
|
a1860c82fb | ||
|
|
d47d65df10 | ||
|
|
b42297ad84 | ||
|
|
6cb1cf7b7e | ||
|
|
a65dd1c27c | ||
|
|
d85d611642 | ||
|
|
6a00786535 | ||
|
|
6490fe93a1 | ||
|
|
642a13ad0d | ||
|
|
e1bfe9a3b6 | ||
|
|
af8ff9b29f | ||
|
|
fcfdac2844 | ||
|
|
ce68e270c3 | ||
|
|
0d8a20c35e | ||
|
|
1f3780f338 | ||
|
|
85f6195a51 | ||
|
|
7e1b1779a9 | ||
|
|
d95e7168aa | ||
|
|
a7c22c06af | ||
|
|
a72d1ca1b3 | ||
|
|
be5e4458ba | ||
|
|
317cd585b2 | ||
|
|
5d8db176f4 | ||
|
|
c6039f4b51 | ||
|
|
d0f9e57bf1 | ||
|
|
385c60e993 | ||
|
|
58c68bade9 | ||
|
|
eb992c7b45 | ||
|
|
0688405f86 | ||
|
|
dd34fda42e | ||
|
|
6becd73ac2 | ||
|
|
72d6e251b8 | ||
|
|
9491c9102c | ||
|
|
a728cf312d | ||
|
|
e321e27899 | ||
|
|
96e8467e13 | ||
|
|
508918a684 | ||
|
|
8adef26d18 | ||
|
|
2d45abd12b | ||
|
|
bd5e55aad9 | ||
|
|
b57e4fce07 | ||
|
|
b460705831 | ||
|
|
58c47f4c0a | ||
|
|
f3a6b064c8 | ||
|
|
5e6fb33ed7 | ||
|
|
5e7137e0c4 | ||
|
|
4cf5e47ec3 | ||
|
|
143a59a19d | ||
|
|
61b247b156 | ||
|
|
c1aa013053 | ||
|
|
a3f9eed6e2 | ||
|
|
21c9332a7f | ||
|
|
ae6e0a08ea | ||
|
|
d9d2e851f4 | ||
|
|
91c63cb12e | ||
|
|
4ff354dd41 | ||
|
|
bd8c325306 | ||
|
|
9902cedc06 | ||
|
|
b64ee96636 | ||
|
|
8c1ff2dc1c | ||
|
|
f2ab409c9c | ||
|
|
db46763e13 | ||
|
|
7ee1af3cc8 | ||
|
|
32b371eac1 | ||
|
|
f65cadd24c | ||
|
|
40551b36e5 | ||
|
|
c0056e75d0 | ||
|
|
e5825b5fcd | ||
|
|
d3dc59c5da | ||
|
|
642a097b4b | ||
|
|
1c615c42b6 | ||
|
|
b1f708dcad | ||
|
|
55f202b7cb | ||
|
|
247f1045fe | ||
|
|
42e78ad3a3 | ||
|
|
113826b2e7 | ||
|
|
7fe8da8590 | ||
|
|
821251a53f | ||
|
|
5334bbb303 | ||
|
|
012d5e7ae0 | ||
|
|
03f4e9f621 | ||
|
|
055968bea9 | ||
|
|
d0457b73ec | ||
|
|
7e8ff50886 | ||
|
|
36a6ee4fc9 | ||
|
|
db8b00e8df | ||
|
|
5d31c372fa | ||
|
|
0497122e25 | ||
|
|
645d68d5d0 | ||
|
|
f04b8368aa | ||
|
|
f9fd4f1e2a | ||
|
|
55ed552ba7 | ||
|
|
7bfa23fab7 | ||
|
|
7bd427b4e7 | ||
|
|
a9a9fb1da2 | ||
|
|
6653b13144 | ||
|
|
8bea29f0e7 | ||
|
|
d556564ee1 | ||
|
|
2286a9e2a4 | ||
|
|
30c10cb67f | ||
|
|
74a42a4d4f | ||
|
|
c31443cb79 | ||
|
|
a698aec7a5 | ||
|
|
04d2aaf05c | ||
|
|
5103f898e1 | ||
|
|
68ee3231f4 | ||
|
|
62a7850a0b | ||
|
|
20f1ec42b1 | ||
|
|
e51e55b634 | ||
|
|
bc7db973ad | ||
|
|
0489103e11 | ||
|
|
b99249d2d2 | ||
|
|
23aed5415c | ||
|
|
2adbcf5e6f | ||
|
|
6a99e3c1c9 | ||
|
|
8e1de5bf2d | ||
|
|
f6808ee522 | ||
|
|
4f650d3c5b | ||
|
|
ba641d96d5 | ||
|
|
3dc514c67d | ||
|
|
5df7c58b1b | ||
|
|
bb680ac514 | ||
|
|
e18018cacd | ||
|
|
5d91c8832b | ||
|
|
c96c8ac30d | ||
|
|
f930533d8b | ||
|
|
29bfb8a8bf | ||
|
|
f04359f398 | ||
|
|
c24052e976 | ||
|
|
5f8e43fc67 | ||
|
|
5427b146cf | ||
|
|
6f231ce800 | ||
|
|
d66d1c8739 | ||
|
|
50b4388b8d | ||
|
|
9cc8b75ffb | ||
|
|
e715342f7a | ||
|
|
c86ac4f9a7 | ||
|
|
b79fe06be4 | ||
|
|
e5764ac495 | ||
|
|
2ff7cb8956 | ||
|
|
3064ab4b25 | ||
|
|
d2f8d2e903 | ||
|
|
036c7796e5 | ||
|
|
356dd46537 | ||
|
|
bb30e1abb8 | ||
|
|
84d225e389 | ||
|
|
dcf2780cac | ||
|
|
3e421c770b | ||
|
|
19cb0e873a | ||
|
|
ed81dbc4a2 | ||
|
|
a93d5b87e1 | ||
|
|
d40a52e403 | ||
|
|
a4a3797cc1 | ||
|
|
bd29e5f13a | ||
|
|
ce13ee8a55 | ||
|
|
e5ed5fbc6a | ||
|
|
ff7eca2f08 | ||
|
|
06be217030 | ||
|
|
4880052559 | ||
|
|
147043857b | ||
|
|
1bfa1a7746 | ||
|
|
3747a6a454 | ||
|
|
f1e6246962 | ||
|
|
d2c6190b59 | ||
|
|
0f8247ce69 | ||
|
|
dae3be99ce | ||
|
|
6e625e0cc9 | ||
|
|
a602101695 | ||
|
|
48d86fdbf5 | ||
|
|
d6cfde0f94 | ||
|
|
1b9b4fdd39 | ||
|
|
8bb551eb10 | ||
|
|
6177035f84 | ||
|
|
e6d3ce5918 | ||
|
|
9e08143981 | ||
|
|
2014a48d22 | ||
|
|
b7e1202cf1 | ||
|
|
44b994414d | ||
|
|
a7265c2493 | ||
|
|
261ec270c5 | ||
|
|
356be511a8 | ||
|
|
f896e72013 | ||
|
|
187a895265 | ||
|
|
6224f8ca51 | ||
|
|
3b27e6e466 | ||
|
|
4e53deec9d | ||
|
|
2cafa78339 | ||
|
|
f3f86017b6 | ||
|
|
5479080eb2 | ||
|
|
3cb3e8a7f9 | ||
|
|
6a907f1fed | ||
|
|
241f845c08 | ||
|
|
623f63abb3 | ||
|
|
293adc3a99 | ||
|
|
dee9f90a0b | ||
|
|
a7348f0eb9 | ||
|
|
7457735c04 | ||
|
|
0f389b2a48 | ||
|
|
bfe01899a4 | ||
|
|
9531762c44 | ||
|
|
e59a35e804 | ||
|
|
21f5f5fe5e | ||
|
|
e6483fed98 | ||
|
|
98bc04697e | ||
|
|
38e9b59b89 | ||
|
|
118b22fe56 | ||
|
|
8062694331 | ||
|
|
e576235307 | ||
|
|
e87502e7bf | ||
|
|
400ed9e999 | ||
|
|
5b01ad23c4 | ||
|
|
9a06fa4704 | ||
|
|
c5555ad365 | ||
|
|
9c6db1d730 | ||
|
|
30cfe69e26 | ||
|
|
e45049a602 | ||
|
|
82129ff3bd | ||
|
|
593b603295 | ||
|
|
54b2e41afd | ||
|
|
ede6e6dd87 | ||
|
|
e18ea88735 | ||
|
|
750dfe746e | ||
|
|
53404f1002 | ||
|
|
5623784c59 | ||
|
|
d122de04e4 | ||
|
|
2fa9774955 |
Binary file not shown.
|
After Width: | Height: | Size: 1.5 MiB |
109
.doc/itop-version-history.md
Normal file
109
.doc/itop-version-history.md
Normal file
@@ -0,0 +1,109 @@
|
|||||||
|
# iTop version history
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
%%{init: { 'logLevel': 'debug', 'theme': 'base', 'themeVariables': {
|
||||||
|
'git0': 'lawngreen',
|
||||||
|
'git3': 'dodgerblue',
|
||||||
|
'git4': 'grey',
|
||||||
|
'git5': 'grey',
|
||||||
|
'git6': 'grey',
|
||||||
|
'git7': 'grey'
|
||||||
|
}, 'gitGraph': {'showBranches': true,'mainBranchName': 'develop','rotateCommitLabel': true}} }%%
|
||||||
|
gitGraph
|
||||||
|
commit id: "2016-07-06" tag: "2.3.0" type: HIGHLIGHT
|
||||||
|
branch support/2.3 order: 900
|
||||||
|
commit id: "2016-07-08" tag: "2.3.1"
|
||||||
|
commit id: "2016-12-22" tag: "2.3.3"
|
||||||
|
commit id: "2017-04-14" tag: "2.3.4"
|
||||||
|
checkout develop
|
||||||
|
commit id: "2017-07-12" tag: "2.4.0-beta" type: REVERSE
|
||||||
|
commit id: "2017-11-16" tag: "2.4.0" type: HIGHLIGHT
|
||||||
|
branch support/2.4 order: 890
|
||||||
|
commit id: "2018-02-14" tag: "2.4.1"
|
||||||
|
checkout develop
|
||||||
|
commit id: "2018-04-25" tag: "2.5.0-beta" type: REVERSE
|
||||||
|
checkout support/2.4
|
||||||
|
commit id: "2018-06-14" tag: "2.4.2"
|
||||||
|
checkout develop
|
||||||
|
commit id: "2018-06-27" tag: "2.5.0" type: HIGHLIGHT
|
||||||
|
branch support/2.5 order: 880
|
||||||
|
checkout develop
|
||||||
|
commit id: "2019-01-09" tag: "2.6.0" type: HIGHLIGHT
|
||||||
|
branch support/2.6 order: 870
|
||||||
|
commit id: "2019-03-28" tag: "2.6.1"
|
||||||
|
checkout develop
|
||||||
|
commit id: "2019-12-18" tag: "2.7.0-beta" type: REVERSE
|
||||||
|
checkout support/2.5
|
||||||
|
commit id: "2020-01-22" tag: "2.5.4"
|
||||||
|
checkout support/2.6
|
||||||
|
commit id: "2020-01-23" tag: "2.6.3"
|
||||||
|
checkout develop
|
||||||
|
commit id: "2020-01-29" tag: "2.7.0-beta2" type: REVERSE
|
||||||
|
commit id: "2020-04-01" tag: "2.7.0-1" type: HIGHLIGHT
|
||||||
|
checkout support/2.6
|
||||||
|
commit id: "2020-04-22" tag: "2.6.4"
|
||||||
|
checkout develop
|
||||||
|
branch support/2.7 order: 860
|
||||||
|
commit id: "2020-06-26" tag: "2.7.1"
|
||||||
|
checkout support/2.7
|
||||||
|
commit id: "2020-12-09" tag: "2.7.3"
|
||||||
|
commit id: "2021-03-31" tag: "2.7.4"
|
||||||
|
checkout develop
|
||||||
|
commit id: "2021-04-06" tag: "3.0.0-beta" type: REVERSE
|
||||||
|
checkout support/2.7
|
||||||
|
commit id: "2021-07-05" tag: "2.7.5"
|
||||||
|
checkout develop
|
||||||
|
commit id: "2021-07-05." tag: "3.0.0-beta2" type: REVERSE
|
||||||
|
checkout support/2.7
|
||||||
|
commit id: "2021-12-17" tag: "2.7.6"
|
||||||
|
checkout develop
|
||||||
|
commit id: "2022-01-04" tag: "3.0.0" type: HIGHLIGHT
|
||||||
|
branch support/3.0 order: 850
|
||||||
|
commit id: "2022-04-08" tag: "3.0.1"
|
||||||
|
checkout support/2.7
|
||||||
|
commit id: "2022-07-11" tag: "2.7.7"
|
||||||
|
checkout support/3.0
|
||||||
|
commit id: "2022-09-12" tag: "3.0.2-1"
|
||||||
|
checkout develop
|
||||||
|
checkout support/2.7
|
||||||
|
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"
|
||||||
|
checkout develop
|
||||||
|
commit id: "2024-01-15" tag: "Start 3.2" type: HIGHLIGHT
|
||||||
|
branch support/3.2 order: 830
|
||||||
|
checkout support/2.7
|
||||||
|
commit id: "2024-01-17a" tag: "2.7.10"
|
||||||
|
checkout support/3.0
|
||||||
|
commit id: "2024-01-17b" tag: "3.0.4"
|
||||||
|
checkout support/3.2
|
||||||
|
commit id: "2024-06-25" tag: "3.2.0-beta1" type: REVERSE
|
||||||
|
commit id: "2024-08-07" tag: "3.2.0"
|
||||||
|
commit id: "2024-09-13" tag: "3.2.0-2"
|
||||||
|
checkout support/3.1
|
||||||
|
commit id: "2024-09-27" tag: "3.1.2"
|
||||||
|
checkout support/2.7
|
||||||
|
commit id: "2024-09-28" tag: "2.7.11"
|
||||||
|
checkout support/2.7
|
||||||
|
commit id: "2025-02-25" tag: "2.7.12"
|
||||||
|
checkout support/3.1
|
||||||
|
commit id: "2025-02-25 " tag: "3.1.3"
|
||||||
|
checkout support/3.2
|
||||||
|
commit id: "2025-02-25 " tag: "3.2.1"
|
||||||
|
commit id: "2025-04-08" tag: "3.2.1-1"
|
||||||
|
commit id: "2025-08-19" tag: "3.2.2-1"
|
||||||
|
checkout support/2.7
|
||||||
|
commit id: "2025-10-07" tag: "2.7.13"
|
||||||
|
```
|
||||||
|
|
||||||
|
To learn more, check the [iTop community versions history on the official wiki](https://www.itophub.io/wiki/page?id=latest:release:start).
|
||||||
2
.github/pull_request_template.md
vendored
2
.github/pull_request_template.md
vendored
@@ -9,7 +9,7 @@ Any PRs not following the guidelines or with missing information will not be con
|
|||||||
## Base information
|
## Base information
|
||||||
| Question | Answer
|
| Question | Answer
|
||||||
|---------------------------------------------------------------|--------
|
|---------------------------------------------------------------|--------
|
||||||
| Related to a SourceForge thead / Another PR / Combodo ticket? | <!-- Put the URL -->
|
| Related to a SourceForge thread / Another PR / Combodo ticket? | <!-- Put the URL -->
|
||||||
| Type of change? | Bug fix / Enhancement / Translations
|
| Type of change? | Bug fix / Enhancement / Translations
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
14
.github/workflows/action.yml
vendored
14
.github/workflows/action.yml
vendored
@@ -26,13 +26,23 @@ jobs:
|
|||||||
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
- name: Add internal tag if member
|
- name: Add internal tag if member of the organization
|
||||||
if: env.is_member == 'true'
|
if: env.is_member == 'true'
|
||||||
run: |
|
run: |
|
||||||
curl -X POST -H "Authorization: token ${{ secrets.PR_AUTOMATICALLY_ADD_TO_PROJECT }}" \
|
curl -X POST -H "Authorization: token ${{ secrets.PR_AUTOMATICALLY_ADD_TO_PROJECT }}" \
|
||||||
-H "Accept: application/vnd.github.v3+json" \
|
-H "Accept: application/vnd.github.v3+json" \
|
||||||
https://api.github.com/repos/Combodo/iTop/issues/${{ github.event.pull_request.number }}/labels \
|
https://api.github.com/repos/Combodo/iTop/issues/${{ github.event.pull_request.number }}/labels \
|
||||||
-d '{"labels":["internal"]}'
|
-d '{"labels":["internal"]}'
|
||||||
|
|
||||||
|
- name: Set PR author as assignee if member of the organization
|
||||||
|
if: env.is_member == 'true'
|
||||||
|
run: |
|
||||||
|
curl -L \
|
||||||
|
-X POST \
|
||||||
|
-H "Accept: application/vnd.github+json" \
|
||||||
|
-H "Authorization: Bearer ${{ secrets.PR_AUTOMATICALLY_ADD_TO_PROJECT }}" \
|
||||||
|
https://api.github.com/repos/Combodo/iTop/issues/${{ github.event.pull_request.number }}/assignees \
|
||||||
|
-d '{"assignees":["${{ github.event.pull_request.user.login }}"]}'
|
||||||
env:
|
env:
|
||||||
is_member: ${{ env.is_member }}
|
is_member: ${{ env.is_member }}
|
||||||
|
|
||||||
@@ -40,4 +50,4 @@ jobs:
|
|||||||
uses: actions/add-to-project@v1.0.2
|
uses: actions/add-to-project@v1.0.2
|
||||||
with:
|
with:
|
||||||
project-url: ${{ env.project_url }}
|
project-url: ${{ env.project_url }}
|
||||||
github-token: ${{ secrets.PR_AUTOMATICALLY_ADD_TO_PROJECT }}
|
github-token: ${{ secrets.PR_AUTOMATICALLY_ADD_TO_PROJECT }}
|
||||||
|
|||||||
3
.gitignore
vendored
3
.gitignore
vendored
@@ -58,6 +58,9 @@ tests/*/vendor/*
|
|||||||
/tests/php-unit-tests/phpunit.xml
|
/tests/php-unit-tests/phpunit.xml
|
||||||
/tests/php-unit-tests/postbuild_integration.xml
|
/tests/php-unit-tests/postbuild_integration.xml
|
||||||
|
|
||||||
|
# PHP CS Fixer: Cache file
|
||||||
|
/.php-cs-fixer.cache
|
||||||
|
|
||||||
|
|
||||||
# Jetbrains
|
# Jetbrains
|
||||||
/.idea/**
|
/.idea/**
|
||||||
|
|||||||
@@ -25,12 +25,34 @@
|
|||||||
|
|
||||||
|
|
||||||
if (count($argv) === 1) {
|
if (count($argv) === 1) {
|
||||||
echo '⚠ You must pass the base tag/sha1 as parameter';
|
echo "⚠ You must pass the base tag/sha1 as parameter\n";
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
$sBaseReference = $argv[1];
|
$sBaseReference = $argv[1];
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Replace the Github emojis codes by their UTF-8 character equivalent
|
||||||
|
*/
|
||||||
|
function ReplaceGitmojis(string $sLine)
|
||||||
|
{
|
||||||
|
static $aGitmojis = null;
|
||||||
|
|
||||||
|
if ($aGitmojis === null) {
|
||||||
|
$aRawGitmojis = json_decode(trim(file_get_contents(__DIR__.'/gitmojis.json')), true);
|
||||||
|
if ($aRawGitmojis === false) {
|
||||||
|
echo "\nFailed to parse ".__DIR__."/gitmojis.json, emoji codes will not be replaced by their unicode equivalent.\n";
|
||||||
|
} else {
|
||||||
|
foreach($aRawGitmojis["gitmojis"] as $aGitmoji) {
|
||||||
|
$aGitmojis[$aGitmoji['code']] = $aGitmoji['emoji'];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (is_array($aGitmojis)) {
|
||||||
|
return str_replace(array_keys($aGitmojis), array_values($aGitmojis), $sLine);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//--- Get log
|
//--- Get log
|
||||||
$sGitLogCommand = 'git log --decorate --pretty="%h;%s" --date-order --no-merges '.$sBaseReference.'..HEAD';
|
$sGitLogCommand = 'git log --decorate --pretty="%h;%s" --date-order --no-merges '.$sBaseReference.'..HEAD';
|
||||||
$sGitLogRaw = shell_exec($sGitLogCommand);
|
$sGitLogRaw = shell_exec($sGitLogCommand);
|
||||||
@@ -73,5 +95,5 @@ echo "\n";
|
|||||||
echo "# Logs line without bug referenced\n";
|
echo "# Logs line without bug referenced\n";
|
||||||
echo "sha1;subject\n";
|
echo "sha1;subject\n";
|
||||||
foreach ($aLogLineNoBug as $sLogLine) {
|
foreach ($aLogLineNoBug as $sLogLine) {
|
||||||
echo "$sLogLine\n";
|
echo ReplaceGitmojis($sLogLine)."\n";
|
||||||
}
|
}
|
||||||
|
|||||||
589
.make/release/gitmojis.json
Normal file
589
.make/release/gitmojis.json
Normal file
@@ -0,0 +1,589 @@
|
|||||||
|
{
|
||||||
|
"$schema": "https://gitmoji.dev/api/gitmojis/schema",
|
||||||
|
"gitmojis": [
|
||||||
|
{
|
||||||
|
"emoji": "🎨",
|
||||||
|
"entity": "🎨",
|
||||||
|
"code": ":art:",
|
||||||
|
"description": "Improve structure / format of the code.",
|
||||||
|
"name": "art",
|
||||||
|
"semver": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"emoji": "⚡️",
|
||||||
|
"entity": "⚡",
|
||||||
|
"code": ":zap:",
|
||||||
|
"description": "Improve performance.",
|
||||||
|
"name": "zap",
|
||||||
|
"semver": "patch"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"emoji": "🔥",
|
||||||
|
"entity": "🔥",
|
||||||
|
"code": ":fire:",
|
||||||
|
"description": "Remove code or files.",
|
||||||
|
"name": "fire",
|
||||||
|
"semver": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"emoji": "🐛",
|
||||||
|
"entity": "🐛",
|
||||||
|
"code": ":bug:",
|
||||||
|
"description": "Fix a bug.",
|
||||||
|
"name": "bug",
|
||||||
|
"semver": "patch"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"emoji": "🚑️",
|
||||||
|
"entity": "🚑",
|
||||||
|
"code": ":ambulance:",
|
||||||
|
"description": "Critical hotfix.",
|
||||||
|
"name": "ambulance",
|
||||||
|
"semver": "patch"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"emoji": "✨",
|
||||||
|
"entity": "✨",
|
||||||
|
"code": ":sparkles:",
|
||||||
|
"description": "Introduce new features.",
|
||||||
|
"name": "sparkles",
|
||||||
|
"semver": "minor"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"emoji": "📝",
|
||||||
|
"entity": "📝",
|
||||||
|
"code": ":memo:",
|
||||||
|
"description": "Add or update documentation.",
|
||||||
|
"name": "memo",
|
||||||
|
"semver": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"emoji": "🚀",
|
||||||
|
"entity": "🚀",
|
||||||
|
"code": ":rocket:",
|
||||||
|
"description": "Deploy stuff.",
|
||||||
|
"name": "rocket",
|
||||||
|
"semver": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"emoji": "💄",
|
||||||
|
"entity": "&#ff99cc;",
|
||||||
|
"code": ":lipstick:",
|
||||||
|
"description": "Add or update the UI and style files.",
|
||||||
|
"name": "lipstick",
|
||||||
|
"semver": "patch"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"emoji": "🎉",
|
||||||
|
"entity": "🎉",
|
||||||
|
"code": ":tada:",
|
||||||
|
"description": "Begin a project.",
|
||||||
|
"name": "tada",
|
||||||
|
"semver": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"emoji": "✅",
|
||||||
|
"entity": "✅",
|
||||||
|
"code": ":white_check_mark:",
|
||||||
|
"description": "Add, update, or pass tests.",
|
||||||
|
"name": "white-check-mark",
|
||||||
|
"semver": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"emoji": "🔒️",
|
||||||
|
"entity": "🔒",
|
||||||
|
"code": ":lock:",
|
||||||
|
"description": "Fix security or privacy issues.",
|
||||||
|
"name": "lock",
|
||||||
|
"semver": "patch"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"emoji": "🔐",
|
||||||
|
"entity": "🔐",
|
||||||
|
"code": ":closed_lock_with_key:",
|
||||||
|
"description": "Add or update secrets.",
|
||||||
|
"name": "closed-lock-with-key",
|
||||||
|
"semver": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"emoji": "🔖",
|
||||||
|
"entity": "🔖",
|
||||||
|
"code": ":bookmark:",
|
||||||
|
"description": "Release / Version tags.",
|
||||||
|
"name": "bookmark",
|
||||||
|
"semver": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"emoji": "🚨",
|
||||||
|
"entity": "🚨",
|
||||||
|
"code": ":rotating_light:",
|
||||||
|
"description": "Fix compiler / linter warnings.",
|
||||||
|
"name": "rotating-light",
|
||||||
|
"semver": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"emoji": "🚧",
|
||||||
|
"entity": "🚧",
|
||||||
|
"code": ":construction:",
|
||||||
|
"description": "Work in progress.",
|
||||||
|
"name": "construction",
|
||||||
|
"semver": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"emoji": "💚",
|
||||||
|
"entity": "💚",
|
||||||
|
"code": ":green_heart:",
|
||||||
|
"description": "Fix CI Build.",
|
||||||
|
"name": "green-heart",
|
||||||
|
"semver": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"emoji": "⬇️",
|
||||||
|
"entity": "⬇️",
|
||||||
|
"code": ":arrow_down:",
|
||||||
|
"description": "Downgrade dependencies.",
|
||||||
|
"name": "arrow-down",
|
||||||
|
"semver": "patch"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"emoji": "⬆️",
|
||||||
|
"entity": "⬆️",
|
||||||
|
"code": ":arrow_up:",
|
||||||
|
"description": "Upgrade dependencies.",
|
||||||
|
"name": "arrow-up",
|
||||||
|
"semver": "patch"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"emoji": "📌",
|
||||||
|
"entity": "📌",
|
||||||
|
"code": ":pushpin:",
|
||||||
|
"description": "Pin dependencies to specific versions.",
|
||||||
|
"name": "pushpin",
|
||||||
|
"semver": "patch"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"emoji": "👷",
|
||||||
|
"entity": "👷",
|
||||||
|
"code": ":construction_worker:",
|
||||||
|
"description": "Add or update CI build system.",
|
||||||
|
"name": "construction-worker",
|
||||||
|
"semver": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"emoji": "📈",
|
||||||
|
"entity": "📈",
|
||||||
|
"code": ":chart_with_upwards_trend:",
|
||||||
|
"description": "Add or update analytics or track code.",
|
||||||
|
"name": "chart-with-upwards-trend",
|
||||||
|
"semver": "patch"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"emoji": "♻️",
|
||||||
|
"entity": "♻",
|
||||||
|
"code": ":recycle:",
|
||||||
|
"description": "Refactor code.",
|
||||||
|
"name": "recycle",
|
||||||
|
"semver": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"emoji": "➕",
|
||||||
|
"entity": "➕",
|
||||||
|
"code": ":heavy_plus_sign:",
|
||||||
|
"description": "Add a dependency.",
|
||||||
|
"name": "heavy-plus-sign",
|
||||||
|
"semver": "patch"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"emoji": "➖",
|
||||||
|
"entity": "➖",
|
||||||
|
"code": ":heavy_minus_sign:",
|
||||||
|
"description": "Remove a dependency.",
|
||||||
|
"name": "heavy-minus-sign",
|
||||||
|
"semver": "patch"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"emoji": "🔧",
|
||||||
|
"entity": "🔧",
|
||||||
|
"code": ":wrench:",
|
||||||
|
"description": "Add or update configuration files.",
|
||||||
|
"name": "wrench",
|
||||||
|
"semver": "patch"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"emoji": "🔨",
|
||||||
|
"entity": "🔨",
|
||||||
|
"code": ":hammer:",
|
||||||
|
"description": "Add or update development scripts.",
|
||||||
|
"name": "hammer",
|
||||||
|
"semver": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"emoji": "🌐",
|
||||||
|
"entity": "🌐",
|
||||||
|
"code": ":globe_with_meridians:",
|
||||||
|
"description": "Internationalization and localization.",
|
||||||
|
"name": "globe-with-meridians",
|
||||||
|
"semver": "patch"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"emoji": "✏️",
|
||||||
|
"entity": "",
|
||||||
|
"code": ":pencil2:",
|
||||||
|
"description": "Fix typos.",
|
||||||
|
"name": "pencil2",
|
||||||
|
"semver": "patch"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"emoji": "💩",
|
||||||
|
"entity": "",
|
||||||
|
"code": ":poop:",
|
||||||
|
"description": "Write bad code that needs to be improved.",
|
||||||
|
"name": "poop",
|
||||||
|
"semver": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"emoji": "⏪️",
|
||||||
|
"entity": "⏪",
|
||||||
|
"code": ":rewind:",
|
||||||
|
"description": "Revert changes.",
|
||||||
|
"name": "rewind",
|
||||||
|
"semver": "patch"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"emoji": "🔀",
|
||||||
|
"entity": "🔀",
|
||||||
|
"code": ":twisted_rightwards_arrows:",
|
||||||
|
"description": "Merge branches.",
|
||||||
|
"name": "twisted-rightwards-arrows",
|
||||||
|
"semver": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"emoji": "📦️",
|
||||||
|
"entity": "F4E6;",
|
||||||
|
"code": ":package:",
|
||||||
|
"description": "Add or update compiled files or packages.",
|
||||||
|
"name": "package",
|
||||||
|
"semver": "patch"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"emoji": "👽️",
|
||||||
|
"entity": "F47D;",
|
||||||
|
"code": ":alien:",
|
||||||
|
"description": "Update code due to external API changes.",
|
||||||
|
"name": "alien",
|
||||||
|
"semver": "patch"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"emoji": "🚚",
|
||||||
|
"entity": "F69A;",
|
||||||
|
"code": ":truck:",
|
||||||
|
"description": "Move or rename resources (e.g.: files, paths, routes).",
|
||||||
|
"name": "truck",
|
||||||
|
"semver": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"emoji": "📄",
|
||||||
|
"entity": "F4C4;",
|
||||||
|
"code": ":page_facing_up:",
|
||||||
|
"description": "Add or update license.",
|
||||||
|
"name": "page-facing-up",
|
||||||
|
"semver": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"emoji": "💥",
|
||||||
|
"entity": "💥",
|
||||||
|
"code": ":boom:",
|
||||||
|
"description": "Introduce breaking changes.",
|
||||||
|
"name": "boom",
|
||||||
|
"semver": "major"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"emoji": "🍱",
|
||||||
|
"entity": "F371",
|
||||||
|
"code": ":bento:",
|
||||||
|
"description": "Add or update assets.",
|
||||||
|
"name": "bento",
|
||||||
|
"semver": "patch"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"emoji": "♿️",
|
||||||
|
"entity": "♿",
|
||||||
|
"code": ":wheelchair:",
|
||||||
|
"description": "Improve accessibility.",
|
||||||
|
"name": "wheelchair",
|
||||||
|
"semver": "patch"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"emoji": "💡",
|
||||||
|
"entity": "💡",
|
||||||
|
"code": ":bulb:",
|
||||||
|
"description": "Add or update comments in source code.",
|
||||||
|
"name": "bulb",
|
||||||
|
"semver": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"emoji": "🍻",
|
||||||
|
"entity": "🍻",
|
||||||
|
"code": ":beers:",
|
||||||
|
"description": "Write code drunkenly.",
|
||||||
|
"name": "beers",
|
||||||
|
"semver": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"emoji": "💬",
|
||||||
|
"entity": "💬",
|
||||||
|
"code": ":speech_balloon:",
|
||||||
|
"description": "Add or update text and literals.",
|
||||||
|
"name": "speech-balloon",
|
||||||
|
"semver": "patch"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"emoji": "🗃️",
|
||||||
|
"entity": "🗃",
|
||||||
|
"code": ":card_file_box:",
|
||||||
|
"description": "Perform database related changes.",
|
||||||
|
"name": "card-file-box",
|
||||||
|
"semver": "patch"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"emoji": "🔊",
|
||||||
|
"entity": "🔊",
|
||||||
|
"code": ":loud_sound:",
|
||||||
|
"description": "Add or update logs.",
|
||||||
|
"name": "loud-sound",
|
||||||
|
"semver": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"emoji": "🔇",
|
||||||
|
"entity": "🔇",
|
||||||
|
"code": ":mute:",
|
||||||
|
"description": "Remove logs.",
|
||||||
|
"name": "mute",
|
||||||
|
"semver": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"emoji": "👥",
|
||||||
|
"entity": "👥",
|
||||||
|
"code": ":busts_in_silhouette:",
|
||||||
|
"description": "Add or update contributor(s).",
|
||||||
|
"name": "busts-in-silhouette",
|
||||||
|
"semver": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"emoji": "🚸",
|
||||||
|
"entity": "🚸",
|
||||||
|
"code": ":children_crossing:",
|
||||||
|
"description": "Improve user experience / usability.",
|
||||||
|
"name": "children-crossing",
|
||||||
|
"semver": "patch"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"emoji": "🏗️",
|
||||||
|
"entity": "f3d7;",
|
||||||
|
"code": ":building_construction:",
|
||||||
|
"description": "Make architectural changes.",
|
||||||
|
"name": "building-construction",
|
||||||
|
"semver": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"emoji": "📱",
|
||||||
|
"entity": "📱",
|
||||||
|
"code": ":iphone:",
|
||||||
|
"description": "Work on responsive design.",
|
||||||
|
"name": "iphone",
|
||||||
|
"semver": "patch"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"emoji": "🤡",
|
||||||
|
"entity": "🤡",
|
||||||
|
"code": ":clown_face:",
|
||||||
|
"description": "Mock things.",
|
||||||
|
"name": "clown-face",
|
||||||
|
"semver": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"emoji": "🥚",
|
||||||
|
"entity": "🥚",
|
||||||
|
"code": ":egg:",
|
||||||
|
"description": "Add or update an easter egg.",
|
||||||
|
"name": "egg",
|
||||||
|
"semver": "patch"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"emoji": "🙈",
|
||||||
|
"entity": "bdfe7;",
|
||||||
|
"code": ":see_no_evil:",
|
||||||
|
"description": "Add or update a .gitignore file.",
|
||||||
|
"name": "see-no-evil",
|
||||||
|
"semver": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"emoji": "📸",
|
||||||
|
"entity": "📸",
|
||||||
|
"code": ":camera_flash:",
|
||||||
|
"description": "Add or update snapshots.",
|
||||||
|
"name": "camera-flash",
|
||||||
|
"semver": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"emoji": "⚗️",
|
||||||
|
"entity": "⚗",
|
||||||
|
"code": ":alembic:",
|
||||||
|
"description": "Perform experiments.",
|
||||||
|
"name": "alembic",
|
||||||
|
"semver": "patch"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"emoji": "🔍️",
|
||||||
|
"entity": "🔍",
|
||||||
|
"code": ":mag:",
|
||||||
|
"description": "Improve SEO.",
|
||||||
|
"name": "mag",
|
||||||
|
"semver": "patch"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"emoji": "🏷️",
|
||||||
|
"entity": "🏷",
|
||||||
|
"code": ":label:",
|
||||||
|
"description": "Add or update types.",
|
||||||
|
"name": "label",
|
||||||
|
"semver": "patch"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"emoji": "🌱",
|
||||||
|
"entity": "🌱",
|
||||||
|
"code": ":seedling:",
|
||||||
|
"description": "Add or update seed files.",
|
||||||
|
"name": "seedling",
|
||||||
|
"semver": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"emoji": "🚩",
|
||||||
|
"entity": "🚩",
|
||||||
|
"code": ":triangular_flag_on_post:",
|
||||||
|
"description": "Add, update, or remove feature flags.",
|
||||||
|
"name": "triangular-flag-on-post",
|
||||||
|
"semver": "patch"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"emoji": "🥅",
|
||||||
|
"entity": "🥅",
|
||||||
|
"code": ":goal_net:",
|
||||||
|
"description": "Catch errors.",
|
||||||
|
"name": "goal-net",
|
||||||
|
"semver": "patch"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"emoji": "💫",
|
||||||
|
"entity": "💫",
|
||||||
|
"code": ":dizzy:",
|
||||||
|
"description": "Add or update animations and transitions.",
|
||||||
|
"name": "dizzy",
|
||||||
|
"semver": "patch"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"emoji": "🗑️",
|
||||||
|
"entity": "🗑",
|
||||||
|
"code": ":wastebasket:",
|
||||||
|
"description": "Deprecate code that needs to be cleaned up.",
|
||||||
|
"name": "wastebasket",
|
||||||
|
"semver": "patch"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"emoji": "🛂",
|
||||||
|
"entity": "🛂",
|
||||||
|
"code": ":passport_control:",
|
||||||
|
"description": "Work on code related to authorization, roles and permissions.",
|
||||||
|
"name": "passport-control",
|
||||||
|
"semver": "patch"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"emoji": "🩹",
|
||||||
|
"entity": "🩹",
|
||||||
|
"code": ":adhesive_bandage:",
|
||||||
|
"description": "Simple fix for a non-critical issue.",
|
||||||
|
"name": "adhesive-bandage",
|
||||||
|
"semver": "patch"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"emoji": "🧐",
|
||||||
|
"entity": "🧐",
|
||||||
|
"code": ":monocle_face:",
|
||||||
|
"description": "Data exploration/inspection.",
|
||||||
|
"name": "monocle-face",
|
||||||
|
"semver": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"emoji": "⚰️",
|
||||||
|
"entity": "⚰",
|
||||||
|
"code": ":coffin:",
|
||||||
|
"description": "Remove dead code.",
|
||||||
|
"name": "coffin",
|
||||||
|
"semver": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"emoji": "🧪",
|
||||||
|
"entity": "🧪",
|
||||||
|
"code": ":test_tube:",
|
||||||
|
"description": "Add a failing test.",
|
||||||
|
"name": "test-tube",
|
||||||
|
"semver": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"emoji": "👔",
|
||||||
|
"entity": "👔",
|
||||||
|
"code": ":necktie:",
|
||||||
|
"description": "Add or update business logic.",
|
||||||
|
"name": "necktie",
|
||||||
|
"semver": "patch"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"emoji": "🩺",
|
||||||
|
"entity": "🩺",
|
||||||
|
"code": ":stethoscope:",
|
||||||
|
"description": "Add or update healthcheck.",
|
||||||
|
"name": "stethoscope",
|
||||||
|
"semver": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"emoji": "🧱",
|
||||||
|
"entity": "🧱",
|
||||||
|
"code": ":bricks:",
|
||||||
|
"description": "Infrastructure related changes.",
|
||||||
|
"name": "bricks",
|
||||||
|
"semver": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"emoji": "🧑💻",
|
||||||
|
"entity": "🧑‍💻",
|
||||||
|
"code": ":technologist:",
|
||||||
|
"description": "Improve developer experience.",
|
||||||
|
"name": "technologist",
|
||||||
|
"semver": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"emoji": "💸",
|
||||||
|
"entity": "💸",
|
||||||
|
"code": ":money_with_wings:",
|
||||||
|
"description": "Add sponsorships or money related infrastructure.",
|
||||||
|
"name": "money-with-wings",
|
||||||
|
"semver": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"emoji": "🧵",
|
||||||
|
"entity": "🧵",
|
||||||
|
"code": ":thread:",
|
||||||
|
"description": "Add or update code related to multithreading or concurrency.",
|
||||||
|
"name": "thread",
|
||||||
|
"semver": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"emoji": "🦺",
|
||||||
|
"entity": "🦺",
|
||||||
|
"code": ":safety_vest:",
|
||||||
|
"description": "Add or update code related to validation.",
|
||||||
|
"name": "safety-vest",
|
||||||
|
"semver": null
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -199,7 +199,7 @@ class DatamodelsXmlFiles extends AbstractGlobFileVersionUpdater
|
|||||||
libxml_clear_errors();
|
libxml_clear_errors();
|
||||||
$oFileXml->formatOutput = true;
|
$oFileXml->formatOutput = true;
|
||||||
$oFileXml->preserveWhiteSpace = false;
|
$oFileXml->preserveWhiteSpace = false;
|
||||||
$oFileXml->loadXML($sFileContent);
|
$oFileXml->loadXML($sFileContent, LIBXML_BIGLINES);
|
||||||
|
|
||||||
$oFileItopFormat = new iTopDesignFormat($oFileXml);
|
$oFileItopFormat = new iTopDesignFormat($oFileXml);
|
||||||
|
|
||||||
|
|||||||
16
.phpstorm.meta.php
Normal file
16
.phpstorm.meta.php
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @copyright Copyright (C) 2010-2025 Combodo SAS
|
||||||
|
* @license http://opensource.org/licenses/AGPL-3.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace PHPSTORM_META
|
||||||
|
{
|
||||||
|
override(\MetaModel::NewObject(0), map([
|
||||||
|
'' => '@',
|
||||||
|
]));
|
||||||
|
override(\MetaModel::GetObject(0), map([
|
||||||
|
'' => '@',
|
||||||
|
]));
|
||||||
|
}
|
||||||
@@ -5,7 +5,7 @@ You want to contribute to iTop? Many thanks to you! 🎉 👍
|
|||||||
Here are some guidelines that will help us integrate your work!
|
Here are some guidelines that will help us integrate your work!
|
||||||
|
|
||||||
|
|
||||||
## Contributions
|
|
||||||
|
|
||||||
### Subjects
|
### Subjects
|
||||||
You are welcome to create pull requests on any of those subjects:
|
You are welcome to create pull requests on any of those subjects:
|
||||||
@@ -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 2024:
|
Here is the design of each stickers for year 2024:
|
||||||
|
|
||||||

|

|
||||||
|
|||||||
24
README.md
24
README.md
@@ -1,4 +1,4 @@
|
|||||||
<p align="center"><a href="https://www.combodo.com/itop-193" target="_blank">
|
<p align="center"><a href="https://combodo.com" target="_blank">
|
||||||
<picture>
|
<picture>
|
||||||
<source media="(prefers-color-scheme: dark)" srcset="/images/logos/logo-itop-baseline-light.svg">
|
<source media="(prefers-color-scheme: dark)" srcset="/images/logos/logo-itop-baseline-light.svg">
|
||||||
<source media="(prefers-color-scheme: light)" srcset="/images/logos/logo-itop-baseline-dark.svg">
|
<source media="(prefers-color-scheme: light)" srcset="/images/logos/logo-itop-baseline-dark.svg">
|
||||||
@@ -53,7 +53,7 @@ iTop also offers mass import tools to help you become even more efficient.
|
|||||||
[4]: https://www.itophub.io/wiki/page?id=latest:install:requirements
|
[4]: https://www.itophub.io/wiki/page?id=latest:install:requirements
|
||||||
[5]: https://www.itophub.io/wiki
|
[5]: https://www.itophub.io/wiki
|
||||||
[6]: https://store.itophub.io/en_US/
|
[6]: https://store.itophub.io/en_US/
|
||||||
[7]: .doc/itop-version-history.md
|
[7]: itop-version-history.md
|
||||||
|
|
||||||
[10]: https://www.itophub.io/wiki/page?id=latest%3Adatamodel%3Astart#configuration_management_cmdb
|
[10]: https://www.itophub.io/wiki/page?id=latest%3Adatamodel%3Astart#configuration_management_cmdb
|
||||||
[11]: https://www.itophub.io/wiki/page?id=latest%3Adatamodel%3Astart#ticketing
|
[11]: https://www.itophub.io/wiki/page?id=latest%3Adatamodel%3Astart#ticketing
|
||||||
@@ -80,7 +80,9 @@ We would like to give a special thank you 🤗 to the people from the community
|
|||||||
|
|
||||||
### Names
|
### Names
|
||||||
|
|
||||||
|
- Al Hallak, Amr (a.k.a [@v4yne1](https://github.com/v4yne1))
|
||||||
- Alves, David
|
- Alves, David
|
||||||
|
- Audon, Florian
|
||||||
- Beck, Pedro
|
- Beck, Pedro
|
||||||
- Beer, Christian (a.k.a [@ChristianBeer](https://www.github.com/ChristianBeer))
|
- Beer, Christian (a.k.a [@ChristianBeer](https://www.github.com/ChristianBeer))
|
||||||
- Bilger, Jean-François
|
- Bilger, Jean-François
|
||||||
@@ -92,19 +94,27 @@ We would like to give a special thank you 🤗 to the people from the community
|
|||||||
- Colantoni, Maria Laura
|
- Colantoni, Maria Laura
|
||||||
- Couronné, Guy
|
- Couronné, Guy
|
||||||
- Dejin, Bie (a.k.a [@bdejin](https://github.com/bdejin))
|
- Dejin, Bie (a.k.a [@bdejin](https://github.com/bdejin))
|
||||||
|
- Delicado, Elodie
|
||||||
- Dvořák, Lukáš
|
- Dvořák, Lukáš
|
||||||
- Goethals, Stefan
|
- Goethals, Stefan
|
||||||
|
- Giuva, Vincenzo Katriel (a.k.a [@DarkNight97boss](https://github.com/DarkNight97boss))
|
||||||
- Gumble, David
|
- Gumble, David
|
||||||
|
- Håkon, Harnes (a.k.a [@hakonharnes](https://github.com/hakonharnes))
|
||||||
|
- Heloir, Arthur
|
||||||
|
- Janssens, Jelle (a.k.a [@janssensjelle](https://github.com/janssensjelle))
|
||||||
- Ji, Leeb (冀利斌) (a.k.a [@chileeb](https://github.com/chileeb))
|
- Ji, Leeb (冀利斌) (a.k.a [@chileeb](https://github.com/chileeb))
|
||||||
- Kaltefleiter, Lars (a.k.a [@larhip](https://www.github.com/larhip))
|
- Kaltefleiter, Lars (a.k.a [@larhip](https://www.github.com/larhip))
|
||||||
- Khamit, Shamil
|
- Khamit, Shamil
|
||||||
- Kincel, Martin
|
- Kincel, Martin
|
||||||
- Konečný, Kamil
|
- Konečný, Kamil
|
||||||
- Kunin, Vladimir
|
- Kunin, Vladimir
|
||||||
- Lassiter, Dennis
|
- Lassiter, Denis (a.k.a [@delassiter](https://github.com/delassiter))
|
||||||
- Lazcano, Federico
|
- Lazcano, Federico
|
||||||
- Lucas, Jonathan
|
- Lucas, Jonathan
|
||||||
- Malik, Remie
|
- Malik, Remie
|
||||||
|
- Mantel, Ina
|
||||||
|
- Martin, Pierre (a.k.a [@Worty](https://github.com/worty-syn))
|
||||||
|
- Melchiorre, Romain
|
||||||
- Mindêllo de Andrade, Lucas (a.k.a [@rokam](https://www.github.com/rokam))
|
- Mindêllo de Andrade, Lucas (a.k.a [@rokam](https://www.github.com/rokam))
|
||||||
- Mozart de Oliveira, Eduardo (a.k.a [@eduardomozart](https://github.com/eduardomozart))
|
- Mozart de Oliveira, Eduardo (a.k.a [@eduardomozart](https://github.com/eduardomozart))
|
||||||
- Raenker, Martin
|
- Raenker, Martin
|
||||||
@@ -116,10 +126,12 @@ We would like to give a special thank you 🤗 to the people from the community
|
|||||||
- Seki, Shoji
|
- Seki, Shoji
|
||||||
- Shilov, Vladimir
|
- Shilov, Vladimir
|
||||||
- Stetina, Pavel (a.k.a [@Stetinac](https://github.com/Stetinac))
|
- Stetina, Pavel (a.k.a [@Stetinac](https://github.com/Stetinac))
|
||||||
- Stukalov, Ilya (a.k.a [@ilya](https://www.github.com/ilya)-stukalov)
|
- Stukalov, Ilya (a.k.a [@ilya](https://www.github.com/ilya-stukalov))
|
||||||
- Tarjányi, Csaba (a.k.a [@tacsaby](https://github.com/tacsaby))
|
- Tarjányi, Csaba (a.k.a [@tacsaby](https://github.com/tacsaby))
|
||||||
|
- Toraya, Chairat (a.k.a [@Kyokito1412](https://github.com/Kyokito1412))
|
||||||
- Tulio, Marco
|
- Tulio, Marco
|
||||||
- Turrubiates, Miguel
|
- Turrubiates, Miguel
|
||||||
|
- Višnjić, Aldin (a.k.a[@viliald](https://github.com/viliald))
|
||||||
- Vlk, Karel (a.k.a [@vlk-charles](https://www.github.com/vlk-charles))
|
- Vlk, Karel (a.k.a [@vlk-charles](https://www.github.com/vlk-charles))
|
||||||
|
|
||||||
### Aliases
|
### Aliases
|
||||||
@@ -141,4 +153,6 @@ We would like to give a special thank you 🤗 to the people from the community
|
|||||||
- [ITOMIG](https://www.itomig.de/)
|
- [ITOMIG](https://www.itomig.de/)
|
||||||
- [Pimkie](https://www.pimkie.com/)
|
- [Pimkie](https://www.pimkie.com/)
|
||||||
- [Super-Visions](https://www.super-visions.com/)
|
- [Super-Visions](https://www.super-visions.com/)
|
||||||
|
- [Defence Tech Cyber Security - Malware Lab](https://github.com/DefenceTechSecurity)
|
||||||
|
- Orange Cyberdefense
|
||||||
|
- MipihSIB
|
||||||
|
|||||||
@@ -1,362 +0,0 @@
|
|||||||
<?php
|
|
||||||
// Copyright (C) 2010-2024 Combodo SAS
|
|
||||||
//
|
|
||||||
// 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/>
|
|
||||||
|
|
||||||
/**
|
|
||||||
* UserRightsMatrix (User management Module)
|
|
||||||
*
|
|
||||||
* @copyright Copyright (C) 2010-2024 Combodo SAS
|
|
||||||
* @license http://opensource.org/licenses/AGPL-3.0
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
class UserRightsMatrixClassGrant extends DBObject
|
|
||||||
{
|
|
||||||
public static function Init()
|
|
||||||
{
|
|
||||||
$aParams = array
|
|
||||||
(
|
|
||||||
"category" => "addon/userrights",
|
|
||||||
"key_type" => "autoincrement",
|
|
||||||
"name_attcode" => "",
|
|
||||||
"state_attcode" => "",
|
|
||||||
"reconc_keys" => array(),
|
|
||||||
"db_table" => "priv_ur_matrixclasses",
|
|
||||||
"db_key_field" => "id",
|
|
||||||
"db_finalclass_field" => "",
|
|
||||||
);
|
|
||||||
MetaModel::Init_Params($aParams);
|
|
||||||
//MetaModel::Init_InheritAttributes();
|
|
||||||
MetaModel::Init_AddAttribute(new AttributeExternalKey("userid", array("targetclass"=>"User", "jointype"=> "", "allowed_values"=>null, "sql"=>"userid", "is_null_allowed"=>false, "on_target_delete"=>DEL_MANUAL, "depends_on"=>array())));
|
|
||||||
MetaModel::Init_AddAttribute(new AttributeExternalField("login", array("allowed_values"=>null, "extkey_attcode"=> 'userid', "target_attcode"=>"login")));
|
|
||||||
MetaModel::Init_AddAttribute(new AttributeString("class", array("allowed_values"=>null, "sql"=>"class", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array())));
|
|
||||||
|
|
||||||
MetaModel::Init_AddAttribute(new AttributeString("action", array("allowed_values"=>null, "sql"=>"action", "default_value"=>"", "is_null_allowed"=>false, "depends_on"=>array())));
|
|
||||||
MetaModel::Init_AddAttribute(new AttributeEnum("permission", array("allowed_values"=>new ValueSetEnum('yes,no'), "sql"=>"permission", "default_value"=>"yes", "is_null_allowed"=>false, "depends_on"=>array())));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class UserRightsMatrixClassStimulusGrant extends DBObject
|
|
||||||
{
|
|
||||||
public static function Init()
|
|
||||||
{
|
|
||||||
$aParams = array
|
|
||||||
(
|
|
||||||
"category" => "addon/userrights",
|
|
||||||
"key_type" => "autoincrement",
|
|
||||||
"name_attcode" => "",
|
|
||||||
"state_attcode" => "",
|
|
||||||
"reconc_keys" => array(),
|
|
||||||
"db_table" => "priv_ur_matrixclassesstimulus",
|
|
||||||
"db_key_field" => "id",
|
|
||||||
"db_finalclass_field" => "",
|
|
||||||
);
|
|
||||||
MetaModel::Init_Params($aParams);
|
|
||||||
//MetaModel::Init_InheritAttributes();
|
|
||||||
MetaModel::Init_AddAttribute(new AttributeExternalKey("userid", array("targetclass"=>"User", "jointype"=> "", "allowed_values"=>null, "sql"=>"userid", "is_null_allowed"=>false, "on_target_delete"=>DEL_MANUAL, "depends_on"=>array())));
|
|
||||||
MetaModel::Init_AddAttribute(new AttributeExternalField("login", array("allowed_values"=>null, "extkey_attcode"=> 'userid', "target_attcode"=>"login")));
|
|
||||||
MetaModel::Init_AddAttribute(new AttributeString("class", array("allowed_values"=>null, "sql"=>"class", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array())));
|
|
||||||
|
|
||||||
MetaModel::Init_AddAttribute(new AttributeString("stimulus", array("allowed_values"=>null, "sql"=>"action", "default_value"=>"", "is_null_allowed"=>false, "depends_on"=>array())));
|
|
||||||
MetaModel::Init_AddAttribute(new AttributeEnum("permission", array("allowed_values"=>new ValueSetEnum('yes,no'), "sql"=>"permission", "default_value"=>"yes", "is_null_allowed"=>false, "depends_on"=>array())));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class UserRightsMatrixAttributeGrant extends DBObject
|
|
||||||
{
|
|
||||||
public static function Init()
|
|
||||||
{
|
|
||||||
$aParams = array
|
|
||||||
(
|
|
||||||
"category" => "addon/userrights",
|
|
||||||
"key_type" => "autoincrement",
|
|
||||||
"name_attcode" => "",
|
|
||||||
"state_attcode" => "",
|
|
||||||
"reconc_keys" => array(),
|
|
||||||
"db_table" => "priv_ur_matrixattributes",
|
|
||||||
"db_key_field" => "id",
|
|
||||||
"db_finalclass_field" => "",
|
|
||||||
);
|
|
||||||
MetaModel::Init_Params($aParams);
|
|
||||||
//MetaModel::Init_InheritAttributes();
|
|
||||||
MetaModel::Init_AddAttribute(new AttributeExternalKey("userid", array("targetclass"=>"User", "jointype"=> "", "allowed_values"=>null, "sql"=>"userid", "is_null_allowed"=>false, "on_target_delete"=>DEL_MANUAL, "depends_on"=>array())));
|
|
||||||
MetaModel::Init_AddAttribute(new AttributeExternalField("login", array("allowed_values"=>null, "extkey_attcode"=> 'userid', "target_attcode"=>"login")));
|
|
||||||
MetaModel::Init_AddAttribute(new AttributeString("class", array("allowed_values"=>null, "sql"=>"class", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array())));
|
|
||||||
MetaModel::Init_AddAttribute(new AttributeString("attcode", array("allowed_values"=>null, "sql"=>"attcode", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array())));
|
|
||||||
|
|
||||||
MetaModel::Init_AddAttribute(new AttributeString("action", array("allowed_values"=>null, "sql"=>"action", "default_value"=>"", "is_null_allowed"=>false, "depends_on"=>array())));
|
|
||||||
MetaModel::Init_AddAttribute(new AttributeEnum("permission", array("allowed_values"=>new ValueSetEnum('yes,no'), "sql"=>"permission", "default_value"=>"yes", "is_null_allowed"=>false, "depends_on"=>array())));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class UserRightsMatrix extends UserRightsAddOnAPI
|
|
||||||
{
|
|
||||||
static public $m_aActionCodes = array(
|
|
||||||
UR_ACTION_READ => 'read',
|
|
||||||
UR_ACTION_MODIFY => 'modify',
|
|
||||||
UR_ACTION_DELETE => 'delete',
|
|
||||||
UR_ACTION_BULK_READ => 'bulk read',
|
|
||||||
UR_ACTION_BULK_MODIFY => 'bulk modify',
|
|
||||||
UR_ACTION_BULK_DELETE => 'bulk delete',
|
|
||||||
);
|
|
||||||
|
|
||||||
// Installation: create the very first user
|
|
||||||
public function CreateAdministrator($sAdminUser, $sAdminPwd, $sLanguage = 'EN US')
|
|
||||||
{
|
|
||||||
// Maybe we should check that no other user with userid == 0 exists
|
|
||||||
$oUser = new UserLocal();
|
|
||||||
$oUser->Set('login', $sAdminUser);
|
|
||||||
$oUser->Set('password', $sAdminPwd);
|
|
||||||
$oUser->Set('contactid', 1); // one is for root !
|
|
||||||
$oUser->Set('language', $sLanguage); // Language was chosen during the installation
|
|
||||||
|
|
||||||
// Now record the admin user object
|
|
||||||
$iUserId = $oUser->DBInsertNoReload();
|
|
||||||
$this->SetupUser($iUserId, true);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function IsAdministrator($oUser)
|
|
||||||
{
|
|
||||||
return ($oUser->GetKey() == 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function IsPortalUser($oUser)
|
|
||||||
{
|
|
||||||
return ($oUser->GetKey() == 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Deprecated - create a new module !
|
|
||||||
public function Setup()
|
|
||||||
{
|
|
||||||
// Users must be added manually
|
|
||||||
// This procedure will then update the matrix when a new user is found or a new class/attribute appears
|
|
||||||
$oUserSet = new DBObjectSet(DBObjectSearch::FromOQL("SELECT User"));
|
|
||||||
while ($oUser = $oUserSet->Fetch())
|
|
||||||
{
|
|
||||||
$this->SetupUser($oUser->GetKey());
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function SetupUser($iUserId, $bNewUser = false)
|
|
||||||
{
|
|
||||||
foreach(array('bizmodel', 'application', 'gui', 'core/cmdb') as $sCategory)
|
|
||||||
{
|
|
||||||
foreach (MetaModel::GetClasses($sCategory) as $sClass)
|
|
||||||
{
|
|
||||||
foreach (self::$m_aActionCodes as $iActionCode => $sAction)
|
|
||||||
{
|
|
||||||
if ($bNewUser)
|
|
||||||
{
|
|
||||||
$bAddCell = true;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
$oSet = new DBObjectSet(DBObjectSearch::FromOQL("SELECT UserRightsMatrixClassGrant WHERE class = '$sClass' AND action = '$sAction' AND userid = $iUserId"));
|
|
||||||
$bAddCell = ($oSet->Count() < 1);
|
|
||||||
}
|
|
||||||
if ($bAddCell)
|
|
||||||
{
|
|
||||||
// Create a new entry
|
|
||||||
$oMyClassGrant = MetaModel::NewObject("UserRightsMatrixClassGrant");
|
|
||||||
$oMyClassGrant->Set("userid", $iUserId);
|
|
||||||
$oMyClassGrant->Set("class", $sClass);
|
|
||||||
$oMyClassGrant->Set("action", $sAction);
|
|
||||||
$oMyClassGrant->Set("permission", "yes");
|
|
||||||
$iId = $oMyClassGrant->DBInsertNoReload();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
foreach (MetaModel::EnumStimuli($sClass) as $sStimulusCode => $oStimulus)
|
|
||||||
{
|
|
||||||
if ($bNewUser)
|
|
||||||
{
|
|
||||||
$bAddCell = true;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
$oSet = new DBObjectSet(DBObjectSearch::FromOQL("SELECT UserRightsMatrixClassStimulusGrant WHERE class = '$sClass' AND stimulus = '$sStimulusCode' AND userid = $iUserId"));
|
|
||||||
$bAddCell = ($oSet->Count() < 1);
|
|
||||||
}
|
|
||||||
if ($bAddCell)
|
|
||||||
{
|
|
||||||
// Create a new entry
|
|
||||||
$oMyClassGrant = MetaModel::NewObject("UserRightsMatrixClassStimulusGrant");
|
|
||||||
$oMyClassGrant->Set("userid", $iUserId);
|
|
||||||
$oMyClassGrant->Set("class", $sClass);
|
|
||||||
$oMyClassGrant->Set("stimulus", $sStimulusCode);
|
|
||||||
$oMyClassGrant->Set("permission", "yes");
|
|
||||||
$iId = $oMyClassGrant->DBInsertNoReload();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
foreach (MetaModel::GetAttributesList($sClass) as $sAttCode)
|
|
||||||
{
|
|
||||||
if ($bNewUser)
|
|
||||||
{
|
|
||||||
$bAddCell = true;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
$oSet = new DBObjectSet(DBObjectSearch::FromOQL("SELECT UserRightsMatrixAttributeGrant WHERE class = '$sClass' AND attcode = '$sAttCode' AND userid = $iUserId"));
|
|
||||||
$bAddCell = ($oSet->Count() < 1);
|
|
||||||
}
|
|
||||||
if ($bAddCell)
|
|
||||||
{
|
|
||||||
foreach (array('read', 'modify') as $sAction)
|
|
||||||
{
|
|
||||||
// Create a new entry
|
|
||||||
$oMyAttGrant = MetaModel::NewObject("UserRightsMatrixAttributeGrant");
|
|
||||||
$oMyAttGrant->Set("userid", $iUserId);
|
|
||||||
$oMyAttGrant->Set("class", $sClass);
|
|
||||||
$oMyAttGrant->Set("attcode", $sAttCode);
|
|
||||||
$oMyAttGrant->Set("action", $sAction);
|
|
||||||
$oMyAttGrant->Set("permission", "yes");
|
|
||||||
$iId = $oMyAttGrant->DBInsertNoReload();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
// Create the "My Bookmarks" menu item (parent_id = 0, rank = 6)
|
|
||||||
if ($bNewUser)
|
|
||||||
{
|
|
||||||
$bAddMenu = true;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
$oSet = new DBObjectSet(DBObjectSearch::FromOQL("SELECT menuNode WHERE type = 'user' AND parent_id = 0 AND user_id = $iUserId"));
|
|
||||||
$bAddMenu = ($oSet->Count() < 1);
|
|
||||||
}
|
|
||||||
if ($bAddMenu)
|
|
||||||
{
|
|
||||||
$oMenu = MetaModel::NewObject('menuNode');
|
|
||||||
$oMenu->Set('type', 'user');
|
|
||||||
$oMenu->Set('parent_id', 0); // It's a toplevel entry
|
|
||||||
$oMenu->Set('rank', 6); // Located just above the Admin Tools section (=7)
|
|
||||||
$oMenu->Set('name', 'My Bookmarks');
|
|
||||||
$oMenu->Set('label', 'My Favorite Items');
|
|
||||||
$oMenu->Set('hyperlink', 'UI.php');
|
|
||||||
$oMenu->Set('template', '<p></p><p></p><p style="text-align:center; font-family:Georgia, Times, serif; font-size:32px;">My bookmarks</p><p style="text-align:center; font-family:Georgia, Times, serif; font-size:14px;"><i>This section contains my most favorite search results</i></p>');
|
|
||||||
$oMenu->Set('user_id', $iUserId);
|
|
||||||
$oMenu->DBInsert();
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public function Init()
|
|
||||||
{
|
|
||||||
// Could be loaded in a shared memory (?)
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function GetSelectFilter($oUser, $sClass, $aSettings = array())
|
|
||||||
{
|
|
||||||
$oNullFilter = new DBObjectSearch($sClass);
|
|
||||||
return $oNullFilter;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function IsActionAllowed($oUser, $sClass, $iActionCode, $oInstanceSet = null)
|
|
||||||
{
|
|
||||||
if (!array_key_exists($iActionCode, self::$m_aActionCodes))
|
|
||||||
{
|
|
||||||
return UR_ALLOWED_NO;
|
|
||||||
}
|
|
||||||
$sAction = self::$m_aActionCodes[$iActionCode];
|
|
||||||
|
|
||||||
$oSet = new DBObjectSet(DBObjectSearch::FromOQL("SELECT UserRightsMatrixClassGrant WHERE class = '$sClass' AND action = '$sAction' AND userid = '{$oUser->GetKey()}'"));
|
|
||||||
if ($oSet->Count() < 1)
|
|
||||||
{
|
|
||||||
return UR_ALLOWED_NO;
|
|
||||||
}
|
|
||||||
|
|
||||||
$oGrantRecord = $oSet->Fetch();
|
|
||||||
switch ($oGrantRecord->Get('permission'))
|
|
||||||
{
|
|
||||||
case 'yes':
|
|
||||||
$iRetCode = UR_ALLOWED_YES;
|
|
||||||
break;
|
|
||||||
case 'no':
|
|
||||||
default:
|
|
||||||
$iRetCode = UR_ALLOWED_NO;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return $iRetCode;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function IsActionAllowedOnAttribute($oUser, $sClass, $sAttCode, $iActionCode, $oInstanceSet = null)
|
|
||||||
{
|
|
||||||
if (!array_key_exists($iActionCode, self::$m_aActionCodes))
|
|
||||||
{
|
|
||||||
return UR_ALLOWED_NO;
|
|
||||||
}
|
|
||||||
$sAction = self::$m_aActionCodes[$iActionCode];
|
|
||||||
|
|
||||||
$oSet = new DBObjectSet(DBObjectSearch::FromOQL("SELECT UserRightsMatrixAttributeGrant WHERE class = '$sClass' AND attcode = '$sAttCode' AND action = '$sAction' AND userid = '{$oUser->GetKey()}'"));
|
|
||||||
if ($oSet->Count() < 1)
|
|
||||||
{
|
|
||||||
return UR_ALLOWED_NO;
|
|
||||||
}
|
|
||||||
|
|
||||||
$oGrantRecord = $oSet->Fetch();
|
|
||||||
switch ($oGrantRecord->Get('permission'))
|
|
||||||
{
|
|
||||||
case 'yes':
|
|
||||||
$iRetCode = UR_ALLOWED_YES;
|
|
||||||
break;
|
|
||||||
case 'no':
|
|
||||||
default:
|
|
||||||
$iRetCode = UR_ALLOWED_NO;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return $iRetCode;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function IsStimulusAllowed($oUser, $sClass, $sStimulusCode, $oInstanceSet = null)
|
|
||||||
{
|
|
||||||
$oSet = new DBObjectSet(DBObjectSearch::FromOQL("SELECT UserRightsMatrixClassStimulusGrant WHERE class = '$sClass' AND stimulus = '$sStimulusCode' AND userid = '{$oUser->GetKey()}'"));
|
|
||||||
if ($oSet->Count() < 1)
|
|
||||||
{
|
|
||||||
return UR_ALLOWED_NO;
|
|
||||||
}
|
|
||||||
|
|
||||||
$oGrantRecord = $oSet->Fetch();
|
|
||||||
switch ($oGrantRecord->Get('permission'))
|
|
||||||
{
|
|
||||||
case 'yes':
|
|
||||||
$iRetCode = UR_ALLOWED_YES;
|
|
||||||
break;
|
|
||||||
case 'no':
|
|
||||||
default:
|
|
||||||
$iRetCode = UR_ALLOWED_NO;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return $iRetCode;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function FlushPrivileges()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
UserRights::SelectModule('UserRightsMatrix');
|
|
||||||
|
|
||||||
?>
|
|
||||||
@@ -1,78 +0,0 @@
|
|||||||
<?php
|
|
||||||
// Copyright (C) 2010-2024 Combodo SAS
|
|
||||||
//
|
|
||||||
// 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/>
|
|
||||||
|
|
||||||
/**
|
|
||||||
* UserRightsNull
|
|
||||||
* User management Module - say Yeah! to everything
|
|
||||||
*
|
|
||||||
* @copyright Copyright (C) 2010-2024 Combodo SAS
|
|
||||||
* @license http://opensource.org/licenses/AGPL-3.0
|
|
||||||
*/
|
|
||||||
|
|
||||||
class UserRightsNull extends UserRightsAddOnAPI
|
|
||||||
{
|
|
||||||
// Installation: create the very first user
|
|
||||||
public function CreateAdministrator($sAdminUser, $sAdminPwd, $sLanguage = 'EN US')
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function IsAdministrator($oUser)
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function IsPortalUser($oUser)
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function Init()
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function GetSelectFilter($oUser, $sClass, $aSettings = array())
|
|
||||||
{
|
|
||||||
$oNullFilter = new DBObjectSearch($sClass);
|
|
||||||
return $oNullFilter;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function IsActionAllowed($oUser, $sClass, $iActionCode, $oInstanceSet = null)
|
|
||||||
{
|
|
||||||
return UR_ALLOWED_YES;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function IsStimulusAllowed($oUser, $sClass, $sStimulusCode, $oInstanceSet = null)
|
|
||||||
{
|
|
||||||
return UR_ALLOWED_YES;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function IsActionAllowedOnAttribute($oUser, $sClass, $sAttCode, $iActionCode, $oInstanceSet = null)
|
|
||||||
{
|
|
||||||
return UR_ALLOWED_YES;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function FlushPrivileges()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
UserRights::SelectModule('UserRightsNull');
|
|
||||||
|
|
||||||
?>
|
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* @copyright Copyright (C) 2010-2024 Combodo SAS
|
* @copyright Copyright (C) 2010-2024 Combodo SAS
|
||||||
* @license http://opensource.org/licenses/AGPL-3.0
|
* @license http://opensource.org/licenses/AGPL-3.0
|
||||||
@@ -29,56 +30,52 @@ class UserRightsBaseClassGUI extends cmdbAbstractObject
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
class URP_Profiles extends UserRightsBaseClassGUI
|
class URP_Profiles extends UserRightsBaseClassGUI
|
||||||
{
|
{
|
||||||
public static function Init()
|
public static function Init()
|
||||||
{
|
{
|
||||||
$aParams = array
|
$aParams =
|
||||||
(
|
[
|
||||||
"category" => "addon/userrights,grant_by_profile,filter",
|
"category" => "addon/userrights,grant_by_profile,filter",
|
||||||
"key_type" => "autoincrement",
|
"key_type" => "autoincrement",
|
||||||
"name_attcode" => "name",
|
"name_attcode" => "name",
|
||||||
"complementary_name_attcode" => array('description'),
|
"complementary_name_attcode" => ['description'],
|
||||||
"state_attcode" => "",
|
"state_attcode" => "",
|
||||||
"reconc_keys" => array(),
|
"reconc_keys" => [],
|
||||||
"db_table" => "priv_urp_profiles",
|
"db_table" => "priv_urp_profiles",
|
||||||
"db_key_field" => "id",
|
"db_key_field" => "id",
|
||||||
"db_finalclass_field" => "",
|
"db_finalclass_field" => "",
|
||||||
);
|
];
|
||||||
MetaModel::Init_Params($aParams);
|
MetaModel::Init_Params($aParams);
|
||||||
//MetaModel::Init_InheritAttributes();
|
//MetaModel::Init_InheritAttributes();
|
||||||
MetaModel::Init_AddAttribute(new AttributeString("name", array("allowed_values"=>null, "sql"=>"name", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array())));
|
MetaModel::Init_AddAttribute(new AttributeString("name", ["allowed_values" => null, "sql" => "name", "default_value" => null, "is_null_allowed" => false, "depends_on" => []]));
|
||||||
MetaModel::Init_AddAttribute(new AttributeString("description", array("allowed_values"=>null, "sql"=>"description", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array())));
|
MetaModel::Init_AddAttribute(new AttributeString("description", ["allowed_values" => null, "sql" => "description", "default_value" => null, "is_null_allowed" => false, "depends_on" => []]));
|
||||||
|
|
||||||
MetaModel::Init_AddAttribute(new AttributeLinkedSetIndirect("user_list", array("linked_class"=>"URP_UserProfile", "ext_key_to_me"=>"profileid", "ext_key_to_remote"=>"userid", "allowed_values"=>null, "count_min"=>1, "count_max"=>0, "depends_on"=>array())));
|
MetaModel::Init_AddAttribute(new AttributeLinkedSetIndirect("user_list", ["linked_class" => "URP_UserProfile", "ext_key_to_me" => "profileid", "ext_key_to_remote" => "userid", "allowed_values" => null, "count_min" => 1, "count_max" => 0, "depends_on" => []]));
|
||||||
|
|
||||||
// Display lists
|
// Display lists
|
||||||
MetaModel::Init_SetZListItems('details', array('name', 'description', 'user_list')); // Attributes to be displayed for the complete details
|
MetaModel::Init_SetZListItems('details', ['name', 'description', 'user_list']); // Attributes to be displayed for the complete details
|
||||||
MetaModel::Init_SetZListItems('list', array('description')); // Attributes to be displayed for a list
|
MetaModel::Init_SetZListItems('list', ['description']); // Attributes to be displayed for a list
|
||||||
// Search criteria
|
// Search criteria
|
||||||
MetaModel::Init_SetZListItems('standard_search', array('name','description')); // Criteria of the std search form
|
MetaModel::Init_SetZListItems('standard_search', ['name','description']); // Criteria of the std search form
|
||||||
MetaModel::Init_SetZListItems('default_search', array ('name','description'));
|
MetaModel::Init_SetZListItems('default_search', ['name','description']);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected static $m_aCacheProfiles = null;
|
protected static $m_aCacheProfiles = null;
|
||||||
|
|
||||||
public static function DoCreateProfile($sName, $sDescription)
|
public static function DoCreateProfile($sName, $sDescription)
|
||||||
{
|
{
|
||||||
if (is_null(self::$m_aCacheProfiles))
|
if (is_null(self::$m_aCacheProfiles)) {
|
||||||
{
|
self::$m_aCacheProfiles = [];
|
||||||
self::$m_aCacheProfiles = array();
|
|
||||||
$oFilterAll = new DBObjectSearch('URP_Profiles');
|
$oFilterAll = new DBObjectSearch('URP_Profiles');
|
||||||
$oSet = new DBObjectSet($oFilterAll);
|
$oSet = new DBObjectSet($oFilterAll);
|
||||||
while ($oProfile = $oSet->Fetch())
|
while ($oProfile = $oSet->Fetch()) {
|
||||||
{
|
|
||||||
self::$m_aCacheProfiles[$oProfile->Get('name')] = $oProfile->GetKey();
|
self::$m_aCacheProfiles[$oProfile->Get('name')] = $oProfile->GetKey();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$sCacheKey = $sName;
|
$sCacheKey = $sName;
|
||||||
if (isset(self::$m_aCacheProfiles[$sCacheKey]))
|
if (isset(self::$m_aCacheProfiles[$sCacheKey])) {
|
||||||
{
|
|
||||||
return self::$m_aCacheProfiles[$sCacheKey];
|
return self::$m_aCacheProfiles[$sCacheKey];
|
||||||
}
|
}
|
||||||
$oNewObj = MetaModel::NewObject("URP_Profiles");
|
$oNewObj = MetaModel::NewObject("URP_Profiles");
|
||||||
@@ -89,27 +86,21 @@ class URP_Profiles extends UserRightsBaseClassGUI
|
|||||||
return $iId;
|
return $iId;
|
||||||
}
|
}
|
||||||
|
|
||||||
function GetGrantAsHtml($oUserRights, $sClass, $sAction)
|
public function GetGrantAsHtml($oUserRights, $sClass, $sAction)
|
||||||
{
|
{
|
||||||
$bGrant = $oUserRights->GetProfileActionGrant($this->GetKey(), $sClass, $sAction);
|
$bGrant = $oUserRights->GetProfileActionGrant($this->GetKey(), $sClass, $sAction);
|
||||||
if (is_null($bGrant))
|
if (is_null($bGrant)) {
|
||||||
{
|
return '<span class="ibo-user-rights ibo-is-failure">'.Dict::S('UI:UserManagement:ActionAllowed:No').'</span>';
|
||||||
return '<span style="background-color: #ffdddd;">'.Dict::S('UI:UserManagement:ActionAllowed:No').'</span>';
|
} elseif ($bGrant) {
|
||||||
}
|
return '<span class="ibo-user-rights ibo-is-success">'.Dict::S('UI:UserManagement:ActionAllowed:Yes').'</span>';
|
||||||
elseif ($bGrant)
|
} else {
|
||||||
{
|
return '<span class="ibo-user-rights ibo-is-failure">'.Dict::S('UI:UserManagement:ActionAllowed:No').'</span>';
|
||||||
return '<span style="background-color: #ddffdd;">'.Dict::S('UI:UserManagement:ActionAllowed:Yes').'</span>';
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return '<span style="background-color: #ffdddd;">'.Dict::S('UI:UserManagement:ActionAllowed:No').'</span>';
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function DoShowGrantSumary($oPage)
|
public function DoShowGrantSumary($oPage)
|
||||||
{
|
{
|
||||||
if ($this->GetRawName() == "Administrator")
|
if ($this->GetRawName() == "Administrator") {
|
||||||
{
|
|
||||||
// Looks dirty, but ok that's THE ONE
|
// Looks dirty, but ok that's THE ONE
|
||||||
$oPage->p(Dict::S('UI:UserManagement:AdminProfile+'));
|
$oPage->p(Dict::S('UI:UserManagement:AdminProfile+'));
|
||||||
return;
|
return;
|
||||||
@@ -118,21 +109,18 @@ class URP_Profiles extends UserRightsBaseClassGUI
|
|||||||
// Note: for sure, we assume that the instance is derived from UserRightsProfile
|
// Note: for sure, we assume that the instance is derived from UserRightsProfile
|
||||||
$oUserRights = UserRights::GetModuleInstance();
|
$oUserRights = UserRights::GetModuleInstance();
|
||||||
|
|
||||||
$aDisplayData = array();
|
$aDisplayData = [];
|
||||||
foreach (MetaModel::GetClasses('bizmodel,grant_by_profile') as $sClass)
|
foreach (MetaModel::GetClasses('bizmodel,grant_by_profile') as $sClass) {
|
||||||
{
|
$aStimuli = [];
|
||||||
$aStimuli = array();
|
foreach (MetaModel::EnumStimuli($sClass) as $sStimulusCode => $oStimulus) {
|
||||||
foreach (MetaModel::EnumStimuli($sClass) as $sStimulusCode => $oStimulus)
|
|
||||||
{
|
|
||||||
$bGrant = $oUserRights->GetClassStimulusGrant($this->GetKey(), $sClass, $sStimulusCode);
|
$bGrant = $oUserRights->GetClassStimulusGrant($this->GetKey(), $sClass, $sStimulusCode);
|
||||||
if ($bGrant === true)
|
if ($bGrant === true) {
|
||||||
{
|
|
||||||
$aStimuli[] = '<span title="'.$sStimulusCode.': '.utils::EscapeHtml($oStimulus->GetDescription()).'">'.utils::EscapeHtml($oStimulus->GetLabel()).'</span>';
|
$aStimuli[] = '<span title="'.$sStimulusCode.': '.utils::EscapeHtml($oStimulus->GetDescription()).'">'.utils::EscapeHtml($oStimulus->GetLabel()).'</span>';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$sStimuli = implode(', ', $aStimuli);
|
$sStimuli = implode(', ', $aStimuli);
|
||||||
|
|
||||||
$aDisplayData[] = array(
|
$aDisplayData[] = [
|
||||||
'class' => MetaModel::GetName($sClass),
|
'class' => MetaModel::GetName($sClass),
|
||||||
'read' => $this->GetGrantAsHtml($oUserRights, $sClass, 'r'),
|
'read' => $this->GetGrantAsHtml($oUserRights, $sClass, 'r'),
|
||||||
'bulkread' => $this->GetGrantAsHtml($oUserRights, $sClass, 'br'),
|
'bulkread' => $this->GetGrantAsHtml($oUserRights, $sClass, 'br'),
|
||||||
@@ -141,22 +129,22 @@ class URP_Profiles extends UserRightsBaseClassGUI
|
|||||||
'delete' => $this->GetGrantAsHtml($oUserRights, $sClass, 'd'),
|
'delete' => $this->GetGrantAsHtml($oUserRights, $sClass, 'd'),
|
||||||
'bulkdelete' => $this->GetGrantAsHtml($oUserRights, $sClass, 'bd'),
|
'bulkdelete' => $this->GetGrantAsHtml($oUserRights, $sClass, 'bd'),
|
||||||
'stimuli' => $sStimuli,
|
'stimuli' => $sStimuli,
|
||||||
);
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
$aDisplayConfig = array();
|
$aDisplayConfig = [];
|
||||||
$aDisplayConfig['class'] = array('label' => Dict::S('UI:UserManagement:Class'), 'description' => Dict::S('UI:UserManagement:Class+'));
|
$aDisplayConfig['class'] = ['label' => Dict::S('UI:UserManagement:Class'), 'description' => Dict::S('UI:UserManagement:Class+')];
|
||||||
$aDisplayConfig['read'] = array('label' => Dict::S('UI:UserManagement:Action:Read'), 'description' => Dict::S('UI:UserManagement:Action:Read+'));
|
$aDisplayConfig['read'] = ['label' => Dict::S('UI:UserManagement:Action:Read'), 'description' => Dict::S('UI:UserManagement:Action:Read+')];
|
||||||
$aDisplayConfig['bulkread'] = array('label' => Dict::S('UI:UserManagement:Action:BulkRead'), 'description' => Dict::S('UI:UserManagement:Action:BulkRead+'));
|
$aDisplayConfig['bulkread'] = ['label' => Dict::S('UI:UserManagement:Action:BulkRead'), 'description' => Dict::S('UI:UserManagement:Action:BulkRead+')];
|
||||||
$aDisplayConfig['write'] = array('label' => Dict::S('UI:UserManagement:Action:Modify'), 'description' => Dict::S('UI:UserManagement:Action:Modify+'));
|
$aDisplayConfig['write'] = ['label' => Dict::S('UI:UserManagement:Action:Modify'), 'description' => Dict::S('UI:UserManagement:Action:Modify+')];
|
||||||
$aDisplayConfig['bulkwrite'] = array('label' => Dict::S('UI:UserManagement:Action:BulkModify'), 'description' => Dict::S('UI:UserManagement:Action:BulkModify+'));
|
$aDisplayConfig['bulkwrite'] = ['label' => Dict::S('UI:UserManagement:Action:BulkModify'), 'description' => Dict::S('UI:UserManagement:Action:BulkModify+')];
|
||||||
$aDisplayConfig['delete'] = array('label' => Dict::S('UI:UserManagement:Action:Delete'), 'description' => Dict::S('UI:UserManagement:Action:Delete+'));
|
$aDisplayConfig['delete'] = ['label' => Dict::S('UI:UserManagement:Action:Delete'), 'description' => Dict::S('UI:UserManagement:Action:Delete+')];
|
||||||
$aDisplayConfig['bulkdelete'] = array('label' => Dict::S('UI:UserManagement:Action:BulkDelete'), 'description' => Dict::S('UI:UserManagement:Action:BulkDelete+'));
|
$aDisplayConfig['bulkdelete'] = ['label' => Dict::S('UI:UserManagement:Action:BulkDelete'), 'description' => Dict::S('UI:UserManagement:Action:BulkDelete+')];
|
||||||
$aDisplayConfig['stimuli'] = array('label' => Dict::S('UI:UserManagement:Action:Stimuli'), 'description' => Dict::S('UI:UserManagement:Action:Stimuli+'));
|
$aDisplayConfig['stimuli'] = ['label' => Dict::S('UI:UserManagement:Action:Stimuli'), 'description' => Dict::S('UI:UserManagement:Action:Stimuli+')];
|
||||||
$oPage->table($aDisplayConfig, $aDisplayData);
|
$oPage->table($aDisplayConfig, $aDisplayData);
|
||||||
}
|
}
|
||||||
|
|
||||||
function DisplayBareRelations(WebPage $oPage, $bEditMode = false)
|
public function DisplayBareRelations(WebPage $oPage, $bEditMode = false)
|
||||||
{
|
{
|
||||||
parent::DisplayBareRelations($oPage, $bEditMode);
|
parent::DisplayBareRelations($oPage, $bEditMode);
|
||||||
|
|
||||||
@@ -166,10 +154,9 @@ class URP_Profiles extends UserRightsBaseClassGUI
|
|||||||
|
|
||||||
public static function GetReadOnlyAttributes()
|
public static function GetReadOnlyAttributes()
|
||||||
{
|
{
|
||||||
return array('name', 'description');
|
return ['name', 'description'];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// returns an array of id => array of column => php value(so-called "real value")
|
// returns an array of id => array of column => php value(so-called "real value")
|
||||||
public static function GetPredefinedObjects()
|
public static function GetPredefinedObjects()
|
||||||
{
|
{
|
||||||
@@ -181,15 +168,13 @@ class URP_Profiles extends UserRightsBaseClassGUI
|
|||||||
protected function OnDelete()
|
protected function OnDelete()
|
||||||
{
|
{
|
||||||
// Don't remove admin profile
|
// Don't remove admin profile
|
||||||
if ($this->Get('name') === ADMIN_PROFILE_NAME)
|
if ($this->Get('name') === ADMIN_PROFILE_NAME) {
|
||||||
{
|
|
||||||
throw new SecurityException(Dict::Format('UI:Login:Error:AccessAdmin'));
|
throw new SecurityException(Dict::Format('UI:Login:Error:AccessAdmin'));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Note: this may break the rule that says: "a user must have at least ONE profile" !
|
// Note: this may break the rule that says: "a user must have at least ONE profile" !
|
||||||
$oLnkSet = $this->Get('user_list');
|
$oLnkSet = $this->Get('user_list');
|
||||||
while($oLnk = $oLnkSet->Fetch())
|
while ($oLnk = $oLnkSet->Fetch()) {
|
||||||
{
|
|
||||||
$oLnk->DBDelete();
|
$oLnk->DBDelete();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -202,11 +187,10 @@ class URP_Profiles extends UserRightsBaseClassGUI
|
|||||||
* @param $sTargetState string The target state in which to evalutate the flags, if empty the current state will be used
|
* @param $sTargetState string The target state in which to evalutate the flags, if empty the current state will be used
|
||||||
* @return integer Flags: the binary combination of the flags applicable to this attribute
|
* @return integer Flags: the binary combination of the flags applicable to this attribute
|
||||||
*/
|
*/
|
||||||
public function GetAttributeFlags($sAttCode, &$aReasons = array(), $sTargetState = '')
|
public function GetAttributeFlags($sAttCode, &$aReasons = [], $sTargetState = '')
|
||||||
{
|
{
|
||||||
$iFlags = parent::GetAttributeFlags($sAttCode, $aReasons, $sTargetState);
|
$iFlags = parent::GetAttributeFlags($sAttCode, $aReasons, $sTargetState);
|
||||||
if (MetaModel::GetConfig()->Get('demo_mode'))
|
if (MetaModel::GetConfig()->Get('demo_mode')) {
|
||||||
{
|
|
||||||
$aReasons[] = 'Sorry, profiles are read-only in the demonstration mode!';
|
$aReasons[] = 'Sorry, profiles are read-only in the demonstration mode!';
|
||||||
$iFlags |= OPT_ATT_READONLY;
|
$iFlags |= OPT_ATT_READONLY;
|
||||||
}
|
}
|
||||||
@@ -214,52 +198,52 @@ class URP_Profiles extends UserRightsBaseClassGUI
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class URP_UserProfile extends UserRightsBaseClassGUI
|
class URP_UserProfile extends UserRightsBaseClassGUI
|
||||||
{
|
{
|
||||||
public static function Init()
|
public static function Init()
|
||||||
{
|
{
|
||||||
$aParams = array
|
$aParams =
|
||||||
(
|
[
|
||||||
"category" => "addon/userrights,grant_by_profile,filter",
|
"category" => "addon/userrights,grant_by_profile,filter",
|
||||||
"key_type" => "autoincrement",
|
"key_type" => "autoincrement",
|
||||||
"name_attcode" => array("userlogin", "profile"),
|
"name_attcode" => ["userlogin", "profile"],
|
||||||
"state_attcode" => "",
|
"state_attcode" => "",
|
||||||
"reconc_keys" => array(),
|
"reconc_keys" => [],
|
||||||
"db_table" => "priv_urp_userprofile",
|
"db_table" => "priv_urp_userprofile",
|
||||||
"db_key_field" => "id",
|
"db_key_field" => "id",
|
||||||
"db_finalclass_field" => "",
|
"db_finalclass_field" => "",
|
||||||
"is_link" => true, /** @since 3.1.0 N°6482 */
|
"is_link" => true, /** @since 3.1.0 N°6482 */
|
||||||
'uniqueness_rules' => array(
|
'uniqueness_rules' => [
|
||||||
'no_duplicate' => array(
|
'no_duplicate' => [
|
||||||
'attributes' => array(
|
'attributes' => [
|
||||||
0 => 'userid',
|
0 => 'userid',
|
||||||
1 => 'profileid',
|
1 => 'profileid',
|
||||||
),
|
],
|
||||||
'filter' => '',
|
'filter' => '',
|
||||||
'disabled' => false,
|
'disabled' => false,
|
||||||
'is_blocking' => true,
|
'is_blocking' => true,
|
||||||
),
|
],
|
||||||
),
|
],
|
||||||
);
|
];
|
||||||
MetaModel::Init_Params($aParams);
|
MetaModel::Init_Params($aParams);
|
||||||
//MetaModel::Init_InheritAttributes();
|
//MetaModel::Init_InheritAttributes();
|
||||||
MetaModel::Init_AddAttribute(new AttributeExternalKey("userid", array("targetclass" => "User", "jointype" => "", "allowed_values" => null, "sql" => "userid", "is_null_allowed" => false, "on_target_delete" => DEL_AUTO, "depends_on" => array())));
|
MetaModel::Init_AddAttribute(new AttributeExternalKey("userid", ["targetclass" => "User", "jointype" => "", "allowed_values" => null, "sql" => "userid", "is_null_allowed" => false, "on_target_delete" => DEL_AUTO, "depends_on" => []]));
|
||||||
MetaModel::Init_AddAttribute(new AttributeExternalField("userlogin", array("allowed_values" => null, "extkey_attcode" => 'userid', "target_attcode" => "login")));
|
MetaModel::Init_AddAttribute(new AttributeExternalField("userlogin", ["allowed_values" => null, "extkey_attcode" => 'userid', "target_attcode" => "login"]));
|
||||||
|
|
||||||
MetaModel::Init_AddAttribute(new AttributeExternalKey("profileid",
|
MetaModel::Init_AddAttribute(new AttributeExternalKey(
|
||||||
array("targetclass" => "URP_Profiles", "jointype" => "", "allowed_values" => null, "sql" => "profileid", "is_null_allowed" => false, "on_target_delete" => DEL_AUTO, "depends_on" => array(), "allow_target_creation" => false)));
|
"profileid",
|
||||||
MetaModel::Init_AddAttribute(new AttributeExternalField("profile", array("allowed_values" => null, "extkey_attcode" => 'profileid', "target_attcode" => "name")));
|
["targetclass" => "URP_Profiles", "jointype" => "", "allowed_values" => null, "sql" => "profileid", "is_null_allowed" => false, "on_target_delete" => DEL_AUTO, "depends_on" => [], "allow_target_creation" => false]
|
||||||
|
));
|
||||||
|
MetaModel::Init_AddAttribute(new AttributeExternalField("profile", ["allowed_values" => null, "extkey_attcode" => 'profileid', "target_attcode" => "name"]));
|
||||||
|
|
||||||
MetaModel::Init_AddAttribute(new AttributeString("reason", array("allowed_values" => null, "sql" => "description", "default_value" => null, "is_null_allowed" => true, "depends_on" => array())));
|
MetaModel::Init_AddAttribute(new AttributeString("reason", ["allowed_values" => null, "sql" => "description", "default_value" => null, "is_null_allowed" => true, "depends_on" => []]));
|
||||||
|
|
||||||
// Display lists
|
// Display lists
|
||||||
MetaModel::Init_SetZListItems('details', array('userid', 'profileid', 'reason')); // Attributes to be displayed for the complete details
|
MetaModel::Init_SetZListItems('details', ['userid', 'profileid', 'reason']); // Attributes to be displayed for the complete details
|
||||||
MetaModel::Init_SetZListItems('list', array('userid', 'profileid', 'reason')); // Attributes to be displayed for a list
|
MetaModel::Init_SetZListItems('list', ['userid', 'profileid', 'reason']); // Attributes to be displayed for a list
|
||||||
// Search criteria
|
// Search criteria
|
||||||
MetaModel::Init_SetZListItems('standard_search', array('userid', 'profileid')); // Criteria of the std search form
|
MetaModel::Init_SetZListItems('standard_search', ['userid', 'profileid']); // Criteria of the std search form
|
||||||
MetaModel::Init_SetZListItems('advanced_search', array('userid', 'profileid')); // Criteria of the advanced search form
|
MetaModel::Init_SetZListItems('advanced_search', ['userid', 'profileid']); // Criteria of the advanced search form
|
||||||
}
|
}
|
||||||
|
|
||||||
public function CheckToDelete(&$oDeletionPlan)
|
public function CheckToDelete(&$oDeletionPlan)
|
||||||
@@ -267,15 +251,14 @@ class URP_UserProfile extends UserRightsBaseClassGUI
|
|||||||
if (MetaModel::GetConfig()->Get('demo_mode')) {
|
if (MetaModel::GetConfig()->Get('demo_mode')) {
|
||||||
// Users deletion is NOT allowed in demo mode
|
// Users deletion is NOT allowed in demo mode
|
||||||
$oDeletionPlan->AddToDelete($this, null);
|
$oDeletionPlan->AddToDelete($this, null);
|
||||||
$oDeletionPlan->SetDeletionIssues($this, array('deletion not allowed in demo mode.'), true);
|
$oDeletionPlan->SetDeletionIssues($this, ['deletion not allowed in demo mode.'], true);
|
||||||
$oDeletionPlan->ComputeResults();
|
$oDeletionPlan->ComputeResults();
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
$this->CheckIfProfileIsAllowed(UR_ACTION_DELETE);
|
$this->CheckIfProfileIsAllowed(UR_ACTION_DELETE);
|
||||||
}
|
} catch (SecurityException $e) {
|
||||||
catch (SecurityException $e) {
|
|
||||||
// Users deletion is NOT allowed
|
// Users deletion is NOT allowed
|
||||||
$oDeletionPlan->AddToDelete($this, null);
|
$oDeletionPlan->AddToDelete($this, null);
|
||||||
$oDeletionPlan->SetDeletionIssues($this, [$e->getMessage()], true);
|
$oDeletionPlan->SetDeletionIssues($this, [$e->getMessage()], true);
|
||||||
@@ -292,15 +275,14 @@ class URP_UserProfile extends UserRightsBaseClassGUI
|
|||||||
if (MetaModel::GetConfig()->Get('demo_mode')) {
|
if (MetaModel::GetConfig()->Get('demo_mode')) {
|
||||||
// Users deletion is NOT allowed in demo mode
|
// Users deletion is NOT allowed in demo mode
|
||||||
$oDeletionPlan->AddToDelete($this, null);
|
$oDeletionPlan->AddToDelete($this, null);
|
||||||
$oDeletionPlan->SetDeletionIssues($this, array('deletion not allowed in demo mode.'), true);
|
$oDeletionPlan->SetDeletionIssues($this, ['deletion not allowed in demo mode.'], true);
|
||||||
$oDeletionPlan->ComputeResults();
|
$oDeletionPlan->ComputeResults();
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
$this->CheckIfProfileIsAllowed(UR_ACTION_DELETE);
|
$this->CheckIfProfileIsAllowed(UR_ACTION_DELETE);
|
||||||
}
|
} catch (SecurityException $e) {
|
||||||
catch (SecurityException $e) {
|
|
||||||
// Users deletion is NOT allowed
|
// Users deletion is NOT allowed
|
||||||
$oDeletionPlan->AddToDelete($this, null);
|
$oDeletionPlan->AddToDelete($this, null);
|
||||||
$oDeletionPlan->SetDeletionIssues($this, [$e->getMessage()], true);
|
$oDeletionPlan->SetDeletionIssues($this, [$e->getMessage()], true);
|
||||||
@@ -336,29 +318,30 @@ class URP_UserProfile extends UserRightsBaseClassGUI
|
|||||||
protected function CheckIfProfileIsAllowed($iActionCode)
|
protected function CheckIfProfileIsAllowed($iActionCode)
|
||||||
{
|
{
|
||||||
// When initializing or admin, we need to let everything pass trough
|
// When initializing or admin, we need to let everything pass trough
|
||||||
if (!UserRights::IsLoggedIn() || UserRights::IsAdministrator()) { return; }
|
if (!UserRights::IsLoggedIn() || UserRights::IsAdministrator()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Only administrators can manage administrators
|
// Only administrators can manage administrators
|
||||||
$iOrigUserId = $this->GetOriginal('userid');
|
$iOrigUserId = $this->GetOriginal('userid');
|
||||||
if (!empty($iOrigUserId))
|
if (!empty($iOrigUserId)) {
|
||||||
{
|
|
||||||
$oUser = MetaModel::GetObject('User', $iOrigUserId, true, true);
|
$oUser = MetaModel::GetObject('User', $iOrigUserId, true, true);
|
||||||
if (UserRights::IsAdministrator($oUser) && !UserRights::IsAdministrator())
|
if (UserRights::IsAdministrator($oUser) && !UserRights::IsAdministrator()) {
|
||||||
{
|
|
||||||
throw new SecurityException(Dict::Format('UI:Login:Error:AccessRestricted'));
|
throw new SecurityException(Dict::Format('UI:Login:Error:AccessRestricted'));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$oUser = MetaModel::GetObject('User', $this->Get('userid'), true, true);
|
$oUser = MetaModel::GetObject('User', $this->Get('userid'), true, true);
|
||||||
if (UserRights::IsAdministrator($oUser) && !UserRights::IsAdministrator())
|
if (UserRights::IsAdministrator($oUser) && !UserRights::IsAdministrator()) {
|
||||||
{
|
|
||||||
throw new SecurityException(Dict::Format('UI:Login:Error:AccessRestricted'));
|
throw new SecurityException(Dict::Format('UI:Login:Error:AccessRestricted'));
|
||||||
}
|
}
|
||||||
if (!UserRights::IsActionAllowed(get_class($this), $iActionCode, DBObjectSet::FromObject($this)))
|
|
||||||
{
|
$oSet = new \ormLinkSet(get_class($oUser), 'profile_list', \DBObjectSet::FromScratch(\URP_UserProfile::class));
|
||||||
|
$oSet->AddItem(MetaModel::NewObject('URP_UserProfile', ['profileid' => $this->GetKey(), 'reason' => 'CheckIfProfileIsAllowed']));
|
||||||
|
|
||||||
|
if (!UserRights::IsActionAllowed(get_class($this), $iActionCode, $oSet)) {
|
||||||
throw new SecurityException(Dict::Format('UI:Error:ObjectCannotBeUpdated'));
|
throw new SecurityException(Dict::Format('UI:Error:ObjectCannotBeUpdated'));
|
||||||
}
|
}
|
||||||
if (!UserRights::IsAdministrator() && ($this->Get('profile') === ADMIN_PROFILE_NAME))
|
if (!UserRights::IsAdministrator() && ($this->Get('profile') === ADMIN_PROFILE_NAME)) {
|
||||||
{
|
|
||||||
throw new SecurityException(Dict::Format('UI:Login:Error:AccessAdmin'));
|
throw new SecurityException(Dict::Format('UI:Login:Error:AccessAdmin'));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -369,33 +352,33 @@ class URP_UserOrg extends UserRightsBaseClassGUI
|
|||||||
{
|
{
|
||||||
public static function Init()
|
public static function Init()
|
||||||
{
|
{
|
||||||
$aParams = array
|
$aParams =
|
||||||
(
|
[
|
||||||
"category" => "addon/userrights,grant_by_profile",
|
"category" => "addon/userrights,grant_by_profile",
|
||||||
"key_type" => "autoincrement",
|
"key_type" => "autoincrement",
|
||||||
"name_attcode" => array("userlogin", "allowed_org_name"),
|
"name_attcode" => ["userlogin", "allowed_org_name"],
|
||||||
"state_attcode" => "",
|
"state_attcode" => "",
|
||||||
"reconc_keys" => array(),
|
"reconc_keys" => [],
|
||||||
"db_table" => "priv_urp_userorg",
|
"db_table" => "priv_urp_userorg",
|
||||||
"db_key_field" => "id",
|
"db_key_field" => "id",
|
||||||
"db_finalclass_field" => "",
|
"db_finalclass_field" => "",
|
||||||
);
|
];
|
||||||
MetaModel::Init_Params($aParams);
|
MetaModel::Init_Params($aParams);
|
||||||
//MetaModel::Init_InheritAttributes();
|
//MetaModel::Init_InheritAttributes();
|
||||||
MetaModel::Init_AddAttribute(new AttributeExternalKey("userid", array("targetclass"=>"User", "jointype"=> "", "allowed_values"=>null, "sql"=>"userid", "is_null_allowed"=>false, "on_target_delete"=>DEL_AUTO, "depends_on"=>array())));
|
MetaModel::Init_AddAttribute(new AttributeExternalKey("userid", ["targetclass" => "User", "jointype" => "", "allowed_values" => null, "sql" => "userid", "is_null_allowed" => false, "on_target_delete" => DEL_AUTO, "depends_on" => []]));
|
||||||
MetaModel::Init_AddAttribute(new AttributeExternalField("userlogin", array("allowed_values"=>null, "extkey_attcode"=> 'userid', "target_attcode"=>"login")));
|
MetaModel::Init_AddAttribute(new AttributeExternalField("userlogin", ["allowed_values" => null, "extkey_attcode" => 'userid', "target_attcode" => "login"]));
|
||||||
|
|
||||||
MetaModel::Init_AddAttribute(new AttributeExternalKey("allowed_org_id", array("targetclass"=>"Organization", "jointype"=> "", "allowed_values"=>null, "sql"=>"allowed_org_id", "is_null_allowed"=>false, "on_target_delete"=>DEL_AUTO, "depends_on"=>array())));
|
MetaModel::Init_AddAttribute(new AttributeExternalKey("allowed_org_id", ["targetclass" => "Organization", "jointype" => "", "allowed_values" => null, "sql" => "allowed_org_id", "is_null_allowed" => false, "on_target_delete" => DEL_AUTO, "depends_on" => []]));
|
||||||
MetaModel::Init_AddAttribute(new AttributeExternalField("allowed_org_name", array("allowed_values"=>null, "extkey_attcode"=> 'allowed_org_id', "target_attcode"=>"name")));
|
MetaModel::Init_AddAttribute(new AttributeExternalField("allowed_org_name", ["allowed_values" => null, "extkey_attcode" => 'allowed_org_id', "target_attcode" => "name"]));
|
||||||
|
|
||||||
MetaModel::Init_AddAttribute(new AttributeString("reason", array("allowed_values"=>null, "sql"=>"reason", "default_value"=>null, "is_null_allowed"=>true, "depends_on"=>array())));
|
MetaModel::Init_AddAttribute(new AttributeString("reason", ["allowed_values" => null, "sql" => "reason", "default_value" => null, "is_null_allowed" => true, "depends_on" => []]));
|
||||||
|
|
||||||
// Display lists
|
// Display lists
|
||||||
MetaModel::Init_SetZListItems('details', array('userid', 'allowed_org_id', 'reason')); // Attributes to be displayed for the complete details
|
MetaModel::Init_SetZListItems('details', ['userid', 'allowed_org_id', 'reason']); // Attributes to be displayed for the complete details
|
||||||
MetaModel::Init_SetZListItems('list', array('allowed_org_id', 'reason')); // Attributes to be displayed for a list
|
MetaModel::Init_SetZListItems('list', ['allowed_org_id', 'reason']); // Attributes to be displayed for a list
|
||||||
// Search criteria
|
// Search criteria
|
||||||
MetaModel::Init_SetZListItems('standard_search', array('userid', 'allowed_org_id')); // Criteria of the std search form
|
MetaModel::Init_SetZListItems('standard_search', ['userid', 'allowed_org_id']); // Criteria of the std search form
|
||||||
MetaModel::Init_SetZListItems('advanced_search', array('userid', 'allowed_org_id')); // Criteria of the advanced search form
|
MetaModel::Init_SetZListItems('advanced_search', ['userid', 'allowed_org_id']); // Criteria of the advanced search form
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function OnInsert()
|
protected function OnInsert()
|
||||||
@@ -418,40 +401,37 @@ class URP_UserOrg extends UserRightsBaseClassGUI
|
|||||||
*/
|
*/
|
||||||
protected function CheckIfOrgIsAllowed()
|
protected function CheckIfOrgIsAllowed()
|
||||||
{
|
{
|
||||||
if (!UserRights::IsLoggedIn() || UserRights::IsAdministrator()) { return; }
|
if (!UserRights::IsLoggedIn() || UserRights::IsAdministrator()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
$oUser = UserRights::GetUserObject();
|
$oUser = UserRights::GetUserObject();
|
||||||
$oAddon = UserRights::GetModuleInstance();
|
$oAddon = UserRights::GetModuleInstance();
|
||||||
$aOrgs = $oAddon->GetUserOrgs($oUser, '');
|
$aOrgs = $oAddon->GetUserOrgs($oUser, '');
|
||||||
if (count($aOrgs) > 0)
|
if (count($aOrgs) > 0) {
|
||||||
{
|
|
||||||
$iOrigOrgId = $this->GetOriginal('allowed_org_id');
|
$iOrigOrgId = $this->GetOriginal('allowed_org_id');
|
||||||
if ((!empty($iOrigOrgId) && !in_array($iOrigOrgId, $aOrgs)) || !in_array($this->Get('allowed_org_id'), $aOrgs))
|
if ((!empty($iOrigOrgId) && !in_array($iOrigOrgId, $aOrgs)) || !in_array($this->Get('allowed_org_id'), $aOrgs)) {
|
||||||
{
|
|
||||||
throw new SecurityException(Dict::Format('Class:User/Error:OrganizationNotAllowed'));
|
throw new SecurityException(Dict::Format('Class:User/Error:OrganizationNotAllowed'));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class UserRightsProfile extends UserRightsAddOnAPI
|
class UserRightsProfile extends UserRightsAddOnAPI
|
||||||
{
|
{
|
||||||
static public $m_aActionCodes = array(
|
public static $m_aActionCodes = [
|
||||||
UR_ACTION_READ => 'r',
|
UR_ACTION_READ => 'r',
|
||||||
UR_ACTION_MODIFY => 'w',
|
UR_ACTION_MODIFY => 'w',
|
||||||
UR_ACTION_DELETE => 'd',
|
UR_ACTION_DELETE => 'd',
|
||||||
UR_ACTION_BULK_READ => 'br',
|
UR_ACTION_BULK_READ => 'br',
|
||||||
UR_ACTION_BULK_MODIFY => 'bw',
|
UR_ACTION_BULK_MODIFY => 'bw',
|
||||||
UR_ACTION_BULK_DELETE => 'bd',
|
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, ...]
|
* @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
|
* @since 2.7.10 3.0.4 3.1.1 3.2.0 N°6887
|
||||||
*/
|
*/
|
||||||
private $aUsersProfilesList = [];
|
private $aUsersProfilesList = [];
|
||||||
|
|
||||||
// Installation: create the very first user
|
// Installation: create the very first user
|
||||||
@@ -472,8 +452,7 @@ class UserRightsProfile extends UserRightsAddOnAPI
|
|||||||
$oContact = MetaModel::NewObject('Person');
|
$oContact = MetaModel::NewObject('Person');
|
||||||
$oContact->Set('name', 'My last name');
|
$oContact->Set('name', 'My last name');
|
||||||
$oContact->Set('first_name', 'My first name');
|
$oContact->Set('first_name', 'My first name');
|
||||||
if (MetaModel::IsValidAttCode('Person', 'org_id'))
|
if (MetaModel::IsValidAttCode('Person', 'org_id')) {
|
||||||
{
|
|
||||||
$oContact->Set('org_id', $iOrgId);
|
$oContact->Set('org_id', $iOrgId);
|
||||||
}
|
}
|
||||||
$oContact->Set('email', 'my.email@foo.org');
|
$oContact->Set('email', 'my.email@foo.org');
|
||||||
@@ -481,24 +460,19 @@ class UserRightsProfile extends UserRightsAddOnAPI
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
$oUser = new UserLocal();
|
$oUser = new UserLocal();
|
||||||
$oUser->Set('login', $sAdminUser);
|
$oUser->Set('login', $sAdminUser);
|
||||||
$oUser->Set('password', $sAdminPwd);
|
$oUser->Set('password', $sAdminPwd);
|
||||||
if (MetaModel::IsValidAttCode('UserLocal', 'contactid') && ($iContactId != 0))
|
if (MetaModel::IsValidAttCode('UserLocal', 'contactid') && ($iContactId != 0)) {
|
||||||
{
|
|
||||||
$oUser->Set('contactid', $iContactId);
|
$oUser->Set('contactid', $iContactId);
|
||||||
}
|
}
|
||||||
$oUser->Set('language', $sLanguage); // Language was chosen during the installation
|
$oUser->Set('language', $sLanguage); // Language was chosen during the installation
|
||||||
|
|
||||||
// Add this user to the very specific 'admin' profile
|
// Add this user to the very specific 'admin' profile
|
||||||
$oAdminProfile = MetaModel::GetObjectFromOQL("SELECT URP_Profiles WHERE name = :name", array('name' => ADMIN_PROFILE_NAME), true /*all data*/);
|
$oAdminProfile = MetaModel::GetObjectFromOQL("SELECT URP_Profiles WHERE name = :name", ['name' => ADMIN_PROFILE_NAME], true /*all data*/);
|
||||||
if (is_object($oAdminProfile))
|
if (is_object($oAdminProfile)) {
|
||||||
{
|
$oSet = new \ormLinkSet(UserLocal::class, 'profile_list', \DBObjectSet::FromScratch(\URP_UserProfile::class));
|
||||||
$oUserProfile = new URP_UserProfile();
|
$oSet->AddItem(MetaModel::NewObject('URP_UserProfile', ['profileid' => $oAdminProfile->GetKey(), 'reason' => 'CreateAdministrator']));
|
||||||
$oUserProfile->Set('profileid', $oAdminProfile->GetKey());
|
|
||||||
$oUserProfile->Set('reason', 'By definition, the administrator must have the administrator profile');
|
|
||||||
$oSet = DBObjectSet::FromObject($oUserProfile);
|
|
||||||
$oUser->Set('profile_list', $oSet);
|
$oUser->Set('profile_list', $oSet);
|
||||||
}
|
}
|
||||||
$iUserId = $oUser->DBInsertNoReload();
|
$iUserId = $oUser->DBInsertNoReload();
|
||||||
@@ -509,11 +483,11 @@ class UserRightsProfile extends UserRightsAddOnAPI
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
protected $m_aUserOrgs = array(); // userid -> array of orgid
|
protected $m_aUserOrgs = []; // userid -> array of orgid
|
||||||
protected $m_aAdministrators = null; // [user id]
|
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)
|
// Built on demand, could be optimized if necessary (doing a query for each attribute that needs to be read)
|
||||||
protected $m_aObjectActionGrants = array();
|
protected $m_aObjectActionGrants = [];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Read and cache organizations allowed to the given user
|
* Read and cache organizations allowed to the given user
|
||||||
@@ -528,31 +502,25 @@ class UserRightsProfile extends UserRightsAddOnAPI
|
|||||||
public function GetUserOrgs($oUser, $sClass)
|
public function GetUserOrgs($oUser, $sClass)
|
||||||
{
|
{
|
||||||
$iUser = $oUser->GetKey();
|
$iUser = $oUser->GetKey();
|
||||||
if (!array_key_exists($iUser, $this->m_aUserOrgs))
|
if (!array_key_exists($iUser, $this->m_aUserOrgs)) {
|
||||||
{
|
$this->m_aUserOrgs[$iUser] = [];
|
||||||
$this->m_aUserOrgs[$iUser] = array();
|
|
||||||
|
|
||||||
$sHierarchicalKeyCode = MetaModel::IsHierarchicalClass('Organization');
|
$sHierarchicalKeyCode = MetaModel::IsHierarchicalClass('Organization');
|
||||||
if ($sHierarchicalKeyCode !== false)
|
if ($sHierarchicalKeyCode !== false) {
|
||||||
{
|
|
||||||
$sUserOrgQuery = 'SELECT UserOrg, Org FROM Organization AS Org JOIN Organization AS Root ON Org.'.$sHierarchicalKeyCode.' BELOW Root.id JOIN URP_UserOrg AS UserOrg ON UserOrg.allowed_org_id = Root.id WHERE UserOrg.userid = :userid';
|
$sUserOrgQuery = 'SELECT UserOrg, Org FROM Organization AS Org JOIN Organization AS Root ON Org.'.$sHierarchicalKeyCode.' BELOW Root.id JOIN URP_UserOrg AS UserOrg ON UserOrg.allowed_org_id = Root.id WHERE UserOrg.userid = :userid';
|
||||||
$oUserOrgSet = new DBObjectSet(DBObjectSearch::FromOQL_AllData($sUserOrgQuery), array(), array('userid' => $iUser));
|
$oUserOrgSet = new DBObjectSet(DBObjectSearch::FromOQL_AllData($sUserOrgQuery), [], ['userid' => $iUser]);
|
||||||
while ($aRow = $oUserOrgSet->FetchAssoc())
|
while ($aRow = $oUserOrgSet->FetchAssoc()) {
|
||||||
{
|
|
||||||
$oOrg = $aRow['Org'];
|
$oOrg = $aRow['Org'];
|
||||||
$this->m_aUserOrgs[$iUser][] = $oOrg->GetKey();
|
$this->m_aUserOrgs[$iUser][] = $oOrg->GetKey();
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
$oSearch = new DBObjectSearch('URP_UserOrg');
|
$oSearch = new DBObjectSearch('URP_UserOrg');
|
||||||
$oSearch->AllowAllData();
|
$oSearch->AllowAllData();
|
||||||
$oCondition = new BinaryExpression(new FieldExpression('userid'), '=', new VariableExpression('userid'));
|
$oCondition = new BinaryExpression(new FieldExpression('userid'), '=', new VariableExpression('userid'));
|
||||||
$oSearch->AddConditionExpression($oCondition);
|
$oSearch->AddConditionExpression($oCondition);
|
||||||
|
|
||||||
$oUserOrgSet = new DBObjectSet($oSearch, array(), array('userid' => $iUser));
|
$oUserOrgSet = new DBObjectSet($oSearch, [], ['userid' => $iUser]);
|
||||||
while ($oUserOrg = $oUserOrgSet->Fetch())
|
while ($oUserOrg = $oUserOrgSet->Fetch()) {
|
||||||
{
|
|
||||||
$this->m_aUserOrgs[$iUser][] = $oUserOrg->Get('allowed_org_id');
|
$this->m_aUserOrgs[$iUser][] = $oUserOrg->Get('allowed_org_id');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -563,21 +531,20 @@ class UserRightsProfile extends UserRightsAddOnAPI
|
|||||||
public function ResetCache()
|
public function ResetCache()
|
||||||
{
|
{
|
||||||
// Loaded by Load cache
|
// Loaded by Load cache
|
||||||
$this->m_aUserOrgs = array();
|
$this->m_aUserOrgs = [];
|
||||||
|
|
||||||
// Cache
|
// Cache
|
||||||
$this->m_aObjectActionGrants = array();
|
$this->m_aObjectActionGrants = [];
|
||||||
$this->m_aAdministrators = null;
|
$this->m_aAdministrators = null;
|
||||||
|
$this->aUsersProfilesList = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
public function LoadCache()
|
public function LoadCache()
|
||||||
{
|
{
|
||||||
static $bSharedObjectInitialized = false;
|
static $bSharedObjectInitialized = false;
|
||||||
if (!$bSharedObjectInitialized)
|
if (!$bSharedObjectInitialized) {
|
||||||
{
|
|
||||||
$bSharedObjectInitialized = true;
|
$bSharedObjectInitialized = true;
|
||||||
if (self::HasSharing())
|
if (self::HasSharing()) {
|
||||||
{
|
|
||||||
SharedObject::InitSharedClassProperties();
|
SharedObject::InitSharedClassProperties();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -615,45 +582,40 @@ class UserRightsProfile extends UserRightsAddOnAPI
|
|||||||
*/
|
*/
|
||||||
public function ListProfiles($oUser)
|
public function ListProfiles($oUser)
|
||||||
{
|
{
|
||||||
$aRet = array();
|
$aRet = [];
|
||||||
$oSearch = new DBObjectSearch('URP_UserProfile');
|
$oSearch = new DBObjectSearch('URP_UserProfile');
|
||||||
$oSearch->AllowAllData();
|
$oSearch->AllowAllData();
|
||||||
$oSearch->NoContextParameters();
|
$oSearch->NoContextParameters();
|
||||||
$oSearch->Addcondition('userid', $oUser->GetKey(), '=');
|
$oSearch->Addcondition('userid', $oUser->GetKey(), '=');
|
||||||
$oProfiles = new DBObjectSet($oSearch);
|
$oProfiles = new DBObjectSet($oSearch);
|
||||||
while ($oUserProfile = $oProfiles->Fetch())
|
while ($oUserProfile = $oProfiles->Fetch()) {
|
||||||
{
|
|
||||||
$aRet[$oUserProfile->Get('profileid')] = $oUserProfile->Get('profileid_friendlyname');
|
$aRet[$oUserProfile->Get('profileid')] = $oUserProfile->Get('profileid_friendlyname');
|
||||||
}
|
}
|
||||||
return $aRet;
|
return $aRet;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function GetSelectFilter($oUser, $sClass, $aSettings = array())
|
public function GetSelectFilter($oUser, $sClass, $aSettings = [])
|
||||||
{
|
{
|
||||||
$this->LoadCache();
|
$this->LoadCache();
|
||||||
|
|
||||||
// Let us pass an administrator for bypassing the grant matrix check in order to test this method without the need to set up a complex profile
|
// Let us pass an administrator for bypassing the grant matrix check in order to test this method without the need to set up a complex profile
|
||||||
// In the nominal case Administrators never end up here (since they completely bypass GetSelectFilter)
|
// In the nominal case Administrators never end up here (since they completely bypass GetSelectFilter)
|
||||||
if (!static::IsAdministrator($oUser) && (MetaModel::HasCategory($sClass, 'silo') || MetaModel::HasCategory($sClass, 'bizmodel')))
|
if (!static::IsAdministrator($oUser) && (MetaModel::HasCategory($sClass, 'silo') || MetaModel::HasCategory($sClass, 'bizmodel'))) {
|
||||||
{
|
|
||||||
// N°4354 - Categories 'silo' and 'bizmodel' do check the grant matrix. Whereas 'filter' always allows to read (but the result can be filtered)
|
// N°4354 - Categories 'silo' and 'bizmodel' do check the grant matrix. Whereas 'filter' always allows to read (but the result can be filtered)
|
||||||
$aObjectPermissions = $this->GetUserActionGrant($oUser, $sClass, UR_ACTION_READ);
|
$aObjectPermissions = $this->GetUserActionGrant($oUser, $sClass, UR_ACTION_READ);
|
||||||
if ($aObjectPermissions['permission'] == UR_ALLOWED_NO)
|
if ($aObjectPermissions['permission'] == UR_ALLOWED_NO) {
|
||||||
{
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$oFilter = true;
|
$oFilter = true;
|
||||||
$aConditions = array();
|
$aConditions = [];
|
||||||
|
|
||||||
// Determine if this class is part of a silo and build the filter for it
|
// Determine if this class is part of a silo and build the filter for it
|
||||||
$sAttCode = self::GetOwnerOrganizationAttCode($sClass);
|
$sAttCode = self::GetOwnerOrganizationAttCode($sClass);
|
||||||
if (!is_null($sAttCode))
|
if (!is_null($sAttCode)) {
|
||||||
{
|
|
||||||
$aUserOrgs = $this->GetUserOrgs($oUser, $sClass);
|
$aUserOrgs = $this->GetUserOrgs($oUser, $sClass);
|
||||||
if (count($aUserOrgs) > 0)
|
if (count($aUserOrgs) > 0) {
|
||||||
{
|
|
||||||
$oFilter = $this->MakeSelectFilter($sClass, $aUserOrgs, $aSettings, $sAttCode);
|
$oFilter = $this->MakeSelectFilter($sClass, $aUserOrgs, $aSettings, $sAttCode);
|
||||||
}
|
}
|
||||||
// else: No org means 'any org'
|
// else: No org means 'any org'
|
||||||
@@ -662,20 +624,15 @@ class UserRightsProfile extends UserRightsAddOnAPI
|
|||||||
|
|
||||||
// Specific conditions to hide, for non-administrators, the Administrator Users, the Administrator Profile and related links
|
// Specific conditions to hide, for non-administrators, the Administrator Users, the Administrator Profile and related links
|
||||||
// Note: when logged as an administrator, GetSelectFilter is completely bypassed.
|
// Note: when logged as an administrator, GetSelectFilter is completely bypassed.
|
||||||
if ($this->AdministratorsAreHidden())
|
if ($this->AdministratorsAreHidden()) {
|
||||||
{
|
if ($sClass == 'URP_Profiles') {
|
||||||
if ($sClass == 'URP_Profiles')
|
|
||||||
{
|
|
||||||
$oExpression = new FieldExpression('id', $sClass);
|
$oExpression = new FieldExpression('id', $sClass);
|
||||||
$oScalarExpr = new ScalarExpression(1);
|
$oScalarExpr = new ScalarExpression(1);
|
||||||
|
|
||||||
$aConditions[] = new BinaryExpression($oExpression, '!=', $oScalarExpr);
|
$aConditions[] = new BinaryExpression($oExpression, '!=', $oScalarExpr);
|
||||||
}
|
} elseif (($sClass == 'URP_UserProfile') || ($sClass == 'User') || (is_subclass_of($sClass, 'User'))) {
|
||||||
else if (($sClass == 'URP_UserProfile') || ($sClass == 'User') || (is_subclass_of($sClass, 'User')))
|
|
||||||
{
|
|
||||||
$aAdministrators = $this->GetAdministrators();
|
$aAdministrators = $this->GetAdministrators();
|
||||||
if (count($aAdministrators) > 0)
|
if (count($aAdministrators) > 0) {
|
||||||
{
|
|
||||||
$sAttCode = ($sClass == 'URP_UserProfile') ? 'userid' : 'id';
|
$sAttCode = ($sClass == 'URP_UserProfile') ? 'userid' : 'id';
|
||||||
$oExpression = new FieldExpression($sAttCode, $sClass);
|
$oExpression = new FieldExpression($sAttCode, $sClass);
|
||||||
$oListExpr = ListExpression::FromScalars($aAdministrators);
|
$oListExpr = ListExpression::FromScalars($aAdministrators);
|
||||||
@@ -685,17 +642,14 @@ class UserRightsProfile extends UserRightsAddOnAPI
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Handling of the added conditions
|
// Handling of the added conditions
|
||||||
if (count($aConditions) > 0)
|
if (count($aConditions) > 0) {
|
||||||
{
|
if ($oFilter === true) {
|
||||||
if($oFilter === true)
|
|
||||||
{
|
|
||||||
// No 'silo' filter, let's build a clean one
|
// No 'silo' filter, let's build a clean one
|
||||||
$oFilter = new DBObjectSearch($sClass);
|
$oFilter = new DBObjectSearch($sClass);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add the conditions to the filter
|
// Add the conditions to the filter
|
||||||
foreach($aConditions as $oCondition)
|
foreach ($aConditions as $oCondition) {
|
||||||
{
|
|
||||||
$oFilter->AddConditionExpression($oCondition);
|
$oFilter->AddConditionExpression($oCondition);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -710,10 +664,9 @@ class UserRightsProfile extends UserRightsAddOnAPI
|
|||||||
*/
|
*/
|
||||||
private function GetAdministrators()
|
private function GetAdministrators()
|
||||||
{
|
{
|
||||||
if ($this->m_aAdministrators === null)
|
if ($this->m_aAdministrators === null) {
|
||||||
{
|
|
||||||
// Find all administrators
|
// Find all administrators
|
||||||
$this->m_aAdministrators = array();
|
$this->m_aAdministrators = [];
|
||||||
$oAdministratorsFilter = new DBObjectSearch('User');
|
$oAdministratorsFilter = new DBObjectSearch('User');
|
||||||
$oLnkFilter = new DBObjectSearch('URP_UserProfile');
|
$oLnkFilter = new DBObjectSearch('URP_UserProfile');
|
||||||
$oExpression = new FieldExpression('profileid', 'URP_UserProfile');
|
$oExpression = new FieldExpression('profileid', 'URP_UserProfile');
|
||||||
@@ -723,9 +676,8 @@ class UserRightsProfile extends UserRightsAddOnAPI
|
|||||||
$oAdministratorsFilter->AddCondition_ReferencedBy($oLnkFilter, 'userid');
|
$oAdministratorsFilter->AddCondition_ReferencedBy($oLnkFilter, 'userid');
|
||||||
$oAdministratorsFilter->AllowAllData(true); // Mandatory to prevent infinite recursion !!
|
$oAdministratorsFilter->AllowAllData(true); // Mandatory to prevent infinite recursion !!
|
||||||
$oSet = new DBObjectSet($oAdministratorsFilter);
|
$oSet = new DBObjectSet($oAdministratorsFilter);
|
||||||
$oSet->OptimizeColumnLoad(array('User' => array('login')));
|
$oSet->OptimizeColumnLoad(['User' => ['login']]);
|
||||||
while($oUser = $oSet->Fetch())
|
while ($oUser = $oSet->Fetch()) {
|
||||||
{
|
|
||||||
$this->m_aAdministrators[] = $oUser->GetKey();
|
$this->m_aAdministrators[] = $oUser->GetKey();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -741,7 +693,6 @@ class UserRightsProfile extends UserRightsAddOnAPI
|
|||||||
return ((bool)MetaModel::GetConfig()->Get('security.hide_administrators'));
|
return ((bool)MetaModel::GetConfig()->Get('security.hide_administrators'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// This verb has been made public to allow the development of an accurate feedback for the current configuration
|
// This verb has been made public to allow the development of an accurate feedback for the current configuration
|
||||||
public function GetProfileActionGrant($iProfile, $sClass, $sAction)
|
public function GetProfileActionGrant($iProfile, $sClass, $sAction)
|
||||||
{
|
{
|
||||||
@@ -758,33 +709,29 @@ class UserRightsProfile extends UserRightsAddOnAPI
|
|||||||
// load and cache permissions for the current user on the given class
|
// load and cache permissions for the current user on the given class
|
||||||
//
|
//
|
||||||
$iUser = $oUser->GetKey();
|
$iUser = $oUser->GetKey();
|
||||||
if (isset($this->m_aObjectActionGrants[$iUser][$sClass][$iActionCode])){
|
if (isset($this->m_aObjectActionGrants[$iUser][$sClass][$iActionCode])) {
|
||||||
$aTest = $this->m_aObjectActionGrants[$iUser][$sClass][$iActionCode];
|
$aTest = $this->m_aObjectActionGrants[$iUser][$sClass][$iActionCode];
|
||||||
if (is_array($aTest)) return $aTest;
|
if (is_array($aTest)) {
|
||||||
|
return $aTest;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$sAction = self::$m_aActionCodes[$iActionCode];
|
$sAction = self::$m_aActionCodes[$iActionCode];
|
||||||
|
|
||||||
$bStatus = null;
|
$bStatus = null;
|
||||||
// Cache user's profiles
|
// Cache user's profiles
|
||||||
if(false === array_key_exists($iUser, $this->aUsersProfilesList)){
|
if (false === array_key_exists($iUser, $this->aUsersProfilesList)) {
|
||||||
$this->aUsersProfilesList[$iUser] = UserRights::ListProfiles($oUser);
|
$this->aUsersProfilesList[$iUser] = UserRights::ListProfiles($oUser);
|
||||||
}
|
}
|
||||||
// Call the API of UserRights because it caches the list for us
|
// Call the API of UserRights because it caches the list for us
|
||||||
foreach($this->aUsersProfilesList[$iUser] as $iProfile => $oProfile)
|
foreach ($this->aUsersProfilesList[$iUser] as $iProfile => $oProfile) {
|
||||||
{
|
|
||||||
$bGrant = $this->GetProfileActionGrant($iProfile, $sClass, $sAction);
|
$bGrant = $this->GetProfileActionGrant($iProfile, $sClass, $sAction);
|
||||||
if (!is_null($bGrant))
|
if (!is_null($bGrant)) {
|
||||||
{
|
if ($bGrant) {
|
||||||
if ($bGrant)
|
if (is_null($bStatus)) {
|
||||||
{
|
|
||||||
if (is_null($bStatus))
|
|
||||||
{
|
|
||||||
$bStatus = true;
|
$bStatus = true;
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
$bStatus = false;
|
$bStatus = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -792,9 +739,9 @@ class UserRightsProfile extends UserRightsAddOnAPI
|
|||||||
|
|
||||||
$iPermission = $bStatus ? UR_ALLOWED_YES : UR_ALLOWED_NO;
|
$iPermission = $bStatus ? UR_ALLOWED_YES : UR_ALLOWED_NO;
|
||||||
|
|
||||||
$aRes = array(
|
$aRes = [
|
||||||
'permission' => $iPermission,
|
'permission' => $iPermission,
|
||||||
);
|
];
|
||||||
$this->m_aObjectActionGrants[$iUser][$sClass][$iActionCode] = $aRes;
|
$this->m_aObjectActionGrants[$iUser][$sClass][$iActionCode] = $aRes;
|
||||||
return $aRes;
|
return $aRes;
|
||||||
}
|
}
|
||||||
@@ -809,20 +756,13 @@ class UserRightsProfile extends UserRightsAddOnAPI
|
|||||||
// Note: In most cases the object set is ignored because it was interesting to optimize for huge data sets
|
// Note: In most cases 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
|
// and acceptable to consider only the root class of the object set
|
||||||
|
|
||||||
if ($iPermission != UR_ALLOWED_YES)
|
if ($iPermission != UR_ALLOWED_YES) {
|
||||||
{
|
|
||||||
// It is already NO for everyone... that's the final word!
|
// It is already NO for everyone... that's the final word!
|
||||||
}
|
} elseif ($iActionCode == UR_ACTION_READ) {
|
||||||
elseif ($iActionCode == UR_ACTION_READ)
|
|
||||||
{
|
|
||||||
// We are protected by GetSelectFilter: the object set contains objects allowed or shared for reading
|
// We are protected by GetSelectFilter: the object set contains objects allowed or shared for reading
|
||||||
}
|
} elseif ($iActionCode == UR_ACTION_BULK_READ) {
|
||||||
elseif ($iActionCode == UR_ACTION_BULK_READ)
|
|
||||||
{
|
|
||||||
// We are protected by GetSelectFilter: the object set contains objects allowed or shared for reading
|
// We are protected by GetSelectFilter: the object set contains objects allowed or shared for reading
|
||||||
}
|
} elseif ($oInstanceSet) {
|
||||||
elseif ($oInstanceSet)
|
|
||||||
{
|
|
||||||
// We are protected by GetSelectFilter: the object set contains objects allowed or shared for reading
|
// We are protected by GetSelectFilter: the object set contains objects allowed or shared for reading
|
||||||
// We have to answer NO for objects shared for reading purposes
|
// We have to answer NO for objects shared for reading purposes
|
||||||
if (self::HasSharing() && SharedObject::GetSharedClassProperties($sClass)) {
|
if (self::HasSharing() && SharedObject::GetSharedClassProperties($sClass)) {
|
||||||
@@ -886,8 +826,8 @@ class UserRightsProfile extends UserRightsAddOnAPI
|
|||||||
// Note: this code is VERY close to the code of IsActionAllowed()
|
// Note: this code is VERY close to the code of IsActionAllowed()
|
||||||
$iUser = $oUser->GetKey();
|
$iUser = $oUser->GetKey();
|
||||||
|
|
||||||
// Cache user's profiles
|
// Cache user's profiles
|
||||||
if(false === array_key_exists($iUser, $this->aUsersProfilesList)){
|
if (false === array_key_exists($iUser, $this->aUsersProfilesList)) {
|
||||||
$this->aUsersProfilesList[$iUser] = UserRights::ListProfiles($oUser);
|
$this->aUsersProfilesList[$iUser] = UserRights::ListProfiles($oUser);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -895,20 +835,14 @@ class UserRightsProfile extends UserRightsAddOnAPI
|
|||||||
// and acceptable to consider only the root class of the object set
|
// and acceptable to consider only the root class of the object set
|
||||||
$bStatus = null;
|
$bStatus = null;
|
||||||
// Call the API of UserRights because it caches the list for us
|
// Call the API of UserRights because it caches the list for us
|
||||||
foreach($this->aUsersProfilesList[$iUser] as $iProfile => $oProfile)
|
foreach ($this->aUsersProfilesList[$iUser] as $iProfile => $oProfile) {
|
||||||
{
|
|
||||||
$bGrant = $this->GetClassStimulusGrant($iProfile, $sClass, $sStimulusCode);
|
$bGrant = $this->GetClassStimulusGrant($iProfile, $sClass, $sStimulusCode);
|
||||||
if (!is_null($bGrant))
|
if (!is_null($bGrant)) {
|
||||||
{
|
if ($bGrant) {
|
||||||
if ($bGrant)
|
if (is_null($bStatus)) {
|
||||||
{
|
|
||||||
if (is_null($bStatus))
|
|
||||||
{
|
|
||||||
$bStatus = true;
|
$bStatus = true;
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
$bStatus = false;
|
$bStatus = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -932,22 +866,16 @@ class UserRightsProfile extends UserRightsAddOnAPI
|
|||||||
{
|
{
|
||||||
$sAttCode = null;
|
$sAttCode = null;
|
||||||
|
|
||||||
$aCallSpec = array($sClass, 'MapContextParam');
|
$aCallSpec = [$sClass, 'MapContextParam'];
|
||||||
if (($sClass == 'Organization') || is_subclass_of($sClass, 'Organization'))
|
if (($sClass == 'Organization') || is_subclass_of($sClass, 'Organization')) {
|
||||||
{
|
|
||||||
$sAttCode = 'id';
|
$sAttCode = 'id';
|
||||||
}
|
} elseif (is_callable($aCallSpec)) {
|
||||||
elseif (is_callable($aCallSpec))
|
|
||||||
{
|
|
||||||
$sAttCode = call_user_func($aCallSpec, 'org_id'); // Returns null when there is no mapping for this parameter
|
$sAttCode = call_user_func($aCallSpec, 'org_id'); // Returns null when there is no mapping for this parameter
|
||||||
if (!MetaModel::IsValidAttCode($sClass, $sAttCode))
|
if (!MetaModel::IsValidAttCode($sClass, $sAttCode)) {
|
||||||
{
|
|
||||||
// Skip silently. The data model checker will tell you something about this...
|
// Skip silently. The data model checker will tell you something about this...
|
||||||
$sAttCode = null;
|
$sAttCode = null;
|
||||||
}
|
}
|
||||||
}
|
} elseif (MetaModel::IsValidAttCode($sClass, 'org_id')) {
|
||||||
elseif(MetaModel::IsValidAttCode($sClass, 'org_id'))
|
|
||||||
{
|
|
||||||
$sAttCode = 'org_id';
|
$sAttCode = 'org_id';
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -960,14 +888,11 @@ class UserRightsProfile extends UserRightsAddOnAPI
|
|||||||
protected static function HasSharing()
|
protected static function HasSharing()
|
||||||
{
|
{
|
||||||
static $bHasSharing;
|
static $bHasSharing;
|
||||||
if (!isset($bHasSharing))
|
if (!isset($bHasSharing)) {
|
||||||
{
|
|
||||||
$bHasSharing = class_exists('SharedObject');
|
$bHasSharing = class_exists('SharedObject');
|
||||||
}
|
}
|
||||||
return $bHasSharing;
|
return $bHasSharing;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
UserRights::SelectModule('UserRightsProfile');
|
UserRights::SelectModule('UserRightsProfile');
|
||||||
|
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,4 +1,5 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* @copyright Copyright (C) 2010-2024 Combodo SAS
|
* @copyright Copyright (C) 2010-2024 Combodo SAS
|
||||||
* @license http://opensource.org/licenses/AGPL-3.0
|
* @license http://opensource.org/licenses/AGPL-3.0
|
||||||
@@ -48,8 +49,7 @@ class DBSearchHelper
|
|||||||
$oHKFilter->AddCondition_PointingTo($oFilter, $sHierarchicalKeyCode, TREE_OPERATOR_BELOW);
|
$oHKFilter->AddCondition_PointingTo($oFilter, $sHierarchicalKeyCode, TREE_OPERATOR_BELOW);
|
||||||
$oSearch->AddCondition_PointingTo($oHKFilter, $sAttCode);
|
$oSearch->AddCondition_PointingTo($oHKFilter, $sAttCode);
|
||||||
}
|
}
|
||||||
}
|
} catch (Exception $e) {
|
||||||
catch (Exception $e) {
|
|
||||||
// If filtering fails just ignore it
|
// If filtering fails just ignore it
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -57,4 +57,4 @@ class DBSearchHelper
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,25 +0,0 @@
|
|||||||
<?php
|
|
||||||
/**
|
|
||||||
* @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-2024 Combodo SAS
|
|
||||||
*/
|
|
||||||
|
|
||||||
// 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
|
|
||||||
*
|
|
||||||
* @deprecated 3.0.0 will be removed in 3.1.0 - moved to AjaxPage
|
|
||||||
*/
|
|
||||||
class ajax_page extends AjaxPage
|
|
||||||
{
|
|
||||||
function __construct($s_title)
|
|
||||||
{
|
|
||||||
DeprecatedCallsLog::NotifyDeprecatedPhpMethod('ajax_page is deprecated. Please use AjaxPage instead');
|
|
||||||
parent::__construct($s_title);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* @copyright Copyright (C) 2010-2024 Combodo SAS
|
* @copyright Copyright (C) 2010-2024 Combodo SAS
|
||||||
* @license http://opensource.org/licenses/AGPL-3.0
|
* @license http://opensource.org/licenses/AGPL-3.0
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
// Copyright (C) 2010-2024 Combodo SAS
|
// Copyright (C) 2010-2024 Combodo SAS
|
||||||
//
|
//
|
||||||
// This file is part of iTop.
|
// 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
|
// 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
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
// (at your option) any later version.
|
// (at your option) any later version.
|
||||||
@@ -16,7 +17,6 @@
|
|||||||
// You should have received a copy of the GNU Affero General Public License
|
// You should have received a copy of the GNU Affero General Public License
|
||||||
// along with iTop. If not, see <http://www.gnu.org/licenses/>
|
// along with iTop. If not, see <http://www.gnu.org/licenses/>
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class ApplicationContext
|
* Class ApplicationContext
|
||||||
*
|
*
|
||||||
@@ -47,16 +47,16 @@ interface iDBObjectURLMaker
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Direct end-users to the standard iTop application: UI.php
|
* Direct end-users to the standard iTop application: UI.php
|
||||||
*/
|
*/
|
||||||
class iTopStandardURLMaker implements iDBObjectURLMaker
|
class iTopStandardURLMaker implements iDBObjectURLMaker
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* @param string $sClass
|
* @param string $sClass
|
||||||
* @param string $iId
|
* @param string $iId
|
||||||
*
|
*
|
||||||
* @return string
|
* @return string
|
||||||
* @throws \Exception
|
* @throws \Exception
|
||||||
*/
|
*/
|
||||||
public static function MakeObjectURL($sClass, $iId)
|
public static function MakeObjectURL($sClass, $iId)
|
||||||
{
|
{
|
||||||
$sPage = DBObject::ComputeStandardUIPage($sClass);
|
$sPage = DBObject::ComputeStandardUIPage($sClass);
|
||||||
@@ -68,16 +68,16 @@ class iTopStandardURLMaker implements iDBObjectURLMaker
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Direct end-users to the standard Portal application
|
* Direct end-users to the standard Portal application
|
||||||
*/
|
*/
|
||||||
class PortalURLMaker implements iDBObjectURLMaker
|
class PortalURLMaker implements iDBObjectURLMaker
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* @param string $sClass
|
* @param string $sClass
|
||||||
* @param string $iId
|
* @param string $iId
|
||||||
*
|
*
|
||||||
* @return string
|
* @return string
|
||||||
* @throws \Exception
|
* @throws \Exception
|
||||||
*/
|
*/
|
||||||
public static function MakeObjectURL($sClass, $iId)
|
public static function MakeObjectURL($sClass, $iId)
|
||||||
{
|
{
|
||||||
$sAbsoluteUrl = utils::GetAbsoluteUrlAppRoot();
|
$sAbsoluteUrl = utils::GetAbsoluteUrlAppRoot();
|
||||||
@@ -86,7 +86,6 @@ class PortalURLMaker implements iDBObjectURLMaker
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Helper class to store and manipulate the parameters that make the application's context
|
* Helper class to store and manipulate the parameters that make the application's context
|
||||||
*
|
*
|
||||||
@@ -99,99 +98,90 @@ class PortalURLMaker implements iDBObjectURLMaker
|
|||||||
*/
|
*/
|
||||||
class ApplicationContext
|
class ApplicationContext
|
||||||
{
|
{
|
||||||
public static $m_sUrlMakerClass = null;
|
public static $m_sUrlMakerClass = null;
|
||||||
protected static $m_aPluginProperties = null;
|
protected static $m_aPluginProperties = null;
|
||||||
protected static $aDefaultValues; // Cache shared among all instances
|
protected static $aDefaultValues; // Cache shared among all instances
|
||||||
|
|
||||||
protected $aNames;
|
protected $aNames;
|
||||||
protected $aValues;
|
protected $aValues;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ApplicationContext constructor.
|
* ApplicationContext constructor.
|
||||||
*
|
*
|
||||||
* @param bool $bReadContext
|
* @param bool $bReadContext
|
||||||
*
|
*
|
||||||
* @throws \Exception
|
* @throws \Exception
|
||||||
*/
|
*/
|
||||||
public function __construct($bReadContext = true)
|
public function __construct($bReadContext = true)
|
||||||
{
|
{
|
||||||
$this->aNames = array(
|
$this->aNames = [
|
||||||
'org_id', 'menu'
|
'org_id', 'menu',
|
||||||
);
|
];
|
||||||
if ($bReadContext)
|
if ($bReadContext) {
|
||||||
{
|
$this->ReadContext();
|
||||||
$this->ReadContext();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Read the context directly in the PHP parameters (either POST or GET)
|
* Read the context directly in the PHP parameters (either POST or GET)
|
||||||
* return nothing
|
* return nothing
|
||||||
*
|
*
|
||||||
* @throws \Exception
|
* @throws \Exception
|
||||||
*/
|
*/
|
||||||
protected function ReadContext()
|
protected function ReadContext()
|
||||||
{
|
{
|
||||||
if (!isset(self::$aDefaultValues))
|
if (!isset(self::$aDefaultValues)) {
|
||||||
{
|
self::$aDefaultValues = [];
|
||||||
self::$aDefaultValues = array();
|
$aContext = utils::ReadParam('c', [], false, 'context_param');
|
||||||
$aContext = utils::ReadParam('c', array(), false, 'context_param');
|
foreach ($this->aNames as $sName) {
|
||||||
foreach($this->aNames as $sName)
|
|
||||||
{
|
|
||||||
$sValue = isset($aContext[$sName]) ? $aContext[$sName] : '';
|
$sValue = isset($aContext[$sName]) ? $aContext[$sName] : '';
|
||||||
// TO DO: check if some of the context parameters are mandatory (or have default values)
|
// TO DO: check if some of the context parameters are mandatory (or have default values)
|
||||||
if (!empty($sValue))
|
if (!empty($sValue)) {
|
||||||
{
|
|
||||||
self::$aDefaultValues[$sName] = $sValue;
|
self::$aDefaultValues[$sName] = $sValue;
|
||||||
}
|
}
|
||||||
// Hmm, there must be a better (more generic) way to handle the case below:
|
// Hmm, there must be a better (more generic) way to handle the case below:
|
||||||
// When there is only one possible (allowed) organization, the context must be
|
// When there is only one possible (allowed) organization, the context must be
|
||||||
// fixed to this org unless there is only one organization in the system then
|
// fixed to this org unless there is only one organization in the system then
|
||||||
// no filter is applied
|
// no filter is applied
|
||||||
if ($sName == 'org_id')
|
if ($sName == 'org_id') {
|
||||||
{
|
if (MetaModel::IsValidClass('Organization')) {
|
||||||
if (MetaModel::IsValidClass('Organization'))
|
|
||||||
{
|
|
||||||
$oSearchFilter = new DBObjectSearch('Organization');
|
$oSearchFilter = new DBObjectSearch('Organization');
|
||||||
$oSet = new CMDBObjectSet($oSearchFilter);
|
$oSet = new CMDBObjectSet($oSearchFilter);
|
||||||
$iCount = $oSet->CountWithLimit(2);
|
$iCount = $oSet->CountWithLimit(2);
|
||||||
if ($iCount > 1)
|
if ($iCount > 1) {
|
||||||
{
|
|
||||||
$oSearchFilter->SetModifierProperty('UserRightsGetSelectFilter', 'bSearchMode', true);
|
$oSearchFilter->SetModifierProperty('UserRightsGetSelectFilter', 'bSearchMode', true);
|
||||||
$oSet = new CMDBObjectSet($oSearchFilter);
|
$oSet = new CMDBObjectSet($oSearchFilter);
|
||||||
$iCount = $oSet->CountWithLimit(2);
|
$iCount = $oSet->CountWithLimit(2);
|
||||||
if ($iCount == 1)
|
if ($iCount == 1) {
|
||||||
{
|
|
||||||
// Only one possible value for org_id, set it in the context
|
// Only one possible value for org_id, set it in the context
|
||||||
$oOrg = $oSet->Fetch();
|
$oOrg = $oSet->Fetch();
|
||||||
self::$aDefaultValues[$sName] = $oOrg->GetKey();
|
self::$aDefaultValues[$sName] = $oOrg->GetKey();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$this->aValues = self::$aDefaultValues;
|
$this->aValues = self::$aDefaultValues;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the current value for the given parameter
|
* Returns the current value for the given parameter
|
||||||
*
|
*
|
||||||
* @param string $sParamName Name of the parameter to read
|
* @param string $sParamName Name of the parameter to read
|
||||||
* @param string $defaultValue
|
* @param string $defaultValue
|
||||||
*
|
*
|
||||||
* @return mixed The value for this parameter
|
* @return mixed The value for this parameter
|
||||||
*/
|
*/
|
||||||
public function GetCurrentValue($sParamName, $defaultValue = '')
|
public function GetCurrentValue($sParamName, $defaultValue = '')
|
||||||
{
|
{
|
||||||
if (isset($this->aValues[$sParamName]))
|
if (isset($this->aValues[$sParamName])) {
|
||||||
{
|
|
||||||
return $this->aValues[$sParamName];
|
return $this->aValues[$sParamName];
|
||||||
}
|
}
|
||||||
return $defaultValue;
|
return $defaultValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the context as string with the format name1=value1&name2=value2....
|
* Returns the context as string with the format name1=value1&name2=value2....
|
||||||
* @return string The context as a string to be appended to an href property
|
* @return string The context as a string to be appended to an href property
|
||||||
@@ -200,21 +190,20 @@ class ApplicationContext
|
|||||||
public function GetForLink(bool $bWithLeadingAmpersand = false)
|
public function GetForLink(bool $bWithLeadingAmpersand = false)
|
||||||
{
|
{
|
||||||
// If there are no parameters, return an empty string
|
// If there are no parameters, return an empty string
|
||||||
if(empty($this->aValues)){
|
if (empty($this->aValues)) {
|
||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
|
|
||||||
// Build the query string with ampersand separated parameters
|
// Build the query string with ampersand separated parameters
|
||||||
$aParams = array();
|
$aParams = [];
|
||||||
foreach($this->aValues as $sName => $sValue)
|
foreach ($this->aValues as $sName => $sValue) {
|
||||||
{
|
|
||||||
$aParams[] = "c[$sName]".'='.urlencode($sValue);
|
$aParams[] = "c[$sName]".'='.urlencode($sValue);
|
||||||
}
|
}
|
||||||
$sReturnValue = implode('&', $aParams);
|
$sReturnValue = implode('&', $aParams);
|
||||||
|
|
||||||
// add the leading ampersand if requested
|
// add the leading ampersand if requested
|
||||||
if($bWithLeadingAmpersand){
|
if ($bWithLeadingAmpersand) {
|
||||||
$sReturnValue = '&' . $sReturnValue;
|
$sReturnValue = '&'.$sReturnValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
return $sReturnValue;
|
return $sReturnValue;
|
||||||
@@ -278,14 +267,13 @@ class ApplicationContext
|
|||||||
*/
|
*/
|
||||||
public function GetAsHash()
|
public function GetAsHash()
|
||||||
{
|
{
|
||||||
$aReturn = array();
|
$aReturn = [];
|
||||||
foreach($this->aValues as $sName => $sValue)
|
foreach ($this->aValues as $sName => $sValue) {
|
||||||
{
|
|
||||||
$aReturn["c[$sName]"] = $sValue;
|
$aReturn["c[$sName]"] = $sValue;
|
||||||
}
|
}
|
||||||
return $aReturn;
|
return $aReturn;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns an array of the context parameters NAMEs
|
* Returns an array of the context parameters NAMEs
|
||||||
* @return array The list of context parameters
|
* @return array The list of context parameters
|
||||||
@@ -298,11 +286,10 @@ class ApplicationContext
|
|||||||
* Removes the specified parameter from the context, for example when the same parameter
|
* Removes the specified parameter from the context, for example when the same parameter
|
||||||
* is already a search parameter
|
* is already a search parameter
|
||||||
* @param string $sParamName Name of the parameter to remove
|
* @param string $sParamName Name of the parameter to remove
|
||||||
*/
|
*/
|
||||||
public function Reset($sParamName)
|
public function Reset($sParamName)
|
||||||
{
|
{
|
||||||
if (isset($this->aValues[$sParamName]))
|
if (isset($this->aValues[$sParamName])) {
|
||||||
{
|
|
||||||
unset($this->aValues[$sParamName]);
|
unset($this->aValues[$sParamName]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -318,27 +305,22 @@ class ApplicationContext
|
|||||||
public function InitObjectFromContext(DBObject &$oObj)
|
public function InitObjectFromContext(DBObject &$oObj)
|
||||||
{
|
{
|
||||||
$sClass = get_class($oObj);
|
$sClass = get_class($oObj);
|
||||||
foreach($this->GetNames() as $key)
|
foreach ($this->GetNames() as $key) {
|
||||||
{
|
$aCallSpec = [$sClass, 'MapContextParam'];
|
||||||
$aCallSpec = array($sClass, 'MapContextParam');
|
if (is_callable($aCallSpec)) {
|
||||||
if (is_callable($aCallSpec))
|
$sAttCode = call_user_func($aCallSpec, $key); // Returns null when there is no mapping for this parameter
|
||||||
{
|
|
||||||
$sAttCode = call_user_func($aCallSpec, $key); // Returns null when there is no mapping for this parameter
|
|
||||||
|
|
||||||
if (MetaModel::IsValidAttCode($sClass, $sAttCode))
|
if (MetaModel::IsValidAttCode($sClass, $sAttCode)) {
|
||||||
{
|
|
||||||
$oAttDef = MetaModel::GetAttributeDef($sClass, $sAttCode);
|
$oAttDef = MetaModel::GetAttributeDef($sClass, $sAttCode);
|
||||||
if ($oAttDef->IsWritable())
|
if ($oAttDef->IsWritable()) {
|
||||||
{
|
|
||||||
$value = $this->GetCurrentValue($key, null);
|
$value = $this->GetCurrentValue($key, null);
|
||||||
if (!is_null($value))
|
if (!is_null($value)) {
|
||||||
{
|
|
||||||
$oObj->Set($sAttCode, $value);
|
$oObj->Set($sAttCode, $value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -362,14 +344,10 @@ class ApplicationContext
|
|||||||
*/
|
*/
|
||||||
public static function GetUrlMakerClass()
|
public static function GetUrlMakerClass()
|
||||||
{
|
{
|
||||||
if (is_null(self::$m_sUrlMakerClass))
|
if (is_null(self::$m_sUrlMakerClass)) {
|
||||||
{
|
if (Session::IsSet('UrlMakerClass')) {
|
||||||
if (Session::IsSet('UrlMakerClass'))
|
|
||||||
{
|
|
||||||
self::$m_sUrlMakerClass = Session::Get('UrlMakerClass');
|
self::$m_sUrlMakerClass = Session::Get('UrlMakerClass');
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
self::$m_sUrlMakerClass = 'iTopStandardURLMaker';
|
self::$m_sUrlMakerClass = 'iTopStandardURLMaker';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -387,23 +365,23 @@ class ApplicationContext
|
|||||||
* @return string the name of the class
|
* @return string the name of the class
|
||||||
* @throws \Exception
|
* @throws \Exception
|
||||||
*/
|
*/
|
||||||
public static function MakeObjectUrl($sObjClass, $sObjKey, $sUrlMakerClass = null, $bWithNavigationContext = true)
|
public static function MakeObjectUrl($sObjClass, $sObjKey, $sUrlMakerClass = null, $bWithNavigationContext = true)
|
||||||
{
|
{
|
||||||
$oAppContext = new ApplicationContext();
|
$oAppContext = new ApplicationContext();
|
||||||
|
|
||||||
if (is_null($sUrlMakerClass)) {
|
if (is_null($sUrlMakerClass)) {
|
||||||
$sUrlMakerClass = self::GetUrlMakerClass();
|
$sUrlMakerClass = self::GetUrlMakerClass();
|
||||||
}
|
}
|
||||||
$sUrl = call_user_func(array($sUrlMakerClass, 'MakeObjectUrl'), $sObjClass, $sObjKey);
|
$sUrl = call_user_func([$sUrlMakerClass, 'MakeObjectUrl'], $sObjClass, $sObjKey);
|
||||||
if (utils::StrLen($sUrl) > 0) {
|
if (utils::StrLen($sUrl) > 0) {
|
||||||
if ($bWithNavigationContext) {
|
if ($bWithNavigationContext) {
|
||||||
return $sUrl.$oAppContext->GetForLink(true);
|
return $sUrl.$oAppContext->GetForLink(true);
|
||||||
} else {
|
} else {
|
||||||
return $sUrl;
|
return $sUrl;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -412,13 +390,10 @@ class ApplicationContext
|
|||||||
*/
|
*/
|
||||||
protected static function LoadPluginProperties()
|
protected static function LoadPluginProperties()
|
||||||
{
|
{
|
||||||
if (Session::IsSet('PluginProperties'))
|
if (Session::IsSet('PluginProperties')) {
|
||||||
{
|
|
||||||
self::$m_aPluginProperties = Session::Get('PluginProperties');
|
self::$m_aPluginProperties = Session::Get('PluginProperties');
|
||||||
}
|
} else {
|
||||||
else
|
self::$m_aPluginProperties = [];
|
||||||
{
|
|
||||||
self::$m_aPluginProperties = array();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -431,7 +406,9 @@ class ApplicationContext
|
|||||||
*/
|
*/
|
||||||
public static function SetPluginProperty($sPluginClass, $sProperty, $value)
|
public static function SetPluginProperty($sPluginClass, $sProperty, $value)
|
||||||
{
|
{
|
||||||
if (is_null(self::$m_aPluginProperties)) self::LoadPluginProperties();
|
if (is_null(self::$m_aPluginProperties)) {
|
||||||
|
self::LoadPluginProperties();
|
||||||
|
}
|
||||||
|
|
||||||
self::$m_aPluginProperties[$sPluginClass][$sProperty] = $value;
|
self::$m_aPluginProperties[$sPluginClass][$sProperty] = $value;
|
||||||
Session::Set(['PluginProperties', $sPluginClass, $sProperty], $value);
|
Session::Set(['PluginProperties', $sPluginClass, $sProperty], $value);
|
||||||
@@ -444,15 +421,14 @@ class ApplicationContext
|
|||||||
*/
|
*/
|
||||||
public static function GetPluginProperties($sPluginClass)
|
public static function GetPluginProperties($sPluginClass)
|
||||||
{
|
{
|
||||||
if (is_null(self::$m_aPluginProperties)) self::LoadPluginProperties();
|
if (is_null(self::$m_aPluginProperties)) {
|
||||||
|
self::LoadPluginProperties();
|
||||||
if (array_key_exists($sPluginClass, self::$m_aPluginProperties))
|
|
||||||
{
|
|
||||||
return self::$m_aPluginProperties[$sPluginClass];
|
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
if (array_key_exists($sPluginClass, self::$m_aPluginProperties)) {
|
||||||
return array();
|
return self::$m_aPluginProperties[$sPluginClass];
|
||||||
|
} else {
|
||||||
|
return [];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,72 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extend this class instead of implementing iApplicationUIExtension if you don't need to overload
|
||||||
|
*
|
||||||
|
* @api
|
||||||
|
* @package UIExtensibilityAPI
|
||||||
|
* @since 2.7.0
|
||||||
|
*/
|
||||||
|
abstract class AbstractApplicationUIExtension implements iApplicationUIExtension
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
public function OnDisplayProperties($oObject, \Combodo\iTop\Application\WebPage\WebPage $oPage, $bEditMode = false)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
public function OnDisplayRelations($oObject, \Combodo\iTop\Application\WebPage\WebPage $oPage, $bEditMode = false)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
public function OnFormSubmit($oObject, $sFormPrefix = '')
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
public function OnFormCancel($sTempId)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
public function EnumUsedAttributes($oObject)
|
||||||
|
{
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
public function GetIcon($oObject)
|
||||||
|
{
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
public function GetHilightClass($oObject)
|
||||||
|
{
|
||||||
|
return HILIGHT_CLASS_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
public function EnumAllowedActions(DBObjectSet $oSet)
|
||||||
|
{
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extend this class instead of iPageUIBlockExtension if you don't need to overload all methods
|
||||||
|
*
|
||||||
|
* @api
|
||||||
|
* @package UIBlockExtensibilityAPI
|
||||||
|
* @since 3.0.0
|
||||||
|
*/
|
||||||
|
abstract class AbstractPageUIBlockExtension implements iPageUIBlockExtension
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
public function GetBannerBlock()
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
public function GetHeaderBlock()
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
public function GetFooterBlock()
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extend this class instead of implementing iPreferencesExtension if you don't need to overload all methods
|
||||||
|
*
|
||||||
|
* @api
|
||||||
|
* @package PreferencesExtensibilityAPI
|
||||||
|
* @since 2.7.0
|
||||||
|
*/
|
||||||
|
abstract class AbstractPreferencesExtension implements iPreferencesExtension
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
public function DisplayPreferences(\Combodo\iTop\Application\WebPage\WebPage $oPage)
|
||||||
|
{
|
||||||
|
// Do nothing
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
public function ApplyPreferences(\Combodo\iTop\Application\WebPage\WebPage $oPage, $sOperation)
|
||||||
|
{
|
||||||
|
// Do nothing
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Inherit from this class to provide messages to be displayed in the "Welcome Popup"
|
||||||
|
*
|
||||||
|
* @api
|
||||||
|
* @since 3.2.0
|
||||||
|
*/
|
||||||
|
abstract class AbstractWelcomePopupExtension implements iWelcomePopupExtension
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
public function GetIconRelPath(): string
|
||||||
|
{
|
||||||
|
return \Combodo\iTop\Application\Branding::$aLogoPaths[\Combodo\iTop\Application\Branding::ENUM_LOGO_TYPE_MAIN_LOGO_COMPACT]['default'];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
public function GetMessages(): array
|
||||||
|
{
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
public function AcknowledgeMessage(string $sMessageId): void
|
||||||
|
{
|
||||||
|
// No need to process the acknowledgment notice by default
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,149 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Base class for the various types of custom menus
|
||||||
|
*
|
||||||
|
* @api
|
||||||
|
* @package UIExtensibilityAPI
|
||||||
|
* @since 2.0
|
||||||
|
*/
|
||||||
|
abstract class ApplicationPopupMenuItem
|
||||||
|
{
|
||||||
|
/** @ignore */
|
||||||
|
protected $sUID;
|
||||||
|
/** @ignore */
|
||||||
|
protected $sLabel;
|
||||||
|
/** @ignore */
|
||||||
|
protected $sTooltip;
|
||||||
|
/** @ignore */
|
||||||
|
protected $sIconClass;
|
||||||
|
/** @ignore */
|
||||||
|
protected $aCssClasses;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor
|
||||||
|
*
|
||||||
|
* @param string $sUID The unique identifier of this menu in iTop... make sure you pass something unique enough
|
||||||
|
* @param string $sLabel The display label of the menu (must be localized)
|
||||||
|
* @api
|
||||||
|
*/
|
||||||
|
public function __construct($sUID, $sLabel)
|
||||||
|
{
|
||||||
|
$this->sUID = $sUID;
|
||||||
|
$this->sLabel = $sLabel;
|
||||||
|
$this->sTooltip = '';
|
||||||
|
$this->sIconClass = '';
|
||||||
|
$this->aCssClasses = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the UID
|
||||||
|
*
|
||||||
|
* @return string The unique identifier
|
||||||
|
* @ignore
|
||||||
|
*/
|
||||||
|
public function GetUID()
|
||||||
|
{
|
||||||
|
return $this->sUID;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the label
|
||||||
|
*
|
||||||
|
* @return string The label
|
||||||
|
* @ignore
|
||||||
|
*/
|
||||||
|
public function GetLabel()
|
||||||
|
{
|
||||||
|
return $this->sLabel;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the CSS classes
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
* @ignore
|
||||||
|
*/
|
||||||
|
public function GetCssClasses()
|
||||||
|
{
|
||||||
|
return $this->aCssClasses;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param $aCssClasses
|
||||||
|
* @api
|
||||||
|
*/
|
||||||
|
public function SetCssClasses($aCssClasses)
|
||||||
|
{
|
||||||
|
$this->aCssClasses = $aCssClasses;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a CSS class to the CSS classes that will be put on the menu item
|
||||||
|
*
|
||||||
|
* @param $sCssClass
|
||||||
|
* @api
|
||||||
|
*/
|
||||||
|
public function AddCssClass($sCssClass)
|
||||||
|
{
|
||||||
|
$this->aCssClasses[] = $sCssClass;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param $sTooltip
|
||||||
|
*
|
||||||
|
* @api
|
||||||
|
* @since 3.0.0
|
||||||
|
*/
|
||||||
|
public function SetTooltip($sTooltip)
|
||||||
|
{
|
||||||
|
$this->sTooltip = $sTooltip;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return string
|
||||||
|
*
|
||||||
|
* @api
|
||||||
|
* @since 3.0.0
|
||||||
|
*/
|
||||||
|
public function GetTooltip()
|
||||||
|
{
|
||||||
|
return $this->sTooltip;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param $sIconClass
|
||||||
|
*
|
||||||
|
* @api
|
||||||
|
* @since 3.0.0
|
||||||
|
*/
|
||||||
|
public function SetIconClass($sIconClass)
|
||||||
|
{
|
||||||
|
$this->sIconClass = $sIconClass;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return string
|
||||||
|
*
|
||||||
|
* @api
|
||||||
|
* @since 3.0.0
|
||||||
|
*/
|
||||||
|
public function GetIconClass()
|
||||||
|
{
|
||||||
|
return $this->sIconClass;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the components to create a popup menu item in HTML
|
||||||
|
*
|
||||||
|
* @return array A hash array: array('label' => , 'url' => , 'target' => , 'onclick' => )
|
||||||
|
* @ignore
|
||||||
|
*/
|
||||||
|
abstract public function GetMenuItem();
|
||||||
|
|
||||||
|
/** @ignore */
|
||||||
|
public function GetLinkedScripts()
|
||||||
|
{
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
}
|
||||||
12
application/applicationextension/backoffice/JSButtonItem.php
Normal file
12
application/applicationextension/backoffice/JSButtonItem.php
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class for adding an item as a button that runs some JS code
|
||||||
|
*
|
||||||
|
* @api
|
||||||
|
* @package UIExtensibilityAPI
|
||||||
|
* @since 2.0
|
||||||
|
*/
|
||||||
|
class JSButtonItem extends JSPopupMenuItem
|
||||||
|
{
|
||||||
|
}
|
||||||
@@ -0,0 +1,70 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class for adding an item into a popup menu that triggers some Javascript code
|
||||||
|
*
|
||||||
|
* Note: This works only in the backoffice, {@see \JSButtonItem} for the end-user portal
|
||||||
|
*
|
||||||
|
* @api
|
||||||
|
* @package UIExtensibilityAPI
|
||||||
|
* @since 2.0
|
||||||
|
*/
|
||||||
|
class JSPopupMenuItem extends ApplicationPopupMenuItem
|
||||||
|
{
|
||||||
|
/** @ignore */
|
||||||
|
protected $sJsCode;
|
||||||
|
/** @ignore */
|
||||||
|
protected $sUrl;
|
||||||
|
/** @ignore */
|
||||||
|
protected $aIncludeJSFiles;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class for adding an item that triggers some Javascript code
|
||||||
|
*
|
||||||
|
* @param string $sUID The unique identifier of this menu in iTop... make sure you pass something unique enough
|
||||||
|
* @param string $sLabel The display label of the menu (must be localized)
|
||||||
|
* @param string $sJSCode In case the menu consists in executing some havascript code inside the page, pass it here. If supplied $sURL
|
||||||
|
* ans $sTarget will be ignored
|
||||||
|
* @param array $aIncludeJSFiles An array of file URLs to be included (once) to provide some JS libraries for the page.
|
||||||
|
* @api
|
||||||
|
*/
|
||||||
|
public function __construct($sUID, $sLabel, $sJSCode, $aIncludeJSFiles = [])
|
||||||
|
{
|
||||||
|
parent::__construct($sUID, $sLabel);
|
||||||
|
$this->sJsCode = $sJSCode;
|
||||||
|
$this->sUrl = '#';
|
||||||
|
$this->aIncludeJSFiles = $aIncludeJSFiles;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @ignore */
|
||||||
|
public function GetMenuItem()
|
||||||
|
{
|
||||||
|
// Note: the semicolumn is a must here!
|
||||||
|
return [
|
||||||
|
'label' => $this->GetLabel(),
|
||||||
|
'onclick' => $this->GetJsCode().'; return false;',
|
||||||
|
'url' => $this->GetUrl(),
|
||||||
|
'css_classes' => $this->GetCssClasses(),
|
||||||
|
'icon_class' => $this->sIconClass,
|
||||||
|
'tooltip' => $this->sTooltip,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @ignore */
|
||||||
|
public function GetLinkedScripts()
|
||||||
|
{
|
||||||
|
return $this->aIncludeJSFiles;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @ignore */
|
||||||
|
public function GetJsCode()
|
||||||
|
{
|
||||||
|
return $this->sJsCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @ignore */
|
||||||
|
public function GetUrl()
|
||||||
|
{
|
||||||
|
return $this->sUrl;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class for adding a separator (horizontal line, not selectable) the output
|
||||||
|
* will automatically reduce several consecutive separators to just one
|
||||||
|
*
|
||||||
|
* @api
|
||||||
|
* @package UIExtensibilityAPI
|
||||||
|
* @since 2.0
|
||||||
|
*/
|
||||||
|
class SeparatorPopupMenuItem extends ApplicationPopupMenuItem
|
||||||
|
{
|
||||||
|
public static $idx = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor
|
||||||
|
* @api
|
||||||
|
*/
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
parent::__construct('_separator_'.(self::$idx++), '');
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @ignore */
|
||||||
|
public function GetMenuItem()
|
||||||
|
{
|
||||||
|
return ['label' => '<hr class="menu-separator">', 'url' => '', 'css_classes' => $this->aCssClasses];
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class for adding an item as a button that browses to the given URL
|
||||||
|
*
|
||||||
|
* @api
|
||||||
|
* @package UIExtensibilityAPI
|
||||||
|
* @since 2.0
|
||||||
|
*/
|
||||||
|
class URLButtonItem extends URLPopupMenuItem
|
||||||
|
{
|
||||||
|
}
|
||||||
@@ -0,0 +1,58 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class for adding an item into a popup menu that browses to the given URL
|
||||||
|
*
|
||||||
|
* Note: This works only in the backoffice, {@see \URLButtonItem} for the end-user portal
|
||||||
|
*
|
||||||
|
* @api
|
||||||
|
* @package UIExtensibilityAPI
|
||||||
|
* @since 2.0
|
||||||
|
*/
|
||||||
|
class URLPopupMenuItem extends ApplicationPopupMenuItem
|
||||||
|
{
|
||||||
|
/** @ignore */
|
||||||
|
protected $sUrl;
|
||||||
|
/** @ignore */
|
||||||
|
protected $sTarget;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor
|
||||||
|
*
|
||||||
|
* @param string $sUID The unique identifier of this menu in iTop... make sure you pass something unique enough
|
||||||
|
* @param string $sLabel The display label of the menu (must be localized)
|
||||||
|
* @param string $sUrl If the menu is an hyperlink, provide the absolute hyperlink here
|
||||||
|
* @param string $sTarget In case the menu is an hyperlink and a specific target is needed (_blank for example), pass it here
|
||||||
|
* @api
|
||||||
|
*/
|
||||||
|
public function __construct($sUID, $sLabel, $sUrl, $sTarget = '_top')
|
||||||
|
{
|
||||||
|
parent::__construct($sUID, $sLabel);
|
||||||
|
$this->sUrl = $sUrl;
|
||||||
|
$this->sTarget = $sTarget;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @ignore */
|
||||||
|
public function GetMenuItem()
|
||||||
|
{
|
||||||
|
return ['label' => $this->GetLabel(),
|
||||||
|
'url' => $this->GetUrl(),
|
||||||
|
'target' => $this->GetTarget(),
|
||||||
|
'css_classes' => $this->aCssClasses,
|
||||||
|
'icon_class' => $this->sIconClass,
|
||||||
|
'tooltip' => $this->sTooltip,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @ignore */
|
||||||
|
public function GetUrl()
|
||||||
|
{
|
||||||
|
return $this->sUrl;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @ignore */
|
||||||
|
public function GetTarget()
|
||||||
|
{
|
||||||
|
return $this->sTarget;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,173 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implement this interface to change the behavior of the GUI for some objects.
|
||||||
|
*
|
||||||
|
* All methods are invoked by iTop for a given object. There are basically two usages:
|
||||||
|
*
|
||||||
|
* 1) To tweak the form of an object, you will have to implement a specific behavior within:
|
||||||
|
*
|
||||||
|
* * OnDisplayProperties (bEditMode = true)
|
||||||
|
* * OnFormSubmit
|
||||||
|
* * OnFormCancel
|
||||||
|
*
|
||||||
|
* 2) To tune the display of the object details, you can use:
|
||||||
|
*
|
||||||
|
* * OnDisplayProperties
|
||||||
|
* * OnDisplayRelations
|
||||||
|
* * GetIcon
|
||||||
|
* * GetHilightClass
|
||||||
|
*
|
||||||
|
* Please note that some of the APIs can be called several times for a single page displayed.
|
||||||
|
* Therefore it is not recommended to perform too many operations, such as querying the database.
|
||||||
|
* A recommended pattern is to cache data by the mean of static members.
|
||||||
|
*
|
||||||
|
* @api
|
||||||
|
* @package UIExtensibilityAPI
|
||||||
|
*/
|
||||||
|
interface iApplicationUIExtension
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Invoked when an object is being displayed (wiew or edit)
|
||||||
|
*
|
||||||
|
* The method is called right after the main tab has been displayed.
|
||||||
|
* You can add output to the page, either to change the display, or to add a form input
|
||||||
|
*
|
||||||
|
* Example:
|
||||||
|
* <code>
|
||||||
|
* if ($bEditMode)
|
||||||
|
* {
|
||||||
|
* $oPage->p('Age of the captain: <input type="text" name="captain_age"/>');
|
||||||
|
* }
|
||||||
|
* else
|
||||||
|
* {
|
||||||
|
* $oPage->p('Age of the captain: '.$iCaptainAge);
|
||||||
|
* }
|
||||||
|
* </code>
|
||||||
|
*
|
||||||
|
* @api
|
||||||
|
*
|
||||||
|
*@param \Combodo\iTop\Application\WebPage\WebPage $oPage The output context
|
||||||
|
* @param boolean $bEditMode True if the edition form is being displayed
|
||||||
|
*
|
||||||
|
* @param DBObject $oObject The object being displayed
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function OnDisplayProperties($oObject, \Combodo\iTop\Application\WebPage\WebPage $oPage, $bEditMode = false);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Invoked when an object is being displayed (wiew or edit)
|
||||||
|
*
|
||||||
|
* The method is called rigth after all the tabs have been displayed
|
||||||
|
*
|
||||||
|
* @api
|
||||||
|
*
|
||||||
|
*@param \Combodo\iTop\Application\WebPage\WebPage $oPage The output context
|
||||||
|
* @param boolean $bEditMode True if the edition form is being displayed
|
||||||
|
*
|
||||||
|
* @param DBObject $oObject The object being displayed
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function OnDisplayRelations($oObject, \Combodo\iTop\Application\WebPage\WebPage $oPage, $bEditMode = false);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Invoked when the end-user clicks on Modify from the object edition form
|
||||||
|
*
|
||||||
|
* The method is called after the changes from the standard form have been
|
||||||
|
* taken into account, and before saving the changes into the database.
|
||||||
|
*
|
||||||
|
* @param DBObject $oObject The object being edited
|
||||||
|
* @param string $sFormPrefix Prefix given to the HTML form inputs
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
* @api
|
||||||
|
*/
|
||||||
|
public function OnFormSubmit($oObject, $sFormPrefix = '');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Invoked when the end-user clicks on Cancel from the object edition form
|
||||||
|
*
|
||||||
|
* Implement here any cleanup. This is necessary when you have injected some
|
||||||
|
* javascript into the edition form, and if that code requires to store temporary data
|
||||||
|
* (this is the case when a file must be uploaded).
|
||||||
|
*
|
||||||
|
* @param string $sTempId Unique temporary identifier made of session_id and transaction_id. It identifies the object in a unique way.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
* @api
|
||||||
|
*/
|
||||||
|
public function OnFormCancel($sTempId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Not yet called by the framework!
|
||||||
|
*
|
||||||
|
* Sorry, the verb has been reserved. You must implement it, but it is not called as of now.
|
||||||
|
*
|
||||||
|
* @param DBObject $oObject The object being displayed
|
||||||
|
*
|
||||||
|
* @return string[] desc
|
||||||
|
* @api
|
||||||
|
*/
|
||||||
|
public function EnumUsedAttributes($oObject); // Not yet implemented
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Not yet called by the framework!
|
||||||
|
*
|
||||||
|
* Sorry, the verb has been reserved. You must implement it, but it is not called as of now.
|
||||||
|
*
|
||||||
|
* @param DBObject $oObject The object being displayed
|
||||||
|
*
|
||||||
|
* @return string Path of the icon, relative to the modules directory.
|
||||||
|
* @api
|
||||||
|
*/
|
||||||
|
public function GetIcon($oObject); // Not yet implemented
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Invoked when the object is displayed alone or within a list
|
||||||
|
*
|
||||||
|
* Returns a value influencing the appearance of the object depending on its
|
||||||
|
* state.
|
||||||
|
*
|
||||||
|
* Possible values are:
|
||||||
|
*
|
||||||
|
* * HILIGHT_CLASS_CRITICAL
|
||||||
|
* * HILIGHT_CLASS_WARNING
|
||||||
|
* * HILIGHT_CLASS_OK
|
||||||
|
* * HILIGHT_CLASS_NONE
|
||||||
|
*
|
||||||
|
* @param DBObject $oObject The object being displayed
|
||||||
|
*
|
||||||
|
* @return integer The value representing the mood of the object
|
||||||
|
* @api
|
||||||
|
*/
|
||||||
|
public function GetHilightClass($oObject);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called when building the Actions menu for a single object or a list of objects
|
||||||
|
*
|
||||||
|
* Use this to add items to the Actions menu. You will have to specify a label and an URL.
|
||||||
|
*
|
||||||
|
* Example:
|
||||||
|
* <code>
|
||||||
|
* $oObject = $oSet->fetch();
|
||||||
|
* if ($oObject instanceof Sheep)
|
||||||
|
* {
|
||||||
|
* return array('View in my app' => 'http://myserver/view_sheeps?id='.$oObject->Get('name'));
|
||||||
|
* }
|
||||||
|
* else
|
||||||
|
* {
|
||||||
|
* return array();
|
||||||
|
* }
|
||||||
|
* </code>
|
||||||
|
*
|
||||||
|
* See also iPopupMenuExtension for greater flexibility
|
||||||
|
*
|
||||||
|
* @param DBObjectSet $oSet A set of persistent objects (DBObject)
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
* @api
|
||||||
|
*/
|
||||||
|
public function EnumAllowedActions(DBObjectSet $oSet);
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implement this interface to add Dict entries
|
||||||
|
*
|
||||||
|
* @see \iTopWebPage::$a_dict_entries
|
||||||
|
* @api
|
||||||
|
* @package BackofficeUIExtensibilityAPI
|
||||||
|
* @since 3.0.0
|
||||||
|
*/
|
||||||
|
interface iBackofficeDictEntriesExtension
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @return array
|
||||||
|
* @see \iTopWebPage::a_dict_entries
|
||||||
|
* @api
|
||||||
|
*/
|
||||||
|
public function GetDictEntries(): array;
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implement this interface to add Dict entries prefixes
|
||||||
|
*
|
||||||
|
* @see \iTopWebPage::$a_dict_entries_prefixes
|
||||||
|
* @api
|
||||||
|
* @package BackofficeUIExtensibilityAPI
|
||||||
|
* @since 3.0.0
|
||||||
|
*/
|
||||||
|
interface iBackofficeDictEntriesPrefixesExtension
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @return array
|
||||||
|
* @see \iTopWebPage::a_dict_entries_prefixes
|
||||||
|
* @api
|
||||||
|
*/
|
||||||
|
public function GetDictEntriesPrefixes(): array;
|
||||||
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implement this interface to add inline script (JS) to the backoffice pages' head.
|
||||||
|
* Will be executed first, BEFORE the DOM interpretation.
|
||||||
|
*
|
||||||
|
* @see \iTopWebPage::$a_early_scripts
|
||||||
|
* @api
|
||||||
|
* @package BackofficeUIExtensibilityAPI
|
||||||
|
* @since 3.0.0
|
||||||
|
*/
|
||||||
|
interface iBackofficeEarlyScriptExtension
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @return string
|
||||||
|
* @see \iTopWebPage::$a_early_scripts
|
||||||
|
* @api
|
||||||
|
*/
|
||||||
|
public function GetEarlyScript(): string;
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implement this interface to add inline script (JS) to the backoffice pages that will be executed right when the DOM is ready.
|
||||||
|
*
|
||||||
|
* @see \iTopWebPage::$a_init_scripts
|
||||||
|
* @api
|
||||||
|
* @package BackofficeUIExtensibilityAPI
|
||||||
|
* @since 3.0.0
|
||||||
|
*/
|
||||||
|
interface iBackofficeInitScriptExtension
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @return string
|
||||||
|
* @see \iTopWebPage::$a_init_scripts
|
||||||
|
* @api
|
||||||
|
*/
|
||||||
|
public function GetInitScript(): string;
|
||||||
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implement this interface to add script (JS) files to the backoffice pages
|
||||||
|
*
|
||||||
|
* @see \iTopWebPage::$a_linked_scripts
|
||||||
|
* @api
|
||||||
|
* @package BackofficeUIExtensibilityAPI
|
||||||
|
* @since 3.0.0
|
||||||
|
*/
|
||||||
|
interface iBackofficeLinkedScriptsExtension
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Each script will be included using this property
|
||||||
|
* @return array An array of absolute URLs to the files to include
|
||||||
|
* @see \iTopWebPage::$a_linked_scripts
|
||||||
|
* @api
|
||||||
|
*/
|
||||||
|
public function GetLinkedScriptsAbsUrls(): array;
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implement this interface to add stylesheets (CSS) to the backoffice pages
|
||||||
|
*
|
||||||
|
* @see \iTopWebPage::$a_linked_stylesheets
|
||||||
|
* @api
|
||||||
|
* @package BackofficeUIExtensibilityAPI
|
||||||
|
* @since 3.0.0
|
||||||
|
*/
|
||||||
|
interface iBackofficeLinkedStylesheetsExtension
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @return array An array of absolute URLs to the files to include
|
||||||
|
* @see \iTopWebPage::$a_linked_stylesheets
|
||||||
|
* @api
|
||||||
|
*/
|
||||||
|
public function GetLinkedStylesheetsAbsUrls(): array;
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implement this interface to add inline script (JS) to the backoffice pages that will be executed slightly AFTER the DOM is ready (just after the init. scripts).
|
||||||
|
*
|
||||||
|
* @see \iTopWebPage::$a_ready_scripts
|
||||||
|
* @api
|
||||||
|
* @package BackofficeUIExtensibilityAPI
|
||||||
|
* @since 3.0.0
|
||||||
|
*/
|
||||||
|
interface iBackofficeReadyScriptExtension
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @return string
|
||||||
|
* @see \iTopWebPage::$a_ready_scripts
|
||||||
|
* @api
|
||||||
|
*/
|
||||||
|
public function GetReadyScript(): string;
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implement this interface to add sass file (SCSS) to the backoffice pages.
|
||||||
|
* example: return "css/setup.scss"
|
||||||
|
*
|
||||||
|
* @api
|
||||||
|
* @package BackofficeUIExtensibilityAPI
|
||||||
|
* @since 3.3.0
|
||||||
|
*/
|
||||||
|
interface iBackofficeSassExtension
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @return string
|
||||||
|
* @see \iTopWebPage::$a_styles
|
||||||
|
* @api
|
||||||
|
*/
|
||||||
|
public function GetSass(): string;
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implement this interface to add inline script (JS) to the backoffice pages that will be executed immediately, without waiting for the DOM to be ready.
|
||||||
|
*
|
||||||
|
* @see \iTopWebPage::$a_scripts
|
||||||
|
* @api
|
||||||
|
* @package BackofficeUIExtensibilityAPI
|
||||||
|
* @since 3.0.0
|
||||||
|
*/
|
||||||
|
interface iBackofficeScriptExtension
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @return string
|
||||||
|
* @see \iTopWebPage::$a_scripts
|
||||||
|
* @api
|
||||||
|
*/
|
||||||
|
public function GetScript(): string;
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implement this interface to add inline style (CSS) to the backoffice pages' head.
|
||||||
|
*
|
||||||
|
* @see \iTopWebPage::$a_styles
|
||||||
|
* @api
|
||||||
|
* @package BackofficeUIExtensibilityAPI
|
||||||
|
* @since 3.0.0
|
||||||
|
*/
|
||||||
|
interface iBackofficeStyleExtension
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @return string
|
||||||
|
* @see \iTopWebPage::$a_styles
|
||||||
|
* @api
|
||||||
|
*/
|
||||||
|
public function GetStyle(): string;
|
||||||
|
}
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implement this interface to register a new field renderer mapping to either:
|
||||||
|
* - Add the rendering of a new attribute type
|
||||||
|
* - Overload the default rendering of an attribute type
|
||||||
|
*
|
||||||
|
* @since 3.1.0 N°6041
|
||||||
|
*
|
||||||
|
* @experimental Form / Field / Renderer should be used in more places in next iTop releases, which may introduce major API changes
|
||||||
|
*/
|
||||||
|
interface iFieldRendererMappingsExtension
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @return array {
|
||||||
|
* array: {
|
||||||
|
* field: string,
|
||||||
|
* form_renderer: string,
|
||||||
|
* field_renderer: string
|
||||||
|
* }
|
||||||
|
* } List of field renderer mapping: FQCN field class, FQCN Form Renderer class, FQCN Field Renderer class
|
||||||
|
*
|
||||||
|
* Example:
|
||||||
|
*
|
||||||
|
* ```php
|
||||||
|
* [
|
||||||
|
* ['field' => 'FQCN\FieldA', 'form_renderer' => 'Combodo\iTop\Renderer\Console\ConsoleFormRenderer', 'field_renderer' => 'FQCN\FieldRendererA'],
|
||||||
|
* ['field' => 'FQCN\FieldB', 'form_renderer' => 'Combodo\iTop\Renderer\Console\ConsoleFormRenderer', 'field_renderer' => 'FQCN\FieldRendererB'],
|
||||||
|
* ['field' => 'FQCN\FieldA', 'form_renderer' => 'Combodo\iTop\Renderer\Bootstrap\BsFormRenderer', 'field_renderer' => 'FQCN\FieldRendererA'],
|
||||||
|
* ['field' => 'FQCN\FieldB', 'form_renderer' => 'Combodo\iTop\Renderer\Bootstrap\BsFormRenderer', 'field_renderer' => 'FQCN\FieldRendererB'],
|
||||||
|
* ]
|
||||||
|
* ```
|
||||||
|
*/
|
||||||
|
public static function RegisterSupportedFields(): array;
|
||||||
|
}
|
||||||
@@ -0,0 +1,47 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implement this interface to add content to any iTopWebPage
|
||||||
|
*
|
||||||
|
* There are 3 places where content can be added:
|
||||||
|
*
|
||||||
|
* * The north pane: (normaly empty/hidden) at the top of the page, spanning the whole
|
||||||
|
* width of the page
|
||||||
|
* * The south pane: (normaly empty/hidden) at the bottom of the page, spanning the whole
|
||||||
|
* width of the page
|
||||||
|
* * The admin banner (two tones gray background) at the left of the global search.
|
||||||
|
* Limited space, use it for short messages
|
||||||
|
*
|
||||||
|
* Each of the methods of this interface is supposed to return the HTML to be inserted at
|
||||||
|
* the specified place and can use the passed iTopWebPage object to add javascript or CSS definitions
|
||||||
|
*
|
||||||
|
* @api
|
||||||
|
* @package BackofficeUIExtensibilityAPI
|
||||||
|
* @since 3.0.0
|
||||||
|
*/
|
||||||
|
interface iPageUIBlockExtension
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Add content to the "admin banner"
|
||||||
|
*
|
||||||
|
* @api
|
||||||
|
* @return \Combodo\iTop\Application\UI\Base\iUIBlock|null The Block to add into the page
|
||||||
|
*/
|
||||||
|
public function GetBannerBlock();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add content to the header of the page
|
||||||
|
*
|
||||||
|
* @api
|
||||||
|
* @return \Combodo\iTop\Application\UI\Base\iUIBlock|null The Block to add into the page
|
||||||
|
*/
|
||||||
|
public function GetHeaderBlock();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add content to the footer of the page
|
||||||
|
*
|
||||||
|
* @api
|
||||||
|
* @return \Combodo\iTop\Application\UI\Base\iUIBlock|null The Block to add into the page
|
||||||
|
*/
|
||||||
|
public function GetFooterBlock();
|
||||||
|
}
|
||||||
@@ -0,0 +1,112 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* New extension to add menu items in the "popup" menus inside iTop. Provides a greater flexibility than
|
||||||
|
* iApplicationUIExtension::EnumAllowedActions.
|
||||||
|
*
|
||||||
|
* To add some menus into iTop, declare a class that implements this interface, it will be called automatically
|
||||||
|
* by the application, as long as the class definition is included somewhere in the code
|
||||||
|
*
|
||||||
|
* @api
|
||||||
|
* @package UIExtensibilityAPI
|
||||||
|
* @since 2.0
|
||||||
|
*/
|
||||||
|
interface iPopupMenuExtension
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Insert an item into the Actions menu of a list
|
||||||
|
*
|
||||||
|
* $param is a DBObjectSet containing the list of objects
|
||||||
|
* @api
|
||||||
|
*/
|
||||||
|
public const MENU_OBJLIST_ACTIONS = 1;
|
||||||
|
/**
|
||||||
|
* Insert an item into the Toolkit menu of a list
|
||||||
|
*
|
||||||
|
* $param is a DBObjectSet containing the list of objects
|
||||||
|
* @api
|
||||||
|
*/
|
||||||
|
public const MENU_OBJLIST_TOOLKIT = 2;
|
||||||
|
/**
|
||||||
|
* Insert an item into the Actions menu on an object details page
|
||||||
|
*
|
||||||
|
* $param is a DBObject instance: the object currently displayed
|
||||||
|
* @api
|
||||||
|
*/
|
||||||
|
public const MENU_OBJDETAILS_ACTIONS = 3;
|
||||||
|
/**
|
||||||
|
* Insert an item into the Dashboard menu
|
||||||
|
*
|
||||||
|
* The dashboad menu is shown on the top right corner when a dashboard
|
||||||
|
* is being displayed.
|
||||||
|
*
|
||||||
|
* $param is a Dashboard instance: the dashboard currently displayed
|
||||||
|
* @api
|
||||||
|
*/
|
||||||
|
public const MENU_DASHBOARD_ACTIONS = 4;
|
||||||
|
/**
|
||||||
|
* Insert an item into the User menu (upper right corner)
|
||||||
|
*
|
||||||
|
* $param is null
|
||||||
|
* @api
|
||||||
|
*/
|
||||||
|
public const MENU_USER_ACTIONS = 5;
|
||||||
|
/**
|
||||||
|
* Insert an item into the Action menu on an object item in an objects list in the portal
|
||||||
|
*
|
||||||
|
* $param is an array('portal_id' => $sPortalId, 'object' => $oObject) containing the portal id and a DBObject instance (the object on
|
||||||
|
* the current line)
|
||||||
|
* @api
|
||||||
|
*/
|
||||||
|
public const PORTAL_OBJLISTITEM_ACTIONS = 7;
|
||||||
|
/**
|
||||||
|
* Insert an item into the Action menu on an object details page in the portal
|
||||||
|
*
|
||||||
|
* $param is an array('portal_id' => $sPortalId, 'object' => $oObject) containing the portal id and a DBObject instance (the object
|
||||||
|
* currently displayed)
|
||||||
|
* @api
|
||||||
|
*/
|
||||||
|
public const PORTAL_OBJDETAILS_ACTIONS = 8;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Insert an item into the Actions menu of a list in the portal
|
||||||
|
* Note: This is not implemented yet !
|
||||||
|
*
|
||||||
|
* $param is an array('portal_id' => $sPortalId, 'object_set' => $oSet) containing DBObjectSet containing the list of objects
|
||||||
|
*
|
||||||
|
* @todo
|
||||||
|
*/
|
||||||
|
public const PORTAL_OBJLIST_ACTIONS = 6;
|
||||||
|
/**
|
||||||
|
* Insert an item into the user menu of the portal
|
||||||
|
* Note: This is not implemented yet !
|
||||||
|
*
|
||||||
|
* $param is the portal id
|
||||||
|
*
|
||||||
|
* @todo
|
||||||
|
*/
|
||||||
|
public const PORTAL_USER_ACTIONS = 9;
|
||||||
|
/**
|
||||||
|
* Insert an item into the navigation menu of the portal
|
||||||
|
* Note: This is not implemented yet !
|
||||||
|
*
|
||||||
|
* $param is the portal id
|
||||||
|
*
|
||||||
|
* @todo
|
||||||
|
*/
|
||||||
|
public const PORTAL_MENU_ACTIONS = 10;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the list of items to be added to a menu.
|
||||||
|
*
|
||||||
|
* This method is called by the framework for each menu.
|
||||||
|
* The items will be inserted in the menu in the order of the returned array.
|
||||||
|
*
|
||||||
|
* @param int $iMenuId The identifier of the type of menu, as listed by the constants MENU_xxx
|
||||||
|
* @param mixed $param Depends on $iMenuId, see the constants defined above
|
||||||
|
*
|
||||||
|
* @return object[] An array of ApplicationPopupMenuItem or an empty array if no action is to be added to the menu
|
||||||
|
* @api
|
||||||
|
*/
|
||||||
|
public static function EnumItems($iMenuId, $param);
|
||||||
|
}
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @api
|
||||||
|
* @package PreferencesExtensibilityAPI
|
||||||
|
* @since 2.7.0
|
||||||
|
*/
|
||||||
|
interface iPreferencesExtension
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @api
|
||||||
|
*
|
||||||
|
* @param \Combodo\iTop\Application\WebPage\WebPage $oPage
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public function DisplayPreferences(\Combodo\iTop\Application\WebPage\WebPage $oPage);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @api
|
||||||
|
*
|
||||||
|
* @param string $sOperation
|
||||||
|
*
|
||||||
|
* @param \Combodo\iTop\Application\WebPage\WebPage $oPage
|
||||||
|
*
|
||||||
|
* @return bool true if the operation has been used
|
||||||
|
*/
|
||||||
|
public function ApplyPreferences(\Combodo\iTop\Application\WebPage\WebPage $oPage, $sOperation);
|
||||||
|
}
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Interface to provide messages to be displayed in the "Welcome Popup"
|
||||||
|
*
|
||||||
|
* @api
|
||||||
|
* @since 3.2.0
|
||||||
|
*/
|
||||||
|
interface iWelcomePopupExtension
|
||||||
|
{
|
||||||
|
// Importance for ordering messages
|
||||||
|
// Just two levels since less important messages have nothing to do in the welcome popup
|
||||||
|
public const ENUM_IMPORTANCE_CRITICAL = 0;
|
||||||
|
public const ENUM_IMPORTANCE_HIGH = 1;
|
||||||
|
public const DEFAULT_IMPORTANCE = self::ENUM_IMPORTANCE_HIGH;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Overload this method if you need to display an icon representing the provider (eg. your own company logo, module icon, ...)
|
||||||
|
*
|
||||||
|
* @return string Relative path (from app. root) of the icon representing the provider
|
||||||
|
* @api
|
||||||
|
*/
|
||||||
|
public function GetIconRelPath(): string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return \Combodo\iTop\Application\WelcomePopup\Message[]
|
||||||
|
* @api
|
||||||
|
*/
|
||||||
|
public function GetMessages(): array;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Overload this method if the provider needs to do some additional processing after the message ($sMessageId) has been acknowledged by the current user
|
||||||
|
*
|
||||||
|
* @param string $sMessageId
|
||||||
|
* @api
|
||||||
|
*/
|
||||||
|
public function AcknowledgeMessage(string $sMessageId): void;
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implement this interface to add files to the backup
|
||||||
|
*
|
||||||
|
* @api
|
||||||
|
* @since 3.2.0
|
||||||
|
*/
|
||||||
|
interface iBackupExtraFilesExtension
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @return string[] Array of relative paths (from app root) for files and directories to be included in the backup
|
||||||
|
* @api
|
||||||
|
*/
|
||||||
|
public function GetExtraFilesRelPaths(): array;
|
||||||
|
}
|
||||||
25
application/applicationextension/iKPILoggerExtension.php
Normal file
25
application/applicationextension/iKPILoggerExtension.php
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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);
|
||||||
|
}
|
||||||
16
application/applicationextension/iModuleExtension.php
Normal file
16
application/applicationextension/iModuleExtension.php
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helpers for modules extensibility, with discover performed by the MetaModel.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @api
|
||||||
|
* @package Extensibility
|
||||||
|
*/
|
||||||
|
interface iModuleExtension
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @api
|
||||||
|
*/
|
||||||
|
public function __construct();
|
||||||
|
}
|
||||||
@@ -0,0 +1,159 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Login finite state machine
|
||||||
|
*
|
||||||
|
* Execute the action corresponding to the current login state.
|
||||||
|
*
|
||||||
|
* * If a page is displayed, the action must exit at this point
|
||||||
|
* * if LoginWebPage::LOGIN_FSM_RETURN_ERROR is returned $iErrorCode must be set
|
||||||
|
* * if LoginWebPage::LOGIN_FSM_RETURN_OK is returned then the login is OK and terminated
|
||||||
|
* * if LoginWebPage::LOGIN_FSM_CONTINUE is returned then the FSM will proceed to next plugin or to next state
|
||||||
|
*
|
||||||
|
* @api
|
||||||
|
* @package LoginExtensibilityAPI
|
||||||
|
* @since 2.7.0
|
||||||
|
*/
|
||||||
|
abstract class AbstractLoginFSMExtension implements iLoginFSMExtension
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
abstract public function ListSupportedLoginModes();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
public function LoginAction($sLoginState, &$iErrorCode)
|
||||||
|
{
|
||||||
|
switch ($sLoginState) {
|
||||||
|
case LoginWebPage::LOGIN_STATE_START:
|
||||||
|
return $this->OnStart($iErrorCode);
|
||||||
|
|
||||||
|
case LoginWebPage::LOGIN_STATE_MODE_DETECTION:
|
||||||
|
return $this->OnModeDetection($iErrorCode);
|
||||||
|
|
||||||
|
case LoginWebPage::LOGIN_STATE_READ_CREDENTIALS:
|
||||||
|
return $this->OnReadCredentials($iErrorCode);
|
||||||
|
|
||||||
|
case LoginWebPage::LOGIN_STATE_CHECK_CREDENTIALS:
|
||||||
|
return $this->OnCheckCredentials($iErrorCode);
|
||||||
|
|
||||||
|
case LoginWebPage::LOGIN_STATE_CREDENTIALS_OK:
|
||||||
|
return $this->OnCredentialsOK($iErrorCode);
|
||||||
|
|
||||||
|
case LoginWebPage::LOGIN_STATE_USER_OK:
|
||||||
|
return $this->OnUsersOK($iErrorCode);
|
||||||
|
|
||||||
|
case LoginWebPage::LOGIN_STATE_CONNECTED:
|
||||||
|
return $this->OnConnected($iErrorCode);
|
||||||
|
|
||||||
|
case LoginWebPage::LOGIN_STATE_ERROR:
|
||||||
|
return $this->OnError($iErrorCode);
|
||||||
|
}
|
||||||
|
|
||||||
|
return LoginWebPage::LOGIN_FSM_CONTINUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialization
|
||||||
|
*
|
||||||
|
* @param int $iErrorCode (see LoginWebPage::EXIT_CODE_...)
|
||||||
|
*
|
||||||
|
* @return int LoginWebPage::LOGIN_FSM_RETURN_ERROR, LoginWebPage::LOGIN_FSM_RETURN_OK or LoginWebPage::LOGIN_FSM_CONTINUE
|
||||||
|
* @api
|
||||||
|
*/
|
||||||
|
protected function OnStart(&$iErrorCode)
|
||||||
|
{
|
||||||
|
return LoginWebPage::LOGIN_FSM_CONTINUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Detect login mode explicitly without respecting configured order (legacy mode)
|
||||||
|
* In most case do nothing here
|
||||||
|
*
|
||||||
|
* @param int $iErrorCode (see LoginWebPage::EXIT_CODE_...)
|
||||||
|
*
|
||||||
|
* @return int LoginWebPage::LOGIN_FSM_RETURN_ERROR, LoginWebPage::LOGIN_FSM_RETURN_OK or LoginWebPage::LOGIN_FSM_CONTINUE
|
||||||
|
* @api
|
||||||
|
*/
|
||||||
|
protected function OnModeDetection(&$iErrorCode)
|
||||||
|
{
|
||||||
|
return LoginWebPage::LOGIN_FSM_CONTINUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Obtain the credentials either if login mode is empty or set to yours.
|
||||||
|
* This step can be called multiple times by the FSM:
|
||||||
|
* for example:
|
||||||
|
* 1 - display login form
|
||||||
|
* 2 - read the values posted by the user (store that in session)
|
||||||
|
*
|
||||||
|
* @param int $iErrorCode (see LoginWebPage::EXIT_CODE_...)
|
||||||
|
*
|
||||||
|
* @return int LoginWebPage::LOGIN_FSM_RETURN_ERROR, LoginWebPage::LOGIN_FSM_RETURN_OK or LoginWebPage::LOGIN_FSM_CONTINUE
|
||||||
|
* @api
|
||||||
|
*/
|
||||||
|
protected function OnReadCredentials(&$iErrorCode)
|
||||||
|
{
|
||||||
|
return LoginWebPage::LOGIN_FSM_CONTINUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Control the validity of the data from the session
|
||||||
|
* Automatic user provisioning can be done here
|
||||||
|
*
|
||||||
|
* @param int $iErrorCode (see LoginWebPage::EXIT_CODE_...)
|
||||||
|
*
|
||||||
|
* @return int LoginWebPage::LOGIN_FSM_RETURN_ERROR, LoginWebPage::LOGIN_FSM_RETURN_OK or LoginWebPage::LOGIN_FSM_CONTINUE
|
||||||
|
* @api
|
||||||
|
*/
|
||||||
|
protected function OnCheckCredentials(&$iErrorCode)
|
||||||
|
{
|
||||||
|
return LoginWebPage::LOGIN_FSM_CONTINUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param int $iErrorCode (see LoginWebPage::EXIT_CODE_...)
|
||||||
|
*
|
||||||
|
* @return int LoginWebPage::LOGIN_FSM_RETURN_ERROR, LoginWebPage::LOGIN_FSM_RETURN_OK or LoginWebPage::LOGIN_FSM_CONTINUE
|
||||||
|
* @api
|
||||||
|
*/
|
||||||
|
protected function OnCredentialsOK(&$iErrorCode)
|
||||||
|
{
|
||||||
|
return LoginWebPage::LOGIN_FSM_CONTINUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param int $iErrorCode (see LoginWebPage::EXIT_CODE_...)
|
||||||
|
*
|
||||||
|
* @return int LoginWebPage::LOGIN_FSM_RETURN_ERROR, LoginWebPage::LOGIN_FSM_RETURN_OK or LoginWebPage::LOGIN_FSM_CONTINUE
|
||||||
|
* @api
|
||||||
|
*/
|
||||||
|
protected function OnUsersOK(&$iErrorCode)
|
||||||
|
{
|
||||||
|
return LoginWebPage::LOGIN_FSM_CONTINUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param int $iErrorCode (see LoginWebPage::EXIT_CODE_...)
|
||||||
|
*
|
||||||
|
* @return int LoginWebPage::LOGIN_FSM_RETURN_ERROR, LoginWebPage::LOGIN_FSM_RETURN_OK or LoginWebPage::LOGIN_FSM_CONTINUE
|
||||||
|
* @api
|
||||||
|
*/
|
||||||
|
protected function OnConnected(&$iErrorCode)
|
||||||
|
{
|
||||||
|
return LoginWebPage::LOGIN_FSM_CONTINUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param int $iErrorCode (see LoginWebPage::EXIT_CODE_...)
|
||||||
|
*
|
||||||
|
* @return int LoginWebPage::LOGIN_FSM_RETURN_ERROR, LoginWebPage::LOGIN_FSM_RETURN_OK or LoginWebPage::LOGIN_FSM_CONTINUE
|
||||||
|
* @api
|
||||||
|
*/
|
||||||
|
protected function OnError(&$iErrorCode)
|
||||||
|
{
|
||||||
|
return LoginWebPage::LOGIN_FSM_CONTINUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
17
application/applicationextension/login/iLoginExtension.php
Normal file
17
application/applicationextension/login/iLoginExtension.php
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @api
|
||||||
|
* @package LoginExtensibilityAPI
|
||||||
|
* @since 2.7.0
|
||||||
|
*/
|
||||||
|
interface iLoginExtension
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Return the list of supported login modes for this plugin
|
||||||
|
*
|
||||||
|
* @return array of supported login modes
|
||||||
|
* @api
|
||||||
|
*/
|
||||||
|
public function ListSupportedLoginModes();
|
||||||
|
}
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @api
|
||||||
|
* @package LoginExtensibilityAPI
|
||||||
|
* @since 2.7.0
|
||||||
|
*/
|
||||||
|
interface iLoginFSMExtension extends iLoginExtension
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Execute action for this login state
|
||||||
|
* If a page is displayed, the action must exit at this point
|
||||||
|
* if LoginWebPage::LOGIN_FSM_RETURN_ERROR is returned $iErrorCode must be set
|
||||||
|
* if LoginWebPage::LOGIN_FSM_RETURN_OK is returned then the login is OK and terminated
|
||||||
|
* if LoginWebPage::LOGIN_FSM_CONTINUE is returned then the FSM will proceed to next plugin or state
|
||||||
|
*
|
||||||
|
* @param string $sLoginState (see LoginWebPage::LOGIN_STATE_...)
|
||||||
|
* @param int $iErrorCode (see LoginWebPage::EXIT_CODE_...)
|
||||||
|
*
|
||||||
|
* @return int LoginWebPage::LOGIN_FSM_RETURN_ERROR, LoginWebPage::LOGIN_FSM_RETURN_OK or LoginWebPage::LOGIN_FSM_CONTINUE
|
||||||
|
* @api
|
||||||
|
*/
|
||||||
|
public function LoginAction($sLoginState, &$iErrorCode);
|
||||||
|
}
|
||||||
17
application/applicationextension/login/iLoginUIExtension.php
Normal file
17
application/applicationextension/login/iLoginUIExtension.php
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Login page extensibility
|
||||||
|
*
|
||||||
|
* @api
|
||||||
|
* @package UIExtensibilityAPI
|
||||||
|
* @since 2.7.0
|
||||||
|
*/
|
||||||
|
interface iLoginUIExtension extends iLoginExtension
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @return LoginTwigContext
|
||||||
|
* @api
|
||||||
|
*/
|
||||||
|
public function GetTwigContext();
|
||||||
|
}
|
||||||
15
application/applicationextension/login/iLogoutExtension.php
Normal file
15
application/applicationextension/login/iLogoutExtension.php
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @api
|
||||||
|
* @package LoginExtensibilityAPI
|
||||||
|
* @since 2.7.0
|
||||||
|
*/
|
||||||
|
interface iLogoutExtension extends iLoginExtension
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Execute all actions to log out properly
|
||||||
|
* @api
|
||||||
|
*/
|
||||||
|
public function LogoutAction();
|
||||||
|
}
|
||||||
@@ -0,0 +1,67 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extend this class instead of iPortalUIExtension if you don't need to overload all methods
|
||||||
|
*
|
||||||
|
* @api
|
||||||
|
* @package PortalExtensibilityAPI
|
||||||
|
* @since 2.4.0
|
||||||
|
*/
|
||||||
|
abstract class AbstractPortalUIExtension implements iPortalUIExtension
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
public function GetCSSFiles(\Symfony\Component\DependencyInjection\Container $oContainer)
|
||||||
|
{
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
public function GetCSSInline(\Symfony\Component\DependencyInjection\Container $oContainer)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
public function GetJSFiles(\Symfony\Component\DependencyInjection\Container $oContainer)
|
||||||
|
{
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
public function GetJSInline(\Symfony\Component\DependencyInjection\Container $oContainer)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
public function GetBodyHTML(\Symfony\Component\DependencyInjection\Container $oContainer)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
public function GetMainContentHTML(\Symfony\Component\DependencyInjection\Container $oContainer)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
public function GetNavigationMenuHTML(\Symfony\Component\DependencyInjection\Container $oContainer)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,87 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implement this interface to add content to any enhanced portal page
|
||||||
|
*
|
||||||
|
* @api
|
||||||
|
* @package PortalExtensibilityAPI
|
||||||
|
*
|
||||||
|
* @since 2.4.0 interface creation
|
||||||
|
* @since 2.7.0 change method signatures due to Silex to Symfony migration
|
||||||
|
*/
|
||||||
|
interface iPortalUIExtension
|
||||||
|
{
|
||||||
|
public const ENUM_PORTAL_EXT_UI_BODY = 'Body';
|
||||||
|
public const ENUM_PORTAL_EXT_UI_NAVIGATION_MENU = 'NavigationMenu';
|
||||||
|
public const ENUM_PORTAL_EXT_UI_MAIN_CONTENT = 'MainContent';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an array of CSS file urls
|
||||||
|
*
|
||||||
|
* @param \Symfony\Component\DependencyInjection\Container $oContainer
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
* @api
|
||||||
|
*/
|
||||||
|
public function GetCSSFiles(\Symfony\Component\DependencyInjection\Container $oContainer);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns inline (raw) CSS
|
||||||
|
*
|
||||||
|
* @param \Symfony\Component\DependencyInjection\Container $oContainer
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
* @api
|
||||||
|
*/
|
||||||
|
public function GetCSSInline(\Symfony\Component\DependencyInjection\Container $oContainer);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an array of JS file urls
|
||||||
|
*
|
||||||
|
* @param \Symfony\Component\DependencyInjection\Container $oContainer
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
* @api
|
||||||
|
*/
|
||||||
|
public function GetJSFiles(\Symfony\Component\DependencyInjection\Container $oContainer);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns raw JS code
|
||||||
|
*
|
||||||
|
* @param \Symfony\Component\DependencyInjection\Container $oContainer
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
* @api
|
||||||
|
*/
|
||||||
|
public function GetJSInline(\Symfony\Component\DependencyInjection\Container $oContainer);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns raw HTML code to put at the end of the <body> tag
|
||||||
|
*
|
||||||
|
* @param \Symfony\Component\DependencyInjection\Container $oContainer
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
* @api
|
||||||
|
*/
|
||||||
|
public function GetBodyHTML(\Symfony\Component\DependencyInjection\Container $oContainer);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns raw HTML code to put at the end of the #main-wrapper element
|
||||||
|
*
|
||||||
|
* @param \Symfony\Component\DependencyInjection\Container $oContainer
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
* @api
|
||||||
|
*/
|
||||||
|
public function GetMainContentHTML(\Symfony\Component\DependencyInjection\Container $oContainer);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns raw HTML code to put at the end of the #topbar and #sidebar elements
|
||||||
|
*
|
||||||
|
* @param \Symfony\Component\DependencyInjection\Container $oContainer
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
* @api
|
||||||
|
*/
|
||||||
|
public function GetNavigationMenuHTML(\Symfony\Component\DependencyInjection\Container $oContainer);
|
||||||
|
}
|
||||||
102
application/applicationextension/rest/RestResult.php
Normal file
102
application/applicationextension/rest/RestResult.php
Normal file
@@ -0,0 +1,102 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Minimal REST response structure. Derive this structure to add response data and error codes.
|
||||||
|
*
|
||||||
|
* @api
|
||||||
|
* @package RESTAPI
|
||||||
|
* @since 2.0.1
|
||||||
|
*/
|
||||||
|
class RestResult
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Result: no issue has been encountered
|
||||||
|
* @api
|
||||||
|
*/
|
||||||
|
public const OK = 0;
|
||||||
|
/**
|
||||||
|
* Result: missing/wrong credentials or the user does not have enough rights to perform the requested operation
|
||||||
|
* @api
|
||||||
|
*/
|
||||||
|
public const UNAUTHORIZED = 1;
|
||||||
|
/**
|
||||||
|
* Result: the parameter 'version' is missing
|
||||||
|
* @api
|
||||||
|
*/
|
||||||
|
public const MISSING_VERSION = 2;
|
||||||
|
/**
|
||||||
|
* Result: the parameter 'json_data' is missing
|
||||||
|
* @api
|
||||||
|
*/
|
||||||
|
public const MISSING_JSON = 3;
|
||||||
|
/**
|
||||||
|
* Result: the input structure is not a valid JSON string
|
||||||
|
* @api
|
||||||
|
*/
|
||||||
|
public const INVALID_JSON = 4;
|
||||||
|
/**
|
||||||
|
* Result: the parameter 'auth_user' is missing, authentication aborted
|
||||||
|
* @api
|
||||||
|
*/
|
||||||
|
public const MISSING_AUTH_USER = 5;
|
||||||
|
/**
|
||||||
|
* Result: the parameter 'auth_pwd' is missing, authentication aborted
|
||||||
|
* @api
|
||||||
|
*/
|
||||||
|
public const MISSING_AUTH_PWD = 6;
|
||||||
|
/**
|
||||||
|
* Result: no operation is available for the specified version
|
||||||
|
* @api
|
||||||
|
*/
|
||||||
|
public const UNSUPPORTED_VERSION = 10;
|
||||||
|
/**
|
||||||
|
* Result: the requested operation is not valid for the specified version
|
||||||
|
* @api
|
||||||
|
*/
|
||||||
|
public const UNKNOWN_OPERATION = 11;
|
||||||
|
/**
|
||||||
|
* Result: the requested operation cannot be performed because it can cause data (integrity) loss
|
||||||
|
* @api
|
||||||
|
*/
|
||||||
|
public const UNSAFE = 12;
|
||||||
|
/**
|
||||||
|
* Result: the request page number is not valid. It must be an integer greater than 0
|
||||||
|
* @api
|
||||||
|
*/
|
||||||
|
public const INVALID_PAGE = 13;
|
||||||
|
/**
|
||||||
|
* Result: the operation could not be performed, see the message for troubleshooting
|
||||||
|
* @api
|
||||||
|
*/
|
||||||
|
public const INTERNAL_ERROR = 100;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Default constructor - ok!
|
||||||
|
* @api
|
||||||
|
*/
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
$this->code = RestResult::OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Result code
|
||||||
|
* @var int
|
||||||
|
* @api
|
||||||
|
*/
|
||||||
|
public $code;
|
||||||
|
/**
|
||||||
|
* Result message
|
||||||
|
* @var string
|
||||||
|
* @api
|
||||||
|
*/
|
||||||
|
public $message;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sanitize the content of this result to hide sensitive information
|
||||||
|
*/
|
||||||
|
public function SanitizeContent()
|
||||||
|
{
|
||||||
|
// The default implementation does nothing
|
||||||
|
}
|
||||||
|
}
|
||||||
364
application/applicationextension/rest/RestUtils.php
Normal file
364
application/applicationextension/rest/RestUtils.php
Normal file
@@ -0,0 +1,364 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helpers for implementing REST services
|
||||||
|
*
|
||||||
|
* @api
|
||||||
|
* @package RESTAPI
|
||||||
|
*/
|
||||||
|
class RestUtils
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Registering tracking information. Any further object modification be associated with the given comment, when the modification gets
|
||||||
|
* recorded into the DB
|
||||||
|
*
|
||||||
|
* @param StdClass $oData Structured input data. Must contain 'comment'.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
* @throws Exception
|
||||||
|
* @api
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public static function InitTrackingComment($oData)
|
||||||
|
{
|
||||||
|
$sComment = self::GetMandatoryParam($oData, 'comment');
|
||||||
|
CMDBObject::SetTrackInfo($sComment);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Read a mandatory parameter from from a Rest/Json structure.
|
||||||
|
*
|
||||||
|
* @param string $sParamName Name of the parameter to fetch from the input data
|
||||||
|
* @param StdClass $oData Structured input data. Must contain the entry defined by sParamName.
|
||||||
|
*
|
||||||
|
* @return mixed parameter value if present
|
||||||
|
* @throws Exception If the parameter is missing
|
||||||
|
* @api
|
||||||
|
*/
|
||||||
|
public static function GetMandatoryParam($oData, $sParamName)
|
||||||
|
{
|
||||||
|
if (isset($oData->$sParamName)) {
|
||||||
|
return $oData->$sParamName;
|
||||||
|
} else {
|
||||||
|
throw new Exception("Missing parameter '$sParamName'");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Read an optional parameter from a Rest/Json structure.
|
||||||
|
*
|
||||||
|
* @param string $sParamName Name of the parameter to fetch from the input data
|
||||||
|
* @param mixed $default Default value if the parameter is not found in the input data
|
||||||
|
*
|
||||||
|
* @param StdClass $oData Structured input data.
|
||||||
|
*
|
||||||
|
* @return mixed
|
||||||
|
* @throws Exception
|
||||||
|
* @api
|
||||||
|
*/
|
||||||
|
public static function GetOptionalParam($oData, $sParamName, $default)
|
||||||
|
{
|
||||||
|
if (isset($oData->$sParamName)) {
|
||||||
|
return $oData->$sParamName;
|
||||||
|
} else {
|
||||||
|
return $default;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Read a class from a Rest/Json structure.
|
||||||
|
*
|
||||||
|
* @param string $sParamName Name of the parameter to fetch from the input data
|
||||||
|
* @param StdClass $oData Structured input data. Must contain the entry defined by sParamName.
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
* @throws Exception If the parameter is missing or the class is unknown
|
||||||
|
* @api
|
||||||
|
*/
|
||||||
|
public static function GetClass($oData, $sParamName)
|
||||||
|
{
|
||||||
|
$sClass = self::GetMandatoryParam($oData, $sParamName);
|
||||||
|
if (!MetaModel::IsValidClass($sClass)) {
|
||||||
|
throw new Exception("$sParamName: '$sClass' is not a valid class'");
|
||||||
|
}
|
||||||
|
|
||||||
|
return $sClass;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Read a list of attribute codes from a Rest/Json structure.
|
||||||
|
*
|
||||||
|
* @param StdClass $oData Structured input data.
|
||||||
|
* @param string $sParamName Name of the parameter to fetch from the input data
|
||||||
|
*
|
||||||
|
* @param string $sClass Name of the class
|
||||||
|
*
|
||||||
|
* @return array of class => list of attributes (see RestResultWithObjects::AddObject that uses it)
|
||||||
|
* @throws Exception
|
||||||
|
* @api
|
||||||
|
*/
|
||||||
|
public static function GetFieldList($sClass, $oData, $sParamName)
|
||||||
|
{
|
||||||
|
$sFields = self::GetOptionalParam($oData, $sParamName, '*');
|
||||||
|
$aShowFields = [];
|
||||||
|
if ($sFields == '*') {
|
||||||
|
foreach (MetaModel::ListAttributeDefs($sClass) as $sAttCode => $oAttDef) {
|
||||||
|
$aShowFields[$sClass][] = $sAttCode;
|
||||||
|
}
|
||||||
|
} elseif ($sFields == '*+') {
|
||||||
|
foreach (MetaModel::EnumChildClasses($sClass, ENUM_CHILD_CLASSES_ALL) as $sRefClass) {
|
||||||
|
foreach (MetaModel::ListAttributeDefs($sRefClass) as $sAttCode => $oAttDef) {
|
||||||
|
$aShowFields[$sRefClass][] = $sAttCode;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
foreach (explode(',', $sFields) as $sAttCode) {
|
||||||
|
$sAttCode = trim($sAttCode);
|
||||||
|
if (($sAttCode != 'id') && (!MetaModel::IsValidAttCode($sClass, $sAttCode))) {
|
||||||
|
throw new Exception("$sParamName: invalid attribute code '$sAttCode'");
|
||||||
|
}
|
||||||
|
$aShowFields[$sClass][] = $sAttCode;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $aShowFields;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Read and interpret object search criteria from a Rest/Json structure
|
||||||
|
*
|
||||||
|
* @param string $sClass Name of the class
|
||||||
|
* @param StdClass $oCriteria Hash of attribute code => value (can be a substructure or a scalar, depending on the nature of the
|
||||||
|
* attriute)
|
||||||
|
*
|
||||||
|
* @return object The object found
|
||||||
|
* @throws Exception If the input structure is not valid or it could not find exactly one object
|
||||||
|
* @api
|
||||||
|
*/
|
||||||
|
protected static function FindObjectFromCriteria($sClass, $oCriteria)
|
||||||
|
{
|
||||||
|
$aCriteriaReport = [];
|
||||||
|
if (isset($oCriteria->finalclass)) {
|
||||||
|
if (!MetaModel::IsValidClass($oCriteria->finalclass)) {
|
||||||
|
throw new Exception("finalclass: Unknown class '".$oCriteria->finalclass."'");
|
||||||
|
}
|
||||||
|
if (!MetaModel::IsParentClass($sClass, $oCriteria->finalclass)) {
|
||||||
|
throw new Exception("finalclass: '".$oCriteria->finalclass."' is not a child class of '$sClass'");
|
||||||
|
}
|
||||||
|
$sClass = $oCriteria->finalclass;
|
||||||
|
}
|
||||||
|
$oSearch = new DBObjectSearch($sClass);
|
||||||
|
foreach ($oCriteria as $sAttCode => $value) {
|
||||||
|
$realValue = static::MakeValue($sClass, $sAttCode, $value);
|
||||||
|
$oSearch->AddCondition($sAttCode, $realValue, '=');
|
||||||
|
if (is_object($value) || is_array($value)) {
|
||||||
|
$value = json_encode($value);
|
||||||
|
}
|
||||||
|
$aCriteriaReport[] = "$sAttCode: $value ($realValue)";
|
||||||
|
}
|
||||||
|
$oSet = new DBObjectSet($oSearch);
|
||||||
|
$iCount = $oSet->Count();
|
||||||
|
if ($iCount == 0) {
|
||||||
|
throw new Exception("No item found with criteria: ".implode(', ', $aCriteriaReport));
|
||||||
|
} elseif ($iCount > 1) {
|
||||||
|
throw new Exception("Several items found ($iCount) with criteria: ".implode(', ', $aCriteriaReport));
|
||||||
|
}
|
||||||
|
$res = $oSet->Fetch();
|
||||||
|
|
||||||
|
return $res;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Find an object from a polymorph search specification (Rest/Json)
|
||||||
|
*
|
||||||
|
* @param mixed $key Either search criteria (substructure), or an object or an OQL string.
|
||||||
|
* @param bool $bAllowNullValue Allow the cases such as key = 0 or key = {null} and return null then
|
||||||
|
* @param string $sClass Name of the class
|
||||||
|
*
|
||||||
|
* @return DBObject The object found
|
||||||
|
* @throws Exception If the input structure is not valid or it could not find exactly one object
|
||||||
|
*
|
||||||
|
* @api
|
||||||
|
* @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)
|
||||||
|
{
|
||||||
|
if (is_object($key)) {
|
||||||
|
$res = static::FindObjectFromCriteria($sClass, $key);
|
||||||
|
} elseif (is_numeric($key)) {
|
||||||
|
if ($bAllowNullValue && ($key == 0)) {
|
||||||
|
$res = null;
|
||||||
|
} else {
|
||||||
|
$res = MetaModel::GetObject($sClass, $key, false);
|
||||||
|
if (is_null($res)) {
|
||||||
|
throw new Exception("Invalid object $sClass::$key");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} elseif (is_string($key)) {
|
||||||
|
// OQL
|
||||||
|
$oSearch = DBObjectSearch::FromOQL($key);
|
||||||
|
$oSet = new DBObjectSet($oSearch);
|
||||||
|
$iCount = $oSet->Count();
|
||||||
|
if ($iCount == 0) {
|
||||||
|
throw new Exception("No item found for query: $key");
|
||||||
|
} elseif ($iCount > 1) {
|
||||||
|
throw new Exception("Several items found ($iCount) for query: $key");
|
||||||
|
}
|
||||||
|
$res = $oSet->Fetch();
|
||||||
|
} else {
|
||||||
|
throw new Exception("Wrong format for key");
|
||||||
|
}
|
||||||
|
|
||||||
|
return $res;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Search objects from a polymorph search specification (Rest/Json)
|
||||||
|
*
|
||||||
|
* @param string $sClass Name of the class
|
||||||
|
* @param mixed $key Either search criteria (substructure), or an object or an OQL string.
|
||||||
|
* @param int $iLimit The limit of results to return
|
||||||
|
* @param int $iOffset The offset of results to return
|
||||||
|
*
|
||||||
|
* @return DBObjectSet The search result set
|
||||||
|
* @throws Exception If the input structure is not valid
|
||||||
|
* @api
|
||||||
|
*/
|
||||||
|
public static function GetObjectSetFromKey($sClass, $key, $iLimit = 0, $iOffset = 0)
|
||||||
|
{
|
||||||
|
if (is_object($key)) {
|
||||||
|
if (isset($key->finalclass)) {
|
||||||
|
$sClass = $key->finalclass;
|
||||||
|
if (!MetaModel::IsValidClass($sClass)) {
|
||||||
|
throw new Exception("finalclass: Unknown class '$sClass'");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$oSearch = new DBObjectSearch($sClass);
|
||||||
|
foreach ($key as $sAttCode => $value) {
|
||||||
|
$realValue = static::MakeValue($sClass, $sAttCode, $value);
|
||||||
|
$oSearch->AddCondition($sAttCode, $realValue, '=');
|
||||||
|
}
|
||||||
|
} elseif (is_numeric($key)) {
|
||||||
|
$oSearch = new DBObjectSearch($sClass);
|
||||||
|
$oSearch->AddCondition('id', $key);
|
||||||
|
} elseif (is_string($key)) {
|
||||||
|
// OQL
|
||||||
|
try {
|
||||||
|
$oSearch = DBObjectSearch::FromOQL($key);
|
||||||
|
} catch (Exception $e) {
|
||||||
|
throw new CoreOqlException('Query failed to execute', [
|
||||||
|
'query' => $key,
|
||||||
|
'exception_class' => get_class($e),
|
||||||
|
'exception_message' => $e->getMessage(),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
throw new Exception("Wrong format for key");
|
||||||
|
}
|
||||||
|
$oObjectSet = new DBObjectSet($oSearch, [], [], null, $iLimit, $iOffset);
|
||||||
|
|
||||||
|
return $oObjectSet;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Interpret the Rest/Json value and get a valid attribute value
|
||||||
|
*
|
||||||
|
* @param string $sAttCode Attribute code
|
||||||
|
* @param mixed $value Depending on the type of attribute (a scalar, or search criteria, or list of related objects...)
|
||||||
|
* @param string $sClass Name of the class
|
||||||
|
*
|
||||||
|
* @return mixed The value that can be used with DBObject::Set()
|
||||||
|
* @throws Exception If the specification of the value is not valid.
|
||||||
|
* @api
|
||||||
|
*/
|
||||||
|
public static function MakeValue($sClass, $sAttCode, $value)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
if (!MetaModel::IsValidAttCode($sClass, $sAttCode)) {
|
||||||
|
throw new Exception("Unknown attribute");
|
||||||
|
}
|
||||||
|
$oAttDef = MetaModel::GetAttributeDef($sClass, $sAttCode);
|
||||||
|
if ($oAttDef instanceof AttributeExternalKey) {
|
||||||
|
$oExtKeyObject = static::FindObjectFromKey($oAttDef->GetTargetClass(), $value, true /* allow null */);
|
||||||
|
$value = ($oExtKeyObject != null) ? $oExtKeyObject->GetKey() : 0;
|
||||||
|
} elseif ($oAttDef instanceof AttributeLinkedSet) {
|
||||||
|
if (!is_array($value)) {
|
||||||
|
throw new Exception("A link set must be defined by an array of objects");
|
||||||
|
}
|
||||||
|
$sLnkClass = $oAttDef->GetLinkedClass();
|
||||||
|
$aLinks = [];
|
||||||
|
foreach ($value as $oValues) {
|
||||||
|
$oLnk = static::MakeObjectFromFields($sLnkClass, $oValues);
|
||||||
|
// Fix for N°1939
|
||||||
|
if (($oAttDef instanceof AttributeLinkedSetIndirect) && ($oLnk->Get($oAttDef->GetExtKeyToRemote()) == 0)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
$aLinks[] = $oLnk;
|
||||||
|
}
|
||||||
|
$value = DBObjectSet::FromArray($sLnkClass, $aLinks);
|
||||||
|
} elseif ($oAttDef instanceof AttributeTagSet) {
|
||||||
|
if (!is_array($value)) {
|
||||||
|
throw new Exception("A tag set must be defined by an array of tag codes");
|
||||||
|
}
|
||||||
|
$value = $oAttDef->FromJSONToValue($value);
|
||||||
|
} else {
|
||||||
|
$value = $oAttDef->FromJSONToValue($value);
|
||||||
|
}
|
||||||
|
} catch (Exception $e) {
|
||||||
|
throw new Exception("$sAttCode: ".$e->getMessage(), $e->getCode());
|
||||||
|
}
|
||||||
|
|
||||||
|
return $value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Interpret a Rest/Json structure that defines attribute values, and build an object
|
||||||
|
*
|
||||||
|
* @param array $aFields A hash of attribute code => value specification.
|
||||||
|
* @param string $sClass Name of the class
|
||||||
|
*
|
||||||
|
* @return DBObject The newly created object
|
||||||
|
* @throws Exception If the specification of the values is not valid
|
||||||
|
* @api
|
||||||
|
*/
|
||||||
|
public static function MakeObjectFromFields($sClass, $aFields)
|
||||||
|
{
|
||||||
|
$oObject = MetaModel::NewObject($sClass);
|
||||||
|
foreach ($aFields as $sAttCode => $value) {
|
||||||
|
$realValue = static::MakeValue($sClass, $sAttCode, $value);
|
||||||
|
try {
|
||||||
|
$oObject->Set($sAttCode, $realValue);
|
||||||
|
} catch (Exception $e) {
|
||||||
|
throw new Exception("$sAttCode: ".$e->getMessage(), $e->getCode());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $oObject;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Interpret a Rest/Json structure that defines attribute values, and update the given object
|
||||||
|
*
|
||||||
|
* @param array $aFields A hash of attribute code => value specification.
|
||||||
|
* @param DBObject $oObject The object being modified
|
||||||
|
*
|
||||||
|
* @return DBObject The object modified
|
||||||
|
* @throws Exception If the specification of the values is not valid
|
||||||
|
* @api
|
||||||
|
*/
|
||||||
|
public static function UpdateObjectFromFields($oObject, $aFields)
|
||||||
|
{
|
||||||
|
$sClass = get_class($oObject);
|
||||||
|
foreach ($aFields as $sAttCode => $value) {
|
||||||
|
$realValue = static::MakeValue($sClass, $sAttCode, $value);
|
||||||
|
try {
|
||||||
|
$oObject->Set($sAttCode, $realValue);
|
||||||
|
} catch (Exception $e) {
|
||||||
|
throw new Exception("$sAttCode: ".$e->getMessage(), $e->getCode());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $oObject;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A REST service provider implementing this interface will have its input JSON data sanitized for logging purposes
|
||||||
|
*
|
||||||
|
* @see \iRestServiceProvider
|
||||||
|
* @since 2.7.13, 3.2.1-1
|
||||||
|
*/
|
||||||
|
interface iRestInputSanitizer
|
||||||
|
{
|
||||||
|
public function SanitizeJsonInput(string $sJsonInput): string;
|
||||||
|
}
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implement this interface to add new operations to the REST/JSON web service
|
||||||
|
*
|
||||||
|
* @api
|
||||||
|
* @package RESTExtensibilityAPI
|
||||||
|
* @since 2.0.1
|
||||||
|
*/
|
||||||
|
interface iRestServiceProvider
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Enumerate services delivered by this class
|
||||||
|
*
|
||||||
|
* @param string $sVersion The version (e.g. 1.0) supported by the services
|
||||||
|
*
|
||||||
|
* @return array An array of hash 'verb' => verb, 'description' => description
|
||||||
|
* @api
|
||||||
|
*/
|
||||||
|
public function ListOperations($sVersion);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enumerate services delivered by this class
|
||||||
|
*
|
||||||
|
* @param string $sVersion The version (e.g. 1.0) supported by the services
|
||||||
|
* @param string $sVerb
|
||||||
|
* @param array $aParams
|
||||||
|
*
|
||||||
|
* @return RestResult The standardized result structure (at least a message)
|
||||||
|
* @api
|
||||||
|
*/
|
||||||
|
public function ExecOperation($sVersion, $sVerb, $aParams);
|
||||||
|
}
|
||||||
@@ -1,9 +1,10 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
// Copyright (C) 2010-2024 Combodo SAS
|
// Copyright (C) 2010-2024 Combodo SAS
|
||||||
//
|
//
|
||||||
// This file is part of iTop.
|
// 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
|
// 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
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
// (at your option) any later version.
|
// (at your option) any later version.
|
||||||
@@ -16,7 +17,6 @@
|
|||||||
// You should have received a copy of the GNU Affero General Public License
|
// You should have received a copy of the GNU Affero General Public License
|
||||||
// along with iTop. If not, see <http://www.gnu.org/licenses/>
|
// along with iTop. If not, see <http://www.gnu.org/licenses/>
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class manages the audit "categories". Each category defines a set of objects
|
* This class manages the audit "categories". Each category defines a set of objects
|
||||||
* to check and is linked to a set of rules that determine the valid or invalid objects
|
* to check and is linked to a set of rules that determine the valid or invalid objects
|
||||||
@@ -32,34 +32,36 @@ class AuditCategory extends cmdbAbstractObject
|
|||||||
{
|
{
|
||||||
public static function Init()
|
public static function Init()
|
||||||
{
|
{
|
||||||
$aParams = array
|
$aParams =
|
||||||
(
|
[
|
||||||
"category" => "application,grant_by_profile",
|
"category" => "application,grant_by_profile",
|
||||||
"key_type" => "autoincrement",
|
"key_type" => "autoincrement",
|
||||||
"name_attcode" => "name",
|
"name_attcode" => "name",
|
||||||
"state_attcode" => "",
|
"state_attcode" => "",
|
||||||
"reconc_keys" => array('name'),
|
"reconc_keys" => ['name'],
|
||||||
"db_table" => "priv_auditcategory",
|
"db_table" => "priv_auditcategory",
|
||||||
"db_key_field" => "id",
|
"db_key_field" => "id",
|
||||||
"db_finalclass_field" => "",
|
"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_Params($aParams);
|
||||||
MetaModel::Init_AddAttribute(new AttributeString("name", array("description"=>"Short name for this category", "allowed_values"=>null, "sql"=>"name", "default_value"=>"", "is_null_allowed"=>false, "depends_on"=>array())));
|
MetaModel::Init_AddAttribute(new AttributeString("name", ["description" => "Short name for this category", "allowed_values" => null, "sql" => "name", "default_value" => "", "is_null_allowed" => false, "depends_on" => []]));
|
||||||
MetaModel::Init_AddAttribute(new AttributeString("description", array("allowed_values"=>null, "sql"=>"description", "default_value"=>"", "is_null_allowed"=>true, "depends_on"=>array())));
|
MetaModel::Init_AddAttribute(new AttributeString("description", ["allowed_values" => null, "sql" => "description", "default_value" => "", "is_null_allowed" => true, "depends_on" => []]));
|
||||||
MetaModel::Init_AddAttribute(new AttributeOQL("definition_set", array("allowed_values"=>null, "sql"=>"definition_set", "default_value"=>"", "is_null_allowed"=>false, "depends_on"=>array())));
|
MetaModel::Init_AddAttribute(new AttributeOQL("definition_set", ["allowed_values" => null, "sql" => "definition_set", "default_value" => "", "is_null_allowed" => false, "depends_on" => []]));
|
||||||
MetaModel::Init_AddAttribute(new AttributeLinkedSet("rules_list", array("linked_class"=>"AuditRule", "ext_key_to_me"=>"category_id", "allowed_values"=>null, "count_min"=>0, "count_max"=>0, "depends_on"=>array(), "edit_mode" => LINKSET_EDITMODE_INPLACE, "tracking_level" => LINKSET_TRACKING_ALL)));
|
MetaModel::Init_AddAttribute(new AttributeLinkedSet("rules_list", ["linked_class" => "AuditRule", "ext_key_to_me" => "category_id", "allowed_values" => null, "count_min" => 0, "count_max" => 0, "depends_on" => [], "edit_mode" => LINKSET_EDITMODE_INPLACE, "edit_when" => LINKSET_EDITWHEN_ALWAYS, "tracking_level" => LINKSET_TRACKING_ALL]));
|
||||||
MetaModel::Init_AddAttribute(new AttributeInteger("ok_error_tolerance", array("allowed_values"=>null, "sql"=>"ok_error_tolerance", "default_value"=>5, "is_null_allowed"=>true, "depends_on"=>array())));
|
MetaModel::Init_AddAttribute(new AttributeInteger("ok_error_tolerance", ["allowed_values" => null, "sql" => "ok_error_tolerance", "default_value" => 5, "is_null_allowed" => true, "depends_on" => []]));
|
||||||
MetaModel::Init_AddAttribute(new AttributeInteger("warning_error_tolerance", array("allowed_values" => null, "sql" => "warning_error_tolerance", "default_value" => 25, "is_null_allowed" => true, "depends_on" => array())));
|
MetaModel::Init_AddAttribute(new AttributeInteger("warning_error_tolerance", ["allowed_values" => null, "sql" => "warning_error_tolerance", "default_value" => 25, "is_null_allowed" => true, "depends_on" => []]));
|
||||||
MetaModel::Init_AddAttribute(new AttributeLinkedSetIndirect("domains_list",
|
MetaModel::Init_AddAttribute(new AttributeLinkedSetIndirect(
|
||||||
array("linked_class" => "lnkAuditCategoryToAuditDomain", "ext_key_to_me" => "category_id", "ext_key_to_remote" => "domain_id", "allowed_values" => null, "count_min" => 0, "count_max" => 0, "depends_on" => array(), "display_style" => 'property')));
|
"domains_list",
|
||||||
|
["linked_class" => "lnkAuditCategoryToAuditDomain", "ext_key_to_me" => "category_id", "ext_key_to_remote" => "domain_id", "allowed_values" => null, "count_min" => 0, "count_max" => 0, "depends_on" => [], "display_style" => 'property']
|
||||||
|
));
|
||||||
|
|
||||||
// Display lists
|
// Display lists
|
||||||
MetaModel::Init_SetZListItems('details', array('name', 'description', 'definition_set', 'ok_error_tolerance', 'warning_error_tolerance', 'rules_list', 'domains_list')); // Attributes to be displayed for the complete details
|
MetaModel::Init_SetZListItems('details', ['name', 'description', 'definition_set', 'ok_error_tolerance', 'warning_error_tolerance', 'rules_list', 'domains_list']); // Attributes to be displayed for the complete details
|
||||||
MetaModel::Init_SetZListItems('list', array('description', )); // Attributes to be displayed for a list
|
MetaModel::Init_SetZListItems('list', ['description', ]); // Attributes to be displayed for a list
|
||||||
// Search criteria
|
// Search criteria
|
||||||
MetaModel::Init_SetZListItems('standard_search', array('description', 'definition_set')); // Criteria of the std search form
|
MetaModel::Init_SetZListItems('standard_search', ['description', 'definition_set']); // Criteria of the std search form
|
||||||
MetaModel::Init_SetZListItems('default_search', array('name', 'description')); // Criteria of the default search form
|
MetaModel::Init_SetZListItems('default_search', ['name', 'description']); // Criteria of the default search form
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -74,9 +76,9 @@ class AuditCategory extends cmdbAbstractObject
|
|||||||
public function GetReportColor($iTotal, $iErrors)
|
public function GetReportColor($iTotal, $iErrors)
|
||||||
{
|
{
|
||||||
$sResult = 'red';
|
$sResult = 'red';
|
||||||
if ( ($iTotal == 0) || ($iErrors / $iTotal) <= ($this->Get('ok_error_tolerance') / 100) ) {
|
if (($iTotal == 0) || ($iErrors / $iTotal) <= ($this->Get('ok_error_tolerance') / 100)) {
|
||||||
$sResult = 'green';
|
$sResult = 'green';
|
||||||
} else if (($iErrors / $iTotal) <= ($this->Get('warning_error_tolerance') / 100)) {
|
} elseif (($iErrors / $iTotal) <= ($this->Get('warning_error_tolerance') / 100)) {
|
||||||
$sResult = 'orange';
|
$sResult = 'orange';
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -93,4 +95,3 @@ class AuditCategory extends cmdbAbstractObject
|
|||||||
return $aShortcutActions;
|
return $aShortcutActions;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
?>
|
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
// Copyright (C) 2010-2024 Combodo SAS
|
// Copyright (C) 2010-2024 Combodo SAS
|
||||||
//
|
//
|
||||||
// This file is part of iTop.
|
// This file is part of iTop.
|
||||||
@@ -16,7 +17,6 @@
|
|||||||
// You should have received a copy of the GNU Affero General Public License
|
// You should have received a copy of the GNU Affero General Public License
|
||||||
// along with iTop. If not, see <http://www.gnu.org/licenses/>
|
// along with iTop. If not, see <http://www.gnu.org/licenses/>
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class manages the audit "categories". Each category defines a set of objects
|
* This class manages the audit "categories". Each category defines a set of objects
|
||||||
* to check and is linked to a set of rules that determine the valid or invalid objects
|
* to check and is linked to a set of rules that determine the valid or invalid objects
|
||||||
@@ -33,32 +33,34 @@ class AuditDomain extends cmdbAbstractObject
|
|||||||
{
|
{
|
||||||
public static function Init()
|
public static function Init()
|
||||||
{
|
{
|
||||||
$aParams = array
|
$aParams =
|
||||||
(
|
[
|
||||||
"category" => "application,grant_by_profile",
|
"category" => "application,grant_by_profile",
|
||||||
"key_type" => "autoincrement",
|
"key_type" => "autoincrement",
|
||||||
"name_attcode" => "name",
|
"name_attcode" => "name",
|
||||||
"complementary_name_attcode" => array('description'),
|
"complementary_name_attcode" => ['description'],
|
||||||
"state_attcode" => "",
|
"state_attcode" => "",
|
||||||
"reconc_keys" => array('name'),
|
"reconc_keys" => ['name'],
|
||||||
"db_table" => "priv_auditdomain",
|
"db_table" => "priv_auditdomain",
|
||||||
"db_key_field" => "id",
|
"db_key_field" => "id",
|
||||||
"db_finalclass_field" => "",
|
"db_finalclass_field" => "",
|
||||||
'style' => new ormStyle(null, null, null, null, null, '../images/icons/icons8-audit-album.svg'),
|
'style' => new ormStyle(null, null, null, null, null, '../images/icons/icons8-audit-album.svg'),
|
||||||
);
|
];
|
||||||
MetaModel::Init_Params($aParams);
|
MetaModel::Init_Params($aParams);
|
||||||
MetaModel::Init_AddAttribute(new AttributeString("name", array("description" => "Short name for this category", "allowed_values" => null, "sql" => "name", "default_value" => "", "is_null_allowed" => false, "depends_on" => array())));
|
MetaModel::Init_AddAttribute(new AttributeString("name", ["description" => "Short name for this category", "allowed_values" => null, "sql" => "name", "default_value" => "", "is_null_allowed" => false, "depends_on" => []]));
|
||||||
MetaModel::Init_AddAttribute(new AttributeString("description", array("allowed_values" => null, "sql" => "description", "default_value" => "", "is_null_allowed" => true, "depends_on" => array())));
|
MetaModel::Init_AddAttribute(new AttributeString("description", ["allowed_values" => null, "sql" => "description", "default_value" => "", "is_null_allowed" => true, "depends_on" => []]));
|
||||||
MetaModel::Init_AddAttribute(new AttributeImage("icon", array("is_null_allowed" => true, "depends_on" => array(), "display_max_width" => 96, "display_max_height" => 96, "storage_max_width" => 256, "storage_max_height" => 256, "default_image" => null, "always_load_in_tables" => false)));
|
MetaModel::Init_AddAttribute(new AttributeImage("icon", ["is_null_allowed" => true, "depends_on" => [], "display_max_width" => 96, "display_max_height" => 96, "storage_max_width" => 256, "storage_max_height" => 256, "default_image" => null, "always_load_in_tables" => false]));
|
||||||
MetaModel::Init_AddAttribute(new AttributeLinkedSetIndirect("categories_list",
|
MetaModel::Init_AddAttribute(new AttributeLinkedSetIndirect(
|
||||||
array("linked_class" => "lnkAuditCategoryToAuditDomain", "ext_key_to_me" => "domain_id", "ext_key_to_remote" => "category_id", "allowed_values" => null, "count_min" => 0, "count_max" => 0, "depends_on" => array())));
|
"categories_list",
|
||||||
|
["linked_class" => "lnkAuditCategoryToAuditDomain", "ext_key_to_me" => "domain_id", "ext_key_to_remote" => "category_id", "allowed_values" => null, "count_min" => 0, "count_max" => 0, "depends_on" => []]
|
||||||
|
));
|
||||||
|
|
||||||
// Display lists
|
// Display lists
|
||||||
MetaModel::Init_SetZListItems('details', array('name', 'description', 'icon', 'categories_list')); // Attributes to be displayed for the complete details
|
MetaModel::Init_SetZListItems('details', ['name', 'description', 'icon', 'categories_list']); // Attributes to be displayed for the complete details
|
||||||
MetaModel::Init_SetZListItems('list', array('description',)); // Attributes to be displayed for a list
|
MetaModel::Init_SetZListItems('list', ['description',]); // Attributes to be displayed for a list
|
||||||
// Search criteria
|
// Search criteria
|
||||||
MetaModel::Init_SetZListItems('standard_search', array('description')); // Criteria of the std search form
|
MetaModel::Init_SetZListItems('standard_search', ['description']); // Criteria of the std search form
|
||||||
MetaModel::Init_SetZListItems('default_search', array('name', 'description')); // Criteria of the default search form
|
MetaModel::Init_SetZListItems('default_search', ['name', 'description']); // Criteria of the default search form
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function GetShortcutActions($sFinalClass)
|
public static function GetShortcutActions($sFinalClass)
|
||||||
@@ -84,40 +86,39 @@ class lnkAuditCategoryToAuditDomain extends cmdbAbstractObject
|
|||||||
*/
|
*/
|
||||||
public static function Init()
|
public static function Init()
|
||||||
{
|
{
|
||||||
$aParams = array
|
$aParams =
|
||||||
(
|
[
|
||||||
"category" => "application,grant_by_profile",
|
"category" => "application,grant_by_profile",
|
||||||
"key_type" => "autoincrement",
|
"key_type" => "autoincrement",
|
||||||
"name_attcode" => "",
|
"name_attcode" => "",
|
||||||
"state_attcode" => "",
|
"state_attcode" => "",
|
||||||
"reconc_keys" => array('category_id', 'domain_id'),
|
"reconc_keys" => ['category_id', 'domain_id'],
|
||||||
"db_table" => "priv_link_audit_category_domain",
|
"db_table" => "priv_link_audit_category_domain",
|
||||||
"db_key_field" => "id",
|
"db_key_field" => "id",
|
||||||
"db_finalclass_field" => "",
|
"db_finalclass_field" => "",
|
||||||
"is_link" => true,
|
"is_link" => true,
|
||||||
'uniqueness_rules' => array(
|
'uniqueness_rules' => [
|
||||||
'no_duplicate' => array(
|
'no_duplicate' => [
|
||||||
'attributes' => array(
|
'attributes' => [
|
||||||
0 => 'category_id',
|
0 => 'category_id',
|
||||||
1 => 'domain_id',
|
1 => 'domain_id',
|
||||||
),
|
],
|
||||||
'filter' => '',
|
'filter' => '',
|
||||||
'disabled' => false,
|
'disabled' => false,
|
||||||
'is_blocking' => true,
|
'is_blocking' => true,
|
||||||
),
|
],
|
||||||
),
|
],
|
||||||
);
|
];
|
||||||
MetaModel::Init_Params($aParams);
|
MetaModel::Init_Params($aParams);
|
||||||
MetaModel::Init_AddAttribute(new AttributeExternalKey("category_id", array("targetclass" => "AuditCategory", "jointype" => '', "allowed_values" => null, "sql" => "category_id", "is_null_allowed" => false, "on_target_delete" => DEL_AUTO, "depends_on" => array())));
|
MetaModel::Init_AddAttribute(new AttributeExternalKey("category_id", ["targetclass" => "AuditCategory", "jointype" => '', "allowed_values" => null, "sql" => "category_id", "is_null_allowed" => false, "on_target_delete" => DEL_AUTO, "depends_on" => []]));
|
||||||
MetaModel::Init_AddAttribute(new AttributeExternalField("category_name", array("allowed_values" => null, "extkey_attcode" => 'category_id', "target_attcode" => "name")));
|
MetaModel::Init_AddAttribute(new AttributeExternalField("category_name", ["allowed_values" => null, "extkey_attcode" => 'category_id', "target_attcode" => "name"]));
|
||||||
MetaModel::Init_AddAttribute(new AttributeExternalKey("domain_id", array("targetclass" => "AuditDomain", "jointype" => '', "allowed_values" => null, "sql" => "domain_id", "is_null_allowed" => false, "on_target_delete" => DEL_AUTO, "depends_on" => array())));
|
MetaModel::Init_AddAttribute(new AttributeExternalKey("domain_id", ["targetclass" => "AuditDomain", "jointype" => '', "allowed_values" => null, "sql" => "domain_id", "is_null_allowed" => false, "on_target_delete" => DEL_AUTO, "depends_on" => []]));
|
||||||
MetaModel::Init_AddAttribute(new AttributeExternalField("domain_name", array("allowed_values" => null, "extkey_attcode" => 'domain_id', "target_attcode" => "name")));
|
MetaModel::Init_AddAttribute(new AttributeExternalField("domain_name", ["allowed_values" => null, "extkey_attcode" => 'domain_id', "target_attcode" => "name"]));
|
||||||
|
|
||||||
// Display lists
|
// Display lists
|
||||||
MetaModel::Init_SetZListItems('details', array('category_id', 'domain_id'));
|
MetaModel::Init_SetZListItems('details', ['category_id', 'domain_id']);
|
||||||
MetaModel::Init_SetZListItems('list', array('category_id', 'domain_id'));
|
MetaModel::Init_SetZListItems('list', ['category_id', 'domain_id']);
|
||||||
// Search criteria
|
// Search criteria
|
||||||
MetaModel::Init_SetZListItems('standard_search', array('category_id', 'domain_id'));
|
MetaModel::Init_SetZListItems('standard_search', ['category_id', 'domain_id']);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
// Copyright (C) 2010-2024 Combodo SAS
|
// Copyright (C) 2010-2024 Combodo SAS
|
||||||
//
|
//
|
||||||
// This file is part of iTop.
|
// 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
|
// 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
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
// (at your option) any later version.
|
// (at your option) any later version.
|
||||||
@@ -16,7 +17,6 @@
|
|||||||
// You should have received a copy of the GNU Affero General Public License
|
// You should have received a copy of the GNU Affero General Public License
|
||||||
// along with iTop. If not, see <http://www.gnu.org/licenses/>
|
// along with iTop. If not, see <http://www.gnu.org/licenses/>
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class manages the audit "rule" linked to a given audit category.
|
* This class manages the audit "rule" linked to a given audit category.
|
||||||
* Each rule is based on an OQL expression that returns either the "good" objects
|
* Each rule is based on an OQL expression that returns either the "good" objects
|
||||||
@@ -33,35 +33,35 @@ class AuditRule extends cmdbAbstractObject
|
|||||||
{
|
{
|
||||||
public static function Init()
|
public static function Init()
|
||||||
{
|
{
|
||||||
$aParams = array
|
$aParams =
|
||||||
(
|
[
|
||||||
"category" => "application,grant_by_profile",
|
"category" => "application,grant_by_profile",
|
||||||
"key_type" => "autoincrement",
|
"key_type" => "autoincrement",
|
||||||
"name_attcode" => "name",
|
"name_attcode" => "name",
|
||||||
"state_attcode" => "",
|
"state_attcode" => "",
|
||||||
"reconc_keys" => array('name'),
|
"reconc_keys" => ['name'],
|
||||||
"db_table" => "priv_auditrule",
|
"db_table" => "priv_auditrule",
|
||||||
"db_key_field" => "id",
|
"db_key_field" => "id",
|
||||||
"db_finalclass_field" => "",
|
"db_finalclass_field" => "",
|
||||||
'style' => new ormStyle(null, null, null, null, null, '../images/icons/icons8-audit.svg'),
|
'style' => new ormStyle(null, null, null, null, null, '../images/icons/icons8-audit.svg'),
|
||||||
);
|
];
|
||||||
MetaModel::Init_Params($aParams);
|
MetaModel::Init_Params($aParams);
|
||||||
MetaModel::Init_AddAttribute(new AttributeString("name", array("allowed_values" => null, "sql" => "name", "default_value" => "", "is_null_allowed" => false, "depends_on" => array())));
|
MetaModel::Init_AddAttribute(new AttributeString("name", ["allowed_values" => null, "sql" => "name", "default_value" => "", "is_null_allowed" => false, "depends_on" => []]));
|
||||||
MetaModel::Init_AddAttribute(new AttributeString("description", array("allowed_values" => null, "sql" => "description", "default_value" => "", "is_null_allowed" => true, "depends_on" => array())));
|
MetaModel::Init_AddAttribute(new AttributeString("description", ["allowed_values" => null, "sql" => "description", "default_value" => "", "is_null_allowed" => true, "depends_on" => []]));
|
||||||
MetaModel::Init_AddAttribute(new AttributeOQL("query", array("allowed_values" => null, "sql" => "query", "default_value" => "", "is_null_allowed" => false, "depends_on" => array())));
|
MetaModel::Init_AddAttribute(new AttributeOQL("query", ["allowed_values" => null, "sql" => "query", "default_value" => "", "is_null_allowed" => false, "depends_on" => []]));
|
||||||
MetaModel::Init_AddAttribute(new AttributeEnum("valid_flag", array("allowed_values" => new ValueSetEnum('true,false'), "sql" => "valid_flag", "default_value" => "true", "is_null_allowed" => false, "depends_on" => array())));
|
MetaModel::Init_AddAttribute(new AttributeEnum("valid_flag", ["allowed_values" => new ValueSetEnum('true,false'), "sql" => "valid_flag", "default_value" => "true", "is_null_allowed" => false, "depends_on" => []]));
|
||||||
MetaModel::Init_AddAttribute(new AttributeExternalKey("category_id", array("allowed_values" => null, "sql" => "category_id", "targetclass" => "AuditCategory", "is_null_allowed" => false, "on_target_delete" => DEL_MANUAL, "depends_on" => array())));
|
MetaModel::Init_AddAttribute(new AttributeExternalKey("category_id", ["allowed_values" => null, "sql" => "category_id", "targetclass" => "AuditCategory", "is_null_allowed" => false, "on_target_delete" => DEL_MANUAL, "depends_on" => []]));
|
||||||
MetaModel::Init_AddAttribute(new AttributeExternalField("category_name", array("allowed_values" => null, "extkey_attcode" => 'category_id', "target_attcode" => "name")));
|
MetaModel::Init_AddAttribute(new AttributeExternalField("category_name", ["allowed_values" => null, "extkey_attcode" => 'category_id', "target_attcode" => "name"]));
|
||||||
|
MetaModel::Init_AddAttribute(new AttributeExternalKey("contact_id", ["allowed_values" => null, "sql" => "contact_id", "targetclass" => "Contact", "is_null_allowed" => true, "on_target_delete" => DEL_MANUAL, "depends_on" => []]));
|
||||||
|
MetaModel::Init_AddAttribute(new AttributeHTML("process", ["allowed_values" => null, "sql" => "process", "default_value" => "", "is_null_allowed" => true, "depends_on" => []]));
|
||||||
// Display lists
|
// Display lists
|
||||||
MetaModel::Init_SetZListItems('details', array('category_id', 'name', 'description', 'query', 'valid_flag')); // Attributes to be displayed for the complete details
|
MetaModel::Init_SetZListItems('details', ['category_id', 'name', 'description', 'query', 'valid_flag', 'process', 'contact_id']); // Attributes to be displayed for the complete details
|
||||||
MetaModel::Init_SetZListItems('list', array('category_id', 'description', 'valid_flag')); // Attributes to be displayed for a list
|
MetaModel::Init_SetZListItems('list', ['category_id', 'description', 'query']); // Attributes to be displayed for a list
|
||||||
// Search criteria
|
// Search criteria
|
||||||
MetaModel::Init_SetZListItems('standard_search', array('category_id', 'name', 'description', 'valid_flag', 'query')); // Criteria of the std search form
|
MetaModel::Init_SetZListItems('standard_search', ['category_id', 'name', 'description', 'valid_flag', 'query']); // Criteria of the std search form
|
||||||
MetaModel::Init_SetZListItems('default_search', array('name', 'description', 'category_id')); // Criteria of the advanced search form
|
MetaModel::Init_SetZListItems('default_search', ['name', 'description', 'category_id', 'contact_id', 'query']); // Criteria of the advanced search form
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public static function GetShortcutActions($sFinalClass)
|
public static function GetShortcutActions($sFinalClass)
|
||||||
{
|
{
|
||||||
$aShortcutActions = parent::GetShortcutActions($sFinalClass);
|
$aShortcutActions = parent::GetShortcutActions($sFinalClass);
|
||||||
@@ -72,4 +72,3 @@ class AuditRule extends cmdbAbstractObject
|
|||||||
return $aShortcutActions;
|
return $aShortcutActions;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
?>
|
|
||||||
|
|||||||
@@ -1,8 +0,0 @@
|
|||||||
<?php
|
|
||||||
/**
|
|
||||||
* @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-2024 Combodo SAS
|
|
||||||
*/
|
|
||||||
|
|
||||||
DeprecatedCallsLog::NotifyDeprecatedFile('moved to sources/Application/WebPage/CaptureWebPage.php, now loadable using autoloader');
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
<?php
|
|
||||||
/**
|
|
||||||
* @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-2024 Combodo SAS
|
|
||||||
*/
|
|
||||||
|
|
||||||
DeprecatedCallsLog::NotifyDeprecatedFile('moved to sources/Application/WebPage/CLIPage.php, now loadable using autoloader');
|
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -1,4 +1,5 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Copyright (C) 2013-2024 Combodo SAS
|
* Copyright (C) 2013-2024 Combodo SAS
|
||||||
*
|
*
|
||||||
@@ -32,7 +33,8 @@ class CompileCSSService
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
public function CompileCSSFromSASS($sSassContent, $aImportPaths = [], $aVariables = []){
|
public function CompileCSSFromSASS($sSassContent, $aImportPaths = [], $aVariables = [])
|
||||||
|
{
|
||||||
return utils::CompileCSSFromSASS($sSassContent, $aImportPaths, $aVariables);
|
return utils::CompileCSSFromSASS($sSassContent, $aImportPaths, $aVariables);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +0,0 @@
|
|||||||
<?php
|
|
||||||
/**
|
|
||||||
* @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-2024 Combodo SAS
|
|
||||||
*/
|
|
||||||
|
|
||||||
DeprecatedCallsLog::NotifyDeprecatedFile('moved to sources/Application/WebPage/CSVPage.php, now loadable using autoloader');
|
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* @copyright Copyright (C) 2010-2024 Combodo SAS
|
* @copyright Copyright (C) 2010-2024 Combodo SAS
|
||||||
* @license http://opensource.org/licenses/AGPL-3.0
|
* @license http://opensource.org/licenses/AGPL-3.0
|
||||||
@@ -53,7 +54,7 @@ abstract class Dashboard
|
|||||||
$this->sLayoutClass = 'DashboardLayoutOneCol';
|
$this->sLayoutClass = 'DashboardLayoutOneCol';
|
||||||
$this->bAutoReload = false;
|
$this->bAutoReload = false;
|
||||||
$this->iAutoReloadSec = MetaModel::GetConfig()->GetStandardReloadInterval();
|
$this->iAutoReloadSec = MetaModel::GetConfig()->GetStandardReloadInterval();
|
||||||
$this->aCells = array();
|
$this->aCells = [];
|
||||||
$this->oDOMNode = null;
|
$this->oDOMNode = null;
|
||||||
$this->sId = $sId;
|
$this->sId = $sId;
|
||||||
}
|
}
|
||||||
@@ -65,8 +66,8 @@ abstract class Dashboard
|
|||||||
*/
|
*/
|
||||||
public function FromXml($sXml)
|
public function FromXml($sXml)
|
||||||
{
|
{
|
||||||
$this->aCells = array(); // reset the content of the dashboard
|
$this->aCells = []; // reset the content of the dashboard
|
||||||
set_error_handler(array('Dashboard', 'ErrorHandler'));
|
set_error_handler(['Dashboard', 'ErrorHandler']);
|
||||||
$oDoc = new DOMDocument();
|
$oDoc = new DOMDocument();
|
||||||
$oDoc->loadXML($sXml);
|
$oDoc->loadXML($sXml);
|
||||||
restore_error_handler();
|
restore_error_handler();
|
||||||
@@ -79,87 +80,69 @@ abstract class Dashboard
|
|||||||
public function FromDOMDocument(DOMDocument $oDoc)
|
public function FromDOMDocument(DOMDocument $oDoc)
|
||||||
{
|
{
|
||||||
$this->oDOMNode = $oDoc->getElementsByTagName('dashboard')->item(0);
|
$this->oDOMNode = $oDoc->getElementsByTagName('dashboard')->item(0);
|
||||||
|
|
||||||
if ($oLayoutNode = $this->oDOMNode->getElementsByTagName('layout')->item(0))
|
if ($oLayoutNode = $this->oDOMNode->getElementsByTagName('layout')->item(0)) {
|
||||||
{
|
|
||||||
$this->sLayoutClass = $oLayoutNode->textContent;
|
$this->sLayoutClass = $oLayoutNode->textContent;
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
$this->sLayoutClass = 'DashboardLayoutOneCol';
|
$this->sLayoutClass = 'DashboardLayoutOneCol';
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($oTitleNode = $this->oDOMNode->getElementsByTagName('title')->item(0))
|
if ($oTitleNode = $this->oDOMNode->getElementsByTagName('title')->item(0)) {
|
||||||
{
|
|
||||||
$this->sTitle = $oTitleNode->textContent;
|
$this->sTitle = $oTitleNode->textContent;
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
$this->sTitle = '';
|
$this->sTitle = '';
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->bAutoReload = false;
|
$this->bAutoReload = false;
|
||||||
$this->iAutoReloadSec = MetaModel::GetConfig()->GetStandardReloadInterval();
|
$this->iAutoReloadSec = MetaModel::GetConfig()->GetStandardReloadInterval();
|
||||||
if ($oAutoReloadNode = $this->oDOMNode->getElementsByTagName('auto_reload')->item(0))
|
if ($oAutoReloadNode = $this->oDOMNode->getElementsByTagName('auto_reload')->item(0)) {
|
||||||
{
|
if ($oAutoReloadEnabled = $oAutoReloadNode->getElementsByTagName('enabled')->item(0)) {
|
||||||
if ($oAutoReloadEnabled = $oAutoReloadNode->getElementsByTagName('enabled')->item(0))
|
|
||||||
{
|
|
||||||
$this->bAutoReload = ($oAutoReloadEnabled->textContent == 'true');
|
$this->bAutoReload = ($oAutoReloadEnabled->textContent == 'true');
|
||||||
}
|
}
|
||||||
if ($oAutoReloadInterval = $oAutoReloadNode->getElementsByTagName('interval')->item(0))
|
if ($oAutoReloadInterval = $oAutoReloadNode->getElementsByTagName('interval')->item(0)) {
|
||||||
{
|
|
||||||
$this->iAutoReloadSec = max(MetaModel::GetConfig()->Get('min_reload_interval'), (int)$oAutoReloadInterval->textContent);
|
$this->iAutoReloadSec = max(MetaModel::GetConfig()->Get('min_reload_interval'), (int)$oAutoReloadInterval->textContent);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($oCellsNode = $this->oDOMNode->getElementsByTagName('cells')->item(0))
|
if ($oCellsNode = $this->oDOMNode->getElementsByTagName('cells')->item(0)) {
|
||||||
{
|
|
||||||
$oCellsList = $oCellsNode->getElementsByTagName('cell');
|
$oCellsList = $oCellsNode->getElementsByTagName('cell');
|
||||||
$aCellOrder = array();
|
$aCellOrder = [];
|
||||||
$iCellRank = 0;
|
$iCellRank = 0;
|
||||||
/** @var \DOMElement $oCellNode */
|
/** @var \DOMElement $oCellNode */
|
||||||
foreach($oCellsList as $oCellNode)
|
foreach ($oCellsList as $oCellNode) {
|
||||||
{
|
|
||||||
$oCellRank = $oCellNode->getElementsByTagName('rank')->item(0);
|
$oCellRank = $oCellNode->getElementsByTagName('rank')->item(0);
|
||||||
if ($oCellRank)
|
if ($oCellRank) {
|
||||||
{
|
|
||||||
$iCellRank = (float)$oCellRank->textContent;
|
$iCellRank = (float)$oCellRank->textContent;
|
||||||
}
|
}
|
||||||
$oDashletsNode = $oCellNode->getElementsByTagName('dashlets')->item(0);
|
$oDashletsNode = $oCellNode->getElementsByTagName('dashlets')->item(0);
|
||||||
{
|
{
|
||||||
$oDashletList = $oDashletsNode->getElementsByTagName('dashlet');
|
$oDashletList = $oDashletsNode->getElementsByTagName('dashlet');
|
||||||
$iRank = 0;
|
$iRank = 0;
|
||||||
$aDashletOrder = array();
|
$aDashletOrder = [];
|
||||||
/** @var \DOMElement $oDomNode */
|
/** @var \DOMElement $oDomNode */
|
||||||
foreach($oDashletList as $oDomNode)
|
foreach ($oDashletList as $oDomNode) {
|
||||||
{
|
|
||||||
$oRank = $oDomNode->getElementsByTagName('rank')->item(0);
|
$oRank = $oDomNode->getElementsByTagName('rank')->item(0);
|
||||||
if ($oRank)
|
if ($oRank) {
|
||||||
{
|
|
||||||
$iRank = (float)$oRank->textContent;
|
$iRank = (float)$oRank->textContent;
|
||||||
}
|
}
|
||||||
|
|
||||||
$oNewDashlet = $this->InitDashletFromDOMNode($oDomNode);
|
$oNewDashlet = $this->InitDashletFromDOMNode($oDomNode);
|
||||||
$aDashletOrder[] = array('rank' => $iRank, 'dashlet' => $oNewDashlet);
|
$aDashletOrder[] = ['rank' => $iRank, 'dashlet' => $oNewDashlet];
|
||||||
}
|
}
|
||||||
usort($aDashletOrder, array(get_class($this), 'SortOnRank'));
|
usort($aDashletOrder, [get_class($this), 'SortOnRank']);
|
||||||
$aDashletList = array();
|
$aDashletList = [];
|
||||||
foreach($aDashletOrder as $aItem)
|
foreach ($aDashletOrder as $aItem) {
|
||||||
{
|
|
||||||
$aDashletList[] = $aItem['dashlet'];
|
$aDashletList[] = $aItem['dashlet'];
|
||||||
}
|
}
|
||||||
$aCellOrder[] = array('rank' => $iCellRank, 'dashlets' => $aDashletList);
|
$aCellOrder[] = ['rank' => $iCellRank, 'dashlets' => $aDashletList];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
usort($aCellOrder, array(get_class($this), 'SortOnRank'));
|
usort($aCellOrder, [get_class($this), 'SortOnRank']);
|
||||||
foreach($aCellOrder as $aItem)
|
foreach ($aCellOrder as $aItem) {
|
||||||
{
|
|
||||||
$this->aCells[] = $aItem['dashlets'];
|
$this->aCells[] = $aItem['dashlets'];
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
else
|
$this->aCells = [];
|
||||||
{
|
|
||||||
$this->aCells = array();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -169,20 +152,20 @@ abstract class Dashboard
|
|||||||
* @return mixed
|
* @return mixed
|
||||||
*/
|
*/
|
||||||
protected function InitDashletFromDOMNode($oDomNode)
|
protected function InitDashletFromDOMNode($oDomNode)
|
||||||
{
|
{
|
||||||
$sId = $oDomNode->getAttribute('id');
|
$sId = $oDomNode->getAttribute('id');
|
||||||
|
|
||||||
$sDashletType = $oDomNode->getAttribute('xsi:type');
|
$sDashletType = $oDomNode->getAttribute('xsi:type');
|
||||||
|
|
||||||
// Test if dashlet can be instantiated, otherwise (uninstalled, broken, ...) we display a placeholder
|
// Test if dashlet can be instantiated, otherwise (uninstalled, broken, ...) we display a placeholder
|
||||||
$sClass = static::GetDashletClassFromType($sDashletType);
|
$sClass = static::GetDashletClassFromType($sDashletType);
|
||||||
/** @var \Dashlet $oNewDashlet */
|
/** @var \Dashlet $oNewDashlet */
|
||||||
$oNewDashlet = new $sClass($this->oMetaModel, $sId);
|
$oNewDashlet = new $sClass($this->oMetaModel, $sId);
|
||||||
$oNewDashlet->SetDashletType($sDashletType);
|
$oNewDashlet->SetDashletType($sDashletType);
|
||||||
$oNewDashlet->FromDOMNode($oDomNode);
|
$oNewDashlet->FromDOMNode($oDomNode);
|
||||||
|
|
||||||
return $oNewDashlet;
|
return $oNewDashlet;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param array $aItem1
|
* @param array $aItem1
|
||||||
@@ -208,12 +191,9 @@ abstract class Dashboard
|
|||||||
*/
|
*/
|
||||||
public static function ErrorHandler($errno, $errstr, $errfile, $errline)
|
public static function ErrorHandler($errno, $errstr, $errfile, $errline)
|
||||||
{
|
{
|
||||||
if ($errno == E_WARNING && (substr_count($errstr,"DOMDocument::loadXML()")>0))
|
if ($errno == E_WARNING && (substr_count($errstr, "DOMDocument::loadXML()") > 0)) {
|
||||||
{
|
|
||||||
throw new DOMException($errstr);
|
throw new DOMException($errstr);
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -231,7 +211,7 @@ abstract class Dashboard
|
|||||||
$oMainNode = $oDoc->createElement('dashboard');
|
$oMainNode = $oDoc->createElement('dashboard');
|
||||||
$oMainNode->setAttribute('xmlns:xsi', "http://www.w3.org/2001/XMLSchema-instance");
|
$oMainNode->setAttribute('xmlns:xsi', "http://www.w3.org/2001/XMLSchema-instance");
|
||||||
$oDoc->appendChild($oMainNode);
|
$oDoc->appendChild($oMainNode);
|
||||||
|
|
||||||
$this->ToDOMNode($oMainNode);
|
$this->ToDOMNode($oMainNode);
|
||||||
|
|
||||||
$sXml = $oDoc->saveXML();
|
$sXml = $oDoc->saveXML();
|
||||||
@@ -261,23 +241,21 @@ abstract class Dashboard
|
|||||||
|
|
||||||
$oCellsNode = $oDoc->createElement('cells');
|
$oCellsNode = $oDoc->createElement('cells');
|
||||||
$oDefinition->appendChild($oCellsNode);
|
$oDefinition->appendChild($oCellsNode);
|
||||||
|
|
||||||
$iCellRank = 0;
|
$iCellRank = 0;
|
||||||
foreach ($this->aCells as $aCell)
|
foreach ($this->aCells as $aCell) {
|
||||||
{
|
|
||||||
$oCellNode = $oDoc->createElement('cell');
|
$oCellNode = $oDoc->createElement('cell');
|
||||||
$oCellNode->setAttribute('id', $iCellRank);
|
$oCellNode->setAttribute('id', $iCellRank);
|
||||||
$oCellsNode->appendChild($oCellNode);
|
$oCellsNode->appendChild($oCellNode);
|
||||||
$oCellRank = $oDoc->createElement('rank', $iCellRank);
|
$oCellRank = $oDoc->createElement('rank', $iCellRank);
|
||||||
$oCellNode->appendChild($oCellRank);
|
$oCellNode->appendChild($oCellRank);
|
||||||
$iCellRank++;
|
$iCellRank++;
|
||||||
|
|
||||||
$iDashletRank = 0;
|
$iDashletRank = 0;
|
||||||
$oDashletsNode = $oDoc->createElement('dashlets');
|
$oDashletsNode = $oDoc->createElement('dashlets');
|
||||||
$oCellNode->appendChild($oDashletsNode);
|
$oCellNode->appendChild($oDashletsNode);
|
||||||
/** @var \Dashlet $oDashlet */
|
/** @var \Dashlet $oDashlet */
|
||||||
foreach ($aCell as $oDashlet)
|
foreach ($aCell as $oDashlet) {
|
||||||
{
|
|
||||||
$oNode = $oDoc->createElement('dashlet');
|
$oNode = $oDoc->createElement('dashlet');
|
||||||
$oDashletsNode->appendChild($oNode);
|
$oDashletsNode->appendChild($oNode);
|
||||||
$oNode->setAttribute('id', $oDashlet->GetID());
|
$oNode->setAttribute('id', $oDashlet->GetID());
|
||||||
@@ -296,21 +274,21 @@ abstract class Dashboard
|
|||||||
public function FromParams($aParams)
|
public function FromParams($aParams)
|
||||||
{
|
{
|
||||||
$this->sLayoutClass = $aParams['layout_class'];
|
$this->sLayoutClass = $aParams['layout_class'];
|
||||||
|
if (!is_subclass_of($this->sLayoutClass, DashboardLayout::class)) {
|
||||||
|
throw new InvalidParameterException('Invalid parameter layout_class "'.$aParams['layout_class'].'"');
|
||||||
|
}
|
||||||
$this->sTitle = $aParams['title'];
|
$this->sTitle = $aParams['title'];
|
||||||
$this->bAutoReload = $aParams['auto_reload'] == 'true';
|
$this->bAutoReload = $aParams['auto_reload'] == 'true';
|
||||||
$this->iAutoReloadSec = max(MetaModel::GetConfig()->Get('min_reload_interval'), (int) $aParams['auto_reload_sec']);
|
$this->iAutoReloadSec = max(MetaModel::GetConfig()->Get('min_reload_interval'), (int) $aParams['auto_reload_sec']);
|
||||||
|
|
||||||
foreach($aParams['cells'] as $aCell)
|
foreach ($aParams['cells'] as $aCell) {
|
||||||
{
|
$aCellDashlets = [];
|
||||||
$aCellDashlets = array();
|
foreach ($aCell as $aDashletParams) {
|
||||||
foreach($aCell as $aDashletParams)
|
|
||||||
{
|
|
||||||
$sDashletClass = $aDashletParams['dashlet_class'];
|
$sDashletClass = $aDashletParams['dashlet_class'];
|
||||||
$sId = $aDashletParams['dashlet_id'];
|
$sId = $aDashletParams['dashlet_id'];
|
||||||
/** @var \Dashlet $oNewDashlet */
|
/** @var \Dashlet $oNewDashlet */
|
||||||
$oNewDashlet = new $sDashletClass($this->oMetaModel, $sId);
|
$oNewDashlet = new $sDashletClass($this->oMetaModel, $sId);
|
||||||
if (isset($aDashletParams['dashlet_type']))
|
if (isset($aDashletParams['dashlet_type'])) {
|
||||||
{
|
|
||||||
$oNewDashlet->SetDashletType($aDashletParams['dashlet_type']);
|
$oNewDashlet->SetDashletType($aDashletParams['dashlet_type']);
|
||||||
}
|
}
|
||||||
$oForm = $oNewDashlet->GetForm();
|
$oForm = $oNewDashlet->GetForm();
|
||||||
@@ -322,12 +300,12 @@ abstract class Dashboard
|
|||||||
}
|
}
|
||||||
$this->aCells[] = $aCellDashlets;
|
$this->aCells[] = $aCellDashlets;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function Save()
|
public function Save()
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -420,7 +398,7 @@ abstract class Dashboard
|
|||||||
{
|
{
|
||||||
$sId = $this->GetNewDashletId();
|
$sId = $this->GetNewDashletId();
|
||||||
$oDashlet->SetId($sId);
|
$oDashlet->SetId($sId);
|
||||||
$this->aCells[] = array($oDashlet);
|
$this->aCells[] = [$oDashlet];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -430,7 +408,7 @@ abstract class Dashboard
|
|||||||
* @throws \ReflectionException
|
* @throws \ReflectionException
|
||||||
* @throws \Exception
|
* @throws \Exception
|
||||||
*/
|
*/
|
||||||
public function RenderProperties($oPage, $aExtraParams = array())
|
public function RenderProperties($oPage, $aExtraParams = [])
|
||||||
{
|
{
|
||||||
// menu to pick a layout and edit other properties of the dashboard
|
// menu to pick a layout and edit other properties of the dashboard
|
||||||
$oPage->add('<div class="ui-widget-content ui-corner-all ibo-dashboard-editor--properties"><div class="ui-widget-header ui-corner-all ibo-dashboard-editor--properties-title">'.Dict::S('UI:DashboardEdit:Properties').'</div>');
|
$oPage->add('<div class="ui-widget-content ui-corner-all ibo-dashboard-editor--properties"><div class="ui-widget-header ui-corner-all ibo-dashboard-editor--properties-title">'.Dict::S('UI:DashboardEdit:Properties').'</div>');
|
||||||
@@ -442,7 +420,7 @@ abstract class Dashboard
|
|||||||
if (is_subclass_of($sLayoutClass, 'DashboardLayout')) {
|
if (is_subclass_of($sLayoutClass, 'DashboardLayout')) {
|
||||||
$oReflection = new ReflectionClass($sLayoutClass);
|
$oReflection = new ReflectionClass($sLayoutClass);
|
||||||
if (!$oReflection->isAbstract()) {
|
if (!$oReflection->isAbstract()) {
|
||||||
$aCallSpec = array($sLayoutClass, 'GetInfo');
|
$aCallSpec = [$sLayoutClass, 'GetInfo'];
|
||||||
$aInfo = call_user_func($aCallSpec);
|
$aInfo = call_user_func($aCallSpec);
|
||||||
$sChecked = ($this->sLayoutClass == $sLayoutClass) ? 'checked' : '';
|
$sChecked = ($this->sLayoutClass == $sLayoutClass) ? 'checked' : '';
|
||||||
$oPage->add('<input type="radio" name="layout_class" '.$sChecked.' value="'.$sLayoutClass.'" id="layout_'.$sLayoutClass.'"><label for="layout_'.$sLayoutClass.'"><img src="'.$sUrl.$aInfo['icon'].'" class="ibo-dashboard--properties--icon" data-role="ibo-dashboard--properties--icon"/></label>'); // title="" on either the img or the label does nothing !
|
$oPage->add('<input type="radio" name="layout_class" '.$sChecked.' value="'.$sLayoutClass.'" id="layout_'.$sLayoutClass.'"><label for="layout_'.$sLayoutClass.'"><img src="'.$sUrl.$aInfo['icon'].'" class="ibo-dashboard--properties--icon" data-role="ibo-dashboard--properties--icon"/></label>'); // title="" on either the img or the label does nothing !
|
||||||
@@ -466,7 +444,6 @@ abstract class Dashboard
|
|||||||
$oField->SetBoundaries(MetaModel::GetConfig()->Get('min_reload_interval'), null); // no upper limit
|
$oField->SetBoundaries(MetaModel::GetConfig()->Get('min_reload_interval'), null); // no upper limit
|
||||||
$oForm->AddField($oField);
|
$oForm->AddField($oField);
|
||||||
|
|
||||||
|
|
||||||
$this->SetFormParams($oForm, $aExtraParams);
|
$this->SetFormParams($oForm, $aExtraParams);
|
||||||
$oForm->RenderAsPropertySheet($oPage, false, '.itop-dashboard');
|
$oForm->RenderAsPropertySheet($oPage, false, '.itop-dashboard');
|
||||||
|
|
||||||
@@ -474,7 +451,7 @@ abstract class Dashboard
|
|||||||
|
|
||||||
$sRateTitle = addslashes(Dict::Format('UI:DashboardEdit:AutoReloadSec+', MetaModel::GetConfig()->Get('min_reload_interval')));
|
$sRateTitle = addslashes(Dict::Format('UI:DashboardEdit:AutoReloadSec+', MetaModel::GetConfig()->Get('min_reload_interval')));
|
||||||
$oPage->add_ready_script(
|
$oPage->add_ready_script(
|
||||||
<<<EOF
|
<<<EOF
|
||||||
// Note: the title gets deleted by the validation mechanism
|
// Note: the title gets deleted by the validation mechanism
|
||||||
$("#attr_auto_reload_sec").attr('data-tooltip-content', '$sRateTitle');
|
$("#attr_auto_reload_sec").attr('data-tooltip-content', '$sRateTitle');
|
||||||
CombodoTooltip.InitTooltipFromMarkup($("#attr_auto_reload_sec"));
|
CombodoTooltip.InitTooltipFromMarkup($("#attr_auto_reload_sec"));
|
||||||
@@ -522,7 +499,7 @@ EOF
|
|||||||
*
|
*
|
||||||
* @return \Combodo\iTop\Application\UI\Base\Layout\Dashboard\DashboardLayout
|
* @return \Combodo\iTop\Application\UI\Base\Layout\Dashboard\DashboardLayout
|
||||||
*/
|
*/
|
||||||
public function Render($oPage, $bEditMode = false, $aExtraParams = array(), $bCanEdit = true)
|
public function Render($oPage, $bEditMode = false, $aExtraParams = [], $bCanEdit = true)
|
||||||
{
|
{
|
||||||
$aExtraParams['dashboard_div_id'] = utils::Sanitize($aExtraParams['dashboard_div_id'] ?? null, $this->GetId(), utils::ENUM_SANITIZATION_FILTER_ELEMENT_IDENTIFIER);
|
$aExtraParams['dashboard_div_id'] = utils::Sanitize($aExtraParams['dashboard_div_id'] ?? null, $this->GetId(), utils::ENUM_SANITIZATION_FILTER_ELEMENT_IDENTIFIER);
|
||||||
|
|
||||||
@@ -551,7 +528,8 @@ EOF
|
|||||||
|
|
||||||
$oToolbar->AddHtml($sHtml);
|
$oToolbar->AddHtml($sHtml);
|
||||||
} else {
|
} else {
|
||||||
$oPage->add_script(<<<JS
|
$oPage->add_script(
|
||||||
|
<<<JS
|
||||||
$(".ibo-top-bar--toolbar-dashboard-title").html("$sTitleForHTML").attr("title", $('<div>').html("$sTitleForHTML").text());
|
$(".ibo-top-bar--toolbar-dashboard-title").html("$sTitleForHTML").attr("title", $('<div>').html("$sTitleForHTML").text());
|
||||||
JS
|
JS
|
||||||
);
|
);
|
||||||
@@ -595,7 +573,7 @@ JS
|
|||||||
* @param WebPage $oPage
|
* @param WebPage $oPage
|
||||||
* @param array $aExtraParams
|
* @param array $aExtraParams
|
||||||
*/
|
*/
|
||||||
public function RenderDashletsProperties(WebPage $oPage, $aExtraParams = array())
|
public function RenderDashletsProperties(WebPage $oPage, $aExtraParams = [])
|
||||||
{
|
{
|
||||||
// Toolbox/palette to edit the properties of each dashlet
|
// Toolbox/palette to edit the properties of each dashlet
|
||||||
$oPage->add('<div class="ui-widget-content ui-corner-all ibo-dashlet--properties"><div class="ui-widget-header ui-corner-all ibo-dashlet--properties--title">'.Dict::S('UI:DashboardEdit:DashletProperties').'</div>');
|
$oPage->add('<div class="ui-widget-content ui-corner-all ibo-dashlet--properties"><div class="ui-widget-header ui-corner-all ibo-dashlet--properties--title">'.Dict::S('UI:DashboardEdit:DashletProperties').'</div>');
|
||||||
@@ -604,13 +582,10 @@ JS
|
|||||||
$oLayout = new $this->sLayoutClass();
|
$oLayout = new $this->sLayoutClass();
|
||||||
|
|
||||||
$oPage->add('<div id="dashlet_properties">');
|
$oPage->add('<div id="dashlet_properties">');
|
||||||
foreach($this->aCells as $iCellIdx => $aCell)
|
foreach ($this->aCells as $iCellIdx => $aCell) {
|
||||||
{
|
|
||||||
/** @var \Dashlet $oDashlet */
|
/** @var \Dashlet $oDashlet */
|
||||||
foreach($aCell as $oDashlet)
|
foreach ($aCell as $oDashlet) {
|
||||||
{
|
if ($oDashlet->IsVisible()) {
|
||||||
if ($oDashlet->IsVisible())
|
|
||||||
{
|
|
||||||
$oPage->add('<div class="dashlet_properties" id="dashlet_properties_'.$oDashlet->GetID().'" style="display:none">');
|
$oPage->add('<div class="dashlet_properties" id="dashlet_properties_'.$oDashlet->GetID().'" style="display:none">');
|
||||||
$oForm = $oDashlet->GetForm();
|
$oForm = $oDashlet->GetForm();
|
||||||
$this->SetFormParams($oForm, $aExtraParams);
|
$this->SetFormParams($oForm, $aExtraParams);
|
||||||
@@ -632,18 +607,17 @@ JS
|
|||||||
*/
|
*/
|
||||||
protected function GetAvailableDashlets()
|
protected function GetAvailableDashlets()
|
||||||
{
|
{
|
||||||
$aDashlets = array();
|
$aDashlets = [];
|
||||||
|
|
||||||
foreach( get_declared_classes() as $sDashletClass)
|
foreach (get_declared_classes() as $sDashletClass) {
|
||||||
{
|
|
||||||
// DashletUnknown is not among the selection as it is just a fallback for dashlets that can't instantiated.
|
// DashletUnknown is not among the selection as it is just a fallback for dashlets that can't instantiated.
|
||||||
if (is_subclass_of($sDashletClass, 'Dashlet') && !in_array($sDashletClass, array('DashletUnknown', 'DashletProxy'))) {
|
if (is_subclass_of($sDashletClass, 'Dashlet') && !in_array($sDashletClass, ['DashletUnknown', 'DashletProxy'])) {
|
||||||
$oReflection = new ReflectionClass($sDashletClass);
|
$oReflection = new ReflectionClass($sDashletClass);
|
||||||
if (!$oReflection->isAbstract()) {
|
if (!$oReflection->isAbstract()) {
|
||||||
$aCallSpec = array($sDashletClass, 'IsVisible');
|
$aCallSpec = [$sDashletClass, 'IsVisible'];
|
||||||
$bVisible = call_user_func($aCallSpec);
|
$bVisible = call_user_func($aCallSpec);
|
||||||
if ($bVisible) {
|
if ($bVisible) {
|
||||||
$aCallSpec = array($sDashletClass, 'GetInfo');
|
$aCallSpec = [$sDashletClass, 'GetInfo'];
|
||||||
$aInfo = call_user_func($aCallSpec);
|
$aInfo = call_user_func($aCallSpec);
|
||||||
$aDashlets[$sDashletClass] = $aInfo;
|
$aDashlets[$sDashletClass] = $aInfo;
|
||||||
}
|
}
|
||||||
@@ -660,11 +634,9 @@ JS
|
|||||||
protected function GetNewDashletId()
|
protected function GetNewDashletId()
|
||||||
{
|
{
|
||||||
$iNewId = 0;
|
$iNewId = 0;
|
||||||
foreach($this->aCells as $aDashlets)
|
foreach ($this->aCells as $aDashlets) {
|
||||||
{
|
|
||||||
/** @var \Dashlet $oDashlet */
|
/** @var \Dashlet $oDashlet */
|
||||||
foreach($aDashlets as $oDashlet)
|
foreach ($aDashlets as $oDashlet) {
|
||||||
{
|
|
||||||
$iNewId = max($iNewId, (int)$oDashlet->GetID());
|
$iNewId = max($iNewId, (int)$oDashlet->GetID());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -681,15 +653,15 @@ JS
|
|||||||
*
|
*
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
abstract protected function PrepareDashletForRendering(Dashlet $oDashlet, $aCoordinates, $aExtraParams = array());
|
abstract protected function PrepareDashletForRendering(Dashlet $oDashlet, $aCoordinates, $aExtraParams = []);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param \DesignerForm $oForm
|
* @param \DesignerForm $oForm
|
||||||
* @param array $aExtraParams
|
* @param array $aExtraParams
|
||||||
*
|
*
|
||||||
* @return mixed
|
* @return mixed
|
||||||
*/
|
*/
|
||||||
abstract protected function SetFormParams($oForm, $aExtraParams = array());
|
abstract protected function SetFormParams($oForm, $aExtraParams = []);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param string $sType
|
* @param string $sType
|
||||||
@@ -699,8 +671,7 @@ JS
|
|||||||
*/
|
*/
|
||||||
public static function GetDashletClassFromType($sType, $oFactory = null)
|
public static function GetDashletClassFromType($sType, $oFactory = null)
|
||||||
{
|
{
|
||||||
if (is_subclass_of($sType, 'Dashlet'))
|
if (is_subclass_of($sType, 'Dashlet')) {
|
||||||
{
|
|
||||||
return $sType;
|
return $sType;
|
||||||
}
|
}
|
||||||
return 'DashletUnknown';
|
return 'DashletUnknown';
|
||||||
@@ -723,14 +694,12 @@ JS
|
|||||||
*/
|
*/
|
||||||
public static function GetDashletUniqueId($bIsCustomized, $sDashboardDivId, $iRow, $iCol, $sDashletOrigId)
|
public static function GetDashletUniqueId($bIsCustomized, $sDashboardDivId, $iRow, $iCol, $sDashletOrigId)
|
||||||
{
|
{
|
||||||
if(strpos($sDashletOrigId, '_ID_row') !== false)
|
if (strpos($sDashletOrigId, '_ID_row') !== false) {
|
||||||
{
|
|
||||||
return $sDashletOrigId;
|
return $sDashletOrigId;
|
||||||
}
|
}
|
||||||
|
|
||||||
$sDashletId = $sDashboardDivId."_ID_row".$iRow."_col".$iCol."_".$sDashletOrigId;
|
$sDashletId = $sDashboardDivId."_ID_row".$iRow."_col".$iCol."_".$sDashletOrigId;
|
||||||
if ($bIsCustomized)
|
if ($bIsCustomized) {
|
||||||
{
|
|
||||||
$sDashletId = 'CUSTOM_'.$sDashletId;
|
$sDashletId = 'CUSTOM_'.$sDashletId;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -782,9 +751,9 @@ class RuntimeDashboard extends Dashboard
|
|||||||
* @inheritDoc
|
* @inheritDoc
|
||||||
* @throws \Exception
|
* @throws \Exception
|
||||||
*/
|
*/
|
||||||
protected function SetFormParams($oForm, $aExtraParams = array())
|
protected function SetFormParams($oForm, $aExtraParams = [])
|
||||||
{
|
{
|
||||||
$oForm->SetSubmitParams(utils::GetAbsoluteUrlAppRoot().'pages/ajax.render.php', array('operation' => 'update_dashlet_property', 'extra_params' => $aExtraParams));
|
$oForm->SetSubmitParams(utils::GetAbsoluteUrlAppRoot().'pages/ajax.render.php', ['operation' => 'update_dashlet_property', 'extra_params' => $aExtraParams]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -800,14 +769,11 @@ class RuntimeDashboard extends Dashboard
|
|||||||
$oUDSearch->AddCondition('menu_code', $this->sId, '=');
|
$oUDSearch->AddCondition('menu_code', $this->sId, '=');
|
||||||
$oUDSet = new DBObjectSet($oUDSearch);
|
$oUDSet = new DBObjectSet($oUDSearch);
|
||||||
$bIsNew = false;
|
$bIsNew = false;
|
||||||
if ($oUDSet->Count() > 0)
|
if ($oUDSet->Count() > 0) {
|
||||||
{
|
|
||||||
// Assuming there is at most one couple {user, menu}!
|
// Assuming there is at most one couple {user, menu}!
|
||||||
$oUserDashboard = $oUDSet->Fetch();
|
$oUserDashboard = $oUDSet->Fetch();
|
||||||
$oUserDashboard->Set('contents', $sXml);
|
$oUserDashboard->Set('contents', $sXml);
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
// No such customized dashboard for the current user, let's create a new record
|
// No such customized dashboard for the current user, let's create a new record
|
||||||
$oUserDashboard = new UserDashboard();
|
$oUserDashboard = new UserDashboard();
|
||||||
$oUserDashboard->Set('user_id', UserRights::GetUserId());
|
$oUserDashboard->Set('user_id', UserRights::GetUserId());
|
||||||
@@ -838,8 +804,7 @@ class RuntimeDashboard extends Dashboard
|
|||||||
$oUDSearch->AddCondition('user_id', UserRights::GetUserId(), '=');
|
$oUDSearch->AddCondition('user_id', UserRights::GetUserId(), '=');
|
||||||
$oUDSearch->AddCondition('menu_code', $this->sId, '=');
|
$oUDSearch->AddCondition('menu_code', $this->sId, '=');
|
||||||
$oUDSet = new DBObjectSet($oUDSearch);
|
$oUDSet = new DBObjectSet($oUDSearch);
|
||||||
if ($oUDSet->Count() > 0)
|
if ($oUDSet->Count() > 0) {
|
||||||
{
|
|
||||||
// Assuming there is at most one couple {user, menu}!
|
// Assuming there is at most one couple {user, menu}!
|
||||||
$oUserDashboard = $oUDSet->Fetch();
|
$oUserDashboard = $oUDSet->Fetch();
|
||||||
utils::PushArchiveMode(false);
|
utils::PushArchiveMode(false);
|
||||||
@@ -883,14 +848,11 @@ class RuntimeDashboard extends Dashboard
|
|||||||
} else {
|
} else {
|
||||||
$sDashboardDefinition = @file_get_contents($sDashboardFileSanitized);
|
$sDashboardDefinition = @file_get_contents($sDashboardFileSanitized);
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
$sDashboardDefinition = @file_get_contents($sDashboardFileSanitized);
|
$sDashboardDefinition = @file_get_contents($sDashboardFileSanitized);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($sDashboardDefinition !== false)
|
if ($sDashboardDefinition !== false) {
|
||||||
{
|
|
||||||
$oDashboard = new RuntimeDashboard($sDashBoardId);
|
$oDashboard = new RuntimeDashboard($sDashBoardId);
|
||||||
$oDashboard->FromXml($sDashboardDefinition);
|
$oDashboard->FromXml($sDashboardDefinition);
|
||||||
$oDashboard->SetCustomFlag($bCustomized);
|
$oDashboard->SetCustomFlag($bCustomized);
|
||||||
@@ -937,7 +899,6 @@ class RuntimeDashboard extends Dashboard
|
|||||||
$sDashboardDefinition = @file_get_contents($sDashboardFileSanitized);
|
$sDashboardDefinition = @file_get_contents($sDashboardFileSanitized);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if ($sDashboardDefinition !== false) {
|
if ($sDashboardDefinition !== false) {
|
||||||
$oDashboard = new RuntimeDashboard($sDashBoardId);
|
$oDashboard = new RuntimeDashboard($sDashBoardId);
|
||||||
$oDashboard->FromXml($sDashboardDefinition);
|
$oDashboard->FromXml($sDashboardDefinition);
|
||||||
@@ -954,11 +915,11 @@ class RuntimeDashboard extends Dashboard
|
|||||||
* @inheritDoc
|
* @inheritDoc
|
||||||
* @throws \Exception
|
* @throws \Exception
|
||||||
*/
|
*/
|
||||||
public function Render($oPage, $bEditMode = false, $aExtraParams = array(), $bCanEdit = true)
|
public function Render($oPage, $bEditMode = false, $aExtraParams = [], $bCanEdit = true)
|
||||||
{
|
{
|
||||||
if (!isset($aExtraParams['query_params']) && isset($aExtraParams['this->class'])) {
|
if (!isset($aExtraParams['query_params']) && isset($aExtraParams['this->class'])) {
|
||||||
$oObj = MetaModel::GetObject($aExtraParams['this->class'], $aExtraParams['this->id']);
|
$oObj = MetaModel::GetObject($aExtraParams['this->class'], $aExtraParams['this->id']);
|
||||||
$aRenderParams = array('query_params' => $oObj->ToArgsForQuery());
|
$aRenderParams = ['query_params' => $oObj->ToArgsForQuery()];
|
||||||
} else {
|
} else {
|
||||||
$aRenderParams = $aExtraParams;
|
$aRenderParams = $aExtraParams;
|
||||||
}
|
}
|
||||||
@@ -968,7 +929,7 @@ class RuntimeDashboard extends Dashboard
|
|||||||
if (isset($aExtraParams['query_params']['this->object()'])) {
|
if (isset($aExtraParams['query_params']['this->object()'])) {
|
||||||
/** @var \DBObject $oObj */
|
/** @var \DBObject $oObj */
|
||||||
$oObj = $aExtraParams['query_params']['this->object()'];
|
$oObj = $aExtraParams['query_params']['this->object()'];
|
||||||
$aAjaxParams = array('this->class' => get_class($oObj), 'this->id' => $oObj->GetKey());
|
$aAjaxParams = ['this->class' => get_class($oObj), 'this->id' => $oObj->GetKey()];
|
||||||
if (isset($aExtraParams['from_dashboard_page'])) {
|
if (isset($aExtraParams['from_dashboard_page'])) {
|
||||||
$aAjaxParams['from_dashboard_page'] = $aExtraParams['from_dashboard_page'];
|
$aAjaxParams['from_dashboard_page'] = $aExtraParams['from_dashboard_page'];
|
||||||
}
|
}
|
||||||
@@ -1001,9 +962,7 @@ class RuntimeDashboard extends Dashboard
|
|||||||
}
|
}
|
||||||
JS
|
JS
|
||||||
);
|
);
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
$oPage->add_script(
|
$oPage->add_script(
|
||||||
<<<EOF
|
<<<EOF
|
||||||
if (typeof(AutoReloadDashboardId$sDivId) !== 'undefined')
|
if (typeof(AutoReloadDashboardId$sDivId) !== 'undefined')
|
||||||
@@ -1032,7 +991,7 @@ EOF
|
|||||||
* @throws \CoreUnexpectedValue
|
* @throws \CoreUnexpectedValue
|
||||||
* @throws \MySQLException
|
* @throws \MySQLException
|
||||||
*/
|
*/
|
||||||
protected function RenderSelector(WebPage $oPage, DashboardLayoutUIBlock $oDashboard, $aAjaxParams = array())
|
protected function RenderSelector(WebPage $oPage, DashboardLayoutUIBlock $oDashboard, $aAjaxParams = [])
|
||||||
{
|
{
|
||||||
if (!$this->HasCustomDashboard()) {
|
if (!$this->HasCustomDashboard()) {
|
||||||
return;
|
return;
|
||||||
@@ -1070,7 +1029,7 @@ EOF
|
|||||||
var dashboard = $('.ibo-dashboard#$sDivId')
|
var dashboard = $('.ibo-dashboard#$sDivId')
|
||||||
dashboard.block();
|
dashboard.block();
|
||||||
$.post(GetAbsoluteUrlAppRoot()+'pages/ajax.render.php',
|
$.post(GetAbsoluteUrlAppRoot()+'pages/ajax.render.php',
|
||||||
{ operation: 'toggle_dashboard', dashboard_id: '$sId', file: '$sFile', extra_params: $sExtraParams, reload_url: '$sReloadURL' },
|
{ operation: 'toggle_dashboard', dashboard_id: '$sId', file: '$sFile', extra_params: $sExtraParams, reload_url: $sReloadURL },
|
||||||
function(data) {
|
function(data) {
|
||||||
dashboard.html(data);
|
dashboard.html(data);
|
||||||
dashboard.unblock();
|
dashboard.unblock();
|
||||||
@@ -1092,8 +1051,7 @@ JS
|
|||||||
*/
|
*/
|
||||||
protected function HasCustomDashboard()
|
protected function HasCustomDashboard()
|
||||||
{
|
{
|
||||||
try
|
try {
|
||||||
{
|
|
||||||
// Search for an eventual user defined dashboard
|
// Search for an eventual user defined dashboard
|
||||||
$oUDSearch = new DBObjectSearch('UserDashboard');
|
$oUDSearch = new DBObjectSearch('UserDashboard');
|
||||||
$oUDSearch->AddCondition('user_id', UserRights::GetUserId(), '=');
|
$oUDSearch->AddCondition('user_id', UserRights::GetUserId(), '=');
|
||||||
@@ -1101,9 +1059,7 @@ JS
|
|||||||
$oUDSet = new DBObjectSet($oUDSearch);
|
$oUDSet = new DBObjectSet($oUDSearch);
|
||||||
|
|
||||||
return ($oUDSet->Count() > 0);
|
return ($oUDSet->Count() > 0);
|
||||||
}
|
} catch (Exception $e) {
|
||||||
catch (Exception $e)
|
|
||||||
{
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1139,21 +1095,23 @@ JS
|
|||||||
->AddCSSClass('ibo-action-button');
|
->AddCSSClass('ibo-action-button');
|
||||||
|
|
||||||
$oToolbar->AddSubBlock($oActionButton);
|
$oToolbar->AddSubBlock($oActionButton);
|
||||||
$aActions = array();
|
$aActions = [];
|
||||||
$sFile = addslashes(utils::LocalPath($this->sDefinitionFile));
|
$sFile = addslashes(utils::LocalPath($this->sDefinitionFile));
|
||||||
$sJSExtraParams = json_encode($aExtraParams);
|
$sJSExtraParams = json_encode($aExtraParams);
|
||||||
if ($this->HasCustomDashboard()) {
|
if ($this->HasCustomDashboard()) {
|
||||||
$oEdit = new JSPopupMenuItem('UI:Dashboard:Edit', Dict::S('UI:Dashboard:EditCustom'), "return EditDashboard('{$this->sId}', '$sFile', $sJSExtraParams)");
|
$oEdit = new JSPopupMenuItem('UI:Dashboard:Edit', Dict::S('UI:Dashboard:EditCustom'), "return EditDashboard('{$this->sId}', '$sFile', $sJSExtraParams)");
|
||||||
$aActions[$oEdit->GetUID()] = $oEdit->GetMenuItem();
|
$aActions[$oEdit->GetUID()] = $oEdit->GetMenuItem();
|
||||||
$oRevert = new JSPopupMenuItem('UI:Dashboard:RevertConfirm', Dict::S('UI:Dashboard:DeleteCustom'),
|
$oRevert = new JSPopupMenuItem(
|
||||||
"if (confirm('".addslashes(Dict::S('UI:Dashboard:RevertConfirm'))."')) return RevertDashboard('{$this->sId}', $sJSExtraParams); else return false");
|
'UI:Dashboard:RevertConfirm',
|
||||||
|
Dict::S('UI:Dashboard:DeleteCustom'),
|
||||||
|
"if (confirm('".addslashes(Dict::S('UI:Dashboard:RevertConfirm'))."')) return RevertDashboard('{$this->sId}', $sJSExtraParams); else return false"
|
||||||
|
);
|
||||||
$aActions[$oRevert->GetUID()] = $oRevert->GetMenuItem();
|
$aActions[$oRevert->GetUID()] = $oRevert->GetMenuItem();
|
||||||
} else {
|
} else {
|
||||||
$oEdit = new JSPopupMenuItem('UI:Dashboard:Edit', Dict::S('UI:Dashboard:CreateCustom'), "return EditDashboard('{$this->sId}', '$sFile', $sJSExtraParams)");
|
$oEdit = new JSPopupMenuItem('UI:Dashboard:Edit', Dict::S('UI:Dashboard:CreateCustom'), "return EditDashboard('{$this->sId}', '$sFile', $sJSExtraParams)");
|
||||||
$aActions[$oEdit->GetUID()] = $oEdit->GetMenuItem();
|
$aActions[$oEdit->GetUID()] = $oEdit->GetMenuItem();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
utils::GetPopupMenuItems($oPage, iPopupMenuExtension::MENU_DASHBOARD_ACTIONS, $this, $aActions);
|
utils::GetPopupMenuItems($oPage, iPopupMenuExtension::MENU_DASHBOARD_ACTIONS, $this, $aActions);
|
||||||
|
|
||||||
$oActionsMenu = $oPage->GetPopoverMenu($sPopoverMenuId, $aActions)
|
$oActionsMenu = $oPage->GetPopoverMenu($sPopoverMenuId, $aActions)
|
||||||
@@ -1193,12 +1151,12 @@ EOF
|
|||||||
/**
|
/**
|
||||||
* @inheritDoc
|
* @inheritDoc
|
||||||
*/
|
*/
|
||||||
public function RenderProperties($oPage, $aExtraParams = array())
|
public function RenderProperties($oPage, $aExtraParams = [])
|
||||||
{
|
{
|
||||||
parent::RenderProperties($oPage, $aExtraParams);
|
parent::RenderProperties($oPage, $aExtraParams);
|
||||||
|
|
||||||
$oPage->add_ready_script(
|
$oPage->add_ready_script(
|
||||||
<<<EOF
|
<<<EOF
|
||||||
$('#select_layout input').on('click', function() {
|
$('#select_layout input').on('click', function() {
|
||||||
var sLayoutClass = $(this).val();
|
var sLayoutClass = $(this).val();
|
||||||
$('.itop-dashboard').runtimedashboard('option', {layout_class: sLayoutClass});
|
$('.itop-dashboard').runtimedashboard('option', {layout_class: sLayoutClass});
|
||||||
@@ -1225,7 +1183,6 @@ EOF
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param WebPage $oPage
|
* @param WebPage $oPage
|
||||||
*
|
*
|
||||||
@@ -1236,11 +1193,11 @@ EOF
|
|||||||
* @throws \ReflectionException
|
* @throws \ReflectionException
|
||||||
* @throws \Exception
|
* @throws \Exception
|
||||||
*/
|
*/
|
||||||
public function RenderEditor($oPage, $aExtraParams = array())
|
public function RenderEditor($oPage, $aExtraParams = [])
|
||||||
{
|
{
|
||||||
if (isset($aExtraParams['this->class'])) {
|
if (isset($aExtraParams['this->class'])) {
|
||||||
$oObj = MetaModel::GetObject($aExtraParams['this->class'], $aExtraParams['this->id']);
|
$oObj = MetaModel::GetObject($aExtraParams['this->class'], $aExtraParams['this->id']);
|
||||||
$aRenderParams = array('query_params' => $oObj->ToArgsForQuery());
|
$aRenderParams = ['query_params' => $oObj->ToArgsForQuery()];
|
||||||
} else {
|
} else {
|
||||||
$aRenderParams = $aExtraParams;
|
$aRenderParams = $aExtraParams;
|
||||||
}
|
}
|
||||||
@@ -1262,7 +1219,7 @@ EOF
|
|||||||
$sDialogTitle = Dict::S('UI:DashboardEdit:Title');
|
$sDialogTitle = Dict::S('UI:DashboardEdit:Title');
|
||||||
$sOkButtonLabel = Dict::S('UI:Button:Save');
|
$sOkButtonLabel = Dict::S('UI:Button:Save');
|
||||||
$sCancelButtonLabel = Dict::S('UI:Button:Cancel');
|
$sCancelButtonLabel = Dict::S('UI:Button:Cancel');
|
||||||
|
|
||||||
$sId = json_encode($this->sId);
|
$sId = json_encode($this->sId);
|
||||||
$sLayoutClass = json_encode($this->sLayoutClass);
|
$sLayoutClass = json_encode($this->sLayoutClass);
|
||||||
$sAutoReload = $this->bAutoReload ? 'true' : 'false';
|
$sAutoReload = $this->bAutoReload ? 'true' : 'false';
|
||||||
@@ -1275,9 +1232,9 @@ EOF
|
|||||||
$sExitConfirmationMessage = addslashes(Dict::S('UI:NavigateAwayConfirmationMessage'));
|
$sExitConfirmationMessage = addslashes(Dict::S('UI:NavigateAwayConfirmationMessage'));
|
||||||
$sCancelConfirmationMessage = addslashes(Dict::S('UI:CancelConfirmationMessage'));
|
$sCancelConfirmationMessage = addslashes(Dict::S('UI:CancelConfirmationMessage'));
|
||||||
$sAutoApplyConfirmationMessage = addslashes(Dict::S('UI:AutoApplyConfirmationMessage'));
|
$sAutoApplyConfirmationMessage = addslashes(Dict::S('UI:AutoApplyConfirmationMessage'));
|
||||||
|
|
||||||
$oPage->add_ready_script(
|
$oPage->add_ready_script(
|
||||||
<<<JS
|
<<<JS
|
||||||
window.bLeavingOnUserAction = false;
|
window.bLeavingOnUserAction = false;
|
||||||
|
|
||||||
$('#dashboard_editor').dialog({
|
$('#dashboard_editor').dialog({
|
||||||
@@ -1385,104 +1342,89 @@ JS
|
|||||||
$sContextMenuId = $oAppContext->GetCurrentValue('menu', null);
|
$sContextMenuId = $oAppContext->GetCurrentValue('menu', null);
|
||||||
|
|
||||||
$oForm = new DesignerForm();
|
$oForm = new DesignerForm();
|
||||||
|
|
||||||
// Get the list of all 'dashboard' menus in which we can insert a dashlet
|
// Get the list of all 'dashboard' menus in which we can insert a dashlet
|
||||||
$aAllMenus = ApplicationMenu::ReflectionMenuNodes();
|
$aAllMenus = ApplicationMenu::ReflectionMenuNodes();
|
||||||
$sRootMenuId = ApplicationMenu::GetRootMenuId($sContextMenuId);
|
$sRootMenuId = ApplicationMenu::GetRootMenuId($sContextMenuId);
|
||||||
$aAllowedDashboards = array();
|
$aAllowedDashboards = [];
|
||||||
$sDefaultDashboard = null;
|
$sDefaultDashboard = null;
|
||||||
|
|
||||||
// Store the parent menus for acces check
|
// Store the parent menus for acces check
|
||||||
$aParentMenus = array();
|
$aParentMenus = [];
|
||||||
foreach($aAllMenus as $idx => $aMenu)
|
foreach ($aAllMenus as $idx => $aMenu) {
|
||||||
{
|
/** @var MenuNode $oMenu */
|
||||||
/** @var MenuNode $oMenu */
|
|
||||||
$oMenu = $aMenu['node'];
|
|
||||||
if (count(ApplicationMenu::GetChildren($oMenu->GetIndex())) > 0)
|
|
||||||
{
|
|
||||||
$aParentMenus[$oMenu->GetMenuId()] = $aMenu;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach($aAllMenus as $idx => $aMenu)
|
|
||||||
{
|
|
||||||
$oMenu = $aMenu['node'];
|
$oMenu = $aMenu['node'];
|
||||||
if ($oMenu instanceof DashboardMenuNode)
|
if (count(ApplicationMenu::GetChildren($oMenu->GetIndex())) > 0) {
|
||||||
{
|
$aParentMenus[$oMenu->GetMenuId()] = $aMenu;
|
||||||
// Get the root parent for access check
|
}
|
||||||
$sParentId = $aMenu['parent'];
|
|
||||||
$aParentMenu = $aParentMenus[$sParentId];
|
|
||||||
while (isset($aParentMenus[$aParentMenu['parent']]))
|
|
||||||
{
|
|
||||||
// grand parent exists
|
|
||||||
$sParentId = $aParentMenu['parent'];
|
|
||||||
$aParentMenu = $aParentMenus[$sParentId];
|
|
||||||
}
|
|
||||||
/** @var \MenuNode $oParentMenu */
|
|
||||||
$oParentMenu = $aParentMenu['node'];
|
|
||||||
if ($oMenu->IsEnabled() && $oParentMenu->IsEnabled())
|
|
||||||
{
|
|
||||||
$sMenuLabel = $oMenu->GetTitle();
|
|
||||||
$sParentLabel = Dict::S('Menu:'.$sParentId);
|
|
||||||
if ($sParentLabel != $sMenuLabel)
|
|
||||||
{
|
|
||||||
$aAllowedDashboards[$oMenu->GetMenuId()] = $sParentLabel.' - '.$sMenuLabel;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
$aAllowedDashboards[$oMenu->GetMenuId()] = $sMenuLabel;
|
|
||||||
}
|
|
||||||
if (empty($sDefaultDashboard) && ($sRootMenuId == ApplicationMenu::GetRootMenuId($oMenu->GetMenuId())))
|
|
||||||
{
|
|
||||||
$sDefaultDashboard = $oMenu->GetMenuId();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
asort($aAllowedDashboards);
|
|
||||||
|
foreach ($aAllMenus as $idx => $aMenu) {
|
||||||
$oField = new DesignerComboField('menu_id', Dict::S('UI:DashletCreation:Dashboard'), $sDefaultDashboard);
|
$oMenu = $aMenu['node'];
|
||||||
$oField->SetAllowedValues($aAllowedDashboards);
|
if ($oMenu instanceof DashboardMenuNode) {
|
||||||
$oField->SetMandatory(true);
|
// Get the root parent for access check
|
||||||
$oForm->AddField($oField);
|
$sParentId = $aMenu['parent'];
|
||||||
|
$aParentMenu = $aParentMenus[$sParentId];
|
||||||
// Get the list of possible dashlets that support a creation from
|
while (isset($aParentMenus[$aParentMenu['parent']])) {
|
||||||
// an OQL
|
// grand parent exists
|
||||||
$aDashlets = array();
|
$sParentId = $aParentMenu['parent'];
|
||||||
foreach(get_declared_classes() as $sDashletClass)
|
$aParentMenu = $aParentMenus[$sParentId];
|
||||||
{
|
}
|
||||||
if (is_subclass_of($sDashletClass, 'Dashlet'))
|
/** @var \MenuNode $oParentMenu */
|
||||||
{
|
$oParentMenu = $aParentMenu['node'];
|
||||||
$oReflection = new ReflectionClass($sDashletClass);
|
if ($oMenu->IsEnabled() && $oParentMenu->IsEnabled()) {
|
||||||
if (!$oReflection->isAbstract())
|
$sMenuLabel = $oMenu->GetTitle();
|
||||||
{
|
$sParentLabel = Dict::S('Menu:'.$sParentId);
|
||||||
$aCallSpec = array($sDashletClass, 'CanCreateFromOQL');
|
if ($sParentLabel != $sMenuLabel) {
|
||||||
$bShorcutMode = call_user_func($aCallSpec);
|
$aAllowedDashboards[$oMenu->GetMenuId()] = $sParentLabel.' - '.$sMenuLabel;
|
||||||
if ($bShorcutMode)
|
} else {
|
||||||
{
|
$aAllowedDashboards[$oMenu->GetMenuId()] = $sMenuLabel;
|
||||||
$aCallSpec = array($sDashletClass, 'GetInfo');
|
}
|
||||||
$aInfo = call_user_func($aCallSpec);
|
if (empty($sDefaultDashboard) && ($sRootMenuId == ApplicationMenu::GetRootMenuId($oMenu->GetMenuId()))) {
|
||||||
$aDashlets[$sDashletClass] = array('label' => $aInfo['label'], 'class' => $sDashletClass, 'icon' => $aInfo['icon']);
|
$sDefaultDashboard = $oMenu->GetMenuId();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
asort($aAllowedDashboards);
|
||||||
|
|
||||||
|
$oField = new DesignerComboField('menu_id', Dict::S('UI:DashletCreation:Dashboard'), $sDefaultDashboard);
|
||||||
|
$oField->SetAllowedValues($aAllowedDashboards);
|
||||||
|
$oField->SetMandatory(true);
|
||||||
|
$oForm->AddField($oField);
|
||||||
|
|
||||||
|
// Get the list of possible dashlets that support a creation from
|
||||||
|
// an OQL
|
||||||
|
$aDashlets = [];
|
||||||
|
foreach (get_declared_classes() as $sDashletClass) {
|
||||||
|
if (is_subclass_of($sDashletClass, 'Dashlet')) {
|
||||||
|
$oReflection = new ReflectionClass($sDashletClass);
|
||||||
|
if (!$oReflection->isAbstract()) {
|
||||||
|
$aCallSpec = [$sDashletClass, 'CanCreateFromOQL'];
|
||||||
|
$bShorcutMode = call_user_func($aCallSpec);
|
||||||
|
if ($bShorcutMode) {
|
||||||
|
$aCallSpec = [$sDashletClass, 'GetInfo'];
|
||||||
|
$aInfo = call_user_func($aCallSpec);
|
||||||
|
$aDashlets[$sDashletClass] = ['label' => $aInfo['label'], 'class' => $sDashletClass, 'icon' => $aInfo['icon']];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
$oSelectorField = new DesignerFormSelectorField('dashlet_class', Dict::S('UI:DashletCreation:DashletType'), '');
|
$oSelectorField = new DesignerFormSelectorField('dashlet_class', Dict::S('UI:DashletCreation:DashletType'), '');
|
||||||
$oForm->AddField($oSelectorField);
|
$oForm->AddField($oSelectorField);
|
||||||
foreach($aDashlets as $sDashletClass => $aDashletInfo)
|
foreach ($aDashlets as $sDashletClass => $aDashletInfo) {
|
||||||
{
|
|
||||||
$oSubForm = new DesignerForm();
|
$oSubForm = new DesignerForm();
|
||||||
$oMetaModel = new ModelReflectionRuntime();
|
$oMetaModel = new ModelReflectionRuntime();
|
||||||
/** @var \Dashlet $oDashlet */
|
/** @var \Dashlet $oDashlet */
|
||||||
$oDashlet = new $sDashletClass($oMetaModel, 0);
|
$oDashlet = new $sDashletClass($oMetaModel, 0);
|
||||||
$oDashlet->GetPropertiesFieldsFromOQL($oSubForm, $sOQL);
|
$oDashlet->GetPropertiesFieldsFromOQL($oSubForm, $sOQL);
|
||||||
|
|
||||||
$oSelectorField->AddSubForm($oSubForm, $aDashletInfo['label'], $aDashletInfo['class']);
|
$oSelectorField->AddSubForm($oSubForm, $aDashletInfo['label'], $aDashletInfo['class']);
|
||||||
}
|
}
|
||||||
$oField = new DesignerBooleanField('open_editor', Dict::S('UI:DashletCreation:EditNow'), true);
|
$oField = new DesignerBooleanField('open_editor', Dict::S('UI:DashletCreation:EditNow'), true);
|
||||||
$oForm->AddField($oField);
|
$oForm->AddField($oField);
|
||||||
|
|
||||||
return $oForm;
|
return $oForm;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1501,11 +1443,11 @@ JS
|
|||||||
|
|
||||||
$oForm->Render($oPage);
|
$oForm->Render($oPage);
|
||||||
$oPage->add('</div>');
|
$oPage->add('</div>');
|
||||||
|
|
||||||
$sDialogTitle = Dict::S('UI:DashletCreation:Title');
|
$sDialogTitle = Dict::S('UI:DashletCreation:Title');
|
||||||
$sOkButtonLabel = Dict::S('UI:Button:Ok');
|
$sOkButtonLabel = Dict::S('UI:Button:Ok');
|
||||||
$sCancelButtonLabel = Dict::S('UI:Button:Cancel');
|
$sCancelButtonLabel = Dict::S('UI:Button:Cancel');
|
||||||
|
|
||||||
$oPage->add_ready_script(
|
$oPage->add_ready_script(
|
||||||
<<<JS
|
<<<JS
|
||||||
$('#dashlet_creation_dlg').dialog({
|
$('#dashlet_creation_dlg').dialog({
|
||||||
@@ -1603,7 +1545,7 @@ JS
|
|||||||
/**
|
/**
|
||||||
* @inheritDoc
|
* @inheritDoc
|
||||||
*/
|
*/
|
||||||
protected function PrepareDashletForRendering(Dashlet $oDashlet, $aCoordinates, $aExtraParams = array())
|
protected function PrepareDashletForRendering(Dashlet $oDashlet, $aCoordinates, $aExtraParams = [])
|
||||||
{
|
{
|
||||||
$sDashletIdOrig = $oDashlet->GetID();
|
$sDashletIdOrig = $oDashlet->GetID();
|
||||||
$sDashboardSanitizedId = $this->GetSanitizedId();
|
$sDashboardSanitizedId = $this->GetSanitizedId();
|
||||||
@@ -1630,31 +1572,27 @@ JS
|
|||||||
private function UpdateDashletUserPrefs(Dashlet $oDashlet, $sDashletIdOrig, array $aExtraParams)
|
private function UpdateDashletUserPrefs(Dashlet $oDashlet, $sDashletIdOrig, array $aExtraParams)
|
||||||
{
|
{
|
||||||
$bIsDashletWithListPref = ($oDashlet instanceof DashletObjectList);
|
$bIsDashletWithListPref = ($oDashlet instanceof DashletObjectList);
|
||||||
if (!$bIsDashletWithListPref)
|
if (!$bIsDashletWithListPref) {
|
||||||
{
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
/** @var \DashletObjectList $oDashlet */
|
/** @var \DashletObjectList $oDashlet */
|
||||||
|
|
||||||
$bDashletIdInNewFormat = ($sDashletIdOrig === $oDashlet->GetID());
|
$bDashletIdInNewFormat = ($sDashletIdOrig === $oDashlet->GetID());
|
||||||
if ($bDashletIdInNewFormat)
|
if ($bDashletIdInNewFormat) {
|
||||||
{
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
$sNewPrefKey = $this->GetDashletObjectListAppUserPreferencesPrefix($oDashlet, $aExtraParams, $oDashlet->GetID());
|
$sNewPrefKey = $this->GetDashletObjectListAppUserPreferencesPrefix($oDashlet, $aExtraParams, $oDashlet->GetID());
|
||||||
$sPrefValueForNewKey = appUserPreferences::GetPref($sNewPrefKey, null);
|
$sPrefValueForNewKey = appUserPreferences::GetPref($sNewPrefKey, null);
|
||||||
$bHasPrefInNewFormat = ($sPrefValueForNewKey !== null);
|
$bHasPrefInNewFormat = ($sPrefValueForNewKey !== null);
|
||||||
if ($bHasPrefInNewFormat)
|
if ($bHasPrefInNewFormat) {
|
||||||
{
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
$sOldPrefKey = $this->GetDashletObjectListAppUserPreferencesPrefix($oDashlet, $aExtraParams, $sDashletIdOrig);
|
$sOldPrefKey = $this->GetDashletObjectListAppUserPreferencesPrefix($oDashlet, $aExtraParams, $sDashletIdOrig);
|
||||||
$sPrefValueForOldKey = appUserPreferences::GetPref($sOldPrefKey, null);
|
$sPrefValueForOldKey = appUserPreferences::GetPref($sOldPrefKey, null);
|
||||||
$bHasPrefInOldFormat = ($sPrefValueForOldKey !== null);
|
$bHasPrefInOldFormat = ($sPrefValueForOldKey !== null);
|
||||||
if (!$bHasPrefInOldFormat)
|
if (!$bHasPrefInOldFormat) {
|
||||||
{
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1673,7 +1611,7 @@ JS
|
|||||||
private function GetDashletObjectListAppUserPreferencesPrefix(DashletObjectList $oDashlet, $aExtraParams, $sDashletId)
|
private function GetDashletObjectListAppUserPreferencesPrefix(DashletObjectList $oDashlet, $aExtraParams, $sDashletId)
|
||||||
{
|
{
|
||||||
$sDataTableId = Dashlet::APPUSERPREFERENCES_PREFIX.$sDashletId;
|
$sDataTableId = Dashlet::APPUSERPREFERENCES_PREFIX.$sDashletId;
|
||||||
$aClassAliases = array();
|
$aClassAliases = [];
|
||||||
try {
|
try {
|
||||||
$oFilter = $oDashlet->GetDBSearch($aExtraParams);
|
$oFilter = $oDashlet->GetDBSearch($aExtraParams);
|
||||||
$aClassAliases = $oFilter->GetSelectedClasses();
|
$aClassAliases = $oFilter->GetSelectedClasses();
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
// Copyright (C) 2010-2024 Combodo SAS
|
// Copyright (C) 2010-2024 Combodo SAS
|
||||||
//
|
//
|
||||||
// This file is part of iTop.
|
// 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
|
// 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
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
// (at your option) any later version.
|
// (at your option) any later version.
|
||||||
@@ -38,21 +39,21 @@ abstract class DashboardLayout
|
|||||||
* @since 2.7.0
|
* @since 2.7.0
|
||||||
*/
|
*/
|
||||||
abstract public function GetDashletCoordinates($iCellIdx);
|
abstract public function GetDashletCoordinates($iCellIdx);
|
||||||
|
|
||||||
public static function GetInfo()
|
public static function GetInfo()
|
||||||
{
|
{
|
||||||
return array(
|
return [
|
||||||
'label' => '',
|
'label' => '',
|
||||||
'icon' => '',
|
'icon' => '',
|
||||||
'description' => '',
|
'description' => '',
|
||||||
);
|
];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
abstract class DashboardLayoutMultiCol extends DashboardLayout
|
abstract class DashboardLayoutMultiCol extends DashboardLayout
|
||||||
{
|
{
|
||||||
protected $iNbCols;
|
protected $iNbCols;
|
||||||
|
|
||||||
public function __construct()
|
public function __construct()
|
||||||
{
|
{
|
||||||
$this->iNbCols = 1;
|
$this->iNbCols = 1;
|
||||||
@@ -63,47 +64,38 @@ abstract class DashboardLayoutMultiCol extends DashboardLayout
|
|||||||
$aKeys = array_reverse(array_keys($aDashlets));
|
$aKeys = array_reverse(array_keys($aDashlets));
|
||||||
$idx = 0;
|
$idx = 0;
|
||||||
$bNoVisibleFound = true;
|
$bNoVisibleFound = true;
|
||||||
while($idx < count($aKeys) && $bNoVisibleFound)
|
while ($idx < count($aKeys) && $bNoVisibleFound) {
|
||||||
{
|
|
||||||
/** @var \Dashlet $oDashlet */
|
/** @var \Dashlet $oDashlet */
|
||||||
$oDashlet = $aDashlets[$aKeys[$idx]];
|
$oDashlet = $aDashlets[$aKeys[$idx]];
|
||||||
if ($oDashlet::IsVisible())
|
if ($oDashlet::IsVisible()) {
|
||||||
{
|
|
||||||
$bNoVisibleFound = false;
|
$bNoVisibleFound = false;
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
unset($aDashlets[$aKeys[$idx]]);
|
unset($aDashlets[$aKeys[$idx]]);
|
||||||
}
|
}
|
||||||
$idx++;
|
$idx++;
|
||||||
}
|
}
|
||||||
return $aDashlets;
|
return $aDashlets;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function TrimCellsArray($aCells)
|
protected function TrimCellsArray($aCells)
|
||||||
{
|
{
|
||||||
foreach($aCells as $key => $aDashlets)
|
foreach ($aCells as $key => $aDashlets) {
|
||||||
{
|
|
||||||
$aCells[$key] = $this->TrimCell($aDashlets);
|
$aCells[$key] = $this->TrimCell($aDashlets);
|
||||||
}
|
}
|
||||||
$aKeys = array_reverse(array_keys($aCells));
|
$aKeys = array_reverse(array_keys($aCells));
|
||||||
$idx = 0;
|
$idx = 0;
|
||||||
$bNoVisibleFound = true;
|
$bNoVisibleFound = true;
|
||||||
while($idx < count($aKeys) && $bNoVisibleFound)
|
while ($idx < count($aKeys) && $bNoVisibleFound) {
|
||||||
{
|
|
||||||
$aDashlets = $aCells[$aKeys[$idx]];
|
$aDashlets = $aCells[$aKeys[$idx]];
|
||||||
if (count($aDashlets) > 0)
|
if (count($aDashlets) > 0) {
|
||||||
{
|
|
||||||
$bNoVisibleFound = false;
|
$bNoVisibleFound = false;
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
unset($aCells[$aKeys[$idx]]);
|
unset($aCells[$aKeys[$idx]]);
|
||||||
}
|
}
|
||||||
$idx++;
|
$idx++;
|
||||||
}
|
}
|
||||||
return $aCells;
|
return $aCells;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -112,7 +104,7 @@ abstract class DashboardLayoutMultiCol extends DashboardLayout
|
|||||||
* @param bool $bEditMode
|
* @param bool $bEditMode
|
||||||
* @param array $aExtraParams
|
* @param array $aExtraParams
|
||||||
*/
|
*/
|
||||||
public function Render($oPage, $aCells, $bEditMode = false, $aExtraParams = array())
|
public function Render($oPage, $aCells, $bEditMode = false, $aExtraParams = [])
|
||||||
{
|
{
|
||||||
// Trim the list of cells to remove the invisible/empty ones at the end of the array
|
// Trim the list of cells to remove the invisible/empty ones at the end of the array
|
||||||
$aCells = $this->TrimCellsArray($aCells);
|
$aCells = $this->TrimCellsArray($aCells);
|
||||||
@@ -157,8 +149,7 @@ abstract class DashboardLayoutMultiCol extends DashboardLayout
|
|||||||
|
|
||||||
$oPage->add_script("function updateDashboard".$aExtraParams['dashboard_div_id']."(){".$sJSReload."}");
|
$oPage->add_script("function updateDashboard".$aExtraParams['dashboard_div_id']."(){".$sJSReload."}");
|
||||||
|
|
||||||
if ($bEditMode) // Add one row for extensibility
|
if ($bEditMode) { // Add one row for extensibility
|
||||||
{
|
|
||||||
$oDashboardRow = new DashboardRow();
|
$oDashboardRow = new DashboardRow();
|
||||||
$oDashboardLayout->AddDashboardRow($oDashboardRow);
|
$oDashboardLayout->AddDashboardRow($oDashboardRow);
|
||||||
|
|
||||||
@@ -180,7 +171,7 @@ abstract class DashboardLayoutMultiCol extends DashboardLayout
|
|||||||
$iColNumber = (int) $iCellIdx % $this->iNbCols;
|
$iColNumber = (int) $iCellIdx % $this->iNbCols;
|
||||||
$iRowNumber = (int) floor($iCellIdx / $this->iNbCols);
|
$iRowNumber = (int) floor($iCellIdx / $this->iNbCols);
|
||||||
|
|
||||||
return array($iColNumber, $iRowNumber);
|
return [$iColNumber, $iRowNumber];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -191,13 +182,13 @@ class DashboardLayoutOneCol extends DashboardLayoutMultiCol
|
|||||||
parent::__construct();
|
parent::__construct();
|
||||||
$this->iNbCols = 1;
|
$this->iNbCols = 1;
|
||||||
}
|
}
|
||||||
static public function GetInfo()
|
public static function GetInfo()
|
||||||
{
|
{
|
||||||
return array(
|
return [
|
||||||
'label' => 'One Column',
|
'label' => 'One Column',
|
||||||
'icon' => 'images/layout_1col.png',
|
'icon' => 'images/layout_1col.png',
|
||||||
'description' => '',
|
'description' => '',
|
||||||
);
|
];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -208,13 +199,13 @@ class DashboardLayoutTwoCols extends DashboardLayoutMultiCol
|
|||||||
parent::__construct();
|
parent::__construct();
|
||||||
$this->iNbCols = 2;
|
$this->iNbCols = 2;
|
||||||
}
|
}
|
||||||
static public function GetInfo()
|
public static function GetInfo()
|
||||||
{
|
{
|
||||||
return array(
|
return [
|
||||||
'label' => 'Two Columns',
|
'label' => 'Two Columns',
|
||||||
'icon' => 'images/layout_2col.png',
|
'icon' => 'images/layout_2col.png',
|
||||||
'description' => '',
|
'description' => '',
|
||||||
);
|
];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -225,12 +216,12 @@ class DashboardLayoutThreeCols extends DashboardLayoutMultiCol
|
|||||||
parent::__construct();
|
parent::__construct();
|
||||||
$this->iNbCols = 3;
|
$this->iNbCols = 3;
|
||||||
}
|
}
|
||||||
static public function GetInfo()
|
public static function GetInfo()
|
||||||
{
|
{
|
||||||
return array(
|
return [
|
||||||
'label' => 'Two Columns',
|
'label' => 'Two Columns',
|
||||||
'icon' => 'images/layout_3col.png',
|
'icon' => 'images/layout_3col.png',
|
||||||
'description' => '',
|
'description' => '',
|
||||||
);
|
];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -1,10 +1,12 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<itop_design xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="3.2">
|
<itop_design xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:noNamespaceSchemaLocation="https://www.combodo.com/itop-schema/3.3"
|
||||||
|
version="3.3">
|
||||||
<classes>
|
<classes>
|
||||||
<class id="AbstractResource" _delta="define">
|
<class id="AbstractResource" _delta="define">
|
||||||
<parent>cmdbAbstractObject</parent>
|
<parent>cmdbAbstractObject</parent>
|
||||||
<properties>
|
<properties>
|
||||||
<comment>/* Resource access control abstraction. Can be herited by abstract resource access control classes. Generaly controlled using UR_ACTION_MODIFY access right. */</comment>
|
<comment>/* Resource access control abstraction. Can be herited by abstract resource access control classes. Generally controlled using UR_ACTION_MODIFY access right. */</comment>
|
||||||
<abstract>true</abstract>
|
<abstract>true</abstract>
|
||||||
</properties>
|
</properties>
|
||||||
<presentation/>
|
<presentation/>
|
||||||
@@ -45,7 +47,7 @@
|
|||||||
<properties>
|
<properties>
|
||||||
<comment>/** Acknowledge welcome popup messages */</comment>
|
<comment>/** Acknowledge welcome popup messages */</comment>
|
||||||
<abstract>false</abstract>
|
<abstract>false</abstract>
|
||||||
<category></category>
|
<category/>
|
||||||
<key_type>autoincrement</key_type>
|
<key_type>autoincrement</key_type>
|
||||||
<db_table>priv_welcome_popup_acknowledge</db_table>
|
<db_table>priv_welcome_popup_acknowledge</db_table>
|
||||||
</properties>
|
</properties>
|
||||||
@@ -111,7 +113,6 @@
|
|||||||
<menu id="UserManagement" xsi:type="TemplateMenuNode" _delta="define">
|
<menu id="UserManagement" xsi:type="TemplateMenuNode" _delta="define">
|
||||||
<rank>10</rank>
|
<rank>10</rank>
|
||||||
<parent>AdminTools</parent>
|
<parent>AdminTools</parent>
|
||||||
<template_file/>
|
|
||||||
</menu>
|
</menu>
|
||||||
<menu id="UserAccountsMenu" xsi:type="OQLMenuNode" _delta="define">
|
<menu id="UserAccountsMenu" xsi:type="OQLMenuNode" _delta="define">
|
||||||
<rank>11</rank>
|
<rank>11</rank>
|
||||||
@@ -141,7 +142,6 @@
|
|||||||
<menu id="Queries" xsi:type="TemplateMenuNode" _delta="define">
|
<menu id="Queries" xsi:type="TemplateMenuNode" _delta="define">
|
||||||
<rank>30</rank>
|
<rank>30</rank>
|
||||||
<parent>AdminTools</parent>
|
<parent>AdminTools</parent>
|
||||||
<template_file/>
|
|
||||||
</menu>
|
</menu>
|
||||||
<menu id="RunQueriesMenu" xsi:type="WebPageMenuNode" _delta="define">
|
<menu id="RunQueriesMenu" xsi:type="WebPageMenuNode" _delta="define">
|
||||||
<rank>31</rank>
|
<rank>31</rank>
|
||||||
@@ -188,7 +188,6 @@
|
|||||||
<menu id="Integrations" xsi:type="TemplateMenuNode" _delta="define">
|
<menu id="Integrations" xsi:type="TemplateMenuNode" _delta="define">
|
||||||
<rank>50</rank>
|
<rank>50</rank>
|
||||||
<parent>ConfigurationTools</parent>
|
<parent>ConfigurationTools</parent>
|
||||||
<template_file/>
|
|
||||||
</menu>
|
</menu>
|
||||||
<menu id="DataSources" xsi:type="OQLMenuNode" _delta="define">
|
<menu id="DataSources" xsi:type="OQLMenuNode" _delta="define">
|
||||||
<rank>20</rank>
|
<rank>20</rank>
|
||||||
@@ -555,7 +554,7 @@ Call $this->AddInitialAttributeFlags($sAttCode, $iFlags) for all the initial att
|
|||||||
<description><![CDATA[Inform the listeners about the connection states]]></description>
|
<description><![CDATA[Inform the listeners about the connection states]]></description>
|
||||||
<event_data>
|
<event_data>
|
||||||
<event_datum id="code">
|
<event_datum id="code">
|
||||||
<description>The login step result code (LoginWebPage::EXIT_CODE_...) </description>
|
<description>The login step result code (LoginWebPage::EXIT_CODE_...)</description>
|
||||||
<type>integer</type>
|
<type>integer</type>
|
||||||
</event_datum>
|
</event_datum>
|
||||||
<event_datum id="state">
|
<event_datum id="state">
|
||||||
@@ -852,5 +851,168 @@ Call $this->AddInitialAttributeFlags($sAttCode, $iFlags) for all the initial att
|
|||||||
</methods>
|
</methods>
|
||||||
</class>
|
</class>
|
||||||
</classes>
|
</classes>
|
||||||
|
<property_types _delta="define">
|
||||||
|
<property_type id="Dashlet" xsi:type="Combodo-AbstractPropertyType"/>
|
||||||
|
<property_type id="DashletGroupBy" xsi:type="Combodo-PropertyType">
|
||||||
|
<extends>Dashlet</extends>
|
||||||
|
<definition xsi:type="Combodo-ValueType-PropertyTree">
|
||||||
|
<label>UI:DashletGroupBy:Title</label>
|
||||||
|
<nodes>
|
||||||
|
<node id="title" xsi:type="Combodo-ValueType-Label">
|
||||||
|
<label>UI:DashletGroupBy:Prop-Title</label>
|
||||||
|
</node>
|
||||||
|
<node id="query" xsi:type="Combodo-ValueType-OQL">
|
||||||
|
<label>UI:DashletGroupBy:Prop-Query</label>
|
||||||
|
</node>
|
||||||
|
<node id="group_by" xsi:type="Combodo-ValueType-ClassAttributeGroupBy">
|
||||||
|
<label>UI:DashletGroupBy:Prop-GroupBy</label>
|
||||||
|
<class>{{query.selected_class}}</class>
|
||||||
|
</node>
|
||||||
|
<node id="style" xsi:type="Combodo-ValueType-Choice"> <!-- Possible de le cacher, etc celui-ci nous met dedans -->
|
||||||
|
<label>UI:DashletGroupBy:Prop-Style</label>
|
||||||
|
<values>
|
||||||
|
<value id="bars">
|
||||||
|
<label>UI:DashletGroupByBars:Label</label>
|
||||||
|
</value>
|
||||||
|
<value id="pie">
|
||||||
|
<label>UI:DashletGroupByPie:Label</label>
|
||||||
|
</value>
|
||||||
|
<value id="table">
|
||||||
|
<label>UI:DashletGroupByTable:Label</label>
|
||||||
|
</value>
|
||||||
|
</values>
|
||||||
|
</node>
|
||||||
|
<node id="aggregation_function" xsi:type="Combodo-ValueType-AggregateFunction">
|
||||||
|
<label>UI:DashletGroupBy:Prop-Function</label>
|
||||||
|
<class>{{query.selected_class}}</class> <!-- pour savoir si il y a des attributs additionnables -->
|
||||||
|
</node>
|
||||||
|
<node id="aggregation_attribute" xsi:type="Combodo-ValueType-ClassAttribute">
|
||||||
|
<label>UI:DashletGroupBy:Prop-FunctionAttribute</label>
|
||||||
|
<relevance-condition>{{aggregation_function.value != 'count'}}</relevance-condition>
|
||||||
|
<class>{{query.selected_class}}</class>
|
||||||
|
<category>numeric</category>
|
||||||
|
</node>
|
||||||
|
<node id="order_by" xsi:type="Combodo-ValueType-ChoiceFromInput">
|
||||||
|
<label>UI:DashletGroupBy:Prop-OrderField</label>
|
||||||
|
<values>
|
||||||
|
<value id="attribute">
|
||||||
|
<label>{{aggregation_attribute.label}}</label>
|
||||||
|
</value>
|
||||||
|
<value id="function">
|
||||||
|
<label>{{aggregation_function.label}}</label>
|
||||||
|
</value>
|
||||||
|
</values>
|
||||||
|
</node>
|
||||||
|
<node id="limit" xsi:type="Combodo-ValueType-Integer">
|
||||||
|
<label>UI:DashletGroupBy:Prop-Limit</label>
|
||||||
|
<relevance-condition>{{order_by.value = 'function'}}</relevance-condition>
|
||||||
|
</node>
|
||||||
|
<node id="order_direction" xsi:type="Combodo-ValueType-Choice">
|
||||||
|
<label>UI:DashletGroupBy:Prop-OrderDirection</label>
|
||||||
|
<values>
|
||||||
|
<value id="asc">
|
||||||
|
<label>UI:DashletGroupBy:Order:asc</label>
|
||||||
|
</value>
|
||||||
|
<value id="desc">
|
||||||
|
<label>UI:DashletGroupBy:Order:desc</label>
|
||||||
|
</value>
|
||||||
|
</values>
|
||||||
|
</node>
|
||||||
|
</nodes>
|
||||||
|
</definition>
|
||||||
|
</property_type>
|
||||||
|
<property_type id="DashletBadge" xsi:type="Combodo-PropertyType">
|
||||||
|
<extends>Dashlet</extends>
|
||||||
|
<definition xsi:type="Combodo-ValueType-PropertyTree">
|
||||||
|
<nodes>
|
||||||
|
<node id="class" xsi:type="Combodo-ValueType-Class">
|
||||||
|
<label>UI:DashletBadge:Prop-Class</label>
|
||||||
|
<categories-csv>bizmodel</categories-csv>
|
||||||
|
</node>
|
||||||
|
</nodes>
|
||||||
|
</definition>
|
||||||
|
</property_type>
|
||||||
|
<property_type id="DashletHeaderDynamic" xsi:type="Combodo-PropertyType">
|
||||||
|
<extends>Dashlet</extends>
|
||||||
|
<definition xsi:type="Combodo-ValueType-PropertyTree">
|
||||||
|
<label>UI:DashletHeaderDynamic:Title</label>
|
||||||
|
<nodes>
|
||||||
|
<node id="title" xsi:type="Combodo-ValueType-Label">
|
||||||
|
<label>UI:DashletHeaderDynamic:Prop-Title</label>
|
||||||
|
</node>
|
||||||
|
<node id="icon" xsi:type="Combodo-ValueType-Icon">
|
||||||
|
<label>UI:DashletHeaderDynamic:Prop-Icon</label>
|
||||||
|
</node>
|
||||||
|
<node id="subtitle" xsi:type="Combodo-ValueType-Label">
|
||||||
|
<label>UI:DashletHeaderDynamic:Prop-Subtitle</label>
|
||||||
|
</node>
|
||||||
|
<node id="query" xsi:type="Combodo-ValueType-OQL">
|
||||||
|
<label>UI:DashletHeaderDynamic:Prop-Query</label>
|
||||||
|
</node>
|
||||||
|
<node id="group_by" xsi:type="Combodo-ValueType-ClassAttribute">
|
||||||
|
<label>UI:DashletHeaderDynamic:Prop-GroupBy</label>
|
||||||
|
<class>{{query.selected_class}}</class>
|
||||||
|
<category>enum</category>
|
||||||
|
</node>
|
||||||
|
<node id="values" xsi:type="Combodo-ValueType-CollectionOfValues">
|
||||||
|
<label>UI:DashletHeaderDynamic:Prop-Values</label>
|
||||||
|
<xml-format xsi:type="Combodo-XMLFormat-CSV"/>
|
||||||
|
<value-type xsi:type="Combodo-ValueType-ClassAttributeValue">
|
||||||
|
<class>{{query.selected_class}}</class>
|
||||||
|
<attribute>{{group_by.attribute}}</attribute>
|
||||||
|
</value-type>
|
||||||
|
</node>
|
||||||
|
</nodes>
|
||||||
|
</definition>
|
||||||
|
</property_type>
|
||||||
|
<property_type id="DashletHeaderStatic" xsi:type="Combodo-PropertyType">
|
||||||
|
<extends>Dashlet</extends>
|
||||||
|
<definition xsi:type="Combodo-ValueType-PropertyTree">
|
||||||
|
<nodes>
|
||||||
|
<node id="title" xsi:type="Combodo-ValueType-Label">
|
||||||
|
<label>UI:DashletHeaderStatic:Prop-Title</label>
|
||||||
|
</node>
|
||||||
|
<node id="icon" xsi:type="Combodo-ValueType-Icon">
|
||||||
|
<label>UI:DashletHeaderStatic:Prop-Icon</label>
|
||||||
|
</node>
|
||||||
|
</nodes>
|
||||||
|
</definition>
|
||||||
|
</property_type>
|
||||||
|
<property_type id="DashletObjectList" xsi:type="Combodo-PropertyType">
|
||||||
|
<extends>Dashlet</extends>
|
||||||
|
<definition xsi:type="Combodo-ValueType-PropertyTree">
|
||||||
|
<nodes>
|
||||||
|
<node id="title" xsi:type="Combodo-ValueType-Label">
|
||||||
|
<label>UI:DashletObjectList:Prop-Title</label>
|
||||||
|
</node>
|
||||||
|
<node id="query" xsi:type="Combodo-ValueType-OQL">
|
||||||
|
<label>UI:DashletObjectList:Prop-Query</label>
|
||||||
|
</node>
|
||||||
|
<node id="menu" xsi:type="Combodo-ValueType-Boolean">
|
||||||
|
<label>UI:DashletObjectList:Prop-Menu</label>
|
||||||
|
<on>
|
||||||
|
<!-- not so cute, but matches exactly 3.2 implementation of boolean fields -->
|
||||||
|
<label>UI:UserManagement:ActionAllowed:Yes</label>
|
||||||
|
<value>true</value>
|
||||||
|
</on>
|
||||||
|
<off>
|
||||||
|
<label>UI:UserManagement:ActionAllowed:No</label>
|
||||||
|
<value>false</value>
|
||||||
|
</off>
|
||||||
|
</node>
|
||||||
|
</nodes>
|
||||||
|
</definition>
|
||||||
|
</property_type>
|
||||||
|
<property_type id="DashletPlainText" xsi:type="Combodo-PropertyType">
|
||||||
|
<extends>Dashlet</extends>
|
||||||
|
<definition xsi:type="Combodo-ValueType-PropertyTree">
|
||||||
|
<nodes>
|
||||||
|
<node id="text" xsi:type="Combodo-ValueType-Text">
|
||||||
|
<label>UI:DashletPlainText:Prop-Text</label>
|
||||||
|
</node>
|
||||||
|
</nodes>
|
||||||
|
</definition>
|
||||||
|
</property_type>
|
||||||
|
</property_types>
|
||||||
</meta>
|
</meta>
|
||||||
</itop_design>
|
</itop_design>
|
||||||
|
|||||||
@@ -1,880 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
use Combodo\iTop\Application\UI\Base\Component\DataTable\DataTableSettings;
|
|
||||||
use Combodo\iTop\Application\WebPage\WebPage;
|
|
||||||
use Combodo\iTop\Renderer\Console\ConsoleBlockRenderer;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Copyright (C) 2013-2024 Combodo SAS
|
|
||||||
*
|
|
||||||
* 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
|
|
||||||
*
|
|
||||||
* @deprecated 3.0.0 use Combodo\iTop\Application\UI\Base\Component\DataTable\Datatable
|
|
||||||
*/
|
|
||||||
|
|
||||||
class DataTable
|
|
||||||
{
|
|
||||||
protected $iListId; // Unique ID inside the web page
|
|
||||||
/** @var string */
|
|
||||||
private $sDatatableContainerId;
|
|
||||||
protected $sTableId; // identifier for saving the settings (combined with the class aliases)
|
|
||||||
protected $oSet; // The set of objects to display
|
|
||||||
protected $aClassAliases; // The aliases (alias => class) inside the set
|
|
||||||
protected $iNbObjects; // Total number of objects in the set
|
|
||||||
protected $bUseCustomSettings; // Whether or not the current display uses custom settings
|
|
||||||
protected $oDefaultSettings; // the default settings for displaying such a list
|
|
||||||
protected $bShowObsoleteData;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param string $iListId Unique ID for this div/table in the page
|
|
||||||
* @param DBObjectSet $oSet The set of data to display
|
|
||||||
* @param array$aClassAliases The list of classes/aliases to be displayed in this set $sAlias => $sClassName
|
|
||||||
* @param string $sTableId A string (or null) identifying this table in order to persist its settings
|
|
||||||
*
|
|
||||||
* @throws \CoreException
|
|
||||||
* @throws \MissingQueryArgument
|
|
||||||
* @throws \MySQLException
|
|
||||||
* @throws \MySQLHasGoneAwayException
|
|
||||||
*/
|
|
||||||
public function __construct($iListId, $oSet, $aClassAliases, $sTableId = null)
|
|
||||||
{
|
|
||||||
DeprecatedCallsLog::NotifyDeprecatedPhpMethod('use Combodo\iTop\Application\UI\Base\Component\DataTable\Datatable');
|
|
||||||
$this->iListId = utils::GetSafeId($iListId); // Make a "safe" ID for jQuery
|
|
||||||
$this->sDatatableContainerId = 'datatable_'.utils::GetSafeId($iListId);
|
|
||||||
$this->oSet = $oSet;
|
|
||||||
$this->aClassAliases = $aClassAliases;
|
|
||||||
$this->sTableId = $sTableId;
|
|
||||||
$this->iNbObjects = $oSet->Count();
|
|
||||||
$this->bUseCustomSettings = false;
|
|
||||||
$this->oDefaultSettings = null;
|
|
||||||
$this->bShowObsoleteData = $oSet->GetShowObsoleteData();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param WebPage $oPage
|
|
||||||
* @param DataTableSettings $oSettings
|
|
||||||
* @param $bActionsMenu
|
|
||||||
* @param $sSelectMode
|
|
||||||
* @param $bViewLink
|
|
||||||
* @param $aExtraParams
|
|
||||||
*
|
|
||||||
* @return string
|
|
||||||
* @throws \CoreException
|
|
||||||
* @throws \MySQLException
|
|
||||||
*/
|
|
||||||
public function Display(WebPage $oPage, DataTableSettings $oSettings, $bActionsMenu, $sSelectMode, $bViewLink, $aExtraParams)
|
|
||||||
{
|
|
||||||
$this->oDefaultSettings = $oSettings;
|
|
||||||
|
|
||||||
// Identified tables can have their own specific settings
|
|
||||||
$oCustomSettings = DataTableSettings::GetTableSettings($this->aClassAliases, $this->sTableId);
|
|
||||||
|
|
||||||
if ($oCustomSettings != null)
|
|
||||||
{
|
|
||||||
// Custom settings overload the default ones
|
|
||||||
$this->bUseCustomSettings = true;
|
|
||||||
if ($this->oDefaultSettings->iDefaultPageSize == 0)
|
|
||||||
{
|
|
||||||
$oCustomSettings->iDefaultPageSize = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
$oCustomSettings = $oSettings;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($oCustomSettings->iDefaultPageSize > 0)
|
|
||||||
{
|
|
||||||
$this->oSet->SetLimit($oCustomSettings->iDefaultPageSize);
|
|
||||||
}
|
|
||||||
$this->oSet->SetOrderBy($oCustomSettings->GetSortOrder());
|
|
||||||
|
|
||||||
// Load only the requested columns
|
|
||||||
$aColumnsToLoad = array();
|
|
||||||
foreach($oCustomSettings->aColumns as $sAlias => $aColumnsInfo)
|
|
||||||
{
|
|
||||||
foreach($aColumnsInfo as $sAttCode => $aData)
|
|
||||||
{
|
|
||||||
if ($sAttCode != '_key_')
|
|
||||||
{
|
|
||||||
if ($aData['checked'])
|
|
||||||
{
|
|
||||||
$aColumnsToLoad[$sAlias][] = $sAttCode;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// See if this column is a must to load
|
|
||||||
$sClass = $this->aClassAliases[$sAlias];
|
|
||||||
$oAttDef = MetaModel::GetAttributeDef($sClass, $sAttCode);
|
|
||||||
if ($oAttDef->AlwaysLoadInTables()) {
|
|
||||||
$aColumnsToLoad[$sAlias][] = $sAttCode;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
$this->oSet->OptimizeColumnLoad($aColumnsToLoad);
|
|
||||||
|
|
||||||
|
|
||||||
$bToolkitMenu = true;
|
|
||||||
if (isset($aExtraParams['toolkit_menu']))
|
|
||||||
{
|
|
||||||
$bToolkitMenu = (bool) $aExtraParams['toolkit_menu'];
|
|
||||||
}
|
|
||||||
if (UserRights::IsPortalUser())
|
|
||||||
{
|
|
||||||
// Portal users have a limited access to data, for now they can only see what's configured for them
|
|
||||||
$bToolkitMenu = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return $this->GetAsHTML($oPage, $oCustomSettings->iDefaultPageSize, $oCustomSettings->iDefaultPageSize, 0, $oCustomSettings->aColumns, $bActionsMenu, $bToolkitMenu, $sSelectMode, $bViewLink, $aExtraParams);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param WebPage $oPage
|
|
||||||
* @param $iPageSize
|
|
||||||
* @param $iDefaultPageSize
|
|
||||||
* @param $iPageIndex
|
|
||||||
* @param $aColumns
|
|
||||||
* @param $bActionsMenu
|
|
||||||
* @param $bToolkitMenu
|
|
||||||
* @param $sSelectMode
|
|
||||||
* @param $bViewLink
|
|
||||||
* @param $aExtraParams
|
|
||||||
*
|
|
||||||
* @return string
|
|
||||||
* @throws \ArchivedObjectException
|
|
||||||
* @throws \CoreException
|
|
||||||
*/
|
|
||||||
public function GetAsHTML(WebPage $oPage, $iPageSize, $iDefaultPageSize, $iPageIndex, $aColumns, $bActionsMenu, $bToolkitMenu, $sSelectMode, $bViewLink, $aExtraParams)
|
|
||||||
{
|
|
||||||
$sObjectsCount = $this->GetObjectCount($oPage, $sSelectMode);
|
|
||||||
$sPager = $this->GetPager($oPage, $iPageSize, $iDefaultPageSize, $iPageIndex);
|
|
||||||
$sActionsMenu = '';
|
|
||||||
$sToolkitMenu = '';
|
|
||||||
if ($bActionsMenu) {
|
|
||||||
$sActionsMenu = $this->GetActionsMenu($oPage, $aExtraParams);
|
|
||||||
}
|
|
||||||
// if ($bToolkitMenu)
|
|
||||||
// {
|
|
||||||
// $sToolkitMenu = $this->GetToolkitMenu($oPage, $aExtraParams);
|
|
||||||
// }
|
|
||||||
|
|
||||||
$sDataTable = $this->GetHTMLTable($oPage, $aColumns, $sSelectMode, $iPageSize, $bViewLink, $aExtraParams);
|
|
||||||
$sConfigDlg = $this->GetTableConfigDlg($oPage, $aColumns, $bViewLink, $iDefaultPageSize);
|
|
||||||
|
|
||||||
$sHtml = "<table id=\"{$this->sDatatableContainerId}\" class=\"datatable\">";
|
|
||||||
$sHtml .= "<tr><td>";
|
|
||||||
$sHtml .= "<table style=\"width:100%;\">";
|
|
||||||
$sHtml .= "<tr><td class=\"pagination_container\">$sObjectsCount</td><td class=\"menucontainer\">$sToolkitMenu $sActionsMenu</td></tr>";
|
|
||||||
$sHtml .= "<tr>$sPager</tr>";
|
|
||||||
$sHtml .= "</table>";
|
|
||||||
$sHtml .= "</td></tr>";
|
|
||||||
$sHtml .= "<tr><td class=\"datacontents\">$sDataTable</td></tr>";
|
|
||||||
$sHtml .= "</table>\n";
|
|
||||||
$oPage->add_at_the_end($sConfigDlg);
|
|
||||||
|
|
||||||
$aExtraParams['show_obsolete_data'] = $this->bShowObsoleteData;
|
|
||||||
|
|
||||||
$aOptions = array(
|
|
||||||
'sPersistentId' => '',
|
|
||||||
'sFilter' => $this->oSet->GetFilter()->serialize(),
|
|
||||||
'oColumns' => $aColumns,
|
|
||||||
'sSelectMode' => $sSelectMode,
|
|
||||||
'sViewLink' => ($bViewLink ? 'true' : 'false'),
|
|
||||||
'iNbObjects' => $this->iNbObjects,
|
|
||||||
'iDefaultPageSize' => $iDefaultPageSize,
|
|
||||||
'iPageSize' => $iPageSize,
|
|
||||||
'iPageIndex' => $iPageIndex,
|
|
||||||
'oClassAliases' => $this->aClassAliases,
|
|
||||||
'sTableId' => $this->sTableId,
|
|
||||||
'oExtraParams' => $aExtraParams,
|
|
||||||
'sRenderUrl' => utils::GetAbsoluteUrlAppRoot().'pages/ajax.render.php',
|
|
||||||
'oRenderParameters' => array('str' => ''), // Forces JSON to encode this as a object...
|
|
||||||
'oDefaultSettings' => array('str' => ''), // Forces JSON to encode this as a object...
|
|
||||||
'oLabels' => array('moveup' => Dict::S('UI:Button:MoveUp'), 'movedown' => Dict::S('UI:Button:MoveDown')),
|
|
||||||
);
|
|
||||||
if($this->oDefaultSettings != null)
|
|
||||||
{
|
|
||||||
$aOptions['oDefaultSettings'] = $this->GetAsHash($this->oDefaultSettings);
|
|
||||||
}
|
|
||||||
$sJSOptions = json_encode($aOptions);
|
|
||||||
$oPage->add_ready_script("$('#{$this->sDatatableContainerId}').datatable($sJSOptions);");
|
|
||||||
|
|
||||||
return $sHtml;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* When refreshing the body of a paginated table, get the rows of the table (inside the TBODY)
|
|
||||||
* return string The HTML rows to insert inside the <tbody> node
|
|
||||||
*/
|
|
||||||
public function GetAsHTMLTableRows(WebPage $oPage, $iPageSize, $aColumns, $sSelectMode, $bViewLink, $aExtraParams)
|
|
||||||
{
|
|
||||||
if ($iPageSize < 1)
|
|
||||||
{
|
|
||||||
$iPageSize = -1; // convention: no pagination
|
|
||||||
}
|
|
||||||
$aAttribs = $this->GetHTMLTableConfig($aColumns, $sSelectMode, $bViewLink);
|
|
||||||
$aValues = $this->GetHTMLTableValues($aColumns, $sSelectMode, $iPageSize, $bViewLink, $aExtraParams);
|
|
||||||
|
|
||||||
$sHtml = '';
|
|
||||||
foreach($aValues as $aRow)
|
|
||||||
{
|
|
||||||
$sHtml .= $oPage->GetTableRow($aRow, $aAttribs);
|
|
||||||
}
|
|
||||||
return $sHtml;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param WebPage $oPage
|
|
||||||
* @param $sSelectMode
|
|
||||||
*
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
protected function GetObjectCount(WebPage $oPage, $sSelectMode)
|
|
||||||
{
|
|
||||||
if (($sSelectMode == 'single') || ($sSelectMode == 'multiple'))
|
|
||||||
{
|
|
||||||
$sHtml = '<div class="pagination_objcount">'.Dict::Format('UI:Pagination:HeaderSelection', '<span id="total">'.$this->iNbObjects.'</span>', '<span class="selectedCount">0</span>').'</div>';
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
$sHtml = '<div class="pagination_objcount">'.Dict::Format('UI:Pagination:HeaderNoSelection', '<span id="total">'.$this->iNbObjects.'</span>').'</div>';
|
|
||||||
}
|
|
||||||
return $sHtml;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param WebPage $oPage
|
|
||||||
* @param $iPageSize
|
|
||||||
* @param $iDefaultPageSize
|
|
||||||
* @param $iPageIndex
|
|
||||||
*
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
protected function GetPager(WebPage $oPage, $iPageSize, $iDefaultPageSize, $iPageIndex)
|
|
||||||
{
|
|
||||||
$sHtml = '';
|
|
||||||
if ($iPageSize < 1) // Display all
|
|
||||||
{
|
|
||||||
$sPagerStyle = 'style="display:none"'; // no limit: display the full table, so hide the "pager" UI
|
|
||||||
// WARNING: mPDF does not take the "display" style into account
|
|
||||||
// when applied to a <td> or a <table> tag, so make sure you apply this to a div
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
$sPagerStyle = '';
|
|
||||||
}
|
|
||||||
|
|
||||||
$sCombo = '<select class="pagesize">';
|
|
||||||
if($iPageSize < 1)
|
|
||||||
{
|
|
||||||
$sCombo .= "<option selected=\"selected\" value=\"-1\">".Dict::S('UI:Pagination:All')."</option>";
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
for($iPage = 1; $iPage < 5; $iPage++)
|
|
||||||
{
|
|
||||||
$iNbItems = $iPage * $iDefaultPageSize;
|
|
||||||
$sSelected = ($iNbItems == $iPageSize) ? 'selected="selected"' : '';
|
|
||||||
$sCombo .= "<option $sSelected value=\"$iNbItems\">$iNbItems</option>";
|
|
||||||
}
|
|
||||||
$sCombo .= "<option value=\"-1\">".Dict::S('UI:Pagination:All')."</option>";
|
|
||||||
}
|
|
||||||
|
|
||||||
$sCombo .= '</select>';
|
|
||||||
|
|
||||||
$sPages = Dict::S('UI:Pagination:PagesLabel');
|
|
||||||
$sPageSizeCombo = Dict::Format('UI:Pagination:PageSize', $sCombo);
|
|
||||||
|
|
||||||
$iNbPages = ($iPageSize < 1) ? 1 : ceil($this->iNbObjects / $iPageSize);
|
|
||||||
if ($iNbPages == 1)
|
|
||||||
{
|
|
||||||
// No need to display the pager
|
|
||||||
$sPagerStyle = 'style="display:none"';
|
|
||||||
}
|
|
||||||
$aPagesToDisplay = array();
|
|
||||||
for($idx = 0; $idx <= min(4, $iNbPages-1); $idx++)
|
|
||||||
{
|
|
||||||
if ($idx == 0)
|
|
||||||
{
|
|
||||||
$aPagesToDisplay[$idx] = '<span page="0" class="curr_page">1</span>';
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
$aPagesToDisplay[$idx] = "<span id=\"gotopage_$idx\" class=\"gotopage\" page=\"$idx\">".(1+$idx)."</span>";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
$iLastPageIdx = $iNbPages - 1;
|
|
||||||
if (!isset($aPagesToDisplay[$iLastPageIdx]))
|
|
||||||
{
|
|
||||||
unset($aPagesToDisplay[$idx - 1]); // remove the last page added to make room for the very last page
|
|
||||||
$aPagesToDisplay[$iLastPageIdx] = "<span id=\"gotopage_$iLastPageIdx\" class=\"gotopage\" page=\"$iLastPageIdx\">... $iNbPages</span>";
|
|
||||||
}
|
|
||||||
$sPagesLinks = implode('', $aPagesToDisplay);
|
|
||||||
$sPagesList = '['.implode(',', array_keys($aPagesToDisplay)).']';
|
|
||||||
|
|
||||||
$sAppRootUrl = utils::GetAbsoluteUrlAppRoot();
|
|
||||||
$sSelectionMode = ($iNbPages == 1) ? '' : 'positive';
|
|
||||||
$sHtml =
|
|
||||||
<<<EOF
|
|
||||||
<td colspan="2">
|
|
||||||
<div $sPagerStyle>
|
|
||||||
<table id="pager{$this->iListId}" class="pager"><tr>
|
|
||||||
<td>$sPages</td>
|
|
||||||
<td><img src="{$sAppRootUrl}images/first.png" class="first"/>AAAA</td>
|
|
||||||
<td><img src="{$sAppRootUrl}images/prev.png" class="prev"/></td>
|
|
||||||
<td><span id="index">$sPagesLinks</span></td>
|
|
||||||
<td><img src="{$sAppRootUrl}images/next.png" class="next"/></td>
|
|
||||||
<td><img src="{$sAppRootUrl}images/last.png" class="last"/></td>
|
|
||||||
<td>$sPageSizeCombo</td>
|
|
||||||
<td><span id="loading"> </span><input type="hidden" name="selectionMode" value="$sSelectionMode"></input>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
</td>
|
|
||||||
EOF;
|
|
||||||
return $sHtml;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param WebPage $oPage
|
|
||||||
* @param $aExtraParams
|
|
||||||
*
|
|
||||||
* @return string
|
|
||||||
* @throws \ApplicationException
|
|
||||||
* @throws \ArchivedObjectException
|
|
||||||
* @throws \CoreException
|
|
||||||
* @throws \CoreUnexpectedValue
|
|
||||||
* @throws \DictExceptionMissingString
|
|
||||||
* @throws \MissingQueryArgument
|
|
||||||
* @throws \MySQLException
|
|
||||||
* @throws \MySQLHasGoneAwayException
|
|
||||||
* @throws \OQLException
|
|
||||||
* @throws \ReflectionException
|
|
||||||
* @throws \Twig\Error\LoaderError
|
|
||||||
* @throws \Twig\Error\RuntimeError
|
|
||||||
* @throws \Twig\Error\SyntaxError
|
|
||||||
*/
|
|
||||||
protected function GetActionsMenu(WebPage $oPage, $aExtraParams)
|
|
||||||
{
|
|
||||||
$oMenuBlock = new MenuBlock($this->oSet->GetFilter(), 'list');
|
|
||||||
$oBlock = $oMenuBlock->GetRenderContent($oPage, $aExtraParams, $this->iListId);
|
|
||||||
|
|
||||||
return ConsoleBlockRenderer::RenderBlockTemplateInPage($oPage, $oBlock);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param WebPage $oPage
|
|
||||||
* @param $aExtraParams
|
|
||||||
*
|
|
||||||
* @return string
|
|
||||||
* @throws \Exception
|
|
||||||
*/
|
|
||||||
protected function GetToolkitMenu(WebPage $oPage, $aExtraParams)
|
|
||||||
{
|
|
||||||
if (!$oPage->IsPrintableVersion())
|
|
||||||
{
|
|
||||||
$sMenuTitle = Dict::S('UI:ConfigureThisList');
|
|
||||||
$sHtml = '<div class="itop_popup toolkit_menu" id="tk_'.$this->iListId.'"><ul><li aria-label="'.Dict::S('UI:Menu:Toolkit').'"><i class="fas fa-tools"></i><i class="fas fa-caret-down"></i><ul>';
|
|
||||||
|
|
||||||
$oMenuItem1 = new JSPopupMenuItem('iTop::ConfigureList', $sMenuTitle, "$('#datatable_dlg_".$this->iListId."').dialog('open');");
|
|
||||||
$aActions = array(
|
|
||||||
$oMenuItem1->GetUID() => $oMenuItem1->GetMenuItem(),
|
|
||||||
);
|
|
||||||
$this->oSet->Rewind();
|
|
||||||
utils::GetPopupMenuItems($oPage, iPopupMenuExtension::MENU_OBJLIST_TOOLKIT, $this->oSet, $aActions, $this->sTableId, $this->iListId);
|
|
||||||
$this->oSet->Rewind();
|
|
||||||
$sHtml .= $oPage->RenderPopupMenuItems($aActions);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
$sHtml = '';
|
|
||||||
}
|
|
||||||
return $sHtml;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param WebPage $oPage
|
|
||||||
* @param $aColumns
|
|
||||||
* @param $bViewLink
|
|
||||||
* @param $iDefaultPageSize
|
|
||||||
*
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
protected function GetTableConfigDlg(WebPage $oPage, $aColumns, $bViewLink, $iDefaultPageSize)
|
|
||||||
{
|
|
||||||
$sHtml = "<div id=\"datatable_dlg_{$this->iListId}\" style=\"display: none;\">";
|
|
||||||
$sHtml .= "<form onsubmit=\"return false\">";
|
|
||||||
$sChecked = ($this->bUseCustomSettings) ? '' : 'checked';
|
|
||||||
$sHtml .= "<p><input id=\"dtbl_dlg_settings_{$this->iListId}\" type=\"radio\" name=\"settings\" $sChecked value=\"defaults\"><label for=\"dtbl_dlg_settings_{$this->iListId}\"> ".Dict::S('UI:UseDefaultSettings').'</label></p>';
|
|
||||||
$sHtml .= "<fieldset>";
|
|
||||||
$sChecked = ($this->bUseCustomSettings) ? 'checked': '';
|
|
||||||
$sHtml .= "<legend class=\"transparent\"><input id=\"dtbl_dlg_specific_{$this->iListId}\" type=\"radio\" class=\"specific_settings\" name=\"settings\" $sChecked value=\"specific\"><label for=\"dtbl_dlg_specific_{$this->iListId}\"> ".Dict::S('UI:UseSpecificSettings')."</label></legend>";
|
|
||||||
$sHtml .= Dict::S('UI:ColumnsAndSortOrder').'<br/><ul class="sortable_field_list" id="sfl_'.$this->iListId.'"></ul>';
|
|
||||||
|
|
||||||
$sHtml .= '<p>'.Dict::Format('UI:Display_X_ItemsPerPage', '<input type="text" size="4" name="page_size" value="'.$iDefaultPageSize.'">').'</p>';
|
|
||||||
$sHtml .= "</fieldset>";
|
|
||||||
$sHtml .= "<fieldset>";
|
|
||||||
$sSaveChecked = ($this->sTableId != null) ? 'checked' : '';
|
|
||||||
$sCustomDisabled = ($this->sTableId == null) ? 'disabled="disabled" stay-disabled="true" ' : '';
|
|
||||||
$sCustomChecked = ($this->sTableId != null) ? 'checked' : '';
|
|
||||||
$sGenericChecked = ($this->sTableId == null) ? 'checked' : '';
|
|
||||||
$sHtml .= "<legend class=\"transparent\"><input id=\"dtbl_dlg_save_{$this->iListId}\" type=\"checkbox\" $sSaveChecked name=\"save_settings\"><label for=\"dtbl_dlg_save_{$this->iListId}\"> ".Dict::S('UI:UseSavetheSettings')."</label></legend>";
|
|
||||||
$sHtml .= "<p><input id=\"dtbl_dlg_this_list_{$this->iListId}\" type=\"radio\" name=\"scope\" $sCustomChecked $sCustomDisabled value=\"this_list\"><label for=\"dtbl_dlg_this_list_{$this->iListId}\"> ".Dict::S('UI:OnlyForThisList').'</label> ';
|
|
||||||
$sHtml .= "<input id=\"dtbl_dlg_all_{$this->iListId}\" type=\"radio\" name=\"scope\" $sGenericChecked value=\"defaults\"><label for=\"dtbl_dlg_all_{$this->iListId}\"> ".Dict::S('UI:ForAllLists').'</label></p>';
|
|
||||||
$sHtml .= "</fieldset>";
|
|
||||||
$sHtml .= '<table style="width:100%"><tr><td style="text-align:center;">';
|
|
||||||
$sHtml .= '<button type="button" onclick="$(\'#'.$this->sDatatableContainerId.'\').datatable(\'onDlgCancel\'); $(\'#datatable_dlg_'.$this->iListId.'\').dialog(\'close\')">'.Dict::S('UI:Button:Cancel').'</button>';
|
|
||||||
$sHtml .= '</td><td style="text-align:center;">';
|
|
||||||
$sHtml .= '<button type="submit" onclick="$(\'#'.$this->sDatatableContainerId.'\').datatable(\'onDlgOk\');$(\'#datatable_dlg_'.$this->iListId.'\').dialog(\'close\');">'.Dict::S('UI:Button:Ok').'</button>';
|
|
||||||
$sHtml .= '</td></tr></table>';
|
|
||||||
$sHtml .= "</form>";
|
|
||||||
$sHtml .= "</div>";
|
|
||||||
|
|
||||||
$sDlgTitle = addslashes(Dict::S('UI:ListConfigurationTitle'));
|
|
||||||
$oPage->add_ready_script("$('#datatable_dlg_{$this->iListId}').dialog({autoOpen: false, title: '$sDlgTitle', width: 500, close: function() { $('#{$this->sDatatableContainerId}').datatable('onDlgCancel'); } });");
|
|
||||||
|
|
||||||
return $sHtml;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param $oSetting
|
|
||||||
*
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
public function GetAsHash($oSetting)
|
|
||||||
{
|
|
||||||
$aSettings = array('iDefaultPageSize' => $oSetting->iDefaultPageSize, 'oColumns' => $oSetting->aColumns);
|
|
||||||
return $aSettings;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param array $aColumns
|
|
||||||
* @param string $sSelectMode
|
|
||||||
* @param bool $bViewLink
|
|
||||||
*
|
|
||||||
* @return array
|
|
||||||
* @throws \CoreException
|
|
||||||
* @throws \DictExceptionMissingString
|
|
||||||
* @throws \Exception
|
|
||||||
*/
|
|
||||||
protected function GetHTMLTableConfig($aColumns, $sSelectMode, $bViewLink)
|
|
||||||
{
|
|
||||||
$aAttribs = array();
|
|
||||||
if ($sSelectMode == 'multiple')
|
|
||||||
{
|
|
||||||
$aAttribs['form::select'] = array(
|
|
||||||
'label' => "<input type=\"checkbox\" onClick=\"CheckAll('.selectList{$this->iListId}:not(:disabled)', this.checked);\" class=\"checkAll\"></input>",
|
|
||||||
'description' => Dict::S('UI:SelectAllToggle+'),
|
|
||||||
'metadata' => array(),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
else if ($sSelectMode == 'single')
|
|
||||||
{
|
|
||||||
$aAttribs['form::select'] = array('label' => '', 'description' => '', 'metadata' => array());
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach($this->aClassAliases as $sAlias => $sClassName)
|
|
||||||
{
|
|
||||||
foreach($aColumns[$sAlias] as $sAttCode => $aData)
|
|
||||||
{
|
|
||||||
if ($aData['checked'])
|
|
||||||
{
|
|
||||||
if ($sAttCode == '_key_')
|
|
||||||
{
|
|
||||||
$sAttLabel = MetaModel::GetName($sClassName);
|
|
||||||
|
|
||||||
$aAttribs['key_'.$sAlias] = array(
|
|
||||||
'label' => $sAttLabel,
|
|
||||||
'description' => '',
|
|
||||||
'metadata' => array(
|
|
||||||
'object_class' => $sClassName,
|
|
||||||
'attribute_label' => $sAttLabel,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
$oAttDef = MetaModel::GetAttributeDef($sClassName, $sAttCode);
|
|
||||||
$sAttDefClass = get_class($oAttDef);
|
|
||||||
$sAttLabel = MetaModel::GetLabel($sClassName, $sAttCode);
|
|
||||||
|
|
||||||
$aAttribs[$sAttCode.'_'.$sAlias] = array(
|
|
||||||
'label' => $sAttLabel,
|
|
||||||
'description' => $oAttDef->GetOrderByHint(),
|
|
||||||
'metadata' => array(
|
|
||||||
'object_class' => $sClassName,
|
|
||||||
'attribute_code' => $sAttCode,
|
|
||||||
'attribute_type' => $sAttDefClass,
|
|
||||||
'attribute_label' => $sAttLabel,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return $aAttribs;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param $aColumns
|
|
||||||
* @param $sSelectMode
|
|
||||||
* @param $iPageSize
|
|
||||||
* @param $bViewLink
|
|
||||||
* @param $aExtraParams
|
|
||||||
*
|
|
||||||
* @return array
|
|
||||||
* @throws \CoreException
|
|
||||||
* @throws \CoreUnexpectedValue
|
|
||||||
* @throws \MissingQueryArgument
|
|
||||||
* @throws \MySQLException
|
|
||||||
* @throws \MySQLHasGoneAwayException
|
|
||||||
* @throws \Exception
|
|
||||||
*/
|
|
||||||
protected function GetHTMLTableValues($aColumns, $sSelectMode, $iPageSize, $bViewLink, $aExtraParams)
|
|
||||||
{
|
|
||||||
$bLocalize = true;
|
|
||||||
if (isset($aExtraParams['localize_values']))
|
|
||||||
{
|
|
||||||
$bLocalize = (bool) $aExtraParams['localize_values'];
|
|
||||||
}
|
|
||||||
|
|
||||||
$aValues = array();
|
|
||||||
$aAttDefsCache = array();
|
|
||||||
$this->oSet->Seek(0);
|
|
||||||
$iMaxObjects = $iPageSize;
|
|
||||||
while (($aObjects = $this->oSet->FetchAssoc()) && ($iMaxObjects != 0))
|
|
||||||
{
|
|
||||||
$bFirstObject = true;
|
|
||||||
$aRow = array();
|
|
||||||
foreach($this->aClassAliases as $sAlias => $sClassName)
|
|
||||||
{
|
|
||||||
if (is_object($aObjects[$sAlias]))
|
|
||||||
{
|
|
||||||
$sHilightClass = MetaModel::GetHilightClass($sClassName, $aObjects[$sAlias]);
|
|
||||||
if ($sHilightClass != '')
|
|
||||||
{
|
|
||||||
$aRow['@class'] = $sHilightClass;
|
|
||||||
}
|
|
||||||
if ((($sSelectMode == 'single') || ($sSelectMode == 'multiple')) && $bFirstObject)
|
|
||||||
{
|
|
||||||
if (array_key_exists('selection_enabled', $aExtraParams) && isset($aExtraParams['selection_enabled'][$aObjects[$sAlias]->GetKey()]))
|
|
||||||
{
|
|
||||||
$sDisabled = ($aExtraParams['selection_enabled'][$aObjects[$sAlias]->GetKey()]) ? '' : ' disabled="disabled"';
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
$sDisabled = '';
|
|
||||||
}
|
|
||||||
if ($sSelectMode == 'single')
|
|
||||||
{
|
|
||||||
$aRow['form::select'] = "<input type=\"radio\" $sDisabled class=\"selectList{$this->iListId}\" name=\"selectObject\" value=\"".$aObjects[$sAlias]->GetKey()."\"></input>";
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
$aRow['form::select'] = "<input type=\"checkbox\" $sDisabled class=\"selectList{$this->iListId}\" name=\"selectObject[]\" value=\"".$aObjects[$sAlias]->GetKey()."\"></input>";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
foreach($aColumns[$sAlias] as $sAttCode => $aData)
|
|
||||||
{
|
|
||||||
if ($aData['checked'])
|
|
||||||
{
|
|
||||||
if ($sAttCode == '_key_')
|
|
||||||
{
|
|
||||||
$aRow['key_'.$sAlias] = array(
|
|
||||||
'value_raw' => $aObjects[$sAlias]->GetKey(),
|
|
||||||
'value_html' => $aObjects[$sAlias]->GetHyperLink(),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Prepare att. def. classes cache to avoid retrieving AttDef for each row
|
|
||||||
if(!isset($aAttDefsCache[$sClassName][$sAttCode]))
|
|
||||||
{
|
|
||||||
$aAttDefClassesCache[$sClassName][$sAttCode] = get_class(MetaModel::GetAttributeDef($sClassName, $sAttCode));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Only retrieve raw (stored) value for simple fields
|
|
||||||
$bExcludeRawValue = false;
|
|
||||||
foreach (cmdbAbstractObject::GetAttDefClassesToExcludeFromMarkupMetadataRawValue() as $sAttDefClassToExclude)
|
|
||||||
{
|
|
||||||
if (is_a($aAttDefClassesCache[$sClassName][$sAttCode], $sAttDefClassToExclude, true))
|
|
||||||
{
|
|
||||||
$bExcludeRawValue = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if($bExcludeRawValue)
|
|
||||||
{
|
|
||||||
$aRow[$sAttCode.'_'.$sAlias] = $aObjects[$sAlias]->GetAsHTML($sAttCode, $bLocalize);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
$aRow[$sAttCode.'_'.$sAlias] = array(
|
|
||||||
'value_raw' => $aObjects[$sAlias]->Get($sAttCode),
|
|
||||||
'value_html' => $aObjects[$sAlias]->GetAsHTML($sAttCode, $bLocalize),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
foreach($aColumns[$sAlias] as $sAttCode => $aData)
|
|
||||||
{
|
|
||||||
if ($aData['checked'])
|
|
||||||
{
|
|
||||||
if ($sAttCode == '_key_')
|
|
||||||
{
|
|
||||||
$aRow['key_'.$sAlias] = '';
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
$aRow[$sAttCode.'_'.$sAlias] = '';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
$bFirstObject = false;
|
|
||||||
}
|
|
||||||
$aValues[] = $aRow;
|
|
||||||
$iMaxObjects--;
|
|
||||||
}
|
|
||||||
return $aValues;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param WebPage $oPage
|
|
||||||
* @param $aColumns
|
|
||||||
* @param $sSelectMode
|
|
||||||
* @param $iPageSize
|
|
||||||
* @param $bViewLink
|
|
||||||
* @param $aExtraParams
|
|
||||||
*
|
|
||||||
* @return string
|
|
||||||
* @throws \ArchivedObjectException
|
|
||||||
* @throws \CoreException
|
|
||||||
* @throws \CoreUnexpectedValue
|
|
||||||
* @throws \DictExceptionMissingString
|
|
||||||
* @throws \MissingQueryArgument
|
|
||||||
* @throws \MySQLException
|
|
||||||
* @throws \MySQLHasGoneAwayException
|
|
||||||
* @throws \Exception
|
|
||||||
*/
|
|
||||||
public function GetHTMLTable(WebPage $oPage, $aColumns, $sSelectMode, $iPageSize, $bViewLink, $aExtraParams)
|
|
||||||
{
|
|
||||||
$iNbPages = ($iPageSize < 1) ? 1 : ceil($this->iNbObjects / $iPageSize);
|
|
||||||
if ($iPageSize < 1)
|
|
||||||
{
|
|
||||||
$iPageSize = -1; // convention: no pagination
|
|
||||||
}
|
|
||||||
$aAttribs = $this->GetHTMLTableConfig($aColumns, $sSelectMode, $bViewLink);
|
|
||||||
|
|
||||||
$aValues = $this->GetHTMLTableValues($aColumns, $sSelectMode, $iPageSize, $bViewLink, $aExtraParams);
|
|
||||||
|
|
||||||
$sHtml = '<table class="listContainer object-list">';
|
|
||||||
|
|
||||||
foreach($this->oSet->GetFilter()->GetInternalParams() as $sName => $sValue)
|
|
||||||
{
|
|
||||||
$aExtraParams['query_params'][$sName] = $sValue;
|
|
||||||
}
|
|
||||||
$aExtraParams['show_obsolete_data'] = $this->bShowObsoleteData;
|
|
||||||
|
|
||||||
$sHtml .= "<tr><td>";
|
|
||||||
$sHtml .= $oPage->GetTable($aAttribs, $aValues);
|
|
||||||
$sHtml .= '</td></tr>';
|
|
||||||
$sHtml .= '</table>';
|
|
||||||
$iCount = $this->iNbObjects;
|
|
||||||
|
|
||||||
$aArgs = $this->oSet->GetArgs();
|
|
||||||
$sExtraParams = addslashes(str_replace('"', "'", json_encode(array_merge($aExtraParams, $aArgs)))); // JSON encode, change the style of the quotes and escape them
|
|
||||||
$sSelectModeJS = '';
|
|
||||||
$sHeaders = '';
|
|
||||||
if (($sSelectMode == 'single') || ($sSelectMode == 'multiple'))
|
|
||||||
{
|
|
||||||
$sSelectModeJS = $sSelectMode;
|
|
||||||
$sHeaders = 'headers: { 0: {sorter: false}},';
|
|
||||||
}
|
|
||||||
$sDisplayKey = ($bViewLink) ? 'true' : 'false';
|
|
||||||
// Protect against duplicate elements in the Zlist
|
|
||||||
$aUniqueOrderedList = array();
|
|
||||||
foreach($this->aClassAliases as $sAlias => $sClassName)
|
|
||||||
{
|
|
||||||
foreach($aColumns[$sAlias] as $sAttCode => $aData)
|
|
||||||
{
|
|
||||||
if ($aData['checked'])
|
|
||||||
{
|
|
||||||
$aUniqueOrderedList[$sAttCode] = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
$aUniqueOrderedList = array_keys($aUniqueOrderedList);
|
|
||||||
$sJSColumns = json_encode($aColumns);
|
|
||||||
$sJSClassAliases = json_encode($this->aClassAliases);
|
|
||||||
$sCssCount = isset($aExtraParams['cssCount']) ? ", cssCount: '{$aExtraParams['cssCount']}'" : '';
|
|
||||||
$this->oSet->ApplyParameters();
|
|
||||||
// Display the actual sort order of the table
|
|
||||||
$aRealSortOrder = $this->oSet->GetRealSortOrder();
|
|
||||||
$aDefaultSort = array();
|
|
||||||
$iColOffset = 0;
|
|
||||||
if (($sSelectMode == 'single') || ($sSelectMode == 'multiple'))
|
|
||||||
{
|
|
||||||
$iColOffset += 1;
|
|
||||||
}
|
|
||||||
if ($bViewLink)
|
|
||||||
{
|
|
||||||
// $iColOffset += 1;
|
|
||||||
}
|
|
||||||
foreach($aRealSortOrder as $sColCode => $bAscending)
|
|
||||||
{
|
|
||||||
$iPos = array_search($sColCode, $aUniqueOrderedList);
|
|
||||||
if ($iPos !== false)
|
|
||||||
{
|
|
||||||
$aDefaultSort[] = "[".($iColOffset+$iPos).",".($bAscending ? '0' : '1')."]";
|
|
||||||
}
|
|
||||||
else if (($iPos = array_search(preg_replace('/_friendlyname$/', '', $sColCode), $aUniqueOrderedList)) !== false)
|
|
||||||
{
|
|
||||||
// if sorted on the friendly name of an external key, then consider it sorted on the column that shows the links
|
|
||||||
$aDefaultSort[] = "[".($iColOffset+$iPos).",".($bAscending ? '0' : '1')."]";
|
|
||||||
}
|
|
||||||
else if($sColCode == 'friendlyname' && $bViewLink)
|
|
||||||
{
|
|
||||||
$aDefaultSort[] = "[".($iColOffset).",".($bAscending ? '0' : '1')."]";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
$sFakeSortList = '';
|
|
||||||
if (count($aDefaultSort) > 0)
|
|
||||||
{
|
|
||||||
$sFakeSortList = '['.implode(',', $aDefaultSort).']';
|
|
||||||
}
|
|
||||||
$sOQL = addslashes($this->oSet->GetFilter()->serialize());
|
|
||||||
$oPage->add_ready_script(
|
|
||||||
<<<JS
|
|
||||||
var oTable = $('#{$this->sDatatableContainerId} table.listResults');
|
|
||||||
oTable.tableHover();
|
|
||||||
oTable
|
|
||||||
.tablesorter({ $sHeaders widgets: ['myZebra', 'truncatedList']})
|
|
||||||
.tablesorterPager({
|
|
||||||
container: $('#pager{$this->iListId}'),
|
|
||||||
totalRows:$iCount,
|
|
||||||
size: $iPageSize,
|
|
||||||
filter: '$sOQL',
|
|
||||||
extra_params: '$sExtraParams',
|
|
||||||
select_mode: '$sSelectModeJS',
|
|
||||||
displayKey: $sDisplayKey,
|
|
||||||
table_id: '{$this->sDatatableContainerId}',
|
|
||||||
columns: $sJSColumns,
|
|
||||||
class_aliases: $sJSClassAliases $sCssCount
|
|
||||||
});
|
|
||||||
JS
|
|
||||||
);
|
|
||||||
if ($sFakeSortList != '')
|
|
||||||
{
|
|
||||||
$oPage->add_ready_script("oTable.trigger(\"fakesorton\", [$sFakeSortList]);");
|
|
||||||
}
|
|
||||||
return $sHtml;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param WebPage $oPage
|
|
||||||
* @param $iDefaultPageSize
|
|
||||||
* @param $iStart
|
|
||||||
*/
|
|
||||||
public function UpdatePager(WebPage $oPage, $iDefaultPageSize, $iStart)
|
|
||||||
{
|
|
||||||
$iPageSize = $iDefaultPageSize;
|
|
||||||
$iPageIndex = 0;
|
|
||||||
$sHtml = $this->GetPager($oPage, $iPageSize, $iDefaultPageSize, $iPageIndex);
|
|
||||||
$oPage->add_ready_script("$('#pager{$this->iListId}').html('".json_encode($sHtml)."');");
|
|
||||||
if ($iDefaultPageSize < 1)
|
|
||||||
{
|
|
||||||
$oPage->add_ready_script("$('#pager{$this->iListId}').parent().hide()");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
$oPage->add_ready_script("$('#pager{$this->iListId}').parent().show()");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Simplified version of the data table with less "decoration" (and no paging)
|
|
||||||
* which is optimized for printing
|
|
||||||
*/
|
|
||||||
class PrintableDataTable extends DataTable
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* @param WebPage $oPage
|
|
||||||
* @param $iPageSize
|
|
||||||
* @param $iDefaultPageSize
|
|
||||||
* @param $iPageIndex
|
|
||||||
* @param $aColumns
|
|
||||||
* @param $bActionsMenu
|
|
||||||
* @param $bToolkitMenu
|
|
||||||
* @param $sSelectMode
|
|
||||||
* @param $bViewLink
|
|
||||||
* @param $aExtraParams
|
|
||||||
*
|
|
||||||
* @return string
|
|
||||||
* @throws \ArchivedObjectException
|
|
||||||
* @throws \CoreException
|
|
||||||
* @throws \CoreUnexpectedValue
|
|
||||||
* @throws \DictExceptionMissingString
|
|
||||||
* @throws \MissingQueryArgument
|
|
||||||
* @throws \MySQLException
|
|
||||||
* @throws \MySQLHasGoneAwayException
|
|
||||||
*/
|
|
||||||
public function GetAsHTML(WebPage $oPage, $iPageSize, $iDefaultPageSize, $iPageIndex, $aColumns, $bActionsMenu, $bToolkitMenu, $sSelectMode, $bViewLink, $aExtraParams)
|
|
||||||
{
|
|
||||||
return $this->GetHTMLTable($oPage, $aColumns, $sSelectMode, -1, $bViewLink, $aExtraParams);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param WebPage $oPage
|
|
||||||
* @param $aColumns
|
|
||||||
* @param $sSelectMode
|
|
||||||
* @param $iPageSize
|
|
||||||
* @param $bViewLink
|
|
||||||
* @param $aExtraParams
|
|
||||||
*
|
|
||||||
* @return string
|
|
||||||
* @throws \CoreException
|
|
||||||
* @throws \CoreUnexpectedValue
|
|
||||||
* @throws \DictExceptionMissingString
|
|
||||||
* @throws \MissingQueryArgument
|
|
||||||
* @throws \MySQLException
|
|
||||||
* @throws \MySQLHasGoneAwayException
|
|
||||||
*/
|
|
||||||
public function GetHTMLTable(WebPage $oPage, $aColumns, $sSelectMode, $iPageSize, $bViewLink, $aExtraParams)
|
|
||||||
{
|
|
||||||
$iNbPages = ($iPageSize < 1) ? 1 : ceil($this->iNbObjects / $iPageSize);
|
|
||||||
if ($iPageSize < 1)
|
|
||||||
{
|
|
||||||
$iPageSize = -1; // convention: no pagination
|
|
||||||
}
|
|
||||||
$aAttribs = $this->GetHTMLTableConfig($aColumns, $sSelectMode, $bViewLink);
|
|
||||||
|
|
||||||
$aValues = $this->GetHTMLTableValues($aColumns, $sSelectMode, $iPageSize, $bViewLink, $aExtraParams);
|
|
||||||
|
|
||||||
$sHtml = $oPage->GetTable($aAttribs, $aValues);
|
|
||||||
|
|
||||||
return $sHtml;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -1,8 +0,0 @@
|
|||||||
<?php
|
|
||||||
/**
|
|
||||||
* @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-2024 Combodo SAS
|
|
||||||
*/
|
|
||||||
|
|
||||||
DeprecatedCallsLog::NotifyDeprecatedFile('moved to sources/Application/WebPage/ErrorPage.php, now loadable using autoloader');
|
|
||||||
@@ -19,73 +19,67 @@ class ExcelExporter
|
|||||||
protected $iPosition;
|
protected $iPosition;
|
||||||
protected $sOutputFilePath;
|
protected $sOutputFilePath;
|
||||||
protected $bAdvancedMode;
|
protected $bAdvancedMode;
|
||||||
|
|
||||||
public function __construct($sToken = null)
|
public function __construct($sToken = null)
|
||||||
{
|
{
|
||||||
$this->aStatistics = array(
|
$this->aStatistics = [
|
||||||
'objects_count' => 0,
|
'objects_count' => 0,
|
||||||
'total_duration' => 0,
|
'total_duration' => 0,
|
||||||
'data_retrieval_duration' => 0,
|
'data_retrieval_duration' => 0,
|
||||||
'excel_build_duration' => 0,
|
'excel_build_duration' => 0,
|
||||||
'excel_write_duration' => 0,
|
'excel_write_duration' => 0,
|
||||||
'peak_memory_usage' => 0,
|
'peak_memory_usage' => 0,
|
||||||
);
|
];
|
||||||
$this->fStartTime = microtime(true);
|
$this->fStartTime = microtime(true);
|
||||||
$this->oSearch = null;
|
$this->oSearch = null;
|
||||||
|
|
||||||
$this->sState = 'new';
|
$this->sState = 'new';
|
||||||
$this->aObjectsIDs = array();
|
$this->aObjectsIDs = [];
|
||||||
$this->iPosition = 0;
|
$this->iPosition = 0;
|
||||||
$this->aAuthorizedClasses = null;
|
$this->aAuthorizedClasses = null;
|
||||||
$this->aTableHeaders = null;
|
$this->aTableHeaders = null;
|
||||||
$this->sOutputFilePath = null;
|
$this->sOutputFilePath = null;
|
||||||
$this->bAdvancedMode = false;
|
$this->bAdvancedMode = false;
|
||||||
$this->CheckDataDir();
|
$this->CheckDataDir();
|
||||||
if ($sToken == null)
|
if ($sToken == null) {
|
||||||
{
|
|
||||||
$this->sToken = $this->GetNewToken();
|
$this->sToken = $this->GetNewToken();
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
$this->sToken = $sToken;
|
$this->sToken = $sToken;
|
||||||
$this->ReloadState();
|
$this->ReloadState();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function __destruct()
|
public function __destruct()
|
||||||
{
|
{
|
||||||
if (($this->sState != 'done') && ($this->sState != 'error') && ($this->sToken != null))
|
if (($this->sState != 'done') && ($this->sState != 'error') && ($this->sToken != null)) {
|
||||||
{
|
|
||||||
// Operation in progress, save the state
|
// Operation in progress, save the state
|
||||||
$this->SaveState();
|
$this->SaveState();
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
// Operation completed, cleanup the temp files
|
// Operation completed, cleanup the temp files
|
||||||
@unlink($this->GetStateFile());
|
@unlink($this->GetStateFile());
|
||||||
@unlink($this->GetDataFile());
|
@unlink($this->GetDataFile());
|
||||||
}
|
}
|
||||||
self::CleanupOldFiles();
|
self::CleanupOldFiles();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function SetChunkSize($iChunkSize)
|
public function SetChunkSize($iChunkSize)
|
||||||
{
|
{
|
||||||
$this->iChunkSize = $iChunkSize;
|
$this->iChunkSize = $iChunkSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function SetOutputFilePath($sDestFilePath)
|
public function SetOutputFilePath($sDestFilePath)
|
||||||
{
|
{
|
||||||
$this->sOutputFilePath = $sDestFilePath;
|
$this->sOutputFilePath = $sDestFilePath;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function SetAdvancedMode($bAdvanced)
|
public function SetAdvancedMode($bAdvanced)
|
||||||
{
|
{
|
||||||
$this->bAdvancedMode = $bAdvanced;
|
$this->bAdvancedMode = $bAdvanced;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function SaveState()
|
public function SaveState()
|
||||||
{
|
{
|
||||||
$aState = array(
|
$aState = [
|
||||||
'state' => $this->sState,
|
'state' => $this->sState,
|
||||||
'statistics' => $this->aStatistics,
|
'statistics' => $this->aStatistics,
|
||||||
'filter' => $this->oSearch->serialize(),
|
'filter' => $this->oSearch->serialize(),
|
||||||
@@ -94,31 +88,28 @@ class ExcelExporter
|
|||||||
'object_ids' => $this->aObjectsIDs,
|
'object_ids' => $this->aObjectsIDs,
|
||||||
'output_file_path' => $this->sOutputFilePath,
|
'output_file_path' => $this->sOutputFilePath,
|
||||||
'advanced_mode' => $this->bAdvancedMode,
|
'advanced_mode' => $this->bAdvancedMode,
|
||||||
);
|
];
|
||||||
|
|
||||||
file_put_contents($this->GetStateFile(), json_encode($aState));
|
file_put_contents($this->GetStateFile(), json_encode($aState));
|
||||||
|
|
||||||
return $this->sToken;
|
return $this->sToken;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function ReloadState()
|
public function ReloadState()
|
||||||
{
|
{
|
||||||
if ($this->sToken == null)
|
if ($this->sToken == null) {
|
||||||
{
|
|
||||||
throw new Exception('ExcelExporter not initialized with a token, cannot reload state');
|
throw new Exception('ExcelExporter not initialized with a token, cannot reload state');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!file_exists($this->GetStateFile()))
|
if (!file_exists($this->GetStateFile())) {
|
||||||
{
|
|
||||||
throw new Exception("ExcelExporter: missing status file '".$this->GetStateFile()."', cannot reload state.");
|
throw new Exception("ExcelExporter: missing status file '".$this->GetStateFile()."', cannot reload state.");
|
||||||
}
|
}
|
||||||
$sJson = file_get_contents($this->GetStateFile());
|
$sJson = file_get_contents($this->GetStateFile());
|
||||||
$aState = json_decode($sJson, true);
|
$aState = json_decode($sJson, true);
|
||||||
if ($aState === null)
|
if ($aState === null) {
|
||||||
{
|
|
||||||
throw new Exception("ExcelExporter:corrupted status file '".$this->GetStateFile()."', not a JSON, cannot reload state.");
|
throw new Exception("ExcelExporter:corrupted status file '".$this->GetStateFile()."', not a JSON, cannot reload state.");
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->sState = $aState['state'];
|
$this->sState = $aState['state'];
|
||||||
$this->aStatistics = $aState['statistics'];
|
$this->aStatistics = $aState['statistics'];
|
||||||
$this->oSearch = DBObjectSearch::unserialize($aState['filter']);
|
$this->oSearch = DBObjectSearch::unserialize($aState['filter']);
|
||||||
@@ -128,223 +119,197 @@ class ExcelExporter
|
|||||||
$this->sOutputFilePath = $aState['output_file_path'];
|
$this->sOutputFilePath = $aState['output_file_path'];
|
||||||
$this->bAdvancedMode = $aState['advanced_mode'];
|
$this->bAdvancedMode = $aState['advanced_mode'];
|
||||||
}
|
}
|
||||||
|
|
||||||
public function SetObjectList($oSearch)
|
public function SetObjectList($oSearch)
|
||||||
{
|
{
|
||||||
$this->oSearch = $oSearch;
|
$this->oSearch = $oSearch;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function Run()
|
public function Run()
|
||||||
{
|
{
|
||||||
$sCode = 'error';
|
$sCode = 'error';
|
||||||
$iPercentage = 100;
|
$iPercentage = 100;
|
||||||
$sMessage = Dict::Format('ExcelExporter:ErrorUnexpected_State', $this->sState);
|
$sMessage = Dict::Format('ExcelExporter:ErrorUnexpected_State', $this->sState);
|
||||||
$fTime = microtime(true);
|
$fTime = microtime(true);
|
||||||
|
|
||||||
try
|
try {
|
||||||
{
|
switch ($this->sState) {
|
||||||
switch($this->sState)
|
|
||||||
{
|
|
||||||
case 'new':
|
case 'new':
|
||||||
$oIDSet = new DBObjectSet($this->oSearch);
|
$oIDSet = new DBObjectSet($this->oSearch);
|
||||||
$oIDSet->OptimizeColumnLoad(array('id'));
|
$oIDSet->OptimizeColumnLoad(['id']);
|
||||||
$this->aObjectsIDs = array();
|
$this->aObjectsIDs = [];
|
||||||
while($oObj = $oIDSet->Fetch())
|
while ($oObj = $oIDSet->Fetch()) {
|
||||||
{
|
$this->aObjectsIDs[] = $oObj->GetKey();
|
||||||
$this->aObjectsIDs[] = $oObj->GetKey();
|
|
||||||
}
|
|
||||||
$sCode = 'retrieving-data';
|
|
||||||
$iPercentage = 5;
|
|
||||||
$sMessage = Dict::S('ExcelExporter:RetrievingData');
|
|
||||||
$this->iPosition = 0;
|
|
||||||
$this->aStatistics['objects_count'] = count($this->aObjectsIDs);
|
|
||||||
$this->aStatistics['data_retrieval_duration'] += microtime(true) - $fTime;
|
|
||||||
|
|
||||||
// The first line of the file is the "headers" specifying the label and the type of each column
|
|
||||||
$this->GetFieldsList($oIDSet, $this->bAdvancedMode);
|
|
||||||
$sRow = json_encode($this->aTableHeaders);
|
|
||||||
$hFile = @fopen($this->GetDataFile(), 'ab');
|
|
||||||
if ($hFile === false)
|
|
||||||
{
|
|
||||||
throw new Exception('ExcelExporter: Failed to open temporary data file: "'.$this->GetDataFile().'" for writing.');
|
|
||||||
}
|
|
||||||
fwrite($hFile, $sRow."\n");
|
|
||||||
fclose($hFile);
|
|
||||||
|
|
||||||
// Next state
|
|
||||||
$this->sState = 'retrieving-data';
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'retrieving-data':
|
|
||||||
$oCurrentSearch = clone $this->oSearch;
|
|
||||||
$aIDs = array_slice($this->aObjectsIDs, $this->iPosition, $this->iChunkSize);
|
|
||||||
|
|
||||||
$oCurrentSearch->AddCondition('id', $aIDs, 'IN');
|
|
||||||
$hFile = @fopen($this->GetDataFile(), 'ab');
|
|
||||||
if ($hFile === false)
|
|
||||||
{
|
|
||||||
throw new Exception('ExcelExporter: Failed to open temporary data file: "'.$this->GetDataFile().'" for writing.');
|
|
||||||
}
|
|
||||||
$oSet = new DBObjectSet($oCurrentSearch);
|
|
||||||
$this->GetFieldsList($oSet, $this->bAdvancedMode);
|
|
||||||
while($aObjects = $oSet->FetchAssoc())
|
|
||||||
{
|
|
||||||
$aRow = array();
|
|
||||||
foreach($this->aAuthorizedClasses as $sAlias => $sClassName)
|
|
||||||
{
|
|
||||||
$oObj = $aObjects[$sAlias];
|
|
||||||
if ($this->bAdvancedMode)
|
|
||||||
{
|
|
||||||
$aRow[] = $oObj->GetKey();
|
|
||||||
}
|
|
||||||
foreach($this->aFieldsList[$sAlias] as $sAttCodeEx => $oAttDef)
|
|
||||||
{
|
|
||||||
$value = $oObj->Get($sAttCodeEx);
|
|
||||||
if ($value instanceOf ormCaseLog)
|
|
||||||
{
|
|
||||||
// Extract the case log as text and remove the "===" which make Excel think that the cell contains a formula the next time you edit it!
|
|
||||||
$sExcelVal = trim(preg_replace('/========== ([^=]+) ============/', '********** $1 ************', $value->GetText()));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
$sExcelVal = $oAttDef->GetEditValue($value, $oObj);
|
|
||||||
}
|
|
||||||
$aRow[] = $sExcelVal;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
$sRow = json_encode($aRow);
|
|
||||||
fwrite($hFile, $sRow."\n");
|
|
||||||
}
|
|
||||||
fclose($hFile);
|
|
||||||
|
|
||||||
if (($this->iPosition + $this->iChunkSize) > count($this->aObjectsIDs))
|
|
||||||
{
|
|
||||||
// Next state
|
|
||||||
$this->sState = 'building-excel';
|
|
||||||
$sCode = 'building-excel';
|
|
||||||
$iPercentage = 80;
|
|
||||||
$sMessage = Dict::S('ExcelExporter:BuildingExcelFile');
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
$sCode = 'retrieving-data';
|
$sCode = 'retrieving-data';
|
||||||
$this->iPosition += $this->iChunkSize;
|
$iPercentage = 5;
|
||||||
$iPercentage = 5 + round(75 * ($this->iPosition / count($this->aObjectsIDs)));
|
$sMessage = Dict::S('ExcelExporter:RetrievingData');
|
||||||
$sMessage = Dict::S('ExcelExporter:RetrievingData');
|
$this->iPosition = 0;
|
||||||
}
|
$this->aStatistics['objects_count'] = count($this->aObjectsIDs);
|
||||||
break;
|
$this->aStatistics['data_retrieval_duration'] += microtime(true) - $fTime;
|
||||||
|
|
||||||
|
// The first line of the file is the "headers" specifying the label and the type of each column
|
||||||
|
$this->GetFieldsList($oIDSet, $this->bAdvancedMode);
|
||||||
|
$sRow = json_encode($this->aTableHeaders);
|
||||||
|
$hFile = @fopen($this->GetDataFile(), 'ab');
|
||||||
|
if ($hFile === false) {
|
||||||
|
throw new Exception('ExcelExporter: Failed to open temporary data file: "'.$this->GetDataFile().'" for writing.');
|
||||||
|
}
|
||||||
|
fwrite($hFile, $sRow."\n");
|
||||||
|
fclose($hFile);
|
||||||
|
|
||||||
|
// Next state
|
||||||
|
$this->sState = 'retrieving-data';
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'retrieving-data':
|
||||||
|
$oCurrentSearch = clone $this->oSearch;
|
||||||
|
$aIDs = array_slice($this->aObjectsIDs, $this->iPosition, $this->iChunkSize);
|
||||||
|
|
||||||
|
$oCurrentSearch->AddCondition('id', $aIDs, 'IN');
|
||||||
|
$hFile = @fopen($this->GetDataFile(), 'ab');
|
||||||
|
if ($hFile === false) {
|
||||||
|
throw new Exception('ExcelExporter: Failed to open temporary data file: "'.$this->GetDataFile().'" for writing.');
|
||||||
|
}
|
||||||
|
$oSet = new DBObjectSet($oCurrentSearch);
|
||||||
|
$this->GetFieldsList($oSet, $this->bAdvancedMode);
|
||||||
|
while ($aObjects = $oSet->FetchAssoc()) {
|
||||||
|
$aRow = [];
|
||||||
|
foreach ($this->aAuthorizedClasses as $sAlias => $sClassName) {
|
||||||
|
$oObj = $aObjects[$sAlias];
|
||||||
|
if ($this->bAdvancedMode) {
|
||||||
|
$aRow[] = $oObj->GetKey();
|
||||||
|
}
|
||||||
|
foreach ($this->aFieldsList[$sAlias] as $sAttCodeEx => $oAttDef) {
|
||||||
|
$value = $oObj->Get($sAttCodeEx);
|
||||||
|
if ($value instanceof ormCaseLog) {
|
||||||
|
// Extract the case log as text and remove the "===" which make Excel think that the cell contains a formula the next time you edit it!
|
||||||
|
$sExcelVal = trim(preg_replace('/========== ([^=]+) ============/', '********** $1 ************', $value->GetText()));
|
||||||
|
} else {
|
||||||
|
$sExcelVal = $oAttDef->GetEditValue($value, $oObj);
|
||||||
|
}
|
||||||
|
$aRow[] = $sExcelVal;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$sRow = json_encode($aRow);
|
||||||
|
fwrite($hFile, $sRow."\n");
|
||||||
|
}
|
||||||
|
fclose($hFile);
|
||||||
|
|
||||||
|
if (($this->iPosition + $this->iChunkSize) > count($this->aObjectsIDs)) {
|
||||||
|
// Next state
|
||||||
|
$this->sState = 'building-excel';
|
||||||
|
$sCode = 'building-excel';
|
||||||
|
$iPercentage = 80;
|
||||||
|
$sMessage = Dict::S('ExcelExporter:BuildingExcelFile');
|
||||||
|
} else {
|
||||||
|
$sCode = 'retrieving-data';
|
||||||
|
$this->iPosition += $this->iChunkSize;
|
||||||
|
$iPercentage = 5 + round(75 * ($this->iPosition / count($this->aObjectsIDs)));
|
||||||
|
$sMessage = Dict::S('ExcelExporter:RetrievingData');
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
case 'building-excel':
|
case 'building-excel':
|
||||||
$hFile = @fopen($this->GetDataFile(), 'rb');
|
$hFile = @fopen($this->GetDataFile(), 'rb');
|
||||||
if ($hFile === false)
|
if ($hFile === false) {
|
||||||
{
|
throw new Exception('ExcelExporter: Failed to open temporary data file: "'.$this->GetDataFile().'" for reading.');
|
||||||
throw new Exception('ExcelExporter: Failed to open temporary data file: "'.$this->GetDataFile().'" for reading.');
|
}
|
||||||
}
|
$sHeaders = fgets($hFile);
|
||||||
$sHeaders = fgets($hFile);
|
$aHeaders = json_decode($sHeaders, true);
|
||||||
$aHeaders = json_decode($sHeaders, true);
|
|
||||||
|
$aData = [];
|
||||||
$aData = array();
|
while ($sLine = fgets($hFile)) {
|
||||||
while($sLine = fgets($hFile))
|
$aRow = json_decode($sLine);
|
||||||
{
|
$aData[] = $aRow;
|
||||||
$aRow = json_decode($sLine);
|
}
|
||||||
$aData[] = $aRow;
|
fclose($hFile);
|
||||||
}
|
@unlink($this->GetDataFile());
|
||||||
fclose($hFile);
|
|
||||||
@unlink($this->GetDataFile());
|
$fStartExcel = microtime(true);
|
||||||
|
$writer = new XLSXWriter();
|
||||||
$fStartExcel = microtime(true);
|
$writer->setAuthor(UserRights::GetUserFriendlyName());
|
||||||
$writer = new XLSXWriter();
|
$writer->writeSheet($aData, 'Sheet1', $aHeaders);
|
||||||
$writer->setAuthor(UserRights::GetUserFriendlyName());
|
$fExcelTime = microtime(true) - $fStartExcel;
|
||||||
$writer->writeSheet($aData,'Sheet1', $aHeaders);
|
$this->aStatistics['excel_build_duration'] = $fExcelTime;
|
||||||
$fExcelTime = microtime(true) - $fStartExcel;
|
|
||||||
$this->aStatistics['excel_build_duration'] = $fExcelTime;
|
$fTime = microtime(true);
|
||||||
|
$writer->writeToFile($this->GetExcelFilePath());
|
||||||
$fTime = microtime(true);
|
$fExcelSaveTime = microtime(true) - $fTime;
|
||||||
$writer->writeToFile($this->GetExcelFilePath());
|
$this->aStatistics['excel_write_duration'] = $fExcelSaveTime;
|
||||||
$fExcelSaveTime = microtime(true) - $fTime;
|
|
||||||
$this->aStatistics['excel_write_duration'] = $fExcelSaveTime;
|
// Next state
|
||||||
|
$this->sState = 'done';
|
||||||
// Next state
|
$sCode = 'done';
|
||||||
$this->sState = 'done';
|
$iPercentage = 100;
|
||||||
$sCode = 'done';
|
$sMessage = Dict::S('ExcelExporter:Done');
|
||||||
$iPercentage = 100;
|
break;
|
||||||
$sMessage = Dict::S('ExcelExporter:Done');
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'done':
|
case 'done':
|
||||||
$this->sState = 'done';
|
$this->sState = 'done';
|
||||||
$sCode = 'done';
|
$sCode = 'done';
|
||||||
$iPercentage = 100;
|
$iPercentage = 100;
|
||||||
$sMessage = Dict::S('ExcelExporter:Done');
|
$sMessage = Dict::S('ExcelExporter:Done');
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
} catch (Exception $e) {
|
||||||
catch(Exception $e)
|
|
||||||
{
|
|
||||||
$sCode = 'error';
|
$sCode = 'error';
|
||||||
$sMessage = $e->getMessage();
|
$sMessage = $e->getMessage();
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->aStatistics['total_duration'] += microtime(true) - $fTime;
|
$this->aStatistics['total_duration'] += microtime(true) - $fTime;
|
||||||
$peak_memory = memory_get_peak_usage(true);
|
$peak_memory = memory_get_peak_usage(true);
|
||||||
if ($peak_memory > $this->aStatistics['peak_memory_usage'])
|
if ($peak_memory > $this->aStatistics['peak_memory_usage']) {
|
||||||
{
|
|
||||||
$this->aStatistics['peak_memory_usage'] = $peak_memory;
|
$this->aStatistics['peak_memory_usage'] = $peak_memory;
|
||||||
}
|
}
|
||||||
|
|
||||||
return array(
|
return [
|
||||||
'code' => $sCode,
|
'code' => $sCode,
|
||||||
'message' => $sMessage,
|
'message' => $sMessage,
|
||||||
'percentage' => $iPercentage,
|
'percentage' => $iPercentage,
|
||||||
);
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
public function GetExcelFilePath()
|
public function GetExcelFilePath()
|
||||||
{
|
{
|
||||||
if ($this->sOutputFilePath == null)
|
if ($this->sOutputFilePath == null) {
|
||||||
{
|
return utils::GetDataPath().'bulk_export/'.$this->sToken.'.xlsx';
|
||||||
return APPROOT.'data/bulk_export/'.$this->sToken.'.xlsx';
|
} else {
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return $this->sOutputFilePath;
|
return $this->sOutputFilePath;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function GetExcelFileFromToken($sToken)
|
public static function GetExcelFileFromToken($sToken)
|
||||||
{
|
{
|
||||||
return @file_get_contents(APPROOT.'data/bulk_export/'.$sToken.'.xlsx');
|
return @file_get_contents(utils::GetDataPath().'bulk_export/'.$sToken.'.xlsx');
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function CleanupFromToken($sToken)
|
public static function CleanupFromToken($sToken)
|
||||||
{
|
{
|
||||||
@unlink(APPROOT.'data/bulk_export/'.$sToken.'.status');
|
@unlink(utils::GetDataPath().'bulk_export/'.$sToken.'.status');
|
||||||
@unlink(APPROOT.'data/bulk_export/'.$sToken.'.data');
|
@unlink(utils::GetDataPath().'bulk_export/'.$sToken.'.data');
|
||||||
@unlink(APPROOT.'data/bulk_export/'.$sToken.'.xlsx');
|
@unlink(utils::GetDataPath().'bulk_export/'.$sToken.'.xlsx');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function Cleanup()
|
public function Cleanup()
|
||||||
{
|
{
|
||||||
self::CleanupFromToken($this->sToken);
|
self::CleanupFromToken($this->sToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Delete all files in the data/bulk_export directory which are older than 1 day
|
* Delete all files in the data/bulk_export directory which are older than 1 day
|
||||||
* unless a different delay is configured.
|
* unless a different delay is configured.
|
||||||
*/
|
*/
|
||||||
public static function CleanupOldFiles()
|
public static function CleanupOldFiles()
|
||||||
{
|
{
|
||||||
$aFiles = glob(APPROOT.'data/bulk_export/*.*');
|
$aFiles = glob(utils::GetDataPath().'bulk_export/*.*');
|
||||||
$iDelay = MetaModel::GetConfig()->Get('xlsx_exporter_cleanup_old_files_delay');
|
$iDelay = MetaModel::GetConfig()->Get('xlsx_exporter_cleanup_old_files_delay');
|
||||||
|
|
||||||
if($iDelay > 0)
|
if ($iDelay > 0) {
|
||||||
{
|
foreach ($aFiles as $sFile) {
|
||||||
foreach($aFiles as $sFile)
|
|
||||||
{
|
|
||||||
$iModificationTime = filemtime($sFile);
|
$iModificationTime = filemtime($sFile);
|
||||||
|
|
||||||
if($iModificationTime < (time() - $iDelay))
|
if ($iModificationTime < (time() - $iDelay)) {
|
||||||
{
|
|
||||||
// Temporary files older than one day are deleted
|
// Temporary files older than one day are deleted
|
||||||
//echo "Supposed to delete: '".$sFile." (Unix Modification Time: $iModificationTime)'\n";
|
//echo "Supposed to delete: '".$sFile." (Unix Modification Time: $iModificationTime)'\n";
|
||||||
@unlink($sFile);
|
@unlink($sFile);
|
||||||
@@ -352,189 +317,155 @@ class ExcelExporter
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function DisplayStatistics(Page $oPage)
|
public function DisplayStatistics(Page $oPage)
|
||||||
{
|
{
|
||||||
$aStats = array(
|
$aStats = [
|
||||||
'Number of objects exported' => $this->aStatistics['objects_count'],
|
'Number of objects exported' => $this->aStatistics['objects_count'],
|
||||||
'Total export duration' => sprintf('%.3f s', $this->aStatistics['total_duration']),
|
'Total export duration' => sprintf('%.3f s', $this->aStatistics['total_duration']),
|
||||||
'Data retrieval duration' => sprintf('%.3f s', $this->aStatistics['data_retrieval_duration']),
|
'Data retrieval duration' => sprintf('%.3f s', $this->aStatistics['data_retrieval_duration']),
|
||||||
'Excel build duration' => sprintf('%.3f s', $this->aStatistics['excel_build_duration']),
|
'Excel build duration' => sprintf('%.3f s', $this->aStatistics['excel_build_duration']),
|
||||||
'Excel write duration' => sprintf('%.3f s', $this->aStatistics['excel_write_duration']),
|
'Excel write duration' => sprintf('%.3f s', $this->aStatistics['excel_write_duration']),
|
||||||
'Peak memory usage' => self::HumanDisplay($this->aStatistics['peak_memory_usage']),
|
'Peak memory usage' => self::HumanDisplay($this->aStatistics['peak_memory_usage']),
|
||||||
);
|
];
|
||||||
|
|
||||||
if ($oPage instanceof CLIPage)
|
if ($oPage instanceof CLIPage) {
|
||||||
{
|
|
||||||
$oPage->add($this->GetStatistics('text'));
|
$oPage->add($this->GetStatistics('text'));
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
$oPage->add($this->GetStatistics('html'));
|
$oPage->add($this->GetStatistics('html'));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function GetStatistics($sFormat = 'html')
|
public function GetStatistics($sFormat = 'html')
|
||||||
{
|
{
|
||||||
$sStats = '';
|
$sStats = '';
|
||||||
$aStats = array(
|
$aStats = [
|
||||||
'Number of objects exported' => $this->aStatistics['objects_count'],
|
'Number of objects exported' => $this->aStatistics['objects_count'],
|
||||||
'Total export duration' => sprintf('%.3f s', $this->aStatistics['total_duration']),
|
'Total export duration' => sprintf('%.3f s', $this->aStatistics['total_duration']),
|
||||||
'Data retrieval duration' => sprintf('%.3f s', $this->aStatistics['data_retrieval_duration']),
|
'Data retrieval duration' => sprintf('%.3f s', $this->aStatistics['data_retrieval_duration']),
|
||||||
'Excel build duration' => sprintf('%.3f s', $this->aStatistics['excel_build_duration']),
|
'Excel build duration' => sprintf('%.3f s', $this->aStatistics['excel_build_duration']),
|
||||||
'Excel write duration' => sprintf('%.3f s', $this->aStatistics['excel_write_duration']),
|
'Excel write duration' => sprintf('%.3f s', $this->aStatistics['excel_write_duration']),
|
||||||
'Peak memory usage' => self::HumanDisplay($this->aStatistics['peak_memory_usage']),
|
'Peak memory usage' => self::HumanDisplay($this->aStatistics['peak_memory_usage']),
|
||||||
);
|
];
|
||||||
|
|
||||||
if ($sFormat == 'text')
|
if ($sFormat == 'text') {
|
||||||
{
|
foreach ($aStats as $sLabel => $sValue) {
|
||||||
foreach($aStats as $sLabel => $sValue)
|
|
||||||
{
|
|
||||||
$sStats .= "+------------------------------+----------+\n";
|
$sStats .= "+------------------------------+----------+\n";
|
||||||
$sStats .= sprintf("|%-30s|%10s|\n", $sLabel, $sValue);
|
$sStats .= sprintf("|%-30s|%10s|\n", $sLabel, $sValue);
|
||||||
}
|
}
|
||||||
$sStats .= "+------------------------------+----------+";
|
$sStats .= "+------------------------------+----------+";
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
$sStats .= '<table><tbody>';
|
$sStats .= '<table><tbody>';
|
||||||
foreach($aStats as $sLabel => $sValue)
|
foreach ($aStats as $sLabel => $sValue) {
|
||||||
{
|
|
||||||
$sStats .= "<tr><td>$sLabel</td><td>$sValue</td></tr>";
|
$sStats .= "<tr><td>$sLabel</td><td>$sValue</td></tr>";
|
||||||
}
|
}
|
||||||
$sStats .= '</tbody></table>';
|
$sStats .= '</tbody></table>';
|
||||||
|
|
||||||
}
|
}
|
||||||
return $sStats;
|
return $sStats;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function HumanDisplay($iSize)
|
public static function HumanDisplay($iSize)
|
||||||
{
|
{
|
||||||
$aUnits = array('B','KB','MB','GB','TB','PB');
|
$aUnits = ['B','KB','MB','GB','TB','PB'];
|
||||||
return @round($iSize/pow(1024,($i=floor(log($iSize,1024)))),2).' '.$aUnits[$i];
|
return @round($iSize / pow(1024, ($i = floor(log($iSize, 1024)))), 2).' '.$aUnits[$i];
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function CheckDataDir()
|
protected function CheckDataDir()
|
||||||
{
|
{
|
||||||
if(!is_dir(APPROOT."data/bulk_export"))
|
if (!is_dir(utils::GetDataPath()."bulk_export")) {
|
||||||
{
|
@mkdir(utils::GetDataPath()."bulk_export", 0777, true /* recursive */);
|
||||||
@mkdir(APPROOT."data/bulk_export", 0777, true /* recursive */);
|
|
||||||
clearstatcache();
|
clearstatcache();
|
||||||
}
|
}
|
||||||
if (!is_writable(APPROOT."data/bulk_export"))
|
if (!is_writable(utils::GetDataPath()."bulk_export")) {
|
||||||
{
|
throw new Exception('Data directory "'.utils::GetDataPath().'bulk_export" could not be written.');
|
||||||
throw new Exception('Data directory "'.APPROOT.'data/bulk_export" could not be written.');
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function GetStateFile($sToken = null)
|
protected function GetStateFile($sToken = null)
|
||||||
{
|
{
|
||||||
if ($sToken == null)
|
if ($sToken == null) {
|
||||||
{
|
|
||||||
$sToken = $this->sToken;
|
$sToken = $this->sToken;
|
||||||
}
|
}
|
||||||
return APPROOT."data/bulk_export/$sToken.status";
|
return utils::GetDataPath()."bulk_export/$sToken.status";
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function GetDataFile()
|
protected function GetDataFile()
|
||||||
{
|
{
|
||||||
return APPROOT.'data/bulk_export/'.$this->sToken.'.data';
|
return utils::GetDataPath().'bulk_export/'.$this->sToken.'.data';
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function GetNewToken()
|
protected function GetNewToken()
|
||||||
{
|
{
|
||||||
$iNum = rand();
|
$iNum = rand();
|
||||||
do
|
do {
|
||||||
{
|
|
||||||
$iNum++;
|
$iNum++;
|
||||||
$sToken = sprintf("%08x", $iNum);
|
$sToken = sprintf("%08x", $iNum);
|
||||||
$sFileName = $this->GetStateFile($sToken);
|
$sFileName = $this->GetStateFile($sToken);
|
||||||
$hFile = @fopen($sFileName, 'x');
|
$hFile = @fopen($sFileName, 'x');
|
||||||
}
|
} while ($hFile === false);
|
||||||
while($hFile === false);
|
|
||||||
|
|
||||||
fclose($hFile);
|
fclose($hFile);
|
||||||
return $sToken;
|
return $sToken;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function GetFieldsList($oSet, $bFieldsAdvanced = false, $bLocalize = true, $aFields = null)
|
protected function GetFieldsList($oSet, $bFieldsAdvanced = false, $bLocalize = true, $aFields = null)
|
||||||
{
|
{
|
||||||
$this->aFieldsList = array();
|
$this->aFieldsList = [];
|
||||||
|
|
||||||
$oAppContext = new ApplicationContext();
|
$oAppContext = new ApplicationContext();
|
||||||
$aClasses = $oSet->GetFilter()->GetSelectedClasses();
|
$aClasses = $oSet->GetFilter()->GetSelectedClasses();
|
||||||
$this->aAuthorizedClasses = array();
|
$this->aAuthorizedClasses = [];
|
||||||
foreach($aClasses as $sAlias => $sClassName)
|
foreach ($aClasses as $sAlias => $sClassName) {
|
||||||
{
|
if (UserRights::IsActionAllowed($sClassName, UR_ACTION_READ, $oSet) != UR_ALLOWED_NO) {
|
||||||
if (UserRights::IsActionAllowed($sClassName, UR_ACTION_READ, $oSet) != UR_ALLOWED_NO)
|
|
||||||
{
|
|
||||||
$this->aAuthorizedClasses[$sAlias] = $sClassName;
|
$this->aAuthorizedClasses[$sAlias] = $sClassName;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$aAttribs = array();
|
$aAttribs = [];
|
||||||
$this->aTableHeaders = array();
|
$this->aTableHeaders = [];
|
||||||
foreach($this->aAuthorizedClasses as $sAlias => $sClassName)
|
foreach ($this->aAuthorizedClasses as $sAlias => $sClassName) {
|
||||||
{
|
$aList[$sAlias] = [];
|
||||||
$aList[$sAlias] = array();
|
|
||||||
|
foreach (MetaModel::ListAttributeDefs($sClassName) as $sAttCode => $oAttDef) {
|
||||||
foreach(MetaModel::ListAttributeDefs($sClassName) as $sAttCode => $oAttDef)
|
if (is_null($aFields) || (count($aFields) == 0)) {
|
||||||
{
|
|
||||||
if (is_null($aFields) || (count($aFields) == 0))
|
|
||||||
{
|
|
||||||
// Standard list of attributes (no link sets)
|
// Standard list of attributes (no link sets)
|
||||||
if ($oAttDef->IsScalar() && ($oAttDef->IsWritable() || $oAttDef->IsExternalField()))
|
if ($oAttDef->IsScalar() && ($oAttDef->IsWritable() || $oAttDef->IsExternalField())) {
|
||||||
{
|
|
||||||
$sAttCodeEx = $oAttDef->IsExternalField() ? $oAttDef->GetKeyAttCode().'->'.$oAttDef->GetExtAttCode() : $sAttCode;
|
$sAttCodeEx = $oAttDef->IsExternalField() ? $oAttDef->GetKeyAttCode().'->'.$oAttDef->GetExtAttCode() : $sAttCode;
|
||||||
|
|
||||||
if ($oAttDef->IsExternalKey(EXTKEY_ABSOLUTE))
|
if ($oAttDef->IsExternalKey(EXTKEY_ABSOLUTE)) {
|
||||||
{
|
if ($bFieldsAdvanced) {
|
||||||
if ($bFieldsAdvanced)
|
|
||||||
{
|
|
||||||
$aList[$sAlias][$sAttCodeEx] = $oAttDef;
|
$aList[$sAlias][$sAttCodeEx] = $oAttDef;
|
||||||
|
|
||||||
if ($oAttDef->IsExternalKey(EXTKEY_RELATIVE))
|
if ($oAttDef->IsExternalKey(EXTKEY_RELATIVE)) {
|
||||||
{
|
$sRemoteClass = $oAttDef->GetTargetClass();
|
||||||
$sRemoteClass = $oAttDef->GetTargetClass();
|
foreach (MetaModel::GetReconcKeys($sRemoteClass) as $sRemoteAttCode) {
|
||||||
foreach(MetaModel::GetReconcKeys($sRemoteClass) as $sRemoteAttCode)
|
|
||||||
{
|
|
||||||
$this->aFieldsList[$sAlias][$sAttCode.'->'.$sRemoteAttCode] = MetaModel::GetAttributeDef($sRemoteClass, $sRemoteAttCode);
|
$this->aFieldsList[$sAlias][$sAttCode.'->'.$sRemoteAttCode] = MetaModel::GetAttributeDef($sRemoteClass, $sRemoteAttCode);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
// Any other attribute
|
// Any other attribute
|
||||||
$this->aFieldsList[$sAlias][$sAttCodeEx] = $oAttDef;
|
$this->aFieldsList[$sAlias][$sAttCodeEx] = $oAttDef;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
// User defined list of attributes
|
// User defined list of attributes
|
||||||
if (in_array($sAttCode, $aFields) || in_array($sAlias.'.'.$sAttCode, $aFields))
|
if (in_array($sAttCode, $aFields) || in_array($sAlias.'.'.$sAttCode, $aFields)) {
|
||||||
{
|
|
||||||
$this->aFieldsList[$sAlias][$sAttCode] = $oAttDef;
|
$this->aFieldsList[$sAlias][$sAttCode] = $oAttDef;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ($bFieldsAdvanced)
|
if ($bFieldsAdvanced) {
|
||||||
{
|
|
||||||
$this->aTableHeaders['id'] = '0';
|
$this->aTableHeaders['id'] = '0';
|
||||||
}
|
}
|
||||||
foreach($this->aFieldsList[$sAlias] as $sAttCodeEx => $oAttDef)
|
foreach ($this->aFieldsList[$sAlias] as $sAttCodeEx => $oAttDef) {
|
||||||
{
|
|
||||||
$sLabel = $bLocalize ? MetaModel::GetLabel($sClassName, $sAttCodeEx, isset($aParams['showMandatoryFields'])) : $sAttCodeEx;
|
$sLabel = $bLocalize ? MetaModel::GetLabel($sClassName, $sAttCodeEx, isset($aParams['showMandatoryFields'])) : $sAttCodeEx;
|
||||||
if($oAttDef instanceof AttributeDateTime)
|
if ($oAttDef instanceof AttributeDateTime) {
|
||||||
{
|
|
||||||
$this->aTableHeaders[$sLabel] = 'datetime';
|
$this->aTableHeaders[$sLabel] = 'datetime';
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
$this->aTableHeaders[$sLabel] = 'string';
|
$this->aTableHeaders[$sLabel] = 'string';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* @copyright Copyright (C) 2010-2024 Combodo SAS
|
* @copyright Copyright (C) 2010-2024 Combodo SAS
|
||||||
* @license http://opensource.org/licenses/AGPL-3.0
|
* @license http://opensource.org/licenses/AGPL-3.0
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* @copyright Copyright (C) 2010-2024 Combodo SAS
|
* @copyright Copyright (C) 2010-2024 Combodo SAS
|
||||||
* @license http://opensource.org/licenses/AGPL-3.0
|
* @license http://opensource.org/licenses/AGPL-3.0
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* @copyright Copyright (C) 2010-2024 Combodo SAS
|
* @copyright Copyright (C) 2010-2024 Combodo SAS
|
||||||
* @license http://opensource.org/licenses/AGPL-3.0
|
* @license http://opensource.org/licenses/AGPL-3.0
|
||||||
@@ -6,4 +7,4 @@
|
|||||||
|
|
||||||
class BulkChangeException extends CoreException
|
class BulkChangeException extends CoreException
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* @copyright Copyright (C) 2010-2024 Combodo SAS
|
* @copyright Copyright (C) 2010-2024 Combodo SAS
|
||||||
* @license http://opensource.org/licenses/AGPL-3.0
|
* @license http://opensource.org/licenses/AGPL-3.0
|
||||||
@@ -6,4 +7,4 @@
|
|||||||
|
|
||||||
class CSVParserException extends CoreException
|
class CSVParserException extends CoreException
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* @copyright Copyright (C) 2010-2024 Combodo SAS
|
* @copyright Copyright (C) 2010-2024 Combodo SAS
|
||||||
* @license http://opensource.org/licenses/AGPL-3.0
|
* @license http://opensource.org/licenses/AGPL-3.0
|
||||||
@@ -6,4 +7,4 @@
|
|||||||
|
|
||||||
class ConfigException extends CoreException
|
class ConfigException extends CoreException
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* @copyright Copyright (C) 2010-2024 Combodo SAS
|
* @copyright Copyright (C) 2010-2024 Combodo SAS
|
||||||
* @license http://opensource.org/licenses/AGPL-3.0
|
* @license http://opensource.org/licenses/AGPL-3.0
|
||||||
@@ -63,21 +64,20 @@ class CoreCannotSaveObjectException extends CoreException
|
|||||||
public function getTextMessage()
|
public function getTextMessage()
|
||||||
{
|
{
|
||||||
$sTitle = Dict::S('UI:Error:SaveFailed');
|
$sTitle = Dict::S('UI:Error:SaveFailed');
|
||||||
$sContent = $sTitle;
|
$sContent = $sTitle;
|
||||||
|
|
||||||
if (count($this->aIssues) == 1) {
|
if (count($this->aIssues) == 1) {
|
||||||
$sIssue = reset($this->aIssues);
|
$sIssue = reset($this->aIssues);
|
||||||
$sContent .= $sIssue;
|
$sContent .= $sIssue;
|
||||||
} else {
|
} else {
|
||||||
foreach ($this->aIssues as $sError) {
|
foreach ($this->aIssues as $sError) {
|
||||||
$sContent .= " " . $sError . ", ";
|
$sContent .= " ".$sError.", ";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return $sContent;
|
return $sContent;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public function getIssues()
|
public function getIssues()
|
||||||
{
|
{
|
||||||
return $this->aIssues;
|
return $this->aIssues;
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* @copyright Copyright (C) 2010-2024 Combodo SAS
|
* @copyright Copyright (C) 2010-2024 Combodo SAS
|
||||||
* @license http://opensource.org/licenses/AGPL-3.0
|
* @license http://opensource.org/licenses/AGPL-3.0
|
||||||
@@ -35,10 +36,10 @@ class CoreException extends Exception
|
|||||||
}
|
}
|
||||||
if (count($this->m_aContextData) > 0) {
|
if (count($this->m_aContextData) > 0) {
|
||||||
$sMessage .= ": ";
|
$sMessage .= ": ";
|
||||||
$aContextItems = array();
|
$aContextItems = [];
|
||||||
foreach ($this->m_aContextData as $sKey => $value) {
|
foreach ($this->m_aContextData as $sKey => $value) {
|
||||||
if (is_array($value)) {
|
if (is_array($value)) {
|
||||||
$aPairs = array();
|
$aPairs = [];
|
||||||
foreach ($value as $key => $val) {
|
foreach ($value as $key => $val) {
|
||||||
if (is_array($val)) {
|
if (is_array($val)) {
|
||||||
$aPairs[] = $key.'=>('.implode(', ', $val).')';
|
$aPairs[] = $key.'=>('.implode(', ', $val).')';
|
||||||
@@ -109,4 +110,4 @@ class CoreException extends Exception
|
|||||||
{
|
{
|
||||||
return $this->m_aContextData;
|
return $this->m_aContextData;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* @copyright Copyright (C) 2010-2024 Combodo SAS
|
* @copyright Copyright (C) 2010-2024 Combodo SAS
|
||||||
* @license http://opensource.org/licenses/AGPL-3.0
|
* @license http://opensource.org/licenses/AGPL-3.0
|
||||||
@@ -9,5 +10,4 @@
|
|||||||
*/
|
*/
|
||||||
class CorePortalInvalidActionRuleException extends CoreException
|
class CorePortalInvalidActionRuleException extends CoreException
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* @copyright Copyright (C) 2010-2024 Combodo SAS
|
* @copyright Copyright (C) 2010-2024 Combodo SAS
|
||||||
* @license http://opensource.org/licenses/AGPL-3.0
|
* @license http://opensource.org/licenses/AGPL-3.0
|
||||||
@@ -14,4 +15,4 @@ class CoreTemplateException extends CoreException
|
|||||||
$sMessage = "Twig Exception when rendering '$sTemplatePath' : ".$oTwigException->getMessage();
|
$sMessage = "Twig Exception when rendering '$sTemplatePath' : ".$oTwigException->getMessage();
|
||||||
parent::__construct($sMessage, null, '', $oTwigException);
|
parent::__construct($sMessage, null, '', $oTwigException);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* @copyright Copyright (C) 2010-2024 Combodo SAS
|
* @copyright Copyright (C) 2010-2024 Combodo SAS
|
||||||
* @license http://opensource.org/licenses/AGPL-3.0
|
* @license http://opensource.org/licenses/AGPL-3.0
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* @copyright Copyright (C) 2010-2024 Combodo SAS
|
* @copyright Copyright (C) 2010-2024 Combodo SAS
|
||||||
* @license http://opensource.org/licenses/AGPL-3.0
|
* @license http://opensource.org/licenses/AGPL-3.0
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* @copyright Copyright (C) 2010-2024 Combodo SAS
|
* @copyright Copyright (C) 2010-2024 Combodo SAS
|
||||||
* @license http://opensource.org/licenses/AGPL-3.0
|
* @license http://opensource.org/licenses/AGPL-3.0
|
||||||
@@ -6,4 +7,4 @@
|
|||||||
|
|
||||||
class DeleteException extends CoreException
|
class DeleteException extends CoreException
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,10 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @copyright Copyright (C) 2010-2026 Combodo SAS
|
||||||
|
* @license http://opensource.org/licenses/AGPL-3.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
class ForgotPasswordApplicationException extends Exception
|
||||||
|
{
|
||||||
|
}
|
||||||
10
application/exceptions/ForgotPasswordUserInputException.php
Normal file
10
application/exceptions/ForgotPasswordUserInputException.php
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @copyright Copyright (C) 2010-2026 Combodo SAS
|
||||||
|
* @license http://opensource.org/licenses/AGPL-3.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
class ForgotPasswordUserInputException extends Exception
|
||||||
|
{
|
||||||
|
}
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* @copyright Copyright (C) 2010-2024 Combodo SAS
|
* @copyright Copyright (C) 2010-2024 Combodo SAS
|
||||||
* @license http://opensource.org/licenses/AGPL-3.0
|
* @license http://opensource.org/licenses/AGPL-3.0
|
||||||
|
|||||||
@@ -12,13 +12,13 @@ class InvalidExternalKeyValueException extends CoreUnexpectedValue
|
|||||||
|
|
||||||
public function __construct($oObject, $sAttCode, $aContextData = null, $oPrevious = null)
|
public function __construct($oObject, $sAttCode, $aContextData = null, $oPrevious = null)
|
||||||
{
|
{
|
||||||
$aContextData[self::ENUM_PARAMS_OBJECT] = get_class($oObject) . '::' . $oObject->GetKey();
|
$aContextData[self::ENUM_PARAMS_OBJECT] = get_class($oObject).'::'.$oObject->GetKey();
|
||||||
$aContextData[self::ENUM_PARAMS_ATTCODE] = $sAttCode;
|
$aContextData[self::ENUM_PARAMS_ATTCODE] = $sAttCode;
|
||||||
$aContextData[self::ENUM_PARAMS_ATTVALUE] = $oObject->Get($sAttCode);
|
$aContextData[self::ENUM_PARAMS_ATTVALUE] = $oObject->Get($sAttCode);
|
||||||
|
|
||||||
$oCurrentUser = UserRights::GetUserObject();
|
$oCurrentUser = UserRights::GetUserObject();
|
||||||
if (false === is_null($oCurrentUser)) {
|
if (false === is_null($oCurrentUser)) {
|
||||||
$aContextData[self::ENUM_PARAMS_USER] = get_class($oCurrentUser) . '::' . $oCurrentUser->GetKey();
|
$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);
|
parent::__construct('Attribute pointing to an object that is either non existing or not readable by the current user', $aContextData, '', $oPrevious);
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* @copyright Copyright (C) 2010-2024 Combodo SAS
|
* @copyright Copyright (C) 2010-2024 Combodo SAS
|
||||||
* @license http://opensource.org/licenses/AGPL-3.0
|
* @license http://opensource.org/licenses/AGPL-3.0
|
||||||
@@ -11,4 +12,4 @@
|
|||||||
*/
|
*/
|
||||||
class InvalidPasswordAttributeOneWayPassword extends CoreException
|
class InvalidPasswordAttributeOneWayPassword extends CoreException
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @copyright Copyright (C) 2010-2024 Combodo SAS
|
* @copyright Copyright (C) 2010-2024 Combodo SAS
|
||||||
* @license http://opensource.org/licenses/AGPL-3.0
|
* @license http://opensource.org/licenses/AGPL-3.0
|
||||||
@@ -10,4 +11,4 @@ use Exception;
|
|||||||
|
|
||||||
class PageNotFoundException extends Exception
|
class PageNotFoundException extends Exception
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* @copyright Copyright (C) 2010-2024 Combodo SAS
|
* @copyright Copyright (C) 2010-2024 Combodo SAS
|
||||||
* @license http://opensource.org/licenses/AGPL-3.0
|
* @license http://opensource.org/licenses/AGPL-3.0
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* @copyright Copyright (C) 2010-2024 Combodo SAS
|
* @copyright Copyright (C) 2010-2024 Combodo SAS
|
||||||
* @license http://opensource.org/licenses/AGPL-3.0
|
* @license http://opensource.org/licenses/AGPL-3.0
|
||||||
@@ -6,4 +7,4 @@
|
|||||||
|
|
||||||
class SynchroExceptionNotStarted extends CoreException
|
class SynchroExceptionNotStarted extends CoreException
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* @copyright Copyright (C) 2010-2024 Combodo SAS
|
* @copyright Copyright (C) 2010-2024 Combodo SAS
|
||||||
* @license http://opensource.org/licenses/AGPL-3.0
|
* @license http://opensource.org/licenses/AGPL-3.0
|
||||||
@@ -6,4 +7,4 @@
|
|||||||
|
|
||||||
class UserRightException extends CoreException
|
class UserRightException extends CoreException
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* @copyright Copyright (C) 2010-2024 Combodo SAS
|
* @copyright Copyright (C) 2010-2024 Combodo SAS
|
||||||
* @license http://opensource.org/licenses/AGPL-3.0
|
* @license http://opensource.org/licenses/AGPL-3.0
|
||||||
@@ -6,4 +7,4 @@
|
|||||||
|
|
||||||
class DictException extends CoreException
|
class DictException extends CoreException
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* @copyright Copyright (C) 2010-2024 Combodo SAS
|
* @copyright Copyright (C) 2010-2024 Combodo SAS
|
||||||
* @license http://opensource.org/licenses/AGPL-3.0
|
* @license http://opensource.org/licenses/AGPL-3.0
|
||||||
@@ -8,9 +9,9 @@ class DictExceptionMissingString extends DictException
|
|||||||
{
|
{
|
||||||
public function __construct($sLanguageCode, $sStringCode)
|
public function __construct($sLanguageCode, $sStringCode)
|
||||||
{
|
{
|
||||||
$aContext = array();
|
$aContext = [];
|
||||||
$aContext['language_code'] = $sLanguageCode;
|
$aContext['language_code'] = $sLanguageCode;
|
||||||
$aContext['string_code'] = $sStringCode;
|
$aContext['string_code'] = $sStringCode;
|
||||||
parent::__construct('Missing localized string', $aContext);
|
parent::__construct('Missing localized string', $aContext);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user