Compare commits
470 Commits
support/1.
...
support/1.
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b4a33b521a | ||
|
|
2bc01db8d9 | ||
|
|
d72503b411 | ||
|
|
71732f1722 | ||
|
|
489c4c05e0 | ||
|
|
f65e18400d | ||
|
|
9a53938473 | ||
|
|
e2bd0b82c7 | ||
|
|
48a067c286 | ||
|
|
bd933f3b14 | ||
|
|
cb9bc8f6d7 | ||
|
|
dd61cd1697 | ||
|
|
dd0c22708c | ||
|
|
b6f6e7a1ff | ||
|
|
db640fde59 | ||
|
|
aa9933a6b3 | ||
|
|
7a9d70d15b | ||
|
|
cd33335401 | ||
|
|
9755af9b7b | ||
|
|
5edf6ee43f | ||
|
|
00176a7f71 | ||
|
|
4f8e62b44a | ||
|
|
d1944c1af3 | ||
|
|
470397e2fd | ||
|
|
ea3fe45ce5 | ||
|
|
5b39fd372f | ||
|
|
6bca068bbe | ||
|
|
4c0150378c | ||
|
|
be4d017f4c | ||
|
|
ffd816038d | ||
|
|
9818214ec8 | ||
|
|
f115e0b120 | ||
|
|
10b81f0569 | ||
|
|
3d5c05f6d4 | ||
|
|
46c71fcefc | ||
|
|
198898ada4 | ||
|
|
42f355a592 | ||
|
|
ab1fc4b1b5 | ||
|
|
2273e2dbaa | ||
|
|
68412f53a4 | ||
|
|
7c7b657d71 | ||
|
|
42dc240aac | ||
|
|
fac1084b1d | ||
|
|
e623467782 | ||
|
|
32208fcbfc | ||
|
|
dcbff406f7 | ||
|
|
017dfe641c | ||
|
|
fad258cd2d | ||
|
|
3470ce18e8 | ||
|
|
af710c549f | ||
|
|
ee938d674d | ||
|
|
423de35cf5 | ||
|
|
6a7af8ad73 | ||
|
|
89732d6e52 | ||
|
|
cddeab2c90 | ||
|
|
d9d84703ae | ||
|
|
c3de9ecf10 | ||
|
|
cf37a50b3d | ||
|
|
4db30648c2 | ||
|
|
8de84d5ec7 | ||
|
|
459a271d11 | ||
|
|
9da00b83b2 | ||
|
|
0c8ef6a690 | ||
|
|
cdefd7a4c6 | ||
|
|
4f057ac29f | ||
|
|
ab16588f87 | ||
|
|
07d8da9d99 | ||
|
|
c539f19ce9 | ||
|
|
3635e60850 | ||
|
|
b278b84f46 | ||
|
|
04647970a8 | ||
|
|
fe58f6bd19 | ||
|
|
0d6cd529a1 | ||
|
|
2a155fe8ee | ||
|
|
3f381a3530 | ||
|
|
7fadb5e08b | ||
|
|
5d4476f48b | ||
|
|
2fbb37cc2f | ||
|
|
6801ecb266 | ||
|
|
fa821d3a9b | ||
|
|
00f9deeaa5 | ||
|
|
58cfc1d51b | ||
|
|
af8b3b972d | ||
|
|
07671f40fd | ||
|
|
3da5c65fe4 | ||
|
|
489be44b90 | ||
|
|
912088d017 | ||
|
|
06620133b6 | ||
|
|
95d7a24630 | ||
|
|
cb0e1d8ef3 | ||
|
|
d321ebc8e4 | ||
|
|
c149ec8e2c | ||
|
|
281adfb043 | ||
|
|
4244029087 | ||
|
|
78e173d5fb | ||
|
|
6b8abce03a | ||
|
|
33a7005069 | ||
|
|
006a6037d1 | ||
|
|
e2f8be1745 | ||
|
|
ebae45f6a5 | ||
|
|
0685835d49 | ||
|
|
1b1e88f9a4 | ||
|
|
b90f443e75 | ||
|
|
4da64a64b1 | ||
|
|
6673e171dc | ||
|
|
afee7297cc | ||
|
|
3cc8b5b88a | ||
|
|
b2e6981b24 | ||
|
|
c0a79fa573 | ||
|
|
02ad6d19fe | ||
|
|
d16308ab62 | ||
|
|
4598959bc2 | ||
|
|
65a3755f81 | ||
|
|
dc46c65499 | ||
|
|
9d691c8e56 | ||
|
|
99f897bff7 | ||
|
|
8d83447222 | ||
|
|
dcc8ad08a4 | ||
|
|
c1b0b73b51 | ||
|
|
81173decca | ||
|
|
9aca062bf5 | ||
|
|
09aba95d0a | ||
|
|
1683ca2dd6 | ||
|
|
9e732d6045 | ||
|
|
69df343bd2 | ||
|
|
eb8f49ebfe | ||
|
|
398e294604 | ||
|
|
d04c6bccd5 | ||
|
|
f00c7c6bc2 | ||
|
|
d30e8c359f | ||
|
|
2bd4a61c00 | ||
|
|
ba3080594c | ||
|
|
e35c8323df | ||
|
|
e4e814281d | ||
|
|
a3a94cccbb | ||
|
|
635cb424a2 | ||
|
|
e8c8e4a0d7 | ||
|
|
5b3350f6d5 | ||
|
|
b454b24e0f | ||
|
|
e95aa6cc69 | ||
|
|
c58fd17fc9 | ||
|
|
099afb5451 | ||
|
|
ec226ce76d | ||
|
|
5080bd58d5 | ||
|
|
efdec7a343 | ||
|
|
5ec37fd26a | ||
|
|
2352c05d36 | ||
|
|
8ae92cb50e | ||
|
|
f82a4ada23 | ||
|
|
e5ce12ed0a | ||
|
|
428f1a26cc | ||
|
|
9976999a88 | ||
|
|
da2b8ab4c0 | ||
|
|
0de75db474 | ||
|
|
23634964a5 | ||
|
|
b014596172 | ||
|
|
b46ed4764d | ||
|
|
2b1aecda53 | ||
|
|
619252db99 | ||
|
|
19318973ca | ||
|
|
ca4dbd833c | ||
|
|
f62a3b22a3 | ||
|
|
cac76a7e08 | ||
|
|
88416bca5d | ||
|
|
abd645ca98 | ||
|
|
7301cb9369 | ||
|
|
559de3d38f | ||
|
|
552ffd79b1 | ||
|
|
aae8ca7b8b | ||
|
|
13c636cab6 | ||
|
|
cc40fc5d91 | ||
|
|
bddfdb4a28 | ||
|
|
6bc639c6ce | ||
|
|
9b8ae03413 | ||
|
|
17f00198d3 | ||
|
|
5041ec2e0c | ||
|
|
ee4f7e5b6a | ||
|
|
cbb40b85dc | ||
|
|
9aca772209 | ||
|
|
c4db9cd84e | ||
|
|
205e80f8a5 | ||
|
|
06e9bd0c25 | ||
|
|
1c812f8b34 | ||
|
|
f3c5759721 | ||
|
|
69368a39cb | ||
|
|
ab5849b3cd | ||
|
|
1ab796bd40 | ||
|
|
c1221054b4 | ||
|
|
3bd681bc9d | ||
|
|
b33989ec62 | ||
|
|
b3121eebae | ||
|
|
7d8971139b | ||
|
|
04f20860dc | ||
|
|
8f21b9dabb | ||
|
|
eb89610465 | ||
|
|
13f4e90ee6 | ||
|
|
29f1dd5a69 | ||
|
|
a7e937ec58 | ||
|
|
bc2a8a8c4a | ||
|
|
c9b0a2b561 | ||
|
|
5fcea9bf69 | ||
|
|
3b42c86f46 | ||
|
|
038fe30fbe | ||
|
|
aa95e51e00 | ||
|
|
6a78c7dcc2 | ||
|
|
17aa1d1fc0 | ||
|
|
24244f1bac | ||
|
|
f7be35848c | ||
|
|
1aa7ff14fe | ||
|
|
c33a508376 | ||
|
|
37ec8b12f3 | ||
|
|
dde3efc0c7 | ||
|
|
54f3dec7a9 | ||
|
|
6be497ee7d | ||
|
|
5d9d44dc5e | ||
|
|
d547394ba2 | ||
|
|
ace0a3e278 | ||
|
|
dd9cb27971 | ||
|
|
a3dc8ab3d7 | ||
|
|
496bf386be | ||
|
|
c337616fea | ||
|
|
186ba76092 | ||
|
|
20a06c9212 | ||
|
|
e515dfb434 | ||
|
|
2ee85dd407 | ||
|
|
6df6e4a9cc | ||
|
|
c74c955973 | ||
|
|
a3a4fd0a75 | ||
|
|
c7f3ac0361 | ||
|
|
21002574ce | ||
|
|
64cae5b58b | ||
|
|
cc1105ff60 | ||
|
|
71655f0632 | ||
|
|
6e4e5be35d | ||
|
|
872a424a78 | ||
|
|
612c355e03 | ||
|
|
ffa9b21364 | ||
|
|
180311fd0a | ||
|
|
16b7714139 | ||
|
|
c6865cf63d | ||
|
|
905d9b5931 | ||
|
|
0850370275 | ||
|
|
38591f444e | ||
|
|
ae36aa1f74 | ||
|
|
264af56591 | ||
|
|
0a2c9d0e37 | ||
|
|
9d9d53c967 | ||
|
|
54315f41e4 | ||
|
|
a04e7ea375 | ||
|
|
795296e6e3 | ||
|
|
98ac85c098 | ||
|
|
e53c07393c | ||
|
|
48d66447b7 | ||
|
|
54b4f67ed6 | ||
|
|
9836797da9 | ||
|
|
931a260435 | ||
|
|
2a6d36b9cd | ||
|
|
9420c14c13 | ||
|
|
272807ba56 | ||
|
|
d05ea1863c | ||
|
|
6c8e021727 | ||
|
|
266135b1b9 | ||
|
|
02fc610a18 | ||
|
|
e2aa3cc69f | ||
|
|
de516c0ce4 | ||
|
|
92ac1fe2ca | ||
|
|
cc7844ea10 | ||
|
|
22bdc02b1b | ||
|
|
e8586515e3 | ||
|
|
071a30d928 | ||
|
|
488f1c47bf | ||
|
|
c15976f148 | ||
|
|
6f8e2e60ce | ||
|
|
b7b8da0848 | ||
|
|
2f1803b3b6 | ||
|
|
58e61c9d6b | ||
|
|
ddd98b9335 | ||
|
|
278b84ee38 | ||
|
|
c0764bce74 | ||
|
|
7cf0e2f747 | ||
|
|
c7e8627679 | ||
|
|
1c7d5b8fd2 | ||
|
|
18217e4adb | ||
|
|
1357e7e225 | ||
|
|
a941c2d14e | ||
|
|
cb55a75bcf | ||
|
|
1e20253229 | ||
|
|
53a48dc8e0 | ||
|
|
2ad9d69396 | ||
|
|
74baca3a7b | ||
|
|
2bd8700c90 | ||
|
|
51bd6cdf97 | ||
|
|
b02021a4ff | ||
|
|
96f3350029 | ||
|
|
e2e4c53b0d | ||
|
|
9c6605f7e7 | ||
|
|
f481652666 | ||
|
|
212389f43e | ||
|
|
f68680ada1 | ||
|
|
6859326646 | ||
|
|
a129c9814f | ||
|
|
05ee0caec2 | ||
|
|
6fff9d6a20 | ||
|
|
d2955557bf | ||
|
|
aa00cd9ae7 | ||
|
|
aa9d9ed578 | ||
|
|
9bd6fa61c5 | ||
|
|
f16997fb2d | ||
|
|
f4c1cf0818 | ||
|
|
01dd63f623 | ||
|
|
3393808c7a | ||
|
|
772c892b15 | ||
|
|
435d943f47 | ||
|
|
eab1060f8e | ||
|
|
cb8774370f | ||
|
|
23b1d15b64 | ||
|
|
61727aca02 | ||
|
|
8cfebdf723 | ||
|
|
506702c50b | ||
|
|
b9de1df6a8 | ||
|
|
a7175007be | ||
|
|
5d8acbb41a | ||
|
|
3ccbeac996 | ||
|
|
1643ba8e9c | ||
|
|
768dbd8946 | ||
|
|
c2d02a2394 | ||
|
|
b26f2738f6 | ||
|
|
781ec7e33a | ||
|
|
d09db3a920 | ||
|
|
998a8692cb | ||
|
|
b83ac447e8 | ||
|
|
6688f1811e | ||
|
|
ec26750b58 | ||
|
|
0f0abc0501 | ||
|
|
9ad6f2c994 | ||
|
|
abab47558b | ||
|
|
f3147be8f6 | ||
|
|
af185b79c8 | ||
|
|
3fc686e403 | ||
|
|
f5ea073c2b | ||
|
|
aa6d7578d1 | ||
|
|
05338caa23 | ||
|
|
a6ac78d7c1 | ||
|
|
9bcf78bfd6 | ||
|
|
9c97df5186 | ||
|
|
c2a8fd4e09 | ||
|
|
c8b6ec08e7 | ||
|
|
4293230416 | ||
|
|
bfddec242b | ||
|
|
ee3652acad | ||
|
|
5baa213e6a | ||
|
|
ca8ea8dd02 | ||
|
|
308d2626a9 | ||
|
|
8cab8dd7b7 | ||
|
|
0a5e37c592 | ||
|
|
72326435ce | ||
|
|
ca9f17d6e1 | ||
|
|
ff89c4d424 | ||
|
|
fa3b7ce545 | ||
|
|
c85feb7cea | ||
|
|
d50f812694 | ||
|
|
c7e27a836a | ||
|
|
c8a1380bef | ||
|
|
7732c9bc6a | ||
|
|
82c57972c6 | ||
|
|
0cc0c820a5 | ||
|
|
9150a569a7 | ||
|
|
3c76b90a48 | ||
|
|
5f2a5d9cfa | ||
|
|
4e40702809 | ||
|
|
a2b8813628 | ||
|
|
751ab5a4b4 | ||
|
|
b6bcade4c0 | ||
|
|
d6be6ca92c | ||
|
|
9024e0b2db | ||
|
|
ecca1aa070 | ||
|
|
3fde682653 | ||
|
|
aee8a98d84 | ||
|
|
3ab670e8c2 | ||
|
|
1fc7ce3b81 | ||
|
|
e8c44951a1 | ||
|
|
c11ca679d4 | ||
|
|
46781c349f | ||
|
|
189b802452 | ||
|
|
6b7687c80b | ||
|
|
906abd5fe6 | ||
|
|
0c539aada9 | ||
|
|
a3611f7f63 | ||
|
|
d62d6e14c8 | ||
|
|
4cd4d91225 | ||
|
|
5257287421 | ||
|
|
7e60a9fce7 | ||
|
|
b80cc36fb5 | ||
|
|
0e75824247 | ||
|
|
7470c8e72e | ||
|
|
a04f0ee816 | ||
|
|
d37244e6e2 | ||
|
|
82c4f43c4f | ||
|
|
1c2c244273 | ||
|
|
a991a84a8e | ||
|
|
532912984d | ||
|
|
265ef1e1ce | ||
|
|
70ad369ad6 | ||
|
|
723685b4cb | ||
|
|
061711afc8 | ||
|
|
8b6a8f02a4 | ||
|
|
893ec0f097 | ||
|
|
7c9d4c76a9 | ||
|
|
52fb63c0ee | ||
|
|
8a547bf104 | ||
|
|
0019ab216a | ||
|
|
8d52cd3a58 | ||
|
|
c7fbe56423 | ||
|
|
5ff5ea71de | ||
|
|
6297526da6 | ||
|
|
56ac89f6a6 | ||
|
|
aa46ab1a67 | ||
|
|
645b02b2d1 | ||
|
|
b2c5f183ec | ||
|
|
c6b60731d8 | ||
|
|
fd2f40f070 | ||
|
|
9fef41404f | ||
|
|
017aec3ae8 | ||
|
|
2ae4aca687 | ||
|
|
692fd91801 | ||
|
|
12ec9c3ba1 | ||
|
|
ac5e40f4ed | ||
|
|
f44afb8ee6 | ||
|
|
9e01277e49 | ||
|
|
73dc5eb922 | ||
|
|
a5091d9af0 | ||
|
|
a573d3cfa0 | ||
|
|
c4b7497770 | ||
|
|
1964658584 | ||
|
|
077b7be2a4 | ||
|
|
22c6df1a7a | ||
|
|
54d5497f0a | ||
|
|
9d2a8d0a67 | ||
|
|
20024729ec | ||
|
|
43315f50ea | ||
|
|
46edbbbd2b | ||
|
|
dc3713f0ea | ||
|
|
01a4a04364 | ||
|
|
7384191fb6 | ||
|
|
b8c930016f | ||
|
|
5d37201391 | ||
|
|
2c8963784c | ||
|
|
c42fa13b92 | ||
|
|
c02d62044c | ||
|
|
7bcb4ed3b2 | ||
|
|
834e9c48e1 | ||
|
|
ddfc84db6a | ||
|
|
b4a7d0b86c | ||
|
|
02cafd0e0b | ||
|
|
f5891a531e | ||
|
|
4681b03646 | ||
|
|
733953ac99 | ||
|
|
4837984ac3 | ||
|
|
4efd93defe | ||
|
|
35f7d143b8 | ||
|
|
d48fd1a12e | ||
|
|
a0900cd732 | ||
|
|
64b4922499 | ||
|
|
4574126428 | ||
|
|
9704dd8e35 | ||
|
|
f8d794bc93 | ||
|
|
5c7c7b98ee | ||
|
|
3826c1f886 | ||
|
|
58844b04ef | ||
|
|
178f7f3426 |
@@ -265,7 +265,7 @@ class URP_Profiles extends UserRightsBaseClassGUI
|
||||
|
||||
function DoShowGrantSumary($oPage)
|
||||
{
|
||||
if ($this->GetName() == "Administrator")
|
||||
if ($this->GetRawName() == "Administrator")
|
||||
{
|
||||
// Looks dirty, but ok that's THE ONE
|
||||
$oPage->p(Dict::S('UI:UserManagement:AdminProfile+'));
|
||||
@@ -538,41 +538,39 @@ class UserRightsProfile extends UserRightsAddOnAPI
|
||||
$oChange->Set("userinfo", "Initialization");
|
||||
$iChangeId = $oChange->DBInsert();
|
||||
|
||||
// Support drastic data model changes: no organization class !
|
||||
if (MetaModel::IsValidClass('Organization'))
|
||||
$iContactId = 0;
|
||||
// Support drastic data model changes: no organization class (or not writable)!
|
||||
if (MetaModel::IsValidClass('Organization') && !MetaModel::IsAbstract('Organization'))
|
||||
{
|
||||
$oOrg = new Organization();
|
||||
$oOrg->Set('name', 'My Company/Department');
|
||||
$oOrg->Set('code', 'SOMECODE');
|
||||
$iOrgId = $oOrg->DBInsertTrackedNoReload($oChange, true /* skip security */);
|
||||
}
|
||||
else
|
||||
{
|
||||
$iOrgId = 0;
|
||||
|
||||
// Support drastic data model changes: no Person class (or not writable)!
|
||||
if (MetaModel::IsValidClass('Person') && !MetaModel::IsAbstract('Person'))
|
||||
{
|
||||
$oContact = new Person();
|
||||
$oContact->Set('name', 'My last name');
|
||||
$oContact->Set('first_name', 'My first name');
|
||||
if (MetaModel::IsValidAttCode('Person', 'org_id'))
|
||||
{
|
||||
$oContact->Set('org_id', $iOrgId);
|
||||
}
|
||||
if (MetaModel::IsValidAttCode('Person', 'phone'))
|
||||
{
|
||||
$oContact->Set('phone', '+00 000 000 000');
|
||||
}
|
||||
$oContact->Set('email', 'my.email@foo.org');
|
||||
$iContactId = $oContact->DBInsertTrackedNoReload($oChange, true /* skip security */);
|
||||
}
|
||||
}
|
||||
|
||||
// Support drastic data model changes: no Person class !
|
||||
if (MetaModel::IsValidClass('Person'))
|
||||
{
|
||||
$oContact = new Person();
|
||||
$oContact->Set('name', 'My last name');
|
||||
$oContact->Set('first_name', 'My first name');
|
||||
if (MetaModel::IsValidAttCode('Person', 'org_id'))
|
||||
{
|
||||
$oContact->Set('org_id', $iOrgId);
|
||||
}
|
||||
$oContact->Set('email', 'my.email@foo.org');
|
||||
$iContactId = $oContact->DBInsertTrackedNoReload($oChange, true /* skip security */);
|
||||
}
|
||||
else
|
||||
{
|
||||
$iContactId = 0;
|
||||
}
|
||||
|
||||
$oUser = new UserLocal();
|
||||
$oUser->Set('login', $sAdminUser);
|
||||
$oUser->Set('password', $sAdminPwd);
|
||||
if (MetaModel::IsValidAttCode('UserLocal', 'contactid'))
|
||||
if (MetaModel::IsValidAttCode('UserLocal', 'contactid') && ($iContactId != 0))
|
||||
{
|
||||
$oUser->Set('contactid', $iContactId);
|
||||
}
|
||||
@@ -599,12 +597,12 @@ class UserRightsProfile extends UserRightsAddOnAPI
|
||||
}
|
||||
|
||||
|
||||
protected $m_aAdmins; // id of users being linked to the well-known admin profile
|
||||
protected $m_aPortalUsers; // id of users being linked to the well-known admin profile
|
||||
protected $m_aAdmins = array(); // id -> bool, true if the user has the well-known admin profile
|
||||
protected $m_aPortalUsers = array(); // id -> bool, true if the user has the well-known portal user profile
|
||||
|
||||
protected $m_aProfiles; // id -> object
|
||||
protected $m_aUserProfiles; // userid,profileid -> object
|
||||
protected $m_aUserOrgs; // userid,orgid -> object
|
||||
protected $m_aUserProfiles = array(); // userid,profileid -> object
|
||||
protected $m_aUserOrgs = array(); // userid -> array of orgid
|
||||
|
||||
// Those arrays could be completed on demand (inheriting parent permissions)
|
||||
protected $m_aClassActionGrants = null; // profile, class, action -> actiongrantid (or false if NO, or null/missing if undefined)
|
||||
@@ -613,15 +611,64 @@ class UserRightsProfile extends UserRightsAddOnAPI
|
||||
// Built on demand, could be optimized if necessary (doing a query for each attribute that needs to be read)
|
||||
protected $m_aObjectActionGrants = array();
|
||||
|
||||
/**
|
||||
* Read and cache organizations allowed to the given user
|
||||
*
|
||||
* @param oUser
|
||||
* @param sClass -not used here but can be used in overloads
|
||||
*/
|
||||
protected function GetUserOrgs($oUser, $sClass)
|
||||
{
|
||||
$iUser = $oUser->GetKey();
|
||||
if (!array_key_exists($iUser, $this->m_aUserOrgs))
|
||||
{
|
||||
$oSearch = new DBObjectSearch('URP_UserOrg');
|
||||
$oSearch->AllowAllData();
|
||||
$oCondition = new BinaryExpression(new FieldExpression('userid'), '=', new VariableExpression('userid'));
|
||||
$oSearch->AddConditionExpression($oCondition);
|
||||
|
||||
$this->m_aUserOrgs[$iUser] = array();
|
||||
$oUserOrgSet = new DBObjectSet($oSearch, array(), array('userid' => $iUser));
|
||||
while ($oUserOrg = $oUserOrgSet->Fetch())
|
||||
{
|
||||
$this->m_aUserOrgs[$iUser][] = $oUserOrg->Get('allowed_org_id');
|
||||
}
|
||||
}
|
||||
return $this->m_aUserOrgs[$iUser];
|
||||
}
|
||||
|
||||
/**
|
||||
* Read and cache profiles of the given user
|
||||
*/
|
||||
protected function GetUserProfiles($iUser)
|
||||
{
|
||||
if (!array_key_exists($iUser, $this->m_aUserProfiles))
|
||||
{
|
||||
$oSearch = new DBObjectSearch('URP_UserProfile');
|
||||
$oSearch->AllowAllData();
|
||||
$oCondition = new BinaryExpression(new FieldExpression('userid'), '=', new VariableExpression('userid'));
|
||||
$oSearch->AddConditionExpression($oCondition);
|
||||
|
||||
$this->m_aUserProfiles[$iUser] = array();
|
||||
$oUserProfileSet = new DBObjectSet($oSearch, array(), array('userid' => $iUser));
|
||||
while ($oUserProfile = $oUserProfileSet->Fetch())
|
||||
{
|
||||
$this->m_aUserProfiles[$iUser][$oUserProfile->Get('profileid')] = $oUserProfile;
|
||||
}
|
||||
}
|
||||
return $this->m_aUserProfiles[$iUser];
|
||||
|
||||
}
|
||||
|
||||
public function ResetCache()
|
||||
{
|
||||
// Loaded by Load cache
|
||||
$this->m_aProfiles = null;
|
||||
$this->m_aUserProfiles = null;
|
||||
$this->m_aUserOrgs = null;
|
||||
$this->m_aUserProfiles = array();
|
||||
$this->m_aUserOrgs = array();
|
||||
|
||||
$this->m_aAdmins = null;
|
||||
$this->m_aPortalUsers = null;
|
||||
$this->m_aAdmins = array();
|
||||
$this->m_aPortalUsers = array();
|
||||
|
||||
// Loaded on demand (time consuming as compared to the others)
|
||||
$this->m_aClassActionGrants = null;
|
||||
@@ -663,30 +710,6 @@ class UserRightsProfile extends UserRightsAddOnAPI
|
||||
$this->m_aProfiles[$oProfile->GetKey()] = $oProfile;
|
||||
}
|
||||
|
||||
$oUserProfileSet = new DBObjectSet(DBObjectSearch::FromOQL_AllData("SELECT URP_UserProfile"));
|
||||
$this->m_aUserProfiles = array();
|
||||
$this->m_aAdmins = array();
|
||||
$this->m_aPortalUsers = array();
|
||||
while ($oUserProfile = $oUserProfileSet->Fetch())
|
||||
{
|
||||
$this->m_aUserProfiles[$oUserProfile->Get('userid')][$oUserProfile->Get('profileid')] = $oUserProfile;
|
||||
if ($oUserProfile->Get('profile') == ADMIN_PROFILE_NAME)
|
||||
{
|
||||
$this->m_aAdmins[] = $oUserProfile->Get('userid');
|
||||
}
|
||||
elseif ($oUserProfile->Get('profile') == PORTAL_PROFILE_NAME)
|
||||
{
|
||||
$this->m_aPortalUsers[] = $oUserProfile->Get('userid');
|
||||
}
|
||||
}
|
||||
|
||||
$oUserOrgSet = new DBObjectSet(DBObjectSearch::FromOQL_AllData("SELECT URP_UserOrg"));
|
||||
$this->m_aUserOrgs = array();
|
||||
while ($oUserOrg = $oUserOrgSet->Fetch())
|
||||
{
|
||||
$this->m_aUserOrgs[$oUserOrg->Get('userid')][$oUserOrg->Get('allowed_org_id')] = $oUserOrg;
|
||||
}
|
||||
|
||||
$this->m_aClassStimulusGrants = array();
|
||||
$oStimGrantSet = new DBObjectSet(DBObjectSearch::FromOQL_AllData("SELECT URP_StimulusGrant"));
|
||||
$this->m_aStimGrants = array();
|
||||
@@ -713,32 +736,45 @@ exit;
|
||||
|
||||
public function IsAdministrator($oUser)
|
||||
{
|
||||
$this->LoadCache();
|
||||
|
||||
if (in_array($oUser->GetKey(), $this->m_aAdmins))
|
||||
//$this->LoadCache();
|
||||
$iUser = $oUser->GetKey();
|
||||
if (!array_key_exists($iUser, $this->m_aAdmins))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
$bIsAdmin = false;
|
||||
foreach($this->GetUserProfiles($iUser) as $oUserProfile)
|
||||
{
|
||||
if ($oUserProfile->Get('profile') == ADMIN_PROFILE_NAME)
|
||||
{
|
||||
$bIsAdmin = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
$this->m_aAdmins[$iUser] = $bIsAdmin;
|
||||
}
|
||||
return $this->m_aAdmins[$iUser];
|
||||
}
|
||||
|
||||
public function IsPortalUser($oUser)
|
||||
{
|
||||
$this->LoadCache();
|
||||
|
||||
if (in_array($oUser->GetKey(), $this->m_aPortalUsers))
|
||||
//$this->LoadCache();
|
||||
$iUser = $oUser->GetKey();
|
||||
if (!array_key_exists($iUser, $this->m_aPortalUsers))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
$bIsPortalUser = false;
|
||||
foreach($this->GetUserProfiles($iUser) as $oUserProfile)
|
||||
{
|
||||
if ($oUserProfile->Get('profile') == PORTAL_PROFILE_NAME)
|
||||
{
|
||||
$bIsPortalUser = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
$this->m_aPortalUsers[$iUser] = $bIsPortalUser;
|
||||
}
|
||||
return $this->m_aPortalUsers[$iUser];
|
||||
}
|
||||
|
||||
|
||||
public function GetSelectFilter($oUser, $sClass)
|
||||
{
|
||||
$this->LoadCache();
|
||||
@@ -751,17 +787,24 @@ exit;
|
||||
|
||||
// Determine how to position the objects of this class
|
||||
//
|
||||
if ($sClass == 'Organization')
|
||||
$aCallSpec = array($sClass, 'MapContextParam');
|
||||
if (($sClass == 'Organization') || is_subclass_of($sClass, 'Organization'))
|
||||
{
|
||||
$sAttCode = 'id';
|
||||
}
|
||||
elseif (is_callable("$sClass::MapContextParam"))
|
||||
elseif (is_callable($aCallSpec))
|
||||
{
|
||||
$sAttCode = eval("return $sClass::MapContextParam('org_id');"); // Returns null when there is no mapping for this parameter
|
||||
$sAttCode = call_user_func($aCallSpec, 'org_id'); // Returns null when there is no mapping for this parameter
|
||||
|
||||
if ($sAttCode == null)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
if (!MetaModel::IsValidAttCode($sClass, $sAttCode))
|
||||
{
|
||||
// Skip silently. The data model checker will tell you something about this...
|
||||
return true;
|
||||
}
|
||||
}
|
||||
elseif(MetaModel::IsValidAttCode($sClass, 'org_id'))
|
||||
{
|
||||
@@ -773,23 +816,61 @@ exit;
|
||||
// All of them are visible
|
||||
return true;
|
||||
}
|
||||
$oExpression = new FieldExpression($sAttCode, $sClass);
|
||||
|
||||
// Position the user
|
||||
//
|
||||
@$aUserOrgs = $this->m_aUserOrgs[$oUser->GetKey()];
|
||||
if (!isset($aUserOrgs) || count($aUserOrgs) == 0)
|
||||
$aUserOrgs = $this->GetUserOrgs($oUser, $sClass);
|
||||
if (count($aUserOrgs) == 0)
|
||||
{
|
||||
// No position means 'Everywhere'
|
||||
// No org means 'any org'
|
||||
return true;
|
||||
}
|
||||
|
||||
$aIds = array_keys($aUserOrgs);
|
||||
$oListExpr = ListExpression::FromScalars($aIds);
|
||||
$oCondition = new BinaryExpression($oExpression, 'IN', $oListExpr);
|
||||
|
||||
$oExpression = new FieldExpression($sAttCode, $sClass);
|
||||
$oFilter = new DBObjectSearch($sClass);
|
||||
$oFilter->AddConditionExpression($oCondition);
|
||||
$oListExpr = ListExpression::FromScalars($aUserOrgs);
|
||||
|
||||
// Check if the condition points to a hierarchical key
|
||||
$bConditionAdded = false;
|
||||
|
||||
if ($sAttCode == 'id')
|
||||
{
|
||||
// Filtering on the objects themselves
|
||||
$sHierarchicalKeyCode = MetaModel::IsHierarchicalClass($sClass);
|
||||
|
||||
if ($sHierarchicalKeyCode !== false)
|
||||
{
|
||||
$oRootFilter = new DBObjectSearch($sClass);
|
||||
$oCondition = new BinaryExpression($oExpression, 'IN', $oListExpr);
|
||||
$oRootFilter->AddConditionExpression($oCondition);
|
||||
$oFilter->AddCondition_PointingTo($oRootFilter, $sHierarchicalKeyCode, TREE_OPERATOR_BELOW); // Use the 'below' operator by default
|
||||
$bConditionAdded = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$oAttDef = MetaModel::GetAttributeDef($sClass, $sAttCode);
|
||||
if ($oAttDef->IsExternalKey())
|
||||
{
|
||||
$sHierarchicalKeyCode = MetaModel::IsHierarchicalClass($oAttDef->GetTargetClass());
|
||||
|
||||
if ($sHierarchicalKeyCode !== false)
|
||||
{
|
||||
$oRootFilter = new DBObjectSearch($oAttDef->GetTargetClass());
|
||||
$oExpression = new FieldExpression('id', $oAttDef->GetTargetClass());
|
||||
$oCondition = new BinaryExpression($oExpression, 'IN', $oListExpr);
|
||||
$oRootFilter->AddConditionExpression($oCondition);
|
||||
$oHKFilter = new DBObjectSearch($oAttDef->GetTargetClass());
|
||||
$oHKFilter->AddCondition_PointingTo($oRootFilter, $sHierarchicalKeyCode, TREE_OPERATOR_BELOW); // Use the 'below' operator by default
|
||||
$oFilter->AddCondition_PointingTo($oHKFilter, $sAttCode);
|
||||
$bConditionAdded = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!$bConditionAdded)
|
||||
{
|
||||
$oCondition = new BinaryExpression($oExpression, 'IN', $oListExpr);
|
||||
$oFilter->AddConditionExpression($oCondition);
|
||||
}
|
||||
return $oFilter;
|
||||
}
|
||||
|
||||
@@ -835,33 +916,30 @@ exit;
|
||||
|
||||
$iPermission = UR_ALLOWED_NO;
|
||||
$aAttributes = array();
|
||||
if (isset($this->m_aUserProfiles[$iUser]))
|
||||
foreach($this->GetUserProfiles($iUser) as $iProfile => $oProfile)
|
||||
{
|
||||
foreach($this->m_aUserProfiles[$iUser] as $iProfile => $oProfile)
|
||||
$iGrant = $this->GetProfileActionGrant($iProfile, $sClass, $sAction);
|
||||
if (is_null($iGrant) || !$iGrant)
|
||||
{
|
||||
$iGrant = $this->GetProfileActionGrant($iProfile, $sClass, $sAction);
|
||||
if (is_null($iGrant) || !$iGrant)
|
||||
continue; // loop to the next profile
|
||||
}
|
||||
else
|
||||
{
|
||||
$iPermission = UR_ALLOWED_YES;
|
||||
|
||||
// update the list of attributes with those allowed for this profile
|
||||
//
|
||||
$oSearch = DBObjectSearch::FromOQL_AllData("SELECT URP_AttributeGrant WHERE actiongrantid = :actiongrantid");
|
||||
$oSet = new DBObjectSet($oSearch, array(), array('actiongrantid' => $iGrant));
|
||||
$aProfileAttributes = $oSet->GetColumnAsArray('attcode', false);
|
||||
if (count($aProfileAttributes) == 0)
|
||||
{
|
||||
continue; // loop to the next profile
|
||||
$aAllAttributes = array_keys(MetaModel::ListAttributeDefs($sClass));
|
||||
$aAttributes = array_merge($aAttributes, $aAllAttributes);
|
||||
}
|
||||
else
|
||||
{
|
||||
$iPermission = UR_ALLOWED_YES;
|
||||
|
||||
// update the list of attributes with those allowed for this profile
|
||||
//
|
||||
$oSearch = DBObjectSearch::FromOQL_AllData("SELECT URP_AttributeGrant WHERE actiongrantid = :actiongrantid");
|
||||
$oSet = new DBObjectSet($oSearch, array(), array('actiongrantid' => $iGrant));
|
||||
$aProfileAttributes = $oSet->GetColumnAsArray('attcode', false);
|
||||
if (count($aProfileAttributes) == 0)
|
||||
{
|
||||
$aAllAttributes = array_keys(MetaModel::ListAttributeDefs($sClass));
|
||||
$aAttributes = array_merge($aAttributes, $aAllAttributes);
|
||||
}
|
||||
else
|
||||
{
|
||||
$aAttributes = array_merge($aAttributes, $aProfileAttributes);
|
||||
}
|
||||
$aAttributes = array_merge($aAttributes, $aProfileAttributes);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -926,16 +1004,13 @@ exit;
|
||||
// Note: The object set is ignored because it was interesting to optimize for huge data sets
|
||||
// and acceptable to consider only the root class of the object set
|
||||
$iPermission = UR_ALLOWED_NO;
|
||||
if (isset($this->m_aUserProfiles[$iUser]))
|
||||
foreach($this->GetUserProfiles($iUser) as $iProfile => $oProfile)
|
||||
{
|
||||
foreach($this->m_aUserProfiles[$iUser] as $iProfile => $oProfile)
|
||||
$oGrantRecord = $this->GetClassStimulusGrant($iProfile, $sClass, $sStimulusCode);
|
||||
if (!is_null($oGrantRecord))
|
||||
{
|
||||
$oGrantRecord = $this->GetClassStimulusGrant($iProfile, $sClass, $sStimulusCode);
|
||||
if (!is_null($oGrantRecord))
|
||||
{
|
||||
// no need to fetch the record, we've requested the records having permission = 'yes'
|
||||
$iPermission = UR_ALLOWED_YES;
|
||||
}
|
||||
// no need to fetch the record, we've requested the records having permission = 'yes'
|
||||
$iPermission = UR_ALLOWED_YES;
|
||||
}
|
||||
}
|
||||
return $iPermission;
|
||||
|
||||
@@ -97,7 +97,7 @@ class URP_Profiles extends UserRightsBaseClass
|
||||
|
||||
function DoShowGrantSumary($oPage)
|
||||
{
|
||||
if ($this->GetName() == "Administrator")
|
||||
if ($this->GetRawName() == "Administrator")
|
||||
{
|
||||
// Looks dirty, but ok that's THE ONE
|
||||
$oPage->p(Dict::S('UI:UserManagement:AdminProfile+'));
|
||||
|
||||
@@ -45,11 +45,13 @@ class ajax_page extends WebPage
|
||||
{
|
||||
parent::__construct($s_title);
|
||||
$this->m_sReadyScript = "";
|
||||
$this->add_header("Content-type: text/html; charset=utf-8");
|
||||
//$this->add_header("Content-type: text/html; charset=utf-8");
|
||||
$this->add_header("Cache-control: no-cache");
|
||||
$this->m_sCurrentTabContainer = '';
|
||||
$this->m_sCurrentTab = '';
|
||||
$this->m_aTabs = array();
|
||||
$this->sContentType = 'text/html';
|
||||
$this->sContentDisposition = 'inline';
|
||||
}
|
||||
|
||||
public function AddTabContainer($sTabContainer, $sPrefix = '')
|
||||
@@ -86,17 +88,29 @@ class ajax_page extends WebPage
|
||||
return $sPreviousTab;
|
||||
}
|
||||
|
||||
public function GetCurrentTab()
|
||||
{
|
||||
return $this->m_sCurrentTab;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 (count($this->m_aTabs) > 0)
|
||||
{
|
||||
$this->add_ready_script(
|
||||
@@ -165,7 +179,15 @@ EOF
|
||||
|
||||
$s_captured_output = ob_get_contents();
|
||||
ob_end_clean();
|
||||
echo $this->s_content;
|
||||
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;
|
||||
}
|
||||
//echo $this->s_deferred_content;
|
||||
if (count($this->a_scripts) > 0)
|
||||
{
|
||||
@@ -176,7 +198,7 @@ EOF
|
||||
if (!empty($this->s_deferred_content))
|
||||
{
|
||||
echo "<script type=\"text/javascript\">\n";
|
||||
echo "\$('body').append('".$this->s_deferred_content."');\n";
|
||||
echo "\$('body').append('".addslashes(str_replace("\n", '', $this->s_deferred_content))."');\n";
|
||||
echo "\n</script>\n";
|
||||
}
|
||||
if (!empty($this->m_sReadyScript))
|
||||
@@ -187,7 +209,7 @@ EOF
|
||||
}
|
||||
if (trim($s_captured_output) != "")
|
||||
{
|
||||
echo $s_captured_output;
|
||||
echo self::FilterXSS($s_captured_output);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -212,6 +234,64 @@ EOF
|
||||
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()
|
||||
{
|
||||
if (!empty($this->m_sCurrentTabContainer) && !empty($this->m_sCurrentTab))
|
||||
{
|
||||
$iOffset = isset($this->m_aTabs[$this->m_sCurrentTabContainer]['content'][$this->m_sCurrentTab]) ? strlen($this->m_aTabs[$this->m_sCurrentTabContainer]['content'][$this->m_sCurrentTab]): 0;
|
||||
return array('tc' => $this->m_sCurrentTabContainer, 'tab' => $this->m_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 (isset($this->m_aTabs[$offset['tc']]['content'][$offset['tab']]))
|
||||
{
|
||||
$sCaptured = substr($this->m_aTabs[$offset['tc']]['content'][$offset['tab']], $offset['offset']);
|
||||
$this->m_aTabs[$offset['tc']]['content'][$offset['tab']] = substr($this->m_aTabs[$offset['tc']]['content'][$offset['tab']], 0, $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)
|
||||
@@ -220,9 +300,6 @@ EOF
|
||||
*/
|
||||
public function add_ready_script($sScript)
|
||||
{
|
||||
// Does nothing in ajax rendered content.. for now...
|
||||
// Maybe we should add this as a simple <script> tag at the end of the output
|
||||
// considering that at this time everything in the page is "ready"...
|
||||
$this->m_sReadyScript .= $sScript;
|
||||
}
|
||||
|
||||
@@ -236,6 +313,10 @@ EOF
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static function FilterXSS($sHTML)
|
||||
{
|
||||
return str_ireplace(array('<script', '</script>'), array('<!-- <removed-script', '</removed-script> -->'), $sHTML);
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
|
||||
@@ -26,8 +26,10 @@
|
||||
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/sqlblock.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.'/application/menunode.class.inc.php');
|
||||
require_once(APPROOT.'/application/utils.inc.php');
|
||||
|
||||
|
||||
@@ -24,6 +24,43 @@
|
||||
*/
|
||||
|
||||
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
|
||||
*
|
||||
@@ -40,12 +77,16 @@ class ApplicationContext
|
||||
protected $aValues;
|
||||
protected static $aDefaultValues; // Cache shared among all instances
|
||||
|
||||
public function __construct()
|
||||
public function __construct($bReadContext = true)
|
||||
{
|
||||
$this->aNames = array(
|
||||
'org_id', 'menu'
|
||||
);
|
||||
$this->ReadContext();
|
||||
if ($bReadContext)
|
||||
{
|
||||
$this->ReadContext();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -54,7 +95,7 @@ class ApplicationContext
|
||||
*/
|
||||
protected function ReadContext()
|
||||
{
|
||||
if (empty(self::$aDefaultValues))
|
||||
if (!isset(self::$aDefaultValues))
|
||||
{
|
||||
self::$aDefaultValues = array();
|
||||
$aContext = utils::ReadParam('c', array());
|
||||
@@ -126,7 +167,7 @@ class ApplicationContext
|
||||
$sContext = "";
|
||||
foreach($this->aValues as $sName => $sValue)
|
||||
{
|
||||
$sContext .= "<input type=\"hidden\" name=\"c[$sName]\" value=\"$sValue\" />\n";
|
||||
$sContext .= "<input type=\"hidden\" name=\"c[$sName]\" value=\"".htmlentities($sValue, ENT_QUOTES, 'UTF-8')."\" />\n";
|
||||
}
|
||||
return $sContext;
|
||||
}
|
||||
@@ -166,5 +207,101 @@ class ApplicationContext
|
||||
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 '';
|
||||
}
|
||||
}
|
||||
}
|
||||
?>
|
||||
|
||||
@@ -178,36 +178,6 @@ class DisplayBlock
|
||||
public function Display(WebPage $oPage, $sId, $aExtraParams = array())
|
||||
{
|
||||
$oPage->add($this->GetDisplay($oPage, $sId, $aExtraParams));
|
||||
/*
|
||||
$aExtraParams = array_merge($aExtraParams, $this->m_aParams);
|
||||
$aExtraParams['block_id'] = $sId;
|
||||
if (!$this->m_bAsynchronous)
|
||||
{
|
||||
// render now
|
||||
$oPage->add("<div id=\"$sId\" class=\"display_block\">\n");
|
||||
$this->RenderContent($oPage, $aExtraParams);
|
||||
$oPage->add("</div>\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
// render it as an Ajax (asynchronous) call
|
||||
$sFilter = $this->m_oFilter->serialize();
|
||||
$oPage->add("<div id=\"$sId\" class=\"display_block loading\">\n");
|
||||
$oPage->p("<img src=\"../images/indicator_arrows.gif\"> Loading...");
|
||||
$oPage->add("</div>\n");
|
||||
$oPage->add('
|
||||
<script language="javascript">
|
||||
$.post("ajax.render.php?style='.$this->m_sStyle.'",
|
||||
{ operation: "ajax", filter: "$sFilter" },
|
||||
function(data){
|
||||
$("#'.$sId.'").empty();
|
||||
$("#'.$sId.'").append(data);
|
||||
$("#'.$sId.'").removeClass("loading");
|
||||
}
|
||||
);
|
||||
</script>'); // TO DO: add support for $aExtraParams in asynchronous/Ajax mode
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
public function GetDisplay(WebPage $oPage, $sId, $aExtraParams = array())
|
||||
@@ -262,41 +232,20 @@ class DisplayBlock
|
||||
$sHtml .= "<div id=\"$sId\" class=\"display_block loading\">\n";
|
||||
$sHtml .= $oPage->GetP("<img src=\"../images/indicator_arrows.gif\"> ".Dict::S('UI:Loading'));
|
||||
$sHtml .= "</div>\n";
|
||||
$sHtml .= '
|
||||
<script language="javascript">
|
||||
$oPage->add_script('
|
||||
$.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");
|
||||
// Check each "listResults" table for a checkbox in the first column and make the first column sortable only if it does not contain a checkbox in the header
|
||||
$("#'.$sId.'".listResults").each( function()
|
||||
{
|
||||
var table = $(this);
|
||||
var id = $(this).parent();
|
||||
var checkbox = (table.find(\'th:first :checkbox\').length > 0);
|
||||
if (checkbox)
|
||||
{
|
||||
// There is a checkbox in the first column, do not make it sortable
|
||||
table.tablesorter( { headers: { 0: {sorter: false}}, widgets: [\'myZebra\', \'truncatedList\']} ); // sortable and zebra tables
|
||||
}
|
||||
else
|
||||
{
|
||||
// There is NO checkbox in the first column, all columns are considered sortable
|
||||
table.tablesorter( { widgets: [\'myZebra\', \'truncatedList\']} ); // sortable and zebra tables
|
||||
}
|
||||
});
|
||||
}
|
||||
);
|
||||
</script>';
|
||||
');
|
||||
}
|
||||
if ($bAutoReload)
|
||||
{
|
||||
$sHtml .= '
|
||||
<script language="javascript">
|
||||
setInterval("ReloadBlock(\''.$sId.'\', \''.$this->m_sStyle.'\', \''.$sFilter.'\', \"'.$sExtraParams.'\")", '.$iReloadInterval.');
|
||||
</script>';
|
||||
$oPage->add_script('setInterval("ReloadBlock(\''.$sId.'\', \''.$this->m_sStyle.'\', \''.$sFilter.'\', \"'.$sExtraParams.'\")", '.$iReloadInterval.');');
|
||||
}
|
||||
return $sHtml;
|
||||
}
|
||||
@@ -331,9 +280,10 @@ class DisplayBlock
|
||||
$oAppContext = new ApplicationContext();
|
||||
$sClass = $this->m_oFilter->GetClass();
|
||||
$aFilterCodes = array_keys(MetaModel::GetClassFilterDefs($sClass));
|
||||
$aCallSpec = array($sClass, 'MapContextParam');
|
||||
foreach($oAppContext->GetNames() as $sContextParam)
|
||||
{
|
||||
eval("\$sParamCode = $sClass::MapContextParam('$sContextParam');"); //Map context parameter to the value/filter code depending on the class
|
||||
$sParamCode = call_user_func($aCallSpec, $sContextParam); //Map context parameter to the value/filter code depending on the class
|
||||
if (!is_null($sParamCode))
|
||||
{
|
||||
$sParamValue = $oAppContext->GetCurrentValue($sContextParam, null);
|
||||
@@ -345,7 +295,7 @@ class DisplayBlock
|
||||
}
|
||||
foreach($aFilterCodes as $sFilterCode)
|
||||
{
|
||||
$sExternalFilterValue = utils::ReadParam($sFilterCode, '');
|
||||
$sExternalFilterValue = utils::ReadParam($sFilterCode, '', false, 'raw_data');
|
||||
$condition = null;
|
||||
if (isset($aExtraParams[$sFilterCode]))
|
||||
{
|
||||
@@ -361,11 +311,33 @@ class DisplayBlock
|
||||
|
||||
if (!is_null($condition))
|
||||
{
|
||||
$this->m_oFilter->AddCondition($sFilterCode, $condition); // Use the default 'loose' operator
|
||||
$this->AddCondition($sFilterCode, $condition);
|
||||
}
|
||||
}
|
||||
}
|
||||
$this->m_oSet = new CMDBObjectSet($this->m_oFilter, array(), $aQueryParams);
|
||||
$aOrderBy = array();
|
||||
if (isset($aExtraParams['order_by']))
|
||||
{
|
||||
// Convert the string describing the order_by parameter into an array
|
||||
// The syntax is +attCode1,-attCode2
|
||||
// attCode1 => ascending, attCode2 => descending
|
||||
$aTemp = explode(',', $aExtraParams['order_by']);
|
||||
foreach($aTemp as $sTemp)
|
||||
{
|
||||
$aMatches = array();
|
||||
if (preg_match('/^([+-])?(.+)$/', $sTemp, $aMatches))
|
||||
{
|
||||
$bAscending = true;
|
||||
if ($aMatches[1] == '-')
|
||||
{
|
||||
$bAscending = false;
|
||||
}
|
||||
$aOrderBy[$aMatches[2]] = $bAscending;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$this->m_oSet = new CMDBObjectSet($this->m_oFilter, $aOrderBy, $aQueryParams);
|
||||
}
|
||||
switch($this->m_sStyle)
|
||||
{
|
||||
@@ -375,7 +347,12 @@ class DisplayBlock
|
||||
$sGroupByField = $aExtraParams['group_by'];
|
||||
$aGroupBy = array();
|
||||
$sLabels = array();
|
||||
while($oObj = $this->m_oSet->Fetch())
|
||||
$iTotalCount = $this->m_oSet->Count();
|
||||
$oTmpSet = clone $this->m_oSet;
|
||||
// Speed up the load, load only the needed field to group on
|
||||
$sAlias = $oTmpSet->GetFilter()->GetClassAlias();
|
||||
$oTmpSet->OptimizeColumnLoad(array($sAlias => array($sGroupByField)));
|
||||
while($oObj = $oTmpSet->Fetch())
|
||||
{
|
||||
if (isset($aExtraParams['group_by_expr']))
|
||||
{
|
||||
@@ -395,12 +372,14 @@ class DisplayBlock
|
||||
foreach($aGroupBy as $sValue => $iCount)
|
||||
{
|
||||
$aData[] = array ( 'group' => $sLabels[$sValue],
|
||||
'value' => "<a href=\"./UI.php?operation=search&dosearch=1&$sParams&filter=$sFilter&$sGroupByField=".urlencode($sValue)."\">$iCount</a>"); // TO DO: add the context information
|
||||
'value' => "<a href=\"".utils::GetAbsoluteUrlAppRoot()."pages/UI.php?operation=search&dosearch=1&$sParams&filter=$sFilter&$sGroupByField=".urlencode($sValue)."\">$iCount</a>"); // TO DO: add the context information
|
||||
}
|
||||
$aAttribs =array(
|
||||
'group' => array('label' => MetaModel::GetLabel($this->m_oFilter->GetClass(), $sGroupByField), 'description' => ''),
|
||||
'value' => array('label'=> Dict::S('UI:GroupBy:Count'), 'description' => Dict::S('UI:GroupBy:Count+'))
|
||||
);
|
||||
$sFormat = isset($aExtraParams['format']) ? $aExtraParams['format'] : 'UI:Pagination:HeaderNoSelection';
|
||||
$sHtml .= $oPage->GetP(Dict::Format($sFormat, $iTotalCount));
|
||||
$sHtml .= $oPage->GetTable($aAttribs, $aData);
|
||||
}
|
||||
else
|
||||
@@ -574,7 +553,7 @@ class DisplayBlock
|
||||
}
|
||||
}
|
||||
|
||||
$sHtml .= $oPage->GetP("<a href=\"./UI.php?operation=new&class=$sClass&$sParams{$sDefault}\">".Dict::Format('UI:ClickToCreateNew', Metamodel::GetName($sClass))."</a>\n");
|
||||
$sHtml .= $oPage->GetP("<a href=\"".utils::GetAbsoluteUrlAppRoot()."pages/UI.php?operation=new&class=$sClass&$sParams{$sDefault}\">".Dict::Format('UI:ClickToCreateNew', Metamodel::GetName($sClass))."</a>\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -610,7 +589,7 @@ class DisplayBlock
|
||||
$sDefaults .= '&'.urlencode($sName).'='.urlencode($sValue);
|
||||
}
|
||||
}
|
||||
$sHtml .= $oPage->GetP("<a href=\"../pages/UI.php?operation=modify_links&class=$sClass&sParams&link_attr=".$aExtraParams['link_attr']."&id=".$aExtraParams['object_id']."&target_class=$sTargetClass&addObjects=true$sDefaults\">".Dict::Format('UI:ClickToCreateNew', Metamodel::GetName($sClass))."</a>\n");
|
||||
$sHtml .= $oPage->GetP("<a href=\"".utils::GetAbsoluteUrlAppRoot()."pages/UI.php?operation=modify_links&class=$sClass&sParams&link_attr=".$aExtraParams['link_attr']."&id=".$aExtraParams['object_id']."&target_class=$sTargetClass&addObjects=true$sDefaults\">".Dict::Format('UI:ClickToCreateNew', Metamodel::GetName($sClass))."</a>\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -635,7 +614,7 @@ class DisplayBlock
|
||||
$sContextParamValue = $oAppContext->GetCurrentValue($sFilterCode, null);
|
||||
if (!is_null($sContextParamValue) && ! empty($sContextParamValue) && MetaModel::IsValidFilterCode($sClass, $sFilterCode))
|
||||
{
|
||||
$this->m_oFilter->AddCondition($sFilterCode, $sContextParamValue); // Use the default 'loose' operator
|
||||
$this->AddCondition($sFilterCode, $sContextParamValue);
|
||||
}
|
||||
}
|
||||
$aQueryParams = array();
|
||||
@@ -646,7 +625,7 @@ class DisplayBlock
|
||||
$this->m_oSet = new CMDBObjectSet($this->m_oFilter, array(), $aQueryParams);
|
||||
}
|
||||
$iCount = $this->m_oSet->Count();
|
||||
$sHyperlink = '../pages/UI.php?operation=search&'.$oAppContext->GetForLink().'&filter='.$this->m_oFilter->serialize();
|
||||
$sHyperlink = utils::GetAbsoluteUrlAppRoot().'pages/UI.php?operation=search&'.$oAppContext->GetForLink().'&filter='.urlencode($this->m_oFilter->serialize());
|
||||
$sHtml .= '<p><a class="actions" href="'.$sHyperlink.'">';
|
||||
$sHtml .= MetaModel::GetClassIcon($sClass, true, 'float;left;margin-right:10px;');
|
||||
$sHtml .= MetaModel::GetName($sClass).': '.$iCount.'</a></p>';
|
||||
@@ -654,9 +633,9 @@ class DisplayBlock
|
||||
$sHtml .= '<p>';
|
||||
if (UserRights::IsActionAllowed($sClass, UR_ACTION_MODIFY))
|
||||
{
|
||||
$sHtml .= "<a href=\"../pages/UI.php?operation=new&class={$sClass}&$sParams\">".Dict::Format('UI:ClickToCreateNew', MetaModel::GetName($sClass))."</a><br/>\n";
|
||||
$sHtml .= "<a href=\"".utils::GetAbsoluteUrlAppRoot()."pages/UI.php?operation=new&class={$sClass}&$sParams\">".Dict::Format('UI:ClickToCreateNew', MetaModel::GetName($sClass))."</a><br/>\n";
|
||||
}
|
||||
$sHtml .= "<a href=\"../pages/UI.php?operation=search_form&class={$sClass}&$sParams\">".Dict::Format('UI:SearchFor_Class', MetaModel::GetName($sClass))."</a>\n";
|
||||
$sHtml .= "<a href=\"".utils::GetAbsoluteUrlAppRoot()."pages/UI.php?operation=search_form&class={$sClass}&$sParams\">".Dict::Format('UI:SearchFor_Class', MetaModel::GetName($sClass))."</a>\n";
|
||||
$sHtml .= '</p>';
|
||||
break;
|
||||
|
||||
@@ -677,7 +656,7 @@ class DisplayBlock
|
||||
$sContextParamValue = $oAppContext->GetCurrentValue($sFilterCode, null);
|
||||
if (!is_null($sContextParamValue) && ! empty($sContextParamValue) && MetaModel::IsValidFilterCode($sClass, $sFilterCode))
|
||||
{
|
||||
$this->m_oFilter->AddCondition($sFilterCode, $sContextParamValue); // Use the default 'loose' operator
|
||||
$this->AddCondition($sFilterCode, $sContextParamValue);
|
||||
}
|
||||
}
|
||||
$aQueryParams = array();
|
||||
@@ -700,14 +679,14 @@ class DisplayBlock
|
||||
$oFilter->AddCondition($sStateAttrCode, $sStateValue, '=');
|
||||
$oSet = new DBObjectSet($oFilter);
|
||||
$aCounts[$sStateValue] = $oSet->Count();
|
||||
$aStateLabels[$sStateValue] = Dict::S("Class:".$oAttDef->GetHostClass()."/Attribute:$sStateAttrCode/Value:$sStateValue");
|
||||
$aStateLabels[$sStateValue] = $oAttDef->GetValueLabel($sStateValue);
|
||||
if ($aCounts[$sStateValue] == 0)
|
||||
{
|
||||
$aCounts[$sStateValue] = '-';
|
||||
}
|
||||
else
|
||||
{
|
||||
$sHyperlink = '../pages/UI.php?operation=search&'.$oAppContext->GetForLink().'&filter='.$oFilter->serialize();
|
||||
$sHyperlink = utils::GetAbsoluteUrlAppRoot().'pages/UI.php?operation=search&'.$oAppContext->GetForLink().'&filter='.urlencode($oFilter->serialize());
|
||||
$aCounts[$sStateValue] = "<a href=\"$sHyperlink\">{$aCounts[$sStateValue]}</a>";
|
||||
}
|
||||
}
|
||||
@@ -716,18 +695,11 @@ class DisplayBlock
|
||||
$sHtml .= '<tr><td>'.implode('</td><td>', $aCounts).'</td></tr></table></div>';
|
||||
// Title & summary
|
||||
$iCount = $this->m_oSet->Count();
|
||||
$sHyperlink = '../pages/UI.php?operation=search&'.$oAppContext->GetForLink().'&filter='.$this->m_oFilter->serialize();
|
||||
$sHyperlink = utils::GetAbsoluteUrlAppRoot().'pages/UI.php?operation=search&'.$oAppContext->GetForLink().'&filter='.urlencode($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>';
|
||||
break;
|
||||
|
||||
case 'bare_details':
|
||||
while($oObj = $this->m_oSet->Fetch())
|
||||
{
|
||||
$sHtml .= $oObj->GetBareProperties($oPage);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'csv':
|
||||
$sHtml .= "<textarea style=\"width:95%;height:98%\">\n";
|
||||
$sHtml .= cmdbAbstractObject::GetSetAsCSV($this->m_oSet);
|
||||
@@ -764,6 +736,12 @@ EOF
|
||||
|
||||
case 'open_flash_chart':
|
||||
static $iChartCounter = 0;
|
||||
$oAppContext = new ApplicationContext();
|
||||
$sContext = $oAppContext->GetForLink();
|
||||
if (!empty($sContext))
|
||||
{
|
||||
$sContext = '&'.$sContext;
|
||||
}
|
||||
$sChartType = isset($aExtraParams['chart_type']) ? $aExtraParams['chart_type'] : 'pie';
|
||||
$sTitle = isset($aExtraParams['chart_title']) ? $aExtraParams['chart_title'] : '';
|
||||
$sGroupBy = isset($aExtraParams['group_by']) ? $aExtraParams['group_by'] : '';
|
||||
@@ -772,13 +750,58 @@ EOF
|
||||
$sHtml .= "<div id=\"my_chart_{$iChartCounter}\">If the chart does not display, <a href=\"http://get.adobe.com/flash/\" target=\"_blank\">install Flash</a></div>\n";
|
||||
$oPage->add_script("function ofc_resize(left, width, top, height) { /* do nothing special */ }");
|
||||
$oPage->add_ready_script("swfobject.embedSWF(\"../images/open-flash-chart.swf\", \"my_chart_{$iChartCounter}\", \"100%\", \"300\",\"9.0.0\", \"expressInstall.swf\",
|
||||
{\"data-file\":\"".urlencode("../pages/ajax.render.php?operation=open_flash_chart¶ms[group_by]=$sGroupBy{$sGroupByExpr}¶ms[chart_type]=$sChartType¶ms[chart_title]=$sTitle&filter=".$sFilter)."\"}, {wmode: 'transparent'} );\n");
|
||||
{\"data-file\":\"".urlencode(utils::GetAbsoluteUrlAppRoot()."pages/ajax.render.php?operation=open_flash_chart¶ms[group_by]=$sGroupBy{$sGroupByExpr}¶ms[chart_type]=$sChartType¶ms[chart_title]=$sTitle&id=$sId&filter=".urlencode($sFilter))."\"}, {wmode: 'transparent'} );\n");
|
||||
$iChartCounter++;
|
||||
if (isset($aExtraParams['group_by']))
|
||||
{
|
||||
$sGroupByField = $aExtraParams['group_by'];
|
||||
$aGroupBy = array();
|
||||
while($oObj = $this->m_oSet->Fetch())
|
||||
{
|
||||
if (isset($aExtraParams['group_by_expr']))
|
||||
{
|
||||
eval("\$sValue = ".sprintf($aExtraParams['group_by_expr'], $oObj->Get($sGroupByField)).';');
|
||||
}
|
||||
else
|
||||
{
|
||||
$sValue = $oObj->Get($sGroupByField);
|
||||
}
|
||||
$aGroupBy[$sValue] = isset($aGroupBy[$sValue]) ? $aGroupBy[$sValue]+1 : 1;
|
||||
}
|
||||
$sFilter = urlencode($this->m_oFilter->serialize());
|
||||
$aData = array();
|
||||
$aLabels = array();
|
||||
$idx = 0;
|
||||
$aURLs = array();
|
||||
foreach($aGroupBy as $sValue => $iValue)
|
||||
{
|
||||
$oDrillDownFilter = clone $this->m_oFilter;
|
||||
$oDrillDownFilter->AddCondition($sGroupByField, $sValue, '=');
|
||||
$aURLs[$idx] = $oDrillDownFilter->serialize();
|
||||
$idx++;
|
||||
}
|
||||
$sURLList = '';
|
||||
foreach($aURLs as $index => $sURL)
|
||||
{
|
||||
$sURLList .= "\taURLs[$index] = '".utils::GetAbsoluteUrlAppRoot()."pages/UI.php?operation=search&format=html{$sContext}&filter=".addslashes($sURL)."';\n";
|
||||
}
|
||||
$oPage->add_script(
|
||||
<<<EOF
|
||||
function ofc_drill_down_{$sId}(index)
|
||||
{
|
||||
var aURLs = new Array();
|
||||
{$sURLList}
|
||||
window.location.href=aURLs[index];
|
||||
}
|
||||
EOF
|
||||
);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'open_flash_chart_ajax':
|
||||
require_once(APPROOT.'/pages/php-ofc-library/open-flash-chart.php');
|
||||
$sChartType = isset($aExtraParams['chart_type']) ? $aExtraParams['chart_type'] : 'pie';
|
||||
$sId = utils::ReadParam('id', '');
|
||||
|
||||
$oChart = new open_flash_chart();
|
||||
switch($sChartType)
|
||||
@@ -805,12 +828,15 @@ EOF
|
||||
$sFilter = urlencode($this->m_oFilter->serialize());
|
||||
$aData = array();
|
||||
$aLabels = array();
|
||||
$maxValue = 0;
|
||||
foreach($aGroupBy as $sValue => $iValue)
|
||||
{
|
||||
$aData[] = $iValue;
|
||||
$oBarValue = new bar_value($iValue);
|
||||
$oBarValue->on_click("ofc_drill_down_$sId");
|
||||
$aData[] = $oBarValue;
|
||||
if ($iValue > $maxValue) $maxValue = $iValue;
|
||||
$aLabels[] = $sValue;
|
||||
}
|
||||
$maxValue = max($aData);
|
||||
$oYAxis = new y_axis();
|
||||
$aMagicValues = array(1,2,5,10);
|
||||
$iMultiplier = 1;
|
||||
@@ -869,7 +895,9 @@ EOF
|
||||
$aData = array();
|
||||
foreach($aGroupBy as $sValue => $iValue)
|
||||
{
|
||||
$aData[] = new pie_value($iValue, $sValue); //@@ BUG: not passed via ajax !!!
|
||||
$PieValue = new pie_value($iValue, $sValue); //@@ BUG: not passed via ajax !!!
|
||||
$PieValue->on_click("ofc_drill_down_$sId");
|
||||
$aData[] = $PieValue;
|
||||
}
|
||||
|
||||
|
||||
@@ -894,6 +922,43 @@ EOF
|
||||
}
|
||||
return $sHtml;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a condition (restriction) to the current DBObjectSearch on which the display block is based
|
||||
* taking into account the hierarchical keys for which the condition is based on the 'below' operator
|
||||
*/
|
||||
protected function AddCondition($sFilterCode, $condition)
|
||||
{
|
||||
$sClass = $this->m_oFilter->GetClass();
|
||||
$bConditionAdded = false;
|
||||
|
||||
// If the condition is an external key with a class having a hierarchy, use a "below" criteria
|
||||
if (MetaModel::IsValidAttCode($sClass, $sFilterCode))
|
||||
{
|
||||
$oAttDef = MetaModel::GetAttributeDef($sClass, $sFilterCode);
|
||||
|
||||
if ($oAttDef->IsExternalKey())
|
||||
{
|
||||
$sHierarchicalKeyCode = MetaModel::IsHierarchicalClass($oAttDef->GetTargetClass());
|
||||
|
||||
if ($sHierarchicalKeyCode !== false)
|
||||
{
|
||||
$oFilter = new DBObjectSearch($oAttDef->GetTargetClass());
|
||||
$oFilter->AddCondition('id', $condition);
|
||||
$oHKFilter = new DBObjectSearch($oAttDef->GetTargetClass());
|
||||
$oHKFilter->AddCondition_PointingTo($oFilter, $sHierarchicalKeyCode, TREE_OPERATOR_BELOW); // Use the 'below' operator by default
|
||||
$this->m_oFilter->AddCondition_PointingTo($oHKFilter, $sFilterCode);
|
||||
$bConditionAdded = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// In all other cases, just add the condition directly
|
||||
if (!$bConditionAdded)
|
||||
{
|
||||
$this->m_oFilter->AddCondition($sFilterCode, $condition); // Use the default 'loose' operator
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -973,7 +1038,7 @@ class HistoryBlock extends DisplayBlock
|
||||
$aValues = array();
|
||||
foreach($aChanges as $aChange)
|
||||
{
|
||||
$aValues[] = array('date' => $aChange['date'], 'userinfo' => $aChange['userinfo'], 'log' => "<ul><li>".implode('</li><li>', $aChange['log'])."</li></ul>");
|
||||
$aValues[] = array('date' => $aChange['date'], 'userinfo' => htmlentities($aChange['userinfo'], ENT_QUOTES, 'UTF-8'), 'log' => "<ul><li>".implode('</li><li>', $aChange['log'])."</li></ul>");
|
||||
}
|
||||
$sHtml .= $oPage->GetTable($aAttribs, $aValues);
|
||||
return $sHtml;
|
||||
@@ -996,11 +1061,17 @@ class MenuBlock extends DisplayBlock
|
||||
$sHtml = '';
|
||||
$oAppContext = new ApplicationContext();
|
||||
$sContext = $oAppContext->GetForLink();
|
||||
if (!empty($sContext))
|
||||
{
|
||||
$sContext = '&'.$sContext;
|
||||
}
|
||||
$sClass = $this->m_oFilter->GetClass();
|
||||
$oSet = new CMDBObjectSet($this->m_oFilter);
|
||||
$sFilter = $this->m_oFilter->serialize();
|
||||
$sFilterDesc = $this->m_oFilter->ToOql();
|
||||
$aActions = array();
|
||||
$sUIPage = cmdbAbstractObject::ComputeUIPage($sClass);
|
||||
$sUIPage = cmdbAbstractObject::ComputeStandardUIPage($sClass);
|
||||
$sRootUrl = utils::GetAbsoluteUrlAppRoot();
|
||||
// 1:n links, populate the target object as a default value when creating a new linked object
|
||||
if (isset($aExtraParams['target_attr']))
|
||||
{
|
||||
@@ -1019,7 +1090,7 @@ class MenuBlock extends DisplayBlock
|
||||
case 0:
|
||||
// No object in the set, the only possible action is "new"
|
||||
$bIsModifyAllowed = (UserRights::IsActionAllowed($sClass, UR_ACTION_MODIFY) == UR_ALLOWED_YES);
|
||||
if ($bIsModifyAllowed) { $aActions[] = array ('label' => Dict::S('UI:Menu:New'), 'url' => "../page/$sUIPage?operation=new&class=$sClass&$sContext{$sDefault}"); }
|
||||
if ($bIsModifyAllowed) { $aActions['UI:Menu:New'] = array ('label' => Dict::S('UI:Menu:New'), 'url' => "{$sRootUrl}pages/$sUIPage?operation=new&class=$sClass{$sContext}{$sDefault}"); }
|
||||
break;
|
||||
|
||||
case 1:
|
||||
@@ -1032,23 +1103,22 @@ class MenuBlock extends DisplayBlock
|
||||
// Just one object in the set, possible actions are "new / clone / modify and delete"
|
||||
if (!isset($aExtraParams['link_attr']))
|
||||
{
|
||||
$sUrl = utils::GetAbsoluteUrl(false);
|
||||
if ($bIsModifyAllowed) { $aActions[] = array ('label' => Dict::S('UI:Menu:Modify'), 'url' => "../pages/$sUIPage?operation=modify&class=$sClass&id=$id&$sContext#"); }
|
||||
if ($bIsModifyAllowed) { $aActions[] = array ('label' => Dict::S('UI:Menu:New'), 'url' => "../pages/$sUIPage?operation=new&class=$sClass&$sContext{$sDefault}"); }
|
||||
if ($bIsDeleteAllowed) { $aActions[] = array ('label' => Dict::S('UI:Menu:Delete'), 'url' => "../pages/$sUIPage?operation=delete&class=$sClass&id=$id&$sContext"); }
|
||||
if ($bIsModifyAllowed) { $aActions['UI:Menu:Modify'] = array ('label' => Dict::S('UI:Menu:Modify'), 'url' => "{$sRootUrl}pages/$sUIPage?operation=modify&class=$sClass&id=$id{$sContext}#"); }
|
||||
if ($bIsModifyAllowed) { $aActions['UI:Menu:New'] = array ('label' => Dict::S('UI:Menu:New'), 'url' => "{$sRootUrl}pages/$sUIPage?operation=new&class=$sClass{$sContext}{$sDefault}"); }
|
||||
if ($bIsDeleteAllowed) { $aActions['UI:Menu:Delete'] = array ('label' => Dict::S('UI:Menu:Delete'), 'url' => "{$sRootUrl}pages/$sUIPage?operation=delete&class=$sClass&id=$id{$sContext}"); }
|
||||
// Transitions / Stimuli
|
||||
$aTransitions = $oObj->EnumTransitions();
|
||||
if (count($aTransitions))
|
||||
{
|
||||
$this->AddMenuSeparator($aActions);
|
||||
$aStimuli = Metamodel::EnumStimuli($sClass);
|
||||
$aStimuli = Metamodel::EnumStimuli(get_class($oObj));
|
||||
foreach($aTransitions as $sStimulusCode => $aTransitionDef)
|
||||
{
|
||||
$iActionAllowed = (get_class($aStimuli[$sStimulusCode]) == 'StimulusUserAction') ? UserRights::IsStimulusAllowed($sClass, $sStimulusCode, $oSet) : UR_ALLOWED_NO;
|
||||
switch($iActionAllowed)
|
||||
{
|
||||
case UR_ALLOWED_YES:
|
||||
$aActions[] = array('label' => $aStimuli[$sStimulusCode]->GetLabel(), 'url' => "../pages/UI.php?operation=stimulus&stimulus=$sStimulusCode&class=$sClass&id=$id&$sContext");
|
||||
$aActions[$sStimulusCode] = array('label' => $aStimuli[$sStimulusCode]->GetLabel(), 'url' => "{$sRootUrl}pages/UI.php?operation=stimulus&stimulus=$sStimulusCode&class=$sClass&id=$id{$sContext}");
|
||||
break;
|
||||
|
||||
default:
|
||||
@@ -1063,23 +1133,14 @@ class MenuBlock extends DisplayBlock
|
||||
$this->AddMenuSeparator($aActions);
|
||||
foreach($aRelations as $sRelationCode)
|
||||
{
|
||||
$aActions[] = array ('label' => MetaModel::GetRelationVerbUp($sRelationCode), 'url' => "../pages/$sUIPage?operation=swf_navigator&relation=$sRelationCode&class=$sClass&id=$id&$sContext");
|
||||
$aActions[$sRelationCode] = array ('label' => MetaModel::GetRelationVerbUp($sRelationCode), 'url' => "{$sRootUrl}pages/$sUIPage?operation=swf_navigator&relation=$sRelationCode&class=$sClass&id=$id{$sContext}");
|
||||
}
|
||||
}
|
||||
$this->AddMenuSeparator($aActions);
|
||||
// Static menus: Email this page & CSV Export
|
||||
$aActions[] = array ('label' => Dict::S('UI:Menu:EMail'), 'url' => "mailto:?subject=".$oObj->GetName()."&body=".urlencode("$sUrl?operation=details&class=$sClass&id=$id&$sContext"));
|
||||
$aActions[] = array ('label' => Dict::S('UI:Menu:CSVExport'), 'url' => "../pages/$sUIPage?operation=search&filter=$sFilter&format=csv&$sContext");
|
||||
}
|
||||
else
|
||||
{
|
||||
// List of links, the only actions are 'Add...' and 'Manage...'
|
||||
$id = $aExtraParams['object_id'];
|
||||
$sTargetAttr = $aExtraParams['target_attr'];
|
||||
$oAttDef = MetaModel::GetAttributeDef($sClass, $sTargetAttr);
|
||||
$sTargetClass = $oAttDef->GetTargetClass();
|
||||
if ($bIsModifyAllowed) { $aActions[] = array ('label' => Dict::S('UI:Menu:Add'), 'url' => "../pages/$sUIPage?operation=modify_links&class=$sClass&link_attr=".$aExtraParams['link_attr']."&target_class=$sTargetClass&id=$id&addObjects=true&$sContext"); }
|
||||
if ($bIsModifyAllowed) { $aActions[] = array ('label' => Dict::S('UI:Menu:Manage'), 'url' => "../pages/$sUIPage?operation=modify_links&class=$sClass&link_attr=".$aExtraParams['link_attr']."&target_class=$sTargetClass&id=$id&sContext"); }
|
||||
$sUrl = ApplicationContext::MakeObjectUrl($sClass, $id);
|
||||
$aActions['UI:Menu:EMail'] = array ('label' => Dict::S('UI:Menu:EMail'), 'url' => "mailto:?subject=".urlencode($oObj->GetRawName())."&body=".urlencode($sUrl));
|
||||
$aActions['UI:Menu:CSVExport'] = array ('label' => Dict::S('UI:Menu:CSVExport'), 'url' => "{$sRootUrl}pages/$sUIPage?operation=search&filter=".urlencode($sFilter)."&format=csv{$sContext}");
|
||||
}
|
||||
$this->AddMenuSeparator($aActions);
|
||||
foreach (MetaModel::EnumPlugins('iApplicationUIExtension') as $oExtensionInstance)
|
||||
@@ -1087,7 +1148,7 @@ class MenuBlock extends DisplayBlock
|
||||
$oSet->Rewind();
|
||||
foreach($oExtensionInstance->EnumAllowedActions($oSet) as $sLabel => $sUrl)
|
||||
{
|
||||
$aActions[] = array ('label' => $sLabel, 'url' => $sUrl);
|
||||
$aActions[$sLabel] = array ('label' => $sLabel, 'url' => $sUrl);
|
||||
}
|
||||
}
|
||||
break;
|
||||
@@ -1105,21 +1166,23 @@ class MenuBlock extends DisplayBlock
|
||||
$oAttDef = MetaModel::GetAttributeDef($sClass, $sTargetAttr);
|
||||
$sTargetClass = $oAttDef->GetTargetClass();
|
||||
$bIsDeleteAllowed = UserRights::IsActionAllowed($sClass, UR_ACTION_DELETE, $oSet);
|
||||
if ($bIsModifyAllowed) { $aActions[] = array ('label' => Dict::S('UI:Menu:Add'), 'url' => "../pages/$sUIPage?operation=modify_links&class=$sClass&link_attr=".$aExtraParams['link_attr']."&target_class=$sTargetClass&id=$id&addObjects=true&$sContext"); }
|
||||
if ($bIsBulkModifyAllowed) { $aActions[] = array ('label' => Dict::S('UI:Menu:Manage'), 'url' => "../pages/$sUIPage?operation=modify_links&class=$sClass&link_attr=".$aExtraParams['link_attr']."&target_class=$sTargetClass&id=$id&sContext"); }
|
||||
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}"); }
|
||||
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}"); }
|
||||
//if ($bIsBulkDeleteAllowed) { $aActions[] = array ('label' => 'Remove All...', 'url' => "#"); }
|
||||
}
|
||||
else
|
||||
{
|
||||
// many objects in the set, possible actions are: new / modify all / delete all
|
||||
$sUrl = utils::GetAbsoluteUrl();
|
||||
if ($bIsModifyAllowed) { $aActions[] = array ('label' => Dict::S('UI:Menu:New'), 'url' => "../pages/$sUIPage?operation=new&class=$sClass&$sContext{$sDefault}"); }
|
||||
if ($bIsBulkModifyAllowed) { $aActions[] = array ('label' => Dict::S('UI:Menu:ModifyAll'), 'url' => "../pages/$sUIPage?operation=select_for_modify_all&class=$sClass&filter=$sFilter&sContext"); }
|
||||
if ($bIsBulkDeleteAllowed) { $aActions[] = array ('label' => Dict::S('UI:Menu:BulkDelete'), 'url' => "../pages/$sUIPage?operation=select_for_deletion&filter=$sFilter&$sContext"); }
|
||||
if ($bIsModifyAllowed) { $aActions['UI:Menu:New'] = array ('label' => Dict::S('UI:Menu:New'), 'url' => "{$sRootUrl}pages/$sUIPage?operation=new&class=$sClass{$sContext}{$sDefault}"); }
|
||||
if ($bIsBulkModifyAllowed) { $aActions['UI:Menu:ModifyAll'] = array ('label' => Dict::S('UI:Menu:ModifyAll'), 'url' => "{$sRootUrl}pages/$sUIPage?operation=select_for_modify_all&class=$sClass&filter=".urlencode($sFilter)."{$sContext}"); }
|
||||
if ($bIsBulkDeleteAllowed) { $aActions['UI:Menu:BulkDelete'] = array ('label' => Dict::S('UI:Menu:BulkDelete'), 'url' => "{$sRootUrl}pages/$sUIPage?operation=select_for_deletion&filter=".urlencode($sFilter)."{$sContext}"); }
|
||||
|
||||
// Stimuli
|
||||
$aStates = MetaModel::EnumStates($sClass);
|
||||
if (count($aStates) > 0)
|
||||
// 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)))
|
||||
{
|
||||
// Life cycle actions may be available... if all objects are in the same state
|
||||
$oSet->Rewind();
|
||||
@@ -1146,7 +1209,7 @@ class MenuBlock extends DisplayBlock
|
||||
{
|
||||
case UR_ALLOWED_YES:
|
||||
case UR_ALLOWED_DEPENDS:
|
||||
$aActions[] = array('label' => $aStimuli[$sStimulusCode]->GetLabel(), 'url' => "../pages/UI.php?operation=select_bulk_stimulus&stimulus=$sStimulusCode&state=$sState&class=$sClass&filter=$sFilter&$sContext");
|
||||
$aActions[$sStimulusCode] = array('label' => $aStimuli[$sStimulusCode]->GetLabel(), 'url' => "{$sRootUrl}pages/UI.php?operation=select_bulk_stimulus&stimulus=$sStimulusCode&state=$sState&class=$sClass&filter=".urlencode($sFilter)."{$sContext}");
|
||||
break;
|
||||
|
||||
default:
|
||||
@@ -1157,8 +1220,9 @@ class MenuBlock extends DisplayBlock
|
||||
}
|
||||
}
|
||||
$this->AddMenuSeparator($aActions);
|
||||
$aActions[] = array ('label' => Dict::S('UI:Menu:EMail'), 'url' => "mailto:?subject=".$oSet->GetFilter()->__DescribeHTML()."&body=".urlencode("$sUrl?operation=search&filter=$sFilter&$sContext"));
|
||||
$aActions[] = array ('label' => Dict::S('UI:Menu:CSVExport'), 'url' => "../pages/$sUIPage?operation=search&filter=$sFilter&format=csv&$sContext");
|
||||
$sUrl = utils::GetAbsoluteUrlAppRoot();
|
||||
$aActions['UI:Menu:EMail'] = array ('label' => Dict::S('UI:Menu:EMail'), 'url' => "mailto:?subject=$sFilterDesc&body=".urlencode("{$sUrl}pages/$sUIPage?operation=search&filter=".urlencode($sFilter)."{$sContext}"));
|
||||
$aActions['UI:Menu:CSVExport'] = array ('label' => Dict::S('UI:Menu:CSVExport'), 'url' => "{$sRootUrl}pages/$sUIPage?operation=search&filter=".urlencode($sFilter)."&format=csv{$sContext}");
|
||||
}
|
||||
$this->AddMenuSeparator($aActions);
|
||||
foreach (MetaModel::EnumPlugins('iApplicationUIExtension') as $oExtensionInstance)
|
||||
@@ -1166,24 +1230,67 @@ class MenuBlock extends DisplayBlock
|
||||
$oSet->Rewind();
|
||||
foreach($oExtensionInstance->EnumAllowedActions($oSet) as $sLabel => $sUrl)
|
||||
{
|
||||
$aActions[] = array ('label' => $sLabel, 'url' => $sUrl);
|
||||
$aActions[$sLabel] = array ('label' => $sLabel, 'url' => $sUrl);
|
||||
}
|
||||
}
|
||||
}
|
||||
$sHtml .= "<div class=\"itop_popup\"><ul>\n<li>".Dict::S('UI:Menu:Actions')."\n<ul>\n";
|
||||
foreach ($aActions as $aAction)
|
||||
$aFavoriteActions = array();
|
||||
$aCallSpec = array($sClass, 'GetShortcutActions');
|
||||
if (is_callable($aCallSpec))
|
||||
{
|
||||
$sClass = isset($aAction['class']) ? " class=\"{$aAction['class']}\"" : "";
|
||||
if (empty($aAction['url']))
|
||||
$aShortcutActions = call_user_func($aCallSpec, $sClass);
|
||||
foreach ($aActions as $key => $aAction)
|
||||
{
|
||||
$sHtml .= "<li>{$aAction['label']}</li>\n";
|
||||
if (in_array($key, $aShortcutActions))
|
||||
{
|
||||
$aFavoriteActions[] = $aAction;
|
||||
unset($aActions[$key]);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$aShortcutActions = array();
|
||||
}
|
||||
|
||||
if (count($aFavoriteActions) > 0)
|
||||
{
|
||||
$sHtml .= "<div class=\"itop_popup\"><ul>\n<li>".Dict::S('UI:Menu:OtherActions')."\n<ul>\n";
|
||||
}
|
||||
else
|
||||
{
|
||||
$sHtml .= "<div class=\"itop_popup\"><ul>\n<li>".Dict::S('UI:Menu:Actions')."\n<ul>\n";
|
||||
}
|
||||
$sPrevUrl = '';
|
||||
foreach ($aActions as $key => $aAction)
|
||||
{
|
||||
if (in_array($key, $aShortcutActions))
|
||||
{
|
||||
$aFavoriteActions[] = $aAction;
|
||||
}
|
||||
else
|
||||
{
|
||||
$sHtml .= "<li><a href=\"{$aAction['url']}\"$sClass>{$aAction['label']}</a></li>\n";
|
||||
$sClass = isset($aAction['class']) ? " class=\"{$aAction['class']}\"" : "";
|
||||
if (empty($aAction['url']))
|
||||
{
|
||||
if ($sPrevUrl != '') // Don't output consecutively two separators...
|
||||
{
|
||||
$sHtml .= "<li>{$aAction['label']}</li>\n";
|
||||
}
|
||||
$sPrevUrl = '';
|
||||
}
|
||||
else
|
||||
{
|
||||
$sHtml .= "<li><a href=\"{$aAction['url']}\"$sClass>{$aAction['label']}</a></li>\n";
|
||||
$sPrevUrl = $aAction['url'];
|
||||
}
|
||||
}
|
||||
}
|
||||
$sHtml .= "</ul>\n</li>\n</ul></div>\n";
|
||||
$sHtml .= "</ul>\n</li>\n</ul></div>";
|
||||
foreach(array_reverse($aFavoriteActions) as $aAction)
|
||||
{
|
||||
$sHtml .= "<div class=\"actions_button\"><a href='{$aAction['url']}'>{$aAction['label']}</a></div>";
|
||||
}
|
||||
static $bPopupScript = false;
|
||||
if (!$bPopupScript)
|
||||
{
|
||||
@@ -1204,9 +1311,11 @@ class MenuBlock extends DisplayBlock
|
||||
$sSeparator = '<hr class="menu-separator"/>';
|
||||
if (count($aActions) > 0) // Make sure that the separator is not the first item in the menu
|
||||
{
|
||||
if ($aActions[count($aActions)-1]['label'] != $sSeparator) // Make sure there are no 2 consecutive separators
|
||||
$aKeys = array_keys($aActions);
|
||||
$sLastKey = array_pop($aKeys);
|
||||
if ($aActions[$sLastKey]['label'] != $sSeparator) // Make sure there are no 2 consecutive separators
|
||||
{
|
||||
$aActions[] = array('label' => $sSeparator, 'url' => '');
|
||||
$aActions['sep_'.(count($aActions)-1)] = array('label' => $sSeparator, 'url' => '');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,32 +39,33 @@ class iTopWebPage extends NiceWebPage
|
||||
private $m_sMessage;
|
||||
private $m_sInitScript;
|
||||
|
||||
public function __construct($sTitle)
|
||||
{
|
||||
parent::__construct($sTitle);
|
||||
$this->m_sCurrentTabContainer = '';
|
||||
$this->m_sCurrentTab = '';
|
||||
public function __construct($sTitle)
|
||||
{
|
||||
parent::__construct($sTitle);
|
||||
|
||||
ApplicationContext::SetUrlMakerClass('iTopStandardURLMaker');
|
||||
|
||||
$this->m_sCurrentTabContainer = '';
|
||||
$this->m_sCurrentTab = '';
|
||||
$this->m_aTabs = array();
|
||||
$this->m_sMenu = "";
|
||||
$this->m_sMessage = '';
|
||||
$sAbsURLAppRoot = addslashes(utils::GetAbsoluteUrlAppRoot()); // Pass it to Javascript scripts
|
||||
$oAppContext = new ApplicationContext();
|
||||
$sExtraParams = $oAppContext->GetForLink();
|
||||
// $this->m_currentOrganization = $currentOrganization;
|
||||
$sAppContext = addslashes($sExtraParams);
|
||||
$this->add_header("Content-type: text/html; charset=utf-8");
|
||||
$this->add_header("Cache-control: no-cache");
|
||||
$this->add_linked_stylesheet("../css/jquery.treeview.css");
|
||||
$this->add_linked_stylesheet("../css/jquery.autocomplete.css");
|
||||
// $this->add_linked_stylesheet("../css/date.picker.css");
|
||||
$this->add_linked_script('../js/jquery.layout.min.js');
|
||||
$this->add_linked_script('../js/jquery.ba-bbq.min.js');
|
||||
// $this->add_linked_script("../js/jquery.dimensions.js");
|
||||
$this->add_linked_script("../js/jquery.tablehover.js");
|
||||
$this->add_linked_script("../js/jquery.treeview.js");
|
||||
$this->add_linked_script("../js/jquery.autocomplete.js");
|
||||
$this->add_linked_script("../js/jquery.positionBy.js");
|
||||
$this->add_linked_script("../js/jquery.popupmenu.js");
|
||||
$this->add_linked_script("../js/date.js");
|
||||
// $this->add_linked_script("../js/jquery.date.picker.js");
|
||||
$this->add_linked_script("../js/jquery.tablesorter.min.js");
|
||||
$this->add_linked_script("../js/jquery.blockUI.js");
|
||||
$this->add_linked_script("../js/utils.js");
|
||||
@@ -72,6 +73,7 @@ class iTopWebPage extends NiceWebPage
|
||||
$this->add_linked_script("../js/ckeditor/ckeditor.js");
|
||||
$this->add_linked_script("../js/ckeditor/adapters/jquery.js");
|
||||
$this->add_linked_script("../js/jquery.qtip-1.0.min.js");
|
||||
$this->add_linked_script("../js/jquery.tablesorter.pager.js");
|
||||
$this->m_sInitScript =
|
||||
<<< EOF
|
||||
try
|
||||
@@ -144,7 +146,12 @@ class iTopWebPage extends NiceWebPage
|
||||
// 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' });
|
||||
tabs.tabs({ event: 'change', 'show': function(event, ui) {
|
||||
$('.resizable', ui.panel).resizable(); // Make resizable everything that claims to be resizable !
|
||||
}
|
||||
});
|
||||
|
||||
$('.resizable').filter(':visible').resizable();
|
||||
}
|
||||
catch(err)
|
||||
{
|
||||
@@ -196,7 +203,6 @@ EOF
|
||||
}
|
||||
});
|
||||
|
||||
$('.resizable').resizable(); // Make resizable everything that claims to be resizable !
|
||||
// Adjust initial size
|
||||
$('.v-resizable').each( function()
|
||||
{
|
||||
@@ -286,26 +292,22 @@ EOF
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
// Shortcut menu actions
|
||||
$('.actions_button a').click( function() {
|
||||
aMatches = /#(.*)$/.exec(window.location.href);
|
||||
if (aMatches != null)
|
||||
{
|
||||
currentHash = aMatches[1];
|
||||
if ( /#(.*)$/.test(this.href))
|
||||
{
|
||||
this.href = this.href.replace(/#(.*)$/, '#'+currentHash);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// End of Tabs handling
|
||||
$("table.listResults").tableHover(); // hover tables
|
||||
// Check each 'listResults' table for a checkbox in the first column and make the first column sortable only if it does not contain a checkbox in the header
|
||||
$(".listResults").each( function()
|
||||
{
|
||||
var table = $(this);
|
||||
var id = $(this).parent();
|
||||
var checkbox = (table.find('th:first :checkbox').length > 0);
|
||||
if (checkbox)
|
||||
{
|
||||
// There is a checkbox in the first column, don't make it sortable
|
||||
table.tablesorter( { headers: { 0: {sorter: false}}, widgets: ['myZebra', 'truncatedList']} ); // sortable and zebra tables
|
||||
}
|
||||
else
|
||||
{
|
||||
// There is NO checkbox in the first column, all columns are considered sortable
|
||||
table.tablesorter( { widgets: ['myZebra', 'truncatedList']} ); // sortable and zebra tables
|
||||
}
|
||||
});
|
||||
$(".date-pick").datepicker({
|
||||
showOn: 'button',
|
||||
buttonImage: '../images/calendar.png',
|
||||
@@ -368,10 +370,6 @@ EOF
|
||||
// }
|
||||
// }
|
||||
|
||||
function formatItem(row) {
|
||||
return row[0];
|
||||
}
|
||||
|
||||
function goBack()
|
||||
{
|
||||
window.history.back();
|
||||
@@ -379,22 +377,23 @@ EOF
|
||||
|
||||
function BackToDetails(sClass, id, sDefaultUrl)
|
||||
{
|
||||
window.bInCancel = true;
|
||||
if (id > 0)
|
||||
{
|
||||
window.location.href = './UI.php?operation=details&class='+sClass+'&id='+id;
|
||||
window.location.href = AddAppContext(GetAbsoluteUrlAppRoot()+'pages/UI.php?operation=details&class='+sClass+'&id='+id);
|
||||
}
|
||||
else
|
||||
{
|
||||
window.location.href = sDefaultUrl;
|
||||
window.location.href = sDefaultUrl; // Already contains the context...
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function BackToList(sClass)
|
||||
{
|
||||
window.location.href = './UI.php?operation=search_oql&oql_class='+sClass+'&oql_clause=WHERE id=0';
|
||||
window.location.href = AddAppContext(GetAbsoluteUrlAppRoot()+'pages/UI.php?operation=search_oql&oql_class='+sClass+'&oql_clause=WHERE id=0');
|
||||
}
|
||||
|
||||
|
||||
function ShowDebug()
|
||||
{
|
||||
if ($('#rawOutput > div').html() != '')
|
||||
@@ -403,6 +402,30 @@ EOF
|
||||
}
|
||||
}
|
||||
|
||||
function GetAbsoluteUrlAppRoot()
|
||||
{
|
||||
return '$sAbsURLAppRoot';
|
||||
}
|
||||
|
||||
function GetAbsoluteUrlModulesRoot()
|
||||
{
|
||||
return '$sAbsURLAppRoot'+'modules/';
|
||||
}
|
||||
|
||||
function AddAppContext(sURL)
|
||||
{
|
||||
var sContext = '$sAppContext';
|
||||
if (sContext.length > 0)
|
||||
{
|
||||
if (sURL.indexOf('?') == -1)
|
||||
{
|
||||
return sURL+'?'+sContext;
|
||||
}
|
||||
return sURL+'&'+sContext;
|
||||
}
|
||||
return sURL;
|
||||
}
|
||||
|
||||
var oUserPreferences = $sUserPrefs;
|
||||
|
||||
// For disabling the CKEditor at init time when the corresponding textarea is disabled !
|
||||
@@ -443,11 +466,22 @@ EOF
|
||||
{
|
||||
// List of visible Organizations
|
||||
$iCount = 0;
|
||||
$oSet = null;
|
||||
if (MetaModel::IsValidClass('Organization'))
|
||||
{
|
||||
// Display the list of *favorite* organizations... but keeping in mind what is the real number of organizations
|
||||
$aFavoriteOrgs = appUserPreferences::GetPref('favorite_orgs', null);
|
||||
$oSearchFilter = new DBObjectSearch('Organization');
|
||||
$oSet = new CMDBObjectSet($oSearchFilter);
|
||||
$iCount = $oSet->Count();
|
||||
$iCount = $oSet->Count(); // total number of existing Orgs
|
||||
|
||||
// Now get the list of Orgs to be displayed in the menu
|
||||
$oSearchFilter = DBObjectSearch::FromOQL(ApplicationMenu::GetFavoriteSiloQuery());
|
||||
if (!empty($aFavoriteOrgs))
|
||||
{
|
||||
$oSearchFilter->AddCondition('id', $aFavoriteOrgs, 'IN');
|
||||
}
|
||||
$oSet = new CMDBObjectSet($oSearchFilter); // List of favorite orgs
|
||||
}
|
||||
switch($iCount)
|
||||
{
|
||||
@@ -464,10 +498,12 @@ EOF
|
||||
break;
|
||||
|
||||
default:
|
||||
$sHtml = '';
|
||||
$oAppContext = new ApplicationContext();
|
||||
$iCurrentOrganization = $oAppContext->GetCurrentValue('org_id');
|
||||
$sHtml = '<div id="SiloSelection">';
|
||||
$sHtml .= '<form style="display:inline" action="'.$_SERVER['PHP_SELF'].'"><select class="org_combo" name="c[org_id]" title="Pick an organization" onChange="this.form.submit();">';
|
||||
$sHtml .= '<form style="display:inline" action="'.utils::GetAbsoluteUrlAppRoot().'pages/UI.php">'; //<select class="org_combo" name="c[org_id]" title="Pick an organization" onChange="this.form.submit();">';
|
||||
/*
|
||||
$sSelected = ($iCurrentOrganization == '') ? ' selected' : '';
|
||||
$sHtml .= '<option value=""'.$sSelected.'>'.Dict::S('UI:AllOrganizations').'</option>';
|
||||
while($oOrg = $oSet->Fetch())
|
||||
@@ -485,10 +521,16 @@ EOF
|
||||
$sHtml .= '<option title="'.$oOrg->GetName().'" value="'.$oOrg->GetKey().'"'.$sSelected.'>'.$oOrg->GetName().'</option>';
|
||||
}
|
||||
$sHtml .= '</select>';
|
||||
*/
|
||||
$sFavoriteOrgs = '';
|
||||
$oWidget = new UIExtKeyWidget('Organization', 'org_id');
|
||||
$sHtml .= $oWidget->Display($this, 50, false, '', $oSet, $iCurrentOrganization, 'org_id', false, 'c[org_id]', '', array('iFieldSize' => 20, 'iMinChars' => MetaModel::GetConfig()->Get('min_autocomplete_chars'), 'sDefaultValue' => Dict::S('UI:AllOrganizations')), $bSearchMode = true);
|
||||
$this->add_ready_script('$("#org_id").bind("extkeychange", function() { $("#SiloSelection form").submit(); } )');
|
||||
$this->add_ready_script("$('#label_org_id').click( function() { $(this).val(''); $('#org_id').val(''); return true; } );\n");
|
||||
// Add other dimensions/context information to this form
|
||||
// $oAppContext = new ApplicationContext();
|
||||
$oAppContext->Reset('org_id'); // org_id is handled above and we want to be able to change it here !
|
||||
$sHtml .= $oAppContext->GetForForm();
|
||||
$oAppContext->Reset('menu'); // don't pass the menu, since a menu may expect more parameters
|
||||
$sHtml .= $oAppContext->GetForForm(); // Pass what remains, if anything...
|
||||
$sHtml .= '</form>';
|
||||
$sHtml .= '</div>';
|
||||
}
|
||||
@@ -509,6 +551,7 @@ EOF
|
||||
*/
|
||||
public function output()
|
||||
{
|
||||
$sForm = $this->GetSiloSelectionForm();
|
||||
$this->DisplayMenu(); // Compute the menu
|
||||
|
||||
// Put here the 'ready scripts' that must be executed after all others
|
||||
@@ -517,6 +560,9 @@ EOF
|
||||
// Since the event is only triggered when the hash changes, we need to trigger
|
||||
// the event now, to handle the hash the page may have loaded with.
|
||||
$(window).trigger( 'hashchange' );
|
||||
|
||||
// Some table are sort-able, some are not, let's fix this
|
||||
$('table.listResults').each( function() { FixTableSorter($(this)); } );
|
||||
|
||||
EOF
|
||||
);
|
||||
@@ -532,7 +578,7 @@ EOF
|
||||
// Make sure that Internet Explorer renders the page using its latest/highest/greatest standards !
|
||||
echo "<meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\" />\n";
|
||||
echo "<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\" />\n";
|
||||
echo "<title>{$this->s_title}</title>\n";
|
||||
echo "<title>".htmlentities($this->s_title, ENT_QUOTES, 'UTF-8')."</title>\n";
|
||||
echo $this->get_base_tag();
|
||||
// Stylesheets MUST be loaded before any scripts otherwise
|
||||
// jQuery scripts may face some spurious problems (like failing on a 'reload')
|
||||
@@ -552,13 +598,13 @@ EOF
|
||||
{
|
||||
// Make sure that the URL to the script contains the application's version number
|
||||
// so that the new script do NOT get reloaded from the cache when the application is upgraded
|
||||
if (strpos('?', $s_script) === false)
|
||||
if (strpos($s_script, '?') === false)
|
||||
{
|
||||
$s_script .= "?version=".ITOP_VERSION;
|
||||
$s_script .= "?itopversion=".ITOP_VERSION;
|
||||
}
|
||||
else
|
||||
{
|
||||
$s_script .= "&version=".ITOP_VERSION;
|
||||
$s_script .= "&itopversion=".ITOP_VERSION;
|
||||
}
|
||||
echo "<script type=\"text/javascript\" src=\"$s_script\"></script>\n";
|
||||
}
|
||||
@@ -586,7 +632,9 @@ EOF
|
||||
}
|
||||
echo "</style>\n";
|
||||
}
|
||||
echo "<link rel=\"search\" type=\"application/opensearchdescription+xml\" title=\"iTop\" href=\"./opensearch.xml.php\" />\n";
|
||||
echo "<link rel=\"search\" type=\"application/opensearchdescription+xml\" title=\"iTop\" href=\"".utils::GetAbsoluteUrlAppRoot()."pages/opensearch.xml.php\" />\n";
|
||||
echo "<link rel=\"shortcut icon\" href=\"".utils::GetAbsoluteUrlAppRoot()."images/favicon.ico\" />\n";
|
||||
|
||||
echo "</head>\n";
|
||||
echo "<body>\n";
|
||||
|
||||
@@ -596,7 +644,6 @@ EOF
|
||||
|
||||
|
||||
|
||||
|
||||
// Render the revision number
|
||||
if (ITOP_REVISION == '$WCREV$')
|
||||
{
|
||||
@@ -610,7 +657,7 @@ EOF
|
||||
}
|
||||
|
||||
// Render the text of the global search form
|
||||
$sText = Utils::ReadParam('text', '');
|
||||
$sText = htmlentities(utils::ReadParam('text', '', false, 'raw_data'), ENT_QUOTES, 'UTF-8');
|
||||
$sOnClick = "";
|
||||
if (empty($sText))
|
||||
{
|
||||
@@ -619,10 +666,7 @@ EOF
|
||||
// 2) clicking on it will erase it
|
||||
$sText = Dict::S("UI:YourSearch");
|
||||
$sOnClick = " onclick=\"this.value='';this.onclick=null;\"";
|
||||
}
|
||||
|
||||
$sForm = $this->GetSiloSelectionForm();
|
||||
|
||||
}
|
||||
// Render the tabs in the page (if any)
|
||||
foreach($this->m_aTabs as $sTabContainerName => $m_aTabs)
|
||||
{
|
||||
@@ -664,15 +708,16 @@ EOF
|
||||
}
|
||||
$sLogOffMenu = "<span id=\"logOffBtn\"><ul><li><img src=\"../images/onOffBtn.png\"><ul>";
|
||||
$sLogOffMenu .= "<li><span>$sLogonMessage</span></li>\n";
|
||||
$sLogOffMenu .= "<li><a href=\"".utils::GetAbsoluteUrlAppRoot()."pages/preferences.php\">".Dict::S('UI:Preferences')."</a></li>\n";
|
||||
|
||||
if (utils::CanLogOff() && UserRights::CanLogOff())
|
||||
if (utils::CanLogOff())
|
||||
{
|
||||
//$sLogOffMenu .= "<li><a href=\"../pages/UI.php?loginop=logoff\">".Dict::S('UI:LogOffMenu')."</a></li>\n";
|
||||
$sLogOffMenu .= "<li><a href=\"../pages/logoff.php\">".Dict::S('UI:LogOffMenu')."</a></li>\n";
|
||||
$sLogOffMenu .= "<li><a href=\"".utils::GetAbsoluteUrlAppRoot()."pages/logoff.php\">".Dict::S('UI:LogOffMenu')."</a></li>\n";
|
||||
}
|
||||
if (UserRights::CanChangePassword())
|
||||
{
|
||||
$sLogOffMenu .= "<li><a href=\"../pages/UI.php?loginop=change_pwd\">".Dict::S('UI:ChangePwdMenu')."</a></li>\n";
|
||||
$sLogOffMenu .= "<li><a href=\"".utils::GetAbsoluteUrlAppRoot()."pages/UI.php?loginop=change_pwd\">".Dict::S('UI:ChangePwdMenu')."</a></li>\n";
|
||||
}
|
||||
$sLogOffMenu .= "</ul>\n</li>\n</ul></span>\n";
|
||||
|
||||
@@ -716,16 +761,16 @@ EOF
|
||||
echo '<div id="left-pane" class="ui-layout-west">';
|
||||
echo '<!-- Beginning of the left pane -->';
|
||||
echo ' <div id="header-logo">';
|
||||
echo ' <div id="top-left"></div><div id="logo"><a href="http://www.combodo.com/itop"><img src="../images/itop-logo.png" title="'.$sVersionString.'" style="border:0; margin-top:16px; margin-right:40px;"/></a></div>';
|
||||
echo ' <div id="top-left"></div><div id="logo"><a href="http://www.combodo.com/itop"><img src="../images/itop-logo.png" title="'.htmlentities($sVersionString, ENT_QUOTES, 'UTF-8').'" style="border:0; margin-top:16px; margin-right:40px;"/></a></div>';
|
||||
echo ' </div>';
|
||||
echo ' <div class="header-menu">';
|
||||
echo ' <div class="icon ui-state-default ui-corner-all"><span id="tPinMenu" class="ui-icon ui-icon-pin-w">pin</span></div>';
|
||||
echo ' <div style="text-align:center;">'.$sForm.'</div>';
|
||||
echo ' <div style="text-align:center;">'.self::FilterXSS($sForm).'</div>';
|
||||
echo ' </div>';
|
||||
echo ' <div id="menu" class="ui-layout-content">';
|
||||
echo ' <div id="inner_menu">';
|
||||
echo ' <div id="accordion">';
|
||||
echo $this->m_sMenu;
|
||||
echo self::FilterXSS($this->m_sMenu);
|
||||
echo ' <!-- Beginning of the accordion menu -->';
|
||||
echo ' <!-- End of the accordion menu-->';
|
||||
echo ' </div>';
|
||||
@@ -737,74 +782,26 @@ EOF
|
||||
|
||||
echo '<div class="ui-layout-center">';
|
||||
echo ' <div id="top-bar" style="width:100%">';
|
||||
echo $sApplicationBanner;
|
||||
echo ' <div id="global-search"><form action="../pages/UI.php"><table><tr><td></td><td id="g-search-input"><input type="text" name="text" value="'.$sText.'"'.$sOnClick.'/></td>';
|
||||
echo self::FilterXSS($sApplicationBanner);
|
||||
echo ' <div id="global-search"><form action="'.utils::GetAbsoluteUrlAppRoot().'pages/UI.php"><table><tr><td></td><td id="g-search-input"><input type="text" name="text" value="'.$sText.'"'.$sOnClick.'/></td>';
|
||||
echo '<td><input type="image" src="../images/searchBtn.png"/></a></td>';
|
||||
echo '<td><a style="background:transparent;" href="'.$sOnlineHelpUrl.'" target="_blank"><img style="border:0;padding-left:20px;padding-right:10px;" title="'.Dict::S('UI:Help').'" src="../images/help.png"/></td>';
|
||||
echo '<td style="padding-right:20px;padding-left:10px;">'.$sLogOffMenu.'</td><td><input type="hidden" name="operation" value="full_text"/></td></tr></table></form></div>';
|
||||
echo '<td style="padding-right:20px;padding-left:10px;">'.self::FilterXSS($sLogOffMenu).'</td><td><input type="hidden" name="operation" value="full_text"/></td></tr></table></form></div>';
|
||||
//echo '<td> <input type="hidden" name="operation" value="full_text"/></td></tr></table></form></div>';
|
||||
echo ' </div>';
|
||||
echo ' <div class="ui-layout-content">';
|
||||
echo ' <!-- Beginning of page content -->';
|
||||
echo $this->s_content;
|
||||
echo self::FilterXSS($this->s_content);
|
||||
echo ' <!-- End of page content -->';
|
||||
echo ' </div>';
|
||||
echo '</div>';
|
||||
/*
|
||||
echo "<div class=\"iTopLogo\" title=\"$sVersionString\"><span>iTop</span></div>\n";
|
||||
//echo "<div id=\"GlobalSearch\"><div style=\"border: 1px solid #999; padding:1px; background-color:#fff;\"><img src=\"../images/magnifier.gif\"/><input style=\"border:0\" type=\"text\" size=\"15\" title=\"Global Search\"></input></div></div>\n";
|
||||
$sText = Utils::ReadParam('text', '');
|
||||
$sOnClick = "";
|
||||
if (empty($sText))
|
||||
{
|
||||
// if no search text is supplied then
|
||||
// 1) the search text is filled with "your search"
|
||||
// 2) clicking on it will erase it
|
||||
$sText = Dict::S("UI:YourSearch");
|
||||
$sOnClick = " onclick=\"this.value='';this.onclick=null;\"";
|
||||
}
|
||||
$sUserName = UserRights::GetUser();
|
||||
$sIsAdmin = UserRights::IsAdministrator() ? '(Administrator)' : '';
|
||||
if (UserRights::IsAdministrator())
|
||||
{
|
||||
$sLogonMessage = Dict::Format('UI:LoggedAsMessage+Admin', $sUserName);
|
||||
}
|
||||
else
|
||||
{
|
||||
$sLogonMessage = Dict::Format('UI:LoggedAsMessage', $sUserName);
|
||||
}
|
||||
$sLogOffBtn = Dict::S('UI:Button:Logoff');
|
||||
$sSearchBtn = Dict::S('UI:Button:GlobalSearch');
|
||||
echo "<div id=\"Login\" style=\"position:absolute; top:18px; right:16px; width:600px;\">{$sLogonMessage} ";
|
||||
echo "<form action=\"../pages/UI.php\" method=\"post\" style=\"display:inline\">\n";
|
||||
echo "<input type=\"submit\" value=\"$sLogOffBtn\" />\n";
|
||||
echo "<input type=\"hidden\" name=\"loginop\" value=\"logoff\" />\n";
|
||||
echo "</form>\n";
|
||||
echo "<form action=\"../pages/UI.php\" style=\"display:inline\"><div style=\"padding:1px; background-color:#fff;display:inline;\"><img src=\"../images/magnifier.gif\"/><input style=\"border:0\" type=\"text\" size=\"15\" title=\"Global Search\" name=\"text\" value=\"$sText\"$sOnClick></input></div><input type=\"submit\" value=\"$sSearchBtn\" />
|
||||
<input type=\"hidden\" name=\"operation\" value=\"full_text\" /></form>\n";
|
||||
echo "</div>\n";
|
||||
|
||||
echo "</div>\n";
|
||||
|
||||
// Display the menu
|
||||
echo "<div id=\"MySplitter\">\n";
|
||||
echo " <div id=\"LeftPane\">\n";
|
||||
echo $this->m_sMenu;
|
||||
echo " </div> <!-- LeftPane -->\n";
|
||||
|
||||
echo "<div id=\"RightPane\">\n";
|
||||
|
||||
|
||||
// Display the page's content
|
||||
echo $this->s_content;
|
||||
|
||||
*/
|
||||
// Add the captured output
|
||||
if (trim($s_captured_output) != "")
|
||||
{
|
||||
echo "<div id=\"rawOutput\" title=\"Debug Output\"><div style=\"height:500px; overflow-y:auto;\">$s_captured_output</div></div>\n";
|
||||
echo "<div id=\"rawOutput\" title=\"Debug Output\"><div style=\"height:500px; overflow-y:auto;\">".self::FilterXSS($s_captured_output)."</div></div>\n";
|
||||
}
|
||||
echo "<div id=\"at_the_end\">".$this->s_deferred_content."</div>";
|
||||
echo "<div id=\"at_the_end\">".self::FilterXSS($this->s_deferred_content)."</div>";
|
||||
// echo $this->s_deferred_content;
|
||||
echo "<div style=\"display:none\" title=\"ex2\" id=\"ex2\">Please wait...</div>\n"; // jqModal Window
|
||||
echo "<div style=\"display:none\" title=\"dialog\" id=\"ModalDlg\"></div>";
|
||||
@@ -848,6 +845,11 @@ EOF
|
||||
return $sPreviousTab;
|
||||
}
|
||||
|
||||
public function GetCurrentTab()
|
||||
{
|
||||
return $this->m_sCurrentTab;
|
||||
}
|
||||
|
||||
/**
|
||||
* Make the given tab the active one, as if it were clicked
|
||||
* DOES NOT WORK: apparently in the *old* version of jquery
|
||||
@@ -919,6 +921,50 @@ EOF
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Records the current state of the 'html' part of the page output
|
||||
* @return mixed The current state of the 'html' output
|
||||
*/
|
||||
public function start_capture()
|
||||
{
|
||||
if (!empty($this->m_sCurrentTabContainer) && !empty($this->m_sCurrentTab))
|
||||
{
|
||||
$iOffset = isset($this->m_aTabs[$this->m_sCurrentTabContainer][$this->m_sCurrentTab]) ? strlen($this->m_aTabs[$this->m_sCurrentTabContainer][$this->m_sCurrentTab]): 0;
|
||||
return array('tc' => $this->m_sCurrentTabContainer, 'tab' => $this->m_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 (isset($this->m_aTabs[$offset['tc']][$offset['tab']]))
|
||||
{
|
||||
$sCaptured = substr($this->m_aTabs[$offset['tc']][$offset['tab']], $offset['offset']);
|
||||
$this->m_aTabs[$offset['tc']][$offset['tab']] = substr($this->m_aTabs[$offset['tc']][$offset['tab']], 0, $offset['offset']);
|
||||
}
|
||||
else
|
||||
{
|
||||
$sCaptured = '';
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$sCaptured = parent::end_capture($offset);
|
||||
}
|
||||
return $sCaptured;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the message to be displayed in the 'admin-banner' section at the top of the page
|
||||
*/
|
||||
|
||||
@@ -48,7 +48,7 @@ class iTopWizardWebPage extends iTopWebPage
|
||||
$sStyle = ($iIndex == $this->m_iCurrentStep) ? 'wizActiveStep' : 'wizStep';
|
||||
$aSteps[] = "<div class=\"$sStyle\"><span>$sStepTitle</span></div>";
|
||||
}
|
||||
$sWizardHeader = "<div class=\"wizHeader\"><h1>{$this->s_title}</h1>\n".implode("<div class=\"wizSeparator\"><img align=\"bottom\" src=\"../images/wizArrow.gif\"></div>", $aSteps)."<br style=\"clear:both;\"/></div>\n";
|
||||
$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();
|
||||
}
|
||||
|
||||
@@ -27,8 +27,11 @@ require_once(APPROOT."/application/nicewebpage.class.inc.php");
|
||||
/**
|
||||
* Web page used for displaying the login form
|
||||
*/
|
||||
|
||||
class LoginWebPage extends NiceWebPage
|
||||
{
|
||||
protected static $m_sLoginFailedMessage = '';
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct("iTop Login");
|
||||
@@ -88,10 +91,21 @@ EOF
|
||||
);
|
||||
}
|
||||
|
||||
public static function SetLoginFailedMessage($sMessage)
|
||||
{
|
||||
self::$m_sLoginFailedMessage = $sMessage;
|
||||
}
|
||||
|
||||
public function DisplayLoginForm($sLoginType, $bFailedLogin = false)
|
||||
{
|
||||
switch($sLoginType)
|
||||
{
|
||||
case 'cas':
|
||||
utils::InitCASClient();
|
||||
// force CAS authentication
|
||||
phpCAS::forceAuthentication(); // Will redirect the user and exit since the user is not yet authenticated
|
||||
break;
|
||||
|
||||
case 'basic':
|
||||
case 'url':
|
||||
$this->add_header('WWW-Authenticate: Basic realm="'.Dict::Format('UI:iTopVersion:Short', ITOP_VERSION));
|
||||
@@ -103,8 +117,8 @@ EOF
|
||||
case 'external':
|
||||
case 'form':
|
||||
default: // In case the settings get messed up...
|
||||
$sAuthUser = utils::ReadParam('auth_user', '');
|
||||
$sAuthPwd = utils::ReadParam('suggest_pwd', '');
|
||||
$sAuthUser = utils::ReadParam('auth_user', '', true, 'raw_data');
|
||||
$sAuthPwd = utils::ReadParam('suggest_pwd', '', true, 'raw_data');
|
||||
|
||||
$sVersionShort = Dict::Format('UI:iTopVersion:Short', ITOP_VERSION);
|
||||
$this->add("<div id=\"login-logo\"><a href=\"http://www.combodo.com/itop\"><img title=\"$sVersionShort\" src=\"../images/itop-logo-external.png\"></a></div>\n");
|
||||
@@ -112,7 +126,14 @@ EOF
|
||||
$this->add("<h1>".Dict::S('UI:Login:Welcome')."</h1>\n");
|
||||
if ($bFailedLogin)
|
||||
{
|
||||
$this->add("<p class=\"hilite\">".Dict::S('UI:Login:IncorrectLoginPassword')."</p>\n");
|
||||
if (self::$m_sLoginFailedMessage != '')
|
||||
{
|
||||
$this->add("<p class=\"hilite\">".self::$m_sLoginFailedMessage."</p>\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->add("<p class=\"hilite\">".Dict::S('UI:Login:IncorrectLoginPassword')."</p>\n");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -120,12 +141,13 @@ EOF
|
||||
}
|
||||
$this->add("<form method=\"post\">\n");
|
||||
$this->add("<table width=\"100%\">\n");
|
||||
$this->add("<tr><td style=\"text-align:right\"><label for=\"user\">".Dict::S('UI:Login:UserNamePrompt').":</label></td><td style=\"text-align:left\"><input id=\"user\" type=\"text\" name=\"auth_user\" value=\"$sAuthUser\" /></td></tr>\n");
|
||||
$this->add("<tr><td style=\"text-align:right\"><label for=\"pwd\">".Dict::S('UI:Login:PasswordPrompt').":</label></td><td style=\"text-align:left\"><input id=\"pwd\" type=\"password\" name=\"auth_pwd\" value=\"$sAuthPwd\" /></td></tr>\n");
|
||||
$this->add("<tr><td style=\"text-align:right\"><label for=\"user\">".Dict::S('UI:Login:UserNamePrompt').":</label></td><td style=\"text-align:left\"><input id=\"user\" type=\"text\" name=\"auth_user\" value=\"".htmlentities($sAuthUser, ENT_QUOTES, 'UTF-8')."\" /></td></tr>\n");
|
||||
$this->add("<tr><td style=\"text-align:right\"><label for=\"pwd\">".Dict::S('UI:Login:PasswordPrompt').":</label></td><td style=\"text-align:left\"><input id=\"pwd\" type=\"password\" name=\"auth_pwd\" value=\"".htmlentities($sAuthPwd, ENT_QUOTES, 'UTF-8')."\" /></td></tr>\n");
|
||||
$this->add("<tr><td colspan=\"2\" class=\"center v-spacer\"> <input type=\"submit\" value=\"".Dict::S('UI:Button:Login')."\" /></td></tr>\n");
|
||||
$this->add("</table>\n");
|
||||
$this->add("<input type=\"hidden\" name=\"loginop\" value=\"login\" />\n");
|
||||
$this->add("</form>\n");
|
||||
$this->add(Dict::S('UI:Login:About'));
|
||||
$this->add("</div>\n");
|
||||
break;
|
||||
}
|
||||
@@ -133,8 +155,7 @@ EOF
|
||||
|
||||
public function DisplayChangePwdForm($bFailedLogin = false)
|
||||
{
|
||||
$sAuthUser = utils::ReadParam('auth_user', '');
|
||||
$sAuthPwd = utils::ReadParam('suggest_pwd', '');
|
||||
$sAuthUser = utils::ReadParam('auth_user', '', false, 'raw_data');
|
||||
|
||||
$sVersionShort = Dict::Format('UI:iTopVersion:Short', ITOP_VERSION);
|
||||
$sInconsistenPwdMsg = Dict::S('UI:Login:RetypePwdDoesNotMatch');
|
||||
@@ -216,10 +237,8 @@ EOF
|
||||
{
|
||||
if (self::SecureConnectionRequired() && !self::IsConnectionSecure())
|
||||
{
|
||||
// Non secured URL... redirect to a secured one
|
||||
$sUrl = Utils::GetAbsoluteUrl(true /* query string */, true /* force HTTPS */);
|
||||
header("Location: $sUrl");
|
||||
exit;
|
||||
// Non secured URL... request for a secure connection
|
||||
throw new Exception('Secure connection required!');
|
||||
}
|
||||
|
||||
$aAllowedLoginTypes = MetaModel::GetConfig()->GetAllowedLoginTypes();
|
||||
@@ -241,10 +260,22 @@ EOF
|
||||
$sLoginType = $aAllowedLoginTypes[$index];
|
||||
switch($sLoginType)
|
||||
{
|
||||
case 'cas':
|
||||
utils::InitCASClient();
|
||||
// check CAS authentication
|
||||
if (phpCAS::isAuthenticated())
|
||||
{
|
||||
$sAuthUser = phpCAS::getUser();
|
||||
$sAuthPwd = '';
|
||||
$sLoginMode = 'cas';
|
||||
$sAuthentication = 'external';
|
||||
}
|
||||
break;
|
||||
|
||||
case 'form':
|
||||
// iTop standard mode: form based authentication
|
||||
$sAuthUser = utils::ReadPostedParam('auth_user', '');
|
||||
$sAuthPwd = utils::ReadPostedParam('auth_pwd', '');
|
||||
$sAuthUser = utils::ReadPostedParam('auth_user', '', false, 'raw_data');
|
||||
$sAuthPwd = utils::ReadPostedParam('auth_pwd', '', false, 'raw_data');
|
||||
if ($sAuthUser != '')
|
||||
{
|
||||
$sLoginMode = 'form';
|
||||
@@ -270,12 +301,10 @@ EOF
|
||||
case 'external':
|
||||
// Web server supplied authentication
|
||||
$bExternalAuth = false;
|
||||
$sExtAuthVar = MetaModel::GetConfig()->GetExternalAuthenticationVariable(); // In which variable is the info passed ?
|
||||
$sEval = '$bExternalAuth = isset('.$sExtAuthVar.');';
|
||||
eval($sEval);
|
||||
if ($bExternalAuth)
|
||||
{
|
||||
eval('$sAuthUser = '.$sExtAuthVar.';'); // Retrieve the value
|
||||
$sExtAuthVar = MetaModel::GetConfig()->GetExternalAuthenticationVariable(); // In which variable is the info passed ?
|
||||
eval('$sAuthUser = isset('.$sExtAuthVar.') ? '.$sExtAuthVar.' : false;'); // Retrieve the value
|
||||
if ($sAuthUser && (strlen($sAuthUser) > 0))
|
||||
{
|
||||
$sAuthPwd = ''; // No password in this case the web server already authentified the user...
|
||||
$sLoginMode = 'external';
|
||||
$sAuthentication = 'external';
|
||||
@@ -284,10 +313,10 @@ EOF
|
||||
|
||||
case 'url':
|
||||
// Credentials passed directly in the url
|
||||
$sAuthUser = utils::ReadParam('auth_user', '');
|
||||
if ($sAuthUser != '')
|
||||
$sAuthUser = utils::ReadParam('auth_user', '', false, 'raw_data');
|
||||
$sAuthPwd = utils::ReadParam('auth_pwd', null, false, 'raw_data');
|
||||
if (($sAuthUser != '') && ($sAuthPwd != null))
|
||||
{
|
||||
$sAuthPwd = utils::ReadParam('auth_pwd', '');
|
||||
$sLoginMode = 'url';
|
||||
}
|
||||
break;
|
||||
@@ -314,8 +343,9 @@ EOF
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!UserRights::CheckCredentials($sAuthUser, $sAuthPwd, $sAuthentication))
|
||||
if (!UserRights::CheckCredentials($sAuthUser, $sAuthPwd, $sLoginMode, $sAuthentication))
|
||||
{
|
||||
//echo "Check Credentials returned false for user $sAuthUser!";
|
||||
self::ResetSession();
|
||||
$oPage = new LoginWebPage();
|
||||
$oPage->DisplayLoginForm( $sLoginMode, true /* failed attempt */);
|
||||
@@ -394,8 +424,8 @@ EOF
|
||||
{
|
||||
$sAuthUser = $_SESSION['auth_user'];
|
||||
UserRights::Login($sAuthUser); // Set the user's language
|
||||
$sOldPwd = utils::ReadPostedParam('old_pwd');
|
||||
$sNewPwd = utils::ReadPostedParam('new_pwd');
|
||||
$sOldPwd = utils::ReadPostedParam('old_pwd', '', false, 'raw_data');
|
||||
$sNewPwd = utils::ReadPostedParam('new_pwd', '', false, 'raw_data');
|
||||
if (UserRights::CanChangePassword() && ((!UserRights::CheckCredentials($sAuthUser, $sOldPwd)) || (!UserRights::ChangePassword($sOldPwd, $sNewPwd))))
|
||||
{
|
||||
$oPage = new LoginWebPage();
|
||||
@@ -412,17 +442,16 @@ EOF
|
||||
require_once(APPROOT.'/setup/setuppage.class.inc.php');
|
||||
$oP = new SetupWebPage(Dict::S('UI:PageTitle:FatalError'));
|
||||
$oP->add("<h1>".Dict::S('UI:Login:Error:AccessAdmin')."</h1>\n");
|
||||
$oP->p("<a href=\"../pages/logoff.php\">".Dict::S('UI:LogOffMenu')."</a>");
|
||||
$oP->p("<a href=\"".utils::GetAbsoluteUrlAppRoot()."pages/logoff.php\">".Dict::S('UI:LogOffMenu')."</a>");
|
||||
$oP->output();
|
||||
exit;
|
||||
}
|
||||
elseif ( (!$bIsAllowedToPortalUsers) && (UserRights::IsPortalUser()))
|
||||
{
|
||||
// No rights to be here, redirect to the portal
|
||||
header('Location: ../portal/index.php');
|
||||
header('Location: '.utils::GetAbsoluteUrlAppRoot().'portal/index.php');
|
||||
}
|
||||
return $sMessage;
|
||||
}
|
||||
|
||||
}
|
||||
} // End of class
|
||||
?>
|
||||
|
||||
@@ -61,6 +61,27 @@ class ApplicationMenu
|
||||
{
|
||||
static $aRootMenus = array();
|
||||
static $aMenusIndex = array();
|
||||
static $sFavoriteSiloQuery = 'SELECT Organization';
|
||||
|
||||
/**
|
||||
* Set the query used to limit the list of displayed organizations in the drop-down menu
|
||||
* @param $sOQL string The OQL query returning a list of Organization objects
|
||||
* @return none
|
||||
*/
|
||||
static public function SetFavoriteSiloQuery($sOQL)
|
||||
{
|
||||
self::$sFavoriteSiloQuery = $sOQL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the query used to limit the list of displayed organizations in the drop-down menu
|
||||
* @return string The OQL query returning a list of Organization objects
|
||||
*/
|
||||
static public function GetFavoriteSiloQuery()
|
||||
{
|
||||
return self::$sFavoriteSiloQuery;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Main function to add a menu entry into the application, can be called during the definition
|
||||
@@ -83,6 +104,11 @@ class ApplicationMenu
|
||||
self::$aMenusIndex[$iParentIndex]['children'][] = array ('rank' => $fRank, 'index' => $index);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// the menu already exists, let's combine the conditions that make it visible
|
||||
self::$aMenusIndex[$index]['node']->AddCondition($oMenuNode);
|
||||
}
|
||||
return $index;
|
||||
}
|
||||
|
||||
@@ -266,22 +292,22 @@ abstract class MenuNode
|
||||
/**
|
||||
* Class of objects to check if the menu is enabled, null if none
|
||||
*/
|
||||
protected $m_sEnableClass;
|
||||
protected $m_aEnableClasses;
|
||||
|
||||
/**
|
||||
* User Rights Action code to check if the menu is enabled, null if none
|
||||
*/
|
||||
protected $m_iEnableAction;
|
||||
protected $m_aEnableActions;
|
||||
|
||||
/**
|
||||
* User Rights allowed results (actually a bitmask) to check if the menu is enabled, null if none
|
||||
*/
|
||||
protected $m_iEnableActionResults;
|
||||
protected $m_aEnableActionResults;
|
||||
|
||||
/**
|
||||
* Stimulus to check: if the user can 'apply' this stimulus, then she/he can see this menu
|
||||
*/
|
||||
protected $m_sEnableStimulus;
|
||||
protected $m_aEnableStimuli;
|
||||
|
||||
/**
|
||||
* Create a menu item, sets the condition to have it displayed and inserts it into the application's main menu
|
||||
@@ -297,10 +323,10 @@ abstract class MenuNode
|
||||
public function __construct($sMenuId, $iParentIndex = -1, $fRank = 0, $sEnableClass = null, $iActionCode = null, $iAllowedResults = UR_ALLOWED_YES, $sEnableStimulus = null)
|
||||
{
|
||||
$this->sMenuId = $sMenuId;
|
||||
$this->m_sEnableClass = $sEnableClass;
|
||||
$this->m_iEnableAction = $iActionCode;
|
||||
$this->m_iEnableActionResults = $iAllowedResults;
|
||||
$this->m_sEnableStimulus = $sEnableStimulus;
|
||||
$this->m_aEnableClasses = array($sEnableClass);
|
||||
$this->m_aEnableActions = array($iActionCode);
|
||||
$this->m_aEnableActionResults = array($iAllowedResults);
|
||||
$this->m_aEnableStimuli = array($sEnableStimulus);
|
||||
$this->index = ApplicationMenu::InsertMenu($this, $iParentIndex, $fRank);
|
||||
}
|
||||
|
||||
@@ -327,41 +353,57 @@ abstract class MenuNode
|
||||
public function GetHyperlink($aExtraParams)
|
||||
{
|
||||
$aExtraParams['c[menu]'] = $this->GetIndex();
|
||||
return $this->AddParams('../pages/UI.php', $aExtraParams);
|
||||
return $this->AddParams(utils::GetAbsoluteUrlAppRoot().'pages/UI.php', $aExtraParams);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a limiting display condition for the same menu node. The conditions will be combined with a AND
|
||||
* @param $oMenuNode MenuNode Another definition of the same menu node, with potentially different access restriction
|
||||
* @return void
|
||||
*/
|
||||
public function AddCondition(MenuNode $oMenuNode)
|
||||
{
|
||||
foreach($oMenuNode->m_aEnableClasses as $index => $sClass )
|
||||
{
|
||||
$this->m_aEnableClasses[] = $sClass;
|
||||
$this->m_aEnableActions[] = $oMenuNode->m_aEnableActions[$index];
|
||||
$this->m_aEnableActionResults[] = $oMenuNode->m_aEnableActionResults[$index];
|
||||
$this->m_aEnableStimuli[] = $oMenuNode->m_aEnableStimuli[$index];
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Tells whether the menu is enabled (i.e. displayed) for the current user
|
||||
* @return bool True if enabled, false otherwise
|
||||
*/
|
||||
public function IsEnabled()
|
||||
{
|
||||
if ($this->m_sEnableClass != null)
|
||||
foreach($this->m_aEnableClasses as $index => $sClass)
|
||||
{
|
||||
if (MetaModel::IsValidClass($this->m_sEnableClass))
|
||||
if ($sClass != null)
|
||||
{
|
||||
if ($this->m_sEnableStimulus != null)
|
||||
if (MetaModel::IsValidClass($sClass))
|
||||
{
|
||||
if (!UserRights::IsStimulusAllowed($this->m_sEnableClass, $this->m_sEnableStimulus))
|
||||
if ($this->m_aEnableStimuli[$index] != null)
|
||||
{
|
||||
return false;
|
||||
if (!UserRights::IsStimulusAllowed($sClass, $this->m_aEnableStimuli[$index]))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if ($this->m_aEnableActions[$index] != null)
|
||||
{
|
||||
$iResult = UserRights::IsActionAllowed($sClass, $this->m_aEnableActions[$index]);
|
||||
if (!($iResult & $this->m_aEnableActionResults[$index]))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
if ($this->m_iEnableAction != null)
|
||||
else
|
||||
{
|
||||
$iResult = UserRights::IsActionAllowed($this->m_sEnableClass, $this->m_iEnableAction);
|
||||
if (($iResult & $this->m_iEnableActionResults))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -652,7 +694,7 @@ class NewObjectMenuNode extends MenuNode
|
||||
|
||||
public function GetHyperlink($aExtraParams)
|
||||
{
|
||||
$sHyperlink = '../pages/UI.php?operation=new&class='.$this->sClass;
|
||||
$sHyperlink = utils::GetAbsoluteUrlAppRoot().'pages/UI.php?operation=new&class='.$this->sClass;
|
||||
$aExtraParams['c[menu]'] = $this->GetIndex();
|
||||
return $this->AddParams($sHyperlink, $aExtraParams);
|
||||
}
|
||||
|
||||
@@ -26,6 +26,18 @@
|
||||
require_once(APPROOT."/application/nicewebpage.class.inc.php");
|
||||
require_once(APPROOT."/application/applicationcontext.class.inc.php");
|
||||
require_once(APPROOT."/application/user.preferences.class.inc.php");
|
||||
|
||||
define('BUTTON_CANCEL', 1);
|
||||
define('BUTTON_BACK', 2);
|
||||
define('BUTTON_NEXT', 4);
|
||||
define('BUTTON_FINISH', 8);
|
||||
|
||||
define('PARAM_ARROW_SEP', '_x_');
|
||||
|
||||
class TransactionException extends Exception
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Web page with some associated CSS and scripts (jquery) for a fancier display
|
||||
* of the Portal web page
|
||||
@@ -35,16 +47,21 @@ class PortalWebPage extends NiceWebPage
|
||||
/**
|
||||
* Portal menu
|
||||
*/
|
||||
protected $m_sWelcomeMsg;
|
||||
protected $m_aMenuButtons;
|
||||
|
||||
public function __construct($sTitle, $sAlternateStyleSheet = '')
|
||||
{
|
||||
$this->m_sWelcomeMsg = '';
|
||||
$this->m_aMenuButtons = array();
|
||||
parent::__construct($sTitle);
|
||||
$this->add_header("Content-type: text/html; charset=utf-8");
|
||||
$this->add_header("Cache-control: no-cache");
|
||||
$this->add_linked_stylesheet("../css/jquery.treeview.css");
|
||||
$this->add_linked_stylesheet("../css/jquery.autocomplete.css");
|
||||
$sAbsURLAppRoot = addslashes(utils::GetAbsoluteUrlAppRoot()); // Pass it to Javascript scripts
|
||||
$oAppContext = new ApplicationContext();
|
||||
$sAppContext = addslashes($oAppContext->GetForLink());
|
||||
if ($sAlternateStyleSheet != '')
|
||||
{
|
||||
$this->add_linked_stylesheet("../portal/$sAlternateStyleSheet/portal.css");
|
||||
@@ -62,10 +79,12 @@ class PortalWebPage extends NiceWebPage
|
||||
$this->add_linked_script("../js/jquery.popupmenu.js");
|
||||
$this->add_linked_script("../js/date.js");
|
||||
$this->add_linked_script("../js/jquery.tablesorter.min.js");
|
||||
$this->add_linked_script("../js/jquery.tablesorter.pager.js");
|
||||
$this->add_linked_script("../js/jquery.blockUI.js");
|
||||
$this->add_linked_script("../js/utils.js");
|
||||
$this->add_linked_script("../js/forms-json-utils.js");
|
||||
$this->add_linked_script("../js/swfobject.js");
|
||||
$this->add_linked_script("../js/jquery.qtip-1.0.min.js");
|
||||
$this->add_ready_script(
|
||||
<<<EOF
|
||||
try
|
||||
@@ -106,8 +125,6 @@ try
|
||||
}
|
||||
});
|
||||
|
||||
$("table.listResults").tableHover(); // hover tables
|
||||
$(".listResults").tablesorter( { widgets: ['myZebra', 'truncatedList']} ); // sortable and zebra tables
|
||||
$(".date-pick").datepicker({
|
||||
showOn: 'button',
|
||||
buttonImage: '../images/calendar.png',
|
||||
@@ -117,7 +134,7 @@ try
|
||||
changeMonth: true,
|
||||
changeYear: true
|
||||
});
|
||||
$('.resizable').resizable(); // Make resizable everything that claims to be resizable !
|
||||
//$('.resizable').resizable(); // Make resizable everything that claims to be resizable !
|
||||
$('.caselog_header').click( function () { $(this).toggleClass('open').next('.caselog_entry').toggle(); });
|
||||
}
|
||||
catch(err)
|
||||
@@ -130,9 +147,18 @@ EOF
|
||||
|
||||
$this->add_script(
|
||||
<<<EOF
|
||||
function CheckSelection(sMessage)
|
||||
function CheckSelection(sMessage, sInputId)
|
||||
{
|
||||
var bResult = ($('input:checked').length > 0);
|
||||
var bResult;
|
||||
if (sInputId.length > 0)
|
||||
{
|
||||
bResult = ($('input[name='+sInputId+']:checked').length > 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
// First select found...
|
||||
bResult = ($('input:checked').length > 0);
|
||||
}
|
||||
if (!bResult)
|
||||
{
|
||||
alert(sMessage);
|
||||
@@ -140,19 +166,69 @@ EOF
|
||||
return bResult;
|
||||
}
|
||||
|
||||
function GoBack()
|
||||
|
||||
function GetAbsoluteUrlAppRoot()
|
||||
{
|
||||
var form = $('#request_form');
|
||||
var step = $('input[name=step]');
|
||||
return '$sAbsURLAppRoot';
|
||||
}
|
||||
|
||||
function AddAppContext(sURL)
|
||||
{
|
||||
var sContext = '$sAppContext';
|
||||
if (sContext.length > 0)
|
||||
{
|
||||
if (sURL.indexOf('?') == -1)
|
||||
{
|
||||
return sURL+'?'+sContext;
|
||||
}
|
||||
return sURL+'&'+sContext;
|
||||
}
|
||||
return sURL;
|
||||
}
|
||||
|
||||
function GoBack(sFormId)
|
||||
{
|
||||
var form = $('#'+sFormId);
|
||||
var step_back = $('input[name=step_back]');
|
||||
|
||||
form.unbind('submit'); // De-activate validation
|
||||
step.val(step.val() -2); // To go Back one step: next step is x, current step is x-1, previous step is x-2
|
||||
|
||||
step_back.val(1);
|
||||
form.submit(); // Go
|
||||
}
|
||||
|
||||
function GoHome()
|
||||
{
|
||||
var form = $('FORM');
|
||||
form.unbind('submit'); // De-activate validation
|
||||
window.location.href = '?operation=';
|
||||
return false;
|
||||
}
|
||||
|
||||
function SetWizardNextStep(sStep)
|
||||
{
|
||||
var next_step = $('input[id=next_step]');
|
||||
next_step.val(sStep);
|
||||
}
|
||||
EOF
|
||||
);
|
||||
|
||||
|
||||
// For Wizard helper to process the ajax replies
|
||||
$this->add('<div id="ajax_content"></div>');
|
||||
}
|
||||
|
||||
public function SetCurrentTab($sTabLabel = '')
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify a welcome message (optional)
|
||||
*/
|
||||
public function SetWelcomeMessage($sMsg)
|
||||
{
|
||||
$this->m_sWelcomeMsg = $sMsg;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Add a button to the portal's main menu
|
||||
@@ -161,17 +237,590 @@ EOF
|
||||
{
|
||||
$this->m_aMenuButtons[] = array('id' => $sId, 'label' => $sLabel, 'hyperlink' => $sHyperlink);
|
||||
}
|
||||
|
||||
var $m_bEnableDisconnectButton = true;
|
||||
public function EnableDisconnectButton($bEnable)
|
||||
{
|
||||
$this->m_bEnableDisconnectButton = $bEnable;
|
||||
}
|
||||
|
||||
public function output()
|
||||
{
|
||||
$sMenu = '';
|
||||
$this->AddMenuButton('logoff', 'Portal:Disconnect', '../pages/logoff.php'); // This menu is always present and is the last one
|
||||
if ($this->m_bEnableDisconnectButton)
|
||||
{
|
||||
$this->AddMenuButton('logoff', 'Portal:Disconnect', utils::GetAbsoluteUrlAppRoot().'pages/logoff.php'); // This menu is always present and is the last one
|
||||
}
|
||||
foreach($this->m_aMenuButtons as $aMenuItem)
|
||||
{
|
||||
$sMenu .= "<a class=\"button\" id=\"{$aMenuItem['id']}\" href=\"{$aMenuItem['hyperlink']}\"><span>".Dict::S($aMenuItem['label'])."</span></a>";
|
||||
}
|
||||
$this->s_content = '<div id="portal"><div id="banner"><div id="logo"></div>'.$sMenu.'</div><div id="content">'.$this->s_content.'</div></div>';
|
||||
$this->s_content = '<div id="portal"><div id="welcome">'.$this->m_sWelcomeMsg.'</div><div id="banner"><div id="logo"></div><div id="menu">'.$sMenu.'</div></div><div id="content">'.$this->s_content.'</div></div>';
|
||||
parent::output();
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays a list of objects, without any hyperlink (except for the object's details)
|
||||
* @param DBObjectSet $oSet The set of objects to display
|
||||
* @param Array $aZList The ZList (list of field codes) to use for the tabular display
|
||||
* @param String $sEmptyListMessage Message displayed whenever the list is empty
|
||||
* @return string The HTML text representing the list
|
||||
*/
|
||||
public function DisplaySet($oSet, $aZList, $sEmptyListMessage = '')
|
||||
{
|
||||
if ($oSet->Count() > 0)
|
||||
{
|
||||
$sClass = $oSet->GetClass();
|
||||
if (is_subclass_of($sClass, 'cmdbAbstractObject'))
|
||||
{
|
||||
// Home-made and very limited display of an object set
|
||||
|
||||
$sUniqueId = $sClass.$this->GetUniqueId();
|
||||
$this->add("<div id=\"$sUniqueId\">\n"); // The id here MUST be the same as currentId, otherwise the pagination will be broken
|
||||
cmdbAbstractObject::DisplaySet($this, $oSet, array('currentId' => $sUniqueId, 'menu' => false, 'zlist' => false, 'extra_fields' => implode(',', $aZList)));
|
||||
$this->add("</div>\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
// Home-made and very limited display of an object set
|
||||
$aAttribs = array();
|
||||
$aValues = array();
|
||||
$aAttribs['key'] = array('label' => MetaModel::GetName($sClass), 'description' => '');
|
||||
foreach($aZList as $sAttCode)
|
||||
{
|
||||
$oAttDef = MetaModel::GetAttributeDef($sClass, $sAttCode);
|
||||
$aAttribs[$sAttCode] = array('label' => $oAttDef->GetLabel(), 'description' => $oAttDef->GetDescription());
|
||||
}
|
||||
while($oObj = $oSet->Fetch())
|
||||
{
|
||||
$aRow = array();
|
||||
|
||||
$aRow['key'] = '<a href="./index.php?operation=details&class='.get_class($oObj).'&id='.$oObj->GetKey().'">'.$oObj->GetName().'</a>';
|
||||
$sHilightClass = $oObj->GetHilightClass();
|
||||
if ($sHilightClass != '')
|
||||
{
|
||||
$aRow['@class'] = $sHilightClass;
|
||||
}
|
||||
foreach($aZList as $sAttCode)
|
||||
{
|
||||
$aRow[$sAttCode] = $oObj->GetAsHTML($sAttCode);
|
||||
}
|
||||
$aValues[$oObj->GetKey()] = $aRow;
|
||||
}
|
||||
$this->table($aAttribs, $aValues);
|
||||
}
|
||||
}
|
||||
elseif (strlen($sEmptyListMessage) > 0)
|
||||
{
|
||||
$this->add($sEmptyListMessage);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Display the attributes of an object (no title, no form)
|
||||
* @param Object $oObj Any kind of object
|
||||
* @param aAttList The list of attributes to display
|
||||
* @return void
|
||||
*/
|
||||
public function DisplayObjectDetails($oObj, $aAttList)
|
||||
{
|
||||
$sClass = get_class($oObj);
|
||||
$aDetails = array();
|
||||
foreach($aAttList as $sAttCode)
|
||||
{
|
||||
$iFlags = $oObj->GetAttributeFlags($sAttCode);
|
||||
$oAttDef = MetaModel::GetAttributeDef(get_class($oObj), $sAttCode);
|
||||
if ( (!$oAttDef->IsLinkSet()) && (($iFlags & OPT_ATT_HIDDEN) == 0) )
|
||||
{
|
||||
// Don't display linked set and non-visible attributes (in this state)
|
||||
$sDisplayValue = $oObj->GetAsHTML($sAttCode);
|
||||
$aDetails[] = array('label' => '<span title="'.MetaModel::GetDescription($sClass, $sAttCode).'">'.MetaModel::GetLabel($sClass, $sAttCode).'</span>', 'value' => $sDisplayValue);
|
||||
}
|
||||
}
|
||||
$this->details($aDetails);
|
||||
}
|
||||
|
||||
/**
|
||||
* DisplayObjectLinkset
|
||||
* @param Object $oObj Any kind of object
|
||||
* @param $sLinkSetAttCode The attribute code of the link set attribute to display
|
||||
* @param $sRemoteAttCode The external key on the linked class, pointing to the remote objects
|
||||
* @param $aZList The list of attribute of the remote object
|
||||
* @param $sEmptyListMessage The message to display if the list is empty
|
||||
* @return void
|
||||
*/
|
||||
public function DisplayObjectLinkset($oObj, $sLinkSetAttCode, $sRemoteAttCode, $aZList, $sEmptyListMessage = '', $oSearchRestriction = null)
|
||||
{
|
||||
if (empty($sEmptyListMessage))
|
||||
{
|
||||
$sEmptyListMessage = Dict::S('UI:Search:NoObjectFound');
|
||||
}
|
||||
|
||||
$oLinkSet = $oObj->Get($sLinkSetAttCode);
|
||||
if ($oLinkSet->Count() > 0)
|
||||
{
|
||||
$sClass = $oLinkSet->GetClass();
|
||||
$oExtKeyToRemote = MetaModel::GetAttributeDef($sClass, $sRemoteAttCode);
|
||||
$sRemoteClass = $oExtKeyToRemote->GetTargetClass();
|
||||
|
||||
if (is_null($oSearchRestriction))
|
||||
{
|
||||
$oObjSearch = new DBObjectSearch($sRemoteClass);
|
||||
}
|
||||
else
|
||||
{
|
||||
$oObjSearch = $oSearchRestriction;
|
||||
}
|
||||
$oObjSearch->AddCondition_ReferencedBy($oLinkSet->GetFilter(), $sRemoteAttCode);
|
||||
|
||||
$aExtraParams = array('menu' => false, 'zlist' => false, 'extra_fields' => implode(',', $aZList));
|
||||
$oBlock = new DisplayBlock($oObjSearch, 'list', false);
|
||||
$oBlock->Display($this, 1, $aExtraParams);
|
||||
}
|
||||
elseif (strlen($sEmptyListMessage) > 0)
|
||||
{
|
||||
$this->add($sEmptyListMessage);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
protected function DisplaySearchField($sClass, $sAttSpec, $aExtraParams, $sPrefix, $sFieldName = null)
|
||||
{
|
||||
if (is_null($sFieldName))
|
||||
{
|
||||
$sFieldName = str_replace('->', PARAM_ARROW_SEP, $sAttSpec);
|
||||
}
|
||||
|
||||
$iPos = strpos($sAttSpec, '->');
|
||||
if ($iPos !== false)
|
||||
{
|
||||
$sAttCode = substr($sAttSpec, 0, $iPos);
|
||||
$sSubSpec = substr($sAttSpec, $iPos + 2);
|
||||
|
||||
if (!MetaModel::IsValidAttCode($sClass, $sAttCode))
|
||||
{
|
||||
throw new Exception("Invalid attribute code '$sClass/$sAttCode' in search specification '$sAttSpec'");
|
||||
}
|
||||
|
||||
$oAttDef = MetaModel::GetAttributeDef($sClass, $sAttCode);
|
||||
if ($oAttDef->IsLinkSet())
|
||||
{
|
||||
$sTargetClass = $oAttDef->GetLinkedClass();
|
||||
}
|
||||
elseif ($oAttDef->IsExternalKey(EXTKEY_ABSOLUTE))
|
||||
{
|
||||
$sTargetClass = $oAttDef->GetTargetClass(EXTKEY_ABSOLUTE);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new Exception("Attribute specification '$sAttSpec', '$sAttCode' should be either a link set or an external key");
|
||||
}
|
||||
$this->DisplaySearchField($sTargetClass, $sSubSpec, $aExtraParams, $sPrefix, $sFieldName);
|
||||
}
|
||||
else
|
||||
{
|
||||
// $sAttSpec is an attribute code
|
||||
//
|
||||
$this->add('<span style="white-space: nowrap;padding:5px;display:inline-block;">');
|
||||
$sFilterValue = '';
|
||||
$sFilterValue = utils::ReadParam($sPrefix.$sFieldName, '', false, 'raw_data');
|
||||
$sFilterOpCode = null; // Use the default 'loose' OpCode
|
||||
$oAttDef = MetaModel::GetAttributeDef($sClass, $sAttSpec);
|
||||
if ($oAttDef->IsExternalKey())
|
||||
{
|
||||
$sTargetClass = $oAttDef->GetTargetClass();
|
||||
$oAllowedValues = new DBObjectSet(new DBObjectSearch($sTargetClass));
|
||||
|
||||
$iFieldSize = $oAttDef->GetMaxSize();
|
||||
$iMaxComboLength = $oAttDef->GetMaximumComboLength();
|
||||
$this->add("<label>".MetaModel::GetFilterLabel($sClass, $sAttSpec).":</label> ");
|
||||
//$oWidget = UIExtKeyWidget::DIsplayFromAttCode($sAttSpec, $sClass, $oAttDef->GetLabel(), $oAllowedValues, $sFilterValue, $sPrefix.$sFieldName, false, '', $sPrefix, '');
|
||||
//$this->add($oWidget->Display($this, $aExtraParams, true /* bSearchMode */));
|
||||
$aExtKeyParams = $aExtraParams;
|
||||
$aExtKeyParams['iFieldSize'] = $oAttDef->GetMaxSize();
|
||||
$aExtKeyParams['iMinChars'] = $oAttDef->GetMinAutoCompleteChars();
|
||||
// DisplayFromAttCode($this, $sAttCode, $sClass, $sTitle, $oAllowedValues, $value, $iInputId, $bMandatory, $sFieldName = '', $sFormPrefix = '', $aArgs, $bSearchMode = false)
|
||||
$sHtml = UIExtKeyWidget::DisplayFromAttCode($this, $sAttSpec, $sClass, $oAttDef->GetLabel(), $oAllowedValues, $sFilterValue, $sPrefix.$sFieldName, false, $sPrefix.$sFieldName, $sPrefix, $aExtKeyParams, true);
|
||||
$this->add($sHtml);
|
||||
}
|
||||
else
|
||||
{
|
||||
$aAllowedValues = MetaModel::GetAllowedValues_flt($sClass, $sAttSpec, $aExtraParams);
|
||||
if (is_null($aAllowedValues))
|
||||
{
|
||||
// Any value is possible, display an input box
|
||||
$this->add("<label>".MetaModel::GetFilterLabel($sClass, $sAttSpec).":</label> <input class=\"textSearch\" name=\"$sPrefix$sFieldName\" value=\"$sFilterValue\"/>\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
//Enum field or external key, display a combo
|
||||
$sValue = "<select name=\"$sPrefix$sFieldName\">\n";
|
||||
$sValue .= "<option value=\"\">".Dict::S('UI:SearchValue:Any')."</option>\n";
|
||||
foreach($aAllowedValues as $key => $value)
|
||||
{
|
||||
if ($sFilterValue == $key)
|
||||
{
|
||||
$sSelected = ' selected';
|
||||
}
|
||||
else
|
||||
{
|
||||
$sSelected = '';
|
||||
}
|
||||
$sValue .= "<option value=\"$key\"$sSelected>$value</option>\n";
|
||||
}
|
||||
$sValue .= "</select>\n";
|
||||
$this->add("<label>".MetaModel::GetFilterLabel($sClass, $sAttSpec).":</label> $sValue\n");
|
||||
}
|
||||
}
|
||||
unset($aExtraParams[$sFieldName]);
|
||||
$this->add('</span> ');
|
||||
|
||||
$sTip = $oAttDef->GetHelpOnSmartSearch();
|
||||
if (strlen($sTip) > 0)
|
||||
{
|
||||
$sTip = addslashes($sTip);
|
||||
$sTip = str_replace(array("\n", "\r"), " ", $sTip);
|
||||
// :input does represent in form visible input (INPUT, SELECT, TEXTAREA)
|
||||
$this->add_ready_script("$(':input[name={$sPrefix}$sFieldName]').qtip( { content: '$sTip', show: 'mouseover', hide: 'mouseout', style: { name: 'dark', tip: 'leftTop' }, position: { corner: { target: 'rightMiddle', tooltip: 'leftTop' }} } );");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public function DisplaySearchForm($sClass, $aAttList, $aExtraParams, $sPrefix, $bClosed = true)
|
||||
{
|
||||
$sCSSClass = ($bClosed) ? 'DrawerClosed' : '';
|
||||
$this->add("<div id=\"ds_$sPrefix\" class=\"SearchDrawer $sCSSClass\">\n");
|
||||
$this->add_ready_script(
|
||||
<<<EOF
|
||||
$("#dh_$sPrefix").click( function() {
|
||||
$("#ds_$sPrefix").slideToggle('normal', function() { $("#ds_$sPrefix").parent().resize(); } );
|
||||
$("#dh_$sPrefix").toggleClass('open');
|
||||
});
|
||||
EOF
|
||||
);
|
||||
$this->add("<form id=\"search_$sClass\" action=\"\" method=\"post\">\n"); // Don't use $_SERVER['SCRIPT_NAME'] since the form may be called asynchronously (from ajax.php)
|
||||
// $this->add("<h2>".Dict::Format('UI:SearchFor_Class_Objects', 'xxxxxx')."</h2>\n");
|
||||
$this->add("<p>\n");
|
||||
foreach($aAttList as $sAttSpec)
|
||||
{
|
||||
//$oAppContext->Reset($sAttSpec); // Make sure the same parameter will not be passed twice
|
||||
$this->DisplaySearchField($sClass, $sAttSpec, $aExtraParams, $sPrefix);
|
||||
}
|
||||
$this->add("</p>\n");
|
||||
$this->add("<p align=\"right\"><input type=\"submit\" value=\"".Dict::S('UI:Button:Search')."\"></p>\n");
|
||||
foreach($aExtraParams as $sName => $sValue)
|
||||
{
|
||||
$this->add("<input type=\"hidden\" name=\"$sName\" value=\"$sValue\" />\n");
|
||||
}
|
||||
// $this->add($oAppContext->GetForForm());
|
||||
$this->add("</form>\n");
|
||||
$this->add("</div>\n");
|
||||
$this->add("<div class=\"HRDrawer\"></div>\n");
|
||||
$this->add("<div id=\"dh_$sPrefix\" class=\"DrawerHandle\">".Dict::S('UI:SearchToggle')."</div>\n");
|
||||
}
|
||||
|
||||
/**
|
||||
* Read parameters from the page
|
||||
* Parameters that were absent from the page's parameters are not set in the resulting hash array
|
||||
* @input string $sMethod Either get or post
|
||||
* @return Hash Array of name => value corresponding to the parameters that were passed to the page
|
||||
*/
|
||||
public function ReadAllParams($sParamList, $sPrefix = 'attr_')
|
||||
{
|
||||
$aParams = explode(',', $sParamList);
|
||||
$aValues = array();
|
||||
foreach($aParams as $sName)
|
||||
{
|
||||
$sName = trim($sName);
|
||||
$value = utils::ReadParam($sPrefix.$sName, null, false, 'raw_data');
|
||||
if (!is_null($value))
|
||||
{
|
||||
$aValues[$sName] = $value;
|
||||
}
|
||||
}
|
||||
return $aValues;
|
||||
}
|
||||
|
||||
/**
|
||||
* Outputs a list of parameters as hidden fields
|
||||
* Example: attr_dummy[-123][id] = "blah"
|
||||
* @param Hash $aParameters Array name => value for the parameters
|
||||
* @param Array $aExclude The list of parameters that must not be handled this way (probably already in the visible part of the form)
|
||||
* @return void
|
||||
*/
|
||||
protected function DumpHiddenParamsInternal($sName, $value)
|
||||
{
|
||||
if (is_array($value))
|
||||
{
|
||||
foreach($value as $sKey => $item)
|
||||
{
|
||||
$this->DumpHiddenParamsInternal($sName.'['.$sKey.']', $item);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->Add("<input type=\"hidden\" name=\"$sName\" value=\"$value\">");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Outputs a list of parameters as hidden field into the current page
|
||||
* (must be called when inside a form)
|
||||
* @param Hash $aParameters Array name => value for the parameters
|
||||
* @param Array $aExclude The list of parameters that must not be handled this way (probably already in the visible part of the form)
|
||||
* @return void
|
||||
*/
|
||||
public function DumpHiddenParams($aParameters, $aExclude = null, $sPrefix = 'attr_')
|
||||
{
|
||||
foreach($aParameters as $sAttCode => $value)
|
||||
{
|
||||
if (is_null($aExclude) || !in_array($sAttCode, $aExclude))
|
||||
{
|
||||
$this->DumpHiddenParamsInternal($sPrefix.$sAttCode, $value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function PostedParamsToFilter($sClass, $aAttList, $sPrefix)
|
||||
{
|
||||
$oFilter = new DBObjectSearch($sClass);
|
||||
$iCountParams = 0;
|
||||
foreach($aAttList as $sAttSpec)
|
||||
{
|
||||
$sFieldName = str_replace('->', PARAM_ARROW_SEP, $sAttSpec);
|
||||
$value = utils::ReadPostedParam($sPrefix.$sFieldName, null, 'raw_data');
|
||||
if (!is_null($value) && strlen($value) > 0)
|
||||
{
|
||||
$oFilter->AddConditionAdvanced($sAttSpec, $value);
|
||||
$iCountParams++;
|
||||
}
|
||||
}
|
||||
if ($iCountParams == 0)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
else
|
||||
{
|
||||
return $oFilter;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the object form POSTED arguments, and writes it into the DB (applies a stimuli if requested)
|
||||
* @param DBObject $oObj The object to update
|
||||
* $param array $aAttList If set, this will limit the list of updated attributes
|
||||
* @return void
|
||||
*/
|
||||
public function DoUpdateObjectFromPostedForm(DBObject $oObj, $aAttList = null)
|
||||
{
|
||||
$sTransactionId = utils::ReadPostedParam('transaction_id', '');
|
||||
if (!utils::IsTransactionValid($sTransactionId))
|
||||
{
|
||||
throw new TransactionException();
|
||||
}
|
||||
|
||||
$sClass = get_class($oObj);
|
||||
|
||||
$sStimulus = trim(utils::ReadPostedParam('apply_stimulus', ''));
|
||||
$sTargetState = '';
|
||||
if (!empty($sStimulus))
|
||||
{
|
||||
// Compute the target state
|
||||
|
||||
$aTransitions = $oObj->EnumTransitions();
|
||||
if (!isset($aTransitions[$sStimulus]))
|
||||
{
|
||||
throw new ApplicationException(Dict::Format('UI:Error:Invalid_Stimulus_On_Object_In_State', $sStimulus, $oObj->GetName(), $oObj->GetStateLabel()));
|
||||
}
|
||||
$sTargetState = $aTransitions[$sStimulus]['target_state'];
|
||||
}
|
||||
|
||||
$oObj->UpdateObjectFromPostedForm('' /* form prefix */, $aAttList, $sTargetState);
|
||||
|
||||
// Optional: apply a stimulus
|
||||
//
|
||||
if (!empty($sStimulus))
|
||||
{
|
||||
if (!$oObj->ApplyStimulus($sStimulus))
|
||||
{
|
||||
throw new Exception("Cannot apply stimulus '$sStimulus' to {$oObj->GetName()}");
|
||||
}
|
||||
}
|
||||
|
||||
// Record the change
|
||||
//
|
||||
$oMyChange = MetaModel::NewObject("CMDBChange");
|
||||
$oMyChange->Set("date", time());
|
||||
$sUserString = CMDBChange::GetCurrentUserName();
|
||||
$oMyChange->Set("userinfo", $sUserString);
|
||||
$iChangeId = $oMyChange->DBInsert();
|
||||
$oObj->DBUpdateTracked($oMyChange);
|
||||
|
||||
// Trigger ?
|
||||
//
|
||||
$aClasses = MetaModel::EnumParentClasses($sClass, ENUM_PARENT_CLASSES_ALL);
|
||||
$sClassList = implode(", ", CMDBSource::Quote($aClasses));
|
||||
$oSet = new DBObjectSet(DBObjectSearch::FromOQL("SELECT TriggerOnPortalUpdate AS t WHERE t.target_class IN ($sClassList)"));
|
||||
while ($oTrigger = $oSet->Fetch())
|
||||
{
|
||||
$oTrigger->DoActivate($oObj->ToArgs('this'));
|
||||
}
|
||||
|
||||
$this->p("<h1>".Dict::Format('UI:Class_Object_Updated', MetaModel::GetName(get_class($oObj)), $oObj->GetName())."</h1>\n");
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the object of the specified Class/ID.
|
||||
* @param WebPage $oP The current page
|
||||
* @return DBObject The found object, or throws an exception in case of failure
|
||||
*/
|
||||
public function FindObjectFromArgs($aAllowedClasses = null)
|
||||
{
|
||||
$sClass = utils::ReadParam('class', '', true, 'class');
|
||||
$iId = utils::ReadParam('id', 0, true, 'integer');
|
||||
|
||||
if (empty($sClass))
|
||||
{
|
||||
throw new Exception("Missing argument 'class'");
|
||||
}
|
||||
if (!MetaModel::IsValidClass($sClass))
|
||||
{
|
||||
throw new Exception("Wrong value for argument 'class': $sClass");
|
||||
}
|
||||
if ($iId == 0)
|
||||
{
|
||||
throw new Exception("Missing argument 'id'");
|
||||
}
|
||||
|
||||
if(!is_null($aAllowedClasses))
|
||||
{
|
||||
$bAllowed = false;
|
||||
foreach($aAllowedClasses as $sParentClass)
|
||||
{
|
||||
if (MetaModel::IsParentClass($sParentClass, $sClass))
|
||||
{
|
||||
$bAllowed = true;
|
||||
}
|
||||
}
|
||||
if (!$bAllowed)
|
||||
{
|
||||
throw new Exception("Class '$sClass not allowed in this implementation'");
|
||||
}
|
||||
}
|
||||
|
||||
$oObj = MetaModel::GetObject($sClass, $iId, false);
|
||||
if (!is_object($oObj))
|
||||
{
|
||||
throw new Exception("Could not find the object $sClass/$iId");
|
||||
}
|
||||
return $oObj;
|
||||
}
|
||||
|
||||
var $m_sWizardId = null;
|
||||
|
||||
public function WizardFormStart($sId = '', $sNextStep = null, $bAttachment = false, $sMethod = 'post')
|
||||
{
|
||||
$this->m_sWizardId = $sId;
|
||||
|
||||
// multipart... needed for file upload
|
||||
$this->add("<form id=\"{$this->m_sWizardId}\" method=\"$sMethod\" enctype=\"multipart/form-data\">\n");
|
||||
|
||||
$aPreviousSteps = $this->GetWizardStepHistory();
|
||||
if (utils::ReadParam('step_back', 0) == 1)
|
||||
{
|
||||
// Back into the past history
|
||||
array_pop($aPreviousSteps);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Moving forward
|
||||
array_push($aPreviousSteps, utils::ReadParam('next_step'));
|
||||
}
|
||||
|
||||
$sStepHistory = implode(',', $aPreviousSteps);
|
||||
$this->add("<input type=\"hidden\" id=\"step_history\" name=\"step_history\" value=\"$sStepHistory\">");
|
||||
|
||||
if (!is_null($sNextStep))
|
||||
{
|
||||
$this->add("<input type=\"hidden\" id=\"next_step\" name=\"next_step\" value=\"$sNextStep\">");
|
||||
}
|
||||
$this->add("<input type=\"hidden\" id=\"step_back\" name=\"step_back\" value=\"0\">");
|
||||
|
||||
$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");
|
||||
}
|
||||
|
||||
public function WizardFormButtons($iButtonFlags)
|
||||
{
|
||||
$aButtons = array();
|
||||
if ($iButtonFlags & BUTTON_CANCEL)
|
||||
{
|
||||
$aButtons[] = "<input id=\"btn_cancel\" type=\"button\" value=\"".Dict::S('UI:Button:Cancel')."\" onClick=\"GoHome();\">";
|
||||
}
|
||||
if ($iButtonFlags & BUTTON_BACK)
|
||||
{
|
||||
$aButtons[] = "<input id=\"btn_back\" type=\"submit\" value=\"".Dict::S('UI:Button:Back')."\" onClick=\"GoBack('{$this->m_sWizardId}');\">";
|
||||
}
|
||||
if ($iButtonFlags & BUTTON_NEXT)
|
||||
{
|
||||
$aButtons[] = "<input id=\"btn_next\" type=\"submit\" value=\"".Dict::S('UI:Button:Next')."\">";
|
||||
}
|
||||
if ($iButtonFlags & BUTTON_FINISH)
|
||||
{
|
||||
$aButtons[] = "<input id=\"btn_finish\" type=\"submit\" value=\"".Dict::S('UI:Button:Finish')."\">";
|
||||
}
|
||||
|
||||
$this->add('<div id="buttons">');
|
||||
$this->add(implode('', $aButtons));
|
||||
$this->add('</div>');
|
||||
}
|
||||
|
||||
public function WizardFormEnd()
|
||||
{
|
||||
$this->add("</form>\n");
|
||||
}
|
||||
|
||||
public function GetWizardStep()
|
||||
{
|
||||
if (utils::ReadParam('step_back', 0) == 1)
|
||||
{
|
||||
// Take the value into the history - one level above
|
||||
$aPreviousSteps = $this->GetWizardStepHistory();
|
||||
array_pop($aPreviousSteps);
|
||||
return end($aPreviousSteps);
|
||||
}
|
||||
else
|
||||
{
|
||||
return utils::ReadParam('next_step');
|
||||
}
|
||||
}
|
||||
|
||||
protected function GetWizardStepHistory()
|
||||
{
|
||||
$sRawHistory = trim(utils::ReadParam('step_history', '', false, 'raw_data'));
|
||||
if (strlen($sRawHistory) == 0)
|
||||
{
|
||||
return array();
|
||||
}
|
||||
else
|
||||
{
|
||||
return explode(',', $sRawHistory);
|
||||
}
|
||||
}
|
||||
|
||||
public function WizardCheckSelectionOnSubmit($sMessageIfNoSelection, $sInputName = '')
|
||||
{
|
||||
$this->add_ready_script(
|
||||
<<<EOF
|
||||
$('#{$this->m_sWizardId}').submit(function() {
|
||||
return CheckSelection('$sMessageIfNoSelection', '$sInputName');
|
||||
});
|
||||
EOF
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
|
||||
107
application/query.class.inc.php
Normal file
@@ -0,0 +1,107 @@
|
||||
<?php
|
||||
// Copyright (C) 2010 Combodo SARL
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation; version 3 of the License.
|
||||
//
|
||||
// This program 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 General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
/**
|
||||
* Persistent class Event and derived
|
||||
* Application internal events
|
||||
* There is also a file log
|
||||
*
|
||||
* @author Erwan Taloc <erwan.taloc@combodo.com>
|
||||
* @author Romain Quetiez <romain.quetiez@combodo.com>
|
||||
* @author Denis Flaven <denis.flaven@combodo.com>
|
||||
* @license http://www.opensource.org/licenses/gpl-3.0.html LGPL
|
||||
*/
|
||||
|
||||
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 AttributeString("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')); // 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')); // 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())
|
||||
{
|
||||
parent::DisplayBareProperties($oPage, $bEditMode, $sPrefix, $aExtraParams);
|
||||
|
||||
if (!$bEditMode)
|
||||
{
|
||||
$sUrl = utils::GetAbsoluteUrlAppRoot().'webservices/export.php?format=spreadsheet&login_mode=basic&query='.$this->GetKey();
|
||||
$sOql = $this->Get('oql');
|
||||
$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>');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
531
application/sqlblock.class.inc.php
Normal file
@@ -0,0 +1,531 @@
|
||||
<?php
|
||||
// Copyright (C) 2010 Combodo SARL
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation; version 3 of the License.
|
||||
//
|
||||
// This program 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 General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
/**
|
||||
* SqlBlock - display tables or charts, given an SQL query - use cautiously!
|
||||
*
|
||||
*
|
||||
* @author Erwan Taloc <erwan.taloc@combodo.com>
|
||||
* @author Romain Quetiez <romain.quetiez@combodo.com>
|
||||
* @author Denis Flaven <denis.flaven@combodo.com>
|
||||
* @license http://www.opensource.org/licenses/gpl-3.0.html LGPL
|
||||
*/
|
||||
|
||||
|
||||
require_once(APPROOT.'/application/webpage.class.inc.php');
|
||||
require_once(APPROOT.'/application/utils.inc.php');
|
||||
|
||||
require_once(APPROOT.'/pages/php-ofc-library/open-flash-chart.php');
|
||||
|
||||
/**
|
||||
* Helper class to design optimized dashboards, based on an SQL query
|
||||
*
|
||||
*/
|
||||
class SqlBlock
|
||||
{
|
||||
protected $m_sQuery;
|
||||
protected $m_aColumns;
|
||||
protected $m_sTitle;
|
||||
protected $m_sType;
|
||||
protected $m_aParams;
|
||||
|
||||
public function __construct($sQuery, $aColumns, $sTitle, $sType, $aParams = array())
|
||||
{
|
||||
$this->m_sQuery = $sQuery;
|
||||
$this->m_aColumns = $aColumns;
|
||||
$this->m_sTitle = $sTitle;
|
||||
$this->m_sType = $sType;
|
||||
$this->m_aParams = $aParams;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a SqlBlock object from an XML template
|
||||
/*
|
||||
*
|
||||
* <sqlblock>
|
||||
* <sql>SELECT date_format(start_date, '%d') AS Date, count(*) AS Count FROM ticket WHERE DATE_SUB(NOW(), INTERVAL 15 DAY) < start_date AND finalclass = 'UserIssue' GROUP BY date_format(start_date, '%d') AND $CONDITION(param1, ticket.org_id)$</sql>
|
||||
* <type>table</type>
|
||||
* <title>UserRequest:Overview-Title</title>
|
||||
* <parameter>
|
||||
* <name>param1</name>
|
||||
* <type>context</type>
|
||||
* <mapping>org_id</mapping>
|
||||
* </parameter>
|
||||
* <column>
|
||||
* <name>Date</name>
|
||||
* <label>UserRequest:Overview-Date</label>
|
||||
* <drilldown></drilldown>
|
||||
* </column>
|
||||
* <column>
|
||||
* <name>Count</name>
|
||||
* <label>UserRequest:Overview-Count</label>
|
||||
* <drilldown>SELECT UserIssue WHERE date_format(start_date, '%d') = :Date</drilldown>
|
||||
* </column>
|
||||
* </sqlblock>
|
||||
*
|
||||
* Tags
|
||||
* - sql: a (My)SQL query. Do not forget to use html entities (e.g. < for <)
|
||||
* - type: table (default), bars or pie. If bars or pie is selected only the two first columns are taken into account.
|
||||
* - title: optional title, typed in clear or given as a dictionnary entry
|
||||
* - parameter: specifies how to map the context parameters (namely org_id) to a given named parameter in the query.
|
||||
* The expression $CONDITION(<param_name>, <sql_column_name>) will be automatically replaced by:
|
||||
* either the string "1" if there is no restriction on the organisation in iTop
|
||||
* or the string "(<sql_column_name>=<value_of_org_id>)" if there is a limitation to one organizations in iTop
|
||||
* or the string "(<sql_column_name> IN (<values_of_org_id>))" if there is a limitation to a given set of organizations in iTop
|
||||
* - column: specification of a column (not displayed if omitted)
|
||||
* - column / name: name of the column in the SQL query (use aliases)
|
||||
* - column / label: label, typed in clear or given as a dictionnary entry
|
||||
* - column / drilldown: NOT IMPLEMENTED YET - OQL with parameters corresponding to column names (in the query)
|
||||
*
|
||||
* @param $sTemplate string The XML template
|
||||
* @return DisplayBlock The DisplayBlock object, or null if the template is invalid
|
||||
*/
|
||||
public static function FromTemplate($sTemplate)
|
||||
{
|
||||
$oXml = simplexml_load_string('<root>'.$sTemplate.'</root>', 'SimpleXMLElement', LIBXML_NOCDATA);
|
||||
if (false)
|
||||
{
|
||||
// Debug
|
||||
echo "<pre>\n";
|
||||
print_r($oXml);
|
||||
echo "</pre>\n";
|
||||
}
|
||||
|
||||
if (isset($oXml->title))
|
||||
{
|
||||
$sTitle = (string)$oXml->title;
|
||||
}
|
||||
if (isset($oXml->type))
|
||||
{
|
||||
$sType = (string)$oXml->type;
|
||||
}
|
||||
else
|
||||
{
|
||||
$sType = 'table';
|
||||
}
|
||||
if (!isset($oXml->sql))
|
||||
{
|
||||
throw new Exception('Missing tag "sql" in sqlblock');
|
||||
}
|
||||
$sQuery = (string)$oXml->sql;
|
||||
|
||||
$aColumns = array();
|
||||
if (isset($oXml->column))
|
||||
{
|
||||
foreach ($oXml->column AS $oColumnData)
|
||||
{
|
||||
if (!isset($oColumnData->name))
|
||||
{
|
||||
throw new Exception("Missing tag 'name' in sqlblock/column");
|
||||
}
|
||||
$sName = (string) $oColumnData->name;
|
||||
if (strlen($sName) == 0)
|
||||
{
|
||||
throw new Exception("Empty tag 'name' in sqlblock/column");
|
||||
}
|
||||
|
||||
$aColumns[$sName] = array();
|
||||
if (isset($oColumnData->label))
|
||||
{
|
||||
$sLabel = (string)$oColumnData->label;
|
||||
if (strlen($sLabel) > 0)
|
||||
{
|
||||
$aColumns[$sName]['label'] = Dict::S($sLabel);
|
||||
}
|
||||
}
|
||||
if (isset($oColumnData->drilldown))
|
||||
{
|
||||
$sDrillDown = (string)$oColumnData->drilldown;
|
||||
if (strlen($sDrillDown) > 0)
|
||||
{
|
||||
$aColumns[$sName]['drilldown'] = $sDrillDown;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
$aParams = array();
|
||||
if (isset($oXml->parameter))
|
||||
{
|
||||
foreach ($oXml->parameter AS $oParamData)
|
||||
{
|
||||
if (!isset($oParamData->name))
|
||||
{
|
||||
throw new Exception("Missing tag 'name' for parameter in sqlblock/column");
|
||||
}
|
||||
$sName = (string) $oParamData->name;
|
||||
if (strlen($sName) == 0)
|
||||
{
|
||||
throw new Exception("Empty tag 'name' for parameter in sqlblock/column");
|
||||
}
|
||||
if (!isset($oParamData->mapping))
|
||||
{
|
||||
throw new Exception("Missing tag 'mapping' for parameter in sqlblock/column");
|
||||
}
|
||||
$sMapping = (string) $oParamData->mapping;
|
||||
if (strlen($sMapping) == 0)
|
||||
{
|
||||
throw new Exception("Empty tag 'mapping' for parameter in sqlblock/column");
|
||||
}
|
||||
|
||||
if (isset($oParamData->type))
|
||||
{
|
||||
$sParamType = $oParamData->type;
|
||||
}
|
||||
else
|
||||
{
|
||||
$sParamType = 'context';
|
||||
}
|
||||
$aParams[$sName] = array('mapping' => $sMapping, 'type' => $sParamType);
|
||||
}
|
||||
}
|
||||
|
||||
return new SqlBlock($sQuery, $aColumns, $sTitle, $sType, $aParams);
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies the defined parameters into the SQL query
|
||||
* @return string the SQL query to execute
|
||||
*/
|
||||
public function BuildQuery()
|
||||
{
|
||||
$oAppContext = new ApplicationContext();
|
||||
$sQuery = $this->m_sQuery;
|
||||
$sQuery = str_replace('$DB_PREFIX$', MetaModel::GetConfig()->GetDBSubname(), $sQuery); // put the tables DB prefix (if any)
|
||||
foreach($this->m_aParams as $sName => $aParam)
|
||||
{
|
||||
if ($aParam['type'] == 'context')
|
||||
{
|
||||
$sSearchPattern = '/\$CONDITION\('.$sName.',([^\)]+)\)\$/';
|
||||
$value = $oAppContext->GetCurrentValue($aParam['mapping']);
|
||||
if (empty($value))
|
||||
{
|
||||
$sSQLExpr = '(1)';
|
||||
}
|
||||
else
|
||||
{
|
||||
// Special case for managing the hierarchy of organizations
|
||||
if (($aParam['mapping'] == 'org_id') && ( MetaModel::IsValidClass('Organization')))
|
||||
{
|
||||
$sHierarchicalKeyCode = MetaModel::IsHierarchicalClass('Organization');
|
||||
if ($sHierarchicalKeyCode != false)
|
||||
{
|
||||
// organizations are in hierarchy... gather all the orgs below the given one...
|
||||
$sOQL = "SELECT Organization AS node JOIN Organization AS root ON node.$sHierarchicalKeyCode BELOW root.id WHERE root.id = :value";
|
||||
$oSet = new DBObjectSet(DBObjectSearch::FromOQL($sOQL), array(), array('value' => $value));
|
||||
$aOrgIds = array();
|
||||
while($oOrg = $oSet->Fetch())
|
||||
{
|
||||
$aOrgIds[]= $oOrg->GetKey();
|
||||
}
|
||||
$sSQLExpr = '($1 IN('.implode(',', $aOrgIds).'))';
|
||||
}
|
||||
else
|
||||
{
|
||||
$sSQLExpr = '($1 = '.CMDBSource::Quote($value).')';
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$sSQLExpr = '($1 = '.CMDBSource::Quote($value).')';
|
||||
}
|
||||
}
|
||||
$sQuery = preg_replace($sSearchPattern, $sSQLExpr, $sQuery);
|
||||
}
|
||||
}
|
||||
return $sQuery;
|
||||
}
|
||||
|
||||
public function RenderContent(WebPage $oPage, $aExtraParams = array())
|
||||
{
|
||||
if (empty($aExtraParams['currentId']))
|
||||
{
|
||||
$sId = 'sqlblock_'.$oPage->GetUniqueId(); // Works only if the page is not an Ajax one !
|
||||
}
|
||||
else
|
||||
{
|
||||
$sId = $aExtraParams['currentId'];
|
||||
}
|
||||
// $oPage->add($this->GetRenderContent($oPage, $aExtraParams, $sId));
|
||||
|
||||
$sQuery = $this->BuildQuery();
|
||||
$res = CMDBSource::Query($sQuery);
|
||||
$aQueryCols = CMDBSource::GetColumns($res);
|
||||
|
||||
// Prepare column definitions (check + give default values)
|
||||
//
|
||||
foreach($this->m_aColumns as $sName => $aColumnData)
|
||||
{
|
||||
if (!in_array($sName, $aQueryCols))
|
||||
{
|
||||
throw new Exception("Unknown column name '$sName' in sqlblock column");
|
||||
}
|
||||
if (!isset($aColumnData['label']))
|
||||
{
|
||||
$this->m_aColumns[$sName]['label'] = $sName;
|
||||
}
|
||||
if (isset($aColumnData['drilldown']) && !empty($aColumnData['drilldown']))
|
||||
{
|
||||
// Check if the OQL is valid
|
||||
try
|
||||
{
|
||||
$this->m_aColumns[$sName]['filter'] = DBObjectSearch::FromOQL($aColumnData['drilldown']);
|
||||
}
|
||||
catch(OQLException $e)
|
||||
{
|
||||
unset($aColumnData['drilldown']);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (strlen($this->m_sTitle) > 0)
|
||||
{
|
||||
$oPage->add("<h2>".Dict::S($this->m_sTitle)."</h2>\n");
|
||||
}
|
||||
|
||||
switch ($this->m_sType)
|
||||
{
|
||||
case 'bars':
|
||||
case 'pie':
|
||||
$aColNames = array_keys($this->m_aColumns);
|
||||
$sXColName = $aColNames[0];
|
||||
$sYColName = $aColNames[1];
|
||||
$aData = array();
|
||||
$aRows = array();
|
||||
while($aRow = CMDBSource::FetchArray($res))
|
||||
{
|
||||
$aData[$aRow[$sXColName]] = $aRow[$sYColName];
|
||||
$aRows[$aRow[$sXColName]] = $aRow;
|
||||
}
|
||||
$this->RenderChart($oPage, $sId, $aData, $this->m_aColumns[$sYColName]['drilldown'], $aRows);
|
||||
break;
|
||||
|
||||
default:
|
||||
case 'table':
|
||||
$oAppContext = new ApplicationContext();
|
||||
$sContext = $oAppContext->GetForLink();
|
||||
if (!empty($sContext))
|
||||
{
|
||||
$sContext = '&'.$sContext;
|
||||
}
|
||||
$aDisplayConfig = array();
|
||||
foreach($this->m_aColumns as $sName => $aColumnData)
|
||||
{
|
||||
$aDisplayConfig[$sName] = array('label' => $aColumnData['label'], 'description' => '');
|
||||
}
|
||||
|
||||
$aDisplayData = array();
|
||||
while($aRow = CMDBSource::FetchArray($res))
|
||||
{
|
||||
$aSQLColNames = array_keys($aRow);
|
||||
$aDisplayRow = array();
|
||||
foreach($this->m_aColumns as $sName => $aColumnData)
|
||||
{
|
||||
if (isset($aColumnData['filter']))
|
||||
{
|
||||
$sFilter = $aColumnData['drilldown'];
|
||||
$sClass = $aColumnData['filter']->GetClass();
|
||||
$sFilter = str_replace('SELECT '.$sClass, '', $sFilter);
|
||||
foreach($aSQLColNames as $sColName)
|
||||
{
|
||||
$sFilter = str_replace(':'.$sColName, "'".addslashes( $aRow[$sColName] )."'", $sFilter);
|
||||
}
|
||||
$sURL = utils::GetAbsoluteUrlAppRoot().'pages/UI.php?operation=search_oql&search_form=0&oql_class='.$sClass.'&oql_clause='.urlencode($sFilter).'&format=html'.$sContext;
|
||||
$aDisplayRow[$sName] = '<a href="'.$sURL.'">'.$aRow[$sName]."</a>";
|
||||
}
|
||||
else
|
||||
{
|
||||
$aDisplayRow[$sName] = $aRow[$sName];
|
||||
}
|
||||
}
|
||||
$aDisplayData[] = $aDisplayRow;
|
||||
}
|
||||
$oPage->table($aDisplayConfig, $aDisplayData);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public function GetRenderContent(WebPage $oPage, $aExtraParams = array(), $sId)
|
||||
{
|
||||
$sHtml = '';
|
||||
return $sHtml;
|
||||
}
|
||||
|
||||
protected function RenderChart($oPage, $sId, $aValues, $sDrillDown = '', $aRows = array())
|
||||
{
|
||||
// 1- Compute Open Flash Chart data
|
||||
//
|
||||
$aValueKeys = array();
|
||||
$index = 0;
|
||||
if ((count($aValues) > 0) && ($sDrillDown != ''))
|
||||
{
|
||||
$oFilter = DBObjectSearch::FromOQL($sDrillDown);
|
||||
$sClass = $oFilter->GetClass();
|
||||
$sOQLClause = str_replace('SELECT '.$sClass, '', $sDrillDown);
|
||||
$aSQLColNames = array_keys(current($aRows)); // Read the list of columns from the current (i.e. first) element of the array
|
||||
$oAppContext = new ApplicationContext();
|
||||
$sURL = utils::GetAbsoluteUrlAppRoot().'pages/UI.php?operation=search_oql&search_form=0&oql_class='.$sClass.'&format=html&'.$oAppContext->GetForLink().'&oql_clause=';
|
||||
}
|
||||
$aURLs = array();
|
||||
foreach($aValues as $key => $value)
|
||||
{
|
||||
// Make sure that values are integers (so that max() will work....)
|
||||
// and build an array of STRING with the keys (numeric keys are transformed into string by PHP :-(
|
||||
$aValues[$key] = (int)$value;
|
||||
$aValueKeys[] = (string)$key;
|
||||
|
||||
// Build the custom query for the 'drill down' on each element
|
||||
if ($sDrillDown != '')
|
||||
{
|
||||
$sFilter = $sOQLClause;
|
||||
foreach($aSQLColNames as $sColName)
|
||||
{
|
||||
$sFilter = str_replace(':'.$sColName, "'".addslashes( $aRows[$key][$sColName] )."'", $sFilter);
|
||||
$aURLs[$index] = $sURL.urlencode($sFilter);
|
||||
}
|
||||
}
|
||||
$index++;
|
||||
}
|
||||
|
||||
$oChart = new open_flash_chart();
|
||||
|
||||
if ($this->m_sType == 'bars')
|
||||
{
|
||||
$oChartElement = new bar_glass();
|
||||
|
||||
if (count($aValues) > 0)
|
||||
{
|
||||
$maxValue = max($aValues);
|
||||
}
|
||||
else
|
||||
{
|
||||
$maxValue = 1;
|
||||
}
|
||||
$oYAxis = new y_axis();
|
||||
$aMagicValues = array(1,2,5,10);
|
||||
$iMultiplier = 1;
|
||||
$index = 0;
|
||||
$iTop = $aMagicValues[$index % count($aMagicValues)]*$iMultiplier;
|
||||
while($maxValue > $iTop)
|
||||
{
|
||||
$index++;
|
||||
$iTop = $aMagicValues[$index % count($aMagicValues)]*$iMultiplier;
|
||||
if (($index % count($aMagicValues)) == 0)
|
||||
{
|
||||
$iMultiplier = $iMultiplier * 10;
|
||||
}
|
||||
}
|
||||
//echo "oYAxis->set_range(0, $iTop, $iMultiplier);\n";
|
||||
$oYAxis->set_range(0, $iTop, $iMultiplier);
|
||||
$oChart->set_y_axis( $oYAxis );
|
||||
$aBarValues = array();
|
||||
foreach($aValues as $iValue)
|
||||
{
|
||||
$oBarValue = new bar_value($iValue);
|
||||
$oBarValue->on_click("ofc_drilldown_{$sId}");
|
||||
$aBarValues[] = $oBarValue;
|
||||
}
|
||||
$oChartElement->set_values($aBarValues);
|
||||
//$oChartElement->set_values(array_values($aValues));
|
||||
$oXAxis = new x_axis();
|
||||
$oXLabels = new x_axis_labels();
|
||||
// set them vertical
|
||||
$oXLabels->set_vertical();
|
||||
// set the label text
|
||||
$oXLabels->set_labels($aValueKeys);
|
||||
// Add the X Axis Labels to the X Axis
|
||||
$oXAxis->set_labels( $oXLabels );
|
||||
$oChart->set_x_axis( $oXAxis );
|
||||
}
|
||||
else
|
||||
{
|
||||
$oChartElement = new pie();
|
||||
$oChartElement->set_start_angle( 35 );
|
||||
$oChartElement->set_animate( true );
|
||||
$oChartElement->set_tooltip( '#label# - #val# (#percent#)' );
|
||||
$oChartElement->set_colours( array('#FF8A00', '#909980', '#2C2B33', '#CCC08D', '#596664') );
|
||||
|
||||
$aData = array();
|
||||
foreach($aValues as $sValue => $iValue)
|
||||
{
|
||||
$oPieValue = new pie_value($iValue, $sValue); //@@ BUG: not passed via ajax !!!
|
||||
$oPieValue->on_click("ofc_drilldown_{$sId}");
|
||||
$aData[] = $oPieValue;
|
||||
}
|
||||
|
||||
$oChartElement->set_values( $aData );
|
||||
$oChart->x_axis = null;
|
||||
}
|
||||
|
||||
// Title given in HTML
|
||||
//$oTitle = new title($this->m_sTitle);
|
||||
//$oChart->set_title($oTitle);
|
||||
$oChart->set_bg_colour('#FFFFFF');
|
||||
$oChart->add_element( $oChartElement );
|
||||
|
||||
$sData = $oChart->toPrettyString();
|
||||
$sData = json_encode($sData);
|
||||
|
||||
// 2- Declare the Javascript function that will render the chart data\
|
||||
//
|
||||
$oPage->add_script(
|
||||
<<< EOF
|
||||
function ofc_get_data_{$sId}()
|
||||
{
|
||||
return $sData;
|
||||
}
|
||||
EOF
|
||||
);
|
||||
|
||||
if (count($aURLs) > 0)
|
||||
{
|
||||
$sURLList = '';
|
||||
foreach($aURLs as $index => $sURL)
|
||||
{
|
||||
$sURLList .= "\taURLs[$index] = '".addslashes($sURL)."';\n";
|
||||
}
|
||||
|
||||
$oPage->add_script(
|
||||
<<< EOF
|
||||
function ofc_drilldown_{$sId}(index)
|
||||
{
|
||||
var aURLs = new Array();
|
||||
{$sURLList}
|
||||
var sURL = aURLs[index];
|
||||
|
||||
window.location.href = sURL; // Navigate !
|
||||
}
|
||||
EOF
|
||||
);
|
||||
}
|
||||
|
||||
// 3- Insert the Open Flash chart
|
||||
//
|
||||
$oPage->add("<div id=\"$sId\"><div>\n");
|
||||
$oPage->add_ready_script(
|
||||
<<<EOF
|
||||
swfobject.embedSWF( "../images/open-flash-chart.swf",
|
||||
"{$sId}",
|
||||
"100%", "300","9.0.0",
|
||||
"expressInstall.swf",
|
||||
{"get-data":"ofc_get_data_{$sId}", "id":"{$sId}"},
|
||||
{'wmode': 'transparent'}
|
||||
);
|
||||
EOF
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
@@ -35,7 +35,15 @@ class DisplayTemplate
|
||||
|
||||
public function __construct($sTemplate)
|
||||
{
|
||||
$this->m_aTags = array('itopblock', 'itopcheck', 'itoptabs', 'itoptab', 'itoptoggle', 'itopstring');
|
||||
$this->m_aTags = array (
|
||||
'itopblock',
|
||||
'itopcheck',
|
||||
'itoptabs',
|
||||
'itoptab',
|
||||
'itoptoggle',
|
||||
'itopstring',
|
||||
'sqlblock'
|
||||
);
|
||||
$this->m_sTemplate = $sTemplate;
|
||||
}
|
||||
|
||||
@@ -203,6 +211,11 @@ class DisplayTemplate
|
||||
$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;
|
||||
@@ -227,7 +240,6 @@ class DisplayTemplate
|
||||
<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">
|
||||
<itopblock blockclass="DisplayBlock" asynchronous="false" type="bare_details" encoding="text/oql">SELECT NetworkDevice AS d WHERE d.id = $id$</itopblock>
|
||||
<itoptabs>
|
||||
<itoptab name="Interfaces">
|
||||
<itopblock blockclass="DisplayBlock" type="list" encoding="text/oql">SELECT Interface AS i WHERE i.device_id = $id$</itopblock>
|
||||
@@ -248,6 +260,143 @@ class DisplayTemplate
|
||||
}
|
||||
}
|
||||
|
||||
//DisplayTemplate::UnitTest();
|
||||
/**
|
||||
* 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);
|
||||
$aTemplateFields = $aMatches[1];
|
||||
preg_match_all('/\\$this->field\\(([a-z0-9_]+)\\)\\$/', $this->m_sTemplate, $aMatches);
|
||||
$aTemplateFields = array_merge($aTemplateFields, $aMatches[1]);
|
||||
$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_$sInputId\" src=\"../images/transp-lock.png\" style=\"vertical-align:middle\"/>";
|
||||
$sTip = '';
|
||||
foreach($aReasons as $aRow)
|
||||
{
|
||||
$sTip .= "<p>Synchronized with {$aRow['name']} - {$aRow['description']}</p>";
|
||||
}
|
||||
$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();
|
||||
?>
|
||||
|
||||
@@ -38,11 +38,11 @@ class privUITransaction
|
||||
// Strictly speaking, the two lines below should be grouped together
|
||||
// by a critical section
|
||||
// sem_acquire($rSemIdentified);
|
||||
$id = 1 + count($_SESSION['transactions']);
|
||||
$id = str_replace(array('.', ' '), '', microtime()); //1 + count($_SESSION['transactions']);
|
||||
$_SESSION['transactions'][$id] = true;
|
||||
// sem_release($rSemIdentified);
|
||||
|
||||
return sprintf("%d", $id);
|
||||
return (string)$id;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -63,27 +63,34 @@ require_once(APPROOT.'/application/displayblock.class.inc.php');
|
||||
|
||||
class UIExtKeyWidget
|
||||
{
|
||||
protected static $iWidgetIndex = 0;
|
||||
protected $sAttCode;
|
||||
protected $sNameSuffix;
|
||||
protected $iId;
|
||||
protected $sTitle;
|
||||
protected $sTargetClass;
|
||||
protected $sAttCode;
|
||||
|
||||
public function __construct($sAttCode, $sClass, $sTitle, $aAllowedValues, $value, $iInputId, $bMandatory, $sNameSuffix = '', $sFieldPrefix = '', $sFormPrefix = '')
|
||||
//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)
|
||||
{
|
||||
self::$iWidgetIndex++;
|
||||
$this->sAttCode = $sAttCode;
|
||||
$this->sClass = $sClass;
|
||||
$this->oAttDef = MetaModel::GetAttributeDef($sClass, $sAttCode);
|
||||
$this->sNameSuffix = $sNameSuffix;
|
||||
$oAttDef = MetaModel::GetAttributeDef($sClass, $sAttCode);
|
||||
$sTargetClass = $oAttDef->GetTargetClass();
|
||||
$iMaxComboLength = $oAttDef->GetMaximumComboLength();
|
||||
$bAllowTargetCreation = $oAttDef->AllowTargetCreation();
|
||||
if (!$bSearchMode)
|
||||
{
|
||||
$sDisplayStyle = $oAttDef->GetDisplayStyle();
|
||||
}
|
||||
else
|
||||
{
|
||||
$sDisplayStyle = 'select'; // In search mode, always use a drop-down list
|
||||
}
|
||||
$oWidget = new UIExtKeyWidget($sTargetClass, $iInputId, $sAttCode);
|
||||
return $oWidget->Display($oPage, $iMaxComboLength, $bAllowTargetCreation, $sTitle, $oAllowedValues, $value, $iInputId, $bMandatory, $sFieldName, $sFormPrefix, $aArgs, $bSearchMode, $sDisplayStyle);
|
||||
}
|
||||
|
||||
public function __construct($sTargetClass, $iInputId, $sAttCode = '')
|
||||
{
|
||||
$this->sTargetClass = $sTargetClass;
|
||||
$this->iId = $iInputId;
|
||||
$this->aAllowedValues = $aAllowedValues;
|
||||
$this->value = $value;
|
||||
$this->sFieldPrefix = $sFieldPrefix;
|
||||
$this->sTargetClass = $this->oAttDef->GetTargetClass();
|
||||
$this->sTitle = $sTitle;
|
||||
$this->sFormPrefix = $sFormPrefix;
|
||||
$this->bMandatory = $bMandatory;
|
||||
$this->sAttCode = $sAttCode;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -92,121 +99,189 @@ class UIExtKeyWidget
|
||||
* @param Hash $aArgs Extra context arguments
|
||||
* @return string The HTML fragment to be inserted into the page
|
||||
*/
|
||||
public function Display(WebPage $oPage, $aArgs = array(), $bSearchMode = false)
|
||||
public function Display(WebPage $oPage, $iMaxComboLength, $bAllowTargetCreation, $sTitle, $oAllowedValues, $value, $iInputId, $bMandatory, $sFieldName, $sFormPrefix = '', $aArgs = array(), $bSearchMode = false, $sDisplayStyle = 'select')
|
||||
{
|
||||
$sTitle = addslashes($sTitle);
|
||||
$oPage->add_linked_script('../js/extkeywidget.js');
|
||||
$oPage->add_linked_script('../js/forms-json-utils.js');
|
||||
|
||||
$bCreate = (!$bSearchMode) && (!MetaModel::IsAbstract($this->sTargetClass)) && (UserRights::IsActionAllowed($this->sTargetClass, UR_ACTION_BULK_MODIFY) && $this->oAttDef->AllowTargetCreation());
|
||||
$bCreate = (!$bSearchMode) && (!MetaModel::IsAbstract($this->sTargetClass)) && (UserRights::IsActionAllowed($this->sTargetClass, UR_ACTION_BULK_MODIFY) && $bAllowTargetCreation);
|
||||
$bExtensions = true;
|
||||
$sMessage = Dict::S('UI:Message:EmptyList:UseSearchForm');
|
||||
$sAttrFieldPrefix = ($bSearchMode) ? '' : 'attr_';
|
||||
|
||||
$sHTMLValue = "<span style=\"white-space:nowrap\">"; // no wrap
|
||||
$sFilter = addslashes($oAllowedValues->GetFilter()->ToOQL());
|
||||
if($bSearchMode)
|
||||
{
|
||||
$sWizHelper = 'null';
|
||||
$sWizHelperJSON = "''";
|
||||
}
|
||||
else
|
||||
{
|
||||
$sWizHelper = 'oWizardHelper'.$this->sFormPrefix;
|
||||
$sWizHelper = 'oWizardHelper'.$sFormPrefix;
|
||||
$sWizHelperJSON = $sWizHelper.'.UpdateWizardToJSON()';
|
||||
}
|
||||
if (count($this->aAllowedValues) < $this->oAttDef->GetMaximumComboLength())
|
||||
if (is_null($oAllowedValues))
|
||||
{
|
||||
// Few choices, use a normal 'select'
|
||||
$sSelectMode = 'true';
|
||||
|
||||
$sHelpText = $this->oAttDef->GetHelpOnEdition();
|
||||
|
||||
// In case there are no valid values, the select will be empty, thus blocking the user from validating the form
|
||||
$sHTMLValue = "<select title=\"$sHelpText\" name=\"{$sAttrFieldPrefix}{$this->sFieldPrefix}{$this->sAttCode}{$this->sNameSuffix}\" id=\"$this->iId\">\n";
|
||||
if ($bSearchMode)
|
||||
throw new Exception('Implementation: null value for allowed values definition');
|
||||
}
|
||||
elseif ($oAllowedValues->Count() < $iMaxComboLength)
|
||||
{
|
||||
// Discrete list of values, use a SELECT or RADIO buttons depending on the config
|
||||
switch($sDisplayStyle)
|
||||
{
|
||||
$sHTMLValue .= "<option value=\"\">".Dict::S('UI:SearchValue:Any')."</option>\n";
|
||||
}
|
||||
else
|
||||
{
|
||||
$sHTMLValue .= "<option value=\"\">".Dict::S('UI:SelectOne')."</option>\n";
|
||||
}
|
||||
foreach($this->aAllowedValues as $key => $display_value)
|
||||
{
|
||||
if ((count($this->aAllowedValues) == 1) && ($this->bMandatory == 'true') )
|
||||
case 'radio':
|
||||
case 'radio_horizontal':
|
||||
case 'radio_vertical':
|
||||
$sValidationField = "<span id=\"v_{$this->iId}\"></span>";
|
||||
$sHTMLValue = '';
|
||||
$bVertical = ($sDisplayStyle != 'radio_horizontal');
|
||||
$bExtensions = false;
|
||||
$oAllowedValues->Rewind();
|
||||
$aAllowedValues = array();
|
||||
while($oObj = $oAllowedValues->Fetch())
|
||||
{
|
||||
// When there is only once choice, select it by default
|
||||
$sSelected = ' selected';
|
||||
$aAllowedValues[$oObj->GetKey()] = $oObj->GetName();
|
||||
}
|
||||
$sHTMLValue = $oPage->GetRadioButtons($aAllowedValues, $value, $this->iId, "{$sAttrFieldPrefix}{$sFieldName}", $bMandatory, $bVertical, $sValidationField);
|
||||
$aEventsList[] ='change';
|
||||
break;
|
||||
|
||||
case 'select':
|
||||
default:
|
||||
$sSelectMode = 'true';
|
||||
|
||||
$sHelpText = ''; //$this->oAttDef->GetHelpOnEdition();
|
||||
|
||||
$sHTMLValue = "<select title=\"$sHelpText\" name=\"{$sAttrFieldPrefix}{$sFieldName}\" id=\"$this->iId\">\n";
|
||||
if ($bSearchMode)
|
||||
{
|
||||
$sDisplayValue = isset($aArgs['sDefaultValue']) ? $aArgs['sDefaultValue'] : Dict::S('UI:SearchValue:Any');
|
||||
$sHTMLValue .= "<option value=\"\">$sDisplayValue</option>\n";
|
||||
}
|
||||
else
|
||||
{
|
||||
$sSelected = ($this->value == $key) ? ' selected' : '';
|
||||
$sHTMLValue .= "<option value=\"\">".Dict::S('UI:SelectOne')."</option>\n";
|
||||
}
|
||||
$sHTMLValue .= "<option value=\"$key\"$sSelected>$display_value</option>\n";
|
||||
}
|
||||
$sHTMLValue .= "</select>\n";
|
||||
$oPage->add_ready_script(
|
||||
$oAllowedValues->Rewind();
|
||||
while($oObj = $oAllowedValues->Fetch())
|
||||
{
|
||||
$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';
|
||||
}
|
||||
else
|
||||
{
|
||||
$sSelected = ($value == $key) ? ' selected' : '';
|
||||
}
|
||||
$sHTMLValue .= "<option value=\"$key\"$sSelected>$display_value</option>\n";
|
||||
}
|
||||
$sHTMLValue .= "</select>\n";
|
||||
$oPage->add_ready_script(
|
||||
<<<EOF
|
||||
oACWidget_{$this->iId} = new ExtKeyWidget('{$this->iId}', '{$this->sClass}', '{$this->sAttCode}', '{$this->sNameSuffix}', $sSelectMode, $sWizHelper);
|
||||
oACWidget_{$this->iId} = new ExtKeyWidget('{$this->iId}', '{$this->sTargetClass}', '$sFilter', '$sTitle', true, $sWizHelper, '{$this->sAttCode}');
|
||||
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') } );
|
||||
|
||||
EOF
|
||||
);
|
||||
);
|
||||
} // Switch
|
||||
}
|
||||
else
|
||||
{
|
||||
// Too many choices, use an autocomplete
|
||||
$sSelectMode = 'false';
|
||||
|
||||
if ($this->oAttDef->IsNull($this->value)) // Null values are displayed as ''
|
||||
if (is_null($value) || ($value == 0)) // Null values are displayed as ''
|
||||
{
|
||||
$sDisplayValue = '';
|
||||
$sDisplayValue = isset($aArgs['sDefaultValue']) ? $aArgs['sDefaultValue'] : '';
|
||||
}
|
||||
else
|
||||
{
|
||||
$sDisplayValue = $this->GetObjectName($this->value);
|
||||
$sDisplayValue = $this->GetObjectName($value);
|
||||
}
|
||||
$sFormPrefix = $this->sFormPrefix;
|
||||
$iMinChars = $this->oAttDef->GetMinAutoCompleteChars();
|
||||
$iFieldSize = $this->oAttDef->GetMaxSize();
|
||||
$iMinChars = isset($aArgs['iMinChars']) ? $aArgs['iMinChars'] : 3; //@@@ $this->oAttDef->GetMinAutoCompleteChars();
|
||||
$iFieldSize = isset($aArgs['iFieldSize']) ? $aArgs['iFieldSize'] : 30; //@@@ $this->oAttDef->GetMaxSize();
|
||||
|
||||
// the input for the auto-complete
|
||||
$sHTMLValue = "<input count=\"".count($this->aAllowedValues)."\" type=\"text\" id=\"label_$this->iId\" size=\"30\" maxlength=\"$iFieldSize\" value=\"$sDisplayValue\"/> ";
|
||||
$sHTMLValue .= "<a class=\"no-arrow\" href=\"javascript:oACWidget_{$this->iId}.Search();\"><img id=\"mini_search_{$this->iId}\" style=\"border:0;vertical-align:middle;\" src=\"../images/mini_search.gif\" /></a> ";
|
||||
$sHTMLValue = "<input count=\"".$oAllowedValues->Count()."\" type=\"text\" id=\"label_$this->iId\" size=\"$iFieldSize\" value=\"$sDisplayValue\"/> ";
|
||||
$sHTMLValue .= "<img id=\"mini_search_{$this->iId}\" style=\"border:0;vertical-align:middle;cursor:pointer;\" src=\"../images/mini_search.gif\" onClick=\"oACWidget_{$this->iId}.Search();\"/> ";
|
||||
|
||||
// another hidden input to store & pass the object's Id
|
||||
$sHTMLValue .= "<input type=\"hidden\" id=\"$this->iId\" name=\"{$sAttrFieldPrefix}{$this->sFieldPrefix}{$this->sAttCode}{$this->sNameSuffix}\" value=\"$this->value\" />\n";
|
||||
$sHTMLValue .= "<input type=\"hidden\" id=\"$this->iId\" name=\"{$sAttrFieldPrefix}{$sFieldName}\" value=\"$value\" />\n";
|
||||
|
||||
// Scripts to start the autocomplete and bind some events to it
|
||||
$oPage->add_ready_script(
|
||||
<<<EOF
|
||||
oACWidget_{$this->iId} = new ExtKeyWidget('{$this->iId}', '{$this->sClass}', '{$this->sAttCode}', '{$this->sNameSuffix}', $sSelectMode, $sWizHelper);
|
||||
oACWidget_{$this->iId} = new ExtKeyWidget('{$this->iId}', '{$this->sTargetClass}', '$sFilter', '$sTitle', false, $sWizHelper, '{$this->sAttCode}');
|
||||
oACWidget_{$this->iId}.emptyHtml = "<div style=\"background: #fff; border:0; text-align:center; vertical-align:middle;\"><p>$sMessage</p></div>";
|
||||
$('#label_$this->iId').autocomplete('./ajax.render.php', { scroll:true, minChars:{$iMinChars}, formatItem:formatItem, autoFill:false, matchContains:true, keyHolder:'#{$this->iId}', extraParams:{operation:'autocomplete', sclass:'{$this->sClass}',attCode:'{$this->sAttCode}'}});
|
||||
$('#label_$this->iId').blur(function() { $(this).search(); } );
|
||||
$('#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', json: function() { return $sWizHelperJSON; } }});
|
||||
$('#label_$this->iId').keyup(function() { if ($(this).val() == '') { $('#$this->iId').val(''); } } ); // Useful for search forms: empty value in the "label", means no value, immediatly !
|
||||
$('#label_$this->iId').result( function(event, data, formatted) { OnAutoComplete('{$this->iId}', event, data, formatted); } );
|
||||
$('#$this->iId').bind('update', function() { oACWidget_{$this->iId}.Update(); } );
|
||||
if ($('#ac_dlg_{$this->iId}').length == 0)
|
||||
{
|
||||
$('body').append('<div id="ac_dlg_{$this->iId}"></div>');
|
||||
}
|
||||
EOF
|
||||
);
|
||||
//$oPage->add_at_the_end($this->GetSearchDialog($oPage)); // To prevent adding forms inside the main form
|
||||
$oPage->add_at_the_end('<div id="ac_dlg_'.$this->iId.'"></div>'); // The place where to download the search dialog is outside of the main form (to prevent nested forms)
|
||||
|
||||
}
|
||||
if ($bCreate)
|
||||
if ($bExtensions && MetaModel::IsHierarchicalClass($this->sTargetClass) !== false)
|
||||
{
|
||||
$sHTMLValue .= "<a class=\"no-arrow\" href=\"javascript:oACWidget_{$this->iId}.CreateObject();\"><img id=\"mini_add_{$this->iId}\" style=\"border:0;vertical-align:middle;\" src=\"../images/mini_add.gif\" /></a> ";
|
||||
$oPage->add_at_the_end('<div id="ajax_'.$this->iId.'"></div>');
|
||||
$sHTMLValue .= "<img id=\"mini_tree_{$this->iId}\" style=\"border:0;vertical-align:middle;cursor:pointer;\" src=\"../images/mini_tree.gif\" onClick=\"oACWidget_{$this->iId}.HKDisplay();\"/> ";
|
||||
$oPage->add_ready_script(
|
||||
<<<EOF
|
||||
if ($('#ac_tree_{$this->iId}').length == 0)
|
||||
{
|
||||
$('body').append('<div id="ac_tree_{$this->iId}"></div>');
|
||||
}
|
||||
EOF
|
||||
);
|
||||
}
|
||||
if ($bCreate && $bExtensions)
|
||||
{
|
||||
$sHTMLValue .= "<img id=\"mini_add_{$this->iId}\" style=\"border:0;vertical-align:middle;cursor:pointer;\" src=\"../images/mini_add.gif\" onClick=\"oACWidget_{$this->iId}.CreateObject();\"/> ";
|
||||
$oPage->add_ready_script(
|
||||
<<<EOF
|
||||
if ($('#ajax_{$this->iId}').length == 0)
|
||||
{
|
||||
$('body').append('<div id="ajax_{$this->iId}"></div>');
|
||||
}
|
||||
EOF
|
||||
);
|
||||
}
|
||||
if ($sDisplayStyle == 'select')
|
||||
{
|
||||
$sHTMLValue .= "<span id=\"v_{$this->iId}\"></span>";
|
||||
}
|
||||
$sHTMLValue .= "<span id=\"v_{$this->iId}\"></span>";
|
||||
$sHTMLValue .= "</span>"; // end of no wrap
|
||||
return $sHTMLValue;
|
||||
}
|
||||
|
||||
public function GetSearchDialog(WebPage $oPage)
|
||||
public function GetSearchDialog(WebPage $oPage, $sTitle, $oCurrObject = null)
|
||||
{
|
||||
$sHTML = '<div class="wizContainer" style="vertical-align:top;"><div id="dc_'.$this->iId.'">';
|
||||
|
||||
$oFilter = new DBObjectSearch($this->sTargetClass);
|
||||
$oSet = new CMDBObjectSet($oFilter);
|
||||
$oBlock = new DisplayBlock($oFilter, 'search', false);
|
||||
if ( ($oCurrObject != null) && ($this->sAttCode != ''))
|
||||
{
|
||||
$oAttDef = MetaModel::GetAttributeDef(get_class($oCurrObject), $this->sAttCode);
|
||||
$aParams = array('query_params' => array('this' => $oCurrObject));
|
||||
$oSet = $oAttDef->GetAllowedValuesAsObjectSet($aParams);
|
||||
$oFilter = $oSet->GetFilter();
|
||||
}
|
||||
else
|
||||
{
|
||||
$aParam = array();
|
||||
$oFilter = new DBObjectSearch($this->sTargetClass);
|
||||
$oSet = new CMDBObjectSet($oFilter);
|
||||
}
|
||||
$oBlock = new DisplayBlock($oFilter, 'search', false, $aParams);
|
||||
$sHTML .= $oBlock->GetDisplay($oPage, $this->iId, array('open' => true, 'currentId' => $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";
|
||||
@@ -214,10 +289,11 @@ EOF
|
||||
$sHTML .= "</div>\n";
|
||||
$sHTML .= "<input type=\"button\" id=\"btn_cancel_{$this->iId}\" value=\"".Dict::S('UI:Button:Cancel')."\" onClick=\"$('#ac_dlg_{$this->iId}').dialog('close');\"> ";
|
||||
$sHTML .= "<input type=\"button\" id=\"btn_ok_{$this->iId}\" value=\"".Dict::S('UI:Button:Ok')."\" onClick=\"oACWidget_{$this->iId}.DoOk();\">";
|
||||
$sHTML .= "<input type=\"hidden\" id=\"count_{$this->iId}\" value=\"0\">";
|
||||
$sHTML .= "</form>\n";
|
||||
$sHTML .= '</div></div>';
|
||||
|
||||
$sDialogTitle = addslashes($this->sTitle);
|
||||
$sDialogTitle = addslashes($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 });
|
||||
@@ -234,22 +310,48 @@ EOF
|
||||
* @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
|
||||
*/
|
||||
public function SearchObjectsToSelect(WebPage $oP, $sTargetClass = '')
|
||||
public function SearchObjectsToSelect(WebPage $oP, $sFilter, $sRemoteClass = '', $oObj = null)
|
||||
{
|
||||
if ($sTargetClass != '')
|
||||
if (is_null($sFilter))
|
||||
{
|
||||
// assert(MetaModel::IsParentClass($this->m_sRemoteClass, $sRemoteClass));
|
||||
$oFilter = new DBObjectSearch($sTargetClass);
|
||||
throw new Exception('Implementation: null value for allowed values definition');
|
||||
}
|
||||
else
|
||||
try
|
||||
{
|
||||
// No remote class specified use the one defined in the linkedset
|
||||
$oFilter = new DBObjectSearch($this->sTargetClass);
|
||||
$oFilter = DBObjectSearch::FromOQL($sFilter);
|
||||
$oBlock = new DisplayBlock($oFilter, 'list', false, array('query_params' => array('this' => $oObj)));
|
||||
$oBlock->Display($oP, $this->iId.'_results', array('this' => $oObj, 'cssCount'=> '#count_'.$this->iId, 'menu' => false, 'selection_mode' => true, 'selection_type' => 'single')); // Don't display the 'Actions' menu on the results
|
||||
}
|
||||
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 '.$sRemoteClass;
|
||||
$oFilter = DBObjectSearch::FromOQL($sOQL);
|
||||
//$oBlock = new DisplayBlock($oFilter, 'list', false);
|
||||
//$oBlock->Display($oP, $this->iId.'_results', array('cssCount'=> '#count_'.$this->iId, 'menu' => false, 'selection_mode' => true, 'selection_type' => 'single')); // 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)
|
||||
{
|
||||
if (is_null($sFilter))
|
||||
{
|
||||
throw new Exception('Implementation: null value for allowed values definition');
|
||||
}
|
||||
$oValuesSet = new ValueSetObjects($sFilter, 'friendlyname'); // Bypass GetName() to avoid the encoding by htmlentities
|
||||
$aValues = $oValuesSet->GetValues(array('this' => $oObj), $sContains);
|
||||
foreach($aValues as $sKey => $sFriendlyName)
|
||||
{
|
||||
$oP->add(trim($sFriendlyName)."\t".$sKey."\n");
|
||||
}
|
||||
$oFilter->AddCondition('id', array_keys($this->aAllowedValues), 'IN');
|
||||
$oSet = new CMDBObjectSet($oFilter);
|
||||
$oBlock = new DisplayBlock($oFilter, 'list', false);
|
||||
$oBlock->Display($oP, $this->iId, array('menu' => false, 'selection_mode' => true, 'selection_type' => 'single', 'display_limit' => false)); // Don't display the 'Actions' menu on the results
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -264,12 +366,39 @@ EOF
|
||||
/**
|
||||
* Get the form to create a new object of the 'target' class
|
||||
*/
|
||||
public function GetObjectCreationForm(WebPage $oPage)
|
||||
public function GetObjectCreationForm(WebPage $oPage, $oCurrObject)
|
||||
{
|
||||
// Set all the default values in an object and clone this "default" object
|
||||
$oNewObj = MetaModel::NewObject($this->sTargetClass);
|
||||
|
||||
// 1st - set context values
|
||||
$oAppContext = new ApplicationContext();
|
||||
$oAppContext->InitObjectFromContext($oNewObj);
|
||||
|
||||
// 2nd set the default values from the constraint on the external key... if any
|
||||
if ( ($oCurrObject != null) && ($this->sAttCode != ''))
|
||||
{
|
||||
$oAttDef = MetaModel::GetAttributeDef(get_class($oCurrObject), $this->sAttCode);
|
||||
$aParams = array('this' => $oCurrObject);
|
||||
$oSet = $oAttDef->GetAllowedValuesAsObjectSet($aParams);
|
||||
$aConsts = $oSet->ListConstantFields();
|
||||
$sClassAlias = $oSet->GetFilter()->GetClassAlias();
|
||||
if (isset($aConsts[$sClassAlias]))
|
||||
{
|
||||
foreach($aConsts[$sClassAlias] as $sAttCode => $value)
|
||||
{
|
||||
$oNewObj->Set($sAttCode, $value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 3rd - set values from the page argument 'default'
|
||||
$oNewObj->UpdateObjectFromArg('default');
|
||||
|
||||
$sDialogTitle = addslashes($this->sTitle);
|
||||
$oPage->add('<div id="ac_create_'.$this->iId.'"><div class="wizContainer" style="vertical-align:top;"><div id="dcr_'.$this->iId.'">');
|
||||
$oPage->add("<h1>".MetaModel::GetClassIcon($this->sTargetClass)." ".Dict::Format('UI:CreationTitle_Class', MetaModel::GetName($this->sTargetClass))."</h1>\n");
|
||||
cmdbAbstractObject::DisplayCreationForm($oPage, $this->sTargetClass, null, array(), array('formPrefix' => $this->iId, 'noRelations' => true));
|
||||
cmdbAbstractObject::DisplayCreationForm($oPage, $this->sTargetClass, $oNewObj, array(), array('formPrefix' => $this->iId, 'noRelations' => true));
|
||||
$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', autoOpen: false, modal: true, title: '$sDialogTitle'});\n");
|
||||
@@ -277,13 +406,52 @@ EOF
|
||||
$oPage->add_ready_script("$('#dcr_{$this->iId} form').bind('submit.uilinksWizard', oACWidget_{$this->iId}.DoCreateObject);");
|
||||
}
|
||||
|
||||
/**
|
||||
* Display the hierarchy of the 'target' class
|
||||
*/
|
||||
public function DisplayHierarchy(WebPage $oPage, $sFilter, $currValue, $oObj)
|
||||
{
|
||||
$sDialogTitle = addslashes(Dict::Format('UI:HierarchyOf_Class', MetaModel::GetName($this->sTargetClass)));
|
||||
$oPage->add('<div id="dlg_tree_'.$this->iId.'"><div class="wizContainer" style="vertical-align:top;"><div style="overflow:auto;background:#fff;margin-bottom:5px;" id="tree_'.$this->iId.'">');
|
||||
$oPage->add('<table style="width:100%"><tr><td>');
|
||||
if (is_null($sFilter))
|
||||
{
|
||||
throw new Exception('Implementation: null value for allowed values definition');
|
||||
}
|
||||
try
|
||||
{
|
||||
$oFilter = DBObjectSearch::FromOQL($sFilter);
|
||||
$oSet = new DBObjectSet($oFilter, array(), array('this' => $oObj));
|
||||
}
|
||||
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);
|
||||
$oSet = new DBObjectSet($oFilter);
|
||||
}
|
||||
|
||||
$sHKAttCode = MetaModel::IsHierarchicalClass($this->sTargetClass);
|
||||
$this->DumpTree($oPage, $oSet, $sHKAttCode, $currValue);
|
||||
|
||||
$oPage->add('</td></tr></table>');
|
||||
$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");
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the form to create a new object of the 'target' class
|
||||
*/
|
||||
public function DoCreateObject($oPage)
|
||||
{
|
||||
$oObj = MetaModel::NewObject($this->sTargetClass);
|
||||
$aErrors = $oObj->UpdateObject($this->sFormPrefix.$this->iId);
|
||||
$aErrors = $oObj->UpdateObjectFromPostedForm($this->iId);
|
||||
if (count($aErrors) == 0)
|
||||
{
|
||||
$oMyChange = MetaModel::NewObject("CMDBChange");
|
||||
@@ -299,5 +467,68 @@ EOF
|
||||
return array('name' => implode(' ', $aErrors), 'id' => 0);
|
||||
}
|
||||
}
|
||||
|
||||
function DumpTree($oP, $oSet, $sParentAttCode, $currValue)
|
||||
{
|
||||
$aTree = array();
|
||||
$aNodes = array();
|
||||
while($oObj = $oSet->Fetch())
|
||||
{
|
||||
$iParentId = $oObj->Get($sParentAttCode);
|
||||
if (!isset($aTree[$iParentId]))
|
||||
{
|
||||
$aTree[$iParentId] = array();
|
||||
}
|
||||
$aTree[$iParentId][$oObj->GetKey()] = $oObj->GetName();
|
||||
$aNodes[$oObj->GetKey()] = $oObj;
|
||||
}
|
||||
|
||||
$aParents = array_keys($aTree);
|
||||
$aRoots = array();
|
||||
foreach($aParents as $id)
|
||||
{
|
||||
if (!array_key_exists($id, $aNodes))
|
||||
{
|
||||
$aRoots[] = $id;
|
||||
}
|
||||
}
|
||||
foreach($aRoots as $iRootId)
|
||||
{
|
||||
$this->DumpNodes($oP, $iRootId, $aTree, $aNodes, $currValue);
|
||||
}
|
||||
}
|
||||
|
||||
function DumpNodes($oP, $iRootId, $aTree, $aNodes, $currValue)
|
||||
{
|
||||
$bSelect = true;
|
||||
$bMultiple = false;
|
||||
$sSelect = '';
|
||||
if (array_key_exists($iRootId, $aTree))
|
||||
{
|
||||
$aSortedRoots = $aTree[$iRootId];
|
||||
asort($aSortedRoots);
|
||||
$oP->add("<ul>\n");
|
||||
foreach($aSortedRoots as $id => $sName)
|
||||
{
|
||||
if ($bSelect)
|
||||
{
|
||||
$sChecked = ($aNodes[$id]->GetKey() == $currValue) ? 'checked' : '';
|
||||
if ($bMultiple)
|
||||
{
|
||||
$sSelect = '<input type="checkbox" value="'.$aNodes[$id]->GetKey().'" name="selectObject[]" '.$sChecked.'> ';
|
||||
}
|
||||
else
|
||||
{
|
||||
$sSelect = '<input type="radio" value="'.$aNodes[$id]->GetKey().'" name="selectObject" '.$sChecked.'> ';
|
||||
}
|
||||
}
|
||||
$oP->add('<li>'.$sSelect.$aNodes[$id]->GetHyperlink());
|
||||
$this->DumpNodes($oP, $id, $aTree, $aNodes, $currValue);
|
||||
$oP->add("</li>\n");
|
||||
}
|
||||
$oP->add("</ul>\n");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
?>
|
||||
|
||||
@@ -34,6 +34,7 @@ class UILinksWidget
|
||||
protected $m_iInputId;
|
||||
protected $m_aAttributes;
|
||||
protected $m_sExtKeyToRemote;
|
||||
protected $m_sExtKeyToMe;
|
||||
protected $m_sLinkedClass;
|
||||
protected $m_sRemoteClass;
|
||||
protected $m_bDuplicatesAllowed;
|
||||
@@ -50,6 +51,7 @@ class UILinksWidget
|
||||
$oAttDef = MetaModel::GetAttributeDef($this->m_sClass, $this->m_sAttCode);
|
||||
$this->m_sLinkedClass = $oAttDef->GetLinkedClass();
|
||||
$this->m_sExtKeyToRemote = $oAttDef->GetExtKeyToRemote();
|
||||
$this->m_sExtKeyToMe = $oAttDef->GetExtKeyToMe();
|
||||
$oLinkingAttDef = MetaModel::GetAttributeDef($this->m_sLinkedClass, $this->m_sExtKeyToRemote);
|
||||
$this->m_sRemoteClass = $oLinkingAttDef->GetTargetClass();
|
||||
$sExtKeyToMe = $oAttDef->GetExtKeyToMe();
|
||||
@@ -97,7 +99,7 @@ class UILinksWidget
|
||||
* @param Hash $aArgs Extra context arguments
|
||||
* @return string The HTML fragment of the one-row form
|
||||
*/
|
||||
protected function GetFormRow(WebPage $oP, DBObject $oLinkedObj, $linkObjOrId = null, $aArgs = array() )
|
||||
protected function GetFormRow(WebPage $oP, DBObject $oLinkedObj, $linkObjOrId = null, $aArgs = array(), $oCurrentObj )
|
||||
{
|
||||
$sPrefix = "$this->m_sAttCode{$this->m_sNameSuffix}";
|
||||
$aRow = array();
|
||||
@@ -107,6 +109,7 @@ class UILinksWidget
|
||||
$sPrefix .= "[$key][";
|
||||
$sNameSuffix = "]"; // To make a tabular form
|
||||
$aArgs['prefix'] = $sPrefix;
|
||||
$aArgs['this'] = $linkObjOrId;
|
||||
$aRow['form::checkbox'] = "<input class=\"selection\" type=\"checkbox\" onClick=\"oWidget".$this->m_iInputId.".OnSelectChange();\" value=\"$key\">";
|
||||
$aRow['form::checkbox'] .= "<input type=\"hidden\" name=\"attr_{$sPrefix}id{$sNameSuffix}\" value=\"$key\">";
|
||||
foreach($this->m_aEditableFields as $sFieldCode)
|
||||
@@ -121,8 +124,13 @@ class UILinksWidget
|
||||
{
|
||||
// form for creating a new record
|
||||
$sPrefix .= "[$linkObjOrId][";
|
||||
$oNewLinkObj = MetaModel::NewObject($this->m_sLinkedClass);
|
||||
$oRemoteObj = MetaModel::GetObject($this->m_sRemoteClass, -$linkObjOrId);
|
||||
$oNewLinkObj->Set($this->m_sExtKeyToRemote, $oRemoteObj); // Setting the extkey with the object alsoo fills the related external fields
|
||||
$oNewLinkObj->Set($this->m_sExtKeyToMe, $oCurrentObj); // Setting the extkey with the object alsoo fills the related external fields
|
||||
$sNameSuffix = "]"; // To make a tabular form
|
||||
$aArgs['prefix'] = $sPrefix;
|
||||
$aArgs['this'] = $oNewLinkObj;
|
||||
$aRow['form::checkbox'] = "<input class=\"selection\" type=\"checkbox\" onClick=\"oWidget".$this->m_iInputId.".OnSelectChange();\" value=\"$linkObjOrId\">";
|
||||
$aRow['form::checkbox'] .= "<input type=\"hidden\" name=\"attr_{$sPrefix}id{$sNameSuffix}\" value=\"\">";
|
||||
foreach($this->m_aEditableFields as $sFieldCode)
|
||||
@@ -182,17 +190,17 @@ class UILinksWidget
|
||||
|
||||
// Content
|
||||
$sHtml .= "</tbody>\n";
|
||||
if (count($aData) == 0)
|
||||
$sEmptyRowStyle = '';
|
||||
if (count($aData) != 0)
|
||||
{
|
||||
$sHtml .= "<tr id=\"{$this->m_sAttCode}{$this->m_sNameSuffix}_empty_row\"><td colspan=\"".count($aConfig)."\" style=\"text-align:center;\">".Dict::S('UI:Message:EmptyList:UseAdd')."<input type=\"hidden\" name=\"attr_{$this->m_sAttCode}{$this->m_sNameSuffix}\" value=\"\"></td></td>";
|
||||
$sEmptyRowStyle = 'style="display:none;"';
|
||||
}
|
||||
else
|
||||
|
||||
$sHtml .= "<tr $sEmptyRowStyle id=\"{$this->m_sAttCode}{$this->m_sNameSuffix}_empty_row\"><td colspan=\"".count($aConfig)."\" style=\"text-align:center;\">".Dict::S('UI:Message:EmptyList:UseAdd')."<input type=\"hidden\" name=\"attr_{$this->m_sAttCode}{$this->m_sNameSuffix}\" value=\"\"></td></td>";
|
||||
foreach($aData as $iRowId => $aRow)
|
||||
{
|
||||
foreach($aData as $iRowId => $aRow)
|
||||
{
|
||||
$sHtml .= $this->DisplayFormRow($oP, $aConfig, $aRow, $iRowId);
|
||||
}
|
||||
}
|
||||
$sHtml .= $this->DisplayFormRow($oP, $aConfig, $aRow, $iRowId);
|
||||
}
|
||||
$sHtml .= "</tbody>\n";
|
||||
|
||||
// Footer
|
||||
@@ -207,9 +215,11 @@ class UILinksWidget
|
||||
* @param WebPage $oP The web page used for all the output
|
||||
* @param DBObjectSet The initial value of the linked set
|
||||
* @param Hash $aArgs Extra context arguments
|
||||
* @param string $sFormPrefix prefix of the fields in the current form
|
||||
* @param DBObject $oCurrentObj the current object to which the linkset is related
|
||||
* @return string The HTML fragment to be inserted into the page
|
||||
*/
|
||||
public function Display(WebPage $oPage, DBObjectSet $oValue, $aArgs = array())
|
||||
public function Display(WebPage $oPage, DBObjectSet $oValue, $aArgs = array(), $sFormPrefix, $oCurrentObj)
|
||||
{
|
||||
$sHtmlValue = '';
|
||||
$sTargetClass = self::GetTargetClass($this->m_sClass, $this->m_sAttCode);
|
||||
@@ -219,23 +229,32 @@ class UILinksWidget
|
||||
while($oCurrentLink = $oValue->Fetch())
|
||||
{
|
||||
$aRow = array();
|
||||
$key = $oCurrentLink->GetKey();
|
||||
$oLinkedObj = MetaModel::GetObject($this->m_sRemoteClass, $oCurrentLink->Get($this->m_sExtKeyToRemote));
|
||||
if ($oCurrentLink->IsNew())
|
||||
{
|
||||
$key = -$oLinkedObj->GetKey();
|
||||
$aForm[$key] = $this->GetFormRow($oPage, $oLinkedObj, $key, $aArgs, $oCurrentObj);
|
||||
}
|
||||
else
|
||||
{
|
||||
$key = $oCurrentLink->GetKey();
|
||||
$aForm[$key] = $this->GetFormRow($oPage, $oLinkedObj, $oCurrentLink, $aArgs, $oCurrentObj);
|
||||
}
|
||||
|
||||
$aForm[$key] = $this->GetFormRow($oPage, $oLinkedObj, $oCurrentLink, $aArgs);
|
||||
}
|
||||
$sHtmlValue .= $this->DisplayFormTable($oPage, $this->m_aTableConfig, $aForm);
|
||||
$sDuplicates = ($this->m_bDuplicatesAllowed) ? 'true' : 'false';
|
||||
$sWizHelper = 'oWizardHelper'.$sFormPrefix;
|
||||
$oPage->add_ready_script(<<<EOF
|
||||
oWidget{$this->m_iInputId} = new LinksWidget('{$this->m_sAttCode}{$this->m_sNameSuffix}', '{$this->m_sClass}', '{$this->m_sAttCode}', '{$this->m_iInputId}', '{$this->m_sNameSuffix}', $sDuplicates);
|
||||
oWidget{$this->m_iInputId} = new LinksWidget('{$this->m_sAttCode}{$this->m_sNameSuffix}', '{$this->m_sClass}', '{$this->m_sAttCode}', '{$this->m_iInputId}', '{$this->m_sNameSuffix}', $sDuplicates, $sWizHelper);
|
||||
oWidget{$this->m_iInputId}.Init();
|
||||
EOF
|
||||
);
|
||||
$sHtmlValue .= "<span style=\"float:left;\"> <img src=\"../images/tv-item-last.gif\"> <input id=\"{$this->m_sAttCode}{$this->m_sNameSuffix}_btnRemove\" type=\"button\" value=\"".Dict::S('UI:RemoveLinkedObjectsOf_Class')."\" onClick=\"oWidget{$this->m_iInputId}.RemoveSelected();\" >";
|
||||
$sHtmlValue .= " <input id=\"{$this->m_sAttCode}{$this->m_sNameSuffix}_btnAdd\" type=\"button\" value=\"".Dict::Format('UI:AddLinkedObjectsOf_Class', MetaModel::GetName($this->m_sRemoteClass))."\" onClick=\"oWidget{$this->m_iInputId}.AddObjects();\"></span>\n";
|
||||
$sHtmlValue .= " <input id=\"{$this->m_sAttCode}{$this->m_sNameSuffix}_btnAdd\" type=\"button\" value=\"".Dict::Format('UI:AddLinkedObjectsOf_Class', MetaModel::GetName($this->m_sRemoteClass))."\" onClick=\"oWidget{$this->m_iInputId}.AddObjects();\"><span id=\"{$this->m_sAttCode}{$this->m_sNameSuffix}_indicatorAdd\"></span></span>\n";
|
||||
$sHtmlValue .= "<span style=\"clear:both;\"><p> </p></span>\n";
|
||||
$sHtmlValue .= "</div>\n";
|
||||
$oPage->add_at_the_end($this->GetObjectPickerDialog($oPage)); // To prevent adding forms inside the main form
|
||||
$oPage->add_at_the_end("<div id=\"dlg_{$this->m_sAttCode}{$this->m_sNameSuffix}\"></div>"); // To prevent adding forms inside the main form
|
||||
return $sHtmlValue;
|
||||
}
|
||||
|
||||
@@ -258,27 +277,26 @@ EOF
|
||||
return $sTargetClass;
|
||||
}
|
||||
|
||||
protected function GetObjectPickerDialog($oPage)
|
||||
public function GetObjectPickerDialog($oPage, $oCurrentObj)
|
||||
{
|
||||
$sHtml = "<div id=\"dlg_{$this->m_sAttCode}{$this->m_sNameSuffix}\">";
|
||||
$sHtml .= "<div class=\"wizContainer\" style=\"vertical-align:top;\">\n";
|
||||
$sHtml = "<div class=\"wizContainer\" style=\"vertical-align:top;\">\n";
|
||||
$oFilter = new DBObjectSearch($this->m_sRemoteClass);
|
||||
$oSet = new CMDBObjectSet($oFilter);
|
||||
$this->SetSearchDefaultFromContext($oCurrentObj, $oFilter);
|
||||
$oBlock = new DisplayBlock($oFilter, 'search', false);
|
||||
$sHtml .= $oBlock->GetDisplay($oPage, "SearchFormToAdd_{$this->m_sAttCode}{$this->m_sNameSuffix}", array('open' => true));
|
||||
$sHtml .= "<form id=\"ObjectsAddForm_{$this->m_sAttCode}{$this->m_sNameSuffix}\" OnSubmit=\"return oWidget{$this->m_iInputId}.DoAddObjects(this.id);\">\n";
|
||||
$sHtml .= "<div id=\"SearchResultsToAdd_{$this->m_sAttCode}{$this->m_sNameSuffix}\" style=\"vertical-align:top;background: #fff;height:100%;overflow:auto;padding:0;border:0;\">\n";
|
||||
$sHtml .= "<div style=\"background: #fff; border:0; text-align:center; vertical-align:middle;\"><p>".Dict::S('UI:Message:EmptyList:UseSearchForm')."</p></div>\n";
|
||||
$sHtml .= "</div>\n";
|
||||
$sHtml .= "<input type=\"button\" value=\"".Dict::S('UI:Button:Cancel')."\" onClick=\"$('#dlg_{$this->m_sAttCode}{$this->m_sNameSuffix}').dialog('close');\"> <input type=\"submit\" value=\"".Dict::S('UI:Button:Add')."\">";
|
||||
$sHtml .= "<input type=\"hidden\" id=\"count_{$this->m_sAttCode}{$this->m_sNameSuffix}\" value=\"0\"/>";
|
||||
$sHtml .= "<input type=\"button\" value=\"".Dict::S('UI:Button:Cancel')."\" onClick=\"$('#dlg_{$this->m_sAttCode}{$this->m_sNameSuffix}').dialog('close');\"> <input id=\"btn_ok_{$this->m_sAttCode}{$this->m_sNameSuffix}\" disabled=\"disabled\" type=\"submit\" value=\"".Dict::S('UI:Button:Add')."\">";
|
||||
$sHtml .= "</div>\n";
|
||||
$sHtml .= "</form>\n";
|
||||
$sHtml .= "</div>\n";
|
||||
$oPage->add($sHtml);
|
||||
$oPage->add_ready_script("$('#dlg_{$this->m_sAttCode}{$this->m_sNameSuffix}').dialog({ width: $(window).width()*0.8, height: $(window).height()*0.8, autoOpen: false, modal: true, resizeStop: oWidget{$this->m_iInputId}.UpdateSizes });");
|
||||
$oPage->add_ready_script("$('#dlg_{$this->m_sAttCode}{$this->m_sNameSuffix}').dialog('option', {title:'".addslashes(Dict::Format('UI:AddObjectsOf_Class_LinkedWith_Class', MetaModel::GetName($this->m_sLinkedClass), MetaModel::GetName($this->m_sClass)))."'});");
|
||||
$oPage->add_ready_script("$('#SearchFormToAdd_{$this->m_sAttCode}{$this->m_sNameSuffix} form').bind('submit.uilinksWizard', oWidget{$this->m_iInputId}.SearchObjectsToAdd);");
|
||||
$oPage->add_ready_script("$('#SearchFormToAdd_{$this->m_sAttCode}{$this->m_sNameSuffix}').resize(oWidget{$this->m_iInputId}.UpdateSizes);");
|
||||
return $sHtml;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -332,18 +350,19 @@ EOF
|
||||
}
|
||||
$oSet = new CMDBObjectSet($oFilter);
|
||||
$oBlock = new DisplayBlock($oFilter, 'list', false);
|
||||
$oBlock->Display($oP, 'ResultsToAdd', array('menu' => false, 'selection_mode' => true, 'display_limit' => false)); // Don't display the 'Actions' menu on the results
|
||||
$oBlock->Display($oP, "ResultsToAdd_{$this->m_sAttCode}", array('menu' => false, 'cssCount'=> '#count_'.$this->m_sAttCode.$this->m_sNameSuffix , 'selection_mode' => true)); // Don't display the 'Actions' menu on the results
|
||||
}
|
||||
|
||||
public function DoAddObjects(WebPage $oP, $aLinkedObjectIds = array())
|
||||
public function DoAddObjects(WebPage $oP, $oFullSetFilter, $oCurrentObj)
|
||||
{
|
||||
$aTable = array();
|
||||
$aLinkedObjectIds = utils::ReadMultipleSelection($oFullSetFilter);
|
||||
|
||||
foreach($aLinkedObjectIds as $iObjectId)
|
||||
{
|
||||
$oLinkedObj = MetaModel::GetObject($this->m_sRemoteClass, $iObjectId);
|
||||
if (is_object($oLinkedObj))
|
||||
{
|
||||
$aRow = $this->GetFormRow($oP, $oLinkedObj, -$iObjectId ); // Not yet created link get negative Ids
|
||||
$aRow = $this->GetFormRow($oP, $oLinkedObj, -$iObjectId, array(), $oCurrentObj ); // Not yet created link get negative Ids
|
||||
$oP->add($this->DisplayFormRow($oP, $this->m_aTableConfig, $aRow, -$iObjectId));
|
||||
}
|
||||
else
|
||||
@@ -352,5 +371,47 @@ EOF
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the default search parameters based on 1) a 'current' object and 2) the silos defined by the context
|
||||
* @param DBObject $oSourceObj
|
||||
* @param DBObjectSearch $oSearch
|
||||
*/
|
||||
protected function SetSearchDefaultFromContext($oSourceObj, &$oSearch)
|
||||
{
|
||||
$oAppContext = new ApplicationContext();
|
||||
$sSrcClass = get_class($oSourceObj);
|
||||
$sDestClass = $oSearch->GetClass();
|
||||
foreach($oAppContext->GetNames() as $key)
|
||||
{
|
||||
// Find the value of the object corresponding to each 'context' parameter
|
||||
$aCallSpec = array($sSrcClass, 'MapContextParam');
|
||||
$sAttCode = '';
|
||||
if (is_callable($aCallSpec))
|
||||
{
|
||||
$sAttCode = call_user_func($aCallSpec, $key); // Returns null when there is no mapping for this parameter
|
||||
}
|
||||
|
||||
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
|
||||
// and sets its value as the default value for the search condition
|
||||
$aCallSpec = array($sDestClass, 'MapContextParam');
|
||||
$sAttCode = '';
|
||||
if (is_callable($aCallSpec))
|
||||
{
|
||||
$sAttCode = call_user_func($aCallSpec, $key); // Returns null when there is no mapping for this parameter
|
||||
}
|
||||
|
||||
if (MetaModel::IsValidAttCode($sDestClass, $sAttCode) && !empty($defaultValue))
|
||||
{
|
||||
$oSearch->AddCondition($sAttCode, $defaultValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
?>
|
||||
|
||||
@@ -52,13 +52,13 @@ class UIPasswordWidget
|
||||
{
|
||||
$sCode = $this->sAttCode.$this->sNameSuffix;
|
||||
$iWidgetIndex = self::$iWidgetIndex;
|
||||
$sPasswordValue = utils::ReadPostedParam("attr_$sCode", '*****');
|
||||
$sConfirmPasswordValue = utils::ReadPostedParam("attr_{$sCode}_confirmed", '*****');
|
||||
$sPasswordValue = utils::ReadPostedParam("attr_{$sCode}[value]", '*****', 'raw_data');
|
||||
$sConfirmPasswordValue = utils::ReadPostedParam("attr_{$sCode}[confirm]", '*****', 'raw_data');
|
||||
$sChangedValue = (($sPasswordValue != '*****') || ($sConfirmPasswordValue != '*****')) ? 1 : 0;
|
||||
$sHtmlValue = '';
|
||||
$sHtmlValue = '<input type="password" maxlength="255" name="attr_'.$sCode.'" id="'.$this->iId.'" value="'.htmlentities($sPasswordValue, ENT_QUOTES, 'UTF-8').'"/> <span class="form_validation" id="v_'.$this->iId.'"></span><br/>';
|
||||
$sHtmlValue .= '<input type="password" maxlength="255" id="'.$this->iId.'_confirm" value="'.htmlentities($sConfirmPasswordValue, ENT_QUOTES, 'UTF-8').'" name="attr_'.$sCode.'_confirmed"/> '.Dict::S('UI:PasswordConfirm').' <input id="'.$this->iId.'_reset" type="button" value="'.Dict::S('UI:Button:ResetPassword').'" onClick="ResetPwd(\''.$this->iId.'\');">';
|
||||
$sHtmlValue .= '<input type="hidden" id="'.$this->iId.'_changed" name="attr_'.$sCode.'_changed" value="'.$sChangedValue.'"/>';
|
||||
$sHtmlValue = '<input type="password" maxlength="255" name="attr_'.$sCode.'[value]" id="'.$this->iId.'" value="'.htmlentities($sPasswordValue, ENT_QUOTES, 'UTF-8').'"/> <span class="form_validation" id="v_'.$this->iId.'"></span><br/>';
|
||||
$sHtmlValue .= '<input type="password" maxlength="255" id="'.$this->iId.'_confirm" value="'.htmlentities($sConfirmPasswordValue, ENT_QUOTES, 'UTF-8').'" name="attr_'.$sCode.'[confirm]"/> '.Dict::S('UI:PasswordConfirm').' <input id="'.$this->iId.'_reset" type="button" value="'.Dict::S('UI:Button:ResetPassword').'" onClick="ResetPwd(\''.$this->iId.'\');">';
|
||||
$sHtmlValue .= '<input type="hidden" id="'.$this->iId.'_changed" name="attr_'.$sCode.'[changed]" value="'.$sChangedValue.'"/>';
|
||||
|
||||
$oPage->add_ready_script("$('#$this->iId').bind('keyup change', function(evt) { return PasswordFieldChanged('$this->iId') } );"); // Bind to a custom event: validate
|
||||
$oPage->add_ready_script("$('#$this->iId').bind('keyup change validate', function(evt, sFormId) { return ValidatePasswordField('$this->iId', sFormId) } );"); // Bind to a custom event: validate
|
||||
|
||||
@@ -85,7 +85,7 @@ class UILinksWizard
|
||||
$sTargetClass = $oAttDef->GetTargetClass();
|
||||
$oTargetObj = MetaModel::GetObject($sTargetClass, $this->m_iObjectId);
|
||||
|
||||
$oP->set_title("iTop - ".MetaModel::GetName($this->m_sLinkedClass)." objects linked with ".MetaModel::GetName(get_class($oTargetObj)).": ".$oTargetObj->GetName());
|
||||
$oP->set_title("iTop - ".MetaModel::GetName($this->m_sLinkedClass)." objects linked with ".MetaModel::GetName(get_class($oTargetObj)).": ".$oTargetObj->GetRawName());
|
||||
$oP->add("<div class=\"wizContainer\">\n");
|
||||
$oP->add("<form method=\"post\">\n");
|
||||
$oP->add("<div class=\"page_header\">\n");
|
||||
@@ -97,8 +97,7 @@ class UILinksWizard
|
||||
$oP->add("<input type=\"hidden\" name=\"linking_attcode\" value=\"{$this->m_sLinkingAttCode}\">\n");
|
||||
$oP->add("<h1>".Dict::Format('UI:ManageObjectsOf_Class_LinkedWith_Class_Instance', MetaModel::GetName($this->m_sLinkedClass), MetaModel::GetName(get_class($oTargetObj)), "<span class=\"hilite\">".$oTargetObj->GetHyperlink()."</span>")."</h1>\n");
|
||||
$oP->add("</div>\n");
|
||||
$oP->add("<script type=\"text/javascript\">\n");
|
||||
$oP->add(
|
||||
$oP->add_script(
|
||||
<<<EOF
|
||||
function OnSelectChange()
|
||||
{
|
||||
@@ -132,7 +131,7 @@ class UILinksWizard
|
||||
function AddObjects()
|
||||
{
|
||||
// TO DO: compute the list of objects already linked with the current Object
|
||||
$.post( '../pages/ajax.render.php', { 'operation': 'addObjects',
|
||||
$.post( GetAbsoluteUrlAppRoot()+'pages/ajax.render.php', { 'operation': 'addObjects',
|
||||
'class': '{$this->m_sClass}',
|
||||
'linkageAttr': '{$this->m_sLinkageAttr}',
|
||||
'linkedClass': '{$this->m_sLinkedClass}',
|
||||
@@ -175,7 +174,7 @@ class UILinksWizard
|
||||
theMap['operation'] = 'searchObjectsToAdd';
|
||||
|
||||
// Run the query and display the results
|
||||
$.post( '../pages/ajax.render.php', theMap,
|
||||
$.post( GetAbsoluteUrlAppRoot()+'pages/ajax.render.php', theMap,
|
||||
function(data)
|
||||
{
|
||||
$('#SearchResultsToAdd').html(data);
|
||||
@@ -223,7 +222,7 @@ class UILinksWizard
|
||||
theMap['operation'] = 'doAddObjects';
|
||||
|
||||
// Run the query and display the results
|
||||
$.post( '../pages/ajax.render.php', theMap,
|
||||
$.post( GetAbsoluteUrlAppRoot()+'pages/ajax.render.php', theMap,
|
||||
function(data)
|
||||
{
|
||||
//console.log('Data: ' + data);
|
||||
@@ -257,7 +256,6 @@ class UILinksWizard
|
||||
}
|
||||
EOF
|
||||
);
|
||||
$oP->Add("</script>\n");
|
||||
$oP->add_ready_script("InitForm();");
|
||||
$oFilter = new DBObjectSearch($this->m_sClass);
|
||||
$oFilter->AddCondition($this->m_sLinkageAttr, $this->m_iObjectId, '=');
|
||||
@@ -395,7 +393,7 @@ EOF
|
||||
$oFilter = new DBObjectSearch($this->m_sLinkedClass);
|
||||
$oSet = new CMDBObjectSet($oFilter);
|
||||
$oBlock = new DisplayBlock($oFilter, 'list', false);
|
||||
$oBlock->Display($oP, 'ResultsToAdd', array('menu' => false, 'selection_mode' => true, 'display_limit' => false)); // Don't display the 'Actions' menu on the results
|
||||
$oBlock->Display($oP, 'ResultsToAdd', array('menu' => false, 'selection_mode' => true)); // Don't display the 'Actions' menu on the results
|
||||
}
|
||||
|
||||
public function DoAddObjects(WebPage $oP, $aLinkedObjectIds = array())
|
||||
|
||||
@@ -53,7 +53,7 @@ class UIWizard
|
||||
{
|
||||
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=\"../pages/UI.php\">\n");
|
||||
$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");
|
||||
@@ -112,8 +112,7 @@ class UIWizard
|
||||
<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 type=\"text/javascript\">
|
||||
$this->m_oPage->add_script("
|
||||
function OnEnterStep{$iStepIndex}()
|
||||
{
|
||||
oWizardHelper.ResetQuery();
|
||||
@@ -123,7 +122,7 @@ $sJSHandlerCode
|
||||
|
||||
oWizardHelper.AjaxQueryServer();
|
||||
}
|
||||
</script>\n");
|
||||
");
|
||||
$this->m_oPage->add("</div>\n\n");
|
||||
}
|
||||
|
||||
@@ -139,16 +138,15 @@ $sJSHandlerCode
|
||||
$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");
|
||||
$this->m_oPage->add("<script type=\"text/javascript\">\n");
|
||||
$this->m_oPage->add("function OnEnterStep$iStepIndex() {\n");
|
||||
$sScript = "function OnEnterStep$iStepIndex() {\n";
|
||||
foreach($aFieldsMap as $iInputId => $sAttCode)
|
||||
{
|
||||
$this->m_oPage->add("\toWizardHelper.UpdateCurrentValue('$sAttCode');\n");
|
||||
$sScript .= "\toWizardHelper.UpdateCurrentValue('$sAttCode');\n";
|
||||
}
|
||||
$this->m_oPage->add("\toWizardHelper.Preview('object_preview');\n");
|
||||
$this->m_oPage->add("\t$('#wizard_json_obj').val(oWizardHelper.ToJSON());\n");
|
||||
$this->m_oPage->add("}\n");
|
||||
$this->m_oPage->add("</script>\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());
|
||||
|
||||
@@ -27,6 +27,7 @@ require_once(APPROOT.'/core/config.class.inc.php');
|
||||
require_once(APPROOT.'/application/transaction.class.inc.php');
|
||||
|
||||
define('ITOP_CONFIG_FILE', APPROOT.'/config-itop.php');
|
||||
define('SERVER_NAME_PLACEHOLDER', '$SERVER_NAME$');
|
||||
|
||||
class FileUploadException extends Exception
|
||||
{
|
||||
@@ -41,9 +42,11 @@ class utils
|
||||
{
|
||||
private static $m_sConfigFile = ITOP_CONFIG_FILE;
|
||||
private static $m_oConfig = null;
|
||||
private static $m_bCASClient = false;
|
||||
|
||||
// Parameters loaded from a file, parameters of the page/command line still have precedence
|
||||
private static $m_aParamsFromFile = null;
|
||||
private static $m_aParamSource = array();
|
||||
|
||||
protected static function LoadParamFile($sParamFile)
|
||||
{
|
||||
@@ -80,13 +83,14 @@ class utils
|
||||
$sParam = $aMatches[1];
|
||||
$value = trim($aMatches[2]);
|
||||
self::$m_aParamsFromFile[$sParam] = $value;
|
||||
self::$m_aParamSource[$sParam] = $sParamFile;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static function UseParamFile($sParamFileArgName = 'param_file', $bAllowCLI = true)
|
||||
{
|
||||
$sFileSpec = self::ReadParam($sParamFileArgName, '', $bAllowCLI);
|
||||
$sFileSpec = self::ReadParam($sParamFileArgName, '', $bAllowCLI, 'raw_data');
|
||||
foreach(explode(',', $sFileSpec) as $sFile)
|
||||
{
|
||||
$sFile = trim($sFile);
|
||||
@@ -97,6 +101,25 @@ class utils
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the source file from which the parameter has been found,
|
||||
* usefull when it comes to pass user credential to a process executed
|
||||
* in the background
|
||||
* @param $sName Parameter name
|
||||
* @return The file name if any, or null
|
||||
*/
|
||||
public static function GetParamSourceFile($sName)
|
||||
{
|
||||
if (array_key_exists($sName, self::$m_aParamSource))
|
||||
{
|
||||
return self::$m_aParamSource[$sName];
|
||||
}
|
||||
else
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static function IsModeCLI()
|
||||
{
|
||||
$sSAPIName = php_sapi_name();
|
||||
@@ -112,7 +135,7 @@ class utils
|
||||
}
|
||||
|
||||
|
||||
public static function ReadParam($sName, $defaultValue = "", $bAllowCLI = false)
|
||||
public static function ReadParam($sName, $defaultValue = "", $bAllowCLI = false, $sSanitizationFilter = 'parameter')
|
||||
{
|
||||
global $argv;
|
||||
$retValue = $defaultValue;
|
||||
@@ -139,29 +162,115 @@ class utils
|
||||
}
|
||||
}
|
||||
}
|
||||
return $retValue;
|
||||
return self::Sanitize($retValue, $defaultValue, $sSanitizationFilter);
|
||||
}
|
||||
|
||||
public static function ReadPostedParam($sName, $defaultValue = "")
|
||||
public static function ReadPostedParam($sName, $defaultValue = '', $sSanitizationFilter = 'parameter')
|
||||
{
|
||||
return isset($_POST[$sName]) ? $_POST[$sName] : $defaultValue;
|
||||
$retValue = isset($_POST[$sName]) ? $_POST[$sName] : $defaultValue;
|
||||
return self::Sanitize($retValue, $defaultValue, $sSanitizationFilter);
|
||||
}
|
||||
|
||||
public static function Sanitize($value, $defaultValue, $sSanitizationFilter)
|
||||
{
|
||||
if ($value === $defaultValue)
|
||||
{
|
||||
// Preserve the real default value (can be used to detect missing mandatory parameters)
|
||||
$retValue = $value;
|
||||
}
|
||||
else
|
||||
{
|
||||
$retValue = self::Sanitize_Internal($value, $sSanitizationFilter);
|
||||
if ($retValue === false)
|
||||
{
|
||||
$retValue = $defaultValue;
|
||||
}
|
||||
}
|
||||
return $retValue;
|
||||
}
|
||||
|
||||
protected static function Sanitize_Internal($value, $sSanitizationFilter)
|
||||
{
|
||||
switch($sSanitizationFilter)
|
||||
{
|
||||
case 'integer':
|
||||
$retValue = filter_var($value, FILTER_SANITIZE_NUMBER_INT);
|
||||
break;
|
||||
|
||||
case 'class':
|
||||
$retValue = $value;
|
||||
if (!MetaModel::IsValidClass($value))
|
||||
{
|
||||
$retValue = false;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'string':
|
||||
$retValue = filter_var($value, FILTER_SANITIZE_SPECIAL_CHARS);
|
||||
break;
|
||||
|
||||
case 'parameter':
|
||||
case 'field_name':
|
||||
if (is_array($value))
|
||||
{
|
||||
$retValue = array();
|
||||
foreach($value as $key => $val)
|
||||
{
|
||||
$retValue[$key] = self::Sanitize_Internal($val, $sSanitizationFilter); // recursively check arrays
|
||||
if ($retValue[$key] === false)
|
||||
{
|
||||
$retValue = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
switch($sSanitizationFilter)
|
||||
{
|
||||
case 'parameter':
|
||||
$retValue = filter_var($value, FILTER_VALIDATE_REGEXP, array("options"=>array("regexp"=>'/^[ A-Za-z0-9_=-]*$/'))); // the '=' equal character is used in serialized filters
|
||||
break;
|
||||
|
||||
case 'field_name':
|
||||
$retValue = filter_var($value, FILTER_VALIDATE_REGEXP, array("options"=>array("regexp"=>'/^[A-Za-z0-9_]+(->[A-Za-z0-9_]+)*$/'))); // att_code or att_code->name or AttCode->Name or AttCode->Key2->Name
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
case 'raw_data':
|
||||
$retValue = $value;
|
||||
// Do nothing
|
||||
}
|
||||
return $retValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads an uploaded file and turns it into an ormDocument object - Triggers an exception in case of error
|
||||
* @param string $sName Name of the input used from uploading the file
|
||||
* @param string $sIndex If Name is an array of posted files, then the index must be used to point out the file
|
||||
* @return ormDocument The uploaded file (can be 'empty' if nothing was uploaded)
|
||||
*/
|
||||
public static function ReadPostedDocument($sName)
|
||||
public static function ReadPostedDocument($sName, $sIndex = null)
|
||||
{
|
||||
$oDocument = new ormDocument(); // an empty document
|
||||
if(isset($_FILES[$sName]))
|
||||
{
|
||||
switch($_FILES[$sName]['error'])
|
||||
$aFileInfo = $_FILES[$sName];
|
||||
|
||||
$sError = is_null($sIndex) ? $aFileInfo['error'] : $aFileInfo['error'][$sIndex];
|
||||
switch($sError)
|
||||
{
|
||||
case UPLOAD_ERR_OK:
|
||||
$doc_content = file_get_contents($_FILES[$sName]['tmp_name']);
|
||||
$sMimeType = $_FILES[$sName]['type'];
|
||||
$sTmpName = is_null($sIndex) ? $aFileInfo['tmp_name'] : $aFileInfo['tmp_name'][$sIndex];
|
||||
$sMimeType = is_null($sIndex) ? $aFileInfo['type'] : $aFileInfo['type'][$sIndex];
|
||||
$sName = is_null($sIndex) ? $aFileInfo['name'] : $aFileInfo['name'][$sIndex];
|
||||
|
||||
$doc_content = file_get_contents($sTmpName);
|
||||
if (function_exists('finfo_file'))
|
||||
{
|
||||
// as of PHP 5.3 the fileinfo extension is bundled within PHP
|
||||
@@ -179,7 +288,7 @@ class utils
|
||||
}
|
||||
@finfo_close($rInfo);
|
||||
}
|
||||
$oDocument = new ormDocument($doc_content, $sMimeType, $_FILES[$sName]['name']);
|
||||
$oDocument = new ormDocument($doc_content, $sMimeType, $sName);
|
||||
break;
|
||||
|
||||
case UPLOAD_ERR_NO_FILE:
|
||||
@@ -204,11 +313,12 @@ class utils
|
||||
break;
|
||||
|
||||
case UPLOAD_ERR_EXTENSION:
|
||||
throw new FileUploadException(Dict::Format('UI:Error:UploadStoppedByExtension_FileName', $_FILES[$sName]['name']));
|
||||
$sName = is_null($sIndex) ? $aFileInfo['name'] : $aFileInfo['name'][$sIndex];
|
||||
throw new FileUploadException(Dict::Format('UI:Error:UploadStoppedByExtension_FileName', $sName));
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new FileUploadException(Dict::Format('UI:Error:UploadFailedUnknownCause_Code', $_FILES[$sName]['error']));
|
||||
throw new FileUploadException(Dict::Format('UI:Error:UploadFailedUnknownCause_Code', $sError));
|
||||
break;
|
||||
|
||||
}
|
||||
@@ -216,6 +326,43 @@ class utils
|
||||
return $oDocument;
|
||||
}
|
||||
|
||||
/**
|
||||
* Interprets the results posted by a normal or paginated list (in multiple selection mode)
|
||||
* @param $oFullSetFilter DBObjectSearch The criteria defining the whole sets of objects being selected
|
||||
* @return Array An arry of object IDs corresponding to the objects selected in the set
|
||||
*/
|
||||
public static function ReadMultipleSelection($oFullSetFilter)
|
||||
{
|
||||
$aSelectedObj = utils::ReadParam('selectObject', array());
|
||||
$sSelectionMode = utils::ReadParam('selectionMode', '');
|
||||
if ($sSelectionMode != '')
|
||||
{
|
||||
// Paginated selection
|
||||
$aExceptions = utils::ReadParam('storedSelection', array());
|
||||
if ($sSelectionMode == 'positive')
|
||||
{
|
||||
// Only the explicitely listed items are selected
|
||||
$aSelectedObj = $aExceptions;
|
||||
}
|
||||
else
|
||||
{
|
||||
// All items of the set are selected, except the one explicitely listed
|
||||
$aSelectedObj = array();
|
||||
$oFullSet = new DBObjectSet($oFullSetFilter);
|
||||
$sClassAlias = $oFullSetFilter->GetClassAlias();
|
||||
$oFullSet->OptimizeColumnLoad(array($sClassAlias => array('friendlyname'))); // We really need only the IDs but it does not work since id is not a real field
|
||||
while($oObj = $oFullSet->Fetch())
|
||||
{
|
||||
if (!in_array($oObj->GetKey(), $aExceptions))
|
||||
{
|
||||
$aSelectedObj[] = $oObj->GetKey();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return $aSelectedObj;
|
||||
}
|
||||
|
||||
public static function GetNewTransactionId()
|
||||
{
|
||||
return privUITransaction::GetNewTransactionId();
|
||||
@@ -264,39 +411,89 @@ class utils
|
||||
return $iReturn;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an absolute URL to the current page
|
||||
* @param $bQueryString bool True to also get the query string, false otherwise
|
||||
* @param $bForceHTTPS bool True to force HTTPS, false otherwise
|
||||
* @return string The absolute URL to the current page
|
||||
*/
|
||||
static public function GetAbsoluteUrl($bQueryString = true, $bForceHTTPS = false)
|
||||
/**
|
||||
* Helper function to convert a string to a date, given a format specification. It replaces strtotime which does not allow for specifying a date in a french format (for instance)
|
||||
* Example: StringToTime('01/05/11 12:03:45', '%d/%m/%y %H:%i:%s')
|
||||
* @param string $sDate
|
||||
* @param string $sFormat
|
||||
* @return timestamp or false if the input format is not correct
|
||||
*/
|
||||
public static function StringToTime($sDate, $sFormat)
|
||||
{
|
||||
// Build an absolute URL to this page on this server/port
|
||||
$sServerName = isset($_SERVER['SERVER_NAME']) ? $_SERVER['SERVER_NAME'] : '';
|
||||
if (MetaModel::GetConfig()->GetSecureConnectionRequired() || MetaModel::GetConfig()->GetHttpsHyperlinks())
|
||||
// Source: http://php.net/manual/fr/function.strftime.php
|
||||
// (alternative: http://www.php.net/manual/fr/datetime.formats.date.php)
|
||||
static $aDateTokens = null;
|
||||
static $aDateRegexps = null;
|
||||
if (is_null($aDateTokens))
|
||||
{
|
||||
// If a secure connection is required, or if the URL is requested to start with HTTPS
|
||||
// then any URL must start with https !
|
||||
$bForceHTTPS = true;
|
||||
$aSpec = array(
|
||||
'%d' =>'(?<day>[0-9]{2})',
|
||||
'%m' => '(?<month>[0-9]{2})',
|
||||
'%y' => '(?<year>[0-9]{2})',
|
||||
'%Y' => '(?<year>[0-9]{4})',
|
||||
'%H' => '(?<hour>[0-2][0-9])',
|
||||
'%i' => '(?<minute>[0-5][0-9])',
|
||||
'%s' => '(?<second>[0-5][0-9])',
|
||||
);
|
||||
$aDateTokens = array_keys($aSpec);
|
||||
$aDateRegexps = array_values($aSpec);
|
||||
}
|
||||
if ($bForceHTTPS)
|
||||
{
|
||||
$sProtocol = 'https';
|
||||
$sPort = '';
|
||||
|
||||
$sDateRegexp = str_replace($aDateTokens, $aDateRegexps, $sFormat);
|
||||
|
||||
if (preg_match('!^(?<head>)'.$sDateRegexp.'(?<tail>)$!', $sDate, $aMatches))
|
||||
{
|
||||
$sYear = isset($aMatches['year']) ? $aMatches['year'] : 0;
|
||||
$sMonth = isset($aMatches['month']) ? $aMatches['month'] : 1;
|
||||
$sDay = isset($aMatches['day']) ? $aMatches['day'] : 1;
|
||||
$sHour = isset($aMatches['hour']) ? $aMatches['hour'] : 0;
|
||||
$sMinute = isset($aMatches['minute']) ? $aMatches['minute'] : 0;
|
||||
$sSecond = isset($aMatches['second']) ? $aMatches['second'] : 0;
|
||||
return strtotime("$sYear-$sMonth-$sDay $sHour:$sMinute:$sSecond");
|
||||
}
|
||||
else
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
// http://www.spaweditor.com/scripts/regex/index.php
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the absolute URL to the server's root path
|
||||
* @return string The absolute URL to the server's root, without the first slash
|
||||
*/
|
||||
static public function GetAbsoluteUrlAppRoot()
|
||||
{
|
||||
$sUrl = MetaModel::GetConfig()->Get('app_root_url');
|
||||
if (strpos($sUrl, SERVER_NAME_PLACEHOLDER) > -1)
|
||||
{
|
||||
$sProtocol = (isset($_SERVER['HTTPS']) && ($_SERVER['HTTPS']!="off")) ? 'https' : 'http';
|
||||
$iPort = isset($_SERVER['SERVER_PORT']) ? $_SERVER['SERVER_PORT'] : 80;
|
||||
if ($sProtocol == 'http')
|
||||
if (isset($_SERVER['SERVER_NAME']))
|
||||
{
|
||||
$sPort = ($iPort == 80) ? '' : ':'.$iPort;
|
||||
$sServerName = $_SERVER['SERVER_NAME'];
|
||||
}
|
||||
else
|
||||
{
|
||||
$sPort = ($iPort == 443) ? '' : ':'.$iPort;
|
||||
// CLI mode ?
|
||||
$sServerName = php_uname('n');
|
||||
}
|
||||
$sUrl = str_replace(SERVER_NAME_PLACEHOLDER, $sServerName, $sUrl);
|
||||
}
|
||||
return $sUrl;
|
||||
}
|
||||
|
||||
static public function GetDefaultUrlAppRoot()
|
||||
{
|
||||
// Build an absolute URL to this page on this server/port
|
||||
$sServerName = isset($_SERVER['SERVER_NAME']) ? $_SERVER['SERVER_NAME'] : '';
|
||||
$sProtocol = (isset($_SERVER['HTTPS']) && ($_SERVER['HTTPS']!="off")) ? 'https' : 'http';
|
||||
$iPort = isset($_SERVER['SERVER_PORT']) ? $_SERVER['SERVER_PORT'] : 80;
|
||||
if ($sProtocol == 'http')
|
||||
{
|
||||
$sPort = ($iPort == 80) ? '' : ':'.$iPort;
|
||||
}
|
||||
else
|
||||
{
|
||||
$sPort = ($iPort == 443) ? '' : ':'.$iPort;
|
||||
}
|
||||
// $_SERVER['REQUEST_URI'] is empty when running on IIS
|
||||
// Let's use Ivan Tcholakov's fix (found on www.dokeos.com)
|
||||
@@ -313,51 +510,53 @@ class utils
|
||||
}
|
||||
$_SERVER['REQUEST_URI'] = $sPath;
|
||||
}
|
||||
$sPath = $_SERVER['REQUEST_URI'];
|
||||
if (!$bQueryString)
|
||||
{
|
||||
// remove all the parameters from the query string
|
||||
$iQuestionMarkPos = strpos($sPath, '?');
|
||||
if ($iQuestionMarkPos !== false)
|
||||
{
|
||||
$sPath = substr($sPath, 0, $iQuestionMarkPos);
|
||||
}
|
||||
}
|
||||
$sUrl = "$sProtocol://{$sServerName}{$sPort}{$sPath}";
|
||||
|
||||
return $sUrl;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the absolute URL PATH of the current page
|
||||
* @param $bForceHTTPS bool True to force HTTPS, false otherwise
|
||||
* @return string The absolute URL to the current page
|
||||
*/
|
||||
static public function GetAbsoluteUrlPath($bForceHTTPS = false)
|
||||
{
|
||||
$sAbsoluteUrl = self::GetAbsoluteUrl(false, $bForceHTTPS); // False => Don't get the query string
|
||||
$sAbsoluteUrl = substr($sAbsoluteUrl, 0, 1+strrpos($sAbsoluteUrl, '/')); // remove the current page, keep just the path, up to the last /
|
||||
return $sAbsoluteUrl;
|
||||
}
|
||||
$sPath = $_SERVER['REQUEST_URI'];
|
||||
|
||||
/**
|
||||
* Returns the absolute URL to the server's root path
|
||||
* @param $bForceHTTPS bool True to force HTTPS, false otherwise
|
||||
* @return string The absolute URL to the server's root, without the first slash
|
||||
*/
|
||||
static public function GetAbsoluteUrlAppRoot($sCurrentRelativePath = '', $bForceHTTPS = false)
|
||||
{
|
||||
$sAbsoluteUrl = self::GetAbsoluteUrl(false, $bForceHTTPS); // False => Don't get the query string
|
||||
// remove all the parameters from the query string
|
||||
$iQuestionMarkPos = strpos($sPath, '?');
|
||||
if ($iQuestionMarkPos !== false)
|
||||
{
|
||||
$sPath = substr($sPath, 0, $iQuestionMarkPos);
|
||||
}
|
||||
$sAbsoluteUrl = "$sProtocol://{$sServerName}{$sPort}{$sPath}";
|
||||
|
||||
$sCurrentScript = realpath($_SERVER['SCRIPT_FILENAME']);
|
||||
$sCurrentScript = str_replace('\\', '/', $sCurrentScript); // canonical path
|
||||
$sAppRoot = str_replace('\\', '/', APPROOT); // canonical path
|
||||
$sCurrentRelativePath = str_replace($sAppRoot, '', $sCurrentScript);
|
||||
|
||||
$sAppRootPos = strpos($sAbsoluteUrl, $sCurrentRelativePath);
|
||||
if ($sAppRootPos !== false)
|
||||
{
|
||||
$sAbsoluteUrl = substr($sAbsoluteUrl, 0, $sAppRootPos); // remove the current page and path
|
||||
$sAppRootUrl = substr($sAbsoluteUrl, 0, $sAppRootPos); // remove the current page and path
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new Exception("Failed to determine application root path $sAbsoluteUrl ($sCurrentRelativePath)");
|
||||
// Second attempt without index.php at the end...
|
||||
$sCurrentRelativePath = str_replace('index.php', '', $sCurrentRelativePath);
|
||||
$sAppRootPos = strpos($sAbsoluteUrl, $sCurrentRelativePath);
|
||||
if ($sAppRootPos !== false)
|
||||
{
|
||||
$sAppRootUrl = substr($sAbsoluteUrl, 0, $sAppRootPos); // remove the current page and path
|
||||
}
|
||||
else
|
||||
{
|
||||
// No luck...
|
||||
throw new Exception("Failed to determine application root path $sAbsoluteUrl ($sCurrentRelativePath) APPROOT:'$sAppRoot'");
|
||||
}
|
||||
}
|
||||
return $sAbsoluteUrl;
|
||||
return $sAppRootUrl;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the absolute URL to the modules root path
|
||||
* Hardcoded here for compatibility with iTop 2.0 modules
|
||||
* @return string The absolute URL to the modules
|
||||
*/
|
||||
static public function GetAbsoluteUrlModulesRoot()
|
||||
{
|
||||
$sUrl = self::GetAbsoluteUrlAppRoot().'modules/';
|
||||
return $sUrl;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -369,7 +568,157 @@ class utils
|
||||
*/
|
||||
static function CanLogOff()
|
||||
{
|
||||
return (isset($_SESSION['login_mode']) && $_SESSION['login_mode'] == 'form');
|
||||
$bResult = false;
|
||||
if(isset($_SESSION['login_mode']))
|
||||
{
|
||||
$sLoginMode = $_SESSION['login_mode'];
|
||||
switch($sLoginMode)
|
||||
{
|
||||
case 'external':
|
||||
$bResult = false;
|
||||
break;
|
||||
|
||||
case 'form':
|
||||
case 'basic':
|
||||
case 'url':
|
||||
case 'cas':
|
||||
default:
|
||||
$bResult = true;
|
||||
|
||||
}
|
||||
}
|
||||
return $bResult;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the CAS client
|
||||
*/
|
||||
static function InitCASClient()
|
||||
{
|
||||
$sCASIncludePath = MetaModel::GetConfig()->Get('cas_include_path');
|
||||
include_once($sCASIncludePath.'/CAS.php');
|
||||
|
||||
$bCASDebug = MetaModel::GetConfig()->Get('cas_debug');
|
||||
if ($bCASDebug)
|
||||
{
|
||||
phpCAS::setDebug(APPROOT.'/error.log');
|
||||
}
|
||||
|
||||
if (!self::$m_bCASClient)
|
||||
{
|
||||
// Initialize phpCAS
|
||||
$sCASVersion = MetaModel::GetConfig()->Get('cas_version');
|
||||
$sCASHost = MetaModel::GetConfig()->Get('cas_host');
|
||||
$iCASPort = MetaModel::GetConfig()->Get('cas_port');
|
||||
$sCASContext = MetaModel::GetConfig()->Get('cas_context');
|
||||
phpCAS::client($sCASVersion, $sCASHost, $iCASPort, $sCASContext, false /* session already started */);
|
||||
self::$m_bCASClient = true;
|
||||
$sCASCACertPath = MetaModel::GetConfig()->Get('cas_server_ca_cert_path');
|
||||
if (empty($sCASCACertPath))
|
||||
{
|
||||
// If no certificate authority is provided, do not attempt to validate
|
||||
// the server's certificate
|
||||
// THIS SETTING IS NOT RECOMMENDED FOR PRODUCTION.
|
||||
// VALIDATING THE CAS SERVER IS CRUCIAL TO THE SECURITY OF THE CAS PROTOCOL!
|
||||
phpCAS::setNoCasServerValidation();
|
||||
}
|
||||
else
|
||||
{
|
||||
phpCAS::setCasServerCACert($sCASCACertPath);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static function DebugBacktrace($iLimit = 5)
|
||||
{
|
||||
$aFullTrace = debug_backtrace();
|
||||
$aLightTrace = array();
|
||||
for($i=1; ($i<=$iLimit && $i < count($aFullTrace)); $i++) // Skip the last function call... which is the call to this function !
|
||||
{
|
||||
$aLightTrace[$i] = $aFullTrace[$i]['function'].'(), called from line '.$aFullTrace[$i]['line'].' in '.$aFullTrace[$i]['file'];
|
||||
}
|
||||
echo "<p><pre>".print_r($aLightTrace, true)."</pre></p>\n";
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the given iTop PHP script, passing it the current credentials
|
||||
* Only CLI mode is supported, because of the need to hand the credentials over to the next process
|
||||
* Throws an exception if the execution fails or could not be attempted (config issue)
|
||||
* @param string $sScript Name and relative path to the file (relative to the iTop root dir)
|
||||
* @param hash $aArguments Associative array of 'arg' => 'value'
|
||||
* @return array(iCode, array(output lines))
|
||||
*/
|
||||
/**
|
||||
*/
|
||||
static function ExecITopScript($sScriptName, $aArguments)
|
||||
{
|
||||
$aDisabled = explode(', ', ini_get('disable_functions'));
|
||||
if (in_array('exec', $aDisabled))
|
||||
{
|
||||
throw new Exception("The PHP exec() function has been disabled on this server");
|
||||
}
|
||||
|
||||
$sPHPExec = trim(MetaModel::GetConfig()->Get('php_path'));
|
||||
if (strlen($sPHPExec) == 0)
|
||||
{
|
||||
throw new Exception("The path to php must not be empty. Please set a value for 'php_path' in your configuration file.");
|
||||
}
|
||||
|
||||
$sAuthUser = self::ReadParam('auth_user', '', 'raw_data');
|
||||
$sAuthPwd = self::ReadParam('auth_pwd', '', 'raw_data');
|
||||
$sParamFile = self::GetParamSourceFile('auth_user');
|
||||
if (is_null($sParamFile))
|
||||
{
|
||||
$aArguments['auth_user'] = $sAuthUser;
|
||||
$aArguments['auth_pwd'] = $sAuthPwd;
|
||||
}
|
||||
else
|
||||
{
|
||||
$aArguments['param_file'] = $sParamFile;
|
||||
}
|
||||
|
||||
$aArgs = array();
|
||||
foreach($aArguments as $sName => $value)
|
||||
{
|
||||
// Note: See comment from the 23-Apr-2004 03:30 in the PHP documentation
|
||||
// It suggests to rely on pctnl_* function instead of using escapeshellargs
|
||||
$aArgs[] = "--$sName=".escapeshellarg($value);
|
||||
}
|
||||
$sArgs = implode(' ', $aArgs);
|
||||
|
||||
$sScript = realpath(APPROOT.$sScriptName);
|
||||
if (!file_exists($sScript))
|
||||
{
|
||||
throw new Exception("Could not find the script file '$sScriptName' from the directory '".APPROOT."'");
|
||||
}
|
||||
|
||||
$sCommand = '"'.$sPHPExec.'" '.escapeshellarg($sScript).' -- '.$sArgs;
|
||||
|
||||
if (version_compare(phpversion(), '5.3.0', '<'))
|
||||
{
|
||||
if (substr(PHP_OS,0,3) == 'WIN')
|
||||
{
|
||||
// Under Windows, and for PHP 5.2.x, the whole command has to be quoted
|
||||
// Cf PHP doc: http://php.net/manual/fr/function.exec.php, comment from the 27-Dec-2010
|
||||
$sCommand = '"'.$sCommand.'"';
|
||||
}
|
||||
}
|
||||
|
||||
$sLastLine = exec($sCommand, $aOutput, $iRes);
|
||||
if ($iRes == 1)
|
||||
{
|
||||
throw new Exception(Dict::S('Core:ExecProcess:Code1')." - ".$sCommand);
|
||||
}
|
||||
elseif ($iRes == 255)
|
||||
{
|
||||
$sErrors = implode("\n", $aOutput);
|
||||
throw new Exception(Dict::S('Core:ExecProcess:Code255')." - ".$sCommand.":\n".$sErrors);
|
||||
}
|
||||
|
||||
//$aOutput[] = $sCommand;
|
||||
return array($iRes, $aOutput);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
?>
|
||||
|
||||
@@ -47,7 +47,10 @@ class WebPage
|
||||
protected $a_base;
|
||||
protected $iNextId;
|
||||
protected $iTransactionId;
|
||||
|
||||
protected $sContentType;
|
||||
protected $sContentDisposition;
|
||||
protected $sContentFileName;
|
||||
|
||||
public function __construct($s_title)
|
||||
{
|
||||
$this->s_title = $s_title;
|
||||
@@ -61,6 +64,9 @@ class WebPage
|
||||
$this->a_base = array( 'href' => '', 'target' => '');
|
||||
$this->iNextId = 0;
|
||||
$this->iTransactionId = 0;
|
||||
$this->sContentType = '';
|
||||
$this->sContentDisposition = '';
|
||||
$this->sContentFileName = '';
|
||||
ob_start(); // Start capturing the output
|
||||
}
|
||||
|
||||
@@ -90,11 +96,11 @@ class WebPage
|
||||
}
|
||||
|
||||
/**
|
||||
* Add any text or HTML fragment at the end of the body of the page
|
||||
* 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)
|
||||
public function add_at_the_end($s_html, $sId = '')
|
||||
{
|
||||
$this->s_deferred_content .= $s_html;
|
||||
}
|
||||
@@ -154,27 +160,33 @@ class WebPage
|
||||
$sHtml .= "<tbody>\n";
|
||||
foreach($aData as $aRow)
|
||||
{
|
||||
if (isset($aRow['@class'])) // Row specific class, for hilighting certain rows
|
||||
{
|
||||
$sHtml .= "<tr class=\"{$aRow['@class']}\">\n";
|
||||
}
|
||||
else
|
||||
{
|
||||
$sHtml .= "<tr>\n";
|
||||
}
|
||||
foreach($aConfig as $sName=>$aAttribs)
|
||||
{
|
||||
$aMatches = array();
|
||||
$sClass = isset($aAttribs['class']) ? 'class="'.$aAttribs['class'].'"' : '';
|
||||
$sValue = ($aRow[$sName] === '') ? ' ' : $aRow[$sName];
|
||||
$sHtml .= "<td $sClass>$sValue</td>\n";
|
||||
}
|
||||
$sHtml .= "</tr>\n";
|
||||
$sHtml .= $this->GetTableRow($aRow, $aConfig);
|
||||
}
|
||||
$sHtml .= "</tbody>\n";
|
||||
$sHtml .= "</table>\n";
|
||||
return $sHtml;
|
||||
}
|
||||
|
||||
public function GetTableRow($aRow, $aConfig)
|
||||
{
|
||||
$sHtml = '';
|
||||
if (isset($aRow['@class'])) // Row specific class, for hilighting certain rows
|
||||
{
|
||||
$sHtml .= "<tr class=\"{$aRow['@class']}\">";
|
||||
}
|
||||
else
|
||||
{
|
||||
$sHtml .= "<tr>";
|
||||
}
|
||||
foreach($aConfig as $sName=>$aAttribs)
|
||||
{
|
||||
$sClass = isset($aAttribs['class']) ? 'class="'.$aAttribs['class'].'"' : '';
|
||||
$sValue = ($aRow[$sName] === '') ? ' ' : $aRow[$sName];
|
||||
$sHtml .= "<td $sClass>$sValue</td>";
|
||||
}
|
||||
$sHtml .= "</tr>";
|
||||
return $sHtml;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add some Javascript to the header of the page
|
||||
@@ -240,6 +252,28 @@ class WebPage
|
||||
|
||||
$this->add($this->GetDetails($aFields));
|
||||
}
|
||||
|
||||
/**
|
||||
* 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()
|
||||
{
|
||||
return strlen($this->s_content);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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)
|
||||
{
|
||||
$sCaptured = substr($this->s_content, $offset);
|
||||
$this->s_content = substr($this->s_content, 0, $offset);
|
||||
return $sCaptured;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build a special kind of TABLE useful for displaying the details of an object from a hash array of data
|
||||
@@ -269,6 +303,53 @@ class WebPage
|
||||
$sHtml .= "</table>\n";
|
||||
return $sHtml;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build a set of radio buttons suitable for editing a field/attribute of an object (including its validation)
|
||||
* @param $aAllowedValues hash Array of value => display_value
|
||||
* @param $value mixed Current value for the field/attribute
|
||||
* @param $iId mixed Unique Id for the input control in the page
|
||||
* @param $sFieldName string The name of the field, attr_<$sFieldName> will hold the value for the field
|
||||
* @param $bMandatory bool Whether or not the field is mandatory
|
||||
* @param $bVertical bool Disposition of the radio buttons vertical or horizontal
|
||||
* @param $sValidationField string HTML fragment holding the validation field (exclamation icon...)
|
||||
* @return string The HTML fragment corresponding to the radio buttons
|
||||
*/
|
||||
public function GetRadioButtons($aAllowedValues, $value, $iId, $sFieldName, $bMandatory, $bVertical, $sValidationField)
|
||||
{
|
||||
$idx = 0;
|
||||
$sHTMLValue = '';
|
||||
foreach($aAllowedValues as $key => $display_value)
|
||||
{
|
||||
if ((count($aAllowedValues) == 1) && ($bMandatory == 'true') )
|
||||
{
|
||||
// When there is only once choice, select it by default
|
||||
$sSelected = ' checked';
|
||||
}
|
||||
else
|
||||
{
|
||||
$sSelected = ($value == $key) ? ' checked' : '';
|
||||
}
|
||||
$sHTMLValue .= "<input type=\"radio\" id=\"{$iId}_{$key}\" name=\"radio_$sFieldName\" onChange=\"$('#{$iId}').val(this.value).trigger('change');\" value=\"$key\"$sSelected><label class=\"radio\" for=\"{$iId}_{$key}\"> $display_value</label> ";
|
||||
if ($bVertical)
|
||||
{
|
||||
if ($idx == 0)
|
||||
{
|
||||
// Validation icon at the end of the first line
|
||||
$sHTMLValue .= " {$sValidationField}\n";
|
||||
}
|
||||
$sHTMLValue .= "<br>\n";
|
||||
}
|
||||
$idx++;
|
||||
}
|
||||
$sHTMLValue .= "<input type=\"hidden\" id=\"$iId\" name=\"$sFieldName\" value=\"$value\"/>";
|
||||
if (!$bVertical)
|
||||
{
|
||||
// Validation icon at the end of the line
|
||||
$sHTMLValue .= " {$sValidationField}\n";
|
||||
}
|
||||
return $sHTMLValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Outputs (via some echo) the complete HTML page by assembling all its elements
|
||||
@@ -284,20 +365,20 @@ class WebPage
|
||||
echo "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n";
|
||||
echo "<html>\n";
|
||||
echo "<head>\n";
|
||||
echo "<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\" />\n";
|
||||
echo "<title>{$this->s_title}</title>\n";
|
||||
echo "<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\" />\n";
|
||||
echo "<title>".htmlentities($this->s_title, ENT_QUOTES, 'UTF-8')."</title>\n";
|
||||
echo $this->get_base_tag();
|
||||
foreach($this->a_linked_scripts as $s_script)
|
||||
{
|
||||
// Make sure that the URL to the script contains the application's version number
|
||||
// so that the new script do NOT get reloaded from the cache when the application is upgraded
|
||||
if (strpos('?', $s_script) === false)
|
||||
if (strpos($s_script, '?') === false)
|
||||
{
|
||||
$s_script .= "?version=".ITOP_VERSION;
|
||||
$s_script .= "?itopversion=".ITOP_VERSION;
|
||||
}
|
||||
else
|
||||
{
|
||||
$s_script .= "&version=".ITOP_VERSION;
|
||||
$s_script .= "&itopversion=".ITOP_VERSION;
|
||||
}
|
||||
echo "<script type=\"text/javascript\" src=\"$s_script\"></script>\n";
|
||||
}
|
||||
@@ -332,14 +413,18 @@ class WebPage
|
||||
}
|
||||
echo "</style>\n";
|
||||
}
|
||||
if (class_exists('MetaModel') && MetaModel::GetConfig())
|
||||
{
|
||||
echo "<link rel=\"shortcut icon\" href=\"".utils::GetAbsoluteUrlAppRoot()."images/favicon.ico\" />\n";
|
||||
}
|
||||
echo "</head>\n";
|
||||
echo "<body>\n";
|
||||
echo $this->s_content;
|
||||
echo self::FilterXSS($this->s_content);
|
||||
if (trim($s_captured_output) != "")
|
||||
{
|
||||
echo "<div class=\"raw_output\">$s_captured_output</div>\n";
|
||||
echo "<div class=\"raw_output\">".self::FilterXSS($s_captured_output)."</div>\n";
|
||||
}
|
||||
echo '<div id="at_the_end">'.$this->s_deferred_content.'</div>';
|
||||
echo '<div id="at_the_end">'.self::FilterXSS($this->s_deferred_content).'</div>';
|
||||
echo "</body>\n";
|
||||
echo "</html>\n";
|
||||
}
|
||||
@@ -384,7 +469,29 @@ class WebPage
|
||||
{
|
||||
return $this->iNextId++;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set the content-type (mime type) for the page's content
|
||||
* @param $sContentType string
|
||||
* @return void
|
||||
*/
|
||||
public function SetContentType($sContentType)
|
||||
{
|
||||
$this->sContentType = $sContentType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the content-disposition (mime type) for the page's content
|
||||
* @param $sDisposition string The disposition: 'inline' or 'attachment'
|
||||
* @param $sFileName string The original name of the file
|
||||
* @return void
|
||||
*/
|
||||
public function SetContentDisposition($sDisposition, $sFileName)
|
||||
{
|
||||
$this->sContentDisposition = $sDisposition;
|
||||
$this->sContentFileName = $sFileName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the transactionId of the current form
|
||||
* @param $iTransactionId integer
|
||||
@@ -403,5 +510,10 @@ class WebPage
|
||||
{
|
||||
return $this->iTransactionId;
|
||||
}
|
||||
|
||||
public static function FilterXSS($sHTML)
|
||||
{
|
||||
return str_ireplace('<script', '<script', $sHTML);
|
||||
}
|
||||
}
|
||||
?>
|
||||
@@ -98,7 +98,7 @@ class WizardHelper
|
||||
{
|
||||
if ($bReadUploadedFiles)
|
||||
{
|
||||
$oDocument = utils::ReadPostedDocument('file_'.$sAttCode);
|
||||
$oDocument = utils::ReadPostedDocument('attr_'.$sAttCode, 'fcontents');
|
||||
$oObj->Set($sAttCode, $oDocument);
|
||||
}
|
||||
else
|
||||
@@ -125,7 +125,7 @@ class WizardHelper
|
||||
{
|
||||
$oObj->Set(MetaModel::GetStateAttributeCode($this->m_aData['m_sClass']), $this->m_aData['m_sState']);
|
||||
}
|
||||
|
||||
$oObj->DoComputeValues();
|
||||
return $oObj;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
<?php
|
||||
define('APPROOT', dirname(__FILE__).'/');
|
||||
define('MODULESROOT', APPROOT.'modules/');
|
||||
if (function_exists('microtime'))
|
||||
{
|
||||
$fItopStarted = microtime(true);
|
||||
|
||||
@@ -42,7 +42,7 @@ abstract class Action extends cmdbAbstractObject
|
||||
"key_type" => "autoincrement",
|
||||
"name_attcode" => "name",
|
||||
"state_attcode" => "",
|
||||
"reconc_keys" => array(),
|
||||
"reconc_keys" => array('name'),
|
||||
"db_table" => "priv_action",
|
||||
"db_key_field" => "id",
|
||||
"db_finalclass_field" => "realclass",
|
||||
@@ -106,7 +106,7 @@ abstract class ActionNotification extends Action
|
||||
"key_type" => "autoincrement",
|
||||
"name_attcode" => "name",
|
||||
"state_attcode" => "",
|
||||
"reconc_keys" => array(),
|
||||
"reconc_keys" => array('name'),
|
||||
"db_table" => "priv_action_notification",
|
||||
"db_key_field" => "id",
|
||||
"db_finalclass_field" => "",
|
||||
@@ -139,7 +139,7 @@ class ActionEmail extends ActionNotification
|
||||
"key_type" => "autoincrement",
|
||||
"name_attcode" => "name",
|
||||
"state_attcode" => "",
|
||||
"reconc_keys" => array(),
|
||||
"reconc_keys" => array('name'),
|
||||
"db_table" => "priv_action_email",
|
||||
"db_key_field" => "id",
|
||||
"db_finalclass_field" => "",
|
||||
@@ -183,6 +183,7 @@ class ActionEmail extends ActionNotification
|
||||
try
|
||||
{
|
||||
$oSearch = DBObjectSearch::FromOQL($sOQL);
|
||||
$oSearch->AllowAllData();
|
||||
}
|
||||
catch (OQLException $e)
|
||||
{
|
||||
@@ -274,26 +275,38 @@ class ActionEmail extends ActionNotification
|
||||
|
||||
protected function _DoExecute($oTrigger, $aContextArgs, &$oLog)
|
||||
{
|
||||
$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 = $this->Get('from');
|
||||
$sReplyTo = $this->Get('reply_to');
|
||||
|
||||
$sSubject = MetaModel::ApplyParams($this->Get('subject'), $aContextArgs);
|
||||
$sBody = MetaModel::ApplyParams($this->Get('body'), $aContextArgs);
|
||||
$sPreviousUrlMaker = ApplicationContext::SetUrlMakerClass();
|
||||
$aHeaders = array();
|
||||
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 = $this->Get('from');
|
||||
$sReplyTo = $this->Get('reply_to');
|
||||
|
||||
$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::GetConfig()->Get('session_name'));
|
||||
$sReference = $sMessageId;
|
||||
$aHeaders['Message-ID'] = $sMessageId;
|
||||
}
|
||||
catch(Exception $e)
|
||||
{
|
||||
ApplicationContext::SetUrlMakerClass($sPreviousUrlMaker);
|
||||
throw $e;
|
||||
}
|
||||
ApplicationContext::SetUrlMakerClass($sPreviousUrlMaker);
|
||||
|
||||
$oObj = $aContextArgs['this->object()'];
|
||||
$sServerIP = $_SERVER['SERVER_ADDR']; //gethostbyname(gethostname());
|
||||
$sReference = '<iTop/'.get_class($oObj).'/'.$oObj->GetKey().'@'.$sServerIP.'>';
|
||||
|
||||
if (!is_null($oLog))
|
||||
{
|
||||
// Note: we have to secure this because those values are calculated
|
||||
@@ -307,7 +320,7 @@ class ActionEmail extends ActionNotification
|
||||
if (isset($sBody)) $oLog->Set('body', $sBody);
|
||||
}
|
||||
|
||||
$oEmail = new EMail();
|
||||
$oEmail = new EMail('', '', '', $aHeaders);
|
||||
|
||||
if ($this->IsBeingTested())
|
||||
{
|
||||
|
||||
@@ -64,7 +64,14 @@ define('DEL_MANUAL', 1);
|
||||
* @package iTopORM
|
||||
*/
|
||||
define('DEL_AUTO', 2);
|
||||
/**
|
||||
* Fully silent delete... not yet implemented
|
||||
*/
|
||||
define('DEL_SILENT', 2);
|
||||
/**
|
||||
* For HierarchicalKeys only: move all the children up one level automatically
|
||||
*/
|
||||
define('DEL_MOVEUP', 3);
|
||||
|
||||
|
||||
/**
|
||||
@@ -163,15 +170,56 @@ abstract class AttributeDefinition
|
||||
return "";
|
||||
// e.g: return array("Site", "infrid", "name");
|
||||
}
|
||||
public function GetFinalAttDef()
|
||||
{
|
||||
return $this;
|
||||
}
|
||||
public function IsDirectField() {return false;}
|
||||
public function IsScalar() {return false;}
|
||||
public function IsLinkSet() {return false;}
|
||||
public function IsExternalKey($iType = EXTKEY_RELATIVE) {return false;}
|
||||
public function IsHierarchicalKey() {return false;}
|
||||
public function IsExternalField() {return false;}
|
||||
public function IsWritable() {return false;}
|
||||
public function IsNullAllowed() {return true;}
|
||||
public function GetCode() {return $this->m_sCode;}
|
||||
public function GetLabel() {return Dict::S('Class:'.$this->m_sHostClass.'/Attribute:'.$this->m_sCode, $this->m_sCode);}
|
||||
|
||||
public function GetLabel($sDefault = null)
|
||||
{
|
||||
// If no default value is specified, let's define the most relevant one for developping purposes
|
||||
if (is_null($sDefault))
|
||||
{
|
||||
$sDefault = $this->m_sCode;
|
||||
}
|
||||
|
||||
$sLabel = Dict::S('Class:'.$this->m_sHostClass.'/Attribute:'.$this->m_sCode, '');
|
||||
if (strlen($sLabel) == 0)
|
||||
{
|
||||
// Nothing found: go higher in the hierarchy (if possible)
|
||||
//
|
||||
$sLabel = $sDefault;
|
||||
$sParentClass = MetaModel::GetParentClass($this->m_sHostClass);
|
||||
if ($sParentClass)
|
||||
{
|
||||
if (MetaModel::IsValidAttCode($sParentClass, $this->m_sCode))
|
||||
{
|
||||
$oAttDef = MetaModel::GetAttributeDef($sParentClass, $this->m_sCode);
|
||||
$sLabel = $oAttDef->GetLabel($sDefault);
|
||||
}
|
||||
}
|
||||
}
|
||||
return $sLabel;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the label corresponding to the given value
|
||||
* To be overloaded for localized enums
|
||||
*/
|
||||
public function GetValueLabel($sValue)
|
||||
{
|
||||
return GetAsHTML($sValue);
|
||||
}
|
||||
|
||||
public function GetLabel_Obsolete()
|
||||
{
|
||||
// Written for compatibility with a data model written prior to version 0.9.1
|
||||
@@ -184,8 +232,73 @@ abstract class AttributeDefinition
|
||||
return $this->GetLabel();
|
||||
}
|
||||
}
|
||||
public function GetDescription() {return Dict::S('Class:'.$this->m_sHostClass.'/Attribute:'.$this->m_sCode.'+', '');}
|
||||
public function GetHelpOnEdition() {return Dict::S('Class:'.$this->m_sHostClass.'/Attribute:'.$this->m_sCode.'?', '');}
|
||||
|
||||
public function GetDescription($sDefault = null)
|
||||
{
|
||||
// If no default value is specified, let's define the most relevant one for developping purposes
|
||||
if (is_null($sDefault))
|
||||
{
|
||||
$sDefault = '';
|
||||
}
|
||||
$sLabel = Dict::S('Class:'.$this->m_sHostClass.'/Attribute:'.$this->m_sCode.'+', '');
|
||||
if (strlen($sLabel) == 0)
|
||||
{
|
||||
// Nothing found: go higher in the hierarchy (if possible)
|
||||
//
|
||||
$sLabel = $sDefault;
|
||||
$sParentClass = MetaModel::GetParentClass($this->m_sHostClass);
|
||||
if ($sParentClass)
|
||||
{
|
||||
if (MetaModel::IsValidAttCode($sParentClass, $this->m_sCode))
|
||||
{
|
||||
$oAttDef = MetaModel::GetAttributeDef($sParentClass, $this->m_sCode);
|
||||
$sLabel = $oAttDef->GetDescription($sDefault);
|
||||
}
|
||||
}
|
||||
}
|
||||
return $sLabel;
|
||||
}
|
||||
|
||||
public function GetHelpOnEdition($sDefault = null)
|
||||
{
|
||||
// If no default value is specified, let's define the most relevant one for developping purposes
|
||||
if (is_null($sDefault))
|
||||
{
|
||||
$sDefault = '';
|
||||
}
|
||||
$sLabel = Dict::S('Class:'.$this->m_sHostClass.'/Attribute:'.$this->m_sCode.'?', '');
|
||||
if (strlen($sLabel) == 0)
|
||||
{
|
||||
// Nothing found: go higher in the hierarchy (if possible)
|
||||
//
|
||||
$sLabel = $sDefault;
|
||||
$sParentClass = MetaModel::GetParentClass($this->m_sHostClass);
|
||||
if ($sParentClass)
|
||||
{
|
||||
if (MetaModel::IsValidAttCode($sParentClass, $this->m_sCode))
|
||||
{
|
||||
$oAttDef = MetaModel::GetAttributeDef($sParentClass, $this->m_sCode);
|
||||
$sLabel = $oAttDef->GetHelpOnEdition($sDefault);
|
||||
}
|
||||
}
|
||||
}
|
||||
return $sLabel;
|
||||
}
|
||||
|
||||
public function GetHelpOnSmartSearch()
|
||||
{
|
||||
$aParents = array_merge(array(get_class($this) => get_class($this)), class_parents($this));
|
||||
foreach ($aParents as $sClass)
|
||||
{
|
||||
$sHelp = Dict::S("Core:$sClass?SmartSearch", '-missing-');
|
||||
if ($sHelp != '-missing-')
|
||||
{
|
||||
return $sHelp;
|
||||
}
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
||||
public function GetDescription_Obsolete()
|
||||
{
|
||||
// Written for compatibility with a data model written prior to version 0.9.1
|
||||
@@ -586,6 +699,28 @@ class AttributeLinkedSet extends AttributeDefinition
|
||||
}
|
||||
}
|
||||
|
||||
// Check (roughly) if such a link is valid
|
||||
$aErrors = array();
|
||||
foreach(MetaModel::ListAttributeDefs($sTargetClass) as $sAttCode => $oAttDef)
|
||||
{
|
||||
if ($oAttDef->IsExternalKey())
|
||||
{
|
||||
if (($oAttDef->GetTargetClass() == $this->GetHostClass()) || (is_subclass_of($this->GetHostClass(), $oAttDef->GetTargetClass())))
|
||||
{
|
||||
continue; // Don't check the key to self
|
||||
}
|
||||
}
|
||||
|
||||
if ($oAttDef->IsWritable() && $oAttDef->IsNull($oLink->Get($sAttCode)) && !$oAttDef->IsNullAllowed())
|
||||
{
|
||||
$aErrors[] = $sAttCode;
|
||||
}
|
||||
}
|
||||
if (count($aErrors) > 0)
|
||||
{
|
||||
throw new CoreException("Missing value for mandatory attribute(s): ".implode(', ', $aErrors));
|
||||
}
|
||||
|
||||
$aLinks[] = $oLink;
|
||||
}
|
||||
$oSet = DBObjectSet::FromArray($sTargetClass, $aLinks);
|
||||
@@ -950,6 +1085,11 @@ class AttributeBoolean extends AttributeInteger
|
||||
if ($value) return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
public function GetAsXML($sValue, $oHostObject = null)
|
||||
{
|
||||
return $sValue ? '1' : '0';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1071,6 +1211,11 @@ class AttributeString extends AttributeDBField
|
||||
$sEscaped = str_replace($sFrom, $sTo, (string)$sValue);
|
||||
return $sTextQualifier.$sEscaped.$sTextQualifier;
|
||||
}
|
||||
|
||||
public function GetDisplayStyle()
|
||||
{
|
||||
return $this->GetOptional('display_style', 'select');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1206,7 +1351,12 @@ class AttributeFinalClass extends AttributeString
|
||||
{
|
||||
return '=';
|
||||
}
|
||||
|
||||
|
||||
public function GetValueLabel($sValue)
|
||||
{
|
||||
if (empty($sValue)) return '';
|
||||
return MetaModel::GetName($sValue);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1388,7 +1538,7 @@ class AttributeText extends AttributeString
|
||||
$sText = str_replace($aMatches[0], "<span class=\"wiki_broken_link\">$sClassLabel:$sName</span>", $sText);
|
||||
// Later: propose a link to create a new object
|
||||
// Anyhow... there is no easy way to suggest default values based on the given FRIENDLY name
|
||||
//$sText = preg_replace('/\[\[(.+):(.+)\]\]/', '<a href="./UI.php?operation=new&class='.$sClass.'&default[att1]=xxx&default[att2]=yyy">'.$sName.'</a>', $sText);
|
||||
//$sText = preg_replace('/\[\[(.+):(.+)\]\]/', '<a href="'.utils::GetAbsoluteUrlAppRoot().'pages/UI.php?operation=new&class='.$sClass.'&default[att1]=xxx&default[att2]=yyy">'.$sName.'</a>', $sText);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1498,7 +1648,7 @@ class AttributeLongText extends AttributeText
|
||||
*
|
||||
* @package iTopORM
|
||||
*/
|
||||
class AttributeCaseLog extends AttributeText
|
||||
class AttributeCaseLog extends AttributeLongText
|
||||
{
|
||||
public function GetNullValue()
|
||||
{
|
||||
@@ -1684,7 +1834,7 @@ class AttributeCaseLog extends AttributeText
|
||||
*
|
||||
* @package iTopORM
|
||||
*/
|
||||
class AttributeHTML extends AttributeText
|
||||
class AttributeHTML extends AttributeLongText
|
||||
{
|
||||
public function GetEditClass() {return "HTML";}
|
||||
|
||||
@@ -1735,6 +1885,7 @@ class AttributeIPAddress extends AttributeString
|
||||
*/
|
||||
class AttributeOQL extends AttributeText
|
||||
{
|
||||
public function GetEditClass() {return "OQLExpression";}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1845,7 +1996,7 @@ class AttributeEnum extends AttributeString
|
||||
return parent::GetBasicFilterSQLExpr($sOpCode, $value);
|
||||
}
|
||||
|
||||
public function GetAsHTML($sValue, $oHostObject = null)
|
||||
public function GetValueLabel($sValue)
|
||||
{
|
||||
if (is_null($sValue))
|
||||
{
|
||||
@@ -1854,17 +2005,61 @@ class AttributeEnum extends AttributeString
|
||||
}
|
||||
else
|
||||
{
|
||||
$sLabel = Dict::S('Class:'.$this->GetHostClass().'/Attribute:'.$this->GetCode().'/Value:'.$sValue, $sValue);
|
||||
$sLabel = Dict::S('Class:'.$this->GetHostClass().'/Attribute:'.$this->GetCode().'/Value:'.$sValue, '');
|
||||
if (strlen($sLabel) == 0)
|
||||
{
|
||||
$sLabel = $sValue;
|
||||
$sParentClass = MetaModel::GetParentClass($this->m_sHostClass);
|
||||
if ($sParentClass)
|
||||
{
|
||||
if (MetaModel::IsValidAttCode($sParentClass, $this->m_sCode))
|
||||
{
|
||||
$oAttDef = MetaModel::GetAttributeDef($sParentClass, $this->m_sCode);
|
||||
$sLabel = $oAttDef->GetValueLabel($sValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
$sDescription = Dict::S('Class:'.$this->GetHostClass().'/Attribute:'.$this->GetCode().'/Value:'.$sValue.'+', $sValue);
|
||||
return $sLabel;
|
||||
}
|
||||
|
||||
public function GetValueDescription($sValue)
|
||||
{
|
||||
if (is_null($sValue))
|
||||
{
|
||||
// Unless a specific label is defined for the null value of this enum, use a generic "undefined" label
|
||||
$sDescription = Dict::S('Class:'.$this->GetHostClass().'/Attribute:'.$this->GetCode().'/Value:'.$sValue.'+', Dict::S('Enum:Undefined'));
|
||||
}
|
||||
else
|
||||
{
|
||||
$sDescription = Dict::S('Class:'.$this->GetHostClass().'/Attribute:'.$this->GetCode().'/Value:'.$sValue.'+', '');
|
||||
if (strlen($sDescription) == 0)
|
||||
{
|
||||
$sParentClass = MetaModel::GetParentClass($this->m_sHostClass);
|
||||
if ($sParentClass)
|
||||
{
|
||||
if (MetaModel::IsValidAttCode($sParentClass, $this->m_sCode))
|
||||
{
|
||||
$oAttDef = MetaModel::GetAttributeDef($sParentClass, $this->m_sCode);
|
||||
$sDescription = $oAttDef->GetValueDescription($sValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return $sDescription;
|
||||
}
|
||||
|
||||
public function GetAsHTML($sValue, $oHostObject = null)
|
||||
{
|
||||
$sLabel = $this->GetValueLabel($sValue);
|
||||
$sDescription = $this->GetValueDescription($sValue);
|
||||
// later, we could imagine a detailed description in the title
|
||||
return "<span title=\"$sDescription\">".parent::GetAsHtml($sLabel)."</span>";
|
||||
}
|
||||
|
||||
public function GetEditValue($sValue)
|
||||
{
|
||||
$sLabel = Dict::S('Class:'.$this->GetHostClass().'/Attribute:'.$this->GetCode().'/Value:'.$sValue, $sValue);
|
||||
return $sLabel;
|
||||
return $this->GetValueLabel($sValue);
|
||||
}
|
||||
|
||||
public function GetAllowedValues($aArgs = array(), $sContains = '')
|
||||
@@ -1874,7 +2069,7 @@ class AttributeEnum extends AttributeString
|
||||
$aLocalizedValues = array();
|
||||
foreach ($aRawValues as $sKey => $sValue)
|
||||
{
|
||||
$aLocalizedValues[$sKey] = Dict::S('Class:'.$this->GetHostClass().'/Attribute:'.$this->GetCode().'/Value:'.$sKey, $sKey);
|
||||
$aLocalizedValues[$sKey] = $this->GetValueLabel($sKey);
|
||||
}
|
||||
return $aLocalizedValues;
|
||||
}
|
||||
@@ -1935,7 +2130,7 @@ class AttributeDateTime extends AttributeDBField
|
||||
{
|
||||
if (empty($default))
|
||||
{
|
||||
$default = date(self::GetDateFormat());
|
||||
$default = date($this->GetDateFormat());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2118,6 +2313,7 @@ class AttributeDateTime extends AttributeDBField
|
||||
|
||||
default:
|
||||
$oNewCondition = parent::GetSmartConditionExpression($sSearchText, $oField, $aParams);
|
||||
|
||||
}
|
||||
|
||||
return $oNewCondition;
|
||||
@@ -2193,6 +2389,7 @@ class AttributeDuration extends AttributeInteger
|
||||
|
||||
static function SplitDuration($duration)
|
||||
{
|
||||
$duration = (int) $duration;
|
||||
$days = floor($duration / 86400);
|
||||
$hours = floor(($duration - (86400*$days)) / 3600);
|
||||
$minutes = floor(($duration - (86400*$days + 3600*$hours)) / 60);
|
||||
@@ -2241,17 +2438,20 @@ class AttributeDeadline extends AttributeDateTime
|
||||
$sResult = '';
|
||||
if ($value !== null)
|
||||
{
|
||||
$value = AttributeDateTime::GetAsUnixSeconds($value);
|
||||
$difference = $value - time();
|
||||
$iValue = AttributeDateTime::GetAsUnixSeconds($value);
|
||||
$sDate = parent::GetAsHTML($value, $oHostObject);
|
||||
$difference = $iValue - time();
|
||||
|
||||
if ($difference >= 0)
|
||||
{
|
||||
$sResult = self::FormatDuration($difference);
|
||||
$sDifference = self::FormatDuration($difference);
|
||||
}
|
||||
else
|
||||
{
|
||||
$sResult = Dict::Format('UI:DeadlineMissedBy_duration', self::FormatDuration(-$difference));
|
||||
$sDifference = Dict::Format('UI:DeadlineMissedBy_duration', self::FormatDuration(-$difference));
|
||||
}
|
||||
$sFormat = MetaModel::GetConfig()->Get('deadline_format', '$difference$');
|
||||
$sResult = str_replace(array('$date$', '$difference$'), array($sDate, $sDifference), $sFormat);
|
||||
}
|
||||
return $sResult;
|
||||
}
|
||||
@@ -2313,6 +2513,7 @@ class AttributeExternalKey extends AttributeDBFieldVoid
|
||||
public function GetTargetClass($iType = EXTKEY_RELATIVE) {return $this->Get("targetclass");}
|
||||
public function GetKeyAttDef($iType = EXTKEY_RELATIVE){return $this;}
|
||||
public function GetKeyAttCode() {return $this->GetCode();}
|
||||
public function GetDisplayStyle() { return $this->GetOptional('display_style', 'select'); }
|
||||
|
||||
|
||||
public function GetDefaultValue() {return 0;}
|
||||
@@ -2347,6 +2548,7 @@ class AttributeExternalKey extends AttributeDBFieldVoid
|
||||
|
||||
public function GetAllowedValues($aArgs = array(), $sContains = '')
|
||||
{
|
||||
//throw new Exception("GetAllowedValues on ext key has been deprecated");
|
||||
try
|
||||
{
|
||||
return parent::GetAllowedValues($aArgs, $sContains);
|
||||
@@ -2359,6 +2561,13 @@ class AttributeExternalKey extends AttributeDBFieldVoid
|
||||
}
|
||||
}
|
||||
|
||||
public function GetAllowedValuesAsObjectSet($aArgs = array(), $sContains = '')
|
||||
{
|
||||
$oValSetDef = $this->GetValuesDef();
|
||||
$oSet = $oValSetDef->ToObjectSet($aArgs, $sContains);
|
||||
return $oSet;
|
||||
}
|
||||
|
||||
public function GetDeletionPropagationOption()
|
||||
{
|
||||
return $this->Get("on_target_delete");
|
||||
@@ -2398,6 +2607,130 @@ class AttributeExternalKey extends AttributeDBFieldVoid
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Special kind of External Key to manage a hierarchy of objects
|
||||
*/
|
||||
class AttributeHierarchicalKey extends AttributeExternalKey
|
||||
{
|
||||
protected $m_sTargetClass;
|
||||
|
||||
static protected function ListExpectedParams()
|
||||
{
|
||||
$aParams = parent::ListExpectedParams();
|
||||
$idx = array_search('targetclass', $aParams);
|
||||
unset($aParams[$idx]);
|
||||
$idx = array_search('jointype', $aParams);
|
||||
unset($aParams[$idx]);
|
||||
return $aParams; // TODO: mettre les bons parametres ici !!
|
||||
}
|
||||
|
||||
public function GetEditClass() {return "ExtKey";}
|
||||
public function RequiresIndex()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* The target class is the class for which the attribute has been defined first
|
||||
*/
|
||||
public function SetHostClass($sHostClass)
|
||||
{
|
||||
if (!isset($this->m_sTargetClass))
|
||||
{
|
||||
$this->m_sTargetClass = $sHostClass;
|
||||
}
|
||||
parent::SetHostClass($sHostClass);
|
||||
}
|
||||
|
||||
public function IsHierarchicalKey() {return true;}
|
||||
public function GetTargetClass($iType = EXTKEY_RELATIVE) {return $this->m_sTargetClass;}
|
||||
public function GetKeyAttDef($iType = EXTKEY_RELATIVE){return $this;}
|
||||
public function GetKeyAttCode() {return $this->GetCode();}
|
||||
|
||||
public function GetBasicFilterOperators()
|
||||
{
|
||||
return parent::GetBasicFilterOperators();
|
||||
}
|
||||
public function GetBasicFilterLooseOperator()
|
||||
{
|
||||
return parent::GetBasicFilterLooseOperator();
|
||||
}
|
||||
|
||||
public function GetSQLColumns()
|
||||
{
|
||||
$aColumns = array();
|
||||
$aColumns[$this->GetCode()] = 'INT(11)';
|
||||
$aColumns[$this->GetSQLLeft()] = 'INT(11)';
|
||||
$aColumns[$this->GetSQLRight()] = 'INT(11)';
|
||||
return $aColumns;
|
||||
}
|
||||
public function GetSQLRight()
|
||||
{
|
||||
return $this->GetCode().'_right';
|
||||
}
|
||||
public function GetSQLLeft()
|
||||
{
|
||||
return $this->GetCode().'_left';
|
||||
}
|
||||
|
||||
public function GetSQLValues($value)
|
||||
{
|
||||
if (!is_array($value))
|
||||
{
|
||||
$aValues[$this->GetCode()] = $value;
|
||||
}
|
||||
else
|
||||
{
|
||||
$aValues = array();
|
||||
$aValues[$this->GetCode()] = $value[$this->GetCode()];
|
||||
$aValues[$this->GetSQLRight()] = $value[$this->GetSQLRight()];
|
||||
$aValues[$this->GetSQLLeft()] = $value[$this->GetSQLLeft()];
|
||||
}
|
||||
return $aValues;
|
||||
}
|
||||
|
||||
public function GetAllowedValues($aArgs = array(), $sContains = '')
|
||||
{
|
||||
if (array_key_exists('this', $aArgs))
|
||||
{
|
||||
// Hierarchical keys have one more constraint: the "parent value" cannot be
|
||||
// "under" themselves
|
||||
$iRootId = $aArgs['this']->GetKey();
|
||||
if ($iRootId > 0) // ignore objects that do no exist in the database...
|
||||
{
|
||||
$oValSetDef = $this->GetValuesDef();
|
||||
$sClass = $this->m_sTargetClass;
|
||||
$oFilter = DBObjectSearch::FromOQL("SELECT $sClass AS node JOIN $sClass AS root ON node.".$this->GetCode()." NOT BELOW root.id WHERE root.id = $iRootId");
|
||||
$oValSetDef->AddCondition($oFilter);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return parent::GetAllowedValues($aArgs, $sContains);
|
||||
}
|
||||
}
|
||||
|
||||
public function GetAllowedValuesAsObjectSet($aArgs = array(), $sContains = '')
|
||||
{
|
||||
$oValSetDef = $this->GetValuesDef();
|
||||
if (array_key_exists('this', $aArgs))
|
||||
{
|
||||
// Hierarchical keys have one more constraint: the "parent value" cannot be
|
||||
// "under" themselves
|
||||
$iRootId = $aArgs['this']->GetKey();
|
||||
if ($iRootId > 0) // ignore objects that do no exist in the database...
|
||||
{
|
||||
$aValuesSetDef = $this->GetValuesDef();
|
||||
$sClass = $this->m_sTargetClass;
|
||||
$oFilter = DBObjectSearch::FromOQL("SELECT $sClass AS node JOIN $sClass AS root ON node.".$this->GetCode()." NOT BELOW root.id WHERE root.id = $iRootId");
|
||||
$oValSetDef->AddCondition($oFilter);
|
||||
}
|
||||
}
|
||||
$oSet = $oValSetDef->ToObjectSet($aArgs, $sContains);
|
||||
return $oSet;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An attribute which corresponds to an external key (direct or indirect)
|
||||
*
|
||||
@@ -2411,6 +2744,13 @@ class AttributeExternalField extends AttributeDefinition
|
||||
}
|
||||
|
||||
public function GetEditClass() {return "ExtField";}
|
||||
|
||||
public function GetFinalAttDef()
|
||||
{
|
||||
$oExtAttDef = $this->GetExtAttDef();
|
||||
return $oExtAttDef->GetFinalAttDef();
|
||||
}
|
||||
|
||||
protected function GetSQLCol()
|
||||
{
|
||||
// throw new CoreException("external attribute: does it make any sense to request its type ?");
|
||||
@@ -2430,23 +2770,35 @@ class AttributeExternalField extends AttributeDefinition
|
||||
}
|
||||
}
|
||||
|
||||
public function GetLabel()
|
||||
public function GetLabel($sDefault = null)
|
||||
{
|
||||
$oRemoteAtt = $this->GetExtAttDef();
|
||||
$sDefault = $oRemoteAtt->GetLabel();
|
||||
return Dict::S('Class:'.$this->m_sHostClass.'/Attribute:'.$this->m_sCode, $sDefault);
|
||||
$sLabel = parent::GetLabel('');
|
||||
if (strlen($sLabel) == 0)
|
||||
{
|
||||
$oRemoteAtt = $this->GetExtAttDef();
|
||||
$sLabel = $oRemoteAtt->GetLabel($this->m_sCode);
|
||||
}
|
||||
return $sLabel;
|
||||
}
|
||||
public function GetDescription()
|
||||
public function GetDescription($sDefault = null)
|
||||
{
|
||||
$oRemoteAtt = $this->GetExtAttDef();
|
||||
$sDefault = $oRemoteAtt->GetDescription();
|
||||
return Dict::S('Class:'.$this->m_sHostClass.'/Attribute:'.$this->m_sCode.'+', $sDefault);
|
||||
$sLabel = parent::GetDescription('');
|
||||
if (strlen($sLabel) == 0)
|
||||
{
|
||||
$oRemoteAtt = $this->GetExtAttDef();
|
||||
$sLabel = $oRemoteAtt->GetDescription('');
|
||||
}
|
||||
return $sLabel;
|
||||
}
|
||||
public function GetHelpOnEdition()
|
||||
public function GetHelpOnEdition($sDefault = null)
|
||||
{
|
||||
$oRemoteAtt = $this->GetExtAttDef();
|
||||
$sDefault = $oRemoteAtt->GetHelpOnEdition();
|
||||
return Dict::S('Class:'.$this->m_sHostClass.'/Attribute:'.$this->m_sCode.'?', $sDefault);
|
||||
$sLabel = parent::GetHelpOnEdition('');
|
||||
if (strlen($sLabel) == 0)
|
||||
{
|
||||
$oRemoteAtt = $this->GetExtAttDef();
|
||||
$sLabel = $oRemoteAtt->GetHelpOnEdition('');
|
||||
}
|
||||
return $sLabel;
|
||||
}
|
||||
|
||||
public function IsExternalKey($iType = EXTKEY_RELATIVE)
|
||||
@@ -2503,8 +2855,8 @@ class AttributeExternalField extends AttributeDefinition
|
||||
public function GetExtAttDef()
|
||||
{
|
||||
$oKeyAttDef = $this->GetKeyAttDef();
|
||||
$oExtAttDef = MetaModel::GetAttributeDef($oKeyAttDef->Get("targetclass"), $this->Get("target_attcode"));
|
||||
if (!is_object($oExtAttDef)) throw new CoreException("Invalid external field ".$this->GetCode()." in class ".$this->GetHostClass().". The class ".$oKeyAttDef->Get("targetclass")." has no attribute ".$this->Get("target_attcode"));
|
||||
$oExtAttDef = MetaModel::GetAttributeDef($oKeyAttDef->GetTargetClass(), $this->Get("target_attcode"));
|
||||
if (!is_object($oExtAttDef)) throw new CoreException("Invalid external field ".$this->GetCode()." in class ".$this->GetHostClass().". The class ".$oKeyAttDef->GetTargetClass()." has no attribute ".$this->Get("target_attcode"));
|
||||
return $oExtAttDef;
|
||||
}
|
||||
|
||||
@@ -2944,16 +3296,26 @@ class AttributeOneWayPassword extends AttributeDefinition
|
||||
}
|
||||
|
||||
// Indexed array having two dimensions
|
||||
class AttributeTable extends AttributeText
|
||||
class AttributeTable extends AttributeDBField
|
||||
{
|
||||
public function GetEditClass() {return "Text";}
|
||||
protected function GetSQLCol() {return "TEXT";}
|
||||
public function GetEditClass() {return "Table";}
|
||||
protected function GetSQLCol() {return "LONGTEXT";}
|
||||
|
||||
public function GetMaxSize()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
public function GetNullValue()
|
||||
{
|
||||
return array();
|
||||
}
|
||||
|
||||
public function IsNull($proposedValue)
|
||||
{
|
||||
return (count($proposedValue) == 0);
|
||||
}
|
||||
|
||||
// Facilitate things: allow the user to Set the value from a string
|
||||
public function MakeRealValue($proposedValue, $oHostObj)
|
||||
{
|
||||
@@ -3016,13 +3378,39 @@ class AttributeTable extends AttributeText
|
||||
$sRes .= "</TABLE>";
|
||||
return $sRes;
|
||||
}
|
||||
|
||||
public function GetAsCSV($sValue, $sSeparator = ',', $sTextQualifier = '"', $oHostObject = null)
|
||||
{
|
||||
// Not implemented
|
||||
return '';
|
||||
}
|
||||
|
||||
public function GetAsXML($value, $oHostObject = null)
|
||||
{
|
||||
if (count($value) == 0)
|
||||
{
|
||||
return "";
|
||||
}
|
||||
|
||||
$sRes = "";
|
||||
foreach($value as $iRow => $aRawData)
|
||||
{
|
||||
$sRes .= "<row>";
|
||||
foreach ($aRawData as $iCol => $cell)
|
||||
{
|
||||
$sCell = Str::pure2xml((string)$cell);
|
||||
$sRes .= "<cell icol=\"$iCol\">$sCell</cell>";
|
||||
}
|
||||
$sRes .= "</row>";
|
||||
}
|
||||
return $sRes;
|
||||
}
|
||||
}
|
||||
|
||||
// The PHP value is a hash array, it is stored as a TEXT column
|
||||
class AttributePropertySet extends AttributeTable
|
||||
{
|
||||
public function GetEditClass() {return "Text";}
|
||||
protected function GetSQLCol() {return "TEXT";}
|
||||
public function GetEditClass() {return "PropertySet";}
|
||||
|
||||
// Facilitate things: allow the user to Set the value from a string
|
||||
public function MakeRealValue($proposedValue, $oHostObj)
|
||||
@@ -3049,6 +3437,10 @@ class AttributePropertySet extends AttributeTable
|
||||
$sRes .= "<TBODY>";
|
||||
foreach($value as $sProperty => $sValue)
|
||||
{
|
||||
if ($sProperty == 'auth_pwd')
|
||||
{
|
||||
$sValue = '*****';
|
||||
}
|
||||
$sRes .= "<TR>";
|
||||
$sCell = str_replace("\n", "<br>\n", Str::pure2html((string)$sValue));
|
||||
$sRes .= "<TD class=\"label\">$sProperty</TD><TD>$sCell</TD>";
|
||||
@@ -3058,6 +3450,53 @@ class AttributePropertySet extends AttributeTable
|
||||
$sRes .= "</TABLE>";
|
||||
return $sRes;
|
||||
}
|
||||
|
||||
public function GetAsCSV($value, $sSeparator = ',', $sTextQualifier = '"', $oHostObject = null)
|
||||
{
|
||||
if (count($value) == 0)
|
||||
{
|
||||
return "";
|
||||
}
|
||||
|
||||
$aRes = array();
|
||||
foreach($value as $sProperty => $sValue)
|
||||
{
|
||||
if ($sProperty == 'auth_pwd')
|
||||
{
|
||||
$sValue = '*****';
|
||||
}
|
||||
$sFrom = array(',', '=');
|
||||
$sTo = array('\,', '\=');
|
||||
$aRes[] = $sProperty.'='.str_replace($sFrom, $sTo, (string)$sValue);
|
||||
}
|
||||
$sRaw = implode(',', $aRes);
|
||||
|
||||
$sFrom = array("\r\n", $sTextQualifier);
|
||||
$sTo = array("\n", $sTextQualifier.$sTextQualifier);
|
||||
$sEscaped = str_replace($sFrom, $sTo, $sRaw);
|
||||
return $sTextQualifier.$sEscaped.$sTextQualifier;
|
||||
}
|
||||
|
||||
public function GetAsXML($value, $oHostObject = null)
|
||||
{
|
||||
if (count($value) == 0)
|
||||
{
|
||||
return "";
|
||||
}
|
||||
|
||||
$sRes = "";
|
||||
foreach($value as $sProperty => $sValue)
|
||||
{
|
||||
if ($sProperty == 'auth_pwd')
|
||||
{
|
||||
$sValue = '*****';
|
||||
}
|
||||
$sRes .= "<property id=\"$sProperty\">";
|
||||
$sRes .= Str::pure2xml((string)$sValue);
|
||||
$sRes .= "</property>";
|
||||
}
|
||||
return $sRes;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -3160,6 +3599,43 @@ class AttributeFriendlyName extends AttributeComputedFieldVoid
|
||||
|
||||
public function GetKeyAttCode() {return $this->Get("extkey_attcode");}
|
||||
|
||||
public function GetLabel($sDefault = null)
|
||||
{
|
||||
$sLabel = parent::GetLabel('');
|
||||
if (strlen($sLabel) == 0)
|
||||
{
|
||||
$sKeyAttCode = $this->Get("extkey_attcode");
|
||||
if ($sKeyAttCode == 'id')
|
||||
{
|
||||
return Dict::S('Core:FriendlyName-Label');
|
||||
}
|
||||
else
|
||||
{
|
||||
$oExtKeyAttDef = MetaModel::GetAttributeDef($this->GetHostClass(), $sKeyAttCode);
|
||||
$sLabel = $oExtKeyAttDef->GetLabel($this->m_sCode);
|
||||
}
|
||||
}
|
||||
return $sLabel;
|
||||
}
|
||||
public function GetDescription($sDefault = null)
|
||||
{
|
||||
$sLabel = parent::GetDescription('');
|
||||
if (strlen($sLabel) == 0)
|
||||
{
|
||||
$sKeyAttCode = $this->Get("extkey_attcode");
|
||||
if ($sKeyAttCode == 'id')
|
||||
{
|
||||
return Dict::S('Core:FriendlyName-Description');
|
||||
}
|
||||
else
|
||||
{
|
||||
$oExtKeyAttDef = MetaModel::GetAttributeDef($this->GetHostClass(), $sKeyAttCode);
|
||||
$sLabel = $oExtKeyAttDef->GetDescription('');
|
||||
}
|
||||
}
|
||||
return $sLabel;
|
||||
}
|
||||
|
||||
// n/a, the friendly name is made of a complex expression (see GetNameSpec)
|
||||
protected function GetSQLCol() {return "";}
|
||||
|
||||
|
||||
@@ -252,8 +252,9 @@ class BulkChange
|
||||
protected $m_aReconcilKeys; // attcode (attcode = 'id' for the pkey)
|
||||
protected $m_sSynchroScope; // OQL - if specified, then the missing items will be reported
|
||||
protected $m_aOnDisappear; // array of attcode => value, values to be set when an object gets out of scope (ignored if no scope has been defined)
|
||||
protected $m_sDateFormat; // Date format specification, see utils::StringToTime()
|
||||
|
||||
public function __construct($sClass, $aData, $aAttList, $aExtKeys, $aReconcilKeys, $sSynchroScope = null, $aOnDisappear = null)
|
||||
public function __construct($sClass, $aData, $aAttList, $aExtKeys, $aReconcilKeys, $sSynchroScope = null, $aOnDisappear = null, $sDateFormat = null)
|
||||
{
|
||||
$this->m_sClass = $sClass;
|
||||
$this->m_aData = $aData;
|
||||
@@ -262,6 +263,7 @@ class BulkChange
|
||||
$this->m_aExtKeys = $aExtKeys;
|
||||
$this->m_sSynchroScope = $sSynchroScope;
|
||||
$this->m_aOnDisappear = $aOnDisappear;
|
||||
$this->m_sDateFormat = $sDateFormat;
|
||||
}
|
||||
|
||||
protected $m_bReportHtml = false;
|
||||
@@ -399,7 +401,13 @@ class BulkChange
|
||||
if ($sAttCode == 'id') continue;
|
||||
|
||||
$oAttDef = MetaModel::GetAttributeDef($this->m_sClass, $sAttCode);
|
||||
if ($oAttDef->IsLinkSet() && $oAttDef->IsIndirect())
|
||||
$aReasons = array();
|
||||
$iFlags = $oTargetObj->GetAttributeFlags($sAttCode, $aReasons);
|
||||
if ( (($iFlags & OPT_ATT_READONLY) == OPT_ATT_READONLY) && ( $oTargetObj->Get($sAttCode) != $aRowData[$iCol]) )
|
||||
{
|
||||
$aErrors[$sAttCode] = "the attribute '$sAttCode' is read-only and cannot be modified (current value: ".$oTargetObj->Get($sAttCode).", proposed value: {$aRowData[$iCol]}).";
|
||||
}
|
||||
else if ($oAttDef->IsLinkSet() && $oAttDef->IsIndirect())
|
||||
{
|
||||
try
|
||||
{
|
||||
@@ -412,7 +420,7 @@ class BulkChange
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
{
|
||||
$res = $oTargetObj->CheckValue($sAttCode, $aRowData[$iCol]);
|
||||
if ($res === true)
|
||||
{
|
||||
@@ -702,6 +710,35 @@ class BulkChange
|
||||
exit;
|
||||
}
|
||||
|
||||
$aResult = array();
|
||||
|
||||
if (!is_null($this->m_sDateFormat) && (strlen($this->m_sDateFormat) > 0))
|
||||
{
|
||||
// Translate dates from the source data
|
||||
//
|
||||
foreach ($this->m_aAttList as $sAttCode => $iCol)
|
||||
{
|
||||
$oAttDef = MetaModel::GetAttributeDef($this->m_sClass, $sAttCode);
|
||||
if ($oAttDef instanceof AttributeDateTime)
|
||||
{
|
||||
foreach($this->m_aData as $iRow => $aRowData)
|
||||
{
|
||||
$sNewDate = utils::StringToTime($this->m_aData[$iRow][$iCol], $this->m_sDateFormat);
|
||||
if ($sNewDate !== false)
|
||||
{
|
||||
// Todo - improve the reporting
|
||||
$this->m_aData[$iRow][$iCol] = $sNewDate;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Leave the cell unchanged
|
||||
$aResult[$iRow]["__STATUS__"]= new RowStatus_Issue("wrong date format");
|
||||
$aResult[$iRow][$sAttCode] = new CellStatus_Issue(null, $this->m_aData[$iRow][$iCol], 'Wrong date format');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Compute the results
|
||||
//
|
||||
@@ -709,9 +746,13 @@ class BulkChange
|
||||
{
|
||||
$aVisited = array();
|
||||
}
|
||||
$aResult = array();
|
||||
foreach($this->m_aData as $iRow => $aRowData)
|
||||
{
|
||||
if (isset($aResult[$iRow]["__STATUS__"]))
|
||||
{
|
||||
// An issue at the earlier steps - skip the rest
|
||||
continue;
|
||||
}
|
||||
$oReconciliationFilter = new CMDBSearchFilter($this->m_sClass);
|
||||
$bSkipQuery = false;
|
||||
foreach($this->m_aReconcilKeys as $sAttCode)
|
||||
@@ -798,8 +839,28 @@ class BulkChange
|
||||
$aResult[$iRow]["finalclass"]= 'n/a';
|
||||
}
|
||||
}
|
||||
|
||||
// Whatever happened, do report the reconciliation values
|
||||
}
|
||||
|
||||
if (!is_null($this->m_sSynchroScope))
|
||||
{
|
||||
// Compute the delta between the scope and visited objects
|
||||
$oScopeSearch = DBObjectSearch::FromOQL($this->m_sSynchroScope);
|
||||
$oScopeSet = new DBObjectSet($oScopeSearch);
|
||||
while ($oObj = $oScopeSet->Fetch())
|
||||
{
|
||||
$iObj = $oObj->GetKey();
|
||||
if (!in_array($iObj, $aVisited))
|
||||
{
|
||||
$iRow++;
|
||||
$this->UpdateMissingObject($aResult, $iRow, $oObj, $oChange);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Fill in the blanks - the result matrix is expected to be 100% complete
|
||||
//
|
||||
foreach($this->m_aData as $iRow => $aRowData)
|
||||
{
|
||||
foreach($this->m_aAttList as $iCol)
|
||||
{
|
||||
if (!array_key_exists($iCol, $aResult[$iRow]))
|
||||
@@ -824,22 +885,6 @@ class BulkChange
|
||||
}
|
||||
}
|
||||
|
||||
if (!is_null($this->m_sSynchroScope))
|
||||
{
|
||||
// Compute the delta between the scope and visited objects
|
||||
$oScopeSearch = DBObjectSearch::FromOQL($this->m_sSynchroScope);
|
||||
$oScopeSet = new DBObjectSet($oScopeSearch);
|
||||
while ($oObj = $oScopeSet->Fetch())
|
||||
{
|
||||
$iObj = $oObj->GetKey();
|
||||
if (!in_array($iObj, $aVisited))
|
||||
{
|
||||
$iRow++;
|
||||
$this->UpdateMissingObject($aResult, $iRow, $oObj, $oChange);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $aResult;
|
||||
}
|
||||
|
||||
@@ -960,7 +1005,7 @@ EOF
|
||||
<<<EOF
|
||||
function OnTruncatedHistoryToggle(bShowAll)
|
||||
{
|
||||
$.get('../pages/ajax.render.php?{$sAppContext}', {operation: 'displayCSVHistory', showall: bShowAll}, function(data)
|
||||
$.get(GetAbsoluteUrlAppRoot()+'pages/ajax.render.php?{$sAppContext}', {operation: 'displayCSVHistory', showall: bShowAll}, function(data)
|
||||
{
|
||||
$('#$sAjaxDivId').html(data);
|
||||
var table = $('#$sAjaxDivId .listResults');
|
||||
@@ -1032,10 +1077,19 @@ EOF
|
||||
$oAttDef = MetaModel::GetAttributeDef($sClass, $sAttCode);
|
||||
if ($oAttDef->IsExternalKey())
|
||||
{
|
||||
$oOldTarget = MetaModel::GetObject($oAttDef->GetTargetClass(), $oOperation->Get('oldvalue'));
|
||||
$oNewTarget = MetaModel::GetObject($oAttDef->GetTargetClass(), $oOperation->Get('newvalue'));
|
||||
$sOldValue = $oOldTarget->GetHyperlink();
|
||||
$sNewValue = $oNewTarget->GetHyperlink();
|
||||
$sOldValue = Dict::S('UI:UndefinedObject');
|
||||
if ($oOperation->Get('oldvalue') != 0)
|
||||
{
|
||||
$oOldTarget = MetaModel::GetObject($oAttDef->GetTargetClass(), $oOperation->Get('oldvalue'));
|
||||
$sOldValue = $oOldTarget->GetHyperlink();
|
||||
}
|
||||
|
||||
$sNewValue = Dict::S('UI:UndefinedObject');
|
||||
if ($oOperation->Get('newvalue') != 0)
|
||||
{
|
||||
$oNewTarget = MetaModel::GetObject($oAttDef->GetTargetClass(), $oOperation->Get('newvalue'));
|
||||
$sNewValue = $oNewTarget->GetHyperlink();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -212,11 +212,27 @@ class CMDBChangeOpSetAttributeScalar extends CMDBChangeOpSetAttribute
|
||||
$oMonoObjectSet = new DBObjectSet($oTargetSearch);
|
||||
if (UserRights::IsActionAllowedOnAttribute($this->Get('objclass'), $this->Get('attcode'), UR_ACTION_READ, $oMonoObjectSet) == UR_ALLOWED_YES)
|
||||
{
|
||||
if (!MetaModel::IsValidAttCode($this->Get('objclass'), $this->Get('attcode'))) return ''; // Protects against renamed attributes...
|
||||
|
||||
$oAttDef = MetaModel::GetAttributeDef($this->Get('objclass'), $this->Get('attcode'));
|
||||
$sAttName = $oAttDef->GetLabel();
|
||||
$sNewValue = $this->Get('newvalue');
|
||||
$sOldValue = $this->Get('oldvalue');
|
||||
if ( (($oAttDef->GetType() == 'String') || ($oAttDef->GetType() == 'Text')) &&
|
||||
if ($oAttDef instanceof AttributeEnum)
|
||||
{
|
||||
// translate the enum values
|
||||
$sOldValue = $oAttDef->GetAsHTML($sOldValue);
|
||||
$sNewValue = $oAttDef->GetAsHTML($sNewValue);
|
||||
if (strlen($sOldValue) == 0)
|
||||
{
|
||||
$sResult = Dict::Format('Change:AttName_SetTo', $sAttName, $sNewValue);
|
||||
}
|
||||
else
|
||||
{
|
||||
$sResult = Dict::Format('Change:AttName_SetTo_NewValue_PreviousValue_OldValue', $sAttName, $sNewValue, $sOldValue);
|
||||
}
|
||||
}
|
||||
elseif ( (($oAttDef->GetType() == 'String') || ($oAttDef->GetType() == 'Text')) &&
|
||||
(strlen($sNewValue) > strlen($sOldValue)) )
|
||||
{
|
||||
// Check if some text was not appended to the field
|
||||
@@ -554,4 +570,41 @@ class CMDBChangeOpSetAttributeCaseLog extends CMDBChangeOpSetAttribute
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Record an action made by a plug-in
|
||||
*
|
||||
* @package iTopORM
|
||||
*/
|
||||
class CMDBChangeOpPlugin extends CMDBChangeOp
|
||||
{
|
||||
public static function Init()
|
||||
{
|
||||
$aParams = array
|
||||
(
|
||||
"category" => "core/cmdb",
|
||||
"key_type" => "",
|
||||
"name_attcode" => "change",
|
||||
"state_attcode" => "",
|
||||
"reconc_keys" => array(),
|
||||
"db_table" => "priv_changeop_plugin",
|
||||
"db_key_field" => "id",
|
||||
"db_finalclass_field" => "",
|
||||
);
|
||||
MetaModel::Init_Params($aParams);
|
||||
MetaModel::Init_AddAttribute(new AttributeString("description", array("allowed_values"=>null, "sql"=>"description", "default_value"=>'', "is_null_allowed"=>false, "depends_on"=>array())));
|
||||
/* May be used later when implementing an extension mechanism that will allow the plug-ins to store some extra information and still degrades gracefully when the plug-in is desinstalled
|
||||
MetaModel::Init_AddAttribute(new AttributeString("extension_class", array("allowed_values"=>null, "sql"=>"extension_class", "default_value"=>'', "is_null_allowed"=>false, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeInteger("extension_id", array("allowed_values"=>null, "sql"=>"extension_id", "default_value"=>0, "is_null_allowed"=>false, "depends_on"=>array())));
|
||||
*/
|
||||
MetaModel::Init_InheritAttributes();
|
||||
}
|
||||
|
||||
/**
|
||||
* Describe (as a text string) the modifications corresponding to this change
|
||||
*/
|
||||
public function GetDescription()
|
||||
{
|
||||
return $this->Get('description');
|
||||
}
|
||||
}
|
||||
?>
|
||||
|
||||
@@ -76,6 +76,7 @@ require_once('cmdbchangeop.class.inc.php');
|
||||
// Romain: temporary moved into application.inc.php (see explanations there)
|
||||
//require_once('event.class.inc.php');
|
||||
|
||||
require_once('templatestring.class.inc.php');
|
||||
require_once('csvparser.class.inc.php');
|
||||
require_once('bulkchange.class.inc.php');
|
||||
|
||||
@@ -279,9 +280,10 @@ abstract class CMDBObject extends DBObject
|
||||
{
|
||||
$this->CheckUserRights($bSkipStrongSecurity, UR_ACTION_MODIFY);
|
||||
|
||||
$oPreviousChange = self::$m_oCurrChange;
|
||||
self::$m_oCurrChange = $oChange;
|
||||
$ret = $this->DBInsertTracked_Internal();
|
||||
self::$m_oCurrChange = null;
|
||||
self::$m_oCurrChange = $oPreviousChange;
|
||||
return $ret;
|
||||
}
|
||||
|
||||
@@ -289,9 +291,10 @@ abstract class CMDBObject extends DBObject
|
||||
{
|
||||
$this->CheckUserRights($bSkipStrongSecurity, UR_ACTION_MODIFY);
|
||||
|
||||
$oPreviousChange = self::$m_oCurrChange;
|
||||
self::$m_oCurrChange = $oChange;
|
||||
$ret = $this->DBInsertTracked_Internal(true);
|
||||
self::$m_oCurrChange = null;
|
||||
self::$m_oCurrChange = $oPreviousChange;
|
||||
return $ret;
|
||||
}
|
||||
|
||||
@@ -320,9 +323,10 @@ abstract class CMDBObject extends DBObject
|
||||
|
||||
public function DBCloneTracked(CMDBChange $oChange, $newKey = null)
|
||||
{
|
||||
$oPreviousChange = self::$m_oCurrChange;
|
||||
self::$m_oCurrChange = $oChange;
|
||||
$this->DBCloneTracked_Internal($newKey);
|
||||
self::$m_oCurrChange = null;
|
||||
self::$m_oCurrChange = $oPreviousChange;
|
||||
}
|
||||
|
||||
protected function DBCloneTracked_Internal($newKey = null)
|
||||
@@ -347,9 +351,10 @@ abstract class CMDBObject extends DBObject
|
||||
{
|
||||
$this->CheckUserRights($bSkipStrongSecurity, UR_ACTION_MODIFY);
|
||||
|
||||
$oPreviousChange = self::$m_oCurrChange;
|
||||
self::$m_oCurrChange = $oChange;
|
||||
$this->DBUpdateTracked_Internal();
|
||||
self::$m_oCurrChange = null;
|
||||
self::$m_oCurrChange = $oPreviousChange;
|
||||
}
|
||||
|
||||
protected function DBUpdateTracked_Internal()
|
||||
@@ -382,9 +387,10 @@ abstract class CMDBObject extends DBObject
|
||||
{
|
||||
$this->CheckUserRights($bSkipStrongSecurity, UR_ACTION_DELETE);
|
||||
|
||||
$oPreviousChange = self::$m_oCurrChange;
|
||||
self::$m_oCurrChange = $oChange;
|
||||
$this->DBDeleteTracked_Internal($oDeletionPlan);
|
||||
self::$m_oCurrChange = null;
|
||||
self::$m_oCurrChange = $oPreviousChange;
|
||||
}
|
||||
|
||||
protected function DBDeleteTracked_Internal(&$oDeletionPlan = null)
|
||||
@@ -406,9 +412,10 @@ abstract class CMDBObject extends DBObject
|
||||
|
||||
public static function BulkDeleteTracked(CMDBChange $oChange, DBObjectSearch $oFilter)
|
||||
{
|
||||
$oPreviousChange = self::$m_oCurrChange;
|
||||
self::$m_oCurrChange = $oChange;
|
||||
$this->BulkDeleteTracked_Internal($oFilter);
|
||||
self::$m_oCurrChange = null;
|
||||
self::$m_oCurrChange = $oPreviousChange;
|
||||
}
|
||||
|
||||
protected static function BulkDeleteTracked_Internal(DBObjectSearch $oFilter)
|
||||
@@ -445,9 +452,10 @@ abstract class CMDBObject extends DBObject
|
||||
|
||||
public static function BulkUpdateTracked(CMDBChange $oChange, DBObjectSearch $oFilter, array $aValues)
|
||||
{
|
||||
$oPreviousChange = self::$m_oCurrChange;
|
||||
self::$m_oCurrChange = $oChange;
|
||||
$this->BulkUpdateTracked_Internal($oFilter, $aValues);
|
||||
self::$m_oCurrChange = null;
|
||||
self::$m_oCurrChange = $oPreviousChange;
|
||||
}
|
||||
|
||||
protected static function BulkUpdateTracked_Internal(DBObjectSearch $oFilter, array $aValues)
|
||||
@@ -498,24 +506,22 @@ class CMDBObjectSet extends DBObjectSet
|
||||
static public function FromScratch($sClass)
|
||||
{
|
||||
$oFilter = new CMDBSearchFilter($sClass);
|
||||
$oRetSet = new CMDBObjectSet($oFilter); // THE ONLY DIFF IS HERE
|
||||
// NOTE: THIS DOES NOT WORK IF m_bLoaded is private...
|
||||
// BUT IT THAT CASE YOU DO NOT GET ANY ERROR !!!!!
|
||||
$oFilter->AddConditionExpression(new FalseExpression());
|
||||
$oRetSet = new self($oFilter);
|
||||
// NOTE: THIS DOES NOT WORK IF m_bLoaded is private in the base class (and you will not get any error message)
|
||||
$oRetSet->m_bLoaded = true; // no DB load
|
||||
return $oRetSet;
|
||||
}
|
||||
|
||||
// create an object set ex nihilo
|
||||
// input = array of objects
|
||||
static public function FromArray($sClass, $aObjects)
|
||||
{
|
||||
$oFilter = new CMDBSearchFilter($sClass);
|
||||
$oRetSet = new CMDBObjectSet($oFilter); // THE ONLY DIFF IS HERE
|
||||
// NOTE: THIS DOES NOT WORK IF m_bLoaded is private...
|
||||
// BUT IT THAT CASE YOU DO NOT GET ANY ERROR !!!!!
|
||||
$oRetSet->m_bLoaded = true; // no DB load
|
||||
$oRetSet->AddObjectArray($aObjects);
|
||||
$oRetSet = self::FromScratch($sClass);
|
||||
$oRetSet->AddObjectArray($aObjects, $sClass);
|
||||
return $oRetSet;
|
||||
}
|
||||
|
||||
|
||||
static public function FromArrayAssoc($aClasses, $aObjects)
|
||||
{
|
||||
// In a perfect world, we should create a complete tree of DBObjectSearch,
|
||||
|
||||
@@ -58,7 +58,6 @@ define ('DEFAULT_MAX_DISPLAY_LIMIT', 15);
|
||||
define ('DEFAULT_STANDARD_RELOAD_INTERVAL', 5*60);
|
||||
define ('DEFAULT_FAST_RELOAD_INTERVAL', 1*60);
|
||||
define ('DEFAULT_SECURE_CONNECTION_REQUIRED', false);
|
||||
define ('DEFAULT_HTTPS_HYPERLINKS', false);
|
||||
define ('DEFAULT_ALLOWED_LOGIN_TYPES', 'form|basic|external');
|
||||
define ('DEFAULT_EXT_AUTH_VARIABLE', '$_SERVER[\'REMOTE_USER\']');
|
||||
define ('DEFAULT_ENCRYPTION_KEY', '@iT0pEncr1pti0n!'); // We'll use a random value, later...
|
||||
@@ -85,6 +84,14 @@ class Config
|
||||
// New way to store the settings !
|
||||
//
|
||||
protected $m_aSettings = array(
|
||||
'app_root_url' => array(
|
||||
'type' => 'string',
|
||||
'description' => 'Root URL used for navigating within the application, or from an email to the application (you can put $SERVER_NAME$ as a placeholder for the server\'s name)',
|
||||
'default' => '',
|
||||
'value' => '',
|
||||
'source_of_value' => '',
|
||||
'show_in_conf_sample' => true,
|
||||
),
|
||||
'skip_check_to_write' => array(
|
||||
'type' => 'bool',
|
||||
'description' => 'Disable data format and integrity checks to boost up data load (insert or update)',
|
||||
@@ -117,6 +124,14 @@ class Config
|
||||
'source_of_value' => '',
|
||||
'show_in_conf_sample' => false,
|
||||
),
|
||||
'php_path' => array(
|
||||
'type' => 'string',
|
||||
'description' => 'Path to the php executable in CLI mode',
|
||||
'default' => 'php',
|
||||
'value' => 'php',
|
||||
'source_of_value' => '',
|
||||
'show_in_conf_sample' => true,
|
||||
),
|
||||
'session_name' => array(
|
||||
'type' => 'string',
|
||||
'description' => 'The name of the cookie used to store the PHP session id',
|
||||
@@ -182,6 +197,14 @@ class Config
|
||||
'source_of_value' => '',
|
||||
'show_in_conf_sample' => false,
|
||||
),
|
||||
'csv_import_history_display' => array(
|
||||
'type' => 'bool',
|
||||
'description' => 'Display the history tab in the import wizard',
|
||||
'default' => true,
|
||||
'value' => true,
|
||||
'source_of_value' => '',
|
||||
'show_in_conf_sample' => true,
|
||||
),
|
||||
'access_mode' => array(
|
||||
'type' => 'integer',
|
||||
'description' => 'Combination of flags (ACCESS_USER_WRITE | ACCESS_ADMIN_WRITE, or ACCESS_FULL)',
|
||||
@@ -304,12 +327,169 @@ class Config
|
||||
'source_of_value' => '',
|
||||
'show_in_conf_sample' => true,
|
||||
),
|
||||
'cas_include_path' => array(
|
||||
'type' => 'string',
|
||||
'description' => 'The path where to find the phpCAS library',
|
||||
// examples... not used (nor 'description')
|
||||
'default' => '/usr/share/php',
|
||||
'value' => '/usr/share/php',
|
||||
'source_of_value' => '',
|
||||
'show_in_conf_sample' => true,
|
||||
),
|
||||
'cas_version' => array(
|
||||
'type' => 'string',
|
||||
'description' => 'The CAS protocol version to use: "1.0" (CAS v1), "2.0" (CAS v2) or "S1" (SAML V1) )',
|
||||
// examples... not used (nor 'description')
|
||||
'default' => '2.0',
|
||||
'value' => '',
|
||||
'source_of_value' => '',
|
||||
'show_in_conf_sample' => true,
|
||||
),
|
||||
'cas_host' => array(
|
||||
'type' => 'string',
|
||||
'description' => 'The name of the CAS host',
|
||||
// examples... not used (nor 'description')
|
||||
'default' => '',
|
||||
'value' => '',
|
||||
'source_of_value' => '',
|
||||
'show_in_conf_sample' => true,
|
||||
),
|
||||
'cas_port' => array(
|
||||
'type' => 'integer',
|
||||
'description' => 'The port used by the CAS server',
|
||||
// examples... not used (nor 'description')
|
||||
'default' => 443,
|
||||
'value' => 443,
|
||||
'source_of_value' => '',
|
||||
'show_in_conf_sample' => true,
|
||||
),
|
||||
'cas_context' => array(
|
||||
'type' => 'string',
|
||||
'description' => 'The CAS context',
|
||||
// examples... not used (nor 'description')
|
||||
'default' => '',
|
||||
'value' => '',
|
||||
'source_of_value' => '',
|
||||
'show_in_conf_sample' => true,
|
||||
),
|
||||
'cas_server_ca_cert_path' => array(
|
||||
'type' => 'string',
|
||||
'description' => 'The path where to find the certificate of the CA for validating the certificate of the CAS server',
|
||||
// examples... not used (nor 'description')
|
||||
'default' => '',
|
||||
'value' => '',
|
||||
'source_of_value' => '',
|
||||
'show_in_conf_sample' => true,
|
||||
),
|
||||
'cas_logout_redirect_service' => array(
|
||||
'type' => 'string',
|
||||
'description' => 'The redirect service (URL) to use when logging-out with CAS',
|
||||
// examples... not used (nor 'description')
|
||||
'default' => '',
|
||||
'value' => '',
|
||||
'source_of_value' => '',
|
||||
'show_in_conf_sample' => true,
|
||||
),
|
||||
'cas_memberof' => array(
|
||||
'type' => 'string',
|
||||
'description' => 'A semicolon separated list of group names that the user must be member of (works only with SAML - e.g. cas_version=> "S1")',
|
||||
// examples... not used (nor 'description')
|
||||
'default' => '',
|
||||
'value' => '',
|
||||
'source_of_value' => '',
|
||||
'show_in_conf_sample' => true,
|
||||
),
|
||||
'cas_user_synchro' => array(
|
||||
'type' => 'bool',
|
||||
'description' => 'Whether or not to synchronize users with CAS/LDAP',
|
||||
// examples... not used (nor 'description')
|
||||
'default' => 0,
|
||||
'value' => 0,
|
||||
'source_of_value' => '',
|
||||
'show_in_conf_sample' => true,
|
||||
),
|
||||
'cas_update_profiles' => array(
|
||||
'type' => 'bool',
|
||||
'description' => 'Whether or not to update the profiles of an existing user from the CAS information',
|
||||
// examples... not used (nor 'description')
|
||||
'default' => 0,
|
||||
'value' => 0,
|
||||
'source_of_value' => '',
|
||||
'show_in_conf_sample' => true,
|
||||
),
|
||||
'cas_profile_pattern' => array(
|
||||
'type' => 'string',
|
||||
'description' => 'A regular expression pattern to extract the name of the iTop profile from the name of an LDAP/CAS group',
|
||||
// examples... not used (nor 'description')
|
||||
'default' => '/^cn=([^,]+),/',
|
||||
'value' => '/^cn=([^,]+),/',
|
||||
'source_of_value' => '',
|
||||
'show_in_conf_sample' => true,
|
||||
),
|
||||
'cas_default_profiles' => array(
|
||||
'type' => 'string',
|
||||
'description' => 'A semi-colon separated list of iTop Profiles to use when creating a new user if no profile is retrieved from CAS',
|
||||
// examples... not used (nor 'description')
|
||||
'default' => 'Portal user',
|
||||
'value' => 'Portal user',
|
||||
'source_of_value' => '',
|
||||
'show_in_conf_sample' => true,
|
||||
),
|
||||
'cas_debug' => array(
|
||||
'type' => 'bool',
|
||||
'description' => 'Activate the CAS debug',
|
||||
// examples... not used (nor 'description')
|
||||
'default' => false,
|
||||
'value' => false,
|
||||
'source_of_value' => '',
|
||||
'show_in_conf_sample' => true,
|
||||
),
|
||||
'deadline_format' => array(
|
||||
'type' => 'string',
|
||||
'description' => 'The format used for displaying "deadline" attributes: any string with the following placeholders: $date$, $difference$',
|
||||
// examples... $date$ ($deadline$)
|
||||
'default' => '$difference$',
|
||||
'value' => '$difference$',
|
||||
'source_of_value' => '',
|
||||
'show_in_conf_sample' => true,
|
||||
),
|
||||
'buttons_position' => array(
|
||||
'type' => 'string',
|
||||
'description' => 'Position of the forms buttons: bottom | top | both',
|
||||
// examples... not used
|
||||
'default' => 'both',
|
||||
'value' => 'both',
|
||||
'source_of_value' => '',
|
||||
'show_in_conf_sample' => true,
|
||||
),
|
||||
'shortcut_actions' => array(
|
||||
'type' => 'string',
|
||||
'description' => 'Actions that are available as direct buttons next to the "Actions" menu',
|
||||
// examples... not used
|
||||
'default' => 'UI:Menu:Modify,UI:Menu:New',
|
||||
'value' => 'UI:Menu:Modify',
|
||||
'source_of_value' => '',
|
||||
'show_in_conf_sample' => true,
|
||||
),
|
||||
'complex_actions_limit' => array(
|
||||
'type' => 'integer',
|
||||
'description' => 'Display the "actions" menu items that require long computation only if the list of objects is contains less objects than this number (0 means no limit)',
|
||||
// examples... not used
|
||||
'default' => 50,
|
||||
'value' => 50,
|
||||
'source_of_value' => '',
|
||||
'show_in_conf_sample' => false,
|
||||
),
|
||||
);
|
||||
|
||||
public function IsProperty($sPropCode)
|
||||
{
|
||||
return (array_key_exists($sPropCode, $this->m_aSettings));
|
||||
}
|
||||
public function GetDescription($sPropCode)
|
||||
{
|
||||
return $this->m_aSettings[$sPropCode];
|
||||
}
|
||||
|
||||
public function Set($sPropCode, $value, $sSourceDesc = 'unknown')
|
||||
{
|
||||
@@ -388,13 +568,6 @@ class Config
|
||||
*/
|
||||
protected $m_bSecureConnectionRequired;
|
||||
|
||||
/**
|
||||
* @var boolean Forces iTop to output hyperlinks starting with https:// even
|
||||
* if the current page is not using https. This can be useful when
|
||||
* the application runs behind a SSL gateway
|
||||
*/
|
||||
protected $m_bHttpsHyperlinks;
|
||||
|
||||
/**
|
||||
* @var string Langage code, default if the user language is undefined
|
||||
*/
|
||||
@@ -432,6 +605,7 @@ class Config
|
||||
'application/menunode.class.inc.php',
|
||||
'application/user.preferences.class.inc.php',
|
||||
'application/audit.rule.class.inc.php',
|
||||
'application/query.class.inc.php',
|
||||
// Romain - That's dirty, because those classes are in fact part of the core
|
||||
// but I needed those classes to be derived from cmdbAbstractObject
|
||||
// (to be managed via the GUI) and this class in not really known from
|
||||
@@ -450,29 +624,8 @@ class Config
|
||||
// Default AddOn, always present can be moved to an official iTop Module later if needed
|
||||
'user rights' => 'addons/userrights/userrightsprofile.class.inc.php',
|
||||
);
|
||||
$this->m_aDictionaries = array(
|
||||
// Default dictionaries, always present can be moved to an official iTop Module later if needed
|
||||
'dictionaries/dictionary.itop.core.php',
|
||||
'dictionaries/dictionary.itop.ui.php', // Support for English
|
||||
'dictionaries/fr.dictionary.itop.ui.php', // Support for French
|
||||
'dictionaries/fr.dictionary.itop.core.php', // Support for French
|
||||
'dictionaries/es_cr.dictionary.itop.ui.php', // Support for Spanish (from Costa Rica)
|
||||
'dictionaries/es_cr.dictionary.itop.core.php', // Support for Spanish (from Costa Rica)
|
||||
'dictionaries/de.dictionary.itop.ui.php', // Support for German
|
||||
'dictionaries/de.dictionary.itop.core.php', // Support for German
|
||||
'dictionaries/pt_br.dictionary.itop.ui.php', // Support for Brazilian Portuguese
|
||||
'dictionaries/pt_br.dictionary.itop.core.php', // Support for Brazilian Portuguese
|
||||
'dictionaries/ru.dictionary.itop.ui.php', // Support for Russian
|
||||
'dictionaries/ru.dictionary.itop.core.php', // Support for Russian
|
||||
'dictionaries/tr.dictionary.itop.ui.php', // Support for Turkish
|
||||
'dictionaries/tr.dictionary.itop.core.php', // Support for Turkish
|
||||
'dictionaries/zh.dictionary.itop.ui.php', // Support for Chinese
|
||||
'dictionaries/zh.dictionary.itop.core.php', // Support for Chinese
|
||||
'dictionaries/it.dictionary.itop.ui.php', // Support for Italian
|
||||
'dictionaries/it.dictionary.itop.core.php', // Support for Italian
|
||||
'dictionaries/hu.dictionary.itop.ui.php', // Support for Hungarian
|
||||
'dictionaries/hu.dictionary.itop.core.php', // Support for Hungarian
|
||||
);
|
||||
$this->m_aDictionaries = self::ScanDictionariesDir();
|
||||
|
||||
foreach($this->m_aSettings as $sPropCode => $aSettingInfo)
|
||||
{
|
||||
$this->m_aSettings[$sPropCode]['value'] = $aSettingInfo['default'];
|
||||
@@ -496,7 +649,6 @@ class Config
|
||||
$this->m_iStandardReloadInterval = DEFAULT_STANDARD_RELOAD_INTERVAL;
|
||||
$this->m_iFastReloadInterval = DEFAULT_FAST_RELOAD_INTERVAL;
|
||||
$this->m_bSecureConnectionRequired = DEFAULT_SECURE_CONNECTION_REQUIRED;
|
||||
$this->m_bHttpsHyperlinks = DEFAULT_HTTPS_HYPERLINKS;
|
||||
$this->m_sDefaultLanguage = 'EN US';
|
||||
$this->m_sAllowedLoginTypes = DEFAULT_ALLOWED_LOGIN_TYPES;
|
||||
$this->m_sExtAuthVariable = DEFAULT_EXT_AUTH_VARIABLE;
|
||||
@@ -510,6 +662,18 @@ class Config
|
||||
$this->Load($sConfigFile);
|
||||
$this->Verify();
|
||||
}
|
||||
|
||||
// Application root url: set a default value, then normalize it
|
||||
$sAppRootUrl = trim($this->Get('app_root_url'));
|
||||
if (strlen($sAppRootUrl) == 0)
|
||||
{
|
||||
$sAppRootUrl = utils::GetDefaultUrlAppRoot();
|
||||
}
|
||||
if (substr($sAppRootUrl, -1, 1) != '/')
|
||||
{
|
||||
$sAppRootUrl .= '/';
|
||||
}
|
||||
$this->Set('app_root_url', $sAppRootUrl);
|
||||
}
|
||||
|
||||
protected function CheckFile($sPurpose, $sFileName)
|
||||
@@ -518,6 +682,10 @@ class Config
|
||||
{
|
||||
throw new ConfigException("Could not find $sPurpose file", array('file' => $sFileName));
|
||||
}
|
||||
if (!is_readable($sFileName))
|
||||
{
|
||||
throw new ConfigException("Could not read $sPurpose file (the file exists but cannot be read). Do you have the rights to access this file?", array('file' => $sFileName));
|
||||
}
|
||||
}
|
||||
|
||||
protected function Load($sConfigFile)
|
||||
@@ -618,7 +786,6 @@ class Config
|
||||
$this->m_iStandardReloadInterval = isset($MySettings['standard_reload_interval']) ? trim($MySettings['standard_reload_interval']) : DEFAULT_STANDARD_RELOAD_INTERVAL;
|
||||
$this->m_iFastReloadInterval = isset($MySettings['fast_reload_interval']) ? trim($MySettings['fast_reload_interval']) : DEFAULT_FAST_RELOAD_INTERVAL;
|
||||
$this->m_bSecureConnectionRequired = isset($MySettings['secure_connection_required']) ? (bool) trim($MySettings['secure_connection_required']) : DEFAULT_SECURE_CONNECTION_REQUIRED;
|
||||
$this->m_bHttpsHyperlinks = isset($MySettings['https_hyperlinks']) ? (bool) trim($MySettings['https_hyperlinks']) : DEFAULT_HTTPS_HYPERLINKS;
|
||||
|
||||
$this->m_aModuleSettings = isset($MyModuleSettings) ? $MyModuleSettings : array();
|
||||
|
||||
@@ -794,11 +961,6 @@ class Config
|
||||
return $this->m_bSecureConnectionRequired;
|
||||
}
|
||||
|
||||
public function GetHttpsHyperlinks()
|
||||
{
|
||||
return $this->m_bHttpsHyperlinks;
|
||||
}
|
||||
|
||||
public function GetDefaultLanguage()
|
||||
{
|
||||
return $this->m_sDefaultLanguage;
|
||||
@@ -904,11 +1066,6 @@ class Config
|
||||
$this->m_bSecureConnectionRequired = $bSecureConnectionRequired;
|
||||
}
|
||||
|
||||
public function SetHttpsHyperlinks($bHttpsHyperlinks)
|
||||
{
|
||||
$this->m_bHttpsHyperlinks = $bHttpsHyperlinks;
|
||||
}
|
||||
|
||||
public function SetDefaultLanguage($sLanguageCode)
|
||||
{
|
||||
$this->m_sDefaultLanguage = $sLanguageCode;
|
||||
@@ -974,7 +1131,6 @@ class Config
|
||||
$aSettings['standard_reload_interval'] = $this->m_iStandardReloadInterval;
|
||||
$aSettings['fast_reload_interval'] = $this->m_iFastReloadInterval;
|
||||
$aSettings['secure_connection_required'] = $this->m_bSecureConnectionRequired;
|
||||
$aSettings['https_hyperlinks'] = $this->m_bHttpsHyperlinks;
|
||||
$aSettings['default_language'] = $this->m_sDefaultLanguage;
|
||||
$aSettings['allowed_login_types'] = $this->m_sAllowedLoginTypes;
|
||||
$aSettings['encryption_key'] = $this->m_sEncryptionKey;
|
||||
@@ -1069,7 +1225,6 @@ class Config
|
||||
fwrite($hFile, "\t'standard_reload_interval' => {$this->m_iStandardReloadInterval},\n");
|
||||
fwrite($hFile, "\t'fast_reload_interval' => {$this->m_iFastReloadInterval},\n");
|
||||
fwrite($hFile, "\t'secure_connection_required' => ".($this->m_bSecureConnectionRequired ? 'true' : 'false').",\n");
|
||||
fwrite($hFile, "\t'https_hyperlinks' => ".($this->m_bHttpsHyperlinks ? 'true' : 'false').",\n");
|
||||
fwrite($hFile, "\t'default_language' => '{$this->m_sDefaultLanguage}',\n");
|
||||
fwrite($hFile, "\t'allowed_login_types' => '{$this->m_sAllowedLoginTypes}',\n");
|
||||
fwrite($hFile, "\t'encryption_key' => '{$this->m_sEncryptionKey}',\n");
|
||||
@@ -1094,7 +1249,7 @@ class Config
|
||||
|
||||
fwrite($hFile, "\n/**\n");
|
||||
fwrite($hFile, " *\n");
|
||||
fwrite($hFile, " * Data model modules to be loaded. Names should be specified as absolute paths\n");
|
||||
fwrite($hFile, " * Data model modules to be loaded. Names are specified as relative paths\n");
|
||||
fwrite($hFile, " *\n");
|
||||
fwrite($hFile, " */\n");
|
||||
fwrite($hFile, "\$MyModules = array(\n");
|
||||
@@ -1137,5 +1292,25 @@ class Config
|
||||
throw new ConfigException("Could not write to configuration file", array('file' => $sFileName));
|
||||
}
|
||||
}
|
||||
|
||||
protected static function ScanDictionariesDir()
|
||||
{
|
||||
$aResult = array();
|
||||
// Populate automatically the list of dictionary files
|
||||
$sDir = APPROOT.'/dictionaries';
|
||||
if ($hDir = @opendir($sDir))
|
||||
{
|
||||
while (($sFile = readdir($hDir)) !== false)
|
||||
{
|
||||
$aMatches = array();
|
||||
if (preg_match("/^([^\.]+\.)?dictionary\.itop\.(ui|core)\.php$/i", $sFile, $aMatches)) // Dictionary files named like [<Lang>.]dictionary.[core|ui].php are loaded automatically
|
||||
{
|
||||
$aResult[] = 'dictionaries/'.$sFile;
|
||||
}
|
||||
}
|
||||
closedir($hDir);
|
||||
}
|
||||
return $aResult;
|
||||
}
|
||||
}
|
||||
?>
|
||||
|
||||
@@ -62,15 +62,15 @@ abstract class DBObject
|
||||
protected $m_oMasterReplicaSet = null; // Set of SynchroReplica related to this object
|
||||
|
||||
// Use the MetaModel::NewObject to build an object (do we have to force it?)
|
||||
public function __construct($aRow = null, $sClassAlias = '', $aExtendedDataSpec = null)
|
||||
public function __construct($aRow = null, $sClassAlias = '', $aAttToLoad = null, $aExtendedDataSpec = null)
|
||||
{
|
||||
if (!empty($aRow))
|
||||
{
|
||||
$this->FromRow($aRow, $sClassAlias, $aExtendedDataSpec);
|
||||
$this->FromRow($aRow, $sClassAlias, $aAttToLoad, $aExtendedDataSpec);
|
||||
$this->m_bFullyLoaded = $this->IsFullyLoaded();
|
||||
return;
|
||||
}
|
||||
// Creation of brand new object
|
||||
// Creation of a brand new object
|
||||
//
|
||||
|
||||
$this->m_iKey = self::GetNextTempId(get_class($this));
|
||||
@@ -82,8 +82,8 @@ abstract class DBObject
|
||||
$this->m_aOrigValues[$sAttCode] = null;
|
||||
if ($oAttDef->IsExternalField())
|
||||
{
|
||||
// This field has to be read from the DB
|
||||
$this->m_aLoadedAtt[$sAttCode] = false;
|
||||
// This field has to be read from the DB
|
||||
// Leave the flag unset (optimization)
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -154,7 +154,7 @@ abstract class DBObject
|
||||
return true;
|
||||
}
|
||||
|
||||
protected function Reload()
|
||||
public function Reload()
|
||||
{
|
||||
assert($this->m_bIsInDB);
|
||||
$aRow = MetaModel::MakeSingleRow(get_class($this), $this->m_iKey, false/*, $this->m_bAllowAllData*/);
|
||||
@@ -194,7 +194,7 @@ abstract class DBObject
|
||||
$this->m_bFullyLoaded = true;
|
||||
}
|
||||
|
||||
protected function FromRow($aRow, $sClassAlias = '', $aExtendedDataSpec = null)
|
||||
protected function FromRow($aRow, $sClassAlias = '', $aAttToLoad = null, $aExtendedDataSpec = null)
|
||||
{
|
||||
if (strlen($sClassAlias) == 0)
|
||||
{
|
||||
@@ -235,11 +235,17 @@ abstract class DBObject
|
||||
// Build the object from an array of "attCode"=>"value")
|
||||
//
|
||||
$bFullyLoaded = true; // ... set to false if any attribute is not found
|
||||
foreach(MetaModel::ListAttributeDefs(get_class($this)) as $sAttCode=>$oAttDef)
|
||||
if (is_null($aAttToLoad) || !array_key_exists($sClassAlias, $aAttToLoad))
|
||||
{
|
||||
$aAttList = MetaModel::ListAttributeDefs(get_class($this));
|
||||
}
|
||||
else
|
||||
{
|
||||
$aAttList = $aAttToLoad[$sClassAlias];
|
||||
}
|
||||
|
||||
foreach($aAttList as $sAttCode=>$oAttDef)
|
||||
{
|
||||
// Say something, whatever the type of attribute
|
||||
$this->m_aLoadedAtt[$sAttCode] = false;
|
||||
|
||||
// Skip links (could not be loaded by the mean of this query)
|
||||
if ($oAttDef->IsLinkSet()) continue;
|
||||
|
||||
@@ -296,30 +302,53 @@ abstract class DBObject
|
||||
$this->Reload();
|
||||
}
|
||||
|
||||
if ($oAttDef->IsExternalKey() && is_object($value))
|
||||
if ($oAttDef->IsExternalKey())
|
||||
{
|
||||
// Setting an external key with a whole object (instead of just an ID)
|
||||
// let's initialize also the external fields that depend on it
|
||||
// (useful when building objects in memory and not from a query)
|
||||
if ( (get_class($value) != $oAttDef->GetTargetClass()) && (!is_subclass_of($value, $oAttDef->GetTargetClass())))
|
||||
if (is_object($value))
|
||||
{
|
||||
throw new CoreUnexpectedValue("Trying to set the value of '$sAttCode', to an object of class '".get_class($value)."', whereas it's an ExtKey to '".$oAttDef->GetTargetClass()."'. Ignored");
|
||||
// Setting an external key with a whole object (instead of just an ID)
|
||||
// let's initialize also the external fields that depend on it
|
||||
// (useful when building objects in memory and not from a query)
|
||||
if ( (get_class($value) != $oAttDef->GetTargetClass()) && (!is_subclass_of($value, $oAttDef->GetTargetClass())))
|
||||
{
|
||||
throw new CoreUnexpectedValue("Trying to set the value of '$sAttCode', to an object of class '".get_class($value)."', whereas it's an ExtKey to '".$oAttDef->GetTargetClass()."'. Ignored");
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->m_aCurrValues[$sAttCode] = $value->GetKey();
|
||||
foreach(MetaModel::ListAttributeDefs(get_class($this)) as $sCode => $oDef)
|
||||
{
|
||||
if ($oDef->IsExternalField() && ($oDef->GetKeyAttCode() == $sAttCode))
|
||||
{
|
||||
$this->m_aCurrValues[$sCode] = $value->Get($oDef->GetExtAttCode());
|
||||
}
|
||||
}
|
||||
$this->m_aCurrValues[$sAttCode.'_friendlyname'] = $value->GetName();
|
||||
}
|
||||
}
|
||||
else
|
||||
else if ($this->m_aCurrValues[$sAttCode] != $value)
|
||||
{
|
||||
// The object has changed, reset caches
|
||||
$this->m_bCheckStatus = null;
|
||||
$this->m_aAsArgs = null;
|
||||
|
||||
$this->m_aCurrValues[$sAttCode] = $value->GetKey();
|
||||
// If the external key changed, invalidate all the external fields (and friendly name) related to this external key
|
||||
$this->m_aCurrValues[$sAttCode] = $value;
|
||||
foreach(MetaModel::ListAttributeDefs(get_class($this)) as $sCode => $oDef)
|
||||
{
|
||||
if ($oDef->IsExternalField() && ($oDef->GetKeyAttCode() == $sAttCode))
|
||||
{
|
||||
$this->m_aCurrValues[$sCode] = $value->Get($oDef->GetExtAttCode());
|
||||
unset($this->m_aLoadedAtt[$sCode]);
|
||||
$this->m_aCurrValues[$sCode] = null;
|
||||
}
|
||||
}
|
||||
$this->m_aCurrValues[$sAttCode.'_friendlyname'] = null;
|
||||
unset($this->m_aLoadedAtt[$sAttCode.'_friendlyname']);
|
||||
}
|
||||
|
||||
// The object has changed, reset caches
|
||||
$this->m_bCheckStatus = null;
|
||||
$this->m_aAsArgs = null;
|
||||
|
||||
// Make sure we do not reload it anymore... before saving it
|
||||
$this->RegisterAsDirty();
|
||||
|
||||
return;
|
||||
}
|
||||
if(!$oAttDef->IsScalar() && !is_object($value))
|
||||
@@ -361,15 +390,93 @@ abstract class DBObject
|
||||
}
|
||||
|
||||
public function Get($sAttCode)
|
||||
{
|
||||
if (($iPos = strpos($sAttCode, '->')) === false)
|
||||
{
|
||||
return $this->GetStrict($sAttCode);
|
||||
}
|
||||
else
|
||||
{
|
||||
$sExtKeyAttCode = substr($sAttCode, 0, $iPos);
|
||||
$sRemoteAttCode = substr($sAttCode, $iPos + 2);
|
||||
if (!MetaModel::IsValidAttCode(get_class($this), $sExtKeyAttCode))
|
||||
{
|
||||
throw new CoreException("Unknown external key '$sExtKeyAttCode' for the class ".get_class($this));
|
||||
}
|
||||
$oKeyAttDef = MetaModel::GetAttributeDef(get_class($this), $sExtKeyAttCode);
|
||||
$sRemoteClass = $oKeyAttDef->GetTargetClass();
|
||||
$oRemoteObj = MetaModel::GetObject($sRemoteClass, $this->GetStrict($sExtKeyAttCode), false);
|
||||
if (is_null($oRemoteObj))
|
||||
{
|
||||
return '';
|
||||
}
|
||||
else
|
||||
{
|
||||
return $oRemoteObj->Get($sRemoteAttCode);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function GetStrict($sAttCode)
|
||||
{
|
||||
if (!array_key_exists($sAttCode, MetaModel::ListAttributeDefs(get_class($this))))
|
||||
{
|
||||
throw new CoreException("Unknown attribute code '$sAttCode' for the class ".get_class($this));
|
||||
}
|
||||
if ($this->m_bIsInDB && !$this->m_aLoadedAtt[$sAttCode] && !$this->m_bDirty)
|
||||
if ($this->m_bIsInDB && !isset($this->m_aLoadedAtt[$sAttCode]))
|
||||
{
|
||||
// #@# non-scalar attributes.... handle that differently
|
||||
$this->Reload();
|
||||
if (!$this->m_bDirty)
|
||||
{
|
||||
$this->Reload();
|
||||
}
|
||||
else
|
||||
{
|
||||
// If the missing attribute is an external fields (or a friendlyname), try to selectively reload it
|
||||
// from the value of its external key... and reload the related external fields & friendlyname as well
|
||||
$sTargetClass = '';
|
||||
$iCurrKey = 0;
|
||||
$oAttDef = MetaModel::GetAttributeDef(get_class($this), $sAttCode);
|
||||
if ($oAttDef->IsExternalField())
|
||||
{
|
||||
$sKeyAttCode = $oAttDef->GetKeyAttCode();
|
||||
$iCurrKey = $this->m_aCurrValues[$oAttDef->GetKeyAttCode()];
|
||||
$sTargetClass= $oAttDef->GetTargetClass();
|
||||
}
|
||||
else if ($oAttDef instanceof AttributeFriendlyName)
|
||||
{
|
||||
$sKeyAttCode = $oAttDef->GetKeyAttCode();
|
||||
$oKeyAttDef = MetaModel::GetAttributeDef(get_class($this), $sKeyAttCode);
|
||||
$iCurrKey = $this->m_aCurrValues[$oAttDef->GetKeyAttCode()];
|
||||
$sTargetClass = $oKeyAttDef->GetTargetClass();
|
||||
}
|
||||
|
||||
if (($sTargetClass != '') && ($iCurrKey != 0))
|
||||
{
|
||||
$oTargetObj = MetaModel::GetObject($sTargetClass, $iCurrKey, false);
|
||||
if (is_object($oTargetObj))
|
||||
{
|
||||
foreach(MetaModel::ListAttributeDefs(get_class($this)) as $sCode => $oDef)
|
||||
{
|
||||
if ($oDef->IsExternalField() && ($oDef->GetKeyAttCode() == $sKeyAttCode))
|
||||
{
|
||||
$this->m_aLoadedAtt[$sCode] = true;
|
||||
$this->m_aCurrValues[$sCode] = $oTargetObj->Get($oDef->GetExtAttCode());
|
||||
}
|
||||
}
|
||||
if ($oAttDef instanceof AttributeFriendlyName)
|
||||
{
|
||||
$this->m_aLoadedAtt[$sAttCode] = true;
|
||||
$this->m_aCurrValues[$sAttCode] = $oTargetObj->GetName();
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->m_aLoadedAtt[$sKeyAttCode.'_friendlyname'] = true;
|
||||
$this->m_aCurrValues[$sKeyAttCode.'_friendlyname'] = $oTargetObj->GetName();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
$value = $this->m_aCurrValues[$sAttCode];
|
||||
if ($value instanceof DBObjectSet)
|
||||
@@ -454,7 +561,7 @@ abstract class DBObject
|
||||
}
|
||||
|
||||
// That's a standard attribute (might be an ext field or a direct field, etc.)
|
||||
return $oAtt->GetAsHTML($this->Get($sAttCode));
|
||||
return $oAtt->GetAsHTML($this->Get($sAttCode), $this);
|
||||
}
|
||||
|
||||
public function GetEditValue($sAttCode)
|
||||
@@ -522,44 +629,46 @@ abstract class DBObject
|
||||
return $oAtt->GetAsCSV($this->GetOriginal($sAttCode), $sSeparator, $sTextQualifier, $this);
|
||||
}
|
||||
|
||||
protected static function MakeHyperLink($sObjClass, $sObjKey, $sLabel = '')
|
||||
protected static function MakeHyperLink($sObjClass, $sObjKey, $sLabel = '', $sUrlMakerClass = null, $bWithNavigationContext = true)
|
||||
{
|
||||
if ($sObjKey <= 0) return '<em>'.Dict::S('UI:UndefinedObject').'</em>'; // Objects built in memory have negative IDs
|
||||
|
||||
$oAppContext = new ApplicationContext();
|
||||
$sPage = self::ComputeUIPage($sObjClass);
|
||||
$sAbsoluteUrl = utils::GetAbsoluteUrlPath();
|
||||
|
||||
// Safety net
|
||||
//
|
||||
if (empty($sLabel))
|
||||
{
|
||||
// If the object if not issued from a query but constructed programmatically
|
||||
// the label may be empty. In this case run a query to get the object's friendly name
|
||||
$oTmpObj = MetaModel::GetObject($sObjClass, $sObjKey);
|
||||
$sLabel = $oTmpObj->GetName();
|
||||
$oTmpObj = MetaModel::GetObject($sObjClass, $sObjKey, false);
|
||||
if (is_object($oTmpObj))
|
||||
{
|
||||
$sLabel = $oTmpObj->GetName();
|
||||
}
|
||||
else
|
||||
{
|
||||
// May happen in case the target object is not in the list of allowed values for this attribute
|
||||
$sLabel = "<em>$sObjClass::$sObjKey</em>";
|
||||
}
|
||||
//$sLabel = MetaModel::GetName($sObjClass)." #$sObjKey";
|
||||
}
|
||||
$sHint = MetaModel::GetName($sObjClass)."::$sObjKey";
|
||||
return "<a href=\"{$sAbsoluteUrl}{$sPage}?operation=details&class=$sObjClass&id=$sObjKey&".$oAppContext->GetForLink()."\" title=\"$sHint\">$sLabel</a>";
|
||||
$sUrl = ApplicationContext::MakeObjectUrl($sObjClass, $sObjKey, $sUrlMakerClass, $bWithNavigationContext);
|
||||
if (strlen($sUrl) > 0)
|
||||
{
|
||||
return "<a href=\"$sUrl\" title=\"$sHint\">$sLabel</a>";
|
||||
}
|
||||
else
|
||||
{
|
||||
return $sLabel;
|
||||
}
|
||||
}
|
||||
|
||||
public function GetHyperlink()
|
||||
public function GetHyperlink($sUrlMakerClass = null, $bWithNavigationContext = true)
|
||||
{
|
||||
if ($this->IsNew()) return '<em>'.Dict::S('UI:UndefinedObject').'</em>'; // Objects built in memory have negative IDs
|
||||
|
||||
$oAppContext = new ApplicationContext();
|
||||
$sPage = $this->GetUIPage();
|
||||
$sAbsoluteUrl = utils::GetAbsoluteUrlPath();
|
||||
$sObjClass = get_class($this);
|
||||
$sObjKey = $this->GetKey();
|
||||
|
||||
$sLabel = $this->GetName();
|
||||
$sHint = MetaModel::GetName($sObjClass)."::$sObjKey";
|
||||
return "<a href=\"{$sAbsoluteUrl}{$sPage}?operation=details&class=$sObjClass&id=$sObjKey&".$oAppContext->GetForLink()."\" title=\"$sHint\">$sLabel</a>";
|
||||
return self::MakeHyperLink(get_class($this), $this->GetKey(), $this->GetName(), $sUrlMakerClass, $bWithNavigationContext);
|
||||
}
|
||||
|
||||
public static function ComputeUIPage($sClass)
|
||||
public static function ComputeStandardUIPage($sClass)
|
||||
{
|
||||
static $aUIPagesCache = array(); // Cache to store the php page used to display each class of object
|
||||
if (!isset($aUIPagesCache[$sClass]))
|
||||
@@ -614,25 +723,25 @@ abstract class DBObject
|
||||
return MetaModel::GetClassIcon(get_class($this), $bImgTag);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the name of an object in a safe manner for displaying inside a web page
|
||||
* @return string
|
||||
*/
|
||||
public function GetName()
|
||||
{
|
||||
$aNameSpec = MetaModel::GetNameSpec(get_class($this));
|
||||
$sFormat = $aNameSpec[0];
|
||||
$aAttributes = $aNameSpec[1];
|
||||
return htmlentities($this->GetRawName(), ENT_QUOTES, 'UTF-8');
|
||||
}
|
||||
|
||||
$aValues = array();
|
||||
foreach ($aAttributes as $sAttCode)
|
||||
{
|
||||
if (empty($sAttCode))
|
||||
{
|
||||
$aValues[] = $this->m_iKey;
|
||||
}
|
||||
else
|
||||
{
|
||||
$aValues[] = $this->Get($sAttCode);
|
||||
}
|
||||
}
|
||||
return vsprintf($sFormat, $aValues);
|
||||
/**
|
||||
* Gets the raw name of an object, this is not safe for displaying inside a web page
|
||||
* since the " < > characters are not escaped and the name may contain some XSS script
|
||||
* instructions.
|
||||
* Use this function only for internal computations or for an output to a non-HTML destination
|
||||
* @return string
|
||||
*/
|
||||
public function GetRawName()
|
||||
{
|
||||
return $this->Get('friendlyname');
|
||||
}
|
||||
|
||||
public function GetState()
|
||||
@@ -678,22 +787,48 @@ abstract class DBObject
|
||||
/**
|
||||
* Returns the set of flags (OPT_ATT_HIDDEN, OPT_ATT_READONLY, OPT_ATT_MANDATORY...)
|
||||
* for the given attribute in the current state of the object
|
||||
* @param string $sAttCode The code of the attribute
|
||||
* @param $sAttCode string $sAttCode The code of the attribute
|
||||
* @param $aReasons array To store the reasons why the attribute is read-only (info about the synchro replicas)
|
||||
* @param $sTargetState string The target state in which to evalutate the flags, if empty the current state will be used
|
||||
* @return integer Flags: the binary combination of the flags applicable to this attribute
|
||||
*/
|
||||
public function GetAttributeFlags($sAttCode, &$aReasons = array())
|
||||
public function GetAttributeFlags($sAttCode, &$aReasons = array(), $sTargetState = '')
|
||||
{
|
||||
$iFlags = 0; // By default (if no life cycle) no flag at all
|
||||
$sStateAttCode = MetaModel::GetStateAttributeCode(get_class($this));
|
||||
if (!empty($sStateAttCode))
|
||||
{
|
||||
$iFlags = MetaModel::GetAttributeFlags(get_class($this), $this->Get($sStateAttCode), $sAttCode);
|
||||
if ($sTargetState != '')
|
||||
{
|
||||
$iFlags = MetaModel::GetAttributeFlags(get_class($this), $sTargetState, $sAttCode);
|
||||
}
|
||||
else
|
||||
{
|
||||
$iFlags = MetaModel::GetAttributeFlags(get_class($this), $this->Get($sStateAttCode), $sAttCode);
|
||||
}
|
||||
}
|
||||
$aReasons = array();
|
||||
$iSynchroFlags = $this->GetSynchroReplicaFlags($sAttCode, $aReasons);
|
||||
return $iFlags | $iSynchroFlags; // Combine both sets of flags
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the set of flags (OPT_ATT_HIDDEN, OPT_ATT_READONLY, OPT_ATT_MANDATORY...)
|
||||
* for the given attribute for the current state of the object considered as an INITIAL state
|
||||
* @param string $sAttCode The code of the attribute
|
||||
* @return integer Flags: the binary combination of the flags applicable to this attribute
|
||||
*/
|
||||
public function GetInitialStateAttributeFlags($sAttCode, &$aReasons = array())
|
||||
{
|
||||
$iFlags = 0;
|
||||
$sStateAttCode = MetaModel::GetStateAttributeCode(get_class($this));
|
||||
if (!empty($sStateAttCode))
|
||||
{
|
||||
$iFlags = MetaModel::GetInitialStateAttributeFlags(get_class($this), $this->Get($sStateAttCode), $sAttCode);
|
||||
}
|
||||
return $iFlags; // No need to care about the synchro flags since we'll be creating a new object anyway
|
||||
}
|
||||
|
||||
// check if the given (or current) value is suitable for the attribute
|
||||
// return true if successfull
|
||||
// return the error desciption otherwise
|
||||
@@ -735,6 +870,14 @@ abstract class DBObject
|
||||
return "Target object not found ($sTargetClass::$toCheck)";
|
||||
}
|
||||
}
|
||||
if ($oAtt->IsHierarchicalKey())
|
||||
{
|
||||
// This check cannot be deactivated since otherwise the user may break things by a CSV import of a bulk modify
|
||||
if ($toCheck == $this->GetKey())
|
||||
{
|
||||
return "An object can not be its own parent in a hierarchy (".$oAtt->Getlabel()." = $toCheck)";
|
||||
}
|
||||
}
|
||||
}
|
||||
elseif ($oAtt->IsScalar())
|
||||
{
|
||||
@@ -862,7 +1005,7 @@ abstract class DBObject
|
||||
|
||||
$oDeletionPlan->AddToDelete($oReplica, DEL_SILENT);
|
||||
|
||||
if ($oDataSource->GetKey() == SynchroDataSource::GetCurrentTaskId())
|
||||
if ($oDataSource->GetKey() == SynchroExecution::GetCurrentTaskId())
|
||||
{
|
||||
// The current task has the right to delete the object
|
||||
continue;
|
||||
@@ -911,30 +1054,35 @@ abstract class DBObject
|
||||
$aDelta = array();
|
||||
foreach ($aProposal as $sAtt => $proposedValue)
|
||||
{
|
||||
if (!array_key_exists($sAtt, $this->m_aOrigValues))
|
||||
$oAttDef = MetaModel::GetAttributeDef(get_class($this), $sAtt);
|
||||
// Ignore external fields and friendly names that change only as a consequence of modifying another field
|
||||
if ((!$oAttDef->IsExternalField() && !($oAttDef instanceof AttributeFriendlyName)))
|
||||
{
|
||||
// The value was not set
|
||||
$aDelta[$sAtt] = $proposedValue;
|
||||
}
|
||||
elseif(is_object($proposedValue))
|
||||
{
|
||||
$oLinkAttDef = MetaModel::GetAttributeDef(get_class($this), $sAtt);
|
||||
// The value is an object, the comparison is not strict
|
||||
if (!$oLinkAttDef->Equals($proposedValue, $this->m_aOrigValues[$sAtt]))
|
||||
if (!array_key_exists($sAtt, $this->m_aOrigValues))
|
||||
{
|
||||
// The value was not set
|
||||
$aDelta[$sAtt] = $proposedValue;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// The value is a scalar, the comparison must be 100% strict
|
||||
if($this->m_aOrigValues[$sAtt] !== $proposedValue)
|
||||
{
|
||||
//echo "$sAtt:<pre>\n";
|
||||
//var_dump($this->m_aOrigValues[$sAtt]);
|
||||
//var_dump($proposedValue);
|
||||
//echo "</pre>\n";
|
||||
$aDelta[$sAtt] = $proposedValue;
|
||||
elseif(is_object($proposedValue))
|
||||
{
|
||||
$oLinkAttDef = MetaModel::GetAttributeDef(get_class($this), $sAtt);
|
||||
// The value is an object, the comparison is not strict
|
||||
if (!$oLinkAttDef->Equals($proposedValue, $this->m_aOrigValues[$sAtt]))
|
||||
{
|
||||
$aDelta[$sAtt] = $proposedValue;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// The value is a scalar, the comparison must be 100% strict
|
||||
if($this->m_aOrigValues[$sAtt] !== $proposedValue)
|
||||
{
|
||||
//echo "$sAtt:<pre>\n";
|
||||
//var_dump($this->m_aOrigValues[$sAtt]);
|
||||
//var_dump($proposedValue);
|
||||
//echo "</pre>\n";
|
||||
$aDelta[$sAtt] = $proposedValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1083,6 +1231,8 @@ abstract class DBObject
|
||||
$aValuesToWrite[] = CMDBSource::Quote($this->m_iKey);
|
||||
}
|
||||
|
||||
$aHierarchicalKeys = array();
|
||||
|
||||
foreach(MetaModel::ListAttributeDefs($sTableClass) as $sAttCode=>$oAttDef)
|
||||
{
|
||||
// Skip this attribute if not defined in this table
|
||||
@@ -1093,6 +1243,10 @@ abstract class DBObject
|
||||
$aFieldsToWrite[] = "`$sColumn`";
|
||||
$aValuesToWrite[] = CMDBSource::Quote($sValue);
|
||||
}
|
||||
if ($oAttDef->IsHierarchicalKey())
|
||||
{
|
||||
$aHierarchicalKeys[$sAttCode] = $oAttDef;
|
||||
}
|
||||
}
|
||||
|
||||
if (count($aValuesToWrite) == 0) return false;
|
||||
@@ -1115,6 +1269,17 @@ abstract class DBObject
|
||||
}
|
||||
else
|
||||
{
|
||||
if (count($aHierarchicalKeys) > 0)
|
||||
{
|
||||
foreach($aHierarchicalKeys as $sAttCode => $oAttDef)
|
||||
{
|
||||
$aValues = MetaModel::HKInsertChildUnder($this->m_aCurrValues[$sAttCode], $oAttDef, $sTable);
|
||||
$aFieldsToWrite[] = '`'.$oAttDef->GetSQLRight().'`';
|
||||
$aValuesToWrite[] = $aValues[$oAttDef->GetSQLRight()];
|
||||
$aFieldsToWrite[] = '`'.$oAttDef->GetSQLLeft().'`';
|
||||
$aValuesToWrite[] = $aValues[$oAttDef->GetSQLLeft()];
|
||||
}
|
||||
}
|
||||
$sInsertSQL = "INSERT INTO `$sTable` (".join(",", $aFieldsToWrite).") VALUES (".join(", ", $aValuesToWrite).")";
|
||||
$iNewKey = CMDBSource::InsertInto($sInsertSQL);
|
||||
}
|
||||
@@ -1194,13 +1359,11 @@ abstract class DBObject
|
||||
|
||||
// Activate any existing trigger
|
||||
$sClass = get_class($this);
|
||||
$oSet = new DBObjectSet(new DBObjectSearch('TriggerOnObjectCreate'));
|
||||
$sClassList = implode("', '", MetaModel::EnumParentClasses($sClass, ENUM_PARENT_CLASSES_ALL));
|
||||
$oSet = new DBObjectSet(DBObjectSearch::FromOQL("SELECT TriggerOnObjectCreate AS t WHERE t.target_class IN ('$sClassList')"));
|
||||
while ($oTrigger = $oSet->Fetch())
|
||||
{
|
||||
if (MetaModel::IsParentClass($oTrigger->Get('target_class'), $sClass))
|
||||
{
|
||||
$oTrigger->DoActivate($this->ToArgs('this'));
|
||||
}
|
||||
$oTrigger->DoActivate($this->ToArgs('this'));
|
||||
}
|
||||
|
||||
return $this->m_iKey;
|
||||
@@ -1266,22 +1429,68 @@ abstract class DBObject
|
||||
}
|
||||
|
||||
$bHasANewExternalKeyValue = false;
|
||||
$aHierarchicalKeys = array();
|
||||
foreach($aChanges as $sAttCode => $valuecurr)
|
||||
{
|
||||
$oAttDef = MetaModel::GetAttributeDef(get_class($this), $sAttCode);
|
||||
if ($oAttDef->IsExternalKey()) $bHasANewExternalKeyValue = true;
|
||||
if (!$oAttDef->IsDirectField()) unset($aChanges[$sAttCode]);
|
||||
if ($oAttDef->IsHierarchicalKey())
|
||||
{
|
||||
$aHierarchicalKeys[$sAttCode] = $oAttDef;
|
||||
}
|
||||
}
|
||||
|
||||
// Update scalar attributes
|
||||
if (count($aChanges) != 0)
|
||||
if (!MetaModel::DBIsReadOnly())
|
||||
{
|
||||
$oFilter = new DBObjectSearch(get_class($this));
|
||||
$oFilter->AddCondition('id', $this->m_iKey, '=');
|
||||
|
||||
$sSQL = MetaModel::MakeUpdateQuery($oFilter, $aChanges);
|
||||
if (!MetaModel::DBIsReadOnly())
|
||||
// Update the left & right indexes for each hierarchical key
|
||||
foreach($aHierarchicalKeys as $sAttCode => $oAttDef)
|
||||
{
|
||||
$sTable = $sTable = MetaModel::DBGetTable(get_class($this), $sAttCode);
|
||||
$sSQL = "SELECT `".$oAttDef->GetSQLRight()."` AS `right`, `".$oAttDef->GetSQLLeft()."` AS `left` FROM `$sTable` WHERE id=".$this->GetKey();
|
||||
$aRes = CMDBSource::QueryToArray($sSQL);
|
||||
$iMyLeft = $aRes[0]['left'];
|
||||
$iMyRight = $aRes[0]['right'];
|
||||
$iDelta =$iMyRight - $iMyLeft + 1;
|
||||
MetaModel::HKTemporaryCutBranch($iMyLeft, $iMyRight, $oAttDef, $sTable);
|
||||
|
||||
if ($aChanges[$sAttCode] == 0)
|
||||
{
|
||||
// No new parent, insert completely at the right of the tree
|
||||
$sSQL = "SELECT max(`".$oAttDef->GetSQLRight()."`) AS max FROM `$sTable`";
|
||||
$aRes = CMDBSource::QueryToArray($sSQL);
|
||||
if (count($aRes) == 0)
|
||||
{
|
||||
$iNewLeft = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
$iNewLeft = $aRes[0]['max']+1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Insert at the right of the specified parent
|
||||
$sSQL = "SELECT `".$oAttDef->GetSQLRight()."` FROM `$sTable` WHERE id=".((int)$aChanges[$sAttCode]);
|
||||
$iNewLeft = CMDBSource::QueryToScalar($sSQL);
|
||||
}
|
||||
|
||||
MetaModel::HKReplugBranch($iNewLeft, $iNewLeft + $iDelta - 1, $oAttDef, $sTable);
|
||||
|
||||
$aHKChanges = array();
|
||||
$aHKChanges[$sAttCode] = $aChanges[$sAttCode];
|
||||
$aHKChanges[$oAttDef->GetSQLLeft()] = $iNewLeft;
|
||||
$aHKChanges[$oAttDef->GetSQLRight()] = $iNewLeft + $iDelta - 1;
|
||||
$aChanges[$sAttCode] = $aHKChanges; // the 3 values will be stored by MakeUpdateQuery below
|
||||
}
|
||||
|
||||
// Update scalar attributes
|
||||
if (count($aChanges) != 0)
|
||||
{
|
||||
$oFilter = new DBObjectSearch(get_class($this));
|
||||
$oFilter->AddCondition('id', $this->m_iKey, '=');
|
||||
|
||||
$sSQL = MetaModel::MakeUpdateQuery($oFilter, $aChanges);
|
||||
CMDBSource::Query($sSQL);
|
||||
}
|
||||
}
|
||||
@@ -1337,6 +1546,34 @@ abstract class DBObject
|
||||
|
||||
if (!MetaModel::DBIsReadOnly())
|
||||
{
|
||||
foreach(MetaModel::ListAttributeDefs(get_class($this)) as $sAttCode => $oAttDef)
|
||||
{
|
||||
if ($oAttDef->IsHierarchicalKey())
|
||||
{
|
||||
// Update the left & right indexes for each hierarchical key
|
||||
$sTable = $sTable = MetaModel::DBGetTable(get_class($this), $sAttCode);
|
||||
$sSQL = "SELECT `".$oAttDef->GetSQLRight()."` AS `right`, `".$oAttDef->GetSQLLeft()."` AS `left` FROM `$sTable` WHERE id=".CMDBSource::Quote($this->m_iKey);
|
||||
$aRes = CMDBSource::QueryToArray($sSQL);
|
||||
$iMyLeft = $aRes[0]['left'];
|
||||
$iMyRight = $aRes[0]['right'];
|
||||
$iDelta =$iMyRight - $iMyLeft + 1;
|
||||
MetaModel::HKTemporaryCutBranch($iMyLeft, $iMyRight, $oAttDef, $sTable);
|
||||
|
||||
// No new parent for now, insert completely at the right of the tree
|
||||
$sSQL = "SELECT max(`".$oAttDef->GetSQLRight()."`) AS max FROM `$sTable`";
|
||||
$aRes = CMDBSource::QueryToArray($sSQL);
|
||||
if (count($aRes) == 0)
|
||||
{
|
||||
$iNewLeft = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
$iNewLeft = $aRes[0]['max']+1;
|
||||
}
|
||||
MetaModel::HKReplugBranch($iNewLeft, $iNewLeft + $iDelta - 1, $oAttDef, $sTable);
|
||||
}
|
||||
}
|
||||
|
||||
foreach(MetaModel::EnumParentClasses(get_class($this), ENUM_PARENT_CLASSES_ALL) as $sParentClass)
|
||||
{
|
||||
$this->DBDeleteSingleTable($sParentClass);
|
||||
@@ -1372,7 +1609,14 @@ abstract class DBObject
|
||||
foreach ($aToDelete as $iId => $aData)
|
||||
{
|
||||
$oToDelete = $aData['to_delete'];
|
||||
$oToDelete->DBDeleteSingleObject();
|
||||
// The deletion based on a deletion plan should not be done for each oject if the deletion plan is common (Trac #457)
|
||||
// because for each object we would try to update all the preceding ones... that are already deleted
|
||||
// A better approach would be to change the API to apply the DBDelete on the deletion plan itself... just once
|
||||
// As a temporary fix: delete only the objects that are still to be deleted...
|
||||
if ($oToDelete->m_bIsInDB)
|
||||
{
|
||||
$oToDelete->DBDeleteSingleObject();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1383,7 +1627,7 @@ abstract class DBObject
|
||||
$oToUpdate = $aData['to_reset'];
|
||||
foreach ($aData['attributes'] as $sRemoteExtKey => $aRemoteAttDef)
|
||||
{
|
||||
$oToUpdate->Set($sRemoteExtKey, 0);
|
||||
$oToUpdate->Set($sRemoteExtKey, $aData['values'][$sRemoteExtKey]);
|
||||
$oToUpdate->DBUpdate();
|
||||
}
|
||||
}
|
||||
@@ -1442,19 +1686,22 @@ abstract class DBObject
|
||||
if (!$bRet) $bSuccess = false;
|
||||
}
|
||||
|
||||
// Change state triggers...
|
||||
$sClass = get_class($this);
|
||||
$sClassList = implode("', '", MetaModel::EnumParentClasses($sClass, ENUM_PARENT_CLASSES_ALL));
|
||||
$oSet = new DBObjectSet(DBObjectSearch::FromOQL("SELECT TriggerOnStateLeave AS t WHERE t.target_class IN ('$sClassList') AND t.state='$sPreviousState'"));
|
||||
while ($oTrigger = $oSet->Fetch())
|
||||
if ($bSuccess)
|
||||
{
|
||||
$oTrigger->DoActivate($this->ToArgs('this'));
|
||||
}
|
||||
|
||||
$oSet = new DBObjectSet(DBObjectSearch::FromOQL("SELECT TriggerOnStateEnter AS t WHERE t.target_class IN ('$sClassList') AND t.state='$sNewState'"));
|
||||
while ($oTrigger = $oSet->Fetch())
|
||||
{
|
||||
$oTrigger->DoActivate($this->ToArgs('this'));
|
||||
// Change state triggers...
|
||||
$sClass = get_class($this);
|
||||
$sClassList = implode("', '", MetaModel::EnumParentClasses($sClass, ENUM_PARENT_CLASSES_ALL));
|
||||
$oSet = new DBObjectSet(DBObjectSearch::FromOQL("SELECT TriggerOnStateLeave AS t WHERE t.target_class IN ('$sClassList') AND t.state='$sPreviousState'"));
|
||||
while ($oTrigger = $oSet->Fetch())
|
||||
{
|
||||
$oTrigger->DoActivate($this->ToArgs('this'));
|
||||
}
|
||||
|
||||
$oSet = new DBObjectSet(DBObjectSearch::FromOQL("SELECT TriggerOnStateEnter AS t WHERE t.target_class IN ('$sClassList') AND t.state='$sNewState'"));
|
||||
while ($oTrigger = $oSet->Fetch())
|
||||
{
|
||||
$oTrigger->DoActivate($this->ToArgs('this'));
|
||||
}
|
||||
}
|
||||
|
||||
return $bSuccess;
|
||||
@@ -1474,10 +1721,8 @@ abstract class DBObject
|
||||
$aScalarArgs[$sArgName] = $this->GetKey();
|
||||
$aScalarArgs[$sArgName.'->id'] = $this->GetKey();
|
||||
$aScalarArgs[$sArgName.'->object()'] = $this;
|
||||
$aScalarArgs[$sArgName.'->hyperlink()'] = $this->GetHyperlink();
|
||||
// #@# Prototype for a user portal - to be dehardcoded later
|
||||
$sToPortal = utils::GetAbsoluteUrlPath().'../portal/index.php?operation=details&id='.$this->GetKey();
|
||||
$aScalarArgs[$sArgName.'->hyperlink(portal)'] = '<a href="'.$sToPortal.'">'.$this->GetName().'</a>';
|
||||
$aScalarArgs[$sArgName.'->hyperlink()'] = $this->GetHyperlink('iTopStandardURLMaker', false);
|
||||
$aScalarArgs[$sArgName.'->hyperlink(portal)'] = $this->GetHyperlink('PortalURLMaker', false);
|
||||
$aScalarArgs[$sArgName.'->name()'] = $this->GetName();
|
||||
|
||||
$sClass = get_class($this);
|
||||
@@ -1489,7 +1734,14 @@ abstract class DBObject
|
||||
// #@# Note: This has been proven to be quite slow, this can slow down bulk load
|
||||
$sAsHtml = $this->GetAsHtml($sAttCode);
|
||||
$aScalarArgs[$sArgName.'->html('.$sAttCode.')'] = $sAsHtml;
|
||||
$aScalarArgs[$sArgName.'->label('.$sAttCode.')'] = strip_tags($sAsHtml);
|
||||
$aScalarArgs[$sArgName.'->label('.$sAttCode.')'] = $this->GetEditValue($sAttCode); // "Nice" display value, but without HTML tags and entities
|
||||
}
|
||||
// Do something for case logs... quick N' dirty...
|
||||
if ($aScalarArgs[$sArgName.'->'.$sAttCode] instanceof ormCaseLog)
|
||||
{
|
||||
$oCaseLog = $aScalarArgs[$sArgName.'->'.$sAttCode];
|
||||
$aScalarArgs[$sArgName.'->'.$sAttCode] = $oCaseLog->GetText();
|
||||
$aScalarArgs[$sArgName.'->head('.$sAttCode.')'] = $oCaseLog->GetLatestEntry();
|
||||
}
|
||||
}
|
||||
$this->m_aAsArgs = $aScalarArgs;
|
||||
@@ -1639,7 +1891,16 @@ abstract class DBObject
|
||||
if ($oAttDef->IsNullAllowed())
|
||||
{
|
||||
// Optional external key, list to reset
|
||||
$oDeletionPlan->AddToUpdate($oDependentObj, $oAttDef);
|
||||
if (($iDeletePropagationOption == DEL_MOVEUP) && ($oAttDef->IsHierarchicalKey()))
|
||||
{
|
||||
// Move the child up one level i.e. set the same parent as the current object
|
||||
$iParentId = $this->Get($oAttDef->GetCode());
|
||||
$oDeletionPlan->AddToUpdate($oDependentObj, $oAttDef, $iParentId);
|
||||
}
|
||||
else
|
||||
{
|
||||
$oDeletionPlan->AddToUpdate($oDependentObj, $oAttDef);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1679,7 +1940,7 @@ abstract class DBObject
|
||||
$oSet = $this->GetMasterReplica();
|
||||
while($aData = $oSet->FetchAssoc())
|
||||
{
|
||||
if ($aData['datasource']->GetKey() == SynchroDataSource::GetCurrentTaskId())
|
||||
if ($aData['datasource']->GetKey() == SynchroExecution::GetCurrentTaskId())
|
||||
{
|
||||
// Ignore the current task (check to write => ok)
|
||||
continue;
|
||||
|
||||
@@ -22,6 +22,16 @@
|
||||
* @author Denis Flaven <denis.flaven@combodo.com>
|
||||
* @license http://www.opensource.org/licenses/gpl-3.0.html LGPL
|
||||
*/
|
||||
|
||||
define('TREE_OPERATOR_EQUALS', 0);
|
||||
define('TREE_OPERATOR_BELOW', 1);
|
||||
define('TREE_OPERATOR_BELOW_STRICT', 2);
|
||||
define('TREE_OPERATOR_NOT_BELOW', 3);
|
||||
define('TREE_OPERATOR_NOT_BELOW_STRICT', 4);
|
||||
define('TREE_OPERATOR_ABOVE', 5);
|
||||
define('TREE_OPERATOR_ABOVE_STRICT', 6);
|
||||
define('TREE_OPERATOR_NOT_ABOVE', 7);
|
||||
define('TREE_OPERATOR_NOT_ABOVE_STRICT', 8);
|
||||
|
||||
class DBObjectSearch
|
||||
{
|
||||
@@ -33,6 +43,7 @@ class DBObjectSearch
|
||||
private $m_aPointingTo;
|
||||
private $m_aReferencedBy;
|
||||
private $m_aRelatedTo;
|
||||
private $m_bDataFiltered;
|
||||
|
||||
// By default, some information may be hidden to the current user
|
||||
// But it may happen that we need to disable that feature
|
||||
@@ -53,12 +64,27 @@ class DBObjectSearch
|
||||
$this->m_aPointingTo = array();
|
||||
$this->m_aReferencedBy = array();
|
||||
$this->m_aRelatedTo = array();
|
||||
$this->m_bDataFiltered = false;
|
||||
$this->m_aParentConditions = array();
|
||||
}
|
||||
|
||||
public function AllowAllData() {$this->m_bAllowAllData = true;}
|
||||
public function IsAllDataAllowed() {return $this->m_bAllowAllData;}
|
||||
public function IsDataFiltered() {return $this->m_bDataFiltered; }
|
||||
public function SetDataFiltered() {$this->m_bDataFiltered = true;}
|
||||
|
||||
public function GetClassName($sAlias)
|
||||
{
|
||||
if (array_key_exists($sAlias, $this->m_aClasses))
|
||||
{
|
||||
return $this->m_aClasses[$sAlias];
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new CoreException("Invalid class alias '$sAlias'");
|
||||
}
|
||||
}
|
||||
|
||||
public function GetClassName($sAlias) {return $this->m_aClasses[$sAlias];}
|
||||
public function GetJoinedClasses() {return $this->m_aClasses;}
|
||||
|
||||
public function GetClass()
|
||||
@@ -107,6 +133,7 @@ class DBObjectSearch
|
||||
if (count($this->m_aPointingTo) > 0) return false;
|
||||
if (count($this->m_aReferencedBy) > 0) return false;
|
||||
if (count($this->m_aRelatedTo) > 0) return false;
|
||||
if (count($this->m_aParentConditions) > 0) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -115,13 +142,55 @@ class DBObjectSearch
|
||||
// To replace __Describe
|
||||
}
|
||||
|
||||
public function DescribeConditionPointTo($sExtKeyAttCode)
|
||||
public function DescribeConditionPointTo($sExtKeyAttCode, $aPointingTo)
|
||||
{
|
||||
if (!isset($this->m_aPointingTo[$sExtKeyAttCode])) return "";
|
||||
$oFilter = $this->m_aPointingTo[$sExtKeyAttCode];
|
||||
if ($oFilter->IsAny()) return "";
|
||||
$oAtt = MetaModel::GetAttributeDef($this->GetClass(), $sExtKeyAttCode);
|
||||
return $oAtt->GetLabel()." having ({$oFilter->DescribeConditions()})";
|
||||
if (empty($aPointingTo)) return "";
|
||||
foreach($aPointingTo as $iOperatorCode => $oFilter)
|
||||
{
|
||||
if ($oFilter->IsAny()) break;
|
||||
$oAtt = MetaModel::GetAttributeDef($this->GetClass(), $sExtKeyAttCode);
|
||||
$sOperator = '';
|
||||
switch($iOperatorCode)
|
||||
{
|
||||
case TREE_OPERATOR_EQUALS:
|
||||
$sOperator = 'having';
|
||||
break;
|
||||
|
||||
case TREE_OPERATOR_BELOW:
|
||||
$sOperator = 'below';
|
||||
break;
|
||||
|
||||
case TREE_OPERATOR_BELOW_STRICT:
|
||||
$sOperator = 'strictly below';
|
||||
break;
|
||||
|
||||
case TREE_OPERATOR_NOT_BELOW:
|
||||
$sOperator = 'not below';
|
||||
break;
|
||||
|
||||
case TREE_OPERATOR_NOT_BELOW_STRICT:
|
||||
$sOperator = 'strictly not below';
|
||||
break;
|
||||
|
||||
case TREE_OPERATOR_ABOVE:
|
||||
$sOperator = 'above';
|
||||
break;
|
||||
|
||||
case TREE_OPERATOR_ABOVE_STRICT:
|
||||
$sOperator = 'strictly above';
|
||||
break;
|
||||
|
||||
case TREE_OPERATOR_NOT_ABOVE:
|
||||
$sOperator = 'not above';
|
||||
break;
|
||||
|
||||
case TREE_OPERATOR_NOT_ABOVE_STRICT:
|
||||
$sOperator = 'strictly not above';
|
||||
break;
|
||||
}
|
||||
$aDescription[] = $oAtt->GetLabel()."$sOperator ({$oFilter->DescribeConditions()})";
|
||||
}
|
||||
return implode(' and ', $aDescription);
|
||||
}
|
||||
|
||||
public function DescribeConditionRefBy($sForeignClass, $sForeignExtKeyAttCode)
|
||||
@@ -141,6 +210,7 @@ class DBObjectSearch
|
||||
return "related ($sRelCode... peut mieux faire !, $iMaxDepth dig depth) to a {$oFilter->GetClass()} ({$oFilter->DescribeConditions()})";
|
||||
}
|
||||
|
||||
|
||||
public function DescribeConditions()
|
||||
{
|
||||
$aConditions = array();
|
||||
@@ -159,10 +229,9 @@ class DBObjectSearch
|
||||
$aConditions[] = $this->RenderCondition();
|
||||
|
||||
$aCondPoint = array();
|
||||
foreach($this->m_aPointingTo as $sExtKeyAttCode=>$oFilter)
|
||||
foreach($this->m_aPointingTo as $sExtKeyAttCode => $aPointingTo)
|
||||
{
|
||||
if ($oFilter->IsAny()) continue;
|
||||
$aCondPoint[] = $this->DescribeConditionPointTo($sExtKeyAttCode);
|
||||
$aCondPoint[] = $this->DescribeConditionPointTo($sExtKeyAttCode, $aPointingTo);
|
||||
}
|
||||
if (count($aCondPoint) > 0)
|
||||
{
|
||||
@@ -187,6 +256,11 @@ class DBObjectSearch
|
||||
$aConditions[] = implode(" and ", $aCondReferred);
|
||||
}
|
||||
|
||||
foreach ($this->m_aParentConditions as $aRelInfo)
|
||||
{
|
||||
$aCondReferred[] = $this->DescribeConditionParent($aRelInfo);
|
||||
}
|
||||
|
||||
return implode(" and ", $aConditions);
|
||||
}
|
||||
|
||||
@@ -209,18 +283,75 @@ class DBObjectSearch
|
||||
|
||||
protected function TransferConditionExpression($oFilter, $aTranslation)
|
||||
{
|
||||
// Prevent collisions in the parameter names by renaming them if needed
|
||||
foreach($this->m_aParams as $sParam => $value)
|
||||
{
|
||||
if (array_key_exists($sParam, $oFilter->m_aParams) && ($value != $oFilter->m_aParams[$sParam]))
|
||||
{
|
||||
// Generate a new and unique name for the collinding parameter
|
||||
$index = 1;
|
||||
while(array_key_exists($sParam.$index, $oFilter->m_aParams))
|
||||
{
|
||||
$index++;
|
||||
}
|
||||
$secondValue = $oFilter->m_aParams[$sParam];
|
||||
$oFilter->RenameParam($sParam, $sParam.$index);
|
||||
unset($oFilter->m_aParams[$sParam]);
|
||||
$oFilter->m_aParams[$sParam.$index] = $secondValue;
|
||||
}
|
||||
}
|
||||
//echo "<p>TransferConditionExpression:<br/>";
|
||||
//echo "Adding Conditions:<br/><pre>oFilter:\n".print_r($oFilter, true)."\naTranslation:\n".print_r($aTranslation, true)."</pre>\n";
|
||||
//echo "</p>";
|
||||
$oTranslated = $oFilter->GetCriteria()->Translate($aTranslation, false, false /* leave unresolved fields */);
|
||||
//echo "Adding Conditions (translated):<br/><pre>".print_r($oTranslated, true)."</pre>\n";
|
||||
$this->AddConditionExpression($oTranslated);
|
||||
// #@# what about collisions in parameter names ???
|
||||
$this->m_aParams = array_merge($this->m_aParams, $oFilter->m_aParams);
|
||||
}
|
||||
|
||||
protected function RenameParam($sOldName, $sNewName)
|
||||
{
|
||||
$this->m_oSearchCondition->RenameParam($sOldName, $sNewName);
|
||||
foreach($this->m_aRelatedTo as $aRelatedTo)
|
||||
{
|
||||
$aRelatedTo['flt']->RenameParam($sOldName, $sNewName);
|
||||
}
|
||||
foreach($this->m_aPointingTo as $sExtKeyAttCode=>$aPointingTo)
|
||||
{
|
||||
foreach($aPointingTo as $iOperatorCode => $aFilter)
|
||||
{
|
||||
foreach($aFilter as $sAlias => $oExtFilter)
|
||||
{
|
||||
$oExtFilter->RenameParam($sOldName, $sNewName);
|
||||
}
|
||||
}
|
||||
}
|
||||
foreach($this->m_aReferencedBy as $sForeignClass => $aReferences)
|
||||
{
|
||||
foreach($aReferences as $sForeignExtKeyAttCode => $oForeignFilter)
|
||||
{
|
||||
$oForeignFilter->RenameParam($sOldName, $sNewName);
|
||||
}
|
||||
}
|
||||
|
||||
foreach($this->m_aParentConditions as $aParent)
|
||||
{
|
||||
$aParent['expression']->RenameParam($sOldName, $sNewName);
|
||||
}
|
||||
}
|
||||
|
||||
public function ResetCondition()
|
||||
{
|
||||
$this->m_oSearchCondition = new TrueExpression();
|
||||
$this->m_aParentConditions = array();
|
||||
// ? is that usefull/enough, do I need to rebuild the list after the subqueries ?
|
||||
}
|
||||
|
||||
public function MergeConditionExpression($oExpression)
|
||||
{
|
||||
$this->m_oSearchCondition = $this->m_oSearchCondition->LogOr($oExpression);
|
||||
}
|
||||
|
||||
public function AddConditionExpression($oExpression)
|
||||
{
|
||||
$this->m_oSearchCondition = $this->m_oSearchCondition->LogAnd($oExpression);
|
||||
@@ -320,30 +451,113 @@ class DBObjectSearch
|
||||
$this->AddConditionExpression($oNewCondition);
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify a condition on external keys or link sets
|
||||
* @param sAttSpec Can be either an attribute code or extkey->[sAttSpec] or linkset->[sAttSpec] and so on, recursively
|
||||
* Example: infra_list->ci_id->location_id->country
|
||||
* @param value The value to match
|
||||
* @return void
|
||||
*/
|
||||
public function AddConditionAdvanced($sAttSpec, $value)
|
||||
{
|
||||
$sClass = $this->GetClass();
|
||||
|
||||
$iPos = strpos($sAttSpec, '->');
|
||||
if ($iPos !== false)
|
||||
{
|
||||
$sAttCode = substr($sAttSpec, 0, $iPos);
|
||||
$sSubSpec = substr($sAttSpec, $iPos + 2);
|
||||
|
||||
if (!MetaModel::IsValidAttCode($sClass, $sAttCode))
|
||||
{
|
||||
throw new Exception("Invalid attribute code '$sClass/$sAttCode' in condition specification '$sAttSpec'");
|
||||
}
|
||||
|
||||
$oAttDef = MetaModel::GetAttributeDef($sClass, $sAttCode);
|
||||
if ($oAttDef->IsLinkSet())
|
||||
{
|
||||
$sTargetClass = $oAttDef->GetLinkedClass();
|
||||
$sExtKeyToMe = $oAttDef->GetExtKeyToMe();
|
||||
|
||||
$oNewFilter = new DBObjectSearch($sTargetClass);
|
||||
$oNewFilter->AddConditionAdvanced($sSubSpec, $value);
|
||||
|
||||
$this->AddCondition_ReferencedBy($oNewFilter, $sExtKeyToMe);
|
||||
}
|
||||
elseif ($oAttDef->IsExternalKey(EXTKEY_ABSOLUTE))
|
||||
{
|
||||
$sTargetClass = $oAttDef->GetTargetClass(EXTKEY_ABSOLUTE);
|
||||
|
||||
$oNewFilter = new DBObjectSearch($sTargetClass);
|
||||
$oNewFilter->AddConditionAdvanced($sSubSpec, $value);
|
||||
|
||||
$this->AddCondition_PointingTo($oNewFilter, $sAttCode);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new Exception("Attribute specification '$sAttSpec', '$sAttCode' should be either a link set or an external key");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// $sAttSpec is an attribute code
|
||||
//
|
||||
$this->AddCondition($sAttSpec, $value);
|
||||
}
|
||||
}
|
||||
|
||||
public function AddCondition_FullText($sFullText)
|
||||
{
|
||||
$this->m_aFullText[] = $sFullText;
|
||||
}
|
||||
|
||||
protected function AddToNameSpace(&$aClassAliases, &$aAliasTranslation)
|
||||
public function AddCondition_Parent($sAttCode, $iOperatorCode, $oExpression)
|
||||
{
|
||||
$sOrigAlias = $this->GetClassAlias();
|
||||
if (array_key_exists($sOrigAlias, $aClassAliases))
|
||||
$oAttDef = MetaModel::GetAttributeDef($this->GetClass(), $sAttCode);
|
||||
if (!$oAttDef instanceof AttributeHierarchicalKey)
|
||||
{
|
||||
$sNewAlias = MetaModel::GenerateUniqueAlias($aClassAliases, $sOrigAlias, $this->GetClass());
|
||||
$this->m_aSelectedClasses[$sNewAlias] = $this->GetClass();
|
||||
unset($this->m_aSelectedClasses[$sOrigAlias]);
|
||||
|
||||
// Translate the condition expression with the new alias
|
||||
$aAliasTranslation[$sOrigAlias]['*'] = $sNewAlias;
|
||||
throw new Exception("AddCondition_Parent can only be used on hierarchical keys. '$sAttCode' is not a hierarchical key.");
|
||||
}
|
||||
|
||||
// add the alias into the filter aliases list
|
||||
$aClassAliases[$this->GetClassAlias()] = $this->GetClass();
|
||||
|
||||
foreach($this->m_aPointingTo as $sExtKeyAttCode=>$oFilter)
|
||||
$this->m_aParentConditions[] = array(
|
||||
'attCode' => $sAttCode,
|
||||
'operator' => $iOperatorCode,
|
||||
'expression' => $oExpression,
|
||||
);
|
||||
}
|
||||
|
||||
protected function AddToNameSpace(&$aClassAliases, &$aAliasTranslation, $bTranslateMainAlias = true)
|
||||
{
|
||||
if ($bTranslateMainAlias)
|
||||
{
|
||||
$oFilter->AddToNameSpace($aClassAliases, $aAliasTranslation);
|
||||
$sOrigAlias = $this->GetClassAlias();
|
||||
if (array_key_exists($sOrigAlias, $aClassAliases))
|
||||
{
|
||||
$sNewAlias = MetaModel::GenerateUniqueAlias($aClassAliases, $sOrigAlias, $this->GetClass());
|
||||
//echo "<p>Generating a new alias for $sOrigAlias (already used). It is now: $sNewAlias</p>\n";
|
||||
$this->m_aSelectedClasses[$sNewAlias] = $this->GetClass();
|
||||
unset($this->m_aSelectedClasses[$sOrigAlias]);
|
||||
|
||||
$this->m_aClasses[$sNewAlias] = $this->GetClass();
|
||||
unset($this->m_aClasses[$sOrigAlias]);
|
||||
|
||||
// Translate the condition expression with the new alias
|
||||
$aAliasTranslation[$sOrigAlias]['*'] = $sNewAlias;
|
||||
}
|
||||
|
||||
//echo "<p>Adding the alias ".$this->GetClass()." as ".$this->GetClassAlias()."</p>\n";
|
||||
// add the alias into the filter aliases list
|
||||
$aClassAliases[$this->GetClassAlias()] = $this->GetClass();
|
||||
}
|
||||
|
||||
foreach($this->m_aPointingTo as $sExtKeyAttCode=>$aPointingTo)
|
||||
{
|
||||
foreach($aPointingTo as $iOperatorCode => $aFilter)
|
||||
{
|
||||
foreach($aFilter as $sAlias => $oFilter)
|
||||
{
|
||||
$oFilter->AddToNameSpace($aClassAliases, $aAliasTranslation);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach($this->m_aReferencedBy as $sForeignClass=>$aReferences)
|
||||
@@ -355,16 +569,17 @@ class DBObjectSearch
|
||||
}
|
||||
}
|
||||
|
||||
public function AddCondition_PointingTo(DBObjectSearch $oFilter, $sExtKeyAttCode)
|
||||
public function AddCondition_PointingTo(DBObjectSearch $oFilter, $sExtKeyAttCode, $iOperatorCode = TREE_OPERATOR_EQUALS)
|
||||
{
|
||||
$aAliasTranslation = array();
|
||||
$res = $this->AddCondition_PointingTo_InNameSpace($oFilter, $sExtKeyAttCode, $this->m_aClasses, $aAliasTranslation);
|
||||
$res = $this->AddCondition_PointingTo_InNameSpace($oFilter, $sExtKeyAttCode, $this->m_aClasses, $aAliasTranslation, $iOperatorCode);
|
||||
$this->TransferConditionExpression($oFilter, $aAliasTranslation);
|
||||
return $res;
|
||||
}
|
||||
|
||||
protected function AddCondition_PointingTo_InNameSpace(DBObjectSearch $oFilter, $sExtKeyAttCode, &$aClassAliases, &$aAliasTranslation)
|
||||
protected function AddCondition_PointingTo_InNameSpace(DBObjectSearch $oFilter, $sExtKeyAttCode, &$aClassAliases, &$aAliasTranslation, $iOperatorCode)
|
||||
{
|
||||
//echo "<p style=\"color:green\">Calling: AddCondition_PointingTo_InNameSpace([<pre>".print_r($aClassAliases, true)."</pre></br>], [<pre>".print_r($aAliasTranslation, true)."</pre>]);</p>";
|
||||
if (!MetaModel::IsValidKeyAttCode($this->GetClass(), $sExtKeyAttCode))
|
||||
{
|
||||
throw new CoreWarning("The attribute code '$sExtKeyAttCode' is not an external key of the class '{$this->GetClass()}' - the condition will be ignored");
|
||||
@@ -374,20 +589,41 @@ class DBObjectSearch
|
||||
{
|
||||
throw new CoreException("The specified filter (pointing to {$oFilter->GetClass()}) is not compatible with the key '{$this->GetClass()}::$sExtKeyAttCode', which is pointing to {$oAttExtKey->GetTargetClass()}");
|
||||
}
|
||||
if(($iOperatorCode != TREE_OPERATOR_EQUALS) && !($oAttExtKey instanceof AttributeHierarchicalKey))
|
||||
{
|
||||
throw new CoreException("The specified tree operator $isOperatorCode is not applicable to the key '{$this->GetClass()}::$sExtKeyAttCode', which is not a HierarchicalKey");
|
||||
}
|
||||
|
||||
$bSamePointingTo = false;
|
||||
if (array_key_exists($sExtKeyAttCode, $this->m_aPointingTo))
|
||||
{
|
||||
$this->m_aPointingTo[$sExtKeyAttCode]->MergeWith_InNamespace($oFilter, $aClassAliases, $aAliasTranslation);
|
||||
if (array_key_exists($iOperatorCode, $this->m_aPointingTo[$sExtKeyAttCode]))
|
||||
{
|
||||
if (array_key_exists($oFilter->GetClassAlias(), $this->m_aPointingTo[$sExtKeyAttCode][$iOperatorCode]))
|
||||
{
|
||||
//echo "<p style=\"color:red\">[".__LINE__."]this->m_aPointingTo[$sExtKeyAttCode][$iOperatorCode][".$oFilter->GetFirstJoinedClassAlias()."]:<pre>\n".print_r($this->m_aPointingTo[$sExtKeyAttCode][$iOperatorCode], true)."</pre>;</p>";
|
||||
$bSamePointingTo = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//echo "<p style=\"color:red\">[".__LINE__."]Calling: AddToNameSpace([".implode(',', $aClassAliases)."], [".implode(',', $aAliasTranslation)."]);</p>";
|
||||
if ($bSamePointingTo)
|
||||
{
|
||||
//echo "<p style=\"color:red\">[".__LINE__."]AddPointingTo: Merging filters for [$sExtKeyAttCode][$iOperatorCode][".$oFilter->GetClassAlias()."]</p>";
|
||||
// Same ext key, alias and same operator, merge the filters together
|
||||
// $sAlias = $oFilter->GetClassAlias();
|
||||
//echo "<p style=\"color:red\">[".__LINE__."]before: AddToNameSpace(aClassAliases[<pre>\n".print_r($aClassAliases, true)."</pre>], aAliasTranslation[<pre>\n".print_r($aAliasTranslation, true)."</pre>]);</p>";
|
||||
$oFilter->AddToNamespace($aClassAliases, $aAliasTranslation, true /* Don't translate the main alias */);
|
||||
//echo "<p style=\"color:blue\">[".__LINE__."]after: AddToNameSpace(aClassAliases[<pre>\n".print_r($aClassAliases, true)."</pre>], aAliasTranslation[<pre>\n".print_r($aAliasTranslation, true)."</pre>]);</p>";
|
||||
// $this->m_aPointingTo[$sExtKeyAttCode][$iOperatorCode][$sAlias]->MergeWith($oFilter, $aClassAliases, $aAliasTranslation);
|
||||
$this->m_aPointingTo[$sExtKeyAttCode][$iOperatorCode][$oFilter->GetClassAlias()] = $oFilter;
|
||||
}
|
||||
else
|
||||
{
|
||||
//echo "<p style=\"color:red\">[".__LINE__."]AddPointingTo: Adding a new PointingTo filter for [$sExtKeyAttCode][$iOperatorCode][".$oFilter->GetClassAlias()."]</p>";
|
||||
$oFilter->AddToNamespace($aClassAliases, $aAliasTranslation);
|
||||
|
||||
// #@# The condition expression found in that filter should not be used - could be another kind of structure like a join spec tree !!!!
|
||||
// $oNewFilter = clone $oFilter;
|
||||
// $oNewFilter->ResetCondition();
|
||||
|
||||
$this->m_aPointingTo[$sExtKeyAttCode] = $oFilter;
|
||||
$this->m_aPointingTo[$sExtKeyAttCode][$iOperatorCode][$oFilter->GetClassAlias()] = $oFilter;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -431,6 +667,7 @@ class DBObjectSearch
|
||||
public function AddCondition_LinkedTo(DBObjectSearch $oLinkFilter, $sExtKeyAttCodeToMe, $sExtKeyAttCodeTarget, DBObjectSearch $oFilterTarget)
|
||||
{
|
||||
$oLinkFilterFinal = clone $oLinkFilter;
|
||||
// todo : new function prototype
|
||||
$oLinkFilterFinal->AddCondition_PointingTo($sExtKeyAttCodeToMe);
|
||||
|
||||
$this->AddCondition_ReferencedBy($oLinkFilterFinal, $sExtKeyAttCodeToMe);
|
||||
@@ -463,9 +700,15 @@ class DBObjectSearch
|
||||
$this->m_aFullText = array_merge($this->m_aFullText, $oFilter->m_aFullText);
|
||||
$this->m_aRelatedTo = array_merge($this->m_aRelatedTo, $oFilter->m_aRelatedTo);
|
||||
|
||||
foreach($oFilter->m_aPointingTo as $sExtKeyAttCode=>$oExtFilter)
|
||||
foreach($oFilter->m_aPointingTo as $sExtKeyAttCode=>$aPointingTo)
|
||||
{
|
||||
$this->AddCondition_PointingTo_InNamespace($oExtFilter, $sExtKeyAttCode, $aClassAliases, $aAliasTranslation);
|
||||
foreach($aPointingTo as $iOperatorCode => $aFilter)
|
||||
{
|
||||
foreach($aFilter as $sAlias => $oExtFilter)
|
||||
{
|
||||
$this->AddCondition_PointingTo_InNamespace($oExtFilter, $sExtKeyAttCode, $aClassAliases, $aAliasTranslation, $iOperatorCode);
|
||||
}
|
||||
}
|
||||
}
|
||||
foreach($oFilter->m_aReferencedBy as $sForeignClass => $aReferences)
|
||||
{
|
||||
@@ -484,7 +727,7 @@ class DBObjectSearch
|
||||
{
|
||||
return $this->m_aPointingTo;
|
||||
}
|
||||
if (!array_key_exists($sKeyAttCode, $this->m_aPointingTo)) return null;
|
||||
if (!array_key_exists($sKeyAttCode, $this->m_aPointingTo)) return array();
|
||||
return $this->m_aPointingTo[$sKeyAttCode];
|
||||
}
|
||||
public function GetCriteria_ReferencedBy($sRemoteClass = "", $sForeignExtKeyAttCode = "")
|
||||
@@ -505,16 +748,43 @@ class DBObjectSearch
|
||||
{
|
||||
return $this->m_aRelatedTo;
|
||||
}
|
||||
|
||||
public function SetInternalParams($aParams)
|
||||
{
|
||||
return $this->m_aParams = $aParams;
|
||||
}
|
||||
|
||||
public function GetInternalParams()
|
||||
{
|
||||
return $this->m_aParams;
|
||||
}
|
||||
|
||||
public function GetQueryParams()
|
||||
{
|
||||
$aParams = array();
|
||||
$this->m_oSearchCondition->Render($aParams, true);
|
||||
return $aParams;
|
||||
}
|
||||
|
||||
public function ListConstantFields()
|
||||
{
|
||||
return $this->m_oSearchCondition->ListConstantFields();
|
||||
}
|
||||
|
||||
public function RenderCondition()
|
||||
{
|
||||
return $this->m_oSearchCondition->Render($this->m_aParams, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Turn the parameters (:xxx) into scalar values in order to easily
|
||||
* serialize a search
|
||||
*/
|
||||
public function ApplyParameters($aArgs)
|
||||
{
|
||||
return $this->m_oSearchCondition->ApplyParameters(array_merge($this->m_aParams, $aArgs));
|
||||
}
|
||||
|
||||
public function serialize($bDevelopParams = false, $aContextParams = null)
|
||||
{
|
||||
$sOql = $this->ToOql($bDevelopParams, $aContextParams);
|
||||
@@ -650,10 +920,55 @@ class DBObjectSearch
|
||||
protected function ToOQL_Joins()
|
||||
{
|
||||
$sRes = '';
|
||||
foreach($this->m_aPointingTo as $sExtKey=>$oFilter)
|
||||
foreach($this->m_aPointingTo as $sExtKey => $aPointingTo)
|
||||
{
|
||||
$sRes .= ' JOIN '.$oFilter->GetClass().' AS '.$oFilter->GetClassAlias().' ON '.$this->GetClassAlias().'.'.$sExtKey.' = '.$oFilter->GetClassAlias().'.id';
|
||||
$sRes .= $oFilter->ToOQL_Joins();
|
||||
foreach($aPointingTo as $iOperatorCode => $aFilter)
|
||||
{
|
||||
foreach($aFilter as $sAlias => $oFilter)
|
||||
{
|
||||
switch($iOperatorCode)
|
||||
{
|
||||
case TREE_OPERATOR_EQUALS:
|
||||
$sOperator = ' = ';
|
||||
break;
|
||||
|
||||
case TREE_OPERATOR_BELOW:
|
||||
$sOperator = ' BELOW ';
|
||||
break;
|
||||
|
||||
case TREE_OPERATOR_BELOW_STRICT:
|
||||
$sOperator = ' BELOW STRICT ';
|
||||
break;
|
||||
|
||||
case TREE_OPERATOR_NOT_BELOW:
|
||||
$sOperator = ' NOT BELOW ';
|
||||
break;
|
||||
|
||||
case TREE_OPERATOR_NOT_BELOW_STRICT:
|
||||
$sOperator = ' NOT BELOW STRICT ';
|
||||
break;
|
||||
|
||||
case TREE_OPERATOR_ABOVE:
|
||||
$sOperator = ' ABOVE ';
|
||||
break;
|
||||
|
||||
case TREE_OPERATOR_ABOVE_STRICT:
|
||||
$sOperator = ' ABOVE STRICT ';
|
||||
break;
|
||||
|
||||
case TREE_OPERATOR_NOT_ABOVE:
|
||||
$sOperator = ' NOT ABOVE ';
|
||||
break;
|
||||
|
||||
case TREE_OPERATOR_NOT_ABOVE_STRICT:
|
||||
$sOperator = ' NOT ABOVE STRICT ';
|
||||
break;
|
||||
|
||||
}
|
||||
$sRes .= ' JOIN '.$oFilter->GetClass().' AS '.$oFilter->GetClassAlias().' ON '.$this->GetClassAlias().'.'.$sExtKey.$sOperator.$oFilter->GetClassAlias().'.id';
|
||||
$sRes .= $oFilter->ToOQL_Joins();
|
||||
}
|
||||
}
|
||||
}
|
||||
foreach($this->m_aReferencedBy as $sForeignClass=>$aReferences)
|
||||
{
|
||||
@@ -866,7 +1181,38 @@ class DBObjectSearch
|
||||
}
|
||||
else
|
||||
{
|
||||
$aJoinItems[$sFromClass]->AddCondition_PointingTo($aJoinItems[$sToClass], $sExtKeyAttCode);
|
||||
$sOperator = $oJoinSpec->GetOperator();
|
||||
switch($sOperator)
|
||||
{
|
||||
case '=':
|
||||
$iOperatorCode = TREE_OPERATOR_EQUALS;
|
||||
break;
|
||||
case 'BELOW':
|
||||
$iOperatorCode = TREE_OPERATOR_BELOW;
|
||||
break;
|
||||
case 'BELOW_STRICT':
|
||||
$iOperatorCode = TREE_OPERATOR_BELOW_STRICT;
|
||||
break;
|
||||
case 'NOT_BELOW':
|
||||
$iOperatorCode = TREE_OPERATOR_NOT_BELOW;
|
||||
break;
|
||||
case 'NOT_BELOW_STRICT':
|
||||
$iOperatorCode = TREE_OPERATOR_NOT_BELOW_STRICT;
|
||||
break;
|
||||
case 'ABOVE':
|
||||
$iOperatorCode = TREE_OPERATOR_ABOVE;
|
||||
break;
|
||||
case 'ABOVE_STRICT':
|
||||
$iOperatorCode = TREE_OPERATOR_ABOVE_STRICT;
|
||||
break;
|
||||
case 'NOT_ABOVE':
|
||||
$iOperatorCode = TREE_OPERATOR_NOT_ABOVE;
|
||||
break;
|
||||
case 'NOT_ABOVE_STRICT':
|
||||
$iOperatorCode = TREE_OPERATOR_NOT_ABOVE_STRICT;
|
||||
break;
|
||||
}
|
||||
$aJoinItems[$sFromClass]->AddCondition_PointingTo($aJoinItems[$sToClass], $sExtKeyAttCode, $iOperatorCode);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,6 +32,7 @@
|
||||
class DBObjectSet
|
||||
{
|
||||
private $m_oFilter;
|
||||
private $m_aAddedIds; // Ids of objects added (discrete lists)
|
||||
private $m_aOrderBy;
|
||||
public $m_bLoaded;
|
||||
private $m_aData;
|
||||
@@ -41,12 +42,15 @@ class DBObjectSet
|
||||
public function __construct(DBObjectSearch $oFilter, $aOrderBy = array(), $aArgs = array(), $aExtendedDataSpec = null, $iLimitCount = 0, $iLimitStart = 0)
|
||||
{
|
||||
$this->m_oFilter = $oFilter;
|
||||
$this->m_aAddedIds = array();
|
||||
$this->m_aOrderBy = $aOrderBy;
|
||||
$this->m_aArgs = $aArgs;
|
||||
$this->m_aAttToLoad = null;
|
||||
$this->m_aExtendedDataSpec = $aExtendedDataSpec;
|
||||
$this->m_iLimitCount = $iLimitCount;
|
||||
$this->m_iLimitStart = $iLimitStart;
|
||||
|
||||
$this->m_iCount = null; // null if unknown yet
|
||||
$this->m_bLoaded = false; // true when the filter has been used OR the set is built step by step (AddObject...)
|
||||
$this->m_aData = array(); // array of (row => array of (classalias) => object/null)
|
||||
$this->m_aId2Row = array(); // array of (pkey => index in m_aData)
|
||||
@@ -77,6 +81,46 @@ class DBObjectSet
|
||||
return $sRet;
|
||||
}
|
||||
|
||||
public function OptimizeColumnLoad($aAttToLoad)
|
||||
{
|
||||
if (is_null($aAttToLoad))
|
||||
{
|
||||
$this->m_aAttToLoad = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Complete the attribute list with the attribute codes
|
||||
$aAttToLoadWithAttDef = array();
|
||||
foreach($aAttToLoad as $sClassAlias => $aAttList)
|
||||
{
|
||||
$aSelectedClasses = $this->m_oFilter->GetSelectedClasses();
|
||||
$sClass = $aSelectedClasses[$sClassAlias];
|
||||
foreach($aAttList as $sAttToLoad)
|
||||
{
|
||||
$oAttDef = MetaModel::GetAttributeDef($sClass, $sAttToLoad);
|
||||
$aAttToLoadWithAttDef[$sClassAlias][$sAttToLoad] = $oAttDef;
|
||||
if ($oAttDef->IsExternalKey())
|
||||
{
|
||||
// Add the external key friendly name anytime
|
||||
$oFriendlyNameAttDef = MetaModel::GetAttributeDef($sClass, $sAttToLoad.'_friendlyname');
|
||||
$aAttToLoadWithAttDef[$sClassAlias][$sAttToLoad.'_friendlyname'] = $oFriendlyNameAttDef;
|
||||
}
|
||||
}
|
||||
// Add the friendly name anytime
|
||||
$oFriendlyNameAttDef = MetaModel::GetAttributeDef($sClass, 'friendlyname');
|
||||
$aAttToLoadWithAttDef[$sClassAlias]['friendlyname'] = $oFriendlyNameAttDef;
|
||||
|
||||
// Make sure that the final class is requested anytime, whatever the specification (needed for object construction!)
|
||||
if (!MetaModel::IsStandaloneClass($sClass) && !array_key_exists('finalclass', $aAttList))
|
||||
{
|
||||
$aAttToLoadWithAttDef[$sClassAlias]['finalclass'] = MetaModel::GetAttributeDef($sClass, 'finalclass');
|
||||
}
|
||||
}
|
||||
|
||||
$this->m_aAttToLoad = $aAttToLoadWithAttDef;
|
||||
}
|
||||
}
|
||||
|
||||
static public function FromObject($oObject)
|
||||
{
|
||||
$oRetSet = self::FromScratch(get_class($oObject));
|
||||
@@ -86,7 +130,8 @@ class DBObjectSet
|
||||
|
||||
static public function FromScratch($sClass)
|
||||
{
|
||||
$oFilter = new CMDBSearchFilter($sClass);
|
||||
$oFilter = new DBObjectSearch($sClass);
|
||||
$oFilter->AddConditionExpression(new FalseExpression());
|
||||
$oRetSet = new self($oFilter);
|
||||
$oRetSet->m_bLoaded = true; // no DB load
|
||||
return $oRetSet;
|
||||
@@ -96,9 +141,7 @@ class DBObjectSet
|
||||
// input = array of objects
|
||||
static public function FromArray($sClass, $aObjects)
|
||||
{
|
||||
$oFilter = new CMDBSearchFilter($sClass);
|
||||
$oRetSet = new self($oFilter);
|
||||
$oRetSet->m_bLoaded = true; // no DB load
|
||||
$oRetSet = self::FromScratch($sClass);
|
||||
$oRetSet->AddObjectArray($aObjects, $sClass);
|
||||
return $oRetSet;
|
||||
}
|
||||
@@ -226,8 +269,20 @@ class DBObjectSet
|
||||
|
||||
public function GetFilter()
|
||||
{
|
||||
// #@# This is false as soon as the set has been manipulated (AddObject...)
|
||||
return $this->m_oFilter;
|
||||
if (count($this->m_aAddedIds) == 0)
|
||||
{
|
||||
return $this->m_oFilter;
|
||||
}
|
||||
else
|
||||
{
|
||||
$oFilter = clone $this->m_oFilter;
|
||||
|
||||
$oIdListExpr = ListExpression::FromScalars(array_keys($this->m_aAddedIds));
|
||||
$oIdExpr = new FieldExpression('id', $oFilter->GetClassAlias());
|
||||
$oIdInList = new BinaryExpression($oIdExpr, 'IN', $oIdListExpr);
|
||||
$oFilter->MergeConditionExpression($oIdInList);
|
||||
return $oFilter;
|
||||
}
|
||||
}
|
||||
|
||||
public function GetClass()
|
||||
@@ -245,6 +300,11 @@ class DBObjectSet
|
||||
return MetaModel::GetRootClass($this->GetClass());
|
||||
}
|
||||
|
||||
public function GetArgs()
|
||||
{
|
||||
return $this->m_aArgs;
|
||||
}
|
||||
|
||||
public function SetLimit($iLimitCount, $iLimitStart = 0)
|
||||
{
|
||||
$this->m_iLimitCount = $iLimitCount;
|
||||
@@ -269,11 +329,11 @@ class DBObjectSet
|
||||
|
||||
if ($this->m_iLimitCount > 0)
|
||||
{
|
||||
$sSQL = MetaModel::MakeSelectQuery($this->m_oFilter, $this->m_aOrderBy, $this->m_aArgs, $this->m_aExtendedDataSpec, $this->m_iLimitCount, $this->m_iLimitStart);
|
||||
$sSQL = MetaModel::MakeSelectQuery($this->m_oFilter, $this->m_aOrderBy, $this->m_aArgs, $this->m_aAttToLoad, $this->m_aExtendedDataSpec, $this->m_iLimitCount, $this->m_iLimitStart);
|
||||
}
|
||||
else
|
||||
{
|
||||
$sSQL = MetaModel::MakeSelectQuery($this->m_oFilter, $this->m_aOrderBy, $this->m_aArgs, $this->m_aExtendedDataSpec);
|
||||
$sSQL = MetaModel::MakeSelectQuery($this->m_oFilter, $this->m_aOrderBy, $this->m_aArgs, $this->m_aAttToLoad, $this->m_aExtendedDataSpec);
|
||||
}
|
||||
$resQuery = CMDBSource::Query($sSQL);
|
||||
if (!$resQuery) return;
|
||||
@@ -290,11 +350,12 @@ class DBObjectSet
|
||||
}
|
||||
else
|
||||
{
|
||||
$oObject = MetaModel::GetObjectByRow($sClass, $aRow, $sClassAlias, $this->m_aExtendedDataSpec);
|
||||
$oObject = MetaModel::GetObjectByRow($sClass, $aRow, $sClassAlias, $this->m_aAttToLoad, $this->m_aExtendedDataSpec);
|
||||
}
|
||||
|
||||
$aObjects[$sClassAlias] = $oObject;
|
||||
}
|
||||
$this->AddObjectExtended($aObjects);
|
||||
$this->AddObjectExtended($aObjects, true /* internal load */);
|
||||
}
|
||||
CMDBSource::FreeResult($resQuery);
|
||||
}
|
||||
@@ -307,13 +368,17 @@ class DBObjectSet
|
||||
}
|
||||
else
|
||||
{
|
||||
$sSQL = MetaModel::MakeSelectQuery($this->m_oFilter, $this->m_aOrderBy, $this->m_aArgs, null, 0, 0, true);
|
||||
$resQuery = CMDBSource::Query($sSQL);
|
||||
if (!$resQuery) return 0;
|
||||
|
||||
$aRow = CMDBSource::FetchArray($resQuery);
|
||||
CMDBSource::FreeResult($resQuery);
|
||||
return $aRow['COUNT'];
|
||||
if (is_null($this->m_iCount))
|
||||
{
|
||||
$sSQL = MetaModel::MakeSelectQuery($this->m_oFilter, $this->m_aOrderBy, $this->m_aArgs, null, null, 0, 0, true);
|
||||
$resQuery = CMDBSource::Query($sSQL);
|
||||
if (!$resQuery) return 0;
|
||||
|
||||
$aRow = CMDBSource::FetchArray($resQuery);
|
||||
CMDBSource::FreeResult($resQuery);
|
||||
$this->m_iCount = $aRow['COUNT'];
|
||||
}
|
||||
return $this->m_iCount;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -353,7 +418,10 @@ class DBObjectSet
|
||||
|
||||
public function Rewind()
|
||||
{
|
||||
$this->Seek(0);
|
||||
if ($this->m_bLoaded)
|
||||
{
|
||||
$this->Seek(0);
|
||||
}
|
||||
}
|
||||
|
||||
public function Seek($iRow)
|
||||
@@ -378,10 +446,11 @@ class DBObjectSet
|
||||
if (!is_null($oObject))
|
||||
{
|
||||
$this->m_aId2Row[$sClassAlias][$oObject->GetKey()] = $iNextPos;
|
||||
$this->m_aAddedIds[$oObject->GetKey()] = true;
|
||||
}
|
||||
}
|
||||
|
||||
protected function AddObjectExtended($aObjectArray)
|
||||
protected function AddObjectExtended($aObjectArray, $bInternalLoad = false)
|
||||
{
|
||||
if (!$this->m_bLoaded) $this->Load();
|
||||
|
||||
@@ -393,6 +462,10 @@ class DBObjectSet
|
||||
if (!is_null($oObject))
|
||||
{
|
||||
$this->m_aId2Row[$sClassAlias][$oObject->GetKey()] = $iNextPos;
|
||||
if (!$bInternalLoad)
|
||||
{
|
||||
$this->m_aAddedIds[$oObject->GetKey()] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -614,6 +687,56 @@ class DBObjectSet
|
||||
$this->Rewind();
|
||||
return $oCommonObj;
|
||||
}
|
||||
|
||||
/**
|
||||
* List the constant fields (and their value) in the given query
|
||||
* @return Hash [Alias][AttCode] => value
|
||||
*/
|
||||
public function ListConstantFields()
|
||||
{
|
||||
$aScalarArgs = $this->ExpandArgs();
|
||||
$aConst = $this->m_oFilter->ListConstantFields();
|
||||
|
||||
foreach($aConst as $sClassAlias => $aVals)
|
||||
{
|
||||
foreach($aVals as $sCode => $oExpr)
|
||||
{
|
||||
if ($oExpr instanceof ScalarExpression)
|
||||
{
|
||||
$aConst[$sClassAlias][$sCode] = $oExpr->GetValue();
|
||||
}
|
||||
else //Variable
|
||||
{
|
||||
$aConst[$sClassAlias][$sCode] = $aScalarArgs[$oExpr->GetName()];
|
||||
}
|
||||
}
|
||||
}
|
||||
return $aConst;
|
||||
}
|
||||
|
||||
protected function ExpandArgs()
|
||||
{
|
||||
$aScalarArgs = $this->m_oFilter->GetInternalParams();
|
||||
foreach($this->m_aArgs as $sArgName => $value)
|
||||
{
|
||||
if (MetaModel::IsValidObject($value))
|
||||
{
|
||||
$aScalarArgs = array_merge($aScalarArgs, $value->ToArgs($sArgName));
|
||||
}
|
||||
else
|
||||
{
|
||||
$aScalarArgs[$sArgName] = (string) $value;
|
||||
}
|
||||
}
|
||||
$aScalarArgs['current_contact_id'] = UserRights::GetContactId();
|
||||
return $aScalarArgs;
|
||||
}
|
||||
|
||||
public function ApplyParameters()
|
||||
{
|
||||
$aScalarArgs = $this->ExpandArgs();
|
||||
$this->m_oFilter->ApplyParameters($aScalarArgs);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -109,11 +109,11 @@ class DeletionPlan
|
||||
{
|
||||
$this->m_iToUpdate++;
|
||||
|
||||
$oObject = $aData['to_reset'];
|
||||
$oObject = $aData['to_reset'];
|
||||
$aExtKeyLabels = array();
|
||||
foreach ($aData['attributes'] as $sRemoteExtKey => $aRemoteAttDef)
|
||||
{
|
||||
$oObject->Set($sRemoteExtKey, 0);
|
||||
$oObject->Set($sRemoteExtKey, $aData['values'][$sRemoteExtKey]);
|
||||
$aExtKeyLabels[] = $aRemoteAttDef->GetLabel();
|
||||
}
|
||||
$this->m_aToUpdate[$sClass][$iId]['attributes_list'] = implode(', ', $aExtKeyLabels);
|
||||
@@ -264,7 +264,7 @@ class DeletionPlan
|
||||
}
|
||||
}
|
||||
|
||||
public function AddToUpdate($oObject, $oAttDef)
|
||||
public function AddToUpdate($oObject, $oAttDef, $value = 0)
|
||||
{
|
||||
$sClass = get_class($oObject);
|
||||
$iId = $oObject->GetKey();
|
||||
@@ -281,6 +281,7 @@ class DeletionPlan
|
||||
);
|
||||
}
|
||||
$this->m_aToUpdate[$sClass][$iId]['attributes'][$oAttDef->GetCode()] = $oAttDef;
|
||||
$this->m_aToUpdate[$sClass][$iId]['values'][$oAttDef->GetCode()] = $value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -97,7 +97,7 @@ class Dict
|
||||
}
|
||||
|
||||
|
||||
public static function GetCurrentLanguage()
|
||||
public static function GetUserLanguage()
|
||||
{
|
||||
if (self::$m_sCurrentLanguage == null) // May happen when no user is logged in (i.e login screen, non authentifed page)
|
||||
{
|
||||
@@ -124,12 +124,12 @@ class Dict
|
||||
{
|
||||
// Attempt to find the string in the user language
|
||||
//
|
||||
if (!array_key_exists(self::GetCurrentLanguage(), self::$m_aData))
|
||||
if (!array_key_exists(self::GetUserLanguage(), self::$m_aData))
|
||||
{
|
||||
// It may happen, when something happens before the dictionnaries get loaded
|
||||
return $sStringCode;
|
||||
}
|
||||
$aCurrentDictionary = self::$m_aData[self::GetCurrentLanguage()];
|
||||
$aCurrentDictionary = self::$m_aData[self::GetUserLanguage()];
|
||||
if (array_key_exists($sStringCode, $aCurrentDictionary))
|
||||
{
|
||||
return $aCurrentDictionary[$sStringCode];
|
||||
|
||||
@@ -35,6 +35,7 @@ class EMail
|
||||
protected $m_sSubject;
|
||||
protected $m_sTo;
|
||||
protected $m_aHeaders; // array of key=>value
|
||||
protected $m_aAttachments;
|
||||
|
||||
public function __construct($sTo = '', $sSubject = '', $sBody = '', $aHeaders = array())
|
||||
{
|
||||
@@ -42,6 +43,7 @@ class EMail
|
||||
$this->m_sSubject = $sSubject;
|
||||
$this->m_sBody = $sBody;
|
||||
$this->m_aHeaders = $aHeaders;
|
||||
$this->m_aAttachments = array();
|
||||
}
|
||||
|
||||
// Errors management : not that simple because we need that function to be
|
||||
@@ -73,8 +75,14 @@ class EMail
|
||||
{
|
||||
$sHeaders = 'MIME-Version: 1.0' . "\r\n";
|
||||
// ! the case is important for MS-Outlook
|
||||
$sHeaders .= 'Content-Type: text/html; charset=UTF-8' . "\r\n";
|
||||
$sHeaders .= 'Content-Transfer-Encoding: 8bit' . "\r\n";
|
||||
if (!array_key_exists('Content-Type', $this->m_aHeaders))
|
||||
{
|
||||
$sHeaders .= 'Content-Type: text/html; charset=UTF-8' . "\r\n";
|
||||
}
|
||||
if (!array_key_exists('Content-Transfer-Encoding', $this->m_aHeaders))
|
||||
{
|
||||
$sHeaders .= 'Content-Transfer-Encoding: 8bit' . "\r\n";
|
||||
}
|
||||
foreach ($this->m_aHeaders as $sKey => $sValue)
|
||||
{
|
||||
$sHeaders .= "$sKey: $sValue\r\n";
|
||||
@@ -86,8 +94,8 @@ class EMail
|
||||
set_error_handler(array($this, 'mail_error_handler'));
|
||||
$bRes = mail
|
||||
(
|
||||
$this->m_sTo,
|
||||
$this->m_sSubject,
|
||||
str_replace(array("\n", "\r"), ' ', $this->m_sTo), // Prevent header injection
|
||||
$this->EncodeHeaderField($this->m_sSubject), // Prevent header injection & MIME Encode charsets
|
||||
$this->m_sBody,
|
||||
$sHeaders
|
||||
);
|
||||
@@ -110,6 +118,7 @@ class EMail
|
||||
|
||||
public function Send(&$aIssues, $bForceSynchronous = false, $oLog = null)
|
||||
{
|
||||
$this->BuildMessage(); // assemble the attachments into the header/body structure
|
||||
if ($bForceSynchronous)
|
||||
{
|
||||
return $this->SendSynchronous($aIssues, $oLog);
|
||||
@@ -135,6 +144,11 @@ class EMail
|
||||
$this->m_aHeaders[$sKey] = $sValue;
|
||||
}
|
||||
}
|
||||
|
||||
public function SetMessageId($sId)
|
||||
{
|
||||
$this->AddToHeader('Message-ID', $sId);
|
||||
}
|
||||
|
||||
public function SetReferences($sReferences)
|
||||
{
|
||||
@@ -181,6 +195,48 @@ class EMail
|
||||
$this->AddToHeader('Reply-To', $sAddress);
|
||||
}
|
||||
|
||||
public function AddAttachment($data, $sFileName, $sMimeType)
|
||||
{
|
||||
$this->m_aAttachments[] = array('data' => $data, 'filename' => $sFileName, 'mimeType' => $sMimeType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Takes care of the attachments (if any) to build the header/body of the message before storing or sending it
|
||||
*/
|
||||
protected function BuildMessage()
|
||||
{
|
||||
if (count($this->m_aAttachments) == 0) return; // Nothing to do if there are no attachments
|
||||
|
||||
$sDelimiter = '== iTopEmailPart---'.md5(date('r', time()))." ==";
|
||||
$sContentType = isset($this->m_aHeaders['Content-Type']) ? $this->m_aHeaders['Content-Type'] : 'text/html; charset="UTF-8"';
|
||||
$sContentHeader = "Content-Type: $sContentType\r\n";
|
||||
$this->m_aHeaders['Content-Type'] = "multipart/mixed; boundary=\"{$sDelimiter}\"";
|
||||
|
||||
$aAttachments = array();
|
||||
foreach($this->m_aAttachments as $aAttach)
|
||||
{
|
||||
$sAttachmentHeader = "Content-Type: {$aAttach['mimeType']};\r\n Name=\"{$aAttach['filename']}\"\r\n";
|
||||
$sAttachmentHeader .= "Content-Transfer-Encoding: base64\r\nContent-Disposition: attachment;\r\n filename=\"{$aAttach['filename']}\"\r\n";
|
||||
$sAttachmentHeader .= "\r\n";
|
||||
$sAttachment = chunk_split(base64_encode($aAttach['data']));
|
||||
$aAttachments[] = $sAttachmentHeader.$sAttachment."\r\n";
|
||||
}
|
||||
$this->m_sBody = "This is a multi-part message in MIME format.\r\n--".$sDelimiter."\r\n".$sContentHeader."\r\n".$this->m_sBody."\r\n--".$sDelimiter."\r\n";
|
||||
$this->m_sBody .= implode("--".$sDelimiter."\r\n", $aAttachments);
|
||||
$this->m_sBody .= "--".$sDelimiter."--";
|
||||
}
|
||||
|
||||
/**
|
||||
* MIME encode the content of a header field according to RFC2047
|
||||
* @param string $sFieldContent the content of the header to encode
|
||||
* @return string The encoded string
|
||||
*/
|
||||
protected function EncodeHeaderField($sFieldContent)
|
||||
{
|
||||
$sTemp = str_replace(array("\n", "\r"), ' ', $sFieldContent);
|
||||
$sTemp = iconv_mime_encode('Tagada', $sTemp, array('scheme' => 'Q', 'input-charset' => 'UTF-8', 'output-charset' => 'UTF-8'));
|
||||
return preg_replace('/^Tagada: /', '', $sTemp);
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
@@ -90,7 +90,7 @@ class Event extends DBObject implements iDisplay
|
||||
|
||||
public static function GetUIPage()
|
||||
{
|
||||
return '../pages/UI.php';
|
||||
return 'UI.php';
|
||||
}
|
||||
|
||||
function DisplayDetails(WebPage $oPage, $bEditMode = false)
|
||||
@@ -103,7 +103,7 @@ class Event extends DBObject implements iDisplay
|
||||
$this->DisplayBareProperties($oPage, $bEditMode);
|
||||
}
|
||||
|
||||
function DisplayBareProperties(WebPage $oPage, $bEditMode = false)
|
||||
function DisplayBareProperties(WebPage $oPage, $bEditMode = false, $sPrefix = '', $aExtraParams = array())
|
||||
{
|
||||
if ($bEditMode) return; // Not editable
|
||||
|
||||
@@ -174,7 +174,7 @@ class EventNotificationEmail extends EventNotification
|
||||
MetaModel::Init_AddAttribute(new AttributeText("bcc", array("allowed_values"=>null, "sql"=>"bcc", "default_value"=>null, "is_null_allowed"=>true, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeText("from", array("allowed_values"=>null, "sql"=>"from", "default_value"=>null, "is_null_allowed"=>true, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeText("subject", array("allowed_values"=>null, "sql"=>"subject", "default_value"=>null, "is_null_allowed"=>true, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeText("body", array("allowed_values"=>null, "sql"=>"body", "default_value"=>null, "is_null_allowed"=>true, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeHTML("body", array("allowed_values"=>null, "sql"=>"body", "default_value"=>null, "is_null_allowed"=>true, "depends_on"=>array())));
|
||||
|
||||
// Display lists
|
||||
MetaModel::Init_SetZListItems('details', array('date', 'userinfo', 'message', 'trigger_id', 'action_id', 'object_id', 'to', 'cc', 'bcc', 'from', 'subject', 'body')); // Attributes to be displayed for the complete details
|
||||
|
||||
@@ -36,11 +36,16 @@ abstract class Expression
|
||||
// recursive rendering (aArgs used as input by default, or used as output if bRetrofitParams set to True
|
||||
abstract public function Render(&$aArgs = null, $bRetrofitParams = false);
|
||||
|
||||
abstract public function ApplyParameters($aArgs);
|
||||
|
||||
// recursively builds an array of class => fieldname
|
||||
abstract public function ListRequiredFields();
|
||||
|
||||
abstract public function IsTrue();
|
||||
|
||||
|
||||
// recursively builds an array of [classAlias][fieldName] => value
|
||||
abstract public function ListConstantFields();
|
||||
|
||||
public function RequiresField($sClass, $sFieldName)
|
||||
{
|
||||
// #@# todo - optimize : this is called quite often when building a single query !
|
||||
@@ -84,6 +89,8 @@ abstract class Expression
|
||||
{
|
||||
return new BinaryExpression($this, 'OR', $oExpr);
|
||||
}
|
||||
|
||||
abstract public function RenameParam($sOldName, $sNewName);
|
||||
}
|
||||
|
||||
class SQLExpression extends Expression
|
||||
@@ -106,6 +113,10 @@ class SQLExpression extends Expression
|
||||
return $this->m_sSQL;
|
||||
}
|
||||
|
||||
public function ApplyParameters($aArgs)
|
||||
{
|
||||
}
|
||||
|
||||
public function GetUnresolvedFields($sAlias, &$aUnresolved)
|
||||
{
|
||||
}
|
||||
@@ -119,6 +130,16 @@ class SQLExpression extends Expression
|
||||
{
|
||||
return array();
|
||||
}
|
||||
|
||||
public function ListConstantFields()
|
||||
{
|
||||
return array();
|
||||
}
|
||||
|
||||
public function RenameParam($sOldName, $sNewName)
|
||||
{
|
||||
// Do nothing, since there is nothing to rename
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -157,11 +178,11 @@ class BinaryExpression extends Expression
|
||||
// return true if we are certain that it will be true
|
||||
if ($this->m_sOperator == 'AND')
|
||||
{
|
||||
if ($this->m_oLeftExpr->IsTrue() && $this->m_oLeftExpr->IsTrue()) return true;
|
||||
if ($this->m_oLeftExpr->IsTrue() && $this->m_oRightExpr->IsTrue()) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
public function GetLeftExpr()
|
||||
{
|
||||
return $this->m_oLeftExpr;
|
||||
@@ -185,7 +206,27 @@ class BinaryExpression extends Expression
|
||||
$sRight = $this->GetRightExpr()->Render($aArgs, $bRetrofitParams);
|
||||
return "($sLeft $sOperator $sRight)";
|
||||
}
|
||||
|
||||
|
||||
public function ApplyParameters($aArgs)
|
||||
{
|
||||
if ($this->m_oLeftExpr instanceof VariableExpression)
|
||||
{
|
||||
$this->m_oLeftExpr = $this->m_oLeftExpr->GetAsScalar($aArgs);
|
||||
}
|
||||
else //if ($this->m_oLeftExpr instanceof Expression)
|
||||
{
|
||||
$this->m_oLeftExpr->ApplyParameters($aArgs);
|
||||
}
|
||||
if ($this->m_oRightExpr instanceof VariableExpression)
|
||||
{
|
||||
$this->m_oRightExpr = $this->m_oRightExpr->GetAsScalar($aArgs);
|
||||
}
|
||||
else //if ($this->m_oRightExpr instanceof Expression)
|
||||
{
|
||||
$this->m_oRightExpr->ApplyParameters($aArgs);
|
||||
}
|
||||
}
|
||||
|
||||
public function GetUnresolvedFields($sAlias, &$aUnresolved)
|
||||
{
|
||||
$this->GetLeftExpr()->GetUnresolvedFields($sAlias, $aUnresolved);
|
||||
@@ -205,6 +246,50 @@ class BinaryExpression extends Expression
|
||||
$aRight = $this->GetRightExpr()->ListRequiredFields();
|
||||
return array_merge($aLeft, $aRight);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* List all constant expression of the form <field> = <scalar> or <field> = :<variable>
|
||||
* Could be extended to support <field> = <function><constant_expression>
|
||||
*/
|
||||
public function ListConstantFields()
|
||||
{
|
||||
$aResult = array();
|
||||
if ($this->m_sOperator == '=')
|
||||
{
|
||||
if (($this->m_oLeftExpr instanceof FieldExpression) && ($this->m_oRightExpr instanceof ScalarExpression))
|
||||
{
|
||||
$aResult[$this->m_oLeftExpr->GetParent()][$this->m_oLeftExpr->GetName()] = $this->m_oRightExpr;
|
||||
}
|
||||
else if (($this->m_oRightExpr instanceof FieldExpression) && ($this->m_oLeftExpr instanceof ScalarExpression))
|
||||
{
|
||||
$aResult[$this->m_oRightExpr->GetParent()][$this->m_oRightExpr->GetName()] = $this->m_oLeftExpr;
|
||||
}
|
||||
else if (($this->m_oLeftExpr instanceof FieldExpression) && ($this->m_oRightExpr instanceof VariableExpression))
|
||||
{
|
||||
$aResult[$this->m_oLeftExpr->GetParent()][$this->m_oLeftExpr->GetName()] = $this->m_oRightExpr;
|
||||
}
|
||||
else if (($this->m_oRightExpr instanceof FieldExpression) && ($this->m_oLeftExpr instanceof VariableExpression))
|
||||
{
|
||||
$aResult[$this->m_oRightExpr->GetParent()][$this->m_oRightExpr->GetName()] = $this->m_oLeftExpr;
|
||||
}
|
||||
else
|
||||
{
|
||||
$aResult = array_merge($this->m_oRightExpr->ListConstantFields(), $this->m_oLeftExpr->ListConstantFields()) ;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$aResult = array_merge($this->m_oRightExpr->ListConstantFields(), $this->m_oLeftExpr->ListConstantFields()) ;
|
||||
}
|
||||
return $aResult;
|
||||
}
|
||||
|
||||
public function RenameParam($sOldName, $sNewName)
|
||||
{
|
||||
$this->GetLeftExpr()->RenameParam($sOldName, $sNewName);
|
||||
$this->GetRightExpr()->RenameParam($sOldName, $sNewName);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -231,18 +316,13 @@ class UnaryExpression extends Expression
|
||||
// recursive rendering
|
||||
public function Render(&$aArgs = null, $bRetrofitParams = false)
|
||||
{
|
||||
if ($bRetrofitParams)
|
||||
{
|
||||
$iParamIndex = count($aArgs) + 1; // 1-based indexation
|
||||
$aArgs['param'.$iParamIndex] = $this->m_value;
|
||||
return ':param'.$iParamIndex;
|
||||
}
|
||||
else
|
||||
{
|
||||
return CMDBSource::Quote($this->m_value);
|
||||
}
|
||||
return CMDBSource::Quote($this->m_value);
|
||||
}
|
||||
|
||||
public function ApplyParameters($aArgs)
|
||||
{
|
||||
}
|
||||
|
||||
public function GetUnresolvedFields($sAlias, &$aUnresolved)
|
||||
{
|
||||
}
|
||||
@@ -256,6 +336,17 @@ class UnaryExpression extends Expression
|
||||
{
|
||||
return array();
|
||||
}
|
||||
|
||||
public function ListConstantFields()
|
||||
{
|
||||
return array();
|
||||
}
|
||||
|
||||
public function RenameParam($sOldName, $sNewName)
|
||||
{
|
||||
// Do nothing
|
||||
// really ? what about :param{$iParamIndex} ??
|
||||
}
|
||||
}
|
||||
|
||||
class ScalarExpression extends UnaryExpression
|
||||
@@ -421,7 +512,7 @@ class VariableExpression extends UnaryExpression
|
||||
}
|
||||
elseif ($bRetrofitParams)
|
||||
{
|
||||
//$aArgs[$this->m_sName] = null;
|
||||
$aArgs[$this->m_sName] = null;
|
||||
return ':'.$this->m_sName;
|
||||
}
|
||||
else
|
||||
@@ -429,6 +520,28 @@ class VariableExpression extends UnaryExpression
|
||||
throw new MissingQueryArgument('Missing query argument', array('expecting'=>$this->m_sName, 'available'=>$aArgs));
|
||||
}
|
||||
}
|
||||
|
||||
public function RenameParam($sOldName, $sNewName)
|
||||
{
|
||||
if ($this->m_sName == $sOldName)
|
||||
{
|
||||
$this->m_sName = $sNewName;
|
||||
}
|
||||
}
|
||||
|
||||
public function GetAsScalar($aArgs)
|
||||
{
|
||||
$value = '';
|
||||
if (array_key_exists($this->m_sName, $aArgs))
|
||||
{
|
||||
$value = $aArgs[$this->m_sName];
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new MissingQueryArgument('Missing query argument', array('expecting'=>$this->m_sName, 'available'=>array_keys($aArgs)));
|
||||
}
|
||||
return new ScalarExpression($value);
|
||||
}
|
||||
}
|
||||
|
||||
// Temporary, until we implement functions and expression casting!
|
||||
@@ -474,6 +587,22 @@ class ListExpression extends Expression
|
||||
return '('.implode(', ', $aRes).')';
|
||||
}
|
||||
|
||||
public function ApplyParameters($aArgs)
|
||||
{
|
||||
$aRes = array();
|
||||
foreach ($this->m_aExpressions as $idx => $oExpr)
|
||||
{
|
||||
if ($oExpr instanceof VariableExpression)
|
||||
{
|
||||
$this->m_aExpressions[$idx] = $oExpr->GetAsScalar();
|
||||
}
|
||||
else
|
||||
{
|
||||
$oExpr->ApplyParameters($aArgs);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function GetUnresolvedFields($sAlias, &$aUnresolved)
|
||||
{
|
||||
foreach ($this->m_aExpressions as $oExpr)
|
||||
@@ -501,6 +630,25 @@ class ListExpression extends Expression
|
||||
}
|
||||
return $aRes;
|
||||
}
|
||||
|
||||
public function ListConstantFields()
|
||||
{
|
||||
$aRes = array();
|
||||
foreach ($this->m_aExpressions as $oExpr)
|
||||
{
|
||||
$aRes = array_merge($aRes, $oExpr->ListConstantFields());
|
||||
}
|
||||
return $aRes;
|
||||
}
|
||||
|
||||
public function RenameParam($sOldName, $sNewName)
|
||||
{
|
||||
$aRes = array();
|
||||
foreach ($this->m_aExpressions as $key => $oExpr)
|
||||
{
|
||||
$this->m_aExpressions[$key] = $oExpr->RenameParam($sOldName, $sNewName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -542,6 +690,22 @@ class FunctionExpression extends Expression
|
||||
return $this->m_sVerb.'('.implode(', ', $aRes).')';
|
||||
}
|
||||
|
||||
public function ApplyParameters($aArgs)
|
||||
{
|
||||
$aRes = array();
|
||||
foreach ($this->m_aArgs as $idx => $oExpr)
|
||||
{
|
||||
if ($oExpr instanceof VariableExpression)
|
||||
{
|
||||
$this->m_aArgs[$idx] = $oExpr->GetAsScalar($aArgs);
|
||||
}
|
||||
else
|
||||
{
|
||||
$oExpr->ApplyParameters($aArgs);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function GetUnresolvedFields($sAlias, &$aUnresolved)
|
||||
{
|
||||
foreach ($this->m_aArgs as $oExpr)
|
||||
@@ -569,6 +733,24 @@ class FunctionExpression extends Expression
|
||||
}
|
||||
return $aRes;
|
||||
}
|
||||
|
||||
public function ListConstantFields()
|
||||
{
|
||||
$aRes = array();
|
||||
foreach ($this->m_aArgs as $oExpr)
|
||||
{
|
||||
$aRes = array_merge($aRes, $oExpr->ListConstantFields());
|
||||
}
|
||||
return $aRes;
|
||||
}
|
||||
|
||||
public function RenameParam($sOldName, $sNewName)
|
||||
{
|
||||
foreach ($this->m_aArgs as $key => $oExpr)
|
||||
{
|
||||
$this->m_aArgs[$key] = $oExpr->RenameParam($sOldName, $sNewName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class IntervalExpression extends Expression
|
||||
@@ -604,6 +786,18 @@ class IntervalExpression extends Expression
|
||||
return 'INTERVAL '.$this->m_oValue->Render($aArgs, $bRetrofitParams).' '.$this->m_sUnit;
|
||||
}
|
||||
|
||||
public function ApplyParameters($aArgs)
|
||||
{
|
||||
if ($this->m_oValue instanceof VariableExpression)
|
||||
{
|
||||
$this->m_oValue = $this->m_oValue->GetAsScalar($aArgs);
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->m_oValue->ApplyParameters($aArgs);
|
||||
}
|
||||
}
|
||||
|
||||
public function GetUnresolvedFields($sAlias, &$aUnresolved)
|
||||
{
|
||||
$this->m_oValue->GetUnresolvedFields($sAlias, $aUnresolved);
|
||||
@@ -618,6 +812,16 @@ class IntervalExpression extends Expression
|
||||
{
|
||||
return array();
|
||||
}
|
||||
|
||||
public function ListConstantFields()
|
||||
{
|
||||
return array();
|
||||
}
|
||||
|
||||
public function RenameParam($sOldName, $sNewName)
|
||||
{
|
||||
$this->m_oValue->RenameParam($sOldName, $sNewName);
|
||||
}
|
||||
}
|
||||
|
||||
class CharConcatExpression extends Expression
|
||||
@@ -653,6 +857,22 @@ class CharConcatExpression extends Expression
|
||||
return "CAST(CONCAT(".implode(', ', $aRes).") AS CHAR)";
|
||||
}
|
||||
|
||||
public function ApplyParameters($aArgs)
|
||||
{
|
||||
$aRes = array();
|
||||
foreach ($this->m_aExpressions as $idx => $oExpr)
|
||||
{
|
||||
if ($oExpr instanceof VariableExpression)
|
||||
{
|
||||
$this->m_aExpressions[$idx] = $oExpr->GetAsScalar();
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->m_aExpressions->ApplyParameters($aArgs);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function GetUnresolvedFields($sAlias, &$aUnresolved)
|
||||
{
|
||||
foreach ($this->m_aExpressions as $oExpr)
|
||||
@@ -680,6 +900,24 @@ class CharConcatExpression extends Expression
|
||||
}
|
||||
return $aRes;
|
||||
}
|
||||
|
||||
public function ListConstantFields()
|
||||
{
|
||||
$aRes = array();
|
||||
foreach ($this->m_aExpressions as $oExpr)
|
||||
{
|
||||
$aRes = array_merge($aRes, $oExpr->ListConstantFields());
|
||||
}
|
||||
return $aRes;
|
||||
}
|
||||
|
||||
public function RenameParam($sOldName, $sNewName)
|
||||
{
|
||||
foreach ($this->m_aExpressions as $key => $oExpr)
|
||||
{
|
||||
$this->m_aExpressions[$key] = $oExpr->RenameParam($sOldName, $sNewName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -778,6 +1016,19 @@ class QueryBuilderExpressions
|
||||
$this->m_aJoinFields[$index] = $oExpression->Translate($aTranslationData, $bMatchAll, $bMarkFieldsAsResolved);
|
||||
}
|
||||
}
|
||||
|
||||
public function RenameParam($sOldName, $sNewName)
|
||||
{
|
||||
$this->m_oConditionExpr->RenameParam($sOldName, $sNewName);
|
||||
foreach($this->m_aSelectExpr as $sColAlias => $oExpr)
|
||||
{
|
||||
$this->m_aSelectExpr[$sColAlias] = $oExpr->RenameParam($sOldName, $sNewName);
|
||||
}
|
||||
foreach($this->m_aJoinFields as $index => $oExpression)
|
||||
{
|
||||
$this->m_aJoinFields[$index] = $oExpression->RenameParam($sOldName, $sNewName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
|
||||
@@ -191,6 +191,16 @@ class ExecutionKPI
|
||||
return $output[1] * 1024;
|
||||
}
|
||||
}
|
||||
|
||||
static public function memory_get_peak_usage($bRealUsage = false)
|
||||
{
|
||||
if (function_exists('memory_get_peak_usage'))
|
||||
{
|
||||
return memory_get_peak_usage($bRealUsage);
|
||||
}
|
||||
// PHP > 5.2.1 - this verb depends on a compilation option
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
class ApplicationStartupKPI extends ExecutionKPI
|
||||
|
||||
4
core/oql/build.bash
Executable file
@@ -0,0 +1,4 @@
|
||||
#!/bin/bash
|
||||
php /usr/share/php/PHP/LexerGenerator/cli.php oql-lexer.plex
|
||||
php /usr/share/php/PHP/ParserGenerator/cli.php oql-parser.y
|
||||
|
||||
@@ -3,5 +3,6 @@
|
||||
# since they are used solely for constructing other files during the build process
|
||||
#
|
||||
build.cmd
|
||||
build.bash
|
||||
oql-lexer.plex
|
||||
oql-parser.y
|
||||
oql-parser.y
|
||||
|
||||
@@ -104,155 +104,163 @@ class OQLLexerRaw
|
||||
if ($this->count >= strlen($this->data)) {
|
||||
return false; // end of input
|
||||
}
|
||||
do {
|
||||
$rules = array(
|
||||
'/^[ \t\n\r]+/',
|
||||
'/^SELECT/',
|
||||
'/^FROM/',
|
||||
'/^AS/',
|
||||
'/^WHERE/',
|
||||
'/^JOIN/',
|
||||
'/^ON/',
|
||||
'/^\//',
|
||||
'/^\\*/',
|
||||
'/^\\+/',
|
||||
'/^-/',
|
||||
'/^AND/',
|
||||
'/^OR/',
|
||||
'/^,/',
|
||||
'/^\\(/',
|
||||
'/^\\)/',
|
||||
'/^REGEXP/',
|
||||
'/^=/',
|
||||
'/^!=/',
|
||||
'/^>/',
|
||||
'/^</',
|
||||
'/^>=/',
|
||||
'/^<=/',
|
||||
'/^LIKE/',
|
||||
'/^NOT LIKE/',
|
||||
'/^IN/',
|
||||
'/^NOT IN/',
|
||||
'/^INTERVAL/',
|
||||
'/^IF/',
|
||||
'/^ELT/',
|
||||
'/^COALESCE/',
|
||||
'/^ISNULL/',
|
||||
'/^CONCAT/',
|
||||
'/^SUBSTR/',
|
||||
'/^TRIM/',
|
||||
'/^DATE/',
|
||||
'/^DATE_FORMAT/',
|
||||
'/^CURRENT_DATE/',
|
||||
'/^NOW/',
|
||||
'/^TIME/',
|
||||
'/^TO_DAYS/',
|
||||
'/^FROM_DAYS/',
|
||||
'/^YEAR/',
|
||||
'/^MONTH/',
|
||||
'/^DAY/',
|
||||
'/^HOUR/',
|
||||
'/^MINUTE/',
|
||||
'/^SECOND/',
|
||||
'/^DATE_ADD/',
|
||||
'/^DATE_SUB/',
|
||||
'/^ROUND/',
|
||||
'/^FLOOR/',
|
||||
'/^INET_ATON/',
|
||||
'/^INET_NTOA/',
|
||||
'/^[0-9]+|0x[0-9a-fA-F]+/',
|
||||
'/^\"([^\\\\\"]|\\\\\"|\\\\\\\\)*\"|'.chr(94).chr(39).'([^\\\\'.chr(39).']|\\\\'.chr(39).'|\\\\\\\\)*'.chr(39).'/',
|
||||
'/^([_a-zA-Z][_a-zA-Z0-9]*|`[^`]+`)/',
|
||||
'/^:([_a-zA-Z][_a-zA-Z0-9]*->[_a-zA-Z][_a-zA-Z0-9]*|[_a-zA-Z][_a-zA-Z0-9]*)/',
|
||||
'/^\\./',
|
||||
);
|
||||
$match = false;
|
||||
foreach ($rules as $index => $rule) {
|
||||
if (preg_match($rule, substr($this->data, $this->count), $yymatches)) {
|
||||
if ($match) {
|
||||
if (strlen($yymatches[0]) > strlen($match[0][0])) {
|
||||
$match = array($yymatches, $index); // matches, token
|
||||
}
|
||||
} else {
|
||||
$match = array($yymatches, $index);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!$match) {
|
||||
throw new Exception('Unexpected input at line' . $this->line .
|
||||
': ' . $this->data[$this->count]);
|
||||
}
|
||||
$this->token = $match[1];
|
||||
$this->value = $match[0][0];
|
||||
$yysubmatches = $match[0];
|
||||
array_shift($yysubmatches);
|
||||
if (!$yysubmatches) {
|
||||
$yysubmatches = array();
|
||||
}
|
||||
$r = $this->{'yy_r1_' . $this->token}($yysubmatches);
|
||||
if ($r === null) {
|
||||
$this->count += strlen($this->value);
|
||||
$this->line += substr_count($this->value, "\n");
|
||||
// accept this token
|
||||
return true;
|
||||
} elseif ($r === true) {
|
||||
// we have changed state
|
||||
// process this token in the new state
|
||||
return $this->yylex();
|
||||
} elseif ($r === false) {
|
||||
$this->count += strlen($this->value);
|
||||
$this->line += substr_count($this->value, "\n");
|
||||
if ($this->count >= strlen($this->data)) {
|
||||
return false; // end of input
|
||||
}
|
||||
// skip this token
|
||||
continue;
|
||||
} else {
|
||||
$yy_yymore_patterns = array_slice($rules, $this->token, true);
|
||||
// yymore is needed
|
||||
do {
|
||||
if (!isset($yy_yymore_patterns[$this->token])) {
|
||||
throw new Exception('cannot do yymore for the last token');
|
||||
}
|
||||
$match = false;
|
||||
foreach ($yy_yymore_patterns[$this->token] as $index => $rule) {
|
||||
if (preg_match('/' . $rule . '/',
|
||||
substr($this->data, $this->count), $yymatches)) {
|
||||
$yymatches = array_filter($yymatches, 'strlen'); // remove empty sub-patterns
|
||||
if ($match) {
|
||||
if (strlen($yymatches[0]) > strlen($match[0][0])) {
|
||||
$match = array($yymatches, $index); // matches, token
|
||||
}
|
||||
} else {
|
||||
$match = array($yymatches, $index);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!$match) {
|
||||
throw new Exception('Unexpected input at line' . $this->line .
|
||||
': ' . $this->data[$this->count]);
|
||||
}
|
||||
$this->token = $match[1];
|
||||
$this->value = $match[0][0];
|
||||
$yysubmatches = $match[0];
|
||||
array_shift($yysubmatches);
|
||||
if (!$yysubmatches) {
|
||||
$yysubmatches = array();
|
||||
}
|
||||
$this->line = substr_count($this->value, "\n");
|
||||
$r = $this->{'yy_r1_' . $this->token}();
|
||||
} while ($r !== null || !$r);
|
||||
if ($r === true) {
|
||||
// we have changed state
|
||||
// process this token in the new state
|
||||
return $this->yylex();
|
||||
} else {
|
||||
// accept
|
||||
$this->count += strlen($this->value);
|
||||
$this->line += substr_count($this->value, "\n");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
do {
|
||||
$rules = array(
|
||||
'/\G[ \t\n\r]+/ ',
|
||||
'/\GSELECT/ ',
|
||||
'/\GFROM/ ',
|
||||
'/\GAS/ ',
|
||||
'/\GWHERE/ ',
|
||||
'/\GJOIN/ ',
|
||||
'/\GON/ ',
|
||||
'/\G\// ',
|
||||
'/\G\\*/ ',
|
||||
'/\G\\+/ ',
|
||||
'/\G-/ ',
|
||||
'/\GAND/ ',
|
||||
'/\GOR/ ',
|
||||
'/\G,/ ',
|
||||
'/\G\\(/ ',
|
||||
'/\G\\)/ ',
|
||||
'/\GREGEXP/ ',
|
||||
'/\G=/ ',
|
||||
'/\G!=/ ',
|
||||
'/\G>/ ',
|
||||
'/\G</ ',
|
||||
'/\G>=/ ',
|
||||
'/\G<=/ ',
|
||||
'/\GLIKE/ ',
|
||||
'/\GNOT LIKE/ ',
|
||||
'/\GIN/ ',
|
||||
'/\GNOT IN/ ',
|
||||
'/\GINTERVAL/ ',
|
||||
'/\GIF/ ',
|
||||
'/\GELT/ ',
|
||||
'/\GCOALESCE/ ',
|
||||
'/\GISNULL/ ',
|
||||
'/\GCONCAT/ ',
|
||||
'/\GSUBSTR/ ',
|
||||
'/\GTRIM/ ',
|
||||
'/\GDATE/ ',
|
||||
'/\GDATE_FORMAT/ ',
|
||||
'/\GCURRENT_DATE/ ',
|
||||
'/\GNOW/ ',
|
||||
'/\GTIME/ ',
|
||||
'/\GTO_DAYS/ ',
|
||||
'/\GFROM_DAYS/ ',
|
||||
'/\GYEAR/ ',
|
||||
'/\GMONTH/ ',
|
||||
'/\GDAY/ ',
|
||||
'/\GHOUR/ ',
|
||||
'/\GMINUTE/ ',
|
||||
'/\GSECOND/ ',
|
||||
'/\GDATE_ADD/ ',
|
||||
'/\GDATE_SUB/ ',
|
||||
'/\GROUND/ ',
|
||||
'/\GFLOOR/ ',
|
||||
'/\GINET_ATON/ ',
|
||||
'/\GINET_NTOA/ ',
|
||||
'/\GBELOW/ ',
|
||||
'/\GBELOW STRICT/ ',
|
||||
'/\GNOT BELOW/ ',
|
||||
'/\GNOT BELOW STRICT/ ',
|
||||
'/\GABOVE/ ',
|
||||
'/\GABOVE STRICT/ ',
|
||||
'/\GNOT ABOVE/ ',
|
||||
'/\GNOT ABOVE STRICT/ ',
|
||||
'/\G(0x[0-9a-fA-F]+|[0-9]+)/ ',
|
||||
'/\G\"([^\\\\\"]|\\\\\"|\\\\\\\\)*\"|'.chr(94).chr(39).'([^\\\\'.chr(39).']|\\\\'.chr(39).'|\\\\\\\\)*'.chr(39).'/ ',
|
||||
'/\G([_a-zA-Z][_a-zA-Z0-9]*|`[^`]+`)/ ',
|
||||
'/\G:([_a-zA-Z][_a-zA-Z0-9]*->[_a-zA-Z][_a-zA-Z0-9]*|[_a-zA-Z][_a-zA-Z0-9]*)/ ',
|
||||
'/\G\\./ ',
|
||||
);
|
||||
$match = false;
|
||||
foreach ($rules as $index => $rule) {
|
||||
if (preg_match($rule, substr($this->data, $this->count), $yymatches)) {
|
||||
if ($match) {
|
||||
if (strlen($yymatches[0]) > strlen($match[0][0])) {
|
||||
$match = array($yymatches, $index); // matches, token
|
||||
}
|
||||
} else {
|
||||
$match = array($yymatches, $index);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!$match) {
|
||||
throw new Exception('Unexpected input at line ' . $this->line .
|
||||
': ' . $this->data[$this->count]);
|
||||
}
|
||||
$this->token = $match[1];
|
||||
$this->value = $match[0][0];
|
||||
$yysubmatches = $match[0];
|
||||
array_shift($yysubmatches);
|
||||
if (!$yysubmatches) {
|
||||
$yysubmatches = array();
|
||||
}
|
||||
$r = $this->{'yy_r1_' . $this->token}($yysubmatches);
|
||||
if ($r === null) {
|
||||
$this->count += strlen($this->value);
|
||||
$this->line += substr_count($this->value, "\n");
|
||||
// accept this token
|
||||
return true;
|
||||
} elseif ($r === true) {
|
||||
// we have changed state
|
||||
// process this token in the new state
|
||||
return $this->yylex();
|
||||
} elseif ($r === false) {
|
||||
$this->count += strlen($this->value);
|
||||
$this->line += substr_count($this->value, "\n");
|
||||
if ($this->count >= strlen($this->data)) {
|
||||
return false; // end of input
|
||||
}
|
||||
// skip this token
|
||||
continue;
|
||||
} else {
|
||||
$yy_yymore_patterns = array_slice($rules, $this->token, true);
|
||||
// yymore is needed
|
||||
do {
|
||||
if (!isset($yy_yymore_patterns[$this->token])) {
|
||||
throw new Exception('cannot do yymore for the last token');
|
||||
}
|
||||
$match = false;
|
||||
foreach ($yy_yymore_patterns[$this->token] as $index => $rule) {
|
||||
if (preg_match('/' . $rule . '/',
|
||||
$this->data, $yymatches, null, $this->count)) {
|
||||
$yymatches = array_filter($yymatches, 'strlen'); // remove empty sub-patterns
|
||||
if ($match) {
|
||||
if (strlen($yymatches[0]) > strlen($match[0][0])) {
|
||||
$match = array($yymatches, $index); // matches, token
|
||||
}
|
||||
} else {
|
||||
$match = array($yymatches, $index);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!$match) {
|
||||
throw new Exception('Unexpected input at line ' . $this->line .
|
||||
': ' . $this->data[$this->count]);
|
||||
}
|
||||
$this->token = $match[1];
|
||||
$this->value = $match[0][0];
|
||||
$yysubmatches = $match[0];
|
||||
array_shift($yysubmatches);
|
||||
if (!$yysubmatches) {
|
||||
$yysubmatches = array();
|
||||
}
|
||||
$this->line = substr_count($this->value, "\n");
|
||||
$r = $this->{'yy_r1_' . $this->token}();
|
||||
} while ($r !== null || !$r);
|
||||
if ($r === true) {
|
||||
// we have changed state
|
||||
// process this token in the new state
|
||||
return $this->yylex();
|
||||
} else {
|
||||
// accept
|
||||
$this->count += strlen($this->value);
|
||||
$this->line += substr_count($this->value, "\n");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
} while (true);
|
||||
|
||||
} // end function
|
||||
@@ -530,24 +538,64 @@ class OQLLexerRaw
|
||||
function yy_r1_54($yy_subpatterns)
|
||||
{
|
||||
|
||||
$this->token = OQLParser::NUMVAL;
|
||||
$this->token = OQLParser::BELOW;
|
||||
}
|
||||
function yy_r1_55($yy_subpatterns)
|
||||
{
|
||||
|
||||
$this->token = OQLParser::STRVAL;
|
||||
$this->token = OQLParser::BELOW_STRICT;
|
||||
}
|
||||
function yy_r1_56($yy_subpatterns)
|
||||
{
|
||||
|
||||
$this->token = OQLParser::NAME;
|
||||
$this->token = OQLParser::NOT_BELOW;
|
||||
}
|
||||
function yy_r1_57($yy_subpatterns)
|
||||
{
|
||||
|
||||
$this->token = OQLParser::VARNAME;
|
||||
$this->token = OQLParser::NOT_BELOW_STRICT;
|
||||
}
|
||||
function yy_r1_58($yy_subpatterns)
|
||||
{
|
||||
|
||||
$this->token = OQLParser::ABOVE;
|
||||
}
|
||||
function yy_r1_59($yy_subpatterns)
|
||||
{
|
||||
|
||||
$this->token = OQLParser::ABOVE_STRICT;
|
||||
}
|
||||
function yy_r1_60($yy_subpatterns)
|
||||
{
|
||||
|
||||
$this->token = OQLParser::NOT_ABOVE;
|
||||
}
|
||||
function yy_r1_61($yy_subpatterns)
|
||||
{
|
||||
|
||||
$this->token = OQLParser::NOT_ABOVE_STRICT;
|
||||
}
|
||||
function yy_r1_62($yy_subpatterns)
|
||||
{
|
||||
|
||||
$this->token = OQLParser::NUMVAL;
|
||||
}
|
||||
function yy_r1_63($yy_subpatterns)
|
||||
{
|
||||
|
||||
$this->token = OQLParser::STRVAL;
|
||||
}
|
||||
function yy_r1_64($yy_subpatterns)
|
||||
{
|
||||
|
||||
$this->token = OQLParser::NAME;
|
||||
}
|
||||
function yy_r1_65($yy_subpatterns)
|
||||
{
|
||||
|
||||
$this->token = OQLParser::VARNAME;
|
||||
}
|
||||
function yy_r1_66($yy_subpatterns)
|
||||
{
|
||||
|
||||
$this->token = OQLParser::DOT;
|
||||
|
||||
@@ -132,7 +132,31 @@ f_round = "ROUND"
|
||||
f_floor = "FLOOR"
|
||||
f_inet_aton = "INET_ATON"
|
||||
f_inet_ntoa = "INET_NTOA"
|
||||
numval = /[0-9]+|0x[0-9a-fA-F]+/
|
||||
below = "BELOW"
|
||||
below_strict = "BELOW STRICT"
|
||||
not_below = "NOT BELOW"
|
||||
not_below_strict = "NOT BELOW STRICT"
|
||||
above = "ABOVE"
|
||||
above_strict = "ABOVE STRICT"
|
||||
not_above = "NOT ABOVE"
|
||||
not_above_strict = "NOT ABOVE STRICT"
|
||||
//
|
||||
// WARNING: there seems to be a bug in the Lexer about matching the longest pattern
|
||||
// when there are alternates in the regexp.
|
||||
//
|
||||
// For instance:
|
||||
// numval = /[0-9]+|0x[0-9a-fA-F]+/
|
||||
// Does not work: SELECT Toto WHERE name = 'Text0xCTest' => Fails because 0xC is recongnized as a numval (inside the string) instead of a strval !!
|
||||
//
|
||||
// Inserting a ^ after the alternate (see comment at the top of this file) does not work either
|
||||
// numval = /[0-9]+|'.chr(94).'0x[0-9a-fA-F]+/
|
||||
// SELECT Toto WHERE name = 'Text0xCTest' => works but
|
||||
// SELECT Toto WHERE id = 0xC => does not work, 'xC' is found as a name (apparently 0 is recognized as a numval and the remaining is a name !)
|
||||
//
|
||||
// numval = /([0-9]+|0x[0-9a-fA-F]+)/
|
||||
// Does not work either, the hexadecimal numbers are not matched properly
|
||||
// The following seems to work...
|
||||
numval = /(0x[0-9a-fA-F]+|[0-9]+)/
|
||||
strval = /"([^\\"]|\\"|\\\\)*"|'.chr(94).chr(39).'([^\\'.chr(39).']|\\'.chr(39).'|\\\\)*'.chr(39).'/
|
||||
name = /([_a-zA-Z][_a-zA-Z0-9]*|`[^`]+`)/
|
||||
varname = /:([_a-zA-Z][_a-zA-Z0-9]*->[_a-zA-Z][_a-zA-Z0-9]*|[_a-zA-Z][_a-zA-Z0-9]*)/
|
||||
@@ -302,6 +326,30 @@ f_inet_aton {
|
||||
f_inet_ntoa {
|
||||
$this->token = OQLParser::F_INET_NTOA;
|
||||
}
|
||||
below {
|
||||
$this->token = OQLParser::BELOW;
|
||||
}
|
||||
below_strict {
|
||||
$this->token = OQLParser::BELOW_STRICT;
|
||||
}
|
||||
not_below {
|
||||
$this->token = OQLParser::NOT_BELOW;
|
||||
}
|
||||
not_below_strict {
|
||||
$this->token = OQLParser::NOT_BELOW_STRICT;
|
||||
}
|
||||
above {
|
||||
$this->token = OQLParser::ABOVE;
|
||||
}
|
||||
above_strict {
|
||||
$this->token = OQLParser::ABOVE_STRICT;
|
||||
}
|
||||
not_above {
|
||||
$this->token = OQLParser::NOT_ABOVE;
|
||||
}
|
||||
not_above_strict {
|
||||
$this->token = OQLParser::NOT_ABOVE_STRICT;
|
||||
}
|
||||
numval {
|
||||
$this->token = OQLParser::NUMVAL;
|
||||
}
|
||||
|
||||
@@ -78,6 +78,14 @@ join_item(A) ::= JOIN class_name(X) ON join_condition(C).
|
||||
}
|
||||
|
||||
join_condition(A) ::= field_id(X) EQ field_id(Y). { A = new BinaryOqlExpression(X, '=', Y); }
|
||||
join_condition(A) ::= field_id(X) BELOW field_id(Y). { A = new BinaryOqlExpression(X, 'BELOW', Y); }
|
||||
join_condition(A) ::= field_id(X) BELOW_STRICT field_id(Y). { A = new BinaryOqlExpression(X, 'BELOW_STRICT', Y); }
|
||||
join_condition(A) ::= field_id(X) NOT_BELOW field_id(Y). { A = new BinaryOqlExpression(X, 'NOT_BELOW', Y); }
|
||||
join_condition(A) ::= field_id(X) NOT_BELOW_STRICT field_id(Y). { A = new BinaryOqlExpression(X, 'NOT_BELOW_STRICT', Y); }
|
||||
join_condition(A) ::= field_id(X) ABOVE field_id(Y). { A = new BinaryOqlExpression(X, 'ABOVE', Y); }
|
||||
join_condition(A) ::= field_id(X) ABOVE_STRICT field_id(Y). { A = new BinaryOqlExpression(X, 'ABOVE_STRICT', Y); }
|
||||
join_condition(A) ::= field_id(X) NOT_ABOVE field_id(Y). { A = new BinaryOqlExpression(X, 'NOT_ABOVE', Y); }
|
||||
join_condition(A) ::= field_id(X) NOT_ABOVE_STRICT field_id(Y). { A = new BinaryOqlExpression(X, 'NOT_ABOVE_STRICT', Y); }
|
||||
|
||||
condition(A) ::= expression_prio4(X). { A = X; }
|
||||
|
||||
|
||||
@@ -59,6 +59,7 @@ class OqlJoinSpec
|
||||
protected $m_oClassAlias;
|
||||
protected $m_oLeftField;
|
||||
protected $m_oRightField;
|
||||
protected $m_sOperator;
|
||||
|
||||
protected $m_oNextJoinspec;
|
||||
|
||||
@@ -68,6 +69,8 @@ class OqlJoinSpec
|
||||
$this->m_oClassAlias = $oClassAlias;
|
||||
$this->m_oLeftField = $oExpression->GetLeftExpr();
|
||||
$this->m_oRightField = $oExpression->GetRightExpr();
|
||||
$this->m_oRightField = $oExpression->GetRightExpr();
|
||||
$this->m_sOperator = $oExpression->GetOperator();
|
||||
}
|
||||
|
||||
public function GetClass()
|
||||
@@ -96,6 +99,10 @@ class OqlJoinSpec
|
||||
{
|
||||
return $this->m_oRightField;
|
||||
}
|
||||
public function GetOperator()
|
||||
{
|
||||
return $this->m_sOperator;
|
||||
}
|
||||
}
|
||||
|
||||
class BinaryOqlExpression extends BinaryExpression
|
||||
|
||||
@@ -79,7 +79,29 @@ class ormCaseLog {
|
||||
$iPos += $this->m_aIndex[$index]['text_length'];
|
||||
|
||||
$sEntry = '<div class="caselog_header'.$sOpen.'">';
|
||||
$sEntry .= sprintf(Dict::S('UI:CaseLog:Header_Date_UserName'), $this->m_aIndex[$index]['date']->format(Dict::S('UI:CaseLog:DateFormat')), $this->m_aIndex[$index]['user_name']);
|
||||
// Workaround: PHP < 5.3 cannot unserialize correctly DateTime objects,
|
||||
// therefore we have changed the format. To preserve the compatibility with existing
|
||||
// installations of iTop, both format are allowed:
|
||||
// the 'date' item is either a DateTime object, or a unix timestamp
|
||||
if (is_int($this->m_aIndex[$index]['date']))
|
||||
{
|
||||
// Unix timestamp
|
||||
$sDate = date(Dict::S('UI:CaseLog:DateFormat'), $this->m_aIndex[$index]['date']);
|
||||
}
|
||||
elseif (is_object($this->m_aIndex[$index]['date']))
|
||||
{
|
||||
if (version_compare(phpversion(), '5.3.0', '>='))
|
||||
{
|
||||
// DateTime
|
||||
$sDate = $this->m_aIndex[$index]['date']->format(Dict::S('UI:CaseLog:DateFormat'));
|
||||
}
|
||||
else
|
||||
{
|
||||
// No Warning... but the date is unknown
|
||||
$sDate = '';
|
||||
}
|
||||
}
|
||||
$sEntry .= sprintf(Dict::S('UI:CaseLog:Header_Date_UserName'), $sDate, $this->m_aIndex[$index]['user_name']);
|
||||
$sEntry .= '</div>';
|
||||
$sEntry .= '<div class="caselog_entry"'.$sDisplay.'>';
|
||||
$sEntry .= $sTextEntry;
|
||||
@@ -131,17 +153,26 @@ class ormCaseLog {
|
||||
* Add a new entry to the log and updates the internal index
|
||||
* @param $sText string The text of the new entry
|
||||
*/
|
||||
public function AddLogEntry($sText)
|
||||
public function AddLogEntry($sText, $sOnBehalfOf = '')
|
||||
{
|
||||
$sDate = date(Dict::S('UI:CaseLog:DateFormat'));
|
||||
$sSeparator = sprintf(CASELOG_SEPARATOR, $sDate, UserRights::GetUserFriendlyName(), UserRights::GetUserId());
|
||||
if ($sOnBehalfOf == '')
|
||||
{
|
||||
$sOnBehalfOf = UserRights::GetUserFriendlyName();
|
||||
$iUserId = UserRights::GetUserId();
|
||||
}
|
||||
else
|
||||
{
|
||||
$iUserId = null;
|
||||
}
|
||||
$sSeparator = sprintf(CASELOG_SEPARATOR, $sDate, $sOnBehalfOf, $iUserId);
|
||||
$iSepLength = strlen($sSeparator);
|
||||
$iTextlength = strlen($sText);
|
||||
$this->m_sLog = $sSeparator.$sText.$this->m_sLog; // Latest entry printed first
|
||||
$this->m_aIndex[] = array(
|
||||
'user_name' => UserRights::GetUserFriendlyName(),
|
||||
'user_id' => UserRights::GetUserId(),
|
||||
'date' => new DateTime(),
|
||||
'user_name' => $sOnBehalfOf,
|
||||
'user_id' => $iUserId,
|
||||
'date' => time(),
|
||||
'text_length' => $iTextlength,
|
||||
'separator_length' => $iSepLength,
|
||||
);
|
||||
@@ -153,8 +184,7 @@ class ormCaseLog {
|
||||
*/
|
||||
public function GetLatestEntry()
|
||||
{
|
||||
$iLast = count($this->m_aIndex) - 1;
|
||||
$aLastEntry = $this->m_aIndex[$iLast];
|
||||
$aLastEntry = end($this->m_aIndex);
|
||||
$sRes = substr($this->m_sLog, $aLastEntry['separator_length'], $aLastEntry['text_length']);
|
||||
return $sRes;
|
||||
}
|
||||
@@ -165,7 +195,8 @@ class ormCaseLog {
|
||||
*/
|
||||
public function GetLatestEntryIndex()
|
||||
{
|
||||
$iLast = count($this->m_aIndex) - 1;
|
||||
$aKeys = array_keys($this->m_aIndex);
|
||||
$iLast = end($aKeys); // Strict standards: the parameter passed to 'end' must be a variable since it is passed by reference
|
||||
return $iLast;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -105,7 +105,7 @@ class ormDocument
|
||||
*/
|
||||
public function GetDisplayLink($sClass, $Id, $sAttCode)
|
||||
{
|
||||
return "<a href=\"../pages/ajax.render.php?operation=display_document&class=$sClass&id=$Id&field=$sAttCode\" target=\"_blank\" >".$this->GetFileName()."</a>\n";
|
||||
return "<a href=\"".utils::GetAbsoluteUrlAppRoot()."pages/ajax.render.php?operation=display_document&class=$sClass&id=$Id&field=$sAttCode\" target=\"_blank\" >".$this->GetFileName()."</a>\n";
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -114,7 +114,7 @@ class ormDocument
|
||||
*/
|
||||
public function GetDownloadLink($sClass, $Id, $sAttCode)
|
||||
{
|
||||
return "<a href=\"../pages/ajax.render.php?operation=download_document&class=$sClass&id=$Id&field=$sAttCode\">".$this->GetFileName()."</a>\n";
|
||||
return "<a href=\"".utils::GetAbsoluteUrlAppRoot()."pages/ajax.render.php?operation=download_document&class=$sClass&id=$Id&field=$sAttCode\">".$this->GetFileName()."</a>\n";
|
||||
}
|
||||
}
|
||||
?>
|
||||
|
||||
@@ -163,7 +163,6 @@ class SQLQuery
|
||||
// {
|
||||
// throw new CoreException("Unknown field '$sRightField' in table '".$sRightTable."'");
|
||||
// }
|
||||
|
||||
$this->m_aJoinSelects[] = array(
|
||||
"jointype" => $sJoinType,
|
||||
"select" => $oSQLQuery,
|
||||
@@ -172,9 +171,26 @@ class SQLQuery
|
||||
"righttablealias" => $sRightTableAlias
|
||||
);
|
||||
}
|
||||
public function AddInnerJoin($oSQLQuery, $sLeftField, $sRightField, $sRigthtTable = '')
|
||||
public function AddInnerJoin($oSQLQuery, $sLeftField, $sRightField, $sRightTable = '')
|
||||
{
|
||||
$this->AddJoin("inner", $oSQLQuery, $sLeftField, $sRightField, $sRigthtTable);
|
||||
$this->AddJoin("inner", $oSQLQuery, $sLeftField, $sRightField, $sRightTable);
|
||||
}
|
||||
public function AddInnerJoinTree($oSQLQuery, $sLeftFieldLeft, $sLeftFieldRight, $sRightFieldLeft, $sRightFieldRight, $sRightTableAlias = '', $iOperatorCode = TREE_OPERATOR_BELOW)
|
||||
{
|
||||
assert((get_class($oSQLQuery) == __CLASS__) || is_subclass_of($oSQLQuery, __CLASS__));
|
||||
if (empty($sRightTableAlias))
|
||||
{
|
||||
$sRightTableAlias = $oSQLQuery->m_sTableAlias;
|
||||
}
|
||||
$this->m_aJoinSelects[] = array(
|
||||
"jointype" => 'inner_tree',
|
||||
"select" => $oSQLQuery,
|
||||
"leftfield" => $sLeftFieldLeft,
|
||||
"rightfield" => $sLeftFieldRight,
|
||||
"rightfield_left" => $sRightFieldLeft,
|
||||
"rightfield_right" => $sRightFieldRight,
|
||||
"righttablealias" => $sRightTableAlias,
|
||||
"tree_operator" => $iOperatorCode);
|
||||
}
|
||||
public function AddLeftJoin($oSQLQuery, $sLeftField, $sRightField)
|
||||
{
|
||||
@@ -227,7 +243,6 @@ class SQLQuery
|
||||
$aSetValues = array();
|
||||
$aSelectedIdFields = array();
|
||||
$this->privRender($aFrom, $aFields, $oCondition, $aDelTables, $aSetValues, $aSelectedIdFields);
|
||||
|
||||
$sFrom = self::ClauseFrom($aFrom);
|
||||
$sValues = self::ClauseValues($aSetValues);
|
||||
$sWhere = self::ClauseWhere($oCondition, $aArgs);
|
||||
@@ -315,6 +330,7 @@ class SQLQuery
|
||||
$sFrom .= " ".self::ClauseFrom($aJoinInfo["subfrom"]);
|
||||
break;
|
||||
case "inner":
|
||||
case "inner_tree":
|
||||
$sFrom .= " INNER JOIN (`".$aJoinInfo["tablename"]."` AS `$sTableAlias`";
|
||||
$sFrom .= " ".self::ClauseFrom($aJoinInfo["subfrom"]);
|
||||
$sFrom .= ") ON ".$aJoinInfo["joincondition"];
|
||||
@@ -368,12 +384,12 @@ class SQLQuery
|
||||
// Purpose: prepare the query data, once for all
|
||||
private function privRender(&$aFrom, &$aFields, &$oCondition, &$aDelTables, &$aSetValues, &$aSelectedIdFields)
|
||||
{
|
||||
$sTableAlias = $this->privRenderSingleTable($aFrom, $aFields, $aDelTables, $aSetValues, $aSelectedIdFields);
|
||||
$sTableAlias = $this->privRenderSingleTable($aFrom, $aFields, $aDelTables, $aSetValues, $aSelectedIdFields, '', array('jointype' => 'first'));
|
||||
$oCondition = $this->m_oConditionExpr;
|
||||
return $sTableAlias;
|
||||
}
|
||||
|
||||
private function privRenderSingleTable(&$aFrom, &$aFields, &$aDelTables, &$aSetValues, &$aSelectedIdFields, $sJoinType = 'first', $sCallerAlias = '', $sLeftField = '', $sRightField = '', $sRightTableAlias = '')
|
||||
private function privRenderSingleTable(&$aFrom, &$aFields, &$aDelTables, &$aSetValues, &$aSelectedIdFields, $sCallerAlias = '', $aJoinData)
|
||||
{
|
||||
$aActualTableFields = CMDBSource::GetTableFieldsList($this->m_sTable);
|
||||
|
||||
@@ -381,12 +397,15 @@ class SQLQuery
|
||||
|
||||
// Handle the various kinds of join (or first table in the list)
|
||||
//
|
||||
if (empty($sRightTableAlias))
|
||||
if (empty($aJoinData['righttablealias']))
|
||||
{
|
||||
$sRightTableAlias = $this->m_sTableAlias;
|
||||
}
|
||||
$sJoinCond = "`$sCallerAlias`.`$sLeftField` = `$sRightTableAlias`.`$sRightField`";
|
||||
switch ($sJoinType)
|
||||
else
|
||||
{
|
||||
$sRightTableAlias = $aJoinData['righttablealias'];
|
||||
}
|
||||
switch ($aJoinData['jointype'])
|
||||
{
|
||||
case "first":
|
||||
$aFrom[$this->m_sTableAlias] = array("jointype"=>"first", "tablename"=>$this->m_sTable, "joincondition"=>"");
|
||||
@@ -394,7 +413,50 @@ class SQLQuery
|
||||
case "inner":
|
||||
case "left":
|
||||
// table or tablealias ???
|
||||
$aFrom[$this->m_sTableAlias] = array("jointype"=>$sJoinType, "tablename"=>$this->m_sTable, "joincondition"=>"$sJoinCond");
|
||||
$sJoinCond = "`$sCallerAlias`.`{$aJoinData['leftfield']}` = `$sRightTableAlias`.`{$aJoinData['rightfield']}`";
|
||||
$aFrom[$this->m_sTableAlias] = array("jointype"=>$aJoinData['jointype'], "tablename"=>$this->m_sTable, "joincondition"=>"$sJoinCond");
|
||||
break;
|
||||
case "inner_tree":
|
||||
$sNodeLeft = "`$sCallerAlias`.`{$aJoinData['leftfield']}`";
|
||||
$sNodeRight = "`$sCallerAlias`.`{$aJoinData['rightfield']}`";
|
||||
$sRootLeft = "`$sRightTableAlias`.`{$aJoinData['rightfield_left']}`";
|
||||
$sRootRight = "`$sRightTableAlias`.`{$aJoinData['rightfield_right']}`";
|
||||
switch($aJoinData['tree_operator'])
|
||||
{
|
||||
case TREE_OPERATOR_BELOW:
|
||||
$sJoinCond = "$sNodeLeft >= $sRootLeft AND $sNodeLeft <= $sRootRight";
|
||||
break;
|
||||
|
||||
case TREE_OPERATOR_BELOW_STRICT:
|
||||
$sJoinCond = "$sNodeLeft > $sRootLeft AND $sNodeLeft < $sRootRight";
|
||||
break;
|
||||
|
||||
case TREE_OPERATOR_NOT_BELOW: // Complementary of 'BELOW'
|
||||
$sJoinCond = "$sNodeLeft < $sRootLeft OR $sNodeLeft > $sRootRight";
|
||||
break;
|
||||
|
||||
case TREE_OPERATOR_NOT_BELOW_STRICT: // Complementary of BELOW_STRICT
|
||||
$sJoinCond = "$sNodeLeft <= $sRootLeft OR $sNodeLeft >= $sRootRight";
|
||||
break;
|
||||
|
||||
case TREE_OPERATOR_ABOVE:
|
||||
$sJoinCond = "$sNodeLeft <= $sRootLeft AND $sNodeRight >= $sRootRight";
|
||||
break;
|
||||
|
||||
case TREE_OPERATOR_ABOVE_STRICT:
|
||||
$sJoinCond = "$sNodeLeft < $sRootLeft AND $sNodeRight > $sRootRight";
|
||||
break;
|
||||
|
||||
case TREE_OPERATOR_NOT_ABOVE: // Complementary of 'ABOVE'
|
||||
$sJoinCond = "$sNodeLeft > $sRootLeft OR $sNodeRight < $sRootRight";
|
||||
break;
|
||||
|
||||
case TREE_OPERATOR_NOT_ABOVE_STRICT: // Complementary of ABOVE_STRICT
|
||||
$sJoinCond = "$sNodeLeft >= $sRootLeft OR $sNodeRight <= $sRootRight";
|
||||
break;
|
||||
|
||||
}
|
||||
$aFrom[$this->m_sTableAlias] = array("jointype"=>$aJoinData['jointype'], "tablename"=>$this->m_sTable, "joincondition"=>"$sJoinCond");
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -409,6 +471,7 @@ class SQLQuery
|
||||
{
|
||||
$aDelTables[] = "`{$this->m_sTableAlias}`";
|
||||
}
|
||||
//echo "<p>in privRenderSingleTable this->m_aValues<pre>".print_r($this->m_aValues, true)."</pre></p>\n";
|
||||
foreach($this->m_aValues as $sFieldName=>$value)
|
||||
{
|
||||
$aSetValues["`{$this->m_sTableAlias}`.`$sFieldName`"] = $value; // quoted further!
|
||||
@@ -424,13 +487,13 @@ class SQLQuery
|
||||
$aTempFrom = array(); // temporary subset of 'from' specs, to be grouped in the final query
|
||||
foreach ($this->m_aJoinSelects as $aJoinData)
|
||||
{
|
||||
$sJoinType = $aJoinData["jointype"];
|
||||
$oRightSelect = $aJoinData["select"];
|
||||
$sLeftField = $aJoinData["leftfield"];
|
||||
$sRightField = $aJoinData["rightfield"];
|
||||
$sRightTableAlias = $aJoinData["righttablealias"];
|
||||
// $sJoinType = $aJoinData["jointype"];
|
||||
// $sLeftField = $aJoinData["leftfield"];
|
||||
// $sRightField = $aJoinData["rightfield"];
|
||||
// $sRightTableAlias = $aJoinData["righttablealias"];
|
||||
|
||||
$sJoinTableAlias = $oRightSelect->privRenderSingleTable($aTempFrom, $aFields, $aDelTables, $aSetValues, $aSelectedIdFields, $sJoinType, $this->m_sTableAlias, $sLeftField, $sRightField, $sRightTableAlias);
|
||||
$sJoinTableAlias = $oRightSelect->privRenderSingleTable($aTempFrom, $aFields, $aDelTables, $aSetValues, $aSelectedIdFields, $this->m_sTableAlias, $aJoinData);
|
||||
}
|
||||
$aFrom[$this->m_sTableAlias]['subfrom'] = $aTempFrom;
|
||||
|
||||
|
||||
177
core/templatestring.class.inc.php
Normal file
@@ -0,0 +1,177 @@
|
||||
<?php
|
||||
// Copyright (C) 2010 Combodo SARL
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation; version 3 of the License.
|
||||
//
|
||||
// This program 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 General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
/**
|
||||
* Simple helper class to interpret and transform a template string
|
||||
*
|
||||
* Usage:
|
||||
* $oString = new TemplateString("Blah $this->friendlyname$ is in location $this->location_id->name$ ('$this->location_id->org_id->name$)");
|
||||
* echo $oString->Render(array('this' => $oContact));
|
||||
|
||||
* @author Erwan Taloc <erwan.taloc@combodo.com>
|
||||
* @author Romain Quetiez <romain.quetiez@combodo.com>
|
||||
* @author Denis Flaven <denis.flaven@combodo.com>
|
||||
* @license http://www.opensource.org/licenses/gpl-3.0.html LGPL
|
||||
*/
|
||||
|
||||
/**
|
||||
* Helper class
|
||||
*/
|
||||
class TemplateStringPlaceholder
|
||||
{
|
||||
public $sToken;
|
||||
public $sAttCode;
|
||||
public $sFunction;
|
||||
public $sParamName;
|
||||
public $bIsValid;
|
||||
|
||||
public function __construct($sToken)
|
||||
{
|
||||
$this->sToken = $sToken;
|
||||
$this->sAttcode = '';
|
||||
$this->sFunction = '';
|
||||
$this->sParamName = '';
|
||||
$this->bIsValid = false; // Validity may be false in general, but it can work anyway (thanks to specialization) when rendering
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Class TemplateString
|
||||
*/
|
||||
class TemplateString
|
||||
{
|
||||
protected $m_sRaw;
|
||||
protected $m_aPlaceholders;
|
||||
|
||||
public function __construct($sRaw)
|
||||
{
|
||||
$this->m_sRaw = $sRaw;
|
||||
$this->m_aPlaceholders = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Split the string into placholders
|
||||
* @param Hash $aParamTypes Class of the expected parameters: hash array of '<param_id>' => '<class_name>'
|
||||
* @return void
|
||||
*/
|
||||
protected function Analyze($aParamTypes = array())
|
||||
{
|
||||
if (!is_null($this->m_aPlaceholders)) return;
|
||||
|
||||
$this->m_aPlaceholders = array();
|
||||
if (preg_match_all('/\\$([a-z0-9_]+(->[a-z0-9_]+)*)\\$/', $this->m_sRaw, $aMatches))
|
||||
{
|
||||
foreach($aMatches[1] as $sPlaceholder)
|
||||
{
|
||||
$oPlaceholder = new TemplateStringPlaceholder($sPlaceholder);
|
||||
$oPlaceholder->bIsValid = false;
|
||||
foreach ($aParamTypes as $sParamName => $sClass)
|
||||
{
|
||||
$sParamPrefix = $sParamName.'->';
|
||||
if (substr($sPlaceholder, 0, strlen($sParamPrefix)) == $sParamPrefix)
|
||||
{
|
||||
// Todo - detect functions (label...)
|
||||
$oPlaceholder->sFunction = '';
|
||||
|
||||
$oPlaceholder->sParamName = $sParamName;
|
||||
$sAttcode = substr($sPlaceholder, strlen($sParamPrefix));
|
||||
$oPlaceholder->sAttcode = $sAttcode;
|
||||
$oPlaceholder->bIsValid = MetaModel::IsValidAttCode($sClass, $sAttcode, true /* extended */);
|
||||
}
|
||||
}
|
||||
|
||||
$this->m_aPlaceholders[] = $oPlaceholder;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the placeholders (for reporting purposes)
|
||||
* @return void
|
||||
*/
|
||||
public function GetPlaceholders()
|
||||
{
|
||||
return $this->m_aPlaceholders;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check the format when possible
|
||||
* @param Hash $aParamTypes Class of the expected parameters: hash array of '<param_id>' => '<class_name>'
|
||||
* @return void
|
||||
*/
|
||||
public function IsValid($aParamTypes = array())
|
||||
{
|
||||
$this->Analyze($aParamTypes);
|
||||
|
||||
foreach($this->m_aPlaceholders as $oPlaceholder)
|
||||
{
|
||||
if (!$oPlaceholder->bIsValid)
|
||||
{
|
||||
if (count($aParamTypes) == 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (array_key_exists($oPlaceholder->sParamName, $aParamTypes))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply the given parameters to replace the placeholders
|
||||
* @param Hash $aParamValues Value of the expected parameters: hash array of '<param_id>' => '<value>'
|
||||
* @return void
|
||||
*/
|
||||
public function Render($aParamValues = array())
|
||||
{
|
||||
$aParamTypes = array();
|
||||
foreach($aParamValues as $sParamName => $value)
|
||||
{
|
||||
$aParamTypes[$sParamName] = get_class($value);
|
||||
}
|
||||
$this->Analyze($aParamTypes);
|
||||
|
||||
$aSearch = array();
|
||||
$aReplace = array();
|
||||
foreach($this->m_aPlaceholders as $oPlaceholder)
|
||||
{
|
||||
if (array_key_exists($oPlaceholder->sParamName, $aParamValues))
|
||||
{
|
||||
$oRef = $aParamValues[$oPlaceholder->sParamName];
|
||||
try
|
||||
{
|
||||
$value = $oRef->Get($oPlaceholder->sAttcode);
|
||||
$aSearch[] = '$'.$oPlaceholder->sToken.'$';
|
||||
$aReplace[] = $value;
|
||||
$oPlaceholder->bIsValid = true;
|
||||
}
|
||||
catch(Exception $e)
|
||||
{
|
||||
$oPlaceholder->bIsValid = false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$oPlaceholder->bIsValid = false;
|
||||
}
|
||||
}
|
||||
return str_replace($aSearch, $aReplace, $this->m_sRaw);
|
||||
}
|
||||
}
|
||||
?>
|
||||
@@ -41,7 +41,7 @@ abstract class Trigger extends cmdbAbstractObject
|
||||
"key_type" => "autoincrement",
|
||||
"name_attcode" => "description",
|
||||
"state_attcode" => "",
|
||||
"reconc_keys" => array(),
|
||||
"reconc_keys" => array('description'),
|
||||
"db_table" => "priv_trigger",
|
||||
"db_key_field" => "id",
|
||||
"db_finalclass_field" => "realclass",
|
||||
@@ -87,7 +87,7 @@ abstract class TriggerOnObject extends Trigger
|
||||
"key_type" => "autoincrement",
|
||||
"name_attcode" => "description",
|
||||
"state_attcode" => "",
|
||||
"reconc_keys" => array(),
|
||||
"reconc_keys" => array('description'),
|
||||
"db_table" => "priv_trigger_onobject",
|
||||
"db_key_field" => "id",
|
||||
"db_finalclass_field" => "",
|
||||
@@ -118,7 +118,7 @@ class TriggerOnPortalUpdate extends TriggerOnObject
|
||||
"key_type" => "autoincrement",
|
||||
"name_attcode" => "description",
|
||||
"state_attcode" => "",
|
||||
"reconc_keys" => array(),
|
||||
"reconc_keys" => array('description'),
|
||||
"db_table" => "priv_trigger_onportalupdate",
|
||||
"db_key_field" => "id",
|
||||
"db_finalclass_field" => "",
|
||||
@@ -144,7 +144,7 @@ abstract class TriggerOnStateChange extends TriggerOnObject
|
||||
"key_type" => "autoincrement",
|
||||
"name_attcode" => "description",
|
||||
"state_attcode" => "",
|
||||
"reconc_keys" => array(),
|
||||
"reconc_keys" => array('description'),
|
||||
"db_table" => "priv_trigger_onstatechange",
|
||||
"db_key_field" => "id",
|
||||
"db_finalclass_field" => "",
|
||||
@@ -173,7 +173,7 @@ class TriggerOnStateEnter extends TriggerOnStateChange
|
||||
"key_type" => "autoincrement",
|
||||
"name_attcode" => "description",
|
||||
"state_attcode" => "",
|
||||
"reconc_keys" => array(),
|
||||
"reconc_keys" => array('description'),
|
||||
"db_table" => "priv_trigger_onstateenter",
|
||||
"db_key_field" => "id",
|
||||
"db_finalclass_field" => "",
|
||||
@@ -201,7 +201,7 @@ class TriggerOnStateLeave extends TriggerOnStateChange
|
||||
"key_type" => "autoincrement",
|
||||
"name_attcode" => "description",
|
||||
"state_attcode" => "",
|
||||
"reconc_keys" => array(),
|
||||
"reconc_keys" => array('description'),
|
||||
"db_table" => "priv_trigger_onstateleave",
|
||||
"db_key_field" => "id",
|
||||
"db_finalclass_field" => "",
|
||||
@@ -229,7 +229,7 @@ class TriggerOnObjectCreate extends TriggerOnObject
|
||||
"key_type" => "autoincrement",
|
||||
"name_attcode" => "description",
|
||||
"state_attcode" => "",
|
||||
"reconc_keys" => array(),
|
||||
"reconc_keys" => array('description'),
|
||||
"db_table" => "priv_trigger_onobjcreate",
|
||||
"db_key_field" => "id",
|
||||
"db_finalclass_field" => "",
|
||||
@@ -257,7 +257,7 @@ class lnkTriggerAction extends cmdbAbstractObject
|
||||
"key_type" => "autoincrement",
|
||||
"name_attcode" => "",
|
||||
"state_attcode" => "",
|
||||
"reconc_keys" => array(""),
|
||||
"reconc_keys" => array('action_id', 'trigger_id'),
|
||||
"db_table" => "priv_link_action_trigger",
|
||||
"db_key_field" => "link_id",
|
||||
"db_finalclass_field" => "",
|
||||
|
||||
@@ -295,6 +295,35 @@ abstract class UserInternal extends User
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Self register extension
|
||||
*
|
||||
* @package iTopORM
|
||||
*/
|
||||
interface iSelfRegister
|
||||
{
|
||||
/**
|
||||
* Called when no user is found in iTop for the corresponding 'name'. This method
|
||||
* can create/synchronize the User in iTop with an external source (such as AD/LDAP) on the fly
|
||||
* @param string $sName The typed-in user name
|
||||
* @param string $sPassword The typed-in password
|
||||
* @param string $sLoginMode The login method used (cas|form|basic|url)
|
||||
* @param string $sAuthentication The authentication method used (any|internal|external)
|
||||
* @return bool true if the user is a valid one, false otherwise
|
||||
*/
|
||||
public static function CheckCredentialsAndCreateUser($sName, $sPassword, $sLoginMode, $sAuthentication);
|
||||
|
||||
/**
|
||||
* Called after the user has been authenticated and found in iTop. This method can
|
||||
* Update the user's definition on the fly (profiles...) to keep it in sync with an external source
|
||||
* @param User $oUser The user to update/synchronize
|
||||
* @param string $sLoginMode The login mode used (cas|form|basic|url)
|
||||
* @param string $sAuthentication The authentication method used
|
||||
* @return void
|
||||
*/
|
||||
public static function UpdateUser(User $oUser, $sLoginMode, $sAuthentication);
|
||||
}
|
||||
|
||||
/**
|
||||
* User management core API
|
||||
*
|
||||
@@ -305,6 +334,7 @@ class UserRights
|
||||
protected static $m_oAddOn;
|
||||
protected static $m_oUser;
|
||||
protected static $m_oRealUser;
|
||||
protected static $m_sSelfRegisterAddOn = null;
|
||||
|
||||
public static function SelectModule($sModuleName)
|
||||
{
|
||||
@@ -324,6 +354,15 @@ class UserRights
|
||||
self::$m_oRealUser = null;
|
||||
}
|
||||
|
||||
public static function SelectSelfRegister($sModuleName)
|
||||
{
|
||||
if (!class_exists($sModuleName))
|
||||
{
|
||||
throw new CoreException("Could not select the class, '$sModuleName' for self register, is not a valid class name");
|
||||
}
|
||||
self::$m_sSelfRegisterAddOn = $sModuleName;
|
||||
}
|
||||
|
||||
public static function GetModuleInstance()
|
||||
{
|
||||
return self::$m_oAddOn;
|
||||
@@ -361,21 +400,38 @@ class UserRights
|
||||
return true;
|
||||
}
|
||||
|
||||
public static function CheckCredentials($sName, $sPassword, $sAuthentication = 'any')
|
||||
public static function CheckCredentials($sName, $sPassword, $sLoginMode = 'form', $sAuthentication = 'any')
|
||||
{
|
||||
$oUser = self::FindUser($sName, $sAuthentication);
|
||||
if (is_null($oUser))
|
||||
{
|
||||
return false;
|
||||
return self::CheckCredentialsAndCreateUser($sName, $sPassword, $sLoginMode, $sAuthentication);
|
||||
}
|
||||
|
||||
if (!$oUser->CheckCredentials($sPassword))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
self::UpdateUser($oUser, $sLoginMode, $sAuthentication);
|
||||
return true;
|
||||
}
|
||||
|
||||
public static function CheckCredentialsAndCreateUser($sName, $sPassword, $sLoginMode, $sAuthentication)
|
||||
{
|
||||
if (self::$m_sSelfRegisterAddOn != null)
|
||||
{
|
||||
return call_user_func(array(self::$m_sSelfRegisterAddOn, 'CheckCredentialsAndCreateUser'), $sName, $sPassword, $sLoginMode, $sAuthentication);
|
||||
}
|
||||
}
|
||||
|
||||
public static function UpdateUser($oUser, $sLoginMode, $sAuthentication)
|
||||
{
|
||||
if (self::$m_sSelfRegisterAddOn != null)
|
||||
{
|
||||
call_user_func(array(self::$m_sSelfRegisterAddOn, 'UpdateUser'), $oUser, $sLoginMode, $sAuthentication);
|
||||
}
|
||||
}
|
||||
|
||||
public static function TrustWebServerContext()
|
||||
{
|
||||
if (!is_null(self::$m_oUser))
|
||||
@@ -405,18 +461,6 @@ class UserRights
|
||||
}
|
||||
}
|
||||
|
||||
public static function CanLogOff()
|
||||
{
|
||||
if (!is_null(self::$m_oUser))
|
||||
{
|
||||
return self::$m_oUser->CanLogOff();
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static function ChangePassword($sOldPassword, $sNewPassword, $sName = '')
|
||||
{
|
||||
if (empty($sName))
|
||||
@@ -609,8 +653,6 @@ class UserRights
|
||||
if (!self::CheckLogin()) return true;
|
||||
|
||||
if (self::IsAdministrator()) return true;
|
||||
// Portal users actions are limited by the portal page...
|
||||
if (self::IsPortalUser()) return true;
|
||||
|
||||
if (MetaModel::HasCategory($sClass, 'bizmodel'))
|
||||
{
|
||||
@@ -639,10 +681,6 @@ class UserRights
|
||||
|
||||
if (MetaModel::HasCategory($sClass, 'bizmodel'))
|
||||
{
|
||||
// #@# Temporary?????
|
||||
// The read access is controlled in MetaModel::MakeSelectQuery()
|
||||
if ($iActionCode == UR_ACTION_READ) return true;
|
||||
|
||||
if (is_null($oUser))
|
||||
{
|
||||
$oUser = self::$m_oUser;
|
||||
@@ -863,7 +901,7 @@ class ActionChecker
|
||||
{
|
||||
$sClass = $this->oFilter->GetClass();
|
||||
$oSet = new DBObjectSet($this->oFilter);
|
||||
$iActionAllowed = UserRights::IsActionAllowed($sClass, $oSet, $this->iActionCode);
|
||||
$iActionAllowed = UserRights::IsActionAllowed($sClass, $this->iActionCode, $oSet);
|
||||
if ($iActionAllowed == UR_ALLOWED_DEPENDS)
|
||||
{
|
||||
// Check for each object if the action is allowed or not
|
||||
@@ -919,6 +957,8 @@ class StimulusChecker extends ActionChecker
|
||||
public function IsAllowed()
|
||||
{
|
||||
$sClass = $this->oFilter->GetClass();
|
||||
if (MetaModel::IsAbstract($sClass)) return UR_ALLOWED_NO; // Safeguard, not implemented if the base class of the set is abstract !
|
||||
|
||||
$oSet = new DBObjectSet($this->oFilter);
|
||||
$iActionAllowed = UserRights::IsStimulusAllowed($sClass, $this->iActionCode, $oSet);
|
||||
if ($iActionAllowed == UR_ALLOWED_NO)
|
||||
@@ -945,7 +985,7 @@ class StimulusChecker extends ActionChecker
|
||||
// of IsActionAllowed does not perform a 'per instance' check, we could
|
||||
// skip this second validation phase and assume it would return UR_ALLOWED_YES
|
||||
$oObjSet = DBObjectSet::FromArray($sClass, array($oObj));
|
||||
if (UserRights::IsActionAllowed($sClass, $this->iActionCode, $oObjSet) == UR_ALLOWED_NO)
|
||||
if (!UserRights::IsStimulusAllowed($sClass, $this->iActionCode, $oObjSet))
|
||||
{
|
||||
$this->aAllowedIDs[$oObj->GetKey()] = false;
|
||||
}
|
||||
@@ -981,4 +1021,339 @@ class StimulusChecker extends ActionChecker
|
||||
return $this->iState;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Self-register extension to allow the automatic creation & update of CAS users
|
||||
*
|
||||
* @package iTopORM
|
||||
*
|
||||
*/
|
||||
class CAS_SelfRegister implements iSelfRegister
|
||||
{
|
||||
/**
|
||||
* Called when no user is found in iTop for the corresponding 'name'. This method
|
||||
* can create/synchronize the User in iTop with an external source (such as AD/LDAP) on the fly
|
||||
* @param string $sName The CAS authenticated user name
|
||||
* @param string $sPassword Ignored
|
||||
* @param string $sLoginMode The login mode used (cas|form|basic|url)
|
||||
* @param string $sAuthentication The authentication method used
|
||||
* @return bool true if the user is a valid one, false otherwise
|
||||
*/
|
||||
public static function CheckCredentialsAndCreateUser($sName, $sPassword, $sLoginMode, $sAuthentication)
|
||||
{
|
||||
$bOk = true;
|
||||
if ($sLoginMode != 'cas') return false; // Must be authenticated via CAS
|
||||
|
||||
$sCASMemberships = MetaModel::GetConfig()->Get('cas_memberof');
|
||||
$bFound = false;
|
||||
if (!empty($sCASMemberships))
|
||||
{
|
||||
if (phpCAS::hasAttribute('memberOf'))
|
||||
{
|
||||
// A list of groups is specified, the user must a be member of (at least) one of them to pass
|
||||
$aCASMemberships = array();
|
||||
$aTmp = explode(';', $sCASMemberships);
|
||||
setlocale(LC_ALL, "en_US.utf8"); // !!! WARNING: this is needed to have the iconv //TRANSLIT working fine below !!!
|
||||
foreach($aTmp as $sGroupName)
|
||||
{
|
||||
$aCASMemberships[] = trim(iconv('UTF-8', 'ASCII//TRANSLIT', $sGroupName)); // Just in case remove accents and spaces...
|
||||
}
|
||||
|
||||
$aMemberOf = phpCAS::getAttribute('memberOf');
|
||||
if (!is_array($aMemberOf)) $aMemberOf = array($aMemberOf); // Just one entry, turn it into an array
|
||||
$aFilteredGroupNames = array();
|
||||
foreach($aMemberOf as $sGroupName)
|
||||
{
|
||||
phpCAS::log("Info: user if a member of the group: ".$sGroupName);
|
||||
$sGroupName = trim(iconv('UTF-8', 'ASCII//TRANSLIT', $sGroupName)); // Remove accents and spaces as well
|
||||
$aFilteredGroupNames[] = $sGroupName;
|
||||
$bIsMember = false;
|
||||
foreach($aCASMemberships as $sCASPattern)
|
||||
{
|
||||
if (self::IsPattern($sCASPattern))
|
||||
{
|
||||
if (preg_match($sCASPattern, $sGroupName))
|
||||
{
|
||||
$bIsMember = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if ($sPattern == $sGroupName)
|
||||
{
|
||||
$bIsMember = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ($bIsMember)
|
||||
{
|
||||
$bCASUserSynchro = MetaModel::GetConfig()->Get('cas_user_synchro');
|
||||
if ($bCASUserSynchro)
|
||||
{
|
||||
// If needed create a new user for this email/profile
|
||||
phpCAS::log('Info: cas_user_synchro is ON');
|
||||
$bOk = self::CreateCASUser(phpCAS::getUser(), $aMemberOf);
|
||||
if($bOk)
|
||||
{
|
||||
$bFound = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
phpCAS::log("User ".phpCAS::getUser()." cannot be created in iTop. Logging off...");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
phpCAS::log('Info: cas_user_synchro is OFF');
|
||||
$bFound = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
if($bOk && !$bFound)
|
||||
{
|
||||
phpCAS::log("User ".phpCAS::getUser().", none of his/her groups (".implode('; ', $aFilteredGroupNames).") match any of the required groups: ".implode('; ', $aCASMemberships));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Too bad, the user is not part of any of the group => not allowed
|
||||
phpCAS::log("No 'memberOf' attribute found for user ".phpCAS::getUser().". Are you using the SAML protocol (S1) ?");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// No membership required, anybody will pass
|
||||
$bFound = true;
|
||||
}
|
||||
|
||||
if (!$bFound)
|
||||
{
|
||||
// The user is not part of the allowed groups, => log out
|
||||
$sUrl = utils::GetAbsoluteUrlAppRoot().'pages/UI.php';
|
||||
$sCASLogoutUrl = MetaModel::GetConfig()->Get('cas_logout_redirect_service');
|
||||
if (empty($sCASLogoutUrl))
|
||||
{
|
||||
$sCASLogoutUrl = $sUrl;
|
||||
}
|
||||
phpCAS::logoutWithRedirectService($sCASLogoutUrl); // Redirects to the CAS logout page
|
||||
// Will never return !
|
||||
}
|
||||
return $bFound;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called after the user has been authenticated and found in iTop. This method can
|
||||
* Update the user's definition (profiles...) on the fly to keep it in sync with an external source
|
||||
* @param User $oUser The user to update/synchronize
|
||||
* @param string $sLoginMode The login mode used (cas|form|basic|url)
|
||||
* @param string $sAuthentication The authentication method used
|
||||
* @return void
|
||||
*/
|
||||
public static function UpdateUser(User $oUser, $sLoginMode, $sAuthentication)
|
||||
{
|
||||
$bCASUpdateProfiles = MetaModel::GetConfig()->Get('cas_update_profiles');
|
||||
if (($sLoginMode == 'cas') && $bCASUpdateProfiles && (phpCAS::hasAttribute('memberOf')))
|
||||
{
|
||||
$aMemberOf = phpCAS::getAttribute('memberOf');
|
||||
if (!is_array($aMemberOf)) $aMemberOf = array($aMemberOf); // Just one entry, turn it into an array
|
||||
|
||||
return self::SetProfilesFromCAS($oUser, $aMemberOf);
|
||||
}
|
||||
// No groups defined in CAS or not CAS at all: do nothing...
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method to create a CAS based user
|
||||
* @param string $sEmail
|
||||
* @param array $aGroups
|
||||
* @return bool true on success, false otherwise
|
||||
*/
|
||||
protected static function CreateCASUser($sEmail, $aGroups)
|
||||
{
|
||||
if (!MetaModel::IsValidClass('URP_Profiles'))
|
||||
{
|
||||
phpCAS::log("URP_Profiles is not a valid class. Automatic creation of Users is not supported in this context, sorry.");
|
||||
return false;
|
||||
}
|
||||
|
||||
$oUser = MetaModel::GetObjectByName('UserExternal', $sEmail, false);
|
||||
if ($oUser == null)
|
||||
{
|
||||
// Create the user, link it to a contact
|
||||
phpCAS::log("Info: the user '$sEmail' does not exist. A new UserExternal will be created.");
|
||||
$oSearch = new DBObjectSearch('Person');
|
||||
$oSearch->AddCondition('email', $sEmail);
|
||||
$oSet = new DBObjectSet($oSearch);
|
||||
$iContactId = 0;
|
||||
switch($oSet->Count())
|
||||
{
|
||||
case 0:
|
||||
phpCAS::log("Error: found no contact with the email: '$sEmail'. Cannot create the user in iTop.");
|
||||
return false;
|
||||
|
||||
case 1:
|
||||
$oContact = $oSet->Fetch();
|
||||
$iContactId = $oContact->GetKey();
|
||||
phpCAS::log("Info: Found 1 contact '".$oContact->GetName()."' (id=$iContactId) corresponding to the email '$sEmail'.");
|
||||
break;
|
||||
|
||||
default:
|
||||
phpCAS::log("Error: ".$oSet->Count()." contacts have the same email: '$sEmail'. Cannot create a user for this email.");
|
||||
return false;
|
||||
}
|
||||
|
||||
$oUser = new UserExternal();
|
||||
$oUser->Set('login', $sEmail);
|
||||
$oUser->Set('contactid', $iContactId);
|
||||
$oUser->Set('language', MetaModel::GetConfig()->GetDefaultLanguage());
|
||||
}
|
||||
else
|
||||
{
|
||||
phpCAS::log("Info: the user '$sEmail' already exists (id=".$oUser->GetKey().").");
|
||||
}
|
||||
|
||||
// Now synchronize the profiles
|
||||
if (!self::SetProfilesFromCAS($oUser, $aGroups))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
if ($oUser->IsNew() || $oUser->IsModified())
|
||||
{
|
||||
$oMyChange = MetaModel::NewObject("CMDBChange");
|
||||
$oMyChange->Set("date", time());
|
||||
$oMyChange->Set("userinfo", 'CAS/LDAP Synchro');
|
||||
$oMyChange->DBInsert();
|
||||
if ($oUser->IsNew())
|
||||
{
|
||||
$oUser->DBInsertTracked($oMyChange);
|
||||
}
|
||||
else
|
||||
{
|
||||
$oUser->DBUpdateTracked($oMyChange);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
protected static function SetProfilesFromCAS($oUser, $aGroups)
|
||||
{
|
||||
if (!MetaModel::IsValidClass('URP_Profiles'))
|
||||
{
|
||||
phpCAS::log("URP_Profiles is not a valid class. Automatic creation of Users is not supported in this context, sorry.");
|
||||
return false;
|
||||
}
|
||||
|
||||
// read all the existing profiles
|
||||
$oProfilesSearch = new DBObjectSearch('URP_Profiles');
|
||||
$oProfilesSet = new DBObjectSet($oProfilesSearch);
|
||||
$aAllProfiles = array();
|
||||
while($oProfile = $oProfilesSet->Fetch())
|
||||
{
|
||||
$aAllProfiles[strtolower($oProfile->GetName())] = $oProfile->GetKey();
|
||||
}
|
||||
|
||||
// Translate the CAS/LDAP group names into iTop profile names
|
||||
$aProfiles = array();
|
||||
$sPattern = MetaModel::GetConfig()->Get('cas_profile_pattern');
|
||||
foreach($aGroups as $sGroupName)
|
||||
{
|
||||
if (preg_match($sPattern, $sGroupName, $aMatches))
|
||||
{
|
||||
if (array_key_exists(strtolower($aMatches[1]), $aAllProfiles))
|
||||
{
|
||||
$aProfiles[] = $aAllProfiles[strtolower($aMatches[1])];
|
||||
phpCAS::log("Info: Adding the profile '{$aMatches[1]}' from CAS.");
|
||||
}
|
||||
else
|
||||
{
|
||||
phpCAS::log("Warning: {$aMatches[1]} is not a valid iTop profile (extracted from group name: '$sGroupName'). Ignored.");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
phpCAS::log("Info: The CAS group '$sGroupName' does not seem to match an iTop pattern. Ignored.");
|
||||
}
|
||||
}
|
||||
if (count($aProfiles) == 0)
|
||||
{
|
||||
phpCAS::log("Info: The user '".$oUser->GetName()."' has no profiles retrieved from CAS. Default profile(s) will be used.");
|
||||
|
||||
// Second attempt: check if there is/are valid default profile(s)
|
||||
$sCASDefaultProfiles = MetaModel::GetConfig()->Get('cas_default_profiles');
|
||||
$aCASDefaultProfiles = explode(';', $sCASDefaultProfiles);
|
||||
foreach($aCASDefaultProfiles as $sDefaultProfileName)
|
||||
{
|
||||
if (array_key_exists(strtolower($sDefaultProfileName), $aAllProfiles))
|
||||
{
|
||||
$aProfiles[] = $aAllProfiles[strtolower($sDefaultProfileName)];
|
||||
phpCAS::log("Info: Adding the default profile '".$aAllProfiles[strtolower($sDefaultProfileName)]."' from CAS.");
|
||||
}
|
||||
else
|
||||
{
|
||||
phpCAS::log("Warning: the default profile {$sDefaultProfileName} is not a valid iTop profile. Ignored.");
|
||||
}
|
||||
}
|
||||
|
||||
if (count($aProfiles) == 0)
|
||||
{
|
||||
phpCAS::log("Error: The user '".$oUser->GetName()."' has no profiles in iTop, and therefore cannot be created.");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Now synchronize the profiles
|
||||
$oProfilesSet = DBObjectSet::FromScratch('URP_UserProfile');
|
||||
foreach($aProfiles as $iProfileId)
|
||||
{
|
||||
$oLink = new URP_UserProfile();
|
||||
$oLink->Set('profileid', $iProfileId);
|
||||
$oLink->Set('reason', 'CAS/LDAP Synchro');
|
||||
$oProfilesSet->AddObject($oLink);
|
||||
}
|
||||
$oUser->Set('profile_list', $oProfilesSet);
|
||||
phpCAS::log("Info: the user '".$oUser->GetName()."' (id=".$oUser->GetKey().") now has the following profiles: '".implode("', '", $aProfiles)."'.");
|
||||
if ($oUser->IsModified())
|
||||
{
|
||||
$oMyChange = MetaModel::NewObject("CMDBChange");
|
||||
$oMyChange->Set("date", time());
|
||||
$oMyChange->Set("userinfo", 'CAS/LDAP Synchro');
|
||||
$oMyChange->DBInsert();
|
||||
if ($oUser->IsNew())
|
||||
{
|
||||
$oUser->DBInsertTracked($oMyChange);
|
||||
}
|
||||
else
|
||||
{
|
||||
$oUser->DBUpdateTracked($oMyChange);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
/**
|
||||
* Helper function to check if the supplied string is a litteral string or a regular expression pattern
|
||||
* @param string $sCASPattern
|
||||
* @return bool True if it's a regular expression pattern, false otherwise
|
||||
*/
|
||||
protected static function IsPattern($sCASPattern)
|
||||
{
|
||||
if ((substr($sCASPattern, 0, 1) == '/') && (substr($sCASPattern, -1) == '/'))
|
||||
{
|
||||
// the string is enclosed by slashes, let's assume it's a pattern
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// By default enable the 'CAS_SelfRegister' defined above
|
||||
UserRights::SelectSelfRegister('CAS_SelfRegister');
|
||||
?>
|
||||
|
||||
@@ -60,10 +60,12 @@ abstract class ValueSetDefinition
|
||||
}
|
||||
if (strlen($sContains) == 0)
|
||||
{
|
||||
// No filtering
|
||||
$aRet = $this->m_aValues;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Filter on results containing the needle <sContain>
|
||||
$aRet = array();
|
||||
foreach ($this->m_aValues as $sKey=>$sValue)
|
||||
{
|
||||
@@ -73,6 +75,7 @@ abstract class ValueSetDefinition
|
||||
}
|
||||
}
|
||||
}
|
||||
// Sort on the display value
|
||||
asort($aRet);
|
||||
return $aRet;
|
||||
}
|
||||
@@ -88,21 +91,62 @@ abstract class ValueSetDefinition
|
||||
*/
|
||||
class ValueSetObjects extends ValueSetDefinition
|
||||
{
|
||||
protected $m_sContains;
|
||||
protected $m_sFilterExpr; // in OQL
|
||||
protected $m_sValueAttCode;
|
||||
protected $m_aOrderBy;
|
||||
protected $m_aExtraConditions;
|
||||
private $m_bAllowAllData;
|
||||
|
||||
public function __construct($sFilterExp, $sValueAttCode = '', $aOrderBy = array(), $bAllowAllData = false)
|
||||
{
|
||||
$this->m_sContains = '';
|
||||
$this->m_sFilterExpr = $sFilterExp;
|
||||
$this->m_sValueAttCode = $sValueAttCode;
|
||||
$this->m_aOrderBy = $aOrderBy;
|
||||
$this->m_bAllowAllData = $bAllowAllData;
|
||||
$this->m_aExtraConditions = array();
|
||||
}
|
||||
|
||||
protected function LoadValues($aArgs)
|
||||
public function AddCondition(DBObjectSearch $oFilter)
|
||||
{
|
||||
$this->m_aExtraConditions[] = $oFilter;
|
||||
}
|
||||
|
||||
public function ToObjectSet($aArgs = array(), $sContains = '')
|
||||
{
|
||||
if ($this->m_bAllowAllData)
|
||||
{
|
||||
$oFilter = DBObjectSearch::FromOQL_AllData($this->m_sFilterExpr);
|
||||
}
|
||||
else
|
||||
{
|
||||
$oFilter = DBObjectSearch::FromOQL($this->m_sFilterExpr);
|
||||
}
|
||||
foreach($this->m_aExtraConditions as $oExtraFilter)
|
||||
{
|
||||
$oFilter->MergeWith($oExtraFilter);
|
||||
}
|
||||
|
||||
return new DBObjectSet($oFilter, $this->m_aOrderBy, $aArgs);
|
||||
}
|
||||
|
||||
public function GetValues($aArgs, $sContains = '')
|
||||
{
|
||||
if (!$this->m_bIsLoaded || ($sContains != $this->m_sContains))
|
||||
{
|
||||
$this->LoadValues($aArgs, $sContains);
|
||||
$this->m_bIsLoaded = true;
|
||||
}
|
||||
// The results are already filtered and sorted (on friendly name)
|
||||
$aRet = $this->m_aValues;
|
||||
return $aRet;
|
||||
}
|
||||
|
||||
protected function LoadValues($aArgs, $sContains = '')
|
||||
{
|
||||
$this->m_sContains = $sContains;
|
||||
|
||||
$this->m_aValues = array();
|
||||
|
||||
if ($this->m_bAllowAllData)
|
||||
@@ -114,6 +158,15 @@ class ValueSetObjects extends ValueSetDefinition
|
||||
$oFilter = DBObjectSearch::FromOQL($this->m_sFilterExpr);
|
||||
}
|
||||
if (!$oFilter) return false;
|
||||
foreach($this->m_aExtraConditions as $oExtraFilter)
|
||||
{
|
||||
$oFilter->MergeWith($oExtraFilter);
|
||||
}
|
||||
|
||||
$oValueExpr = new ScalarExpression('%'.$sContains.'%');
|
||||
$oNameExpr = new FieldExpression('friendlyname', $oFilter->GetClassAlias());
|
||||
$oNewCondition = new BinaryExpression($oNameExpr, 'LIKE', $oValueExpr);
|
||||
$oFilter->AddConditionExpression($oNewCondition);
|
||||
|
||||
$oObjects = new DBObjectSet($oFilter, $this->m_aOrderBy, $aArgs);
|
||||
while ($oObject = $oObjects->Fetch())
|
||||
@@ -198,7 +251,7 @@ class ValueSetRelatedObjectsFromLinkSet extends ValueSetDefinition
|
||||
}
|
||||
// #@# or AddObjectArray($aObjects) ?
|
||||
$oSetToCreate = DBObjectSet::FromArray($this->m_sTargetLinkClass, $aLinksToCreate);
|
||||
$this->m_aValues[$oObject->GetKey()] = $oObject->GetAsHTML($oObject->GetName());
|
||||
$this->m_aValues[$oObject->GetKey()] = $oObject->GetName();
|
||||
}
|
||||
|
||||
return true;
|
||||
@@ -250,6 +303,34 @@ class ValueSetEnum extends ValueSetDefinition
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fixed set values, defined as a range: 0..59 (with an optional increment)
|
||||
*
|
||||
* @package iTopORM
|
||||
*/
|
||||
class ValueSetRange extends ValueSetDefinition
|
||||
{
|
||||
protected $m_iStart;
|
||||
protected $m_iEnd;
|
||||
|
||||
public function __construct($iStart, $iEnd, $iStep = 1)
|
||||
{
|
||||
$this->m_iStart = $iStart;
|
||||
$this->m_iEnd = $iEnd;
|
||||
$this->m_iStep = $iStep;
|
||||
}
|
||||
|
||||
protected function LoadValues($aArgs)
|
||||
{
|
||||
$iValue = $this->m_iStart;
|
||||
for($iValue = $this->m_iStart; $iValue <= $this->m_iEnd; $iValue += $this->m_iStep)
|
||||
{
|
||||
$this->m_aValues[$iValue] = $iValue;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Data model classes
|
||||
|
||||
@@ -176,6 +176,10 @@ legend {
|
||||
-webkit-border-radius: 6px;
|
||||
border-radius: 6px;
|
||||
}
|
||||
.ui-widget-content td legend a, .ui-widget-content td legend a:hover, .ui-widget-content td legend a:visited {
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.ui-widget-content td a, p a, p a:visited, td a, td a:visited {
|
||||
text-decoration:none;
|
||||
color: #1C94C4;
|
||||
@@ -402,8 +406,10 @@ div.itop_popup {
|
||||
|
||||
div.itop_popup > ul {
|
||||
height:19px;
|
||||
line-height: 17px;
|
||||
vertical-align: middle;
|
||||
display:block;
|
||||
width:70px; /* Nasty work-around for IE... en attendant mieux */
|
||||
nowidth:70px; /* Nasty work-around for IE... en attendant mieux */
|
||||
padding-left: 5px;
|
||||
background: url(../images/actions_left.png) no-repeat top left;
|
||||
cursor: pointer;
|
||||
@@ -414,7 +420,7 @@ div.itop_popup > ul > li {
|
||||
list-style: none;
|
||||
font-size: 11px;
|
||||
font-family: Tahoma,sans-serif;
|
||||
height: 19px;
|
||||
height: 17px;
|
||||
padding-right: 16px;
|
||||
padding-left: 4px;
|
||||
background: url(../images/actions_right.png) no-repeat top right transparent;
|
||||
@@ -1048,4 +1054,61 @@ fieldset table.details>tbody>tr>td {
|
||||
}
|
||||
.ac_dlg_loading {
|
||||
background: white url('../images/indicator.gif') right center no-repeat;
|
||||
}
|
||||
table.pagination {
|
||||
display:inline-block;
|
||||
}
|
||||
table.pagination tr td {
|
||||
padding: 3px;
|
||||
}
|
||||
.pager {
|
||||
float:left;
|
||||
}
|
||||
.pager p {
|
||||
margin-top: 0;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
.pager td span {
|
||||
min-width: 20px;
|
||||
display:inline-block;
|
||||
text-align: center;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.pager td span.curr_page {
|
||||
color: #fff;
|
||||
background: #999;
|
||||
-moz-border-radius: 4px;
|
||||
-webkit-border-radius: 4px;
|
||||
border-radius: 4px;
|
||||
}
|
||||
img.prev, img.first, img.next, img.last {
|
||||
cursor: pointer;
|
||||
}
|
||||
div.actions_button {
|
||||
float:right;
|
||||
background: url("../images/actions_left.png") no-repeat scroll left top transparent;
|
||||
padding-left: 5px;
|
||||
margin-top: 13px;
|
||||
margin-right: 10px;
|
||||
height:17px;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
div.actions_button a, .actions_button a:hover, .actions_button a:visited {
|
||||
background:url(../images/actions_bkg.png) no-repeat scroll right top transparent;
|
||||
color:#fff;
|
||||
padding-right: 8px;
|
||||
cursor:pointer;
|
||||
font-family: Tahoma,sans-serif;
|
||||
font-size: 11px;
|
||||
font-weight: bold;
|
||||
padding-left: 4px;
|
||||
text-decoration: none;
|
||||
height:17px;
|
||||
line-height: 17px;
|
||||
display: block;
|
||||
}
|
||||
select#org_id {
|
||||
max-width: 90%;
|
||||
}
|
||||
@@ -86,9 +86,36 @@ Dict::Add('EN US', 'English', 'English', array(
|
||||
|
||||
'Core:AttributeDateTime' => 'Date/time',
|
||||
'Core:AttributeDateTime+' => 'Date and time (year-month-day hh:mm:ss)',
|
||||
'Core:AttributeDateTime?SmartSearch' => '
|
||||
<p>
|
||||
Date format:<br/>
|
||||
<b>yyyy-mm-dd hh:mm:ss</b><br/>
|
||||
Example: 2011-07-19 18:40:00
|
||||
</p>
|
||||
<p>
|
||||
Operators:<br/>
|
||||
<b>></b><em>date</em><br/>
|
||||
<b><</b><em>date</em><br/>
|
||||
<b>[</b><em>date</em>,<em>date</em><b>]</b>
|
||||
</p>
|
||||
<p>
|
||||
If the time is omitted, it defaults to 00:00:00
|
||||
</p>',
|
||||
|
||||
'Core:AttributeDate' => 'Date',
|
||||
'Core:AttributeDate+' => 'Date (year-month-day)',
|
||||
'Core:AttributeDate?SmartSearch' => '
|
||||
<p>
|
||||
Date format:<br/>
|
||||
<b>yyyy-mm-dd</b><br/>
|
||||
Example: 2011-07-19
|
||||
</p>
|
||||
<p>
|
||||
Operators:<br/>
|
||||
<b>></b><em>date</em><br/>
|
||||
<b><</b><em>date</em><br/>
|
||||
<b>[</b><em>date</em>,<em>date</em><b>]</b>
|
||||
</p>',
|
||||
|
||||
'Core:AttributeDeadline' => 'Deadline',
|
||||
'Core:AttributeDeadline+' => 'Date, displayed relatively to the current time',
|
||||
@@ -113,6 +140,12 @@ Dict::Add('EN US', 'English', 'English', array(
|
||||
|
||||
'Core:AttributePropertySet' => 'Properties',
|
||||
'Core:AttributePropertySet+' => 'List of untyped properties (name and value)',
|
||||
|
||||
'Core:AttributeFriendlyName' => 'Friendly name',
|
||||
'Core:AttributeFriendlyName+' => 'Attribute created automatically ; the friendly name is computed after several attributes',
|
||||
|
||||
'Core:FriendlyName-Label' => 'Name',
|
||||
'Core:FriendlyName-Description' => 'Friendly name',
|
||||
));
|
||||
|
||||
|
||||
@@ -441,8 +474,8 @@ Dict::Add('EN US', 'English', 'English', array(
|
||||
//
|
||||
|
||||
Dict::Add('EN US', 'English', 'English', array(
|
||||
'Class:TriggerOnPortalUpdate' => 'Trigger (when updated from the portal)',
|
||||
|
||||
'Class:TriggerOnPortalUpdate' => 'Trigger (when updated from the portal)',
|
||||
'Class:TriggerOnPortalUpdate+' => 'Trigger on a end-user\'s update from the portal',
|
||||
));
|
||||
|
||||
//
|
||||
@@ -537,6 +570,8 @@ Dict::Add('EN US', 'English', 'English', array(
|
||||
'Class:SynchroDataSource/Attribute:delete_policy_update+' => 'Syntax: field_name:value; ...',
|
||||
'Class:SynchroDataSource/Attribute:delete_policy_retention' => 'Retention Duration',
|
||||
'Class:SynchroDataSource/Attribute:delete_policy_retention+' => 'How much time an obsolete object is kept before being deleted',
|
||||
'Class:SynchroDataSource/Attribute:database_table_name' => 'Data table',
|
||||
'Class:SynchroDataSource/Attribute:database_table_name+' => 'Name of the table to store the synchronization data. If left empty, a default name will be computed.',
|
||||
'SynchroDataSource:Description' => 'Description',
|
||||
'SynchroDataSource:Reconciliation' => 'Search & reconciliation',
|
||||
'SynchroDataSource:Deletion' => 'Deletion rules',
|
||||
@@ -560,7 +595,7 @@ Dict::Add('EN US', 'English', 'English', array(
|
||||
'Core:Synchro:History' => 'Synchronization History',
|
||||
'Core:Synchro:NeverRun' => 'This synchro was never run. No log yet.',
|
||||
'Core:Synchro:SynchroEndedOn_Date' => 'The latest synchronization ended on %1$s.',
|
||||
'Core:Synchro:SynchroRunningStartedOn_Date' => 'The synchronization started on $1$s is still running...',
|
||||
'Core:Synchro:SynchroRunningStartedOn_Date' => 'The synchronization started on %1$s is still running...',
|
||||
'Menu:DataSources' => 'Synchronization Data Sources',
|
||||
'Menu:DataSources+' => 'All Synchronization Data Sources',
|
||||
'Core:Synchro:label_repl_ignored' => 'Ignored (%1$s)',
|
||||
@@ -585,6 +620,7 @@ Dict::Add('EN US', 'English', 'English', array(
|
||||
'Class:SynchroDataSource/Error:AtLeastOneReconciliationKeyMustBeSpecified' => 'At Least one reconciliation key must be specified, or the reconciliation policy must be to use the primary key.',
|
||||
'Class:SynchroDataSource/Error:DeleteRetentionDurationMustBeSpecified' => 'A delete retention period must be specified, since objects are to be deleted after being marked as obsolete',
|
||||
'Class:SynchroDataSource/Error:DeletePolicyUpdateMustBeSpecified' => 'Obsolete objects are to be updated, but no update is specified.',
|
||||
'Class:SynchroDataSource/Error:DataTableAlreadyExists' => 'The table %1$s already exists in the database. Please use another name for the synchro data table.',
|
||||
'Core:SynchroReplica:PublicData' => 'Public Data',
|
||||
'Core:SynchroReplica:PrivateDetails' => 'Private Details',
|
||||
'Core:SynchroReplica:BackToDataSource' => 'Go Back to the Synchro Data Source: %1$s',
|
||||
@@ -600,7 +636,7 @@ Dict::Add('EN US', 'English', 'English', array(
|
||||
'Core:SynchroAtt:update_policy+' => 'Behavior of the updated field',
|
||||
'Core:SynchroAtt:reconciliation_attcode' => 'Reconciliation Key',
|
||||
'Core:SynchroAtt:reconciliation_attcode+' => 'Attribute Code for the External Key Reconciliation',
|
||||
'Core:SyncDataExchangeComment' => '(DataExchange)',
|
||||
'Core:SyncDataExchangeComment' => '(Data Synchro)',
|
||||
'Core:Synchro:ListOfDataSources' => 'List of data sources:',
|
||||
'Core:Synchro:LastSynchro' => 'Last synchronization:',
|
||||
'Core:Synchro:ThisObjectIsSynchronized' => 'This object is synchronized with an external data source',
|
||||
@@ -612,7 +648,9 @@ Dict::Add('EN US', 'English', 'English', array(
|
||||
'Core:SyncDataSourceObsolete' => 'The data source is marked as obsolete. Operation cancelled.',
|
||||
'Core:SyncDataSourceAccessRestriction' => 'Only adminstrators or the user specified in the data source can execute this operation. Operation cancelled.',
|
||||
'Core:SyncTooManyMissingReplicas' => 'All records have been untouched for some time (all of the objects could be deleted). Please check that the process that writes into the synchronization table is still running. Operation cancelled.',
|
||||
|
||||
'Core:SyncSplitModeCLIOnly' => 'The synchronization can be executed in chunks only if run in mode CLI',
|
||||
'Core:Synchro:ListReplicas_AllReplicas_Errors_Warnings' => '%1$s replicas, %2$s error(s), %3$s warning(s).',
|
||||
'Core:SynchroReplica:TargetObject' => 'Synchronized Object: %1$s',
|
||||
'Class:AsyncSendEmail' => 'Email (asynchronous)',
|
||||
'Class:AsyncSendEmail/Attribute:to' => 'To',
|
||||
'Class:AsyncSendEmail/Attribute:subject' => 'Subject',
|
||||
@@ -690,7 +728,7 @@ Dict::Add('EN US', 'English', 'English', array(
|
||||
'Class:SynchroReplica/Attribute:sync_source_id' => 'Synchro Data Source',
|
||||
'Class:SynchroReplica/Attribute:dest_id' => 'Destination object (ID)',
|
||||
'Class:SynchroReplica/Attribute:dest_class' => 'Destination type',
|
||||
'Class:SynchroReplica/Attribute:status_last_seen' => 'Lat seen',
|
||||
'Class:SynchroReplica/Attribute:status_last_seen' => 'Last seen',
|
||||
'Class:SynchroReplica/Attribute:status' => 'Status',
|
||||
'Class:SynchroReplica/Attribute:status/Value:modified' => 'Modified',
|
||||
'Class:SynchroReplica/Attribute:status/Value:new' => 'New',
|
||||
@@ -699,11 +737,14 @@ Dict::Add('EN US', 'English', 'English', array(
|
||||
'Class:SynchroReplica/Attribute:status/Value:synchronized' => 'Synchronized',
|
||||
'Class:SynchroReplica/Attribute:status_dest_creator' => 'Object Created ?',
|
||||
'Class:SynchroReplica/Attribute:status_last_error' => 'Last Error',
|
||||
'Class:SynchroReplica/Attribute:status_last_warning' => 'Warnings',
|
||||
'Class:SynchroReplica/Attribute:info_creation_date' => 'Creation Date',
|
||||
'Class:SynchroReplica/Attribute:info_last_modified' => 'Last Modified Date',
|
||||
'Class:appUserPreferences' => 'User Preferences',
|
||||
'Class:appUserPreferences/Attribute:userid' => 'User',
|
||||
'Class:appUserPreferences/Attribute:preferences' => 'Prefs',
|
||||
'Core:ExecProcess:Code1' => 'Wrong command or command finished with errors (e.g. wrong script name)',
|
||||
'Core:ExecProcess:Code255' => 'PHP Error (parsing, or runtime)',
|
||||
));
|
||||
|
||||
//
|
||||
|
||||
@@ -76,6 +76,26 @@ Dict::Add('EN US', 'English', 'English', array(
|
||||
'Class:AuditRule/Attribute:category_name+' => 'Name of the category for this rule',
|
||||
));
|
||||
|
||||
//
|
||||
// Class: QueryOQL
|
||||
//
|
||||
|
||||
Dict::Add('EN US', 'English', 'English', array(
|
||||
'Class:Query' => 'Query',
|
||||
'Class:Query+' => 'A query is a data set defined in a dynamic way',
|
||||
'Class:Query/Attribute:name' => 'Name',
|
||||
'Class:Query/Attribute:name+' => 'Identifies the query',
|
||||
'Class:Query/Attribute:description' => 'Description',
|
||||
'Class:Query/Attribute:description+' => 'Long description for the query (purpose, usage, etc.)',
|
||||
'Class:Query/Attribute:fields' => 'Fields',
|
||||
'Class:Query/Attribute:fields+' => 'Coma separated list of attributes (or alias.attribute) to export',
|
||||
|
||||
'Class:QueryOQL' => 'OQL Query',
|
||||
'Class:QueryOQL+' => 'A query based on the Object Query Language',
|
||||
'Class:QueryOQL/Attribute:oql' => 'Expression',
|
||||
'Class:QueryOQL/Attribute:oql+' => 'OQL Expression',
|
||||
));
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// Classes in 'addon/userrights'
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
@@ -367,7 +387,7 @@ Dict::Add('EN US', 'English', 'English', array(
|
||||
'UI:Error:IncorrectLinkDefinition_LinkedClass_Class' => 'Incorrect link definition: the class of objects to manage: %1$s was not found as an external key in the class %2$s',
|
||||
'UI:Error:Object_Class_Id_NotFound' => 'Object: %1$s:%2$d not found.',
|
||||
'UI:Error:WizardCircularReferenceInDependencies' => 'Error: Circular reference in the dependencies between the fields, check the data model.',
|
||||
'UI:Error:UploadedFileTooBig' => 'Uploaded file is too big. (Max allowed size is %1$s). Check you PHP configuration for upload_max_filesize and post_max_size.',
|
||||
'UI:Error:UploadedFileTooBig' => 'The uploaded file is too big. (Max allowed size is %1$s). To modify this limit, contact your iTop administrator. (Check the PHP configuration for upload_max_filesize and post_max_size on the server).',
|
||||
'UI:Error:UploadedFileTruncated.' => 'Uploaded file has been truncated !',
|
||||
'UI:Error:NoTmpDir' => 'The temporary directory is not defined.',
|
||||
'UI:Error:CannotWriteToTmp_Dir' => 'Unable to write the temporary file to the disk. upload_tmp_dir = "%1$s".',
|
||||
@@ -416,6 +436,7 @@ Dict::Add('EN US', 'English', 'English', array(
|
||||
'UI:History:StatsDeletes+' => 'Count of objects deleted',
|
||||
'UI:Loading' => 'Loading...',
|
||||
'UI:Menu:Actions' => 'Actions',
|
||||
'UI:Menu:OtherActions' => 'Other Actions',
|
||||
'UI:Menu:New' => 'New...',
|
||||
'UI:Menu:Add' => 'Add...',
|
||||
'UI:Menu:Manage' => 'Manage...',
|
||||
@@ -428,6 +449,8 @@ Dict::Add('EN US', 'English', 'English', array(
|
||||
'UI:UndefinedObject' => 'undefined',
|
||||
'UI:Document:OpenInNewWindow:Download' => 'Open in new window: %1$s, Download: %2$s',
|
||||
'UI:SelectAllToggle+' => 'Select / Deselect All',
|
||||
'UI:SplitDateTime-Date' => 'date',
|
||||
'UI:SplitDateTime-Time' => 'time',
|
||||
'UI:TruncatedResults' => '%1$d objects displayed out of %2$d',
|
||||
'UI:DisplayAll' => 'Display All',
|
||||
'UI:CollapseList' => 'Collapse',
|
||||
@@ -447,6 +470,7 @@ Dict::Add('EN US', 'English', 'English', array(
|
||||
'UI:Login:IdentifyYourself' => 'Identify yourself before continuing',
|
||||
'UI:Login:UserNamePrompt' => 'User Name',
|
||||
'UI:Login:PasswordPrompt' => 'Password',
|
||||
'UI:Login:About' => '',
|
||||
'UI:Login:ChangeYourPassword' => 'Change Your Password',
|
||||
'UI:Login:OldPasswordPrompt' => 'Old password',
|
||||
'UI:Login:NewPasswordPrompt' => 'New password',
|
||||
@@ -531,7 +555,9 @@ Dict::Add('EN US', 'English', 'English', array(
|
||||
'UI:Audit:HeaderNbObjects' => '# Objects',
|
||||
'UI:Audit:HeaderNbErrors' => '# Errors',
|
||||
'UI:Audit:PercentageOk' => '% Ok',
|
||||
|
||||
'UI:Audit:ErrorIn_Rule_Reason' => 'OQL Error in the Rule %1$s: %2$s.',
|
||||
'UI:Audit:ErrorIn_Category_Reason' => 'OQL Error in the Category %1$s: %2$s.',
|
||||
|
||||
'UI:RunQuery:Title' => 'iTop - OQL Query Evaluation',
|
||||
'UI:RunQuery:QueryExamples' => 'Query Examples',
|
||||
'UI:RunQuery:HeaderPurpose' => 'Purpose',
|
||||
@@ -543,7 +569,7 @@ Dict::Add('EN US', 'English', 'English', array(
|
||||
'UI:RunQuery:DevelopedQuery' => 'Redevelopped query expression: ',
|
||||
'UI:RunQuery:SerializedFilter' => 'Serialized filter: ',
|
||||
'UI:RunQuery:Error' => 'An error occured while running the query: %1$s',
|
||||
|
||||
'UI:Query:UrlForExcel' => 'URL to use for MS-Excel web queries',
|
||||
'UI:Schema:Title' => 'iTop objects schema',
|
||||
'UI:Schema:CategoryMenuItem' => 'Category <b>%1$s</b>',
|
||||
'UI:Schema:Relationships' => 'Relationships',
|
||||
@@ -603,8 +629,8 @@ Dict::Add('EN US', 'English', 'English', array(
|
||||
'UI:Schema:LifeCycleAttributeMustChange' => 'Must change',
|
||||
'UI:Schema:LifeCycleAttributeMustPrompt' => 'User will be prompted to change the value',
|
||||
'UI:Schema:LifeCycleEmptyList' => 'empty list',
|
||||
|
||||
'UI:LinksWidget:Autocomplete+' => 'Type the first 3 characters...',
|
||||
'UI:Edit:TestQuery' => 'Test query',
|
||||
'UI:Combo:SelectValue' => '--- select a value ---',
|
||||
'UI:Label:SelectedObjects' => 'Selected objects: ',
|
||||
'UI:Label:AvailableObjects' => 'Available objects: ',
|
||||
@@ -617,7 +643,6 @@ Dict::Add('EN US', 'English', 'English', array(
|
||||
'UI:RemoveLinkedObjectsOf_Class' => 'Remove selected objects',
|
||||
'UI:Message:EmptyList:UseAdd' => 'The list is empty, use the "Add..." button to add elements.',
|
||||
'UI:Message:EmptyList:UseSearchForm' => 'Use the search form above to search for objects to be added.',
|
||||
|
||||
'UI:Wizard:FinalStepTitle' => 'Final step: confirmation',
|
||||
'UI:Title:DeletionOf_Object' => 'Deletion of %1$s',
|
||||
'UI:Title:BulkDeletionOf_Count_ObjectsOf_Class' => 'Bulk deletion of %1$d objects of class %2$s',
|
||||
@@ -820,6 +845,9 @@ When associated with a trigger, each action is given an "order" number, specifyi
|
||||
'Menu:RunQueriesMenu' => 'Run Queries',
|
||||
'Menu:RunQueriesMenu+' => 'Run any query',
|
||||
|
||||
'Menu:QueryMenu' => 'Query phrasebook',
|
||||
'Menu:QueryMenu+' => 'Query phrasebook',
|
||||
|
||||
'Menu:DataAdministration' => 'Data administration',
|
||||
'Menu:DataAdministration+' => 'Data administration',
|
||||
|
||||
@@ -861,14 +889,19 @@ When associated with a trigger, each action is given an "order" number, specifyi
|
||||
'UI:RelationshipGraph' => 'Graphical view',
|
||||
'UI:RelationshipList' => 'List',
|
||||
'UI:OperationCancelled' => 'Operation Cancelled',
|
||||
'UI:ElementsDisplayed' => 'Filtering',
|
||||
|
||||
'Portal:Title' => 'iTop user portal',
|
||||
'Portal:Refresh' => 'Refresh',
|
||||
'Portal:Back' => 'Back',
|
||||
'Portal:WelcomeUserOrg' => 'Welcome %1$s, from %2$s',
|
||||
'Portal:ShowOngoing' => 'Show open requests',
|
||||
'Portal:ShowClosed' => 'Show closed requests',
|
||||
'Portal:CreateNewRequest' => 'Create a new request',
|
||||
'Portal:ChangeMyPassword' => 'Change my password',
|
||||
'Portal:Disconnect' => 'Disconnect',
|
||||
'Portal:OpenRequests' => 'My open requests',
|
||||
'Portal:ClosedRequests' => 'My closed requests',
|
||||
'Portal:ResolvedRequests' => 'My resolved requests',
|
||||
'Portal:SelectService' => 'Select a service from the catalog:',
|
||||
'Portal:PleaseSelectOneService' => 'Please select one service',
|
||||
@@ -876,8 +909,11 @@ When associated with a trigger, each action is given an "order" number, specifyi
|
||||
'Portal:PleaseSelectAServiceSubCategory' => 'Please select one sub-category',
|
||||
'Portal:DescriptionOfTheRequest' => 'Enter the description of your request:',
|
||||
'Portal:TitleRequestDetailsFor_Request' => 'Details for request %1$s:',
|
||||
'Portal:NoOpenRequest' => 'No request in this category.',
|
||||
'Portal:NoOpenRequest' => 'No request in this category',
|
||||
'Portal:NoClosedRequest' => 'No request in this category',
|
||||
'Portal:Button:ReopenTicket' => 'Reopen this ticket',
|
||||
'Portal:Button:CloseTicket' => 'Close this ticket',
|
||||
'Portal:Button:UpdateRequest' => 'Update the request',
|
||||
'Portal:EnterYourCommentsOnTicket' => 'Enter your comments about the resolution of this ticket:',
|
||||
'Portal:ErrorNoContactForThisUser' => 'Error: the current user is not associated with a Contact/Person. Please contact your administrator.',
|
||||
'Portal:Attachments' => 'Attachments',
|
||||
@@ -915,5 +951,17 @@ When associated with a trigger, each action is given an "order" number, specifyi
|
||||
'UI:ActionNotAllowed' => 'You are not allowed to perform this action on these objects.',
|
||||
'UI:BulkAction:NoObjectSelected' => 'Please select at least one object to perform this operation',
|
||||
'UI:AttemptingToChangeASlaveAttribute_Name' => 'The field %1$s is not writable because it is mastered by the data synchronization. Value remains unchanged.',
|
||||
'UI:Pagination:HeaderSelection' => 'Total: %1$s objects (%2$s objects selected).',
|
||||
'UI:Pagination:HeaderNoSelection' => 'Total: %1$s objects.',
|
||||
'UI:Pagination:PageSize' => '%1$s objects per page',
|
||||
'UI:Pagination:PagesLabel' => 'Pages:',
|
||||
'UI:Pagination:All' => 'All',
|
||||
'UI:HierarchyOf_Class' => 'Hierarchy of %1$s',
|
||||
'UI:Preferences' => 'Preferences...',
|
||||
'UI:FavoriteOrganizations' => 'My Favorite Organizations',
|
||||
'UI:FavoriteOrganizations+' => 'Check in the list below the organizations that you want to see in the drop-down menu for a quick access. '.
|
||||
'Note that this is not a security setting, objects from any organization are still visible and can be accessed by selecting "All Organizations" in the drop-down list.',
|
||||
'UI:NavigateAwayConfirmationMessage' => 'Any modification will be discarded.',
|
||||
'UI:Create_Class_InState' => 'Create the %1$s in state: ',
|
||||
));
|
||||
?>
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
|
||||
Dict::Add('ES CR', 'English', 'English', array(
|
||||
Dict::Add('ES CR', 'Spanish', 'Español, Castellano', array(
|
||||
'Core:AttributeLinkedSet' => 'Array of objects',
|
||||
'Core:AttributeLinkedSet+' => 'Any kind of objects [subclass] of the same class',
|
||||
|
||||
|
||||
@@ -414,6 +414,7 @@ Dict::Add('ES CR', 'Spanish', 'Español, Castellano', array(
|
||||
'UI:History:Changes+' => 'Chambios hechos al objeto',
|
||||
'UI:Loading' => 'Cargando...',
|
||||
'UI:Menu:Actions' => 'Acciones',
|
||||
'UI:Menu:OtherActions' => 'Otras Acciones',
|
||||
'UI:Menu:New' => 'Nuevo...',
|
||||
'UI:History:StatsCreations' => 'Created',
|
||||
'UI:History:StatsCreations+' => 'Count of objects created',
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
* @author Erwan Taloc <erwan.taloc@combodo.com>
|
||||
* @author Romain Quetiez <romain.quetiez@combodo.com>
|
||||
* @author Denis Flaven <denis.flaven@combodo.com>
|
||||
* @licence http://www.opensource.org/licenses/gpl-3.0.html LGPL
|
||||
* @licence http://www.opensource.org/licenses/gpl-3.0.html LGPL
|
||||
*/
|
||||
|
||||
Dict::Add('FR FR', 'French', 'Français', array(
|
||||
@@ -48,11 +48,11 @@ Dict::Add('FR FR', 'French', 'Français', array(
|
||||
'Class:ActionEmail/Attribute:importance/Value:low+' => '',
|
||||
'Class:ActionEmail/Attribute:importance/Value:normal' => 'Normale',
|
||||
'Class:ActionEmail/Attribute:importance/Value:normal+' => '',
|
||||
'Class:TriggerOnPortalUdpate' => 'Déclencheur sur mise à jour depuis le portail',
|
||||
'Class:TriggerOnPortalUdpate+' => '',
|
||||
'Class:TriggerOnPortalUpdate' => 'Déclencheur sur mise à jour depuis le portail',
|
||||
'Class:TriggerOnPortalUpdate+' => '',
|
||||
'Class:TriggerOnStateEnter' => 'Déclencheur sur un objet entrant dans un état',
|
||||
'Class:TriggerOnStateEnter+' => '',
|
||||
'Class:TriggerOnStateLeave' => 'Déclencheur sur un objet quitant un état',
|
||||
'Class:TriggerOnStateLeave' => 'Déclencheur sur un objet quittant un état',
|
||||
'Class:TriggerOnStateLeave+' => '',
|
||||
'Class:TriggerOnObjectCreate' => 'Déclencheur sur la création d\'un objet',
|
||||
'Class:TriggerOnObjectCreate+' => '',
|
||||
@@ -280,6 +280,8 @@ Dict::Add('FR FR', 'French', 'Français', array(
|
||||
'Class:SynchroDataSource/Attribute:url_icon+' => 'Hyperlien vers une icône représentant l\'application source des données',
|
||||
'Class:SynchroDataSource/Attribute:url_application' => 'Application (hyperlien)',
|
||||
'Class:SynchroDataSource/Attribute:url_application+' => 'Un hyperlien vers l\'application source des données. Paramètres possibles: $this->nom_de_champ$ et $replica->primary_key$',
|
||||
'Class:SynchroDataSource/Attribute:database_table_name' => 'Table de données',
|
||||
'Class:SynchroDataSource/Attribute:database_table_name+' => 'Nom de la table stockant les données de cette source. Un nom par défaut est calculé automatiquement si ce champ est laissé vide.',
|
||||
'Class:SynchroAttribute' => 'Champs de synchronisation',
|
||||
'Class:SynchroAttribute+' => '',
|
||||
'Class:SynchroAttribute/Attribute:sync_source_id' => 'Source de données',
|
||||
@@ -386,6 +388,8 @@ Dict::Add('FR FR', 'French', 'Français', array(
|
||||
'Class:SynchroReplica/Attribute:status_dest_creator+' => '',
|
||||
'Class:SynchroReplica/Attribute:status_last_error' => 'Dernière erreur',
|
||||
'Class:SynchroReplica/Attribute:status_last_error+' => '',
|
||||
'Class:SynchroReplica/Attribute:status_last_warning' => 'Avertissements',
|
||||
'Class:SynchroReplica/Attribute:status_last_warning+' => '',
|
||||
'Class:SynchroReplica/Attribute:info_creation_date' => 'Date de création',
|
||||
'Class:SynchroReplica/Attribute:info_creation_date+' => '',
|
||||
'Class:SynchroReplica/Attribute:info_last_modified' => 'Date de dernière modification',
|
||||
@@ -438,8 +442,35 @@ Dict::Add('FR FR', 'French', 'Français', array(
|
||||
'Core:AttributeTemplateHTML+' => 'HTML contenant des espaces réservés pour des données iTop',
|
||||
'Core:AttributeDateTime' => 'Date/heure',
|
||||
'Core:AttributeDateTime+' => 'Date et heure (année-mois-jour hh:mm:ss)',
|
||||
'Core:AttributeDateTime?SmartSearch' => '
|
||||
<p>
|
||||
Format de date :<br/>
|
||||
<b>aaaa-mm-jj hh:mm:ss</b><br/>
|
||||
Exemple : 2011-07-19 18:40:00
|
||||
</p>
|
||||
<p>
|
||||
Opérateurs :<br/>
|
||||
<b>></b><em>date</em><br/>
|
||||
<b><</b><em>date</em><br/>
|
||||
<b>[</b><em>date</em>,<em>date</em><b>]</b>
|
||||
</p>
|
||||
<p>
|
||||
Si l\'heure n\'est pas spécifiée, cela revient à 00:00:00 (minuit)
|
||||
</p>',
|
||||
'Core:AttributeDate' => 'Date',
|
||||
'Core:AttributeDate+' => 'Date (année-mois-jour)',
|
||||
'Core:AttributeDate?SmartSearch' => '
|
||||
<p>
|
||||
Format de date :<br/>
|
||||
<b>aaaa-mm-jj</b><br/>
|
||||
Exemple : 2011-07-19
|
||||
</p>
|
||||
<p>
|
||||
Opérateurs :<br/>
|
||||
<b>></b><em>date</em><br/>
|
||||
<b><</b><em>date</em><br/>
|
||||
<b>[</b><em>date</em>,<em>date</em><b>]</b>
|
||||
</p>',
|
||||
'Core:AttributeDeadline' => 'Délai',
|
||||
'Core:AttributeDeadline+' => 'Date/heure exprimée relativement à l\'heure courante',
|
||||
'Core:AttributeExternalKey' => 'Clé externe',
|
||||
@@ -456,6 +487,13 @@ Dict::Add('FR FR', 'French', 'Français', array(
|
||||
'Core:AttributeTable+' => 'Tableau à deux dimensions',
|
||||
'Core:AttributePropertySet' => 'Propriétés',
|
||||
'Core:AttributePropertySet+' => 'Liste de propriétés (nom et valeur) non typées',
|
||||
|
||||
'Core:AttributeFriendlyName' => 'Nom usuel (convivial)',
|
||||
'Core:AttributeFriendlyName+' => 'Attribut créé automatiquement ; sa valeur est calculée d\'après d\'autres attributs',
|
||||
|
||||
'Core:FriendlyName-Label' => 'Nom',
|
||||
'Core:FriendlyName-Description' => 'Nom usuel',
|
||||
|
||||
'Change:ObjectCreated' => 'Elément créé',
|
||||
'Change:ObjectDeleted' => 'Elément effacé',
|
||||
'Change:ObjectModified' => 'Elément modifié',
|
||||
@@ -485,7 +523,7 @@ Dict::Add('FR FR', 'French', 'Français', array(
|
||||
'Class:Action/Attribute:finalclass+' => '',
|
||||
'Class:ActionNotification' => 'notification',
|
||||
'Class:ActionNotification+' => '',
|
||||
'Class:Trigger' => 'trigger',
|
||||
'Class:Trigger' => 'Déclencheur',
|
||||
'Class:Trigger+' => '',
|
||||
'Class:Trigger/Attribute:description' => 'Description',
|
||||
'Class:Trigger/Attribute:description+' => '',
|
||||
@@ -527,7 +565,7 @@ Dict::Add('FR FR', 'French', 'Français', array(
|
||||
'Core:Synchro:History' => 'Historique de synchronisation',
|
||||
'Core:Synchro:NeverRun' => 'Aucun historique, la synchronisation n\'a pas encore fonctionné',
|
||||
'Core:Synchro:SynchroEndedOn_Date' => 'La dernière synchronisation s\'est terminée à: %1$s.',
|
||||
'Core:Synchro:SynchroRunningStartedOn_Date' => 'Synchronisation en cours (début à $1$s)',
|
||||
'Core:Synchro:SynchroRunningStartedOn_Date' => 'Synchronisation en cours (début à %1$s)',
|
||||
'Menu:DataSources' => 'Synchronisation',
|
||||
'Menu:DataSources+' => '',
|
||||
'Core:Synchro:label_repl_ignored' => 'Ignorés (%1$s)',
|
||||
@@ -551,6 +589,7 @@ Dict::Add('FR FR', 'French', 'Français', array(
|
||||
'Class:SynchroDataSource/Error:AtLeastOneReconciliationKeyMustBeSpecified' => 'Si la politique de réconciliation n\'est pas la clé primaire, au moins une clé de recherche doit être spécifiée',
|
||||
'Class:SynchroDataSource/Error:DeleteRetentionDurationMustBeSpecified' => 'Pour que les objets soient effacés après avoir été obsoletés, il faut spécifier une durée de rétention',
|
||||
'Class:SynchroDataSource/Error:DeletePolicyUpdateMustBeSpecified' => 'Les objets obsolètes doivent être mis à jour, mais aucune information de mise à jour n\'est spécifiée',
|
||||
'Class:SynchroDataSource/Error:DataTableAlreadyExists' => 'La table %1$s existe déjà dans la base de données. Veuillez utiliser un autre nom pour la table des données de cette source.',
|
||||
'Core:SynchroReplica:PublicData' => 'Données synchronisées',
|
||||
'Core:SynchroReplica:PrivateDetails' => 'Informations internes',
|
||||
'Core:SynchroReplica:BackToDataSource' => 'Retourner aux détails de la source de données: %1$s',
|
||||
@@ -566,7 +605,7 @@ Dict::Add('FR FR', 'French', 'Français', array(
|
||||
'Core:SynchroAtt:update_policy+' => '',
|
||||
'Core:SynchroAtt:reconciliation_attcode' => 'Clé de recherche',
|
||||
'Core:SynchroAtt:reconciliation_attcode+' => '',
|
||||
'Core:SyncDataExchangeComment' => '(Synhcronisation)',
|
||||
'Core:SyncDataExchangeComment' => '(Synchronisation)',
|
||||
'Core:Synchro:ListOfDataSources' => 'Sources de données:',
|
||||
'Core:Synchro:LastSynchro' => 'Dernière synchronisation:',
|
||||
'Core:Synchro:ThisObjectIsSynchronized' => 'Cet objet est synchronisé avec une source de données',
|
||||
@@ -578,6 +617,8 @@ Dict::Add('FR FR', 'French', 'Français', array(
|
||||
'Core:SyncDataSourceObsolete' => 'Cette source de données est obsolète. Opération annulée.',
|
||||
'Core:SyncDataSourceAccessRestriction' => 'Seuls les administrateurs et l\'utilisateur spécifié dans la source de données peuvent exécuter cette synchronisation. Opération annulée.',
|
||||
'Core:SyncTooManyMissingReplicas' => 'Tous les réplicas sont absents de l\'import. L\'import a-t-il réellement tourné. Opération annulée.',
|
||||
'Core:Synchro:ListReplicas_AllReplicas_Errors_Warnings' => '%1$s replicas, %2$s erreur(s), %3$s avertissement(s).',
|
||||
'Core:SynchroReplica:TargetObject' => 'Objet Synchronisé : %1$s',
|
||||
'Core:Duration_Seconds' => '%1$ds',
|
||||
'Core:Duration_Minutes_Seconds' => '%1$dmin %2$ds',
|
||||
'Core:Duration_Hours_Minutes_Seconds' => '%1$dh %2$dmin %3$ds',
|
||||
|
||||
@@ -50,6 +50,18 @@ Dict::Add('FR FR', 'French', 'Français', array(
|
||||
'Class:AuditCategory/Attribute:definition_set+' => 'Expression OQL qui défini le périmètre d\'application de l\'audit',
|
||||
'Class:AuditCategory/Attribute:rules_list' => 'Règles d\'audit',
|
||||
'Class:AuditCategory/Attribute:rules_list+' => 'Règles d\'audit pour cette catégorie',
|
||||
'Class:Query' => 'Requête',
|
||||
'Class:Query+' => 'Une requête définit un ensemble d\'information de manière dynamique',
|
||||
'Class:Query/Attribute:name' => 'Nom',
|
||||
'Class:Query/Attribute:name+' => 'Identification de la requête',
|
||||
'Class:Query/Attribute:description' => 'Description',
|
||||
'Class:Query/Attribute:description+' => 'Description complète (finalité, utilisations, public)',
|
||||
'Class:Query/Attribute:fields' => 'Champs',
|
||||
'Class:Query/Attribute:fields+' => 'Liste CSV des attributs (ou alias.attribut) à exporter',
|
||||
'Class:QueryOQL' => 'Requête OQL',
|
||||
'Class:QueryOQL+' => 'Une requête écrite dans le langage "Object Query Language"',
|
||||
'Class:QueryOQL/Attribute:oql' => 'Expression',
|
||||
'Class:QueryOQL/Attribute:oql+' => 'Expression OQL',
|
||||
'Class:URP_Profiles' => 'Profil',
|
||||
'Class:URP_Profiles+' => 'Profil utilisateur',
|
||||
'Class:URP_Profiles/Attribute:name' => 'Nom',
|
||||
@@ -71,7 +83,7 @@ Dict::Add('FR FR', 'French', 'Français', array(
|
||||
'Class:URP_UserProfile/Attribute:reason' => 'Raison',
|
||||
'Class:URP_UserProfile/Attribute:reason+' => 'Justifie le rôle affecté à cet utilisateur',
|
||||
'Class:URP_UserOrg' => 'Utilisateur/Organisation',
|
||||
'Class:URP_UserOrg+' => 'Organizations permises pour l\'utilisateur',
|
||||
'Class:URP_UserOrg+' => 'Organisations permises pour l\'utilisateur',
|
||||
'Class:URP_UserOrg/Attribute:userid' => 'Utilisateur',
|
||||
'Class:URP_UserOrg/Attribute:userid+' => '',
|
||||
'Class:URP_UserOrg/Attribute:userlogin' => 'Login',
|
||||
@@ -215,7 +227,7 @@ Dict::Add('FR FR', 'French', 'Français', array(
|
||||
'UI:WelcomeMenu:OpenIncidents' => 'Incidents en cours: %1$d',
|
||||
'UI:WelcomeMenu:AllConfigItems' => 'Actifs: %1$d',
|
||||
'UI:WelcomeMenu:MyIncidents' => 'Mes Incidents',
|
||||
'UI:AllOrganizations' => ' Toutes les Organizations ',
|
||||
'UI:AllOrganizations' => ' Toutes les Organisations ',
|
||||
'UI:YourSearch' => 'Votre recherche',
|
||||
'UI:LoggedAsMessage' => 'Connecté comme: %1$s',
|
||||
'UI:LoggedAsMessage+Admin' => 'Connecté comme: %1$s (Administrateur)',
|
||||
@@ -257,7 +269,7 @@ Dict::Add('FR FR', 'French', 'Français', array(
|
||||
'UI:Error:IncorrectLinkDefinition_LinkedClass_Class' => 'la définition du lien est incorrecte: la classe d\'objets à gérer: %1$s n\'est référencée par aucune clef externe de la classe %2$s',
|
||||
'UI:Error:Object_Class_Id_NotFound' => 'L\'objet: %1$s:%2$d est introuvable.',
|
||||
'UI:Error:WizardCircularReferenceInDependencies' => 'Erreur: Référence circulaire entre les dépendences entre champs, vérifiez le modèle de données.',
|
||||
'UI:Error:UploadedFileTooBig' => 'Le fichier téléchargé est trop gros. (La taille maximale autorisée est %1$s). Vérifiez la valeur des variables upload_max_filesize et post_max_size dans la configuration PHP.',
|
||||
'UI:Error:UploadedFileTooBig' => 'Le fichier téléchargé est trop gros. (La taille maximale autorisée est %1$s). Pour modifier cette limite contactez votre administrateur iTop. (Réglages upload_max_filesize et post_max_size dans la configuration PHP sur le serveur)',
|
||||
'UI:Error:UploadedFileTruncated.' => 'Le fichier téléchargé a été tronqué !',
|
||||
'UI:Error:NoTmpDir' => 'Il n\'y a aucun répertoire temporaire de défini.',
|
||||
'UI:Error:CannotWriteToTmp_Dir' => 'Impossible d\'écrire le fichier temporaire sur disque. upload_tmp_dir = "%1$s".',
|
||||
@@ -303,6 +315,7 @@ Dict::Add('FR FR', 'French', 'Français', array(
|
||||
'UI:History:StatsDeletes+' => 'Nombre d\'objets effacés',
|
||||
'UI:Loading' => 'Chargement...',
|
||||
'UI:Menu:Actions' => 'Actions',
|
||||
'UI:Menu:OtherActions' => 'Autres Actions',
|
||||
'UI:Menu:New' => 'Créer...',
|
||||
'UI:Menu:Add' => 'Ajouter...',
|
||||
'UI:Menu:Manage' => 'Gérer...',
|
||||
@@ -315,6 +328,8 @@ Dict::Add('FR FR', 'French', 'Français', array(
|
||||
'UI:Document:OpenInNewWindow:Download' => 'Ouvrir dans un nouvelle fenêtre: %1$s, Télécharger: %2$s',
|
||||
'UI:SelectAllToggle+' => 'Tout sélectionner / Tout déselectionner',
|
||||
'UI:TruncatedResults' => '%1$d objets affichés sur %2$d',
|
||||
'UI:SplitDateTime-Date' => 'date',
|
||||
'UI:SplitDateTime-Time' => 'heure',
|
||||
'UI:DisplayAll' => 'Tout afficher',
|
||||
'UI:CollapseList' => 'Refermer',
|
||||
'UI:CountOfResults' => '%1$d objet(s)',
|
||||
@@ -415,6 +430,8 @@ Dict::Add('FR FR', 'French', 'Français', array(
|
||||
'UI:Audit:HeaderNbObjects' => 'Nb d\'Objets',
|
||||
'UI:Audit:HeaderNbErrors' => 'Nb d\'Erreurs',
|
||||
'UI:Audit:PercentageOk' => '% Ok',
|
||||
'UI:Audit:ErrorIn_Rule_Reason' => 'Erreur OQL dans la règle %1$s: %2$s.',
|
||||
'UI:Audit:ErrorIn_Category_Reason' => 'Erreur OQL dans la catégorie %1$s: %2$s.',
|
||||
'UI:RunQuery:Title' => 'iTop - Evaluation de requêtes OQL',
|
||||
'UI:RunQuery:QueryExamples' => 'Exemples de requêtes',
|
||||
'UI:RunQuery:HeaderPurpose' => 'Objectif',
|
||||
@@ -426,6 +443,7 @@ Dict::Add('FR FR', 'French', 'Français', array(
|
||||
'UI:RunQuery:DevelopedQuery' => 'Requête OQL décompilée : ',
|
||||
'UI:RunQuery:SerializedFilter' => 'Version sérialisée : ',
|
||||
'UI:RunQuery:Error' => 'Une erreur s\'est produite durant l\'exécution de la requête : %1$s',
|
||||
'UI:Query:UrlForExcel' => 'Lien à copier-coller dans Excel, pour déclarer une source de données à partir du web',
|
||||
'UI:Schema:Title' => 'Modèle de données iTop',
|
||||
'UI:Schema:CategoryMenuItem' => 'Catégorie <b>%1$s</b>',
|
||||
'UI:Schema:Relationships' => 'Relations',
|
||||
@@ -485,6 +503,7 @@ Dict::Add('FR FR', 'French', 'Français', array(
|
||||
'UI:Schema:LifeCycleAttributeMustPrompt' => 'L\'utilisateur se verra proposer de changer la valeur',
|
||||
'UI:Schema:LifeCycleEmptyList' => 'liste vide',
|
||||
'UI:LinksWidget:Autocomplete+' => 'Tapez les 3 premiers caractères...',
|
||||
'UI:Edit:TestQuery' => 'Tester le requête',
|
||||
'UI:Combo:SelectValue' => '--- choisissez une valeur ---',
|
||||
'UI:Label:SelectedObjects' => 'Objets sélectionnés: ',
|
||||
'UI:Label:AvailableObjects' => 'Objets disponibles: ',
|
||||
@@ -679,6 +698,8 @@ Lors de l\'association à un déclencheur, on attribue à chaque action un numé
|
||||
'Menu:Notifications:Title' => 'Catégories d\'audit',
|
||||
'Menu:RunQueriesMenu' => 'Requêtes OQL',
|
||||
'Menu:RunQueriesMenu+' => 'Executer une requête OQL',
|
||||
'Menu:QueryMenu' => 'Livre des requêtes',
|
||||
'Menu:QueryMenu+' => 'Livre des requêtes',
|
||||
'Menu:DataAdministration' => 'Administration des données',
|
||||
'Menu:DataAdministration+' => 'Administration des données',
|
||||
'Menu:UniversalSearchMenu' => 'Recherche Universelle',
|
||||
@@ -697,7 +718,7 @@ Lors de l\'association à un déclencheur, on attribue à chaque action un numé
|
||||
'UI:iTopVersion:Short' => 'iTop version %1$s',
|
||||
'UI:iTopVersion:Long' => 'iTop version %1$s-%2$s du %3$s',
|
||||
'UI:PropertiesTab' => 'Propriétés',
|
||||
'UI:OpenDocumentInNewWindow_' => 'Ouvrir de document dans un autre fenêtre: %1$s',
|
||||
'UI:OpenDocumentInNewWindow_' => 'Ouvrir ce document dans uns autre fenêtre: %1$s',
|
||||
'UI:DownloadDocument_' => 'Télécharger ce document: %1$s',
|
||||
'UI:Document:NoPreview' => 'L\'aperçu n\'est pas disponible pour ce type de documents',
|
||||
'UI:DeadlineMissedBy_duration' => 'Passé de %1$s',
|
||||
@@ -711,14 +732,19 @@ Lors de l\'association à un déclencheur, on attribue à chaque action un numé
|
||||
'UI:DisplayThisMessageAtStartup' => 'Afficher ce message au démarrage',
|
||||
'UI:RelationshipGraph' => 'Vue graphique',
|
||||
'UI:RelationshipList' => 'Liste',
|
||||
'UI:ElementsDisplayed' => 'Filtrage',
|
||||
'UI:OperationCancelled' => 'Opération Annulée',
|
||||
'Portal:Title' => 'Portail utilisateur iTop',
|
||||
'Portal:Refresh' => 'Rafraîchir',
|
||||
'Portal:Back' => 'Retour',
|
||||
'Portal:WelcomeUserOrg' => 'Bienvenue %1$s (%2$s)',
|
||||
'Portal:ShowOngoing' => 'Requêtes en cours',
|
||||
'Portal:ShowClosed' => 'Requêtes fermées',
|
||||
'Portal:CreateNewRequest' => 'Créer une nouvelle requête',
|
||||
'Portal:ChangeMyPassword' => 'Changer mon mot de passe',
|
||||
'Portal:Disconnect' => 'Déconnexion',
|
||||
'Portal:OpenRequests' => 'Mes requêtes en cours',
|
||||
'Portal:ClosedRequests' => 'Mes requêtes fermées',
|
||||
'Portal:ResolvedRequests' => 'Mes requêtes résolues',
|
||||
'Portal:SelectService' => 'Choisissez un service dans le catalogue:',
|
||||
'Portal:PleaseSelectOneService' => 'Veuillez choisir un service',
|
||||
@@ -727,7 +753,10 @@ Lors de l\'association à un déclencheur, on attribue à chaque action un numé
|
||||
'Portal:DescriptionOfTheRequest' => 'Entrez la description de votre requête:',
|
||||
'Portal:TitleRequestDetailsFor_Request' => 'Détails de votre requête %1$s:',
|
||||
'Portal:NoOpenRequest' => 'Aucune requête.',
|
||||
'Portal:NoClosedRequest' => 'Aucune requête.',
|
||||
'Portal:Button:ReopenTicket' => 'Réouvrir cette requête',
|
||||
'Portal:Button:CloseTicket' => 'Clôre cette requête',
|
||||
'Portal:Button:UpdateRequest' => 'Mettre à jour la requête',
|
||||
'Portal:EnterYourCommentsOnTicket' => 'Vos commentaires à propos du traitement de cette requête:',
|
||||
'Portal:ErrorNoContactForThisUser' => 'Erreur: l\'utilisateur courant n\'est pas associé à une Personne/Contact. Contactez votre administrateur.',
|
||||
'Portal:Attachments' => 'Pièces jointes',
|
||||
@@ -765,5 +794,17 @@ Lors de l\'association à un déclencheur, on attribue à chaque action un numé
|
||||
'UI:ActionNotAllowed' => 'Vous n\'êtes pas autorisé à exécuter cette opération sur ces objets.',
|
||||
'UI:BulkAction:NoObjectSelected' => 'Veuillez s\électionner au moins un objet pour cette opération.',
|
||||
'UI:AttemptingToChangeASlaveAttribute_Name' => 'Le champ %1$s ne peut pas être modifié car il est géré par une synchronisation avec une source de données. Valeur inchangée.',
|
||||
'UI:Pagination:HeaderSelection' => 'Total: %1$s éléments / %2$s éléments sélectionné(s).',
|
||||
'UI:Pagination:HeaderNoSelection' => 'Total: %1$s éléments.',
|
||||
'UI:Pagination:PageSize' => '%1$s éléments par page',
|
||||
'UI:Pagination:PagesLabel' => 'Pages:',
|
||||
'UI:Pagination:All' => 'Tous',
|
||||
'UI:HierarchyOf_Class' => 'Hiérarchie de type %1$s',
|
||||
'UI:Preferences' => 'Preferences...',
|
||||
'UI:FavoriteOrganizations' => 'Mes Organisations Favorites',
|
||||
'UI:FavoriteOrganizations+' => 'Cochez dans la liste ci-dessous les organisations que vous voulez voir listées dans le menu principal. '.
|
||||
'Ceci n\'est pas un réglage de sécurité. Les objets de toutes les organisations sont toujours visibles en choisissant "Toutes les Organisations" dans le menu.',
|
||||
'UI:NavigateAwayConfirmationMessage' => 'Toute modification sera perdue.',
|
||||
'UI:Create_Class_InState' => 'Créer l\'objet %1$s dans l\'état: ',
|
||||
));
|
||||
?>
|
||||
|
||||
@@ -422,7 +422,7 @@ Dict::Add('HU HU', 'Hungarian', 'Magyar', array(
|
||||
'Core:Synchro:History' => 'Szinkronizáció történet',
|
||||
'Core:Synchro:NeverRun' => 'Ez a szinkronizáció még soha nem futott. Nincs még napló bejegyzés.',
|
||||
'Core:Synchro:SynchroEndedOn_Date' => 'Az utolsó szinkronizáció lefutásának időpontja: %1$s.',
|
||||
'Core:Synchro:SynchroRunningStartedOn_Date' => 'Az szinkronizáció elindut $1$s, de még fut.',
|
||||
'Core:Synchro:SynchroRunningStartedOn_Date' => 'Az szinkronizáció elindut %1$s, de még fut.',
|
||||
'Menu:DataSources' => 'Szinkronizált adatforrások',
|
||||
'Menu:DataSources+' => '',
|
||||
'Core:Synchro:label_repl_ignored' => 'Figyelmen kívül hagyott (%1$s)',
|
||||
|
||||
@@ -302,6 +302,7 @@ Dict::Add('HU HU', 'Hungarian', 'Magyar', array(
|
||||
'UI:History:StatsDeletes+' => '',
|
||||
'UI:Loading' => 'Betöltés...',
|
||||
'UI:Menu:Actions' => 'Akciók',
|
||||
'UI:Menu:OtherActions' => 'Egyéb Akciók',
|
||||
'UI:Menu:New' => 'Új...',
|
||||
'UI:Menu:Add' => 'Hozzáad...',
|
||||
'UI:Menu:Manage' => 'Kezel...',
|
||||
@@ -714,10 +715,14 @@ Akció kiváltó okhoz rendelésekor kap egy sorszámot , amely meghatározza az
|
||||
'Portal:Title' => 'iTop felhasználói portál',
|
||||
'Portal:Refresh' => 'Frissítés',
|
||||
'Portal:Back' => 'Vissza',
|
||||
'Portal:WelcomeUserOrg' => 'Welcome %1$s, from %2$s',
|
||||
'Portal:ShowOngoing' => 'Show open requests',
|
||||
'Portal:ShowClosed' => 'Show closed requests',
|
||||
'Portal:CreateNewRequest' => 'Új kérés létrehozása',
|
||||
'Portal:ChangeMyPassword' => 'Jelszó változtatás',
|
||||
'Portal:Disconnect' => 'Kilépés',
|
||||
'Portal:OpenRequests' => 'Nyitott kéréseim',
|
||||
'Portal:ClosedRequests' => 'My closed requests',
|
||||
'Portal:ResolvedRequests' => 'Megoldott kéréseim',
|
||||
'Portal:SelectService' => 'Válasszon szolgáltatást a katalógusból:',
|
||||
'Portal:PleaseSelectOneService' => 'Kérem válasszon egy szolgáltatást',
|
||||
@@ -726,7 +731,10 @@ Akció kiváltó okhoz rendelésekor kap egy sorszámot , amely meghatározza az
|
||||
'Portal:DescriptionOfTheRequest' => 'Adja meg a kérés leírásást:',
|
||||
'Portal:TitleRequestDetailsFor_Request' => '%1$s kérés részletei:',
|
||||
'Portal:NoOpenRequest' => 'A kategóriához nem tartozik nyitott kérés.',
|
||||
'Portal:NoClosedRequest' => 'No request in this category',
|
||||
'Portal:Button:ReopenTicket' => 'Reopen this ticket',
|
||||
'Portal:Button:CloseTicket' => 'Hibajegy lezárása',
|
||||
'Portal:Button:UpdateRequest' => 'Update the request',
|
||||
'Portal:EnterYourCommentsOnTicket' => 'Adjon megjegyzést a megoldáshoz:',
|
||||
'Portal:ErrorNoContactForThisUser' => 'Hiba: az aktuális felhasználó nem tartozik egyetlen Kapcsolattartóhoz / Szemályhez sem. Kérem vegye felk a kapcsolatot az adminisztrátorral.',
|
||||
'Portal:Attachments' => 'Csatolmányok',
|
||||
|
||||
@@ -1,485 +1,485 @@
|
||||
<?php
|
||||
// Copyright (C) 2010 Combodo SARL
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation; version 3 of the License.
|
||||
//
|
||||
// This program 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 General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
/**
|
||||
<?php
|
||||
// Copyright (C) 2010 Combodo SARL
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation; version 3 of the License.
|
||||
//
|
||||
// This program 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 General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
/**
|
||||
* @author Erwan Taloc <erwan.taloc@combodo.com>
|
||||
* @author Romain Quetiez <romain.quetiez@combodo.com>
|
||||
* @author Denis Flaven <denis.flaven@combodo.com>
|
||||
|
||||
* @licence http://www.opensource.org/licenses/gpl-3.0.html LGPL
|
||||
*/
|
||||
|
||||
Dict::Add('IT IT', 'Italian', 'Italiano', array(
|
||||
'Class:ActionEmail' => 'E-mail di notifica',
|
||||
'Class:ActionEmail+' => '',
|
||||
'Class:ActionEmail/Attribute:test_recipient' => 'Test destinatario',
|
||||
'Class:ActionEmail/Attribute:test_recipient+' => '',
|
||||
'Class:ActionEmail/Attribute:from' => 'Da',
|
||||
'Class:ActionEmail/Attribute:from+' => '',
|
||||
'Class:ActionEmail/Attribute:reply_to' => 'Rispondi A',
|
||||
'Class:ActionEmail/Attribute:reply_to+' => '',
|
||||
'Class:ActionEmail/Attribute:to' => 'A',
|
||||
'Class:ActionEmail/Attribute:to+' => '',
|
||||
'Class:ActionEmail/Attribute:cc' => 'Cc',
|
||||
'Class:ActionEmail/Attribute:cc+' => '',
|
||||
'Class:ActionEmail/Attribute:bcc' => 'BCC',
|
||||
'Class:ActionEmail/Attribute:bcc+' => '',
|
||||
'Class:ActionEmail/Attribute:subject' => 'Oggetto',
|
||||
'Class:ActionEmail/Attribute:subject+' => '',
|
||||
'Class:ActionEmail/Attribute:body' => 'corpo',
|
||||
'Class:ActionEmail/Attribute:body+' => '',
|
||||
'Class:ActionEmail/Attribute:importance' => 'priorità',
|
||||
'Class:ActionEmail/Attribute:importance+' => '',
|
||||
'Class:ActionEmail/Attribute:importance/Value:high' => 'alta',
|
||||
'Class:ActionEmail/Attribute:importance/Value:high+' => '',
|
||||
'Class:ActionEmail/Attribute:importance/Value:low' => 'bassa',
|
||||
'Class:ActionEmail/Attribute:importance/Value:low+' => '',
|
||||
'Class:ActionEmail/Attribute:importance/Value:normal' => 'normake',
|
||||
'Class:ActionEmail/Attribute:importance/Value:normal+' => '',
|
||||
'Class:TriggerOnStateEnter' => 'Trigger (sull\'entrare in uno stato)',
|
||||
'Class:TriggerOnStateEnter+' => '',
|
||||
'Class:TriggerOnStateLeave' => 'Trigger (sul lasciare uno stato)~~',
|
||||
'Class:TriggerOnStateLeave+' => '',
|
||||
'Class:TriggerOnObjectCreate' => 'Trigger (sulla creazione di un oggetto)~~',
|
||||
'Class:TriggerOnObjectCreate+' => '',
|
||||
'Class:lnkTriggerAction' => 'Azione/Trigger~~',
|
||||
'Class:lnkTriggerAction+' => '',
|
||||
'Class:lnkTriggerAction/Attribute:action_id' => 'Azione',
|
||||
'Class:lnkTriggerAction/Attribute:action_id+' => '',
|
||||
'Class:lnkTriggerAction/Attribute:trigger_id' => 'Trigger',
|
||||
'Class:lnkTriggerAction/Attribute:trigger_id+' => '',
|
||||
'Class:lnkTriggerAction/Attribute:order' => 'Ordine',
|
||||
'Class:lnkTriggerAction/Attribute:order+' => '',
|
||||
'Class:AsyncSendEmail' => 'Email (asincrona)',
|
||||
'Class:AsyncSendEmail/Attribute:to' => 'A',
|
||||
'Class:AsyncSendEmail/Attribute:subject' => 'Oggetto',
|
||||
'Class:AsyncSendEmail/Attribute:body' => 'Corpo',
|
||||
'Class:AsyncSendEmail/Attribute:header' => 'Intestazione',
|
||||
'Class:CMDBChange' => 'Cambio',
|
||||
'Class:CMDBChange+' => '',
|
||||
'Class:CMDBChange/Attribute:date' => 'data',
|
||||
'Class:CMDBChange/Attribute:date+' => '',
|
||||
'Class:CMDBChange/Attribute:userinfo' => 'info varie',
|
||||
'Class:CMDBChange/Attribute:userinfo+' => '',
|
||||
'Class:CMDBChangeOp' => 'Operazione di Cambio',
|
||||
'Class:CMDBChangeOp+' => '',
|
||||
'Class:CMDBChangeOp/Attribute:change' => 'cambio',
|
||||
'Class:CMDBChangeOp/Attribute:change+' => '',
|
||||
'Class:CMDBChangeOp/Attribute:objclass' => 'oggetto della classe',
|
||||
'Class:CMDBChangeOp/Attribute:objclass+' => '',
|
||||
'Class:CMDBChangeOp/Attribute:objkey' => 'oggetto id',
|
||||
'Class:CMDBChangeOp/Attribute:objkey+' => '',
|
||||
'Class:CMDBChangeOp/Attribute:finalclass' => 'tipo',
|
||||
'Class:CMDBChangeOp/Attribute:finalclass+' => '',
|
||||
'Class:CMDBChangeOpCreate' => 'creazione dell\'oggetto',
|
||||
'Class:CMDBChangeOpCreate+' => '',
|
||||
'Class:CMDBChangeOpDelete' => 'cancellazione dell\'oggetto',
|
||||
'Class:CMDBChangeOpDelete+' => '',
|
||||
'Class:CMDBChangeOpSetAttribute' => 'cambio dell\'oggetto',
|
||||
'Class:CMDBChangeOpSetAttribute+' => '',
|
||||
'Class:CMDBChangeOpSetAttribute/Attribute:attcode' => 'Attributo',
|
||||
'Class:CMDBChangeOpSetAttribute/Attribute:attcode+' => '',
|
||||
'Class:CMDBChangeOpSetAttributeScalar' => 'cambio della proprietà',
|
||||
'Class:CMDBChangeOpSetAttributeScalar+' => '',
|
||||
'Class:CMDBChangeOpSetAttributeScalar/Attribute:oldvalue' => 'Valore precedente',
|
||||
'Class:CMDBChangeOpSetAttributeScalar/Attribute:oldvalue+' => '',
|
||||
'Class:CMDBChangeOpSetAttributeScalar/Attribute:newvalue' => 'Valore Nuovo',
|
||||
'Class:CMDBChangeOpSetAttributeScalar/Attribute:newvalue+' => '',
|
||||
'Class:CMDBChangeOpSetAttributeBlob' => 'modifica i dati',
|
||||
'Class:CMDBChangeOpSetAttributeBlob+' => '',
|
||||
'Class:CMDBChangeOpSetAttributeBlob/Attribute:prevdata' => 'Dati precedenti',
|
||||
'Class:CMDBChangeOpSetAttributeBlob/Attribute:prevdata+' => '',
|
||||
'Class:CMDBChangeOpSetAttributeOneWayPassword' => 'Password criptata',
|
||||
'Class:CMDBChangeOpSetAttributeOneWayPassword/Attribute:prev_pwd' => 'Valore Precedente',
|
||||
'Class:CMDBChangeOpSetAttributeEncrypted' => 'Encrypted Field~~',
|
||||
'Class:CMDBChangeOpSetAttributeEncrypted/Attribute:prevstring' => 'Valore Precedente',
|
||||
'Class:CMDBChangeOpSetAttributeText' => 'modifica testo',
|
||||
'Class:CMDBChangeOpSetAttributeText+' => '',
|
||||
'Class:CMDBChangeOpSetAttributeText/Attribute:prevdata' => 'Dati precendenti',
|
||||
'Class:CMDBChangeOpSetAttributeText/Attribute:prevdata+' => '',
|
||||
'Class:CMDBChangeOpSetAttributeCaseLog' => 'Log dei casi',
|
||||
'Class:CMDBChangeOpSetAttributeCaseLog/Attribute:lastentry' => 'Ultima entrata',
|
||||
'Class:Event' => 'Log dell\'evento',
|
||||
'Class:Event+' => '',
|
||||
'Class:Event/Attribute:message' => 'Messaggio',
|
||||
'Class:Event/Attribute:message+' => '',
|
||||
'Class:Event/Attribute:date' => 'Data',
|
||||
'Class:Event/Attribute:date+' => '',
|
||||
'Class:Event/Attribute:userinfo' => 'Info Utente',
|
||||
'Class:Event/Attribute:userinfo+' => '',
|
||||
'Class:Event/Attribute:finalclass' => 'Tipo',
|
||||
'Class:Event/Attribute:finalclass+' => '',
|
||||
'Class:EventNotification' => 'Notifica dell\'evento',
|
||||
'Class:EventNotification+' => '',
|
||||
'Class:EventNotification/Attribute:trigger_id' => 'Trigger',
|
||||
'Class:EventNotification/Attribute:trigger_id+' => '',
|
||||
'Class:EventNotification/Attribute:action_id' => 'utente',
|
||||
'Class:EventNotification/Attribute:action_id+' => '',
|
||||
'Class:EventNotification/Attribute:object_id' => 'Oggetto id',
|
||||
'Class:EventNotification/Attribute:object_id+' => '',
|
||||
'Class:EventNotificationEmail' => 'Email caso di emissione',
|
||||
'Class:EventNotificationEmail+' => '',
|
||||
'Class:EventNotificationEmail/Attribute:to' => 'A',
|
||||
'Class:EventNotificationEmail/Attribute:to+' => '',
|
||||
'Class:EventNotificationEmail/Attribute:cc' => 'CC',
|
||||
'Class:EventNotificationEmail/Attribute:cc+' => '',
|
||||
'Class:EventNotificationEmail/Attribute:bcc' => 'BCC',
|
||||
'Class:EventNotificationEmail/Attribute:bcc+' => '',
|
||||
'Class:EventNotificationEmail/Attribute:from' => 'Da',
|
||||
'Class:EventNotificationEmail/Attribute:from+' => '',
|
||||
'Class:EventNotificationEmail/Attribute:subject' => 'Oggeto',
|
||||
'Class:EventNotificationEmail/Attribute:subject+' => '',
|
||||
'Class:EventNotificationEmail/Attribute:body' => 'Corpo',
|
||||
'Class:EventNotificationEmail/Attribute:body+' => '',
|
||||
'Class:EventIssue' => 'Evento Problema',
|
||||
'Class:EventIssue+' => '',
|
||||
'Class:EventIssue/Attribute:issue' => 'Problema',
|
||||
'Class:EventIssue/Attribute:issue+' => '',
|
||||
'Class:EventIssue/Attribute:impact' => 'Impatto',
|
||||
'Class:EventIssue/Attribute:impact+' => '',
|
||||
'Class:EventIssue/Attribute:page' => 'Pagina',
|
||||
'Class:EventIssue/Attribute:page+' => '',
|
||||
'Class:EventIssue/Attribute:arguments_post' => 'Argomenti inviati',
|
||||
'Class:EventIssue/Attribute:arguments_post+' => '',
|
||||
'Class:EventIssue/Attribute:arguments_get' => 'Argomenti URL',
|
||||
'Class:EventIssue/Attribute:arguments_get+' => '',
|
||||
'Class:EventIssue/Attribute:callstack' => 'Callstack',
|
||||
'Class:EventIssue/Attribute:callstack+' => '',
|
||||
'Class:EventIssue/Attribute:data' => 'Dati',
|
||||
'Class:EventIssue/Attribute:data+' => '',
|
||||
'Class:EventWebService' => 'Evento Servizio Web',
|
||||
'Class:EventWebService+' => '',
|
||||
'Class:EventWebService/Attribute:verb' => 'Verbo',
|
||||
'Class:EventWebService/Attribute:verb+' => '',
|
||||
'Class:EventWebService/Attribute:result' => 'Resulto',
|
||||
'Class:EventWebService/Attribute:result+' => '',
|
||||
'Class:EventWebService/Attribute:log_info' => 'Log delle info',
|
||||
'Class:EventWebService/Attribute:log_info+' => '',
|
||||
'Class:EventWebService/Attribute:log_warning' => 'Log dei warning',
|
||||
'Class:EventWebService/Attribute:log_warning+' => '',
|
||||
'Class:EventWebService/Attribute:log_error' => 'Log degli errori',
|
||||
'Class:EventWebService/Attribute:log_error+' => '',
|
||||
'Class:EventWebService/Attribute:data' => 'Dati',
|
||||
'Class:EventWebService/Attribute:data+' => '',
|
||||
'Class:EventLoginUsage' => 'Login di utilizzo',
|
||||
'Class:EventLoginUsage+' => '',
|
||||
'Class:EventLoginUsage/Attribute:user_id' => 'Login',
|
||||
'Class:EventLoginUsage/Attribute:user_id+' => '',
|
||||
'Class:SynchroDataSource' => 'Sorgente di sincronizzazione dei dati',
|
||||
'Class:SynchroDataSource/Attribute:name' => 'Nome',
|
||||
'Class:SynchroDataSource/Attribute:name+' => '',
|
||||
'Class:SynchroDataSource/Attribute:description' => 'Descrizione',
|
||||
'Class:SynchroDataSource/Attribute:status' => 'Stato',
|
||||
'Class:SynchroDataSource/Attribute:status/Value:implementation' => 'Implementazione',
|
||||
'Class:SynchroDataSource/Attribute:status/Value:obsolete' => 'Obsoleto',
|
||||
'Class:SynchroDataSource/Attribute:status/Value:production' => 'Produzione',
|
||||
'Class:SynchroDataSource/Attribute:user_id' => 'Utente',
|
||||
'Class:SynchroDataSource/Attribute:scope_class' => 'Classe Target',
|
||||
'Class:SynchroDataSource/Attribute:scope_restriction' => 'Campo di applicazione restrizione',
|
||||
'Class:SynchroDataSource/Attribute:full_load_periodicity' => 'Intervallo a pieno carico',
|
||||
'Class:SynchroDataSource/Attribute:full_load_periodicity+' => '',
|
||||
'Class:SynchroDataSource/Attribute:reconciliation_policy' => 'Policy di riconciliazione',
|
||||
'Class:SynchroDataSource/Attribute:reconciliation_policy/Value:use_attributes' => 'Usa gli attributi',
|
||||
'Class:SynchroDataSource/Attribute:reconciliation_policy/Value:use_primary_key' => 'Usa il campo chiave primaria',
|
||||
'Class:SynchroDataSource/Attribute:action_on_zero' => 'Azione su zero~~',
|
||||
'Class:SynchroDataSource/Attribute:action_on_zero+' => '',
|
||||
'Class:SynchroDataSource/Attribute:action_on_zero/Value:create' => 'Crea',
|
||||
'Class:SynchroDataSource/Attribute:action_on_zero/Value:error' => 'Errore',
|
||||
'Class:SynchroDataSource/Attribute:action_on_one' => 'Azione su uno',
|
||||
'Class:SynchroDataSource/Attribute:action_on_one+' => '',
|
||||
'Class:SynchroDataSource/Attribute:action_on_one/Value:error' => 'Error',
|
||||
'Class:SynchroDataSource/Attribute:action_on_one/Value:update' => 'Aggiorna',
|
||||
'Class:SynchroDataSource/Attribute:action_on_multiple' => 'Azione su molti',
|
||||
'Class:SynchroDataSource/Attribute:action_on_multiple+' => '',
|
||||
'Class:SynchroDataSource/Attribute:action_on_multiple/Value:create' => 'Crea',
|
||||
'Class:SynchroDataSource/Attribute:action_on_multiple/Value:error' => 'Errore',
|
||||
'Class:SynchroDataSource/Attribute:action_on_multiple/Value:take_first' => 'Considera il primo (random?)',
|
||||
'Class:SynchroDataSource/Attribute:delete_policy' => 'Policy di cancellazioen',
|
||||
'Class:SynchroDataSource/Attribute:delete_policy/Value:delete' => 'Cancella',
|
||||
'Class:SynchroDataSource/Attribute:delete_policy/Value:ignore' => 'Ignora',
|
||||
'Class:SynchroDataSource/Attribute:delete_policy/Value:update' => 'Aggiorna',
|
||||
'Class:SynchroDataSource/Attribute:delete_policy/Value:update_then_delete' => 'Aggiorna e poi Cancella',
|
||||
'Class:SynchroDataSource/Attribute:delete_policy_update' => 'Regole per l\'aggiornamento',
|
||||
'Class:SynchroDataSource/Attribute:delete_policy_update+' => '',
|
||||
'Class:SynchroDataSource/Attribute:delete_policy_retention' => 'Durata di conservazione',
|
||||
'Class:SynchroDataSource/Attribute:delete_policy_retention+' => '',
|
||||
'Class:SynchroDataSource/Attribute:attribute_list' => 'Lista degli attributi',
|
||||
'Class:SynchroDataSource/Attribute:user_delete_policy' => 'utenti autorizzati',
|
||||
'Class:SynchroDataSource/Attribute:user_delete_policy+' => '',
|
||||
'Class:SynchroDataSource/Attribute:user_delete_policy/Value:administrators' => 'Solo Amministratore',
|
||||
'Class:SynchroDataSource/Attribute:user_delete_policy/Value:everybody' => 'Tutti sono autorizzati a cancellare questi oggetti',
|
||||
'Class:SynchroDataSource/Attribute:user_delete_policy/Value:nobody' => 'Nessuno',
|
||||
'Class:SynchroDataSource/Attribute:url_icon' => 'Icona di collegamento ipertestuale',
|
||||
'Class:SynchroDataSource/Attribute:url_icon+' => '',
|
||||
'Class:SynchroDataSource/Attribute:url_application' => 'Collegamento ipertestuale all\'applicazione',
|
||||
'Class:SynchroDataSource/Attribute:url_application+' => '',
|
||||
'Class:SynchroAttribute' => 'Attributo di sincronizzazione',
|
||||
'Class:SynchroAttribute/Attribute:sync_source_id' => 'Sorgente sincronizzazione dati',
|
||||
'Class:SynchroAttribute/Attribute:attcode' => 'Codice attributo',
|
||||
'Class:SynchroAttribute/Attribute:update' => 'Aggiorna',
|
||||
'Class:SynchroAttribute/Attribute:reconcile' => 'Rincocilia',
|
||||
'Class:SynchroAttribute/Attribute:update_policy' => 'Policy di aggiornamento',
|
||||
'Class:SynchroAttribute/Attribute:update_policy/Value:master_locked' => 'Bloccato',
|
||||
'Class:SynchroAttribute/Attribute:update_policy/Value:master_unlocked' => 'Sbloccato',
|
||||
'Class:SynchroAttribute/Attribute:update_policy/Value:write_if_empty' => 'Inizializza se vuoto',
|
||||
'Class:SynchroAttribute/Attribute:finalclass' => 'Classe',
|
||||
'Class:SynchroAttExtKey' => 'Attributo di sincronizzazione (ExtKey)',
|
||||
'Class:SynchroAttExtKey/Attribute:reconciliation_attcode' => 'Attributo di riconciliazione',
|
||||
'Class:SynchroAttLinkSet' => 'Attributo di sincronizzazione (Linkset)',
|
||||
'Class:SynchroAttLinkSet/Attribute:row_separator' => 'Separatore di righe',
|
||||
'Class:SynchroAttLinkSet/Attribute:attribute_separator' => 'Separatore di attributi',
|
||||
'Class:SynchroLog' => 'Log di sincronizzazione',
|
||||
'Class:SynchroLog/Attribute:sync_source_id' => 'Sorgente di sincronizzazione dati',
|
||||
'Class:SynchroLog/Attribute:start_date' => 'Data di inizio',
|
||||
'Class:SynchroLog/Attribute:end_date' => 'Data di fine',
|
||||
'Class:SynchroLog/Attribute:status' => 'Stato',
|
||||
'Class:SynchroLog/Attribute:status/Value:completed' => 'Completo',
|
||||
'Class:SynchroLog/Attribute:status/Value:error' => 'Errore',
|
||||
'Class:SynchroLog/Attribute:status/Value:running' => 'Ancora in esecuzione',
|
||||
'Class:SynchroLog/Attribute:stats_nb_replica_seen' => 'Nb replica viste',
|
||||
'Class:SynchroLog/Attribute:stats_nb_replica_total' => 'Nb replica totale',
|
||||
'Class:SynchroLog/Attribute:stats_nb_obj_deleted' => 'Nb oggetti cancellati',
|
||||
'Class:SynchroLog/Attribute:stats_nb_obj_deleted_errors' => 'Nb di errore durante la cancellazione',
|
||||
'Class:SynchroLog/Attribute:stats_nb_obj_obsoleted' => 'Nb oggetti obsoleti',
|
||||
'Class:SynchroLog/Attribute:stats_nb_obj_obsoleted_errors' => 'Nb di errori mentre obsoleta',
|
||||
'Class:SynchroLog/Attribute:stats_nb_obj_created' => 'Nb oggetti creati',
|
||||
'Class:SynchroLog/Attribute:stats_nb_obj_created_errors' => 'Nb di errori durante la creazione',
|
||||
'Class:SynchroLog/Attribute:stats_nb_obj_updated' => 'Nb oggetti aggiornati',
|
||||
'Class:SynchroLog/Attribute:stats_nb_obj_updated_errors' => 'Nb di errori durante l\'aggiornamento',
|
||||
'Class:SynchroLog/Attribute:stats_nb_replica_reconciled_errors' => 'Nb di errori durante la riconcilazione',
|
||||
'Class:SynchroLog/Attribute:stats_nb_replica_disappeared_no_action' => 'Nb repliche scomparse',
|
||||
'Class:SynchroLog/Attribute:stats_nb_obj_new_updated' => 'Nb oggetti aggiornati',
|
||||
'Class:SynchroLog/Attribute:stats_nb_obj_new_unchanged' => 'Nb oggetti non modificati',
|
||||
'Class:SynchroLog/Attribute:last_error' => 'Untimo errore',
|
||||
'Class:SynchroLog/Attribute:traces' => 'Tracce',
|
||||
'Class:SynchroReplica' => 'Replica sincronizzazione',
|
||||
'Class:SynchroReplica/Attribute:sync_source_id' => 'Sorgente di sincronizzazione dati',
|
||||
'Class:SynchroReplica/Attribute:dest_id' => 'Oggetto di destinazione (ID)~~',
|
||||
'Class:SynchroReplica/Attribute:dest_class' => 'Tipo di destinazione',
|
||||
'Class:SynchroReplica/Attribute:status_last_seen' => 'Ultimo visto',
|
||||
'Class:SynchroReplica/Attribute:status' => 'Stato',
|
||||
'Class:SynchroReplica/Attribute:status/Value:modified' => 'Modificato',
|
||||
'Class:SynchroReplica/Attribute:status/Value:new' => 'Nuovo',
|
||||
'Class:SynchroReplica/Attribute:status/Value:obsolete' => 'Obsoleto',
|
||||
'Class:SynchroReplica/Attribute:status/Value:orphan' => 'Orfano',
|
||||
'Class:SynchroReplica/Attribute:status/Value:synchronized' => 'Sincronizzato',
|
||||
'Class:SynchroReplica/Attribute:status_dest_creator' => 'Oggetto Creato ?',
|
||||
'Class:SynchroReplica/Attribute:status_last_error' => 'Ultimo Errore',
|
||||
'Class:SynchroReplica/Attribute:info_creation_date' => 'Data di creazione',
|
||||
'Class:SynchroReplica/Attribute:info_last_modified' => 'Data ultima modifica',
|
||||
'Class:appUserPreferences' => 'Preferenze utente',
|
||||
'Class:appUserPreferences/Attribute:userid' => 'Utente',
|
||||
'Class:appUserPreferences/Attribute:preferences' => 'Preferenze',
|
||||
'Core:AttributeLinkedSet' => 'Array di oggetti',
|
||||
'Core:AttributeLinkedSet+' => '',
|
||||
'Core:AttributeLinkedSetIndirect' => 'Array di oggetti (N-N)',
|
||||
'Core:AttributeLinkedSetIndirect+' => '',
|
||||
'Core:AttributeInteger' => 'Integero',
|
||||
'Core:AttributeInteger+' => '',
|
||||
'Core:AttributeDecimal' => 'Decimale',
|
||||
'Core:AttributeDecimal+' => '',
|
||||
'Core:AttributeBoolean' => 'Booleano',
|
||||
'Core:AttributeBoolean+' => '',
|
||||
'Core:AttributeString' => 'Stringa',
|
||||
'Core:AttributeString+' => '',
|
||||
'Core:AttributeClass' => 'Classe',
|
||||
'Core:AttributeClass+' => '',
|
||||
'Core:AttributeApplicationLanguage' => 'Linguaggio Utente',
|
||||
'Core:AttributeApplicationLanguage+' => '',
|
||||
'Core:AttributeFinalClass' => 'Classe (auto)',
|
||||
'Core:AttributeFinalClass+' => '',
|
||||
'Core:AttributePassword' => 'Password',
|
||||
'Core:AttributePassword+' => '',
|
||||
'Core:AttributeEncryptedString' => 'Stringa criptata',
|
||||
'Core:AttributeEncryptedString+' => '',
|
||||
'Core:AttributeText' => 'Testo',
|
||||
'Core:AttributeText+' => '',
|
||||
'Core:AttributeHTML' => 'HTML',
|
||||
'Core:AttributeHTML+' => '',
|
||||
'Core:AttributeEmailAddress' => 'Indirizzo Email',
|
||||
'Core:AttributeEmailAddress+' => '',
|
||||
'Core:AttributeIPAddress' => 'Indirizzo IP',
|
||||
'Core:AttributeIPAddress+' => '',
|
||||
'Core:AttributeOQL' => 'OQL',
|
||||
'Core:AttributeOQL+' => '',
|
||||
'Core:AttributeEnum' => 'Enum',
|
||||
'Core:AttributeEnum+' => '',
|
||||
'Core:AttributeTemplateString' => 'Stringa Template',
|
||||
'Core:AttributeTemplateString+' => '',
|
||||
'Core:AttributeTemplateText' => 'Testo Template',
|
||||
'Core:AttributeTemplateText+' => '',
|
||||
'Core:AttributeTemplateHTML' => 'HTML Template',
|
||||
'Core:AttributeTemplateHTML+' => '',
|
||||
'Core:AttributeDateTime' => 'Data/ora',
|
||||
'Core:AttributeDateTime+' => '',
|
||||
'Core:AttributeDate' => 'Data',
|
||||
'Core:AttributeDate+' => '',
|
||||
'Core:AttributeDeadline' => 'Scadenza',
|
||||
'Core:AttributeDeadline+' => '',
|
||||
'Core:AttributeExternalKey' => 'Chiave esterna',
|
||||
'Core:AttributeExternalKey+' => '',
|
||||
'Core:AttributeExternalField' => 'Campo esterno',
|
||||
'Core:AttributeExternalField+' => '',
|
||||
'Core:AttributeURL' => 'URL',
|
||||
'Core:AttributeURL+' => '',
|
||||
'Core:AttributeBlob' => 'Blob',
|
||||
'Core:AttributeBlob+' => '',
|
||||
'Core:AttributeOneWayPassword' => 'Password unidierzionale',
|
||||
'Core:AttributeOneWayPassword+' => '',
|
||||
'Core:AttributeTable' => 'Tabella',
|
||||
'Core:AttributeTable+' => '',
|
||||
'Core:AttributePropertySet' => 'Proprietà',
|
||||
'Core:AttributePropertySet+' => '',
|
||||
'Class:CMDBChangeOp/Attribute:date' => 'data',
|
||||
'Class:CMDBChangeOp/Attribute:date+' => '',
|
||||
'Class:CMDBChangeOp/Attribute:userinfo' => 'utente',
|
||||
'Class:CMDBChangeOp/Attribute:userinfo+' => '',
|
||||
'Change:ObjectCreated' => 'Oggetto creato',
|
||||
'Change:ObjectDeleted' => 'Oggetto cancellato',
|
||||
'Change:ObjectModified' => 'Object modificato',
|
||||
'Change:AttName_SetTo_NewValue_PreviousValue_OldValue' => '%1$s imposatato a %2$s (valore precendente: %3$s)',
|
||||
'Change:AttName_SetTo' => '%1$s impostato a %2$s~~',
|
||||
'Change:Text_AppendedTo_AttName' => '%1$s allegato a %2$s~~',
|
||||
'Change:AttName_Changed_PreviousValue_OldValue' => '%1$s moficato, valore precendente: %2$s',
|
||||
'Change:AttName_Changed' => '%1$s modificato',
|
||||
'Change:AttName_EntryAdded' => '%1$s modificato, nuova entrata aggiunta.',
|
||||
'Class:EventLoginUsage/Attribute:contact_name' => 'Nome Utente',
|
||||
'Class:EventLoginUsage/Attribute:contact_name+' => '',
|
||||
'Class:EventLoginUsage/Attribute:contact_email' => 'Email Utente',
|
||||
'Class:EventLoginUsage/Attribute:contact_email+' => '',
|
||||
'Class:Action' => 'Azione personalizzata',
|
||||
'Class:Action+' => '',
|
||||
'Class:Action/Attribute:name' => 'Nome',
|
||||
'Class:Action/Attribute:name+' => '',
|
||||
'Class:Action/Attribute:description' => 'Descrizione',
|
||||
'Class:Action/Attribute:description+' => '',
|
||||
'Class:Action/Attribute:status' => 'Stato',
|
||||
'Class:Action/Attribute:status+' => '',
|
||||
'Class:Action/Attribute:status/Value:test' => 'In fase di test',
|
||||
'Class:Action/Attribute:status/Value:test+' => '',
|
||||
'Class:Action/Attribute:status/Value:enabled' => 'In produzione',
|
||||
'Class:Action/Attribute:status/Value:enabled+' => '',
|
||||
'Class:Action/Attribute:status/Value:disabled' => 'Inattivo',
|
||||
'Class:Action/Attribute:status/Value:disabled+' => '',
|
||||
'Class:Action/Attribute:trigger_list' => 'Trigger Correlati',
|
||||
'Class:Action/Attribute:trigger_list+' => '',
|
||||
'Class:Action/Attribute:finalclass' => 'Tipo',
|
||||
'Class:Action/Attribute:finalclass+' => '',
|
||||
'Class:ActionNotification' => 'Notifica',
|
||||
'Class:ActionNotification+' => '',
|
||||
'Class:Trigger' => 'Trigger',
|
||||
'Class:Trigger+' => '',
|
||||
'Class:Trigger/Attribute:description' => 'Descrizione',
|
||||
'Class:Trigger/Attribute:description+' => '',
|
||||
'Class:Trigger/Attribute:action_list' => 'Azioni Triggerate',
|
||||
'Class:Trigger/Attribute:action_list+' => '',
|
||||
'Class:Trigger/Attribute:finalclass' => 'Tipo',
|
||||
'Class:Trigger/Attribute:finalclass+' => '',
|
||||
'Class:TriggerOnObject' => 'Trigger (classe dipendente)',
|
||||
'Class:TriggerOnObject+' => '',
|
||||
'Class:TriggerOnObject/Attribute:target_class' => 'Classe Target',
|
||||
'Class:TriggerOnObject/Attribute:target_class+' => '',
|
||||
'Class:TriggerOnStateChange' => 'Trigger (sul cambio di stato)',
|
||||
'Class:TriggerOnStateChange+' => '',
|
||||
'Class:TriggerOnStateChange/Attribute:state' => 'Stato',
|
||||
'Class:TriggerOnStateChange/Attribute:state+' => '',
|
||||
'Class:lnkTriggerAction/Attribute:action_name' => 'Azione',
|
||||
'Class:lnkTriggerAction/Attribute:action_name+' => '',
|
||||
'Class:lnkTriggerAction/Attribute:trigger_name' => 'Trigger',
|
||||
'Class:lnkTriggerAction/Attribute:trigger_name+' => '',
|
||||
'Class:SynchroDataSource/Attribute:delete_policy/Value:never' => 'Nessuno',
|
||||
'Class:SynchroDataSource/Attribute:delete_policy/Value:depends' => 'Solo Amministratore',
|
||||
'Class:SynchroDataSource/Attribute:delete_policy/Value:always' => 'Tutti gli utenti autorizzati',
|
||||
'SynchroDataSource:Description' => 'Descrizione',
|
||||
'SynchroDataSource:Reconciliation' => 'Ricerca & riconciliazione',
|
||||
'SynchroDataSource:Deletion' => 'Regole di cancellazione',
|
||||
'SynchroDataSource:Status' => 'Stato',
|
||||
'SynchroDataSource:Information' => 'Informazione',
|
||||
'SynchroDataSource:Definition' => 'Definizione',
|
||||
'Core:SynchroAttributes' => 'Attributi',
|
||||
'Core:SynchroStatus' => 'Stato',
|
||||
'Core:Synchro:ErrorsLabel' => 'Errori',
|
||||
'Core:Synchro:CreatedLabel' => 'Creato',
|
||||
'Core:Synchro:ModifiedLabel' => 'Modificato',
|
||||
'Core:Synchro:UnchangedLabel' => 'Non modificato',
|
||||
'Core:Synchro:ReconciledErrorsLabel' => 'Errori',
|
||||
'Core:Synchro:ReconciledLabel' => 'Reconciliato',
|
||||
'Core:Synchro:ReconciledNewLabel' => 'Creato',
|
||||
'Core:SynchroReconcile:Yes' => 'Si',
|
||||
'Core:SynchroReconcile:No' => 'No',
|
||||
'Core:SynchroUpdate:Yes' => 'Si',
|
||||
'Core:SynchroUpdate:No' => 'No',
|
||||
'Core:Synchro:LastestStatus' => 'Ultimo stato',
|
||||
'Core:Synchro:History' => 'Storia della sincronizzazione',
|
||||
'Core:Synchro:NeverRun' => 'Questa sincronizzazione non è mai stata eseguita. Nessun Log ancora...',
|
||||
'Core:Synchro:SynchroEndedOn_Date' => 'L\'ultima sincronizzazione si è conclusa il %1$s.~~',
|
||||
'Core:Synchro:SynchroRunningStartedOn_Date' => 'La sincronizzazione è iniziata il $1$s è ancora in esecuzione...~~',
|
||||
'Menu:DataSources' => 'Sorgente di sincronizzazione dei dati',
|
||||
'Menu:DataSources+' => '',
|
||||
'Core:Synchro:label_repl_ignored' => 'Ignorato(%1$s)',
|
||||
'Core:Synchro:label_repl_disappeared' => 'Scomparso (%1$s)',
|
||||
'Core:Synchro:label_repl_existing' => 'Esistente (%1$s)',
|
||||
'Core:Synchro:label_repl_new' => 'Nuovo (%1$s)~~',
|
||||
'Core:Synchro:label_obj_deleted' => 'Cancellato (%1$s)',
|
||||
'Core:Synchro:label_obj_obsoleted' => 'Obsoleto (%1$s)',
|
||||
'Core:Synchro:label_obj_disappeared_errors' => 'Errori (%1$s)',
|
||||
'Core:Synchro:label_obj_disappeared_no_action' => 'Nessuna Azione (%1$s)',
|
||||
'Core:Synchro:label_obj_unchanged' => 'Non modificato(%1$s)',
|
||||
'Core:Synchro:label_obj_updated' => 'Aggiornato (%1$s)',
|
||||
'Core:Synchro:label_obj_updated_errors' => 'Errori (%1$s)',
|
||||
'Core:Synchro:label_obj_new_unchanged' => 'Non modificato (%1$s)',
|
||||
'Core:Synchro:label_obj_new_updated' => 'Aggiornato (%1$s)',
|
||||
'Core:Synchro:label_obj_created' => 'Creato (%1$s)',
|
||||
'Core:Synchro:label_obj_new_errors' => 'Errori (%1$s)',
|
||||
'Core:SynchroLogTitle' => '%1$s - %2$s~~',
|
||||
'Core:Synchro:Nb_Replica' => 'Replica processata: %1$s',
|
||||
'Core:Synchro:Nb_Class:Objects' => '%1$s: %2$s',
|
||||
'Class:SynchroDataSource/Error:AtLeastOneReconciliationKeyMustBeSpecified' => 'Almeno una chiave riconciliazione deve essere specificata, o la policy di conciliazione deve essere quella di utilizzare la chiave primaria',
|
||||
'Class:SynchroDataSource/Error:DeleteRetentionDurationMustBeSpecified' => 'Deve essere specificato un periodo di conservazione di cancellazione , dato che gli oggetti devono essere eliminati dopo essere contrassegnati come obsoleti ',
|
||||
'Class:SynchroDataSource/Error:DeletePolicyUpdateMustBeSpecified' => 'Oggetti obsoleti devono essere aggiornati, ma nessun aggiornamento è specificato',
|
||||
'Core:SynchroReplica:PublicData' => 'Dati Pubblici',
|
||||
'Core:SynchroReplica:PrivateDetails' => 'Dettagli Privati',
|
||||
'Core:SynchroReplica:BackToDataSource' => 'Torna indietro alla sorgente di sincronizzazione dei dati: %1$s~~',
|
||||
'Core:SynchroReplica:ListOfReplicas' => 'Lista della Replica',
|
||||
'Core:SynchroAttExtKey:ReconciliationById' => 'id (Chiave Primaria)',
|
||||
'Core:SynchroAtt:attcode' => 'Attributo',
|
||||
'Core:SynchroAtt:attcode+' => '',
|
||||
'Core:SynchroAtt:reconciliation' => 'Riconciliazione ?~~',
|
||||
'Core:SynchroAtt:reconciliation+' => '',
|
||||
'Core:SynchroAtt:update' => 'Aggiornamento ?~~',
|
||||
'Core:SynchroAtt:update+' => '',
|
||||
'Core:SynchroAtt:update_policy' => 'Policy di aggiornamento',
|
||||
'Core:SynchroAtt:update_policy+' => '',
|
||||
'Core:SynchroAtt:reconciliation_attcode' => 'Chiave di riconciliazione',
|
||||
'Core:SynchroAtt:reconciliation_attcode+' => '',
|
||||
'Core:SyncDataExchangeComment' => '(Scambio dati)',
|
||||
'Core:Synchro:ListOfDataSources' => 'Lista delle sorgenti di dati:',
|
||||
'Core:Synchro:LastSynchro' => 'Ultima sincronizzazione:',
|
||||
'Core:Synchro:ThisObjectIsSynchronized' => 'Questo oggetto è sincronizzato con una sorgente esterna di dati',
|
||||
'Core:Synchro:TheObjectWasCreatedBy_Source' => 'L\'oggetti è stato <b>creato</b> da una sorgente esterna di dati %1$s~~',
|
||||
'Core:Synchro:TheObjectCanBeDeletedBy_Source' => 'L\'oggetti <b>può essere cancellato</b> da una sorgente esterna di dati %1$s~~',
|
||||
'Core:Synchro:TheObjectCannotBeDeletedByUser_Source' => 'Tu <b>non puoi cancellare l\'oggetto</b> perché è di proprietà della sorgente dati esterna %1$s~~',
|
||||
'TitleSynchroExecution' => 'Esecuzione della sincronizzazione',
|
||||
'Class:SynchroDataSource:DataTable' => 'Tabella del database: %1$s',
|
||||
'Core:SyncDataSourceObsolete' => 'La fonte dei dati è contrassegnata come obsoleta. Operazione annullata',
|
||||
'Core:SyncDataSourceAccessRestriction' => 'Solo amministratori o l\'utente specificato nella fonte dei dati può eseguire questa operazione. Operazione annullata',
|
||||
'Core:SyncTooManyMissingReplicas' => 'Tutte le repliche sono mancanti dall\'importazione. Hai eseguito realmente l\'importazione? Operazione annullata',
|
||||
'Core:Duration_Seconds' => '%1$ds',
|
||||
'Core:Duration_Minutes_Seconds' => '%1$dmin %2$ds',
|
||||
'Core:Duration_Hours_Minutes_Seconds' => '%1$dh %2$dmin %3$sec~~',
|
||||
'Core:Duration_Days_Hours_Minutes_Seconds' => '%1$sg %2$dh %3$dmin %4$ds~~',
|
||||
));
|
||||
?>
|
||||
|
||||
* @licence http://www.opensource.org/licenses/gpl-3.0.html LGPL
|
||||
*/
|
||||
|
||||
Dict::Add('IT IT', 'Italian', 'Italiano', array(
|
||||
'Class:ActionEmail' => 'E-mail di notifica',
|
||||
'Class:ActionEmail+' => '',
|
||||
'Class:ActionEmail/Attribute:test_recipient' => 'Test destinatario',
|
||||
'Class:ActionEmail/Attribute:test_recipient+' => '',
|
||||
'Class:ActionEmail/Attribute:from' => 'Da',
|
||||
'Class:ActionEmail/Attribute:from+' => '',
|
||||
'Class:ActionEmail/Attribute:reply_to' => 'Rispondi A',
|
||||
'Class:ActionEmail/Attribute:reply_to+' => '',
|
||||
'Class:ActionEmail/Attribute:to' => 'A',
|
||||
'Class:ActionEmail/Attribute:to+' => '',
|
||||
'Class:ActionEmail/Attribute:cc' => 'Cc',
|
||||
'Class:ActionEmail/Attribute:cc+' => '',
|
||||
'Class:ActionEmail/Attribute:bcc' => 'BCC',
|
||||
'Class:ActionEmail/Attribute:bcc+' => '',
|
||||
'Class:ActionEmail/Attribute:subject' => 'Oggetto',
|
||||
'Class:ActionEmail/Attribute:subject+' => '',
|
||||
'Class:ActionEmail/Attribute:body' => 'corpo',
|
||||
'Class:ActionEmail/Attribute:body+' => '',
|
||||
'Class:ActionEmail/Attribute:importance' => 'priorità',
|
||||
'Class:ActionEmail/Attribute:importance+' => '',
|
||||
'Class:ActionEmail/Attribute:importance/Value:high' => 'alta',
|
||||
'Class:ActionEmail/Attribute:importance/Value:high+' => '',
|
||||
'Class:ActionEmail/Attribute:importance/Value:low' => 'bassa',
|
||||
'Class:ActionEmail/Attribute:importance/Value:low+' => '',
|
||||
'Class:ActionEmail/Attribute:importance/Value:normal' => 'normake',
|
||||
'Class:ActionEmail/Attribute:importance/Value:normal+' => '',
|
||||
'Class:TriggerOnStateEnter' => 'Trigger (sull\'entrare in uno stato)',
|
||||
'Class:TriggerOnStateEnter+' => '',
|
||||
'Class:TriggerOnStateLeave' => 'Trigger (sul lasciare uno stato)~~',
|
||||
'Class:TriggerOnStateLeave+' => '',
|
||||
'Class:TriggerOnObjectCreate' => 'Trigger (sulla creazione di un oggetto)~~',
|
||||
'Class:TriggerOnObjectCreate+' => '',
|
||||
'Class:lnkTriggerAction' => 'Azione/Trigger~~',
|
||||
'Class:lnkTriggerAction+' => '',
|
||||
'Class:lnkTriggerAction/Attribute:action_id' => 'Azione',
|
||||
'Class:lnkTriggerAction/Attribute:action_id+' => '',
|
||||
'Class:lnkTriggerAction/Attribute:trigger_id' => 'Trigger',
|
||||
'Class:lnkTriggerAction/Attribute:trigger_id+' => '',
|
||||
'Class:lnkTriggerAction/Attribute:order' => 'Ordine',
|
||||
'Class:lnkTriggerAction/Attribute:order+' => '',
|
||||
'Class:AsyncSendEmail' => 'Email (asincrona)',
|
||||
'Class:AsyncSendEmail/Attribute:to' => 'A',
|
||||
'Class:AsyncSendEmail/Attribute:subject' => 'Oggetto',
|
||||
'Class:AsyncSendEmail/Attribute:body' => 'Corpo',
|
||||
'Class:AsyncSendEmail/Attribute:header' => 'Intestazione',
|
||||
'Class:CMDBChange' => 'Cambio',
|
||||
'Class:CMDBChange+' => '',
|
||||
'Class:CMDBChange/Attribute:date' => 'data',
|
||||
'Class:CMDBChange/Attribute:date+' => '',
|
||||
'Class:CMDBChange/Attribute:userinfo' => 'info varie',
|
||||
'Class:CMDBChange/Attribute:userinfo+' => '',
|
||||
'Class:CMDBChangeOp' => 'Operazione di Cambio',
|
||||
'Class:CMDBChangeOp+' => '',
|
||||
'Class:CMDBChangeOp/Attribute:change' => 'cambio',
|
||||
'Class:CMDBChangeOp/Attribute:change+' => '',
|
||||
'Class:CMDBChangeOp/Attribute:objclass' => 'oggetto della classe',
|
||||
'Class:CMDBChangeOp/Attribute:objclass+' => '',
|
||||
'Class:CMDBChangeOp/Attribute:objkey' => 'oggetto id',
|
||||
'Class:CMDBChangeOp/Attribute:objkey+' => '',
|
||||
'Class:CMDBChangeOp/Attribute:finalclass' => 'tipo',
|
||||
'Class:CMDBChangeOp/Attribute:finalclass+' => '',
|
||||
'Class:CMDBChangeOpCreate' => 'creazione dell\'oggetto',
|
||||
'Class:CMDBChangeOpCreate+' => '',
|
||||
'Class:CMDBChangeOpDelete' => 'cancellazione dell\'oggetto',
|
||||
'Class:CMDBChangeOpDelete+' => '',
|
||||
'Class:CMDBChangeOpSetAttribute' => 'cambio dell\'oggetto',
|
||||
'Class:CMDBChangeOpSetAttribute+' => '',
|
||||
'Class:CMDBChangeOpSetAttribute/Attribute:attcode' => 'Attributo',
|
||||
'Class:CMDBChangeOpSetAttribute/Attribute:attcode+' => '',
|
||||
'Class:CMDBChangeOpSetAttributeScalar' => 'cambio della proprietà',
|
||||
'Class:CMDBChangeOpSetAttributeScalar+' => '',
|
||||
'Class:CMDBChangeOpSetAttributeScalar/Attribute:oldvalue' => 'Valore precedente',
|
||||
'Class:CMDBChangeOpSetAttributeScalar/Attribute:oldvalue+' => '',
|
||||
'Class:CMDBChangeOpSetAttributeScalar/Attribute:newvalue' => 'Valore Nuovo',
|
||||
'Class:CMDBChangeOpSetAttributeScalar/Attribute:newvalue+' => '',
|
||||
'Class:CMDBChangeOpSetAttributeBlob' => 'modifica i dati',
|
||||
'Class:CMDBChangeOpSetAttributeBlob+' => '',
|
||||
'Class:CMDBChangeOpSetAttributeBlob/Attribute:prevdata' => 'Dati precedenti',
|
||||
'Class:CMDBChangeOpSetAttributeBlob/Attribute:prevdata+' => '',
|
||||
'Class:CMDBChangeOpSetAttributeOneWayPassword' => 'Password criptata',
|
||||
'Class:CMDBChangeOpSetAttributeOneWayPassword/Attribute:prev_pwd' => 'Valore Precedente',
|
||||
'Class:CMDBChangeOpSetAttributeEncrypted' => 'Encrypted Field~~',
|
||||
'Class:CMDBChangeOpSetAttributeEncrypted/Attribute:prevstring' => 'Valore Precedente',
|
||||
'Class:CMDBChangeOpSetAttributeText' => 'modifica testo',
|
||||
'Class:CMDBChangeOpSetAttributeText+' => '',
|
||||
'Class:CMDBChangeOpSetAttributeText/Attribute:prevdata' => 'Dati precendenti',
|
||||
'Class:CMDBChangeOpSetAttributeText/Attribute:prevdata+' => '',
|
||||
'Class:CMDBChangeOpSetAttributeCaseLog' => 'Log dei casi',
|
||||
'Class:CMDBChangeOpSetAttributeCaseLog/Attribute:lastentry' => 'Ultima entrata',
|
||||
'Class:Event' => 'Log dell\'evento',
|
||||
'Class:Event+' => '',
|
||||
'Class:Event/Attribute:message' => 'Messaggio',
|
||||
'Class:Event/Attribute:message+' => '',
|
||||
'Class:Event/Attribute:date' => 'Data',
|
||||
'Class:Event/Attribute:date+' => '',
|
||||
'Class:Event/Attribute:userinfo' => 'Info Utente',
|
||||
'Class:Event/Attribute:userinfo+' => '',
|
||||
'Class:Event/Attribute:finalclass' => 'Tipo',
|
||||
'Class:Event/Attribute:finalclass+' => '',
|
||||
'Class:EventNotification' => 'Notifica dell\'evento',
|
||||
'Class:EventNotification+' => '',
|
||||
'Class:EventNotification/Attribute:trigger_id' => 'Trigger',
|
||||
'Class:EventNotification/Attribute:trigger_id+' => '',
|
||||
'Class:EventNotification/Attribute:action_id' => 'utente',
|
||||
'Class:EventNotification/Attribute:action_id+' => '',
|
||||
'Class:EventNotification/Attribute:object_id' => 'Oggetto id',
|
||||
'Class:EventNotification/Attribute:object_id+' => '',
|
||||
'Class:EventNotificationEmail' => 'Email caso di emissione',
|
||||
'Class:EventNotificationEmail+' => '',
|
||||
'Class:EventNotificationEmail/Attribute:to' => 'A',
|
||||
'Class:EventNotificationEmail/Attribute:to+' => '',
|
||||
'Class:EventNotificationEmail/Attribute:cc' => 'CC',
|
||||
'Class:EventNotificationEmail/Attribute:cc+' => '',
|
||||
'Class:EventNotificationEmail/Attribute:bcc' => 'BCC',
|
||||
'Class:EventNotificationEmail/Attribute:bcc+' => '',
|
||||
'Class:EventNotificationEmail/Attribute:from' => 'Da',
|
||||
'Class:EventNotificationEmail/Attribute:from+' => '',
|
||||
'Class:EventNotificationEmail/Attribute:subject' => 'Oggeto',
|
||||
'Class:EventNotificationEmail/Attribute:subject+' => '',
|
||||
'Class:EventNotificationEmail/Attribute:body' => 'Corpo',
|
||||
'Class:EventNotificationEmail/Attribute:body+' => '',
|
||||
'Class:EventIssue' => 'Evento Problema',
|
||||
'Class:EventIssue+' => '',
|
||||
'Class:EventIssue/Attribute:issue' => 'Problema',
|
||||
'Class:EventIssue/Attribute:issue+' => '',
|
||||
'Class:EventIssue/Attribute:impact' => 'Impatto',
|
||||
'Class:EventIssue/Attribute:impact+' => '',
|
||||
'Class:EventIssue/Attribute:page' => 'Pagina',
|
||||
'Class:EventIssue/Attribute:page+' => '',
|
||||
'Class:EventIssue/Attribute:arguments_post' => 'Argomenti inviati',
|
||||
'Class:EventIssue/Attribute:arguments_post+' => '',
|
||||
'Class:EventIssue/Attribute:arguments_get' => 'Argomenti URL',
|
||||
'Class:EventIssue/Attribute:arguments_get+' => '',
|
||||
'Class:EventIssue/Attribute:callstack' => 'Callstack',
|
||||
'Class:EventIssue/Attribute:callstack+' => '',
|
||||
'Class:EventIssue/Attribute:data' => 'Dati',
|
||||
'Class:EventIssue/Attribute:data+' => '',
|
||||
'Class:EventWebService' => 'Evento Servizio Web',
|
||||
'Class:EventWebService+' => '',
|
||||
'Class:EventWebService/Attribute:verb' => 'Verbo',
|
||||
'Class:EventWebService/Attribute:verb+' => '',
|
||||
'Class:EventWebService/Attribute:result' => 'Resulto',
|
||||
'Class:EventWebService/Attribute:result+' => '',
|
||||
'Class:EventWebService/Attribute:log_info' => 'Log delle info',
|
||||
'Class:EventWebService/Attribute:log_info+' => '',
|
||||
'Class:EventWebService/Attribute:log_warning' => 'Log dei warning',
|
||||
'Class:EventWebService/Attribute:log_warning+' => '',
|
||||
'Class:EventWebService/Attribute:log_error' => 'Log degli errori',
|
||||
'Class:EventWebService/Attribute:log_error+' => '',
|
||||
'Class:EventWebService/Attribute:data' => 'Dati',
|
||||
'Class:EventWebService/Attribute:data+' => '',
|
||||
'Class:EventLoginUsage' => 'Login di utilizzo',
|
||||
'Class:EventLoginUsage+' => '',
|
||||
'Class:EventLoginUsage/Attribute:user_id' => 'Login',
|
||||
'Class:EventLoginUsage/Attribute:user_id+' => '',
|
||||
'Class:SynchroDataSource' => 'Sorgente di sincronizzazione dei dati',
|
||||
'Class:SynchroDataSource/Attribute:name' => 'Nome',
|
||||
'Class:SynchroDataSource/Attribute:name+' => '',
|
||||
'Class:SynchroDataSource/Attribute:description' => 'Descrizione',
|
||||
'Class:SynchroDataSource/Attribute:status' => 'Stato',
|
||||
'Class:SynchroDataSource/Attribute:status/Value:implementation' => 'Implementazione',
|
||||
'Class:SynchroDataSource/Attribute:status/Value:obsolete' => 'Obsoleto',
|
||||
'Class:SynchroDataSource/Attribute:status/Value:production' => 'Produzione',
|
||||
'Class:SynchroDataSource/Attribute:user_id' => 'Utente',
|
||||
'Class:SynchroDataSource/Attribute:scope_class' => 'Classe Target',
|
||||
'Class:SynchroDataSource/Attribute:scope_restriction' => 'Campo di applicazione restrizione',
|
||||
'Class:SynchroDataSource/Attribute:full_load_periodicity' => 'Intervallo a pieno carico',
|
||||
'Class:SynchroDataSource/Attribute:full_load_periodicity+' => '',
|
||||
'Class:SynchroDataSource/Attribute:reconciliation_policy' => 'Policy di riconciliazione',
|
||||
'Class:SynchroDataSource/Attribute:reconciliation_policy/Value:use_attributes' => 'Usa gli attributi',
|
||||
'Class:SynchroDataSource/Attribute:reconciliation_policy/Value:use_primary_key' => 'Usa il campo chiave primaria',
|
||||
'Class:SynchroDataSource/Attribute:action_on_zero' => 'Azione su zero~~',
|
||||
'Class:SynchroDataSource/Attribute:action_on_zero+' => '',
|
||||
'Class:SynchroDataSource/Attribute:action_on_zero/Value:create' => 'Crea',
|
||||
'Class:SynchroDataSource/Attribute:action_on_zero/Value:error' => 'Errore',
|
||||
'Class:SynchroDataSource/Attribute:action_on_one' => 'Azione su uno',
|
||||
'Class:SynchroDataSource/Attribute:action_on_one+' => '',
|
||||
'Class:SynchroDataSource/Attribute:action_on_one/Value:error' => 'Error',
|
||||
'Class:SynchroDataSource/Attribute:action_on_one/Value:update' => 'Aggiorna',
|
||||
'Class:SynchroDataSource/Attribute:action_on_multiple' => 'Azione su molti',
|
||||
'Class:SynchroDataSource/Attribute:action_on_multiple+' => '',
|
||||
'Class:SynchroDataSource/Attribute:action_on_multiple/Value:create' => 'Crea',
|
||||
'Class:SynchroDataSource/Attribute:action_on_multiple/Value:error' => 'Errore',
|
||||
'Class:SynchroDataSource/Attribute:action_on_multiple/Value:take_first' => 'Considera il primo (random?)',
|
||||
'Class:SynchroDataSource/Attribute:delete_policy' => 'Policy di cancellazioen',
|
||||
'Class:SynchroDataSource/Attribute:delete_policy/Value:delete' => 'Cancella',
|
||||
'Class:SynchroDataSource/Attribute:delete_policy/Value:ignore' => 'Ignora',
|
||||
'Class:SynchroDataSource/Attribute:delete_policy/Value:update' => 'Aggiorna',
|
||||
'Class:SynchroDataSource/Attribute:delete_policy/Value:update_then_delete' => 'Aggiorna e poi Cancella',
|
||||
'Class:SynchroDataSource/Attribute:delete_policy_update' => 'Regole per l\'aggiornamento',
|
||||
'Class:SynchroDataSource/Attribute:delete_policy_update+' => '',
|
||||
'Class:SynchroDataSource/Attribute:delete_policy_retention' => 'Durata di conservazione',
|
||||
'Class:SynchroDataSource/Attribute:delete_policy_retention+' => '',
|
||||
'Class:SynchroDataSource/Attribute:attribute_list' => 'Lista degli attributi',
|
||||
'Class:SynchroDataSource/Attribute:user_delete_policy' => 'utenti autorizzati',
|
||||
'Class:SynchroDataSource/Attribute:user_delete_policy+' => '',
|
||||
'Class:SynchroDataSource/Attribute:user_delete_policy/Value:administrators' => 'Solo Amministratore',
|
||||
'Class:SynchroDataSource/Attribute:user_delete_policy/Value:everybody' => 'Tutti sono autorizzati a cancellare questi oggetti',
|
||||
'Class:SynchroDataSource/Attribute:user_delete_policy/Value:nobody' => 'Nessuno',
|
||||
'Class:SynchroDataSource/Attribute:url_icon' => 'Icona di collegamento ipertestuale',
|
||||
'Class:SynchroDataSource/Attribute:url_icon+' => '',
|
||||
'Class:SynchroDataSource/Attribute:url_application' => 'Collegamento ipertestuale all\'applicazione',
|
||||
'Class:SynchroDataSource/Attribute:url_application+' => '',
|
||||
'Class:SynchroAttribute' => 'Attributo di sincronizzazione',
|
||||
'Class:SynchroAttribute/Attribute:sync_source_id' => 'Sorgente sincronizzazione dati',
|
||||
'Class:SynchroAttribute/Attribute:attcode' => 'Codice attributo',
|
||||
'Class:SynchroAttribute/Attribute:update' => 'Aggiorna',
|
||||
'Class:SynchroAttribute/Attribute:reconcile' => 'Rincocilia',
|
||||
'Class:SynchroAttribute/Attribute:update_policy' => 'Policy di aggiornamento',
|
||||
'Class:SynchroAttribute/Attribute:update_policy/Value:master_locked' => 'Bloccato',
|
||||
'Class:SynchroAttribute/Attribute:update_policy/Value:master_unlocked' => 'Sbloccato',
|
||||
'Class:SynchroAttribute/Attribute:update_policy/Value:write_if_empty' => 'Inizializza se vuoto',
|
||||
'Class:SynchroAttribute/Attribute:finalclass' => 'Classe',
|
||||
'Class:SynchroAttExtKey' => 'Attributo di sincronizzazione (ExtKey)',
|
||||
'Class:SynchroAttExtKey/Attribute:reconciliation_attcode' => 'Attributo di riconciliazione',
|
||||
'Class:SynchroAttLinkSet' => 'Attributo di sincronizzazione (Linkset)',
|
||||
'Class:SynchroAttLinkSet/Attribute:row_separator' => 'Separatore di righe',
|
||||
'Class:SynchroAttLinkSet/Attribute:attribute_separator' => 'Separatore di attributi',
|
||||
'Class:SynchroLog' => 'Log di sincronizzazione',
|
||||
'Class:SynchroLog/Attribute:sync_source_id' => 'Sorgente di sincronizzazione dati',
|
||||
'Class:SynchroLog/Attribute:start_date' => 'Data di inizio',
|
||||
'Class:SynchroLog/Attribute:end_date' => 'Data di fine',
|
||||
'Class:SynchroLog/Attribute:status' => 'Stato',
|
||||
'Class:SynchroLog/Attribute:status/Value:completed' => 'Completo',
|
||||
'Class:SynchroLog/Attribute:status/Value:error' => 'Errore',
|
||||
'Class:SynchroLog/Attribute:status/Value:running' => 'Ancora in esecuzione',
|
||||
'Class:SynchroLog/Attribute:stats_nb_replica_seen' => 'Nb replica viste',
|
||||
'Class:SynchroLog/Attribute:stats_nb_replica_total' => 'Nb replica totale',
|
||||
'Class:SynchroLog/Attribute:stats_nb_obj_deleted' => 'Nb oggetti cancellati',
|
||||
'Class:SynchroLog/Attribute:stats_nb_obj_deleted_errors' => 'Nb di errore durante la cancellazione',
|
||||
'Class:SynchroLog/Attribute:stats_nb_obj_obsoleted' => 'Nb oggetti obsoleti',
|
||||
'Class:SynchroLog/Attribute:stats_nb_obj_obsoleted_errors' => 'Nb di errori mentre obsoleta',
|
||||
'Class:SynchroLog/Attribute:stats_nb_obj_created' => 'Nb oggetti creati',
|
||||
'Class:SynchroLog/Attribute:stats_nb_obj_created_errors' => 'Nb di errori durante la creazione',
|
||||
'Class:SynchroLog/Attribute:stats_nb_obj_updated' => 'Nb oggetti aggiornati',
|
||||
'Class:SynchroLog/Attribute:stats_nb_obj_updated_errors' => 'Nb di errori durante l\'aggiornamento',
|
||||
'Class:SynchroLog/Attribute:stats_nb_replica_reconciled_errors' => 'Nb di errori durante la riconcilazione',
|
||||
'Class:SynchroLog/Attribute:stats_nb_replica_disappeared_no_action' => 'Nb repliche scomparse',
|
||||
'Class:SynchroLog/Attribute:stats_nb_obj_new_updated' => 'Nb oggetti aggiornati',
|
||||
'Class:SynchroLog/Attribute:stats_nb_obj_new_unchanged' => 'Nb oggetti non modificati',
|
||||
'Class:SynchroLog/Attribute:last_error' => 'Untimo errore',
|
||||
'Class:SynchroLog/Attribute:traces' => 'Tracce',
|
||||
'Class:SynchroReplica' => 'Replica sincronizzazione',
|
||||
'Class:SynchroReplica/Attribute:sync_source_id' => 'Sorgente di sincronizzazione dati',
|
||||
'Class:SynchroReplica/Attribute:dest_id' => 'Oggetto di destinazione (ID)~~',
|
||||
'Class:SynchroReplica/Attribute:dest_class' => 'Tipo di destinazione',
|
||||
'Class:SynchroReplica/Attribute:status_last_seen' => 'Ultimo visto',
|
||||
'Class:SynchroReplica/Attribute:status' => 'Stato',
|
||||
'Class:SynchroReplica/Attribute:status/Value:modified' => 'Modificato',
|
||||
'Class:SynchroReplica/Attribute:status/Value:new' => 'Nuovo',
|
||||
'Class:SynchroReplica/Attribute:status/Value:obsolete' => 'Obsoleto',
|
||||
'Class:SynchroReplica/Attribute:status/Value:orphan' => 'Orfano',
|
||||
'Class:SynchroReplica/Attribute:status/Value:synchronized' => 'Sincronizzato',
|
||||
'Class:SynchroReplica/Attribute:status_dest_creator' => 'Oggetto Creato ?',
|
||||
'Class:SynchroReplica/Attribute:status_last_error' => 'Ultimo Errore',
|
||||
'Class:SynchroReplica/Attribute:info_creation_date' => 'Data di creazione',
|
||||
'Class:SynchroReplica/Attribute:info_last_modified' => 'Data ultima modifica',
|
||||
'Class:appUserPreferences' => 'Preferenze utente',
|
||||
'Class:appUserPreferences/Attribute:userid' => 'Utente',
|
||||
'Class:appUserPreferences/Attribute:preferences' => 'Preferenze',
|
||||
'Core:AttributeLinkedSet' => 'Array di oggetti',
|
||||
'Core:AttributeLinkedSet+' => '',
|
||||
'Core:AttributeLinkedSetIndirect' => 'Array di oggetti (N-N)',
|
||||
'Core:AttributeLinkedSetIndirect+' => '',
|
||||
'Core:AttributeInteger' => 'Integero',
|
||||
'Core:AttributeInteger+' => '',
|
||||
'Core:AttributeDecimal' => 'Decimale',
|
||||
'Core:AttributeDecimal+' => '',
|
||||
'Core:AttributeBoolean' => 'Booleano',
|
||||
'Core:AttributeBoolean+' => '',
|
||||
'Core:AttributeString' => 'Stringa',
|
||||
'Core:AttributeString+' => '',
|
||||
'Core:AttributeClass' => 'Classe',
|
||||
'Core:AttributeClass+' => '',
|
||||
'Core:AttributeApplicationLanguage' => 'Linguaggio Utente',
|
||||
'Core:AttributeApplicationLanguage+' => '',
|
||||
'Core:AttributeFinalClass' => 'Classe (auto)',
|
||||
'Core:AttributeFinalClass+' => '',
|
||||
'Core:AttributePassword' => 'Password',
|
||||
'Core:AttributePassword+' => '',
|
||||
'Core:AttributeEncryptedString' => 'Stringa criptata',
|
||||
'Core:AttributeEncryptedString+' => '',
|
||||
'Core:AttributeText' => 'Testo',
|
||||
'Core:AttributeText+' => '',
|
||||
'Core:AttributeHTML' => 'HTML',
|
||||
'Core:AttributeHTML+' => '',
|
||||
'Core:AttributeEmailAddress' => 'Indirizzo Email',
|
||||
'Core:AttributeEmailAddress+' => '',
|
||||
'Core:AttributeIPAddress' => 'Indirizzo IP',
|
||||
'Core:AttributeIPAddress+' => '',
|
||||
'Core:AttributeOQL' => 'OQL',
|
||||
'Core:AttributeOQL+' => '',
|
||||
'Core:AttributeEnum' => 'Enum',
|
||||
'Core:AttributeEnum+' => '',
|
||||
'Core:AttributeTemplateString' => 'Stringa Template',
|
||||
'Core:AttributeTemplateString+' => '',
|
||||
'Core:AttributeTemplateText' => 'Testo Template',
|
||||
'Core:AttributeTemplateText+' => '',
|
||||
'Core:AttributeTemplateHTML' => 'HTML Template',
|
||||
'Core:AttributeTemplateHTML+' => '',
|
||||
'Core:AttributeDateTime' => 'Data/ora',
|
||||
'Core:AttributeDateTime+' => '',
|
||||
'Core:AttributeDate' => 'Data',
|
||||
'Core:AttributeDate+' => '',
|
||||
'Core:AttributeDeadline' => 'Scadenza',
|
||||
'Core:AttributeDeadline+' => '',
|
||||
'Core:AttributeExternalKey' => 'Chiave esterna',
|
||||
'Core:AttributeExternalKey+' => '',
|
||||
'Core:AttributeExternalField' => 'Campo esterno',
|
||||
'Core:AttributeExternalField+' => '',
|
||||
'Core:AttributeURL' => 'URL',
|
||||
'Core:AttributeURL+' => '',
|
||||
'Core:AttributeBlob' => 'Blob',
|
||||
'Core:AttributeBlob+' => '',
|
||||
'Core:AttributeOneWayPassword' => 'Password unidierzionale',
|
||||
'Core:AttributeOneWayPassword+' => '',
|
||||
'Core:AttributeTable' => 'Tabella',
|
||||
'Core:AttributeTable+' => '',
|
||||
'Core:AttributePropertySet' => 'Proprietà',
|
||||
'Core:AttributePropertySet+' => '',
|
||||
'Class:CMDBChangeOp/Attribute:date' => 'data',
|
||||
'Class:CMDBChangeOp/Attribute:date+' => '',
|
||||
'Class:CMDBChangeOp/Attribute:userinfo' => 'utente',
|
||||
'Class:CMDBChangeOp/Attribute:userinfo+' => '',
|
||||
'Change:ObjectCreated' => 'Oggetto creato',
|
||||
'Change:ObjectDeleted' => 'Oggetto cancellato',
|
||||
'Change:ObjectModified' => 'Object modificato',
|
||||
'Change:AttName_SetTo_NewValue_PreviousValue_OldValue' => '%1$s imposatato a %2$s (valore precendente: %3$s)',
|
||||
'Change:AttName_SetTo' => '%1$s impostato a %2$s~~',
|
||||
'Change:Text_AppendedTo_AttName' => '%1$s allegato a %2$s~~',
|
||||
'Change:AttName_Changed_PreviousValue_OldValue' => '%1$s moficato, valore precendente: %2$s',
|
||||
'Change:AttName_Changed' => '%1$s modificato',
|
||||
'Change:AttName_EntryAdded' => '%1$s modificato, nuova entrata aggiunta.',
|
||||
'Class:EventLoginUsage/Attribute:contact_name' => 'Nome Utente',
|
||||
'Class:EventLoginUsage/Attribute:contact_name+' => '',
|
||||
'Class:EventLoginUsage/Attribute:contact_email' => 'Email Utente',
|
||||
'Class:EventLoginUsage/Attribute:contact_email+' => '',
|
||||
'Class:Action' => 'Azione personalizzata',
|
||||
'Class:Action+' => '',
|
||||
'Class:Action/Attribute:name' => 'Nome',
|
||||
'Class:Action/Attribute:name+' => '',
|
||||
'Class:Action/Attribute:description' => 'Descrizione',
|
||||
'Class:Action/Attribute:description+' => '',
|
||||
'Class:Action/Attribute:status' => 'Stato',
|
||||
'Class:Action/Attribute:status+' => '',
|
||||
'Class:Action/Attribute:status/Value:test' => 'In fase di test',
|
||||
'Class:Action/Attribute:status/Value:test+' => '',
|
||||
'Class:Action/Attribute:status/Value:enabled' => 'In produzione',
|
||||
'Class:Action/Attribute:status/Value:enabled+' => '',
|
||||
'Class:Action/Attribute:status/Value:disabled' => 'Inattivo',
|
||||
'Class:Action/Attribute:status/Value:disabled+' => '',
|
||||
'Class:Action/Attribute:trigger_list' => 'Trigger Correlati',
|
||||
'Class:Action/Attribute:trigger_list+' => '',
|
||||
'Class:Action/Attribute:finalclass' => 'Tipo',
|
||||
'Class:Action/Attribute:finalclass+' => '',
|
||||
'Class:ActionNotification' => 'Notifica',
|
||||
'Class:ActionNotification+' => '',
|
||||
'Class:Trigger' => 'Trigger',
|
||||
'Class:Trigger+' => '',
|
||||
'Class:Trigger/Attribute:description' => 'Descrizione',
|
||||
'Class:Trigger/Attribute:description+' => '',
|
||||
'Class:Trigger/Attribute:action_list' => 'Azioni Triggerate',
|
||||
'Class:Trigger/Attribute:action_list+' => '',
|
||||
'Class:Trigger/Attribute:finalclass' => 'Tipo',
|
||||
'Class:Trigger/Attribute:finalclass+' => '',
|
||||
'Class:TriggerOnObject' => 'Trigger (classe dipendente)',
|
||||
'Class:TriggerOnObject+' => '',
|
||||
'Class:TriggerOnObject/Attribute:target_class' => 'Classe Target',
|
||||
'Class:TriggerOnObject/Attribute:target_class+' => '',
|
||||
'Class:TriggerOnStateChange' => 'Trigger (sul cambio di stato)',
|
||||
'Class:TriggerOnStateChange+' => '',
|
||||
'Class:TriggerOnStateChange/Attribute:state' => 'Stato',
|
||||
'Class:TriggerOnStateChange/Attribute:state+' => '',
|
||||
'Class:lnkTriggerAction/Attribute:action_name' => 'Azione',
|
||||
'Class:lnkTriggerAction/Attribute:action_name+' => '',
|
||||
'Class:lnkTriggerAction/Attribute:trigger_name' => 'Trigger',
|
||||
'Class:lnkTriggerAction/Attribute:trigger_name+' => '',
|
||||
'Class:SynchroDataSource/Attribute:delete_policy/Value:never' => 'Nessuno',
|
||||
'Class:SynchroDataSource/Attribute:delete_policy/Value:depends' => 'Solo Amministratore',
|
||||
'Class:SynchroDataSource/Attribute:delete_policy/Value:always' => 'Tutti gli utenti autorizzati',
|
||||
'SynchroDataSource:Description' => 'Descrizione',
|
||||
'SynchroDataSource:Reconciliation' => 'Ricerca & riconciliazione',
|
||||
'SynchroDataSource:Deletion' => 'Regole di cancellazione',
|
||||
'SynchroDataSource:Status' => 'Stato',
|
||||
'SynchroDataSource:Information' => 'Informazione',
|
||||
'SynchroDataSource:Definition' => 'Definizione',
|
||||
'Core:SynchroAttributes' => 'Attributi',
|
||||
'Core:SynchroStatus' => 'Stato',
|
||||
'Core:Synchro:ErrorsLabel' => 'Errori',
|
||||
'Core:Synchro:CreatedLabel' => 'Creato',
|
||||
'Core:Synchro:ModifiedLabel' => 'Modificato',
|
||||
'Core:Synchro:UnchangedLabel' => 'Non modificato',
|
||||
'Core:Synchro:ReconciledErrorsLabel' => 'Errori',
|
||||
'Core:Synchro:ReconciledLabel' => 'Reconciliato',
|
||||
'Core:Synchro:ReconciledNewLabel' => 'Creato',
|
||||
'Core:SynchroReconcile:Yes' => 'Si',
|
||||
'Core:SynchroReconcile:No' => 'No',
|
||||
'Core:SynchroUpdate:Yes' => 'Si',
|
||||
'Core:SynchroUpdate:No' => 'No',
|
||||
'Core:Synchro:LastestStatus' => 'Ultimo stato',
|
||||
'Core:Synchro:History' => 'Storia della sincronizzazione',
|
||||
'Core:Synchro:NeverRun' => 'Questa sincronizzazione non è mai stata eseguita. Nessun Log ancora...',
|
||||
'Core:Synchro:SynchroEndedOn_Date' => 'L\'ultima sincronizzazione si è conclusa il %1$s.~~',
|
||||
'Core:Synchro:SynchroRunningStartedOn_Date' => 'La sincronizzazione è iniziata il %1$s è ancora in esecuzione...~~',
|
||||
'Menu:DataSources' => 'Sorgente di sincronizzazione dei dati',
|
||||
'Menu:DataSources+' => '',
|
||||
'Core:Synchro:label_repl_ignored' => 'Ignorato(%1$s)',
|
||||
'Core:Synchro:label_repl_disappeared' => 'Scomparso (%1$s)',
|
||||
'Core:Synchro:label_repl_existing' => 'Esistente (%1$s)',
|
||||
'Core:Synchro:label_repl_new' => 'Nuovo (%1$s)~~',
|
||||
'Core:Synchro:label_obj_deleted' => 'Cancellato (%1$s)',
|
||||
'Core:Synchro:label_obj_obsoleted' => 'Obsoleto (%1$s)',
|
||||
'Core:Synchro:label_obj_disappeared_errors' => 'Errori (%1$s)',
|
||||
'Core:Synchro:label_obj_disappeared_no_action' => 'Nessuna Azione (%1$s)',
|
||||
'Core:Synchro:label_obj_unchanged' => 'Non modificato(%1$s)',
|
||||
'Core:Synchro:label_obj_updated' => 'Aggiornato (%1$s)',
|
||||
'Core:Synchro:label_obj_updated_errors' => 'Errori (%1$s)',
|
||||
'Core:Synchro:label_obj_new_unchanged' => 'Non modificato (%1$s)',
|
||||
'Core:Synchro:label_obj_new_updated' => 'Aggiornato (%1$s)',
|
||||
'Core:Synchro:label_obj_created' => 'Creato (%1$s)',
|
||||
'Core:Synchro:label_obj_new_errors' => 'Errori (%1$s)',
|
||||
'Core:SynchroLogTitle' => '%1$s - %2$s~~',
|
||||
'Core:Synchro:Nb_Replica' => 'Replica processata: %1$s',
|
||||
'Core:Synchro:Nb_Class:Objects' => '%1$s: %2$s',
|
||||
'Class:SynchroDataSource/Error:AtLeastOneReconciliationKeyMustBeSpecified' => 'Almeno una chiave riconciliazione deve essere specificata, o la policy di conciliazione deve essere quella di utilizzare la chiave primaria',
|
||||
'Class:SynchroDataSource/Error:DeleteRetentionDurationMustBeSpecified' => 'Deve essere specificato un periodo di conservazione di cancellazione , dato che gli oggetti devono essere eliminati dopo essere contrassegnati come obsoleti ',
|
||||
'Class:SynchroDataSource/Error:DeletePolicyUpdateMustBeSpecified' => 'Oggetti obsoleti devono essere aggiornati, ma nessun aggiornamento è specificato',
|
||||
'Core:SynchroReplica:PublicData' => 'Dati Pubblici',
|
||||
'Core:SynchroReplica:PrivateDetails' => 'Dettagli Privati',
|
||||
'Core:SynchroReplica:BackToDataSource' => 'Torna indietro alla sorgente di sincronizzazione dei dati: %1$s~~',
|
||||
'Core:SynchroReplica:ListOfReplicas' => 'Lista della Replica',
|
||||
'Core:SynchroAttExtKey:ReconciliationById' => 'id (Chiave Primaria)',
|
||||
'Core:SynchroAtt:attcode' => 'Attributo',
|
||||
'Core:SynchroAtt:attcode+' => '',
|
||||
'Core:SynchroAtt:reconciliation' => 'Riconciliazione ?~~',
|
||||
'Core:SynchroAtt:reconciliation+' => '',
|
||||
'Core:SynchroAtt:update' => 'Aggiornamento ?~~',
|
||||
'Core:SynchroAtt:update+' => '',
|
||||
'Core:SynchroAtt:update_policy' => 'Policy di aggiornamento',
|
||||
'Core:SynchroAtt:update_policy+' => '',
|
||||
'Core:SynchroAtt:reconciliation_attcode' => 'Chiave di riconciliazione',
|
||||
'Core:SynchroAtt:reconciliation_attcode+' => '',
|
||||
'Core:SyncDataExchangeComment' => '(Scambio dati)',
|
||||
'Core:Synchro:ListOfDataSources' => 'Lista delle sorgenti di dati:',
|
||||
'Core:Synchro:LastSynchro' => 'Ultima sincronizzazione:',
|
||||
'Core:Synchro:ThisObjectIsSynchronized' => 'Questo oggetto è sincronizzato con una sorgente esterna di dati',
|
||||
'Core:Synchro:TheObjectWasCreatedBy_Source' => 'L\'oggetti è stato <b>creato</b> da una sorgente esterna di dati %1$s~~',
|
||||
'Core:Synchro:TheObjectCanBeDeletedBy_Source' => 'L\'oggetti <b>può essere cancellato</b> da una sorgente esterna di dati %1$s~~',
|
||||
'Core:Synchro:TheObjectCannotBeDeletedByUser_Source' => 'Tu <b>non puoi cancellare l\'oggetto</b> perché è di proprietà della sorgente dati esterna %1$s~~',
|
||||
'TitleSynchroExecution' => 'Esecuzione della sincronizzazione',
|
||||
'Class:SynchroDataSource:DataTable' => 'Tabella del database: %1$s',
|
||||
'Core:SyncDataSourceObsolete' => 'La fonte dei dati è contrassegnata come obsoleta. Operazione annullata',
|
||||
'Core:SyncDataSourceAccessRestriction' => 'Solo amministratori o l\'utente specificato nella fonte dei dati può eseguire questa operazione. Operazione annullata',
|
||||
'Core:SyncTooManyMissingReplicas' => 'Tutte le repliche sono mancanti dall\'importazione. Hai eseguito realmente l\'importazione? Operazione annullata',
|
||||
'Core:Duration_Seconds' => '%1$ds',
|
||||
'Core:Duration_Minutes_Seconds' => '%1$dmin %2$ds',
|
||||
'Core:Duration_Hours_Minutes_Seconds' => '%1$dh %2$dmin %3$sec~~',
|
||||
'Core:Duration_Days_Hours_Minutes_Seconds' => '%1$sg %2$dh %3$dmin %4$ds~~',
|
||||
));
|
||||
?>
|
||||
|
||||
758
dictionaries/ja.dictionary.itop.core.php
Normal file
@@ -0,0 +1,758 @@
|
||||
<?php
|
||||
// Copyright (C) 2010 Combodo SARL
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation; version 3 of the License.
|
||||
//
|
||||
// This program 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 General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
/**
|
||||
* Localized data
|
||||
*
|
||||
* @author Erwan Taloc <erwan.taloc@combodo.com>
|
||||
* @author Romain Quetiez <romain.quetiez@combodo.com>
|
||||
* @author Denis Flaven <denis.flaven@combodo.com>
|
||||
* @author Tadashi Kaneda <kaneda@smartec.co.jp>
|
||||
* @license http://www.opensource.org/licenses/gpl-3.0.html LGPL
|
||||
*/
|
||||
|
||||
Dict::Add('JA JP', 'Japanese', '日本語', array(
|
||||
'Core:AttributeLinkedSet' => 'オブジェクト配列',
|
||||
'Core:AttributeLinkedSet+' => '同一あるいはサブクラスに属するオブジェクト',
|
||||
|
||||
'Core:AttributeLinkedSetIndirect' => 'オブジェクト配列 (N-N)',
|
||||
'Core:AttributeLinkedSetIndirect+' => '同一クラスの任意のオブジェクト(サブクラス)',
|
||||
|
||||
'Core:AttributeInteger' => 'Int型',
|
||||
'Core:AttributeInteger+' => '数値 (負数あり)',
|
||||
|
||||
'Core:AttributeDecimal' => 'Decimal型',
|
||||
'Core:AttributeDecimal+' => 'Decimal値 (負数あり)',
|
||||
|
||||
'Core:AttributeBoolean' => 'ブール型',
|
||||
'Core:AttributeBoolean+' => 'Bool値',
|
||||
|
||||
'Core:AttributeString' => '文字列',
|
||||
'Core:AttributeString+' => '文字列',
|
||||
|
||||
'Core:AttributeClass' => 'クラス',
|
||||
'Core:AttributeClass+' => 'クラス',
|
||||
|
||||
'Core:AttributeApplicationLanguage' => '使用言語',
|
||||
'Core:AttributeApplicationLanguage+' => '言語・国別 (JA JP)',
|
||||
|
||||
'Core:AttributeFinalClass' => 'クラス (自動)',
|
||||
'Core:AttributeFinalClass+' => 'オブジェクトの実クラス (コアで自動的に生成される)',
|
||||
|
||||
'Core:AttributePassword' => 'パスワード',
|
||||
'Core:AttributePassword+' => '外部デバイス用パスワード',
|
||||
|
||||
'Core:AttributeEncryptedString' => '暗号化文字列',
|
||||
'Core:AttributeEncryptedString+' => 'ローカルキーで暗号化された文字列',
|
||||
|
||||
'Core:AttributeText' => 'テキスト',
|
||||
'Core:AttributeText+' => '複数行文字列',
|
||||
|
||||
'Core:AttributeHTML' => 'HTML',
|
||||
'Core:AttributeHTML+' => 'HTML文字列',
|
||||
|
||||
'Core:AttributeEmailAddress' => 'メールアドレス',
|
||||
'Core:AttributeEmailAddress+' => 'メールアドレス',
|
||||
|
||||
'Core:AttributeIPAddress' => 'IPアドレス',
|
||||
'Core:AttributeIPAddress+' => 'IPアドレス',
|
||||
|
||||
'Core:AttributeOQL' => 'OQL',
|
||||
'Core:AttributeOQL+' => 'OQL式',
|
||||
|
||||
'Core:AttributeEnum' => '列挙型',
|
||||
'Core:AttributeEnum+' => 'ナンバリング済み文字列のリスト',
|
||||
|
||||
'Core:AttributeTemplateString' => 'テンプレート文字列',
|
||||
'Core:AttributeTemplateString+' => 'プレースホルダを含む文字列',
|
||||
|
||||
'Core:AttributeTemplateText' => 'テンプレートテキスト',
|
||||
'Core:AttributeTemplateText+' => 'プレースホルダを含むテキスト',
|
||||
|
||||
'Core:AttributeTemplateHTML' => 'テンプレートHTML',
|
||||
'Core:AttributeTemplateHTML+' => 'プレースホルダを含むHTML',
|
||||
|
||||
'Core:AttributeDateTime' => '日付/時刻',
|
||||
'Core:AttributeDateTime+' => '日付と時刻(年-月-日 hh:mm:ss)',
|
||||
'Core:AttributeDateTime?SmartSearch' => '
|
||||
<p>
|
||||
Date format:<br/>
|
||||
<b>yyyy-mm-dd hh:mm:ss</b><br/>
|
||||
例: 2011-07-19 18:40:00
|
||||
</p>
|
||||
<p>
|
||||
Operators:<br/>
|
||||
<b>></b><em>日付</em><br/>
|
||||
<b><</b><em>日付</em><br/>
|
||||
<b>[</b><em>日付</em>,<em>日付</em><b>]</b>
|
||||
</p>
|
||||
<p>
|
||||
もし、時刻がなければ、規定値 00:00:00となります。
|
||||
</p>',
|
||||
|
||||
'Core:AttributeDate' => '日付',
|
||||
'Core:AttributeDate+' => '日付 (年-月-日)',
|
||||
'Core:AttributeDate?SmartSearch' => '
|
||||
<p>
|
||||
日付フォーマット:<br/>
|
||||
<b>yyyy-mm-dd</b><br/>
|
||||
例: 2011-07-19
|
||||
</p>
|
||||
<p>
|
||||
演算子:<br/>
|
||||
<b>></b><em>日付</em><br/>
|
||||
<b><</b><em>日付</em><br/>
|
||||
<b>[</b><em>日付</em>,<em>日付</em><b>]</b>
|
||||
</p>',
|
||||
|
||||
'Core:AttributeDeadline' => '締切',
|
||||
'Core:AttributeDeadline+' => '日付, 現在時刻からの相対表示',
|
||||
|
||||
'Core:AttributeExternalKey' => '外部キー',
|
||||
'Core:AttributeExternalKey+' => '外部(あるいはフォーリン)キー',
|
||||
|
||||
'Core:AttributeExternalField' => '外部フィールド',
|
||||
'Core:AttributeExternalField+' => '外部キーにマッピングされたフィールド',
|
||||
|
||||
'Core:AttributeURL' => 'URL',
|
||||
'Core:AttributeURL+' => '絶対URLもしくは相対URLのテキスト文字列',
|
||||
|
||||
'Core:AttributeBlob' => 'Blob',
|
||||
'Core:AttributeBlob+' => '任意のバイナリコンテンツ(文書)',
|
||||
|
||||
'Core:AttributeOneWayPassword' => '一方向パスワード',
|
||||
'Core:AttributeOneWayPassword+' => '一方向暗号化(ハッシュ)パスワード',
|
||||
|
||||
'Core:AttributeTable' => 'テーブル',
|
||||
'Core:AttributeTable+' => 'インデックス化された二次元配列',
|
||||
|
||||
'Core:AttributePropertySet' => 'プロパティ',
|
||||
'Core:AttributePropertySet+' => '型づけされていないプロパティのリスト(名前とバリュー)',
|
||||
|
||||
'Core:AttributeFriendlyName' => 'Friendly name',
|
||||
'Core:AttributeFriendlyName+' => 'Attribute created automatically ; the friendly name is computed after several attributes',
|
||||
|
||||
'Core:FriendlyName-Label' => 'Name',
|
||||
'Core:FriendlyName-Description' => 'Friendly name',
|
||||
|
||||
));
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// Classes in 'core/cmdb'
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
|
||||
//
|
||||
// Class: CMDBChange
|
||||
//
|
||||
|
||||
Dict::Add('JA JP', 'Japanese', '日本語', array(
|
||||
'Class:CMDBChange' => '変更',
|
||||
'Class:CMDBChange+' => '変更履歴',
|
||||
'Class:CMDBChange/Attribute:date' => '日付',
|
||||
'Class:CMDBChange/Attribute:date+' => '変更が記録された日時',
|
||||
'Class:CMDBChange/Attribute:userinfo' => 'その他情報',
|
||||
'Class:CMDBChange/Attribute:userinfo+' => '呼出側の定義済み情報',
|
||||
));
|
||||
|
||||
//
|
||||
// Class: CMDBChangeOp
|
||||
//
|
||||
|
||||
Dict::Add('JA JP', 'Japanese', '日本語', array(
|
||||
'Class:CMDBChangeOp' => '変更操作',
|
||||
'Class:CMDBChangeOp+' => '変更操作履歴',
|
||||
'Class:CMDBChangeOp/Attribute:change' => '変更',
|
||||
'Class:CMDBChangeOp/Attribute:change+' => '変更',
|
||||
'Class:CMDBChangeOp/Attribute:date' => '日付',
|
||||
'Class:CMDBChangeOp/Attribute:date+' => '変更日時',
|
||||
'Class:CMDBChangeOp/Attribute:userinfo' => 'ユーザ',
|
||||
'Class:CMDBChangeOp/Attribute:userinfo+' => '変更者',
|
||||
'Class:CMDBChangeOp/Attribute:objclass' => 'オブジェクトクラス',
|
||||
'Class:CMDBChangeOp/Attribute:objclass+' => 'オブジェクトクラス',
|
||||
'Class:CMDBChangeOp/Attribute:objkey' => 'オブジェクトID',
|
||||
'Class:CMDBChangeOp/Attribute:objkey+' => 'オブジェクトID',
|
||||
'Class:CMDBChangeOp/Attribute:finalclass' => 'タイプ',
|
||||
'Class:CMDBChangeOp/Attribute:finalclass+' => '',
|
||||
));
|
||||
|
||||
//
|
||||
// Class: CMDBChangeOpCreate
|
||||
//
|
||||
|
||||
Dict::Add('JA JP', 'Japanese', '日本語', array(
|
||||
'Class:CMDBChangeOpCreate' => 'オブジェクト作成',
|
||||
'Class:CMDBChangeOpCreate+' => 'オブジェクト作成履歴',
|
||||
));
|
||||
|
||||
//
|
||||
// Class: CMDBChangeOpDelete
|
||||
//
|
||||
|
||||
Dict::Add('JA JP', 'Japanese', '日本語', array(
|
||||
'Class:CMDBChangeOpDelete' => 'オブジェクト削除',
|
||||
'Class:CMDBChangeOpDelete+' => 'オブジェクト削除履歴',
|
||||
));
|
||||
|
||||
//
|
||||
// Class: CMDBChangeOpSetAttribute
|
||||
//
|
||||
|
||||
Dict::Add('JA JP', 'Japanese', '日本語', array(
|
||||
'Class:CMDBChangeOpSetAttribute' => 'オブジェクト更新',
|
||||
'Class:CMDBChangeOpSetAttribute+' => 'オブジェクトプロパティの更新履歴',
|
||||
'Class:CMDBChangeOpSetAttribute/Attribute:attcode' => '属性',
|
||||
'Class:CMDBChangeOpSetAttribute/Attribute:attcode+' => '更新プロパティのコード',
|
||||
));
|
||||
|
||||
//
|
||||
// Class: CMDBChangeOpSetAttributeScalar
|
||||
//
|
||||
|
||||
Dict::Add('JA JP', 'Japanese', '日本語', array(
|
||||
'Class:CMDBChangeOpSetAttributeScalar' => 'プロパティ更新',
|
||||
'Class:CMDBChangeOpSetAttributeScalar+' => 'オブジェクトのスカラープロパティの更新履歴',
|
||||
'Class:CMDBChangeOpSetAttributeScalar/Attribute:oldvalue' => '変更前の値',
|
||||
'Class:CMDBChangeOpSetAttributeScalar/Attribute:oldvalue+' => '属性の変更前の値',
|
||||
'Class:CMDBChangeOpSetAttributeScalar/Attribute:newvalue' => '新規の値',
|
||||
'Class:CMDBChangeOpSetAttributeScalar/Attribute:newvalue+' => '属性の新規の値',
|
||||
));
|
||||
// Used by CMDBChangeOp... & derived classes
|
||||
Dict::Add('JA JP', 'Japanese', '日本語', array(
|
||||
'Change:ObjectCreated' => 'オブジェクトを生成しました',
|
||||
'Change:ObjectDeleted' => 'オブジェクトを削除しました',
|
||||
'Change:ObjectModified' => 'オブジェクトを修正しました',
|
||||
'Change:AttName_SetTo_NewValue_PreviousValue_OldValue' => '%1$sを%2$sに設定しました (変更前の値: %3$s)',
|
||||
'Change:AttName_SetTo' => '%1$s は %2$sにセットされました。', // '%1$s set to %2$s',
|
||||
'Change:Text_AppendedTo_AttName' => '%1$sを%2$sに追加しました',
|
||||
'Change:AttName_Changed_PreviousValue_OldValue' => '%1$sを変更しました。更新前の値: %2$s',
|
||||
'Change:AttName_Changed' => '%1$sを変更しました',
|
||||
'Change:AttName_EntryAdded' => '%1$s は、修正されました。新しいエントリーが追加されました。',
|
||||
));
|
||||
|
||||
//
|
||||
// Class: CMDBChangeOpSetAttributeBlob
|
||||
//
|
||||
|
||||
Dict::Add('JA JP', 'Japanese', '日本語', array(
|
||||
'Class:CMDBChangeOpSetAttributeBlob' => 'データ変更',
|
||||
'Class:CMDBChangeOpSetAttributeBlob+' => 'データ変更履歴',
|
||||
'Class:CMDBChangeOpSetAttributeBlob/Attribute:prevdata' => '以前のデータ',
|
||||
'Class:CMDBChangeOpSetAttributeBlob/Attribute:prevdata+' => 'この属性の以前の内容',
|
||||
));
|
||||
|
||||
//
|
||||
// Class: CMDBChangeOpSetAttributeText
|
||||
//
|
||||
|
||||
Dict::Add('JA JP', 'Japanese', '日本語', array(
|
||||
'Class:CMDBChangeOpSetAttributeText' => 'テキストの変更',
|
||||
'Class:CMDBChangeOpSetAttributeText+' => 'テキストの変更履歴',
|
||||
'Class:CMDBChangeOpSetAttributeText/Attribute:prevdata' => '以前の内容',
|
||||
'Class:CMDBChangeOpSetAttributeText/Attribute:prevdata+' => 'この属性の以前の内容',
|
||||
));
|
||||
|
||||
//
|
||||
// Class: Event
|
||||
//
|
||||
|
||||
Dict::Add('JA JP', 'Japanese', '日本語', array(
|
||||
'Class:Event' => 'ログイベント',
|
||||
'Class:Event+' => 'アプリケーション内部イベント',
|
||||
'Class:Event/Attribute:message' => 'メッセージ',
|
||||
'Class:Event/Attribute:message+' => 'イベントの短い説明',
|
||||
'Class:Event/Attribute:date' => '日付',
|
||||
'Class:Event/Attribute:date+' => '変更が記録された日時',
|
||||
'Class:Event/Attribute:userinfo' => 'ユーザ情報',
|
||||
'Class:Event/Attribute:userinfo+' => 'このイベントをトリガーしたアクションを行ったユーザ',
|
||||
'Class:Event/Attribute:finalclass' => 'タイプ',
|
||||
'Class:Event/Attribute:finalclass+' => '',
|
||||
));
|
||||
|
||||
//
|
||||
// Class: EventNotification
|
||||
//
|
||||
|
||||
Dict::Add('JA JP', 'Japanese', '日本語', array(
|
||||
'Class:EventNotification' => '通知イベント',
|
||||
'Class:EventNotification+' => '送信された通知のトレース',
|
||||
'Class:EventNotification/Attribute:trigger_id' => 'トリガー',
|
||||
'Class:EventNotification/Attribute:trigger_id+' => 'ユーザアカウント',
|
||||
'Class:EventNotification/Attribute:action_id' => 'ユーザ',
|
||||
'Class:EventNotification/Attribute:action_id+' => 'ユーザアカウント',
|
||||
'Class:EventNotification/Attribute:object_id' => 'オブジェクトID',
|
||||
'Class:EventNotification/Attribute:object_id+' => 'オブジェクトID(トリガーでクラスが定義済み?)', //'object id (class defined by the trigger ?)',
|
||||
));
|
||||
|
||||
//
|
||||
// Class: EventNotificationEmail
|
||||
//
|
||||
|
||||
Dict::Add('JA JP', 'Japanese', '日本語', array(
|
||||
'Class:EventNotificationEmail' => 'メール送出イベント',
|
||||
'Class:EventNotificationEmail+' => '送出されたメールのトレース',
|
||||
'Class:EventNotificationEmail/Attribute:to' => 'TO',
|
||||
'Class:EventNotificationEmail/Attribute:to+' => 'TO',
|
||||
'Class:EventNotificationEmail/Attribute:cc' => 'CC',
|
||||
'Class:EventNotificationEmail/Attribute:cc+' => 'CC',
|
||||
'Class:EventNotificationEmail/Attribute:bcc' => 'BCC',
|
||||
'Class:EventNotificationEmail/Attribute:bcc+' => 'BCC',
|
||||
'Class:EventNotificationEmail/Attribute:from' => 'From',
|
||||
'Class:EventNotificationEmail/Attribute:from+' => 'メール送信者',
|
||||
'Class:EventNotificationEmail/Attribute:subject' => 'Subject',
|
||||
'Class:EventNotificationEmail/Attribute:subject+' => '件名',
|
||||
'Class:EventNotificationEmail/Attribute:body' => 'Body',
|
||||
'Class:EventNotificationEmail/Attribute:body+' => '本文',
|
||||
));
|
||||
|
||||
//
|
||||
// Class: EventIssue
|
||||
//
|
||||
|
||||
Dict::Add('JA JP', 'Japanese', '日本語', array(
|
||||
'Class:EventIssue' => '課題',
|
||||
'Class:EventIssue+' => '課題(警告、エラー、etc)のトレース',
|
||||
'Class:EventIssue/Attribute:issue' => '課題',
|
||||
'Class:EventIssue/Attribute:issue+' => '課題',
|
||||
'Class:EventIssue/Attribute:impact' => 'インパクト',
|
||||
'Class:EventIssue/Attribute:impact+' => 'その結果',
|
||||
'Class:EventIssue/Attribute:page' => 'ページ',
|
||||
'Class:EventIssue/Attribute:page+' => 'HTTPエントリポイント',
|
||||
'Class:EventIssue/Attribute:arguments_post' => 'POSTされた引数',
|
||||
'Class:EventIssue/Attribute:arguments_post+' => 'HTTP POST引数',
|
||||
'Class:EventIssue/Attribute:arguments_get' => 'URLパラメータ',
|
||||
'Class:EventIssue/Attribute:arguments_get+' => 'HTTP GETパラメータ',
|
||||
'Class:EventIssue/Attribute:callstack' => 'コールスタック',
|
||||
'Class:EventIssue/Attribute:callstack+' => 'スタックをコールする',
|
||||
'Class:EventIssue/Attribute:data' => 'データ',
|
||||
'Class:EventIssue/Attribute:data+' => '追加情報',
|
||||
));
|
||||
|
||||
//
|
||||
// Class: EventWebService
|
||||
//
|
||||
|
||||
Dict::Add('JA JP', 'Japanese', '日本語', array(
|
||||
'Class:EventWebService' => 'ウェブサービスイベント',
|
||||
'Class:EventWebService+' => 'ウェブサービス呼出のトレース',
|
||||
'Class:EventWebService/Attribute:verb' => '動作',
|
||||
'Class:EventWebService/Attribute:verb+' => '操作名',
|
||||
'Class:EventWebService/Attribute:result' => '結果',
|
||||
'Class:EventWebService/Attribute:result+' => '総体的な成功/失敗',
|
||||
'Class:EventWebService/Attribute:log_info' => 'インフォログ',
|
||||
'Class:EventWebService/Attribute:log_info+' => 'インフォログの結果',
|
||||
'Class:EventWebService/Attribute:log_warning' => 'ワーニンググ',
|
||||
'Class:EventWebService/Attribute:log_warning+' => 'ワーニングログ結果',
|
||||
'Class:EventWebService/Attribute:log_error' => 'エラーログ',
|
||||
'Class:EventWebService/Attribute:log_error+' => 'エラーログ結果',
|
||||
'Class:EventWebService/Attribute:data' => 'データ',
|
||||
'Class:EventWebService/Attribute:data+' => '結果データ',
|
||||
));
|
||||
|
||||
//
|
||||
// Class: EventLoginUsage
|
||||
//
|
||||
|
||||
Dict::Add('JA JP', 'Japanese', '日本語', array(
|
||||
'Class:EventLoginUsage' => 'ログイン方法',
|
||||
'Class:EventLoginUsage+' => 'アプリケーションへ接続します。',
|
||||
'Class:EventLoginUsage/Attribute:user_id' => 'ログイン',
|
||||
'Class:EventLoginUsage/Attribute:user_id+' => 'ログイン',
|
||||
'Class:EventLoginUsage/Attribute:contact_name' => 'ユーザ名',
|
||||
'Class:EventLoginUsage/Attribute:contact_name+' => 'ユーザ名',
|
||||
'Class:EventLoginUsage/Attribute:contact_email' => 'ユーザのEmail',
|
||||
'Class:EventLoginUsage/Attribute:contact_email+' => 'ユーザの電子メールアドレス',
|
||||
));
|
||||
|
||||
//
|
||||
// Class: Action
|
||||
//
|
||||
|
||||
Dict::Add('JA JP', 'Japanese', '日本語', array(
|
||||
'Class:Action' => 'カスタムアクション',
|
||||
'Class:Action+' => 'ユーザ定義アクション',
|
||||
'Class:Action/Attribute:name' => '名前',
|
||||
'Class:Action/Attribute:name+' => '',
|
||||
'Class:Action/Attribute:description' => '説明',
|
||||
'Class:Action/Attribute:description+' => '',
|
||||
'Class:Action/Attribute:status' => '状態',
|
||||
'Class:Action/Attribute:status+' => '稼働中、あるいは?',
|
||||
'Class:Action/Attribute:status/Value:test' => 'テスト中',
|
||||
'Class:Action/Attribute:status/Value:test+' => 'テスト中',
|
||||
'Class:Action/Attribute:status/Value:enabled' => '稼働中',
|
||||
'Class:Action/Attribute:status/Value:enabled+' => '稼働中',
|
||||
'Class:Action/Attribute:status/Value:disabled' => '非アクティブ',
|
||||
'Class:Action/Attribute:status/Value:disabled+' => '非アクティブ',
|
||||
'Class:Action/Attribute:trigger_list' => '関連トリガー',
|
||||
'Class:Action/Attribute:trigger_list+' => 'このアクションにリンクされたトリガー',
|
||||
'Class:Action/Attribute:finalclass' => 'タイプ',
|
||||
'Class:Action/Attribute:finalclass+' => 'タイプ',
|
||||
));
|
||||
|
||||
//
|
||||
// Class: ActionNotification
|
||||
//
|
||||
|
||||
Dict::Add('JA JP', 'Japanese', '日本語', array(
|
||||
'Class:ActionNotification' => '通知',
|
||||
'Class:ActionNotification+' => '通知(要約)',
|
||||
));
|
||||
|
||||
//
|
||||
// Class: ActionEmail
|
||||
//
|
||||
|
||||
Dict::Add('JA JP', 'Japanese', '日本語', array(
|
||||
'Class:ActionEmail' => 'メール通知',
|
||||
'Class:ActionEmail+' => '',
|
||||
'Class:ActionEmail/Attribute:test_recipient' => 'テストレシピ',
|
||||
'Class:ActionEmail/Attribute:test_recipient+' => '状態がテストの場合の宛先',
|
||||
'Class:ActionEmail/Attribute:from' => 'From',
|
||||
'Class:ActionEmail/Attribute:from+' => 'Will be sent into the email header',
|
||||
'Class:ActionEmail/Attribute:reply_to' => 'Reply to',
|
||||
'Class:ActionEmail/Attribute:reply_to+' => 'Will be sent into the email header',
|
||||
'Class:ActionEmail/Attribute:to' => 'To',
|
||||
'Class:ActionEmail/Attribute:to+' => 'メールの宛先',
|
||||
'Class:ActionEmail/Attribute:cc' => 'Cc',
|
||||
'Class:ActionEmail/Attribute:cc+' => 'Carbon Copy',
|
||||
'Class:ActionEmail/Attribute:bcc' => 'bcc',
|
||||
'Class:ActionEmail/Attribute:bcc+' => 'Blind Carbon Copy',
|
||||
'Class:ActionEmail/Attribute:subject' => 'subject',
|
||||
'Class:ActionEmail/Attribute:subject+' => 'メールの題名',
|
||||
'Class:ActionEmail/Attribute:body' => 'body',
|
||||
'Class:ActionEmail/Attribute:body+' => 'メールの本文',
|
||||
'Class:ActionEmail/Attribute:importance' => '重要度',
|
||||
'Class:ActionEmail/Attribute:importance+' => '重要度フラグ',
|
||||
'Class:ActionEmail/Attribute:importance/Value:low' => '低',
|
||||
'Class:ActionEmail/Attribute:importance/Value:low+' => 'low',
|
||||
'Class:ActionEmail/Attribute:importance/Value:normal' => '中',
|
||||
'Class:ActionEmail/Attribute:importance/Value:normal+' => 'normal',
|
||||
'Class:ActionEmail/Attribute:importance/Value:high' => '高',
|
||||
'Class:ActionEmail/Attribute:importance/Value:high+' => 'high',
|
||||
));
|
||||
|
||||
//
|
||||
// Class: Trigger
|
||||
//
|
||||
|
||||
Dict::Add('JA JP', 'Japanese', '日本語', array(
|
||||
'Class:Trigger' => 'トリガー',
|
||||
'Class:Trigger+' => 'カスタムイベントハンドラー',
|
||||
'Class:Trigger/Attribute:description' => '説明',
|
||||
'Class:Trigger/Attribute:description+' => '1行の説明',
|
||||
'Class:Trigger/Attribute:action_list' => 'トリガーされたアクション',
|
||||
'Class:Trigger/Attribute:action_list+' => 'トリガーが発行された場合に動作するアクション',
|
||||
'Class:Trigger/Attribute:finalclass' => 'タイプ',
|
||||
'Class:Trigger/Attribute:finalclass+' => 'Type',
|
||||
));
|
||||
|
||||
//
|
||||
// Class: TriggerOnObject
|
||||
//
|
||||
|
||||
Dict::Add('JA JP', 'Japanese', '日本語', array(
|
||||
'Class:TriggerOnObject' => 'トリガー(クラス依存)',
|
||||
'Class:TriggerOnObject+' => 'オブジェクトの指定されたクラスのトリガー',
|
||||
'Class:TriggerOnObject/Attribute:target_class' => 'ターゲットクラス',
|
||||
'Class:TriggerOnObject/Attribute:target_class+' => '',
|
||||
));
|
||||
|
||||
//
|
||||
// Class: TriggerOnPortalUpdate
|
||||
//
|
||||
|
||||
Dict::Add('JA JP', 'Japanese', '日本語', array(
|
||||
'Class:TriggerOnPortalUpdate' => 'トリガー(ポータルから更新された時)',
|
||||
'Class:TriggerOnPortalUpdate+' => 'エンドユーザがポータルから更新した場合のトリガー',
|
||||
));
|
||||
|
||||
//
|
||||
// Class: TriggerOnStateChange
|
||||
//
|
||||
|
||||
Dict::Add('JA JP', 'Japanese', '日本語', array(
|
||||
'Class:TriggerOnStateChange' => '(状態変化の)トリガー',
|
||||
'Class:TriggerOnStateChange+' => 'オブジェクトの状態変化のトリガー',
|
||||
'Class:TriggerOnStateChange/Attribute:state' => '状態',
|
||||
'Class:TriggerOnStateChange/Attribute:state+' => 'State',
|
||||
));
|
||||
|
||||
//
|
||||
// Class: TriggerOnStateEnter
|
||||
//
|
||||
|
||||
Dict::Add('JA JP', 'Japanese', '日本語', array(
|
||||
'Class:TriggerOnStateEnter' => '入状態トリガー',
|
||||
'Class:TriggerOnStateEnter+' => 'オブジェクトの状態へ入る変化(エンター,on entering a state)時のトリガー',
|
||||
));
|
||||
|
||||
//
|
||||
// Class: TriggerOnStateLeave
|
||||
//
|
||||
|
||||
Dict::Add('JA JP', 'Japanese', '日本語', array(
|
||||
'Class:TriggerOnStateLeave' => '出状態トリガー',
|
||||
'Class:TriggerOnStateLeave+' => 'オブジェクトの状態から出る変化(リーブ,on leaving a state)時のトリガー',
|
||||
));
|
||||
|
||||
//
|
||||
// Class: TriggerOnObjectCreate
|
||||
//
|
||||
|
||||
Dict::Add('JA JP', 'Japanese', '日本語', array(
|
||||
'Class:TriggerOnObjectCreate' => 'オブジェクト作成トリガー',
|
||||
'Class:TriggerOnObjectCreate+' => '指定されたクラスの(子クラスの)オブジェクト作成時のトリガ',
|
||||
));
|
||||
|
||||
//
|
||||
// Class: lnkTriggerAction
|
||||
//
|
||||
|
||||
Dict::Add('JA JP', 'Japanese', '日本語', array(
|
||||
'Class:lnkTriggerAction' => 'トリガ/アクション',
|
||||
'Class:lnkTriggerAction+' => 'トリガとアクション間のリンク',
|
||||
'Class:lnkTriggerAction/Attribute:action_id' => 'アクション',
|
||||
'Class:lnkTriggerAction/Attribute:action_id+' => '実行されるアクション',
|
||||
'Class:lnkTriggerAction/Attribute:action_name' => 'アクション',
|
||||
'Class:lnkTriggerAction/Attribute:action_name+' => '',
|
||||
'Class:lnkTriggerAction/Attribute:trigger_id' => 'トリガ',
|
||||
'Class:lnkTriggerAction/Attribute:trigger_id+' => '',
|
||||
'Class:lnkTriggerAction/Attribute:trigger_name' => 'トリガ',
|
||||
'Class:lnkTriggerAction/Attribute:trigger_name+' => '',
|
||||
'Class:lnkTriggerAction/Attribute:order' => '順序',
|
||||
'Class:lnkTriggerAction/Attribute:order+' => 'アクション実行順序',
|
||||
));
|
||||
|
||||
//
|
||||
// Synchro Data Source
|
||||
//
|
||||
Dict::Add('JA JP', 'Japanese', '日本語', array(
|
||||
'Class:SynchroDataSource/Attribute:name' => '名前',
|
||||
'Class:SynchroDataSource/Attribute:name+' => '名前',
|
||||
'Class:SynchroDataSource/Attribute:description' => '説明',
|
||||
'Class:SynchroDataSource/Attribute:status' => '状態', //TODO: enum values
|
||||
'Class:SynchroDataSource/Attribute:scope_class' => 'ターゲットクラス',
|
||||
'Class:SynchroDataSource/Attribute:user_id' => 'ユーザ',
|
||||
'Class:SynchroDataSource/Attribute:notify_contact_id' => '通知する連絡先',
|
||||
'Class:SynchroDataSource/Attribute:notify_contact_id+' => 'エラーが発生した場合に通知する連絡先。',
|
||||
'Class:SynchroDataSource/Attribute:url_icon' => 'アイコンのハイパーリンク',
|
||||
'Class:SynchroDataSource/Attribute:url_icon+' => 'iTopが同期されたアプリケーションを示すハイパーリンク(小さな)イメージ',
|
||||
'Class:SynchroDataSource/Attribute:url_application' => 'アプリケーションのハイパーリンク',
|
||||
'Class:SynchroDataSource/Attribute:url_application+' => 'iTopが同期化された外部アプリケーションのiTopオブジェクトへのハイパーリンク(該当する場合)。可能なプレースホルダ: $this->attribute$ and $replica->primary_key$',
|
||||
'Class:SynchroDataSource/Attribute:reconciliation_policy' => '調整ポリシー', //TODO enum values
|
||||
'Class:SynchroDataSource/Attribute:full_load_periodicity' => '全データロードの間隔',
|
||||
'Class:SynchroDataSource/Attribute:full_load_periodicity+' => '全データの完全な再ロードを最低ここに指定されている間隔で行う必要があります。',
|
||||
'Class:SynchroDataSource/Attribute:action_on_zero' => '検索結果0件時のアクション',
|
||||
'Class:SynchroDataSource/Attribute:action_on_zero+' => '検索結果としてオブジェクトが何も返さない場合に実行されるアクション',
|
||||
'Class:SynchroDataSource/Attribute:action_on_one' => '検索結果1件時のアクション',
|
||||
'Class:SynchroDataSource/Attribute:action_on_one+' => '検索結果として一つのみのオブジェクトが返されたときに実行されるアクション',
|
||||
'Class:SynchroDataSource/Attribute:action_on_multiple' => '検索結果複数時のアクション',
|
||||
'Class:SynchroDataSource/Attribute:action_on_multiple+' => '検索結果として二つ以上のオブジェクトが返されたときに実行されるアクション',
|
||||
'Class:SynchroDataSource/Attribute:user_delete_policy' => '許可されたユーザ',
|
||||
'Class:SynchroDataSource/Attribute:user_delete_policy+' => '同期されたオブジェクトの削除が許可されたユーザ',
|
||||
// 'Class:SynchroDataSource/Attribute:user_delete_policy' => '許可されたユーザ', // double
|
||||
'Class:SynchroDataSource/Attribute:delete_policy/Value:never' => '誰もいない',//'Nobody',
|
||||
'Class:SynchroDataSource/Attribute:delete_policy/Value:depends' => '管理者のみ',
|
||||
'Class:SynchroDataSource/Attribute:delete_policy/Value:always' => '全ての許可されたユーザ',
|
||||
'Class:SynchroDataSource/Attribute:delete_policy_update' => '更新ルール',
|
||||
'Class:SynchroDataSource/Attribute:delete_policy_update+' => '構文: フィールド名:値; ...',
|
||||
'Class:SynchroDataSource/Attribute:delete_policy_retention' => '保持時間',
|
||||
'Class:SynchroDataSource/Attribute:delete_policy_retention+' => '廃止されたオブジェクトを削除するまでに保持しておく時間',
|
||||
'SynchroDataSource:Description' => '説明',
|
||||
'SynchroDataSource:Reconciliation' => '検索と調整',
|
||||
'SynchroDataSource:Deletion' => '削除ルール',
|
||||
'SynchroDataSource:Status' => '状態',
|
||||
'SynchroDataSource:Information' => 'インフォメーション',
|
||||
'SynchroDataSource:Definition' => '定義',
|
||||
'Core:SynchroAttributes' => '属性',
|
||||
'Core:SynchroStatus' => '状態',
|
||||
'Core:Synchro:ErrorsLabel' => 'エラー',
|
||||
'Core:Synchro:CreatedLabel' => '作成',
|
||||
'Core:Synchro:ModifiedLabel' => '修正',
|
||||
'Core:Synchro:UnchangedLabel' => '無変更',
|
||||
'Core:Synchro:ReconciledErrorsLabel' => 'エラー',
|
||||
'Core:Synchro:ReconciledLabel' => '調整',
|
||||
'Core:Synchro:ReconciledNewLabel' => '新',
|
||||
'Core:SynchroReconcile:Yes' => 'はい',
|
||||
'Core:SynchroReconcile:No' => 'いいえ',
|
||||
'Core:SynchroUpdate:Yes' => 'はい',
|
||||
'Core:SynchroUpdate:No' => 'いいえ',
|
||||
'Core:Synchro:LastestStatus' => '最新の状態',
|
||||
'Core:Synchro:History' => '同期履歴',
|
||||
'Core:Synchro:NeverRun' => 'この同期は実行されたことがありません。ログはありません。',
|
||||
'Core:Synchro:SynchroEndedOn_Date' => '最後の同期は %1$s に終了しました。',
|
||||
'Core:Synchro:SynchroRunningStartedOn_Date' => '同期は %1$s に始まり、現在実行中です。',
|
||||
'Menu:DataSources' => '同期データソース',
|
||||
'Menu:DataSources+' => '全ての同期データソース',
|
||||
'Core:Synchro:label_repl_ignored' => '無視 (%1$s)',
|
||||
'Core:Synchro:label_repl_disappeared' => '消えた (%1$s)',
|
||||
'Core:Synchro:label_repl_existing' => '存在 (%1$s)',
|
||||
'Core:Synchro:label_repl_new' => '新しい (%1$s)',
|
||||
'Core:Synchro:label_obj_deleted' => '削除 (%1$s)',
|
||||
'Core:Synchro:label_obj_obsoleted' => '廃止 (%1$s)',
|
||||
'Core:Synchro:label_obj_disappeared_errors' => 'エラー (%1$s)',
|
||||
'Core:Synchro:label_obj_disappeared_no_action' => '何もしない (%1$s)',
|
||||
'Core:Synchro:label_obj_unchanged' => '無変更 (%1$s)',
|
||||
'Core:Synchro:label_obj_updated' => '更新 (%1$s)',
|
||||
'Core:Synchro:label_obj_updated_errors' => 'エラー (%1$s)',
|
||||
'Core:Synchro:label_obj_new_unchanged' => '無変更 (%1$s)',
|
||||
'Core:Synchro:label_obj_new_updated' => '無変更 (%1$s)',
|
||||
'Core:Synchro:label_obj_created' => '作成 (%1$s)',
|
||||
'Core:Synchro:label_obj_new_errors' => 'エラー (%1$s)',
|
||||
'Core:Synchro:History' => '同期履歴',
|
||||
'Core:SynchroLogTitle' => '%1$s - %2$s',
|
||||
'Core:Synchro:Nb_Replica' => 'レプリカプロセス: %1$s',
|
||||
'Core:Synchro:Nb_Class:Objects' => '%1$s: %2$s',
|
||||
'Class:SynchroDataSource/Error:AtLeastOneReconciliationKeyMustBeSpecified' => '少なくとも一つの調整キーが必要です。または、調整ポリシーは主キーを使用しなければなりません。',
|
||||
'Class:SynchroDataSource/Error:DeleteRetentionDurationMustBeSpecified' => 'オブジェクトは廃止としてマークされた後に削除されますので、削除の保存期間を指定する必要があります。',
|
||||
'Class:SynchroDataSource/Error:DeletePolicyUpdateMustBeSpecified' => '廃止されたオブジェクトは更新されます、しかし、更新は指定されていません。',
|
||||
'Core:SynchroReplica:PublicData' => 'パブリックデータ',
|
||||
'Core:SynchroReplica:PrivateDetails' => 'プライベート詳細',
|
||||
'Core:SynchroReplica:BackToDataSource' => '同期データソースへ戻る: %1$s',
|
||||
'Core:SynchroReplica:ListOfReplicas' => 'レプリカのリスト',
|
||||
'Core:SynchroAttExtKey:ReconciliationById' => 'id (主キー)',
|
||||
'Core:SynchroAtt:attcode' => '属性',
|
||||
'Core:SynchroAtt:attcode+' => 'オブジェクトのフィールド',
|
||||
'Core:SynchroAtt:reconciliation' => '調整 ?',
|
||||
'Core:SynchroAtt:reconciliation+' => '検索に使用',
|
||||
'Core:SynchroAtt:update' => '更新 ?',
|
||||
'Core:SynchroAtt:update+' => 'オブジェクトの更新のため使用',
|
||||
'Core:SynchroAtt:update_policy' => '更新ポリシー',
|
||||
'Core:SynchroAtt:update_policy+' => '更新されたフィールドの振る舞い',
|
||||
'Core:SynchroAtt:reconciliation_attcode' => '調整キー',
|
||||
'Core:SynchroAtt:reconciliation_attcode+' => '外部キー調整用の属性コード',
|
||||
'Core:SyncDataExchangeComment' => '(データ同期)',
|
||||
'Core:Synchro:ListOfDataSources' => 'データソースのリスト:',
|
||||
'Core:Synchro:LastSynchro' => '最後の同期:',
|
||||
'Core:Synchro:ThisObjectIsSynchronized' => 'このオブジェクトは、外部データソースと同期されます。',
|
||||
'Core:Synchro:TheObjectWasCreatedBy_Source' => 'このオブジェクトは、外部データソース%1$sにより<b>作成</b>されました。',
|
||||
'Core:Synchro:TheObjectCanBeDeletedBy_Source' => 'オブジェクトは、外部データソース%1$sにより削除可能です。',
|
||||
'Core:Synchro:TheObjectCannotBeDeletedByUser_Source' => 'このオブジェクトは、外部データソースに保持されているので削除できません。',
|
||||
'TitleSynchroExecution' => '同期の実行',
|
||||
'Class:SynchroDataSource:DataTable' => 'データベーステーブル: %1$s',
|
||||
'Core:SyncDataSourceObsolete' => 'データソースは廃止とマークされています。操作はキャンセルされました。',
|
||||
'Core:SyncDataSourceAccessRestriction' => '管理者またはデータ·ソースに指定されたユーザーのみ、この操作を実行することができます。操作はキャンセルされました。',
|
||||
'Core:SyncTooManyMissingReplicas' => '暫くの間全てのレコードは変更されていません。(全てのオブジェクトが削除される可能性があります。)同期テーブルへ書き込むプロセスがまだ実行中であることを確認ください。操作は、キャンセルされました。',
|
||||
'Core:SyncSplitModeCLIOnly' => 'CLIモードでの実行時のみチャンクで同期を実行することが出来ます。',
|
||||
'Core:Synchro:ListReplicas_AllReplicas_Errors_Warnings' => '%1$s レプリカ、 %2$s エラー、 %3$s 警告。',
|
||||
'Core:SynchroReplica:TargetObject' => '同期されたオブジェクト: %1$s',
|
||||
'Class:AsyncSendEmail' => '電子メール (非同期)',
|
||||
'Class:AsyncSendEmail/Attribute:to' => 'To',
|
||||
'Class:AsyncSendEmail/Attribute:subject' => '件名',
|
||||
'Class:AsyncSendEmail/Attribute:body' => '本文',
|
||||
'Class:AsyncSendEmail/Attribute:header' => 'ヘッダー',
|
||||
'Class:CMDBChangeOpSetAttributeOneWayPassword' => '暗号化パスワード',
|
||||
'Class:CMDBChangeOpSetAttributeOneWayPassword/Attribute:prev_pwd' => '以前の値',
|
||||
'Class:CMDBChangeOpSetAttributeEncrypted' => '暗号化フィールド',
|
||||
'Class:CMDBChangeOpSetAttributeEncrypted/Attribute:prevstring' => '以前の値',
|
||||
'Class:CMDBChangeOpSetAttributeCaseLog' => 'ケースログ',
|
||||
'Class:CMDBChangeOpSetAttributeCaseLog/Attribute:lastentry' => '最後のエントリー',
|
||||
'Class:SynchroDataSource' => '同期データソース',
|
||||
'Class:SynchroDataSource/Attribute:status/Value:implementation' => '実装中',
|
||||
'Class:SynchroDataSource/Attribute:status/Value:obsolete' => '廃止済',
|
||||
'Class:SynchroDataSource/Attribute:status/Value:production' => '稼働中',
|
||||
'Class:SynchroDataSource/Attribute:scope_restriction' => '範囲の制限',
|
||||
'Class:SynchroDataSource/Attribute:reconciliation_policy/Value:use_attributes' => '属性を使用',
|
||||
'Class:SynchroDataSource/Attribute:reconciliation_policy/Value:use_primary_key' => '主キーフィールドを使用',
|
||||
'Class:SynchroDataSource/Attribute:action_on_zero/Value:create' => '作成',
|
||||
'Class:SynchroDataSource/Attribute:action_on_zero/Value:error' => 'エラー',
|
||||
'Class:SynchroDataSource/Attribute:action_on_one/Value:error' => 'エラー',
|
||||
'Class:SynchroDataSource/Attribute:action_on_one/Value:update' => '更新',
|
||||
'Class:SynchroDataSource/Attribute:action_on_multiple/Value:create' => '作成',
|
||||
'Class:SynchroDataSource/Attribute:action_on_multiple/Value:error' => 'エラー',
|
||||
'Class:SynchroDataSource/Attribute:action_on_multiple/Value:take_first' => '最初を採用 (ランダム?)',
|
||||
'Class:SynchroDataSource/Attribute:delete_policy' => '削除ポリシー',
|
||||
'Class:SynchroDataSource/Attribute:delete_policy/Value:delete' => '削除',
|
||||
'Class:SynchroDataSource/Attribute:delete_policy/Value:ignore' => '無視',
|
||||
'Class:SynchroDataSource/Attribute:delete_policy/Value:update' => '更新',
|
||||
'Class:SynchroDataSource/Attribute:delete_policy/Value:update_then_delete' => '更新そして削除',
|
||||
'Class:SynchroDataSource/Attribute:attribute_list' => '属性リスト',
|
||||
'Class:SynchroDataSource/Attribute:user_delete_policy/Value:administrators' => '管理者のみ',
|
||||
'Class:SynchroDataSource/Attribute:user_delete_policy/Value:everybody' => '誰でもがそのようなオブジェクトを削除出来ます。',
|
||||
'Class:SynchroDataSource/Attribute:user_delete_policy/Value:nobody' => 'nobody',
|
||||
'Class:SynchroAttribute' => '同期属性',
|
||||
'Class:SynchroAttribute/Attribute:sync_source_id' => '同期データソース',
|
||||
'Class:SynchroAttribute/Attribute:attcode' => '属性コード',
|
||||
'Class:SynchroAttribute/Attribute:update' => '更新',
|
||||
'Class:SynchroAttribute/Attribute:reconcile' => '調整',
|
||||
'Class:SynchroAttribute/Attribute:update_policy' => '更新ポリシー',
|
||||
'Class:SynchroAttribute/Attribute:update_policy/Value:master_locked' => 'ロック',
|
||||
'Class:SynchroAttribute/Attribute:update_policy/Value:master_unlocked' => 'アンロック',
|
||||
'Class:SynchroAttribute/Attribute:update_policy/Value:write_if_empty' => '空の場合は、初期化',
|
||||
'Class:SynchroAttribute/Attribute:finalclass' => 'クラス',
|
||||
'Class:SynchroAttExtKey' => '同期属性 (外部キー)',
|
||||
'Class:SynchroAttExtKey/Attribute:reconciliation_attcode' => '調整属性',
|
||||
'Class:SynchroAttLinkSet' => '同期属性 (リンクセット)',
|
||||
'Class:SynchroAttLinkSet/Attribute:row_separator' => '行の区切り',
|
||||
'Class:SynchroAttLinkSet/Attribute:attribute_separator' => '属性区切り',
|
||||
'Class:SynchroLog' => '同期ログ',
|
||||
'Class:SynchroLog/Attribute:sync_source_id' => '同期データソース',
|
||||
'Class:SynchroLog/Attribute:start_date' => '開始日',
|
||||
'Class:SynchroLog/Attribute:end_date' => '終了日',
|
||||
'Class:SynchroLog/Attribute:status' => '状態',
|
||||
'Class:SynchroLog/Attribute:status/Value:completed' => '完了',
|
||||
'Class:SynchroLog/Attribute:status/Value:error' => 'エラー',
|
||||
'Class:SynchroLog/Attribute:status/Value:running' => '実行中',
|
||||
'Class:SynchroLog/Attribute:stats_nb_replica_seen' => 'のレプリカ ',
|
||||
'Class:SynchroLog/Attribute:stats_nb_replica_total' => 'レプリカ合計 ',
|
||||
'Class:SynchroLog/Attribute:stats_nb_obj_deleted' => 'オブジェクト削除 ',
|
||||
'Class:SynchroLog/Attribute:stats_nb_obj_deleted_errors' => '削除中のエラー ',
|
||||
'Class:SynchroLog/Attribute:stats_nb_obj_obsoleted' => 'オブジェクト廃止 ',
|
||||
'Class:SynchroLog/Attribute:stats_nb_obj_obsoleted_errors' => '廃止中のエラー ',
|
||||
'Class:SynchroLog/Attribute:stats_nb_obj_created' => 'オブジェクト作成 ',
|
||||
'Class:SynchroLog/Attribute:stats_nb_obj_created_errors' => '作成中のエラー ',
|
||||
'Class:SynchroLog/Attribute:stats_nb_obj_updated' => 'オブジェクト更新 ',
|
||||
'Class:SynchroLog/Attribute:stats_nb_obj_updated_errors' => '更新中のエラー ',
|
||||
'Class:SynchroLog/Attribute:stats_nb_replica_reconciled_errors' => '調整中のエラー ',
|
||||
'Class:SynchroLog/Attribute:stats_nb_replica_disappeared_no_action' => 'レプリカ消 ',
|
||||
'Class:SynchroLog/Attribute:stats_nb_obj_new_updated' => ' オブジェクトは更新されました',
|
||||
'Class:SynchroLog/Attribute:stats_nb_obj_new_unchanged' => ' オブジェクトは変更されていません',
|
||||
'Class:SynchroLog/Attribute:last_error' => '最後のエラー',
|
||||
'Class:SynchroLog/Attribute:traces' => 'トレース',
|
||||
'Class:SynchroReplica' => '同期レプリカ',
|
||||
'Class:SynchroReplica/Attribute:sync_source_id' => '同期データソース',
|
||||
'Class:SynchroReplica/Attribute:dest_id' => '同期先オブジェクト (ID)',
|
||||
'Class:SynchroReplica/Attribute:dest_class' => '同期先タイプ',
|
||||
'Class:SynchroReplica/Attribute:status_last_seen' => 'ラストシーン',
|
||||
'Class:SynchroReplica/Attribute:status' => '状態',
|
||||
'Class:SynchroReplica/Attribute:status/Value:modified' => '修正済み',
|
||||
'Class:SynchroReplica/Attribute:status/Value:new' => '新規',
|
||||
'Class:SynchroReplica/Attribute:status/Value:obsolete' => '廃止',
|
||||
'Class:SynchroReplica/Attribute:status/Value:orphan' => '孤立',
|
||||
'Class:SynchroReplica/Attribute:status/Value:synchronized' => '同期済み',
|
||||
'Class:SynchroReplica/Attribute:status_dest_creator' => 'オブジェクト作成 ?',
|
||||
'Class:SynchroReplica/Attribute:status_last_error' => '最後のエラー',
|
||||
'Class:SynchroReplica/Attribute:status_last_warning' => '警告',
|
||||
'Class:SynchroReplica/Attribute:info_creation_date' => '作成日',
|
||||
'Class:SynchroReplica/Attribute:info_last_modified' => '最終修正日',
|
||||
'Class:appUserPreferences' => 'ユーザプリファレンス',
|
||||
'Class:appUserPreferences/Attribute:userid' => 'ユーザ',
|
||||
'Class:appUserPreferences/Attribute:preferences' => 'プリファレンス',
|
||||
'Core:ExecProcess:Code1' => '間違ったコマンドまたはエラーで終了したコマンド(例えば、間違ったスクリプト名)',
|
||||
'Core:ExecProcess:Code255' => 'PHP エラー (parsing, or runtime)',
|
||||
));
|
||||
|
||||
//
|
||||
// Attribute Duration
|
||||
//
|
||||
Dict::Add('JA JP', 'Japanese', '日本語', array(
|
||||
'Core:Duration_Seconds' => '%1$ds',
|
||||
'Core:Duration_Minutes_Seconds' =>'%1$d分 %2$d秒',
|
||||
'Core:Duration_Hours_Minutes_Seconds' => '%1$d時 %2$d分 %3$d秒',
|
||||
'Core:Duration_Days_Hours_Minutes_Seconds' => '%1$s日 %2$d時 %3$d分 %4$d秒',
|
||||
));
|
||||
|
||||
?>
|
||||
968
dictionaries/ja.dictionary.itop.ui.php
Normal file
@@ -0,0 +1,968 @@
|
||||
<?php
|
||||
// Copyright (C) 2010 Combodo SARL
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation; version 3 of the License.
|
||||
//
|
||||
// This program 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 General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
/**
|
||||
* Localized data
|
||||
*
|
||||
* @author Erwan Taloc <erwan.taloc@combodo.com>
|
||||
* @author Romain Quetiez <romain.quetiez@combodo.com>
|
||||
* @author Denis Flaven <denis.flaven@combodo.com>
|
||||
* @author Tadashi Kaneda <kaneda@rworks.jp>
|
||||
* @license http://www.opensource.org/licenses/gpl-3.0.html LGPL
|
||||
*/
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// Classes in 'gui'
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// Classes in 'application'
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
|
||||
//
|
||||
// Class: AuditCategory
|
||||
//
|
||||
|
||||
Dict::Add('JA JP', 'Japanese', '日本語', array(
|
||||
'Class:AuditCategory' => '監査カテゴリ',
|
||||
'Class:AuditCategory+' => '監査全体の内部セクション',
|
||||
'Class:AuditCategory/Attribute:name' => 'カテゴリ名',
|
||||
'Class:AuditCategory/Attribute:name+' => 'カテゴリの短縮名',
|
||||
'Class:AuditCategory/Attribute:description' => '監査カテゴリ説明',
|
||||
'Class:AuditCategory/Attribute:description+' => '監査カテゴリの説明',
|
||||
'Class:AuditCategory/Attribute:definition_set' => '定義セット',
|
||||
'Class:AuditCategory/Attribute:definition_set+' => '監査するべきオブジェクトの集合を定義するOQL式',
|
||||
'Class:AuditCategory/Attribute:rules_list' => '監査ルール',
|
||||
'Class:AuditCategory/Attribute:rules_list+' => 'このカテゴリの監査ルール',
|
||||
));
|
||||
|
||||
//
|
||||
// Class: AuditRule
|
||||
//
|
||||
|
||||
Dict::Add('JA JP', 'Japanese', '日本語', array(
|
||||
'Class:AuditRule' => '監査ルール',
|
||||
'Class:AuditRule+' => '指定された監査カテゴリをチェックするためのルール',
|
||||
'Class:AuditRule/Attribute:name' => 'ルール名',
|
||||
'Class:AuditRule/Attribute:name+' => 'ルールの短縮名',
|
||||
'Class:AuditRule/Attribute:description' => '監査ルール説明',
|
||||
'Class:AuditRule/Attribute:description+' => 'この監査ルールの長い説明',
|
||||
'Class:AuditRule/Attribute:query' => '実行するクエリ',
|
||||
'Class:AuditRule/Attribute:query+' => '実行するOQL式',
|
||||
'Class:AuditRule/Attribute:valid_flag' => '有効なオブジェクト',
|
||||
'Class:AuditRule/Attribute:valid_flag+' => 'このルールが有効なオブジェクトを返す場合は真、そうでなければ偽',
|
||||
'Class:AuditRule/Attribute:valid_flag/Value:true' => '真',
|
||||
'Class:AuditRule/Attribute:valid_flag/Value:true+' => '真',
|
||||
'Class:AuditRule/Attribute:valid_flag/Value:false' => '偽',
|
||||
'Class:AuditRule/Attribute:valid_flag/Value:false+' => '偽',
|
||||
'Class:AuditRule/Attribute:category_id' => 'カテゴリ',
|
||||
'Class:AuditRule/Attribute:category_id+' => 'このルールのカテゴリ',
|
||||
'Class:AuditRule/Attribute:category_name' => 'カテゴリ',
|
||||
'Class:AuditRule/Attribute:category_name+' => 'このルールのカテゴリ名',
|
||||
));
|
||||
|
||||
//
|
||||
// Class: QueryOQL
|
||||
//
|
||||
|
||||
Dict::Add('JA JP', 'Japanese', '日本語', array(
|
||||
'Class:Query' => 'クエリ',
|
||||
'Class:Query+' => 'クエリは動的な方法で定義されるデータセットです。',
|
||||
'Class:Query/Attribute:name' => '名前',
|
||||
'Class:Query/Attribute:name+' => 'クエリを識別します。',
|
||||
'Class:Query/Attribute:description' => '説明',
|
||||
'Class:Query/Attribute:description+' => 'クエリの長い説明(目的、使用方法等)',
|
||||
'Class:Query/Attribute:fields' => 'フィールド',
|
||||
'Class:Query/Attribute:fields+' => 'エクスポートする属性(またはエイリアス属性,alias.attribute)のコンマ区切り(CSV)リスト',
|
||||
|
||||
'Class:QueryOQL' => 'OQL クエリ',
|
||||
'Class:QueryOQL+' => ' Object Query Language に基づいたクエリ',
|
||||
'Class:QueryOQL/Attribute:oql' => '式',
|
||||
'Class:QueryOQL/Attribute:oql+' => 'OQL 式',
|
||||
));
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// Classes in 'addon/userrights'
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
|
||||
//
|
||||
// Class: User
|
||||
//
|
||||
|
||||
Dict::Add('JA JP', 'Japanese', '日本語', array(
|
||||
'Class:User' => 'ユーザー',
|
||||
'Class:User+' => 'ユーザーログイン',
|
||||
'Class:User/Attribute:finalclass' => 'アカウントタイプ',
|
||||
'Class:User/Attribute:finalclass+' => '',
|
||||
'Class:User/Attribute:contactid' => '連絡先(人物)',
|
||||
'Class:User/Attribute:contactid+' => 'ビジネスデータから抽出した個人の詳細',
|
||||
'Class:User/Attribute:last_name' => 'ラストネーム',
|
||||
'Class:User/Attribute:last_name+' => '対応する連絡先の名前',
|
||||
'Class:User/Attribute:first_name' => 'ファーストネーム',
|
||||
'Class:User/Attribute:first_name+' => '対応する連絡先のファーストネーム',
|
||||
'Class:User/Attribute:email' => 'メールアドレス',
|
||||
'Class:User/Attribute:email+' => '対応する連絡先のメールアドレス',
|
||||
'Class:User/Attribute:login' => 'ログイン',
|
||||
'Class:User/Attribute:login+' => 'ユーザ識別文字列',
|
||||
'Class:User/Attribute:language' => '言語',
|
||||
'Class:User/Attribute:language+' => 'ユーザ使用言語',
|
||||
'Class:User/Attribute:language/Value:EN US' => '英語',
|
||||
'Class:User/Attribute:language/Value:EN US+' => '英語(米国)',
|
||||
'Class:User/Attribute:language/Value:FR FR' => 'フランス語',
|
||||
'Class:User/Attribute:language/Value:FR FR+' => 'フランス語(フランス)',
|
||||
'Class:User/Attribute:profile_list' => 'プロフィール',
|
||||
'Class:User/Attribute:profile_list+' => '役割、この人物に付与された権限',
|
||||
'Class:User/Attribute:allowed_org_list' => '許可された組織',
|
||||
'Class:User/Attribute:allowed_org_list+' => 'エンドユーザは以下の組織に属するデータの参照を許可されています。組織が指定されていなければ、制限はありません。',
|
||||
|
||||
'Class:User/Error:LoginMustBeUnique' => 'ログイン名は一意でないといけません。- "%1s" はすでに使われています。',
|
||||
'Class:User/Error:AtLeastOneProfileIsNeeded' => '少なくとも1件のプロフィールがこのユーザに指定されなければなりません。',
|
||||
));
|
||||
|
||||
//
|
||||
// Class: URP_Profiles
|
||||
//
|
||||
|
||||
Dict::Add('JA JP', 'Japanese', '日本語', array(
|
||||
'Class:URP_Profiles' => 'プロフィール',
|
||||
'Class:URP_Profiles+' => 'ユーザプロフィール',
|
||||
'Class:URP_Profiles/Attribute:name' => '名前',
|
||||
'Class:URP_Profiles/Attribute:name+' => 'ラベル',
|
||||
'Class:URP_Profiles/Attribute:description' => '説明',
|
||||
'Class:URP_Profiles/Attribute:description+' => '1行の説明',
|
||||
'Class:URP_Profiles/Attribute:user_list' => 'ユーザー',
|
||||
'Class:URP_Profiles/Attribute:user_list+' => 'この役割をもつ人',
|
||||
));
|
||||
|
||||
//
|
||||
// Class: URP_Dimensions
|
||||
//
|
||||
|
||||
Dict::Add('JA JP', 'Japanese', '日本語', array(
|
||||
'Class:URP_Dimensions' => 'ディメンション',
|
||||
'Class:URP_Dimensions+' => 'アプリケーションディメンション(defining silos)',
|
||||
'Class:URP_Dimensions/Attribute:name' => '名前',
|
||||
'Class:URP_Dimensions/Attribute:name+' => 'ラベル',
|
||||
'Class:URP_Dimensions/Attribute:description' => '説明',
|
||||
'Class:URP_Dimensions/Attribute:description+' => '1行の説明',
|
||||
'Class:URP_Dimensions/Attribute:type' => 'タイプ',
|
||||
'Class:URP_Dimensions/Attribute:type+' => 'クラス名、もしくはデータ型(projection unit)',
|
||||
));
|
||||
|
||||
//
|
||||
// Class: URP_UserProfile
|
||||
//
|
||||
|
||||
Dict::Add('JA JP', 'Japanese', '日本語', array(
|
||||
'Class:URP_UserProfile' => 'ユーザープロフィール',
|
||||
'Class:URP_UserProfile+' => 'ユーザープロフィール',
|
||||
'Class:URP_UserProfile/Attribute:userid' => 'ユーザー',
|
||||
'Class:URP_UserProfile/Attribute:userid+' => 'ユーザアカウント',
|
||||
'Class:URP_UserProfile/Attribute:userlogin' => 'ログイン',
|
||||
'Class:URP_UserProfile/Attribute:userlogin+' => 'ユーザーのログイン',
|
||||
'Class:URP_UserProfile/Attribute:profileid' => 'プロフィール',
|
||||
'Class:URP_UserProfile/Attribute:profileid+' => '使用プロフィール',
|
||||
'Class:URP_UserProfile/Attribute:profile' => 'プロフィール',
|
||||
'Class:URP_UserProfile/Attribute:profile+' => 'プロフィール名',
|
||||
'Class:URP_UserProfile/Attribute:reason' => '理由',
|
||||
'Class:URP_UserProfile/Attribute:reason+' => 'なぜ、この人物がこの役割を持つかを説明する',
|
||||
));
|
||||
|
||||
//
|
||||
// Class: URP_UserOrg
|
||||
//
|
||||
|
||||
Dict::Add('JA JP', 'Japanese', '日本語', array(
|
||||
'Class:URP_UserOrg' => 'ユーザー組織',
|
||||
'Class:URP_UserOrg+' => '許可された組織',
|
||||
'Class:URP_UserOrg/Attribute:userid' => 'ユーザー',
|
||||
'Class:URP_UserOrg/Attribute:userid+' => 'ユーザーアカウント',
|
||||
'Class:URP_UserOrg/Attribute:userlogin' => 'ログイン',
|
||||
'Class:URP_UserOrg/Attribute:userlogin+' => 'ユーザのログイン',
|
||||
'Class:URP_UserOrg/Attribute:allowed_org_id' => '組織',
|
||||
'Class:URP_UserOrg/Attribute:allowed_org_id+' => '許可された組織',
|
||||
'Class:URP_UserOrg/Attribute:allowed_org_name' => '組織',
|
||||
'Class:URP_UserOrg/Attribute:allowed_org_name+' => '許可された組織',
|
||||
'Class:URP_UserOrg/Attribute:reason' => '理由',
|
||||
'Class:URP_UserOrg/Attribute:reason+' => 'なぜこの人物がこの組織に属するデータを参照できるのかを説明する',
|
||||
));
|
||||
|
||||
//
|
||||
// Class: URP_ProfileProjection
|
||||
//
|
||||
|
||||
Dict::Add('JA JP', 'Japanese', '日本語', array(
|
||||
'Class:URP_ProfileProjection' => 'プロフィールプロジェクション',
|
||||
'Class:URP_ProfileProjection+' => 'プロフィールプロジェクション',
|
||||
'Class:URP_ProfileProjection/Attribute:dimensionid' => 'ディメンション',
|
||||
'Class:URP_ProfileProjection/Attribute:dimensionid+' => 'アプリケーションディメンション',
|
||||
'Class:URP_ProfileProjection/Attribute:dimension' => 'ディメンション',
|
||||
'Class:URP_ProfileProjection/Attribute:dimension+' => 'アプリケーションディメンション',
|
||||
'Class:URP_ProfileProjection/Attribute:profileid' => 'プロフィール',
|
||||
'Class:URP_ProfileProjection/Attribute:profileid+' => '使用プロフィール',
|
||||
'Class:URP_ProfileProjection/Attribute:profile' => 'プロフィール',
|
||||
'Class:URP_ProfileProjection/Attribute:profile+' => 'プロフィール名',
|
||||
'Class:URP_ProfileProjection/Attribute:value' => 'Value式',
|
||||
'Class:URP_ProfileProjection/Attribute:value+' => '($userを使う)OQL式 | 定数 | | +属性コード',
|
||||
'Class:URP_ProfileProjection/Attribute:attribute' => '属性',
|
||||
'Class:URP_ProfileProjection/Attribute:attribute+' => 'ターゲット属性コード (オプション)',
|
||||
));
|
||||
|
||||
//
|
||||
// Class: URP_ClassProjection
|
||||
//
|
||||
|
||||
Dict::Add('JA JP', 'Japanese', '日本語', array(
|
||||
'Class:URP_ClassProjection' => 'クラスプロジェクション',
|
||||
'Class:URP_ClassProjection+' => 'クラスのプロジェクション',
|
||||
'Class:URP_ClassProjection/Attribute:dimensionid' => 'ディメンション',
|
||||
'Class:URP_ClassProjection/Attribute:dimensionid+' => 'アプリケーションディメンション',
|
||||
'Class:URP_ClassProjection/Attribute:dimension' => 'ディメンション',
|
||||
'Class:URP_ClassProjection/Attribute:dimension+' => 'アプリケーションディメンション',
|
||||
'Class:URP_ClassProjection/Attribute:class' => 'クラス',
|
||||
'Class:URP_ClassProjection/Attribute:class+' => 'ターゲットクラス',
|
||||
'Class:URP_ClassProjection/Attribute:value' => '値式',
|
||||
'Class:URP_ClassProjection/Attribute:value+' => '($this を使った)OQL式 | 定数 | | +属性コード',
|
||||
'Class:URP_ClassProjection/Attribute:attribute' => '属性',
|
||||
'Class:URP_ClassProjection/Attribute:attribute+' => 'ターゲット属性コード(オプション)',
|
||||
));
|
||||
|
||||
//
|
||||
// Class: URP_ActionGrant
|
||||
//
|
||||
|
||||
Dict::Add('JA JP', 'Japanese', '日本語', array(
|
||||
'Class:URP_ActionGrant' => 'アクション権限',
|
||||
'Class:URP_ActionGrant+' => 'クラスに対する権限',
|
||||
'Class:URP_ActionGrant/Attribute:profileid' => 'プロフィール',
|
||||
'Class:URP_ActionGrant/Attribute:profileid+' => '使用プロフィール',
|
||||
'Class:URP_ActionGrant/Attribute:profile' => 'プロフィール',
|
||||
'Class:URP_ActionGrant/Attribute:profile+' => '使用プロフィール',
|
||||
'Class:URP_ActionGrant/Attribute:class' => 'クラス',
|
||||
'Class:URP_ActionGrant/Attribute:class+' => 'ターゲットクラス',
|
||||
'Class:URP_ActionGrant/Attribute:permission' => '許可',
|
||||
'Class:URP_ActionGrant/Attribute:permission+' => '許可の有無は?',
|
||||
'Class:URP_ActionGrant/Attribute:permission/Value:yes' => 'はい',
|
||||
'Class:URP_ActionGrant/Attribute:permission/Value:yes+' => 'はい',
|
||||
'Class:URP_ActionGrant/Attribute:permission/Value:no' => 'いいえ',
|
||||
'Class:URP_ActionGrant/Attribute:permission/Value:no+' => 'いいえ',
|
||||
'Class:URP_ActionGrant/Attribute:action' => 'アクション',
|
||||
'Class:URP_ActionGrant/Attribute:action+' => '指定されたクラスに実行する操作',
|
||||
));
|
||||
|
||||
//
|
||||
// Class: URP_StimulusGrant
|
||||
//
|
||||
|
||||
Dict::Add('JA JP', 'Japanese', '日本語', array(
|
||||
'Class:URP_StimulusGrant' => 'シティミュラス権限',
|
||||
'Class:URP_StimulusGrant+' => 'オブジェクトのライフサイクル中のシティミュラスにおける権限',
|
||||
'Class:URP_StimulusGrant/Attribute:profileid' => 'プロフィール',
|
||||
'Class:URP_StimulusGrant/Attribute:profileid+' => '使用プロフィール',
|
||||
'Class:URP_StimulusGrant/Attribute:profile' => 'プロフィール',
|
||||
'Class:URP_StimulusGrant/Attribute:profile+' => '使用プロフィール',
|
||||
'Class:URP_StimulusGrant/Attribute:class' => 'クラス',
|
||||
'Class:URP_StimulusGrant/Attribute:class+' => 'ターゲットクラス',
|
||||
'Class:URP_StimulusGrant/Attribute:permission' => '権限',
|
||||
'Class:URP_StimulusGrant/Attribute:permission+' => '許可されているか、いないか。',
|
||||
'Class:URP_StimulusGrant/Attribute:permission/Value:yes' => 'はい',
|
||||
'Class:URP_StimulusGrant/Attribute:permission/Value:yes+' => 'はい',
|
||||
'Class:URP_StimulusGrant/Attribute:permission/Value:no' => 'いいえ',
|
||||
'Class:URP_StimulusGrant/Attribute:permission/Value:no+' => 'いいえ',
|
||||
'Class:URP_StimulusGrant/Attribute:stimulus' => 'シティミュラス',
|
||||
'Class:URP_StimulusGrant/Attribute:stimulus+' => 'シティミュラスコード',
|
||||
));
|
||||
|
||||
//
|
||||
// Class: URP_AttributeGrant
|
||||
//
|
||||
|
||||
Dict::Add('JA JP', 'Japanese', '日本語', array(
|
||||
'Class:URP_AttributeGrant' => '属性権限',
|
||||
'Class:URP_AttributeGrant+' => '属性レベルでの権限',
|
||||
'Class:URP_AttributeGrant/Attribute:actiongrantid' => '実行権限',
|
||||
'Class:URP_AttributeGrant/Attribute:actiongrantid+' => '実行権限',
|
||||
'Class:URP_AttributeGrant/Attribute:attcode' => '属性',
|
||||
'Class:URP_AttributeGrant/Attribute:attcode+' => '属性コード',
|
||||
));
|
||||
|
||||
//
|
||||
// String from the User Interface: menu, messages, buttons, etc...
|
||||
//
|
||||
|
||||
Dict::Add('JA JP', 'Japanese', '日本語', array(
|
||||
'Menu:WelcomeMenu' => 'ようこそ',
|
||||
'Menu:WelcomeMenu+' => 'ようこそ、iTopへ',
|
||||
'Menu:WelcomeMenuPage' => 'ようこそ',
|
||||
'Menu:WelcomeMenuPage+' => 'ようこそ、iTopへ',
|
||||
'UI:WelcomeMenu:Title' => 'ようこそ、iTopへ',
|
||||
|
||||
'UI:WelcomeMenu:LeftBlock' => '<p>iTopは、オープンソースの、完結したIT運用ポータルです。</p>
|
||||
<ul>以下を含みます。
|
||||
<li>ITインベントリを文書化し、管理するための完全なCMDB(構成管理データベース)。</li>
|
||||
<li>IT環境で発生する出来事を追跡、共有するためのインシデント管理モジュール。</li>
|
||||
<li>IT環境への変更を計画、追跡するための変更管理モジュール。</li>
|
||||
<li>インシデントの解決をスピードアップするための既知のエラーデータベース。</li>
|
||||
<li>すべての計画停止を文書化し、適切な連絡先を通知するために停止モジュール。</li>
|
||||
<li>ITの概観を素早く得るためのダッシュボード。</li>
|
||||
</ul>
|
||||
<p>すべてのモジュールはお互いに独立しており、別個にセットアップが可能です。</p>',
|
||||
|
||||
'UI:WelcomeMenu:RightBlock' => '<p>iTopはサービスプロバイダ志向であり、ITエンジニアが複数の顧客や組織を簡単に管理できるようになります。
|
||||
<ul>iTopは、機能豊富な下記のビジネスプロセスのセットを提供します。
|
||||
<li>IT管理の実効性の強化。</li>
|
||||
<li>IT運用効率化の推進。</li>
|
||||
<li>顧客満足度の改善と、業績への洞察を経営経営幹部へ提供。</li>
|
||||
</ul>
|
||||
</p>
|
||||
<p>iTopは完全にオープンなので、あなたが今使っているIT管理インフラとの統合が可能です。</p>
|
||||
<p>
|
||||
<ul>この新世代IT運用ポータルの採用は、下記のお手伝いをします。
|
||||
<li>ますます複雑になるIT環境のより良い管理。</li>
|
||||
<li>あなたのペースでのITILプロセス実装。</li>
|
||||
<li>ITの中でもっとも重要な財産である「文書化」の管理。</li>
|
||||
</ul>
|
||||
</p>',
|
||||
'UI:WelcomeMenu:AllOpenRequests' => '要求を開く: %1$d',
|
||||
'UI:WelcomeMenu:MyCalls' => '担当中の要求',
|
||||
'UI:WelcomeMenu:OpenIncidents' => 'インシデントを開く: %1$d',
|
||||
'UI:WelcomeMenu:AllConfigItems' => '構成項目(CI): %1$d',
|
||||
'UI:WelcomeMenu:MyIncidents' => '担当中のインシデント',
|
||||
'UI:AllOrganizations' => '全ての組織',
|
||||
'UI:YourSearch' => '検索',
|
||||
'UI:LoggedAsMessage' => '%1$s としてログインする',
|
||||
'UI:LoggedAsMessage+Admin' => '%1$s (管理者)としてログインする',
|
||||
'UI:Button:Logoff' => 'ログオフ',
|
||||
'UI:Button:GlobalSearch' => '検索',
|
||||
'UI:Button:Search' => ' 検索 ',
|
||||
'UI:Button:Query' => ' クエリ',
|
||||
'UI:Button:Ok' => 'OK',
|
||||
'UI:Button:Cancel' => 'キャンセル',
|
||||
'UI:Button:Apply' => '適用する',
|
||||
'UI:Button:Back' => ' << 戻る',
|
||||
'UI:Button:Restart' => ' |<< リスタート',
|
||||
'UI:Button:Next' => ' 次へ >> ',
|
||||
'UI:Button:Finish' => ' 終了 ',
|
||||
'UI:Button:DoImport' => ' インポート実行! ',
|
||||
'UI:Button:Done' => ' 完了 ',
|
||||
'UI:Button:SimulateImport' => ' インポートをシュミレート ',
|
||||
'UI:Button:Test' => 'テスト実行!',
|
||||
'UI:Button:Evaluate' => ' 評価 ',
|
||||
'UI:Button:AddObject' => ' 追加...',
|
||||
'UI:Button:BrowseObjects' => 'ブラウズ...',
|
||||
'UI:Button:Add' => ' 追加 ',
|
||||
'UI:Button:AddToList' => ' << 追加 ',
|
||||
'UI:Button:RemoveFromList' => '削除 >> ',
|
||||
'UI:Button:FilterList' => ' フィルタ... ',
|
||||
'UI:Button:Create' => ' 作成 ',
|
||||
'UI:Button:Delete' => ' 削除! ',
|
||||
'UI:Button:ChangePassword' => ' パスワード変更 ',
|
||||
'UI:Button:ResetPassword' => 'パスワードリセット ',
|
||||
|
||||
'UI:SearchToggle' => '検索(トグル↓↑)',
|
||||
'UI:ClickToCreateNew' => '新規 %1$s を作成',
|
||||
'UI:SearchFor_Class' => '%1$s オブジェクトを検索',
|
||||
'UI:NoObjectToDisplay' => '表示するオブジェクトはありません。',
|
||||
'UI:Error:MandatoryTemplateParameter_object_id' => 'link_attrが指定されている時は、object_idパラメータは必須です。表示テンプレートの定義を確認してください。',
|
||||
'UI:Error:MandatoryTemplateParameter_target_attr' => 'link_attrを指定する場合は、target_attrパラメータは必須です。表示テンプレートの定義を確認してください。',
|
||||
'UI:Error:MandatoryTemplateParameter_group_by' => 'group_byパラメータは必須です。表示テンプレートの定義を確認してください。',
|
||||
'UI:Error:InvalidGroupByFields' => '無効なフィールドリストです。 group by: "%1$s".',
|
||||
'UI:Error:UnsupportedStyleOfBlock' => 'エラー:サポートされていないブロックスタイル:"%1$s"',
|
||||
'UI:Error:IncorrectLinkDefinition_LinkedClass_Class' => '不正なリンク定義: 管理オブジェクトのクラス:%1$s は、クラス %2$s 中の外部キーとして見つかりません。',
|
||||
'UI:Error:Object_Class_Id_NotFound' => 'オブジェクト:%1$s:%2$d が見つかりません。',
|
||||
'UI:Error:WizardCircularReferenceInDependencies' => 'エラー: フィールド間の依存関係に循環参照があります。データモデルを確認してください。',
|
||||
'UI:Error:UploadedFileTooBig' => 'アップロードファイルが大きすぎます(上限は %1$s )。PHPの設定 upload_max_filesizeと、post_max_sizeを確認してください。',
|
||||
'UI:Error:UploadedFileTruncated.' => 'アップロードファイルが切り捨てられました!',
|
||||
'UI:Error:NoTmpDir' => '一時ディレクトリは定義されていません。',
|
||||
'UI:Error:CannotWriteToTmp_Dir' => '一時ファイルをディスクに書き込めません。upload_tmp_dir = "%1$s"',
|
||||
'UI:Error:UploadStoppedByExtension_FileName' => 'extensionにより、アップロードを停止しました。(オリジナルのファイル名は"%1$s"です)。',
|
||||
'UI:Error:UploadFailedUnknownCause_Code' => 'ファイルのアップロードに失敗しました。原因は不明(エラーコード: "%1$s")です。',
|
||||
|
||||
'UI:Error:1ParametersMissing' => 'エラー: この操作には下記のパラメータを指定する必要があります:%1$s',
|
||||
'UI:Error:2ParametersMissing' => 'エラー:この操作には、下記のパラメータを指定する必要があります:%1$s , %2$s',
|
||||
'UI:Error:3ParametersMissing' => 'エラー:この操作には、下記のパラメータを指定する必要があります:%1$s, %2$s, %3$s',
|
||||
'UI:Error:4ParametersMissing' => 'エラー:この操作には、下記のパラメータを指定する必要があります:%1$s, %2$s, %3$s,%4$s',
|
||||
'UI:Error:IncorrectOQLQuery_Message' => 'エラー:誤ったOQLクエリ:%1$s',
|
||||
'UI:Error:AnErrorOccuredWhileRunningTheQuery_Message' => 'クエリ:%1$s 実行中にエラーが発生しました。',
|
||||
'UI:Error:ObjectAlreadyUpdated' => 'エラー:このオブジェクトはすでに更新済みです。',
|
||||
'UI:Error:ObjectCannotBeUpdated' => 'エラー:オブジェクトを更新できません。',
|
||||
'UI:Error:ObjectsAlreadyDeleted' => 'エラー:オブジェクトは既に削除されています。',
|
||||
'UI:Error:BulkDeleteNotAllowedOn_Class' => '%1$s クラスのオブジェクトに対するバルク削除の実行は許可されていません。',
|
||||
'UI:Error:DeleteNotAllowedOn_Class' => '%1$s クラスのオブジェクトの削除は許可されていません。',
|
||||
'UI:Error:BulkModifyNotAllowedOn_Class' => '%1$s クラスのオブジェクトに対するバルクアップデートの実行は許可されていません。',
|
||||
'UI:Error:ObjectAlreadyCloned' => 'エラー:このオブジェクトはすでに、クローンされています。',
|
||||
'UI:Error:ObjectAlreadyCreated' => 'エラー:このオブジェクトは既に作成済みです。',
|
||||
'UI:Error:Invalid_Stimulus_On_Object_In_State' => 'エラー:状態"%3$s"のオブジェクト%2$s上の無効なスティミュラス"%1$s".',
|
||||
|
||||
|
||||
'UI:GroupBy:Count' => 'カウント',
|
||||
'UI:GroupBy:Count+' => '要素数',
|
||||
'UI:CountOfObjects' => '%1$d 個のオブジェクトが条件にマッチしました。',
|
||||
'UI_CountOfObjectsShort' => '%1$d オブジェクト。',
|
||||
'UI:NoObject_Class_ToDisplay' => '表示する %1$s はありません。',
|
||||
'UI:History:LastModified_On_By' => '%2$sによる最終更新 %1$s',
|
||||
'UI:HistoryTab' => '履歴',
|
||||
'UI:NotificationsTab' => '通知',
|
||||
'UI:History:BulkImports' => '履歴',
|
||||
'UI:History:BulkImports+' => 'CSVインポートのリスト(last first)',
|
||||
'UI:History:BulkImportDetails' => '(%2$s により)実行された %1$s へCSVインポートによる変更結果',
|
||||
'UI:History:Date' => '日付',
|
||||
'UI:History:Date+' => '変更日',
|
||||
'UI:History:User' => 'ユーザー',
|
||||
'UI:History:User+' => 'この変更を行ったユーザー',
|
||||
'UI:History:Changes' => '変更',
|
||||
'UI:History:Changes+' => 'このオブジェクトを変更する',
|
||||
'UI:History:StatsCreations' => '作成',
|
||||
'UI:History:StatsCreations+' => '作成されたオブジェクト数',
|
||||
'UI:History:StatsModifs' => '修正',
|
||||
'UI:History:StatsModifs+' => '修正されたオブジェクト数',
|
||||
'UI:History:StatsDeletes' => '削除',
|
||||
'UI:History:StatsDeletes+' => '削除されたオブジェクト数',
|
||||
'UI:Loading' => '読み込み...',
|
||||
'UI:Menu:Actions' => '実行',
|
||||
'UI:Menu:OtherActions' => 'その他の実行',
|
||||
'UI:Menu:New' => '新規...',
|
||||
'UI:Menu:Add' => '追加...',
|
||||
'UI:Menu:Manage' => '管理...',
|
||||
'UI:Menu:EMail' => 'Eメール',
|
||||
'UI:Menu:CSVExport' => 'CSVエクスポート',
|
||||
'UI:Menu:Modify' => '修正...',
|
||||
'UI:Menu:Delete' => '削除...',
|
||||
'UI:Menu:Manage' => '管理...',
|
||||
'UI:Menu:BulkDelete' => '削除...',
|
||||
'UI:UndefinedObject' => '未定義',
|
||||
'UI:Document:OpenInNewWindow:Download' => '新規ウィンドウで開く: %1$s、 ダウンロード: %2$s',
|
||||
'UI:SelectAllToggle+' => 'すべて選択 / すべて非選択',
|
||||
'UI:SplitDateTime-Date' => '日付',
|
||||
'UI:SplitDateTime-Time' => '時刻',
|
||||
'UI:TruncatedResults' => '%2$d中%1$dのオブジェクトを表示',
|
||||
'UI:DisplayAll' => 'すべて表示',
|
||||
'UI:CollapseList' => '折りたたむ',
|
||||
'UI:CountOfResults' => '%1$d オブジェクト',
|
||||
'UI:ChangesLogTitle' => '変更履歴(%1$d)',
|
||||
'UI:EmptyChangesLogTitle' => '変更履歴は空です。',
|
||||
'UI:SearchFor_Class_Objects' => '%1$s オブジェクトを検索',
|
||||
'UI:OQLQueryBuilderTitle' => 'OQLクエリビルダ',
|
||||
'UI:OQLQueryTab' => 'OQLクエリ',
|
||||
'UI:SimpleSearchTab' => '単純検索',
|
||||
'UI:Details+' => '詳細',
|
||||
'UI:SearchValue:Any' => '* 任意 *',
|
||||
'UI:SearchValue:Mixed' => '* 混成 *',
|
||||
'UI:SelectOne' => '-- 選んでください --',
|
||||
'UI:Login:Welcome' => 'iTopへようこそ',
|
||||
'UI:Login:IncorrectLoginPassword' => 'ログイン/パスワードが正しくありません。再度ログインしてください。',
|
||||
'UI:Login:IdentifyYourself' => '続けて作業を行う前に認証を受けてください。',
|
||||
'UI:Login:UserNamePrompt' => 'ユーザー名',
|
||||
'UI:Login:PasswordPrompt' => 'パスワード',
|
||||
'UI:Login:About' => '',
|
||||
'UI:Login:ChangeYourPassword' => 'パスワードを変更してください',
|
||||
'UI:Login:OldPasswordPrompt' => '古いパスワード',
|
||||
'UI:Login:NewPasswordPrompt' => '新しいパスワード',
|
||||
'UI:Login:RetypeNewPasswordPrompt' => '新しいパスワードを再度入力してください。',
|
||||
'UI:Login:IncorrectOldPassword' => 'エラー:既存パスワードが正しくありません。',
|
||||
'UI:LogOffMenu' => 'ログオフ',
|
||||
'UI:LogOff:ThankYou' => 'iTopをご利用いただき、ありがとうございます。',
|
||||
'UI:LogOff:ClickHereToLoginAgain' => '再度ログインするにはここをクリックしてください...',
|
||||
'UI:ChangePwdMenu' => 'パスワードを変更する...',
|
||||
'UI:Login:PasswordChanged' => 'パスワードは変更されました。',
|
||||
'UI:AccessRO-All' => 'iTopは参照専用です。',
|
||||
'UI:AccessRO-Users' => 'エンドユーザの方はiTopは参照専用です。',
|
||||
'UI:Login:RetypePwdDoesNotMatch' => '2度入力された新しいパスワードが一致しません!',
|
||||
'UI:Button:Login' => 'iTopへ入る',
|
||||
'UI:Login:Error:AccessRestricted' => 'iTopへのアクセスは制限されています。iTop管理者に問い合わせしてください。',
|
||||
'UI:Login:Error:AccessAdmin' => '管理者権限をもつユーザにアクセスが制限されています。iTop管理者に問い合わせしてください。',
|
||||
'UI:CSVImport:MappingSelectOne' => '-- 選択してください --',
|
||||
'UI:CSVImport:MappingNotApplicable' => '--このフィールドを無視する --',
|
||||
'UI:CSVImport:NoData' => '空のデータセット..., データを提供してください。',
|
||||
'UI:Title:DataPreview' => 'データプレビュー',
|
||||
'UI:CSVImport:ErrorOnlyOneColumn' => 'エラー:このデータにはカラムが1つしか含まれていません。適切なセパレータ文字を選択しましたか。',
|
||||
'UI:CSVImport:FieldName' => 'フィールド %1$d',
|
||||
'UI:CSVImport:DataLine1' => 'データ行 1',
|
||||
'UI:CSVImport:DataLine2' => 'データ行 2',
|
||||
'UI:CSVImport:idField' => 'ID (主キー)',
|
||||
'UI:Title:BulkImport' => 'iTop - バルクインポート',
|
||||
'UI:Title:BulkImport+' => 'CSV インポートウィザード',
|
||||
'UI:Title:BulkSynchro_nbItem_ofClass_class' => '%2$s クラスの %1$d オブジェクトを同期',
|
||||
'UI:CSVImport:ClassesSelectOne' => '--選択してください --',
|
||||
'UI:CSVImport:ErrorExtendedAttCode' => '内部エラー: "%2$s" は"%3$s"クラスの外部キーではないので、"%1$s" は誤ったコードです。',
|
||||
'UI:CSVImport:ObjectsWillStayUnchanged' => '%1$d オブジェクトは変更されません。',
|
||||
'UI:CSVImport:ObjectsWillBeModified' => '%1$d オブジェクトが修正されます。',
|
||||
'UI:CSVImport:ObjectsWillBeAdded' => '%1$d オブジェクトが追加されます。',
|
||||
'UI:CSVImport:ObjectsWillHaveErrors' => '%1$d オブジェクトにエラーがあります。',
|
||||
'UI:CSVImport:ObjectsRemainedUnchanged' => '%1$d オブジェクトは変更されていません。',
|
||||
'UI:CSVImport:ObjectsWereModified' => '%1$d オブジェクトが修正されました。',
|
||||
'UI:CSVImport:ObjectsWereAdded' => '%1$d オブジェクトが追加されました。',
|
||||
'UI:CSVImport:ObjectsHadErrors' => '%1$s オブジェクトにエラーがあります。',
|
||||
'UI:Title:CSVImportStep2' => 'ステップ2/5: CSVデータオプション',
|
||||
'UI:Title:CSVImportStep3' => 'ステップ3/5: データマッピング',
|
||||
'UI:Title:CSVImportStep4' => 'ステップ4/5: インポートシミュレーション',
|
||||
'UI:Title:CSVImportStep5' => 'ステップ5/5: インポート完了',
|
||||
'UI:CSVImport:LinesNotImported' => 'ロードできなかった行:',
|
||||
'UI:CSVImport:LinesNotImported+' => '下記の行はエラーが含まれていたのでインポートされませんでした。',
|
||||
'UI:CSVImport:SeparatorComma+' => ', (コンマ)',
|
||||
'UI:CSVImport:SeparatorSemicolon+' => '; (セミコロン)',
|
||||
'UI:CSVImport:SeparatorTab+' => 'タブ',
|
||||
'UI:CSVImport:SeparatorOther' => 'その他:',
|
||||
'UI:CSVImport:QualifierDoubleQuote+' => '" (ダブルクォート)',
|
||||
'UI:CSVImport:QualifierSimpleQuote+' => '\' (シングルクォート)',
|
||||
'UI:CSVImport:QualifierOther' => 'その他:',
|
||||
'UI:CSVImport:TreatFirstLineAsHeader' => '1行めをヘッダ(カラム名)として扱う。',
|
||||
'UI:CSVImport:Skip_N_LinesAtTheBeginning' => 'ファイル最初の%1$s 行をスキップする',
|
||||
'UI:CSVImport:CSVDataPreview' => 'CSVデータプレビュー',
|
||||
'UI:CSVImport:SelectFile' => 'インポートするファイルを選択してください:',
|
||||
'UI:CSVImport:Tab:LoadFromFile' => 'ファイルからロード',
|
||||
'UI:CSVImport:Tab:CopyPaste' => 'データをコピーとペースト',
|
||||
'UI:CSVImport:Tab:Templates' => 'テンプレート',
|
||||
'UI:CSVImport:PasteData' => 'インポートするデータをペーストしてください:',
|
||||
'UI:CSVImport:PickClassForTemplate' => 'ダウンロードするテンプレートを選んでください',
|
||||
'UI:CSVImport:SeparatorCharacter' => 'セパレータ文字',
|
||||
'UI:CSVImport:TextQualifierCharacter' => 'テキスト修飾子文字',
|
||||
'UI:CSVImport:CommentsAndHeader' => 'コメントとヘッダ',
|
||||
'UI:CSVImport:SelectClass' => 'インポートするクラスを選択してください:',
|
||||
'UI:CSVImport:AdvancedMode' => '拡張モード',
|
||||
'UI:CSVImport:AdvancedMode+' => '拡張モードでは、オブジェクトの"id"(主キー)はオブジェクトの更新、リネームに使用可能です。' .
|
||||
'しかしながら、"id"カラムは(たとえ存在しても)検索条件として使用可能なだけであり、他の検索条件と組み合わせて利用することはできません。',
|
||||
'UI:CSVImport:SelectAClassFirst' => 'マッピングを設定するには、まず最初にクラスを選択してください。',
|
||||
'UI:CSVImport:HeaderFields' => 'フィールド',
|
||||
'UI:CSVImport:HeaderMappings' => 'マッピング',
|
||||
'UI:CSVImport:HeaderSearch' => '検索しますか',
|
||||
'UI:CSVImport:AlertIncompleteMapping' => 'すべてのフィールドのマッピングを選択してください。',
|
||||
'UI:CSVImport:AlertNoSearchCriteria' => '少なくとも1つ以上の検索条件を選択してください。',
|
||||
'UI:CSVImport:Encoding' => '文字エンコーディング',
|
||||
'UI:UniversalSearchTitle' => 'iTop - ユニバーサル検索',
|
||||
'UI:UniversalSearch:Error' => 'エラー:%1$s',
|
||||
'UI:UniversalSearch:LabelSelectTheClass' => '検索するクラスを選択してください。',
|
||||
|
||||
'UI:Audit:Title' => 'iTop - CMDB 監査',
|
||||
'UI:Audit:InteractiveAudit' => '対話型監査',
|
||||
'UI:Audit:HeaderAuditRule' => '監査ルール',
|
||||
'UI:Audit:HeaderNbObjects' => 'オブジェクト数',
|
||||
'UI:Audit:HeaderNbErrors' => 'エラー数',
|
||||
'UI:Audit:PercentageOk' => '% OK',
|
||||
'UI:Audit:ErrorIn_Rule_Reason' => 'ルール %1$s 中のOQLエラー: %2$s.',
|
||||
'UI:Audit:ErrorIn_Category_Reason' => 'カテゴリ %1$s 中のOQLエラー: %2$s.',
|
||||
|
||||
'UI:RunQuery:Title' => 'iTop - OQLクエリ評価',
|
||||
'UI:RunQuery:QueryExamples' => 'クエリの例',
|
||||
'UI:RunQuery:HeaderPurpose' => '目的',
|
||||
'UI:RunQuery:HeaderPurpose+' => 'クエリについての説明',
|
||||
'UI:RunQuery:HeaderOQLExpression' => 'OQL式',
|
||||
'UI:RunQuery:HeaderOQLExpression+' => 'OQL文法によるクエリ',
|
||||
'UI:RunQuery:ExpressionToEvaluate' => '評価式',
|
||||
'UI:RunQuery:MoreInfo' => 'クエリに関する追加情報',
|
||||
'UI:RunQuery:DevelopedQuery' => 'クエリ式の再開発',
|
||||
'UI:RunQuery:SerializedFilter' => 'シリアライズされたフィルタ:',
|
||||
'UI:RunQuery:Error' => 'クエリ: %1$s 実行時にエラーが発生しました',
|
||||
'UI:Query:UrlForExcel' => 'MS-Excel Webクエリに使用するURL',
|
||||
'UI:Schema:Title' => 'iTop オブジェクトスキーマ',
|
||||
'UI:Schema:CategoryMenuItem' => 'カテゴリ <b>%1$s</b>',
|
||||
'UI:Schema:Relationships' => '関係',
|
||||
'UI:Schema:AbstractClass' => '抽象クラス:このクラスのインスタンスを作成することはできません。',
|
||||
'UI:Schema:NonAbstractClass' => '非抽象クラス:このクラスのインスタンスを作成できます。',
|
||||
'UI:Schema:ClassHierarchyTitle' => 'クラス階層',
|
||||
'UI:Schema:AllClasses' => '全クラス',
|
||||
'UI:Schema:ExternalKey_To' => '%1$s への外部キー',
|
||||
'UI:Schema:Columns_Description' => 'カラム: <em>%1$s</em>',
|
||||
'UI:Schema:Default_Description' => 'デフォルト: "%1$s"',
|
||||
'UI:Schema:NullAllowed' => 'Nullを許容',
|
||||
'UI:Schema:NullNotAllowed' => 'Nullを非許容',
|
||||
'UI:Schema:Attributes' => '属性',
|
||||
'UI:Schema:AttributeCode' => '属性コード',
|
||||
'UI:Schema:AttributeCode+' => '属性の内部コード',
|
||||
'UI:Schema:Label' => 'ラベル',
|
||||
'UI:Schema:Label+' => '属性のラベル',
|
||||
'UI:Schema:Type' => '型',
|
||||
|
||||
'UI:Schema:Type+' => '属性のデータ型',
|
||||
'UI:Schema:Origin' => 'オリジン',
|
||||
'UI:Schema:Origin+' => 'この属性が定義されているベースクラス',
|
||||
'UI:Schema:Description' => '説明',
|
||||
'UI:Schema:Description+' => 'この属性の概要',
|
||||
'UI:Schema:AllowedValues' => '可能な値',
|
||||
'UI:Schema:AllowedValues+' => '本属性で可能な値の制限',
|
||||
'UI:Schema:MoreInfo' => '追加情報',
|
||||
'UI:Schema:MoreInfo+' => 'データベースに定義された本フィールドの追加情報',
|
||||
'UI:Schema:SearchCriteria' => '検索条件',
|
||||
'UI:Schema:FilterCode' => 'フィルタコード',
|
||||
'UI:Schema:FilterCode+' => '本検索条件のコード',
|
||||
'UI:Schema:FilterDescription' => '説明',
|
||||
'UI:Schema:FilterDescription+' => '本検索条件の説明',
|
||||
'UI:Schema:AvailOperators' => '利用可能な演算子',
|
||||
'UI:Schema:AvailOperators+' => '本検索条件で利用可能な演算子',
|
||||
'UI:Schema:ChildClasses' => '子クラス',
|
||||
'UI:Schema:ReferencingClasses' => '参照クラス',
|
||||
'UI:Schema:RelatedClasses' => '関係するクラス',
|
||||
'UI:Schema:LifeCycle' => 'ライフサイクル',
|
||||
'UI:Schema:Triggers' => 'トリガー',
|
||||
'UI:Schema:Relation_Code_Description' => 'リレーション <em>%1$s</em> (%2$s)',
|
||||
'UI:Schema:RelationDown_Description' => '下へ: %1$s',
|
||||
'UI:Schema:RelationUp_Description' => '上へ: %1$s',
|
||||
'UI:Schema:RelationPropagates' => '%1$s: %2$d レベルへ伝播、クエリ:%3$s',
|
||||
'UI:Schema:RelationDoesNotPropagate' => '%1$s: 伝播しない (%2$d レベル), クエリ: %3$s',
|
||||
'UI:Schema:Class_ReferencingClasses_From_By' => '%1$s は%2$s クラスから %3$s フィールドにより参照されている',
|
||||
'UI:Schema:Class_IsLinkedTo_Class_Via_ClassAndAttribute' => '%1$s は %3$s::<em>%4$s</em>により%2$s へリンクされています。',
|
||||
'UI:Schema:Links:1-n' => 'クラスは%1$sへポイントしています。(1:n リンク)',
|
||||
'UI:Schema:Links:n-n' => 'クラスは%1$sへリンクしています。(n:n リンク)',
|
||||
'UI:Schema:Links:All' => '関連する全クラスのグラフ表示',
|
||||
'UI:Schema:NoLifeCyle' => 'このクラスにはライフサイクルが定義されていません。',
|
||||
'UI:Schema:LifeCycleTransitions' => 'トランジション',
|
||||
'UI:Schema:LifeCyleAttributeOptions' => '属性オプション',
|
||||
'UI:Schema:LifeCycleHiddenAttribute' => '隠し',
|
||||
'UI:Schema:LifeCycleReadOnlyAttribute' => '参照のみ',
|
||||
'UI:Schema:LifeCycleMandatoryAttribute' => '必須',
|
||||
'UI:Schema:LifeCycleAttributeMustChange' => '変更必須',
|
||||
'UI:Schema:LifeCycleAttributeMustPrompt' => 'ユーザはこの値を変更するよう、促されます。',
|
||||
'UI:Schema:LifeCycleEmptyList' => '空リスト',
|
||||
'UI:LinksWidget:Autocomplete+' => '最初の3文字をタイプしてください...',
|
||||
'UI:Edit:TestQuery' => 'Test query',
|
||||
'UI:Combo:SelectValue' => '--- 値を選んでください ---',
|
||||
'UI:Label:SelectedObjects' => '選択されたオブジェクト: ',
|
||||
'UI:Label:AvailableObjects' => '利用可能なオブジェクト: ',
|
||||
'UI:Link_Class_Attributes' => '%1$s 属性',
|
||||
'UI:SelectAllToggle+' => '全てを選択 / 全てを非選択',
|
||||
'UI:AddObjectsOf_Class_LinkedWith_Class_Instance' => '%2$s にリンクされた%1$sオブジェクトを追加:%3$s',
|
||||
'UI:AddObjectsOf_Class_LinkedWith_Class' => '%1$s オブジェクトを%2$sとのリンクに追加',
|
||||
'UI:ManageObjectsOf_Class_LinkedWith_Class_Instance' => '%2$s にリンクされた%1$sオブジェクトの管理: %3$s',
|
||||
'UI:AddLinkedObjectsOf_Class' => '%1$s を追加...',
|
||||
'UI:RemoveLinkedObjectsOf_Class' => '選択されたオブジェクトを削除',
|
||||
'UI:Message:EmptyList:UseAdd' => 'リストは空です。"追加..."ボタンを利用して要素を追加してください。',
|
||||
'UI:Message:EmptyList:UseSearchForm' => '上の検索フォームを使って追加するオブジェクトを検索してください。',
|
||||
'UI:Wizard:FinalStepTitle' => '最終ステップ:確認',
|
||||
'UI:Title:DeletionOf_Object' => '%1$sの削除',
|
||||
'UI:Title:BulkDeletionOf_Count_ObjectsOf_Class' => '%2$s クラスの%1$d個のオブジェクトをバルク削除',
|
||||
'UI:Delete:NotAllowedToDelete' => 'このオブジェクトの削除は、許可されていません。',
|
||||
'UI:Delete:NotAllowedToUpdate_Fields' => '以下のフィールドの更新は、許可されていません。: %1$s',
|
||||
'UI:Error:NotEnoughRightsToDelete' => 'カレントユーザは十分な権限を持っていないので、このオブジェクトは削除することができません。',
|
||||
'UI:Error:CannotDeleteBecause' => 'このオブジェクトは、削除できません。理由: %1$s',
|
||||
'UI:Error:CannotDeleteBecauseOfDepencies' => 'いくつかの手動操作を先に実行する必要があるので、このオブジェクトは削除できません。',
|
||||
'UI:Error:CannotDeleteBecauseManualOpNeeded' => 'いくつかの手動操作を先に実行する必要があるので、このオブジェクトは削除できません。',
|
||||
'UI:Archive_User_OnBehalfOf_User' => '%2$s の代りに %1$s',
|
||||
'UI:Delete:Deleted' => '削除済み',
|
||||
'UI:Delete:AutomaticallyDeleted' => '自動的に削除されました。',
|
||||
'UI:Delete:AutomaticResetOf_Fields' => 'フィールドの自動リセット: %1$s',
|
||||
'UI:Delete:CleaningUpRefencesTo_Object' => '%1$s への参照すべてをクリア',
|
||||
'UI:Delete:CleaningUpRefencesTo_Several_ObjectsOf_Class' => '%2$s クラスの %1$d個のオブジェクトへの参照をすべてクリア',
|
||||
'UI:Delete:Done+' => '実行しました...',
|
||||
'UI:Delete:_Name_Class_Deleted' => '%1$s - %2$s 削除しました。',
|
||||
'UI:Delete:ConfirmDeletionOf_Name' => '%1$s の削除',
|
||||
'UI:Delete:ConfirmDeletionOf_Count_ObjectsOf_Class' => '%2$sクラスの%1$dオブジェクトの削除',
|
||||
'UI:Delete:CannotDeleteBecause' => '削除できません: %1$s',
|
||||
'UI:Delete:ShouldBeDeletedAtomaticallyButNotAllowed' => '自動的に削除されるべきですが、それは許可されていません。',
|
||||
'UI:Delete:MustBeDeletedManuallyButNotAllowed' => '手動で削除されるべきですが、このオブジェクトの削除は許可されていません。アプリケーション管理者に問い合わせてください。',
|
||||
'UI:Delete:WillBeDeletedAutomatically' => '自動的に削除されます。',
|
||||
'UI:Delete:MustBeDeletedManually' => '手動で削除されるべきです。',
|
||||
'UI:Delete:CannotUpdateBecause_Issue' => '自動的に更新されるべきですが、しかし: %1$s',
|
||||
'UI:Delete:WillAutomaticallyUpdate_Fields' => '自動的に更新されます。(reset: %1$s)',
|
||||
'UI:Delete:Count_Objects/LinksReferencing_Object' => '%1$dオブジェクト/リンクは%2$sを参照しています。',
|
||||
'UI:Delete:Count_Objects/LinksReferencingTheObjects' => '%1$dオブジェクト/リンクは削除されるオブジェクトを参照しています。',
|
||||
'UI:Delete:ReferencesMustBeDeletedToEnsureIntegrity' => 'データベースの整合性を確保するために、いくつかの参照を削除する必要があります。',
|
||||
'UI:Delete:Consequence+' => '行われます。',
|
||||
'UI:Delete:SorryDeletionNotAllowed' => '申し訳ありませんが、あなたは、このオブジェクトを削除する権限がありません、上記の詳細な説明を参照してください。',
|
||||
'UI:Delete:PleaseDoTheManualOperations' => 'このオブジェクトの削除を要求する前に、上記にリストされている手動操作を実行してください。',
|
||||
'UI:Delect:Confirm_Object' => '%1$sを削除しようとしています。確認ください。',
|
||||
'UI:Delect:Confirm_Count_ObjectsOf_Class' => '以下の%2$sクラスの%1$dオブジェクトを削除しようとしています。確認ください。',
|
||||
'UI:WelcomeToITop' => 'iTopへようこそ',
|
||||
'UI:DetailsPageTitle' => 'iTop - %1$s - %2$sの詳細',
|
||||
'UI:ErrorPageTitle' => 'iTop - エラー',
|
||||
'UI:ObjectDoesNotExist' => '申し訳ございません。このオブジェクトは既に存在しません。(あるいは参照する権限がありません。)',
|
||||
'UI:SearchResultsPageTitle' => 'iTop - 検索結果',
|
||||
'UI:Search:NoSearch' => '検索するものがありません。',
|
||||
'UI:FullTextSearchTitle_Text' => '"%1$s"の結果:',
|
||||
'UI:Search:Count_ObjectsOf_Class_Found' => '%2$sクラスの%1$dオブジェクトが見つかりました。',
|
||||
'UI:Search:NoObjectFound' => 'オブジェクトが見つかりませんでした。',
|
||||
'UI:ModificationPageTitle_Object_Class' => 'iTop - %1$s - %2$s 修正',
|
||||
'UI:ModificationTitle_Class_Object' => '%1$sの修正: <span class=\"hilite\">%2$s</span>',
|
||||
'UI:ClonePageTitle_Object_Class' => 'iTop - クローン%1$s - %2$s 修正',
|
||||
'UI:CloneTitle_Class_Object' => '%1$sのクローン:<span class=\"hilite">%2$s</span>',
|
||||
'UI:CreationPageTitle_Class' => 'iTop - 新規%1$sを作成',
|
||||
'UI:CreationTitle_Class' => '新規%1$sの作成',
|
||||
'UI:SelectTheTypeOf_Class_ToCreate' => '作成する%1$sのタイプを選択:',
|
||||
'UI:Class_Object_NotUpdated' => '変更は検出されませんでした。%1$s(%2$s)は修正されて<strong>いません</strong>',
|
||||
'UI:Class_Object_Updated' => '%1$s (%2$s) は更新されました。',
|
||||
'UI:BulkDeletePageTitle' => 'iTop - バルク削除',
|
||||
'UI:BulkDeleteTitle' => '削除するオブジェクトを選択してください。',
|
||||
'UI:PageTitle:ObjectCreated' => 'iTopオブジェクトが作成されました。',
|
||||
'UI:Title:Object_Of_Class_Created' => '%1$s - %2$s が作成されました。',
|
||||
'UI:Apply_Stimulus_On_Object_In_State_ToTarget_State' => '状態%3$sにあるオブジェクト:%2$sに、ターゲット状態:%4$sで、%1$sを適用します。',
|
||||
'UI:ObjectCouldNotBeWritten' => 'そのオブジェクトへは書き込みできません: %1$s',
|
||||
'UI:PageTitle:FatalError' => 'iTop - 致命的なエラー',
|
||||
'UI:SystemIntrusion' => 'アクセスが拒否されました。あなたが許可されていない操作を実行しようとしています。',
|
||||
'UI:FatalErrorMessage' => '致命的なエラー、ITOPを続行することはできません。',
|
||||
'UI:Error_Details' => 'エラー:%1$s',
|
||||
|
||||
'UI:PageTitle:ClassProjections' => 'iTop ユーザ管理 - クラスプロジェクション',
|
||||
'UI:PageTitle:ProfileProjections' => 'iTop ユーザ管理 - プロフィールプロジェクション',
|
||||
'UI:UserManagement:Class' => 'クラス',
|
||||
'UI:UserManagement:Class+' => 'オブジェクトのクラス',
|
||||
'UI:UserManagement:ProjectedObject' => 'オブジェクト',
|
||||
'UI:UserManagement:ProjectedObject+' => 'プロジェクトオブジェクト',
|
||||
'UI:UserManagement:AnyObject' => '* 任意 *',
|
||||
'UI:UserManagement:User' => 'ユーザ',
|
||||
'UI:UserManagement:User+' => 'このプロジェクションに関与しているユーザー',
|
||||
'UI:UserManagement:Profile' => 'プロフィール',
|
||||
'UI:UserManagement:Profile+' => 'プロジェクションが指定されているプロフィール',
|
||||
'UI:UserManagement:Action:Read' => '読み込み',
|
||||
'UI:UserManagement:Action:Read+' => 'オブジェクトの読み込み/表示',
|
||||
'UI:UserManagement:Action:Modify' => '修正',
|
||||
'UI:UserManagement:Action:Modify+' => 'オブジェクトの作成、編集(修正)',
|
||||
'UI:UserManagement:Action:Delete' => '削除',
|
||||
'UI:UserManagement:Action:Delete+' => 'オブジェクトの削除',
|
||||
'UI:UserManagement:Action:BulkRead' => '一括読み出し(エクスポート)',
|
||||
'UI:UserManagement:Action:BulkRead+' => 'オブジェクトのリスト表示、もしくは一括エクスポート',
|
||||
'UI:UserManagement:Action:BulkModify' => '一括修正',
|
||||
'UI:UserManagement:Action:BulkModify+' => '一括作成/編集(CVSインポート)',
|
||||
'UI:UserManagement:Action:BulkDelete' => '一括削除',
|
||||
'UI:UserManagement:Action:BulkDelete+' => '複数オブジェクトをまとめて削除',
|
||||
'UI:UserManagement:Action:Stimuli' => 'Stimuli',
|
||||
'UI:UserManagement:Action:Stimuli+' => '許可されている(複合)アクション',
|
||||
'UI:UserManagement:Action' => 'アクション',
|
||||
'UI:UserManagement:Action+' => 'ユーザが実行したアクション',
|
||||
'UI:UserManagement:TitleActions' => 'アクション',
|
||||
'UI:UserManagement:Permission' => 'パーミッション',
|
||||
'UI:UserManagement:Permission+' => 'ユーザのパーミッション',
|
||||
'UI:UserManagement:Attributes' => '属性',
|
||||
'UI:UserManagement:ActionAllowed:Yes' => 'はい',
|
||||
'UI:UserManagement:ActionAllowed:No' => 'いいえ',
|
||||
'UI:UserManagement:AdminProfile+' => '管理者はデータベース中の全てのオブジェクトに対する全ての読み/書き権限を持っています。',
|
||||
'UI:UserManagement:NoLifeCycleApplicable' => 'N/A',
|
||||
'UI:UserManagement:NoLifeCycleApplicable+' => 'このクラスにはライフサイクルは定義されていません。',
|
||||
'UI:UserManagement:GrantMatrix' => '権限マトリクス',
|
||||
'UI:UserManagement:LinkBetween_User_And_Profile' => '%1$s と %2$s間のリンク',
|
||||
'UI:UserManagement:LinkBetween_User_And_Org' => '%1$s と %2$s 間のリンク',
|
||||
|
||||
'Menu:AdminTools' => '管理ツール',
|
||||
'Menu:AdminTools+' => '管理ツール',
|
||||
'Menu:AdminTools?' => 'このツールは管理者プロフィールを持つユーザのみアクセスが可能です。',
|
||||
|
||||
'UI:ChangeManagementMenu' => '変更管理',
|
||||
'UI:ChangeManagementMenu+' => '変更管理',
|
||||
'UI:ChangeManagementMenu:Title' => '変更管理概要',
|
||||
'UI-ChangeManagementMenu-ChangesByType' => 'タイプ別変更',
|
||||
'UI-ChangeManagementMenu-ChangesByStatus' => '状態別変更',
|
||||
'UI-ChangeManagementMenu-ChangesByWorkgroup' => 'ワークグループ別変更',
|
||||
'UI-ChangeManagementMenu-ChangesNotYetAssigned' => 'まだ割り当てられていない変更',
|
||||
|
||||
'UI:ConfigurationItemsMenu'=> '設定項目',
|
||||
'UI:ConfigurationItemsMenu+'=> 'すべてのデバイス',
|
||||
'UI:ConfigurationItemsMenu:Title' => '設定項目概要',
|
||||
'UI-ConfigurationItemsMenu-ServersByCriticity' => 'サーバ(by criticity)', // 'Servers by criticity',
|
||||
'UI-ConfigurationItemsMenu-PCsByCriticity' => 'PC (by criticity)', // 'PCs by criticity',
|
||||
'UI-ConfigurationItemsMenu-NWDevicesByCriticity' => 'ネットワークデバイス (by criticity)', // 'Network devices by criticity',
|
||||
'UI-ConfigurationItemsMenu-ApplicationsByCriticity' => 'アプリケーション (by criticity)', // 'Applications by criticity',
|
||||
|
||||
'UI:ConfigurationManagementMenu' => '構成管理',
|
||||
'UI:ConfigurationManagementMenu+' => '構成管理',
|
||||
'UI:ConfigurationManagementMenu:Title' => 'インフラ概要',
|
||||
'UI-ConfigurationManagementMenu-InfraByType' => 'タイプ別インフラオブジェクト',
|
||||
'UI-ConfigurationManagementMenu-InfraByStatus' => '状態別インフラオブジェクト',
|
||||
|
||||
'UI:ConfigMgmtMenuOverview:Title' => '構成管理ダッシュボード',
|
||||
'UI-ConfigMgmtMenuOverview-FunctionalCIbyStatus' => '状態別構成項目',
|
||||
'UI-ConfigMgmtMenuOverview-FunctionalCIByType' => 'タイプ別構成項目',
|
||||
|
||||
'UI:RequestMgmtMenuOverview:Title' => '要求管理ダッシュボード',
|
||||
'UI-RequestManagementOverview-RequestByService' => 'サービス別要求',
|
||||
'UI-RequestManagementOverview-RequestByPriority' => '優先度別要求',
|
||||
'UI-RequestManagementOverview-RequestUnassigned' => 'エージェントへ未割り当て要求',
|
||||
|
||||
'UI:IncidentMgmtMenuOverview:Title' => 'インシデント管理ダッシュボード',
|
||||
'UI-IncidentManagementOverview-IncidentByService' => 'サービス別インシデント',
|
||||
'UI-IncidentManagementOverview-IncidentByPriority' => '優先度別インシデント',
|
||||
'UI-IncidentManagementOverview-IncidentUnassigned' => 'エージェントへ未割り当てインシデント',
|
||||
|
||||
'UI:ChangeMgmtMenuOverview:Title' => '変更管理ダッシュボード',
|
||||
'UI-ChangeManagementOverview-ChangeByType' => 'タイプ別変更内容',
|
||||
'UI-ChangeManagementOverview-ChangeUnassigned' => 'エージェントへ未割り当て変更内容',
|
||||
'UI-ChangeManagementOverview-ChangeWithOutage' => '変更に伴う停止',
|
||||
|
||||
'UI:ServiceMgmtMenuOverview:Title' => 'サービス管理ダッシュボード',
|
||||
'UI-ServiceManagementOverview-CustomerContractToRenew' => '30日以内に契約更新が必要な顧客',
|
||||
'UI-ServiceManagementOverview-ProviderContractToRenew' => '30日以内に契約更新が必要なプロバイダ',
|
||||
|
||||
'UI:ContactsMenu' => '連絡先',
|
||||
'UI:ContactsMenu+' => '連絡先',
|
||||
'UI:ContactsMenu:Title' => '連絡先概要',
|
||||
'UI-ContactsMenu-ContactsByLocation' => '場所別連絡先',
|
||||
'UI-ContactsMenu-ContactsByType' => 'タイプ別連絡先',
|
||||
'UI-ContactsMenu-ContactsByStatus' => '状態別連絡先',
|
||||
|
||||
'Menu:CSVImportMenu' => 'CSV インポート',
|
||||
'Menu:CSVImportMenu+' => '一括作成/一括更新',
|
||||
|
||||
'Menu:DataModelMenu' => 'データモデル',
|
||||
'Menu:DataModelMenu+' => 'データモデル概要',
|
||||
|
||||
'Menu:ExportMenu' => 'エクスポート',
|
||||
'Menu:ExportMenu+' => '任意のクエリ結果をHTML、CSV、XMLでエクスポートする',
|
||||
|
||||
'Menu:NotificationsMenu' => '通知',
|
||||
'Menu:NotificationsMenu+' => '通知の設定',
|
||||
'UI:NotificationsMenu:Title' => '<span class="hilite">通知</span>の設定',
|
||||
'UI:NotificationsMenu:Help' => 'ヘルプ',
|
||||
'UI:NotificationsMenu:HelpContent' => '<p>iTopでは、通知はすべてカスタマイズが可能です。通知は<i>トリガーとアクション</i>という二つのオブジェクトがベースになっています。
|
||||
<p><i><b>トリガー</b></i>は、ある通知がいつ実行されるのか、を定義します。トリガーは3つのタイプに分類され、オブジェクトライフサイクルにおける3つの異なるフェーズに対応します:
|
||||
<ol>
|
||||
<li>"onCreate"トリガーは、指定されたクラスのオブジェクトが作成されたときに実行されます。</li>
|
||||
<li>"onStateEnter"トリガーは、指定されたクラスのオブジェクトが(他の状態から)指定された状態に入る前に実行されます。</li>
|
||||
<li>"onStateLeave"トリガーは、指定されたクラスのオブジェクトが指定された状態から出る際に実行されます。</li>
|
||||
</ol>
|
||||
</p>
|
||||
<p>
|
||||
<i><b>アクション</b></i>はトリガーが実行される際の動作を定義します。例えば今、「メールを送信する」という動作で構成されるたった1種類だけのアクションがあるとします。
|
||||
このようなアクションは、受信者、重要度といったメッセージに付随する他のパラメータと同様、メール送信に利用されるテンプレートも定義します。
|
||||
</p>
|
||||
<p>特別なページ: <a href="../setup/email.test.php" target="_blank">email.test.php</p>は、PHPのメール設定をテストしたりトラブルシュートするのに利用可能であす。</p>
|
||||
<p>実行するには、アクションがトリガーに関連づけられている必要があります。
|
||||
トリガーに関連づけられると、各々のアクションは順番が与えられ、どの順序でアクションが実行されるかが指定されます。</p>',
|
||||
'UI:NotificationsMenu:Triggers' => 'トリガー',
|
||||
'UI:NotificationsMenu:AvailableTriggers' => '利用可能トリガー',
|
||||
'UI:NotificationsMenu:OnCreate' => 'オブジェクトが作成された時',
|
||||
'UI:NotificationsMenu:OnStateEnter' => 'オブジェクトが指定状態に入った時',
|
||||
'UI:NotificationsMenu:OnStateLeave' => 'オブジェクトが指定状態から出た時',
|
||||
'UI:NotificationsMenu:Actions' => 'アクション',
|
||||
'UI:NotificationsMenu:AvailableActions' => '利用可能アクション',
|
||||
|
||||
'Menu:AuditCategories' => '監査カテゴリ',
|
||||
'Menu:AuditCategories+' => '監査カテゴリ',
|
||||
'Menu:Notifications:Title' => '監査カテゴリ',
|
||||
|
||||
'Menu:RunQueriesMenu' => 'クエリ実行',
|
||||
'Menu:RunQueriesMenu+' => '任意のクエリを実行',
|
||||
|
||||
'Menu:QueryMenu' => 'クエリのフレーズブック',
|
||||
'Menu:QueryMenu+' => 'クエリのフレーズブック',
|
||||
|
||||
'Menu:DataAdministration' => 'データ管理',
|
||||
'Menu:DataAdministration+' => 'データ管理',
|
||||
|
||||
'Menu:UniversalSearchMenu' => '全検索',
|
||||
'Menu:UniversalSearchMenu+' => '何か...検索',
|
||||
|
||||
'Menu:ApplicationLogMenu' => 'アプリケーションのログ',
|
||||
'Menu:ApplicationLogMenu+' => 'アプリケーションのログ',
|
||||
'Menu:ApplicationLogMenu:Title' => 'アプリケーションのログ',
|
||||
|
||||
'Menu:UserManagementMenu' => 'ユーザ管理',
|
||||
'Menu:UserManagementMenu+' => 'ユーザ管理',
|
||||
|
||||
'Menu:ProfilesMenu' => 'プロフィール',
|
||||
'Menu:ProfilesMenu+' => 'プロフィール',
|
||||
'Menu:ProfilesMenu:Title' => 'プロフィール',
|
||||
|
||||
'Menu:UserAccountsMenu' => 'ユーザアカウント',
|
||||
'Menu:UserAccountsMenu+' => 'ユーザアカウント',
|
||||
'Menu:UserAccountsMenu:Title' => 'ユーザアカウント',
|
||||
|
||||
'UI:iTopVersion:Short' => 'iTopバージョン%1$s',
|
||||
'UI:iTopVersion:Long' => 'iTopバージョン%1$s-%2$s ビルド%3$s',
|
||||
'UI:PropertiesTab' => 'プロパティ',
|
||||
|
||||
'UI:OpenDocumentInNewWindow_' => '新規ウィンドウでこ文章を開く: %1$s',
|
||||
'UI:DownloadDocument_' => 'この文書をダウンロードする: %1$s',
|
||||
'UI:Document:NoPreview' => 'このタイプの文書はプレビューできません。',
|
||||
|
||||
'UI:DeadlineMissedBy_duration' => '%1$s によって消去されました。',
|
||||
'UI:Deadline_LessThan1Min' => ' < 1分',
|
||||
'UI:Deadline_Minutes' => '%1$d 分',
|
||||
'UI:Deadline_Hours_Minutes' => '%1$d時間%2$d分',
|
||||
'UI:Deadline_Days_Hours_Minutes' => '%1$d日%2$d時間%3$d分',
|
||||
'UI:Help' => 'ヘルプ',
|
||||
'UI:PasswordConfirm' => '(確認)',
|
||||
'UI:BeforeAdding_Class_ObjectsSaveThisObject' => '%1$sオブジェクトをさらに追加する前に、このオブジェクトを保存してください。',
|
||||
'UI:DisplayThisMessageAtStartup' => '起動時にこのメッセージを表示する',
|
||||
'UI:RelationshipGraph' => 'グラフィカル表示',
|
||||
'UI:RelationshipList' => 'リスト',
|
||||
'UI:OperationCancelled' => '操作はキャンセルされました',
|
||||
'UI:ElementsDisplayed' => 'フィルターリング',
|
||||
|
||||
'Portal:Title' => 'iTopユーザポータル',
|
||||
'Portal:Refresh' => 'リフレッシュ',
|
||||
'Portal:Back' => '戻る',
|
||||
'Portal:WelcomeUserOrg' => 'ようこそ %1$s, %2$sより',
|
||||
'Portal:ShowOngoing' => 'オープン中の要求を表示',
|
||||
'Portal:ShowClosed' => 'クローズした要求を表示',
|
||||
'Portal:CreateNewRequest' => '新規要求を作成',
|
||||
'Portal:ChangeMyPassword' => 'パスワードを変更',
|
||||
'Portal:Disconnect' => '切断する',
|
||||
'Portal:OpenRequests' => '担当のオープン中の要求',
|
||||
'Portal:ClosedRequests' => '担当のクローズした要求',
|
||||
'Portal:ResolvedRequests' => '担当の解決済み要求',
|
||||
'Portal:SelectService' => 'カタログからサービスを選択してください:',
|
||||
'Portal:PleaseSelectOneService' => 'サービスを1つ選んでください',
|
||||
'Portal:SelectSubcategoryFrom_Service' => 'サービス%1$sのサブカテゴリを選んでください:',
|
||||
'Portal:PleaseSelectAServiceSubCategory' => 'サブカテゴリを1つ選んでください',
|
||||
'Portal:DescriptionOfTheRequest' => 'あなたの要求の説明を記入してください:',
|
||||
'Portal:TitleRequestDetailsFor_Request' => '要求%1$sの詳細:',
|
||||
'Portal:NoOpenRequest' => 'このカテゴリに要求はありません',
|
||||
'Portal:NoClosedRequest' => 'このカテゴリにはクローズした要求はありません。',
|
||||
'Portal:Button:ReopenTicket' => 'このチケットを再オープン',
|
||||
'Portal:Button:CloseTicket' => 'このチケットをクローズ。',
|
||||
'Portal:Button:UpdateRequest' => '要求を更新',
|
||||
'Portal:EnterYourCommentsOnTicket' => 'このチケットの解決について、コメントを入力してください。',
|
||||
'Portal:ErrorNoContactForThisUser' => 'エラー:現在のユーザは連絡先/人物に関連づけられていません。管理者に問い合わせてください。',
|
||||
'Portal:Attachments' => '添付',
|
||||
'Portal:AddAttachment' => ' 添付を追加 ',
|
||||
'Portal:RemoveAttachment' => ' 添付を削除 ',
|
||||
'Portal:Attachment_No_To_Ticket_Name' => '$2$s ($3$s)への添付 #%1$d',
|
||||
'Enum:Undefined' => '未定義',
|
||||
'UI:DurationForm_Days_Hours_Minutes_Seconds' => '%1$s 日 %2$s 時 %3$s 分 %4$s 秒',
|
||||
'UI:ModifyAllPageTitle' => '全てを修正',
|
||||
'UI:Modify_N_ObjectsOf_Class' => 'クラス%2$Sの%1$dオブジェクトを修正',
|
||||
'UI:Modify_M_ObjectsOf_Class_OutOf_N' => 'クラス%2$sの%3$d中%1$dを修正',
|
||||
'UI:Menu:ModifyAll' => '修正...',
|
||||
'UI:Button:ModifyAll' => '全て修正',
|
||||
'UI:Button:PreviewModifications' => '修正をプレビュー >>',
|
||||
'UI:ModifiedObject' => '修正されたオブジェクト',
|
||||
'UI:BulkModifyStatus' => '操作',
|
||||
'UI:BulkModifyStatus+' => '操作の状態',
|
||||
'UI:BulkModifyErrors' => 'エラー (もしあれば)',
|
||||
'UI:BulkModifyErrors+' => '修正を出来ないようにしているエラー',
|
||||
'UI:BulkModifyStatusOk' => 'Ok',
|
||||
'UI:BulkModifyStatusError' => 'エラー',
|
||||
'UI:BulkModifyStatusModified' => '修正',
|
||||
'UI:BulkModifyStatusSkipped' => 'スキップ',
|
||||
'UI:BulkModify_Count_DistinctValues' => '%1$d 個の個別の値:',
|
||||
'UI:BulkModify:Value_Exists_N_Times' => '%1$s, %2$d 回存在',
|
||||
'UI:BulkModify:N_MoreValues' => '%1$d 個以上の値...',
|
||||
'UI:AttemptingToSetAReadOnlyAttribute_Name' => '読み込み専用フィールド %1$にセットしょうとしています。',
|
||||
'UI:FailedToApplyStimuli' => 'アクションは失敗しました。',
|
||||
'UI:StimulusModify_N_ObjectsOf_Class' => '%1$s: クラス%3$sの%2$dオブジェクトを修正',
|
||||
'UI:CaseLogTypeYourTextHere' => 'テキストを入力ください:',
|
||||
'UI:CaseLog:DateFormat' => 'Y-m-d H:i:s',
|
||||
'UI:CaseLog:Header_Date_UserName' => '%1$s - %2$s:',
|
||||
'UI:CaseLog:InitialValue' => '初期値:',
|
||||
'UI:AttemptingToSetASlaveAttribute_Name' => 'フィールド %1$s は、データの同期によってマスターリングされているため書き込み可能ではありません。値は設定されません。',
|
||||
'UI:ActionNotAllowed' => 'あなたは、これらのオブジェクトへのこのアクションを許可されていません。',
|
||||
'UI:BulkAction:NoObjectSelected' => 'この操作を実行するには、少なくとも1つのオブジェクトを選択してください。',
|
||||
'UI:AttemptingToChangeASlaveAttribute_Name' => 'フィールド %1$s はデータの同期によってマスターリングされているため、書き込み可能ではありません。値は変更されません。',
|
||||
'UI:Pagination:HeaderSelection' => '全: %1$s オブジェクト (%2$s オブジェクト選択)。',
|
||||
'UI:Pagination:HeaderNoSelection' => '全: %1$s オブジェクト。',
|
||||
'UI:Pagination:PageSize' => '%1$s オブジェクト/ページ',
|
||||
'UI:Pagination:PagesLabel' => 'ページ:',
|
||||
'UI:Pagination:All' => '全',
|
||||
'UI:HierarchyOf_Class' => '%1$s の階層',
|
||||
'UI:Preferences' => 'プリファレンス...',
|
||||
'UI:FavoriteOrganizations' => '私の好きな組織',
|
||||
'UI:FavoriteOrganizations+' => '迅速なアクセスのためのドロップダウンメニューに表示したい組織は、以下のリストで確認してください。'.
|
||||
'セキュリティ設定ではないことに注意してください。全ての組織のオブジェクトは、表示可能です。ドロップダウンリストで「すべての組織(All Organizations)」を選択することでアクセスすることができます。',
|
||||
'UI:NavigateAwayConfirmationMessage' => '全ての変更を破棄します。',
|
||||
'UI:Create_Class_InState' => '%1$sを作成、ステート:',
|
||||
));
|
||||
?>
|
||||
@@ -406,6 +406,7 @@ Dict::Add('RU RU', 'Russian', 'Русский', array(
|
||||
'UI:History:Changes+' => 'Изменения, внесенные в объект',
|
||||
'UI:Loading' => 'Загрузка...',
|
||||
'UI:Menu:Actions' => 'Действия',
|
||||
'UI:Menu:OtherActions' => 'Другие Действия',
|
||||
'UI:Menu:New' => 'Новый...',
|
||||
'UI:Menu:Add' => 'Добавить...',
|
||||
'UI:Menu:Manage' => 'Управление...',
|
||||
@@ -847,10 +848,14 @@ Dict::Add('RU RU', 'Russian', 'Русский', array(
|
||||
'Portal:Title' => 'Пользовательский iTop портал',
|
||||
'Portal:Refresh' => 'Обновить',
|
||||
'Portal:Back' => 'Назад',
|
||||
'Portal:WelcomeUserOrg' => 'Welcome %1$s, from %2$s',
|
||||
'Portal:ShowOngoing' => 'Show open requests',
|
||||
'Portal:ShowClosed' => 'Show closed requests',
|
||||
'Portal:CreateNewRequest' => 'Создать новый запрос',
|
||||
'Portal:ChangeMyPassword' => 'Изменить мой пароль',
|
||||
'Portal:Disconnect' => 'Отключить',
|
||||
'Portal:OpenRequests' => 'Мои открытые запросы',
|
||||
'Portal:ClosedRequests' => 'My closed requests',
|
||||
'Portal:ResolvedRequests' => 'Мои решённые запросы',
|
||||
'Portal:SelectService' => 'Выбери сервис из каталога:',
|
||||
'Portal:PleaseSelectOneService' => 'Необходимо выбрать хотя-бы один сервис',
|
||||
@@ -859,7 +864,10 @@ Dict::Add('RU RU', 'Russian', 'Русский', array(
|
||||
'Portal:DescriptionOfTheRequest' => 'Введи описание запроса:',
|
||||
'Portal:TitleRequestDetailsFor_Request' => 'Подробности запроса %1$s:',
|
||||
'Portal:NoOpenRequest' => 'Нет запросов в этой категории.',
|
||||
'Portal:NoClosedRequest' => 'No request in this category',
|
||||
'Portal:Button:ReopenTicket' => 'Reopen this ticket',
|
||||
'Portal:Button:CloseTicket' => 'Закрыть этот "тикет"',
|
||||
'Portal:Button:UpdateRequest' => 'Update the request',
|
||||
'Portal:EnterYourCommentsOnTicket' => 'Введите ваши каментарии по решению этого "тикета":',
|
||||
'Portal:ErrorNoContactForThisUser' => 'Ошибка: текющий пользователь не ассоциирован с Контактом/Человеком. Пожалуйста свяжитесь с вашим администратором.',
|
||||
|
||||
|
||||
@@ -405,6 +405,7 @@ Dict::Add('TR TR', 'Turkish', 'Türkçe', array(
|
||||
'UI:History:Changes+' => 'Nesneye yapılan değişiklikler',
|
||||
'UI:Loading' => 'Yükleniyor...',
|
||||
'UI:Menu:Actions' => 'İşlemler',
|
||||
'UI:Menu:OtherActions' => 'Diğer İşlemler',
|
||||
'UI:Menu:New' => 'Yeni...',
|
||||
'UI:Menu:Add' => 'Ekle...',
|
||||
'UI:Menu:Manage' => 'Yönet...',
|
||||
@@ -846,10 +847,14 @@ Tetikleme gerçekleştiriğinde işlemler tanımlanan sıra numarası ile gerçe
|
||||
'Portal:Title' => 'iTop Kullanıcı Portalı',
|
||||
'Portal:Refresh' => 'Yenile',
|
||||
'Portal:Back' => 'Geri',
|
||||
'Portal:WelcomeUserOrg' => 'Welcome %1$s, from %2$s',
|
||||
'Portal:ShowOngoing' => 'Show open requests',
|
||||
'Portal:ShowClosed' => 'Show closed requests',
|
||||
'Portal:CreateNewRequest' => 'Yeni istek yarat',
|
||||
'Portal:ChangeMyPassword' => 'Şifre değiştir',
|
||||
'Portal:Disconnect' => 'Çıkış',
|
||||
'Portal:OpenRequests' => 'Açık isteklerim',
|
||||
'Portal:ClosedRequests' => 'My closed requests',
|
||||
'Portal:ResolvedRequests' => 'Çözdüğüm istekler',
|
||||
'Portal:SelectService' => 'Kataloğdan servis seçiniz:',
|
||||
'Portal:PleaseSelectOneService' => 'Sevis seçiniz',
|
||||
@@ -858,7 +863,10 @@ Tetikleme gerçekleştiriğinde işlemler tanımlanan sıra numarası ile gerçe
|
||||
'Portal:DescriptionOfTheRequest' => 'İstek tanımlaması:',
|
||||
'Portal:TitleRequestDetailsFor_Request' => 'İsteğin detayı %1$s:',
|
||||
'Portal:NoOpenRequest' => 'Bu kategoride istek yok.',
|
||||
'Portal:NoClosedRequest' => 'Bu kategoride istek yok.',
|
||||
'Portal:Button:ReopenTicket' => 'Reopen this ticket',
|
||||
'Portal:Button:CloseTicket' => 'Çağrıyı kapat',
|
||||
'Portal:Button:UpdateRequest' => 'Update the request',
|
||||
'Portal:EnterYourCommentsOnTicket' => 'İsteğin çözümüne yönelik açıklamalar:',
|
||||
'Portal:ErrorNoContactForThisUser' => 'Hata: mevcut kullanıcının irtibat bilgisi yok. Sistem yöneticisi ile irtibata geçiniz.',
|
||||
|
||||
|
||||
@@ -404,6 +404,7 @@ Dict::Add('ZH CN', 'Chinese', '简体中文', array(
|
||||
'UI:History:Changes+' => '对该对象所做的变更',
|
||||
'UI:Loading' => '载入...',
|
||||
'UI:Menu:Actions' => '动作',
|
||||
'UI:Menu:OtherActions' => '其他操作',
|
||||
'UI:Menu:New' => '新建...',
|
||||
'UI:Menu:Add' => '添加...',
|
||||
'UI:Menu:Manage' => '管理...',
|
||||
@@ -845,10 +846,14 @@ Dict::Add('ZH CN', 'Chinese', '简体中文', array(
|
||||
'Portal:Title' => 'iTop 用户门户',
|
||||
'Portal:Refresh' => '刷新',
|
||||
'Portal:Back' => '返回',
|
||||
'Portal:WelcomeUserOrg' => 'Welcome %1$s, from %2$s',
|
||||
'Portal:ShowOngoing' => 'Show open requests',
|
||||
'Portal:ShowClosed' => 'Show closed requests',
|
||||
'Portal:CreateNewRequest' => '创建一个新的请求',
|
||||
'Portal:ChangeMyPassword' => '改变我的密码',
|
||||
'Portal:Disconnect' => '断开',
|
||||
'Portal:OpenRequests' => '我的待解决的请求',
|
||||
'Portal:ClosedRequests' => 'My closed requests',
|
||||
'Portal:ResolvedRequests' => '我的已解决的请求',
|
||||
'Portal:SelectService' => '从类目中选择一个服务:',
|
||||
'Portal:PleaseSelectOneService' => '请选择一个服务',
|
||||
@@ -857,7 +862,9 @@ Dict::Add('ZH CN', 'Chinese', '简体中文', array(
|
||||
'Portal:DescriptionOfTheRequest' => '输入您的请求描述:',
|
||||
'Portal:TitleRequestDetailsFor_Request' => '请求明细内容 %1$s:',
|
||||
'Portal:NoOpenRequest' => '该类目中没有请求.',
|
||||
'Portal:NoClosedRequest' => 'No request in this category',
|
||||
'Portal:Button:CloseTicket' => '关闭这个单据',
|
||||
'Portal:Button:UpdateRequest' => 'Update the request',
|
||||
'Portal:EnterYourCommentsOnTicket' => '输入您对于该单据解决情况的评述:',
|
||||
'Portal:ErrorNoContactForThisUser' => '错误: 当前用户没有和一个联系人或人员关联. 请联系您的系统管理员.',
|
||||
|
||||
|
||||
BIN
images/actions_bkg.png
Normal file
|
After Width: | Height: | Size: 271 B |
|
Before Width: | Height: | Size: 283 B After Width: | Height: | Size: 314 B |
BIN
images/first.png
Normal file
|
After Width: | Height: | Size: 720 B |
BIN
images/last.png
Normal file
|
After Width: | Height: | Size: 737 B |
BIN
images/mini_tree.gif
Normal file
|
After Width: | Height: | Size: 140 B |
BIN
images/next.png
Normal file
|
After Width: | Height: | Size: 736 B |
BIN
images/play.png
Normal file
|
After Width: | Height: | Size: 1.3 KiB |
BIN
images/preferences.png
Normal file
|
After Width: | Height: | Size: 5.4 KiB |
BIN
images/prev.png
Normal file
|
After Width: | Height: | Size: 745 B |
@@ -13,12 +13,13 @@
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
function ExtKeyWidget(id, sClass, sAttCode, sSuffix, bSelectMode, oWizHelper)
|
||||
function ExtKeyWidget(id, sTargetClass, sFilter, sTitle, bSelectMode, oWizHelper, sAttCode)
|
||||
{
|
||||
this.id = id;
|
||||
this.sClass = sClass;
|
||||
this.sTargetClass = sTargetClass;
|
||||
this.sFilter = sFilter;
|
||||
this.sTitle = sTitle;
|
||||
this.sAttCode = sAttCode;
|
||||
this.sSuffix = sSuffix;
|
||||
this.emptyHtml = ''; // content to be displayed when the search results are empty (when opening the dialog)
|
||||
this.emptyOnClose = true; // Workaround for the JQuery dialog being very slow when opening and closing if the content contains many INPUT tags
|
||||
this.oWizardHelper = oWizHelper;
|
||||
@@ -38,7 +39,7 @@ function ExtKeyWidget(id, sClass, sAttCode, sSuffix, bSelectMode, oWizHelper)
|
||||
{
|
||||
if (me.ajax_request)
|
||||
{
|
||||
me.ajax_request.Abort();
|
||||
me.ajax_request.abort();
|
||||
me.ajax_request = null;
|
||||
}
|
||||
}
|
||||
@@ -60,18 +61,29 @@ function ExtKeyWidget(id, sClass, sAttCode, sSuffix, bSelectMode, oWizHelper)
|
||||
}
|
||||
var theMap = { sAttCode: me.sAttCode,
|
||||
iInputId: me.id,
|
||||
sSuffix: me.sSuffix,
|
||||
'class': me.sClass,
|
||||
sValue: value,
|
||||
sTitle: me.sTitle,
|
||||
sAttCode: me.sAttCode,
|
||||
sTargetClass: me.sTargetClass,
|
||||
operation: 'objectSearchForm'
|
||||
}
|
||||
|
||||
if (me.oWizardHelper == null)
|
||||
{
|
||||
theMap['json'] = '';
|
||||
}
|
||||
else
|
||||
{
|
||||
// Not inside a "search form", updating a real object
|
||||
me.oWizardHelper.UpdateWizard();
|
||||
theMap['json'] = me.oWizardHelper.ToJSON();
|
||||
}
|
||||
|
||||
// Make sure that we cancel any pending request before issuing another
|
||||
// since responses may arrive in arbitrary order
|
||||
me.StopPendingRequest();
|
||||
|
||||
// Run the query and get the result back directly in HTML
|
||||
me.ajax_request = $.post( '../pages/ajax.render.php', theMap,
|
||||
me.ajax_request = $.post( AddAppContext(GetAbsoluteUrlAppRoot()+'pages/ajax.render.php'), theMap,
|
||||
function(data)
|
||||
{
|
||||
$('#ac_dlg_'+me.id).html(data);
|
||||
@@ -79,6 +91,7 @@ function ExtKeyWidget(id, sClass, sAttCode, sSuffix, bSelectMode, oWizHelper)
|
||||
me.UpdateSizes();
|
||||
me.UpdateButtons();
|
||||
me.ajax_request = null;
|
||||
me.DoSearchObjects();
|
||||
},
|
||||
'html'
|
||||
);
|
||||
@@ -111,7 +124,7 @@ function ExtKeyWidget(id, sClass, sAttCode, sSuffix, bSelectMode, oWizHelper)
|
||||
this.UpdateButtons = function()
|
||||
{
|
||||
var okBtn = $('#btn_ok_'+me.id);
|
||||
if ($('#fr_'+me.id+' input[name=selectObject]:checked').length > 0)
|
||||
if ($('#count_'+me.id).val() > 0)
|
||||
{
|
||||
okBtn.attr('disabled', '');
|
||||
}
|
||||
@@ -123,9 +136,9 @@ function ExtKeyWidget(id, sClass, sAttCode, sSuffix, bSelectMode, oWizHelper)
|
||||
|
||||
this.DoSearchObjects = function(id)
|
||||
{
|
||||
var theMap = { sAttCode: me.sAttCode,
|
||||
var theMap = { sTargetClass: me.sTargetClass,
|
||||
iInputId: me.id,
|
||||
sSuffix: me.sSuffix
|
||||
sFilter: me.sFilter
|
||||
}
|
||||
|
||||
// Gather the parameters from the search form
|
||||
@@ -151,8 +164,8 @@ function ExtKeyWidget(id, sClass, sAttCode, sSuffix, bSelectMode, oWizHelper)
|
||||
}
|
||||
|
||||
theMap['sRemoteClass'] = theMap['class']; // swap 'class' (defined in the form) and 'remoteClass'
|
||||
theMap['class'] = me.sClass;
|
||||
theMap.operation = 'searchObjectsToSelect'; // Override what is defined in the form itself
|
||||
theMap.sAttCode = me.sAttCode,
|
||||
|
||||
sSearchAreaId = '#dr_'+me.id;
|
||||
//$(sSearchAreaId).html('<div style="text-align:center;width:100%;height:24px;vertical-align:middle;"><img src="../images/indicator.gif" /></div>');
|
||||
@@ -164,15 +177,17 @@ function ExtKeyWidget(id, sClass, sAttCode, sSuffix, bSelectMode, oWizHelper)
|
||||
me.StopPendingRequest();
|
||||
|
||||
// Run the query and display the results
|
||||
me.ajax_request = $.post( '../pages/ajax.render.php', theMap,
|
||||
me.ajax_request = $.post( AddAppContext(GetAbsoluteUrlAppRoot()+'pages/ajax.render.php'), theMap,
|
||||
function(data)
|
||||
{
|
||||
$(sSearchAreaId).html(data);
|
||||
$(sSearchAreaId+' .listResults').tableHover();
|
||||
$(sSearchAreaId+' .listResults').tablesorter( { headers: {0: {sorter: false}}, widgets: ['myZebra', 'truncatedList']} ); // sortable and zebra tables
|
||||
$('#fr_'+me.id+' input:radio').click(function() { me.UpdateButtons(); });
|
||||
me.UpdateButtons();
|
||||
me.ajax_request = null;
|
||||
$('#count_'+me.id).change(function(){
|
||||
me.UpdateButtons();
|
||||
});
|
||||
},
|
||||
'html'
|
||||
);
|
||||
@@ -182,16 +197,24 @@ function ExtKeyWidget(id, sClass, sAttCode, sSuffix, bSelectMode, oWizHelper)
|
||||
|
||||
this.DoOk = function()
|
||||
{
|
||||
var iObjectId = $('#fr_'+me.id+' input[name=selectObject]:checked').val();
|
||||
var s = $('#'+me.id+'_results').find(':input[name^=storedSelection]');
|
||||
var iObjectId = 0;
|
||||
if (s.length > 0)
|
||||
{
|
||||
iObjectId = s.val();
|
||||
}
|
||||
else
|
||||
{
|
||||
iObjectId = $('#fr_'+me.id+' input[name=selectObject]:checked').val();
|
||||
}
|
||||
$('#ac_dlg_'+this.id).dialog('close');
|
||||
$('#label_'+this.id).addClass('ac_dlg_loading');
|
||||
|
||||
// Query the server again to get the display name of the selected object
|
||||
var theMap = { sAttCode: me.sAttCode,
|
||||
var theMap = { sTargetClass: me.sTargetClass,
|
||||
iInputId: me.id,
|
||||
iObjectId: iObjectId,
|
||||
sSuffix: me.sSuffix,
|
||||
'class': me.sClass,
|
||||
sAttCode: me.sAttCode,
|
||||
operation: 'getObjectName'
|
||||
}
|
||||
|
||||
@@ -200,13 +223,19 @@ function ExtKeyWidget(id, sClass, sAttCode, sSuffix, bSelectMode, oWizHelper)
|
||||
me.StopPendingRequest();
|
||||
|
||||
// Run the query and get the result back directly in JSON
|
||||
me.ajax_request = $.post( '../pages/ajax.render.php', theMap,
|
||||
me.ajax_request = $.post( AddAppContext(GetAbsoluteUrlAppRoot()+'pages/ajax.render.php'), theMap,
|
||||
function(data)
|
||||
{
|
||||
$('#label_'+me.id).val(data.name);
|
||||
$('#label_'+me.id).removeClass('ac_dlg_loading');
|
||||
var prevValue = $('#'+me.id).val();
|
||||
$('#'+me.id).val(iObjectId);
|
||||
$('#'+me.id).trigger('validate');
|
||||
if (prevValue != iObjectId)
|
||||
{
|
||||
$('#'+me.id).trigger('validate');
|
||||
$('#'+me.id).trigger('extkeychange');
|
||||
$('#'+me.id).trigger('change');
|
||||
}
|
||||
$('#label_'+me.id).focus();
|
||||
me.ajax_request = null;
|
||||
},
|
||||
@@ -246,10 +275,9 @@ function ExtKeyWidget(id, sClass, sAttCode, sSuffix, bSelectMode, oWizHelper)
|
||||
$('#label_'+me.id).addClass('ac_dlg_loading');
|
||||
}
|
||||
me.oWizardHelper.UpdateWizard();
|
||||
var theMap = { sAttCode: me.sAttCode,
|
||||
var theMap = { sTargetClass: me.sTargetClass,
|
||||
iInputId: me.id,
|
||||
sSuffix: me.sSuffix,
|
||||
'class': me.sClass,
|
||||
sAttCode: me.sAttCode,
|
||||
'json': me.oWizardHelper.ToJSON(),
|
||||
operation: 'objectCreationForm'
|
||||
}
|
||||
@@ -259,7 +287,7 @@ function ExtKeyWidget(id, sClass, sAttCode, sSuffix, bSelectMode, oWizHelper)
|
||||
me.StopPendingRequest();
|
||||
|
||||
// Run the query and get the result back directly in HTML
|
||||
me.ajax_request = $.post( '../pages/ajax.render.php', theMap,
|
||||
me.ajax_request = $.post( AddAppContext(GetAbsoluteUrlAppRoot()+'pages/ajax.render.php'), theMap,
|
||||
function(data)
|
||||
{
|
||||
$('#ajax_'+me.id).html(data);
|
||||
@@ -309,10 +337,9 @@ function ExtKeyWidget(id, sClass, sAttCode, sSuffix, bSelectMode, oWizHelper)
|
||||
if (CheckFields(sFormId, true))
|
||||
{
|
||||
$('#'+sFormId).block();
|
||||
var theMap = { sAttCode: me.sAttCode,
|
||||
var theMap = { sTargetClass: me.sTargetClass,
|
||||
iInputId: me.id,
|
||||
sSuffix: me.sSuffix,
|
||||
'class': me.sClass,
|
||||
sAttCode: me.sAttCode,
|
||||
'json': me.oWizardHelper.ToJSON()
|
||||
}
|
||||
|
||||
@@ -338,13 +365,13 @@ function ExtKeyWidget(id, sClass, sAttCode, sSuffix, bSelectMode, oWizHelper)
|
||||
me.StopPendingRequest();
|
||||
|
||||
// Run the query and get the result back directly in JSON
|
||||
me.ajax_request = $.post( '../pages/ajax.render.php', theMap,
|
||||
me.ajax_request = $.post( AddAppContext(GetAbsoluteUrlAppRoot()+'pages/ajax.render.php'), theMap,
|
||||
function(data)
|
||||
{
|
||||
if (me.bSelectMode)
|
||||
{
|
||||
// Add the newly created object to the drop-down list and select it
|
||||
$('<option/>', { value : data.id }).text(data.name).appendTo('#'+me.id);
|
||||
$('<option/>', { value : data.id }).html(data.name).appendTo('#'+me.id);
|
||||
$('#'+me.id+' option[value="'+data.id+'"]').attr('selected', 'selected');
|
||||
$('#'+me.id).focus();
|
||||
}
|
||||
@@ -357,6 +384,8 @@ function ExtKeyWidget(id, sClass, sAttCode, sSuffix, bSelectMode, oWizHelper)
|
||||
$('#label_'+me.id).focus();
|
||||
}
|
||||
$('#'+me.id).trigger('validate');
|
||||
$('#'+me.id).trigger('extkeychange');
|
||||
$('#'+me.id).trigger('change');
|
||||
me.ajax_request = null;
|
||||
},
|
||||
'json'
|
||||
@@ -373,6 +402,7 @@ function ExtKeyWidget(id, sClass, sAttCode, sSuffix, bSelectMode, oWizHelper)
|
||||
$('#label_'+me.id).attr('disabled', 'disabled');
|
||||
$('#label_'+me.id).css({'background': 'transparent'});
|
||||
$('#mini_add_'+me.id).hide();
|
||||
$('#mini_tree_'+me.id).hide();
|
||||
$('#mini_search_'+me.id).hide();
|
||||
}
|
||||
else
|
||||
@@ -380,7 +410,127 @@ function ExtKeyWidget(id, sClass, sAttCode, sSuffix, bSelectMode, oWizHelper)
|
||||
$('#label_'+me.id).attr('disabled', '');
|
||||
$('#label_'+me.id).css({'background': '#fff url(../images/ac-background.gif) no-repeat right'});
|
||||
$('#mini_add_'+me.id).show();
|
||||
$('#mini_tree_'+me.id).show();
|
||||
$('#mini_search_'+me.id).show();
|
||||
}
|
||||
}
|
||||
|
||||
this.HKDisplay = function()
|
||||
{
|
||||
var theMap = { sTargetClass: me.sTargetClass,
|
||||
sInputId: me.id,
|
||||
sFilter: me.sFilter,
|
||||
sAttCode: me.sAttCode,
|
||||
value: $('#'+me.id).val()
|
||||
};
|
||||
|
||||
if (me.bSelectMode)
|
||||
{
|
||||
me.v_html = $('#v_'+me.id).html();
|
||||
$('#v_'+me.id).html('<img src="../images/indicator.gif" />');
|
||||
}
|
||||
else
|
||||
{
|
||||
$('#label_'+me.id).addClass('ac_dlg_loading');
|
||||
}
|
||||
if (me.oWizardHelper == null)
|
||||
{
|
||||
theMap['json'] = '';
|
||||
}
|
||||
else
|
||||
{
|
||||
// Not inside a "search form", updating a real object
|
||||
me.oWizardHelper.UpdateWizard();
|
||||
theMap['json'] = me.oWizardHelper.ToJSON();
|
||||
}
|
||||
|
||||
theMap['sRemoteClass'] = me.sTargetClass;
|
||||
theMap.operation = 'displayHierarchy';
|
||||
|
||||
// Make sure that we cancel any pending request before issuing another
|
||||
// since responses may arrive in arbitrary order
|
||||
me.StopPendingRequest();
|
||||
|
||||
// Run the query and display the results
|
||||
me.ajax_request = $.post( AddAppContext(GetAbsoluteUrlAppRoot()+'pages/ajax.render.php'), theMap,
|
||||
function(data)
|
||||
{
|
||||
$('#ac_tree_'+me.id).html(data);
|
||||
var maxHeight = $(window).height()-110;
|
||||
$('#tree_'+me.id).css({maxHeight: maxHeight});
|
||||
},
|
||||
'html'
|
||||
);
|
||||
}
|
||||
|
||||
this.OnHKResize = function(event, ui)
|
||||
{
|
||||
var dh = ui.size.height - ui.originalSize.height;
|
||||
if (dh != 0)
|
||||
{
|
||||
var dlg_content = $('#dlg_tree_'+me.id+' .wizContainer');
|
||||
var h = dlg_content.height();
|
||||
dlg_content.height(h + dh);
|
||||
var tree = $('#tree_'+me.id);
|
||||
var h = tree.height();
|
||||
tree.height(h + dh - 1);
|
||||
}
|
||||
}
|
||||
|
||||
this.OnHKClose = function()
|
||||
{
|
||||
if (me.bSelectMode)
|
||||
{
|
||||
$('#v_'+me.id).html(me.v_html);
|
||||
}
|
||||
else
|
||||
{
|
||||
$('#label_'+me.id).removeClass('ac_dlg_loading');
|
||||
}
|
||||
$('#label_'+me.id).focus();
|
||||
$('#dlg_tree_'+me.id).dialog("destroy");
|
||||
$('#dlg_tree_'+me.id).remove();
|
||||
}
|
||||
|
||||
this.DoHKOk = function()
|
||||
{
|
||||
iObjectId = $('#tree_'+me.id+' input[name=selectObject]:checked').val();
|
||||
|
||||
$('#dlg_tree_'+me.id).dialog('close');
|
||||
|
||||
// Query the server again to get the display name of the selected object
|
||||
var theMap = { sTargetClass: me.sTargetClass,
|
||||
iInputId: me.id,
|
||||
iObjectId: iObjectId,
|
||||
sAttCode: me.sAttCode,
|
||||
operation: 'getObjectName'
|
||||
}
|
||||
|
||||
// Make sure that we cancel any pending request before issuing another
|
||||
// since responses may arrive in arbitrary order
|
||||
me.StopPendingRequest();
|
||||
|
||||
// Run the query and get the result back directly in JSON
|
||||
me.ajax_request = $.post( AddAppContext(GetAbsoluteUrlAppRoot()+'pages/ajax.render.php'), theMap,
|
||||
function(data)
|
||||
{
|
||||
$('#label_'+me.id).val(data.name);
|
||||
$('#label_'+me.id).removeClass('ac_dlg_loading');
|
||||
var prevValue = $('#'+me.id).val();
|
||||
$('#'+me.id).val(iObjectId);
|
||||
if (prevValue != iObjectId)
|
||||
{
|
||||
$('#'+me.id).trigger('validate');
|
||||
$('#'+me.id).trigger('extkeychange');
|
||||
$('#'+me.id).trigger('change');
|
||||
}
|
||||
$('#label_'+me.id).focus();
|
||||
me.ajax_request = null;
|
||||
},
|
||||
'json'
|
||||
);
|
||||
|
||||
return false; // Do NOT submit the form in case we are called by OnSubmit...
|
||||
}
|
||||
|
||||
}
|
||||
@@ -10,6 +10,8 @@ var oObj = {};
|
||||
// of Id 'att_2' in the form
|
||||
var aFieldsMap = new Array;
|
||||
|
||||
window.bInSubmit = false; // For handling form cancellation via OnBeforeUnload events
|
||||
|
||||
// Update the whole object from the form and also update its
|
||||
// JSON (serialized) representation in the (hidden) field
|
||||
function UpdateObjectFromForm(aFieldsMap, oObj)
|
||||
@@ -88,34 +90,28 @@ function ActivateStep(iTargetStep)
|
||||
//$('#wizStep'+(iTargetStep)).block({ message: null });
|
||||
}
|
||||
|
||||
function OnUnload(sTransactionId)
|
||||
{
|
||||
if (!window.bInSubmit)
|
||||
{
|
||||
// If it's not a submit, then it's a "cancel" (Pressing the Cancel button, closing the window, using the back button...)
|
||||
$.post(GetAbsoluteUrlAppRoot()+'pages/ajax.render.php', {operation: 'on_form_cancel', transaction_id: sTransactionId }, function()
|
||||
{
|
||||
// Do nothing for now...
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
//function AjaxGetValuesDef(oObj, sClass, sAttCode, iFieldId)
|
||||
//{
|
||||
// var oJSON = document.getElementById(sJsonFieldId);
|
||||
// $.get('ajax.render.php?class=' + sClass + '&json_obj=' + oJSON.value + '&att_code=' + sAttCode,
|
||||
// { operation: "allowed_values" },
|
||||
// function(data){
|
||||
// //$('#field_'+iFieldId).html(data);
|
||||
// }
|
||||
// );
|
||||
//}
|
||||
//
|
||||
//function AjaxGetDefaultValue(oObj, sClass, sAttCode, iFieldId)
|
||||
//{
|
||||
// // Asynchronously call the server to provide a default value if the field is
|
||||
// // empty
|
||||
// if (oObj['m_aCurrValues'][sAttCode] == '')
|
||||
// {
|
||||
// var oJSON = document.getElementById(sJsonFieldId);
|
||||
// $.get('../pages/ajax.render.php?class=' + sClass + '&json_obj=' + oJSON.value + '&att_code=' + sAttCode,
|
||||
// { operation: "default_value" },
|
||||
// function(json_data){
|
||||
// var oObj = ReloadObjectFromServer(json_data);
|
||||
// UpdateFieldFromObject(iFieldId, aFieldsMap, oObj)
|
||||
// }
|
||||
// );
|
||||
// }
|
||||
//}
|
||||
function OnSubmit(sFormId)
|
||||
{
|
||||
window.bInSubmit=true; // This is a submit, make sure that when the page gets unloaded we don't cancel the action
|
||||
var bResult = CheckFields(sFormId, true);
|
||||
if (!bResult)
|
||||
{
|
||||
window.bInSubmit = false; // Submit is/will be canceled
|
||||
}
|
||||
return bResult;
|
||||
}
|
||||
|
||||
// Store the result of the form validation... there may be several forms per page, beware
|
||||
var oFormErrors = { err_form0: 0 };
|
||||
@@ -299,6 +295,35 @@ function ValidatePasswordField(id, sFormId)
|
||||
return true;
|
||||
}
|
||||
|
||||
//Special validation function for case log fields, taking into account the history
|
||||
// to determine if the field is empty or not
|
||||
function ValidateCaseLogField(sFieldId, bMandatory, sFormId)
|
||||
{
|
||||
bValid = true;
|
||||
|
||||
if ($('#'+sFieldId).attr('disabled'))
|
||||
{
|
||||
bValid = true; // disabled fields are not checked
|
||||
}
|
||||
else if (!bMandatory)
|
||||
{
|
||||
bValid = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (bMandatory)
|
||||
{
|
||||
var count = $('#'+sFieldId+'_count').val();
|
||||
if ( (count == 0) && ($('#'+sFieldId).val() == '') )
|
||||
{
|
||||
// No previous entry and no content typed
|
||||
bValid = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
ReportFieldValidationStatus(sFieldId, sFormId, bValid);
|
||||
return bValid;
|
||||
}
|
||||
// Manage a 'duration' field
|
||||
function UpdateDuration(iId)
|
||||
{
|
||||
@@ -319,8 +344,12 @@ function OnAutoComplete(id, event, data, formatted)
|
||||
if (data)
|
||||
{
|
||||
// A valid match was found: data[0] => label, data[1] => value
|
||||
$('#'+id).val(data[1]);
|
||||
$('#'+id).trigger('change');
|
||||
if (data[1] != $('#'+id).val())
|
||||
{
|
||||
$('#'+id).val(data[1]);
|
||||
$('#'+id).trigger('change');
|
||||
$('#'+id).trigger('extkeychange');
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -388,7 +388,7 @@ $.Autocompleter = function(input, options) {
|
||||
for (var i=0; i < rows.length; i++) {
|
||||
var row = $.trim(rows[i]);
|
||||
if (row) {
|
||||
row = row.split("|");
|
||||
row = row.split("\t");
|
||||
parsed[parsed.length] = {
|
||||
data: row,
|
||||
value: row[0],
|
||||
@@ -668,6 +668,8 @@ $.Autocompleter.Select = function (options, input, select, config) {
|
||||
var formatted = options.formatItem(data[i].data, i+1, max, data[i].value, term);
|
||||
if ( formatted === false )
|
||||
continue;
|
||||
// Escape dangerous characters to prevent XSS vulnerabilities
|
||||
formatted = formatted.replace('&', '&').replace('"', '"').replace('>', '>').replace('<', '<');
|
||||
var li = $("<li/>").html( options.highlight(formatted, term) ).addClass(i%2 == 0 ? "ac_even" : "ac_odd").appendTo(list)[0];
|
||||
$.data(li, "ac_data", data[i]);
|
||||
}
|
||||
|
||||
468
js/jquery.tablesorter.pager.js
Normal file
@@ -0,0 +1,468 @@
|
||||
function sprintf(format, etc) {
|
||||
var arg = arguments;
|
||||
var i = 1;
|
||||
return format.replace(/%((%)|s)/g, function (m) { return m[2] || arg[i++] })
|
||||
}
|
||||
|
||||
|
||||
(function($) {
|
||||
$.extend({
|
||||
tablesorterPager: new function() {
|
||||
|
||||
function updatePageDisplay(c) {
|
||||
var s = $(c.cssPageDisplay,c.container).val((c.page+1) + c.seperator + c.totalPages);
|
||||
}
|
||||
|
||||
function setPageSize(table,size, bReload) {
|
||||
var c = table.config;
|
||||
c.selectedSize = size;
|
||||
if (size == -1)
|
||||
{
|
||||
size = c.totalRows;
|
||||
}
|
||||
c.size = size;
|
||||
c.totalPages = Math.ceil(c.totalRows / c.size);
|
||||
c.pagerPositionSet = false;
|
||||
if (bReload)
|
||||
{
|
||||
moveToPage(table);
|
||||
}
|
||||
fixPosition(table);
|
||||
}
|
||||
|
||||
function fixPosition(table) {
|
||||
var c = table.config;
|
||||
if(!c.pagerPositionSet && c.positionFixed) {
|
||||
var c = table.config, o = $(table);
|
||||
if(o.offset) {
|
||||
c.container.css({
|
||||
top: o.offset().top + o.height() + 'px',
|
||||
position: 'absolute'
|
||||
});
|
||||
}
|
||||
c.pagerPositionSet = true;
|
||||
}
|
||||
}
|
||||
|
||||
function moveToFirstPage(table) {
|
||||
var c = table.config;
|
||||
c.page = 0;
|
||||
moveToPage(table);
|
||||
}
|
||||
|
||||
function moveToLastPage(table) {
|
||||
var c = table.config;
|
||||
c.page = (c.totalPages-1);
|
||||
moveToPage(table);
|
||||
}
|
||||
|
||||
function moveToNextPage(table) {
|
||||
var c = table.config;
|
||||
c.page++;
|
||||
if(c.page >= (c.totalPages-1)) {
|
||||
c.page = (c.totalPages-1);
|
||||
}
|
||||
moveToPage(table);
|
||||
}
|
||||
|
||||
function moveToPrevPage(table) {
|
||||
var c = table.config;
|
||||
c.page--;
|
||||
if(c.page <= 0) {
|
||||
c.page = 0;
|
||||
}
|
||||
moveToPage(table);
|
||||
}
|
||||
|
||||
|
||||
function moveToPage(table) {
|
||||
var c = table.config;
|
||||
if(c.page < 0 || c.page > (c.totalPages-1)) {
|
||||
c.page = 0;
|
||||
}
|
||||
|
||||
renderTable(table,c.rowsCopy);
|
||||
}
|
||||
|
||||
function checkAll(table, pager, value)
|
||||
{
|
||||
// Mark all the displayed items as check or unchecked depending on the value
|
||||
$(table).find(':checkbox[name^=selectObj]').attr('checked', value);
|
||||
// Set the 'selectionMode' for the future objects to load
|
||||
if (value)
|
||||
{
|
||||
table.config.selectionMode = 'negative';
|
||||
}
|
||||
else
|
||||
{
|
||||
table.config.selectionMode = 'positive';
|
||||
}
|
||||
$(pager).find(':input[name=selectionMode]').val(table.config.selectionMode);
|
||||
// Reset the list of saved selection...
|
||||
resetStoredSelection(pager);
|
||||
updateCounter(table, pager);
|
||||
return true;
|
||||
}
|
||||
|
||||
function resetStoredSelection(pager)
|
||||
{
|
||||
$(':input[name^=storedSelection]', pager).remove();
|
||||
}
|
||||
|
||||
function storeSelection(table, pager, id, value)
|
||||
{
|
||||
var valueToStore = value;
|
||||
if (table.config.selectionMode == 'negative')
|
||||
{
|
||||
valueToStore = !(valueToStore);
|
||||
}
|
||||
if (valueToStore)
|
||||
{
|
||||
if (table.config.select_mode == 'single')
|
||||
{
|
||||
$(':input[name^=storedSelection]', pager).remove(); // Remove any previous selection
|
||||
}
|
||||
if ($('#'+id, pager).length ==0)
|
||||
{
|
||||
$(pager).append($('<input type="hidden" id="'+id+'" name="storedSelection[]" value="'+id+'"></input>'));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if ($('#'+id, pager).length !=0)
|
||||
{
|
||||
$('#'+id, pager).remove();
|
||||
}
|
||||
}
|
||||
updateCounter(table, pager);
|
||||
}
|
||||
|
||||
function loadSelection(table, pager)
|
||||
{
|
||||
table.config.selectionMode = $(pager).find(':input[name=selectionMode]').val();
|
||||
updateCounter(table, pager);
|
||||
}
|
||||
|
||||
function updateCounter(table, pager)
|
||||
{
|
||||
var ex = $(':input[name^=storedSelection]', pager).length;
|
||||
var s = ex;
|
||||
if (table.config.selectionMode == 'negative')
|
||||
{
|
||||
s = table.config.totalRows - ex;
|
||||
}
|
||||
$('.selectedCount',pager).text(s);
|
||||
if (table.config.cssCount != '')
|
||||
{
|
||||
$(table.config.cssCount).val(s);
|
||||
$(table.config.cssCount).trigger('change');
|
||||
}
|
||||
}
|
||||
|
||||
function getData(table, start, end)
|
||||
{
|
||||
if (table.ajax_request)
|
||||
{
|
||||
table.ajax_request.abort();
|
||||
table.ajax_request = null;
|
||||
}
|
||||
|
||||
var c = table.config;
|
||||
var s = c.sortList[0];
|
||||
var s_col = null;
|
||||
var s_order = null;
|
||||
if (s != undefined)
|
||||
{
|
||||
s_col = s[0];
|
||||
s_order = (s[1] == 0) ? 'asc' : 'desc';
|
||||
}
|
||||
$('#loading', table.config.container).html('<img src="../images/indicator.gif" />');
|
||||
table.ajax_request = $.post(AddAppContext(GetAbsoluteUrlAppRoot()+"pages/ajax.render.php"),
|
||||
{ operation: 'pagination',
|
||||
filter: c.filter,
|
||||
extra_param: c.extra_params,
|
||||
start: start,
|
||||
end: end,
|
||||
sort_col: s_col,
|
||||
sort_order: s_order,
|
||||
select_mode: c.select_mode,
|
||||
display_key: c.displayKey,
|
||||
display_list: c.displayList
|
||||
},
|
||||
function(data)
|
||||
{
|
||||
table.ajax_request = null; // Ajax request completed
|
||||
oData = $(data);
|
||||
var tableBody = $(table.tBodies[0]);
|
||||
|
||||
// clear the table body
|
||||
|
||||
$.tablesorter.clearTableBody(table);
|
||||
|
||||
for(var i = 0; i < end-start; i++) {
|
||||
|
||||
//tableBody.append(rows[i]);
|
||||
|
||||
//var o = rows[i];
|
||||
var r = $(oData[i]);
|
||||
var l = r.length;
|
||||
for(var j=0; j < l; j++) {
|
||||
|
||||
//tableBody[0].appendChild(r);
|
||||
tableBody[0].appendChild(r[j]);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
fixPosition(table,tableBody);
|
||||
applySelection(table);
|
||||
|
||||
$(table).trigger("applyWidgets");
|
||||
|
||||
if( c.page >= c.totalPages ) {
|
||||
moveToLastPage(table);
|
||||
}
|
||||
|
||||
updatePageDisplay(c);
|
||||
updateCounter(table, table.config.container);
|
||||
renderPager(table, table.config.container);
|
||||
$(table).tableHover();
|
||||
$('#loading', table.config.container).empty();
|
||||
|
||||
saveParams(table.config);
|
||||
});
|
||||
}
|
||||
|
||||
function applySelection(table)
|
||||
{
|
||||
var c = table.config;
|
||||
if (c.selectionMode == 'negative')
|
||||
{
|
||||
$(table).find(':checkbox[name^=selectObj]').attr('checked', true);
|
||||
}
|
||||
|
||||
if (table.config.select_mode == 'multiple')
|
||||
{
|
||||
$(table).find(':checkbox[name^=selectObj]').each(function() {
|
||||
var id = parseInt(this.value, 10);
|
||||
if ($('#'+id, table.config.container).length > 0)
|
||||
{
|
||||
if (c.selectionMode == 'positive')
|
||||
{
|
||||
$(this).attr('checked', true);
|
||||
}
|
||||
else
|
||||
{
|
||||
$(this).attr('checked', false);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
$(table).find(':checkbox[name^=selectObj]').change(function() {
|
||||
storeSelection(table, table.config.container, this.value, this.checked);
|
||||
});
|
||||
}
|
||||
else if (table.config.select_mode == 'single')
|
||||
{
|
||||
$(table).find('input[name^=selectObject]:radio').each(function() {
|
||||
var id = parseInt(this.value, 10);
|
||||
if ($('#'+id, table.config.container).length > 0)
|
||||
{
|
||||
if (c.selectionMode == 'positive')
|
||||
{
|
||||
$(this).attr('checked', true);
|
||||
}
|
||||
else
|
||||
{
|
||||
$(this).attr('checked', false);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
$(table).find('input[name^=selectObject]:radio').change(function() {
|
||||
storeSelection(table, table.config.container, this.value, this.checked);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function renderPager(table, pager)
|
||||
{
|
||||
var c = table.config;
|
||||
var s = c.page - 2;
|
||||
var nb = Math.ceil(c.totalRows / c.size);
|
||||
if (s < 0)
|
||||
{
|
||||
s = 0;
|
||||
}
|
||||
var e = s +5;
|
||||
if (e > nb)
|
||||
{
|
||||
e = nb;
|
||||
s = e - 5;
|
||||
if (s < 0) s = 0;
|
||||
}
|
||||
txt = '';
|
||||
for(var i=s; i<e; i++)
|
||||
{
|
||||
var page = 1+i;
|
||||
var link = ' '+page+' ';
|
||||
if (i != c.page)
|
||||
{
|
||||
link = ' <span page="'+i+'" id="gotopage_'+i+'">'+page+'</span> ';
|
||||
}
|
||||
else
|
||||
{
|
||||
link = ' <span class="curr_page" page="'+i+'">'+page+'</span> ';
|
||||
}
|
||||
txt += link;
|
||||
}
|
||||
txt += '';
|
||||
$('#total', pager).text(c.totalRows);
|
||||
$('#index', pager).html(txt);
|
||||
for(var j=s; j<e; j++)
|
||||
{
|
||||
$('#gotopage_'+j, pager).click(function(){
|
||||
var idx = $(this).attr('page');
|
||||
table.config.page = idx;
|
||||
moveToPage(table);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function renderTable(table) {
|
||||
|
||||
var c = table.config;
|
||||
//var l = rows.length;
|
||||
var s = (c.page * c.size);
|
||||
var e = (s + c.size);
|
||||
if(e > c.totalRows ) {
|
||||
e = c.totalRows;
|
||||
}
|
||||
|
||||
getData(table, s, e);
|
||||
}
|
||||
|
||||
this.appender = function(table,rows) {
|
||||
|
||||
var c = table.config;
|
||||
|
||||
if (c.totalRows == 0)
|
||||
{
|
||||
c.totalRows = rows.length;
|
||||
}
|
||||
c.totalPages = Math.ceil(c.totalRows / c.size);
|
||||
|
||||
renderTable(table,rows);
|
||||
};
|
||||
|
||||
function saveParams(config) {
|
||||
|
||||
var sPagerId = config.container.attr('id');
|
||||
|
||||
var params = { size: config.selectedSize, page: config.page, sortList: config.sortList };
|
||||
if (window.pager_params == undefined)
|
||||
{
|
||||
window.pager_params = {};
|
||||
}
|
||||
window.pager_params[sPagerId] = params;
|
||||
};
|
||||
|
||||
function restoreParams(table) {
|
||||
|
||||
var sPagerId = config.container.attr('id');
|
||||
if (window.pager_params != undefined)
|
||||
{
|
||||
params = window.pager_params[sPagerId];
|
||||
|
||||
if (params != undefined)
|
||||
{
|
||||
$(table.config.cssPageSize, table.config.container).val(params.size);
|
||||
setPageSize(table, params.size, false); // false => don't trigger a reload
|
||||
if (table.config.sortList != params.sortList)
|
||||
{
|
||||
$(table).trigger("sorton", [params.sortList]); // triggers a reload anyway
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
this.defaults = {
|
||||
size: 10,
|
||||
offset: 0,
|
||||
page: 0,
|
||||
totalRows: 0,
|
||||
totalPages: 0,
|
||||
container: null,
|
||||
cssNext: '.next',
|
||||
cssPrev: '.prev',
|
||||
cssFirst: '.first',
|
||||
cssLast: '.last',
|
||||
cssPageDisplay: '.pagedisplay',
|
||||
cssPageSize: '.pagesize',
|
||||
cssCount: '',
|
||||
seperator: "/",
|
||||
positionFixed: false,
|
||||
appender: this.appender,
|
||||
filter: '',
|
||||
extra_params: '',
|
||||
select_mode: '',
|
||||
totalSelected: 0,
|
||||
selectionMode: 'positive',
|
||||
displayKey: true,
|
||||
displayList: []
|
||||
};
|
||||
|
||||
this.construct = function(settings) {
|
||||
|
||||
return this.each(function() {
|
||||
|
||||
config = $.extend(this.config, $.tablesorterPager.defaults, settings);
|
||||
|
||||
var table = this, pager = config.container;
|
||||
|
||||
this.ajax_request = null;
|
||||
|
||||
config.selectedSize = parseInt($(".pagesize",pager).val());
|
||||
setPageSize(table,config.selectedSize, false);
|
||||
restoreParams(table, config);
|
||||
|
||||
$(this).trigger("appendCache"); // Load the data
|
||||
|
||||
$(config.cssFirst,pager).click(function() {
|
||||
moveToFirstPage(table);
|
||||
return false;
|
||||
});
|
||||
$(config.cssNext,pager).click(function() {
|
||||
moveToNextPage(table);
|
||||
return false;
|
||||
});
|
||||
$(config.cssPrev,pager).click(function() {
|
||||
moveToPrevPage(table);
|
||||
return false;
|
||||
});
|
||||
$(config.cssLast,pager).click(function() {
|
||||
moveToLastPage(table);
|
||||
return false;
|
||||
});
|
||||
$(config.cssPageSize,pager).change(function() {
|
||||
setPageSize(table,parseInt($(this).val()), true);
|
||||
return false;
|
||||
});
|
||||
$(table).find(':checkbox.checkAll').removeAttr('onclick').click(function() {
|
||||
return checkAll(table, pager, this.checked);
|
||||
});
|
||||
|
||||
$(table).bind('load_selection', function() {
|
||||
loadSelection(table, pager);
|
||||
applySelection(table);
|
||||
});
|
||||
});
|
||||
};
|
||||
}
|
||||
});
|
||||
// extend plugin scope
|
||||
$.fn.extend({
|
||||
tablesorterPager: $.tablesorterPager.construct
|
||||
});
|
||||
|
||||
})(jQuery);
|
||||
@@ -1,5 +1,5 @@
|
||||
// JavaScript Document
|
||||
function LinksWidget(id, sClass, sAttCode, iInputId, sSuffix, bDuplicates)
|
||||
function LinksWidget(id, sClass, sAttCode, iInputId, sSuffix, bDuplicates, oWizHelper)
|
||||
{
|
||||
this.id = id;
|
||||
this.iInputId = iInputId;
|
||||
@@ -7,6 +7,7 @@ function LinksWidget(id, sClass, sAttCode, iInputId, sSuffix, bDuplicates)
|
||||
this.sAttCode = sAttCode;
|
||||
this.sSuffix = sSuffix;
|
||||
this.bDuplicates = bDuplicates;
|
||||
this.oWizardHelper = oWizHelper;
|
||||
var me = this;
|
||||
this.Init = function()
|
||||
{
|
||||
@@ -40,6 +41,12 @@ function LinksWidget(id, sClass, sAttCode, iInputId, sSuffix, bDuplicates)
|
||||
// Re-run the zebra plugin to properly highlight the remaining lines & and take into account the removed ones
|
||||
$('#linkedset_'+this.id+' .listResults').trigger('update').trigger("applyWidgets");
|
||||
|
||||
if ($('$linkedset_'+this.id+' .selection').length == 0)
|
||||
{
|
||||
// All items were removed: add a dummy hidden input to make sure that the linkset will be updated (emptied) when posted
|
||||
$('#'+me.id+'_empty_row').show();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
this.OnSelectChange = function()
|
||||
@@ -57,8 +64,28 @@ function LinksWidget(id, sClass, sAttCode, iInputId, sSuffix, bDuplicates)
|
||||
|
||||
this.AddObjects = function()
|
||||
{
|
||||
$('#dlg_'+me.id).dialog('open');
|
||||
this.UpdateSizes(null, null);
|
||||
var me = this;
|
||||
$('#'+me.id+'_indicatorAdd').html(' <img src="../images/indicator.gif"/>');
|
||||
me.oWizardHelper.UpdateWizard();
|
||||
var theMap = { sAttCode: me.sAttCode,
|
||||
iInputId: me.iInputId,
|
||||
sSuffix: me.sSuffix,
|
||||
bDuplicates: me.bDuplicates,
|
||||
'class' : me.sClass,
|
||||
operation: 'addObjects',
|
||||
json: me.oWizardHelper.ToJSON()
|
||||
};
|
||||
$.post( GetAbsoluteUrlAppRoot()+'pages/ajax.render.php', theMap,
|
||||
function(data)
|
||||
{
|
||||
$('#dlg_'+me.id).html(data);
|
||||
$('#dlg_'+me.id).dialog('open');
|
||||
me.UpdateSizes(null, null);
|
||||
me.SearchObjectsToAdd();
|
||||
$('#'+me.id+'_indicatorAdd').html('');
|
||||
},
|
||||
'html'
|
||||
);
|
||||
}
|
||||
|
||||
this.SearchObjectsToAdd = function()
|
||||
@@ -69,6 +96,7 @@ function LinksWidget(id, sClass, sAttCode, iInputId, sSuffix, bDuplicates)
|
||||
bDuplicates: me.bDuplicates
|
||||
}
|
||||
|
||||
me.UpdateButtons(0);
|
||||
// Gather the parameters from the search form
|
||||
$('#SearchFormToAdd_'+me.id+' :input').each(
|
||||
function(i)
|
||||
@@ -96,12 +124,15 @@ function LinksWidget(id, sClass, sAttCode, iInputId, sSuffix, bDuplicates)
|
||||
$(sSearchAreaId).block();
|
||||
|
||||
// Run the query and display the results
|
||||
$.post( '../pages/ajax.render.php', theMap,
|
||||
$.post( GetAbsoluteUrlAppRoot()+'pages/ajax.render.php', theMap,
|
||||
function(data)
|
||||
{
|
||||
$(sSearchAreaId).html(data);
|
||||
$(sSearchAreaId+' .listResults').tableHover();
|
||||
$(sSearchAreaId+' .listResults').tablesorter( { headers: {0: {sorter: false}}, widgets: ['myZebra', 'truncatedList']} ); // sortable and zebra tables
|
||||
$('#count_'+me.id).change(function(){
|
||||
var c = this.value;
|
||||
me.UpdateButtons(c);
|
||||
});
|
||||
$(sSearchAreaId).unblock();
|
||||
},
|
||||
'html'
|
||||
@@ -110,6 +141,19 @@ function LinksWidget(id, sClass, sAttCode, iInputId, sSuffix, bDuplicates)
|
||||
return false; // Don't submit the form, stay in the current page !
|
||||
}
|
||||
|
||||
this.UpdateButtons = function(iCount)
|
||||
{
|
||||
var okBtn = $('#btn_ok_'+me.id);
|
||||
if (iCount > 0)
|
||||
{
|
||||
okBtn.attr('disabled', '');
|
||||
}
|
||||
else
|
||||
{
|
||||
okBtn.attr('disabled', 'disabled');
|
||||
}
|
||||
}
|
||||
|
||||
this.DoAddObjects = function()
|
||||
{
|
||||
var theMap = { sAttCode: me.sAttCode,
|
||||
@@ -120,40 +164,83 @@ function LinksWidget(id, sClass, sAttCode, iInputId, sSuffix, bDuplicates)
|
||||
}
|
||||
|
||||
// Gather the parameters from the search form
|
||||
$('#SearchResultsToAdd_'+me.id+' :checked').each(
|
||||
function(i)
|
||||
{
|
||||
if ( (this.name != '') && ((this.type != 'checkbox') || (this.checked)) )
|
||||
{
|
||||
//console.log(this.type);
|
||||
arrayExpr = /\[\]$/;
|
||||
if (arrayExpr.test(this.name))
|
||||
{
|
||||
// Array
|
||||
if (theMap[this.name] == undefined)
|
||||
{
|
||||
theMap[this.name] = new Array();
|
||||
}
|
||||
theMap[this.name].push(this.value);
|
||||
}
|
||||
else
|
||||
var context = $('#SearchResultsToAdd_'+me.id);
|
||||
var selectionMode = $(':input[name=selectionMode]', context);
|
||||
if (selectionMode.length > 0)
|
||||
{
|
||||
// Paginated table retrieve the mode and the exceptions
|
||||
var sMode = selectionMode.val();
|
||||
theMap['selectionMode'] = sMode;
|
||||
$('#fs_SearchFormToAdd_'+me.id+' :input').each(
|
||||
function(i)
|
||||
{
|
||||
theMap[this.name] = this.value;
|
||||
}
|
||||
);
|
||||
theMap['sRemoteClass'] = theMap['class']; // swap 'class' (defined in the form) and 'remoteClass'
|
||||
theMap['class'] = me.sClass;
|
||||
$(' :input[name^=storedSelection]', context).each(function() {
|
||||
if (theMap[this.name] == undefined)
|
||||
{
|
||||
theMap[this.name] = new Array();
|
||||
}
|
||||
theMap[this.name].push(this.value);
|
||||
$(this).remove(); // Remove the selection for the next time the dialog re-opens
|
||||
});
|
||||
// Retrieve the 'filter' definition
|
||||
var table = $('#ResultsToAdd_'+me.id).find('table.listResults')[0];
|
||||
theMap['filter'] = table.config.filter;
|
||||
theMap['extra_params'] = table.config.extra_params;
|
||||
}
|
||||
// else
|
||||
// {
|
||||
// Normal table, retrieve all the checked check-boxes
|
||||
$(':checked[name^=selectObject]', context).each(
|
||||
function(i)
|
||||
{
|
||||
if ( (this.name != '') && ((this.type != 'checkbox') || (this.checked)) )
|
||||
{
|
||||
//console.log(this.type);
|
||||
arrayExpr = /\[\]$/;
|
||||
if (arrayExpr.test(this.name))
|
||||
{
|
||||
// Array
|
||||
if (theMap[this.name] == undefined)
|
||||
{
|
||||
theMap[this.name] = new Array();
|
||||
}
|
||||
theMap[this.name].push(this.value);
|
||||
}
|
||||
else
|
||||
{
|
||||
theMap[this.name] = this.value;
|
||||
}
|
||||
}
|
||||
$(this).parents('tr:first').remove(); // Remove the whole line, so that, next time the dialog gets displayed it's no longer there
|
||||
}
|
||||
}
|
||||
);
|
||||
);
|
||||
// }
|
||||
|
||||
theMap['operation'] = 'doAddObjects';
|
||||
if (me.oWizardHelper == null)
|
||||
{
|
||||
theMap['json'] = '';
|
||||
}
|
||||
else
|
||||
{
|
||||
// Not inside a "search form", updating a real object
|
||||
me.oWizardHelper.UpdateWizard();
|
||||
theMap['json'] = me.oWizardHelper.ToJSON();
|
||||
}
|
||||
$('#busy_'+me.iInputId).html(' <img src="../images/indicator.gif"/>');
|
||||
// Run the query and display the results
|
||||
$.post( '../pages/ajax.render.php', theMap,
|
||||
$.post( GetAbsoluteUrlAppRoot()+'pages/ajax.render.php', theMap,
|
||||
function(data)
|
||||
{
|
||||
//console.log('Data: ' + data);
|
||||
if (data != '')
|
||||
{
|
||||
$('#'+me.id+'_empty_row').remove();
|
||||
$('#'+me.id+'_empty_row').hide();
|
||||
$('#linkedset_'+me.id+' .listResults tbody').append(data);
|
||||
$('#linkedset_'+me.id+' .listResults').trigger('update');
|
||||
$('#linkedset_'+me.id+' .listResults').tableHover();
|
||||
|
||||
68
js/utils.js
@@ -21,7 +21,7 @@ function ReloadTruncatedList(divId, sSerializedFilter, sExtraParams)
|
||||
console.log('Uh,uh, exception !');
|
||||
}
|
||||
}
|
||||
aTruncatedLists[divId] = $.post('../pages/ajax.render.php?style=list',
|
||||
aTruncatedLists[divId] = $.post(GetAbsoluteUrlAppRoot()+'pages/ajax.render.php?style=list',
|
||||
{ operation: 'ajax', filter: sSerializedFilter, extra_params: sExtraParams },
|
||||
function(data)
|
||||
{
|
||||
@@ -39,12 +39,12 @@ function ReloadTruncatedList(divId, sSerializedFilter, sExtraParams)
|
||||
if (checkbox)
|
||||
{
|
||||
// There is a checkbox in the first column, don't make it sortable
|
||||
table.tablesorter( { headers: { 0: {sorter: false}}, widgets: ['myZebra', 'truncatedList']} ); // sortable and zebra tables
|
||||
table.tablesorter( { headers: { 0: {sorter: false}}, widgets: ['myZebra', 'truncatedList']} ).tablesorterPager({container: $("#pager")}); // sortable and zebra tables
|
||||
}
|
||||
else
|
||||
{
|
||||
// There is NO checkbox in the first column, all columns are considered sortable
|
||||
table.tablesorter( { widgets: ['myZebra', 'truncatedList']} ); // sortable and zebra tables
|
||||
table.tablesorter( { widgets: ['myZebra', 'truncatedList']} ).tablesorterPager({container: $("#pager"), totalRows:97, filter: sSerializedFilter, extra_params: sExtraParams }); // sortable and zebra tables
|
||||
}
|
||||
});
|
||||
$('#'+divId).unblock();
|
||||
@@ -76,30 +76,12 @@ function ReloadBlock(divId, sStyle, sSerializedFilter, sExtraParams)
|
||||
{
|
||||
$('#'+divId).block();
|
||||
//$('#'+divId).blockUI();
|
||||
$.post('../pages/ajax.render.php?style='+sStyle,
|
||||
$.post(GetAbsoluteUrlAppRoot()+'pages/ajax.render.php?style='+sStyle,
|
||||
{ operation: 'ajax', filter: sSerializedFilter, extra_params: sExtraParams },
|
||||
function(data){
|
||||
$('#'+divId).empty();
|
||||
$('#'+divId).append(data);
|
||||
$('#'+divId).removeClass('loading');
|
||||
$('#'+divId+' .listResults').tableHover(); // hover tables
|
||||
$('#'+divId+' .listResults').each( function()
|
||||
{
|
||||
var table = $(this);
|
||||
var id = $(this).parent();
|
||||
var checkbox = (table.find('th:first :checkbox').length > 0);
|
||||
if (checkbox)
|
||||
{
|
||||
// There is a checkbox in the first column, don't make it sortable
|
||||
table.tablesorter( { headers: { 0: {sorter: false}}, widgets: ['myZebra', 'truncatedList']} ); // sortable and zebra tables
|
||||
}
|
||||
else
|
||||
{
|
||||
// There is NO checkbox in the first column, all columns are considered sortable
|
||||
table.tablesorter( { widgets: ['myZebra', 'truncatedList']} ); // sortable and zebra tables
|
||||
}
|
||||
});
|
||||
//$('#'+divId).unblockUI();
|
||||
}
|
||||
);
|
||||
}
|
||||
@@ -137,8 +119,18 @@ function ReloadSearchForm(divId, sClassName, sBaseClass, sContext)
|
||||
}
|
||||
sAction = $('#ds_'+divId+' form').attr('action');
|
||||
|
||||
$.post('../pages/ajax.render.php?'+sContext,
|
||||
{ operation: 'search_form', className: sClassName, baseClass: sBaseClass, currentId: divId, action: sAction },
|
||||
// Save the current values in the form
|
||||
var oMap = {};
|
||||
$('#ds_'+divId+" form :input[name!='']").each(function() {
|
||||
oMap[this.name] = this.value;
|
||||
});
|
||||
oMap.operation = 'search_form';
|
||||
oMap.className = sClassName;
|
||||
oMap.baseClass = sBaseClass;
|
||||
oMap.currentId = divId;
|
||||
oMap.action = sAction;
|
||||
|
||||
$.post(GetAbsoluteUrlAppRoot()+'pages/ajax.render.php?'+sContext, oMap,
|
||||
function(data) {
|
||||
oDiv.empty();
|
||||
oDiv.append(data);
|
||||
@@ -183,7 +175,7 @@ function SetUserPreference(sPreferenceCode, sPrefValue, bPersistent)
|
||||
oUserPreferences[sPreferenceCode] = sPrefValue;
|
||||
if (bPersistent && (sPrefValue != sPreviousValue))
|
||||
{
|
||||
ajax_request = $.post('../pages/ajax.render.php',
|
||||
ajax_request = $.post(GetAbsoluteUrlAppRoot()+'pages/ajax.render.php',
|
||||
{ operation: 'set_pref', code: sPreferenceCode, value: sPrefValue} ); // Make it persistent
|
||||
}
|
||||
}
|
||||
@@ -210,10 +202,15 @@ function CheckAll(sSelector, bValue)
|
||||
{
|
||||
var value = bValue;
|
||||
$(sSelector).each( function() {
|
||||
this.checked = value;
|
||||
if (this.checked != value)
|
||||
{
|
||||
this.checked = value;
|
||||
$(this).trigger('change');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Toggle (enabled/disabled) the specified field of a form
|
||||
*/
|
||||
@@ -284,4 +281,23 @@ function PropagateCheckBox(bCurrValue, aFieldsList, bCheck)
|
||||
ToogleField(bCheck, aFieldsList[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function FixTableSorter(table)
|
||||
{
|
||||
if ($('th.header', table).length == 0)
|
||||
{
|
||||
// Table is not sort-able, let's fix it
|
||||
var checkbox = (table.find('th:first :checkbox').length > 0);
|
||||
if (checkbox)
|
||||
{
|
||||
// There is a checkbox in the first column, don't make it sort-able
|
||||
table.tablesorter( { headers: { 0: {sorter: false}}, widgets: ['myZebra', 'truncatedList']} ); // sort-able and zebra tables
|
||||
}
|
||||
else
|
||||
{
|
||||
// There is NO checkbox in the first column, all columns are considered sort-able
|
||||
table.tablesorter( { widgets: ['myZebra', 'truncatedList']} ); // sort-able and zebra tables
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -9,7 +9,7 @@ function UpdateObjectList(sClass, sId, sExtKeyToRemote)
|
||||
aRelatedObjectIds[0] = 0;
|
||||
}
|
||||
var oql = "SELECT "+sClass+" AS c WHERE c.id IN (" + aRelatedObjectIds.join(", ") + ")";
|
||||
$.post("ajax.render.php?style=list&encoding=oql",
|
||||
$.post(GetAbsoluteUrlAppRoot()+"ajax.render.php?style=list&encoding=oql",
|
||||
{ operation: "ajax", filter: oql },
|
||||
function(data){
|
||||
$("#related_objects_"+sId).empty();
|
||||
@@ -42,7 +42,7 @@ function ManageObjects(sTitle, sClass, sId, sExtKeyToRemote)
|
||||
function Manage_LoadSelect(sSelectedId, sFilter)
|
||||
{
|
||||
$('#'+sSelectedId).addClass('loading');
|
||||
$.post('../pages/ajax.render.php',
|
||||
$.post(GetAbsoluteUrlAppRoot()+'pages/ajax.render.php',
|
||||
{ operation: 'combo_options', filter: sFilter },
|
||||
function(data){
|
||||
$('#'+sSelectedId).empty();
|
||||
|
||||
@@ -136,11 +136,17 @@ function WizardHelper(sClass, sFormPrefix, sState)
|
||||
}
|
||||
}
|
||||
|
||||
this.UpdateWizardToJSON = function ()
|
||||
{
|
||||
this.UpdateWizard();
|
||||
return this.ToJSON()
|
||||
}
|
||||
|
||||
this.AjaxQueryServer = function ()
|
||||
{
|
||||
//console.log('data sent:', this.ToJSON());
|
||||
//console.log('oWizard:', this);
|
||||
$.post('../pages/ajax.render.php',
|
||||
$.post(GetAbsoluteUrlAppRoot()+'pages/ajax.render.php',
|
||||
{ operation: 'wizard_helper', json_obj: this.ToJSON() },
|
||||
function(html){
|
||||
$('#ajax_content').html(html);
|
||||
@@ -156,7 +162,7 @@ function WizardHelper(sClass, sFormPrefix, sState)
|
||||
{
|
||||
//console.log('data sent:', this.ToJSON());
|
||||
//console.log('oWizard:', this);
|
||||
$('#'+divId).load('../pages/ajax.render.php?operation=wizard_helper_preview',
|
||||
$('#'+divId).load(GetAbsoluteUrlAppRoot()+'pages/ajax.render.php?operation=wizard_helper_preview',
|
||||
{'json_obj': this.ToJSON()},
|
||||
function(responseText, textStatus, XMLHttpRequest){
|
||||
$('#wizStep'+ G_iCurrentStep).unblock( {fadeOut: 0} );
|
||||
@@ -189,4 +195,21 @@ function WizardHelper(sClass, sFormPrefix, sState)
|
||||
}
|
||||
this.AjaxQueryServer();
|
||||
}
|
||||
|
||||
this.ReloadObjectCreationForm = function(sFormId, sTargetState)
|
||||
{
|
||||
$('#'+sFormId).block();
|
||||
this.UpdateWizard();
|
||||
this.ResetQuery();
|
||||
var sTransactionId = $('input[name=transaction_id]').val();
|
||||
$.post(GetAbsoluteUrlAppRoot()+'pages/ajax.render.php',
|
||||
{ json_obj: this.ToJSON(), operation: 'obj_creation_form', target_state: sTargetState, transaction_id: sTransactionId },
|
||||
function(data)
|
||||
{
|
||||
$('#'+sFormId).html(data);
|
||||
onDelayedReady();
|
||||
$('#'+sFormId).unblock();
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
47
modules/authent-external/ja.dict.authent-external.php
Normal file
@@ -0,0 +1,47 @@
|
||||
<?php
|
||||
// Copyright (C) 2010 Combodo SARL
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation; version 3 of the License.
|
||||
//
|
||||
// This program 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 General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
/**
|
||||
* Localized data
|
||||
*
|
||||
* @author Erwan Taloc <erwan.taloc@combodo.com>
|
||||
* @author Romain Quetiez <romain.quetiez@combodo.com>
|
||||
* @author Denis Flaven <denis.flaven@combodo.com>
|
||||
* @license http://www.opensource.org/licenses/gpl-3.0.html LGPL
|
||||
*/
|
||||
|
||||
// Dictionnay conventions
|
||||
// Class:<class_name>
|
||||
// Class:<class_name>+
|
||||
// Class:<class_name>/Attribute:<attribute_code>
|
||||
// Class:<class_name>/Attribute:<attribute_code>+
|
||||
// Class:<class_name>/Attribute:<attribute_code>/Value:<value>
|
||||
// Class:<class_name>/Attribute:<attribute_code>/Value:<value>+
|
||||
// Class:<class_name>/Stimulus:<stimulus_code>
|
||||
// Class:<class_name>/Stimulus:<stimulus_code>+
|
||||
|
||||
//
|
||||
// Class: UserExternal
|
||||
//
|
||||
|
||||
Dict::Add('JA JP', 'Japanese', '日本語', array (
|
||||
'Class:UserExternal' => '外部ユーザー',
|
||||
'Class:UserExternal+' => 'iTopの外で認証されたユーザー',
|
||||
));
|
||||
|
||||
|
||||
|
||||
?>
|
||||
@@ -79,12 +79,6 @@ class UserExternal extends User
|
||||
return false;
|
||||
}
|
||||
|
||||
public function CanLogOff()
|
||||
{
|
||||
// External authentication: iTop has no way to force a log off
|
||||
return false;
|
||||
}
|
||||
|
||||
public function ChangePassword($sOldPassword, $sNewPassword)
|
||||
{
|
||||
return false;
|
||||
|
||||
25
modules/authent-external/pt_br.dict.authent-external.php
Normal file
@@ -0,0 +1,25 @@
|
||||
<?php
|
||||
// Copyright (C) 2010 Combodo SARL
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation; version 3 of the License.
|
||||
//
|
||||
// This program 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 General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
/**
|
||||
* @licence http://www.opensource.org/licenses/gpl-3.0.html LGPL
|
||||
*/
|
||||
|
||||
Dict::Add('PT BR', 'Brazilian', 'Brazilian', array(
|
||||
'Class:UserExternal' => 'Usuário externo',
|
||||
'Class:UserExternal+' => '',
|
||||
));
|
||||
?>
|
||||
@@ -20,6 +20,7 @@
|
||||
* @author Erwan Taloc <erwan.taloc@combodo.com>
|
||||
* @author Romain Quetiez <romain.quetiez@combodo.com>
|
||||
* @author Denis Flaven <denis.flaven@combodo.com>
|
||||
* @author Stephan Rosenke <stephan.rosenke@itomig.de>
|
||||
* @license http://www.opensource.org/licenses/gpl-3.0.html LGPL
|
||||
*/
|
||||
|
||||
@@ -39,7 +40,7 @@
|
||||
|
||||
Dict::Add('DE DE', 'German', 'Deutsch', array(
|
||||
'Class:UserLDAP' => 'LDAP-Benutzer',
|
||||
'Class:UserLDAP+' => 'Benutzer,der über LDAP authenifiziert wird',
|
||||
'Class:UserLDAP+' => 'Benutzer, der über LDAP authentifiziert wird',
|
||||
'Class:UserLDAP/Attribute:password' => 'Passwort',
|
||||
'Class:UserLDAP/Attribute:password+' => 'Benutzerpasswort',
|
||||
));
|
||||
|
||||
49
modules/authent-ldap/ja.dict.authent-ldap.php
Normal file
@@ -0,0 +1,49 @@
|
||||
<?php
|
||||
// Copyright (C) 2010 Combodo SARL
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation; version 3 of the License.
|
||||
//
|
||||
// This program 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 General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
/**
|
||||
* Localized data
|
||||
*
|
||||
* @author Erwan Taloc <erwan.taloc@combodo.com>
|
||||
* @author Romain Quetiez <romain.quetiez@combodo.com>
|
||||
* @author Denis Flaven <denis.flaven@combodo.com>
|
||||
* @license http://www.opensource.org/licenses/gpl-3.0.html LGPL
|
||||
*/
|
||||
|
||||
// Dictionnay conventions
|
||||
// Class:<class_name>
|
||||
// Class:<class_name>+
|
||||
// Class:<class_name>/Attribute:<attribute_code>
|
||||
// Class:<class_name>/Attribute:<attribute_code>+
|
||||
// Class:<class_name>/Attribute:<attribute_code>/Value:<value>
|
||||
// Class:<class_name>/Attribute:<attribute_code>/Value:<value>+
|
||||
// Class:<class_name>/Stimulus:<stimulus_code>
|
||||
// Class:<class_name>/Stimulus:<stimulus_code>+
|
||||
|
||||
//
|
||||
// Class: UserLDAP
|
||||
//
|
||||
|
||||
Dict::Add('JA JP', 'Japanese', '日本語', array (
|
||||
'Class:UserLDAP' => 'LDAP ユーザー', # 'LDAP user',
|
||||
'Class:UserLDAP+' => 'LDAPにて認証されたユーザー', # 'User authentified by LDAP',
|
||||
'Class:UserLDAP/Attribute:password' => 'パスワード', # 'Password',
|
||||
'Class:UserLDAP/Attribute:password+' => '認証文字列', # 'user authentication string',
|
||||
));
|
||||
|
||||
|
||||
|
||||
?>
|
||||
@@ -120,7 +120,7 @@ class UserLDAP extends UserInternal
|
||||
$aEntry = ldap_get_entries($hDS, $hSearchResult);
|
||||
$sUserDN = $aEntry[0]['dn'];
|
||||
$bUserBind = @ldap_bind($hDS, $sUserDN, $sPassword);
|
||||
if ($bUserBind !== false)
|
||||
if (($bUserBind !== false) && !empty($sPassword))
|
||||
{
|
||||
ldap_unbind($hDS);
|
||||
return true; // Password Ok
|
||||
@@ -158,12 +158,6 @@ class UserLDAP extends UserInternal
|
||||
return false;
|
||||
}
|
||||
|
||||
public function CanLogOff()
|
||||
{
|
||||
// Internal authentication allows everybody to log off
|
||||
return true;
|
||||
}
|
||||
|
||||
public function ChangePassword($sOldPassword, $sNewPassword)
|
||||
{
|
||||
return false;
|
||||
|
||||
27
modules/authent-ldap/pt_br.dict.authent-ldap.php
Normal file
@@ -0,0 +1,27 @@
|
||||
<?php
|
||||
// Copyright (C) 2010 Combodo SARL
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation; version 3 of the License.
|
||||
//
|
||||
// This program 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 General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
/**
|
||||
* @licence http://www.opensource.org/licenses/gpl-3.0.html LGPL
|
||||
*/
|
||||
|
||||
Dict::Add('PT BR', 'Brazilian', 'Brazilian', array(
|
||||
'Class:UserLDAP' => 'Usuário externo',
|
||||
'Class:UserLDAP+' => '',
|
||||
'Class:UserLDAP/Attribute:password' => 'Senha',
|
||||
'Class:UserLDAP/Attribute:password+' => '',
|
||||
));
|
||||
?>
|
||||