mirror of
https://github.com/Combodo/iTop.git
synced 2026-02-13 23:44:11 +01:00
Compare commits
1339 Commits
support/2.
...
1.0.8
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
35215cf62f | ||
|
|
66273ebd39 | ||
|
|
eebc29d2bb | ||
|
|
512b415bd6 | ||
|
|
906c8855b0 | ||
|
|
97d322a059 | ||
|
|
ada7f30793 | ||
|
|
b065d13374 | ||
|
|
1f092f8418 | ||
|
|
65d6947e52 | ||
|
|
ba54b47f7d | ||
|
|
adb4e77c8d | ||
|
|
d3cf7176da | ||
|
|
1cfb52d220 | ||
|
|
18d5231900 | ||
|
|
e6539ccb6e | ||
|
|
96332b7885 | ||
|
|
557b9be795 | ||
|
|
75ebecddd5 | ||
|
|
2d130cbba8 | ||
|
|
06acac97ba | ||
|
|
2d6d1132c7 | ||
|
|
ed0e16494d | ||
|
|
a765eb8725 | ||
|
|
5d7ae38adf | ||
|
|
2e08ae571a | ||
|
|
37522459a8 | ||
|
|
db8c26da17 | ||
|
|
93c91c4077 | ||
|
|
e4b3871947 | ||
|
|
b2474d3368 | ||
|
|
6cd0670d6b | ||
|
|
e9f81bd978 | ||
|
|
0cc5dc0471 | ||
|
|
20ce42b24b | ||
|
|
d86e904e18 | ||
|
|
5a46bb8461 | ||
|
|
05a0d61244 | ||
|
|
80b3212a19 | ||
|
|
794d4f1e0e | ||
|
|
389b61d3a8 | ||
|
|
0948e80060 | ||
|
|
9520d2794f | ||
|
|
e2c67dfcc4 | ||
|
|
4e0eed6e13 | ||
|
|
94b9a9bb75 | ||
|
|
0c90b701ea | ||
|
|
58961cd4ec | ||
|
|
1453558f3e | ||
|
|
c6df0b6d7d | ||
|
|
7c3659d5ba | ||
|
|
dd942997cb | ||
|
|
57fea03745 | ||
|
|
827b4b5bbe | ||
|
|
7de59c1977 | ||
|
|
c34c4bc09d | ||
|
|
bced819b3f | ||
|
|
23136bdf00 | ||
|
|
98c371c5cf | ||
|
|
1e0415e902 | ||
|
|
dbada2f72a | ||
|
|
9694e9848d | ||
|
|
fe87700135 | ||
|
|
7107c2f616 | ||
|
|
92e0f101d7 | ||
|
|
29624bc5c5 | ||
|
|
d09f3f4f83 | ||
|
|
f774a90b7e | ||
|
|
fef8038f70 | ||
|
|
2806a76c1d | ||
|
|
328ec52c88 | ||
|
|
70734e2b71 | ||
|
|
bb892cc180 | ||
|
|
4618f12d8a | ||
|
|
d12e2e592a | ||
|
|
6a25933744 | ||
|
|
208ccfe3ab | ||
|
|
f74c78d61c | ||
|
|
6176af089c | ||
|
|
a35b2d83b7 | ||
|
|
8902d6e532 | ||
|
|
07bd6b8539 | ||
|
|
1148449bb7 | ||
|
|
11d418fd49 | ||
|
|
ace676dc24 | ||
|
|
8122270476 | ||
|
|
1f66d53ab4 | ||
|
|
dfaeca43e4 | ||
|
|
5b04143711 | ||
|
|
bd14096d43 | ||
|
|
3b20be05cb | ||
|
|
fdec608c3e | ||
|
|
72cb3de50d | ||
|
|
c03d32b423 | ||
|
|
94f9b16c03 | ||
|
|
311aeb0b07 | ||
|
|
68fe3f01be | ||
|
|
7ce94486bd | ||
|
|
6523b34d58 | ||
|
|
be20705449 | ||
|
|
e7abaa2838 | ||
|
|
8d73eb6dff | ||
|
|
f84995a58f | ||
|
|
7f66e26b5f | ||
|
|
a6639b067f | ||
|
|
8a6d66effd | ||
|
|
6885d64124 | ||
|
|
6fa153ae8b | ||
|
|
e226222c2a | ||
|
|
aca0143e89 | ||
|
|
1968c60770 | ||
|
|
26014f410a | ||
|
|
8912618732 | ||
|
|
7bee718a13 | ||
|
|
2705543efd | ||
|
|
1e6b885301 | ||
|
|
c768e18e2b | ||
|
|
d4b93f3bf0 | ||
|
|
6354c62c2b | ||
|
|
cf8a12fe95 | ||
|
|
36804dfcf4 | ||
|
|
6966c0498a | ||
|
|
bbffc40ee0 | ||
|
|
1b7473365d | ||
|
|
0b84e809f6 | ||
|
|
a858362622 | ||
|
|
d195c2b4c9 | ||
|
|
28b75f29e5 | ||
|
|
9d8a7bf561 | ||
|
|
8064a20718 | ||
|
|
f301a283e2 | ||
|
|
e6a8f492d5 | ||
|
|
336637a7a4 | ||
|
|
0e5a501b2a | ||
|
|
59af58a173 | ||
|
|
7f922560ba | ||
|
|
d2e286345e | ||
|
|
fb120bdc7c | ||
|
|
5548997f3e | ||
|
|
156828c448 | ||
|
|
04ef2b0454 | ||
|
|
076d2e3d46 | ||
|
|
0c6ab86e54 | ||
|
|
876db3e58f | ||
|
|
5f7fe345cc | ||
|
|
cb6f78c9e3 | ||
|
|
8c86908652 | ||
|
|
7e69256cb4 | ||
|
|
83e3c089a4 | ||
|
|
0d1059a8fc | ||
|
|
e2f15ca24a | ||
|
|
7628b85b70 | ||
|
|
525f600c18 | ||
|
|
0ffa2850ea | ||
|
|
fa3610cfee | ||
|
|
898ee95a2c | ||
|
|
730570f1f8 | ||
|
|
80ce1eb125 | ||
|
|
79909fadc0 | ||
|
|
746b47bb0e | ||
|
|
150d3e096d | ||
|
|
23afee514d | ||
|
|
48c5698f08 | ||
|
|
1a4ee0f977 | ||
|
|
1ca39618e1 | ||
|
|
7bb1f9f423 | ||
|
|
21c2574cd9 | ||
|
|
6d9923be68 | ||
|
|
839bbc425f | ||
|
|
70cc19768a | ||
|
|
873d109b98 | ||
|
|
a81950571a | ||
|
|
bcd9679957 | ||
|
|
2c10913fe5 | ||
|
|
0342b89481 | ||
|
|
3fd55c6dd6 | ||
|
|
c15b3462d1 | ||
|
|
32f05ea917 | ||
|
|
6a50b55a2a | ||
|
|
72f11c6a4d | ||
|
|
609ea47f7b | ||
|
|
74b3cfd46c | ||
|
|
f7ea6c09cd | ||
|
|
526a7f9817 | ||
|
|
5ccb1ef72a | ||
|
|
180da03f08 | ||
|
|
7ec7626aa0 | ||
|
|
f92a980b4d | ||
|
|
5d7582bb6f | ||
|
|
7a40db94fb | ||
|
|
843798505a | ||
|
|
bf13f9fc8a | ||
|
|
289171b9f1 | ||
|
|
9b065ffb0a | ||
|
|
96d888fcf3 | ||
|
|
a182a37139 | ||
|
|
23c15c1b6c | ||
|
|
866e4ab995 | ||
|
|
75730eeea0 | ||
|
|
58fd8709be | ||
|
|
f18ea18a5b | ||
|
|
1904bfdba6 | ||
|
|
e1949cd3eb | ||
|
|
1b2d3d1e84 | ||
|
|
0b95dbee7f | ||
|
|
db593ff85e | ||
|
|
1f750bb12d | ||
|
|
4ee66377ce | ||
|
|
432a950f8c | ||
|
|
bbc751bee4 | ||
|
|
a77ba2fbab | ||
|
|
5b60ec9edf | ||
|
|
3103f361a4 | ||
|
|
621295199c | ||
|
|
c1a7a36896 | ||
|
|
d5fe653e51 | ||
|
|
fc2fb235a2 | ||
|
|
d7211509bd | ||
|
|
c182b1a01f | ||
|
|
15e5e21a89 | ||
|
|
ee0d231426 | ||
|
|
3282b46c9b | ||
|
|
05649ba50f | ||
|
|
40efc4cbb1 | ||
|
|
30034d381b | ||
|
|
986eb90546 | ||
|
|
eb41d3e2ef | ||
|
|
c6b16bb52e | ||
|
|
95adbbb58f | ||
|
|
60f5c60059 | ||
|
|
c0284ecc3b | ||
|
|
fc7b772ba3 | ||
|
|
011d742ae3 | ||
|
|
5b496f4d15 | ||
|
|
97f4c32271 | ||
|
|
c002ca7902 | ||
|
|
ff22074418 | ||
|
|
84968ff550 | ||
|
|
46151c87c0 | ||
|
|
75a900c6f8 | ||
|
|
e8c9d99783 | ||
|
|
1600302ad9 | ||
|
|
a9c3a1b782 | ||
|
|
74848254a4 | ||
|
|
d7d9bfe0fd | ||
|
|
dd96dec100 | ||
|
|
16ff51f3b7 | ||
|
|
27c651b33c | ||
|
|
32375265cb | ||
|
|
0cba163dc9 | ||
|
|
fd1e17cc32 | ||
|
|
d85e1906b7 | ||
|
|
f8df84aa7b | ||
|
|
c26b9459bb | ||
|
|
4f7676c42d | ||
|
|
ceddafaebe | ||
|
|
950640babe | ||
|
|
11e6be1037 | ||
|
|
29d963317f | ||
|
|
dd300e075c | ||
|
|
774ace2302 | ||
|
|
bbfddea93d | ||
|
|
c5c7fd5c85 | ||
|
|
5d4b9f4a89 | ||
|
|
d01caaf4e4 | ||
|
|
f895821db9 | ||
|
|
19f34d1a72 | ||
|
|
7ff1a03a3c | ||
|
|
eadc3b72c2 | ||
|
|
c06f8e9a98 | ||
|
|
6675d7d42a | ||
|
|
afc118e9c2 | ||
|
|
f36fcb2a2d | ||
|
|
f062af367d | ||
|
|
29d24faf52 | ||
|
|
33f3f2810e | ||
|
|
fad00200b6 | ||
|
|
56ef6feadf | ||
|
|
2be16f9078 | ||
|
|
6874aed4a2 | ||
|
|
07b8830436 | ||
|
|
39d3e00ba1 | ||
|
|
ffa43160bf | ||
|
|
a45d1336f4 | ||
|
|
5a287fabba | ||
|
|
da86ee4114 | ||
|
|
5157788afe | ||
|
|
386e25efd6 | ||
|
|
649e2f8e6a | ||
|
|
3c3d744747 | ||
|
|
1371eee826 | ||
|
|
6645a5053f | ||
|
|
e2a3e0e74f | ||
|
|
401f82062a | ||
|
|
5a01a76f80 | ||
|
|
3e5520d079 | ||
|
|
beef2a89a3 | ||
|
|
2f920cbb46 | ||
|
|
feae36e5b8 | ||
|
|
92ae0e72e1 | ||
|
|
ed030403aa | ||
|
|
dfc894f6fd | ||
|
|
368b49ef8f | ||
|
|
ccfd3848fb | ||
|
|
ea59f7bc23 | ||
|
|
9d6ed7f489 | ||
|
|
0aa006f7c4 | ||
|
|
c669d6951b | ||
|
|
9412f260ae | ||
|
|
9781a11988 | ||
|
|
1ed0210fe2 | ||
|
|
1ce5ec73ea | ||
|
|
98304e2bda | ||
|
|
04fc58b55c | ||
|
|
096c3a3f13 | ||
|
|
87e22163d7 | ||
|
|
4cc8b89f4e | ||
|
|
19809249a2 | ||
|
|
7347eed3ac | ||
|
|
69d816e345 | ||
|
|
4008cb7688 | ||
|
|
41a1bede70 | ||
|
|
e12845e412 | ||
|
|
b30ad45792 | ||
|
|
84a11fb3c1 | ||
|
|
ee39a387db | ||
|
|
e3c6ac814e | ||
|
|
d668d65c70 | ||
|
|
e21e7c9cf0 | ||
|
|
27a0de1da1 | ||
|
|
d76e54996c | ||
|
|
a4710f7542 | ||
|
|
98a9c680c5 | ||
|
|
a92157f763 | ||
|
|
412f1a394f | ||
|
|
dba6e8ce1a | ||
|
|
a127ca9ca0 | ||
|
|
0b5ee1e05c | ||
|
|
f94e86ecea | ||
|
|
fe770f36c5 | ||
|
|
cf83bc7364 | ||
|
|
76982a2846 | ||
|
|
4cedd30625 | ||
|
|
a86079c477 | ||
|
|
128a237392 | ||
|
|
0ecfffe413 | ||
|
|
ef3bdd63a4 | ||
|
|
585135c6c7 | ||
|
|
b3faa96a45 | ||
|
|
6f04525cdf | ||
|
|
03834fedb8 | ||
|
|
6bde8e867f | ||
|
|
0e3d195250 | ||
|
|
fae8c9edbd | ||
|
|
133d267aca | ||
|
|
166986f336 | ||
|
|
f76d649d1a | ||
|
|
30747b92c7 | ||
|
|
12ce718662 | ||
|
|
a1cdb46663 | ||
|
|
824d8398a3 | ||
|
|
406774aa15 | ||
|
|
dd8712e2e8 | ||
|
|
767bcdf117 | ||
|
|
5e060737df | ||
|
|
d9bf0fe012 | ||
|
|
93c9783b1a | ||
|
|
e9c1467026 | ||
|
|
863cb4cad6 | ||
|
|
94b70fc473 | ||
|
|
4dc383cba8 | ||
|
|
55d8a2316a | ||
|
|
fe8f274c14 | ||
|
|
72fad49c4e | ||
|
|
888d0775e6 | ||
|
|
db19f71758 | ||
|
|
a259443735 | ||
|
|
58e8ca1f50 | ||
|
|
ab79426508 | ||
|
|
7e61917521 | ||
|
|
e42aab30a5 | ||
|
|
a79ef0bd51 | ||
|
|
5d88391109 | ||
|
|
c56c04d84d | ||
|
|
f2b8f50a94 | ||
|
|
9de11a29fb | ||
|
|
6537e00453 | ||
|
|
dd5f4909da | ||
|
|
ed67df734f | ||
|
|
44894526f1 | ||
|
|
de78963b30 | ||
|
|
948fd6f0ce | ||
|
|
214dbeef5b | ||
|
|
f2fbd8457d | ||
|
|
6a432c6a25 | ||
|
|
e96a8387a0 | ||
|
|
f3576cffb0 | ||
|
|
c5625e6a8d | ||
|
|
3d2a844fef | ||
|
|
110a030902 | ||
|
|
5ccd885607 | ||
|
|
e5c6efbe69 | ||
|
|
65b8132914 | ||
|
|
3c2130aa72 | ||
|
|
e70a2f75d3 | ||
|
|
fe8e6ba4b0 | ||
|
|
008614fde6 | ||
|
|
ac6e60f5a1 | ||
|
|
bf18d623d6 | ||
|
|
10d04756ee | ||
|
|
6e927114e0 | ||
|
|
682c24a873 | ||
|
|
d4b4ced649 | ||
|
|
c2589492d9 | ||
|
|
15c9cf926e | ||
|
|
78d4c8c7c7 | ||
|
|
d9e8eed084 | ||
|
|
ebe86d09ee | ||
|
|
5e5d368299 | ||
|
|
f990a83453 | ||
|
|
c6325dce8e | ||
|
|
bbca1625fb | ||
|
|
53975d1d8f | ||
|
|
1358bf9b7f | ||
|
|
7c17be4db6 | ||
|
|
367a92b711 | ||
|
|
0a3201dd41 | ||
|
|
d82690dd84 | ||
|
|
7f9e4385ac | ||
|
|
aa3e284af3 | ||
|
|
a941e5f752 | ||
|
|
b1878f7265 | ||
|
|
b106a54c50 | ||
|
|
002da0b387 | ||
|
|
6b9e723a45 | ||
|
|
b54e457cbb | ||
|
|
e750dd53d8 | ||
|
|
da6a55504e | ||
|
|
b58356c42e | ||
|
|
524e43b8c4 | ||
|
|
a80bd6f2b9 | ||
|
|
08eb9ee630 | ||
|
|
05485b838e | ||
|
|
029fe6882d | ||
|
|
b31eb6aab9 | ||
|
|
a96c194676 | ||
|
|
0d85331bca | ||
|
|
e9dec8ae05 | ||
|
|
6a6a0ffa24 | ||
|
|
87623fba3d | ||
|
|
a7619f2820 | ||
|
|
cff53d71ba | ||
|
|
71708cfbc7 | ||
|
|
e05b3a5fb9 | ||
|
|
bfcb1fdb30 | ||
|
|
cc4e1ea104 | ||
|
|
5485897bbb | ||
|
|
27f343e543 | ||
|
|
cca79735fc | ||
|
|
c48bbfd32a | ||
|
|
3ae2058f6f | ||
|
|
0a63568715 | ||
|
|
f878eea68d | ||
|
|
8ad2b8091c | ||
|
|
d6ca08efb8 | ||
|
|
ba8a2c1b15 | ||
|
|
0ae0336e04 | ||
|
|
8df0ef6af9 | ||
|
|
d77c77c03b | ||
|
|
5967895561 | ||
|
|
6e754d4fa5 | ||
|
|
165fd0e700 | ||
|
|
d100ce8005 | ||
|
|
770f5a7b67 | ||
|
|
a993f6a80b | ||
|
|
c8bb710d21 | ||
|
|
d963fbd8cf | ||
|
|
beda8e2810 | ||
|
|
083f8d69c2 | ||
|
|
1c16eeb5e4 | ||
|
|
ecc0b57b31 | ||
|
|
be9f6eff29 | ||
|
|
900e8ac6d7 | ||
|
|
2fcea4d02e | ||
|
|
1927fc743a | ||
|
|
6aff09eaf7 | ||
|
|
54e9830a3b | ||
|
|
a45819dbf0 | ||
|
|
e8aaec5789 | ||
|
|
d16c0ffef9 | ||
|
|
24ad593dc8 | ||
|
|
0b67828ab9 | ||
|
|
8a1a78444d | ||
|
|
4552bc0778 | ||
|
|
3a113e31fb | ||
|
|
8a666b09d6 | ||
|
|
0d9dc34a08 | ||
|
|
c7ca1eeab5 | ||
|
|
02265135e3 | ||
|
|
2c1bf665c3 | ||
|
|
60b6fcc783 | ||
|
|
53adb37f43 | ||
|
|
a6fe564a95 | ||
|
|
4945f25d49 | ||
|
|
e5f3daf88a | ||
|
|
cc3e6d64e1 | ||
|
|
8024aad43d | ||
|
|
757dbb8b25 | ||
|
|
b370deaac9 | ||
|
|
026b7e1836 | ||
|
|
d03b924240 | ||
|
|
97a047e38f | ||
|
|
5be800cfce | ||
|
|
956b597e50 | ||
|
|
57100dee9f | ||
|
|
c3cc1afec1 | ||
|
|
7fe24f58f3 | ||
|
|
e4160c7cf2 | ||
|
|
7d87768ec4 | ||
|
|
9946e6c41a | ||
|
|
02b483e33e | ||
|
|
7b6481efbd | ||
|
|
efef582119 | ||
|
|
5056e561fe | ||
|
|
4400cfde62 | ||
|
|
5a39581c60 | ||
|
|
4eab0e6450 | ||
|
|
f3b66a44ee | ||
|
|
558f108520 | ||
|
|
07a93d12e2 | ||
|
|
ce127278bb | ||
|
|
887946144c | ||
|
|
cc887c29fd | ||
|
|
460836852e | ||
|
|
208d7ee7ba | ||
|
|
3d92b73ae5 | ||
|
|
deddb0824b | ||
|
|
3718899663 | ||
|
|
7f30d74f30 | ||
|
|
21199fce34 | ||
|
|
ad821e7d9c | ||
|
|
881fc2a1de | ||
|
|
44ee6baddb | ||
|
|
42d782740e | ||
|
|
cf16229948 | ||
|
|
a25427f4c6 | ||
|
|
04b2f7c836 | ||
|
|
0f917af55a | ||
|
|
daaed4696e | ||
|
|
5f52c273d9 | ||
|
|
b8d35e4783 | ||
|
|
149dff4b4d | ||
|
|
f235e0cd66 | ||
|
|
e47e02932a | ||
|
|
4544bba652 | ||
|
|
9445e12254 | ||
|
|
951945a607 | ||
|
|
34f8fff01c | ||
|
|
8d45e48ce1 | ||
|
|
ed26f1cecc | ||
|
|
bc298afda3 | ||
|
|
1fc290587c | ||
|
|
77fa02fcf9 | ||
|
|
d445551031 | ||
|
|
ebfe9da464 | ||
|
|
fdd79e91f0 | ||
|
|
94a09493b0 | ||
|
|
56dbbb09dc | ||
|
|
f019e05af5 | ||
|
|
838c4f123c | ||
|
|
2043010aad | ||
|
|
cda18b950e | ||
|
|
acf28ca4aa | ||
|
|
864ded2102 | ||
|
|
5cdc58846b | ||
|
|
45cd96eb0d | ||
|
|
c8335499fd | ||
|
|
7f3efe59ab | ||
|
|
69551378c2 | ||
|
|
f3fd4bde87 | ||
|
|
c115f64cb5 | ||
|
|
ee61c1e8fb | ||
|
|
e716fb118b | ||
|
|
b0c76346a5 | ||
|
|
56807fd941 | ||
|
|
b56f248b79 | ||
|
|
7a85201a07 | ||
|
|
97ebffd5fb | ||
|
|
46c239c211 | ||
|
|
906e309791 | ||
|
|
4ad1ca0fc6 | ||
|
|
015955f396 | ||
|
|
9bee1905c8 | ||
|
|
8ab157eae4 | ||
|
|
17978b829b | ||
|
|
4ddb23cd7c | ||
|
|
e27eb7419e | ||
|
|
64ef572429 | ||
|
|
2f81e0fd6f | ||
|
|
987f1f7dbf | ||
|
|
b53c91f7f3 | ||
|
|
13d31ac211 | ||
|
|
57ae29cf2f | ||
|
|
0b3895e39e | ||
|
|
0d231d9b94 | ||
|
|
27a6abeeb3 | ||
|
|
c75e6960a7 | ||
|
|
4766ca3fd0 | ||
|
|
523dd97eca | ||
|
|
c09bd2bfc6 | ||
|
|
bd662eaf19 | ||
|
|
ff75ecfe27 | ||
|
|
54f8b74383 | ||
|
|
18a506673f | ||
|
|
a108be8517 | ||
|
|
3e57c3b1e9 | ||
|
|
f18e27a183 | ||
|
|
358efb0f2f | ||
|
|
723fc917f1 | ||
|
|
01f34eea29 | ||
|
|
705d941979 | ||
|
|
691acb45e6 | ||
|
|
97e4ff30ff | ||
|
|
34c76c735a | ||
|
|
47d8e35639 | ||
|
|
d4dc739b30 | ||
|
|
b84859b07e | ||
|
|
3f154fa765 | ||
|
|
f31e32d7a9 | ||
|
|
1589535a45 | ||
|
|
53353ec9e1 | ||
|
|
a601b1c59a | ||
|
|
e093abcb2b | ||
|
|
01cb88a661 | ||
|
|
5ef32b6b31 | ||
|
|
ba1c719568 | ||
|
|
0507e4f4a8 | ||
|
|
60eb312e68 | ||
|
|
044a8926b3 | ||
|
|
acf8c9d49e | ||
|
|
d99e79eb3f | ||
|
|
843c8ccd38 | ||
|
|
d45326606d | ||
|
|
5886d038e3 | ||
|
|
8fed7c7005 | ||
|
|
604522aa61 | ||
|
|
7af35c2d09 | ||
|
|
87497eb491 | ||
|
|
434ed0dd4e | ||
|
|
473a55bde6 | ||
|
|
0b65b36e74 | ||
|
|
4aeb78ccac | ||
|
|
21d5de1756 | ||
|
|
797893d317 | ||
|
|
dd5ac38dd4 | ||
|
|
2741a446ea | ||
|
|
da3d886bd7 | ||
|
|
ad40e02fee | ||
|
|
7cc63e21dd | ||
|
|
611e828d1a | ||
|
|
3abcd59b03 | ||
|
|
48f4cd8943 | ||
|
|
abd5e27c2e | ||
|
|
ccb3a21c68 | ||
|
|
aa060746d7 | ||
|
|
6ec441e501 | ||
|
|
52d3d8cfe7 | ||
|
|
081ba68af4 | ||
|
|
38d5889979 | ||
|
|
5b4808c378 | ||
|
|
2af22d3387 | ||
|
|
7c1a8c90da | ||
|
|
e7726a17db | ||
|
|
57da9a848d | ||
|
|
464ee46631 | ||
|
|
46358b6e36 | ||
|
|
46d6779562 | ||
|
|
ea708e1e05 | ||
|
|
374946505a | ||
|
|
18db31f138 | ||
|
|
332c6eb33c | ||
|
|
e5c49e3bd4 | ||
|
|
60769dc4b7 | ||
|
|
9e652ef214 | ||
|
|
d2825c1b24 | ||
|
|
8482be7068 | ||
|
|
9dc56b727e | ||
|
|
c6759220b9 | ||
|
|
470af54acb | ||
|
|
344f74f444 | ||
|
|
0d1ca1bc0e | ||
|
|
d9e3684d3d | ||
|
|
e59db3f3d9 | ||
|
|
c883d618c3 | ||
|
|
8911a9a3ed | ||
|
|
366d2754ef | ||
|
|
4db114f64d | ||
|
|
d36340a3cd | ||
|
|
7e6de5d8dd | ||
|
|
490eda4f4a | ||
|
|
b5b4d70c2d | ||
|
|
a74cff6902 | ||
|
|
1010274c48 | ||
|
|
c39ff13217 | ||
|
|
58da108e85 | ||
|
|
8b4fdb54ea | ||
|
|
1877cb5e93 | ||
|
|
1530b3f2ca | ||
|
|
4c3c5228aa | ||
|
|
3ae4ca89f4 | ||
|
|
b415b1eeae | ||
|
|
c0ae983faa | ||
|
|
7845cbcc55 | ||
|
|
a33977251e | ||
|
|
b0d668b124 | ||
|
|
b0856c1abf | ||
|
|
2bffa3cf17 | ||
|
|
5ab05c6a6a | ||
|
|
72af2b7cd6 | ||
|
|
143c0a5b07 | ||
|
|
daf79f2324 | ||
|
|
15d11c6c86 | ||
|
|
b298a1fa82 | ||
|
|
007b8147c7 | ||
|
|
4013b76c9e | ||
|
|
ed81391aff | ||
|
|
28818010d6 | ||
|
|
928c19f923 | ||
|
|
34aa240840 | ||
|
|
6872dbd180 | ||
|
|
c5bea30c64 | ||
|
|
071a254611 | ||
|
|
d2d203df34 | ||
|
|
e1ffdea172 | ||
|
|
9abcf40df7 | ||
|
|
b67dc888fe | ||
|
|
c7b101d169 | ||
|
|
df5a7440a4 | ||
|
|
a59a8c0ec5 | ||
|
|
bf9f43da8b | ||
|
|
928b82a9c8 | ||
|
|
b9008d2459 | ||
|
|
50dddaaa9b | ||
|
|
1b168501af | ||
|
|
35a49bad60 | ||
|
|
97c1ff55e9 | ||
|
|
ffead92d5a | ||
|
|
81ea2b1fe4 | ||
|
|
9cdfe0ecb4 | ||
|
|
0473269132 | ||
|
|
4798bf2f79 | ||
|
|
c3c5c56dd8 | ||
|
|
4fb9bbb831 | ||
|
|
267cdd2aee | ||
|
|
fe0bd1a4b8 | ||
|
|
9fa510d2a8 | ||
|
|
fd29986354 | ||
|
|
8ec6bb4758 | ||
|
|
f3306f5fb4 | ||
|
|
20683fdf50 | ||
|
|
603ae8c0e1 | ||
|
|
f1d0418e48 | ||
|
|
9c8c306df3 | ||
|
|
d2543e9c67 | ||
|
|
55a0d910fa | ||
|
|
bd8144a67c | ||
|
|
004d1a7245 | ||
|
|
09fb99ed58 | ||
|
|
ae8071f707 | ||
|
|
c1cf084e43 | ||
|
|
87c794b22e | ||
|
|
a382d6ad35 | ||
|
|
2d86599a19 | ||
|
|
914971b30d | ||
|
|
443763de48 | ||
|
|
ff3c7ebe54 | ||
|
|
c0f82f25a3 | ||
|
|
f90381d412 | ||
|
|
d367d2e864 | ||
|
|
9d20eba2ad | ||
|
|
863746852f | ||
|
|
f416f994c9 | ||
|
|
70dfbbc15e | ||
|
|
85932eab98 | ||
|
|
0ee77d8c88 | ||
|
|
2f2d9547b7 | ||
|
|
32b065708b | ||
|
|
18285df154 | ||
|
|
b1b6c9f426 | ||
|
|
ff884533f9 | ||
|
|
417e80fe8d | ||
|
|
c203e6c7be | ||
|
|
730a0d1c98 | ||
|
|
d9b374f723 | ||
|
|
b9cb692504 | ||
|
|
23fc4bb4f7 | ||
|
|
4ae035dd51 | ||
|
|
3a791162c5 | ||
|
|
06791b06c4 | ||
|
|
5ebc290b94 | ||
|
|
675221a15e | ||
|
|
2f431a0d14 | ||
|
|
fd4e41950c | ||
|
|
41d5ae704a | ||
|
|
83fc069bf4 | ||
|
|
32c5cd245b | ||
|
|
a259be9033 | ||
|
|
fbbdee242a | ||
|
|
4a12635ea5 | ||
|
|
db7278e9c1 | ||
|
|
10056aa4ca | ||
|
|
bb566df432 | ||
|
|
4042a12d39 | ||
|
|
5ae4f9ade8 | ||
|
|
1636f9839c | ||
|
|
c76cccd2e7 | ||
|
|
532eb466a1 | ||
|
|
e8879a0455 | ||
|
|
ef5b4e212c | ||
|
|
24eb82d140 | ||
|
|
cdc8edb56b | ||
|
|
7235c63445 | ||
|
|
fd3b33b04b | ||
|
|
e8815e5653 | ||
|
|
551b9a3b76 | ||
|
|
1c6b639992 | ||
|
|
6fb7587d95 | ||
|
|
3953e74cb4 | ||
|
|
a8f616bba7 | ||
|
|
560eb5e071 | ||
|
|
c665bb4761 | ||
|
|
36584092e5 | ||
|
|
30430bb7dc | ||
|
|
fdf5cff12a | ||
|
|
4816b2b0fe | ||
|
|
9c808bf2ed | ||
|
|
7a12c2c615 | ||
|
|
149bc9f4ef | ||
|
|
b91183e9ec | ||
|
|
b67639f9ec | ||
|
|
cdbcc9ce8c | ||
|
|
6c7d094921 | ||
|
|
23466f6e00 | ||
|
|
08c1f4f072 | ||
|
|
1194c5c7fe | ||
|
|
f63fb16233 | ||
|
|
a4143df36a | ||
|
|
3e78568755 | ||
|
|
9b14cd7633 | ||
|
|
2b2488f376 | ||
|
|
fd77554cb7 | ||
|
|
2ee3d27ba8 | ||
|
|
af24f46803 | ||
|
|
da1684a8b9 | ||
|
|
5e7ae930c5 | ||
|
|
541226356c | ||
|
|
a30345c96c | ||
|
|
d035130d00 | ||
|
|
7d8181c44f | ||
|
|
45536cf957 | ||
|
|
da5ccaaa85 | ||
|
|
7c773991e7 | ||
|
|
bf976e5b8f | ||
|
|
d9ad3f5e98 | ||
|
|
9054dcb9ff | ||
|
|
57116ef054 | ||
|
|
c6f5b8b1f9 | ||
|
|
9e015ba59a | ||
|
|
6144cfad3d | ||
|
|
3844a18b86 | ||
|
|
e88c6e9583 | ||
|
|
6793fb2a35 | ||
|
|
4834c326aa | ||
|
|
e6167adefd | ||
|
|
a8c3756ba7 | ||
|
|
34b47f0239 | ||
|
|
0d13d9eabe | ||
|
|
358adb2109 | ||
|
|
92285b55b6 | ||
|
|
dda91be6d1 | ||
|
|
bec4dbafd2 | ||
|
|
dcb46990c2 | ||
|
|
fe03342b6f | ||
|
|
ee037acd34 | ||
|
|
d4a696cb6b | ||
|
|
5c483efd15 | ||
|
|
9aeba1df9b | ||
|
|
e98683ae1c | ||
|
|
c552e73d20 | ||
|
|
1851163cee | ||
|
|
3667f95b7c | ||
|
|
b6796d2742 | ||
|
|
047983cb91 | ||
|
|
8455abdfe9 | ||
|
|
b7c3fbb176 | ||
|
|
5642552f9a | ||
|
|
6f6b654dba | ||
|
|
c8b791efd3 | ||
|
|
52fd58cd93 | ||
|
|
66d638e224 | ||
|
|
16c4f18a81 | ||
|
|
cd6104ddb3 | ||
|
|
4fe7cd5adc | ||
|
|
3f59141407 | ||
|
|
8b37f503c7 | ||
|
|
7c9353d299 | ||
|
|
dfc901ffa4 | ||
|
|
611bf3035f | ||
|
|
35bb2da6bd | ||
|
|
53e034ce4f | ||
|
|
cd4db1db06 | ||
|
|
b1dbddffb9 | ||
|
|
221c10aa9b | ||
|
|
15ecd7bccf | ||
|
|
0d8dd0dc17 | ||
|
|
ec986e0fbc | ||
|
|
f0e0c73e9b | ||
|
|
d9a24d2e14 | ||
|
|
93618f974d | ||
|
|
4dfc217992 | ||
|
|
5a1a6cf6f0 | ||
|
|
36b325f71d | ||
|
|
74a3712116 | ||
|
|
1fe7eb6cf4 | ||
|
|
0d0f8e9ffc | ||
|
|
0a2063ce69 | ||
|
|
ce207e5c56 | ||
|
|
f22eaae457 | ||
|
|
fbc5280add | ||
|
|
65512ca984 | ||
|
|
385b4f8d4a | ||
|
|
f65f22f333 | ||
|
|
607d355c61 | ||
|
|
29c30c1f89 | ||
|
|
2ff771c16a | ||
|
|
5e641f2273 | ||
|
|
d52254bbf0 | ||
|
|
a97c8be31a | ||
|
|
9c067e5645 | ||
|
|
24d6857069 | ||
|
|
ed9259df9e | ||
|
|
75794fb4d9 | ||
|
|
4c386da7d2 | ||
|
|
abbd2e64c9 | ||
|
|
300a723fca | ||
|
|
ddf42d0358 | ||
|
|
88be0d7638 | ||
|
|
e26428a0eb | ||
|
|
7b36852d7a | ||
|
|
d1eb674314 | ||
|
|
4afed39b0e | ||
|
|
c1460cfdc7 | ||
|
|
85a94ee1e7 | ||
|
|
68895551b2 | ||
|
|
eece09e5ed | ||
|
|
0dd1f26b39 | ||
|
|
1b958a3c4d | ||
|
|
a1d23cddc5 | ||
|
|
14c25e3d9b | ||
|
|
c3915ee48e | ||
|
|
21ff03e28f | ||
|
|
2c8887398d | ||
|
|
f51cd65b1f | ||
|
|
dbb5a5191b | ||
|
|
e9844aed45 | ||
|
|
aaf6289953 | ||
|
|
b0d0223821 | ||
|
|
f271606e5e | ||
|
|
23a9bae391 | ||
|
|
b7c795c313 | ||
|
|
46c553fbad | ||
|
|
fc5bbfbed2 | ||
|
|
afe760a8bc | ||
|
|
7e78c35d23 | ||
|
|
56f0e95a22 | ||
|
|
7f9024465f | ||
|
|
75dc11b882 | ||
|
|
db0a5bd071 | ||
|
|
64434f8065 | ||
|
|
044623309c | ||
|
|
a54695b2e0 | ||
|
|
7acb53a22f | ||
|
|
a2d05e8119 | ||
|
|
dfcebfcbea | ||
|
|
3f165c9803 | ||
|
|
85971ea9f3 | ||
|
|
ff3ec219ef | ||
|
|
e0374dd186 | ||
|
|
51ee3b31cb | ||
|
|
496ea830c5 | ||
|
|
1e911b5094 | ||
|
|
6073be25de | ||
|
|
93a736e42a | ||
|
|
128afc8a56 | ||
|
|
a8d5630030 | ||
|
|
d83a256b9d | ||
|
|
5af33ffe0a | ||
|
|
ffd37d7802 | ||
|
|
4ccd842bdf | ||
|
|
f186c9e242 | ||
|
|
4e66c9fc23 | ||
|
|
99e21652a0 | ||
|
|
24a0cc2f64 | ||
|
|
e9dee86b7c | ||
|
|
42d7901828 | ||
|
|
7f156e961d | ||
|
|
d71b3b1893 | ||
|
|
cb1488c17f | ||
|
|
e13bcba89a | ||
|
|
7d8e8df0c5 | ||
|
|
0e5c0ff46d | ||
|
|
67bff3e19d | ||
|
|
19d9c69fb8 | ||
|
|
cb772a9527 | ||
|
|
ee621c1b92 | ||
|
|
20aa1bfdd6 | ||
|
|
9c52f6b949 | ||
|
|
0f890ad228 | ||
|
|
aac6ab0fc6 | ||
|
|
3fde778c0c | ||
|
|
348bdbdc0d | ||
|
|
3e9223a0bc | ||
|
|
a905a8a3c1 | ||
|
|
b2ab07aa69 | ||
|
|
9bd1da95e0 | ||
|
|
83c0df2157 | ||
|
|
8d7c64be66 | ||
|
|
0625a01a4f | ||
|
|
208a8723ff | ||
|
|
f4c2a9ca7d | ||
|
|
c97fd63e6d | ||
|
|
58402cdda8 | ||
|
|
59fa3e10a3 | ||
|
|
0831a427cc | ||
|
|
08517f0c7e | ||
|
|
97e58c2d79 | ||
|
|
6693ec48a0 | ||
|
|
9a13d4ce04 | ||
|
|
51bbe1f79d | ||
|
|
5dd92ab506 | ||
|
|
7120201469 | ||
|
|
046eeb03f2 | ||
|
|
ce22dc9309 | ||
|
|
953c9e588e | ||
|
|
2ceb4068ad | ||
|
|
11f62063a6 | ||
|
|
7885d712a6 | ||
|
|
a6ca282ff4 | ||
|
|
8ef67dee3b | ||
|
|
fb1b730bd5 | ||
|
|
af9c45849e | ||
|
|
a711a67f4c | ||
|
|
b743b7e2fb | ||
|
|
3db92359e5 | ||
|
|
088f08b315 | ||
|
|
71cd61dfe4 | ||
|
|
947e26d864 | ||
|
|
e3995a130f | ||
|
|
384641e274 | ||
|
|
0985415e11 | ||
|
|
3e13c9e825 | ||
|
|
ec09589646 | ||
|
|
83e3321a48 | ||
|
|
bb4c8ea52d | ||
|
|
5960dc6245 | ||
|
|
ca92316e7d | ||
|
|
b096472ccf | ||
|
|
261498d225 | ||
|
|
320a6b8a16 | ||
|
|
b3cadaf314 | ||
|
|
660852115e | ||
|
|
543e57ed7d | ||
|
|
4d78b7ca13 | ||
|
|
a32bdf3f2f | ||
|
|
5382d2006c | ||
|
|
ae1d60d11e | ||
|
|
e8c0bcfbb2 | ||
|
|
b8a04cb842 | ||
|
|
b4ffa8c045 | ||
|
|
7e540f16f9 | ||
|
|
e69275c6c5 | ||
|
|
16c123df49 | ||
|
|
446eee79fc | ||
|
|
cbc96d8a58 | ||
|
|
d2015b7d7b | ||
|
|
305b236f41 | ||
|
|
e172bd13df | ||
|
|
94cb4a2bb4 | ||
|
|
7abbbf6b7b | ||
|
|
66287757b3 | ||
|
|
661ecc57c5 | ||
|
|
15f9f79a24 | ||
|
|
286374fe7c | ||
|
|
ea288c2194 | ||
|
|
927cd60ad2 | ||
|
|
fb6e47e42a | ||
|
|
34d4f6b1f9 | ||
|
|
f7170953fb | ||
|
|
e80d52cc0f | ||
|
|
75da1ce7a7 | ||
|
|
7894c872dc | ||
|
|
14b2d2ed4c | ||
|
|
a7b5077e0c | ||
|
|
de2b88b707 | ||
|
|
130734bec7 | ||
|
|
db4c241cba | ||
|
|
be09909976 | ||
|
|
a6b1da393b | ||
|
|
501c20a34d | ||
|
|
b858ba3786 | ||
|
|
60863c5fcf | ||
|
|
1ee3f4a984 | ||
|
|
0205f150a3 | ||
|
|
cdbdf580c8 | ||
|
|
e4ba2b0828 | ||
|
|
28d00cc7c9 | ||
|
|
b897da8f6f | ||
|
|
dc868b16ab | ||
|
|
ee2e109769 | ||
|
|
2b955ddd53 | ||
|
|
33cb4fd42b | ||
|
|
a03af7e9ef | ||
|
|
90dbc35d41 | ||
|
|
66e9fc2068 | ||
|
|
0a9b376684 | ||
|
|
83ba909c08 | ||
|
|
9ed33f16dd | ||
|
|
e9fdb61bb5 | ||
|
|
073b1cd303 | ||
|
|
e712791f43 | ||
|
|
a4743901a3 | ||
|
|
ced9489643 | ||
|
|
0c45a0ca49 | ||
|
|
f3572e82ec | ||
|
|
dd620022a8 | ||
|
|
2237ec581c | ||
|
|
a0cd70ae71 | ||
|
|
80fce579a0 | ||
|
|
1313484ebe | ||
|
|
95aa541293 | ||
|
|
c4702f6a87 | ||
|
|
5c0fc0bec5 | ||
|
|
d8de7b19cb | ||
|
|
38640b01a8 | ||
|
|
a11e783867 | ||
|
|
8ca2fffa78 | ||
|
|
3f3cbd17ed | ||
|
|
5a18769336 | ||
|
|
cd6fe171cd | ||
|
|
ee45e546a8 | ||
|
|
c8be217a1d | ||
|
|
618df6de1d | ||
|
|
e6e79df8db | ||
|
|
509ca47b36 | ||
|
|
066353e1e7 | ||
|
|
a6737afb2f | ||
|
|
d5b3a62df5 | ||
|
|
7f82faefe1 | ||
|
|
08731857e5 | ||
|
|
90062acc35 | ||
|
|
030d912820 | ||
|
|
9e9187b169 | ||
|
|
c1258d0527 | ||
|
|
b7039c81ba | ||
|
|
7088b96c16 | ||
|
|
d31273dff5 | ||
|
|
85460ef6e2 | ||
|
|
5ab059c404 | ||
|
|
322ea1870d | ||
|
|
ab3024d98a | ||
|
|
d447c96385 | ||
|
|
e3ac4d1039 | ||
|
|
8fc4aa7240 | ||
|
|
aff9d8cbca | ||
|
|
260c15c6b6 | ||
|
|
dab48146bf | ||
|
|
1115cdd2ec | ||
|
|
44673b9fd2 | ||
|
|
faf9b32176 | ||
|
|
a93c1092fc | ||
|
|
6c81163d20 | ||
|
|
f71edbf45b | ||
|
|
0d3e48475e | ||
|
|
ae8451e837 | ||
|
|
123e734046 | ||
|
|
008261e918 | ||
|
|
d388086baa | ||
|
|
f7af705bb5 | ||
|
|
a827cb7546 | ||
|
|
c7fe6f388a | ||
|
|
a04080a93e | ||
|
|
04158f5589 | ||
|
|
6de6c38834 | ||
|
|
a5745ba72d | ||
|
|
0867d8a3c4 | ||
|
|
71f5d29cba | ||
|
|
e68340273b | ||
|
|
b0414748cb | ||
|
|
b1761e04b2 | ||
|
|
d6b194b0aa | ||
|
|
50ed52bacc | ||
|
|
daa906a697 | ||
|
|
ecd8f40c0f | ||
|
|
616c1b9b73 | ||
|
|
d24870e0ae | ||
|
|
b57c224052 | ||
|
|
895abde39c | ||
|
|
b6418d95e7 | ||
|
|
b7dc55604e | ||
|
|
991bc359cb | ||
|
|
bc55bfbee1 | ||
|
|
e9119e95ac | ||
|
|
af332a34d6 | ||
|
|
2d6251e5df | ||
|
|
d9bf3339d2 | ||
|
|
b4ee5cd59c | ||
|
|
91f410a85c | ||
|
|
58ffd37f9e | ||
|
|
0a48696cd8 | ||
|
|
2f71570390 | ||
|
|
5c9d98d12c | ||
|
|
15362df69a | ||
|
|
ab0c97621a | ||
|
|
78b6c03af7 | ||
|
|
22342cdc05 | ||
|
|
dccdd84c25 | ||
|
|
d4d16f43ac | ||
|
|
dcf4963e0c | ||
|
|
a773a4957a | ||
|
|
9ec36a76f6 | ||
|
|
5dc8283229 | ||
|
|
09b470e6c7 | ||
|
|
40151c7a43 | ||
|
|
34c030b501 | ||
|
|
e9a2528b13 | ||
|
|
e9d72bd022 | ||
|
|
b166686a15 | ||
|
|
c59d3cc624 | ||
|
|
ca95060b05 | ||
|
|
0451ae07c8 | ||
|
|
3e55693bfa | ||
|
|
f5d0947b27 | ||
|
|
2da181a399 | ||
|
|
6e8bcf7b69 | ||
|
|
da6791d75f | ||
|
|
2a0928b4be | ||
|
|
9bb365e60d | ||
|
|
b3c80e6ecf | ||
|
|
e5c77f64aa | ||
|
|
c313ed2efc | ||
|
|
d8f75495fe | ||
|
|
2240743100 | ||
|
|
a6a2410c50 | ||
|
|
34751a52a8 | ||
|
|
cb7c382b99 | ||
|
|
76c3f640db | ||
|
|
f5b56d9855 | ||
|
|
b25a8b4c9f | ||
|
|
7ad9b9dd08 | ||
|
|
065895aa73 | ||
|
|
06592d7d37 | ||
|
|
49e31ddb3d | ||
|
|
fd55bdf9a8 | ||
|
|
6eb3a243df | ||
|
|
b52e972a39 | ||
|
|
2d344e0209 | ||
|
|
519252efd4 | ||
|
|
e59e62fb1b | ||
|
|
a35690d13c | ||
|
|
4857569813 | ||
|
|
acf80b4b92 | ||
|
|
084d12bb45 | ||
|
|
1587218c6d | ||
|
|
12d3e36887 | ||
|
|
456b51d7f8 | ||
|
|
6f0effcc66 | ||
|
|
3dd8f214bf | ||
|
|
d3700ac9f8 | ||
|
|
7aa5d84ff4 | ||
|
|
46e99bfb40 | ||
|
|
fb5f59e72e | ||
|
|
8af1a53721 | ||
|
|
7034ffea39 | ||
|
|
94ed0354c2 | ||
|
|
2cf3408023 | ||
|
|
3b16d33775 | ||
|
|
3ff6374ace | ||
|
|
0ea2fed481 | ||
|
|
6bbc543ac1 | ||
|
|
1ca4f993b0 | ||
|
|
44f448fec4 | ||
|
|
abf7e65816 | ||
|
|
55bce63cea | ||
|
|
710e5afe08 | ||
|
|
cbf37677cb | ||
|
|
efb98c6414 | ||
|
|
01fbcb7044 | ||
|
|
53d2f6320b | ||
|
|
9d02da9d9c | ||
|
|
a0841d76db | ||
|
|
e3c4d611c3 | ||
|
|
79e8c48824 | ||
|
|
9ef298608e | ||
|
|
3ee8d5125b | ||
|
|
59c490fcea | ||
|
|
b8b468195c | ||
|
|
d873a5e68b | ||
|
|
6ad27b43ab | ||
|
|
1df19f65c4 | ||
|
|
c22a20c1ef | ||
|
|
c140ab970e | ||
|
|
5723e9a77e | ||
|
|
bdedd83368 | ||
|
|
2f5f92ddca | ||
|
|
87a98fe382 | ||
|
|
8894ff0fda | ||
|
|
488d2ed886 | ||
|
|
48f190447c | ||
|
|
63184d0bf5 | ||
|
|
a9bd5a8bb0 | ||
|
|
6c9850b8f6 | ||
|
|
e89b4e070c | ||
|
|
911d84d513 | ||
|
|
1a3f836a5a | ||
|
|
bb0e797cee | ||
|
|
05d866f0f7 | ||
|
|
e7fbb2273d | ||
|
|
91f159841b | ||
|
|
905dba67c3 | ||
|
|
676b83519a | ||
|
|
0e2c8ff220 | ||
|
|
e39a6b96bd | ||
|
|
da1268fc05 | ||
|
|
fb07d19a64 | ||
|
|
487e0c8769 | ||
|
|
5ee125c593 | ||
|
|
4876ae7c22 | ||
|
|
e9b04b923e | ||
|
|
5d8b9fd4db |
@@ -1,8 +1,8 @@
|
||||
# Phpdoc dokuwiki template
|
||||
This directory contains a template rendering iTop phpdoc as wiki pages.
|
||||
This directory contains a template for rendering iTop phpdoc as dokuwiki pages.
|
||||
|
||||
|
||||
conventional tag that you should use:
|
||||
Conventional tags that you should use:
|
||||
* `@internal` : exclude from the documentation.
|
||||
* `@api` : it means that a method is an api, thus it may be interacted with.
|
||||
* `@see` : it points to another documented method
|
||||
@@ -14,7 +14,7 @@ conventional tag that you should use:
|
||||
|
||||
## Special instructions
|
||||
|
||||
some tags where added :
|
||||
Some iTop specific tags were added :
|
||||
* `@api-advanced`: it means that a method is an `@api` but mark it also as "complex" to use
|
||||
* `@overwritable-hook`: used to mark a method as "designed to be extended"
|
||||
* `@extension-hook`: not used for now
|
||||
@@ -23,7 +23,7 @@ some tags where added :
|
||||
|
||||
### known limitations:
|
||||
#### `@see` tags must be very specific:
|
||||
* always prefix class members with `ClassName::`
|
||||
* always prefix class members (attributes or methods) with `ClassName::` (do not use self)
|
||||
* for methods always suffix them with `()`,
|
||||
* do not reference variables since they are not documented. If you have to, always prefix them with `$`
|
||||
|
||||
@@ -39,12 +39,12 @@ examples:
|
||||
#### Do not use inline tags, they do not work properly, example:
|
||||
```
|
||||
/**
|
||||
* This is a texts with ans inline tag {@see [FQSEN] [<description>]} it must never be used
|
||||
* This is a texts with an inline tag {@see [FQSEN] [<description>]} it must never be used
|
||||
*/
|
||||
```
|
||||
|
||||
#### The `@example` tag must respect this very precise syntax
|
||||
* the sentence in the first line (next to the tag) is the title, it must be enclose by double quotes
|
||||
* the sentence in the first line (next to the tag) is the title, it must be enclosed by double quotes
|
||||
* the following lines are the sample code.
|
||||
* 💔 since we simply hack the official tag, this syntax must be respected carefully 💔
|
||||
example:
|
||||
@@ -82,14 +82,15 @@ Then, **for a method** of an eligible class:
|
||||
|
||||
## Installation
|
||||
```
|
||||
cd .doc
|
||||
composer require phpdocumentor/phpdocumentor:~2 --dev
|
||||
```
|
||||
|
||||
## Generation
|
||||
`.doc/bin/build-doc-object-manipulation` and `.doc/bin/build-doc-extensions` contains examples of doc. generation, beware: they have to be called from iTop root directory:
|
||||
`./bin/build-doc-object-manipulation` and `./bin/build-doc-extensions` contains examples of doc. generation, beware: they have to be called from the .doc directory:
|
||||
```shell
|
||||
cd /path/to/itop/
|
||||
./.doc/bin/build-doc-object-manipulation
|
||||
cd /path/to/itop/.doc
|
||||
./bin/build-doc-object-manipulation
|
||||
```
|
||||
|
||||
the resulting documentation is written into `data/phpdocumentor/output`
|
||||
@@ -100,4 +101,3 @@ the resulting documentation is written into `data/phpdocumentor/output`
|
||||
* the generated files have to be placed under an arbitrary directory of `[/path/to/dokuwiki]/data/pages`.
|
||||
* the html has to be activated [config:htmlok](https://www.dokuwiki.org/config:htmlok)
|
||||
* the generated files have to be in lowercase
|
||||
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
#!/bin/sh -x
|
||||
|
||||
rm -rf /tmp/phpdoc-twig-cache/ && rm -rf data/phpdocumentor/output/extensions/ && rm -rf data/phpdocumentor/temp/extensions/ && vendor/bin/phpdoc -c .doc/phpdoc-extensions.dist.xml -vvv
|
||||
rm -rf /tmp/phpdoc-twig-cache/ && rm -rf data/phpdocumentor/output/extensions/ && rm -rf data/phpdocumentor/temp/extensions/ && .doc/vendor/bin/phpdoc -c .doc/phpdoc-extensions.dist.xml -vvv
|
||||
|
||||
# now wee need to lowercase every generated file because dokuwiki can't handle uppercase
|
||||
cd data/phpdocumentor/output/extensions/
|
||||
for i in $( ls | grep [A-Z] ); do mv -i $i `echo $i | tr 'A-Z' 'a-z'`; done
|
||||
cd data/phpdocumentor/output/extensions/ && for i in $( ls | grep [A-Z] ); do mv -i $i `echo $i | tr 'A-Z' 'a-z'`; done
|
||||
@@ -1,8 +1,7 @@
|
||||
#!/bin/sh -x
|
||||
|
||||
rm -rf /tmp/phpdoc-twig-cache/ && rm -rf data/phpdocumentor/output/objects-manipulation/ && rm -rf data/phpdocumentor/temp/objects-manipulation/ && vendor/bin/phpdoc -c .doc/phpdoc-objects-manipulation.dist.xml -vvv
|
||||
rm -rf /tmp/phpdoc-twig-cache/ && rm -rf ../data/phpdocumentor/output/objects-manipulation/ && rm -rf ../data/phpdocumentor/temp/objects-manipulation/ && ./vendor/bin/phpdoc -c ./phpdoc-objects-manipulation.dist.xml -vvv
|
||||
|
||||
|
||||
# now wee need to lowercase every generated file because dokuwiki can't handle uppercase
|
||||
cd data/phpdocumentor/output/objects-manipulation/
|
||||
for i in $( ls | grep [A-Z] ); do mv -i $i `echo $i | tr 'A-Z' 'a-z'`; done
|
||||
cd ../data/phpdocumentor/output/objects-manipulation/ && for i in $( ls | grep [A-Z] ); do mv -i $i `echo $i | tr 'A-Z' 'a-z'`; done
|
||||
6
.doc/composer.json
Normal file
6
.doc/composer.json
Normal file
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"require-dev": {
|
||||
"phpdocumentor/phpdocumentor": "~2",
|
||||
"jms/serializer": "1.7.*"
|
||||
}
|
||||
}
|
||||
3015
.doc/composer.lock
generated
Normal file
3015
.doc/composer.lock
generated
Normal file
File diff suppressed because it is too large
Load Diff
@@ -18,7 +18,7 @@
|
||||
|
||||
|
||||
{{ structure.summary|raw }}
|
||||
[[{{structureName}}|More informations]]
|
||||
[[{{structureName}}|More information]]
|
||||
|
||||
</WRAP>{# group #}
|
||||
|
||||
|
||||
536
.editorconfig
Normal file
536
.editorconfig
Normal file
@@ -0,0 +1,536 @@
|
||||
root = true
|
||||
|
||||
[*]
|
||||
charset = utf-8
|
||||
end_of_line = lf
|
||||
indent_size = 4
|
||||
indent_style = space
|
||||
insert_final_newline = false
|
||||
max_line_length = 140
|
||||
tab_width = 4
|
||||
ij_continuation_indent_size = 8
|
||||
ij_formatter_off_tag = @formatter:off
|
||||
ij_formatter_on_tag = @formatter:on
|
||||
ij_formatter_tags_enabled = false
|
||||
ij_smart_tabs = false
|
||||
ij_visual_guides = 80,120
|
||||
ij_wrap_on_typing = true
|
||||
|
||||
[*.css]
|
||||
indent_style = tab
|
||||
ij_smart_tabs = true
|
||||
ij_css_align_closing_brace_with_properties = false
|
||||
ij_css_blank_lines_around_nested_selector = 1
|
||||
ij_css_blank_lines_between_blocks = 1
|
||||
ij_css_brace_placement = end_of_line
|
||||
ij_css_enforce_quotes_on_format = false
|
||||
ij_css_hex_color_long_format = false
|
||||
ij_css_hex_color_lower_case = false
|
||||
ij_css_hex_color_short_format = false
|
||||
ij_css_hex_color_upper_case = false
|
||||
ij_css_keep_blank_lines_in_code = 2
|
||||
ij_css_keep_indents_on_empty_lines = false
|
||||
ij_css_keep_single_line_blocks = false
|
||||
ij_css_properties_order = font,font-family,font-size,font-weight,font-style,font-variant,font-size-adjust,font-stretch,line-height,position,z-index,top,right,bottom,left,display,visibility,float,clear,overflow,overflow-x,overflow-y,clip,zoom,align-content,align-items,align-self,flex,flex-flow,flex-basis,flex-direction,flex-grow,flex-shrink,flex-wrap,justify-content,order,box-sizing,width,min-width,max-width,height,min-height,max-height,margin,margin-top,margin-right,margin-bottom,margin-left,padding,padding-top,padding-right,padding-bottom,padding-left,table-layout,empty-cells,caption-side,border-spacing,border-collapse,list-style,list-style-position,list-style-type,list-style-image,content,quotes,counter-reset,counter-increment,resize,cursor,user-select,nav-index,nav-up,nav-right,nav-down,nav-left,transition,transition-delay,transition-timing-function,transition-duration,transition-property,transform,transform-origin,animation,animation-name,animation-duration,animation-play-state,animation-timing-function,animation-delay,animation-iteration-count,animation-direction,text-align,text-align-last,vertical-align,white-space,text-decoration,text-emphasis,text-emphasis-color,text-emphasis-style,text-emphasis-position,text-indent,text-justify,letter-spacing,word-spacing,text-outline,text-transform,text-wrap,text-overflow,text-overflow-ellipsis,text-overflow-mode,word-wrap,word-break,tab-size,hyphens,pointer-events,opacity,color,border,border-width,border-style,border-color,border-top,border-top-width,border-top-style,border-top-color,border-right,border-right-width,border-right-style,border-right-color,border-bottom,border-bottom-width,border-bottom-style,border-bottom-color,border-left,border-left-width,border-left-style,border-left-color,border-radius,border-top-left-radius,border-top-right-radius,border-bottom-right-radius,border-bottom-left-radius,border-image,border-image-source,border-image-slice,border-image-width,border-image-outset,border-image-repeat,outline,outline-width,outline-style,outline-color,outline-offset,background,background-color,background-image,background-repeat,background-attachment,background-position,background-position-x,background-position-y,background-clip,background-origin,background-size,box-decoration-break,box-shadow,text-shadow
|
||||
ij_css_space_after_colon = true
|
||||
ij_css_space_before_opening_brace = true
|
||||
ij_css_use_double_quotes = true
|
||||
ij_css_value_alignment = do_not_align
|
||||
|
||||
[*.scss]
|
||||
indent_style = tab
|
||||
ij_scss_align_closing_brace_with_properties = false
|
||||
ij_scss_blank_lines_around_nested_selector = 1
|
||||
ij_scss_blank_lines_between_blocks = 1
|
||||
ij_scss_brace_placement = 0
|
||||
ij_scss_enforce_quotes_on_format = false
|
||||
ij_scss_hex_color_long_format = false
|
||||
ij_scss_hex_color_lower_case = false
|
||||
ij_scss_hex_color_short_format = false
|
||||
ij_scss_hex_color_upper_case = false
|
||||
ij_scss_keep_blank_lines_in_code = 2
|
||||
ij_scss_keep_indents_on_empty_lines = false
|
||||
ij_scss_keep_single_line_blocks = false
|
||||
ij_scss_properties_order = font,font-family,font-size,font-weight,font-style,font-variant,font-size-adjust,font-stretch,line-height,position,z-index,top,right,bottom,left,display,visibility,float,clear,overflow,overflow-x,overflow-y,clip,zoom,align-content,align-items,align-self,flex,flex-flow,flex-basis,flex-direction,flex-grow,flex-shrink,flex-wrap,justify-content,order,box-sizing,width,min-width,max-width,height,min-height,max-height,margin,margin-top,margin-right,margin-bottom,margin-left,padding,padding-top,padding-right,padding-bottom,padding-left,table-layout,empty-cells,caption-side,border-spacing,border-collapse,list-style,list-style-position,list-style-type,list-style-image,content,quotes,counter-reset,counter-increment,resize,cursor,user-select,nav-index,nav-up,nav-right,nav-down,nav-left,transition,transition-delay,transition-timing-function,transition-duration,transition-property,transform,transform-origin,animation,animation-name,animation-duration,animation-play-state,animation-timing-function,animation-delay,animation-iteration-count,animation-direction,text-align,text-align-last,vertical-align,white-space,text-decoration,text-emphasis,text-emphasis-color,text-emphasis-style,text-emphasis-position,text-indent,text-justify,letter-spacing,word-spacing,text-outline,text-transform,text-wrap,text-overflow,text-overflow-ellipsis,text-overflow-mode,word-wrap,word-break,tab-size,hyphens,pointer-events,opacity,color,border,border-width,border-style,border-color,border-top,border-top-width,border-top-style,border-top-color,border-right,border-right-width,border-right-style,border-right-color,border-bottom,border-bottom-width,border-bottom-style,border-bottom-color,border-left,border-left-width,border-left-style,border-left-color,border-radius,border-top-left-radius,border-top-right-radius,border-bottom-right-radius,border-bottom-left-radius,border-image,border-image-source,border-image-slice,border-image-width,border-image-outset,border-image-repeat,outline,outline-width,outline-style,outline-color,outline-offset,background,background-color,background-image,background-repeat,background-attachment,background-position,background-position-x,background-position-y,background-clip,background-origin,background-size,box-decoration-break,box-shadow,text-shadow
|
||||
ij_scss_space_after_colon = true
|
||||
ij_scss_space_before_opening_brace = true
|
||||
ij_scss_use_double_quotes = true
|
||||
ij_scss_value_alignment = 0
|
||||
|
||||
[*.twig]
|
||||
indent_style = tab
|
||||
ij_smart_tabs = true
|
||||
ij_wrap_on_typing = false
|
||||
ij_twig_keep_indents_on_empty_lines = false
|
||||
ij_twig_spaces_inside_comments_delimiters = true
|
||||
ij_twig_spaces_inside_delimiters = true
|
||||
ij_twig_spaces_inside_variable_delimiters = true
|
||||
|
||||
[.editorconfig]
|
||||
ij_editorconfig_align_group_field_declarations = false
|
||||
ij_editorconfig_space_after_colon = false
|
||||
ij_editorconfig_space_after_comma = true
|
||||
ij_editorconfig_space_before_colon = false
|
||||
ij_editorconfig_space_before_comma = false
|
||||
ij_editorconfig_spaces_around_assignment_operators = true
|
||||
|
||||
[{*.ant,*.fxml,*.jhm,*.jnlp,*.jrxml,*.rng,*.tld,*.wsdl,*.xml,*.xsd,*.xsl,*.xslt,*.xul,phpunit.xml.dist}]
|
||||
indent_size = 2
|
||||
tab_width = 2
|
||||
ij_smart_tabs = true
|
||||
ij_xml_align_attributes = true
|
||||
ij_xml_align_text = false
|
||||
ij_xml_attribute_wrap = normal
|
||||
ij_xml_block_comment_at_first_column = true
|
||||
ij_xml_keep_blank_lines = 2
|
||||
ij_xml_keep_indents_on_empty_lines = false
|
||||
ij_xml_keep_line_breaks = false
|
||||
ij_xml_keep_line_breaks_in_text = true
|
||||
ij_xml_keep_whitespaces = false
|
||||
ij_xml_keep_whitespaces_around_cdata = preserve
|
||||
ij_xml_keep_whitespaces_inside_cdata = true
|
||||
ij_xml_line_comment_at_first_column = true
|
||||
ij_xml_space_after_tag_name = false
|
||||
ij_xml_space_around_equals_in_attribute = false
|
||||
ij_xml_space_inside_empty_tag = false
|
||||
ij_xml_text_wrap = normal
|
||||
|
||||
[{*.bash,*.sh,*.zsh}]
|
||||
indent_size = 2
|
||||
tab_width = 2
|
||||
ij_shell_binary_ops_start_line = false
|
||||
ij_shell_keep_column_alignment_padding = false
|
||||
ij_shell_minify_program = false
|
||||
ij_shell_redirect_followed_by_space = false
|
||||
ij_shell_switch_cases_indented = false
|
||||
|
||||
[{*.cjs,*.js}]
|
||||
indent_style = tab
|
||||
ij_continuation_indent_size = 4
|
||||
ij_smart_tabs = true
|
||||
ij_javascript_align_imports = false
|
||||
ij_javascript_align_multiline_array_initializer_expression = false
|
||||
ij_javascript_align_multiline_binary_operation = false
|
||||
ij_javascript_align_multiline_chained_methods = false
|
||||
ij_javascript_align_multiline_extends_list = false
|
||||
ij_javascript_align_multiline_for = true
|
||||
ij_javascript_align_multiline_parameters = true
|
||||
ij_javascript_align_multiline_parameters_in_calls = false
|
||||
ij_javascript_align_multiline_ternary_operation = false
|
||||
ij_javascript_align_object_properties = 0
|
||||
ij_javascript_align_union_types = false
|
||||
ij_javascript_align_var_statements = 0
|
||||
ij_javascript_array_initializer_new_line_after_left_brace = false
|
||||
ij_javascript_array_initializer_right_brace_on_new_line = false
|
||||
ij_javascript_array_initializer_wrap = off
|
||||
ij_javascript_assignment_wrap = off
|
||||
ij_javascript_binary_operation_sign_on_next_line = false
|
||||
ij_javascript_binary_operation_wrap = off
|
||||
ij_javascript_blacklist_imports = rxjs/Rx,node_modules/**,**/node_modules/**,@angular/material,@angular/material/typings/**
|
||||
ij_javascript_blank_lines_after_imports = 1
|
||||
ij_javascript_blank_lines_around_class = 1
|
||||
ij_javascript_blank_lines_around_field = 0
|
||||
ij_javascript_blank_lines_around_function = 1
|
||||
ij_javascript_blank_lines_around_method = 1
|
||||
ij_javascript_block_brace_style = end_of_line
|
||||
ij_javascript_call_parameters_new_line_after_left_paren = false
|
||||
ij_javascript_call_parameters_right_paren_on_new_line = false
|
||||
ij_javascript_call_parameters_wrap = off
|
||||
ij_javascript_catch_on_new_line = false
|
||||
ij_javascript_chained_call_dot_on_new_line = true
|
||||
ij_javascript_class_brace_style = end_of_line
|
||||
ij_javascript_comma_on_new_line = false
|
||||
ij_javascript_do_while_brace_force = always
|
||||
ij_javascript_else_on_new_line = true
|
||||
ij_javascript_enforce_trailing_comma = keep
|
||||
ij_javascript_extends_keyword_wrap = off
|
||||
ij_javascript_extends_list_wrap = off
|
||||
ij_javascript_field_prefix = _
|
||||
ij_javascript_file_name_style = relaxed
|
||||
ij_javascript_finally_on_new_line = false
|
||||
ij_javascript_for_brace_force = always
|
||||
ij_javascript_for_statement_new_line_after_left_paren = false
|
||||
ij_javascript_for_statement_right_paren_on_new_line = false
|
||||
ij_javascript_for_statement_wrap = off
|
||||
ij_javascript_force_quote_style = false
|
||||
ij_javascript_force_semicolon_style = false
|
||||
ij_javascript_function_expression_brace_style = end_of_line
|
||||
ij_javascript_if_brace_force = always
|
||||
ij_javascript_import_merge_members = global
|
||||
ij_javascript_import_prefer_absolute_path = global
|
||||
ij_javascript_import_sort_members = true
|
||||
ij_javascript_import_sort_module_name = false
|
||||
ij_javascript_import_use_node_resolution = true
|
||||
ij_javascript_imports_wrap = on_every_item
|
||||
ij_javascript_indent_case_from_switch = true
|
||||
ij_javascript_indent_chained_calls = true
|
||||
ij_javascript_indent_package_children = 0
|
||||
ij_javascript_jsx_attribute_value = braces
|
||||
ij_javascript_keep_blank_lines_in_code = 2
|
||||
ij_javascript_keep_first_column_comment = true
|
||||
ij_javascript_keep_indents_on_empty_lines = false
|
||||
ij_javascript_keep_line_breaks = true
|
||||
ij_javascript_keep_simple_blocks_in_one_line = false
|
||||
ij_javascript_keep_simple_methods_in_one_line = false
|
||||
ij_javascript_line_comment_add_space = true
|
||||
ij_javascript_line_comment_at_first_column = false
|
||||
ij_javascript_method_brace_style = end_of_line
|
||||
ij_javascript_method_call_chain_wrap = off
|
||||
ij_javascript_method_parameters_new_line_after_left_paren = false
|
||||
ij_javascript_method_parameters_right_paren_on_new_line = false
|
||||
ij_javascript_method_parameters_wrap = off
|
||||
ij_javascript_object_literal_wrap = on_every_item
|
||||
ij_javascript_parentheses_expression_new_line_after_left_paren = false
|
||||
ij_javascript_parentheses_expression_right_paren_on_new_line = false
|
||||
ij_javascript_place_assignment_sign_on_next_line = false
|
||||
ij_javascript_prefer_as_type_cast = false
|
||||
ij_javascript_prefer_explicit_types_function_expression_returns = false
|
||||
ij_javascript_prefer_explicit_types_function_returns = false
|
||||
ij_javascript_prefer_explicit_types_vars_fields = false
|
||||
ij_javascript_prefer_parameters_wrap = false
|
||||
ij_javascript_reformat_c_style_comments = false
|
||||
ij_javascript_space_after_colon = true
|
||||
ij_javascript_space_after_comma = true
|
||||
ij_javascript_space_after_dots_in_rest_parameter = false
|
||||
ij_javascript_space_after_generator_mult = true
|
||||
ij_javascript_space_after_property_colon = true
|
||||
ij_javascript_space_after_quest = true
|
||||
ij_javascript_space_after_type_colon = true
|
||||
ij_javascript_space_after_unary_not = false
|
||||
ij_javascript_space_before_async_arrow_lparen = true
|
||||
ij_javascript_space_before_catch_keyword = true
|
||||
ij_javascript_space_before_catch_left_brace = true
|
||||
ij_javascript_space_before_catch_parentheses = true
|
||||
ij_javascript_space_before_class_lbrace = true
|
||||
ij_javascript_space_before_class_left_brace = true
|
||||
ij_javascript_space_before_colon = true
|
||||
ij_javascript_space_before_comma = false
|
||||
ij_javascript_space_before_do_left_brace = true
|
||||
ij_javascript_space_before_else_keyword = true
|
||||
ij_javascript_space_before_else_left_brace = true
|
||||
ij_javascript_space_before_finally_keyword = true
|
||||
ij_javascript_space_before_finally_left_brace = true
|
||||
ij_javascript_space_before_for_left_brace = true
|
||||
ij_javascript_space_before_for_parentheses = true
|
||||
ij_javascript_space_before_for_semicolon = false
|
||||
ij_javascript_space_before_function_left_parenth = true
|
||||
ij_javascript_space_before_generator_mult = false
|
||||
ij_javascript_space_before_if_left_brace = true
|
||||
ij_javascript_space_before_if_parentheses = true
|
||||
ij_javascript_space_before_method_call_parentheses = false
|
||||
ij_javascript_space_before_method_left_brace = true
|
||||
ij_javascript_space_before_method_parentheses = false
|
||||
ij_javascript_space_before_property_colon = false
|
||||
ij_javascript_space_before_quest = true
|
||||
ij_javascript_space_before_switch_left_brace = true
|
||||
ij_javascript_space_before_switch_parentheses = true
|
||||
ij_javascript_space_before_try_left_brace = true
|
||||
ij_javascript_space_before_type_colon = false
|
||||
ij_javascript_space_before_unary_not = false
|
||||
ij_javascript_space_before_while_keyword = true
|
||||
ij_javascript_space_before_while_left_brace = true
|
||||
ij_javascript_space_before_while_parentheses = true
|
||||
ij_javascript_spaces_around_additive_operators = false
|
||||
ij_javascript_spaces_around_arrow_function_operator = true
|
||||
ij_javascript_spaces_around_assignment_operators = true
|
||||
ij_javascript_spaces_around_bitwise_operators = true
|
||||
ij_javascript_spaces_around_equality_operators = true
|
||||
ij_javascript_spaces_around_logical_operators = true
|
||||
ij_javascript_spaces_around_multiplicative_operators = true
|
||||
ij_javascript_spaces_around_relational_operators = true
|
||||
ij_javascript_spaces_around_shift_operators = true
|
||||
ij_javascript_spaces_around_unary_operator = false
|
||||
ij_javascript_spaces_within_array_initializer_brackets = false
|
||||
ij_javascript_spaces_within_brackets = false
|
||||
ij_javascript_spaces_within_catch_parentheses = false
|
||||
ij_javascript_spaces_within_for_parentheses = false
|
||||
ij_javascript_spaces_within_if_parentheses = false
|
||||
ij_javascript_spaces_within_imports = false
|
||||
ij_javascript_spaces_within_interpolation_expressions = false
|
||||
ij_javascript_spaces_within_method_call_parentheses = false
|
||||
ij_javascript_spaces_within_method_parentheses = false
|
||||
ij_javascript_spaces_within_object_literal_braces = false
|
||||
ij_javascript_spaces_within_object_type_braces = true
|
||||
ij_javascript_spaces_within_parentheses = false
|
||||
ij_javascript_spaces_within_switch_parentheses = false
|
||||
ij_javascript_spaces_within_type_assertion = false
|
||||
ij_javascript_spaces_within_union_types = true
|
||||
ij_javascript_spaces_within_while_parentheses = false
|
||||
ij_javascript_special_else_if_treatment = true
|
||||
ij_javascript_ternary_operation_signs_on_next_line = false
|
||||
ij_javascript_ternary_operation_wrap = off
|
||||
ij_javascript_union_types_wrap = on_every_item
|
||||
ij_javascript_use_chained_calls_group_indents = true
|
||||
ij_javascript_use_double_quotes = true
|
||||
ij_javascript_use_explicit_js_extension = global
|
||||
ij_javascript_use_path_mapping = always
|
||||
ij_javascript_use_public_modifier = false
|
||||
ij_javascript_use_semicolon_after_statement = true
|
||||
ij_javascript_var_declaration_wrap = normal
|
||||
ij_javascript_while_brace_force = always
|
||||
ij_javascript_while_on_new_line = false
|
||||
ij_javascript_wrap_comments = false
|
||||
|
||||
[{*.ctp,*.hphp,*.inc,*.module,*.php,*.php4,*.php5,*.phtml}]
|
||||
indent_style = tab
|
||||
ij_continuation_indent_size = 4
|
||||
ij_smart_tabs = true
|
||||
ij_wrap_on_typing = false
|
||||
ij_php_align_assignments = false
|
||||
ij_php_align_class_constants = false
|
||||
ij_php_align_group_field_declarations = false
|
||||
ij_php_align_inline_comments = false
|
||||
ij_php_align_key_value_pairs = false
|
||||
ij_php_align_multiline_array_initializer_expression = false
|
||||
ij_php_align_multiline_binary_operation = false
|
||||
ij_php_align_multiline_chained_methods = false
|
||||
ij_php_align_multiline_extends_list = false
|
||||
ij_php_align_multiline_for = true
|
||||
ij_php_align_multiline_parameters = false
|
||||
ij_php_align_multiline_parameters_in_calls = false
|
||||
ij_php_align_multiline_ternary_operation = false
|
||||
ij_php_align_phpdoc_comments = false
|
||||
ij_php_align_phpdoc_param_names = false
|
||||
ij_php_anonymous_brace_style = end_of_line
|
||||
ij_php_api_weight = 1
|
||||
ij_php_array_initializer_new_line_after_left_brace = true
|
||||
ij_php_array_initializer_right_brace_on_new_line = true
|
||||
ij_php_array_initializer_wrap = on_every_item
|
||||
ij_php_assignment_wrap = off
|
||||
ij_php_author_weight = 8
|
||||
ij_php_binary_operation_sign_on_next_line = false
|
||||
ij_php_binary_operation_wrap = off
|
||||
ij_php_blank_lines_after_class_header = 0
|
||||
ij_php_blank_lines_after_function = 1
|
||||
ij_php_blank_lines_after_imports = 1
|
||||
ij_php_blank_lines_after_opening_tag = 0
|
||||
ij_php_blank_lines_after_package = 1
|
||||
ij_php_blank_lines_around_class = 1
|
||||
ij_php_blank_lines_around_constants = 0
|
||||
ij_php_blank_lines_around_field = 0
|
||||
ij_php_blank_lines_around_method = 1
|
||||
ij_php_blank_lines_before_class_end = 0
|
||||
ij_php_blank_lines_before_imports = 1
|
||||
ij_php_blank_lines_before_method_body = 0
|
||||
ij_php_blank_lines_before_package = 1
|
||||
ij_php_blank_lines_before_return_statement = 1
|
||||
ij_php_blank_lines_between_imports = 0
|
||||
ij_php_block_brace_style = end_of_line
|
||||
ij_php_call_parameters_new_line_after_left_paren = false
|
||||
ij_php_call_parameters_right_paren_on_new_line = false
|
||||
ij_php_call_parameters_wrap = normal
|
||||
ij_php_catch_on_new_line = true
|
||||
ij_php_category_weight = 28
|
||||
ij_php_class_brace_style = next_line
|
||||
ij_php_comma_after_last_array_element = true
|
||||
ij_php_concat_spaces = false
|
||||
ij_php_copyright_weight = 28
|
||||
ij_php_deprecated_weight = 2
|
||||
ij_php_do_while_brace_force = always
|
||||
ij_php_else_if_style = as_is
|
||||
ij_php_else_on_new_line = false
|
||||
ij_php_example_weight = 4
|
||||
ij_php_extends_keyword_wrap = off
|
||||
ij_php_extends_list_wrap = off
|
||||
ij_php_fields_default_visibility = private
|
||||
ij_php_filesource_weight = 28
|
||||
ij_php_finally_on_new_line = true
|
||||
ij_php_for_brace_force = always
|
||||
ij_php_for_statement_new_line_after_left_paren = false
|
||||
ij_php_for_statement_right_paren_on_new_line = false
|
||||
ij_php_for_statement_wrap = off
|
||||
ij_php_force_short_declaration_array_style = false
|
||||
ij_php_getters_setters_naming_style = camel_case
|
||||
ij_php_getters_setters_order_style = getters_first
|
||||
ij_php_global_weight = 28
|
||||
ij_php_group_use_wrap = on_every_item
|
||||
ij_php_if_brace_force = always
|
||||
ij_php_if_lparen_on_next_line = false
|
||||
ij_php_if_rparen_on_next_line = false
|
||||
ij_php_ignore_weight = 28
|
||||
ij_php_import_sorting = alphabetic
|
||||
ij_php_indent_break_from_case = true
|
||||
ij_php_indent_case_from_switch = true
|
||||
ij_php_indent_code_in_php_tags = false
|
||||
ij_php_internal_weight = 0
|
||||
ij_php_keep_blank_lines_after_lbrace = 2
|
||||
ij_php_keep_blank_lines_before_right_brace = 2
|
||||
ij_php_keep_blank_lines_in_code = 2
|
||||
ij_php_keep_blank_lines_in_declarations = 2
|
||||
ij_php_keep_control_statement_in_one_line = true
|
||||
ij_php_keep_first_column_comment = true
|
||||
ij_php_keep_indents_on_empty_lines = false
|
||||
ij_php_keep_line_breaks = true
|
||||
ij_php_keep_rparen_and_lbrace_on_one_line = false
|
||||
ij_php_keep_simple_classes_in_one_line = false
|
||||
ij_php_keep_simple_methods_in_one_line = false
|
||||
ij_php_lambda_brace_style = end_of_line
|
||||
ij_php_license_weight = 28
|
||||
ij_php_line_comment_add_space = false
|
||||
ij_php_line_comment_at_first_column = true
|
||||
ij_php_link_weight = 28
|
||||
ij_php_lower_case_boolean_const = true
|
||||
ij_php_lower_case_keywords = true
|
||||
ij_php_lower_case_null_const = true
|
||||
ij_php_method_brace_style = next_line
|
||||
ij_php_method_call_chain_wrap = off
|
||||
ij_php_method_parameters_new_line_after_left_paren = true
|
||||
ij_php_method_parameters_right_paren_on_new_line = true
|
||||
ij_php_method_parameters_wrap = normal
|
||||
ij_php_method_weight = 28
|
||||
ij_php_modifier_list_wrap = false
|
||||
ij_php_multiline_chained_calls_semicolon_on_new_line = false
|
||||
ij_php_namespace_brace_style = 1
|
||||
ij_php_new_line_after_php_opening_tag = false
|
||||
ij_php_null_type_position = in_the_end
|
||||
ij_php_package_weight = 28
|
||||
ij_php_param_weight = 5
|
||||
ij_php_parentheses_expression_new_line_after_left_paren = false
|
||||
ij_php_parentheses_expression_right_paren_on_new_line = false
|
||||
ij_php_phpdoc_blank_line_before_tags = true
|
||||
ij_php_phpdoc_blank_lines_around_parameters = true
|
||||
ij_php_phpdoc_keep_blank_lines = true
|
||||
ij_php_phpdoc_param_spaces_between_name_and_description = 1
|
||||
ij_php_phpdoc_param_spaces_between_tag_and_type = 1
|
||||
ij_php_phpdoc_param_spaces_between_type_and_name = 1
|
||||
ij_php_phpdoc_use_fqcn = true
|
||||
ij_php_phpdoc_wrap_long_lines = true
|
||||
ij_php_place_assignment_sign_on_next_line = false
|
||||
ij_php_place_parens_for_constructor = 0
|
||||
ij_php_property_read_weight = 28
|
||||
ij_php_property_weight = 28
|
||||
ij_php_property_write_weight = 28
|
||||
ij_php_return_type_on_new_line = false
|
||||
ij_php_return_weight = 6
|
||||
ij_php_see_weight = 3
|
||||
ij_php_since_weight = 28
|
||||
ij_php_sort_phpdoc_elements = true
|
||||
ij_php_space_after_colon = true
|
||||
ij_php_space_after_colon_in_return_type = true
|
||||
ij_php_space_after_comma = true
|
||||
ij_php_space_after_for_semicolon = true
|
||||
ij_php_space_after_quest = true
|
||||
ij_php_space_after_type_cast = false
|
||||
ij_php_space_after_unary_not = false
|
||||
ij_php_space_before_array_initializer_left_brace = false
|
||||
ij_php_space_before_catch_keyword = true
|
||||
ij_php_space_before_catch_left_brace = true
|
||||
ij_php_space_before_catch_parentheses = true
|
||||
ij_php_space_before_class_left_brace = true
|
||||
ij_php_space_before_closure_left_parenthesis = true
|
||||
ij_php_space_before_colon = true
|
||||
ij_php_space_before_colon_in_return_type = false
|
||||
ij_php_space_before_comma = false
|
||||
ij_php_space_before_do_left_brace = true
|
||||
ij_php_space_before_else_keyword = true
|
||||
ij_php_space_before_else_left_brace = true
|
||||
ij_php_space_before_finally_keyword = true
|
||||
ij_php_space_before_finally_left_brace = true
|
||||
ij_php_space_before_for_left_brace = true
|
||||
ij_php_space_before_for_parentheses = true
|
||||
ij_php_space_before_for_semicolon = false
|
||||
ij_php_space_before_if_left_brace = true
|
||||
ij_php_space_before_if_parentheses = true
|
||||
ij_php_space_before_method_call_parentheses = false
|
||||
ij_php_space_before_method_left_brace = true
|
||||
ij_php_space_before_method_parentheses = false
|
||||
ij_php_space_before_quest = true
|
||||
ij_php_space_before_short_closure_left_parenthesis = false
|
||||
ij_php_space_before_switch_left_brace = true
|
||||
ij_php_space_before_switch_parentheses = true
|
||||
ij_php_space_before_try_left_brace = true
|
||||
ij_php_space_before_unary_not = false
|
||||
ij_php_space_before_while_keyword = true
|
||||
ij_php_space_before_while_left_brace = true
|
||||
ij_php_space_before_while_parentheses = true
|
||||
ij_php_space_between_ternary_quest_and_colon = false
|
||||
ij_php_spaces_around_additive_operators = true
|
||||
ij_php_spaces_around_arrow = false
|
||||
ij_php_spaces_around_assignment_in_declare = false
|
||||
ij_php_spaces_around_assignment_operators = true
|
||||
ij_php_spaces_around_bitwise_operators = true
|
||||
ij_php_spaces_around_equality_operators = true
|
||||
ij_php_spaces_around_logical_operators = true
|
||||
ij_php_spaces_around_multiplicative_operators = true
|
||||
ij_php_spaces_around_null_coalesce_operator = true
|
||||
ij_php_spaces_around_relational_operators = true
|
||||
ij_php_spaces_around_shift_operators = true
|
||||
ij_php_spaces_around_unary_operator = false
|
||||
ij_php_spaces_around_var_within_brackets = false
|
||||
ij_php_spaces_within_array_initializer_braces = false
|
||||
ij_php_spaces_within_brackets = false
|
||||
ij_php_spaces_within_catch_parentheses = false
|
||||
ij_php_spaces_within_for_parentheses = false
|
||||
ij_php_spaces_within_if_parentheses = false
|
||||
ij_php_spaces_within_method_call_parentheses = false
|
||||
ij_php_spaces_within_method_parentheses = false
|
||||
ij_php_spaces_within_parentheses = false
|
||||
ij_php_spaces_within_short_echo_tags = true
|
||||
ij_php_spaces_within_switch_parentheses = false
|
||||
ij_php_spaces_within_while_parentheses = false
|
||||
ij_php_special_else_if_treatment = true
|
||||
ij_php_subpackage_weight = 28
|
||||
ij_php_ternary_operation_signs_on_next_line = false
|
||||
ij_php_ternary_operation_wrap = off
|
||||
ij_php_throws_weight = 7
|
||||
ij_php_todo_weight = 28
|
||||
ij_php_unknown_tag_weight = 28
|
||||
ij_php_upper_case_boolean_const = false
|
||||
ij_php_upper_case_null_const = false
|
||||
ij_php_uses_weight = 28
|
||||
ij_php_var_weight = 28
|
||||
ij_php_variable_naming_style = mixed
|
||||
ij_php_version_weight = 28
|
||||
ij_php_while_brace_force = always
|
||||
ij_php_while_on_new_line = false
|
||||
|
||||
[{*.har,*.jsb2,*.jsb3,*.json,.babelrc,.eslintrc,.stylelintrc,bowerrc,composer.lock,jest.config}]
|
||||
indent_size = 2
|
||||
ij_json_keep_blank_lines_in_code = 0
|
||||
ij_json_keep_indents_on_empty_lines = false
|
||||
ij_json_keep_line_breaks = true
|
||||
ij_json_space_after_colon = true
|
||||
ij_json_space_after_comma = true
|
||||
ij_json_space_before_colon = true
|
||||
ij_json_space_before_comma = false
|
||||
ij_json_spaces_within_braces = false
|
||||
ij_json_spaces_within_brackets = false
|
||||
ij_json_wrap_long_lines = false
|
||||
|
||||
[{*.htm,*.html,*.sht,*.shtm,*.shtml}]
|
||||
indent_style = tab
|
||||
ij_smart_tabs = true
|
||||
ij_html_add_new_line_before_tags = body,div,p,form,h1,h2,h3
|
||||
ij_html_align_attributes = true
|
||||
ij_html_align_text = false
|
||||
ij_html_attribute_wrap = normal
|
||||
ij_html_block_comment_at_first_column = true
|
||||
ij_html_do_not_align_children_of_min_lines = 0
|
||||
ij_html_do_not_break_if_inline_tags = title,h1,h2,h3,h4,h5,h6,p
|
||||
ij_html_do_not_indent_children_of_tags = html,body,thead,tbody,tfoot,style,script,head
|
||||
ij_html_enforce_quotes = false
|
||||
ij_html_inline_tags = a,abbr,acronym,b,basefont,bdo,big,br,cite,cite,code,dfn,em,font,i,img,input,kbd,label,q,s,samp,select,small,span,strike,strong,sub,sup,textarea,tt,u,var
|
||||
ij_html_keep_blank_lines = 2
|
||||
ij_html_keep_indents_on_empty_lines = false
|
||||
ij_html_keep_line_breaks = true
|
||||
ij_html_keep_line_breaks_in_text = true
|
||||
ij_html_keep_whitespaces = false
|
||||
ij_html_keep_whitespaces_inside = span,pre,textarea
|
||||
ij_html_line_comment_at_first_column = true
|
||||
ij_html_new_line_after_last_attribute = never
|
||||
ij_html_new_line_before_first_attribute = never
|
||||
ij_html_quote_style = none
|
||||
ij_html_remove_new_line_before_tags = br
|
||||
ij_html_space_after_tag_name = false
|
||||
ij_html_space_around_equality_in_attribute = false
|
||||
ij_html_space_inside_empty_tag = false
|
||||
ij_html_text_wrap = normal
|
||||
ij_html_uniform_ident = false
|
||||
|
||||
[{*.yaml,*.yml}]
|
||||
indent_size = 2
|
||||
ij_yaml_keep_indents_on_empty_lines = false
|
||||
ij_yaml_keep_line_breaks = true
|
||||
ij_yaml_space_before_colon = true
|
||||
ij_yaml_spaces_within_braces = true
|
||||
ij_yaml_spaces_within_brackets = true
|
||||
19
.gitignore
vendored
19
.gitignore
vendored
@@ -3,6 +3,15 @@
|
||||
/toolkit
|
||||
/env-*
|
||||
|
||||
# maintenance mode (N°2240)
|
||||
/.maintenance
|
||||
|
||||
# listing prevention in conf directory
|
||||
/conf/**
|
||||
!/conf/.htaccess
|
||||
!/conf/index.php
|
||||
!/conf/web.config
|
||||
|
||||
# composer reserver directory, from sources, populate/update using "composer install"
|
||||
vendor/*
|
||||
test/vendor/*
|
||||
@@ -31,11 +40,10 @@ test/vendor/*
|
||||
|
||||
# Jetbrains
|
||||
/.idea/**
|
||||
!/.idea/encodings.xml
|
||||
!/.idea/codeStyles
|
||||
!/.idea/codeStyles/*
|
||||
!/.idea/inspectionProfiles
|
||||
!/.idea/inspectionProfiles/*
|
||||
|
||||
# doc. generation
|
||||
/.doc/vendor
|
||||
|
||||
|
||||
#phpdocumentor temp file
|
||||
ast.dump
|
||||
@@ -126,4 +134,3 @@ local.properties
|
||||
.cache-main
|
||||
.scala_dependencies
|
||||
.worksheet
|
||||
|
||||
|
||||
57
.idea/codeStyles/Project.xml
generated
57
.idea/codeStyles/Project.xml
generated
@@ -1,57 +0,0 @@
|
||||
<component name="ProjectCodeStyleConfiguration">
|
||||
<code_scheme name="Project" version="173">
|
||||
<option name="LINE_SEPARATOR" value=" " />
|
||||
<option name="RIGHT_MARGIN" value="320" />
|
||||
<HTMLCodeStyleSettings>
|
||||
<option name="HTML_DO_NOT_INDENT_CHILDREN_OF" value="html,body,thead,tbody,tfoot,script,style" />
|
||||
<option name="HTML_DO_NOT_ALIGN_CHILDREN_OF_MIN_LINES" value="4" />
|
||||
</HTMLCodeStyleSettings>
|
||||
<PHPCodeStyleSettings>
|
||||
<option name="CONCAT_SPACES" value="false" />
|
||||
<option name="PHPDOC_BLANK_LINE_BEFORE_TAGS" value="true" />
|
||||
<option name="PHPDOC_BLANK_LINES_AROUND_PARAMETERS" value="true" />
|
||||
<option name="PHPDOC_WRAP_LONG_LINES" value="true" />
|
||||
<option name="LOWER_CASE_BOOLEAN_CONST" value="true" />
|
||||
<option name="LOWER_CASE_NULL_CONST" value="true" />
|
||||
<option name="BLANK_LINES_BEFORE_RETURN_STATEMENT" value="1" />
|
||||
<option name="KEEP_RPAREN_AND_LBRACE_ON_ONE_LINE" value="true" />
|
||||
<option name="PHPDOC_USE_FQCN" value="true" />
|
||||
</PHPCodeStyleSettings>
|
||||
<codeStyleSettings language="JavaScript">
|
||||
<option name="BRACE_STYLE" value="2" />
|
||||
<option name="ELSE_ON_NEW_LINE" value="true" />
|
||||
<option name="IF_BRACE_FORCE" value="3" />
|
||||
<indentOptions>
|
||||
<option name="USE_TAB_CHARACTER" value="true" />
|
||||
</indentOptions>
|
||||
</codeStyleSettings>
|
||||
<codeStyleSettings language="PHP">
|
||||
<option name="RIGHT_MARGIN" value="320" />
|
||||
<option name="BLANK_LINES_AFTER_PACKAGE" value="1" />
|
||||
<option name="BRACE_STYLE" value="2" />
|
||||
<option name="ELSE_ON_NEW_LINE" value="true" />
|
||||
<option name="ALIGN_MULTILINE_PARAMETERS" value="false" />
|
||||
<option name="SPACE_BEFORE_FOR_PARENTHESES" value="false" />
|
||||
<option name="CALL_PARAMETERS_WRAP" value="1" />
|
||||
<option name="METHOD_PARAMETERS_WRAP" value="1" />
|
||||
<option name="METHOD_PARAMETERS_LPAREN_ON_NEXT_LINE" value="true" />
|
||||
<option name="METHOD_PARAMETERS_RPAREN_ON_NEXT_LINE" value="true" />
|
||||
<option name="ARRAY_INITIALIZER_WRAP" value="5" />
|
||||
<option name="ARRAY_INITIALIZER_LBRACE_ON_NEXT_LINE" value="true" />
|
||||
<option name="ARRAY_INITIALIZER_RBRACE_ON_NEXT_LINE" value="true" />
|
||||
<option name="IF_BRACE_FORCE" value="3" />
|
||||
<option name="DOWHILE_BRACE_FORCE" value="3" />
|
||||
<option name="WHILE_BRACE_FORCE" value="3" />
|
||||
<option name="FOR_BRACE_FORCE" value="3" />
|
||||
<indentOptions>
|
||||
<option name="USE_TAB_CHARACTER" value="true" />
|
||||
<option name="SMART_TABS" value="true" />
|
||||
</indentOptions>
|
||||
</codeStyleSettings>
|
||||
<codeStyleSettings language="XML">
|
||||
<indentOptions>
|
||||
<option name="USE_TAB_CHARACTER" value="true" />
|
||||
</indentOptions>
|
||||
</codeStyleSettings>
|
||||
</code_scheme>
|
||||
</component>
|
||||
5
.idea/codeStyles/codeStyleConfig.xml
generated
5
.idea/codeStyles/codeStyleConfig.xml
generated
@@ -1,5 +0,0 @@
|
||||
<component name="ProjectCodeStyleConfiguration">
|
||||
<state>
|
||||
<option name="PREFERRED_PROJECT_CODE_STYLE" value="Combodo" />
|
||||
</state>
|
||||
</component>
|
||||
6
.idea/encodings.xml
generated
6
.idea/encodings.xml
generated
@@ -1,6 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="Encoding" defaultCharsetForPropertiesFiles="UTF-8">
|
||||
<file url="PROJECT" charset="UTF-8" />
|
||||
</component>
|
||||
</project>
|
||||
44
.idea/inspectionProfiles/Combodo.xml
generated
44
.idea/inspectionProfiles/Combodo.xml
generated
@@ -1,44 +0,0 @@
|
||||
<component name="InspectionProjectProfileManager">
|
||||
<profile version="1.0">
|
||||
<option name="myName" value="Combodo" />
|
||||
<inspection_tool class="InconsistentLineSeparators" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||
<inspection_tool class="MysqlParsingInspection" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="PhpIncludeInspection" enabled="true" level="WEAK WARNING" enabled_by_default="true" />
|
||||
<inspection_tool class="PhpMethodParametersCountMismatchInspection" enabled="true" level="ERROR" enabled_by_default="true" />
|
||||
<inspection_tool class="PhpTooManyParametersInspection" enabled="true" level="WARNING" enabled_by_default="true">
|
||||
<option name="limit" value="7" />
|
||||
</inspection_tool>
|
||||
<inspection_tool class="PhpUndefinedClassInspection" enabled="true" level="WARNING" enabled_by_default="true">
|
||||
<option name="DONT_REPORT_MULTI_RESOLVE" value="true" />
|
||||
</inspection_tool>
|
||||
<inspection_tool class="PhpUndefinedMethodInspection" enabled="true" level="WEAK WARNING" enabled_by_default="true" />
|
||||
<inspection_tool class="PhpUnhandledExceptionInspection" enabled="true" level="WEAK WARNING" enabled_by_default="true" />
|
||||
<inspection_tool class="PhpUnusedLocalVariableInspection" enabled="true" level="WEAK WARNING" enabled_by_default="true">
|
||||
<option name="DONT_REPORT_INSIDE_LIST" value="true" />
|
||||
</inspection_tool>
|
||||
<inspection_tool class="PhpUnusedParameterInspection" enabled="true" level="WEAK WARNING" enabled_by_default="true">
|
||||
<option name="DONT_REPORT_ABSTRACT_CLASS" value="true" />
|
||||
</inspection_tool>
|
||||
<inspection_tool class="SqlAddNotNullColumnInspection" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="SqlAmbiguousColumnInspection" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="SqlAutoIncrementDuplicateInspection" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="SqlCheckUsingColumnsInspection" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="SqlConstantConditionInspection" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="SqlDeprecateTypeInspection" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="SqlDerivedTableAliasInspection" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="SqlDialectInspection" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="SqlDropIndexedColumnInspection" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="SqlIdentifierInspection" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="SqlInsertValuesInspection" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="SqlNoDataSourceInspection" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="SqlNullComparisonInspection" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="SqlPostgresqlSelectFromProcedureInspection" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="SqlResolveInspection" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="SqlShouldBeInGroupByInspection" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="SqlSideEffectsInspection" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="SqlSignatureInspection" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="SqlStorageInspection" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="SqlTypeInspection" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="SqlUnusedVariableInspection" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
</profile>
|
||||
</component>
|
||||
19
.idea/inspectionProfiles/Project_Default.xml
generated
19
.idea/inspectionProfiles/Project_Default.xml
generated
@@ -1,19 +0,0 @@
|
||||
<component name="InspectionProjectProfileManager">
|
||||
<profile version="1.0">
|
||||
<option name="myName" value="Project Default" />
|
||||
<inspection_tool class="InconsistentLineSeparators" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||
<inspection_tool class="PhpIncludeInspection" enabled="true" level="WEAK WARNING" enabled_by_default="true" />
|
||||
<inspection_tool class="PhpMethodParametersCountMismatchInspection" enabled="true" level="ERROR" enabled_by_default="true" />
|
||||
<inspection_tool class="PhpTooManyParametersInspection" enabled="true" level="WARNING" enabled_by_default="true">
|
||||
<option name="limit" value="7" />
|
||||
</inspection_tool>
|
||||
<inspection_tool class="PhpUndefinedClassInspection" enabled="true" level="WARNING" enabled_by_default="true">
|
||||
<option name="DONT_REPORT_MULTI_RESOLVE" value="true" />
|
||||
</inspection_tool>
|
||||
<inspection_tool class="PhpUnhandledExceptionInspection" enabled="true" level="WEAK WARNING" enabled_by_default="true" />
|
||||
<inspection_tool class="PhpUnusedParameterInspection" enabled="true" level="WEAK WARNING" enabled_by_default="true">
|
||||
<option name="DONT_REPORT_ABSTRACT_CLASS" value="true" />
|
||||
</inspection_tool>
|
||||
<inspection_tool class="SqlNoDataSourceInspection" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
</profile>
|
||||
</component>
|
||||
6
.idea/inspectionProfiles/profiles_settings.xml
generated
6
.idea/inspectionProfiles/profiles_settings.xml
generated
@@ -1,6 +0,0 @@
|
||||
<component name="InspectionProjectProfileManager">
|
||||
<settings>
|
||||
<option name="PROJECT_PROFILE" value="Combodo" />
|
||||
<version value="1.0" />
|
||||
</settings>
|
||||
</component>
|
||||
6
.make/README.md
Normal file
6
.make/README.md
Normal file
@@ -0,0 +1,6 @@
|
||||
= Make Doc =
|
||||
.make folder is meant to gather tools for releasing process. Maybe other new purposes will come as well....
|
||||
|
||||
== license ==
|
||||
- updateLicenses.php: used to update community-licenses.xml easily based on composer.json files
|
||||
- sortLicenceXml.php: used to sort licenses based on scope + product name
|
||||
90
.make/build/afterBuild.php
Normal file
90
.make/build/afterBuild.php
Normal file
@@ -0,0 +1,90 @@
|
||||
<?php
|
||||
$iBeginTime = time();
|
||||
|
||||
chdir(__DIR__);
|
||||
|
||||
$aCommands = [
|
||||
'php composer/rmDeniedTestDir.php',
|
||||
'php build/commands/setupCssCompiler.php',
|
||||
// 'bash /tmp/gabuzomeu.sh',
|
||||
];
|
||||
|
||||
$aFailedCommands=[];
|
||||
foreach ($aCommands as $sCommand)
|
||||
{
|
||||
if (!ExecCommand($sCommand))
|
||||
{
|
||||
$aFailedCommands[] = $sCommand;
|
||||
}
|
||||
}
|
||||
|
||||
$iElapsed = time() - $iBeginTime;
|
||||
|
||||
if (count($aFailedCommands))
|
||||
{
|
||||
fwrite(STDERR, "\nafterBuild execution failed! (in ${iElapsed}s)\n");
|
||||
fwrite(STDERR, "List of failling commands:\n - " . implode("\n - ", $aFailedCommands) . "\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
|
||||
echo "\nDone (${iElapsed}s)\n";
|
||||
exit(0);
|
||||
|
||||
/**
|
||||
* Executes a command and returns an array with exit code, stdout and stderr content
|
||||
*
|
||||
* @param string $cmd - Command to execute
|
||||
*
|
||||
* @return bool
|
||||
* @throws \Exception
|
||||
*/
|
||||
function ExecCommand($cmd) {
|
||||
$iBeginTime = time();
|
||||
|
||||
|
||||
echo sprintf("command: %s", str_pad("$cmd ", 50));
|
||||
|
||||
$descriptorspec = array(
|
||||
0 => array("pipe", "r"), // stdin
|
||||
1 => array("pipe", "w"), // stdout
|
||||
2 => array("pipe", "w"), // stderr
|
||||
);
|
||||
$process = proc_open($cmd, $descriptorspec, $pipes, __DIR__ . '/..', null);
|
||||
|
||||
$stdout = stream_get_contents($pipes[1]);
|
||||
fclose($pipes[1]);
|
||||
|
||||
$stderr = stream_get_contents($pipes[2]);
|
||||
fclose($pipes[2]);
|
||||
|
||||
$iCode = proc_close($process);
|
||||
$bSuccess = (0 === $iCode);
|
||||
|
||||
$iElapsed = time() - $iBeginTime;
|
||||
if (!$bSuccess) {
|
||||
fwrite(STDERR, sprintf(
|
||||
"\nCOMMAND FAILED! (%s) \n - status:%s \n - stderr:%s \n - stdout: %s\n - elapsed:%ss\n\n",
|
||||
$cmd,
|
||||
$iCode,
|
||||
rtrim($stderr),
|
||||
rtrim($stdout),
|
||||
$iElapsed
|
||||
));
|
||||
}
|
||||
else
|
||||
{
|
||||
echo "| elapsed:${iElapsed}s \n";
|
||||
}
|
||||
|
||||
if (!empty($stderr))
|
||||
{
|
||||
fwrite(STDERR, "$stderr\n");
|
||||
}
|
||||
if (!empty($stdout))
|
||||
{
|
||||
echo "stdout :$stdout\n\n";
|
||||
}
|
||||
|
||||
return $bSuccess;
|
||||
}
|
||||
51
.make/build/commands/setupCssCompiler.php
Normal file
51
.make/build/commands/setupCssCompiler.php
Normal file
@@ -0,0 +1,51 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Copyright (C) 2010-2020 Combodo SARL
|
||||
*
|
||||
* This file is part of iTop.
|
||||
*
|
||||
* iTop is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* iTop is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with iTop. If not, see <http: *www.gnu.org/licenses/>
|
||||
*
|
||||
*/
|
||||
|
||||
use Combodo\iTop\Composer\iTopComposer;
|
||||
|
||||
$iTopFolder = __DIR__."/../../../";
|
||||
|
||||
require_once("$iTopFolder/approot.inc.php");
|
||||
require_once(APPROOT."/application/utils.inc.php");
|
||||
|
||||
if (php_sapi_name() !== 'cli')
|
||||
{
|
||||
throw new \Exception('This script can only run from CLI');
|
||||
}
|
||||
|
||||
$sCssFile = APPROOT.'/css/setup.css';
|
||||
if (file_exists($sCssFile))
|
||||
{
|
||||
fwrite(STDERR, "$sCssFile already exists (it should not), removing it.");
|
||||
if (!unlink($sCssFile))
|
||||
{
|
||||
fwrite(STDERR, "Failed to remove $sCssFile, exiting.");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
$sCssRelPath = utils::GetCSSFromSASS('css/setup.scss');
|
||||
|
||||
if (!file_exists($sCssFile))
|
||||
{
|
||||
fwrite(STDERR, "Failed to compile $sCssFile, exiting.");
|
||||
exit(1);
|
||||
}
|
||||
98
.make/composer/listOutdated.php
Normal file
98
.make/composer/listOutdated.php
Normal file
@@ -0,0 +1,98 @@
|
||||
<?php
|
||||
/**
|
||||
* Copyright (C) 2010-2020 Combodo SARL
|
||||
*
|
||||
* This file is part of iTop.
|
||||
*
|
||||
* iTop is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* iTop is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with iTop. If not, see <http: *www.gnu.org/licenses/>
|
||||
*
|
||||
*/
|
||||
|
||||
$iTopFolder = __DIR__ . "/../../" ;
|
||||
|
||||
require_once ("$iTopFolder/approot.inc.php");
|
||||
$sApproot = APPROOT;
|
||||
$aTrace = array();
|
||||
|
||||
$aParamsConfig = array(
|
||||
'composer-path' => array(
|
||||
'default' => 'composer.phar',
|
||||
)
|
||||
);
|
||||
$aParamsConfigNotFound = array_flip(array_keys($aParamsConfig));
|
||||
$aGivenArgs = $argv;
|
||||
unset($aGivenArgs[0]);
|
||||
|
||||
$aParams = array();
|
||||
|
||||
foreach ($aParamsConfig as $sParam => $aConfig)
|
||||
{
|
||||
$bParamsFound = false;
|
||||
foreach ($aGivenArgs as $sGivenArg)
|
||||
{
|
||||
if (preg_match("/--$sParam(?:=(?<value>.*))?$/", $sGivenArg, $aMatches))
|
||||
{
|
||||
$aParams[$sParam] =
|
||||
isset($aMatches['value'])
|
||||
? $aMatches['value']
|
||||
: true
|
||||
;
|
||||
$bParamsFound = true;
|
||||
unset($aGivenArgs[$sGivenArg]);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
if ($bParamsFound)
|
||||
{
|
||||
unset($aParamsConfigNotFound[$sParam]);
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($aParamsConfigNotFound as $sParamsConfigNotFound => $void)
|
||||
{
|
||||
if (isset($aParamsConfig[$sParamsConfigNotFound]['default']))
|
||||
{
|
||||
$aParams[$sParamsConfigNotFound] = $aParamsConfig[$sParamsConfigNotFound]['default'];
|
||||
$aTrace[] = "\e[1;30mUsing default value '{$aParams[$sParamsConfigNotFound]}' for '$sParamsConfigNotFound'\e[0m\n";
|
||||
continue;
|
||||
}
|
||||
|
||||
die("Missing '$sParamsConfigNotFound'");
|
||||
}
|
||||
|
||||
echo "This command aims at helping you find upgradable dependencies\n";
|
||||
echo "\e[0;33mBeware of the version colored in orange, they probably introduce BC breaks!\e[0m\n";
|
||||
|
||||
$sCommand = "{$aParams['composer-path']} show -loD --working-dir=$sApproot --ansi";
|
||||
$execCode = exec($sCommand, $output);
|
||||
$sOutput = implode("\n", $output)."\n";
|
||||
|
||||
if (!$execCode)
|
||||
{
|
||||
echo "\e[41mFailed to execute '$sCommand'\e[0m\n";
|
||||
echo "Trace: \n".implode("\n", $aTrace);
|
||||
}
|
||||
else
|
||||
{
|
||||
$iCountDepdendenciesFound = count($output);
|
||||
|
||||
$iCountBc = substr_count($sOutput, '[33m');
|
||||
|
||||
echo sprintf("Found \033[44m%d\033[0m upgradable dependencies, including \e[41m%s BC break\e[0m 😱 :\n\n", $iCountDepdendenciesFound, $iCountBc);
|
||||
}
|
||||
|
||||
|
||||
echo $sOutput;
|
||||
|
||||
57
.make/composer/rmDeniedTestDir.php
Normal file
57
.make/composer/rmDeniedTestDir.php
Normal file
@@ -0,0 +1,57 @@
|
||||
<?php
|
||||
/**
|
||||
* Copyright (C) 2010-2020 Combodo SARL
|
||||
*
|
||||
* This file is part of iTop.
|
||||
*
|
||||
* iTop is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* iTop is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with iTop. If not, see <http: *www.gnu.org/licenses/>
|
||||
*
|
||||
*/
|
||||
|
||||
use Combodo\iTop\Composer\iTopComposer;
|
||||
|
||||
$iTopFolder = __DIR__ . "/../../" ;
|
||||
|
||||
require_once ("$iTopFolder/approot.inc.php");
|
||||
require_once (APPROOT."/setup/setuputils.class.inc.php");
|
||||
|
||||
if (php_sapi_name() !== 'cli')
|
||||
{
|
||||
throw new \Exception('This script can only run from CLI');
|
||||
}
|
||||
|
||||
clearstatcache();
|
||||
|
||||
$oiTopComposer = new iTopComposer();
|
||||
$aDeniedButStillPresent = $oiTopComposer->ListDeniedButStillPresent();
|
||||
|
||||
foreach ($aDeniedButStillPresent as $sDir)
|
||||
{
|
||||
if (! preg_match('#[tT]ests?/?$#', $sDir))
|
||||
{
|
||||
echo "\nfound INVALID denied test dir: '$sDir'\n";
|
||||
throw new \Exception("$sDir must end with /Test/ or /test/");
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
SetupUtils::rrmdir($sDir);
|
||||
echo "Remove denied test dir: '$sDir'\n";
|
||||
}
|
||||
catch (\Exception $e)
|
||||
{
|
||||
echo "\nFAILED to remove denied test dir: '$sDir'\n";
|
||||
}
|
||||
|
||||
}
|
||||
90
.make/license/gen-community-license.sh
Normal file
90
.make/license/gen-community-license.sh
Normal file
@@ -0,0 +1,90 @@
|
||||
#/bin/bash
|
||||
|
||||
#git diff --name-status 2.6.2..HEAD js |grep 'A\sjs/' |awk -F/ '{printf("lib/%s/%s\n",$2,$3)}'|sort |uniq >/tmp/toto
|
||||
#git diff --name-status 2.6.2..HEAD lib |grep 'A\slib/' |awk -F/ '{printf("lib/%s/%s\n",$2,$3)}'|sort |uniq >/tmp/toto
|
||||
|
||||
function HELP(){
|
||||
echo " Syntax: bash $0 /var/www/html/iTop"
|
||||
}
|
||||
|
||||
if [ $# -eq 0 ]
|
||||
then
|
||||
echo "no iTop path provided"
|
||||
HELP
|
||||
exit 1
|
||||
fi
|
||||
|
||||
iTopPath=$1
|
||||
|
||||
if [ ! -d $iTopPath ]
|
||||
then
|
||||
echo "$iTopPath is not an iTop path."
|
||||
HELP
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "<?xml version=\"1.0\"?>
|
||||
<licenses>"
|
||||
|
||||
for subfolder in lib datamodels
|
||||
do
|
||||
for l in $(find $iTopPath/$subfolder/ -name composer.json|sed 's|/composer.json||')
|
||||
do
|
||||
if [ ! -d $l ]
|
||||
then
|
||||
continue
|
||||
fi
|
||||
if [ "$subfolder" == "datamodels" ]
|
||||
then
|
||||
if [ $(find $l -name module*.php|wc -l) -ne 0 -o $(echo "$l"|grep -c "itop-portal-base") -ne 0 ]
|
||||
then
|
||||
continue
|
||||
fi
|
||||
fi
|
||||
dir=$(dirname $(dirname $l))
|
||||
prod=$(echo $l| sed "s|$dir/||1")
|
||||
echo $l $subfolder
|
||||
lictype=$(cd $l && composer licenses --format json |jq .license[] |sed 's|\"||g')
|
||||
|
||||
authors=""
|
||||
if [ -f $l/composer.json ]
|
||||
then
|
||||
author_nb=$(grep -c authors $l/composer.json|sed 's| ||g')
|
||||
if [ "x$author_nb" != "x0" ]
|
||||
then
|
||||
OLDIFS=$IFS
|
||||
IFS=$'\n'
|
||||
for a in $(cat $l/composer.json |jq .authors[].name|sed 's|\"||g')
|
||||
do
|
||||
authors="$authors$a - "
|
||||
done
|
||||
authors="$authors#"
|
||||
authors=$(echo $authors |sed 's| - #||')
|
||||
IFS=$OLDIFS
|
||||
fi
|
||||
fi
|
||||
|
||||
lic=""
|
||||
for licf in $(find $l -name LICEN*)
|
||||
do
|
||||
lic=$(cat $licf)
|
||||
break
|
||||
done
|
||||
|
||||
#if [ "x$lic" == "x" ]
|
||||
#then
|
||||
# echo "============== no license found $l"
|
||||
#fi
|
||||
|
||||
echo " <license>
|
||||
<product scope=\"$subfolder\">$prod</product>
|
||||
<author>$authors</author>
|
||||
<license_type>$lictype</license_type>
|
||||
<text><![CDATA[
|
||||
$lic
|
||||
]]></text>
|
||||
</license>"
|
||||
done
|
||||
done
|
||||
|
||||
echo "</licenses>"
|
||||
64
.make/license/sortLicenceXml.php
Normal file
64
.make/license/sortLicenceXml.php
Normal file
@@ -0,0 +1,64 @@
|
||||
<?php
|
||||
/**
|
||||
* script used to sort license file (usefull for autogeneration)
|
||||
* Example:
|
||||
*/
|
||||
$iTopFolder = __DIR__ . "/../../" ;
|
||||
$xmlFilePath = $iTopFolder . "setup/licenses/community-licenses.xml";
|
||||
$dom = new DOMDocument();
|
||||
$dom->load($xmlFilePath);
|
||||
$xp = new DOMXPath($dom);
|
||||
|
||||
$licenseList = $xp->query('/licenses/license');
|
||||
$licenses = iterator_to_array($licenseList);
|
||||
|
||||
|
||||
function get_scope($product_node)
|
||||
{
|
||||
$scope = $product_node->getAttribute("scope");
|
||||
|
||||
if ($scope === "")
|
||||
{ //put iTop first
|
||||
return "aaaaaaaaa";
|
||||
}
|
||||
return $scope;
|
||||
}
|
||||
|
||||
function get_product_node($license_node)
|
||||
{
|
||||
foreach ($license_node->childNodes as $child)
|
||||
{
|
||||
if (is_a($child, 'DomElement') && $child->tagName === "product")
|
||||
{
|
||||
return $child;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
function sort_by_product($a, $b)
|
||||
{
|
||||
$aProductNode = get_product_node($a);
|
||||
$bProductNode = get_product_node($b);
|
||||
|
||||
$res = strcmp(get_scope($aProductNode), get_scope($bProductNode));
|
||||
if ($res !== 0)
|
||||
{
|
||||
return $res;
|
||||
}
|
||||
//sort on node product name
|
||||
return strcmp($aProductNode->nodeValue, $bProductNode->nodeValue);
|
||||
}
|
||||
|
||||
usort($licenses, 'sort_by_product');
|
||||
|
||||
$newdom = new DOMDocument("1.0");
|
||||
$newdom->formatOutput = true;
|
||||
$root = $newdom->createElement("licenses");
|
||||
$newdom->appendChild($root);
|
||||
foreach ($licenses as $b) {
|
||||
$node = $newdom->importNode($b,true);
|
||||
$root->appendChild($newdom->importNode($b,true));
|
||||
}
|
||||
|
||||
$newdom->save($xmlFilePath);
|
||||
89
.make/license/updateLicenses.php
Normal file
89
.make/license/updateLicenses.php
Normal file
@@ -0,0 +1,89 @@
|
||||
<?php
|
||||
/**
|
||||
* script used to sort license file (usefull for autogeneration)
|
||||
* Example: php
|
||||
*/
|
||||
|
||||
$iTopFolder = __DIR__ . "/../../" ;
|
||||
$xmlFilePath = $iTopFolder . "setup/licenses/community-licenses.xml";
|
||||
|
||||
function get_scope($product_node)
|
||||
{
|
||||
$scope = $product_node->getAttribute("scope");
|
||||
|
||||
if ($scope === "")
|
||||
{ //put iTop first
|
||||
return "aaaaaaaaa";
|
||||
}
|
||||
return $scope;
|
||||
}
|
||||
|
||||
function get_product_node($license_node)
|
||||
{
|
||||
foreach ($license_node->childNodes as $child)
|
||||
{
|
||||
if (is_a($child, 'DomElement') && $child->tagName === "product")
|
||||
{
|
||||
return $child;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
function sort_by_product($a, $b)
|
||||
{
|
||||
$aProductNode = get_product_node($a);
|
||||
$bProductNode = get_product_node($b);
|
||||
|
||||
$res = strcmp(get_scope($aProductNode), get_scope($bProductNode));
|
||||
if ($res !== 0)
|
||||
{
|
||||
return $res;
|
||||
}
|
||||
//sort on node product name
|
||||
return strcmp($aProductNode->nodeValue, $bProductNode->nodeValue);
|
||||
}
|
||||
|
||||
function get_license_nodes($file_path)
|
||||
{
|
||||
$dom = new DOMDocument();
|
||||
$dom->load($file_path);
|
||||
$xp = new DOMXPath($dom);
|
||||
|
||||
$licenseList = $xp->query('/licenses/license');
|
||||
$licenses = iterator_to_array($licenseList);
|
||||
|
||||
usort($licenses, 'sort_by_product');
|
||||
return $licenses;
|
||||
}
|
||||
|
||||
$old_licenses = get_license_nodes($xmlFilePath);
|
||||
|
||||
//generate file with updated licenses
|
||||
$generated_license_file_path = __DIR__."/provfile.xml";
|
||||
exec("bash " . __DIR__ . "/gen-community-license.sh $iTopFolder > ". $generated_license_file_path);
|
||||
$new_licenses = get_license_nodes($generated_license_file_path);
|
||||
exec("rm -f ". $generated_license_file_path);
|
||||
|
||||
foreach ($old_licenses as $b) {
|
||||
$aProductNode = get_product_node($b);
|
||||
|
||||
if (get_scope($aProductNode) !== "lib" && get_scope($aProductNode) !== "datamodels" )
|
||||
{
|
||||
$new_licenses[] = $b;
|
||||
}
|
||||
}
|
||||
|
||||
usort($new_licenses, 'sort_by_product');
|
||||
|
||||
$new_dom = new DOMDocument("1.0");
|
||||
$new_dom->formatOutput = true;
|
||||
$root = $new_dom->createElement("licenses");
|
||||
$new_dom->appendChild($root);
|
||||
|
||||
foreach ($new_licenses as $b) {
|
||||
$node = $new_dom->importNode($b,true);
|
||||
$root->appendChild($new_dom->importNode($b,true));
|
||||
}
|
||||
|
||||
$new_dom->save($xmlFilePath);
|
||||
139
CONTRIBUTING.md
Normal file
139
CONTRIBUTING.md
Normal file
@@ -0,0 +1,139 @@
|
||||
# Contributing to iTop
|
||||
|
||||
You want to contribute to iTop? Many thanks to you! 🎉 👍
|
||||
|
||||
Here are some guidelines that will help us integrate your work!
|
||||
|
||||
|
||||
## Contributions
|
||||
|
||||
### Subjects
|
||||
You are welcome to create pull requests on any of those subjects:
|
||||
|
||||
* 🐛 bug fix
|
||||
* 🌐 translation / i18n / l10n
|
||||
|
||||
If you want to implement a **new feature**, please [create a corresponding ticket](https://sourceforge.net/p/itop/tickets/new/) for review.
|
||||
If you ever want to begin implementation, do so in a fork, and add a link to the corresponding commits in the ticket.
|
||||
|
||||
For all **security related subjects**, please see our [security policy](SECURITY.md).
|
||||
|
||||
All **datamodel modification** should be done in an extension. Beware that such change would
|
||||
impact all existing customers, and could prevent them from
|
||||
upgrading!
|
||||
Combodo has a long experience of datamodel changes: they are very disruptive!
|
||||
This is why we avoid them in iTop core, especially the changes on existing objects/fields.
|
||||
If you have an idea you're sure would benefit to all of iTop users, you may
|
||||
[create a corresponding ticket](https://sourceforge.net/p/itop/tickets/new/) to submit it, but be warned that there are lots of good
|
||||
reasons to refuse such changes.
|
||||
|
||||
### 📄 License
|
||||
iTop is distributed under the AGPL-3.0 license (see the [license.txt] file),
|
||||
your code must comply with this license.
|
||||
|
||||
If you want to use another license, you may [create an extension][wiki new ext].
|
||||
|
||||
[license.txt]: https://github.com/Combodo/iTop/blob/develop/license.txt
|
||||
[wiki new ext]: https://www.itophub.io/wiki/page?id=latest%3Acustomization%3Astart#by_writing_your_own_extension
|
||||
|
||||
|
||||
## 🔀 iTop branch model
|
||||
|
||||
When we first start with Git, we were using the [GitFlow](https://nvie.com/posts/a-successful-git-branching-model/) branch model. As
|
||||
there was some confusions about branches to use for current developed release and previous maintained release, and also because we were
|
||||
using just a very few of the GitFlow commands, we decided to add just a little modification to this branch model : since april 2020
|
||||
we don't have anymore a `master` branch.
|
||||
|
||||
Here are the branches we use and their meaning :
|
||||
|
||||
- `develop`: ongoing development version
|
||||
- `release/*`: if present, that means we are working on a alpha/beta/rc version for shipping
|
||||
- `support/*`: maintenance branches for older versions
|
||||
|
||||
For example, if no version is currently prepared for shipping we could have:
|
||||
|
||||
- `develop` containing future 2.8.0 version
|
||||
- `support/2.7`: 2.7.x maintenance version
|
||||
- `support/2.6`: 2.6.x maintenance version
|
||||
- `support/2.5`: 2.5.x maintenance version
|
||||
|
||||
In this example, when 2.8.0-beta is shipped that will become:
|
||||
|
||||
- `develop`: future 2.9.0 version
|
||||
- `release/2.8`: 2.8.0-beta
|
||||
- `support/2.7`: 2.7.x maintenance version
|
||||
- `support/2.6`: 2.6.x maintenance version
|
||||
- `support/2.5`: 2.5.x maintenance version
|
||||
|
||||
And when 2.8.0 final will be out:
|
||||
|
||||
- `develop`: future 2.9.0 version
|
||||
- `support/2.8`: 2.8.x maintenance version (will host developments for 2.8.1)
|
||||
- `support/2.7`: 2.7.x maintenance version
|
||||
- `support/2.6`: 2.6.x maintenance version
|
||||
- `support/2.5`: 2.5.x maintenance version
|
||||
|
||||
Also note that we have a "micro-version" concept : each of those versions have a very small amount of modifications. They are made from
|
||||
`support/*` branches as well. For example 2.6.2-1 and 2.6.2-2 were made from the `support/2.6.2` branch.
|
||||
|
||||
|
||||
## Coding
|
||||
|
||||
### 🌐 Translations
|
||||
|
||||
A [dedicated page](https://www.itophub.io/wiki/page?id=latest%3Acustomization%3Atranslation) is available in the official wiki.
|
||||
|
||||
### Where to start ?
|
||||
|
||||
1. Create a fork from our repository (see [Working with forks - GitHub Help](https://help.github.com/en/github/collaborating-with-issues-and-pull-requests/working-with-forks))
|
||||
2. Create a branch in this fork, based on the develop branch
|
||||
3. Code !
|
||||
|
||||
Do create a dedicated branch for each modification you want to propose : if you don't it will be very hard to merge back your work !
|
||||
|
||||
Most of the time you should based your developments on the develop branch.
|
||||
That may be different if you want to fix a bug, please use develop anyway and ask in your PR if rebase is possible.
|
||||
|
||||
|
||||
### 🎨 PHP styleguide
|
||||
|
||||
Please follow [our guidelines](https://www.itophub.io/wiki/page?id=latest%3Acustomization%3Acoding_standards).
|
||||
|
||||
### ✅ Tests
|
||||
|
||||
Please create tests that covers as much as possible the code you're submitting.
|
||||
|
||||
Our tests are located in the `test/` directory, containing a PHPUnit config file : `phpunit.xml.dist`.
|
||||
|
||||
### Git Commit Messages
|
||||
|
||||
* Describe the functional change instead of the technical modifications
|
||||
* Use the present tense ("Add feature" not "Added feature")
|
||||
* Use the imperative mood ("Move cursor to..." not "Moves cursor to...")
|
||||
* Limit the first line to 72 characters or less
|
||||
* Please start the commit message with an applicable emoji code (following the [Gitmoji guide](https://gitmoji.carloscuesta.me/)).
|
||||
Beware to use the code (for example `:bug:`) and not the character (🐛) as Unicode support in git clients is very poor for now...
|
||||
Emoji examples :
|
||||
* 🌐 `:globe_with_meridians:` for translations
|
||||
* 🎨 `:art:` when improving the format/structure of the code
|
||||
* ⚡️ `:zap:` when improving performance
|
||||
* 🐛 `:bug:` when fixing a bug
|
||||
* 🔥 `:fire:` when removing code or files
|
||||
* 💚 `:green_heart:` when fixing the CI build
|
||||
* ✅ `:white_check_mark:` when adding tests
|
||||
* 🔒 `:lock:` when dealing with security
|
||||
* ⬆️ `:arrow_up:` when upgrading dependencies
|
||||
* ⬇️ `:arrow_down:` when downgrading dependencies
|
||||
* ♻️ `:recycle:` code refactoring
|
||||
* 💄 `:lipstick:` Updating the UI and style files.
|
||||
|
||||
|
||||
## 👥 Pull request
|
||||
|
||||
When your code is working, please:
|
||||
|
||||
* stash as much as possible your commits,
|
||||
* rebase your branch on our repo last commit,
|
||||
* create a pull request.
|
||||
|
||||
Detailed procedure to work on fork and create PR is available [in GitHub help pages](https://help.github.com/articles/creating-a-pull-request-from-a-fork/).
|
||||
117
README.md
117
README.md
@@ -23,43 +23,85 @@ iTop also offers mass import tools and web services to integrate with your IT
|
||||
|
||||
## Resources
|
||||
|
||||
- [iTop Forums][1]: for support request
|
||||
- [iTop Forums][1]: community support
|
||||
- [iTop Tickets][2]: for feature requests and bug reports
|
||||
- [Releases download][3]
|
||||
- [iTop documentation][4] for iTop and official extensions
|
||||
- [iTop extensions][5] for discovering and installing extensions
|
||||
- [Documentation][4] covering both iTop and its official extensions
|
||||
- [iTop Hub][5] : discover and install extensions !
|
||||
|
||||
|
||||
## Releases
|
||||
### Version 2.6
|
||||
|
||||
|
||||
[1]: https://sourceforge.net/p/itop/discussion/
|
||||
[2]: https://sourceforge.net/p/itop/tickets/
|
||||
[3]: https://sourceforge.net/projects/itop/files/itop/
|
||||
[4]: https://www.itophub.io/wiki
|
||||
[5]: https://store.itophub.io/en_US/
|
||||
|
||||
[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
|
||||
[12]: https://www.itophub.io/wiki/page?id=latest%3Adatamodel%3Astart#service_management
|
||||
[13]: https://www.itophub.io/wiki/page?id=latest%3Adatamodel%3Astart#change_management
|
||||
[14]: https://www.itophub.io/wiki/page?id=latest%3Aimplementation%3Astart#service_level_agreements_and_targets
|
||||
[15]: https://www.itophub.io/wiki/page?id=latest%3Auser%3Aactions#relations
|
||||
[16]: https://www.itophub.io/wiki/page?id=latest%3Auser%3Abulk_modify#uploading_data
|
||||
[17]: https://www.itophub.io/wiki/page?id=latest%3Aadmin%3Aaudit
|
||||
[18]: https://www.itophub.io/wiki/page?id=latest%3Aadvancedtopics%3Adata_synchro_overview
|
||||
|
||||
|
||||
|
||||
## Last releases
|
||||
|
||||
### Versions 2.7.*
|
||||
- 2.7.1 published on April 8, 2020
|
||||
- [Changes since the previous version][62]
|
||||
- [New features][63]
|
||||
- [Migration notes][64]
|
||||
- [Download iTop 2.7.0-2][65]
|
||||
|
||||
[62]: https://www.itophub.io/wiki/page?id=2_7_0:release:change_log
|
||||
[63]: https://www.itophub.io/wiki/page?id=2_7_0:release:2_7_whats_new
|
||||
[64]: https://www.itophub.io/wiki/page?id=2_7_0:install:260_to_270_migration_notes
|
||||
[65]: https://sourceforge.net/projects/itop/files/itop/2.7.0-2
|
||||
|
||||
|
||||
### Versions 2.6.*
|
||||
- 2.6.0 published on January 9, 2019
|
||||
- [Changes since the previous version][58]
|
||||
- [New features][59]
|
||||
- [Migration notes][60]
|
||||
- [Download iTop 2.6.3][61]
|
||||
|
||||
[58]: https://www.itophub.io/wiki/page?id=2_6_0:release:change_log
|
||||
[59]: https://www.itophub.io/wiki/page?id=2_6_0:release:2_6_whats_new
|
||||
[60]: https://www.itophub.io/wiki/page?id=2_6_0:install:250_to_260_migration_notes
|
||||
[61]: https://sourceforge.net/projects/itop/files/itop/2.6.3
|
||||
|
||||
### Version 2.5
|
||||
|
||||
### Versions 2.5.*
|
||||
- 2.5.0 published on July 11, 2018
|
||||
- [Changes since the previous version][54]
|
||||
- [New features][55]
|
||||
- [Migration notes][56]
|
||||
- [Download iTop 2.5.1][57]
|
||||
|
||||
|
||||
### Version 2.4
|
||||
- [Changes since the previous version][50]
|
||||
- [New features][51]
|
||||
- [Migration notes][52]
|
||||
- [Download iTop 2.4.1][53]
|
||||
[54]: https://www.itophub.io/wiki/page?id=2_5_0:release:change_log
|
||||
[55]: https://www.itophub.io/wiki/page?id=2_5_0:release:2_5_whats_new
|
||||
[56]: https://www.itophub.io/wiki/page?id=2_5_0:install:240_to_250_migration_notes
|
||||
[57]: https://sourceforge.net/projects/itop/files/itop/2.5.1
|
||||
|
||||
|
||||
# About Us
|
||||
## About Us
|
||||
|
||||
iTop development is sponsored, led and supported by [Combodo][0].
|
||||
|
||||
[0]: https://www.combodo.com
|
||||
|
||||
# Contributors
|
||||
|
||||
## Contributors
|
||||
|
||||
We would like to give a special thank you to the people from the community who contributed to this project, including:
|
||||
|
||||
### Names
|
||||
- Alves, David
|
||||
- Beck, Pedro
|
||||
- Bilger, Jean-François
|
||||
@@ -69,6 +111,7 @@ We would like to give a special thank you to the people from the community who c
|
||||
- Casteleyn, Thomas
|
||||
- Castro, Randall Badilla
|
||||
- Colantoni, Maria Laura
|
||||
- Couronné, Guy
|
||||
- Dvořák, Lukáš
|
||||
- Goethals, Stefan
|
||||
- Gumble, David
|
||||
@@ -78,6 +121,7 @@ We would like to give a special thank you to the people from the community who c
|
||||
- Konečný, Kamil
|
||||
- Kunin, Vladimir
|
||||
- Lassiter, Dennis
|
||||
- Lazcano, Federico
|
||||
- Lucas, Jonathan
|
||||
- Malik, Remie
|
||||
- Rosenke, Stephan
|
||||
@@ -86,7 +130,7 @@ We would like to give a special thank you to the people from the community who c
|
||||
- Tulio, Marco
|
||||
- Turrubiates, Miguel
|
||||
|
||||
#### Aliases
|
||||
### Aliases
|
||||
- chifu1234
|
||||
- cprobst
|
||||
- Karkoff1212
|
||||
@@ -97,45 +141,8 @@ We would like to give a special thank you to the people from the community who c
|
||||
- theBigOne
|
||||
- ulmerspatz
|
||||
|
||||
#### Companies
|
||||
### Companies
|
||||
- Hardis
|
||||
- ITOMIG
|
||||
- Pimkie
|
||||
|
||||
|
||||
|
||||
[0]: https://www.combodo.com
|
||||
|
||||
[1]: https://sourceforge.net/p/itop/discussion/
|
||||
[2]: https://sourceforge.net/p/itop/tickets/
|
||||
[3]: https://sourceforge.net/projects/itop/files/itop/
|
||||
[4]: https://www.itophub.io/wiki
|
||||
[5]: https://store.itophub.io/en_US/
|
||||
|
||||
|
||||
|
||||
[10]: https://www.itophub.io/wiki/page?id=2_5_0%3Adatamodel%3Astart#configuration_management_cmdb
|
||||
[11]: https://www.itophub.io/wiki/page?id=2_5_0%3Adatamodel%3Astart#ticketing
|
||||
[12]: https://www.itophub.io/wiki/page?id=2_5_0%3Adatamodel%3Astart#service_management
|
||||
[13]: https://www.itophub.io/wiki/page?id=2_5_0%3Adatamodel%3Astart#change_management
|
||||
[14]: https://www.itophub.io/wiki/page?id=2_5_0%3Aimplementation%3Astart#service_level_agreements_and_targets
|
||||
[15]: https://www.itophub.io/wiki/page?id=2_5_0%3Auser%3Aactions#relations
|
||||
[16]: https://www.itophub.io/wiki/page?id=2_5_0%3Auser%3Abulk_modify#uploading_data
|
||||
[17]: https://www.itophub.io/wiki/page?id=2_5_0%3Aadmin%3Aaudit
|
||||
[18]: https://www.itophub.io/wiki/page?id=2_5_0%3Aadvancedtopics%3Adata_synchro_overview
|
||||
|
||||
|
||||
|
||||
[50]: https://www.itophub.io/wiki/page?id=2_4_0:release:change_log
|
||||
[51]: https://www.itophub.io/wiki/page?id=2_4_0:release:2_4_whats_new
|
||||
[52]: https://www.itophub.io/wiki/page?id=2_4_0:install:230_to_240_migration_notes
|
||||
[53]: https://sourceforge.net/projects/itop/files/itop/2.4.1
|
||||
|
||||
[54]: https://www.itophub.io/wiki/page?id=2_5_0:release:change_log
|
||||
[55]: https://www.itophub.io/wiki/page?id=2_5_0:release:2_5_whats_new
|
||||
[56]: https://www.itophub.io/wiki/page?id=2_5_0:install:240_to_250_migration_notes
|
||||
[57]: https://sourceforge.net/projects/itop/files/itop/2.5.1
|
||||
|
||||
[58]: https://www.itophub.io/wiki/page?id=2_6_0:release:change_log
|
||||
[59]: https://www.itophub.io/wiki/page?id=2_6_0:release:2_6_whats_new
|
||||
[60]: https://www.itophub.io/wiki/page?id=2_6_0:install:250_to_260_migration_notes
|
||||
[61]: https://sourceforge.net/projects/itop/files/itop/2.6.3
|
||||
|
||||
36
SECURITY.md
Normal file
36
SECURITY.md
Normal file
@@ -0,0 +1,36 @@
|
||||
# 🔒 Reporting vulnerabilities
|
||||
|
||||
We take all security bugs seriously. Thank you for improving the security of iTop! We appreciate your efforts and
|
||||
responsible disclosure and will make every effort to acknowledge your contributions.
|
||||
|
||||
|
||||
## ✉️ How to report
|
||||
|
||||
### iTop vulnerabilities
|
||||
Please send a procedure to reproduce iTop vulnerabilities to [itop-security@combodo.com](mailto:itop-security@combodo.com).
|
||||
|
||||
You can send us a standard "given / then / when" report, including iTop version, impacts, and maybe installed modules or data if they are
|
||||
needed to reproduce.
|
||||
|
||||
### Dependencies vulnerabilities
|
||||
Report security bugs in third-party modules to the person or team maintaining the module, and notify us of this report by sending an email
|
||||
to [itop-security@combodo.com](mailto:itop-security@combodo.com).
|
||||
|
||||
|
||||
|
||||
## 📆 Disclosure Policy
|
||||
|
||||
Report sent to us will be acknowledged within the week.
|
||||
|
||||
Then, a Combodo developer will be assigned to the reported issue and will:
|
||||
|
||||
* confirm the problem and determine the affected iTop versions
|
||||
* audit the code to search any potential similar problems
|
||||
* try to find a workaround if any
|
||||
* create fixes for all releases still under maintenance
|
||||
* send you the commit(s) for review
|
||||
* send you the next version(s) that will contain the fix, and the estimated release dates
|
||||
|
||||
Security issues always take precedence over bug fixes and feature work.
|
||||
|
||||
The assignee will keep you informed of the resolution progress, and may ask you for additional information or guidance.
|
||||
@@ -121,20 +121,15 @@ class UserRightsMatrix extends UserRightsAddOnAPI
|
||||
public function CreateAdministrator($sAdminUser, $sAdminPwd, $sLanguage = 'EN US')
|
||||
{
|
||||
// Maybe we should check that no other user with userid == 0 exists
|
||||
CMDBObject::SetTrackInfo('Initialization');
|
||||
$oUser = new UserLocal();
|
||||
$oUser->Set('login', $sAdminUser);
|
||||
$oUser->Set('password', $sAdminPwd);
|
||||
$oUser->Set('contactid', 1); // one is for root !
|
||||
$oUser->Set('language', $sLanguage); // Language was chosen during the installation
|
||||
|
||||
// Create a change to record the history of the User object
|
||||
$oChange = MetaModel::NewObject("CMDBChange");
|
||||
$oChange->Set("date", time());
|
||||
$oChange->Set("userinfo", "Initialization");
|
||||
$iChangeId = $oChange->DBInsert();
|
||||
|
||||
// Now record the admin user object
|
||||
$iUserId = $oUser->DBInsertTrackedNoReload($oChange, true /* skip security */);
|
||||
$iUserId = $oUser->DBInsertNoReload();
|
||||
$this->SetupUser($iUserId, true);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -1,27 +1,20 @@
|
||||
<?php
|
||||
// Copyright (C) 2010-2013 Combodo SARL
|
||||
//
|
||||
// This file is part of iTop.
|
||||
//
|
||||
// iTop is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// iTop is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with iTop. If not, see <http://www.gnu.org/licenses/>
|
||||
|
||||
/**
|
||||
* UserRightsProfile
|
||||
* User management Module, basing the right on profiles and a matrix (similar to UserRightsMatrix, but profiles and other decorations have been added)
|
||||
* Copyright (C) 2013-2020 Combodo SARL
|
||||
*
|
||||
* @copyright Copyright (C) 2010-2012 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
* 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
|
||||
*/
|
||||
|
||||
define('ADMIN_PROFILE_NAME', 'Administrator');
|
||||
@@ -179,7 +172,7 @@ class URP_Profiles extends UserRightsBaseClassGUI
|
||||
parent::DisplayBareRelations($oPage, $bEditMode);
|
||||
if (!$bEditMode)
|
||||
{
|
||||
$oPage->SetCurrentTab(Dict::S('UI:UserManagement:GrantMatrix'));
|
||||
$oPage->SetCurrentTab('UI:UserManagement:GrantMatrix');
|
||||
$this->DoShowGrantSumary($oPage);
|
||||
}
|
||||
}
|
||||
@@ -437,33 +430,27 @@ class UserRightsProfile extends UserRightsAddOnAPI
|
||||
{
|
||||
CMDBObject::SetTrackInfo('Initialization');
|
||||
|
||||
$oChange = CMDBObject::GetCurrentChange();
|
||||
|
||||
$iContactId = 0;
|
||||
// Support drastic data model changes: no organization class (or not writable)!
|
||||
if (MetaModel::IsValidClass('Organization') && !MetaModel::IsAbstract('Organization'))
|
||||
{
|
||||
$oOrg = new Organization();
|
||||
$oOrg = MetaModel::NewObject('Organization');
|
||||
$oOrg->Set('name', 'My Company/Department');
|
||||
$oOrg->Set('code', 'SOMECODE');
|
||||
$iOrgId = $oOrg->DBInsertTrackedNoReload($oChange, true /* skip security */);
|
||||
$iOrgId = $oOrg->DBInsertNoReload();
|
||||
|
||||
// Support drastic data model changes: no Person class (or not writable)!
|
||||
if (MetaModel::IsValidClass('Person') && !MetaModel::IsAbstract('Person'))
|
||||
{
|
||||
$oContact = new Person();
|
||||
$oContact = MetaModel::NewObject('Person');
|
||||
$oContact->Set('name', 'My last name');
|
||||
$oContact->Set('first_name', 'My first name');
|
||||
if (MetaModel::IsValidAttCode('Person', 'org_id'))
|
||||
{
|
||||
$oContact->Set('org_id', $iOrgId);
|
||||
}
|
||||
if (MetaModel::IsValidAttCode('Person', 'phone'))
|
||||
{
|
||||
$oContact->Set('phone', '+00 000 000 000');
|
||||
}
|
||||
$oContact->Set('email', 'my.email@foo.org');
|
||||
$iContactId = $oContact->DBInsertTrackedNoReload($oChange, true /* skip security */);
|
||||
$iContactId = $oContact->DBInsertNoReload();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -482,14 +469,12 @@ class UserRightsProfile extends UserRightsAddOnAPI
|
||||
if (is_object($oAdminProfile))
|
||||
{
|
||||
$oUserProfile = new URP_UserProfile();
|
||||
//$oUserProfile->Set('userid', $iUserId);
|
||||
$oUserProfile->Set('profileid', $oAdminProfile->GetKey());
|
||||
$oUserProfile->Set('reason', 'By definition, the administrator must have the administrator profile');
|
||||
//$oUserProfile->DBInsertTrackedNoReload($oChange, true /* skip security */);
|
||||
$oSet = DBObjectSet::FromObject($oUserProfile);
|
||||
$oUser->Set('profile_list', $oSet);
|
||||
}
|
||||
$iUserId = $oUser->DBInsertTrackedNoReload($oChange, true /* skip security */);
|
||||
$iUserId = $oUser->DBInsertNoReload();
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -572,7 +557,7 @@ class UserRightsProfile extends UserRightsAddOnAPI
|
||||
|
||||
/**
|
||||
* @param $oUser User
|
||||
* @return array
|
||||
* @return bool
|
||||
*/
|
||||
public function IsAdministrator($oUser)
|
||||
{
|
||||
@@ -582,16 +567,22 @@ class UserRightsProfile extends UserRightsAddOnAPI
|
||||
|
||||
/**
|
||||
* @param $oUser User
|
||||
* @return array
|
||||
* @return bool
|
||||
*/
|
||||
public function IsPortalUser($oUser)
|
||||
{
|
||||
// UserRights caches the list for us
|
||||
return UserRights::HasProfile(PORTAL_PROFILE_NAME, $oUser);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $oUser User
|
||||
* @return bool
|
||||
*
|
||||
* @return array
|
||||
* @throws \ArchivedObjectException
|
||||
* @throws \CoreException
|
||||
* @throws \CoreUnexpectedValue
|
||||
* @throws \MySQLException
|
||||
*/
|
||||
public function ListProfiles($oUser)
|
||||
{
|
||||
|
||||
@@ -1,27 +1,20 @@
|
||||
<?php
|
||||
// Copyright (C) 2010-2013 Combodo SARL
|
||||
//
|
||||
// This file is part of iTop.
|
||||
//
|
||||
// iTop is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// iTop is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with iTop. If not, see <http://www.gnu.org/licenses/>
|
||||
|
||||
/**
|
||||
* UserRightsProfile
|
||||
* User management Module, basing the right on profiles and a matrix (similar to UserRightsMatrix, but profiles and other decorations have been added)
|
||||
* Copyright (C) 2013-2020 Combodo SARL
|
||||
*
|
||||
* @copyright Copyright (C) 2010-2012 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
* 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
|
||||
*/
|
||||
|
||||
define('ADMIN_PROFILE_NAME', 'Administrator');
|
||||
@@ -321,7 +314,7 @@ class URP_Profiles extends UserRightsBaseClassGUI
|
||||
parent::DisplayBareRelations($oPage, $bEditMode);
|
||||
if (!$bEditMode)
|
||||
{
|
||||
$oPage->SetCurrentTab(Dict::S('UI:UserManagement:GrantMatrix'));
|
||||
$oPage->SetCurrentTab('UI:UserManagement:GrantMatrix');
|
||||
$this->DoShowGrantSumary($oPage);
|
||||
}
|
||||
}
|
||||
@@ -533,36 +526,34 @@ class UserRightsProfile extends UserRightsAddOnAPI
|
||||
public function CreateAdministrator($sAdminUser, $sAdminPwd, $sLanguage = 'EN US')
|
||||
{
|
||||
// Create a change to record the history of the User object
|
||||
/** @var \CMDBChange $oChange */
|
||||
$oChange = MetaModel::NewObject("CMDBChange");
|
||||
$oChange->Set("date", time());
|
||||
$oChange->Set("userinfo", "Initialization");
|
||||
$iChangeId = $oChange->DBInsert();
|
||||
|
||||
$iContactId = 0;
|
||||
// Support drastic data model changes: no organization class (or not writable)!
|
||||
if (MetaModel::IsValidClass('Organization') && !MetaModel::IsAbstract('Organization'))
|
||||
{
|
||||
$oOrg = new Organization();
|
||||
$oOrg = MetaModel::NewObject('Organization');
|
||||
$oOrg->Set('name', 'My Company/Department');
|
||||
$oOrg->Set('code', 'SOMECODE');
|
||||
$iOrgId = $oOrg->DBInsertTrackedNoReload($oChange, true /* skip security */);
|
||||
$oOrg::SetCurrentChange($oChange);
|
||||
$iOrgId = $oOrg->DBInsertNoReload();
|
||||
|
||||
// Support drastic data model changes: no Person class (or not writable)!
|
||||
if (MetaModel::IsValidClass('Person') && !MetaModel::IsAbstract('Person'))
|
||||
{
|
||||
$oContact = new Person();
|
||||
$oContact = MetaModel::NewObject('Person');
|
||||
$oContact->Set('name', 'My last name');
|
||||
$oContact->Set('first_name', 'My first name');
|
||||
if (MetaModel::IsValidAttCode('Person', 'org_id'))
|
||||
{
|
||||
$oContact->Set('org_id', $iOrgId);
|
||||
}
|
||||
if (MetaModel::IsValidAttCode('Person', 'phone'))
|
||||
{
|
||||
$oContact->Set('phone', '+00 000 000 000');
|
||||
}
|
||||
$oContact->Set('email', 'my.email@foo.org');
|
||||
$iContactId = $oContact->DBInsertTrackedNoReload($oChange, true /* skip security */);
|
||||
$oContact::SetCurrentChange($oChange);
|
||||
$iContactId = $oContact->DBInsertNoReload();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -581,14 +572,13 @@ class UserRightsProfile extends UserRightsAddOnAPI
|
||||
if (is_object($oAdminProfile))
|
||||
{
|
||||
$oUserProfile = new URP_UserProfile();
|
||||
//$oUserProfile->Set('userid', $iUserId);
|
||||
$oUserProfile->Set('profileid', $oAdminProfile->GetKey());
|
||||
$oUserProfile->Set('reason', 'By definition, the administrator must have the administrator profile');
|
||||
//$oUserProfile->DBInsertTrackedNoReload($oChange, true /* skip security */);
|
||||
$oSet = DBObjectSet::FromObject($oUserProfile);
|
||||
$oUser->Set('profile_list', $oSet);
|
||||
}
|
||||
$iUserId = $oUser->DBInsertTrackedNoReload($oChange, true /* skip security */);
|
||||
$oUser::SetCurrentChange($oChange);
|
||||
$iUserId = $oUser->DBInsertNoReload();
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -717,7 +707,7 @@ class UserRightsProfile extends UserRightsAddOnAPI
|
||||
|
||||
public function LoadCache()
|
||||
{
|
||||
if (!is_null($this->m_aProfiles)) return;
|
||||
if (!is_null($this->m_aProfiles)) return false;
|
||||
// Could be loaded in a shared memory (?)
|
||||
|
||||
$oKPI = new ExecutionKPI();
|
||||
|
||||
@@ -1,27 +1,20 @@
|
||||
<?php
|
||||
// Copyright (C) 2010-2012 Combodo SARL
|
||||
//
|
||||
// This file is part of iTop.
|
||||
//
|
||||
// iTop is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// iTop is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with iTop. If not, see <http://www.gnu.org/licenses/>
|
||||
|
||||
/**
|
||||
* UserRightsProjection
|
||||
* User management Module, basing the right on profiles and a matrix (similar to UserRightsProfile, but enhanced with dimensions and projection of classes and profile over the dimensions)
|
||||
* Copyright (C) 2013-2020 Combodo SARL
|
||||
*
|
||||
* @copyright Copyright (C) 2010-2012 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
* 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
|
||||
*/
|
||||
|
||||
define('ADMIN_PROFILE_ID', 1);
|
||||
@@ -153,7 +146,7 @@ class URP_Profiles extends UserRightsBaseClass
|
||||
parent::DisplayBareRelations($oPage, $bEditMode);
|
||||
if (!$bEditMode)
|
||||
{
|
||||
$oPage->SetCurrentTab(Dict::S('UI:UserManagement:GrantMatrix'));
|
||||
$oPage->SetCurrentTab('UI:UserManagement:GrantMatrix');
|
||||
$this->DoShowGrantSumary($oPage);
|
||||
}
|
||||
}
|
||||
@@ -593,25 +586,12 @@ class UserRightsProjection extends UserRightsAddOnAPI
|
||||
$oChange = MetaModel::NewObject("CMDBChange");
|
||||
$oChange->Set("date", time());
|
||||
$oChange->Set("userinfo", "Initialization");
|
||||
$iChangeId = $oChange->DBInsert();
|
||||
|
||||
$oOrg = new Organization();
|
||||
$oOrg->Set('name', 'My Company/Department');
|
||||
$oOrg->Set('code', 'SOMECODE');
|
||||
// $oOrg->Set('status', 'implementation');
|
||||
//$oOrg->Set('parent_id', xxx);
|
||||
$iOrgId = $oOrg->DBInsertTrackedNoReload($oChange, true /* skip strong security */);
|
||||
|
||||
// Location : optional
|
||||
//$oLocation = new bizLocation();
|
||||
//$oLocation->Set('name', 'MyOffice');
|
||||
//$oLocation->Set('status', 'implementation');
|
||||
//$oLocation->Set('org_id', $iOrgId);
|
||||
//$oLocation->Set('severity', 'high');
|
||||
//$oLocation->Set('address', 'my building in my city');
|
||||
//$oLocation->Set('country', 'my country');
|
||||
//$oLocation->Set('parent_location_id', xxx);
|
||||
//$iLocationId = $oLocation->DBInsertNoReload();
|
||||
$oOrg::SetCurrentChange($oChange);
|
||||
$iOrgId = $oOrg->DBInsertNoReload();
|
||||
|
||||
$oContact = new Person();
|
||||
$oContact->Set('name', 'My last name');
|
||||
@@ -619,24 +599,24 @@ class UserRightsProjection extends UserRightsAddOnAPI
|
||||
//$oContact->Set('status', 'available');
|
||||
$oContact->Set('org_id', $iOrgId);
|
||||
$oContact->Set('email', 'my.email@foo.org');
|
||||
//$oContact->Set('phone', '');
|
||||
//$oContact->Set('location_id', $iLocationId);
|
||||
//$oContact->Set('employee_number', '');
|
||||
$iContactId = $oContact->DBInsertTrackedNoReload($oChange, true /* skip security */);
|
||||
$oContact::SetCurrentChange($oChange);
|
||||
$iContactId = $oContact->DBInsertNoReload();
|
||||
|
||||
$oUser = new UserLocal();
|
||||
$oUser->Set('login', $sAdminUser);
|
||||
$oUser->Set('password', $sAdminPwd);
|
||||
$oUser->Set('contactid', $iContactId);
|
||||
$oUser->Set('language', $sLanguage); // Language was chosen during the installation
|
||||
$iUserId = $oUser->DBInsertTrackedNoReload($oChange, true /* skip security */);
|
||||
$oUser::SetCurrentChange($oChange);
|
||||
$iUserId = $oUser->DBInsertNoReload();
|
||||
|
||||
// Add this user to the very specific 'admin' profile
|
||||
$oUserProfile = new URP_UserProfile();
|
||||
$oUserProfile->Set('userid', $iUserId);
|
||||
$oUserProfile->Set('profileid', ADMIN_PROFILE_ID);
|
||||
$oUserProfile->Set('reason', 'By definition, the administrator must have the administrator profile');
|
||||
$oUserProfile->DBInsertTrackedNoReload($oChange, true /* skip security */);
|
||||
$oUserProfile::SetCurrentChange($oChange);
|
||||
$oUserProfile->DBInsertNoReload();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,27 +1,20 @@
|
||||
<?php
|
||||
// Copyright (C) 2010-2018 Combodo SARL
|
||||
//
|
||||
// This file is part of iTop.
|
||||
//
|
||||
// iTop is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// iTop is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with iTop. If not, see <http://www.gnu.org/licenses/>
|
||||
|
||||
/**
|
||||
* Simple web page with no includes, header or fancy formatting, useful to
|
||||
* generate HTML fragments when called by an AJAX method
|
||||
* Copyright (C) 2013-2020 Combodo SARL
|
||||
*
|
||||
* @copyright Copyright (C) 2010-2017 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
* 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
|
||||
*/
|
||||
|
||||
require_once(APPROOT."/application/webpage.class.inc.php");
|
||||
@@ -30,7 +23,7 @@ class ajax_page extends WebPage implements iTabbedPage
|
||||
{
|
||||
/**
|
||||
* Jquery style ready script
|
||||
* @var Hash
|
||||
* @var array
|
||||
*/
|
||||
protected $m_sReadyScript;
|
||||
protected $m_oTabs;
|
||||
@@ -60,56 +53,67 @@ class ajax_page extends WebPage implements iTabbedPage
|
||||
utils::InitArchiveMode();
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function AddTabContainer($sTabContainer, $sPrefix = '')
|
||||
{
|
||||
$this->add($this->m_oTabs->AddTabContainer($sTabContainer, $sPrefix));
|
||||
}
|
||||
|
||||
public function AddToTab($sTabContainer, $sTabLabel, $sHtml)
|
||||
/**
|
||||
* @inheritDoc
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function AddToTab($sTabContainer, $sTabCode, $sHtml)
|
||||
{
|
||||
$this->add($this->m_oTabs->AddToTab($sTabContainer, $sTabLabel, $sHtml));
|
||||
$this->add($this->m_oTabs->AddToTab($sTabContainer, $sTabCode, $sHtml));
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function SetCurrentTabContainer($sTabContainer = '')
|
||||
{
|
||||
return $this->m_oTabs->SetCurrentTabContainer($sTabContainer);
|
||||
}
|
||||
|
||||
public function SetCurrentTab($sTabLabel = '')
|
||||
{
|
||||
return $this->m_oTabs->SetCurrentTab($sTabLabel);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a tab which content will be loaded asynchronously via the supplied URL
|
||||
*
|
||||
* Limitations:
|
||||
* Cross site scripting is not not allowed for security reasons. Use a normal tab with an IFRAME if you want to pull content from another server.
|
||||
* Static content cannot be added inside such tabs.
|
||||
*
|
||||
* @param string $sTabLabel The (localised) label of the tab
|
||||
* @param string $sUrl The URL to load (on the same server)
|
||||
* @param boolean $bCache Whether or not to cache the content of the tab once it has been loaded. flase will cause the tab to be reloaded upon each activation.
|
||||
* @since 2.0.3
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function AddAjaxTab($sTabLabel, $sUrl, $bCache = true)
|
||||
public function SetCurrentTab($sTabCode = '', $sTabTitle = null)
|
||||
{
|
||||
$this->add($this->m_oTabs->AddAjaxTab($sTabLabel, $sUrl, $bCache));
|
||||
return $this->m_oTabs->SetCurrentTab($sTabCode, $sTabTitle);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function AddAjaxTab($sTabCode, $sUrl, $bCache = true, $sTabTitle = null)
|
||||
{
|
||||
$this->add($this->m_oTabs->AddAjaxTab($sTabCode, $sUrl, $bCache, $sTabTitle));
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function GetCurrentTab()
|
||||
{
|
||||
return $this->m_oTabs->GetCurrentTab();
|
||||
}
|
||||
|
||||
public function RemoveTab($sTabLabel, $sTabContainer = null)
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function RemoveTab($sTabCode, $sTabContainer = null)
|
||||
{
|
||||
$this->m_oTabs->RemoveTab($sTabLabel, $sTabContainer);
|
||||
$this->m_oTabs->RemoveTab($sTabCode, $sTabContainer);
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds the tab whose title matches a given pattern
|
||||
* @return mixed The name of the tab as a string or false if not found
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function FindTab($sPattern, $sTabContainer = null)
|
||||
{
|
||||
@@ -122,21 +126,23 @@ class ajax_page extends WebPage implements iTabbedPage
|
||||
* that we are using this is not supported... TO DO upgrade
|
||||
* the whole jquery bundle...
|
||||
*/
|
||||
public function SelectTab($sTabContainer, $sTabLabel)
|
||||
public function SelectTab($sTabContainer, $sTabCode)
|
||||
{
|
||||
$this->add_ready_script($this->m_oTabs->SelectTab($sTabContainer, $sTabLabel));
|
||||
$this->add_ready_script($this->m_oTabs->SelectTab($sTabContainer, $sTabCode));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param string $sHtml
|
||||
*/
|
||||
public function AddToMenu($sHtml)
|
||||
{
|
||||
$this->m_sMenu .= $sHtml;
|
||||
}
|
||||
|
||||
/**
|
||||
* Echoes the content of the whole page
|
||||
* @return void
|
||||
*/
|
||||
public function output()
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function output()
|
||||
{
|
||||
if (!empty($this->sContentType))
|
||||
{
|
||||
@@ -217,8 +223,11 @@ PrepareWidgets();
|
||||
EOF
|
||||
);
|
||||
}
|
||||
$s_captured_output = $this->ob_get_clean_safe();
|
||||
if (($this->sContentType == 'text/html') && ($this->sContentDisposition == 'inline'))
|
||||
$this->outputCollapsibleSectionInit();
|
||||
|
||||
$oKPI = new ExecutionKPI();
|
||||
$s_captured_output = $this->ob_get_clean_safe();
|
||||
if (($this->sContentType == 'text/html') && ($this->sContentDisposition == 'inline'))
|
||||
{
|
||||
// inline content != attachment && html => filter all scripts for malicious XSS scripts
|
||||
echo self::FilterXSS($this->s_content);
|
||||
@@ -288,10 +297,16 @@ EOF
|
||||
echo self::FilterXSS($s_captured_output);
|
||||
}
|
||||
|
||||
$oKPI->ComputeAndReport('Echoing');
|
||||
|
||||
if (class_exists('DBSearch'))
|
||||
{
|
||||
DBSearch::RecordQueryTrace();
|
||||
}
|
||||
if (class_exists('ExecutionKPI'))
|
||||
{
|
||||
ExecutionKPI::ReportStats();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -304,7 +319,11 @@ EOF
|
||||
{
|
||||
}
|
||||
|
||||
public function add($sHtml)
|
||||
/**
|
||||
* @inheritDoc
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function add($sHtml)
|
||||
{
|
||||
if (($this->m_oTabs->GetCurrentTabContainer() != '') && ($this->m_oTabs->GetCurrentTab() != ''))
|
||||
{
|
||||
@@ -317,10 +336,9 @@ EOF
|
||||
}
|
||||
|
||||
/**
|
||||
* Records the current state of the 'html' part of the page output
|
||||
* @return mixed The current state of the 'html' output
|
||||
*/
|
||||
public function start_capture()
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function start_capture()
|
||||
{
|
||||
$sCurrentTabContainer = $this->m_oTabs->GetCurrentTabContainer();
|
||||
$sCurrentTab = $this->m_oTabs->GetCurrentTab();
|
||||
@@ -336,13 +354,10 @@ EOF
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the part of the html output that occurred since the call to start_capture
|
||||
* and removes this part from the current html output
|
||||
* @param $offset mixed The value returned by start_capture
|
||||
* @return string The part of the html output that was added since the call to start_capture
|
||||
*/
|
||||
public function end_capture($offset)
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function end_capture($offset)
|
||||
{
|
||||
if (is_array($offset))
|
||||
{
|
||||
@@ -363,11 +378,9 @@ EOF
|
||||
}
|
||||
|
||||
/**
|
||||
* Add any text or HTML fragment (identified by an ID) at the end of the body of the page
|
||||
* This is useful to add hidden content, DIVs or FORMs that should not
|
||||
* be embedded into each other.
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function add_at_the_end($s_html, $sId = '')
|
||||
public function add_at_the_end($s_html, $sId = '')
|
||||
{
|
||||
if ($sId != '')
|
||||
{
|
||||
@@ -375,27 +388,27 @@ EOF
|
||||
}
|
||||
$this->s_deferred_content .= $s_html;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Adds a script to be executed when the DOM is ready (typical JQuery use)
|
||||
* NOT implemented in this version of the class.
|
||||
* @return void
|
||||
*/
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function add_ready_script($sScript)
|
||||
{
|
||||
$this->m_sReadyScript .= $sScript."\n";
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Cannot be called in this context, since Ajax pages do not share
|
||||
* any context with the calling page !!
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function GetUniqueId()
|
||||
{
|
||||
assert(false);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public static function FilterXSS($sHTML)
|
||||
{
|
||||
return str_ireplace(array('<script', '</script>'), array('<!-- <removed-script', '</removed-script> -->'), $sHTML);
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -31,7 +31,7 @@ class CSVPage extends WebPage
|
||||
{
|
||||
function __construct($s_title) {
|
||||
parent::__construct($s_title);
|
||||
$this->add_header("Content-type: text/plain; charset=utf-8");
|
||||
$this->add_header("Content-type: text/plain; charset=".self::PAGES_CHARSET);
|
||||
$this->add_header('Cache-control: no-cache, no-store, must-revalidate');
|
||||
$this->add_header('Pragma: no-cache');
|
||||
$this->add_header('Expires: 0');
|
||||
|
||||
@@ -1,20 +1,21 @@
|
||||
<?php
|
||||
// Copyright (C) 2010-2017 Combodo SARL
|
||||
//
|
||||
// This file is part of iTop.
|
||||
//
|
||||
// iTop is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// iTop is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with iTop. If not, see <http://www.gnu.org/licenses/>
|
||||
/**
|
||||
* Copyright (C) 2013-2019 Combodo SARL
|
||||
*
|
||||
* This file is part of iTop.
|
||||
*
|
||||
* iTop is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* iTop is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
*/
|
||||
|
||||
require_once(APPROOT.'application/dashboardlayout.class.inc.php');
|
||||
require_once(APPROOT.'application/dashlet.class.inc.php');
|
||||
@@ -24,21 +25,33 @@ require_once(APPROOT.'core/modelreflection.class.inc.php');
|
||||
*
|
||||
* A user editable dashboard page
|
||||
*
|
||||
* @copyright Copyright (C) 2010-2017 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
abstract class Dashboard
|
||||
{
|
||||
/** @var string $sTitle*/
|
||||
protected $sTitle;
|
||||
/** @var bool $bAutoReload */
|
||||
protected $bAutoReload;
|
||||
/** @var float|int $iAutoReloadSec */
|
||||
protected $iAutoReloadSec;
|
||||
/** @var string $sLayoutClass */
|
||||
protected $sLayoutClass;
|
||||
/** @var array $aWidgetsData */
|
||||
protected $aWidgetsData;
|
||||
/** @var \DOMNode|null $oDOMNode */
|
||||
protected $oDOMNode;
|
||||
/** @var string $sId */
|
||||
protected $sId;
|
||||
/** @var array $aCells */
|
||||
protected $aCells;
|
||||
/** @var \ModelReflection $oMetaModel */
|
||||
protected $oMetaModel;
|
||||
|
||||
|
||||
/**
|
||||
* Dashboard constructor.
|
||||
*
|
||||
* @param string $sId
|
||||
*/
|
||||
public function __construct($sId)
|
||||
{
|
||||
$this->sTitle = '';
|
||||
@@ -51,7 +64,7 @@ abstract class Dashboard
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $sXml
|
||||
* @param string $sXml
|
||||
*
|
||||
* @throws \Exception
|
||||
*/
|
||||
@@ -64,7 +77,10 @@ abstract class Dashboard
|
||||
restore_error_handler();
|
||||
$this->FromDOMDocument($oDoc);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param \DOMDocument $oDoc
|
||||
*/
|
||||
public function FromDOMDocument(DOMDocument $oDoc)
|
||||
{
|
||||
$this->oDOMNode = $oDoc->getElementsByTagName('dashboard')->item(0);
|
||||
@@ -160,9 +176,10 @@ abstract class Dashboard
|
||||
protected function InitDashletFromDOMNode($oDomNode)
|
||||
{
|
||||
$sId = $oDomNode->getAttribute('id');
|
||||
|
||||
$sDashletType = $oDomNode->getAttribute('xsi:type');
|
||||
|
||||
// Test if dashlet can be instanciated, otherwise (uninstalled, broken, ...) we display a placeholder
|
||||
// Test if dashlet can be instantiated, otherwise (uninstalled, broken, ...) we display a placeholder
|
||||
$sClass = static::GetDashletClassFromType($sDashletType);
|
||||
/** @var \Dashlet $oNewDashlet */
|
||||
$oNewDashlet = new $sClass($this->oMetaModel, $sId);
|
||||
@@ -172,7 +189,13 @@ abstract class Dashboard
|
||||
return $oNewDashlet;
|
||||
}
|
||||
|
||||
static function SortOnRank($aItem1, $aItem2)
|
||||
/**
|
||||
* @param array $aItem1
|
||||
* @param array $aItem2
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public static function SortOnRank($aItem1, $aItem2)
|
||||
{
|
||||
return ($aItem1['rank'] > $aItem2['rank']) ? +1 : -1;
|
||||
}
|
||||
@@ -200,6 +223,10 @@ abstract class Dashboard
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function ToXml()
|
||||
{
|
||||
$oDoc = new DOMDocument();
|
||||
@@ -268,7 +295,9 @@ abstract class Dashboard
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param array $aParams
|
||||
*/
|
||||
public function FromParams($aParams)
|
||||
{
|
||||
$this->sLayoutClass = $aParams['layout_class'];
|
||||
@@ -305,42 +334,85 @@ abstract class Dashboard
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function GetId()
|
||||
{
|
||||
return $this->sId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a sanitize ID for usages in XML/HTML attributes
|
||||
*
|
||||
* @return string
|
||||
* @since 2.7.0
|
||||
*/
|
||||
public function GetSanitizedId()
|
||||
{
|
||||
return utils::Sanitize($this->GetId(), '', 'element_identifier');
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function GetLayout()
|
||||
{
|
||||
return $this->sLayoutClass;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param string $sLayoutClass
|
||||
*/
|
||||
public function SetLayout($sLayoutClass)
|
||||
{
|
||||
$this->sLayoutClass = $sLayoutClass;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function GetTitle()
|
||||
{
|
||||
return $this->sTitle;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $sTitle
|
||||
*/
|
||||
public function SetTitle($sTitle)
|
||||
{
|
||||
$this->sTitle = $sTitle;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function GetAutoReload()
|
||||
{
|
||||
return $this->bAutoReload;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bool $bAutoReload
|
||||
*/
|
||||
public function SetAutoReload($bAutoReload)
|
||||
{
|
||||
$this->bAutoReload = $bAutoReload;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return float|int
|
||||
*/
|
||||
public function GetAutoReloadInterval()
|
||||
{
|
||||
return $this->iAutoReloadSec;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bool $iAutoReloadSec
|
||||
*/
|
||||
public function SetAutoReloadInterval($iAutoReloadSec)
|
||||
{
|
||||
$this->iAutoReloadSec = max(MetaModel::GetConfig()->Get('min_reload_interval'), (int)$iAutoReloadSec);
|
||||
@@ -356,12 +428,13 @@ abstract class Dashboard
|
||||
$this->aCells[] = array($oDashlet);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \WebPage $oPage *
|
||||
* @param array $aExtraParams
|
||||
*
|
||||
* @throws \ReflectionException
|
||||
*/
|
||||
/**
|
||||
* @param \WebPage $oPage *
|
||||
* @param array $aExtraParams
|
||||
*
|
||||
* @throws \ReflectionException
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function RenderProperties($oPage, $aExtraParams = array())
|
||||
{
|
||||
// menu to pick a layout and edit other properties of the dashboard
|
||||
@@ -449,17 +522,32 @@ EOF
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \iTopWebPage $oPage
|
||||
* @param \WebPage $oPage
|
||||
* @param bool $bEditMode
|
||||
* @param array $aExtraParams
|
||||
* @param bool $bCanEdit
|
||||
*/
|
||||
public function Render($oPage, $bEditMode = false, $aExtraParams = array(), $bCanEdit = true)
|
||||
{
|
||||
if (!array_key_exists('dashboard_div_id', $aExtraParams))
|
||||
{
|
||||
$aExtraParams['dashboard_div_id'] = utils::Sanitize($this->GetId(), '', 'element_identifier');
|
||||
}
|
||||
|
||||
$oPage->add('<div class="dashboard-title-line"><div class="dashboard-title">'.htmlentities(Dict::S($this->sTitle), ENT_QUOTES, 'UTF-8', false).'</div></div>');
|
||||
|
||||
$oLayout = new $this->sLayoutClass;
|
||||
/** @var \DashboardLayoutMultiCol $oLayout */
|
||||
$oLayout = new $this->sLayoutClass();
|
||||
|
||||
foreach($this->aCells as $iCellIdx => $aDashlets)
|
||||
{
|
||||
foreach($aDashlets as $oDashlet)
|
||||
{
|
||||
$aDashletCoordinates = $oLayout->GetDashletCoordinates($iCellIdx);
|
||||
$this->PrepareDashletForRendering($oDashlet, $aDashletCoordinates, $aExtraParams);
|
||||
}
|
||||
}
|
||||
|
||||
$oLayout->Render($oPage, $this->aCells, $bEditMode, $aExtraParams);
|
||||
if (!$bEditMode)
|
||||
{
|
||||
@@ -468,6 +556,12 @@ EOF
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \WebPage $oPage
|
||||
*
|
||||
* @throws \ReflectionException
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function RenderDashletsSelection(WebPage $oPage)
|
||||
{
|
||||
// Toolbox/palette to drag and drop dashlets
|
||||
@@ -485,25 +579,31 @@ EOF
|
||||
$oPage->add('</div>');
|
||||
$oPage->add_ready_script("$('.dashlet_icon').draggable({helper: 'clone', appendTo: 'body', zIndex: 10000, revert:'invalid'});");
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param \WebPage $oPage
|
||||
* @param array $aExtraParams
|
||||
*/
|
||||
public function RenderDashletsProperties(WebPage $oPage, $aExtraParams = array())
|
||||
{
|
||||
// Toolbox/palette to edit the properties of each dashlet
|
||||
$oPage->add('<div class="ui-widget-content ui-corner-all"><div class="ui-widget-header ui-corner-all" style="text-align:center; padding: 2px;">'.Dict::S('UI:DashboardEdit:DashletProperties').'</div>');
|
||||
|
||||
/** @var \DashboardLayoutMultiCol $oLayout */
|
||||
$oLayout = new $this->sLayoutClass();
|
||||
|
||||
$oPage->add('<div id="dashlet_properties" style="text-align:center">');
|
||||
foreach($this->aCells as $aCell)
|
||||
foreach($this->aCells as $iCellIdx => $aCell)
|
||||
{
|
||||
/** @var \Dashlet $oDashlet */
|
||||
foreach($aCell as $oDashlet)
|
||||
{
|
||||
$sId = $oDashlet->GetID();
|
||||
if ($oDashlet->IsVisible())
|
||||
{
|
||||
$oPage->add('<div class="dashlet_properties" id="dashlet_properties_'.$sId.'" style="display:none">');
|
||||
$oPage->add('<div class="dashlet_properties" id="dashlet_properties_'.$oDashlet->GetID().'" style="display:none">');
|
||||
$oForm = $oDashlet->GetForm();
|
||||
$this->SetFormParams($oForm, $aExtraParams);
|
||||
$oForm->RenderAsPropertySheet($oPage, false, '.itop-dashboard');
|
||||
$oForm->RenderAsPropertySheet($oPage, false, '.itop-dashboard');
|
||||
$oPage->add('</div>');
|
||||
}
|
||||
}
|
||||
@@ -545,7 +645,10 @@ EOF
|
||||
|
||||
return $aDashlets;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return int|mixed
|
||||
*/
|
||||
protected function GetNewDashletId()
|
||||
{
|
||||
$iNewId = 0;
|
||||
@@ -560,14 +663,32 @@ EOF
|
||||
return $iNewId + 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare dashlet for rendering (eg. change its ID or another processing).
|
||||
* Meant to be overloaded.
|
||||
*
|
||||
* @param \Dashlet $oDashlet
|
||||
* @param array $aCoordinates
|
||||
* @param array $aExtraParams
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
abstract protected function PrepareDashletForRendering(Dashlet $oDashlet, $aCoordinates, $aExtraParams = array());
|
||||
|
||||
/**
|
||||
* @param $oForm
|
||||
* @param \DesignerForm $oForm
|
||||
* @param array $aExtraParams
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
abstract protected function SetFormParams($oForm, $aExtraParams = array());
|
||||
|
||||
/**
|
||||
* @param string $sType
|
||||
* @param \ModelFactory|null $oFactory
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function GetDashletClassFromType($sType, $oFactory = null)
|
||||
{
|
||||
if (is_subclass_of($sType, 'Dashlet'))
|
||||
@@ -578,45 +699,90 @@ EOF
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
* N°2634: we must have a unique id per dashlet!
|
||||
* To avoid collision with other dashlets with the same ID we prefix it with row/cell id
|
||||
* Collisions typically happen with extensions.
|
||||
*
|
||||
* @param boolean $bIsCustomized
|
||||
* @param string $sDashboardDivId
|
||||
* @param int $iRow
|
||||
* @param int $iCol
|
||||
* @param string $sDashletOrigId
|
||||
*
|
||||
* @return string
|
||||
*
|
||||
* @since 2.7.0 N°2735
|
||||
*/
|
||||
public function GetId()
|
||||
public static function GetDashletUniqueId($bIsCustomized, $sDashboardDivId, $iRow, $iCol, $sDashletOrigId)
|
||||
{
|
||||
return $this->sId;
|
||||
if(strpos($sDashletOrigId, '_ID_row') !== false)
|
||||
{
|
||||
return $sDashletOrigId;
|
||||
}
|
||||
|
||||
$sDashletId = $sDashboardDivId."_ID_row".$iRow."_col".$iCol."_".$sDashletOrigId;
|
||||
if ($bIsCustomized)
|
||||
{
|
||||
$sDashletId = 'CUSTOM_'.$sDashletId;
|
||||
}
|
||||
|
||||
return $sDashletId;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Class RuntimeDashboard
|
||||
*/
|
||||
class RuntimeDashboard extends Dashboard
|
||||
{
|
||||
protected $bCustomized;
|
||||
/** @var string $sDefinitionFile */
|
||||
private $sDefinitionFile = '';
|
||||
/** @var null $sReloadURL */
|
||||
private $sReloadURL = null;
|
||||
/** @var bool $bCustomized */
|
||||
protected $bCustomized;
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function __construct($sId)
|
||||
{
|
||||
parent::__construct($sId);
|
||||
$this->bCustomized = false;
|
||||
$this->oMetaModel = new ModelReflectionRuntime();
|
||||
$this->bCustomized = false;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
* @since 2.7.0
|
||||
*/
|
||||
public function GetCustomFlag()
|
||||
{
|
||||
return $this->bCustomized;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bool $bCustomized
|
||||
* @since 2.7.0
|
||||
*/
|
||||
public function SetCustomFlag($bCustomized)
|
||||
{
|
||||
$this->bCustomized = $bCustomized;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \DesignerForm $oForm
|
||||
*
|
||||
* @param array $aExtraParams
|
||||
*
|
||||
* @inheritDoc
|
||||
* @throws \Exception
|
||||
*/
|
||||
protected function SetFormParams($oForm, $aExtraParams = array())
|
||||
{
|
||||
$oForm->SetSubmitParams(utils::GetAbsoluteUrlAppRoot().'pages/ajax.render.php', array('operation' => 'update_dashlet_property', 'extra_params' => $aExtraParams));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function Save()
|
||||
{
|
||||
$sXml = $this->ToXml();
|
||||
@@ -632,7 +798,7 @@ class RuntimeDashboard extends Dashboard
|
||||
}
|
||||
else
|
||||
{
|
||||
// No such customized dasboard 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->Set('user_id', UserRights::GetUserId());
|
||||
$oUserDashboard->Set('menu_code', $this->sId);
|
||||
@@ -642,7 +808,18 @@ class RuntimeDashboard extends Dashboard
|
||||
$oUserDashboard->DBWrite();
|
||||
utils::PopArchiveMode();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @throws \ArchivedObjectException
|
||||
* @throws \CoreCannotSaveObjectException
|
||||
* @throws \CoreException
|
||||
* @throws \CoreUnexpectedValue
|
||||
* @throws \DeleteException
|
||||
* @throws \MissingQueryArgument
|
||||
* @throws \MySQLException
|
||||
* @throws \MySQLHasGoneAwayException
|
||||
* @throws \OQLException
|
||||
*/
|
||||
public function Revert()
|
||||
{
|
||||
$oUDSearch = new DBObjectSearch('UserDashboard');
|
||||
@@ -669,6 +846,7 @@ class RuntimeDashboard extends Dashboard
|
||||
* @throws \MissingQueryArgument
|
||||
* @throws \MySQLException
|
||||
* @throws \MySQLHasGoneAwayException
|
||||
* @throws \Exception
|
||||
*/
|
||||
public static function GetDashboard($sDashboardFile, $sDashBoardId)
|
||||
{
|
||||
@@ -713,10 +891,7 @@ class RuntimeDashboard extends Dashboard
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \iTopWebPage $oPage
|
||||
* @param bool $bEditMode
|
||||
* @param array $aExtraParams (class and id of the current object
|
||||
*
|
||||
* @inheritDoc
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function Render($oPage, $bEditMode = false, $aExtraParams = array(), $bCanEdit = true)
|
||||
@@ -746,7 +921,7 @@ class RuntimeDashboard extends Dashboard
|
||||
if (!$bEditMode && !$oPage->IsPrintableVersion())
|
||||
{
|
||||
$sId = $this->GetId();
|
||||
$sDivId = preg_replace('/[^a-zA-Z0-9_]/', '', $sId);
|
||||
$sDivId = utils::Sanitize($sId, '', 'element_identifier');
|
||||
if ($this->GetAutoReload())
|
||||
{
|
||||
$sFile = addslashes($this->GetDefinitionFile());
|
||||
@@ -809,7 +984,7 @@ EOF
|
||||
protected function RenderSelector($oPage, $aAjaxParams = array())
|
||||
{
|
||||
$sId = $this->GetId();
|
||||
$sDivId = preg_replace('/[^a-zA-Z0-9_]/', '', $sId);
|
||||
$sDivId = utils::Sanitize($sId, '', 'element_identifier');
|
||||
$sExtraParams = json_encode($aAjaxParams);
|
||||
|
||||
$sSelectorHtml = '<div class="dashboard-selector">';
|
||||
@@ -851,6 +1026,9 @@ EOF
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
protected function HasCustomDashboard()
|
||||
{
|
||||
try
|
||||
@@ -879,7 +1057,7 @@ EOF
|
||||
{
|
||||
$oPage->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/jquery.iframe-transport.js');
|
||||
$oPage->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/jquery.fileupload.js');
|
||||
$sEditMenu = "<div id=\"DashboardMenu\"><ul><li><img src=\"../images/pencil-menu.png\"><ul>";
|
||||
$sEditMenu = "<div id=\"DashboardMenu\"><ul><li><i class=\"top-right-icon icon-additional-arrow fas fa-pencil-alt\"></i><ul>";
|
||||
|
||||
$aActions = array();
|
||||
$sFile = addslashes($this->sDefinitionFile);
|
||||
@@ -939,9 +1117,7 @@ EOF
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \WebPage $oPage
|
||||
*
|
||||
* @throws \ReflectionException
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function RenderProperties($oPage, $aExtraParams = array())
|
||||
{
|
||||
@@ -977,7 +1153,7 @@ EOF
|
||||
|
||||
|
||||
/**
|
||||
* @param \iTopWebPage $oPage
|
||||
* @param \WebPage $oPage
|
||||
*
|
||||
* @param array $aExtraParams
|
||||
*
|
||||
@@ -997,9 +1173,11 @@ EOF
|
||||
{
|
||||
$aRenderParams = $aExtraParams;
|
||||
}
|
||||
$aRenderParams['dashboard_div_id'] = $aExtraParams['dashboard_div_id'];
|
||||
$sJSExtraParams = json_encode($aExtraParams);
|
||||
$oPage->add('<div id="dashboard_editor">');
|
||||
$oPage->add('<div class="ui-layout-center">');
|
||||
$this->SetCustomFlag(true);
|
||||
$this->Render($oPage, true, $aRenderParams);
|
||||
$oPage->add('</div>');
|
||||
$oPage->add('<div class="ui-layout-east">');
|
||||
@@ -1028,7 +1206,7 @@ EOF
|
||||
$sAutoApplyConfirmationMessage = addslashes(Dict::S('UI:AutoApplyConfirmationMessage'));
|
||||
|
||||
$oPage->add_ready_script(
|
||||
<<<EOF
|
||||
<<<JS
|
||||
window.bLeavingOnUserAction = false;
|
||||
|
||||
$('#dashboard_editor').dialog({
|
||||
@@ -1071,10 +1249,15 @@ $('#dashboard_editor').dialog({
|
||||
});
|
||||
|
||||
$('#dashboard_editor .ui-layout-center').runtimedashboard({
|
||||
dashboard_id: '$sId', layout_class: '$sLayoutClass', title: '$sTitle',
|
||||
auto_reload: $sAutoReload, auto_reload_sec: $sAutoReloadSec,
|
||||
submit_to: '$sUrl', submit_parameters: {operation: 'save_dashboard', file: '$sFile', extra_params: $sJSExtraParams, reload_url: '$sReloadURL'},
|
||||
render_to: '$sUrl', render_parameters: {operation: 'render_dashboard', file: '$sFile', extra_params: $sJSExtraParams, reload_url: '$sReloadURL'},
|
||||
dashboard_id: '$sId',
|
||||
layout_class: '$sLayoutClass',
|
||||
title: '$sTitle',
|
||||
auto_reload: $sAutoReload,
|
||||
auto_reload_sec: $sAutoReloadSec,
|
||||
submit_to: '$sUrl',
|
||||
submit_parameters: {operation: 'save_dashboard', file: '$sFile', extra_params: $sJSExtraParams, reload_url: '$sReloadURL'},
|
||||
render_to: '$sUrl',
|
||||
render_parameters: {operation: 'render_dashboard', file: '$sFile', extra_params: $sJSExtraParams, reload_url: '$sReloadURL'},
|
||||
new_dashlet_parameters: {operation: 'new_dashlet'}
|
||||
});
|
||||
|
||||
@@ -1113,11 +1296,18 @@ window.onbeforeunload = function() {
|
||||
}
|
||||
// return nothing ! safer for IE
|
||||
};
|
||||
EOF
|
||||
JS
|
||||
);
|
||||
$oPage->add_ready_script("");
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param string|null $sOQL
|
||||
*
|
||||
* @return \DesignerForm
|
||||
* @throws \DictExceptionMissingString
|
||||
* @throws \ReflectionException
|
||||
*/
|
||||
public static function GetDashletCreationForm($sOQL = null)
|
||||
{
|
||||
$oAppContext = new ApplicationContext();
|
||||
@@ -1228,6 +1418,9 @@ EOF
|
||||
/**
|
||||
* @param \WebPage $oPage
|
||||
* @param $sOQL
|
||||
*
|
||||
* @throws \DictExceptionMissingString
|
||||
* @throws \ReflectionException
|
||||
*/
|
||||
public static function GetDashletCreationDlgFromOQL($oPage, $sOQL)
|
||||
{
|
||||
@@ -1243,7 +1436,7 @@ EOF
|
||||
$sCancelButtonLabel = Dict::S('UI:Button:Cancel');
|
||||
|
||||
$oPage->add_ready_script(
|
||||
<<<EOF
|
||||
<<<JS
|
||||
$('#dashlet_creation_dlg').dialog({
|
||||
width: 600,
|
||||
modal: true,
|
||||
@@ -1272,7 +1465,7 @@ $('#dashlet_creation_dlg').dialog({
|
||||
],
|
||||
close: function() { $(this).remove(); }
|
||||
});
|
||||
EOF
|
||||
JS
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1292,13 +1485,105 @@ EOF
|
||||
$this->sDefinitionFile = $sDefinitionFile;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string|null
|
||||
*/
|
||||
public function GetReloadURL()
|
||||
{
|
||||
return $this->sReloadURL;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $sReloadURL
|
||||
*/
|
||||
public function SetReloadURL($sReloadURL)
|
||||
{
|
||||
$this->sReloadURL = $sReloadURL;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
protected function PrepareDashletForRendering(Dashlet $oDashlet, $aCoordinates, $aExtraParams = array())
|
||||
{
|
||||
$sDashletIdOrig = $oDashlet->GetID();
|
||||
$sDashboardSanitizedId = $this->GetSanitizedId();
|
||||
$sDashletIdNew = static::GetDashletUniqueId($this->GetCustomFlag(), $sDashboardSanitizedId, $aCoordinates[1], $aCoordinates[0], $sDashletIdOrig);
|
||||
$oDashlet->SetID($sDashletIdNew);
|
||||
$this->UpdateDashletUserPrefs($oDashlet, $sDashletIdOrig, $aExtraParams);
|
||||
}
|
||||
|
||||
/**
|
||||
* Migrate dashlet specific prefs to new format
|
||||
* Before 2.7.0 we were using the same for dashboard menu or dashboard attributes, standard or custom :
|
||||
* <alias>-<class>|Dashlet<idx_dashlet>
|
||||
* Since 2.7.0 it is the following, with a "CUSTOM_" prefix if necessary :
|
||||
* * dashboard menu : <dashboard_id>_IDrow<row_idx>-col<col_idx>-<dashlet_idx>
|
||||
* * dashboard attribute : <class>__<attcode>_IDrow<row_idx>-col<col_idx>-<dashlet_idx>
|
||||
*
|
||||
* @param \Dashlet $oDashlet
|
||||
* @param string $sDashletIdOrig
|
||||
*
|
||||
* @param array $aExtraParams
|
||||
*
|
||||
* @since 2.7.0 N°2735
|
||||
*/
|
||||
private function UpdateDashletUserPrefs(Dashlet $oDashlet, $sDashletIdOrig, array $aExtraParams)
|
||||
{
|
||||
$bIsDashletWithListPref = ($oDashlet instanceof DashletObjectList);
|
||||
if (!$bIsDashletWithListPref)
|
||||
{
|
||||
return;
|
||||
}
|
||||
/** @var \DashletObjectList $oDashlet */
|
||||
|
||||
$bDashletIdInNewFormat = ($sDashletIdOrig === $oDashlet->GetID());
|
||||
if ($bDashletIdInNewFormat)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
$sNewPrefKey = $this->GetDashletObjectListAppUserPreferencesPrefix($oDashlet, $aExtraParams, $oDashlet->GetID());
|
||||
$sPrefValueForNewKey = appUserPreferences::GetPref($sNewPrefKey, null);
|
||||
$bHasPrefInNewFormat = ($sPrefValueForNewKey !== null);
|
||||
if ($bHasPrefInNewFormat)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
$sOldPrefKey = $this->GetDashletObjectListAppUserPreferencesPrefix($oDashlet, $aExtraParams, $sDashletIdOrig);
|
||||
$sPrefValueForOldKey = appUserPreferences::GetPref($sOldPrefKey, null);
|
||||
$bHasPrefInOldFormat = ($sPrefValueForOldKey !== null);
|
||||
if (!$bHasPrefInOldFormat)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
appUserPreferences::SetPref($sNewPrefKey, $sPrefValueForOldKey);
|
||||
appUserPreferences::UnsetPref($sOldPrefKey);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \DashletObjectList $oDashlet
|
||||
* @param array $aExtraParams
|
||||
* @param string $sDashletId
|
||||
*
|
||||
* @return string
|
||||
* @since 2.7.0
|
||||
*/
|
||||
private function GetDashletObjectListAppUserPreferencesPrefix(DashletObjectList $oDashlet, $aExtraParams, $sDashletId)
|
||||
{
|
||||
$sDataTableId = Dashlet::APPUSERPREFERENCES_PREFIX.$sDashletId;
|
||||
$aClassAliases = array();
|
||||
try{
|
||||
$oFilter = $oDashlet->GetDBSearch($aExtraParams);
|
||||
$aClassAliases = $oFilter->GetSelectedClasses();
|
||||
}
|
||||
catch (Exception $e)
|
||||
{
|
||||
//on error, return default value
|
||||
return null;
|
||||
}
|
||||
return DataTableSettings::GetAppUserPreferenceKey($aClassAliases, $sDataTableId);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,14 +26,17 @@
|
||||
|
||||
abstract class DashboardLayout
|
||||
{
|
||||
public function __construct()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
abstract public function Render($oPage, $aDashlets, $bEditMode = false);
|
||||
|
||||
/**
|
||||
* @param int $iCellIdx
|
||||
*
|
||||
* @return array Containing 2 scalars: Col number and row number (starting from 0)
|
||||
* @since 2.7.0
|
||||
*/
|
||||
abstract public function GetDashletCoordinates($iCellIdx);
|
||||
|
||||
static public function GetInfo()
|
||||
public static function GetInfo()
|
||||
{
|
||||
return array(
|
||||
'label' => '',
|
||||
@@ -51,7 +54,7 @@ abstract class DashboardLayoutMultiCol extends DashboardLayout
|
||||
{
|
||||
$this->iNbCols = 1;
|
||||
}
|
||||
|
||||
|
||||
protected function TrimCell($aDashlets)
|
||||
{
|
||||
$aKeys = array_reverse(array_keys($aDashlets));
|
||||
@@ -61,7 +64,7 @@ abstract class DashboardLayoutMultiCol extends DashboardLayout
|
||||
{
|
||||
/** @var \Dashlet $oDashlet */
|
||||
$oDashlet = $aDashlets[$aKeys[$idx]];
|
||||
if ($oDashlet->IsVisible())
|
||||
if ($oDashlet::IsVisible())
|
||||
{
|
||||
$bNoVisibleFound = false;
|
||||
}
|
||||
@@ -110,20 +113,21 @@ abstract class DashboardLayoutMultiCol extends DashboardLayout
|
||||
{
|
||||
// Trim the list of cells to remove the invisible/empty ones at the end of the array
|
||||
$aCells = $this->TrimCellsArray($aCells);
|
||||
|
||||
|
||||
$oPage->add('<table style="width:100%;table-layout:fixed;"><tbody>');
|
||||
$iCellIdx = 0;
|
||||
$fColSize = 100 / $this->iNbCols;
|
||||
$sStyle = $bEditMode ? 'border: 1px #ccc dashed; width:'.$fColSize.'%;' : 'width: '.$fColSize.'%;';
|
||||
$sClass = $bEditMode ? 'layout_cell edit_mode' : 'dashboard';
|
||||
$iNbRows = ceil(count($aCells) / $this->iNbCols);
|
||||
|
||||
for($iRows = 0; $iRows < $iNbRows; $iRows++)
|
||||
{
|
||||
$oPage->add('<tr>');
|
||||
$oPage->add("<tr data-dashboard-row-index=\"$iRows\">");
|
||||
for($iCols = 0; $iCols < $this->iNbCols; $iCols++)
|
||||
{
|
||||
$sCellClass = ($iRows == $iNbRows-1) ? $sClass.' layout_last_used_rank' : $sClass;
|
||||
$oPage->add("<td style=\"$sStyle\" class=\"$sCellClass\" data-dashboard-cell-index=\"$iCellIdx\">");
|
||||
$oPage->add("<td style=\"$sStyle\" class=\"$sCellClass\" data-dashboard-column-index=\"$iCols\" data-dashboard-cell-index=\"$iCellIdx\">");
|
||||
if (array_key_exists($iCellIdx, $aCells))
|
||||
{
|
||||
$aDashlets = $aCells[$iCellIdx];
|
||||
@@ -132,7 +136,7 @@ abstract class DashboardLayoutMultiCol extends DashboardLayout
|
||||
/** @var \Dashlet $oDashlet */
|
||||
foreach($aDashlets as $oDashlet)
|
||||
{
|
||||
if ($oDashlet->IsVisible())
|
||||
if ($oDashlet::IsVisible())
|
||||
{
|
||||
$oDashlet->DoRender($oPage, $bEditMode, true /* bEnclosingDiv */, $aExtraParams);
|
||||
}
|
||||
@@ -155,10 +159,10 @@ abstract class DashboardLayoutMultiCol extends DashboardLayout
|
||||
if ($bEditMode) // Add one row for extensibility
|
||||
{
|
||||
$sStyle = 'style="border: 1px #ccc dashed; width:'.$fColSize.'%;" class="layout_cell edit_mode layout_extension" data-dashboard-cell-index="'.$iCellIdx.'"';
|
||||
$oPage->add('<tr>');
|
||||
$oPage->add("<tr data-dashboard-row-index=\"$iRows\">");
|
||||
for($iCols = 0; $iCols < $this->iNbCols; $iCols++)
|
||||
{
|
||||
$oPage->add("<td $sStyle>");
|
||||
$oPage->add("<td $sStyle data-dashboard-column-index=\"$iCols\">");
|
||||
$oPage->add(' ');
|
||||
$oPage->add('</td>');
|
||||
}
|
||||
@@ -166,6 +170,17 @@ abstract class DashboardLayoutMultiCol extends DashboardLayout
|
||||
}
|
||||
$oPage->add('</tbody></table>');
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function GetDashletCoordinates($iCellIdx)
|
||||
{
|
||||
$iColNumber = (int) $iCellIdx % $this->iNbCols;
|
||||
$iRowNumber = (int) floor($iCellIdx / $this->iNbCols);
|
||||
|
||||
return array($iColNumber, $iRowNumber);
|
||||
}
|
||||
}
|
||||
|
||||
class DashboardLayoutOneCol extends DashboardLayoutMultiCol
|
||||
|
||||
@@ -26,6 +26,9 @@ require_once(APPROOT.'application/forms.class.inc.php');
|
||||
*/
|
||||
abstract class Dashlet
|
||||
{
|
||||
/** @var string */
|
||||
const APPUSERPREFERENCES_PREFIX = 'Dashlet';
|
||||
|
||||
protected $oModelReflection;
|
||||
protected $sId;
|
||||
protected $bRedrawNeeded;
|
||||
@@ -514,7 +517,7 @@ EOF
|
||||
*
|
||||
* Used as a fallback in iTop for unknown dashlet classes.
|
||||
*
|
||||
* @since 2.5
|
||||
* @since 2.5.0
|
||||
*/
|
||||
class DashletUnknown extends Dashlet
|
||||
{
|
||||
@@ -913,15 +916,28 @@ class DashletObjectList extends Dashlet
|
||||
public function Render($oPage, $bEditMode = false, $aExtraParams = array())
|
||||
{
|
||||
$sTitle = $this->aProperties['title'];
|
||||
$sQuery = $this->aProperties['query'];
|
||||
$sShowMenu = $this->aProperties['menu'] ? '1' : '0';
|
||||
|
||||
$oPage->add('<div class="dashlet-content">');
|
||||
$sHtmlTitle = utils::HtmlEntities(Dict::S($sTitle)); // done in the itop block
|
||||
if ($sHtmlTitle != '')
|
||||
{
|
||||
$oPage->add('<h1>'.$sHtmlTitle.'</h1>');
|
||||
$oPage->add('<div class="main_header"><h1> '.$sHtmlTitle.'</h1></div>');
|
||||
}
|
||||
$oFilter = $this->GetDBSearch($aExtraParams);
|
||||
$oBlock = new DisplayBlock($oFilter, 'list');
|
||||
$aParams = array(
|
||||
'menu' => $sShowMenu,
|
||||
'table_id' => self::APPUSERPREFERENCES_PREFIX.$this->sId,
|
||||
);
|
||||
$sBlockId = 'block_'.$this->sId.($bEditMode ? '_edit' : ''); // make a unique id (edition occurring in the same DOM)
|
||||
$oBlock->Display($oPage, $sBlockId, array_merge($aExtraParams, $aParams));
|
||||
$oPage->add('</div>');
|
||||
}
|
||||
|
||||
public function GetDBSearch($aExtraParams = array())
|
||||
{
|
||||
$sQuery = $this->aProperties['query'];
|
||||
if (isset($aExtraParams['query_params']))
|
||||
{
|
||||
$aQueryParams = $aExtraParams['query_params'];
|
||||
@@ -935,15 +951,8 @@ class DashletObjectList extends Dashlet
|
||||
{
|
||||
$aQueryParams = array();
|
||||
}
|
||||
$oFilter = DBObjectSearch::FromOQL($sQuery, $aQueryParams);
|
||||
$oBlock = new DisplayBlock($oFilter, 'list');
|
||||
$aParams = array(
|
||||
'menu' => $sShowMenu,
|
||||
'table_id' => 'Dashlet'.$this->sId,
|
||||
);
|
||||
$sBlockId = 'block_'.$this->sId.($bEditMode ? '_edit' : ''); // make a unique id (edition occurring in the same DOM)
|
||||
$oBlock->Display($oPage, $sBlockId, array_merge($aExtraParams, $aParams));
|
||||
$oPage->add('</div>');
|
||||
|
||||
return DBObjectSearch::FromOQL($sQuery, $aQueryParams);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1112,7 +1121,7 @@ abstract class DashletGroupBy extends Dashlet
|
||||
$this->sFunction = null;
|
||||
}
|
||||
|
||||
if (empty($this->aProperties['order_direction']))
|
||||
if ((!is_null($this->sClass)) && empty($this->aProperties['order_direction']))
|
||||
{
|
||||
$aAttributeTypes = $this->oModelReflection->ListAttributes($this->sClass);
|
||||
if (isset($aAttributeTypes[$this->sGroupByAttCode]))
|
||||
@@ -1263,10 +1272,10 @@ abstract class DashletGroupBy extends Dashlet
|
||||
break;
|
||||
}
|
||||
|
||||
$oPage->add('<div style="text-align:center" class="dashlet-content">');
|
||||
$oPage->add('<div class="dashlet-content">');
|
||||
if ($sHtmlTitle != '')
|
||||
{
|
||||
$oPage->add('<h1>'.$sHtmlTitle.'</h1>');
|
||||
$oPage->add('<div class="main_header"><h1> '.$sHtmlTitle.'</h1></div>');
|
||||
}
|
||||
$sBlockId = 'block_'.$this->sId.($bEditMode ? '_edit' : ''); // make a unique id (edition occuring in the same DOM)
|
||||
$oBlock = new DisplayBlock($oFilter, $sType);
|
||||
@@ -1859,11 +1868,11 @@ class DashletGroupByTable extends DashletGroupBy
|
||||
$iTotal += $aDisplayData['value'];
|
||||
}
|
||||
|
||||
$oPage->add('<div class="dashlet-content">');
|
||||
|
||||
$sBlockId = 'block_fake_'.$this->sId.($bEditMode ? '_edit' : ''); // make a unique id (edition occuring in the same DOM)
|
||||
|
||||
$oPage->add('<div id="'.$sBlockId.'" class="display_block">');
|
||||
$oPage->add('<div class="dashlet-content">');
|
||||
$oPage->add('<p>'.Dict::Format('UI:Pagination:HeaderNoSelection', $iTotal).'</p>');
|
||||
$oPage->add('<table class="listResults">');
|
||||
$oPage->add('<thead>');
|
||||
@@ -1917,7 +1926,7 @@ class DashletHeaderStatic extends Dashlet
|
||||
$oPage->add('<div class="main_header">');
|
||||
|
||||
$oPage->add('<img src="'.$sIconPath.'">');
|
||||
$oPage->add('<h1>'.$this->oModelReflection->DictString($sTitle).'</h1>');
|
||||
$oPage->add('<div class="main_header"><h1> '.$this->oModelReflection->DictString($sTitle).'</h1></div>');
|
||||
|
||||
$oPage->add('</div>');
|
||||
$oPage->add('</div>');
|
||||
|
||||
@@ -1,14 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<itop_design xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="1.6">
|
||||
<itop_design xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="1.7">
|
||||
<portals>
|
||||
<portal id="legacy_portal" _delta="define">
|
||||
<url>portal/index.php</url>
|
||||
<rank>1.0</rank>
|
||||
<handler/>
|
||||
<allow>
|
||||
</allow>
|
||||
<deny/>
|
||||
</portal>
|
||||
<portal id="backoffice" _delta="define">
|
||||
<url>pages/UI.php</url>
|
||||
<rank>2.0</rank>
|
||||
@@ -23,5 +15,10 @@
|
||||
<menu id="AdminTools" xsi:type="MenuGroup" _delta="define">
|
||||
<rank>80</rank>
|
||||
</menu>
|
||||
<menu id="SystemTools" xsi:type="MenuGroup" _delta="define">
|
||||
<rank>100</rank>
|
||||
<enable_class>ResourceSystemMenu</enable_class>
|
||||
<enable_action>UR_ACTION_MODIFY</enable_action>
|
||||
</menu>
|
||||
</menus>
|
||||
</itop_design>
|
||||
|
||||
@@ -1,30 +1,27 @@
|
||||
<?php
|
||||
// Copyright (C) 2010-2017 Combodo SARL
|
||||
//
|
||||
// This file is part of iTop.
|
||||
//
|
||||
// iTop is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// iTop is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with iTop. If not, see <http://www.gnu.org/licenses/>
|
||||
/**
|
||||
* Data Table to display a set of objects in a tabular manner in HTML
|
||||
* Copyright (C) 2013-2020 Combodo SARL
|
||||
*
|
||||
* @copyright Copyright (C) 2010-2017 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
* 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
|
||||
*/
|
||||
|
||||
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
|
||||
@@ -34,14 +31,20 @@ class DataTable
|
||||
protected $bShowObsoleteData;
|
||||
|
||||
/**
|
||||
* @param $iListId mixed Unique ID for this div/table in the page
|
||||
* @param $oSet DBObjectSet The set of data to display
|
||||
* @param $aClassAliases Hash The list of classes/aliases to be displayed in this set $sAlias => $sClassName
|
||||
* @param $sTableId mixed A string (or null) identifying this table in order to persist its settings
|
||||
* @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)
|
||||
{
|
||||
$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;
|
||||
@@ -50,7 +53,19 @@ class DataTable
|
||||
$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;
|
||||
@@ -119,7 +134,23 @@ class DataTable
|
||||
|
||||
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);
|
||||
@@ -137,7 +168,7 @@ class DataTable
|
||||
$sDataTable = $this->GetHTMLTable($oPage, $aColumns, $sSelectMode, $iPageSize, $bViewLink, $aExtraParams);
|
||||
$sConfigDlg = $this->GetTableConfigDlg($oPage, $aColumns, $bViewLink, $iDefaultPageSize);
|
||||
|
||||
$sHtml = "<table id=\"datatable_{$this->iListId}\" class=\"datatable\">";
|
||||
$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>";
|
||||
@@ -173,7 +204,7 @@ class DataTable
|
||||
$aOptions['oDefaultSettings'] = $this->GetAsHash($this->oDefaultSettings);
|
||||
}
|
||||
$sJSOptions = json_encode($aOptions);
|
||||
$oPage->add_ready_script("$('#datatable_{$this->iListId}').datatable($sJSOptions);");
|
||||
$oPage->add_ready_script("$('#{$this->sDatatableContainerId}').datatable($sJSOptions);");
|
||||
|
||||
return $sHtml;
|
||||
}
|
||||
@@ -198,7 +229,13 @@ class DataTable
|
||||
}
|
||||
return $sHtml;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param \WebPage $oPage
|
||||
* @param $sSelectMode
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function GetObjectCount(WebPage $oPage, $sSelectMode)
|
||||
{
|
||||
if (($sSelectMode == 'single') || ($sSelectMode == 'multiple'))
|
||||
@@ -211,6 +248,15 @@ class DataTable
|
||||
}
|
||||
return $sHtml;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \WebPage $oPage
|
||||
* @param $iPageSize
|
||||
* @param $iDefaultPageSize
|
||||
* @param $iPageIndex
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function GetPager(WebPage $oPage, $iPageSize, $iDefaultPageSize, $iPageIndex)
|
||||
{
|
||||
$sHtml = '';
|
||||
@@ -295,7 +341,17 @@ class DataTable
|
||||
EOF;
|
||||
return $sHtml;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param \WebPage $oPage
|
||||
* @param $aExtraParams
|
||||
*
|
||||
* @return string
|
||||
* @throws \CoreException
|
||||
* @throws \DictExceptionMissingString
|
||||
* @throws \MissingQueryArgument
|
||||
* @throws \MySQLException
|
||||
*/
|
||||
protected function GetActionsMenu(WebPage $oPage, $aExtraParams)
|
||||
{
|
||||
$oMenuBlock = new MenuBlock($this->oSet->GetFilter(), 'list');
|
||||
@@ -303,13 +359,20 @@ EOF;
|
||||
$sHtml = $oMenuBlock->GetRenderContent($oPage, $aExtraParams, $this->iListId);
|
||||
return $sHtml;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @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><img src="../images/toolkit_menu.png?t='.utils::GetCacheBusterTimestamp().'"><ul>';
|
||||
$sHtml = '<div class="itop_popup toolkit_menu" id="tk_'.$this->iListId.'"><ul><li><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(
|
||||
@@ -326,7 +389,15 @@ EOF;
|
||||
}
|
||||
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;\">";
|
||||
@@ -350,35 +421,54 @@ EOF;
|
||||
$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="$(\'#datatable_'.$this->iListId.'\').datatable(\'onDlgCancel\'); $(\'#datatable_dlg_'.$this->iListId.'\').dialog(\'close\')">'.Dict::S('UI:Button:Cancel').'</button>';
|
||||
$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="$(\'#datatable_'.$this->iListId.'\').datatable(\'onDlgOk\');$(\'#datatable_dlg_'.$this->iListId.'\').dialog(\'close\');">'.Dict::S('UI:Button:Ok').'</button>';
|
||||
$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() { $('#datatable_{$this->iListId}').datatable('onDlgCancel'); } });");
|
||||
$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+'));
|
||||
$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' => '');
|
||||
$aAttribs['form::select'] = array('label' => '', 'description' => '', 'metadata' => array());
|
||||
}
|
||||
|
||||
foreach($this->aClassAliases as $sAlias => $sClassName)
|
||||
@@ -389,19 +479,55 @@ EOF;
|
||||
{
|
||||
if ($sAttCode == '_key_')
|
||||
{
|
||||
$aAttribs['key_'.$sAlias] = array('label' => MetaModel::GetName($sClassName), 'description' => '');
|
||||
$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);
|
||||
$aAttribs[$sAttCode.'_'.$sAlias] = array('label' => MetaModel::GetLabel($sClassName, $sAttCode), 'description' => $oAttDef->GetOrderByHint());
|
||||
$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;
|
||||
@@ -411,6 +537,7 @@ EOF;
|
||||
}
|
||||
|
||||
$aValues = array();
|
||||
$aAttDefsCache = array();
|
||||
$this->oSet->Seek(0);
|
||||
$iMaxObjects = $iPageSize;
|
||||
while (($aObjects = $this->oSet->FetchAssoc()) && ($iMaxObjects != 0))
|
||||
@@ -451,11 +578,41 @@ EOF;
|
||||
{
|
||||
if ($sAttCode == '_key_')
|
||||
{
|
||||
$aRow['key_'.$sAlias] = $aObjects[$sAlias]->GetHyperLink();
|
||||
$aRow['key_'.$sAlias] = array(
|
||||
'value_raw' => $aObjects[$sAlias]->GetKey(),
|
||||
'value_html' => $aObjects[$sAlias]->GetHyperLink(),
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
$aRow[$sAttCode.'_'.$sAlias] = $aObjects[$sAlias]->GetAsHTML($sAttCode, $bLocalize);
|
||||
// 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),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -484,7 +641,25 @@ EOF;
|
||||
}
|
||||
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);
|
||||
@@ -496,7 +671,7 @@ EOF;
|
||||
|
||||
$aValues = $this->GetHTMLTableValues($aColumns, $sSelectMode, $iPageSize, $bViewLink, $aExtraParams);
|
||||
|
||||
$sHtml = '<table class="listContainer">';
|
||||
$sHtml = '<table class="listContainer object-list">';
|
||||
|
||||
foreach($this->oSet->GetFilter()->GetInternalParams() as $sName => $sValue)
|
||||
{
|
||||
@@ -573,19 +748,37 @@ EOF;
|
||||
}
|
||||
$sOQL = addslashes($this->oSet->GetFilter()->serialize());
|
||||
$oPage->add_ready_script(
|
||||
<<<EOF
|
||||
var oTable = $('#{$this->iListId} table.listResults');
|
||||
<<<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->iListId}', columns: $sJSColumns, class_aliases: $sJSClassAliases $sCssCount});
|
||||
EOF
|
||||
);
|
||||
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;
|
||||
@@ -609,11 +802,48 @@ EOF
|
||||
*/
|
||||
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);
|
||||
@@ -638,7 +868,13 @@ class DataTableSettings implements Serializable
|
||||
public $iDefaultPageSize;
|
||||
public $aColumns;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* DataTableSettings constructor.
|
||||
*
|
||||
* @param $aClassAliases
|
||||
* @param null $sTableId
|
||||
*/
|
||||
public function __construct($aClassAliases, $sTableId = null)
|
||||
{
|
||||
$this->aClassAliases = $aClassAliases;
|
||||
@@ -646,14 +882,22 @@ class DataTableSettings implements Serializable
|
||||
$this->iDefaultPageSize = 10;
|
||||
$this->aColumns = array();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $iDefaultPageSize
|
||||
* @param $aSortOrder
|
||||
* @param $aColumns
|
||||
*/
|
||||
protected function Init($iDefaultPageSize, $aSortOrder, $aColumns)
|
||||
{
|
||||
$this->iDefaultPageSize = $iDefaultPageSize;
|
||||
$this->aColumns = $aColumns;
|
||||
$this->FixVisibleColumns();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function serialize()
|
||||
{
|
||||
// Save only the 'visible' columns
|
||||
@@ -679,7 +923,12 @@ class DataTableSettings implements Serializable
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param string $sData
|
||||
*
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function unserialize($sData)
|
||||
{
|
||||
$aData = unserialize($sData);
|
||||
@@ -712,7 +961,16 @@ class DataTableSettings implements Serializable
|
||||
}
|
||||
$this->FixVisibleColumns();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $aClassAliases
|
||||
* @param $bViewLink
|
||||
* @param $aDefaultLists
|
||||
*
|
||||
* @return \DataTableSettings
|
||||
* @throws \CoreException
|
||||
* @throws \DictExceptionMissingString
|
||||
*/
|
||||
static public function GetDataModelSettings($aClassAliases, $bViewLink, $aDefaultLists)
|
||||
{
|
||||
$oSettings = new DataTableSettings($aClassAliases);
|
||||
@@ -762,7 +1020,10 @@ class DataTableSettings implements Serializable
|
||||
$oSettings->Init($iDefaultPageSize, $aSortOrder, $aColumns);
|
||||
return $oSettings;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @throws \CoreException
|
||||
*/
|
||||
protected function FixVisibleColumns()
|
||||
{
|
||||
foreach($this->aClassAliases as $sAlias => $sClass)
|
||||
@@ -799,7 +1060,15 @@ class DataTableSettings implements Serializable
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $aClassAliases
|
||||
* @param null $sTableId
|
||||
* @param bool $bOnlyOnTable
|
||||
*
|
||||
* @return \DataTableSettings|null
|
||||
* @throws \Exception
|
||||
*/
|
||||
static public function GetTableSettings($aClassAliases, $sTableId = null, $bOnlyOnTable = false)
|
||||
{
|
||||
$pref = null;
|
||||
@@ -828,7 +1097,10 @@ class DataTableSettings implements Serializable
|
||||
|
||||
return $oSettings;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function GetSortOrder()
|
||||
{
|
||||
$aSortOrder = array();
|
||||
@@ -846,7 +1118,12 @@ class DataTableSettings implements Serializable
|
||||
}
|
||||
return $aSortOrder;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param null $sTargetTableId
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function Save($sTargetTableId = null)
|
||||
{
|
||||
$sSaveId = is_null($sTargetTableId) ? $this->sTableId : $sTargetTableId;
|
||||
@@ -857,6 +1134,9 @@ class DataTableSettings implements Serializable
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function SaveAsDefault()
|
||||
{
|
||||
$sSettings = $this->serialize();
|
||||
@@ -886,18 +1166,43 @@ class DataTableSettings implements Serializable
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param null $sTableId
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function GetPrefsKey($sTableId = null)
|
||||
{
|
||||
if ($sTableId == null) $sTableId = '*';
|
||||
return static::GetAppUserPreferenceKey($this->aClassAliases, $sTableId);
|
||||
}
|
||||
|
||||
public static function GetAppUserPreferenceKey($aClassAliases, $sTableId)
|
||||
{
|
||||
if ($sTableId === null)
|
||||
{
|
||||
$sTableId = '*';
|
||||
}
|
||||
|
||||
$aKeys = array();
|
||||
foreach($this->aClassAliases as $sAlias => $sClass)
|
||||
foreach($aClassAliases as $sAlias => $sClass)
|
||||
{
|
||||
$aKeys[] = $sAlias.'-'.$sClass;
|
||||
}
|
||||
return implode('/', $aKeys).'|'.$sTableId;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $sAlias
|
||||
* @param $sAttCode
|
||||
* @param $oAttDef
|
||||
* @param $bChecked
|
||||
* @param $sSort
|
||||
*
|
||||
* @return array|bool
|
||||
* @throws \CoreException
|
||||
* @throws \DictExceptionMissingString
|
||||
*/
|
||||
protected function GetFieldData($sAlias, $sAttCode, $oAttDef, $bChecked, $sSort)
|
||||
{
|
||||
$ret = false;
|
||||
|
||||
@@ -1,26 +1,20 @@
|
||||
<?php
|
||||
// Copyright (C) 2010-2017 Combodo SARL
|
||||
//
|
||||
// This file is part of iTop.
|
||||
//
|
||||
// iTop is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// iTop is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with iTop. If not, see <http://www.gnu.org/licenses/>
|
||||
|
||||
/**
|
||||
* DisplayBlock and derived class
|
||||
* Copyright (C) 2013-2019 Combodo SARL
|
||||
*
|
||||
* @copyright Copyright (C) 2010-2017 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
* 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
|
||||
*/
|
||||
|
||||
require_once(APPROOT.'/application/webpage.class.inc.php');
|
||||
@@ -91,7 +85,7 @@ class DisplayBlock
|
||||
{
|
||||
$oDummyFilter = new DBObjectSearch($oSet->GetClass());
|
||||
$aKeys = array();
|
||||
$oSet->OptimizeColumnLoad(array('id')); // No need to load all the columns just to get the id
|
||||
$oSet->OptimizeColumnLoad(array($oSet->GetClassAlias() => array())); // No need to load all the columns just to get the id
|
||||
while($oObject = $oSet->Fetch())
|
||||
{
|
||||
$aKeys[] = $oObject->GetKey();
|
||||
@@ -249,7 +243,7 @@ class DisplayBlock
|
||||
$sHtml .= $this->GetRenderContent($oPage, $aExtraParams, $sId);
|
||||
} catch (Exception $e)
|
||||
{
|
||||
|
||||
IssueLog::Error('Exception during GetDisplay: ' . $e->getMessage());
|
||||
}
|
||||
$sHtml .= "</div>\n";
|
||||
}
|
||||
@@ -843,7 +837,8 @@ class DisplayBlock
|
||||
|
||||
foreach($aStates as $sStateValue)
|
||||
{
|
||||
$aStateLabels[$sStateValue] = htmlentities($oAttDef->GetValueLabel($sStateValue), ENT_QUOTES, 'UTF-8');
|
||||
$sHtmlValue=$aGroupBy['group1']->MakeValueLabel($this->m_oFilter, $sStateValue, $sStateValue);
|
||||
$aStateLabels[$sStateValue] = html_entity_decode(strip_tags($sHtmlValue), ENT_QUOTES, 'UTF-8');
|
||||
|
||||
$aCounts[$sStateValue] = (array_key_exists($sStateValue, $aCountsQueryResults))
|
||||
? $aCountsQueryResults[$sStateValue]
|
||||
@@ -952,7 +947,7 @@ class DisplayBlock
|
||||
$iChartCounter++;
|
||||
|
||||
$sChartType = isset($aExtraParams['chart_type']) ? $aExtraParams['chart_type'] : 'pie';
|
||||
$sTitle = isset($aExtraParams['chart_title']) ? '<h1 style="text-align:center">'.htmlentities(Dict::S($aExtraParams['chart_title']), ENT_QUOTES, 'UTF-8').'</h1>' : '';
|
||||
$sTitle = isset($aExtraParams['chart_title']) ? '<div class="main_header"><h1> '.htmlentities(Dict::S($aExtraParams['chart_title']), ENT_QUOTES, 'UTF-8').'</h1></div>' : '';
|
||||
$sHtml = "$sTitle<div style=\"height:200px;width:100%\" class=\"dashboard_chart\" id=\"my_chart_$sId{$iChartCounter}\"><div style=\"height:200px;line-height:200px;vertical-align:center;text-align:center;width:100%\"><img src=\"../images/indicator.gif\"></div></div>\n";
|
||||
$sGroupBy = isset($aExtraParams['group_by']) ? $aExtraParams['group_by'] : '';
|
||||
$sGroupByExpr = isset($aExtraParams['group_by_expr']) ? '¶ms[group_by_expr]='.$aExtraParams['group_by_expr'] : '';
|
||||
@@ -1886,11 +1881,11 @@ class MenuBlock extends DisplayBlock
|
||||
{
|
||||
if (count($aFavoriteActions) > 0)
|
||||
{
|
||||
$sHtml .= "<div class=\"itop_popup actions_menu\"><ul>\n<li>".Dict::S('UI:Menu:OtherActions')."\n<ul>\n";
|
||||
$sHtml .= "<div class=\"itop_popup actions_menu\"><ul>\n<li>".Dict::S('UI:Menu:OtherActions')."<i class=\"fas fa-caret-down\"></i>"."\n<ul>\n";
|
||||
}
|
||||
else
|
||||
{
|
||||
$sHtml .= "<div class=\"itop_popup actions_menu\"><ul>\n<li>".Dict::S('UI:Menu:Actions')."\n<ul>\n";
|
||||
$sHtml .= "<div class=\"itop_popup actions_menu\"><ul>\n<li>".Dict::S('UI:Menu:Actions')."<i class=\"fas fa-caret-down\"></i>"."\n<ul>\n";
|
||||
}
|
||||
|
||||
$sHtml .= $oPage->RenderPopupMenuItems($aActions, $aFavoriteActions);
|
||||
@@ -1898,7 +1893,8 @@ class MenuBlock extends DisplayBlock
|
||||
if ($this->m_sStyle == 'details')
|
||||
{
|
||||
$sSearchAction = "window.location=\"{$sRootUrl}pages/UI.php?operation=search_form&do_search=0&class=$sClass{$sContext}\"";
|
||||
$sHtml .= "<div class=\"actions_button icon_actions_button\" title=\"".htmlentities(Dict::Format('UI:SearchFor_Class', MetaModel::GetName($sClass)), ENT_QUOTES, 'UTF-8')."\"><span class=\"search-button fa fa-search\" onclick='$sSearchAction'></span></div>";
|
||||
$sHtml .= "<div class=\"actions_button icon_actions_button\" title=\"".htmlentities(Dict::Format('UI:SearchFor_Class',
|
||||
MetaModel::GetName($sClass)), ENT_QUOTES, 'UTF-8')."\"><span class=\"search-button fas fa-search\" onclick='$sSearchAction'></span></div>";
|
||||
}
|
||||
|
||||
|
||||
@@ -1909,7 +1905,8 @@ class MenuBlock extends DisplayBlock
|
||||
}
|
||||
if (!$oPage->IsPrintableVersion() && ($sRefreshAction!=''))
|
||||
{
|
||||
$sHtml .= "<div class=\"actions_button icon_actions_button\" title=\"".htmlentities(Dict::S('UI:Button:Refresh'), ENT_QUOTES, 'UTF-8')."\"><span class=\"refresh-button fa fa-refresh\" onclick=\"$sRefreshAction\"></span></div>";
|
||||
$sHtml .= "<div class=\"actions_button icon_actions_button\" title=\"".htmlentities(Dict::S('UI:Button:Refresh'),
|
||||
ENT_QUOTES, 'UTF-8')."\"><span class=\"refresh-button fas fa-sync\" onclick=\"$sRefreshAction\"></span></div>";
|
||||
}
|
||||
|
||||
|
||||
|
||||
82
application/errorpage.class.inc.php
Normal file
82
application/errorpage.class.inc.php
Normal file
@@ -0,0 +1,82 @@
|
||||
<?php
|
||||
/**
|
||||
* @copyright Copyright (C) 2010-2020 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
|
||||
class ErrorPage extends NiceWebPage
|
||||
{
|
||||
public function __construct($sTitle)
|
||||
{
|
||||
parent::__construct($sTitle);
|
||||
$this->add_linked_script("../js/jquery.blockUI.js");
|
||||
$this->add_linked_script("../setup/setup.js");
|
||||
$this->add_saas("css/setup.scss");
|
||||
}
|
||||
|
||||
public function info($sText)
|
||||
{
|
||||
$this->add("<p class=\"info\">$sText</p>\n");
|
||||
$this->log_info($sText);
|
||||
}
|
||||
|
||||
public function ok($sText)
|
||||
{
|
||||
$this->add("<div class=\"message message-valid\"><span class=\"message-title\">Success:</span>$sText</div>");
|
||||
$this->log_ok($sText);
|
||||
}
|
||||
|
||||
public function warning($sText)
|
||||
{
|
||||
$this->add("<div class=\"message message-warning\"><span class=\"message-title\">Warning:</span>$sText</div>");
|
||||
$this->log_warning($sText);
|
||||
}
|
||||
|
||||
public function error($sText)
|
||||
{
|
||||
$this->add("<div class=\"message message-error\">$sText</div>");
|
||||
$this->log_error($sText);
|
||||
}
|
||||
|
||||
public function output()
|
||||
{
|
||||
$sLogo = utils::GetAbsoluteUrlAppRoot().'/images/itop-logo.png';
|
||||
$sTimeStamp = utils::GetCacheBusterTimestamp();
|
||||
$sTitle = utils::HtmlEntities($this->s_title);
|
||||
$this->s_content = <<<HTML
|
||||
<div id="header" class="error_page">
|
||||
<h1><a href="http://www.combodo.com/itop" target="_blank"><img title="iTop by Combodo" alt=" " src="{$sLogo}?t={$sTimeStamp}"></a> {$sTitle}</h1>
|
||||
</div>
|
||||
<div id="setup" class="error_page">
|
||||
{$this->s_content}
|
||||
</div>
|
||||
HTML;
|
||||
return parent::output();
|
||||
}
|
||||
|
||||
public static function log_error($sText)
|
||||
{
|
||||
IssueLog::Error($sText);
|
||||
}
|
||||
|
||||
public static function log_warning($sText)
|
||||
{
|
||||
IssueLog::Warning($sText);
|
||||
}
|
||||
|
||||
public static function log_info($sText)
|
||||
{
|
||||
IssueLog::Info($sText);
|
||||
}
|
||||
|
||||
public static function log_ok($sText)
|
||||
{
|
||||
IssueLog::Ok($sText);
|
||||
}
|
||||
|
||||
public static function log($sText)
|
||||
{
|
||||
IssueLog::Ok($sText);
|
||||
}
|
||||
}
|
||||
@@ -395,6 +395,7 @@ EOF
|
||||
{
|
||||
foreach($aFields as $oField)
|
||||
{
|
||||
/** @var \DesignerFormField $oField */
|
||||
$oField->ReadParam($aValues);
|
||||
}
|
||||
}
|
||||
@@ -679,18 +680,34 @@ class DesignerTabularForm extends DesignerForm
|
||||
|
||||
class DesignerFormField
|
||||
{
|
||||
/** @var string $sLabel */
|
||||
protected $sLabel;
|
||||
/** @var string $sCode */
|
||||
protected $sCode;
|
||||
/** @var mixed $defaultValue */
|
||||
protected $defaultValue;
|
||||
/** @var \DesignerForm $oForm */
|
||||
protected $oForm;
|
||||
/** @var bool $bMandatory */
|
||||
protected $bMandatory;
|
||||
/** @var bool $bReadOnly */
|
||||
protected $bReadOnly;
|
||||
/** @var bool $bAutoApply */
|
||||
protected $bAutoApply;
|
||||
/** @var array $aCSSClasses */
|
||||
protected $aCSSClasses;
|
||||
/** @var bool $bDisplayed */
|
||||
protected $bDisplayed;
|
||||
/** @var array $aWidgetExtraParams */
|
||||
protected $aWidgetExtraParams;
|
||||
|
||||
|
||||
/**
|
||||
* DesignerFormField constructor.
|
||||
*
|
||||
* @param string $sCode
|
||||
* @param string $sLabel
|
||||
* @param mixed $defaultValue
|
||||
*/
|
||||
public function __construct($sCode, $sLabel, $defaultValue)
|
||||
{
|
||||
$this->sLabel = $sLabel;
|
||||
@@ -703,7 +720,10 @@ class DesignerFormField
|
||||
$this->bDisplayed = true;
|
||||
$this->aWidgetExtraParams = array();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function GetCode()
|
||||
{
|
||||
return $this->sCode;
|
||||
@@ -712,69 +732,108 @@ class DesignerFormField
|
||||
/**
|
||||
* @param \DesignerForm $oForm
|
||||
*/
|
||||
public function SetForm(\DesignerForm $oForm)
|
||||
public function SetForm(DesignerForm $oForm)
|
||||
{
|
||||
$this->oForm = $oForm;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param bool $bMandatory
|
||||
*/
|
||||
public function SetMandatory($bMandatory = true)
|
||||
{
|
||||
$this->bMandatory = $bMandatory;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bool $bReadOnly
|
||||
*/
|
||||
public function SetReadOnly($bReadOnly = true)
|
||||
{
|
||||
$this->bReadOnly = $bReadOnly;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function IsReadOnly()
|
||||
{
|
||||
return ($this->oForm->IsReadOnly() || $this->bReadOnly);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bool $bAutoApply
|
||||
*/
|
||||
public function SetAutoApply($bAutoApply)
|
||||
{
|
||||
$this->bAutoApply = $bAutoApply;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function IsAutoApply()
|
||||
{
|
||||
return $this->bAutoApply;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bool $bDisplayed
|
||||
*/
|
||||
public function SetDisplayed($bDisplayed)
|
||||
{
|
||||
$this->bDisplayed = $bDisplayed;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function IsDisplayed()
|
||||
{
|
||||
return $this->bDisplayed;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function GetFieldId()
|
||||
{
|
||||
return $this->oForm->GetFieldId($this->sCode);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function GetWidgetClass()
|
||||
{
|
||||
return 'property_field';
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function GetWidgetExtraParams()
|
||||
{
|
||||
return $this->aWidgetExtraParams;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param \WebPage $oP
|
||||
* @param string $sFormId
|
||||
* @param string $sRenderMode
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function Render(WebPage $oP, $sFormId, $sRenderMode='dialog')
|
||||
{
|
||||
$sId = $this->oForm->GetFieldId($this->sCode);
|
||||
$sName = $this->oForm->GetFieldName($this->sCode);
|
||||
return array('label' => $this->sLabel, 'value' => "<input type=\"text\" id=\"$sId\" name=\"$sName\" value=\"".htmlentities($this->defaultValue, ENT_QUOTES, 'UTF-8')."\">");
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param array $aValues
|
||||
*/
|
||||
public function ReadParam(&$aValues)
|
||||
{
|
||||
if ($this->IsReadOnly())
|
||||
@@ -801,12 +860,18 @@ class DesignerFormField
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function IsVisible()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param string $sCSSClass
|
||||
*/
|
||||
public function AddCSSClass($sCSSClass)
|
||||
{
|
||||
$this->aCSSClasses[] = $sCSSClass;
|
||||
@@ -814,6 +879,8 @@ class DesignerFormField
|
||||
|
||||
/**
|
||||
* A way to set/change the default value after constructing the field
|
||||
*
|
||||
* @param array $aAllDefaultValue
|
||||
*/
|
||||
public function SetDefaultValueFrom($aAllDefaultValue)
|
||||
{
|
||||
@@ -822,7 +889,12 @@ class DesignerFormField
|
||||
$this->defaultValue = $aAllDefaultValue[$this->GetCode()];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $sFieldCode
|
||||
*
|
||||
* @return \DesignerFormField|false
|
||||
*/
|
||||
public function FindField($sFieldCode)
|
||||
{
|
||||
if ($this->sCode == $sFieldCode)
|
||||
@@ -832,11 +904,17 @@ class DesignerFormField
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function GetHandlerEquals()
|
||||
{
|
||||
return 'null';
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function GetHandlerGetValue()
|
||||
{
|
||||
return 'null';
|
||||
@@ -845,25 +923,43 @@ class DesignerFormField
|
||||
|
||||
class DesignerLabelField extends DesignerFormField
|
||||
{
|
||||
/** @var int $iCount A counter to automatically make the field code */
|
||||
protected static $iCount = 0;
|
||||
/** @var string $sDescription */
|
||||
protected $sDescription;
|
||||
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function __construct($sLabel, $sDescription)
|
||||
{
|
||||
parent::__construct('', $sLabel, '');
|
||||
// Increase counter
|
||||
static::$iCount++;
|
||||
|
||||
parent::__construct('label_number_' . static::$iCount, $sLabel, '');
|
||||
$this->sDescription = $sDescription;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function Render(WebPage $oP, $sFormId, $sRenderMode='dialog')
|
||||
{
|
||||
$sId = $this->oForm->GetFieldId($this->sCode);
|
||||
$sName = $this->oForm->GetFieldName($this->sCode);
|
||||
return array('label' => $this->sLabel, 'value' => $this->sDescription);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function ReadParam(&$aValues)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function IsVisible()
|
||||
{
|
||||
return true;
|
||||
@@ -1334,7 +1430,8 @@ class DesignerIconSelectionField extends DesignerFormField
|
||||
$sPostUploadTo = ($this->sUploadUrl == null) ? 'null' : "'{$this->sUploadUrl}'";
|
||||
if (!$this->IsReadOnly())
|
||||
{
|
||||
$sValue = "<input type=\"hidden\" id=\"$sId\" name=\"$sName\" value=\"{$this->defaultValue}\"/>";
|
||||
$sDefaultValue = ($this->defaultValue !== '') ? $this->defaultValue : $this->aAllowedValues[$idx]['value'];
|
||||
$sValue = "<input type=\"hidden\" id=\"$sId\" name=\"$sName\" value=\"{$sDefaultValue}\"/>";
|
||||
$oP->add_ready_script(
|
||||
<<<EOF
|
||||
$('#$sId').icon_select({current_idx: $idx, items: $sJSItems, post_upload_to: $sPostUploadTo});
|
||||
@@ -1396,6 +1493,7 @@ class RunTimeIconSelectionField extends DesignerIconSelectionField
|
||||
$sAvailableIcons .= ' static $sKey = '.var_export($sKey, true).';'.PHP_EOL;
|
||||
$sAvailableIcons .= ' static $aIconFiles = '.var_export($aFiles, true).';'.PHP_EOL;
|
||||
$sAvailableIcons .= '}'.PHP_EOL;
|
||||
SetupUtils::builddir(dirname($sCacheFile));
|
||||
file_put_contents($sCacheFile, $sAvailableIcons, LOCK_EX);
|
||||
}
|
||||
return $aFiles;
|
||||
|
||||
@@ -1,27 +1,20 @@
|
||||
<?php
|
||||
// Copyright (C) 2010-2018 Combodo SARL
|
||||
//
|
||||
// This file is part of iTop.
|
||||
//
|
||||
// iTop is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// iTop is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with iTop. If not, see <http://www.gnu.org/licenses/>
|
||||
|
||||
|
||||
/**
|
||||
* Class iTopWebPage
|
||||
* Copyright (C) 2013-2020 Combodo SARL
|
||||
*
|
||||
* @copyright Copyright (C) 2010-2018 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
* 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
|
||||
*/
|
||||
|
||||
require_once(APPROOT."/application/nicewebpage.class.inc.php");
|
||||
@@ -46,13 +39,19 @@ class iTopWebPage extends NiceWebPage implements iTabbedPage
|
||||
protected $sBreadCrumbEntryIcon;
|
||||
protected $oCtx;
|
||||
|
||||
protected $bHasCollapsibleSection = false;
|
||||
|
||||
/**
|
||||
* iTopWebPage constructor.
|
||||
*
|
||||
* @param string $sTitle
|
||||
* @param bool $bPrintable
|
||||
*
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function __construct($sTitle, $bPrintable = false)
|
||||
{
|
||||
parent::__construct($sTitle, $bPrintable);
|
||||
$this->m_oTabs = new TabManager();
|
||||
$this->oCtx = new ContextTag('GUI:Console');
|
||||
$this->oCtx = new ContextTag(ContextTag::TAG_CONSOLE);
|
||||
|
||||
ApplicationContext::SetUrlMakerClass('iTopStandardURLMaker');
|
||||
|
||||
@@ -71,7 +70,7 @@ class iTopWebPage extends NiceWebPage implements iTabbedPage
|
||||
$this->m_sMenu = "";
|
||||
$this->m_aMessages = array();
|
||||
$this->SetRootUrl(utils::GetAbsoluteUrlAppRoot());
|
||||
$this->add_header("Content-type: text/html; charset=utf-8");
|
||||
$this->add_header("Content-type: text/html; charset=".self::PAGES_CHARSET);
|
||||
$this->add_header('Cache-control: no-cache, no-store, must-revalidate');
|
||||
$this->add_header('Pragma: no-cache');
|
||||
$this->add_header('Expires: 0');
|
||||
@@ -82,7 +81,9 @@ class iTopWebPage extends NiceWebPage implements iTabbedPage
|
||||
$this->add_linked_stylesheet("../css/jquery.multiselect.css");
|
||||
$this->add_linked_stylesheet("../css/magnific-popup.css");
|
||||
$this->add_linked_stylesheet("../css/c3.min.css");
|
||||
$this->add_linked_stylesheet("../css/font-awesome/css/font-awesome.min.css");
|
||||
$this->add_linked_stylesheet("../css/font-awesome/css/all.min.css");
|
||||
$this->add_linked_stylesheet("../css/font-awesome/css/v4-shims.min.css");
|
||||
$this->add_linked_stylesheet("../js/ckeditor/plugins/codesnippet/lib/highlight/styles/obsidian.css");
|
||||
|
||||
$this->add_linked_script('../js/jquery.layout.min.js');
|
||||
$this->add_linked_script('../js/jquery.ba-bbq.min.js');
|
||||
@@ -96,6 +97,7 @@ class iTopWebPage extends NiceWebPage implements iTabbedPage
|
||||
$this->add_linked_script("../js/swfobject.js");
|
||||
$this->add_linked_script("../js/ckeditor/ckeditor.js");
|
||||
$this->add_linked_script("../js/ckeditor/adapters/jquery.js");
|
||||
$this->add_linked_script("../js/ckeditor/plugins/codesnippet/lib/highlight/highlight.pack.js");
|
||||
$this->add_linked_script("../js/jquery.qtip-1.0.min.js");
|
||||
$this->add_linked_script('../js/property_field.js');
|
||||
$this->add_linked_script('../js/icon_select.js');
|
||||
@@ -154,6 +156,9 @@ EOF
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
protected function IsMenuPaneVisible()
|
||||
{
|
||||
$bLeftPaneOpen = true;
|
||||
@@ -176,6 +181,9 @@ EOF
|
||||
return $bLeftPaneOpen;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
protected function PrepareLayout()
|
||||
{
|
||||
if (MetaModel::GetConfig()->Get('demo_mode'))
|
||||
@@ -224,7 +232,6 @@ EOF;
|
||||
);
|
||||
$sTimeFormat = AttributeDateTime::GetFormat()->ToTimeFormat();
|
||||
$oTimeFormat = new DateTimeFormat($sTimeFormat);
|
||||
$sJSLangShort = json_encode(strtolower(substr(Dict::GetUserLanguage(), 0, 2)));
|
||||
|
||||
// Date picker options
|
||||
$aPickerOptions = array(
|
||||
@@ -242,29 +249,38 @@ EOF;
|
||||
$sJSDatePickerOptions = json_encode($aPickerOptions);
|
||||
|
||||
// Time picker additional options
|
||||
$sUserLang = Dict::GetUserLanguage();
|
||||
$sUserLangShort = strtolower(
|
||||
substr($sUserLang, 0, 2)
|
||||
);
|
||||
// PR #40 : we are picking correct values for specific cases in dict files
|
||||
// some languages are using codes like zh-CN or pt-BR
|
||||
$sTimePickerLang = json_encode(
|
||||
Dict::S('INTERNAL:JQuery-DatePicker:LangCode', $sUserLangShort)
|
||||
);
|
||||
$aPickerOptions['showOn'] = '';
|
||||
$aPickerOptions['buttonImage'] = null;
|
||||
$aPickerOptions['timeFormat'] = $oTimeFormat->ToDatePicker();
|
||||
$aPickerOptions['controlType'] = 'select';
|
||||
$aPickerOptions['closeText'] = Dict::S('UI:Button:Ok');
|
||||
$sJSDateTimePickerOptions = json_encode($aPickerOptions);
|
||||
if ($sJSLangShort != '"en"')
|
||||
if ($sTimePickerLang != '"en"')
|
||||
{
|
||||
// More options that cannot be passed via json_encode since they must be evaluated client-side
|
||||
$aMoreJSOptions = ",
|
||||
'timeText': $.timepicker.regional[$sJSLangShort].timeText,
|
||||
'hourText': $.timepicker.regional[$sJSLangShort].hourText,
|
||||
'minuteText': $.timepicker.regional[$sJSLangShort].minuteText,
|
||||
'secondText': $.timepicker.regional[$sJSLangShort].secondText,
|
||||
'currentText': $.timepicker.regional[$sJSLangShort].currentText
|
||||
'timeText': $.timepicker.regional[$sTimePickerLang].timeText,
|
||||
'hourText': $.timepicker.regional[$sTimePickerLang].hourText,
|
||||
'minuteText': $.timepicker.regional[$sTimePickerLang].minuteText,
|
||||
'secondText': $.timepicker.regional[$sTimePickerLang].secondText,
|
||||
'currentText': $.timepicker.regional[$sTimePickerLang].currentText
|
||||
}";
|
||||
$sJSDateTimePickerOptions = substr($sJSDateTimePickerOptions, 0, -1).$aMoreJSOptions;
|
||||
}
|
||||
$this->add_script(
|
||||
<<< EOF
|
||||
<<< JS
|
||||
function GetUserLanguage()
|
||||
{
|
||||
return $sJSLangShort;
|
||||
return $sTimePickerLang;
|
||||
}
|
||||
function PrepareWidgets()
|
||||
{
|
||||
@@ -296,12 +312,12 @@ EOF;
|
||||
});
|
||||
});
|
||||
}
|
||||
EOF
|
||||
JS
|
||||
);
|
||||
|
||||
// Attribute set tooltip on items
|
||||
$this->add_ready_script(
|
||||
<<<EOF
|
||||
<<<JS
|
||||
$('.attribute-set-item').each(function(){
|
||||
// Encoding only title as the content is already sanitized by the HTML attribute.
|
||||
var sLabel = $('<div/>').text($(this).attr('data-label')).html();
|
||||
@@ -328,25 +344,38 @@ EOF
|
||||
position: { corner: { target: 'topMiddle', tooltip: 'bottomLeft' }}
|
||||
});
|
||||
});
|
||||
EOF
|
||||
JS
|
||||
);
|
||||
|
||||
// Make image attributes zoomable
|
||||
$this->add_ready_script(
|
||||
<<<EOF
|
||||
<<<JS
|
||||
$('.view-image img').each(function(){
|
||||
$(this).attr('href', $(this).attr('src'))
|
||||
})
|
||||
.magnificPopup({type: 'image', closeOnContentClick: true });
|
||||
EOF
|
||||
JS
|
||||
);
|
||||
|
||||
// Highlight code content created with CKEditor
|
||||
$this->add_ready_script(
|
||||
<<<JS
|
||||
// Highlight code content for HTML AttributeText
|
||||
$("[data-attribute-type='AttributeText'] .HTML pre").each(function(i, block) {
|
||||
hljs.highlightBlock(block);
|
||||
});
|
||||
// Highlight code content for CaseLogs
|
||||
$("[data-attribute-type='AttributeCaseLog'] .caselog_entry_html pre").each(function(i, block) {
|
||||
hljs.highlightBlock(block);
|
||||
});
|
||||
JS
|
||||
);
|
||||
|
||||
$this->add_init_script(
|
||||
<<< EOF
|
||||
<<< JS
|
||||
try
|
||||
{
|
||||
var myLayout; // a var is required because this page utilizes: myLayout.allowOverflow() method
|
||||
|
||||
|
||||
// Layout
|
||||
paneSize = GetUserPreference('menu_size', 300);
|
||||
if ($('body').length > 0)
|
||||
@@ -452,11 +481,11 @@ EOF
|
||||
// Do something with the error !
|
||||
alert(err);
|
||||
}
|
||||
EOF
|
||||
JS
|
||||
);
|
||||
|
||||
$this->add_ready_script(
|
||||
<<< EOF
|
||||
<<< JS
|
||||
|
||||
// Adjust initial size
|
||||
$('.v-resizable').each( function()
|
||||
@@ -617,7 +646,7 @@ EOF
|
||||
});
|
||||
}
|
||||
});
|
||||
EOF
|
||||
JS
|
||||
);
|
||||
$this->add_ready_script(InlineImage::FixImagesWidth());
|
||||
/*
|
||||
@@ -628,7 +657,7 @@ EOF
|
||||
|
||||
$sUserPrefs = appUserPreferences::GetAsJSON();
|
||||
$this->add_script(
|
||||
<<<EOF
|
||||
<<<JS
|
||||
// // for JQuery history
|
||||
// function history_callback(hash)
|
||||
// {
|
||||
@@ -698,7 +727,7 @@ EOF
|
||||
{
|
||||
$('.ui-layout-center, .ui-layout-north, .ui-layout-south').css({display: 'block'});
|
||||
}
|
||||
EOF
|
||||
JS
|
||||
);
|
||||
}
|
||||
|
||||
@@ -733,11 +762,22 @@ EOF
|
||||
$this->sBreadCrumbEntryIcon = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $sHtml
|
||||
*/
|
||||
public function AddToMenu($sHtml)
|
||||
{
|
||||
$this->m_sMenu .= $sHtml;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
* @throws \CoreException
|
||||
* @throws \MissingQueryArgument
|
||||
* @throws \MySQLException
|
||||
* @throws \MySQLHasGoneAwayException
|
||||
* @throws \OQLException
|
||||
*/
|
||||
public function GetSiloSelectionForm()
|
||||
{
|
||||
// List of visible Organizations
|
||||
@@ -764,15 +804,9 @@ EOF
|
||||
switch ($iCount)
|
||||
{
|
||||
case 0:
|
||||
// No such dimension/silo => nothing to select
|
||||
$sHtml = '<div id="SiloSelection"><!-- nothing to select --></div>';
|
||||
break;
|
||||
|
||||
case 1:
|
||||
// Only one possible choice... no selection, but display the value
|
||||
$oOrg = $oSet->Fetch();
|
||||
$sHtml = '<div id="SiloSelection">'.$oOrg->GetName().'</div>';
|
||||
$sHtml .= '';
|
||||
// No such dimension/silo or only one possible choice => nothing to select
|
||||
$sHtml = '<div id="SiloSelection"><!-- nothing to select --></div>';
|
||||
break;
|
||||
|
||||
default:
|
||||
@@ -804,6 +838,9 @@ EOF
|
||||
return $sHtml;
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws \DictExceptionMissingString
|
||||
*/
|
||||
public function DisplayMenu()
|
||||
{
|
||||
// Display the menu
|
||||
@@ -819,6 +856,8 @@ EOF
|
||||
protected function InitNewsroom()
|
||||
{
|
||||
$sNewsroomInitialImage = '';
|
||||
$aProviderParams = array();
|
||||
|
||||
if (MetaModel::GetConfig()->Get('newsroom_enabled') !== false)
|
||||
{
|
||||
$oUser = UserRights::GetUserObject();
|
||||
@@ -826,31 +865,32 @@ EOF
|
||||
* @var iNewsroomProvider[] $aProviders
|
||||
*/
|
||||
$aProviders = MetaModel::EnumPlugins('iNewsroomProvider');
|
||||
$aProviderParams = array();
|
||||
foreach($aProviders as $oProvider)
|
||||
{
|
||||
$oProvider->SetConfig(MetaModel::GetConfig());
|
||||
$bProviderEnabled = appUserPreferences::GetPref('newsroom_provider_'.get_class($oProvider), true);
|
||||
if ($bProviderEnabled && $oProvider->IsApplicable($oUser))
|
||||
{
|
||||
$aProviderParams[] = array(
|
||||
'label' => $oProvider->GetLabel(),
|
||||
'fetch_url' => $oProvider->GetFetchURL(),
|
||||
'view_all_url' => $oProvider->GetViewAllURL(),
|
||||
'mark_all_as_read_url' => $oProvider->GetMarkAllAsReadURL(),
|
||||
'placeholders' => $oProvider->GetPlaceholders(),
|
||||
'ttl' => $oProvider->GetTTL(),
|
||||
);
|
||||
$bProviderEnabled = appUserPreferences::GetPref('newsroom_provider_'.get_class($oProvider),true);
|
||||
if ($bProviderEnabled && $oProvider->IsApplicable($oUser))
|
||||
{
|
||||
$aProviderParams[] = array(
|
||||
'label' => $oProvider->GetLabel(),
|
||||
'fetch_url' => $oProvider->GetFetchURL(),
|
||||
'view_all_url' => $oProvider->GetViewAllURL(),
|
||||
'mark_all_as_read_url' => $oProvider->GetMarkAllAsReadURL(),
|
||||
'placeholders' => $oProvider->GetPlaceholders(),
|
||||
'ttl' => $oProvider->GetTTL(),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Show newsroom only if there are some providers
|
||||
if (count($aProviderParams) > 0)
|
||||
{
|
||||
$sImageUrl= '../images/newsroom_menu.png';
|
||||
$sPlaceholderImageUrl= '../images/newsroom-message.svg';
|
||||
$sImageUrl= 'fas fa-comment-dots';
|
||||
$sPlaceholderImageUrl= 'far fa-envelope';
|
||||
$aParams = array(
|
||||
'image_url' => $sImageUrl,
|
||||
'placeholder_image_url' => $sPlaceholderImageUrl,
|
||||
'cache_uuid' => 'itop-newsroom-'.md5(APPROOT),
|
||||
'image_icon' => $sImageUrl,
|
||||
'placeholder_image_icon' => $sPlaceholderImageUrl,
|
||||
'cache_uuid' => 'itop-newsroom-'.UserRights::GetUserId().'-'.md5(APPROOT),
|
||||
'providers' => $aProviderParams,
|
||||
'display_limit' => (int)appUserPreferences::GetPref('newsroom_display_size', 7),
|
||||
'labels' => array(
|
||||
@@ -865,20 +905,16 @@ EOF
|
||||
$('#top-left-newsroom-cell').newsroom_menu($sParams);
|
||||
EOF
|
||||
);
|
||||
$sNewsroomInitialImage = '<img style="opacity:0.4" src="../images/newsroom_menu.png">';
|
||||
$sNewsroomInitialImage = '<i style="opacity:0.4" class="top-right-icon fas fa-comment-dots"></i>';
|
||||
}
|
||||
else
|
||||
{
|
||||
// No newsroom menu at all
|
||||
}
|
||||
}
|
||||
// else no newsroom menu
|
||||
return $sNewsroomInitialImage;
|
||||
// else no newsroom menu
|
||||
return $sNewsroomInitialImage;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Outputs (via some echo) the complete HTML page by assembling all its elements
|
||||
* @inheritDoc
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function output()
|
||||
{
|
||||
@@ -957,8 +993,8 @@ EOF
|
||||
$sNewEntry = json_encode(array(
|
||||
'id' => $this->sBreadCrumbEntryId,
|
||||
'url' => $this->sBreadCrumbEntryUrl,
|
||||
'label' => htmlentities($this->sBreadCrumbEntryLabel, ENT_QUOTES, 'UTF-8'),
|
||||
'description' => htmlentities($this->sBreadCrumbEntryDescription, ENT_QUOTES, 'UTF-8'),
|
||||
'label' => htmlentities($this->sBreadCrumbEntryLabel, ENT_QUOTES, self::PAGES_CHARSET),
|
||||
'description' => htmlentities($this->sBreadCrumbEntryDescription, ENT_QUOTES, self::PAGES_CHARSET),
|
||||
'icon' => $this->sBreadCrumbEntryIcon,
|
||||
));
|
||||
}
|
||||
@@ -991,8 +1027,9 @@ EOF
|
||||
$sHtml .= "<head>\n";
|
||||
// Make sure that Internet Explorer renders the page using its latest/highest/greatest standards !
|
||||
$sHtml .= "<meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\" />\n";
|
||||
$sHtml .= "<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\" />\n";
|
||||
$sHtml .= "<title>".htmlentities($this->s_title, ENT_QUOTES, 'UTF-8')."</title>\n";
|
||||
$sPageCharset = self::PAGES_CHARSET;
|
||||
$sHtml .= "<meta http-equiv=\"Content-Type\" content=\"text/html; charset=$sPageCharset\" />\n";
|
||||
$sHtml .= "<title>".htmlentities($this->s_title, ENT_QUOTES, $sPageCharset)."</title>\n";
|
||||
$sHtml .= $this->get_base_tag();
|
||||
// Stylesheets MUST be loaded before any scripts otherwise
|
||||
// jQuery scripts may face some spurious problems (like failing on a 'reload')
|
||||
@@ -1111,16 +1148,18 @@ EOF
|
||||
{
|
||||
$sBodyClass = 'printable-version';
|
||||
}
|
||||
$sHtml .= "<body class=\"$sBodyClass\">\n";
|
||||
$sHtml .= "<body class=\"$sBodyClass\" data-gui-type=\"backoffice\">\n";
|
||||
if ($this->IsPrintableVersion())
|
||||
{
|
||||
$sHtml .= "<div class=\"explain-printable not-printable\">";
|
||||
$sHtml .= '<p>'.Dict::Format('UI:ExplainPrintable',
|
||||
'<img src="../images/eye-open-555.png" style="vertical-align:middle">').'</p>';
|
||||
$sHtml .= "<div id=\"hiddeable_chapters\"></div>";
|
||||
$sHtml .= '<button onclick="window.print()">'.htmlentities(Dict::S('UI:Button:GoPrint'), ENT_QUOTES, 'UTF-8').'</button>';
|
||||
$sHtml .= '<button onclick="window.print()">'.htmlentities(Dict::S('UI:Button:GoPrint'), ENT_QUOTES,
|
||||
self::PAGES_CHARSET).'</button>';
|
||||
$sHtml .= ' ';
|
||||
$sHtml .= '<button onclick="window.close()">'.htmlentities(Dict::S('UI:Button:Cancel'), ENT_QUOTES, 'UTF-8').'</button>';
|
||||
$sHtml .= '<button onclick="window.close()">'.htmlentities(Dict::S('UI:Button:Cancel'), ENT_QUOTES,
|
||||
self::PAGES_CHARSET).'</button>';
|
||||
$sHtml .= ' ';
|
||||
|
||||
$sDefaultResolution = '27.7cm';
|
||||
@@ -1146,7 +1185,7 @@ EOF;
|
||||
}
|
||||
|
||||
// Render the revision number
|
||||
if (ITOP_REVISION == '$WCREV$')
|
||||
if (ITOP_REVISION == 'svn')
|
||||
{
|
||||
// This is NOT a version built using the buil system, just display the main version
|
||||
$sVersionString = Dict::Format('UI:iTopVersion:Short', ITOP_APPLICATION, ITOP_VERSION);
|
||||
@@ -1158,7 +1197,7 @@ EOF;
|
||||
}
|
||||
|
||||
// Render the text of the global search form
|
||||
$sText = htmlentities(utils::ReadParam('text', '', false, 'raw_data'), ENT_QUOTES, 'UTF-8');
|
||||
$sText = htmlentities(utils::ReadParam('text', '', false, 'raw_data'), ENT_QUOTES, self::PAGES_CHARSET);
|
||||
$sOnClick = " onclick=\"if ($('#global-search-input').val() != '') { $('#global-search form').submit(); } \"";
|
||||
$sDefaultPlaceHolder = Dict::S("UI:YourSearch");
|
||||
|
||||
@@ -1182,7 +1221,7 @@ EOF;
|
||||
{
|
||||
$sLogonMessage = Dict::Format('UI:LoggedAsMessage', $sUserName);
|
||||
}
|
||||
$sLogOffMenu = "<span id=\"logOffBtn\"><ul><li><img src=\"../images/on-off-menu.png\"><ul>";
|
||||
$sLogOffMenu = "<span id=\"logOffBtn\"><ul><li><i class=\"top-right-icon icon-additional-arrow fas fa-power-off\"></i><ul>";
|
||||
$sLogOffMenu .= "<li><span>$sLogonMessage</span></li>\n";
|
||||
$aActions = array();
|
||||
|
||||
@@ -1213,7 +1252,7 @@ EOF;
|
||||
$oExitArchive = new JSPopupMenuItem('UI:ArchiveModeOff', Dict::S('UI:ArchiveModeOff'), 'return ArchiveMode(false);');
|
||||
$aActions[$oExitArchive->GetUID()] = $oExitArchive->GetMenuItem();
|
||||
|
||||
$sIcon = '<span class="fa fa-lock fa-1x"></span>';
|
||||
$sIcon = '<span class="fas fa-lock fa-1x"></span>';
|
||||
$this->AddApplicationMessage(Dict::S('UI:ArchiveMode:Banner'), $sIcon, Dict::S('UI:ArchiveMode:Banner+'));
|
||||
}
|
||||
elseif (UserRights::CanBrowseArchive())
|
||||
@@ -1259,8 +1298,8 @@ EOF;
|
||||
$sIcon =
|
||||
<<<EOF
|
||||
<span class="fa-stack fa-sm">
|
||||
<i class="fa fa-pencil fa-flip-horizontal fa-stack-1x"></i>
|
||||
<i class="fa fa-ban fa-stack-2x text-danger"></i>
|
||||
<i class="fas fa-pencil-alt fa-flip-horizontal fa-stack-1x"></i>
|
||||
<i class="fas fa-ban fa-stack-2x text-danger"></i>
|
||||
</span>
|
||||
EOF;
|
||||
|
||||
@@ -1277,7 +1316,7 @@ EOF;
|
||||
{
|
||||
$sHtmlIcon = $aMessage['icon'] ? $aMessage['icon'] : '';
|
||||
$sHtmlMessage = $aMessage['message'];
|
||||
$sTitleAttr = $aMessage['tip'] ? 'title="'.htmlentities($aMessage['tip'], ENT_QUOTES, 'UTF-8').'"' : '';
|
||||
$sTitleAttr = $aMessage['tip'] ? 'title="'.htmlentities($aMessage['tip'], ENT_QUOTES, self::PAGES_CHARSET).'"' : '';
|
||||
$sApplicationMessages .= '<div class="app-message" '.$sTitleAttr.'><span class="app-message-icon">'.$sHtmlIcon.'</span><span class="app-message-body">'.$sHtmlMessage.'</div></span>';
|
||||
}
|
||||
|
||||
@@ -1308,9 +1347,11 @@ EOF;
|
||||
$sHtml .= '<!-- Beginning of the left pane -->';
|
||||
$sHtml .= ' <div class="ui-layout-north">';
|
||||
$sHtml .= ' <div id="header-logo">';
|
||||
$sHtml .= ' <div id="top-left"></div><div id="logo"><a href="'.htmlentities($sIconUrl, ENT_QUOTES,
|
||||
'UTF-8').'"><img src="'.$sDisplayIcon.'" title="'.htmlentities($sVersionString, ENT_QUOTES,
|
||||
'UTF-8').'" style="border:0; margin-top:16px; margin-right:40px;"/></a></div>';
|
||||
$sHtml .= ' <div id="top-left"></div><div id="logo"><a href="'
|
||||
.htmlentities($sIconUrl, ENT_QUOTES, self::PAGES_CHARSET)
|
||||
.'"><img src="'.$sDisplayIcon.'" title="'
|
||||
.htmlentities($sVersionString, ENT_QUOTES, self::PAGES_CHARSET)
|
||||
.'" style="border:0; margin-top:16px; margin-right:40px;"/></a></div>';
|
||||
$sHtml .= ' </div>';
|
||||
$sHtml .= ' <div class="header-menu">';
|
||||
if (!MetaModel::GetConfig()->Get('demo_mode'))
|
||||
@@ -1342,10 +1383,10 @@ EOF;
|
||||
$sHtml .= ' <table id="top-bar-table">';
|
||||
$sHtml .= ' <tr>';
|
||||
$sHtml .= ' <td id="open-left-pane" class="menu-pane-exclusive" style="'.$GoHomeInitialStyle.'" onclick="$(\'body\').layout().open(\'west\');">';
|
||||
$sHtml .= ' <img src="../images/menu.png">';
|
||||
$sHtml .= ' <i class="fas fa-bars"></i>';
|
||||
$sHtml .= ' </td>';
|
||||
$sHtml .= ' <td id="go-home" class="menu-pane-exclusive" style="'.$GoHomeInitialStyle.'">';
|
||||
$sHtml .= ' <a href="'.utils::GetAbsoluteUrlAppRoot().'pages/UI.php"><img src="../images/home.png"></a>';
|
||||
$sHtml .= ' <a href="'.utils::GetAbsoluteUrlAppRoot().'pages/UI.php"><i class="fas fa-home"></i></a>';
|
||||
$sHtml .= ' </td>';
|
||||
$sHtml .= ' <td class="top-bar-spacer menu-pane-exclusive" style="'.$GoHomeInitialStyle.'">';
|
||||
$sHtml .= ' </td>';
|
||||
@@ -1355,8 +1396,8 @@ EOF;
|
||||
$sHtml .= ' <td id="top-bar-table-search">';
|
||||
$sHtml .= ' <div id="global-search"><form action="'.utils::GetAbsoluteUrlAppRoot().'pages/UI.php">';
|
||||
$sHtml .= ' <table id="top-left-buttons-area"><tr>';
|
||||
$sHtml .= ' <td id="top-left-global-search-cell"><div id="global-search-area"><input id="global-search-input" type="text" name="text" placeholder="'.$sDefaultPlaceHolder.'" value="'.$sText.'"></input><div '.$sOnClick.' id="global-search-image"><input type="hidden" name="operation" value="full_text"/></div></div></td>';
|
||||
$sHtml .= ' <td id="top-left-help-cell"><a id="help-link" href="'.$sOnlineHelpUrl.'" target="_blank"><img title="'.Dict::S('UI:Help').'" src="../images/help.png?t='.utils::GetCacheBusterTimestamp().'"/></td>';
|
||||
$sHtml .= ' <td id="top-left-global-search-cell"><div id="global-search-area"><input id="global-search-input" type="text" name="text" placeholder="'.$sDefaultPlaceHolder.'" value="'.$sText.'"></input><div '.$sOnClick.' id="global-search-image"><i class="top-right-icon fa-flip-horizontal fas fa-search"></i><input type="hidden" name="operation" value="full_text"/></div></div></td>';
|
||||
$sHtml .= ' <td id="top-left-help-cell"><a id="help-link" href="'.$sOnlineHelpUrl.'" target="_blank" title="'.Dict::S('UI:Help').'"><i class="top-right-icon fas fa-question-circle"></i></a></td>';
|
||||
$sHtml .= ' <td id="top-left-newsroom-cell">'.$sNewsRoomInitialImage.'</td>';
|
||||
$sHtml .= ' <td id="top-left-logoff-cell">'.self::FilterXSS($sLogOffMenu).'</td>';
|
||||
$sHtml .= ' </tr></table></form></div>';
|
||||
@@ -1411,9 +1452,12 @@ EOF;
|
||||
{
|
||||
if ($this->GetOutputFormat() == 'pdf' && $this->IsOutputFormatAvailable('pdf'))
|
||||
{
|
||||
// Note: Apparently this was a demand from ITOMIG a while back, so it's not "dead code" per say.
|
||||
// The last trace we got is in R-007989. Do not remove this without checking before with the concerned parties if it is still used!
|
||||
if (@is_readable(APPROOT.'lib/MPDF/mpdf.php'))
|
||||
{
|
||||
require_once(APPROOT.'lib/MPDF/mpdf.php');
|
||||
/** @noinspection PhpUndefinedClassInspection Check above comment */
|
||||
$oMPDF = new mPDF('c');
|
||||
$oMPDF->mirroMargins = false;
|
||||
if ($this->a_base['href'] != '')
|
||||
@@ -1441,90 +1485,67 @@ EOF;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds init scripts for the collapsible sections
|
||||
* @inheritDoc
|
||||
* @throws \Exception
|
||||
*/
|
||||
private function outputCollapsibleSectionInit()
|
||||
{
|
||||
if (!$this->bHasCollapsibleSection)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
$this->add_script(<<<'EOD'
|
||||
function initCollapsibleSection(iSectionId, bOpenedByDefault, sSectionStateStorageKey)
|
||||
{
|
||||
var bStoredSectionState = JSON.parse(localStorage.getItem(sSectionStateStorageKey));
|
||||
var bIsSectionOpenedInitially = (bStoredSectionState == null) ? bOpenedByDefault : bStoredSectionState;
|
||||
|
||||
if (bIsSectionOpenedInitially) {
|
||||
$("#LnkCollapse_"+iSectionId).toggleClass("open");
|
||||
$("#Collapse_"+iSectionId).toggle();
|
||||
}
|
||||
|
||||
$("#LnkCollapse_"+iSectionId).click(function(e) {
|
||||
localStorage.setItem(sSectionStateStorageKey, !($("#Collapse_"+iSectionId).is(":visible")));
|
||||
$("#LnkCollapse_"+iSectionId).toggleClass("open");
|
||||
$("#Collapse_"+iSectionId).slideToggle("normal");
|
||||
e.preventDefault(); // we don't want to do anything more (see #1030 : a non wanted tab switching was triggered)
|
||||
});
|
||||
}
|
||||
EOD
|
||||
);
|
||||
}
|
||||
|
||||
public function AddTabContainer($sTabContainer, $sPrefix = '')
|
||||
{
|
||||
$this->add($this->m_oTabs->AddTabContainer($sTabContainer, $sPrefix));
|
||||
}
|
||||
|
||||
public function AddToTab($sTabContainer, $sTabLabel, $sHtml)
|
||||
/**
|
||||
* @inheritDoc
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function AddToTab($sTabContainer, $sTabCode, $sHtml)
|
||||
{
|
||||
$this->add($this->m_oTabs->AddToTab($sTabContainer, $sTabLabel, $sHtml));
|
||||
$this->add($this->m_oTabs->AddToTab($sTabContainer, $sTabCode, $sHtml));
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function SetCurrentTabContainer($sTabContainer = '')
|
||||
{
|
||||
return $this->m_oTabs->SetCurrentTabContainer($sTabContainer);
|
||||
}
|
||||
|
||||
public function SetCurrentTab($sTabLabel = '')
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function SetCurrentTab($sTabCode = '', $sTabTitle = null)
|
||||
{
|
||||
return $this->m_oTabs->SetCurrentTab($sTabLabel);
|
||||
return $this->m_oTabs->SetCurrentTab($sTabCode, $sTabTitle);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a tab which content will be loaded asynchronously via the supplied URL
|
||||
*
|
||||
* Limitations:
|
||||
* Cross site scripting is not not allowed for security reasons. Use a normal tab with an IFRAME if you want to pull content from
|
||||
* another server. Static content cannot be added inside such tabs.
|
||||
*
|
||||
* @param string $sTabLabel The (localised) label of the tab
|
||||
* @param string $sUrl The URL to load (on the same server)
|
||||
* @param boolean $bCache Whether or not to cache the content of the tab once it has been loaded. flase will cause the tab to be
|
||||
* reloaded upon each activation.
|
||||
*
|
||||
* @inheritDoc
|
||||
* @throws \Exception
|
||||
* @since 2.0.3
|
||||
*/
|
||||
public function AddAjaxTab($sTabLabel, $sUrl, $bCache = true)
|
||||
public function AddAjaxTab($sTabCode, $sUrl, $bCache = true, $sTabTitle = null)
|
||||
{
|
||||
$this->add($this->m_oTabs->AddAjaxTab($sTabLabel, $sUrl, $bCache));
|
||||
$this->add($this->m_oTabs->AddAjaxTab($sTabCode, $sUrl, $bCache, $sTabTitle));
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function GetCurrentTab()
|
||||
{
|
||||
return $this->m_oTabs->GetCurrentTab();
|
||||
}
|
||||
|
||||
public function RemoveTab($sTabLabel, $sTabContainer = null)
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function RemoveTab($sTabCode, $sTabContainer = null)
|
||||
{
|
||||
$this->m_oTabs->RemoveTab($sTabLabel, $sTabContainer);
|
||||
$this->m_oTabs->RemoveTab($sTabCode, $sTabContainer);
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds the tab whose title matches a given pattern
|
||||
*
|
||||
* @return mixed The name of the tab as a string or false if not found
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function FindTab($sPattern, $sTabContainer = null)
|
||||
{
|
||||
@@ -1536,49 +1557,19 @@ EOD
|
||||
* DOES NOT WORK: apparently in the *old* version of jquery
|
||||
* that we are using this is not supported... TO DO upgrade
|
||||
* the whole jquery bundle...
|
||||
*
|
||||
* @param string $sTabContainer
|
||||
* @param string $sTabCode
|
||||
*/
|
||||
public function SelectTab($sTabContainer, $sTabLabel)
|
||||
public function SelectTab($sTabContainer, $sTabCode)
|
||||
{
|
||||
$this->add_ready_script($this->m_oTabs->SelectTab($sTabContainer, $sTabLabel));
|
||||
}
|
||||
|
||||
public function StartCollapsibleSection(
|
||||
$sSectionLabel, $bOpenedByDefault = false, $sSectionStateStorageBusinessKey = ''
|
||||
) {
|
||||
$this->add($this->GetStartCollapsibleSection($sSectionLabel, $bOpenedByDefault,
|
||||
$sSectionStateStorageBusinessKey));
|
||||
}
|
||||
|
||||
private function GetStartCollapsibleSection(
|
||||
$sSectionLabel, $bOpenedByDefault = false, $sSectionStateStorageBusinessKey = ''
|
||||
) {
|
||||
$this->bHasCollapsibleSection = true;
|
||||
$sHtml = '';
|
||||
static $iSectionId = 0;
|
||||
$sHtml .= '<a id="LnkCollapse_'.$iSectionId.'" class="CollapsibleLabel" href="#">'.$sSectionLabel.'</a></br>'."\n";
|
||||
$sHtml .= '<div id="Collapse_'.$iSectionId.'" style="display:none">'."\n";
|
||||
|
||||
$oConfig = MetaModel::GetConfig();
|
||||
$sSectionStateStorageKey = $oConfig->GetItopInstanceid().'/'.$sSectionStateStorageBusinessKey.'/collapsible-'.$iSectionId;
|
||||
$sSectionStateStorageKey = json_encode($sSectionStateStorageKey);
|
||||
$sOpenedByDefault = ($bOpenedByDefault) ? 'true' : 'false';
|
||||
$this->add_ready_script("initCollapsibleSection($iSectionId, $sOpenedByDefault, '$sSectionStateStorageKey');");
|
||||
|
||||
$iSectionId++;
|
||||
|
||||
return $sHtml;
|
||||
}
|
||||
|
||||
public function EndCollapsibleSection()
|
||||
{
|
||||
$this->add($this->GetEndCollapsibleSection());
|
||||
}
|
||||
|
||||
public function GetEndCollapsibleSection()
|
||||
{
|
||||
return "</div>";
|
||||
$this->add_ready_script($this->m_oTabs->SelectTab($sTabContainer, $sTabCode));
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function add($sHtml)
|
||||
{
|
||||
if (($this->m_oTabs->GetCurrentTabContainer() != '') && ($this->m_oTabs->GetCurrentTab() != ''))
|
||||
@@ -1592,9 +1583,7 @@ EOD
|
||||
}
|
||||
|
||||
/**
|
||||
* Records the current state of the 'html' part of the page output
|
||||
*
|
||||
* @return mixed The current state of the 'html' output
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function start_capture()
|
||||
{
|
||||
@@ -1614,12 +1603,7 @@ EOD
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the part of the html output that occurred since the call to start_capture
|
||||
* and removes this part from the current html output
|
||||
*
|
||||
* @param $offset mixed The value returned by start_capture
|
||||
*
|
||||
* @return string The part of the html output that was added since the call to start_capture
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function end_capture($offset)
|
||||
{
|
||||
@@ -1644,15 +1628,21 @@ EOD
|
||||
|
||||
/**
|
||||
* Set the message to be displayed in the 'app-banner' section at the top of the page
|
||||
*
|
||||
* @param string $sHtmlMessage
|
||||
*/
|
||||
public function SetMessage($sHtmlMessage)
|
||||
{
|
||||
$sHtmlIcon = '<span class="fa fa-comment fa-1x"></span>';
|
||||
$sHtmlIcon = '<span class="fas fa-comment fa-1x"></span>';
|
||||
$this->AddApplicationMessage($sHtmlMessage, $sHtmlIcon);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add message to be displayed in the 'app-banner' section at the top of the page
|
||||
*
|
||||
* @param string $sHtmlMessage
|
||||
* @param string|null $sHtmlIcon
|
||||
* @param string|null $sTip
|
||||
*/
|
||||
public function AddApplicationMessage($sHtmlMessage, $sHtmlIcon = null, $sTip = null)
|
||||
{
|
||||
@@ -1673,7 +1663,8 @@ EOD
|
||||
* @param string $sContent
|
||||
* @param string $sCssClasses CSS classes to add to the container
|
||||
*
|
||||
* @since 2.6
|
||||
* @throws \Exception
|
||||
* @since 2.6.0
|
||||
*/
|
||||
public function AddHeaderMessage($sContent, $sCssClasses = 'message_info')
|
||||
{
|
||||
@@ -1686,6 +1677,8 @@ EOF
|
||||
/**
|
||||
* Adds a script to be executed when the DOM is ready (typical JQuery use), right before add_ready_script
|
||||
*
|
||||
* @param string $sScript
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function add_init_script($sScript)
|
||||
|
||||
138
application/loginbasic.class.inc.php
Normal file
138
application/loginbasic.class.inc.php
Normal file
@@ -0,0 +1,138 @@
|
||||
<?php
|
||||
/**
|
||||
* Class LoginBasic
|
||||
*
|
||||
* @copyright Copyright (C) 2010-2019 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
class LoginBasic extends AbstractLoginFSMExtension
|
||||
{
|
||||
/**
|
||||
* Return the list of supported login modes for this plugin
|
||||
*
|
||||
* @return array of supported login modes
|
||||
*/
|
||||
public function ListSupportedLoginModes()
|
||||
{
|
||||
return array('basic');
|
||||
}
|
||||
|
||||
protected function OnModeDetection(&$iErrorCode)
|
||||
{
|
||||
if (!isset($_SESSION['login_mode']))
|
||||
{
|
||||
if (isset($_SERVER['HTTP_AUTHORIZATION']) && !empty($_SERVER['HTTP_AUTHORIZATION']))
|
||||
{
|
||||
$_SESSION['login_mode'] = 'basic';
|
||||
}
|
||||
elseif (isset($_SERVER['REDIRECT_HTTP_AUTHORIZATION']) && !empty($_SERVER['REDIRECT_HTTP_AUTHORIZATION']))
|
||||
{
|
||||
$_SESSION['login_mode'] = 'basic';
|
||||
}
|
||||
elseif (isset($_SERVER['PHP_AUTH_USER']))
|
||||
{
|
||||
$_SESSION['login_mode'] = 'basic';
|
||||
}
|
||||
}
|
||||
return LoginWebPage::LOGIN_FSM_CONTINUE;
|
||||
}
|
||||
|
||||
protected function OnReadCredentials(&$iErrorCode)
|
||||
{
|
||||
if (!isset($_SESSION['login_mode']) || $_SESSION['login_mode'] == 'basic')
|
||||
{
|
||||
list($sAuthUser, $sAuthPwd) = $this->GetAuthUserAndPassword();
|
||||
$_SESSION['login_temp_auth_user'] = $sAuthUser;
|
||||
}
|
||||
return LoginWebPage::LOGIN_FSM_CONTINUE;
|
||||
}
|
||||
|
||||
|
||||
protected function OnCheckCredentials(&$iErrorCode)
|
||||
{
|
||||
if ($_SESSION['login_mode'] == 'basic')
|
||||
{
|
||||
list($sAuthUser, $sAuthPwd) = $this->GetAuthUserAndPassword();
|
||||
if (!UserRights::CheckCredentials($sAuthUser, $sAuthPwd, $_SESSION['login_mode'], 'internal'))
|
||||
{
|
||||
$iErrorCode = LoginWebPage::EXIT_CODE_WRONGCREDENTIALS;
|
||||
return LoginWebPage::LOGIN_FSM_ERROR;
|
||||
}
|
||||
}
|
||||
return LoginWebPage::LOGIN_FSM_CONTINUE;
|
||||
}
|
||||
|
||||
protected function OnCredentialsOK(&$iErrorCode)
|
||||
{
|
||||
if ($_SESSION['login_mode'] == 'basic')
|
||||
{
|
||||
list($sAuthUser) = $this->GetAuthUserAndPassword();
|
||||
LoginWebPage::OnLoginSuccess($sAuthUser, 'internal', $_SESSION['login_mode']);
|
||||
}
|
||||
return LoginWebPage::LOGIN_FSM_CONTINUE;
|
||||
}
|
||||
|
||||
protected function OnError(&$iErrorCode)
|
||||
{
|
||||
if ($_SESSION['login_mode'] == 'basic')
|
||||
{
|
||||
LoginWebPage::HTTP401Error();
|
||||
}
|
||||
return LoginWebPage::LOGIN_FSM_CONTINUE;
|
||||
}
|
||||
|
||||
protected function OnConnected(&$iErrorCode)
|
||||
{
|
||||
if ($_SESSION['login_mode'] == 'basic')
|
||||
{
|
||||
$_SESSION['can_logoff'] = true;
|
||||
return LoginWebPage::CheckLoggedUser($iErrorCode);
|
||||
}
|
||||
return LoginWebPage::LOGIN_FSM_CONTINUE;
|
||||
}
|
||||
|
||||
private function GetAuthUserAndPassword()
|
||||
{
|
||||
$sAuthUser = '';
|
||||
$sAuthPwd = null;
|
||||
$sAuthorization = '';
|
||||
if (isset($_SERVER['HTTP_AUTHORIZATION']) && !empty($_SERVER['HTTP_AUTHORIZATION']))
|
||||
{
|
||||
$sAuthorization = $_SERVER['HTTP_AUTHORIZATION'];
|
||||
}
|
||||
elseif (isset($_SERVER['REDIRECT_HTTP_AUTHORIZATION']) && !empty($_SERVER['REDIRECT_HTTP_AUTHORIZATION']))
|
||||
{
|
||||
$sAuthorization = $_SERVER['REDIRECT_HTTP_AUTHORIZATION'];
|
||||
}
|
||||
|
||||
if (!empty($sAuthorization))
|
||||
{
|
||||
list($sAuthUser, $sAuthPwd) = explode(':', base64_decode(substr($sAuthorization, 6)));
|
||||
}
|
||||
else
|
||||
{
|
||||
if (isset($_SERVER['PHP_AUTH_USER']))
|
||||
{
|
||||
$sAuthUser = $_SERVER['PHP_AUTH_USER'];
|
||||
// Unfortunately, the RFC is not clear about the encoding...
|
||||
// IE and FF supply the user and password encoded in ISO-8859-1 whereas Chrome provides them encoded in UTF-8
|
||||
// So let's try to guess if it's an UTF-8 string or not... fortunately all encodings share the same ASCII base
|
||||
if (!LoginWebPage::LooksLikeUTF8($sAuthUser))
|
||||
{
|
||||
// Does not look like and UTF-8 string, try to convert it from iso-8859-1 to UTF-8
|
||||
// Supposed to be harmless in case of a plain ASCII string...
|
||||
$sAuthUser = iconv('iso-8859-1', 'utf-8', $sAuthUser);
|
||||
}
|
||||
$sAuthPwd = $_SERVER['PHP_AUTH_PW'];
|
||||
if (!LoginWebPage::LooksLikeUTF8($sAuthPwd))
|
||||
{
|
||||
// Does not look like and UTF-8 string, try to convert it from iso-8859-1 to UTF-8
|
||||
// Supposed to be harmless in case of a plain ASCII string...
|
||||
$sAuthPwd = iconv('iso-8859-1', 'utf-8', $sAuthPwd);
|
||||
}
|
||||
}
|
||||
}
|
||||
return array($sAuthUser, $sAuthPwd);
|
||||
}
|
||||
}
|
||||
129
application/logindefault.class.inc.php
Normal file
129
application/logindefault.class.inc.php
Normal file
@@ -0,0 +1,129 @@
|
||||
<?php
|
||||
/**
|
||||
* @copyright Copyright (C) 2010-2019 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* Class LoginDefaultBefore
|
||||
*/
|
||||
class LoginDefaultBefore extends AbstractLoginFSMExtension
|
||||
{
|
||||
/**
|
||||
* Must be executed before the other login plugins
|
||||
*
|
||||
* @return array of supported login modes
|
||||
*/
|
||||
public function ListSupportedLoginModes()
|
||||
{
|
||||
return array('before');
|
||||
}
|
||||
|
||||
protected function OnStart(&$iErrorCode)
|
||||
{
|
||||
$iErrorCode = LoginWebPage::EXIT_CODE_OK;
|
||||
|
||||
unset($_SESSION['login_temp_auth_user']);
|
||||
|
||||
// Check if proposed login mode is present and allowed
|
||||
$aAllowedLoginTypes = MetaModel::GetConfig()->GetAllowedLoginTypes();
|
||||
$sProposedLoginMode = utils::ReadParam('login_mode', '');
|
||||
$index = array_search($sProposedLoginMode, $aAllowedLoginTypes);
|
||||
if ($index !== false)
|
||||
{
|
||||
// Force login mode
|
||||
$_SESSION['login_mode'] = $sProposedLoginMode;
|
||||
}
|
||||
else
|
||||
{
|
||||
unset($_SESSION['login_mode']);
|
||||
}
|
||||
return LoginWebPage::LOGIN_FSM_CONTINUE;
|
||||
}
|
||||
|
||||
protected function OnReadCredentials(&$iErrorCode)
|
||||
{
|
||||
// Check if proposed login mode is present and allowed
|
||||
$aAllowedLoginTypes = MetaModel::GetConfig()->GetAllowedLoginTypes();
|
||||
$sProposedLoginMode = utils::ReadParam('login_mode', '');
|
||||
$index = array_search($sProposedLoginMode, $aAllowedLoginTypes);
|
||||
if ($index !== false)
|
||||
{
|
||||
// Force login mode
|
||||
LoginWebPage::SetLoginModeAndReload($sProposedLoginMode);
|
||||
}
|
||||
return LoginWebPage::LOGIN_FSM_CONTINUE;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Class LoginDefaultAfter
|
||||
*/
|
||||
class LoginDefaultAfter extends AbstractLoginFSMExtension implements iLogoutExtension
|
||||
{
|
||||
|
||||
|
||||
/**
|
||||
* Must be executed after the other login plugins
|
||||
*
|
||||
* @return array of supported login modes
|
||||
*/
|
||||
public function ListSupportedLoginModes()
|
||||
{
|
||||
return array('after');
|
||||
}
|
||||
|
||||
protected function OnError(&$iErrorCode)
|
||||
{
|
||||
self::ResetLoginSession();
|
||||
$iOnExit = LoginWebPage::getIOnExit();
|
||||
if ($iOnExit == LoginWebPage::EXIT_RETURN)
|
||||
{
|
||||
return LoginWebPage::LOGIN_FSM_RETURN; // Error, exit FSM
|
||||
}
|
||||
elseif ($iOnExit == LoginWebPage::EXIT_HTTP_401)
|
||||
{
|
||||
LoginWebPage::HTTP401Error(); // Error, exit
|
||||
}
|
||||
// LoginWebPage::EXIT_PROMPT
|
||||
return LoginWebPage::LOGIN_FSM_CONTINUE;
|
||||
}
|
||||
|
||||
protected function OnCredentialsOk(&$iErrorCode)
|
||||
{
|
||||
if (!isset($_SESSION['login_mode']))
|
||||
{
|
||||
// If no plugin validated the user, exit
|
||||
self::ResetLoginSession();
|
||||
exit();
|
||||
}
|
||||
return LoginWebPage::LOGIN_FSM_CONTINUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute all actions to log out properly
|
||||
*/
|
||||
public function LogoutAction()
|
||||
{
|
||||
self::ResetLoginSession();
|
||||
}
|
||||
|
||||
protected function OnConnected(&$iErrorCode)
|
||||
{
|
||||
unset($_SESSION['login_temp_auth_user']);
|
||||
return LoginWebPage::LOGIN_FSM_CONTINUE;
|
||||
}
|
||||
|
||||
// Hard reset of the session
|
||||
private static function ResetLoginSession()
|
||||
{
|
||||
LoginWebPage::ResetSession();
|
||||
foreach (array_keys($_SESSION) as $sKey)
|
||||
{
|
||||
if (utils::StartsWith($sKey, 'login_'))
|
||||
{
|
||||
unset($_SESSION[$sKey]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
89
application/loginexternal.class.inc.php
Normal file
89
application/loginexternal.class.inc.php
Normal file
@@ -0,0 +1,89 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Class LoginExternal
|
||||
*
|
||||
* @copyright Copyright (C) 2010-2019 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
class LoginExternal extends AbstractLoginFSMExtension
|
||||
{
|
||||
|
||||
/**
|
||||
* Return the list of supported login modes for this plugin
|
||||
*
|
||||
* @return array of supported login modes
|
||||
*/
|
||||
public function ListSupportedLoginModes()
|
||||
{
|
||||
return array('external');
|
||||
}
|
||||
|
||||
protected function OnModeDetection(&$iErrorCode)
|
||||
{
|
||||
if (!isset($_SESSION['login_mode']))
|
||||
{
|
||||
$sAuthUser = $this->GetAuthUser();
|
||||
if ($sAuthUser && (strlen($sAuthUser) > 0))
|
||||
{
|
||||
$_SESSION['login_mode'] = 'external';
|
||||
}
|
||||
}
|
||||
return LoginWebPage::LOGIN_FSM_CONTINUE;
|
||||
}
|
||||
|
||||
protected function OnCheckCredentials(&$iErrorCode)
|
||||
{
|
||||
if ($_SESSION['login_mode'] == 'external')
|
||||
{
|
||||
$sAuthUser = $this->GetAuthUser();
|
||||
if (!UserRights::CheckCredentials($sAuthUser, '', $_SESSION['login_mode'], 'external'))
|
||||
{
|
||||
$iErrorCode = LoginWebPage::EXIT_CODE_WRONGCREDENTIALS;
|
||||
return LoginWebPage::LOGIN_FSM_ERROR;
|
||||
}
|
||||
}
|
||||
return LoginWebPage::LOGIN_FSM_CONTINUE;
|
||||
}
|
||||
|
||||
protected function OnCredentialsOK(&$iErrorCode)
|
||||
{
|
||||
if ($_SESSION['login_mode'] == 'external')
|
||||
{
|
||||
$sAuthUser = $this->GetAuthUser();
|
||||
LoginWebPage::OnLoginSuccess($sAuthUser, 'external', $_SESSION['login_mode']);
|
||||
}
|
||||
return LoginWebPage::LOGIN_FSM_CONTINUE;
|
||||
}
|
||||
|
||||
protected function OnConnected(&$iErrorCode)
|
||||
{
|
||||
if ($_SESSION['login_mode'] == 'external')
|
||||
{
|
||||
$_SESSION['can_logoff'] = false;
|
||||
return LoginWebPage::CheckLoggedUser($iErrorCode);
|
||||
}
|
||||
return LoginWebPage::LOGIN_FSM_CONTINUE;
|
||||
}
|
||||
|
||||
protected function OnError(&$iErrorCode)
|
||||
{
|
||||
if ($_SESSION['login_mode'] == 'external')
|
||||
{
|
||||
LoginWebPage::HTTP401Error();
|
||||
}
|
||||
return LoginWebPage::LOGIN_FSM_CONTINUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
private function GetAuthUser()
|
||||
{
|
||||
$sExtAuthVar = MetaModel::GetConfig()->GetExternalAuthenticationVariable(); // In which variable is the info passed ?
|
||||
eval('$sAuthUser = isset('.$sExtAuthVar.') ? '.$sExtAuthVar.' : false;'); // Retrieve the value
|
||||
/** @var string $sAuthUser */
|
||||
return $sAuthUser; // Retrieve the value
|
||||
}
|
||||
}
|
||||
156
application/loginform.class.inc.php
Normal file
156
application/loginform.class.inc.php
Normal file
@@ -0,0 +1,156 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @copyright Copyright (C) 2010-2019 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* Class LoginForm
|
||||
*
|
||||
* @since 2.7.0
|
||||
*/
|
||||
class LoginForm extends AbstractLoginFSMExtension implements iLoginUIExtension
|
||||
{
|
||||
private $bForceFormOnError = false;
|
||||
|
||||
/**
|
||||
* Return the list of supported login modes for this plugin
|
||||
*
|
||||
* @return array of supported login modes
|
||||
*/
|
||||
public function ListSupportedLoginModes()
|
||||
{
|
||||
return array('form');
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
protected function OnReadCredentials(&$iErrorCode)
|
||||
{
|
||||
if (!isset($_SESSION['login_mode']) || ($_SESSION['login_mode'] == 'form'))
|
||||
{
|
||||
$sAuthUser = utils::ReadPostedParam('auth_user', '', 'raw_data');
|
||||
$sAuthPwd = utils::ReadPostedParam('auth_pwd', null, 'raw_data');
|
||||
if ($this->bForceFormOnError || empty($sAuthUser) || empty($sAuthPwd))
|
||||
{
|
||||
if (array_key_exists('HTTP_X_COMBODO_AJAX', $_SERVER))
|
||||
{
|
||||
// X-Combodo-Ajax is a special header automatically added to all ajax requests
|
||||
// Let's reply that we're currently logged-out
|
||||
header('HTTP/1.0 401 Unauthorized');
|
||||
exit;
|
||||
}
|
||||
|
||||
// No credentials yet, display the form
|
||||
$oPage = LoginWebPage::NewLoginWebPage();
|
||||
$oPage->DisplayLoginForm($this->bForceFormOnError);
|
||||
$oPage->output();
|
||||
$this->bForceFormOnError = false;
|
||||
exit;
|
||||
}
|
||||
|
||||
$_SESSION['login_temp_auth_user'] = $sAuthUser;
|
||||
$_SESSION['login_mode'] = 'form';
|
||||
}
|
||||
return LoginWebPage::LOGIN_FSM_CONTINUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
protected function OnCheckCredentials(&$iErrorCode)
|
||||
{
|
||||
if ($_SESSION['login_mode'] == 'form')
|
||||
{
|
||||
$sAuthUser = utils::ReadPostedParam('auth_user', '', 'raw_data');
|
||||
$sAuthPwd = utils::ReadPostedParam('auth_pwd', null, 'raw_data');
|
||||
if (!UserRights::CheckCredentials($sAuthUser, $sAuthPwd, $_SESSION['login_mode'], 'internal'))
|
||||
{
|
||||
$iErrorCode = LoginWebPage::EXIT_CODE_WRONGCREDENTIALS;
|
||||
return LoginWebPage::LOGIN_FSM_ERROR;
|
||||
}
|
||||
}
|
||||
return LoginWebPage::LOGIN_FSM_CONTINUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
protected function OnCredentialsOK(&$iErrorCode)
|
||||
{
|
||||
if ($_SESSION['login_mode'] == 'form')
|
||||
{
|
||||
if (isset($_SESSION['auth_user']))
|
||||
{
|
||||
// If FSM reenter this state (example 2FA) then the auth_user is not resubmitted
|
||||
$sAuthUser = $_SESSION['auth_user'];
|
||||
}
|
||||
else
|
||||
{
|
||||
$sAuthUser = utils::ReadPostedParam('auth_user', '', 'raw_data');
|
||||
}
|
||||
// Store 'auth_user' in session for further use
|
||||
LoginWebPage::OnLoginSuccess($sAuthUser, 'internal', $_SESSION['login_mode']);
|
||||
}
|
||||
return LoginWebPage::LOGIN_FSM_CONTINUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
protected function OnError(&$iErrorCode)
|
||||
{
|
||||
if ($_SESSION['login_mode'] == 'form')
|
||||
{
|
||||
$this->bForceFormOnError = true;
|
||||
}
|
||||
return LoginWebPage::LOGIN_FSM_CONTINUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
protected function OnConnected(&$iErrorCode)
|
||||
{
|
||||
if ($_SESSION['login_mode'] == 'form')
|
||||
{
|
||||
$_SESSION['can_logoff'] = true;
|
||||
return LoginWebPage::CheckLoggedUser($iErrorCode);
|
||||
}
|
||||
return LoginWebPage::LOGIN_FSM_CONTINUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function GetTwigContext()
|
||||
{
|
||||
$oLoginContext = new LoginTwigContext();
|
||||
$oLoginContext->AddPostedVar('auth_user');
|
||||
$oLoginContext->AddPostedVar('auth_pwd');
|
||||
|
||||
$sAuthUser = utils::ReadParam('auth_user', '', true, 'raw_data');
|
||||
$sAuthPwd = utils::ReadParam('suggest_pwd', '', true, 'raw_data');
|
||||
|
||||
$aData = array(
|
||||
'sAuthUser' => $sAuthUser,
|
||||
'sAuthPwd' => $sAuthPwd,
|
||||
);
|
||||
$oLoginContext->AddBlockExtension('login_input', new LoginBlockExtension('extensionblock/loginforminput.html.twig', $aData));
|
||||
$oLoginContext->AddBlockExtension('login_submit', new LoginBlockExtension('extensionblock/loginformsubmit.html.twig'));
|
||||
$oLoginContext->AddBlockExtension('login_form_footer', new LoginBlockExtension('extensionblock/loginformfooter.html.twig'));
|
||||
|
||||
$bEnableResetPassword = MetaModel::GetConfig()->Get('forgot_password');
|
||||
$sResetPasswordUrl = utils::GetAbsoluteUrlAppRoot() . 'pages/UI.php?loginop=forgot_pwd';
|
||||
$aData = array(
|
||||
'bEnableResetPassword' => $bEnableResetPassword,
|
||||
'sResetPasswordUrl' => $sResetPasswordUrl,
|
||||
);
|
||||
$oLoginContext->AddBlockExtension('login_links', new LoginBlockExtension('extensionblock/loginformlinks.html.twig', $aData));
|
||||
|
||||
return $oLoginContext;
|
||||
}
|
||||
}
|
||||
321
application/logintwig.class.inc.php
Normal file
321
application/logintwig.class.inc.php
Normal file
@@ -0,0 +1,321 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
*
|
||||
* @copyright Copyright (C) 2010-2019 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
|
||||
use Combodo\iTop\TwigExtension;
|
||||
|
||||
/**
|
||||
* Twig context for modules extending the login screen
|
||||
* Class LoginTwigContext
|
||||
*/
|
||||
class LoginTwigContext
|
||||
{
|
||||
/** @var array */
|
||||
private $aBlockExtension;
|
||||
/** @var array */
|
||||
private $aPostedVars;
|
||||
/** @var string */
|
||||
private $sTwigLoaderPath;
|
||||
/** @var array */
|
||||
private $aCSSFiles;
|
||||
/** @var array */
|
||||
private $aJsFiles;
|
||||
private $sTwigNameSpace;
|
||||
|
||||
/**
|
||||
* Build a context to display the twig files used
|
||||
* to extend the login screens
|
||||
*
|
||||
* LoginTwigContext constructor.
|
||||
* @api
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->aBlockExtension = array();
|
||||
$this->aPostedVars = array();
|
||||
$this->sTwigLoaderPath = null;
|
||||
$this->aCSSFiles = array();
|
||||
$this->aJsFiles = array();
|
||||
$this->sTwigNameSpace = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the absolute path on disk of the folder containing the twig templates
|
||||
*
|
||||
* @param string $sPath absolute path of twig templates directory
|
||||
* @api
|
||||
*/
|
||||
public function SetLoaderPath($sPath)
|
||||
{
|
||||
$this->sTwigLoaderPath = $sPath;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a Twig block extension
|
||||
*
|
||||
* @param string $sBlockName
|
||||
* @param LoginBlockExtension $oBlockExtension
|
||||
*/
|
||||
public function AddBlockExtension($sBlockName, $oBlockExtension)
|
||||
{
|
||||
$this->aBlockExtension[$sBlockName] = $oBlockExtension;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a variable intended to be posted on URL (and managed) by the module.
|
||||
* Declaring the posted variables will prevent the core engine to manipulate these variables.
|
||||
*
|
||||
* @param string $sPostedVar Name of the posted variable
|
||||
* @api
|
||||
*/
|
||||
public function AddPostedVar($sPostedVar)
|
||||
{
|
||||
$this->aPostedVars[] = $sPostedVar;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the URL of a CSS file to link to the login screen
|
||||
*
|
||||
* @param string $sFile URL of the CSS file to link
|
||||
* @api
|
||||
*/
|
||||
public function AddCSSFile($sFile)
|
||||
{
|
||||
$this->aCSSFiles[] = $sFile;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the URL of a javascript file to link to the login screen
|
||||
* @param string $sFile URL of the javascript file to link
|
||||
* @api
|
||||
*/
|
||||
public function AddJsFile($sFile)
|
||||
{
|
||||
$this->aJsFiles[] = $sFile;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $sBlockName
|
||||
*
|
||||
* @return \LoginBlockExtension
|
||||
*/
|
||||
public function GetBlockExtension($sBlockName)
|
||||
{
|
||||
/** @var LoginBlockExtension $oBlockExtension */
|
||||
$oBlockExtension = isset($this->aBlockExtension[$sBlockName]) ? $this->aBlockExtension[$sBlockName] : null;
|
||||
return $oBlockExtension;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function GetPostedVars()
|
||||
{
|
||||
return $this->aPostedVars;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function GetTwigLoaderPath()
|
||||
{
|
||||
return $this->sTwigLoaderPath;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function GetCSSFiles()
|
||||
{
|
||||
return $this->aCSSFiles;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function GetJsFiles()
|
||||
{
|
||||
return $this->aJsFiles;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Twig block description for login screen extension
|
||||
* The login screen can be extended by adding twig templates
|
||||
* to specific blocks of the login screens
|
||||
*
|
||||
* Class LoginBlockExtension
|
||||
*/
|
||||
class LoginBlockExtension
|
||||
{
|
||||
private $sTwig;
|
||||
private $aData;
|
||||
|
||||
/**
|
||||
* Create a new twig extension block
|
||||
* The given twig template can be HTML, CSS or JavaScript.
|
||||
* CSS goes to the block named 'css' and is inline in the page.
|
||||
* JavaScript goes to the blocks named 'script' or 'ready_script' and are inline in the page.
|
||||
* HTML goes to everywhere else
|
||||
*
|
||||
* LoginBlockExtension constructor.
|
||||
*
|
||||
* @param string $sTwig name of the twig file relative to the path given to the LoginTwigContext
|
||||
* @param array $aData Data given to the twig template (into the variable {{ aData }})
|
||||
* @api
|
||||
*/
|
||||
public function __construct($sTwig, $aData = array())
|
||||
{
|
||||
$this->sTwig = $sTwig;
|
||||
$this->aData = $aData;
|
||||
}
|
||||
|
||||
public function GetTwig()
|
||||
{
|
||||
return $this->sTwig;
|
||||
}
|
||||
|
||||
public function GetData()
|
||||
{
|
||||
return $this->aData;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Used by LoginWebPage to display the login screen
|
||||
* Class LoginTwigRenderer
|
||||
*/
|
||||
class LoginTwigRenderer
|
||||
{
|
||||
private $aLoginPluginList;
|
||||
private $aPluginFormData;
|
||||
private $aPostedVars;
|
||||
private $oTwig;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->aLoginPluginList = LoginWebPage::GetLoginPluginList('iLoginUIExtension', false);
|
||||
$this->aPluginFormData = array();
|
||||
$aTwigLoaders = array();
|
||||
$this->aPostedVars = array();
|
||||
foreach ($this->aLoginPluginList as $oLoginPlugin)
|
||||
{
|
||||
/** @var \iLoginUIExtension $oLoginPlugin */
|
||||
$oLoginContext = $oLoginPlugin->GetTwigContext();
|
||||
if (is_null($oLoginContext))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
$this->aPluginFormData[] = $oLoginContext;
|
||||
$sTwigLoaderPath = $oLoginContext->GetTwigLoaderPath();
|
||||
if ($sTwigLoaderPath != null)
|
||||
{
|
||||
$oExtensionLoader = new Twig_Loader_Filesystem();
|
||||
$oExtensionLoader->setPaths($sTwigLoaderPath);
|
||||
$aTwigLoaders[] = $oExtensionLoader;
|
||||
}
|
||||
$this->aPostedVars = array_merge($this->aPostedVars, $oLoginContext->GetPostedVars());
|
||||
}
|
||||
|
||||
$oCoreLoader = new Twig_Loader_Filesystem(array(), APPROOT.'templates');
|
||||
$aCoreTemplatesPaths = array('login', 'login/password');
|
||||
// Having this path declared after the plugins let the plugins replace the core templates
|
||||
$oCoreLoader->setPaths($aCoreTemplatesPaths);
|
||||
// Having the core templates accessible within a different namespace offer the possibility to extend them while replacing them
|
||||
$oCoreLoader->setPaths($aCoreTemplatesPaths, 'ItopCore');
|
||||
$aTwigLoaders[] = $oCoreLoader;
|
||||
|
||||
$oLoader = new Twig_Loader_Chain($aTwigLoaders);
|
||||
$this->oTwig = new Twig_Environment($oLoader);
|
||||
TwigExtension::RegisterTwigExtensions($this->oTwig);
|
||||
}
|
||||
|
||||
public function GetDefaultVars()
|
||||
{
|
||||
$sLogo = 'itop-logo-external.png';
|
||||
$sBrandingLogo = 'login-logo.png';
|
||||
|
||||
$sVersionShort = Dict::Format('UI:iTopVersion:Short', ITOP_APPLICATION, ITOP_VERSION);
|
||||
$sIconUrl = Utils::GetConfig()->Get('app_icon_url');
|
||||
$sDisplayIcon = utils::GetAbsoluteUrlAppRoot().'images/'.$sLogo.'?t='.utils::GetCacheBusterTimestamp();
|
||||
if (file_exists(MODULESROOT.'branding/'.$sBrandingLogo))
|
||||
{
|
||||
$sDisplayIcon = utils::GetAbsoluteUrlModulesRoot().'branding/'.$sBrandingLogo.'?t='.utils::GetCacheBusterTimestamp();
|
||||
}
|
||||
|
||||
$aVars = array(
|
||||
'sAppRootUrl' => utils::GetAbsoluteUrlAppRoot(),
|
||||
'aPluginFormData' => $this->GetPluginFormData(),
|
||||
'sItopVersion' => ITOP_VERSION,
|
||||
'sVersionShort' => $sVersionShort,
|
||||
'sIconUrl' => $sIconUrl,
|
||||
'sDisplayIcon' => $sDisplayIcon,
|
||||
);
|
||||
|
||||
return $aVars;
|
||||
}
|
||||
|
||||
public function Render(NiceWebPage $oPage, $sTwigFile, $aVars = array())
|
||||
{
|
||||
$oTemplate = $this->GetTwig()->load($sTwigFile);
|
||||
$oPage->add($oTemplate->renderBlock('body', $aVars));
|
||||
$oPage->add_script($oTemplate->renderBlock('script', $aVars));
|
||||
$oPage->add_ready_script($oTemplate->renderBlock('ready_script', $aVars));
|
||||
$oPage->add_style($oTemplate->renderBlock('css', $aVars));
|
||||
|
||||
// Render CSS links
|
||||
foreach ($this->aPluginFormData as $oFormData)
|
||||
{
|
||||
/** @var \LoginTwigContext $oFormData */
|
||||
$aCSSFiles = $oFormData->GetCSSFiles();
|
||||
foreach ($aCSSFiles as $sCSSFile)
|
||||
{
|
||||
$oPage->add_linked_stylesheet($sCSSFile);
|
||||
}
|
||||
$aJsFiles = $oFormData->GetJsFiles();
|
||||
foreach ($aJsFiles as $sJsFile)
|
||||
{
|
||||
$oPage->add_linked_script($sJsFile);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function GetLoginPluginList()
|
||||
{
|
||||
return $this->aLoginPluginList;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function GetPluginFormData()
|
||||
{
|
||||
return $this->aPluginFormData;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function GetPostedVars()
|
||||
{
|
||||
return $this->aPostedVars;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Twig_Environment
|
||||
*/
|
||||
public function GetTwig()
|
||||
{
|
||||
return $this->oTwig;
|
||||
}
|
||||
}
|
||||
93
application/loginurl.class.inc.php
Normal file
93
application/loginurl.class.inc.php
Normal file
@@ -0,0 +1,93 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Class LoginURL
|
||||
*
|
||||
* @copyright Copyright (C) 2010-2019 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
class LoginURL extends AbstractLoginFSMExtension
|
||||
{
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
private $bErrorOccurred = false;
|
||||
|
||||
/**
|
||||
* Return the list of supported login modes for this plugin
|
||||
*
|
||||
* @return array of supported login modes
|
||||
*/
|
||||
public function ListSupportedLoginModes()
|
||||
{
|
||||
return array('url');
|
||||
}
|
||||
|
||||
protected function OnModeDetection(&$iErrorCode)
|
||||
{
|
||||
if (!isset($_SESSION['login_mode']) && !$this->bErrorOccurred)
|
||||
{
|
||||
$sAuthUser = utils::ReadParam('auth_user', '', false, 'raw_data');
|
||||
$sAuthPwd = utils::ReadParam('auth_pwd', null, false, 'raw_data');
|
||||
if (!empty($sAuthUser) && !empty($sAuthPwd))
|
||||
{
|
||||
$_SESSION['login_mode'] = 'url';
|
||||
}
|
||||
}
|
||||
return LoginWebPage::LOGIN_FSM_CONTINUE;
|
||||
}
|
||||
|
||||
protected function OnReadCredentials(&$iErrorCode)
|
||||
{
|
||||
if ($_SESSION['login_mode'] == 'url')
|
||||
{
|
||||
$_SESSION['login_temp_auth_user'] = utils::ReadParam('auth_user', '', false, 'raw_data');
|
||||
}
|
||||
return LoginWebPage::LOGIN_FSM_CONTINUE;
|
||||
}
|
||||
|
||||
protected function OnCheckCredentials(&$iErrorCode)
|
||||
{
|
||||
if ($_SESSION['login_mode'] == 'url')
|
||||
{
|
||||
$sAuthUser = utils::ReadParam('auth_user', '', false, 'raw_data');
|
||||
$sAuthPwd = utils::ReadParam('auth_pwd', null, false, 'raw_data');
|
||||
if (!UserRights::CheckCredentials($sAuthUser, $sAuthPwd, $_SESSION['login_mode'], 'internal'))
|
||||
{
|
||||
$iErrorCode = LoginWebPage::EXIT_CODE_WRONGCREDENTIALS;
|
||||
return LoginWebPage::LOGIN_FSM_ERROR;
|
||||
}
|
||||
}
|
||||
return LoginWebPage::LOGIN_FSM_CONTINUE;
|
||||
}
|
||||
|
||||
protected function OnCredentialsOK(&$iErrorCode)
|
||||
{
|
||||
if ($_SESSION['login_mode'] == 'url')
|
||||
{
|
||||
$sAuthUser = utils::ReadParam('auth_user', '', false, 'raw_data');
|
||||
LoginWebPage::OnLoginSuccess($sAuthUser, 'internal', $_SESSION['login_mode']);
|
||||
}
|
||||
return LoginWebPage::LOGIN_FSM_CONTINUE;
|
||||
}
|
||||
|
||||
protected function OnError(&$iErrorCode)
|
||||
{
|
||||
if ($_SESSION['login_mode'] == 'url')
|
||||
{
|
||||
$this->bErrorOccurred = true;
|
||||
}
|
||||
return LoginWebPage::LOGIN_FSM_CONTINUE;
|
||||
}
|
||||
|
||||
protected function OnConnected(&$iErrorCode)
|
||||
{
|
||||
if ($_SESSION['login_mode'] == 'url')
|
||||
{
|
||||
$_SESSION['can_logoff'] = true;
|
||||
return LoginWebPage::CheckLoggedUser($iErrorCode);
|
||||
}
|
||||
return LoginWebPage::LOGIN_FSM_CONTINUE;
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
93
application/maintenancemsg.php
Normal file
93
application/maintenancemsg.php
Normal file
@@ -0,0 +1,93 @@
|
||||
<?php
|
||||
/**
|
||||
* Copyright (C) 2013-2019 Combodo SARL
|
||||
*
|
||||
* This file is part of iTop.
|
||||
*
|
||||
* iTop is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* iTop is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
*/
|
||||
|
||||
|
||||
//
|
||||
// Maintenance message display functions
|
||||
// Only included by approot.inc.php
|
||||
//
|
||||
|
||||
/**
|
||||
* Use a setup page to display the maintenance message
|
||||
* @param $sTitle
|
||||
* @param $sMessage
|
||||
*/
|
||||
function _MaintenanceSetupPageMessage($sTitle, $sMessage)
|
||||
{
|
||||
// Web Page
|
||||
@include_once(APPROOT.'setup/setuppage.class.inc.php');
|
||||
if (class_exists('SetupPage'))
|
||||
{
|
||||
$oP = new ErrorPage($sTitle);
|
||||
$oP->p("<h2 class=\"center\">$sMessage</h2>");
|
||||
$oP->add_ready_script(
|
||||
<<<JS
|
||||
// Reload in 30s to check if maintenance is over
|
||||
setTimeout(function(){ window.location.reload(); }, 30000);
|
||||
JS
|
||||
|
||||
);
|
||||
$oP->output();
|
||||
}
|
||||
else
|
||||
{
|
||||
_MaintenanceTextMessage($sMessage);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Use simple text to display the maintenance message
|
||||
* @param $sMessage
|
||||
*/
|
||||
function _MaintenanceTextMessage($sMessage)
|
||||
{
|
||||
echo $sMessage;
|
||||
}
|
||||
|
||||
/**
|
||||
* Use a simple HTML to display the maintenance message
|
||||
* @param $sMessage
|
||||
*/
|
||||
function _MaintenanceHtmlMessage($sMessage)
|
||||
{
|
||||
echo '<html><body><div>'.$sMessage.'</div></body></html>';
|
||||
}
|
||||
|
||||
/**
|
||||
* Use a simple JSON to display the maintenance message
|
||||
*
|
||||
* @param $sTitle
|
||||
* @param $sMessage
|
||||
*/
|
||||
function _MaintenanceJsonMessage($sTitle, $sMessage)
|
||||
{
|
||||
@include_once(APPROOT."/application/ajaxwebpage.class.inc.php");
|
||||
if (class_exists('ajax_page'))
|
||||
{
|
||||
$oP = new ajax_page($sTitle);
|
||||
$oP->add_header('Access-Control-Allow-Origin: *');
|
||||
$oP->SetContentType('application/json');
|
||||
$oP->add('{"code":100, "message":"'.$sMessage.'"}');
|
||||
$oP->Output();
|
||||
}
|
||||
else
|
||||
{
|
||||
_MaintenanceTextMessage($sMessage);
|
||||
}
|
||||
}
|
||||
@@ -1,27 +1,20 @@
|
||||
<?php
|
||||
// Copyright (C) 2010-2016 Combodo SARL
|
||||
//
|
||||
// This file is part of iTop.
|
||||
//
|
||||
// iTop is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// iTop is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with iTop. If not, see <http://www.gnu.org/licenses/>
|
||||
|
||||
|
||||
/**
|
||||
* Construction and display of the application's main menu
|
||||
* Copyright (C) 2013-2019 Combodo SARL
|
||||
*
|
||||
* @copyright Copyright (C) 2010-2016 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
* 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
|
||||
*/
|
||||
|
||||
require_once(APPROOT.'/application/utils.inc.php');
|
||||
@@ -135,7 +128,7 @@ class ApplicationMenu
|
||||
if (is_null($oMenuNode) || !$oMenuNode->IsEnabled())
|
||||
{
|
||||
require_once(APPROOT.'/setup/setuppage.class.inc.php');
|
||||
$oP = new SetupPage(Dict::S('UI:PageTitle:FatalError'));
|
||||
$oP = new ErrorPage(Dict::S('UI:PageTitle:FatalError'));
|
||||
$oP->add("<h1>".Dict::S('UI:Login:Error:AccessRestricted')."</h1>\n");
|
||||
$oP->p("<a href=\"".utils::GetAbsoluteUrlAppRoot()."pages/logoff.php\">".Dict::S('UI:LogOffMenu')."</a>");
|
||||
$oP->output();
|
||||
@@ -201,7 +194,7 @@ class ApplicationMenu
|
||||
|
||||
/**
|
||||
* Entry point to display the whole menu into the web page, used by iTopWebPage
|
||||
* @param \iTopWebPage $oPage
|
||||
* @param \WebPage $oPage
|
||||
* @param $aExtraParams
|
||||
* @throws DictExceptionMissingString
|
||||
*/
|
||||
@@ -217,7 +210,7 @@ class ApplicationMenu
|
||||
{
|
||||
if (!self::CanDisplayMenu($aMenu)) { continue; }
|
||||
$oMenuNode = self::GetMenuNode($aMenu['index']);
|
||||
$oPage->AddToMenu('<h3 id="'.utils::GetSafeId('AccordionMenu_'.$oMenuNode->GetMenuID()).'">'.$oMenuNode->GetTitle().'</h3>');
|
||||
$oPage->AddToMenu('<h3 id="'.utils::GetSafeId('AccordionMenu_'.$oMenuNode->GetMenuID()).'" class="navigation-menu-group" data-menu-id="'.$oMenuNode->GetMenuId().'">'.$oMenuNode->GetTitle().'</h3>');
|
||||
$oPage->AddToMenu('<div>');
|
||||
$oPage->AddToMenu('<ul>');
|
||||
$aChildren = self::GetChildren($aMenu['index']);
|
||||
@@ -270,12 +263,15 @@ EOF
|
||||
|
||||
/**
|
||||
* Handles the display of the sub-menus (called recursively if necessary)
|
||||
* @param \iTopWebPage $oPage
|
||||
*
|
||||
* @param \WebPage $oPage
|
||||
* @param array $aMenus
|
||||
* @param array $aExtraParams
|
||||
* @param int $iActiveMenu
|
||||
*
|
||||
* @return true if the currently selected menu is one of the submenus
|
||||
* @throws DictExceptionMissingString
|
||||
* @throws \Exception
|
||||
*/
|
||||
static protected function DisplaySubMenu($oPage, $aMenus, $aExtraParams, $iActiveMenu = -1)
|
||||
{
|
||||
@@ -284,22 +280,39 @@ EOF
|
||||
usort($aMenus, array('ApplicationMenu', 'CompareOnRank'));
|
||||
foreach($aMenus as $aMenu)
|
||||
{
|
||||
if (!self::CanDisplayMenu($aMenu))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
$index = $aMenu['index'];
|
||||
$oMenu = self::GetMenuNode($index);
|
||||
if ($oMenu->IsEnabled())
|
||||
{
|
||||
$aChildren = self::GetChildren($index);
|
||||
$sCSSClass = (count($aChildren) > 0) ? ' class="submenu"' : '';
|
||||
$aCSSClasses = array('navigation-menu-item');
|
||||
if (count($aChildren) > 0)
|
||||
{
|
||||
$aCSSClasses[] = 'submenu';
|
||||
}
|
||||
$sHyperlink = $oMenu->GetHyperlink($aExtraParams);
|
||||
$sItemHtml = '<li id="'.utils::GetSafeId('AccordionMenu_'.$oMenu->GetMenuID()).'" class="'.implode(' ', $aCSSClasses).'" data-menu-id="'.$oMenu->GetMenuID().'">';
|
||||
if ($sHyperlink != '')
|
||||
{
|
||||
$sLinkTarget = '';
|
||||
if ($oMenu->IsHyperLinkInNewWindow())
|
||||
{
|
||||
$sLinkTarget .= ' target="_blank"';
|
||||
}
|
||||
$sURL = '"'.$oMenu->GetHyperlink($aExtraParams).'"'.$sLinkTarget;
|
||||
$sTitle = utils::HtmlEntities($oMenu->GetTitle());
|
||||
$oPage->AddToMenu('<li id="'.utils::GetSafeId('AccordionMenu_'.$oMenu->GetMenuID()).'" '.$sCSSClass.'><a href="'.$oMenu->GetHyperlink($aExtraParams).'">'.$sTitle.'</a></li>');
|
||||
$sItemHtml .= "<a href={$sURL}>{$sTitle}</a>";
|
||||
}
|
||||
else
|
||||
{
|
||||
$oPage->AddToMenu('<li id="'.utils::GetSafeId('AccordionMenu_'.$oMenu->GetMenuID()).'" '.$sCSSClass.'>'.$oMenu->GetTitle().'</li>');
|
||||
$sItemHtml .= $oMenu->GetTitle();
|
||||
}
|
||||
$sItemHtml .= '</li>';
|
||||
$oPage->AddToMenu($sItemHtml);
|
||||
if ($iActiveMenu == $index)
|
||||
{
|
||||
$bActive = true;
|
||||
@@ -600,13 +613,24 @@ abstract class MenuNode
|
||||
|
||||
/**
|
||||
* @param $aExtraParams
|
||||
*
|
||||
* @return string
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function GetHyperlink($aExtraParams)
|
||||
{
|
||||
$aExtraParams['c[menu]'] = $this->GetMenuId();
|
||||
return $this->AddParams(utils::GetAbsoluteUrlAppRoot().'pages/UI.php', $aExtraParams);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool true if the link should be opened in a new window
|
||||
* @since 2.7.0 N°1283
|
||||
*/
|
||||
public function IsHyperLinkInNewWindow()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a limiting display condition for the same menu node. The conditions will be combined with a AND
|
||||
@@ -671,8 +695,8 @@ abstract class MenuNode
|
||||
public abstract function RenderContent(WebPage $oPage, $aExtraParams = array());
|
||||
|
||||
/**
|
||||
* @param $sHyperlink
|
||||
* @param $aExtraParams
|
||||
* @param string $sHyperlink
|
||||
* @param array $aExtraParams
|
||||
* @return string
|
||||
*/
|
||||
protected function AddParams($sHyperlink, $aExtraParams)
|
||||
@@ -716,8 +740,7 @@ class MenuGroup extends MenuNode
|
||||
}
|
||||
|
||||
/**
|
||||
* @param WebPage $oPage
|
||||
* @param array $aExtraParams
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function RenderContent(WebPage $oPage, $aExtraParams = array())
|
||||
{
|
||||
@@ -755,8 +778,7 @@ class TemplateMenuNode extends MenuNode
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $aExtraParams
|
||||
* @return string
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function GetHyperlink($aExtraParams)
|
||||
{
|
||||
@@ -765,10 +787,8 @@ class TemplateMenuNode extends MenuNode
|
||||
}
|
||||
|
||||
/**
|
||||
* @param WebPage $oPage
|
||||
* @param array $aExtraParams
|
||||
* @return mixed|void
|
||||
* @throws DictExceptionMissingString
|
||||
* @inheritDoc
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function RenderContent(WebPage $oPage, $aExtraParams = array())
|
||||
{
|
||||
@@ -857,12 +877,8 @@ class OQLMenuNode extends MenuNode
|
||||
}
|
||||
|
||||
/**
|
||||
* @param WebPage $oPage
|
||||
* @param array $aExtraParams
|
||||
* @return mixed|void
|
||||
* @throws CoreException
|
||||
* @throws DictExceptionMissingString
|
||||
* @throws OQLException
|
||||
* @inheritDoc
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function RenderContent(WebPage $oPage, $aExtraParams = array())
|
||||
{
|
||||
@@ -881,11 +897,11 @@ class OQLMenuNode extends MenuNode
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $sOql
|
||||
* @param $sTitle
|
||||
* @param $sUsageId
|
||||
* @param $bSearchPane
|
||||
* @param $bSearchOpen
|
||||
* @param string $sOql
|
||||
* @param string $sTitle
|
||||
* @param string $sUsageId
|
||||
* @param bool $bSearchPane
|
||||
* @param bool $bSearchOpen
|
||||
* @param WebPage $oPage
|
||||
* @param array $aExtraParams
|
||||
* @param bool $bEnableBreadcrumb
|
||||
@@ -958,16 +974,14 @@ class SearchMenuNode extends MenuNode
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \iTopWebPage $oPage
|
||||
* @param array $aExtraParams
|
||||
* @return mixed|void
|
||||
* @throws DictExceptionMissingString
|
||||
* @throws Exception
|
||||
* @inheritDoc
|
||||
* @throws \DictExceptionMissingString
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function RenderContent(WebPage $oPage, $aExtraParams = array())
|
||||
{
|
||||
ApplicationMenu::CheckMenuIdEnabled($this->GetMenuId());
|
||||
$oPage->SetBreadCrumbEntry("menu-".$this->sMenuId, $this->GetTitle(), '', '', utils::GetAbsoluteUrlAppRoot().'images/search.png');
|
||||
$oPage->SetBreadCrumbEntry("menu-".$this->sMenuId, $this->GetTitle(), '', '', utils::GetAbsoluteUrlAppRoot().'images/breadcrumb-search.png');
|
||||
|
||||
$oSearch = new DBObjectSearch($this->sClass);
|
||||
$aParams = array_merge(array('table_id' => 'Menu_'.utils::GetSafeId($this->GetMenuId())), $aExtraParams);
|
||||
@@ -990,8 +1004,12 @@ class WebPageMenuNode extends MenuNode
|
||||
*/
|
||||
protected $sHyperlink;
|
||||
|
||||
/** @var bool */
|
||||
protected $bIsLinkInNewWindow;
|
||||
|
||||
/**
|
||||
* Create a menu item that points to any web page (not only UI.php)
|
||||
*
|
||||
* @param string $sMenuId Unique identifier of the menu (used to identify the menu for bookmarking, and for getting the labels from the dictionary)
|
||||
* @param string $sHyperlink URL to the page to load. Use relative URL if you want to keep the application portable !
|
||||
* @param integer $iParentIndex ID of the parent menu
|
||||
@@ -1000,17 +1018,21 @@ class WebPageMenuNode extends MenuNode
|
||||
* @param integer $iActionCode Either UR_ACTION_READ, UR_ACTION_MODIFY, UR_ACTION_DELETE, UR_ACTION_BULKREAD, UR_ACTION_BULKMODIFY or UR_ACTION_BULKDELETE
|
||||
* @param integer $iAllowedResults Expected "rights" for the action: either UR_ALLOWED_YES, UR_ALLOWED_NO, UR_ALLOWED_DEPENDS or a mix of them...
|
||||
* @param string $sEnableStimulus
|
||||
* @param bool $bIsLinkInNewWindow for the {@link WebPageMenuNode::IsHyperLinkInNewWindow} method
|
||||
*/
|
||||
public function __construct($sMenuId, $sHyperlink, $iParentIndex, $fRank = 0.0, $sEnableClass = null, $iActionCode = null, $iAllowedResults = UR_ALLOWED_YES, $sEnableStimulus = null)
|
||||
public function __construct(
|
||||
$sMenuId, $sHyperlink, $iParentIndex, $fRank = 0.0, $sEnableClass = null, $iActionCode = null,
|
||||
$iAllowedResults = UR_ALLOWED_YES, $sEnableStimulus = null, $bIsLinkInNewWindow = false
|
||||
)
|
||||
{
|
||||
parent::__construct($sMenuId, $iParentIndex, $fRank, $sEnableClass, $iActionCode, $iAllowedResults, $sEnableStimulus);
|
||||
$this->sHyperlink = $sHyperlink;
|
||||
$this->aReflectionProperties['url'] = $sHyperlink;
|
||||
$this->bIsLinkInNewWindow = $bIsLinkInNewWindow;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $aExtraParams
|
||||
* @return string
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function GetHyperlink($aExtraParams)
|
||||
{
|
||||
@@ -1019,8 +1041,15 @@ class WebPageMenuNode extends MenuNode
|
||||
}
|
||||
|
||||
/**
|
||||
* @param WebPage $oPage
|
||||
* @param array $aExtraParams
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function IsHyperLinkInNewWindow()
|
||||
{
|
||||
return $this->bIsLinkInNewWindow;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function RenderContent(WebPage $oPage, $aExtraParams = array())
|
||||
{
|
||||
@@ -1061,10 +1090,7 @@ class NewObjectMenuNode extends MenuNode
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string[] $aExtraParams
|
||||
*
|
||||
* @return string
|
||||
* @throws \Exception
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function GetHyperlink($aExtraParams)
|
||||
{
|
||||
@@ -1098,8 +1124,7 @@ class NewObjectMenuNode extends MenuNode
|
||||
}
|
||||
|
||||
/**
|
||||
* @param WebPage $oPage
|
||||
* @param string[] $aExtraParams
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function RenderContent(WebPage $oPage, $aExtraParams = array())
|
||||
{
|
||||
@@ -1137,8 +1162,7 @@ class DashboardMenuNode extends MenuNode
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string[] $aExtraParams
|
||||
* @return string
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function GetHyperlink($aExtraParams)
|
||||
{
|
||||
@@ -1157,10 +1181,8 @@ class DashboardMenuNode extends MenuNode
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \iTopWebPage $oPage
|
||||
* @param string[] $aExtraParams
|
||||
* @throws CoreException
|
||||
* @throws Exception
|
||||
* @inheritDoc
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function RenderContent(WebPage $oPage, $aExtraParams = array())
|
||||
{
|
||||
@@ -1168,8 +1190,9 @@ class DashboardMenuNode extends MenuNode
|
||||
$oDashboard = $this->GetDashboard();
|
||||
if ($oDashboard != null)
|
||||
{
|
||||
$sDivId = preg_replace('/[^a-zA-Z0-9_]/', '', $this->sMenuId);
|
||||
$sDivId = utils::Sanitize($this->sMenuId, '', 'element_identifier');
|
||||
$oPage->add('<div class="dashboard_contents" id="'.$sDivId.'">');
|
||||
$aExtraParams['dashboard_div_id'] = $sDivId;
|
||||
$oDashboard->SetReloadURL($this->GetHyperlink($aExtraParams));
|
||||
$oDashboard->Render($oPage, false, $aExtraParams);
|
||||
$oPage->add('</div>');
|
||||
@@ -1254,8 +1277,7 @@ class DashboardMenuNode extends MenuNode
|
||||
class ShortcutContainerMenuNode extends MenuNode
|
||||
{
|
||||
/**
|
||||
* @param string[] $aExtraParams
|
||||
* @return string
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function GetHyperlink($aExtraParams)
|
||||
{
|
||||
@@ -1263,15 +1285,14 @@ class ShortcutContainerMenuNode extends MenuNode
|
||||
}
|
||||
|
||||
/**
|
||||
* @param WebPage $oPage
|
||||
* @param string[] $aExtraParams
|
||||
* @return mixed|void
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function RenderContent(WebPage $oPage, $aExtraParams = array())
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
* @throws CoreException
|
||||
* @throws Exception
|
||||
*/
|
||||
@@ -1326,9 +1347,7 @@ class ShortcutMenuNode extends MenuNode
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string[] $aExtraParams
|
||||
* @return string
|
||||
* @throws CoreException
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function GetHyperlink($aExtraParams)
|
||||
{
|
||||
@@ -1346,10 +1365,8 @@ class ShortcutMenuNode extends MenuNode
|
||||
}
|
||||
|
||||
/**
|
||||
* @param WebPage $oPage
|
||||
* @param string[] $aExtraParams
|
||||
* @return mixed|void
|
||||
* @throws DictExceptionMissingString
|
||||
* @inheritDoc
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function RenderContent(WebPage $oPage, $aExtraParams = array())
|
||||
{
|
||||
@@ -1358,8 +1375,9 @@ class ShortcutMenuNode extends MenuNode
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
* @throws CoreException
|
||||
* @inheritDoc
|
||||
*
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function GetTitle()
|
||||
{
|
||||
@@ -1367,8 +1385,9 @@ class ShortcutMenuNode extends MenuNode
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
* @throws CoreException
|
||||
* @inheritDoc
|
||||
*
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function GetLabel()
|
||||
{
|
||||
|
||||
@@ -1,27 +1,20 @@
|
||||
<?php
|
||||
// Copyright (C) 2010-2016 Combodo SARL
|
||||
//
|
||||
// This file is part of iTop.
|
||||
//
|
||||
// iTop is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// iTop is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with iTop. If not, see <http://www.gnu.org/licenses/>
|
||||
|
||||
|
||||
/**
|
||||
* Class NiceWebPage
|
||||
* Copyright (C) 2013-2020 Combodo SARL
|
||||
*
|
||||
* @copyright Copyright (C) 2010-2016 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
* 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
|
||||
*/
|
||||
|
||||
require_once(APPROOT."/application/webpage.class.inc.php");
|
||||
@@ -37,17 +30,16 @@ class NiceWebPage extends WebPage
|
||||
{
|
||||
parent::__construct($s_title, $bPrintable);
|
||||
$this->m_aReadyScripts = array();
|
||||
$this->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/jquery-3.3.1.min.js');
|
||||
$this->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/jquery.min.js');
|
||||
if(utils::IsDevelopmentEnvironment()) // Needed since many other plugins still rely on oldies like $.browser
|
||||
{
|
||||
$this->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/jquery-migrate-3.0.1.dev.js');
|
||||
$this->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/jquery-migrate.dev.js');
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/jquery-migrate-3.0.1.prod.min.js');
|
||||
$this->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/jquery-migrate.prod.min.js');
|
||||
}
|
||||
$this->add_linked_stylesheet(utils::GetAbsoluteUrlAppRoot().'css/ui-lightness/jquery-ui-1.11.4.custom.css');
|
||||
$this->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/jquery-ui-1.11.4.custom.min.js');
|
||||
$this->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/jquery-ui-1.11.4.custom.min.js');
|
||||
$this->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/utils.js');
|
||||
$this->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/hovertip.js');
|
||||
// table sorting
|
||||
@@ -75,6 +67,8 @@ class NiceWebPage extends WebPage
|
||||
$this->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/search/search_form_criteria_date_abstract.js');
|
||||
$this->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/search/search_form_criteria_date.js');
|
||||
$this->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/search/search_form_criteria_date_time.js');
|
||||
$this->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/clipboard.min.js');
|
||||
$this->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/clipboardwidget.js');
|
||||
|
||||
$this->add_dict_entries('UI:Combo');
|
||||
|
||||
@@ -122,7 +116,7 @@ class NiceWebPage extends WebPage
|
||||
$("table.listResults").tableHover(); // hover tables
|
||||
EOF
|
||||
);
|
||||
$this->add_saas("css/light-grey.scss");
|
||||
$this->LoadTheme();
|
||||
|
||||
$this->m_sRootUrl = $this->GetAbsoluteUrlAppRoot();
|
||||
$sAbsURLAppRoot = addslashes($this->m_sRootUrl);
|
||||
@@ -232,7 +226,8 @@ EOF
|
||||
foreach($aChoices as $sKey => $sValue)
|
||||
{
|
||||
$sSelected = ($sKey == $sDefaultValue) ? " SELECTED" : "";
|
||||
$this->add("<option style=\"width: ".$iWidthPx." px;\" value=\"".htmlspecialchars($sKey)."\"$sSelected>".htmlentities($sValue, ENT_QUOTES, 'UTF-8')."</option>");
|
||||
$this->add("<option style=\"width: ".$iWidthPx." px;\" value=\"".htmlspecialchars($sKey)."\"$sSelected>".htmlentities($sValue,
|
||||
ENT_QUOTES, self::PAGES_CHARSET)."</option>");
|
||||
}
|
||||
$this->add("</select>");
|
||||
}
|
||||
@@ -254,6 +249,14 @@ EOF
|
||||
}
|
||||
parent::output();
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
/**
|
||||
* @throws \Exception
|
||||
* @since 2.7.0
|
||||
*/
|
||||
protected function LoadTheme()
|
||||
{
|
||||
$sCssThemeUrl = ThemeHandler::GetCurrentThemeUrl();
|
||||
$this->add_linked_stylesheet($sCssThemeUrl);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,15 +1,53 @@
|
||||
<?php
|
||||
require_once(APPROOT.'lib/tcpdf/tcpdf.php');
|
||||
/**
|
||||
* Copyright (C) 2013-2019 Combodo SARL
|
||||
*
|
||||
* This file is part of iTop.
|
||||
*
|
||||
* iTop is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* iTop is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
*/
|
||||
|
||||
require_once(APPROOT.'application/utils.inc.php');
|
||||
|
||||
/**
|
||||
* Custom class derived from TCPDF for providing custom headers and footers
|
||||
*
|
||||
* @author denis
|
||||
*
|
||||
*/
|
||||
class iTopPDF extends TCPDF
|
||||
{
|
||||
protected $sDocumentTitle;
|
||||
|
||||
|
||||
/**
|
||||
* Shortcut for {@link TCPDF::SetFont}, to use the font configured
|
||||
*
|
||||
* @param string $style
|
||||
* @param int $size
|
||||
* @param string $fontfile
|
||||
* @param string $subset
|
||||
* @param bool $out
|
||||
*
|
||||
* @uses \TCPDF::SetFont()
|
||||
* @uses \iTopPDF::GetPdfFont()
|
||||
* @since 2.7.0
|
||||
*/
|
||||
public function SetFontParams($style, $size, $fontfile='', $subset='default', $out=true)
|
||||
{
|
||||
$siTopFont = self::GetPdfFont();
|
||||
$this->SetFont($siTopFont, $style, $size, $fontfile, $subset, $out);
|
||||
}
|
||||
|
||||
public function SetDocumentTitle($sDocumentTitle)
|
||||
{
|
||||
$this->sDocumentTitle = $sDocumentTitle;
|
||||
@@ -17,26 +55,29 @@ class iTopPDF extends TCPDF
|
||||
|
||||
/**
|
||||
* Builds the custom header. Called for each new page.
|
||||
*
|
||||
* @see TCPDF::Header()
|
||||
*/
|
||||
public function Header()
|
||||
{
|
||||
// Title
|
||||
// Set font
|
||||
$this->SetFont('dejavusans', 'B', 10);
|
||||
|
||||
$this->SetFontParams('B', 10);
|
||||
|
||||
$iPageNumberWidth = 25;
|
||||
$aMargins = $this->getMargins();
|
||||
|
||||
|
||||
// Display the title (centered)
|
||||
$this->SetXY($aMargins['left'] + $iPageNumberWidth, 0);
|
||||
$this->MultiCell($this->getPageWidth() - $aMargins['left'] - $aMargins['right'] - 2*$iPageNumberWidth, 15, $this->sDocumentTitle, 0, 'C', false, 0 /* $ln */, '', '', true, 0, false, true, 15, 'M' /* $valign */);
|
||||
$this->SetFont('dejavusans', '', 10);
|
||||
|
||||
$this->MultiCell($this->getPageWidth() - $aMargins['left'] - $aMargins['right'] - 2 * $iPageNumberWidth, 15, $this->sDocumentTitle,
|
||||
0, 'C', false, 0 /* $ln */, '', '', true, 0, false, true, 15, 'M' /* $valign */);
|
||||
$this->SetFontParams('', 10);
|
||||
|
||||
// Display the page number (right aligned)
|
||||
// Warning: the 'R'ight alignment does not work when using placeholders like $this->getAliasNumPage() or $this->getAliasNbPages()
|
||||
$this->MultiCell($iPageNumberWidth, 15, Dict::Format('Core:BulkExport:PDF:PageNumber' ,$this->page), 0, 'R', false, 0 /* $ln */, '', '', true, 0, false, true, 15, 'M' /* $valign */);
|
||||
|
||||
$this->MultiCell($iPageNumberWidth, 15, Dict::Format('Core:BulkExport:PDF:PageNumber', $this->page), 0, 'R', false, 0 /* $ln */, '',
|
||||
'', true, 0, false, true, 15, 'M' /* $valign */);
|
||||
|
||||
// Branding logo
|
||||
$sBrandingIcon = APPROOT.'images/itop-logo.png';
|
||||
if (file_exists(MODULESROOT.'branding/main-logo.png'))
|
||||
@@ -51,6 +92,18 @@ class iTopPDF extends TCPDF
|
||||
{
|
||||
// No footer
|
||||
}
|
||||
|
||||
/**
|
||||
* dejavusans is a UTF-8 Unicode font. Standard PDF fonts like helvetica or times new roman are NOT UTF-8
|
||||
* @return string font in the config file (export_pdf_font)
|
||||
*/
|
||||
public static function GetPdfFont()
|
||||
{
|
||||
$oConfig = utils::GetConfig();
|
||||
$sPdfFont = $oConfig->Get('export_pdf_font');
|
||||
|
||||
return $sPdfFont;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -58,49 +111,45 @@ class iTopPDF extends TCPDF
|
||||
*/
|
||||
class PDFPage extends WebPage
|
||||
{
|
||||
/**
|
||||
* Instance of the TCPDF object for creating the PDF
|
||||
* @var TCPDF
|
||||
*/
|
||||
/** @var \iTopPDF Instance of the TCPDF object for creating the PDF */
|
||||
protected $oPdf;
|
||||
|
||||
|
||||
public function __construct($s_title, $sPageFormat = 'A4', $sPageOrientation = 'L')
|
||||
{
|
||||
parent::__construct($s_title);
|
||||
define(K_PATH_FONTS, APPROOT.'lib/tcpdf/fonts');
|
||||
$this->oPdf = new iTopPDF($sPageOrientation, 'mm', $sPageFormat, true, 'UTF-8', false);
|
||||
|
||||
define(K_PATH_FONTS, APPROOT.'lib/combodo/tcpdf/fonts');
|
||||
$this->oPdf = new iTopPDF($sPageOrientation, 'mm', $sPageFormat, true, self::PAGES_CHARSET, false);
|
||||
|
||||
// set document information
|
||||
$this->oPdf->SetCreator(PDF_CREATOR);
|
||||
$this->oPdf->SetAuthor('iTop');
|
||||
$this->oPdf->SetTitle($s_title);
|
||||
$this->oPdf->SetDocumentTitle($s_title);
|
||||
|
||||
|
||||
$this->oPdf->setFontSubsetting(true);
|
||||
|
||||
// Set font
|
||||
|
||||
// dejavusans is a UTF-8 Unicode font. Standard PDF fonts like helvetica or times new roman are NOT UTF-8
|
||||
$this->oPdf->SetFont('dejavusans', '', 10, '', true);
|
||||
|
||||
$this->oPdf->SetFontParams('', 10, '', true);
|
||||
|
||||
// set auto page breaks
|
||||
$this->oPdf->SetAutoPageBreak(true, 15); // 15 mm break margin at the bottom
|
||||
$this->oPdf->SetTopMargin(15);
|
||||
|
||||
|
||||
// Add a page, we're ready to start
|
||||
$this->oPdf->AddPage();
|
||||
|
||||
|
||||
$this->SetContentDisposition('inline', $s_title.'.pdf');
|
||||
$this->SetDefaultStyle();
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Sets a default style (suitable for printing) to be included each time $this->oPdf->writeHTML() is called
|
||||
*/
|
||||
protected function SetDefaultStyle()
|
||||
{
|
||||
$this->add_style(
|
||||
<<<EOF
|
||||
<<<EOF
|
||||
table {
|
||||
padding: 2pt;
|
||||
}
|
||||
@@ -124,19 +173,21 @@ td.icon {
|
||||
width: 30px;
|
||||
}
|
||||
EOF
|
||||
);
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get access to the underlying TCPDF object
|
||||
* @return TCPDF
|
||||
*
|
||||
* @return \iTopPDF
|
||||
*/
|
||||
public function get_tcpdf()
|
||||
{
|
||||
$this->flush();
|
||||
|
||||
return $this->oPdf;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Writes the currently buffered HTML content into the PDF. This can be useful:
|
||||
* - to sync the flow in case you want to access the underlying TCPDF object for some specific/graphic output
|
||||
@@ -156,39 +207,42 @@ EOF
|
||||
$this->s_content = '';
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Whether or not the page is a PDF page
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function is_pdf()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Generates the PDF document and returns the PDF content as a string
|
||||
*
|
||||
* @return string
|
||||
* @see WebPage::output()
|
||||
*/
|
||||
public function output()
|
||||
{
|
||||
$this->add_header('Content-type: application/x-pdf');
|
||||
if (!empty($this->sContentDisposition))
|
||||
{
|
||||
if (!empty($this->sContentDisposition))
|
||||
{
|
||||
$this->add_header('Content-Disposition: '.$this->sContentDisposition.'; filename="'.$this->sContentFileName.'"');
|
||||
}
|
||||
foreach($this->a_headers as $s_header)
|
||||
{
|
||||
header($s_header);
|
||||
}
|
||||
$this->flush();
|
||||
}
|
||||
foreach ($this->a_headers as $s_header)
|
||||
{
|
||||
header($s_header);
|
||||
}
|
||||
$this->flush();
|
||||
echo $this->oPdf->Output($this->s_title.'.pdf', 'S');
|
||||
}
|
||||
|
||||
|
||||
public function get_pdf()
|
||||
{
|
||||
$this->flush();
|
||||
|
||||
return $this->oPdf->Output($this->s_title.'.pdf', 'S');
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -3,7 +3,7 @@
|
||||
//
|
||||
// This file is part of iTop.
|
||||
//
|
||||
// iTop is free software; you can redistribute it and/or modify
|
||||
// iTop is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
@@ -15,12 +15,15 @@
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with iTop. If not, see <http://www.gnu.org/licenses/>
|
||||
require_once(APPROOT.'/core/cmdbobject.class.inc.php');
|
||||
require_once(APPROOT.'/application/utils.inc.php');
|
||||
require_once(APPROOT.'/core/contexttag.class.inc.php');
|
||||
|
||||
|
||||
/**
|
||||
* File to include to initialize the datamodel in memory
|
||||
*
|
||||
* @copyright Copyright (C) 2010-2016 Combodo SARL
|
||||
* @copyright Copyright (C) 2010-2019 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
@@ -32,10 +35,26 @@ register_shutdown_function(function()
|
||||
$sReservedMemory = null;
|
||||
if (!is_null($err = error_get_last()) && ($err['type'] == E_ERROR))
|
||||
{
|
||||
// Remove stack trace from MySQLException
|
||||
$sMessage = $err['message'];
|
||||
if (strpos($sMessage, 'MySQLException') !== false)
|
||||
{
|
||||
$iStackTracePos = strpos($sMessage, 'Stack trace:');
|
||||
if ($iStackTracePos !== false)
|
||||
{
|
||||
$sMessage = substr($sMessage, 0, $iStackTracePos);
|
||||
}
|
||||
}
|
||||
IssueLog::error($sMessage);
|
||||
if (strpos($err['message'], 'Allowed memory size of') !== false)
|
||||
{
|
||||
$sLimit = ini_get('memory_limit');
|
||||
echo "<p>iTop: Allowed memory size of $sLimit exhausted, contact your administrator to increase memory_limit in php.ini</p>\n";
|
||||
echo "<p>iTop: Allowed memory size of $sLimit exhausted, contact your administrator to increase 'memory_limit' in php.ini</p>\n";
|
||||
}
|
||||
elseif (strpos($err['message'], 'Maximum execution time') !== false)
|
||||
{
|
||||
$sLimit = ini_get('max_execution_time');
|
||||
echo "<p>iTop: Maximum execution time of $sLimit exceeded, contact your administrator to increase 'max_execution_time' in php.ini</p>\n";
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -44,9 +63,6 @@ register_shutdown_function(function()
|
||||
}
|
||||
});
|
||||
|
||||
require_once(APPROOT.'/core/cmdbobject.class.inc.php');
|
||||
require_once(APPROOT.'/application/utils.inc.php');
|
||||
require_once(APPROOT.'/core/contexttag.class.inc.php');
|
||||
session_name('itop-'.md5(APPROOT));
|
||||
session_start();
|
||||
$sSwitchEnv = utils::ReadParam('switch_env', null);
|
||||
@@ -79,4 +95,4 @@ else
|
||||
$_SESSION['itop_env'] = ITOP_DEFAULT_ENV;
|
||||
}
|
||||
$sConfigFile = APPCONF.$sEnv.'/'.ITOP_CONFIG_FILE;
|
||||
MetaModel::Startup($sConfigFile, false /* $bModelOnly */, $bAllowCache, false /* $bTraceSourceFiles */, $sEnv);
|
||||
MetaModel::Startup($sConfigFile, false /* $bModelOnly */, $bAllowCache, false /* $bTraceSourceFiles */, $sEnv);
|
||||
|
||||
@@ -1,27 +1,20 @@
|
||||
<?php
|
||||
// Copyright (C) 2010-2017 Combodo SARL
|
||||
//
|
||||
// This file is part of iTop.
|
||||
//
|
||||
// iTop is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// iTop is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with iTop. If not, see <http://www.gnu.org/licenses/>
|
||||
|
||||
|
||||
/**
|
||||
* Class DisplayTemplate
|
||||
* Copyright (C) 2013-2020 Combodo SARL
|
||||
*
|
||||
* @copyright Copyright (C) 2010-2017 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
* 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
|
||||
*/
|
||||
|
||||
require_once(APPROOT.'/application/displayblock.class.inc.php');
|
||||
@@ -191,7 +184,7 @@ class DisplayTemplate
|
||||
break;
|
||||
|
||||
case 'itoptab':
|
||||
$oPage->SetCurrentTab(Dict::S(str_replace('_', ' ', $aAttributes['name'])));
|
||||
$oPage->SetCurrentTab($aAttributes['name'], str_replace('_', ' ', $aAttributes['name']));
|
||||
$oTemplate = new DisplayTemplate($sContent);
|
||||
$oTemplate->Render($oPage, array()); // no params to apply, they have already been applied
|
||||
//$oPage->p('iTop Tab Content:<pre>'.htmlentities($sContent, ENT_QUOTES, 'UTF-8').'</pre>');
|
||||
|
||||
194
application/themehandler.class.inc.php
Normal file
194
application/themehandler.class.inc.php
Normal file
@@ -0,0 +1,194 @@
|
||||
<?php
|
||||
/**
|
||||
* Copyright (C) 2013-2020 Combodo SARL
|
||||
*
|
||||
* This file is part of iTop.
|
||||
*
|
||||
* iTop is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* iTop is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
*/
|
||||
|
||||
/**
|
||||
* Class ThemeHandler
|
||||
*
|
||||
* @author Stephen Abello <stephen.abello@combodo.com>
|
||||
* @since 2.7.0
|
||||
*/
|
||||
class ThemeHandler
|
||||
{
|
||||
/**
|
||||
* Return default theme name and parameters
|
||||
*
|
||||
* @return array
|
||||
* @since 2.7.0
|
||||
*/
|
||||
public static function GetDefaultThemeInformation()
|
||||
{
|
||||
return array(
|
||||
'name' => 'light-grey',
|
||||
'parameters' => array(
|
||||
'variables' => array(),
|
||||
'imports' => array(
|
||||
'css-variables' => '../css/css-variables.scss',
|
||||
),
|
||||
'stylesheets' => array(
|
||||
'jqueryui' => '../css/ui-lightness/jqueryui.scss',
|
||||
'main' => '../css/light-grey.scss',
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the ID of the theme currently defined in the config. file
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function GetCurrentThemeId()
|
||||
{
|
||||
try
|
||||
{
|
||||
if (is_null(MetaModel::GetConfig()))
|
||||
{
|
||||
throw new CoreException('no config');
|
||||
}
|
||||
$sThemeId = MetaModel::GetConfig()->Get('backoffice_default_theme');
|
||||
}
|
||||
catch(CoreException $oCompileException)
|
||||
{
|
||||
// Fallback on our default theme in case the config. is not available yet
|
||||
$aDefaultTheme = ThemeHandler::GetDefaultThemeInformation();
|
||||
$sThemeId = $aDefaultTheme['name'];
|
||||
}
|
||||
|
||||
return $sThemeId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the absolute path of the compiled theme folder.
|
||||
*
|
||||
* @param string $sThemeId
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function GetCompiledThemeFolderAbsolutePath($sThemeId)
|
||||
{
|
||||
return APPROOT.'env-'.utils::GetCurrentEnvironment().'/branding/themes/'.$sThemeId.'/';
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the absolute URL for the current theme CSS file
|
||||
*
|
||||
* @return string
|
||||
* @throws \Exception
|
||||
*/
|
||||
public static function GetCurrentThemeUrl()
|
||||
{
|
||||
try
|
||||
{
|
||||
// Try to compile theme defined in the configuration
|
||||
$sThemeId = static::GetCurrentThemeId();
|
||||
static::CompileTheme($sThemeId);
|
||||
}
|
||||
catch(CoreException $oCompileException)
|
||||
{
|
||||
// Fallback on our default theme (should always be compilable) in case the previous theme doesn't exists
|
||||
$aDefaultTheme = ThemeHandler::GetDefaultThemeInformation();
|
||||
$sThemeId = $aDefaultTheme['name'];
|
||||
$sDefaultThemeDirPath = static::GetCompiledThemeFolderAbsolutePath($sThemeId);
|
||||
|
||||
// Create our theme dir if it doesn't exist (XML theme node removed, renamed etc..)
|
||||
if(!is_dir($sDefaultThemeDirPath))
|
||||
{
|
||||
SetupUtils::builddir($sDefaultThemeDirPath);
|
||||
}
|
||||
|
||||
static::CompileTheme($sThemeId, $aDefaultTheme['parameters']);
|
||||
}
|
||||
|
||||
// Return absolute url to theme compiled css
|
||||
return utils::GetAbsoluteUrlModulesRoot().'/branding/themes/'.$sThemeId.'/main.css';
|
||||
}
|
||||
|
||||
/**
|
||||
* Compile the $sThemeId theme
|
||||
*
|
||||
* @param string $sThemeId
|
||||
* @param array|null $aThemeParameters Parameters (variables, imports, stylesheets) for the theme, if not passed, will be retrieved from compiled DM
|
||||
* @param array|null $aImportsPaths Paths where imports can be found. Must end with '/'
|
||||
* @param string|null $sWorkingPath Path of the folder used during compilation. Must end with a '/'
|
||||
*
|
||||
* @throws \CoreException
|
||||
*/
|
||||
public static function CompileTheme($sThemeId, $aThemeParameters = null, $aImportsPaths = null, $sWorkingPath = null)
|
||||
{
|
||||
// Default working path
|
||||
if($sWorkingPath === null)
|
||||
{
|
||||
$sWorkingPath = APPROOT.'env-'.utils::GetCurrentEnvironment().'/';
|
||||
}
|
||||
|
||||
// Default import paths (env-*)
|
||||
if($aImportsPaths === null)
|
||||
{
|
||||
$aImportsPaths = array(
|
||||
APPROOT.'env-'.utils::GetCurrentEnvironment().'/',
|
||||
);
|
||||
}
|
||||
|
||||
// Note: We do NOT check that the folder exists!
|
||||
$sThemeFolderPath = $sWorkingPath.'/branding/themes/'.$sThemeId.'/';
|
||||
$sThemeCssPath = $sThemeFolderPath.'main.css';
|
||||
|
||||
// Save parameters if passed... (typically during DM compilation)
|
||||
if(is_array($aThemeParameters))
|
||||
{
|
||||
file_put_contents($sThemeFolderPath.'/theme-parameters.json', json_encode($aThemeParameters));
|
||||
}
|
||||
// ... Otherwise, retrieve them from compiled DM (typically when switching current theme in the config. file)
|
||||
else
|
||||
{
|
||||
$aThemeParameters = json_decode(@file_get_contents($sThemeFolderPath.'theme-parameters.json'), true);
|
||||
if ($aThemeParameters === null)
|
||||
{
|
||||
throw new CoreException('Could not load "'.$sThemeId.'" theme parameters from file, check that it has been compiled correctly');
|
||||
}
|
||||
}
|
||||
|
||||
$sTmpThemeScssContent = '';
|
||||
$iStyleLastModified = 0;
|
||||
clearstatcache();
|
||||
// Loading files to import and stylesheet to compile, also getting most recent modification time on overall files
|
||||
foreach ($aThemeParameters['imports'] as $sImport)
|
||||
{
|
||||
$sTmpThemeScssContent .= '@import "'.$sImport.'";'."\n";
|
||||
|
||||
$iImportLastModified = @filemtime($sWorkingPath.$sImport);
|
||||
$iStyleLastModified = $iStyleLastModified < $iImportLastModified ? $iImportLastModified : $iStyleLastModified;
|
||||
}
|
||||
foreach ($aThemeParameters['stylesheets'] as $sStylesheet)
|
||||
{
|
||||
$sTmpThemeScssContent .= '@import "'.$sStylesheet.'";'."\n";
|
||||
|
||||
$iStylesheetLastModified = @filemtime($sWorkingPath.$sStylesheet);
|
||||
$iStyleLastModified = $iStyleLastModified < $iStylesheetLastModified ? $iStylesheetLastModified : $iStyleLastModified;
|
||||
}
|
||||
|
||||
// Checking if our compiled css is outdated
|
||||
if (!file_exists($sThemeCssPath) || (is_writable($sThemeFolderPath) && (@filemtime($sThemeCssPath) < $iStyleLastModified)))
|
||||
{
|
||||
$sTmpThemeCssContent = utils::CompileCSSFromSASS($sTmpThemeScssContent, $aImportsPaths, $aThemeParameters['variables']);
|
||||
file_put_contents($sThemeCssPath, $sTmpThemeCssContent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -195,9 +195,8 @@ class privUITransactionSession
|
||||
class privUITransactionFile
|
||||
{
|
||||
/**
|
||||
* Create a new transaction id, store it in the session and return its id
|
||||
* @param void
|
||||
* @return int The identifier of the new transaction
|
||||
* @return int The new transaction identifier
|
||||
* @throws \Exception
|
||||
*/
|
||||
public static function GetNewTransactionId()
|
||||
{
|
||||
@@ -207,7 +206,9 @@ class privUITransactionFile
|
||||
{
|
||||
throw new Exception('The directory "'.APPROOT.'data" must be writable to the application.');
|
||||
}
|
||||
if (!@mkdir(APPROOT.'data/transactions'))
|
||||
// condition avoids race condition N°2345
|
||||
// See https://github.com/kalessil/phpinspectionsea/blob/master/docs/probable-bugs.md#mkdir-race-condition
|
||||
if (!mkdir($concurrentDirectory = APPROOT.'data/transactions') && !is_dir($concurrentDirectory))
|
||||
{
|
||||
throw new Exception('Failed to create the directory "'.APPROOT.'data/transactions". Ajust the rights on the parent directory or let an administrator create the transactions directory and give the web sever enough rights to write into it.');
|
||||
}
|
||||
|
||||
140
application/twigextension.class.inc.php
Normal file
140
application/twigextension.class.inc.php
Normal file
@@ -0,0 +1,140 @@
|
||||
<?php
|
||||
|
||||
namespace Combodo\iTop;
|
||||
|
||||
use AttributeDateTime;
|
||||
use Dict;
|
||||
use Exception;
|
||||
use MetaModel;
|
||||
use Twig_Environment;
|
||||
use Twig_SimpleFilter;
|
||||
use Twig_SimpleFunction;
|
||||
use utils;
|
||||
|
||||
class TwigExtension
|
||||
{
|
||||
/**
|
||||
* Registers Twig extensions such as filters or functions.
|
||||
* It allows us to access some stuff directly in twig.
|
||||
*
|
||||
* @param \Twig_Environment $oTwigEnv
|
||||
*/
|
||||
public static function RegisterTwigExtensions(Twig_Environment &$oTwigEnv)
|
||||
{
|
||||
// Filter to translate a string via the Dict::S function
|
||||
// Usage in twig: {{ 'String:ToTranslate'|dict_s }}
|
||||
$oTwigEnv->addFilter(new Twig_SimpleFilter('dict_s',
|
||||
function ($sStringCode, $sDefault = null, $bUserLanguageOnly = false) {
|
||||
return Dict::S($sStringCode, $sDefault, $bUserLanguageOnly);
|
||||
})
|
||||
);
|
||||
|
||||
// Filter to format a string via the Dict::Format function
|
||||
// Usage in twig: {{ 'String:ToTranslate'|dict_format() }}
|
||||
$oTwigEnv->addFilter(new Twig_SimpleFilter('dict_format',
|
||||
function ($sStringCode, $sParam01 = null, $sParam02 = null, $sParam03 = null, $sParam04 = null) {
|
||||
return Dict::Format($sStringCode, $sParam01, $sParam02, $sParam03, $sParam04);
|
||||
})
|
||||
);
|
||||
|
||||
// Filter to format output
|
||||
// example a DateTime is converted to user format
|
||||
// Usage in twig: {{ 'String:ToFormat'|output_format }}
|
||||
$oTwigEnv->addFilter(new Twig_SimpleFilter('date_format',
|
||||
function ($sDate) {
|
||||
try
|
||||
{
|
||||
if (preg_match('@^\d\d\d\d-\d\d-\d\d \d\d:\d\d:\d\d$@', trim($sDate)))
|
||||
{
|
||||
return AttributeDateTime::GetFormat()->Format($sDate);
|
||||
}
|
||||
}
|
||||
catch (Exception $e)
|
||||
{
|
||||
}
|
||||
return $sDate;
|
||||
})
|
||||
);
|
||||
|
||||
|
||||
// Filter to format output
|
||||
// example a DateTime is converted to user format
|
||||
// Usage in twig: {{ 'String:ToFormat'|output_format }}
|
||||
$oTwigEnv->addFilter(new Twig_SimpleFilter('size_format',
|
||||
function ($sSize) {
|
||||
return utils::BytesToFriendlyFormat($sSize);
|
||||
})
|
||||
);
|
||||
|
||||
// Filter to enable base64 encode/decode
|
||||
// Usage in twig: {{ 'String to encode'|base64_encode }}
|
||||
$oTwigEnv->addFilter(new Twig_SimpleFilter('base64_encode', 'base64_encode'));
|
||||
$oTwigEnv->addFilter(new Twig_SimpleFilter('base64_decode', 'base64_decode'));
|
||||
|
||||
// Filter to enable json decode (encode already exists)
|
||||
// Usage in twig: {{ aSomeArray|json_decode }}
|
||||
$oTwigEnv->addFilter(new Twig_SimpleFilter('json_decode', function ($sJsonString, $bAssoc = false) {
|
||||
return json_decode($sJsonString, $bAssoc);
|
||||
})
|
||||
);
|
||||
|
||||
// Filter to add itopversion to an url
|
||||
$oTwigEnv->addFilter(new Twig_SimpleFilter('add_itop_version', function ($sUrl) {
|
||||
if (strpos($sUrl, '?') === false)
|
||||
{
|
||||
$sUrl = $sUrl."?itopversion=".ITOP_VERSION;
|
||||
}
|
||||
else
|
||||
{
|
||||
$sUrl = $sUrl."&itopversion=".ITOP_VERSION;
|
||||
}
|
||||
|
||||
return $sUrl;
|
||||
}));
|
||||
|
||||
// Filter to add a module's version to an url
|
||||
$oTwigEnv->addFilter(new Twig_SimpleFilter('add_module_version', function ($sUrl, $sModuleName) {
|
||||
$sModuleVersion = utils::GetCompiledModuleVersion($sModuleName);
|
||||
|
||||
if (strpos($sUrl, '?') === false)
|
||||
{
|
||||
$sUrl = $sUrl."?moduleversion=".$sModuleVersion;
|
||||
}
|
||||
else
|
||||
{
|
||||
$sUrl = $sUrl."&moduleversion=".$sModuleVersion;
|
||||
}
|
||||
|
||||
return $sUrl;
|
||||
}));
|
||||
|
||||
// Function to check our current environment
|
||||
// Usage in twig: {% if is_development_environment() %}
|
||||
$oTwigEnv->addFunction(new Twig_SimpleFunction('is_development_environment', function()
|
||||
{
|
||||
return utils::IsDevelopmentEnvironment();
|
||||
}));
|
||||
|
||||
// Function to get configuration parameter
|
||||
// Usage in twig: {{ get_config_parameter('foo') }}
|
||||
$oTwigEnv->addFunction(new Twig_SimpleFunction('get_config_parameter', function($sParamName)
|
||||
{
|
||||
$oConfig = MetaModel::GetConfig();
|
||||
return $oConfig->Get($sParamName);
|
||||
}));
|
||||
|
||||
// Function to get the URL of a static page in a module
|
||||
// Usage in twig: {{ get_static_page_module_url('itop-my-module', 'path-to-my-page') }}
|
||||
$oTwigEnv->addFunction(new Twig_SimpleFunction('get_static_page_module_url', function($sModuleName, $sPage)
|
||||
{
|
||||
return utils::GetAbsoluteUrlModulesRoot().$sModuleName.'/'.$sPage;
|
||||
}));
|
||||
|
||||
// Function to get the URL of a php page in a module
|
||||
// Usage in twig: {{ get_page_module_url('itop-my-module', 'path-to-my-my-page.php') }}
|
||||
$oTwigEnv->addFunction(new Twig_SimpleFunction('get_page_module_url', function($sModuleName, $sPage)
|
||||
{
|
||||
return utils::GetAbsoluteUrlModulePage($sModuleName, $sPage);
|
||||
}));
|
||||
}
|
||||
}
|
||||
@@ -1,23 +1,28 @@
|
||||
<?php
|
||||
// Copyright (C) 2010-2017 Combodo SARL
|
||||
//
|
||||
// This file is part of iTop.
|
||||
//
|
||||
// iTop is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// iTop is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with iTop. If not, see <http://www.gnu.org/licenses/>
|
||||
/**
|
||||
* Copyright (C) 2013-2020 Combodo SARL
|
||||
*
|
||||
* This file is part of iTop.
|
||||
*
|
||||
* iTop is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* iTop is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
*/
|
||||
|
||||
require_once(APPROOT.'/application/webpage.class.inc.php');
|
||||
require_once(APPROOT.'/application/displayblock.class.inc.php');
|
||||
|
||||
/**
|
||||
* Class UIExtKeyWidget
|
||||
* UI wdiget for displaying and editing external keys when
|
||||
* UI widget for displaying and editing external keys when
|
||||
* A simple drop-down list is not enough...
|
||||
*
|
||||
* The layout is the following
|
||||
@@ -54,13 +59,7 @@
|
||||
* | | +--------+ +-----+ | |
|
||||
* | +--------------------------------------------+ |
|
||||
* +------------------------------------------------+
|
||||
* @copyright Copyright (C) 2010-2017 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
require_once(APPROOT.'/application/webpage.class.inc.php');
|
||||
require_once(APPROOT.'/application/displayblock.class.inc.php');
|
||||
|
||||
class UIExtKeyWidget
|
||||
{
|
||||
const ENUM_OUTPUT_FORMAT_CSV = 'csv';
|
||||
@@ -274,7 +273,7 @@ EOF
|
||||
|
||||
// the input for the auto-complete
|
||||
$sHTMLValue .= "<input class=\"field_autocomplete\" type=\"text\" id=\"label_$this->iId\" value=\"$sDisplayValue\"/>";
|
||||
$sHTMLValue .= "<span class=\"field_input_btn\"><img id=\"mini_search_{$this->iId}\" style=\"border:0;vertical-align:middle;cursor:pointer;\" src=\"../images/mini_search.gif?t=".utils::GetCacheBusterTimestamp()."\" onClick=\"oACWidget_{$this->iId}.Search();\"/></span>";
|
||||
$sHTMLValue .= "<span class=\"field_input_btn\"><div class=\"mini_button\" id=\"mini_search_{$this->iId}\" onClick=\"oACWidget_{$this->iId}.Search();\"><i class=\"fas fa-search\"></i></div></span>";
|
||||
|
||||
// another hidden input to store & pass the object's Id
|
||||
$sHTMLValue .= "<input type=\"hidden\" id=\"$this->iId\" name=\"{$sAttrFieldPrefix}{$sFieldName}\" value=\"".htmlentities($value, ENT_QUOTES, 'UTF-8')."\" />\n";
|
||||
@@ -298,7 +297,7 @@ EOF
|
||||
}
|
||||
if ($bExtensions && MetaModel::IsHierarchicalClass($this->sTargetClass) !== false)
|
||||
{
|
||||
$sHTMLValue .= "<span class=\"field_input_btn\"><img id=\"mini_tree_{$this->iId}\" style=\"border:0;vertical-align:middle;cursor:pointer;\" src=\"../images/mini_tree.gif?t=".utils::GetCacheBusterTimestamp()."\" onClick=\"oACWidget_{$this->iId}.HKDisplay();\"/></span>";
|
||||
$sHTMLValue .= "<span class=\"field_input_btn\"><div class=\"mini_button\" id=\"mini_tree_{$this->iId}\" onClick=\"oACWidget_{$this->iId}.HKDisplay();\"><i class=\"fas fa-sitemap\"></i></div></span>";
|
||||
$oPage->add_ready_script(
|
||||
<<<EOF
|
||||
if ($('#ac_tree_{$this->iId}').length == 0)
|
||||
@@ -312,7 +311,7 @@ EOF
|
||||
{
|
||||
$sCallbackName = (MetaModel::IsAbstract($this->sTargetClass)) ? 'SelectObjectClass' : 'CreateObject';
|
||||
|
||||
$sHTMLValue .= "<span class=\"field_input_btn\"><img id=\"mini_add_{$this->iId}\" style=\"border:0;vertical-align:middle;cursor:pointer;\" src=\"../images/mini_add.gif?t=".utils::GetCacheBusterTimestamp()."\" onClick=\"oACWidget_{$this->iId}.{$sCallbackName}();\"/></span>";
|
||||
$sHTMLValue .= "<span class=\"field_input_btn\"><div class=\"mini_button\" id=\"mini_add_{$this->iId}\" onClick=\"oACWidget_{$this->iId}.{$sCallbackName}();\"><i class=\"fas fa-plus\"></i></div></span>";
|
||||
$oPage->add_ready_script(
|
||||
<<<EOF
|
||||
if ($('#ajax_{$this->iId}').length == 0)
|
||||
@@ -578,8 +577,21 @@ EOF
|
||||
$oNewObj->UpdateObjectFromArg('default');
|
||||
|
||||
$sDialogTitle = '';
|
||||
$oPage->add('<div id="ac_create_'.$this->iId.'"><div class="wizContainer" style="vertical-align:top;"><div id="dcr_'.$this->iId.'">');
|
||||
$oPage->add("<h1>".MetaModel::GetClassIcon($this->sTargetClass)." ".Dict::Format('UI:CreationTitle_Class', MetaModel::GetName($this->sTargetClass))."</h1>\n");
|
||||
$sClassLabel = MetaModel::GetName($this->sTargetClass);
|
||||
$sClassIcon = MetaModel::GetClassIcon($this->sTargetClass);
|
||||
$sObjClass = get_class($oNewObj);
|
||||
$sObjKey = $oNewObj->GetKey();
|
||||
$sHeaderTitle = Dict::Format('UI:CreationTitle_Class', $sClassLabel);
|
||||
$oPage->add(<<<HTML
|
||||
<div id="ac_create_{$this->iId}">
|
||||
<!-- Beginning of object-details -->
|
||||
<div class="object-details" data-object-class="$sObjClass" data-object-id="$sObjKey" data-object-mode="create">
|
||||
<!-- Beginning of wizContainer -->
|
||||
<div class="wizContainer" style="vertical-align:top;">
|
||||
<div id="dcr_{$this->iId}">
|
||||
<h1>$sClassIcon $sHeaderTitle</h1>
|
||||
HTML
|
||||
);
|
||||
$aFieldsFlags = array();
|
||||
$aFieldsComments = array();
|
||||
foreach(MetaModel::ListAttributeDefs($this->sTargetClass) as $sAttCode => $oAttDef)
|
||||
@@ -591,7 +603,13 @@ EOF
|
||||
}
|
||||
}
|
||||
cmdbAbstractObject::DisplayCreationForm($oPage, $this->sTargetClass, $oNewObj, array(), array('formPrefix' => $this->iId, 'noRelations' => true, 'fieldsFlags' => $aFieldsFlags, 'fieldsComments' => $aFieldsComments));
|
||||
$oPage->add('</div></div></div>');
|
||||
$oPage->add(<<<HTML
|
||||
</div>
|
||||
</div><!-- End of wizContainer -->
|
||||
</div><!-- End of object-details -->
|
||||
</div>
|
||||
HTML
|
||||
);
|
||||
// $oPage->add_ready_script("\$('#ac_create_$this->iId').dialog({ width: $(window).width()*0.8, height: 'auto', autoOpen: false, modal: true, title: '$sDialogTitle'});\n");
|
||||
$oPage->add_ready_script("\$('#ac_create_$this->iId').dialog({ width: 'auto', height: 'auto', maxHeight: $(window).height() - 50, autoOpen: false, modal: true, title: '$sDialogTitle'});\n");
|
||||
$oPage->add_ready_script("$('#dcr_{$this->iId} form').removeAttr('onsubmit');");
|
||||
@@ -618,15 +636,22 @@ EOF
|
||||
$oSet->SetShowObsoleteData(utils::ShowObsoleteData());
|
||||
|
||||
$sHKAttCode = MetaModel::IsHierarchicalClass($this->sTargetClass);
|
||||
$this->DumpTree($oPage, $oSet, $sHKAttCode, $currValue);
|
||||
$bHasChildLeafs = $this->DumpTree($oPage, $oSet, $sHKAttCode, $currValue);
|
||||
|
||||
$oPage->add('</td></tr></table>');
|
||||
$oPage->add('</div>');
|
||||
|
||||
if ($bHasChildLeafs)
|
||||
{
|
||||
$oPage->add('<div class="treecontrol" id="treecontrolid"><a href="?#">'.Dict::S("UI:Treeview:CollapseAll").'</a> | <a href="?#">'.Dict::S("UI:Treeview:ExpandAll").'</a></div>');
|
||||
}
|
||||
|
||||
$oPage->add("<input type=\"button\" id=\"btn_cancel_{$this->iId}\" value=\"".Dict::S('UI:Button:Cancel')."\" onClick=\"$('#dlg_tree_{$this->iId}').dialog('close');\"> ");
|
||||
$oPage->add("<input type=\"button\" id=\"btn_ok_{$this->iId}\" value=\"".Dict::S('UI:Button:Ok')."\" onClick=\"oACWidget_{$this->iId}.DoHKOk();\">");
|
||||
|
||||
$oPage->add('</div></div>');
|
||||
$oPage->add_ready_script("\$('#tree_$this->iId ul').treeview();\n");
|
||||
|
||||
$oPage->add_ready_script("\$('#tree_$this->iId ul').treeview({ control: '#treecontrolid', persist: 'false'});\n");
|
||||
$oPage->add_ready_script("\$('#dlg_tree_$this->iId').dialog({ width: 'auto', height: 'auto', autoOpen: true, modal: true, title: '$sDialogTitle', resizeStop: oACWidget_{$this->iId}.OnHKResize, close: oACWidget_{$this->iId}.OnHKClose });\n");
|
||||
}
|
||||
|
||||
@@ -655,6 +680,18 @@ EOF
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param WebPage $oP
|
||||
* @param \DBObjectSet $oSet
|
||||
* @param string $sParentAttCode
|
||||
* @param string $currValue
|
||||
*
|
||||
* @return bool true if there are at least one child leaf, false if only roots nodes are present
|
||||
* @throws \ArchivedObjectException
|
||||
* @throws \CoreException
|
||||
* @throws \CoreUnexpectedValue
|
||||
* @throws \MySQLException
|
||||
*/
|
||||
function DumpTree($oP, $oSet, $sParentAttCode, $currValue)
|
||||
{
|
||||
$aTree = array();
|
||||
@@ -683,6 +720,9 @@ EOF
|
||||
{
|
||||
$this->DumpNodes($oP, $iRootId, $aTree, $aNodes, $currValue);
|
||||
}
|
||||
|
||||
$bHasOnlyRootNodes = (count($aTree) === 1);
|
||||
return !$bHasOnlyRootNodes;
|
||||
}
|
||||
|
||||
function DumpNodes($oP, $iRootId, $aTree, $aNodes, $currValue)
|
||||
@@ -710,7 +750,7 @@ EOF
|
||||
$sSelect = '<input id="input_'.$fUniqueId.'_'.$aNodes[$id]->GetKey().'" type="radio" value="'.$aNodes[$id]->GetKey().'" name="selectObject" '.$sChecked.'> ';
|
||||
}
|
||||
}
|
||||
$oP->add('<li>'.$sSelect.'<label for="input_'.$fUniqueId.'_'.$aNodes[$id]->GetKey().'">'.$aNodes[$id]->GetName().'</label>');
|
||||
$oP->add('<li class="closed">'.$sSelect.'<label for="input_'.$fUniqueId.'_'.$aNodes[$id]->GetKey().'">'.$aNodes[$id]->GetName().'</label>');
|
||||
$this->DumpNodes($oP, $id, $aTree, $aNodes, $currValue);
|
||||
$oP->add("</li>\n");
|
||||
}
|
||||
|
||||
@@ -74,7 +74,7 @@ class UIHTMLEditorWidget
|
||||
$sLanguage = strtolower(trim(UserRights::GetUserLanguage()));
|
||||
$aConfig['language'] = $sLanguage;
|
||||
$aConfig['contentsLanguage'] = $sLanguage;
|
||||
$aConfig['extraPlugins'] = 'disabler';
|
||||
$aConfig['extraPlugins'] = 'disabler,codesnippet';
|
||||
$sWidthSpec = addslashes(trim($this->m_oAttDef->GetWidth()));
|
||||
if ($sWidthSpec != '')
|
||||
{
|
||||
|
||||
@@ -346,7 +346,7 @@ EOF
|
||||
* @throws \CoreException
|
||||
* @throws \DictExceptionMissingString
|
||||
*/
|
||||
public function Display(WebPage $oPage, $oValue, $aArgs = array(), $sFormPrefix, $oCurrentObj)
|
||||
public function Display(WebPage $oPage, $oValue, $aArgs, $sFormPrefix, $oCurrentObj)
|
||||
{
|
||||
$sHtmlValue = '';
|
||||
$sHtmlValue .= "<div id=\"linkedset_{$this->m_sAttCode}{$this->m_sNameSuffix}\">\n";
|
||||
|
||||
@@ -34,7 +34,7 @@ require_once(APPROOT.'/core/userrights.class.inc.php');
|
||||
*/
|
||||
class appUserPreferences extends DBObject
|
||||
{
|
||||
static $oUserPrefs = null; // Local cache
|
||||
private static $oUserPrefs = null; // Local cache
|
||||
|
||||
/**
|
||||
* Get the value of the given property/preference
|
||||
@@ -43,7 +43,7 @@ class appUserPreferences extends DBObject
|
||||
* @param string $sDefaultValue The default value
|
||||
* @return string The value of the property for the current user
|
||||
*/
|
||||
static function GetPref($sCode, $sDefaultValue)
|
||||
public static function GetPref($sCode, $sDefaultValue)
|
||||
{
|
||||
if (self::$oUserPrefs == null)
|
||||
{
|
||||
@@ -65,7 +65,7 @@ class appUserPreferences extends DBObject
|
||||
* @param string $sCode Code/Name of the property/preference to set
|
||||
* @param string $sValue Value to set
|
||||
*/
|
||||
static function SetPref($sCode, $sValue)
|
||||
public static function SetPref($sCode, $sValue)
|
||||
{
|
||||
if (self::$oUserPrefs == null)
|
||||
{
|
||||
@@ -83,13 +83,13 @@ class appUserPreferences extends DBObject
|
||||
self::Save();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Clears the value for a given preference (or list of preferences that matches a pattern), and updates the database
|
||||
* @param string $sPattern Code/Pattern of the properties/preferences to reset
|
||||
* @param string $sCodeOrPattern Code/Pattern of the properties/preferences to reset
|
||||
* @param boolean $bPattern Whether or not the supplied code is a PCRE pattern
|
||||
*/
|
||||
static function UnsetPref($sCodeOrPattern, $bPattern = false)
|
||||
public static function UnsetPref($sCodeOrPattern, $bPattern = false)
|
||||
{
|
||||
if (self::$oUserPrefs == null)
|
||||
{
|
||||
@@ -124,7 +124,7 @@ class appUserPreferences extends DBObject
|
||||
* Call this function to get all the preferences for the user, packed as a JSON object
|
||||
* @return string JSON representation of the preferences
|
||||
*/
|
||||
static function GetAsJSON()
|
||||
public static function GetAsJSON()
|
||||
{
|
||||
if (self::$oUserPrefs == null)
|
||||
{
|
||||
@@ -137,19 +137,19 @@ class appUserPreferences extends DBObject
|
||||
/**
|
||||
* Call this function if the user has changed (like when doing a logoff...)
|
||||
*/
|
||||
static public function ResetPreferences()
|
||||
public static function ResetPreferences()
|
||||
{
|
||||
self::$oUserPrefs = null;
|
||||
}
|
||||
/**
|
||||
* Call this function to ERASE all the preferences from the current user
|
||||
*/
|
||||
static public function ClearPreferences()
|
||||
public static function ClearPreferences()
|
||||
{
|
||||
self::$oUserPrefs = null;
|
||||
}
|
||||
|
||||
static protected function Save()
|
||||
protected static function Save()
|
||||
{
|
||||
if (self::$oUserPrefs != null)
|
||||
{
|
||||
@@ -166,7 +166,7 @@ class appUserPreferences extends DBObject
|
||||
* Loads the preferences for the current user, creating the record in the database
|
||||
* if needed
|
||||
*/
|
||||
static protected function Load()
|
||||
protected static function Load()
|
||||
{
|
||||
if (self::$oUserPrefs != null) return;
|
||||
$oSearch = new DBObjectSearch('appUserPreferences');
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -273,10 +273,6 @@ class WizardHelper
|
||||
static public function FromJSON($sJSON)
|
||||
{
|
||||
$oWizHelper = new WizardHelper();
|
||||
if (get_magic_quotes_gpc())
|
||||
{
|
||||
$sJSON = stripslashes($sJSON);
|
||||
}
|
||||
$aData = json_decode($sJSON, true); // true means hash array instead of object
|
||||
$oWizHelper->m_aData = $aData;
|
||||
return $oWizHelper;
|
||||
|
||||
@@ -174,7 +174,7 @@ Class XLSXWriter
|
||||
fwrite($fd,'<c r="'.$cell.'" s="'.$s.'" t="n"><v>'.self::convert_date_time($value).'</v></c>');
|
||||
} else if ($value==''){
|
||||
fwrite($fd,'<c r="'.$cell.'" s="'.$s.'"/>');
|
||||
} else if ($value{0}=='='){
|
||||
} else if ($value[0]=='='){
|
||||
fwrite($fd,'<c r="'.$cell.'" s="'.$s.'" t="s"><f>'.self::xmlspecialchars($value).'</f></c>');
|
||||
} else if ($value!==''){
|
||||
fwrite($fd,'<c r="'.$cell.'" s="'.$s.'" t="s"><v>'.self::xmlspecialchars($this->setSharedString($value)).'</v></c>');
|
||||
|
||||
@@ -42,7 +42,7 @@ class XMLPage extends WebPage
|
||||
parent::__construct($s_title);
|
||||
$this->m_bPassThrough = $bPassThrough;
|
||||
$this->m_bHeaderSent = false;
|
||||
$this->add_header("Content-type: text/xml; charset=utf-8");
|
||||
$this->add_header("Content-type: text/xml; charset=".self::PAGES_CHARSET);
|
||||
$this->add_header('Cache-control: no-cache, no-store, must-revalidate');
|
||||
$this->add_header('Pragma: no-cache');
|
||||
$this->add_header('Expires: 0');
|
||||
@@ -57,7 +57,8 @@ class XMLPage extends WebPage
|
||||
// Get the unexpected output but do nothing with it
|
||||
$sTrash = $this->ob_get_clean_safe();
|
||||
|
||||
$this->s_content = "<?xml version=\"1.0\" encoding=\"UTF-8\"?".">\n".trim($this->s_content);
|
||||
$sCharset = self::PAGES_CHARSET;
|
||||
$this->s_content = "<?xml version=\"1.0\" encoding=\"$sCharset\"?".">\n".trim($this->s_content);
|
||||
$this->add_header("Content-Length: ".strlen($this->s_content));
|
||||
foreach($this->a_headers as $s_header)
|
||||
{
|
||||
@@ -90,7 +91,8 @@ class XMLPage extends WebPage
|
||||
{
|
||||
header($s_header);
|
||||
}
|
||||
echo "<?xml version=\"1.0\" encoding=\"UTF-8\"?".">\n";
|
||||
$sCharset = self::PAGES_CHARSET;
|
||||
echo "<?xml version=\"1.0\" encoding=\"$sCharset\"?".">\n";
|
||||
echo trim($s_captured_output);
|
||||
echo trim($this->s_content);
|
||||
echo $sText;
|
||||
|
||||
@@ -2,14 +2,5 @@
|
||||
|
||||
define('APPROOT', dirname(__FILE__).'/');
|
||||
define('APPCONF', APPROOT.'conf/');
|
||||
define('ITOP_DEFAULT_ENV', 'production');
|
||||
|
||||
if (function_exists('microtime'))
|
||||
{
|
||||
$fItopStarted = microtime(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
$fItopStarted = 1000 * time();
|
||||
}
|
||||
?>
|
||||
require_once APPROOT.'bootstrap.inc.php';
|
||||
|
||||
93
bootstrap.inc.php
Normal file
93
bootstrap.inc.php
Normal file
@@ -0,0 +1,93 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Copyright (C) 2013-2019 Combodo SARL
|
||||
*
|
||||
* This file is part of iTop.
|
||||
*
|
||||
* iTop is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* iTop is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
*/
|
||||
|
||||
define('ITOP_DEFAULT_ENV', 'production');
|
||||
define('MAINTENANCE_MODE_FILE', APPROOT.'data/.maintenance');
|
||||
define('READONLY_MODE_FILE', APPROOT.'data/.readonly');
|
||||
|
||||
if (function_exists('microtime'))
|
||||
{
|
||||
$fItopStarted = microtime(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
$fItopStarted = 1000 * time();
|
||||
}
|
||||
|
||||
if (! isset($GLOBALS['bBypassAutoload']) || $GLOBALS['bBypassAutoload'] == false)
|
||||
{
|
||||
require_once APPROOT.'/lib/autoload.php';
|
||||
}
|
||||
|
||||
//
|
||||
// Maintenance mode
|
||||
//
|
||||
|
||||
// Use 'maintenance' parameter to bypass maintenance mode
|
||||
if (!isset($bBypassMaintenance))
|
||||
{
|
||||
$bBypassMaintenance = isset($_REQUEST['maintenance']) ? boolval($_REQUEST['maintenance']) : false;
|
||||
}
|
||||
|
||||
if (file_exists(MAINTENANCE_MODE_FILE) && !$bBypassMaintenance)
|
||||
{
|
||||
$sTitle = 'Maintenance';
|
||||
$sMessage = 'This application is currently under maintenance.';
|
||||
|
||||
http_response_code(503);
|
||||
// Display message depending on the request
|
||||
include(APPROOT.'application/maintenancemsg.php');
|
||||
$sSAPIName = strtoupper(trim(php_sapi_name()));
|
||||
|
||||
switch (true)
|
||||
{
|
||||
case isset($_SERVER['REQUEST_URI']) && EndsWith($_SERVER['REQUEST_URI'], '/pages/ajax.searchform.php'):
|
||||
_MaintenanceHtmlMessage($sMessage);
|
||||
break;
|
||||
|
||||
case $sSAPIName == 'CLI':
|
||||
case array_key_exists('HTTP_X_COMBODO_AJAX', $_SERVER):
|
||||
case isset($_SERVER['REQUEST_URI']) && (strpos($_SERVER['REQUEST_URI'], '/webservices/soapserver.php') !== false):
|
||||
case isset($_SERVER['REQUEST_URI']) && (strpos($_SERVER['REQUEST_URI'], '/webservices/export-v2.php') !== false):
|
||||
_MaintenanceTextMessage($sMessage);
|
||||
break;
|
||||
|
||||
case isset($_SERVER['REQUEST_URI']) && (strpos($_SERVER['REQUEST_URI'], '/webservices/rest.php') !== false):
|
||||
case isset($_SERVER['CONTENT_TYPE']) && ($_SERVER['CONTENT_TYPE'] == 'application/json'):
|
||||
_MaintenanceJsonMessage($sTitle, $sMessage);
|
||||
break;
|
||||
|
||||
default:
|
||||
_MaintenanceSetupPageMessage($sTitle, $sMessage);
|
||||
break;
|
||||
}
|
||||
exit();
|
||||
}
|
||||
|
||||
/**
|
||||
* helper to test if a string ends with another
|
||||
* @param $haystack
|
||||
* @param $needle
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
function EndsWith($haystack, $needle) {
|
||||
return substr_compare($haystack, $needle, -strlen($needle)) === 0;
|
||||
}
|
||||
@@ -1,13 +1,31 @@
|
||||
{
|
||||
"type": "project",
|
||||
"license": "AGPLv3",
|
||||
"require": {
|
||||
"php": ">=5.6.0",
|
||||
"ext-soap": "*",
|
||||
"ext-json": "*",
|
||||
"ext-zip": "*",
|
||||
"ext-mysqli": "*",
|
||||
"ext-ctype": "*",
|
||||
"ext-dom": "*",
|
||||
"ext-gd": "*",
|
||||
"ext-iconv": "*",
|
||||
"ext-gd": "*"
|
||||
"ext-json": "*",
|
||||
"ext-mysqli": "*",
|
||||
"ext-soap": "*",
|
||||
"combodo/tcpdf": "6.3.5",
|
||||
"nikic/php-parser": "^3.1",
|
||||
"pear/archive_tar": "1.4.10",
|
||||
"pelago/emogrifier": "2.1.0",
|
||||
"scssphp/scssphp": "1.0.6",
|
||||
"swiftmailer/swiftmailer": "5.4.12",
|
||||
"symfony/console": "3.4.*",
|
||||
"symfony/dotenv": "3.4.*",
|
||||
"symfony/framework-bundle": "3.4.*",
|
||||
"symfony/polyfill-php70": "1.*",
|
||||
"symfony/twig-bundle": "3.4.*",
|
||||
"symfony/yaml": "3.4.*"
|
||||
},
|
||||
"require-dev": {
|
||||
"symfony/stopwatch": "3.4.*",
|
||||
"symfony/web-profiler-bundle": "3.4.*"
|
||||
},
|
||||
"suggest": {
|
||||
"ext-libsodium": "Required to use the AttributeEncryptedString.",
|
||||
@@ -20,6 +38,48 @@
|
||||
"config": {
|
||||
"platform": {
|
||||
"php": "5.6.0"
|
||||
},
|
||||
"vendor-dir": "lib",
|
||||
"preferred-install": {
|
||||
"*": "dist"
|
||||
},
|
||||
"sort-packages": true,
|
||||
"classmap-authoritative": true
|
||||
},
|
||||
"autoload": {
|
||||
"classmap": [
|
||||
"core",
|
||||
"application",
|
||||
"sources/application",
|
||||
"sources/Composer",
|
||||
"sources/Controller"
|
||||
],
|
||||
"exclude-from-classmap": [
|
||||
"core/dbobjectsearch.class.php",
|
||||
"core/legacy/dbobjectsearchlegacy.class.php",
|
||||
"core/querybuildercontext.class.inc.php",
|
||||
"core/legacy/querybuildercontextlegacy.class.inc.php",
|
||||
"core/querybuilderexpressions.class.inc.php",
|
||||
"core/legacy/querybuilderexpressionslegacy.class.inc.php",
|
||||
"application/loginform.class.inc.php",
|
||||
"application/loginbasic.class.inc.php",
|
||||
"application/logindefault.class.inc.php",
|
||||
"application/loginexternal.class.inc.php",
|
||||
"application/loginurl.class.inc.php"
|
||||
]
|
||||
},
|
||||
"conflict": {
|
||||
"symfony/symfony": "*"
|
||||
},
|
||||
"extra": {
|
||||
"symfony": {
|
||||
"allow-contrib": false,
|
||||
"require": "3.4.*"
|
||||
}
|
||||
},
|
||||
"scripts": {
|
||||
"post-install-cmd": ["@rmDeniedTestDir"],
|
||||
"post-update-cmd": ["@rmDeniedTestDir"],
|
||||
"rmDeniedTestDir": "@php .make/composer/rmDeniedTestDir.php"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
3870
composer.lock
generated
3870
composer.lock
generated
File diff suppressed because it is too large
Load Diff
2
composer.readme
Normal file
2
composer.readme
Normal file
@@ -0,0 +1,2 @@
|
||||
To regenerate the autoload, run:
|
||||
composer dump-autoload -a
|
||||
2
conf/index.php
Normal file
2
conf/index.php
Normal file
@@ -0,0 +1,2 @@
|
||||
<?php
|
||||
echo 'Access denied';
|
||||
105
contributing.md
105
contributing.md
@@ -1,105 +0,0 @@
|
||||
# Contributing to iTop
|
||||
|
||||
You want to contribute to iTop? Many thanks to you! 🎉 👍
|
||||
|
||||
Here are some guidelines that will help us integrate your work!
|
||||
|
||||
|
||||
## Contributions
|
||||
|
||||
### Subjects
|
||||
You are welcome to create pull requests on any of those subjects:
|
||||
|
||||
* 🐛 `:bug:` bug fix
|
||||
* 🔒 `:lock:` security
|
||||
* 🌐 `:globe_with_meridians:` translation / i18n / l10n
|
||||
|
||||
If you want to implement a **new feature**, please [create a corresponding ticket](https://sourceforge.net/p/itop/tickets/new/) for review.
|
||||
If you ever want to begin implementation, do so in a fork, and add a link to the corresponding commits in the ticket.
|
||||
|
||||
### License
|
||||
iTop is distributed under the AGPL-3.0 license (see the [license.txt] file),
|
||||
your code must comply with this license.
|
||||
|
||||
If you want to use another license, you may [create an extension][wiki new ext].
|
||||
|
||||
[license.txt]: https://github.com/Combodo/iTop/blob/develop/license.txt
|
||||
[wiki new ext]: https://www.itophub.io/wiki/page?id=latest%3Acustomization%3Astart#by_writing_your_own_extension
|
||||
|
||||
|
||||
## Branch model
|
||||
|
||||
TL;DR:
|
||||
> **create a fork from iTop main repository,
|
||||
> create a branch based on either release branch if present, or develop otherwise**
|
||||
|
||||
We are using the [GitFlow](https://nvie.com/posts/a-successful-git-branching-model/) branch model. That means we have in our repo those
|
||||
main branches:
|
||||
|
||||
- develop: ongoing development version
|
||||
- release/\*: if present, that means we are working on a beta version
|
||||
- master: previous stable version
|
||||
|
||||
For example, if no beta version is currently ongoing we could have:
|
||||
|
||||
- develop containing future 2.8.0 version
|
||||
- master containing 2.7.x maintenance version
|
||||
|
||||
In this example, when 2.8.0-beta is shipped that will become:
|
||||
|
||||
- develop: future 2.9.0 version
|
||||
- release/2.8: 2.8.0-beta
|
||||
- master: 2.7.x maintenance version
|
||||
|
||||
And when 2.8.0 final will be out:
|
||||
|
||||
- develop: future 2.9.0 version
|
||||
- master: 2.8.x maintenance version
|
||||
- support/2.7 : 2.7.x maintenance version
|
||||
|
||||
|
||||
## Coding
|
||||
|
||||
### PHP styleguide
|
||||
|
||||
Please follow [our guidelines](https://www.itophub.io/wiki/page?id=latest%3Acustomization%3Acoding_standards).
|
||||
|
||||
### 🌐 Translations
|
||||
|
||||
A [dedicated page](https://www.itophub.io/wiki/page?id=latest%3Acustomization%3Atranslation) is available in the official wiki.
|
||||
|
||||
### Tests
|
||||
|
||||
Please create tests that covers as much as possible the code you're submitting.
|
||||
|
||||
Our tests are located in the `test/` directory, containing a PHPUnit config file : `phpunit.xml.dist`.
|
||||
|
||||
### Git Commit Messages
|
||||
|
||||
* Describe the functional change instead of the technical modifications
|
||||
* Use the present tense ("Add feature" not "Added feature")
|
||||
* Use the imperative mood ("Move cursor to..." not "Moves cursor to...")
|
||||
* Limit the first line to 72 characters or less
|
||||
* Please start the commit message with an applicable emoji code (following the [Gitmoji guide](https://gitmoji.carloscuesta.me/)). For example :
|
||||
* 🌐 `:globe_with_meridians:` for translations
|
||||
* 🎨 `:art:` when improving the format/structure of the code
|
||||
* ⚡️ `:zap:` when improving performance
|
||||
* 🐛 `:bug:` when fixing a bug
|
||||
* 🔥 `:fire:` when removing code or files
|
||||
* 💚 `:green_heart:` when fixing the CI build
|
||||
* ✅ `:white_check_mark:` when adding tests
|
||||
* 🔒 `:lock:` when dealing with security
|
||||
* ⬆️ `:arrow_up:` when upgrading dependencies
|
||||
* ⬇️ `:arrow_down:` when downgrading dependencies
|
||||
* ♻️ `:recycle:` code refactoring
|
||||
* 💄 `:lipstick:` Updating the UI and style files.
|
||||
|
||||
## Pull request
|
||||
|
||||
When your code is working, please:
|
||||
|
||||
* stash as much as possible your commits,
|
||||
* rebase your branch on our repo last commit,
|
||||
* create a pull request.
|
||||
|
||||
Detailed procedure to work on fork and create PR is available [in GitHub help pages](https://help.github.com/articles/creating-a-pull-request-from-a-fork/).
|
||||
@@ -457,7 +457,7 @@ class Str
|
||||
public static function gpc2pure($gpc)
|
||||
{
|
||||
if (ini_get('magic_quotes_sybase')) $pure = str_replace("''", "'", $gpc);
|
||||
else $pure = get_magic_quotes_gpc() ? stripslashes($gpc) : $gpc;
|
||||
else $pure = $gpc;
|
||||
return $pure;
|
||||
}
|
||||
public static function html2pure($html)
|
||||
|
||||
@@ -166,7 +166,14 @@ class apcFile
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!@unlink($sCache))
|
||||
if (is_file($sCache))
|
||||
{
|
||||
if (!@unlink($sCache))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@@ -209,8 +216,14 @@ class apcFile
|
||||
return false;
|
||||
}
|
||||
|
||||
@unlink(self::GetCacheFileName($sKey));
|
||||
@unlink(self::GetCacheFileName('-'.$sKey));
|
||||
if (is_file(self::GetCacheFileName($sKey)))
|
||||
{
|
||||
@unlink(self::GetCacheFileName($sKey));
|
||||
}
|
||||
if (is_file(self::GetCacheFileName('-'.$sKey)))
|
||||
{
|
||||
@unlink(self::GetCacheFileName('-'.$sKey));
|
||||
}
|
||||
if ($iTTL > 0)
|
||||
{
|
||||
// hint for ttl management
|
||||
@@ -312,6 +325,10 @@ class apcFile
|
||||
*/
|
||||
static protected function ReadCacheLocked($sFilename)
|
||||
{
|
||||
if (!is_file($sFilename))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
$file = @fopen($sFilename, 'r');
|
||||
if ($file === false)
|
||||
{
|
||||
|
||||
@@ -1,335 +0,0 @@
|
||||
<?php
|
||||
// Copyright (C) 2010-2012 Combodo SARL
|
||||
//
|
||||
// This file is part of iTop.
|
||||
//
|
||||
// iTop is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// iTop is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with iTop. If not, see <http://www.gnu.org/licenses/>
|
||||
|
||||
|
||||
/**
|
||||
* Utility to import/export the DB from/to a ZIP file
|
||||
*
|
||||
* @copyright Copyright (C) 2010-2012 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* iTopArchive a class to manipulate (read/write) iTop archives with their catalog
|
||||
* Each iTop archive is a zip file that contains (at the root of the archive)
|
||||
* a file called catalog.xml holding the description of the archive
|
||||
*/
|
||||
class iTopArchive
|
||||
{
|
||||
const read = 0;
|
||||
const create = ZipArchive::CREATE;
|
||||
|
||||
protected $m_sZipPath;
|
||||
protected $m_oZip;
|
||||
protected $m_sVersion;
|
||||
protected $m_sTitle;
|
||||
protected $m_sDescription;
|
||||
protected $m_aPackages;
|
||||
protected $m_aErrorMessages;
|
||||
|
||||
/**
|
||||
* Construct an iTopArchive object
|
||||
* @param $sArchivePath string The full path the archive file
|
||||
* @param $iMode integrer Either iTopArchive::read for reading an existing archive or iTopArchive::create for creating a new one. Updating is not supported (yet)
|
||||
*/
|
||||
public function __construct($sArchivePath, $iMode = iTopArchive::read)
|
||||
{
|
||||
$this->m_sZipPath = $sArchivePath;
|
||||
$this->m_oZip = new ZipArchive();
|
||||
$this->m_oZip->open($this->m_sZipPath, $iMode);
|
||||
$this->m_aErrorMessages = array();
|
||||
$this->m_sVersion = '1.0';
|
||||
$this->m_sTitle = '';
|
||||
$this->m_sDescription = '';
|
||||
$this->m_aPackages = array();
|
||||
}
|
||||
|
||||
public function SetTitle($sTitle)
|
||||
{
|
||||
$this->m_sTitle = $sTitle;
|
||||
}
|
||||
|
||||
public function SetDescription($sDescription)
|
||||
{
|
||||
$this->m_sDescription = $sDescription;
|
||||
}
|
||||
|
||||
public function GetTitle()
|
||||
{
|
||||
return $this->m_sTitle;
|
||||
}
|
||||
|
||||
public function GetDescription()
|
||||
{
|
||||
return $this->m_sDescription;
|
||||
}
|
||||
|
||||
public function GetPackages()
|
||||
{
|
||||
return $this->m_aPackages;
|
||||
}
|
||||
|
||||
public function __destruct()
|
||||
{
|
||||
$this->m_oZip->close();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the error message explaining the latest error encountered
|
||||
* @return array All the error messages encountered during the validation
|
||||
*/
|
||||
public function GetErrors()
|
||||
{
|
||||
return $this->m_aErrorMessages;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read the catalog from the archive (zip) file
|
||||
* @param sPath string Path the the zip file
|
||||
* @return boolean True in case of success, false otherwise
|
||||
*/
|
||||
public function ReadCatalog()
|
||||
{
|
||||
if ($this->IsValid())
|
||||
{
|
||||
$sXmlCatalog = $this->m_oZip->getFromName('catalog.xml');
|
||||
$oParser = xml_parser_create();
|
||||
xml_parse_into_struct($oParser, $sXmlCatalog, $aValues, $aIndexes);
|
||||
xml_parser_free($oParser);
|
||||
|
||||
$iIndex = $aIndexes['ARCHIVE'][0];
|
||||
$this->m_sVersion = $aValues[$iIndex]['attributes']['VERSION'];
|
||||
$iIndex = $aIndexes['TITLE'][0];
|
||||
$this->m_sTitle = $aValues[$iIndex]['value'];
|
||||
$iIndex = $aIndexes['DESCRIPTION'][0];
|
||||
if (array_key_exists('value', $aValues[$iIndex]))
|
||||
{
|
||||
// #@# implement a get_array_value(array, key, default) ?
|
||||
$this->m_sDescription = $aValues[$iIndex]['value'];
|
||||
}
|
||||
|
||||
foreach($aIndexes['PACKAGE'] as $iIndex)
|
||||
{
|
||||
$this->m_aPackages[$aValues[$iIndex]['attributes']['HREF']] = array( 'type' => $aValues[$iIndex]['attributes']['TYPE'], 'title'=> $aValues[$iIndex]['attributes']['TITLE'], 'description' => $aValues[$iIndex]['value']);
|
||||
}
|
||||
|
||||
//echo "Archive path: {$this->m_sZipPath}<br/>\n";
|
||||
//echo "Archive format version: {$this->m_sVersion}<br/>\n";
|
||||
//echo "Title: {$this->m_sTitle}<br/>\n";
|
||||
//echo "Description: {$this->m_sDescription}<br/>\n";
|
||||
//foreach($this->m_aPackages as $aFile)
|
||||
//{
|
||||
// echo "{$aFile['title']} ({$aFile['type']}): {$aFile['description']}<br/>\n";
|
||||
//}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public function WriteCatalog()
|
||||
{
|
||||
$sXml = "<?xml version=\"1.0\" encoding=\"utf-8\"?".">\n"; // split the XML closing tag that disturbs PSPad's syntax coloring
|
||||
$sXml .= "<archive version=\"1.0\">\n";
|
||||
$sXml .= "<title>{$this->m_sTitle}</title>\n";
|
||||
$sXml .= "<description>{$this->m_sDescription}</description>\n";
|
||||
foreach($this->m_aPackages as $sFileName => $aFile)
|
||||
{
|
||||
$sXml .= "<package title=\"{$aFile['title']}\" type=\"{$aFile['type']}\" href=\"$sFileName\">{$aFile['description']}</package>\n";
|
||||
}
|
||||
$sXml .= "</archive>";
|
||||
$this->m_oZip->addFromString('catalog.xml', $sXml);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a package to the archive
|
||||
* @param string $sExternalFilePath The path to the file to be added to the archive as a package (directories are not yet implemented)
|
||||
* @param string $sFilePath The name of the file inside the archive
|
||||
* @param string $sTitle A short title for this package
|
||||
* @param string $sType Type of the package. SQL scripts must be of type 'text/sql'
|
||||
* @param string $sDescription A longer description of the purpose of this package
|
||||
* @return none
|
||||
*/
|
||||
public function AddPackage($sExternalFilePath, $sFilePath, $sTitle, $sType, $sDescription)
|
||||
{
|
||||
$this->m_aPackages[$sFilePath] = array('title' => $sTitle, 'type' => $sType, 'description' => $sDescription);
|
||||
$this->m_oZip->addFile($sExternalFilePath, $sFilePath);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads the contents of the given file from the archive
|
||||
* @param string $sFileName The path to the file inside the archive
|
||||
* @return string The content of the file read from the archive
|
||||
*/
|
||||
public function GetFileContents($sFileName)
|
||||
{
|
||||
return $this->m_oZip->getFromName($sFileName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts the contents of the given file from the archive
|
||||
* @param string $sFileName The path to the file inside the archive
|
||||
* @param string $sDestinationFileName The path of the file to write
|
||||
* @return none
|
||||
*/
|
||||
public function ExtractToFile($sFileName, $sDestinationFileName)
|
||||
{
|
||||
$iBufferSize = 64 * 1024; // Read 64K at a time
|
||||
$oZipStream = $this->m_oZip->getStream($sFileName);
|
||||
$oDestinationStream = fopen($sDestinationFileName, 'wb');
|
||||
while (!feof($oZipStream)) {
|
||||
$sContents = fread($oZipStream, $iBufferSize);
|
||||
fwrite($oDestinationStream, $sContents);
|
||||
}
|
||||
fclose($oZipStream);
|
||||
fclose($oDestinationStream);
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply a SQL script taken from the archive. The package must be listed in the catalog and of type text/sql
|
||||
* @param string $sFileName The path to the SQL package inside the archive
|
||||
* @return boolean false in case of error, true otherwise
|
||||
*/
|
||||
public function ImportSql($sFileName, $sDatabase = 'itop')
|
||||
{
|
||||
if ( ($this->m_oZip->locateName($sFileName) == false) || (!isset($this->m_aPackages[$sFileName])) || ($this->m_aPackages[$sFileName]['type'] != 'text/sql'))
|
||||
{
|
||||
// invalid type or not listed in the catalog
|
||||
return false;
|
||||
}
|
||||
$sTempName = tempnam("../tmp/", "sql");
|
||||
//echo "Extracting to: '$sTempName'<br/>\n";
|
||||
$this->ExtractToFile($sFileName, $sTempName);
|
||||
// Note: the command line below works on Windows with the right path to mysql !!!
|
||||
$sCommandLine = 'type "'.$sTempName.'" | "/iTop/MySQL Server 5.0/bin/mysql.exe" -u root '.$sDatabase;
|
||||
//echo "Executing: '$sCommandLine'<br/>\n";
|
||||
exec($sCommandLine, $aOutput, $iRet);
|
||||
//echo "Return code: $iRet<br/>\n";
|
||||
//echo "Output:<br/><pre>\n";
|
||||
//print_r($aOutput);
|
||||
//echo "</pre><br/>\n";
|
||||
unlink($sTempName);
|
||||
return ($iRet == 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Dumps some part of the specified MySQL database into the archive as a text/sql package
|
||||
* @param $sTitle string A short title for this SQL script
|
||||
* @param $sDescription string A longer description of the purpose of this SQL script
|
||||
* @param $sFileName string The name of the package inside the archive
|
||||
* @param $sDatabase string name of the database
|
||||
* @param $aTables array array or table names. If empty, all tables are dumped
|
||||
* @param $bStructureOnly boolean Whether or not to dump the data or just the schema
|
||||
* @return boolean False in case of error, true otherwise
|
||||
*/
|
||||
public function AddDatabaseDump($sTitle, $sDescription, $sFileName, $sDatabase = 'itop', $aTables = array(), $bStructureOnly = true)
|
||||
{
|
||||
$sTempName = tempnam("../tmp/", "sql");
|
||||
$sNoData = $bStructureOnly ? "--no-data" : "";
|
||||
$sCommandLine = "\"/iTop/MySQL Server 5.0/bin/mysqldump.exe\" --user=root --opt $sNoData --result-file=$sTempName $sDatabase ".implode(" ", $aTables);
|
||||
//echo "Executing command: '$sCommandLine'<br/>\n";
|
||||
exec($sCommandLine, $aOutput, $iRet);
|
||||
//echo "Return code: $iRet<br/>\n";
|
||||
//echo "Output:<br/><pre>\n";
|
||||
//print_r($aOutput);
|
||||
//echo "</pre><br/>\n";
|
||||
if ($iRet == 0)
|
||||
{
|
||||
$this->AddPackage($sTempName, $sFileName, $sTitle, 'text/sql', $sDescription);
|
||||
}
|
||||
//unlink($sTempName);
|
||||
return ($iRet == 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check the consistency of the archive
|
||||
* @return boolean True if the archive file is consistent
|
||||
*/
|
||||
public function IsValid()
|
||||
{
|
||||
// TO DO: use a DTD to validate the XML instead of this hand-made validation
|
||||
$bResult = true;
|
||||
$aMandatoryTags = array('ARCHIVE' => array('VERSION'),
|
||||
'TITLE' => array(),
|
||||
'DESCRIPTION' => array(),
|
||||
'PACKAGE' => array('TYPE', 'HREF', 'TITLE'));
|
||||
|
||||
$sXmlCatalog = $this->m_oZip->getFromName('catalog.xml');
|
||||
$oParser = xml_parser_create();
|
||||
xml_parse_into_struct($oParser, $sXmlCatalog, $aValues, $aIndexes);
|
||||
xml_parser_free($oParser);
|
||||
|
||||
foreach($aMandatoryTags as $sTag => $aAttributes)
|
||||
{
|
||||
// Check that all the required tags are present
|
||||
if (!isset($aIndexes[$sTag]))
|
||||
{
|
||||
$this->m_aErrorMessages[] = "The XML catalog does not contain the mandatory tag $sTag.";
|
||||
$bResult = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach($aIndexes[$sTag] as $iIndex)
|
||||
{
|
||||
switch($aValues[$iIndex]['type'])
|
||||
{
|
||||
case 'complete':
|
||||
case 'open':
|
||||
// Check that all the required attributes are present
|
||||
foreach($aAttributes as $sAttribute)
|
||||
{
|
||||
if (!isset($aValues[$iIndex]['attributes'][$sAttribute]))
|
||||
{
|
||||
$this->m_aErrorMessages[] = "The tag $sTag ($iIndex) does not contain the required attribute $sAttribute.";
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
// ignore other type of tags: close or cdata
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return $bResult;
|
||||
}
|
||||
}
|
||||
/*
|
||||
// Unit test - reading an archive
|
||||
$sArchivePath = '../tmp/archive.zip';
|
||||
$oArchive = new iTopArchive($sArchivePath, iTopArchive::read);
|
||||
$oArchive->ReadCatalog();
|
||||
$oArchive->ImportSql('full_backup.sql');
|
||||
|
||||
// Writing an archive --
|
||||
|
||||
$sArchivePath = '../tmp/archive2.zip';
|
||||
$oArchive = new iTopArchive($sArchivePath, iTopArchive::create);
|
||||
$oArchive->SetTitle('First Archive !');
|
||||
$oArchive->SetDescription('This is just a test. Does not contain a lot of useful data.');
|
||||
$oArchive->AddPackage('../tmp/schema.sql', 'test.sql', 'this is just a test', 'text/sql', 'My first attempt at creating an archive from PHP...');
|
||||
$oArchive->WriteCatalog();
|
||||
|
||||
|
||||
$sArchivePath = '../tmp/archive2.zip';
|
||||
$oArchive = new iTopArchive($sArchivePath, iTopArchive::create);
|
||||
$oArchive->SetTitle('First Archive !');
|
||||
$oArchive->SetDescription('This is just a test. Does not contain a lot of useful data.');
|
||||
$oArchive->AddDatabaseDump('Test', 'This is my first automatic dump', 'schema.sql', 'itop', array('objects'));
|
||||
$oArchive->WriteCatalog();
|
||||
*/
|
||||
?>
|
||||
File diff suppressed because it is too large
Load Diff
@@ -33,6 +33,7 @@ MetaModel::IncludeModule('core/tagsetfield.class.inc.php');
|
||||
MetaModel::IncludeModule('synchro/synchrodatasource.class.inc.php');
|
||||
MetaModel::IncludeModule('core/backgroundtask.class.inc.php');
|
||||
MetaModel::IncludeModule('core/inlineimage.class.inc.php');
|
||||
MetaModel::IncludeModule('core/counter.class.inc.php');
|
||||
|
||||
MetaModel::IncludeModule('webservices/webservices.basic.php');
|
||||
|
||||
|
||||
@@ -1,29 +1,23 @@
|
||||
<?php
|
||||
// Copyright (C) 2010-2013 Combodo SARL
|
||||
//
|
||||
// This file is part of iTop.
|
||||
//
|
||||
// iTop is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// iTop is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with iTop. If not, see <http://www.gnu.org/licenses/>
|
||||
|
||||
|
||||
/**
|
||||
* interface iProcess
|
||||
* Something that can be executed
|
||||
* Copyright (C) 2010-2020 Combodo SARL
|
||||
*
|
||||
* @copyright Copyright (C) 2010-2012 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
* 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
|
||||
*/
|
||||
|
||||
|
||||
interface iProcess
|
||||
{
|
||||
/**
|
||||
@@ -56,8 +50,9 @@ interface iBackgroundProcess extends iProcess
|
||||
* interface iScheduledProcess
|
||||
* A variant of process that must be called at specific times
|
||||
*
|
||||
* @copyright Copyright (C) 2013 Combodo SARL
|
||||
* @see \AbstractWeeklyScheduledProcess for a bootstrap implementation
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
* @copyright Copyright (C) 2013 Combodo SARL
|
||||
*/
|
||||
interface iScheduledProcess extends iProcess
|
||||
{
|
||||
@@ -67,22 +62,226 @@ interface iScheduledProcess extends iProcess
|
||||
public function GetNextOccurrence();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Class ProcessException
|
||||
* Exception for iProcess implementations.<br>
|
||||
* Implementation of {@link iScheduledProcess}, using config parameters for module
|
||||
*
|
||||
* Use these parameters :
|
||||
*
|
||||
* * enabled
|
||||
* * week_days
|
||||
* * time
|
||||
*
|
||||
* Param names and some of their default values are in constant that can be overridden.
|
||||
*
|
||||
* Other info (module name and time default value) should be provided using a method that needs to be implemented.
|
||||
*
|
||||
* @since 2.7.0 PR #89
|
||||
* @since 2.7.0-2 N°2580 Fix {@link GetNextOccurrence} returning wrong value
|
||||
*/
|
||||
abstract class AbstractWeeklyScheduledProcess implements iScheduledProcess
|
||||
{
|
||||
// param have default names/values but can be overridden
|
||||
const MODULE_SETTING_ENABLED = 'enabled';
|
||||
const DEFAULT_MODULE_SETTING_ENABLED = true;
|
||||
const MODULE_SETTING_WEEKDAYS = 'week_days';
|
||||
const DEFAULT_MODULE_SETTING_WEEKDAYS = 'monday, tuesday, wednesday, thursday, friday, saturday, sunday';
|
||||
const MODULE_SETTING_TIME = 'time';
|
||||
|
||||
/**
|
||||
* @var Config can be used to mock config for tests
|
||||
*/
|
||||
protected $oConfig;
|
||||
|
||||
/**
|
||||
* Module must be declared in each implementation
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
abstract protected function GetModuleName();
|
||||
|
||||
/**
|
||||
* @return string default value for {@link MODULE_SETTING_TIME} config param.
|
||||
* example '23:30'
|
||||
*/
|
||||
abstract protected function GetDefaultModuleSettingTime();
|
||||
|
||||
/**
|
||||
* @return \Config
|
||||
*/
|
||||
public function getOConfig()
|
||||
{
|
||||
if (!isset($this->oConfig))
|
||||
{
|
||||
$this->oConfig = MetaModel::GetConfig();
|
||||
}
|
||||
|
||||
return $this->oConfig;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Interpret current setting for the week days
|
||||
*
|
||||
* @returns int[] (monday = 1)
|
||||
* @throws ProcessInvalidConfigException
|
||||
*/
|
||||
public function InterpretWeekDays()
|
||||
{
|
||||
static $aWEEKDAYTON = array(
|
||||
'monday' => 1,
|
||||
'tuesday' => 2,
|
||||
'wednesday' => 3,
|
||||
'thursday' => 4,
|
||||
'friday' => 5,
|
||||
'saturday' => 6,
|
||||
'sunday' => 7,
|
||||
);
|
||||
$aDays = array();
|
||||
$sWeekDays = $this->getOConfig()->GetModuleSetting(
|
||||
$this->GetModuleName(),
|
||||
static::MODULE_SETTING_WEEKDAYS,
|
||||
static::DEFAULT_MODULE_SETTING_WEEKDAYS
|
||||
);
|
||||
|
||||
if ($sWeekDays !== '')
|
||||
{
|
||||
$aWeekDaysRaw = explode(',', $sWeekDays);
|
||||
foreach ($aWeekDaysRaw as $sWeekDay)
|
||||
{
|
||||
$sWeekDay = strtolower(trim($sWeekDay));
|
||||
if (array_key_exists($sWeekDay, $aWEEKDAYTON))
|
||||
{
|
||||
$aDays[] = $aWEEKDAYTON[$sWeekDay];
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new ProcessInvalidConfigException($this->GetModuleName().": wrong format for setting '".static::MODULE_SETTING_WEEKDAYS."' (found '$sWeekDay')");
|
||||
}
|
||||
}
|
||||
}
|
||||
if (count($aDays) === 0)
|
||||
{
|
||||
throw new ProcessInvalidConfigException($this->GetModuleName().': missing setting \''.static::MODULE_SETTING_WEEKDAYS.'\'');
|
||||
}
|
||||
$aDays = array_unique($aDays);
|
||||
sort($aDays);
|
||||
|
||||
return $aDays;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $sCurrentTime Date string to extract time dependency
|
||||
* this parameter is not present in the interface but as it is optional it's ok
|
||||
*
|
||||
* @return DateTime the exact time at which the process must be run next time
|
||||
* @throws \ProcessInvalidConfigException
|
||||
*/
|
||||
public function GetNextOccurrence($sCurrentTime = 'now')
|
||||
{
|
||||
$bEnabled = $this->getOConfig()->GetModuleSetting(
|
||||
$this->GetModuleName(),
|
||||
static::MODULE_SETTING_ENABLED,
|
||||
static::DEFAULT_MODULE_SETTING_ENABLED
|
||||
);
|
||||
|
||||
$sItopTimeZone = $this->getOConfig()->Get('timezone');
|
||||
$timezone = new DateTimeZone($sItopTimeZone);
|
||||
|
||||
if (!$bEnabled)
|
||||
{
|
||||
return new DateTime('3000-01-01', $timezone);
|
||||
}
|
||||
|
||||
// 1st - Interpret the list of days as ordered numbers (monday = 1)
|
||||
//
|
||||
$aDays = $this->InterpretWeekDays();
|
||||
|
||||
// 2nd - Find the next active week day
|
||||
//
|
||||
$sProcessTime = $this->getOConfig()->GetModuleSetting(
|
||||
$this->GetModuleName(),
|
||||
static::MODULE_SETTING_TIME,
|
||||
static::GetDefaultModuleSettingTime()
|
||||
);
|
||||
if (!preg_match('/[0-2]\d:[0-5]\d/', $sProcessTime))
|
||||
{
|
||||
throw new ProcessInvalidConfigException($this->GetModuleName().": wrong format for setting '".static::MODULE_SETTING_TIME."' (found '$sProcessTime')");
|
||||
}
|
||||
|
||||
$oNow = new DateTime($sCurrentTime, $timezone);
|
||||
$iNextPos = false;
|
||||
$sDay = $oNow->format('N');
|
||||
for ($iDay = (int) $sDay; $iDay <= 7; $iDay++)
|
||||
{
|
||||
$iNextPos = array_search($iDay, $aDays, true);
|
||||
if ($iNextPos !== false)
|
||||
{
|
||||
if (($iDay > $oNow->format('N')) || ($oNow->format('H:i') < $sProcessTime))
|
||||
{
|
||||
break;
|
||||
}
|
||||
$iNextPos = false; // necessary on sundays
|
||||
}
|
||||
}
|
||||
|
||||
// 3rd - Compute the result
|
||||
//
|
||||
if ($iNextPos === false)
|
||||
{
|
||||
// Jump to the first day within the next week
|
||||
$iFirstDayOfWeek = $aDays[0];
|
||||
$iDayMove = $oNow->format('N') - $iFirstDayOfWeek;
|
||||
$oRet = clone $oNow;
|
||||
$oRet->modify('-'.$iDayMove.' days');
|
||||
$oRet->modify('+1 weeks');
|
||||
}
|
||||
else
|
||||
{
|
||||
$iNextDayOfWeek = $aDays[$iNextPos];
|
||||
$iMove = $iNextDayOfWeek - $oNow->format('N');
|
||||
$oRet = clone $oNow;
|
||||
$oRet->modify('+'.$iMove.' days');
|
||||
}
|
||||
list($sHours, $sMinutes) = explode(':', $sProcessTime);
|
||||
/** @noinspection PhpElementIsNotAvailableInCurrentPhpVersionInspection non used new parameter in PHP 7.1 */
|
||||
$oRet->setTime((int)$sHours, (int)$sMinutes);
|
||||
|
||||
return $oRet;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see \iProcess
|
||||
*
|
||||
* @param int $iUnixTimeLimit
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
abstract public function Process($iUnixTimeLimit);
|
||||
}
|
||||
|
||||
/**
|
||||
* Exception for {@link iProcess} implementations.<br>
|
||||
* An error happened during the processing but we can go on with the next implementations.
|
||||
* @since 2.5.0 N°1195
|
||||
*/
|
||||
class ProcessException extends CoreException
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 2.7.0 PR #89
|
||||
*/
|
||||
class ProcessInvalidConfigException extends ProcessException
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Class ProcessFatalException
|
||||
* Exception for iProcess implementations.<br>
|
||||
* A big error occurred, we have to stop the iProcess processing.
|
||||
* @since 2.5.0 N°1195
|
||||
*/
|
||||
class ProcessFatalException extends CoreException
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
@@ -19,13 +19,31 @@
|
||||
|
||||
/**
|
||||
* Class BackgroundTask
|
||||
* A class to record information about the execution of background processes
|
||||
* A class to record information about the execution of background processes ({@link iProcess} impl)
|
||||
*
|
||||
* @copyright Copyright (C) 2010-2012 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
class BackgroundTask extends DBObject
|
||||
{
|
||||
protected $bDebug = false;
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function IsDebug()
|
||||
{
|
||||
return $this->bDebug;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bool $bDebug
|
||||
*/
|
||||
public function SetDebug($bDebug)
|
||||
{
|
||||
$this->bDebug = $bDebug;
|
||||
}
|
||||
|
||||
public static function Init()
|
||||
{
|
||||
$aParams = array
|
||||
@@ -55,6 +73,7 @@ class BackgroundTask extends DBObject
|
||||
|
||||
MetaModel::Init_AddAttribute(new AttributeBoolean("running", array("allowed_values"=>null, "sql"=>"running", "default_value"=>false, "is_null_allowed"=>false, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeEnum("status", array("allowed_values"=>new ValueSetEnum('active,paused'), "sql"=>"status", "default_value"=>'active', "is_null_allowed"=>false, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeString("system_user", array("allowed_values"=>null, "sql"=>"system_user", "default_value"=>null, "is_null_allowed"=>true, "depends_on"=>array())));
|
||||
}
|
||||
|
||||
public function ComputeDurations($fLatestDuration)
|
||||
@@ -73,4 +92,4 @@ class BackgroundTask extends DBObject
|
||||
}
|
||||
$this->Set('latest_run_duration', sprintf('%.3f',$fLatestDuration));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -309,7 +309,7 @@ class BulkChange
|
||||
$value = $oForeignAtt->MakeValueFromString($aRowData[$iCol], $this->m_bLocalizedValues);
|
||||
}
|
||||
$oReconFilter->AddCondition($sForeignAttCode, $value, '=');
|
||||
$aResults[$iCol] = new CellStatus_Void($aRowData[$iCol]);
|
||||
$aResults[$iCol] = new CellStatus_Void(utils::HtmlEntities($aRowData[$iCol]));
|
||||
}
|
||||
|
||||
$oExtObjects = new CMDBObjectSet($oReconFilter);
|
||||
@@ -363,6 +363,7 @@ class BulkChange
|
||||
foreach ($aKeyConfig as $sForeignAttCode => $iCol)
|
||||
{
|
||||
// Default reporting
|
||||
// $aRowData[$iCol] is always null
|
||||
$aResults[$iCol] = new CellStatus_Void($aRowData[$iCol]);
|
||||
}
|
||||
if ($oExtKey->IsNullAllowed())
|
||||
@@ -395,7 +396,7 @@ class BulkChange
|
||||
}
|
||||
$aCacheKeys[] = $value;
|
||||
$oReconFilter->AddCondition($sForeignAttCode, $value, '=');
|
||||
$aResults[$iCol] = new CellStatus_Void($aRowData[$iCol]);
|
||||
$aResults[$iCol] = new CellStatus_Void(utils::HtmlEntities($aRowData[$iCol]));
|
||||
}
|
||||
$sCacheKey = implode('_|_', $aCacheKeys); // Unique key for this query...
|
||||
$iForeignKey = null;
|
||||
@@ -465,7 +466,7 @@ class BulkChange
|
||||
foreach ($aKeyConfig as $sForeignAttCode => $iCol)
|
||||
{
|
||||
// Report the change on reconciliation values as well
|
||||
$aResults[$iCol] = new CellStatus_Modify($aRowData[$iCol]);
|
||||
$aResults[$iCol] = new CellStatus_Modify(utils::HtmlEntities($aRowData[$iCol]));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -538,7 +539,7 @@ class BulkChange
|
||||
{
|
||||
if ($sAttCode == 'id')
|
||||
{
|
||||
$aResults[$iCol]= new CellStatus_Void($aRowData[$iCol]);
|
||||
$aResults[$iCol]= new CellStatus_Void(utils::HtmlEntities($aRowData[$iCol]));
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -554,7 +555,7 @@ class BulkChange
|
||||
}
|
||||
if (isset($aErrors[$sAttCode]))
|
||||
{
|
||||
$aResults[$iCol]= new CellStatus_Issue($aRowData[$iCol], $sOrigValue, $aErrors[$sAttCode]);
|
||||
$aResults[$iCol]= new CellStatus_Issue(utils::HtmlEntities($aRowData[$iCol]), $sOrigValue, $aErrors[$sAttCode]);
|
||||
}
|
||||
elseif (array_key_exists($sAttCode, $aChangedFields))
|
||||
{
|
||||
@@ -577,7 +578,7 @@ class BulkChange
|
||||
}
|
||||
else
|
||||
{
|
||||
$aResults[$iCol]= new CellStatus_Void($aRowData[$iCol]);
|
||||
$aResults[$iCol]= new CellStatus_Void(utils::HtmlEntities($aRowData[$iCol]));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -654,7 +655,7 @@ class BulkChange
|
||||
return $aResults;
|
||||
}
|
||||
|
||||
|
||||
|
||||
protected function CreateObject(&$aResult, $iRow, $aRowData, CMDBChange $oChange = null)
|
||||
{
|
||||
$oTargetObj = MetaModel::NewObject($this->m_sClass);
|
||||
@@ -726,25 +727,38 @@ class BulkChange
|
||||
$aResult[$iRow]["__STATUS__"] = new RowStatus_Issue(Dict::Format('UI:CSVReport-Row-Issue-MissingExtKey', $sMissingKeys));
|
||||
return $oTargetObj;
|
||||
}
|
||||
|
||||
// Optionaly record the results
|
||||
|
||||
// Optionally record the results
|
||||
//
|
||||
if ($oChange)
|
||||
{
|
||||
$newID = $oTargetObj->DBInsertTrackedNoReload($oChange);
|
||||
$aResult[$iRow]["__STATUS__"] = new RowStatus_NewObj();
|
||||
$aResult[$iRow]["finalclass"] = get_class($oTargetObj);
|
||||
$aResult[$iRow]["id"] = new CellStatus_Void($newID);
|
||||
$newID = $oTargetObj->DBInsert();
|
||||
}
|
||||
else
|
||||
{
|
||||
$aResult[$iRow]["__STATUS__"] = new RowStatus_NewObj();
|
||||
$aResult[$iRow]["finalclass"] = get_class($oTargetObj);
|
||||
$aResult[$iRow]["id"] = new CellStatus_Void(0);
|
||||
$newID = 0;
|
||||
}
|
||||
|
||||
$aResult[$iRow]["__STATUS__"] = new RowStatus_NewObj();
|
||||
$aResult[$iRow]["finalclass"] = get_class($oTargetObj);
|
||||
$aResult[$iRow]["id"] = new CellStatus_Void($newID);
|
||||
|
||||
return $oTargetObj;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param array $aResult
|
||||
* @param int $iRow
|
||||
* @param \CMDBObject $oTargetObj
|
||||
* @param array $aRowData
|
||||
* @param \CMDBChange $oChange
|
||||
*
|
||||
* @throws \CoreException
|
||||
* @throws \CoreUnexpectedValue
|
||||
* @throws \MissingQueryArgument
|
||||
* @throws \MySQLException
|
||||
* @throws \MySQLHasGoneAwayException
|
||||
*/
|
||||
protected function UpdateObject(&$aResult, $iRow, $oTargetObj, $aRowData, CMDBChange $oChange = null)
|
||||
{
|
||||
$aResult[$iRow] = $this->PrepareObject($oTargetObj, $aRowData, $aErrors);
|
||||
@@ -772,7 +786,7 @@ class BulkChange
|
||||
{
|
||||
try
|
||||
{
|
||||
$oTargetObj->DBUpdateTracked($oChange);
|
||||
$oTargetObj->DBUpdate();
|
||||
}
|
||||
catch(CoreException $e)
|
||||
{
|
||||
@@ -786,6 +800,14 @@ class BulkChange
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $aResult
|
||||
* @param int $iRow
|
||||
* @param \CMDBObject $oTargetObj
|
||||
* @param \CMDBChange $oChange
|
||||
*
|
||||
* @throws \BulkChangeException
|
||||
*/
|
||||
protected function UpdateMissingObject(&$aResult, $iRow, $oTargetObj, CMDBChange $oChange = null)
|
||||
{
|
||||
$aResult[$iRow] = $this->PrepareMissingObject($oTargetObj, $aErrors);
|
||||
@@ -813,7 +835,7 @@ class BulkChange
|
||||
{
|
||||
try
|
||||
{
|
||||
$oTargetObj->DBUpdateTracked($oChange);
|
||||
$oTargetObj->DBUpdate();
|
||||
}
|
||||
catch(CoreException $e)
|
||||
{
|
||||
@@ -829,6 +851,11 @@ class BulkChange
|
||||
|
||||
public function Process(CMDBChange $oChange = null)
|
||||
{
|
||||
if ($oChange)
|
||||
{
|
||||
CMDBObject::SetCurrentChange($oChange);
|
||||
}
|
||||
|
||||
// Note: $oChange can be null, in which case the aim is to check what would be done
|
||||
|
||||
// Debug...
|
||||
@@ -898,7 +925,7 @@ class BulkChange
|
||||
{
|
||||
// Leave the cell unchanged
|
||||
$aResult[$iRow]["__STATUS__"]= new RowStatus_Issue(Dict::S('UI:CSVReport-Row-Issue-DateFormat'));
|
||||
$aResult[$iRow][$sAttCode] = new CellStatus_Issue(null, $this->m_aData[$iRow][$iCol], Dict::S('UI:CSVReport-Row-Issue-DateFormat'));
|
||||
$aResult[$iRow][$sAttCode] = new CellStatus_Issue(null, utils::HtmlEntities($this->m_aData[$iRow][$iCol]), Dict::S('UI:CSVReport-Row-Issue-DateFormat'));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1056,7 +1083,7 @@ class BulkChange
|
||||
{
|
||||
if (!array_key_exists($iCol, $aResult[$iRow]))
|
||||
{
|
||||
$aResult[$iRow][$iCol] = new CellStatus_Void($aRowData[$iCol]);
|
||||
$aResult[$iRow][$iCol] = new CellStatus_Void(utils::HtmlEntities($aRowData[$iCol]));
|
||||
}
|
||||
}
|
||||
foreach($this->m_aExtKeys as $sAttCode => $aForeignAtts)
|
||||
@@ -1070,7 +1097,7 @@ class BulkChange
|
||||
if (!array_key_exists($iCol, $aResult[$iRow]))
|
||||
{
|
||||
// The foreign attribute is one of our reconciliation key
|
||||
$aResult[$iRow][$iCol] = new CellStatus_Void($aRowData[$iCol]);
|
||||
$aResult[$iRow][$iCol] = new CellStatus_Void(utils::HtmlEntities($aRowData[$iCol]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,20 +1,21 @@
|
||||
<?php
|
||||
// Copyright (C) 2015 Combodo SARL
|
||||
//
|
||||
// This file is part of iTop.
|
||||
//
|
||||
// iTop is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// iTop is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with iTop. If not, see <http://www.gnu.org/licenses/>
|
||||
/**
|
||||
* Copyright (C) 2013-2019 Combodo SARL
|
||||
*
|
||||
* This file is part of iTop.
|
||||
*
|
||||
* iTop is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* iTop is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
*/
|
||||
|
||||
define('EXPORTER_DEFAULT_CHUNK_SIZE', 1000);
|
||||
|
||||
@@ -109,7 +110,7 @@ class BulkExportResultGC implements iBackgroundProcess
|
||||
{
|
||||
// Next one ?
|
||||
$oSet = new CMDBObjectSet(DBObjectSearch::FromOQL($sOQL), array('created' => true) /* order by*/, array(), null, 1 /* limit count */);
|
||||
$oSet->OptimizeColumnLoad(array('temp_file_path'));
|
||||
$oSet->OptimizeColumnLoad(array('BulkExportResult' => array('temp_file_path')));
|
||||
$oResult = $oSet->Fetch();
|
||||
if (is_null($oResult))
|
||||
{
|
||||
@@ -170,6 +171,7 @@ abstract class BulkExport
|
||||
$oRefClass = new ReflectionClass($sPHPClass);
|
||||
if ($oRefClass->isSubclassOf('BulkExport') && !$oRefClass->isAbstract())
|
||||
{
|
||||
/** @var BulkExport $oBulkExporter */
|
||||
$oBulkExporter = new $sPHPClass();
|
||||
if ($oBulkExporter->IsFormatSupported($sFormatCode, $oSearch))
|
||||
{
|
||||
@@ -189,7 +191,7 @@ abstract class BulkExport
|
||||
*
|
||||
* @param int $iPersistentToken The identifier of the BulkExportResult object storing the information
|
||||
*
|
||||
* @return iBulkExport|null
|
||||
* @return BulkExport|null
|
||||
* @throws ArchivedObjectException
|
||||
* @throws CoreException
|
||||
* @throws ReflectionException
|
||||
@@ -343,10 +345,10 @@ abstract class BulkExport
|
||||
$this->oBulkExportResult->Set('format', $this->sFormatCode);
|
||||
$this->oBulkExportResult->Set('search', $this->oSearch->serialize());
|
||||
$this->oBulkExportResult->Set('chunk_size', $this->iChunkSize);
|
||||
$this->oBulkExportResult->Set('temp_file_path', $this->sTmpFile);
|
||||
$this->oBulkExportResult->Set('localize_output', $this->bLocalizeOutput);
|
||||
}
|
||||
$this->oBulkExportResult->Set('status_info', json_encode($this->GetStatusInfo()));
|
||||
$this->oBulkExportResult->Set('temp_file_path', $this->sTmpFile);
|
||||
utils::PushArchiveMode(false);
|
||||
$ret = $this->oBulkExportResult->DBWrite();
|
||||
utils::PopArchiveMode();
|
||||
@@ -418,6 +420,11 @@ abstract class BulkExport
|
||||
public function GetStatistics()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public function SetFields($sFields)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public function GetDownloadFileName()
|
||||
|
||||
@@ -544,7 +544,7 @@ class CMDBChangeOpSetAttributeEncrypted extends CMDBChangeOpSetAttribute
|
||||
// The attribute was renamed or removed from the object ?
|
||||
$sAttName = $this->Get('attcode');
|
||||
}
|
||||
$sPrevString = $this->Get('prevstring');
|
||||
$sPrevString = $this->GetAsHTML('prevstring');
|
||||
$sResult = Dict::Format('Change:AttName_Changed_PreviousValue_OldValue', $sAttName, $sPrevString);
|
||||
}
|
||||
return $sResult;
|
||||
|
||||
@@ -59,7 +59,6 @@ require_once('sqlobjectquery.class.inc.php');
|
||||
require_once('sqlunionquery.class.inc.php');
|
||||
|
||||
require_once('dbobject.class.php');
|
||||
require_once('dbsearch.class.php');
|
||||
require_once('dbobjectset.class.php');
|
||||
|
||||
require_once('backgroundprocess.inc.php');
|
||||
@@ -96,11 +95,21 @@ abstract class CMDBObject extends DBObject
|
||||
protected static $m_oCurrChange = null;
|
||||
protected static $m_sInfo = null; // null => the information is built in a standard way
|
||||
protected static $m_sOrigin = null; // null => the origin is 'interactive'
|
||||
|
||||
|
||||
/**
|
||||
* Specify another change (this is mainly for backward compatibility)
|
||||
* Specify the change to be used by the API to attach any CMDBChangeOp* object created
|
||||
*
|
||||
* @see SetTrackInfo if CurrentChange is null, then a new one will be create using trackinfo
|
||||
*
|
||||
* @param CMDBChange|null $oChange use null so that the API will recreate a new CMDBChange using TrackInfo & TrackOrigin
|
||||
* If providing a CMDBChange, you should persist it first ! Indeed the API will automatically create CMDBChangeOp (see
|
||||
* \CMDBObject::RecordObjCreation / RecordAttChange / RecordObjDeletion for example) and link them to the current change : in
|
||||
* consequence this CMDBChange must have a key set !
|
||||
*
|
||||
* @since 2.7.2 N°3219 can now reset CMDBChange by passing null
|
||||
* @since 2.7.2 N°3218 PHPDoc about persisting the $oChange parameter first
|
||||
*/
|
||||
public static function SetCurrentChange(CMDBChange $oChange)
|
||||
public static function SetCurrentChange($oChange)
|
||||
{
|
||||
self::$m_oCurrChange = $oChange;
|
||||
}
|
||||
@@ -113,7 +122,11 @@ abstract class CMDBObject extends DBObject
|
||||
// GetCurrentChange to create a default change if not already done in the current context
|
||||
//
|
||||
/**
|
||||
* Get a change record (create it if not existing)
|
||||
* @param bool $bAutoCreate if true calls {@link CreateChange} to get a new persisted object
|
||||
*
|
||||
* @return \CMDBChange
|
||||
*
|
||||
* @uses CreateChange
|
||||
*/
|
||||
public static function GetCurrentChange($bAutoCreate = true)
|
||||
{
|
||||
@@ -127,11 +140,15 @@ abstract class CMDBObject extends DBObject
|
||||
/**
|
||||
* Override the additional information (defaulting to user name)
|
||||
* A call to this verb should replace every occurence of
|
||||
* $oMyChange = MetaModel::NewObject("CMDBChange");
|
||||
* $oMyChange = MetaModel::NewObject("CMDBChange");
|
||||
* $oMyChange->Set("date", time());
|
||||
* $oMyChange->Set("userinfo", 'this is done by ... for ...');
|
||||
* $iChangeId = $oMyChange->DBInsert();
|
||||
*/
|
||||
*
|
||||
* @see SetCurrentChange to specify a CMDBObject instance instead
|
||||
*
|
||||
* @param string $sInfo
|
||||
*/
|
||||
public static function SetTrackInfo($sInfo)
|
||||
{
|
||||
self::$m_sInfo = $sInfo;
|
||||
@@ -139,8 +156,13 @@ abstract class CMDBObject extends DBObject
|
||||
|
||||
/**
|
||||
* Provides information about the origin of the change
|
||||
* @param $sOrigin String: one of: interactive, csv-interactive, csv-import.php, webservice-soap, webservice-rest, syncho-data-source, email-processing, custom-extension
|
||||
*/
|
||||
*
|
||||
* @see SetTrackInfo
|
||||
* @see SetCurrentChange to specify a CMDBObject instance instead
|
||||
*
|
||||
* @param $sOrigin String: one of: interactive, csv-interactive, csv-import.php, webservice-soap, webservice-rest, syncho-data-source,
|
||||
* email-processing, custom-extension
|
||||
*/
|
||||
public static function SetTrackOrigin($sOrigin)
|
||||
{
|
||||
self::$m_sOrigin = $sOrigin;
|
||||
@@ -175,10 +197,12 @@ abstract class CMDBObject extends DBObject
|
||||
return self::$m_sOrigin;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Create a standard change record (done here 99% of the time, and nearly once per page)
|
||||
*/
|
||||
* Set to {@link $m_oCurrChange} a standard change record (done here 99% of the time, and nearly once per page)
|
||||
*
|
||||
* The CMDBChange is persisted so that it has a key > 0, and any new CMDBChangeOp can link to it
|
||||
*/
|
||||
protected static function CreateChange()
|
||||
{
|
||||
self::$m_oCurrChange = MetaModel::NewObject("CMDBChange");
|
||||
@@ -514,7 +538,23 @@ abstract class CMDBObject extends DBObject
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @deprecated 2.7.0 N°2361 simply use {@link DBInsert} instead, that will automatically create and persist a CMDBChange object.
|
||||
* If you need to persist your own, call {@link CMDBObject::SetCurrentChange} before.
|
||||
*
|
||||
* @param \CMDBChange $oChange
|
||||
* @param null $bSkipStrongSecurity
|
||||
*
|
||||
* @return int|null
|
||||
* @throws \ArchivedObjectException
|
||||
* @throws \CoreCannotSaveObjectException
|
||||
* @throws \CoreException
|
||||
* @throws \CoreUnexpectedValue
|
||||
* @throws \CoreWarning
|
||||
* @throws \MySQLException
|
||||
* @throws \OQLException
|
||||
* @throws \SecurityException
|
||||
*/
|
||||
public function DBInsertTracked(CMDBChange $oChange, $bSkipStrongSecurity = null)
|
||||
{
|
||||
self::SetCurrentChange($oChange);
|
||||
@@ -522,7 +562,24 @@ abstract class CMDBObject extends DBObject
|
||||
$ret = $this->DBInsertTracked_Internal();
|
||||
return $ret;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @deprecated 2.7.0 N°2361 simply use {@link DBInsertNoReload} instead, that will automatically create and persist a CMDBChange object.
|
||||
* If you need to persist your own, call {@link CMDBObject::SetCurrentChange} before.
|
||||
*
|
||||
* @param \CMDBChange $oChange
|
||||
* @param null $bSkipStrongSecurity
|
||||
*
|
||||
* @return int
|
||||
* @throws \ArchivedObjectException
|
||||
* @throws \CoreCannotSaveObjectException
|
||||
* @throws \CoreException
|
||||
* @throws \CoreUnexpectedValue
|
||||
* @throws \CoreWarning
|
||||
* @throws \MySQLException
|
||||
* @throws \OQLException
|
||||
* @throws \SecurityException
|
||||
*/
|
||||
public function DBInsertTrackedNoReload(CMDBChange $oChange, $bSkipStrongSecurity = null)
|
||||
{
|
||||
self::SetCurrentChange($oChange);
|
||||
@@ -530,13 +587,20 @@ abstract class CMDBObject extends DBObject
|
||||
$ret = $this->DBInsertTracked_Internal(true);
|
||||
return $ret;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* To Be Obsoleted: DO NOT rely on an overload of this method since
|
||||
* DBInsertTracked (resp. DBInsertTrackedNoReload) may call directly
|
||||
* DBInsert (resp. DBInsertNoReload) in future versions of iTop.
|
||||
* @deprecated 2.7.0 N°2361 simply use {@link DBInsert} or {@link DBInsertNoReload} instead
|
||||
*
|
||||
* @param bool $bDoNotReload
|
||||
*
|
||||
* @return integer Identifier of the created object
|
||||
* @throws \ArchivedObjectException
|
||||
* @throws \CoreCannotSaveObjectException
|
||||
* @throws \CoreException
|
||||
* @throws \CoreUnexpectedValue
|
||||
* @throws \CoreWarning
|
||||
* @throws \MySQLException
|
||||
* @throws \OQLException
|
||||
*/
|
||||
protected function DBInsertTracked_Internal($bDoNotReload = false)
|
||||
{
|
||||
@@ -583,6 +647,18 @@ abstract class CMDBObject extends DBObject
|
||||
return $ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated 2.7.0 N°2361 simply use {@link DBUpdate} instead, that will automatically create and persist a CMDBChange object.
|
||||
* If you need to persist your own, call {@link CMDBObject::SetCurrentChange} before.
|
||||
*
|
||||
* @param \CMDBChange $oChange
|
||||
* @param null $bSkipStrongSecurity
|
||||
*
|
||||
* @return int|void
|
||||
* @throws \CoreCannotSaveObjectException
|
||||
* @throws \CoreException
|
||||
* @throws \SecurityException
|
||||
*/
|
||||
public function DBUpdateTracked(CMDBChange $oChange, $bSkipStrongSecurity = null)
|
||||
{
|
||||
self::SetCurrentChange($oChange);
|
||||
@@ -594,13 +670,38 @@ abstract class CMDBObject extends DBObject
|
||||
* @param null $oDeletionPlan
|
||||
*
|
||||
* @return \DeletionPlan|null
|
||||
* @throws \ArchivedObjectException
|
||||
* @throws \CoreCannotSaveObjectException
|
||||
* @throws \CoreException
|
||||
* @throws \CoreUnexpectedValue
|
||||
* @throws \DeleteException
|
||||
* @throws \MySQLException
|
||||
* @throws \MySQLHasGoneAwayException
|
||||
* @throws \OQLException
|
||||
*/
|
||||
public function DBDelete(&$oDeletionPlan = null)
|
||||
{
|
||||
return $this->DBDeleteTracked_Internal($oDeletionPlan);
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated 2.7.0 N°2361 simply use {@link DBDelete} instead, that will automatically create and persist a CMDBChange object.
|
||||
* If you need to persist your own, call {@link CMDBObject::SetCurrentChange} before.
|
||||
*
|
||||
* @param \CMDBChange $oChange
|
||||
* @param null $bSkipStrongSecurity
|
||||
* @param null $oDeletionPlan
|
||||
*
|
||||
* @throws \ArchivedObjectException
|
||||
* @throws \CoreCannotSaveObjectException
|
||||
* @throws \CoreException
|
||||
* @throws \CoreUnexpectedValue
|
||||
* @throws \DeleteException
|
||||
* @throws \MySQLException
|
||||
* @throws \MySQLHasGoneAwayException
|
||||
* @throws \OQLException
|
||||
* @throws \SecurityException
|
||||
*/
|
||||
public function DBDeleteTracked(CMDBChange $oChange, $bSkipStrongSecurity = null, &$oDeletionPlan = null)
|
||||
{
|
||||
self::SetCurrentChange($oChange);
|
||||
@@ -612,11 +713,17 @@ abstract class CMDBObject extends DBObject
|
||||
* @param null $oDeletionPlan
|
||||
*
|
||||
* @return \DeletionPlan|null
|
||||
* @throws \ArchivedObjectException
|
||||
* @throws \CoreCannotSaveObjectException
|
||||
* @throws \CoreException
|
||||
* @throws \CoreUnexpectedValue
|
||||
* @throws \DeleteException
|
||||
* @throws \MySQLException
|
||||
* @throws \MySQLHasGoneAwayException
|
||||
* @throws \OQLException
|
||||
*/
|
||||
protected function DBDeleteTracked_Internal(&$oDeletionPlan = null)
|
||||
{
|
||||
$prevkey = $this->GetKey();
|
||||
$ret = parent::DBDelete($oDeletionPlan);
|
||||
return $ret;
|
||||
}
|
||||
|
||||
@@ -64,7 +64,7 @@ class MySQLException extends CoreException
|
||||
/**
|
||||
* Class MySQLQueryHasNoResultException
|
||||
*
|
||||
* @since 2.5
|
||||
* @since 2.5.0
|
||||
*/
|
||||
class MySQLQueryHasNoResultException extends MySQLException
|
||||
{
|
||||
@@ -74,7 +74,7 @@ class MySQLQueryHasNoResultException extends MySQLException
|
||||
/**
|
||||
* Class MySQLHasGoneAwayException
|
||||
*
|
||||
* @since 2.5
|
||||
* @since 2.5.0
|
||||
* @see itop bug 1195
|
||||
* @see https://dev.mysql.com/doc/refman/5.7/en/gone-away.html
|
||||
*/
|
||||
@@ -99,6 +99,14 @@ class MySQLHasGoneAwayException extends MySQLException
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 2.7.0 N°679
|
||||
*/
|
||||
class MySQLNoTransactionException extends MySQLException
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* CMDBSource
|
||||
@@ -111,25 +119,42 @@ class CMDBSource
|
||||
const ENUM_DB_VENDOR_MYSQL = 'MySQL';
|
||||
const ENUM_DB_VENDOR_MARIADB = 'MariaDB';
|
||||
const ENUM_DB_VENDOR_PERCONA = 'Percona';
|
||||
|
||||
|
||||
/**
|
||||
* Error: 1205 SQLSTATE: HY000 (ER_LOCK_WAIT_TIMEOUT)
|
||||
* Message: Lock wait timeout exceeded; try restarting transaction
|
||||
*/
|
||||
const MYSQL_ERRNO_WAIT_TIMEOUT = 1205;
|
||||
/**
|
||||
* Error: 1213 SQLSTATE: 40001 (ER_LOCK_DEADLOCK)
|
||||
* Message: Deadlock found when trying to get lock; try restarting transaction
|
||||
*/
|
||||
const MYSQL_ERRNO_DEADLOCK = 1213;
|
||||
|
||||
protected static $m_sDBHost;
|
||||
protected static $m_sDBUser;
|
||||
protected static $m_sDBPwd;
|
||||
protected static $m_sDBName;
|
||||
/**
|
||||
* @var boolean
|
||||
* @since 2.5 N°1260 MySQL TLS first implementation
|
||||
* @since 2.5.0 N°1260 MySQL TLS first implementation
|
||||
*/
|
||||
protected static $m_bDBTlsEnabled;
|
||||
/**
|
||||
* @var string
|
||||
* @since 2.5 N°1260 MySQL TLS first implementation
|
||||
* @since 2.5.0 N°1260 MySQL TLS first implementation
|
||||
*/
|
||||
protected static $m_sDBTlsCA;
|
||||
|
||||
/** @var mysqli $m_oMysqli */
|
||||
protected static $m_oMysqli;
|
||||
|
||||
/**
|
||||
* @var int number of level for nested transactions : 0 if no transaction was ever opened, +1 for each 'START TRANSACTION' sent
|
||||
* @since 2.7.0 N°679
|
||||
*/
|
||||
protected static $m_iTransactionLevel = 0;
|
||||
|
||||
/**
|
||||
* SQL charset & collation declaration for text columns
|
||||
*
|
||||
@@ -137,7 +162,7 @@ class CMDBSource
|
||||
* use expression as value)
|
||||
*
|
||||
* @see https://dev.mysql.com/doc/refman/5.7/en/charset-column.html
|
||||
* @since 2.5 N°1001 switch to utf8mb4
|
||||
* @since 2.5.1 N°1001 switch to utf8mb4
|
||||
*/
|
||||
public static function GetSqlStringColumnDefinition()
|
||||
{
|
||||
@@ -289,11 +314,11 @@ class CMDBSource
|
||||
$iConnectInfoCount = count($aConnectInfo);
|
||||
if ($bUsePersistentConnection && ($iConnectInfoCount == 3))
|
||||
{
|
||||
$iPort = $aConnectInfo[2];
|
||||
$iPort = (int)($aConnectInfo[2]);
|
||||
}
|
||||
else if (!$bUsePersistentConnection && ($iConnectInfoCount == 2))
|
||||
{
|
||||
$iPort = $aConnectInfo[1];
|
||||
$iPort = (int)($aConnectInfo[1]);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -410,6 +435,14 @@ class CMDBSource
|
||||
return $aVersions[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public static function GetServerInfo()
|
||||
{
|
||||
return mysqli_get_server_info ( self::$m_oMysqli );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the DB vendor between MySQL and its main forks
|
||||
* @return string
|
||||
@@ -554,11 +587,6 @@ class CMDBSource
|
||||
return $aRes;
|
||||
}
|
||||
|
||||
// Stripslashes
|
||||
if (get_magic_quotes_gpc())
|
||||
{
|
||||
$value = stripslashes($value);
|
||||
}
|
||||
// Quote if not a number or a numeric string
|
||||
if ($bAlways || is_string($value))
|
||||
{
|
||||
@@ -567,28 +595,90 @@ class CMDBSource
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* MariaDB returns "'value'" for enum, while MySQL returns "value" (without the surrounding single quotes)
|
||||
*
|
||||
* @param string $sValue
|
||||
*
|
||||
* @return string without the surrounding quotes
|
||||
* @since 2.7.0 N°2490
|
||||
*/
|
||||
private static function RemoveSurroundingQuotes($sValue)
|
||||
{
|
||||
if (utils::StartsWith($sValue, '\'') && utils::EndsWith($sValue, '\''))
|
||||
{
|
||||
$sValue = substr($sValue, 1, -1);
|
||||
}
|
||||
|
||||
return $sValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $sSQLQuery
|
||||
*
|
||||
* @return \mysqli_result
|
||||
* @return \mysqli_result|null
|
||||
* @throws \MySQLException
|
||||
* @throws \MySQLHasGoneAwayException
|
||||
* @throws \CoreException
|
||||
*
|
||||
* @since 2.7.0 N°679 handles nested transactions
|
||||
*/
|
||||
public static function Query($sSQLQuery)
|
||||
{
|
||||
if (preg_match('/^START TRANSACTION;?$/i', $sSQLQuery))
|
||||
{
|
||||
self::StartTransaction();
|
||||
|
||||
return null;
|
||||
}
|
||||
if (preg_match('/^COMMIT;?$/i', $sSQLQuery))
|
||||
{
|
||||
self::Commit();
|
||||
|
||||
return null;
|
||||
}
|
||||
if (preg_match('/^ROLLBACK;?$/i', $sSQLQuery))
|
||||
{
|
||||
self::Rollback();
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
return self::DBQuery($sSQLQuery);
|
||||
}
|
||||
|
||||
/**
|
||||
* Send the query directly to the DB. **Be extra cautious with this !**
|
||||
*
|
||||
* Use {@link Query} if you're not sure.
|
||||
*
|
||||
* @internal
|
||||
*
|
||||
* @param string $sSql
|
||||
*
|
||||
* @return bool|\mysqli_result
|
||||
* @throws \MySQLHasGoneAwayException
|
||||
* @throws \MySQLException
|
||||
*
|
||||
* @since 2.7.0 N°679
|
||||
*/
|
||||
private static function DBQuery($sSql)
|
||||
{
|
||||
$oKPI = new ExecutionKPI();
|
||||
try
|
||||
{
|
||||
$oResult = self::$m_oMysqli->query($sSQLQuery);
|
||||
$oResult = self::$m_oMysqli->query($sSql);
|
||||
}
|
||||
catch(mysqli_sql_exception $e)
|
||||
catch (mysqli_sql_exception $e)
|
||||
{
|
||||
throw new MySQLException('Failed to issue SQL query', array('query' => $sSQLQuery, $e));
|
||||
self::LogDeadLock($e);
|
||||
throw new MySQLException('Failed to issue SQL query', array('query' => $sSql, $e));
|
||||
}
|
||||
$oKPI->ComputeStats('Query exec (mySQL)', $sSQLQuery);
|
||||
$oKPI->ComputeStats('Query exec (mySQL)', $sSql);
|
||||
if ($oResult === false)
|
||||
{
|
||||
$aContext = array('query' => $sSQLQuery);
|
||||
$aContext = array('query' => $sSql);
|
||||
|
||||
$iMySqlErrorNo = self::$m_oMysqli->errno;
|
||||
$aMySqlHasGoneAwayErrorCodes = MySQLHasGoneAwayException::getErrorCodes();
|
||||
@@ -596,14 +686,183 @@ class CMDBSource
|
||||
{
|
||||
throw new MySQLHasGoneAwayException(self::GetError(), $aContext);
|
||||
}
|
||||
|
||||
throw new MySQLException('Failed to issue SQL query', $aContext);
|
||||
$e = new MySQLException('Failed to issue SQL query', $aContext);
|
||||
self::LogDeadLock($e);
|
||||
throw $e;
|
||||
}
|
||||
|
||||
|
||||
return $oResult;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \Exception $e
|
||||
*
|
||||
* @since 2.7.1
|
||||
*/
|
||||
private static function LogDeadLock(Exception $e)
|
||||
{
|
||||
// checks MySQL error code
|
||||
$iMySqlErrorNo = self::$m_oMysqli->errno;
|
||||
if (!in_array($iMySqlErrorNo, array(self::MYSQL_ERRNO_WAIT_TIMEOUT, self::MYSQL_ERRNO_DEADLOCK)))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Get error info
|
||||
$sUser = UserRights::GetUser();
|
||||
$oError = self::$m_oMysqli->query('SHOW ENGINE INNODB STATUS');
|
||||
if ($oError !== false)
|
||||
{
|
||||
$aData = $oError->fetch_all(MYSQLI_ASSOC);
|
||||
$sInnodbStatus = $aData[0];
|
||||
}
|
||||
else
|
||||
{
|
||||
$sInnodbStatus = 'Get status query cannot execute';
|
||||
}
|
||||
|
||||
// log !
|
||||
$sMessage = "deadlock detected: user= $sUser; errno=$iMySqlErrorNo";
|
||||
$aLogContext = array(
|
||||
'userinfo' => $sUser,
|
||||
'errno' => $iMySqlErrorNo,
|
||||
'ex_msg' => $e->getMessage(),
|
||||
'callstack' => $e->getTraceAsString(),
|
||||
'data' => $sInnodbStatus,
|
||||
);
|
||||
DeadLockLog::Info($sMessage, $iMySqlErrorNo, $aLogContext);
|
||||
|
||||
IssueLog::Error($sMessage, 'DeadLock', $e->getMessage());
|
||||
}
|
||||
|
||||
/**
|
||||
* If nested transaction, we are not starting a new one : only one global transaction will exist.
|
||||
*
|
||||
* Indeed [the official documentation](https://dev.mysql.com/doc/refman/5.6/en/commit.html) states :
|
||||
*
|
||||
* > Beginning a transaction causes any pending transaction to be committed
|
||||
*
|
||||
* @internal
|
||||
* @see m_iTransactionLevel
|
||||
* @since 2.7.0 N°679
|
||||
*/
|
||||
private static function StartTransaction()
|
||||
{
|
||||
$bHasExistingTransactions = self::IsInsideTransaction();
|
||||
if (!$bHasExistingTransactions)
|
||||
{
|
||||
self::DBQuery('START TRANSACTION');
|
||||
}
|
||||
|
||||
self::AddTransactionLevel();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends the COMMIT to the db only if we are at the root transaction level
|
||||
*
|
||||
* @internal
|
||||
* @see m_iTransactionLevel
|
||||
* @throws \MySQLException
|
||||
* @throws \MySQLHasGoneAwayException
|
||||
* @throws \MySQLNoTransactionException if called with no opened transaction
|
||||
* @since 2.7.0 N°679
|
||||
*/
|
||||
private static function Commit()
|
||||
{
|
||||
if (!self::IsInsideTransaction())
|
||||
{
|
||||
// should not happen !
|
||||
throw new MySQLNoTransactionException('Trying to commit transaction whereas none have been started !', null);
|
||||
}
|
||||
|
||||
self::RemoveLastTransactionLevel();
|
||||
|
||||
if (self::IsInsideTransaction())
|
||||
{
|
||||
return;
|
||||
}
|
||||
self::DBQuery('COMMIT');
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends the ROLLBACK to the db only if we are at the root transaction level
|
||||
*
|
||||
* The parameter allows to send a ROLLBACK whatever the current transaction level is
|
||||
*
|
||||
* @internal
|
||||
* @see m_iTransactionLevel
|
||||
*
|
||||
* @throws \MySQLNoTransactionException if called with no opened transaction
|
||||
* @throws \MySQLException
|
||||
* @throws \MySQLHasGoneAwayException
|
||||
* @since 2.7.0 N°679
|
||||
*/
|
||||
private static function Rollback()
|
||||
{
|
||||
if (!self::IsInsideTransaction())
|
||||
{
|
||||
// should not happen !
|
||||
throw new MySQLNoTransactionException('Trying to commit transaction whereas none have been started !', null);
|
||||
}
|
||||
self::RemoveLastTransactionLevel();
|
||||
if (self::IsInsideTransaction())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
self::DBQuery('ROLLBACK');
|
||||
}
|
||||
|
||||
/**
|
||||
* @api
|
||||
* @see m_iTransactionLevel
|
||||
* @return bool true if there is one transaction opened, false otherwise (not a single 'START TRANSACTION' sent)
|
||||
* @since 2.7.0 N°679
|
||||
*/
|
||||
public static function IsInsideTransaction()
|
||||
{
|
||||
return (self::$m_iTransactionLevel > 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* @see m_iTransactionLevel
|
||||
* @since 2.7.0 N°679
|
||||
*/
|
||||
private static function AddTransactionLevel()
|
||||
{
|
||||
++self::$m_iTransactionLevel;
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* @see m_iTransactionLevel
|
||||
* @since 2.7.0 N°679
|
||||
*/
|
||||
private static function RemoveLastTransactionLevel()
|
||||
{
|
||||
if (self::$m_iTransactionLevel === 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
--self::$m_iTransactionLevel;
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* @see m_iTransactionLevel
|
||||
* @since 2.7.0 N°679
|
||||
*/
|
||||
private static function RemoveAllTransactionLevels()
|
||||
{
|
||||
self::$m_iTransactionLevel = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @deprecated 2.7.0 N°1627 use ItopCounter instead
|
||||
*
|
||||
* @param string $sTable
|
||||
*
|
||||
* @return int
|
||||
@@ -638,6 +897,13 @@ class CMDBSource
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $sSQLQuery
|
||||
*
|
||||
* @throws \CoreException
|
||||
* @throws \MySQLException
|
||||
* @throws \MySQLHasGoneAwayException
|
||||
*/
|
||||
public static function DeleteFrom($sSQLQuery)
|
||||
{
|
||||
self::Query($sSQLQuery);
|
||||
@@ -914,6 +1180,83 @@ class CMDBSource
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* There may have some differences between DB : for example in MySQL 5.7 we have "INT", while in MariaDB >= 10.2 you get "int DEFAULT 'NULL'"
|
||||
*
|
||||
* We still do a case sensitive comparison for enum values !
|
||||
*
|
||||
* A better solution would be to generate SQL field definitions ({@link GetFieldSpec} method) based on the DB used... But for
|
||||
* now (N°2490 / SF #1756 / PR #91) we did implement this simpler solution
|
||||
*
|
||||
* @param string $sItopGeneratedFieldType
|
||||
* @param string $sDbFieldType
|
||||
*
|
||||
* @return bool true if same type and options (case sensitive comparison only for type options), false otherwise
|
||||
* @since 2.7.0 N°2490
|
||||
*/
|
||||
public static function IsSameFieldTypes($sItopGeneratedFieldType, $sDbFieldType)
|
||||
{
|
||||
list($sItopFieldDataType, $sItopFieldTypeOptions, $sItopFieldOtherOptions) = static::GetFieldDataTypeAndOptions($sItopGeneratedFieldType);
|
||||
list($sDbFieldDataType, $sDbFieldTypeOptions, $sDbFieldOtherOptions) = static::GetFieldDataTypeAndOptions($sDbFieldType);
|
||||
|
||||
if (strcasecmp($sItopFieldDataType, $sDbFieldDataType) !== 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (strcmp($sItopFieldTypeOptions, $sDbFieldTypeOptions) !== 0)
|
||||
{
|
||||
// case sensitive comp as we need to check case for enum possible values for example
|
||||
return false;
|
||||
}
|
||||
|
||||
// remove the default value NULL added by MariadDB
|
||||
$sMariaDbDefaultNull = ' DEFAULT \'NULL\'';
|
||||
if (utils::EndsWith($sDbFieldOtherOptions, $sMariaDbDefaultNull))
|
||||
{
|
||||
$sDbFieldOtherOptions = substr($sDbFieldOtherOptions, 0, -strlen($sMariaDbDefaultNull));
|
||||
}
|
||||
// remove quotes around default values (always present in MariaDB)
|
||||
$sDbFieldOtherOptions = preg_replace_callback(
|
||||
'/( DEFAULT )\'([^\']+)\'/',
|
||||
function ($aMatches) use ($sItopFieldDataType) {
|
||||
// ENUM default values should keep quotes, but all other numeric values don't have quotes
|
||||
if (is_numeric($aMatches[2]) && ($sItopFieldDataType !== 'ENUM'))
|
||||
{
|
||||
return $aMatches[1].$aMatches[2];
|
||||
}
|
||||
|
||||
return $aMatches[0];
|
||||
},
|
||||
$sDbFieldOtherOptions);
|
||||
|
||||
if (strcasecmp($sItopFieldOtherOptions, $sDbFieldOtherOptions) !== 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $sCompleteFieldType sql field type, for example 'VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT 0'
|
||||
*
|
||||
* @return string[] consisting of 3 items :
|
||||
* 1. data type : for example 'VARCHAR'
|
||||
* 2. type value : for example '255'
|
||||
* 3. other options : for example ' CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT 0'
|
||||
*/
|
||||
private static function GetFieldDataTypeAndOptions($sCompleteFieldType)
|
||||
{
|
||||
preg_match('/^([a-zA-Z]+)(\(([^\)]+)\))?( .+)?/', $sCompleteFieldType, $aMatches);
|
||||
|
||||
$sDataType = isset($aMatches[1]) ? $aMatches[1] : '';
|
||||
$sTypeOptions = isset($aMatches[2]) ? $aMatches[3] : '';
|
||||
$sOtherOptions = isset($aMatches[4]) ? $aMatches[4] : '';
|
||||
|
||||
return array($sDataType, $sTypeOptions, $sOtherOptions);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $sTable
|
||||
* @param string $sField
|
||||
@@ -965,7 +1308,8 @@ class CMDBSource
|
||||
}
|
||||
elseif (is_string($aFieldData["Default"]) == 'string')
|
||||
{
|
||||
$sRet .= ' DEFAULT '.self::Quote($aFieldData["Default"]);
|
||||
$sDefaultValue = static::RemoveSurroundingQuotes($aFieldData["Default"]);
|
||||
$sRet .= ' DEFAULT '.self::Quote($sDefaultValue);
|
||||
}
|
||||
|
||||
return $sRet;
|
||||
@@ -1100,20 +1444,20 @@ class CMDBSource
|
||||
* @return string query to upgrade table charset and collation if needed, null if not
|
||||
* @throws \MySQLException
|
||||
*
|
||||
* @since 2.5 N°1001 switch to utf8mb4
|
||||
* @since 2.5.0 N°1001 switch to utf8mb4
|
||||
* @see https://dev.mysql.com/doc/refman/5.7/en/charset-table.html
|
||||
*/
|
||||
public static function DBCheckTableCharsetAndCollation($sTableName)
|
||||
{
|
||||
$sDBName = self::DBName();
|
||||
$sTableInfoQuery = "SELECT C.character_set_name, T.table_collation
|
||||
$sTableInfoQuery = "SELECT C.CHARACTER_SET_NAME, T.TABLE_COLLATION
|
||||
FROM information_schema.`TABLES` T inner join information_schema.`COLLATION_CHARACTER_SET_APPLICABILITY` C
|
||||
ON T.table_collation = C.collation_name
|
||||
WHERE T.table_schema = '$sDBName'
|
||||
AND T.table_name = '$sTableName';";
|
||||
$aTableInfo = self::QueryToArray($sTableInfoQuery);
|
||||
$sTableCharset = $aTableInfo[0]['character_set_name'];
|
||||
$sTableCollation = $aTableInfo[0]['table_collation'];
|
||||
$sTableCharset = $aTableInfo[0]['CHARACTER_SET_NAME'];
|
||||
$sTableCollation = $aTableInfo[0]['TABLE_COLLATION'];
|
||||
|
||||
if ((DEFAULT_CHARACTER_SET == $sTableCharset) && (DEFAULT_COLLATION == $sTableCollation))
|
||||
{
|
||||
@@ -1250,14 +1594,14 @@ class CMDBSource
|
||||
* @return string query to upgrade database charset and collation if needed, null if not
|
||||
* @throws \MySQLException
|
||||
*
|
||||
* @since 2.5 N°1001 switch to utf8mb4
|
||||
* @since 2.5.0 N°1001 switch to utf8mb4
|
||||
* @see https://dev.mysql.com/doc/refman/5.7/en/charset-database.html
|
||||
*/
|
||||
public static function DBCheckCharsetAndCollation()
|
||||
{
|
||||
$sDBName = CMDBSource::DBName();
|
||||
$sDBInfoQuery = "SELECT DEFAULT_CHARACTER_SET_NAME, DEFAULT_COLLATION_NAME
|
||||
FROM INFORMATION_SCHEMA.SCHEMATA WHERE SCHEMA_NAME = '$sDBName';";
|
||||
FROM information_schema.SCHEMATA WHERE SCHEMA_NAME = '$sDBName';";
|
||||
$aDBInfo = CMDBSource::QueryToArray($sDBInfoQuery);
|
||||
$sDBCharset = $aDBInfo[0]['DEFAULT_CHARACTER_SET_NAME'];
|
||||
$sDBCollation = $aDBInfo[0]['DEFAULT_COLLATION_NAME'];
|
||||
|
||||
@@ -1,35 +1,44 @@
|
||||
<?php
|
||||
// Copyright (C) 2010-2014 Combodo SARL
|
||||
//
|
||||
// This file is part of iTop.
|
||||
//
|
||||
// iTop is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// iTop is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with iTop. If not, see <http://www.gnu.org/licenses/>
|
||||
/**
|
||||
* Copyright (C) 2010-2020 Combodo SARL
|
||||
*
|
||||
* This file is part of iTop.
|
||||
*
|
||||
* iTop is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* iTop is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with iTop. If not, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* Any extension to compute things like a stop watch deadline or working hours
|
||||
* Any extension to compute things like a stop watch deadline or working hours
|
||||
*
|
||||
* @copyright Copyright (C) 2010-2012 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* Metric computing for stop watches
|
||||
* Metric computing for stop watches.
|
||||
* Can be used for AttributeStopWatch goal (iTop XML node xpath: /itop_design/classes/class/fields/field/goal)
|
||||
*/
|
||||
interface iMetricComputer
|
||||
{
|
||||
public static function GetDescription();
|
||||
|
||||
/**
|
||||
* @param \DBObject $oObject
|
||||
*
|
||||
* @return float number of seconds for the time limit
|
||||
*/
|
||||
public function ComputeMetric($oObject);
|
||||
}
|
||||
|
||||
@@ -41,21 +50,21 @@ interface iWorkingTimeComputer
|
||||
public static function GetDescription();
|
||||
|
||||
/**
|
||||
* Get the date/time corresponding to a given delay in the future from the present
|
||||
* considering only the valid (open) hours for a specified object
|
||||
* @param $oObject DBObject The object for which to compute the deadline
|
||||
* @param $iDuration integer The duration (in seconds) in the future
|
||||
* @param $oStartDate DateTime The starting point for the computation
|
||||
* @return DateTime The date/time for the deadline
|
||||
* @param DBObject $oObject The object for which to compute the deadline
|
||||
* @param integer $iDuration The duration (in seconds) in the future
|
||||
* @param DateTime $oStartDate The starting point for the computation
|
||||
*
|
||||
* @return DateTime The date/time corresponding to a given delay in the future from the present
|
||||
* considering only the valid (open) hours for a specified object
|
||||
*/
|
||||
public function GetDeadline($oObject, $iDuration, DateTime $oStartDate);
|
||||
|
||||
/**
|
||||
* Get duration (considering only open hours) elapsed bewteen two given DateTimes
|
||||
* @param $oObject DBObject The object for which to compute the duration
|
||||
* @param $oStartDate DateTime The starting point for the computation (default = now)
|
||||
* @param $oEndDate DateTime The ending point for the computation (default = now)
|
||||
* @return integer The duration (number of seconds) of open hours elapsed between the two dates
|
||||
* @param DBObject $oObject The object for which to compute the duration
|
||||
* @param DateTime $oStartDate The starting point for the computation (default = now)
|
||||
* @param DateTime $oEndDate The ending point for the computation (default = now)
|
||||
*
|
||||
* @return integer The duration (number of seconds) elapsed between two given dates, considering only open hours
|
||||
*/
|
||||
public function GetOpenDuration($oObject, DateTime $oStartDate, DateTime $oEndDate);
|
||||
}
|
||||
@@ -87,12 +96,7 @@ class DefaultWorkingTimeComputer implements iWorkingTimeComputer
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the date/time corresponding to a given delay in the future from the present
|
||||
* considering only the valid (open) hours for a specified object
|
||||
* @param $oObject DBObject The object for which to compute the deadline
|
||||
* @param $iDuration integer The duration (in seconds) in the future
|
||||
* @param $oStartDate DateTime The starting point for the computation
|
||||
* @return DateTime The date/time for the deadline
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function GetDeadline($oObject, $iDuration, DateTime $oStartDate)
|
||||
{
|
||||
@@ -113,11 +117,7 @@ class DefaultWorkingTimeComputer implements iWorkingTimeComputer
|
||||
}
|
||||
|
||||
/**
|
||||
* Get duration (considering only open hours) elapsed bewteen two given DateTimes
|
||||
* @param $oObject DBObject The object for which to compute the duration
|
||||
* @param $oStartDate DateTime The starting point for the computation (default = now)
|
||||
* @param $oEndDate DateTime The ending point for the computation (default = now)
|
||||
* @return integer The duration (number of seconds) of open hours elapsed between the two dates
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function GetOpenDuration($oObject, DateTime $oStartDate, DateTime $oEndDate)
|
||||
{
|
||||
@@ -134,6 +134,3 @@ class DefaultWorkingTimeComputer implements iWorkingTimeComputer
|
||||
return $iDuration;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
?>
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -19,14 +19,14 @@
|
||||
|
||||
/**
|
||||
* Simple helper class for keeping track of the context inside the call stack
|
||||
*
|
||||
*
|
||||
* To check (anywhere in the code) if a particular context tag is present
|
||||
* in the call stack simply do:
|
||||
*
|
||||
*
|
||||
* if (ContextTag::Check(<the_tag>)) ...
|
||||
*
|
||||
*
|
||||
* For example to know if the code is being executed in the context of a portal do:
|
||||
*
|
||||
*
|
||||
* if (ContextTag::Check('GUI:Portal'))
|
||||
*
|
||||
* @copyright Copyright (C) 2016-2017 Combodo SARL
|
||||
@@ -35,8 +35,15 @@
|
||||
|
||||
class ContextTag
|
||||
{
|
||||
const TAG_PORTAL = 'GUI:Portal';
|
||||
const TAG_CRON = 'CRON';
|
||||
const TAG_CONSOLE = 'GUI:Console';
|
||||
const TAG_SETUP = 'Setup';
|
||||
const TAG_SYNCHRO = 'Synchro';
|
||||
const TAG_REST = 'REST/JSON';
|
||||
|
||||
protected static $aStack = array();
|
||||
|
||||
|
||||
/**
|
||||
* Store a context tag on the stack
|
||||
* @param string $sTag
|
||||
@@ -46,6 +53,11 @@ class ContextTag
|
||||
static::$aStack[] = $sTag;
|
||||
}
|
||||
|
||||
public static function AddContext($sTag)
|
||||
{
|
||||
static::$aStack[] = $sTag;
|
||||
}
|
||||
|
||||
/**
|
||||
* Cleanup the context stack
|
||||
*/
|
||||
@@ -53,7 +65,7 @@ class ContextTag
|
||||
{
|
||||
array_pop(static::$aStack);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Check if a given tag is present in the stack
|
||||
* @param string $sTag
|
||||
@@ -63,13 +75,53 @@ class ContextTag
|
||||
{
|
||||
return in_array($sTag, static::$aStack);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the whole stack as an array
|
||||
* @return hash
|
||||
* @return array
|
||||
*/
|
||||
public static function GetStack()
|
||||
{
|
||||
return static::$aStack;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all the predefined context tags
|
||||
* @return array
|
||||
*/
|
||||
public static function GetTags()
|
||||
{
|
||||
$aRawTags = array(
|
||||
ContextTag::TAG_REST,
|
||||
ContextTag::TAG_SYNCHRO,
|
||||
ContextTag::TAG_SETUP,
|
||||
ContextTag::TAG_CONSOLE,
|
||||
ContextTag::TAG_CRON,
|
||||
ContextTag::TAG_PORTAL);
|
||||
|
||||
$aTags = array();
|
||||
|
||||
foreach ($aRawTags as $sRawTag)
|
||||
{
|
||||
$aTags[$sRawTag] = Dict::S("Core:Context={$sRawTag}");
|
||||
}
|
||||
|
||||
$aPortalsConf = PortalDispatcherData::GetData();
|
||||
$aDispatchers = array();
|
||||
foreach ($aPortalsConf as $sPortalId => $aConf)
|
||||
{
|
||||
$sHandlerClass = $aConf['handler'];
|
||||
$aDispatchers[$sPortalId] = new $sHandlerClass($sPortalId);
|
||||
}
|
||||
|
||||
foreach ($aDispatchers as $sPortalId => $oDispatcher)
|
||||
{
|
||||
if ($sPortalId != 'backoffice')
|
||||
{
|
||||
$aTags['Portal:'.$sPortalId] = $oDispatcher->GetLabel();
|
||||
}
|
||||
}
|
||||
|
||||
return $aTags;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,31 +28,39 @@
|
||||
|
||||
class CoreException extends Exception
|
||||
{
|
||||
public function __construct($sIssue, $aContextData = null, $sImpact = '')
|
||||
/**
|
||||
* CoreException constructor.
|
||||
*
|
||||
* @param string $sIssue error message
|
||||
* @param array|null $aContextData key/value array, value MUST implements _toString
|
||||
* @param string $sImpact
|
||||
* @param Exception|null $oPrevious
|
||||
*/
|
||||
public function __construct($sIssue, $aContextData = null, $sImpact = '', $oPrevious = null)
|
||||
{
|
||||
$this->m_sIssue = $sIssue;
|
||||
$this->m_sImpact = $sImpact;
|
||||
$this->m_aContextData = $aContextData ? $aContextData : array();
|
||||
|
||||
|
||||
if (is_array($aContextData)) {
|
||||
$this->m_aContextData = $aContextData;
|
||||
} else {
|
||||
$this->m_aContextData = [];
|
||||
}
|
||||
|
||||
$sMessage = $sIssue;
|
||||
if (!empty($sImpact)) $sMessage .= "($sImpact)";
|
||||
if (count($this->m_aContextData) > 0)
|
||||
{
|
||||
if (!empty($sImpact)) {
|
||||
$sMessage .= "($sImpact)";
|
||||
}
|
||||
if (count($this->m_aContextData) > 0) {
|
||||
$sMessage .= ": ";
|
||||
$aContextItems = array();
|
||||
foreach($this->m_aContextData as $sKey => $value)
|
||||
{
|
||||
if (is_array($value))
|
||||
{
|
||||
foreach ($this->m_aContextData as $sKey => $value) {
|
||||
if (is_array($value)) {
|
||||
$aPairs = array();
|
||||
foreach($value as $key => $val)
|
||||
{
|
||||
if (is_array($val))
|
||||
{
|
||||
foreach ($value as $key => $val) {
|
||||
if (is_array($val)) {
|
||||
$aPairs[] = $key.'=>('.implode(', ', $val).')';
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
$aPairs[] = $key.'=>'.$val;
|
||||
}
|
||||
}
|
||||
@@ -66,7 +74,7 @@ class CoreException extends Exception
|
||||
}
|
||||
$sMessage .= implode(', ', $aContextItems);
|
||||
}
|
||||
parent::__construct($sMessage, 0);
|
||||
parent::__construct($sMessage, 0, $oPrevious);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -81,6 +89,16 @@ class CoreException extends Exception
|
||||
return $this->getMessage();
|
||||
}
|
||||
|
||||
/**
|
||||
* getTraceAsString() cannot be overrided and it is limited as only current exception stack is returned.
|
||||
* we need stack of all previous exceptions
|
||||
* @uses __tostring() already does the work.
|
||||
* @since 2.7.2/ 2.8.0
|
||||
*/
|
||||
public function getFullStackTraceAsString(){
|
||||
return "" . $this;
|
||||
}
|
||||
|
||||
public function getTraceAsHtml()
|
||||
{
|
||||
$aBackTrace = $this->getTrace();
|
||||
@@ -115,7 +133,7 @@ class CoreException extends Exception
|
||||
* @see \DBObject::DBInsertNoReload()
|
||||
* @see \DBObject::DBUpdate()
|
||||
*
|
||||
* @since 2.6 N°659 uniqueness constraint
|
||||
* @since 2.6.0 N°659 uniqueness constraint
|
||||
*/
|
||||
class CoreCannotSaveObjectException extends CoreException
|
||||
{
|
||||
@@ -183,6 +201,30 @@ class CoreCannotSaveObjectException extends CoreException
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 2.7.0 N°2555
|
||||
*/
|
||||
class CorePortalInvalidActionRuleException extends CoreException
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 2.7.0 N°2555
|
||||
*/
|
||||
class CoreOqlException extends CoreException
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 2.7.0 N°2555
|
||||
*/
|
||||
class CoreOqlMultipleResultsForbiddenException extends CoreOqlException
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
class CoreWarning extends CoreException
|
||||
{
|
||||
}
|
||||
@@ -199,7 +241,27 @@ class SecurityException extends CoreException
|
||||
* Throwned when querying on an object that exists in the database but is archived
|
||||
*
|
||||
* @see N.1108
|
||||
* @since 2.5.1
|
||||
*/
|
||||
class ArchivedObjectException extends CoreException
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* A parameter stored in the {@link Config} is invalid
|
||||
*
|
||||
* @since 2.7.0
|
||||
*/
|
||||
class InvalidConfigParamException extends CoreException
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Throwned when the password is not valid
|
||||
*
|
||||
* @since 2.7.0
|
||||
*/
|
||||
class InvalidPasswordAttributeOneWayPassword extends CoreException
|
||||
{
|
||||
}
|
||||
251
core/counter.class.inc.php
Normal file
251
core/counter.class.inc.php
Normal file
@@ -0,0 +1,251 @@
|
||||
<?php
|
||||
/**
|
||||
* Copyright (C) 2013-2019 Combodo SARL
|
||||
*
|
||||
* This file is part of iTop.
|
||||
*
|
||||
* iTop is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* iTop is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* Class ItopCounter
|
||||
*
|
||||
*/
|
||||
final class ItopCounter
|
||||
{
|
||||
|
||||
/**
|
||||
* Key based counter.
|
||||
* The counter is protected against concurrency script.
|
||||
*
|
||||
* @param $sCounterName
|
||||
* @param null|callable $oNewObjectValueProvider optional callable that must return an integer. Used when no key is found
|
||||
*
|
||||
* @return int the counter starting at
|
||||
* * `0` when no $oNewObjectValueProvider is given (or null)
|
||||
* * `$oNewObjectValueProvider() + 1` otherwise
|
||||
*
|
||||
* @throws \CoreException
|
||||
* @throws \MySQLException
|
||||
* @throws \Exception
|
||||
*/
|
||||
public static function Inc($sCounterName, $oNewObjectValueProvider = null)
|
||||
{
|
||||
$sSelfClassName = self::class;
|
||||
$sMutexKeyName = "{$sSelfClassName}-{$sCounterName}";
|
||||
$oiTopMutex = new iTopMutex($sMutexKeyName);
|
||||
$oiTopMutex->Lock();
|
||||
|
||||
$bIsInsideTransaction = CMDBSource::IsInsideTransaction();
|
||||
if ($bIsInsideTransaction)
|
||||
{
|
||||
// # Transaction isolation hack:
|
||||
// When inside a transaction, we need to open a new connection for the counter.
|
||||
// So it is visible immediately to the connections outside of the transaction.
|
||||
// Either way, the lock is not long enought, and there would be duplicate ref.
|
||||
//
|
||||
// SELECT ... FOR UPDATE would have also worked but with the cost of extra long lock (until the commit),
|
||||
// we did not wanted this! As opening a short connection is less prone to starving than a long running one.
|
||||
// Plus it would trigger way more deadlocks!
|
||||
$hDBLink = self::InitMySQLSession();
|
||||
}
|
||||
else
|
||||
{
|
||||
$hDBLink = CMDBSource::GetMysqli();
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
$oFilter = DBObjectSearch::FromOQL('SELECT KeyValueStore WHERE key_name=:key_name AND namespace=:namespace', array(
|
||||
'key_name' => $sCounterName,
|
||||
'namespace' => $sSelfClassName,
|
||||
));
|
||||
$oAttDef = MetaModel::GetAttributeDef('KeyValueStore', 'value');
|
||||
$aAttToLoad = array('KeyValueStore' => array('value' => $oAttDef));
|
||||
$sSql = $oFilter->MakeSelectQuery(array(), array(), $aAttToLoad);
|
||||
$hResult = mysqli_query($hDBLink, $sSql);
|
||||
$aCounter = mysqli_fetch_array($hResult, MYSQLI_NUM);
|
||||
mysqli_free_result($hResult);
|
||||
|
||||
//Rebuild the filter, as the MakeSelectQuery polluted the orignal and it cannot be reused
|
||||
$oFilter = DBObjectSearch::FromOQL('SELECT KeyValueStore WHERE key_name=:key_name AND namespace=:namespace', array(
|
||||
'key_name' => $sCounterName,
|
||||
'namespace' => $sSelfClassName,
|
||||
));
|
||||
|
||||
if (is_null($aCounter))
|
||||
{
|
||||
if (null != $oNewObjectValueProvider)
|
||||
{
|
||||
$iComputedValue = $oNewObjectValueProvider();
|
||||
}
|
||||
else
|
||||
{
|
||||
$iComputedValue = 0;
|
||||
}
|
||||
|
||||
$iCurrentValue = $iComputedValue + 1;
|
||||
|
||||
$aQueryParams = array(
|
||||
'key_name' => $sCounterName,
|
||||
'value' => "$iCurrentValue",
|
||||
'namespace' => $sSelfClassName,
|
||||
);
|
||||
|
||||
$sSql = $oFilter->MakeInsertQuery($aQueryParams);
|
||||
}
|
||||
else
|
||||
{
|
||||
$iCurrentValue = (int) $aCounter[1];
|
||||
$iCurrentValue++;
|
||||
$aQueryParams = array(
|
||||
'value' => "$iCurrentValue",
|
||||
);
|
||||
|
||||
$sSql = $oFilter->MakeUpdateQuery($aQueryParams);
|
||||
}
|
||||
|
||||
$hResult = mysqli_query($hDBLink, $sSql);
|
||||
|
||||
}
|
||||
catch(Exception $e)
|
||||
{
|
||||
IssueLog::Error($e->getMessage());
|
||||
throw $e;
|
||||
}
|
||||
finally
|
||||
{
|
||||
if ($bIsInsideTransaction)
|
||||
{
|
||||
mysqli_close($hDBLink);
|
||||
}
|
||||
$oiTopMutex->Unlock();
|
||||
}
|
||||
|
||||
return $iCurrentValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* handle a counter for the root class of given $sLeafClass.
|
||||
* If no counter exist initialize it with the `max(id) + 1`
|
||||
*
|
||||
*
|
||||
*
|
||||
* @param $sLeafClass
|
||||
*
|
||||
* @return int
|
||||
* @throws \ArchivedObjectException
|
||||
* @throws \CoreCannotSaveObjectException
|
||||
* @throws \CoreException
|
||||
* @throws \CoreOqlMultipleResultsForbiddenException
|
||||
* @throws \CoreUnexpectedValue
|
||||
* @throws \MySQLException
|
||||
* @throws \OQLException
|
||||
*/
|
||||
public static function IncClass($sLeafClass)
|
||||
{
|
||||
$sRootClass = MetaModel::GetRootClass($sLeafClass);
|
||||
|
||||
$oNewObjectCallback = function() use ($sRootClass)
|
||||
{
|
||||
$sRootTable = MetaModel::DBGetTable($sRootClass);
|
||||
$sIdField = MetaModel::DBGetKey($sRootClass);
|
||||
|
||||
return CMDBSource::QueryToScalar("SELECT max(`$sIdField`) FROM `$sRootTable`");
|
||||
};
|
||||
|
||||
return self::Inc($sRootClass, $oNewObjectCallback);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \mysqli
|
||||
* @throws \ConfigException
|
||||
* @throws \CoreException
|
||||
* @throws \MySQLException
|
||||
*/
|
||||
private static function InitMySQLSession()
|
||||
{
|
||||
$oConfig = utils::GetConfig();
|
||||
$sDBHost = $oConfig->Get('db_host');
|
||||
$sDBUser = $oConfig->Get('db_user');
|
||||
$sDBPwd = $oConfig->Get('db_pwd');
|
||||
$sDBName = $oConfig->Get('db_name');
|
||||
$bDBTlsEnabled = $oConfig->Get('db_tls.enabled');
|
||||
$sDBTlsCA = $oConfig->Get('db_tls.ca');
|
||||
|
||||
$hDBLink = CMDBSource::GetMysqliInstance($sDBHost, $sDBUser, $sDBPwd, $sDBName, $bDBTlsEnabled, $sDBTlsCA, false);
|
||||
|
||||
if (!$hDBLink)
|
||||
{
|
||||
throw new Exception("Could not connect to the DB server (host=$sDBHost, user=$sDBUser): ".mysqli_connect_error().' (mysql errno: '.mysqli_connect_errno().')');
|
||||
}
|
||||
|
||||
return $hDBLink;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Persistent classes for a CMDB
|
||||
*
|
||||
* @copyright Copyright (C) 2010-2017 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
class KeyValueStore extends DBObject
|
||||
{
|
||||
public static function Init()
|
||||
{
|
||||
$aParams = array(
|
||||
'category' => '',
|
||||
'key_type' => 'autoincrement',
|
||||
'name_attcode' => array('key_name'),
|
||||
'state_attcode' => '',
|
||||
'reconc_keys' => array(''),
|
||||
'db_table' => 'key_value_store',
|
||||
'db_key_field' => 'id',
|
||||
'db_finalclass_field' => '',
|
||||
'indexes' => array (
|
||||
array (
|
||||
0 => 'key_name',
|
||||
1 => 'namespace',
|
||||
),
|
||||
),);
|
||||
MetaModel::Init_Params($aParams);
|
||||
MetaModel::Init_InheritAttributes();
|
||||
MetaModel::Init_AddAttribute(new AttributeString("namespace", array("allowed_values"=>null, "sql"=>'namespace', "default_value"=>null, "is_null_allowed"=>true, "depends_on"=>array(), "always_load_in_tables"=>false)));
|
||||
MetaModel::Init_AddAttribute(new AttributeString("key_name", array("allowed_values"=>null, "sql"=>'key_name', "default_value"=>'', "is_null_allowed"=>false, "depends_on"=>array(), "always_load_in_tables"=>false)));
|
||||
MetaModel::Init_AddAttribute(new AttributeString("value", array("allowed_values"=>null, "sql"=>'value', "default_value"=>'0', "is_null_allowed"=>false, "depends_on"=>array(), "always_load_in_tables"=>false)));
|
||||
|
||||
MetaModel::Init_SetZListItems('details', array (
|
||||
0 => 'key_name',
|
||||
1 => 'value',
|
||||
2 => 'namespace',
|
||||
));
|
||||
MetaModel::Init_SetZListItems('standard_search', array (
|
||||
0 => 'key_name',
|
||||
1 => 'value',
|
||||
2 => 'namespace',
|
||||
));
|
||||
MetaModel::Init_SetZListItems('list', array (
|
||||
0 => 'key_name',
|
||||
1 => 'value',
|
||||
2 => 'namespace',
|
||||
));
|
||||
;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -1,11 +1,13 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<itop_design xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="1.6">
|
||||
<itop_design xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="1.7">
|
||||
<user_rights>
|
||||
<profiles>
|
||||
<profile id="1024" _delta="define">
|
||||
<name>REST Services User</name>
|
||||
<description>Only users having this profile are allowed to use the REST Web Services (unless 'secure_rest_services' is set to false in the configuration file).</description>
|
||||
<groups />
|
||||
<description>Only users having this profile are allowed to use the REST Web Services (unless 'secure_rest_services' is set to false
|
||||
in the configuration file).
|
||||
</description>
|
||||
<groups/>
|
||||
</profile>
|
||||
</profiles>
|
||||
</user_rights>
|
||||
|
||||
@@ -58,8 +58,8 @@ class DateTimeFormat
|
||||
{
|
||||
return array(
|
||||
// Days
|
||||
'd' => array('regexpr' => '(0[1-9]|[1-2][0-9]||3[0-1])', 'datepicker' => 'dd', 'excel' => 'dd', 'moment' => 'DD'), // Day of the month: 2 digits (with leading zero)
|
||||
'j' => array('regexpr' => '([1-9]|[1-2][0-9]||3[0-1])', 'datepicker' => 'd', 'excel' => 'd', 'moment' => 'D'), // Day of the month: 1 or 2 digits (without leading zero)
|
||||
'd' => array('regexpr' => '(0[1-9]|[1-2][0-9]|3[0-1])', 'datepicker' => 'dd', 'excel' => 'dd', 'moment' => 'DD'), // Day of the month: 2 digits (with leading zero)
|
||||
'j' => array('regexpr' => '([1-9]|[1-2][0-9]|3[0-1])', 'datepicker' => 'd', 'excel' => 'd', 'moment' => 'D'), // Day of the month: 1 or 2 digits (without leading zero)
|
||||
// Months
|
||||
'm' => array('regexpr' => '(0[1-9]|1[0-2])', 'datepicker' => 'mm', 'excel' => 'MM', 'moment' => 'MM' ), // Month on 2 digits i.e. 01-12
|
||||
'n' => array('regexpr' => '([1-9]|1[0-2])', 'datepicker' => 'm', 'excel' => 'm', 'moment' => 'M'), // Month on 1 or 2 digits 1-12
|
||||
@@ -69,7 +69,7 @@ class DateTimeFormat
|
||||
// Hours
|
||||
'H' => array('regexpr' => '([0-1][0-9]|2[0-3])', 'datepicker' => 'HH', 'excel' => 'HH', 'moment' => 'HH'), // Hour 00..23
|
||||
'h' => array('regexpr' => '(0[1-9]|1[0-2])', 'datepicker' => 'hh', 'excel' => 'hh', 'moment' => 'hh'), // Hour 01..12
|
||||
'G' => array('regexpr' => '([1-9]|[1[0-9]|2[0-3])', 'datepicker' => 'H', 'excel' => 'H', 'moment' => 'H'), // Hour 0..23
|
||||
'G' => array('regexpr' => '([0-9]|1[0-9]|2[0-3])', 'datepicker' => 'H', 'excel' => 'H', 'moment' => 'H'), // Hour 0..23
|
||||
'g' => array('regexpr' => '([1-9]|1[0-2])', 'datepicker' => 'h', 'excel' => 'h', 'moment' => 'h'), // Hour 1..12
|
||||
'a' => array('regexpr' => '(am|pm)', 'datepicker' => 'tt', 'excel' => 'am/pm', 'moment' => 'a'),
|
||||
'A' => array('regexpr' => '(AM|PM)', 'datepicker' => 'TT', 'excel' => 'AM/PM', 'moment' => 'A'),
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -89,7 +89,8 @@ class DBObjectSet implements iDBObjectSetIterator
|
||||
* @api
|
||||
*
|
||||
* @param DBSearch $oFilter The search filter defining the objects which are part of the set (multiple columns/objects per row are supported)
|
||||
* @param array $aOrderBy Array of '[<classalias>.]attcode' => bAscending
|
||||
* @param array $aOrderBy Array of '[<classalias>.]attcode' => bAscending (true for ASC, false, for DESC)
|
||||
* Example : array('name' => true, 'id' => false)
|
||||
* @param array $aArgs Values to substitute for the search/query parameters (if any). Format: param_name => value
|
||||
* @param array $aExtendedDataSpec
|
||||
* @param int $iLimitCount Maximum number of rows to load (i.e. equivalent to MySQL's LIMIT start, count)
|
||||
@@ -217,73 +218,81 @@ class DBObjectSet implements iDBObjectSetIterator
|
||||
*/
|
||||
public function OptimizeColumnLoad($aAttToLoad)
|
||||
{
|
||||
if (is_null($aAttToLoad))
|
||||
// Check that the structure is an array of array
|
||||
if (!is_array($aAttToLoad))
|
||||
{
|
||||
$this->m_aAttToLoad = null;
|
||||
return;
|
||||
}
|
||||
else
|
||||
foreach ($aAttToLoad as $sAlias => $aAttCodes)
|
||||
{
|
||||
// Complete the attribute list with the attribute codes
|
||||
$aAttToLoadWithAttDef = array();
|
||||
foreach($this->m_oFilter->GetSelectedClasses() as $sClassAlias => $sClass)
|
||||
if (!is_array($aAttCodes))
|
||||
{
|
||||
$aAttToLoadWithAttDef[$sClassAlias] = array();
|
||||
if (array_key_exists($sClassAlias, $aAttToLoad))
|
||||
$this->m_aAttToLoad = null;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Complete the attribute list with the attribute codes
|
||||
$aAttToLoadWithAttDef = array();
|
||||
foreach($this->m_oFilter->GetSelectedClasses() as $sClassAlias => $sClass)
|
||||
{
|
||||
$aAttToLoadWithAttDef[$sClassAlias] = array();
|
||||
if (array_key_exists($sClassAlias, $aAttToLoad))
|
||||
{
|
||||
$aAttList = $aAttToLoad[$sClassAlias];
|
||||
foreach($aAttList as $sAttToLoad)
|
||||
{
|
||||
$aAttList = $aAttToLoad[$sClassAlias];
|
||||
foreach($aAttList as $sAttToLoad)
|
||||
$oAttDef = MetaModel::GetAttributeDef($sClass, $sAttToLoad);
|
||||
$aAttToLoadWithAttDef[$sClassAlias][$sAttToLoad] = $oAttDef;
|
||||
if ($oAttDef->IsExternalKey(EXTKEY_ABSOLUTE))
|
||||
{
|
||||
$oAttDef = MetaModel::GetAttributeDef($sClass, $sAttToLoad);
|
||||
$aAttToLoadWithAttDef[$sClassAlias][$sAttToLoad] = $oAttDef;
|
||||
if ($oAttDef->IsExternalKey(EXTKEY_ABSOLUTE))
|
||||
// Add the external key friendly name anytime
|
||||
$oFriendlyNameAttDef = MetaModel::GetAttributeDef($sClass, $sAttToLoad.'_friendlyname');
|
||||
$aAttToLoadWithAttDef[$sClassAlias][$sAttToLoad.'_friendlyname'] = $oFriendlyNameAttDef;
|
||||
|
||||
if (MetaModel::IsArchivable($oAttDef->GetTargetClass(EXTKEY_ABSOLUTE)))
|
||||
{
|
||||
// Add the external key friendly name anytime
|
||||
$oFriendlyNameAttDef = MetaModel::GetAttributeDef($sClass, $sAttToLoad.'_friendlyname');
|
||||
$aAttToLoadWithAttDef[$sClassAlias][$sAttToLoad.'_friendlyname'] = $oFriendlyNameAttDef;
|
||||
// Add the archive flag if necessary
|
||||
$oArchiveFlagAttDef = MetaModel::GetAttributeDef($sClass, $sAttToLoad.'_archive_flag');
|
||||
$aAttToLoadWithAttDef[$sClassAlias][$sAttToLoad.'_archive_flag'] = $oArchiveFlagAttDef;
|
||||
}
|
||||
|
||||
if (MetaModel::IsArchivable($oAttDef->GetTargetClass(EXTKEY_ABSOLUTE)))
|
||||
{
|
||||
// Add the archive flag if necessary
|
||||
$oArchiveFlagAttDef = MetaModel::GetAttributeDef($sClass, $sAttToLoad.'_archive_flag');
|
||||
$aAttToLoadWithAttDef[$sClassAlias][$sAttToLoad.'_archive_flag'] = $oArchiveFlagAttDef;
|
||||
}
|
||||
|
||||
if (MetaModel::IsObsoletable($oAttDef->GetTargetClass(EXTKEY_ABSOLUTE)))
|
||||
{
|
||||
// Add the obsolescence flag if necessary
|
||||
$oObsoleteFlagAttDef = MetaModel::GetAttributeDef($sClass, $sAttToLoad.'_obsolescence_flag');
|
||||
$aAttToLoadWithAttDef[$sClassAlias][$sAttToLoad.'_obsolescence_flag'] = $oObsoleteFlagAttDef;
|
||||
}
|
||||
if (MetaModel::IsObsoletable($oAttDef->GetTargetClass(EXTKEY_ABSOLUTE)))
|
||||
{
|
||||
// Add the obsolescence flag if necessary
|
||||
$oObsoleteFlagAttDef = MetaModel::GetAttributeDef($sClass, $sAttToLoad.'_obsolescence_flag');
|
||||
$aAttToLoadWithAttDef[$sClassAlias][$sAttToLoad.'_obsolescence_flag'] = $oObsoleteFlagAttDef;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Add the friendly name anytime
|
||||
$oFriendlyNameAttDef = MetaModel::GetAttributeDef($sClass, 'friendlyname');
|
||||
$aAttToLoadWithAttDef[$sClassAlias]['friendlyname'] = $oFriendlyNameAttDef;
|
||||
}
|
||||
// Add the friendly name anytime
|
||||
$oFriendlyNameAttDef = MetaModel::GetAttributeDef($sClass, 'friendlyname');
|
||||
$aAttToLoadWithAttDef[$sClassAlias]['friendlyname'] = $oFriendlyNameAttDef;
|
||||
|
||||
if (MetaModel::IsArchivable($sClass))
|
||||
{
|
||||
// Add the archive flag if necessary
|
||||
$oArchiveFlagAttDef = MetaModel::GetAttributeDef($sClass, 'archive_flag');
|
||||
$aAttToLoadWithAttDef[$sClassAlias]['archive_flag'] = $oArchiveFlagAttDef;
|
||||
}
|
||||
|
||||
if (MetaModel::IsObsoletable($sClass))
|
||||
{
|
||||
// Add the obsolescence flag if necessary
|
||||
$oObsoleteFlagAttDef = MetaModel::GetAttributeDef($sClass, 'obsolescence_flag');
|
||||
$aAttToLoadWithAttDef[$sClassAlias]['obsolescence_flag'] = $oObsoleteFlagAttDef;
|
||||
}
|
||||
|
||||
// Make sure that the final class is requested anytime, whatever the specification (needed for object construction!)
|
||||
if (!MetaModel::IsStandaloneClass($sClass) && !array_key_exists('finalclass', $aAttToLoadWithAttDef[$sClassAlias]))
|
||||
{
|
||||
$aAttToLoadWithAttDef[$sClassAlias]['finalclass'] = MetaModel::GetAttributeDef($sClass, 'finalclass');
|
||||
}
|
||||
if (MetaModel::IsArchivable($sClass))
|
||||
{
|
||||
// Add the archive flag if necessary
|
||||
$oArchiveFlagAttDef = MetaModel::GetAttributeDef($sClass, 'archive_flag');
|
||||
$aAttToLoadWithAttDef[$sClassAlias]['archive_flag'] = $oArchiveFlagAttDef;
|
||||
}
|
||||
|
||||
$this->m_aAttToLoad = $aAttToLoadWithAttDef;
|
||||
if (MetaModel::IsObsoletable($sClass))
|
||||
{
|
||||
// Add the obsolescence flag if necessary
|
||||
$oObsoleteFlagAttDef = MetaModel::GetAttributeDef($sClass, 'obsolescence_flag');
|
||||
$aAttToLoadWithAttDef[$sClassAlias]['obsolescence_flag'] = $oObsoleteFlagAttDef;
|
||||
}
|
||||
|
||||
// Make sure that the final class is requested anytime, whatever the specification (needed for object construction!)
|
||||
if (!MetaModel::IsStandaloneClass($sClass) && !array_key_exists('finalclass', $aAttToLoadWithAttDef[$sClassAlias]))
|
||||
{
|
||||
$aAttToLoadWithAttDef[$sClassAlias]['finalclass'] = MetaModel::GetAttributeDef($sClass, 'finalclass');
|
||||
}
|
||||
}
|
||||
|
||||
$this->m_aAttToLoad = $aAttToLoadWithAttDef;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -415,7 +424,7 @@ class DBObjectSet implements iDBObjectSetIterator
|
||||
*
|
||||
* @api
|
||||
*
|
||||
* @param bool $bWithId
|
||||
* @param bool $bWithId if true array key will be set to object id
|
||||
*
|
||||
* @return DBObject[]
|
||||
*
|
||||
@@ -971,7 +980,15 @@ class DBObjectSet implements iDBObjectSetIterator
|
||||
}
|
||||
else
|
||||
{
|
||||
$oRetObj = MetaModel::GetObjectByRow($sClass, $aRow, $sClassAlias, $this->m_aAttToLoad, $this->m_aExtendedDataSpec);
|
||||
try
|
||||
{
|
||||
$oRetObj = MetaModel::GetObjectByRow($sClass, $aRow, $sClassAlias, $this->m_aAttToLoad, $this->m_aExtendedDataSpec);
|
||||
}
|
||||
catch (CoreException $e)
|
||||
{
|
||||
$this->m_iCurrRow++;
|
||||
$oRetObj = $this->Fetch($sRequestedClassAlias);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -1,24 +1,39 @@
|
||||
<?php
|
||||
// Copyright (C) 2015-2017 Combodo SARL
|
||||
//
|
||||
// This file is part of iTop.
|
||||
//
|
||||
// iTop is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// iTop is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with iTop. If not, see <http://www.gnu.org/licenses/>
|
||||
/**
|
||||
* Copyright (C) 2013-2019 Combodo SARL
|
||||
*
|
||||
* This file is part of iTop.
|
||||
*
|
||||
* iTop is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* iTop is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
*/
|
||||
|
||||
|
||||
require_once('dbobjectsearch.class.php');
|
||||
require_once('dbunionsearch.class.php');
|
||||
$bUseLegacyDBSearch = utils::GetConfig()->Get('use_legacy_dbsearch');
|
||||
|
||||
if ($bUseLegacyDBSearch)
|
||||
{
|
||||
// excluded from autoload
|
||||
require_once (APPROOT.'core/legacy/querybuilderexpressionslegacy.class.inc.php');
|
||||
require_once (APPROOT.'core/legacy/querybuildercontextlegacy.class.inc.php');
|
||||
require_once(APPROOT.'core/legacy/dbobjectsearchlegacy.class.php');
|
||||
}
|
||||
else
|
||||
{
|
||||
// excluded from autoload
|
||||
require_once (APPROOT.'core/querybuilderexpressions.class.inc.php');
|
||||
require_once (APPROOT.'core/querybuildercontext.class.inc.php');
|
||||
require_once(APPROOT.'core/dbobjectsearch.class.php');
|
||||
}
|
||||
|
||||
/**
|
||||
* An object search
|
||||
@@ -82,42 +97,40 @@ abstract class DBSearch
|
||||
/**
|
||||
* Perform a deep clone (as opposed to "clone" which does copy a reference to the underlying objects)
|
||||
*
|
||||
* @internal
|
||||
*
|
||||
* @internal
|
||||
*
|
||||
* @return \DBSearch
|
||||
**/
|
||||
**/
|
||||
public function DeepClone()
|
||||
{
|
||||
return unserialize(serialize($this)); // Beware this serializes/unserializes the search and its parameters as well
|
||||
}
|
||||
|
||||
/**
|
||||
* whether or not some information should be hidden to the current user.
|
||||
*
|
||||
* @api
|
||||
* @see IsAllDataAllowed()
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
abstract public function AllowAllData();
|
||||
/**
|
||||
* @api
|
||||
* @see IsAllDataAllowed()
|
||||
*
|
||||
* @param bool $bAllowAllData whether or not some information should be hidden to the current user.
|
||||
*/
|
||||
abstract public function AllowAllData($bAllowAllData = true);
|
||||
|
||||
/**
|
||||
* Current state of AllowAllData
|
||||
*
|
||||
* @internal
|
||||
* @see AllowAllData()
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
/**
|
||||
* Current state of AllowAllData
|
||||
*
|
||||
* @internal
|
||||
* @see AllowAllData()
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
abstract public function IsAllDataAllowed();
|
||||
|
||||
/**
|
||||
* Should the archives be fetched
|
||||
*
|
||||
* @internal
|
||||
*
|
||||
* @param $bEnable
|
||||
*/
|
||||
/**
|
||||
* Should the archives be fetched
|
||||
*
|
||||
* @internal
|
||||
*
|
||||
* @param $bEnable
|
||||
*/
|
||||
public function SetArchiveMode($bEnable)
|
||||
{
|
||||
$this->m_bArchiveMode = $bEnable;
|
||||
@@ -223,6 +236,12 @@ abstract class DBSearch
|
||||
*/
|
||||
abstract public function GetClassAlias();
|
||||
|
||||
/**
|
||||
* @return string
|
||||
* @internal
|
||||
*/
|
||||
abstract public function GetFirstJoinedClass();
|
||||
|
||||
/**
|
||||
* Change the class
|
||||
*
|
||||
@@ -257,6 +276,10 @@ abstract class DBSearch
|
||||
*/
|
||||
abstract public function RenameAlias($sOldName, $sNewName);
|
||||
|
||||
abstract public function RenameAliasesInNameSpace($aClassAliases, $aAliasTranslation = array());
|
||||
|
||||
abstract public function TranslateConditions($aTranslationData, $bMatchAll = true, $bMarkFieldsAsResolved = true);
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* @return mixed
|
||||
@@ -379,7 +402,9 @@ abstract class DBSearch
|
||||
*/
|
||||
abstract public function AddCondition_FullText($sFullText);
|
||||
|
||||
/**
|
||||
abstract public function AddCondition_FullTextOnAttributes(array $aAttCodes, $sNeedle);
|
||||
|
||||
/**
|
||||
* Perform a join, the remote class being matched by the mean of its primary key
|
||||
*
|
||||
* The join is performed
|
||||
@@ -419,11 +444,27 @@ abstract class DBSearch
|
||||
*/
|
||||
abstract public function AddCondition_ReferencedBy(DBObjectSearch $oFilter, $sForeignExtKeyAttCode, $iOperatorCode = TREE_OPERATOR_EQUALS, &$aRealiasingMap = null);
|
||||
|
||||
/**
|
||||
/**
|
||||
* Filter this search with another search.
|
||||
* Initial search is unmodified.
|
||||
* The difference with Intersect, is that an alias can be provided,
|
||||
* the filtered class does not need to be the first joined class,
|
||||
* it can be any class of the search.
|
||||
*
|
||||
* @param string $sClassAlias class being filtered
|
||||
* @param DBSearch $oFilter Filter to apply
|
||||
*
|
||||
* @return DBSearch The filtered search
|
||||
* @throws \CoreException
|
||||
*/
|
||||
abstract public function Filter($sClassAlias, DBSearch $oFilter);
|
||||
|
||||
/**
|
||||
* Filter the result
|
||||
*
|
||||
* The filter is performed by returning only the values in common with the given $oFilter
|
||||
* The impact on the resulting query performance/viability can be significant.
|
||||
* Only the first joined class can be filtered.
|
||||
*
|
||||
* @internal
|
||||
*
|
||||
@@ -442,7 +483,7 @@ abstract class DBSearch
|
||||
*
|
||||
* @param DBSearch $oFilter The join is performed against $oFilter selected class
|
||||
* @param integer $iDirection can be either DBSearch::JOIN_POINTING_TO or DBSearch::JOIN_REFERENCED_BY
|
||||
* @param string $sExtKeyAttCode The join is performed against $sExtKeyAttCode wetheir it is compared aginst the current DBSearch or $oFilter depend of $iDirection
|
||||
* @param string $sExtKeyAttCode The join is performed against $sExtKeyAttCode whether it is compared against the current DBSearch or $oFilter depend of $iDirection
|
||||
* @param integer $iOperatorCode See DBSearch::AddCondition_PointingTo()
|
||||
* @param array|null $aRealiasingMap Map of aliases from the attached query, that could have been renamed by the optimization process
|
||||
*
|
||||
@@ -466,6 +507,7 @@ abstract class DBSearch
|
||||
}
|
||||
else
|
||||
{
|
||||
/** @var \DBObjectSearch $oFilter */
|
||||
if ($iDirection === static::JOIN_POINTING_TO)
|
||||
{
|
||||
$oSourceFilter->AddCondition_PointingTo($oFilter, $sExtKeyAttCode, $iOperatorCode, $aRealiasingMap);
|
||||
@@ -589,7 +631,7 @@ abstract class DBSearch
|
||||
}
|
||||
|
||||
$sOql = $this->ToOql($bDevelopParams, $aContextParams);
|
||||
return json_encode(array($sOql, $aQueryParams, $this->m_aModifierProperties));
|
||||
return urlencode(json_encode(array($sOql, $aQueryParams, $this->m_aModifierProperties)));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -606,7 +648,7 @@ abstract class DBSearch
|
||||
*/
|
||||
static public function unserialize($sValue)
|
||||
{
|
||||
$aData = json_decode($sValue, true);
|
||||
$aData = json_decode(urldecode($sValue), true);
|
||||
if (is_null($aData))
|
||||
{
|
||||
throw new CoreException("Invalid filter parameter");
|
||||
@@ -669,6 +711,15 @@ abstract class DBSearch
|
||||
*/
|
||||
abstract public function ToOQL($bDevelopParams = false, $aContextParams = null, $bWithAllowAllFlag = false);
|
||||
|
||||
/**
|
||||
* Export the DBSearch as a structure (array of arrays...) suitable for a conversion to JSON
|
||||
*
|
||||
* @internal
|
||||
*
|
||||
* @return mixed[string]
|
||||
*/
|
||||
abstract public function ToJSON();
|
||||
|
||||
static protected $m_aOQLQueries = array();
|
||||
|
||||
/**
|
||||
@@ -704,12 +755,13 @@ abstract class DBSearch
|
||||
*
|
||||
* @param string $sQuery The OQL to convert to a DBSearch
|
||||
* @param mixed[string] $aParams array of <mixed> params index by <string> name
|
||||
* @param ModelReflection|null $oMetaModel The MetaModel to use when checking the consistency of the OQL
|
||||
*
|
||||
* @return DBObjectSearch|DBUnionSearch
|
||||
*
|
||||
* @throws OQLException
|
||||
*/
|
||||
static public function FromOQL($sQuery, $aParams = null)
|
||||
static public function FromOQL($sQuery, $aParams = null, ModelReflection $oMetaModel=null)
|
||||
{
|
||||
if (empty($sQuery))
|
||||
{
|
||||
@@ -751,7 +803,10 @@ abstract class DBSearch
|
||||
$oOql = new OqlInterpreter($sQuery);
|
||||
$oOqlQuery = $oOql->ParseQuery();
|
||||
|
||||
$oMetaModel = new ModelReflectionRuntime();
|
||||
if ($oMetaModel === null)
|
||||
{
|
||||
$oMetaModel = new ModelReflectionRuntime();
|
||||
}
|
||||
$oOqlQuery->Check($oMetaModel, $sQuery); // Exceptions thrown in case of issue
|
||||
|
||||
$oResultFilter = $oOqlQuery->ToDBSearch($sQuery);
|
||||
@@ -925,29 +980,35 @@ abstract class DBSearch
|
||||
$aAttToLoad = array();
|
||||
$oSQLQuery = $oQueryFilter->GetSQLQuery(array(), $aArgs, $aAttToLoad, null, 0, 0, false, $aGroupByExpr, $aSelectExpr);
|
||||
|
||||
$aScalarArgs = MetaModel::PrepareQueryArguments($aArgs, $this->GetInternalParams());
|
||||
$aScalarArgs = MetaModel::PrepareQueryArguments($aArgs, $this->GetInternalParams(), $this->GetExpectedArguments());
|
||||
try
|
||||
{
|
||||
$bBeautifulSQL = self::$m_bTraceQueries || self::$m_bDebugQuery || self::$m_bIndentQueries;
|
||||
$sRes = $oSQLQuery->RenderGroupBy($aScalarArgs, $bBeautifulSQL, $aOrderBy, $iLimitCount, $iLimitStart);
|
||||
}
|
||||
catch (Exception $e)
|
||||
// Catch CoreException to add info before throwing again
|
||||
// Other exceptions will be thrown directly
|
||||
catch (CoreException $e)
|
||||
{
|
||||
// Add some information...
|
||||
$e->addInfo('OQL', $this->ToOQL());
|
||||
throw $e;
|
||||
}
|
||||
$this->AddQueryTraceGroupBy($aArgs, $aGroupByExpr, $sRes);
|
||||
$this->AddQueryTraceGroupBy($aArgs, $aGroupByExpr, $bExcludeNullValues, $aSelectExpr, $aOrderBy, $iLimitCount, $iLimitStart, $sRes);
|
||||
return $sRes;
|
||||
}
|
||||
|
||||
function GetExpectedArguments()
|
||||
{
|
||||
return $this->GetCriteria()->ListParameters();
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a SQL query from the current search
|
||||
*
|
||||
* @internal
|
||||
*
|
||||
* @param array|hash $aOrderBy Array of '[<classalias>.]attcode' => bAscending
|
||||
* @param array $aOrderBy Array of '[<classalias>.]attcode' => bAscending
|
||||
* @param array $aArgs
|
||||
* @param null $aAttToLoad
|
||||
* @param null $aExtendedDataSpec
|
||||
@@ -1020,12 +1081,12 @@ abstract class DBSearch
|
||||
else
|
||||
{
|
||||
// The complete list of arguments will include magic arguments (e.g. current_user->attcode)
|
||||
$aScalarArgs = MetaModel::PrepareQueryArguments($aArgs, $this->GetInternalParams());
|
||||
$aScalarArgs = MetaModel::PrepareQueryArguments($aArgs, $this->GetInternalParams(), $this->GetExpectedArguments());
|
||||
}
|
||||
try
|
||||
{
|
||||
$bBeautifulSQL = self::$m_bTraceQueries || self::$m_bDebugQuery || self::$m_bIndentQueries;
|
||||
$sRes = $oSQLQuery->RenderSelect($aOrderSpec, $aScalarArgs, $iLimitCount, $iLimitStart, $bGetCount, $bBeautifulSQL);
|
||||
// $bBeautifulSQL = self::$m_bTraceQueries || self::$m_bDebugQuery || self::$m_bIndentQueries;
|
||||
$sRes = $oSQLQuery->RenderSelect($aOrderSpec, $aScalarArgs, $iLimitCount, $iLimitStart, $bGetCount, true);
|
||||
if ($sClassAlias == '_itop_')
|
||||
{
|
||||
IssueLog::Info('SQL Query (_itop_): '.$sRes);
|
||||
@@ -1037,10 +1098,45 @@ abstract class DBSearch
|
||||
$e->addInfo('OQL', $this->ToOQL());
|
||||
throw $e;
|
||||
}
|
||||
$this->AddQueryTraceSelect($aOrderBy, $aArgs, $aAttToLoad, $aExtendedDataSpec, $iLimitCount, $iLimitStart, $bGetCount, $sRes);
|
||||
$this->AddQueryTraceSelect($oSQLQuery->GetSourceOQL(), $aOrderBy, $aScalarArgs, $aAttToLoad, $aExtendedDataSpec, $iLimitCount, $iLimitStart, $bGetCount, $sRes);
|
||||
return $sRes;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bool $bMustHaveOneResultMax if true will throw a CoreOqlMultipleResultsFound if multiple results
|
||||
* @param array $aOrderBy
|
||||
* @param array $aSearchParams
|
||||
*
|
||||
* @return null|\DBObject query result
|
||||
* @throws \CoreOqlMultipleResultsForbiddenException if multiple results found and parameter enforce the check
|
||||
* @throws \CoreException
|
||||
* @throws \CoreUnexpectedValue
|
||||
* @throws \MySQLException
|
||||
*
|
||||
* @since 2.7.0 N°2555
|
||||
*/
|
||||
public function GetFirstResult($bMustHaveOneResultMax = true, $aOrderBy = array(), $aSearchParams = array())
|
||||
{
|
||||
$oSet = new DBObjectSet($this, array(), $aSearchParams, null, 2);
|
||||
$oFirstResult = $oSet->Fetch();
|
||||
if ($oFirstResult === null) // useless but here for readability ;)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
if ($bMustHaveOneResultMax)
|
||||
{
|
||||
$oSecondResult = $oSet->Fetch();
|
||||
if ($oSecondResult !== null)
|
||||
{
|
||||
throw new CoreOqlMultipleResultsForbiddenException(
|
||||
'Search returned multiple results, this is forbidden. Query was: '.$this->ToOQL());
|
||||
}
|
||||
}
|
||||
|
||||
return $oFirstResult;
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* @return mixed
|
||||
@@ -1053,38 +1149,41 @@ abstract class DBSearch
|
||||
*/
|
||||
protected abstract function SetDataFiltered();
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*
|
||||
* @param $aOrderBy
|
||||
* @param $aArgs
|
||||
* @param $aAttToLoad
|
||||
* @param $aExtendedDataSpec
|
||||
* @param $iLimitCount
|
||||
* @param $iLimitStart
|
||||
* @param $bGetCount
|
||||
* @param null $aGroupByExpr
|
||||
* @param null $aSelectExpr
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
/**
|
||||
* @param $aOrderBy
|
||||
* @param $aArgs
|
||||
* @param $aAttToLoad
|
||||
* @param $aExtendedDataSpec
|
||||
* @param $iLimitCount
|
||||
* @param $iLimitStart
|
||||
* @param $bGetCount
|
||||
* @param null $aGroupByExpr
|
||||
* @param null $aSelectExpr
|
||||
*
|
||||
* @return SQLObjectQuery
|
||||
* @throws \CoreException
|
||||
* @internal
|
||||
*
|
||||
*/
|
||||
protected function GetSQLQuery($aOrderBy, $aArgs, $aAttToLoad, $aExtendedDataSpec, $iLimitCount, $iLimitStart, $bGetCount, $aGroupByExpr = null, $aSelectExpr = null)
|
||||
{
|
||||
$oSearch = $this;
|
||||
if (!$this->IsAllDataAllowed() && !$this->IsDataFiltered())
|
||||
{
|
||||
$oVisibleObjects = UserRights::GetSelectFilter($this->GetClass(), $this->GetModifierProperties('UserRightsGetSelectFilter'));
|
||||
if ($oVisibleObjects === false)
|
||||
foreach ($this->GetSelectedClasses() as $sClassAlias => $sClass)
|
||||
{
|
||||
// Make sure this is a valid search object, saying NO for all
|
||||
$oVisibleObjects = DBObjectSearch::FromEmptySet($this->GetClass());
|
||||
}
|
||||
if (is_object($oVisibleObjects))
|
||||
{
|
||||
$oVisibleObjects->AllowAllData();
|
||||
$oSearch = $this->Intersect($oVisibleObjects);
|
||||
/** @var DBSearch $oSearch */
|
||||
$oSearch->SetDataFiltered();
|
||||
$oVisibleObjects = UserRights::GetSelectFilter($sClass, $this->GetModifierProperties('UserRightsGetSelectFilter'));
|
||||
if ($oVisibleObjects === false)
|
||||
{
|
||||
// Make sure this is a valid search object, saying NO for all
|
||||
$oVisibleObjects = DBObjectSearch::FromEmptySet($sClass);
|
||||
}
|
||||
if (is_object($oVisibleObjects))
|
||||
{
|
||||
$oVisibleObjects->AllowAllData();
|
||||
$oSearch = $oSearch->Filter($sClassAlias, $oVisibleObjects);
|
||||
$oSearch->SetDataFiltered();
|
||||
}
|
||||
}
|
||||
}
|
||||
$oSQLQuery = $oSearch->GetSQLQueryStructure($aAttToLoad, $bGetCount, $aGroupByExpr, null, $aSelectExpr);
|
||||
@@ -1133,6 +1232,8 @@ abstract class DBSearch
|
||||
*/
|
||||
public abstract function GetCriteria();
|
||||
|
||||
public abstract function ListParameters();
|
||||
|
||||
/**
|
||||
* Shortcut to add efficient IN condition
|
||||
*
|
||||
@@ -1226,61 +1327,112 @@ abstract class DBSearch
|
||||
self::$m_bOptimizeQueries = $bEnabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*
|
||||
* @param $aOrderBy
|
||||
* @param $aArgs
|
||||
* @param $aAttToLoad
|
||||
* @param $aExtendedDataSpec
|
||||
* @param $iLimitCount
|
||||
* @param $iLimitStart
|
||||
* @param $bGetCount
|
||||
* @param $sSql
|
||||
*
|
||||
* @throws MySQLException
|
||||
*/
|
||||
protected function AddQueryTraceSelect($aOrderBy, $aArgs, $aAttToLoad, $aExtendedDataSpec, $iLimitCount, $iLimitStart, $bGetCount, $sSql)
|
||||
/**
|
||||
* @param $sOql
|
||||
* @param $aOrderBy
|
||||
* @param $aArgs
|
||||
* @param $aAttToLoad
|
||||
* @param $aExtendedDataSpec
|
||||
* @param $iLimitCount
|
||||
* @param $iLimitStart
|
||||
* @param $bGetCount
|
||||
* @param $sSql
|
||||
*
|
||||
* @throws \ConfigException
|
||||
* @throws \CoreException
|
||||
* @internal
|
||||
*
|
||||
*/
|
||||
protected function AddQueryTraceSelect($sOql, $aOrderBy, $aArgs, $aAttToLoad, $aExtendedDataSpec, $iLimitCount, $iLimitStart, $bGetCount, $sSql)
|
||||
{
|
||||
if (self::$m_bTraceQueries)
|
||||
{
|
||||
$aQueryData = array(
|
||||
'type' => 'select',
|
||||
'filter' => $this,
|
||||
'order_by' => $aOrderBy,
|
||||
'args' => $aArgs,
|
||||
'att_to_load' => $aAttToLoad,
|
||||
'extended_data_spec' => $aExtendedDataSpec,
|
||||
'limit_count' => $iLimitCount,
|
||||
'limit_start' => $iLimitStart,
|
||||
'is_count' => $bGetCount
|
||||
);
|
||||
$sOql = $this->ToOQL(true, $aArgs);
|
||||
self::AddQueryTrace($aQueryData, $sOql, $sSql);
|
||||
|
||||
DBSearch::EnableQueryTrace(false);
|
||||
$aQueryData['oql'] = $this->ToOQL(true, $aArgs);
|
||||
DBSearch::EnableQueryTrace(true);
|
||||
|
||||
if (!empty($aAttToLoad))
|
||||
{
|
||||
$aAttToLoadNames = array();
|
||||
foreach ($aAttToLoad as $sClass => $aAttributes)
|
||||
{
|
||||
$aAttToLoadNames[$sClass] = array();
|
||||
foreach ($aAttributes as $sAttCode => $oAttDef)
|
||||
{
|
||||
$aAttToLoadNames[$sClass][] = $sAttCode;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$aAttToLoadNames = null;
|
||||
}
|
||||
$aQueryData['att_to_load'] = $aAttToLoadNames;
|
||||
|
||||
$hLogFile = @fopen(APPROOT.'log/oql_records.txt', 'a');
|
||||
if ($hLogFile !== false)
|
||||
{
|
||||
flock($hLogFile,LOCK_EX);
|
||||
fwrite($hLogFile,serialize($aQueryData)."\n");
|
||||
fflush($hLogFile);
|
||||
flock($hLogFile,LOCK_UN);
|
||||
fclose($hLogFile);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*
|
||||
* @param $aArgs
|
||||
* @param $aGroupByExpr
|
||||
* @param $sSql
|
||||
*
|
||||
* @throws MySQLException
|
||||
*/
|
||||
protected function AddQueryTraceGroupBy($aArgs, $aGroupByExpr, $sSql)
|
||||
/**
|
||||
* @param $aArgs
|
||||
* @param $aGroupByExpr
|
||||
* @param $bExcludeNullValues
|
||||
* @param $aSelectExpr
|
||||
* @param $aOrderBy
|
||||
* @param $iLimitCount
|
||||
* @param $iLimitStart
|
||||
* @param $sSql
|
||||
*
|
||||
* @throws \ConfigException
|
||||
* @throws \CoreException
|
||||
* @throws \MySQLException
|
||||
* @internal
|
||||
*
|
||||
*/
|
||||
protected function AddQueryTraceGroupBy($aArgs, $aGroupByExpr, $bExcludeNullValues, $aSelectExpr, $aOrderBy, $iLimitCount, $iLimitStart, $sSql)
|
||||
{
|
||||
if (self::$m_bTraceQueries)
|
||||
{
|
||||
$aQueryData = array(
|
||||
'type' => 'group_by',
|
||||
'filter' => $this,
|
||||
'args' => $aArgs,
|
||||
'group_by_expr' => $aGroupByExpr
|
||||
'order_by' => $aOrderBy,
|
||||
'group_by_expr' => $aGroupByExpr,
|
||||
'exclude_null_values' => $bExcludeNullValues,
|
||||
'select_expr' => $aSelectExpr,
|
||||
'limit_count' => $iLimitCount,
|
||||
'limit_start' => $iLimitStart,
|
||||
);
|
||||
$sOql = $this->ToOQL(true, $aArgs);
|
||||
self::AddQueryTrace($aQueryData, $sOql, $sSql);
|
||||
|
||||
$aQueryData['oql'] = $this->ToOQL(true, $aArgs);
|
||||
$aQueryData['group_by_expr'] = Expression::ConvertArrayToOQL($aQueryData['group_by_expr'], $aArgs);
|
||||
$aQueryData['select_expr'] = Expression::ConvertArrayToOQL($aQueryData['select_expr'], $aArgs);
|
||||
|
||||
$hLogFile = @fopen(APPROOT.'log/oql_group_by_records.txt', 'a');
|
||||
if ($hLogFile !== false)
|
||||
{
|
||||
flock($hLogFile,LOCK_EX);
|
||||
fwrite($hLogFile,serialize($aQueryData)."\n");
|
||||
fflush($hLogFile);
|
||||
flock($hLogFile,LOCK_UN);
|
||||
fclose($hLogFile);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1424,15 +1576,16 @@ abstract class DBSearch
|
||||
}
|
||||
|
||||
/**
|
||||
* Experimental!
|
||||
* @todo implement the change tracking
|
||||
*
|
||||
* @internal
|
||||
* Updates archive_flag and archive_date fields in the whole class hierarchy
|
||||
*
|
||||
* @see \DBObject::DBWriteArchiveFlag()
|
||||
*
|
||||
* @param boolean $bArchive
|
||||
*
|
||||
* @param $bArchive
|
||||
* @throws Exception
|
||||
* @todo implement the change tracking
|
||||
*/
|
||||
function DBBulkWriteArchiveFlag($bArchive)
|
||||
public function DBBulkWriteArchiveFlag($bArchive)
|
||||
{
|
||||
$sClass = $this->GetClass();
|
||||
if (!MetaModel::IsArchivable($sClass))
|
||||
|
||||
@@ -65,9 +65,7 @@ class DBUnionSearch extends DBSearch
|
||||
{
|
||||
$this->aSearches[] = $oSubSearch->DeepClone();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
$this->aSearches[] = $oSearch->DeepClone();
|
||||
}
|
||||
}
|
||||
@@ -75,17 +73,16 @@ class DBUnionSearch extends DBSearch
|
||||
$this->ComputeSelectedClasses();
|
||||
}
|
||||
|
||||
public function AllowAllData()
|
||||
public function AllowAllData($bAllowAllData = true)
|
||||
{
|
||||
foreach ($this->aSearches as $oSearch)
|
||||
{
|
||||
foreach ($this->aSearches as $oSearch) {
|
||||
$oSearch->AllowAllData();
|
||||
}
|
||||
}
|
||||
|
||||
public function IsAllDataAllowed()
|
||||
{
|
||||
foreach ($this->aSearches as $oSearch)
|
||||
{
|
||||
foreach ($this->aSearches as $oSearch) {
|
||||
if ($oSearch->IsAllDataAllowed() === false) return false;
|
||||
}
|
||||
return true;
|
||||
@@ -161,6 +158,11 @@ class DBUnionSearch extends DBSearch
|
||||
return $this->aSearches;
|
||||
}
|
||||
|
||||
public function GetFirstJoinedClass()
|
||||
{
|
||||
return $this->GetClass();
|
||||
}
|
||||
|
||||
/**
|
||||
* Limited to the selected classes
|
||||
*/
|
||||
@@ -258,6 +260,24 @@ class DBUnionSearch extends DBSearch
|
||||
return $bRet;
|
||||
}
|
||||
|
||||
public function RenameAliasesInNameSpace($aClassAliases, $aAliasTranslation = array())
|
||||
{
|
||||
foreach ($this->aSearches as $oSearch)
|
||||
{
|
||||
$oSearch->RenameAliasesInNameSpace($aClassAliases, $aAliasTranslation);
|
||||
}
|
||||
}
|
||||
|
||||
public function TranslateConditions($aTranslationData, $bMatchAll = true, $bMarkFieldsAsResolved = true)
|
||||
{
|
||||
foreach ($this->aSearches as $oSearch)
|
||||
{
|
||||
$oSearch->TranslateConditions($aTranslationData, $bMatchAll, $bMarkFieldsAsResolved);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
public function IsAny()
|
||||
{
|
||||
$bIsAny = true;
|
||||
@@ -353,19 +373,26 @@ class DBUnionSearch extends DBSearch
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
public function AddCondition_FullTextOnAttributes(array $aAttCodes, $sNeedle)
|
||||
{
|
||||
foreach ($this->aSearches as $oSearch)
|
||||
{
|
||||
$oSearch->AddCondition_FullTextOnAttributes($aAttCodes, $sNeedle);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param DBObjectSearch $oFilter
|
||||
* @param $sExtKeyAttCode
|
||||
* @param int $iOperatorCode
|
||||
* @param null $aRealiasingMap array of <old-alias> => <new-alias>, for each alias that has changed
|
||||
* @throws CoreException
|
||||
* @throws CoreWarning
|
||||
* @param null $aRealiasingMap array of [old-alias][] => <new-alias>, for each alias that has changed (@since 2.7.2)
|
||||
*/
|
||||
public function AddCondition_PointingTo(DBObjectSearch $oFilter, $sExtKeyAttCode, $iOperatorCode = TREE_OPERATOR_EQUALS, &$aRealiasingMap = null)
|
||||
{
|
||||
foreach ($this->aSearches as $oSearch)
|
||||
{
|
||||
$oSearch->AddCondition_PointingTo($oFilter, $sExtKeyAttCode, $iOperatorCode, $aRealiasingMap);
|
||||
$oConditionFilter = $oFilter->DeepClone();
|
||||
$oSearch->AddCondition_PointingTo($oConditionFilter, $sExtKeyAttCode, $iOperatorCode, $aRealiasingMap);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -373,16 +400,27 @@ class DBUnionSearch extends DBSearch
|
||||
* @param DBObjectSearch $oFilter
|
||||
* @param $sForeignExtKeyAttCode
|
||||
* @param int $iOperatorCode
|
||||
* @param null $aRealiasingMap array of <old-alias> => <new-alias>, for each alias that has changed
|
||||
* @param null $aRealiasingMap array of [old-alias][] => <new-alias>, for each alias that has changed (@since 2.7.2)
|
||||
*/
|
||||
public function AddCondition_ReferencedBy(DBObjectSearch $oFilter, $sForeignExtKeyAttCode, $iOperatorCode = TREE_OPERATOR_EQUALS, &$aRealiasingMap = null)
|
||||
{
|
||||
foreach ($this->aSearches as $oSearch)
|
||||
{
|
||||
$oSearch->AddCondition_ReferencedBy($oFilter, $sForeignExtKeyAttCode, $iOperatorCode, $aRealiasingMap);
|
||||
$oConditionFilter = $oFilter->DeepClone();
|
||||
$oSearch->AddCondition_ReferencedBy($oConditionFilter, $sForeignExtKeyAttCode, $iOperatorCode, $aRealiasingMap);
|
||||
}
|
||||
}
|
||||
|
||||
public function Filter($sClassAlias, DBSearch $oFilter)
|
||||
{
|
||||
$aSearches = array();
|
||||
foreach ($this->aSearches as $oSearch)
|
||||
{
|
||||
$aSearches[] = $oSearch->Filter($sClassAlias, $oFilter);
|
||||
}
|
||||
return new DBUnionSearch($aSearches);
|
||||
}
|
||||
|
||||
public function Intersect(DBSearch $oFilter)
|
||||
{
|
||||
$aSearches = array();
|
||||
@@ -453,10 +491,25 @@ class DBUnionSearch extends DBSearch
|
||||
return $sRet;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
* @see DBSearch::ToJSON()
|
||||
*/
|
||||
public function ToJSON()
|
||||
{
|
||||
$sRet = array('unions' => array());
|
||||
foreach ($this->aSearches as $oSearch)
|
||||
{
|
||||
$sRet['unions'][] = $oSearch->ToJSON();
|
||||
}
|
||||
return $sRet;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new DBUnionSearch object where duplicates queries have been removed based on their OQLs
|
||||
*
|
||||
*
|
||||
* @return \DBUnionSearch
|
||||
* @throws \CoreException
|
||||
*/
|
||||
public function RemoveDuplicateQueries()
|
||||
{
|
||||
@@ -498,7 +551,7 @@ class DBUnionSearch extends DBSearch
|
||||
{
|
||||
if (count($this->aSearches) == 1)
|
||||
{
|
||||
return $this->aSearches[0]->GetSQLQueryStructure($aAttToLoad, $bGetCount, $aGroupByExpr, $aSelectExpr);
|
||||
return $this->aSearches[0]->GetSQLQueryStructure($aAttToLoad, $bGetCount, $aGroupByExpr, $aSelectedClasses, $aSelectExpr);
|
||||
}
|
||||
|
||||
$aSQLQueries = array();
|
||||
@@ -619,6 +672,16 @@ class DBUnionSearch extends DBSearch
|
||||
return $oSQLQuery;
|
||||
}
|
||||
|
||||
function GetExpectedArguments()
|
||||
{
|
||||
$aVariableCriteria = array();
|
||||
foreach ($this->aSearches as $oSearch)
|
||||
{
|
||||
$aVariableCriteria = array_merge($aVariableCriteria, $oSearch->GetExpectedArguments());
|
||||
}
|
||||
|
||||
return $aVariableCriteria;
|
||||
}
|
||||
/**
|
||||
* @return \Expression
|
||||
*/
|
||||
@@ -651,6 +714,8 @@ class DBUnionSearch extends DBSearch
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
public function AddConditionForInOperatorUsingParam($sFilterCode, $aValues, $bPositiveMatch = true)
|
||||
{
|
||||
$sInParamName = $this->GenerateUniqueParamName();
|
||||
@@ -668,4 +733,14 @@ class DBUnionSearch extends DBSearch
|
||||
$oSearch->AddConditionExpression($oInCondition);
|
||||
}
|
||||
}
|
||||
|
||||
public function ListParameters()
|
||||
{
|
||||
$aParameters = array();
|
||||
foreach ($this->aSearches as $oSearch)
|
||||
{
|
||||
$aParameters = array_merge($aParameters, $oSearch->ListParameters());
|
||||
}
|
||||
return $aParameters;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -192,7 +192,11 @@ class Dict
|
||||
/**
|
||||
* Formats a localized string with numbered placeholders (%1$s...) for the additional arguments
|
||||
* See vsprintf for more information about the syntax of the placeholders
|
||||
*
|
||||
* @see \TemplateString to use placeholders
|
||||
*
|
||||
* @param string $sFormatCode
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function Format($sFormatCode /*, ... arguments ....*/)
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user