mirror of
https://github.com/Combodo/iTop.git
synced 2026-02-14 16:04:10 +01:00
Compare commits
1807 Commits
2.4.3
...
support/2.
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8295eaed90 | ||
|
|
219b970703 | ||
|
|
76c139253e | ||
|
|
10cfb373f2 | ||
|
|
97d6d413bb | ||
|
|
3f8f57fa9a | ||
|
|
f916f9cde8 | ||
|
|
8a65a592f3 | ||
|
|
5e48400cb1 | ||
|
|
252562ace9 | ||
|
|
770ac8ffe5 | ||
|
|
ed3c387712 | ||
|
|
81a2a9278c | ||
|
|
e15d4bfab6 | ||
|
|
3e8dd2f4a5 | ||
|
|
51a49dfce8 | ||
|
|
066b71686d | ||
|
|
be633001a5 | ||
|
|
84426c6634 | ||
|
|
dbaf924171 | ||
|
|
8adf743cc7 | ||
|
|
75450ded1d | ||
|
|
2beb795f9a | ||
|
|
e8d314e1f6 | ||
|
|
e29f1825be | ||
|
|
9b854dbcc7 | ||
|
|
7757f1f2d2 | ||
|
|
a353317746 | ||
|
|
723eb90160 | ||
|
|
b3f827ed5e | ||
|
|
eaf8a187aa | ||
|
|
34f64c61f6 | ||
|
|
92a9a8c65f | ||
|
|
834ac00d37 | ||
|
|
5691ca0327 | ||
|
|
86f649affc | ||
|
|
4f5c987d8b | ||
|
|
e441e5e78a | ||
|
|
43daa2ef08 | ||
|
|
db6e813cba | ||
|
|
066a6d8b36 | ||
|
|
b9ca2ac13d | ||
|
|
65e43e8d04 | ||
|
|
5fee2438ab | ||
|
|
8b1c20cc11 | ||
|
|
0001e8ffc4 | ||
|
|
df5aacca42 | ||
|
|
1f53757318 | ||
|
|
090119147c | ||
|
|
1551694198 | ||
|
|
bef1832ac7 | ||
|
|
45e366745d | ||
|
|
1e634a8bba | ||
|
|
228a945da9 | ||
|
|
834297e675 | ||
|
|
3c9318d56a | ||
|
|
30d10b6f11 | ||
|
|
f8e39877b3 | ||
|
|
0a3f7d7ef7 | ||
|
|
222eb47bd2 | ||
|
|
c5b1f02d2b | ||
|
|
f81ab4d71a | ||
|
|
b88b9dabdb | ||
|
|
06b17e82db | ||
|
|
2add79a473 | ||
|
|
3a37e24496 | ||
|
|
b1d703bff3 | ||
|
|
a3a34a94e7 | ||
|
|
6edc365685 | ||
|
|
4b7f736af0 | ||
|
|
016fbaed36 | ||
|
|
bfcd137e52 | ||
|
|
f9af8fc912 | ||
|
|
bd083d632f | ||
|
|
bd9da07734 | ||
|
|
3dbbf296b8 | ||
|
|
50a8af4082 | ||
|
|
6a1125875b | ||
|
|
878c23892d | ||
|
|
248dab9289 | ||
|
|
4f0e3430c0 | ||
|
|
3347f400b8 | ||
|
|
6082308e20 | ||
|
|
5fce2a2c1c | ||
|
|
03b8ed5ce4 | ||
|
|
31a34c247c | ||
|
|
a625733885 | ||
|
|
d7fad4b646 | ||
|
|
f4d538ef6c | ||
|
|
aadb605dec | ||
|
|
f63f2bd445 | ||
|
|
fefd9aae95 | ||
|
|
878b87b68c | ||
|
|
14ae9f0809 | ||
|
|
b3369c8b0e | ||
|
|
33903f570b | ||
|
|
127809a836 | ||
|
|
6c948873ff | ||
|
|
a93be39aeb | ||
|
|
7c93d116ec | ||
|
|
f948d6e026 | ||
|
|
a222ead43c | ||
|
|
d6bfbbcd30 | ||
|
|
17df9d0f9d | ||
|
|
93099ea3c7 | ||
|
|
2f9e050e2b | ||
|
|
5c341138e1 | ||
|
|
56b9eb6cf3 | ||
|
|
db20244212 | ||
|
|
6f9f74e72f | ||
|
|
8070d5b9b7 | ||
|
|
6197ecbaf4 | ||
|
|
ca585d3f42 | ||
|
|
02c78d4044 | ||
|
|
9e5d668c02 | ||
|
|
051656f295 | ||
|
|
9a51a44549 | ||
|
|
5102b113ed | ||
|
|
f1e4d94499 | ||
|
|
d04102bab3 | ||
|
|
c723d19e01 | ||
|
|
dac77e0606 | ||
|
|
02b98543d9 | ||
|
|
519aaadd9a | ||
|
|
fe27fef530 | ||
|
|
72dbb6f937 | ||
|
|
ccb29d10ae | ||
|
|
e479775833 | ||
|
|
86a7192f5a | ||
|
|
4a1be13904 | ||
|
|
0f3347f64d | ||
|
|
6564d84a2f | ||
|
|
f4747c5cef | ||
|
|
1e92c2f28a | ||
|
|
e4b097b196 | ||
|
|
85653c9ffc | ||
|
|
da5d8b20fa | ||
|
|
9a5a5f858f | ||
|
|
a0cd281c42 | ||
|
|
6bb5606c00 | ||
|
|
a6ceb88fca | ||
|
|
7bb7a94fbc | ||
|
|
e4324cedb4 | ||
|
|
07781c7c9d | ||
|
|
ea58a807fc | ||
|
|
fb6806a1c1 | ||
|
|
166451c4e9 | ||
|
|
7c1290f684 | ||
|
|
179c774ba8 | ||
|
|
e886d80de6 | ||
|
|
3791b2dd24 | ||
|
|
12c916f4e5 | ||
|
|
ba7e00e130 | ||
|
|
bada955725 | ||
|
|
f9e18675f3 | ||
|
|
22416cc0be | ||
|
|
ec086ad94a | ||
|
|
17d4b570e8 | ||
|
|
2dfad12553 | ||
|
|
26dcaa0ded | ||
|
|
b5d3ddb7e3 | ||
|
|
8b178914b3 | ||
|
|
ce6fd4d775 | ||
|
|
9c75cb4537 | ||
|
|
633fa343a5 | ||
|
|
a1d01e252b | ||
|
|
b157fad0b6 | ||
|
|
70d2bb163c | ||
|
|
fae6c89e9a | ||
|
|
89d310258b | ||
|
|
a58529f46c | ||
|
|
12a2035791 | ||
|
|
b1ff7f0e9b | ||
|
|
23cf2b91f4 | ||
|
|
3c4fe338b6 | ||
|
|
6159ab33b7 | ||
|
|
77f757995e | ||
|
|
2858d13fd5 | ||
|
|
99f398a87e | ||
|
|
87ee731dbe | ||
|
|
f2380ae354 | ||
|
|
2d039af278 | ||
|
|
831879fe37 | ||
|
|
ea1dfd8933 | ||
|
|
24519c69a4 | ||
|
|
b5c4801beb | ||
|
|
3eff8f62b1 | ||
|
|
16c8466841 | ||
|
|
b83e5e2b72 | ||
|
|
764b0f8e31 | ||
|
|
cac0da4e3d | ||
|
|
7e064365eb | ||
|
|
7c7382f372 | ||
|
|
4918b9c83a | ||
|
|
ed95f4e05f | ||
|
|
9f0e8dc49b | ||
|
|
693fdfdc5b | ||
|
|
b8d5c01382 | ||
|
|
01108ca83d | ||
|
|
3d5b7197f6 | ||
|
|
d3db77c675 | ||
|
|
54c027823b | ||
|
|
f63aceeabe | ||
|
|
533e65fcd1 | ||
|
|
3fb0c768e6 | ||
|
|
243aab1030 | ||
|
|
22dba9ae07 | ||
|
|
02857a86fd | ||
|
|
d663d01798 | ||
|
|
3602163b38 | ||
|
|
3322074ce7 | ||
|
|
83bb3b6d72 | ||
|
|
229f800266 | ||
|
|
75737b4ffe | ||
|
|
a5340917a7 | ||
|
|
914d19e7e4 | ||
|
|
eb49dbbdc8 | ||
|
|
912bab5a43 | ||
|
|
94092f445f | ||
|
|
856c037bb0 | ||
|
|
388896b963 | ||
|
|
1d8addf675 | ||
|
|
c8c3d32b18 | ||
|
|
75a0979eee | ||
|
|
d6a0a279a5 | ||
|
|
44f5d71e1b | ||
|
|
bc841dd239 | ||
|
|
9c71d32964 | ||
|
|
d199d84b27 | ||
|
|
24aca83de4 | ||
|
|
3de7aa1ada | ||
|
|
5a0edb5c39 | ||
|
|
d4fec14123 | ||
|
|
38951fab1a | ||
|
|
e2c8237beb | ||
|
|
1224570fa5 | ||
|
|
afb99c0f4b | ||
|
|
733c908e34 | ||
|
|
377b4b038c | ||
|
|
3f7fd6f9f9 | ||
|
|
1cb36621a1 | ||
|
|
ddd9188eb7 | ||
|
|
02254eac67 | ||
|
|
ebe026b2e9 | ||
|
|
efc7c5b0f4 | ||
|
|
f68a77450d | ||
|
|
c5943c6c28 | ||
|
|
bc3b50ad23 | ||
|
|
1f7923beae | ||
|
|
2f15bbdaf3 | ||
|
|
a2d34d1779 | ||
|
|
cdba1e0d36 | ||
|
|
48f15d7781 | ||
|
|
d0a766d424 | ||
|
|
a89bca4626 | ||
|
|
23ec21e494 | ||
|
|
63a36fd0f6 | ||
|
|
02617e8976 | ||
|
|
7cf7e55454 | ||
|
|
5067c867b8 | ||
|
|
6b5cc7ca4b | ||
|
|
7bb49893ee | ||
|
|
bf62b63173 | ||
|
|
b8fb1fa78a | ||
|
|
818b4d08da | ||
|
|
f438fbd06f | ||
|
|
297a45d477 | ||
|
|
17fe9dfd5f | ||
|
|
9d0cbca497 | ||
|
|
a613b4b101 | ||
|
|
c989e2eda5 | ||
|
|
c6fd381b01 | ||
|
|
a784661025 | ||
|
|
1f9a638bc1 | ||
|
|
545504c0de | ||
|
|
32f1e97bcd | ||
|
|
43b0747b83 | ||
|
|
9637e75f97 | ||
|
|
84767692b0 | ||
|
|
d484614c0f | ||
|
|
b403bace6c | ||
|
|
0b751a9dd6 | ||
|
|
8f434cad08 | ||
|
|
f83292fccc | ||
|
|
90e128f951 | ||
|
|
8efc372a68 | ||
|
|
257fb4d036 | ||
|
|
97261820f6 | ||
|
|
2f83a2168c | ||
|
|
c0275eec21 | ||
|
|
2bd7a7b5f8 | ||
|
|
0aab80917a | ||
|
|
31a2b634cc | ||
|
|
dc7bafa41c | ||
|
|
505aad1e89 | ||
|
|
4508b9d7d5 | ||
|
|
888aa5f958 | ||
|
|
4051524b5c | ||
|
|
c8c4b072b1 | ||
|
|
08543287e8 | ||
|
|
21e5eee31f | ||
|
|
ed3fd851f1 | ||
|
|
dfe81f6272 | ||
|
|
00c59b7f2c | ||
|
|
dbcde14f5e | ||
|
|
a6f4adfed8 | ||
|
|
effaba42d0 | ||
|
|
340cacc691 | ||
|
|
0bce9c78ea | ||
|
|
48c920f848 | ||
|
|
a85bedd31c | ||
|
|
23269eab77 | ||
|
|
05bcfbe4c3 | ||
|
|
27ad2e2169 | ||
|
|
5d09841cd5 | ||
|
|
11ec46c18b | ||
|
|
da76fc70bb | ||
|
|
2b563d4fc8 | ||
|
|
2773a8bf2f | ||
|
|
ad36011fc8 | ||
|
|
b82b095f58 | ||
|
|
2f5c810276 | ||
|
|
d90e094d4d | ||
|
|
4eb416d407 | ||
|
|
636a3940cd | ||
|
|
352f8cee10 | ||
|
|
523e19528e | ||
|
|
9f3332b2f2 | ||
|
|
2b71621628 | ||
|
|
5349fc6f4b | ||
|
|
1665b12b86 | ||
|
|
1bbed99636 | ||
|
|
778db225a8 | ||
|
|
ca48e8ff92 | ||
|
|
75d5630164 | ||
|
|
bb6bd61c37 | ||
|
|
b51b5582a0 | ||
|
|
bc5643707e | ||
|
|
27b1b1f8a8 | ||
|
|
a45e543eac | ||
|
|
50235bbb04 | ||
|
|
a2ddb30f78 | ||
|
|
d31a4047f6 | ||
|
|
75fbb831c9 | ||
|
|
3219957eed | ||
|
|
44671a5085 | ||
|
|
bc4873dfe5 | ||
|
|
92657951c7 | ||
|
|
8b2c18ab8c | ||
|
|
18999f29c5 | ||
|
|
e8075bf5fd | ||
|
|
5338325a73 | ||
|
|
4d3810a10d | ||
|
|
672bc471be | ||
|
|
3089cbc2bc | ||
|
|
ce9416d887 | ||
|
|
473d1fb756 | ||
|
|
b880ca05a5 | ||
|
|
cbc9784d21 | ||
|
|
faba67b292 | ||
|
|
16cb1bbbbf | ||
|
|
a1c2b809ba | ||
|
|
c9691457b8 | ||
|
|
9828b905b2 | ||
|
|
9ef6c78395 | ||
|
|
81f70c4c58 | ||
|
|
869f590bf4 | ||
|
|
3b6aa7eaf5 | ||
|
|
53ef2b0b5d | ||
|
|
4dfe6fc817 | ||
|
|
260143050e | ||
|
|
6adde38399 | ||
|
|
76a40b2f45 | ||
|
|
77c2537df7 | ||
|
|
6a88f622ad | ||
|
|
9b5d8b8a01 | ||
|
|
b4448c5bb9 | ||
|
|
7faf3258f7 | ||
|
|
cb3440c85d | ||
|
|
7c0d03ea3b | ||
|
|
d1837377a4 | ||
|
|
1c3a503a82 | ||
|
|
daafa9123c | ||
|
|
5a1b6e43c9 | ||
|
|
81d502cae8 | ||
|
|
4a99ed2ad8 | ||
|
|
7016724abc | ||
|
|
0a8e3f099e | ||
|
|
45910dc115 | ||
|
|
afd6428411 | ||
|
|
7eb419507b | ||
|
|
8400eb910f | ||
|
|
b38d33d7a6 | ||
|
|
b4a6d378ab | ||
|
|
44b7821015 | ||
|
|
52ac819c1f | ||
|
|
c4ba1d55ac | ||
|
|
85acac60c7 | ||
|
|
23ee8d6a14 | ||
|
|
2154916848 | ||
|
|
d3fd81545a | ||
|
|
f54da5f9a6 | ||
|
|
36d47c2274 | ||
|
|
bd082c0a6e | ||
|
|
fb028710e0 | ||
|
|
29dd196193 | ||
|
|
80a8f7a888 | ||
|
|
7f497fe3be | ||
|
|
59570f3a21 | ||
|
|
53fe826f9f | ||
|
|
56b4ecb4ce | ||
|
|
d17717e4b5 | ||
|
|
68da3a4aad | ||
|
|
855480fd7b | ||
|
|
79200e8f96 | ||
|
|
7d43ae40b8 | ||
|
|
540bc3a54b | ||
|
|
35752a8041 | ||
|
|
2baa95ff6d | ||
|
|
86dce21849 | ||
|
|
fca5a625d2 | ||
|
|
2766fad61a | ||
|
|
c6da1db72b | ||
|
|
843c06b007 | ||
|
|
7cf7628b8f | ||
|
|
41b096ba76 | ||
|
|
2a4bd4b0dc | ||
|
|
f4f5281769 | ||
|
|
a4a09cd8c7 | ||
|
|
831b18b4d2 | ||
|
|
e4e5f627c4 | ||
|
|
53e532cbaf | ||
|
|
3fa0cbf0fe | ||
|
|
6450d2339f | ||
|
|
af8b06dda6 | ||
|
|
72e2473444 | ||
|
|
6e31a040b2 | ||
|
|
0c8dd6fd1b | ||
|
|
6c07688c34 | ||
|
|
598c22a285 | ||
|
|
d392b9c0f6 | ||
|
|
387c166985 | ||
|
|
9115bc118d | ||
|
|
aca11ac966 | ||
|
|
c15d626095 | ||
|
|
79d00b9fe6 | ||
|
|
a92e2fd882 | ||
|
|
7ed51984c7 | ||
|
|
cdf11a3485 | ||
|
|
bbefd22950 | ||
|
|
e08369122d | ||
|
|
0ce0572c40 | ||
|
|
9d19556419 | ||
|
|
67c0e0eb1c | ||
|
|
c5d0dd05b9 | ||
|
|
4e1f877ab4 | ||
|
|
0e0d254188 | ||
|
|
992421292c | ||
|
|
47cb4feeeb | ||
|
|
76acd8fe9e | ||
|
|
961b1570e8 | ||
|
|
88dea990e1 | ||
|
|
19d4de482d | ||
|
|
d2505d15fe | ||
|
|
122c3a9542 | ||
|
|
15d9ba9906 | ||
|
|
95a22a1a7e | ||
|
|
5309aa225a | ||
|
|
c0cd450c5f | ||
|
|
d831549c7b | ||
|
|
0f20f9ca5d | ||
|
|
d5568afc68 | ||
|
|
44d7abac6e | ||
|
|
1b4b71cb35 | ||
|
|
f37f3c4c22 | ||
|
|
83b3fb80d5 | ||
|
|
c242f90440 | ||
|
|
e4912ee175 | ||
|
|
83e1f35f9c | ||
|
|
c42333d085 | ||
|
|
c4c0b0f630 | ||
|
|
aec3c34eea | ||
|
|
c4ff20b9fb | ||
|
|
c7ce35a877 | ||
|
|
5ccfa24b27 | ||
|
|
1c6a6edf5a | ||
|
|
a659de9c9b | ||
|
|
8530db347b | ||
|
|
29e28dedf1 | ||
|
|
3aed65c921 | ||
|
|
0acc0b4a74 | ||
|
|
c300e46480 | ||
|
|
0a3f076335 | ||
|
|
12d9551845 | ||
|
|
0d6c799f9c | ||
|
|
a395f5b63c | ||
|
|
cf0ad59ec5 | ||
|
|
2e46fa50b3 | ||
|
|
5a30a3dcb3 | ||
|
|
f9bb2e7a14 | ||
|
|
57e8b9faaf | ||
|
|
c737b83eb5 | ||
|
|
5c91a1a612 | ||
|
|
0c49641094 | ||
|
|
99e909dae4 | ||
|
|
ecf34b47cb | ||
|
|
949b4495fc | ||
|
|
bd7e0174f3 | ||
|
|
ac89b2dc44 | ||
|
|
7e3fceb7dc | ||
|
|
b28ed08a85 | ||
|
|
a488c42dca | ||
|
|
62bc6714e0 | ||
|
|
9c9ebeeceb | ||
|
|
fb233709e0 | ||
|
|
9169cced20 | ||
|
|
9ceb8e9f0b | ||
|
|
1db9708624 | ||
|
|
5cedcb2389 | ||
|
|
52b42d0210 | ||
|
|
67f5f09530 | ||
|
|
b9e0747825 | ||
|
|
e44ed248ef | ||
|
|
b0c120d7fd | ||
|
|
177b6d1757 | ||
|
|
ff39b7bc51 | ||
|
|
7401e88844 | ||
|
|
b1e1e29254 | ||
|
|
ffac3250af | ||
|
|
e9fb885d34 | ||
|
|
b87037d187 | ||
|
|
a97680fb04 | ||
|
|
798e526010 | ||
|
|
d344478b48 | ||
|
|
b898a09c4c | ||
|
|
17589e060a | ||
|
|
7e4f235c59 | ||
|
|
7867cc1dca | ||
|
|
114b18d7c8 | ||
|
|
5baff6257b | ||
|
|
8264d21520 | ||
|
|
8bd10a2d11 | ||
|
|
cce88f09b0 | ||
|
|
26475ad10f | ||
|
|
c1a81e4f0d | ||
|
|
4a5cb23730 | ||
|
|
f0e5128fb5 | ||
|
|
63b08b0e70 | ||
|
|
4072ed09ac | ||
|
|
c722d64850 | ||
|
|
70137808f0 | ||
|
|
36ade3b15c | ||
|
|
6b5f32611d | ||
|
|
43bfe06882 | ||
|
|
6f79c16ba0 | ||
|
|
29df8f8f92 | ||
|
|
216d965d76 | ||
|
|
95fce0eefb | ||
|
|
841127c131 | ||
|
|
405b1b8e6f | ||
|
|
b050210737 | ||
|
|
ed02e3522e | ||
|
|
a327b5fb5e | ||
|
|
f9b2fda092 | ||
|
|
0d082bf378 | ||
|
|
d8cef95d56 | ||
|
|
2258e8c652 | ||
|
|
5e19d338b9 | ||
|
|
14ecfc4ce8 | ||
|
|
170d84d635 | ||
|
|
a962f6535e | ||
|
|
a4055c4a74 | ||
|
|
9ed550ee7f | ||
|
|
00bd7583f7 | ||
|
|
e4619fbc0f | ||
|
|
518d94f5f3 | ||
|
|
389a1791d7 | ||
|
|
54eb41b66f | ||
|
|
ede2673ba5 | ||
|
|
dd50c99ec4 | ||
|
|
357555e507 | ||
|
|
1f6a51b31f | ||
|
|
6d4cf71197 | ||
|
|
87f898d29d | ||
|
|
d5576522ae | ||
|
|
6addd9acec | ||
|
|
9b5942bf4e | ||
|
|
9faa4e4cbd | ||
|
|
8b80bd71e7 | ||
|
|
8989206461 | ||
|
|
5f7e8c9229 | ||
|
|
89a21c8e44 | ||
|
|
a7ec6e5ca0 | ||
|
|
a08675352a | ||
|
|
7158b1f787 | ||
|
|
3925ad252f | ||
|
|
f3fd47a792 | ||
|
|
af92f58265 | ||
|
|
81b5f18579 | ||
|
|
184c0cb84b | ||
|
|
c892862822 | ||
|
|
b61d1feec4 | ||
|
|
a73ff16642 | ||
|
|
7763983ef4 | ||
|
|
35f7fe98ae | ||
|
|
533acbde8d | ||
|
|
d72da422de | ||
|
|
891608f812 | ||
|
|
e66da81a20 | ||
|
|
cae0cd00c2 | ||
|
|
32fc87023c | ||
|
|
0021482c1b | ||
|
|
276427e3df | ||
|
|
7b49bde3ad | ||
|
|
a94d940bd3 | ||
|
|
313c3c6fc3 | ||
|
|
de86f71c90 | ||
|
|
098b0531d8 | ||
|
|
34552214bf | ||
|
|
d61a8ba160 | ||
|
|
84ebca58ac | ||
|
|
def4c54d26 | ||
|
|
027b0fcff7 | ||
|
|
fc0cb44a84 | ||
|
|
574d72b0e7 | ||
|
|
cd5e1afb2b | ||
|
|
0298d6bc19 | ||
|
|
60d2fd4f7e | ||
|
|
5faa0ffe08 | ||
|
|
705ce02580 | ||
|
|
78c674a989 | ||
|
|
84d9be3293 | ||
|
|
30c622052e | ||
|
|
ada56da63e | ||
|
|
78b626bbd2 | ||
|
|
823311dc86 | ||
|
|
21c5638e1e | ||
|
|
588899db63 | ||
|
|
a37698a9de | ||
|
|
02da84b4cf | ||
|
|
ebb5ede613 | ||
|
|
db4b8b2f43 | ||
|
|
c17f7caa29 | ||
|
|
d7df975971 | ||
|
|
f3f70d6296 | ||
|
|
256d4e2cb3 | ||
|
|
fb31c9006a | ||
|
|
bf000e6a89 | ||
|
|
94b4f10277 | ||
|
|
15671f6dd4 | ||
|
|
2460d2112f | ||
|
|
709badd0f7 | ||
|
|
99153d02ee | ||
|
|
4347b2c5ff | ||
|
|
c13b6ea13a | ||
|
|
6e5d4834f1 | ||
|
|
9f489d8a59 | ||
|
|
c9be1a8e71 | ||
|
|
c1e2f35c96 | ||
|
|
462148a12f | ||
|
|
7e4edc6e3a | ||
|
|
452e7cce01 | ||
|
|
cb7b5dfffb | ||
|
|
0a34fb7a7a | ||
|
|
11ba459d1b | ||
|
|
460337954b | ||
|
|
215786d740 | ||
|
|
fe9ca2b9cc | ||
|
|
41a479b48d | ||
|
|
74a8c3f5bd | ||
|
|
3347d32f2a | ||
|
|
eb630efdf5 | ||
|
|
91b7130671 | ||
|
|
80be4b4371 | ||
|
|
21d7de7d8d | ||
|
|
4c2be6b2c5 | ||
|
|
860bb6d615 | ||
|
|
4a431be0a9 | ||
|
|
950ffcde2b | ||
|
|
b84ac80aaa | ||
|
|
0580c71749 | ||
|
|
c66b0bea41 | ||
|
|
7281bd4a1a | ||
|
|
c9d73fc0c8 | ||
|
|
8720ac2b08 | ||
|
|
33e8b6a64c | ||
|
|
d7cf339ab5 | ||
|
|
714fada9f0 | ||
|
|
d36fd6a47d | ||
|
|
b6d0843e55 | ||
|
|
c0d83e96d8 | ||
|
|
3da6251cc7 | ||
|
|
396fc2cdcd | ||
|
|
11308dc76a | ||
|
|
7fddd6acdc | ||
|
|
1bf39aa092 | ||
|
|
10b7fa6014 | ||
|
|
3387d8fdd2 | ||
|
|
cbe749af13 | ||
|
|
c5f3598f4e | ||
|
|
9f926fccd8 | ||
|
|
e9a77c798e | ||
|
|
12e9e453d8 | ||
|
|
6e50a1c4be | ||
|
|
e3e416b467 | ||
|
|
fcb6a4069a | ||
|
|
02f83c4f52 | ||
|
|
452c6c3df6 | ||
|
|
2966efcfde | ||
|
|
1cf36a5d01 | ||
|
|
1973f7526e | ||
|
|
866dfe4531 | ||
|
|
f617cb556b | ||
|
|
29691a09fe | ||
|
|
cb73c2a3f9 | ||
|
|
713a41909b | ||
|
|
9972e253d5 | ||
|
|
55309be9a1 | ||
|
|
fd75f3af28 | ||
|
|
af7e5eb03e | ||
|
|
b97ce7a25f | ||
|
|
89d617c152 | ||
|
|
4595c565cc | ||
|
|
8f55d4054a | ||
|
|
2e255b10a7 | ||
|
|
cf9c1b52ed | ||
|
|
d3b3c44cbd | ||
|
|
edb25b6dca | ||
|
|
4bf748641d | ||
|
|
16a6b70708 | ||
|
|
40355cb2d0 | ||
|
|
b52aaaadf2 | ||
|
|
f55c0aa1c9 | ||
|
|
333c51b0f9 | ||
|
|
46dee2919e | ||
|
|
799618dee7 | ||
|
|
96aaa0d8e1 | ||
|
|
5556e3efec | ||
|
|
d8b2d4435a | ||
|
|
a4315b4789 | ||
|
|
3e8dd61607 | ||
|
|
1d28a67d21 | ||
|
|
3a551e9cec | ||
|
|
cf6693a534 | ||
|
|
8c5c275952 | ||
|
|
5fa4b4cb88 | ||
|
|
58525f247e | ||
|
|
d78f19525e | ||
|
|
5559c8205f | ||
|
|
2a6a97526d | ||
|
|
1adea8f014 | ||
|
|
29177ec86b | ||
|
|
741e88e1f0 | ||
|
|
66bddc5730 | ||
|
|
6eaa7c0530 | ||
|
|
b257fae03e | ||
|
|
2d24324dea | ||
|
|
ec597f697a | ||
|
|
3bed62a473 | ||
|
|
b5f7227ecd | ||
|
|
615adf8281 | ||
|
|
cb7bb3242a | ||
|
|
4b08eea998 | ||
|
|
01551942b3 | ||
|
|
720d334053 | ||
|
|
9397d1ac2e | ||
|
|
1530bb89fe | ||
|
|
a7000b2582 | ||
|
|
f09683949d | ||
|
|
e1f96974bb | ||
|
|
1fc261937f | ||
|
|
a94211d3d3 | ||
|
|
534f6b6a54 | ||
|
|
901764bf70 | ||
|
|
e67d6e8a80 | ||
|
|
16476f736a | ||
|
|
e9ecd89cda | ||
|
|
55036511ab | ||
|
|
3cf5d31f5d | ||
|
|
84ae36cf1a | ||
|
|
00515ac14a | ||
|
|
245612d0eb | ||
|
|
ae6e3b4f17 | ||
|
|
12a3f1c36c | ||
|
|
1af1e92b60 | ||
|
|
a1ad7a5def | ||
|
|
398d1aa820 | ||
|
|
38278f3432 | ||
|
|
baf4662ed8 | ||
|
|
cf07c9f1a2 | ||
|
|
446bd0ad1f | ||
|
|
3d5e46faac | ||
|
|
b8fba8997a | ||
|
|
a07c81d0d9 | ||
|
|
0252d091ca | ||
|
|
18d9ada58d | ||
|
|
055d2cc62c | ||
|
|
e15c5c58d8 | ||
|
|
b734aca4d0 | ||
|
|
e495b36dfb | ||
|
|
cdcfe03d67 | ||
|
|
2c6dc20046 | ||
|
|
a8c3b7ac2e | ||
|
|
98572c6efb | ||
|
|
70840c53aa | ||
|
|
9fbd27f3a8 | ||
|
|
c3c1897258 | ||
|
|
5403219746 | ||
|
|
fb08903a8a | ||
|
|
416005654e | ||
|
|
1debf77ab4 | ||
|
|
f1a8bb08da | ||
|
|
7edff12bbf | ||
|
|
27332931d0 | ||
|
|
34d601f49c | ||
|
|
ec38473d88 | ||
|
|
875c77ae65 | ||
|
|
75e24f9f79 | ||
|
|
16a4662129 | ||
|
|
1eda1eb9de | ||
|
|
d981fd35ef | ||
|
|
6f1dc44932 | ||
|
|
95b929dd27 | ||
|
|
0c75b98f48 | ||
|
|
ecc5a0bf8a | ||
|
|
d9315bec84 | ||
|
|
d1ee7f4353 | ||
|
|
979095337b | ||
|
|
34b528b1f4 | ||
|
|
5ea056a3fc | ||
|
|
2ba31244c2 | ||
|
|
3ea16694b4 | ||
|
|
35e872310d | ||
|
|
b86b24d444 | ||
|
|
45e1a6ffd6 | ||
|
|
c87f001956 | ||
|
|
1fc3b3a4ed | ||
|
|
c706a2d77c | ||
|
|
8577fc6701 | ||
|
|
ead3067d49 | ||
|
|
4772b8c5bb | ||
|
|
36e32b23e2 | ||
|
|
6817cfbeea | ||
|
|
f851238eab | ||
|
|
79157c465a | ||
|
|
64438f6b6d | ||
|
|
f2b914a4c5 | ||
|
|
da71004898 | ||
|
|
e9019b294a | ||
|
|
e2c3ea22e4 | ||
|
|
c7f3f20229 | ||
|
|
46dc024335 | ||
|
|
34c68cfef0 | ||
|
|
d6a564a38b | ||
|
|
31c69088ca | ||
|
|
49bb8fd515 | ||
|
|
b8f8a0d455 | ||
|
|
374e34a8b8 | ||
|
|
7ef1d72314 | ||
|
|
b9708c8d37 | ||
|
|
5666a3d74c | ||
|
|
8004b411da | ||
|
|
e473c46dc3 | ||
|
|
148309245b | ||
|
|
5dc39fe068 | ||
|
|
47c7a3c5e3 | ||
|
|
85b7e86e58 | ||
|
|
f871581997 | ||
|
|
3fca465f1d | ||
|
|
7955dd86f4 | ||
|
|
40a4e6d7b0 | ||
|
|
bef4ac83a4 | ||
|
|
bde83fc705 | ||
|
|
cad18bee73 | ||
|
|
98e5eaa4e0 | ||
|
|
3129e94363 | ||
|
|
7ac0e50bd9 | ||
|
|
10683d943f | ||
|
|
9ad8c6a96d | ||
|
|
c74d9bbafb | ||
|
|
7d502fae23 | ||
|
|
894eeef140 | ||
|
|
7991069282 | ||
|
|
39f3972a24 | ||
|
|
fc0e5ecd3b | ||
|
|
8897d9f82b | ||
|
|
1329b5f684 | ||
|
|
e58bc738d0 | ||
|
|
af63579f31 | ||
|
|
55fad3a9ec | ||
|
|
3250e0a1e6 | ||
|
|
8df287f45e | ||
|
|
f458a77449 | ||
|
|
1953c05b33 | ||
|
|
a03c553000 | ||
|
|
ecdc4076d9 | ||
|
|
cd2ea3793e | ||
|
|
d40ffd944f | ||
|
|
0ee4b52baa | ||
|
|
5e7db7a27e | ||
|
|
9631021f84 | ||
|
|
157193c831 | ||
|
|
1415f12506 | ||
|
|
4df497a768 | ||
|
|
9a13eb0f90 | ||
|
|
eaa49bce05 | ||
|
|
96334d859a | ||
|
|
13855b1501 | ||
|
|
22df5d09fb | ||
|
|
277b24e2f0 | ||
|
|
abb2a2a6e2 | ||
|
|
961f5fd387 | ||
|
|
bdb62de81c | ||
|
|
422a850792 | ||
|
|
1dfcc77098 | ||
|
|
13097d7e0e | ||
|
|
ea9b7eddde | ||
|
|
07056613e5 | ||
|
|
4d45793ec7 | ||
|
|
931593a59e | ||
|
|
4718133ab6 | ||
|
|
ba518fa975 | ||
|
|
0311e78690 | ||
|
|
9db47428db | ||
|
|
7092dc6f86 | ||
|
|
84dc3c2093 | ||
|
|
7d37b06555 | ||
|
|
6e6a89fb8c | ||
|
|
135d9c5e55 | ||
|
|
dd46048ea6 | ||
|
|
8fe38b03f6 | ||
|
|
0adadeb280 | ||
|
|
775a5122c9 | ||
|
|
5099060be2 | ||
|
|
c3f80a5876 | ||
|
|
201c93e20a | ||
|
|
c852d91a72 | ||
|
|
821eb4df8c | ||
|
|
a3c6e62bd5 | ||
|
|
8cd18fe190 | ||
|
|
5e1452f9b9 | ||
|
|
b76de65886 | ||
|
|
48b3bd8bf3 | ||
|
|
ab1715edec | ||
|
|
3589783ee1 | ||
|
|
af43e22f03 | ||
|
|
956f6403b8 | ||
|
|
e276587fdc | ||
|
|
82ed1853fa | ||
|
|
eb0403945b | ||
|
|
3126af94ac | ||
|
|
e71ad536a9 | ||
|
|
d0322b471d | ||
|
|
a6af11e644 | ||
|
|
1809180d41 | ||
|
|
9612b1b9e9 | ||
|
|
526d4c4d15 | ||
|
|
3f4c824fd5 | ||
|
|
9c25feb67c | ||
|
|
e31faf81a9 | ||
|
|
6eb13c24aa | ||
|
|
dd20017b0a | ||
|
|
6630051ef3 | ||
|
|
a66d91c507 | ||
|
|
2f34f0458b | ||
|
|
076abc8ae7 | ||
|
|
5134e57109 | ||
|
|
a454a43111 | ||
|
|
045f58144e | ||
|
|
8ffea22f0e | ||
|
|
c630676792 | ||
|
|
3d1ccf2028 | ||
|
|
60b980fbff | ||
|
|
df20f1b5ab | ||
|
|
27144f07b1 | ||
|
|
8135fdb9d2 | ||
|
|
985ad18048 | ||
|
|
768ed2666d | ||
|
|
0bbb586094 | ||
|
|
efa1f4ee43 | ||
|
|
e184eb6aae | ||
|
|
c289a53ed3 | ||
|
|
5c206718c8 | ||
|
|
d7f18e879a | ||
|
|
4881a2c274 | ||
|
|
5eb5fa05bc | ||
|
|
c7e0f36d7c | ||
|
|
6e9fcb81f0 | ||
|
|
54d54ca78e | ||
|
|
4cd591f81c | ||
|
|
774ecb4003 | ||
|
|
d21d732545 | ||
|
|
ea4854d239 | ||
|
|
7ca95b9413 | ||
|
|
00d0d383f8 | ||
|
|
401a8cdd77 | ||
|
|
b2384855fd | ||
|
|
602c087c29 | ||
|
|
0d96ed5436 | ||
|
|
c555d1274b | ||
|
|
97fa3ac3b3 | ||
|
|
261bc83811 | ||
|
|
2dbaf4dfa1 | ||
|
|
5df9f38391 | ||
|
|
93763c5932 | ||
|
|
242caff990 | ||
|
|
e97e9907c7 | ||
|
|
ac330b6665 | ||
|
|
a4a70a1287 | ||
|
|
dda8651ba2 | ||
|
|
83e2d48f4d | ||
|
|
a903711a7a | ||
|
|
9e17a611d2 | ||
|
|
1e11ed3041 | ||
|
|
0449470cdf | ||
|
|
21a5a2d4ef | ||
|
|
a848cb28f1 | ||
|
|
b7ae6b143e | ||
|
|
ba0c18eec1 | ||
|
|
61366b347d | ||
|
|
edab6643f6 | ||
|
|
ce36ef3aad | ||
|
|
fdb439f054 | ||
|
|
2229f3f015 | ||
|
|
18a5df1ce7 | ||
|
|
f5cb29fadd | ||
|
|
d929732fb6 | ||
|
|
6c36f3bc7c | ||
|
|
c6a59a5309 | ||
|
|
b02c30a525 | ||
|
|
46a647ae66 | ||
|
|
8943a67f85 | ||
|
|
f132d751f5 | ||
|
|
4ba8c9ff9e | ||
|
|
955ae6c392 | ||
|
|
ed33b327fb | ||
|
|
f8f7486be2 | ||
|
|
3215875e5f | ||
|
|
62da90418a | ||
|
|
7c620fae78 | ||
|
|
daef0c3a8f | ||
|
|
52b6d399a0 | ||
|
|
f210f63ec4 | ||
|
|
41694050ea | ||
|
|
3f612cfc90 | ||
|
|
272acdd8d3 | ||
|
|
5a4375cb71 | ||
|
|
5b3d7e2354 | ||
|
|
189cefac1b | ||
|
|
87d36914c4 | ||
|
|
72e14805b1 | ||
|
|
87e2f76793 | ||
|
|
8fbd53d72d | ||
|
|
586cc1f003 | ||
|
|
a77753cfef | ||
|
|
5e464ef3a2 | ||
|
|
0727c9774b | ||
|
|
ee43a365dc | ||
|
|
d5ba0d9ed5 | ||
|
|
7031a52a43 | ||
|
|
12af164dcc | ||
|
|
362cd72e87 | ||
|
|
cb19520b6b | ||
|
|
c74972488d | ||
|
|
b78e40153f | ||
|
|
f7212662b9 | ||
|
|
97c8e1f7a9 | ||
|
|
2afc6d1c62 | ||
|
|
708858da39 | ||
|
|
41dccb468e | ||
|
|
36cfe9e5c2 | ||
|
|
1c7fd57f2e | ||
|
|
f920851420 | ||
|
|
04b8fe3326 | ||
|
|
9fb4374efa | ||
|
|
885cabd6ef | ||
|
|
e00f9c2a83 | ||
|
|
fe24eda4b4 | ||
|
|
483d80b576 | ||
|
|
70a0a3c52e | ||
|
|
5b2f32c08a | ||
|
|
5bad1e1c88 | ||
|
|
2706ebf638 | ||
|
|
9fe3261424 | ||
|
|
9df087984f | ||
|
|
cbb9bcd93d | ||
|
|
ad8f7576e0 | ||
|
|
e205d85728 | ||
|
|
a01d5c2760 | ||
|
|
b57423386c | ||
|
|
22e525452a | ||
|
|
6c84074b02 | ||
|
|
6cc4a6e1be | ||
|
|
04e41ab676 | ||
|
|
3ad64d9823 | ||
|
|
8de7ff5470 | ||
|
|
0a44f34c2c | ||
|
|
4f900e36c1 | ||
|
|
571d90618e | ||
|
|
fe8436f2ad | ||
|
|
a4459901e8 | ||
|
|
bef8fd566f | ||
|
|
0f9994ac74 | ||
|
|
8691ccc013 | ||
|
|
bac7b50090 | ||
|
|
39ff1e318c | ||
|
|
1f8110573c | ||
|
|
7c128e0f6e | ||
|
|
11b50b4917 | ||
|
|
9d771be8b2 | ||
|
|
02315b8aa1 | ||
|
|
7fb3d133e3 | ||
|
|
65fb29a1d4 | ||
|
|
703a432f7b | ||
|
|
4d37942717 | ||
|
|
137067ea43 | ||
|
|
67e12dcc74 | ||
|
|
911c0d2c1b | ||
|
|
4b9648affa | ||
|
|
804afa65f2 | ||
|
|
c56dc6cade | ||
|
|
c4f7055e1a | ||
|
|
44b6dfab1d | ||
|
|
50e79b8c97 | ||
|
|
185825f83c | ||
|
|
c6be331f14 | ||
|
|
c0dd418992 | ||
|
|
c03d5167f6 | ||
|
|
56d625b7b9 | ||
|
|
e74b23f305 | ||
|
|
6e7d2abc9a | ||
|
|
3bebb9bf0f | ||
|
|
1063697e85 | ||
|
|
7bdad90564 | ||
|
|
1dccc54814 | ||
|
|
1c255213e1 | ||
|
|
cb2c172483 | ||
|
|
b43063a6d2 | ||
|
|
3974406f1b | ||
|
|
21aed2d2e1 | ||
|
|
820c257e96 | ||
|
|
56e5616080 | ||
|
|
6f7351ecc3 | ||
|
|
8f56032d49 | ||
|
|
1b6ca2ed14 | ||
|
|
d956682b9f | ||
|
|
76759f1847 | ||
|
|
d441595ee6 | ||
|
|
2be0250aee | ||
|
|
b2a3b10065 | ||
|
|
22b181a8f7 | ||
|
|
71d07be646 | ||
|
|
95e56e7148 | ||
|
|
ec471520f2 | ||
|
|
65b516d761 | ||
|
|
7d45d5e0ce | ||
|
|
d8e3966825 | ||
|
|
65409373eb | ||
|
|
50a1449a2a | ||
|
|
8150faaa40 | ||
|
|
019542ff10 | ||
|
|
20def0de02 | ||
|
|
4a30a875f0 | ||
|
|
61905f111b | ||
|
|
1832d72e51 | ||
|
|
4d63b9e463 | ||
|
|
7b54f51d75 | ||
|
|
eaf94bc10a | ||
|
|
9d6b5d347c | ||
|
|
e82a16146e | ||
|
|
9797021511 | ||
|
|
c27a9e8193 | ||
|
|
c5506dab5d | ||
|
|
d120109a78 | ||
|
|
b529f3d4cc | ||
|
|
ea11b76461 | ||
|
|
09c54d4fed | ||
|
|
c5f00c5363 | ||
|
|
256808c473 | ||
|
|
487d89d970 | ||
|
|
ed3665b8c5 | ||
|
|
ef7a9ff02e | ||
|
|
aa4416ac4e | ||
|
|
c734eec9e1 | ||
|
|
e1caf61a18 | ||
|
|
f7879256c1 | ||
|
|
1c86eba9d9 | ||
|
|
6a089aa1b7 | ||
|
|
9a3749c1ed | ||
|
|
d82b755557 | ||
|
|
5b83f2a554 | ||
|
|
1f2b01937b | ||
|
|
18bd0ae096 | ||
|
|
512f368cbf | ||
|
|
853d9ee87f | ||
|
|
e9440d0d4c | ||
|
|
381a988f43 | ||
|
|
5d6ec4ce56 | ||
|
|
182e644a33 | ||
|
|
c719fbf7fc | ||
|
|
9c3b053727 | ||
|
|
d32db977eb | ||
|
|
1eca74180c | ||
|
|
0210e090f2 | ||
|
|
baf413ee55 | ||
|
|
8e6c001bf3 | ||
|
|
127e940ed4 | ||
|
|
aa8072118d | ||
|
|
f07bbfa174 | ||
|
|
e3a2c5b05b | ||
|
|
3ba5e30a96 | ||
|
|
7bf49011a3 | ||
|
|
bd84dd9f2c | ||
|
|
c3fbdc907c | ||
|
|
f7817714a8 | ||
|
|
c485286114 | ||
|
|
bd8e44f835 | ||
|
|
eddf4226b7 | ||
|
|
804578e38d | ||
|
|
d464fe5d67 | ||
|
|
885428627f | ||
|
|
4c90a90131 | ||
|
|
ec2aadb7cf | ||
|
|
9d5ab75dbd | ||
|
|
d5b145e052 | ||
|
|
163f5dba8a | ||
|
|
e026ecf92f | ||
|
|
dcda5084d0 | ||
|
|
496441cae6 | ||
|
|
cf75937b1d | ||
|
|
d7fc003216 | ||
|
|
de54575e04 | ||
|
|
12093c311c | ||
|
|
5b9ca03fa6 | ||
|
|
bb820ab388 | ||
|
|
c68f56ecd4 | ||
|
|
910bae64e9 | ||
|
|
40258fb02a | ||
|
|
011ed65ea1 | ||
|
|
411d934e6a | ||
|
|
582de40960 | ||
|
|
79d7ac7c8e | ||
|
|
6d86bd516b | ||
|
|
f71bf1416c | ||
|
|
8a1a27ee19 | ||
|
|
dc30cb2e4a | ||
|
|
24e669c65b | ||
|
|
80e6ba2d96 | ||
|
|
beef4b2738 | ||
|
|
56f1369000 | ||
|
|
7bcde47081 | ||
|
|
35663281fa | ||
|
|
0b8f75f799 | ||
|
|
7309c046ae | ||
|
|
6dfd44b731 | ||
|
|
d6e7309c34 | ||
|
|
e15bad7d3b | ||
|
|
4450d6af2f | ||
|
|
efa7a4ee55 | ||
|
|
757130847f | ||
|
|
c562098ef7 | ||
|
|
42606873af | ||
|
|
df8b73999f | ||
|
|
234b0e6825 | ||
|
|
6ca9f8ad31 | ||
|
|
dbc0971b99 | ||
|
|
26127c8218 | ||
|
|
f4b8b4cae3 | ||
|
|
d641ff3ab7 | ||
|
|
a08904a936 | ||
|
|
c13158cdb5 | ||
|
|
70a8c50d47 | ||
|
|
991c87530f | ||
|
|
9d5156e0e0 | ||
|
|
ec3ac05a1f | ||
|
|
a20fe37e98 | ||
|
|
ee76eaedd6 | ||
|
|
b90b200cd1 | ||
|
|
873af8865c | ||
|
|
906ac14fa9 | ||
|
|
fcffe9d188 | ||
|
|
a84748a544 | ||
|
|
320c7646f0 | ||
|
|
f4f3c3bd37 | ||
|
|
2bb6acfa22 | ||
|
|
da5a8b0fd1 | ||
|
|
aa22956f87 | ||
|
|
8b300358e9 | ||
|
|
54c5edc5da | ||
|
|
5f08d98f66 | ||
|
|
4d45f8d012 | ||
|
|
b1c48929e4 | ||
|
|
612479b632 | ||
|
|
013dcdf93e | ||
|
|
d22d3945ee | ||
|
|
d4960080ea | ||
|
|
4bc3d0ce2d | ||
|
|
e1243532ba | ||
|
|
f41a80a309 | ||
|
|
b447418f07 | ||
|
|
95b523c2fa | ||
|
|
7dadd6e410 | ||
|
|
8ec75b9d45 | ||
|
|
e4b3086429 | ||
|
|
c56bda2f60 | ||
|
|
56566d83fd | ||
|
|
0e4dc43171 | ||
|
|
7154aa05a6 | ||
|
|
1e80d76383 | ||
|
|
0ca2e33e7c | ||
|
|
38b10b6c10 | ||
|
|
e9444d3055 | ||
|
|
7e884dc69f | ||
|
|
24c7ff4cfa | ||
|
|
456f8be6e5 | ||
|
|
dfab460478 | ||
|
|
04154fa40c | ||
|
|
6e9fab849c | ||
|
|
06555eb03e | ||
|
|
6b8d1b4b76 | ||
|
|
73d9ea42f0 | ||
|
|
06f648b714 | ||
|
|
155034092f | ||
|
|
11af11b3be | ||
|
|
3246c36984 | ||
|
|
c12a5cc98b | ||
|
|
18ee7b194d | ||
|
|
14c0733949 | ||
|
|
f3a2a24ee4 | ||
|
|
26ec1269a5 | ||
|
|
2811eb66c5 | ||
|
|
9b0ccb8943 | ||
|
|
e33bdab4e9 | ||
|
|
573b5fc879 | ||
|
|
678821d54d | ||
|
|
5772042dd3 | ||
|
|
7868a38137 | ||
|
|
7bccfef3bd | ||
|
|
736838474a | ||
|
|
d553fad58d | ||
|
|
9e66ef5460 | ||
|
|
9550ec6efd | ||
|
|
bc9e1b1d94 | ||
|
|
7672858d6b | ||
|
|
2a2a9ab8b7 | ||
|
|
d8354c6666 | ||
|
|
ba04725ee3 | ||
|
|
7664633f18 | ||
|
|
edcc211988 | ||
|
|
389e8f2de6 | ||
|
|
070ac49d1b | ||
|
|
40dbb2ce17 | ||
|
|
cd5dd04352 | ||
|
|
592792dd7a | ||
|
|
cfe892d35e | ||
|
|
e01f48303b | ||
|
|
f0c8b348c6 | ||
|
|
ac5d24a848 | ||
|
|
e8a37ff0af | ||
|
|
a60a8c0c4f | ||
|
|
e78f8c803e | ||
|
|
6ea0ba52d1 | ||
|
|
8b0d9670f9 | ||
|
|
440dd90316 | ||
|
|
5f86a60954 | ||
|
|
50e0ea5ec5 | ||
|
|
b566bead31 | ||
|
|
52731d7b0a | ||
|
|
465532014b | ||
|
|
7153ae9614 | ||
|
|
0feb0fe972 | ||
|
|
b3cdbfc71b | ||
|
|
3a32bd62ef | ||
|
|
c1adf880a4 | ||
|
|
b0332b6ef5 | ||
|
|
965e7b48df | ||
|
|
27f41baa9a | ||
|
|
43615450ad | ||
|
|
956b8958fb | ||
|
|
024459408a | ||
|
|
78ccc44014 | ||
|
|
85397c4e28 | ||
|
|
0253f7d069 | ||
|
|
ddcb709fd1 | ||
|
|
a7d11c6670 | ||
|
|
bbb4959f22 | ||
|
|
254b3fe9aa | ||
|
|
35c016482b | ||
|
|
62895eedb7 | ||
|
|
32809ae7d4 | ||
|
|
73e1e3422d | ||
|
|
2d9041c045 | ||
|
|
60d6bb79b3 | ||
|
|
6afb3a06ac | ||
|
|
3cdf22e9b2 | ||
|
|
b05b41c7cc | ||
|
|
114a340527 | ||
|
|
cfa5163590 | ||
|
|
53535dd82d | ||
|
|
34f17074ca | ||
|
|
157d404019 | ||
|
|
d1ef987dca | ||
|
|
fd8c7c99bd | ||
|
|
4295437b3e | ||
|
|
92a08a1865 | ||
|
|
fbd7abf4e2 | ||
|
|
306ec09118 | ||
|
|
a5e41b224f | ||
|
|
4abcf75b34 | ||
|
|
7131a505be | ||
|
|
9b42af0149 | ||
|
|
27b9748f86 | ||
|
|
1301aa5c35 | ||
|
|
1b80789288 | ||
|
|
ca0232ae7b | ||
|
|
2fb0ecc446 | ||
|
|
0c41db76e2 | ||
|
|
e120b149dc | ||
|
|
e33596960a | ||
|
|
d04fb645ec | ||
|
|
87c5ee67c0 | ||
|
|
a53a046351 | ||
|
|
afda182b4e | ||
|
|
d883e3e661 | ||
|
|
c9526130b7 | ||
|
|
d6e3c7d1b7 | ||
|
|
0fdf6bfbb2 | ||
|
|
e628c68f09 | ||
|
|
8f858c2ddf | ||
|
|
f8f6e201b9 | ||
|
|
52f56e1bb0 | ||
|
|
187f7e591e | ||
|
|
272e8eac4f | ||
|
|
d423d741b2 | ||
|
|
102b2d76f4 | ||
|
|
bb31cedcba | ||
|
|
bf02e04ae5 | ||
|
|
c66884be0a | ||
|
|
e7b94d3132 | ||
|
|
b219161011 | ||
|
|
fd7d30333f | ||
|
|
d734cdaf48 | ||
|
|
f60d0b10e0 | ||
|
|
a1c6e32e28 | ||
|
|
156cb03069 | ||
|
|
cdb75729cb | ||
|
|
d1a812f04c | ||
|
|
b190ba1268 | ||
|
|
87ed90a825 | ||
|
|
a03a4af1e6 | ||
|
|
e48e4e7139 | ||
|
|
6ef31b7983 | ||
|
|
d378658a62 | ||
|
|
ed02758940 | ||
|
|
b28c45c84c | ||
|
|
42af530c63 | ||
|
|
7c3de1e976 | ||
|
|
afdd43c5e3 | ||
|
|
5bc756716e | ||
|
|
6a6c069896 | ||
|
|
9499799f80 | ||
|
|
5632f9786c | ||
|
|
6f79e07e90 | ||
|
|
601f18bbab | ||
|
|
6f750cf584 | ||
|
|
3b7c92d022 | ||
|
|
af12b47c90 | ||
|
|
2d9140e56c | ||
|
|
0351ff30b4 | ||
|
|
6d13dac2c3 | ||
|
|
e2174b9ad4 | ||
|
|
2038785b09 | ||
|
|
0c8650d2e5 | ||
|
|
3e7edea7be | ||
|
|
b3d625b9fc | ||
|
|
d02fb69ca7 | ||
|
|
8cf4bc58a7 | ||
|
|
b8aed0f004 | ||
|
|
03a6473bd4 | ||
|
|
7d95c02b57 | ||
|
|
767507d195 | ||
|
|
1d96cbeb07 | ||
|
|
0bf33ec7e9 | ||
|
|
37196b42ed | ||
|
|
5f7453d031 | ||
|
|
88b7ef5345 | ||
|
|
213d591eb0 | ||
|
|
c04f73e86b | ||
|
|
2033c171f0 | ||
|
|
8ce708dade | ||
|
|
fa60322ff1 | ||
|
|
e9bcd170c0 | ||
|
|
118b5c8a7d | ||
|
|
b5bcfa8d90 | ||
|
|
e496ab06b2 | ||
|
|
d7c960e150 | ||
|
|
9de7b4ba35 | ||
|
|
bb1a18f187 | ||
|
|
68cdd6b8a9 | ||
|
|
34dab0c498 | ||
|
|
f9511aba17 | ||
|
|
d96015f2c1 | ||
|
|
e66d577f21 | ||
|
|
47653eeba7 | ||
|
|
a0463c85a1 | ||
|
|
519093dceb | ||
|
|
08c5d0e4c1 | ||
|
|
cae4526b3b | ||
|
|
79381d7fd2 | ||
|
|
d8c141b1c9 | ||
|
|
3b3f4044cb | ||
|
|
c0256428f9 | ||
|
|
85a5ddb980 | ||
|
|
06bc58f383 | ||
|
|
b739c00414 | ||
|
|
d65bd97956 | ||
|
|
b952f9da4a | ||
|
|
388b3257fc | ||
|
|
6318077278 | ||
|
|
9fee51bafb | ||
|
|
397ec9587b | ||
|
|
862d08f57d | ||
|
|
ebb541e4f5 | ||
|
|
e05d780bec | ||
|
|
84b383154d | ||
|
|
f458826643 | ||
|
|
5d808992e6 | ||
|
|
03f9a9fcac | ||
|
|
7ea9b5b2f3 | ||
|
|
b8fc24f093 | ||
|
|
bddba15403 | ||
|
|
894f1c4f28 | ||
|
|
19665d4ad9 | ||
|
|
18a8e86b2a | ||
|
|
3af724a941 | ||
|
|
5b378ee9dd | ||
|
|
d5889a90d4 | ||
|
|
81c8eb2830 | ||
|
|
507a073203 | ||
|
|
abe67d9e4e | ||
|
|
741f44e8b7 | ||
|
|
c715b9488a | ||
|
|
5107ef5119 | ||
|
|
ca28eeb596 | ||
|
|
f51eb96c69 | ||
|
|
b032299b05 | ||
|
|
5a2576bc29 | ||
|
|
3375629d06 | ||
|
|
37232bc222 | ||
|
|
d2f0deec9c | ||
|
|
5a25e44177 | ||
|
|
08d9d58894 | ||
|
|
0254a75c95 | ||
|
|
a7cfcefee2 | ||
|
|
f78c057b45 | ||
|
|
4bd3084403 | ||
|
|
9d817f0c77 | ||
|
|
68b8cc1d20 | ||
|
|
fb8b0f4f65 | ||
|
|
94d45fc77f | ||
|
|
5144f62da9 | ||
|
|
a58ba7fcc5 | ||
|
|
17bec06c98 | ||
|
|
d531ec846f | ||
|
|
07849922b8 | ||
|
|
63ba267da0 | ||
|
|
93526c8a44 | ||
|
|
c7c2f4a482 | ||
|
|
dc0e739667 | ||
|
|
e74b2e32c9 | ||
|
|
a2dd9b1d48 | ||
|
|
474fdc0473 | ||
|
|
e6ab3ac9f9 | ||
|
|
ae59780297 | ||
|
|
cbdafbf264 | ||
|
|
76fa4a3090 | ||
|
|
896c6b79db | ||
|
|
bb052f30d6 | ||
|
|
ebbff7f615 | ||
|
|
9d76ac96bc | ||
|
|
1926a40277 | ||
|
|
6cd108badf | ||
|
|
5993d74eec | ||
|
|
84b98a2265 | ||
|
|
0df071b4db | ||
|
|
bfd092b499 | ||
|
|
23f2ea5031 | ||
|
|
29165b8ef4 | ||
|
|
c862179465 | ||
|
|
7a371f8b26 | ||
|
|
7a7b968c1b | ||
|
|
9571404907 | ||
|
|
ae946f6821 | ||
|
|
6128625706 | ||
|
|
ea2a3c1980 | ||
|
|
9b6814aee9 | ||
|
|
6544659251 | ||
|
|
dcff39da25 | ||
|
|
94ba32af57 | ||
|
|
cc08613304 | ||
|
|
95941f4dc5 | ||
|
|
3f2e20fe44 | ||
|
|
67124a4104 | ||
|
|
174bcf56d3 | ||
|
|
d9fd3b47e1 | ||
|
|
89492f8904 | ||
|
|
42dc73964c | ||
|
|
449316257a | ||
|
|
3b621adcb2 | ||
|
|
8d9d4e67ca | ||
|
|
eb43a02bce | ||
|
|
7f034f60d6 | ||
|
|
c4cf10b6e6 | ||
|
|
b2a1404ce0 | ||
|
|
52a97db259 | ||
|
|
e5ccb4271e | ||
|
|
27a2614b7d | ||
|
|
5cc39848ff | ||
|
|
b9d719d636 | ||
|
|
3e6b3a2755 | ||
|
|
88167fb3ae | ||
|
|
b5685a9d76 | ||
|
|
4c652a87c0 | ||
|
|
1f8bd69aef | ||
|
|
71d9bb18e5 | ||
|
|
067b3364ee | ||
|
|
b2494ebaf7 | ||
|
|
f73ca10b6c | ||
|
|
fe23e099fe | ||
|
|
333411535e | ||
|
|
cc6272e84a | ||
|
|
c7857835c7 | ||
|
|
9bfaf10468 | ||
|
|
095d5c9442 | ||
|
|
4fa6f85c2e | ||
|
|
76a9978fc5 | ||
|
|
4b46b2776a | ||
|
|
907505ccf9 | ||
|
|
3e35dafefb | ||
|
|
11ee5126ef | ||
|
|
37bdb1ba2f | ||
|
|
a9fc1083c7 | ||
|
|
9be804fb35 | ||
|
|
38a466fc21 | ||
|
|
aa5ee45034 | ||
|
|
5b1e1d0d6a | ||
|
|
a818a09469 | ||
|
|
0d439a08fc | ||
|
|
9032f25d64 | ||
|
|
28efea7ac1 | ||
|
|
f2f0badc77 | ||
|
|
00e3d5c0d2 | ||
|
|
c08edc207c | ||
|
|
6477e2e1bb | ||
|
|
694da178c4 | ||
|
|
d80b890cd0 | ||
|
|
6b9c038b31 | ||
|
|
b071f920e9 | ||
|
|
3cd28d1559 | ||
|
|
72563d8ef1 | ||
|
|
375798a344 | ||
|
|
b401c65684 | ||
|
|
d7c78b3ce2 | ||
|
|
4a4c03a225 | ||
|
|
85b31701f4 | ||
|
|
28b3110895 | ||
|
|
011e6d895b | ||
|
|
0f7099acfa | ||
|
|
96296fe211 | ||
|
|
51a60e637c | ||
|
|
078f13fdb1 | ||
|
|
c210afd086 | ||
|
|
81d9071b01 | ||
|
|
94ca9c4df9 | ||
|
|
bff2ae319f | ||
|
|
5bd30381cf | ||
|
|
121a615ce3 | ||
|
|
5877b66c83 | ||
|
|
1ba86a91f9 | ||
|
|
e56847ee8d | ||
|
|
1fbbfd1063 | ||
|
|
1fed66fff3 | ||
|
|
c607a7e35d | ||
|
|
06d6968951 | ||
|
|
7ed8a9f638 | ||
|
|
52595138cd | ||
|
|
eca2b01307 | ||
|
|
df758679cc | ||
|
|
6b6300d117 | ||
|
|
b535e11f5a | ||
|
|
a4ad8d0a61 | ||
|
|
e66eb537d8 | ||
|
|
b8ef2e68ba | ||
|
|
30b10d3b6b | ||
|
|
f09347841c | ||
|
|
f87e8ca522 | ||
|
|
2871f64f68 | ||
|
|
cd1c5f5799 | ||
|
|
890fcac73f | ||
|
|
d7851ed090 | ||
|
|
678df3cc46 | ||
|
|
2f48b2e302 | ||
|
|
a816a6ff8d | ||
|
|
b189d2a39b | ||
|
|
5424682fdb | ||
|
|
ad3ce7c536 | ||
|
|
d4dd300e28 | ||
|
|
99fd6b97db | ||
|
|
684e9e3537 | ||
|
|
1bde863124 | ||
|
|
5c34e3d988 | ||
|
|
b7c4e084f3 | ||
|
|
36395ae355 | ||
|
|
f4881d11c7 | ||
|
|
bbde89e0f9 | ||
|
|
fb22107be8 | ||
|
|
5ada93b46c | ||
|
|
b798b43733 | ||
|
|
1669eb3759 | ||
|
|
071316c606 | ||
|
|
d8b5dd7bd2 | ||
|
|
868c1cface | ||
|
|
8e83baf72b | ||
|
|
54858c63f5 | ||
|
|
bc3d03c462 | ||
|
|
c94476b9a2 | ||
|
|
73812dc400 | ||
|
|
cfdc7eb74a | ||
|
|
a0ad331023 | ||
|
|
2561358f9d | ||
|
|
3fd7dae8f9 | ||
|
|
426a0933b1 | ||
|
|
2f8062d296 | ||
|
|
d18165ebe9 | ||
|
|
38796f9d0c | ||
|
|
79b887d189 | ||
|
|
8dc92e7ccf | ||
|
|
e04e5913de | ||
|
|
5c734cdabc | ||
|
|
f924e99f70 | ||
|
|
e179825896 | ||
|
|
94a561f0e4 | ||
|
|
56e14fc107 | ||
|
|
29f0b74824 | ||
|
|
de682d5530 | ||
|
|
571a3341da | ||
|
|
8edf7f2d60 | ||
|
|
5408545c07 | ||
|
|
d504fb209f | ||
|
|
ee53c3a71e | ||
|
|
bcf88d24f3 | ||
|
|
b2935139b4 | ||
|
|
635e7cfeec | ||
|
|
49b6c3bed7 | ||
|
|
3f7ab67506 | ||
|
|
df26833eb1 | ||
|
|
df1ebaebf9 | ||
|
|
26bd04857d | ||
|
|
4c4ed14af5 | ||
|
|
f0c5a1b382 | ||
|
|
59ebc49d46 | ||
|
|
bfde101f6b | ||
|
|
2a0dce848c | ||
|
|
d759fed5e4 | ||
|
|
f731abe4e8 | ||
|
|
74111212a3 | ||
|
|
f86c1a87f9 | ||
|
|
1f2493914f | ||
|
|
e3efa7dc3d | ||
|
|
6612782021 | ||
|
|
bdaabcea93 | ||
|
|
e6b6be2624 | ||
|
|
b1f1c10878 | ||
|
|
d5b0bb021f | ||
|
|
dd70275b41 | ||
|
|
6aa782bd8b | ||
|
|
029545703f | ||
|
|
8183674fc6 | ||
|
|
7391f64776 | ||
|
|
776385cdc9 | ||
|
|
17bafc037c | ||
|
|
e785352050 | ||
|
|
43e4408df1 | ||
|
|
78a68bb361 | ||
|
|
ec2a2d3505 | ||
|
|
2625477d35 | ||
|
|
a655dd639d | ||
|
|
3e61fd2452 | ||
|
|
c11753d91c | ||
|
|
5884e6b3cf | ||
|
|
46e4ba4518 | ||
|
|
a9c9e48cdb | ||
|
|
e32c1a4447 | ||
|
|
fb99c25594 | ||
|
|
6011aa2ac9 | ||
|
|
048c1ecf72 | ||
|
|
40360da454 | ||
|
|
0ce9ff4557 | ||
|
|
625bfbb6fe | ||
|
|
4290d94841 | ||
|
|
8ff2151448 | ||
|
|
610d69fb2e | ||
|
|
822308b3a4 | ||
|
|
c1d1e562ad | ||
|
|
379a0bd785 | ||
|
|
a477443c8d | ||
|
|
ed693c03ab |
103
.doc/README.md
Normal file
103
.doc/README.md
Normal file
@@ -0,0 +1,103 @@
|
||||
# Phpdoc dokuwiki template
|
||||
This directory contains a template rendering iTop phpdoc as wiki pages.
|
||||
|
||||
|
||||
conventional tag that you should use:
|
||||
* `@internal` : exclude from the documentation.
|
||||
* `@api` : it means that a method is an api, thus it may be interacted with.
|
||||
* `@see` : it points to another documented method
|
||||
* `@link` : external url
|
||||
* if you point to another page of the wiki, please use relative links.
|
||||
* `@example` : let you provide example of code
|
||||
* `@param`, `@return`, `@throws`, ...
|
||||
|
||||
|
||||
## Special instructions
|
||||
|
||||
some tags where added :
|
||||
* `@api-advanced`: it means that a method is an `@api` but mark it also as "complex" to use
|
||||
* `@overwritable-hook`: used to mark a method as "designed to be extended"
|
||||
* `@extension-hook`: not used for now
|
||||
* `@phpdoc-tuning-exclude-inherited`: once this tag is present on a class, it's inherited methods won't be showed.
|
||||
|
||||
|
||||
### known limitations:
|
||||
#### `@see` tags must be very specific:
|
||||
* always prefix class members with `ClassName::`
|
||||
* for methods always suffix them with `()`,
|
||||
* do not reference variables since they are not documented. If you have to, always prefix them with `$`
|
||||
|
||||
examples:
|
||||
```
|
||||
/**
|
||||
* @see DBObject
|
||||
* @see DBObject::Get()
|
||||
* @see DBObject::$foo
|
||||
*/
|
||||
```
|
||||
|
||||
#### Do not use inline tags, they do not work properly, example:
|
||||
```
|
||||
/**
|
||||
* This is a texts with ans inline tag {@see [FQSEN] [<description>]} it must never be used
|
||||
*/
|
||||
```
|
||||
|
||||
#### The `@example` tag must respect this very precise syntax
|
||||
* the sentence in the first line (next to the tag) is the title, it must be enclose by double quotes
|
||||
* the following lines are the sample code.
|
||||
* 💔 since we simply hack the official tag, this syntax must be respected carefully 💔
|
||||
example:
|
||||
```
|
||||
/**
|
||||
* @example "This is the title of the multiline example"
|
||||
* $foo = DBObject::Get('foo');
|
||||
* DBObject::Set('foo', ++$foo);
|
||||
*/
|
||||
```
|
||||
|
||||
## How content is included into the documentation
|
||||
|
||||
**For a class** those requirements have to be respected:
|
||||
- the file containing the class must be listed in `/phpdoc/files/file[]` of `.doc/phpdoc-objects-manipulation.dist.xml`
|
||||
- the class **must not** have the tag `@internal`
|
||||
- the class **must** have at least one of: `@api`, `@api-advanced`, `@overwritable-hook`, `@extension-hook`
|
||||
|
||||
Then, **for a method** of an eligible class:
|
||||
- **public** methods **must** have at least one of: `@api`, `@api-advanced`, `@overwritable-hook`, `@extension-hook`
|
||||
- **protected** methods **must** have at least one of: `@overwritable-hook`, `@extension-hook`
|
||||
- **private** methods are **always excluded**
|
||||
|
||||
**Class properties** and **constants** are never documented (this is subject to change).
|
||||
|
||||
|
||||
|
||||
|
||||
## A note about the rendering engine
|
||||
|
||||
:notebook: as spaces are used to mark code, the templates (`.doc/phpdoc-templates/combodo-wiki/*`) have very few indentation, thus they are awful to read (sorry).
|
||||
|
||||
|
||||
|
||||
|
||||
## Installation
|
||||
```
|
||||
composer require phpdocumentor/phpdocumentor:~2 --dev
|
||||
```
|
||||
|
||||
## Generation
|
||||
`.doc/bin/build-doc-object-manipulation` and `.doc/bin/build-doc-extensions` contains examples of doc. generation, beware: they have to be called from iTop root directory:
|
||||
```shell
|
||||
cd /path/to/itop/
|
||||
./.doc/bin/build-doc-object-manipulation
|
||||
```
|
||||
|
||||
the resulting documentation is written into `data/phpdocumentor/output`
|
||||
|
||||
|
||||
## Dokuwiki requirements
|
||||
* the template uses the [wrap plugin](https://www.dokuwiki.org/plugin:wrap).
|
||||
* the generated files have to be placed under an arbitrary directory of `[/path/to/dokuwiki]/data/pages`.
|
||||
* the html has to be activated [config:htmlok](https://www.dokuwiki.org/config:htmlok)
|
||||
* the generated files have to be in lowercase
|
||||
|
||||
7
.doc/bin/build-doc-extensions
Executable file
7
.doc/bin/build-doc-extensions
Executable file
@@ -0,0 +1,7 @@
|
||||
#!/bin/sh -x
|
||||
|
||||
rm -rf /tmp/phpdoc-twig-cache/ && rm -rf data/phpdocumentor/output/extensions/ && rm -rf data/phpdocumentor/temp/extensions/ && vendor/bin/phpdoc -c .doc/phpdoc-extensions.dist.xml -vvv
|
||||
|
||||
# now wee need to lowercase every generated file because dokuwiki can't handle uppercase
|
||||
cd data/phpdocumentor/output/extensions/
|
||||
for i in $( ls | grep [A-Z] ); do mv -i $i `echo $i | tr 'A-Z' 'a-z'`; done
|
||||
8
.doc/bin/build-doc-object-manipulation
Executable file
8
.doc/bin/build-doc-object-manipulation
Executable file
@@ -0,0 +1,8 @@
|
||||
#!/bin/sh -x
|
||||
|
||||
rm -rf /tmp/phpdoc-twig-cache/ && rm -rf data/phpdocumentor/output/objects-manipulation/ && rm -rf data/phpdocumentor/temp/objects-manipulation/ && vendor/bin/phpdoc -c .doc/phpdoc-objects-manipulation.dist.xml -vvv
|
||||
|
||||
|
||||
# now wee need to lowercase every generated file because dokuwiki can't handle uppercase
|
||||
cd data/phpdocumentor/output/objects-manipulation/
|
||||
for i in $( ls | grep [A-Z] ); do mv -i $i `echo $i | tr 'A-Z' 'a-z'`; done
|
||||
20
.doc/phpdoc-extensions.dist.xml
Executable file
20
.doc/phpdoc-extensions.dist.xml
Executable file
@@ -0,0 +1,20 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<phpdoc>
|
||||
<title><![CDATA[iTop extensions]]></title>
|
||||
|
||||
<parser>
|
||||
<target>../data/phpdocumentor/temp/extensions</target>
|
||||
</parser>
|
||||
|
||||
<transformer>
|
||||
<target>../data/phpdocumentor/output/extensions</target>
|
||||
</transformer>
|
||||
|
||||
<transformations>
|
||||
<template name="phpdoc-templates/combodo-wiki"/>
|
||||
</transformations>
|
||||
|
||||
<files>
|
||||
<file>../application/applicationextension.inc.php</file>
|
||||
</files>
|
||||
</phpdoc>
|
||||
58
.doc/phpdoc-objects-manipulation.dist.xml
Executable file
58
.doc/phpdoc-objects-manipulation.dist.xml
Executable file
@@ -0,0 +1,58 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<phpdoc>
|
||||
|
||||
<!--
|
||||
/**
|
||||
The documentation of this file can be found here : https://docs.phpdoc.org/references/configuration.html
|
||||
it has to be completed by the CLI parameters documentation which is more comprehensive: https://docs.phpdoc.org/references/commands/project_run.html#usage
|
||||
|
||||
usage:
|
||||
vendor/bin/phpdoc -c phpdoc-objects-manipulation.dist.xml
|
||||
|
||||
*/
|
||||
-->
|
||||
|
||||
<title><![CDATA[iTop's objects manipulation API]]></title>
|
||||
|
||||
<parser>
|
||||
<default-package-name>iTopORM</default-package-name>
|
||||
<target>../data/phpdocumentor/temp/objects-manipulation</target>
|
||||
<visibility>public,protected</visibility>
|
||||
<markers>
|
||||
<!--<item>TODO</item>-->
|
||||
<!--<item>FIXME</item>-->
|
||||
</markers>
|
||||
<extensions>
|
||||
<extension>php</extension>
|
||||
</extensions>
|
||||
</parser>
|
||||
|
||||
<transformer>
|
||||
<target>../data/phpdocumentor/output/objects-manipulation</target>
|
||||
</transformer>
|
||||
|
||||
<transformations>
|
||||
<template name="phpdoc-templates/combodo-wiki"/>
|
||||
</transformations>
|
||||
|
||||
<!--<logging>-->
|
||||
<!--<level>warn</level>-->
|
||||
<!--<paths>-->
|
||||
<!--<!–<default>data/phpdocumentor/log/objects-manipulation/{DATE}.log</default>–>-->
|
||||
<!--<!–<errors>data/phpdocumentor/log/objects-manipulation/{DATE}.errors.log</errors>–>-->
|
||||
|
||||
<!--<default>{APP_ROOT}/data/log/{DATE}.log</default>-->
|
||||
<!--<errors>{APP_ROOT}/data/log/{DATE}.errors.log</errors>-->
|
||||
<!--</paths>-->
|
||||
<!--</logging>-->
|
||||
|
||||
<files>
|
||||
<file>../core/dbobject.class.php</file>
|
||||
<file>../core/dbobjectsearch.class.php</file>
|
||||
<file>../core/metamodel.class.php</file>
|
||||
<file>../core/dbobjectset.class.php</file>
|
||||
<file>../core/dbsearch.class.php</file>
|
||||
<file>../core/dbunionsearch.class.php</file>
|
||||
</files>
|
||||
|
||||
</phpdoc>
|
||||
0
.doc/phpdoc-templates/.placeholder
Normal file
0
.doc/phpdoc-templates/.placeholder
Normal file
136
.doc/phpdoc-templates/combodo-wiki/class.txt.twig
Normal file
136
.doc/phpdoc-templates/combodo-wiki/class.txt.twig
Normal file
@@ -0,0 +1,136 @@
|
||||
{% extends 'layout.txt.twig' %}
|
||||
|
||||
{% block content %}
|
||||
<wrap button>[[start|🔙 Back]]</wrap>
|
||||
|
||||
{% if node.tags['internal'] is defined %}
|
||||
====== {{ node.name }} ======
|
||||
<WRAP alert>This class is "internal", and thus is not documented!</WRAP>
|
||||
{% elseif node.tags['api'] is not defined and node.tags['api-advanced'] is not defined and node.tags['overwritable-hook'] is not defined and node.tags['extension-hook'] is not defined %}
|
||||
====== {{ node.name }} ======
|
||||
<WRAP alert>This class is neither "api", "api-advanced", "overwritable-hook" or "extension-hook", and thus is not documented!</WRAP>
|
||||
{% else %}
|
||||
|
||||
====== {{ node.name }} ======
|
||||
|
||||
{% if node.deprecated %}<wrap danger>deprecated</wrap>{% endif %}
|
||||
{% if node.abstract %}<wrap warning>abstract</wrap>{% endif %}
|
||||
{% if node.final %}<wrap notice>final</wrap>{% endif %}
|
||||
{% include 'includes/wrap-tags.txt.twig' with {structure:node, wrap: 'safety', wrapTags: ['api', 'api-advanced', 'overwritable-hook', 'extension-hook']} %}
|
||||
|
||||
|
||||
|
||||
{% if node.deprecated %}
|
||||
=== **<del>Deprecated</del>**===
|
||||
//{{ node.tags.deprecated[0].description }}//
|
||||
{% endif %}
|
||||
|
||||
|
||||
== {{ node.summary|replace({"\n":""})|raw }} ==
|
||||
<html>{{ node.description|markdown|raw }}</html>
|
||||
|
||||
|
||||
{% include 'includes/code-examples.txt.twig' with {structure:node, title_level: '====='} %}
|
||||
|
||||
|
||||
{% set class = node.parent %}
|
||||
{% block hierarchy_element %}
|
||||
|
||||
{% if class and class.name is defined and class.name|trim != '' %}
|
||||
==== parent ====
|
||||
{% set child = class %}
|
||||
{% set class = class.parent %}
|
||||
{{ block('hierarchy_element') }}
|
||||
[[{{ child.name }}|{{ child.name }}]]
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
|
||||
|
||||
{% for interface in node.interfaces|sort_asc %}
|
||||
{% if loop.first %}
|
||||
==== Implements ====
|
||||
{% endif %}
|
||||
{% if loop.length > 1 %} * {% endif %}{{ interface.fullyQualifiedStructuralElementName ?: interface }}
|
||||
{% endfor %}
|
||||
|
||||
|
||||
{% for trait in node.usedTraits|sort_asc %}
|
||||
{% if loop.first %}
|
||||
==== Uses traits ====
|
||||
{% endif %}
|
||||
{% if loop.length > 1 %} * {% endif %}{{ trait.fullyQualifiedStructuralElementName ?: trait }}
|
||||
{% endfor %}
|
||||
|
||||
|
||||
{% include 'includes/see-also.txt.twig' with {structure:node, title_level: '==='} %}
|
||||
|
||||
{% include 'includes/tags.txt.twig' with {structure:node, title_level: '=====', blacklist: ['link', 'see', 'abstract', 'example', 'method', 'property', 'property-read', 'property-write', 'package', 'subpackage', 'phpdoc-tuning-exclude-inherited', 'api', 'api-advanced', 'overwritable-hook', 'extension-hook', 'copyright', 'license', 'code-example']} %}
|
||||
|
||||
{% set methods = node.inheritedMethods.merge(node.methods.merge(node.magicMethods)) %}
|
||||
{% include 'includes/tag-synthesys.txt.twig' with {methods:methods, tag:'api'} %}
|
||||
{% include 'includes/tag-synthesys.txt.twig' with {methods:methods, tag:'api-advanced'} %}
|
||||
{% include 'includes/tag-synthesys.txt.twig' with {methods:methods, tag:'overwritable-hook'} %}
|
||||
{% include 'includes/tag-synthesys.txt.twig' with {methods:methods, tag:'extension-hook'} %}
|
||||
|
||||
|
||||
{% include 'includes/code-examples.txt.twig' with {structure:node, title_level: '=====', sub_title_level: '=='} %}
|
||||
|
||||
<WRAP clear />
|
||||
|
||||
{% for method in methods|sort_asc
|
||||
if method.visibility == 'public'
|
||||
and (
|
||||
method.tags['api'] is defined
|
||||
or method.tags['api-advanced'] is defined
|
||||
or method.tags['overwritable-hook'] is defined
|
||||
or method.tags['extension-hook'] is defined
|
||||
)
|
||||
and (
|
||||
node.tags['phpdoc-tuning-exclude-inherited'] is not defined
|
||||
or method.parent.name == node.name
|
||||
)
|
||||
%}
|
||||
{%- if loop.first %}
|
||||
===== Public methods =====
|
||||
{% endif %}
|
||||
{{ block('method') }}
|
||||
{% endfor %}
|
||||
{% for method in methods|sort_asc if method.visibility == 'protected' and (method.tags['overwritable-hook'] is defined or method.tags['extension-hook'] is defined) %}
|
||||
{%- if loop.first %}
|
||||
===== Protected methods =====
|
||||
{% endif %}
|
||||
{{ block('method') }}
|
||||
{% endfor %}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
{% set constants = node.inheritedConstants.merge(node.constants) %}
|
||||
{% if constants|length > 0 %}
|
||||
===== Constants =====
|
||||
{% for constant in constants|sort_asc %}
|
||||
{{ block('constant') }}
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
|
||||
|
||||
{#{% set properties = node.inheritedProperties.merge(node.properties.merge(node.magicProperties)) %}#}
|
||||
{#{% for property in properties|sort_asc if property.visibility == 'public' %}#}
|
||||
{#{%- if loop.first %}#}
|
||||
{#===== Public properties =====#}
|
||||
{#{% endif %}#}
|
||||
{#{{ block('property') }}#}
|
||||
{#{% endfor %}#}
|
||||
{#{% for property in properties|sort_asc if property.visibility == 'protected' %}#}
|
||||
{#{%- if loop.first %}#}
|
||||
{#===== Protected properties =====#}
|
||||
{#{% endif %}#}
|
||||
{#{{ block('property') }}#}
|
||||
{#{% endfor %}#}
|
||||
|
||||
|
||||
{%- endif %} {#{% elseif node.tags['xxx'] is not defined and ... #}
|
||||
|
||||
<wrap button>[[start|🔙 Back]]</wrap>
|
||||
{% endblock %}
|
||||
@@ -0,0 +1,31 @@
|
||||
{% block constant %}
|
||||
|
||||
<WRAP group box >
|
||||
<WRAP twothirds column >
|
||||
==== {{ constant.name }} ====
|
||||
</WRAP>{# twothirds column#}
|
||||
|
||||
<WRAP third column>
|
||||
{% if constant.deprecated %}<wrap danger>deprecated</wrap> {% endif %}
|
||||
{% if (node.parent is not null and constant.parent.fullyQualifiedStructuralElementName != node.fullyQualifiedStructuralElementName) %}<wrap notice>inherited</wrap> {% endif %}
|
||||
</WRAP>{# third column#}
|
||||
|
||||
== {{ constant.summary|replace({"\n":""})|raw }} ==
|
||||
<html>{{ constant.description|markdown|raw }}</html>
|
||||
|
||||
{% if constant.deprecated %}
|
||||
=== Deprecated ===
|
||||
{{ constant.tags.deprecated[0].description|raw }}
|
||||
{% endif %}
|
||||
|
||||
{% include 'includes/inherited-from.txt.twig' with {structure:constant} %}
|
||||
|
||||
{% include 'includes/see-also.txt.twig' with {structure:constant, title_level: '=='} %}
|
||||
|
||||
{% include 'includes/uses.txt.twig' with {structure:constant, title_level: '=='} %}
|
||||
|
||||
{% include 'includes/tags.txt.twig' with {structure:constant, title_level: '==', blacklist: ['link', 'see', 'var', 'deprecated', 'uses', 'package', 'subpackage', 'todo', 'code-example']} %}
|
||||
|
||||
</WRAP>{# group #}
|
||||
|
||||
{% endblock %}
|
||||
95
.doc/phpdoc-templates/combodo-wiki/elements/method.txt.twig
Normal file
95
.doc/phpdoc-templates/combodo-wiki/elements/method.txt.twig
Normal file
@@ -0,0 +1,95 @@
|
||||
{% block method %}
|
||||
|
||||
|
||||
<WRAP group box >
|
||||
<WRAP twothirds column >
|
||||
==== {{ method.name }} ====
|
||||
</WRAP>{# twothirds column#}
|
||||
<WRAP third column >
|
||||
{% include 'includes/wrap-tags.txt.twig' with {structure:method, wrap: 'safety', wrapTags: ['api', 'api-advanced', 'overwritable-hook', 'extension-hook']} %}
|
||||
{% if method.deprecated %}<wrap danger>deprecated</wrap> {% endif %}
|
||||
{% if (node.parent is not null and method.parent.fullyQualifiedStructuralElementName != node.fullyQualifiedStructuralElementName) %}<wrap notice>inherited</wrap> {% endif %}
|
||||
{% if method.abstract %}<wrap warning>abstract</wrap> {% endif %}
|
||||
{% if method.final %}<wrap notice>final</wrap> {% endif %}
|
||||
<wrap notice>{{ method.visibility }}</wrap>
|
||||
{% if method.static %}<wrap warning>static</wrap> {% endif %}
|
||||
</WRAP>{# third column#}
|
||||
|
||||
|
||||
== {{ method.summary|replace({"\n":""})|raw }} ==
|
||||
<html>{{ method.description|markdown|raw }}</html>
|
||||
|
||||
<code php>{% if method.abstract %}abstract {% endif %}{% if method.final %}final {% endif %}{{ method.visibility }} {% if method.static %}static {% endif %}{{ method.name }}({% for argument in method.arguments %}{{ argument.isVariadic ? '...' }}{{ argument.name }}{{ argument.default ? (' = '~argument.default)|raw }}{% if not loop.last %}, {% endif %}{% endfor %})</code>
|
||||
|
||||
<WRAP twothirds column >
|
||||
|
||||
|
||||
=== Parameters ===
|
||||
{% if method.arguments|length > 0 -%}
|
||||
^ types ^ name ^ default ^ description ^
|
||||
{% for argument in method.arguments -%}
|
||||
| **<nowiki>{{ argument.types|join('|')|raw }}</nowiki>** | {{ argument.name }} {{ argument.isVariadic ? '<small style="color: gray">variadic</small>' }} | <nowiki>{{ argument.default|raw }}</nowiki> | {{ argument.description|trim|replace("\n", ' ')|raw }} |{{ "\r\n" }}
|
||||
{%- endfor %}
|
||||
{% else %}
|
||||
//none//
|
||||
{% endif %}
|
||||
|
||||
|
||||
{#=== Parameters ===#}
|
||||
{#{% if method.arguments|length > 0 -%}#}
|
||||
{#{% for argument in method.arguments -%}#}
|
||||
{#== {{ argument.name }} ==#}
|
||||
|
||||
|
||||
{#{% set varDesc %}#}
|
||||
{#<span style="margin:0 10px; 0 20px; font-weight: bold;">{{ argument.types|join('|') }}</span>#}
|
||||
{#{{ argument.isVariadic ? '<small style="color: gray">variadic</small>' }}#}
|
||||
{#{{ argument.description|raw }}#}
|
||||
{#{% endset %}#}
|
||||
{#<html>{{ varDesc|markdown|raw }}</html>#}
|
||||
{#{%- endfor %}#}
|
||||
{#{% else %}#}
|
||||
{#<wrap tip>This method has no parameter</wrap>#}
|
||||
{#{% endif %}#}
|
||||
|
||||
|
||||
{% if method.response and method.response.types|join() != 'void' %}
|
||||
=== Returns ===
|
||||
<html>{{ ('**' ~ method.response.types|join('|')|trim ~ '** ' ~ method.response.description)|markdown|raw }}</html>
|
||||
{% endif %}
|
||||
|
||||
</WRAP>{# twothirds column#}
|
||||
|
||||
<WRAP third column >
|
||||
|
||||
{% if method.tags.throws|length > 0 or method.tags.throw|length > 0 %}
|
||||
=== Throws ===
|
||||
{% for exception in method.tags.throws -%}
|
||||
{% if loop.length > 1 %} * {% endif %}''{{ exception.types|join('|')|raw }}'' <nowiki>{{ exception.description|raw }}</nowiki>
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
|
||||
{% include 'includes/inherited-from.txt.twig' with {structure:method} %}
|
||||
|
||||
{% include 'includes/see-also.txt.twig' with {structure:method, title_level: '==='} %}
|
||||
|
||||
{% include 'includes/uses.txt.twig' with {structure:method, title_level: '==='} %}
|
||||
|
||||
{% include 'includes/used-by.txt.twig' with {structure:method, title_level: '==='} %}
|
||||
|
||||
{% include 'includes/tags-with-description.txt.twig' with {structure:method, title_level: '===', WRAP: 'info', tagsWithDescription: ['api', 'api-advanced', 'overwritable-hook', 'extension-hook']} %}
|
||||
|
||||
{% include 'includes/tags.txt.twig' with {structure:method, title_level: '===', blacklist: ['todo', 'link', 'see', 'abstract', 'example', 'param', 'return', 'access', 'deprecated', 'throws', 'throw', 'uses', 'api', 'api-advanced', 'overwritable-hook', 'extension-hook', 'used-by', 'inheritdoc', 'code-example']} %}
|
||||
|
||||
</WRAP>{# third column#}
|
||||
|
||||
|
||||
|
||||
{% include 'includes/code-examples.txt.twig' with {structure:method, title_level: '==='} %}
|
||||
|
||||
</WRAP>{# group #}
|
||||
|
||||
|
||||
|
||||
|
||||
{% endblock %}
|
||||
@@ -0,0 +1,49 @@
|
||||
{% block property %}
|
||||
|
||||
<WRAP group box>
|
||||
<WRAP twothirds column >
|
||||
==== ${{ property.name }} ====
|
||||
</WRAP>{# twothirds column#}
|
||||
|
||||
<WRAP third column>
|
||||
{% if property.deprecated %}<wrap danger>deprecated</wrap> {% endif %}
|
||||
{% if (node.parent is not null and property.parent.fullyQualifiedStructuralElementName != node.fullyQualifiedStructuralElementName) %}<wrap notice>inherited</wrap> {% endif %}
|
||||
</WRAP>{# third column#}
|
||||
|
||||
|
||||
|
||||
|
||||
== {{ property.summary|replace({"\n":""})|raw }} ==
|
||||
<html>{{ property.description|markdown|raw }}</html>
|
||||
{% if property.var.0.description %}<html>{{ property.var.0.description|markdown|raw }}</html>{% endif %}
|
||||
|
||||
|
||||
|
||||
{#{% if property.types %}#}
|
||||
{#== Type ==#}
|
||||
{#{% for type in property.types %}#}
|
||||
{#{% if loop.length > 1 %} * {% endif %}{{ type|raw }} : {{ type.description|raw }}#}
|
||||
{#{% endfor %}#}
|
||||
{#{{ property.types|join('|')|raw }}#}
|
||||
{#{% endif %}#}
|
||||
|
||||
|
||||
{% if property.deprecated %}
|
||||
== Deprecated ==
|
||||
{{ property.tags.deprecated[0].description }}
|
||||
{% endif %}
|
||||
|
||||
{% include 'includes/inherited-from.txt.twig' with {structure:property} %}
|
||||
|
||||
{% include 'includes/see-also.txt.twig' with {structure:property, title_level: '=='} %}
|
||||
|
||||
{% include 'includes/uses.txt.twig' with {structure:property, title_level: ''} %}
|
||||
|
||||
{% include 'includes/tags.txt.twig' with {structure:property, title_level: '==', blacklist: ['link', 'see', 'access', 'var', 'deprecated', 'uses', 'todo', 'code-example']} %}
|
||||
|
||||
|
||||
<code php>{{ property.visibility }} ${{ property.name }}{% if property.types %} : {{ property.types|join('|')|raw }}{% endif %}</code>
|
||||
|
||||
</WRAP>{# group #}
|
||||
|
||||
{% endblock %}
|
||||
1
.doc/phpdoc-templates/combodo-wiki/file.source.txt.twig
Normal file
1
.doc/phpdoc-templates/combodo-wiki/file.source.txt.twig
Normal file
@@ -0,0 +1 @@
|
||||
{{ node.source|raw }}
|
||||
122
.doc/phpdoc-templates/combodo-wiki/file.txt.twig
Normal file
122
.doc/phpdoc-templates/combodo-wiki/file.txt.twig
Normal file
@@ -0,0 +1,122 @@
|
||||
{% extends 'layout.txt.twig' %}
|
||||
|
||||
{% block javascripts %}
|
||||
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
{#<section class="row-fluid">#}
|
||||
{#<div class="span2 sidebar">#}
|
||||
{#{% set namespace = project.namespace %}#}
|
||||
{#{{ block('sidebarNamespaces') }}#}
|
||||
{#</div>#}
|
||||
{#</section>#}
|
||||
{#<section class="row-fluid">#}
|
||||
====== {{ node.path|split('/')|slice(0,-1)|join('/') }}{{ node.name }} ======
|
||||
{{ node.summary }}
|
||||
<html>{{ node.description|markdown|raw }}</html>
|
||||
|
||||
{% if node.traits|length > 0 %}
|
||||
|
||||
===== Traits =====
|
||||
{% for trait in node.traits %}
|
||||
<tr>
|
||||
<td>{{ trait|raw }}</td>
|
||||
<td><em>{{ trait.summary }}</em></td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
|
||||
|
||||
{% if node.interfaces|length > 0 %}
|
||||
===== Interfaces =====
|
||||
{% for interface in node.interfaces %}
|
||||
<tr>
|
||||
<td>{{ interface|raw }}</td>
|
||||
<td><em>{{ interface.summary }}</em></td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
|
||||
{% if node.classes|length > 0 %}
|
||||
===== Classes =====
|
||||
{% for class in node.classes %}
|
||||
{{ class|raw }}
|
||||
<em>{{ class.summary }}</em>
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
|
||||
{% if node.package is not empty and node.package != '\\' %}
|
||||
===== Package =====
|
||||
{{ node.subpackage ? (node.package ~ '\\' ~ node.subpackage) : node.package }}
|
||||
{% endif %}
|
||||
|
||||
{% for tagName,tags in node.tags if tagName in ['link', 'see'] %}
|
||||
{% if loop.first %}
|
||||
===== See also =====
|
||||
{% endif %}
|
||||
{% for tag in tags %}
|
||||
<dd><a href="{{ tag.reference ?: tag.link }}"><div class="namespace-wrapper">{{ tag.description ?: tag.reference }}</div></a></dd>
|
||||
{% endfor %}
|
||||
{% endfor %}
|
||||
|
||||
<h2>Tags</h2>
|
||||
<table class="table table-condensed">
|
||||
{% for tagName,tags in node.tags if tagName not in ['link', 'see', 'package', 'subpackage'] %}
|
||||
<tr>
|
||||
<th>
|
||||
{{ tagName }}
|
||||
</th>
|
||||
<td>
|
||||
{% for tag in tags %}
|
||||
{{ tag.description|markdown|raw }}
|
||||
{% endfor %}
|
||||
</td>
|
||||
</tr>
|
||||
{% else %}
|
||||
<tr><td colspan="2"><em>None found</em></td></tr>
|
||||
{% endfor %}
|
||||
</table>
|
||||
|
||||
</aside>
|
||||
</div>
|
||||
|
||||
{% if node.constants|length > 0 %}
|
||||
<div class="row-fluid">
|
||||
<section class="span8 content file">
|
||||
<h2>Constants</h2>
|
||||
</section>
|
||||
<aside class="span4 detailsbar"></aside>
|
||||
</div>
|
||||
|
||||
{% for constant in node.constants %}
|
||||
{{ block('constant') }}
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
|
||||
{% if node.functions|length > 0 %}
|
||||
<div class="row-fluid">
|
||||
<section class="span8 content file">
|
||||
<h2>Functions</h2>
|
||||
</section>
|
||||
<aside class="span4 detailsbar"></aside>
|
||||
</div>
|
||||
|
||||
{% for method in node.functions %}
|
||||
{{ block('method') }}
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<div id="source-view" class="modal hide fade" tabindex="-1" role="dialog" aria-labelledby="source-view-label" aria-hidden="true">
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
|
||||
<h3 id="source-view-label">{{ node.file.name }}</h3>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<pre data-src="{{ path('files/' ~ node.path ~ '.txt')|raw }}" class="language-php line-numbers"></pre>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
42
.doc/phpdoc-templates/combodo-wiki/graphs/class.html.twig
Normal file
42
.doc/phpdoc-templates/combodo-wiki/graphs/class.html.twig
Normal file
@@ -0,0 +1,42 @@
|
||||
{% extends 'layout.html.twig' %}
|
||||
|
||||
{% block stylesheets %}
|
||||
<link href="{{ path('css/jquery.iviewer.css') }}" rel="stylesheet" media="all"/>
|
||||
<style>
|
||||
#viewer {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
}
|
||||
.wrapper {
|
||||
overflow: hidden;
|
||||
}
|
||||
</style>
|
||||
{% endblock %}
|
||||
|
||||
{% block javascripts %}
|
||||
<script src="{{ path('js/jquery.mousewheel.js') }}" type="text/javascript"></script>
|
||||
<script src="{{ path('js/jquery.iviewer.js') }}" type="text/javascript"></script>
|
||||
<script type="text/javascript">
|
||||
$(window).resize(function(){
|
||||
$("#viewer").height($(window).height() - 100);
|
||||
});
|
||||
|
||||
$(document).ready(function() {
|
||||
$("#viewer").iviewer({src: '{{ path('graphs/classes.svg') }}', zoom_animation: false});
|
||||
$('#viewer img').bind('dragstart', function(event){
|
||||
event.preventDefault();
|
||||
});
|
||||
$(window).resize();
|
||||
});
|
||||
</script>
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="row-fluid">
|
||||
<div class="span12">
|
||||
<div class="wrapper">
|
||||
<div id="viewer" class="viewer"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
5
.doc/phpdoc-templates/combodo-wiki/htaccess.dist
Normal file
5
.doc/phpdoc-templates/combodo-wiki/htaccess.dist
Normal file
@@ -0,0 +1,5 @@
|
||||
# Fixes a vulnerability in CentOS: http://stackoverflow.com/questions/20533279/prevent-php-from-parsing-non-php-files-such-as-somefile-php-txt
|
||||
<FilesMatch \.php\.txt$>
|
||||
RemoveHandler .php
|
||||
ForceType text/plain
|
||||
</FilesMatch>
|
||||
@@ -0,0 +1,34 @@
|
||||
{% if title_level is not defined %}
|
||||
{%- set title_level = '==' -%}
|
||||
{% endif %}
|
||||
|
||||
{% if sub_title_level is not defined %}
|
||||
{%- set sub_title_level = title_level|slice(1) -%}
|
||||
{% endif %}
|
||||
{% if sub_title_level == '=' %}
|
||||
{%- set sub_title_level = '' -%}
|
||||
{% endif %}
|
||||
|
||||
{#{% for tagName,tags in structure.tags if tagName in ['code-example'] %}#}
|
||||
{#{% if loop.first %}#}
|
||||
{#{{title_level}} Examples {{title_level}}#}
|
||||
{#{% endif %}#}
|
||||
{#{% for tag in tags %}#}
|
||||
{#{%- set descToken = tag.description|split("\n", 2) -%}#}
|
||||
{#{%- set title = descToken[0] -%}#}
|
||||
{#{%- set code = descToken[1] -%}#}
|
||||
{#{{sub_title_level}} {{ title }} {{sub_title_level}}#}
|
||||
{#<code php>{{ code|raw }}</code>#}
|
||||
{#{% endfor %}#}
|
||||
{#{% endfor %}#}
|
||||
|
||||
|
||||
{% for tagName,tags in structure.tags if tagName in ['example'] %}
|
||||
{% if loop.first %}
|
||||
{{title_level}} Examples {{title_level}}
|
||||
{% endif %}
|
||||
{% for tag in tags %}
|
||||
{{ sub_title_level }} {{ tag.filePath|escape }}{{ sub_title_level }}
|
||||
<code php>{{ tag.description|raw }}</code>
|
||||
{% endfor %}
|
||||
{% endfor %}
|
||||
@@ -0,0 +1,12 @@
|
||||
{% if title_level is not defined %}
|
||||
{% set title_level='' %}
|
||||
{% endif %}
|
||||
|
||||
{% if (node.parent is null) %}
|
||||
{{title_level}} File {{ structure.path }} {{title_level}}
|
||||
{% endif %}
|
||||
|
||||
{% if (node.parent is not null and structure.parent.fullyQualifiedStructuralElementName != node.fullyQualifiedStructuralElementName) %}
|
||||
{{title_level}} Inherited from {{title_level}}
|
||||
[[{{structure.parent}}|{{structure.parent}}]]
|
||||
{% endif %}
|
||||
@@ -0,0 +1,26 @@
|
||||
{% for structure in structures|sort_asc if structure.tags['internal'] is not defined and (structure.tags['api'] is defined or structure.tags['api-advanced'] is defined or structure.tags['overwritable-hook'] is defined or structure.tags['extension-hook'] is defined ) %}
|
||||
{#{{ structure|raw }}#}
|
||||
|
||||
{% set structureName = structure|trim('\\', 'left') %}
|
||||
|
||||
<WRAP group box>
|
||||
<WRAP twothirds column >
|
||||
==== {{ structureName }} ====
|
||||
</WRAP>{# twothirds column#}
|
||||
|
||||
<WRAP third column>
|
||||
{% if structure.deprecated %}<wrap danger>deprecated</wrap>{% endif %}
|
||||
{% if structure.abstract %}<wrap warning>abstract</wrap>{% endif %}
|
||||
{% if structure.final %}<wrap notice>final</wrap>{% endif %}
|
||||
{% if (node.parent is not null and structure.parent.fullyQualifiedStructuralElementName != node.fullyQualifiedStructuralElementName) %}<wrap notice>inherited</wrap> {% endif %}
|
||||
{% include 'includes/wrap-tags.txt.twig' with {structure:structure, wrap: 'safety', wrapTags: ['api', 'api-advanced', 'overwritable-hook', 'extension-hook']} %}
|
||||
</WRAP>{# third column#}
|
||||
|
||||
|
||||
{{ structure.summary|raw }}
|
||||
[[{{structureName}}|More informations]]
|
||||
|
||||
</WRAP>{# group #}
|
||||
|
||||
{% endfor %}
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
{% if title_level is not defined %}
|
||||
{%- set title_level='==' -%}
|
||||
{% endif %}
|
||||
{% for tagName,tags in structure.tags if tagName in ['link', 'see'] %}
|
||||
{% if loop.first %}
|
||||
{{title_level}} See also {{title_level}}
|
||||
{% endif %}
|
||||
{% for tag in tags %}
|
||||
{%- set linkTag = tag.reference|trim('\\', 'left') -%}
|
||||
{% if not('()' in linkTag or '$' in linkTag or node.name in linkTag or '::' in linkTag ) %}
|
||||
{%- set linkTag = linkTag|lower -%}
|
||||
{% elseif node.name~'::' in linkTag %}
|
||||
{%- set linkTag = linkTag|replace({(node.name~'::'): '#'})|lower -%}
|
||||
{% elseif '::' in linkTag -%}
|
||||
{%- set linkTag = linkTag|replace({'::': '#'})|lower -%}
|
||||
{% else %}
|
||||
{%- set linkTag = '#' ~ linkTag|lower -%}
|
||||
{%- endif %}
|
||||
|
||||
{% if loop.length > 1 %} * {% endif %}{% if tag.reference is not empty -%}
|
||||
[[{{linkTag}}|{{ (tag.reference)|trim('\\', 'left') }}]] {% if tag.description|trim is not empty %}: {{ tag.description|trim('\\', 'left') }} {% endif %}
|
||||
{%- else -%}
|
||||
{#{{ tag.description|trim('\\', 'left') }}#}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{% endfor %}
|
||||
@@ -0,0 +1,56 @@
|
||||
{% if tag is not defined -%}
|
||||
{# Do not display @api if @api-advanced is also present #}
|
||||
{%- set tag = "api" -%}
|
||||
{%- endif %}
|
||||
|
||||
{% if hidden_by is not defined -%}
|
||||
{# Do not display @api if @api-advanced is also present #}
|
||||
{%- set hidden_by = {"api" : "api-advanced"} -%}
|
||||
{%- endif %}
|
||||
|
||||
|
||||
|
||||
{% for method in methods|sort_asc
|
||||
if (method.visibility == 'public')
|
||||
and (
|
||||
method.tags[tag] is defined
|
||||
and (
|
||||
hidden_by[tag] is not defined or method.tags[hidden_by[tag]] is not defined
|
||||
)
|
||||
)
|
||||
%}
|
||||
{%- if loop.first %}
|
||||
{% if tag == 'api' %}
|
||||
===== API synthesis =====
|
||||
<WRAP>
|
||||
List of the public API methods.
|
||||
When manipulating {{ node.name }}, You can call those methods:
|
||||
</WRAP>
|
||||
{% elseif tag == 'api-advanced' %}
|
||||
===== Advanced API synthesis =====
|
||||
<WRAP>
|
||||
List of advanced API methods
|
||||
Beware they usage is recommended to advanced users only.
|
||||
</WRAP>
|
||||
{% elseif tag == 'overwritable-hook' %}
|
||||
===== overwritable-hook synthesis =====
|
||||
<WRAP >When inheriting from {{ node.name }},
|
||||
you can overwrite those methods in order to add custom logic:
|
||||
</WRAP>
|
||||
{% elseif tag == 'extension-hook' %}
|
||||
===== extension-hook synthesis =====
|
||||
<WRAP >
|
||||
When inheriting from {{ node.name }},
|
||||
you can extend the behaviour of iTop by implementing:
|
||||
</WRAP>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% set sanitizedMethod = method|trim('\\', 'left')|replace({(node.name~'::'): ''}) %}
|
||||
{% if '::' in sanitizedMethod -%}
|
||||
{%- if node.tags['phpdoc-tuning-exclude-inherited'] is not defined %}
|
||||
* [[{{sanitizedMethod|replace({'::': '#'})|lower}}|↪{{sanitizedMethod}}]] — {{ method.summary|replace({"\n":""})|raw }}
|
||||
{% endif %}
|
||||
{%- else %}
|
||||
* [[#{{sanitizedMethod}}|{{sanitizedMethod}}]] — {{ method.summary|replace({"\n":""})|raw }}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
@@ -0,0 +1,20 @@
|
||||
{% if title_level is not defined %}
|
||||
{% set title_level = '==' %}
|
||||
{% endif %}
|
||||
|
||||
|
||||
{%- for tagName,tags in structure.tags if tagName in tagsWithDescription -%}
|
||||
{%- for tag in tags -%}
|
||||
{%- if tag.description is not empty -%}
|
||||
{%- if WRAP is defined -%}
|
||||
<WRAP {{WRAP}}>
|
||||
{%- endif -%}
|
||||
{{title_level}} {{ tagName }} {{title_level}}
|
||||
{{ tag.description|escape }}
|
||||
{%- if WRAP is defined -%}
|
||||
</WRAP>
|
||||
{%- endif -%}
|
||||
{%- endif -%}
|
||||
{%- endfor -%}
|
||||
{%- endfor -%}
|
||||
|
||||
22
.doc/phpdoc-templates/combodo-wiki/includes/tags.txt.twig
Normal file
22
.doc/phpdoc-templates/combodo-wiki/includes/tags.txt.twig
Normal file
@@ -0,0 +1,22 @@
|
||||
{% if title_level is not defined %}
|
||||
{% set title_level='=====' %}
|
||||
{% endif %}
|
||||
|
||||
{% if blacklist is not defined %}
|
||||
{% set blacklist =['link', 'see', 'abstract', 'example', 'method', 'property', 'property-read', 'property-write', 'package', 'subpackage', 'api', 'api-advanced', 'todo', 'code-example'] %}
|
||||
{% endif %}
|
||||
{% if hidden_by is not defined -%}
|
||||
{# Do not display @api if @api-advanced is also present #}
|
||||
{%- set hidden_by = {"api" : "api-advanced"} -%}
|
||||
{%- endif %}
|
||||
|
||||
{#^ {% for tagName,tags in structure.tags if tagName not in blacklist -%}#}
|
||||
{#{{ tagName }} ^#}
|
||||
{#{%- endfor %}#}
|
||||
|
||||
{% for tagName,tags in structure.tags if tagName not in blacklist and (hidden_by[tagName] is not defined or structure.tags[hidden_by[tagName]] is not defined) %}
|
||||
{%- if loop.first %}
|
||||
{{title_level}} Tags {{title_level}}
|
||||
{% endif %}
|
||||
^ {{ tagName }} | {% for tag in tags %}{{ tag.version ? tag.version ~ ' ' : '' }}{{ tag.description}}{% endfor %} |
|
||||
{% endfor %}
|
||||
24
.doc/phpdoc-templates/combodo-wiki/includes/used-by.txt.twig
Normal file
24
.doc/phpdoc-templates/combodo-wiki/includes/used-by.txt.twig
Normal file
@@ -0,0 +1,24 @@
|
||||
{% if title_level is not defined %}
|
||||
{% set title_level='' %}
|
||||
{% endif %}
|
||||
{% for tagName,tags in structure.tags if tagName in ['used-by'] %}
|
||||
{% if loop.first %}
|
||||
{{title_level}} Used by {{title_level}}
|
||||
{% endif %}
|
||||
{% for tag in tags %}
|
||||
{% if loop.length > 1 %} * {% endif %}{{ tag.reference ?: tag.link }} : {{ tag.description ?: tag.reference }}
|
||||
{% endfor %}
|
||||
{% endfor %}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
{#{% for tagName,tags in method.tags if tagName in ['uses'] %}#}
|
||||
{#{% if loop.first %}#}
|
||||
{#<dt>Uses</dt>#}
|
||||
{#{% endif %}#}
|
||||
{#{% for tag in tags %}#}
|
||||
{#<dd>{{ tag.reference|raw }}</dd>#}
|
||||
{#{% endfor %}#}
|
||||
{#{% endfor %}#}
|
||||
24
.doc/phpdoc-templates/combodo-wiki/includes/uses.txt.twig
Normal file
24
.doc/phpdoc-templates/combodo-wiki/includes/uses.txt.twig
Normal file
@@ -0,0 +1,24 @@
|
||||
{% if title_level is not defined %}
|
||||
{% set title_level='' %}
|
||||
{% endif %}
|
||||
{% for tagName,tags in structure.tags if tagName in ['uses'] %}
|
||||
{% if loop.first %}
|
||||
{{title_level}} Uses {{title_level}}
|
||||
{% endif %}
|
||||
{% for tag in tags %}
|
||||
{% if loop.length > 1 %} * {% endif %}{{ tag.reference ?: tag.link }} : {{ tag.description ?: tag.reference }}
|
||||
{% endfor %}
|
||||
{% endfor %}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
{#{% for tagName,tags in method.tags if tagName in ['uses'] %}#}
|
||||
{#{% if loop.first %}#}
|
||||
{#<dt>Uses</dt>#}
|
||||
{#{% endif %}#}
|
||||
{#{% for tag in tags %}#}
|
||||
{#<dd>{{ tag.reference|raw }}</dd>#}
|
||||
{#{% endfor %}#}
|
||||
{#{% endfor %}#}
|
||||
@@ -0,0 +1,11 @@
|
||||
{% if wrap is not defined -%}
|
||||
{% set wrap = 'notice' %}
|
||||
{%- endif -%}
|
||||
{% if hidden_by is not defined -%}
|
||||
{# Do not display @api if @api-advanced is also present #}
|
||||
{%- set hidden_by = {"api" : "api-advanced"} -%}
|
||||
{%- endif %}
|
||||
|
||||
{%- for tagName,tags in structure.tags if tagName in wrapTags and (hidden_by[tagName] is not defined or structure.tags[hidden_by[tagName]] is not defined) %}
|
||||
<wrap {{wrap}}>{{tagName}}</wrap>
|
||||
{% endfor %}
|
||||
121
.doc/phpdoc-templates/combodo-wiki/interface.txt.twig
Normal file
121
.doc/phpdoc-templates/combodo-wiki/interface.txt.twig
Normal file
@@ -0,0 +1,121 @@
|
||||
{% extends 'layout.txt.twig' %}
|
||||
|
||||
{% block content %}
|
||||
<wrap button>[[start|🔙 Back]]</wrap>
|
||||
|
||||
{% if node.tags['internal'] is defined %}
|
||||
====== {{ node.name }} ======
|
||||
<WRAP alert>This interface is "internal", and thus is not documented!</WRAP>
|
||||
{% elseif node.tags['api'] is not defined and node.tags['api-advanced'] is not defined and node.tags['overwritable-hook'] is not defined and node.tags['extension-hook'] is not defined %}
|
||||
====== {{ node.name }} ======
|
||||
<WRAP alert>This interface is neither "api", "overwritable-hook" or "extension-hook", and thus is not documented!</WRAP>
|
||||
{% else %}
|
||||
|
||||
====== {{ node.name }} ======
|
||||
|
||||
{% if node.deprecated %}<wrap danger>deprecated</wrap>{% endif %}
|
||||
{% if node.abstract %}<wrap warning>abstract</wrap>{% endif %}
|
||||
{% if node.final %}<wrap notice>final</wrap>{% endif %}
|
||||
{% include 'includes/wrap-tags.txt.twig' with {structure:node, wrap: 'safety', wrapTags: ['api', 'api-advanced', 'overwritable-hook', 'extension-hook']} %}
|
||||
|
||||
|
||||
|
||||
{% if node.deprecated %}
|
||||
=== **<del>Deprecated</del>**===
|
||||
//{{ node.tags.deprecated[0].description }}//
|
||||
{% endif %}
|
||||
|
||||
|
||||
== {{ node.summary|replace({"\n":""})|raw }} ==
|
||||
<html>{{ node.description|markdown|raw }}</html>
|
||||
|
||||
|
||||
{% include 'includes/code-examples.txt.twig' with {structure:node, title_level: '====='} %}
|
||||
|
||||
|
||||
{% set class = node.parent %}
|
||||
{% block hierarchy_element %}
|
||||
|
||||
{% if class and class.name is defined and class.name|trim != '' %}
|
||||
==== parent ====
|
||||
{% set child = class %}
|
||||
{% set class = class.parent %}
|
||||
{{ block('hierarchy_element') }}
|
||||
[[{{ child.name }}|{{ child.name }}]]
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
|
||||
|
||||
{% for interface in node.interfaces|sort_asc %}
|
||||
{% if loop.first %}
|
||||
==== Implements ====
|
||||
{% endif %}
|
||||
{% if loop.length > 1 %} * {% endif %}{{ interface.fullyQualifiedStructuralElementName ?: interface }}
|
||||
{% endfor %}
|
||||
|
||||
|
||||
{% for trait in node.usedTraits|sort_asc %}
|
||||
{% if loop.first %}
|
||||
==== Uses traits ====
|
||||
{% endif %}
|
||||
{% if loop.length > 1 %} * {% endif %}{{ trait.fullyQualifiedStructuralElementName ?: trait }}
|
||||
{% endfor %}
|
||||
|
||||
|
||||
{% include 'includes/see-also.txt.twig' with {structure:node, title_level: '==='} %}
|
||||
|
||||
{% include 'includes/tags.txt.twig' with {structure:node, title_level: '=====', blacklist: ['link', 'see', 'abstract', 'example', 'method', 'property', 'property-read', 'property-write', 'package', 'subpackage', 'phpdoc-tuning-exclude-inherited', 'api', 'api-advanced', 'overwritable-hook', 'extension-hook', 'copyright', 'license', 'code-example']} %}
|
||||
|
||||
|
||||
{% set methods = node.inheritedMethods.merge(node.methods) %}
|
||||
{% include 'includes/tag-synthesys.txt.twig' with {methods:methods, tag:'api'} %}
|
||||
{% include 'includes/tag-synthesys.txt.twig' with {methods:methods, tag:'api-advanced'} %}
|
||||
{% include 'includes/tag-synthesys.txt.twig' with {methods:methods, tag:'overwritable-hook'} %}
|
||||
{% include 'includes/tag-synthesys.txt.twig' with {methods:methods, tag:'extension-hook'} %}
|
||||
|
||||
<WRAP clear />
|
||||
|
||||
|
||||
{% for method in methods|sort_asc if method.visibility == 'public' %}
|
||||
{%- if loop.first %}
|
||||
===== Public methods =====
|
||||
{% endif %}
|
||||
{{ block('method') }}
|
||||
{% endfor %}
|
||||
{% for method in methods|sort_asc if method.visibility == 'protected' %}
|
||||
{%- if loop.first %}
|
||||
===== Protected methods =====
|
||||
{% endif %}
|
||||
{{ block('method') }}
|
||||
{% endfor %}
|
||||
|
||||
|
||||
|
||||
{% set constants = node.inheritedConstants.merge(node.constants) %}
|
||||
{% if constants|length > 0 %}
|
||||
===== Constants =====
|
||||
{% for constant in constants|sort_asc %}
|
||||
{{ block('constant') }}
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
|
||||
|
||||
{#{% set properties = node.inheritedProperties.merge(node.properties) %}#}
|
||||
{#{% for property in properties|sort_asc if property.visibility == 'public' %}#}
|
||||
{#{%- if loop.first %}#}
|
||||
{#===== Public properties =====#}
|
||||
{#{% endif %}#}
|
||||
{#{{ block('property') }}#}
|
||||
{#{% endfor %}#}
|
||||
{#{% for property in properties|sort_asc if property.visibility == 'protected' %}#}
|
||||
{#{%- if loop.first %}#}
|
||||
{#===== Protected properties =====#}
|
||||
{#{% endif %}#}
|
||||
{#{{ block('property') }}#}
|
||||
{#{% endfor %}#}
|
||||
|
||||
|
||||
{%- endif %} {#{% elseif node.tags['xxx'] is not defined and ... #}
|
||||
|
||||
<wrap button>[[start|🔙 Back]]</wrap>
|
||||
{% endblock %}
|
||||
5
.doc/phpdoc-templates/combodo-wiki/layout.txt.twig
Normal file
5
.doc/phpdoc-templates/combodo-wiki/layout.txt.twig
Normal file
@@ -0,0 +1,5 @@
|
||||
{% use 'elements/constant.txt.twig' %}
|
||||
{% use 'elements/property.txt.twig' %}
|
||||
{% use 'elements/method.txt.twig' %}
|
||||
|
||||
{% block content %}{% endblock %}
|
||||
51
.doc/phpdoc-templates/combodo-wiki/namespace.txt.twig
Normal file
51
.doc/phpdoc-templates/combodo-wiki/namespace.txt.twig
Normal file
@@ -0,0 +1,51 @@
|
||||
{% extends 'layout.txt.twig' %}
|
||||
|
||||
{% block content %}
|
||||
{% set namespace = project.namespace %}
|
||||
{{ block('sidebarNamespaces') }}
|
||||
|
||||
{#{{ node.parent|raw }}#}
|
||||
{#====== {{ node.parent.fullyQualifiedStructuralElementName }}{{ node.name }} ======#}
|
||||
|
||||
{% if node.children|length > 0 %}
|
||||
=====Namespaces=====
|
||||
{% include 'includes/namespace-structure-toc.html.twig' with {structures: node.children} %}
|
||||
----
|
||||
{% endif %}
|
||||
|
||||
{% if node.traits|length > 0 %}
|
||||
===== Traits =====
|
||||
{% include 'includes/namespace-structure-toc.html.twig' with {structures: node.traits} %}
|
||||
----
|
||||
{%- endif %}
|
||||
|
||||
{% if node.interfaces|length > 0 %}
|
||||
===== Interfaces =====
|
||||
{% include 'includes/namespace-structure-toc.html.twig' with {structures: node.interfaces} %}
|
||||
----
|
||||
{% endif %}
|
||||
|
||||
{% if node.classes|length > 0 %}
|
||||
===== Classes =====
|
||||
{% include 'includes/namespace-structure-toc.html.twig' with {structures: node.classes} %}
|
||||
----
|
||||
{% endif %}
|
||||
|
||||
|
||||
|
||||
{#{% if node.constants|length > 0 %}#}
|
||||
{#===== Constants =====#}
|
||||
{#{% for constant in node.constants|sort_asc %}#}
|
||||
{# {{ block('constant') }}#}
|
||||
{#{% endfor %}#}
|
||||
{#{% endif %}#}
|
||||
|
||||
{#{% if node.functions|length > 0 %}#}
|
||||
{#===== Functions =====#}
|
||||
|
||||
{#{% for method in node.functions|sort_asc %}#}
|
||||
{# {{ block('method') }}#}
|
||||
{#{% endfor %}#}
|
||||
{#{% endif %}#}
|
||||
|
||||
{% endblock %}
|
||||
@@ -0,0 +1,49 @@
|
||||
|
||||
====== Deprecated elements ======
|
||||
|
||||
{#{% for element in project.indexes.elements if element.deprecated %}#}
|
||||
{#{% if element.file.path != previousPath %}#}
|
||||
{#<li><a href="#{{ element.file.path }}"><i class="icon-file"></i> {{ element.file.path }}</a></li>#}
|
||||
{#{% endif %}#}
|
||||
{#{% set previousPath = element.file.path %}#}
|
||||
{#{% endfor %}#}
|
||||
|
||||
{% for element in project.indexes.elements if element.deprecated %}
|
||||
{% if element.file.path != previousPath %}
|
||||
{% if previousPath %}
|
||||
</WRAP>{# group #}
|
||||
{% endif %}
|
||||
{#<a name="{{ element.file.path }}" id="{{ element.file.path }}"></a>#}
|
||||
===== {{ element.file.path }} ({{ element.tags.deprecated.count }} found)=====
|
||||
|
||||
<WRAP group >
|
||||
<WRAP third column >
|
||||
Element
|
||||
</WRAP>{# third column#}
|
||||
<WRAP third column >
|
||||
Line
|
||||
</WRAP>{# third column#}
|
||||
<WRAP third column >
|
||||
Description
|
||||
</WRAP>{# third column#}
|
||||
|
||||
{% endif %}
|
||||
{% for tag in element.tags.deprecated %}
|
||||
<WRAP group >
|
||||
<WRAP third column >
|
||||
{{ element.fullyQualifiedStructuralElementName }}
|
||||
</WRAP>{# third column#}
|
||||
<WRAP third column >
|
||||
{{ element.line }}
|
||||
</WRAP>{# third column#}
|
||||
<WRAP third column >
|
||||
{{ tag.description }}
|
||||
</WRAP>{# third column#}
|
||||
|
||||
{% endfor %}
|
||||
</WRAP>{# group #}
|
||||
{% set previousPath = element.file.path %}
|
||||
{% else %}
|
||||
<WRAP info>No deprecated elements have been found in this project.</WRAP>
|
||||
{% endfor %}
|
||||
|
||||
27
.doc/phpdoc-templates/combodo-wiki/template.xml
Normal file
27
.doc/phpdoc-templates/combodo-wiki/template.xml
Normal file
@@ -0,0 +1,27 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<template>
|
||||
<author>Bruno DA SILVA</author>
|
||||
<email>contact [at] combodo.com</email>
|
||||
<version>1.0.0</version>
|
||||
<copyright>Combodo 2018</copyright>
|
||||
<description><![CDATA[
|
||||
|
||||
Forked from the clean theme of https://github.com/phpDocumentor/phpDocumentor2 provided under the MIT licence.
|
||||
The original work is copyright "Mike van Riel".
|
||||
|
||||
------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
To improve performance you can add the following to your .htaccess:
|
||||
|
||||
<ifModule mod_deflate.c>
|
||||
<filesMatch "\.(js|css|html)$">
|
||||
SetOutputFilter DEFLATE
|
||||
</filesMatch>
|
||||
</ifModule>
|
||||
]]></description>
|
||||
<transformations>
|
||||
<transformation writer="twig" query="namespace" source="templates/combodo-wiki/namespace.txt.twig" artifact="start.txt"/>
|
||||
<transformation writer="twig" query="indexes.classes" source="templates/combodo-wiki/class.txt.twig" artifact="{{name}}.txt"/>
|
||||
<transformation writer="twig" query="indexes.interfaces" source="templates/combodo-wiki/interface.txt.twig" artifact="{{name}}.txt" />
|
||||
</transformations>
|
||||
</template>
|
||||
556
.editorconfig
Normal file
556
.editorconfig
Normal file
@@ -0,0 +1,556 @@
|
||||
root = true
|
||||
|
||||
[*]
|
||||
charset = utf-8
|
||||
end_of_line = lf
|
||||
indent_size = 4
|
||||
indent_style = space
|
||||
insert_final_newline = false
|
||||
max_line_length = 140
|
||||
tab_width = 4
|
||||
ij_continuation_indent_size = 8
|
||||
ij_formatter_off_tag = @formatter:off
|
||||
ij_formatter_on_tag = @formatter:on
|
||||
ij_formatter_tags_enabled = false
|
||||
ij_smart_tabs = false
|
||||
ij_visual_guides = 80,120
|
||||
ij_wrap_on_typing = true
|
||||
|
||||
[*.css]
|
||||
indent_style = tab
|
||||
ij_smart_tabs = true
|
||||
ij_visual_guides = none
|
||||
ij_css_align_closing_brace_with_properties = false
|
||||
ij_css_blank_lines_around_nested_selector = 1
|
||||
ij_css_blank_lines_between_blocks = 1
|
||||
ij_css_brace_placement = end_of_line
|
||||
ij_css_enforce_quotes_on_format = false
|
||||
ij_css_hex_color_long_format = false
|
||||
ij_css_hex_color_lower_case = false
|
||||
ij_css_hex_color_short_format = false
|
||||
ij_css_hex_color_upper_case = false
|
||||
ij_css_keep_blank_lines_in_code = 2
|
||||
ij_css_keep_indents_on_empty_lines = false
|
||||
ij_css_keep_single_line_blocks = false
|
||||
ij_css_properties_order = font,font-family,font-size,font-weight,font-style,font-variant,font-size-adjust,font-stretch,line-height,position,z-index,top,right,bottom,left,display,visibility,float,clear,overflow,overflow-x,overflow-y,clip,zoom,align-content,align-items,align-self,flex,flex-flow,flex-basis,flex-direction,flex-grow,flex-shrink,flex-wrap,justify-content,order,box-sizing,width,min-width,max-width,height,min-height,max-height,margin,margin-top,margin-right,margin-bottom,margin-left,padding,padding-top,padding-right,padding-bottom,padding-left,table-layout,empty-cells,caption-side,border-spacing,border-collapse,list-style,list-style-position,list-style-type,list-style-image,content,quotes,counter-reset,counter-increment,resize,cursor,user-select,nav-index,nav-up,nav-right,nav-down,nav-left,transition,transition-delay,transition-timing-function,transition-duration,transition-property,transform,transform-origin,animation,animation-name,animation-duration,animation-play-state,animation-timing-function,animation-delay,animation-iteration-count,animation-direction,text-align,text-align-last,vertical-align,white-space,text-decoration,text-emphasis,text-emphasis-color,text-emphasis-style,text-emphasis-position,text-indent,text-justify,letter-spacing,word-spacing,text-outline,text-transform,text-wrap,text-overflow,text-overflow-ellipsis,text-overflow-mode,word-wrap,word-break,tab-size,hyphens,pointer-events,opacity,color,border,border-width,border-style,border-color,border-top,border-top-width,border-top-style,border-top-color,border-right,border-right-width,border-right-style,border-right-color,border-bottom,border-bottom-width,border-bottom-style,border-bottom-color,border-left,border-left-width,border-left-style,border-left-color,border-radius,border-top-left-radius,border-top-right-radius,border-bottom-right-radius,border-bottom-left-radius,border-image,border-image-source,border-image-slice,border-image-width,border-image-outset,border-image-repeat,outline,outline-width,outline-style,outline-color,outline-offset,background,background-color,background-image,background-repeat,background-attachment,background-position,background-position-x,background-position-y,background-clip,background-origin,background-size,box-decoration-break,box-shadow,text-shadow
|
||||
ij_css_space_after_colon = true
|
||||
ij_css_space_before_opening_brace = true
|
||||
ij_css_use_double_quotes = true
|
||||
ij_css_value_alignment = do_not_align
|
||||
|
||||
[*.scss]
|
||||
indent_size = 2
|
||||
tab_width = 2
|
||||
ij_visual_guides = none
|
||||
ij_scss_align_closing_brace_with_properties = false
|
||||
ij_scss_blank_lines_around_nested_selector = 1
|
||||
ij_scss_blank_lines_between_blocks = 1
|
||||
ij_scss_brace_placement = 0
|
||||
ij_scss_enforce_quotes_on_format = false
|
||||
ij_scss_hex_color_long_format = false
|
||||
ij_scss_hex_color_lower_case = false
|
||||
ij_scss_hex_color_short_format = false
|
||||
ij_scss_hex_color_upper_case = false
|
||||
ij_scss_keep_blank_lines_in_code = 2
|
||||
ij_scss_keep_indents_on_empty_lines = false
|
||||
ij_scss_keep_single_line_blocks = false
|
||||
ij_scss_properties_order = font,font-family,font-size,font-weight,font-style,font-variant,font-size-adjust,font-stretch,line-height,position,z-index,top,right,bottom,left,display,visibility,float,clear,overflow,overflow-x,overflow-y,clip,zoom,align-content,align-items,align-self,flex,flex-flow,flex-basis,flex-direction,flex-grow,flex-shrink,flex-wrap,justify-content,order,box-sizing,width,min-width,max-width,height,min-height,max-height,margin,margin-top,margin-right,margin-bottom,margin-left,padding,padding-top,padding-right,padding-bottom,padding-left,table-layout,empty-cells,caption-side,border-spacing,border-collapse,list-style,list-style-position,list-style-type,list-style-image,content,quotes,counter-reset,counter-increment,resize,cursor,user-select,nav-index,nav-up,nav-right,nav-down,nav-left,transition,transition-delay,transition-timing-function,transition-duration,transition-property,transform,transform-origin,animation,animation-name,animation-duration,animation-play-state,animation-timing-function,animation-delay,animation-iteration-count,animation-direction,text-align,text-align-last,vertical-align,white-space,text-decoration,text-emphasis,text-emphasis-color,text-emphasis-style,text-emphasis-position,text-indent,text-justify,letter-spacing,word-spacing,text-outline,text-transform,text-wrap,text-overflow,text-overflow-ellipsis,text-overflow-mode,word-wrap,word-break,tab-size,hyphens,pointer-events,opacity,color,border,border-width,border-style,border-color,border-top,border-top-width,border-top-style,border-top-color,border-right,border-right-width,border-right-style,border-right-color,border-bottom,border-bottom-width,border-bottom-style,border-bottom-color,border-left,border-left-width,border-left-style,border-left-color,border-radius,border-top-left-radius,border-top-right-radius,border-bottom-right-radius,border-bottom-left-radius,border-image,border-image-source,border-image-slice,border-image-width,border-image-outset,border-image-repeat,outline,outline-width,outline-style,outline-color,outline-offset,background,background-color,background-image,background-repeat,background-attachment,background-position,background-position-x,background-position-y,background-clip,background-origin,background-size,box-decoration-break,box-shadow,text-shadow
|
||||
ij_scss_space_after_colon = true
|
||||
ij_scss_space_before_opening_brace = true
|
||||
ij_scss_use_double_quotes = true
|
||||
ij_scss_value_alignment = 0
|
||||
|
||||
[*.twig]
|
||||
ij_smart_tabs = true
|
||||
ij_visual_guides = none
|
||||
ij_wrap_on_typing = false
|
||||
ij_twig_keep_indents_on_empty_lines = false
|
||||
ij_twig_spaces_inside_comments_delimiters = true
|
||||
ij_twig_spaces_inside_delimiters = true
|
||||
ij_twig_spaces_inside_variable_delimiters = true
|
||||
|
||||
[.editorconfig]
|
||||
ij_visual_guides = none
|
||||
ij_editorconfig_align_group_field_declarations = false
|
||||
ij_editorconfig_space_after_colon = false
|
||||
ij_editorconfig_space_after_comma = true
|
||||
ij_editorconfig_space_before_colon = false
|
||||
ij_editorconfig_space_before_comma = false
|
||||
ij_editorconfig_spaces_around_assignment_operators = true
|
||||
|
||||
[{*.ant, *.fxml, *.jhm, *.jnlp, *.jrxml, *.rng, *.tld, *.wsdl, *.xml, *.xsd, *.xsl, *.xslt, *.xul, phpunit.xml.dist}]
|
||||
indent_size = 2
|
||||
tab_width = 2
|
||||
ij_smart_tabs = true
|
||||
ij_visual_guides = none
|
||||
ij_wrap_on_typing = false
|
||||
ij_xml_align_attributes = true
|
||||
ij_xml_align_text = false
|
||||
ij_xml_attribute_wrap = normal
|
||||
ij_xml_block_comment_at_first_column = true
|
||||
ij_xml_keep_blank_lines = 2
|
||||
ij_xml_keep_indents_on_empty_lines = false
|
||||
ij_xml_keep_line_breaks = false
|
||||
ij_xml_keep_line_breaks_in_text = true
|
||||
ij_xml_keep_whitespaces = false
|
||||
ij_xml_keep_whitespaces_around_cdata = preserve
|
||||
ij_xml_keep_whitespaces_inside_cdata = true
|
||||
ij_xml_line_comment_at_first_column = true
|
||||
ij_xml_space_after_tag_name = false
|
||||
ij_xml_space_around_equals_in_attribute = false
|
||||
ij_xml_space_inside_empty_tag = false
|
||||
ij_xml_text_wrap = off
|
||||
|
||||
[{*.bash,*.sh,*.zsh}]
|
||||
indent_size = 2
|
||||
tab_width = 2
|
||||
ij_visual_guides = none
|
||||
ij_shell_binary_ops_start_line = false
|
||||
ij_shell_keep_column_alignment_padding = false
|
||||
ij_shell_minify_program = false
|
||||
ij_shell_redirect_followed_by_space = false
|
||||
ij_shell_switch_cases_indented = false
|
||||
|
||||
[{*.cjs,*.js}]
|
||||
indent_style = tab
|
||||
ij_continuation_indent_size = 4
|
||||
ij_smart_tabs = true
|
||||
ij_visual_guides = none
|
||||
ij_javascript_align_imports = false
|
||||
ij_javascript_align_multiline_array_initializer_expression = false
|
||||
ij_javascript_align_multiline_binary_operation = false
|
||||
ij_javascript_align_multiline_chained_methods = false
|
||||
ij_javascript_align_multiline_extends_list = false
|
||||
ij_javascript_align_multiline_for = true
|
||||
ij_javascript_align_multiline_parameters = true
|
||||
ij_javascript_align_multiline_parameters_in_calls = false
|
||||
ij_javascript_align_multiline_ternary_operation = false
|
||||
ij_javascript_align_object_properties = 0
|
||||
ij_javascript_align_union_types = false
|
||||
ij_javascript_align_var_statements = 0
|
||||
ij_javascript_array_initializer_new_line_after_left_brace = false
|
||||
ij_javascript_array_initializer_right_brace_on_new_line = false
|
||||
ij_javascript_array_initializer_wrap = off
|
||||
ij_javascript_assignment_wrap = off
|
||||
ij_javascript_binary_operation_sign_on_next_line = false
|
||||
ij_javascript_binary_operation_wrap = off
|
||||
ij_javascript_blacklist_imports = rxjs/Rx,node_modules/**,**/node_modules/**,@angular/material,@angular/material/typings/**
|
||||
ij_javascript_blank_lines_after_imports = 1
|
||||
ij_javascript_blank_lines_around_class = 1
|
||||
ij_javascript_blank_lines_around_field = 0
|
||||
ij_javascript_blank_lines_around_function = 1
|
||||
ij_javascript_blank_lines_around_method = 1
|
||||
ij_javascript_block_brace_style = end_of_line
|
||||
ij_javascript_call_parameters_new_line_after_left_paren = false
|
||||
ij_javascript_call_parameters_right_paren_on_new_line = false
|
||||
ij_javascript_call_parameters_wrap = off
|
||||
ij_javascript_catch_on_new_line = false
|
||||
ij_javascript_chained_call_dot_on_new_line = true
|
||||
ij_javascript_class_brace_style = end_of_line
|
||||
ij_javascript_comma_on_new_line = false
|
||||
ij_javascript_do_while_brace_force = always
|
||||
ij_javascript_else_on_new_line = false
|
||||
ij_javascript_enforce_trailing_comma = keep
|
||||
ij_javascript_extends_keyword_wrap = off
|
||||
ij_javascript_extends_list_wrap = off
|
||||
ij_javascript_field_prefix = _
|
||||
ij_javascript_file_name_style = relaxed
|
||||
ij_javascript_finally_on_new_line = false
|
||||
ij_javascript_for_brace_force = always
|
||||
ij_javascript_for_statement_new_line_after_left_paren = false
|
||||
ij_javascript_for_statement_right_paren_on_new_line = false
|
||||
ij_javascript_for_statement_wrap = off
|
||||
ij_javascript_force_quote_style = false
|
||||
ij_javascript_force_semicolon_style = false
|
||||
ij_javascript_function_expression_brace_style = end_of_line
|
||||
ij_javascript_if_brace_force = always
|
||||
ij_javascript_import_merge_members = global
|
||||
ij_javascript_import_prefer_absolute_path = global
|
||||
ij_javascript_import_sort_members = true
|
||||
ij_javascript_import_sort_module_name = false
|
||||
ij_javascript_import_use_node_resolution = true
|
||||
ij_javascript_imports_wrap = on_every_item
|
||||
ij_javascript_indent_case_from_switch = true
|
||||
ij_javascript_indent_chained_calls = true
|
||||
ij_javascript_indent_package_children = 0
|
||||
ij_javascript_jsx_attribute_value = braces
|
||||
ij_javascript_keep_blank_lines_in_code = 2
|
||||
ij_javascript_keep_first_column_comment = true
|
||||
ij_javascript_keep_indents_on_empty_lines = false
|
||||
ij_javascript_keep_line_breaks = true
|
||||
ij_javascript_keep_simple_blocks_in_one_line = false
|
||||
ij_javascript_keep_simple_methods_in_one_line = false
|
||||
ij_javascript_line_comment_add_space = true
|
||||
ij_javascript_line_comment_at_first_column = false
|
||||
ij_javascript_method_brace_style = end_of_line
|
||||
ij_javascript_method_call_chain_wrap = off
|
||||
ij_javascript_method_parameters_new_line_after_left_paren = false
|
||||
ij_javascript_method_parameters_right_paren_on_new_line = false
|
||||
ij_javascript_method_parameters_wrap = off
|
||||
ij_javascript_object_literal_wrap = on_every_item
|
||||
ij_javascript_parentheses_expression_new_line_after_left_paren = false
|
||||
ij_javascript_parentheses_expression_right_paren_on_new_line = false
|
||||
ij_javascript_place_assignment_sign_on_next_line = false
|
||||
ij_javascript_prefer_as_type_cast = false
|
||||
ij_javascript_prefer_explicit_types_function_expression_returns = false
|
||||
ij_javascript_prefer_explicit_types_function_returns = false
|
||||
ij_javascript_prefer_explicit_types_vars_fields = false
|
||||
ij_javascript_prefer_parameters_wrap = false
|
||||
ij_javascript_reformat_c_style_comments = false
|
||||
ij_javascript_space_after_colon = true
|
||||
ij_javascript_space_after_comma = true
|
||||
ij_javascript_space_after_dots_in_rest_parameter = false
|
||||
ij_javascript_space_after_generator_mult = true
|
||||
ij_javascript_space_after_property_colon = true
|
||||
ij_javascript_space_after_quest = true
|
||||
ij_javascript_space_after_type_colon = true
|
||||
ij_javascript_space_after_unary_not = false
|
||||
ij_javascript_space_before_async_arrow_lparen = true
|
||||
ij_javascript_space_before_catch_keyword = true
|
||||
ij_javascript_space_before_catch_left_brace = true
|
||||
ij_javascript_space_before_catch_parentheses = true
|
||||
ij_javascript_space_before_class_lbrace = true
|
||||
ij_javascript_space_before_class_left_brace = true
|
||||
ij_javascript_space_before_colon = true
|
||||
ij_javascript_space_before_comma = false
|
||||
ij_javascript_space_before_do_left_brace = true
|
||||
ij_javascript_space_before_else_keyword = true
|
||||
ij_javascript_space_before_else_left_brace = true
|
||||
ij_javascript_space_before_finally_keyword = true
|
||||
ij_javascript_space_before_finally_left_brace = true
|
||||
ij_javascript_space_before_for_left_brace = true
|
||||
ij_javascript_space_before_for_parentheses = true
|
||||
ij_javascript_space_before_for_semicolon = false
|
||||
ij_javascript_space_before_function_left_parenth = true
|
||||
ij_javascript_space_before_generator_mult = false
|
||||
ij_javascript_space_before_if_left_brace = true
|
||||
ij_javascript_space_before_if_parentheses = true
|
||||
ij_javascript_space_before_method_call_parentheses = false
|
||||
ij_javascript_space_before_method_left_brace = true
|
||||
ij_javascript_space_before_method_parentheses = false
|
||||
ij_javascript_space_before_property_colon = false
|
||||
ij_javascript_space_before_quest = true
|
||||
ij_javascript_space_before_switch_left_brace = true
|
||||
ij_javascript_space_before_switch_parentheses = true
|
||||
ij_javascript_space_before_try_left_brace = true
|
||||
ij_javascript_space_before_type_colon = false
|
||||
ij_javascript_space_before_unary_not = false
|
||||
ij_javascript_space_before_while_keyword = true
|
||||
ij_javascript_space_before_while_left_brace = true
|
||||
ij_javascript_space_before_while_parentheses = true
|
||||
ij_javascript_spaces_around_additive_operators = false
|
||||
ij_javascript_spaces_around_arrow_function_operator = true
|
||||
ij_javascript_spaces_around_assignment_operators = true
|
||||
ij_javascript_spaces_around_bitwise_operators = true
|
||||
ij_javascript_spaces_around_equality_operators = true
|
||||
ij_javascript_spaces_around_logical_operators = true
|
||||
ij_javascript_spaces_around_multiplicative_operators = true
|
||||
ij_javascript_spaces_around_relational_operators = true
|
||||
ij_javascript_spaces_around_shift_operators = true
|
||||
ij_javascript_spaces_around_unary_operator = false
|
||||
ij_javascript_spaces_within_array_initializer_brackets = false
|
||||
ij_javascript_spaces_within_brackets = false
|
||||
ij_javascript_spaces_within_catch_parentheses = false
|
||||
ij_javascript_spaces_within_for_parentheses = false
|
||||
ij_javascript_spaces_within_if_parentheses = false
|
||||
ij_javascript_spaces_within_imports = false
|
||||
ij_javascript_spaces_within_interpolation_expressions = false
|
||||
ij_javascript_spaces_within_method_call_parentheses = false
|
||||
ij_javascript_spaces_within_method_parentheses = false
|
||||
ij_javascript_spaces_within_object_literal_braces = false
|
||||
ij_javascript_spaces_within_object_type_braces = true
|
||||
ij_javascript_spaces_within_parentheses = false
|
||||
ij_javascript_spaces_within_switch_parentheses = false
|
||||
ij_javascript_spaces_within_type_assertion = false
|
||||
ij_javascript_spaces_within_union_types = true
|
||||
ij_javascript_spaces_within_while_parentheses = false
|
||||
ij_javascript_special_else_if_treatment = true
|
||||
ij_javascript_ternary_operation_signs_on_next_line = false
|
||||
ij_javascript_ternary_operation_wrap = off
|
||||
ij_javascript_union_types_wrap = on_every_item
|
||||
ij_javascript_use_chained_calls_group_indents = true
|
||||
ij_javascript_use_double_quotes = true
|
||||
ij_javascript_use_explicit_js_extension = global
|
||||
ij_javascript_use_path_mapping = always
|
||||
ij_javascript_use_public_modifier = false
|
||||
ij_javascript_use_semicolon_after_statement = true
|
||||
ij_javascript_var_declaration_wrap = normal
|
||||
ij_javascript_while_brace_force = always
|
||||
ij_javascript_while_on_new_line = false
|
||||
ij_javascript_wrap_comments = false
|
||||
|
||||
[{*.ctp,*.hphp,*.inc,*.module,*.php,*.php4,*.php5,*.phtml}]
|
||||
indent_style = tab
|
||||
ij_continuation_indent_size = 4
|
||||
ij_smart_tabs = true
|
||||
ij_wrap_on_typing = false
|
||||
ij_php_align_assignments = false
|
||||
ij_php_align_class_constants = false
|
||||
ij_php_align_group_field_declarations = false
|
||||
ij_php_align_inline_comments = false
|
||||
ij_php_align_key_value_pairs = false
|
||||
ij_php_align_multiline_array_initializer_expression = false
|
||||
ij_php_align_multiline_binary_operation = false
|
||||
ij_php_align_multiline_chained_methods = false
|
||||
ij_php_align_multiline_extends_list = false
|
||||
ij_php_align_multiline_for = true
|
||||
ij_php_align_multiline_parameters = false
|
||||
ij_php_align_multiline_parameters_in_calls = false
|
||||
ij_php_align_multiline_ternary_operation = false
|
||||
ij_php_align_phpdoc_comments = false
|
||||
ij_php_align_phpdoc_param_names = false
|
||||
ij_php_anonymous_brace_style = end_of_line
|
||||
ij_php_api_weight = 1
|
||||
ij_php_array_initializer_new_line_after_left_brace = true
|
||||
ij_php_array_initializer_right_brace_on_new_line = true
|
||||
ij_php_array_initializer_wrap = on_every_item
|
||||
ij_php_assignment_wrap = off
|
||||
ij_php_attributes_wrap = off
|
||||
ij_php_author_weight = 8
|
||||
ij_php_binary_operation_sign_on_next_line = false
|
||||
ij_php_binary_operation_wrap = off
|
||||
ij_php_blank_lines_after_class_header = 0
|
||||
ij_php_blank_lines_after_function = 1
|
||||
ij_php_blank_lines_after_imports = 1
|
||||
ij_php_blank_lines_after_opening_tag = 0
|
||||
ij_php_blank_lines_after_package = 1
|
||||
ij_php_blank_lines_around_class = 1
|
||||
ij_php_blank_lines_around_constants = 0
|
||||
ij_php_blank_lines_around_field = 0
|
||||
ij_php_blank_lines_around_method = 1
|
||||
ij_php_blank_lines_before_class_end = 0
|
||||
ij_php_blank_lines_before_imports = 1
|
||||
ij_php_blank_lines_before_method_body = 0
|
||||
ij_php_blank_lines_before_package = 1
|
||||
ij_php_blank_lines_before_return_statement = 1
|
||||
ij_php_blank_lines_between_imports = 0
|
||||
ij_php_block_brace_style = end_of_line
|
||||
ij_php_call_parameters_new_line_after_left_paren = false
|
||||
ij_php_call_parameters_right_paren_on_new_line = false
|
||||
ij_php_call_parameters_wrap = normal
|
||||
ij_php_catch_on_new_line = true
|
||||
ij_php_category_weight = 28
|
||||
ij_php_class_brace_style = next_line
|
||||
ij_php_comma_after_last_array_element = true
|
||||
ij_php_concat_spaces = false
|
||||
ij_php_copyright_weight = 28
|
||||
ij_php_deprecated_weight = 2
|
||||
ij_php_do_while_brace_force = always
|
||||
ij_php_else_if_style = as_is
|
||||
ij_php_else_on_new_line = false
|
||||
ij_php_example_weight = 4
|
||||
ij_php_extends_keyword_wrap = off
|
||||
ij_php_extends_list_wrap = off
|
||||
ij_php_fields_default_visibility = private
|
||||
ij_php_filesource_weight = 28
|
||||
ij_php_finally_on_new_line = true
|
||||
ij_php_for_brace_force = always
|
||||
ij_php_for_statement_new_line_after_left_paren = false
|
||||
ij_php_for_statement_right_paren_on_new_line = false
|
||||
ij_php_for_statement_wrap = off
|
||||
ij_php_force_short_declaration_array_style = false
|
||||
ij_php_getters_setters_naming_style = camel_case
|
||||
ij_php_getters_setters_order_style = getters_first
|
||||
ij_php_global_weight = 28
|
||||
ij_php_group_use_wrap = on_every_item
|
||||
ij_php_if_brace_force = always
|
||||
ij_php_if_lparen_on_next_line = false
|
||||
ij_php_if_rparen_on_next_line = false
|
||||
ij_php_ignore_weight = 28
|
||||
ij_php_import_sorting = alphabetic
|
||||
ij_php_indent_break_from_case = true
|
||||
ij_php_indent_case_from_switch = true
|
||||
ij_php_indent_code_in_php_tags = false
|
||||
ij_php_internal_weight = 0
|
||||
ij_php_keep_blank_lines_after_lbrace = 2
|
||||
ij_php_keep_blank_lines_before_right_brace = 2
|
||||
ij_php_keep_blank_lines_in_code = 2
|
||||
ij_php_keep_blank_lines_in_declarations = 2
|
||||
ij_php_keep_control_statement_in_one_line = true
|
||||
ij_php_keep_first_column_comment = true
|
||||
ij_php_keep_indents_on_empty_lines = false
|
||||
ij_php_keep_line_breaks = true
|
||||
ij_php_keep_rparen_and_lbrace_on_one_line = false
|
||||
ij_php_keep_simple_classes_in_one_line = false
|
||||
ij_php_keep_simple_methods_in_one_line = false
|
||||
ij_php_lambda_brace_style = end_of_line
|
||||
ij_php_license_weight = 28
|
||||
ij_php_line_comment_add_space = false
|
||||
ij_php_line_comment_at_first_column = true
|
||||
ij_php_link_weight = 28
|
||||
ij_php_lower_case_boolean_const = true
|
||||
ij_php_lower_case_keywords = true
|
||||
ij_php_lower_case_null_const = true
|
||||
ij_php_method_brace_style = next_line
|
||||
ij_php_method_call_chain_wrap = off
|
||||
ij_php_method_parameters_new_line_after_left_paren = true
|
||||
ij_php_method_parameters_right_paren_on_new_line = true
|
||||
ij_php_method_parameters_wrap = normal
|
||||
ij_php_method_weight = 28
|
||||
ij_php_modifier_list_wrap = false
|
||||
ij_php_multiline_chained_calls_semicolon_on_new_line = false
|
||||
ij_php_namespace_brace_style = 1
|
||||
ij_php_new_line_after_php_opening_tag = false
|
||||
ij_php_null_type_position = in_the_end
|
||||
ij_php_package_weight = 28
|
||||
ij_php_param_weight = 5
|
||||
ij_php_parameters_attributes_wrap = off
|
||||
ij_php_parentheses_expression_new_line_after_left_paren = false
|
||||
ij_php_parentheses_expression_right_paren_on_new_line = false
|
||||
ij_php_phpdoc_blank_line_before_tags = true
|
||||
ij_php_phpdoc_blank_lines_around_parameters = true
|
||||
ij_php_phpdoc_keep_blank_lines = true
|
||||
ij_php_phpdoc_param_spaces_between_name_and_description = 1
|
||||
ij_php_phpdoc_param_spaces_between_tag_and_type = 1
|
||||
ij_php_phpdoc_param_spaces_between_type_and_name = 1
|
||||
ij_php_phpdoc_use_fqcn = true
|
||||
ij_php_phpdoc_wrap_long_lines = true
|
||||
ij_php_place_assignment_sign_on_next_line = false
|
||||
ij_php_place_parens_for_constructor = 0
|
||||
ij_php_property_read_weight = 28
|
||||
ij_php_property_weight = 28
|
||||
ij_php_property_write_weight = 28
|
||||
ij_php_return_type_on_new_line = false
|
||||
ij_php_return_weight = 6
|
||||
ij_php_see_weight = 3
|
||||
ij_php_since_weight = 28
|
||||
ij_php_sort_phpdoc_elements = true
|
||||
ij_php_space_after_colon = true
|
||||
ij_php_space_after_colon_in_named_argument = true
|
||||
ij_php_space_after_colon_in_return_type = true
|
||||
ij_php_space_after_comma = true
|
||||
ij_php_space_after_for_semicolon = true
|
||||
ij_php_space_after_quest = true
|
||||
ij_php_space_after_type_cast = false
|
||||
ij_php_space_after_unary_not = false
|
||||
ij_php_space_before_array_initializer_left_brace = false
|
||||
ij_php_space_before_catch_keyword = true
|
||||
ij_php_space_before_catch_left_brace = true
|
||||
ij_php_space_before_catch_parentheses = true
|
||||
ij_php_space_before_class_left_brace = true
|
||||
ij_php_space_before_closure_left_parenthesis = true
|
||||
ij_php_space_before_colon = true
|
||||
ij_php_space_before_colon_in_named_argument = false
|
||||
ij_php_space_before_colon_in_return_type = false
|
||||
ij_php_space_before_comma = false
|
||||
ij_php_space_before_do_left_brace = true
|
||||
ij_php_space_before_else_keyword = true
|
||||
ij_php_space_before_else_left_brace = true
|
||||
ij_php_space_before_finally_keyword = true
|
||||
ij_php_space_before_finally_left_brace = true
|
||||
ij_php_space_before_for_left_brace = true
|
||||
ij_php_space_before_for_parentheses = true
|
||||
ij_php_space_before_for_semicolon = false
|
||||
ij_php_space_before_if_left_brace = true
|
||||
ij_php_space_before_if_parentheses = true
|
||||
ij_php_space_before_method_call_parentheses = false
|
||||
ij_php_space_before_method_left_brace = true
|
||||
ij_php_space_before_method_parentheses = false
|
||||
ij_php_space_before_quest = true
|
||||
ij_php_space_before_short_closure_left_parenthesis = false
|
||||
ij_php_space_before_switch_left_brace = true
|
||||
ij_php_space_before_switch_parentheses = true
|
||||
ij_php_space_before_try_left_brace = true
|
||||
ij_php_space_before_unary_not = false
|
||||
ij_php_space_before_while_keyword = true
|
||||
ij_php_space_before_while_left_brace = true
|
||||
ij_php_space_before_while_parentheses = true
|
||||
ij_php_space_between_ternary_quest_and_colon = false
|
||||
ij_php_spaces_around_additive_operators = true
|
||||
ij_php_spaces_around_arrow = false
|
||||
ij_php_spaces_around_assignment_in_declare = false
|
||||
ij_php_spaces_around_assignment_operators = true
|
||||
ij_php_spaces_around_bitwise_operators = true
|
||||
ij_php_spaces_around_equality_operators = true
|
||||
ij_php_spaces_around_logical_operators = true
|
||||
ij_php_spaces_around_multiplicative_operators = true
|
||||
ij_php_spaces_around_null_coalesce_operator = true
|
||||
ij_php_spaces_around_relational_operators = true
|
||||
ij_php_spaces_around_shift_operators = true
|
||||
ij_php_spaces_around_unary_operator = false
|
||||
ij_php_spaces_around_var_within_brackets = false
|
||||
ij_php_spaces_within_array_initializer_braces = false
|
||||
ij_php_spaces_within_brackets = false
|
||||
ij_php_spaces_within_catch_parentheses = false
|
||||
ij_php_spaces_within_for_parentheses = false
|
||||
ij_php_spaces_within_if_parentheses = false
|
||||
ij_php_spaces_within_method_call_parentheses = false
|
||||
ij_php_spaces_within_method_parentheses = false
|
||||
ij_php_spaces_within_parentheses = false
|
||||
ij_php_spaces_within_short_echo_tags = true
|
||||
ij_php_spaces_within_switch_parentheses = false
|
||||
ij_php_spaces_within_while_parentheses = false
|
||||
ij_php_special_else_if_treatment = true
|
||||
ij_php_subpackage_weight = 28
|
||||
ij_php_ternary_operation_signs_on_next_line = false
|
||||
ij_php_ternary_operation_wrap = off
|
||||
ij_php_throws_weight = 7
|
||||
ij_php_todo_weight = 28
|
||||
ij_php_unknown_tag_weight = 28
|
||||
ij_php_upper_case_boolean_const = false
|
||||
ij_php_upper_case_null_const = false
|
||||
ij_php_uses_weight = 28
|
||||
ij_php_var_weight = 28
|
||||
ij_php_variable_naming_style = mixed
|
||||
ij_php_version_weight = 28
|
||||
ij_php_while_brace_force = always
|
||||
ij_php_while_on_new_line = false
|
||||
|
||||
[{*.har,*.jsb2,*.jsb3,*.json,.babelrc,.eslintrc,.stylelintrc,bowerrc,composer.lock,jest.config}]
|
||||
indent_size = 2
|
||||
ij_visual_guides = none
|
||||
ij_json_keep_blank_lines_in_code = 0
|
||||
ij_json_keep_indents_on_empty_lines = false
|
||||
ij_json_keep_line_breaks = true
|
||||
ij_json_space_after_colon = true
|
||||
ij_json_space_after_comma = true
|
||||
ij_json_space_before_colon = true
|
||||
ij_json_space_before_comma = false
|
||||
ij_json_spaces_within_braces = false
|
||||
ij_json_spaces_within_brackets = false
|
||||
ij_json_wrap_long_lines = false
|
||||
|
||||
[{*.htm,*.html,*.sht,*.shtm,*.shtml}]
|
||||
indent_style = tab
|
||||
ij_smart_tabs = true
|
||||
ij_visual_guides = none
|
||||
ij_html_add_new_line_before_tags = body, div, p, form, h1, h2, h3
|
||||
ij_html_align_attributes = true
|
||||
ij_html_align_text = false
|
||||
ij_html_attribute_wrap = normal
|
||||
ij_html_block_comment_at_first_column = true
|
||||
ij_html_do_not_align_children_of_min_lines = 0
|
||||
ij_html_do_not_break_if_inline_tags = title,h1,h2,h3,h4,h5,h6,p
|
||||
ij_html_do_not_indent_children_of_tags = html,body,thead,tbody,tfoot,style,script,head
|
||||
ij_html_enforce_quotes = false
|
||||
ij_html_inline_tags = a,abbr,acronym,b,basefont,bdo,big,br,cite,cite,code,dfn,em,font,i,img,input,kbd,label,q,s,samp,select,small,span,strike,strong,sub,sup,textarea,tt,u,var
|
||||
ij_html_keep_blank_lines = 2
|
||||
ij_html_keep_indents_on_empty_lines = false
|
||||
ij_html_keep_line_breaks = true
|
||||
ij_html_keep_line_breaks_in_text = true
|
||||
ij_html_keep_whitespaces = false
|
||||
ij_html_keep_whitespaces_inside = span,pre,textarea
|
||||
ij_html_line_comment_at_first_column = true
|
||||
ij_html_new_line_after_last_attribute = never
|
||||
ij_html_new_line_before_first_attribute = never
|
||||
ij_html_quote_style = none
|
||||
ij_html_remove_new_line_before_tags = br
|
||||
ij_html_space_after_tag_name = false
|
||||
ij_html_space_around_equality_in_attribute = false
|
||||
ij_html_space_inside_empty_tag = false
|
||||
ij_html_text_wrap = normal
|
||||
ij_html_uniform_ident = false
|
||||
|
||||
[{*.yaml, *.yml}]
|
||||
indent_size = 2
|
||||
ij_visual_guides = none
|
||||
ij_yaml_align_values_properties = do_not_align
|
||||
ij_yaml_autoinsert_sequence_marker = true
|
||||
ij_yaml_block_mapping_on_new_line = false
|
||||
ij_yaml_indent_sequence_value = true
|
||||
ij_yaml_keep_indents_on_empty_lines = false
|
||||
ij_yaml_keep_line_breaks = true
|
||||
ij_yaml_sequence_on_new_line = false
|
||||
ij_yaml_space_before_colon = false
|
||||
ij_yaml_spaces_within_braces = true
|
||||
ij_yaml_spaces_within_brackets = true
|
||||
129
.gitignore
vendored
Normal file
129
.gitignore
vendored
Normal file
@@ -0,0 +1,129 @@
|
||||
|
||||
# no slash at the end to handle also symlinks
|
||||
/toolkit
|
||||
/env-*
|
||||
|
||||
# composer reserver directory, from sources, populate/update using "composer install"
|
||||
vendor/*
|
||||
test/vendor/*
|
||||
|
||||
# all conf but listing prevention
|
||||
/conf/**
|
||||
!/conf/.htaccess
|
||||
!/conf/web.config
|
||||
|
||||
# all datas but listing prevention
|
||||
/data/**
|
||||
!/data/.htaccess
|
||||
!/data/index.php
|
||||
!/data/web.config
|
||||
|
||||
# iTop extensions
|
||||
/extensions/**
|
||||
!/extensions/readme.txt
|
||||
|
||||
# all logs but listing prevention
|
||||
/log/**
|
||||
!/log/.htaccess
|
||||
!/log/index.php
|
||||
!/log/web.config
|
||||
|
||||
|
||||
# Jetbrains
|
||||
/.idea/**
|
||||
!/.idea/encodings.xml
|
||||
!/.idea/codeStyles
|
||||
!/.idea/codeStyles/*
|
||||
!/.idea/inspectionProfiles
|
||||
!/.idea/inspectionProfiles/*
|
||||
|
||||
#phpdocumentor temp file
|
||||
ast.dump
|
||||
|
||||
# CMake
|
||||
cmake-build-*/
|
||||
|
||||
# Mongo Explorer plugin
|
||||
.idea/**/mongoSettings.xml
|
||||
|
||||
# File-based project format
|
||||
*.iws
|
||||
|
||||
# IntelliJ
|
||||
out/
|
||||
|
||||
# mpeltonen/sbt-idea plugin
|
||||
.idea_modules/
|
||||
|
||||
# JIRA plugin
|
||||
atlassian-ide-plugin.xml
|
||||
|
||||
# Cursive Clojure plugin
|
||||
.idea/replstate.xml
|
||||
|
||||
# Crashlytics plugin (for Android Studio and IntelliJ)
|
||||
com_crashlytics_export_strings.xml
|
||||
crashlytics.properties
|
||||
crashlytics-build.properties
|
||||
fabric.properties
|
||||
|
||||
# Editor-based Rest Client
|
||||
.idea/httpRequests
|
||||
### Eclipse template
|
||||
|
||||
.metadata
|
||||
tmp/
|
||||
*.tmp
|
||||
*.bak
|
||||
*.swp
|
||||
*~.nib
|
||||
local.properties
|
||||
.settings/
|
||||
.loadpath
|
||||
.recommenders
|
||||
.project
|
||||
|
||||
# External tool builders
|
||||
.externalToolBuilders/
|
||||
|
||||
# Locally stored "Eclipse launch configurations"
|
||||
*.launch
|
||||
|
||||
# PyDev specific (Python IDE for Eclipse)
|
||||
*.pydevproject
|
||||
|
||||
# CDT-specific (C/C++ Development Tooling)
|
||||
.cproject
|
||||
|
||||
# CDT- autotools
|
||||
.autotools
|
||||
|
||||
# Java annotation processor (APT)
|
||||
.factorypath
|
||||
|
||||
# PDT-specific (PHP Development Tools)
|
||||
.buildpath
|
||||
|
||||
# sbteclipse plugin
|
||||
.target
|
||||
|
||||
# Tern plugin
|
||||
.tern-project
|
||||
|
||||
# TeXlipse plugin
|
||||
.texlipse
|
||||
|
||||
# STS (Spring Tool Suite)
|
||||
.springBeans
|
||||
|
||||
# Code Recommenders
|
||||
.recommenders/
|
||||
|
||||
# Annotation Processing
|
||||
.apt_generated/
|
||||
|
||||
# Scala IDE specific (Scala & Java development for Eclipse)
|
||||
.cache-main
|
||||
.scala_dependencies
|
||||
.worksheet
|
||||
|
||||
57
.idea/codeStyles/Project.xml
generated
Normal file
57
.idea/codeStyles/Project.xml
generated
Normal file
@@ -0,0 +1,57 @@
|
||||
<component name="ProjectCodeStyleConfiguration">
|
||||
<code_scheme name="Project" version="173">
|
||||
<option name="LINE_SEPARATOR" value=" " />
|
||||
<option name="RIGHT_MARGIN" value="320" />
|
||||
<HTMLCodeStyleSettings>
|
||||
<option name="HTML_DO_NOT_INDENT_CHILDREN_OF" value="html,body,thead,tbody,tfoot,script,style" />
|
||||
<option name="HTML_DO_NOT_ALIGN_CHILDREN_OF_MIN_LINES" value="4" />
|
||||
</HTMLCodeStyleSettings>
|
||||
<PHPCodeStyleSettings>
|
||||
<option name="CONCAT_SPACES" value="false" />
|
||||
<option name="PHPDOC_BLANK_LINE_BEFORE_TAGS" value="true" />
|
||||
<option name="PHPDOC_BLANK_LINES_AROUND_PARAMETERS" value="true" />
|
||||
<option name="PHPDOC_WRAP_LONG_LINES" value="true" />
|
||||
<option name="LOWER_CASE_BOOLEAN_CONST" value="true" />
|
||||
<option name="LOWER_CASE_NULL_CONST" value="true" />
|
||||
<option name="BLANK_LINES_BEFORE_RETURN_STATEMENT" value="1" />
|
||||
<option name="KEEP_RPAREN_AND_LBRACE_ON_ONE_LINE" value="true" />
|
||||
<option name="PHPDOC_USE_FQCN" value="true" />
|
||||
</PHPCodeStyleSettings>
|
||||
<codeStyleSettings language="JavaScript">
|
||||
<option name="BRACE_STYLE" value="2" />
|
||||
<option name="ELSE_ON_NEW_LINE" value="true" />
|
||||
<option name="IF_BRACE_FORCE" value="3" />
|
||||
<indentOptions>
|
||||
<option name="USE_TAB_CHARACTER" value="true" />
|
||||
</indentOptions>
|
||||
</codeStyleSettings>
|
||||
<codeStyleSettings language="PHP">
|
||||
<option name="RIGHT_MARGIN" value="320" />
|
||||
<option name="BLANK_LINES_AFTER_PACKAGE" value="1" />
|
||||
<option name="BRACE_STYLE" value="2" />
|
||||
<option name="ELSE_ON_NEW_LINE" value="true" />
|
||||
<option name="ALIGN_MULTILINE_PARAMETERS" value="false" />
|
||||
<option name="SPACE_BEFORE_FOR_PARENTHESES" value="false" />
|
||||
<option name="CALL_PARAMETERS_WRAP" value="1" />
|
||||
<option name="METHOD_PARAMETERS_WRAP" value="1" />
|
||||
<option name="METHOD_PARAMETERS_LPAREN_ON_NEXT_LINE" value="true" />
|
||||
<option name="METHOD_PARAMETERS_RPAREN_ON_NEXT_LINE" value="true" />
|
||||
<option name="ARRAY_INITIALIZER_WRAP" value="5" />
|
||||
<option name="ARRAY_INITIALIZER_LBRACE_ON_NEXT_LINE" value="true" />
|
||||
<option name="ARRAY_INITIALIZER_RBRACE_ON_NEXT_LINE" value="true" />
|
||||
<option name="IF_BRACE_FORCE" value="3" />
|
||||
<option name="DOWHILE_BRACE_FORCE" value="3" />
|
||||
<option name="WHILE_BRACE_FORCE" value="3" />
|
||||
<option name="FOR_BRACE_FORCE" value="3" />
|
||||
<indentOptions>
|
||||
<option name="USE_TAB_CHARACTER" value="true" />
|
||||
<option name="SMART_TABS" value="true" />
|
||||
</indentOptions>
|
||||
</codeStyleSettings>
|
||||
<codeStyleSettings language="XML">
|
||||
<indentOptions>
|
||||
<option name="USE_TAB_CHARACTER" value="true" />
|
||||
</indentOptions>
|
||||
</codeStyleSettings>
|
||||
</code_scheme>
|
||||
</component>
|
||||
5
.idea/codeStyles/codeStyleConfig.xml
generated
Normal file
5
.idea/codeStyles/codeStyleConfig.xml
generated
Normal file
@@ -0,0 +1,5 @@
|
||||
<component name="ProjectCodeStyleConfiguration">
|
||||
<state>
|
||||
<option name="PREFERRED_PROJECT_CODE_STYLE" value="Combodo" />
|
||||
</state>
|
||||
</component>
|
||||
6
.idea/encodings.xml
generated
Normal file
6
.idea/encodings.xml
generated
Normal file
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="Encoding" defaultCharsetForPropertiesFiles="UTF-8">
|
||||
<file url="PROJECT" charset="UTF-8" />
|
||||
</component>
|
||||
</project>
|
||||
44
.idea/inspectionProfiles/Combodo.xml
generated
Normal file
44
.idea/inspectionProfiles/Combodo.xml
generated
Normal file
@@ -0,0 +1,44 @@
|
||||
<component name="InspectionProjectProfileManager">
|
||||
<profile version="1.0">
|
||||
<option name="myName" value="Combodo" />
|
||||
<inspection_tool class="InconsistentLineSeparators" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||
<inspection_tool class="MysqlParsingInspection" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="PhpIncludeInspection" enabled="true" level="WEAK WARNING" enabled_by_default="true" />
|
||||
<inspection_tool class="PhpMethodParametersCountMismatchInspection" enabled="true" level="ERROR" enabled_by_default="true" />
|
||||
<inspection_tool class="PhpTooManyParametersInspection" enabled="true" level="WARNING" enabled_by_default="true">
|
||||
<option name="limit" value="7" />
|
||||
</inspection_tool>
|
||||
<inspection_tool class="PhpUndefinedClassInspection" enabled="true" level="WARNING" enabled_by_default="true">
|
||||
<option name="DONT_REPORT_MULTI_RESOLVE" value="true" />
|
||||
</inspection_tool>
|
||||
<inspection_tool class="PhpUndefinedMethodInspection" enabled="true" level="WEAK WARNING" enabled_by_default="true" />
|
||||
<inspection_tool class="PhpUnhandledExceptionInspection" enabled="true" level="WEAK WARNING" enabled_by_default="true" />
|
||||
<inspection_tool class="PhpUnusedLocalVariableInspection" enabled="true" level="WEAK WARNING" enabled_by_default="true">
|
||||
<option name="DONT_REPORT_INSIDE_LIST" value="true" />
|
||||
</inspection_tool>
|
||||
<inspection_tool class="PhpUnusedParameterInspection" enabled="true" level="WEAK WARNING" enabled_by_default="true">
|
||||
<option name="DONT_REPORT_ABSTRACT_CLASS" value="true" />
|
||||
</inspection_tool>
|
||||
<inspection_tool class="SqlAddNotNullColumnInspection" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="SqlAmbiguousColumnInspection" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="SqlAutoIncrementDuplicateInspection" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="SqlCheckUsingColumnsInspection" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="SqlConstantConditionInspection" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="SqlDeprecateTypeInspection" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="SqlDerivedTableAliasInspection" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="SqlDialectInspection" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="SqlDropIndexedColumnInspection" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="SqlIdentifierInspection" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="SqlInsertValuesInspection" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="SqlNoDataSourceInspection" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="SqlNullComparisonInspection" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="SqlPostgresqlSelectFromProcedureInspection" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="SqlResolveInspection" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="SqlShouldBeInGroupByInspection" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="SqlSideEffectsInspection" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="SqlSignatureInspection" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="SqlStorageInspection" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="SqlTypeInspection" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="SqlUnusedVariableInspection" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
</profile>
|
||||
</component>
|
||||
19
.idea/inspectionProfiles/Project_Default.xml
generated
Normal file
19
.idea/inspectionProfiles/Project_Default.xml
generated
Normal file
@@ -0,0 +1,19 @@
|
||||
<component name="InspectionProjectProfileManager">
|
||||
<profile version="1.0">
|
||||
<option name="myName" value="Project Default" />
|
||||
<inspection_tool class="InconsistentLineSeparators" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||
<inspection_tool class="PhpIncludeInspection" enabled="true" level="WEAK WARNING" enabled_by_default="true" />
|
||||
<inspection_tool class="PhpMethodParametersCountMismatchInspection" enabled="true" level="ERROR" enabled_by_default="true" />
|
||||
<inspection_tool class="PhpTooManyParametersInspection" enabled="true" level="WARNING" enabled_by_default="true">
|
||||
<option name="limit" value="7" />
|
||||
</inspection_tool>
|
||||
<inspection_tool class="PhpUndefinedClassInspection" enabled="true" level="WARNING" enabled_by_default="true">
|
||||
<option name="DONT_REPORT_MULTI_RESOLVE" value="true" />
|
||||
</inspection_tool>
|
||||
<inspection_tool class="PhpUnhandledExceptionInspection" enabled="true" level="WEAK WARNING" enabled_by_default="true" />
|
||||
<inspection_tool class="PhpUnusedParameterInspection" enabled="true" level="WEAK WARNING" enabled_by_default="true">
|
||||
<option name="DONT_REPORT_ABSTRACT_CLASS" value="true" />
|
||||
</inspection_tool>
|
||||
<inspection_tool class="SqlNoDataSourceInspection" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
</profile>
|
||||
</component>
|
||||
6
.idea/inspectionProfiles/profiles_settings.xml
generated
Normal file
6
.idea/inspectionProfiles/profiles_settings.xml
generated
Normal file
@@ -0,0 +1,6 @@
|
||||
<component name="InspectionProjectProfileManager">
|
||||
<settings>
|
||||
<option name="PROJECT_PROFILE" value="Combodo" />
|
||||
<version value="1.0" />
|
||||
</settings>
|
||||
</component>
|
||||
47
.make/release/update-versions.php
Normal file
47
.make/release/update-versions.php
Normal file
@@ -0,0 +1,47 @@
|
||||
<?php
|
||||
|
||||
/*******************************************************************************
|
||||
* Tool to automate version update before release
|
||||
*
|
||||
* Will update version in the following files :
|
||||
*
|
||||
* * datamodels/2.x/.../module.*.php
|
||||
* * datamodels/2.x/version.xml
|
||||
* * css/css-variables.scss $version
|
||||
*
|
||||
* Usage :
|
||||
* `php .make\release\update-versions.php "2.7.0-rc"`
|
||||
*
|
||||
* @since 2.7.0
|
||||
******************************************************************************/
|
||||
|
||||
|
||||
|
||||
require_once (__DIR__.'/../../approot.inc.php');
|
||||
require_once (__DIR__.DIRECTORY_SEPARATOR.'update.classes.inc.php');
|
||||
|
||||
|
||||
|
||||
/** @var \FileVersionUpdater[] $aFilesUpdaters */
|
||||
$aFilesUpdaters = array(
|
||||
new iTopVersionFileUpdater(),
|
||||
new CssVariablesFileUpdater(),
|
||||
new DatamodelsModulesFiles(),
|
||||
);
|
||||
|
||||
if (count($argv) === 1)
|
||||
{
|
||||
echo '/!\ You must pass the new version as parameter';
|
||||
exit(1);
|
||||
}
|
||||
$sVersionLabel = $argv[1];
|
||||
if (empty($sVersionLabel))
|
||||
{
|
||||
echo 'Version passed as parameter is empty !';
|
||||
exit(2);
|
||||
}
|
||||
|
||||
foreach ($aFilesUpdaters as $oFileVersionUpdater)
|
||||
{
|
||||
$oFileVersionUpdater->UpdateAllFiles($sVersionLabel);
|
||||
}
|
||||
36
.make/release/update-xml.php
Normal file
36
.make/release/update-xml.php
Normal file
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
|
||||
/*******************************************************************************
|
||||
* Tool to automate datamodel version update in XML
|
||||
*
|
||||
* Will update version in the following files :
|
||||
*
|
||||
* datamodels/2.x/.../datamodel.*.xml
|
||||
*
|
||||
* Usage :
|
||||
* `php .make\release\update-xml.php "1.7"`
|
||||
*
|
||||
* @since 2.7.0
|
||||
******************************************************************************/
|
||||
|
||||
|
||||
|
||||
require_once (__DIR__.'/../../approot.inc.php');
|
||||
require_once (__DIR__.DIRECTORY_SEPARATOR.'update.classes.inc.php');
|
||||
|
||||
|
||||
|
||||
if (count($argv) === 1)
|
||||
{
|
||||
echo '/!\ You must pass the new version as parameter';
|
||||
exit(1);
|
||||
}
|
||||
$sVersionLabel = $argv[1];
|
||||
if (empty($sVersionLabel))
|
||||
{
|
||||
echo 'Version passed as parameter is empty !';
|
||||
exit(2);
|
||||
}
|
||||
|
||||
$oFileVersionUpdater = new DatamodelsXmlFiles();
|
||||
$oFileVersionUpdater->UpdateAllFiles($sVersionLabel);
|
||||
169
.make/release/update.classes.inc.php
Normal file
169
.make/release/update.classes.inc.php
Normal file
@@ -0,0 +1,169 @@
|
||||
<?php
|
||||
|
||||
/*******************************************************************************
|
||||
* Classes for updater tools
|
||||
*
|
||||
* @see update-versions.php
|
||||
* @see update-xml.php
|
||||
******************************************************************************/
|
||||
|
||||
|
||||
|
||||
require_once (__DIR__.'/../../approot.inc.php');
|
||||
|
||||
|
||||
|
||||
|
||||
abstract class FileVersionUpdater
|
||||
{
|
||||
/**
|
||||
* @return string[] full path of files to modify
|
||||
*/
|
||||
abstract public function GetFiles();
|
||||
|
||||
/**
|
||||
* Warnign : will consume lots of memory on larger files !
|
||||
*
|
||||
* @param string $sVersionLabel
|
||||
* @param string $sFileContent
|
||||
* @param string $sFileFullPath
|
||||
*
|
||||
* @return string file content with replaced values
|
||||
*/
|
||||
abstract public function UpdateFileContent($sVersionLabel, $sFileContent, $sFileFullPath);
|
||||
|
||||
public function UpdateAllFiles($sVersionLabel)
|
||||
{
|
||||
$aFilesToUpdate = $this->GetFiles();
|
||||
$sFileUpdaterName = get_class($this);
|
||||
echo "# Updater : $sFileUpdaterName\n";
|
||||
foreach ($aFilesToUpdate as $sFileToUpdateFullPath)
|
||||
{
|
||||
try
|
||||
{
|
||||
$sCurrentFileContent = file_get_contents($sFileToUpdateFullPath);
|
||||
$sNewFileContent = $this->UpdateFileContent($sVersionLabel, $sCurrentFileContent, $sFileToUpdateFullPath);
|
||||
file_put_contents($sFileToUpdateFullPath, $sNewFileContent);
|
||||
echo " - $sFileToUpdateFullPath : OK !\n";
|
||||
}
|
||||
catch (Exception $e)
|
||||
{
|
||||
echo " - $sFileToUpdateFullPath : Error :(\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
abstract class AbstractSingleFileVersionUpdater extends FileVersionUpdater
|
||||
{
|
||||
private $sFileToUpdate;
|
||||
|
||||
public function __construct($sFileToUpdate)
|
||||
{
|
||||
$this->sFileToUpdate = $sFileToUpdate;
|
||||
}
|
||||
|
||||
public function GetFiles()
|
||||
{
|
||||
return array(APPROOT.$this->sFileToUpdate);
|
||||
}
|
||||
}
|
||||
|
||||
class iTopVersionFileUpdater extends AbstractSingleFileVersionUpdater
|
||||
{
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct('datamodels/2.x/version.xml');
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function UpdateFileContent($sVersionLabel, $sFileContent, $sFileFullPath)
|
||||
{
|
||||
return preg_replace(
|
||||
'/(<version>)[^<]*(<\/version>)/',
|
||||
'${1}'.$sVersionLabel.'${2}',
|
||||
$sFileContent
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class CssVariablesFileUpdater extends AbstractSingleFileVersionUpdater
|
||||
{
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct('css/css-variables.scss');
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function UpdateFileContent($sVersionLabel, $sFileContent, $sFileFullPath)
|
||||
{
|
||||
return preg_replace(
|
||||
'/(\$version: "v)[^"]*(";)/',
|
||||
'${1}'.$sVersionLabel.'${2}',
|
||||
$sFileContent
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
abstract class AbstractGlobFileVersionUpdater extends FileVersionUpdater
|
||||
{
|
||||
protected $sGlobPattern;
|
||||
|
||||
public function __construct($sGlobPattern)
|
||||
{
|
||||
$this->sGlobPattern = $sGlobPattern;
|
||||
}
|
||||
|
||||
public function GetFiles()
|
||||
{
|
||||
return glob($this->sGlobPattern);
|
||||
}
|
||||
}
|
||||
|
||||
class DatamodelsModulesFiles extends AbstractGlobFileVersionUpdater
|
||||
{
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct(APPROOT.'datamodels/2.x/*/module.*.php');
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function UpdateFileContent($sVersionLabel, $sFileContent, $sFileFullPath)
|
||||
{
|
||||
$sModulePath = realpath($sFileFullPath);
|
||||
$sModuleFileName = basename($sModulePath, 1);
|
||||
$sModuleName = preg_replace('/[^.]+\.([^.]+)\.php/', '$1', $sModuleFileName);
|
||||
|
||||
return preg_replace(
|
||||
"/('$sModuleName\/)[^']+(')/",
|
||||
'${1}'.$sVersionLabel.'${2}',
|
||||
$sFileContent
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class DatamodelsXmlFiles extends AbstractGlobFileVersionUpdater
|
||||
{
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct(APPROOT.'datamodels/2.x/*/datamodel.*.xml');
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function UpdateFileContent($sVersionLabel, $sFileContent, $sFileFullPath)
|
||||
{
|
||||
return preg_replace(
|
||||
'/(<itop_design .* version=")[^"]+(">)/',
|
||||
'${1}'.$sVersionLabel.'${2}',
|
||||
$sFileContent
|
||||
);
|
||||
}
|
||||
}
|
||||
11
Jenkinsfile
vendored
Normal file
11
Jenkinsfile
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
def infra
|
||||
|
||||
node(){
|
||||
checkout scm
|
||||
|
||||
infra = load '/var/lib/jenkins/workspace/itop-test-infra_master/src/Infra.groovy'
|
||||
}
|
||||
|
||||
|
||||
infra.call()
|
||||
|
||||
132
README.md
Normal file
132
README.md
Normal file
@@ -0,0 +1,132 @@
|
||||
<p align="center"><a href="https://www.combodo.com/itop-193" target="_blank">
|
||||
<img src="https://www.combodo.com/logos/logo-itop.svg">
|
||||
</a></p>
|
||||
|
||||
|
||||
# iTop - ITSM & CMDB
|
||||
|
||||
iTop stands for *IT Operations Portal*.
|
||||
It is a complete open source, ITIL, web based service management tool including a fully customizable CMDB, a helpdesk system and a document management tool.
|
||||
iTop also offers mass import tools and web services to integrate with your IT
|
||||
|
||||
## Features
|
||||
- Fully configurable [Configuration Management (CMDB)][10]
|
||||
- [HelpDesk][11] and Incident Management
|
||||
- [Service and Contract Management][12]
|
||||
- [Change][13] Management
|
||||
- Configurable [SLA][14] Management
|
||||
- Graphical [impact analysis][15]
|
||||
- [CSV import][16] tool for any data
|
||||
- Consistency [audit][17] to check data quality
|
||||
- [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]: for support request
|
||||
- [iTop Tickets][2]: for feature requests and bug reports
|
||||
- [Releases download][3]
|
||||
- [iTop documentation][4] for iTop and official extensions
|
||||
- [iTop extensions][5] for discovering and installing extensions
|
||||
|
||||
|
||||
# About Us
|
||||
|
||||
iTop development is sponsored, led and supported by [Combodo][0].
|
||||
|
||||
|
||||
# Contributors
|
||||
|
||||
We would like to give a special thank you to the people from the community who contributed to this project, including:
|
||||
- Alves, David
|
||||
- Beck, Pedro
|
||||
- Bilger, Jean-François
|
||||
- Bostoen, Jeffrey
|
||||
- Cardoso, Anderson
|
||||
- Cassaro, Bruno
|
||||
- Casteleyn, Thomas
|
||||
- Castro, Randall Badilla
|
||||
- Colantoni, Maria Laura
|
||||
- Dvořák, Lukáš
|
||||
- Goethals, Stefan
|
||||
- Gumble, David
|
||||
- Hippler, Lars
|
||||
- Khamit, Shamil
|
||||
- Kincel, Martin
|
||||
- Konečný, Kamil
|
||||
- Kunin, Vladimir
|
||||
- Lassiter, Dennis
|
||||
- Lucas, Jonathan
|
||||
- Malik, Remie
|
||||
- Rosenke, Stephan
|
||||
- Seki, Shoji
|
||||
- Shilov, Vladimir
|
||||
- Tulio, Marco
|
||||
- Turrubiates, Miguel
|
||||
|
||||
#### Aliases
|
||||
- chifu1234
|
||||
- cprobst
|
||||
- Karkoff1212
|
||||
- larhip
|
||||
- Laura
|
||||
- Purple Grape
|
||||
- Schlobinux
|
||||
- theBigOne
|
||||
- ulmerspatz
|
||||
|
||||
#### Companies
|
||||
- Hardis
|
||||
- ITOMIG
|
||||
|
||||
|
||||
|
||||
[0]: https://www.combodo.com
|
||||
|
||||
[1]: https://sourceforge.net/p/itop/discussion/
|
||||
[2]: https://sourceforge.net/p/itop/tickets/
|
||||
[3]: https://sourceforge.net/projects/itop/files/itop/
|
||||
[4]: https://www.itophub.io/wiki
|
||||
[5]: https://store.itophub.io/en_US/
|
||||
|
||||
|
||||
|
||||
[10]: https://www.itophub.io/wiki/page?id=2_5_0%3Adatamodel%3Astart#configuration_management_cmdb
|
||||
[11]: https://www.itophub.io/wiki/page?id=2_5_0%3Adatamodel%3Astart#ticketing
|
||||
[12]: https://www.itophub.io/wiki/page?id=2_5_0%3Adatamodel%3Astart#service_management
|
||||
[13]: https://www.itophub.io/wiki/page?id=2_5_0%3Adatamodel%3Astart#change_management
|
||||
[14]: https://www.itophub.io/wiki/page?id=2_5_0%3Aimplementation%3Astart#service_level_agreements_and_targets
|
||||
[15]: https://www.itophub.io/wiki/page?id=2_5_0%3Auser%3Aactions#relations
|
||||
[16]: https://www.itophub.io/wiki/page?id=2_5_0%3Auser%3Abulk_modify#uploading_data
|
||||
[17]: https://www.itophub.io/wiki/page?id=2_5_0%3Aadmin%3Aaudit
|
||||
[18]: https://www.itophub.io/wiki/page?id=2_5_0%3Aadvancedtopics%3Adata_synchro_overview
|
||||
|
||||
|
||||
|
||||
[50]: https://www.itophub.io/wiki/page?id=2_4_0:release:change_log
|
||||
[51]: https://www.itophub.io/wiki/page?id=2_4_0:release:2_4_whats_new
|
||||
[52]: https://www.itophub.io/wiki/page?id=2_4_0:install:230_to_240_migration_notes
|
||||
[53]: https://sourceforge.net/projects/itop/files/itop/2.4.1
|
||||
|
||||
[54]: https://www.itophub.io/wiki/page?id=2_5_0:release:change_log
|
||||
[55]: https://www.itophub.io/wiki/page?id=2_5_0:release:2_5_whats_new
|
||||
[56]: https://www.itophub.io/wiki/page?id=2_5_0:install:240_to_250_migration_notes
|
||||
[57]: https://sourceforge.net/projects/itop/files/itop/2.5.1
|
||||
|
||||
[58]: https://www.itophub.io/wiki/page?id=2_6_0:release:change_log
|
||||
[59]: https://www.itophub.io/wiki/page?id=2_6_0:release:2_6_whats_new
|
||||
[60]: https://www.itophub.io/wiki/page?id=2_6_0:install:250_to_260_migration_notes
|
||||
[61]: https://sourceforge.net/projects/itop/files/itop/2.6.3
|
||||
@@ -1,368 +1,368 @@
|
||||
<?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/>
|
||||
|
||||
/**
|
||||
* UserRightsMatrix (User management Module)
|
||||
*
|
||||
* @copyright Copyright (C) 2010-2012 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
|
||||
class UserRightsMatrixClassGrant extends DBObject
|
||||
{
|
||||
public static function Init()
|
||||
{
|
||||
$aParams = array
|
||||
(
|
||||
"category" => "addon/userrights",
|
||||
"key_type" => "autoincrement",
|
||||
"name_attcode" => "",
|
||||
"state_attcode" => "",
|
||||
"reconc_keys" => array(),
|
||||
"db_table" => "priv_ur_matrixclasses",
|
||||
"db_key_field" => "id",
|
||||
"db_finalclass_field" => "",
|
||||
);
|
||||
MetaModel::Init_Params($aParams);
|
||||
//MetaModel::Init_InheritAttributes();
|
||||
MetaModel::Init_AddAttribute(new AttributeExternalKey("userid", array("targetclass"=>"User", "jointype"=> "", "allowed_values"=>null, "sql"=>"userid", "is_null_allowed"=>false, "on_target_delete"=>DEL_MANUAL, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeExternalField("login", array("allowed_values"=>null, "extkey_attcode"=> 'userid', "target_attcode"=>"login")));
|
||||
MetaModel::Init_AddAttribute(new AttributeString("class", array("allowed_values"=>null, "sql"=>"class", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array())));
|
||||
|
||||
MetaModel::Init_AddAttribute(new AttributeString("action", array("allowed_values"=>null, "sql"=>"action", "default_value"=>"", "is_null_allowed"=>false, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeEnum("permission", array("allowed_values"=>new ValueSetEnum('yes,no'), "sql"=>"permission", "default_value"=>"yes", "is_null_allowed"=>false, "depends_on"=>array())));
|
||||
}
|
||||
}
|
||||
|
||||
class UserRightsMatrixClassStimulusGrant extends DBObject
|
||||
{
|
||||
public static function Init()
|
||||
{
|
||||
$aParams = array
|
||||
(
|
||||
"category" => "addon/userrights",
|
||||
"key_type" => "autoincrement",
|
||||
"name_attcode" => "",
|
||||
"state_attcode" => "",
|
||||
"reconc_keys" => array(),
|
||||
"db_table" => "priv_ur_matrixclassesstimulus",
|
||||
"db_key_field" => "id",
|
||||
"db_finalclass_field" => "",
|
||||
);
|
||||
MetaModel::Init_Params($aParams);
|
||||
//MetaModel::Init_InheritAttributes();
|
||||
MetaModel::Init_AddAttribute(new AttributeExternalKey("userid", array("targetclass"=>"User", "jointype"=> "", "allowed_values"=>null, "sql"=>"userid", "is_null_allowed"=>false, "on_target_delete"=>DEL_MANUAL, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeExternalField("login", array("allowed_values"=>null, "extkey_attcode"=> 'userid', "target_attcode"=>"login")));
|
||||
MetaModel::Init_AddAttribute(new AttributeString("class", array("allowed_values"=>null, "sql"=>"class", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array())));
|
||||
|
||||
MetaModel::Init_AddAttribute(new AttributeString("stimulus", array("allowed_values"=>null, "sql"=>"action", "default_value"=>"", "is_null_allowed"=>false, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeEnum("permission", array("allowed_values"=>new ValueSetEnum('yes,no'), "sql"=>"permission", "default_value"=>"yes", "is_null_allowed"=>false, "depends_on"=>array())));
|
||||
}
|
||||
}
|
||||
|
||||
class UserRightsMatrixAttributeGrant extends DBObject
|
||||
{
|
||||
public static function Init()
|
||||
{
|
||||
$aParams = array
|
||||
(
|
||||
"category" => "addon/userrights",
|
||||
"key_type" => "autoincrement",
|
||||
"name_attcode" => "",
|
||||
"state_attcode" => "",
|
||||
"reconc_keys" => array(),
|
||||
"db_table" => "priv_ur_matrixattributes",
|
||||
"db_key_field" => "id",
|
||||
"db_finalclass_field" => "",
|
||||
);
|
||||
MetaModel::Init_Params($aParams);
|
||||
//MetaModel::Init_InheritAttributes();
|
||||
MetaModel::Init_AddAttribute(new AttributeExternalKey("userid", array("targetclass"=>"User", "jointype"=> "", "allowed_values"=>null, "sql"=>"userid", "is_null_allowed"=>false, "on_target_delete"=>DEL_MANUAL, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeExternalField("login", array("allowed_values"=>null, "extkey_attcode"=> 'userid', "target_attcode"=>"login")));
|
||||
MetaModel::Init_AddAttribute(new AttributeString("class", array("allowed_values"=>null, "sql"=>"class", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeString("attcode", array("allowed_values"=>null, "sql"=>"attcode", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array())));
|
||||
|
||||
MetaModel::Init_AddAttribute(new AttributeString("action", array("allowed_values"=>null, "sql"=>"action", "default_value"=>"", "is_null_allowed"=>false, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeEnum("permission", array("allowed_values"=>new ValueSetEnum('yes,no'), "sql"=>"permission", "default_value"=>"yes", "is_null_allowed"=>false, "depends_on"=>array())));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
class UserRightsMatrix extends UserRightsAddOnAPI
|
||||
{
|
||||
static public $m_aActionCodes = array(
|
||||
UR_ACTION_READ => 'read',
|
||||
UR_ACTION_MODIFY => 'modify',
|
||||
UR_ACTION_DELETE => 'delete',
|
||||
UR_ACTION_BULK_READ => 'bulk read',
|
||||
UR_ACTION_BULK_MODIFY => 'bulk modify',
|
||||
UR_ACTION_BULK_DELETE => 'bulk delete',
|
||||
);
|
||||
|
||||
// Installation: create the very first user
|
||||
public function CreateAdministrator($sAdminUser, $sAdminPwd, $sLanguage = 'EN US')
|
||||
{
|
||||
// Maybe we should check that no other user with userid == 0 exists
|
||||
$oUser = new UserLocal();
|
||||
$oUser->Set('login', $sAdminUser);
|
||||
$oUser->Set('password', $sAdminPwd);
|
||||
$oUser->Set('contactid', 1); // one is for root !
|
||||
$oUser->Set('language', $sLanguage); // Language was chosen during the installation
|
||||
|
||||
// Create a change to record the history of the User object
|
||||
$oChange = MetaModel::NewObject("CMDBChange");
|
||||
$oChange->Set("date", time());
|
||||
$oChange->Set("userinfo", "Initialization");
|
||||
$iChangeId = $oChange->DBInsert();
|
||||
|
||||
// Now record the admin user object
|
||||
$iUserId = $oUser->DBInsertTrackedNoReload($oChange, true /* skip security */);
|
||||
$this->SetupUser($iUserId, true);
|
||||
return true;
|
||||
}
|
||||
|
||||
public function IsAdministrator($oUser)
|
||||
{
|
||||
return ($oUser->GetKey() == 1);
|
||||
}
|
||||
|
||||
public function IsPortalUser($oUser)
|
||||
{
|
||||
return ($oUser->GetKey() == 1);
|
||||
}
|
||||
|
||||
// Deprecated - create a new module !
|
||||
public function Setup()
|
||||
{
|
||||
// Users must be added manually
|
||||
// This procedure will then update the matrix when a new user is found or a new class/attribute appears
|
||||
$oUserSet = new DBObjectSet(DBObjectSearch::FromOQL("SELECT User"));
|
||||
while ($oUser = $oUserSet->Fetch())
|
||||
{
|
||||
$this->SetupUser($oUser->GetKey());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
protected function SetupUser($iUserId, $bNewUser = false)
|
||||
{
|
||||
foreach(array('bizmodel', 'application', 'gui', 'core/cmdb') as $sCategory)
|
||||
{
|
||||
foreach (MetaModel::GetClasses($sCategory) as $sClass)
|
||||
{
|
||||
foreach (self::$m_aActionCodes as $iActionCode => $sAction)
|
||||
{
|
||||
if ($bNewUser)
|
||||
{
|
||||
$bAddCell = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
$oSet = new DBObjectSet(DBObjectSearch::FromOQL("SELECT UserRightsMatrixClassGrant WHERE class = '$sClass' AND action = '$sAction' AND userid = $iUserId"));
|
||||
$bAddCell = ($oSet->Count() < 1);
|
||||
}
|
||||
if ($bAddCell)
|
||||
{
|
||||
// Create a new entry
|
||||
$oMyClassGrant = MetaModel::NewObject("UserRightsMatrixClassGrant");
|
||||
$oMyClassGrant->Set("userid", $iUserId);
|
||||
$oMyClassGrant->Set("class", $sClass);
|
||||
$oMyClassGrant->Set("action", $sAction);
|
||||
$oMyClassGrant->Set("permission", "yes");
|
||||
$iId = $oMyClassGrant->DBInsertNoReload();
|
||||
}
|
||||
}
|
||||
foreach (MetaModel::EnumStimuli($sClass) as $sStimulusCode => $oStimulus)
|
||||
{
|
||||
if ($bNewUser)
|
||||
{
|
||||
$bAddCell = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
$oSet = new DBObjectSet(DBObjectSearch::FromOQL("SELECT UserRightsMatrixClassStimulusGrant WHERE class = '$sClass' AND stimulus = '$sStimulusCode' AND userid = $iUserId"));
|
||||
$bAddCell = ($oSet->Count() < 1);
|
||||
}
|
||||
if ($bAddCell)
|
||||
{
|
||||
// Create a new entry
|
||||
$oMyClassGrant = MetaModel::NewObject("UserRightsMatrixClassStimulusGrant");
|
||||
$oMyClassGrant->Set("userid", $iUserId);
|
||||
$oMyClassGrant->Set("class", $sClass);
|
||||
$oMyClassGrant->Set("stimulus", $sStimulusCode);
|
||||
$oMyClassGrant->Set("permission", "yes");
|
||||
$iId = $oMyClassGrant->DBInsertNoReload();
|
||||
}
|
||||
}
|
||||
foreach (MetaModel::GetAttributesList($sClass) as $sAttCode)
|
||||
{
|
||||
if ($bNewUser)
|
||||
{
|
||||
$bAddCell = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
$oSet = new DBObjectSet(DBObjectSearch::FromOQL("SELECT UserRightsMatrixAttributeGrant WHERE class = '$sClass' AND attcode = '$sAttCode' AND userid = $iUserId"));
|
||||
$bAddCell = ($oSet->Count() < 1);
|
||||
}
|
||||
if ($bAddCell)
|
||||
{
|
||||
foreach (array('read', 'modify') as $sAction)
|
||||
{
|
||||
// Create a new entry
|
||||
$oMyAttGrant = MetaModel::NewObject("UserRightsMatrixAttributeGrant");
|
||||
$oMyAttGrant->Set("userid", $iUserId);
|
||||
$oMyAttGrant->Set("class", $sClass);
|
||||
$oMyAttGrant->Set("attcode", $sAttCode);
|
||||
$oMyAttGrant->Set("action", $sAction);
|
||||
$oMyAttGrant->Set("permission", "yes");
|
||||
$iId = $oMyAttGrant->DBInsertNoReload();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/*
|
||||
// Create the "My Bookmarks" menu item (parent_id = 0, rank = 6)
|
||||
if ($bNewUser)
|
||||
{
|
||||
$bAddMenu = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
$oSet = new DBObjectSet(DBObjectSearch::FromOQL("SELECT menuNode WHERE type = 'user' AND parent_id = 0 AND user_id = $iUserId"));
|
||||
$bAddMenu = ($oSet->Count() < 1);
|
||||
}
|
||||
if ($bAddMenu)
|
||||
{
|
||||
$oMenu = MetaModel::NewObject('menuNode');
|
||||
$oMenu->Set('type', 'user');
|
||||
$oMenu->Set('parent_id', 0); // It's a toplevel entry
|
||||
$oMenu->Set('rank', 6); // Located just above the Admin Tools section (=7)
|
||||
$oMenu->Set('name', 'My Bookmarks');
|
||||
$oMenu->Set('label', 'My Favorite Items');
|
||||
$oMenu->Set('hyperlink', 'UI.php');
|
||||
$oMenu->Set('template', '<p></p><p></p><p style="text-align:center; font-family:Georgia, Times, serif; font-size:32px;">My bookmarks</p><p style="text-align:center; font-family:Georgia, Times, serif; font-size:14px;"><i>This section contains my most favorite search results</i></p>');
|
||||
$oMenu->Set('user_id', $iUserId);
|
||||
$oMenu->DBInsert();
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
|
||||
public function Init()
|
||||
{
|
||||
// Could be loaded in a shared memory (?)
|
||||
return true;
|
||||
}
|
||||
|
||||
public function GetSelectFilter($oUser, $sClass, $aSettings = array())
|
||||
{
|
||||
$oNullFilter = new DBObjectSearch($sClass);
|
||||
return $oNullFilter;
|
||||
}
|
||||
|
||||
public function IsActionAllowed($oUser, $sClass, $iActionCode, $oInstanceSet = null)
|
||||
{
|
||||
if (!array_key_exists($iActionCode, self::$m_aActionCodes))
|
||||
{
|
||||
return UR_ALLOWED_NO;
|
||||
}
|
||||
$sAction = self::$m_aActionCodes[$iActionCode];
|
||||
|
||||
$oSet = new DBObjectSet(DBObjectSearch::FromOQL("SELECT UserRightsMatrixClassGrant WHERE class = '$sClass' AND action = '$sAction' AND userid = '{$oUser->GetKey()}'"));
|
||||
if ($oSet->Count() < 1)
|
||||
{
|
||||
return UR_ALLOWED_NO;
|
||||
}
|
||||
|
||||
$oGrantRecord = $oSet->Fetch();
|
||||
switch ($oGrantRecord->Get('permission'))
|
||||
{
|
||||
case 'yes':
|
||||
$iRetCode = UR_ALLOWED_YES;
|
||||
break;
|
||||
case 'no':
|
||||
default:
|
||||
$iRetCode = UR_ALLOWED_NO;
|
||||
break;
|
||||
}
|
||||
return $iRetCode;
|
||||
}
|
||||
|
||||
public function IsActionAllowedOnAttribute($oUser, $sClass, $sAttCode, $iActionCode, $oInstanceSet = null)
|
||||
{
|
||||
if (!array_key_exists($iActionCode, self::$m_aActionCodes))
|
||||
{
|
||||
return UR_ALLOWED_NO;
|
||||
}
|
||||
$sAction = self::$m_aActionCodes[$iActionCode];
|
||||
|
||||
$oSet = new DBObjectSet(DBObjectSearch::FromOQL("SELECT UserRightsMatrixAttributeGrant WHERE class = '$sClass' AND attcode = '$sAttCode' AND action = '$sAction' AND userid = '{$oUser->GetKey()}'"));
|
||||
if ($oSet->Count() < 1)
|
||||
{
|
||||
return UR_ALLOWED_NO;
|
||||
}
|
||||
|
||||
$oGrantRecord = $oSet->Fetch();
|
||||
switch ($oGrantRecord->Get('permission'))
|
||||
{
|
||||
case 'yes':
|
||||
$iRetCode = UR_ALLOWED_YES;
|
||||
break;
|
||||
case 'no':
|
||||
default:
|
||||
$iRetCode = UR_ALLOWED_NO;
|
||||
break;
|
||||
}
|
||||
return $iRetCode;
|
||||
}
|
||||
|
||||
public function IsStimulusAllowed($oUser, $sClass, $sStimulusCode, $oInstanceSet = null)
|
||||
{
|
||||
$oSet = new DBObjectSet(DBObjectSearch::FromOQL("SELECT UserRightsMatrixClassStimulusGrant WHERE class = '$sClass' AND stimulus = '$sStimulusCode' AND userid = '{$oUser->GetKey()}'"));
|
||||
if ($oSet->Count() < 1)
|
||||
{
|
||||
return UR_ALLOWED_NO;
|
||||
}
|
||||
|
||||
$oGrantRecord = $oSet->Fetch();
|
||||
switch ($oGrantRecord->Get('permission'))
|
||||
{
|
||||
case 'yes':
|
||||
$iRetCode = UR_ALLOWED_YES;
|
||||
break;
|
||||
case 'no':
|
||||
default:
|
||||
$iRetCode = UR_ALLOWED_NO;
|
||||
break;
|
||||
}
|
||||
return $iRetCode;
|
||||
}
|
||||
|
||||
public function FlushPrivileges()
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
UserRights::SelectModule('UserRightsMatrix');
|
||||
|
||||
?>
|
||||
<?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/>
|
||||
|
||||
/**
|
||||
* UserRightsMatrix (User management Module)
|
||||
*
|
||||
* @copyright Copyright (C) 2010-2012 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
|
||||
class UserRightsMatrixClassGrant extends DBObject
|
||||
{
|
||||
public static function Init()
|
||||
{
|
||||
$aParams = array
|
||||
(
|
||||
"category" => "addon/userrights",
|
||||
"key_type" => "autoincrement",
|
||||
"name_attcode" => "",
|
||||
"state_attcode" => "",
|
||||
"reconc_keys" => array(),
|
||||
"db_table" => "priv_ur_matrixclasses",
|
||||
"db_key_field" => "id",
|
||||
"db_finalclass_field" => "",
|
||||
);
|
||||
MetaModel::Init_Params($aParams);
|
||||
//MetaModel::Init_InheritAttributes();
|
||||
MetaModel::Init_AddAttribute(new AttributeExternalKey("userid", array("targetclass"=>"User", "jointype"=> "", "allowed_values"=>null, "sql"=>"userid", "is_null_allowed"=>false, "on_target_delete"=>DEL_MANUAL, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeExternalField("login", array("allowed_values"=>null, "extkey_attcode"=> 'userid', "target_attcode"=>"login")));
|
||||
MetaModel::Init_AddAttribute(new AttributeString("class", array("allowed_values"=>null, "sql"=>"class", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array())));
|
||||
|
||||
MetaModel::Init_AddAttribute(new AttributeString("action", array("allowed_values"=>null, "sql"=>"action", "default_value"=>"", "is_null_allowed"=>false, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeEnum("permission", array("allowed_values"=>new ValueSetEnum('yes,no'), "sql"=>"permission", "default_value"=>"yes", "is_null_allowed"=>false, "depends_on"=>array())));
|
||||
}
|
||||
}
|
||||
|
||||
class UserRightsMatrixClassStimulusGrant extends DBObject
|
||||
{
|
||||
public static function Init()
|
||||
{
|
||||
$aParams = array
|
||||
(
|
||||
"category" => "addon/userrights",
|
||||
"key_type" => "autoincrement",
|
||||
"name_attcode" => "",
|
||||
"state_attcode" => "",
|
||||
"reconc_keys" => array(),
|
||||
"db_table" => "priv_ur_matrixclassesstimulus",
|
||||
"db_key_field" => "id",
|
||||
"db_finalclass_field" => "",
|
||||
);
|
||||
MetaModel::Init_Params($aParams);
|
||||
//MetaModel::Init_InheritAttributes();
|
||||
MetaModel::Init_AddAttribute(new AttributeExternalKey("userid", array("targetclass"=>"User", "jointype"=> "", "allowed_values"=>null, "sql"=>"userid", "is_null_allowed"=>false, "on_target_delete"=>DEL_MANUAL, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeExternalField("login", array("allowed_values"=>null, "extkey_attcode"=> 'userid', "target_attcode"=>"login")));
|
||||
MetaModel::Init_AddAttribute(new AttributeString("class", array("allowed_values"=>null, "sql"=>"class", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array())));
|
||||
|
||||
MetaModel::Init_AddAttribute(new AttributeString("stimulus", array("allowed_values"=>null, "sql"=>"action", "default_value"=>"", "is_null_allowed"=>false, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeEnum("permission", array("allowed_values"=>new ValueSetEnum('yes,no'), "sql"=>"permission", "default_value"=>"yes", "is_null_allowed"=>false, "depends_on"=>array())));
|
||||
}
|
||||
}
|
||||
|
||||
class UserRightsMatrixAttributeGrant extends DBObject
|
||||
{
|
||||
public static function Init()
|
||||
{
|
||||
$aParams = array
|
||||
(
|
||||
"category" => "addon/userrights",
|
||||
"key_type" => "autoincrement",
|
||||
"name_attcode" => "",
|
||||
"state_attcode" => "",
|
||||
"reconc_keys" => array(),
|
||||
"db_table" => "priv_ur_matrixattributes",
|
||||
"db_key_field" => "id",
|
||||
"db_finalclass_field" => "",
|
||||
);
|
||||
MetaModel::Init_Params($aParams);
|
||||
//MetaModel::Init_InheritAttributes();
|
||||
MetaModel::Init_AddAttribute(new AttributeExternalKey("userid", array("targetclass"=>"User", "jointype"=> "", "allowed_values"=>null, "sql"=>"userid", "is_null_allowed"=>false, "on_target_delete"=>DEL_MANUAL, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeExternalField("login", array("allowed_values"=>null, "extkey_attcode"=> 'userid', "target_attcode"=>"login")));
|
||||
MetaModel::Init_AddAttribute(new AttributeString("class", array("allowed_values"=>null, "sql"=>"class", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeString("attcode", array("allowed_values"=>null, "sql"=>"attcode", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array())));
|
||||
|
||||
MetaModel::Init_AddAttribute(new AttributeString("action", array("allowed_values"=>null, "sql"=>"action", "default_value"=>"", "is_null_allowed"=>false, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeEnum("permission", array("allowed_values"=>new ValueSetEnum('yes,no'), "sql"=>"permission", "default_value"=>"yes", "is_null_allowed"=>false, "depends_on"=>array())));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
class UserRightsMatrix extends UserRightsAddOnAPI
|
||||
{
|
||||
static public $m_aActionCodes = array(
|
||||
UR_ACTION_READ => 'read',
|
||||
UR_ACTION_MODIFY => 'modify',
|
||||
UR_ACTION_DELETE => 'delete',
|
||||
UR_ACTION_BULK_READ => 'bulk read',
|
||||
UR_ACTION_BULK_MODIFY => 'bulk modify',
|
||||
UR_ACTION_BULK_DELETE => 'bulk delete',
|
||||
);
|
||||
|
||||
// Installation: create the very first user
|
||||
public function CreateAdministrator($sAdminUser, $sAdminPwd, $sLanguage = 'EN US')
|
||||
{
|
||||
// Maybe we should check that no other user with userid == 0 exists
|
||||
$oUser = new UserLocal();
|
||||
$oUser->Set('login', $sAdminUser);
|
||||
$oUser->Set('password', $sAdminPwd);
|
||||
$oUser->Set('contactid', 1); // one is for root !
|
||||
$oUser->Set('language', $sLanguage); // Language was chosen during the installation
|
||||
|
||||
// Create a change to record the history of the User object
|
||||
$oChange = MetaModel::NewObject("CMDBChange");
|
||||
$oChange->Set("date", time());
|
||||
$oChange->Set("userinfo", "Initialization");
|
||||
$iChangeId = $oChange->DBInsert();
|
||||
|
||||
// Now record the admin user object
|
||||
$iUserId = $oUser->DBInsertTrackedNoReload($oChange, true /* skip security */);
|
||||
$this->SetupUser($iUserId, true);
|
||||
return true;
|
||||
}
|
||||
|
||||
public function IsAdministrator($oUser)
|
||||
{
|
||||
return ($oUser->GetKey() == 1);
|
||||
}
|
||||
|
||||
public function IsPortalUser($oUser)
|
||||
{
|
||||
return ($oUser->GetKey() == 1);
|
||||
}
|
||||
|
||||
// Deprecated - create a new module !
|
||||
public function Setup()
|
||||
{
|
||||
// Users must be added manually
|
||||
// This procedure will then update the matrix when a new user is found or a new class/attribute appears
|
||||
$oUserSet = new DBObjectSet(DBObjectSearch::FromOQL("SELECT User"));
|
||||
while ($oUser = $oUserSet->Fetch())
|
||||
{
|
||||
$this->SetupUser($oUser->GetKey());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
protected function SetupUser($iUserId, $bNewUser = false)
|
||||
{
|
||||
foreach(array('bizmodel', 'application', 'gui', 'core/cmdb') as $sCategory)
|
||||
{
|
||||
foreach (MetaModel::GetClasses($sCategory) as $sClass)
|
||||
{
|
||||
foreach (self::$m_aActionCodes as $iActionCode => $sAction)
|
||||
{
|
||||
if ($bNewUser)
|
||||
{
|
||||
$bAddCell = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
$oSet = new DBObjectSet(DBObjectSearch::FromOQL("SELECT UserRightsMatrixClassGrant WHERE class = '$sClass' AND action = '$sAction' AND userid = $iUserId"));
|
||||
$bAddCell = ($oSet->Count() < 1);
|
||||
}
|
||||
if ($bAddCell)
|
||||
{
|
||||
// Create a new entry
|
||||
$oMyClassGrant = MetaModel::NewObject("UserRightsMatrixClassGrant");
|
||||
$oMyClassGrant->Set("userid", $iUserId);
|
||||
$oMyClassGrant->Set("class", $sClass);
|
||||
$oMyClassGrant->Set("action", $sAction);
|
||||
$oMyClassGrant->Set("permission", "yes");
|
||||
$iId = $oMyClassGrant->DBInsertNoReload();
|
||||
}
|
||||
}
|
||||
foreach (MetaModel::EnumStimuli($sClass) as $sStimulusCode => $oStimulus)
|
||||
{
|
||||
if ($bNewUser)
|
||||
{
|
||||
$bAddCell = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
$oSet = new DBObjectSet(DBObjectSearch::FromOQL("SELECT UserRightsMatrixClassStimulusGrant WHERE class = '$sClass' AND stimulus = '$sStimulusCode' AND userid = $iUserId"));
|
||||
$bAddCell = ($oSet->Count() < 1);
|
||||
}
|
||||
if ($bAddCell)
|
||||
{
|
||||
// Create a new entry
|
||||
$oMyClassGrant = MetaModel::NewObject("UserRightsMatrixClassStimulusGrant");
|
||||
$oMyClassGrant->Set("userid", $iUserId);
|
||||
$oMyClassGrant->Set("class", $sClass);
|
||||
$oMyClassGrant->Set("stimulus", $sStimulusCode);
|
||||
$oMyClassGrant->Set("permission", "yes");
|
||||
$iId = $oMyClassGrant->DBInsertNoReload();
|
||||
}
|
||||
}
|
||||
foreach (MetaModel::GetAttributesList($sClass) as $sAttCode)
|
||||
{
|
||||
if ($bNewUser)
|
||||
{
|
||||
$bAddCell = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
$oSet = new DBObjectSet(DBObjectSearch::FromOQL("SELECT UserRightsMatrixAttributeGrant WHERE class = '$sClass' AND attcode = '$sAttCode' AND userid = $iUserId"));
|
||||
$bAddCell = ($oSet->Count() < 1);
|
||||
}
|
||||
if ($bAddCell)
|
||||
{
|
||||
foreach (array('read', 'modify') as $sAction)
|
||||
{
|
||||
// Create a new entry
|
||||
$oMyAttGrant = MetaModel::NewObject("UserRightsMatrixAttributeGrant");
|
||||
$oMyAttGrant->Set("userid", $iUserId);
|
||||
$oMyAttGrant->Set("class", $sClass);
|
||||
$oMyAttGrant->Set("attcode", $sAttCode);
|
||||
$oMyAttGrant->Set("action", $sAction);
|
||||
$oMyAttGrant->Set("permission", "yes");
|
||||
$iId = $oMyAttGrant->DBInsertNoReload();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/*
|
||||
// Create the "My Bookmarks" menu item (parent_id = 0, rank = 6)
|
||||
if ($bNewUser)
|
||||
{
|
||||
$bAddMenu = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
$oSet = new DBObjectSet(DBObjectSearch::FromOQL("SELECT menuNode WHERE type = 'user' AND parent_id = 0 AND user_id = $iUserId"));
|
||||
$bAddMenu = ($oSet->Count() < 1);
|
||||
}
|
||||
if ($bAddMenu)
|
||||
{
|
||||
$oMenu = MetaModel::NewObject('menuNode');
|
||||
$oMenu->Set('type', 'user');
|
||||
$oMenu->Set('parent_id', 0); // It's a toplevel entry
|
||||
$oMenu->Set('rank', 6); // Located just above the Admin Tools section (=7)
|
||||
$oMenu->Set('name', 'My Bookmarks');
|
||||
$oMenu->Set('label', 'My Favorite Items');
|
||||
$oMenu->Set('hyperlink', 'UI.php');
|
||||
$oMenu->Set('template', '<p></p><p></p><p style="text-align:center; font-family:Georgia, Times, serif; font-size:32px;">My bookmarks</p><p style="text-align:center; font-family:Georgia, Times, serif; font-size:14px;"><i>This section contains my most favorite search results</i></p>');
|
||||
$oMenu->Set('user_id', $iUserId);
|
||||
$oMenu->DBInsert();
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
|
||||
public function Init()
|
||||
{
|
||||
// Could be loaded in a shared memory (?)
|
||||
return true;
|
||||
}
|
||||
|
||||
public function GetSelectFilter($oUser, $sClass, $aSettings = array())
|
||||
{
|
||||
$oNullFilter = new DBObjectSearch($sClass);
|
||||
return $oNullFilter;
|
||||
}
|
||||
|
||||
public function IsActionAllowed($oUser, $sClass, $iActionCode, $oInstanceSet = null)
|
||||
{
|
||||
if (!array_key_exists($iActionCode, self::$m_aActionCodes))
|
||||
{
|
||||
return UR_ALLOWED_NO;
|
||||
}
|
||||
$sAction = self::$m_aActionCodes[$iActionCode];
|
||||
|
||||
$oSet = new DBObjectSet(DBObjectSearch::FromOQL("SELECT UserRightsMatrixClassGrant WHERE class = '$sClass' AND action = '$sAction' AND userid = '{$oUser->GetKey()}'"));
|
||||
if ($oSet->Count() < 1)
|
||||
{
|
||||
return UR_ALLOWED_NO;
|
||||
}
|
||||
|
||||
$oGrantRecord = $oSet->Fetch();
|
||||
switch ($oGrantRecord->Get('permission'))
|
||||
{
|
||||
case 'yes':
|
||||
$iRetCode = UR_ALLOWED_YES;
|
||||
break;
|
||||
case 'no':
|
||||
default:
|
||||
$iRetCode = UR_ALLOWED_NO;
|
||||
break;
|
||||
}
|
||||
return $iRetCode;
|
||||
}
|
||||
|
||||
public function IsActionAllowedOnAttribute($oUser, $sClass, $sAttCode, $iActionCode, $oInstanceSet = null)
|
||||
{
|
||||
if (!array_key_exists($iActionCode, self::$m_aActionCodes))
|
||||
{
|
||||
return UR_ALLOWED_NO;
|
||||
}
|
||||
$sAction = self::$m_aActionCodes[$iActionCode];
|
||||
|
||||
$oSet = new DBObjectSet(DBObjectSearch::FromOQL("SELECT UserRightsMatrixAttributeGrant WHERE class = '$sClass' AND attcode = '$sAttCode' AND action = '$sAction' AND userid = '{$oUser->GetKey()}'"));
|
||||
if ($oSet->Count() < 1)
|
||||
{
|
||||
return UR_ALLOWED_NO;
|
||||
}
|
||||
|
||||
$oGrantRecord = $oSet->Fetch();
|
||||
switch ($oGrantRecord->Get('permission'))
|
||||
{
|
||||
case 'yes':
|
||||
$iRetCode = UR_ALLOWED_YES;
|
||||
break;
|
||||
case 'no':
|
||||
default:
|
||||
$iRetCode = UR_ALLOWED_NO;
|
||||
break;
|
||||
}
|
||||
return $iRetCode;
|
||||
}
|
||||
|
||||
public function IsStimulusAllowed($oUser, $sClass, $sStimulusCode, $oInstanceSet = null)
|
||||
{
|
||||
$oSet = new DBObjectSet(DBObjectSearch::FromOQL("SELECT UserRightsMatrixClassStimulusGrant WHERE class = '$sClass' AND stimulus = '$sStimulusCode' AND userid = '{$oUser->GetKey()}'"));
|
||||
if ($oSet->Count() < 1)
|
||||
{
|
||||
return UR_ALLOWED_NO;
|
||||
}
|
||||
|
||||
$oGrantRecord = $oSet->Fetch();
|
||||
switch ($oGrantRecord->Get('permission'))
|
||||
{
|
||||
case 'yes':
|
||||
$iRetCode = UR_ALLOWED_YES;
|
||||
break;
|
||||
case 'no':
|
||||
default:
|
||||
$iRetCode = UR_ALLOWED_NO;
|
||||
break;
|
||||
}
|
||||
return $iRetCode;
|
||||
}
|
||||
|
||||
public function FlushPrivileges()
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
UserRights::SelectModule('UserRightsMatrix');
|
||||
|
||||
?>
|
||||
|
||||
@@ -1,78 +1,78 @@
|
||||
<?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/>
|
||||
|
||||
/**
|
||||
* UserRightsNull
|
||||
* User management Module - say Yeah! to everything
|
||||
*
|
||||
* @copyright Copyright (C) 2010-2012 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
class UserRightsNull extends UserRightsAddOnAPI
|
||||
{
|
||||
// Installation: create the very first user
|
||||
public function CreateAdministrator($sAdminUser, $sAdminPwd, $sLanguage = 'EN US')
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public function IsAdministrator($oUser)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public function IsPortalUser($oUser)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public function Init()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public function GetSelectFilter($oUser, $sClass, $aSettings = array())
|
||||
{
|
||||
$oNullFilter = new DBObjectSearch($sClass);
|
||||
return $oNullFilter;
|
||||
}
|
||||
|
||||
public function IsActionAllowed($oUser, $sClass, $iActionCode, $oInstanceSet = null)
|
||||
{
|
||||
return UR_ALLOWED_YES;
|
||||
}
|
||||
|
||||
public function IsStimulusAllowed($oUser, $sClass, $sStimulusCode, $oInstanceSet = null)
|
||||
{
|
||||
return UR_ALLOWED_YES;
|
||||
}
|
||||
|
||||
public function IsActionAllowedOnAttribute($oUser, $sClass, $sAttCode, $iActionCode, $oInstanceSet = null)
|
||||
{
|
||||
return UR_ALLOWED_YES;
|
||||
}
|
||||
|
||||
public function FlushPrivileges()
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
UserRights::SelectModule('UserRightsNull');
|
||||
|
||||
?>
|
||||
<?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/>
|
||||
|
||||
/**
|
||||
* UserRightsNull
|
||||
* User management Module - say Yeah! to everything
|
||||
*
|
||||
* @copyright Copyright (C) 2010-2012 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
class UserRightsNull extends UserRightsAddOnAPI
|
||||
{
|
||||
// Installation: create the very first user
|
||||
public function CreateAdministrator($sAdminUser, $sAdminPwd, $sLanguage = 'EN US')
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public function IsAdministrator($oUser)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public function IsPortalUser($oUser)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public function Init()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public function GetSelectFilter($oUser, $sClass, $aSettings = array())
|
||||
{
|
||||
$oNullFilter = new DBObjectSearch($sClass);
|
||||
return $oNullFilter;
|
||||
}
|
||||
|
||||
public function IsActionAllowed($oUser, $sClass, $iActionCode, $oInstanceSet = null)
|
||||
{
|
||||
return UR_ALLOWED_YES;
|
||||
}
|
||||
|
||||
public function IsStimulusAllowed($oUser, $sClass, $sStimulusCode, $oInstanceSet = null)
|
||||
{
|
||||
return UR_ALLOWED_YES;
|
||||
}
|
||||
|
||||
public function IsActionAllowedOnAttribute($oUser, $sClass, $sAttCode, $iActionCode, $oInstanceSet = null)
|
||||
{
|
||||
return UR_ALLOWED_YES;
|
||||
}
|
||||
|
||||
public function FlushPrivileges()
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
UserRights::SelectModule('UserRightsNull');
|
||||
|
||||
?>
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,382 +1,404 @@
|
||||
<?php
|
||||
// Copyright (C) 2010-2017 Combodo SARL
|
||||
//
|
||||
// This file is part of iTop.
|
||||
//
|
||||
// iTop is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// iTop is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with iTop. If not, see <http://www.gnu.org/licenses/>
|
||||
|
||||
/**
|
||||
* Simple web page with no includes, header or fancy formatting, useful to
|
||||
* generate HTML fragments when called by an AJAX method
|
||||
*
|
||||
* @copyright Copyright (C) 2010-2017 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
require_once(APPROOT."/application/webpage.class.inc.php");
|
||||
|
||||
class ajax_page extends WebPage implements iTabbedPage
|
||||
{
|
||||
/**
|
||||
* Jquery style ready script
|
||||
* @var Hash
|
||||
*/
|
||||
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");
|
||||
$this->m_oTabs = new TabManager();
|
||||
$this->sContentType = 'text/html';
|
||||
$this->sContentDisposition = 'inline';
|
||||
$this->m_sMenu = "";
|
||||
|
||||
utils::InitArchiveMode();
|
||||
}
|
||||
|
||||
public function AddTabContainer($sTabContainer, $sPrefix = '')
|
||||
{
|
||||
$this->add($this->m_oTabs->AddTabContainer($sTabContainer, $sPrefix));
|
||||
}
|
||||
|
||||
public function AddToTab($sTabContainer, $sTabLabel, $sHtml)
|
||||
{
|
||||
$this->add($this->m_oTabs->AddToTab($sTabContainer, $sTabLabel, $sHtml));
|
||||
}
|
||||
|
||||
public function SetCurrentTabContainer($sTabContainer = '')
|
||||
{
|
||||
return $this->m_oTabs->SetCurrentTabContainer($sTabContainer);
|
||||
}
|
||||
|
||||
public function SetCurrentTab($sTabLabel = '')
|
||||
{
|
||||
return $this->m_oTabs->SetCurrentTab($sTabLabel);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a tab which content will be loaded asynchronously via the supplied URL
|
||||
*
|
||||
* Limitations:
|
||||
* Cross site scripting is not not allowed for security reasons. Use a normal tab with an IFRAME if you want to pull content from another server.
|
||||
* Static content cannot be added inside such tabs.
|
||||
*
|
||||
* @param string $sTabLabel The (localised) label of the tab
|
||||
* @param string $sUrl The URL to load (on the same server)
|
||||
* @param boolean $bCache Whether or not to cache the content of the tab once it has been loaded. flase will cause the tab to be reloaded upon each activation.
|
||||
* @since 2.0.3
|
||||
*/
|
||||
public function AddAjaxTab($sTabLabel, $sUrl, $bCache = true)
|
||||
{
|
||||
$this->add($this->m_oTabs->AddAjaxTab($sTabLabel, $sUrl, $bCache));
|
||||
}
|
||||
|
||||
public function GetCurrentTab()
|
||||
{
|
||||
return $this->m_oTabs->GetCurrentTab();
|
||||
}
|
||||
|
||||
public function RemoveTab($sTabLabel, $sTabContainer = null)
|
||||
{
|
||||
$this->m_oTabs->RemoveTab($sTabLabel, $sTabContainer);
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds the tab whose title matches a given pattern
|
||||
* @return mixed The name of the tab as a string or false if not found
|
||||
*/
|
||||
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, $sTabLabel)
|
||||
{
|
||||
$this->add_ready_script($this->m_oTabs->SelectTab($sTabContainer, $sTabLabel));
|
||||
}
|
||||
|
||||
public function AddToMenu($sHtml)
|
||||
{
|
||||
$this->m_sMenu .= $sHtml;
|
||||
}
|
||||
|
||||
/**
|
||||
* Echoes the content of the whole page
|
||||
* @return void
|
||||
*/
|
||||
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
|
||||
);
|
||||
}
|
||||
$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 (!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 (trim($s_captured_output) != "")
|
||||
{
|
||||
echo self::FilterXSS($s_captured_output);
|
||||
}
|
||||
|
||||
if (class_exists('DBSearch'))
|
||||
{
|
||||
DBSearch::RecordQueryTrace();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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)
|
||||
{
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Records the current state of the 'html' part of the page output
|
||||
* @return mixed The current state of the 'html' output
|
||||
*/
|
||||
public function start_capture()
|
||||
{
|
||||
$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();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the part of the html output that occurred since the call to start_capture
|
||||
* and removes this part from the current html output
|
||||
* @param $offset mixed The value returned by start_capture
|
||||
* @return string The part of the html output that was added since the call to start_capture
|
||||
*/
|
||||
public function end_capture($offset)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add any text or HTML fragment (identified by an ID) at the end of the body of the page
|
||||
* This is useful to add hidden content, DIVs or FORMs that should not
|
||||
* be embedded into each other.
|
||||
*/
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a script to be executed when the DOM is ready (typical JQuery use)
|
||||
* NOT implemented in this version of the class.
|
||||
* @return void
|
||||
*/
|
||||
public function add_ready_script($sScript)
|
||||
{
|
||||
$this->m_sReadyScript .= $sScript."\n";
|
||||
}
|
||||
|
||||
/**
|
||||
* Cannot be called in this context, since Ajax pages do not share
|
||||
* any context with the calling page !!
|
||||
*/
|
||||
public function GetUniqueId()
|
||||
{
|
||||
assert(false);
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static function FilterXSS($sHTML)
|
||||
{
|
||||
return str_ireplace(array('<script', '</script>'), array('<!-- <removed-script', '</removed-script> -->'), $sHTML);
|
||||
}
|
||||
}
|
||||
|
||||
<?php
|
||||
// Copyright (C) 2010-2018 Combodo SARL
|
||||
//
|
||||
// This file is part of iTop.
|
||||
//
|
||||
// iTop is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// iTop is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with iTop. If not, see <http://www.gnu.org/licenses/>
|
||||
|
||||
/**
|
||||
* Simple web page with no includes, header or fancy formatting, useful to
|
||||
* generate HTML fragments when called by an AJAX method
|
||||
*
|
||||
* @copyright Copyright (C) 2010-2017 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
require_once(APPROOT."/application/webpage.class.inc.php");
|
||||
|
||||
class ajax_page extends WebPage implements iTabbedPage
|
||||
{
|
||||
/**
|
||||
* Jquery style ready script
|
||||
* @var Hash
|
||||
*/
|
||||
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();
|
||||
}
|
||||
|
||||
public function AddTabContainer($sTabContainer, $sPrefix = '')
|
||||
{
|
||||
$this->add($this->m_oTabs->AddTabContainer($sTabContainer, $sPrefix));
|
||||
}
|
||||
|
||||
public function AddToTab($sTabContainer, $sTabLabel, $sHtml)
|
||||
{
|
||||
$this->add($this->m_oTabs->AddToTab($sTabContainer, $sTabLabel, $sHtml));
|
||||
}
|
||||
|
||||
public function SetCurrentTabContainer($sTabContainer = '')
|
||||
{
|
||||
return $this->m_oTabs->SetCurrentTabContainer($sTabContainer);
|
||||
}
|
||||
|
||||
public function SetCurrentTab($sTabLabel = '')
|
||||
{
|
||||
return $this->m_oTabs->SetCurrentTab($sTabLabel);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a tab which content will be loaded asynchronously via the supplied URL
|
||||
*
|
||||
* Limitations:
|
||||
* Cross site scripting is not not allowed for security reasons. Use a normal tab with an IFRAME if you want to pull content from another server.
|
||||
* Static content cannot be added inside such tabs.
|
||||
*
|
||||
* @param string $sTabLabel The (localised) label of the tab
|
||||
* @param string $sUrl The URL to load (on the same server)
|
||||
* @param boolean $bCache Whether or not to cache the content of the tab once it has been loaded. flase will cause the tab to be reloaded upon each activation.
|
||||
* @since 2.0.3
|
||||
*/
|
||||
public function AddAjaxTab($sTabLabel, $sUrl, $bCache = true)
|
||||
{
|
||||
$this->add($this->m_oTabs->AddAjaxTab($sTabLabel, $sUrl, $bCache));
|
||||
}
|
||||
|
||||
public function GetCurrentTab()
|
||||
{
|
||||
return $this->m_oTabs->GetCurrentTab();
|
||||
}
|
||||
|
||||
public function RemoveTab($sTabLabel, $sTabContainer = null)
|
||||
{
|
||||
$this->m_oTabs->RemoveTab($sTabLabel, $sTabContainer);
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds the tab whose title matches a given pattern
|
||||
* @return mixed The name of the tab as a string or false if not found
|
||||
*/
|
||||
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, $sTabLabel)
|
||||
{
|
||||
$this->add_ready_script($this->m_oTabs->SelectTab($sTabContainer, $sTabLabel));
|
||||
}
|
||||
|
||||
public function AddToMenu($sHtml)
|
||||
{
|
||||
$this->m_sMenu .= $sHtml;
|
||||
}
|
||||
|
||||
/**
|
||||
* Echoes the content of the whole page
|
||||
* @return void
|
||||
*/
|
||||
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
|
||||
);
|
||||
}
|
||||
$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);
|
||||
}
|
||||
|
||||
if (class_exists('DBSearch'))
|
||||
{
|
||||
DBSearch::RecordQueryTrace();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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)
|
||||
{
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Records the current state of the 'html' part of the page output
|
||||
* @return mixed The current state of the 'html' output
|
||||
*/
|
||||
public function start_capture()
|
||||
{
|
||||
$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();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the part of the html output that occurred since the call to start_capture
|
||||
* and removes this part from the current html output
|
||||
* @param $offset mixed The value returned by start_capture
|
||||
* @return string The part of the html output that was added since the call to start_capture
|
||||
*/
|
||||
public function end_capture($offset)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add any text or HTML fragment (identified by an ID) at the end of the body of the page
|
||||
* This is useful to add hidden content, DIVs or FORMs that should not
|
||||
* be embedded into each other.
|
||||
*/
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a script to be executed when the DOM is ready (typical JQuery use)
|
||||
* NOT implemented in this version of the class.
|
||||
* @return void
|
||||
*/
|
||||
public function add_ready_script($sScript)
|
||||
{
|
||||
$this->m_sReadyScript .= $sScript."\n";
|
||||
}
|
||||
|
||||
/**
|
||||
* Cannot be called in this context, since Ajax pages do not share
|
||||
* any context with the calling page !!
|
||||
*/
|
||||
public function GetUniqueId()
|
||||
{
|
||||
assert(false);
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static function FilterXSS($sHTML)
|
||||
{
|
||||
return str_ireplace(array('<script', '</script>'), array('<!-- <removed-script', '</removed-script> -->'), $sHTML);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,40 +1,40 @@
|
||||
<?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/>
|
||||
|
||||
|
||||
/**
|
||||
* Includes all the classes to have the application up and running
|
||||
*
|
||||
* @copyright Copyright (C) 2010-2012 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
require_once(APPROOT.'/application/applicationcontext.class.inc.php');
|
||||
require_once(APPROOT.'/application/cmdbabstract.class.inc.php');
|
||||
require_once(APPROOT.'/application/displayblock.class.inc.php');
|
||||
require_once(APPROOT.'/application/audit.category.class.inc.php');
|
||||
require_once(APPROOT.'/application/audit.rule.class.inc.php');
|
||||
require_once(APPROOT.'/application/query.class.inc.php');
|
||||
require_once(APPROOT.'/setup/moduleinstallation.class.inc.php');
|
||||
//require_once(APPROOT.'/application/menunode.class.inc.php');
|
||||
require_once(APPROOT.'/application/utils.inc.php');
|
||||
|
||||
class ApplicationException extends CoreException
|
||||
{
|
||||
}
|
||||
?>
|
||||
<?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/>
|
||||
|
||||
|
||||
/**
|
||||
* Includes all the classes to have the application up and running
|
||||
*
|
||||
* @copyright Copyright (C) 2010-2012 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
require_once(APPROOT.'/application/applicationcontext.class.inc.php');
|
||||
require_once(APPROOT.'/application/cmdbabstract.class.inc.php');
|
||||
require_once(APPROOT.'/application/displayblock.class.inc.php');
|
||||
require_once(APPROOT.'/application/audit.category.class.inc.php');
|
||||
require_once(APPROOT.'/application/audit.rule.class.inc.php');
|
||||
require_once(APPROOT.'/application/query.class.inc.php');
|
||||
require_once(APPROOT.'/setup/moduleinstallation.class.inc.php');
|
||||
//require_once(APPROOT.'/application/menunode.class.inc.php');
|
||||
require_once(APPROOT.'/application/utils.inc.php');
|
||||
|
||||
class ApplicationException extends CoreException
|
||||
{
|
||||
}
|
||||
?>
|
||||
|
||||
@@ -1,362 +1,409 @@
|
||||
<?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 ApplicationContext
|
||||
*
|
||||
* @copyright Copyright (C) 2010-2012 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
require_once(APPROOT."/application/utils.inc.php");
|
||||
|
||||
/**
|
||||
* Interface for directing end-users to the relevant application
|
||||
*/
|
||||
interface iDBObjectURLMaker
|
||||
{
|
||||
public static function MakeObjectURL($sClass, $iId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Direct end-users to the standard iTop application: UI.php
|
||||
*/
|
||||
class iTopStandardURLMaker implements iDBObjectURLMaker
|
||||
{
|
||||
public static function MakeObjectURL($sClass, $iId)
|
||||
{
|
||||
$sPage = DBObject::ComputeStandardUIPage($sClass);
|
||||
$sAbsoluteUrl = utils::GetAbsoluteUrlAppRoot();
|
||||
$sUrl = "{$sAbsoluteUrl}pages/$sPage?operation=details&class=$sClass&id=$iId";
|
||||
return $sUrl;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Direct end-users to the standard Portal application
|
||||
*/
|
||||
class PortalURLMaker implements iDBObjectURLMaker
|
||||
{
|
||||
public static function MakeObjectURL($sClass, $iId)
|
||||
{
|
||||
$sAbsoluteUrl = utils::GetAbsoluteUrlAppRoot();
|
||||
$sUrl = "{$sAbsoluteUrl}portal/index.php?operation=details&class=$sClass&id=$iId";
|
||||
return $sUrl;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Helper class to store and manipulate the parameters that make the application's context
|
||||
*
|
||||
* Usage:
|
||||
* 1) Build the application's context by constructing the object
|
||||
* (the object will read some of the page's parameters)
|
||||
*
|
||||
* 2) Add these parameters to hyperlinks or to forms using the helper, functions
|
||||
* GetForLink(), GetForForm() or GetAsHash()
|
||||
*/
|
||||
class ApplicationContext
|
||||
{
|
||||
protected $aNames;
|
||||
protected $aValues;
|
||||
protected static $aDefaultValues; // Cache shared among all instances
|
||||
|
||||
public function __construct($bReadContext = true)
|
||||
{
|
||||
$this->aNames = array(
|
||||
'org_id', 'menu'
|
||||
);
|
||||
if ($bReadContext)
|
||||
{
|
||||
$this->ReadContext();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Read the context directly in the PHP parameters (either POST or GET)
|
||||
* return nothing
|
||||
*/
|
||||
protected function ReadContext()
|
||||
{
|
||||
if (!isset(self::$aDefaultValues))
|
||||
{
|
||||
self::$aDefaultValues = array();
|
||||
$aContext = utils::ReadParam('c', array(), false, 'context_param');
|
||||
foreach($this->aNames as $sName)
|
||||
{
|
||||
$sValue = isset($aContext[$sName]) ? $aContext[$sName] : '';
|
||||
// TO DO: check if some of the context parameters are mandatory (or have default values)
|
||||
if (!empty($sValue))
|
||||
{
|
||||
self::$aDefaultValues[$sName] = $sValue;
|
||||
}
|
||||
// Hmm, there must be a better (more generic) way to handle the case below:
|
||||
// When there is only one possible (allowed) organization, the context must be
|
||||
// fixed to this org
|
||||
if ($sName == 'org_id')
|
||||
{
|
||||
if (MetaModel::IsValidClass('Organization'))
|
||||
{
|
||||
$oSearchFilter = new DBObjectSearch('Organization');
|
||||
$oSearchFilter->SetModifierProperty('UserRightsGetSelectFilter', 'bSearchMode', true);
|
||||
$oSet = new CMDBObjectSet($oSearchFilter);
|
||||
$iCount = $oSet->Count();
|
||||
if ($iCount == 1)
|
||||
{
|
||||
// Only one possible value for org_id, set it in the context
|
||||
$oOrg = $oSet->Fetch();
|
||||
self::$aDefaultValues[$sName] = $oOrg->GetKey();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
$this->aValues = self::$aDefaultValues;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current value for the given parameter
|
||||
* @param string $sParamName Name of the parameter to read
|
||||
* @return mixed The value for this parameter
|
||||
*/
|
||||
public function GetCurrentValue($sParamName, $defaultValue = '')
|
||||
{
|
||||
if (isset($this->aValues[$sParamName]))
|
||||
{
|
||||
return $this->aValues[$sParamName];
|
||||
}
|
||||
return $defaultValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the context as string with the format name1=value1&name2=value2....
|
||||
* return string The context as a string to be appended to an href property
|
||||
*/
|
||||
public function GetForLink()
|
||||
{
|
||||
$aParams = array();
|
||||
foreach($this->aValues as $sName => $sValue)
|
||||
{
|
||||
$aParams[] = "c[$sName]".'='.urlencode($sValue);
|
||||
}
|
||||
return implode("&", $aParams);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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)
|
||||
{
|
||||
$sContext .= "<input type=\"hidden\" name=\"c[$sName]\" value=\"".htmlentities($sValue, ENT_QUOTES, 'UTF-8')."\" />\n";
|
||||
}
|
||||
return $sContext;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the context as a hash array 'parameter_name' => value
|
||||
* return array The context information
|
||||
*/
|
||||
public function GetAsHash()
|
||||
{
|
||||
$aReturn = array();
|
||||
foreach($this->aValues as $sName => $sValue)
|
||||
{
|
||||
$aReturn["c[$sName]"] = $sValue;
|
||||
}
|
||||
return $aReturn;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array of the context parameters NAMEs
|
||||
* @return array The list of context parameters
|
||||
*/
|
||||
public function GetNames()
|
||||
{
|
||||
return $this->aNames;
|
||||
}
|
||||
/**
|
||||
* Removes the specified parameter from the context, for example when the same parameter
|
||||
* is already a search parameter
|
||||
* @param string $sParamName Name of the parameter to remove
|
||||
* @return none
|
||||
*/
|
||||
public function Reset($sParamName)
|
||||
{
|
||||
if (isset($this->aValues[$sParamName]))
|
||||
{
|
||||
unset($this->aValues[$sParamName]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the given object with the default values provided by the context
|
||||
*/
|
||||
public function InitObjectFromContext(DBObject &$oObj)
|
||||
{
|
||||
$sClass = get_class($oObj);
|
||||
foreach($this->GetNames() as $key)
|
||||
{
|
||||
$aCallSpec = array($sClass, 'MapContextParam');
|
||||
if (is_callable($aCallSpec))
|
||||
{
|
||||
$sAttCode = call_user_func($aCallSpec, $key); // Returns null when there is no mapping for this parameter
|
||||
|
||||
if (MetaModel::IsValidAttCode($sClass, $sAttCode))
|
||||
{
|
||||
$oAttDef = MetaModel::GetAttributeDef($sClass, $sAttCode);
|
||||
if ($oAttDef->IsWritable())
|
||||
{
|
||||
$value = $this->GetCurrentValue($key, null);
|
||||
if (!is_null($value))
|
||||
{
|
||||
$oObj->Set($sAttCode, $value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static $m_sUrlMakerClass = null;
|
||||
|
||||
/**
|
||||
* Set the current application url provider
|
||||
* @param sClass string Class implementing iDBObjectURLMaker
|
||||
* @return void
|
||||
*/
|
||||
public static function SetUrlMakerClass($sClass = 'iTopStandardURLMaker')
|
||||
{
|
||||
$sPrevious = self::GetUrlMakerClass();
|
||||
|
||||
self::$m_sUrlMakerClass = $sClass;
|
||||
$_SESSION['UrlMakerClass'] = $sClass;
|
||||
|
||||
return $sPrevious;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current application url provider
|
||||
* @return string the name of the class
|
||||
*/
|
||||
public static function GetUrlMakerClass()
|
||||
{
|
||||
if (is_null(self::$m_sUrlMakerClass))
|
||||
{
|
||||
if (isset($_SESSION['UrlMakerClass']))
|
||||
{
|
||||
self::$m_sUrlMakerClass = $_SESSION['UrlMakerClass'];
|
||||
}
|
||||
else
|
||||
{
|
||||
self::$m_sUrlMakerClass = 'iTopStandardURLMaker';
|
||||
}
|
||||
}
|
||||
return self::$m_sUrlMakerClass;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current application url provider
|
||||
* @return string the name of the class
|
||||
*/
|
||||
public static function MakeObjectUrl($sObjClass, $sObjKey, $sUrlMakerClass = null, $bWithNavigationContext = true)
|
||||
{
|
||||
$oAppContext = new ApplicationContext();
|
||||
|
||||
if (is_null($sUrlMakerClass))
|
||||
{
|
||||
$sUrlMakerClass = self::GetUrlMakerClass();
|
||||
}
|
||||
$sUrl = call_user_func(array($sUrlMakerClass, 'MakeObjectUrl'), $sObjClass, $sObjKey);
|
||||
if (strlen($sUrl) > 0)
|
||||
{
|
||||
if ($bWithNavigationContext)
|
||||
{
|
||||
return $sUrl."&".$oAppContext->GetForLink();
|
||||
}
|
||||
else
|
||||
{
|
||||
return $sUrl;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
protected static $m_aPluginProperties = null;
|
||||
|
||||
/**
|
||||
* Load plugin properties for the current session
|
||||
* @return void
|
||||
*/
|
||||
protected static function LoadPluginProperties()
|
||||
{
|
||||
if (isset($_SESSION['PluginProperties']))
|
||||
{
|
||||
self::$m_aPluginProperties = $_SESSION['PluginProperties'];
|
||||
}
|
||||
else
|
||||
{
|
||||
self::$m_aPluginProperties = array();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set plugin properties
|
||||
* @param sPluginClass string Class implementing any plugin interface
|
||||
* @param sProperty string Name of the property
|
||||
* @param value scalar Value (numeric or string)
|
||||
* @return void
|
||||
*/
|
||||
public static function SetPluginProperty($sPluginClass, $sProperty, $value)
|
||||
{
|
||||
if (is_null(self::$m_aPluginProperties)) self::LoadPluginProperties();
|
||||
|
||||
self::$m_aPluginProperties[$sPluginClass][$sProperty] = $value;
|
||||
$_SESSION['PluginProperties'][$sPluginClass][$sProperty] = $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get plugin properties
|
||||
* @param sPluginClass string Class implementing any plugin interface
|
||||
* @return array of sProperty=>value pairs
|
||||
*/
|
||||
public static function GetPluginProperties($sPluginClass)
|
||||
{
|
||||
if (is_null(self::$m_aPluginProperties)) self::LoadPluginProperties();
|
||||
|
||||
if (array_key_exists($sPluginClass, self::$m_aPluginProperties))
|
||||
{
|
||||
return self::$m_aPluginProperties[$sPluginClass];
|
||||
}
|
||||
else
|
||||
{
|
||||
return array();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
?>
|
||||
<?php
|
||||
// Copyright (C) 2010-2018 Combodo SARL
|
||||
//
|
||||
// This file is part of iTop.
|
||||
//
|
||||
// iTop is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// iTop is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with iTop. If not, see <http://www.gnu.org/licenses/>
|
||||
|
||||
|
||||
/**
|
||||
* Class ApplicationContext
|
||||
*
|
||||
* @copyright Copyright (C) 2010-2018 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
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
|
||||
*/
|
||||
public static function MakeObjectURL($sClass, $iId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Direct end-users to the standard iTop application: UI.php
|
||||
*/
|
||||
class iTopStandardURLMaker implements iDBObjectURLMaker
|
||||
{
|
||||
/**
|
||||
* @param string $sClass
|
||||
* @param string $iId
|
||||
*
|
||||
* @return string
|
||||
* @throws \Exception
|
||||
*/
|
||||
public static function MakeObjectURL($sClass, $iId)
|
||||
{
|
||||
$sPage = DBObject::ComputeStandardUIPage($sClass);
|
||||
$sAbsoluteUrl = utils::GetAbsoluteUrlAppRoot();
|
||||
$sUrl = "{$sAbsoluteUrl}pages/$sPage?operation=details&class=$sClass&id=$iId";
|
||||
return $sUrl;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Direct end-users to the standard Portal application
|
||||
*/
|
||||
class PortalURLMaker implements iDBObjectURLMaker
|
||||
{
|
||||
/**
|
||||
* @param string $sClass
|
||||
* @param string $iId
|
||||
*
|
||||
* @return string
|
||||
* @throws \Exception
|
||||
*/
|
||||
public static function MakeObjectURL($sClass, $iId)
|
||||
{
|
||||
$sAbsoluteUrl = utils::GetAbsoluteUrlAppRoot();
|
||||
$sUrl = "{$sAbsoluteUrl}portal/index.php?operation=details&class=$sClass&id=$iId";
|
||||
return $sUrl;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Helper class to store and manipulate the parameters that make the application's context
|
||||
*
|
||||
* Usage:
|
||||
* 1) Build the application's context by constructing the object
|
||||
* (the object will read some of the page's parameters)
|
||||
*
|
||||
* 2) Add these parameters to hyperlinks or to forms using the helper, functions
|
||||
* GetForLink(), GetForForm() or GetAsHash()
|
||||
*/
|
||||
class ApplicationContext
|
||||
{
|
||||
public static $m_sUrlMakerClass = null;
|
||||
protected static $m_aPluginProperties = null;
|
||||
protected static $aDefaultValues; // Cache shared among all instances
|
||||
|
||||
protected $aNames;
|
||||
protected $aValues;
|
||||
|
||||
/**
|
||||
* ApplicationContext constructor.
|
||||
*
|
||||
* @param bool $bReadContext
|
||||
*
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function __construct($bReadContext = true)
|
||||
{
|
||||
$this->aNames = array(
|
||||
'org_id', 'menu'
|
||||
);
|
||||
if ($bReadContext)
|
||||
{
|
||||
$this->ReadContext();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Read the context directly in the PHP parameters (either POST or GET)
|
||||
* return nothing
|
||||
*
|
||||
* @throws \Exception
|
||||
*/
|
||||
protected function ReadContext()
|
||||
{
|
||||
if (!isset(self::$aDefaultValues))
|
||||
{
|
||||
self::$aDefaultValues = array();
|
||||
$aContext = utils::ReadParam('c', array(), false, 'context_param');
|
||||
foreach($this->aNames as $sName)
|
||||
{
|
||||
$sValue = isset($aContext[$sName]) ? $aContext[$sName] : '';
|
||||
// TO DO: check if some of the context parameters are mandatory (or have default values)
|
||||
if (!empty($sValue))
|
||||
{
|
||||
self::$aDefaultValues[$sName] = $sValue;
|
||||
}
|
||||
// Hmm, there must be a better (more generic) way to handle the case below:
|
||||
// When there is only one possible (allowed) organization, the context must be
|
||||
// fixed to this org unless there is only one organization in the system then
|
||||
// no filter is applied
|
||||
if ($sName == 'org_id')
|
||||
{
|
||||
if (MetaModel::IsValidClass('Organization'))
|
||||
{
|
||||
$oSearchFilter = new DBObjectSearch('Organization');
|
||||
$oSet = new CMDBObjectSet($oSearchFilter);
|
||||
$iCount = $oSet->CountWithLimit(2);
|
||||
if ($iCount > 1)
|
||||
{
|
||||
$oSearchFilter->SetModifierProperty('UserRightsGetSelectFilter', 'bSearchMode', true);
|
||||
$oSet = new CMDBObjectSet($oSearchFilter);
|
||||
$iCount = $oSet->CountWithLimit(2);
|
||||
if ($iCount == 1)
|
||||
{
|
||||
// Only one possible value for org_id, set it in the context
|
||||
$oOrg = $oSet->Fetch();
|
||||
self::$aDefaultValues[$sName] = $oOrg->GetKey();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
$this->aValues = self::$aDefaultValues;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current value for the given parameter
|
||||
*
|
||||
* @param string $sParamName Name of the parameter to read
|
||||
* @param string $defaultValue
|
||||
*
|
||||
* @return mixed The value for this parameter
|
||||
*/
|
||||
public function GetCurrentValue($sParamName, $defaultValue = '')
|
||||
{
|
||||
if (isset($this->aValues[$sParamName]))
|
||||
{
|
||||
return $this->aValues[$sParamName];
|
||||
}
|
||||
return $defaultValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the context as string with the format name1=value1&name2=value2....
|
||||
* @return string The context as a string to be appended to an href property
|
||||
*/
|
||||
public function GetForLink()
|
||||
{
|
||||
$aParams = array();
|
||||
foreach($this->aValues as $sName => $sValue)
|
||||
{
|
||||
$aParams[] = "c[$sName]".'='.urlencode($sValue);
|
||||
}
|
||||
return implode("&", $aParams);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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)
|
||||
{
|
||||
$sContext .= "<input type=\"hidden\" name=\"c[$sName]\" value=\"".htmlentities($sValue, ENT_QUOTES, 'UTF-8')."\" />\n";
|
||||
}
|
||||
return $sContext;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the context as a hash array 'parameter_name' => value
|
||||
* @return array The context information
|
||||
*/
|
||||
public function GetAsHash()
|
||||
{
|
||||
$aReturn = array();
|
||||
foreach($this->aValues as $sName => $sValue)
|
||||
{
|
||||
$aReturn["c[$sName]"] = $sValue;
|
||||
}
|
||||
return $aReturn;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array of the context parameters NAMEs
|
||||
* @return array The list of context parameters
|
||||
*/
|
||||
public function GetNames()
|
||||
{
|
||||
return $this->aNames;
|
||||
}
|
||||
/**
|
||||
* Removes the specified parameter from the context, for example when the same parameter
|
||||
* is already a search parameter
|
||||
* @param string $sParamName Name of the parameter to remove
|
||||
*/
|
||||
public function Reset($sParamName)
|
||||
{
|
||||
if (isset($this->aValues[$sParamName]))
|
||||
{
|
||||
unset($this->aValues[$sParamName]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the given object with the default values provided by the context
|
||||
*
|
||||
* @param \DBObject $oObj
|
||||
*
|
||||
* @throws \Exception
|
||||
* @throws \CoreUnexpectedValue
|
||||
*/
|
||||
public function InitObjectFromContext(DBObject &$oObj)
|
||||
{
|
||||
$sClass = get_class($oObj);
|
||||
foreach($this->GetNames() as $key)
|
||||
{
|
||||
$aCallSpec = array($sClass, 'MapContextParam');
|
||||
if (is_callable($aCallSpec))
|
||||
{
|
||||
$sAttCode = call_user_func($aCallSpec, $key); // Returns null when there is no mapping for this parameter
|
||||
|
||||
if (MetaModel::IsValidAttCode($sClass, $sAttCode))
|
||||
{
|
||||
$oAttDef = MetaModel::GetAttributeDef($sClass, $sAttCode);
|
||||
if ($oAttDef->IsWritable())
|
||||
{
|
||||
$value = $this->GetCurrentValue($key, null);
|
||||
if (!is_null($value))
|
||||
{
|
||||
$oObj->Set($sAttCode, $value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the current application url provider
|
||||
* @param string $sClass Class implementing iDBObjectURLMaker
|
||||
* @return string
|
||||
*/
|
||||
public static function SetUrlMakerClass($sClass = 'iTopStandardURLMaker')
|
||||
{
|
||||
$sPrevious = self::GetUrlMakerClass();
|
||||
|
||||
self::$m_sUrlMakerClass = $sClass;
|
||||
$_SESSION['UrlMakerClass'] = $sClass;
|
||||
|
||||
return $sPrevious;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current application url provider
|
||||
* @return string the name of the class
|
||||
*/
|
||||
public static function GetUrlMakerClass()
|
||||
{
|
||||
if (is_null(self::$m_sUrlMakerClass))
|
||||
{
|
||||
if (isset($_SESSION['UrlMakerClass']))
|
||||
{
|
||||
self::$m_sUrlMakerClass = $_SESSION['UrlMakerClass'];
|
||||
}
|
||||
else
|
||||
{
|
||||
self::$m_sUrlMakerClass = 'iTopStandardURLMaker';
|
||||
}
|
||||
}
|
||||
return self::$m_sUrlMakerClass;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current application url provider
|
||||
*
|
||||
* @param string $sObjClass
|
||||
* @param string $sObjKey
|
||||
* @param null $sUrlMakerClass
|
||||
* @param bool $bWithNavigationContext
|
||||
*
|
||||
* @return string the name of the class
|
||||
* @throws \Exception
|
||||
*/
|
||||
public static function MakeObjectUrl($sObjClass, $sObjKey, $sUrlMakerClass = null, $bWithNavigationContext = true)
|
||||
{
|
||||
$oAppContext = new ApplicationContext();
|
||||
|
||||
if (is_null($sUrlMakerClass))
|
||||
{
|
||||
$sUrlMakerClass = self::GetUrlMakerClass();
|
||||
}
|
||||
$sUrl = call_user_func(array($sUrlMakerClass, 'MakeObjectUrl'), $sObjClass, $sObjKey);
|
||||
if (strlen($sUrl) > 0)
|
||||
{
|
||||
if ($bWithNavigationContext)
|
||||
{
|
||||
return $sUrl."&".$oAppContext->GetForLink();
|
||||
}
|
||||
else
|
||||
{
|
||||
return $sUrl;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Load plugin properties for the current session
|
||||
* @return void
|
||||
*/
|
||||
protected static function LoadPluginProperties()
|
||||
{
|
||||
if (isset($_SESSION['PluginProperties']))
|
||||
{
|
||||
self::$m_aPluginProperties = $_SESSION['PluginProperties'];
|
||||
}
|
||||
else
|
||||
{
|
||||
self::$m_aPluginProperties = array();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set plugin properties
|
||||
* @param string $sPluginClass Class implementing any plugin interface
|
||||
* @param string $sProperty Name of the property
|
||||
* @param mixed $value Value (numeric or string)
|
||||
* @return void
|
||||
*/
|
||||
public static function SetPluginProperty($sPluginClass, $sProperty, $value)
|
||||
{
|
||||
if (is_null(self::$m_aPluginProperties)) self::LoadPluginProperties();
|
||||
|
||||
self::$m_aPluginProperties[$sPluginClass][$sProperty] = $value;
|
||||
$_SESSION['PluginProperties'][$sPluginClass][$sProperty] = $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get plugin properties
|
||||
* @param string $sPluginClass Class implementing any plugin interface
|
||||
* @return array of sProperty=>value pairs
|
||||
*/
|
||||
public static function GetPluginProperties($sPluginClass)
|
||||
{
|
||||
if (is_null(self::$m_aPluginProperties)) self::LoadPluginProperties();
|
||||
|
||||
if (array_key_exists($sPluginClass, self::$m_aPluginProperties))
|
||||
{
|
||||
return self::$m_aPluginProperties[$sPluginClass];
|
||||
}
|
||||
else
|
||||
{
|
||||
return array();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,60 +1,60 @@
|
||||
<?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/>
|
||||
|
||||
|
||||
/**
|
||||
* This class manages the audit "categories". Each category defines a set of objects
|
||||
* to check and is linked to a set of rules that determine the valid or invalid objects
|
||||
* inside the set
|
||||
*
|
||||
* @copyright Copyright (C) 2010-2012 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
require_once(APPROOT.'/application/cmdbabstract.class.inc.php');
|
||||
|
||||
class AuditCategory extends cmdbAbstractObject
|
||||
{
|
||||
public static function Init()
|
||||
{
|
||||
$aParams = array
|
||||
(
|
||||
"category" => "application",
|
||||
"key_type" => "autoincrement",
|
||||
"name_attcode" => "name",
|
||||
"state_attcode" => "",
|
||||
"reconc_keys" => array('name'),
|
||||
"db_table" => "priv_auditcategory",
|
||||
"db_key_field" => "id",
|
||||
"db_finalclass_field" => "",
|
||||
);
|
||||
MetaModel::Init_Params($aParams);
|
||||
MetaModel::Init_AddAttribute(new AttributeString("name", array("description"=>"Short name for this category", "allowed_values"=>null, "sql"=>"name", "default_value"=>"", "is_null_allowed"=>false, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeString("description", array("allowed_values"=>null, "sql"=>"description", "default_value"=>"", "is_null_allowed"=>true, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeOQL("definition_set", array("allowed_values"=>null, "sql"=>"definition_set", "default_value"=>"", "is_null_allowed"=>false, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeLinkedSet("rules_list", array("linked_class"=>"AuditRule", "ext_key_to_me"=>"category_id", "allowed_values"=>null, "count_min"=>0, "count_max"=>0, "depends_on"=>array(), "edit_mode" => LINKSET_EDITMODE_INPLACE, "tracking_level" => LINKSET_TRACKING_ALL)));
|
||||
|
||||
// Display lists
|
||||
MetaModel::Init_SetZListItems('details', array('name', 'description', 'definition_set', 'rules_list')); // Attributes to be displayed for the complete details
|
||||
MetaModel::Init_SetZListItems('list', array('description', )); // Attributes to be displayed for a list
|
||||
// Search criteria
|
||||
MetaModel::Init_SetZListItems('standard_search', array('name', 'description')); // Criteria of the std search form
|
||||
MetaModel::Init_SetZListItems('advanced_search', array('name', 'description', 'definition_set')); // Criteria of the advanced search form
|
||||
}
|
||||
}
|
||||
?>
|
||||
<?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/>
|
||||
|
||||
|
||||
/**
|
||||
* This class manages the audit "categories". Each category defines a set of objects
|
||||
* to check and is linked to a set of rules that determine the valid or invalid objects
|
||||
* inside the set
|
||||
*
|
||||
* @copyright Copyright (C) 2010-2012 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
require_once(APPROOT.'/application/cmdbabstract.class.inc.php');
|
||||
|
||||
class AuditCategory extends cmdbAbstractObject
|
||||
{
|
||||
public static function Init()
|
||||
{
|
||||
$aParams = array
|
||||
(
|
||||
"category" => "application, grant_by_profile",
|
||||
"key_type" => "autoincrement",
|
||||
"name_attcode" => "name",
|
||||
"state_attcode" => "",
|
||||
"reconc_keys" => array('name'),
|
||||
"db_table" => "priv_auditcategory",
|
||||
"db_key_field" => "id",
|
||||
"db_finalclass_field" => "",
|
||||
);
|
||||
MetaModel::Init_Params($aParams);
|
||||
MetaModel::Init_AddAttribute(new AttributeString("name", array("description"=>"Short name for this category", "allowed_values"=>null, "sql"=>"name", "default_value"=>"", "is_null_allowed"=>false, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeString("description", array("allowed_values"=>null, "sql"=>"description", "default_value"=>"", "is_null_allowed"=>true, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeOQL("definition_set", array("allowed_values"=>null, "sql"=>"definition_set", "default_value"=>"", "is_null_allowed"=>false, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeLinkedSet("rules_list", array("linked_class"=>"AuditRule", "ext_key_to_me"=>"category_id", "allowed_values"=>null, "count_min"=>0, "count_max"=>0, "depends_on"=>array(), "edit_mode" => LINKSET_EDITMODE_INPLACE, "tracking_level" => LINKSET_TRACKING_ALL)));
|
||||
|
||||
// Display lists
|
||||
MetaModel::Init_SetZListItems('details', array('name', 'description', 'definition_set', 'rules_list')); // Attributes to be displayed for the complete details
|
||||
MetaModel::Init_SetZListItems('list', array('description', )); // Attributes to be displayed for a list
|
||||
// Search criteria
|
||||
MetaModel::Init_SetZListItems('standard_search', array('description', 'definition_set')); // Criteria of the std search form
|
||||
MetaModel::Init_SetZListItems('default_search', array('name', 'description')); // Criteria of the default search form
|
||||
}
|
||||
}
|
||||
?>
|
||||
|
||||
@@ -1,64 +1,64 @@
|
||||
<?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/>
|
||||
|
||||
|
||||
/**
|
||||
* This class manages the audit "rule" linked to a given audit category.
|
||||
* Each rule is based on an OQL expression that returns either the "good" objects
|
||||
* or the "bad" ones. The core audit engines computes the complement to the definition
|
||||
* set when needed to obtain either the valid objects, or the ones with an error
|
||||
*
|
||||
* @copyright Copyright (C) 2010-2012 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
require_once(APPROOT.'/application/audit.category.class.inc.php');
|
||||
|
||||
class AuditRule extends cmdbAbstractObject
|
||||
{
|
||||
public static function Init()
|
||||
{
|
||||
$aParams = array
|
||||
(
|
||||
"category" => "application",
|
||||
"key_type" => "autoincrement",
|
||||
"name_attcode" => "name",
|
||||
"state_attcode" => "",
|
||||
"reconc_keys" => array('name'),
|
||||
"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())));
|
||||
MetaModel::Init_AddAttribute(new AttributeString("description", array("allowed_values"=>null, "sql"=>"description", "default_value"=>"", "is_null_allowed"=>true, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeOQL("query", array("allowed_values"=>null, "sql"=>"query", "default_value"=>"", "is_null_allowed"=>false, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeEnum("valid_flag", array("allowed_values"=>new ValueSetEnum('true,false'), "sql"=>"valid_flag", "default_value"=>"true", "is_null_allowed"=>false, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeExternalKey("category_id", array("allowed_values"=>null, "sql"=>"category_id", "targetclass"=>"AuditCategory", "is_null_allowed"=>false, "on_target_delete"=>DEL_MANUAL, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeExternalField("category_name", array("allowed_values"=>null, "extkey_attcode"=> 'category_id', "target_attcode"=>"name")));
|
||||
|
||||
// Display lists
|
||||
MetaModel::Init_SetZListItems('details', array('category_id', 'name', 'description', 'query', 'valid_flag')); // Attributes to be displayed for the complete details
|
||||
MetaModel::Init_SetZListItems('list', array('category_id', 'description', 'valid_flag')); // Attributes to be displayed for a list
|
||||
// Search criteria
|
||||
MetaModel::Init_SetZListItems('standard_search', array('category_id', 'name', 'description', 'valid_flag')); // Criteria of the std search form
|
||||
MetaModel::Init_SetZListItems('advanced_search', array('category_id', 'name', 'description', 'valid_flag', 'query')); // Criteria of the advanced search form
|
||||
}
|
||||
}
|
||||
?>
|
||||
<?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/>
|
||||
|
||||
|
||||
/**
|
||||
* This class manages the audit "rule" linked to a given audit category.
|
||||
* Each rule is based on an OQL expression that returns either the "good" objects
|
||||
* or the "bad" ones. The core audit engines computes the complement to the definition
|
||||
* set when needed to obtain either the valid objects, or the ones with an error
|
||||
*
|
||||
* @copyright Copyright (C) 2010-2012 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
require_once(APPROOT.'/application/audit.category.class.inc.php');
|
||||
|
||||
class AuditRule extends cmdbAbstractObject
|
||||
{
|
||||
public static function Init()
|
||||
{
|
||||
$aParams = array
|
||||
(
|
||||
"category" => "application, grant_by_profile",
|
||||
"key_type" => "autoincrement",
|
||||
"name_attcode" => "name",
|
||||
"state_attcode" => "",
|
||||
"reconc_keys" => array('name'),
|
||||
"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())));
|
||||
MetaModel::Init_AddAttribute(new AttributeString("description", array("allowed_values"=>null, "sql"=>"description", "default_value"=>"", "is_null_allowed"=>true, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeOQL("query", array("allowed_values"=>null, "sql"=>"query", "default_value"=>"", "is_null_allowed"=>false, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeEnum("valid_flag", array("allowed_values"=>new ValueSetEnum('true,false'), "sql"=>"valid_flag", "default_value"=>"true", "is_null_allowed"=>false, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeExternalKey("category_id", array("allowed_values"=>null, "sql"=>"category_id", "targetclass"=>"AuditCategory", "is_null_allowed"=>false, "on_target_delete"=>DEL_MANUAL, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeExternalField("category_name", array("allowed_values"=>null, "extkey_attcode"=> 'category_id', "target_attcode"=>"name")));
|
||||
|
||||
// Display lists
|
||||
MetaModel::Init_SetZListItems('details', array('category_id', 'name', 'description', 'query', 'valid_flag')); // Attributes to be displayed for the complete details
|
||||
MetaModel::Init_SetZListItems('list', array('category_id', 'description', 'valid_flag')); // Attributes to be displayed for a list
|
||||
// Search criteria
|
||||
MetaModel::Init_SetZListItems('standard_search', array('category_id', 'name', 'description', 'valid_flag', 'query')); // Criteria of the std search form
|
||||
MetaModel::Init_SetZListItems('default_search', array('name', 'description', 'category_id')); // Criteria of the advanced search form
|
||||
}
|
||||
}
|
||||
?>
|
||||
|
||||
@@ -1,84 +1,84 @@
|
||||
<?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
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
<?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
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
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,97 @@
|
||||
<?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
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
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";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
<?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
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
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,111 +1,113 @@
|
||||
<?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
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
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=utf-8");
|
||||
$this->add_header("Cache-control: no-cache");
|
||||
//$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";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
<?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
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
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=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->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";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -21,6 +21,7 @@ require_once(APPROOT.'application/dashlet.class.inc.php');
|
||||
require_once(APPROOT.'core/modelreflection.class.inc.php');
|
||||
|
||||
/**
|
||||
*
|
||||
* A user editable dashboard page
|
||||
*
|
||||
* @copyright Copyright (C) 2010-2017 Combodo SARL
|
||||
@@ -49,6 +50,11 @@ abstract class Dashboard
|
||||
$this->sId = $sId;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $sXml
|
||||
*
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function FromXml($sXml)
|
||||
{
|
||||
$this->aCells = array(); // reset the content of the dashboard
|
||||
@@ -100,10 +106,10 @@ abstract class Dashboard
|
||||
$oCellsList = $oCellsNode->getElementsByTagName('cell');
|
||||
$aCellOrder = array();
|
||||
$iCellRank = 0;
|
||||
/** @var \DOMElement $oCellNode */
|
||||
foreach($oCellsList as $oCellNode)
|
||||
{
|
||||
$aDashletList = array();
|
||||
$oCellRank = $oCellNode->getElementsByTagName('rank')->item(0);
|
||||
$oCellRank = $oCellNode->getElementsByTagName('rank')->item(0);
|
||||
if ($oCellRank)
|
||||
{
|
||||
$iCellRank = (float)$oCellRank->textContent;
|
||||
@@ -113,17 +119,16 @@ abstract class Dashboard
|
||||
$oDashletList = $oDashletsNode->getElementsByTagName('dashlet');
|
||||
$iRank = 0;
|
||||
$aDashletOrder = array();
|
||||
/** @var \DOMElement $oDomNode */
|
||||
foreach($oDashletList as $oDomNode)
|
||||
{
|
||||
$sDashletClass = $oDomNode->getAttribute('xsi:type');
|
||||
$oRank = $oDomNode->getElementsByTagName('rank')->item(0);
|
||||
if ($oRank)
|
||||
{
|
||||
$iRank = (float)$oRank->textContent;
|
||||
}
|
||||
$sId = $oDomNode->getAttribute('id');
|
||||
$oNewDashlet = new $sDashletClass($this->oMetaModel, $sId);
|
||||
$oNewDashlet->FromDOMNode($oDomNode);
|
||||
|
||||
$oNewDashlet = $this->InitDashletFromDOMNode($oDomNode);
|
||||
$aDashletOrder[] = array('rank' => $iRank, 'dashlet' => $oNewDashlet);
|
||||
}
|
||||
usort($aDashletOrder, array(get_class($this), 'SortOnRank'));
|
||||
@@ -147,12 +152,41 @@ abstract class Dashboard
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \DOMElement $oDomNode
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
protected function InitDashletFromDOMNode($oDomNode)
|
||||
{
|
||||
$sId = $oDomNode->getAttribute('id');
|
||||
$sDashletType = $oDomNode->getAttribute('xsi:type');
|
||||
|
||||
// Test if dashlet can be instanciated, otherwise (uninstalled, broken, ...) we display a placeholder
|
||||
$sClass = static::GetDashletClassFromType($sDashletType);
|
||||
/** @var \Dashlet $oNewDashlet */
|
||||
$oNewDashlet = new $sClass($this->oMetaModel, $sId);
|
||||
$oNewDashlet->SetDashletType($sDashletType);
|
||||
$oNewDashlet->FromDOMNode($oDomNode);
|
||||
|
||||
return $oNewDashlet;
|
||||
}
|
||||
|
||||
static function SortOnRank($aItem1, $aItem2)
|
||||
{
|
||||
return ($aItem1['rank'] > $aItem2['rank']) ? +1 : -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Error handler to turn XML loading warnings into exceptions
|
||||
*
|
||||
* @param $errno
|
||||
* @param $errstr
|
||||
* @param $errfile
|
||||
* @param $errline
|
||||
*
|
||||
* @return bool
|
||||
* @throws \DOMException
|
||||
*/
|
||||
public static function ErrorHandler($errno, $errstr, $errfile, $errline)
|
||||
{
|
||||
@@ -182,8 +216,12 @@ abstract class Dashboard
|
||||
return $sXml;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \DOMElement $oDefinition
|
||||
*/
|
||||
public function ToDOMNode($oDefinition)
|
||||
{
|
||||
/** @var \DOMDocument $oDoc */
|
||||
$oDoc = $oDefinition->ownerDocument;
|
||||
|
||||
$oNode = $oDoc->createElement('layout', $this->sLayoutClass);
|
||||
@@ -215,12 +253,13 @@ abstract class Dashboard
|
||||
$iDashletRank = 0;
|
||||
$oDashletsNode = $oDoc->createElement('dashlets');
|
||||
$oCellNode->appendChild($oDashletsNode);
|
||||
/** @var \Dashlet $oDashlet */
|
||||
foreach ($aCell as $oDashlet)
|
||||
{
|
||||
$oNode = $oDoc->createElement('dashlet');
|
||||
$oDashletsNode->appendChild($oNode);
|
||||
$oNode->setAttribute('id', $oDashlet->GetID());
|
||||
$oNode->setAttribute('xsi:type', get_class($oDashlet));
|
||||
$oNode->setAttribute('xsi:type', $oDashlet->GetDashletType());
|
||||
$oDashletRank = $oDoc->createElement('rank', $iDashletRank);
|
||||
$oNode->appendChild($oDashletRank);
|
||||
$iDashletRank++;
|
||||
@@ -244,8 +283,12 @@ abstract class Dashboard
|
||||
{
|
||||
$sDashletClass = $aDashletParams['dashlet_class'];
|
||||
$sId = $aDashletParams['dashlet_id'];
|
||||
/** @var \Dashlet $oNewDashlet */
|
||||
$oNewDashlet = new $sDashletClass($this->oMetaModel, $sId);
|
||||
|
||||
if (isset($aDashletParams['dashlet_type']))
|
||||
{
|
||||
$oNewDashlet->SetDashletType($aDashletParams['dashlet_type']);
|
||||
}
|
||||
$oForm = $oNewDashlet->GetForm();
|
||||
$oForm->SetParamsContainer($sId);
|
||||
$oForm->SetPrefix('');
|
||||
@@ -303,31 +346,28 @@ abstract class Dashboard
|
||||
$this->iAutoReloadSec = max(MetaModel::GetConfig()->Get('min_reload_interval'), (int)$iAutoReloadSec);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \Dashlet $oDashlet
|
||||
*/
|
||||
public function AddDashlet($oDashlet)
|
||||
{
|
||||
$sId = $this->GetNewDashletId();
|
||||
$oDashlet->SetId($sId);
|
||||
$this->aCells[] = array($oDashlet);
|
||||
}
|
||||
|
||||
public function Render($oPage, $bEditMode = false, $aExtraParams = array())
|
||||
{
|
||||
$oPage->add('<h1>'.htmlentities(Dict::S($this->sTitle), ENT_QUOTES, 'UTF-8', false).'</h1>');
|
||||
$oLayout = new $this->sLayoutClass;
|
||||
$oLayout->Render($oPage, $this->aCells, $bEditMode, $aExtraParams);
|
||||
if (!$bEditMode)
|
||||
{
|
||||
$oPage->add_linked_script('../js/dashlet.js');
|
||||
$oPage->add_linked_script('../js/dashboard.js');
|
||||
}
|
||||
}
|
||||
|
||||
public function RenderProperties($oPage)
|
||||
|
||||
/**
|
||||
* @param \WebPage $oPage *
|
||||
* @param array $aExtraParams
|
||||
*
|
||||
* @throws \ReflectionException
|
||||
*/
|
||||
public function RenderProperties($oPage, $aExtraParams = array())
|
||||
{
|
||||
// menu to pick a layout and edit other properties of the dashboard
|
||||
$oPage->add('<div class="ui-widget-content ui-corner-all"><div class="ui-widget-header ui-corner-all" style="text-align:center; padding: 2px;">'.Dict::S('UI:DashboardEdit:Properties').'</div>');
|
||||
$sUrl = utils::GetAbsoluteUrlAppRoot();
|
||||
|
||||
|
||||
$oPage->add('<div style="text-align:center">'.Dict::S('UI:DashboardEdit:Layout').'</div>');
|
||||
$oPage->add('<div id="select_layout" style="text-align:center">');
|
||||
foreach( get_declared_classes() as $sLayoutClass)
|
||||
@@ -345,13 +385,13 @@ abstract class Dashboard
|
||||
}
|
||||
}
|
||||
$oPage->add('</div>');
|
||||
|
||||
|
||||
$oForm = new DesignerForm();
|
||||
|
||||
$oField = new DesignerHiddenField('dashboard_id', '', $this->sId);
|
||||
$oForm->AddField($oField);
|
||||
|
||||
$oField = new DesignerLongTextField('dashboard_title', Dict::S('UI:DashboardEdit:DashboardTitle'), $this->sTitle);
|
||||
$oField = new DesignerTextField('dashboard_title', Dict::S('UI:DashboardEdit:DashboardTitle'), $this->sTitle);
|
||||
$oForm->AddField($oField);
|
||||
|
||||
$oField = new DesignerBooleanField('auto_reload', Dict::S('UI:DashboardEdit:AutoReload'), $this->bAutoReload);
|
||||
@@ -362,8 +402,8 @@ abstract class Dashboard
|
||||
$oForm->AddField($oField);
|
||||
|
||||
|
||||
$this->SetFormParams($oForm);
|
||||
$oForm->RenderAsPropertySheet($oPage, false, '.itop-dashboard');
|
||||
$this->SetFormParams($oForm, $aExtraParams);
|
||||
$oForm->RenderAsPropertySheet($oPage, false, '.itop-dashboard');
|
||||
|
||||
$oPage->add('</div>');
|
||||
|
||||
@@ -407,17 +447,86 @@ abstract class Dashboard
|
||||
EOF
|
||||
);
|
||||
}
|
||||
|
||||
public function RenderDashletsSelection($oPage)
|
||||
|
||||
/**
|
||||
* @param \iTopWebPage $oPage
|
||||
* @param bool $bEditMode
|
||||
* @param array $aExtraParams
|
||||
* @param bool $bCanEdit
|
||||
*/
|
||||
public function Render($oPage, $bEditMode = false, $aExtraParams = array(), $bCanEdit = true)
|
||||
{
|
||||
$oPage->add('<div class="dashboard-title-line"><div class="dashboard-title">'.htmlentities(Dict::S($this->sTitle), ENT_QUOTES, 'UTF-8', false).'</div></div>');
|
||||
|
||||
$oLayout = new $this->sLayoutClass;
|
||||
/** @var \DashboardLayoutMultiCol $oLayout */
|
||||
$oLayout->Render($oPage, $this->aCells, $bEditMode, $aExtraParams);
|
||||
if (!$bEditMode)
|
||||
{
|
||||
$oPage->add_linked_script('../js/dashlet.js');
|
||||
$oPage->add_linked_script('../js/dashboard.js');
|
||||
}
|
||||
}
|
||||
|
||||
public function RenderDashletsSelection(WebPage $oPage)
|
||||
{
|
||||
// Toolbox/palette to drag and drop dashlets
|
||||
$oPage->add('<div class="ui-widget-content ui-corner-all"><div class="ui-widget-header ui-corner-all" style="text-align:center; padding: 2px;">'.Dict::S('UI:DashboardEdit:Dashlets').'</div>');
|
||||
$sUrl = utils::GetAbsoluteUrlAppRoot();
|
||||
|
||||
$oPage->add('<div id="select_dashlet" style="text-align:center">');
|
||||
$oPage->add('<div id="select_dashlet" style="text-align:center; max-height:120px; overflow-y:auto;">');
|
||||
$aAvailableDashlets = $this->GetAvailableDashlets();
|
||||
foreach($aAvailableDashlets as $sDashletClass => $aInfo)
|
||||
{
|
||||
$oPage->add('<span dashlet_class="'.$sDashletClass.'" class="dashlet_icon ui-widget-content ui-corner-all" id="dashlet_'.$sDashletClass.'" title="'.$aInfo['label'].'" style="width:34px; height:34px; display:inline-block; margin:2px;"><img src="'.$sUrl.$aInfo['icon'].'" /></span>');
|
||||
}
|
||||
$oPage->add('</div>');
|
||||
|
||||
$oPage->add('</div>');
|
||||
$oPage->add_ready_script("$('.dashlet_icon').draggable({helper: 'clone', appendTo: 'body', zIndex: 10000, revert:'invalid'});");
|
||||
}
|
||||
|
||||
public function RenderDashletsProperties(WebPage $oPage, $aExtraParams = array())
|
||||
{
|
||||
// Toolbox/palette to edit the properties of each dashlet
|
||||
$oPage->add('<div class="ui-widget-content ui-corner-all"><div class="ui-widget-header ui-corner-all" style="text-align:center; padding: 2px;">'.Dict::S('UI:DashboardEdit:DashletProperties').'</div>');
|
||||
|
||||
$oPage->add('<div id="dashlet_properties" style="text-align:center">');
|
||||
foreach($this->aCells as $aCell)
|
||||
{
|
||||
/** @var \Dashlet $oDashlet */
|
||||
foreach($aCell as $oDashlet)
|
||||
{
|
||||
$sId = $oDashlet->GetID();
|
||||
if ($oDashlet->IsVisible())
|
||||
{
|
||||
$oPage->add('<div class="dashlet_properties" id="dashlet_properties_'.$sId.'" style="display:none">');
|
||||
$oForm = $oDashlet->GetForm();
|
||||
$this->SetFormParams($oForm, $aExtraParams);
|
||||
$oForm->RenderAsPropertySheet($oPage, false, '.itop-dashboard');
|
||||
$oPage->add('</div>');
|
||||
}
|
||||
}
|
||||
}
|
||||
$oPage->add('</div>');
|
||||
|
||||
$oPage->add('</div>');
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an array of dashlets available for selection.
|
||||
*
|
||||
* @return array
|
||||
* @throws \ReflectionException
|
||||
*/
|
||||
protected function GetAvailableDashlets()
|
||||
{
|
||||
$aDashlets = array();
|
||||
|
||||
foreach( get_declared_classes() as $sDashletClass)
|
||||
{
|
||||
if (is_subclass_of($sDashletClass, 'Dashlet'))
|
||||
// DashletUnknown is not among the selection as it is just a fallback for dashlets that can't instanciated.
|
||||
if ( is_subclass_of($sDashletClass, 'Dashlet') && !in_array($sDashletClass, array('DashletUnknown', 'DashletProxy')) )
|
||||
{
|
||||
$oReflection = new ReflectionClass($sDashletClass);
|
||||
if (!$oReflection->isAbstract())
|
||||
@@ -428,42 +537,13 @@ EOF
|
||||
{
|
||||
$aCallSpec = array($sDashletClass, 'GetInfo');
|
||||
$aInfo = call_user_func($aCallSpec);
|
||||
$oPage->add('<span dashlet_class="'.$sDashletClass.'" class="dashlet_icon ui-widget-content ui-corner-all" id="dashlet_'.$sDashletClass.'" title="'.$aInfo['label'].'" style="width:34px; height:34px; display:inline-block; margin:2px;"><img src="'.$sUrl.$aInfo['icon'].'" /></span>');
|
||||
$aDashlets[$sDashletClass] = $aInfo;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
$oPage->add('</div>');
|
||||
|
||||
$oPage->add('</div>');
|
||||
$oPage->add_ready_script("$('.dashlet_icon').draggable({helper: 'clone', appendTo: 'body', zIndex: 10000, revert:'invalid'});");
|
||||
}
|
||||
|
||||
public function RenderDashletsProperties($oPage)
|
||||
{
|
||||
// Toolbox/palette to edit the properties of each dashlet
|
||||
$oPage->add('<div class="ui-widget-content ui-corner-all"><div class="ui-widget-header ui-corner-all" style="text-align:center; padding: 2px;">'.Dict::S('UI:DashboardEdit:DashletProperties').'</div>');
|
||||
|
||||
$oPage->add('<div id="dashlet_properties" style="text-align:center">');
|
||||
foreach($this->aCells as $aCell)
|
||||
{
|
||||
foreach($aCell as $oDashlet)
|
||||
{
|
||||
$sId = $oDashlet->GetID();
|
||||
$sClass = get_class($oDashlet);
|
||||
if ($oDashlet->IsVisible())
|
||||
{
|
||||
$oPage->add('<div class="dashlet_properties" id="dashlet_properties_'.$sId.'" style="display:none">');
|
||||
$oForm = $oDashlet->GetForm();
|
||||
$this->SetFormParams($oForm);
|
||||
$oForm->RenderAsPropertySheet($oPage, false, '.itop-dashboard');
|
||||
$oPage->add('</div>');
|
||||
}
|
||||
}
|
||||
}
|
||||
$oPage->add('</div>');
|
||||
|
||||
$oPage->add('</div>');
|
||||
return $aDashlets;
|
||||
}
|
||||
|
||||
protected function GetNewDashletId()
|
||||
@@ -471,6 +551,7 @@ EOF
|
||||
$iNewId = 0;
|
||||
foreach($this->aCells as $aDashlets)
|
||||
{
|
||||
/** @var \Dashlet $oDashlet */
|
||||
foreach($aDashlets as $oDashlet)
|
||||
{
|
||||
$iNewId = max($iNewId, (int)$oDashlet->GetID());
|
||||
@@ -478,13 +559,39 @@ EOF
|
||||
}
|
||||
return $iNewId + 1;
|
||||
}
|
||||
|
||||
abstract protected function SetFormParams($oForm);
|
||||
|
||||
/**
|
||||
* @param $oForm
|
||||
* @param array $aExtraParams
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
abstract protected function SetFormParams($oForm, $aExtraParams = array());
|
||||
|
||||
public static function GetDashletClassFromType($sType, $oFactory = null)
|
||||
{
|
||||
if (is_subclass_of($sType, 'Dashlet'))
|
||||
{
|
||||
return $sType;
|
||||
}
|
||||
return 'DashletUnknown';
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function GetId()
|
||||
{
|
||||
return $this->sId;
|
||||
}
|
||||
}
|
||||
|
||||
class RuntimeDashboard extends Dashboard
|
||||
{
|
||||
protected $bCustomized;
|
||||
private $sDefinitionFile = '';
|
||||
private $sReloadURL = null;
|
||||
|
||||
|
||||
public function __construct($sId)
|
||||
{
|
||||
@@ -497,10 +604,17 @@ class RuntimeDashboard extends Dashboard
|
||||
{
|
||||
$this->bCustomized = $bCustomized;
|
||||
}
|
||||
|
||||
protected function SetFormParams($oForm)
|
||||
|
||||
/**
|
||||
* @param \DesignerForm $oForm
|
||||
*
|
||||
* @param array $aExtraParams
|
||||
*
|
||||
* @throws \Exception
|
||||
*/
|
||||
protected function SetFormParams($oForm, $aExtraParams = array())
|
||||
{
|
||||
$oForm->SetSubmitParams(utils::GetAbsoluteUrlAppRoot().'pages/ajax.render.php', array('operation' => 'update_dashlet_property'));
|
||||
$oForm->SetSubmitParams(utils::GetAbsoluteUrlAppRoot().'pages/ajax.render.php', array('operation' => 'update_dashlet_property', 'extra_params' => $aExtraParams));
|
||||
}
|
||||
|
||||
public function Save()
|
||||
@@ -544,41 +658,266 @@ class RuntimeDashboard extends Dashboard
|
||||
utils::PopArchiveMode();
|
||||
}
|
||||
}
|
||||
|
||||
public function RenderEditionTools($oPage)
|
||||
|
||||
/**
|
||||
* @param string $sDashboardFile file name relative to the current module folder
|
||||
* @param string $sDashBoardId code of the dashboard either menu_id or <class>__<attcode>
|
||||
*
|
||||
* @return null|RuntimeDashboard
|
||||
* @throws \CoreException
|
||||
* @throws \CoreUnexpectedValue
|
||||
* @throws \MissingQueryArgument
|
||||
* @throws \MySQLException
|
||||
* @throws \MySQLHasGoneAwayException
|
||||
*/
|
||||
public static function GetDashboard($sDashboardFile, $sDashBoardId)
|
||||
{
|
||||
$bCustomized = false;
|
||||
|
||||
$sDashboardFileSanitized = utils::RealPath($sDashboardFile, APPROOT);
|
||||
if (false === $sDashboardFileSanitized) {
|
||||
throw new SecurityException('Invalid dashboard file !');
|
||||
}
|
||||
|
||||
if (!appUserPreferences::GetPref('display_original_dashboard_'.$sDashBoardId, false)) {
|
||||
// Search for an eventual user defined dashboard
|
||||
$oUDSearch = new DBObjectSearch('UserDashboard');
|
||||
$oUDSearch->AddCondition('user_id', UserRights::GetUserId(), '=');
|
||||
$oUDSearch->AddCondition('menu_code', $sDashBoardId, '=');
|
||||
$oUDSet = new DBObjectSet($oUDSearch);
|
||||
if ($oUDSet->Count() > 0) {
|
||||
// Assuming there is at most one couple {user, menu}!
|
||||
$oUserDashboard = $oUDSet->Fetch();
|
||||
$sDashboardDefinition = $oUserDashboard->Get('contents');
|
||||
$bCustomized = true;
|
||||
} else {
|
||||
$sDashboardDefinition = @file_get_contents($sDashboardFileSanitized);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$sDashboardDefinition = @file_get_contents($sDashboardFileSanitized);
|
||||
}
|
||||
|
||||
if ($sDashboardDefinition !== false)
|
||||
{
|
||||
$oDashboard = new RuntimeDashboard($sDashBoardId);
|
||||
$oDashboard->FromXml($sDashboardDefinition);
|
||||
$oDashboard->SetCustomFlag($bCustomized);
|
||||
$oDashboard->SetDefinitionFile($sDashboardFileSanitized);
|
||||
}
|
||||
else
|
||||
{
|
||||
$oDashboard = null;
|
||||
}
|
||||
return $oDashboard;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \iTopWebPage $oPage
|
||||
* @param bool $bEditMode
|
||||
* @param array $aExtraParams (class and id of the current object
|
||||
*
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function Render($oPage, $bEditMode = false, $aExtraParams = array(), $bCanEdit = true)
|
||||
{
|
||||
if (!isset($aExtraParams['query_params']) && isset($aExtraParams['this->class']))
|
||||
{
|
||||
$oObj = MetaModel::GetObject($aExtraParams['this->class'], $aExtraParams['this->id']);
|
||||
$aRenderParams = array('query_params' => $oObj->ToArgsForQuery());
|
||||
}
|
||||
else
|
||||
{
|
||||
$aRenderParams = $aExtraParams;
|
||||
}
|
||||
|
||||
parent::Render($oPage, $bEditMode, $aRenderParams);
|
||||
|
||||
if (isset($aExtraParams['query_params']['this->object()']))
|
||||
{
|
||||
/** @var \DBObject $oObj */
|
||||
$oObj = $aExtraParams['query_params']['this->object()'];
|
||||
$aAjaxParams = array('this->class' => get_class($oObj), 'this->id' => $oObj->GetKey());
|
||||
}
|
||||
else
|
||||
{
|
||||
$aAjaxParams = $aExtraParams;
|
||||
}
|
||||
if (!$bEditMode && !$oPage->IsPrintableVersion())
|
||||
{
|
||||
$sId = $this->GetId();
|
||||
$sDivId = preg_replace('/[^a-zA-Z0-9_]/', '', $sId);
|
||||
if ($this->GetAutoReload())
|
||||
{
|
||||
$sFile = addslashes($this->GetDefinitionFile());
|
||||
$sExtraParams = json_encode($aAjaxParams);
|
||||
$iReloadInterval = 1000 * $this->GetAutoReloadInterval();
|
||||
$sReloadURL = $this->GetReloadURL();
|
||||
$oPage->add_script(
|
||||
<<<EOF
|
||||
if (typeof(AutoReloadDashboardId$sDivId) !== 'undefined')
|
||||
{
|
||||
clearInterval(AutoReloadDashboardId$sDivId);
|
||||
delete AutoReloadDashboardId$sDivId;
|
||||
}
|
||||
|
||||
AutoReloadDashboardId$sDivId = setInterval("ReloadDashboard$sDivId();", $iReloadInterval);
|
||||
|
||||
function ReloadDashboard$sDivId()
|
||||
{
|
||||
// Do not reload when a dialog box is active
|
||||
if (!($('.ui-dialog:visible').length > 0) && $('.dashboard_contents#$sDivId').is(':visible'))
|
||||
{
|
||||
$('.dashboard_contents#$sDivId').block();
|
||||
$.post(GetAbsoluteUrlAppRoot()+'pages/ajax.render.php',
|
||||
{ operation: 'reload_dashboard', dashboard_id: '$sId', file: '$sFile', extra_params: $sExtraParams, reload_url: '$sReloadURL'},
|
||||
function(data){
|
||||
$('.dashboard_contents#$sDivId').html(data);
|
||||
$('.dashboard_contents#$sDivId').unblock();
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
EOF
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
$oPage->add_script(
|
||||
<<<EOF
|
||||
if (typeof(AutoReloadDashboardId$sDivId) !== 'undefined')
|
||||
{
|
||||
clearInterval(AutoReloadDashboardId$sDivId);
|
||||
delete AutoReloadDashboardId$sDivId;
|
||||
}
|
||||
EOF
|
||||
);
|
||||
}
|
||||
|
||||
if ($bCanEdit)
|
||||
{
|
||||
$this->RenderSelector($oPage, $aAjaxParams);
|
||||
$this->RenderEditionTools($oPage, $aAjaxParams);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \iTopWebPage $oPage
|
||||
* @param array $aAjaxParams
|
||||
*/
|
||||
protected function RenderSelector($oPage, $aAjaxParams = array())
|
||||
{
|
||||
$sId = $this->GetId();
|
||||
$sDivId = preg_replace('/[^a-zA-Z0-9_]/', '', $sId);
|
||||
$sExtraParams = json_encode($aAjaxParams);
|
||||
|
||||
$sSelectorHtml = '<div class="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
|
||||
);
|
||||
|
||||
$oPage->add_script(
|
||||
<<<EOF
|
||||
function ToggleDashboardSelector$sDivId()
|
||||
{
|
||||
$('.dashboard_contents#$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();
|
||||
}
|
||||
);
|
||||
}
|
||||
EOF
|
||||
);
|
||||
}
|
||||
|
||||
protected function HasCustomDashboard()
|
||||
{
|
||||
try
|
||||
{
|
||||
// Search for an eventual user defined dashboard
|
||||
$oUDSearch = new DBObjectSearch('UserDashboard');
|
||||
$oUDSearch->AddCondition('user_id', UserRights::GetUserId(), '=');
|
||||
$oUDSearch->AddCondition('menu_code', $this->GetId(), '=');
|
||||
$oUDSet = new DBObjectSet($oUDSearch);
|
||||
|
||||
return ($oUDSet->Count() > 0);
|
||||
}
|
||||
catch (Exception $e)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \WebPage $oPage
|
||||
* @param array $aExtraParams
|
||||
*
|
||||
* @throws \Exception
|
||||
*/
|
||||
protected function RenderEditionTools(WebPage $oPage, $aExtraParams)
|
||||
{
|
||||
$oPage->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/jquery.iframe-transport.js');
|
||||
$oPage->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/jquery.fileupload.js');
|
||||
$sEditMenu = "<td><span id=\"DashboardMenu\"><ul><li><img src=\"../images/pencil-menu.png\"><ul>";
|
||||
$sEditMenu = "<div id=\"DashboardMenu\"><ul><li><img src=\"../images/pencil-menu.png\"><ul>";
|
||||
|
||||
$aActions = array();
|
||||
$oEdit = new JSPopupMenuItem('UI:Dashboard:Edit', Dict::S('UI:Dashboard:Edit'), "return EditDashboard('{$this->sId}')");
|
||||
$aActions[$oEdit->GetUID()] = $oEdit->GetMenuItem();
|
||||
$sFile = addslashes($this->sDefinitionFile);
|
||||
$sJSExtraParams = json_encode($aExtraParams);
|
||||
$bCanEdit = true;
|
||||
if ($this->HasCustomDashboard())
|
||||
{
|
||||
$bCanEdit = !appUserPreferences::GetPref('display_original_dashboard_'.$this->GetId(), false);
|
||||
}
|
||||
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)
|
||||
{
|
||||
$oRevert = new JSPopupMenuItem('UI:Dashboard:RevertConfirm', Dict::S('UI:Dashboard:Revert'),
|
||||
"if (confirm('".addslashes(Dict::S('UI:Dashboard:RevertConfirm'))."')) return RevertDashboard('{$this->sId}'); 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);
|
||||
//$sEditBtn = addslashes('<div style="display: inline-block; height: 55px; width:200px;vertical-align:center;line-height:60px;text-align:left;"><button onclick="EditDashboard(\''.$this->sId.'\');">Edit This Page</button></div>');
|
||||
$sReloadURL = $this->GetReloadURL();
|
||||
$oPage->add_ready_script(
|
||||
<<<EOF
|
||||
$('#logOffBtn').parent().before('$sEditMenu');
|
||||
$('.dashboard-title').after('$sEditMenu');
|
||||
$('#DashboardMenu>ul').popupmenu();
|
||||
|
||||
EOF
|
||||
);
|
||||
$oPage->add_script(
|
||||
<<<EOF
|
||||
function EditDashboard(sId)
|
||||
function EditDashboard(sId, sDashboardFile, aExtraParams)
|
||||
{
|
||||
$.post(GetAbsoluteUrlAppRoot()+'pages/ajax.render.php', {operation: 'dashboard_editor', id: sId},
|
||||
$.post(GetAbsoluteUrlAppRoot()+'pages/ajax.render.php', {operation: 'dashboard_editor', id: sId, file: sDashboardFile, extra_params: aExtraParams, reload_url: '$sReloadURL'},
|
||||
function(data)
|
||||
{
|
||||
$('body').append(data);
|
||||
@@ -586,12 +925,12 @@ function EditDashboard(sId)
|
||||
);
|
||||
return false;
|
||||
}
|
||||
function RevertDashboard(sId)
|
||||
function RevertDashboard(sId, aExtraParams)
|
||||
{
|
||||
$.post(GetAbsoluteUrlAppRoot()+'pages/ajax.render.php', {operation: 'revert_dashboard', dashboard_id: sId},
|
||||
$.post(GetAbsoluteUrlAppRoot()+'pages/ajax.render.php', {operation: 'revert_dashboard', dashboard_id: sId, extra_params: aExtraParams, reload_url: '$sReloadURL'},
|
||||
function(data)
|
||||
{
|
||||
$('body').append(data);
|
||||
location.reload();
|
||||
}
|
||||
);
|
||||
return false;
|
||||
@@ -600,9 +939,14 @@ EOF
|
||||
);
|
||||
}
|
||||
|
||||
public function RenderProperties($oPage)
|
||||
/**
|
||||
* @param \WebPage $oPage
|
||||
*
|
||||
* @throws \ReflectionException
|
||||
*/
|
||||
public function RenderProperties($oPage, $aExtraParams = array())
|
||||
{
|
||||
parent::RenderProperties($oPage);
|
||||
parent::RenderProperties($oPage, $aExtraParams);
|
||||
|
||||
$oPage->add_ready_script(
|
||||
<<<EOF
|
||||
@@ -633,16 +977,36 @@ EOF
|
||||
}
|
||||
|
||||
|
||||
public function RenderEditor($oPage)
|
||||
/**
|
||||
* @param \iTopWebPage $oPage
|
||||
*
|
||||
* @param array $aExtraParams
|
||||
*
|
||||
* @throws \ArchivedObjectException
|
||||
* @throws \CoreException
|
||||
* @throws \ReflectionException
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function RenderEditor($oPage, $aExtraParams = array())
|
||||
{
|
||||
if (isset($aExtraParams['this->class']))
|
||||
{
|
||||
$oObj = MetaModel::GetObject($aExtraParams['this->class'], $aExtraParams['this->id']);
|
||||
$aRenderParams = array('query_params' => $oObj->ToArgsForQuery());
|
||||
}
|
||||
else
|
||||
{
|
||||
$aRenderParams = $aExtraParams;
|
||||
}
|
||||
$sJSExtraParams = json_encode($aExtraParams);
|
||||
$oPage->add('<div id="dashboard_editor">');
|
||||
$oPage->add('<div class="ui-layout-center">');
|
||||
$this->Render($oPage, true);
|
||||
$this->Render($oPage, true, $aRenderParams);
|
||||
$oPage->add('</div>');
|
||||
$oPage->add('<div class="ui-layout-east">');
|
||||
$this->RenderProperties($oPage);
|
||||
$this->RenderProperties($oPage, $aExtraParams);
|
||||
$this->RenderDashletsSelection($oPage);
|
||||
$this->RenderDashletsProperties($oPage);
|
||||
$this->RenderDashletsProperties($oPage, $aExtraParams);
|
||||
$oPage->add('</div>');
|
||||
$oPage->add('<div id="event_bus"/>'); // For exchanging messages between the panes, same as in the designer
|
||||
$oPage->add('</div>');
|
||||
@@ -656,7 +1020,9 @@ EOF
|
||||
$sAutoReload = $this->bAutoReload ? 'true' : 'false';
|
||||
$sAutoReloadSec = (string) $this->iAutoReloadSec;
|
||||
$sTitle = addslashes($this->sTitle);
|
||||
$sFile = addslashes($this->GetDefinitionFile());
|
||||
$sUrl = utils::GetAbsoluteUrlAppRoot().'pages/ajax.render.php';
|
||||
$sReloadURL = $this->GetReloadURL();
|
||||
|
||||
$sExitConfirmationMessage = addslashes(Dict::S('UI:NavigateAwayConfirmationMessage'));
|
||||
$sCancelConfirmationMessage = addslashes(Dict::S('UI:CancelConfirmationMessage'));
|
||||
@@ -686,7 +1052,7 @@ $('#dashboard_editor').dialog({
|
||||
}
|
||||
}
|
||||
window.bLeavingOnUserAction = true;
|
||||
oDashboard.save();
|
||||
oDashboard.save($(this));
|
||||
} },
|
||||
{ text: "$sCancelButtonLabel", click: function() {
|
||||
var oDashboard = $('.itop-dashboard').data('itopRuntimedashboard');
|
||||
@@ -708,8 +1074,8 @@ $('#dashboard_editor').dialog({
|
||||
$('#dashboard_editor .ui-layout-center').runtimedashboard({
|
||||
dashboard_id: '$sId', layout_class: '$sLayoutClass', title: '$sTitle',
|
||||
auto_reload: $sAutoReload, auto_reload_sec: $sAutoReloadSec,
|
||||
submit_to: '$sUrl', submit_parameters: {operation: 'save_dashboard'},
|
||||
render_to: '$sUrl', render_parameters: {operation: 'render_dashboard'},
|
||||
submit_to: '$sUrl', submit_parameters: {operation: 'save_dashboard', file: '$sFile', extra_params: $sJSExtraParams, reload_url: '$sReloadURL'},
|
||||
render_to: '$sUrl', render_parameters: {operation: 'render_dashboard', file: '$sFile', extra_params: $sJSExtraParams, reload_url: '$sReloadURL'},
|
||||
new_dashlet_parameters: {operation: 'new_dashlet'}
|
||||
});
|
||||
|
||||
@@ -755,33 +1121,66 @@ EOF
|
||||
|
||||
public static function GetDashletCreationForm($sOQL = null)
|
||||
{
|
||||
$oAppContext = new ApplicationContext();
|
||||
$sContextMenuId = $oAppContext->GetCurrentValue('menu', null);
|
||||
|
||||
$oForm = new DesignerForm();
|
||||
|
||||
// Get the list of all 'dashboard' menus in which we can insert a dashlet
|
||||
$aAllMenus = ApplicationMenu::ReflectionMenuNodes();
|
||||
$sRootMenuId = ApplicationMenu::GetRootMenuId($sContextMenuId);
|
||||
$aAllowedDashboards = array();
|
||||
foreach($aAllMenus as $idx => $aMenu)
|
||||
$sDefaultDashboard = null;
|
||||
|
||||
// Store the parent menus for acces check
|
||||
$aParentMenus = array();
|
||||
foreach($aAllMenus as $idx => $aMenu)
|
||||
{
|
||||
/** @var MenuNode $oMenu */
|
||||
$oMenu = $aMenu['node'];
|
||||
if (count(ApplicationMenu::GetChildren($oMenu->GetIndex())) > 0)
|
||||
{
|
||||
$aParentMenus[$oMenu->GetMenuId()] = $aMenu;
|
||||
}
|
||||
}
|
||||
|
||||
foreach($aAllMenus as $idx => $aMenu)
|
||||
{
|
||||
$oMenu = $aMenu['node'];
|
||||
$sParentId = $aMenu['parent'];
|
||||
if ($oMenu instanceof DashboardMenuNode)
|
||||
{
|
||||
$sMenuLabel = $oMenu->GetTitle();
|
||||
$sParentLabel = Dict::S('Menu:'.$sParentId);
|
||||
if ($sParentLabel != $sMenuLabel)
|
||||
{
|
||||
$aAllowedDashboards[$oMenu->GetMenuId()] = $sParentLabel.' - '.$sMenuLabel;
|
||||
}
|
||||
else
|
||||
{
|
||||
$aAllowedDashboards[$oMenu->GetMenuId()] = $sMenuLabel;
|
||||
}
|
||||
}
|
||||
if ($oMenu instanceof DashboardMenuNode)
|
||||
{
|
||||
// Get the root parent for access check
|
||||
$sParentId = $aMenu['parent'];
|
||||
$aParentMenu = $aParentMenus[$sParentId];
|
||||
while (isset($aParentMenus[$aParentMenu['parent']]))
|
||||
{
|
||||
// grand parent exists
|
||||
$sParentId = $aParentMenu['parent'];
|
||||
$aParentMenu = $aParentMenus[$sParentId];
|
||||
}
|
||||
/** @var \MenuNode $oParentMenu */
|
||||
$oParentMenu = $aParentMenu['node'];
|
||||
if ($oMenu->IsEnabled() && $oParentMenu->IsEnabled())
|
||||
{
|
||||
$sMenuLabel = $oMenu->GetTitle();
|
||||
$sParentLabel = Dict::S('Menu:'.$sParentId);
|
||||
if ($sParentLabel != $sMenuLabel)
|
||||
{
|
||||
$aAllowedDashboards[$oMenu->GetMenuId()] = $sParentLabel.' - '.$sMenuLabel;
|
||||
}
|
||||
else
|
||||
{
|
||||
$aAllowedDashboards[$oMenu->GetMenuId()] = $sMenuLabel;
|
||||
}
|
||||
if (empty($sDefaultDashboard) && ($sRootMenuId == ApplicationMenu::GetRootMenuId($oMenu->GetMenuId())))
|
||||
{
|
||||
$sDefaultDashboard = $oMenu->GetMenuId();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
asort($aAllowedDashboards);
|
||||
|
||||
$aKeys = array_keys($aAllowedDashboards); // Select the first one by default
|
||||
$sDefaultDashboard = $aKeys[0];
|
||||
$oField = new DesignerComboField('menu_id', Dict::S('UI:DashletCreation:Dashboard'), $sDefaultDashboard);
|
||||
$oField->SetAllowedValues($aAllowedDashboards);
|
||||
$oField->SetMandatory(true);
|
||||
@@ -815,6 +1214,7 @@ EOF
|
||||
{
|
||||
$oSubForm = new DesignerForm();
|
||||
$oMetaModel = new ModelReflectionRuntime();
|
||||
/** @var \Dashlet $oDashlet */
|
||||
$oDashlet = new $sDashletClass($oMetaModel, 0);
|
||||
$oDashlet->GetPropertiesFieldsFromOQL($oSubForm, $sOQL);
|
||||
|
||||
@@ -825,7 +1225,11 @@ EOF
|
||||
|
||||
return $oForm;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param \WebPage $oPage
|
||||
* @param $sOQL
|
||||
*/
|
||||
public static function GetDashletCreationDlgFromOQL($oPage, $sOQL)
|
||||
{
|
||||
$oPage->add('<div id="dashlet_creation_dlg">');
|
||||
@@ -842,7 +1246,7 @@ EOF
|
||||
$oPage->add_ready_script(
|
||||
<<<EOF
|
||||
$('#dashlet_creation_dlg').dialog({
|
||||
width: 400,
|
||||
width: 600,
|
||||
modal: true,
|
||||
title: '$sDialogTitle',
|
||||
buttons: [
|
||||
@@ -872,4 +1276,30 @@ $('#dashlet_creation_dlg').dialog({
|
||||
EOF
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function GetDefinitionFile()
|
||||
{
|
||||
return $this->sDefinitionFile;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $sDefinitionFile
|
||||
*/
|
||||
public function SetDefinitionFile($sDefinitionFile)
|
||||
{
|
||||
$this->sDefinitionFile = $sDefinitionFile;
|
||||
}
|
||||
|
||||
public function GetReloadURL()
|
||||
{
|
||||
return $this->sReloadURL;
|
||||
}
|
||||
|
||||
public function SetReloadURL($sReloadURL)
|
||||
{
|
||||
$this->sReloadURL = $sReloadURL;
|
||||
}
|
||||
}
|
||||
@@ -59,6 +59,7 @@ abstract class DashboardLayoutMultiCol extends DashboardLayout
|
||||
$bNoVisibleFound = true;
|
||||
while($idx < count($aKeys) && $bNoVisibleFound)
|
||||
{
|
||||
/** @var \Dashlet $oDashlet */
|
||||
$oDashlet = $aDashlets[$aKeys[$idx]];
|
||||
if ($oDashlet->IsVisible())
|
||||
{
|
||||
@@ -98,7 +99,13 @@ abstract class DashboardLayoutMultiCol extends DashboardLayout
|
||||
return $aCells;
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param \WebPage $oPage
|
||||
* @param $aCells
|
||||
* @param bool $bEditMode
|
||||
* @param array $aExtraParams
|
||||
*/
|
||||
public function Render($oPage, $aCells, $bEditMode = false, $aExtraParams = array())
|
||||
{
|
||||
// Trim the list of cells to remove the invisible/empty ones at the end of the array
|
||||
@@ -122,6 +129,7 @@ abstract class DashboardLayoutMultiCol extends DashboardLayout
|
||||
$aDashlets = $aCells[$iCellIdx];
|
||||
if (count($aDashlets) > 0)
|
||||
{
|
||||
/** @var \Dashlet $oDashlet */
|
||||
foreach($aDashlets as $oDashlet)
|
||||
{
|
||||
if ($oDashlet->IsVisible())
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,5 +1,5 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<itop_design>
|
||||
<itop_design xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="1.6">
|
||||
<portals>
|
||||
<portal id="legacy_portal" _delta="define">
|
||||
<url>portal/index.php</url>
|
||||
@@ -19,4 +19,9 @@
|
||||
</deny>
|
||||
</portal>
|
||||
</portals>
|
||||
<menus>
|
||||
<menu id="AdminTools" xsi:type="MenuGroup" _delta="define">
|
||||
<rank>80</rank>
|
||||
</menu>
|
||||
</menus>
|
||||
</itop_design>
|
||||
|
||||
@@ -174,6 +174,7 @@ class DataTable
|
||||
}
|
||||
$sJSOptions = json_encode($aOptions);
|
||||
$oPage->add_ready_script("$('#datatable_{$this->iListId}').datatable($sJSOptions);");
|
||||
|
||||
return $sHtml;
|
||||
}
|
||||
|
||||
@@ -183,6 +184,10 @@ class DataTable
|
||||
*/
|
||||
public function GetAsHTMLTableRows(WebPage $oPage, $iPageSize, $aColumns, $sSelectMode, $bViewLink, $aExtraParams)
|
||||
{
|
||||
if ($iPageSize < 1)
|
||||
{
|
||||
$iPageSize = -1; // convention: no pagination
|
||||
}
|
||||
$aAttribs = $this->GetHTMLTableConfig($aColumns, $sSelectMode, $bViewLink);
|
||||
$aValues = $this->GetHTMLTableValues($aColumns, $sSelectMode, $iPageSize, $bViewLink, $aExtraParams);
|
||||
|
||||
@@ -221,14 +226,21 @@ class DataTable
|
||||
}
|
||||
|
||||
$sCombo = '<select class="pagesize">';
|
||||
for($iPage = 1; $iPage < 5; $iPage++)
|
||||
if($iPageSize < 1)
|
||||
{
|
||||
$iNbItems = $iPage * $iDefaultPageSize;
|
||||
$sSelected = ($iNbItems == $iPageSize) ? 'selected="selected"' : '';
|
||||
$sCombo .= "<option $sSelected value=\"$iNbItems\">$iNbItems</option>";
|
||||
$sCombo .= "<option selected=\"selected\" value=\"-1\">".Dict::S('UI:Pagination:All')."</option>";
|
||||
}
|
||||
$sSelected = ($iPageSize < 1) ? 'selected="selected"' : '';
|
||||
$sCombo .= "<option $sSelected value=\"-1\">".Dict::S('UI:Pagination:All')."</option>";
|
||||
else
|
||||
{
|
||||
for($iPage = 1; $iPage < 5; $iPage++)
|
||||
{
|
||||
$iNbItems = $iPage * $iDefaultPageSize;
|
||||
$sSelected = ($iNbItems == $iPageSize) ? 'selected="selected"' : '';
|
||||
$sCombo .= "<option $sSelected value=\"$iNbItems\">$iNbItems</option>";
|
||||
}
|
||||
$sCombo .= "<option value=\"-1\">".Dict::S('UI:Pagination:All')."</option>";
|
||||
}
|
||||
|
||||
$sCombo .= '</select>';
|
||||
|
||||
$sPages = Dict::S('UI:Pagination:PagesLabel');
|
||||
@@ -297,7 +309,7 @@ EOF;
|
||||
if (!$oPage->IsPrintableVersion())
|
||||
{
|
||||
$sMenuTitle = Dict::S('UI:ConfigureThisList');
|
||||
$sHtml = '<div class="itop_popup toolkit_menu" id="tk_'.$this->iListId.'"><ul><li><img src="../images/toolkit_menu.png?itopversion='.ITOP_VERSION.'"><ul>';
|
||||
$sHtml = '<div class="itop_popup toolkit_menu" id="tk_'.$this->iListId.'"><ul><li><img src="../images/toolkit_menu.png?t='.utils::GetCacheBusterTimestamp().'"><ul>';
|
||||
|
||||
$oMenuItem1 = new JSPopupMenuItem('iTop::ConfigureList', $sMenuTitle, "$('#datatable_dlg_".$this->iListId."').dialog('open');");
|
||||
$aActions = array(
|
||||
@@ -430,7 +442,7 @@ EOF;
|
||||
}
|
||||
else
|
||||
{
|
||||
$aRow['form::select'] = "<input type=\"checkBox\" $sDisabled class=\"selectList{$this->iListId}\" name=\"selectObject[]\" value=\"".$aObjects[$sAlias]->GetKey()."\"></input>";
|
||||
$aRow['form::select'] = "<input type=\"checkbox\" $sDisabled class=\"selectList{$this->iListId}\" name=\"selectObject[]\" value=\"".$aObjects[$sAlias]->GetKey()."\"></input>";
|
||||
}
|
||||
}
|
||||
foreach($aColumns[$sAlias] as $sAttCode => $aData)
|
||||
@@ -564,49 +576,22 @@ EOF;
|
||||
<<<EOF
|
||||
var oTable = $('#{$this->iListId} table.listResults');
|
||||
oTable.tableHover();
|
||||
oTable.tablesorter( { $sHeaders widgets: ['myZebra', 'truncatedList']} ).tablesorterPager({container: $('#pager{$this->iListId}'), totalRows:$iCount, size: $iPageSize, filter: '$sOQL', extra_params: '$sExtraParams', select_mode: '$sSelectModeJS', displayKey: $sDisplayKey, columns: $sJSColumns, class_aliases: $sJSClassAliases $sCssCount});
|
||||
oTable.tablesorter( { $sHeaders widgets: ['myZebra', 'truncatedList']} ).tablesorterPager({container: $('#pager{$this->iListId}'), totalRows:$iCount, size: $iPageSize, filter: '$sOQL', extra_params: '$sExtraParams', select_mode: '$sSelectModeJS', displayKey: $sDisplayKey, table_id: '{$this->iListId}', columns: $sJSColumns, class_aliases: $sJSClassAliases $sCssCount});
|
||||
EOF
|
||||
);
|
||||
if ($sFakeSortList != '')
|
||||
{
|
||||
$oPage->add_ready_script("oTable.trigger(\"fakesorton\", [$sFakeSortList]);");
|
||||
}
|
||||
//if ($iNbPages == 1)
|
||||
if (false)
|
||||
{
|
||||
if (isset($aExtraParams['cssCount']))
|
||||
{
|
||||
$sCssCount = $aExtraParams['cssCount'];
|
||||
if ($sSelectMode == 'single')
|
||||
{
|
||||
$sSelectSelector = ":radio[name^=selectObj]";
|
||||
}
|
||||
else if ($sSelectMode == 'multiple')
|
||||
{
|
||||
$sSelectSelector = ":checkbox[name^=selectObj]";
|
||||
}
|
||||
$oPage->add_ready_script(
|
||||
<<<EOF
|
||||
$('#{$this->iListId} table.listResults $sSelectSelector').change(function() {
|
||||
var c = $('{$sCssCount}');
|
||||
var v = $('#{$this->iListId} table.listResults $sSelectSelector:checked').length;
|
||||
c.val(v);
|
||||
$('#{$this->iListId} .selectedCount').text(v);
|
||||
c.trigger('change');
|
||||
});
|
||||
EOF
|
||||
);
|
||||
}
|
||||
}
|
||||
return $sHtml;
|
||||
}
|
||||
|
||||
public function UpdatePager(WebPage $oPage, $iDefaultPageSize, $iStart)
|
||||
{
|
||||
$iPageSize = ($iDefaultPageSize < 1) ? 1 : $iDefaultPageSize;
|
||||
$iPageIndex = 1 + floor($iStart / $iPageSize);
|
||||
$iPageSize = $iDefaultPageSize;
|
||||
$iPageIndex = 0;
|
||||
$sHtml = $this->GetPager($oPage, $iPageSize, $iDefaultPageSize, $iPageIndex);
|
||||
$oPage->add_ready_script("$('#pager{$this->iListId}').html('".str_replace("\n", ' ', addslashes($sHtml))."');");
|
||||
$oPage->add_ready_script("$('#pager{$this->iListId}').html('".json_encode($sHtml)."');");
|
||||
if ($iDefaultPageSize < 1)
|
||||
{
|
||||
$oPage->add_ready_script("$('#pager{$this->iListId}').parent().hide()");
|
||||
@@ -782,6 +767,10 @@ class DataTableSettings implements Serializable
|
||||
{
|
||||
foreach($this->aClassAliases as $sAlias => $sClass)
|
||||
{
|
||||
if (!isset($this->aColumns[$sAlias]))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
foreach($this->aColumns[$sAlias] as $sAttCode => $aData)
|
||||
{
|
||||
// Remove non-existent columns
|
||||
@@ -797,7 +786,7 @@ class DataTableSettings implements Serializable
|
||||
$aTempData = array();
|
||||
foreach($aList as $sAttCode => $oAttDef)
|
||||
{
|
||||
if ( (!array_key_exists($sAttCode, $this->aColumns[$sAlias])) && (!$oAttDef instanceof AttributeLinkSet))
|
||||
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;
|
||||
@@ -958,4 +947,4 @@ class DataTableSettings implements Serializable
|
||||
}
|
||||
return $ret;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -43,6 +43,7 @@ require_once(APPROOT.'/application/utils.inc.php');
|
||||
class DisplayBlock
|
||||
{
|
||||
const TAG_BLOCK = 'itopblock';
|
||||
/** @var \DBSearch */
|
||||
protected $m_oFilter;
|
||||
protected $m_aConditions; // Conditions added to the filter -> avoid duplicate conditions
|
||||
protected $m_sStyle;
|
||||
@@ -74,10 +75,17 @@ class DisplayBlock
|
||||
{
|
||||
return $this->m_oFilter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a DisplayBlock object from a DBObjectSet already in memory
|
||||
* @param $oSet DBObjectSet
|
||||
*
|
||||
* @param DBObjectSet $oSet
|
||||
* @param string $sStyle
|
||||
* @param array $aParams
|
||||
*
|
||||
* @return DisplayBlock The DisplayBlock object, or null if the creation failed
|
||||
* @throws \CoreException
|
||||
* @throws \Exception
|
||||
*/
|
||||
public static function FromObjectSet(DBObjectSet $oSet, $sStyle, $aParams = array())
|
||||
{
|
||||
@@ -100,11 +108,15 @@ class DisplayBlock
|
||||
$oBlock = new DisplayBlock($oDummyFilter, $sStyle, false, $aParams); // DisplayBlocks built this way are synchronous
|
||||
return $oBlock;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Constructs a DisplayBlock object from an XML template
|
||||
*
|
||||
* @param $sTemplate string The XML template
|
||||
*
|
||||
* @return DisplayBlock The DisplayBlock object, or null if the template is invalid
|
||||
* @throws \ApplicationException
|
||||
* @throws \OQLException
|
||||
*/
|
||||
public static function FromTemplate($sTemplate)
|
||||
{
|
||||
@@ -114,7 +126,6 @@ class DisplayBlock
|
||||
$aParams = array();
|
||||
|
||||
if (($iStartPos === false) || ($iEndPos === false)) return null; // invalid template
|
||||
$sITopBlock = substr($sTemplate,$iStartPos, $iEndPos-$iStartPos+strlen('</'.self::TAG_BLOCK.'>'));
|
||||
$sITopData = substr($sTemplate, 1+$iEndTag, $iEndPos - $iEndTag - 1);
|
||||
$sITopTag = substr($sTemplate, $iStartPos + strlen('<'.self::TAG_BLOCK), $iEndTag - $iStartPos - strlen('<'.self::TAG_BLOCK));
|
||||
|
||||
@@ -135,10 +146,6 @@ class DisplayBlock
|
||||
{
|
||||
$sBlockClass = $aMatches[1];
|
||||
}
|
||||
if (preg_match('/ objectclass="(.*)"/U',$sITopTag, $aMatches))
|
||||
{
|
||||
$sObjectClass = $aMatches[1];
|
||||
}
|
||||
if (preg_match('/ encoding="(.*)"/U',$sITopTag, $aMatches))
|
||||
{
|
||||
$sEncoding = strtolower($aMatches[1]);
|
||||
@@ -187,6 +194,7 @@ class DisplayBlock
|
||||
}
|
||||
|
||||
}
|
||||
$oFilter = null;
|
||||
switch($sEncoding)
|
||||
{
|
||||
case 'text/serialize':
|
||||
@@ -212,47 +220,37 @@ class DisplayBlock
|
||||
$aExtraParams['currentId'] = $sId;
|
||||
$sExtraParams = addslashes(str_replace('"', "'", json_encode($aExtraParams))); // JSON encode, change the style of the quotes and escape them
|
||||
|
||||
$bAutoReload = false;
|
||||
if (isset($aExtraParams['auto_reload']))
|
||||
if (isset($aExtraParams['query_params']))
|
||||
{
|
||||
if ($aExtraParams['auto_reload'] === true)
|
||||
$aQueryParams = $aExtraParams['query_params'];
|
||||
}
|
||||
else
|
||||
{
|
||||
if (isset($aExtraParams['this->id']) && isset($aExtraParams['this->class']))
|
||||
{
|
||||
// Note: does not work in the switch (case true) because a positive number evaluates to true!!!
|
||||
$aExtraParams['auto_reload'] = 'standard';
|
||||
$sClass = $aExtraParams['this->class'];
|
||||
$iKey = $aExtraParams['this->id'];
|
||||
$oObj = MetaModel::GetObject($sClass, $iKey);
|
||||
$aQueryParams = array('this->object()' => $oObj);
|
||||
}
|
||||
switch($aExtraParams['auto_reload'])
|
||||
else
|
||||
{
|
||||
case 'fast':
|
||||
$bAutoReload = true;
|
||||
$iReloadInterval = MetaModel::GetConfig()->GetFastReloadInterval()*1000;
|
||||
break;
|
||||
|
||||
case 'standard':
|
||||
case 'true':
|
||||
$bAutoReload = true;
|
||||
$iReloadInterval = MetaModel::GetConfig()->GetStandardReloadInterval()*1000;
|
||||
break;
|
||||
|
||||
default:
|
||||
if (is_numeric($aExtraParams['auto_reload']) && ($aExtraParams['auto_reload'] > 0))
|
||||
{
|
||||
$bAutoReload = true;
|
||||
$iReloadInterval = max(MetaModel::GetConfig()->Get('min_reload_interval'), $aExtraParams['auto_reload'])*1000;
|
||||
}
|
||||
else
|
||||
{
|
||||
// incorrect config, ignore it
|
||||
$bAutoReload = false;
|
||||
}
|
||||
$aQueryParams = array();
|
||||
}
|
||||
}
|
||||
|
||||
$sFilter = $this->m_oFilter->serialize(); // Used either for asynchronous or auto_reload
|
||||
$sFilter = addslashes($this->m_oFilter->serialize(false, $aQueryParams)); // Used either for asynchronous or auto_reload
|
||||
if (!$this->m_bAsynchronous)
|
||||
{
|
||||
// render now
|
||||
$sHtml .= "<div id=\"$sId\" class=\"display_block\">\n";
|
||||
$sHtml .= $this->GetRenderContent($oPage, $aExtraParams, $sId);
|
||||
$sHtml .= "<div id=\"$sId\" class=\"display_block\" >\n";
|
||||
try
|
||||
{
|
||||
$sHtml .= $this->GetRenderContent($oPage, $aExtraParams, $sId);
|
||||
} catch (Exception $e)
|
||||
{
|
||||
|
||||
}
|
||||
$sHtml .= "</div>\n";
|
||||
}
|
||||
else
|
||||
@@ -265,20 +263,49 @@ class DisplayBlock
|
||||
$.post("ajax.render.php?style='.$this->m_sStyle.'",
|
||||
{ operation: "ajax", filter: "'.$sFilter.'", extra_params: "'.$sExtraParams.'" },
|
||||
function(data){
|
||||
$("#'.$sId.'").empty();
|
||||
$("#'.$sId.'").append(data);
|
||||
$("#'.$sId.'").removeClass("loading");
|
||||
$("#'.$sId.'")
|
||||
.empty()
|
||||
.append(data)
|
||||
.removeClass("loading")
|
||||
;
|
||||
}
|
||||
);
|
||||
');
|
||||
}
|
||||
if (($bAutoReload) && ($this->m_sStyle != 'search')) // Search form do NOT auto-reload
|
||||
{
|
||||
$oPage->add_script('setInterval("ReloadBlock(\''.$sId.'\', \''.$this->m_sStyle.'\', \''.$sFilter.'\', \"'.$sExtraParams.'\")", '.$iReloadInterval.');');
|
||||
}
|
||||
|
||||
|
||||
if ($this->m_sStyle == 'list') // Search form need to extract result list extra data, the simplest way is to expose this configuration
|
||||
{
|
||||
|
||||
$listJsonExtraParams = json_encode(json_encode($aExtraParams));
|
||||
$oPage->add_ready_script("
|
||||
$('#$sId').data('sExtraParams', ".$listJsonExtraParams.");
|
||||
// console.debug($('#$sId').data());
|
||||
// console.debug($('#$sId'));
|
||||
// console.debug('#$sId');
|
||||
");
|
||||
|
||||
|
||||
|
||||
|
||||
// $oPage->add_ready_script("console.debug($('#Menu_UserRequest_OpenRequests').data());");
|
||||
|
||||
}
|
||||
|
||||
|
||||
return $sHtml;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param \WebPage $oPage
|
||||
* @param array $aExtraParams
|
||||
*
|
||||
* @throws \ApplicationException
|
||||
* @throws \CoreException
|
||||
* @throws \CoreWarning
|
||||
* @throws \DictExceptionMissingString
|
||||
* @throws \MySQLException
|
||||
*/
|
||||
public function RenderContent(WebPage $oPage, $aExtraParams = array())
|
||||
{
|
||||
if (!isset($aExtraParams['currentId']))
|
||||
@@ -291,20 +318,44 @@ class DisplayBlock
|
||||
}
|
||||
$oPage->add($this->GetRenderContent($oPage, $aExtraParams, $sId));
|
||||
}
|
||||
|
||||
public function GetRenderContent(WebPage $oPage, $aExtraParams = array(), $sId)
|
||||
|
||||
/**
|
||||
* @param WebPage $oPage
|
||||
* @param array $aExtraParams
|
||||
* @param $sId
|
||||
* @return string
|
||||
* @throws ApplicationException
|
||||
* @throws CoreException
|
||||
* @throws CoreWarning
|
||||
* @throws DictExceptionMissingString
|
||||
* @throws MySQLException
|
||||
* @throws Exception
|
||||
*/
|
||||
public function GetRenderContent(WebPage $oPage, $aExtraParams, $sId)
|
||||
{
|
||||
$sHtml = '';
|
||||
// Add the extra params into the filter if they make sense for such a filter
|
||||
$bDoSearch = utils::ReadParam('dosearch', false);
|
||||
$aQueryParams = array();
|
||||
if (isset($aExtraParams['query_params']))
|
||||
{
|
||||
$aQueryParams = $aExtraParams['query_params'];
|
||||
}
|
||||
else
|
||||
{
|
||||
if (isset($aExtraParams['this->id']) && isset($aExtraParams['this->class']))
|
||||
{
|
||||
$sClass = $aExtraParams['this->class'];
|
||||
$iKey = $aExtraParams['this->id'];
|
||||
$oObj = MetaModel::GetObject($sClass, $iKey);
|
||||
$aQueryParams = array('this->object()' => $oObj);
|
||||
}
|
||||
}
|
||||
if ($this->m_oSet == null)
|
||||
{
|
||||
$aQueryParams = array();
|
||||
if (isset($aExtraParams['query_params']))
|
||||
{
|
||||
$aQueryParams = $aExtraParams['query_params'];
|
||||
}
|
||||
if ($this->m_sStyle != 'links')
|
||||
|
||||
// In case of search, the context filtering is done by the search itself
|
||||
if (($this->m_sStyle != 'links') && ($this->m_sStyle != 'search') && ($this->m_sStyle != 'list_search'))
|
||||
{
|
||||
$oAppContext = new ApplicationContext();
|
||||
$sClass = $this->m_oFilter->GetClass();
|
||||
@@ -406,37 +457,8 @@ class DisplayBlock
|
||||
case 'count':
|
||||
if (isset($aExtraParams['group_by']))
|
||||
{
|
||||
if (isset($aExtraParams['group_by_label']))
|
||||
{
|
||||
$oGroupByExp = Expression::FromOQL($aExtraParams['group_by']);
|
||||
$sGroupByLabel = $aExtraParams['group_by_label'];
|
||||
}
|
||||
else
|
||||
{
|
||||
// Backward compatibility: group_by is simply a field id
|
||||
$sAlias = $this->m_oFilter->GetClassAlias();
|
||||
$oGroupByExp = new FieldExpression($aExtraParams['group_by'], $sAlias);
|
||||
$sGroupByLabel = MetaModel::GetLabel($this->m_oFilter->GetClass(), $aExtraParams['group_by']);
|
||||
}
|
||||
$this->MakeGroupByQuery($aExtraParams, $oGroupByExp, $sGroupByLabel, $aGroupBy, $sAggregationFunction, $sFctVar, $sAggregationAttr, $sSql);
|
||||
|
||||
// Security filtering
|
||||
$aFields = $oGroupByExp->ListRequiredFields();
|
||||
foreach($aFields as $sFieldAlias)
|
||||
{
|
||||
if (preg_match('/^([^.]+)\\.([^.]+)$/', $sFieldAlias, $aMatches))
|
||||
{
|
||||
$sFieldClass = $this->m_oFilter->GetClassName($aMatches[1]);
|
||||
$oAttDef = MetaModel::GetAttributeDef($sFieldClass, $aMatches[2]);
|
||||
if ($oAttDef instanceof AttributeOneWayPassword)
|
||||
{
|
||||
throw new Exception('Grouping on password fields is not supported.');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$aGroupBy = array();
|
||||
$aGroupBy['grouped_by_1'] = $oGroupByExp;
|
||||
$sSql = $this->m_oFilter->MakeGroupByQuery($aQueryParams, $aGroupBy, true);
|
||||
$aRes = CMDBSource::QueryToArray($sSql);
|
||||
|
||||
$aGroupBy = array();
|
||||
@@ -449,7 +471,7 @@ class DisplayBlock
|
||||
$aValues[$iRow] = $sValue;
|
||||
$sHtmlValue = $oGroupByExp->MakeValueLabel($this->m_oFilter, $sValue, $sValue);
|
||||
$aLabels[$iRow] = $sHtmlValue;
|
||||
$aGroupBy[$iRow] = (int) $aRow['_itop_count_'];
|
||||
$aGroupBy[$iRow] = (int) $aRow[$sFctVar];
|
||||
$iTotalCount += $aRow['_itop_count_'];
|
||||
}
|
||||
|
||||
@@ -463,14 +485,25 @@ class DisplayBlock
|
||||
$oSubsetSearch = $this->m_oFilter->DeepClone();
|
||||
$oCondition = new BinaryExpression($oGroupByExp, '=', new ScalarExpression($aValues[$iRow]));
|
||||
$oSubsetSearch->AddConditionExpression($oCondition);
|
||||
$sFilter = urlencode($oSubsetSearch->serialize());
|
||||
if (isset($aExtraParams['query_params']))
|
||||
{
|
||||
$aQueryParams = $aExtraParams['query_params'];
|
||||
}
|
||||
else
|
||||
{
|
||||
$aQueryParams = array();
|
||||
}
|
||||
$sFilter = rawurlencode($oSubsetSearch->serialize(false, $aQueryParams));
|
||||
|
||||
$aData[] = array ( 'group' => $aLabels[$iRow],
|
||||
$aData[] = array ('group' => $aLabels[$iRow],
|
||||
'value' => "<a href=\"".utils::GetAbsoluteUrlAppRoot()."pages/UI.php?operation=search&dosearch=1&$sParams&filter=$sFilter\">$iCount</a>"); // TO DO: add the context information
|
||||
}
|
||||
$aAttribs =array(
|
||||
'group' => array('label' => $sGroupByLabel, 'description' => ''),
|
||||
'value' => array('label'=> Dict::S('UI:GroupBy:Count'), 'description' => Dict::S('UI:GroupBy:Count+'))
|
||||
'value' => array(
|
||||
'label' => Dict::S('UI:GroupBy:'.$sAggregationFunction),
|
||||
'description' => Dict::Format('UI:GroupBy:'.$sAggregationFunction.'+', $sAggregationAttr),
|
||||
),
|
||||
);
|
||||
$sFormat = isset($aExtraParams['format']) ? $aExtraParams['format'] : 'UI:Pagination:HeaderNoSelection';
|
||||
$sHtml .= $oPage->GetP(Dict::Format($sFormat, $iTotalCount));
|
||||
@@ -586,6 +619,7 @@ class DisplayBlock
|
||||
}
|
||||
break;
|
||||
|
||||
case 'list_search':
|
||||
case 'list':
|
||||
$aClasses = $this->m_oSet->GetSelectedClasses();
|
||||
$aAuthorizedClasses = array();
|
||||
@@ -594,14 +628,14 @@ class DisplayBlock
|
||||
// Check the classes that can be read (i.e authorized) by this user...
|
||||
foreach($aClasses as $sAlias => $sClassName)
|
||||
{
|
||||
if (UserRights::IsActionAllowed($sClassName, UR_ACTION_READ, $this->m_oSet) && (UR_ALLOWED_YES || UR_ALLOWED_DEPENDS))
|
||||
if (UserRights::IsActionAllowed($sClassName, UR_ACTION_READ, $this->m_oSet) != UR_ALLOWED_NO)
|
||||
{
|
||||
$aAuthorizedClasses[$sAlias] = $sClassName;
|
||||
}
|
||||
}
|
||||
if (count($aAuthorizedClasses) > 0)
|
||||
{
|
||||
if($this->m_oSet->Count() > 0)
|
||||
if($this->m_oSet->CountWithLimit(1) > 0)
|
||||
{
|
||||
$sHtml .= cmdbAbstractObject::GetDisplayExtendedSet($oPage, $this->m_oSet, $aExtraParams);
|
||||
}
|
||||
@@ -620,7 +654,7 @@ class DisplayBlock
|
||||
else
|
||||
{
|
||||
// The list is made of only 1 class of objects, actions on the list are possible
|
||||
if ( ($this->m_oSet->Count()> 0) && (UserRights::IsActionAllowed($this->m_oSet->GetClass(), UR_ACTION_READ, $this->m_oSet) == UR_ALLOWED_YES) )
|
||||
if ( ($this->m_oSet->CountWithLimit(1)> 0) && (UserRights::IsActionAllowed($this->m_oSet->GetClass(), UR_ACTION_READ, $this->m_oSet) == UR_ALLOWED_YES) )
|
||||
{
|
||||
$sHtml .= cmdbAbstractObject::GetDisplaySet($oPage, $this->m_oSet, $aExtraParams);
|
||||
}
|
||||
@@ -655,13 +689,32 @@ class DisplayBlock
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($aExtraParams['update_history']) && true == $aExtraParams['update_history'])
|
||||
{
|
||||
$sSearchFilter = $this->m_oSet->GetFilter()->serialize();
|
||||
// Limit the size of the URL (N°1585 - request uri too long)
|
||||
if (strlen($sSearchFilter) < SERVER_MAX_URL_LENGTH)
|
||||
{
|
||||
$seventAttachedData = json_encode(array(
|
||||
'filter' => $sSearchFilter,
|
||||
'breadcrumb_id' => "ui-search-".$this->m_oSet->GetClass(),
|
||||
'breadcrumb_label' => MetaModel::GetName($this->m_oSet->GetClass()),
|
||||
'breadcrumb_max_count' => utils::GetConfig()->Get('breadcrumb.max_count'),
|
||||
'breadcrumb_instance_id' => MetaModel::GetConfig()->GetItopInstanceid(),
|
||||
'breadcrumb_icon' => utils::GetAbsoluteUrlAppRoot().'images/breadcrumb-search.png',
|
||||
));
|
||||
|
||||
$oPage->add_ready_script("$('body').trigger('update_history.itop', [$seventAttachedData])");
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 'links':
|
||||
//$bDashboardMode = isset($aExtraParams['dashboard']) ? ($aExtraParams['dashboard'] == 'true') : false;
|
||||
//$bSelectMode = isset($aExtraParams['select']) ? ($aExtraParams['select'] == 'true') : false;
|
||||
if ( ($this->m_oSet->Count()> 0) && (UserRights::IsActionAllowed($this->m_oSet->GetClass(), UR_ACTION_READ, $this->m_oSet) == UR_ALLOWED_YES) )
|
||||
if ( ($this->m_oSet->CountWithLimit(1) > 0) && (UserRights::IsActionAllowed($this->m_oSet->GetClass(), UR_ACTION_READ, $this->m_oSet) == UR_ALLOWED_YES) )
|
||||
{
|
||||
//$sLinkage = isset($aExtraParams['linkage']) ? $aExtraParams['linkage'] : '';
|
||||
$sHtml .= cmdbAbstractObject::GetDisplaySet($oPage, $this->m_oSet, $aExtraParams);
|
||||
@@ -677,8 +730,6 @@ class DisplayBlock
|
||||
{
|
||||
if ((UserRights::IsActionAllowed($sClass, UR_ACTION_MODIFY) == UR_ALLOWED_YES))
|
||||
{
|
||||
$oAppContext = new ApplicationContext();
|
||||
$sParams = $oAppContext->GetForLink();
|
||||
$sDefaults = '';
|
||||
if (isset($this->m_aParams['default']))
|
||||
{
|
||||
@@ -704,9 +755,8 @@ class DisplayBlock
|
||||
$sClass = $this->m_oFilter->GetClass();
|
||||
$oAppContext = new ApplicationContext();
|
||||
$bContextFilter = isset($aExtraParams['context_filter']) ? isset($aExtraParams['context_filter']) != 0 : false;
|
||||
if ($bContextFilter)
|
||||
if ($bContextFilter && is_null($this->m_oSet))
|
||||
{
|
||||
$aFilterCodes = array_keys(MetaModel::GetClassFilterDefs($this->m_oFilter->GetClass()));
|
||||
foreach($oAppContext->GetNames() as $sFilterCode)
|
||||
{
|
||||
$sContextParamValue = $oAppContext->GetCurrentValue($sFilterCode, null);
|
||||
@@ -724,7 +774,7 @@ class DisplayBlock
|
||||
$this->m_oSet->SetShowObsoleteData($this->m_bShowObsoleteData);
|
||||
}
|
||||
$iCount = $this->m_oSet->Count();
|
||||
$sHyperlink = utils::GetAbsoluteUrlAppRoot().'pages/UI.php?operation=search&'.$oAppContext->GetForLink().'&filter='.urlencode($this->m_oFilter->serialize());
|
||||
$sHyperlink = utils::GetAbsoluteUrlAppRoot().'pages/UI.php?operation=search&'.$oAppContext->GetForLink().'&filter='.rawurlencode($this->m_oFilter->serialize());
|
||||
$sHtml .= '<p><a class="actions" href="'.$sHyperlink.'">';
|
||||
// Note: border set to 0 due to various browser interpretations (IE9 adding a 2px border)
|
||||
$sHtml .= MetaModel::GetClassIcon($sClass, true, 'float;left;margin-right:10px;border:0;');
|
||||
@@ -750,7 +800,6 @@ class DisplayBlock
|
||||
$bContextFilter = isset($aExtraParams['context_filter']) ? isset($aExtraParams['context_filter']) != 0 : false;
|
||||
if ($bContextFilter)
|
||||
{
|
||||
$aFilterCodes = array_keys(MetaModel::GetClassFilterDefs($this->m_oFilter->GetClass()));
|
||||
foreach($oAppContext->GetNames() as $sFilterCode)
|
||||
{
|
||||
$sContextParamValue = $oAppContext->GetCurrentValue($sFilterCode, null);
|
||||
@@ -774,21 +823,47 @@ class DisplayBlock
|
||||
{
|
||||
$aStates = explode(',', $sStatesList);
|
||||
$oAttDef = MetaModel::GetAttributeDef($sClass, $sStateAttrCode);
|
||||
|
||||
// Generate one count + group by query [#1330]
|
||||
$sClassAlias = $this->m_oFilter->GetClassAlias();
|
||||
$oGroupByExpr = Expression::FromOQL($sClassAlias.'.'.$sStateAttrCode);
|
||||
$aGroupBy = array('group1' => $oGroupByExpr);
|
||||
$oGroupBySearch = $this->m_oFilter->DeepClone();
|
||||
if (isset($this->m_bShowObsoleteData))
|
||||
{
|
||||
$oGroupBySearch->SetShowObsoleteData($this->m_bShowObsoleteData);
|
||||
}
|
||||
$sCountGroupByQuery = $oGroupBySearch->MakeGroupByQuery(array(), $aGroupBy, false);
|
||||
$aCountGroupByResults = CMDBSource::QueryToArray($sCountGroupByQuery);
|
||||
$aCountsQueryResults = array();
|
||||
foreach ($aCountGroupByResults as $aCountGroupBySingleResult)
|
||||
{
|
||||
$aCountsQueryResults[$aCountGroupBySingleResult[0]] = $aCountGroupBySingleResult[1];
|
||||
}
|
||||
|
||||
foreach($aStates as $sStateValue)
|
||||
{
|
||||
$oFilter = $this->m_oFilter->DeepClone();
|
||||
$oFilter->AddCondition($sStateAttrCode, $sStateValue, '=');
|
||||
$oSet = new DBObjectSet($oFilter);
|
||||
$oSet->SetShowObsoleteData($this->m_bShowObsoleteData);
|
||||
$aCounts[$sStateValue] = $oSet->Count();
|
||||
$aStateLabels[$sStateValue] = htmlentities($oAttDef->GetValueLabel($sStateValue), ENT_QUOTES, 'UTF-8');
|
||||
|
||||
$aCounts[$sStateValue] = (array_key_exists($sStateValue, $aCountsQueryResults))
|
||||
? $aCountsQueryResults[$sStateValue]
|
||||
: 0;
|
||||
|
||||
if ($aCounts[$sStateValue] == 0)
|
||||
{
|
||||
$aCounts[$sStateValue] = '-';
|
||||
}
|
||||
else
|
||||
{
|
||||
$sHyperlink = utils::GetAbsoluteUrlAppRoot().'pages/UI.php?operation=search&'.$oAppContext->GetForLink().'&filter='.urlencode($oFilter->serialize());
|
||||
$oSingleGroupByValueFilter = $this->m_oFilter->DeepClone();
|
||||
$oSingleGroupByValueFilter->AddCondition($sStateAttrCode, $sStateValue, '=');
|
||||
if (isset($this->m_bShowObsoleteData))
|
||||
{
|
||||
$oSingleGroupByValueFilter->SetShowObsoleteData($this->m_bShowObsoleteData);
|
||||
}
|
||||
$sHyperlink = utils::GetAbsoluteUrlAppRoot()
|
||||
.'pages/UI.php?operation=search&'.$oAppContext->GetForLink()
|
||||
.'&filter='.rawurlencode($oSingleGroupByValueFilter->serialize());
|
||||
$aCounts[$sStateValue] = "<a href=\"$sHyperlink\">{$aCounts[$sStateValue]}</a>";
|
||||
}
|
||||
}
|
||||
@@ -797,7 +872,7 @@ class DisplayBlock
|
||||
$sHtml .= '<tr><td>'.implode('</td><td>', $aCounts).'</td></tr></table></div>';
|
||||
// Title & summary
|
||||
$iCount = $this->m_oSet->Count();
|
||||
$sHyperlink = utils::GetAbsoluteUrlAppRoot().'pages/UI.php?operation=search&'.$oAppContext->GetForLink().'&filter='.urlencode($this->m_oFilter->serialize());
|
||||
$sHyperlink = utils::GetAbsoluteUrlAppRoot().'pages/UI.php?operation=search&'.$oAppContext->GetForLink().'&filter='.rawurlencode($this->m_oFilter->serialize());
|
||||
$sHtml .= '<h1>'.Dict::S(str_replace('_', ':', $sTitle)).'</h1>';
|
||||
$sHtml .= '<a class="summary" href="'.$sHyperlink.'">'.Dict::Format(str_replace('_', ':', $sLabel), $iCount).'</a>';
|
||||
$sHtml .= '<div style="clear:both;"></div>';
|
||||
@@ -808,7 +883,7 @@ class DisplayBlock
|
||||
|
||||
$sCsvFile = strtolower($this->m_oFilter->GetClass()).'.csv';
|
||||
$sDownloadLink = utils::GetAbsoluteUrlAppRoot().'webservices/export.php?expression='.urlencode($this->m_oFilter->ToOQL(true)).'&format=csv&filename='.urlencode($sCsvFile);
|
||||
$sLinkToToggle = utils::GetAbsoluteUrlAppRoot().'pages/UI.php?operation=search&'.$oAppContext->GetForLink().'&filter='.urlencode($this->m_oFilter->serialize()).'&format=csv';
|
||||
$sLinkToToggle = utils::GetAbsoluteUrlAppRoot().'pages/UI.php?operation=search&'.$oAppContext->GetForLink().'&filter='.rawurlencode($this->m_oFilter->serialize()).'&format=csv';
|
||||
// Pass the parameters via POST, since expression may be very long
|
||||
$aParamsToPost = array(
|
||||
'expression' => $this->m_oFilter->ToOQL(true),
|
||||
@@ -829,36 +904,6 @@ class DisplayBlock
|
||||
}
|
||||
$sAjaxLink = utils::GetAbsoluteUrlAppRoot().'webservices/export.php';
|
||||
|
||||
/*
|
||||
$sCSVData = cmdbAbstractObject::GetSetAsCSV($this->m_oSet, array('fields_advanced' => $bAdvancedMode));
|
||||
$sCharset = MetaModel::GetConfig()->Get('csv_file_default_charset');
|
||||
if ($sCharset == 'UTF-8')
|
||||
{
|
||||
$bLostChars = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
$sConverted = @iconv('UTF-8', $sCharset, $sCSVData);
|
||||
$sRestored = @iconv($sCharset, 'UTF-8', $sConverted);
|
||||
$bLostChars = ($sRestored != $sCSVData);
|
||||
}
|
||||
|
||||
if ($bLostChars)
|
||||
{
|
||||
$sCharsetNotice = " <span id=\"csv_charset_issue\">";
|
||||
$sCharsetNotice .= '<img src="../images/error.png" style="vertical-align:middle"/>';
|
||||
$sCharsetNotice .= "</span>";
|
||||
|
||||
$sTip = "<p>".htmlentities(Dict::S('UI:CSVExport:LostChars'), ENT_QUOTES, 'UTF-8')."</p>";
|
||||
$sTip .= "<p>".htmlentities(Dict::Format('UI:CSVExport:LostChars+', $sCharset), ENT_QUOTES, 'UTF-8')."</p>";
|
||||
$oPage->add_ready_script("$('#csv_charset_issue').qtip( { content: '$sTip', show: 'mouseover', hide: 'mouseout', style: { name: 'dark', tip: 'leftTop' }, position: { corner: { target: 'rightMiddle', tooltip: 'leftTop' }} } );");
|
||||
}
|
||||
else
|
||||
{
|
||||
$sCharsetNotice = '';
|
||||
}
|
||||
|
||||
*/
|
||||
$sCharsetNotice = false;
|
||||
$sHtml .= "<div>";
|
||||
$sHtml .= '<table style="width:100%" class="transparent">';
|
||||
@@ -895,21 +940,10 @@ class DisplayBlock
|
||||
case 'search':
|
||||
if (!$oPage->IsPrintableVersion())
|
||||
{
|
||||
$sStyle = (isset($aExtraParams['open']) && ($aExtraParams['open'] == 'true')) ? 'SearchDrawer' : 'SearchDrawer DrawerClosed';
|
||||
$sHtml .= "<div id=\"ds_$sId\" class=\"$sStyle\">\n";
|
||||
$oPage->add_ready_script(
|
||||
<<<EOF
|
||||
$("#dh_$sId").click( function() {
|
||||
$("#ds_$sId").slideToggle('normal', function() { $("#ds_$sId").parent().resize(); FixSearchFormsDisposition(); $("#dh_$sId").trigger('toggle_complete'); } );
|
||||
$("#dh_$sId").toggleClass('open');
|
||||
});
|
||||
EOF
|
||||
);
|
||||
$sHtml .= "<div id=\"ds_$sId\" class=\"search_box\">\n";
|
||||
$aExtraParams['currentId'] = $sId;
|
||||
$sHtml .= cmdbAbstractObject::GetSearchForm($oPage, $this->m_oSet, $aExtraParams);
|
||||
$sHtml .= "</div>\n";
|
||||
$sHtml .= "<div class=\"HRDrawer\"></div>\n";
|
||||
$sHtml .= "<div id=\"dh_$sId\" class=\"DrawerHandle\">".Dict::S('UI:SearchToggle')."</div>\n";
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -919,24 +953,27 @@ EOF
|
||||
|
||||
$sChartType = isset($aExtraParams['chart_type']) ? $aExtraParams['chart_type'] : 'pie';
|
||||
$sTitle = isset($aExtraParams['chart_title']) ? '<h1 style="text-align:center">'.htmlentities(Dict::S($aExtraParams['chart_title']), ENT_QUOTES, 'UTF-8').'</h1>' : '';
|
||||
$sHtml = "$sTitle<div style=\"height:200px;width:100%\" id=\"my_chart_$sId{$iChartCounter}\"><div style=\"height:200px;line-height:200px;vertical-align:center;text-align:center;width:100%\"><img src=\"../images/indicator.gif\"></div></div>\n";
|
||||
$sHtml = "$sTitle<div style=\"height:200px;width:100%\" class=\"dashboard_chart\" id=\"my_chart_$sId{$iChartCounter}\"><div style=\"height:200px;line-height:200px;vertical-align:center;text-align:center;width:100%\"><img src=\"../images/indicator.gif\"></div></div>\n";
|
||||
$sGroupBy = isset($aExtraParams['group_by']) ? $aExtraParams['group_by'] : '';
|
||||
$sGroupByExpr = isset($aExtraParams['group_by_expr']) ? '¶ms[group_by_expr]='.$aExtraParams['group_by_expr'] : '';
|
||||
$sFilter = $this->m_oFilter->serialize();
|
||||
$sFilter = $this->m_oFilter->serialize(false, $aQueryParams);
|
||||
$oContext = new ApplicationContext();
|
||||
$sContextParam = $oContext->GetForLink();
|
||||
$sAggregationFunction = isset($aExtraParams['aggregation_function']) ? $aExtraParams['aggregation_function'] : '';
|
||||
$sAggregationAttr = isset($aExtraParams['aggregation_attribute']) ? $aExtraParams['aggregation_attribute'] : '';
|
||||
$sLimit = isset($aExtraParams['limit']) ? $aExtraParams['limit'] : '';
|
||||
$sOrderBy = isset($aExtraParams['order_by']) ? $aExtraParams['order_by'] : '';
|
||||
$sOrderDirection = isset($aExtraParams['order_direction']) ? $aExtraParams['order_direction'] : '';
|
||||
|
||||
if (isset($aExtraParams['group_by_label']))
|
||||
{
|
||||
$sUrl = json_encode(utils::GetAbsoluteUrlAppRoot()."pages/ajax.render.php?operation=chart¶ms[group_by]=$sGroupBy{$sGroupByExpr}¶ms[group_by_label]={$aExtraParams['group_by_label']}¶ms[chart_type]=$sChartType¶ms[currentId]=$sId{$iChartCounter}&id=$sId{$iChartCounter}&filter=".urlencode($sFilter).'&'.$sContextParam);
|
||||
$sUrl = json_encode(utils::GetAbsoluteUrlAppRoot()."pages/ajax.render.php?operation=chart¶ms[group_by]=$sGroupBy{$sGroupByExpr}¶ms[group_by_label]={$aExtraParams['group_by_label']}¶ms[chart_type]=$sChartType¶ms[currentId]=$sId{$iChartCounter}¶ms[order_direction]=$sOrderDirection¶ms[order_by]=$sOrderBy¶ms[limit]=$sLimit¶ms[aggregation_function]=$sAggregationFunction¶ms[aggregation_attribute]=$sAggregationAttr&id=$sId{$iChartCounter}&filter=".rawurlencode($sFilter).'&'.$sContextParam);
|
||||
}
|
||||
else
|
||||
{
|
||||
$sUrl = json_encode(utils::GetAbsoluteUrlAppRoot()."pages/ajax.render.php?operation=chart¶ms[group_by]=$sGroupBy{$sGroupByExpr}¶ms[chart_type]=$sChartType¶ms[currentId]=$sId{$iChartCounter}&id=$sId{$iChartCounter}&filter=".urlencode($sFilter).'&'.$sContextParam);
|
||||
$sUrl = json_encode(utils::GetAbsoluteUrlAppRoot()."pages/ajax.render.php?operation=chart¶ms[group_by]=$sGroupBy{$sGroupByExpr}¶ms[chart_type]=$sChartType¶ms[currentId]=$sId{$iChartCounter}¶ms[order_direction]=$sOrderDirection¶ms[order_by]=$sOrderBy¶ms[limit]=$sLimit¶ms[aggregation_function]=$sAggregationFunction¶ms[aggregation_attribute]=$sAggregationAttr&id=$sId{$iChartCounter}&filter=".rawurlencode($sFilter).'&'.$sContextParam);
|
||||
}
|
||||
|
||||
$sType = ($sChartType == 'pie') ? 'pie' : 'bar';
|
||||
|
||||
|
||||
$oPage->add_ready_script(
|
||||
<<<EOF
|
||||
$.post($sUrl, {}, function(data) {
|
||||
@@ -953,22 +990,7 @@ EOF
|
||||
|
||||
if (isset($aExtraParams['group_by']))
|
||||
{
|
||||
if (isset($aExtraParams['group_by_label']))
|
||||
{
|
||||
$oGroupByExp = Expression::FromOQL($aExtraParams['group_by']);
|
||||
$sGroupByLabel = $aExtraParams['group_by_label'];
|
||||
}
|
||||
else
|
||||
{
|
||||
// Backward compatibility: group_by is simply a field id
|
||||
$sAlias = $this->m_oFilter->GetClassAlias();
|
||||
$oGroupByExp = new FieldExpression($aExtraParams['group_by'], $sAlias);
|
||||
$sGroupByLabel = MetaModel::GetLabel($this->m_oFilter->GetClass(), $aExtraParams['group_by']);
|
||||
}
|
||||
|
||||
$aGroupBy = array();
|
||||
$aGroupBy['grouped_by_1'] = $oGroupByExp;
|
||||
$sSql = $this->m_oFilter->MakeGroupByQuery($aQueryParams, $aGroupBy, true);
|
||||
$this->MakeGroupByQuery($aExtraParams, $oGroupByExp, $sGroupByLabel, $aGroupBy, $sAggregationFunction, $sFctVar, $sAggregationAttr, $sSql);
|
||||
$aRes = CMDBSource::QueryToArray($sSql);
|
||||
$oContext = new ApplicationContext();
|
||||
$sContextParam = $oContext->GetForLink();
|
||||
@@ -981,15 +1003,15 @@ EOF
|
||||
{
|
||||
$sValue = $aRow['grouped_by_1'];
|
||||
$sHtmlValue = $oGroupByExp->MakeValueLabel($this->m_oFilter, $sValue, $sValue);
|
||||
$aGroupBy[(int)$iRow] = (int) $aRow['_itop_count_'];
|
||||
$aGroupBy[(int)$iRow] = (int) $aRow[$sFctVar];
|
||||
$iTotalCount += $aRow['_itop_count_'];
|
||||
$aValues[] = array('label' => html_entity_decode(strip_tags($sHtmlValue), ENT_QUOTES, 'UTF-8'), 'label_html' => $sHtmlValue, 'value' => (int) $aRow['_itop_count_']);
|
||||
$aValues[] = array('label' => html_entity_decode(strip_tags($sHtmlValue), ENT_QUOTES, 'UTF-8'), 'label_html' => $sHtmlValue, 'value' => (int) $aRow[$sFctVar]);
|
||||
|
||||
// Build the search for this subset
|
||||
$oSubsetSearch = $this->m_oFilter->DeepClone();
|
||||
$oCondition = new BinaryExpression($oGroupByExp, '=', new ScalarExpression($sValue));
|
||||
$oSubsetSearch->AddConditionExpression($oCondition);
|
||||
$aURLs[] = utils::GetAbsoluteUrlAppRoot()."pages/UI.php?operation=search&format=html&filter=".urlencode($oSubsetSearch->serialize()).'&'.$sContextParam;
|
||||
$aURLs[] = utils::GetAbsoluteUrlAppRoot()."pages/UI.php?operation=search&format=html&filter=".rawurlencode($oSubsetSearch->serialize()).'&'.$sContextParam;
|
||||
}
|
||||
$sJSURLs = json_encode($aURLs);
|
||||
}
|
||||
@@ -1005,9 +1027,9 @@ EOF
|
||||
$sJSNames = json_encode($aNames);
|
||||
|
||||
$sJson = json_encode($aValues);
|
||||
$sJSCount = json_encode(Dict::S('UI:GroupBy:Count'));
|
||||
$oPage->add_ready_script(
|
||||
<<<EOF
|
||||
|
||||
var chart = c3.generate({
|
||||
bindto: d3.select('#my_chart_$sId'),
|
||||
data: {
|
||||
@@ -1055,6 +1077,12 @@ var chart = c3.generate({
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if (typeof(charts) === "undefined")
|
||||
{
|
||||
charts = [];
|
||||
}
|
||||
charts.push(chart);
|
||||
EOF
|
||||
);
|
||||
break;
|
||||
@@ -1081,6 +1109,7 @@ var chart = c3.generate({
|
||||
var aURLs = $sJSURLs;
|
||||
window.location.href= aURLs[d.index];
|
||||
},
|
||||
order: null,
|
||||
},
|
||||
legend: {
|
||||
show: true,
|
||||
@@ -1092,6 +1121,12 @@ var chart = c3.generate({
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if (typeof(charts) === "undefined")
|
||||
{
|
||||
charts = [];
|
||||
}
|
||||
charts.push(chart);
|
||||
EOF
|
||||
);
|
||||
break;
|
||||
@@ -1102,12 +1137,81 @@ EOF
|
||||
// Unsupported style, do nothing.
|
||||
$sHtml .= Dict::format('UI:Error:UnsupportedStyleOfBlock', $this->m_sStyle);
|
||||
}
|
||||
|
||||
|
||||
$bAutoReload = false;
|
||||
if (isset($aExtraParams['auto_reload']))
|
||||
{
|
||||
if ($aExtraParams['auto_reload'] === true)
|
||||
{
|
||||
// Note: does not work in the switch (case true) because a positive number evaluates to true!!!
|
||||
$aExtraParams['auto_reload'] = 'standard';
|
||||
}
|
||||
switch($aExtraParams['auto_reload'])
|
||||
{
|
||||
case 'fast':
|
||||
$bAutoReload = true;
|
||||
$iReloadInterval = MetaModel::GetConfig()->GetFastReloadInterval()*1000;
|
||||
break;
|
||||
|
||||
case 'standard':
|
||||
case 'true':
|
||||
$bAutoReload = true;
|
||||
$iReloadInterval = MetaModel::GetConfig()->GetStandardReloadInterval()*1000;
|
||||
break;
|
||||
|
||||
default:
|
||||
if (is_numeric($aExtraParams['auto_reload']) && ($aExtraParams['auto_reload'] > 0))
|
||||
{
|
||||
$bAutoReload = true;
|
||||
$iReloadInterval = max(MetaModel::GetConfig()->Get('min_reload_interval'), $aExtraParams['auto_reload'])*1000;
|
||||
}
|
||||
else
|
||||
{
|
||||
// incorrect config, ignore it
|
||||
$bAutoReload = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (($bAutoReload) && ($this->m_sStyle != 'search')) // Search form do NOT auto-reload
|
||||
{
|
||||
// Used either for asynchronous or auto_reload
|
||||
// does a json_encode twice to get a string usable as function parameter
|
||||
$sFilterBefore = $this->m_oFilter->serialize();
|
||||
$sFilter = json_encode($sFilterBefore);
|
||||
$sExtraParams = json_encode(json_encode($aExtraParams));
|
||||
|
||||
$oPage->add_script(
|
||||
<<<JS
|
||||
if (typeof window.oAutoReloadBlock == "undefined") {
|
||||
window.oAutoReloadBlock = {};
|
||||
}
|
||||
if (typeof window.oAutoReloadBlock['$sId'] != "undefined") {
|
||||
clearInterval(window.oAutoReloadBlock['$sId']);
|
||||
}
|
||||
|
||||
window.oAutoReloadBlock['$sId'] = setInterval(function() {
|
||||
ReloadBlock('$sId', '{$this->m_sStyle}', $sFilter, $sExtraParams);
|
||||
}, '$iReloadInterval');
|
||||
JS
|
||||
);
|
||||
}
|
||||
|
||||
return $sHtml;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Add a condition (restriction) to the current DBSearch on which the display block is based
|
||||
* taking into account the hierarchical keys for which the condition is based on the 'below' operator
|
||||
*
|
||||
* @param string $sFilterCode
|
||||
* @param array $condition
|
||||
* @param string $sOpCode
|
||||
* @param bool $bParseSearchString
|
||||
*
|
||||
* @throws \CoreException
|
||||
* @throws \CoreWarning
|
||||
* @throws \Exception
|
||||
*/
|
||||
protected function AddCondition($sFilterCode, $condition, $sOpCode = null, $bParseSearchString = false)
|
||||
{
|
||||
@@ -1164,7 +1268,7 @@ EOF
|
||||
// In all other cases, just add the condition directly
|
||||
if (!$bConditionAdded)
|
||||
{
|
||||
$this->m_oFilter->AddCondition($sFilterCode, $condition, null, $bParseSearchString); // Use the default 'loose' operator
|
||||
$this->m_oFilter->AddCondition($sFilterCode, $condition, null); // Use the default 'loose' operator
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1185,6 +1289,97 @@ EOF
|
||||
{
|
||||
return $this->m_oSet->Count();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $aExtraParams
|
||||
* @param $oGroupByExp
|
||||
* @param $sGroupByLabel
|
||||
* @param $aGroupBy
|
||||
* @param $sAggregationFunction
|
||||
* @param $sFctVar
|
||||
* @param $sAggregationAttr
|
||||
* @param $sSql
|
||||
*
|
||||
* @throws \Exception
|
||||
*/
|
||||
protected function MakeGroupByQuery(&$aExtraParams, &$oGroupByExp, &$sGroupByLabel, &$aGroupBy, &$sAggregationFunction, &$sFctVar, &$sAggregationAttr, &$sSql)
|
||||
{
|
||||
$sAlias = $this->m_oFilter->GetClassAlias();
|
||||
if (isset($aExtraParams['group_by_label']))
|
||||
{
|
||||
$oGroupByExp = Expression::FromOQL($aExtraParams['group_by']);
|
||||
$sGroupByLabel = $aExtraParams['group_by_label'];
|
||||
}
|
||||
else
|
||||
{
|
||||
// Backward compatibility: group_by is simply a field id
|
||||
$oGroupByExp = new FieldExpression($aExtraParams['group_by'], $sAlias);
|
||||
$sGroupByLabel = MetaModel::GetLabel($this->m_oFilter->GetClass(), $aExtraParams['group_by']);
|
||||
}
|
||||
|
||||
// Security filtering
|
||||
$aFields = $oGroupByExp->ListRequiredFields();
|
||||
foreach($aFields as $sFieldAlias)
|
||||
{
|
||||
$aMatches = array();
|
||||
if (preg_match('/^([^.]+)\\.([^.]+)$/', $sFieldAlias, $aMatches))
|
||||
{
|
||||
$sFieldClass = $this->m_oFilter->GetClassName($aMatches[1]);
|
||||
$oAttDef = MetaModel::GetAttributeDef($sFieldClass, $aMatches[2]);
|
||||
if ($oAttDef instanceof AttributeOneWayPassword)
|
||||
{
|
||||
throw new Exception('Grouping on password fields is not supported.');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$aGroupBy = array();
|
||||
$aGroupBy['grouped_by_1'] = $oGroupByExp;
|
||||
$aQueryParams = array();
|
||||
if (isset($aExtraParams['query_params']))
|
||||
{
|
||||
$aQueryParams = $aExtraParams['query_params'];
|
||||
}
|
||||
$aFunctions = array();
|
||||
$sAggregationFunction = 'count';
|
||||
$sFctVar = '_itop_count_';
|
||||
$sAggregationAttr = '';
|
||||
if (isset($aExtraParams['aggregation_function']) && !empty($aExtraParams['aggregation_attribute']))
|
||||
{
|
||||
$sAggregationFunction = $aExtraParams['aggregation_function'];
|
||||
$sAggregationAttr = $aExtraParams['aggregation_attribute'];
|
||||
$oAttrExpr = Expression::FromOQL('`'.$sAlias.'`.`'.$sAggregationAttr.'`');
|
||||
$oFctExpr = new FunctionExpression(strtoupper($sAggregationFunction), array($oAttrExpr));
|
||||
$sFctVar = '_itop_'.$sAggregationFunction.'_';
|
||||
$aFunctions = array($sFctVar => $oFctExpr);
|
||||
}
|
||||
|
||||
if (!empty($sAggregationAttr))
|
||||
{
|
||||
$sClass = $this->m_oFilter->GetClass();
|
||||
$sAggregationAttr = MetaModel::GetLabel($sClass, $sAggregationAttr);
|
||||
}
|
||||
$iLimit = 0;
|
||||
if (isset($aExtraParams['limit']))
|
||||
{
|
||||
$iLimit = intval($aExtraParams['limit']);
|
||||
}
|
||||
$aOrderBy = array();
|
||||
if (isset($aExtraParams['order_direction']) && isset($aExtraParams['order_by']))
|
||||
{
|
||||
switch ($aExtraParams['order_by'])
|
||||
{
|
||||
case 'attribute':
|
||||
$aOrderBy = array('grouped_by_1' => ($aExtraParams['order_direction'] === 'asc'));
|
||||
break;
|
||||
case 'function':
|
||||
$aOrderBy = array($sFctVar => ($aExtraParams['order_direction'] === 'asc'));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
$sSql = $this->m_oFilter->MakeGroupByQuery($aQueryParams, $aGroupBy, true, $aFunctions, $aOrderBy, $iLimit);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1259,7 +1454,7 @@ class HistoryBlock extends DisplayBlock
|
||||
default:
|
||||
if ($bTruncated)
|
||||
{
|
||||
$sFilter = $this->m_oFilter->serialize();
|
||||
$sFilter = htmlentities($this->m_oFilter->serialize(), ENT_QUOTES, 'UTF-8');
|
||||
$sHtml .= '<div id="history_container"><p>';
|
||||
$sHtml .= Dict::Format('UI:TruncatedResults', $this->iLimitCount, $oSet->Count());
|
||||
$sHtml .= ' ';
|
||||
@@ -1336,15 +1531,25 @@ EOF
|
||||
* For backward compatibility 'popup' is equivalent to 'list'...
|
||||
*/
|
||||
class MenuBlock extends DisplayBlock
|
||||
{
|
||||
{
|
||||
/**
|
||||
* Renders the "Actions" popup menu for the given set of objects
|
||||
*
|
||||
*
|
||||
* Note that the menu links containing (or ending) with a hash (#) will have their fragment
|
||||
* part (whatever is after the hash) dynamically replaced (by javascript) when the menu is
|
||||
* displayed, to correspond to the current hash/fragment in the page. This allows modifying
|
||||
* an object in with the same tab active by default as the tab that was active when selecting
|
||||
* the "Modify..." action.
|
||||
*
|
||||
* @param \WebPage $oPage
|
||||
* @param array $aExtraParams
|
||||
* @param string $sId
|
||||
*
|
||||
* @return string
|
||||
* @throws \DictExceptionMissingString
|
||||
* @throws \Exception
|
||||
* @throws \MissingQueryArgument
|
||||
* @throws \MySQLException
|
||||
*/
|
||||
public function GetRenderContent(WebPage $oPage, $aExtraParams = array(), $sId)
|
||||
{
|
||||
@@ -1363,7 +1568,6 @@ class MenuBlock extends DisplayBlock
|
||||
$oReflectionClass = new ReflectionClass($sClass);
|
||||
$oSet = new CMDBObjectSet($this->m_oFilter);
|
||||
$sFilter = $this->m_oFilter->serialize();
|
||||
$sFilterDesc = $this->m_oFilter->ToOql(true);
|
||||
$aActions = array();
|
||||
$sUIPage = cmdbAbstractObject::ComputeStandardUIPage($sClass);
|
||||
$sRootUrl = utils::GetAbsoluteUrlAppRoot();
|
||||
@@ -1482,6 +1686,7 @@ class MenuBlock extends DisplayBlock
|
||||
if ($bLocked && $bRawModifiedAllowed)
|
||||
{
|
||||
// Add a special menu to kill the lock, but only to allowed users who can also modify this object
|
||||
/** @var array $aAllowedProfiles */
|
||||
$aAllowedProfiles = MetaModel::GetConfig()->Get('concurrent_lock_override_profiles');
|
||||
$bCanKill = false;
|
||||
|
||||
@@ -1527,6 +1732,7 @@ class MenuBlock extends DisplayBlock
|
||||
*/
|
||||
}
|
||||
$this->AddMenuSeparator($aActions);
|
||||
/** @var \iApplicationUIExtension $oExtensionInstance */
|
||||
foreach (MetaModel::EnumPlugins('iApplicationUIExtension') as $oExtensionInstance)
|
||||
{
|
||||
$oSet->Rewind();
|
||||
@@ -1550,7 +1756,6 @@ class MenuBlock extends DisplayBlock
|
||||
$sTargetAttr = $aExtraParams['target_attr'];
|
||||
$oAttDef = MetaModel::GetAttributeDef($sClass, $sTargetAttr);
|
||||
$sTargetClass = $oAttDef->GetTargetClass();
|
||||
$bIsDeleteAllowed = UserRights::IsActionAllowed($sClass, UR_ACTION_DELETE, $oSet);
|
||||
if ($bIsModifyAllowed) { $aActions['UI:Menu:Add'] = array ('label' => Dict::S('UI:Menu:Add'), 'url' => "{$sRootUrl}pages/$sUIPage?operation=modify_links&class=$sClass&link_attr=".$aExtraParams['link_attr']."&target_class=$sTargetClass&id=$id&addObjects=true{$sContext}") + $aActionParams; }
|
||||
if ($bIsBulkModifyAllowed) { $aActions['UI:Menu:Manage'] = array ('label' => Dict::S('UI:Menu:Manage'), 'url' => "{$sRootUrl}pages/$sUIPage?operation=modify_links&class=$sClass&link_attr=".$aExtraParams['link_attr']."&target_class=$sTargetClass&id=$id{$sContext}") + $aActionParams; }
|
||||
//if ($bIsBulkDeleteAllowed) { $aActions[] = array ('label' => 'Remove All...', 'url' => "#") + $aActionParams; }
|
||||
@@ -1567,7 +1772,7 @@ class MenuBlock extends DisplayBlock
|
||||
// Do not perform time consuming computations if there are too may objects in the list
|
||||
$iLimit = MetaModel::GetConfig()->Get('complex_actions_limit');
|
||||
|
||||
if ((count($aStates) > 0) && (($iLimit == 0) || ($oSet->Count() < $iLimit)))
|
||||
if ((count($aStates) > 0) && (($iLimit == 0) || ($oSet->CountWithLimit($iLimit + 1) < $iLimit)))
|
||||
{
|
||||
// Life cycle actions may be available... if all objects are in the same state
|
||||
//
|
||||
@@ -1623,6 +1828,7 @@ class MenuBlock extends DisplayBlock
|
||||
}
|
||||
|
||||
$this->AddMenuSeparator($aActions);
|
||||
/** @var \iApplicationUIExtension $oExtensionInstance */
|
||||
foreach (MetaModel::EnumPlugins('iApplicationUIExtension') as $oExtensionInstance)
|
||||
{
|
||||
$oSet->Rewind();
|
||||
@@ -1641,7 +1847,8 @@ class MenuBlock extends DisplayBlock
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$param = null;
|
||||
$iMenuId = null;
|
||||
// New extensions based on iPopupMenuItem interface
|
||||
switch($this->m_sStyle)
|
||||
{
|
||||
@@ -1674,11 +1881,7 @@ class MenuBlock extends DisplayBlock
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$aShortcutActions = array();
|
||||
}
|
||||
|
||||
|
||||
if (!$oPage->IsPrintableVersion())
|
||||
{
|
||||
if (count($aFavoriteActions) > 0)
|
||||
@@ -1689,12 +1892,27 @@ class MenuBlock extends DisplayBlock
|
||||
{
|
||||
$sHtml .= "<div class=\"itop_popup actions_menu\"><ul>\n<li>".Dict::S('UI:Menu:Actions')."\n<ul>\n";
|
||||
}
|
||||
|
||||
|
||||
$sHtml .= $oPage->RenderPopupMenuItems($aActions, $aFavoriteActions);
|
||||
|
||||
if ($this->m_sStyle == 'details')
|
||||
{
|
||||
$sSearchAction = "window.location=\"{$sRootUrl}pages/UI.php?operation=search_form&do_search=0&class=$sClass{$sContext}\"";
|
||||
$sHtml .= "<div class=\"actions_button icon_actions_button\" title=\"".htmlentities(Dict::Format('UI:SearchFor_Class', MetaModel::GetName($sClass)), ENT_QUOTES, 'UTF-8')."\"><span class=\"search-button fa fa-search\" onclick='$sSearchAction'></span></div>";
|
||||
}
|
||||
|
||||
|
||||
if (empty($sRefreshAction) && $this->m_sStyle == 'list')
|
||||
{
|
||||
//for the detail page this var is defined way beyond this line
|
||||
$sRefreshAction = "window.location.reload();";
|
||||
}
|
||||
if (!$oPage->IsPrintableVersion() && ($sRefreshAction!=''))
|
||||
{
|
||||
$sHtml .= "<div class=\"actions_button\" title=\"".htmlentities(Dict::S('UI:Button:Refresh'), ENT_QUOTES, 'UTF-8')."\"><span class=\"refresh-button\" onclick=\"$sRefreshAction\"></span></div>";
|
||||
$sHtml .= "<div class=\"actions_button icon_actions_button\" title=\"".htmlentities(Dict::S('UI:Button:Refresh'), ENT_QUOTES, 'UTF-8')."\"><span class=\"refresh-button fa fa-refresh\" onclick=\"$sRefreshAction\"></span></div>";
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
static $bPopupScript = false;
|
||||
@@ -1709,7 +1927,7 @@ class MenuBlock extends DisplayBlock
|
||||
|
||||
/**
|
||||
* Appends a menu separator to the current list of actions
|
||||
* @param Hash $aActions The current actions list
|
||||
* @param array $aActions The current actions list
|
||||
* @return void
|
||||
*/
|
||||
protected function AddMenuSeparator(&$aActions)
|
||||
|
||||
@@ -462,7 +462,7 @@ class ExcelExporter
|
||||
$this->aAuthorizedClasses = array();
|
||||
foreach($aClasses as $sAlias => $sClassName)
|
||||
{
|
||||
if (UserRights::IsActionAllowed($sClassName, UR_ACTION_READ, $oSet) && (UR_ALLOWED_YES || UR_ALLOWED_DEPENDS))
|
||||
if (UserRights::IsActionAllowed($sClassName, UR_ACTION_READ, $oSet) != UR_ALLOWED_NO)
|
||||
{
|
||||
$this->aAuthorizedClasses[$sAlias] = $sClassName;
|
||||
}
|
||||
|
||||
@@ -203,7 +203,7 @@ class DesignerForm
|
||||
|
||||
public function RenderAsPropertySheet($oP, $bReturnHTML = false, $sNotifyParentSelector = null)
|
||||
{
|
||||
$sReturn = '';
|
||||
$sReturn = '';
|
||||
$sActionUrl = addslashes($this->sSubmitTo);
|
||||
$sJSSubmitParams = json_encode($this->aSubmitParams);
|
||||
$sFormId = $this->GetFormId();
|
||||
@@ -360,6 +360,7 @@ EOF
|
||||
<<<EOF
|
||||
$('#$sDialogId').dialog({
|
||||
height: 'auto',
|
||||
maxHeight: $(window).height() - 8,
|
||||
width: $iDialogWidth,
|
||||
modal: true,
|
||||
autoOpen: $sAutoOpen,
|
||||
@@ -377,9 +378,9 @@ $('#$sDialogId').dialog({
|
||||
}
|
||||
}
|
||||
} },
|
||||
{ text: "$sCancelButtonLabel", click: function() { KillAllMenus(); $(this).dialog( "close" ); $(this).remove(); } },
|
||||
{ text: "$sCancelButtonLabel", click: function() { $(this).dialog( "close" ); $(this).remove(); } },
|
||||
],
|
||||
close: function() { KillAllMenus(); $(this).remove(); }
|
||||
close: function() { $(this).remove(); }
|
||||
});
|
||||
var oForm = $('#$sDialogId form');
|
||||
var sFormId = oForm.attr('id');
|
||||
@@ -681,6 +682,7 @@ class DesignerFormField
|
||||
protected $sLabel;
|
||||
protected $sCode;
|
||||
protected $defaultValue;
|
||||
/** @var \DesignerForm $oForm */
|
||||
protected $oForm;
|
||||
protected $bMandatory;
|
||||
protected $bReadOnly;
|
||||
@@ -706,8 +708,11 @@ class DesignerFormField
|
||||
{
|
||||
return $this->sCode;
|
||||
}
|
||||
|
||||
public function SetForm($oForm)
|
||||
|
||||
/**
|
||||
* @param \DesignerForm $oForm
|
||||
*/
|
||||
public function SetForm(\DesignerForm $oForm)
|
||||
{
|
||||
$this->oForm = $oForm;
|
||||
}
|
||||
@@ -1524,7 +1529,6 @@ class DesignerFormSelectorField extends DesignerFormField
|
||||
|
||||
public function AddSubForm($oSubForm, $sLabel, $sValue)
|
||||
{
|
||||
$idx = count($this->aSubForms);
|
||||
$this->aSubForms[] = array('form' => $oSubForm, 'label' => $sLabel, 'value' => $sValue);
|
||||
if ($sValue == $this->defaultRealValue)
|
||||
{
|
||||
@@ -1538,7 +1542,7 @@ class DesignerFormSelectorField extends DesignerFormField
|
||||
$sId = $this->oForm->GetFieldId($this->sCode);
|
||||
$sName = $this->oForm->GetFieldName($this->sCode);
|
||||
$sReadOnly = $this->IsReadOnly() ? 'disabled="disabled"' : '';
|
||||
|
||||
|
||||
$this->aCSSClasses[] = 'formSelector';
|
||||
|
||||
$sCSSClasses = '';
|
||||
@@ -1554,8 +1558,6 @@ class DesignerFormSelectorField extends DesignerFormField
|
||||
|
||||
if ($this->IsReadOnly())
|
||||
{
|
||||
$aSelected = array();
|
||||
$aHiddenValues = array();
|
||||
$sDisplayValue = '';
|
||||
$sHiddenValue = '';
|
||||
foreach($this->aSubForms as $iKey => $aFormData)
|
||||
@@ -1571,8 +1573,6 @@ class DesignerFormSelectorField extends DesignerFormField
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
|
||||
$sHtml = "<select $sCSSClasses id=\"$sId\" name=\"$sName\" $sReadOnly>";
|
||||
foreach($this->aSubForms as $iKey => $aFormData)
|
||||
{
|
||||
@@ -1588,7 +1588,6 @@ class DesignerFormSelectorField extends DesignerFormField
|
||||
{
|
||||
$sHtml .= '</td><td class="prop_icon prop_apply"><span title="Apply" class="ui-icon ui-icon-circle-check"/></td><td class="prop_icon prop_cancel"><span title="Revert" class="ui-icon ui-icon-circle-close"/></td></tr>';
|
||||
}
|
||||
|
||||
foreach($this->aSubForms as $sKey => $aFormData)
|
||||
{
|
||||
$sId = $this->oForm->GetFieldId($this->sCode);
|
||||
@@ -1614,25 +1613,7 @@ class DesignerFormSelectorField extends DesignerFormField
|
||||
$oSubForm->SetHierarchyPath($sPath);
|
||||
|
||||
$oSubForm->SetDisplayed($sKey == $this->defaultValue);
|
||||
$sState = ($sKey == $this->defaultValue) ? 'visible' : 'hidden';
|
||||
//$sHtml .= "</tbody><tbody data-selector=\"$sSelector\" data-path=\"$sPath\" data-state=\"$sState\" $sStyle>";
|
||||
$sHtml .= $oSubForm->RenderAsPropertySheet($oP, true);
|
||||
|
||||
$sState = $this->oForm->IsDisplayed() ? 'visible' : 'hidden';
|
||||
$sParentStyle = '';
|
||||
if ($oParent = $this->oForm->GetParentForm())
|
||||
{
|
||||
$sParentStyle = ($oParent->IsDisplayed()) ? '' : 'style="display:none"';
|
||||
$sParentSelector = $oParent->GetHierarchyParent();
|
||||
$sParentPath = $oParent->GetHierarchyPath();
|
||||
}
|
||||
else
|
||||
{
|
||||
$sParentSelector = '';
|
||||
$sParentPath = '';
|
||||
}
|
||||
|
||||
//$sHtml .= "</tbody><tbody data-selector=\"$sParentSelector\" data-path=\"$sParentPath\" data-state=\"$sState\" $sParentStyle>";
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1680,7 +1661,6 @@ EOF
|
||||
if ($selectedValue == $aFormData['value'])
|
||||
{
|
||||
$this->defaultValue =$iKey;
|
||||
$aDefaultValues = $this->oForm->GetDefaultValues();
|
||||
$oSubForm = $aFormData['form'];
|
||||
$oSubForm->SetDefaultValues($aAllDefaultValues);
|
||||
}
|
||||
|
||||
@@ -1,69 +1,69 @@
|
||||
<?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/>
|
||||
|
||||
|
||||
/**
|
||||
* Persistent class InputOutputTask
|
||||
*
|
||||
* @copyright Copyright (C) 2010-2012 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
require_once(APPROOT.'/application/cmdbabstract.class.inc.php');
|
||||
|
||||
/**
|
||||
* This class manages the input/output tasks
|
||||
* for synchronizing information with external data sources
|
||||
*/
|
||||
class InputOutputTask extends cmdbAbstractObject
|
||||
{
|
||||
public static function Init()
|
||||
{
|
||||
$aParams = array
|
||||
(
|
||||
"category" => "application",
|
||||
"key_type" => "autoincrement",
|
||||
"name_attcode" => "name",
|
||||
"state_attcode" => "",
|
||||
"reconc_keys" => array(),
|
||||
"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())));
|
||||
MetaModel::Init_AddAttribute(new AttributeString("description", array("allowed_values"=>null, "sql"=>"description", "default_value"=>"", "is_null_allowed"=>true, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeEnum("category", array("allowed_values"=>new ValueSetEnum('Input, Ouput'), "sql"=>"category", "default_value"=>"Input", "is_null_allowed"=>false, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeEnum("source_type", array("allowed_values"=>new ValueSetEnum('File, Database, Web Service'), "sql"=>"source_type", "default_value"=>"File", "is_null_allowed"=>false, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeEnum("source_subtype", array("allowed_values"=>new ValueSetEnum('Oracle, MySQL, Postgress, MSSQL, SOAP, HTTP-Get, HTTP-Post, XML/RPC, CSV, XML, Excel'), "sql"=>"source_subtype", "default_value"=>"CSV", "is_null_allowed"=>false, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeString("source_path", array("allowed_values"=>null, "sql"=>"source_path", "default_value"=>"", "is_null_allowed"=>false, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeClass("objects_class", array("class_category"=>"", "more_values"=>"", "sql"=>"objects_class", "default_value"=>null, "is_null_allowed"=>true, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeEnum("test_mode", array("allowed_values"=>new ValueSetEnum('Yes,No'), "sql"=>"test_mode", "default_value"=>'No', "is_null_allowed"=>false, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeEnum("verbose_mode", array("allowed_values"=>new ValueSetEnum('Yes,No'), "sql"=>"verbose_mode", "default_value" => 'No', "is_null_allowed"=>false, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeEnum("options", array("allowed_values"=>new ValueSetEnum('Full, Update Only, Creation Only'), "sql"=>"options", "default_value"=> 'Full', "is_null_allowed"=>true, "depends_on"=>array())));
|
||||
|
||||
// Display lists
|
||||
MetaModel::Init_SetZListItems('details', array('name', 'description', 'category', 'objects_class', 'source_type', 'source_subtype', 'source_path' , 'options', 'test_mode', 'verbose_mode')); // Attributes to be displayed for the complete details
|
||||
MetaModel::Init_SetZListItems('list', array('description', 'category', 'objects_class', 'source_type', 'source_subtype', 'options')); // Attributes to be displayed for a list
|
||||
// Search criteria
|
||||
MetaModel::Init_SetZListItems('standard_search', array('name', 'category', 'objects_class', 'source_type', 'source_subtype')); // Criteria of the std search form
|
||||
MetaModel::Init_SetZListItems('advanced_search', array('name', 'description', 'category', 'objects_class', 'source_type', 'source_subtype')); // Criteria of the advanced search form
|
||||
}
|
||||
}
|
||||
?>
|
||||
<?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/>
|
||||
|
||||
|
||||
/**
|
||||
* Persistent class InputOutputTask
|
||||
*
|
||||
* @copyright Copyright (C) 2010-2012 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
require_once(APPROOT.'/application/cmdbabstract.class.inc.php');
|
||||
|
||||
/**
|
||||
* This class manages the input/output tasks
|
||||
* for synchronizing information with external data sources
|
||||
*/
|
||||
class InputOutputTask extends cmdbAbstractObject
|
||||
{
|
||||
public static function Init()
|
||||
{
|
||||
$aParams = array
|
||||
(
|
||||
"category" => "application",
|
||||
"key_type" => "autoincrement",
|
||||
"name_attcode" => "name",
|
||||
"state_attcode" => "",
|
||||
"reconc_keys" => array(),
|
||||
"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())));
|
||||
MetaModel::Init_AddAttribute(new AttributeString("description", array("allowed_values"=>null, "sql"=>"description", "default_value"=>"", "is_null_allowed"=>true, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeEnum("category", array("allowed_values"=>new ValueSetEnum('Input, Ouput'), "sql"=>"category", "default_value"=>"Input", "is_null_allowed"=>false, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeEnum("source_type", array("allowed_values"=>new ValueSetEnum('File, Database, Web Service'), "sql"=>"source_type", "default_value"=>"File", "is_null_allowed"=>false, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeEnum("source_subtype", array("allowed_values"=>new ValueSetEnum('Oracle, MySQL, Postgress, MSSQL, SOAP, HTTP-Get, HTTP-Post, XML/RPC, CSV, XML, Excel'), "sql"=>"source_subtype", "default_value"=>"CSV", "is_null_allowed"=>false, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeString("source_path", array("allowed_values"=>null, "sql"=>"source_path", "default_value"=>"", "is_null_allowed"=>false, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeClass("objects_class", array("class_category"=>"", "more_values"=>"", "sql"=>"objects_class", "default_value"=>null, "is_null_allowed"=>true, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeEnum("test_mode", array("allowed_values"=>new ValueSetEnum('Yes,No'), "sql"=>"test_mode", "default_value"=>'No', "is_null_allowed"=>false, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeEnum("verbose_mode", array("allowed_values"=>new ValueSetEnum('Yes,No'), "sql"=>"verbose_mode", "default_value" => 'No', "is_null_allowed"=>false, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeEnum("options", array("allowed_values"=>new ValueSetEnum('Full, Update Only, Creation Only'), "sql"=>"options", "default_value"=> 'Full', "is_null_allowed"=>true, "depends_on"=>array())));
|
||||
|
||||
// Display lists
|
||||
MetaModel::Init_SetZListItems('details', array('name', 'description', 'category', 'objects_class', 'source_type', 'source_subtype', 'source_path' , 'options', 'test_mode', 'verbose_mode')); // Attributes to be displayed for the complete details
|
||||
MetaModel::Init_SetZListItems('list', array('description', 'category', 'objects_class', 'source_type', 'source_subtype', 'options')); // Attributes to be displayed for a list
|
||||
// Search criteria
|
||||
MetaModel::Init_SetZListItems('standard_search', array('name', 'category', 'objects_class', 'source_type', 'source_subtype')); // Criteria of the std search form
|
||||
MetaModel::Init_SetZListItems('advanced_search', array('name', 'description', 'category', 'objects_class', 'source_type', 'source_subtype')); // Criteria of the advanced search form
|
||||
}
|
||||
}
|
||||
?>
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,57 +1,57 @@
|
||||
<?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
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
?>
|
||||
<?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
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
?>
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
159
application/newsroomprovider.class.inc.php
Normal file
159
application/newsroomprovider.class.inc.php
Normal file
@@ -0,0 +1,159 @@
|
||||
<?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/>
|
||||
|
||||
/**
|
||||
* A provider for messages to be displayed in the iTop Newsroom
|
||||
*/
|
||||
interface iNewsroomProvider
|
||||
{
|
||||
/**
|
||||
* Inject the current configuration in the provider
|
||||
* @param Config $oConfig
|
||||
* @return void
|
||||
*/
|
||||
public function SetConfig(Config $oConfig);
|
||||
|
||||
/**
|
||||
* Tells if this provider is enabled for the given user
|
||||
* @param User $oUser The user for who to check if the provider is applicable.
|
||||
* return bool
|
||||
*/
|
||||
public function IsApplicable(User $oUser = null);
|
||||
|
||||
/**
|
||||
* The human readable (localized) label for this provider
|
||||
* @return string
|
||||
*/
|
||||
public function GetLabel();
|
||||
|
||||
/**
|
||||
* The URL to query (from the browser, using jsonp) to fetch all unread messages
|
||||
* @return string
|
||||
*/
|
||||
public function GetFetchURL();
|
||||
|
||||
/**
|
||||
* The URL to navigate to in order to display all messages
|
||||
* @return string
|
||||
*/
|
||||
public function GetViewAllURL();
|
||||
|
||||
/**
|
||||
* The URL to query(from the browser, using jsonp) to mark all unread messages as read
|
||||
* @return string
|
||||
*/
|
||||
public function GetMarkAllAsReadURL();
|
||||
|
||||
/**
|
||||
* Return the URL to configure the preferences for this provider or null is there is nothing to configure
|
||||
* @return string|null
|
||||
*/
|
||||
public function GetPreferencesUrl();
|
||||
|
||||
/**
|
||||
* Return an array key => value to be replaced in URL of the messages
|
||||
* Example: '%itop_root%' => utils::GetAbsoluteUrlAppRoot();
|
||||
* @return string[]
|
||||
*/
|
||||
public function GetPlaceholders();
|
||||
|
||||
/**
|
||||
* The duration between to refreshes of the cache (in seconds)
|
||||
* @return int
|
||||
*/
|
||||
public function GetTTL();
|
||||
}
|
||||
|
||||
/**
|
||||
* Basic implementation of a Newsroom provider, to be overloaded by your own provider implementation
|
||||
*
|
||||
*/
|
||||
abstract class NewsroomProviderBase implements iNewsroomProvider
|
||||
{
|
||||
/**
|
||||
* The current configuration parameters
|
||||
* @var Config
|
||||
*/
|
||||
protected $oConfig;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->oConfig = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
* @see iNewsroomProvider::SetConfig()
|
||||
*/
|
||||
public function SetConfig(Config $oConfig)
|
||||
{
|
||||
$this->oConfig = $oConfig;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
* @see iNewsroomProvider::GetPreferencesUrl()
|
||||
*/
|
||||
public function GetPreferencesUrl()
|
||||
{
|
||||
return null; // No preferences
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
* @see iNewsroomProvider::GetLabel()
|
||||
*/
|
||||
public abstract function GetLabel();
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
* @see iNewsroomProvider::GetFetchURL()
|
||||
*/
|
||||
public abstract function GetFetchURL();
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
* @see iNewsroomProvider::GetMarkAllURL()
|
||||
*/
|
||||
public abstract function GetMarkAllAsReadURL();
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
* @see iNewsroomProvider::GetViewAllURL()
|
||||
*/
|
||||
public abstract function GetViewAllURL();
|
||||
|
||||
public function IsApplicable(User $oUser = null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
* @see iNewsroomProvider::GetPlaceholders()
|
||||
*/
|
||||
public function GetPlaceholders()
|
||||
{
|
||||
return array(); // By default, empty set of placeholders
|
||||
}
|
||||
|
||||
public function GetTTL()
|
||||
{
|
||||
return 10*60; // Refresh every 10 minutes
|
||||
}
|
||||
}
|
||||
@@ -1,231 +1,259 @@
|
||||
<?php
|
||||
// Copyright (C) 2010-2016 Combodo SARL
|
||||
//
|
||||
// This file is part of iTop.
|
||||
//
|
||||
// iTop is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// iTop is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with iTop. If not, see <http://www.gnu.org/licenses/>
|
||||
|
||||
|
||||
/**
|
||||
* Class NiceWebPage
|
||||
*
|
||||
* @copyright Copyright (C) 2010-2016 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
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-1.10.0.min.js');
|
||||
$this->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/jquery-migrate-1.2.1.min.js'); // Needed since many other plugins still rely on oldies like $.browser
|
||||
$this->add_linked_stylesheet(utils::GetAbsoluteUrlAppRoot().'css/ui-lightness/jquery-ui-1.10.3.custom.min.css');
|
||||
$this->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/jquery-ui-1.10.3.custom.min.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/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_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->add_saas("css/light-grey.scss");
|
||||
|
||||
$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, 'UTF-8')."</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();
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
<?php
|
||||
// Copyright (C) 2010-2016 Combodo SARL
|
||||
//
|
||||
// This file is part of iTop.
|
||||
//
|
||||
// iTop is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// iTop is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with iTop. If not, see <http://www.gnu.org/licenses/>
|
||||
|
||||
|
||||
/**
|
||||
* Class NiceWebPage
|
||||
*
|
||||
* @copyright Copyright (C) 2010-2016 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
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-3.3.1.min.js');
|
||||
if(utils::IsDevelopmentEnvironment()) // Needed since many other plugins still rely on oldies like $.browser
|
||||
{
|
||||
$this->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/jquery-migrate-3.0.1.dev.js');
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/jquery-migrate-3.0.1.prod.min.js');
|
||||
}
|
||||
$this->add_linked_stylesheet(utils::GetAbsoluteUrlAppRoot().'css/ui-lightness/jquery-ui-1.11.4.custom.css');
|
||||
$this->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/jquery-ui-1.11.4.custom.min.js');
|
||||
$this->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/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_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->add_saas("css/light-grey.scss");
|
||||
|
||||
$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, 'UTF-8')."</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();
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
|
||||
@@ -35,7 +35,7 @@ class iTopPDF extends TCPDF
|
||||
|
||||
// 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, 'Page '.$this->page, 0, 'R', false, 0 /* $ln */, '', '', true, 0, false, true, 15, 'M' /* $valign */);
|
||||
$this->MultiCell($iPageNumberWidth, 15, Dict::Format('Core:BulkExport:PDF:PageNumber' ,$this->page), 0, 'R', false, 0 /* $ln */, '', '', true, 0, false, true, 15, 'M' /* $valign */);
|
||||
|
||||
// Branding logo
|
||||
$sBrandingIcon = APPROOT.'images/itop-logo.png';
|
||||
|
||||
@@ -807,7 +807,7 @@ EOF
|
||||
*/
|
||||
public function DoUpdateObjectFromPostedForm(DBObject $oObj, $aAttList = null)
|
||||
{
|
||||
$sTransactionId = utils::ReadPostedParam('transaction_id', '');
|
||||
$sTransactionId = utils::ReadPostedParam('transaction_id', '', 'transaction_id');
|
||||
if (!utils::IsTransactionValid($sTransactionId))
|
||||
{
|
||||
throw new TransactionException();
|
||||
@@ -952,7 +952,7 @@ EOF
|
||||
$sTransactionId = utils::GetNewTransactionId();
|
||||
$this->SetTransactionId($sTransactionId);
|
||||
$this->add("<input type=\"hidden\" id=\"transaction_id\" name=\"transaction_id\" value=\"$sTransactionId\">\n");
|
||||
$this->add_ready_script("$(window).unload(function() { OnUnload('$sTransactionId') } );\n");
|
||||
$this->add_ready_script("$(window).on('unload', function() { OnUnload('$sTransactionId') } );\n");
|
||||
}
|
||||
|
||||
public function WizardFormButtons($iButtonFlags)
|
||||
|
||||
@@ -1,141 +1,178 @@
|
||||
<?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/>
|
||||
|
||||
|
||||
/**
|
||||
* Persistent class Event and derived
|
||||
* Application internal events
|
||||
* There is also a file log
|
||||
*
|
||||
* @copyright Copyright (C) 2010-2015 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
abstract class Query extends cmdbAbstractObject
|
||||
{
|
||||
public static function Init()
|
||||
{
|
||||
$aParams = array
|
||||
(
|
||||
"category" => "core/cmdb,view_in_gui,application",
|
||||
"key_type" => "autoincrement",
|
||||
"name_attcode" => "name",
|
||||
"state_attcode" => "",
|
||||
"reconc_keys" => array(),
|
||||
"db_table" => "priv_query",
|
||||
"db_key_field" => "id",
|
||||
"db_finalclass_field" => "realclass",
|
||||
"display_template" => "",
|
||||
);
|
||||
MetaModel::Init_Params($aParams);
|
||||
//MetaModel::Init_InheritAttributes();
|
||||
MetaModel::Init_AddAttribute(new AttributeString("name", array("allowed_values"=>null, "sql"=>"name", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeText("description", array("allowed_values"=>null, "sql"=>"description", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array())));
|
||||
|
||||
MetaModel::Init_AddAttribute(new AttributeText("fields", array("allowed_values"=>null, "sql"=>"fields", "default_value"=>null, "is_null_allowed"=>true, "depends_on"=>array())));
|
||||
|
||||
// Display lists
|
||||
MetaModel::Init_SetZListItems('details', array('name', 'description', 'fields')); // Attributes to be displayed for the complete details
|
||||
MetaModel::Init_SetZListItems('list', array('description')); // Attributes to be displayed for a list
|
||||
// Search criteria
|
||||
MetaModel::Init_SetZListItems('standard_search', array('name', 'description', 'fields')); // Criteria of the std search form
|
||||
// MetaModel::Init_SetZListItems('advanced_search', array('name')); // Criteria of the advanced search form
|
||||
}
|
||||
}
|
||||
|
||||
class QueryOQL extends Query
|
||||
{
|
||||
public static function Init()
|
||||
{
|
||||
$aParams = array
|
||||
(
|
||||
"category" => "core/cmdb,view_in_gui,application",
|
||||
"key_type" => "autoincrement",
|
||||
"name_attcode" => "name",
|
||||
"state_attcode" => "",
|
||||
"reconc_keys" => array(),
|
||||
"db_table" => "priv_query_oql",
|
||||
"db_key_field" => "id",
|
||||
"db_finalclass_field" => "",
|
||||
"display_template" => "",
|
||||
);
|
||||
MetaModel::Init_Params($aParams);
|
||||
MetaModel::Init_InheritAttributes();
|
||||
MetaModel::Init_AddAttribute(new AttributeOQL("oql", array("allowed_values"=>null, "sql"=>"oql", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array())));
|
||||
|
||||
// Display lists
|
||||
MetaModel::Init_SetZListItems('details', array('name', 'description', 'oql', 'fields')); // Attributes to be displayed for the complete details
|
||||
MetaModel::Init_SetZListItems('list', array('description')); // Attributes to be displayed for a list
|
||||
// Search criteria
|
||||
MetaModel::Init_SetZListItems('standard_search', array('name', 'description', 'fields', 'oql')); // Criteria of the std search form
|
||||
// MetaModel::Init_SetZListItems('advanced_search', array('name')); // Criteria of the advanced search form
|
||||
}
|
||||
|
||||
function DisplayBareProperties(WebPage $oPage, $bEditMode = false, $sPrefix = '', $aExtraParams = array())
|
||||
{
|
||||
$aFieldsMap = parent::DisplayBareProperties($oPage, $bEditMode, $sPrefix, $aExtraParams);
|
||||
|
||||
if (!$bEditMode)
|
||||
{
|
||||
$sFields = trim($this->Get('fields'));
|
||||
$bExportV1Recommended = ($sFields == '');
|
||||
if ($bExportV1Recommended)
|
||||
{
|
||||
$oFieldAttDef = MetaModel::GetAttributeDef('QueryOQL', 'fields');
|
||||
$oPage->add('<div class="message message_error" style="padding-left: 30px;"><div style="padding: 10px;">'.Dict::Format('UI:Query:UrlV1', $oFieldAttDef->GetLabel()).'</div></div>');
|
||||
$sUrl = utils::GetAbsoluteUrlAppRoot().'webservices/export.php?format=spreadsheet&login_mode=basic&query='.$this->GetKey();
|
||||
}
|
||||
else
|
||||
{
|
||||
$sUrl = utils::GetAbsoluteUrlAppRoot().'webservices/export-v2.php?format=spreadsheet&login_mode=basic&date_format='.urlencode((string)AttributeDateTime::GetFormat()).'&query='.$this->GetKey();
|
||||
}
|
||||
$sOql = $this->Get('oql');
|
||||
$sMessage = null;
|
||||
try
|
||||
{
|
||||
$oSearch = DBObjectSearch::FromOQL($sOql);
|
||||
$aParameters = $oSearch->GetQueryParams();
|
||||
foreach($aParameters as $sParam => $val)
|
||||
{
|
||||
$sUrl .= '&arg_'.$sParam.'=["'.$sParam.'"]';
|
||||
}
|
||||
|
||||
$oPage->p(Dict::S('UI:Query:UrlForExcel').':<br/><textarea cols="80" rows="3" READONLY>'.$sUrl.'</textarea>');
|
||||
|
||||
if (count($aParameters) == 0)
|
||||
{
|
||||
$oBlock = new DisplayBlock($oSearch, 'list');
|
||||
$aExtraParams = array(
|
||||
//'menu' => $sShowMenu,
|
||||
'table_id' => 'query_preview_'.$this->getKey(),
|
||||
);
|
||||
$sBlockId = 'block_query_preview_'.$this->GetKey(); // make a unique id (edition occuring in the same DOM)
|
||||
$oBlock->Display($oPage, $sBlockId, $aExtraParams);
|
||||
}
|
||||
}
|
||||
catch (OQLException $e)
|
||||
{
|
||||
$sMessage = '<div class="message message_error" style="padding-left: 30px;"><div style="padding: 10px;">'.Dict::Format('UI:RunQuery:Error', $e->getHtmlDesc()).'</div></div>';
|
||||
$oPage->p($sMessage);
|
||||
}
|
||||
}
|
||||
return $aFieldsMap;
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
<?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/>
|
||||
|
||||
|
||||
/**
|
||||
* Persistent class Event and derived
|
||||
* Application internal events
|
||||
* There is also a file log
|
||||
*
|
||||
* @copyright Copyright (C) 2010-2015 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
abstract class Query extends cmdbAbstractObject
|
||||
{
|
||||
public static function Init()
|
||||
{
|
||||
$aParams = array
|
||||
(
|
||||
"category" => "core/cmdb,view_in_gui,application,grant_by_profile",
|
||||
"key_type" => "autoincrement",
|
||||
"name_attcode" => "name",
|
||||
"state_attcode" => "",
|
||||
"reconc_keys" => array(),
|
||||
"db_table" => "priv_query",
|
||||
"db_key_field" => "id",
|
||||
"db_finalclass_field" => "realclass",
|
||||
"display_template" => "",
|
||||
);
|
||||
MetaModel::Init_Params($aParams);
|
||||
//MetaModel::Init_InheritAttributes();
|
||||
MetaModel::Init_AddAttribute(new AttributeString("name", array("allowed_values"=>null, "sql"=>"name", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeText("description", array("allowed_values"=>null, "sql"=>"description", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array())));
|
||||
|
||||
|
||||
// Display lists
|
||||
MetaModel::Init_SetZListItems('details', array('name', 'description')); // Attributes to be displayed for the complete details
|
||||
MetaModel::Init_SetZListItems('list', array('description')); // Attributes to be displayed for a list
|
||||
// Search criteria
|
||||
MetaModel::Init_SetZListItems('standard_search', array('name', 'description')); // Criteria of the std search form
|
||||
MetaModel::Init_SetZListItems('default_search', array('name', 'description')); // Criteria of the default search form
|
||||
// MetaModel::Init_SetZListItems('advanced_search', array('name')); // Criteria of the advanced search form
|
||||
}
|
||||
}
|
||||
|
||||
class QueryOQL extends Query
|
||||
{
|
||||
public static function Init()
|
||||
{
|
||||
$aParams = array
|
||||
(
|
||||
"category" => "core/cmdb,view_in_gui,application,grant_by_profile",
|
||||
"key_type" => "autoincrement",
|
||||
"name_attcode" => "name",
|
||||
"state_attcode" => "",
|
||||
"reconc_keys" => array(),
|
||||
"db_table" => "priv_query_oql",
|
||||
"db_key_field" => "id",
|
||||
"db_finalclass_field" => "",
|
||||
"display_template" => "",
|
||||
);
|
||||
MetaModel::Init_Params($aParams);
|
||||
MetaModel::Init_InheritAttributes();
|
||||
MetaModel::Init_AddAttribute(new AttributeOQL("oql", array("allowed_values"=>null, "sql"=>"oql", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeText("fields", array("allowed_values"=>null, "sql"=>"fields", "default_value"=>null, "is_null_allowed"=>true, "depends_on"=>array())));
|
||||
// Rolled back to AttributeText until AttributeQueryAttCodeSet can manage fields order correctly
|
||||
//MetaModel::Init_AddAttribute(new AttributeQueryAttCodeSet("fields", array("allowed_values"=>null,"max_items" => 1000, "query_field" => "oql", "sql"=>"fields", "default_value"=>null, "is_null_allowed"=>true, "depends_on"=>array('oql'))));
|
||||
|
||||
// Display lists
|
||||
MetaModel::Init_SetZListItems('details', array('name', 'description', 'oql', 'fields')); // Attributes to be displayed for the complete details
|
||||
MetaModel::Init_SetZListItems('list', array('description')); // Attributes to be displayed for a list
|
||||
// Search criteria
|
||||
MetaModel::Init_SetZListItems('standard_search', array('name', 'description', 'fields', 'oql')); // Criteria of the std search form
|
||||
}
|
||||
|
||||
function DisplayBareProperties(WebPage $oPage, $bEditMode = false, $sPrefix = '', $aExtraParams = array())
|
||||
{
|
||||
$aFieldsMap = parent::DisplayBareProperties($oPage, $bEditMode, $sPrefix, $aExtraParams);
|
||||
|
||||
if (!$bEditMode)
|
||||
{
|
||||
$sFields = trim($this->Get('fields'));
|
||||
$bExportV1Recommended = ($sFields == '');
|
||||
if ($bExportV1Recommended)
|
||||
{
|
||||
$oFieldAttDef = MetaModel::GetAttributeDef('QueryOQL', 'fields');
|
||||
$oPage->add('<div class="message message_error" style="padding-left: 30px;"><div style="padding: 10px;">'.Dict::Format('UI:Query:UrlV1', $oFieldAttDef->GetLabel()).'</div></div>');
|
||||
$sUrl = utils::GetAbsoluteUrlAppRoot().'webservices/export.php?format=spreadsheet&login_mode=basic&query='.$this->GetKey();
|
||||
}
|
||||
else
|
||||
{
|
||||
$sUrl = utils::GetAbsoluteUrlAppRoot().'webservices/export-v2.php?format=spreadsheet&login_mode=basic&date_format='.urlencode((string)AttributeDateTime::GetFormat()).'&query='.$this->GetKey();
|
||||
}
|
||||
$sOql = $this->Get('oql');
|
||||
$sMessage = null;
|
||||
try
|
||||
{
|
||||
$oSearch = DBObjectSearch::FromOQL($sOql);
|
||||
$aParameters = $oSearch->GetQueryParams();
|
||||
foreach($aParameters as $sParam => $val)
|
||||
{
|
||||
$sUrl .= '&arg_'.$sParam.'=["'.$sParam.'"]';
|
||||
}
|
||||
|
||||
$oPage->p(Dict::S('UI:Query:UrlForExcel').':<br/><textarea cols="80" rows="3" READONLY>'.$sUrl.'</textarea>');
|
||||
|
||||
if (count($aParameters) == 0)
|
||||
{
|
||||
$oBlock = new DisplayBlock($oSearch, 'list');
|
||||
$aExtraParams = array(
|
||||
//'menu' => $sShowMenu,
|
||||
'table_id' => 'query_preview_'.$this->getKey(),
|
||||
);
|
||||
$sBlockId = 'block_query_preview_'.$this->GetKey(); // make a unique id (edition occuring in the same DOM)
|
||||
$oBlock->Display($oPage, $sBlockId, $aExtraParams);
|
||||
}
|
||||
}
|
||||
catch (OQLException $e)
|
||||
{
|
||||
$sMessage = '<div class="message message_error" style="padding-left: 30px;"><div style="padding: 10px;">'.Dict::Format('UI:RunQuery:Error', $e->getHtmlDesc()).'</div></div>';
|
||||
$oPage->p($sMessage);
|
||||
}
|
||||
}
|
||||
return $aFieldsMap;
|
||||
}
|
||||
|
||||
// Rolled back until 'fields' can be properly managed by AttributeQueryAttCodeSet
|
||||
//
|
||||
// public function ComputeValues()
|
||||
// {
|
||||
// parent::ComputeValues();
|
||||
//
|
||||
// // Remove unwanted attribute codes
|
||||
// $aChanges = $this->ListChanges();
|
||||
// if (isset($aChanges['fields']))
|
||||
// {
|
||||
// $oAttDef = MetaModel::GetAttributeDef(get_class($this), 'fields');
|
||||
// $aArgs = array('this' => $this);
|
||||
// $aAllowedValues = $oAttDef->GetAllowedValues($aArgs);
|
||||
//
|
||||
// /** @var \ormSet $oValue */
|
||||
// $oValue = $this->Get('fields');
|
||||
// $aValues = $oValue->GetValues();
|
||||
// $bChanged = false;
|
||||
// foreach($aValues as $key => $sValue)
|
||||
// {
|
||||
// if (!isset($aAllowedValues[$sValue]))
|
||||
// {
|
||||
// unset($aValues[$key]);
|
||||
// $bChanged = true;
|
||||
// }
|
||||
// }
|
||||
// if ($bChanged)
|
||||
// {
|
||||
// $oValue->SetValues($aValues);
|
||||
// $this->Set('fields', $oValue);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
}
|
||||
|
||||
?>
|
||||
|
||||
@@ -1,338 +1,338 @@
|
||||
<?php
|
||||
// Copyright (C) 2010-2016 Combodo SARL
|
||||
//
|
||||
// This file is part of iTop.
|
||||
//
|
||||
// iTop is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// iTop is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with iTop. If not, see <http://www.gnu.org/licenses/>
|
||||
|
||||
|
||||
/**
|
||||
* Persistent class Shortcut and derived
|
||||
* Shortcuts of any kind
|
||||
*
|
||||
* @copyright Copyright (C) 2010-2016 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
abstract class Shortcut extends DBObject implements iDisplay
|
||||
{
|
||||
public static function Init()
|
||||
{
|
||||
$aParams = array
|
||||
(
|
||||
"category" => "gui,view_in_gui",
|
||||
"key_type" => "autoincrement",
|
||||
"name_attcode" => "name",
|
||||
"state_attcode" => "",
|
||||
"reconc_keys" => array(),
|
||||
"db_table" => "priv_shortcut",
|
||||
"db_key_field" => "id",
|
||||
"db_finalclass_field" => "realclass",
|
||||
"display_template" => "",
|
||||
);
|
||||
MetaModel::Init_Params($aParams);
|
||||
//MetaModel::Init_InheritAttributes();
|
||||
MetaModel::Init_AddAttribute(new AttributeExternalKey("user_id", array("targetclass"=>"User", "allowed_values"=>null, "sql"=>"user_id", "is_null_allowed"=>true, "on_target_delete"=>DEL_AUTO, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeString("name", array("allowed_values"=>null, "sql"=>"name", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeText("context", array("allowed_values"=>null, "sql"=>"context", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array())));
|
||||
|
||||
// Display lists
|
||||
MetaModel::Init_SetZListItems('details', array('name', 'context')); // Attributes to be displayed for the complete details
|
||||
MetaModel::Init_SetZListItems('list', array('name')); // Attributes to be displayed for a list
|
||||
// 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
|
||||
}
|
||||
|
||||
abstract public function RenderContent(WebPage $oPage, $aExtraParams = array());
|
||||
|
||||
protected function OnInsert()
|
||||
{
|
||||
$this->Set('user_id', UserRights::GetUserId());
|
||||
}
|
||||
|
||||
public function StartRenameDialog($oPage)
|
||||
{
|
||||
$oPage->add('<div id="shortcut_rename_dlg">');
|
||||
|
||||
$oForm = new DesignerForm();
|
||||
$sDefault = $this->Get('name');
|
||||
$oField = new DesignerTextField('name', Dict::S('Class:Shortcut/Attribute:name'), $sDefault);
|
||||
$oField->SetMandatory(true);
|
||||
$oForm->AddField($oField);
|
||||
$oForm->Render($oPage);
|
||||
$oPage->add('</div>');
|
||||
|
||||
$sDialogTitle = Dict::S('UI:ShortcutRenameDlg:Title');
|
||||
$sOkButtonLabel = Dict::S('UI:Button:Ok');
|
||||
$sCancelButtonLabel = Dict::S('UI:Button:Cancel');
|
||||
$iShortcut = $this->GetKey();
|
||||
|
||||
$oPage->add_ready_script(
|
||||
<<<EOF
|
||||
function ShortcutRenameOK()
|
||||
{
|
||||
var oForm = $(this).find('form');
|
||||
var sFormId = oForm.attr('id');
|
||||
var oParams = null;
|
||||
var aErrors = ValidateForm(sFormId, false);
|
||||
if (aErrors.length == 0)
|
||||
{
|
||||
oParams = ReadFormParams(sFormId);
|
||||
}
|
||||
oParams.operation = 'shortcut_rename_go';
|
||||
oParams.id = $iShortcut;
|
||||
var me = $(this);
|
||||
$.post(GetAbsoluteUrlAppRoot()+'pages/ajax.render.php', oParams, function(data) {
|
||||
me.dialog( "close" );
|
||||
me.remove();
|
||||
$('body').append(data);
|
||||
});
|
||||
}
|
||||
|
||||
$('#shortcut_rename_dlg form').bind('submit', function() { return false; });
|
||||
|
||||
$('#shortcut_rename_dlg').dialog({
|
||||
width: 400,
|
||||
modal: true,
|
||||
title: '$sDialogTitle',
|
||||
buttons: [
|
||||
{ text: "$sOkButtonLabel", click: ShortcutRenameOK},
|
||||
{ text: "$sCancelButtonLabel", click: function() {
|
||||
$(this).dialog( "close" ); $(this).remove();
|
||||
} },
|
||||
],
|
||||
close: function() { $(this).remove(); }
|
||||
});
|
||||
EOF
|
||||
);
|
||||
}
|
||||
|
||||
// Minimual implementation of iDisplay: to make the shortcut be listable
|
||||
//
|
||||
public static function MapContextParam($sContextParam)
|
||||
{
|
||||
return (($sContextParam == 'menu') ? null : $sContextParam);
|
||||
}
|
||||
|
||||
public function GetHilightClass()
|
||||
{
|
||||
return HILIGHT_CLASS_NONE;
|
||||
}
|
||||
|
||||
public static function GetUIPage()
|
||||
{
|
||||
return '';
|
||||
}
|
||||
|
||||
function DisplayDetails(WebPage $oPage, $bEditMode = false)
|
||||
{
|
||||
}
|
||||
|
||||
function DisplayBareProperties(WebPage $oPage, $bEditMode = false, $sPrefix = '', $aExtraParams = array())
|
||||
{
|
||||
return array();
|
||||
}
|
||||
// End of the minimal implementation of iDisplay
|
||||
}
|
||||
|
||||
class ShortcutOQL extends Shortcut
|
||||
{
|
||||
public static function Init()
|
||||
{
|
||||
$aParams = array
|
||||
(
|
||||
"category" => "gui,view_in_gui",
|
||||
"key_type" => "autoincrement",
|
||||
"name_attcode" => "name",
|
||||
"state_attcode" => "",
|
||||
"reconc_keys" => array(),
|
||||
"db_table" => "priv_shortcut_oql",
|
||||
"db_key_field" => "id",
|
||||
"db_finalclass_field" => "",
|
||||
"display_template" => "",
|
||||
);
|
||||
MetaModel::Init_Params($aParams);
|
||||
MetaModel::Init_InheritAttributes();
|
||||
MetaModel::Init_AddAttribute(new AttributeOQL("oql", array("allowed_values"=>null, "sql"=>"oql", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeEnum("auto_reload", array("allowed_values"=>new ValueSetEnum('none,custom'), "sql"=>"auto_reload", "default_value"=>"none", "is_null_allowed"=>false, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeInteger("auto_reload_sec", array("allowed_values"=>null, "sql"=>"auto_reload_sec", "default_value"=>60, "is_null_allowed"=>false, "depends_on"=>array())));
|
||||
|
||||
// Display lists
|
||||
MetaModel::Init_SetZListItems('details', array('name', 'context', 'oql')); // Attributes to be displayed for the complete details
|
||||
MetaModel::Init_SetZListItems('list', array('name')); // Attributes to be displayed for a list
|
||||
// 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
|
||||
}
|
||||
|
||||
public function RenderContent(WebPage $oPage, $aExtraParams = array())
|
||||
{
|
||||
$oPage->set_title($this->Get('name'));
|
||||
|
||||
switch($this->Get('auto_reload'))
|
||||
{
|
||||
case 'custom':
|
||||
$iRate = (int)$this->Get('auto_reload_sec');
|
||||
if ($iRate > 0)
|
||||
{
|
||||
// Must a string otherwise it can be evaluated to 'true' and defaults to "standard" refresh rate!
|
||||
$aExtraParams['auto_reload'] = (string)$iRate;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
case 'none':
|
||||
}
|
||||
|
||||
$bSearchPane = true;
|
||||
$bSearchOpen = false;
|
||||
try
|
||||
{
|
||||
OQLMenuNode::RenderOQLSearch($this->Get('oql'), $this->Get('name'), 'shortcut_'.$this->GetKey(), $bSearchPane, $bSearchOpen, $oPage, $aExtraParams, true);
|
||||
}
|
||||
catch (Exception $e)
|
||||
{
|
||||
throw new Exception("The OQL shortcut '".$this->Get('name')."' (id: ".$this->GetKey().") could not be displayed: ".$e->getMessage());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public function CloneTableSettings($sTableSettings)
|
||||
{
|
||||
$aTableSettings = json_decode($sTableSettings, true);
|
||||
|
||||
$oFilter = DBObjectSearch::FromOQL($this->Get('oql'));
|
||||
$oCustomSettings = new DataTableSettings($oFilter->GetSelectedClasses());
|
||||
$oCustomSettings->iDefaultPageSize = $aTableSettings['iPageSize'];
|
||||
$oCustomSettings->aColumns = $aTableSettings['oColumns'];
|
||||
$oCustomSettings->Save('shortcut_'.$this->GetKey());
|
||||
}
|
||||
|
||||
public static function GetCreationForm($sOQL = null, $sTableSettings = null)
|
||||
{
|
||||
$oForm = new DesignerForm();
|
||||
|
||||
// Find a unique default name
|
||||
// -> The class of the query + an index if necessary
|
||||
if ($sOQL == null)
|
||||
{
|
||||
$sDefault = '';
|
||||
}
|
||||
else
|
||||
{
|
||||
$oBMSearch = new DBObjectSearch('Shortcut');
|
||||
$oBMSearch->AddCondition('user_id', UserRights::GetUserId(), '=');
|
||||
$oBMSet = new DBObjectSet($oBMSearch);
|
||||
$aNames = $oBMSet->GetColumnAsArray('name');
|
||||
$oSearch = DBObjectSearch::FromOQL($sOQL);
|
||||
$sDefault = utils::MakeUniqueName($oSearch->GetClass(), $aNames);
|
||||
}
|
||||
|
||||
$oField = new DesignerTextField('name', Dict::S('Class:Shortcut/Attribute:name'), $sDefault);
|
||||
$oField->SetMandatory(true);
|
||||
$oForm->AddField($oField);
|
||||
|
||||
/*
|
||||
$oField = new DesignerComboField('auto_reload', Dict::S('Class:ShortcutOQL/Attribute:auto_reload'), 'none');
|
||||
$oAttDef = MetaModel::GetAttributeDef(__class__, 'auto_reload');
|
||||
$oField->SetAllowedValues($oAttDef->GetAllowedValues());
|
||||
$oField->SetMandatory(true);
|
||||
$oForm->AddField($oField);
|
||||
*/
|
||||
$oField = new DesignerBooleanField('auto_reload', Dict::S('Class:ShortcutOQL/Attribute:auto_reload'), false);
|
||||
$oForm->AddField($oField);
|
||||
|
||||
$oField = new DesignerIntegerField('auto_reload_sec', Dict::S('Class:ShortcutOQL/Attribute:auto_reload_sec'), MetaModel::GetConfig()->GetStandardReloadInterval());
|
||||
$oField->SetBoundaries(MetaModel::GetConfig()->Get('min_reload_interval'), null); // no upper limit
|
||||
$oField->SetMandatory(false);
|
||||
$oForm->AddField($oField);
|
||||
|
||||
$oField = new DesignerHiddenField('oql', '', $sOQL);
|
||||
$oForm->AddField($oField);
|
||||
|
||||
$oField = new DesignerHiddenField('table_settings', '', $sTableSettings);
|
||||
$oForm->AddField($oField);
|
||||
|
||||
return $oForm;
|
||||
}
|
||||
|
||||
public static function GetCreationDlgFromOQL($oPage, $sOQL, $sTableSettings)
|
||||
{
|
||||
$oPage->add('<div id="shortcut_creation_dlg">');
|
||||
|
||||
$oForm = self::GetCreationForm($sOQL, $sTableSettings);
|
||||
|
||||
$oForm->Render($oPage);
|
||||
$oPage->add('</div>');
|
||||
|
||||
$sDialogTitle = Dict::S('UI:ShortcutListDlg:Title');
|
||||
$sOkButtonLabel = Dict::S('UI:Button:Ok');
|
||||
$sCancelButtonLabel = Dict::S('UI:Button:Cancel');
|
||||
|
||||
$oAppContext = new ApplicationContext();
|
||||
$sContext = $oAppContext->GetForLink();
|
||||
|
||||
$sRateTitle = addslashes(Dict::Format('Class:ShortcutOQL/Attribute:auto_reload_sec/tip', MetaModel::GetConfig()->Get('min_reload_interval')));
|
||||
|
||||
$oPage->add_ready_script(
|
||||
<<<EOF
|
||||
|
||||
// Note: the title gets deleted by the validation mechanism
|
||||
$("#attr_auto_reload_sec").tooltip({items: 'input', content: '$sRateTitle'});
|
||||
$("#attr_auto_reload_sec").prop('disabled', !$('#attr_auto_reload').is(':checked'));
|
||||
|
||||
$('#attr_auto_reload').change( function(ev) {
|
||||
$("#attr_auto_reload_sec").prop('disabled', !$(this).is(':checked'));
|
||||
} );
|
||||
|
||||
function ShortcutCreationOK()
|
||||
{
|
||||
var oForm = $('#shortcut_creation_dlg form');
|
||||
var sFormId = oForm.attr('id');
|
||||
var oParams = null;
|
||||
var aErrors = ValidateForm(sFormId, false);
|
||||
if (aErrors.length == 0)
|
||||
{
|
||||
oParams = ReadFormParams(sFormId);
|
||||
}
|
||||
oParams.operation = 'shortcut_list_create';
|
||||
var me = $('#shortcut_creation_dlg');
|
||||
$.post(GetAbsoluteUrlAppRoot()+'pages/ajax.render.php?$sContext', oParams, function(data) {
|
||||
me.dialog( "close" );
|
||||
me.remove();
|
||||
$('body').append(data);
|
||||
});
|
||||
}
|
||||
|
||||
$('#shortcut_creation_dlg form').bind('submit', function() { ShortcutCreationOK(); return false; });
|
||||
|
||||
$('#shortcut_creation_dlg').dialog({
|
||||
width: 400,
|
||||
modal: true,
|
||||
title: '$sDialogTitle',
|
||||
buttons: [
|
||||
{ text: "$sOkButtonLabel", click: ShortcutCreationOK },
|
||||
{ text: "$sCancelButtonLabel", click: function() {
|
||||
$(this).dialog( "close" ); $(this).remove();
|
||||
} },
|
||||
],
|
||||
close: function() { $(this).remove(); }
|
||||
});
|
||||
EOF
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
<?php
|
||||
// Copyright (C) 2010-2016 Combodo SARL
|
||||
//
|
||||
// This file is part of iTop.
|
||||
//
|
||||
// iTop is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// iTop is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with iTop. If not, see <http://www.gnu.org/licenses/>
|
||||
|
||||
|
||||
/**
|
||||
* Persistent class Shortcut and derived
|
||||
* Shortcuts of any kind
|
||||
*
|
||||
* @copyright Copyright (C) 2010-2016 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
abstract class Shortcut extends DBObject implements iDisplay
|
||||
{
|
||||
public static function Init()
|
||||
{
|
||||
$aParams = array
|
||||
(
|
||||
"category" => "gui,view_in_gui",
|
||||
"key_type" => "autoincrement",
|
||||
"name_attcode" => "name",
|
||||
"state_attcode" => "",
|
||||
"reconc_keys" => array(),
|
||||
"db_table" => "priv_shortcut",
|
||||
"db_key_field" => "id",
|
||||
"db_finalclass_field" => "realclass",
|
||||
"display_template" => "",
|
||||
);
|
||||
MetaModel::Init_Params($aParams);
|
||||
//MetaModel::Init_InheritAttributes();
|
||||
MetaModel::Init_AddAttribute(new AttributeExternalKey("user_id", array("targetclass"=>"User", "allowed_values"=>null, "sql"=>"user_id", "is_null_allowed"=>true, "on_target_delete"=>DEL_AUTO, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeString("name", array("allowed_values"=>null, "sql"=>"name", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeText("context", array("allowed_values"=>null, "sql"=>"context", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array())));
|
||||
|
||||
// Display lists
|
||||
MetaModel::Init_SetZListItems('details', array('name', 'context')); // Attributes to be displayed for the complete details
|
||||
MetaModel::Init_SetZListItems('list', array('name')); // Attributes to be displayed for a list
|
||||
// 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
|
||||
}
|
||||
|
||||
abstract public function RenderContent(WebPage $oPage, $aExtraParams = array());
|
||||
|
||||
protected function OnInsert()
|
||||
{
|
||||
$this->Set('user_id', UserRights::GetUserId());
|
||||
}
|
||||
|
||||
public function StartRenameDialog($oPage)
|
||||
{
|
||||
$oPage->add('<div id="shortcut_rename_dlg">');
|
||||
|
||||
$oForm = new DesignerForm();
|
||||
$sDefault = $this->Get('name');
|
||||
$oField = new DesignerTextField('name', Dict::S('Class:Shortcut/Attribute:name'), $sDefault);
|
||||
$oField->SetMandatory(true);
|
||||
$oForm->AddField($oField);
|
||||
$oForm->Render($oPage);
|
||||
$oPage->add('</div>');
|
||||
|
||||
$sDialogTitle = Dict::S('UI:ShortcutRenameDlg:Title');
|
||||
$sOkButtonLabel = Dict::S('UI:Button:Ok');
|
||||
$sCancelButtonLabel = Dict::S('UI:Button:Cancel');
|
||||
$iShortcut = $this->GetKey();
|
||||
|
||||
$oPage->add_ready_script(
|
||||
<<<EOF
|
||||
function ShortcutRenameOK()
|
||||
{
|
||||
var oForm = $(this).find('form');
|
||||
var sFormId = oForm.attr('id');
|
||||
var oParams = null;
|
||||
var aErrors = ValidateForm(sFormId, false);
|
||||
if (aErrors.length == 0)
|
||||
{
|
||||
oParams = ReadFormParams(sFormId);
|
||||
}
|
||||
oParams.operation = 'shortcut_rename_go';
|
||||
oParams.id = $iShortcut;
|
||||
var me = $(this);
|
||||
$.post(GetAbsoluteUrlAppRoot()+'pages/ajax.render.php', oParams, function(data) {
|
||||
me.dialog( "close" );
|
||||
me.remove();
|
||||
$('body').append(data);
|
||||
});
|
||||
}
|
||||
|
||||
$('#shortcut_rename_dlg form').bind('submit', function() { return false; });
|
||||
|
||||
$('#shortcut_rename_dlg').dialog({
|
||||
width: 400,
|
||||
modal: true,
|
||||
title: '$sDialogTitle',
|
||||
buttons: [
|
||||
{ text: "$sOkButtonLabel", click: ShortcutRenameOK},
|
||||
{ text: "$sCancelButtonLabel", click: function() {
|
||||
$(this).dialog( "close" ); $(this).remove();
|
||||
} },
|
||||
],
|
||||
close: function() { $(this).remove(); }
|
||||
});
|
||||
EOF
|
||||
);
|
||||
}
|
||||
|
||||
// Minimual implementation of iDisplay: to make the shortcut be listable
|
||||
//
|
||||
public static function MapContextParam($sContextParam)
|
||||
{
|
||||
return (($sContextParam == 'menu') ? null : $sContextParam);
|
||||
}
|
||||
|
||||
public function GetHilightClass()
|
||||
{
|
||||
return HILIGHT_CLASS_NONE;
|
||||
}
|
||||
|
||||
public static function GetUIPage()
|
||||
{
|
||||
return '';
|
||||
}
|
||||
|
||||
function DisplayDetails(WebPage $oPage, $bEditMode = false)
|
||||
{
|
||||
}
|
||||
|
||||
function DisplayBareProperties(WebPage $oPage, $bEditMode = false, $sPrefix = '', $aExtraParams = array())
|
||||
{
|
||||
return array();
|
||||
}
|
||||
// End of the minimal implementation of iDisplay
|
||||
}
|
||||
|
||||
class ShortcutOQL extends Shortcut
|
||||
{
|
||||
public static function Init()
|
||||
{
|
||||
$aParams = array
|
||||
(
|
||||
"category" => "gui,view_in_gui",
|
||||
"key_type" => "autoincrement",
|
||||
"name_attcode" => "name",
|
||||
"state_attcode" => "",
|
||||
"reconc_keys" => array(),
|
||||
"db_table" => "priv_shortcut_oql",
|
||||
"db_key_field" => "id",
|
||||
"db_finalclass_field" => "",
|
||||
"display_template" => "",
|
||||
);
|
||||
MetaModel::Init_Params($aParams);
|
||||
MetaModel::Init_InheritAttributes();
|
||||
MetaModel::Init_AddAttribute(new AttributeOQL("oql", array("allowed_values"=>null, "sql"=>"oql", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeEnum("auto_reload", array("allowed_values"=>new ValueSetEnum('none,custom'), "sql"=>"auto_reload", "default_value"=>"none", "is_null_allowed"=>false, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeInteger("auto_reload_sec", array("allowed_values"=>null, "sql"=>"auto_reload_sec", "default_value"=>60, "is_null_allowed"=>false, "depends_on"=>array())));
|
||||
|
||||
// Display lists
|
||||
MetaModel::Init_SetZListItems('details', array('name', 'context', 'oql')); // Attributes to be displayed for the complete details
|
||||
MetaModel::Init_SetZListItems('list', array('name')); // Attributes to be displayed for a list
|
||||
// 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
|
||||
}
|
||||
|
||||
public function RenderContent(WebPage $oPage, $aExtraParams = array())
|
||||
{
|
||||
$oPage->set_title($this->Get('name'));
|
||||
|
||||
switch($this->Get('auto_reload'))
|
||||
{
|
||||
case 'custom':
|
||||
$iRate = (int)$this->Get('auto_reload_sec');
|
||||
if ($iRate > 0)
|
||||
{
|
||||
// Must a string otherwise it can be evaluated to 'true' and defaults to "standard" refresh rate!
|
||||
$aExtraParams['auto_reload'] = (string)$iRate;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
case 'none':
|
||||
}
|
||||
|
||||
$bSearchPane = true;
|
||||
$bSearchOpen = true;
|
||||
try
|
||||
{
|
||||
OQLMenuNode::RenderOQLSearch($this->Get('oql'), $this->Get('name'), 'shortcut_'.$this->GetKey(), $bSearchPane, $bSearchOpen, $oPage, $aExtraParams, true);
|
||||
}
|
||||
catch (Exception $e)
|
||||
{
|
||||
throw new Exception("The OQL shortcut '".$this->Get('name')."' (id: ".$this->GetKey().") could not be displayed: ".$e->getMessage());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public function CloneTableSettings($sTableSettings)
|
||||
{
|
||||
$aTableSettings = json_decode($sTableSettings, true);
|
||||
|
||||
$oFilter = DBObjectSearch::FromOQL($this->Get('oql'));
|
||||
$oCustomSettings = new DataTableSettings($oFilter->GetSelectedClasses());
|
||||
$oCustomSettings->iDefaultPageSize = $aTableSettings['iPageSize'];
|
||||
$oCustomSettings->aColumns = $aTableSettings['oColumns'];
|
||||
$oCustomSettings->Save('shortcut_'.$this->GetKey());
|
||||
}
|
||||
|
||||
public static function GetCreationForm($sOQL = null, $sTableSettings = null)
|
||||
{
|
||||
$oForm = new DesignerForm();
|
||||
|
||||
// Find a unique default name
|
||||
// -> The class of the query + an index if necessary
|
||||
if ($sOQL == null)
|
||||
{
|
||||
$sDefault = '';
|
||||
}
|
||||
else
|
||||
{
|
||||
$oBMSearch = new DBObjectSearch('Shortcut');
|
||||
$oBMSearch->AddCondition('user_id', UserRights::GetUserId(), '=');
|
||||
$oBMSet = new DBObjectSet($oBMSearch);
|
||||
$aNames = $oBMSet->GetColumnAsArray('name');
|
||||
$oSearch = DBObjectSearch::FromOQL($sOQL);
|
||||
$sDefault = utils::MakeUniqueName($oSearch->GetClass(), $aNames);
|
||||
}
|
||||
|
||||
$oField = new DesignerTextField('name', Dict::S('Class:Shortcut/Attribute:name'), $sDefault);
|
||||
$oField->SetMandatory(true);
|
||||
$oForm->AddField($oField);
|
||||
|
||||
/*
|
||||
$oField = new DesignerComboField('auto_reload', Dict::S('Class:ShortcutOQL/Attribute:auto_reload'), 'none');
|
||||
$oAttDef = MetaModel::GetAttributeDef(__class__, 'auto_reload');
|
||||
$oField->SetAllowedValues($oAttDef->GetAllowedValues());
|
||||
$oField->SetMandatory(true);
|
||||
$oForm->AddField($oField);
|
||||
*/
|
||||
$oField = new DesignerBooleanField('auto_reload', Dict::S('Class:ShortcutOQL/Attribute:auto_reload'), false);
|
||||
$oForm->AddField($oField);
|
||||
|
||||
$oField = new DesignerIntegerField('auto_reload_sec', Dict::S('Class:ShortcutOQL/Attribute:auto_reload_sec'), MetaModel::GetConfig()->GetStandardReloadInterval());
|
||||
$oField->SetBoundaries(MetaModel::GetConfig()->Get('min_reload_interval'), null); // no upper limit
|
||||
$oField->SetMandatory(false);
|
||||
$oForm->AddField($oField);
|
||||
|
||||
$oField = new DesignerHiddenField('oql', '', $sOQL);
|
||||
$oForm->AddField($oField);
|
||||
|
||||
$oField = new DesignerHiddenField('table_settings', '', $sTableSettings);
|
||||
$oForm->AddField($oField);
|
||||
|
||||
return $oForm;
|
||||
}
|
||||
|
||||
public static function GetCreationDlgFromOQL($oPage, $sOQL, $sTableSettings)
|
||||
{
|
||||
$oPage->add('<div id="shortcut_creation_dlg">');
|
||||
|
||||
$oForm = self::GetCreationForm($sOQL, $sTableSettings);
|
||||
|
||||
$oForm->Render($oPage);
|
||||
$oPage->add('</div>');
|
||||
|
||||
$sDialogTitle = Dict::S('UI:ShortcutListDlg:Title');
|
||||
$sOkButtonLabel = Dict::S('UI:Button:Ok');
|
||||
$sCancelButtonLabel = Dict::S('UI:Button:Cancel');
|
||||
|
||||
$oAppContext = new ApplicationContext();
|
||||
$sContext = $oAppContext->GetForLink();
|
||||
|
||||
$sRateTitle = addslashes(Dict::Format('Class:ShortcutOQL/Attribute:auto_reload_sec/tip', MetaModel::GetConfig()->Get('min_reload_interval')));
|
||||
|
||||
$oPage->add_ready_script(
|
||||
<<<EOF
|
||||
|
||||
// Note: the title gets deleted by the validation mechanism
|
||||
$("#attr_auto_reload_sec").tooltip({items: 'input', content: '$sRateTitle'});
|
||||
$("#attr_auto_reload_sec").prop('disabled', !$('#attr_auto_reload').is(':checked'));
|
||||
|
||||
$('#attr_auto_reload').change( function(ev) {
|
||||
$("#attr_auto_reload_sec").prop('disabled', !$(this).is(':checked'));
|
||||
} );
|
||||
|
||||
function ShortcutCreationOK()
|
||||
{
|
||||
var oForm = $('#shortcut_creation_dlg form');
|
||||
var sFormId = oForm.attr('id');
|
||||
var oParams = null;
|
||||
var aErrors = ValidateForm(sFormId, false);
|
||||
if (aErrors.length == 0)
|
||||
{
|
||||
oParams = ReadFormParams(sFormId);
|
||||
}
|
||||
oParams.operation = 'shortcut_list_create';
|
||||
var me = $('#shortcut_creation_dlg');
|
||||
$.post(GetAbsoluteUrlAppRoot()+'pages/ajax.render.php?$sContext', oParams, function(data) {
|
||||
me.dialog( "close" );
|
||||
me.remove();
|
||||
$('body').append(data);
|
||||
});
|
||||
}
|
||||
|
||||
$('#shortcut_creation_dlg form').bind('submit', function() { ShortcutCreationOK(); return false; });
|
||||
|
||||
$('#shortcut_creation_dlg').dialog({
|
||||
width: 400,
|
||||
modal: true,
|
||||
title: '$sDialogTitle',
|
||||
buttons: [
|
||||
{ text: "$sOkButtonLabel", click: ShortcutCreationOK },
|
||||
{ text: "$sCancelButtonLabel", click: function() {
|
||||
$(this).dialog( "close" ); $(this).remove();
|
||||
} },
|
||||
],
|
||||
close: function() { $(this).remove(); }
|
||||
});
|
||||
EOF
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
|
||||
@@ -1,49 +1,82 @@
|
||||
<?php
|
||||
// Copyright (C) 2010-2016 Combodo SARL
|
||||
//
|
||||
// This file is part of iTop.
|
||||
//
|
||||
// iTop is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// iTop is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with iTop. If not, see <http://www.gnu.org/licenses/>
|
||||
|
||||
|
||||
/**
|
||||
* File to include to initialize the datamodel in memory
|
||||
*
|
||||
* @copyright Copyright (C) 2010-2016 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
require_once(APPROOT.'/core/cmdbobject.class.inc.php');
|
||||
require_once(APPROOT.'/application/utils.inc.php');
|
||||
require_once(APPROOT.'/core/contexttag.class.inc.php');
|
||||
session_name('itop-'.md5(APPROOT));
|
||||
session_start();
|
||||
$sSwitchEnv = utils::ReadParam('switch_env', null);
|
||||
if (($sSwitchEnv != null) && (file_exists(APPCONF.$sSwitchEnv.'/'.ITOP_CONFIG_FILE)))
|
||||
{
|
||||
$_SESSION['itop_env'] = $sSwitchEnv;
|
||||
$sEnv = $sSwitchEnv;
|
||||
// TODO: reset the credentials as well ??
|
||||
}
|
||||
else if (isset($_SESSION['itop_env']))
|
||||
{
|
||||
$sEnv = $_SESSION['itop_env'];
|
||||
}
|
||||
else
|
||||
{
|
||||
$sEnv = ITOP_DEFAULT_ENV;
|
||||
$_SESSION['itop_env'] = ITOP_DEFAULT_ENV;
|
||||
}
|
||||
$sConfigFile = APPCONF.$sEnv.'/'.ITOP_CONFIG_FILE;
|
||||
MetaModel::Startup($sConfigFile, false /* $bModelOnly */, true /* $bAllowCache */, false /* $bTraceSourceFiles */, $sEnv);
|
||||
<?php
|
||||
// Copyright (C) 2010-2016 Combodo SARL
|
||||
//
|
||||
// This file is part of iTop.
|
||||
//
|
||||
// iTop is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// iTop is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with iTop. If not, see <http://www.gnu.org/licenses/>
|
||||
|
||||
|
||||
/**
|
||||
* File to include to initialize the datamodel in memory
|
||||
*
|
||||
* @copyright Copyright (C) 2010-2016 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
// This storage is freed on error (case of allowed memory exhausted)
|
||||
$sReservedMemory = str_repeat('*', 1024 * 1024);
|
||||
register_shutdown_function(function()
|
||||
{
|
||||
global $sReservedMemory;
|
||||
$sReservedMemory = null;
|
||||
if (!is_null($err = error_get_last()) && ($err['type'] == E_ERROR))
|
||||
{
|
||||
if (strpos($err['message'], 'Allowed memory size of') !== false)
|
||||
{
|
||||
$sLimit = ini_get('memory_limit');
|
||||
echo "<p>iTop: Allowed memory size of $sLimit exhausted, contact your administrator to increase memory_limit in php.ini</p>\n";
|
||||
}
|
||||
else
|
||||
{
|
||||
echo "<p>iTop: An error occurred, check server error log for more information.</p>\n";
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
require_once(APPROOT.'/core/cmdbobject.class.inc.php');
|
||||
require_once(APPROOT.'/application/utils.inc.php');
|
||||
require_once(APPROOT.'/core/contexttag.class.inc.php');
|
||||
session_name('itop-'.md5(APPROOT));
|
||||
session_start();
|
||||
$sSwitchEnv = utils::ReadParam('switch_env', null);
|
||||
$bAllowCache = true;
|
||||
if (($sSwitchEnv != null) && (file_exists(APPCONF.$sSwitchEnv.'/'.ITOP_CONFIG_FILE)) && isset($_SESSION['itop_env']) && ($_SESSION['itop_env'] !== $sSwitchEnv))
|
||||
{
|
||||
$_SESSION['itop_env'] = $sSwitchEnv;
|
||||
$sEnv = $sSwitchEnv;
|
||||
$bAllowCache = false;
|
||||
// Reset the opcache since otherwise the PHP "model" files may still be cached !!
|
||||
if (function_exists('opcache_reset'))
|
||||
{
|
||||
// Zend opcode cache
|
||||
opcache_reset();
|
||||
}
|
||||
if (function_exists('apc_clear_cache'))
|
||||
{
|
||||
// APC(u) cache
|
||||
apc_clear_cache();
|
||||
}
|
||||
// TODO: reset the credentials as well ??
|
||||
}
|
||||
else if (isset($_SESSION['itop_env']))
|
||||
{
|
||||
$sEnv = $_SESSION['itop_env'];
|
||||
}
|
||||
else
|
||||
{
|
||||
$sEnv = ITOP_DEFAULT_ENV;
|
||||
$_SESSION['itop_env'] = ITOP_DEFAULT_ENV;
|
||||
}
|
||||
$sConfigFile = APPCONF.$sEnv.'/'.ITOP_CONFIG_FILE;
|
||||
MetaModel::Startup($sConfigFile, false /* $bModelOnly */, $bAllowCache, false /* $bTraceSourceFiles */, $sEnv);
|
||||
@@ -1,427 +1,428 @@
|
||||
<?php
|
||||
// Copyright (C) 2010-2017 Combodo SARL
|
||||
//
|
||||
// This file is part of iTop.
|
||||
//
|
||||
// iTop is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// iTop is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with iTop. If not, see <http://www.gnu.org/licenses/>
|
||||
|
||||
|
||||
/**
|
||||
* Class DisplayTemplate
|
||||
*
|
||||
* @copyright Copyright (C) 2010-2017 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
require_once(APPROOT.'/application/displayblock.class.inc.php');
|
||||
/**
|
||||
* This class manages the special template format used internally to build the iTop web pages
|
||||
*/
|
||||
class DisplayTemplate
|
||||
{
|
||||
protected $m_sTemplate;
|
||||
protected $m_aTags;
|
||||
static protected $iBlockCount = 0;
|
||||
|
||||
public function __construct($sTemplate)
|
||||
{
|
||||
$this->m_aTags = array (
|
||||
'itopblock',
|
||||
'itopcheck',
|
||||
'itoptabs',
|
||||
'itoptab',
|
||||
'itoptoggle',
|
||||
'itopstring',
|
||||
'sqlblock'
|
||||
);
|
||||
$this->m_sTemplate = $sTemplate;
|
||||
}
|
||||
|
||||
public function Render(WebPage $oPage, $aParams = array())
|
||||
{
|
||||
$this->m_sTemplate = MetaModel::ApplyParams($this->m_sTemplate, $aParams);
|
||||
$iStart = 0;
|
||||
$iEnd = strlen($this->m_sTemplate);
|
||||
$iCount = 0;
|
||||
$iBeforeTagPos = $iStart;
|
||||
$iAfterTagPos = $iStart;
|
||||
while($sTag = $this->GetNextTag($iStart, $iEnd))
|
||||
{
|
||||
$sContent = $this->GetTagContent($sTag, $iStart, $iEnd);
|
||||
$iAfterTagPos = $iEnd + strlen('</'.$sTag.'>');
|
||||
$sOuterTag = substr($this->m_sTemplate, $iStart, $iAfterTagPos - $iStart);
|
||||
$oPage->add(substr($this->m_sTemplate, $iBeforeTagPos, $iStart - $iBeforeTagPos));
|
||||
if ($sTag == DisplayBlock::TAG_BLOCK)
|
||||
{
|
||||
try
|
||||
{
|
||||
$oBlock = DisplayBlock::FromTemplate($sOuterTag);
|
||||
if (is_object($oBlock))
|
||||
{
|
||||
$oBlock->Display($oPage, 'block_'.self::$iBlockCount, $aParams);
|
||||
}
|
||||
}
|
||||
catch(OQLException $e)
|
||||
{
|
||||
$oPage->p('Error in template (please contact your administrator) - Invalid query<!--'.$sOuterTag.'-->');
|
||||
}
|
||||
catch(Exception $e)
|
||||
{
|
||||
$oPage->p('Error in template (please contact your administrator)<!--'.$e->getMessage().'--><!--'.$sOuterTag.'-->');
|
||||
}
|
||||
|
||||
self::$iBlockCount++;
|
||||
}
|
||||
else
|
||||
{
|
||||
$aAttributes = $this->GetTagAttributes($sTag, $iStart, $iEnd);
|
||||
//$oPage->p("Tag: $sTag - ($iStart, $iEnd)");
|
||||
$this->RenderTag($oPage, $sTag, $aAttributes, $sContent);
|
||||
|
||||
}
|
||||
$iAfterTagPos = $iEnd + strlen('</'.$sTag.'>');
|
||||
$iBeforeTagPos = $iAfterTagPos;
|
||||
$iStart = $iEnd;
|
||||
$iEnd = strlen($this->m_sTemplate);
|
||||
$iCount++;
|
||||
}
|
||||
$oPage->add(substr($this->m_sTemplate, $iAfterTagPos));
|
||||
}
|
||||
|
||||
public function GetNextTag(&$iStartPos, &$iEndPos)
|
||||
{
|
||||
$iChunkStartPos = $iStartPos;
|
||||
$sNextTag = null;
|
||||
$iStartPos = $iEndPos;
|
||||
foreach($this->m_aTags as $sTag)
|
||||
{
|
||||
// Search for the opening tag
|
||||
$iOpeningPos = stripos($this->m_sTemplate, '<'.$sTag.' ', $iChunkStartPos);
|
||||
if ($iOpeningPos === false)
|
||||
{
|
||||
$iOpeningPos = stripos($this->m_sTemplate, '<'.$sTag.'>', $iChunkStartPos);
|
||||
}
|
||||
if ($iOpeningPos !== false)
|
||||
{
|
||||
$iClosingPos = stripos($this->m_sTemplate, '</'.$sTag.'>', $iOpeningPos);
|
||||
}
|
||||
if ( ($iOpeningPos !== false) && ($iClosingPos !== false))
|
||||
{
|
||||
if ($iOpeningPos < $iStartPos)
|
||||
{
|
||||
// This is the next tag
|
||||
$iStartPos = $iOpeningPos;
|
||||
$iEndPos = $iClosingPos;
|
||||
$sNextTag = $sTag;
|
||||
}
|
||||
}
|
||||
}
|
||||
return $sNextTag;
|
||||
}
|
||||
|
||||
public function GetTagContent($sTag, $iStartPos, $iEndPos)
|
||||
{
|
||||
$sContent = "";
|
||||
$iContentStart = strpos($this->m_sTemplate, '>', $iStartPos); // Content of tag start immediatly after the first closing bracket
|
||||
if ($iContentStart !== false)
|
||||
{
|
||||
$sContent = substr($this->m_sTemplate, 1+$iContentStart, $iEndPos - $iContentStart - 1);
|
||||
}
|
||||
return $sContent;
|
||||
}
|
||||
|
||||
public function GetTagAttributes($sTag, $iStartPos, $iEndPos)
|
||||
{
|
||||
$aAttr = array();
|
||||
$iAttrStart = strpos($this->m_sTemplate, ' ', $iStartPos); // Attributes start just after the first space
|
||||
$iAttrEnd = strpos($this->m_sTemplate, '>', $iStartPos); // Attributes end just before the first closing bracket
|
||||
if ( ($iAttrStart !== false) && ($iAttrEnd !== false) && ($iAttrEnd > $iAttrStart))
|
||||
{
|
||||
$sAttributes = substr($this->m_sTemplate, 1+$iAttrStart, $iAttrEnd - $iAttrStart - 1);
|
||||
$aAttributes = explode(' ', $sAttributes);
|
||||
foreach($aAttributes as $sAttr)
|
||||
{
|
||||
if ( preg_match('/(.+) *= *"(.+)"$/', $sAttr, $aMatches) )
|
||||
{
|
||||
$aAttr[strtolower($aMatches[1])] = $aMatches[2];
|
||||
}
|
||||
}
|
||||
}
|
||||
return $aAttr;
|
||||
}
|
||||
|
||||
protected function RenderTag($oPage, $sTag, $aAttributes, $sContent)
|
||||
{
|
||||
static $iTabContainerCount = 0;
|
||||
switch($sTag)
|
||||
{
|
||||
case 'itoptabs':
|
||||
$oPage->AddTabContainer('Tabs_'.$iTabContainerCount);
|
||||
$oPage->SetCurrentTabContainer('Tabs_'.$iTabContainerCount);
|
||||
$iTabContainerCount++;
|
||||
//$oPage->p('Content:<pre>'.htmlentities($sContent, ENT_QUOTES, 'UTF-8').'</pre>');
|
||||
$oTemplate = new DisplayTemplate($sContent);
|
||||
$oTemplate->Render($oPage, array()); // no params to apply, they have already been applied
|
||||
$oPage->SetCurrentTabContainer('');
|
||||
break;
|
||||
|
||||
case 'itopcheck':
|
||||
$sClassName = $aAttributes['class'];
|
||||
if (MetaModel::IsValidClass($sClassName) && UserRights::IsActionAllowed($sClassName, UR_ACTION_READ))
|
||||
{
|
||||
$oTemplate = new DisplayTemplate($sContent);
|
||||
$oTemplate->Render($oPage, array()); // no params to apply, they have already been applied
|
||||
}
|
||||
else
|
||||
{
|
||||
// Leave a trace for those who'd like to understand why nothing is displayed
|
||||
$oPage->add("<!-- class $sClassName does not exist, skipping some part of the template -->\n");
|
||||
}
|
||||
break;
|
||||
|
||||
case 'itoptab':
|
||||
$oPage->SetCurrentTab(Dict::S(str_replace('_', ' ', $aAttributes['name'])));
|
||||
$oTemplate = new DisplayTemplate($sContent);
|
||||
$oTemplate->Render($oPage, array()); // no params to apply, they have already been applied
|
||||
//$oPage->p('iTop Tab Content:<pre>'.htmlentities($sContent, ENT_QUOTES, 'UTF-8').'</pre>');
|
||||
$oPage->SetCurrentTab('');
|
||||
break;
|
||||
|
||||
case 'itoptoggle':
|
||||
$sName = isset($aAttributes['name']) ? $aAttributes['name'] : 'Tagada';
|
||||
$bOpen = isset($aAttributes['open']) ? $aAttributes['open'] : true;
|
||||
$oPage->StartCollapsibleSection(Dict::S($sName), $bOpen);
|
||||
$oTemplate = new DisplayTemplate($sContent);
|
||||
$oTemplate->Render($oPage, array()); // no params to apply, they have already been applied
|
||||
//$oPage->p('iTop Tab Content:<pre>'.htmlentities($sContent, ENT_QUOTES, 'UTF-8').'</pre>');
|
||||
$oPage->EndCollapsibleSection();
|
||||
break;
|
||||
|
||||
case 'itopstring':
|
||||
$oPage->add(Dict::S($sContent));
|
||||
break;
|
||||
|
||||
case 'sqlblock':
|
||||
$oBlock = SqlBlock::FromTemplate($sContent);
|
||||
$oBlock->RenderContent($oPage);
|
||||
break;
|
||||
|
||||
case 'itopblock': // No longer used, handled by DisplayBlock::FromTemplate see above
|
||||
$oPage->add("<!-- Application Error: should be handled by DisplayBlock::FromTemplate -->");
|
||||
break;
|
||||
|
||||
default:
|
||||
// Unknown tag, just ignore it or now -- output an HTML comment
|
||||
$oPage->add("<!-- unsupported tag: $sTag -->");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Unit test
|
||||
*/
|
||||
static public function UnitTest()
|
||||
{
|
||||
require_once(APPROOT.'/application/startup.inc.php');
|
||||
require_once(APPROOT."/application/itopwebpage.class.inc.php");
|
||||
|
||||
$sTemplate = '<div class="page_header">
|
||||
<div class="actions_details"><a href="#"><span>Actions</span></a></div>
|
||||
<h1>$class$: <span class="hilite">$name$</span></h1>
|
||||
<itopblock blockclass="HistoryBlock" type="toggle" encoding="text/oql">SELECT CMDBChangeOp WHERE objkey = $id$ AND objclass = \'$class$\'</itopblock>
|
||||
</div>
|
||||
<img src="../../images/connect_to_network.png" style="margin-top:-10px; margin-right:10px; float:right">
|
||||
<itoptabs>
|
||||
<itoptab name="Interfaces">
|
||||
<itopblock blockclass="DisplayBlock" type="list" encoding="text/oql">SELECT Interface AS i WHERE i.device_id = $id$</itopblock>
|
||||
</itoptab>
|
||||
<itoptab name="Contacts">
|
||||
<itopblock blockclass="DisplayBlock" type="list" encoding="text/oql">SELECT Contact AS c JOIN lnkContactToCI AS l ON l.contact_id = c.id WHERE l.ci_id = $id$</itopblock>
|
||||
</itoptab>
|
||||
<itoptab name="Documents">
|
||||
<itopblock blockclass="DisplayBlock" type="list" encoding="text/oql">SELECT Document AS d JOIN lnkDocumentToCI as l ON l.document_id = d.id WHERE l.ci_id = $id$)</itopblock>
|
||||
</itoptab>
|
||||
</itoptabs>';
|
||||
|
||||
$oPage = new iTopWebPage('Unit Test');
|
||||
//$oPage->add("Template content: <pre>".htmlentities($sTemplate, ENT_QUOTES, 'UTF-8')."</pre>\n");
|
||||
$oTemplate = new DisplayTemplate($sTemplate);
|
||||
$oTemplate->Render($oPage, array('class'=>'Network device','pkey'=> 271, 'name' => 'deliversw01.mecanorama.fr', 'org_id' => 3));
|
||||
$oPage->output();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Special type of template for displaying the details of an object
|
||||
* On top of the defaut 'blocks' managed by the parent class, the following placeholders
|
||||
* are available in such a template:
|
||||
* $attribute_code$ An attribute of the object (in edit mode this is the input for the attribute)
|
||||
* $attribute_code->label()$ The label of an attribute
|
||||
* $PlugIn:plugInClass->properties()$ The ouput of OnDisplayProperties of the specified plugInClass
|
||||
*/
|
||||
class ObjectDetailsTemplate extends DisplayTemplate
|
||||
{
|
||||
public function __construct($sTemplate, $oObj, $sFormPrefix = '')
|
||||
{
|
||||
parent::__construct($sTemplate);
|
||||
$this->m_oObj = $oObj;
|
||||
$this->m_sPrefix = $sFormPrefix;
|
||||
}
|
||||
|
||||
public function Render(WebPage $oPage, $aParams = array(), $bEditMode = false)
|
||||
{
|
||||
$sStateAttCode = MetaModel :: GetStateAttributeCode(get_class($this->m_oObj));
|
||||
$aTemplateFields = array();
|
||||
preg_match_all('/\\$this->([a-z0-9_]+)\\$/', $this->m_sTemplate, $aMatches);
|
||||
foreach ($aMatches[1] as $sAttCode)
|
||||
{
|
||||
if (MetaModel::IsValidAttCode(get_class($this->m_oObj), $sAttCode))
|
||||
{
|
||||
$aTemplateFields[] = $sAttCode;
|
||||
}
|
||||
else
|
||||
{
|
||||
$aParams['this->'.$sAttCode] = "<!--Unknown attribute: $sAttCode-->";
|
||||
}
|
||||
}
|
||||
preg_match_all('/\\$this->field\\(([a-z0-9_]+)\\)\\$/', $this->m_sTemplate, $aMatches);
|
||||
foreach ($aMatches[1] as $sAttCode)
|
||||
{
|
||||
if (MetaModel::IsValidAttCode(get_class($this->m_oObj), $sAttCode))
|
||||
{
|
||||
$aTemplateFields[] = $sAttCode;
|
||||
}
|
||||
else
|
||||
{
|
||||
$aParams['this->field('.$sAttCode.')'] = "<!--Unknown attribute: $sAttCode-->";
|
||||
}
|
||||
}
|
||||
$aFieldsComments = (isset($aParams['fieldsComments'])) ? $aParams['fieldsComments'] : array();
|
||||
$aFieldsMap = array();
|
||||
|
||||
$sClass = get_class($this->m_oObj);
|
||||
// Renders the fields used in the template
|
||||
foreach(MetaModel::ListAttributeDefs(get_class($this->m_oObj)) as $sAttCode => $oAttDef)
|
||||
{
|
||||
$aParams['this->label('.$sAttCode.')'] = $oAttDef->GetLabel();
|
||||
$aParams['this->comments('.$sAttCode.')'] = isset($aFieldsComments[$sAttCode]) ? $aFieldsComments[$sAttCode] : '';
|
||||
$iInputId = '2_'.$sAttCode; // TODO: generate a real/unique prefix...
|
||||
if (in_array($sAttCode, $aTemplateFields))
|
||||
{
|
||||
if ($this->m_oObj->IsNew())
|
||||
{
|
||||
$iFlags = $this->m_oObj->GetInitialStateAttributeFlags($sAttCode);
|
||||
}
|
||||
else
|
||||
{
|
||||
$iFlags = $this->m_oObj->GetAttributeFlags($sAttCode);
|
||||
}
|
||||
if (($iFlags & OPT_ATT_MANDATORY) && $this->m_oObj->IsNew())
|
||||
{
|
||||
$iFlags = $iFlags & ~OPT_ATT_READONLY; // Mandatory fields cannot be read-only when creating an object
|
||||
}
|
||||
|
||||
if ((!$oAttDef->IsWritable()) || ($sStateAttCode == $sAttCode))
|
||||
{
|
||||
$iFlags = $iFlags | OPT_ATT_READONLY;
|
||||
}
|
||||
|
||||
if ($iFlags & OPT_ATT_HIDDEN)
|
||||
{
|
||||
$aParams['this->label('.$sAttCode.')'] = '';
|
||||
$aParams['this->field('.$sAttCode.')'] = '';
|
||||
$aParams['this->comments('.$sAttCode.')'] = '';
|
||||
$aParams['this->'.$sAttCode] = '';
|
||||
}
|
||||
else
|
||||
{
|
||||
if ($bEditMode && ($iFlags & (OPT_ATT_READONLY|OPT_ATT_SLAVE)))
|
||||
{
|
||||
// Check if the attribute is not read-only because of a synchro...
|
||||
$aReasons = array();
|
||||
$sSynchroIcon = '';
|
||||
if ($iFlags & OPT_ATT_SLAVE)
|
||||
{
|
||||
$iSynchroFlags = $this->m_oObj->GetSynchroReplicaFlags($sAttCode, $aReasons);
|
||||
$sSynchroIcon = " <img id=\"synchro_$iInputId\" src=\"../images/transp-lock.png\" style=\"vertical-align:middle\"/>";
|
||||
$sTip = '';
|
||||
foreach($aReasons as $aRow)
|
||||
{
|
||||
$sDescription = htmlentities($aRow['description'], ENT_QUOTES, 'UTF-8');
|
||||
$sDescription = str_replace(array("\r\n", "\n"), "<br/>", $sDescription);
|
||||
$sTip .= "<div class='synchro-source'>";
|
||||
$sTip .= "<div class='synchro-source-title'>Synchronized with {$aRow['name']}</div>";
|
||||
$sTip .= "<div class='synchro-source-description'>$sDescription</div>";
|
||||
}
|
||||
$oPage->add_ready_script("$('#synchro_$iInputId').qtip( { content: '$sTip', show: 'mouseover', hide: 'mouseout', style: { name: 'dark', tip: 'leftTop' }, position: { corner: { target: 'rightMiddle', tooltip: 'leftTop' }} } );");
|
||||
}
|
||||
|
||||
// Attribute is read-only
|
||||
$sHTMLValue = "<span id=\"field_{$iInputId}\">".$this->m_oObj->GetAsHTML($sAttCode);
|
||||
$sHTMLValue .= '<input type="hidden" id="'.$iInputId.'" name="attr_'.$sAttCode.'" value="'.htmlentities($this->m_oObj->Get($sAttCode), ENT_QUOTES, 'UTF-8').'"/></span>';
|
||||
$aFieldsMap[$sAttCode] = $iInputId;
|
||||
$aParams['this->comments('.$sAttCode.')'] = $sSynchroIcon;
|
||||
}
|
||||
|
||||
if ($bEditMode && !($iFlags & OPT_ATT_READONLY)) //TODO: check the data synchro status...
|
||||
{
|
||||
$aParams['this->field('.$sAttCode.')'] = "<span id=\"field_{$iInputId}\">".$this->m_oObj->GetFormElementForField($oPage, $sClass, $sAttCode, $oAttDef,
|
||||
$this->m_oObj->Get($sAttCode),
|
||||
$this->m_oObj->GetEditValue($sAttCode),
|
||||
$iInputId, // InputID
|
||||
'',
|
||||
$iFlags,
|
||||
array('this' => $this->m_oObj) // aArgs
|
||||
).'</span>';
|
||||
$aFieldsMap[$sAttCode] = $iInputId;
|
||||
}
|
||||
else
|
||||
{
|
||||
$aParams['this->field('.$sAttCode.')'] = $this->m_oObj->GetAsHTML($sAttCode);
|
||||
}
|
||||
$aParams['this->'.$sAttCode] = "<table class=\"field\"><tr><td class=\"label\">".$aParams['this->label('.$sAttCode.')'].":</td><td>".$aParams['this->field('.$sAttCode.')']."</td><td>".$aParams['this->comments('.$sAttCode.')']."</td></tr></table>";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Renders the PlugIns used in the template
|
||||
preg_match_all('/\\$PlugIn:([A-Za-z0-9_]+)->properties\\(\\)\\$/', $this->m_sTemplate, $aMatches);
|
||||
$aPlugInProperties = $aMatches[1];
|
||||
foreach($aPlugInProperties as $sPlugInClass)
|
||||
{
|
||||
$oInstance = MetaModel::GetPlugins('iApplicationUIExtension', $sPlugInClass);
|
||||
if ($oInstance != null) // Safety check...
|
||||
{
|
||||
$offset = $oPage->start_capture();
|
||||
$oInstance->OnDisplayProperties($this->m_oObj, $oPage, $bEditMode);
|
||||
$sContent = $oPage->end_capture($offset);
|
||||
$aParams["PlugIn:{$sPlugInClass}->properties()"]= $sContent;
|
||||
}
|
||||
else
|
||||
{
|
||||
$aParams["PlugIn:{$sPlugInClass}->properties()"]= "Missing PlugIn: $sPlugInClass";
|
||||
}
|
||||
}
|
||||
|
||||
$offset = $oPage->start_capture();
|
||||
parent::Render($oPage, $aParams);
|
||||
$sContent = $oPage->end_capture($offset);
|
||||
// Remove empty table rows in case some attributes are hidden...
|
||||
$sContent = preg_replace('/<tr[^>]*>\s*(<td[^>]*>\s*<\\/td>)+\s*<\\/tr>/im', '', $sContent);
|
||||
$oPage->add($sContent);
|
||||
return $aFieldsMap;
|
||||
}
|
||||
}
|
||||
|
||||
//DisplayTemplate::UnitTest();
|
||||
?>
|
||||
<?php
|
||||
// Copyright (C) 2010-2017 Combodo SARL
|
||||
//
|
||||
// This file is part of iTop.
|
||||
//
|
||||
// iTop is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// iTop is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with iTop. If not, see <http://www.gnu.org/licenses/>
|
||||
|
||||
|
||||
/**
|
||||
* Class DisplayTemplate
|
||||
*
|
||||
* @copyright Copyright (C) 2010-2017 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
require_once(APPROOT.'/application/displayblock.class.inc.php');
|
||||
/**
|
||||
* This class manages the special template format used internally to build the iTop web pages
|
||||
*/
|
||||
class DisplayTemplate
|
||||
{
|
||||
protected $m_sTemplate;
|
||||
protected $m_aTags;
|
||||
static protected $iBlockCount = 0;
|
||||
|
||||
public function __construct($sTemplate)
|
||||
{
|
||||
$this->m_aTags = array (
|
||||
'itopblock',
|
||||
'itopcheck',
|
||||
'itoptabs',
|
||||
'itoptab',
|
||||
'itoptoggle',
|
||||
'itopstring',
|
||||
'sqlblock'
|
||||
);
|
||||
$this->m_sTemplate = $sTemplate;
|
||||
}
|
||||
|
||||
public function Render(WebPage $oPage, $aParams = array())
|
||||
{
|
||||
$this->m_sTemplate = MetaModel::ApplyParams($this->m_sTemplate, $aParams);
|
||||
$iStart = 0;
|
||||
$iEnd = strlen($this->m_sTemplate);
|
||||
$iCount = 0;
|
||||
$iBeforeTagPos = $iStart;
|
||||
$iAfterTagPos = $iStart;
|
||||
while($sTag = $this->GetNextTag($iStart, $iEnd))
|
||||
{
|
||||
$sContent = $this->GetTagContent($sTag, $iStart, $iEnd);
|
||||
$iAfterTagPos = $iEnd + strlen('</'.$sTag.'>');
|
||||
$sOuterTag = substr($this->m_sTemplate, $iStart, $iAfterTagPos - $iStart);
|
||||
$oPage->add(substr($this->m_sTemplate, $iBeforeTagPos, $iStart - $iBeforeTagPos));
|
||||
if ($sTag == DisplayBlock::TAG_BLOCK)
|
||||
{
|
||||
try
|
||||
{
|
||||
$oBlock = DisplayBlock::FromTemplate($sOuterTag);
|
||||
if (is_object($oBlock))
|
||||
{
|
||||
$oBlock->Display($oPage, 'block_'.self::$iBlockCount, $aParams);
|
||||
}
|
||||
}
|
||||
catch(OQLException $e)
|
||||
{
|
||||
$oPage->p('Error in template (please contact your administrator) - Invalid query<!--'.$sOuterTag.'-->');
|
||||
}
|
||||
catch(Exception $e)
|
||||
{
|
||||
$oPage->p('Error in template (please contact your administrator)<!--'.$e->getMessage().'--><!--'.$sOuterTag.'-->');
|
||||
}
|
||||
|
||||
self::$iBlockCount++;
|
||||
}
|
||||
else
|
||||
{
|
||||
$aAttributes = $this->GetTagAttributes($sTag, $iStart, $iEnd);
|
||||
//$oPage->p("Tag: $sTag - ($iStart, $iEnd)");
|
||||
$this->RenderTag($oPage, $sTag, $aAttributes, $sContent);
|
||||
|
||||
}
|
||||
$iAfterTagPos = $iEnd + strlen('</'.$sTag.'>');
|
||||
$iBeforeTagPos = $iAfterTagPos;
|
||||
$iStart = $iEnd;
|
||||
$iEnd = strlen($this->m_sTemplate);
|
||||
$iCount++;
|
||||
}
|
||||
$oPage->add(substr($this->m_sTemplate, $iAfterTagPos));
|
||||
}
|
||||
|
||||
public function GetNextTag(&$iStartPos, &$iEndPos)
|
||||
{
|
||||
$iChunkStartPos = $iStartPos;
|
||||
$sNextTag = null;
|
||||
$iStartPos = $iEndPos;
|
||||
foreach($this->m_aTags as $sTag)
|
||||
{
|
||||
// Search for the opening tag
|
||||
$iOpeningPos = stripos($this->m_sTemplate, '<'.$sTag.' ', $iChunkStartPos);
|
||||
if ($iOpeningPos === false)
|
||||
{
|
||||
$iOpeningPos = stripos($this->m_sTemplate, '<'.$sTag.'>', $iChunkStartPos);
|
||||
}
|
||||
if ($iOpeningPos !== false)
|
||||
{
|
||||
$iClosingPos = stripos($this->m_sTemplate, '</'.$sTag.'>', $iOpeningPos);
|
||||
}
|
||||
if ( ($iOpeningPos !== false) && ($iClosingPos !== false))
|
||||
{
|
||||
if ($iOpeningPos < $iStartPos)
|
||||
{
|
||||
// This is the next tag
|
||||
$iStartPos = $iOpeningPos;
|
||||
$iEndPos = $iClosingPos;
|
||||
$sNextTag = $sTag;
|
||||
}
|
||||
}
|
||||
}
|
||||
return $sNextTag;
|
||||
}
|
||||
|
||||
public function GetTagContent($sTag, $iStartPos, $iEndPos)
|
||||
{
|
||||
$sContent = "";
|
||||
$iContentStart = strpos($this->m_sTemplate, '>', $iStartPos); // Content of tag start immediatly after the first closing bracket
|
||||
if ($iContentStart !== false)
|
||||
{
|
||||
$sContent = substr($this->m_sTemplate, 1+$iContentStart, $iEndPos - $iContentStart - 1);
|
||||
}
|
||||
return $sContent;
|
||||
}
|
||||
|
||||
public function GetTagAttributes($sTag, $iStartPos, $iEndPos)
|
||||
{
|
||||
$aAttr = array();
|
||||
$iAttrStart = strpos($this->m_sTemplate, ' ', $iStartPos); // Attributes start just after the first space
|
||||
$iAttrEnd = strpos($this->m_sTemplate, '>', $iStartPos); // Attributes end just before the first closing bracket
|
||||
if ( ($iAttrStart !== false) && ($iAttrEnd !== false) && ($iAttrEnd > $iAttrStart))
|
||||
{
|
||||
$sAttributes = substr($this->m_sTemplate, 1+$iAttrStart, $iAttrEnd - $iAttrStart - 1);
|
||||
$aAttributes = explode(' ', $sAttributes);
|
||||
foreach($aAttributes as $sAttr)
|
||||
{
|
||||
if ( preg_match('/(.+) *= *"(.+)"$/', $sAttr, $aMatches) )
|
||||
{
|
||||
$aAttr[strtolower($aMatches[1])] = $aMatches[2];
|
||||
}
|
||||
}
|
||||
}
|
||||
return $aAttr;
|
||||
}
|
||||
|
||||
protected function RenderTag($oPage, $sTag, $aAttributes, $sContent)
|
||||
{
|
||||
static $iTabContainerCount = 0;
|
||||
switch($sTag)
|
||||
{
|
||||
case 'itoptabs':
|
||||
$oPage->AddTabContainer('Tabs_'.$iTabContainerCount);
|
||||
$oPage->SetCurrentTabContainer('Tabs_'.$iTabContainerCount);
|
||||
$iTabContainerCount++;
|
||||
//$oPage->p('Content:<pre>'.htmlentities($sContent, ENT_QUOTES, 'UTF-8').'</pre>');
|
||||
$oTemplate = new DisplayTemplate($sContent);
|
||||
$oTemplate->Render($oPage, array()); // no params to apply, they have already been applied
|
||||
$oPage->SetCurrentTabContainer('');
|
||||
break;
|
||||
|
||||
case 'itopcheck':
|
||||
$sClassName = $aAttributes['class'];
|
||||
if (MetaModel::IsValidClass($sClassName) && UserRights::IsActionAllowed($sClassName, UR_ACTION_READ))
|
||||
{
|
||||
$oTemplate = new DisplayTemplate($sContent);
|
||||
$oTemplate->Render($oPage, array()); // no params to apply, they have already been applied
|
||||
}
|
||||
else
|
||||
{
|
||||
// Leave a trace for those who'd like to understand why nothing is displayed
|
||||
$oPage->add("<!-- class $sClassName does not exist, skipping some part of the template -->\n");
|
||||
}
|
||||
break;
|
||||
|
||||
case 'itoptab':
|
||||
$oPage->SetCurrentTab(Dict::S(str_replace('_', ' ', $aAttributes['name'])));
|
||||
$oTemplate = new DisplayTemplate($sContent);
|
||||
$oTemplate->Render($oPage, array()); // no params to apply, they have already been applied
|
||||
//$oPage->p('iTop Tab Content:<pre>'.htmlentities($sContent, ENT_QUOTES, 'UTF-8').'</pre>');
|
||||
$oPage->SetCurrentTab('');
|
||||
break;
|
||||
|
||||
case 'itoptoggle':
|
||||
$sName = isset($aAttributes['name']) ? $aAttributes['name'] : 'Tagada';
|
||||
$bOpen = isset($aAttributes['open']) ? $aAttributes['open'] : true;
|
||||
$oPage->StartCollapsibleSection(Dict::S($sName), $bOpen);
|
||||
$oTemplate = new DisplayTemplate($sContent);
|
||||
$oTemplate->Render($oPage, array()); // no params to apply, they have already been applied
|
||||
//$oPage->p('iTop Tab Content:<pre>'.htmlentities($sContent, ENT_QUOTES, 'UTF-8').'</pre>');
|
||||
$oPage->EndCollapsibleSection();
|
||||
break;
|
||||
|
||||
case 'itopstring':
|
||||
$oPage->add(Dict::S($sContent));
|
||||
break;
|
||||
|
||||
case 'sqlblock':
|
||||
$oBlock = SqlBlock::FromTemplate($sContent);
|
||||
$oBlock->RenderContent($oPage);
|
||||
break;
|
||||
|
||||
case 'itopblock': // No longer used, handled by DisplayBlock::FromTemplate see above
|
||||
$oPage->add("<!-- Application Error: should be handled by DisplayBlock::FromTemplate -->");
|
||||
break;
|
||||
|
||||
default:
|
||||
// Unknown tag, just ignore it or now -- output an HTML comment
|
||||
$oPage->add("<!-- unsupported tag: $sTag -->");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Unit test
|
||||
*/
|
||||
static public function UnitTest()
|
||||
{
|
||||
require_once(APPROOT.'/application/startup.inc.php');
|
||||
require_once(APPROOT."/application/itopwebpage.class.inc.php");
|
||||
|
||||
$sTemplate = '<div class="page_header">
|
||||
<div class="actions_details"><a href="#"><span>Actions</span></a></div>
|
||||
<h1>$class$: <span class="hilite">$name$</span></h1>
|
||||
<itopblock blockclass="HistoryBlock" type="toggle" encoding="text/oql">SELECT CMDBChangeOp WHERE objkey = $id$ AND objclass = \'$class$\'</itopblock>
|
||||
</div>
|
||||
<img src="../../images/connect_to_network.png" style="margin-top:-10px; margin-right:10px; float:right">
|
||||
<itoptabs>
|
||||
<itoptab name="Interfaces">
|
||||
<itopblock blockclass="DisplayBlock" type="list" encoding="text/oql">SELECT Interface AS i WHERE i.device_id = $id$</itopblock>
|
||||
</itoptab>
|
||||
<itoptab name="Contacts">
|
||||
<itopblock blockclass="DisplayBlock" type="list" encoding="text/oql">SELECT Contact AS c JOIN lnkContactToCI AS l ON l.contact_id = c.id WHERE l.ci_id = $id$</itopblock>
|
||||
</itoptab>
|
||||
<itoptab name="Documents">
|
||||
<itopblock blockclass="DisplayBlock" type="list" encoding="text/oql">SELECT Document AS d JOIN lnkDocumentToCI as l ON l.document_id = d.id WHERE l.ci_id = $id$)</itopblock>
|
||||
</itoptab>
|
||||
</itoptabs>';
|
||||
|
||||
$oPage = new iTopWebPage('Unit Test');
|
||||
//$oPage->add("Template content: <pre>".htmlentities($sTemplate, ENT_QUOTES, 'UTF-8')."</pre>\n");
|
||||
$oTemplate = new DisplayTemplate($sTemplate);
|
||||
$oTemplate->Render($oPage, array('class'=>'Network device','pkey'=> 271, 'name' => 'deliversw01.mecanorama.fr', 'org_id' => 3));
|
||||
$oPage->output();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Special type of template for displaying the details of an object
|
||||
* On top of the defaut 'blocks' managed by the parent class, the following placeholders
|
||||
* are available in such a template:
|
||||
* $attribute_code$ An attribute of the object (in edit mode this is the input for the attribute)
|
||||
* $attribute_code->label()$ The label of an attribute
|
||||
* $PlugIn:plugInClass->properties()$ The ouput of OnDisplayProperties of the specified plugInClass
|
||||
*/
|
||||
class ObjectDetailsTemplate extends DisplayTemplate
|
||||
{
|
||||
public function __construct($sTemplate, $oObj, $sFormPrefix = '')
|
||||
{
|
||||
parent::__construct($sTemplate);
|
||||
$this->m_oObj = $oObj;
|
||||
$this->m_sPrefix = $sFormPrefix;
|
||||
}
|
||||
|
||||
public function Render(WebPage $oPage, $aParams = array(), $bEditMode = false)
|
||||
{
|
||||
$sStateAttCode = MetaModel :: GetStateAttributeCode(get_class($this->m_oObj));
|
||||
$aTemplateFields = array();
|
||||
preg_match_all('/\\$this->([a-z0-9_]+)\\$/', $this->m_sTemplate, $aMatches);
|
||||
foreach ($aMatches[1] as $sAttCode)
|
||||
{
|
||||
if (MetaModel::IsValidAttCode(get_class($this->m_oObj), $sAttCode))
|
||||
{
|
||||
$aTemplateFields[] = $sAttCode;
|
||||
}
|
||||
else
|
||||
{
|
||||
$aParams['this->'.$sAttCode] = "<!--Unknown attribute: $sAttCode-->";
|
||||
}
|
||||
}
|
||||
preg_match_all('/\\$this->field\\(([a-z0-9_]+)\\)\\$/', $this->m_sTemplate, $aMatches);
|
||||
foreach ($aMatches[1] as $sAttCode)
|
||||
{
|
||||
if (MetaModel::IsValidAttCode(get_class($this->m_oObj), $sAttCode))
|
||||
{
|
||||
$aTemplateFields[] = $sAttCode;
|
||||
}
|
||||
else
|
||||
{
|
||||
$aParams['this->field('.$sAttCode.')'] = "<!--Unknown attribute: $sAttCode-->";
|
||||
}
|
||||
}
|
||||
$aFieldsComments = (isset($aParams['fieldsComments'])) ? $aParams['fieldsComments'] : array();
|
||||
$aFieldsMap = array();
|
||||
|
||||
$sClass = get_class($this->m_oObj);
|
||||
// Renders the fields used in the template
|
||||
foreach(MetaModel::ListAttributeDefs(get_class($this->m_oObj)) as $sAttCode => $oAttDef)
|
||||
{
|
||||
$aParams['this->label('.$sAttCode.')'] = $oAttDef->GetLabel();
|
||||
$aParams['this->comments('.$sAttCode.')'] = isset($aFieldsComments[$sAttCode]) ? $aFieldsComments[$sAttCode] : '';
|
||||
$iInputId = '2_'.$sAttCode; // TODO: generate a real/unique prefix...
|
||||
if (in_array($sAttCode, $aTemplateFields))
|
||||
{
|
||||
if ($this->m_oObj->IsNew())
|
||||
{
|
||||
$iFlags = $this->m_oObj->GetInitialStateAttributeFlags($sAttCode);
|
||||
}
|
||||
else
|
||||
{
|
||||
$iFlags = $this->m_oObj->GetAttributeFlags($sAttCode);
|
||||
}
|
||||
if (($iFlags & OPT_ATT_MANDATORY) && $this->m_oObj->IsNew())
|
||||
{
|
||||
$iFlags = $iFlags & ~OPT_ATT_READONLY; // Mandatory fields cannot be read-only when creating an object
|
||||
}
|
||||
|
||||
if ((!$oAttDef->IsWritable()) || ($sStateAttCode == $sAttCode))
|
||||
{
|
||||
$iFlags = $iFlags | OPT_ATT_READONLY;
|
||||
}
|
||||
|
||||
if ($iFlags & OPT_ATT_HIDDEN)
|
||||
{
|
||||
$aParams['this->label('.$sAttCode.')'] = '';
|
||||
$aParams['this->field('.$sAttCode.')'] = '';
|
||||
$aParams['this->comments('.$sAttCode.')'] = '';
|
||||
$aParams['this->'.$sAttCode] = '';
|
||||
}
|
||||
else
|
||||
{
|
||||
if ($bEditMode && ($iFlags & (OPT_ATT_READONLY|OPT_ATT_SLAVE)))
|
||||
{
|
||||
// Check if the attribute is not read-only because of a synchro...
|
||||
$aReasons = array();
|
||||
$sSynchroIcon = '';
|
||||
if ($iFlags & OPT_ATT_SLAVE)
|
||||
{
|
||||
$iSynchroFlags = $this->m_oObj->GetSynchroReplicaFlags($sAttCode, $aReasons);
|
||||
$sSynchroIcon = " <img id=\"synchro_$iInputId\" src=\"../images/transp-lock.png\" style=\"vertical-align:middle\"/>";
|
||||
$sTip = '';
|
||||
foreach($aReasons as $aRow)
|
||||
{
|
||||
$sDescription = htmlentities($aRow['description'], ENT_QUOTES, 'UTF-8');
|
||||
$sDescription = str_replace(array("\r\n", "\n"), "<br/>", $sDescription);
|
||||
$sTip .= "<div class='synchro-source'>";
|
||||
$sTip .= "<div class='synchro-source-title'>Synchronized with {$aRow['name']}</div>";
|
||||
$sTip .= "<div class='synchro-source-description'>$sDescription</div>";
|
||||
}
|
||||
$oPage->add_ready_script("$('#synchro_$iInputId').qtip( { content: '$sTip', show: 'mouseover', hide: 'mouseout', style: { name: 'dark', tip: 'leftTop' }, position: { corner: { target: 'rightMiddle', tooltip: 'leftTop' }} } );");
|
||||
}
|
||||
|
||||
// Attribute is read-only
|
||||
$sHTMLValue = "<span id=\"field_{$iInputId}\">".$this->m_oObj->GetAsHTML($sAttCode);
|
||||
$sHTMLValue .= '<input type="hidden" id="'.$iInputId.'" name="attr_'.$sAttCode.'" value="'.htmlentities($this->m_oObj->Get($sAttCode), ENT_QUOTES, 'UTF-8').'"/></span>';
|
||||
$aFieldsMap[$sAttCode] = $iInputId;
|
||||
$aParams['this->comments('.$sAttCode.')'] = $sSynchroIcon;
|
||||
}
|
||||
|
||||
if ($bEditMode && !($iFlags & OPT_ATT_READONLY)) //TODO: check the data synchro status...
|
||||
{
|
||||
$aParams['this->field('.$sAttCode.')'] = "<span id=\"field_{$iInputId}\">".$this->m_oObj->GetFormElementForField($oPage, $sClass, $sAttCode, $oAttDef,
|
||||
$this->m_oObj->Get($sAttCode),
|
||||
$this->m_oObj->GetEditValue($sAttCode),
|
||||
$iInputId, // InputID
|
||||
'',
|
||||
$iFlags,
|
||||
array('this' => $this->m_oObj) // aArgs
|
||||
).'</span>';
|
||||
$aFieldsMap[$sAttCode] = $iInputId;
|
||||
}
|
||||
else
|
||||
{
|
||||
$aParams['this->field('.$sAttCode.')'] = $this->m_oObj->GetAsHTML($sAttCode);
|
||||
}
|
||||
$aParams['this->'.$sAttCode] = "<table class=\"field\"><tr><td class=\"label\">".$aParams['this->label('.$sAttCode.')'].":</td><td>".$aParams['this->field('.$sAttCode.')']."</td><td>".$aParams['this->comments('.$sAttCode.')']."</td></tr></table>";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Renders the PlugIns used in the template
|
||||
preg_match_all('/\\$PlugIn:([A-Za-z0-9_]+)->properties\\(\\)\\$/', $this->m_sTemplate, $aMatches);
|
||||
$aPlugInProperties = $aMatches[1];
|
||||
foreach($aPlugInProperties as $sPlugInClass)
|
||||
{
|
||||
/** @var \iApplicationUIExtension $oInstance */
|
||||
$oInstance = MetaModel::GetPlugins('iApplicationUIExtension', $sPlugInClass);
|
||||
if ($oInstance != null) // Safety check...
|
||||
{
|
||||
$offset = $oPage->start_capture();
|
||||
$oInstance->OnDisplayProperties($this->m_oObj, $oPage, $bEditMode);
|
||||
$sContent = $oPage->end_capture($offset);
|
||||
$aParams["PlugIn:{$sPlugInClass}->properties()"]= $sContent;
|
||||
}
|
||||
else
|
||||
{
|
||||
$aParams["PlugIn:{$sPlugInClass}->properties()"]= "Missing PlugIn: $sPlugInClass";
|
||||
}
|
||||
}
|
||||
|
||||
$offset = $oPage->start_capture();
|
||||
parent::Render($oPage, $aParams);
|
||||
$sContent = $oPage->end_capture($offset);
|
||||
// Remove empty table rows in case some attributes are hidden...
|
||||
$sContent = preg_replace('/<tr[^>]*>\s*(<td[^>]*>\s*<\\/td>)+\s*<\\/tr>/im', '', $sContent);
|
||||
$oPage->add($sContent);
|
||||
return $aFieldsMap;
|
||||
}
|
||||
}
|
||||
|
||||
//DisplayTemplate::UnitTest();
|
||||
?>
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
<div class="page_header">
|
||||
<itopblock blockclass="MenuBlock" type="popup" encoding="text/oql" label="Actions">SELECT $class$ WHERE id = $id$</itopblock>
|
||||
<h1>$class$: <span class="hilite">$name$</span></h1>
|
||||
<itopblock blockclass="HistoryBlock" type="toggle" encoding="text/oql">SELECT CMDBChangeOp WHERE objkey = $id$ AND objclass = '$class$'</itopblock>
|
||||
</div>
|
||||
<img src="../../images/clean.png" style="margin-top:-20px; margin-right:10px; float:right">
|
||||
<itopblock blockclass="DisplayBlock" asynchronous="false" type="bare_details" encoding="text/oql">SELECT $class$ WHERE id = $id$</itopblock>
|
||||
<itoptabs>
|
||||
<itoptab name="Rules">
|
||||
<itopblock blockclass="DisplayBlock" type="list" encoding="text/oql">SELECT AuditRule WHERE category_id = $id$</itopblock>
|
||||
</itoptab>
|
||||
</itoptabs>
|
||||
<div class="page_header">
|
||||
<itopblock blockclass="MenuBlock" type="popup" encoding="text/oql" label="Actions">SELECT $class$ WHERE id = $id$</itopblock>
|
||||
<h1>$class$: <span class="hilite">$name$</span></h1>
|
||||
<itopblock blockclass="HistoryBlock" type="toggle" encoding="text/oql">SELECT CMDBChangeOp WHERE objkey = $id$ AND objclass = '$class$'</itopblock>
|
||||
</div>
|
||||
<img src="../../images/clean.png" style="margin-top:-20px; margin-right:10px; float:right">
|
||||
<itopblock blockclass="DisplayBlock" asynchronous="false" type="bare_details" encoding="text/oql">SELECT $class$ WHERE id = $id$</itopblock>
|
||||
<itoptabs>
|
||||
<itoptab name="Rules">
|
||||
<itopblock blockclass="DisplayBlock" type="list" encoding="text/oql">SELECT AuditRule WHERE category_id = $id$</itopblock>
|
||||
</itoptab>
|
||||
</itoptabs>
|
||||
|
||||
@@ -26,8 +26,6 @@
|
||||
* @copyright Copyright (C) 2010-2012 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
|
||||
class privUITransaction
|
||||
{
|
||||
/**
|
||||
@@ -99,9 +97,10 @@ class privUITransaction
|
||||
}
|
||||
|
||||
/**
|
||||
* The original (and by default) mechanism for storing transaction information
|
||||
* as an array in the $_SESSION variable
|
||||
* The original mechanism for storing transaction information as an array in the $_SESSION variable
|
||||
*
|
||||
* Warning, since 2.6.0 the session is regenerated on each login (see PR #20) !
|
||||
* Also, we saw some problems when using memcached as the PHP session implementation (see N°1835)
|
||||
*/
|
||||
class privUITransactionSession
|
||||
{
|
||||
@@ -119,7 +118,7 @@ class privUITransactionSession
|
||||
// Strictly speaking, the two lines below should be grouped together
|
||||
// by a critical section
|
||||
// sem_acquire($rSemIdentified);
|
||||
$id = str_replace(array('.', ' '), '', microtime()); //1 + count($_SESSION['transactions']);
|
||||
$id = static::GetUserPrefix() . str_replace(array('.', ' '), '', microtime()); //1 + count($_SESSION['transactions']);
|
||||
$_SESSION['transactions'][$id] = true;
|
||||
// sem_release($rSemIdentified);
|
||||
|
||||
@@ -174,6 +173,17 @@ class privUITransactionSession
|
||||
// sem_release($rSemIdentified);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a string to prefix transaction ID with info from the current user.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected static function GetUserPrefix()
|
||||
{
|
||||
$sPrefix = 'u'.UserRights::GetUserId();
|
||||
return $sPrefix.'-';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -183,10 +193,35 @@ class privUITransactionSession
|
||||
*/
|
||||
class privUITransactionFile
|
||||
{
|
||||
/** @var int Value to use when no user logged */
|
||||
const UNAUTHENTICATED_USER_ID = -666;
|
||||
|
||||
/**
|
||||
* @return int current user id, or {@see self::UNAUTHENTICATED_USER_ID} if no user logged
|
||||
*
|
||||
* @since 2.6.5 2.7.6 3.0.0 N°4289 method creation
|
||||
*/
|
||||
private static function GetCurrentUserId()
|
||||
{
|
||||
$iCurrentUserId = UserRights::GetConnectedUserId();
|
||||
if ('' === $iCurrentUserId) {
|
||||
$iCurrentUserId = static::UNAUTHENTICATED_USER_ID;
|
||||
}
|
||||
|
||||
return $iCurrentUserId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new transaction id, store it in the session and return its id
|
||||
*
|
||||
* @param void
|
||||
*
|
||||
* @return int The identifier of the new transaction
|
||||
*
|
||||
* @throws \SecurityException
|
||||
* @throws \Exception
|
||||
*
|
||||
* @since 2.6.5 2.7.6 3.0.0 security hardening + throws SecurityException if no user logged
|
||||
*/
|
||||
public static function GetNewTransactionId()
|
||||
{
|
||||
@@ -196,82 +231,102 @@ class privUITransactionFile
|
||||
{
|
||||
throw new Exception('The directory "'.APPROOT.'data" must be writable to the application.');
|
||||
}
|
||||
/** @noinspection MkdirRaceConditionInspection */
|
||||
if (!@mkdir(APPROOT.'data/transactions'))
|
||||
{
|
||||
throw new Exception('Failed to create the directory "'.APPROOT.'data/transactions". Ajust the rights on the parent directory or let an administrator create the transactions directory and give the web sever enough rights to write into it.');
|
||||
}
|
||||
}
|
||||
|
||||
if (!is_writable(APPROOT.'data/transactions'))
|
||||
{
|
||||
throw new Exception('The directory "'.APPROOT.'data/transactions" must be writable to the application.');
|
||||
}
|
||||
self::CleanupOldTransactions();
|
||||
$id = basename(tempnam(APPROOT.'data/transactions', self::GetUserPrefix()));
|
||||
self::Info('GetNewTransactionId: Created transaction: '.$id);
|
||||
|
||||
return (string)$id;
|
||||
$iCurrentUserId = static::GetCurrentUserId();
|
||||
|
||||
self::CleanupOldTransactions();
|
||||
|
||||
$sTransactionIdFullPath = tempnam(APPROOT.'data/transactions', static::GetUserPrefix());
|
||||
file_put_contents($sTransactionIdFullPath, $iCurrentUserId, LOCK_EX);
|
||||
|
||||
$sTransactionIdFileName = basename($sTransactionIdFullPath);
|
||||
self::Info('GetNewTransactionId: Created transaction: '.$sTransactionIdFileName);
|
||||
|
||||
return $sTransactionIdFileName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether a transaction is valid or not and (optionally) remove the valid transaction from
|
||||
* the session so that another call to IsTransactionValid for the same transaction id
|
||||
* will return false
|
||||
*
|
||||
* @param int $id Identifier of the transaction, as returned by GetNewTransactionId
|
||||
* @param bool $bRemoveTransaction True if the transaction must be removed
|
||||
*
|
||||
* @return bool True if the transaction is valid, false otherwise
|
||||
*
|
||||
* @since 2.6.5 2.7.6 3.0.0 N°4289 security hardening
|
||||
*/
|
||||
public static function IsTransactionValid($id, $bRemoveTransaction = true)
|
||||
{
|
||||
$sFilepath = APPROOT.'data/transactions/'.$id;
|
||||
// Constraint the transaction file within APPROOT.'data/transactions'
|
||||
$sTransactionDir = realpath(APPROOT.'data/transactions');
|
||||
$sFilepath = utils::RealPath($sTransactionDir.'/'.$id, $sTransactionDir);
|
||||
if (($sFilepath === false) || (strlen($sTransactionDir) == strlen($sFilepath)))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
clearstatcache(true, $sFilepath);
|
||||
$bResult = file_exists($sFilepath);
|
||||
if ($bResult)
|
||||
|
||||
if (false === $bResult) {
|
||||
self::Info("IsTransactionValid: Transaction '$id' not found. Pending transactions:\n".implode("\n", self::GetPendingTransactions()));
|
||||
return false;
|
||||
}
|
||||
|
||||
$iCurrentUserId = static::GetCurrentUserId();
|
||||
$sTransactionIdUserId = file_get_contents($sFilepath);
|
||||
if ($iCurrentUserId != $sTransactionIdUserId) {
|
||||
self::Info("IsTransactionValid: Transaction '$id' not existing for current user. Pending transactions:\n".implode("\n", self::GetPendingTransactions()));
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($bRemoveTransaction)
|
||||
{
|
||||
if ($bRemoveTransaction)
|
||||
$bResult = @unlink($sFilepath);
|
||||
if (!$bResult)
|
||||
{
|
||||
$bResult = @unlink($sFilepath);
|
||||
if (!$bResult)
|
||||
{
|
||||
self::Error('IsTransactionValid: FAILED to remove transaction '.$id);
|
||||
}
|
||||
else
|
||||
{
|
||||
self::Info('IsTransactionValid: OK. Removed transaction: '.$id);
|
||||
}
|
||||
self::Error('IsTransactionValid: FAILED to remove transaction '.$id);
|
||||
}
|
||||
else
|
||||
{
|
||||
self::Info('IsTransactionValid: OK. Removed transaction: '.$id);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
self::Info("IsTransactionValid: Transaction '$id' not found. Pending transactions for this user:\n".implode("\n", self::GetPendingTransactions()));
|
||||
}
|
||||
|
||||
return $bResult;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the transaction specified by its id
|
||||
* @param int $id The Identifier (as returned by GetNewTransactionId) of the transaction to be removed.
|
||||
* @return void
|
||||
* @return bool true if the token can be removed
|
||||
*
|
||||
* @since 2.6.5 2.7.6 3.0.0 N°4289 security hardening
|
||||
*/
|
||||
public static function RemoveTransaction($id)
|
||||
{
|
||||
$bSuccess = true;
|
||||
$sFilepath = APPROOT.'data/transactions/'.$id;
|
||||
clearstatcache(true, $sFilepath);
|
||||
if(!file_exists($sFilepath))
|
||||
{
|
||||
$bSuccess = false;
|
||||
self::Error("RemoveTransaction: Transaction '$id' not found. Pending transactions for this user:\n".implode("\n", self::GetPendingTransactions()));
|
||||
/** @noinspection PhpRedundantOptionalArgumentInspection */
|
||||
$bResult = static::IsTransactionValid($id, true);
|
||||
if (false === $bResult) {
|
||||
self::Error("RemoveTransaction: Transaction '$id' is invalid. Pending transactions:\n"
|
||||
.implode("\n", self::GetPendingTransactions()));
|
||||
return false;
|
||||
}
|
||||
$bSuccess = @unlink($sFilepath);
|
||||
if (!$bSuccess)
|
||||
{
|
||||
self::Error('RemoveTransaction: FAILED to remove transaction '.$id);
|
||||
}
|
||||
else
|
||||
{
|
||||
self::Info('RemoveTransaction: OK '.$id);
|
||||
}
|
||||
return $bSuccess;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -310,6 +365,11 @@ class privUITransactionFile
|
||||
return $aResult;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a prefix based on the user login instead of its ID for a better usage in tempnam()
|
||||
*
|
||||
* @inheritdoc
|
||||
*/
|
||||
protected static function GetUserPrefix()
|
||||
{
|
||||
$sPrefix = substr(UserRights::GetUser(), 0, 10);
|
||||
@@ -331,22 +391,35 @@ class privUITransactionFile
|
||||
{
|
||||
self::Write('Error | '.$sText);
|
||||
}
|
||||
|
||||
|
||||
protected static function IsLogEnabled() {
|
||||
$oConfig = MetaModel::GetConfig();
|
||||
if (is_null($oConfig)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$bLogTransactions = $oConfig->Get('log_transactions');
|
||||
if (true === $bLogTransactions) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
protected static function Write($sText)
|
||||
{
|
||||
$bLogEnabled = MetaModel::GetConfig()->Get('log_transactions');
|
||||
if ($bLogEnabled)
|
||||
{
|
||||
if (false === static::IsLogEnabled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
$hLogFile = @fopen(APPROOT.'log/transactions.log', 'a');
|
||||
if ($hLogFile !== false)
|
||||
{
|
||||
if ($hLogFile !== false) {
|
||||
flock($hLogFile, LOCK_EX);
|
||||
$sDate = date('Y-m-d H:i:s');
|
||||
fwrite($hLogFile, "$sDate | $sText\n");
|
||||
fflush($hLogFile);
|
||||
flock($hLogFile, LOCK_UN);
|
||||
fclose($hLogFile);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,15 +19,15 @@
|
||||
* Class UIExtKeyWidget
|
||||
* UI wdiget for displaying and editing external keys when
|
||||
* A simple drop-down list is not enough...
|
||||
*
|
||||
*
|
||||
* The layout is the following
|
||||
*
|
||||
*
|
||||
* +-- #label_<id> (input)-------+ +-----------+
|
||||
* | | | Browse... |
|
||||
* +-----------------------------+ +-----------+
|
||||
*
|
||||
*
|
||||
* And the popup dialog has the following layout:
|
||||
*
|
||||
*
|
||||
* +------------------- ac_dlg_<id> (div)-----------+
|
||||
* + +--- ds_<id> (div)---------------------------+ |
|
||||
* | | +------------- fs_<id> (form)------------+ | |
|
||||
@@ -61,13 +61,16 @@
|
||||
require_once(APPROOT.'/application/webpage.class.inc.php');
|
||||
require_once(APPROOT.'/application/displayblock.class.inc.php');
|
||||
|
||||
class UIExtKeyWidget
|
||||
class UIExtKeyWidget
|
||||
{
|
||||
const ENUM_OUTPUT_FORMAT_CSV = 'csv';
|
||||
const ENUM_OUTPUT_FORMAT_JSON = 'json';
|
||||
|
||||
protected $iId;
|
||||
protected $sTargetClass;
|
||||
protected $sAttCode;
|
||||
protected $bSearchMode;
|
||||
|
||||
|
||||
//public function __construct($sAttCode, $sClass, $sTitle, $oAllowedValues, $value, $iInputId, $bMandatory, $sNameSuffix = '', $sFieldPrefix = '', $sFormPrefix = '')
|
||||
static public function DisplayFromAttCode($oPage, $sAttCode, $sClass, $sTitle, $oAllowedValues, $value, $iInputId, $bMandatory, $sFieldName = '', $sFormPrefix = '', $aArgs, $bSearchMode = false)
|
||||
{
|
||||
@@ -94,11 +97,11 @@ class UIExtKeyWidget
|
||||
$this->sAttCode = $sAttCode;
|
||||
$this->bSearchMode = $bSearchMode;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the HTML fragment corresponding to the ext key editing widget
|
||||
* @param WebPage $oP The web page used for all the output
|
||||
* @param Hash $aArgs Extra context arguments
|
||||
* @param array $aArgs Extra context arguments
|
||||
* @return string The HTML fragment to be inserted into the page
|
||||
*/
|
||||
public function Display(WebPage $oPage, $iMaxComboLength, $bAllowTargetCreation, $sTitle, DBObjectset $oAllowedValues, $value, $iInputId, $bMandatory, $sFieldName, $sFormPrefix = '', $aArgs = array(), $bSearchMode = null, $sDisplayStyle = 'select', $bSearchMultiple = true)
|
||||
@@ -107,10 +110,10 @@ class UIExtKeyWidget
|
||||
{
|
||||
$this->bSearchMode = $bSearchMode;
|
||||
}
|
||||
$sTitle = addslashes($sTitle);
|
||||
$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');
|
||||
@@ -123,7 +126,7 @@ class UIExtKeyWidget
|
||||
$sWizHelper = 'null';
|
||||
$sWizHelperJSON = "''";
|
||||
$sJSSearchMode = 'true';
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (isset($aArgs['wizHelper']))
|
||||
@@ -142,7 +145,12 @@ class UIExtKeyWidget
|
||||
throw new Exception('Implementation: null value for allowed values definition');
|
||||
}
|
||||
$oAllowedValues->SetShowObsoleteData(utils::ShowObsoleteData());
|
||||
if ($oAllowedValues->Count() < $iMaxComboLength)
|
||||
// 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
|
||||
switch($sDisplayStyle)
|
||||
@@ -159,7 +167,7 @@ class UIExtKeyWidget
|
||||
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';
|
||||
break;
|
||||
@@ -167,8 +175,7 @@ class UIExtKeyWidget
|
||||
case 'select':
|
||||
case 'list':
|
||||
default:
|
||||
$sSelectMode = 'true';
|
||||
|
||||
|
||||
$sHelpText = ''; //$this->oAttDef->GetHelpOnEdition();
|
||||
$sHTMLValue .= "<div class=\"field_select_wrapper\">\n";
|
||||
|
||||
@@ -196,17 +203,25 @@ class UIExtKeyWidget
|
||||
{
|
||||
$key = $oObj->GetKey();
|
||||
$display_value = $oObj->GetName();
|
||||
|
||||
|
||||
if (($oAllowedValues->Count() == 1) && ($bMandatory == 'true') )
|
||||
{
|
||||
// When there is only once choice, select it by default
|
||||
$sSelected = ' selected';
|
||||
$sSelected = 'selected';
|
||||
if($value != $key)
|
||||
{
|
||||
$oPage->add_ready_script(
|
||||
<<<EOF
|
||||
$('#$this->iId').attr('data-validate','dependencies');
|
||||
EOF
|
||||
);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$sSelected = (is_array($value) && in_array($key, $value)) || ($value == $key) ? ' selected' : '';
|
||||
$sSelected = (is_array($value) && in_array($key, $value)) || ($value == $key) ? 'selected' : '';
|
||||
}
|
||||
$sHTMLValue .= "<option value=\"$key\"$sSelected>$display_value</option>\n";
|
||||
$sHTMLValue .= "<option value=\"$key\" $sSelected>$display_value</option>\n";
|
||||
}
|
||||
$sHTMLValue .= "</select>\n";
|
||||
$sHTMLValue .= "</div>\n";
|
||||
@@ -226,7 +241,7 @@ class UIExtKeyWidget
|
||||
}
|
||||
$oPage->add_ready_script(
|
||||
<<<EOF
|
||||
oACWidget_{$this->iId} = new ExtKeyWidget('{$this->iId}', '{$this->sTargetClass}', '$sFilter', '$sTitle', true, $sWizHelper, '{$this->sAttCode}', $sJSSearchMode);
|
||||
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(); } );
|
||||
$('#$this->iId').bind('change', function() { $(this).trigger('extkeychange') } );
|
||||
@@ -238,8 +253,6 @@ EOF
|
||||
else
|
||||
{
|
||||
// Too many choices, use an autocomplete
|
||||
$sSelectMode = 'false';
|
||||
|
||||
// Check that the given value is allowed
|
||||
$oSearch = $oAllowedValues->GetFilter();
|
||||
$oSearch->AddCondition('id', $value);
|
||||
@@ -258,20 +271,19 @@ EOF
|
||||
$sDisplayValue = $this->GetObjectName($value);
|
||||
}
|
||||
$iMinChars = isset($aArgs['iMinChars']) ? $aArgs['iMinChars'] : 3; //@@@ $this->oAttDef->GetMinAutoCompleteChars();
|
||||
$iFieldSize = isset($aArgs['iFieldSize']) ? $aArgs['iFieldSize'] : 20; //@@@ $this->oAttDef->GetMaxSize();
|
||||
|
||||
|
||||
// the input for the auto-complete
|
||||
$sHTMLValue .= "<input class=\"field_autocomplete\" count=\"".$oAllowedValues->Count()."\" type=\"text\" id=\"label_$this->iId\" value=\"$sDisplayValue\"/>";
|
||||
$sHTMLValue .= "<span class=\"field_input_btn\"><img id=\"mini_search_{$this->iId}\" style=\"border:0;vertical-align:middle;cursor:pointer;\" src=\"../images/mini_search.gif?itopversion=".ITOP_VERSION."\" onClick=\"oACWidget_{$this->iId}.Search();\"/></span>";
|
||||
|
||||
$sHTMLValue .= "<input class=\"field_autocomplete\" type=\"text\" id=\"label_$this->iId\" value=\"$sDisplayValue\"/>";
|
||||
$sHTMLValue .= "<span class=\"field_input_btn\"><img id=\"mini_search_{$this->iId}\" style=\"border:0;vertical-align:middle;cursor:pointer;\" src=\"../images/mini_search.gif?t=".utils::GetCacheBusterTimestamp()."\" onClick=\"oACWidget_{$this->iId}.Search();\"/></span>";
|
||||
|
||||
// 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';
|
||||
$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);
|
||||
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 !
|
||||
@@ -286,7 +298,7 @@ EOF
|
||||
}
|
||||
if ($bExtensions && MetaModel::IsHierarchicalClass($this->sTargetClass) !== false)
|
||||
{
|
||||
$sHTMLValue .= "<span class=\"field_input_btn\"><img id=\"mini_tree_{$this->iId}\" style=\"border:0;vertical-align:middle;cursor:pointer;\" src=\"../images/mini_tree.gif?itopversion=".ITOP_VERSION."\" onClick=\"oACWidget_{$this->iId}.HKDisplay();\"/></span>";
|
||||
$sHTMLValue .= "<span class=\"field_input_btn\"><img id=\"mini_tree_{$this->iId}\" style=\"border:0;vertical-align:middle;cursor:pointer;\" src=\"../images/mini_tree.gif?t=".utils::GetCacheBusterTimestamp()."\" onClick=\"oACWidget_{$this->iId}.HKDisplay();\"/></span>";
|
||||
$oPage->add_ready_script(
|
||||
<<<EOF
|
||||
if ($('#ac_tree_{$this->iId}').length == 0)
|
||||
@@ -300,7 +312,7 @@ EOF
|
||||
{
|
||||
$sCallbackName = (MetaModel::IsAbstract($this->sTargetClass)) ? 'SelectObjectClass' : 'CreateObject';
|
||||
|
||||
$sHTMLValue .= "<span class=\"field_input_btn\"><img id=\"mini_add_{$this->iId}\" style=\"border:0;vertical-align:middle;cursor:pointer;\" src=\"../images/mini_add.gif?itopversion=".ITOP_VERSION."\" onClick=\"oACWidget_{$this->iId}.{$sCallbackName}();\"/></span>";
|
||||
$sHTMLValue .= "<span class=\"field_input_btn\"><img id=\"mini_add_{$this->iId}\" style=\"border:0;vertical-align:middle;cursor:pointer;\" src=\"../images/mini_add.gif?t=".utils::GetCacheBusterTimestamp()."\" onClick=\"oACWidget_{$this->iId}.{$sCallbackName}();\"/></span>";
|
||||
$oPage->add_ready_script(
|
||||
<<<EOF
|
||||
if ($('#ajax_{$this->iId}').length == 0)
|
||||
@@ -320,7 +332,7 @@ EOF
|
||||
|
||||
return $sHTMLValue;
|
||||
}
|
||||
|
||||
|
||||
public function GetSearchDialog(WebPage $oPage, $sTitle, $oCurrObject = null)
|
||||
{
|
||||
$sHTML = '<div class="wizContainer" style="vertical-align:top;"><div id="dc_'.$this->iId.'">';
|
||||
@@ -328,7 +340,8 @@ EOF
|
||||
if ( ($oCurrObject != null) && ($this->sAttCode != ''))
|
||||
{
|
||||
$oAttDef = MetaModel::GetAttributeDef(get_class($oCurrObject), $this->sAttCode);
|
||||
$aArgs = array('this' => $oCurrObject);
|
||||
/** @var \DBObject $oCurrObject */
|
||||
$aArgs = $oCurrObject->ToArgsForQuery();
|
||||
$aParams = array('query_params' => $aArgs);
|
||||
$oSet = $oAttDef->GetAllowedValuesAsObjectSet($aArgs);
|
||||
$oFilter = $oSet->GetFilter();
|
||||
@@ -338,10 +351,18 @@ EOF
|
||||
$aParams = array();
|
||||
$oFilter = new DBObjectSearch($this->sTargetClass);
|
||||
}
|
||||
$bOpen = MetaModel::GetConfig()->Get('legacy_search_drawer_open');
|
||||
$oFilter->SetModifierProperty('UserRightsGetSelectFilter', 'bSearchMode', $this->bSearchMode);
|
||||
$oBlock = new DisplayBlock($oFilter, 'search', false, $aParams);
|
||||
$sHTML .= $oBlock->GetDisplay($oPage, $this->iId, array('open' => $bOpen, 'currentId' => $this->iId));
|
||||
$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";
|
||||
@@ -352,10 +373,10 @@ EOF
|
||||
$sHTML .= "</form>\n";
|
||||
$sHTML .= '</div></div>';
|
||||
|
||||
$sDialogTitle = addslashes($sTitle);
|
||||
$sDialogTitleSanitized = addslashes(utils::HtmlToText($sTitle));
|
||||
$oPage->add_ready_script(
|
||||
<<<EOF
|
||||
$('#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 });
|
||||
$('#ac_dlg_{$this->iId}').dialog({ width: $(window).width()*0.8, height: $(window).height()*0.8, autoOpen: false, modal: true, title: '$sDialogTitleSanitized', 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
|
||||
@@ -365,9 +386,13 @@ EOF
|
||||
|
||||
/**
|
||||
* Search for objects to be selected
|
||||
*
|
||||
* @param WebPage $oP The page used for the output (usually an AjaxWebPage)
|
||||
* @param $sFilter
|
||||
* @param string $sRemoteClass Name of the "remote" class to perform the search on, must be a derived class of m_sRemoteClass
|
||||
* @param Array $aAlreadyLinkedIds List of IDs of objects of "remote" class already linked, to be filtered out of the search
|
||||
* @param null $oObj
|
||||
*
|
||||
* @throws \OQLException
|
||||
*/
|
||||
public function SearchObjectsToSelect(WebPage $oP, $sFilter, $sRemoteClass = '', $oObj = null)
|
||||
{
|
||||
@@ -375,7 +400,7 @@ EOF
|
||||
{
|
||||
throw new Exception('Implementation: null value for allowed values definition');
|
||||
}
|
||||
|
||||
|
||||
$oFilter = DBObjectSearch::FromOQL($sFilter);
|
||||
if (strlen($sRemoteClass) > 0)
|
||||
{
|
||||
@@ -386,18 +411,24 @@ EOF
|
||||
// Current extkey value, so we can display event if it is not available anymore (eg. archived).
|
||||
$iCurrentExtKeyId = (is_null($oObj)) ? 0 : $oObj->Get($this->sAttCode);
|
||||
|
||||
$oBlock = new DisplayBlock($oFilter, 'list', false, array('query_params' => array('this' => $oObj, 'current_extkey_id' => $iCurrentExtKeyId)));
|
||||
$oBlock = new DisplayBlock($oFilter, 'list_search', false, array('query_params' => array('this' => $oObj, 'current_extkey_id' => $iCurrentExtKeyId)));
|
||||
$oBlock->Display($oP, $this->iId.'_results', array('this' => $oObj, 'cssCount'=> '#count_'.$this->iId, 'menu' => false, 'selection_mode' => true, 'selection_type' => 'single', 'table_id' => 'select_'.$this->sAttCode)); // Don't display the 'Actions' menu on the results
|
||||
}
|
||||
|
||||
/**
|
||||
* Search for objects to be selected
|
||||
* @param WebPage $oP The page used for the output (usually an AjaxWebPage)
|
||||
* @param string $sFilter The OQL expression used to define/limit limit the scope of possible values
|
||||
* @param DBObject $oObj The current object for the OQL context
|
||||
* @param string $sContains The text of the autocomplete to filter the results
|
||||
*/
|
||||
public function AutoComplete(WebPage $oP, $sFilter, $oObj = null, $sContains)
|
||||
|
||||
/**
|
||||
* Search for objects to be selected
|
||||
*
|
||||
* @param WebPage $oP The page used for the output (usually an AjaxWebPage)
|
||||
* @param string $sFilter The OQL expression used to define/limit limit the scope of possible values
|
||||
* @param DBObject $oObj The current object for the OQL context
|
||||
* @param string $sContains The text of the autocomplete to filter the results
|
||||
* @param string $sOutputFormat
|
||||
* @param null $sOperation for the values @see ValueSetObjects->LoadValues()
|
||||
*
|
||||
* @throws CoreException
|
||||
* @throws OQLException
|
||||
*/
|
||||
public function AutoComplete(WebPage $oP, $sFilter, $oObj = null, $sContains, $sOutputFormat = self::ENUM_OUTPUT_FORMAT_CSV, $sOperation = null)
|
||||
{
|
||||
if (is_null($sFilter))
|
||||
{
|
||||
@@ -408,14 +439,48 @@ EOF
|
||||
$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);
|
||||
$aValues = $oValuesSet->GetValues(array('this' => $oObj, 'current_extkey_id' => $iCurrentExtKeyId), $sContains);
|
||||
foreach($aValues as $sKey => $sFriendlyName)
|
||||
$oValuesSet->SetLimit($iMax);
|
||||
$aValuesContains = $oValuesSet->GetValues(array('this' => $oObj, 'current_extkey_id' => $iCurrentExtKeyId), $sContains, 'contains');
|
||||
asort($aValuesContains);
|
||||
$aValues = array();
|
||||
foreach($aValuesContains as $sKey => $sFriendlyName)
|
||||
{
|
||||
$oP->add(trim($sFriendlyName)."\t".$sKey."\n");
|
||||
if (!isset($aValues[$sKey]))
|
||||
{
|
||||
$aValues[$sKey] = $sFriendlyName;
|
||||
}
|
||||
}
|
||||
|
||||
switch($sOutputFormat)
|
||||
{
|
||||
case static::ENUM_OUTPUT_FORMAT_JSON:
|
||||
|
||||
$aJsonMap = array();
|
||||
foreach ($aValues as $sKey => $sLabel)
|
||||
{
|
||||
$aJsonMap[] = array('value' => $sKey, 'label' => $sLabel);
|
||||
}
|
||||
|
||||
$oP->SetContentType('application/json');
|
||||
$oP->add(json_encode($aJsonMap));
|
||||
break;
|
||||
|
||||
case static::ENUM_OUTPUT_FORMAT_CSV:
|
||||
foreach($aValues as $sKey => $sFriendlyName)
|
||||
{
|
||||
$oP->add(trim($sFriendlyName)."\t".$sKey."\n");
|
||||
}
|
||||
break;
|
||||
default:
|
||||
throw new Exception('Invalid output format, "'.$sOutputFormat.'" given.');
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the display name of the selected object, to fill back the autocomplete
|
||||
*/
|
||||
@@ -435,12 +500,15 @@ EOF
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
/**
|
||||
* Get the form to select a leaf class from the $this->sTargetClass (that should be abstract)
|
||||
* Note: Inspired from UILinksWidgetDirect::GetObjectCreationDialog()
|
||||
*
|
||||
* @param WebPage $oPage
|
||||
*/
|
||||
* @param WebPage $oPage
|
||||
*
|
||||
* @throws \CoreException
|
||||
* @throws \DictExceptionMissingString
|
||||
*/
|
||||
public function GetClassSelectionForm(WebPage $oPage)
|
||||
{
|
||||
// For security reasons: check that the "proposed" class is actually a subclass of the linked class
|
||||
@@ -480,7 +548,7 @@ EOF
|
||||
/**
|
||||
* Get the form to create a new object of the 'target' class
|
||||
*/
|
||||
public function GetObjectCreationForm(WebPage $oPage, $oCurrObject)
|
||||
public function GetObjectCreationForm(WebPage $oPage, $oCurrObject, $aPrefillFormParam)
|
||||
{
|
||||
// Set all the default values in an object and clone this "default" object
|
||||
$oNewObj = MetaModel::NewObject($this->sTargetClass);
|
||||
@@ -488,7 +556,7 @@ EOF
|
||||
// 1st - set context values
|
||||
$oAppContext = new ApplicationContext();
|
||||
$oAppContext->InitObjectFromContext($oNewObj);
|
||||
|
||||
$oNewObj->PrefillForm('creation_from_extkey', $aPrefillFormParam);
|
||||
// 2nd set the default values from the constraint on the external key... if any
|
||||
if ( ($oCurrObject != null) && ($this->sAttCode != ''))
|
||||
{
|
||||
@@ -505,7 +573,7 @@ EOF
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// 3rd - set values from the page argument 'default'
|
||||
$oNewObj->UpdateObjectFromArg('default');
|
||||
|
||||
@@ -522,7 +590,7 @@ EOF
|
||||
$aFieldsComments[$sAttCode] = ' <img src="../images/transp-lock.png" style="vertical-align:middle" title="'.htmlentities(Dict::S('UI:UploadNotSupportedInThisMode')).'"/>';
|
||||
}
|
||||
}
|
||||
cmdbAbstractObject::DisplayCreationForm($oPage, $this->sTargetClass, $oNewObj, array(), array('formPrefix' => $this->iId, 'noRelations' => true, 'fieldsFlags' => $aFieldsFlags, 'fieldsComments' => $aFieldsComments));
|
||||
cmdbAbstractObject::DisplayCreationForm($oPage, $this->sTargetClass, $oNewObj, array(), array('formPrefix' => $this->iId, 'noRelations' => true, 'fieldsFlags' => $aFieldsFlags, 'fieldsComments' => $aFieldsComments));
|
||||
$oPage->add('</div></div></div>');
|
||||
// $oPage->add_ready_script("\$('#ac_create_$this->iId').dialog({ width: $(window).width()*0.8, height: 'auto', autoOpen: false, modal: true, title: '$sDialogTitle'});\n");
|
||||
$oPage->add_ready_script("\$('#ac_create_$this->iId').dialog({ width: 'auto', height: 'auto', maxHeight: $(window).height() - 50, autoOpen: false, modal: true, title: '$sDialogTitle'});\n");
|
||||
@@ -542,21 +610,11 @@ EOF
|
||||
{
|
||||
throw new Exception('Implementation: null value for allowed values definition');
|
||||
}
|
||||
try
|
||||
{
|
||||
$oFilter = DBObjectSearch::FromOQL($sFilter);
|
||||
$oFilter->SetModifierProperty('UserRightsGetSelectFilter', 'bSearchMode', $this->bSearchMode);
|
||||
$oSet = new DBObjectSet($oFilter, array(), array('this' => $oObj, 'current_extkey_id' => $currValue));
|
||||
}
|
||||
catch(MissingQueryArgument $e)
|
||||
{
|
||||
// When used in a search form the $this parameter may be missing, in this case return all possible values...
|
||||
// TODO check if we can improve this behavior...
|
||||
$sOQL = 'SELECT '.$this->m_sTargetClass;
|
||||
$oFilter = DBObjectSearch::FromOQL($sOQL);
|
||||
$oFilter->SetModifierProperty('UserRightsGetSelectFilter', 'bSearchMode', $this->bSearchMode);
|
||||
$oSet = new DBObjectSet($oFilter);
|
||||
}
|
||||
|
||||
$oFilter = DBObjectSearch::FromOQL($sFilter);
|
||||
$oFilter->SetModifierProperty('UserRightsGetSelectFilter', 'bSearchMode', $this->bSearchMode);
|
||||
$oSet = new DBObjectSet($oFilter, array(), array('this' => $oObj, 'current_extkey_id' => $currValue));
|
||||
|
||||
$oSet->SetShowObsoleteData(utils::ShowObsoleteData());
|
||||
|
||||
$sHKAttCode = MetaModel::IsHierarchicalClass($this->sTargetClass);
|
||||
@@ -566,7 +624,7 @@ EOF
|
||||
$oPage->add('</div>');
|
||||
$oPage->add("<input type=\"button\" id=\"btn_cancel_{$this->iId}\" value=\"".Dict::S('UI:Button:Cancel')."\" onClick=\"$('#dlg_tree_{$this->iId}').dialog('close');\"> ");
|
||||
$oPage->add("<input type=\"button\" id=\"btn_ok_{$this->iId}\" value=\"".Dict::S('UI:Button:Ok')."\" onClick=\"oACWidget_{$this->iId}.DoHKOk();\">");
|
||||
|
||||
|
||||
$oPage->add('</div></div>');
|
||||
$oPage->add_ready_script("\$('#tree_$this->iId ul').treeview();\n");
|
||||
$oPage->add_ready_script("\$('#dlg_tree_$this->iId').dialog({ width: 'auto', height: 'auto', autoOpen: true, modal: true, title: '$sDialogTitle', resizeStop: oACWidget_{$this->iId}.OnHKResize, close: oACWidget_{$this->iId}.OnHKClose });\n");
|
||||
@@ -588,7 +646,7 @@ EOF
|
||||
}
|
||||
else
|
||||
{
|
||||
return array('error' => implode(' ', $aErrors), 'id' => 0);
|
||||
return array('error' => implode(' ', $aErrors), 'id' => 0);
|
||||
}
|
||||
}
|
||||
catch(Exception $e)
|
||||
@@ -611,7 +669,7 @@ EOF
|
||||
$aTree[$iParentId][$oObj->GetKey()] = $oObj->GetName();
|
||||
$aNodes[$oObj->GetKey()] = $oObj;
|
||||
}
|
||||
|
||||
|
||||
$aParents = array_keys($aTree);
|
||||
$aRoots = array();
|
||||
foreach($aParents as $id)
|
||||
@@ -626,7 +684,7 @@ EOF
|
||||
$this->DumpNodes($oP, $iRootId, $aTree, $aNodes, $currValue);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function DumpNodes($oP, $iRootId, $aTree, $aNodes, $currValue)
|
||||
{
|
||||
$bSelect = true;
|
||||
|
||||
@@ -101,7 +101,7 @@ class UIHTMLEditorWidget
|
||||
$oPage->add_ready_script(
|
||||
<<<EOF
|
||||
$('#$iId').bind('update', function(evt){
|
||||
BlockField('cke_$iId', $('#$iId').attr('disabled'));
|
||||
BlockField('cke_$iId', $('#$iId').prop('disabled'));
|
||||
//Delayed execution - ckeditor must be properly initialized before setting readonly
|
||||
var retryCount = 0;
|
||||
var oMe = $('#$iId');
|
||||
|
||||
@@ -30,7 +30,14 @@ class UILinksWidgetDirect
|
||||
protected $sInputid;
|
||||
protected $sNameSuffix;
|
||||
protected $sLinkedClass;
|
||||
|
||||
|
||||
/**
|
||||
* UILinksWidgetDirect constructor.
|
||||
* @param string $sClass
|
||||
* @param string $sAttCode
|
||||
* @param string $sInputId
|
||||
* @param string $sNameSuffix
|
||||
*/
|
||||
public function __construct($sClass, $sAttCode, $sInputId, $sNameSuffix = '')
|
||||
{
|
||||
$this->sClass = $sClass;
|
||||
@@ -74,12 +81,12 @@ class UILinksWidgetDirect
|
||||
|
||||
/**
|
||||
* @param WebPage $oPage
|
||||
* @param DBObjectSet $oValue
|
||||
* @param DBObjectSet|ormLinkSet $oValue
|
||||
* @param array $aArgs
|
||||
* @param $sFormPrefix
|
||||
* @param $oCurrentObj
|
||||
* @param string $sFormPrefix
|
||||
* @param DBObject $oCurrentObj
|
||||
*/
|
||||
public function Display(WebPage $oPage, DBObjectSet $oValue, $aArgs = array(), $sFormPrefix, $oCurrentObj)
|
||||
public function Display(WebPage $oPage, $oValue, $aArgs = array(), $sFormPrefix, $oCurrentObj)
|
||||
{
|
||||
$oLinksetDef = MetaModel::GetAttributeDef($this->sClass, $this->sAttCode);
|
||||
switch($oLinksetDef->GetEditMode())
|
||||
@@ -127,11 +134,11 @@ class UILinksWidgetDirect
|
||||
* @param WebPage $oPage
|
||||
* @param DBObjectSet $oValue
|
||||
* @param array $aArgs
|
||||
* @param $sFormPrefix
|
||||
* @param $oCurrentObj
|
||||
* @param $bDisplayMenu
|
||||
* @param string $sFormPrefix
|
||||
* @param DBObject $oCurrentObj
|
||||
* @param bool $bDisplayMenu
|
||||
*/
|
||||
protected function DisplayAsBlock(WebPage $oPage, DBObjectSet $oValue, $aArgs = array(), $sFormPrefix, $oCurrentObj, $bDisplayMenu)
|
||||
protected function DisplayAsBlock(WebPage $oPage, $oValue, $aArgs = array(), $sFormPrefix, $oCurrentObj, $bDisplayMenu)
|
||||
{
|
||||
$oLinksetDef = MetaModel::GetAttributeDef($this->sClass, $this->sAttCode);
|
||||
$sTargetClass = $oLinksetDef->GetLinkedClass();
|
||||
@@ -170,51 +177,9 @@ class UILinksWidgetDirect
|
||||
|
||||
/**
|
||||
* @param WebPage $oPage
|
||||
* @param DBObjectSet $oValue
|
||||
* @param array $aArgs
|
||||
* @param $sFormPrefix
|
||||
* @param $oCurrentObj
|
||||
* @param array $aButtons
|
||||
* @param string $sProposedRealClass
|
||||
*/
|
||||
protected function DisplayEditInPlace(WebPage $oPage, DBObjectSet $oValue, $aArgs = array(), $sFormPrefix, $oCurrentObj, $aButtons = array('create', 'delete'))
|
||||
{
|
||||
$aAttribs = $this->GetTableConfig();
|
||||
|
||||
$oValue->Rewind();
|
||||
$oPage->add('<table class="listContainer" id="'.$this->sInputid.'"><tr><td>');
|
||||
|
||||
$aData = array();
|
||||
while($oLinkObj = $oValue->Fetch())
|
||||
{
|
||||
$aRow = array();
|
||||
$aRow['form::select'] = '<input type="checkbox" class="selectList'.$this->sInputid.'" value="'.$oLinkObj->GetKey().'"/>';
|
||||
foreach($this->aZlist as $sLinkedAttCode)
|
||||
{
|
||||
$aRow[$sLinkedAttCode] = $oLinkObj->GetAsHTML($sLinkedAttCode);
|
||||
}
|
||||
$aData[] = $aRow;
|
||||
}
|
||||
$oPage->table($aAttribs, $aData);
|
||||
$oPage->add('</td></tr></table>'); //listcontainer
|
||||
$sInputName = $sFormPrefix.'attr_'.$this->sAttCode;
|
||||
$aLabels = array(
|
||||
'delete' => Dict::S('UI:Button:Delete'),
|
||||
// 'modify' => 'Modify...' ,
|
||||
'creation_title' => Dict::Format('UI:CreationTitle_Class', MetaModel::GetName($this->sLinkedClass)),
|
||||
'create' => Dict::Format('UI:ClickToCreateNew', MetaModel::GetName($this->sLinkedClass)),
|
||||
'remove' => Dict::S('UI:Button:Remove'),
|
||||
'add' => Dict::Format('UI:AddAnExisting_Class', MetaModel::GetName($this->sLinkedClass)),
|
||||
'selection_title' => Dict::Format('UI:SelectionOf_Class', MetaModel::GetName($this->sLinkedClass)),
|
||||
);
|
||||
$oContext = new ApplicationContext();
|
||||
$sSubmitUrl = utils::GetAbsoluteUrlAppRoot().'pages/ajax.render.php?'.$oContext->GetForLink();
|
||||
$sJSONLabels = json_encode($aLabels);
|
||||
$sJSONButtons = json_encode($aButtons);
|
||||
$sWizHelper = 'oWizardHelper'.$sFormPrefix;
|
||||
$oPage->add_ready_script("$('#{$this->sInputid}').directlinks({class_name: '$this->sClass', att_code: '$this->sAttCode', input_name:'$sInputName', labels: $sJSONLabels, submit_to: '$sSubmitUrl', buttons: $sJSONButtons, oWizardHelper: $sWizHelper });");
|
||||
}
|
||||
|
||||
public function GetObjectCreationDlg(WebPage $oPage, $sProposedRealClass = '')
|
||||
public function GetObjectCreationDlg(WebPage $oPage, $sProposedRealClass = '', $oSourceObj = null)
|
||||
{
|
||||
// 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
|
||||
@@ -239,14 +204,17 @@ class UILinksWidgetDirect
|
||||
$aKeys = array_keys($aPossibleClasses);
|
||||
$sRealClass = $aKeys[0];
|
||||
}
|
||||
|
||||
|
||||
if ($sRealClass != '')
|
||||
{
|
||||
$oPage->add("<h1>".MetaModel::GetClassIcon($sRealClass)." ".Dict::Format('UI:CreationTitle_Class', MetaModel::GetName($sRealClass))."</h1>\n");
|
||||
$oLinksetDef = MetaModel::GetAttributeDef($this->sClass, $this->sAttCode);
|
||||
$sExtKeyToMe = $oLinksetDef->GetExtKeyToMe();
|
||||
$aFieldFlags = array( $sExtKeyToMe => OPT_ATT_HIDDEN);
|
||||
cmdbAbstractObject::DisplayCreationForm($oPage, $sRealClass, null, array(), array('formPrefix' => $this->sInputid, 'noRelations' => true, 'fieldsFlags' => $aFieldFlags));
|
||||
$oObj = DBObject::MakeDefaultInstance($sRealClass);
|
||||
$aPrefillParam = array('source_obj' => $oSourceObj);
|
||||
$oObj->PrefillForm('creation_from_editinplace', $aPrefillParam);
|
||||
cmdbAbstractObject::DisplayCreationForm($oPage, $sRealClass, $oObj, array(), array('formPrefix' => $this->sInputid, 'noRelations' => true, 'fieldsFlags' => $aFieldFlags));
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -263,13 +231,91 @@ class UILinksWidgetDirect
|
||||
}
|
||||
$oPage->add('</div></div>');
|
||||
}
|
||||
|
||||
public function GetObjectsSelectionDlg($oPage, $oCurrentObj)
|
||||
|
||||
/**
|
||||
* @param WebPage $oPage
|
||||
* @param DBObjectSet $oValue
|
||||
* @param array $aArgs
|
||||
* @param string $sFormPrefix
|
||||
* @param DBObject $oCurrentObj
|
||||
* @param array $aButtons
|
||||
*/
|
||||
protected function DisplayEditInPlace(WebPage $oPage, $oValue, $aArgs = array(), $sFormPrefix, $oCurrentObj, $aButtons = array('create', 'delete'))
|
||||
{
|
||||
$aAttribs = $this->GetTableConfig();
|
||||
|
||||
$oValue->Rewind();
|
||||
$oPage->add('<table class="listContainer" id="'.$this->sInputid.'"><tr><td>');
|
||||
|
||||
$aData = array();
|
||||
while($oLinkObj = $oValue->Fetch())
|
||||
{
|
||||
$aRow = array();
|
||||
$aRow['form::select'] = '<input type="checkbox" class="selectList'.$this->sInputid.'" value="'.$oLinkObj->GetKey().'"/>';
|
||||
foreach($this->aZlist as $sLinkedAttCode)
|
||||
{
|
||||
$aRow[$sLinkedAttCode] = $oLinkObj->GetAsHTML($sLinkedAttCode);
|
||||
}
|
||||
$aData[] = $aRow;
|
||||
}
|
||||
$oPage->table($aAttribs, $aData);
|
||||
$oPage->add('</td></tr></table>'); //listcontainer
|
||||
$sInputName = $sFormPrefix.'attr_'.$this->sAttCode;
|
||||
$aLabels = array(
|
||||
'delete' => Dict::S('UI:Button:Delete'),
|
||||
// 'modify' => 'Modify...' ,
|
||||
'creation_title' => Dict::Format('UI:CreationTitle_Class', MetaModel::GetName($this->sLinkedClass)),
|
||||
'create' => Dict::Format('UI:ClickToCreateNew', MetaModel::GetName($this->sLinkedClass)),
|
||||
'remove' => Dict::S('UI:Button:Remove'),
|
||||
'add' => Dict::Format('UI:AddAnExisting_Class', MetaModel::GetName($this->sLinkedClass)),
|
||||
'selection_title' => Dict::Format('UI:SelectionOf_Class', MetaModel::GetName($this->sLinkedClass)),
|
||||
);
|
||||
$oContext = new ApplicationContext();
|
||||
$sSubmitUrl = utils::GetAbsoluteUrlAppRoot().'pages/ajax.render.php?'.$oContext->GetForLink();
|
||||
$sJSONLabels = json_encode($aLabels);
|
||||
$sJSONButtons = json_encode($aButtons);
|
||||
$sWizHelper = 'oWizardHelper'.$sFormPrefix;
|
||||
// Don't automatically launch the search if the table is huge
|
||||
$bDoSearch = !utils::IsHighCardinality($this->sLinkedClass);
|
||||
$sJSDoSearch = $bDoSearch ? 'true' : 'false';
|
||||
$oPage->add_ready_script("$('#{$this->sInputid}').directlinks({class_name: '$this->sClass', att_code: '$this->sAttCode', input_name:'$sInputName', labels: $sJSONLabels, submit_to: '$sSubmitUrl', buttons: $sJSONButtons, oWizardHelper: $sWizHelper, do_search: $sJSDoSearch});");
|
||||
}
|
||||
|
||||
/**
|
||||
* @param WebPage $oPage
|
||||
* @param DBObject $oCurrentObj
|
||||
* @param $aAlreadyLinked
|
||||
*
|
||||
* @param array $aPrefillFormParam
|
||||
*
|
||||
* @throws \CoreException
|
||||
* @throws \MissingQueryArgument
|
||||
* @throws \OQLException
|
||||
*/
|
||||
public function GetObjectsSelectionDlg($oPage, $oCurrentObj, $aAlreadyLinked, $aPrefillFormParam = array())
|
||||
{
|
||||
$sHtml = "<div class=\"wizContainer\" style=\"vertical-align:top;\">\n";
|
||||
|
||||
$oLinksetDef = MetaModel::GetAttributeDef($this->sClass, $this->sAttCode);
|
||||
$valuesDef = $oLinksetDef->GetValuesDef();
|
||||
|
||||
$oHiddenFilter = new DBObjectSearch($this->sLinkedClass);
|
||||
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())
|
||||
{
|
||||
$oHiddenFilter->AddCondition('id', $oCurrentObj->GetKey(), '!=');
|
||||
}
|
||||
}
|
||||
if (count($aAlreadyLinked) > 0)
|
||||
{
|
||||
$oHiddenFilter->AddCondition('id', $aAlreadyLinked, 'NOTIN');
|
||||
}
|
||||
$oHiddenCriteria = $oHiddenFilter->GetCriteria();
|
||||
$aArgs = $oHiddenFilter->GetInternalParams();
|
||||
$sHiddenCriteria = $oHiddenCriteria->Render($aArgs);
|
||||
|
||||
$oLinkSetDef = MetaModel::GetAttributeDef($this->sClass, $this->sAttCode);
|
||||
$valuesDef = $oLinkSetDef->GetValuesDef();
|
||||
if ($valuesDef === null)
|
||||
{
|
||||
$oFilter = new DBObjectSearch($this->sLinkedClass);
|
||||
@@ -282,13 +328,28 @@ class UILinksWidgetDirect
|
||||
}
|
||||
$oFilter = DBObjectSearch::FromOQL($valuesDef->GetFilterExpression());
|
||||
}
|
||||
|
||||
if ($oCurrentObj != null)
|
||||
{
|
||||
$this->SetSearchDefaultFromContext($oCurrentObj, $oFilter);
|
||||
|
||||
$aArgs = array_merge($oCurrentObj->ToArgs('this'), $oFilter->GetInternalParams());
|
||||
$oFilter->SetInternalParams($aArgs);
|
||||
$aPrefillFormParam['filter'] = $oFilter;
|
||||
$oCurrentObj->PrefillForm('search', $aPrefillFormParam);
|
||||
}
|
||||
$bOpen = MetaModel::GetConfig()->Get('legacy_search_drawer_open');
|
||||
$oBlock = new DisplayBlock($oFilter, 'search', false);
|
||||
$sHtml .= $oBlock->GetDisplay($oPage, "SearchFormToAdd_{$this->sInputid}", array('open' => $bOpen));
|
||||
$sHtml .= $oBlock->GetDisplay($oPage, "SearchFormToAdd_{$this->sInputid}",
|
||||
array(
|
||||
'result_list_outer_selector' => "SearchResultsToAdd_{$this->sInputid}",
|
||||
'table_id' => "add_{$this->sInputid}",
|
||||
'table_inner_id' => "ResultsToAdd_{$this->sInputid}",
|
||||
'selection_mode' => true,
|
||||
'cssCount' => "#count_{$this->sInputid}",
|
||||
'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";
|
||||
@@ -299,22 +360,27 @@ class UILinksWidgetDirect
|
||||
$sHtml .= "</form>\n";
|
||||
$oPage->add($sHtml);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Search for objects to be linked to the current object (i.e "remote" objects)
|
||||
*
|
||||
* @param WebPage $oP The page used for the output (usually an AjaxWebPage)
|
||||
* @param string $sRemoteClass Name of the "remote" class to perform the search on, must be a derived class of $this->sLinkedClass
|
||||
* @param array $aAlreadyLinked Array of indentifiers of objects which are already linke to the current object (or about to be linked)
|
||||
* @param DBObject $oCurrentObj The object currently being edited... if known...
|
||||
* @param array $aPrefillFormParam
|
||||
*
|
||||
* @throws \CoreException
|
||||
* @throws \OQLException
|
||||
*/
|
||||
public function SearchObjectsToAdd(WebPage $oP, $sRemoteClass = '', $aAlreadyLinked = array(), $oCurrentObj = null)
|
||||
public function SearchObjectsToAdd(WebPage $oP, $sRemoteClass = '', $aAlreadyLinked = array(), $oCurrentObj = null, $aPrefillFormParam = array())
|
||||
{
|
||||
if ($sRemoteClass == '')
|
||||
{
|
||||
$sRemoteClass = $this->sLinkedClass;
|
||||
}
|
||||
$oLinksetDef = MetaModel::GetAttributeDef($this->sClass, $this->sAttCode);
|
||||
$valuesDef = $oLinksetDef->GetValuesDef();
|
||||
$oLinkSetDef = MetaModel::GetAttributeDef($this->sClass, $this->sAttCode);
|
||||
$valuesDef = $oLinkSetDef->GetValuesDef();
|
||||
if ($valuesDef === null)
|
||||
{
|
||||
$oFilter = new DBObjectSearch($sRemoteClass);
|
||||
@@ -331,25 +397,34 @@ class UILinksWidgetDirect
|
||||
if (($oCurrentObj != null) && MetaModel::IsSameFamilyBranch($sRemoteClass, $this->sClass))
|
||||
{
|
||||
// Prevent linking to self if the linked object is of the same family
|
||||
// and laready present in the database
|
||||
// and already present in the database
|
||||
if (!$oCurrentObj->IsNew())
|
||||
{
|
||||
$oFilter->AddCondition('id', $oCurrentObj->GetKey(), '!=');
|
||||
}
|
||||
}
|
||||
if ($oCurrentObj != null)
|
||||
{
|
||||
$this->SetSearchDefaultFromContext($oCurrentObj, $oFilter);
|
||||
|
||||
$aArgs = array_merge($oCurrentObj->ToArgs('this'), $oFilter->GetInternalParams());
|
||||
$oFilter->SetInternalParams($aArgs);
|
||||
|
||||
$aPrefillFormParam['filter'] = $oFilter;
|
||||
$oCurrentObj->PrefillForm('search', $aPrefillFormParam);
|
||||
}
|
||||
if (count($aAlreadyLinked) > 0)
|
||||
{
|
||||
$oFilter->AddCondition('id', $aAlreadyLinked, 'NOTIN');
|
||||
}
|
||||
if ($oCurrentObj != null)
|
||||
{
|
||||
$aArgs = array_merge($oCurrentObj->ToArgs('this'), $oFilter->GetInternalParams());
|
||||
$oFilter->SetInternalParams($aArgs);
|
||||
}
|
||||
$oBlock = new DisplayBlock($oFilter, 'list', false);
|
||||
$oBlock->Display($oP, "ResultsToAdd_{$this->sInputid}", array('menu' => false, 'cssCount'=> '#count_'.$this->sInputid , 'selection_mode' => true, 'table_id' => 'add_'.$this->sInputid)); // Don't display the 'Actions' menu on the results
|
||||
}
|
||||
|
||||
/**
|
||||
* @param WebPage $oP
|
||||
* @param $oFullSetFilter
|
||||
*/
|
||||
public function DoAddObjects(WebPage $oP, $oFullSetFilter)
|
||||
{
|
||||
$aLinkedObjectIds = utils::ReadMultipleSelection($oFullSetFilter);
|
||||
@@ -377,7 +452,14 @@ class UILinksWidgetDirect
|
||||
}
|
||||
return $aAttribs;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param WebPage $oPage
|
||||
* @param string $sRealClass
|
||||
* @param array $aValues
|
||||
* @param int $iTempId
|
||||
* @return mixed
|
||||
*/
|
||||
public function GetRow($oPage, $sRealClass, $aValues, $iTempId)
|
||||
{
|
||||
if ($sRealClass == '')
|
||||
@@ -389,7 +471,13 @@ class UILinksWidgetDirect
|
||||
|
||||
return $this->GetObjectRow($oPage, $oLinkObj, $iTempId);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param WebPage $oPage
|
||||
* @param $oLinkObj
|
||||
* @param int $iTempId
|
||||
* @return mixed
|
||||
*/
|
||||
protected function GetObjectRow($oPage, $oLinkObj, $iTempId)
|
||||
{
|
||||
$aAttribs = $this->GetTableConfig();
|
||||
@@ -405,7 +493,7 @@ class UILinksWidgetDirect
|
||||
/**
|
||||
* Initializes the default search parameters based on 1) a 'current' object and 2) the silos defined by the context
|
||||
* @param DBObject $oSourceObj
|
||||
* @param DBSearch $oSearch
|
||||
* @param DBSearch|DBObjectSearch $oSearch
|
||||
*/
|
||||
protected function SetSearchDefaultFromContext($oSourceObj, &$oSearch)
|
||||
{
|
||||
@@ -424,7 +512,6 @@ class UILinksWidgetDirect
|
||||
|
||||
if (MetaModel::IsValidAttCode($sSrcClass, $sAttCode))
|
||||
{
|
||||
$oAttDef = MetaModel::GetAttributeDef($sSrcClass, $sAttCode);
|
||||
$defaultValue = $oSourceObj->Get($sAttCode);
|
||||
|
||||
// Find the attcode for the same 'context' parameter in the destination class
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -73,17 +73,17 @@ class UIPasswordWidget
|
||||
$oPage->add_ready_script("$('#{$this->iId}_confirm').bind('keyup change', function(evt, sFormId) { return ValidatePasswordField('$this->iId', sFormId) } );"); // Bind to a custom event: validate
|
||||
$oPage->add_ready_script("$('#{$this->iId}').bind('update', function(evt, sFormId)
|
||||
{
|
||||
if ($(this).attr('disabled'))
|
||||
if ($(this).prop('disabled'))
|
||||
{
|
||||
$('#{$this->iId}_confirm').attr('disabled', 'disabled');
|
||||
$('#{$this->iId}_changed').attr('disabled', 'disabled');
|
||||
$('#{$this->iId}_reset').attr('disabled', 'disabled');
|
||||
$('#{$this->iId}_confirm').prop('disabled', true);
|
||||
$('#{$this->iId}_changed').prop('disabled', true);
|
||||
$('#{$this->iId}_reset').prop('disabled', true);
|
||||
}
|
||||
else
|
||||
{
|
||||
$('#{$this->iId}_confirm').removeAttr('disabled');
|
||||
$('#{$this->iId}_changed').removeAttr('disabled');
|
||||
$('#{$this->iId}_reset').removeAttr('disabled');
|
||||
$('#{$this->iId}_confirm').prop('disabled', false);
|
||||
$('#{$this->iId}_changed').prop('disabled', false);
|
||||
$('#{$this->iId}_reset').prop('disabled', false);
|
||||
}
|
||||
}
|
||||
);"); // Bind to a custom event: update to handle enabling/disabling
|
||||
|
||||
115
application/ui.searchformforeignkeys.class.inc.php
Normal file
115
application/ui.searchformforeignkeys.class.inc.php
Normal file
@@ -0,0 +1,115 @@
|
||||
<?php
|
||||
/**
|
||||
*
|
||||
* Copyright (C) 2010-2018 Combodo SARL
|
||||
*
|
||||
* This file is part of iTop.
|
||||
*
|
||||
* iTop is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* iTop is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with iTop. If not, see <http://www.gnu.org/licenses/>
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
require_once(APPROOT.'/application/webpage.class.inc.php');
|
||||
require_once(APPROOT.'/application/displayblock.class.inc.php');
|
||||
|
||||
class UISearchFormForeignKeys
|
||||
{
|
||||
public function __construct($sTargetClass, $iInputId = null)
|
||||
{
|
||||
$this->m_sRemoteClass = $sTargetClass;
|
||||
$this->m_iInputId = $iInputId;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param WebPage $oPage
|
||||
*
|
||||
* @param $sTitle
|
||||
*
|
||||
* @throws \Exception
|
||||
*/
|
||||
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}",
|
||||
array(
|
||||
'menu' => false,
|
||||
'result_list_outer_selector' => "SearchResultsToAdd_{$this->m_iInputId}",
|
||||
'table_id' => "add_{$this->m_iInputId}",
|
||||
'table_inner_id' => "ResultsToAdd_{$this->m_iInputId}",
|
||||
'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);
|
||||
$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);");
|
||||
$oPage->add_ready_script("$('#SearchFormToAdd_{$this->m_iInputId}').resize(oForeignKeysWidget{$this->m_iInputId}.UpdateSizes);");
|
||||
}
|
||||
|
||||
public function GetFullListForeignKeysFromSelection($oPage, $oFullSetFilter)
|
||||
{
|
||||
try
|
||||
{
|
||||
$aLinkedObjects = utils::ReadMultipleSelectionWithFriendlyname($oFullSetFilter);
|
||||
$oPage->add(json_encode($aLinkedObjects));
|
||||
}
|
||||
catch (CoreException $e)
|
||||
{
|
||||
http_response_code(500);
|
||||
$oPage->add(json_encode(array('error' => $e->GetMessage())));
|
||||
IssueLog::Error($e->getMessage()."\nDebug trace:\n".$e->getTraceAsString());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Search for objects to be linked to the current object (i.e "remote" objects)
|
||||
*
|
||||
* @param WebPage $oP The page used for the output (usually an AjaxWebPage)
|
||||
* @param string $sRemoteClass Name of the "remote" class to perform the search on, must be a derived class of m_sRemoteClass
|
||||
*
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function ListResultsSearchForeignKeys(WebPage $oP, $sRemoteClass = '')
|
||||
{
|
||||
if ($sRemoteClass != '')
|
||||
{
|
||||
// assert(MetaModel::IsParentClass($this->m_sRemoteClass, $sRemoteClass));
|
||||
$oFilter = new DBObjectSearch($sRemoteClass);
|
||||
}
|
||||
else
|
||||
{
|
||||
// No remote class specified use the one defined in the linkedset
|
||||
$oFilter = new DBObjectSearch($this->m_sRemoteClass);
|
||||
}
|
||||
|
||||
$oBlock = new DisplayBlock($oFilter, 'list', false);
|
||||
$oBlock->Display($oP, "ResultsToAdd_{$this->m_iInputId}",
|
||||
array('menu' => false, 'cssCount' => "#count_{$this->m_iInputId}", 'selection_mode' => true, 'table_id' => "add_{$this->m_iInputId}"));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,331 +1,331 @@
|
||||
<?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 UIWizard
|
||||
*
|
||||
* @copyright Copyright (C) 2010-2012 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
class UIWizard
|
||||
{
|
||||
protected $m_oPage;
|
||||
protected $m_sClass;
|
||||
protected $m_sTargetState;
|
||||
protected $m_aWizardSteps;
|
||||
|
||||
public function __construct($oPage, $sClass, $sTargetState = '')
|
||||
{
|
||||
$this->m_oPage = $oPage;
|
||||
$this->m_sClass = $sClass;
|
||||
if (empty($sTargetState))
|
||||
{
|
||||
$sTargetState = MetaModel::GetDefaultState($sClass);
|
||||
}
|
||||
$this->m_sTargetState = $sTargetState;
|
||||
$this->m_aWizardSteps = $this->ComputeWizardStructure();
|
||||
}
|
||||
|
||||
public function GetObjectClass() { return $this->m_sClass; }
|
||||
public function GetTargetState() { return $this->m_sTargetState; }
|
||||
public function GetWizardStructure() { return $this->m_aWizardSteps; }
|
||||
|
||||
/**
|
||||
* Displays one step of the wizard
|
||||
*/
|
||||
public function DisplayWizardStep($aStep, $iStepIndex, &$iMaxInputId, &$aFieldsMap, $bFinishEnabled = false, $aArgs = array())
|
||||
{
|
||||
if ($iStepIndex == 1) // one big form that contains everything, to make sure that the uploaded files are posted too
|
||||
{
|
||||
$this->m_oPage->add("<form method=\"post\" enctype=\"multipart/form-data\" action=\"".utils::GetAbsoluteUrlAppRoot()."pages/UI.php\">\n");
|
||||
}
|
||||
$this->m_oPage->add("<div class=\"wizContainer\" id=\"wizStep$iStepIndex\" style=\"display:none;\">\n");
|
||||
$this->m_oPage->add("<a name=\"step$iStepIndex\" />\n");
|
||||
$aStates = MetaModel::EnumStates($this->m_sClass);
|
||||
$aDetails = array();
|
||||
$sJSHandlerCode = ''; // Javascript code to be executed each time this step of the wizard is entered
|
||||
foreach($aStep as $sAttCode)
|
||||
{
|
||||
$oAttDef = MetaModel::GetAttributeDef($this->m_sClass, $sAttCode);
|
||||
if ($oAttDef->IsWritable())
|
||||
{
|
||||
$sAttLabel = $oAttDef->GetLabel();
|
||||
$iOptions = isset($aStates[$this->m_sTargetState]['attribute_list'][$sAttCode]) ? $aStates[$this->m_sTargetState]['attribute_list'][$sAttCode] : 0;
|
||||
|
||||
$aPrerequisites = $oAttDef->GetPrerequisiteAttributes();
|
||||
if ($iOptions & (OPT_ATT_MANDATORY | OPT_ATT_MUSTCHANGE | OPT_ATT_MUSTPROMPT))
|
||||
{
|
||||
$aFields[$sAttCode] = array();
|
||||
foreach($aPrerequisites as $sCode)
|
||||
{
|
||||
$aFields[$sAttCode][$sCode] = '';
|
||||
}
|
||||
}
|
||||
if (count($aPrerequisites) > 0)
|
||||
{
|
||||
$aOptions[] = 'Prerequisites: '.implode(', ', $aPrerequisites);
|
||||
}
|
||||
|
||||
$sFieldFlag = (($iOptions & (OPT_ATT_MANDATORY | OPT_ATT_MUSTCHANGE)) || (!$oAttDef->IsNullAllowed()) )? ' <span class="hilite">*</span>' : '';
|
||||
$oDefaultValuesSet = $oAttDef->GetDefaultValue(/* $oObject->ToArgs() */); // @@@ TO DO: get the object's current value if the object exists
|
||||
$sHTMLValue = cmdbAbstractObject::GetFormElementForField($this->m_oPage, $this->m_sClass, $sAttCode, $oAttDef, $oDefaultValuesSet, '', "att_$iMaxInputId", '', $iOptions, $aArgs);
|
||||
$aFieldsMap["att_$iMaxInputId"] = $sAttCode;
|
||||
$aDetails[] = array('label' => '<span title="'.$oAttDef->GetDescription().'">'.$oAttDef->GetLabel().$sFieldFlag.'</span>', 'value' => "<span id=\"field_att_$iMaxInputId\">$sHTMLValue</span>");
|
||||
if ($oAttDef->GetValuesDef() != null)
|
||||
{
|
||||
$sJSHandlerCode .= "\toWizardHelper.RequestAllowedValues('$sAttCode');\n";
|
||||
}
|
||||
if ($oAttDef->GetDefaultValue() != null)
|
||||
{
|
||||
$sJSHandlerCode .= "\toWizardHelper.RequestDefaultValue('$sAttCode');\n";
|
||||
}
|
||||
if ($oAttDef->IsLinkSet())
|
||||
{
|
||||
$sJSHandlerCode .= "\toLinkWidgetatt_$iMaxInputId.Init();";
|
||||
}
|
||||
$iMaxInputId++;
|
||||
}
|
||||
}
|
||||
//$aDetails[] = array('label' => '', 'value' => '<input type="button" value="Next >>">');
|
||||
$this->m_oPage->details($aDetails);
|
||||
$sBackButtonDisabled = ($iStepIndex <= 1) ? 'disabled' : '';
|
||||
$sDisabled = $bFinishEnabled ? '' : 'disabled';
|
||||
$nbSteps = count($this->m_aWizardSteps['mandatory']) + count($this->m_aWizardSteps['optional']);
|
||||
$this->m_oPage->add("<div style=\"text-align:center\">
|
||||
<input type=\"button\" value=\"".Dict::S('UI:Button:Back')."\" $sBackButtonDisabled onClick=\"GoToStep($iStepIndex, $iStepIndex - 1)\" />
|
||||
<input type=\"button\" value=\"".Dict::S('UI:Button:Next')."\" onClick=\"GoToStep($iStepIndex, 1+$iStepIndex)\" />
|
||||
<input type=\"button\" value=\"".Dict::S('UI:Button:Finish')."\" $sDisabled onClick=\"GoToStep($iStepIndex, 1+$nbSteps)\" />
|
||||
</div>\n");
|
||||
$this->m_oPage->add_script("
|
||||
function OnEnterStep{$iStepIndex}()
|
||||
{
|
||||
oWizardHelper.ResetQuery();
|
||||
oWizardHelper.UpdateWizard();
|
||||
|
||||
$sJSHandlerCode
|
||||
|
||||
oWizardHelper.AjaxQueryServer();
|
||||
}
|
||||
");
|
||||
$this->m_oPage->add("</div>\n\n");
|
||||
}
|
||||
|
||||
/**
|
||||
* Display the final step of the wizard: a confirmation screen
|
||||
*/
|
||||
public function DisplayFinalStep($iStepIndex, $aFieldsMap)
|
||||
{
|
||||
$oAppContext = new ApplicationContext();
|
||||
$this->m_oPage->add("<div class=\"wizContainer\" id=\"wizStep$iStepIndex\" style=\"display:none;\">\n");
|
||||
$this->m_oPage->add("<a name=\"step$iStepIndex\" />\n");
|
||||
$this->m_oPage->P(Dict::S('UI:Wizard:FinalStepTitle'));
|
||||
$this->m_oPage->add("<input type=\"hidden\" name=\"operation\" value=\"wizard_apply_new\" />\n");
|
||||
$this->m_oPage->add("<input type=\"hidden\" name=\"transaction_id\" value=\"".utils::GetNewTransactionId()."\" />\n");
|
||||
$this->m_oPage->add("<input type=\"hidden\" id=\"wizard_json_obj\" name=\"json_obj\" value=\"\" />\n");
|
||||
$sScript = "function OnEnterStep$iStepIndex() {\n";
|
||||
foreach($aFieldsMap as $iInputId => $sAttCode)
|
||||
{
|
||||
$sScript .= "\toWizardHelper.UpdateCurrentValue('$sAttCode');\n";
|
||||
}
|
||||
$sScript .= "\toWizardHelper.Preview('object_preview');\n";
|
||||
$sScript .= "\t$('#wizard_json_obj').val(oWizardHelper.ToJSON());\n";
|
||||
$sScript .= "}\n";
|
||||
$this->m_oPage->add_script($sScript);
|
||||
$this->m_oPage->add("<div id=\"object_preview\">\n");
|
||||
$this->m_oPage->add("</div>\n");
|
||||
$this->m_oPage->add($oAppContext->GetForForm());
|
||||
$this->m_oPage->add("<input type=\"button\" value=\"".Dict::S('UI:Button:Back')."\" onClick=\"GoToStep($iStepIndex, $iStepIndex - 1)\" />");
|
||||
$this->m_oPage->add("<input type=\"submit\" value=\"Create ".MetaModel::GetName($this->m_sClass)."\" />\n");
|
||||
$this->m_oPage->add("</div>\n");
|
||||
$this->m_oPage->add("</form>\n");
|
||||
}
|
||||
/**
|
||||
* Compute the order of the fields & pages in the wizard
|
||||
* @param $oPage iTopWebPage The current page (used to display error messages)
|
||||
* @param $sClass string Name of the class
|
||||
* @param $sStateCode string Code of the target state of the object
|
||||
* @return hash Two dimensional array: each element represents the list of fields for a given page
|
||||
*/
|
||||
protected function ComputeWizardStructure()
|
||||
{
|
||||
$aWizardSteps = array( 'mandatory' => array(), 'optional' => array());
|
||||
$aFieldsDone = array(); // Store all the fields that are already covered by a previous step of the wizard
|
||||
|
||||
$aStates = MetaModel::EnumStates($this->m_sClass);
|
||||
$sStateAttCode = MetaModel::GetStateAttributeCode($this->m_sClass);
|
||||
|
||||
$aMandatoryAttributes = array();
|
||||
// Some attributes are always mandatory independently of the state machine (if any)
|
||||
foreach(MetaModel::GetAttributesList($this->m_sClass) as $sAttCode)
|
||||
{
|
||||
$oAttDef = MetaModel::GetAttributeDef($this->m_sClass, $sAttCode);
|
||||
if (!$oAttDef->IsExternalField() && !$oAttDef->IsNullAllowed() &&
|
||||
$oAttDef->IsWritable() && ($sAttCode != $sStateAttCode) )
|
||||
{
|
||||
$aMandatoryAttributes[$sAttCode] = OPT_ATT_MANDATORY;
|
||||
}
|
||||
}
|
||||
|
||||
// Now check the attributes that are mandatory in the specified state
|
||||
if ( (!empty($this->m_sTargetState)) && (count($aStates[$this->m_sTargetState]['attribute_list']) > 0) )
|
||||
{
|
||||
// Check all the fields that *must* be included in the wizard for this
|
||||
// particular target state
|
||||
$aFields = array();
|
||||
foreach($aStates[$this->m_sTargetState]['attribute_list'] as $sAttCode => $iOptions)
|
||||
{
|
||||
if ( (isset($aMandatoryAttributes[$sAttCode])) &&
|
||||
($aMandatoryAttributes[$sAttCode] & (OPT_ATT_MANDATORY | OPT_ATT_MUSTCHANGE | OPT_ATT_MUSTPROMPT)) )
|
||||
{
|
||||
$aMandatoryAttributes[$sAttCode] |= $iOptions;
|
||||
}
|
||||
else
|
||||
{
|
||||
$aMandatoryAttributes[$sAttCode] = $iOptions;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check all the fields that *must* be included in the wizard
|
||||
// i.e. all mandatory, must-change or must-prompt fields that are
|
||||
// not also read-only or hidden.
|
||||
// Some fields may be required (null not allowed) from the database
|
||||
// perspective, but hidden or read-only from the user interface perspective
|
||||
$aFields = array();
|
||||
foreach($aMandatoryAttributes as $sAttCode => $iOptions)
|
||||
{
|
||||
if ( ($iOptions & (OPT_ATT_MANDATORY | OPT_ATT_MUSTCHANGE | OPT_ATT_MUSTPROMPT)) &&
|
||||
!($iOptions & (OPT_ATT_READONLY | OPT_ATT_HIDDEN)) )
|
||||
{
|
||||
$oAttDef = MetaModel::GetAttributeDef($this->m_sClass, $sAttCode);
|
||||
$aPrerequisites = $oAttDef->GetPrerequisiteAttributes();
|
||||
$aFields[$sAttCode] = array();
|
||||
foreach($aPrerequisites as $sCode)
|
||||
{
|
||||
$aFields[$sAttCode][$sCode] = '';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Now use the dependencies between the fields to order them
|
||||
// Start from the order of the 'details'
|
||||
$aList = MetaModel::FlattenZlist(MetaModel::GetZListItems($this->m_sClass, 'details'));
|
||||
$index = 0;
|
||||
$aOrder = array();
|
||||
foreach($aFields as $sAttCode => $void)
|
||||
{
|
||||
$aOrder[$sAttCode] = 999; // At the end of the list...
|
||||
}
|
||||
foreach($aList as $sAttCode)
|
||||
{
|
||||
if (array_key_exists($sAttCode, $aFields))
|
||||
{
|
||||
$aOrder[$sAttCode] = $index;
|
||||
}
|
||||
$index++;
|
||||
}
|
||||
foreach($aFields as $sAttCode => $aDependencies)
|
||||
{
|
||||
// All fields with no remaining dependencies can be entered at this
|
||||
// step of the wizard
|
||||
if (count($aDependencies) > 0)
|
||||
{
|
||||
$iMaxPos = 0;
|
||||
// Remove this field from the dependencies of the other fields
|
||||
foreach($aDependencies as $sDependentAttCode => $void)
|
||||
{
|
||||
// position the current field after the ones it depends on
|
||||
$iMaxPos = max($iMaxPos, 1+$aOrder[$sDependentAttCode]);
|
||||
}
|
||||
}
|
||||
}
|
||||
asort($aOrder);
|
||||
$aCurrentStep = array();
|
||||
foreach($aOrder as $sAttCode => $rank)
|
||||
{
|
||||
$aCurrentStep[] = $sAttCode;
|
||||
$aFieldsDone[$sAttCode] = '';
|
||||
}
|
||||
$aWizardSteps['mandatory'][] = $aCurrentStep;
|
||||
|
||||
|
||||
// Now computes the steps to fill the optional fields
|
||||
$aFields = array(); // reset
|
||||
foreach(MetaModel::ListAttributeDefs($this->m_sClass) as $sAttCode=>$oAttDef)
|
||||
{
|
||||
$iOptions = (isset($aStates[$this->m_sTargetState]['attribute_list'][$sAttCode])) ? $aStates[$this->m_sTargetState]['attribute_list'][$sAttCode] : 0;
|
||||
if ( ($sStateAttCode != $sAttCode) &&
|
||||
(!$oAttDef->IsExternalField()) &&
|
||||
(($iOptions & (OPT_ATT_HIDDEN | OPT_ATT_READONLY)) == 0) &&
|
||||
(!isset($aFieldsDone[$sAttCode])) )
|
||||
|
||||
{
|
||||
// 'State', external fields, read-only and hidden fields
|
||||
// and fields that are already listed in the wizard
|
||||
// are removed from the 'optional' part of the wizard
|
||||
$oAttDef = MetaModel::GetAttributeDef($this->m_sClass, $sAttCode);
|
||||
$aPrerequisites = $oAttDef->GetPrerequisiteAttributes();
|
||||
$aFields[$sAttCode] = array();
|
||||
foreach($aPrerequisites as $sCode)
|
||||
{
|
||||
if (!isset($aFieldsDone[$sCode]))
|
||||
{
|
||||
// retain only the dependencies that were not covered
|
||||
// in the 'mandatory' part of the wizard
|
||||
$aFields[$sAttCode][$sCode] = '';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Now use the dependencies between the fields to order them
|
||||
while(count($aFields) > 0)
|
||||
{
|
||||
$aCurrentStep = array();
|
||||
foreach($aFields as $sAttCode => $aDependencies)
|
||||
{
|
||||
// All fields with no remaining dependencies can be entered at this
|
||||
// step of the wizard
|
||||
if (count($aDependencies) == 0)
|
||||
{
|
||||
$aCurrentStep[] = $sAttCode;
|
||||
$aFieldsDone[$sAttCode] = '';
|
||||
unset($aFields[$sAttCode]);
|
||||
// Remove this field from the dependencies of the other fields
|
||||
foreach($aFields as $sUpdatedCode => $aDummy)
|
||||
{
|
||||
// remove the dependency
|
||||
unset($aFields[$sUpdatedCode][$sAttCode]);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (count($aCurrentStep) == 0)
|
||||
{
|
||||
// This step of the wizard would contain NO field !
|
||||
$this->m_oPage->add(Dict::S('UI:Error:WizardCircularReferenceInDependencies'));
|
||||
print_r($aFields);
|
||||
break;
|
||||
}
|
||||
$aWizardSteps['optional'][] = $aCurrentStep;
|
||||
}
|
||||
return $aWizardSteps;
|
||||
|
||||
}
|
||||
}
|
||||
?>
|
||||
<?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 UIWizard
|
||||
*
|
||||
* @copyright Copyright (C) 2010-2012 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
class UIWizard
|
||||
{
|
||||
protected $m_oPage;
|
||||
protected $m_sClass;
|
||||
protected $m_sTargetState;
|
||||
protected $m_aWizardSteps;
|
||||
|
||||
public function __construct($oPage, $sClass, $sTargetState = '')
|
||||
{
|
||||
$this->m_oPage = $oPage;
|
||||
$this->m_sClass = $sClass;
|
||||
if (empty($sTargetState))
|
||||
{
|
||||
$sTargetState = MetaModel::GetDefaultState($sClass);
|
||||
}
|
||||
$this->m_sTargetState = $sTargetState;
|
||||
$this->m_aWizardSteps = $this->ComputeWizardStructure();
|
||||
}
|
||||
|
||||
public function GetObjectClass() { return $this->m_sClass; }
|
||||
public function GetTargetState() { return $this->m_sTargetState; }
|
||||
public function GetWizardStructure() { return $this->m_aWizardSteps; }
|
||||
|
||||
/**
|
||||
* Displays one step of the wizard
|
||||
*/
|
||||
public function DisplayWizardStep($aStep, $iStepIndex, &$iMaxInputId, &$aFieldsMap, $bFinishEnabled = false, $aArgs = array())
|
||||
{
|
||||
if ($iStepIndex == 1) // one big form that contains everything, to make sure that the uploaded files are posted too
|
||||
{
|
||||
$this->m_oPage->add("<form method=\"post\" enctype=\"multipart/form-data\" action=\"".utils::GetAbsoluteUrlAppRoot()."pages/UI.php\">\n");
|
||||
}
|
||||
$this->m_oPage->add("<div class=\"wizContainer\" id=\"wizStep$iStepIndex\" style=\"display:none;\">\n");
|
||||
$this->m_oPage->add("<a name=\"step$iStepIndex\" />\n");
|
||||
$aStates = MetaModel::EnumStates($this->m_sClass);
|
||||
$aDetails = array();
|
||||
$sJSHandlerCode = ''; // Javascript code to be executed each time this step of the wizard is entered
|
||||
foreach($aStep as $sAttCode)
|
||||
{
|
||||
$oAttDef = MetaModel::GetAttributeDef($this->m_sClass, $sAttCode);
|
||||
if ($oAttDef->IsWritable())
|
||||
{
|
||||
$sAttLabel = $oAttDef->GetLabel();
|
||||
$iOptions = isset($aStates[$this->m_sTargetState]['attribute_list'][$sAttCode]) ? $aStates[$this->m_sTargetState]['attribute_list'][$sAttCode] : 0;
|
||||
|
||||
$aPrerequisites = $oAttDef->GetPrerequisiteAttributes();
|
||||
if ($iOptions & (OPT_ATT_MANDATORY | OPT_ATT_MUSTCHANGE | OPT_ATT_MUSTPROMPT))
|
||||
{
|
||||
$aFields[$sAttCode] = array();
|
||||
foreach($aPrerequisites as $sCode)
|
||||
{
|
||||
$aFields[$sAttCode][$sCode] = '';
|
||||
}
|
||||
}
|
||||
if (count($aPrerequisites) > 0)
|
||||
{
|
||||
$aOptions[] = 'Prerequisites: '.implode(', ', $aPrerequisites);
|
||||
}
|
||||
|
||||
$sFieldFlag = (($iOptions & (OPT_ATT_MANDATORY | OPT_ATT_MUSTCHANGE)) || (!$oAttDef->IsNullAllowed()) )? ' <span class="hilite">*</span>' : '';
|
||||
$oDefaultValuesSet = $oAttDef->GetDefaultValue(/* $oObject->ToArgs() */); // @@@ TO DO: get the object's current value if the object exists
|
||||
$sHTMLValue = cmdbAbstractObject::GetFormElementForField($this->m_oPage, $this->m_sClass, $sAttCode, $oAttDef, $oDefaultValuesSet, '', "att_$iMaxInputId", '', $iOptions, $aArgs);
|
||||
$aFieldsMap["att_$iMaxInputId"] = $sAttCode;
|
||||
$aDetails[] = array('label' => '<span title="'.$oAttDef->GetDescription().'">'.$oAttDef->GetLabel().$sFieldFlag.'</span>', 'value' => "<span id=\"field_att_$iMaxInputId\">$sHTMLValue</span>");
|
||||
if ($oAttDef->GetValuesDef() != null)
|
||||
{
|
||||
$sJSHandlerCode .= "\toWizardHelper.RequestAllowedValues('$sAttCode');\n";
|
||||
}
|
||||
if ($oAttDef->GetDefaultValue() != null)
|
||||
{
|
||||
$sJSHandlerCode .= "\toWizardHelper.RequestDefaultValue('$sAttCode');\n";
|
||||
}
|
||||
if ($oAttDef->IsLinkSet())
|
||||
{
|
||||
$sJSHandlerCode .= "\toLinkWidgetatt_$iMaxInputId.Init();";
|
||||
}
|
||||
$iMaxInputId++;
|
||||
}
|
||||
}
|
||||
//$aDetails[] = array('label' => '', 'value' => '<input type="button" value="Next >>">');
|
||||
$this->m_oPage->details($aDetails);
|
||||
$sBackButtonDisabled = ($iStepIndex <= 1) ? 'disabled' : '';
|
||||
$sDisabled = $bFinishEnabled ? '' : 'disabled';
|
||||
$nbSteps = count($this->m_aWizardSteps['mandatory']) + count($this->m_aWizardSteps['optional']);
|
||||
$this->m_oPage->add("<div style=\"text-align:center\">
|
||||
<input type=\"button\" value=\"".Dict::S('UI:Button:Back')."\" $sBackButtonDisabled onClick=\"GoToStep($iStepIndex, $iStepIndex - 1)\" />
|
||||
<input type=\"button\" value=\"".Dict::S('UI:Button:Next')."\" onClick=\"GoToStep($iStepIndex, 1+$iStepIndex)\" />
|
||||
<input type=\"button\" value=\"".Dict::S('UI:Button:Finish')."\" $sDisabled onClick=\"GoToStep($iStepIndex, 1+$nbSteps)\" />
|
||||
</div>\n");
|
||||
$this->m_oPage->add_script("
|
||||
function OnEnterStep{$iStepIndex}()
|
||||
{
|
||||
oWizardHelper.ResetQuery();
|
||||
oWizardHelper.UpdateWizard();
|
||||
|
||||
$sJSHandlerCode
|
||||
|
||||
oWizardHelper.AjaxQueryServer();
|
||||
}
|
||||
");
|
||||
$this->m_oPage->add("</div>\n\n");
|
||||
}
|
||||
|
||||
/**
|
||||
* Display the final step of the wizard: a confirmation screen
|
||||
*/
|
||||
public function DisplayFinalStep($iStepIndex, $aFieldsMap)
|
||||
{
|
||||
$oAppContext = new ApplicationContext();
|
||||
$this->m_oPage->add("<div class=\"wizContainer\" id=\"wizStep$iStepIndex\" style=\"display:none;\">\n");
|
||||
$this->m_oPage->add("<a name=\"step$iStepIndex\" />\n");
|
||||
$this->m_oPage->P(Dict::S('UI:Wizard:FinalStepTitle'));
|
||||
$this->m_oPage->add("<input type=\"hidden\" name=\"operation\" value=\"wizard_apply_new\" />\n");
|
||||
$this->m_oPage->add("<input type=\"hidden\" name=\"transaction_id\" value=\"".utils::GetNewTransactionId()."\" />\n");
|
||||
$this->m_oPage->add("<input type=\"hidden\" id=\"wizard_json_obj\" name=\"json_obj\" value=\"\" />\n");
|
||||
$sScript = "function OnEnterStep$iStepIndex() {\n";
|
||||
foreach($aFieldsMap as $iInputId => $sAttCode)
|
||||
{
|
||||
$sScript .= "\toWizardHelper.UpdateCurrentValue('$sAttCode');\n";
|
||||
}
|
||||
$sScript .= "\toWizardHelper.Preview('object_preview');\n";
|
||||
$sScript .= "\t$('#wizard_json_obj').val(oWizardHelper.ToJSON());\n";
|
||||
$sScript .= "}\n";
|
||||
$this->m_oPage->add_script($sScript);
|
||||
$this->m_oPage->add("<div id=\"object_preview\">\n");
|
||||
$this->m_oPage->add("</div>\n");
|
||||
$this->m_oPage->add($oAppContext->GetForForm());
|
||||
$this->m_oPage->add("<input type=\"button\" value=\"".Dict::S('UI:Button:Back')."\" onClick=\"GoToStep($iStepIndex, $iStepIndex - 1)\" />");
|
||||
$this->m_oPage->add("<input type=\"submit\" value=\"Create ".MetaModel::GetName($this->m_sClass)."\" />\n");
|
||||
$this->m_oPage->add("</div>\n");
|
||||
$this->m_oPage->add("</form>\n");
|
||||
}
|
||||
/**
|
||||
* Compute the order of the fields & pages in the wizard
|
||||
* @param $oPage iTopWebPage The current page (used to display error messages)
|
||||
* @param $sClass string Name of the class
|
||||
* @param $sStateCode string Code of the target state of the object
|
||||
* @return hash Two dimensional array: each element represents the list of fields for a given page
|
||||
*/
|
||||
protected function ComputeWizardStructure()
|
||||
{
|
||||
$aWizardSteps = array( 'mandatory' => array(), 'optional' => array());
|
||||
$aFieldsDone = array(); // Store all the fields that are already covered by a previous step of the wizard
|
||||
|
||||
$aStates = MetaModel::EnumStates($this->m_sClass);
|
||||
$sStateAttCode = MetaModel::GetStateAttributeCode($this->m_sClass);
|
||||
|
||||
$aMandatoryAttributes = array();
|
||||
// Some attributes are always mandatory independently of the state machine (if any)
|
||||
foreach(MetaModel::GetAttributesList($this->m_sClass) as $sAttCode)
|
||||
{
|
||||
$oAttDef = MetaModel::GetAttributeDef($this->m_sClass, $sAttCode);
|
||||
if (!$oAttDef->IsExternalField() && !$oAttDef->IsNullAllowed() &&
|
||||
$oAttDef->IsWritable() && ($sAttCode != $sStateAttCode) )
|
||||
{
|
||||
$aMandatoryAttributes[$sAttCode] = OPT_ATT_MANDATORY;
|
||||
}
|
||||
}
|
||||
|
||||
// Now check the attributes that are mandatory in the specified state
|
||||
if ( (!empty($this->m_sTargetState)) && (count($aStates[$this->m_sTargetState]['attribute_list']) > 0) )
|
||||
{
|
||||
// Check all the fields that *must* be included in the wizard for this
|
||||
// particular target state
|
||||
$aFields = array();
|
||||
foreach($aStates[$this->m_sTargetState]['attribute_list'] as $sAttCode => $iOptions)
|
||||
{
|
||||
if ( (isset($aMandatoryAttributes[$sAttCode])) &&
|
||||
($aMandatoryAttributes[$sAttCode] & (OPT_ATT_MANDATORY | OPT_ATT_MUSTCHANGE | OPT_ATT_MUSTPROMPT)) )
|
||||
{
|
||||
$aMandatoryAttributes[$sAttCode] |= $iOptions;
|
||||
}
|
||||
else
|
||||
{
|
||||
$aMandatoryAttributes[$sAttCode] = $iOptions;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check all the fields that *must* be included in the wizard
|
||||
// i.e. all mandatory, must-change or must-prompt fields that are
|
||||
// not also read-only or hidden.
|
||||
// Some fields may be required (null not allowed) from the database
|
||||
// perspective, but hidden or read-only from the user interface perspective
|
||||
$aFields = array();
|
||||
foreach($aMandatoryAttributes as $sAttCode => $iOptions)
|
||||
{
|
||||
if ( ($iOptions & (OPT_ATT_MANDATORY | OPT_ATT_MUSTCHANGE | OPT_ATT_MUSTPROMPT)) &&
|
||||
!($iOptions & (OPT_ATT_READONLY | OPT_ATT_HIDDEN)) )
|
||||
{
|
||||
$oAttDef = MetaModel::GetAttributeDef($this->m_sClass, $sAttCode);
|
||||
$aPrerequisites = $oAttDef->GetPrerequisiteAttributes();
|
||||
$aFields[$sAttCode] = array();
|
||||
foreach($aPrerequisites as $sCode)
|
||||
{
|
||||
$aFields[$sAttCode][$sCode] = '';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Now use the dependencies between the fields to order them
|
||||
// Start from the order of the 'details'
|
||||
$aList = MetaModel::FlattenZlist(MetaModel::GetZListItems($this->m_sClass, 'details'));
|
||||
$index = 0;
|
||||
$aOrder = array();
|
||||
foreach($aFields as $sAttCode => $void)
|
||||
{
|
||||
$aOrder[$sAttCode] = 999; // At the end of the list...
|
||||
}
|
||||
foreach($aList as $sAttCode)
|
||||
{
|
||||
if (array_key_exists($sAttCode, $aFields))
|
||||
{
|
||||
$aOrder[$sAttCode] = $index;
|
||||
}
|
||||
$index++;
|
||||
}
|
||||
foreach($aFields as $sAttCode => $aDependencies)
|
||||
{
|
||||
// All fields with no remaining dependencies can be entered at this
|
||||
// step of the wizard
|
||||
if (count($aDependencies) > 0)
|
||||
{
|
||||
$iMaxPos = 0;
|
||||
// Remove this field from the dependencies of the other fields
|
||||
foreach($aDependencies as $sDependentAttCode => $void)
|
||||
{
|
||||
// position the current field after the ones it depends on
|
||||
$iMaxPos = max($iMaxPos, 1+$aOrder[$sDependentAttCode]);
|
||||
}
|
||||
}
|
||||
}
|
||||
asort($aOrder);
|
||||
$aCurrentStep = array();
|
||||
foreach($aOrder as $sAttCode => $rank)
|
||||
{
|
||||
$aCurrentStep[] = $sAttCode;
|
||||
$aFieldsDone[$sAttCode] = '';
|
||||
}
|
||||
$aWizardSteps['mandatory'][] = $aCurrentStep;
|
||||
|
||||
|
||||
// Now computes the steps to fill the optional fields
|
||||
$aFields = array(); // reset
|
||||
foreach(MetaModel::ListAttributeDefs($this->m_sClass) as $sAttCode=>$oAttDef)
|
||||
{
|
||||
$iOptions = (isset($aStates[$this->m_sTargetState]['attribute_list'][$sAttCode])) ? $aStates[$this->m_sTargetState]['attribute_list'][$sAttCode] : 0;
|
||||
if ( ($sStateAttCode != $sAttCode) &&
|
||||
(!$oAttDef->IsExternalField()) &&
|
||||
(($iOptions & (OPT_ATT_HIDDEN | OPT_ATT_READONLY)) == 0) &&
|
||||
(!isset($aFieldsDone[$sAttCode])) )
|
||||
|
||||
{
|
||||
// 'State', external fields, read-only and hidden fields
|
||||
// and fields that are already listed in the wizard
|
||||
// are removed from the 'optional' part of the wizard
|
||||
$oAttDef = MetaModel::GetAttributeDef($this->m_sClass, $sAttCode);
|
||||
$aPrerequisites = $oAttDef->GetPrerequisiteAttributes();
|
||||
$aFields[$sAttCode] = array();
|
||||
foreach($aPrerequisites as $sCode)
|
||||
{
|
||||
if (!isset($aFieldsDone[$sCode]))
|
||||
{
|
||||
// retain only the dependencies that were not covered
|
||||
// in the 'mandatory' part of the wizard
|
||||
$aFields[$sAttCode][$sCode] = '';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Now use the dependencies between the fields to order them
|
||||
while(count($aFields) > 0)
|
||||
{
|
||||
$aCurrentStep = array();
|
||||
foreach($aFields as $sAttCode => $aDependencies)
|
||||
{
|
||||
// All fields with no remaining dependencies can be entered at this
|
||||
// step of the wizard
|
||||
if (count($aDependencies) == 0)
|
||||
{
|
||||
$aCurrentStep[] = $sAttCode;
|
||||
$aFieldsDone[$sAttCode] = '';
|
||||
unset($aFields[$sAttCode]);
|
||||
// Remove this field from the dependencies of the other fields
|
||||
foreach($aFields as $sUpdatedCode => $aDummy)
|
||||
{
|
||||
// remove the dependency
|
||||
unset($aFields[$sUpdatedCode][$sAttCode]);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (count($aCurrentStep) == 0)
|
||||
{
|
||||
// This step of the wizard would contain NO field !
|
||||
$this->m_oPage->add(Dict::S('UI:Error:WizardCircularReferenceInDependencies'));
|
||||
print_r($aFields);
|
||||
break;
|
||||
}
|
||||
$aWizardSteps['optional'][] = $aCurrentStep;
|
||||
}
|
||||
return $aWizardSteps;
|
||||
|
||||
}
|
||||
}
|
||||
?>
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,338 +1,369 @@
|
||||
<?php
|
||||
// Copyright (C) 2010-2016 Combodo SARL
|
||||
//
|
||||
// This file is part of iTop.
|
||||
//
|
||||
// iTop is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// iTop is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with iTop. If not, see <http://www.gnu.org/licenses/>
|
||||
|
||||
|
||||
/**
|
||||
* Class WizardHelper
|
||||
*
|
||||
* @copyright Copyright (C) 2010-2016 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
require_once(APPROOT.'/application/uiwizard.class.inc.php');
|
||||
|
||||
class WizardHelper
|
||||
{
|
||||
protected $m_aData;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
}
|
||||
/**
|
||||
* Constructs the PHP target object from the parameters sent to the web page by the wizard
|
||||
* @param boolean $bReadUploadedFiles True to also read any uploaded file (for blob/document fields)
|
||||
* @return object
|
||||
*/
|
||||
public function GetTargetObject($bReadUploadedFiles = false)
|
||||
{
|
||||
if (isset($this->m_aData['m_oCurrentValues']['id']))
|
||||
{
|
||||
$oObj = MetaModel::GetObject($this->m_aData['m_sClass'], $this->m_aData['m_oCurrentValues']['id']);
|
||||
}
|
||||
else
|
||||
{
|
||||
$oObj = MetaModel::NewObject($this->m_aData['m_sClass']);
|
||||
}
|
||||
foreach($this->m_aData['m_oCurrentValues'] as $sAttCode => $value)
|
||||
{
|
||||
// Because this is stored in a Javascript array, unused indexes
|
||||
// are filled with null values and unused keys (stored as strings) contain $$NULL$$
|
||||
if ( ($sAttCode !='id') && ($value !== '$$NULL$$'))
|
||||
{
|
||||
$oAttDef = MetaModel::GetAttributeDef($this->m_aData['m_sClass'], $sAttCode);
|
||||
if (($oAttDef->IsLinkSet()) && ($value != '') )
|
||||
{
|
||||
// special handling for lists
|
||||
// assumes this is handled as an array of objects
|
||||
// thus encoded in json like: [ { name:'link1', 'id': 123}, { name:'link2', 'id': 124}...]
|
||||
$aData = json_decode($value, true); // true means decode as a hash array (not an object)
|
||||
// Check what are the meaningful attributes
|
||||
$aFields = $this->GetLinkedWizardStructure($oAttDef);
|
||||
$sLinkedClass = $oAttDef->GetLinkedClass();
|
||||
$aLinkedObjectsArray = array();
|
||||
if (!is_array($aData))
|
||||
{
|
||||
echo ("aData: '$aData' (value: '$value')\n");
|
||||
}
|
||||
foreach($aData as $aLinkedObject)
|
||||
{
|
||||
$oLinkedObj = MetaModel::NewObject($sLinkedClass);
|
||||
foreach($aFields as $sLinkedAttCode)
|
||||
{
|
||||
if ( isset($aLinkedObject[$sLinkedAttCode]) && ($aLinkedObject[$sLinkedAttCode] !== null) )
|
||||
{
|
||||
$sLinkedAttDef = MetaModel::GetAttributeDef($sLinkedClass, $sLinkedAttCode);
|
||||
if (($sLinkedAttDef->IsExternalKey()) && ($aLinkedObject[$sLinkedAttCode] != '') && ($aLinkedObject[$sLinkedAttCode] > 0) )
|
||||
{
|
||||
// For external keys: load the target object so that external fields
|
||||
// get filled too
|
||||
$oTargetObj = MetaModel::GetObject($sLinkedAttDef->GetTargetClass(), $aLinkedObject[$sLinkedAttCode]);
|
||||
$oLinkedObj->Set($sLinkedAttCode, $oTargetObj);
|
||||
}
|
||||
elseif($sLinkedAttDef instanceof AttributeDateTime)
|
||||
{
|
||||
$sDate = $aLinkedObject[$sLinkedAttCode];
|
||||
if($sDate !== null && $sDate !== '')
|
||||
{
|
||||
$oDateTimeFormat = AttributeDateTime::GetFormat();
|
||||
$oDate = $oDateTimeFormat->Parse($sDate);
|
||||
$sDate = $oDate->format('Y-m-d H:i:s');
|
||||
}
|
||||
|
||||
$oLinkedObj->Set($sLinkedAttCode, $sDate);
|
||||
}
|
||||
else
|
||||
{
|
||||
$oLinkedObj->Set($sLinkedAttCode, $aLinkedObject[$sLinkedAttCode]);
|
||||
}
|
||||
}
|
||||
}
|
||||
$aLinkedObjectsArray[] = $oLinkedObj;
|
||||
}
|
||||
$oSet = DBObjectSet::FromArray($sLinkedClass, $aLinkedObjectsArray);
|
||||
$oObj->Set($sAttCode, $oSet);
|
||||
}
|
||||
else if ( $oAttDef->GetEditClass() == 'Document' )
|
||||
{
|
||||
if ($bReadUploadedFiles)
|
||||
{
|
||||
$oDocument = utils::ReadPostedDocument('attr_'.$sAttCode, 'fcontents');
|
||||
$oObj->Set($sAttCode, $oDocument);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Create a new empty document, just for displaying the file name
|
||||
$oDocument = new ormDocument(null, '', $value);
|
||||
$oObj->Set($sAttCode, $oDocument);
|
||||
}
|
||||
}
|
||||
else if ( $oAttDef->GetEditClass() == 'Image' )
|
||||
{
|
||||
if ($bReadUploadedFiles)
|
||||
{
|
||||
$oDocument = utils::ReadPostedDocument('attr_'.$sAttCode, 'fcontents');
|
||||
$oObj->Set($sAttCode, $oDocument);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Create a new empty document, just for displaying the file name
|
||||
$oDocument = new ormDocument(null, '', $value);
|
||||
$oObj->Set($sAttCode, $oDocument);
|
||||
}
|
||||
}
|
||||
else if (($oAttDef->IsExternalKey()) && (!empty($value)) && ($value > 0) )
|
||||
{
|
||||
// For external keys: load the target object so that external fields
|
||||
// get filled too
|
||||
$oTargetObj = MetaModel::GetObject($oAttDef->GetTargetClass(), $value, false);
|
||||
if ($oTargetObj)
|
||||
{
|
||||
$oObj->Set($sAttCode, $oTargetObj);
|
||||
}
|
||||
else
|
||||
{
|
||||
// May happen for security reasons (portal, see ticket #1074)
|
||||
$oObj->Set($sAttCode, $value);
|
||||
}
|
||||
}
|
||||
else if ($oAttDef instanceof AttributeDateTime) // AttributeDate is derived from AttributeDateTime
|
||||
{
|
||||
if ($value != null)
|
||||
{
|
||||
$oDate = $oAttDef->GetFormat()->Parse($value);
|
||||
if ($oDate instanceof DateTime)
|
||||
{
|
||||
$value = $oDate->format($oAttDef->GetInternalFormat());
|
||||
}
|
||||
else
|
||||
{
|
||||
$value = null;
|
||||
}
|
||||
}
|
||||
$oObj->Set($sAttCode, $value);
|
||||
}
|
||||
else
|
||||
{
|
||||
$oObj->Set($sAttCode, $value);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (isset($this->m_aData['m_sState']) && !empty($this->m_aData['m_sState']))
|
||||
{
|
||||
$oObj->Set(MetaModel::GetStateAttributeCode($this->m_aData['m_sClass']), $this->m_aData['m_sState']);
|
||||
}
|
||||
$oObj->DoComputeValues();
|
||||
return $oObj;
|
||||
}
|
||||
|
||||
public function GetFieldsForDefaultValue()
|
||||
{
|
||||
return $this->m_aData['m_aDefaultValueRequested'];
|
||||
}
|
||||
|
||||
public function SetDefaultValue($sAttCode, $value)
|
||||
{
|
||||
// Protect against a request for a non existing field
|
||||
if (isset($this->m_aData['m_oFieldsMap'][$sAttCode]))
|
||||
{
|
||||
$oAttDef = MetaModel::GetAttributeDef($this->m_aData['m_sClass'], $sAttCode);
|
||||
if ($oAttDef->GetEditClass() == 'List')
|
||||
{
|
||||
// special handling for lists
|
||||
// this as to be handled as an array of objects
|
||||
// thus encoded in json like: [ { name:'link1', 'id': 123}, { name:'link2', 'id': 124}...]
|
||||
// NOT YET IMPLEMENTED !!
|
||||
$sLinkedClass = $oAttDef->GetLinkedClass();
|
||||
$oSet = $value;
|
||||
$aData = array();
|
||||
$aFields = $this->GetLinkedWizardStructure($oAttDef);
|
||||
while($oSet->fetch())
|
||||
{
|
||||
foreach($aFields as $sLinkedAttCode)
|
||||
{
|
||||
$aRow[$sAttCode] = $oLinkedObj->Get($sLinkedAttCode);
|
||||
}
|
||||
$aData[] = $aRow;
|
||||
}
|
||||
$this->m_aData['m_oDefaultValue'][$sAttCode] = json_encode($aData);
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
// Normal handling for all other scalar attributes
|
||||
$this->m_aData['m_oDefaultValue'][$sAttCode] = $value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function GetFieldsForAllowedValues()
|
||||
{
|
||||
return $this->m_aData['m_aAllowedValuesRequested'];
|
||||
}
|
||||
|
||||
public function SetAllowedValuesHtml($sAttCode, $sHtml)
|
||||
{
|
||||
// Protect against a request for a non existing field
|
||||
if (isset($this->m_aData['m_oFieldsMap'][$sAttCode]))
|
||||
{
|
||||
$this->m_aData['m_oAllowedValues'][$sAttCode] = $sHtml;
|
||||
}
|
||||
}
|
||||
|
||||
public function ToJSON()
|
||||
{
|
||||
return json_encode($this->m_aData);
|
||||
}
|
||||
|
||||
static public function FromJSON($sJSON)
|
||||
{
|
||||
$oWizHelper = new WizardHelper();
|
||||
if (get_magic_quotes_gpc())
|
||||
{
|
||||
$sJSON = stripslashes($sJSON);
|
||||
}
|
||||
$aData = json_decode($sJSON, true); // true means hash array instead of object
|
||||
$oWizHelper->m_aData = $aData;
|
||||
return $oWizHelper;
|
||||
}
|
||||
|
||||
protected function GetLinkedWizardStructure($oAttDef)
|
||||
{
|
||||
$oWizard = new UIWizard(null, $oAttDef->GetLinkedClass());
|
||||
$aWizardSteps = $oWizard->GetWizardStructure();
|
||||
$aFields = array();
|
||||
$sExtKeyToMeCode = $oAttDef->GetExtKeyToMe();
|
||||
// Retrieve as a flat list, all the attributes that are needed to create
|
||||
// an object of the linked class and put them into a flat array, except
|
||||
// the attribute 'ext_key_to_me' which is a constant in our case
|
||||
foreach($aWizardSteps as $sDummy => $aMainSteps)
|
||||
{
|
||||
// 2 entries: 'mandatory' and 'optional'
|
||||
foreach($aMainSteps as $aSteps)
|
||||
{
|
||||
// One entry for each step of the wizard
|
||||
foreach($aSteps as $sAttCode)
|
||||
{
|
||||
if ($sAttCode != $sExtKeyToMeCode)
|
||||
{
|
||||
$aFields[] = $sAttCode;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return $aFields;
|
||||
}
|
||||
|
||||
public function GetTargetClass()
|
||||
{
|
||||
return $this->m_aData['m_sClass'];
|
||||
}
|
||||
|
||||
public function GetFormPrefix()
|
||||
{
|
||||
return $this->m_aData['m_sFormPrefix'];
|
||||
}
|
||||
|
||||
public function GetInitialState()
|
||||
{
|
||||
return isset($this->m_aData['m_sInitialState']) ? $this->m_aData['m_sInitialState'] : null;
|
||||
}
|
||||
|
||||
public function GetStimulus()
|
||||
{
|
||||
return isset($this->m_aData['m_sStimulus']) ? $this->m_aData['m_sStimulus'] : null;
|
||||
}
|
||||
|
||||
public function GetIdForField($sFieldName)
|
||||
{
|
||||
$sResult = '';
|
||||
// It may happen that the field we'd like to update does not
|
||||
// exist in the form. For example, if the field should be hidden/read-only
|
||||
// in the current state of the object
|
||||
if (isset($this->m_aData['m_oFieldsMap'][$sFieldName]))
|
||||
{
|
||||
$sResult = $this->m_aData['m_oFieldsMap'][$sFieldName];
|
||||
}
|
||||
return $sResult;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
$oLink = MetaModel::NewObject($sLinkClass);
|
||||
foreach($aLinkObj as $sAttCode => $value)
|
||||
{
|
||||
$oAttDef = MetaModel::GetAttributeDef($sLinkClass, $sAttCode);
|
||||
if (($oAttDef->IsExternalKey()) && ($value != '') && ($value > 0))
|
||||
{
|
||||
// For external keys: load the target object so that external fields
|
||||
// get filled too
|
||||
$oTargetObj = MetaModel::GetObject($oAttDef->GetTargetClass(), $value);
|
||||
$oLink->Set($sAttCode, $oTargetObj);
|
||||
}
|
||||
$oLink->Set($sAttCode, $value);
|
||||
}
|
||||
$oLink->Set($sExtKeyToMe, $oMe->GetKey());
|
||||
$oSet->AddObject($oLink);
|
||||
}
|
||||
return $oSet;
|
||||
}
|
||||
}
|
||||
<?php
|
||||
// Copyright (C) 2010-2016 Combodo SARL
|
||||
//
|
||||
// This file is part of iTop.
|
||||
//
|
||||
// iTop is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// iTop is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with iTop. If not, see <http://www.gnu.org/licenses/>
|
||||
|
||||
|
||||
/**
|
||||
* Class WizardHelper
|
||||
*
|
||||
* @copyright Copyright (C) 2010-2016 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
require_once(APPROOT.'/application/uiwizard.class.inc.php');
|
||||
|
||||
class WizardHelper
|
||||
{
|
||||
protected $m_aData;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
}
|
||||
/**
|
||||
* Constructs the PHP target object from the parameters sent to the web page by the wizard
|
||||
* @param boolean $bReadUploadedFiles True to also read any uploaded file (for blob/document fields)
|
||||
* @return object
|
||||
*/
|
||||
public function GetTargetObject($bReadUploadedFiles = false)
|
||||
{
|
||||
if (isset($this->m_aData['m_oCurrentValues']['id']))
|
||||
{
|
||||
$oObj = MetaModel::GetObject($this->m_aData['m_sClass'], $this->m_aData['m_oCurrentValues']['id']);
|
||||
}
|
||||
else
|
||||
{
|
||||
$oObj = MetaModel::NewObject($this->m_aData['m_sClass']);
|
||||
}
|
||||
foreach($this->m_aData['m_oCurrentValues'] as $sAttCode => $value)
|
||||
{
|
||||
// Because this is stored in a Javascript array, unused indexes
|
||||
// are filled with null values and unused keys (stored as strings) contain $$NULL$$
|
||||
if ( ($sAttCode !='id') && ($value !== '$$NULL$$'))
|
||||
{
|
||||
$oAttDef = MetaModel::GetAttributeDef($this->m_aData['m_sClass'], $sAttCode);
|
||||
if (($oAttDef->IsLinkSet()) && ($value != '') )
|
||||
{
|
||||
// special handling for lists
|
||||
// assumes this is handled as an array of objects
|
||||
// thus encoded in json like: [ { name:'link1', 'id': 123}, { name:'link2', 'id': 124}...]
|
||||
$aData = json_decode($value, true); // true means decode as a hash array (not an object)
|
||||
// Check what are the meaningful attributes
|
||||
$aFields = $this->GetLinkedWizardStructure($oAttDef);
|
||||
$sLinkedClass = $oAttDef->GetLinkedClass();
|
||||
$aLinkedObjectsArray = array();
|
||||
if (!is_array($aData))
|
||||
{
|
||||
echo ("aData: '$aData' (value: '$value')\n");
|
||||
}
|
||||
foreach($aData as $aLinkedObject)
|
||||
{
|
||||
$oLinkedObj = MetaModel::NewObject($sLinkedClass);
|
||||
foreach($aFields as $sLinkedAttCode)
|
||||
{
|
||||
if ( isset($aLinkedObject[$sLinkedAttCode]) && ($aLinkedObject[$sLinkedAttCode] !== null) )
|
||||
{
|
||||
$sLinkedAttDef = MetaModel::GetAttributeDef($sLinkedClass, $sLinkedAttCode);
|
||||
if (($sLinkedAttDef->IsExternalKey()) && ($aLinkedObject[$sLinkedAttCode] != '') && ($aLinkedObject[$sLinkedAttCode] > 0) )
|
||||
{
|
||||
// For external keys: load the target object so that external fields
|
||||
// get filled too
|
||||
$oTargetObj = MetaModel::GetObject($sLinkedAttDef->GetTargetClass(), $aLinkedObject[$sLinkedAttCode]);
|
||||
$oLinkedObj->Set($sLinkedAttCode, $oTargetObj);
|
||||
}
|
||||
elseif($sLinkedAttDef instanceof AttributeDateTime)
|
||||
{
|
||||
$sDateClass = get_class($sLinkedAttDef);
|
||||
$sDate = $aLinkedObject[$sLinkedAttCode];
|
||||
if($sDate !== null && $sDate !== '')
|
||||
{
|
||||
$oDateTimeFormat = $sDateClass::GetFormat();
|
||||
$oDate = $oDateTimeFormat->Parse($sDate);
|
||||
if ($sDateClass == "AttributeDate")
|
||||
{
|
||||
$sDate = $oDate->format('Y-m-d');
|
||||
}
|
||||
else
|
||||
{
|
||||
$sDate = $oDate->format('Y-m-d H:i:s');
|
||||
}
|
||||
}
|
||||
|
||||
$oLinkedObj->Set($sLinkedAttCode, $sDate);
|
||||
}
|
||||
else
|
||||
{
|
||||
$oLinkedObj->Set($sLinkedAttCode, $aLinkedObject[$sLinkedAttCode]);
|
||||
}
|
||||
}
|
||||
}
|
||||
$aLinkedObjectsArray[] = $oLinkedObj;
|
||||
}
|
||||
$oSet = DBObjectSet::FromArray($sLinkedClass, $aLinkedObjectsArray);
|
||||
$oObj->Set($sAttCode, $oSet);
|
||||
}
|
||||
else if ( $oAttDef->GetEditClass() == 'Document' )
|
||||
{
|
||||
if ($bReadUploadedFiles)
|
||||
{
|
||||
$oDocument = utils::ReadPostedDocument('attr_'.$sAttCode, 'fcontents');
|
||||
$oObj->Set($sAttCode, $oDocument);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Create a new empty document, just for displaying the file name
|
||||
$oDocument = new ormDocument(null, '', $value);
|
||||
$oObj->Set($sAttCode, $oDocument);
|
||||
}
|
||||
}
|
||||
else if ( $oAttDef->GetEditClass() == 'Image' )
|
||||
{
|
||||
if ($bReadUploadedFiles)
|
||||
{
|
||||
$oDocument = utils::ReadPostedDocument('attr_'.$sAttCode, 'fcontents');
|
||||
$oObj->Set($sAttCode, $oDocument);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Create a new empty document, just for displaying the file name
|
||||
$oDocument = new ormDocument(null, '', $value);
|
||||
$oObj->Set($sAttCode, $oDocument);
|
||||
}
|
||||
}
|
||||
else if (($oAttDef->IsExternalKey()) && (!empty($value)) && ($value > 0) )
|
||||
{
|
||||
// For external keys: load the target object so that external fields
|
||||
// get filled too
|
||||
$oTargetObj = MetaModel::GetObject($oAttDef->GetTargetClass(), $value, false);
|
||||
if ($oTargetObj)
|
||||
{
|
||||
$oObj->Set($sAttCode, $oTargetObj);
|
||||
}
|
||||
else
|
||||
{
|
||||
// May happen for security reasons (portal, see ticket N°1074)
|
||||
$oObj->Set($sAttCode, $value);
|
||||
}
|
||||
}
|
||||
else if ($oAttDef instanceof AttributeDateTime) // AttributeDate is derived from AttributeDateTime
|
||||
{
|
||||
if ($value != null)
|
||||
{
|
||||
$oDate = $oAttDef->GetFormat()->Parse($value);
|
||||
if ($oDate instanceof DateTime)
|
||||
{
|
||||
$value = $oDate->format($oAttDef->GetInternalFormat());
|
||||
}
|
||||
else
|
||||
{
|
||||
$value = null;
|
||||
}
|
||||
}
|
||||
$oObj->Set($sAttCode, $value);
|
||||
}
|
||||
else if ($oAttDef instanceof AttributeTagSet) // AttributeDate is derived from AttributeDateTime
|
||||
{
|
||||
if (is_null($value))
|
||||
{
|
||||
// happens if field is hidden (see N°1827)
|
||||
$value = array();
|
||||
}
|
||||
else
|
||||
{
|
||||
$value = json_decode($value, true);
|
||||
}
|
||||
$oTagSet = new ormTagSet(get_class($oObj), $sAttCode, $oAttDef->GetMaxItems());
|
||||
$oTagSet->SetValues($value['orig_value']);
|
||||
$oTagSet->ApplyDelta($value);
|
||||
$oObj->Set($sAttCode, $oTagSet);
|
||||
}
|
||||
else if ($oAttDef instanceof AttributeSet) // AttributeDate is derived from AttributeDateTime
|
||||
{
|
||||
$value = json_decode($value, true);
|
||||
$oTagSet = new ormSet(get_class($oObj), $sAttCode, $oAttDef->GetMaxItems());
|
||||
$oTagSet->SetValues($value['orig_value']);
|
||||
$oTagSet->ApplyDelta($value);
|
||||
$oObj->Set($sAttCode, $oTagSet);
|
||||
}
|
||||
else
|
||||
{
|
||||
$oObj->Set($sAttCode, $value);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (isset($this->m_aData['m_sState']) && !empty($this->m_aData['m_sState']))
|
||||
{
|
||||
$oObj->Set(MetaModel::GetStateAttributeCode($this->m_aData['m_sClass']), $this->m_aData['m_sState']);
|
||||
}
|
||||
$oObj->DoComputeValues();
|
||||
return $oObj;
|
||||
}
|
||||
|
||||
public function GetFieldsForDefaultValue()
|
||||
{
|
||||
return $this->m_aData['m_aDefaultValueRequested'];
|
||||
}
|
||||
|
||||
public function SetDefaultValue($sAttCode, $value)
|
||||
{
|
||||
// Protect against a request for a non existing field
|
||||
if (isset($this->m_aData['m_oFieldsMap'][$sAttCode]))
|
||||
{
|
||||
$oAttDef = MetaModel::GetAttributeDef($this->m_aData['m_sClass'], $sAttCode);
|
||||
if ($oAttDef->GetEditClass() == 'List')
|
||||
{
|
||||
// special handling for lists
|
||||
// this as to be handled as an array of objects
|
||||
// thus encoded in json like: [ { name:'link1', 'id': 123}, { name:'link2', 'id': 124}...]
|
||||
// NOT YET IMPLEMENTED !!
|
||||
$oSet = $value;
|
||||
$aData = array();
|
||||
$aFields = $this->GetLinkedWizardStructure($oAttDef);
|
||||
while($oLinkedObj = $oSet->fetch())
|
||||
{
|
||||
foreach($aFields as $sLinkedAttCode)
|
||||
{
|
||||
$aRow[$sAttCode] = $oLinkedObj->Get($sLinkedAttCode);
|
||||
}
|
||||
$aData[] = $aRow;
|
||||
}
|
||||
$this->m_aData['m_oDefaultValue'][$sAttCode] = json_encode($aData);
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
// Normal handling for all other scalar attributes
|
||||
$this->m_aData['m_oDefaultValue'][$sAttCode] = $value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function GetFieldsForAllowedValues()
|
||||
{
|
||||
return $this->m_aData['m_aAllowedValuesRequested'];
|
||||
}
|
||||
|
||||
public function SetAllowedValuesHtml($sAttCode, $sHtml)
|
||||
{
|
||||
// Protect against a request for a non existing field
|
||||
if (isset($this->m_aData['m_oFieldsMap'][$sAttCode]))
|
||||
{
|
||||
$this->m_aData['m_oAllowedValues'][$sAttCode] = $sHtml;
|
||||
}
|
||||
}
|
||||
|
||||
public function ToJSON()
|
||||
{
|
||||
return json_encode($this->m_aData);
|
||||
}
|
||||
|
||||
static public function FromJSON($sJSON)
|
||||
{
|
||||
$oWizHelper = new WizardHelper();
|
||||
if (get_magic_quotes_gpc())
|
||||
{
|
||||
$sJSON = stripslashes($sJSON);
|
||||
}
|
||||
$aData = json_decode($sJSON, true); // true means hash array instead of object
|
||||
$oWizHelper->m_aData = $aData;
|
||||
return $oWizHelper;
|
||||
}
|
||||
|
||||
protected function GetLinkedWizardStructure($oAttDef)
|
||||
{
|
||||
$oWizard = new UIWizard(null, $oAttDef->GetLinkedClass());
|
||||
$aWizardSteps = $oWizard->GetWizardStructure();
|
||||
$aFields = array();
|
||||
$sExtKeyToMeCode = $oAttDef->GetExtKeyToMe();
|
||||
// Retrieve as a flat list, all the attributes that are needed to create
|
||||
// an object of the linked class and put them into a flat array, except
|
||||
// the attribute 'ext_key_to_me' which is a constant in our case
|
||||
foreach($aWizardSteps as $sDummy => $aMainSteps)
|
||||
{
|
||||
// 2 entries: 'mandatory' and 'optional'
|
||||
foreach($aMainSteps as $aSteps)
|
||||
{
|
||||
// One entry for each step of the wizard
|
||||
foreach($aSteps as $sAttCode)
|
||||
{
|
||||
if ($sAttCode != $sExtKeyToMeCode)
|
||||
{
|
||||
$aFields[] = $sAttCode;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return $aFields;
|
||||
}
|
||||
|
||||
public function GetTargetClass()
|
||||
{
|
||||
return $this->m_aData['m_sClass'];
|
||||
}
|
||||
|
||||
public function GetFormPrefix()
|
||||
{
|
||||
return $this->m_aData['m_sFormPrefix'];
|
||||
}
|
||||
|
||||
public function GetInitialState()
|
||||
{
|
||||
return isset($this->m_aData['m_sInitialState']) ? $this->m_aData['m_sInitialState'] : null;
|
||||
}
|
||||
|
||||
public function GetStimulus()
|
||||
{
|
||||
return isset($this->m_aData['m_sStimulus']) ? $this->m_aData['m_sStimulus'] : null;
|
||||
}
|
||||
|
||||
public function GetIdForField($sFieldName)
|
||||
{
|
||||
$sResult = '';
|
||||
// It may happen that the field we'd like to update does not
|
||||
// exist in the form. For example, if the field should be hidden/read-only
|
||||
// in the current state of the object
|
||||
if (isset($this->m_aData['m_oFieldsMap'][$sFieldName]))
|
||||
{
|
||||
$sResult = $this->m_aData['m_oFieldsMap'][$sFieldName];
|
||||
}
|
||||
return $sResult;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
$oLink = MetaModel::NewObject($sLinkClass);
|
||||
foreach($aLinkObj as $sAttCode => $value)
|
||||
{
|
||||
$oAttDef = MetaModel::GetAttributeDef($sLinkClass, $sAttCode);
|
||||
if (($oAttDef->IsExternalKey()) && ($value != '') && ($value > 0))
|
||||
{
|
||||
// For external keys: load the target object so that external fields
|
||||
// get filled too
|
||||
$oTargetObj = MetaModel::GetObject($oAttDef->GetTargetClass(), $value);
|
||||
$oLink->Set($sAttCode, $oTargetObj);
|
||||
}
|
||||
$oLink->Set($sAttCode, $value);
|
||||
}
|
||||
$oLink->Set($sExtKeyToMe, $oMe->GetKey());
|
||||
$oSet->AddObject($oLink);
|
||||
}
|
||||
return $oSet;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,7 +40,7 @@ Class XLSXWriter
|
||||
|
||||
protected function tempFilename()
|
||||
{
|
||||
$filename = tempnam("/tmp", "xlsx_writer_");
|
||||
$filename = tempnam(SetupUtils::GettmpDir(), 'xlsx_writer_');
|
||||
$this->temp_files[] = $filename;
|
||||
return $filename;
|
||||
}
|
||||
@@ -174,7 +174,7 @@ Class XLSXWriter
|
||||
fwrite($fd,'<c r="'.$cell.'" s="'.$s.'" t="n"><v>'.self::convert_date_time($value).'</v></c>');
|
||||
} else if ($value==''){
|
||||
fwrite($fd,'<c r="'.$cell.'" s="'.$s.'"/>');
|
||||
} else if ($value{0}=='='){
|
||||
} else if ($value[0]=='='){
|
||||
fwrite($fd,'<c r="'.$cell.'" s="'.$s.'" t="s"><f>'.self::xmlspecialchars($value).'</f></c>');
|
||||
} else if ($value!==''){
|
||||
fwrite($fd,'<c r="'.$cell.'" s="'.$s.'" t="s"><v>'.self::xmlspecialchars($this->setSharedString($value)).'</v></c>');
|
||||
|
||||
@@ -1,106 +1,109 @@
|
||||
<?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
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
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=utf-8");
|
||||
$this->add_header("Cache-control: no-cache");
|
||||
$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();
|
||||
|
||||
$this->s_content = "<?xml version=\"1.0\" encoding=\"UTF-8\"?".">\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);
|
||||
}
|
||||
echo "<?xml version=\"1.0\" encoding=\"UTF-8\"?".">\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())
|
||||
{
|
||||
}
|
||||
}
|
||||
<?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
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
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=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->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();
|
||||
|
||||
$this->s_content = "<?xml version=\"1.0\" encoding=\"UTF-8\"?".">\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);
|
||||
}
|
||||
echo "<?xml version=\"1.0\" encoding=\"UTF-8\"?".">\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())
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
25
composer.json
Normal file
25
composer.json
Normal file
@@ -0,0 +1,25 @@
|
||||
{
|
||||
"require": {
|
||||
"php": ">=5.6.0",
|
||||
"ext-soap": "*",
|
||||
"ext-json": "*",
|
||||
"ext-zip": "*",
|
||||
"ext-mysqli": "*",
|
||||
"ext-dom": "*",
|
||||
"ext-iconv": "*",
|
||||
"ext-gd": "*"
|
||||
},
|
||||
"suggest": {
|
||||
"ext-libsodium": "Required to use the AttributeEncryptedString.",
|
||||
"ext-openssl": "Can be used as a polyfill if libsodium is not installed",
|
||||
"ext-mcrypt": "Can be used as a polyfill if either libsodium and openssl are not installed (libsodium and openssl are more secure)",
|
||||
"ext-ldap": "Required to use LDAP as an identity provider",
|
||||
"ext-posix": "Not required by the core, but some extensions uses it.",
|
||||
"ext-imap": "Required by the extension \"Mail to ticket automation\""
|
||||
},
|
||||
"config": {
|
||||
"platform": {
|
||||
"php": "5.6.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
3054
composer.lock
generated
Normal file
3054
composer.lock
generated
Normal file
File diff suppressed because it is too large
Load Diff
13
conf/.htaccess
Normal file
13
conf/.htaccess
Normal file
@@ -0,0 +1,13 @@
|
||||
# Apache 2.4
|
||||
<ifModule mod_authz_core.c>
|
||||
Require all denied
|
||||
</ifModule>
|
||||
|
||||
# Apache 2.2
|
||||
<ifModule !mod_authz_core.c>
|
||||
deny from all
|
||||
Satisfy All
|
||||
</ifModule>
|
||||
|
||||
# Apache 2.2 and 2.4
|
||||
IndexIgnore *
|
||||
13
conf/web.config
Normal file
13
conf/web.config
Normal file
@@ -0,0 +1,13 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<configuration>
|
||||
<system.webServer>
|
||||
<security>
|
||||
<requestFiltering>
|
||||
<fileExtensions applyToWebDAV="false" allowUnlisted="false"></fileExtensions>
|
||||
</requestFiltering>
|
||||
<authorization>
|
||||
<deny users="*" /> <!-- Denies all users -->
|
||||
</authorization>
|
||||
</security>
|
||||
</system.webServer>
|
||||
</configuration>
|
||||
105
contributing.md
Normal file
105
contributing.md
Normal file
@@ -0,0 +1,105 @@
|
||||
# Contributing to iTop
|
||||
|
||||
You want to contribute to iTop? Many thanks to you! 🎉 👍
|
||||
|
||||
Here are some guidelines that will help us integrate your work!
|
||||
|
||||
|
||||
## Contributions
|
||||
|
||||
### Subjects
|
||||
You are welcome to create pull requests on any of those subjects:
|
||||
|
||||
* 🐛 `:bug:` bug fix
|
||||
* 🔒 `:lock:` security
|
||||
* 🌐 `:globe_with_meridians:` translation / i18n / l10n
|
||||
|
||||
If you want to implement a **new feature**, please [create a corresponding ticket](https://sourceforge.net/p/itop/tickets/new/) for review.
|
||||
If you ever want to begin implementation, do so in a fork, and add a link to the corresponding commits in the ticket.
|
||||
|
||||
### License
|
||||
iTop is distributed under the AGPL-3.0 license (see the [license.txt] file),
|
||||
your code must comply with this license.
|
||||
|
||||
If you want to use another license, you may [create an extension][wiki new ext].
|
||||
|
||||
[license.txt]: https://github.com/Combodo/iTop/blob/develop/license.txt
|
||||
[wiki new ext]: https://www.itophub.io/wiki/page?id=latest%3Acustomization%3Astart#by_writing_your_own_extension
|
||||
|
||||
|
||||
## Branch model
|
||||
|
||||
TL;DR:
|
||||
> **create a fork from iTop main repository,
|
||||
> create a branch based on either release branch if present, or develop otherwise**
|
||||
|
||||
We are using the [GitFlow](https://nvie.com/posts/a-successful-git-branching-model/) branch model. That means we have in our repo those
|
||||
main branches:
|
||||
|
||||
- develop: ongoing development version
|
||||
- release/\*: if present, that means we are working on a beta version
|
||||
- master: previous stable version
|
||||
|
||||
For example, if no beta version is currently ongoing we could have:
|
||||
|
||||
- develop containing future 2.8.0 version
|
||||
- master containing 2.7.x maintenance version
|
||||
|
||||
In this example, when 2.8.0-beta is shipped that will become:
|
||||
|
||||
- develop: future 2.9.0 version
|
||||
- release/2.8: 2.8.0-beta
|
||||
- master: 2.7.x maintenance version
|
||||
|
||||
And when 2.8.0 final will be out:
|
||||
|
||||
- develop: future 2.9.0 version
|
||||
- master: 2.8.x maintenance version
|
||||
- support/2.7 : 2.7.x maintenance version
|
||||
|
||||
|
||||
## Coding
|
||||
|
||||
### PHP styleguide
|
||||
|
||||
Please follow [our guidelines](https://www.itophub.io/wiki/page?id=latest%3Acustomization%3Acoding_standards).
|
||||
|
||||
### 🌐 Translations
|
||||
|
||||
A [dedicated page](https://www.itophub.io/wiki/page?id=latest%3Acustomization%3Atranslation) is available in the official wiki.
|
||||
|
||||
### Tests
|
||||
|
||||
Please create tests that covers as much as possible the code you're submitting.
|
||||
|
||||
Our tests are located in the `test/` directory, containing a PHPUnit config file : `phpunit.xml.dist`.
|
||||
|
||||
### Git Commit Messages
|
||||
|
||||
* Describe the functional change instead of the technical modifications
|
||||
* Use the present tense ("Add feature" not "Added feature")
|
||||
* Use the imperative mood ("Move cursor to..." not "Moves cursor to...")
|
||||
* Limit the first line to 72 characters or less
|
||||
* Please start the commit message with an applicable emoji code (following the [Gitmoji guide](https://gitmoji.carloscuesta.me/)). For example :
|
||||
* 🌐 `:globe_with_meridians:` for translations
|
||||
* 🎨 `:art:` when improving the format/structure of the code
|
||||
* ⚡️ `:zap:` when improving performance
|
||||
* 🐛 `:bug:` when fixing a bug
|
||||
* 🔥 `:fire:` when removing code or files
|
||||
* 💚 `:green_heart:` when fixing the CI build
|
||||
* ✅ `:white_check_mark:` when adding tests
|
||||
* 🔒 `:lock:` when dealing with security
|
||||
* ⬆️ `:arrow_up:` when upgrading dependencies
|
||||
* ⬇️ `:arrow_down:` when downgrading dependencies
|
||||
* ♻️ `:recycle:` code refactoring
|
||||
* 💄 `:lipstick:` Updating the UI and style files.
|
||||
|
||||
## Pull request
|
||||
|
||||
When your code is working, please:
|
||||
|
||||
* stash as much as possible your commits,
|
||||
* rebase your branch on our repo last commit,
|
||||
* create a pull request.
|
||||
|
||||
Detailed procedure to work on fork and create PR is available [in GitHub help pages](https://help.github.com/articles/creating-a-pull-request-from-a-fork/).
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,415 +1,453 @@
|
||||
<?php
|
||||
// Copyright (C) 2010-2016 Combodo SARL
|
||||
//
|
||||
// This file is part of iTop.
|
||||
//
|
||||
// iTop is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// iTop is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with iTop. If not, see <http://www.gnu.org/licenses/>
|
||||
|
||||
|
||||
/**
|
||||
* Persistent classes (internal): user defined actions
|
||||
*
|
||||
* @copyright Copyright (C) 2010-2016 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
|
||||
require_once(APPROOT.'/core/asynctask.class.inc.php');
|
||||
require_once(APPROOT.'/core/email.class.inc.php');
|
||||
|
||||
/**
|
||||
* A user defined action, to customize the application
|
||||
*
|
||||
* @package iTopORM
|
||||
*/
|
||||
abstract class Action extends cmdbAbstractObject
|
||||
{
|
||||
public static function Init()
|
||||
{
|
||||
$aParams = array
|
||||
(
|
||||
"category" => "core/cmdb",
|
||||
"key_type" => "autoincrement",
|
||||
"name_attcode" => "name",
|
||||
"state_attcode" => "",
|
||||
"reconc_keys" => array('name'),
|
||||
"db_table" => "priv_action",
|
||||
"db_key_field" => "id",
|
||||
"db_finalclass_field" => "realclass",
|
||||
"display_template" => "",
|
||||
);
|
||||
MetaModel::Init_Params($aParams);
|
||||
//MetaModel::Init_InheritAttributes();
|
||||
MetaModel::Init_AddAttribute(new AttributeString("name", array("allowed_values"=>null, "sql"=>"name", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeString("description", array("allowed_values"=>null, "sql"=>"description", "default_value"=>null, "is_null_allowed"=>true, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeEnum("status", array("allowed_values"=>new ValueSetEnum(array('test'=>'Being tested' ,'enabled'=>'In production', 'disabled'=>'Inactive')), "sql"=>"status", "default_value"=>"test", "is_null_allowed"=>false, "depends_on"=>array())));
|
||||
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
|
||||
// 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
|
||||
}
|
||||
|
||||
abstract public function DoExecute($oTrigger, $aContextArgs);
|
||||
|
||||
public function IsActive()
|
||||
{
|
||||
switch($this->Get('status'))
|
||||
{
|
||||
case 'enabled':
|
||||
case 'test':
|
||||
return true;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public function IsBeingTested()
|
||||
{
|
||||
switch($this->Get('status'))
|
||||
{
|
||||
case 'test':
|
||||
return true;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A notification
|
||||
*
|
||||
* @package iTopORM
|
||||
*/
|
||||
abstract class ActionNotification extends Action
|
||||
{
|
||||
public static function Init()
|
||||
{
|
||||
$aParams = array
|
||||
(
|
||||
"category" => "core/cmdb",
|
||||
"key_type" => "autoincrement",
|
||||
"name_attcode" => "name",
|
||||
"state_attcode" => "",
|
||||
"reconc_keys" => array('name'),
|
||||
"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
|
||||
// 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
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An email notification
|
||||
*
|
||||
* @package iTopORM
|
||||
*/
|
||||
class ActionEmail extends ActionNotification
|
||||
{
|
||||
public static function Init()
|
||||
{
|
||||
$aParams = array
|
||||
(
|
||||
"category" => "core/cmdb,application",
|
||||
"key_type" => "autoincrement",
|
||||
"name_attcode" => "name",
|
||||
"state_attcode" => "",
|
||||
"reconc_keys" => array('name'),
|
||||
"db_table" => "priv_action_email",
|
||||
"db_key_field" => "id",
|
||||
"db_finalclass_field" => "",
|
||||
"display_template" => "",
|
||||
);
|
||||
MetaModel::Init_Params($aParams);
|
||||
MetaModel::Init_InheritAttributes();
|
||||
|
||||
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("reply_to", array("allowed_values"=>null, "sql"=>"reply_to", "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())));
|
||||
MetaModel::Init_AddAttribute(new AttributeTemplateString("subject", array("allowed_values"=>null, "sql"=>"subject", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeTemplateHTML("body", array("allowed_values"=>null, "sql"=>"body", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeEnum("importance", array("allowed_values"=>new ValueSetEnum('low,normal,high'), "sql"=>"importance", "default_value"=>'normal', "is_null_allowed"=>false, "depends_on"=>array())));
|
||||
|
||||
// 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
|
||||
// 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
|
||||
}
|
||||
|
||||
// count the recipients found
|
||||
protected $m_iRecipients;
|
||||
|
||||
// Errors management : not that simple because we need that function to be
|
||||
// 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
|
||||
protected function FindRecipients($sRecipAttCode, $aArgs)
|
||||
{
|
||||
$sOQL = $this->Get($sRecipAttCode);
|
||||
if (strlen($sOQL) == '') return '';
|
||||
|
||||
try
|
||||
{
|
||||
$oSearch = DBObjectSearch::FromOQL($sOQL);
|
||||
$oSearch->AllowAllData();
|
||||
}
|
||||
catch (OQLException $e)
|
||||
{
|
||||
$this->m_aMailErrors[] = "query syntax error for recipient '$sRecipAttCode'";
|
||||
return $e->getMessage();
|
||||
}
|
||||
|
||||
$sClass = $oSearch->GetClass();
|
||||
// Determine the email attribute (the first one will be our choice)
|
||||
foreach (MetaModel::ListAttributeDefs($sClass) as $sAttCode => $oAttDef)
|
||||
{
|
||||
if ($oAttDef instanceof AttributeEmailAddress)
|
||||
{
|
||||
$sEmailAttCode = $sAttCode;
|
||||
// we've got one, exit the loop
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!isset($sEmailAttCode))
|
||||
{
|
||||
$this->m_aMailErrors[] = "wrong target for recipient '$sRecipAttCode'";
|
||||
return "The objects of the class '$sClass' do not have any email attribute";
|
||||
}
|
||||
|
||||
$oSet = new DBObjectSet($oSearch, array() /* order */, $aArgs);
|
||||
$aRecipients = array();
|
||||
while ($oObj = $oSet->Fetch())
|
||||
{
|
||||
$sAddress = trim($oObj->Get($sEmailAttCode));
|
||||
if (strlen($sAddress) > 0)
|
||||
{
|
||||
$aRecipients[] = $sAddress;
|
||||
$this->m_iRecipients++;
|
||||
}
|
||||
}
|
||||
return implode(', ', $aRecipients);
|
||||
}
|
||||
|
||||
|
||||
public function DoExecute($oTrigger, $aContextArgs)
|
||||
{
|
||||
if (MetaModel::IsLogEnabledNotification())
|
||||
{
|
||||
$oLog = new EventNotificationEmail();
|
||||
if ($this->IsBeingTested())
|
||||
{
|
||||
$oLog->Set('message', 'TEST - Notification sent ('.$this->Get('test_recipient').')');
|
||||
}
|
||||
else
|
||||
{
|
||||
$oLog->Set('message', 'Notification pending');
|
||||
}
|
||||
$oLog->Set('userinfo', UserRights::GetUser());
|
||||
$oLog->Set('trigger_id', $oTrigger->GetKey());
|
||||
$oLog->Set('action_id', $this->GetKey());
|
||||
$oLog->Set('object_id', $aContextArgs['this->object()']->GetKey());
|
||||
// Must be inserted now so that it gets a valid id that will make the link
|
||||
// between an eventual asynchronous task (queued) and the log
|
||||
$oLog->DBInsertNoReload();
|
||||
}
|
||||
else
|
||||
{
|
||||
$oLog = null;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
$sRes = $this->_DoExecute($oTrigger, $aContextArgs, $oLog);
|
||||
|
||||
if ($this->IsBeingTested())
|
||||
{
|
||||
$sPrefix = 'TEST ('.$this->Get('test_recipient').') - ';
|
||||
}
|
||||
else
|
||||
{
|
||||
$sPrefix = '';
|
||||
}
|
||||
if ($oLog)
|
||||
{
|
||||
$oLog->Set('message', $sPrefix . $sRes);
|
||||
}
|
||||
}
|
||||
catch (Exception $e)
|
||||
{
|
||||
if ($oLog)
|
||||
{
|
||||
$oLog->Set('message', 'Error: '.$e->getMessage());
|
||||
}
|
||||
}
|
||||
if ($oLog)
|
||||
{
|
||||
$oLog->DBUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
protected function _DoExecute($oTrigger, $aContextArgs, &$oLog)
|
||||
{
|
||||
$sPreviousUrlMaker = ApplicationContext::SetUrlMakerClass();
|
||||
try
|
||||
{
|
||||
$this->m_iRecipients = 0;
|
||||
$this->m_aMailErrors = array();
|
||||
$bRes = false; // until we do succeed in sending the email
|
||||
|
||||
// Determine recicipients
|
||||
//
|
||||
$sTo = $this->FindRecipients('to', $aContextArgs);
|
||||
$sCC = $this->FindRecipients('cc', $aContextArgs);
|
||||
$sBCC = $this->FindRecipients('bcc', $aContextArgs);
|
||||
|
||||
$sFrom = MetaModel::ApplyParams($this->Get('from'), $aContextArgs);
|
||||
$sReplyTo = MetaModel::ApplyParams($this->Get('reply_to'), $aContextArgs);
|
||||
|
||||
$sSubject = MetaModel::ApplyParams($this->Get('subject'), $aContextArgs);
|
||||
$sBody = MetaModel::ApplyParams($this->Get('body'), $aContextArgs);
|
||||
|
||||
$oObj = $aContextArgs['this->object()'];
|
||||
$sMessageId = sprintf('iTop_%s_%d_%f@%s.openitop.org', get_class($oObj), $oObj->GetKey(), microtime(true /* get as float*/), MetaModel::GetEnvironmentId());
|
||||
$sReference = '<'.$sMessageId.'>';
|
||||
}
|
||||
catch(Exception $e)
|
||||
{
|
||||
ApplicationContext::SetUrlMakerClass($sPreviousUrlMaker);
|
||||
throw $e;
|
||||
}
|
||||
ApplicationContext::SetUrlMakerClass($sPreviousUrlMaker);
|
||||
|
||||
if (!is_null($oLog))
|
||||
{
|
||||
// Note: we have to secure this because those values are calculated
|
||||
// inside the try statement, and we would like to keep track of as
|
||||
// many data as we could while some variables may still be undefined
|
||||
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($sSubject)) $oLog->Set('subject', $sSubject);
|
||||
if (isset($sBody)) $oLog->Set('body', $sBody);
|
||||
}
|
||||
$sStyles = file_get_contents(APPROOT.'css/email.css');
|
||||
$sStyles .= MetaModel::GetConfig()->Get('email_css');
|
||||
|
||||
$oEmail = new EMail();
|
||||
|
||||
if ($this->IsBeingTested())
|
||||
{
|
||||
$oEmail->SetSubject('TEST['.$sSubject.']');
|
||||
$sTestBody = $sBody;
|
||||
$sTestBody .= "<div style=\"border: dashed;\">\n";
|
||||
$sTestBody .= "<h1>Testing email notification ".$this->GetHyperlink()."</h1>\n";
|
||||
$sTestBody .= "<p>The email should be sent with the following properties\n";
|
||||
$sTestBody .= "<ul>\n";
|
||||
$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 .= "<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($this->Get('test_recipient'));
|
||||
$oEmail->SetReferences($sReference);
|
||||
$oEmail->SetMessageId($sMessageId);
|
||||
}
|
||||
else
|
||||
{
|
||||
$oEmail->SetSubject($sSubject);
|
||||
$oEmail->SetBody($sBody, 'text/html', $sStyles);
|
||||
$oEmail->SetRecipientTO($sTo);
|
||||
$oEmail->SetRecipientCC($sCC);
|
||||
$oEmail->SetRecipientBCC($sBCC);
|
||||
$oEmail->SetRecipientFrom($sFrom);
|
||||
$oEmail->SetRecipientReplyTo($sReplyTo);
|
||||
$oEmail->SetReferences($sReference);
|
||||
$oEmail->SetMessageId($sMessageId);
|
||||
}
|
||||
|
||||
if (isset($aContextArgs['attachments']))
|
||||
{
|
||||
$aAttachmentReport = array();
|
||||
foreach($aContextArgs['attachments'] as $oDocument)
|
||||
{
|
||||
$oEmail->AddAttachment($oDocument->GetData(), $oDocument->GetFileName(), $oDocument->GetMimeType());
|
||||
$aAttachmentReport[] = array($oDocument->GetFileName(), $oDocument->GetMimeType(), strlen($oDocument->GetData()));
|
||||
}
|
||||
$oLog->Set('attachments', $aAttachmentReport);
|
||||
}
|
||||
|
||||
if (empty($this->m_aMailErrors))
|
||||
{
|
||||
if ($this->m_iRecipients == 0)
|
||||
{
|
||||
return 'No recipient';
|
||||
}
|
||||
else
|
||||
{
|
||||
$iRes = $oEmail->Send($aErrors, false, $oLog); // allow asynchronous mode
|
||||
switch ($iRes)
|
||||
{
|
||||
case EMAIL_SEND_OK:
|
||||
return "Sent";
|
||||
|
||||
case EMAIL_SEND_PENDING:
|
||||
return "Pending";
|
||||
|
||||
case EMAIL_SEND_ERROR:
|
||||
return "Errors: ".implode(', ', $aErrors);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (is_array($this->m_aMailErrors) && count($this->m_aMailErrors) > 0)
|
||||
{
|
||||
$sError = implode(', ', $this->m_aMailErrors);
|
||||
}
|
||||
else
|
||||
{
|
||||
$sError = 'Unknown reason';
|
||||
}
|
||||
return 'Notification was not sent: '.$sError;
|
||||
}
|
||||
}
|
||||
}
|
||||
?>
|
||||
<?php
|
||||
// Copyright (C) 2010-2016 Combodo SARL
|
||||
//
|
||||
// This file is part of iTop.
|
||||
//
|
||||
// iTop is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// iTop is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with iTop. If not, see <http://www.gnu.org/licenses/>
|
||||
|
||||
|
||||
/**
|
||||
* Persistent classes (internal): user defined actions
|
||||
*
|
||||
* @copyright Copyright (C) 2010-2016 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
|
||||
require_once(APPROOT.'/core/asynctask.class.inc.php');
|
||||
require_once(APPROOT.'/core/email.class.inc.php');
|
||||
|
||||
/**
|
||||
* A user defined action, to customize the application
|
||||
*
|
||||
* @package iTopORM
|
||||
*/
|
||||
abstract class Action extends cmdbAbstractObject
|
||||
{
|
||||
public static function Init()
|
||||
{
|
||||
$aParams = array
|
||||
(
|
||||
"category" => "grant_by_profile,core/cmdb",
|
||||
"key_type" => "autoincrement",
|
||||
"name_attcode" => "name",
|
||||
"state_attcode" => "",
|
||||
"reconc_keys" => array('name'),
|
||||
"db_table" => "priv_action",
|
||||
"db_key_field" => "id",
|
||||
"db_finalclass_field" => "realclass",
|
||||
"display_template" => "",
|
||||
);
|
||||
MetaModel::Init_Params($aParams);
|
||||
//MetaModel::Init_InheritAttributes();
|
||||
MetaModel::Init_AddAttribute(new AttributeString("name", array("allowed_values"=>null, "sql"=>"name", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeString("description", array("allowed_values"=>null, "sql"=>"description", "default_value"=>null, "is_null_allowed"=>true, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeEnum("status", array("allowed_values"=>new ValueSetEnum(array('test'=>'Being tested' ,'enabled'=>'In production', 'disabled'=>'Inactive')), "sql"=>"status", "default_value"=>"test", "is_null_allowed"=>false, "depends_on"=>array())));
|
||||
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
|
||||
// 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
|
||||
}
|
||||
|
||||
abstract public function DoExecute($oTrigger, $aContextArgs);
|
||||
|
||||
public function IsActive()
|
||||
{
|
||||
switch($this->Get('status'))
|
||||
{
|
||||
case 'enabled':
|
||||
case 'test':
|
||||
return true;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public function IsBeingTested()
|
||||
{
|
||||
switch($this->Get('status'))
|
||||
{
|
||||
case 'test':
|
||||
return true;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A notification
|
||||
*
|
||||
* @package iTopORM
|
||||
*/
|
||||
abstract class ActionNotification extends Action
|
||||
{
|
||||
public static function Init()
|
||||
{
|
||||
$aParams = array
|
||||
(
|
||||
"category" => "grant_by_profile,core/cmdb",
|
||||
"key_type" => "autoincrement",
|
||||
"name_attcode" => "name",
|
||||
"state_attcode" => "",
|
||||
"reconc_keys" => array('name'),
|
||||
"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
|
||||
// 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
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An email notification
|
||||
*
|
||||
* @package iTopORM
|
||||
*/
|
||||
class ActionEmail extends ActionNotification
|
||||
{
|
||||
public static function Init()
|
||||
{
|
||||
$aParams = array
|
||||
(
|
||||
"category" => "grant_by_profile,core/cmdb,application",
|
||||
"key_type" => "autoincrement",
|
||||
"name_attcode" => "name",
|
||||
"state_attcode" => "",
|
||||
"reconc_keys" => array('name'),
|
||||
"db_table" => "priv_action_email",
|
||||
"db_key_field" => "id",
|
||||
"db_finalclass_field" => "",
|
||||
"display_template" => "",
|
||||
);
|
||||
MetaModel::Init_Params($aParams);
|
||||
MetaModel::Init_InheritAttributes();
|
||||
|
||||
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("reply_to", array("allowed_values"=>null, "sql"=>"reply_to", "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())));
|
||||
MetaModel::Init_AddAttribute(new AttributeTemplateString("subject", array("allowed_values"=>null, "sql"=>"subject", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeTemplateHTML("body", array("allowed_values"=>null, "sql"=>"body", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeEnum("importance", array("allowed_values"=>new ValueSetEnum('low,normal,high'), "sql"=>"importance", "default_value"=>'normal', "is_null_allowed"=>false, "depends_on"=>array())));
|
||||
|
||||
// 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
|
||||
// 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
|
||||
}
|
||||
|
||||
// count the recipients found
|
||||
protected $m_iRecipients;
|
||||
|
||||
// Errors management : not that simple because we need that function to be
|
||||
// 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
|
||||
protected function FindRecipients($sRecipAttCode, $aArgs)
|
||||
{
|
||||
$sOQL = $this->Get($sRecipAttCode);
|
||||
if (strlen($sOQL) == '') return '';
|
||||
|
||||
try
|
||||
{
|
||||
$oSearch = DBObjectSearch::FromOQL($sOQL);
|
||||
$oSearch->AllowAllData();
|
||||
}
|
||||
catch (OQLException $e)
|
||||
{
|
||||
$this->m_aMailErrors[] = "query syntax error for recipient '$sRecipAttCode'";
|
||||
return $e->getMessage();
|
||||
}
|
||||
|
||||
$sClass = $oSearch->GetClass();
|
||||
// Determine the email attribute (the first one will be our choice)
|
||||
foreach (MetaModel::ListAttributeDefs($sClass) as $sAttCode => $oAttDef)
|
||||
{
|
||||
if ($oAttDef instanceof AttributeEmailAddress)
|
||||
{
|
||||
$sEmailAttCode = $sAttCode;
|
||||
// we've got one, exit the loop
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!isset($sEmailAttCode))
|
||||
{
|
||||
$this->m_aMailErrors[] = "wrong target for recipient '$sRecipAttCode'";
|
||||
return "The objects of the class '$sClass' do not have any email attribute";
|
||||
}
|
||||
|
||||
$oSet = new DBObjectSet($oSearch, array() /* order */, $aArgs);
|
||||
$aRecipients = array();
|
||||
while ($oObj = $oSet->Fetch())
|
||||
{
|
||||
$sAddress = trim($oObj->Get($sEmailAttCode));
|
||||
if (strlen($sAddress) > 0)
|
||||
{
|
||||
$aRecipients[] = $sAddress;
|
||||
$this->m_iRecipients++;
|
||||
}
|
||||
}
|
||||
return implode(', ', $aRecipients);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \Trigger $oTrigger
|
||||
* @param array $aContextArgs
|
||||
*
|
||||
* @throws \CoreException
|
||||
* @throws \CoreUnexpectedValue
|
||||
* @throws \CoreWarning
|
||||
*/
|
||||
public function DoExecute($oTrigger, $aContextArgs)
|
||||
{
|
||||
if (MetaModel::IsLogEnabledNotification())
|
||||
{
|
||||
$oLog = new EventNotificationEmail();
|
||||
if ($this->IsBeingTested())
|
||||
{
|
||||
$oLog->Set('message', 'TEST - Notification sent ('.$this->Get('test_recipient').')');
|
||||
}
|
||||
else
|
||||
{
|
||||
$oLog->Set('message', 'Notification pending');
|
||||
}
|
||||
$oLog->Set('userinfo', UserRights::GetUser());
|
||||
$oLog->Set('trigger_id', $oTrigger->GetKey());
|
||||
$oLog->Set('action_id', $this->GetKey());
|
||||
$oLog->Set('object_id', $aContextArgs['this->object()']->GetKey());
|
||||
// Must be inserted now so that it gets a valid id that will make the link
|
||||
// between an eventual asynchronous task (queued) and the log
|
||||
$oLog->DBInsertNoReload();
|
||||
}
|
||||
else
|
||||
{
|
||||
$oLog = null;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
$sRes = $this->_DoExecute($oTrigger, $aContextArgs, $oLog);
|
||||
|
||||
if ($this->IsBeingTested())
|
||||
{
|
||||
$sPrefix = 'TEST ('.$this->Get('test_recipient').') - ';
|
||||
}
|
||||
else
|
||||
{
|
||||
$sPrefix = '';
|
||||
}
|
||||
|
||||
if ($oLog)
|
||||
{
|
||||
$oLog->Set('message', $sPrefix . $sRes);
|
||||
$oLog->DBUpdate();
|
||||
}
|
||||
|
||||
}
|
||||
catch (Exception $e)
|
||||
{
|
||||
if ($oLog)
|
||||
{
|
||||
$oLog->Set('message', 'Error: '.$e->getMessage());
|
||||
|
||||
try
|
||||
{
|
||||
$oLog->DBUpdate();
|
||||
}
|
||||
catch (Exception $eSecondTryUpdate)
|
||||
{
|
||||
IssueLog::Error("Failed to process email ".$oLog->GetKey()." - reason: ".$e->getMessage()."\nTrace:\n".$e->getTraceAsString());
|
||||
|
||||
$oLog->Set('message', 'Error: more details in the log for email "'.$oLog->GetKey().'"');
|
||||
$oLog->DBUpdate();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \Trigger $oTrigger
|
||||
* @param array $aContextArgs
|
||||
* @param \EventNotification $oLog
|
||||
*
|
||||
* @return string
|
||||
* @throws \CoreException
|
||||
*/
|
||||
protected function _DoExecute($oTrigger, $aContextArgs, &$oLog)
|
||||
{
|
||||
$sPreviousUrlMaker = ApplicationContext::SetUrlMakerClass();
|
||||
try
|
||||
{
|
||||
$this->m_iRecipients = 0;
|
||||
$this->m_aMailErrors = array();
|
||||
|
||||
// Determine recicipients
|
||||
//
|
||||
$sTo = $this->FindRecipients('to', $aContextArgs);
|
||||
$sCC = $this->FindRecipients('cc', $aContextArgs);
|
||||
$sBCC = $this->FindRecipients('bcc', $aContextArgs);
|
||||
|
||||
$sFrom = MetaModel::ApplyParams($this->Get('from'), $aContextArgs);
|
||||
$sReplyTo = MetaModel::ApplyParams($this->Get('reply_to'), $aContextArgs);
|
||||
|
||||
$sSubject = MetaModel::ApplyParams($this->Get('subject'), $aContextArgs);
|
||||
$sBody = MetaModel::ApplyParams($this->Get('body'), $aContextArgs);
|
||||
|
||||
$oObj = $aContextArgs['this->object()'];
|
||||
$sMessageId = sprintf('iTop_%s_%d_%f@%s.openitop.org', get_class($oObj), $oObj->GetKey(), microtime(true /* get as float*/),
|
||||
MetaModel::GetEnvironmentId());
|
||||
$sReference = '<'.$sMessageId.'>';
|
||||
}
|
||||
catch (Exception $e) {
|
||||
/** @noinspection PhpUnhandledExceptionInspection */
|
||||
throw $e;
|
||||
}
|
||||
finally {
|
||||
ApplicationContext::SetUrlMakerClass($sPreviousUrlMaker);
|
||||
}
|
||||
|
||||
if (!is_null($oLog)) {
|
||||
// Note: we have to secure this because those values are calculated
|
||||
// inside the try statement, and we would like to keep track of as
|
||||
// many data as we could while some variables may still be undefined
|
||||
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($sSubject)) {
|
||||
$oLog->Set('subject', $sSubject);
|
||||
}
|
||||
if (isset($sBody)) {
|
||||
$oLog->Set('body', $sBody);
|
||||
}
|
||||
}
|
||||
$sStyles = file_get_contents(APPROOT.'css/email.css');
|
||||
$sStyles .= MetaModel::GetConfig()->Get('email_css');
|
||||
|
||||
$oEmail = new EMail();
|
||||
|
||||
if ($this->IsBeingTested())
|
||||
{
|
||||
$oEmail->SetSubject('TEST['.$sSubject.']');
|
||||
$sTestBody = $sBody;
|
||||
$sTestBody .= "<div style=\"border: dashed;\">\n";
|
||||
$sTestBody .= "<h1>Testing email notification ".$this->GetHyperlink()."</h1>\n";
|
||||
$sTestBody .= "<p>The email should be sent with the following properties\n";
|
||||
$sTestBody .= "<ul>\n";
|
||||
$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 .= "<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->SetReferences($sReference);
|
||||
$oEmail->SetMessageId($sMessageId);
|
||||
}
|
||||
else
|
||||
{
|
||||
$oEmail->SetSubject($sSubject);
|
||||
$oEmail->SetBody($sBody, 'text/html', $sStyles);
|
||||
$oEmail->SetRecipientTO($sTo);
|
||||
$oEmail->SetRecipientCC($sCC);
|
||||
$oEmail->SetRecipientBCC($sBCC);
|
||||
$oEmail->SetRecipientFrom($sFrom);
|
||||
$oEmail->SetRecipientReplyTo($sReplyTo);
|
||||
$oEmail->SetReferences($sReference);
|
||||
$oEmail->SetMessageId($sMessageId);
|
||||
}
|
||||
|
||||
if (isset($aContextArgs['attachments']))
|
||||
{
|
||||
$aAttachmentReport = array();
|
||||
foreach($aContextArgs['attachments'] as $oDocument)
|
||||
{
|
||||
$oEmail->AddAttachment($oDocument->GetData(), $oDocument->GetFileName(), $oDocument->GetMimeType());
|
||||
$aAttachmentReport[] = array($oDocument->GetFileName(), $oDocument->GetMimeType(), strlen($oDocument->GetData()));
|
||||
}
|
||||
$oLog->Set('attachments', $aAttachmentReport);
|
||||
}
|
||||
|
||||
if (empty($this->m_aMailErrors))
|
||||
{
|
||||
if ($this->m_iRecipients == 0)
|
||||
{
|
||||
return 'No recipient';
|
||||
}
|
||||
else
|
||||
{
|
||||
$iRes = $oEmail->Send($aErrors, false, $oLog); // allow asynchronous mode
|
||||
switch ($iRes)
|
||||
{
|
||||
case EMAIL_SEND_OK:
|
||||
return "Sent";
|
||||
|
||||
case EMAIL_SEND_PENDING:
|
||||
return "Pending";
|
||||
|
||||
case EMAIL_SEND_ERROR:
|
||||
return "Errors: ".implode(', ', $aErrors);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (is_array($this->m_aMailErrors) && count($this->m_aMailErrors) > 0)
|
||||
{
|
||||
$sError = implode(', ', $this->m_aMailErrors);
|
||||
}
|
||||
else
|
||||
{
|
||||
$sError = 'Unknown reason';
|
||||
}
|
||||
return 'Notification was not sent: '.$sError;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<?php
|
||||
// Copyright (C) 2016 Combodo SARL
|
||||
// Copyright (C) 2016-2017 Combodo SARL
|
||||
//
|
||||
// This file is part of iTop.
|
||||
//
|
||||
@@ -67,3 +67,32 @@ if (!function_exists('apc_store') && function_exists('apcu_store'))
|
||||
return apcu_store($key, $var, $ttl);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns user cache info... beware of the format of the returned structure that may vary (See usages)
|
||||
* @return array
|
||||
*/
|
||||
function apc_cache_info_compat()
|
||||
{
|
||||
if (!function_exists('apc_cache_info')) return array();
|
||||
|
||||
$oFunction = new ReflectionFunction('apc_cache_info');
|
||||
if ($oFunction->getNumberOfParameters() != 2)
|
||||
{
|
||||
// Beware: APCu behaves slightly differently from APC !!
|
||||
// Worse: the compatibility layer integrated into APC differs from apcu-bc (testing the number of parameters is a must)
|
||||
// In CLI mode (PHP > 7) apc_cache_info returns null and outputs an error message.
|
||||
$aCacheUserData = @apc_cache_info();
|
||||
}
|
||||
else
|
||||
{
|
||||
$aCacheUserData = @apc_cache_info('user');
|
||||
}
|
||||
return $aCacheUserData;
|
||||
}
|
||||
|
||||
// Cache emulation
|
||||
if (!function_exists('apc_store'))
|
||||
{
|
||||
require_once(APPROOT.'core/apc-emulation.php');
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user