mirror of
https://github.com/Combodo/iTop.git
synced 2026-02-16 00:44:10 +01:00
Compare commits
726 Commits
2.7.6
...
3.0.0-alph
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fc24746862 | ||
|
|
d0baf298be | ||
|
|
fb70026966 | ||
|
|
ad19a89fc5 | ||
|
|
7b937016d0 | ||
|
|
e8f7c7dafe | ||
|
|
d9264e5181 | ||
|
|
f893603332 | ||
|
|
a49a56def8 | ||
|
|
2f138db4ac | ||
|
|
8d19958d6d | ||
|
|
11b6429e3c | ||
|
|
dccffc91b1 | ||
|
|
6c5e1c429f | ||
|
|
7d0f1f46d3 | ||
|
|
1e7d4e5c31 | ||
|
|
b12dadb0dc | ||
|
|
c6506c9f13 | ||
|
|
af11577450 | ||
|
|
91ab66453b | ||
|
|
b1102bc68c | ||
|
|
0443197c04 | ||
|
|
32e0c8f9bf | ||
|
|
26d912f059 | ||
|
|
3cb5f3d07e | ||
|
|
675a408ab9 | ||
|
|
2f938814e0 | ||
|
|
8042afa20f | ||
|
|
aef77d8f93 | ||
|
|
05c53d35b7 | ||
|
|
ea169e8358 | ||
|
|
28e80e5568 | ||
|
|
487e0ad5a7 | ||
|
|
106dfc63d5 | ||
|
|
5115db1b01 | ||
|
|
9621ff4d5e | ||
|
|
1c5cb4e125 | ||
|
|
dc6a900f6d | ||
|
|
0d23faba1c | ||
|
|
c861941e92 | ||
|
|
313df4551f | ||
|
|
07cc8bf508 | ||
|
|
c2e31de263 | ||
|
|
103b5bfd22 | ||
|
|
4c78ecab91 | ||
|
|
48bf954387 | ||
|
|
89c35f0345 | ||
|
|
434c829f7e | ||
|
|
4c8a8fc510 | ||
|
|
0a02c10287 | ||
|
|
d4516c214c | ||
|
|
931225ed5a | ||
|
|
18ed151e50 | ||
|
|
0046834b2c | ||
|
|
6835ebd11d | ||
|
|
62880b04eb | ||
|
|
6d82a85b12 | ||
|
|
64134ff428 | ||
|
|
c7661bcfcf | ||
|
|
291041610b | ||
|
|
a729c6c1e3 | ||
|
|
23452804aa | ||
|
|
1098182720 | ||
|
|
77ecd055b4 | ||
|
|
38fbc49e51 | ||
|
|
f9b905403d | ||
|
|
96130735c4 | ||
|
|
448afc640d | ||
|
|
f2ff5a4e83 | ||
|
|
b44e6a4a53 | ||
|
|
866a93c0c8 | ||
|
|
d7b1e60219 | ||
|
|
63d52787f0 | ||
|
|
bc809b0f3b | ||
|
|
f64cad75cd | ||
|
|
6237b5565c | ||
|
|
d76e4255f2 | ||
|
|
fa0bb2b466 | ||
|
|
8954d02796 | ||
|
|
87a2d30c78 | ||
|
|
f718b26b7b | ||
|
|
7cfd888516 | ||
|
|
cd10c41362 | ||
|
|
eb391d52fc | ||
|
|
1fc54edf21 | ||
|
|
cfbfaad154 | ||
|
|
b7543b54e8 | ||
|
|
10afd1cede | ||
|
|
b454958742 | ||
|
|
680f522065 | ||
|
|
50421f4753 | ||
|
|
7864461d85 | ||
|
|
be338e385b | ||
|
|
235b4be790 | ||
|
|
dfcc3b22a6 | ||
|
|
f3e47a15f6 | ||
|
|
a70ed7fcc2 | ||
|
|
c43d52277c | ||
|
|
8a1d17551b | ||
|
|
6e584cded4 | ||
|
|
6c7efb2448 | ||
|
|
3548d5e264 | ||
|
|
bd606ca3f9 | ||
|
|
6c5c71a0ee | ||
|
|
dfd9dd3352 | ||
|
|
6583c9495a | ||
|
|
93132dc3b4 | ||
|
|
f257dcfb85 | ||
|
|
776f32dbe1 | ||
|
|
8502fa7721 | ||
|
|
48b3716278 | ||
|
|
5f9cdc0431 | ||
|
|
6df74073a7 | ||
|
|
b59c40570b | ||
|
|
444f60c251 | ||
|
|
2425ccb8f2 | ||
|
|
4fd65a8a62 | ||
|
|
664d3251cc | ||
|
|
f31f991365 | ||
|
|
bb1a8a92dd | ||
|
|
27e1f3d64b | ||
|
|
95a2ffa0f2 | ||
|
|
b1e29cbd81 | ||
|
|
2e97b3b593 | ||
|
|
e419060e8a | ||
|
|
cfd9dba66e | ||
|
|
f72ddd72f3 | ||
|
|
d85d29155f | ||
|
|
91ee5ebfeb | ||
|
|
a6ea75f5fe | ||
|
|
dc789f51e9 | ||
|
|
116c0c0138 | ||
|
|
7fa7ebb59c | ||
|
|
0119f6c395 | ||
|
|
c8a30b0ccb | ||
|
|
8e31d77afb | ||
|
|
c7dce73116 | ||
|
|
71bb071f38 | ||
|
|
deda05351b | ||
|
|
5d1de543cc | ||
|
|
be9a428529 | ||
|
|
e7360661be | ||
|
|
6edb308480 | ||
|
|
43a4d9fcd2 | ||
|
|
9a47e3cf74 | ||
|
|
e7f01e7597 | ||
|
|
910358e04d | ||
|
|
4eebb538df | ||
|
|
d304284e36 | ||
|
|
6e6557e909 | ||
|
|
548342159b | ||
|
|
2221e0541c | ||
|
|
b15ed80732 | ||
|
|
986c08aa81 | ||
|
|
8e6351d346 | ||
|
|
9b19ae5944 | ||
|
|
e35965c065 | ||
|
|
5b2c279eac | ||
|
|
72fc22c49a | ||
|
|
b7b1ef1a1f | ||
|
|
64a96ac001 | ||
|
|
eb3ad0999a | ||
|
|
ecf678f39f | ||
|
|
5bc01d3950 | ||
|
|
2ae50dfb06 | ||
|
|
b25a6a2f04 | ||
|
|
1bd9d35979 | ||
|
|
1dd4d1479c | ||
|
|
00212e8127 | ||
|
|
061f3e9f51 | ||
|
|
e6111609b0 | ||
|
|
3556a95f3b | ||
|
|
82735254e7 | ||
|
|
44351784e6 | ||
|
|
f87002dce3 | ||
|
|
c616e9b65f | ||
|
|
03418663f2 | ||
|
|
5a072c75eb | ||
|
|
10a945eb92 | ||
|
|
6239c29422 | ||
|
|
bb53aef09f | ||
|
|
6cbc7fdb20 | ||
|
|
6a87ce48e1 | ||
|
|
7770cb31fb | ||
|
|
3adcee6da8 | ||
|
|
ff3ade7d62 | ||
|
|
ad59e81144 | ||
|
|
67ab33e727 | ||
|
|
e81e3a0f1c | ||
|
|
e89afa163e | ||
|
|
e48d257b00 | ||
|
|
51669d0479 | ||
|
|
f983655c68 | ||
|
|
157e0a6915 | ||
|
|
7d26b6092e | ||
|
|
f5e92359d9 | ||
|
|
8994f82e0f | ||
|
|
8551322cd7 | ||
|
|
be075dd695 | ||
|
|
0691fca412 | ||
|
|
3298966174 | ||
|
|
79514358db | ||
|
|
aa38be4578 | ||
|
|
e911290b3d | ||
|
|
dc24bbcd97 | ||
|
|
ea8a8e3afa | ||
|
|
6fb5d20971 | ||
|
|
b3522017e7 | ||
|
|
e5b22d270e | ||
|
|
b8af22baad | ||
|
|
5626da7a5e | ||
|
|
79ad75a2c2 | ||
|
|
41c833d0c6 | ||
|
|
29f58103b0 | ||
|
|
15a9856f89 | ||
|
|
b3bb77c8ee | ||
|
|
c2fe1bc5cb | ||
|
|
7f56911f41 | ||
|
|
83a547bbf4 | ||
|
|
8e16d537ff | ||
|
|
d9fe4599ff | ||
|
|
50bf0c9a27 | ||
|
|
261131d6d7 | ||
|
|
5276b48ed4 | ||
|
|
6fd56f750e | ||
|
|
57fda98981 | ||
|
|
ce001a8097 | ||
|
|
d49dd8b993 | ||
|
|
eeec5989d9 | ||
|
|
f25ef7f5ac | ||
|
|
5862ecde69 | ||
|
|
f8129fab74 | ||
|
|
ee9343cf40 | ||
|
|
1b2dd04409 | ||
|
|
40f3d6efbe | ||
|
|
5c07591519 | ||
|
|
f0f7653884 | ||
|
|
de54d28c6b | ||
|
|
292457595c | ||
|
|
a99f03e510 | ||
|
|
fd3f972948 | ||
|
|
12bf77d9ca | ||
|
|
c0337eaa23 | ||
|
|
b8d71b2bfb | ||
|
|
5ef6b6c5d0 | ||
|
|
078f81e853 | ||
|
|
11a79501da | ||
|
|
3dc7b66f6f | ||
|
|
2b0bdda1e0 | ||
|
|
794ee89d12 | ||
|
|
c37aabfc8c | ||
|
|
987ab4cbfb | ||
|
|
0aaa0a33bf | ||
|
|
3fd9aa01ed | ||
|
|
97380fd5f4 | ||
|
|
bcd41dfe96 | ||
|
|
54eb86a16b | ||
|
|
795b28263a | ||
|
|
8306ce36a0 | ||
|
|
6c46c7ff3a | ||
|
|
bfd4ba16d9 | ||
|
|
6969e4db1b | ||
|
|
661d84fc77 | ||
|
|
9eac12bd9c | ||
|
|
ecd5a7aadf | ||
|
|
7bf473d2a3 | ||
|
|
98d2e42bad | ||
|
|
9e9b192b3c | ||
|
|
98789f28bb | ||
|
|
33f11d2a43 | ||
|
|
40efaf0360 | ||
|
|
74160d2447 | ||
|
|
08eada82f4 | ||
|
|
9cd719ab56 | ||
|
|
e83dfe5982 | ||
|
|
077ac81208 | ||
|
|
36f8344ec9 | ||
|
|
745e4aa424 | ||
|
|
5405ae1d91 | ||
|
|
ed1bb3e93a | ||
|
|
0773660ef2 | ||
|
|
68b8490288 | ||
|
|
f100e9bd09 | ||
|
|
0ffe76e359 | ||
|
|
e3739641b4 | ||
|
|
410a637598 | ||
|
|
eded4814a1 | ||
|
|
b9f9322418 | ||
|
|
4badb90344 | ||
|
|
0542a8e4f8 | ||
|
|
f0434f9125 | ||
|
|
43cadb0ede | ||
|
|
11f00cc229 | ||
|
|
163c1ebc91 | ||
|
|
580e8ffa08 | ||
|
|
f5a3bb2baa | ||
|
|
63f8ec594c | ||
|
|
2df2392cc6 | ||
|
|
d2e5e96a63 | ||
|
|
8193ada159 | ||
|
|
46fe1661db | ||
|
|
2ff6658a56 | ||
|
|
f25cd70e73 | ||
|
|
b5cfd1c61e | ||
|
|
3c9c3204ac | ||
|
|
7ab274cb7b | ||
|
|
7d1a61a2f9 | ||
|
|
3c299654e3 | ||
|
|
1eba8ba4ac | ||
|
|
9daf23576d | ||
|
|
b9f23177e7 | ||
|
|
6542cf9d30 | ||
|
|
610e74e642 | ||
|
|
c3ecd51153 | ||
|
|
ff722b579b | ||
|
|
7e0fbd8c25 | ||
|
|
9f592223d9 | ||
|
|
99fc41a0f8 | ||
|
|
76fbd3790f | ||
|
|
d3b57c3bda | ||
|
|
a61ffaf3c0 | ||
|
|
cc6ab8a7b7 | ||
|
|
432a565221 | ||
|
|
7d8aaf91db | ||
|
|
eb99dc9f3f | ||
|
|
f59f2b2109 | ||
|
|
2840f6930b | ||
|
|
c50b6c806a | ||
|
|
84cd18bcb8 | ||
|
|
c2fcadd54d | ||
|
|
26ba45a8da | ||
|
|
4cc31bf941 | ||
|
|
0d878a52a2 | ||
|
|
d1af851fcd | ||
|
|
ec72d1c767 | ||
|
|
3add77308a | ||
|
|
d0ea3665be | ||
|
|
ae19737472 | ||
|
|
4c236b4422 | ||
|
|
c4b7be5b6f | ||
|
|
1afc6cd4c5 | ||
|
|
3b6a03d703 | ||
|
|
a4842f9e5c | ||
|
|
0bef32cf8d | ||
|
|
825c70c001 | ||
|
|
77cd764b1c | ||
|
|
2864d48fa7 | ||
|
|
b5c97e35bf | ||
|
|
9a0d9d2c38 | ||
|
|
8bdaec0129 | ||
|
|
3b0ca9d771 | ||
|
|
fa406c1f17 | ||
|
|
dd18430e70 | ||
|
|
7f3c10b69d | ||
|
|
0a5e4effc0 | ||
|
|
737e17066f | ||
|
|
8108dc8803 | ||
|
|
61ec7f8053 | ||
|
|
d5f44ffd7b | ||
|
|
d2bf4de84c | ||
|
|
5320f69c44 | ||
|
|
eb1322dc3e | ||
|
|
e8e259dde9 | ||
|
|
5df7c8bb07 | ||
|
|
bf142e5e07 | ||
|
|
8319d655b9 | ||
|
|
f5c8411a07 | ||
|
|
2ad4fd1707 | ||
|
|
761c2a46a3 | ||
|
|
c986927de9 | ||
|
|
e8eb6d0e31 | ||
|
|
077772ea9c | ||
|
|
3119af6c29 | ||
|
|
83ef7cff8a | ||
|
|
93eace9e5b | ||
|
|
2142ffedc3 | ||
|
|
23c0a67914 | ||
|
|
3b00911f62 | ||
|
|
b9b1e436ec | ||
|
|
87312d4457 | ||
|
|
9dcb4bbfe5 | ||
|
|
11f27019e4 | ||
|
|
dd81c76aaa | ||
|
|
4e5bbcde35 | ||
|
|
7d7270296e | ||
|
|
44e188fa2c | ||
|
|
e6bab46854 | ||
|
|
0a4ce0865e | ||
|
|
da1d3db204 | ||
|
|
880be200ae | ||
|
|
c5b8d3fa72 | ||
|
|
417008f549 | ||
|
|
8077e5aa62 | ||
|
|
2ce1c2efec | ||
|
|
c69e83f779 | ||
|
|
91006351d3 | ||
|
|
e43f55df03 | ||
|
|
0f741f28f3 | ||
|
|
4d2633a9ea | ||
|
|
c5d265f66b | ||
|
|
0311fe330b | ||
|
|
4648e436ac | ||
|
|
e39947f72c | ||
|
|
74db53d51d | ||
|
|
0b9ba4d053 | ||
|
|
700d11fa8f | ||
|
|
f64e081c1f | ||
|
|
54b6a29ba0 | ||
|
|
e0bf262343 | ||
|
|
3a276715d6 | ||
|
|
9516e7f023 | ||
|
|
223b063c60 | ||
|
|
fabc92eb89 | ||
|
|
71848cb56b | ||
|
|
d011c4e8f5 | ||
|
|
46909c210c | ||
|
|
71b725420a | ||
|
|
fcd4ad6872 | ||
|
|
e3f1deda00 | ||
|
|
a538e3c1a2 | ||
|
|
ac91c4d970 | ||
|
|
3ffe3dd4bd | ||
|
|
f70065b2fc | ||
|
|
4b98f2ac25 | ||
|
|
398621693e | ||
|
|
b9d7967c0e | ||
|
|
0c5c2eccad | ||
|
|
a1f5d8041e | ||
|
|
d679deba02 | ||
|
|
df20d10afa | ||
|
|
f2725c5a5c | ||
|
|
91c6916d86 | ||
|
|
f90a5b77ad | ||
|
|
703161157b | ||
|
|
55c896bcd3 | ||
|
|
ef844c396e | ||
|
|
dfdeb21023 | ||
|
|
47c0f946b3 | ||
|
|
f90105c107 | ||
|
|
b0973263e3 | ||
|
|
4be0d8895d | ||
|
|
6436e8cef4 | ||
|
|
f8b6b37288 | ||
|
|
8996117929 | ||
|
|
9be4743cf6 | ||
|
|
4195cd011c | ||
|
|
440cda87b1 | ||
|
|
efb3f7f9cd | ||
|
|
e5487edbfb | ||
|
|
3cae585f78 | ||
|
|
7b8c390a80 | ||
|
|
c3b9c6963e | ||
|
|
e907c7825a | ||
|
|
ea7924663a | ||
|
|
93871308d1 | ||
|
|
f20310b437 | ||
|
|
af87a04d13 | ||
|
|
521536526e | ||
|
|
1e3771dffa | ||
|
|
6666f3d033 | ||
|
|
470b566c1a | ||
|
|
c81f521d2e | ||
|
|
3ed73ac020 | ||
|
|
1604e233f9 | ||
|
|
46f8fadac0 | ||
|
|
001e937568 | ||
|
|
94ffcf4207 | ||
|
|
7b139ea893 | ||
|
|
76274557a3 | ||
|
|
1231528ab5 | ||
|
|
a5216de232 | ||
|
|
87b027e3bf | ||
|
|
b0609e86d1 | ||
|
|
b9145ca996 | ||
|
|
4e0c6e5614 | ||
|
|
da34383363 | ||
|
|
b628bb5e80 | ||
|
|
4c294cb09c | ||
|
|
dc5ee13ed1 | ||
|
|
8707ae6024 | ||
|
|
ec0f726c26 | ||
|
|
66d6db5174 | ||
|
|
2493fd57b2 | ||
|
|
e3a653010a | ||
|
|
c98c364714 | ||
|
|
a545bb8729 | ||
|
|
c9dab08324 | ||
|
|
18b653f641 | ||
|
|
56e2f63385 | ||
|
|
4f04031183 | ||
|
|
cdc3bbcb0c | ||
|
|
2db7611368 | ||
|
|
f4f846496b | ||
|
|
d6ab310d24 | ||
|
|
bc4b36fda6 | ||
|
|
c61a66ca69 | ||
|
|
bd0480b5c5 | ||
|
|
c93c53488d | ||
|
|
19b5290e80 | ||
|
|
a15235d522 | ||
|
|
c7e95676d2 | ||
|
|
4aeb3ed448 | ||
|
|
4e7b68aa9a | ||
|
|
e22c36c503 | ||
|
|
7264defc35 | ||
|
|
baa2fb2906 | ||
|
|
1d954b80a8 | ||
|
|
1d13181135 | ||
|
|
ed1f3aa950 | ||
|
|
e2e62eca5e | ||
|
|
a85c7e9f8f | ||
|
|
ac2280df50 | ||
|
|
61d611c136 | ||
|
|
f59de920c1 | ||
|
|
7b13078bf9 | ||
|
|
3406ebf1fd | ||
|
|
1f0211b45a | ||
|
|
b207ae1bb3 | ||
|
|
e788a44382 | ||
|
|
71dbccd034 | ||
|
|
3df3619b7c | ||
|
|
a969d352ec | ||
|
|
59b6dd735e | ||
|
|
1766d42350 | ||
|
|
3b6654588a | ||
|
|
b58a084de5 | ||
|
|
5d686d733f | ||
|
|
ea92973e9b | ||
|
|
14505fc5e6 | ||
|
|
90b60f90ae | ||
|
|
a26c2cbcdb | ||
|
|
cc708f6ccc | ||
|
|
d4694b271f | ||
|
|
d56f6e684a | ||
|
|
8999108fe3 | ||
|
|
929eccc88d | ||
|
|
75812ca151 | ||
|
|
ec238569c4 | ||
|
|
b6117b157c | ||
|
|
b3dcfea8dc | ||
|
|
00dc1d3f3b | ||
|
|
da5d55a542 | ||
|
|
6a3bbd8d49 | ||
|
|
46deb9590d | ||
|
|
20ed4fe2d1 | ||
|
|
87d7693be5 | ||
|
|
fa153d8504 | ||
|
|
5d3009646a | ||
|
|
ec70d3546d | ||
|
|
10a14a3844 | ||
|
|
0516862632 | ||
|
|
ad379d3ef4 | ||
|
|
8efd8008fc | ||
|
|
6f9565d979 | ||
|
|
6f3ec99501 | ||
|
|
ab681b0954 | ||
|
|
c9b80074f4 | ||
|
|
f5df442e8b | ||
|
|
fab58d503b | ||
|
|
1a3411e99d | ||
|
|
ddcd6d4e91 | ||
|
|
9eb826bb0b | ||
|
|
a88df33167 | ||
|
|
ec48b397ad | ||
|
|
f8af900c73 | ||
|
|
7d4455baf4 | ||
|
|
e37c620d2d | ||
|
|
dd4ef8f91a | ||
|
|
5edcc91182 | ||
|
|
e2b5992e80 | ||
|
|
a2af061a34 | ||
|
|
a53ce32e54 | ||
|
|
08414296b6 | ||
|
|
06ee1f3a15 | ||
|
|
27ed1f3307 | ||
|
|
4f72336301 | ||
|
|
868c157ae4 | ||
|
|
c2b72c7688 | ||
|
|
307713d326 | ||
|
|
2d8b888a18 | ||
|
|
6b2b56cf72 | ||
|
|
52baed7960 | ||
|
|
7ae895d701 | ||
|
|
120452d2ee | ||
|
|
25791a1d18 | ||
|
|
919a7a8ef5 | ||
|
|
da0e0a99c7 | ||
|
|
82ba53d40b | ||
|
|
7ed1feff3e | ||
|
|
6bdfdad09f | ||
|
|
8c3417adeb | ||
|
|
e4ab543aff | ||
|
|
11ef705816 | ||
|
|
b3b440362a | ||
|
|
ee9e747b1c | ||
|
|
1baf8a6424 | ||
|
|
7a89bfc108 | ||
|
|
68c7b9a0e8 | ||
|
|
9e3b1bfc78 | ||
|
|
01f9a6f758 | ||
|
|
8e028753b7 | ||
|
|
343d626025 | ||
|
|
6078f39730 | ||
|
|
78dc57bdb5 | ||
|
|
94a468efc8 | ||
|
|
864572c02a | ||
|
|
d353d56e7b | ||
|
|
a3e6600195 | ||
|
|
51ab8706e8 | ||
|
|
24f832de78 | ||
|
|
7e970ee93c | ||
|
|
e7fa9eda65 | ||
|
|
e295226bd6 | ||
|
|
78d23261ca | ||
|
|
edefa4da4f | ||
|
|
4ba76f95b2 | ||
|
|
6320879fe1 | ||
|
|
acf0548c4c | ||
|
|
b1fa429234 | ||
|
|
78516f437a | ||
|
|
ea75092bb3 | ||
|
|
df4dfe4803 | ||
|
|
fddf30e6c3 | ||
|
|
b718e26c7f | ||
|
|
e564f71c14 | ||
|
|
4f3931e828 | ||
|
|
d73fdce3c5 | ||
|
|
0787c622d4 | ||
|
|
4c11eb099b | ||
|
|
9628a1d028 | ||
|
|
5585385d08 | ||
|
|
98870b06e3 | ||
|
|
46d91322c1 | ||
|
|
ca28f8f3c4 | ||
|
|
0aaa55b35b | ||
|
|
e9a1167da6 | ||
|
|
a67fce66fc | ||
|
|
491d1d7d53 | ||
|
|
54b48dc908 | ||
|
|
dadeab58eb | ||
|
|
0ecdc6620b | ||
|
|
80161b909e | ||
|
|
888232e8c3 | ||
|
|
d904883bdd | ||
|
|
35d2c3afac | ||
|
|
7cee8c3cd0 | ||
|
|
27622bbcec | ||
|
|
219270ce81 | ||
|
|
16dd47a3b9 | ||
|
|
70835984de | ||
|
|
d9224f43f2 | ||
|
|
5b9643d6fb | ||
|
|
d3525190d5 | ||
|
|
f20808d929 | ||
|
|
aee80e41ca | ||
|
|
56ea6c8848 | ||
|
|
b7136c0b7a | ||
|
|
ea94986247 | ||
|
|
d8363067e6 | ||
|
|
6e4f9a9b93 | ||
|
|
29c4ca7e65 | ||
|
|
4d3aefe2a4 | ||
|
|
c798e0a9cd | ||
|
|
1b9c7b7766 | ||
|
|
19ee8e4071 | ||
|
|
b302569feb | ||
|
|
4741012fb9 | ||
|
|
f5886f603b | ||
|
|
d82086240b | ||
|
|
f47b16c571 | ||
|
|
728b082a7d | ||
|
|
31482ccef7 | ||
|
|
ca99e612cf | ||
|
|
c9c833a868 | ||
|
|
7cad4ac444 | ||
|
|
001680906d | ||
|
|
ed355cb8cf | ||
|
|
fa036ee724 | ||
|
|
e04548a61c | ||
|
|
25c55bdaf4 | ||
|
|
c1c43c7d5d | ||
|
|
b970d81272 | ||
|
|
b7ffa9e3c0 | ||
|
|
e94d5418f4 | ||
|
|
44008fc179 | ||
|
|
c2f62a13e6 | ||
|
|
d13591ca85 | ||
|
|
f88f321d79 | ||
|
|
c1b3cb1e7b | ||
|
|
d43c72b3ac | ||
|
|
1457faa53a | ||
|
|
3ee4b564f0 | ||
|
|
0988c8ccbf | ||
|
|
accda04a37 | ||
|
|
f364e7b043 | ||
|
|
42afe033ef | ||
|
|
5cfa06e36f | ||
|
|
8de4c0360d | ||
|
|
24130dd94f | ||
|
|
427326d074 | ||
|
|
59cc6d3f76 | ||
|
|
ee37373cfa | ||
|
|
56d9653f15 | ||
|
|
d5670abdcc | ||
|
|
0360a3160d | ||
|
|
bcd21aefb4 | ||
|
|
3cbcdd4f13 | ||
|
|
c46d0f5662 | ||
|
|
b2454d44ae | ||
|
|
79cfb95f6e | ||
|
|
ff2e1a3507 | ||
|
|
503afb9831 | ||
|
|
b6772917ae | ||
|
|
00971f9ec7 | ||
|
|
a3a97fa228 | ||
|
|
18c4ca9131 | ||
|
|
466ddf768e | ||
|
|
76d26e8ef9 | ||
|
|
b526d6422b | ||
|
|
63c02ff33d | ||
|
|
4688c92e7c | ||
|
|
75ba9101a6 | ||
|
|
df64c184b6 | ||
|
|
1ab09702d9 | ||
|
|
618326d01f | ||
|
|
9b8dace833 |
@@ -141,7 +141,7 @@ 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_else_on_new_line = false
|
||||
ij_javascript_enforce_trailing_comma = keep
|
||||
ij_javascript_extends_keyword_wrap = off
|
||||
ij_javascript_extends_list_wrap = off
|
||||
|
||||
20
.gitignore
vendored
20
.gitignore
vendored
@@ -1,4 +1,15 @@
|
||||
|
||||
################################### Temporary ignore rules during 2.8 UI/UX dev - START
|
||||
/css/backoffice/main.css
|
||||
|
||||
# Sass converter
|
||||
/**/.sass-cache/
|
||||
################################### Temporary ignore rules during 2.8 UI/UX dev - END
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# no slash at the end to handle also symlinks
|
||||
/toolkit
|
||||
/env-*
|
||||
@@ -6,12 +17,6 @@
|
||||
# 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/*
|
||||
@@ -19,6 +24,7 @@ test/vendor/*
|
||||
# all conf but listing prevention
|
||||
/conf/**
|
||||
!/conf/.htaccess
|
||||
!/conf/index.php
|
||||
!/conf/web.config
|
||||
|
||||
# all datas but listing prevention
|
||||
@@ -134,3 +140,5 @@ local.properties
|
||||
.cache-main
|
||||
.scala_dependencies
|
||||
.worksheet
|
||||
|
||||
/css/setup.css
|
||||
|
||||
@@ -52,23 +52,23 @@ Here are the branches we use and their meaning :
|
||||
|
||||
For example, if no version is currently prepared for shipping we could have:
|
||||
|
||||
- `develop` containing future 2.8.0 version
|
||||
- `develop` containing future 3.0.0 version
|
||||
- `support/2.7`: 2.7.x maintenance version
|
||||
- `support/2.6`: 2.6.x maintenance version
|
||||
- `support/2.5`: 2.5.x maintenance version
|
||||
|
||||
In this example, when 2.8.0-beta is shipped that will become:
|
||||
In this example, when 3.0.0-beta is shipped that will become:
|
||||
|
||||
- `develop`: future 2.9.0 version
|
||||
- `release/2.8`: 2.8.0-beta
|
||||
- `develop`: future 3.1.0 version
|
||||
- `release/3.0.0`: 3.0.0-beta
|
||||
- `support/2.7`: 2.7.x maintenance version
|
||||
- `support/2.6`: 2.6.x maintenance version
|
||||
- `support/2.5`: 2.5.x maintenance version
|
||||
|
||||
And when 2.8.0 final will be out:
|
||||
And when 3.0.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)
|
||||
- `develop`: future 3.1.0 version
|
||||
- `support/2.8`: 2.8.x maintenance version (will host developments for 3.0.1)
|
||||
- `support/2.7`: 2.7.x maintenance version
|
||||
- `support/2.6`: 2.6.x maintenance version
|
||||
- `support/2.5`: 2.5.x maintenance version
|
||||
|
||||
70
README.md
70
README.md
@@ -21,21 +21,35 @@ iTop also offers mass import tools and web services to integrate with your IT
|
||||
- [Data synchronization][18] (for data federation)
|
||||
|
||||
|
||||
## Latest release
|
||||
|
||||
- [Changes since the previous version][62]
|
||||
- [New features][63]
|
||||
- [Installation notes][64]
|
||||
- [Download][65]
|
||||
|
||||
[62]: https://www.itophub.io/wiki/page?id=latest:release:change_log
|
||||
[63]: https://www.itophub.io/wiki/page?id=latest:release:start
|
||||
[64]: https://www.itophub.io/wiki/page?id=latest:install:start
|
||||
[65]: https://sourceforge.net/projects/itop/files/latest/download
|
||||
|
||||
|
||||
## Resources
|
||||
|
||||
- [iTop Forums][1]: community support
|
||||
- [iTop Tickets][2]: for feature requests and bug reports
|
||||
- [Releases download][3]
|
||||
- [Documentation][4] covering both iTop and its official extensions
|
||||
- [iTop Hub][5] : discover and install extensions !
|
||||
|
||||
- [Software requirements][4]
|
||||
- [Documentation][5] covering both iTop and its official extensions
|
||||
- [iTop Hub][6] : discover and install extensions !
|
||||
|
||||
|
||||
[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/
|
||||
[4]: https://www.itophub.io/wiki/page?id=latest:install:upgrading_itop
|
||||
[5]: https://www.itophub.io/wiki
|
||||
[6]: 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
|
||||
@@ -49,47 +63,6 @@ iTop also offers mass import tools and web services to integrate with your IT
|
||||
|
||||
|
||||
|
||||
## 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
|
||||
|
||||
|
||||
### 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]
|
||||
|
||||
[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
|
||||
|
||||
iTop development is sponsored, led and supported by [Combodo][0].
|
||||
@@ -105,10 +78,10 @@ We would like to give a special thank you to the people from the community who c
|
||||
- Alves, David
|
||||
- Beck, Pedro
|
||||
- Bilger, Jean-François
|
||||
- Bostoen, Jeffrey
|
||||
- Bostoen, Jeffrey (a.k.a @jbostoen)
|
||||
- Cardoso, Anderson
|
||||
- Cassaro, Bruno
|
||||
- Casteleyn, Thomas
|
||||
- Casteleyn, Thomas (a.k.a @Hipska)
|
||||
- Castro, Randall Badilla
|
||||
- Colantoni, Maria Laura
|
||||
- Couronné, Guy
|
||||
@@ -124,6 +97,7 @@ We would like to give a special thank you to the people from the community who c
|
||||
- Lazcano, Federico
|
||||
- Lucas, Jonathan
|
||||
- Malik, Remie
|
||||
- Mindêllo de Andrade, Lucas (a.k.a @rokam)
|
||||
- Rosenke, Stephan
|
||||
- Seki, Shoji
|
||||
- Shilov, Vladimir
|
||||
|
||||
@@ -9,7 +9,7 @@ responsible disclosure and will make every effort to acknowledge your contributi
|
||||
### 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
|
||||
You can send us a standard "given / when / then" report, including iTop version, impacts, and maybe installed modules or data if they are
|
||||
needed to reproduce.
|
||||
|
||||
### Dependencies vulnerabilities
|
||||
|
||||
@@ -55,7 +55,6 @@ class URP_Profiles extends UserRightsBaseClassGUI
|
||||
"db_table" => "priv_urp_profiles",
|
||||
"db_key_field" => "id",
|
||||
"db_finalclass_field" => "",
|
||||
"display_template" => "",
|
||||
);
|
||||
MetaModel::Init_Params($aParams);
|
||||
//MetaModel::Init_InheritAttributes();
|
||||
@@ -170,11 +169,9 @@ class URP_Profiles extends UserRightsBaseClassGUI
|
||||
function DisplayBareRelations(WebPage $oPage, $bEditMode = false)
|
||||
{
|
||||
parent::DisplayBareRelations($oPage, $bEditMode);
|
||||
if (!$bEditMode)
|
||||
{
|
||||
$oPage->SetCurrentTab('UI:UserManagement:GrantMatrix');
|
||||
$this->DoShowGrantSumary($oPage);
|
||||
}
|
||||
|
||||
$oPage->SetCurrentTab('UI:UserManagement:GrantMatrix');
|
||||
$this->DoShowGrantSumary($oPage);
|
||||
}
|
||||
|
||||
public static function GetReadOnlyAttributes()
|
||||
@@ -243,7 +240,6 @@ class URP_UserProfile extends UserRightsBaseClassGUI
|
||||
"db_table" => "priv_urp_userprofile",
|
||||
"db_key_field" => "id",
|
||||
"db_finalclass_field" => "",
|
||||
"display_template" => "",
|
||||
);
|
||||
MetaModel::Init_Params($aParams);
|
||||
//MetaModel::Init_InheritAttributes();
|
||||
@@ -349,7 +345,6 @@ class URP_UserOrg extends UserRightsBaseClassGUI
|
||||
"db_table" => "priv_urp_userorg",
|
||||
"db_key_field" => "id",
|
||||
"db_finalclass_field" => "",
|
||||
"display_template" => "",
|
||||
);
|
||||
MetaModel::Init_Params($aParams);
|
||||
//MetaModel::Init_InheritAttributes();
|
||||
|
||||
@@ -77,7 +77,6 @@ class URP_Profiles extends UserRightsBaseClassGUI
|
||||
"db_table" => "priv_urp_profiles",
|
||||
"db_key_field" => "id",
|
||||
"db_finalclass_field" => "",
|
||||
"display_template" => "",
|
||||
);
|
||||
MetaModel::Init_Params($aParams);
|
||||
//MetaModel::Init_InheritAttributes();
|
||||
@@ -312,11 +311,9 @@ class URP_Profiles extends UserRightsBaseClassGUI
|
||||
function DisplayBareRelations(WebPage $oPage, $bEditMode = false)
|
||||
{
|
||||
parent::DisplayBareRelations($oPage, $bEditMode);
|
||||
if (!$bEditMode)
|
||||
{
|
||||
$oPage->SetCurrentTab('UI:UserManagement:GrantMatrix');
|
||||
$this->DoShowGrantSumary($oPage);
|
||||
}
|
||||
|
||||
$oPage->SetCurrentTab('UI:UserManagement:GrantMatrix');
|
||||
$this->DoShowGrantSumary($oPage);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -336,7 +333,6 @@ class URP_UserProfile extends UserRightsBaseClassGUI
|
||||
"db_table" => "priv_urp_userprofile",
|
||||
"db_key_field" => "id",
|
||||
"db_finalclass_field" => "",
|
||||
"display_template" => "",
|
||||
);
|
||||
MetaModel::Init_Params($aParams);
|
||||
//MetaModel::Init_InheritAttributes();
|
||||
@@ -376,7 +372,6 @@ class URP_UserOrg extends UserRightsBaseClassGUI
|
||||
"db_table" => "priv_urp_userorg",
|
||||
"db_key_field" => "id",
|
||||
"db_finalclass_field" => "",
|
||||
"display_template" => "",
|
||||
);
|
||||
MetaModel::Init_Params($aParams);
|
||||
//MetaModel::Init_InheritAttributes();
|
||||
@@ -417,7 +412,6 @@ class URP_ActionGrant extends UserRightsBaseClass
|
||||
"db_table" => "priv_urp_grant_actions",
|
||||
"db_key_field" => "id",
|
||||
"db_finalclass_field" => "",
|
||||
"display_template" => "",
|
||||
);
|
||||
MetaModel::Init_Params($aParams);
|
||||
//MetaModel::Init_InheritAttributes();
|
||||
@@ -454,7 +448,6 @@ class URP_StimulusGrant extends UserRightsBaseClass
|
||||
"db_table" => "priv_urp_grant_stimulus",
|
||||
"db_key_field" => "id",
|
||||
"db_finalclass_field" => "",
|
||||
"display_template" => "",
|
||||
);
|
||||
MetaModel::Init_Params($aParams);
|
||||
//MetaModel::Init_InheritAttributes();
|
||||
@@ -491,7 +484,6 @@ class URP_AttributeGrant extends UserRightsBaseClass
|
||||
"db_table" => "priv_urp_grant_attributes",
|
||||
"db_key_field" => "id",
|
||||
"db_finalclass_field" => "",
|
||||
"display_template" => "",
|
||||
);
|
||||
MetaModel::Init_Params($aParams);
|
||||
//MetaModel::Init_InheritAttributes();
|
||||
|
||||
@@ -58,7 +58,6 @@ class URP_Profiles extends UserRightsBaseClass
|
||||
"db_table" => "priv_urp_profiles",
|
||||
"db_key_field" => "id",
|
||||
"db_finalclass_field" => "",
|
||||
"display_template" => "",
|
||||
);
|
||||
MetaModel::Init_Params($aParams);
|
||||
//MetaModel::Init_InheritAttributes();
|
||||
@@ -144,11 +143,9 @@ class URP_Profiles extends UserRightsBaseClass
|
||||
function DisplayBareRelations(WebPage $oPage, $bEditMode = false)
|
||||
{
|
||||
parent::DisplayBareRelations($oPage, $bEditMode);
|
||||
if (!$bEditMode)
|
||||
{
|
||||
$oPage->SetCurrentTab('UI:UserManagement:GrantMatrix');
|
||||
$this->DoShowGrantSumary($oPage);
|
||||
}
|
||||
|
||||
$oPage->SetCurrentTab('UI:UserManagement:GrantMatrix');
|
||||
$this->DoShowGrantSumary($oPage);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -167,7 +164,6 @@ class URP_Dimensions extends UserRightsBaseClass
|
||||
"db_table" => "priv_urp_dimensions",
|
||||
"db_key_field" => "id",
|
||||
"db_finalclass_field" => "",
|
||||
"display_template" => "",
|
||||
);
|
||||
MetaModel::Init_Params($aParams);
|
||||
//MetaModel::Init_InheritAttributes();
|
||||
@@ -280,7 +276,6 @@ class URP_UserProfile extends UserRightsBaseClass
|
||||
"db_table" => "priv_urp_userprofile",
|
||||
"db_key_field" => "id",
|
||||
"db_finalclass_field" => "",
|
||||
"display_template" => "",
|
||||
);
|
||||
MetaModel::Init_Params($aParams);
|
||||
//MetaModel::Init_InheritAttributes();
|
||||
@@ -321,7 +316,6 @@ class URP_ProfileProjection extends UserRightsBaseClass
|
||||
"db_table" => "priv_urp_profileprojection",
|
||||
"db_key_field" => "id",
|
||||
"db_finalclass_field" => "",
|
||||
"display_template" => "",
|
||||
);
|
||||
MetaModel::Init_Params($aParams);
|
||||
//MetaModel::Init_InheritAttributes();
|
||||
@@ -402,7 +396,6 @@ class URP_ClassProjection extends UserRightsBaseClass
|
||||
"db_table" => "priv_urp_classprojection",
|
||||
"db_key_field" => "id",
|
||||
"db_finalclass_field" => "",
|
||||
"display_template" => "",
|
||||
);
|
||||
MetaModel::Init_Params($aParams);
|
||||
//MetaModel::Init_InheritAttributes();
|
||||
@@ -474,7 +467,6 @@ class URP_ActionGrant extends UserRightsBaseClass
|
||||
"db_table" => "priv_urp_grant_actions",
|
||||
"db_key_field" => "id",
|
||||
"db_finalclass_field" => "",
|
||||
"display_template" => "",
|
||||
);
|
||||
MetaModel::Init_Params($aParams);
|
||||
//MetaModel::Init_InheritAttributes();
|
||||
@@ -511,7 +503,6 @@ class URP_StimulusGrant extends UserRightsBaseClass
|
||||
"db_table" => "priv_urp_grant_stimulus",
|
||||
"db_key_field" => "id",
|
||||
"db_finalclass_field" => "",
|
||||
"display_template" => "",
|
||||
);
|
||||
MetaModel::Init_Params($aParams);
|
||||
//MetaModel::Init_InheritAttributes();
|
||||
@@ -548,7 +539,6 @@ class URP_AttributeGrant extends UserRightsBaseClass
|
||||
"db_table" => "priv_urp_grant_attributes",
|
||||
"db_key_field" => "id",
|
||||
"db_finalclass_field" => "",
|
||||
"display_template" => "",
|
||||
);
|
||||
MetaModel::Init_Params($aParams);
|
||||
//MetaModel::Init_InheritAttributes();
|
||||
|
||||
@@ -30,8 +30,11 @@ function mb_str_replace($search, $replace, $subject, &$count = 0) {
|
||||
$replacements = array_pad($replacements, count($searches), '');
|
||||
foreach ($searches as $key => $search) {
|
||||
$parts = mb_split(preg_quote($search), $subject);
|
||||
$count += count($parts) - 1;
|
||||
$subject = implode($replacements[$key], $parts);
|
||||
if (is_array($parts))
|
||||
{
|
||||
$count += count($parts) - 1;
|
||||
$subject = implode($replacements[$key], $parts);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Call mb_str_replace for each subject in array, recursively
|
||||
|
||||
@@ -1,417 +1,16 @@
|
||||
<?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
|
||||
* @deprecated will be removed in 3.1.0 - moved to sources/application/WebPage/AjaxPage.php
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
* @copyright Copyright (C) 2010-2020 Combodo SARL
|
||||
*/
|
||||
|
||||
require_once(APPROOT."/application/webpage.class.inc.php");
|
||||
|
||||
class ajax_page extends WebPage implements iTabbedPage
|
||||
/**
|
||||
* Class ajax_page
|
||||
* @deprecated will be removed in 3.1.0 - moved to AjaxPage
|
||||
*/
|
||||
class ajax_page extends AjaxPage
|
||||
{
|
||||
/**
|
||||
* Jquery style ready script
|
||||
* @var array
|
||||
*/
|
||||
protected $m_sReadyScript;
|
||||
protected $m_oTabs;
|
||||
private $m_sMenu; // If set, then the menu will be updated
|
||||
|
||||
/**
|
||||
* constructor for the web page
|
||||
*
|
||||
* @param string $s_title Not used
|
||||
*/
|
||||
function __construct($s_title) {
|
||||
$sPrintable = utils::ReadParam('printable', '0');
|
||||
$bPrintable = ($sPrintable == '1');
|
||||
|
||||
parent::__construct($s_title, $bPrintable);
|
||||
$this->m_sReadyScript = "";
|
||||
//$this->add_header("Content-type: text/html; charset=utf-8");
|
||||
$this->add_header('Cache-control: no-cache, no-store, must-revalidate');
|
||||
$this->add_header('Pragma: no-cache');
|
||||
$this->add_header('Expires: 0');
|
||||
$this->add_header('X-Frame-Options: deny');
|
||||
$this->m_oTabs = new TabManager();
|
||||
$this->sContentType = 'text/html';
|
||||
$this->sContentDisposition = 'inline';
|
||||
$this->m_sMenu = "";
|
||||
|
||||
utils::InitArchiveMode();
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function AddTabContainer($sTabContainer, $sPrefix = '')
|
||||
{
|
||||
$this->add($this->m_oTabs->AddTabContainer($sTabContainer, $sPrefix));
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function AddToTab($sTabContainer, $sTabCode, $sHtml)
|
||||
{
|
||||
$this->add($this->m_oTabs->AddToTab($sTabContainer, $sTabCode, $sHtml));
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function SetCurrentTabContainer($sTabContainer = '')
|
||||
{
|
||||
return $this->m_oTabs->SetCurrentTabContainer($sTabContainer);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function SetCurrentTab($sTabCode = '', $sTabTitle = null)
|
||||
{
|
||||
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();
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function RemoveTab($sTabCode, $sTabContainer = null)
|
||||
{
|
||||
$this->m_oTabs->RemoveTab($sTabCode, $sTabContainer);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function FindTab($sPattern, $sTabContainer = null)
|
||||
{
|
||||
return $this->m_oTabs->FindTab($sPattern, $sTabContainer);
|
||||
}
|
||||
|
||||
/**
|
||||
* Make the given tab the active one, as if it were clicked
|
||||
* 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...
|
||||
*/
|
||||
public function SelectTab($sTabContainer, $sTabCode)
|
||||
{
|
||||
$this->add_ready_script($this->m_oTabs->SelectTab($sTabContainer, $sTabCode));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $sHtml
|
||||
*/
|
||||
public function AddToMenu($sHtml)
|
||||
{
|
||||
$this->m_sMenu .= $sHtml;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function output()
|
||||
{
|
||||
if (!empty($this->sContentType))
|
||||
{
|
||||
$this->add_header('Content-type: '.$this->sContentType);
|
||||
}
|
||||
if (!empty($this->sContentDisposition))
|
||||
{
|
||||
$this->add_header('Content-Disposition: '.$this->sContentDisposition.'; filename="'.$this->sContentFileName.'"');
|
||||
}
|
||||
foreach($this->a_headers as $s_header)
|
||||
{
|
||||
header($s_header);
|
||||
}
|
||||
if ($this->m_oTabs->TabsContainerCount() > 0)
|
||||
{
|
||||
$this->add_ready_script(
|
||||
<<<EOF
|
||||
// The "tab widgets" to handle.
|
||||
var tabs = $('div[id^=tabbedContent]');
|
||||
|
||||
// Ugly patch for a change in the behavior of jQuery UI:
|
||||
// Before jQuery UI 1.9, tabs were always considered as "local" (opposed to Ajax)
|
||||
// when their href was beginning by #. Starting with 1.9, a <base> tag in the page
|
||||
// is taken into account and causes "local" tabs to be considered as Ajax
|
||||
// unless their URL is equal to the URL of the page...
|
||||
if ($('base').length > 0)
|
||||
{
|
||||
$('div[id^=tabbedContent] > ul > li > a').each(function() {
|
||||
var sHash = location.hash;
|
||||
var sCleanLocation = location.href.toString().replace(sHash, '').replace(/#$/, '');
|
||||
$(this).attr("href", sCleanLocation+$(this).attr("href"));
|
||||
});
|
||||
}
|
||||
if ($.bbq)
|
||||
{
|
||||
// This selector will be reused when selecting actual tab widget A elements.
|
||||
var tab_a_selector = 'ul.ui-tabs-nav a';
|
||||
|
||||
// Enable tabs on all tab widgets. The `event` property must be overridden so
|
||||
// that the tabs aren't changed on click, and any custom event name can be
|
||||
// specified. Note that if you define a callback for the 'select' event, it
|
||||
// will be executed for the selected tab whenever the hash changes.
|
||||
tabs.tabs({ event: 'change' });
|
||||
|
||||
// Define our own click handler for the tabs, overriding the default.
|
||||
tabs.find( tab_a_selector ).click(function()
|
||||
{
|
||||
var state = {};
|
||||
|
||||
// Get the id of this tab widget.
|
||||
var id = $(this).closest( 'div[id^=tabbedContent]' ).attr( 'id' );
|
||||
|
||||
// Get the index of this tab.
|
||||
var idx = $(this).parent().prevAll().length;
|
||||
|
||||
// Set the state!
|
||||
state[ id ] = idx;
|
||||
$.bbq.pushState( state );
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
tabs.tabs();
|
||||
}
|
||||
EOF
|
||||
);
|
||||
}
|
||||
// Render the tabs in the page (if any)
|
||||
$this->s_content = $this->m_oTabs->RenderIntoContent($this->s_content, $this);
|
||||
|
||||
// Additional UI widgets to be activated inside the ajax fragment
|
||||
// Important: Testing the content type is not enough because some ajax handlers have not correctly positionned the flag (e.g json response corrupted by the script)
|
||||
if (($this->sContentType == 'text/html') && (preg_match('/class="date-pick"/', $this->s_content) || preg_match('/class="datetime-pick"/', $this->s_content)) )
|
||||
{
|
||||
$this->add_ready_script(
|
||||
<<<EOF
|
||||
PrepareWidgets();
|
||||
EOF
|
||||
);
|
||||
}
|
||||
$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);
|
||||
}
|
||||
else
|
||||
{
|
||||
echo $this->s_content;
|
||||
}
|
||||
if (!empty($this->m_sMenu))
|
||||
{
|
||||
$uid = time();
|
||||
echo "<div id=\"accordion_temp_$uid\">\n";
|
||||
echo "<div id=\"accordion\">\n";
|
||||
echo "<!-- Beginning of the accordion menu -->\n";
|
||||
echo self::FilterXSS($this->m_sMenu);
|
||||
echo "<!-- End of the accordion menu-->\n";
|
||||
echo "</div>\n";
|
||||
echo "</div>\n";
|
||||
|
||||
echo "<script type=\"text/javascript\">\n";
|
||||
echo "$('#inner_menu').html($('#accordion_temp_$uid').html());\n";
|
||||
echo "$('#accordion_temp_$uid').remove();\n";
|
||||
echo "\n</script>\n";
|
||||
}
|
||||
|
||||
//echo $this->s_deferred_content;
|
||||
if (count($this->a_scripts) > 0)
|
||||
{
|
||||
echo "<script type=\"text/javascript\">\n";
|
||||
echo implode("\n", $this->a_scripts);
|
||||
echo "\n</script>\n";
|
||||
}
|
||||
if (count($this->a_linked_scripts) > 0)
|
||||
{
|
||||
echo "<script type=\"text/javascript\">\n";
|
||||
foreach($this->a_linked_scripts as $sScriptUrl)
|
||||
{
|
||||
echo '$.getScript('.json_encode($sScriptUrl).");\n";
|
||||
}
|
||||
echo "\n</script>\n";
|
||||
}
|
||||
if (!empty($this->s_deferred_content))
|
||||
{
|
||||
echo "<script type=\"text/javascript\">\n";
|
||||
echo "\$('body').append('".addslashes(str_replace("\n", '', $this->s_deferred_content))."');\n";
|
||||
echo "\n</script>\n";
|
||||
}
|
||||
if (!empty($this->m_sReadyScript))
|
||||
{
|
||||
echo "<script type=\"text/javascript\">\n";
|
||||
echo $this->m_sReadyScript; // Ready Scripts are output as simple scripts
|
||||
echo "\n</script>\n";
|
||||
}
|
||||
if(count($this->a_linked_stylesheets) > 0)
|
||||
{
|
||||
echo "<script type=\"text/javascript\">";
|
||||
foreach($this->a_linked_stylesheets as $aStylesheet)
|
||||
{
|
||||
$sStylesheetUrl = $aStylesheet['link'];
|
||||
echo "if (!$('link[href=\"{$sStylesheetUrl}\"]').length) $('<link href=\"{$sStylesheetUrl}\" rel=\"stylesheet\">').appendTo('head');\n";
|
||||
}
|
||||
echo "\n</script>\n";
|
||||
}
|
||||
|
||||
if (trim($s_captured_output) != "")
|
||||
{
|
||||
echo self::FilterXSS($s_captured_output);
|
||||
}
|
||||
|
||||
$oKPI->ComputeAndReport('Echoing');
|
||||
|
||||
if (class_exists('DBSearch'))
|
||||
{
|
||||
DBSearch::RecordQueryTrace();
|
||||
}
|
||||
if (class_exists('ExecutionKPI'))
|
||||
{
|
||||
ExecutionKPI::ReportStats();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a paragraph with a smaller font into the page
|
||||
* NOT implemented (i.e does nothing)
|
||||
* @param string $sText Content of the (small) paragraph
|
||||
* @return void
|
||||
*/
|
||||
public function small_p($sText)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function add($sHtml)
|
||||
{
|
||||
if (($this->m_oTabs->GetCurrentTabContainer() != '') && ($this->m_oTabs->GetCurrentTab() != ''))
|
||||
{
|
||||
$this->m_oTabs->AddToTab($this->m_oTabs->GetCurrentTabContainer(), $this->m_oTabs->GetCurrentTab(), $sHtml);
|
||||
}
|
||||
else
|
||||
{
|
||||
parent::add($sHtml);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function start_capture()
|
||||
{
|
||||
$sCurrentTabContainer = $this->m_oTabs->GetCurrentTabContainer();
|
||||
$sCurrentTab = $this->m_oTabs->GetCurrentTab();
|
||||
|
||||
if (!empty($sCurrentTabContainer) && !empty($sCurrentTab))
|
||||
{
|
||||
$iOffset = $this->m_oTabs->GetCurrentTabLength();
|
||||
return array('tc' => $sCurrentTabContainer, 'tab' => $sCurrentTab, 'offset' => $iOffset);
|
||||
}
|
||||
else
|
||||
{
|
||||
return parent::start_capture();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function end_capture($offset)
|
||||
{
|
||||
if (is_array($offset))
|
||||
{
|
||||
if ($this->m_oTabs->TabExists($offset['tc'], $offset['tab']))
|
||||
{
|
||||
$sCaptured = $this->m_oTabs->TruncateTab($offset['tc'], $offset['tab'], $offset['offset']);
|
||||
}
|
||||
else
|
||||
{
|
||||
$sCaptured = '';
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$sCaptured = parent::end_capture($offset);
|
||||
}
|
||||
return $sCaptured;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function add_at_the_end($s_html, $sId = '')
|
||||
{
|
||||
if ($sId != '')
|
||||
{
|
||||
$this->add_script("$('#{$sId}').remove();"); // Remove any previous instance of the same Id
|
||||
}
|
||||
$this->s_deferred_content .= $s_html;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function add_ready_script($sScript)
|
||||
{
|
||||
$this->m_sReadyScript .= $sScript."\n";
|
||||
}
|
||||
|
||||
/**
|
||||
* @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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -37,4 +37,3 @@ require_once(APPROOT.'/application/utils.inc.php');
|
||||
class ApplicationException extends CoreException
|
||||
{
|
||||
}
|
||||
?>
|
||||
|
||||
@@ -24,19 +24,23 @@
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
use Combodo\iTop\Application\UI\Component\Input\InputFactory;
|
||||
use Combodo\iTop\Application\UI\Layout\UIContentBlock;
|
||||
use Combodo\iTop\Application\UI\UIBlock;
|
||||
|
||||
require_once(APPROOT."/application/utils.inc.php");
|
||||
|
||||
/**
|
||||
* Interface for directing end-users to the relevant application
|
||||
*/
|
||||
*/
|
||||
interface iDBObjectURLMaker
|
||||
{
|
||||
/**
|
||||
* @param string $sClass
|
||||
* @param string $iId
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
/**
|
||||
* @param string $sClass
|
||||
* @param string $iId
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function MakeObjectURL($sClass, $iId);
|
||||
}
|
||||
|
||||
@@ -200,23 +204,46 @@ class ApplicationContext
|
||||
}
|
||||
return implode("&", $aParams);
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 3.0.0 N°2534 - dashboard: bug with autorefresh that deactivates filtering on organisation
|
||||
* Returns the params as c[menu]:..., c[org_id]:....
|
||||
* @return string The params
|
||||
*/
|
||||
public function GetForPostParams()
|
||||
{
|
||||
return json_encode($this->aValues);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the context as sequence of input tags to be inserted inside a <form> tag
|
||||
*
|
||||
* @return string The context as a sequence of <input type="hidden" /> tags
|
||||
*/
|
||||
public function GetForForm()
|
||||
{
|
||||
$sContext = "";
|
||||
foreach($this->aValues as $sName => $sValue)
|
||||
{
|
||||
foreach ($this->aValues as $sName => $sValue) {
|
||||
$sContext .= "<input type=\"hidden\" name=\"c[$sName]\" value=\"".htmlentities($sValue, ENT_QUOTES, 'UTF-8')."\" />\n";
|
||||
}
|
||||
return $sContext;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the context as sequence of input tags to be inserted inside a <form> tag
|
||||
*
|
||||
*/
|
||||
public function GetForFormBlock(): UIBlock
|
||||
{
|
||||
$oContext = new UIContentBlock();
|
||||
foreach ($this->aValues as $sName => $sValue) {
|
||||
$oContext->AddSubBlock(InputFactory::MakeForHidden('c[$sName]', utils::HtmlEntities($sValue)));
|
||||
}
|
||||
return $oContext;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the context as a hash array 'parameter_name' => value
|
||||
*
|
||||
* @return array The context information
|
||||
*/
|
||||
public function GetAsHash()
|
||||
|
||||
@@ -869,7 +869,7 @@ abstract class ApplicationPopupMenuItem
|
||||
class URLPopupMenuItem extends ApplicationPopupMenuItem
|
||||
{
|
||||
/** @ignore */
|
||||
protected $sURL;
|
||||
protected $sUrl;
|
||||
/** @ignore */
|
||||
protected $sTarget;
|
||||
|
||||
@@ -878,20 +878,32 @@ class URLPopupMenuItem extends ApplicationPopupMenuItem
|
||||
*
|
||||
* @param string $sUID The unique identifier of this menu in iTop... make sure you pass something unique enough
|
||||
* @param string $sLabel The display label of the menu (must be localized)
|
||||
* @param string $sURL If the menu is an hyperlink, provide the absolute hyperlink here
|
||||
* @param string $sUrl If the menu is an hyperlink, provide the absolute hyperlink here
|
||||
* @param string $sTarget In case the menu is an hyperlink and a specific target is needed (_blank for example), pass it here
|
||||
*/
|
||||
public function __construct($sUID, $sLabel, $sURL, $sTarget = '_top')
|
||||
public function __construct($sUID, $sLabel, $sUrl, $sTarget = '_top')
|
||||
{
|
||||
parent::__construct($sUID, $sLabel);
|
||||
$this->sURL = $sURL;
|
||||
$this->sUrl = $sUrl;
|
||||
$this->sTarget = $sTarget;
|
||||
}
|
||||
|
||||
/** @ignore */
|
||||
public function GetMenuItem()
|
||||
{
|
||||
return array('label' => $this->GetLabel(), 'url' => $this->sURL, 'target' => $this->sTarget, 'css_classes' => $this->aCssClasses);
|
||||
return array('label' => $this->GetLabel(), 'url' => $this->GetUrl(), 'target' => $this-> GetTarget(), 'css_classes' => $this->aCssClasses);
|
||||
}
|
||||
|
||||
/** @ignore */
|
||||
public function GetUrl()
|
||||
{
|
||||
return $this->sUrl;
|
||||
}
|
||||
|
||||
/** @ignore */
|
||||
public function GetTarget()
|
||||
{
|
||||
return $this->sTarget;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -905,7 +917,9 @@ class URLPopupMenuItem extends ApplicationPopupMenuItem
|
||||
class JSPopupMenuItem extends ApplicationPopupMenuItem
|
||||
{
|
||||
/** @ignore */
|
||||
protected $sJSCode;
|
||||
protected $sJsCode;
|
||||
/** @ignore */
|
||||
protected $sUrl;
|
||||
/** @ignore */
|
||||
protected $aIncludeJSFiles;
|
||||
|
||||
@@ -923,7 +937,8 @@ class JSPopupMenuItem extends ApplicationPopupMenuItem
|
||||
public function __construct($sUID, $sLabel, $sJSCode, $aIncludeJSFiles = array())
|
||||
{
|
||||
parent::__construct($sUID, $sLabel);
|
||||
$this->sJSCode = $sJSCode;
|
||||
$this->sJsCode = $sJSCode;
|
||||
$this->sUrl = '#';
|
||||
$this->aIncludeJSFiles = $aIncludeJSFiles;
|
||||
}
|
||||
|
||||
@@ -933,9 +948,9 @@ class JSPopupMenuItem extends ApplicationPopupMenuItem
|
||||
// Note: the semicolumn is a must here!
|
||||
return array(
|
||||
'label' => $this->GetLabel(),
|
||||
'onclick' => $this->sJSCode.'; return false;',
|
||||
'url' => '#',
|
||||
'css_classes' => $this->aCssClasses,
|
||||
'onclick' => $this->GetJsCode().'; return false;',
|
||||
'url' => $this->GetUrl(),
|
||||
'css_classes' => $this->GetCssClasses(),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -944,6 +959,18 @@ class JSPopupMenuItem extends ApplicationPopupMenuItem
|
||||
{
|
||||
return $this->aIncludeJSFiles;
|
||||
}
|
||||
|
||||
/** @ignore */
|
||||
public function GetJsCode()
|
||||
{
|
||||
return $this->sJsCode;
|
||||
}
|
||||
|
||||
/** @ignore */
|
||||
public function GetUrl()
|
||||
{
|
||||
return $this->sUrl;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1019,7 +1046,7 @@ class JSButtonItem extends JSPopupMenuItem
|
||||
interface iPageUIExtension
|
||||
{
|
||||
/**
|
||||
* Add content to the North pane
|
||||
* Add content to the header of the page
|
||||
*
|
||||
* @param iTopWebPage $oPage The page to insert stuff into.
|
||||
*
|
||||
@@ -1028,7 +1055,7 @@ interface iPageUIExtension
|
||||
public function GetNorthPaneHtml(iTopWebPage $oPage);
|
||||
|
||||
/**
|
||||
* Add content to the South pane
|
||||
* Add content to the footer of the page
|
||||
*
|
||||
* @param iTopWebPage $oPage The page to insert stuff into.
|
||||
*
|
||||
|
||||
@@ -43,7 +43,6 @@ class AuditRule extends cmdbAbstractObject
|
||||
"db_table" => "priv_auditrule",
|
||||
"db_key_field" => "id",
|
||||
"db_finalclass_field" => "",
|
||||
"display_template" => "",
|
||||
);
|
||||
MetaModel::Init_Params($aParams);
|
||||
MetaModel::Init_AddAttribute(new AttributeString("name", array("allowed_values"=>null, "sql"=>"name", "default_value"=>"", "is_null_allowed"=>false, "depends_on"=>array())));
|
||||
|
||||
@@ -1,84 +1,7 @@
|
||||
<?php
|
||||
// Copyright (C) 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/>
|
||||
|
||||
/**
|
||||
* Adapter class: when an API requires WebPage and you want to produce something else
|
||||
*
|
||||
* @copyright Copyright (C) 2016 Combodo SARL
|
||||
* @deprecated will be removed in 3.1.0 - moved to sources/application/WebPage/CaptureWebPage.php
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
* @copyright Copyright (C) 2010-2020 Combodo SARL
|
||||
*/
|
||||
|
||||
require_once(APPROOT."/application/webpage.class.inc.php");
|
||||
|
||||
class CaptureWebPage extends WebPage
|
||||
{
|
||||
protected $aReadyScripts;
|
||||
|
||||
function __construct()
|
||||
{
|
||||
parent::__construct('capture web page');
|
||||
$this->aReadyScripts = array();
|
||||
}
|
||||
|
||||
public function GetHtml()
|
||||
{
|
||||
$trash = $this->ob_get_clean_safe();
|
||||
return $this->s_content;
|
||||
}
|
||||
|
||||
public function GetJS()
|
||||
{
|
||||
$sRet = implode("\n", $this->a_scripts);
|
||||
if (!empty($this->s_deferred_content))
|
||||
{
|
||||
$sRet .= "\n\$('body').append('".addslashes(str_replace("\n", '', $this->s_deferred_content))."');";
|
||||
}
|
||||
return $sRet;
|
||||
}
|
||||
|
||||
public function GetReadyJS()
|
||||
{
|
||||
return "\$(document).ready(function() {\n".implode("\n", $this->aReadyScripts)."\n});";
|
||||
}
|
||||
|
||||
public function GetCSS()
|
||||
{
|
||||
return $this->a_styles;
|
||||
}
|
||||
|
||||
public function GetJSFiles()
|
||||
{
|
||||
return $this->a_linked_scripts;
|
||||
}
|
||||
|
||||
public function GetCSSFiles()
|
||||
{
|
||||
return $this->a_linked_stylesheets;
|
||||
}
|
||||
|
||||
public function output()
|
||||
{
|
||||
throw new Exception(__method__.' should not be called');
|
||||
}
|
||||
|
||||
public function add_ready_script($sScript)
|
||||
{
|
||||
$this->aReadyScripts[] = $sScript;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1,97 +1,7 @@
|
||||
<?php
|
||||
// Copyright (C) 2010-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/>
|
||||
|
||||
|
||||
/**
|
||||
* CLI page
|
||||
* The page adds the content-type text/XML and the encoding into the headers
|
||||
*
|
||||
* @copyright Copyright (C) 2010-2015 Combodo SARL
|
||||
* @deprecated will be removed in 3.1.0 - moved to sources/application/WebPage/CLIPage.php
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
* @copyright Copyright (C) 2010-2020 Combodo SARL
|
||||
*/
|
||||
|
||||
require_once(APPROOT."/application/webpage.class.inc.php");
|
||||
|
||||
class CLIPage implements Page
|
||||
{
|
||||
function __construct($s_title)
|
||||
{
|
||||
}
|
||||
|
||||
public function output()
|
||||
{
|
||||
if (class_exists('DBSearch'))
|
||||
{
|
||||
DBSearch::RecordQueryTrace();
|
||||
}
|
||||
if (class_exists('ExecutionKPI'))
|
||||
{
|
||||
ExecutionKPI::ReportStats();
|
||||
}
|
||||
}
|
||||
|
||||
public function add($sText)
|
||||
{
|
||||
echo $sText;
|
||||
}
|
||||
|
||||
public function p($sText)
|
||||
{
|
||||
echo $sText."\n";
|
||||
}
|
||||
|
||||
public function pre($sText)
|
||||
{
|
||||
echo $sText."\n";
|
||||
}
|
||||
|
||||
public function add_comment($sText)
|
||||
{
|
||||
echo "#".$sText."\n";
|
||||
}
|
||||
|
||||
public function table($aConfig, $aData, $aParams = array())
|
||||
{
|
||||
$aCells = array();
|
||||
foreach($aConfig as $sName=>$aDef)
|
||||
{
|
||||
if (strlen($aDef['description']) > 0)
|
||||
{
|
||||
$aCells[] = $aDef['label'].' ('.$aDef['description'].')';
|
||||
}
|
||||
else
|
||||
{
|
||||
$aCells[] = $aDef['label'];
|
||||
}
|
||||
}
|
||||
echo implode(';', $aCells)."\n";
|
||||
|
||||
foreach($aData as $aRow)
|
||||
{
|
||||
$aCells = array();
|
||||
foreach($aConfig as $sName=>$aAttribs)
|
||||
{
|
||||
$sValue = $aRow["$sName"];
|
||||
$aCells[] = $sValue;
|
||||
}
|
||||
echo implode(';', $aCells)."\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,113 +1,7 @@
|
||||
<?php
|
||||
// Copyright (C) 2010-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/>
|
||||
|
||||
|
||||
/**
|
||||
* Simple web page with no includes or fancy formatting, useful to generateXML documents
|
||||
* The page adds the content-type text/XML and the encoding into the headers
|
||||
*
|
||||
* @copyright Copyright (C) 2010-2015 Combodo SARL
|
||||
* @deprecated will be removed in 3.1.0 - moved to sources/application/WebPage/CSVPage.php
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
* @copyright Copyright (C) 2010-2020 Combodo SARL
|
||||
*/
|
||||
|
||||
require_once(APPROOT."/application/webpage.class.inc.php");
|
||||
|
||||
class CSVPage extends WebPage
|
||||
{
|
||||
function __construct($s_title) {
|
||||
parent::__construct($s_title);
|
||||
$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');
|
||||
$this->add_header('X-Frame-Options: deny');
|
||||
//$this->add_header("Content-Transfer-Encoding: binary");
|
||||
}
|
||||
|
||||
public function output()
|
||||
{
|
||||
$this->add_header("Content-Length: ".strlen(trim($this->s_content)));
|
||||
|
||||
// Get the unexpected output but do nothing with it
|
||||
$sTrash = $this->ob_get_clean_safe();
|
||||
|
||||
foreach($this->a_headers as $s_header)
|
||||
{
|
||||
header($s_header);
|
||||
}
|
||||
echo trim($this->s_content);
|
||||
echo "\n";
|
||||
|
||||
if (class_exists('DBSearch'))
|
||||
{
|
||||
DBSearch::RecordQueryTrace();
|
||||
}
|
||||
if (class_exists('ExecutionKPI'))
|
||||
{
|
||||
ExecutionKPI::ReportStats();
|
||||
}
|
||||
}
|
||||
|
||||
public function small_p($sText)
|
||||
{
|
||||
}
|
||||
|
||||
public function add($sText)
|
||||
{
|
||||
$this->s_content .= $sText;
|
||||
}
|
||||
|
||||
public function p($sText)
|
||||
{
|
||||
$this->s_content .= $sText."\n";
|
||||
}
|
||||
|
||||
public function add_comment($sText)
|
||||
{
|
||||
$this->s_content .= "#".$sText."\n";
|
||||
}
|
||||
|
||||
public function table($aConfig, $aData, $aParams = array())
|
||||
{
|
||||
$aCells = array();
|
||||
foreach($aConfig as $sName=>$aDef)
|
||||
{
|
||||
if (strlen($aDef['description']) > 0)
|
||||
{
|
||||
$aCells[] = $aDef['label'].' ('.$aDef['description'].')';
|
||||
}
|
||||
else
|
||||
{
|
||||
$aCells[] = $aDef['label'];
|
||||
}
|
||||
}
|
||||
$this->s_content .= implode(';', $aCells)."\n";
|
||||
|
||||
foreach($aData as $aRow)
|
||||
{
|
||||
$aCells = array();
|
||||
foreach($aConfig as $sName=>$aAttribs)
|
||||
{
|
||||
$sValue = $aRow["$sName"];
|
||||
$aCells[] = $sValue;
|
||||
}
|
||||
$this->s_content .= implode(';', $aCells)."\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -17,6 +17,11 @@
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
*/
|
||||
|
||||
use Combodo\iTop\Application\UI\Component\Button\ButtonFactory;
|
||||
use Combodo\iTop\Application\UI\Component\Toolbar\Toolbar;
|
||||
|
||||
use Combodo\iTop\Application\UI\Component\DataTable\DataTableSettings;
|
||||
|
||||
require_once(APPROOT.'application/dashboardlayout.class.inc.php');
|
||||
require_once(APPROOT.'application/dashlet.class.inc.php');
|
||||
require_once(APPROOT.'core/modelreflection.class.inc.php');
|
||||
@@ -491,7 +496,7 @@ abstract class Dashboard
|
||||
$("#attr_auto_reload_sec").prop('disabled', !$(this).is(':checked'));
|
||||
} );
|
||||
|
||||
$('#select_layout').buttonset();
|
||||
$('#select_layout').controlgroup();
|
||||
$('#select_dashlet').droppable({
|
||||
accept: '.dashlet',
|
||||
drop: function(event, ui) {
|
||||
@@ -529,28 +534,37 @@ EOF
|
||||
*/
|
||||
public function Render($oPage, $bEditMode = false, $aExtraParams = array(), $bCanEdit = true)
|
||||
{
|
||||
if (!array_key_exists('dashboard_div_id', $aExtraParams))
|
||||
{
|
||||
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>');
|
||||
$sTitleForHTML = utils::HtmlEntities(Dict::S($this->sTitle));
|
||||
|
||||
$sHtml = "<div class=\"ibo-top-bar--toolbar-dashboard-title\">{$sTitleForHTML}</div>";
|
||||
if ($oPage instanceof iTopWebPage) {
|
||||
$oTopBar = $oPage->GetTopBarLayout();
|
||||
$oToolbar = new Toolbar();
|
||||
$oTopBar->SetToolbar($oToolbar);
|
||||
$oToolbar->AddHtml($sHtml);
|
||||
} else {
|
||||
$oPage->add_script(<<<JS
|
||||
$(".ibo-top-bar--toolbar-dashboard-title").html("$sTitleForHTML");
|
||||
JS
|
||||
);
|
||||
}
|
||||
|
||||
/** @var \DashboardLayoutMultiCol $oLayout */
|
||||
$oLayout = new $this->sLayoutClass();
|
||||
|
||||
foreach($this->aCells as $iCellIdx => $aDashlets)
|
||||
{
|
||||
foreach($aDashlets as $oDashlet)
|
||||
{
|
||||
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)
|
||||
{
|
||||
if (!$bEditMode) {
|
||||
$oPage->add_linked_script('../js/dashlet.js');
|
||||
$oPage->add_linked_script('../js/dashboard.js');
|
||||
}
|
||||
@@ -928,6 +942,9 @@ class RuntimeDashboard extends Dashboard
|
||||
$sExtraParams = json_encode($aAjaxParams);
|
||||
$iReloadInterval = 1000 * $this->GetAutoReloadInterval();
|
||||
$sReloadURL = $this->GetReloadURL();
|
||||
$oAppContext = new ApplicationContext();
|
||||
$sContext=$oAppContext->GetForPostParams();
|
||||
//$sContext is named "c" because it use the existing code for context parameters c[org_id] and c[menu]
|
||||
$oPage->add_script(
|
||||
<<<EOF
|
||||
if (typeof(AutoReloadDashboardId$sDivId) !== 'undefined')
|
||||
@@ -941,14 +958,14 @@ class RuntimeDashboard extends Dashboard
|
||||
function ReloadDashboard$sDivId()
|
||||
{
|
||||
// Do not reload when a dialog box is active
|
||||
if (!($('.ui-dialog:visible').length > 0) && $('.dashboard_contents#$sDivId').is(':visible'))
|
||||
if (!($('.ui-dialog:visible').length > 0) && $('.ibo-dashboard#$sDivId').is(':visible'))
|
||||
{
|
||||
$('.dashboard_contents#$sDivId').block();
|
||||
$('.ibo-dashboard#$sDivId').block();
|
||||
$.post(GetAbsoluteUrlAppRoot()+'pages/ajax.render.php',
|
||||
{ operation: 'reload_dashboard', dashboard_id: '$sId', file: '$sFile', extra_params: $sExtraParams, reload_url: '$sReloadURL'},
|
||||
{ operation: 'reload_dashboard', dashboard_id: '$sId', file: '$sFile', extra_params: $sExtraParams, c: $sContext, reload_url: '$sReloadURL'},
|
||||
function(data){
|
||||
$('.dashboard_contents#$sDivId').html(data);
|
||||
$('.dashboard_contents#$sDivId').unblock();
|
||||
$('.ibo-dashboard#$sDivId').html(data);
|
||||
$('.ibo-dashboard#$sDivId').unblock();
|
||||
}
|
||||
);
|
||||
}
|
||||
@@ -978,52 +995,58 @@ EOF
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \iTopWebPage $oPage
|
||||
* @param WebPage $oPage
|
||||
* @param array $aAjaxParams
|
||||
*
|
||||
* @throws \CoreException
|
||||
* @throws \CoreUnexpectedValue
|
||||
* @throws \MySQLException
|
||||
*/
|
||||
protected function RenderSelector($oPage, $aAjaxParams = array())
|
||||
protected function RenderSelector(WebPage $oPage, $aAjaxParams = array())
|
||||
{
|
||||
$sId = $this->GetId();
|
||||
$sDivId = utils::Sanitize($sId, '', 'element_identifier');
|
||||
$sExtraParams = json_encode($aAjaxParams);
|
||||
|
||||
$sSelectorHtml = '<div class="dashboard-selector">';
|
||||
if ($this->HasCustomDashboard())
|
||||
{
|
||||
$sSelectorHtml = '<div class="ibo-top-bar--toolbar-dashboard-selector">';
|
||||
if ($this->HasCustomDashboard()) {
|
||||
$bStandardSelected = appUserPreferences::GetPref('display_original_dashboard_'.$sId, false);
|
||||
$sStandard = Dict::S('UI:Toggle:StandardDashboard');
|
||||
$sSelectorHtml .= '<div class="selector-label">'.$sStandard.'</div>';
|
||||
$sSelectorHtml .= '<label class="switch"><input type="checkbox" onchange="ToggleDashboardSelector'.$sDivId.'();" '.($bStandardSelected ? '' : 'checked').'><span class="slider round"></span></label></input></label>';
|
||||
$sCustom = Dict::S('UI:Toggle:CustomDashboard');
|
||||
$sSelectorHtml .= '<div class="selector-label">'.$sCustom.'</div>';
|
||||
|
||||
}
|
||||
$sSelectorHtml .= '</div>';
|
||||
$sSelectorHtml = addslashes($sSelectorHtml);
|
||||
$sFile = addslashes($this->GetDefinitionFile());
|
||||
$sReloadURL = $this->GetReloadURL();
|
||||
|
||||
$oPage->add_ready_script(
|
||||
<<<EOF
|
||||
$('.dashboard-title').after('$sSelectorHtml');
|
||||
EOF
|
||||
);
|
||||
if ($oPage instanceof iTopWebPage) {
|
||||
$oToolbar = $oPage->GetTopBarLayout()->GetToolbar();
|
||||
$oToolbar->AddHtml($sSelectorHtml);
|
||||
|
||||
$oPage->add_script(
|
||||
<<<EOF
|
||||
$oPage->add_script(
|
||||
<<<EOF
|
||||
function ToggleDashboardSelector$sDivId()
|
||||
{
|
||||
$('.dashboard_contents#$sDivId').block();
|
||||
$('.ibo-dashboard#$sDivId').block();
|
||||
$.post(GetAbsoluteUrlAppRoot()+'pages/ajax.render.php',
|
||||
{ operation: 'toggle_dashboard', dashboard_id: '$sId', file: '$sFile', extra_params: $sExtraParams, reload_url: '$sReloadURL' },
|
||||
function(data) {
|
||||
$('.dashboard_contents#$sDivId').html(data);
|
||||
$('.dashboard_contents#$sDivId').unblock();
|
||||
$('.ibo-dashboard#$sDivId').html(data);
|
||||
$('.ibo-dashboard#$sDivId').unblock();
|
||||
}
|
||||
);
|
||||
}
|
||||
EOF
|
||||
);
|
||||
);
|
||||
} else {
|
||||
$sSelectorHtml = addslashes($sSelectorHtml);
|
||||
$oPage->add_script(<<<JS
|
||||
$(".ibo-top-bar--toolbar-dashboard-selector").replaceWith("$sSelectorHtml");
|
||||
JS
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1055,43 +1078,67 @@ EOF
|
||||
*/
|
||||
protected function RenderEditionTools(WebPage $oPage, $aExtraParams)
|
||||
{
|
||||
if (!($oPage instanceof iTopWebPage)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$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><i class=\"top-right-icon icon-additional-arrow fas fa-pencil-alt\"></i><ul>";
|
||||
|
||||
$sId = utils::Sanitize($this->GetId(), '', 'element_identifier');
|
||||
|
||||
$sMenuTogglerId = "ibo-dashboard-menu-toggler-{$sId}";
|
||||
$sPopoverMenuId = "ibo-dashboard-menu-popover-{$sId}";
|
||||
$sName = 'UI:Dashboard:Actions';
|
||||
$oToolbar = $oPage->GetTopBarLayout()->GetToolbar();
|
||||
$oActionButton = ButtonFactory::MakeLinkNeutral('', '', 'fas fa-ellipsis-v', $sName, '', $sMenuTogglerId);
|
||||
$oActionButton->AddCSSClasses("ibo-top-bar--toolbar-dashboard-menu-toggler");
|
||||
|
||||
$oToolbar->AddSubBlock($oActionButton);
|
||||
|
||||
$aActions = array();
|
||||
$sFile = addslashes($this->sDefinitionFile);
|
||||
$sJSExtraParams = json_encode($aExtraParams);
|
||||
$bCanEdit = true;
|
||||
if ($this->HasCustomDashboard())
|
||||
{
|
||||
if ($this->HasCustomDashboard()) {
|
||||
$bCanEdit = !appUserPreferences::GetPref('display_original_dashboard_'.$this->GetId(), false);
|
||||
}
|
||||
if ($bCanEdit)
|
||||
{
|
||||
if ($bCanEdit) {
|
||||
$oEdit = new JSPopupMenuItem('UI:Dashboard:Edit', Dict::S('UI:Dashboard:Edit'), "return EditDashboard('{$this->sId}', '$sFile', $sJSExtraParams)");
|
||||
$aActions[$oEdit->GetUID()] = $oEdit->GetMenuItem();
|
||||
}
|
||||
|
||||
if ($this->bCustomized)
|
||||
{
|
||||
if ($this->bCustomized) {
|
||||
$oRevert = new JSPopupMenuItem('UI:Dashboard:RevertConfirm', Dict::S('UI:Dashboard:Revert'),
|
||||
"if (confirm('".addslashes(Dict::S('UI:Dashboard:RevertConfirm'))."')) return RevertDashboard('{$this->sId}', $sJSExtraParams); else return false");
|
||||
"if (confirm('".addslashes(Dict::S('UI:Dashboard:RevertConfirm'))."')) return RevertDashboard('{$this->sId}', $sJSExtraParams); else return false");
|
||||
$aActions[$oRevert->GetUID()] = $oRevert->GetMenuItem();
|
||||
}
|
||||
|
||||
utils::GetPopupMenuItems($oPage, iPopupMenuExtension::MENU_DASHBOARD_ACTIONS, $this, $aActions);
|
||||
$sEditMenu .= $oPage->RenderPopupMenuItems($aActions);
|
||||
$sEditMenu = addslashes($sEditMenu);
|
||||
$sReloadURL = $this->GetReloadURL();
|
||||
$oPage->add_ready_script(
|
||||
<<<EOF
|
||||
$('.dashboard-title').after('$sEditMenu');
|
||||
$('#DashboardMenu>ul').popupmenu();
|
||||
|
||||
$oToolbar->AddSubBlock($oPage->GetPopoverMenu($sPopoverMenuId, $aActions));
|
||||
$oActionButton->AddCSSClasses('ibo-action-button')
|
||||
->SetJsCode(<<<JS
|
||||
$("#{$sPopoverMenuId}").popover_menu({toggler: "#{$sMenuTogglerId}"});
|
||||
$('#{$sMenuTogglerId}').on('click', function(oEvent) {
|
||||
var oEventTarget = $('#{$sMenuTogglerId}');
|
||||
var aEventTargetPos = oEventTarget.position();
|
||||
var popover = $("#{$sPopoverMenuId}");
|
||||
|
||||
EOF
|
||||
);
|
||||
popover.css({
|
||||
// 'top': (aEventTargetPos.top + parseInt(oEventTarget.css('marginTop'), 10) + oEventTarget.height()) + 'px',
|
||||
// 'left': (aEventTargetPos.left + parseInt(oEventTarget.css('marginLeft'), 10) + oEventTarget.width() - popover.width()) + 'px',
|
||||
'top': (aEventTargetPos.top + oEventTarget.outerHeight(true)) + 'px',
|
||||
'left': (aEventTargetPos.left + oEventTarget.outerWidth(true) - popover.width()) + 'px',
|
||||
'z-index': 10060
|
||||
});
|
||||
popover.popover_menu("togglePopup");
|
||||
});
|
||||
JS
|
||||
);
|
||||
|
||||
$sReloadURL = $this->GetReloadURL();
|
||||
$oPage->add_script(
|
||||
<<<EOF
|
||||
<<<EOF
|
||||
function EditDashboard(sId, sDashboardFile, aExtraParams)
|
||||
{
|
||||
$.post(GetAbsoluteUrlAppRoot()+'pages/ajax.render.php', {operation: 'dashboard_editor', id: sId, file: sDashboardFile, extra_params: aExtraParams, reload_url: '$sReloadURL'},
|
||||
@@ -1575,12 +1622,10 @@ JS
|
||||
{
|
||||
$sDataTableId = Dashlet::APPUSERPREFERENCES_PREFIX.$sDashletId;
|
||||
$aClassAliases = array();
|
||||
try{
|
||||
try {
|
||||
$oFilter = $oDashlet->GetDBSearch($aExtraParams);
|
||||
$aClassAliases = $oFilter->GetSelectedClasses();
|
||||
}
|
||||
catch (Exception $e)
|
||||
{
|
||||
} catch (Exception $e) {
|
||||
//on error, return default value
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -15,15 +15,17 @@
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with iTop. If not, see <http://www.gnu.org/licenses/>
|
||||
use Combodo\iTop\Application\UI\Component\Html\Html;
|
||||
use Combodo\iTop\Application\UI\Layout\Dashboard\DashboardColumn;
|
||||
use Combodo\iTop\Application\UI\Layout\Dashboard\DashboardLayout as UIDashboardLayout;
|
||||
use Combodo\iTop\Application\UI\Layout\Dashboard\DashboardRow;
|
||||
|
||||
/**
|
||||
* Dashboard presentation
|
||||
*
|
||||
*
|
||||
* @copyright Copyright (C) 2010-2012 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
|
||||
*/
|
||||
abstract class DashboardLayout
|
||||
{
|
||||
abstract public function Render($oPage, $aDashlets, $bEditMode = false);
|
||||
@@ -114,61 +116,52 @@ 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>');
|
||||
$oDashboardLayout = new UIDashboardLayout();
|
||||
$oPage->AddUiBlock($oDashboardLayout);
|
||||
|
||||
$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 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-column-index=\"$iCols\" data-dashboard-cell-index=\"$iCellIdx\">");
|
||||
if (array_key_exists($iCellIdx, $aCells))
|
||||
{
|
||||
for ($iRows = 0; $iRows < $iNbRows; $iRows++) {
|
||||
$oDashboardRow = new DashboardRow();
|
||||
$oDashboardLayout->AddDashboardRow($oDashboardRow);
|
||||
|
||||
for ($iCols = 0; $iCols < $this->iNbCols; $iCols++) {
|
||||
$oDashboardColumn = new DashboardColumn($bEditMode);
|
||||
$oDashboardColumn->SetCellIndex($iCellIdx);
|
||||
$oDashboardRow->AddDashboardColumn($oDashboardColumn);
|
||||
|
||||
if (array_key_exists($iCellIdx, $aCells)) {
|
||||
$aDashlets = $aCells[$iCellIdx];
|
||||
if (count($aDashlets) > 0)
|
||||
{
|
||||
if (count($aDashlets) > 0) {
|
||||
/** @var \Dashlet $oDashlet */
|
||||
foreach($aDashlets as $oDashlet)
|
||||
{
|
||||
if ($oDashlet::IsVisible())
|
||||
{
|
||||
$oDashlet->DoRender($oPage, $bEditMode, true /* bEnclosingDiv */, $aExtraParams);
|
||||
foreach ($aDashlets as $oDashlet) {
|
||||
if ($oDashlet::IsVisible()) {
|
||||
$oDashboardColumn->AddUIBlock($oDashlet->DoRender($oPage, $bEditMode, true /* bEnclosingDiv */, $aExtraParams));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$oDashboardColumn->AddUIBlock(new Html(' '));
|
||||
}
|
||||
else
|
||||
{
|
||||
$oPage->add(' ');
|
||||
}
|
||||
} else {
|
||||
$oDashboardColumn->AddUIBlock(new Html(' '));
|
||||
}
|
||||
else
|
||||
{
|
||||
$oPage->add(' ');
|
||||
}
|
||||
$oPage->add('</td>');
|
||||
$iCellIdx++;
|
||||
}
|
||||
$oPage->add('</tr>');
|
||||
}
|
||||
|
||||
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 data-dashboard-row-index=\"$iRows\">");
|
||||
for($iCols = 0; $iCols < $this->iNbCols; $iCols++)
|
||||
{
|
||||
$oPage->add("<td $sStyle data-dashboard-column-index=\"$iCols\">");
|
||||
$oPage->add(' ');
|
||||
$oPage->add('</td>');
|
||||
$oDashboardRow = new DashboardRow();
|
||||
$oDashboardLayout->AddDashboardRow($oDashboardRow);
|
||||
|
||||
for ($iCols = 0; $iCols < $this->iNbCols; $iCols++) {
|
||||
$oDashboardColumn = new DashboardColumn($bEditMode, true);
|
||||
$oDashboardRow->AddDashboardColumn($oDashboardColumn);
|
||||
$oDashboardColumn->AddUIBlock(new Html(' '));
|
||||
}
|
||||
$oPage->add('</tr>');
|
||||
}
|
||||
$oPage->add('</tbody></table>');
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -16,6 +16,13 @@
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with iTop. If not, see <http://www.gnu.org/licenses/>
|
||||
|
||||
use Combodo\iTop\Application\UI\Component\Dashlet\DashletContainer;
|
||||
use Combodo\iTop\Application\UI\Component\Dashlet\DashletFactory;
|
||||
use Combodo\iTop\Application\UI\Component\Html\Html;
|
||||
use Combodo\iTop\Application\UI\Component\Panel\PanelFactory;
|
||||
use Combodo\iTop\Application\UI\iUIBlock;
|
||||
use Combodo\iTop\Application\UI\UIBlock;
|
||||
|
||||
require_once(APPROOT.'application/forms.class.inc.php');
|
||||
|
||||
/**
|
||||
@@ -50,7 +57,7 @@ abstract class Dashlet
|
||||
$this->bRedrawNeeded = true; // By default: redraw each time a property changes
|
||||
$this->bFormRedrawNeeded = false; // By default: no need to redraw the form (independent fields)
|
||||
$this->aProperties = array(); // By default: there is no property
|
||||
$this->aCSSClasses = array('dashlet');
|
||||
$this->aCSSClasses = array('ibo-dashlet');
|
||||
$this->sDashletType = get_class($this);
|
||||
}
|
||||
|
||||
@@ -66,21 +73,17 @@ abstract class Dashlet
|
||||
{
|
||||
$refValue = $this->aProperties[$sProperty];
|
||||
$sRefType = gettype($refValue);
|
||||
if (gettype($sValue) == $sRefType)
|
||||
{
|
||||
|
||||
if (gettype($sValue) == $sRefType) {
|
||||
// Do not change anything in that case!
|
||||
$ret = $sValue;
|
||||
}
|
||||
elseif ($sRefType == 'boolean')
|
||||
{
|
||||
} elseif ($sRefType == 'boolean') {
|
||||
$ret = ($sValue == 'true');
|
||||
}
|
||||
elseif ($sRefType == 'array')
|
||||
{
|
||||
} elseif ($sRefType == 'array') {
|
||||
$ret = explode(',', $sValue);
|
||||
}
|
||||
else
|
||||
{
|
||||
} elseif (is_array($sValue)) {
|
||||
$ret = $sValue;
|
||||
} else {
|
||||
$ret = $sValue;
|
||||
settype($ret, $sRefType);
|
||||
}
|
||||
@@ -191,10 +194,8 @@ abstract class Dashlet
|
||||
*/
|
||||
public function FromParams($aParams)
|
||||
{
|
||||
foreach ($this->aProperties as $sProperty => $value)
|
||||
{
|
||||
if (array_key_exists($sProperty, $aParams))
|
||||
{
|
||||
foreach ($this->aProperties as $sProperty => $value) {
|
||||
if (array_key_exists($sProperty, $aParams)) {
|
||||
$this->aProperties[$sProperty] = $aParams[$sProperty];
|
||||
}
|
||||
}
|
||||
@@ -207,79 +208,59 @@ abstract class Dashlet
|
||||
* @param bool $bEnclosingDiv
|
||||
* @param array $aExtraParams
|
||||
*/
|
||||
public function DoRender($oPage, $bEditMode = false, $bEnclosingDiv = true, $aExtraParams = array())
|
||||
public function DoRender($oPage, $bEditMode = false, $bEnclosingDiv = true, $aExtraParams = array()): UIBlock
|
||||
{
|
||||
$sCSSClasses = implode(' ', $this->aCSSClasses);
|
||||
$sId = $this->GetID();
|
||||
if ($bEnclosingDiv)
|
||||
{
|
||||
if ($bEditMode)
|
||||
{
|
||||
$oPage->add('<div class="'.$sCSSClasses.'" id="dashlet_'.$sId.'">');
|
||||
|
||||
$sCSSClasses = implode(' ', $this->aCSSClasses);
|
||||
if ($bEnclosingDiv) {
|
||||
if ($bEditMode) {
|
||||
$oDashletContainer = new DashletContainer("dashlet_{$sId}");
|
||||
} else {
|
||||
$oDashletContainer = new DashletContainer();
|
||||
}
|
||||
else
|
||||
{
|
||||
$oPage->add('<div class="'.$sCSSClasses.'">');
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach ($this->aCSSClasses as $sCSSClass)
|
||||
{
|
||||
$oDashletContainer->AddCSSClasses($sCSSClasses);
|
||||
} else {
|
||||
$oDashletContainer = new DashletContainer();
|
||||
|
||||
foreach ($this->aCSSClasses as $sCSSClass) {
|
||||
$oPage->add_ready_script("$('#dashlet_".$sId."').addClass('$sCSSClass');");
|
||||
}
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
if (get_class($this->oModelReflection) == 'ModelReflectionRuntime')
|
||||
{
|
||||
$this->Render($oPage, $bEditMode, $aExtraParams);
|
||||
try {
|
||||
if (get_class($this->oModelReflection) == 'ModelReflectionRuntime') {
|
||||
$oBlock = $this->Render($oPage, $bEditMode, $aExtraParams);
|
||||
} else {
|
||||
$oBlock = $this->RenderNoData($oPage, $bEditMode, $aExtraParams);
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->RenderNoData($oPage, $bEditMode, $aExtraParams);
|
||||
}
|
||||
}
|
||||
catch(UnknownClassOqlException $e)
|
||||
{
|
||||
$oDashletContainer->AddSubBlock($oBlock);
|
||||
} catch (UnknownClassOqlException $e) {
|
||||
// Maybe the class is part of a non-installed module, fail silently
|
||||
// Except in Edit mode
|
||||
if ($bEditMode)
|
||||
{
|
||||
$oPage->add('<div class="dashlet-content">');
|
||||
$oPage->add('<h2>'.$e->GetUserFriendlyDescription().'</h2>');
|
||||
$oPage->add('</div>');
|
||||
if ($bEditMode) {
|
||||
$oDashletContainer->AddCSSClasses("dashlet-content");
|
||||
$oDashletContainer->AddHtml('<h2>'.$e->GetUserFriendlyDescription().'</h2>');
|
||||
}
|
||||
}
|
||||
catch(OqlException $e)
|
||||
{
|
||||
$oPage->add('<div class="dashlet-content">');
|
||||
$oPage->p($e->GetUserFriendlyDescription());
|
||||
$oPage->add('</div>');
|
||||
}
|
||||
catch(Exception $e)
|
||||
{
|
||||
$oPage->add('<div class="dashlet-content">');
|
||||
$oPage->p($e->getMessage());
|
||||
$oPage->add('</div>');
|
||||
} catch (OqlException $e) {
|
||||
$oDashletContainer->AddCSSClasses("dashlet-content");
|
||||
$oDashletContainer->AddHtml('<p>'.$e->GetUserFriendlyDescription().'</p>');
|
||||
} catch (Exception $e) {
|
||||
$oDashletContainer->AddCSSClasses("dashlet-content");
|
||||
$oDashletContainer->AddHtml('<p>'.$e->getMessage().'</p>');
|
||||
}
|
||||
|
||||
if ($bEnclosingDiv)
|
||||
{
|
||||
$oPage->add('</div>');
|
||||
}
|
||||
|
||||
if ($bEditMode)
|
||||
{
|
||||
if ($bEditMode) {
|
||||
$sClass = get_class($this);
|
||||
$sType = $this->sDashletType;
|
||||
$oPage->add_ready_script(
|
||||
<<<EOF
|
||||
<<<EOF
|
||||
$('#dashlet_$sId').dashlet({dashlet_id: '$sId', dashlet_class: '$sClass', 'dashlet_type': '$sType'});
|
||||
EOF
|
||||
);
|
||||
}
|
||||
|
||||
return $oDashletContainer;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -303,7 +284,7 @@ EOF
|
||||
* @param bool $bEditMode
|
||||
* @param array $aExtraParams
|
||||
*
|
||||
* @return mixed
|
||||
* @return iUIBlock
|
||||
*/
|
||||
abstract public function Render($oPage, $bEditMode = false, $aExtraParams = array());
|
||||
|
||||
@@ -313,10 +294,12 @@ EOF
|
||||
* @param \WebPage $oPage
|
||||
* @param bool $bEditMode
|
||||
* @param array $aExtraParams
|
||||
*
|
||||
* @return iUIBlock
|
||||
*/
|
||||
public function RenderNoData($oPage, $bEditMode = false, $aExtraParams = array())
|
||||
{
|
||||
$this->Render($oPage, $bEditMode, $aExtraParams);
|
||||
return $this->Render($oPage, $bEditMode, $aExtraParams);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -619,12 +602,12 @@ class DashletUnknown extends Dashlet
|
||||
$sIconUrl = utils::HtmlEntities(utils::GetAbsoluteUrlAppRoot().$aInfos['icon']);
|
||||
$sExplainText = ($bEditMode) ? Dict::Format('UI:DashletUnknown:RenderText:Edit', $this->GetDashletType()) : Dict::S('UI:DashletUnknown:RenderText:View');
|
||||
|
||||
$oPage->add('<div class="dashlet-content">');
|
||||
$oDashletContainer = new DashletContainer(null, 'dashlet-content');
|
||||
|
||||
$oPage->add('<div class="dashlet-ukn-image"><img src="'.$sIconUrl.'" /></div>');
|
||||
$oPage->add('<div class="dashlet-ukn-text">'.$sExplainText.'</div>');
|
||||
$oDashletContainer->AddHtml('<div class="dashlet-ukn-image"><img src="'.$sIconUrl.'" /></div>');
|
||||
$oDashletContainer->AddHtml('<div class="dashlet-ukn-text">'.$sExplainText.'</div>');
|
||||
|
||||
$oPage->add('</div>');
|
||||
return $oDashletContainer;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -639,12 +622,12 @@ class DashletUnknown extends Dashlet
|
||||
$sIconUrl = utils::HtmlEntities(utils::GetAbsoluteUrlAppRoot().$aInfos['icon']);
|
||||
$sExplainText = Dict::Format('UI:DashletUnknown:RenderNoDataText:Edit', $this->GetDashletType());
|
||||
|
||||
$oPage->add('<div class="dashlet-content">');
|
||||
$oDashletContainer = new DashletContainer(null, 'dashlet-content');
|
||||
|
||||
$oPage->add('<div class="dashlet-ukn-image"><img src="'.$sIconUrl.'" /></div>');
|
||||
$oPage->add('<div class="dashlet-ukn-text">'.$sExplainText.'</div>');
|
||||
$oDashletContainer->AddHtml('<div class="dashlet-ukn-image"><img src="'.$sIconUrl.'" /></div>');
|
||||
$oDashletContainer->AddHtml('<div class="dashlet-ukn-text">'.$sExplainText.'</div>');
|
||||
|
||||
$oPage->add('</div>');
|
||||
return $oDashletContainer;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -763,9 +746,9 @@ class DashletProxy extends DashletUnknown
|
||||
public function Render($oPage, $bEditMode = false, $aExtraParams = array())
|
||||
{
|
||||
// This should never be called.
|
||||
$oPage->add('<div class="dashlet-content">');
|
||||
$oPage->add('<div>This dashlet is not supposed to be rendered as it is just a proxy for third-party widgets.</div>');
|
||||
$oPage->add('</div>');
|
||||
$oDashletContainer = new DashletContainer(null, 'dashlet-content');
|
||||
$oDashletContainer->AddHtml('<div>This dashlet is not supposed to be rendered as it is just a proxy for third-party widgets.</div>');
|
||||
return $oDashletContainer;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -780,12 +763,14 @@ class DashletProxy extends DashletUnknown
|
||||
$sIconUrl = utils::HtmlEntities(utils::GetAbsoluteUrlAppRoot().$aInfos['icon']);
|
||||
$sExplainText = Dict::Format('UI:DashletProxy:RenderNoDataText:Edit', $this->GetDashletType());
|
||||
|
||||
$oPage->add('<div class="dashlet-content">');
|
||||
$oDashletContainer = new DashletContainer(null, 'dashlet-content');
|
||||
|
||||
$oPage->add('<div class="dashlet-pxy-image"><img src="'.$sIconUrl.'" /></div>');
|
||||
$oPage->add('<div class="dashlet-pxy-text">'.$sExplainText.'</div>');
|
||||
$sHtml = '';
|
||||
$sHtml .= '<div class="dashlet-pxy-image"><img src="'.$sIconUrl.'" /></div>';
|
||||
$sHtml .= '<div class="dashlet-pxy-text">'.$sExplainText.'</div>';
|
||||
|
||||
$oPage->add('</div>');
|
||||
$oDashletContainer->AddHtml($sHtml);
|
||||
return $oDashletContainer;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -816,7 +801,7 @@ class DashletEmptyCell extends Dashlet
|
||||
*/
|
||||
public function Render($oPage, $bEditMode = false, $aExtraParams = array())
|
||||
{
|
||||
$oPage->add(' ');
|
||||
return new Html(' ');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -866,8 +851,9 @@ class DashletPlainText extends Dashlet
|
||||
$sText = utils::HtmlEntities($this->aProperties['text']);
|
||||
$sText = str_replace(array("\r\n", "\n", "\r"), "<br/>", $sText);
|
||||
|
||||
$sId = 'plaintext_'.($bEditMode? 'edit_' : '').$this->sId;
|
||||
$oPage->add('<div id="'.$sId.'" class="dashlet-content">'.$sText.'</div>');
|
||||
$sId = 'plaintext_'.($bEditMode ? 'edit_' : '').$this->sId;
|
||||
|
||||
return DashletFactory::MakeForDashletText($sId, $sText);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -918,12 +904,8 @@ class DashletObjectList extends Dashlet
|
||||
$sTitle = $this->aProperties['title'];
|
||||
$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('<div class="main_header"><h1> '.$sHtmlTitle.'</h1></div>');
|
||||
}
|
||||
$oPanel = PanelFactory::MakeNeutral(Dict::S($sTitle));
|
||||
|
||||
$oFilter = $this->GetDBSearch($aExtraParams);
|
||||
$oBlock = new DisplayBlock($oFilter, 'list');
|
||||
$aParams = array(
|
||||
@@ -931,28 +913,9 @@ class DashletObjectList extends Dashlet
|
||||
'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>');
|
||||
}
|
||||
$oBlock->DisplayIntoContentBlock($oPanel, $oPage, $sBlockId, array_merge($aExtraParams, $aParams));
|
||||
|
||||
public function GetDBSearch($aExtraParams = array())
|
||||
{
|
||||
$sQuery = $this->aProperties['query'];
|
||||
if (isset($aExtraParams['query_params']))
|
||||
{
|
||||
$aQueryParams = $aExtraParams['query_params'];
|
||||
}
|
||||
elseif (isset($aExtraParams['this->class']) && isset($aExtraParams['this->id']))
|
||||
{
|
||||
$oObj = MetaModel::GetObject($aExtraParams['this->class'], $aExtraParams['this->id']);
|
||||
$aQueryParams = $oObj->ToArgsForQuery();
|
||||
}
|
||||
else
|
||||
{
|
||||
$aQueryParams = array();
|
||||
}
|
||||
|
||||
return DBObjectSearch::FromOQL($sQuery, $aQueryParams);
|
||||
return $oPanel;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -966,22 +929,35 @@ class DashletObjectList extends Dashlet
|
||||
|
||||
$oPage->add('<div class="dashlet-content">');
|
||||
$sHtmlTitle = utils::HtmlEntities($this->oModelReflection->DictString($sTitle)); // done in the itop block
|
||||
if ($sHtmlTitle != '')
|
||||
{
|
||||
if ($sHtmlTitle != '') {
|
||||
$oPage->add('<h1>'.$sHtmlTitle.'</h1>');
|
||||
}
|
||||
$oQuery = $this->oModelReflection->GetQuery($sQuery);
|
||||
$sClass = $oQuery->GetClass();
|
||||
$oPage->add('<div id="block_fake_'.$this->sId.'" class="display_block">');
|
||||
$oPage->p(Dict::S('UI:NoObjectToDisplay'));
|
||||
if ($bShowMenu)
|
||||
{
|
||||
if ($bShowMenu) {
|
||||
$oPage->p('<a>'.Dict::Format('UI:ClickToCreateNew', $this->oModelReflection->GetName($sClass)).'</a>');
|
||||
}
|
||||
$oPage->add('</div>');
|
||||
$oPage->add('</div>');
|
||||
}
|
||||
|
||||
public function GetDBSearch($aExtraParams = array())
|
||||
{
|
||||
$sQuery = $this->aProperties['query'];
|
||||
if (isset($aExtraParams['query_params'])) {
|
||||
$aQueryParams = $aExtraParams['query_params'];
|
||||
} elseif (isset($aExtraParams['this->class']) && isset($aExtraParams['this->id'])) {
|
||||
$oObj = MetaModel::GetObject($aExtraParams['this->class'], $aExtraParams['this->id']);
|
||||
$aQueryParams = $oObj->ToArgsForQuery();
|
||||
} else {
|
||||
$aQueryParams = array();
|
||||
}
|
||||
|
||||
return DBObjectSearch::FromOQL($sQuery, $aQueryParams);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
@@ -1199,93 +1175,81 @@ abstract class DashletGroupBy extends Dashlet
|
||||
$sStyle = $this->aProperties['style'];
|
||||
|
||||
// First perform the query - if the OQL is not ok, it will generate an exception : no need to go further
|
||||
if (isset($aExtraParams['query_params']))
|
||||
{
|
||||
if (isset($aExtraParams['query_params'])) {
|
||||
$aQueryParams = $aExtraParams['query_params'];
|
||||
}
|
||||
elseif (isset($aExtraParams['this->class']) && isset($aExtraParams['this->id']))
|
||||
{
|
||||
} elseif (isset($aExtraParams['this->class']) && isset($aExtraParams['this->id'])) {
|
||||
$oObj = MetaModel::GetObject($aExtraParams['this->class'], $aExtraParams['this->id']);
|
||||
$aQueryParams = $oObj->ToArgsForQuery();
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
$aQueryParams = array();
|
||||
}
|
||||
$oFilter = DBObjectSearch::FromOQL($sQuery, $aQueryParams);
|
||||
$oFilter->SetShowObsoleteData(utils::ShowObsoleteData());
|
||||
|
||||
$sClass = $oFilter->GetClass();
|
||||
if (!$this->oModelReflection->IsValidAttCode($sClass, $this->sGroupByAttCode))
|
||||
{
|
||||
$oPage->add('<p>'.Dict::S('UI:DashletGroupBy:MissingGroupBy').'</p>');
|
||||
if (!$this->oModelReflection->IsValidAttCode($sClass, $this->sGroupByAttCode)) {
|
||||
return new Html('<p>'.Dict::S('UI:DashletGroupBy:MissingGroupBy').'</p>');
|
||||
}
|
||||
else
|
||||
{
|
||||
switch($sStyle)
|
||||
{
|
||||
case 'bars':
|
||||
$sType = 'chart';
|
||||
$aParams = array(
|
||||
'chart_type' => 'bars',
|
||||
'chart_title' => $sTitle,
|
||||
'group_by' => $this->sGroupByExpr,
|
||||
'group_by_label' => $this->sGroupByLabel,
|
||||
'aggregation_function' => $this->sAggregationFunction,
|
||||
'aggregation_attribute' => $this->sAggregationAttribute,
|
||||
'limit' => $this->sLimit,
|
||||
'order_direction' => $this->sOrderDirection,
|
||||
'order_by' => $this->sOrderBy,
|
||||
);
|
||||
$sHtmlTitle = ''; // done in the itop block
|
||||
break;
|
||||
|
||||
case 'pie':
|
||||
$sType = 'chart';
|
||||
$aParams = array(
|
||||
'chart_type' => 'pie',
|
||||
'chart_title' => $sTitle,
|
||||
'group_by' => $this->sGroupByExpr,
|
||||
'group_by_label' => $this->sGroupByLabel,
|
||||
'aggregation_function' => $this->sAggregationFunction,
|
||||
'aggregation_attribute' => $this->sAggregationAttribute,
|
||||
'limit' => $this->sLimit,
|
||||
'order_direction' => $this->sOrderDirection,
|
||||
'order_by' => $this->sOrderBy,
|
||||
);
|
||||
$sHtmlTitle = ''; // done in the itop block
|
||||
break;
|
||||
switch ($sStyle) {
|
||||
case 'bars':
|
||||
$sType = 'chart';
|
||||
$aParams = array(
|
||||
'chart_type' => 'bars',
|
||||
'chart_title' => $sTitle,
|
||||
'group_by' => $this->sGroupByExpr,
|
||||
'group_by_label' => $this->sGroupByLabel,
|
||||
'aggregation_function' => $this->sAggregationFunction,
|
||||
'aggregation_attribute' => $this->sAggregationAttribute,
|
||||
'limit' => $this->sLimit,
|
||||
'order_direction' => $this->sOrderDirection,
|
||||
'order_by' => $this->sOrderBy,
|
||||
);
|
||||
$sHtmlTitle = ''; // done in the itop block
|
||||
break;
|
||||
|
||||
case 'table':
|
||||
default:
|
||||
$sHtmlTitle = utils::HtmlEntities(Dict::S($sTitle)); // done in the itop block
|
||||
$sType = 'count';
|
||||
$aParams = array(
|
||||
'group_by' => $this->sGroupByExpr,
|
||||
'group_by_label' => $this->sGroupByLabel,
|
||||
'aggregation_function' => $this->sAggregationFunction,
|
||||
'aggregation_attribute' => $this->sAggregationAttribute,
|
||||
'limit' => $this->sLimit,
|
||||
'order_direction' => $this->sOrderDirection,
|
||||
'order_by' => $this->sOrderBy,
|
||||
);
|
||||
break;
|
||||
}
|
||||
case 'pie':
|
||||
$sType = 'chart';
|
||||
$aParams = array(
|
||||
'chart_type' => 'pie',
|
||||
'chart_title' => $sTitle,
|
||||
'group_by' => $this->sGroupByExpr,
|
||||
'group_by_label' => $this->sGroupByLabel,
|
||||
'aggregation_function' => $this->sAggregationFunction,
|
||||
'aggregation_attribute' => $this->sAggregationAttribute,
|
||||
'limit' => $this->sLimit,
|
||||
'order_direction' => $this->sOrderDirection,
|
||||
'order_by' => $this->sOrderBy,
|
||||
);
|
||||
$sHtmlTitle = ''; // done in the itop block
|
||||
break;
|
||||
|
||||
$oPage->add('<div class="dashlet-content">');
|
||||
if ($sHtmlTitle != '')
|
||||
{
|
||||
$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);
|
||||
$oBlock->Display($oPage, $sBlockId, array_merge($aExtraParams, $aParams));
|
||||
if($bEditMode)
|
||||
{
|
||||
$oPage->add('<div class="dashlet-blocker"></div>');
|
||||
}
|
||||
$oPage->add('</div>');
|
||||
case 'table':
|
||||
default:
|
||||
$sHtmlTitle = utils::HtmlEntities(Dict::S($sTitle)); // done in the itop block
|
||||
$sType = 'count';
|
||||
$aParams = array(
|
||||
'group_by' => $this->sGroupByExpr,
|
||||
'group_by_label' => $this->sGroupByLabel,
|
||||
'aggregation_function' => $this->sAggregationFunction,
|
||||
'aggregation_attribute' => $this->sAggregationAttribute,
|
||||
'limit' => $this->sLimit,
|
||||
'order_direction' => $this->sOrderDirection,
|
||||
'order_by' => $this->sOrderBy,
|
||||
);
|
||||
break;
|
||||
}
|
||||
|
||||
$oPanel = PanelFactory::MakeNeutral(Dict::S($sTitle));
|
||||
|
||||
|
||||
$sBlockId = 'block_'.$this->sId.($bEditMode ? '_edit' : ''); // make a unique id (edition occurring in the same DOM)
|
||||
$oBlock = new DisplayBlock($oFilter, $sType);
|
||||
$oBlock->DisplayIntoContentBlock($oPanel, $oPage, $sBlockId, array_merge($aExtraParams, $aParams));
|
||||
if ($bEditMode) {
|
||||
$oPanel->AddHtml('<div class="dashlet-blocker"></div>');
|
||||
}
|
||||
return $oPanel;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1368,9 +1332,9 @@ abstract class DashletGroupBy extends Dashlet
|
||||
*/
|
||||
public function RenderNoData($oPage, $bEditMode = false, $aExtraParams = array())
|
||||
{
|
||||
$oPage->add('<div class="dashlet-content">');
|
||||
$oPage->add('error!');
|
||||
$oPage->add('</div>');
|
||||
$oDashletContainer = new DashletContainer(null, 'dashlet-content');
|
||||
$oDashletContainer->AddHtml('error!');
|
||||
return $oDashletContainer;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1691,26 +1655,27 @@ class DashletGroupByPie extends DashletGroupBy
|
||||
*/
|
||||
public function RenderNoData($oPage, $bEditMode = false, $aExtraParams = array())
|
||||
{
|
||||
$oDashletContainer = new DashletContainer(null, 'dashlet-content');
|
||||
|
||||
$sTitle = $this->aProperties['title'];
|
||||
|
||||
$sBlockId = 'block_fake_'.$this->sId.($bEditMode ? '_edit' : ''); // make a unique id (edition occuring in the same DOM)
|
||||
|
||||
$HTMLsTitle = ($sTitle != '') ? '<h1 style="text-align:center">'.utils::HtmlEntities($sTitle).'</h1>' : '';
|
||||
$oPage->add("<div style=\"background-color:#fff;padding:0.25em;\">$HTMLsTitle<div id=\"$sBlockId\" style=\"background-color:#fff;\"></div></div>");
|
||||
$oDashletContainer->AddHtml("<div style=\"background-color:#fff;padding:0.25em;\">$HTMLsTitle<div id=\"$sBlockId\" style=\"background-color:#fff;\"></div></div>");
|
||||
|
||||
$aDisplayValues = $this->MakeSimulatedData();
|
||||
|
||||
$aColumns = array();
|
||||
$aNames = array();
|
||||
foreach($aDisplayValues as $idx => $aValue)
|
||||
{
|
||||
foreach ($aDisplayValues as $idx => $aValue) {
|
||||
$aColumns[] = array('series_'.$idx, (int)$aValue['value']);
|
||||
$aNames['series_'.$idx] = $aValue['label'];
|
||||
}
|
||||
$sJSColumns = json_encode($aColumns);
|
||||
$sJSNames = json_encode($aNames);
|
||||
$oPage->add_ready_script(
|
||||
<<<EOF
|
||||
<<<EOF
|
||||
window.setTimeout(function() {
|
||||
var chart = c3.generate({
|
||||
bindto: '#{$sBlockId}',
|
||||
@@ -1731,6 +1696,8 @@ var chart = c3.generate({
|
||||
});}, 100);
|
||||
EOF
|
||||
);
|
||||
|
||||
return $oDashletContainer;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1763,25 +1730,26 @@ class DashletGroupByBars extends DashletGroupBy
|
||||
*/
|
||||
public function RenderNoData($oPage, $bEditMode = false, $aExtraParams = array())
|
||||
{
|
||||
$oDashletContainer = new DashletContainer(null, 'dashlet-content');
|
||||
|
||||
$sTitle = $this->aProperties['title'];
|
||||
|
||||
$sBlockId = 'block_fake_'.$this->sId.($bEditMode ? '_edit' : ''); // make a unique id (edition occuring in the same DOM)
|
||||
|
||||
$HTMLsTitle = ($sTitle != '') ? '<h1 style="text-align:center">'.utils::HtmlEntities($sTitle).'</h1>' : '';
|
||||
$oPage->add("<div style=\"background-color:#fff;padding:0.25em;\">$HTMLsTitle<div id=\"$sBlockId\" style=\"background-color:#fff;\"></div></div>");
|
||||
$oDashletContainer->AddHtml("<div style=\"background-color:#fff;padding:0.25em;\">$HTMLsTitle<div id=\"$sBlockId\" style=\"background-color:#fff;\"></div></div>");
|
||||
|
||||
$aDisplayValues = $this->MakeSimulatedData();
|
||||
|
||||
$aNames = array();
|
||||
foreach($aDisplayValues as $idx => $aValue)
|
||||
{
|
||||
foreach ($aDisplayValues as $idx => $aValue) {
|
||||
$aNames[$idx] = $aValue['label'];
|
||||
}
|
||||
$sJSNames = json_encode($aNames);
|
||||
|
||||
$sJson = json_encode($aDisplayValues);
|
||||
$oPage->add_ready_script(
|
||||
<<<EOF
|
||||
<<<EOF
|
||||
window.setTimeout(function() {
|
||||
var chart = c3.generate({
|
||||
bindto: '#{$sBlockId}',
|
||||
@@ -1829,6 +1797,8 @@ window.setTimeout(function() {
|
||||
}, 100);
|
||||
EOF
|
||||
);
|
||||
|
||||
return $oDashletContainer;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1860,40 +1830,44 @@ class DashletGroupByTable extends DashletGroupBy
|
||||
*/
|
||||
public function RenderNoData($oPage, $bEditMode = false, $aExtraParams = array())
|
||||
{
|
||||
$oDashletContainer = new DashletContainer();
|
||||
|
||||
$aDisplayValues = $this->MakeSimulatedData();
|
||||
$iTotal = 0;
|
||||
foreach($aDisplayValues as $iRow => $aDisplayData)
|
||||
{
|
||||
foreach ($aDisplayValues as $iRow => $aDisplayData) {
|
||||
$iTotal += $aDisplayData['value'];
|
||||
}
|
||||
|
||||
|
||||
$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>');
|
||||
$oPage->add('<tr>');
|
||||
$oPage->add('<th class="header" title="">'.$this->sGroupByLabel.'</th>');
|
||||
$oPage->add('<th class="header" title="'.Dict::S('UI:GroupBy:Count+').'">'.Dict::S('UI:GroupBy:Count').'</th>');
|
||||
$oPage->add('</tr>');
|
||||
$oPage->add('</thead>');
|
||||
$oPage->add('<tbody>');
|
||||
foreach($aDisplayValues as $aDisplayData)
|
||||
{
|
||||
$oPage->add('<tr class="even">');
|
||||
$oPage->add('<td class=""><span title="Active">'.$aDisplayData['label'].'</span></td>');
|
||||
$oPage->add('<td class=""><a>'.$aDisplayData['value'].'</a></td>');
|
||||
$oPage->add('</tr>');
|
||||
$sHtml = '';
|
||||
$sHtml .= '<div id="'.$sBlockId.'" class="display_block">';
|
||||
$sHtml .= '<div class="dashlet-content">';
|
||||
$sHtml .= '<p>'.Dict::Format('UI:Pagination:HeaderNoSelection', $iTotal).'</p>';
|
||||
$sHtml .= '<table class="listResults">';
|
||||
$sHtml .= '<thead>';
|
||||
$sHtml .= '<tr>';
|
||||
$sHtml .= '<th class="header" title="">'.$this->sGroupByLabel.'</th>';
|
||||
$sHtml .= '<th class="header" title="'.Dict::S('UI:GroupBy:Count+').'">'.Dict::S('UI:GroupBy:Count').'</th>';
|
||||
$sHtml .= '</tr>';
|
||||
$sHtml .= '</thead>';
|
||||
$sHtml .= '<tbody>';
|
||||
foreach ($aDisplayValues as $aDisplayData) {
|
||||
$sHtml .= '<tr class="even">';
|
||||
$sHtml .= '<td class=""><span title="Active">'.$aDisplayData['label'].'</span></td>';
|
||||
$sHtml .= '<td class=""><a>'.$aDisplayData['value'].'</a></td>';
|
||||
$sHtml .= '</tr>';
|
||||
}
|
||||
$oPage->add('</tbody>');
|
||||
$oPage->add('</table>');
|
||||
$oPage->add('</div>');
|
||||
$sHtml .= '</tbody>';
|
||||
$sHtml .= '</table>';
|
||||
$sHtml .= '</div>';
|
||||
|
||||
$oPage->add('</div>');
|
||||
$sHtml .= '</div>';
|
||||
|
||||
$oDashletContainer->AddHtml($sHtml);
|
||||
|
||||
return $oDashletContainer;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1922,14 +1896,7 @@ class DashletHeaderStatic extends Dashlet
|
||||
$oIconSelect = $this->oModelReflection->GetIconSelectionField('icon');
|
||||
$sIconPath = utils::HtmlEntities($oIconSelect->MakeFileUrl($sIcon));
|
||||
|
||||
$oPage->add('<div class="dashlet-content">');
|
||||
$oPage->add('<div class="main_header">');
|
||||
|
||||
$oPage->add('<img src="'.$sIconPath.'">');
|
||||
$oPage->add('<div class="main_header"><h1> '.$this->oModelReflection->DictString($sTitle).'</h1></div>');
|
||||
|
||||
$oPage->add('</div>');
|
||||
$oPage->add('</div>');
|
||||
return DashletFactory::MakeForDashletHeaderStatic($this->oModelReflection->DictString($sTitle), $sIconPath);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2056,8 +2023,7 @@ class DashletHeaderDynamic extends Dashlet
|
||||
$sIconPath = utils::HtmlEntities($oIconSelect->MakeFileUrl($sIcon));
|
||||
|
||||
$aValues = $this->GetValues();
|
||||
if (count($aValues) > 0)
|
||||
{
|
||||
if (count($aValues) > 0) {
|
||||
// Stats grouped by <group_by>
|
||||
$sCSV = implode(',', $aValues);
|
||||
$aParams = array(
|
||||
@@ -2067,9 +2033,7 @@ class DashletHeaderDynamic extends Dashlet
|
||||
'status_codes[block]' => $sCSV,
|
||||
'context_filter' => 1,
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
// Simple stats
|
||||
$aParams = array(
|
||||
'title[block]' => $sTitle,
|
||||
@@ -2078,31 +2042,29 @@ class DashletHeaderDynamic extends Dashlet
|
||||
);
|
||||
}
|
||||
|
||||
$oPage->add('<div class="dashlet-content">');
|
||||
$oPage->add('<div class="main_header">');
|
||||
$oPanel = PanelFactory::MakeEnhancedNeutral(Dict::S(str_replace('_', ':', $sTitle)), $sIconPath);
|
||||
|
||||
$oPage->add('<img src="'.$sIconPath.'">');
|
||||
|
||||
if (isset($aExtraParams['query_params']))
|
||||
{
|
||||
if (isset($aExtraParams['query_params'])) {
|
||||
$aQueryParams = $aExtraParams['query_params'];
|
||||
}
|
||||
elseif (isset($aExtraParams['this->class']))
|
||||
{
|
||||
} elseif (isset($aExtraParams['this->class'])) {
|
||||
$oObj = MetaModel::GetObject($aExtraParams['this->class'], $aExtraParams['this->id']);
|
||||
$aQueryParams = $oObj->ToArgsForQuery();
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
$aQueryParams = array();
|
||||
}
|
||||
$oFilter = DBObjectSearch::FromOQL($sQuery, $aQueryParams);
|
||||
$oBlock = new DisplayBlock($oFilter, 'summary');
|
||||
$sBlockId = 'block_'.$this->sId.($bEditMode ? '_edit' : ''); // make a unique id (edition occuring in the same DOM)
|
||||
$oBlock->Display($oPage, $sBlockId, array_merge($aExtraParams, $aParams));
|
||||
$oBlock->DisplayIntoContentBlock($oPanel, $oPage, $sBlockId, array_merge($aExtraParams, $aParams));
|
||||
|
||||
$oPage->add('</div>');
|
||||
$oPage->add('</div>');
|
||||
$oSubTitle = $oPanel->GetSubTitle();
|
||||
$oSet = new DBObjectSet($oFilter);
|
||||
$iCount = $oSet->Count();
|
||||
$oAppContext = new ApplicationContext();
|
||||
$sHyperlink = utils::GetAbsoluteUrlAppRoot().'pages/UI.php?operation=search&'.$oAppContext->GetForLink().'&filter='.rawurlencode($oFilter->serialize());
|
||||
$oSubTitle->AddHtml('<a class="summary" href="'.$sHyperlink.'">'.Dict::Format(str_replace('_', ':', $sSubtitle), $iCount).'</a>');
|
||||
|
||||
return $oPanel;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2122,46 +2084,48 @@ class DashletHeaderDynamic extends Dashlet
|
||||
$oIconSelect = $this->oModelReflection->GetIconSelectionField('icon');
|
||||
$sIconPath = utils::HtmlEntities($oIconSelect->MakeFileUrl($sIcon));
|
||||
|
||||
$oPage->add('<div class="dashlet-content">');
|
||||
$oPage->add('<div class="main_header">');
|
||||
$oDashletContainer = new DashletContainer(null, 'dashlet-content');
|
||||
|
||||
$oPage->add('<img src="'.$sIconPath.'">');
|
||||
$sHtml = '';
|
||||
$sHtml .= '<img src="'.$sIconPath.'">';
|
||||
|
||||
$sBlockId = 'block_fake_'.$this->sId.($bEditMode ? '_edit' : ''); // make a unique id (edition occuring in the same DOM)
|
||||
|
||||
$iTotal = 0;
|
||||
$aValues = $this->GetValues();
|
||||
|
||||
$oPage->add('<div class="display_block" id="'.$sBlockId.'">');
|
||||
$oPage->add('<div class="summary-details">');
|
||||
$oPage->add('<table><tbody>');
|
||||
$oPage->add('<tr>');
|
||||
foreach ($aValues as $sValue)
|
||||
{
|
||||
$sHtml .= '<div class="display_block" id="'.$sBlockId.'">';
|
||||
$sHtml .= '<div class="summary-details">';
|
||||
$sHtml .= '<table><tbody>';
|
||||
$sHtml .= '<tr>';
|
||||
foreach ($aValues as $sValue) {
|
||||
$sValueLabel = $this->oModelReflection->GetValueLabel($sClass, $sGroupBy, $sValue);
|
||||
$oPage->add(' <th>'.$sValueLabel.'</th>');
|
||||
$sHtml .= ' <th>'.$sValueLabel.'</th>';
|
||||
}
|
||||
$oPage->add('</tr>');
|
||||
$oPage->add('<tr>');
|
||||
foreach ($aValues as $sValue)
|
||||
{
|
||||
$iCount = (int) rand(2, 100);
|
||||
$sHtml .= '</tr>';
|
||||
$sHtml .= '<tr>';
|
||||
foreach ($aValues as $sValue) {
|
||||
$iCount = (int)rand(2, 100);
|
||||
$iTotal += $iCount;
|
||||
$oPage->add(' <td>'.$iCount.'</td>');
|
||||
$sHtml .= ' <td>'.$iCount.'</td>';
|
||||
}
|
||||
$oPage->add('</tr>');
|
||||
$oPage->add('</tbody></table>');
|
||||
$oPage->add('</div>');
|
||||
$sHtml .= '</tr>';
|
||||
$sHtml .= '</tbody></table>';
|
||||
$sHtml .= '</div>';
|
||||
|
||||
$sTitle = $this->oModelReflection->DictString($sTitle);
|
||||
$sSubtitle = $this->oModelReflection->DictFormat($sSubtitle, $iTotal);
|
||||
|
||||
$oPage->add('<h1>'.utils::HtmlEntities($sTitle).'</h1>');
|
||||
$oPage->add('<a class="summary">'.utils::HtmlEntities($sSubtitle).'</a>');
|
||||
$oPage->add('</div>');
|
||||
$sHtml .= '<h1>'.utils::HtmlEntities($sTitle).'</h1>';
|
||||
$sHtml .= '<a class="summary">'.utils::HtmlEntities($sSubtitle).'</a>';
|
||||
$sHtml .= '</div>';
|
||||
|
||||
$sHtml .= '</div>';
|
||||
|
||||
$oDashletContainer->AddHtml($sHtml);
|
||||
|
||||
return $oDashletContainer;
|
||||
|
||||
$oPage->add('</div>');
|
||||
$oPage->add('</div>');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2306,8 +2270,8 @@ class DashletBadge extends Dashlet
|
||||
{
|
||||
parent::__construct($oModelReflection, $sId);
|
||||
$this->aProperties['class'] = 'Contact';
|
||||
$this->aCSSClasses[] = 'dashlet-inline';
|
||||
$this->aCSSClasses[] = 'dashlet-badge';
|
||||
$this->aCSSClasses[] = 'ibo-dashlet--is-inline';
|
||||
$this->aCSSClasses[] = 'ibo-dashlet-badge';
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2317,17 +2281,16 @@ class DashletBadge extends Dashlet
|
||||
*/
|
||||
public function Render($oPage, $bEditMode = false, $aExtraParams = array())
|
||||
{
|
||||
$oDashletContainer = new DashletContainer($this->sId, 'dashlet-content');
|
||||
|
||||
$sClass = $this->aProperties['class'];
|
||||
|
||||
$oPage->add('<div class="dashlet-content">');
|
||||
|
||||
$oFilter = new DBObjectSearch($sClass);
|
||||
$oBlock = new DisplayBlock($oFilter, 'actions');
|
||||
$aExtraParams['context_filter'] = 1;
|
||||
$sBlockId = 'block_'.$this->sId.($bEditMode ? '_edit' : ''); // make a unique id (edition occurring in the same DOM)
|
||||
$oBlock->Display($oPage, $sBlockId, $aExtraParams);
|
||||
$oBlock->DisplayIntoContentBlock($oDashletContainer, $oPage, $sBlockId, $aExtraParams);
|
||||
|
||||
$oPage->add('</div>');
|
||||
return $oDashletContainer;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2335,25 +2298,25 @@ class DashletBadge extends Dashlet
|
||||
*/
|
||||
public function RenderNoData($oPage, $bEditMode = false, $aExtraParams = array())
|
||||
{
|
||||
$sClass = $this->aProperties['class'];
|
||||
$oDashletContainer = new DashletContainer($this->sId, 'dashlet-content');
|
||||
|
||||
$sClass = $this->aProperties['class'];
|
||||
$sIconUrl = $this->oModelReflection->GetClassIcon($sClass, false);
|
||||
$sClassLabel = $this->oModelReflection->GetName($sClass);
|
||||
|
||||
$oPage->add('<div class="dashlet-content">');
|
||||
$sHtml = '';
|
||||
$sHtml .= '<div id="block_fake_'.$this->sId.'" class="display_block">';
|
||||
$sHtml .= '<p>';
|
||||
$sHtml .= ' <a class="actions"><img src="'.utils::HtmlEntities($sIconUrl).'" style="vertical-align:middle;float;left;margin-right:10px;border:0;">'.$sClassLabel.': 947</a>';
|
||||
$sHtml .= '</p>';
|
||||
$sHtml .= '<p>';
|
||||
$sHtml .= ' <a>'.Dict::Format('UI:ClickToCreateNew', $sClassLabel).'</a>';
|
||||
$sHtml .= '</p>';
|
||||
$sHtml .= '</div>';
|
||||
|
||||
$oPage->add('<div id="block_fake_'.$this->sId.'" class="display_block">');
|
||||
$oPage->add('<p>');
|
||||
$oPage->add(' <a class="actions"><img src="'.utils::HtmlEntities($sIconUrl).'" style="vertical-align:middle;float;left;margin-right:10px;border:0;">'.$sClassLabel.': 947</a>');
|
||||
$oPage->add('</p>');
|
||||
$oPage->add('<p>');
|
||||
$oPage->add(' <a>'.Dict::Format('UI:ClickToCreateNew', $sClassLabel).'</a>');
|
||||
$oPage->add(' <br/>');
|
||||
$oPage->add(' <a>'.Dict::Format('UI:SearchFor_Class', $sClassLabel).'</a>');
|
||||
$oPage->add('</p>');
|
||||
$oPage->add('</div>');
|
||||
$oDashletContainer->AddHtml($sHtml);
|
||||
|
||||
$oPage->add('</div>');
|
||||
return $oDashletContainer;
|
||||
}
|
||||
|
||||
static protected $aClassList = null;
|
||||
|
||||
@@ -1,5 +1,46 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<itop_design xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="1.7">
|
||||
<itop_design xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="3.0">
|
||||
<classes>
|
||||
<class id="AbstractResource" _delta="define">
|
||||
<parent>cmdbAbstractObject</parent>
|
||||
<properties>
|
||||
<comment>/* Resource access control abstraction. Can be herited by abstract resource access control classes. Generaly controlled using UR_ACTION_MODIFY access right. */</comment>
|
||||
<abstract>true</abstract>
|
||||
</properties>
|
||||
<presentation/>
|
||||
<methods/>
|
||||
</class>
|
||||
<class id="ResourceAdminMenu" _delta="define">
|
||||
<parent>AbstractResource</parent>
|
||||
<properties>
|
||||
<comment>/* AdminTools menu access control. */</comment>
|
||||
<abstract>true</abstract>
|
||||
<category>grant_by_profile</category>
|
||||
</properties>
|
||||
<presentation/>
|
||||
<methods/>
|
||||
</class>
|
||||
<class id="ResourceRunQueriesMenu" _delta="define">
|
||||
<parent>AbstractResource</parent>
|
||||
<properties>
|
||||
<comment>/* RunQueriesMenu menu access control. */</comment>
|
||||
<abstract>true</abstract>
|
||||
<category>grant_by_profile</category>
|
||||
</properties>
|
||||
<presentation/>
|
||||
<methods/>
|
||||
</class>
|
||||
<class id="ResourceSystemMenu" _delta="define">
|
||||
<parent>AbstractResource</parent>
|
||||
<properties>
|
||||
<comment>/* System menu access control. */</comment>
|
||||
<abstract>true</abstract>
|
||||
<category>grant_by_profile</category>
|
||||
</properties>
|
||||
<presentation/>
|
||||
<methods/>
|
||||
</class>
|
||||
</classes>
|
||||
<portals>
|
||||
<portal id="backoffice" _delta="define">
|
||||
<url>pages/UI.php</url>
|
||||
@@ -12,13 +53,351 @@
|
||||
</portal>
|
||||
</portals>
|
||||
<menus>
|
||||
<menu id="WelcomeMenu" xsi:type="MenuGroup" _delta="define">
|
||||
<rank>10</rank>
|
||||
<style>
|
||||
<decoration_classes>fas fa-home</decoration_classes>
|
||||
</style>
|
||||
</menu>
|
||||
<menu id="WelcomeMenuPage" xsi:type="DashboardMenuNode" _delta="define">
|
||||
<rank>10</rank>
|
||||
<parent>WelcomeMenu</parent>
|
||||
<definition>
|
||||
<layout>DashboardLayoutOneCol</layout>
|
||||
<title/>
|
||||
<cells>
|
||||
<cell id="0">
|
||||
<rank>0</rank>
|
||||
<dashlets>
|
||||
</dashlets>
|
||||
</cell>
|
||||
</cells>
|
||||
</definition>
|
||||
</menu>
|
||||
<menu id="MyShortcuts" xsi:type="ShortcutContainerMenuNode" _delta="define">
|
||||
<rank>20</rank>
|
||||
<parent>WelcomeMenu</parent>
|
||||
</menu>
|
||||
<menu id="UserManagement" xsi:type="TemplateMenuNode" _delta="define">
|
||||
<rank>10</rank>
|
||||
<parent>AdminTools</parent>
|
||||
<template_file/>
|
||||
</menu>
|
||||
<menu id="UserAccountsMenu" xsi:type="OQLMenuNode" _delta="define">
|
||||
<rank>11</rank>
|
||||
<parent>UserManagement</parent>
|
||||
<oql><![CDATA[SELECT User]]></oql>
|
||||
<do_search>1</do_search>
|
||||
<search_form_open>1</search_form_open>
|
||||
<enable_class>User</enable_class>
|
||||
<enable_action>UR_ACTION_MODIFY</enable_action>
|
||||
</menu>
|
||||
<menu id="ProfilesMenu" xsi:type="OQLMenuNode" _delta="define">
|
||||
<rank>12</rank>
|
||||
<parent>UserManagement</parent>
|
||||
<oql><![CDATA[SELECT URP_Profiles]]></oql>
|
||||
<do_search>1</do_search>
|
||||
<enable_class>URP_Profiles</enable_class>
|
||||
<enable_action>UR_ACTION_MODIFY</enable_action>
|
||||
</menu>
|
||||
<menu id="AuditCategories" xsi:type="OQLMenuNode" _delta="define">
|
||||
<rank>20</rank>
|
||||
<parent>AdminTools</parent>
|
||||
<oql><![CDATA[SELECT AuditCategory]]></oql>
|
||||
<do_search>1</do_search>
|
||||
<enable_class>AuditCategory</enable_class>
|
||||
<enable_action>UR_ACTION_MODIFY</enable_action>
|
||||
</menu>
|
||||
<menu id="Queries" xsi:type="TemplateMenuNode" _delta="define">
|
||||
<rank>30</rank>
|
||||
<parent>AdminTools</parent>
|
||||
<template_file/>
|
||||
</menu>
|
||||
<menu id="RunQueriesMenu" xsi:type="WebPageMenuNode" _delta="define">
|
||||
<rank>31</rank>
|
||||
<parent>Queries</parent>
|
||||
<url>$pages/run_query.php</url>
|
||||
<enable_class>ResourceRunQueriesMenu</enable_class>
|
||||
<enable_action>UR_ACTION_MODIFY</enable_action>
|
||||
</menu>
|
||||
<menu id="QueryMenu" xsi:type="OQLMenuNode" _delta="define">
|
||||
<rank>32</rank>
|
||||
<parent>Queries</parent>
|
||||
<oql><![CDATA[SELECT Query]]></oql>
|
||||
<do_search>1</do_search>
|
||||
<enable_class>Query</enable_class>
|
||||
<enable_action>UR_ACTION_MODIFY</enable_action>
|
||||
</menu>
|
||||
<menu id="ExportMenu" xsi:type="WebPageMenuNode" _delta="define">
|
||||
<rank>33</rank>
|
||||
<parent>Queries</parent>
|
||||
<url>$webservices/export-v2.php?interactive=1</url>
|
||||
<enable_class>ResourceAdminMenu</enable_class>
|
||||
<enable_action>UR_ACTION_MODIFY</enable_action>
|
||||
</menu>
|
||||
<menu id="DataModelMenu" xsi:type="WebPageMenuNode" _delta="define">
|
||||
<rank>40</rank>
|
||||
<parent>AdminTools</parent>
|
||||
<url>$pages/schema.php</url>
|
||||
<enable_class>ResourceRunQueriesMenu</enable_class>
|
||||
<enable_action>UR_ACTION_MODIFY</enable_action>
|
||||
</menu>
|
||||
<menu id="UniversalSearchMenu" xsi:type="WebPageMenuNode" _delta="define">
|
||||
<rank>35</rank>
|
||||
<parent>Queries</parent>
|
||||
<url>$pages/UniversalSearch.php</url>
|
||||
<enable_class>ResourceAdminMenu</enable_class>
|
||||
<enable_action>UR_ACTION_MODIFY</enable_action>
|
||||
</menu>
|
||||
<menu id="ConfigurationTools" xsi:type="MenuGroup" _delta="define_if_not_exists">
|
||||
<rank>90</rank>
|
||||
<style>
|
||||
<decoration_classes>fas fa-cog</decoration_classes>
|
||||
</style>
|
||||
</menu>
|
||||
<menu id="DataSources" xsi:type="OQLMenuNode" _delta="define">
|
||||
<rank>20</rank>
|
||||
<parent>ConfigurationTools</parent>
|
||||
<oql><![CDATA[SELECT SynchroDataSource]]></oql>
|
||||
<do_search>1</do_search>
|
||||
<enable_class>SynchroDataSource</enable_class>
|
||||
<enable_action>UR_ACTION_MODIFY</enable_action>
|
||||
</menu>
|
||||
<menu id="NotificationsMenu" xsi:type="WebPageMenuNode" _delta="define">
|
||||
<rank>40</rank>
|
||||
<parent>ConfigurationTools</parent>
|
||||
<url>$pages/notifications.php</url>
|
||||
<enable_class>Trigger</enable_class>
|
||||
<enable_action>UR_ACTION_MODIFY</enable_action>
|
||||
</menu>
|
||||
<menu id="AdminTools" xsi:type="MenuGroup" _delta="define">
|
||||
<rank>80</rank>
|
||||
<style>
|
||||
<decoration_classes>fas fa-tools</decoration_classes>
|
||||
</style>
|
||||
</menu>
|
||||
<menu id="SystemTools" xsi:type="MenuGroup" _delta="define">
|
||||
<rank>100</rank>
|
||||
<enable_class>ResourceSystemMenu</enable_class>
|
||||
<enable_action>UR_ACTION_MODIFY</enable_action>
|
||||
<style>
|
||||
<decoration_classes>fas fa-terminal</decoration_classes>
|
||||
</style>
|
||||
</menu>
|
||||
</menus>
|
||||
<meta>
|
||||
<classes>
|
||||
<class id="cmdbAbstractObject" _delta="define">
|
||||
<methods>
|
||||
<method id="Set">
|
||||
<arguments>
|
||||
<argument id="1">
|
||||
<type>attcode</type>
|
||||
<mandatory>true</mandatory>
|
||||
<type_restrictions>
|
||||
<operation>deny</operation>
|
||||
<types>
|
||||
<type id="AttributeStopWatch"/>
|
||||
<type id="AttributeSubItem"/>
|
||||
<type id="AttributeExternalField"/>
|
||||
<type id="AttributeLinkedSetIndirect"/>
|
||||
<type id="AttributeLinkedSet"/>
|
||||
<type id="AttributeImage"/>
|
||||
<type id="AttributeBlob"/>
|
||||
</types>
|
||||
</type_restrictions>
|
||||
</argument>
|
||||
<argument id="2">
|
||||
<type>string</type>
|
||||
<mandatory>true</mandatory>
|
||||
</argument>
|
||||
</arguments>
|
||||
</method>
|
||||
<method id="SetIfNull">
|
||||
<arguments>
|
||||
<argument id="1">
|
||||
<type>attcode</type>
|
||||
<mandatory>true</mandatory>
|
||||
<type_restrictions>
|
||||
<operation>deny</operation>
|
||||
<types>
|
||||
<type id="AttributeStopWatch"/>
|
||||
<type id="AttributeSubItem"/>
|
||||
<type id="AttributeExternalField"/>
|
||||
<type id="AttributeLinkedSetIndirect"/>
|
||||
<type id="AttributeLinkedSet"/>
|
||||
<type id="AttributeImage"/>
|
||||
<type id="AttributeBlob"/>
|
||||
</types>
|
||||
</type_restrictions>
|
||||
</argument>
|
||||
<argument id="2">
|
||||
<type>string</type>
|
||||
<mandatory>true</mandatory>
|
||||
</argument>
|
||||
</arguments>
|
||||
</method>
|
||||
<method id="SetCurrentDate">
|
||||
<arguments>
|
||||
<argument id="1">
|
||||
<type>attcode</type>
|
||||
<mandatory>true</mandatory>
|
||||
<type_restrictions>
|
||||
<operation>allow</operation>
|
||||
<types>
|
||||
<type id="AttributeDate"/>
|
||||
<type id="AttributeDateTime"/>
|
||||
<type id="AttributeString"/>
|
||||
</types>
|
||||
</type_restrictions>
|
||||
</argument>
|
||||
</arguments>
|
||||
</method>
|
||||
<method id="SetCurrentUser">
|
||||
<arguments>
|
||||
<argument id="1">
|
||||
<type>attcode</type>
|
||||
<mandatory>true</mandatory>
|
||||
<type_restrictions>
|
||||
<operation>allow</operation>
|
||||
<types>
|
||||
<type id="AttributeExternalKey"/>
|
||||
<type id="AttributeInteger"/>
|
||||
<type id="AttributeString"/>
|
||||
</types>
|
||||
</type_restrictions>
|
||||
</argument>
|
||||
</arguments>
|
||||
</method>
|
||||
<method id="SetCurrentPerson">
|
||||
<arguments>
|
||||
<argument id="1">
|
||||
<type>attcode</type>
|
||||
<mandatory>true</mandatory>
|
||||
<type_restrictions>
|
||||
<operation>allow</operation>
|
||||
<types>
|
||||
<type id="AttributeExternalKey"/>
|
||||
<type id="AttributeInteger"/>
|
||||
<type id="AttributeString"/>
|
||||
</types>
|
||||
</type_restrictions>
|
||||
</argument>
|
||||
</arguments>
|
||||
</method>
|
||||
<method id="SetElapsedTime">
|
||||
<arguments>
|
||||
<argument id="1">
|
||||
<type>attcode</type>
|
||||
<mandatory>true</mandatory>
|
||||
<type_restrictions>
|
||||
<operation>allow</operation>
|
||||
<types>
|
||||
<type id="AttributeDuration"/>
|
||||
</types>
|
||||
</type_restrictions>
|
||||
</argument>
|
||||
<argument id="2">
|
||||
<type>attcode</type>
|
||||
<mandatory>true</mandatory>
|
||||
<type_restrictions>
|
||||
<operation>allow</operation>
|
||||
<types>
|
||||
<type id="AttributeDate"/>
|
||||
<type id="AttributeDateTime"/>
|
||||
</types>
|
||||
</type_restrictions>
|
||||
</argument>
|
||||
<argument id="3">
|
||||
<type>string</type>
|
||||
<mandatory>false</mandatory>
|
||||
</argument>
|
||||
</arguments>
|
||||
</method>
|
||||
<method id="Reset">
|
||||
<arguments>
|
||||
<argument id="1">
|
||||
<type>attcode</type>
|
||||
<mandatory>true</mandatory>
|
||||
<type_restrictions>
|
||||
<operation>deny</operation>
|
||||
<types>
|
||||
<type id="AttributeStopWatch"/>
|
||||
<type id="AttributeSubItem"/>
|
||||
<type id="AttributeExternalField"/>
|
||||
</types>
|
||||
</type_restrictions>
|
||||
</argument>
|
||||
</arguments>
|
||||
</method>
|
||||
<method id="ResetStopWatch">
|
||||
<arguments>
|
||||
<argument id="1">
|
||||
<type>attcode</type>
|
||||
<mandatory>true</mandatory>
|
||||
<type_restrictions>
|
||||
<operation>allow</operation>
|
||||
<types>
|
||||
<type id="AttributeStopWatch"/>
|
||||
</types>
|
||||
</type_restrictions>
|
||||
</argument>
|
||||
</arguments>
|
||||
</method>
|
||||
<method id="Copy">
|
||||
<arguments>
|
||||
<argument id="1">
|
||||
<type>attcode</type>
|
||||
<mandatory>true</mandatory>
|
||||
<type_restrictions>
|
||||
<operation>deny</operation>
|
||||
<types>
|
||||
<type id="AttributeStopWatch"/>
|
||||
<type id="AttributeSubItem"/>
|
||||
<type id="AttributeExternalField"/>
|
||||
</types>
|
||||
</type_restrictions>
|
||||
</argument>
|
||||
<argument id="2">
|
||||
<type>attcode</type>
|
||||
<mandatory>true</mandatory>
|
||||
</argument>
|
||||
</arguments>
|
||||
</method>
|
||||
<method id="ApplyStimulus">
|
||||
<arguments>
|
||||
<argument id="1">
|
||||
<type>string</type>
|
||||
<mandatory>true</mandatory>
|
||||
</argument>
|
||||
</arguments>
|
||||
</method>
|
||||
<method id="PrefillCreationForm">
|
||||
<arguments>
|
||||
<argument id="1">
|
||||
<type>reference</type>
|
||||
<mandatory>true</mandatory>
|
||||
</argument>
|
||||
</arguments>
|
||||
</method>
|
||||
<method id="PrefillTransitionForm">
|
||||
<arguments>
|
||||
<argument id="1">
|
||||
<type>reference</type>
|
||||
<mandatory>true</mandatory>
|
||||
</argument>
|
||||
</arguments>
|
||||
</method>
|
||||
<method id="PrefillSearchForm">
|
||||
<arguments>
|
||||
<argument id="1">
|
||||
<type>reference</type>
|
||||
<mandatory>true</mandatory>
|
||||
</argument>
|
||||
</arguments>
|
||||
</method>
|
||||
</methods>
|
||||
</class>
|
||||
</classes>
|
||||
</meta>
|
||||
</itop_design>
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
<?php
|
||||
|
||||
use Combodo\iTop\Renderer\BlockRenderer;
|
||||
|
||||
/**
|
||||
* Copyright (C) 2013-2020 Combodo SARL
|
||||
*
|
||||
@@ -25,7 +28,7 @@ class DataTable
|
||||
protected $sTableId; // identifier for saving the settings (combined with the class aliases)
|
||||
protected $oSet; // The set of objects to display
|
||||
protected $aClassAliases; // The aliases (alias => class) inside the set
|
||||
protected $iNbObjects; // Total number of objects inthe set
|
||||
protected $iNbObjects; // Total number of objects in the set
|
||||
protected $bUseCustomSettings; // Whether or not the current display uses custom settings
|
||||
protected $oDefaultSettings; // the default settings for displaying such a list
|
||||
protected $bShowObsoleteData;
|
||||
@@ -157,17 +160,17 @@ class DataTable
|
||||
$sPager = $this->GetPager($oPage, $iPageSize, $iDefaultPageSize, $iPageIndex);
|
||||
$sActionsMenu = '';
|
||||
$sToolkitMenu = '';
|
||||
if ($bActionsMenu)
|
||||
{
|
||||
if ($bActionsMenu) {
|
||||
$sActionsMenu = $this->GetActionsMenu($oPage, $aExtraParams);
|
||||
}
|
||||
if ($bToolkitMenu)
|
||||
{
|
||||
$sToolkitMenu = $this->GetToolkitMenu($oPage, $aExtraParams);
|
||||
}
|
||||
// if ($bToolkitMenu)
|
||||
// {
|
||||
// $sToolkitMenu = $this->GetToolkitMenu($oPage, $aExtraParams);
|
||||
// }
|
||||
|
||||
$sDataTable = $this->GetHTMLTable($oPage, $aColumns, $sSelectMode, $iPageSize, $bViewLink, $aExtraParams);
|
||||
$sConfigDlg = $this->GetTableConfigDlg($oPage, $aColumns, $bViewLink, $iDefaultPageSize);
|
||||
|
||||
|
||||
$sHtml = "<table id=\"{$this->sDatatableContainerId}\" class=\"datatable\">";
|
||||
$sHtml .= "<tr><td>";
|
||||
$sHtml .= "<table style=\"width:100%;\">";
|
||||
@@ -208,7 +211,7 @@ class DataTable
|
||||
|
||||
return $sHtml;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* When refreshing the body of a paginated table, get the rows of the table (inside the TBODY)
|
||||
* return string The HTML rows to insert inside the <tbody> node
|
||||
@@ -355,9 +358,18 @@ EOF;
|
||||
protected function GetActionsMenu(WebPage $oPage, $aExtraParams)
|
||||
{
|
||||
$oMenuBlock = new MenuBlock($this->oSet->GetFilter(), 'list');
|
||||
|
||||
$sHtml = $oMenuBlock->GetRenderContent($oPage, $aExtraParams, $this->iListId);
|
||||
return $sHtml;
|
||||
|
||||
$oBlock = $oMenuBlock->GetRenderContent($oPage, $aExtraParams, $this->iListId);
|
||||
foreach ($oBlock->GetCssFilesUrlRecursively(true) as $sFileAbsUrl) {
|
||||
$oPage->add_linked_stylesheet($sFileAbsUrl);
|
||||
}
|
||||
// JS files
|
||||
foreach ($oBlock->GetJsFilesUrlRecursively(true) as $sFileAbsUrl) {
|
||||
$oPage->add_linked_script($sFileAbsUrl);
|
||||
}
|
||||
|
||||
$oPage->RenderInlineScriptsAndCSSRecursively($oBlock);
|
||||
return BlockRenderer::RenderBlockTemplates($oBlock);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -513,6 +525,7 @@ EOF;
|
||||
return $aAttribs;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $aColumns
|
||||
* @param $sSelectMode
|
||||
@@ -860,396 +873,3 @@ class PrintableDataTable extends DataTable
|
||||
return $sHtml;
|
||||
}
|
||||
}
|
||||
|
||||
class DataTableSettings implements Serializable
|
||||
{
|
||||
public $aClassAliases;
|
||||
public $sTableId;
|
||||
public $iDefaultPageSize;
|
||||
public $aColumns;
|
||||
|
||||
|
||||
/**
|
||||
* DataTableSettings constructor.
|
||||
*
|
||||
* @param $aClassAliases
|
||||
* @param null $sTableId
|
||||
*/
|
||||
public function __construct($aClassAliases, $sTableId = null)
|
||||
{
|
||||
$this->aClassAliases = $aClassAliases;
|
||||
$this->sTableId = $sTableId;
|
||||
$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
|
||||
$aColumns = array();
|
||||
foreach($this->aClassAliases as $sAlias => $sClass)
|
||||
{
|
||||
$aColumns[$sAlias] = array();
|
||||
foreach($this->aColumns[$sAlias] as $sAttCode => $aData)
|
||||
{
|
||||
unset($aData['label']); // Don't save the display name
|
||||
unset($aData['alias']); // Don't save the alias (redundant)
|
||||
unset($aData['code']); // Don't save the code (redundant)
|
||||
if ($aData['checked'])
|
||||
{
|
||||
$aColumns[$sAlias][$sAttCode] = $aData;
|
||||
}
|
||||
}
|
||||
}
|
||||
return serialize(
|
||||
array(
|
||||
'iDefaultPageSize' => $this->iDefaultPageSize,
|
||||
'aColumns' => $aColumns,
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $sData
|
||||
*
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function unserialize($sData)
|
||||
{
|
||||
$aData = unserialize($sData);
|
||||
$this->iDefaultPageSize = $aData['iDefaultPageSize'];
|
||||
$this->aColumns = $aData['aColumns'];
|
||||
foreach($this->aClassAliases as $sAlias => $sClass)
|
||||
{
|
||||
foreach($this->aColumns[$sAlias] as $sAttCode => $aData)
|
||||
{
|
||||
$aFieldData = false;
|
||||
if ($sAttCode == '_key_')
|
||||
{
|
||||
$aFieldData = $this->GetFieldData($sAlias, $sAttCode, null, true /* bChecked */, $aData['sort']);
|
||||
}
|
||||
else if (MetaModel::isValidAttCode($sClass, $sAttCode))
|
||||
{
|
||||
$oAttDef = MetaModel::GetAttributeDef($sClass, $sAttCode);
|
||||
$aFieldData = $this->GetFieldData($sAlias, $sAttCode, $oAttDef, true /* bChecked */, $aData['sort']);
|
||||
}
|
||||
|
||||
if ($aFieldData)
|
||||
{
|
||||
$this->aColumns[$sAlias][$sAttCode] = $aFieldData;
|
||||
}
|
||||
else
|
||||
{
|
||||
unset($this->aColumns[$sAlias][$sAttCode]);
|
||||
}
|
||||
}
|
||||
}
|
||||
$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);
|
||||
// Retrieve the class specific settings for each class/alias based on the 'list' ZList
|
||||
//TODO let the caller pass some other default settings (another Zlist, extre fields...)
|
||||
$aColumns = array();
|
||||
foreach($aClassAliases as $sAlias => $sClass)
|
||||
{
|
||||
if ($aDefaultLists == null)
|
||||
{
|
||||
$aList = cmdbAbstract::FlattenZList(MetaModel::GetZListItems($sClass, 'list'));
|
||||
}
|
||||
else
|
||||
{
|
||||
$aList = $aDefaultLists[$sAlias];
|
||||
}
|
||||
|
||||
$aSortOrder = MetaModel::GetOrderByDefault($sClass);
|
||||
if ($bViewLink)
|
||||
{
|
||||
$sSort = 'none';
|
||||
if(array_key_exists('friendlyname', $aSortOrder))
|
||||
{
|
||||
$sSort = $aSortOrder['friendlyname'] ? 'asc' : 'desc';
|
||||
}
|
||||
$sNormalizedFName = MetaModel::NormalizeFieldSpec($sClass, 'friendlyname');
|
||||
if(array_key_exists($sNormalizedFName, $aSortOrder))
|
||||
{
|
||||
$sSort = $aSortOrder[$sNormalizedFName] ? 'asc' : 'desc';
|
||||
}
|
||||
|
||||
$aColumns[$sAlias]['_key_'] = $oSettings->GetFieldData($sAlias, '_key_', null, true /* bChecked */, $sSort);
|
||||
}
|
||||
foreach($aList as $sAttCode)
|
||||
{
|
||||
$sSort = 'none';
|
||||
if(array_key_exists($sAttCode, $aSortOrder))
|
||||
{
|
||||
$sSort = $aSortOrder[$sAttCode] ? 'asc' : 'desc';
|
||||
}
|
||||
$oAttDef = Metamodel::GetAttributeDef($sClass, $sAttCode);
|
||||
$aFieldData = $oSettings->GetFieldData($sAlias, $sAttCode, $oAttDef, true /* bChecked */, $sSort);
|
||||
if ($aFieldData) $aColumns[$sAlias][$sAttCode] = $aFieldData;
|
||||
}
|
||||
}
|
||||
$iDefaultPageSize = appUserPreferences::GetPref('default_page_size', MetaModel::GetConfig()->GetMinDisplayLimit());
|
||||
$oSettings->Init($iDefaultPageSize, $aSortOrder, $aColumns);
|
||||
return $oSettings;
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws \CoreException
|
||||
*/
|
||||
protected function FixVisibleColumns()
|
||||
{
|
||||
foreach($this->aClassAliases as $sAlias => $sClass)
|
||||
{
|
||||
if (!isset($this->aColumns[$sAlias]))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
foreach($this->aColumns[$sAlias] as $sAttCode => $aData)
|
||||
{
|
||||
// Remove non-existent columns
|
||||
// TODO: check if the existing ones are still valid (in case their type changed)
|
||||
if (($sAttCode != '_key_') && (!MetaModel::IsValidAttCode($sClass, $sAttCode)))
|
||||
{
|
||||
unset($this->aColumns[$sAlias][$sAttCode]);
|
||||
}
|
||||
}
|
||||
$aList = MetaModel::ListAttributeDefs($sClass);
|
||||
|
||||
// Add the other (non visible ones), sorted in alphabetical order
|
||||
$aTempData = array();
|
||||
foreach($aList as $sAttCode => $oAttDef)
|
||||
{
|
||||
if ( (!array_key_exists($sAttCode, $this->aColumns[$sAlias])) && (!($oAttDef instanceof AttributeLinkedSet || $oAttDef instanceof AttributeDashboard)))
|
||||
{
|
||||
$aFieldData = $this->GetFieldData($sAlias, $sAttCode, $oAttDef, false /* bChecked */, 'none');
|
||||
if ($aFieldData) $aTempData[$aFieldData['label']] = $aFieldData;
|
||||
}
|
||||
}
|
||||
ksort($aTempData);
|
||||
foreach($aTempData as $sLabel => $aFieldData)
|
||||
{
|
||||
$this->aColumns[$sAlias][$aFieldData['code']] = $aFieldData;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $aClassAliases
|
||||
* @param null $sTableId
|
||||
* @param bool $bOnlyOnTable
|
||||
*
|
||||
* @return \DataTableSettings|null
|
||||
* @throws \Exception
|
||||
*/
|
||||
static public function GetTableSettings($aClassAliases, $sTableId = null, $bOnlyOnTable = false)
|
||||
{
|
||||
$pref = null;
|
||||
$oSettings = new DataTableSettings($aClassAliases, $sTableId);
|
||||
|
||||
if ($sTableId != null)
|
||||
{
|
||||
// An identified table, let's fetch its own settings (if any)
|
||||
$pref = appUserPreferences::GetPref($oSettings->GetPrefsKey($sTableId), null);
|
||||
}
|
||||
|
||||
if ($pref == null)
|
||||
{
|
||||
if (!$bOnlyOnTable)
|
||||
{
|
||||
// Try the global preferred values for this class / set of classes
|
||||
$pref = appUserPreferences::GetPref($oSettings->GetPrefsKey(null), null);
|
||||
}
|
||||
if ($pref == null)
|
||||
{
|
||||
// no such settings, use the default values provided by the data model
|
||||
return null;
|
||||
}
|
||||
}
|
||||
$oSettings->unserialize($pref);
|
||||
|
||||
return $oSettings;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function GetSortOrder()
|
||||
{
|
||||
$aSortOrder = array();
|
||||
foreach($this->aColumns as $sAlias => $aColumns)
|
||||
{
|
||||
foreach($aColumns as $aColumn)
|
||||
{
|
||||
if ($aColumn['sort'] != 'none')
|
||||
{
|
||||
$sCode = ($aColumn['code'] == '_key_') ? 'friendlyname' : $aColumn['code'];
|
||||
$aSortOrder[$sCode] = ($aColumn['sort']=='asc'); // true for ascending, false for descending
|
||||
}
|
||||
}
|
||||
break; // TODO: For now the Set object supports only sorting on the first class of the set
|
||||
}
|
||||
return $aSortOrder;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param null $sTargetTableId
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function Save($sTargetTableId = null)
|
||||
{
|
||||
$sSaveId = is_null($sTargetTableId) ? $this->sTableId : $sTargetTableId;
|
||||
if ($sSaveId == null) return false; // Cannot save, the table is not identified, use SaveAsDefault instead
|
||||
|
||||
$sSettings = $this->serialize();
|
||||
appUserPreferences::SetPref($this->GetPrefsKey($sSaveId), $sSettings);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function SaveAsDefault()
|
||||
{
|
||||
$sSettings = $this->serialize();
|
||||
appUserPreferences::SetPref($this->GetPrefsKey(null), $sSettings);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Clear the preferences for this particular table
|
||||
* @param $bResetAll boolean If true,the settings for all tables of the same class(es)/alias(es) are reset
|
||||
*/
|
||||
public function ResetToDefault($bResetAll)
|
||||
{
|
||||
if (($this->sTableId == null) && (!$bResetAll)) return false; // Cannot reset, the table is not identified, use force $bResetAll instead
|
||||
if ($bResetAll)
|
||||
{
|
||||
// Turn the key into a suitable PCRE pattern
|
||||
$sKey = $this->GetPrefsKey(null);
|
||||
$sPattern = str_replace(array('|'), array('\\|'), $sKey); // escape the | character
|
||||
$sPattern = '#^'.str_replace(array('*'), array('.*'), $sPattern).'$#'; // Don't use slash as the delimiter since it's used in our key to delimit aliases
|
||||
appUserPreferences::UnsetPref($sPattern, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
appUserPreferences::UnsetPref($this->GetPrefsKey($this->sTableId), false);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param null $sTableId
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function GetPrefsKey($sTableId = null)
|
||||
{
|
||||
return static::GetAppUserPreferenceKey($this->aClassAliases, $sTableId);
|
||||
}
|
||||
|
||||
public static function GetAppUserPreferenceKey($aClassAliases, $sTableId)
|
||||
{
|
||||
if ($sTableId === null)
|
||||
{
|
||||
$sTableId = '*';
|
||||
}
|
||||
|
||||
$aKeys = array();
|
||||
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;
|
||||
if ($sAttCode == '_key_')
|
||||
{
|
||||
$sLabel = Dict::Format('UI:ExtKey_AsLink', MetaModel::GetName($this->aClassAliases[$sAlias]));
|
||||
$ret = array(
|
||||
'label' => $sLabel,
|
||||
'checked' => true,
|
||||
'disabled' => true,
|
||||
'alias' => $sAlias,
|
||||
'code' => $sAttCode,
|
||||
'sort' => $sSort,
|
||||
);
|
||||
}
|
||||
else if (!$oAttDef->IsLinkSet())
|
||||
{
|
||||
$sLabel = $oAttDef->GetLabel();
|
||||
if ($oAttDef->IsExternalKey())
|
||||
{
|
||||
$sLabel = Dict::Format('UI:ExtKey_AsLink', $oAttDef->GetLabel());
|
||||
}
|
||||
else if ($oAttDef->IsExternalField())
|
||||
{
|
||||
if ($oAttDef->IsFriendlyName())
|
||||
{
|
||||
$sLabel = Dict::Format('UI:ExtKey_AsFriendlyName', $oAttDef->GetLabel());
|
||||
}
|
||||
else
|
||||
{
|
||||
$oExtAttDef = $oAttDef->GetExtAttDef();
|
||||
$sLabel = Dict::Format('UI:ExtField_AsRemoteField', $oAttDef->GetLabel(), $oExtAttDef->GetLabel());
|
||||
}
|
||||
}
|
||||
elseif ($oAttDef instanceof AttributeFriendlyName)
|
||||
{
|
||||
$sLabel = Dict::Format('UI:ExtKey_AsFriendlyName', $oAttDef->GetLabel());
|
||||
}
|
||||
$ret = array(
|
||||
'label' => $sLabel,
|
||||
'checked' => $bChecked,
|
||||
'disabled' => false,
|
||||
'alias' => $sAlias,
|
||||
'code' => $sAttCode,
|
||||
'sort' => $sSort,
|
||||
);
|
||||
}
|
||||
return $ret;
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,82 +1,7 @@
|
||||
<?php
|
||||
/**
|
||||
* @copyright Copyright (C) 2010-2020 Combodo SARL
|
||||
* @deprecated will be removed in 3.1.0 - moved to sources/application/WebPage/ErrorPage.php
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
* @copyright Copyright (C) 2010-2020 Combodo SARL
|
||||
*/
|
||||
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -44,7 +44,6 @@ class InputOutputTask extends cmdbAbstractObject
|
||||
"db_table" => "priv_iotask",
|
||||
"db_key_field" => "id",
|
||||
"db_finalclass_field" => "",
|
||||
"display_template" => "",
|
||||
);
|
||||
MetaModel::Init_Params($aParams);
|
||||
MetaModel::Init_AddAttribute(new AttributeString("name", array("allowed_values"=>null, "sql"=>"name", "default_value"=>"", "is_null_allowed"=>false, "depends_on"=>array())));
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,57 +1,7 @@
|
||||
<?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/>
|
||||
|
||||
|
||||
/**
|
||||
* Class iTopWizardWebPage
|
||||
*
|
||||
* @copyright Copyright (C) 2010-2012 Combodo SARL
|
||||
* @deprecated will be removed in 3.1.0 - moved to sources/application/WebPage/iTopWizardWebPage.php
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
* @copyright Copyright (C) 2010-2020 Combodo SARL
|
||||
*/
|
||||
|
||||
require_once('itopwebpage.class.inc.php');
|
||||
/**
|
||||
* Web page to display a wizard in the iTop framework
|
||||
*/
|
||||
class iTopWizardWebPage extends iTopWebPage
|
||||
{
|
||||
var $m_iCurrentStep;
|
||||
var $m_aSteps;
|
||||
public function __construct($sTitle, $currentOrganization, $iCurrentStep, $aSteps)
|
||||
{
|
||||
parent::__construct($sTitle." - step $iCurrentStep of ".count($aSteps)." - ".$aSteps[$iCurrentStep - 1], $currentOrganization);
|
||||
$this->m_iCurrentStep = $iCurrentStep;
|
||||
$this->m_aSteps = $aSteps;
|
||||
}
|
||||
|
||||
public function output()
|
||||
{
|
||||
$aSteps = array();
|
||||
$iIndex = 0;
|
||||
foreach($this->m_aSteps as $sStepTitle)
|
||||
{
|
||||
$iIndex++;
|
||||
$sStyle = ($iIndex == $this->m_iCurrentStep) ? 'wizActiveStep' : 'wizStep';
|
||||
$aSteps[] = "<div class=\"$sStyle\"><span>$sStepTitle</span></div>";
|
||||
}
|
||||
$sWizardHeader = "<div class=\"wizHeader\"><h1>".htmlentities($this->s_title, ENT_QUOTES, 'UTF-8')."</h1>\n".implode("<div class=\"wizSeparator\"><img align=\"bottom\" src=\"../images/wizArrow.gif\"></div>", $aSteps)."<br style=\"clear:both;\"/></div>\n";
|
||||
$this->s_content = "$sWizardHeader<div class=\"wizContainer\">".$this->s_content."</div>";
|
||||
parent::output();
|
||||
}
|
||||
}
|
||||
?>
|
||||
|
||||
|
||||
@@ -224,7 +224,7 @@ class LoginTwigRenderer
|
||||
}
|
||||
|
||||
$oCoreLoader = new Twig_Loader_Filesystem(array(), APPROOT.'templates');
|
||||
$aCoreTemplatesPaths = array('login', 'login/password');
|
||||
$aCoreTemplatesPaths = array('pages/login', 'pages/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
|
||||
|
||||
@@ -94,7 +94,6 @@ class LoginWebPage extends NiceWebPage
|
||||
{
|
||||
$this->add_linked_stylesheet(utils::GetAbsoluteUrlAppRoot().'css/login.css');
|
||||
$this->add_linked_stylesheet(utils::GetAbsoluteUrlAppRoot().'css/font-awesome/css/all.min.css');
|
||||
$this->add_linked_stylesheet(utils::GetAbsoluteUrlAppRoot().'css/font-awesome/css/v4-shims.min.css');
|
||||
}
|
||||
|
||||
public static function SetLoginFailedMessage($sMessage)
|
||||
@@ -102,6 +101,44 @@ class LoginWebPage extends NiceWebPage
|
||||
self::$m_sLoginFailedMessage = $sMessage;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $oUser
|
||||
* @param array $aProfiles
|
||||
*
|
||||
* @return array
|
||||
* @throws \CoreException
|
||||
* @throws \CoreUnexpectedValue
|
||||
*/
|
||||
public static function SynchronizeProfiles(&$oUser, array $aProfiles, $sOrigin)
|
||||
{
|
||||
$oProfilesSet = $oUser->Get(‘profile_list’);
|
||||
//delete old profiles
|
||||
$aExistingProfiles = [];
|
||||
while ($oProfile = $oProfilesSet->Fetch())
|
||||
{
|
||||
array_push($aExistingProfiles, $oProfile->Get('profileid'));
|
||||
$iArrayKey = array_search($oProfile->Get('profileid'), $aProfiles);
|
||||
if (!$iArrayKey)
|
||||
{
|
||||
$oProfilesSet->RemoveItem($oProfile->Get('profileid'));
|
||||
}
|
||||
else
|
||||
{
|
||||
unset($aProfiles[$iArrayKey]);
|
||||
}
|
||||
}
|
||||
//add profiles not already linked with user
|
||||
foreach ($aProfiles as $iProfileId)
|
||||
{
|
||||
$oLink = new URP_UserProfile();
|
||||
$oLink->Set('profileid', $iProfileId);
|
||||
$oLink->Set('reason', $sOrigin);
|
||||
|
||||
$oProfilesSet->AddItem(MetaModel::NewObject('URP_UserProfile', array('profileid' => $iProfileId, 'reason' => $sOrigin)));
|
||||
}
|
||||
$oUser->Set('profile_list', $oProfilesSet);
|
||||
}
|
||||
|
||||
public function DisplayLoginHeader($bMainAppLogo = false)
|
||||
{
|
||||
$sLogo = 'itop-logo-external.png';
|
||||
@@ -888,20 +925,12 @@ class LoginWebPage extends NiceWebPage
|
||||
}
|
||||
|
||||
// Now synchronize the profiles
|
||||
$oProfilesSet = DBObjectSet::FromScratch('URP_UserProfile');
|
||||
$sOrigin = 'External User provisioning';
|
||||
if (isset($_SESSION['login_mode']))
|
||||
{
|
||||
$sOrigin .= " ({$_SESSION['login_mode']})";
|
||||
}
|
||||
foreach ($aProfiles as $iProfileId)
|
||||
{
|
||||
$oLink = new URP_UserProfile();
|
||||
$oLink->Set('profileid', $iProfileId);
|
||||
$oLink->Set('reason', $sOrigin);
|
||||
$oProfilesSet->AddObject($oLink);
|
||||
}
|
||||
$oUser->Set('profile_list', $oProfilesSet);
|
||||
$aExistingProfiles = self::SynchronizeProfiles($oUser, $aProfiles, $sOrigin);
|
||||
if ($oUser->IsModified())
|
||||
{
|
||||
$oUser->DBWrite();
|
||||
|
||||
@@ -17,6 +17,8 @@
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
*/
|
||||
|
||||
use Combodo\iTop\Application\UI\Component\Title\TitleFactory;
|
||||
|
||||
require_once(APPROOT.'/application/utils.inc.php');
|
||||
require_once(APPROOT.'/application/template.class.inc.php');
|
||||
require_once(APPROOT."/application/user.dashboard.class.inc.php");
|
||||
@@ -51,7 +53,10 @@ require_once(APPROOT."/application/user.dashboard.class.inc.php");
|
||||
* new OQLMenuNode('PersonsMenu', 'SELECT bizPerson', $oContactsMenu->GetIndex(), 0);
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* Class ApplicationMenu
|
||||
*/
|
||||
class ApplicationMenu
|
||||
{
|
||||
/**
|
||||
@@ -71,7 +76,10 @@ class ApplicationMenu
|
||||
*/
|
||||
static $sFavoriteSiloQuery = 'SELECT Organization';
|
||||
|
||||
static public function LoadAdditionalMenus()
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public static function LoadAdditionalMenus()
|
||||
{
|
||||
if (!self::$bAdditionalMenusLoaded)
|
||||
{
|
||||
@@ -97,10 +105,10 @@ class ApplicationMenu
|
||||
|
||||
/**
|
||||
* Set the query used to limit the list of displayed organizations in the drop-down menu
|
||||
* @param $sOQL string The OQL query returning a list of Organization objects
|
||||
* @param string $sOQL The OQL query returning a list of Organization objects
|
||||
* @return void
|
||||
*/
|
||||
static public function SetFavoriteSiloQuery($sOQL)
|
||||
public static function SetFavoriteSiloQuery($sOQL)
|
||||
{
|
||||
self::$sFavoriteSiloQuery = $sOQL;
|
||||
}
|
||||
@@ -109,7 +117,7 @@ class ApplicationMenu
|
||||
* Get the query used to limit the list of displayed organizations in the drop-down menu
|
||||
* @return string The OQL query returning a list of Organization objects
|
||||
*/
|
||||
static public function GetFavoriteSiloQuery()
|
||||
public static function GetFavoriteSiloQuery()
|
||||
{
|
||||
return self::$sFavoriteSiloQuery;
|
||||
}
|
||||
@@ -117,11 +125,11 @@ class ApplicationMenu
|
||||
/**
|
||||
* Check whether a menu Id is enabled or not
|
||||
*
|
||||
* @param $sMenuId
|
||||
* @param string $sMenuId
|
||||
*
|
||||
* @throws \Exception
|
||||
*/
|
||||
static public function CheckMenuIdEnabled($sMenuId)
|
||||
public static function CheckMenuIdEnabled($sMenuId)
|
||||
{
|
||||
self::LoadAdditionalMenus();
|
||||
$oMenuNode = self::GetMenuNode(self::GetMenuIndexById($sMenuId));
|
||||
@@ -140,11 +148,11 @@ class ApplicationMenu
|
||||
* Main function to add a menu entry into the application, can be called during the definition
|
||||
* of the data model objects
|
||||
* @param MenuNode $oMenuNode
|
||||
* @param $iParentIndex
|
||||
* @param $fRank
|
||||
* @param int $iParentIndex
|
||||
* @param float $fRank
|
||||
* @return int
|
||||
*/
|
||||
static public function InsertMenu(MenuNode $oMenuNode, $iParentIndex, $fRank)
|
||||
public static function InsertMenu(MenuNode $oMenuNode, $iParentIndex, $fRank)
|
||||
{
|
||||
$index = self::GetMenuIndexById($oMenuNode->GetMenuId());
|
||||
if ($index == -1)
|
||||
@@ -185,20 +193,154 @@ class ApplicationMenu
|
||||
|
||||
/**
|
||||
* Reflection API - Get menu entries
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
static public function ReflectionMenuNodes()
|
||||
public static function ReflectionMenuNodes()
|
||||
{
|
||||
self::LoadAdditionalMenus();
|
||||
return self::$aMenusIndex;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get entries count for all the menus
|
||||
*
|
||||
* @param array $aExtraParams
|
||||
*
|
||||
* @return array
|
||||
* @throws \DictExceptionMissingString
|
||||
* @since 3.0.0
|
||||
*/
|
||||
public static function GetMenusCount($aExtraParams = array())
|
||||
{
|
||||
$aMenuGroups = static::GetMenuGroups($aExtraParams);
|
||||
|
||||
$aMenusCount = [];
|
||||
foreach ($aMenuGroups as $aMenuGroup) {
|
||||
$aSubMenuNodes = $aMenuGroup['aSubMenuNodes'];
|
||||
$aMenusCount = array_merge($aMenusCount, static::GetSubMenusCount($aSubMenuNodes));
|
||||
}
|
||||
|
||||
return $aMenusCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Recurse sub menus for counts
|
||||
*
|
||||
* @param array $aSubMenuNodes
|
||||
*
|
||||
* @return array
|
||||
* @since 3.0.0
|
||||
*/
|
||||
private static function GetSubMenusCount(array $aSubMenuNodes)
|
||||
{
|
||||
$aSubMenusCount = [];
|
||||
foreach ($aSubMenuNodes as $aSubMenuNode) {
|
||||
if ($aSubMenuNode['bHasCount']) {
|
||||
$oMenuNode = static::GetMenuNode(static::GetMenuIndexById($aSubMenuNode['sId']));
|
||||
$aSubMenusCount[$aSubMenuNode['sId']] = $oMenuNode->GetEntriesCount();
|
||||
}
|
||||
$aSubMenusCount = array_merge($aSubMenusCount, static::GetSubMenusCount($aSubMenuNode['aSubMenuNodes']));
|
||||
}
|
||||
return $aSubMenusCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an array of menu groups
|
||||
*
|
||||
* @param array $aExtraParams
|
||||
*
|
||||
* @return array
|
||||
* @throws \DictExceptionMissingString
|
||||
* @since 3.0.0
|
||||
*/
|
||||
public static function GetMenuGroups($aExtraParams = array())
|
||||
{
|
||||
self::LoadAdditionalMenus();
|
||||
|
||||
// Sort the root menu based on the rank
|
||||
usort(self::$aRootMenus, array('ApplicationMenu', 'CompareOnRank'));
|
||||
|
||||
$aMenuGroups = [];
|
||||
foreach(static::$aRootMenus as $aMenuGroup)
|
||||
{
|
||||
if(!static::CanDisplayMenu($aMenuGroup))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
$sMenuGroupIdx = $aMenuGroup['index'];
|
||||
/** @var \MenuGroup $oMenuNode */
|
||||
$oMenuNode = static::GetMenuNode($sMenuGroupIdx);
|
||||
|
||||
$aMenuGroups[] = [
|
||||
'sId' => $oMenuNode->GetMenuID(),
|
||||
'sIconCssClasses' => $oMenuNode->GetDecorationClasses(),
|
||||
'sInitials' => $oMenuNode->GetInitials(),
|
||||
'sTitle' => $oMenuNode->GetTitle(),
|
||||
'aSubMenuNodes' => static::GetSubMenuNodes($sMenuGroupIdx, $aExtraParams),
|
||||
];
|
||||
}
|
||||
|
||||
return $aMenuGroups;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an array of sub-menu nodes for $sMenuGroupIdx
|
||||
*
|
||||
* @param string $sMenuGroupIdx
|
||||
* @param array $aExtraParams
|
||||
*
|
||||
* @return array
|
||||
* @throws \DictExceptionMissingString
|
||||
* @throws \Exception
|
||||
* @since 3.0.0
|
||||
*/
|
||||
public static function GetSubMenuNodes($sMenuGroupIdx, $aExtraParams = array())
|
||||
{
|
||||
$aSubMenuItems = self::GetChildren($sMenuGroupIdx);
|
||||
|
||||
// Sort the children based on the rank
|
||||
usort($aSubMenuItems, array('ApplicationMenu', 'CompareOnRank'));
|
||||
|
||||
$aSubMenuNodes = [];
|
||||
foreach($aSubMenuItems as $aSubMenuItem)
|
||||
{
|
||||
if(!static::CanDisplayMenu($aSubMenuItem))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
$sSubMenuItemIdx = $aSubMenuItem['index'];
|
||||
$oSubMenuNode = static::GetMenuNode($sSubMenuItemIdx);
|
||||
|
||||
if(!$oSubMenuNode->IsEnabled())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
$aSubMenuNodes[] = [
|
||||
'sId' => $oSubMenuNode->GetMenuId(),
|
||||
'sTitle' => $oSubMenuNode->GetTitle(),
|
||||
'bHasCount' => $oSubMenuNode->HasCount(),
|
||||
'sUrl' => $oSubMenuNode->GetHyperlink($aExtraParams),
|
||||
'bOpenInNewWindow' => $oSubMenuNode->IsHyperLinkInNewWindow(),
|
||||
'aSubMenuNodes' => static::GetSubMenuNodes($sSubMenuItemIdx, $aExtraParams),
|
||||
];
|
||||
}
|
||||
|
||||
return $aSubMenuNodes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Entry point to display the whole menu into the web page, used by iTopWebPage
|
||||
* @param \WebPage $oPage
|
||||
* @param $aExtraParams
|
||||
* @param array $aExtraParams
|
||||
* @throws DictExceptionMissingString
|
||||
*
|
||||
* @deprecated Will be removed in 3.0.0, use static::GetMenuGroups() instead
|
||||
*/
|
||||
static public function DisplayMenu($oPage, $aExtraParams)
|
||||
public static function DisplayMenu($oPage, $aExtraParams)
|
||||
{
|
||||
self::LoadAdditionalMenus();
|
||||
// Sort the root menu based on the rank
|
||||
@@ -237,7 +379,7 @@ EOF
|
||||
* @param array $aMenu menu entry
|
||||
* @return bool true if at least one menu is enabled
|
||||
*/
|
||||
static private function CanDisplayMenu($aMenu)
|
||||
private static function CanDisplayMenu($aMenu)
|
||||
{
|
||||
$oMenuNode = self::GetMenuNode($aMenu['index']);
|
||||
if ($oMenuNode->IsEnabled())
|
||||
@@ -269,11 +411,12 @@ EOF
|
||||
* @param array $aExtraParams
|
||||
* @param int $iActiveMenu
|
||||
*
|
||||
* @return true if the currently selected menu is one of the submenus
|
||||
* @return bool True if the currently selected menu is one of the submenus
|
||||
* @throws DictExceptionMissingString
|
||||
* @throws \Exception
|
||||
* @deprecated Will be removed in 3.0.0, use static::GetSubMenuNodes() instead
|
||||
*/
|
||||
static protected function DisplaySubMenu($oPage, $aMenus, $aExtraParams, $iActiveMenu = -1)
|
||||
protected static function DisplaySubMenu($oPage, $aMenus, $aExtraParams, $iActiveMenu = -1)
|
||||
{
|
||||
// Sort the menu based on the rank
|
||||
$bActive = false;
|
||||
@@ -330,11 +473,11 @@ EOF
|
||||
|
||||
/**
|
||||
* Helper function to sort the menus based on their rank
|
||||
* @param $a
|
||||
* @param $b
|
||||
* @param array $a
|
||||
* @param array $b
|
||||
* @return int
|
||||
*/
|
||||
static public function CompareOnRank($a, $b)
|
||||
public static function CompareOnRank($a, $b)
|
||||
{
|
||||
$result = 1;
|
||||
if ($a['rank'] == $b['rank'])
|
||||
@@ -353,7 +496,7 @@ EOF
|
||||
* @param int $index
|
||||
* @return MenuNode|null
|
||||
*/
|
||||
static public function GetMenuNode($index)
|
||||
public static function GetMenuNode($index)
|
||||
{
|
||||
return isset(self::$aMenusIndex[$index]) ? self::$aMenusIndex[$index]['node'] : null;
|
||||
}
|
||||
@@ -363,7 +506,7 @@ EOF
|
||||
* @param int $index
|
||||
* @return array
|
||||
*/
|
||||
static public function GetChildren($index)
|
||||
public static function GetChildren($index)
|
||||
{
|
||||
return self::$aMenusIndex[$index]['children'];
|
||||
}
|
||||
@@ -373,7 +516,7 @@ EOF
|
||||
* @param string $sTitle Title of the menu (as passed when creating the menu)
|
||||
* @return integer ID of the menu, or -1 if not found
|
||||
*/
|
||||
static public function GetMenuIndexById($sTitle)
|
||||
public static function GetMenuIndexById($sTitle)
|
||||
{
|
||||
$index = -1;
|
||||
/** @var MenuNode[] $aMenu */
|
||||
@@ -392,7 +535,7 @@ EOF
|
||||
* Retrieves the currently active menu (if any, otherwise the first menu is the default)
|
||||
* @return string The Id of the currently active menu
|
||||
*/
|
||||
static public function GetActiveNodeId()
|
||||
public static function GetActiveNodeId()
|
||||
{
|
||||
$oAppContext = new ApplicationContext();
|
||||
$sMenuId = $oAppContext->GetCurrentValue('menu', null);
|
||||
@@ -406,7 +549,7 @@ EOF
|
||||
/**
|
||||
* @return null|string
|
||||
*/
|
||||
static public function GetDefaultMenuId()
|
||||
public static function GetDefaultMenuId()
|
||||
{
|
||||
static $sDefaultMenuId = null;
|
||||
if (is_null($sDefaultMenuId))
|
||||
@@ -426,7 +569,7 @@ EOF
|
||||
* @param $sMenuId
|
||||
* @return string
|
||||
*/
|
||||
static public function GetRootMenuId($sMenuId)
|
||||
public static function GetRootMenuId($sMenuId)
|
||||
{
|
||||
$iMenuIndex = self::GetMenuIndexById($sMenuId);
|
||||
if ($iMenuIndex == -1)
|
||||
@@ -563,29 +706,45 @@ abstract class MenuNode
|
||||
|
||||
/**
|
||||
* @return string
|
||||
* @throws DictExceptionMissingString
|
||||
*/
|
||||
public function GetTitle()
|
||||
{
|
||||
return Dict::S("Menu:$this->sMenuId", str_replace('_', ' ', $this->sMenuId));
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates if the page corresponding to this menu node is countable
|
||||
*
|
||||
* @return bool true if corresponding page is countable
|
||||
* @since 3.0.0
|
||||
*/
|
||||
public function HasCount()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the number of entries of the page corresponding to this menu item.
|
||||
*
|
||||
* @return int the number of entries
|
||||
* @since 3.0.0
|
||||
*/
|
||||
public function GetEntriesCount()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
* @throws DictExceptionMissingString
|
||||
*/
|
||||
public function GetLabel()
|
||||
{
|
||||
$sRet = Dict::S("Menu:$this->sMenuId+", "");
|
||||
if ($sRet === '')
|
||||
{
|
||||
if ($this->iParentIndex != -1)
|
||||
{
|
||||
if ($sRet === '') {
|
||||
if ($this->iParentIndex != -1) {
|
||||
$oParentMenu = ApplicationMenu::GetMenuNode($this->iParentIndex);
|
||||
$sRet = $oParentMenu->GetTitle().' / '.$this->GetTitle();
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
$sRet = $this->GetTitle();
|
||||
}
|
||||
//$sRet = $this->GetTitle();
|
||||
@@ -600,7 +759,10 @@ abstract class MenuNode
|
||||
{
|
||||
return $this->index;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function PopulateChildMenus()
|
||||
{
|
||||
foreach (ApplicationMenu::GetChildren($this->GetIndex()) as $aMenu)
|
||||
@@ -725,18 +887,64 @@ abstract class MenuNode
|
||||
*/
|
||||
class MenuGroup extends MenuNode
|
||||
{
|
||||
/** @var string DEFAULT_DECORATION_CLASSES Set to null by default so it is replaced by initials when none is specified */
|
||||
const DEFAULT_DECORATION_CLASSES = null;
|
||||
|
||||
/** @var string The CSS classes used to display the menu group's icon */
|
||||
protected $sDecorationClasses = self::DEFAULT_DECORATION_CLASSES;
|
||||
|
||||
/**
|
||||
* Create a top-level menu group and inserts it into the application's main menu
|
||||
*
|
||||
* @param string $sMenuId Unique identifier of the menu (used to identify the menu for bookmarking, and for getting the labels from the dictionary)
|
||||
* @param float $fRank Number used to order the list, the groups are sorted based on this value
|
||||
* @param string|null $sDecorationClasses CSS classes used to display the menu group's icon
|
||||
* @param string $sEnableClass Name of class of object
|
||||
* @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
|
||||
*/
|
||||
public function __construct($sMenuId, $fRank, $sEnableClass = null, $iActionCode = null, $iAllowedResults = UR_ALLOWED_YES, $sEnableStimulus = null)
|
||||
public function __construct($sMenuId, $fRank, $sDecorationClasses = null, $sEnableClass = null, $iActionCode = null, $iAllowedResults = UR_ALLOWED_YES, $sEnableStimulus = null)
|
||||
{
|
||||
parent::__construct($sMenuId, -1 /* no parent, groups are at root level */, $fRank, $sEnableClass, $iActionCode, $iAllowedResults, $sEnableStimulus);
|
||||
|
||||
if(!empty($sDecorationClasses))
|
||||
{
|
||||
$this->sDecorationClasses = $sDecorationClasses;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the menu group has some decoration classes
|
||||
*
|
||||
* @return bool
|
||||
* @since 3.0.0
|
||||
*/
|
||||
public function HasDecorationClasses()
|
||||
{
|
||||
return (empty($this->GetDecorationClasses()) === false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the CSS classes used for decorating the menu group (typically the icon in the navigation menu)
|
||||
*
|
||||
* @return string
|
||||
* @since 3.0.0
|
||||
*/
|
||||
public function GetDecorationClasses()
|
||||
{
|
||||
return $this->sDecorationClasses;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the initials of the menu group, used by the rendering in case there is no decoration classes
|
||||
*
|
||||
* @return string
|
||||
* @since 3.0.0
|
||||
*/
|
||||
public function GetInitials()
|
||||
{
|
||||
return mb_substr($this->GetTitle(), 0, 1);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -913,30 +1121,51 @@ class OQLMenuNode extends MenuNode
|
||||
{
|
||||
$sUsageId = utils::GetSafeId($sUsageId);
|
||||
$oSearch = DBObjectSearch::FromOQL($sOql);
|
||||
$sIcon = MetaModel::GetClassIcon($oSearch->GetClass());
|
||||
//$sIcon = MetaModel::GetClassIcon($oSearch->GetClass(), false);
|
||||
|
||||
if ($bSearchPane)
|
||||
{
|
||||
if ($bSearchPane) {
|
||||
$aParams = array_merge(array('open' => $bSearchOpen, 'table_id' => $sUsageId), $aExtraParams);
|
||||
$oBlock = new DisplayBlock($oSearch, 'search', false /* Asynchronous */, $aParams);
|
||||
$oBlock->Display($oPage, 0);
|
||||
}
|
||||
|
||||
$oPage->add("<p class=\"page-header\">$sIcon ".utils::HtmlEntities(Dict::S($sTitle))."</p>");
|
||||
|
||||
|
||||
//$oPage->add("<p class=\"page-header\">$sIcon ".utils::HtmlEntities(Dict::S($sTitle))."</p>");
|
||||
$oPage->add("<div class='sf_results_area'>");
|
||||
$oTitle = TitleFactory::MakeForPage($sTitle);
|
||||
$oPage->AddUiBlock($oTitle);
|
||||
|
||||
$aParams = array_merge(array('table_id' => $sUsageId), $aExtraParams);
|
||||
$oBlock = new DisplayBlock($oSearch, 'list', false /* Asynchronous */, $aParams);
|
||||
$oBlock->Display($oPage, $sUsageId);
|
||||
|
||||
if ($bEnableBreadcrumb && ($oPage instanceof iTopWebPage))
|
||||
{
|
||||
$oPage->add("</div>");
|
||||
|
||||
if ($bEnableBreadcrumb && ($oPage instanceof iTopWebPage)) {
|
||||
// Breadcrumb
|
||||
//$iCount = $oBlock->GetDisplayedCount();
|
||||
$sPageId = "ui-search-".$oSearch->GetClass();
|
||||
$sLabel = MetaModel::GetName($oSearch->GetClass());
|
||||
$oPage->SetBreadCrumbEntry($sPageId, $sLabel, $sTitle, '', '../images/breadcrumb-search.png');
|
||||
$oPage->SetBreadCrumbEntry($sPageId, $sLabel, $sTitle, '', 'fas fa-list', iTopWebPage::ENUM_BREADCRUMB_ENTRY_ICON_TYPE_CSS_CLASSES);
|
||||
}
|
||||
}
|
||||
|
||||
public function HasCount()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public function GetEntriesCount()
|
||||
{
|
||||
// Count the entries up to 99
|
||||
|
||||
$oSet = new DBObjectSet(DBSearch::FromOQL($this->sOQL));
|
||||
$iCount = $oSet->CountWithLimit(99);
|
||||
if ($iCount > 99) {
|
||||
$iCount = "99+";
|
||||
}
|
||||
|
||||
return $iCount;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -981,7 +1210,7 @@ class SearchMenuNode extends MenuNode
|
||||
public function RenderContent(WebPage $oPage, $aExtraParams = array())
|
||||
{
|
||||
ApplicationMenu::CheckMenuIdEnabled($this->GetMenuId());
|
||||
$oPage->SetBreadCrumbEntry("menu-".$this->sMenuId, $this->GetTitle(), '', '', utils::GetAbsoluteUrlAppRoot().'images/breadcrumb-search.png');
|
||||
$oPage->SetBreadCrumbEntry("menu-".$this->sMenuId, $this->GetTitle(), '', '', 'fas fa-search', iTopWebPage::ENUM_BREADCRUMB_ENTRY_ICON_TYPE_CSS_CLASSES);
|
||||
|
||||
$oSearch = new DBObjectSearch($this->sClass);
|
||||
$aParams = array_merge(array('table_id' => 'Menu_'.utils::GetSafeId($this->GetMenuId())), $aExtraParams);
|
||||
@@ -1191,7 +1420,7 @@ class DashboardMenuNode extends MenuNode
|
||||
if ($oDashboard != null)
|
||||
{
|
||||
$sDivId = utils::Sanitize($this->sMenuId, '', 'element_identifier');
|
||||
$oPage->add('<div class="dashboard_contents" id="'.$sDivId.'">');
|
||||
$oPage->add('<div class="ibo-dashboard" id="'.$sDivId.'">');
|
||||
$aExtraParams['dashboard_div_id'] = $sDivId;
|
||||
$oDashboard->SetReloadURL($this->GetHyperlink($aExtraParams));
|
||||
$oDashboard->Render($oPage, false, $aExtraParams);
|
||||
@@ -1218,13 +1447,13 @@ class DashboardMenuNode extends MenuNode
|
||||
}
|
||||
if ($this->sMenuId == ApplicationMenu::GetDefaultMenuId())
|
||||
{
|
||||
$sIcon = '../images/breadcrumb_home.png';
|
||||
$sIcon = 'fas fa-home';
|
||||
}
|
||||
else
|
||||
{
|
||||
$sIcon = '../images/breadcrumb-dashboard.png';
|
||||
$sIcon = 'fas fa-chart-pie';
|
||||
}
|
||||
$oPage->SetBreadCrumbEntry("ui-dashboard-".$this->sMenuId, $this->GetTitle(), $sDescription, '', $sIcon);
|
||||
$oPage->SetBreadCrumbEntry("ui-dashboard-".$this->sMenuId, $this->GetTitle(), $sDescription, '', $sIcon, iTopWebPage::ENUM_BREADCRUMB_ENTRY_ICON_TYPE_CSS_CLASSES);
|
||||
}
|
||||
}
|
||||
else
|
||||
|
||||
@@ -1,262 +1,7 @@
|
||||
<?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
|
||||
* @deprecated will be removed in 3.1.0 - moved to sources/application/WebPage/NiceWebPage.php
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
* @copyright Copyright (C) 2010-2020 Combodo SARL
|
||||
*/
|
||||
|
||||
require_once(APPROOT."/application/webpage.class.inc.php");
|
||||
/**
|
||||
* Web page with some associated CSS and scripts (jquery) for a fancier display
|
||||
*/
|
||||
class NiceWebPage extends WebPage
|
||||
{
|
||||
var $m_aReadyScripts;
|
||||
var $m_sRootUrl;
|
||||
|
||||
public function __construct($s_title, $bPrintable = false)
|
||||
{
|
||||
parent::__construct($s_title, $bPrintable);
|
||||
$this->m_aReadyScripts = array();
|
||||
$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.dev.js');
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/jquery-migrate.prod.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
|
||||
$this->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/jquery.tablesorter.js');
|
||||
$this->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/jquery.tablesorter.pager.js');
|
||||
$this->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/jquery.tablehover.js');
|
||||
$this->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/table-selectable-lines.js');
|
||||
$this->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/field_sorter.js');
|
||||
$this->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/datatable.js');
|
||||
$this->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/jquery.positionBy.js');
|
||||
$this->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/jquery.popupmenu.js');
|
||||
$this->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/searchformforeignkeys.js');
|
||||
$this->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/latinise/latinise.min.js');
|
||||
$this->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/search/search_form_handler.js');
|
||||
$this->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/search/search_form_handler_history.js');
|
||||
$this->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/search/search_form_criteria.js');
|
||||
$this->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/search/search_form_criteria_raw.js');
|
||||
$this->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/search/search_form_criteria_string.js');
|
||||
$this->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/search/search_form_criteria_external_field.js');
|
||||
$this->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/search/search_form_criteria_numeric.js');
|
||||
$this->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/search/search_form_criteria_enum.js');
|
||||
$this->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/search/search_form_criteria_tag_set.js');
|
||||
$this->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/search/search_form_criteria_external_key.js');
|
||||
$this->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/search/search_form_criteria_hierarchical_key.js');
|
||||
$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');
|
||||
|
||||
$this->add_ready_script(
|
||||
<<< EOF
|
||||
//add new widget called TruncatedList to properly display truncated lists when they are sorted
|
||||
$.tablesorter.addWidget({
|
||||
// give the widget a id
|
||||
id: "truncatedList",
|
||||
// format is called when the on init and when a sorting has finished
|
||||
format: function(table)
|
||||
{
|
||||
// Check if there is a "truncated" line
|
||||
this.truncatedList = false;
|
||||
if ($("tr td.truncated",table).length > 0)
|
||||
{
|
||||
this.truncatedList = true;
|
||||
}
|
||||
if (this.truncatedList)
|
||||
{
|
||||
$("tr td",table).removeClass('truncated');
|
||||
$("tr:last td",table).addClass('truncated');
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
$.tablesorter.addWidget({
|
||||
// give the widget a id
|
||||
id: "myZebra",
|
||||
// format is called when the on init and when a sorting has finished
|
||||
format: function(table)
|
||||
{
|
||||
// Replace the 'red even' lines by 'red_even' since most browser do not support 2 classes selector in CSS, etc..
|
||||
$("tbody tr:even",table).addClass('even');
|
||||
$("tbody tr.red:even",table).removeClass('red').removeClass('even').addClass('red_even');
|
||||
$("tbody tr.orange:even",table).removeClass('orange').removeClass('even').addClass('orange_even');
|
||||
$("tbody tr.green:even",table).removeClass('green').removeClass('even').addClass('green_even');
|
||||
// In case we sort again the table, we need to remove the added 'even' classes on odd rows
|
||||
$("tbody tr:odd",table).removeClass('even');
|
||||
$("tbody tr.red_even:odd",table).removeClass('even').removeClass('red_even').addClass('red');
|
||||
$("tbody tr.orange_even:odd",table).removeClass('even').removeClass('orange_even').addClass('orange');
|
||||
$("tbody tr.green_even:odd",table).removeClass('even').removeClass('green_even').addClass('green');
|
||||
}
|
||||
});
|
||||
$("table.listResults").tableHover(); // hover tables
|
||||
EOF
|
||||
);
|
||||
$this->LoadTheme();
|
||||
|
||||
$this->m_sRootUrl = $this->GetAbsoluteUrlAppRoot();
|
||||
$sAbsURLAppRoot = addslashes($this->m_sRootUrl);
|
||||
$sAbsURLModulesRoot = addslashes($this->GetAbsoluteUrlModulesRoot());
|
||||
$sEnvironment = addslashes(utils::GetCurrentEnvironment());
|
||||
|
||||
$sAppContext = addslashes($this->GetApplicationContext());
|
||||
|
||||
$this->add_script(
|
||||
<<<EOF
|
||||
function GetAbsoluteUrlAppRoot()
|
||||
{
|
||||
return '$sAbsURLAppRoot';
|
||||
}
|
||||
|
||||
function GetAbsoluteUrlModulesRoot()
|
||||
{
|
||||
return '$sAbsURLModulesRoot';
|
||||
}
|
||||
|
||||
function GetAbsoluteUrlModulePage(sModule, sPage, aArguments)
|
||||
{
|
||||
// aArguments is optional, it default to an empty hash
|
||||
aArguments = typeof aArguments !== 'undefined' ? aArguments : {};
|
||||
|
||||
var sUrl = '$sAbsURLAppRoot'+'pages/exec.php?exec_module='+sModule+'&exec_page='+sPage+'&exec_env='+'$sEnvironment';
|
||||
for (var sArgName in aArguments)
|
||||
{
|
||||
if (aArguments.hasOwnProperty(sArgName))
|
||||
{
|
||||
sUrl = sUrl + '&'+sArgName+'='+aArguments[sArgname];
|
||||
}
|
||||
}
|
||||
return sUrl;
|
||||
}
|
||||
|
||||
function AddAppContext(sURL)
|
||||
{
|
||||
var sContext = '$sAppContext';
|
||||
if (sContext.length > 0)
|
||||
{
|
||||
if (sURL.indexOf('?') == -1)
|
||||
{
|
||||
return sURL+'?'+sContext;
|
||||
}
|
||||
return sURL+'&'+sContext;
|
||||
}
|
||||
return sURL;
|
||||
}
|
||||
EOF
|
||||
);
|
||||
}
|
||||
|
||||
public function SetRootUrl($sRootUrl)
|
||||
{
|
||||
$this->m_sRootUrl = $sRootUrl;
|
||||
}
|
||||
|
||||
public function small_p($sText)
|
||||
{
|
||||
$this->add("<p style=\"font-size:smaller\">$sText</p>\n");
|
||||
}
|
||||
|
||||
public function GetAbsoluteUrlAppRoot()
|
||||
{
|
||||
return utils::GetAbsoluteUrlAppRoot();
|
||||
}
|
||||
|
||||
public function GetAbsoluteUrlModulesRoot()
|
||||
{
|
||||
return utils::GetAbsoluteUrlModulesRoot();
|
||||
}
|
||||
|
||||
function GetApplicationContext()
|
||||
{
|
||||
$oAppContext = new ApplicationContext();
|
||||
return $oAppContext->GetForLink();
|
||||
}
|
||||
|
||||
// By Rom, used by CSVImport and Advanced search
|
||||
public function MakeClassesSelect($sName, $sDefaultValue, $iWidthPx, $iActionCode = null)
|
||||
{
|
||||
// $aTopLevelClasses = array('bizService', 'bizContact', 'logInfra', 'bizDocument');
|
||||
// These are classes wich root class is cmdbAbstractObject !
|
||||
$this->add("<select id=\"select_$sName\" name=\"$sName\">");
|
||||
$aValidClasses = array();
|
||||
foreach(MetaModel::GetClasses('bizmodel') as $sClassName)
|
||||
{
|
||||
if (is_null($iActionCode) || UserRights::IsActionAllowed($sClassName, $iActionCode))
|
||||
{
|
||||
$sSelected = ($sClassName == $sDefaultValue) ? " SELECTED" : "";
|
||||
$sDescription = MetaModel::GetClassDescription($sClassName);
|
||||
$sDisplayName = MetaModel::GetName($sClassName);
|
||||
$aValidClasses[$sDisplayName] = "<option style=\"width: ".$iWidthPx." px;\" title=\"$sDescription\" value=\"$sClassName\"$sSelected>$sDisplayName</option>";
|
||||
}
|
||||
}
|
||||
ksort($aValidClasses);
|
||||
$this->add(implode("\n", $aValidClasses));
|
||||
|
||||
$this->add("</select>");
|
||||
}
|
||||
|
||||
// By Rom, used by Advanced search
|
||||
public function add_select($aChoices, $sName, $sDefaultValue, $iWidthPx)
|
||||
{
|
||||
$this->add("<select id=\"select_$sName\" name=\"$sName\">");
|
||||
foreach($aChoices as $sKey => $sValue)
|
||||
{
|
||||
$sSelected = ($sKey == $sDefaultValue) ? " SELECTED" : "";
|
||||
$this->add("<option style=\"width: ".$iWidthPx." px;\" value=\"".htmlspecialchars($sKey)."\"$sSelected>".htmlentities($sValue,
|
||||
ENT_QUOTES, self::PAGES_CHARSET)."</option>");
|
||||
}
|
||||
$this->add("</select>");
|
||||
}
|
||||
|
||||
public function add_ready_script($sScript)
|
||||
{
|
||||
$this->m_aReadyScripts[] = $sScript;
|
||||
}
|
||||
|
||||
/**
|
||||
* Outputs (via some echo) the complete HTML page by assembling all its elements
|
||||
*/
|
||||
public function output()
|
||||
{
|
||||
//$this->set_base($this->m_sRootUrl.'pages/');
|
||||
if (count($this->m_aReadyScripts)>0)
|
||||
{
|
||||
$this->add_script("\$(document).ready(function() {\n".implode("\n", $this->m_aReadyScripts)."\n});");
|
||||
}
|
||||
parent::output();
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws \Exception
|
||||
* @since 2.7.0
|
||||
*/
|
||||
protected function LoadTheme()
|
||||
{
|
||||
$sCssThemeUrl = ThemeHandler::GetCurrentThemeUrl();
|
||||
$this->add_linked_stylesheet($sCssThemeUrl);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,248 +1,7 @@
|
||||
<?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
|
||||
* @deprecated will be removed in 3.1.0 - moved to sources/application/WebPage/PDFPage.php
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
* @copyright Copyright (C) 2010-2020 Combodo SARL
|
||||
*/
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds the custom header. Called for each new page.
|
||||
*
|
||||
* @see TCPDF::Header()
|
||||
*/
|
||||
public function Header()
|
||||
{
|
||||
// Title
|
||||
// Set font
|
||||
$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->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 */);
|
||||
|
||||
// Branding logo
|
||||
$sBrandingIcon = APPROOT.'images/itop-logo.png';
|
||||
if (file_exists(MODULESROOT.'branding/main-logo.png'))
|
||||
{
|
||||
$sBrandingIcon = MODULESROOT.'branding/main-logo.png';
|
||||
}
|
||||
$this->Image($sBrandingIcon, $aMargins['left'], 5, 0, 10);
|
||||
}
|
||||
|
||||
// Page footer
|
||||
public function Footer()
|
||||
{
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Special class of WebPage for printing into a PDF document
|
||||
*/
|
||||
class PDFPage extends WebPage
|
||||
{
|
||||
/** @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/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);
|
||||
|
||||
// dejavusans is a UTF-8 Unicode font. Standard PDF fonts like helvetica or times new roman are NOT UTF-8
|
||||
$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
|
||||
table {
|
||||
padding: 2pt;
|
||||
}
|
||||
table.listResults td {
|
||||
border: 0.5pt solid #000 ;
|
||||
}
|
||||
table.listResults th {
|
||||
background-color: #eee;
|
||||
border: 0.5pt solid #000 ;
|
||||
}
|
||||
a {
|
||||
text-decoration: none;
|
||||
color: #000;
|
||||
}
|
||||
table.section td {
|
||||
vertical-align: middle;
|
||||
font-size: 10pt;
|
||||
background-color:#eee;
|
||||
}
|
||||
td.icon {
|
||||
width: 30px;
|
||||
}
|
||||
EOF
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get access to the underlying TCPDF object
|
||||
*
|
||||
* @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
|
||||
* - to process the HTML by smaller chunks instead of processing the whole page at once for performance reasons
|
||||
*/
|
||||
public function flush()
|
||||
{
|
||||
if (strlen($this->s_content) > 0)
|
||||
{
|
||||
$sHtml = '';
|
||||
if (count($this->a_styles) > 0)
|
||||
{
|
||||
$sHtml .= "<style>\n".implode("\n", $this->a_styles)."\n</style>\n";
|
||||
}
|
||||
$sHtml .= $this->s_content;
|
||||
$this->oPdf->writeHTML($sHtml); // The style(s) must be supplied each time we call writeHtml
|
||||
$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))
|
||||
{
|
||||
$this->add_header('Content-Disposition: '.$this->sContentDisposition.'; filename="'.$this->sContentFileName.'"');
|
||||
}
|
||||
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');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -40,7 +40,6 @@ abstract class Query extends cmdbAbstractObject
|
||||
"db_table" => "priv_query",
|
||||
"db_key_field" => "id",
|
||||
"db_finalclass_field" => "realclass",
|
||||
"display_template" => "",
|
||||
);
|
||||
MetaModel::Init_Params($aParams);
|
||||
//MetaModel::Init_InheritAttributes();
|
||||
@@ -72,7 +71,6 @@ class QueryOQL extends Query
|
||||
"db_table" => "priv_query_oql",
|
||||
"db_key_field" => "id",
|
||||
"db_finalclass_field" => "",
|
||||
"display_template" => "",
|
||||
);
|
||||
MetaModel::Init_Params($aParams);
|
||||
MetaModel::Init_InheritAttributes();
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with iTop. If not, see <http://www.gnu.org/licenses/>
|
||||
use Combodo\iTop\Application\UI\Component\DataTable\DataTableSettings;
|
||||
|
||||
|
||||
/**
|
||||
@@ -39,7 +40,6 @@ abstract class Shortcut extends DBObject implements iDisplay
|
||||
"db_table" => "priv_shortcut",
|
||||
"db_key_field" => "id",
|
||||
"db_finalclass_field" => "realclass",
|
||||
"display_template" => "",
|
||||
);
|
||||
MetaModel::Init_Params($aParams);
|
||||
//MetaModel::Init_InheritAttributes();
|
||||
@@ -161,7 +161,6 @@ class ShortcutOQL extends Shortcut
|
||||
"db_table" => "priv_shortcut_oql",
|
||||
"db_key_field" => "id",
|
||||
"db_finalclass_field" => "",
|
||||
"display_template" => "",
|
||||
);
|
||||
MetaModel::Init_Params($aParams);
|
||||
MetaModel::Init_InheritAttributes();
|
||||
|
||||
@@ -20,6 +20,8 @@
|
||||
require_once(APPROOT.'/application/displayblock.class.inc.php');
|
||||
/**
|
||||
* This class manages the special template format used internally to build the iTop web pages
|
||||
*
|
||||
* @deprecated Since 3.0.0
|
||||
*/
|
||||
class DisplayTemplate
|
||||
{
|
||||
|
||||
@@ -25,6 +25,15 @@
|
||||
*/
|
||||
class ThemeHandler
|
||||
{
|
||||
const IMAGE_EXTENSIONS = ['png', 'gif', 'jpg', 'jpeg'];
|
||||
|
||||
private static $oCompileCSSService;
|
||||
|
||||
public static function GetAppRootWithSlashes()
|
||||
{
|
||||
return str_replace('\\', '/', APPROOT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return default theme name and parameters
|
||||
*
|
||||
@@ -33,19 +42,19 @@ class ThemeHandler
|
||||
*/
|
||||
public static function GetDefaultThemeInformation()
|
||||
{
|
||||
return array(
|
||||
return [
|
||||
'name' => 'light-grey',
|
||||
'parameters' => array(
|
||||
'variables' => array(),
|
||||
'imports' => array(
|
||||
'parameters' => [
|
||||
'variables' => [],
|
||||
'imports' => [
|
||||
'css-variables' => '../css/css-variables.scss',
|
||||
),
|
||||
'stylesheets' => array(
|
||||
],
|
||||
'stylesheets' => [
|
||||
'jqueryui' => '../css/ui-lightness/jqueryui.scss',
|
||||
'main' => '../css/light-grey.scss',
|
||||
),
|
||||
),
|
||||
);
|
||||
],
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -112,37 +121,49 @@ class ThemeHandler
|
||||
SetupUtils::builddir($sDefaultThemeDirPath);
|
||||
}
|
||||
|
||||
static::CompileTheme($sThemeId, $aDefaultTheme['parameters']);
|
||||
static::CompileTheme($sThemeId, false, "", $aDefaultTheme['parameters']);
|
||||
}
|
||||
|
||||
// Return absolute url to theme compiled css
|
||||
return utils::GetAbsoluteUrlModulesRoot().'/branding/themes/'.$sThemeId.'/main.css';
|
||||
return utils::GetAbsoluteUrlModulesRoot().'branding/themes/'.$sThemeId.'/main.css';
|
||||
}
|
||||
|
||||
/**
|
||||
* Compile the $sThemeId theme
|
||||
* Compile the $sThemeId theme, the actual compilation is skipped when either
|
||||
* 1) The produced CSS file exists and is more recent than any of its components (imports, stylesheets)
|
||||
* 2) The produced CSS file exists and its signature is equal to the expected signature (imports, stylesheets, variables)
|
||||
*
|
||||
* @param string $sThemeId
|
||||
* @param boolean $bSetup
|
||||
* @param string $sSetupCompilationTimestamp : setup compilation timestamp in micro secunds
|
||||
* @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
|
||||
* @return boolean: indicate whether theme compilation occured
|
||||
*/
|
||||
public static function CompileTheme($sThemeId, $aThemeParameters = null, $aImportsPaths = null, $sWorkingPath = null)
|
||||
public static function CompileTheme($sThemeId, $bSetup=false, $sSetupCompilationTimestamp="", $aThemeParameters = null, $aImportsPaths = null, $sWorkingPath = null)
|
||||
{
|
||||
if ($sSetupCompilationTimestamp==="")
|
||||
{
|
||||
$sSetupCompilationTimestamp = microtime(true);
|
||||
}
|
||||
|
||||
$sSetupCompilationTimestampInSecunds = (strpos($sSetupCompilationTimestamp, '.') !==false) ? explode('.', $sSetupCompilationTimestamp)[0] : $sSetupCompilationTimestamp;
|
||||
|
||||
$sEnv = APPROOT.'env-'.utils::GetCurrentEnvironment().'/';
|
||||
|
||||
// Default working path
|
||||
if($sWorkingPath === null)
|
||||
{
|
||||
$sWorkingPath = APPROOT.'env-'.utils::GetCurrentEnvironment().'/';
|
||||
$sWorkingPath = $sEnv;
|
||||
}
|
||||
|
||||
// Default import paths (env-*)
|
||||
if($aImportsPaths === null)
|
||||
{
|
||||
$aImportsPaths = array(
|
||||
APPROOT.'env-'.utils::GetCurrentEnvironment().'/',
|
||||
);
|
||||
$aImportsPaths = [ $sEnv];
|
||||
}
|
||||
|
||||
// Note: We do NOT check that the folder exists!
|
||||
@@ -152,6 +173,11 @@ class ThemeHandler
|
||||
// Save parameters if passed... (typically during DM compilation)
|
||||
if(is_array($aThemeParameters))
|
||||
{
|
||||
if (!is_dir($sThemeFolderPath))
|
||||
{
|
||||
mkdir($sWorkingPath.'/branding/');
|
||||
mkdir($sWorkingPath.'/branding/themes/');
|
||||
}
|
||||
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)
|
||||
@@ -164,31 +190,588 @@ class ThemeHandler
|
||||
}
|
||||
}
|
||||
|
||||
$aThemeParametersWithVersion = self::CloneThemeParameterAndIncludeVersion($aThemeParameters, $sSetupCompilationTimestampInSecunds);
|
||||
|
||||
$sTmpThemeScssContent = '';
|
||||
$iStyleLastModified = 0;
|
||||
clearstatcache();
|
||||
// Loading files to import and stylesheet to compile, also getting most recent modification time on overall files
|
||||
|
||||
$aStylesheetFiles = [];
|
||||
foreach ($aThemeParameters['imports'] as $sImport)
|
||||
{
|
||||
$sTmpThemeScssContent .= '@import "'.$sImport.'";'."\n";
|
||||
|
||||
$iImportLastModified = @filemtime($sWorkingPath.$sImport);
|
||||
$sFile = static::FindStylesheetFile($sImport, $aImportsPaths);
|
||||
$iImportLastModified = @filemtime($sFile);
|
||||
$aStylesheetFiles[] = $sFile;
|
||||
$iStyleLastModified = $iStyleLastModified < $iImportLastModified ? $iImportLastModified : $iStyleLastModified;
|
||||
}
|
||||
foreach ($aThemeParameters['stylesheets'] as $sStylesheet)
|
||||
{
|
||||
$sTmpThemeScssContent .= '@import "'.$sStylesheet.'";'."\n";
|
||||
|
||||
$iStylesheetLastModified = @filemtime($sWorkingPath.$sStylesheet);
|
||||
$sFile = static::FindStylesheetFile($sStylesheet, $aImportsPaths);
|
||||
$iStylesheetLastModified = @filemtime($sFile);
|
||||
$aStylesheetFiles[] = $sFile;
|
||||
$iStyleLastModified = $iStyleLastModified < $iStylesheetLastModified ? $iStylesheetLastModified : $iStyleLastModified;
|
||||
}
|
||||
|
||||
// Checking if our compiled css is outdated
|
||||
if (!file_exists($sThemeCssPath) || (is_writable($sThemeFolderPath) && (@filemtime($sThemeCssPath) < $iStyleLastModified)))
|
||||
$aIncludedImages=static::GetIncludedImages($aThemeParametersWithVersion, $aStylesheetFiles, $sThemeId);
|
||||
foreach ($aIncludedImages as $sImage)
|
||||
{
|
||||
$sTmpThemeCssContent = utils::CompileCSSFromSASS($sTmpThemeScssContent, $aImportsPaths, $aThemeParameters['variables']);
|
||||
file_put_contents($sThemeCssPath, $sTmpThemeCssContent);
|
||||
if (is_file($sImage))
|
||||
{
|
||||
$iStylesheetLastModified = @filemtime($sImage);
|
||||
$iStyleLastModified = $iStyleLastModified < $iStylesheetLastModified ? $iStylesheetLastModified : $iStyleLastModified;
|
||||
}
|
||||
}
|
||||
|
||||
// Checking if our compiled css is outdated
|
||||
$iFilemetime = @filemtime($sThemeCssPath);
|
||||
$bFileExists = file_exists($sThemeCssPath);
|
||||
$bVarSignatureChanged=false;
|
||||
if ($bFileExists && $bSetup)
|
||||
{
|
||||
$sPrecompiledSignature = static::GetSignature($sThemeCssPath);
|
||||
//check variable signature has changed which is independant from any file modification
|
||||
if (!empty($sPrecompiledSignature)){
|
||||
$sPreviousVariableSignature = static::GetVarSignature($sPrecompiledSignature);
|
||||
$sCurrentVariableSignature = md5(json_encode($aThemeParameters['variables']));
|
||||
$bVarSignatureChanged= ($sPreviousVariableSignature!==$sCurrentVariableSignature);
|
||||
}
|
||||
}
|
||||
|
||||
if (!$bFileExists || $bVarSignatureChanged || (is_writable($sThemeFolderPath) && ($iFilemetime < $iStyleLastModified)))
|
||||
{
|
||||
// Dates don't match. Second chance: check if the already compiled stylesheet exists and is consistent based on its signature
|
||||
$sActualSignature = static::ComputeSignature($aThemeParameters, $aImportsPaths, $aIncludedImages);
|
||||
|
||||
if ($bFileExists && !$bSetup)
|
||||
{
|
||||
$sPrecompiledSignature = static::GetSignature($sThemeCssPath);
|
||||
}
|
||||
|
||||
if (!empty($sPrecompiledSignature) && $sActualSignature == $sPrecompiledSignature)
|
||||
{
|
||||
touch($sThemeCssPath); // Stylesheet is up to date, mark it as more recent to speedup next time
|
||||
}
|
||||
else
|
||||
{
|
||||
// Alas, we really need to recompile
|
||||
// Add the signature to the generated CSS file so that the file can be used as a precompiled stylesheet if needed
|
||||
$sSignatureComment =
|
||||
<<<CSS
|
||||
/*
|
||||
=== SIGNATURE BEGIN ===
|
||||
$sActualSignature
|
||||
=== SIGNATURE END ===
|
||||
*/
|
||||
|
||||
CSS;
|
||||
if (!static::$oCompileCSSService)
|
||||
{
|
||||
static::$oCompileCSSService = new CompileCSSService();
|
||||
}
|
||||
//store it again to change $version with latest compiled time
|
||||
$sTmpThemeCssContent = static::$oCompileCSSService->CompileCSSFromSASS($sTmpThemeScssContent, $aImportsPaths,
|
||||
$aThemeParametersWithVersion);
|
||||
file_put_contents($sThemeFolderPath.'/theme-parameters.json', json_encode($aThemeParameters));
|
||||
file_put_contents($sThemeCssPath, $sSignatureComment.$sTmpThemeCssContent);
|
||||
SetupLog::Info("Theme $sThemeId file compiled.");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute the signature of a theme defined by its theme parameters. The signature is a JSON structure of
|
||||
* 1) one MD5 of all the variables/values (JSON encoded)
|
||||
* 2) the MD5 of each stylesheet file
|
||||
* 3) the MD5 of each import file
|
||||
* 3) the MD5 of each images referenced in style sheets
|
||||
*
|
||||
* @param string[] $aThemeParameters
|
||||
* @param string[] $aImportsPaths
|
||||
* @param string[] $aIncludedImages
|
||||
*
|
||||
* @return string
|
||||
* @throws \Exception
|
||||
*/
|
||||
public static function ComputeSignature($aThemeParameters, $aImportsPaths, $aIncludedImages)
|
||||
{
|
||||
$aSignature = [
|
||||
'variables' => md5(json_encode($aThemeParameters['variables'])),
|
||||
'stylesheets' => [],
|
||||
'imports' => [],
|
||||
'images' => []
|
||||
];
|
||||
|
||||
foreach ($aThemeParameters['imports'] as $key => $sImport)
|
||||
{
|
||||
$sFile = static::FindStylesheetFile($sImport, $aImportsPaths);
|
||||
$aSignature['stylesheets'][$key] = md5_file($sFile);
|
||||
}
|
||||
foreach ($aThemeParameters['stylesheets'] as $key => $sStylesheet)
|
||||
{
|
||||
$sFile = static::FindStylesheetFile($sStylesheet, $aImportsPaths);
|
||||
$aSignature['stylesheets'][$key] = md5_file($sFile);
|
||||
}
|
||||
foreach ($aIncludedImages as $sImage)
|
||||
{
|
||||
if (is_file($sImage)) {
|
||||
$sUri = str_replace(self::GetAppRootWithSlashes(), '', $sImage);
|
||||
$aSignature['images'][$sUri] = md5_file($sImage);
|
||||
}
|
||||
}
|
||||
|
||||
return json_encode($aSignature);
|
||||
}
|
||||
|
||||
/**
|
||||
* Search for images referenced in stylesheet files
|
||||
*
|
||||
* @param array $aThemeParametersVariables
|
||||
* @param array $aStylesheetFiles
|
||||
* @param string $sThemeId : used only for logging purpose
|
||||
*
|
||||
* @return array complete path of the images, but with slashes as dir separator instead of DIRECTORY_SEPARATOR
|
||||
* @since 3.0.0
|
||||
*/
|
||||
public static function GetIncludedImages($aThemeParametersVariables, $aStylesheetFiles, $sThemeId)
|
||||
{
|
||||
$sTargetThemeFolderPath = static::GetCompiledThemeFolderAbsolutePath($sThemeId);
|
||||
|
||||
$aCompleteUrls = [];
|
||||
$aToCompleteUrls = [];
|
||||
$aMissingVariables = [];
|
||||
$aFoundVariables = ['version'=>''];
|
||||
$aMap = [
|
||||
'aCompleteUrls' => $aCompleteUrls,
|
||||
'aToCompleteUrls' => $aToCompleteUrls,
|
||||
'aMissingVariables' => $aMissingVariables,
|
||||
'aFoundVariables' => $aFoundVariables,
|
||||
];
|
||||
|
||||
foreach ($aStylesheetFiles as $sStylesheetFile)
|
||||
{
|
||||
$aRes = static::GetAllUrlFromScss($aThemeParametersVariables, $sStylesheetFile);
|
||||
/** @var array $aVal */
|
||||
foreach($aMap as $key => $aVal)
|
||||
{
|
||||
if (array_key_exists($key, $aMap))
|
||||
{
|
||||
$aMap[$key] = array_merge($aVal, $aRes[$key]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$aMap = static::ResolveUncompleteUrlsFromScss($aMap, $aThemeParametersVariables, $aStylesheetFiles);
|
||||
$aImages = [];
|
||||
|
||||
foreach ($aMap ['aCompleteUrls'] as $sUri => $sUrl)
|
||||
{
|
||||
$sImg = $sUrl;
|
||||
if (preg_match("/(.*)\?/", $sUrl, $aMatches))
|
||||
{
|
||||
$sImg=$aMatches[1];
|
||||
}
|
||||
|
||||
if (static::HasImageExtension($sImg)
|
||||
&& ! array_key_exists($sImg, $aImages))
|
||||
{
|
||||
$sFilePath = realpath($sImg);
|
||||
if ($sFilePath !== false) {
|
||||
$sFilePathWithSlashes = str_replace('\\', '/', $sFilePath);
|
||||
$aImages[$sImg] = $sFilePathWithSlashes;
|
||||
continue;
|
||||
}
|
||||
|
||||
$sCanonicalPath = static::CanonicalizePath($sTargetThemeFolderPath.'/'.$sImg);
|
||||
$sFilePath = realpath($sCanonicalPath);
|
||||
if ($sFilePath !== false) {
|
||||
$sFilePathWithSlashes = str_replace('\\', '/', $sFilePath);
|
||||
$aImages[$sImg] = $sFilePathWithSlashes;
|
||||
continue;
|
||||
}
|
||||
|
||||
SetupLog::Warning("Cannot find $sCanonicalPath ($sImg) during SCSS $sThemeId precompilation");
|
||||
}
|
||||
}
|
||||
|
||||
return array_values($aImages);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reduce path without using realpath (works only when file exists)
|
||||
* @param $path
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function CanonicalizePath($path)
|
||||
{
|
||||
$path = explode('/', str_replace('//','/', $path));
|
||||
$stack = array();
|
||||
foreach ($path as $seg) {
|
||||
if ($seg == '..') {
|
||||
// Ignore this segment, remove last segment from stack
|
||||
array_pop($stack);
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($seg == '.') {
|
||||
// Ignore this segment
|
||||
continue;
|
||||
}
|
||||
|
||||
$stack[] = $seg;
|
||||
}
|
||||
|
||||
return implode('/', $stack);
|
||||
}
|
||||
|
||||
/**
|
||||
* Complete url using provided variables. Example with $var=1: XX + $var => XX1
|
||||
* @param $aMap
|
||||
* @param $aThemeParametersVariables
|
||||
* @param $aStylesheetFile
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public static function ResolveUncompleteUrlsFromScss($aMap, $aThemeParametersVariables, $aStylesheetFile)
|
||||
{
|
||||
$sContent="";
|
||||
foreach ($aStylesheetFile as $sStylesheetFile)
|
||||
{
|
||||
if (is_file($sStylesheetFile))
|
||||
{
|
||||
$sContent .= '\n' . file_get_contents($sStylesheetFile);
|
||||
}
|
||||
}
|
||||
|
||||
$aMissingVariables=$aMap['aMissingVariables'];
|
||||
$aFoundVariables=$aMap['aFoundVariables'];
|
||||
$aToCompleteUrls=$aMap['aToCompleteUrls'];
|
||||
$aCompleteUrls=$aMap['aCompleteUrls'];
|
||||
list($aMissingVariables, $aFoundVariables) = static::FindMissingVariables($aThemeParametersVariables, $aMissingVariables, $aFoundVariables, $sContent, true);
|
||||
list($aToCompleteUrls, $aCompleteUrls) = static::ResolveUrls($aFoundVariables, $aToCompleteUrls, $aCompleteUrls);
|
||||
$aMap['aMissingVariables']=$aMissingVariables;
|
||||
$aMap['aFoundVariables']=$aFoundVariables;
|
||||
$aMap['aToCompleteUrls']=$aToCompleteUrls;
|
||||
$aMap['aCompleteUrls']=$aCompleteUrls;
|
||||
return $aMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find missing variable values from SCSS content based on their name.
|
||||
*
|
||||
* @param $aThemeParametersVariables
|
||||
* @param $aMissingVariables
|
||||
* @param $aFoundVariables
|
||||
* @param $sContent : scss content
|
||||
* @param bool $bForceEmptyValueWhenNotFound
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function FindMissingVariables($aThemeParametersVariables, $aMissingVariables, $aFoundVariables, $sContent, $bForceEmptyValueWhenNotFound=false)
|
||||
{
|
||||
$aNewMissingVars = [];
|
||||
if (!empty($aMissingVariables))
|
||||
{
|
||||
foreach ($aMissingVariables as $var)
|
||||
{
|
||||
if (array_key_exists($var, $aThemeParametersVariables))
|
||||
{
|
||||
$aFoundVariables[$var] = $aThemeParametersVariables[$var];
|
||||
}
|
||||
else
|
||||
{
|
||||
if (preg_match_all("/\\\$$var\s*:\s*[\"']{0,1}(.*)[\"']{0,1};/", $sContent, $aValues))
|
||||
{
|
||||
$sValue = $aValues[1][0];
|
||||
if (preg_match_all("/([^!]+)!/", $sValue, $aSubValues))
|
||||
{
|
||||
$sValue = trim($aSubValues[1][0], ' "\'');
|
||||
}
|
||||
|
||||
if (strpos($sValue, '$') === false)
|
||||
{
|
||||
$aFoundVariables[$var] = $sValue;
|
||||
}
|
||||
else{
|
||||
$aNewMissingVars[] = $var;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if ($bForceEmptyValueWhenNotFound)
|
||||
{
|
||||
$aFoundVariables[$var] = '';
|
||||
}
|
||||
else
|
||||
{
|
||||
$aNewMissingVars[] = $var;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return [ $aNewMissingVars, $aFoundVariables ];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $aFoundVariables
|
||||
* @param array $aToCompleteUrls
|
||||
* @param array $aCompleteUrls
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function ResolveUrls($aFoundVariables, array $aToCompleteUrls, array $aCompleteUrls)
|
||||
{
|
||||
if (!empty($aFoundVariables))
|
||||
{
|
||||
$aFoundVariablesWithEmptyValue = [];
|
||||
foreach ($aFoundVariables as $aFoundVariable => $sValue)
|
||||
{
|
||||
$aFoundVariablesWithEmptyValue[$aFoundVariable] = '';
|
||||
}
|
||||
|
||||
foreach ($aToCompleteUrls as $sUrlTemplate)
|
||||
{
|
||||
unset($aToCompleteUrls[$sUrlTemplate]);
|
||||
$sResolvedUrl = static::ResolveUrl($sUrlTemplate, $aFoundVariables);
|
||||
if ($sResolvedUrl == false)
|
||||
{
|
||||
$aToCompleteUrls[$sUrlTemplate] = $sUrlTemplate;
|
||||
}
|
||||
else
|
||||
{
|
||||
$sUri = static::ResolveUrl($sUrlTemplate, $aFoundVariablesWithEmptyValue);
|
||||
$aExplodedUri = explode('?', $sUri);
|
||||
if (empty($aExplodedUri))
|
||||
{
|
||||
$aCompleteUrls[$sUri] = $sResolvedUrl;
|
||||
}
|
||||
else
|
||||
{
|
||||
$aCompleteUrls[$aExplodedUri[0]] = $sResolvedUrl;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return [ $aToCompleteUrls, $aCompleteUrls];
|
||||
}
|
||||
|
||||
/**
|
||||
* Find all referenced URLs from a SCSS file.
|
||||
* @param $aThemeParametersVariables
|
||||
* @param $sStylesheetFile
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function GetAllUrlFromScss($aThemeParametersVariables, $sStylesheetFile)
|
||||
{
|
||||
$aCompleteUrls = [];
|
||||
$aToCompleteUrls = [];
|
||||
$aMissingVariables = [];
|
||||
$aFoundVariables = [];
|
||||
|
||||
if (is_file($sStylesheetFile))
|
||||
{
|
||||
$sContent = file_get_contents($sStylesheetFile);
|
||||
if (preg_match_all("/url\s*\((.*)\)/", $sContent, $aMatches))
|
||||
{
|
||||
foreach ($aMatches[1] as $path)
|
||||
{
|
||||
if (!array_key_exists($path, $aCompleteUrls)
|
||||
&& !array_key_exists($path, $aToCompleteUrls))
|
||||
{
|
||||
if (preg_match_all("/\\$([\w\-_]+)/", $path, $aCurrentVars))
|
||||
{
|
||||
/** @var string $aCurrentVars */
|
||||
foreach ($aCurrentVars[1] as $var)
|
||||
{
|
||||
if (!array_key_exists($var, $aMissingVariables))
|
||||
{
|
||||
$aMissingVariables[$var] = $var;
|
||||
}
|
||||
}
|
||||
$aToCompleteUrls[$path] = $path;
|
||||
}
|
||||
else
|
||||
{
|
||||
$aCompleteUrls[$path] = trim($path, "\"'");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!empty($aMissingVariables))
|
||||
{
|
||||
list($aMissingVariables, $aFoundVariables) = static::FindMissingVariables($aThemeParametersVariables, $aMissingVariables, $aFoundVariables, $sContent);
|
||||
list($aToCompleteUrls, $aCompleteUrls) = static::ResolveUrls($aFoundVariables, $aToCompleteUrls, $aCompleteUrls);
|
||||
}
|
||||
}
|
||||
|
||||
return [
|
||||
'aCompleteUrls' => $aCompleteUrls,
|
||||
'aToCompleteUrls' => $aToCompleteUrls,
|
||||
'aMissingVariables' => $aMissingVariables,
|
||||
'aFoundVariables' => $aFoundVariables
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate url based on its template + variables.
|
||||
* @param $sUrlTemplate
|
||||
* @param $aFoundVariables
|
||||
*
|
||||
* @return bool|string
|
||||
*/
|
||||
public static function ResolveUrl($sUrlTemplate, $aFoundVariables)
|
||||
{
|
||||
$aPattern= [];
|
||||
$aReplacement= [];
|
||||
foreach ($aFoundVariables as $aFoundVariable => $aFoundVariableValue)
|
||||
{
|
||||
//XX + $key + YY
|
||||
$aPattern[]="/['\"]\s*\+\s*\\\$" . $aFoundVariable . "[\s\+]+\s*['\"]/";
|
||||
$aReplacement[]=$aFoundVariableValue;
|
||||
//$key + YY
|
||||
$aPattern[]="/\\\$" . $aFoundVariable. "[\s\+]+\s*['\"]/";
|
||||
$aReplacement[]=$aFoundVariableValue;
|
||||
//XX + $key
|
||||
$aPattern[]="/['\"]\s*[\+\s]+\\\$" . $aFoundVariable . "$/";
|
||||
$aReplacement[]=$aFoundVariableValue;
|
||||
}
|
||||
$sResolvedUrl=preg_replace($aPattern, $aReplacement, $sUrlTemplate);
|
||||
if (strpos($sResolvedUrl, "+")!==false)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return trim($sResolvedUrl, "\"'");
|
||||
}
|
||||
|
||||
/**
|
||||
* indicate whether a string ends with image suffix.
|
||||
* @param $path
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
private static function HasImageExtension($path)
|
||||
{
|
||||
foreach (static::IMAGE_EXTENSIONS as $sExt)
|
||||
{
|
||||
if (endsWith($path, $sExt))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Extract the signature for a generated CSS file. The signature MUST be alone one line immediately
|
||||
* followed (on the next line) by the === SIGNATURE END === pattern
|
||||
*
|
||||
* Note the signature can be place anywhere in the CSS file (obviously inside a CSS comment !) but the
|
||||
* function will be faster if the signature is at the beginning of the file (since the file is scanned from the start)
|
||||
*
|
||||
* @param $sFilepath
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function GetSignature($sFilepath)
|
||||
{
|
||||
$sPreviousLine = '';
|
||||
$hFile = @fopen($sFilepath, "r");
|
||||
if ($hFile !== false)
|
||||
{
|
||||
$sLine = '';
|
||||
do
|
||||
{
|
||||
$sPreviousLine = $sLine;
|
||||
$sLine = rtrim(fgets($hFile)); // Remove the trailing \n
|
||||
}
|
||||
while (($sLine !== false) && ($sLine != '=== SIGNATURE END ==='));
|
||||
fclose($hFile);
|
||||
}
|
||||
return $sPreviousLine;
|
||||
}
|
||||
|
||||
public static function GetVarSignature($JsonSignature)
|
||||
{
|
||||
$aJsonArray = json_decode($JsonSignature, true);
|
||||
if (array_key_exists('variables', $aJsonArray))
|
||||
{
|
||||
return $aJsonArray['variables'];
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the given file in the list of ImportsPaths directory
|
||||
* @param string $sFile
|
||||
* @param string[] $aImportsPaths
|
||||
* @throws Exception
|
||||
* @return string
|
||||
*/
|
||||
public static function FindStylesheetFile($sFile, $aImportsPaths)
|
||||
{
|
||||
foreach($aImportsPaths as $sPath)
|
||||
{
|
||||
$sImportedFile = realpath($sPath.'/'.$sFile);
|
||||
if (file_exists($sImportedFile))
|
||||
{
|
||||
return $sImportedFile;
|
||||
}
|
||||
}
|
||||
return ''; // Not found, fail silently, maybe the SCSS compiler knowns better...
|
||||
}
|
||||
|
||||
public static function MockCompileCSSService($oCompileCSSServiceMock)
|
||||
{
|
||||
static::$oCompileCSSService = $oCompileCSSServiceMock;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clone variable array and include $version with bSetupCompilationTimestamp value
|
||||
* @param $aThemeParameters
|
||||
* @param $bSetupCompilationTimestamp
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function CloneThemeParameterAndIncludeVersion($aThemeParameters, $bSetupCompilationTimestamp)
|
||||
{
|
||||
$aThemeParametersVariable = [];
|
||||
if (array_key_exists('variables', $aThemeParameters))
|
||||
{
|
||||
if (is_array($aThemeParameters['variables']))
|
||||
{
|
||||
$aThemeParametersVariable = array_merge([], $aThemeParameters['variables']);
|
||||
}
|
||||
}
|
||||
|
||||
$aThemeParametersVariable['$version'] = $bSetupCompilationTimestamp;
|
||||
return $aThemeParametersVariable;
|
||||
}
|
||||
}
|
||||
|
||||
class CompileCSSService
|
||||
{
|
||||
/**
|
||||
* CompileCSSService constructor.
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
}
|
||||
|
||||
public function CompileCSSFromSASS($sSassContent, $aImportPaths = [], $aVariables = []){
|
||||
return utils::CompileCSSFromSASS($sSassContent, $aImportPaths, $aVariables);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -17,7 +17,6 @@
|
||||
* 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');
|
||||
|
||||
/**
|
||||
@@ -68,6 +67,7 @@ class UIExtKeyWidget
|
||||
protected $iId;
|
||||
protected $sTargetClass;
|
||||
protected $sAttCode;
|
||||
//@deprecated
|
||||
protected $bSearchMode;
|
||||
|
||||
//public function __construct($sAttCode, $sClass, $sTitle, $oAllowedValues, $value, $iInputId, $bMandatory, $sNameSuffix = '', $sFieldPrefix = '', $sFormPrefix = '')
|
||||
@@ -86,7 +86,29 @@ class UIExtKeyWidget
|
||||
$sDisplayStyle = 'select'; // In search mode, always use a drop-down list
|
||||
}
|
||||
$oWidget = new UIExtKeyWidget($sTargetClass, $iInputId, $sAttCode, $bSearchMode);
|
||||
return $oWidget->Display($oPage, $iMaxComboLength, $bAllowTargetCreation, $sTitle, $oAllowedValues, $value, $iInputId, $bMandatory, $sFieldName, $sFormPrefix, $aArgs, null, $sDisplayStyle);
|
||||
if(!$bSearchMode)
|
||||
{
|
||||
switch($sDisplayStyle)
|
||||
{
|
||||
case 'radio':
|
||||
case 'radio_horizontal':
|
||||
case 'radio_vertical':
|
||||
|
||||
return $oWidget->DisplayRadio($oPage, $iMaxComboLength, $bAllowTargetCreation, $oAllowedValues, $value, $sFieldName, $sDisplayStyle);
|
||||
break;
|
||||
|
||||
case 'select':
|
||||
case 'list':
|
||||
default:
|
||||
return $oWidget->DisplaySelect($oPage, $iMaxComboLength, $bAllowTargetCreation, $sTitle, $oAllowedValues, $value,
|
||||
$bMandatory, $sFieldName, $sFormPrefix, $aArgs);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return $oWidget->Display($oPage, $iMaxComboLength, $bAllowTargetCreation, $sTitle, $oAllowedValues, $value, $iInputId, $bMandatory, $sFieldName, $sFormPrefix, $aArgs, null, $sDisplayStyle);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public function __construct($sTargetClass, $iInputId, $sAttCode = '', $bSearchMode = false)
|
||||
@@ -98,6 +120,291 @@ class UIExtKeyWidget
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 3.0.0 N°2508 - Include Obsolescence icon within list and autocomplete
|
||||
* Get the HTML fragment corresponding to the ext key editing widget
|
||||
* @param WebPage $oP The web page used for all the output
|
||||
* @param array $aArgs Extra context arguments
|
||||
* @return string The HTML fragment to be inserted into the page
|
||||
*/
|
||||
public function DisplaySelect(WebPage $oPage, $iMaxComboLength, $bAllowTargetCreation, $sTitle, DBObjectset $oAllowedValues, $value, $bMandatory, $sFieldName, $sFormPrefix = '', $aArgs = array())
|
||||
{
|
||||
$sTitle = addslashes($sTitle);
|
||||
$oPage->add_linked_script('../js/extkeywidget.js');
|
||||
$oPage->add_linked_script('../js/forms-json-utils.js');
|
||||
|
||||
$bCreate = (!$this->bSearchMode) && (UserRights::IsActionAllowed($this->sTargetClass, UR_ACTION_BULK_MODIFY) && $bAllowTargetCreation);
|
||||
$bExtensions = true;
|
||||
$sMessage = Dict::S('UI:Message:EmptyList:UseSearchForm');
|
||||
$sAttrFieldPrefix = ($this->bSearchMode) ? '' : 'attr_';
|
||||
|
||||
$sHTMLValue = "<div class=\"field_input_zone field_input_extkey ibo-input-wrapper ibo-input-select-wrapper\" data-validation=\"untouched\">";
|
||||
$sFilter = addslashes($oAllowedValues->GetFilter()->ToOQL());
|
||||
if($this->bSearchMode)
|
||||
{
|
||||
$sWizHelper = 'null';
|
||||
$sWizHelperJSON = "''";
|
||||
$sJSSearchMode = 'true';
|
||||
}
|
||||
else
|
||||
{
|
||||
if (isset($aArgs['wizHelper']))
|
||||
{
|
||||
$sWizHelper = $aArgs['wizHelper'];
|
||||
}
|
||||
else
|
||||
{
|
||||
$sWizHelper = 'oWizardHelper'.$sFormPrefix;
|
||||
}
|
||||
$sWizHelperJSON = $sWizHelper.'.UpdateWizardToJSON()';
|
||||
$sJSSearchMode = 'false';
|
||||
}
|
||||
if (is_null($oAllowedValues))
|
||||
{
|
||||
throw new Exception('Implementation: null value for allowed values definition');
|
||||
}
|
||||
$oAllowedValues->SetShowObsoleteData(utils::ShowObsoleteData());
|
||||
// Don't automatically launch the search if the table is huge
|
||||
$bDoSearch = !utils::IsHighCardinality($this->sTargetClass);
|
||||
$sJSDoSearch = $bDoSearch ? 'true' : 'false';
|
||||
|
||||
// We just need to compare the number of entries with MaxComboLength, so no need to get the real count.
|
||||
if (!$oAllowedValues->CountExceeds($iMaxComboLength))
|
||||
{
|
||||
// Discrete list of values, use a SELECT or RADIO buttons depending on the config
|
||||
$sHelpText = ''; //$this->oAttDef->GetHelpOnEdition();
|
||||
//$sHTMLValue .= "<div class=\"field_select_wrapper\">\n";
|
||||
$aOptions = [];
|
||||
$sDisplayValue = "";
|
||||
|
||||
$aOption = [];
|
||||
$aOption['value'] = "";
|
||||
$aOption['label'] = Dict::S('UI:SelectOne');
|
||||
array_push($aOptions,$aOption);
|
||||
|
||||
$oAllowedValues->Rewind();
|
||||
$bAddingValue=false;
|
||||
|
||||
$aComplementAttributeSpec = MetaModel::GetComplementAttributeSpec($oAllowedValues->GetClass());
|
||||
$sFormatAdditionalField = $aComplementAttributeSpec[0];
|
||||
$aAdditionalField = $aComplementAttributeSpec[1];
|
||||
|
||||
if (count($aAdditionalField)>0)
|
||||
{
|
||||
$bAddingValue=true;
|
||||
}
|
||||
while($oObj = $oAllowedValues->Fetch())
|
||||
{
|
||||
$aOption=[];
|
||||
$aOption['value'] = $oObj->GetKey();
|
||||
$aOption['label'] = $oObj->GetName();//.'<span class=\"object-ref-icon fas fa-eye-slash object-obsolete fa-1x fa-fw\"></span>';
|
||||
|
||||
if (($oAllowedValues->Count() == 1) && ($bMandatory == 'true') )
|
||||
{
|
||||
// When there is only once choice, select it by default
|
||||
$sDisplayValue=$oObj->GetName();
|
||||
if($value != $oObj->GetKey())
|
||||
{
|
||||
$oPage->add_ready_script(
|
||||
<<<EOF
|
||||
$('#$this->iId').attr('data-validate','dependencies');
|
||||
EOF
|
||||
);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((is_array($value) && in_array($oObj->GetKey(), $value)) || ($value == $oObj->GetKey()))
|
||||
{
|
||||
$sDisplayValue=$oObj->GetKey();
|
||||
// $sHTMLValue.="<div class='item' data-value='".$oObj->GetKey)."'>".$oObj->GetName()."</div>";
|
||||
}
|
||||
}
|
||||
if ($oObj->IsObsolete()){
|
||||
$aOption['obsolescence_flag'] ="1";
|
||||
}
|
||||
if ($bAddingValue)
|
||||
{
|
||||
$aArguments = [];
|
||||
foreach ($aAdditionalField as $sAdditionalField)
|
||||
{
|
||||
array_push($aArguments,$oObj->Get($sAdditionalField));
|
||||
}
|
||||
$aOption['additional_field'] = vsprintf($sFormatAdditionalField, $aArguments);
|
||||
}
|
||||
array_push($aOptions,$aOption);
|
||||
}
|
||||
$sHTMLValue .= "<select title=\"$sHelpText\" name=\"{$sAttrFieldPrefix}{$sFieldName}\" id=\"$this->iId\"></select>";
|
||||
$sJsonOptions=json_encode($aOptions);
|
||||
$oPage->add_ready_script(
|
||||
<<<EOF
|
||||
oACWidget_{$this->iId} = new ExtKeyWidget('{$this->iId}', '{$this->sTargetClass}', '$sFilter', '$sTitle', true, $sWizHelper, '{$this->sAttCode}', $sJSSearchMode, $sJSDoSearch);
|
||||
oACWidget_{$this->iId}.emptyHtml = "<div style=\"background: #fff; border:0; text-align:center; vertical-align:middle;\"><p>$sMessage</p></div>";
|
||||
oACWidget_{$this->iId}.AddSelectize('$sJsonOptions','$sDisplayValue');
|
||||
$('#$this->iId').bind('update', function() { oACWidget_{$this->iId}.Update(); } );
|
||||
$('#$this->iId').bind('change', function() { $(this).trigger('extkeychange') } );
|
||||
|
||||
EOF
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Too many choices, use an autocomplete
|
||||
// Check that the given value is allowed
|
||||
$oSearch = $oAllowedValues->GetFilter();
|
||||
$oSearch->AddCondition('id', $value);
|
||||
$oSet = new DBObjectSet($oSearch);
|
||||
if ($oSet->Count() == 0)
|
||||
{
|
||||
$value = null;
|
||||
}
|
||||
|
||||
if (is_null($value) || ($value == 0)) // Null values are displayed as ''
|
||||
{
|
||||
$sDisplayValue = isset($aArgs['sDefaultValue']) ? $aArgs['sDefaultValue'] : '';
|
||||
}
|
||||
else
|
||||
{
|
||||
$sDisplayValue = $this->GetObjectName($value);
|
||||
}
|
||||
$iMinChars = isset($aArgs['iMinChars']) ? $aArgs['iMinChars'] : 2; //@@@ $this->oAttDef->GetMinAutoCompleteChars();
|
||||
|
||||
// the input for the auto-complete
|
||||
$sHTMLValue .= "<input class=\"field_autocomplete ibo-input ibo-input-select ibo-input-select-autocomplete\" type=\"text\" id=\"label_$this->iId\" value=\"$sDisplayValue\"/>";
|
||||
$sHTMLValue .= "<div class=\"field_input_btn ibo-input-select--action-button ibo-input-select--action-button--search\" id=\"mini_search_{$this->iId}\" onClick=\"oACWidget_{$this->iId}.Search();\"><i class=\"fas fa-search\"></i></div>";
|
||||
|
||||
// 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";
|
||||
|
||||
$JSSearchMode = $this->bSearchMode ? 'true' : 'false';
|
||||
// Scripts to start the autocomplete and bind some events to it
|
||||
$oPage->add_ready_script(
|
||||
<<<EOF
|
||||
oACWidget_{$this->iId} = new ExtKeyWidget('{$this->iId}', '{$this->sTargetClass}', '$sFilter', '$sTitle', false, $sWizHelper, '{$this->sAttCode}', $sJSSearchMode, $sJSDoSearch);
|
||||
oACWidget_{$this->iId}.emptyHtml = "<div style=\"background: #fff; border:0; text-align:center; vertical-align:middle;\"><p>$sMessage</p></div>";
|
||||
oACWidget_{$this->iId}.AddAutocomplete($iMinChars, $sWizHelperJSON);
|
||||
if ($('#ac_dlg_{$this->iId}').length == 0)
|
||||
{
|
||||
$('body').append('<div id="ac_dlg_{$this->iId}"></div>');
|
||||
}
|
||||
EOF
|
||||
);
|
||||
}
|
||||
if ($bExtensions && MetaModel::IsHierarchicalClass($this->sTargetClass) !== false)
|
||||
{
|
||||
$sHTMLValue .= "<div class=\"field_input_btn ibo-input-select--action-button ibo-input-select--action-button--hierarchy\" id=\"mini_tree_{$this->iId}\" onClick=\"oACWidget_{$this->iId}.HKDisplay();\"><i class=\"fas fa-sitemap\"></i></div>";
|
||||
$oPage->add_ready_script(
|
||||
<<<JS
|
||||
if ($('#ac_tree_{$this->iId}').length == 0)
|
||||
{
|
||||
$('body').append('<div id="ac_tree_{$this->iId}"></div>');
|
||||
}
|
||||
JS
|
||||
);
|
||||
}
|
||||
if ($bCreate && $bExtensions)
|
||||
{
|
||||
$sCallbackName = (MetaModel::IsAbstract($this->sTargetClass)) ? 'SelectObjectClass' : 'CreateObject';
|
||||
|
||||
$sHTMLValue .= "<div class=\"field_input_btn ibo-input-select--action-button ibo-input-select--action-button--create\" id=\"mini_add_{$this->iId}\" onClick=\"oACWidget_{$this->iId}.{$sCallbackName}();\"><i class=\"fas fa-plus\"></i></div>";
|
||||
$oPage->add_ready_script(
|
||||
<<<JS
|
||||
if ($('#ajax_{$this->iId}').length == 0)
|
||||
{
|
||||
$('body').append('<div id="ajax_{$this->iId}"></div>');
|
||||
}
|
||||
JS
|
||||
);
|
||||
}
|
||||
$sHTMLValue .= "</div>";
|
||||
$sHTMLValue .= "<span class=\"form_validation ibo-field-validation\" id=\"v_{$this->iId}\"></span><span class=\"field_status\" id=\"fstatus_{$this->iId}\"></span>";
|
||||
|
||||
return $sHTMLValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 3.0.0 N°2508 - Include Obsolescence icon within list and autocomplete
|
||||
* Get the HTML fragment corresponding to the ext key editing widget
|
||||
* @param WebPage $oP The web page used for all the output
|
||||
* @param array $aArgs Extra context arguments
|
||||
* @return string The HTML fragment to be inserted into the page
|
||||
*/
|
||||
public function DisplayRadio(WebPage $oPage, $iMaxComboLength, $bAllowTargetCreation, DBObjectset $oAllowedValues, $value, $sFieldName, $sDisplayStyle)
|
||||
{
|
||||
$oPage->add_linked_script('../js/forms-json-utils.js');
|
||||
|
||||
$bCreate = (!$this->bSearchMode) && (UserRights::IsActionAllowed($this->sTargetClass, UR_ACTION_BULK_MODIFY) && $bAllowTargetCreation);
|
||||
$bExtensions = true;
|
||||
$sAttrFieldPrefix = ($this->bSearchMode) ? '' : 'attr_';
|
||||
|
||||
$sHTMLValue = "<div class=\"field_input_zone field_input_extkey\">";
|
||||
|
||||
if (is_null($oAllowedValues))
|
||||
{
|
||||
throw new Exception('Implementation: null value for allowed values definition');
|
||||
}
|
||||
$oAllowedValues->SetShowObsoleteData(utils::ShowObsoleteData());
|
||||
|
||||
// We just need to compare the number of entries with MaxComboLength, so no need to get the real count.
|
||||
if (!$oAllowedValues->CountExceeds($iMaxComboLength))
|
||||
{
|
||||
// Discrete list of values, use a SELECT or RADIO buttons depending on the config
|
||||
$sValidationField = null;
|
||||
|
||||
$bVertical = ($sDisplayStyle != 'radio_horizontal');
|
||||
$bExtensions = false;
|
||||
$oAllowedValues->Rewind();
|
||||
$aAllowedValues = array();
|
||||
while($oObj = $oAllowedValues->Fetch())
|
||||
{
|
||||
$aAllowedValues[$oObj->GetKey()] = $oObj->GetName();
|
||||
}
|
||||
$sHTMLValue .= $oPage->GetRadioButtons($aAllowedValues, $value, $this->iId, "{$sAttrFieldPrefix}{$sFieldName}", false /* $bMandatory will be placed manually */, $bVertical, $sValidationField);
|
||||
$aEventsList[] ='change';
|
||||
}
|
||||
else
|
||||
{
|
||||
$sHTMLValue .= "unable to display. Too much values";
|
||||
}
|
||||
$sHTMLValue .= '<div class="ibo-input-select--action-buttons">';
|
||||
if ($bExtensions && MetaModel::IsHierarchicalClass($this->sTargetClass) !== false)
|
||||
{
|
||||
$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(
|
||||
<<<JS
|
||||
if ($('#ac_tree_{$this->iId}').length == 0)
|
||||
{
|
||||
$('body').append('<div id="ac_tree_{$this->iId}"></div>');
|
||||
}
|
||||
JS
|
||||
);
|
||||
}
|
||||
if ($bCreate && $bExtensions)
|
||||
{
|
||||
$sCallbackName = (MetaModel::IsAbstract($this->sTargetClass)) ? 'SelectObjectClass' : 'CreateObject';
|
||||
|
||||
$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(
|
||||
<<<JS
|
||||
if ($('#ajax_{$this->iId}').length == 0)
|
||||
{
|
||||
$('body').append('<div id="ajax_{$this->iId}"></div>');
|
||||
}
|
||||
JS
|
||||
);
|
||||
}
|
||||
$sHTMLValue .= "</div>";
|
||||
$sHTMLValue .= "</div>";
|
||||
|
||||
// Note: This test is no longer necessary as we changed the markup to extract validation decoration in the standard .field_input_xxx container
|
||||
//if (($sDisplayStyle == 'select') || ($sDisplayStyle == 'list'))
|
||||
//{
|
||||
$sHTMLValue .= "<span class=\"form_validation ibo-field-validation\" id=\"v_{$this->iId}\"></span><span class=\"field_status\" id=\"fstatus_{$this->iId}\"></span>";
|
||||
//}
|
||||
|
||||
return $sHTMLValue;
|
||||
}
|
||||
/**
|
||||
* @deprecated Use DisplayBob
|
||||
* Get the HTML fragment corresponding to the ext key editing widget
|
||||
* @param WebPage $oP The web page used for all the output
|
||||
* @param array $aArgs Extra context arguments
|
||||
@@ -239,7 +546,7 @@ EOF
|
||||
$oPage->add_ready_script("$('.multiselect').multiselect($sJSOptions);");
|
||||
}
|
||||
$oPage->add_ready_script(
|
||||
<<<EOF
|
||||
<<<EOF
|
||||
oACWidget_{$this->iId} = new ExtKeyWidget('{$this->iId}', '{$this->sTargetClass}', '$sFilter', '$sTitle', true, $sWizHelper, '{$this->sAttCode}', $sJSSearchMode, $sJSDoSearch);
|
||||
oACWidget_{$this->iId}.emptyHtml = "<div style=\"background: #fff; border:0; text-align:center; vertical-align:middle;\"><p>$sMessage</p></div>";
|
||||
$('#$this->iId').bind('update', function() { oACWidget_{$this->iId}.Update(); } );
|
||||
@@ -269,10 +576,10 @@ EOF
|
||||
{
|
||||
$sDisplayValue = $this->GetObjectName($value);
|
||||
}
|
||||
$iMinChars = isset($aArgs['iMinChars']) ? $aArgs['iMinChars'] : 3; //@@@ $this->oAttDef->GetMinAutoCompleteChars();
|
||||
$iMinChars = isset($aArgs['iMinChars']) ? $aArgs['iMinChars'] : 2; //@@@ $this->oAttDef->GetMinAutoCompleteChars();
|
||||
|
||||
// the input for the auto-complete
|
||||
$sHTMLValue .= "<input class=\"field_autocomplete\" type=\"text\" id=\"label_$this->iId\" value=\"$sDisplayValue\"/>";
|
||||
$sHTMLValue .= "<input class=\"field_autocomplete ibo-input-select\" type=\"text\" id=\"label_$this->iId\" value=\"$sDisplayValue\"/>";
|
||||
$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
|
||||
@@ -281,106 +588,100 @@ EOF
|
||||
$JSSearchMode = $this->bSearchMode ? 'true' : 'false';
|
||||
// Scripts to start the autocomplete and bind some events to it
|
||||
$oPage->add_ready_script(
|
||||
<<<EOF
|
||||
<<<EOF
|
||||
oACWidget_{$this->iId} = new ExtKeyWidget('{$this->iId}', '{$this->sTargetClass}', '$sFilter', '$sTitle', false, $sWizHelper, '{$this->sAttCode}', $sJSSearchMode, $sJSDoSearch);
|
||||
oACWidget_{$this->iId}.emptyHtml = "<div style=\"background: #fff; border:0; text-align:center; vertical-align:middle;\"><p>$sMessage</p></div>";
|
||||
$('#label_$this->iId').autocomplete(GetAbsoluteUrlAppRoot()+'pages/ajax.render.php', { scroll:true, minChars:{$iMinChars}, autoFill:false, matchContains:true, mustMatch: true, keyHolder:'#{$this->iId}', extraParams:{operation:'ac_extkey', sTargetClass:'{$this->sTargetClass}',sFilter:'$sFilter',bSearchMode:$JSSearchMode, json: function() { return $sWizHelperJSON; } }});
|
||||
$('#label_$this->iId').keyup(function() { if ($(this).val() == '') { $('#$this->iId').val(''); } } ); // Useful for search forms: empty value in the "label", means no value, immediatly !
|
||||
$('#label_$this->iId').result( function(event, data, formatted) { OnAutoComplete('{$this->iId}', event, data, formatted); } );
|
||||
$('#$this->iId').bind('update', function() { oACWidget_{$this->iId}.Update(); } );
|
||||
oACWidget_{$this->iId}.AddAutocomplete($iMinChars, $sWizHelperJSON);
|
||||
if ($('#ac_dlg_{$this->iId}').length == 0)
|
||||
{
|
||||
$('body').append('<div id="ac_dlg_{$this->iId}"></div>');
|
||||
}
|
||||
EOF
|
||||
);
|
||||
);
|
||||
}
|
||||
if ($bExtensions && MetaModel::IsHierarchicalClass($this->sTargetClass) !== false)
|
||||
{
|
||||
$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>";
|
||||
$sHTMLValue .= "<span class=\"field_input_btn\"><div class=\"ibo-input-select--action-button\" id=\"mini_tree_{$this->iId}\" onClick=\"oACWidget_{$this->iId}.HKDisplay();\"><i class=\"fas fa-sitemap\"></i></div></span>";
|
||||
$oPage->add_ready_script(
|
||||
<<<EOF
|
||||
<<<JS
|
||||
if ($('#ac_tree_{$this->iId}').length == 0)
|
||||
{
|
||||
$('body').append('<div id="ac_tree_{$this->iId}"></div>');
|
||||
}
|
||||
EOF
|
||||
JS
|
||||
);
|
||||
}
|
||||
if ($bCreate && $bExtensions)
|
||||
{
|
||||
$sCallbackName = (MetaModel::IsAbstract($this->sTargetClass)) ? 'SelectObjectClass' : 'CreateObject';
|
||||
|
||||
$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>";
|
||||
$sHTMLValue .= "<span class=\"field_input_btn\"><div class=\"ibo-input-select--action-button\" id=\"mini_add_{$this->iId}\" onClick=\"oACWidget_{$this->iId}.{$sCallbackName}();\"><i class=\"fas fa-plus\"></i></div></span>";
|
||||
$oPage->add_ready_script(
|
||||
<<<EOF
|
||||
<<<JS
|
||||
if ($('#ajax_{$this->iId}').length == 0)
|
||||
{
|
||||
$('body').append('<div id="ajax_{$this->iId}"></div>');
|
||||
}
|
||||
EOF
|
||||
JS
|
||||
);
|
||||
}
|
||||
$sHTMLValue .= "</div>";
|
||||
|
||||
// Note: This test is no longer necessary as we changed the markup to extract validation decoration in the standard .field_input_xxx container
|
||||
//if (($sDisplayStyle == 'select') || ($sDisplayStyle == 'list'))
|
||||
//{
|
||||
$sHTMLValue .= "<span class=\"form_validation\" id=\"v_{$this->iId}\"></span><span class=\"field_status\" id=\"fstatus_{$this->iId}\"></span>";
|
||||
//}
|
||||
$sHTMLValue .= "<span class=\"form_validation ibo-field-validation\" id=\"v_{$this->iId}\"></span><span class=\"field_status\" id=\"fstatus_{$this->iId}\"></span>";
|
||||
|
||||
return $sHTMLValue;
|
||||
}
|
||||
|
||||
public function GetSearchDialog(WebPage $oPage, $sTitle, $oCurrObject = null)
|
||||
{
|
||||
$sHTML = '<div class="wizContainer" style="vertical-align:top;"><div id="dc_'.$this->iId.'">';
|
||||
$oPage->add('<div class="wizContainer" style="vertical-align:top;"><div id="dc_'.$this->iId.'">');
|
||||
|
||||
if ( ($oCurrObject != null) && ($this->sAttCode != ''))
|
||||
{
|
||||
if (($oCurrObject != null) && ($this->sAttCode != '')) {
|
||||
$oAttDef = MetaModel::GetAttributeDef(get_class($oCurrObject), $this->sAttCode);
|
||||
/** @var \DBObject $oCurrObject */
|
||||
$aArgs = $oCurrObject->ToArgsForQuery();
|
||||
$aParams = array('query_params' => $aArgs);
|
||||
$oSet = $oAttDef->GetAllowedValuesAsObjectSet($aArgs);
|
||||
$oFilter = $oSet->GetFilter();
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
$aParams = array();
|
||||
$oFilter = new DBObjectSearch($this->sTargetClass);
|
||||
}
|
||||
$oFilter->SetModifierProperty('UserRightsGetSelectFilter', 'bSearchMode', $this->bSearchMode);
|
||||
$oBlock = new DisplayBlock($oFilter, 'search', false, $aParams);
|
||||
$sHTML .= $oBlock->GetDisplay($oPage, $this->iId,
|
||||
array(
|
||||
'menu' => false,
|
||||
'currentId' => $this->iId,
|
||||
'table_id' => "dr_{$this->iId}",
|
||||
'table_inner_id' => "{$this->iId}_results",
|
||||
'selection_mode' => true,
|
||||
'selection_type' => 'single',
|
||||
'cssCount' => '#count_'.$this->iId)
|
||||
);
|
||||
$sHTML .= "<form id=\"fr_{$this->iId}\" OnSubmit=\"return oACWidget_{$this->iId}.DoOk();\">\n";
|
||||
$sHTML .= "<div id=\"dr_{$this->iId}\" style=\"vertical-align:top;background: #fff;height:100%;overflow:auto;padding:0;border:0;\">\n";
|
||||
$sHTML .= "<div style=\"background: #fff; border:0; text-align:center; vertical-align:middle;\"><p>".Dict::S('UI:Message:EmptyList:UseSearchForm')."</p></div>\n";
|
||||
$sHTML .= "</div>\n";
|
||||
$sHTML .= "<input type=\"button\" id=\"btn_cancel_{$this->iId}\" value=\"".Dict::S('UI:Button:Cancel')."\" onClick=\"$('#ac_dlg_{$this->iId}').dialog('close');\"> ";
|
||||
$sHTML .= "<input type=\"button\" id=\"btn_ok_{$this->iId}\" value=\"".Dict::S('UI:Button:Ok')."\" onClick=\"oACWidget_{$this->iId}.DoOk();\">";
|
||||
$sHTML .= "<input type=\"hidden\" id=\"count_{$this->iId}\" value=\"0\">";
|
||||
$sHTML .= "</form>\n";
|
||||
$sHTML .= '</div></div>';
|
||||
$oPage->AddUiBlock($oBlock->GetDisplay($oPage, $this->iId,
|
||||
array(
|
||||
'menu' => false,
|
||||
'currentId' => $this->iId,
|
||||
'table_id' => "dr_{$this->iId}",
|
||||
'table_inner_id' => "{$this->iId}_results",
|
||||
'selection_mode' => true,
|
||||
'selection_type' => 'single',
|
||||
'cssCount' => '#count_'.$this->iId
|
||||
)
|
||||
));
|
||||
$sCancel = Dict::S('UI:Button:Cancel');
|
||||
$sOK = Dict::S('UI:Button:Ok');
|
||||
$sEmptyList = Dict::S('UI:Message:EmptyList:UseSearchForm');
|
||||
$oPage->add(<<<HTML
|
||||
<form id="fr_{$this->iId}" OnSubmit="return oACWidget_{$this->iId}.DoOk();">
|
||||
<div id="dr_{$this->iId}" style="vertical-align:top;background: #fff;height:100%;overflow:auto;padding:0;border:0;">
|
||||
<div style="background: #fff; border:0; text-align:center; vertical-align:middle;"><p>{$sEmptyList}</p></div>
|
||||
</div>
|
||||
<input type="button" id="btn_cancel_{$this->iId}" value="{$sCancel}" onClick="$('#ac_dlg_{$this->iId}').dialog('close');">
|
||||
<input type="button" id="btn_ok_{$this->iId}_results" value="{$sOK}" onClick="oACWidget_{$this->iId}.DoOk();">
|
||||
<input type="hidden" id="count_{$this->iId}_results" value="0">
|
||||
</form>
|
||||
</div></div>
|
||||
HTML
|
||||
);
|
||||
|
||||
$sDialogTitle = addslashes($sTitle);
|
||||
$oPage->add_ready_script(
|
||||
<<<EOF
|
||||
$oPage->add_ready_script(<<<JS
|
||||
$('#ac_dlg_{$this->iId}').dialog({ width: $(window).width()*0.8, height: $(window).height()*0.8, autoOpen: false, modal: true, title: '$sDialogTitle', resizeStop: oACWidget_{$this->iId}.UpdateSizes, close: oACWidget_{$this->iId}.OnClose });
|
||||
$('#fs_{$this->iId}').bind('submit.uiAutocomplete', oACWidget_{$this->iId}.DoSearchObjects);
|
||||
$('#dc_{$this->iId}').resize(oACWidget_{$this->iId}.UpdateSizes);
|
||||
EOF
|
||||
);
|
||||
$oPage->add($sHTML);
|
||||
JS
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -436,32 +737,53 @@ EOF
|
||||
|
||||
// Current extkey value, so we can display event if it is not available anymore (eg. archived).
|
||||
$iCurrentExtKeyId = (is_null($oObj) || $this->sAttCode === '') ? 0 : $oObj->Get($this->sAttCode);
|
||||
|
||||
$oValuesSet = new ValueSetObjects($sFilter, 'friendlyname'); // Bypass GetName() to avoid the encoding by htmlentities
|
||||
$iMax = 150;
|
||||
$oValuesSet->SetLimit($iMax);
|
||||
$oValuesSet->SetSort(false);
|
||||
$oValuesSet->SetModifierProperty('UserRightsGetSelectFilter', 'bSearchMode', $this->bSearchMode);
|
||||
$oValuesSet->SetLimit($iMax);
|
||||
$aValuesContains = $oValuesSet->GetValues(array('this' => $oObj, 'current_extkey_id' => $iCurrentExtKeyId), $sContains, 'contains');
|
||||
$aValuesContains = $oValuesSet->GetValuesForAutocomplete(array('this' => $oObj, 'current_extkey_id' => $iCurrentExtKeyId), $sContains, 'start_with');
|
||||
asort($aValuesContains);
|
||||
$aValues = array();
|
||||
foreach($aValuesContains as $sKey => $sFriendlyName)
|
||||
$aValues = $aValuesContains;
|
||||
if (sizeof($aValues) < $iMax)
|
||||
{
|
||||
if (!isset($aValues[$sKey]))
|
||||
$aValuesContains = $oValuesSet->GetValuesForAutocomplete(array('this' => $oObj, 'current_extkey_id' => $iCurrentExtKeyId), $sContains, 'contains');
|
||||
asort($aValuesContains);
|
||||
$iSize = sizeof($aValuesContains);
|
||||
foreach ($aValuesContains as $sKey => $sFriendlyName)
|
||||
{
|
||||
$aValues[$sKey] = $sFriendlyName;
|
||||
if (!isset($aValues[$sKey]))
|
||||
{
|
||||
$aValues[$sKey] = $sFriendlyName;
|
||||
if (++$iSize >= $iMax)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
elseif (!in_array($sContains, $aValues))
|
||||
{
|
||||
$aValuesEquals = $oValuesSet->GetValuesForAutocomplete(array('this' => $oObj, 'current_extkey_id' => $iCurrentExtKeyId), $sContains, 'equals');
|
||||
$aValues = array_merge($aValuesEquals, $aValues);
|
||||
}
|
||||
|
||||
switch($sOutputFormat)
|
||||
{
|
||||
case static::ENUM_OUTPUT_FORMAT_JSON:
|
||||
|
||||
$aJsonMap = array();
|
||||
foreach ($aValues as $sKey => $sLabel)
|
||||
foreach ($aValues as $sKey => $aValue)
|
||||
{
|
||||
$aJsonMap[] = array('value' => $sKey, 'label' => $sLabel);
|
||||
if ($aValue['additional_field'] != '')
|
||||
{
|
||||
$aJsonMap[] = array('value' => $sKey, 'label' => $aValue['label'], 'obsolescence_flag' => $aValue['obsolescence_flag'], 'additional_field' => $aValue['additional_field']);
|
||||
}
|
||||
else
|
||||
{
|
||||
$aJsonMap[] = array('value' => $sKey, 'label' => $aValue['label'], 'obsolescence_flag' => $aValue['obsolescence_flag']);
|
||||
}
|
||||
}
|
||||
|
||||
$oP->SetContentType('application/json');
|
||||
@@ -469,9 +791,9 @@ EOF
|
||||
break;
|
||||
|
||||
case static::ENUM_OUTPUT_FORMAT_CSV:
|
||||
foreach($aValues as $sKey => $sFriendlyName)
|
||||
foreach($aValues as $sKey => $aValue)
|
||||
{
|
||||
$oP->add(trim($sFriendlyName)."\t".$sKey."\n");
|
||||
$oP->add(trim($aValue['label'])."\t".$sKey."\n");
|
||||
}
|
||||
break;
|
||||
default:
|
||||
|
||||
@@ -184,7 +184,7 @@ class UILinksWidgetDirect
|
||||
// For security reasons: check that the "proposed" class is actually a subclass of the linked class
|
||||
// and that the current user is allowed to create objects of this class
|
||||
$sRealClass = '';
|
||||
$oPage->add('<div class="wizContainer" style="vertical-align:top;"><div>');
|
||||
//$oPage->add('<div class="wizContainer" style="vertical-align:top;"><div>');
|
||||
$aSubClasses = MetaModel::EnumChildClasses($this->sLinkedClass, ENUM_CHILD_CLASSES_ALL); // Including the specified class itself
|
||||
$aPossibleClasses = array();
|
||||
foreach($aSubClasses as $sCandidateClass)
|
||||
@@ -294,20 +294,17 @@ class UILinksWidgetDirect
|
||||
*/
|
||||
public function GetObjectsSelectionDlg($oPage, $oCurrentObj, $aAlreadyLinked, $aPrefillFormParam = array())
|
||||
{
|
||||
$sHtml = "<div class=\"wizContainer\" style=\"vertical-align:top;\">\n";
|
||||
//$oPage->add("<div class=\"wizContainer\" style=\"vertical-align:top;\">\n");
|
||||
|
||||
$oHiddenFilter = new DBObjectSearch($this->sLinkedClass);
|
||||
if (($oCurrentObj != null) && MetaModel::IsSameFamilyBranch($this->sLinkedClass, $this->sClass))
|
||||
{
|
||||
if (($oCurrentObj != null) && MetaModel::IsSameFamilyBranch($this->sLinkedClass, $this->sClass)) {
|
||||
// Prevent linking to self if the linked object is of the same family
|
||||
// and already present in the database
|
||||
if (!$oCurrentObj->IsNew())
|
||||
{
|
||||
if (!$oCurrentObj->IsNew()) {
|
||||
$oHiddenFilter->AddCondition('id', $oCurrentObj->GetKey(), '!=');
|
||||
}
|
||||
}
|
||||
if (count($aAlreadyLinked) > 0)
|
||||
{
|
||||
if (count($aAlreadyLinked) > 0) {
|
||||
$oHiddenFilter->AddCondition('id', $aAlreadyLinked, 'NOTIN');
|
||||
}
|
||||
$oHiddenCriteria = $oHiddenFilter->GetCriteria();
|
||||
@@ -319,18 +316,14 @@ class UILinksWidgetDirect
|
||||
if ($valuesDef === null)
|
||||
{
|
||||
$oFilter = new DBObjectSearch($this->sLinkedClass);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!$valuesDef instanceof ValueSetObjects)
|
||||
{
|
||||
} else {
|
||||
if (!$valuesDef instanceof ValueSetObjects) {
|
||||
throw new Exception('Error: only ValueSetObjects are supported for "allowed_values" in AttributeLinkedSet ('.$this->sClass.'/'.$this->sAttCode.').');
|
||||
}
|
||||
$oFilter = DBObjectSearch::FromOQL($valuesDef->GetFilterExpression());
|
||||
}
|
||||
|
||||
if ($oCurrentObj != null)
|
||||
{
|
||||
if ($oCurrentObj != null) {
|
||||
$this->SetSearchDefaultFromContext($oCurrentObj, $oFilter);
|
||||
|
||||
$aArgs = array_merge($oCurrentObj->ToArgs('this'), $oFilter->GetInternalParams());
|
||||
@@ -339,7 +332,7 @@ class UILinksWidgetDirect
|
||||
$oCurrentObj->PrefillForm('search', $aPrefillFormParam);
|
||||
}
|
||||
$oBlock = new DisplayBlock($oFilter, 'search', false);
|
||||
$sHtml .= $oBlock->GetDisplay($oPage, "SearchFormToAdd_{$this->sInputid}",
|
||||
$oPage->AddUiBlock($oBlock->GetDisplay($oPage, "SearchFormToAdd_{$this->sInputid}",
|
||||
array(
|
||||
'result_list_outer_selector' => "SearchResultsToAdd_{$this->sInputid}",
|
||||
'table_id' => "add_{$this->sInputid}",
|
||||
@@ -349,16 +342,21 @@ class UILinksWidgetDirect
|
||||
'query_params' => $oFilter->GetInternalParams(),
|
||||
'hidden_criteria' => $sHiddenCriteria,
|
||||
)
|
||||
);
|
||||
$sHtml .= "<form id=\"ObjectsAddForm_{$this->sInputid}\">\n";
|
||||
$sHtml .= "<div id=\"SearchResultsToAdd_{$this->sInputid}\" style=\"vertical-align:top;background: #fff;height:100%;overflow:auto;padding:0;border:0;\">\n";
|
||||
$sHtml .= "<div style=\"background: #fff; border:0; text-align:center; vertical-align:middle;\"><p>".Dict::S('UI:Message:EmptyList:UseSearchForm')."</p></div>\n";
|
||||
$sHtml .= "</div>\n";
|
||||
$sHtml .= "<input type=\"hidden\" id=\"count_{$this->sInputid}\" value=\"0\"/>";
|
||||
$sHtml .= "<button type=\"button\" class=\"cancel\">".Dict::S('UI:Button:Cancel')."</button> <button type=\"button\" class=\"ok\" disabled=\"disabled\">".Dict::S('UI:Button:Add')."</button>";
|
||||
$sHtml .= "</div>\n";
|
||||
$sHtml .= "</form>\n";
|
||||
$oPage->add($sHtml);
|
||||
));
|
||||
$sEmptyList = Dict::S('UI:Message:EmptyList:UseSearchForm');
|
||||
$sCancel = Dict::S('UI:Button:Cancel');
|
||||
$sAdd = Dict::S('UI:Button:Add');
|
||||
|
||||
$oPage->add(<<<HTML
|
||||
<form id="ObjectsAddForm_{$this->sInputid}">
|
||||
<div id="SearchResultsToAdd_{$this->sInputid}" style="vertical-align:top;background: #fff;height:100%;overflow:auto;padding:0;border:0;">
|
||||
<div style="background: #fff; border:0; text-align:center; vertical-align:middle;"><p>{$sEmptyList}</p></div>
|
||||
</div>
|
||||
<input type="hidden" id="count_{$this->sInputid}" value="0"/>
|
||||
<button type="button" class="cancel">{$sCancel}</button> <button type="button" class="ok" disabled="disabled">{$sAdd}</button>
|
||||
</form>
|
||||
HTML
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -24,7 +24,10 @@
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
require_once(APPROOT.'application/webpage.class.inc.php');
|
||||
use Combodo\iTop\Application\UI\Component\DataTable\DataTableFactory;
|
||||
use Combodo\iTop\Application\UI\Component\DataTable\StaticTable\FormTableRow\FormTableRow;
|
||||
use Combodo\iTop\Renderer\BlockRenderer;
|
||||
|
||||
require_once(APPROOT.'application/displayblock.class.inc.php');
|
||||
|
||||
class UILinksWidget
|
||||
@@ -39,6 +42,7 @@ class UILinksWidget
|
||||
protected $m_sLinkedClass;
|
||||
protected $m_sRemoteClass;
|
||||
protected $m_bDuplicatesAllowed;
|
||||
/** @var string[] list of editables attcodes */
|
||||
protected $m_aEditableFields;
|
||||
protected $m_aTableConfig;
|
||||
|
||||
@@ -46,7 +50,7 @@ class UILinksWidget
|
||||
* UILinksWidget constructor.
|
||||
*
|
||||
* @param string $sClass
|
||||
* @param string $sAttCode
|
||||
* @param string $sAttCode AttributeLinkedSetIndirect attcode
|
||||
* @param int $iInputId
|
||||
* @param string $sNameSuffix
|
||||
* @param bool $bDuplicatesAllowed
|
||||
@@ -73,41 +77,36 @@ class UILinksWidget
|
||||
/** @var AttributeExternalKey $oLinkingAttDef */
|
||||
$oLinkingAttDef = MetaModel::GetAttributeDef($this->m_sLinkedClass, $this->m_sExtKeyToRemote);
|
||||
$this->m_sRemoteClass = $oLinkingAttDef->GetTargetClass();
|
||||
$sExtKeyToMe = $oAttDef->GetExtKeyToMe();
|
||||
$sStateAttCode = MetaModel::GetStateAttributeCode($this->m_sClass);
|
||||
$sDefaultState = MetaModel::GetDefaultState($this->m_sClass);
|
||||
|
||||
$this->m_aEditableFields = array();
|
||||
$this->m_aTableConfig = array();
|
||||
$this->m_aTableConfig['form::checkbox'] = array( 'label' => "<input class=\"select_all\" type=\"checkbox\" value=\"1\" onClick=\"CheckAll('#linkedset_{$this->m_sAttCode}{$this->m_sNameSuffix} .selection', this.checked); oWidget".$this->m_iInputId.".OnSelectChange();\">", 'description' => Dict::S('UI:SelectAllToggle+'));
|
||||
$this->m_aTableConfig['form::checkbox'] = array(
|
||||
'label' => "<input class=\"select_all\" type=\"checkbox\" value=\"1\" onClick=\"CheckAll('#linkedset_{$this->m_sAttCode}{$this->m_sNameSuffix} .selection', this.checked); oWidget".$this->m_iInputId.".OnSelectChange();\">",
|
||||
'description' => Dict::S('UI:SelectAllToggle+'),
|
||||
);
|
||||
|
||||
foreach(MetaModel::FlattenZList(MetaModel::GetZListItems($this->m_sLinkedClass, 'list')) as $sAttCode)
|
||||
$aLnkAttDefsToDisplay = MetaModel::GetZListAttDefsFilteredForIndirectLinkClass($sClass, $sAttCode);
|
||||
foreach ($aLnkAttDefsToDisplay as $oLnkAttDef)
|
||||
{
|
||||
$oAttDef = MetaModel::GetAttributeDef($this->m_sLinkedClass, $sAttCode);
|
||||
if ($sStateAttCode == $sAttCode)
|
||||
{
|
||||
// State attribute is always hidden from the UI
|
||||
}
|
||||
else if ($oAttDef->IsWritable() && ($sAttCode != $sExtKeyToMe) && ($sAttCode != $this->m_sExtKeyToRemote) && ($sAttCode != 'finalclass'))
|
||||
{
|
||||
$iFlags = MetaModel::GetAttributeFlags($this->m_sLinkedClass, $sDefaultState, $sAttCode);
|
||||
if ( !($iFlags & OPT_ATT_HIDDEN) && !($iFlags & OPT_ATT_READONLY) )
|
||||
{
|
||||
$this->m_aEditableFields[] = $sAttCode;
|
||||
$this->m_aTableConfig[$sAttCode] = array( 'label' => $oAttDef->GetLabel(), 'description' => $oAttDef->GetDescription());
|
||||
}
|
||||
}
|
||||
$sLnkAttCode = $oLnkAttDef->GetCode();
|
||||
$this->m_aEditableFields[] = $sLnkAttCode;
|
||||
$this->m_aTableConfig[$sLnkAttCode] = array('label' => $oLnkAttDef->GetLabel(), 'description' => $oLnkAttDef->GetDescription());
|
||||
}
|
||||
|
||||
$this->m_aTableConfig['static::key'] = array( 'label' => MetaModel::GetName($this->m_sRemoteClass), 'description' => MetaModel::GetClassDescription($this->m_sRemoteClass));
|
||||
foreach(MetaModel::GetZListItems($this->m_sRemoteClass, 'list') as $sFieldCode)
|
||||
|
||||
$this->m_aTableConfig['static::key'] = array(
|
||||
'label' => MetaModel::GetName($this->m_sRemoteClass),
|
||||
'description' => MetaModel::GetClassDescription($this->m_sRemoteClass),
|
||||
);
|
||||
$this->m_aEditableFields[] = $this->m_sExtKeyToRemote;
|
||||
|
||||
$aRemoteAttDefsToDisplay = MetaModel::GetZListAttDefsFilteredForIndirectRemoteClass($this->m_sRemoteClass);
|
||||
foreach ($aRemoteAttDefsToDisplay as $oRemoteAttDef)
|
||||
{
|
||||
// TO DO: check the state of the attribute: hidden or visible ?
|
||||
if ($sFieldCode != 'finalclass')
|
||||
{
|
||||
$oAttDef = MetaModel::GetAttributeDef($this->m_sRemoteClass, $sFieldCode);
|
||||
$this->m_aTableConfig['static::'.$sFieldCode] = array( 'label' => $oAttDef->GetLabel(), 'description' => $oAttDef->GetDescription());
|
||||
}
|
||||
$sRemoteAttCode = $oRemoteAttDef->GetCode();
|
||||
$this->m_aTableConfig['static::'.$sRemoteAttCode] = array(
|
||||
'label' => $oRemoteAttDef->GetLabel(),
|
||||
'description' => $oRemoteAttDef->GetDescription(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -116,7 +115,7 @@ class UILinksWidget
|
||||
*
|
||||
* @param WebPage $oP Web page used for the ouput
|
||||
* @param DBObject $oLinkedObj Remote object
|
||||
* @param mixed $linkObjOrId Either the object linked or a unique number for new link records to add
|
||||
* @param DBObject|int $linkObjOrId Either the lnk object or a unique number for new link records to add
|
||||
* @param array $aArgs Extra context arguments
|
||||
* @param DBObject $oCurrentObj The object to which all the elements of the linked set refer to
|
||||
* @param int $iUniqueId A unique identifier of new links
|
||||
@@ -134,43 +133,39 @@ class UILinksWidget
|
||||
$aRow = array();
|
||||
$aFieldsMap = array();
|
||||
$iKey = 0;
|
||||
if(is_object($linkObjOrId) && (!$linkObjOrId->IsNew()))
|
||||
|
||||
if (is_object($linkObjOrId) && (!$linkObjOrId->IsNew()))
|
||||
{
|
||||
$iKey = $linkObjOrId->GetKey();
|
||||
$iRemoteObjKey = $linkObjOrId->Get($this->m_sExtKeyToRemote);
|
||||
$iRemoteObjKey = $linkObjOrId->Get($this->m_sExtKeyToRemote);
|
||||
$sPrefix .= "[$iKey][";
|
||||
$sNameSuffix = "]"; // To make a tabular form
|
||||
$aArgs['prefix'] = $sPrefix;
|
||||
$aArgs['wizHelper'] = "oWizardHelper{$this->m_iInputId}{$iKey}";
|
||||
$aArgs['this'] = $linkObjOrId;
|
||||
|
||||
if($bReadOnly)
|
||||
{
|
||||
$aRow['form::checkbox'] = "";
|
||||
foreach($this->m_aEditableFields as $sFieldCode)
|
||||
{
|
||||
$sDisplayValue = $linkObjOrId->GetEditValue($sFieldCode);
|
||||
$aRow[$sFieldCode] = $sDisplayValue;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$aRow['form::checkbox'] = "<input class=\"selection\" data-remote-id=\"$iRemoteObjKey\" data-link-id=\"$iKey\" data-unique-id=\"$iUniqueId\" type=\"checkbox\" onClick=\"oWidget".$this->m_iInputId.".OnSelectChange();\" value=\"$iKey\">";
|
||||
foreach($this->m_aEditableFields as $sFieldCode)
|
||||
{
|
||||
$sFieldId = $this->m_iInputId.'_'.$sFieldCode.'['.$linkObjOrId->GetKey().']';
|
||||
$sSafeId = utils::GetSafeId($sFieldId);
|
||||
$sValue = $linkObjOrId->Get($sFieldCode);
|
||||
$sDisplayValue = $linkObjOrId->GetEditValue($sFieldCode);
|
||||
$oAttDef = MetaModel::GetAttributeDef($this->m_sLinkedClass, $sFieldCode);
|
||||
$aRow[$sFieldCode] = '<div class="field_container" style="border:none;"><div class="field_data"><div class="field_value">'.
|
||||
cmdbAbstractObject::GetFormElementForField($oP, $this->m_sLinkedClass, $sFieldCode, $oAttDef, $sValue, $sDisplayValue, $sSafeId, $sNameSuffix, 0, $aArgs).
|
||||
'</div></div></div>';
|
||||
$aFieldsMap[$sFieldCode] = $sSafeId;
|
||||
}
|
||||
}
|
||||
if ($bReadOnly)
|
||||
{
|
||||
$aRow['form::checkbox'] = "";
|
||||
foreach ($this->m_aEditableFields as $sFieldCode)
|
||||
{
|
||||
$sDisplayValue = $linkObjOrId->GetEditValue($sFieldCode);
|
||||
$aRow[$sFieldCode] = $sDisplayValue;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$aRow['form::checkbox'] = "<input class=\"selection\" data-remote-id=\"$iRemoteObjKey\" data-link-id=\"$iKey\" data-unique-id=\"$iUniqueId\" type=\"checkbox\" onClick=\"oWidget".$this->m_iInputId.".OnSelectChange();\" value=\"$iKey\">";
|
||||
foreach ($this->m_aEditableFields as $sFieldCode)
|
||||
{
|
||||
$sSafeFieldId = $this->GetFieldId($linkObjOrId->GetKey(), $sFieldCode);
|
||||
$this->AddRowForFieldCode($aRow, $sFieldCode, $aArgs, $linkObjOrId, $oP, $sNameSuffix, $sSafeFieldId);
|
||||
$aFieldsMap[$sFieldCode] = $sSafeFieldId;
|
||||
}
|
||||
}
|
||||
|
||||
$sState = $linkObjOrId->GetState();
|
||||
$sRemoteKeySafeFieldId = $this->GetFieldId($aArgs['this']->GetKey(), $this->m_sExtKeyToRemote);;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -180,15 +175,18 @@ class UILinksWidget
|
||||
// New link existing only in memory
|
||||
$oNewLinkObj = $linkObjOrId;
|
||||
$iRemoteObjKey = $oNewLinkObj->Get($this->m_sExtKeyToRemote);
|
||||
$oNewLinkObj->Set($this->m_sExtKeyToMe, $oCurrentObj); // Setting the extkey with the object also fills the related external fields
|
||||
$oNewLinkObj->Set($this->m_sExtKeyToMe,
|
||||
$oCurrentObj); // Setting the extkey with the object also fills the related external fields
|
||||
}
|
||||
else
|
||||
{
|
||||
$iRemoteObjKey = $linkObjOrId;
|
||||
$oNewLinkObj = MetaModel::NewObject($this->m_sLinkedClass);
|
||||
$oRemoteObj = MetaModel::GetObject($this->m_sRemoteClass, $iRemoteObjKey);
|
||||
$oNewLinkObj->Set($this->m_sExtKeyToRemote, $oRemoteObj); // Setting the extkey with the object alsoo fills the related external fields
|
||||
$oNewLinkObj->Set($this->m_sExtKeyToMe, $oCurrentObj); // Setting the extkey with the object also fills the related external fields
|
||||
$oNewLinkObj->Set($this->m_sExtKeyToRemote,
|
||||
$oRemoteObj); // Setting the extkey with the object alsoo fills the related external fields
|
||||
$oNewLinkObj->Set($this->m_sExtKeyToMe,
|
||||
$oCurrentObj); // Setting the extkey with the object also fills the related external fields
|
||||
}
|
||||
$sPrefix .= "[-$iUniqueId][";
|
||||
$sNameSuffix = "]"; // To make a tabular form
|
||||
@@ -222,112 +220,150 @@ EOF
|
||||
|
||||
foreach($this->m_aEditableFields as $sFieldCode)
|
||||
{
|
||||
$sFieldId = $this->m_iInputId.'_'.$sFieldCode.'['.-$iUniqueId.']';
|
||||
$sSafeId = utils::GetSafeId($sFieldId);
|
||||
$sSafeFieldId = $this->GetFieldId($iUniqueId, $sFieldCode);
|
||||
$this->AddRowForFieldCode($aRow, $sFieldCode, $aArgs, $oNewLinkObj, $oP, $sNameSuffix, $sSafeFieldId);
|
||||
$aFieldsMap[$sFieldCode] = $sSafeFieldId;
|
||||
|
||||
$sValue = $oNewLinkObj->Get($sFieldCode);
|
||||
$sDisplayValue = $oNewLinkObj->GetEditValue($sFieldCode);
|
||||
$oAttDef = MetaModel::GetAttributeDef($this->m_sLinkedClass, $sFieldCode);
|
||||
$aRow[$sFieldCode] = '<div class="field_container" style="border:none;"><div class="field_data"><div class="field_value">'.
|
||||
cmdbAbstractObject::GetFormElementForField($oP, $this->m_sLinkedClass, $sFieldCode, $oAttDef, $sValue, $sDisplayValue, $sSafeId /* id */, $sNameSuffix, 0, $aArgs).
|
||||
'</div></div></div>';
|
||||
$aFieldsMap[$sFieldCode] = $sSafeId;
|
||||
$oP->add_ready_script(<<<EOF
|
||||
$oP->add_ready_script(
|
||||
<<<JS
|
||||
oWidget{$this->m_iInputId}.OnValueChange($iKey, $iUniqueId, '$sFieldCode', '$sValue');
|
||||
EOF
|
||||
);
|
||||
JS
|
||||
);
|
||||
}
|
||||
|
||||
$sState = '';
|
||||
$sRemoteKeySafeFieldId = $this->GetFieldId($iUniqueId, $this->m_sExtKeyToRemote);
|
||||
}
|
||||
|
||||
if(!$bReadOnly)
|
||||
{
|
||||
$sExtKeyToMeId = utils::GetSafeId($sPrefix.$this->m_sExtKeyToMe);
|
||||
$aFieldsMap[$this->m_sExtKeyToMe] = $sExtKeyToMeId;
|
||||
$aRow['form::checkbox'] .= "<input type=\"hidden\" id=\"$sExtKeyToMeId\" value=\"".$oCurrentObj->GetKey()."\">";
|
||||
|
||||
$sExtKeyToRemoteId = utils::GetSafeId($sPrefix.$this->m_sExtKeyToRemote);
|
||||
$aFieldsMap[$this->m_sExtKeyToRemote] = $sExtKeyToRemoteId;
|
||||
$aRow['form::checkbox'] .= "<input type=\"hidden\" id=\"$sExtKeyToRemoteId\" value=\"$iRemoteObjKey\">";
|
||||
}
|
||||
|
||||
$iFieldsCount = count($aFieldsMap);
|
||||
$sJsonFieldsMap = json_encode($aFieldsMap);
|
||||
|
||||
$oP->add_script(
|
||||
<<<EOF
|
||||
var {$aArgs['wizHelper']} = new WizardHelper('{$this->m_sLinkedClass}', '', '$sState');
|
||||
{$aArgs['wizHelper']}.SetFieldsMap($sJsonFieldsMap);
|
||||
{$aArgs['wizHelper']}.SetFieldsCount($iFieldsCount);
|
||||
EOF
|
||||
);
|
||||
$aRow['static::key'] = $oLinkedObj->GetHyperLink();
|
||||
foreach(MetaModel::GetZListItems($this->m_sRemoteClass, 'list') as $sFieldCode)
|
||||
if (!$bReadOnly)
|
||||
{
|
||||
$aRow['static::'.$sFieldCode] = $oLinkedObj->GetAsHTML($sFieldCode);
|
||||
$sExtKeyToMeId = utils::GetSafeId($sPrefix.$this->m_sExtKeyToMe);
|
||||
$aFieldsMap[$this->m_sExtKeyToMe] = $sExtKeyToMeId;
|
||||
$aRow['form::checkbox'] .= "<input type=\"hidden\" id=\"$sExtKeyToMeId\" value=\"".$oCurrentObj->GetKey()."\">";
|
||||
|
||||
$sExtKeyToRemoteId = utils::GetSafeId($sPrefix.$this->m_sExtKeyToRemote);
|
||||
$aFieldsMap[$this->m_sExtKeyToRemote] = $sExtKeyToRemoteId;
|
||||
$aRow['form::checkbox'] .= "<input type=\"hidden\" id=\"$sExtKeyToRemoteId\" value=\"$iRemoteObjKey\">";
|
||||
}
|
||||
|
||||
// Adding fields from remote class
|
||||
// all fields are embedded in a span + added to $aFieldsMap array so that we can refresh them after extkey change
|
||||
$aRemoteFieldsMap = [];
|
||||
foreach (MetaModel::GetZListItems($this->m_sRemoteClass, 'list') as $sFieldCode)
|
||||
{
|
||||
$sSafeFieldId = $this->GetFieldId($aArgs['this']->GetKey(), $sFieldCode);
|
||||
$aRow['static::'.$sFieldCode] = "<span id='field_$sSafeFieldId'>".$oLinkedObj->GetAsHTML($sFieldCode).'</span>';
|
||||
$aRemoteFieldsMap[$sFieldCode] = $sSafeFieldId;
|
||||
}
|
||||
// id field is needed so that remote object could be load server side
|
||||
$aRemoteFieldsMap['id'] = $sRemoteKeySafeFieldId;
|
||||
|
||||
// Generate WizardHelper to update dependant fields
|
||||
$this->AddWizardHelperInit($oP, $aArgs['wizHelper'], $this->m_sLinkedClass, $sState, $aFieldsMap);
|
||||
//instantiate specific WizarHelper instance for remote class fields refresh
|
||||
$bHasExtKeyUpdatingRemoteClassFields = (
|
||||
array_key_exists('replaceDependenciesByRemoteClassFields', $aArgs)
|
||||
&& ($aArgs['replaceDependenciesByRemoteClassFields'])
|
||||
);
|
||||
if ($bHasExtKeyUpdatingRemoteClassFields)
|
||||
{
|
||||
$this->AddWizardHelperInit($oP, $aArgs['wizHelperRemote'], $this->m_sRemoteClass, $sState, $aRemoteFieldsMap);
|
||||
}
|
||||
|
||||
return $aRow;
|
||||
}
|
||||
|
||||
/**
|
||||
* Display one row of the whole form
|
||||
* @param WebPage $oP
|
||||
* @param array $aConfig
|
||||
* @param array $aRow
|
||||
* @param int $iRowId
|
||||
* @return string
|
||||
*/
|
||||
protected function DisplayFormRow(WebPage $oP, $aConfig, $aRow, $iRowId)
|
||||
private function AddRowForFieldCode(&$aRow, $sFieldCode, &$aArgs, $oLnk, $oP, $sNameSuffix, $sSafeFieldId): void
|
||||
{
|
||||
$sHtml = '';
|
||||
$sHtml .= "<tr id=\"{$this->m_sAttCode}{$this->m_sNameSuffix}_row_$iRowId\">\n";
|
||||
foreach($aConfig as $sName=>$void)
|
||||
if (($sFieldCode === $this->m_sExtKeyToRemote))
|
||||
{
|
||||
$sHtml .= "<td>".$aRow[$sName]."</td>\n";
|
||||
// current field is the lnk extkey to the remote class
|
||||
$aArgs['replaceDependenciesByRemoteClassFields'] = true;
|
||||
$sRowFieldCode = 'static::key';
|
||||
$aArgs['wizHelperRemote'] = $aArgs['wizHelper'].'_remote';
|
||||
$aRemoteAttDefs = MetaModel::GetZListAttDefsFilteredForIndirectRemoteClass($this->m_sRemoteClass);
|
||||
$aRemoteCodes = array_map(
|
||||
function ($value) {
|
||||
return $value->GetCode();
|
||||
},
|
||||
$aRemoteAttDefs
|
||||
);
|
||||
$aArgs['remoteCodes'] = $aRemoteCodes;
|
||||
}
|
||||
$sHtml .= "</tr>\n";
|
||||
|
||||
return $sHtml;
|
||||
else
|
||||
{
|
||||
$aArgs['replaceDependenciesByRemoteClassFields'] = false;
|
||||
$sRowFieldCode = $sFieldCode;
|
||||
}
|
||||
$sValue = $oLnk->Get($sFieldCode);
|
||||
$sDisplayValue = $oLnk->GetEditValue($sFieldCode);
|
||||
$oAttDef = MetaModel::GetAttributeDef($this->m_sLinkedClass, $sFieldCode);
|
||||
|
||||
$aRow[$sRowFieldCode] = '<div class="field_container" style="border:none;"><div class="field_data"><div class="field_value">'
|
||||
.cmdbAbstractObject::GetFormElementForField(
|
||||
$oP,
|
||||
$this->m_sLinkedClass,
|
||||
$sFieldCode,
|
||||
$oAttDef,
|
||||
$sValue,
|
||||
$sDisplayValue,
|
||||
$sSafeFieldId,
|
||||
$sNameSuffix,
|
||||
0,
|
||||
$aArgs
|
||||
)
|
||||
.'</div></div></div>';
|
||||
}
|
||||
|
||||
|
||||
private function GetFieldId($iLnkId, $sFieldCode, $bSafe = true)
|
||||
{
|
||||
$sFieldId = $this->m_iInputId.'_'.$sFieldCode.'['.$iLnkId.']';
|
||||
|
||||
return ($bSafe) ? utils::GetSafeId($sFieldId) : $sFieldId;
|
||||
}
|
||||
|
||||
private function AddWizardHelperInit($oP, $sWizardHelperVarName, $sWizardHelperClass, $sState, $aFieldsMap): void
|
||||
{
|
||||
$iFieldsCount = count($aFieldsMap);
|
||||
$sJsonFieldsMap = json_encode($aFieldsMap);
|
||||
|
||||
$oP->add_script(
|
||||
<<<JS
|
||||
var $sWizardHelperVarName = new WizardHelper('$sWizardHelperClass', '', '$sState');
|
||||
$sWizardHelperVarName.SetFieldsMap($sJsonFieldsMap);
|
||||
$sWizardHelperVarName.SetFieldsCount($iFieldsCount);
|
||||
$sWizardHelperVarName.SetReturnNotEditableFields(true);
|
||||
$sWizardHelperVarName.SetWizHelperJsVarName('$sWizardHelperVarName');
|
||||
JS
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Display the table with the form for editing all the links at once
|
||||
*
|
||||
* @param WebPage $oP The web page used for the output
|
||||
* @param array $aConfig The table's header configuration
|
||||
* @param array $aData The tabular data to be displayed
|
||||
*
|
||||
* @return string Html fragment representing the form table
|
||||
* @throws \ReflectionException
|
||||
* @throws \Twig\Error\LoaderError
|
||||
* @throws \Twig\Error\RuntimeError
|
||||
* @throws \Twig\Error\SyntaxError
|
||||
*/
|
||||
protected function DisplayFormTable(WebPage $oP, $aConfig, $aData)
|
||||
{
|
||||
$sHtml = "<input type=\"hidden\" name=\"attr_{$this->m_sAttCode}{$this->m_sNameSuffix}\" value=\"\">";
|
||||
$sHtml .= "<table class=\"listResults\">\n";
|
||||
// Header
|
||||
$sHtml .= "<thead>\n";
|
||||
$sHtml .= "<tr>\n";
|
||||
foreach($aConfig as $sName=>$aDef)
|
||||
$oTable = DataTableFactory::MakeForForm("{$this->m_sAttCode}{$this->m_sNameSuffix}", $aConfig);
|
||||
|
||||
foreach ($aData as $iRowId => $aRow)
|
||||
{
|
||||
$sHtml .= "<th title=\"".$aDef['description']."\">".$aDef['label']."</th>\n";
|
||||
}
|
||||
$sHtml .= "</tr>\n";
|
||||
$sHtml .= "</thead>\n";
|
||||
|
||||
// Content
|
||||
$sHtml .= "</tbody>\n";
|
||||
$sEmptyRowStyle = '';
|
||||
if (count($aData) != 0)
|
||||
{
|
||||
$sEmptyRowStyle = 'style="display:none;"';
|
||||
$oRow = new FormTableRow("{$this->m_sAttCode}{$this->m_sNameSuffix}", $aConfig, $aRow, $iRowId);
|
||||
$oTable->AddRow($oRow);
|
||||
}
|
||||
|
||||
foreach($aData as $iRowId => $aRow)
|
||||
{
|
||||
$sHtml .= $this->DisplayFormRow($oP, $aConfig, $aRow, $iRowId);
|
||||
}
|
||||
$sHtml .= "<tr $sEmptyRowStyle id=\"{$this->m_sAttCode}{$this->m_sNameSuffix}_empty_row\"><td colspan=\"".count($aConfig)."\" style=\"text-align:center;\">".Dict::S('UI:Message:EmptyList:UseAdd')."</td></tr>";
|
||||
$sHtml .= "</tbody>\n";
|
||||
|
||||
// Footer
|
||||
$sHtml .= "</table>\n";
|
||||
|
||||
$sHtml = BlockRenderer::RenderBlockTemplates($oTable);
|
||||
|
||||
return $sHtml;
|
||||
}
|
||||
|
||||
@@ -360,20 +396,21 @@ EOF
|
||||
$bDoSearch = !utils::IsHighCardinality($this->m_sRemoteClass);
|
||||
$sJSDoSearch = $bDoSearch ? 'true' : 'false';
|
||||
$sWizHelper = 'oWizardHelper'.$sFormPrefix;
|
||||
$oPage->add_ready_script(<<<EOF
|
||||
oWidget{$this->m_iInputId} = new LinksWidget('{$this->m_sAttCode}{$this->m_sNameSuffix}', '{$this->m_sClass}', '{$this->m_sAttCode}', '{$this->m_iInputId}', '{$this->m_sNameSuffix}', $sDuplicates, $sWizHelper, '{$this->m_sExtKeyToRemote}', $sJSDoSearch);
|
||||
oWidget{$this->m_iInputId}.Init();
|
||||
EOF
|
||||
$oPage->add_ready_script(<<<JS
|
||||
oWidget{$this->m_iInputId} = new LinksWidget('{$this->m_sAttCode}{$this->m_sNameSuffix}', '{$this->m_sClass}', '{$this->m_sAttCode}', '{$this->m_iInputId}', '{$this->m_sNameSuffix}', $sDuplicates, $sWizHelper, '{$this->m_sExtKeyToRemote}', $sJSDoSearch);
|
||||
oWidget{$this->m_iInputId}.Init();
|
||||
JS
|
||||
);
|
||||
|
||||
while($oCurrentLink = $oValue->Fetch())
|
||||
while ($oCurrentLink = $oValue->Fetch())
|
||||
{
|
||||
// We try to retrieve the remote object as usual
|
||||
$oLinkedObj = MetaModel::GetObject($this->m_sRemoteClass, $oCurrentLink->Get($this->m_sExtKeyToRemote), false /* Must not be found */);
|
||||
// We try to retrieve the remote object as usual
|
||||
$oLinkedObj = MetaModel::GetObject($this->m_sRemoteClass, $oCurrentLink->Get($this->m_sExtKeyToRemote),
|
||||
false /* Must not be found */);
|
||||
// If successful, it means that we can edit its link
|
||||
if($oLinkedObj !== null)
|
||||
{
|
||||
$bReadOnly = false;
|
||||
if ($oLinkedObj !== null)
|
||||
{
|
||||
$bReadOnly = false;
|
||||
}
|
||||
// Else we retrieve it without restrictions (silos) and will display its link as readonly
|
||||
else
|
||||
@@ -393,6 +430,7 @@ EOF
|
||||
$aForm[$key] = $this->GetFormRow($oPage, $oLinkedObj, $oCurrentLink, $aArgs, $oCurrentObj, $key, $bReadOnly);
|
||||
}
|
||||
$sHtmlValue .= $this->DisplayFormTable($oPage, $this->m_aTableConfig, $aForm);
|
||||
// To prevent adding forms inside the main form
|
||||
|
||||
$sHtmlValue .= "<span style=\"float:left;\"> <img src=\"../images/tv-item-last.gif\"> <input id=\"{$this->m_sAttCode}{$this->m_sNameSuffix}_btnRemove\" type=\"button\" value=\"".Dict::S('UI:RemoveLinkedObjectsOf_Class')."\" onClick=\"oWidget{$this->m_iInputId}.RemoveSelected();\" >";
|
||||
$sHtmlValue .= " <input id=\"{$this->m_sAttCode}{$this->m_sNameSuffix}_btnAdd\" type=\"button\" value=\"".Dict::Format('UI:AddLinkedObjectsOf_Class', MetaModel::GetName($this->m_sRemoteClass))."\" onClick=\"oWidget{$this->m_iInputId}.AddObjects();\"><span id=\"{$this->m_sAttCode}{$this->m_sNameSuffix}_indicatorAdd\"></span></span>\n";
|
||||
@@ -443,53 +481,55 @@ EOF
|
||||
*/
|
||||
public function GetObjectPickerDialog($oPage, $oCurrentObj, $sJson, $aAlreadyLinkedIds = array(), $aPrefillFormParam = array())
|
||||
{
|
||||
$sHtml = "<div class=\"wizContainer\" style=\"vertical-align:top;\">\n";
|
||||
//$oPage->add("<div class=\"wizContainer\" style=\"vertical-align:top;\">\n");
|
||||
|
||||
$oAlreadyLinkedFilter = new DBObjectSearch($this->m_sRemoteClass);
|
||||
if (!$this->m_bDuplicatesAllowed && count($aAlreadyLinkedIds) > 0)
|
||||
{
|
||||
if (!$this->m_bDuplicatesAllowed && count($aAlreadyLinkedIds) > 0) {
|
||||
$oAlreadyLinkedFilter->AddCondition('id', $aAlreadyLinkedIds, 'NOTIN');
|
||||
$oAlreadyLinkedExpression = $oAlreadyLinkedFilter->GetCriteria();
|
||||
$sAlreadyLinkedExpression = $oAlreadyLinkedExpression->Render();
|
||||
}
|
||||
else
|
||||
{
|
||||
$sAlreadyLinkedExpression = $oAlreadyLinkedExpression->RenderExpression();
|
||||
} else {
|
||||
$sAlreadyLinkedExpression = '';
|
||||
}
|
||||
|
||||
$oFilter = new DBObjectSearch($this->m_sRemoteClass);
|
||||
|
||||
if(!empty($oCurrentObj))
|
||||
{
|
||||
if (!empty($oCurrentObj)) {
|
||||
$this->SetSearchDefaultFromContext($oCurrentObj, $oFilter);
|
||||
$aPrefillFormParam['filter'] = $oFilter;
|
||||
$aPrefillFormParam['dest_class'] = $this->m_sRemoteClass;
|
||||
$oCurrentObj->PrefillForm('search', $aPrefillFormParam);
|
||||
}
|
||||
$oBlock = new DisplayBlock($oFilter, 'search', false);
|
||||
$sHtml .= $oBlock->GetDisplay($oPage, "SearchFormToAdd_{$this->m_sAttCode}{$this->m_sNameSuffix}",
|
||||
$oPage->AddUiBlock($oBlock->GetDisplay($oPage, "SearchFormToAdd_{$this->m_sAttCode}{$this->m_sNameSuffix}",
|
||||
array(
|
||||
'menu' => false,
|
||||
'result_list_outer_selector' => "SearchResultsToAdd_{$this->m_sAttCode}{$this->m_sNameSuffix}",
|
||||
'table_id' => 'add_'.$this->m_sAttCode,
|
||||
'table_id' => "add_{$this->m_sAttCode}{$this->m_sNameSuffix}",
|
||||
'table_inner_id' => "ResultsToAdd_{$this->m_sAttCode}{$this->m_sNameSuffix}",
|
||||
'selection_mode' => true,
|
||||
'json' => $sJson,
|
||||
'cssCount' => '#count_'.$this->m_sAttCode.$this->m_sNameSuffix,
|
||||
'query_params' => $oFilter->GetInternalParams(),
|
||||
'hidden_criteria' => $sAlreadyLinkedExpression,
|
||||
));
|
||||
$sHtml .= "<form id=\"ObjectsAddForm_{$this->m_sAttCode}{$this->m_sNameSuffix}\">\n";
|
||||
$sHtml .= "<div id=\"SearchResultsToAdd_{$this->m_sAttCode}{$this->m_sNameSuffix}\" style=\"vertical-align:top;background: #fff;height:100%;overflow:auto;padding:0;border:0;\">\n";
|
||||
$sHtml .= "<div style=\"background: #fff; border:0; text-align:center; vertical-align:middle;\"><p>".Dict::S('UI:Message:EmptyList:UseSearchForm')."</p></div>\n";
|
||||
$sHtml .= "</div>\n";
|
||||
$sHtml .= "<input type=\"hidden\" id=\"count_{$this->m_sAttCode}{$this->m_sNameSuffix}\" value=\"0\"/>";
|
||||
$sHtml .= "<input type=\"button\" value=\"".Dict::S('UI:Button:Cancel')."\" onClick=\"$('#dlg_{$this->m_sAttCode}{$this->m_sNameSuffix}').dialog('close');\"> <input id=\"btn_ok_{$this->m_sAttCode}{$this->m_sNameSuffix}\" disabled=\"disabled\" type=\"button\" onclick=\"return oWidget{$this->m_iInputId}.DoAddObjects(this.id);\" value=\"".Dict::S('UI:Button:Add')."\">";
|
||||
$sHtml .= "</div>\n";
|
||||
$sHtml .= "</form>\n";
|
||||
$oPage->add($sHtml);
|
||||
$oPage->add_ready_script("$('#dlg_{$this->m_sAttCode}{$this->m_sNameSuffix}').dialog({ width: $(window).width()*0.8, height: $(window).height()*0.8, autoOpen: false, modal: true, resizeStop: oWidget{$this->m_iInputId}.UpdateSizes });");
|
||||
$oPage->add_ready_script("$('#dlg_{$this->m_sAttCode}{$this->m_sNameSuffix}').dialog('option', {title:'".addslashes(Dict::Format('UI:AddObjectsOf_Class_LinkedWith_Class', MetaModel::GetName($this->m_sLinkedClass), MetaModel::GetName($this->m_sClass)))."'});");
|
||||
)));
|
||||
$sEmptyList = Dict::S('UI:Message:EmptyList:UseSearchForm');
|
||||
$sCancel = Dict::S('UI:Button:Cancel');
|
||||
$sAdd = Dict::S('UI:Button:Add');
|
||||
|
||||
$oPage->add(<<<HTML
|
||||
<form id="ObjectsAddForm_{$this->m_sAttCode}{$this->m_sNameSuffix}">
|
||||
<div id="SearchResultsToAdd_{$this->m_sAttCode}{$this->m_sNameSuffix}" style="vertical-align:top;background: #fff;height:100%;overflow:auto;padding:0;border:0;">
|
||||
<div style="background: #fff; border:0; text-align:center; vertical-align:middle;"><p>{$sEmptyList}</p></div>
|
||||
</div>
|
||||
<input type="hidden" id="count_{$this->m_sAttCode}{$this->m_sNameSuffix}" value="0"/>
|
||||
<input type="button" value="{$sCancel}" onClick="$('#dlg_{$this->m_sAttCode}{$this->m_sNameSuffix}').dialog('close');">
|
||||
<input id="btn_ok_add_{$this->m_sAttCode}{$this->m_sNameSuffix}" disabled="disabled" type="button" onclick="return oWidget{$this->m_iInputId}.DoAddObjects(this.id);" value="{$sAdd}">
|
||||
</form>
|
||||
HTML
|
||||
);
|
||||
|
||||
$oPage->add_ready_script("$('#dlg_{$this->m_sAttCode}{$this->m_sNameSuffix}').dialog({ width: $(window).width()*0.8, height: $(window).height()*0.8, title:'".addslashes(Dict::Format('UI:AddObjectsOf_Class_LinkedWith_Class', MetaModel::GetName($this->m_sLinkedClass), MetaModel::GetName($this->m_sClass)))."' , autoOpen: false, modal: true, resizeStop: oWidget{$this->m_iInputId}.UpdateSizes });");
|
||||
$oPage->add_ready_script("$('#SearchFormToAdd_{$this->m_sAttCode}{$this->m_sNameSuffix} form').bind('submit.uilinksWizard', oWidget{$this->m_iInputId}.SearchObjectsToAdd);");
|
||||
$oPage->add_ready_script("$('#SearchFormToAdd_{$this->m_sAttCode}{$this->m_sNameSuffix}').resize(oWidget{$this->m_iInputId}.UpdateSizes);");
|
||||
}
|
||||
@@ -547,7 +587,8 @@ EOF
|
||||
if (is_object($oLinkedObj))
|
||||
{
|
||||
$aRow = $this->GetFormRow($oP, $oLinkedObj, $iObjectId, array(), $oCurrentObj, $iAdditionId); // Not yet created link get negative Ids
|
||||
$oP->add($this->DisplayFormRow($oP, $this->m_aTableConfig, $aRow, -$iAdditionId));
|
||||
$oRow = new FormTableRow("{$this->m_sAttCode}{$this->m_sNameSuffix}", $this->m_aTableConfig, $aRow, -$iAdditionId);
|
||||
$oP->AddUiBlock($oRow);
|
||||
$iAdditionId++;
|
||||
}
|
||||
else
|
||||
|
||||
@@ -24,7 +24,6 @@
|
||||
* @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 UIPasswordWidget
|
||||
@@ -66,7 +65,7 @@ class UIPasswordWidget
|
||||
$sHtmlValue .= '<input type="hidden" id="'.$this->iId.'_changed" name="attr_'.$sCode.'[changed]" value="'.$sChangedValue.'"/>';
|
||||
$sHtmlValue .= '</div>';
|
||||
|
||||
$sHtmlValue .= '<span class="form_validation" id="v_'.$this->iId.'"></span><span class="field_status" id="fstatus_'.$this->iId.'"></span>';
|
||||
$sHtmlValue .= '<span class="form_validation ibo-field-validation" id="v_'.$this->iId.'"></span><span class="field_status" id="fstatus_'.$this->iId.'"></span>';
|
||||
|
||||
$oPage->add_ready_script("$('#$this->iId').bind('keyup change', function(evt) { return PasswordFieldChanged('$this->iId') } );"); // Bind to a custom event: validate
|
||||
$oPage->add_ready_script("$('#$this->iId').bind('keyup change validate', function(evt, sFormId) { return ValidatePasswordField('$this->iId', sFormId) } );"); // Bind to a custom event: validate
|
||||
|
||||
@@ -21,7 +21,6 @@
|
||||
*/
|
||||
|
||||
|
||||
require_once(APPROOT.'/application/webpage.class.inc.php');
|
||||
require_once(APPROOT.'/application/displayblock.class.inc.php');
|
||||
|
||||
class UISearchFormForeignKeys
|
||||
@@ -41,12 +40,11 @@ class UISearchFormForeignKeys
|
||||
*/
|
||||
public function ShowModalSearchForeignKeys($oPage, $sTitle)
|
||||
{
|
||||
$sHtml = "<div class=\"wizContainer\" style=\"vertical-align:top;\">\n";
|
||||
|
||||
$oFilter = new DBObjectSearch($this->m_sRemoteClass);
|
||||
|
||||
$oBlock = new DisplayBlock($oFilter, 'search', false);
|
||||
$sHtml .= $oBlock->GetDisplay($oPage, "SearchFormToAdd_{$this->m_iInputId}",
|
||||
$oPage->AddUiBlock($oBlock->GetDisplay($oPage, "SearchFormToAdd_{$this->m_iInputId}",
|
||||
array(
|
||||
'menu' => false,
|
||||
'result_list_outer_selector' => "SearchResultsToAdd_{$this->m_iInputId}",
|
||||
@@ -55,16 +53,23 @@ class UISearchFormForeignKeys
|
||||
'selection_mode' => true,
|
||||
'cssCount' => "#count_{$this->m_iInputId}",
|
||||
'query_params' => $oFilter->GetInternalParams(),
|
||||
));
|
||||
$sHtml .= "<form id=\"ObjectsAddForm_{$this->m_iInputId}\">\n";
|
||||
$sHtml .= "<div id=\"SearchResultsToAdd_{$this->m_iInputId}\" style=\"vertical-align:top;background: #fff;height:100%;overflow:auto;padding:0;border:0;\">\n";
|
||||
$sHtml .= "<div style=\"background: #fff; border:0; text-align:center; vertical-align:middle;\"><p>".Dict::S('UI:Message:EmptyList:UseSearchForm')."</p></div>\n";
|
||||
$sHtml .= "</div>\n";
|
||||
$sHtml .= "<input type=\"hidden\" id=\"count_{$this->m_iInputId}\" value=\"0\"/>";
|
||||
$sHtml .= "<input type=\"button\" value=\"".Dict::S('UI:Button:Cancel')."\" onClick=\"$('#dlg_{$this->m_iInputId}').dialog('close');\"> <input id=\"btn_ok_{$this->m_iInputId}\" disabled=\"disabled\" type=\"button\" onclick=\"return oForeignKeysWidget{$this->m_iInputId}.DoAddObjects(this.id);\" value=\"".Dict::S('UI:Button:Add')."\">";
|
||||
$sHtml .= "</div>\n";
|
||||
$sHtml .= "</form>\n";
|
||||
$oPage->add($sHtml);
|
||||
)));
|
||||
$sEmptyList = Dict::S('UI:Message:EmptyList:UseSearchForm');
|
||||
$sCancel = Dict::S('UI:Button:Cancel');
|
||||
$sAdd = Dict::S('UI:Button:Add');
|
||||
|
||||
$oPage->add(<<<HTML
|
||||
<form id="ObjectsAddForm_{$this->m_iInputId}">
|
||||
<div id="SearchResultsToAdd_{$this->m_iInputId}" style="vertical-align:top;background: #fff;height:100%;overflow:auto;padding:0;border:0;">
|
||||
<div style="background: #fff; border:0; text-align:center; vertical-align:middle;"><p>{$sEmptyList}</p></div>
|
||||
</div>
|
||||
<input type="hidden" id="count_{$this->m_iInputId}" value="0"/>
|
||||
<input type="button" value="{$sCancel}" onClick="$('#dlg_{$this->m_iInputId}').dialog('close');">
|
||||
<input id="btn_ok_add_{$this->m_iInputId}" disabled="disabled" type="button" onclick="return oForeignKeysWidget{$this->m_iInputId}.DoAddObjects(this.id);" value="{$sAdd}">
|
||||
</form>
|
||||
HTML
|
||||
);
|
||||
|
||||
$oPage->add_ready_script("$('#dlg_{$this->m_iInputId}').dialog({ width: $(window).width()*0.8, height: $(window).height()*0.8, autoOpen: false, modal: true, resizeStop: oForeignKeysWidget{$this->m_iInputId}.UpdateSizes });");
|
||||
$oPage->add_ready_script("$('#dlg_{$this->m_iInputId}').dialog('option', {title:'$sTitle'});");
|
||||
$oPage->add_ready_script("$('#SearchFormToAdd_{$this->m_iInputId} form').bind('submit.uilinksWizard', oForeignKeysWidget{$this->m_iInputId}.SearchObjectsToAdd);");
|
||||
@@ -112,4 +117,4 @@ class UISearchFormForeignKeys
|
||||
array('menu' => false, 'cssCount' => "#count_{$this->m_iInputId}", 'selection_mode' => true, 'table_id' => "add_{$this->m_iInputId}"));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,15 +35,20 @@ require_once(APPROOT.'/core/userrights.class.inc.php');
|
||||
class appUserPreferences extends DBObject
|
||||
{
|
||||
private static $oUserPrefs = null; // Local cache
|
||||
|
||||
|
||||
/**
|
||||
* Get the value of the given property/preference
|
||||
* If not set, the default value will be returned
|
||||
*
|
||||
* @param string $sCode Code/Name of the property to set
|
||||
* @param string $sDefaultValue The default value
|
||||
* @return string The value of the property for the current user
|
||||
* @param mixed $defaultValue The default value
|
||||
*
|
||||
* @return mixed The value of the property for the current user
|
||||
* @throws \CoreException
|
||||
* @throws \CoreUnexpectedValue
|
||||
* @throws \MySQLException
|
||||
*/
|
||||
public static function GetPref($sCode, $sDefaultValue)
|
||||
public static function GetPref($sCode, $defaultValue)
|
||||
{
|
||||
if (self::$oUserPrefs == null)
|
||||
{
|
||||
@@ -56,29 +61,35 @@ class appUserPreferences extends DBObject
|
||||
}
|
||||
else
|
||||
{
|
||||
return $sDefaultValue;
|
||||
return $defaultValue;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set the value for a given preference, and stores it into the database
|
||||
*
|
||||
* @param string $sCode Code/Name of the property/preference to set
|
||||
* @param string $sValue Value to set
|
||||
* @param mixed $value Value to set
|
||||
*
|
||||
* @return void
|
||||
* @throws \CoreException
|
||||
* @throws \CoreUnexpectedValue
|
||||
* @throws \MySQLException
|
||||
*/
|
||||
public static function SetPref($sCode, $sValue)
|
||||
public static function SetPref($sCode, $value)
|
||||
{
|
||||
if (self::$oUserPrefs == null)
|
||||
{
|
||||
self::Load();
|
||||
}
|
||||
$aPrefs = self::$oUserPrefs->Get('preferences');
|
||||
if (array_key_exists($sCode, $aPrefs) && ($aPrefs[$sCode] === $sValue))
|
||||
if (array_key_exists($sCode, $aPrefs) && ($aPrefs[$sCode] === $value))
|
||||
{
|
||||
// Do not write it again
|
||||
}
|
||||
else
|
||||
{
|
||||
$aPrefs[$sCode] = $sValue;
|
||||
$aPrefs[$sCode] = $value;
|
||||
self::$oUserPrefs->Set('preferences', $aPrefs);
|
||||
self::Save();
|
||||
}
|
||||
@@ -86,8 +97,14 @@ class appUserPreferences extends DBObject
|
||||
|
||||
/**
|
||||
* Clears the value for a given preference (or list of preferences that matches a pattern), and updates the database
|
||||
*
|
||||
* @param string $sCodeOrPattern Code/Pattern of the properties/preferences to reset
|
||||
* @param boolean $bPattern Whether or not the supplied code is a PCRE pattern
|
||||
*
|
||||
* @return void
|
||||
* @throws \CoreException
|
||||
* @throws \CoreUnexpectedValue
|
||||
* @throws \MySQLException
|
||||
*/
|
||||
public static function UnsetPref($sCodeOrPattern, $bPattern = false)
|
||||
{
|
||||
@@ -119,10 +136,14 @@ class appUserPreferences extends DBObject
|
||||
self::Save();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Call this function to get all the preferences for the user, packed as a JSON object
|
||||
*
|
||||
* @return string JSON representation of the preferences
|
||||
* @throws \CoreException
|
||||
* @throws \CoreUnexpectedValue
|
||||
* @throws \MySQLException
|
||||
*/
|
||||
public static function GetAsJSON()
|
||||
{
|
||||
@@ -136,19 +157,29 @@ class appUserPreferences extends DBObject
|
||||
|
||||
/**
|
||||
* Call this function if the user has changed (like when doing a logoff...)
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public static function ResetPreferences()
|
||||
{
|
||||
self::$oUserPrefs = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Call this function to ERASE all the preferences from the current user
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public static function ClearPreferences()
|
||||
{
|
||||
self::$oUserPrefs = null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Save preferences in the DB
|
||||
*
|
||||
* @return void;
|
||||
*/
|
||||
protected static function Save()
|
||||
{
|
||||
if (self::$oUserPrefs != null)
|
||||
@@ -161,10 +192,15 @@ class appUserPreferences extends DBObject
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Loads the preferences for the current user, creating the record in the database
|
||||
* if needed
|
||||
*
|
||||
* @return void;
|
||||
* @throws \CoreException
|
||||
* @throws \CoreUnexpectedValue
|
||||
* @throws \MySQLException
|
||||
*/
|
||||
protected static function Load()
|
||||
{
|
||||
@@ -193,6 +229,9 @@ class appUserPreferences extends DBObject
|
||||
self::$oUserPrefs = $oObj;
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws \CoreException
|
||||
*/
|
||||
public static function Init()
|
||||
{
|
||||
$aParams = array
|
||||
@@ -213,9 +252,22 @@ class appUserPreferences extends DBObject
|
||||
}
|
||||
|
||||
/**
|
||||
* Overloading this function here to secure a fix done right before the release
|
||||
* The real fix should be to implement this verb in DBObject
|
||||
*/
|
||||
* Overloading this function here to secure a fix done right before the release
|
||||
* The real fix should be to implement this verb in DBObject
|
||||
*
|
||||
* @param \CMDBChange $oChange
|
||||
* @param bool|null $bSkipStrongSecurity
|
||||
* @param \DeletionPlan|null $oDeletionPlan
|
||||
*
|
||||
* @throws \ArchivedObjectException
|
||||
* @throws \CoreCannotSaveObjectException
|
||||
* @throws \CoreException
|
||||
* @throws \CoreUnexpectedValue
|
||||
* @throws \DeleteException
|
||||
* @throws \MySQLException
|
||||
* @throws \MySQLHasGoneAwayException
|
||||
* @throws \OQLException
|
||||
*/
|
||||
public function DBDeleteTracked(CMDBChange $oChange, $bSkipStrongSecurity = null, &$oDeletionPlan = null)
|
||||
{
|
||||
utils::PushArchiveMode(false);
|
||||
|
||||
@@ -44,6 +44,57 @@ class FileUploadException extends Exception
|
||||
*/
|
||||
class utils
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
* @since 3.0.0
|
||||
*/
|
||||
public const ENUM_SANITIZATION_FILTER_INTEGER = 'integer';
|
||||
/**
|
||||
* @var string
|
||||
* @since 3.0.0
|
||||
*/
|
||||
public const ENUM_SANITIZATION_FILTER_CLASS = 'class';
|
||||
/**
|
||||
* @var string
|
||||
* @since 3.0.0
|
||||
*/
|
||||
public const ENUM_SANITIZATION_FILTER_STRING = 'string';
|
||||
/**
|
||||
* @var string
|
||||
* @since 3.0.0
|
||||
*/
|
||||
public const ENUM_SANITIZATION_FILTER_CONTEXT_PARAM = 'context_param';
|
||||
/**
|
||||
* @var string
|
||||
* @since 3.0.0
|
||||
*/
|
||||
public const ENUM_SANITIZATION_FILTER_PARAMETER = 'parameter';
|
||||
/**
|
||||
* @var string
|
||||
* @since 3.0.0
|
||||
*/
|
||||
public const ENUM_SANITIZATION_FILTER_FIELD_NAME = 'field_name';
|
||||
/**
|
||||
* @var string
|
||||
* @since 3.0.0
|
||||
*/
|
||||
public const ENUM_SANITIZATION_FILTER_TRANSACTION_ID = 'transaction_id';
|
||||
/**
|
||||
* @var string For XML / HTML node identifiers
|
||||
* @since 3.0.0
|
||||
*/
|
||||
public const ENUM_SANITIZATION_FILTER_ELEMENT_IDENTIFIER = 'element_identifier';
|
||||
/**
|
||||
* @var string
|
||||
* @since 3.0.0
|
||||
*/
|
||||
public const ENUM_SANITIZATION_FILTER_RAW_DATA = 'raw_data';
|
||||
/**
|
||||
* @var string
|
||||
* @since 3.0.0
|
||||
*/
|
||||
public const DEFAULT_SANITIZATION_FILTER = self::ENUM_SANITIZATION_FILTER_RAW_DATA;
|
||||
|
||||
/**
|
||||
* Cache when getting config from disk or set externally (using {@link SetConfig})
|
||||
* @internal
|
||||
@@ -283,31 +334,32 @@ class utils
|
||||
*
|
||||
* @since 2.5.2 2.6.0 new 'transaction_id' filter
|
||||
* @since 2.7.0 new 'element_identifier' filter
|
||||
*
|
||||
* @throws \CoreException
|
||||
*/
|
||||
protected static function Sanitize_Internal($value, $sSanitizationFilter)
|
||||
{
|
||||
switch ($sSanitizationFilter)
|
||||
{
|
||||
case 'integer':
|
||||
case static::ENUM_SANITIZATION_FILTER_INTEGER:
|
||||
$retValue = filter_var($value, FILTER_SANITIZE_NUMBER_INT);
|
||||
break;
|
||||
|
||||
case 'class':
|
||||
case static::ENUM_SANITIZATION_FILTER_CLASS:
|
||||
$retValue = $value;
|
||||
if (!MetaModel::IsValidClass($value))
|
||||
{
|
||||
$retValue = false;
|
||||
if (($value != '') && !MetaModel::IsValidClass($value)) {
|
||||
throw new CoreException(Dict::Format('UI:OQL:UnknownClassNoFix', utils::HtmlEntities($value)));
|
||||
}
|
||||
break;
|
||||
|
||||
case 'string':
|
||||
case static::ENUM_SANITIZATION_FILTER_STRING:
|
||||
$retValue = filter_var($value, FILTER_SANITIZE_SPECIAL_CHARS);
|
||||
break;
|
||||
|
||||
case 'context_param':
|
||||
case 'parameter':
|
||||
case 'field_name':
|
||||
case 'transaction_id':
|
||||
case static::ENUM_SANITIZATION_FILTER_CONTEXT_PARAM:
|
||||
case static::ENUM_SANITIZATION_FILTER_PARAMETER:
|
||||
case static::ENUM_SANITIZATION_FILTER_FIELD_NAME:
|
||||
case static::ENUM_SANITIZATION_FILTER_TRANSACTION_ID:
|
||||
if (is_array($value))
|
||||
{
|
||||
$retValue = array();
|
||||
@@ -325,7 +377,7 @@ class utils
|
||||
{
|
||||
switch ($sSanitizationFilter)
|
||||
{
|
||||
case 'transaction_id':
|
||||
case static::ENUM_SANITIZATION_FILTER_TRANSACTION_ID:
|
||||
// same as parameter type but keep the dot character
|
||||
// see N°1835 : when using file transaction_id on Windows you get *.tmp tokens
|
||||
// it must be included at the regexp beginning otherwise you'll get an invalid character error
|
||||
@@ -333,18 +385,18 @@ class utils
|
||||
array("options" => array("regexp" => '/^[\. A-Za-z0-9_=-]*$/')));
|
||||
break;
|
||||
|
||||
case 'parameter':
|
||||
case static::ENUM_SANITIZATION_FILTER_PARAMETER:
|
||||
$retValue = filter_var($value, FILTER_VALIDATE_REGEXP,
|
||||
array("options" => array("regexp" => '/^[ A-Za-z0-9_=-]*$/'))); // the '=', '%3D, '%2B', '%2F'
|
||||
// characters are used in serialized filters (starting 2.5, only the url encoded versions are presents, but the "=" is kept for BC)
|
||||
break;
|
||||
|
||||
case 'field_name':
|
||||
case static::ENUM_SANITIZATION_FILTER_FIELD_NAME:
|
||||
$retValue = filter_var($value, FILTER_VALIDATE_REGEXP,
|
||||
array("options" => array("regexp" => '/^[A-Za-z0-9_]+(->[A-Za-z0-9_]+)*$/'))); // att_code or att_code->name or AttCode->Name or AttCode->Key2->Name
|
||||
break;
|
||||
|
||||
case 'context_param':
|
||||
case static::ENUM_SANITIZATION_FILTER_CONTEXT_PARAM:
|
||||
$retValue = filter_var($value, FILTER_VALIDATE_REGEXP,
|
||||
array("options" => array("regexp" => '/^[ A-Za-z0-9_=%:+-]*$/')));
|
||||
break;
|
||||
@@ -353,13 +405,12 @@ class utils
|
||||
}
|
||||
break;
|
||||
|
||||
// For XML / HTML node identifiers
|
||||
case 'element_identifier':
|
||||
$retValue = preg_replace('/[^a-zA-Z0-9_]/', '', $value);
|
||||
case static::ENUM_SANITIZATION_FILTER_ELEMENT_IDENTIFIER:
|
||||
$retValue = preg_replace('/[^a-zA-Z0-9_-]/', '', $value);
|
||||
break;
|
||||
|
||||
default:
|
||||
case 'raw_data':
|
||||
case static::ENUM_SANITIZATION_FILTER_RAW_DATA:
|
||||
$retValue = $value;
|
||||
// Do nothing
|
||||
}
|
||||
@@ -767,19 +818,22 @@ class utils
|
||||
return new Config();
|
||||
}
|
||||
|
||||
public static function InitTimeZone() {
|
||||
$oConfig = self::GetConfig();
|
||||
public static function InitTimeZone($oConfig = null)
|
||||
{
|
||||
if (is_null($oConfig))
|
||||
{
|
||||
$oConfig = self::GetConfig();
|
||||
}
|
||||
$sItopTimeZone = $oConfig->Get('timezone');
|
||||
|
||||
if (!empty($sItopTimeZone))
|
||||
{
|
||||
date_default_timezone_set($sItopTimeZone);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Leave as is... up to the admin to set a value somewhere...
|
||||
// see http://php.net/manual/en/datetime.configuration.php#ini.date.timezone
|
||||
}
|
||||
// else
|
||||
// {
|
||||
// // Leave as is... up to the admin to set a value somewhere...
|
||||
// // see http://php.net/manual/en/datetime.configuration.php#ini.date.timezone
|
||||
// }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -908,6 +962,28 @@ class utils
|
||||
return $sAppRootUrl;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the complete revision number of the application
|
||||
*
|
||||
* @return string
|
||||
* @since 3.0.0
|
||||
*/
|
||||
public static function GetAppRevisionNumber()
|
||||
{
|
||||
if (ITOP_REVISION == 'svn')
|
||||
{
|
||||
// This is NOT a version built using the build system, just display the main version
|
||||
$sRevisionNumber = Dict::Format('UI:iTopVersion:Short', ITOP_APPLICATION, ITOP_VERSION);
|
||||
}
|
||||
else
|
||||
{
|
||||
// This is a build made from SVN, let display the full information
|
||||
$sRevisionNumber = Dict::Format('UI:iTopVersion:Long', ITOP_APPLICATION, ITOP_VERSION, ITOP_REVISION, ITOP_BUILD_DATE);
|
||||
}
|
||||
|
||||
return $sRevisionNumber;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper to handle the variety of HTTP servers
|
||||
* See N°286 (fixed in [896]), and N°634 (this fix)
|
||||
@@ -941,16 +1017,11 @@ class utils
|
||||
|
||||
/**
|
||||
* Get the _SESSION variable for logging purpose
|
||||
* @return false|string
|
||||
* @return string
|
||||
*/
|
||||
public static function GetSessionLog()
|
||||
{
|
||||
ob_start();
|
||||
print_r($_SESSION);
|
||||
$sSessionLog = ob_get_contents();
|
||||
ob_end_clean();
|
||||
|
||||
return $sSessionLog;
|
||||
return print_r($_SESSION, true);
|
||||
}
|
||||
|
||||
static function DebugBacktrace($iLimit = 5)
|
||||
@@ -994,19 +1065,19 @@ class utils
|
||||
throw new Exception("The path to php must not be empty. Please set a value for 'php_path' in your configuration file.");
|
||||
}
|
||||
|
||||
$sAuthUser = self::ReadParam('auth_user', '', 'raw_data');
|
||||
$sAuthPwd = self::ReadParam('auth_pwd', '', 'raw_data');
|
||||
$sParamFile = self::GetParamSourceFile('auth_user');
|
||||
if (is_null($sParamFile))
|
||||
{
|
||||
if (!isset($aArguments['auth_user'])) {
|
||||
$sAuthUser = self::ReadParam('auth_user', '', 'raw_data');
|
||||
$aArguments['auth_user'] = $sAuthUser;
|
||||
}
|
||||
if (!isset($aArguments['auth_pwd'])) {
|
||||
$sAuthPwd = self::ReadParam('auth_pwd', '', 'raw_data');
|
||||
$aArguments['auth_pwd'] = $sAuthPwd;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!isset($aArguments['param_file'])) {
|
||||
$sParamFile = self::ReadParam('param_file', '', 'raw_data');
|
||||
$aArguments['param_file'] = $sParamFile;
|
||||
}
|
||||
|
||||
|
||||
$aArgs = array();
|
||||
foreach($aArguments as $sName => $value)
|
||||
{
|
||||
@@ -1158,6 +1229,7 @@ class utils
|
||||
new JSPopupMenuItem('UI:Menu:ExportXLSX', Dict::S('ExcelExporter:ExportMenu'), "ExportListDlg('$sOQL', '', 'xlsx', ".json_encode(Dict::S('ExcelExporter:ExportMenu')).")"),
|
||||
new SeparatorPopupMenuItem(),
|
||||
new URLPopupMenuItem('UI:Menu:PrintableVersion', Dict::S('UI:Menu:PrintableVersion'), $sUrl.'&printable=1', '_blank'),
|
||||
new JSPopupMenuItem('UI:Menu:SwitchTabMode', Dict::S('UI:Menu:SwitchTabMode'), "SwitchTabMode()"),
|
||||
);
|
||||
break;
|
||||
|
||||
@@ -1388,13 +1460,12 @@ class utils
|
||||
// For instance fopen does not allow to work around the bug: http://stackoverflow.com/questions/18191672/php-curl-ssl-routinesssl23-get-server-helloreason1112
|
||||
// by setting the SSLVERSION to 3 as done below.
|
||||
$aHeaders = explode("\n", $sOptionnalHeaders);
|
||||
// N°3267 - Webservices: Fix optional headers not being taken into account
|
||||
// See https://www.php.net/curl_setopt CURLOPT_HTTPHEADER
|
||||
$aHTTPHeaders = array();
|
||||
foreach($aHeaders as $sHeaderString)
|
||||
{
|
||||
if(preg_match('/^([^:]): (.+)$/', $sHeaderString, $aMatches))
|
||||
{
|
||||
$aHTTPHeaders[$aMatches[1]] = $aMatches[2];
|
||||
}
|
||||
$aHTTPHeaders[] = trim($sHeaderString);
|
||||
}
|
||||
// Default options, can be overloaded/extended with the 4th parameter of this method, see above $aCurlOptions
|
||||
$aOptions = array(
|
||||
@@ -1626,7 +1697,7 @@ class utils
|
||||
set_time_limit(0);
|
||||
// Compiling SASS
|
||||
$sCss = $oSass->compile($sSassContent);
|
||||
set_time_limit($iCurrentMaxExecTime);
|
||||
set_time_limit(intval($iCurrentMaxExecTime));
|
||||
|
||||
return $sCss;
|
||||
}
|
||||
@@ -2082,33 +2153,38 @@ class utils
|
||||
*/
|
||||
public static function GetCacheBusterTimestamp()
|
||||
{
|
||||
if(!defined('COMPILATION_TIMESTAMP'))
|
||||
{
|
||||
if (!defined('COMPILATION_TIMESTAMP')) {
|
||||
return ITOP_VERSION;
|
||||
}
|
||||
|
||||
return COMPILATION_TIMESTAMP;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string eg : '2_7_0' ITOP_VERSION is '2.7.1-dev'
|
||||
*/
|
||||
public static function GetItopVersionWikiSyntax()
|
||||
{
|
||||
public static function GetItopVersionWikiSyntax() {
|
||||
$sMinorVersion = self::GetItopMinorVersion();
|
||||
|
||||
return str_replace('.', '_', $sMinorVersion).'_0';
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $sPatchVersion if non provided, will call GetItopPatchVersion
|
||||
*
|
||||
* @return string eg 2.7 if ITOP_VERSION is '2.7.0-dev'
|
||||
* @throws \Exception
|
||||
*/
|
||||
public static function GetItopMinorVersion()
|
||||
{
|
||||
$sPatchVersion = self::GetItopPatchVersion();
|
||||
public static function GetItopMinorVersion($sPatchVersion = null) {
|
||||
if (is_null($sPatchVersion)) {
|
||||
$sPatchVersion = self::GetItopPatchVersion();
|
||||
}
|
||||
$aExplodedVersion = explode('.', $sPatchVersion);
|
||||
|
||||
if (empty($aExplodedVersion[0]) || empty($aExplodedVersion[1]))
|
||||
{
|
||||
if (count($aExplodedVersion) < 2) {
|
||||
throw new Exception('iTop version is wrongfully configured!');
|
||||
}
|
||||
if (($aExplodedVersion[0] == '') || ($aExplodedVersion[1] == '')) {
|
||||
throw new Exception('iTop version is wrongfully configured!');
|
||||
}
|
||||
|
||||
@@ -2118,9 +2194,9 @@ class utils
|
||||
/**
|
||||
* @return string eg '2.7.0' if ITOP_VERSION is '2.7.0-dev'
|
||||
*/
|
||||
public static function GetItopPatchVersion()
|
||||
{
|
||||
public static function GetItopPatchVersion() {
|
||||
$aExplodedVersion = explode('-', ITOP_VERSION);
|
||||
|
||||
return $aExplodedVersion[0];
|
||||
}
|
||||
|
||||
@@ -2153,6 +2229,18 @@ class utils
|
||||
return ITOP_REVISION === 'svn';
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if debug is enabled in the current environment.
|
||||
* Currently just checking if the "debug=true" parameter is in the URL, but could be more complex.
|
||||
*
|
||||
* @return bool
|
||||
* @since 3.0.0
|
||||
*/
|
||||
public static function IsDebugEnabled()
|
||||
{
|
||||
return utils::ReadParam('debug') === 'true';
|
||||
}
|
||||
|
||||
/**
|
||||
* @see https://php.net/manual/en/function.finfo-file.php
|
||||
*
|
||||
@@ -2316,12 +2404,17 @@ class utils
|
||||
return str_replace(' ', '', ucwords(strtr($sInput, '_-', ' ')));
|
||||
}
|
||||
|
||||
public static function FilterXSS($sHTML)
|
||||
{
|
||||
return str_ireplace('<script', '<script', $sHTML);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \cmdbAbstractObject $oCmdbAbstract
|
||||
* @param \Exception $oException
|
||||
*
|
||||
* @throws \Exception
|
||||
* @since 2.7.2/ 2.8.0
|
||||
* @since 2.7.2/ 3.0.0
|
||||
*/
|
||||
public static function EnrichRaisedException($oCmdbAbstract, $oException)
|
||||
{
|
||||
@@ -2337,4 +2430,11 @@ class utils
|
||||
$e = new CoreException($sMessage, null, '', $oException);
|
||||
throw $e;
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 3.0.0
|
||||
*/
|
||||
public static function IsEasterEggAllowed(){
|
||||
return (stripos(ITOP_VERSION, 'alpha') !== false) || utils::IsDevelopmentEnvironment();
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -335,20 +335,41 @@ class WizardHelper
|
||||
{
|
||||
$sResult = $this->m_aData['m_oFieldsMap'][$sFieldName];
|
||||
}
|
||||
|
||||
return $sResult;
|
||||
}
|
||||
|
||||
|
||||
public function GetReturnNotEditableFields()
|
||||
{
|
||||
return $this->m_aData['m_bReturnNotEditableFields'] ?? false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string JS code to be executed for fields update
|
||||
* @since 3.0.0 N°3198
|
||||
*/
|
||||
public function GetJsForUpdateFields()
|
||||
{
|
||||
$sWizardHelperJsVar = ($this->m_aData['m_sWizHelperJsVarName']) ?? 'oWizardHelper'.$this->GetFormPrefix();
|
||||
$sWizardHelperJson = $this->ToJSON();
|
||||
|
||||
return <<<JS
|
||||
{$sWizardHelperJsVar}.m_oData = {$sWizardHelperJson};
|
||||
{$sWizardHelperJsVar}.UpdateFields();
|
||||
JS;
|
||||
}
|
||||
|
||||
static function ParseJsonSet($oMe, $sLinkClass, $sExtKeyToMe, $sJsonSet)
|
||||
{
|
||||
$aSet = json_decode($sJsonSet, true); // true means hash array instead of object
|
||||
$oSet = CMDBObjectSet::FromScratch($sLinkClass);
|
||||
foreach($aSet as $aLinkObj)
|
||||
foreach ($aSet as $aLinkObj)
|
||||
{
|
||||
$oLink = MetaModel::NewObject($sLinkClass);
|
||||
foreach($aLinkObj as $sAttCode => $value)
|
||||
foreach ($aLinkObj as $sAttCode => $value)
|
||||
{
|
||||
$oAttDef = MetaModel::GetAttributeDef($sLinkClass, $sAttCode);
|
||||
if (($oAttDef->IsExternalKey()) && ($value != '') && ($value > 0))
|
||||
if (($oAttDef->IsExternalKey()) && ($value != '') && ($value > 0))
|
||||
{
|
||||
// For external keys: load the target object so that external fields
|
||||
// get filled too
|
||||
|
||||
@@ -1,111 +1,7 @@
|
||||
<?php
|
||||
// Copyright (C) 2010-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/>
|
||||
|
||||
|
||||
/**
|
||||
* Class XMLPage
|
||||
*
|
||||
* @copyright Copyright (C) 2010-2015 Combodo SARL
|
||||
* @deprecated will be removed in 3.1.0 - moved to sources/application/WebPage/XMLPage.php
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
* @copyright Copyright (C) 2010-2020 Combodo SARL
|
||||
*/
|
||||
|
||||
require_once(APPROOT."/application/webpage.class.inc.php");
|
||||
/**
|
||||
* Simple web page with no includes or fancy formatting, useful to generateXML documents
|
||||
* The page adds the content-type text/XML and the encoding into the headers
|
||||
*/
|
||||
class XMLPage extends WebPage
|
||||
{
|
||||
/**
|
||||
* For big XML files, it's better NOT to store everything in memory and output the XML piece by piece
|
||||
*/
|
||||
var $m_bPassThrough;
|
||||
var $m_bHeaderSent;
|
||||
|
||||
function __construct($s_title, $bPassThrough = false)
|
||||
{
|
||||
parent::__construct($s_title);
|
||||
$this->m_bPassThrough = $bPassThrough;
|
||||
$this->m_bHeaderSent = false;
|
||||
$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');
|
||||
$this->add_header('X-Frame-Options: deny');
|
||||
$this->add_header("Content-location: export.xml");
|
||||
}
|
||||
|
||||
public function output()
|
||||
{
|
||||
if (!$this->m_bPassThrough)
|
||||
{
|
||||
// Get the unexpected output but do nothing with it
|
||||
$sTrash = $this->ob_get_clean_safe();
|
||||
|
||||
$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)
|
||||
{
|
||||
header($s_header);
|
||||
}
|
||||
echo $this->s_content;
|
||||
}
|
||||
if (class_exists('DBSearch'))
|
||||
{
|
||||
DBSearch::RecordQueryTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public function add($sText)
|
||||
{
|
||||
if (!$this->m_bPassThrough)
|
||||
{
|
||||
parent::add($sText);
|
||||
}
|
||||
else
|
||||
{
|
||||
if ($this->m_bHeaderSent)
|
||||
{
|
||||
echo $sText;
|
||||
}
|
||||
else
|
||||
{
|
||||
$s_captured_output = $this->ob_get_clean_safe();
|
||||
foreach($this->a_headers as $s_header)
|
||||
{
|
||||
header($s_header);
|
||||
}
|
||||
$sCharset = self::PAGES_CHARSET;
|
||||
echo "<?xml version=\"1.0\" encoding=\"$sCharset\"?".">\n";
|
||||
echo trim($s_captured_output);
|
||||
echo trim($this->s_content);
|
||||
echo $sText;
|
||||
$this->m_bHeaderSent = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function small_p($sText)
|
||||
{
|
||||
}
|
||||
|
||||
public function table($aConfig, $aData, $aParams = array())
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Copyright (C) 2013-2019 Combodo SARL
|
||||
* Copyright (C) 2013-2020 Combodo SARL
|
||||
*
|
||||
* This file is part of iTop.
|
||||
*
|
||||
@@ -18,16 +18,31 @@
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* Checks PHP version
|
||||
*
|
||||
* This is a hard-coded check that limits errors : we are stopping for anything < PHP 7.0.0
|
||||
* The "real one" will be done in {@link \SetupUtils::CheckPhpVersion()}
|
||||
*
|
||||
* @since 3.0.0 N°2214
|
||||
*/
|
||||
$bIsValidPhpVersion = false;
|
||||
if (PHP_MAJOR_VERSION >= 7) {
|
||||
$bIsValidPhpVersion = true;
|
||||
} else {
|
||||
echo 'Your PHP version ('.PHP_VERSION.') isn\'t supported.';
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
|
||||
define('ITOP_DEFAULT_ENV', 'production');
|
||||
define('MAINTENANCE_MODE_FILE', APPROOT.'data/.maintenance');
|
||||
define('READONLY_MODE_FILE', APPROOT.'data/.readonly');
|
||||
|
||||
if (function_exists('microtime'))
|
||||
{
|
||||
if (function_exists('microtime')) {
|
||||
$fItopStarted = microtime(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
$fItopStarted = 1000 * time();
|
||||
}
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
"type": "project",
|
||||
"license": "AGPLv3",
|
||||
"require": {
|
||||
"php": ">=5.6.0",
|
||||
"php": ">=7.1.3",
|
||||
"ext-ctype": "*",
|
||||
"ext-dom": "*",
|
||||
"ext-gd": "*",
|
||||
@@ -37,7 +37,7 @@
|
||||
},
|
||||
"config": {
|
||||
"platform": {
|
||||
"php": "5.6.0"
|
||||
"php": "7.2.0"
|
||||
},
|
||||
"vendor-dir": "lib",
|
||||
"preferred-install": {
|
||||
@@ -52,7 +52,9 @@
|
||||
"application",
|
||||
"sources/application",
|
||||
"sources/Composer",
|
||||
"sources/Controller"
|
||||
"sources/Controller",
|
||||
"sources/Form",
|
||||
"sources/Renderer"
|
||||
],
|
||||
"exclude-from-classmap": [
|
||||
"core/dbobjectsearch.class.php",
|
||||
@@ -61,6 +63,7 @@
|
||||
"core/legacy/querybuildercontextlegacy.class.inc.php",
|
||||
"core/querybuilderexpressions.class.inc.php",
|
||||
"core/legacy/querybuilderexpressionslegacy.class.inc.php",
|
||||
"application/startup.inc.php",
|
||||
"application/loginform.class.inc.php",
|
||||
"application/loginbasic.class.inc.php",
|
||||
"application/logindefault.class.inc.php",
|
||||
|
||||
@@ -35,6 +35,10 @@ require_once(APPROOT.'/core/email.class.inc.php');
|
||||
*/
|
||||
abstract class Action extends cmdbAbstractObject
|
||||
{
|
||||
/**
|
||||
* @throws \CoreException
|
||||
* @throws \Exception
|
||||
*/
|
||||
public static function Init()
|
||||
{
|
||||
$aParams = array
|
||||
@@ -47,7 +51,6 @@ abstract class Action extends cmdbAbstractObject
|
||||
"db_table" => "priv_action",
|
||||
"db_key_field" => "id",
|
||||
"db_finalclass_field" => "realclass",
|
||||
"display_template" => "",
|
||||
);
|
||||
MetaModel::Init_Params($aParams);
|
||||
//MetaModel::Init_InheritAttributes();
|
||||
@@ -57,15 +60,32 @@ abstract class Action extends cmdbAbstractObject
|
||||
MetaModel::Init_AddAttribute(new AttributeLinkedSetIndirect("trigger_list", array("linked_class"=>"lnkTriggerAction", "ext_key_to_me"=>"action_id", "ext_key_to_remote"=>"trigger_id", "allowed_values"=>null, "count_min"=>0, "count_max"=>0, "depends_on"=>array())));
|
||||
|
||||
// Display lists
|
||||
MetaModel::Init_SetZListItems('details', array('name', 'description', 'status', 'trigger_list')); // Attributes to be displayed for the complete details
|
||||
MetaModel::Init_SetZListItems('list', array('finalclass', 'name', 'description', 'status')); // Attributes to be displayed for a list
|
||||
// - Attributes to be displayed for the complete details
|
||||
MetaModel::Init_SetZListItems('details', array('name', 'description', 'status', 'trigger_list'));
|
||||
// - Attributes to be displayed for a list
|
||||
MetaModel::Init_SetZListItems('list', array('finalclass', 'name', 'description', 'status'));
|
||||
// Search criteria
|
||||
MetaModel::Init_SetZListItems('default_search', array('name', 'description', 'status')); // Criteria of the std search form
|
||||
// MetaModel::Init_SetZListItems('advanced_search', array('name')); // Criteria of the advanced search form
|
||||
// - Criteria of the std search form
|
||||
MetaModel::Init_SetZListItems('default_search', array('name', 'description', 'status'));
|
||||
// - Criteria of the advanced search form
|
||||
// MetaModel::Init_SetZListItems('advanced_search', array('name'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Encapsulate the execution of the action and handle failure & logging
|
||||
*
|
||||
* @param \Trigger $oTrigger
|
||||
* @param array $aContextArgs
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
abstract public function DoExecute($oTrigger, $aContextArgs);
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
* @throws \ArchivedObjectException
|
||||
* @throws \CoreException
|
||||
*/
|
||||
public function IsActive()
|
||||
{
|
||||
switch($this->Get('status'))
|
||||
@@ -79,6 +99,13 @@ abstract class Action extends cmdbAbstractObject
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the current action status is set on "test"
|
||||
*
|
||||
* @return bool
|
||||
* @throws \ArchivedObjectException
|
||||
* @throws \CoreException
|
||||
*/
|
||||
public function IsBeingTested()
|
||||
{
|
||||
switch($this->Get('status'))
|
||||
@@ -99,6 +126,10 @@ abstract class Action extends cmdbAbstractObject
|
||||
*/
|
||||
abstract class ActionNotification extends Action
|
||||
{
|
||||
/**
|
||||
* @inheritDoc
|
||||
* @throws \CoreException
|
||||
*/
|
||||
public static function Init()
|
||||
{
|
||||
$aParams = array
|
||||
@@ -111,17 +142,20 @@ abstract class ActionNotification extends Action
|
||||
"db_table" => "priv_action_notification",
|
||||
"db_key_field" => "id",
|
||||
"db_finalclass_field" => "",
|
||||
"display_template" => "",
|
||||
);
|
||||
MetaModel::Init_Params($aParams);
|
||||
MetaModel::Init_InheritAttributes();
|
||||
|
||||
// Display lists
|
||||
MetaModel::Init_SetZListItems('details', array('name', 'description', 'status', 'trigger_list')); // Attributes to be displayed for the complete details
|
||||
MetaModel::Init_SetZListItems('list', array('finalclass', 'name', 'description', 'status')); // Attributes to be displayed for a list
|
||||
// - Attributes to be displayed for the complete details
|
||||
MetaModel::Init_SetZListItems('details', array('name', 'description', 'status', 'trigger_list'));
|
||||
// - Attributes to be displayed for a list
|
||||
MetaModel::Init_SetZListItems('list', array('finalclass', 'name', 'description', 'status'));
|
||||
// Search criteria
|
||||
// MetaModel::Init_SetZListItems('standard_search', array('name')); // Criteria of the std search form
|
||||
// MetaModel::Init_SetZListItems('advanced_search', array('name')); // Criteria of the advanced search form
|
||||
// - Criteria of the std search form
|
||||
// MetaModel::Init_SetZListItems('standard_search', array('name'));
|
||||
// - Criteria of the advanced search form
|
||||
// MetaModel::Init_SetZListItems('advanced_search', array('name'));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -132,6 +166,9 @@ abstract class ActionNotification extends Action
|
||||
*/
|
||||
class ActionEmail extends ActionNotification
|
||||
{
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public static function Init()
|
||||
{
|
||||
$aParams = array
|
||||
@@ -144,7 +181,6 @@ class ActionEmail extends ActionNotification
|
||||
"db_table" => "priv_action_email",
|
||||
"db_key_field" => "id",
|
||||
"db_finalclass_field" => "",
|
||||
"display_template" => "",
|
||||
);
|
||||
MetaModel::Init_Params($aParams);
|
||||
MetaModel::Init_InheritAttributes();
|
||||
@@ -152,7 +188,9 @@ class ActionEmail extends ActionNotification
|
||||
MetaModel::Init_AddAttribute(new AttributeEmailAddress("test_recipient", array("allowed_values"=>null, "sql"=>"test_recipient", "default_value"=>"", "is_null_allowed"=>true, "depends_on"=>array())));
|
||||
|
||||
MetaModel::Init_AddAttribute(new AttributeString("from", array("allowed_values"=>null, "sql"=>"from", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeString("from_label", array("allowed_values"=>null, "sql"=>"from_label", "default_value"=>null, "is_null_allowed"=>true, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeString("reply_to", array("allowed_values"=>null, "sql"=>"reply_to", "default_value"=>null, "is_null_allowed"=>true, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeString("reply_to_label", array("allowed_values"=>null, "sql"=>"reply_to_label", "default_value"=>null, "is_null_allowed"=>true, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeOQL("to", array("allowed_values"=>null, "sql"=>"to", "default_value"=>null, "is_null_allowed"=>true, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeOQL("cc", array("allowed_values"=>null, "sql"=>"cc", "default_value"=>null, "is_null_allowed"=>true, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeOQL("bcc", array("allowed_values"=>null, "sql"=>"bcc", "default_value"=>null, "is_null_allowed"=>true, "depends_on"=>array())));
|
||||
@@ -161,11 +199,15 @@ class ActionEmail extends ActionNotification
|
||||
MetaModel::Init_AddAttribute(new AttributeEnum("importance", array("allowed_values"=>new ValueSetEnum('low,normal,high'), "sql"=>"importance", "default_value"=>'normal', "is_null_allowed"=>false, "depends_on"=>array())));
|
||||
|
||||
// Display lists
|
||||
MetaModel::Init_SetZListItems('details', array('name', 'description', 'status', 'test_recipient', 'from', 'reply_to', 'to', 'cc', 'bcc', 'subject', 'body', 'importance', 'trigger_list')); // Attributes to be displayed for the complete details
|
||||
MetaModel::Init_SetZListItems('list', array('name', 'status', 'to', 'subject')); // Attributes to be displayed for a list
|
||||
// - Attributes to be displayed for the complete details
|
||||
MetaModel::Init_SetZListItems('details', array('name', 'description', 'status', 'test_recipient', 'from', 'from_label', 'reply_to', 'reply_to_label', 'to', 'cc', 'bcc', 'subject', 'body', 'importance', 'trigger_list'));
|
||||
// - Attributes to be displayed for a list
|
||||
MetaModel::Init_SetZListItems('list', array('name', 'status', 'to', 'subject'));
|
||||
// Search criteria
|
||||
MetaModel::Init_SetZListItems('standard_search', array('name','description', 'status', 'subject')); // Criteria of the std search form
|
||||
// MetaModel::Init_SetZListItems('advanced_search', array('name')); // Criteria of the advanced search form
|
||||
// - Criteria of the std search form
|
||||
MetaModel::Init_SetZListItems('standard_search', array('name','description', 'status', 'subject'));
|
||||
// - Criteria of the advanced search form
|
||||
// MetaModel::Init_SetZListItems('advanced_search', array('name'));
|
||||
}
|
||||
|
||||
// count the recipients found
|
||||
@@ -175,7 +217,18 @@ class ActionEmail extends ActionNotification
|
||||
// executed in the background, while making sure that any issue would be reported clearly
|
||||
protected $m_aMailErrors; //array of strings explaining the issue
|
||||
|
||||
// returns a the list of emails as a string, or a detailed error description
|
||||
/**
|
||||
* Return a the list of emails as a string, or a detailed error description
|
||||
*
|
||||
* @param string $sRecipAttCode
|
||||
* @param array $aArgs
|
||||
*
|
||||
* @return string
|
||||
* @throws \ArchivedObjectException
|
||||
* @throws \CoreException
|
||||
* @throws \CoreUnexpectedValue
|
||||
* @throws \MySQLException
|
||||
*/
|
||||
protected function FindRecipients($sRecipAttCode, $aArgs)
|
||||
{
|
||||
$sOQL = $this->Get($sRecipAttCode);
|
||||
@@ -224,9 +277,7 @@ class ActionEmail extends ActionNotification
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \Trigger $oTrigger
|
||||
* @param array $aContextArgs
|
||||
*
|
||||
* @inheritDoc
|
||||
* @throws \CoreException
|
||||
* @throws \CoreUnexpectedValue
|
||||
* @throws \CoreWarning
|
||||
@@ -306,6 +357,7 @@ class ActionEmail extends ActionNotification
|
||||
*
|
||||
* @return string
|
||||
* @throws \CoreException
|
||||
* @throws \Exception
|
||||
*/
|
||||
protected function _DoExecute($oTrigger, $aContextArgs, &$oLog)
|
||||
{
|
||||
@@ -316,15 +368,17 @@ class ActionEmail extends ActionNotification
|
||||
$this->m_aMailErrors = array();
|
||||
$bRes = false; // until we do succeed in sending the email
|
||||
|
||||
// Determine recicipients
|
||||
// Determine recipients
|
||||
//
|
||||
$sTo = $this->FindRecipients('to', $aContextArgs);
|
||||
$sCC = $this->FindRecipients('cc', $aContextArgs);
|
||||
$sBCC = $this->FindRecipients('bcc', $aContextArgs);
|
||||
|
||||
|
||||
$sFrom = MetaModel::ApplyParams($this->Get('from'), $aContextArgs);
|
||||
$sFromLabel = MetaModel::ApplyParams($this->Get('from_label'), $aContextArgs);
|
||||
$sReplyTo = MetaModel::ApplyParams($this->Get('reply_to'), $aContextArgs);
|
||||
|
||||
$sReplyToLabel = MetaModel::ApplyParams($this->Get('reply_to_label'), $aContextArgs);
|
||||
|
||||
$sSubject = MetaModel::ApplyParams($this->Get('subject'), $aContextArgs);
|
||||
$sBody = MetaModel::ApplyParams($this->Get('body'), $aContextArgs);
|
||||
|
||||
@@ -347,7 +401,7 @@ class ActionEmail extends ActionNotification
|
||||
if (isset($sTo)) $oLog->Set('to', $sTo);
|
||||
if (isset($sCC)) $oLog->Set('cc', $sCC);
|
||||
if (isset($sBCC)) $oLog->Set('bcc', $sBCC);
|
||||
if (isset($sFrom)) $oLog->Set('from', $sFrom);
|
||||
if (isset($sFrom)) $oLog->Set('from', empty($sFromLabel) ? $sFrom : "$sFromLabel <$sFrom>");
|
||||
if (isset($sSubject)) $oLog->Set('subject', $sSubject);
|
||||
if (isset($sBody)) $oLog->Set('body', $sBody);
|
||||
}
|
||||
@@ -367,15 +421,15 @@ class ActionEmail extends ActionNotification
|
||||
$sTestBody .= "<li>TO: $sTo</li>\n";
|
||||
$sTestBody .= "<li>CC: $sCC</li>\n";
|
||||
$sTestBody .= "<li>BCC: $sBCC</li>\n";
|
||||
$sTestBody .= "<li>From: $sFrom</li>\n";
|
||||
$sTestBody .= "<li>Reply-To: $sReplyTo</li>\n";
|
||||
$sTestBody .= empty($sFromLabel) ? "<li>From: $sFrom</li>\n": "<li>From: $sFromLabel <$sFrom></li>\n";
|
||||
$sTestBody .= empty($sReplyToLabel) ? "<li>Reply-To: $sReplyTo</li>\n": "<li>Reply-To: $sReplyToLabel <$sReplyTo></li>\n";
|
||||
$sTestBody .= "<li>References: $sReference</li>\n";
|
||||
$sTestBody .= "</ul>\n";
|
||||
$sTestBody .= "</p>\n";
|
||||
$sTestBody .= "</div>\n";
|
||||
$oEmail->SetBody($sTestBody, 'text/html', $sStyles);
|
||||
$oEmail->SetRecipientTO($this->Get('test_recipient'));
|
||||
$oEmail->SetRecipientFrom($sFrom);
|
||||
$oEmail->SetRecipientFrom($sFrom, $sFromLabel);
|
||||
$oEmail->SetReferences($sReference);
|
||||
$oEmail->SetMessageId($sMessageId);
|
||||
}
|
||||
@@ -386,8 +440,8 @@ class ActionEmail extends ActionNotification
|
||||
$oEmail->SetRecipientTO($sTo);
|
||||
$oEmail->SetRecipientCC($sCC);
|
||||
$oEmail->SetRecipientBCC($sBCC);
|
||||
$oEmail->SetRecipientFrom($sFrom);
|
||||
$oEmail->SetRecipientReplyTo($sReplyTo);
|
||||
$oEmail->SetRecipientFrom($sFrom, $sFromLabel);
|
||||
$oEmail->SetRecipientReplyTo($sReplyTo, $sReplyToLabel);
|
||||
$oEmail->SetReferences($sReference);
|
||||
$oEmail->SetMessageId($sMessageId);
|
||||
}
|
||||
@@ -439,4 +493,3 @@ class ActionEmail extends ActionNotification
|
||||
}
|
||||
}
|
||||
}
|
||||
?>
|
||||
|
||||
@@ -65,6 +65,10 @@ class ExecAsyncTask implements iBackgroundProcess
|
||||
*/
|
||||
abstract class AsyncTask extends DBObject
|
||||
{
|
||||
/**
|
||||
* @throws \CoreException
|
||||
* @throws \Exception
|
||||
*/
|
||||
public static function Init()
|
||||
{
|
||||
$aParams = array
|
||||
@@ -77,7 +81,6 @@ abstract class AsyncTask extends DBObject
|
||||
"db_table" => "priv_async_task",
|
||||
"db_key_field" => "id",
|
||||
"db_finalclass_field" => "realclass",
|
||||
"display_template" => "",
|
||||
);
|
||||
MetaModel::Init_Params($aParams);
|
||||
|
||||
@@ -285,11 +288,13 @@ abstract class AsyncTask extends DBObject
|
||||
|
||||
/**
|
||||
* Throws an exception (message and code)
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
abstract public function DoProcess();
|
||||
|
||||
/**
|
||||
* Describes the error codes that DoProcess can return by the mean of exceptions
|
||||
* Describes the error codes that DoProcess can return by the mean of exceptions
|
||||
*/
|
||||
static public function EnumErrorCodes()
|
||||
{
|
||||
@@ -316,7 +321,6 @@ class AsyncSendEmail extends AsyncTask
|
||||
"db_table" => "priv_async_send_email",
|
||||
"db_key_field" => "id",
|
||||
"db_finalclass_field" => "",
|
||||
"display_template" => "",
|
||||
);
|
||||
MetaModel::Init_Params($aParams);
|
||||
MetaModel::Init_InheritAttributes();
|
||||
@@ -352,6 +356,11 @@ class AsyncSendEmail extends AsyncTask
|
||||
$oNew->DBInsert();
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
* @throws \ArchivedObjectException
|
||||
* @throws \CoreException
|
||||
*/
|
||||
public function DoProcess()
|
||||
{
|
||||
$sMessage = $this->Get('message');
|
||||
|
||||
@@ -31,13 +31,9 @@ require_once('ormlinkset.class.inc.php');
|
||||
require_once('ormset.class.inc.php');
|
||||
require_once('ormtagset.class.inc.php');
|
||||
require_once('htmlsanitizer.class.inc.php');
|
||||
require_once(APPROOT.'sources/autoload.php');
|
||||
require_once('customfieldshandler.class.inc.php');
|
||||
require_once('ormcustomfieldsvalue.class.inc.php');
|
||||
require_once('datetimeformat.class.inc.php');
|
||||
// This should be changed to a use when we go full-namespace
|
||||
require_once(APPROOT.'sources/form/validator/validator.class.inc.php');
|
||||
require_once(APPROOT.'sources/form/validator/notemptyextkeyvalidator.class.inc.php');
|
||||
|
||||
/**
|
||||
* MissingColumnException - sent if an attribute is being created but the column is missing in the row
|
||||
@@ -295,7 +291,7 @@ abstract class AttributeDefinition
|
||||
* @param \DBObject $oHostObject
|
||||
* @param $value Object error if any, null otherwise
|
||||
*
|
||||
* @return bool
|
||||
* @return bool|string true for no errors, false or error message otherwise
|
||||
*/
|
||||
public function CheckValue(DBObject $oHostObject, $value)
|
||||
{
|
||||
@@ -1030,10 +1026,17 @@ abstract class AttributeDefinition
|
||||
$oFormField->AddValidator(new Validator($this->GetValidationPattern()));
|
||||
}
|
||||
|
||||
// Description
|
||||
$sAttDescription = $this->GetDescription();
|
||||
if(!empty($sAttDescription))
|
||||
{
|
||||
$oFormField->SetDescription($this->GetDescription());
|
||||
}
|
||||
|
||||
// Metadata
|
||||
$oFormField->AddMetadata('attribute-code', $this->GetCode());
|
||||
$oFormField->AddMetadata('attribute-type', get_class($this));
|
||||
$oFormField->AddMetadata('attribute-label', utils::HtmlEntities($this->GetLabel()));
|
||||
$oFormField->AddMetadata('attribute-label', $this->GetLabel());
|
||||
// - Attribute flags
|
||||
$aPossibleAttFlags = MetaModel::EnumPossibleAttributeFlags();
|
||||
foreach($aPossibleAttFlags as $sFlagCode => $iFlagValue)
|
||||
@@ -1050,7 +1053,7 @@ abstract class AttributeDefinition
|
||||
// - Value raw
|
||||
if ($this::IsScalar())
|
||||
{
|
||||
$oFormField->AddMetadata('value-raw', utils::HtmlEntities($oObject->Get($this->GetCode())));
|
||||
$oFormField->AddMetadata('value-raw', (string) $oObject->Get($this->GetCode()));
|
||||
}
|
||||
|
||||
return $oFormField;
|
||||
@@ -1270,6 +1273,15 @@ abstract class AttributeDefinition
|
||||
{
|
||||
return (string)$value;
|
||||
}
|
||||
|
||||
/*
|
||||
* return string
|
||||
*/
|
||||
public function GetRenderForDataTable(string $sClassAlias) :string
|
||||
{
|
||||
$sRenderFunction = "return data;";
|
||||
return $sRenderFunction;
|
||||
}
|
||||
}
|
||||
|
||||
class AttributeDashboard extends AttributeDefinition
|
||||
@@ -2273,22 +2285,17 @@ class AttributeLinkedSetIndirect extends AttributeLinkedSet
|
||||
/** @var \AttributeExternalKey $oExtKeyToRemote */
|
||||
$oExtKeyToRemote = MetaModel::GetAttributeDef($this->GetLinkedClass(), $this->GetExtKeyToRemote());
|
||||
$sRemoteClass = $oExtKeyToRemote->GetTargetClass();
|
||||
foreach(MetaModel::ListAttributeDefs($sRemoteClass) as $sRemoteAttCode => $oRemoteAttDef)
|
||||
{
|
||||
if (!$oRemoteAttDef instanceof AttributeLinkedSetIndirect)
|
||||
{
|
||||
foreach(MetaModel::ListAttributeDefs($sRemoteClass) as $sRemoteAttCode => $oRemoteAttDef) {
|
||||
if (!$oRemoteAttDef instanceof AttributeLinkedSetIndirect) {
|
||||
continue;
|
||||
}
|
||||
if ($oRemoteAttDef->GetLinkedClass() != $this->GetLinkedClass())
|
||||
{
|
||||
if ($oRemoteAttDef->GetLinkedClass() != $this->GetLinkedClass()) {
|
||||
continue;
|
||||
}
|
||||
if ($oRemoteAttDef->GetExtKeyToMe() != $this->GetExtKeyToRemote())
|
||||
{
|
||||
if ($oRemoteAttDef->GetExtKeyToMe() != $this->GetExtKeyToRemote()) {
|
||||
continue;
|
||||
}
|
||||
if ($oRemoteAttDef->GetExtKeyToRemote() != $this->GetExtKeyToMe())
|
||||
{
|
||||
if ($oRemoteAttDef->GetExtKeyToRemote() != $this->GetExtKeyToMe()) {
|
||||
continue;
|
||||
}
|
||||
$oRet = $oRemoteAttDef;
|
||||
@@ -4994,6 +5001,7 @@ class AttributePhoneNumber extends AttributeString
|
||||
|
||||
return '<a class="tel" href="'.$sUrl.'"><span class="text_decoration '.$sUrlDecorationClass.'"></span>'.parent::GetAsHTML($sValue).'</a>';
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -6654,6 +6662,23 @@ class AttributeExternalKey extends AttributeDBFieldVoid
|
||||
return (int)$proposedValue;
|
||||
}
|
||||
|
||||
public function GetPrerequisiteAttributes($sClass = null)
|
||||
{
|
||||
$aAttributes = parent::GetPrerequisiteAttributes($sClass);
|
||||
$oExpression = DBSearch::FromOQL($this->GetValuesDef()->GetFilterExpression())->GetCriteria();
|
||||
foreach ($oExpression->GetParameters('this') as $sAttCode)
|
||||
{
|
||||
// Skip the id as it cannot change anyway
|
||||
if ($sAttCode =='id') continue;
|
||||
|
||||
if (!in_array($sAttCode, $aAttributes))
|
||||
{
|
||||
$aAttributes[] = $sAttCode;
|
||||
}
|
||||
}
|
||||
return $aAttributes;
|
||||
}
|
||||
|
||||
public function GetMaximumComboLength()
|
||||
{
|
||||
return $this->GetOptional('max_combo_length', MetaModel::GetConfig()->Get('max_combo_length'));
|
||||
@@ -6759,8 +6784,7 @@ class AttributeExternalKey extends AttributeDBFieldVoid
|
||||
|
||||
public function GetAsHTML($sValue, $oHostObject = null, $bLocalize = true)
|
||||
{
|
||||
if (!is_null($oHostObject))
|
||||
{
|
||||
if (!is_null($oHostObject)) {
|
||||
return $oHostObject->GetAsHTML($this->GetCode(), $oHostObject);
|
||||
}
|
||||
|
||||
@@ -7962,18 +7986,6 @@ class AttributeImage extends AttributeBlob
|
||||
return "Image";
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
* @see AttributeBlob::MakeRealValue()
|
||||
*/
|
||||
public function MakeRealValue($proposedValue, $oHostObj)
|
||||
{
|
||||
$oDoc = parent::MakeRealValue($proposedValue, $oHostObj);
|
||||
|
||||
// The validation of the MIME Type is done by CheckFormat below
|
||||
return $oDoc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check that the supplied ormDocument actually contains an image
|
||||
* {@inheritDoc}
|
||||
@@ -10309,6 +10321,7 @@ class AttributeEnumSet extends AttributeSet
|
||||
return $sRes;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param ormSet $value
|
||||
* @param string $sSeparator
|
||||
@@ -11590,7 +11603,17 @@ class AttributeFriendlyName extends AttributeDefinition
|
||||
|
||||
public function GetPrerequisiteAttributes($sClass = null)
|
||||
{
|
||||
return $this->GetOptional("depends_on", array());
|
||||
// Code duplicated with AttributeObsolescenceFlag
|
||||
$aAttributes = $this->GetOptional("depends_on", array());
|
||||
$oExpression = $this->GetOQLExpression();
|
||||
foreach ($oExpression->ListRequiredFields() as $sClass => $sAttCode)
|
||||
{
|
||||
if (!in_array($sAttCode, $aAttributes))
|
||||
{
|
||||
$aAttributes[] = $sAttCode;
|
||||
}
|
||||
}
|
||||
return $aAttributes;
|
||||
}
|
||||
|
||||
public static function IsScalar()
|
||||
@@ -12822,7 +12845,17 @@ class AttributeObsolescenceFlag extends AttributeBoolean
|
||||
|
||||
public function GetPrerequisiteAttributes($sClass = null)
|
||||
{
|
||||
return $this->GetOptional("depends_on", array());
|
||||
// Code duplicated with AttributeFriendlyName
|
||||
$aAttributes = $this->GetOptional("depends_on", array());
|
||||
$oExpression = $this->GetOQLExpression();
|
||||
foreach ($oExpression->ListRequiredFields() as $sClass => $sAttCode)
|
||||
{
|
||||
if (!in_array($sAttCode, $aAttributes))
|
||||
{
|
||||
$aAttributes[] = $sAttCode;
|
||||
}
|
||||
}
|
||||
return $aAttributes;
|
||||
}
|
||||
|
||||
public function IsDirectField()
|
||||
|
||||
@@ -185,12 +185,9 @@ abstract class AbstractWeeklyScheduledProcess implements iScheduledProcess
|
||||
static::DEFAULT_MODULE_SETTING_ENABLED
|
||||
);
|
||||
|
||||
$sItopTimeZone = $this->getOConfig()->Get('timezone');
|
||||
$timezone = new DateTimeZone($sItopTimeZone);
|
||||
|
||||
if (!$bEnabled)
|
||||
{
|
||||
return new DateTime('3000-01-01', $timezone);
|
||||
return new DateTime('3000-01-01');
|
||||
}
|
||||
|
||||
// 1st - Interpret the list of days as ordered numbers (monday = 1)
|
||||
@@ -209,7 +206,7 @@ abstract class AbstractWeeklyScheduledProcess implements iScheduledProcess
|
||||
throw new ProcessInvalidConfigException($this->GetModuleName().": wrong format for setting '".static::MODULE_SETTING_TIME."' (found '$sProcessTime')");
|
||||
}
|
||||
|
||||
$oNow = new DateTime($sCurrentTime, $timezone);
|
||||
$oNow = new DateTime($sCurrentTime);
|
||||
$iNextPos = false;
|
||||
$sDay = $oNow->format('N');
|
||||
for ($iDay = (int) $sDay; $iDay <= 7; $iDay++)
|
||||
@@ -244,7 +241,6 @@ abstract class AbstractWeeklyScheduledProcess implements iScheduledProcess
|
||||
$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;
|
||||
|
||||
@@ -56,7 +56,6 @@ class BackgroundTask extends DBObject
|
||||
"db_table" => "priv_backgroundtask",
|
||||
"db_key_field" => "id",
|
||||
"db_finalclass_field" => "",
|
||||
"display_template" => "",
|
||||
);
|
||||
MetaModel::Init_Params($aParams);
|
||||
|
||||
@@ -72,7 +71,7 @@ class BackgroundTask extends DBObject
|
||||
MetaModel::Init_AddAttribute(new AttributeDecimal("average_run_duration", array("allowed_values"=>null, "sql"=>"average_run_duration", "digits"=> 8, "decimals"=> 3, "default_value"=>"0", "is_null_allowed"=>true, "depends_on"=>array())));
|
||||
|
||||
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 AttributeEnum("status", array("allowed_values"=>new ValueSetEnum('active,paused,removed'), "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())));
|
||||
}
|
||||
|
||||
|
||||
@@ -948,7 +948,7 @@ class BulkChange
|
||||
$iLoopTimeLimit = MetaModel::GetConfig()->Get('max_execution_time_per_loop');
|
||||
foreach($this->m_aData as $iRow => $aRowData)
|
||||
{
|
||||
set_time_limit($iLoopTimeLimit);
|
||||
set_time_limit(intval($iLoopTimeLimit));
|
||||
if (isset($aResult[$iRow]["__STATUS__"]))
|
||||
{
|
||||
// An issue at the earlier steps - skip the rest
|
||||
@@ -1067,13 +1067,13 @@ class BulkChange
|
||||
$iObj = $oObj->GetKey();
|
||||
if (!in_array($iObj, $aVisited))
|
||||
{
|
||||
set_time_limit($iLoopTimeLimit);
|
||||
set_time_limit(intval($iLoopTimeLimit));
|
||||
$iRow++;
|
||||
$this->UpdateMissingObject($aResult, $iRow, $oObj, $oChange);
|
||||
}
|
||||
}
|
||||
}
|
||||
set_time_limit($iPreviousTimeLimit);
|
||||
set_time_limit(itval($iPreviousTimeLimit));
|
||||
|
||||
// Fill in the blanks - the result matrix is expected to be 100% complete
|
||||
//
|
||||
|
||||
@@ -52,12 +52,18 @@ class CMDBChange extends DBObject
|
||||
//MetaModel::Init_InheritAttributes();
|
||||
MetaModel::Init_AddAttribute(new AttributeDateTime("date", array("allowed_values"=>null, "sql"=>"date", "default_value"=>"", "is_null_allowed"=>false, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeString("userinfo", array("allowed_values"=>null, "sql"=>"userinfo", "default_value"=>null, "is_null_allowed"=>true, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeExternalKey("user_id", array("allowed_values"=>null, "sql"=>"user_id", "targetclass"=>"User", "is_null_allowed"=>true, "on_target_delete"=>DEL_MANUAL, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeEnum("origin", array("allowed_values"=>new ValueSetEnum('interactive,csv-interactive,csv-import.php,webservice-soap,webservice-rest,synchro-data-source,email-processing,custom-extension'), "sql"=>"origin", "default_value"=>"interactive", "is_null_allowed"=>true, "depends_on"=>array())));
|
||||
}
|
||||
|
||||
// Helper to keep track of the author of a given change,
|
||||
// taking into account a variety of cases (contact attached or not, impersonation)
|
||||
static public function GetCurrentUserName()
|
||||
/**
|
||||
* Helper to keep track of the author of a given change,
|
||||
* taking into account a variety of cases (contact attached or not, impersonation)
|
||||
*
|
||||
* @return string
|
||||
* @throws \OQLException
|
||||
*/
|
||||
public static function GetCurrentUserName()
|
||||
{
|
||||
if (UserRights::IsImpersonated())
|
||||
{
|
||||
@@ -70,6 +76,19 @@ class CMDBChange extends DBObject
|
||||
return $sUserString;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the current user
|
||||
*
|
||||
* @return string|null
|
||||
* @throws \OQLException
|
||||
* @since 3.0.0
|
||||
*/
|
||||
public static function GetCurrentUserId()
|
||||
{
|
||||
// Note: We might have use only UserRights::GetRealUserId() as it would have done the same thing in the end
|
||||
return UserRights::IsImpersonated() ? UserRights::GetRealUserId() : UserRights::GetUserId();
|
||||
}
|
||||
|
||||
public function GetUserName()
|
||||
{
|
||||
if (preg_match('/^(.*)\\(CSV\\)$/i', $this->Get('userinfo'), $aMatches))
|
||||
@@ -83,5 +102,3 @@ class CMDBChange extends DBObject
|
||||
return $sUser;
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
|
||||
@@ -31,7 +31,22 @@
|
||||
* @package iTopORM
|
||||
*/
|
||||
|
||||
class CMDBChangeOp extends DBObject
|
||||
/**
|
||||
* Interface iCMDBChangeOp
|
||||
*
|
||||
* @since 3.0.0
|
||||
*/
|
||||
interface iCMDBChangeOp
|
||||
{
|
||||
/**
|
||||
* Describe (as a text string) the modifications corresponding to this change
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function GetDescription();
|
||||
}
|
||||
|
||||
class CMDBChangeOp extends DBObject implements iCMDBChangeOp
|
||||
{
|
||||
public static function Init()
|
||||
{
|
||||
@@ -54,6 +69,7 @@ class CMDBChangeOp extends DBObject
|
||||
MetaModel::Init_AddAttribute(new AttributeExternalKey("change", array("allowed_values"=>null, "sql"=>"changeid", "targetclass"=>"CMDBChange", "is_null_allowed"=>false, "on_target_delete"=>DEL_MANUAL, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeExternalField("date", array("allowed_values"=>null, "extkey_attcode"=>"change", "target_attcode"=>"date")));
|
||||
MetaModel::Init_AddAttribute(new AttributeExternalField("userinfo", array("allowed_values"=>null, "extkey_attcode"=>"change", "target_attcode"=>"userinfo")));
|
||||
MetaModel::Init_AddAttribute(new AttributeExternalField("user_id", array("allowed_values"=>null, "extkey_attcode"=>"change", "target_attcode"=>"user_id")));
|
||||
MetaModel::Init_AddAttribute(new AttributeString("objclass", array("allowed_values"=>null, "sql"=>"objclass", "default_value"=>"", "is_null_allowed"=>false, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeObjectKey("objkey", array("allowed_values"=>null, "class_attcode"=>"objclass", "sql"=>"objkey", "is_null_allowed"=>false, "depends_on"=>array())));
|
||||
|
||||
@@ -62,7 +78,7 @@ class CMDBChangeOp extends DBObject
|
||||
}
|
||||
|
||||
/**
|
||||
* Describe (as a text string) the modifications corresponding to this change
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function GetDescription()
|
||||
{
|
||||
@@ -83,8 +99,6 @@ class CMDBChangeOp extends DBObject
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Record the creation of an object
|
||||
*
|
||||
@@ -92,6 +106,9 @@ class CMDBChangeOp extends DBObject
|
||||
*/
|
||||
class CMDBChangeOpCreate extends CMDBChangeOp
|
||||
{
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public static function Init()
|
||||
{
|
||||
$aParams = array
|
||||
@@ -110,7 +127,7 @@ class CMDBChangeOpCreate extends CMDBChangeOp
|
||||
}
|
||||
|
||||
/**
|
||||
* Describe (as a text string) the modifications corresponding to this change
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function GetDescription()
|
||||
{
|
||||
@@ -118,7 +135,6 @@ class CMDBChangeOpCreate extends CMDBChangeOp
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Record the deletion of an object
|
||||
*
|
||||
@@ -126,6 +142,9 @@ class CMDBChangeOpCreate extends CMDBChangeOp
|
||||
*/
|
||||
class CMDBChangeOpDelete extends CMDBChangeOp
|
||||
{
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public static function Init()
|
||||
{
|
||||
$aParams = array
|
||||
@@ -147,16 +166,16 @@ class CMDBChangeOpDelete extends CMDBChangeOp
|
||||
// Last friendly name of the object
|
||||
MetaModel::Init_AddAttribute(new AttributeString("fname", array("allowed_values"=>null, "sql"=>"fname", "default_value"=>"", "is_null_allowed"=>true, "depends_on"=>array())));
|
||||
}
|
||||
|
||||
/**
|
||||
* Describe (as a text string) the modifications corresponding to this change
|
||||
*/
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function GetDescription()
|
||||
{
|
||||
return Dict::S('Change:ObjectDeleted');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Record the modification of an attribute (abstract)
|
||||
*
|
||||
@@ -164,6 +183,9 @@ class CMDBChangeOpDelete extends CMDBChangeOp
|
||||
*/
|
||||
class CMDBChangeOpSetAttribute extends CMDBChangeOp
|
||||
{
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public static function Init()
|
||||
{
|
||||
$aParams = array
|
||||
@@ -194,6 +216,9 @@ class CMDBChangeOpSetAttribute extends CMDBChangeOp
|
||||
*/
|
||||
class CMDBChangeOpSetAttributeScalar extends CMDBChangeOpSetAttribute
|
||||
{
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public static function Init()
|
||||
{
|
||||
$aParams = array
|
||||
@@ -216,10 +241,10 @@ class CMDBChangeOpSetAttributeScalar extends CMDBChangeOpSetAttribute
|
||||
MetaModel::Init_SetZListItems('details', array('date', 'userinfo', 'attcode', 'oldvalue', 'newvalue')); // Attributes to be displayed for the complete details
|
||||
MetaModel::Init_SetZListItems('list', array('date', 'userinfo', 'attcode', 'oldvalue', 'newvalue')); // Attributes to be displayed for a list
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Describe (as a text string) the modifications corresponding to this change
|
||||
*/
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function GetDescription()
|
||||
{
|
||||
$sResult = '';
|
||||
@@ -250,7 +275,10 @@ class CMDBChangeOpSetAttributeScalar extends CMDBChangeOpSetAttribute
|
||||
*/
|
||||
class CMDBChangeOpSetAttributeTagSet extends CMDBChangeOpSetAttribute
|
||||
{
|
||||
public static function Init()
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public static function Init()
|
||||
{
|
||||
$aParams = array
|
||||
(
|
||||
@@ -273,10 +301,10 @@ class CMDBChangeOpSetAttributeTagSet extends CMDBChangeOpSetAttribute
|
||||
MetaModel::Init_SetZListItems('list', array('date', 'userinfo', 'attcode', 'oldvalue', 'newvalue')); // Attributes to be displayed for a list
|
||||
}
|
||||
|
||||
/**
|
||||
* Describe (as a text string) the modifications corresponding to this change
|
||||
*/
|
||||
public function GetDescription()
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function GetDescription()
|
||||
{
|
||||
$sResult = '';
|
||||
$sTargetObjectClass = $this->Get('objclass');
|
||||
@@ -307,6 +335,9 @@ class CMDBChangeOpSetAttributeTagSet extends CMDBChangeOpSetAttribute
|
||||
*/
|
||||
class CMDBChangeOpSetAttributeURL extends CMDBChangeOpSetAttribute
|
||||
{
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public static function Init()
|
||||
{
|
||||
$aParams = array
|
||||
@@ -329,10 +360,10 @@ class CMDBChangeOpSetAttributeURL extends CMDBChangeOpSetAttribute
|
||||
MetaModel::Init_SetZListItems('details', array('date', 'userinfo', 'attcode', 'oldvalue', 'newvalue')); // Attributes to be displayed for the complete details
|
||||
MetaModel::Init_SetZListItems('list', array('date', 'userinfo', 'attcode', 'oldvalue', 'newvalue')); // Attributes to be displayed for a list
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Describe (as a text string) the modifications corresponding to this change
|
||||
*/
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function GetDescription()
|
||||
{
|
||||
$sResult = '';
|
||||
@@ -363,6 +394,9 @@ class CMDBChangeOpSetAttributeURL extends CMDBChangeOpSetAttribute
|
||||
*/
|
||||
class CMDBChangeOpSetAttributeBlob extends CMDBChangeOpSetAttribute
|
||||
{
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public static function Init()
|
||||
{
|
||||
$aParams = array
|
||||
@@ -384,10 +418,10 @@ class CMDBChangeOpSetAttributeBlob extends CMDBChangeOpSetAttribute
|
||||
MetaModel::Init_SetZListItems('details', array('date', 'userinfo', 'attcode')); // Attributes to be displayed for the complete details
|
||||
MetaModel::Init_SetZListItems('list', array('date', 'userinfo', 'attcode')); // Attributes to be displayed for a list
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Describe (as a text string) the modifications corresponding to this change
|
||||
*/
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function GetDescription()
|
||||
{
|
||||
// Temporary, until we change the options of GetDescription() -needs a more global revision
|
||||
@@ -430,11 +464,15 @@ class CMDBChangeOpSetAttributeBlob extends CMDBChangeOpSetAttribute
|
||||
return $sResult;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Safely record the modification of one way encrypted password
|
||||
*/
|
||||
class CMDBChangeOpSetAttributeOneWayPassword extends CMDBChangeOpSetAttribute
|
||||
{
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public static function Init()
|
||||
{
|
||||
$aParams = array
|
||||
@@ -456,10 +494,10 @@ class CMDBChangeOpSetAttributeOneWayPassword extends CMDBChangeOpSetAttribute
|
||||
MetaModel::Init_SetZListItems('details', array('date', 'userinfo', 'attcode')); // Attributes to be displayed for the complete details
|
||||
MetaModel::Init_SetZListItems('list', array('date', 'userinfo', 'attcode')); // Attributes to be displayed for a list
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Describe (as a text string) the modifications corresponding to this change
|
||||
*/
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function GetDescription()
|
||||
{
|
||||
// Temporary, until we change the options of GetDescription() -needs a more global revision
|
||||
@@ -495,6 +533,9 @@ class CMDBChangeOpSetAttributeOneWayPassword extends CMDBChangeOpSetAttribute
|
||||
*/
|
||||
class CMDBChangeOpSetAttributeEncrypted extends CMDBChangeOpSetAttribute
|
||||
{
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public static function Init()
|
||||
{
|
||||
$aParams = array
|
||||
@@ -516,10 +557,10 @@ class CMDBChangeOpSetAttributeEncrypted extends CMDBChangeOpSetAttribute
|
||||
MetaModel::Init_SetZListItems('details', array('date', 'userinfo', 'attcode')); // Attributes to be displayed for the complete details
|
||||
MetaModel::Init_SetZListItems('list', array('date', 'userinfo', 'attcode')); // Attributes to be displayed for a list
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Describe (as a text string) the modifications corresponding to this change
|
||||
*/
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function GetDescription()
|
||||
{
|
||||
// Temporary, until we change the options of GetDescription() -needs a more global revision
|
||||
@@ -558,6 +599,9 @@ class CMDBChangeOpSetAttributeEncrypted extends CMDBChangeOpSetAttribute
|
||||
*/
|
||||
class CMDBChangeOpSetAttributeText extends CMDBChangeOpSetAttribute
|
||||
{
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public static function Init()
|
||||
{
|
||||
$aParams = array
|
||||
@@ -579,10 +623,10 @@ class CMDBChangeOpSetAttributeText extends CMDBChangeOpSetAttribute
|
||||
MetaModel::Init_SetZListItems('details', array('date', 'userinfo', 'attcode')); // Attributes to be displayed for the complete details
|
||||
MetaModel::Init_SetZListItems('list', array('date', 'userinfo', 'attcode')); // Attributes to be displayed for a list
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Describe (as a text string) the modifications corresponding to this change
|
||||
*/
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function GetDescription()
|
||||
{
|
||||
// Temporary, until we change the options of GetDescription() -needs a more global revision
|
||||
@@ -623,6 +667,9 @@ class CMDBChangeOpSetAttributeText extends CMDBChangeOpSetAttribute
|
||||
*/
|
||||
class CMDBChangeOpSetAttributeLongText extends CMDBChangeOpSetAttribute
|
||||
{
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public static function Init()
|
||||
{
|
||||
$aParams = array
|
||||
@@ -644,10 +691,10 @@ class CMDBChangeOpSetAttributeLongText extends CMDBChangeOpSetAttribute
|
||||
MetaModel::Init_SetZListItems('details', array('date', 'userinfo', 'attcode')); // Attributes to be displayed for the complete details
|
||||
MetaModel::Init_SetZListItems('list', array('date', 'userinfo', 'attcode')); // Attributes to be displayed for a list
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Describe (as a text string) the modifications corresponding to this change
|
||||
*/
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function GetDescription()
|
||||
{
|
||||
$sResult = '';
|
||||
@@ -685,6 +732,9 @@ class CMDBChangeOpSetAttributeLongText extends CMDBChangeOpSetAttribute
|
||||
*/
|
||||
class CMDBChangeOpSetAttributeHTML extends CMDBChangeOpSetAttributeLongText
|
||||
{
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public static function Init()
|
||||
{
|
||||
$aParams = array
|
||||
@@ -705,8 +755,9 @@ class CMDBChangeOpSetAttributeHTML extends CMDBChangeOpSetAttributeLongText
|
||||
MetaModel::Init_SetZListItems('details', array('date', 'userinfo', 'attcode')); // Attributes to be displayed for the complete details
|
||||
MetaModel::Init_SetZListItems('list', array('date', 'userinfo', 'attcode')); // Attributes to be displayed for a list
|
||||
}
|
||||
|
||||
/**
|
||||
* Describe (as a text string) the modifications corresponding to this change
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function GetDescription()
|
||||
{
|
||||
@@ -748,6 +799,9 @@ class CMDBChangeOpSetAttributeHTML extends CMDBChangeOpSetAttributeLongText
|
||||
*/
|
||||
class CMDBChangeOpSetAttributeCaseLog extends CMDBChangeOpSetAttribute
|
||||
{
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public static function Init()
|
||||
{
|
||||
$aParams = array
|
||||
@@ -769,10 +823,10 @@ class CMDBChangeOpSetAttributeCaseLog extends CMDBChangeOpSetAttribute
|
||||
MetaModel::Init_SetZListItems('details', array('date', 'userinfo', 'attcode')); // Attributes to be displayed for the complete details
|
||||
MetaModel::Init_SetZListItems('list', array('date', 'userinfo', 'attcode')); // Attributes to be displayed for a list
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Describe (as a text string) the modifications corresponding to this change
|
||||
*/
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function GetDescription()
|
||||
{
|
||||
// Temporary, until we change the options of GetDescription() -needs a more global revision
|
||||
@@ -799,14 +853,18 @@ class CMDBChangeOpSetAttributeCaseLog extends CMDBChangeOpSetAttribute
|
||||
}
|
||||
$oObj = $oMonoObjectSet->Fetch();
|
||||
$oCaseLog = $oObj->Get($this->Get('attcode'));
|
||||
$iMaxVisibleLength = MetaModel::getConfig()->Get('max_history_case_log_entry_length', 0);
|
||||
$sTextEntry = '<div class="history_entry history_entry_truncated"><div class="history_html_content">'.$oCaseLog->GetEntryAt($this->Get('lastentry')).'</div></div>';
|
||||
|
||||
$sResult = Dict::Format('Change:AttName_EntryAdded', $sAttName, $sTextEntry);
|
||||
}
|
||||
return $sResult;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param string $sRawText
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function ToHtml($sRawText)
|
||||
{
|
||||
return str_replace(array("\r\n", "\n", "\r"), "<br/>", htmlentities($sRawText, ENT_QUOTES, 'UTF-8'));
|
||||
@@ -820,6 +878,9 @@ class CMDBChangeOpSetAttributeCaseLog extends CMDBChangeOpSetAttribute
|
||||
*/
|
||||
class CMDBChangeOpPlugin extends CMDBChangeOp
|
||||
{
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public static function Init()
|
||||
{
|
||||
$aParams = array
|
||||
@@ -841,10 +902,10 @@ class CMDBChangeOpPlugin extends CMDBChangeOp
|
||||
*/
|
||||
MetaModel::Init_InheritAttributes();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Describe (as a text string) the modifications corresponding to this change
|
||||
*/
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function GetDescription()
|
||||
{
|
||||
return $this->Get('description');
|
||||
@@ -858,6 +919,9 @@ class CMDBChangeOpPlugin extends CMDBChangeOp
|
||||
*/
|
||||
abstract class CMDBChangeOpSetAttributeLinks extends CMDBChangeOpSetAttribute
|
||||
{
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public static function Init()
|
||||
{
|
||||
$aParams = array
|
||||
@@ -888,6 +952,9 @@ abstract class CMDBChangeOpSetAttributeLinks extends CMDBChangeOpSetAttribute
|
||||
*/
|
||||
class CMDBChangeOpSetAttributeLinksAddRemove extends CMDBChangeOpSetAttributeLinks
|
||||
{
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public static function Init()
|
||||
{
|
||||
$aParams = array
|
||||
@@ -908,8 +975,8 @@ class CMDBChangeOpSetAttributeLinksAddRemove extends CMDBChangeOpSetAttributeLin
|
||||
}
|
||||
|
||||
/**
|
||||
* Describe (as a text string) the modifications corresponding to this change
|
||||
*/
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function GetDescription()
|
||||
{
|
||||
$sResult = '';
|
||||
@@ -952,6 +1019,9 @@ class CMDBChangeOpSetAttributeLinksAddRemove extends CMDBChangeOpSetAttributeLin
|
||||
*/
|
||||
class CMDBChangeOpSetAttributeLinksTune extends CMDBChangeOpSetAttributeLinks
|
||||
{
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public static function Init()
|
||||
{
|
||||
$aParams = array
|
||||
@@ -972,8 +1042,8 @@ class CMDBChangeOpSetAttributeLinksTune extends CMDBChangeOpSetAttributeLinks
|
||||
}
|
||||
|
||||
/**
|
||||
* Describe (as a text string) the modifications corresponding to this change
|
||||
*/
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function GetDescription()
|
||||
{
|
||||
$sResult = '';
|
||||
@@ -1039,6 +1109,9 @@ class CMDBChangeOpSetAttributeLinksTune extends CMDBChangeOpSetAttributeLinks
|
||||
*/
|
||||
class CMDBChangeOpSetAttributeCustomFields extends CMDBChangeOpSetAttribute
|
||||
{
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public static function Init()
|
||||
{
|
||||
$aParams = array
|
||||
@@ -1062,7 +1135,7 @@ class CMDBChangeOpSetAttributeCustomFields extends CMDBChangeOpSetAttribute
|
||||
}
|
||||
|
||||
/**
|
||||
* Describe (as a text string) the modifications corresponding to this change
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function GetDescription()
|
||||
{
|
||||
|
||||
@@ -94,6 +94,7 @@ abstract class CMDBObject extends DBObject
|
||||
// Note: this value is static, but that could be changed because it is sometimes a real issue (see update of interfaces / connected_to
|
||||
protected static $m_oCurrChange = null;
|
||||
protected static $m_sInfo = null; // null => the information is built in a standard way
|
||||
protected static $m_sUserId = null; // null => the user doing the change is unknown
|
||||
protected static $m_sOrigin = null; // null => the origin is 'interactive'
|
||||
|
||||
/**
|
||||
@@ -154,6 +155,21 @@ abstract class CMDBObject extends DBObject
|
||||
self::$m_sInfo = $sInfo;
|
||||
}
|
||||
|
||||
/**
|
||||
* Provide information about the user doing the change
|
||||
*
|
||||
* @see static::SetTrackInfo
|
||||
* @see static::SetCurrentChange
|
||||
*
|
||||
* @param string $sId ID of the user doing the change, null if not done by a user (eg. background task)
|
||||
*
|
||||
* @since 3.0.0
|
||||
*/
|
||||
public static function SetTrackUserId($sId)
|
||||
{
|
||||
self::$m_sUserId = $sId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides information about the origin of the change
|
||||
*
|
||||
@@ -182,6 +198,25 @@ abstract class CMDBObject extends DBObject
|
||||
return self::$m_sInfo;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the ID of the user doing the change (defaulting to null)
|
||||
*
|
||||
* @return string|null
|
||||
* @throws \OQLException
|
||||
* @since 3.0.0
|
||||
*/
|
||||
protected static function GetTrackUserId()
|
||||
{
|
||||
if (is_null(self::$m_sUserId))
|
||||
{
|
||||
return CMDBChange::GetCurrentUserId();
|
||||
}
|
||||
else
|
||||
{
|
||||
return self::$m_sUserId;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the 'origin' information (defaulting to 'interactive')
|
||||
@@ -202,12 +237,21 @@ abstract class CMDBObject extends DBObject
|
||||
* 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
|
||||
*
|
||||
* @throws \ArchivedObjectException
|
||||
* @throws \CoreCannotSaveObjectException
|
||||
* @throws \CoreException
|
||||
* @throws \CoreUnexpectedValue
|
||||
* @throws \CoreWarning
|
||||
* @throws \MySQLException
|
||||
* @throws \OQLException
|
||||
*/
|
||||
protected static function CreateChange()
|
||||
{
|
||||
self::$m_oCurrChange = MetaModel::NewObject("CMDBChange");
|
||||
self::$m_oCurrChange->Set("date", time());
|
||||
self::$m_oCurrChange->Set("userinfo", self::GetTrackInfo());
|
||||
self::$m_oCurrChange->Set("user_id", self::GetTrackUserId());
|
||||
self::$m_oCurrChange->Set("origin", self::GetTrackOrigin());
|
||||
self::$m_oCurrChange->DBInsert();
|
||||
}
|
||||
@@ -513,7 +557,14 @@ abstract class CMDBObject extends DBObject
|
||||
/**
|
||||
* Helper to ultimately check user rights before writing (Insert, Update or Delete)
|
||||
* The check should never fail, because the UI should prevent from such a usage
|
||||
* Anyhow, if the user has found a workaround... the security gets enforced here
|
||||
* Anyhow, if the user has found a workaround... the security gets enforced here
|
||||
*
|
||||
* @deprecated 3.0.0 N°2591 will be removed in 3.1.0
|
||||
*
|
||||
* @param bool $bSkipStrongSecurity
|
||||
* @param int $iActionCode
|
||||
*
|
||||
* @throws \SecurityException
|
||||
*/
|
||||
protected function CheckUserRights($bSkipStrongSecurity, $iActionCode)
|
||||
{
|
||||
@@ -538,83 +589,6 @@ 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);
|
||||
$this->CheckUserRights($bSkipStrongSecurity, UR_ACTION_MODIFY);
|
||||
$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);
|
||||
$this->CheckUserRights($bSkipStrongSecurity, UR_ACTION_MODIFY);
|
||||
$ret = $this->DBInsertTracked_Internal(true);
|
||||
return $ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* @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)
|
||||
{
|
||||
if ($bDoNotReload)
|
||||
{
|
||||
$ret = $this->DBInsertNoReload();
|
||||
}
|
||||
else
|
||||
{
|
||||
$ret = $this->DBInsert();
|
||||
}
|
||||
return $ret;
|
||||
}
|
||||
|
||||
public function DBClone($newKey = null)
|
||||
{
|
||||
return $this->DBCloneTracked_Internal();
|
||||
@@ -647,24 +621,6 @@ 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);
|
||||
$this->CheckUserRights($bSkipStrongSecurity, UR_ACTION_MODIFY);
|
||||
$this->DBUpdate();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param null $oDeletionPlan
|
||||
@@ -684,31 +640,6 @@ abstract class CMDBObject extends DBObject
|
||||
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);
|
||||
$this->CheckUserRights($bSkipStrongSecurity, UR_ACTION_DELETE);
|
||||
$this->DBDeleteTracked_Internal($oDeletionPlan);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param null $oDeletionPlan
|
||||
*
|
||||
|
||||
@@ -859,25 +859,6 @@ class CMDBSource
|
||||
self::$m_iTransactionLevel = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @deprecated 2.7.0 N°1627 use ItopCounter instead
|
||||
*
|
||||
* @param string $sTable
|
||||
*
|
||||
* @return int
|
||||
* @throws \MySQLException
|
||||
* @throws \MySQLHasGoneAwayException
|
||||
*/
|
||||
public static function GetNextInsertId($sTable)
|
||||
{
|
||||
$sSQL = "SHOW TABLE STATUS LIKE '$sTable'";
|
||||
$oResult = self::Query($sSQL);
|
||||
$aRow = $oResult->fetch_assoc();
|
||||
|
||||
return $aRow['Auto_increment'];
|
||||
}
|
||||
|
||||
public static function GetInsertId()
|
||||
{
|
||||
$iRes = self::$m_oMysqli->insert_id;
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -93,7 +93,7 @@ class CoreException extends Exception
|
||||
* 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
|
||||
* @since 2.7.2/ 3.0.0
|
||||
*/
|
||||
public function getFullStackTraceAsString(){
|
||||
return "" . $this;
|
||||
|
||||
@@ -301,7 +301,7 @@ EOF
|
||||
}
|
||||
while($aRow = $oSet->FetchAssoc())
|
||||
{
|
||||
set_time_limit($iLoopTimeLimit);
|
||||
set_time_limit(intval($iLoopTimeLimit));
|
||||
$aData = array();
|
||||
foreach($this->aStatusInfo['fields'] as $iCol => $aFieldSpec)
|
||||
{
|
||||
@@ -339,7 +339,7 @@ EOF
|
||||
// Restore original date & time formats
|
||||
AttributeDateTime::SetFormat($oPrevDateTimeFormat);
|
||||
AttributeDate::SetFormat($oPrevDateFormat);
|
||||
set_time_limit($iPreviousTimeLimit);
|
||||
set_time_limit(intval($iPreviousTimeLimit));
|
||||
$this->aStatusInfo['position'] += $this->iChunkSize;
|
||||
if ($this->aStatusInfo['total'] == 0)
|
||||
{
|
||||
|
||||
@@ -135,7 +135,7 @@ class CSVParser
|
||||
// More time for the next row
|
||||
if ($this->m_iTimeLimitPerRow !== null)
|
||||
{
|
||||
set_time_limit($this->m_iTimeLimitPerRow);
|
||||
set_time_limit(intval($this->m_iTimeLimitPerRow));
|
||||
}
|
||||
}
|
||||
protected function __AddCellTrimmed($c = null, $aFieldMap = null)
|
||||
@@ -194,7 +194,7 @@ class CSVParser
|
||||
{
|
||||
// Give some time for the first row
|
||||
$iTimeLimit = ini_get('max_execution_time');
|
||||
set_time_limit($this->m_iTimeLimitPerRow);
|
||||
set_time_limit(intval($this->m_iTimeLimitPerRow));
|
||||
}
|
||||
for($i = 0; $i <= $iDataLength ; $i++)
|
||||
{
|
||||
@@ -255,7 +255,7 @@ class CSVParser
|
||||
if ($iTimeLimit !== null)
|
||||
{
|
||||
// Restore the previous time limit
|
||||
set_time_limit($iTimeLimit);
|
||||
set_time_limit(intval($iTimeLimit));
|
||||
}
|
||||
return $this->m_aDataSet;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<itop_design xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="1.7">
|
||||
<itop_design xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="3.0">
|
||||
<user_rights>
|
||||
<profiles>
|
||||
<profile id="1024" _delta="define">
|
||||
|
||||
@@ -547,74 +547,64 @@ abstract class DBObject implements iDisplay
|
||||
*/
|
||||
public function Set($sAttCode, $value)
|
||||
{
|
||||
if ($sAttCode == 'finalclass')
|
||||
{
|
||||
if ($sAttCode == 'finalclass') {
|
||||
// Ignore it - this attribute is set upon object creation and that's it
|
||||
return false;
|
||||
}
|
||||
|
||||
$oAttDef = MetaModel::GetAttributeDef(get_class($this), $sAttCode);
|
||||
|
||||
if (!$oAttDef->IsWritable())
|
||||
{
|
||||
if (!$oAttDef->IsWritable()) {
|
||||
$sClass = get_class($this);
|
||||
throw new Exception("Attempting to set the value on the read-only attribute $sClass::$sAttCode");
|
||||
}
|
||||
|
||||
if ($this->m_bIsInDB && !$this->m_bFullyLoaded && !$this->m_bDirty)
|
||||
{
|
||||
if ($this->m_bIsInDB && !$this->m_bFullyLoaded && !$this->m_bDirty) {
|
||||
// First time Set is called... ensure that the object gets fully loaded
|
||||
// Otherwise we would lose the values on a further Reload
|
||||
// + consistency does not make sense !
|
||||
$this->Reload();
|
||||
}
|
||||
|
||||
if ($oAttDef->IsExternalKey())
|
||||
{
|
||||
if (is_object($value))
|
||||
{
|
||||
// Setting an external key with a whole object (instead of just an ID)
|
||||
// let's initialize also the external fields that depend on it
|
||||
// (useful when building objects in memory and not from a query)
|
||||
/** @var \AttributeExternalKey $oAttDef */
|
||||
if ( (get_class($value) != $oAttDef->GetTargetClass()) && (!is_subclass_of($value, $oAttDef->GetTargetClass())))
|
||||
{
|
||||
throw new CoreUnexpectedValue("Trying to set the value of '$sAttCode', to an object of class '".get_class($value)."', whereas it's an ExtKey to '".$oAttDef->GetTargetClass()."'. Ignored");
|
||||
}
|
||||
if ($oAttDef->IsExternalKey() && is_object($value)) {
|
||||
// Setting an external key with a whole object (instead of just an ID)
|
||||
// let's initialize also the external fields that depend on it
|
||||
// (useful when building objects in memory and not from a query)
|
||||
/** @var \AttributeExternalKey $oAttDef */
|
||||
if ((get_class($value) != $oAttDef->GetTargetClass()) && (!is_subclass_of($value, $oAttDef->GetTargetClass()))) {
|
||||
throw new CoreUnexpectedValue("Trying to set the value of '$sAttCode', to an object of class '".get_class($value)."', whereas it's an ExtKey to '".$oAttDef->GetTargetClass()."'. Ignored");
|
||||
}
|
||||
|
||||
foreach(MetaModel::ListAttributeDefs(get_class($this)) as $sCode => $oDef)
|
||||
{
|
||||
/** @var \AttributeExternalField $oDef */
|
||||
if ($oDef->IsExternalField() && ($oDef->GetKeyAttCode() == $sAttCode))
|
||||
{
|
||||
/** @var \DBObject $value */
|
||||
$this->m_aCurrValues[$sCode] = $value->Get($oDef->GetExtAttCode());
|
||||
$this->m_aLoadedAtt[$sCode] = true;
|
||||
}
|
||||
foreach (MetaModel::GetDependentAttributes(get_class($this), $sAttCode) as $sCode) {
|
||||
$oDef = MetaModel::GetAttributeDef(get_class($this), $sCode);
|
||||
/** @var \AttributeExternalField $oDef */
|
||||
if ($oDef->IsExternalField() && ($oDef->GetKeyAttCode() == $sAttCode)) {
|
||||
/** @var \DBObject $value */
|
||||
$this->m_aCurrValues[$sCode] = $value->Get($oDef->GetExtAttCode());
|
||||
$this->m_aLoadedAtt[$sCode] = true;
|
||||
}
|
||||
elseif ($oDef->IsBasedOnOQLExpression()) {
|
||||
$this->m_aCurrValues[$sCode] = $this->GetDefaultValue($sCode);
|
||||
unset($this->m_aLoadedAtt[$sCode]);
|
||||
}
|
||||
}
|
||||
else if ($this->m_aCurrValues[$sAttCode] != $value)
|
||||
{
|
||||
// Setting an external key, but no any other information is available...
|
||||
// Invalidate the corresponding fields so that they get reloaded in case they are needed (See Get())
|
||||
foreach(MetaModel::ListAttributeDefs(get_class($this)) as $sCode => $oDef)
|
||||
{
|
||||
/** @var \AttributeExternalKey $oDef */
|
||||
if ($oDef->IsExternalField() && ($oDef->GetKeyAttCode() == $sAttCode))
|
||||
{
|
||||
} else {
|
||||
if ($this->m_aCurrValues[$sAttCode] !== $value) {
|
||||
// Invalidate dependent fields so that they get reloaded in case they are needed (See Get())
|
||||
//
|
||||
foreach (MetaModel::GetDependentAttributes(get_class($this), $sAttCode) as $sCode) {
|
||||
$oDef = MetaModel::GetAttributeDef(get_class($this), $sCode);
|
||||
if (($oDef->IsExternalField() && ($oDef->GetKeyAttCode() == $sAttCode)) || $oDef->IsBasedOnOQLExpression()) {
|
||||
$this->m_aCurrValues[$sCode] = $this->GetDefaultValue($sCode);
|
||||
unset($this->m_aLoadedAtt[$sCode]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if ($oAttDef->IsLinkSet() && ($value != null))
|
||||
{
|
||||
if ($oAttDef->IsLinkSet() && ($value != null)) {
|
||||
$realvalue = clone $this->m_aCurrValues[$sAttCode];
|
||||
$realvalue->UpdateFromCompleteList($value);
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
$realvalue = $oAttDef->MakeRealValue($value, $this);
|
||||
}
|
||||
$this->_Set($sAttCode, $realvalue);
|
||||
@@ -787,20 +777,20 @@ abstract class DBObject implements iDisplay
|
||||
{
|
||||
// Standard case... we have the information directly
|
||||
}
|
||||
elseif ($this->m_bIsInDB && !$this->m_bDirty)
|
||||
elseif ($this->m_bIsInDB && !$this->m_bFullyLoaded && !$this->m_bDirty)
|
||||
{
|
||||
// Lazy load (polymorphism): complete by reloading the entire object
|
||||
// #@# non-scalar attributes.... handle that differently?
|
||||
$oKPI = new ExecutionKPI();
|
||||
$this->Reload();
|
||||
$oKPI->ComputeStats('Reload', get_class($this).'/'.$sAttCode);
|
||||
}
|
||||
elseif ($sAttCode == 'friendlyname')
|
||||
elseif ($oAttDef->IsBasedOnOQLExpression())
|
||||
{
|
||||
// The friendly name is not computed and the object is dirty
|
||||
// Todo: implement the computation of the friendly name based on sprintf()
|
||||
//
|
||||
$this->m_aCurrValues[$sAttCode] = '';
|
||||
// Recompute -which is likely to call Get()
|
||||
//
|
||||
/** @var AttributeFriendlyName|\AttributeObsolescenceFlag $oAttDef */
|
||||
$this->m_aCurrValues[$sAttCode] = $this->EvaluateExpression($oAttDef->GetOQLExpression());
|
||||
$this->m_aLoadedAtt[$sAttCode] = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1683,6 +1673,7 @@ abstract class DBObject implements iDisplay
|
||||
public function GetAttributeFlags($sAttCode, &$aReasons = array(), $sTargetState = '')
|
||||
{
|
||||
$iFlags = 0; // By default (if no life cycle) no flag at all
|
||||
$sClass = get_class($this);
|
||||
|
||||
$aReadOnlyAtts = $this->GetReadOnlyAttributes();
|
||||
if (($aReadOnlyAtts != null) && (in_array($sAttCode, $aReadOnlyAtts)))
|
||||
@@ -1690,16 +1681,16 @@ abstract class DBObject implements iDisplay
|
||||
return OPT_ATT_READONLY;
|
||||
}
|
||||
|
||||
$sStateAttCode = MetaModel::GetStateAttributeCode(get_class($this));
|
||||
if (!empty($sStateAttCode))
|
||||
if (MetaModel::HasLifecycle($sClass))
|
||||
{
|
||||
if ($sTargetState != '')
|
||||
{
|
||||
$iFlags = MetaModel::GetAttributeFlags(get_class($this), $sTargetState, $sAttCode);
|
||||
$iFlags = MetaModel::GetAttributeFlags($sClass, $sTargetState, $sAttCode);
|
||||
}
|
||||
else
|
||||
{
|
||||
$iFlags = MetaModel::GetAttributeFlags(get_class($this), $this->Get($sStateAttCode), $sAttCode);
|
||||
$sStateAttCode = MetaModel::GetStateAttributeCode($sClass);
|
||||
$iFlags = MetaModel::GetAttributeFlags($sClass, $this->Get($sStateAttCode), $sAttCode);
|
||||
}
|
||||
}
|
||||
$aReasons = array();
|
||||
@@ -1752,10 +1743,10 @@ abstract class DBObject implements iDisplay
|
||||
public function GetTransitionFlags($sAttCode, $sStimulus, &$aReasons = array(), $sOriginState = '')
|
||||
{
|
||||
$iFlags = 0; // By default (if no lifecycle) no flag at all
|
||||
$sClass = get_class($this);
|
||||
|
||||
$sStateAttCode = MetaModel::GetStateAttributeCode(get_class($this));
|
||||
// If no state attribute, there is no lifecycle
|
||||
if (empty($sStateAttCode))
|
||||
if (!MetaModel::HasLifecycle($sClass))
|
||||
{
|
||||
return $iFlags;
|
||||
}
|
||||
@@ -1763,6 +1754,7 @@ abstract class DBObject implements iDisplay
|
||||
// Retrieving current state if necessary
|
||||
if ($sOriginState === '')
|
||||
{
|
||||
$sStateAttCode = MetaModel::GetStateAttributeCode($sClass);
|
||||
$sOriginState = $this->Get($sStateAttCode);
|
||||
}
|
||||
|
||||
@@ -1770,7 +1762,7 @@ abstract class DBObject implements iDisplay
|
||||
$iAttributeFlags = $this->GetAttributeFlags($sAttCode, $aReasons, $sOriginState);
|
||||
|
||||
// Retrieving transition flags
|
||||
$iTransitionFlags = MetaModel::GetTransitionFlags(get_class($this), $sOriginState, $sStimulus, $sAttCode);
|
||||
$iTransitionFlags = MetaModel::GetTransitionFlags($sClass, $sOriginState, $sStimulus, $sAttCode);
|
||||
|
||||
// Merging transition flags with attribute flags
|
||||
$iFlags = $iTransitionFlags | $iAttributeFlags;
|
||||
@@ -1821,10 +1813,12 @@ abstract class DBObject implements iDisplay
|
||||
public function GetInitialStateAttributeFlags($sAttCode, &$aReasons = array())
|
||||
{
|
||||
$iFlags = 0;
|
||||
$sStateAttCode = MetaModel::GetStateAttributeCode(get_class($this));
|
||||
if (!empty($sStateAttCode))
|
||||
$sClass = get_class($this);
|
||||
|
||||
if (MetaModel::HasLifecycle($sClass))
|
||||
{
|
||||
$iFlags = MetaModel::GetInitialStateAttributeFlags(get_class($this), $this->Get($sStateAttCode), $sAttCode);
|
||||
$sStateAttCode = MetaModel::GetStateAttributeCode($sClass);
|
||||
$iFlags = MetaModel::GetInitialStateAttributeFlags($sClass, $this->Get($sStateAttCode), $sAttCode);
|
||||
}
|
||||
return $iFlags; // No need to care about the synchro flags since we'll be creating a new object anyway
|
||||
}
|
||||
@@ -1832,13 +1826,13 @@ abstract class DBObject implements iDisplay
|
||||
/**
|
||||
* Check if the given (or current) value is suitable for the attribute
|
||||
*
|
||||
* @api
|
||||
* @api-advanced
|
||||
*
|
||||
* @param string $sAttCode
|
||||
* @param boolean|string $value true if successful, the error description otherwise
|
||||
* @api
|
||||
* @api-advanced
|
||||
*
|
||||
* @return bool|string
|
||||
* @param string $sAttCode
|
||||
* @param mixed $value if not passed, then will get value using Get method
|
||||
*
|
||||
* @return bool|string true if successful, the error description otherwise
|
||||
* @throws \ArchivedObjectException
|
||||
* @throws \CoreException
|
||||
* @throws \OQLException
|
||||
@@ -2118,23 +2112,75 @@ abstract class DBObject implements iDisplay
|
||||
}
|
||||
|
||||
$aChildClassesWithRuleDisabled = MetaModel::GetChildClassesWithDisabledUniquenessRule($sRuleRootClass, $sUniquenessRuleId);
|
||||
if (!empty($aChildClassesWithRuleDisabled))
|
||||
{
|
||||
if (!empty($aChildClassesWithRuleDisabled)) {
|
||||
$oUniquenessQuery->AddConditionForInOperatorUsingParam('finalclass', $aChildClassesWithRuleDisabled, false);
|
||||
}
|
||||
|
||||
return $oUniquenessQuery;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $sAttCode
|
||||
* @param mixed $value
|
||||
*
|
||||
* @uses m_aCheckWarnings to log to user duplicates found
|
||||
*
|
||||
* @since 3.0.0 N°3198 check duplicates if necessary :<br>
|
||||
* Before we could only add or remove lnk using the uilinks widget. This widget has a filter based on existing values, and so
|
||||
* forbids to add duplicates.<br>
|
||||
* Now we can modify existing entries using the extkey widget, and the widget doesn't have (yet !) such
|
||||
* a filter. The widget will be updated later on, but as a first step we're checking for duplicates server side. This is a non
|
||||
* blocking warning, as it was already possible to add duplicates by other means.
|
||||
*/
|
||||
protected function DoCheckLinkedSetDuplicates($sAttCode, $value)
|
||||
{
|
||||
$oAttDef = MetaModel::GetAttributeDef(get_class($this), $sAttCode);
|
||||
|
||||
if (!($oAttDef instanceof AttributeLinkedSetIndirect)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ($oAttDef->DuplicatesAllowed()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
/** @var \ormLinkSet $value */
|
||||
$aModifiedLnk = $value->ListModifiedLinks();
|
||||
$sExtKeyToRemote = $oAttDef->GetExtKeyToRemote();
|
||||
$aExistingRemotesId = $value->GetColumnAsArray($sExtKeyToRemote, true);
|
||||
$aExistingRemotesFriendlyName = $value->GetColumnAsArray($sExtKeyToRemote.'_friendlyname', true);
|
||||
$aDuplicatesFields = [];
|
||||
foreach ($aModifiedLnk as $oModifiedLnk) {
|
||||
$iModifiedLnkId = $oModifiedLnk->GetKey();
|
||||
$iModifiedLnkRemoteId = $oModifiedLnk->Get($sExtKeyToRemote);
|
||||
$aExistingRemotesIdToCheck = array_filter($aExistingRemotesId, function ($iLnkKey) use ($iModifiedLnkId) {
|
||||
return ($iLnkKey != $iModifiedLnkId);
|
||||
}, ARRAY_FILTER_USE_KEY);
|
||||
|
||||
if (!in_array($iModifiedLnkRemoteId, $aExistingRemotesIdToCheck, true)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$iLnkId = $oModifiedLnk->GetKey();
|
||||
$aDuplicatesFields[] = $aExistingRemotesFriendlyName[$iLnkId];
|
||||
}
|
||||
|
||||
if (!empty($aDuplicatesFields)) {
|
||||
$this->m_aCheckWarnings[] = Dict::Format('Core:AttributeLinkedSetDuplicatesFound',
|
||||
$oAttDef->GetLabel(),
|
||||
implode(', ', $aDuplicatesFields));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check integrity rules (before inserting or updating the object)
|
||||
*
|
||||
* **This method is not meant to be called directly, use DBObject::CheckToWrite()!**
|
||||
* **This method is not meant to be called directly, use DBObject::CheckToWrite()!**
|
||||
* Errors should be inserted in $m_aCheckIssues and $m_aCheckWarnings arrays
|
||||
*
|
||||
* @overwritable-hook You can extend this method in order to provide your own logic.
|
||||
* @see CheckToWrite()
|
||||
* @see $m_aCheckIssues
|
||||
*
|
||||
* @overwritable-hook You can extend this method in order to provide your own logic.
|
||||
* @see CheckToWrite()
|
||||
* @see $m_aCheckIssues
|
||||
* @see $m_aCheckWarnings
|
||||
*
|
||||
* @throws \ArchivedObjectException
|
||||
@@ -2150,14 +2196,14 @@ abstract class DBObject implements iDisplay
|
||||
|
||||
$aChanges = $this->ListChanges();
|
||||
|
||||
foreach($aChanges as $sAttCode => $value)
|
||||
{
|
||||
foreach($aChanges as $sAttCode => $value) {
|
||||
$res = $this->CheckValue($sAttCode);
|
||||
if ($res !== true)
|
||||
{
|
||||
if ($res !== true) {
|
||||
// $res contains the error description
|
||||
$this->m_aCheckIssues[] = "Unexpected value for attribute '$sAttCode': $res";
|
||||
}
|
||||
|
||||
$this->DoCheckLinkedSetDuplicates($sAttCode, $value);
|
||||
}
|
||||
if (count($this->m_aCheckIssues) > 0)
|
||||
{
|
||||
@@ -2960,46 +3006,6 @@ abstract class DBObject implements iDisplay
|
||||
return $this->m_iKey;
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*
|
||||
* @deprecated 2.7.0 N°2361 simply use {@see DBObject::DBInsert()} instead, that will automatically create and persist a CMDBChange object.
|
||||
* If you need to persist your own, call {@see CMDBObject::SetCurrentChange()} before.
|
||||
*
|
||||
* @param CMDBChange $oChange
|
||||
*
|
||||
* @return int|null
|
||||
* @throws CoreException
|
||||
*/
|
||||
public function DBInsertTracked(CMDBChange $oChange)
|
||||
{
|
||||
CMDBObject::SetCurrentChange($oChange);
|
||||
return $this->DBInsert();
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*
|
||||
* @deprecated 2.7.0 N°2361 simply use {@see DBObject::DBInsertNoReload()} instead, that will automatically create and persist a CMDBChange object.
|
||||
* If you need to persist your own, call {@see CMDBObject::SetCurrentChange()} before.
|
||||
*
|
||||
* @param CMDBChange $oChange
|
||||
*
|
||||
* @return int
|
||||
* @throws ArchivedObjectException
|
||||
* @throws CoreCannotSaveObjectException
|
||||
* @throws CoreException
|
||||
* @throws CoreUnexpectedValue
|
||||
* @throws CoreWarning
|
||||
* @throws MySQLException
|
||||
* @throws OQLException
|
||||
*/
|
||||
public function DBInsertTrackedNoReload(CMDBChange $oChange)
|
||||
{
|
||||
CMDBObject::SetCurrentChange($oChange);
|
||||
return $this->DBInsertNoReload();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a copy of the current object into the database
|
||||
*
|
||||
@@ -3358,25 +3364,6 @@ abstract class DBObject implements iDisplay
|
||||
$this->m_aPreviousValuesForUpdatedAttributes = $aPreviousValuesForUpdatedAttributes;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @internal
|
||||
*
|
||||
* @deprecated 2.7.0 N°2361 simply use {@see DBObject::DBUpdate()} instead, that will automatically create and persist a CMDBChange object.
|
||||
* If you need to persist your own, call {@see CMDBObject::SetCurrentChange()} before.
|
||||
*
|
||||
* @param CMDBChange $oChange
|
||||
*
|
||||
* @return int
|
||||
* @throws CoreCannotSaveObjectException
|
||||
* @throws CoreException
|
||||
*/
|
||||
public function DBUpdateTracked(CMDBChange $oChange)
|
||||
{
|
||||
CMDBObject::SetCurrentChange($oChange);
|
||||
return $this->DBUpdate();
|
||||
}
|
||||
|
||||
/**
|
||||
* Make the current changes persistent - clever wrapper for Insert or Update
|
||||
*
|
||||
@@ -3612,7 +3599,7 @@ abstract class DBObject implements iDisplay
|
||||
// As a temporary fix: delete only the objects that are still to be deleted...
|
||||
if ($oToDelete->m_bIsInDB)
|
||||
{
|
||||
set_time_limit($iLoopTimeLimit);
|
||||
set_time_limit(intval($iLoopTimeLimit));
|
||||
$oToDelete->DBDeleteSingleObject();
|
||||
}
|
||||
}
|
||||
@@ -3627,43 +3614,18 @@ abstract class DBObject implements iDisplay
|
||||
foreach ($aData['attributes'] as $sRemoteExtKey => $aRemoteAttDef)
|
||||
{
|
||||
$oToUpdate->Set($sRemoteExtKey, $aData['values'][$sRemoteExtKey]);
|
||||
set_time_limit($iLoopTimeLimit);
|
||||
set_time_limit(intval($iLoopTimeLimit));
|
||||
$oToUpdate->DBUpdate();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
set_time_limit($iPreviousTimeLimit);
|
||||
set_time_limit(intval($iPreviousTimeLimit));
|
||||
|
||||
return $oDeletionPlan;
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*
|
||||
* @deprecated 2.7.0 N°2361 simply use {@see DBObject::DBDelete()} instead.
|
||||
* If you need to persist your own, call {@see CMDBObject::SetCurrentChange()} before.
|
||||
*
|
||||
* @param CMDBChange $oChange
|
||||
* @param boolean $bSkipStrongSecurity
|
||||
* @param \DeletionPlan $oDeletionPlan
|
||||
*
|
||||
* @throws ArchivedObjectException
|
||||
* @throws CoreCannotSaveObjectException
|
||||
* @throws CoreException
|
||||
* @throws CoreUnexpectedValue
|
||||
* @throws DeleteException
|
||||
* @throws MySQLException
|
||||
* @throws MySQLHasGoneAwayException
|
||||
* @throws OQLException
|
||||
*/
|
||||
public function DBDeleteTracked(CMDBChange $oChange, $bSkipStrongSecurity = null, &$oDeletionPlan = null)
|
||||
{
|
||||
CMDBObject::SetCurrentChange($oChange);
|
||||
$this->DBDelete($oDeletionPlan);
|
||||
}
|
||||
|
||||
/**
|
||||
/**
|
||||
* @internal
|
||||
*
|
||||
* @return array
|
||||
@@ -3673,11 +3635,12 @@ abstract class DBObject implements iDisplay
|
||||
*/
|
||||
public function EnumTransitions()
|
||||
{
|
||||
$sStateAttCode = MetaModel::GetStateAttributeCode(get_class($this));
|
||||
if (empty($sStateAttCode)) return array();
|
||||
$sClass = get_class($this);
|
||||
if (!MetaModel::HasLifecycle($sClass)) return array();
|
||||
|
||||
$sStateAttCode = MetaModel::GetStateAttributeCode($sClass);
|
||||
$sState = $this->Get($sStateAttCode);
|
||||
return MetaModel::EnumTransitions(get_class($this), $sState);
|
||||
return MetaModel::EnumTransitions($sClass, $sState);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -3723,14 +3686,14 @@ abstract class DBObject implements iDisplay
|
||||
public function ApplyStimulus($sStimulusCode, $bDoNotWrite = false)
|
||||
{
|
||||
$sClass = get_class($this);
|
||||
$sStateAttCode = MetaModel::GetStateAttributeCode($sClass);
|
||||
if (empty($sStateAttCode))
|
||||
if (!MetaModel::HasLifecycle($sClass))
|
||||
{
|
||||
throw new CoreException('No lifecycle for the class '.$sClass);
|
||||
}
|
||||
|
||||
MyHelpers::CheckKeyInArray('object lifecycle stimulus', $sStimulusCode, MetaModel::EnumStimuli($sClass));
|
||||
|
||||
$sStateAttCode = MetaModel::GetStateAttributeCode($sClass);
|
||||
$aStateTransitions = $this->EnumTransitions();
|
||||
if (!array_key_exists($sStimulusCode, $aStateTransitions))
|
||||
{
|
||||
@@ -4458,22 +4421,7 @@ abstract class DBObject implements iDisplay
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* implement relations
|
||||
*
|
||||
* Return an empty set for the parent of all
|
||||
*
|
||||
* this way of implementing the relations suffers limitations (not handling the redundancy)
|
||||
* and you should consider defining those things in XML
|
||||
*
|
||||
* @internal
|
||||
* @deprecated
|
||||
*/
|
||||
public static function GetRelationQueries($sRelCode)
|
||||
{
|
||||
return array();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Reserved: do not overload
|
||||
*
|
||||
@@ -4484,72 +4432,6 @@ abstract class DBObject implements iDisplay
|
||||
return array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Use GetRelatedObjectsDown/Up instead to take redundancy into account
|
||||
*
|
||||
* @internal
|
||||
* @deprecated
|
||||
*/
|
||||
public function GetRelatedObjects($sRelCode, $iMaxDepth = 99, &$aResults = array())
|
||||
{
|
||||
// Temporary patch: until the impact analysis GUI gets rewritten,
|
||||
// let's consider that "depends on" is equivalent to "impacts/up"
|
||||
// The current patch has been implemented in DBObject and MetaModel
|
||||
$sHackedRelCode = $sRelCode;
|
||||
$bDown = true;
|
||||
if ($sRelCode == 'depends on')
|
||||
{
|
||||
$sHackedRelCode = 'impacts';
|
||||
$bDown = false;
|
||||
}
|
||||
foreach (MetaModel::EnumRelationQueries(get_class($this), $sHackedRelCode, $bDown) as $sDummy => $aQueryInfo)
|
||||
{
|
||||
$sQuery = $bDown ? $aQueryInfo['sQueryDown'] : $aQueryInfo['sQueryUp'];
|
||||
//$bPropagate = $aQueryInfo["bPropagate"];
|
||||
//$iDepth = $bPropagate ? $iMaxDepth - 1 : 0;
|
||||
$iDepth = $iMaxDepth - 1;
|
||||
|
||||
// Note: the loop over the result set has been written in an unusual way for error reporting purposes
|
||||
// In the case of a wrong query parameter name, the error occurs on the first call to Fetch,
|
||||
// thus we need to have this first call into the try/catch, but
|
||||
// we do NOT want to nest the try/catch for the error message to be clear
|
||||
try
|
||||
{
|
||||
$oFlt = DBObjectSearch::FromOQL($sQuery);
|
||||
$oObjSet = new DBObjectSet($oFlt, array(), $this->ToArgsForQuery());
|
||||
$oObj = $oObjSet->Fetch();
|
||||
}
|
||||
catch (Exception $e)
|
||||
{
|
||||
$sClassOfDefinition = $aQueryInfo['_legacy_'] ? get_class($this).'(or a parent)::GetRelationQueries()' : $aQueryInfo['sDefinedInClass'];
|
||||
throw new Exception("Wrong query for the relation $sRelCode/$sClassOfDefinition/{$aQueryInfo['sNeighbour']}: ".$e->getMessage());
|
||||
}
|
||||
if ($oObj)
|
||||
{
|
||||
do
|
||||
{
|
||||
$sRootClass = MetaModel::GetRootClass(get_class($oObj));
|
||||
$sObjKey = $oObj->GetKey();
|
||||
if (array_key_exists($sRootClass, $aResults))
|
||||
{
|
||||
if (array_key_exists($sObjKey, $aResults[$sRootClass]))
|
||||
{
|
||||
continue; // already visited, skip
|
||||
}
|
||||
}
|
||||
|
||||
$aResults[$sRootClass][$sObjKey] = $oObj;
|
||||
if ($iDepth > 0)
|
||||
{
|
||||
$oObj->GetRelatedObjects($sRelCode, $iDepth, $aResults);
|
||||
}
|
||||
}
|
||||
while ($oObj = $oObjSet->Fetch());
|
||||
}
|
||||
}
|
||||
return $aResults;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute the "RelatedObjects" (forward or "down" direction) for the object
|
||||
* for the specified relation
|
||||
@@ -4683,7 +4565,7 @@ abstract class DBObject implements iDisplay
|
||||
{
|
||||
foreach ($aPotentialDeletes as $sRemoteExtKey => $aData)
|
||||
{
|
||||
set_time_limit($iLoopTimeLimit);
|
||||
set_time_limit(intval($iLoopTimeLimit));
|
||||
|
||||
/** @var \AttributeExternalKey $oAttDef */
|
||||
$oAttDef = $aData['attribute'];
|
||||
@@ -4715,7 +4597,7 @@ abstract class DBObject implements iDisplay
|
||||
}
|
||||
}
|
||||
}
|
||||
set_time_limit($iPreviousTimeLimit);
|
||||
set_time_limit(intval($iPreviousTimeLimit));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -5461,10 +5343,10 @@ abstract class DBObject implements iDisplay
|
||||
*/
|
||||
public static function MakeDefaultInstance($sClass)
|
||||
{
|
||||
$sStateAttCode = MetaModel::GetStateAttributeCode($sClass);
|
||||
$oObj = MetaModel::NewObject($sClass);
|
||||
if (!empty($sStateAttCode))
|
||||
if (MetaModel::HasLifecycle($sClass))
|
||||
{
|
||||
$sStateAttCode = MetaModel::GetStateAttributeCode($sClass);
|
||||
$sTargetState = MetaModel::GetDefaultState($sClass);
|
||||
$oObj->Set($sStateAttCode, $sTargetState);
|
||||
}
|
||||
@@ -5561,5 +5443,33 @@ abstract class DBObject implements iDisplay
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public function EvaluateExpression(Expression $oExpression)
|
||||
{
|
||||
$aFields = $oExpression->ListRequiredFields();
|
||||
$aArgs = array();
|
||||
foreach ($aFields as $sFieldDesc)
|
||||
{
|
||||
$aFieldParts = explode('.', $sFieldDesc);
|
||||
if (count($aFieldParts) == 2)
|
||||
{
|
||||
$sClass = $aFieldParts[0];
|
||||
$sAttCode = $aFieldParts[1];
|
||||
}
|
||||
else
|
||||
{
|
||||
$sClass = get_class($this);
|
||||
$sAttCode = $aFieldParts[0];
|
||||
}
|
||||
if (get_class($this) != $sClass) continue;
|
||||
if (!MetaModel::IsValidAttCode(get_class($this), $sAttCode)) continue;
|
||||
|
||||
$oAttDef = MetaModel::GetAttributeDef(get_class($this), $sAttCode);
|
||||
$aSQLValues = $oAttDef->GetSQLValues($this->m_aCurrValues[$sAttCode]);
|
||||
$value = reset($aSQLValues);
|
||||
$aArgs[$sFieldDesc] = $value;
|
||||
}
|
||||
return $oExpression->Evaluate($aArgs);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -907,10 +907,14 @@ class DBObjectSearch extends DBSearch
|
||||
}
|
||||
|
||||
/**
|
||||
* @param DBObjectSearch $oFilter (can be modified)
|
||||
* @param $sExtKeyAttCode
|
||||
* Add a link to another filter, using an extkey already present in current filter
|
||||
*
|
||||
* @param DBObjectSearch $oFilter filter to join to (can be modified)
|
||||
* @param string $sExtKeyAttCode extkey present in current filter, that allows to points to $oFilter
|
||||
* @param int $iOperatorCode
|
||||
* @param null $aRealiasingMap array of <old-alias> => <new-alias>, for each alias that has changed
|
||||
* @param array $aRealiasingMap array of <old-alias> => <new-alias>, for each alias that has changed.
|
||||
* Doesn't change existing alias, use {@link \DBObjectSearch::RenameAlias()} for that.
|
||||
*
|
||||
* @throws CoreException
|
||||
* @throws CoreWarning
|
||||
*/
|
||||
@@ -1372,7 +1376,7 @@ class DBObjectSearch extends DBSearch
|
||||
|
||||
// Make the list of acceptable arguments... could be factorized with run_query, into oSearch->GetQueryParams($bExclude magic params)
|
||||
$aNakedMagicArguments = array();
|
||||
foreach (MetaModel::PrepareQueryArguments(array()) as $sArgName => $value)
|
||||
foreach (MetaModel::PrepareQueryArguments(array(),array(), $this->GetExpectedArguments()) as $sArgName => $value)
|
||||
{
|
||||
$iPos = strpos($sArgName, '->object()');
|
||||
if ($iPos === false)
|
||||
@@ -1435,7 +1439,7 @@ class DBObjectSearch extends DBSearch
|
||||
{
|
||||
$aParams = array_merge($aContextParams, $this->m_aParams);
|
||||
}
|
||||
$aParams = MetaModel::PrepareQueryArguments($aParams);
|
||||
$aParams = MetaModel::PrepareQueryArguments($aParams,array(), $this->GetExpectedArguments());
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1628,7 +1632,7 @@ class DBObjectSearch extends DBSearch
|
||||
$aRet = array('selects' => array(), 'joins' => array(), 'where' => array());
|
||||
|
||||
$aParams = array_merge($this->m_aParams);
|
||||
$aParams = MetaModel::PrepareQueryArguments($aParams);
|
||||
$aParams = MetaModel::PrepareQueryArguments($aParams, array(), $this->GetExpectedArguments());
|
||||
|
||||
foreach ($this->m_aSelectedClasses as $sAlias => $sClass)
|
||||
{
|
||||
@@ -1835,7 +1839,7 @@ class DBObjectSearch extends DBSearch
|
||||
{
|
||||
$oSQLObjectQueryBuilder = new SQLObjectQueryBuilder($this);
|
||||
$oSQLQuery = $oSQLObjectQueryBuilder->MakeSQLObjectDeleteQuery();
|
||||
$aScalarArgs = MetaModel::PrepareQueryArguments($aArgs, $this->GetInternalParams());
|
||||
$aScalarArgs = MetaModel::PrepareQueryArguments($aArgs, $this->GetInternalParams(), $this->GetExpectedArguments());
|
||||
$sRet = $oSQLQuery->RenderDelete($aScalarArgs);
|
||||
return $sRet;
|
||||
}
|
||||
@@ -1851,7 +1855,7 @@ class DBObjectSearch extends DBSearch
|
||||
{
|
||||
$oSQLObjectQueryBuilder = new SQLObjectQueryBuilder($this);
|
||||
$oSQLQuery = $oSQLObjectQueryBuilder->MakeSQLObjectUpdateQuery($aValues);
|
||||
$aScalarArgs = MetaModel::PrepareQueryArguments($aArgs, $this->GetInternalParams());
|
||||
$aScalarArgs = MetaModel::PrepareQueryArguments($aArgs, $this->GetInternalParams(), $this->GetExpectedArguments());
|
||||
$sRet = $oSQLQuery->RenderUpdate($aScalarArgs);
|
||||
return $sRet;
|
||||
}
|
||||
@@ -1870,7 +1874,7 @@ class DBObjectSearch extends DBSearch
|
||||
{
|
||||
$oSQLObjectQueryBuilder = new SQLObjectQueryBuilder($this);
|
||||
$oSQLQuery = $oSQLObjectQueryBuilder->MakeSQLObjectUpdateQuery($aValues);
|
||||
$aScalarArgs = MetaModel::PrepareQueryArguments($aArgs, $this->GetInternalParams());
|
||||
$aScalarArgs = MetaModel::PrepareQueryArguments($aArgs, $this->GetInternalParams(), $this->GetExpectedArguments());
|
||||
$sRet = $oSQLQuery->RenderInsert($aScalarArgs);
|
||||
return $sRet;
|
||||
}
|
||||
|
||||
@@ -222,6 +222,7 @@ class DBObjectSet implements iDBObjectSetIterator
|
||||
if (!is_array($aAttToLoad))
|
||||
{
|
||||
$this->m_aAttToLoad = null;
|
||||
trigger_error ( "OptimizeColumnLoad : wrong format actual :(".print_r($aAttToLoad, true)."). should be [alias=>[attributes]]", E_USER_WARNING );
|
||||
return;
|
||||
}
|
||||
foreach ($aAttToLoad as $sAlias => $aAttCodes)
|
||||
@@ -229,6 +230,7 @@ class DBObjectSet implements iDBObjectSetIterator
|
||||
if (!is_array($aAttCodes))
|
||||
{
|
||||
$this->m_aAttToLoad = null;
|
||||
trigger_error ( "OptimizeColumnLoad : wrong format actual :(".print_r($aAttToLoad, true)."). should be [alias=>[attributes]]", E_USER_WARNING );
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -267,6 +269,7 @@ class DBObjectSet implements iDBObjectSetIterator
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Add the friendly name anytime
|
||||
$oFriendlyNameAttDef = MetaModel::GetAttributeDef($sClass, 'friendlyname');
|
||||
$aAttToLoadWithAttDef[$sClassAlias]['friendlyname'] = $oFriendlyNameAttDef;
|
||||
@@ -1312,34 +1315,6 @@ class DBObjectSet implements iDBObjectSetIterator
|
||||
return $oNewSet;
|
||||
}
|
||||
|
||||
/**
|
||||
* Will be deprecated soon - use MetaModel::GetRelatedObjectsDown/Up instead to take redundancy into account
|
||||
*
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function GetRelatedObjects($sRelCode, $iMaxDepth = 99)
|
||||
{
|
||||
$aRelatedObjs = array();
|
||||
|
||||
$aVisited = array(); // optimization for consecutive calls of MetaModel::GetRelatedObjects
|
||||
$this->Seek(0);
|
||||
while ($oObject = $this->Fetch())
|
||||
{
|
||||
$aMore = $oObject->GetRelatedObjects($sRelCode, $iMaxDepth, $aVisited);
|
||||
foreach ($aMore as $sClass => $aRelated)
|
||||
{
|
||||
foreach ($aRelated as $iObj => $oObj)
|
||||
{
|
||||
if (!isset($aRelatedObjs[$sClass][$iObj]))
|
||||
{
|
||||
$aRelatedObjs[$sClass][$iObj] = $oObj;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return $aRelatedObjs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute the "RelatedObjects" (forward or "down" direction) for the set
|
||||
* for the specified relation
|
||||
@@ -1496,7 +1471,7 @@ class DBObjectSet implements iDBObjectSetIterator
|
||||
public function ListConstantFields()
|
||||
{
|
||||
// The complete list of arguments will include magic arguments (e.g. current_user->attcode)
|
||||
$aScalarArgs = MetaModel::PrepareQueryArguments($this->m_oFilter->GetInternalParams(), $this->m_aArgs);
|
||||
$aScalarArgs = MetaModel::PrepareQueryArguments($this->m_oFilter->GetInternalParams(), $this->m_aArgs, $this->m_oFilter->ListParameters());
|
||||
$aConst = $this->m_oFilter->ListConstantFields();
|
||||
|
||||
foreach($aConst as $sClassAlias => $aVals)
|
||||
@@ -1515,7 +1490,7 @@ class DBObjectSet implements iDBObjectSetIterator
|
||||
|
||||
public function ApplyParameters()
|
||||
{
|
||||
$aAllArgs = MetaModel::PrepareQueryArguments($this->m_oFilter->GetInternalParams(), $this->m_aArgs);
|
||||
$aAllArgs = MetaModel::PrepareQueryArguments($this->m_oFilter->GetInternalParams(), $this->m_aArgs, $this->m_oFilter->GetExpectedArguments());
|
||||
$this->m_oFilter->ApplyParameters($aAllArgs);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -603,11 +603,11 @@ abstract class DBSearch
|
||||
elseif (($iPos = strpos($sParam, '->')) !== false)
|
||||
{
|
||||
$sParamName = substr($sParam, 0, $iPos);
|
||||
if (isset($aContextParams[$sParamName.'->object()']))
|
||||
if (isset($aContextParams[$sParamName.'->object()']) || isset($aContextParams[$sParamName]))
|
||||
{
|
||||
$sAttCode = substr($sParam, $iPos + 2);
|
||||
/** @var \DBObject $oObj */
|
||||
$oObj = $aContextParams[$sParamName.'->object()'];
|
||||
$oObj = isset($aContextParams[$sParamName.'->object()']) ? $aContextParams[$sParamName.'->object()'] : $aContextParams[$sParamName];
|
||||
if ($oObj->IsModified())
|
||||
{
|
||||
if ($sAttCode == 'id')
|
||||
|
||||
@@ -116,7 +116,7 @@ class DeletionPlan
|
||||
{
|
||||
foreach($aToUpdate as $iId => $aData)
|
||||
{
|
||||
set_time_limit($iLoopTimeLimit);
|
||||
set_time_limit(intval($iLoopTimeLimit));
|
||||
$this->m_iToUpdate++;
|
||||
|
||||
$oObject = $aData['to_reset'];
|
||||
@@ -142,7 +142,7 @@ class DeletionPlan
|
||||
}
|
||||
}
|
||||
}
|
||||
set_time_limit($iPreviousTimeLimit);
|
||||
set_time_limit(intval($iPreviousTimeLimit));
|
||||
}
|
||||
|
||||
public function GetIssues()
|
||||
|
||||
@@ -874,7 +874,7 @@ class DisplayableGraph extends SimpleGraph
|
||||
$oNodesIter = new RelationTypeIterator($oGraph, 'Node');
|
||||
foreach($oNodesIter as $oNode)
|
||||
{
|
||||
set_time_limit($iLoopTimeLimit);
|
||||
set_time_limit(intval($iLoopTimeLimit));
|
||||
switch(get_class($oNode))
|
||||
{
|
||||
case 'RelationObjectNode':
|
||||
@@ -921,7 +921,7 @@ class DisplayableGraph extends SimpleGraph
|
||||
$oEdgesIter = new RelationTypeIterator($oGraph, 'Edge');
|
||||
foreach($oEdgesIter as $oEdge)
|
||||
{
|
||||
set_time_limit($iLoopTimeLimit);
|
||||
set_time_limit(intval($iLoopTimeLimit));
|
||||
$oSourceNode = $oNewGraph->GetNode($oEdge->GetSourceNode()->GetId());
|
||||
$oSinkNode = $oNewGraph->GetNode($oEdge->GetSinkNode()->GetId());
|
||||
$oNewEdge = new DisplayableEdge($oNewGraph, $oEdge->GetId(), $oSourceNode, $oSinkNode);
|
||||
@@ -932,7 +932,7 @@ class DisplayableGraph extends SimpleGraph
|
||||
$aEdgeKeys = array();
|
||||
foreach($oEdgesIter as $oEdge)
|
||||
{
|
||||
set_time_limit($iLoopTimeLimit);
|
||||
set_time_limit(intval($iLoopTimeLimit));
|
||||
$sSourceId = $oEdge->GetSourceNode()->GetId();
|
||||
$sSinkId = $oEdge->GetSinkNode()->GetId();
|
||||
if ($sSourceId == $sSinkId)
|
||||
@@ -958,7 +958,7 @@ class DisplayableGraph extends SimpleGraph
|
||||
$oNodesIter = new RelationTypeIterator($oNewGraph, 'Node');
|
||||
foreach($oNodesIter as $oNode)
|
||||
{
|
||||
set_time_limit($iLoopTimeLimit);
|
||||
set_time_limit(intval($iLoopTimeLimit));
|
||||
if ($bDirectionDown && $oNode->GetProperty('source'))
|
||||
{
|
||||
$oNode->GroupSimilarNeighbours($oNewGraph, $iGroupingThreshold, true, $bDirectionDown);
|
||||
@@ -973,7 +973,7 @@ class DisplayableGraph extends SimpleGraph
|
||||
$iGroupIdx = 0;
|
||||
foreach($oIterator as $oNode)
|
||||
{
|
||||
set_time_limit($iLoopTimeLimit);
|
||||
set_time_limit(intval($iLoopTimeLimit));
|
||||
if ($oNode instanceof DisplayableGroupNode)
|
||||
{
|
||||
if ($oNode->GetObjectCount() == 0)
|
||||
@@ -995,7 +995,7 @@ class DisplayableGraph extends SimpleGraph
|
||||
$aEdgeKeys = array();
|
||||
foreach($oEdgesIter as $oEdge)
|
||||
{
|
||||
set_time_limit($iLoopTimeLimit);
|
||||
set_time_limit(intval($iLoopTimeLimit));
|
||||
$sSourceId = $oEdge->GetSourceNode()->GetId();
|
||||
$sSinkId = $oEdge->GetSinkNode()->GetId();
|
||||
if ($sSourceId == $sSinkId)
|
||||
@@ -1017,7 +1017,7 @@ class DisplayableGraph extends SimpleGraph
|
||||
}
|
||||
}
|
||||
}
|
||||
set_time_limit($iPreviousTimeLimit);
|
||||
set_time_limit(intval($iPreviousTimeLimit));
|
||||
|
||||
return $oNewGraph;
|
||||
}
|
||||
@@ -1257,14 +1257,14 @@ class DisplayableGraph extends SimpleGraph
|
||||
$iLoopTimeLimit = MetaModel::GetConfig()->Get('max_execution_time_per_loop');
|
||||
foreach($oIterator as $sId => $oEdge)
|
||||
{
|
||||
set_time_limit($iLoopTimeLimit);
|
||||
set_time_limit(intval($iLoopTimeLimit));
|
||||
$oEdge->RenderAsPDF($oPdf, $this, $fScale, $aContextDefs);
|
||||
}
|
||||
|
||||
$oIterator = new RelationTypeIterator($this, 'Node');
|
||||
foreach($oIterator as $sId => $oNode)
|
||||
{
|
||||
set_time_limit($iLoopTimeLimit);
|
||||
set_time_limit(intval($iLoopTimeLimit));
|
||||
$oNode->RenderAsPDF($oPdf, $this, $fScale, $aContextDefs);
|
||||
}
|
||||
|
||||
|
||||
@@ -100,7 +100,7 @@ class EMail
|
||||
}
|
||||
if (array_key_exists('reply_to', $aData))
|
||||
{
|
||||
$oMessage->SetRecipientReplyTo($aData['reply_to']);
|
||||
$oMessage->SetRecipientReplyTo($aData['reply_to']['address'], $aData['reply_to']['label']);
|
||||
}
|
||||
if (array_key_exists('to', $aData))
|
||||
{
|
||||
@@ -465,10 +465,14 @@ class EMail
|
||||
}
|
||||
}
|
||||
|
||||
public function SetRecipientReplyTo($sAddress)
|
||||
public function SetRecipientReplyTo($sAddress, $sLabel = '')
|
||||
{
|
||||
$this->m_aData['reply_to'] = $sAddress;
|
||||
if (!empty($sAddress))
|
||||
$this->m_aData['reply_to'] = array('address' => $sAddress, 'label' => $sLabel);
|
||||
if ($sLabel != '')
|
||||
{
|
||||
$this->m_oMessage->setReplyTo(array($sAddress => $sLabel));
|
||||
}
|
||||
else if (!empty($sAddress))
|
||||
{
|
||||
$this->m_oMessage->setReplyTo($sAddress);
|
||||
}
|
||||
|
||||
@@ -31,7 +31,6 @@ class Event extends DBObject implements iDisplay
|
||||
"db_table" => "priv_event",
|
||||
"db_key_field" => "id",
|
||||
"db_finalclass_field" => "realclass",
|
||||
"display_template" => "",
|
||||
"order_by_default" => array('date' => false)
|
||||
);
|
||||
MetaModel::Init_Params($aParams);
|
||||
@@ -127,7 +126,6 @@ class EventNotification extends Event
|
||||
"db_table" => "priv_event_notification",
|
||||
"db_key_field" => "id",
|
||||
"db_finalclass_field" => "",
|
||||
"display_template" => "",
|
||||
"order_by_default" => array('date' => false),
|
||||
'indexes' => array(
|
||||
array('object_id'),
|
||||
@@ -163,7 +161,6 @@ class EventNotificationEmail extends EventNotification
|
||||
"db_table" => "priv_event_email",
|
||||
"db_key_field" => "id",
|
||||
"db_finalclass_field" => "",
|
||||
"display_template" => "",
|
||||
"order_by_default" => array('date' => false)
|
||||
);
|
||||
MetaModel::Init_Params($aParams);
|
||||
@@ -201,7 +198,6 @@ class EventIssue extends Event
|
||||
"db_table" => "priv_event_issue",
|
||||
"db_key_field" => "id",
|
||||
"db_finalclass_field" => "",
|
||||
"display_template" => "",
|
||||
"order_by_default" => array('date' => false)
|
||||
);
|
||||
MetaModel::Init_Params($aParams);
|
||||
@@ -301,7 +297,6 @@ class EventWebService extends Event
|
||||
"db_table" => "priv_event_webservice",
|
||||
"db_key_field" => "id",
|
||||
"db_finalclass_field" => "",
|
||||
"display_template" => "",
|
||||
"order_by_default" => array('date' => false)
|
||||
);
|
||||
MetaModel::Init_Params($aParams);
|
||||
@@ -337,7 +332,6 @@ class EventRestService extends Event
|
||||
"db_table" => "priv_event_restservice",
|
||||
"db_key_field" => "id",
|
||||
"db_finalclass_field" => "",
|
||||
"display_template" => "",
|
||||
"order_by_default" => array('date' => false)
|
||||
);
|
||||
MetaModel::Init_Params($aParams);
|
||||
|
||||
@@ -296,7 +296,7 @@ EOF
|
||||
$iLoopTimeLimit = MetaModel::GetConfig()->Get('max_execution_time_per_loop');
|
||||
while($aRow = $oSet->FetchAssoc())
|
||||
{
|
||||
set_time_limit($iLoopTimeLimit);
|
||||
set_time_limit(intval($iLoopTimeLimit));
|
||||
$aData = array();
|
||||
foreach($this->aStatusInfo['fields'] as $iCol => $aFieldSpec)
|
||||
{
|
||||
@@ -314,7 +314,7 @@ EOF
|
||||
fwrite($hFile, json_encode($aData)."\n");
|
||||
$iCount++;
|
||||
}
|
||||
set_time_limit($iPreviousTimeLimit);
|
||||
set_time_limit(intval($iPreviousTimeLimit));
|
||||
$this->aStatusInfo['position'] += $this->iChunkSize;
|
||||
if ($this->aStatusInfo['total'] == 0)
|
||||
{
|
||||
|
||||
@@ -118,7 +118,7 @@ EOF;
|
||||
{
|
||||
$sKey = static::GetKey($sClass, $sAttCode);
|
||||
$oExpr = DBObjectSearch::GetPolymorphicExpression($sClass, $sAttCode);
|
||||
return "'".$sKey."' => '".serialize($oExpr)."',\n";
|
||||
return var_export($sKey, true)." => ".var_export(serialize($oExpr), true).",\n"; // Beware, string values can contain quotes, backslashes, etc!
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -128,7 +128,7 @@ class HTMLBulkExport extends TabularBulkExport
|
||||
$iLoopTimeLimit = MetaModel::GetConfig()->Get('max_execution_time_per_loop');
|
||||
while($aRow = $oSet->FetchAssoc())
|
||||
{
|
||||
set_time_limit($iLoopTimeLimit);
|
||||
set_time_limit(intval($iLoopTimeLimit));
|
||||
$oMainObj = $aRow[$sFirstAlias];
|
||||
$sHilightClass = '';
|
||||
if ($oMainObj)
|
||||
@@ -160,7 +160,7 @@ class HTMLBulkExport extends TabularBulkExport
|
||||
$sData .= "</tr>";
|
||||
$iCount++;
|
||||
}
|
||||
set_time_limit($iPreviousTimeLimit);
|
||||
set_time_limit(intval($iPreviousTimeLimit));
|
||||
$this->aStatusInfo['position'] += $this->iChunkSize;
|
||||
if ($this->aStatusInfo['total'] == 0)
|
||||
{
|
||||
|
||||
@@ -24,14 +24,14 @@ abstract class HTMLSanitizer
|
||||
{
|
||||
// Do nothing..
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Sanitizes the given HTML document
|
||||
* @param string $sHTML
|
||||
* @return string
|
||||
*/
|
||||
abstract public function DoSanitize($sHTML);
|
||||
|
||||
|
||||
/**
|
||||
* Sanitize an HTML string with the configured sanitizer, falling back to HTMLDOMSanitizer in case of Exception or invalid configuration
|
||||
* @param string $sHTML
|
||||
@@ -50,7 +50,7 @@ abstract class HTMLSanitizer
|
||||
IssueLog::Warning('The configured "html_sanitizer" class "'.$sSanitizerClass.'" is not a subclass of HTMLSanitizer. Will use HTMLDOMSanitizer as the default sanitizer.');
|
||||
$sSanitizerClass = 'HTMLDOMSanitizer';
|
||||
}
|
||||
|
||||
|
||||
try
|
||||
{
|
||||
$oSanitizer = new $sSanitizerClass();
|
||||
@@ -70,7 +70,7 @@ abstract class HTMLSanitizer
|
||||
{
|
||||
IssueLog::Error('Failed to sanitize an HTML string with "HTMLDOMSanitizer". The following exception occured: '.$e->getMessage());
|
||||
IssueLog::Error('The HTML will NOT be sanitized.');
|
||||
$sCleanHTML = $sHTML;
|
||||
$sCleanHTML = $sHTML;
|
||||
}
|
||||
}
|
||||
return $sCleanHTML;
|
||||
@@ -97,7 +97,7 @@ class HTMLNullSanitizer extends HTMLSanitizer
|
||||
{
|
||||
return $sHTML;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -109,7 +109,7 @@ class HTMLNullSanitizer extends HTMLSanitizer
|
||||
class HTMLPurifierSanitizer extends HTMLSanitizer
|
||||
{
|
||||
protected static $oPurifier = null;
|
||||
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
if (self::$oPurifier == null)
|
||||
@@ -120,7 +120,7 @@ class HTMLPurifierSanitizer extends HTMLSanitizer
|
||||
throw new Exception("Missing library '$sLibPath', cannot use HTMLPurifierSanitizer.");
|
||||
}
|
||||
require_once($sLibPath);
|
||||
|
||||
|
||||
$oPurifierConfig = HTMLPurifier_Config::createDefault();
|
||||
$oPurifierConfig->set('Core.Encoding', 'UTF-8'); // defaults to 'UTF-8'
|
||||
$oPurifierConfig->set('HTML.Doctype', 'XHTML 1.0 Strict'); // defaults to 'XHTML 1.0 Transitional'
|
||||
@@ -142,11 +142,11 @@ class HTMLPurifierSanitizer extends HTMLSanitizer
|
||||
self::$oPurifier = new HTMLPurifier($oPurifierConfig);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public function DoSanitize($sHTML)
|
||||
{
|
||||
$sCleanHtml = self::$oPurifier->purify($sHTML);
|
||||
return $sCleanHtml;
|
||||
return $sCleanHtml;
|
||||
}
|
||||
}
|
||||
*/
|
||||
@@ -278,13 +278,13 @@ class HTMLDOMSanitizer extends HTMLSanitizer
|
||||
$sHTML = preg_replace('~\xc2\xa0~', ' ', $sHTML);
|
||||
|
||||
@$this->oDoc->loadHTML('<?xml encoding="UTF-8"?>'.$sHTML); // For loading HTML chunks where the character set is not specified
|
||||
|
||||
|
||||
$this->CleanNode($this->oDoc);
|
||||
|
||||
|
||||
$oXPath = new DOMXPath($this->oDoc);
|
||||
$sXPath = "//body";
|
||||
$oNodesList = $oXPath->query($sXPath);
|
||||
|
||||
|
||||
if ($oNodesList->length == 0)
|
||||
{
|
||||
// No body, save the whole document
|
||||
@@ -297,10 +297,10 @@ class HTMLDOMSanitizer extends HTMLSanitizer
|
||||
// remove the body tag itself
|
||||
$sCleanHtml = str_replace( array('<body>', '</body>'), '', $sCleanHtml);
|
||||
}
|
||||
|
||||
|
||||
return $sCleanHtml;
|
||||
}
|
||||
|
||||
|
||||
protected function CleanNode(DOMNode $oElement)
|
||||
{
|
||||
$aAttrToRemove = array();
|
||||
@@ -341,7 +341,7 @@ class HTMLDOMSanitizer extends HTMLSanitizer
|
||||
$oElement->removeAttribute($sName);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if ($oElement->hasChildNodes())
|
||||
{
|
||||
$aChildElementsToRemove = array();
|
||||
@@ -390,7 +390,7 @@ class HTMLDOMSanitizer extends HTMLSanitizer
|
||||
}
|
||||
return implode(';', $aAllowedStyles);
|
||||
}
|
||||
|
||||
|
||||
protected function IsValidAttributeContent($sAttributeName, $sValue)
|
||||
{
|
||||
if (array_key_exists($sAttributeName, self::$aAttrsWhiteList))
|
||||
|
||||
@@ -1,30 +1,27 @@
|
||||
<?php
|
||||
// Copyright (C) 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/>
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
|
||||
define('INLINEIMAGE_DOWNLOAD_URL', 'pages/ajax.document.php?operation=download_inlineimage&id=');
|
||||
|
||||
/**
|
||||
* Persistent classes (internal): store images referenced inside HTML formatted text fields
|
||||
*
|
||||
* @copyright Copyright (C) 2016 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
class InlineImage extends DBObject
|
||||
{
|
||||
/** @var string attribute to be added to IMG tags to contain ID */
|
||||
@@ -32,6 +29,11 @@ class InlineImage extends DBObject
|
||||
/** @var string attribute to be added to IMG tags to contain secret */
|
||||
const DOM_ATTR_SECRET = 'data-img-secret';
|
||||
|
||||
/**
|
||||
*
|
||||
* @throws \CoreException
|
||||
* @throws \Exception
|
||||
*/
|
||||
public static function Init()
|
||||
{
|
||||
$aParams = array
|
||||
@@ -69,8 +71,9 @@ class InlineImage extends DBObject
|
||||
|
||||
/**
|
||||
* Maps the given context parameter name to the appropriate filter/search code for this class
|
||||
*
|
||||
* @param string $sContextParam Name of the context parameter, e.g. 'org_id'
|
||||
* @return string Filter code, e.g. 'customer_id'
|
||||
* @return string|null Filter code, e.g. 'customer_id'
|
||||
*/
|
||||
public static function MapContextParam($sContextParam)
|
||||
{
|
||||
@@ -86,8 +89,15 @@ class InlineImage extends DBObject
|
||||
|
||||
/**
|
||||
* Set/Update all of the '_item' fields
|
||||
*
|
||||
* @param DBObject $oItem Container item
|
||||
* @param bool $bUpdateOnChange
|
||||
*
|
||||
* @return void
|
||||
* @throws \ArchivedObjectException
|
||||
* @throws \CoreCannotSaveObjectException
|
||||
* @throws \CoreException
|
||||
* @throws \CoreUnexpectedValue
|
||||
*/
|
||||
public function SetItem(DBObject $oItem, $bUpdateOnChange = false)
|
||||
{
|
||||
@@ -121,7 +131,12 @@ class InlineImage extends DBObject
|
||||
|
||||
/**
|
||||
* Give a default value for item_org_id (if relevant...)
|
||||
*
|
||||
* @return void
|
||||
* @throws \ArchivedObjectException
|
||||
* @throws \CoreException
|
||||
* @throws \CoreUnexpectedValue
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function SetDefaultOrgId()
|
||||
{
|
||||
@@ -157,12 +172,19 @@ class InlineImage extends DBObject
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* When posting a form, finalize the creation of the inline images
|
||||
* related to the specified object
|
||||
*
|
||||
*
|
||||
* @param DBObject $oObject
|
||||
*
|
||||
* @return void
|
||||
* @throws \CoreCannotSaveObjectException
|
||||
* @throws \CoreException
|
||||
* @throws \CoreUnexpectedValue
|
||||
* @throws \MySQLException
|
||||
* @throws \OQLException
|
||||
*/
|
||||
public static function FinalizeInlineImages(DBObject $oObject)
|
||||
{
|
||||
@@ -203,10 +225,21 @@ class InlineImage extends DBObject
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Cleanup the pending images if the form is not submitted
|
||||
*
|
||||
* @param string $sTempId
|
||||
*
|
||||
* @return void
|
||||
* @throws \ArchivedObjectException
|
||||
* @throws \CoreCannotSaveObjectException
|
||||
* @throws \CoreException
|
||||
* @throws \CoreUnexpectedValue
|
||||
* @throws \DeleteException
|
||||
* @throws \MySQLException
|
||||
* @throws \MySQLHasGoneAwayException
|
||||
* @throws \OQLException
|
||||
*/
|
||||
public static function OnFormCancel($sTempId)
|
||||
{
|
||||
@@ -227,13 +260,16 @@ class InlineImage extends DBObject
|
||||
'HTTP_REFERER' => @$_SERVER['HTTP_REFERER'],
|
||||
));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Parses the supplied HTML fragment to rebuild the attribute src="" for images
|
||||
* that refer to an InlineImage (detected via the attribute data-img-id="") so that
|
||||
* the URL is consistent with the current URL of the application.
|
||||
*
|
||||
* @param string $sHtml The HTML fragment to process
|
||||
*
|
||||
* @return string The modified HTML
|
||||
* @throws \Exception
|
||||
*/
|
||||
public static function FixUrls($sHtml)
|
||||
{
|
||||
@@ -268,6 +304,9 @@ class InlineImage extends DBObject
|
||||
* so that we can later reconstruct the full "src" URL when needed
|
||||
*
|
||||
* @param \DOMElement $oElement
|
||||
*
|
||||
* @return void
|
||||
* @throws \Exception
|
||||
*/
|
||||
public static function ProcessImageTag(DOMElement $oElement)
|
||||
{
|
||||
@@ -301,6 +340,8 @@ class InlineImage extends DBObject
|
||||
|
||||
/**
|
||||
* Get the javascript fragment - to be added to "on document ready" - to adjust (on the fly) the width on Inline Images
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function FixImagesWidth()
|
||||
{
|
||||
@@ -309,15 +350,15 @@ class InlineImage extends DBObject
|
||||
if ($iMaxWidth != 0)
|
||||
{
|
||||
$sJS =
|
||||
<<<EOF
|
||||
<<<JS
|
||||
$('img[data-img-id]').each(function() {
|
||||
if ($(this).width() > $iMaxWidth)
|
||||
if ($(this).width() > {$iMaxWidth})
|
||||
{
|
||||
$(this).css({'max-width': '{$iMaxWidth}px', width: '', height: '', 'max-height': ''});
|
||||
}
|
||||
$(this).addClass('inline-image').attr('href', $(this).attr('src'));
|
||||
}).magnificPopup({type: 'image', closeOnContentClick: true });
|
||||
EOF
|
||||
JS
|
||||
;
|
||||
}
|
||||
|
||||
@@ -563,6 +604,9 @@ JS
|
||||
;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
protected function AfterInsert()
|
||||
{
|
||||
IssueLog::Trace(__METHOD__, 'InlineImage', array(
|
||||
@@ -581,6 +625,9 @@ JS
|
||||
parent::AfterInsert();
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
protected function AfterUpdate()
|
||||
{
|
||||
IssueLog::Trace(__METHOD__, 'InlineImage', array(
|
||||
@@ -599,7 +646,10 @@ JS
|
||||
parent::AfterUpdate();
|
||||
}
|
||||
|
||||
protected function AfterDelete()
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
protected function AfterDelete()
|
||||
{
|
||||
IssueLog::Trace(__METHOD__, 'InlineImage', array(
|
||||
'id' => $this->GetKey(),
|
||||
@@ -625,20 +675,16 @@ JS
|
||||
*/
|
||||
class InlineImageGC implements iBackgroundProcess
|
||||
{
|
||||
public function GetPeriodicity()
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function GetPeriodicity()
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $iTimeLimit
|
||||
*
|
||||
* @return string
|
||||
* @throws \CoreException
|
||||
* @throws \CoreUnexpectedValue
|
||||
* @throws \DeleteException
|
||||
* @throws \MySQLException
|
||||
* @throws \OQLException
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function Process($iTimeLimit)
|
||||
{
|
||||
@@ -692,5 +738,5 @@ class InlineImageGC implements iBackgroundProcess
|
||||
}
|
||||
|
||||
return $iProcessed;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2602,5 +2602,9 @@ class DBObjectSearch extends DBSearch
|
||||
return $oExpression;
|
||||
}
|
||||
|
||||
public function ListParameters()
|
||||
{
|
||||
return $this->GetCriteria()->ListParameters();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -129,8 +129,7 @@ abstract class RotatingLogFileNameBuilder implements iLogFileNameBuilder
|
||||
public function CheckAndRotateLogFile()
|
||||
{
|
||||
$oConfig = utils::GetConfig();
|
||||
$sItopTimeZone = $oConfig->Get('timezone');
|
||||
$timezone = new DateTimeZone($sItopTimeZone);
|
||||
utils::InitTimeZone($oConfig);
|
||||
|
||||
if ($this->GetLastModifiedDateForFile() === null)
|
||||
{
|
||||
@@ -145,11 +144,13 @@ abstract class RotatingLogFileNameBuilder implements iLogFileNameBuilder
|
||||
return;
|
||||
}
|
||||
$oDateTime = DateTime::createFromFormat('U', $iLogDateLastModifiedTimeStamp);
|
||||
$sItopTimeZone = $oConfig->Get('timezone');
|
||||
$timezone = new DateTimeZone($sItopTimeZone);
|
||||
$oDateTime->setTimezone($timezone);
|
||||
$this->SetLastModifiedDateForFile($oDateTime);
|
||||
}
|
||||
|
||||
$oNow = new DateTime('now', $timezone);
|
||||
$oNow = new DateTime();
|
||||
$bShouldRotate = $this->ShouldRotate($this->GetLastModifiedDateForFile(), $oNow);
|
||||
if (!$bShouldRotate)
|
||||
{
|
||||
@@ -830,4 +831,4 @@ class LogFileRotationProcess implements iScheduledProcess
|
||||
|
||||
throw new ProcessException(self::class.' : The configured filename builder is invalid (log_filename_builder_impl="'.$sLogFileNameBuilder.'")');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -126,6 +126,13 @@ abstract class MetaModel
|
||||
/** @var string */
|
||||
protected static $m_sEnvironment = 'production';
|
||||
|
||||
/**
|
||||
* MetaModel constructor.
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
@@ -722,7 +729,51 @@ abstract class MetaModel
|
||||
return array('%1$s', array($nameRawSpec));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $sClass
|
||||
*
|
||||
* @return array
|
||||
* @throws \CoreException
|
||||
* @throws \DictExceptionMissingString
|
||||
*/
|
||||
final static public function GetComplementAttributeSpec($sClass)
|
||||
{
|
||||
self::_check_subclass($sClass);
|
||||
if (!isset(self::$m_aClassParams[$sClass]["name_complement_for_select"]))
|
||||
{
|
||||
return array($sClass, array());
|
||||
}
|
||||
$nameRawSpec = self::$m_aClassParams[$sClass]["name_complement_for_select"];
|
||||
if (is_array($nameRawSpec))
|
||||
{
|
||||
$sFormat = Dict::S("Class:$sClass/ComplementForSelect", '');
|
||||
if (strlen($sFormat) == 0)
|
||||
{
|
||||
// Default to "%1$s %2$s..."
|
||||
for($i = 1; $i <= count($nameRawSpec); $i++)
|
||||
{
|
||||
if (empty($sFormat))
|
||||
{
|
||||
$sFormat .= '%'.$i.'$s';
|
||||
}
|
||||
else
|
||||
{
|
||||
$sFormat .= ' %'.$i.'$s';
|
||||
}
|
||||
}
|
||||
}
|
||||
return array($sFormat, $nameRawSpec);
|
||||
}
|
||||
elseif (empty($nameRawSpec))
|
||||
{
|
||||
return array($sClass, array());
|
||||
}
|
||||
else
|
||||
{
|
||||
// string -> attcode
|
||||
return array('%1$s', array($nameRawSpec));
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Get the friendly name expression for a given class
|
||||
*
|
||||
@@ -802,12 +853,33 @@ abstract class MetaModel
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the $sClass has a state attribute defined.
|
||||
*
|
||||
* Note that having a state attribute does NOT mean having a lifecycle!
|
||||
* - A Person with active/inactive state won't have transitions and therefore no lifecycle
|
||||
* - A UserRequest will have transitions between its states and so a lifecycle
|
||||
*
|
||||
* @see self::HasLifecycle($sClass)
|
||||
* @param string $sClass Datamodel class to check
|
||||
*
|
||||
* @return bool
|
||||
* @throws \CoreException
|
||||
* @since 3.0.0
|
||||
*/
|
||||
final public static function HasStateAttributeCode(string $sClass)
|
||||
{
|
||||
return !empty(self::GetStateAttributeCode($sClass));
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the code of the attribute carrying the state of the instance of the class
|
||||
*
|
||||
* @param string $sClass
|
||||
*
|
||||
* @return string
|
||||
* @throws \CoreException
|
||||
*/
|
||||
final public static function GetStateAttributeCode($sClass)
|
||||
final public static function GetStateAttributeCode(string $sClass)
|
||||
{
|
||||
self::_check_subclass($sClass);
|
||||
|
||||
@@ -821,7 +893,7 @@ abstract class MetaModel
|
||||
* @throws \CoreException
|
||||
* @throws \Exception
|
||||
*/
|
||||
final public static function GetDefaultState($sClass)
|
||||
final public static function GetDefaultState(string $sClass)
|
||||
{
|
||||
$sDefaultState = '';
|
||||
$sStateAttrCode = self::GetStateAttributeCode($sClass);
|
||||
@@ -833,6 +905,37 @@ abstract class MetaModel
|
||||
return $sDefaultState;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the $sClass has an image attribute defined
|
||||
*
|
||||
* @param string $sClass
|
||||
*
|
||||
* @return bool
|
||||
* @throws \CoreException
|
||||
* @since 3.0.0
|
||||
*/
|
||||
final public static function HasImageAttributeCode(string $sClass)
|
||||
{
|
||||
return !empty(self::GetImageAttributeCode($sClass));
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the code of the attribute carrying the image representing an instance of the class
|
||||
*
|
||||
* @param string $sClass Datamodel class to get the image attribute code for
|
||||
*
|
||||
* @return mixed
|
||||
* @throws \CoreException
|
||||
* @since 3.0.0
|
||||
*/
|
||||
final public static function GetImageAttributeCode(string $sClass)
|
||||
{
|
||||
self::_check_subclass($sClass);
|
||||
|
||||
// image_attcode isn't a mandatory class parameter, so it might not be in the $m_aClassParam array
|
||||
return isset(self::$m_aClassParams[$sClass]["image_attcode"]) ? self::$m_aClassParams[$sClass]["image_attcode"] : '';
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $sClass
|
||||
*
|
||||
@@ -846,20 +949,6 @@ abstract class MetaModel
|
||||
return self::$m_aClassParams[$sClass]["reconc_keys"];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $sClass
|
||||
*
|
||||
* @return string
|
||||
* @throws \CoreException
|
||||
*/
|
||||
final public static function GetDisplayTemplate($sClass)
|
||||
{
|
||||
self::_check_subclass($sClass);
|
||||
|
||||
return array_key_exists("display_template",
|
||||
self::$m_aClassParams[$sClass]) ? self::$m_aClassParams[$sClass]["display_template"] : '';
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $sClass
|
||||
* @param bool $bOnlyDeclared
|
||||
@@ -926,11 +1015,6 @@ abstract class MetaModel
|
||||
{
|
||||
self::_check_subclass($sClass);
|
||||
$oAtt = self::GetAttributeDef($sClass, $sAttCode);
|
||||
// Temporary implementation: later, we might be able to compute
|
||||
// the dependencies, based on the attributes definition
|
||||
// (allowed values and default values)
|
||||
|
||||
// Even non-writable attributes (like ExternalFields) can now have Prerequisites
|
||||
return $oAtt->GetPrerequisiteAttributes();
|
||||
}
|
||||
|
||||
@@ -1221,15 +1305,36 @@ abstract class MetaModel
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an array of attributes codes for the $sClass. The list can be limited to some attribute types only.
|
||||
*
|
||||
* @param string $sClass
|
||||
* @param string[] $aDesiredAttTypes Array of AttributeDefinition classes to filter the list on
|
||||
*
|
||||
* @return array
|
||||
* @throws \CoreException
|
||||
*/
|
||||
final public static function GetAttributesList($sClass)
|
||||
final public static function GetAttributesList($sClass, $aDesiredAttTypes = [])
|
||||
{
|
||||
self::_check_subclass($sClass);
|
||||
return array_keys(self::$m_aAttribDefs[$sClass]);
|
||||
|
||||
if(empty($aDesiredAttTypes))
|
||||
{
|
||||
return array_keys(self::$m_aAttribDefs[$sClass]);
|
||||
}
|
||||
|
||||
$aMatchingAttCodes = [];
|
||||
foreach(self::$m_aAttribDefs[$sClass] as $sAttCode => $oAttDef)
|
||||
{
|
||||
foreach($aDesiredAttTypes as $sDesiredAttType)
|
||||
{
|
||||
if(is_a($oAttDef, $sDesiredAttType))
|
||||
{
|
||||
$aMatchingAttCodes[] = $sAttCode;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $aMatchingAttCodes;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1448,6 +1553,7 @@ abstract class MetaModel
|
||||
{
|
||||
$aLinkedSets = array();
|
||||
foreach (self::ListAttributeDefs($sClass) as $sAttCode => $oAtt) {
|
||||
// Note: Careful, this will only return SUB-classes, which does NOT include AttributeLinkedset itself! We might want to use "is_a()" instead.
|
||||
if (is_subclass_of($oAtt, 'AttributeLinkedSet')) {
|
||||
$aLinkedSets[$sAttCode] = $oAtt;
|
||||
}
|
||||
@@ -1495,6 +1601,27 @@ abstract class MetaModel
|
||||
}
|
||||
}
|
||||
|
||||
/** @var array Cache for caselog attributes of the classes */
|
||||
protected static $m_aCaseLogsAttributesCache = [];
|
||||
|
||||
/**
|
||||
* Return an array of attribute codes for the caselogs attributes of $sClass
|
||||
*
|
||||
* @param string $sClass
|
||||
*
|
||||
* @return array
|
||||
* @throws \CoreException
|
||||
* @since 3.0.0
|
||||
*/
|
||||
final public static function GetCaseLogs(string $sClass)
|
||||
{
|
||||
if (!isset(static::$m_aCaseLogsAttributesCache[$sClass])) {
|
||||
static::$m_aCaseLogsAttributesCache[$sClass] = self::GetAttributesList($sClass, ['AttributeCaseLog']);
|
||||
}
|
||||
|
||||
return static::$m_aCaseLogsAttributesCache[$sClass];
|
||||
}
|
||||
|
||||
/** @var array */
|
||||
protected static $m_aTrackForwardCache = array();
|
||||
|
||||
@@ -1800,7 +1927,7 @@ abstract class MetaModel
|
||||
* @param string $sClass
|
||||
* @param string $sListCode
|
||||
*
|
||||
* @return array
|
||||
* @return array list of attribute codes
|
||||
*/
|
||||
public static function GetZListItems($sClass, $sListCode)
|
||||
{
|
||||
@@ -1820,6 +1947,82 @@ abstract class MetaModel
|
||||
return self::GetZListItems($sParentClass, $sListCode);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $sRemoteClass
|
||||
*
|
||||
* @return \AttributeDefinition[] list of attdefs to display by default for the remote class
|
||||
*
|
||||
* @since 3.0.0 N°2334
|
||||
*/
|
||||
public static function GetZListAttDefsFilteredForIndirectRemoteClass($sRemoteClass)
|
||||
{
|
||||
$aAttCodesToPrint = [];
|
||||
|
||||
foreach (MetaModel::GetZListItems($sRemoteClass, 'list') as $sFieldCode)
|
||||
{
|
||||
//TODO: check the state of the attribute: hidden or visible ?
|
||||
if ($sFieldCode == 'finalclass')
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
$oRemoteAttDef = MetaModel::GetAttributeDef($sRemoteClass, $sFieldCode);
|
||||
$aAttCodesToPrint[] = $oRemoteAttDef;
|
||||
}
|
||||
|
||||
return $aAttCodesToPrint;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $sClass left class
|
||||
* @param string $sAttCode AttributeLinkedSetIndirect attcode
|
||||
*
|
||||
* @return \AttributeDefinition[] list of attdefs to display by default for lnk class
|
||||
*
|
||||
* @throws \CoreException
|
||||
* @since 3.0.0 N°2334
|
||||
*/
|
||||
public static function GetZListAttDefsFilteredForIndirectLinkClass($sClass, $sAttCode)
|
||||
{
|
||||
$aAttCodesToPrint = [];
|
||||
|
||||
$oLinkedSetAttDef = MetaModel::GetAttributeDef($sClass, $sAttCode);
|
||||
$sLinkedClass = $oLinkedSetAttDef->GetLinkedClass();
|
||||
$sExtKeyToRemote = $oLinkedSetAttDef->GetExtKeyToRemote();
|
||||
$sExtKeyToMe = $oLinkedSetAttDef->GetExtKeyToMe();
|
||||
|
||||
$sStateAttCode = MetaModel::GetStateAttributeCode($sClass);
|
||||
$sDefaultState = MetaModel::GetDefaultState($sClass);
|
||||
|
||||
foreach (MetaModel::FlattenZList(MetaModel::GetZListItems($sLinkedClass, 'list')) as $sLnkAttCode)
|
||||
{
|
||||
$oLnkAttDef = MetaModel::GetAttributeDef($sLinkedClass, $sLnkAttCode);
|
||||
if ($sStateAttCode == $sLnkAttCode)
|
||||
{
|
||||
// State attribute is always hidden from the UI
|
||||
continue;
|
||||
}
|
||||
if (($sLnkAttCode == $sExtKeyToMe)
|
||||
|| ($sLnkAttCode == $sExtKeyToRemote)
|
||||
|| ($sLnkAttCode == 'finalclass'))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (!($oLnkAttDef->IsWritable()))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
$iFlags = MetaModel::GetAttributeFlags($sLinkedClass, $sDefaultState, $sLnkAttCode);
|
||||
if (!($iFlags & OPT_ATT_HIDDEN) && !($iFlags & OPT_ATT_READONLY))
|
||||
{
|
||||
$aAttCodesToPrint[] = $oLnkAttDef;
|
||||
}
|
||||
}
|
||||
|
||||
return $aAttCodesToPrint;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $sClass
|
||||
* @param string $sListCode
|
||||
@@ -1992,7 +2195,6 @@ abstract class MetaModel
|
||||
*/
|
||||
protected static function ComputeRelationQueries($sRelCode)
|
||||
{
|
||||
$bHasLegacy = false;
|
||||
$aQueries = array();
|
||||
foreach(self::GetClasses() as $sClass)
|
||||
{
|
||||
@@ -2078,158 +2280,8 @@ abstract class MetaModel
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Read legacy definitions
|
||||
// The up/down queries have to be reconcilied, which can only be done later when all the classes have been browsed
|
||||
//
|
||||
// The keys used to store a query (up or down) into the array are built differently between the modern and legacy made data:
|
||||
// Modern way: aQueries[sClass]['up'|'down'][sArrowId], where sArrowId is made of the source class + neighbour id (XML def)
|
||||
// Legacy way: aQueries[sClass]['up'|'down'][sRemoteClass]
|
||||
// The modern way does allow for several arrows between two classes
|
||||
// The legacy way aims at simplifying the transformation (reconciliation between up and down)
|
||||
if ($sRelCode == 'impacts')
|
||||
{
|
||||
$sRevertCode = 'depends on';
|
||||
|
||||
$aLegacy = call_user_func_array(array($sClass, 'GetRelationQueries'), array($sRelCode));
|
||||
foreach($aLegacy as $sId => $aLegacyEntry)
|
||||
{
|
||||
$bHasLegacy = true;
|
||||
|
||||
$oFilter = DBObjectSearch::FromOQL($aLegacyEntry['sQuery']);
|
||||
$sRemoteClass = $oFilter->GetClass();
|
||||
|
||||
// Determine wether the query is inherited from a parent or not
|
||||
$bInherited = false;
|
||||
foreach(self::EnumParentClasses($sClass) as $sParent)
|
||||
{
|
||||
if (!isset($aQueries[$sParent]['down'][$sRemoteClass]))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if ($aLegacyEntry['sQuery'] == $aQueries[$sParent]['down'][$sRemoteClass]['sQueryDown'])
|
||||
{
|
||||
$bInherited = true;
|
||||
$aQueries[$sClass]['down'][$sRemoteClass] = $aQueries[$sParent]['down'][$sRemoteClass];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!$bInherited)
|
||||
{
|
||||
$aQueries[$sClass]['down'][$sRemoteClass] = array(
|
||||
'_legacy_' => true,
|
||||
'sDefinedInClass' => $sClass,
|
||||
'sFromClass' => $sClass,
|
||||
'sToClass' => $sRemoteClass,
|
||||
'sDirection' => 'down',
|
||||
'sQueryDown' => $aLegacyEntry['sQuery'],
|
||||
'sQueryUp' => null,
|
||||
'sNeighbour' => $sRemoteClass // Normalize the neighbour id
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
$aLegacy = call_user_func_array(array($sClass, 'GetRelationQueries'), array($sRevertCode));
|
||||
foreach($aLegacy as $sId => $aLegacyEntry)
|
||||
{
|
||||
$bHasLegacy = true;
|
||||
|
||||
$oFilter = DBObjectSearch::FromOQL($aLegacyEntry['sQuery']);
|
||||
$sRemoteClass = $oFilter->GetClass();
|
||||
|
||||
// Determine wether the query is inherited from a parent or not
|
||||
$bInherited = false;
|
||||
foreach(self::EnumParentClasses($sClass) as $sParent)
|
||||
{
|
||||
if (!isset($aQueries[$sParent]['up'][$sRemoteClass]))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if ($aLegacyEntry['sQuery'] == $aQueries[$sParent]['up'][$sRemoteClass]['sQueryUp'])
|
||||
{
|
||||
$bInherited = true;
|
||||
$aQueries[$sClass]['up'][$sRemoteClass] = $aQueries[$sParent]['up'][$sRemoteClass];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!$bInherited)
|
||||
{
|
||||
$aQueries[$sClass]['up'][$sRemoteClass] = array(
|
||||
'_legacy_' => true,
|
||||
'sDefinedInClass' => $sRemoteClass,
|
||||
'sFromClass' => $sRemoteClass,
|
||||
'sToClass' => $sClass,
|
||||
'sDirection' => 'both',
|
||||
'sQueryDown' => null,
|
||||
'sQueryUp' => $aLegacyEntry['sQuery'],
|
||||
'sNeighbour' => $sClass// Normalize the neighbour id
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
//else
|
||||
//{
|
||||
// Cannot take the legacy system into account... simply ignore it
|
||||
//}
|
||||
} // foreach class
|
||||
|
||||
// Perform the up/down reconciliation for the legacy definitions
|
||||
if ($bHasLegacy)
|
||||
{
|
||||
foreach(self::GetClasses() as $sClass)
|
||||
{
|
||||
// Foreach "up" legacy query, update its "down" counterpart
|
||||
if (isset($aQueries[$sClass]['up']))
|
||||
{
|
||||
foreach($aQueries[$sClass]['up'] as $sNeighbourId => $aNeighbourData)
|
||||
{
|
||||
if (!array_key_exists('_legacy_', $aNeighbourData))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (!$aNeighbourData['_legacy_'])
|
||||
{
|
||||
continue;
|
||||
} // Skip modern definitions
|
||||
|
||||
$sLocalClass = $aNeighbourData['sToClass'];
|
||||
foreach(self::EnumChildClasses($aNeighbourData['sFromClass'], ENUM_CHILD_CLASSES_ALL) as $sRemoteClass)
|
||||
{
|
||||
if (isset($aQueries[$sRemoteClass]['down'][$sLocalClass]))
|
||||
{
|
||||
$aQueries[$sRemoteClass]['down'][$sLocalClass]['sQueryUp'] = $aNeighbourData['sQueryUp'];
|
||||
$aQueries[$sRemoteClass]['down'][$sLocalClass]['sDirection'] = 'both';
|
||||
}
|
||||
// Be silent in order to transparently support legacy data models where the counterpart query does not always exist
|
||||
//else
|
||||
//{
|
||||
// throw new Exception("Legacy definition of the relation '$sRelCode/$sRevertCode', defined on $sLocalClass (relation: $sRevertCode, inherited to $sClass), missing the counterpart query on class $sRemoteClass ($sRelCode)");
|
||||
//}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Foreach "down" legacy query, update its "up" counterpart (if any)
|
||||
foreach($aQueries[$sClass]['down'] as $sNeighbourId => $aNeighbourData)
|
||||
{
|
||||
if (!$aNeighbourData['_legacy_'])
|
||||
{
|
||||
continue;
|
||||
} // Skip modern definitions
|
||||
|
||||
$sLocalClass = $aNeighbourData['sFromClass'];
|
||||
foreach(self::EnumChildClasses($aNeighbourData['sToClass'], ENUM_CHILD_CLASSES_ALL) as $sRemoteClass)
|
||||
{
|
||||
if (isset($aQueries[$sRemoteClass]['up'][$sLocalClass]))
|
||||
{
|
||||
$aQueries[$sRemoteClass]['up'][$sLocalClass]['sQueryDown'] = $aNeighbourData['sQueryDown'];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $aQueries;
|
||||
}
|
||||
|
||||
@@ -2347,6 +2399,22 @@ abstract class MetaModel
|
||||
{
|
||||
return self::$m_aStates[$sClass];
|
||||
}
|
||||
elseif (self::HasStateAttributeCode($sClass))
|
||||
{
|
||||
$sStateAttCode = self::GetStateAttributeCode($sClass);
|
||||
$oAttDef = self::GetAttributeDef($sClass, $sStateAttCode);
|
||||
|
||||
$aStates = [];
|
||||
foreach($oAttDef->GetAllowedValues() as $sStateCode => $sStateLabel)
|
||||
{
|
||||
$aStates[$sStateCode] = [
|
||||
'attribute_inherit' => '',
|
||||
'attribute_list' => [],
|
||||
];
|
||||
}
|
||||
|
||||
return $aStates;
|
||||
}
|
||||
else
|
||||
{
|
||||
return array();
|
||||
@@ -2404,6 +2472,21 @@ abstract class MetaModel
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if $sClass has a lifecycle, which means that it has a state attribute AND stimuli
|
||||
*
|
||||
* @param string $sClass
|
||||
*
|
||||
* @return bool
|
||||
* @throws \CoreException
|
||||
* @since 3.0.0
|
||||
* @see self::HasStateAttributeCode($sClass)
|
||||
*/
|
||||
public static function HasLifecycle(string $sClass)
|
||||
{
|
||||
return self::HasStateAttributeCode($sClass) && !empty(self::EnumStimuli($sClass));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $sClass
|
||||
* @param string $sStateValue
|
||||
@@ -2492,17 +2575,13 @@ abstract class MetaModel
|
||||
public static function GetAttributeFlags($sClass, $sState, $sAttCode)
|
||||
{
|
||||
$iFlags = 0; // By default (if no life cycle) no flag at all
|
||||
$sStateAttCode = self::GetStateAttributeCode($sClass);
|
||||
if (!empty($sStateAttCode))
|
||||
{
|
||||
if (self::HasLifecycle($sClass)) {
|
||||
$aStates = MetaModel::EnumStates($sClass);
|
||||
if (!array_key_exists($sState, $aStates))
|
||||
{
|
||||
if (!array_key_exists($sState, $aStates)) {
|
||||
throw new CoreException("Invalid state '$sState' for class '$sClass', expecting a value in {".implode(', ', array_keys($aStates))."}");
|
||||
}
|
||||
$aCurrentState = $aStates[$sState];
|
||||
if ((array_key_exists('attribute_list', $aCurrentState)) && (array_key_exists($sAttCode, $aCurrentState['attribute_list'])))
|
||||
{
|
||||
if ((array_key_exists('attribute_list', $aCurrentState)) && (array_key_exists($sAttCode, $aCurrentState['attribute_list']))) {
|
||||
$iFlags = $aCurrentState['attribute_list'][$sAttCode];
|
||||
}
|
||||
}
|
||||
@@ -2522,18 +2601,14 @@ abstract class MetaModel
|
||||
public static function GetTransitionFlags($sClass, $sState, $sStimulus, $sAttCode)
|
||||
{
|
||||
$iFlags = 0; // By default (if no lifecycle) no flag at all
|
||||
$sStateAttCode = self::GetStateAttributeCode($sClass);
|
||||
if (!empty($sStateAttCode))
|
||||
{
|
||||
if (self::HasLifecycle($sClass)) {
|
||||
$aTransitions = MetaModel::EnumTransitions($sClass, $sState);
|
||||
if (!array_key_exists($sStimulus, $aTransitions))
|
||||
{
|
||||
if (!array_key_exists($sStimulus, $aTransitions)) {
|
||||
throw new CoreException("Invalid transition '$sStimulus' for class '$sClass', expecting a value in {".implode(', ', array_keys($aTransitions))."}");
|
||||
}
|
||||
|
||||
$aCurrentTransition = $aTransitions[$sStimulus];
|
||||
if ((array_key_exists('attribute_list', $aCurrentTransition)) && (array_key_exists($sAttCode, $aCurrentTransition['attribute_list'])))
|
||||
{
|
||||
if ((array_key_exists('attribute_list', $aCurrentTransition)) && (array_key_exists($sAttCode, $aCurrentTransition['attribute_list']))) {
|
||||
$iFlags = $aCurrentTransition['attribute_list'][$sAttCode];
|
||||
}
|
||||
}
|
||||
@@ -2612,37 +2687,30 @@ abstract class MetaModel
|
||||
public static function GetInitialStateAttributeFlags($sClass, $sState, $sAttCode)
|
||||
{
|
||||
$iFlags = self::GetAttributeFlags($sClass, $sState, $sAttCode); // Be default set the same flags as the 'target' state
|
||||
$sStateAttCode = self::GetStateAttributeCode($sClass);
|
||||
if (!empty($sStateAttCode))
|
||||
{
|
||||
if (self::HasLifecycle($sClass)) {
|
||||
$aStates = MetaModel::EnumInitialStates($sClass);
|
||||
if (array_key_exists($sState, $aStates))
|
||||
{
|
||||
if (array_key_exists($sState, $aStates)) {
|
||||
$bReadOnly = (($iFlags & OPT_ATT_READONLY) == OPT_ATT_READONLY);
|
||||
$bHidden = (($iFlags & OPT_ATT_HIDDEN) == OPT_ATT_HIDDEN);
|
||||
foreach($aStates[$sState] as $sPrevState)
|
||||
{
|
||||
foreach($aStates[$sState] as $sPrevState) {
|
||||
$iPrevFlags = self::GetAttributeFlags($sClass, $sPrevState, $sAttCode);
|
||||
if (($iPrevFlags & OPT_ATT_HIDDEN) != OPT_ATT_HIDDEN)
|
||||
{
|
||||
if (($iPrevFlags & OPT_ATT_HIDDEN) != OPT_ATT_HIDDEN) {
|
||||
$bReadOnly = $bReadOnly && (($iPrevFlags & OPT_ATT_READONLY) == OPT_ATT_READONLY); // if it is/was not readonly => then it's not
|
||||
}
|
||||
$bHidden = $bHidden && (($iPrevFlags & OPT_ATT_HIDDEN) == OPT_ATT_HIDDEN); // if it is/was not hidden => then it's not
|
||||
}
|
||||
if ($bReadOnly)
|
||||
{
|
||||
|
||||
if ($bReadOnly) {
|
||||
$iFlags = $iFlags | OPT_ATT_READONLY;
|
||||
}
|
||||
else
|
||||
{
|
||||
else {
|
||||
$iFlags = $iFlags & ~OPT_ATT_READONLY;
|
||||
}
|
||||
if ($bHidden)
|
||||
{
|
||||
|
||||
if ($bHidden) {
|
||||
$iFlags = $iFlags | OPT_ATT_HIDDEN;
|
||||
}
|
||||
else
|
||||
{
|
||||
else {
|
||||
$iFlags = $iFlags & ~OPT_ATT_HIDDEN;
|
||||
}
|
||||
}
|
||||
@@ -2781,7 +2849,7 @@ abstract class MetaModel
|
||||
$aInterfaces = array('iApplicationUIExtension', 'iPreferencesExtension', 'iApplicationObjectExtension', 'iLoginFSMExtension', 'iLoginUIExtension', 'iLogoutExtension', 'iQueryModifier', 'iOnClassInitialization', 'iPopupMenuExtension', 'iPageUIExtension', 'iPortalUIExtension', 'ModuleHandlerApiInterface', 'iNewsroomProvider', 'iModuleExtension');
|
||||
foreach($aInterfaces as $sInterface)
|
||||
{
|
||||
self::$m_aExtensionClasses[$sInterface] = array();
|
||||
self::$m_aExtensionClassNames[$sInterface] = array();
|
||||
}
|
||||
|
||||
foreach(get_declared_classes() as $sPHPClass)
|
||||
@@ -2792,11 +2860,7 @@ abstract class MetaModel
|
||||
{
|
||||
if ($oRefClass->implementsInterface($sInterface) && $oRefClass->isInstantiable())
|
||||
{
|
||||
if (is_null($oExtensionInstance))
|
||||
{
|
||||
$oExtensionInstance = new $sPHPClass;
|
||||
}
|
||||
self::$m_aExtensionClasses[$sInterface][$sPHPClass] = $oExtensionInstance;
|
||||
self::$m_aExtensionClassNames[$sInterface][$sPHPClass] = $sPHPClass;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2856,6 +2920,25 @@ abstract class MetaModel
|
||||
}
|
||||
self::$m_aClassParams[$sPHPClass]['obsolescence_expression'] = $sObsolescence;
|
||||
|
||||
// Inherit fields semantic
|
||||
// - State attribute
|
||||
$bParentHasStateAttribute = (isset(self::$m_aClassParams[$sParent]['state_attcode']) && !empty(self::$m_aClassParams[$sParent]['state_attcode']));
|
||||
$bHasStateAttribute = (isset(self::$m_aClassParams[$sPHPClass]['state_attcode']) && !empty(self::$m_aClassParams[$sPHPClass]['state_attcode']));
|
||||
if($bParentHasStateAttribute && !$bHasStateAttribute) {
|
||||
// Set attribute code
|
||||
self::$m_aClassParams[$sPHPClass]['state_attcode'] = self::$m_aClassParams[$sParent]['state_attcode'];
|
||||
|
||||
// Set states
|
||||
self::$m_aStates[$sPHPClass] = self::$m_aStates[$sParent];
|
||||
}
|
||||
// - Image attribute
|
||||
$bParentHasImageAttribute = (isset(self::$m_aClassParams[$sParent]['image_attcode']) && !empty(self::$m_aClassParams[$sParent]['image_attcode']));
|
||||
$bHasImageAttribute = (isset(self::$m_aClassParams[$sPHPClass]['image_attcode']) && !empty(self::$m_aClassParams[$sPHPClass]['image_attcode']));
|
||||
if($bParentHasImageAttribute && !$bHasImageAttribute) {
|
||||
// Set attribute code
|
||||
self::$m_aClassParams[$sPHPClass]['image_attcode'] = self::$m_aClassParams[$sParent]['image_attcode'];
|
||||
}
|
||||
|
||||
foreach(MetaModel::EnumPlugins('iOnClassInitialization') as $sPluginClass => $oClassInit)
|
||||
{
|
||||
$oClassInit->OnAfterClassInitialization($sPHPClass);
|
||||
@@ -3262,18 +3345,6 @@ abstract class MetaModel
|
||||
// In fact it is an ABSTRACT function, but this is not compatible with the fact that it is STATIC (error in E_STRICT interpretation)
|
||||
}
|
||||
|
||||
/**
|
||||
* To be overloaded by biz model declarations
|
||||
*
|
||||
* @param string $sRelCode
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function GetRelationQueries($sRelCode)
|
||||
{
|
||||
// In fact it is an ABSTRACT function, but this is not compatible with the fact that it is STATIC (error in E_STRICT interpretation)
|
||||
return array();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $aParams
|
||||
@@ -3283,11 +3354,12 @@ abstract class MetaModel
|
||||
public static function Init_Params($aParams)
|
||||
{
|
||||
// Check mandatory params
|
||||
// Warning: Do not put image_attcode as a mandatory attribute or it will break all PHP datamodel classes
|
||||
$aMandatParams = array(
|
||||
"category" => "group classes by modules defining their visibility in the UI",
|
||||
"key_type" => "autoincrement | string",
|
||||
"name_attcode" => "define wich attribute is the class name, may be an array of attributes (format specified in the dictionary as 'Class:myclass/Name' => '%1\$s %2\$s...'",
|
||||
"state_attcode" => "define wich attribute is representing the state (object lifecycle)",
|
||||
"name_attcode" => "define which attribute is the class name, may be an array of attributes (format specified in the dictionary as 'Class:myclass/Name' => '%1\$s %2\$s...'",
|
||||
"state_attcode" => "define which attribute is representing the state (object lifecycle)",
|
||||
"reconc_keys" => "define the attributes that will 'almost uniquely' identify an object in batch processes",
|
||||
"db_table" => "database table",
|
||||
"db_key_field" => "database field which is the key",
|
||||
@@ -5754,32 +5826,9 @@ abstract class MetaModel
|
||||
$sView = self::DBGetView($sClass);
|
||||
if (CMDBSource::IsTable($sView))
|
||||
{
|
||||
// Check that the view is complete
|
||||
//
|
||||
// Note: checking the list of attributes is not enough because the columns can be stable while the SELECT is not stable
|
||||
// Example: new way to compute the friendly name
|
||||
// The correct comparison algorithm is to compare the queries,
|
||||
// by using "SHOW CREATE VIEW" (MySQL 5.0.1 required) or to look into INFORMATION_SCHEMA/views
|
||||
// both requiring some privileges
|
||||
// Decision: to simplify, let's consider the views as being wrong anytime
|
||||
// Rework the view
|
||||
//
|
||||
$oFilter = new DBObjectSearch($sClass, '');
|
||||
$oFilter->AllowAllData();
|
||||
$sSQL = $oFilter->MakeSelectQuery();
|
||||
$aErrors[$sClass]['*'][] = "Redeclare view '$sView' (systematic - to support an eventual change in the friendly name computation)";
|
||||
$aSugFix[$sClass]['*'][] = "ALTER VIEW `$sView` AS $sSQL";
|
||||
}
|
||||
else
|
||||
{
|
||||
// Create the view
|
||||
//
|
||||
$oFilter = new DBObjectSearch($sClass, '');
|
||||
$oFilter->AllowAllData();
|
||||
$sSQL = $oFilter->MakeSelectQuery();
|
||||
$aErrors[$sClass]['*'][] = "Missing view for class: $sClass";
|
||||
$aSugFix[$sClass]['*'][] = "DROP VIEW IF EXISTS `$sView`";
|
||||
$aSugFix[$sClass]['*'][] = "CREATE VIEW `$sView` AS $sSQL";
|
||||
// Remove deprecated views
|
||||
$aErrors[$sClass]['*'][] = "Remove view '$sView' (deprecated, consider installing combodo-views if needed)";
|
||||
$aSugFix[$sClass]['*'][] = "DROP VIEW `$sView`";
|
||||
}
|
||||
}
|
||||
return array($aErrors, $aSugFix);
|
||||
@@ -6321,6 +6370,7 @@ abstract class MetaModel
|
||||
|
||||
// N°2478 utils has his own private attribute
|
||||
// @see utils::GetConfig : it always call MetaModel, but to be sure we're doing this extra copy anyway O:)
|
||||
utils::InitTimeZone($oConfiguration);
|
||||
utils::SetConfig($oConfiguration);
|
||||
|
||||
// Set log ASAP
|
||||
@@ -6361,19 +6411,6 @@ abstract class MetaModel
|
||||
DBSearch::EnableQueryIndentation(self::$m_oConfig->Get('query_indentation_enabled'));
|
||||
DBSearch::EnableOptimizeQuery(self::$m_oConfig->Get('query_optimization_enabled'));
|
||||
|
||||
// PHP timezone first...
|
||||
//
|
||||
$sPHPTimezone = self::$m_oConfig->Get('timezone');
|
||||
if ($sPHPTimezone == '')
|
||||
{
|
||||
// Leave as is... up to the admin to set a value somewhere...
|
||||
//$sPHPTimezone = date_default_timezone_get();
|
||||
}
|
||||
else
|
||||
{
|
||||
date_default_timezone_set($sPHPTimezone);
|
||||
}
|
||||
|
||||
// Note: load the dictionary as soon as possible, because it might be
|
||||
// needed when some error occur
|
||||
$sAppIdentity = 'itop-'.MetaModel::GetEnvironmentId();
|
||||
@@ -6417,7 +6454,7 @@ abstract class MetaModel
|
||||
if (is_array($result))
|
||||
{
|
||||
// todo - verifier que toutes les classes mentionnees ici sont chargees dans InitClasses()
|
||||
self::$m_aExtensionClasses = $result['m_aExtensionClasses'];
|
||||
self::$m_aExtensionClassNames = $result['m_aExtensionClassNames'];
|
||||
self::$m_Category2Class = $result['m_Category2Class'];
|
||||
self::$m_aRootClasses = $result['m_aRootClasses'];
|
||||
self::$m_aParentClasses = $result['m_aParentClasses'];
|
||||
@@ -6454,7 +6491,7 @@ abstract class MetaModel
|
||||
$oKPI = new ExecutionKPI();
|
||||
|
||||
$aCache = array();
|
||||
$aCache['m_aExtensionClasses'] = self::$m_aExtensionClasses;
|
||||
$aCache['m_aExtensionClassNames'] = self::$m_aExtensionClassNames;
|
||||
$aCache['m_Category2Class'] = self::$m_Category2Class;
|
||||
$aCache['m_aRootClasses'] = self::$m_aRootClasses; // array of "classname" => "rootclass"
|
||||
$aCache['m_aParentClasses'] = self::$m_aParentClasses; // array of ("classname" => array of "parentclass")
|
||||
@@ -6538,8 +6575,8 @@ abstract class MetaModel
|
||||
return md5(APPROOT).'-'.self::$m_sEnvironment;
|
||||
}
|
||||
|
||||
/** @var array */
|
||||
protected static $m_aExtensionClasses = array();
|
||||
/** @var array */
|
||||
protected static $m_aExtensionClassNames = [];
|
||||
|
||||
/**
|
||||
* @param string $sToInclude
|
||||
@@ -7185,99 +7222,11 @@ abstract class MetaModel
|
||||
return $aResult;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated 2.5.0 It is not recommended to use this function: call {@link MetaModel::GetLinkClasses} instead !
|
||||
* The only difference with EnumLinkingClasses is the output format
|
||||
*
|
||||
* @see MetaModel::GetLinkClasses
|
||||
* @return string[] classes having at least two external keys (thus too many classes as compared to GetLinkClasses)
|
||||
*
|
||||
*/
|
||||
public static function EnumLinksClasses()
|
||||
{
|
||||
// Returns a flat array of classes having at least two external keys
|
||||
$aResult = array();
|
||||
foreach(self::$m_aAttribDefs as $sSomeClass => $aClassAttributes)
|
||||
{
|
||||
$iExtKeyCount = 0;
|
||||
foreach($aClassAttributes as $sAttCode => $oAttDef)
|
||||
{
|
||||
if (self::$m_aAttribOrigins[$sSomeClass][$sAttCode] != $sSomeClass)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if ($oAttDef->IsExternalKey())
|
||||
{
|
||||
$iExtKeyCount++;
|
||||
}
|
||||
}
|
||||
if ($iExtKeyCount >= 2)
|
||||
{
|
||||
$aResult[] = $sSomeClass;
|
||||
}
|
||||
}
|
||||
return $aResult;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated 2.5.0 It is not recommended to use this function: call {@link MetaModel::GetLinkClasses} instead !
|
||||
* The only difference with EnumLinksClasses is the output format
|
||||
*
|
||||
* @see MetaModel::GetLinkClasses
|
||||
*
|
||||
*@param string $sClass
|
||||
*
|
||||
* @return string[] classes having at least two external keys (thus too many classes as compared to GetLinkClasses)
|
||||
* @throws \CoreException
|
||||
*
|
||||
*/
|
||||
public static function EnumLinkingClasses($sClass = "")
|
||||
{
|
||||
// N-N links, array of sLinkClass => (array of sAttCode=>sClass)
|
||||
$aResult = array();
|
||||
foreach(self::EnumLinksClasses() as $sSomeClass)
|
||||
{
|
||||
$aTargets = array();
|
||||
$bFoundClass = false;
|
||||
foreach(self::ListAttributeDefs($sSomeClass) as $sAttCode => $oAttDef)
|
||||
{
|
||||
if (self::$m_aAttribOrigins[$sSomeClass][$sAttCode] != $sSomeClass)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if ($oAttDef->IsExternalKey())
|
||||
{
|
||||
$sRemoteClass = $oAttDef->GetTargetClass();
|
||||
if (empty($sClass))
|
||||
{
|
||||
$aTargets[$sAttCode] = $sRemoteClass;
|
||||
}
|
||||
elseif ($sClass == $sRemoteClass)
|
||||
{
|
||||
$bFoundClass = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
$aTargets[$sAttCode] = $sRemoteClass;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (empty($sClass) || $bFoundClass)
|
||||
{
|
||||
$aResult[$sSomeClass] = $aTargets;
|
||||
}
|
||||
}
|
||||
return $aResult;
|
||||
}
|
||||
|
||||
/**
|
||||
* Using GetLinkClasses is the recommended way to determine if a class is
|
||||
* actually an N-N relation because it is based on the decision made by the
|
||||
* designer the data model
|
||||
*
|
||||
* This function has two siblings that will be soon deprecated:
|
||||
* {@link MetaModel::EnumLinkingClasses} and {@link MetaModel::EnumLinkClasses}
|
||||
*
|
||||
* @return array (target class => (external key code => target class))
|
||||
* @throws \CoreException
|
||||
*/
|
||||
@@ -7423,25 +7372,9 @@ abstract class MetaModel
|
||||
*/
|
||||
public static function EnumPlugins($sInterface, $sFilterInstanceOf = null)
|
||||
{
|
||||
if (!array_key_exists($sInterface, self::$m_aExtensionClasses))
|
||||
{
|
||||
return array();
|
||||
}
|
||||
$pluginManager = new PluginManager(self::$m_aExtensionClassNames);
|
||||
|
||||
if (is_null($sFilterInstanceOf))
|
||||
{
|
||||
return self::$m_aExtensionClasses[$sInterface];
|
||||
}
|
||||
|
||||
$fFilterCallback = function ($instance) use ($sFilterInstanceOf)
|
||||
{
|
||||
return $instance instanceof $sFilterInstanceOf;
|
||||
};
|
||||
|
||||
return array_filter(
|
||||
self::$m_aExtensionClasses[$sInterface],
|
||||
$fFilterCallback
|
||||
);
|
||||
return $pluginManager->EnumPlugins($sInterface, $sFilterInstanceOf);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -7452,16 +7385,9 @@ abstract class MetaModel
|
||||
*/
|
||||
public static function GetPlugins($sInterface, $sClassName)
|
||||
{
|
||||
$oInstance = null;
|
||||
if (array_key_exists($sInterface, self::$m_aExtensionClasses))
|
||||
{
|
||||
if (array_key_exists($sClassName, self::$m_aExtensionClasses[$sInterface]))
|
||||
{
|
||||
return self::$m_aExtensionClasses[$sInterface][$sClassName];
|
||||
}
|
||||
}
|
||||
$pluginManager = new PluginManager(self::$m_aExtensionClassNames);
|
||||
|
||||
return $oInstance;
|
||||
return $pluginManager->GetPlugins($sInterface, $sClassName);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -31,7 +31,7 @@ class ExpressionHelper {
|
||||
*
|
||||
* @uses \DBSearch::AllowAllData()
|
||||
*
|
||||
* @since 2.7.2 2.8.0 N°3324
|
||||
* @since 2.7.2 3.0.0 N°3324
|
||||
*/
|
||||
public static function ExpressionAllowAllDataCallback($oExpression, $bAllowAllData) {
|
||||
if (!($oExpression instanceof NestedQueryExpression)) {
|
||||
@@ -42,6 +42,9 @@ class ExpressionHelper {
|
||||
}
|
||||
}
|
||||
|
||||
class NotYetEvaluatedExpression extends CoreException
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* @method Check($oModelReflection, array $aAliases, $sSourceQuery)
|
||||
@@ -129,6 +132,47 @@ abstract class Expression {
|
||||
*/
|
||||
abstract public function RenderExpression($bForSQL = false, &$aArgs = null, $bRetrofitParams = false);
|
||||
|
||||
/**
|
||||
* Collect parameters, i.e. :parameter
|
||||
*
|
||||
* @param null $sParentFilter
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function GetParameters($sParentFilter = null)
|
||||
{
|
||||
$aParameters = array();
|
||||
$unused = $this->RenderExpression(false, $aParameters, true);
|
||||
|
||||
if (!is_null($sParentFilter)) $sParentFilter .= '->';
|
||||
|
||||
$aRet = array();
|
||||
foreach($aParameters as $sParameter => $unused)
|
||||
{
|
||||
if (is_null($sParentFilter))
|
||||
{
|
||||
$aRet[] = $sParameter;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (substr($sParameter, 0, strlen($sParentFilter)) == $sParentFilter)
|
||||
{
|
||||
$aRet[] = substr($sParameter, strlen($sParentFilter));
|
||||
}
|
||||
}
|
||||
}
|
||||
return $aRet;
|
||||
}
|
||||
|
||||
/**
|
||||
* Evaluate the value of the expression
|
||||
*
|
||||
* @param array $aArgs
|
||||
*
|
||||
* @throws \Exception if terms cannot be evaluated as scalars
|
||||
*/
|
||||
abstract public function Evaluate(array $aArgs);
|
||||
|
||||
/**
|
||||
* Recursively renders the expression as a structure (array) suitable for a JSON export
|
||||
*
|
||||
@@ -345,6 +389,16 @@ class SQLExpression extends Expression
|
||||
return $this->m_sSQL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Evaluate the value of the expression
|
||||
* @param array $aArgs
|
||||
* @throws \Exception if terms cannot be evaluated as scalars
|
||||
*/
|
||||
public function Evaluate(array $aArgs)
|
||||
{
|
||||
throw new Exception('a nested query cannot be evaluated');
|
||||
}
|
||||
|
||||
// recursive rendering
|
||||
public function toJSON(&$aArgs = null, $bRetrofitParams = false)
|
||||
{
|
||||
@@ -492,6 +546,149 @@ class BinaryExpression extends Expression
|
||||
return "($sLeft $sOperator $sRight)";
|
||||
}
|
||||
|
||||
/**
|
||||
* Evaluate the value of the expression
|
||||
* @param array $aArgs
|
||||
* @return mixed
|
||||
* @throws \Exception if terms cannot be evaluated as scalars
|
||||
*/
|
||||
public function Evaluate(array $aArgs)
|
||||
{
|
||||
$mLeft = $this->GetLeftExpr()->Evaluate($aArgs);
|
||||
$mRight = $this->GetRightExpr()->Evaluate($aArgs);
|
||||
|
||||
$sOperator = $this->GetOperator();
|
||||
$sType = null;
|
||||
switch($sOperator)
|
||||
{
|
||||
case '+':
|
||||
case '-':
|
||||
case '*':
|
||||
case '/':
|
||||
$sType = 'maths';
|
||||
break;
|
||||
case '=':
|
||||
case '!=':
|
||||
case '<>':
|
||||
$sType = 'comp';
|
||||
break;
|
||||
case '>':
|
||||
case '>=':
|
||||
case '<':
|
||||
case '<=':
|
||||
$sType = 'numcomp';
|
||||
break;
|
||||
case 'OR':
|
||||
case 'AND':
|
||||
$sType = 'logical';
|
||||
break;
|
||||
case 'LIKE':
|
||||
$sType = 'like';
|
||||
break;
|
||||
default:
|
||||
throw new Exception("Operator '$sOperator' not yet supported");
|
||||
}
|
||||
switch ($sType){
|
||||
case 'logical':
|
||||
$bLeft = static::CastToBool($mLeft);
|
||||
$bRight = static::CastToBool($mRight);
|
||||
switch ($sOperator)
|
||||
{
|
||||
case 'OR':
|
||||
$result = (int)($bLeft || $bRight);
|
||||
break;
|
||||
case 'AND':
|
||||
$result = (int)($bLeft && $bRight);
|
||||
break;
|
||||
default:
|
||||
throw new Exception("Logic: unknown operator '$sOperator'");
|
||||
}
|
||||
break;
|
||||
|
||||
case 'maths':
|
||||
$iLeft = (int) $mLeft;
|
||||
$iRight = (int) $mRight;
|
||||
switch ($sOperator)
|
||||
{
|
||||
case '+' : $result = $iLeft + $iRight; break;
|
||||
case '-' : $result = $iLeft - $iRight; break;
|
||||
case '*' : $result = $iLeft * $iRight; break;
|
||||
case '/' : $result = $iLeft / $iRight; break;
|
||||
default:
|
||||
throw new Exception("Logic: unknown operator '$sOperator'");
|
||||
}
|
||||
break;
|
||||
case 'comp':
|
||||
$left = $mLeft;
|
||||
$right = $mRight;
|
||||
switch ($sOperator)
|
||||
{
|
||||
case '=' : $result = ($left == $right); break;
|
||||
case '!=' : $result = ($left != $right); break;
|
||||
case '<>' : $result = ($left != $right); break;
|
||||
default:
|
||||
throw new Exception("Logic: unknown operator '$sOperator'");
|
||||
}
|
||||
break;
|
||||
case 'numcomp':
|
||||
$iLeft = static::ComparableValue($mLeft);
|
||||
$iRight = static::ComparableValue($mRight);
|
||||
switch ($sOperator)
|
||||
{
|
||||
case '=' : $result = ($iLeft == $iRight); break;
|
||||
case '>' : $result = ($iLeft > $iRight); break;
|
||||
case '<' : $result = ($iLeft < $iRight); break;
|
||||
case '>=' : $result = ($iLeft >= $iRight); break;
|
||||
case '<=' : $result = ($iLeft <= $iRight); break;
|
||||
case '!=' : $result = ($iLeft != $iRight); break;
|
||||
case '<>' : $result = ($iLeft != $iRight); break;
|
||||
default:
|
||||
throw new Exception("Logic: unknown operator '$sOperator'");
|
||||
}
|
||||
break;
|
||||
case 'like':
|
||||
$sEscaped = preg_quote($mRight, '/');
|
||||
$sEscaped = str_replace(array('%', '_', '\\\\.*', '\\\\.'), array('.*', '.', '%', '_'), $sEscaped);
|
||||
$result = (int) preg_match("/$sEscaped/i", $mLeft);
|
||||
break;
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
static protected function CastToBool($mValue)
|
||||
{
|
||||
if (is_string($mValue))
|
||||
{
|
||||
if (is_numeric($mValue))
|
||||
{
|
||||
return abs($mValue) > 0;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return (bool)$mValue;
|
||||
}
|
||||
static protected function ComparableValue($mixed)
|
||||
{
|
||||
if (is_string($mixed))
|
||||
{
|
||||
$oDate = new \DateTime($mixed);
|
||||
if (($oDate->format('Y-m-d') == $mixed) || ($oDate->format('Y-m-d H:i:s') == $mixed))
|
||||
{
|
||||
$iRet = $oDate->format('U');
|
||||
}
|
||||
else
|
||||
{
|
||||
$iRet = (int) $mixed;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$iRet = $mixed;
|
||||
}
|
||||
|
||||
return $iRet;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
* @throws \MissingQueryArgument
|
||||
@@ -894,6 +1091,16 @@ class MatchExpression extends BinaryExpression
|
||||
return $sRet;
|
||||
}
|
||||
|
||||
/**
|
||||
* Evaluate the value of the expression
|
||||
* @param array $aArgs
|
||||
* @throws \Exception if terms cannot be evaluated as scalars
|
||||
*/
|
||||
public function Evaluate(array $aArgs)
|
||||
{
|
||||
throw new Exception('evaluation of MATCHES not implemented yet');
|
||||
}
|
||||
|
||||
public function Translate($aTranslationData, $bMatchAll = true, $bMarkFieldsAsResolved = true)
|
||||
{
|
||||
/** @var \FieldExpression $oLeft */
|
||||
@@ -932,6 +1139,16 @@ class UnaryExpression extends Expression
|
||||
return CMDBSource::Quote($this->m_value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Evaluate the value of the expression
|
||||
* @param array $aArgs
|
||||
* @throws \Exception if terms cannot be evaluated as scalars
|
||||
*/
|
||||
public function Evaluate(array $aArgs)
|
||||
{
|
||||
return $this->m_value;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
* @throws \MissingQueryArgument
|
||||
@@ -1078,6 +1295,16 @@ class ScalarExpression extends UnaryExpression
|
||||
return $sRet;
|
||||
}
|
||||
|
||||
/**
|
||||
* Evaluate the value of the expression
|
||||
* @param array $aArgs
|
||||
* @throws \Exception if terms cannot be evaluated as scalars
|
||||
*/
|
||||
public function Evaluate(array $aArgs)
|
||||
{
|
||||
return $this->m_value;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
* @see Expression::ToJSON()
|
||||
@@ -1386,6 +1613,21 @@ class FieldExpression extends UnaryExpression
|
||||
return "`{$this->m_sParent}`.`{$this->m_sName}`";
|
||||
}
|
||||
|
||||
/**
|
||||
* Evaluate the value of the expression
|
||||
* @param array $aArgs
|
||||
* @throws \Exception if terms cannot be evaluated as scalars
|
||||
*/
|
||||
public function Evaluate(array $aArgs)
|
||||
{
|
||||
$sKey = empty($this->m_sParent) ? $this->m_sName : "{$this->m_sParent}.{$this->m_sName}";
|
||||
if (!array_key_exists($sKey, $aArgs))
|
||||
{
|
||||
throw new Exception("Missing field '$sKey' from context");
|
||||
}
|
||||
return $aArgs[$sKey];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
* @see Expression::ToJSON()
|
||||
@@ -1441,7 +1683,8 @@ class FieldExpression extends UnaryExpression
|
||||
|
||||
public function ListRequiredFields()
|
||||
{
|
||||
return array($this->m_sParent.'.'.$this->m_sName);
|
||||
$sField = empty($this->m_sParent) ? $this->m_sName : "{$this->m_sParent}.{$this->m_sName}";
|
||||
return array($sField);
|
||||
}
|
||||
|
||||
public function CollectUsedParents(&$aTable)
|
||||
@@ -1822,6 +2065,16 @@ class VariableExpression extends UnaryExpression
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Evaluate the value of the expression
|
||||
* @param array $aArgs
|
||||
* @throws \Exception if terms cannot be evaluated as scalars
|
||||
*/
|
||||
public function Evaluate(array $aArgs)
|
||||
{
|
||||
throw new Exception('not implemented yet');
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
* @see Expression::ToJSON()
|
||||
@@ -1962,6 +2215,16 @@ class ListExpression extends Expression
|
||||
return '('.implode(', ', $aRes).')';
|
||||
}
|
||||
|
||||
/**
|
||||
* Evaluate the value of the expression
|
||||
* @param array $aArgs
|
||||
* @throws \Exception if terms cannot be evaluated as scalars
|
||||
*/
|
||||
public function Evaluate(array $aArgs)
|
||||
{
|
||||
throw new Exception('list expression not yet supported');
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
* @see Expression::ToJSON()
|
||||
@@ -2177,6 +2440,16 @@ class NestedQueryExpression extends Expression
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Evaluate the value of the expression
|
||||
* @param array $aArgs
|
||||
* @throws \Exception if terms cannot be evaluated as scalars
|
||||
*/
|
||||
public function Evaluate(array $aArgs)
|
||||
{
|
||||
throw new Exception('a nested query cannot be evaluated');
|
||||
}
|
||||
|
||||
public function Browse(Closure $callback)
|
||||
{
|
||||
$callback($this);
|
||||
@@ -2279,6 +2552,252 @@ class FunctionExpression extends Expression
|
||||
return $this->m_sVerb.'('.implode(', ', $aRes).')';
|
||||
}
|
||||
|
||||
/**
|
||||
* Evaluate the value of the expression
|
||||
* @param array $aArgs
|
||||
* @throws \Exception if terms cannot be evaluated as scalars
|
||||
*/
|
||||
public function Evaluate(array $aArgs)
|
||||
{
|
||||
switch($this->m_sVerb)
|
||||
{
|
||||
case 'CONCAT':
|
||||
$sRet = '';
|
||||
foreach ($this->m_aArgs as $iPos => $oExpr)
|
||||
{
|
||||
$item = $oExpr->Evaluate($aArgs);
|
||||
if (is_null($item)) return null;
|
||||
$sRet .= $item;
|
||||
}
|
||||
return $sRet;
|
||||
|
||||
case 'CONCAT_WS':
|
||||
if (count($this->m_aArgs) < 3)
|
||||
{
|
||||
throw new \Exception("Function {$this->m_sVerb} requires at least 3 arguments");
|
||||
}
|
||||
$sSeparator = $this->m_aArgs[0]->Evaluate($aArgs);
|
||||
foreach ($this->m_aArgs as $iPos => $oExpr)
|
||||
{
|
||||
if ($iPos == 0) continue;
|
||||
$item = $oExpr->Evaluate($aArgs);
|
||||
if (is_null($item)) return null;
|
||||
$aStrings[] = $item;
|
||||
}
|
||||
$sRet = implode($sSeparator, $aStrings);
|
||||
return $sRet;
|
||||
|
||||
case 'SUBSTR':
|
||||
if (count($this->m_aArgs) < 2)
|
||||
{
|
||||
throw new \Exception("Function {$this->m_sVerb} requires at least 2 arguments");
|
||||
}
|
||||
$sString = $this->m_aArgs[0]->Evaluate($aArgs);
|
||||
$iRawPos = $this->m_aArgs[1]->Evaluate($aArgs);
|
||||
$iPos = $iRawPos > 0 ?
|
||||
$iRawPos - 1// 0-based in PHP (1-based in SQL)
|
||||
: $iRawPos; // Negative
|
||||
if (count($this->m_aArgs) == 2)
|
||||
{
|
||||
// Up to the end of the string
|
||||
$sRet = substr($sString, $iPos);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Length specified
|
||||
$iLen = $this->m_aArgs[2]->Evaluate($aArgs);
|
||||
$sRet = substr($sString, $iPos, $iLen);
|
||||
}
|
||||
return $sRet;
|
||||
|
||||
case 'TRIM':
|
||||
if (count($this->m_aArgs) != 1)
|
||||
{
|
||||
throw new \Exception("Function {$this->m_sVerb} requires 1 argument");
|
||||
}
|
||||
$sRet = trim($this->m_aArgs[0]->Evaluate($aArgs));
|
||||
return $sRet;
|
||||
|
||||
case 'INET_ATON':
|
||||
if (count($this->m_aArgs) != 1)
|
||||
{
|
||||
throw new \Exception("Function {$this->m_sVerb} requires 1 argument");
|
||||
}
|
||||
$sRet = ip2long($this->m_aArgs[0]->Evaluate($aArgs));
|
||||
return $sRet;
|
||||
|
||||
case 'INET_NTOA':
|
||||
if (count($this->m_aArgs) != 1)
|
||||
{
|
||||
throw new \Exception("Function {$this->m_sVerb} requires 1 argument");
|
||||
}
|
||||
$sRet = long2ip($this->m_aArgs[0]->Evaluate($aArgs));
|
||||
return $sRet;
|
||||
|
||||
case 'ISNULL':
|
||||
if (count($this->m_aArgs) != 1)
|
||||
{
|
||||
throw new \Exception("Function {$this->m_sVerb} requires 1 argument");
|
||||
}
|
||||
$sRet = is_null($this->m_aArgs[0]->Evaluate($aArgs));
|
||||
return $sRet;
|
||||
|
||||
case 'COALESCE':
|
||||
if (count($this->m_aArgs) < 1)
|
||||
{
|
||||
throw new \Exception("Function {$this->m_sVerb} requires at least 1 argument");
|
||||
}
|
||||
$ret = null;
|
||||
foreach($this->m_aArgs as $iPos => $oExpr)
|
||||
{
|
||||
$ret = $oExpr->Evaluate($aArgs);
|
||||
if (!is_null($ret)) break;
|
||||
}
|
||||
return $ret;
|
||||
|
||||
case 'IF':
|
||||
if (count($this->m_aArgs) != 3)
|
||||
{
|
||||
throw new \Exception("Function {$this->m_sVerb} requires 3 arguments");
|
||||
}
|
||||
$bCond = $this->m_aArgs[0]->Evaluate($aArgs);
|
||||
if ($bCond)
|
||||
{
|
||||
$ret = $this->m_aArgs[1]->Evaluate($aArgs);
|
||||
}
|
||||
else
|
||||
{
|
||||
$ret = $this->m_aArgs[2]->Evaluate($aArgs);
|
||||
}
|
||||
return $ret;
|
||||
|
||||
case 'ELT':
|
||||
if (count($this->m_aArgs) < 2)
|
||||
{
|
||||
throw new \Exception("Function {$this->m_sVerb} requires at least 2 arguments");
|
||||
}
|
||||
// First argument is the 1-based position
|
||||
$iPosition = (int) $this->m_aArgs[0]->Evaluate($aArgs);
|
||||
if (($iPosition == 0) || ($iPosition >= count($this->m_aArgs)))
|
||||
{
|
||||
// Out of range
|
||||
$ret = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
$ret = $this->m_aArgs[$iPosition]->Evaluate($aArgs);
|
||||
}
|
||||
return $ret;
|
||||
|
||||
case 'DATE':
|
||||
if (count($this->m_aArgs) != 1)
|
||||
{
|
||||
throw new \Exception("Function {$this->m_sVerb} requires 1 argument");
|
||||
}
|
||||
$sRet = date('Y-m-d', strtotime($this->m_aArgs[0]->Evaluate($aArgs)));
|
||||
return $sRet;
|
||||
|
||||
case 'YEAR':
|
||||
if (count($this->m_aArgs) != 1)
|
||||
{
|
||||
throw new \Exception("Function {$this->m_sVerb} requires 1 argument");
|
||||
}
|
||||
$iRet = (int) date('Y', strtotime($this->m_aArgs[0]->Evaluate($aArgs)));
|
||||
return $iRet;
|
||||
|
||||
case 'MONTH':
|
||||
if (count($this->m_aArgs) != 1)
|
||||
{
|
||||
throw new \Exception("Function {$this->m_sVerb} requires 1 argument");
|
||||
}
|
||||
$iRet = (int) date('m', strtotime($this->m_aArgs[0]->Evaluate($aArgs)));
|
||||
return $iRet;
|
||||
|
||||
case 'DAY':
|
||||
if (count($this->m_aArgs) != 1)
|
||||
{
|
||||
throw new \Exception("Function {$this->m_sVerb} requires 1 argument");
|
||||
}
|
||||
$iRet = (int) date('d', strtotime($this->m_aArgs[0]->Evaluate($aArgs)));
|
||||
return $iRet;
|
||||
|
||||
case 'DATE_FORMAT':
|
||||
if (count($this->m_aArgs) != 2)
|
||||
{
|
||||
throw new \Exception("Function {$this->m_sVerb} requires 2 arguments");
|
||||
}
|
||||
$oDate = new DateTime($this->m_aArgs[0]->Evaluate($aArgs));
|
||||
$sFormat = $this->m_aArgs[1]->Evaluate($aArgs);
|
||||
$sFormat = str_replace(
|
||||
array('%y', '%x', '%w', '%W', '%v', '%T', '%S', '%r', '%p', '%M', '%l', '%k', '%I', '%h', '%b', '%a', '%D', '%c', '%e', '%Y', '%d', '%m', '%H', '%i', '%s'),
|
||||
array('y', 'o', 'w', 'l', 'W', 'H:i:s', 's', 'h:i:s A', 'A', 'F', 'g', 'H', 'h', 'h','M', 'D', 'jS', 'n', 'j', 'Y', 'd', 'm', 'H', 'i', 's'),
|
||||
$sFormat);
|
||||
if (preg_match('/%j/', $sFormat))
|
||||
{
|
||||
$sFormat = str_replace('%j', date_format($oDate, 'z') + 1, $sFormat);
|
||||
}
|
||||
if (preg_match('/%[fUuVX]/', $sFormat))
|
||||
{
|
||||
throw new NotYetEvaluatedExpression("Expression ".$this->RenderExpression().' cannot be evaluated (known limitation)');
|
||||
}
|
||||
$sRet = date_format($oDate, $sFormat);
|
||||
return $sRet;
|
||||
|
||||
case 'TO_DAYS':
|
||||
if (count($this->m_aArgs) != 1)
|
||||
{
|
||||
throw new \Exception("Function {$this->m_sVerb} requires 1 argument");
|
||||
}
|
||||
$oDate = new DateTime($this->m_aArgs[0]->Evaluate($aArgs));
|
||||
$oZero = new DateTime('1582-01-01');
|
||||
$iRet = (int) $oDate->diff($oZero)->format('%a') + 577815;
|
||||
return $iRet;
|
||||
|
||||
case 'FROM_DAYS':
|
||||
if (count($this->m_aArgs) != 1)
|
||||
{
|
||||
throw new \Exception("Function {$this->m_sVerb} requires 1 argument");
|
||||
}
|
||||
$iSince1582 = $this->m_aArgs[0]->Evaluate($aArgs) - 577814;
|
||||
$oDate = new DateTime("1582-01-01 +$iSince1582 days");
|
||||
$sRet = $oDate->format('Y-m-d');
|
||||
return $sRet;
|
||||
|
||||
case 'NOW':
|
||||
$sRet = date('Y-m-d H:i:s');
|
||||
return $sRet;
|
||||
|
||||
case 'CURRENT_DATE':
|
||||
$sRet = date('Y-m-d');
|
||||
return $sRet;
|
||||
|
||||
case 'DATE_ADD':
|
||||
if (count($this->m_aArgs) != 2)
|
||||
{
|
||||
throw new \Exception("Function {$this->m_sVerb} requires 2 arguments");
|
||||
}
|
||||
$sStartDate = $this->m_aArgs[0]->Evaluate($aArgs);
|
||||
$sInterval = $this->m_aArgs[1]->Evaluate($aArgs);
|
||||
$oDate = new DateTime("$sStartDate +$sInterval");
|
||||
$sRet = $oDate->format('Y-m-d H:i:s');
|
||||
return $sRet;
|
||||
|
||||
case 'DATE_SUB':
|
||||
if (count($this->m_aArgs) != 2)
|
||||
{
|
||||
throw new \Exception("Function {$this->m_sVerb} requires 2 arguments");
|
||||
}
|
||||
$sStartDate = $this->m_aArgs[0]->Evaluate($aArgs);
|
||||
$sInterval = $this->m_aArgs[1]->Evaluate($aArgs);
|
||||
$oDate = new DateTime("$sStartDate -$sInterval");
|
||||
$sRet = $oDate->format('Y-m-d H:i:s');
|
||||
return $sRet;
|
||||
|
||||
default:
|
||||
throw new Exception("Function {$this->m_sVerb} cannot be evaluated -unhandled yet");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
* @see Expression::ToJSON()
|
||||
@@ -2605,6 +3124,17 @@ class IntervalExpression extends Expression
|
||||
return 'INTERVAL '.$this->m_oValue->RenderExpression($bForSQL, $aArgs, $bRetrofitParams).' '.$this->m_sUnit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Evaluate the value of the expression
|
||||
* @param array $aArgs
|
||||
* @throws \Exception if terms cannot be evaluated as scalars
|
||||
*/
|
||||
public function Evaluate(array $aArgs)
|
||||
{
|
||||
$iValue = $this->m_oValue->Evaluate($aArgs);
|
||||
return "$iValue {$this->m_sUnit}";
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
* @see Expression::ToJSON()
|
||||
@@ -2723,6 +3253,21 @@ class CharConcatExpression extends Expression
|
||||
return "CAST(CONCAT(".implode(', ', $aRes).") AS CHAR)";
|
||||
}
|
||||
|
||||
/**
|
||||
* Evaluate the value of the expression
|
||||
* @param array $aArgs
|
||||
* @throws \Exception if terms cannot be evaluated as scalars
|
||||
*/
|
||||
public function Evaluate(array $aArgs)
|
||||
{
|
||||
$sRet = '';
|
||||
foreach ($this->m_aExpressions as $oExpr)
|
||||
{
|
||||
$sRet .= $oExpr->Evaluate($aArgs);
|
||||
}
|
||||
return $sRet;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
* @see Expression::ToJSON()
|
||||
@@ -2864,6 +3409,21 @@ class CharConcatWSExpression extends CharConcatExpression
|
||||
return "CAST(CONCAT_WS($sSep, ".implode(', ', $aRes).") AS CHAR)";
|
||||
}
|
||||
|
||||
/**
|
||||
* Evaluate the value of the expression
|
||||
* @param array $aArgs
|
||||
* @throws \Exception if terms cannot be evaluated as scalars
|
||||
*/
|
||||
public function Evaluate(array $aArgs)
|
||||
{
|
||||
$aRes = array();
|
||||
foreach ($this->m_aExpressions as $oExpr)
|
||||
{
|
||||
$aRes .= $oExpr->Evaluate($aArgs);
|
||||
}
|
||||
return implode($this->m_separator, $aRes);
|
||||
}
|
||||
|
||||
public function Browse(Closure $callback)
|
||||
{
|
||||
$callback($this);
|
||||
|
||||
@@ -30,6 +30,9 @@ require_once('dbobjectiterator.php');
|
||||
|
||||
class ormLinkSet implements iDBObjectSetIterator, Iterator, SeekableIterator
|
||||
{
|
||||
const LINK_ALIAS = 'Link';
|
||||
const REMOTE_ALIAS = 'Remote';
|
||||
|
||||
protected $sHostClass; // subclass of DBObject
|
||||
protected $sAttCode; // xxxxxx_list
|
||||
protected $sClass; // class of the links
|
||||
@@ -786,11 +789,13 @@ class ormLinkSet implements iDBObjectSetIterator, Iterator, SeekableIterator
|
||||
/**
|
||||
* @param bool $bShowObsolete
|
||||
*
|
||||
* @return \DBObjectSet
|
||||
* @return \DBObjectSet indirect relations will get `SELECT L,R ...` (l = lnk class, R = remote)
|
||||
* @throws \CoreException
|
||||
* @throws \CoreWarning
|
||||
* @throws \MySQLException
|
||||
* @throws \Exception
|
||||
*
|
||||
* @since 3.0.0 N°2334 returns both lnk and remote classes for indirect relations
|
||||
*/
|
||||
public function ToDBObjectSet($bShowObsolete = true)
|
||||
{
|
||||
@@ -802,7 +807,12 @@ class ormLinkSet implements iDBObjectSetIterator, Iterator, SeekableIterator
|
||||
$sExtKeyToRemote = $oAttDef->GetExtKeyToRemote();
|
||||
/** @var \AttributeExternalKey $oLinkingAttDef */
|
||||
$oLinkingAttDef = MetaModel::GetAttributeDef($this->sClass, $sExtKeyToRemote);
|
||||
|
||||
// N°2334 add pointed class (SELECT L,R) to have all fields (lnk + remote) in display
|
||||
// the pointed class is always present in the search, as generated by \AttributeLinkedSet::GetDefaultValue
|
||||
$sTargetClass = $oLinkingAttDef->GetTargetClass();
|
||||
$oRemoteClassSearch = new DBObjectSearch($sTargetClass);
|
||||
|
||||
if (!$bShowObsolete && MetaModel::IsObsoletable($sTargetClass))
|
||||
{
|
||||
$oNotObsolete = new BinaryExpression(
|
||||
@@ -810,10 +820,9 @@ class ormLinkSet implements iDBObjectSetIterator, Iterator, SeekableIterator
|
||||
'=',
|
||||
new ScalarExpression(0)
|
||||
);
|
||||
$oNotObsoleteRemote = new DBObjectSearch($sTargetClass);
|
||||
$oNotObsoleteRemote->AddConditionExpression($oNotObsolete);
|
||||
$oLinkSearch->AddCondition_PointingTo($oNotObsoleteRemote, $sExtKeyToRemote);
|
||||
$oRemoteClassSearch->AddConditionExpression($oNotObsolete);
|
||||
}
|
||||
|
||||
if (!utils::IsArchiveMode() && MetaModel::IsArchivable($sTargetClass))
|
||||
{
|
||||
$oNotArchived = new BinaryExpression(
|
||||
@@ -821,10 +830,14 @@ class ormLinkSet implements iDBObjectSetIterator, Iterator, SeekableIterator
|
||||
'=',
|
||||
new ScalarExpression(0)
|
||||
);
|
||||
$oNotArchivedRemote = new DBObjectSearch($sTargetClass);
|
||||
$oNotArchivedRemote->AddConditionExpression($oNotArchived);
|
||||
$oLinkSearch->AddCondition_PointingTo($oNotArchivedRemote, $sExtKeyToRemote);
|
||||
|
||||
$oRemoteClassSearch->AddConditionExpression($oNotArchived);
|
||||
}
|
||||
|
||||
$oLinkSearch->AddCondition_PointingTo($oRemoteClassSearch, $sExtKeyToRemote);
|
||||
$oLinkSearch->RenameAlias($oLinkSearch->GetClassAlias(), self::LINK_ALIAS);
|
||||
$oLinkSearch->RenameAlias($sTargetClass, self::REMOTE_ALIAS);
|
||||
$oLinkSearch->SetSelectedClasses([self::LINK_ALIAS, self::REMOTE_ALIAS]);
|
||||
}
|
||||
$oLinkSet = new DBObjectSet($oLinkSearch);
|
||||
$oLinkSet->SetShowObsoleteData($bShowObsolete);
|
||||
|
||||
30
core/plugininstanciationmanager.class.inc.php
Normal file
30
core/plugininstanciationmanager.class.inc.php
Normal file
@@ -0,0 +1,30 @@
|
||||
<?php
|
||||
/**
|
||||
* @copyright Copyright (C) 2010-2020 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
|
||||
class PluginInstanciationManager
|
||||
{
|
||||
public function InstantiatePlugins($m_aExtensionClassNames, $sInterface)
|
||||
{
|
||||
$newPerInstanceClasses = array();
|
||||
if (array_key_exists($sInterface, $m_aExtensionClassNames))
|
||||
{
|
||||
foreach ($m_aExtensionClassNames[$sInterface] as $sClassName)
|
||||
{
|
||||
if (class_exists($sClassName))
|
||||
{
|
||||
$class = new ReflectionClass($sClassName);
|
||||
|
||||
if ($class->isInstantiable())
|
||||
{
|
||||
$newPerInstanceClasses[$sClassName] = new $sClassName();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return $newPerInstanceClasses;
|
||||
}
|
||||
}
|
||||
105
core/pluginmanager.class.inc.php
Normal file
105
core/pluginmanager.class.inc.php
Normal file
@@ -0,0 +1,105 @@
|
||||
<?php
|
||||
/**
|
||||
* @copyright Copyright (C) 2010-2020 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
|
||||
class PluginManager
|
||||
{
|
||||
|
||||
private $m_aExtensionClassNames;
|
||||
private static $m_aExtensionClasses;
|
||||
private $m_pluginInstantiationManager;
|
||||
|
||||
public function __construct($m_aExtensionClassNames, $m_pluginInstanciationManager = null)
|
||||
{
|
||||
if (is_null(self::$m_aExtensionClasses)) {
|
||||
self::$m_aExtensionClasses = [];
|
||||
}
|
||||
$this->m_aExtensionClassNames = $m_aExtensionClassNames;
|
||||
|
||||
if ($m_pluginInstanciationManager == null)
|
||||
{
|
||||
$this->m_pluginInstantiationManager = new PluginInstanciationManager();
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->m_pluginInstantiationManager = $m_pluginInstanciationManager;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $sInterface
|
||||
* @param bool $bCanInstantiatePlugins internal use, let this value to true
|
||||
* @param string|null $sFilterInstanceOf [optional] if given, only instance of this string will be returned
|
||||
*
|
||||
* @return array classes=>instance implementing the given interface
|
||||
*/
|
||||
public function EnumPlugins($sInterface, $sFilterInstanceOf = null, $bCanInstantiatePlugins = true)
|
||||
{
|
||||
$aPlugins = array();
|
||||
if (array_key_exists($sInterface, self::$m_aExtensionClasses))
|
||||
{
|
||||
$aAllPlugins = array_values(self::$m_aExtensionClasses[$sInterface]);
|
||||
|
||||
if (is_null($sFilterInstanceOf))
|
||||
{
|
||||
return $aAllPlugins;
|
||||
};
|
||||
|
||||
$aPlugins = array();
|
||||
foreach ($aAllPlugins as $instance)
|
||||
{
|
||||
if ($instance instanceof $sFilterInstanceOf)
|
||||
{
|
||||
$aPlugins[] = $instance;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if ($bCanInstantiatePlugins && array_key_exists($sInterface, $this->m_aExtensionClassNames))
|
||||
{
|
||||
$this->InstantiatePlugins($sInterface);
|
||||
|
||||
return $this->EnumPlugins($sInterface, $sFilterInstanceOf, false);
|
||||
}
|
||||
}
|
||||
return $aPlugins;
|
||||
}
|
||||
|
||||
public function InstantiatePlugins($sInterface)
|
||||
{
|
||||
self::$m_aExtensionClasses[$sInterface] = $this->m_pluginInstantiationManager->InstantiatePlugins($this->m_aExtensionClassNames, $sInterface);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $sInterface
|
||||
* @param string $sClassName
|
||||
* @param bool $bCanInstantiatePlugins internal use, let this value to true
|
||||
*
|
||||
* @return mixed the instance of the specified plug-ins for the given interface
|
||||
*/
|
||||
public function GetPlugins($sInterface, $sClassName, $bCanInstantiatePlugins = true)
|
||||
{
|
||||
$oInstance = null;
|
||||
if (array_key_exists($sInterface, self::$m_aExtensionClasses))
|
||||
{
|
||||
if (array_key_exists($sClassName, self::$m_aExtensionClasses[$sInterface]))
|
||||
{
|
||||
return self::$m_aExtensionClasses[$sInterface][$sClassName];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if ($bCanInstantiatePlugins && array_key_exists($sInterface, $this->m_aExtensionClassNames))
|
||||
{
|
||||
$this->InstantiatePlugins($sInterface);
|
||||
return $this->GetPlugins($sInterface, $sClassName, false);
|
||||
}
|
||||
}
|
||||
|
||||
return $oInstance;
|
||||
}
|
||||
}
|
||||
@@ -472,7 +472,7 @@ class RelationGraph extends SimpleGraph
|
||||
{
|
||||
do
|
||||
{
|
||||
set_time_limit($iLoopTimeLimit);
|
||||
set_time_limit(intval($iLoopTimeLimit));
|
||||
|
||||
$sObjectRef = RelationObjectNode::MakeId($oRelatedObj);
|
||||
$oRelatedNode = $this->GetNode($sObjectRef);
|
||||
@@ -501,7 +501,7 @@ class RelationGraph extends SimpleGraph
|
||||
while ($oRelatedObj = $oObjSet->Fetch());
|
||||
}
|
||||
}
|
||||
set_time_limit($iPreviousTimeLimit);
|
||||
set_time_limit(intval($iPreviousTimeLimit));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -467,6 +467,18 @@ class CoreServices implements iRestServiceProvider
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!$bExtendedOutput && RestUtils::GetOptionalParam($aParams, 'output_fields', '*') != '*')
|
||||
{
|
||||
$aFields = $aShowFields[$sClass];
|
||||
//Id is not a valid attribute to optimize
|
||||
if (in_array('id', $aFields))
|
||||
{
|
||||
unset($aFields[array_search('id', $aFields)]);
|
||||
}
|
||||
$aAttToLoad = array($oObjectSet->GetClassAlias() => $aFields);
|
||||
$oObjectSet->OptimizeColumnLoad($aAttToLoad);
|
||||
}
|
||||
|
||||
while ($oObject = $oObjectSet->Fetch())
|
||||
{
|
||||
$oResult->AddObject(0, '', $oObject, $aShowFields, $bExtendedOutput);
|
||||
|
||||
@@ -266,7 +266,7 @@ EOF
|
||||
$iLoopTimeLimit = MetaModel::GetConfig()->Get('max_execution_time_per_loop');
|
||||
while($aRow = $oSet->FetchAssoc())
|
||||
{
|
||||
set_time_limit($iLoopTimeLimit);
|
||||
set_time_limit(intval($iLoopTimeLimit));
|
||||
|
||||
$sData .= "<tr>";
|
||||
foreach($this->aStatusInfo['fields'] as $iCol => $aFieldSpec)
|
||||
@@ -362,7 +362,7 @@ EOF
|
||||
$sData .= "</tr>";
|
||||
$iCount++;
|
||||
}
|
||||
set_time_limit($iPreviousTimeLimit);
|
||||
set_time_limit(intval($iPreviousTimeLimit));
|
||||
$this->aStatusInfo['position'] += $this->iChunkSize;
|
||||
if ($this->aStatusInfo['total'] == 0)
|
||||
{
|
||||
|
||||
@@ -50,7 +50,6 @@ abstract class Trigger extends cmdbAbstractObject
|
||||
"db_table" => "priv_trigger",
|
||||
"db_key_field" => "id",
|
||||
"db_finalclass_field" => "realclass",
|
||||
"display_template" => "",
|
||||
);
|
||||
MetaModel::Init_Params($aParams);
|
||||
//MetaModel::Init_InheritAttributes();
|
||||
@@ -168,7 +167,6 @@ abstract class TriggerOnObject extends Trigger
|
||||
"db_table" => "priv_trigger_onobject",
|
||||
"db_key_field" => "id",
|
||||
"db_finalclass_field" => "",
|
||||
"display_template" => "",
|
||||
);
|
||||
MetaModel::Init_Params($aParams);
|
||||
MetaModel::Init_InheritAttributes();
|
||||
@@ -295,7 +293,6 @@ class TriggerOnPortalUpdate extends TriggerOnObject
|
||||
"db_table" => "priv_trigger_onportalupdate",
|
||||
"db_key_field" => "id",
|
||||
"db_finalclass_field" => "",
|
||||
"display_template" => "",
|
||||
);
|
||||
MetaModel::Init_Params($aParams);
|
||||
MetaModel::Init_InheritAttributes();
|
||||
@@ -328,7 +325,6 @@ abstract class TriggerOnStateChange extends TriggerOnObject
|
||||
"db_table" => "priv_trigger_onstatechange",
|
||||
"db_key_field" => "id",
|
||||
"db_finalclass_field" => "",
|
||||
"display_template" => "",
|
||||
);
|
||||
MetaModel::Init_Params($aParams);
|
||||
MetaModel::Init_InheritAttributes();
|
||||
@@ -363,7 +359,6 @@ class TriggerOnStateEnter extends TriggerOnStateChange
|
||||
"db_table" => "priv_trigger_onstateenter",
|
||||
"db_key_field" => "id",
|
||||
"db_finalclass_field" => "",
|
||||
"display_template" => "",
|
||||
);
|
||||
MetaModel::Init_Params($aParams);
|
||||
MetaModel::Init_InheritAttributes();
|
||||
@@ -397,7 +392,6 @@ class TriggerOnStateLeave extends TriggerOnStateChange
|
||||
"db_table" => "priv_trigger_onstateleave",
|
||||
"db_key_field" => "id",
|
||||
"db_finalclass_field" => "",
|
||||
"display_template" => "",
|
||||
);
|
||||
MetaModel::Init_Params($aParams);
|
||||
MetaModel::Init_InheritAttributes();
|
||||
@@ -431,7 +425,6 @@ class TriggerOnObjectCreate extends TriggerOnObject
|
||||
"db_table" => "priv_trigger_onobjcreate",
|
||||
"db_key_field" => "id",
|
||||
"db_finalclass_field" => "",
|
||||
"display_template" => "",
|
||||
);
|
||||
MetaModel::Init_Params($aParams);
|
||||
MetaModel::Init_InheritAttributes();
|
||||
@@ -465,7 +458,6 @@ class TriggerOnObjectDelete extends TriggerOnObject
|
||||
"db_table" => "priv_trigger_onobjdelete",
|
||||
"db_key_field" => "id",
|
||||
"db_finalclass_field" => "",
|
||||
"display_template" => "",
|
||||
);
|
||||
MetaModel::Init_Params($aParams);
|
||||
MetaModel::Init_InheritAttributes();
|
||||
@@ -500,7 +492,6 @@ class TriggerOnObjectUpdate extends TriggerOnObject
|
||||
"db_table" => "priv_trigger_onobjupdate",
|
||||
"db_key_field" => "id",
|
||||
"db_finalclass_field" => "",
|
||||
"display_template" => "",
|
||||
);
|
||||
MetaModel::Init_Params($aParams);
|
||||
MetaModel::Init_InheritAttributes();
|
||||
@@ -593,7 +584,6 @@ class lnkTriggerAction extends cmdbAbstractObject
|
||||
"db_table" => "priv_link_action_trigger",
|
||||
"db_key_field" => "link_id",
|
||||
"db_finalclass_field" => "",
|
||||
"display_template" => "",
|
||||
"is_link" => true,
|
||||
);
|
||||
MetaModel::Init_Params($aParams);
|
||||
@@ -633,7 +623,6 @@ class TriggerOnThresholdReached extends TriggerOnObject
|
||||
"db_table" => "priv_trigger_threshold",
|
||||
"db_key_field" => "id",
|
||||
"db_finalclass_field" => "",
|
||||
"display_template" => "",
|
||||
);
|
||||
MetaModel::Init_Params($aParams);
|
||||
MetaModel::Init_InheritAttributes();
|
||||
|
||||
@@ -45,25 +45,85 @@ define('UR_ACTION_APPLICATION_DEFINED', 10000); // Application specific actions
|
||||
*/
|
||||
abstract class UserRightsAddOnAPI
|
||||
{
|
||||
/**
|
||||
* @param string $sAdminUser
|
||||
* @param string $sAdminPwd
|
||||
* @param string $sLanguage
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
abstract public function CreateAdministrator($sAdminUser, $sAdminPwd, $sLanguage = 'EN US'); // could be used during initial installation
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
abstract public function Init(); // loads data (possible optimizations)
|
||||
|
||||
// Used to build select queries showing only objects visible for the given user
|
||||
/**
|
||||
* Used to build select queries showing only objects visible for the given user
|
||||
*
|
||||
* @param string $sLogin
|
||||
* @param string $sClass
|
||||
* @param array $aSettings
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
abstract public function GetSelectFilter($sLogin, $sClass, $aSettings = array()); // returns a filter object
|
||||
|
||||
abstract public function IsActionAllowed($oUser, $sClass, $iActionCode, /*dbObjectSet*/ $oInstanceSet = null);
|
||||
abstract public function IsStimulusAllowed($oUser, $sClass, $sStimulusCode, /*dbObjectSet*/ $oInstanceSet = null);
|
||||
abstract public function IsActionAllowedOnAttribute($oUser, $sClass, $sAttCode, $iActionCode, /*dbObjectSet*/ $oInstanceSet = null);
|
||||
abstract public function IsAdministrator($oUser);
|
||||
abstract public function IsPortalUser($oUser);
|
||||
abstract public function FlushPrivileges();
|
||||
/**
|
||||
* @param \User $oUser
|
||||
* @param string $sClass
|
||||
* @param int $iActionCode
|
||||
* @param null $oInstanceSet
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
abstract public function IsActionAllowed($oUser, $sClass, $iActionCode, $oInstanceSet = null);
|
||||
|
||||
/**
|
||||
* @param \User $oUser
|
||||
* @param string $sClass
|
||||
* @param string $sStimulusCode
|
||||
* @param \DBObjectSet|null $oInstanceSet
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
abstract public function IsStimulusAllowed($oUser, $sClass, $sStimulusCode, $oInstanceSet = null);
|
||||
|
||||
/**
|
||||
* @param \User $oUser
|
||||
* @param string $sClass
|
||||
* @param string $sAttCode
|
||||
* @param int $iActionCode
|
||||
* @param \DBObjectSet|null $oInstanceSet
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
abstract public function IsActionAllowedOnAttribute($oUser, $sClass, $sAttCode, $iActionCode, $oInstanceSet = null);
|
||||
|
||||
/**
|
||||
* @param \User $oUser
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
abstract public function IsAdministrator($oUser);
|
||||
|
||||
/**
|
||||
* @param \User $oUser
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
abstract public function IsPortalUser($oUser);
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
abstract public function FlushPrivileges();
|
||||
|
||||
/**
|
||||
* Default behavior for addons that do not support profiles
|
||||
*
|
||||
* @param $oUser User
|
||||
* @param \User $oUser
|
||||
* @return array
|
||||
*/
|
||||
public function ListProfiles($oUser)
|
||||
@@ -72,7 +132,18 @@ abstract class UserRightsAddOnAPI
|
||||
}
|
||||
|
||||
/**
|
||||
* ...
|
||||
* ...
|
||||
*
|
||||
* @param string$sClass
|
||||
* @param array $aAllowedOrgs
|
||||
* @param array $aSettings
|
||||
* @param string|null $sAttCode
|
||||
*
|
||||
* @return \DBObjectSearch
|
||||
* @throws \CoreException
|
||||
* @throws \MissingQueryArgument
|
||||
* @throws \MySQLException
|
||||
* @throws \MySQLHasGoneAwayException
|
||||
*/
|
||||
public function MakeSelectFilter($sClass, $aAllowedOrgs, $aSettings = array(), $sAttCode = null)
|
||||
{
|
||||
@@ -156,6 +227,9 @@ abstract class UserRightsAddOnAPI
|
||||
require_once(APPROOT.'/application/cmdbabstract.class.inc.php');
|
||||
abstract class User extends cmdbAbstractObject
|
||||
{
|
||||
/**
|
||||
* @throws \CoreException
|
||||
*/
|
||||
public static function Init()
|
||||
{
|
||||
$aParams = array
|
||||
@@ -168,7 +242,6 @@ abstract class User extends cmdbAbstractObject
|
||||
"db_table" => "priv_user",
|
||||
"db_key_field" => "id",
|
||||
"db_finalclass_field" => "",
|
||||
"display_template" => "",
|
||||
);
|
||||
MetaModel::Init_Params($aParams);
|
||||
//MetaModel::Init_InheritAttributes();
|
||||
@@ -202,7 +275,11 @@ abstract class User extends cmdbAbstractObject
|
||||
|
||||
/*
|
||||
* Compute a name in best effort mode
|
||||
*/
|
||||
*
|
||||
* @return string
|
||||
* @throws \ArchivedObjectException
|
||||
* @throws \CoreException
|
||||
*/
|
||||
public function GetFriendlyName()
|
||||
{
|
||||
if (!MetaModel::IsValidAttCode(get_class($this), 'contactid'))
|
||||
@@ -230,6 +307,32 @@ abstract class User extends cmdbAbstractObject
|
||||
return $this->Get('login');
|
||||
}
|
||||
|
||||
/*
|
||||
* Compute the initials in best effort mode
|
||||
*
|
||||
* @return string
|
||||
* @throws \ArchivedObjectException
|
||||
* @throws \CoreException
|
||||
* @since 3.0.0
|
||||
*/
|
||||
public function GetInitials()
|
||||
{
|
||||
$sInitials = '';
|
||||
|
||||
if (MetaModel::IsValidAttCode(get_class($this), 'contactid') && ($this->Get('contactid') != 0))
|
||||
{
|
||||
$sInitials .= mb_substr($this->Get('first_name'), 0, 1);
|
||||
$sInitials .= mb_substr($this->Get('last_name'), 0, 1);
|
||||
}
|
||||
|
||||
if (empty($sInitials))
|
||||
{
|
||||
$sInitials = mb_substr($this->Get('login'), 0, 1);
|
||||
}
|
||||
|
||||
return $sInitials;
|
||||
}
|
||||
|
||||
protected $oContactObject;
|
||||
|
||||
/**
|
||||
@@ -409,25 +512,23 @@ abstract class User extends cmdbAbstractObject
|
||||
function DisplayBareRelations(WebPage $oPage, $bEditMode = false)
|
||||
{
|
||||
parent::DisplayBareRelations($oPage, $bEditMode);
|
||||
if (!$bEditMode)
|
||||
{
|
||||
$oPage->SetCurrentTab('UI:UserManagement:GrantMatrix');
|
||||
$this->DoShowGrantSumary($oPage, 'bizmodel,grant_by_profile');
|
||||
|
||||
// debug
|
||||
if (false)
|
||||
{
|
||||
$oPage->SetCurrentTab('More on user rigths (dev only)');
|
||||
$oPage->add("<h3>User rights</h3>\n");
|
||||
$this->DoShowGrantSumary($oPage, 'addon/userrights');
|
||||
$oPage->add("<h3>Change log</h3>\n");
|
||||
$this->DoShowGrantSumary($oPage, 'core/cmdb');
|
||||
$oPage->add("<h3>Application</h3>\n");
|
||||
$this->DoShowGrantSumary($oPage, 'application');
|
||||
$oPage->add("<h3>GUI</h3>\n");
|
||||
$this->DoShowGrantSumary($oPage, 'gui');
|
||||
|
||||
}
|
||||
$oPage->SetCurrentTab('UI:UserManagement:GrantMatrix');
|
||||
$this->DoShowGrantSumary($oPage, 'bizmodel,grant_by_profile');
|
||||
|
||||
// debug
|
||||
if (false)
|
||||
{
|
||||
$oPage->SetCurrentTab('More on user rigths (dev only)');
|
||||
$oPage->add("<h3>User rights</h3>\n");
|
||||
$this->DoShowGrantSumary($oPage, 'addon/userrights');
|
||||
$oPage->add("<h3>Change log</h3>\n");
|
||||
$this->DoShowGrantSumary($oPage, 'core/cmdb');
|
||||
$oPage->add("<h3>Application</h3>\n");
|
||||
$this->DoShowGrantSumary($oPage, 'application');
|
||||
$oPage->add("<h3>GUI</h3>\n");
|
||||
$this->DoShowGrantSumary($oPage, 'gui');
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -570,25 +671,38 @@ interface iSelfRegister
|
||||
*/
|
||||
class UserRights
|
||||
{
|
||||
const DEFAULT_USER_CONTACT_ID_ATTCODE = 'contactid';
|
||||
const DEFAULT_CONTACT_ORG_ID_ATTCODE = 'org_id';
|
||||
const DEFAULT_CONTACT_ORG_ID_FRIENDLYNAME_ATTCODE = self::DEFAULT_CONTACT_ORG_ID_ATTCODE.'_friendlyname';
|
||||
const DEFAULT_CONTACT_FIRSTNAME_ATTCODE = 'first_name';
|
||||
const DEFAULT_CONTACT_PICTURE_ATTCODE = 'picture';
|
||||
|
||||
public static $m_aCacheUsers;
|
||||
/** @var UserRightsAddOnAPI $m_oAddOn */
|
||||
protected static $m_oAddOn;
|
||||
protected static $m_oUser;
|
||||
protected static $m_oRealUser;
|
||||
protected static $m_sSelfRegisterAddOn = null;
|
||||
protected static $m_aAdmins = array();
|
||||
protected static $m_aPortalUsers = array();
|
||||
/** @var array array('sName' => $sName, 'bSuccess' => $bSuccess); */
|
||||
private static $m_sLastLoginStatus = null;
|
||||
|
||||
/**
|
||||
* @param string $sModuleName
|
||||
*
|
||||
* @return void
|
||||
* @throws \CoreException
|
||||
*/
|
||||
public static function SelectModule($sModuleName)
|
||||
{
|
||||
if (!class_exists($sModuleName))
|
||||
{
|
||||
throw new CoreException("Could not select this module, '$sModuleName' in not a valid class name");
|
||||
return;
|
||||
}
|
||||
if (!is_subclass_of($sModuleName, 'UserRightsAddOnAPI'))
|
||||
{
|
||||
throw new CoreException("Could not select this module, the class '$sModuleName' is not derived from UserRightsAddOnAPI");
|
||||
return;
|
||||
}
|
||||
self::$m_oAddOn = new $sModuleName;
|
||||
self::$m_oAddOn->Init();
|
||||
@@ -596,6 +710,12 @@ class UserRights
|
||||
self::$m_oRealUser = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $sModuleName
|
||||
*
|
||||
* @return void
|
||||
* @throws \CoreException
|
||||
*/
|
||||
public static function SelectSelfRegister($sModuleName)
|
||||
{
|
||||
if (!class_exists($sModuleName))
|
||||
@@ -605,19 +725,33 @@ class UserRights
|
||||
self::$m_sSelfRegisterAddOn = $sModuleName;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \UserRightsAddOnAPI
|
||||
*/
|
||||
public static function GetModuleInstance()
|
||||
{
|
||||
return self::$m_oAddOn;
|
||||
}
|
||||
|
||||
// Installation: create the very first user
|
||||
/**
|
||||
* Installation: create the very first user
|
||||
*
|
||||
* @param string $sAdminUser
|
||||
* @param string $sAdminPwd
|
||||
* @param string $sLanguage
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function CreateAdministrator($sAdminUser, $sAdminPwd, $sLanguage = 'EN US')
|
||||
{
|
||||
$bRes = self::$m_oAddOn->CreateAdministrator($sAdminUser, $sAdminPwd, $sLanguage);
|
||||
self::FlushPrivileges(true /* reset admin cache */);
|
||||
return $bRes;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public static function IsLoggedIn()
|
||||
{
|
||||
if (self::$m_oUser == null)
|
||||
@@ -630,9 +764,17 @@ class UserRights
|
||||
}
|
||||
}
|
||||
|
||||
public static function Login($sName, $sAuthentication = 'any')
|
||||
/**
|
||||
* @param string $sLogin Login of the concerned user
|
||||
* @param string $sAuthentication
|
||||
*
|
||||
* @return bool
|
||||
* @throws \DictExceptionUnknownLanguage
|
||||
* @throws \OQLException
|
||||
*/
|
||||
public static function Login($sLogin, $sAuthentication = 'any')
|
||||
{
|
||||
$oUser = self::FindUser($sName, $sAuthentication);
|
||||
$oUser = self::FindUser($sLogin, $sAuthentication);
|
||||
if (is_null($oUser))
|
||||
{
|
||||
return false;
|
||||
@@ -649,38 +791,55 @@ class UserRights
|
||||
return true;
|
||||
}
|
||||
|
||||
public static function CheckCredentials($sName, $sPassword, $sLoginMode = 'form', $sAuthentication = 'any')
|
||||
/**
|
||||
* @param string $sLogin Login of the user to check the credentials for
|
||||
* @param string $sPassword
|
||||
* @param string $sLoginMode
|
||||
* @param string $sAuthentication
|
||||
*
|
||||
* @return bool
|
||||
* @throws \OQLException
|
||||
*/
|
||||
public static function CheckCredentials($sLogin, $sPassword, $sLoginMode = 'form', $sAuthentication = 'any')
|
||||
{
|
||||
$oUser = self::FindUser($sName, $sAuthentication);
|
||||
$oUser = self::FindUser($sLogin, $sAuthentication);
|
||||
if (is_null($oUser))
|
||||
{
|
||||
// Check if the user does not exist at all or if it is just disabled
|
||||
if (self::FindUser($sName, $sAuthentication, true) == null)
|
||||
if (self::FindUser($sLogin, $sAuthentication, true) == null)
|
||||
{
|
||||
// User does not exist at all
|
||||
$bCheckCredentialsAndCreateUser = self::CheckCredentialsAndCreateUser($sName, $sPassword, $sLoginMode, $sAuthentication);
|
||||
self::$m_sLastLoginStatus = array('sName' => $sName, 'bSuccess' => $bCheckCredentialsAndCreateUser);
|
||||
$bCheckCredentialsAndCreateUser = self::CheckCredentialsAndCreateUser($sLogin, $sPassword, $sLoginMode, $sAuthentication);
|
||||
self::$m_sLastLoginStatus = array('sName' => $sLogin, 'bSuccess' => $bCheckCredentialsAndCreateUser);
|
||||
return $bCheckCredentialsAndCreateUser;
|
||||
}
|
||||
else
|
||||
{
|
||||
// User is actually disabled
|
||||
self::$m_sLastLoginStatus = array('sName' => $sName, 'bSuccess' => false);
|
||||
self::$m_sLastLoginStatus = array('sName' => $sLogin, 'bSuccess' => false);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!$oUser->CheckCredentials($sPassword))
|
||||
{
|
||||
self::$m_sLastLoginStatus = array('sName' => $sName, 'bSuccess' => false);
|
||||
self::$m_sLastLoginStatus = array('sName' => $sLogin, 'bSuccess' => false);
|
||||
return false;
|
||||
}
|
||||
self::UpdateUser($oUser, $sLoginMode, $sAuthentication);
|
||||
self::$m_sLastLoginStatus = array('sName' => $sName, 'bSuccess' => true);
|
||||
self::$m_sLastLoginStatus = array('sName' => $sLogin, 'bSuccess' => true);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param string $sName
|
||||
* @param string $sPassword
|
||||
* @param string $sLoginMode
|
||||
* @param string $sAuthentication
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public static function CheckCredentialsAndCreateUser($sName, $sPassword, $sLoginMode, $sAuthentication)
|
||||
{
|
||||
if (self::$m_sSelfRegisterAddOn != null)
|
||||
@@ -689,6 +848,11 @@ class UserRights
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \User $oUser
|
||||
* @param string $sLoginMode
|
||||
* @param string $sAuthentication
|
||||
*/
|
||||
public static function UpdateUser($oUser, $sLoginMode, $sAuthentication)
|
||||
{
|
||||
if (self::$m_sSelfRegisterAddOn != null)
|
||||
@@ -696,7 +860,10 @@ class UserRights
|
||||
call_user_func(array(self::$m_sSelfRegisterAddOn, 'UpdateUser'), $oUser, $sLoginMode, $sAuthentication);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public static function TrustWebServerContext()
|
||||
{
|
||||
if (!is_null(self::$m_oUser))
|
||||
@@ -711,9 +878,11 @@ class UserRights
|
||||
|
||||
/**
|
||||
* Tells whether or not the archive mode is allowed to the current user
|
||||
* @return boolean
|
||||
*
|
||||
* @return bool
|
||||
* @throws \CoreException
|
||||
*/
|
||||
static function CanBrowseArchive()
|
||||
public static function CanBrowseArchive()
|
||||
{
|
||||
if (is_null(self::$m_oUser))
|
||||
{
|
||||
@@ -732,6 +901,9 @@ class UserRights
|
||||
return $bRet;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public static function CanChangePassword()
|
||||
{
|
||||
if (MetaModel::DBIsReadOnly())
|
||||
@@ -749,16 +921,24 @@ class UserRights
|
||||
}
|
||||
}
|
||||
|
||||
public static function ChangePassword($sOldPassword, $sNewPassword, $sName = '')
|
||||
/**
|
||||
* @param string $sOldPassword
|
||||
* @param string $sNewPassword
|
||||
* @param string $sLogin Login of the concerned user
|
||||
*
|
||||
* @return bool
|
||||
* @throws \OQLException
|
||||
*/
|
||||
public static function ChangePassword($sOldPassword, $sNewPassword, $sLogin = '')
|
||||
{
|
||||
if (empty($sName))
|
||||
if (empty($sLogin))
|
||||
{
|
||||
$oUser = self::$m_oUser;
|
||||
}
|
||||
else
|
||||
{
|
||||
// find the id out of the login string
|
||||
$oUser = self::FindUser($sName);
|
||||
$oUser = self::FindUser($sLogin);
|
||||
}
|
||||
if (is_null($oUser))
|
||||
{
|
||||
@@ -772,15 +952,18 @@ class UserRights
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $sName Login identifier of the user to impersonate
|
||||
* @param string $sLogin Login identifier of the user to impersonate
|
||||
*
|
||||
* @return bool True if an impersonation occurred
|
||||
* @throws \DictExceptionUnknownLanguage
|
||||
* @throws \OQLException
|
||||
*/
|
||||
public static function Impersonate($sName)
|
||||
public static function Impersonate($sLogin)
|
||||
{
|
||||
if (!self::CheckLogin()) return false;
|
||||
|
||||
$bRet = false;
|
||||
$oUser = self::FindUser($sName);
|
||||
$oUser = self::FindUser($sLogin);
|
||||
if ($oUser)
|
||||
{
|
||||
$bRet = true;
|
||||
@@ -799,13 +982,16 @@ class UserRights
|
||||
// Do impersonate!
|
||||
self::$m_oUser = $oUser;
|
||||
Dict::SetUserLanguage(self::GetUserLanguage());
|
||||
$_SESSION['impersonate_user'] = $sName;
|
||||
$_SESSION['impersonate_user'] = $sLogin;
|
||||
self::_ResetSessionCache();
|
||||
}
|
||||
}
|
||||
return $bRet;
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws \DictExceptionUnknownLanguage
|
||||
*/
|
||||
public static function Deimpersonate()
|
||||
{
|
||||
if (!is_null(self::$m_oRealUser))
|
||||
@@ -817,6 +1003,11 @@ class UserRights
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the current user login or an empty string if nobody connected.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function GetUser()
|
||||
{
|
||||
if (is_null(self::$m_oUser))
|
||||
@@ -829,7 +1020,9 @@ class UserRights
|
||||
}
|
||||
}
|
||||
|
||||
/** User */
|
||||
/**
|
||||
* @return \User|null
|
||||
*/
|
||||
public static function GetUserObject()
|
||||
{
|
||||
if (is_null(self::$m_oUser))
|
||||
@@ -841,7 +1034,10 @@ class UserRights
|
||||
return self::$m_oUser;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public static function GetUserLanguage()
|
||||
{
|
||||
if (is_null(self::$m_oUser))
|
||||
@@ -855,9 +1051,15 @@ class UserRights
|
||||
}
|
||||
}
|
||||
|
||||
public static function GetUserId($sName = '')
|
||||
/**
|
||||
* @param string $sLogin
|
||||
*
|
||||
* @return string|null
|
||||
* @throws \OQLException
|
||||
*/
|
||||
public static function GetUserId($sLogin = '')
|
||||
{
|
||||
if (empty($sName))
|
||||
if (empty($sLogin))
|
||||
{
|
||||
// return current user id
|
||||
if (is_null(self::$m_oUser))
|
||||
@@ -869,7 +1071,7 @@ class UserRights
|
||||
else
|
||||
{
|
||||
// find the id out of the login string
|
||||
$oUser = self::$m_oAddOn->FindUser($sName);
|
||||
$oUser = self::FindUser($sLogin);
|
||||
if (is_null($oUser))
|
||||
{
|
||||
return null;
|
||||
@@ -878,27 +1080,163 @@ class UserRights
|
||||
}
|
||||
}
|
||||
|
||||
public static function GetContactId($sName = '')
|
||||
/**
|
||||
* @param string $sLogin Login of the user from which we return the contact ID
|
||||
*
|
||||
* @return string
|
||||
* @throws \Exception
|
||||
*/
|
||||
public static function GetContactId($sLogin = '')
|
||||
{
|
||||
if (empty($sName))
|
||||
if (empty($sLogin))
|
||||
{
|
||||
$oUser = self::$m_oUser;
|
||||
}
|
||||
else
|
||||
{
|
||||
$oUser = FindUser($sName);
|
||||
$oUser = self::FindUser($sLogin);
|
||||
}
|
||||
if (is_null($oUser))
|
||||
{
|
||||
return '';
|
||||
}
|
||||
if (!MetaModel::IsValidAttCode(get_class($oUser), 'contactid'))
|
||||
if (!MetaModel::IsValidAttCode(get_class($oUser), static::DEFAULT_USER_CONTACT_ID_ATTCODE))
|
||||
{
|
||||
return '';
|
||||
}
|
||||
return $oUser->Get('contactid');
|
||||
return $oUser->Get(static::DEFAULT_USER_CONTACT_ID_ATTCODE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the absolute URL of the contact picture
|
||||
*
|
||||
* @param string $sLogin Login of the user from which we return the picture URL
|
||||
* @param bool $bAllowDefaultPicture Set to false if you want it to return null instead of the default picture URL when the contact has no picture defined. This can be useful when we want to display something else than the default picture (eg. initials)
|
||||
*
|
||||
* @return null|string
|
||||
* @throws \ArchivedObjectException
|
||||
* @throws \CoreException
|
||||
* @throws \Exception
|
||||
* @since 3.0.0
|
||||
*/
|
||||
public static function GetContactPictureAbsUrl($sLogin = '', $bAllowDefaultPicture = true)
|
||||
{
|
||||
// First, the default picture
|
||||
if($bAllowDefaultPicture === true)
|
||||
{
|
||||
$sPictureUrl = utils::GetAbsoluteUrlAppRoot().'images/user-pictures/' . 'user-profile-default-256px.png';
|
||||
}
|
||||
else
|
||||
{
|
||||
$sPictureUrl = null;
|
||||
}
|
||||
|
||||
// Then check if the user has a contact attached and if it has an picture defined
|
||||
$sContactId = UserRights::GetContactId($sLogin);
|
||||
if(!empty($sContactId))
|
||||
{
|
||||
$oContact = MetaModel::GetObject('Contact', $sContactId, false, true);
|
||||
$sContactClass = get_class($oContact);
|
||||
|
||||
// Check that Contact object still exists and that Contact class has a picture attribute
|
||||
if(!is_null($oContact) && MetaModel::IsValidAttCode($sContactClass, static::DEFAULT_CONTACT_PICTURE_ATTCODE))
|
||||
{
|
||||
/** @var \ormDocument $oPicture */
|
||||
$oPicture = $oContact->Get(static::DEFAULT_CONTACT_PICTURE_ATTCODE);
|
||||
if($oPicture->IsEmpty())
|
||||
{
|
||||
if($bAllowDefaultPicture === true)
|
||||
{
|
||||
/** @var \AttributeImage $oAttDef */
|
||||
$oAttDef = MetaModel::GetAttributeDef($sContactClass, static::DEFAULT_CONTACT_PICTURE_ATTCODE);
|
||||
$sPictureUrl = $oAttDef->Get('default_image');
|
||||
}
|
||||
else
|
||||
{
|
||||
$sPictureUrl = null;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (ContextTag::Check(ContextTag::TAG_PORTAL)) {
|
||||
$sPictureUrl = utils::GetAbsoluteUrlAppRoot().'pages/exec.php/object/document/display/'.$sContactClass.'/'.$oContact->GetKey().'/'.static::DEFAULT_CONTACT_PICTURE_ATTCODE.'?exec_module=itop-portal-base&exec_page=index.php&portal_id='.PORTAL_ID;
|
||||
}
|
||||
else {
|
||||
$sPictureUrl = $oPicture->GetDisplayURL($sContactClass, $oContact->GetKey(), static::DEFAULT_CONTACT_PICTURE_ATTCODE);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $sPictureUrl;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the organization name of the current user's contact.
|
||||
* If the user has no contact linked, null is returned.
|
||||
*
|
||||
* @return string|null
|
||||
* @throws \Exception
|
||||
* @since 3.0.0
|
||||
*/
|
||||
public static function GetContactOrganizationFriendlyname()
|
||||
{
|
||||
$sOrgFriendlyname = null;
|
||||
|
||||
$oContact = static::GetContactObject();
|
||||
if(!is_null($oContact) && MetaModel::IsValidAttCode(get_class($oContact), static::DEFAULT_CONTACT_ORG_ID_FRIENDLYNAME_ATTCODE))
|
||||
{
|
||||
$sOrgFriendlyname = $oContact->Get(static::DEFAULT_CONTACT_ORG_ID_FRIENDLYNAME_ATTCODE);
|
||||
}
|
||||
|
||||
return $sOrgFriendlyname;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the first name of the current user's contact.
|
||||
* If the user has no contact, null is returned.
|
||||
*
|
||||
* @return string|null
|
||||
* @throws \Exception
|
||||
* @since 3.0.0
|
||||
*/
|
||||
public static function GetContactFirstname()
|
||||
{
|
||||
$sFirstname = null;
|
||||
|
||||
$oContact = static::GetContactObject();
|
||||
if(!is_null($oContact) && MetaModel::IsValidAttCode(get_class($oContact), static::DEFAULT_CONTACT_FIRSTNAME_ATTCODE))
|
||||
{
|
||||
$sFirstname = $oContact->Get(static::DEFAULT_CONTACT_FIRSTNAME_ATTCODE);
|
||||
}
|
||||
|
||||
return $sFirstname;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the friendlyname of the current user's contact.
|
||||
* If the user has no contact, null is returned.
|
||||
*
|
||||
* @return string|null
|
||||
* @throws \Exception
|
||||
* @since 3.0.0
|
||||
*/
|
||||
public static function GetContactFriendlyname()
|
||||
{
|
||||
$sFriendlyname = null;
|
||||
|
||||
$oContact = static::GetContactObject();
|
||||
if(!is_null($oContact))
|
||||
{
|
||||
$sFriendlyname = $oContact->GetRawName();
|
||||
}
|
||||
|
||||
return $sFriendlyname;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \DBObject|null
|
||||
*/
|
||||
public static function GetContactObject()
|
||||
{
|
||||
if (is_null(self::$m_oUser))
|
||||
@@ -911,16 +1249,23 @@ class UserRights
|
||||
}
|
||||
}
|
||||
|
||||
// Render the user name in best effort mode
|
||||
public static function GetUserFriendlyName($sName = '')
|
||||
/**
|
||||
* Render the user name in best effort mode
|
||||
*
|
||||
* @param string $sLogin Login of the user we want to retrieve the friendlyname
|
||||
*
|
||||
* @return string
|
||||
* @throws \OQLException
|
||||
*/
|
||||
public static function GetUserFriendlyName($sLogin = '')
|
||||
{
|
||||
if (empty($sName))
|
||||
if (empty($sLogin))
|
||||
{
|
||||
$oUser = self::$m_oUser;
|
||||
}
|
||||
else
|
||||
{
|
||||
$oUser = FindUser($sName);
|
||||
$oUser = self::FindUser($sLogin);
|
||||
}
|
||||
if (is_null($oUser))
|
||||
{
|
||||
@@ -929,6 +1274,48 @@ class UserRights
|
||||
return $oUser->GetFriendlyName();
|
||||
}
|
||||
|
||||
/**
|
||||
* Render the user initials in best effort mode
|
||||
*
|
||||
* @param string $sLogin Login of the user from which we want to retrieve the initials
|
||||
*
|
||||
* @return string
|
||||
* @throws \OQLException
|
||||
* @since 3.0.0
|
||||
*/
|
||||
public static function GetUserInitials($sLogin = '')
|
||||
{
|
||||
if (empty($sLogin))
|
||||
{
|
||||
$oUser = self::$m_oUser;
|
||||
}
|
||||
else
|
||||
{
|
||||
$oUser = self::FindUser($sLogin);
|
||||
}
|
||||
if (is_null($oUser))
|
||||
{
|
||||
$sInitials = '';
|
||||
$aLoginParts = explode(' ', $sLogin);
|
||||
foreach($aLoginParts as $sLoginPart)
|
||||
{
|
||||
// Keep only upper case first letters
|
||||
// eg. "My first name My last name" => "MM"
|
||||
// eg. "Carrie Anne Moss" => "CAM"
|
||||
if(preg_match('/^\p{Lu}/u', $sLoginPart) > 0)
|
||||
{
|
||||
$sInitials .= mb_substr($sLoginPart, 0, 1);
|
||||
}
|
||||
}
|
||||
|
||||
return $sInitials;
|
||||
}
|
||||
return $oUser->GetInitials();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public static function IsImpersonated()
|
||||
{
|
||||
if (is_null(self::$m_oRealUser))
|
||||
@@ -938,6 +1325,9 @@ class UserRights
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public static function GetRealUser()
|
||||
{
|
||||
if (is_null(self::$m_oRealUser))
|
||||
@@ -947,11 +1337,17 @@ class UserRights
|
||||
return self::$m_oRealUser->Get('login');
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \User|null
|
||||
*/
|
||||
public static function GetRealUserObject()
|
||||
{
|
||||
return self::$m_oRealUser;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public static function GetRealUserId()
|
||||
{
|
||||
if (is_null(self::$m_oRealUser))
|
||||
@@ -961,6 +1357,9 @@ class UserRights
|
||||
return self::$m_oRealUser->GetKey();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public static function GetRealUserFriendlyName()
|
||||
{
|
||||
if (is_null(self::$m_oRealUser))
|
||||
@@ -970,6 +1369,9 @@ class UserRights
|
||||
return self::$m_oRealUser->GetFriendlyName();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
protected static function CheckLogin()
|
||||
{
|
||||
if (!self::IsLoggedIn())
|
||||
@@ -983,7 +1385,7 @@ class UserRights
|
||||
/**
|
||||
* Add additional filter for organization silos to all the requests.
|
||||
*
|
||||
* @param $sClass
|
||||
* @param string $sClass
|
||||
* @param array $aSettings
|
||||
*
|
||||
* @return bool|\Expression
|
||||
@@ -1015,11 +1417,13 @@ class UserRights
|
||||
/**
|
||||
* @param string $sClass
|
||||
* @param int $iActionCode
|
||||
* @param DBObjectSet $oInstanceSet
|
||||
* @param User $oUser
|
||||
* @param \DBObjectSet $oInstanceSet
|
||||
* @param \User $oUser
|
||||
*
|
||||
* @return int (UR_ALLOWED_YES|UR_ALLOWED_NO|UR_ALLOWED_DEPENDS)
|
||||
* @throws \CoreException
|
||||
*/
|
||||
public static function IsActionAllowed($sClass, $iActionCode, /*dbObjectSet*/$oInstanceSet = null, $oUser = null)
|
||||
public static function IsActionAllowed($sClass, $iActionCode, $oInstanceSet = null, $oUser = null)
|
||||
{
|
||||
// When initializing, we need to let everything pass trough
|
||||
if (!self::CheckLogin()) return UR_ALLOWED_YES;
|
||||
@@ -1071,6 +1475,15 @@ class UserRights
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $sClass
|
||||
* @param string $sStimulusCode
|
||||
* @param \DBObjectSet|null $oInstanceSet
|
||||
* @param \User|null $oUser
|
||||
*
|
||||
* @return bool
|
||||
* @throws \CoreException
|
||||
*/
|
||||
public static function IsStimulusAllowed($sClass, $sStimulusCode, /*dbObjectSet*/ $oInstanceSet = null, $oUser = null)
|
||||
{
|
||||
// When initializing, we need to let everything pass trough
|
||||
@@ -1102,9 +1515,11 @@ class UserRights
|
||||
* @param string $sClass
|
||||
* @param string $sAttCode
|
||||
* @param int $iActionCode
|
||||
* @param DBObjectSet $oInstanceSet
|
||||
* @param User $oUser
|
||||
* @param \DBObjectSet $oInstanceSet
|
||||
* @param \User $oUser
|
||||
*
|
||||
* @return int (UR_ALLOWED_YES|UR_ALLOWED_NO)
|
||||
* @throws \CoreException
|
||||
*/
|
||||
public static function IsActionAllowedOnAttribute($sClass, $sAttCode, $iActionCode, /*dbObjectSet*/$oInstanceSet = null, $oUser = null)
|
||||
{
|
||||
@@ -1139,7 +1554,11 @@ class UserRights
|
||||
|
||||
}
|
||||
|
||||
protected static $m_aAdmins = array();
|
||||
/**
|
||||
* @param \User|null $oUser
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function IsAdministrator($oUser = null)
|
||||
{
|
||||
if (!self::CheckLogin()) return false;
|
||||
@@ -1156,7 +1575,11 @@ class UserRights
|
||||
return self::$m_aAdmins[$iUser];
|
||||
}
|
||||
|
||||
protected static $m_aPortalUsers = array();
|
||||
/**
|
||||
* @param \User|null $oUser
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function IsPortalUser($oUser = null)
|
||||
{
|
||||
if (!self::CheckLogin()) return false;
|
||||
@@ -1173,6 +1596,9 @@ class UserRights
|
||||
return self::$m_aPortalUsers[$iUser];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public static function GetAllowedPortals()
|
||||
{
|
||||
$aAllowedPortals = array();
|
||||
@@ -1198,6 +1624,50 @@ class UserRights
|
||||
return $aAllowedPortals;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see UR_ACTION_READ, UR_ACTION_MODIFY, ...
|
||||
*
|
||||
* @param int $iActionCode
|
||||
* @param array $aCategories
|
||||
* @param bool $bWithLabels
|
||||
* @param \User|null $oUser
|
||||
*
|
||||
* @return array
|
||||
* @throws \DictExceptionMissingString
|
||||
* @throws \CoreException
|
||||
*/
|
||||
public static function GetAllowedClasses($iActionCode, $aCategories = array('bizmodel'), $bWithLabels = false, $oUser = null)
|
||||
{
|
||||
$aAllowedClasses = [];
|
||||
foreach(MetaModel::GetClasses(implode(',', $aCategories)) as $sClass)
|
||||
{
|
||||
if(static::IsActionAllowed($sClass, $iActionCode, null, $oUser) === UR_ALLOWED_YES)
|
||||
{
|
||||
if($bWithLabels)
|
||||
{
|
||||
$aAllowedClasses[$sClass] = MetaModel::GetName($sClass);
|
||||
}
|
||||
else
|
||||
{
|
||||
$aAllowedClasses[] = $sClass;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Sort by label
|
||||
if($bWithLabels)
|
||||
{
|
||||
asort($aAllowedClasses);
|
||||
}
|
||||
|
||||
return $aAllowedClasses;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \User|null $oUser
|
||||
*
|
||||
* @return array|mixed
|
||||
*/
|
||||
public static function ListProfiles($oUser = null)
|
||||
{
|
||||
if (is_null($oUser))
|
||||
@@ -1261,8 +1731,6 @@ class UserRights
|
||||
}
|
||||
}
|
||||
|
||||
static $m_aCacheUsers;
|
||||
|
||||
/**
|
||||
* Find a user based on its login and its type of authentication
|
||||
*
|
||||
@@ -1320,6 +1788,18 @@ class UserRights
|
||||
return $oUser;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string$sClass
|
||||
* @param array $aAllowedOrgs
|
||||
* @param array $aSettings
|
||||
* @param string|null $sAttCode
|
||||
*
|
||||
* @return \DBObjectSearch
|
||||
* @throws \CoreException
|
||||
* @throws \MissingQueryArgument
|
||||
* @throws \MySQLException
|
||||
* @throws \MySQLHasGoneAwayException
|
||||
*/
|
||||
public static function MakeSelectFilter($sClass, $aAllowedOrgs, $aSettings = array(), $sAttCode = null)
|
||||
{
|
||||
return self::$m_oAddOn->MakeSelectFilter($sClass, $aAllowedOrgs, $aSettings, $sAttCode);
|
||||
|
||||
@@ -141,7 +141,10 @@ class ValueSetObjects extends ValueSetDefinition
|
||||
$this->m_oExtraCondition = $oFilter;
|
||||
$this->m_bIsLoaded = false;
|
||||
}
|
||||
|
||||
public function SetOrderBy(array $aOrderBy)
|
||||
{
|
||||
$this->m_aOrderBy = $aOrderBy;
|
||||
}
|
||||
public function ToObjectSet($aArgs = array(), $sContains = '', $iAdditionalValue = null)
|
||||
{
|
||||
if ($this->m_bAllowAllData)
|
||||
@@ -217,7 +220,7 @@ class ValueSetObjects extends ValueSetDefinition
|
||||
$this->m_sOperation = $sOperation;
|
||||
|
||||
$this->m_aValues = array();
|
||||
|
||||
|
||||
if ($this->m_bAllowAllData)
|
||||
{
|
||||
$oFilter = DBObjectSearch::FromOQL_AllData($this->m_sFilterExpr);
|
||||
@@ -243,7 +246,7 @@ class ValueSetObjects extends ValueSetDefinition
|
||||
$oExpression = DBObjectSearch::GetPolymorphicExpression($oFilter->GetClass(), 'friendlyname');
|
||||
$aFields = $oExpression->ListRequiredFields();
|
||||
$sClass = $oFilter->GetClass();
|
||||
foreach($aFields as $sField)
|
||||
/*foreach($aFields as $sField)
|
||||
{
|
||||
$aFieldItems = explode('.', $sField);
|
||||
if ($aFieldItems[0] != $sClass)
|
||||
@@ -251,7 +254,7 @@ class ValueSetObjects extends ValueSetDefinition
|
||||
$sOperation = 'contains';
|
||||
break;
|
||||
}
|
||||
}
|
||||
}*/
|
||||
|
||||
switch ($sOperation)
|
||||
{
|
||||
@@ -345,6 +348,160 @@ class ValueSetObjects extends ValueSetDefinition
|
||||
{
|
||||
$this->m_bSort = $bSort;
|
||||
}
|
||||
|
||||
public function GetValuesForAutocomplete($aArgs, $sContains = '', $sOperation = 'contains')
|
||||
{
|
||||
if (!$this->m_bIsLoaded || ($sContains != $this->m_sContains) || ($sOperation != $this->m_sOperation))
|
||||
{
|
||||
$this->LoadValuesForAutocomplete($aArgs, $sContains, $sOperation);
|
||||
$this->m_bIsLoaded = true;
|
||||
}
|
||||
// The results are already filtered and sorted (on friendly name)
|
||||
$aRet = $this->m_aValues;
|
||||
return $aRet;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $aArgs
|
||||
* @param string $sContains
|
||||
* @param string $sOperation 'contains' or 'equals_start_with'
|
||||
*
|
||||
* @return bool
|
||||
* @throws \CoreException
|
||||
* @throws \OQLException
|
||||
*/
|
||||
protected function LoadValuesForAutocomplete($aArgs, $sContains = '', $sOperation = 'contains')
|
||||
{
|
||||
$this->m_sContains = $sContains;
|
||||
$this->m_sOperation = $sOperation;
|
||||
|
||||
$this->m_aValues = array();
|
||||
|
||||
if ($this->m_bAllowAllData)
|
||||
{
|
||||
$oFilter = DBObjectSearch::FromOQL_AllData($this->m_sFilterExpr);
|
||||
}
|
||||
else
|
||||
{
|
||||
$oFilter = DBObjectSearch::FromOQL($this->m_sFilterExpr);
|
||||
$oFilter->SetShowObsoleteData(utils::ShowObsoleteData());
|
||||
}
|
||||
|
||||
if (!$oFilter) return false;
|
||||
if (!is_null($this->m_oExtraCondition))
|
||||
{
|
||||
$oFilter = $oFilter->Intersect($this->m_oExtraCondition);
|
||||
}
|
||||
foreach($this->m_aModifierProperties as $sPluginClass => $aProperties)
|
||||
{
|
||||
foreach ($aProperties as $sProperty => $value)
|
||||
{
|
||||
$oFilter->SetModifierProperty($sPluginClass, $sProperty, $value);
|
||||
}
|
||||
}
|
||||
|
||||
//$oExpression = DBObjectSearch::GetPolymorphicExpression($oFilter->GetClass(), 'friendlyname');
|
||||
$sClass = $oFilter->GetClass();
|
||||
|
||||
switch ($sOperation)
|
||||
{
|
||||
case 'equals':
|
||||
$aAttributes = MetaModel::GetFriendlyNameAttributeCodeList($sClass);
|
||||
$sClassAlias = $oFilter->GetClassAlias();
|
||||
$aFilters = array();
|
||||
$oValueExpr = new ScalarExpression($sContains);
|
||||
foreach($aAttributes as $sAttribute)
|
||||
{
|
||||
$oNewFilter = $oFilter->DeepClone();
|
||||
$oNameExpr = new FieldExpression($sAttribute, $sClassAlias);
|
||||
$oCondition = new BinaryExpression($oNameExpr, '=', $oValueExpr);
|
||||
$oNewFilter->AddConditionExpression($oCondition);
|
||||
$aFilters[] = $oNewFilter;
|
||||
}
|
||||
// Unions are much faster than OR conditions
|
||||
$oFilter = new DBUnionSearch($aFilters);
|
||||
break;
|
||||
case 'start_with':
|
||||
$aAttributes = MetaModel::GetFriendlyNameAttributeCodeList($sClass);
|
||||
$sClassAlias = $oFilter->GetClassAlias();
|
||||
$aFilters = array();
|
||||
$oValueExpr = new ScalarExpression($sContains.'%');
|
||||
foreach($aAttributes as $sAttribute)
|
||||
{
|
||||
$oNewFilter = $oFilter->DeepClone();
|
||||
$oNameExpr = new FieldExpression($sAttribute, $sClassAlias);
|
||||
$oCondition = new BinaryExpression($oNameExpr, 'LIKE', $oValueExpr);
|
||||
$oNewFilter->AddConditionExpression($oCondition);
|
||||
$aFilters[] = $oNewFilter;
|
||||
}
|
||||
// Unions are much faster than OR conditions
|
||||
$oFilter = new DBUnionSearch($aFilters);
|
||||
break;
|
||||
|
||||
default:
|
||||
$oValueExpr = new ScalarExpression('%'.$sContains.'%');
|
||||
$oNameExpr = new FieldExpression('friendlyname', $oFilter->GetClassAlias());
|
||||
$oNewCondition = new BinaryExpression($oNameExpr, 'LIKE', $oValueExpr);
|
||||
$oFilter->AddConditionExpression($oNewCondition);
|
||||
break;
|
||||
}
|
||||
|
||||
$oObjects = new DBObjectSet($oFilter, $this->m_aOrderBy, $aArgs, null, $this->m_iLimit, 0, $this->m_bSort);
|
||||
if (empty($this->m_sValueAttCode))
|
||||
{
|
||||
$aAttToLoad = array($oFilter->GetClassAlias() => array('friendlyname'));
|
||||
}
|
||||
else
|
||||
{
|
||||
$aAttToLoad = array($oFilter->GetClassAlias() => array($this->m_sValueAttCode));
|
||||
}
|
||||
|
||||
$aComplementAttributeSpec = MetaModel::GetComplementAttributeSpec($sClass);
|
||||
$sFormatAdditionalField = $aComplementAttributeSpec[0];
|
||||
$aAdditionalField = $aComplementAttributeSpec[1];
|
||||
|
||||
if (count($aAdditionalField)>0)
|
||||
{
|
||||
$aAttToLoad = array_merge ($aAttToLoad, [$oFilter->GetClassAlias() => $aAdditionalField]);
|
||||
}
|
||||
|
||||
$oObjects->OptimizeColumnLoad($aAttToLoad);
|
||||
while ($oObject = $oObjects->Fetch())
|
||||
{
|
||||
$aData=[];
|
||||
if (empty($this->m_sValueAttCode))
|
||||
{
|
||||
$aData['label'] = $oObject->GetName();
|
||||
}
|
||||
else
|
||||
{
|
||||
$aData['label'] = $oObject->Get($this->m_sValueAttCode);
|
||||
}
|
||||
if($oObject->IsObsolete())
|
||||
{
|
||||
$aData['obsolescence_flag']='1';
|
||||
}
|
||||
else
|
||||
{
|
||||
$aData['obsolescence_flag']='0';
|
||||
}
|
||||
if (count($aAdditionalField)>0)
|
||||
{
|
||||
$aArguments = [];
|
||||
foreach ($aAdditionalField as $sAdditionalField)
|
||||
{
|
||||
array_push ($aArguments,$oObject->Get($sAdditionalField));
|
||||
}
|
||||
$aData['additional_field'] = vsprintf($sFormatAdditionalField, $aArguments);
|
||||
}
|
||||
else
|
||||
{
|
||||
$aData['additional_field']='';
|
||||
}
|
||||
$this->m_aValues[$oObject->GetKey()] = $aData;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -144,7 +144,7 @@ class XMLBulkExport extends BulkExport
|
||||
|
||||
while ($aObjects = $oSet->FetchAssoc())
|
||||
{
|
||||
set_time_limit($iLoopTimeLimit);
|
||||
set_time_limit(intval($iLoopTimeLimit));
|
||||
if (count($aAuthorizedClasses) > 1)
|
||||
{
|
||||
$sData .= "<Row>\n";
|
||||
@@ -182,7 +182,7 @@ class XMLBulkExport extends BulkExport
|
||||
$iCount++;
|
||||
}
|
||||
|
||||
set_time_limit($iPreviousTimeLimit);
|
||||
set_time_limit(intval($iPreviousTimeLimit));
|
||||
$this->aStatusInfo['position'] += $this->iChunkSize;
|
||||
if ($this->aStatusInfo['total'] == 0)
|
||||
{
|
||||
|
||||
5
css/README.md
Normal file
5
css/README.md
Normal file
@@ -0,0 +1,5 @@
|
||||
In order to better separate our developments from the embedded third-party libs, files should be moved in either the /backoffice, /lib or something new folders.
|
||||
|
||||
IMPORTANT: Before moving a file, we should first consider if:
|
||||
- The file is used in an iTop extension that should be compatible with the iTop version currently under developments
|
||||
- The file is still used in iTop itself (or if we can consider removing it for clean up)
|
||||
71
css/backoffice/README.md
Normal file
71
css/backoffice/README.md
Normal file
@@ -0,0 +1,71 @@
|
||||
## Description
|
||||
This is a brief description of the SASS 7-1 system and how to use it.
|
||||
- [File structure](#file-structure)
|
||||
- [Usage](#usage)
|
||||
|
||||
## File structure
|
||||
SCSS files are structured following the [7-1 pattern](https://sass-guidelin.es/#the-7-1-pattern). \
|
||||
@rveitch made a great summary with the following, which can also be found [here](https://gist.github.com/rveitch/84cea9650092119527bc).
|
||||
|
||||
```
|
||||
css/backoffice/
|
||||
|
|
||||
|– utils/
|
||||
| |– _variables.scss # Sass Variables
|
||||
| |– _functions.scss # Sass Functions
|
||||
| |– _mixins.scss # Sass Mixins
|
||||
| |– _helpers.scss # Class & placeholders helpers
|
||||
|
|
||||
|– vendors/
|
||||
| |– _bootstrap.scss # Bootstrap
|
||||
| |– _jquery-ui.scss # jQuery UI
|
||||
| ... # Etc…
|
||||
|
|
||||
|– base/
|
||||
| |– _reset.scss # Reset/normalize
|
||||
| |– _typography.scss # Typography rules
|
||||
| ... # Etc…
|
||||
|
|
||||
|– components/
|
||||
| |– _buttons.scss # Buttons
|
||||
| |– _carousel.scss # Carousel
|
||||
| |– _cover.scss # Cover
|
||||
| |– _dropdown.scss # Dropdown
|
||||
| ... # Etc…
|
||||
|
|
||||
|– layout/
|
||||
| |– _navigation.scss # Navigation
|
||||
| |– _grid.scss # Grid system
|
||||
| |– _header.scss # Header
|
||||
| |– _footer.scss # Footer
|
||||
| |– _sidebar.scss # Sidebar
|
||||
| |– _forms.scss # Forms
|
||||
| ... # Etc…
|
||||
|
|
||||
|– pages/
|
||||
| |– _home.scss # Home specific styles
|
||||
| |– _contact.scss # Contact specific styles
|
||||
| ... # Etc…
|
||||
|
|
||||
|– themes/
|
||||
| |– _theme.scss # Default theme
|
||||
| |– _admin.scss # Admin theme
|
||||
| ... # Etc…
|
||||
|
|
||||
|
|
||||
`– main.scss # Main Sass file
|
||||
```
|
||||
|
||||
## Usage
|
||||
To avoid common errors, files should be imported in the final file in the following order. Again those are just following the SASS guidelines:
|
||||
- Utils
|
||||
- Variables
|
||||
- Functions
|
||||
- Mixins
|
||||
- Helpers
|
||||
- Vendors
|
||||
- Base
|
||||
- Components
|
||||
- Layout
|
||||
- Pages
|
||||
- Themes
|
||||
20
css/backoffice/base/_all.scss
Normal file
20
css/backoffice/base/_all.scss
Normal file
@@ -0,0 +1,20 @@
|
||||
/*!
|
||||
* 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
|
||||
*/
|
||||
|
||||
@import "base";
|
||||
@import "typography";
|
||||
67
css/backoffice/base/_base.scss
Normal file
67
css/backoffice/base/_base.scss
Normal file
@@ -0,0 +1,67 @@
|
||||
/*!
|
||||
* 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
|
||||
*/
|
||||
|
||||
$ibo-hyperlink-color: $ibo-color-primary-500 !default;
|
||||
$ibo-hyperlink-color--on-hover: $ibo-color-primary-600 !default;
|
||||
$ibo-hyperlink-color--on-active: $ibo-color-primary-700 !default;
|
||||
|
||||
$ibo-svg-illustration--fill: $ibo-color-primary-500 !default;
|
||||
|
||||
$ibo-content-block--background-color: $ibo-color-white-100 !default;
|
||||
$ibo-content-block--border: 1px solid $ibo-color-grey-400 !default;
|
||||
|
||||
/* CSS variables */
|
||||
:root{
|
||||
--ibo-hyperlink-color: #{$ibo-hyperlink-color};
|
||||
--ibo-hyperlink-color--on-hover: #{$ibo-hyperlink-color--on-hover};
|
||||
--ibo-hyperlink-color--on-active: #{$ibo-hyperlink-color--on-active};
|
||||
}
|
||||
|
||||
/* Box sizing reset */
|
||||
*,
|
||||
*::before,
|
||||
*::after{
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
/* Base font size (used by all typographies) */
|
||||
html{
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
/* Hyperlinks reset, ensure that they are of the right color and without decoration everywhere (of course this can be overloaded in some components) */
|
||||
a{
|
||||
color: var(--ibo-hyperlink-color);
|
||||
text-decoration: none;
|
||||
|
||||
&:hover,
|
||||
&:active,
|
||||
&:visited{
|
||||
text-decoration: none;
|
||||
}
|
||||
&:hover{
|
||||
color: var(--ibo-hyperlink-color--on-hover);
|
||||
}
|
||||
&:active{
|
||||
color: var(--ibo-hyperlink-color--on-active);
|
||||
}
|
||||
}
|
||||
|
||||
.ibo-svg-illustration--container>svg *[fill="#6c63ff"]{
|
||||
fill: $ibo-svg-illustration--fill;
|
||||
}
|
||||
163
css/backoffice/base/_typography.scss
Normal file
163
css/backoffice/base/_typography.scss
Normal file
@@ -0,0 +1,163 @@
|
||||
/*!
|
||||
* 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
|
||||
*/
|
||||
|
||||
/* This is an overload of the default lib. stylesheet to use local fonts instead of the CDN */
|
||||
@font-face {
|
||||
font-family: Monorale;
|
||||
font-weight: 100;
|
||||
font-style: normal;
|
||||
src: local('Raleway-v4020 Thin'),
|
||||
url('../../lib/samvk/monorale-raleway-sober/otf/Monorale-Thin.otf') format('otf'),
|
||||
url('../../lib/samvk/monorale-raleway-sober/woff/Monorale-Thin.woff') format('woff');
|
||||
}
|
||||
@font-face {
|
||||
font-family: Monorale;
|
||||
font-weight: 100;
|
||||
font-style: italic;
|
||||
src: local('Raleway-v4020 Thin'),
|
||||
url('../../lib/samvk/monorale-raleway-sober/otf/Monorale-ThinItalic.otf') format('otf'),
|
||||
url('../../lib/samvk/monorale-raleway-sober/woff/Monorale-ThinItalic.woff') format('woff');
|
||||
}
|
||||
@font-face {
|
||||
font-family: Monorale;
|
||||
font-weight: 200;
|
||||
font-style: normal;
|
||||
src: local('Raleway-v4020 ExtraLight'),
|
||||
url('../../lib/samvk/monorale-raleway-sober/otf/Monorale-ExtraLight.otf') format('otf'),
|
||||
url('../../lib/samvk/monorale-raleway-sober/woff/Monorale-ExtraLight.woff') format('woff');
|
||||
}
|
||||
@font-face {
|
||||
font-family: Monorale;
|
||||
font-weight: 200;
|
||||
font-style: italic;
|
||||
src: local('Raleway-v4020 ExtraLight'),
|
||||
url('../../lib/samvk/monorale-raleway-sober/otf/Monorale-ExtraLightItalic.otf') format('otf'),
|
||||
url('../../lib/samvk/monorale-raleway-sober/woff/Monorale-ExtraLightItalic.woff') format('woff');
|
||||
}
|
||||
@font-face {
|
||||
font-family: Monorale;
|
||||
font-weight: 300;
|
||||
font-style: normal;
|
||||
src: local('Raleway-v4020 Light'),
|
||||
url('../../lib/samvk/monorale-raleway-sober/otf/Monorale-Light.otf') format('otf'),
|
||||
url('../../lib/samvk/monorale-raleway-sober/woff/Monorale-Light.woff') format('woff');
|
||||
}
|
||||
@font-face {
|
||||
font-family: Monorale;
|
||||
font-weight: 300;
|
||||
font-style: italic;
|
||||
src: local('Raleway-v4020 Light'),
|
||||
url('../../lib/samvk/monorale-raleway-sober/otf/Monorale-LightItalic.otf') format('otf'),
|
||||
url('../../lib/samvk/monorale-raleway-sober/woff/Monorale-LightItalic.woff') format('woff');
|
||||
}
|
||||
@font-face {
|
||||
font-family: Monorale;
|
||||
font-weight: 400;
|
||||
font-style: normal;
|
||||
src: local('Raleway-v4020'),
|
||||
url('../../lib/samvk/monorale-raleway-sober/otf/Monorale-Regular.otf') format('otf'),
|
||||
url('../../lib/samvk/monorale-raleway-sober/woff/Monorale-Regular.woff') format('woff');
|
||||
}
|
||||
@font-face {
|
||||
font-family: Monorale;
|
||||
font-weight: 400;
|
||||
font-style: italic;
|
||||
src: local('Raleway-v4020'),
|
||||
url('../../lib/samvk/monorale-raleway-sober/otf/Monorale-Italic.otf') format('otf'),
|
||||
url('../../lib/samvk/monorale-raleway-sober/woff/Monorale-Italic.woff') format('woff');
|
||||
}
|
||||
@font-face {
|
||||
font-family: Monorale;
|
||||
font-weight: 500;
|
||||
font-style: normal;
|
||||
src: local('Raleway-v4020 Medium'),
|
||||
url('../../lib/samvk/monorale-raleway-sober/otf/Monorale-Medium.otf') format('otf'),
|
||||
url('../../lib/samvk/monorale-raleway-sober/woff/Monorale-Medium.woff') format('woff');
|
||||
}
|
||||
@font-face {
|
||||
font-family: Monorale;
|
||||
font-weight: 500;
|
||||
font-style: italic;
|
||||
src: local('Raleway-v4020 Medium'),
|
||||
url('../../lib/samvk/monorale-raleway-sober/otf/Monorale-MediumItalic.otf') format('otf'),
|
||||
url('../../lib/samvk/monorale-raleway-sober/woff/Monorale-MediumItalic.woff') format('woff');
|
||||
}
|
||||
@font-face {
|
||||
font-family: Monorale;
|
||||
font-weight: 600;
|
||||
font-style: normal;
|
||||
src: local('Raleway-v4020 SemiBold'),
|
||||
url('../../lib/samvk/monorale-raleway-sober/otf/Monorale-SemiBold.otf') format('otf'),
|
||||
url('../../lib/samvk/monorale-raleway-sober/woff/Monorale-SemiBold.woff') format('woff');
|
||||
}
|
||||
@font-face {
|
||||
font-family: Monorale;
|
||||
font-weight: 600;
|
||||
font-style: italic;
|
||||
src: local('Raleway-v4020 SemiBold'),
|
||||
url('../../lib/samvk/monorale-raleway-sober/otf/Monorale-SemiBoldItalic.otf') format('otf'),
|
||||
url('../../lib/samvk/monorale-raleway-sober/woff/Monorale-SemiBoldItalic.woff') format('woff');
|
||||
}
|
||||
@font-face {
|
||||
font-family: Monorale;
|
||||
font-weight: 700;
|
||||
font-style: normal;
|
||||
src: local('Raleway-v4020'),
|
||||
url('../../lib/samvk/monorale-raleway-sober/otf/Monorale-Bold.otf') format('otf'),
|
||||
url('../../lib/samvk/monorale-raleway-sober/woff/Monorale-Bold.woff') format('woff');
|
||||
}
|
||||
@font-face {
|
||||
font-family: Monorale;
|
||||
font-weight: 700;
|
||||
font-style: italic;
|
||||
src: local('Raleway-v4020'),
|
||||
url('../../lib/samvk/monorale-raleway-sober/otf/Monorale-BoldItalic.otf') format('otf'),
|
||||
url('../../lib/samvk/monorale-raleway-sober/woff/Monorale-BoldItalic.woff') format('woff');
|
||||
}
|
||||
@font-face {
|
||||
font-family: Monorale;
|
||||
font-weight: 800;
|
||||
font-style: normal;
|
||||
src: local('Raleway-v4020 ExtraBold'),
|
||||
url('../../lib/samvk/monorale-raleway-sober/otf/Monorale-ExtraBold.otf') format('otf'),
|
||||
url('../../lib/samvk/monorale-raleway-sober/woff/Monorale-ExtraBold.woff') format('woff');
|
||||
}
|
||||
@font-face {
|
||||
font-family: Monorale;
|
||||
font-weight: 800;
|
||||
font-style: italic;
|
||||
src: local('Raleway-v4020 ExtraBold'),
|
||||
url('../../lib/samvk/monorale-raleway-sober/otf/Monorale-ExtraBoldItalic.otf') format('otf'),
|
||||
url('../../lib/samvk/monorale-raleway-sober/woff/Monorale-ExtraBoldItalic.woff') format('woff');
|
||||
}
|
||||
@font-face {
|
||||
font-family: Monorale;
|
||||
font-weight: 900;
|
||||
font-style: normal;
|
||||
src: local('Raleway-v4020 Black'),
|
||||
url('../../lib/samvk/monorale-raleway-sober/otf/Monorale-Black.otf') format('otf'),
|
||||
url('../../lib/samvk/monorale-raleway-sober/woff/Monorale-Black.woff') format('woff');
|
||||
}
|
||||
@font-face {
|
||||
font-family: Monorale;
|
||||
font-weight: 900;
|
||||
font-style: italic;
|
||||
src: local('Raleway-v4020 Black'),
|
||||
url('../../lib/samvk/monorale-raleway-sober/otf/Monorale-BlackItalic.otf') format('otf'),
|
||||
url('../../lib/samvk/monorale-raleway-sober/woff/Monorale-BlackItalic.woff') format('woff');
|
||||
}
|
||||
98
css/backoffice/components/_alert.scss
Normal file
98
css/backoffice/components/_alert.scss
Normal file
@@ -0,0 +1,98 @@
|
||||
/*!
|
||||
* 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
|
||||
*/
|
||||
|
||||
/* SCSS variables */
|
||||
$ibo-alert--spacing-top--with-same-block: 6px !default;
|
||||
$ibo-alert--spacing-top--with-other-blocks: 16px !default;
|
||||
$ibo-alert--padding-y: 18px !default;
|
||||
$ibo-alert--padding-x: 20px !default;
|
||||
$ibo-alert--border-radius: $ibo-border-radius-300 !default;
|
||||
|
||||
$ibo-alert--title--padding-bottom: 4px !default;
|
||||
|
||||
$ibo-alert--title--highlight--width: 4px !default;
|
||||
$ibo-alert--title--highlight--height: 100% !default;
|
||||
|
||||
$ibo-alert-colors: (
|
||||
'primary': ($ibo-color-primary-200, $ibo-color-primary-700, $ibo-color-primary-900),
|
||||
'secondary': ($ibo-color-secondary-200, $ibo-color-secondary-700, $ibo-color-secondary-900),
|
||||
'neutral': ($ibo-color-secondary-200, $ibo-color-secondary-700, $ibo-color-secondary-900),
|
||||
'information': ($ibo-color-information-200, $ibo-color-information-700, $ibo-color-information-900),
|
||||
'success': ($ibo-color-success-100, $ibo-color-success-700, $ibo-color-success-900),
|
||||
'failure': ($ibo-color-danger-200, $ibo-color-danger-700, $ibo-color-danger-900),
|
||||
'warning': ($ibo-color-warning-200, $ibo-color-warning-700, $ibo-color-warning-900),
|
||||
'danger': ($ibo-color-danger-200, $ibo-color-danger-700, $ibo-color-danger-900),
|
||||
'grey' : ($ibo-color-grey-200, $ibo-color-grey-700, $ibo-color-grey-900),
|
||||
'blue-grey': ($ibo-color-blue-grey-200, $ibo-color-blue-grey-700, $ibo-color-blue-grey-900),
|
||||
'blue': ($ibo-color-blue-200, $ibo-color-blue-700, $ibo-color-blue-900),
|
||||
'cyan': ($ibo-color-cyan-100, $ibo-color-blue-700, $ibo-color-cyan-900),
|
||||
'green': ($ibo-color-green-100, $ibo-color-green-700, $ibo-color-green-900),
|
||||
'orange' : ($ibo-color-orange-200, $ibo-color-orange-700, $ibo-color-orange-900),
|
||||
'red': ($ibo-color-red-200, $ibo-color-red-700, $ibo-color-red-900),
|
||||
'pink': ($ibo-color-pink-200, $ibo-color-pink-700, $ibo-color-pink-900),
|
||||
) !default;
|
||||
|
||||
@each $sColor, $aColorValues in $ibo-alert-colors {
|
||||
$bg-color: nth($aColorValues, 1);
|
||||
$highlight-color: nth($aColorValues, 2);
|
||||
$text-color: nth($aColorValues, 3);
|
||||
.ibo-alert.ibo-is-#{$sColor} {
|
||||
background-color: $bg-color;
|
||||
color: $text-color;
|
||||
|
||||
&::before {
|
||||
background-color: $highlight-color;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Rules */
|
||||
.ibo-alert {
|
||||
position: relative;
|
||||
padding: $ibo-alert--padding-y $ibo-alert--padding-x;
|
||||
border-radius: $ibo-alert--border-radius;
|
||||
overflow: hidden; /* To force highlight color to be cropped by the border radius */
|
||||
|
||||
@extend %ibo-font-ral-med-150;
|
||||
|
||||
&::before {
|
||||
display: block;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
content: '';
|
||||
|
||||
width: $ibo-alert--title--highlight--width;
|
||||
height: $ibo-alert--title--highlight--height;
|
||||
}
|
||||
|
||||
.ibo-alert--title {
|
||||
padding-bottom: $ibo-alert--title--padding-bottom;
|
||||
|
||||
@extend %ibo-font-ral-bol-150;
|
||||
}
|
||||
}
|
||||
|
||||
/* Spacing between alert blocks */
|
||||
.ibo-alert + .ibo-alert {
|
||||
margin-top: $ibo-alert--spacing-top--with-same-block;
|
||||
}
|
||||
/* Spacing between an alert block and something else */
|
||||
.ibo-alert + :not(.ibo-alert) {
|
||||
margin-top: $ibo-alert--spacing-top--with-other-blocks;
|
||||
}
|
||||
29
css/backoffice/components/_all.scss
Normal file
29
css/backoffice/components/_all.scss
Normal file
@@ -0,0 +1,29 @@
|
||||
/*!
|
||||
* copyright Copyright (C) 2010-2020 Combodo SARL
|
||||
* license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
@import "alert";
|
||||
@import "badge";
|
||||
@import "button";
|
||||
@import "breadcrumbs";
|
||||
@import "quick-create";
|
||||
@import "global-search";
|
||||
@import "popover-menu/popover-menu";
|
||||
@import "popover-menu/popover-menu-item";
|
||||
@import "newsroom-menu";
|
||||
@import "panel";
|
||||
@import "modal";
|
||||
@import "dashlet/all";
|
||||
@import "input/all";
|
||||
|
||||
@import "title";
|
||||
@import "datatable";
|
||||
@import "form";
|
||||
@import "fieldset";
|
||||
@import "field";
|
||||
@import "toolbar";
|
||||
@import "richtext";
|
||||
@import "formtable";
|
||||
@import "formtablerow";
|
||||
@import "search-form";
|
||||
99
css/backoffice/components/_badge.scss
Normal file
99
css/backoffice/components/_badge.scss
Normal file
@@ -0,0 +1,99 @@
|
||||
/*!
|
||||
* 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
|
||||
*/
|
||||
|
||||
/* SCSS variables */
|
||||
$ibo-badge--margin: 4px 8px !default;
|
||||
$ibo-badge--padding: 6px 10px !default;
|
||||
$ibo-badge--border-radius: $ibo-border-radius-300 !default;
|
||||
|
||||
$ibo-badge-new-state-primary-color: $ibo-color-blue-100 !default;
|
||||
$ibo-badge-new-state-secondary-color: $ibo-color-blue-900 !default;
|
||||
|
||||
$ibo-badge-neutral-state-primary-color: $ibo-color-blue-100 !default;
|
||||
$ibo-badge-neutral-state-secondary-color: $ibo-color-blue-900 !default;
|
||||
|
||||
$ibo-badge-waiting-state-primary-color: $ibo-color-orange-100 !default;
|
||||
$ibo-badge-waiting-state-secondary-color: $ibo-color-orange-800 !default;
|
||||
|
||||
$ibo-badge-success-state-primary-color: $ibo-color-green-100 !default;
|
||||
$ibo-badge-success-state-secondary-color: $ibo-color-green-900 !default;
|
||||
|
||||
$ibo-badge-failure-state-primary-color: $ibo-color-red-100 !default;
|
||||
$ibo-badge-failure-state-secondary-color: $ibo-color-red-800 !default;
|
||||
|
||||
$ibo-badge-frozen-state-primary-color: $ibo-color-grey-100 !default;
|
||||
$ibo-badge-frozen-state-secondary-color: $ibo-color-grey-700 !default;
|
||||
|
||||
/* - For basic badge */
|
||||
$ibo-badge-active-state-primary-color: $ibo-color-green-100 !default;
|
||||
$ibo-badge-active-state-secondary-color: $ibo-color-green-900 !default;
|
||||
|
||||
$ibo-badge-inactive-state-primary-color: $ibo-color-orange-100 !default;
|
||||
$ibo-badge-inactive-state-secondary-color: $ibo-color-orange-800 !default;
|
||||
|
||||
$ibo-badge-states-colors: (
|
||||
'new': (
|
||||
'primary-color': $ibo-badge-new-state-primary-color,
|
||||
'secondary-color': $ibo-badge-new-state-secondary-color,
|
||||
),
|
||||
'neutral': (
|
||||
'primary-color': $ibo-badge-neutral-state-primary-color,
|
||||
'secondary-color': $ibo-badge-neutral-state-secondary-color,
|
||||
),
|
||||
'waiting': (
|
||||
'primary-color': $ibo-badge-waiting-state-primary-color,
|
||||
'secondary-color': $ibo-badge-waiting-state-secondary-color,
|
||||
),
|
||||
'success': (
|
||||
'primary-color': $ibo-badge-success-state-primary-color,
|
||||
'secondary-color': $ibo-badge-success-state-secondary-color,
|
||||
),
|
||||
'failure': (
|
||||
'primary-color': $ibo-badge-failure-state-primary-color,
|
||||
'secondary-color': $ibo-badge-failure-state-secondary-color,
|
||||
),
|
||||
'frozen': (
|
||||
'primary-color': $ibo-badge-frozen-state-primary-color,
|
||||
'secondary-color': $ibo-badge-frozen-state-secondary-color,
|
||||
),
|
||||
'active': (
|
||||
'primary-color': $ibo-badge-active-state-primary-color,
|
||||
'secondary-color': $ibo-badge-active-state-secondary-color,
|
||||
),
|
||||
'inactive': (
|
||||
'primary-color': $ibo-badge-inactive-state-primary-color,
|
||||
'secondary-color': $ibo-badge-inactive-state-secondary-color,
|
||||
),
|
||||
);
|
||||
|
||||
@each $sType, $aColors in $ibo-badge-states-colors {
|
||||
.ibo-badge-is-#{$sType} {
|
||||
color: map-get($aColors, 'secondary-color');
|
||||
background-color: map-get($aColors, 'primary-color');
|
||||
}
|
||||
}
|
||||
|
||||
/* Rules */
|
||||
.ibo-badge {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
margin: $ibo-badge--margin;
|
||||
padding: $ibo-badge--padding;
|
||||
border-radius: $ibo-badge--border-radius;
|
||||
}
|
||||
80
css/backoffice/components/_breadcrumbs.scss
Normal file
80
css/backoffice/components/_breadcrumbs.scss
Normal file
@@ -0,0 +1,80 @@
|
||||
/*!
|
||||
* 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
|
||||
*/
|
||||
|
||||
$ibo-breadcrumbs--item--text-color: $ibo-color-grey-800 !default;
|
||||
|
||||
$ibo-breadcrumbs--item-icon--margin-x: 8px !default;
|
||||
$ibo-breadcrumbs--item-icon--max-width: 16px !default;
|
||||
$ibo-breadcrumbs--item-icon--text-color: $ibo-color-grey-600 !default;
|
||||
|
||||
$ibo-breadcrumbs--item-label--max-width: 100px !default;
|
||||
|
||||
$ibo-breadcrumbs--item-separator--margin-x: 12px !default;
|
||||
$ibo-breadcrumbs--item-separator--text-color: $ibo-color-grey-500 !default;
|
||||
|
||||
.ibo-breadcrumbs{
|
||||
@extend %ibo-full-height-content;
|
||||
|
||||
* {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
}
|
||||
.ibo-breadcrumbs--item{
|
||||
color: $ibo-breadcrumbs--item--text-color;
|
||||
@extend %ibo-font-ral-nor-100;
|
||||
|
||||
&:not(:last-child){
|
||||
&::after{
|
||||
content: '\f054';
|
||||
margin: 0 $ibo-breadcrumbs--item-separator--margin-x;
|
||||
color: $ibo-breadcrumbs--item-separator--text-color;
|
||||
@extend %fa-solid-base;
|
||||
}
|
||||
|
||||
&:hover{
|
||||
.ibo-breadcrumbs--item-icon{
|
||||
> *{
|
||||
opacity: 1;
|
||||
filter: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.ibo-breadcrumbs--item-icon{
|
||||
margin-right: $ibo-breadcrumbs--item-icon--margin-x;
|
||||
@extend %ibo-font-ral-nor-150;
|
||||
transition: all 0.1s linear;
|
||||
|
||||
> span{
|
||||
color: $ibo-breadcrumbs--item-icon--text-color;
|
||||
opacity: 0.6;
|
||||
}
|
||||
> img{
|
||||
height: auto;
|
||||
max-width: $ibo-breadcrumbs--item-icon--max-width;
|
||||
opacity: 0.3;
|
||||
filter: grayscale(100%);
|
||||
}
|
||||
}
|
||||
.ibo-breadcrumbs--item-label{
|
||||
display: inline; /* Otherwise the "truncate" doesn't work with th default display: flex */
|
||||
max-width: $ibo-breadcrumbs--item-label--max-width;
|
||||
@extend %ibo-text-truncated-with-ellipsis;
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user