Compare commits

..

863 Commits

Author SHA1 Message Date
Denis Flaven
62510e2b04 Fix for Trac #670: XSS vulnerability issue.
SVN:1.2[2588]
2013-01-22 17:38:01 +00:00
Denis Flaven
f33c821306 Merged, the implementation of Track #582: "stable name" for synchro_data_xxx tables
SVN:1.2[2404]
2012-10-29 15:36:55 +00:00
Denis Flaven
11d0e9f52b Do not perform time consuming computations for building the menus if there are too many objects in a list (limit is configurable).
SVN:1.2[2344]
2012-10-24 14:04:57 +00:00
Denis Flaven
3330fd79d0 Bug fix: regression introduced by revision 2278.
SVN:1.2[2340]
2012-10-24 13:20:26 +00:00
Denis Flaven
02e0a61dcf Optimization to speed-up the "group-by" tables. (The complete solution is implemented in 2.0)
SVN:1.2[2338]
2012-10-24 13:13:15 +00:00
Romain Quetiez
2bb8028d4d Fixed regression (CSV import - unknown method utils::GetConfig)
SVN:1.2[2322]
2012-10-22 08:07:46 +00:00
Romain Quetiez
891b22909a #583 Losing attachments when performing massive change
SVN:1.2[2286]
2012-10-18 09:39:37 +00:00
Denis Flaven
463748b6da Properly handle all types of fields when entering values via the state transition "wizard" screen
SVN:1.2[2279]
2012-10-17 14:05:10 +00:00
Denis Flaven
fc2878b6d1 Properly handle a change of an external key...
SVN:1.2[2276]
2012-10-17 13:25:32 +00:00
Romain Quetiez
17919f5389 Portal: enable adding dependent attributes in the request creation form -reintegrated from trunk
SVN:1.2[2274]
2012-10-17 12:54:19 +00:00
Romain Quetiez
e54b1d2ff4 Portal: enable adding dependent attributes in the request creation form -reintegrated from trunk
SVN:1.2[2271]
2012-10-17 12:17:28 +00:00
Romain Quetiez
523fb8bd25 Fixed issue in the portal: the list of opened requests and closed request where messed up when pagination was activated on both lists -reintegrated from trunk
SVN:1.2[2268]
2012-10-17 09:12:01 +00:00
Romain Quetiez
fad77fb9fa CSV import: added a flag to disable the history tab (too long to display, when the feature is heavily used), reintegrated from trunk
SVN:1.2[2265]
2012-10-16 14:47:22 +00:00
Erwan Taloc
8da92c9251 add iTop favicon
SVN:1.2[2171]
2012-09-10 09:39:31 +00:00
Erwan Taloc
977d616ef2 Rename translation of Friendly name attribute to Friendly Name
SVN:1.2[2148]
2012-08-09 12:59:44 +00:00
Romain Quetiez
29faa739c1 Reintegrated fixes from branch 1.2.1 (2116,2118,2119)
- HTML attributes > 64 Kb
- Log of notification displayed as HTML

SVN:1.2[2120]
2012-07-04 09:23:12 +00:00
Denis Flaven
b986f63a67 Bug fix: $this->label(attcode)$ used inside Email Notifications should not contain HTML entities since this not an HTML fragment.
SVN:1.2[2117]
2012-06-29 15:11:35 +00:00
Denis Flaven
8fa3a6d47d Localization of the title of the login page
SVN:1.2[2112]
2012-06-15 13:30:07 +00:00
Denis Flaven
0e6876b068 Localization of the title of the login page
SVN:1.2[2111]
2012-06-15 13:27:16 +00:00
Denis Flaven
8d962f4bdb Fix for Trac #559: ldap user can login with blank password
SVN:1.2[2109]
2012-06-14 16:28:14 +00:00
Denis Flaven
3b8f945c44 Fixed Trac #558: properly parse strings containing hexadecimal sequences (i.e. 'QWERTY0xCUIOP').
Note that for now hexadecimal numbers are parsed but not interpreted properly...

SVN:1.2[2104]
2012-06-14 09:22:01 +00:00
Romain Quetiez
9600c89a1f Fixed regression (See #556) due to the existence of an overload of the protected API GetUserOrgs, reintegrated from branch 1.2.1
SVN:1.2[2100]
2012-06-14 09:12:25 +00:00
Denis Flaven
d01202ba33 Reload the impact/depends on graph only on demand for better performance, via the new Refresh button
SVN:1.2[2088]
2012-06-07 13:57:17 +00:00
Romain Quetiez
1bc1a0a1b2 #556 Merged in branch 1.2
SVN:1.2[2083]
2012-06-05 15:46:24 +00:00
Romain Quetiez
37ea4cb5e3 Reintegrated changes from trunk, to uncompile legacy data models
SVN:1.2[2080]
2012-06-05 11:18:10 +00:00
Denis Flaven
c4a003f620 Make the 'filter' conditions on ExtKey applicable also when searching on derived classes.
SVN:1.2[1991]
2012-05-16 12:23:54 +00:00
Denis Flaven
7a8ee0353a Protects against too long strings when logging web services events
SVN:1.2[1961]
2012-04-19 11:17:20 +00:00
Romain Quetiez
6b526ba455 #541 Fixed bug in the export for spreadsheet (time format)
SVN:1.2[1946]
2012-04-06 09:41:43 +00:00
Denis Flaven
9d9b923b7e Properly log-off (and report the issue in the log) in case we fail to create a user during the CAS Synchro
SVN:1.2[1942]
2012-04-04 10:09:07 +00:00
Erwan Taloc
fcaad0cd07 Add web link to link class in schema.php for an attribute linkset
SVN:1.2[1937]
2012-04-03 11:18:23 +00:00
Romain Quetiez
da875dd945 #540 Data synchro: the option "write if empty" was not implemented
SVN:1.2[1933]
2012-03-29 13:32:35 +00:00
Denis Flaven
2a71bf5008 Bug fix: to do not try to access a DataSource while it's being deleted
SVN:1.2[1929]
2012-03-27 11:26:31 +00:00
Denis Flaven
9b36ebc106 Bug fix: support [+] button inside linkedsets.. with constraints
SVN:1.2[1926]
2012-03-22 17:19:06 +00:00
Denis Flaven
1a507b7aa4 CAS integration. Done.
SVN:1.2[1921]
2012-03-22 15:30:23 +00:00
Denis Flaven
178ee28596 CAS integration continuing
SVN:1.2[1919]
2012-03-22 15:16:22 +00:00
Denis Flaven
e44a5d2980 CAS integration:
- regression fix: support patterns for the MemberOf groups filtering
- activate/de-activate the profiles synchronization using the 'cas_update_profiles' configuration flag
- provide default profile(s) when creating a new user from CAS, only if no match is found for assigning profiles from the CAS MemberOf group(s).

SVN:1.2[1917]
2012-03-22 10:53:09 +00:00
Denis Flaven
828c02db0b Bug fix: support [+] button inside linkedsets.. with constraints
SVN:1.2[1914]
2012-03-22 09:38:03 +00:00
Denis Flaven
d1e4e2109f Bug fix: support [+] button inside linkedsets.. with constraints
SVN:1.2[1913]
2012-03-22 09:35:25 +00:00
Denis Flaven
b7a9b340b8 Bug fix: support [+] button inside linkedsets.. with constraints
SVN:1.2[1912]
2012-03-22 09:11:45 +00:00
Denis Flaven
3731cf6dc1 The date picker fills the "time" part of the field with 00:00:00 when picking a DateTime instead of just a Date.
SVN:1.2[1910]
2012-03-21 10:53:33 +00:00
Denis Flaven
0e7fc5e5c4 Bug fix: support [+] button inside linkedsets
SVN:1.2[1908]
2012-03-21 10:36:55 +00:00
Denis Flaven
bc62c06894 Rollback of the modification: For forward compatibility... It was already implemented !
SVN:1.2[1907]
2012-03-21 10:28:45 +00:00
Denis Flaven
4ed85c23de Allow to specify the name of the PDF to download
SVN:1.2[1905]
2012-03-20 16:55:20 +00:00
Denis Flaven
b6c1347f27 For forward compatibility...
SVN:1.2[1904]
2012-03-20 16:54:13 +00:00
Denis Flaven
237eefcbc6 LinkedSets can be read-only too...
SVN:1.2[1898]
2012-03-19 17:17:45 +00:00
Denis Flaven
5ee3c69898 Make the class "TriggerOnPortalUpdate" importable
SVN:1.2[1896]
2012-03-16 12:58:23 +00:00
Denis Flaven
53b3ae8016 Enhanced fix for Trac #503. Don't drop the column before re-creating it, in case the data can be converted by MySQL.
SVN:1.2[1892]
2012-03-14 16:15:53 +00:00
Denis Flaven
26b6bfaf7f Added detecting of missing columns in the synchro_data_xxx tables (in case of duplicate SQL column names in the orignal data model). See Trac #503.
SVN:1.2[1891]
2012-03-14 16:02:39 +00:00
Denis Flaven
1a659cc4d0 Experimental support of PDF output for iTop pages, provided that mPDF is installed in lib/MPDF
SVN:1.2[1876]
2012-03-07 16:40:22 +00:00
Denis Flaven
b000900d6c Stylesheet enhancements to support printing...
SVN:1.2[1875]
2012-03-07 14:42:28 +00:00
Denis Flaven
f68ec1cef1 Typo
SVN:1.2[1874]
2012-03-04 18:13:06 +00:00
Denis Flaven
3fb867d393 - Current block Id not passed to the chart ?
SVN:1.2[1873]
2012-03-04 17:53:28 +00:00
Denis Flaven
fe559eb492 Small fix for genericity
SVN:1.2[1872]
2012-03-04 17:51:53 +00:00
Denis Flaven
0041afd6d0 - Current block Id not passed to the chart ?
SVN:1.2[1871]
2012-03-04 17:48:03 +00:00
Denis Flaven
dc1b5b0d4c - Bug fix: the hierarchical key in Organizations is not always named 'parent_id' !
SVN:1.2[1868]
2012-02-27 16:15:08 +00:00
Denis Flaven
10a930b7b2 Typo!
SVN:1.2[1862]
2012-02-21 14:03:35 +00:00
Denis Flaven
72b6089db8 Added the ability to Find then Remove a tab inside a page
SVN:1.2[1860]
2012-02-20 17:13:53 +00:00
Denis Flaven
0cfb1c3a83 Fix in case there is only one non-shared organization.
SVN:1.2[1858]
2012-02-17 12:52:35 +00:00
Denis Flaven
36a73535a5 Delay the storage of the dictionary in the cache to allow for its alteration during the initialization of the classes
SVN:1.2[1856]
2012-02-17 12:47:58 +00:00
Denis Flaven
9382b89277 Distinguish between creation and modification rights
SVN:1.2[1854]
2012-02-17 12:43:55 +00:00
Romain Quetiez
6d14da15cf Implemented the capability to implemented a separate module for sharing objects between the silos:
+ possibility for a plugin to alter the definition of a class (add an attribute)
+ fixed a bug (low exposure) in the cache for MetaModel::GetObject()
+ possibility to have computed fields on links (list of fields in the form now based on the ZList 'list')

SVN:1.2[1853]
2012-02-17 09:35:06 +00:00
Denis Flaven
3113205f88 Allow to add some headers like content-type.
SVN:1.2[1852]
2012-02-10 12:42:34 +00:00
Denis Flaven
09bd8052d7 Allow more than 64K for the email body (including attachments)
SVN:1.2[1850]
2012-02-10 12:25:21 +00:00
Denis Flaven
85f0b79203 Update to the Italian translation
SVN:1.2[1848]
2012-02-08 14:39:30 +00:00
Romain Quetiez
81145d7b1c Improved the change tracking to simplify the development of plugins (1st step... still to be drastically simplified)
SVN:1.2[1847]
2012-02-08 14:24:45 +00:00
Denis Flaven
7e6d1c2ce4 Performance improvements of the autocomplete: don't trigger a search when there is no expression to search !
SVN:1.2[1846]
2012-02-07 13:34:40 +00:00
Denis Flaven
364259daa5 Restore the previous state of URLMaker after building a notification
SVN:1.2[1845]
2012-02-07 09:32:29 +00:00
Denis Flaven
7b270294f6 Fix for query modifiers plug-ins
SVN:1.2[1843]
2012-02-07 09:12:45 +00:00
Romain Quetiez
c7aa00e81a Implemented the capability to modify queries by the mean of a plugin (make it work with APC cache)
SVN:1.2[1842]
2012-02-06 10:54:35 +00:00
Romain Quetiez
f9e7446e7b Reverted (removed test code)
SVN:1.2[1841]
2012-02-03 17:22:54 +00:00
Romain Quetiez
493ab80965 Implemented the capability to modify queries by the mean of a plugin (beta)
SVN:1.2[1840]
2012-02-03 17:16:27 +00:00
Denis Flaven
e623467782 Readme updated for the 1.2.1 release.
SVN:1.2[1838]
2012-02-01 10:27:10 +00:00
Denis Flaven
32208fcbfc Readme updated for the 1.2.1 release.
SVN:1.2[1837]
2012-02-01 10:24:31 +00:00
Denis Flaven
dcbff406f7 Fix to the Brazilian translation: thanks to Google translate !
SVN:1.2[1836]
2012-01-31 17:51:15 +00:00
Denis Flaven
017dfe641c Update to the Brazilian translation, thanks to Marco Tulio
SVN:1.2[1834]
2012-01-31 17:48:02 +00:00
Denis Flaven
fad258cd2d (Tried to) improve the display of the Synchronization Tooltip that "sometimes" does not work on IE 8...
SVN:1.2[1832]
2012-01-31 17:30:59 +00:00
Denis Flaven
3470ce18e8 Removed a (useless) hardcoded reference to FunctionalCI
SVN:1.2[1830]
2012-01-31 15:39:35 +00:00
Denis Flaven
af710c549f SQL Block with parameters were always displayed as table, whatever their type...
SVN:1.2[1828]
2012-01-31 15:04:23 +00:00
Denis Flaven
ee938d674d Fixed typos during the copy/paste for automatic account creation
SVN:1.2[1826]
2012-01-31 12:36:05 +00:00
Denis Flaven
423de35cf5 Fixed the encoding of mail headers !
SVN:1.2[1825]
2012-01-31 12:35:34 +00:00
Denis Flaven
6a7af8ad73 Make the OQLQuery class import-able
SVN:1.2[1822]
2012-01-30 17:46:00 +00:00
Denis Flaven
89732d6e52 Put some default reconciliation keys to ease the use of CSV import
SVN:1.2[1820]
2012-01-30 17:42:54 +00:00
Denis Flaven
cddeab2c90 Protect against empty list of reconciliation keys
SVN:1.2[1818]
2012-01-30 17:38:45 +00:00
Denis Flaven
d9d84703ae Fix to have the proper use of GetEditValue... thanks to C. Naud
SVN:1.2[1817]
2012-01-30 12:49:04 +00:00
Romain Quetiez
c3de9ecf10 Export for spreadsheets: transform keys (id of the queried object or external keys) into the corresponding friendly name
SVN:1.2[1815]
2012-01-30 10:58:21 +00:00
Denis Flaven
cf37a50b3d Enhancements to the German localization
SVN:1.2[1814]
2012-01-30 10:45:27 +00:00
Romain Quetiez
4db30648c2 Object details: log always displayed AFTER plugin data
SVN:1.2[1812]
2012-01-27 13:51:17 +00:00
Denis Flaven
8de84d5ec7 Fixed Trac#518 : Properly pass the context (i.e. currently selected org) to the auto-refresh lists
SVN:1.2[1810]
2012-01-25 10:27:23 +00:00
Denis Flaven
459a271d11 Fixed Trac#522: issue with non-ASCII characters in notifications subject.
SVN:1.2[1809]
2012-01-24 18:24:34 +00:00
Denis Flaven
9da00b83b2 Added the ability to display a custom welcome/disclaimer message at the bottom of the login form.
SVN:1.2[1807]
2012-01-24 15:24:25 +00:00
Denis Flaven
0c8ef6a690 Why put "APPROOT/modules/" as the AbsoluteUrlAppRoot in the portal ??
SVN:1.2[1804]
2012-01-24 14:26:39 +00:00
Denis Flaven
cdefd7a4c6 Hmmm, also may cause troubles for bug #519...
SVN:1.2[1801]
2012-01-24 13:04:39 +00:00
Romain Quetiez
4f057ac29f Improved the check on data model consistency: detection of SQL columns used by two attributes
SVN:1.2[1800]
2012-01-24 13:01:55 +00:00
Denis Flaven
ab16588f87 Fix for Trac#519 - change password bug !
SVN:1.2[1799]
2012-01-24 13:00:15 +00:00
Denis Flaven
07d8da9d99 Added the "search" form on top of the list of users
SVN:1.2[1796]
2012-01-20 15:24:33 +00:00
Romain Quetiez
c539f19ce9 Optimized memory usage when auditing large volumes of CIs (10'000 items was requiring 200 Mb, it now runs with 32 Mb -including the 30Mb overhead!)
SVN:1.2[1795]
2012-01-20 15:03:07 +00:00
Denis Flaven
3635e60850 Typo fix
SVN:1.2[1794]
2012-01-20 14:19:56 +00:00
Denis Flaven
b278b84f46 Fixed #481: localized characters in Service / Service Category name and description were not properly displayed.
SVN:1.2[1793]
2012-01-20 14:16:20 +00:00
Romain Quetiez
04647970a8 Case log now largely bigger than 64 Kilobytes... (reintegrated change made in trunk)
SVN:1.2[1791]
2012-01-19 15:32:48 +00:00
Romain Quetiez
fe58f6bd19 Fixed regression in the tool to test queries: losing the query when there is a syntax error
SVN:1.2[1788]
2012-01-19 10:13:36 +00:00
Romain Quetiez
0d6cd529a1 #516 and #517 Improved the export (specify fields for multi-column queries) and web queries (default field list)
SVN:1.2[1786]
2012-01-18 16:59:09 +00:00
Denis Flaven
2a155fe8ee Added SetMessageId for forward compatibility with SwiftMailer
SVN:1.2[1785]
2012-01-18 10:05:12 +00:00
Romain Quetiez
3f381a3530 Partially de-hardcoded against the subdirectory "modules", so that 1.2.1 should be compatible with modules running under 2.0.
SVN:1.2[1778]
2012-01-17 15:26:02 +00:00
Denis Flaven
7fadb5e08b Added self-registering / user synchronization extensibility
SVN:1.2[1760]
2012-01-11 16:01:11 +00:00
Denis Flaven
5d4476f48b Added self-registering / user synchronization extensibility
SVN:1.2[1757]
2012-01-11 14:31:44 +00:00
Romain Quetiez
2fbb37cc2f Readme updated, ready for 1.2.1 beta
SVN:1.2[1753]
2011-12-22 10:34:00 +00:00
Denis Flaven
6801ecb266 Updated the readme file to prepare for the 1.2.1 beta release
SVN:1.2[1752]
2011-12-22 10:29:27 +00:00
Romain Quetiez
fa821d3a9b #512 Allow the CLI mode for export.php
SVN:1.2[1750]
2011-12-21 15:28:50 +00:00
Denis Flaven
00f9deeaa5 Updated the readme file to prepare for the 1.2.1 beta release
SVN:1.2[1747]
2011-12-21 15:14:41 +00:00
Romain Quetiez
58cfc1d51b CSV import (both std and related to the data synchro) can be used with a tab (keyword 'tab', case insensitive)
SVN:1.2[1746]
2011-12-21 14:46:03 +00:00
Denis Flaven
af8b3b972d Fixed Trac #480: properly take into account the 'min_autocomplete_chars' settings.
SVN:1.2[1745]
2011-12-21 14:23:20 +00:00
Denis Flaven
07671f40fd Allow a module to restrict the access to a given menu/group by redeclaring the menu with restricted rights. All rights are combined with the AND operator.
SVN:1.2[1743]
2011-12-21 14:17:03 +00:00
Denis Flaven
3da5c65fe4 Allow to filter which class(es) of objects are displayed in the graphical impact analysis view
SVN:1.2[1742]
2011-12-21 14:15:27 +00:00
Romain Quetiez
489be44b90 #489 Data synchro: reintegrated the latest improvements from trunk.
SVN:1.2[1740]
2011-12-21 13:45:07 +00:00
Denis Flaven
912088d017 Fixed Trac #486: SQL dashboards limitations
SVN:1.2[1730]
2011-12-20 15:17:14 +00:00
Denis Flaven
06620133b6 Bug fix: missing (but useless) parameter in ExpandArgs causes a notice...
SVN:1.2[1728]
2011-12-20 12:41:05 +00:00
Denis Flaven
95d7a24630 Keep the current value iin the search form when reloading the search form for a different (sub)class. For example Contact => Person.
SVN:1.2[1726]
2011-12-19 17:30:02 +00:00
Denis Flaven
cb0e1d8ef3 When searching objects to add to the current object (n:n relationship), set the default search params in order to stay in the current silo.
SVN:1.2[1724]
2011-12-19 16:50:39 +00:00
Denis Flaven
d321ebc8e4 Bug fix: apply the AllowedValues constraints(as default values) when selecting elements via the "magnifier" button or creating an new element via the "plus" button... also make sure that allowed values is enforced
SVN:1.2[1721]
2011-12-15 10:46:48 +00:00
Romain Quetiez
c149ec8e2c #485 Improved the end-user experience with Excel and the web queries (added a phrasebook) + link to test the OQL attributes (query phrasebook or email actions, etc.) including the handlink of query arguments) + fixed wrong prototypes for a few implementations of GetBareProperties()
SVN:1.2[1719]
2011-12-14 17:44:06 +00:00
Denis Flaven
281adfb043 Bug fix: apply the AllowedValues constraints(as default values) when selecting elements via the "magnifier" button or creating an new element via the "plus" button.
SVN:1.2[1715]
2011-12-13 14:43:33 +00:00
Romain Quetiez
4244029087 #485 Export for MS Excel web queries: format=spreadsheet
SVN:1.2[1713]
2011-12-13 14:30:36 +00:00
Denis Flaven
78e173d5fb Bug fix: paginated lists were broken in the Impact Analysis "List" tab
SVN:1.2[1708]
2011-12-07 10:41:13 +00:00
Romain Quetiez
6b8abce03a - commited merge information (done earlier) -
SVN:1.2[1705]
2011-12-06 13:52:44 +00:00
Denis Flaven
33a7005069 - Bug ! Incorrectly appending a parameter ?version= to linked scripts already containing a parameter in their URL !
- changed the parameter name to itopversion to avoid collisions

SVN:1.2[1702]
2011-12-01 17:18:47 +00:00
Denis Flaven
006a6037d1 Increased Suhosin minimum value for get_max_value to 2048 due to a bug seen on some installations
SVN:1.2[1700]
2011-11-30 13:23:32 +00:00
Denis Flaven
e2f8be1745 Use the default language when creating a new user from CAS
SVN:1.2[1698]
2011-11-29 15:56:24 +00:00
Denis Flaven
ebae45f6a5 Support patterns for casMemberof
SVN:1.2[1696]
2011-11-29 15:36:58 +00:00
Denis Flaven
0685835d49 Allow to log entries on behalf of another user
SVN:1.2[1694]
2011-11-24 17:22:19 +00:00
Romain Quetiez
1b1e88f9a4 In french, organiZation takes an S
SVN:1.2[1691]
2011-11-23 15:30:11 +00:00
Denis Flaven
b90f443e75 - Don't create warnings for empty ext keys (i.e. empty string)
- Properly record multiple warnings
- Don't record warnings in case of creation error (error has precedence)

SVN:1.2[1689]
2011-11-23 09:55:44 +00:00
Romain Quetiez
4da64a64b1 Cosmetic on the API of the dictionnary (internal)
SVN:1.2[1686]
2011-11-21 17:03:36 +00:00
Denis Flaven
6673e171dc Properly handle restrictions (e.g. AllowedValues) on objects that are used as n:n relationships managed via LinksWidget.
SVN:1.2[1685]
2011-11-21 13:08:10 +00:00
Denis Flaven
afee7297cc Properly handle restrictions (e.g. AllowedValues) on objects that are used as n:n relationships managed via LinksWidget.
SVN:1.2[1683]
2011-11-21 10:57:50 +00:00
Denis Flaven
3cc8b5b88a Enhancement: when an (optional) external key cannot be reconciled, log a warning on the replica. the replicas containing a warning are then processed everytime in case the ext key changes
Also improved the search/display of replicas

SVN:1.2[1678]
2011-11-18 11:42:29 +00:00
Romain Quetiez
b2e6981b24 Fixed bug in change tracking: it was impossible to factorize code creating objects in the background either in the context of an object update or in the context of the application of a stimulus
SVN:1.2[1674]
2011-11-18 10:46:42 +00:00
Denis Flaven
c0a79fa573 Prevent warnings when checking the available stimuli in the menu...
SVN:1.2[1672]
2011-11-16 17:26:27 +00:00
Denis Flaven
02ad6d19fe Prevent Javascript errors in case a name contains a quote.
SVN:1.2[1670]
2011-11-15 13:12:22 +00:00
Denis Flaven
d16308ab62 - Reload the object after applying a stimulus, in case an action has an effect on an external field...
SVN:1.2[1665]
2011-11-14 10:44:31 +00:00
Denis Flaven
4598959bc2 - Reload the object after applying a stimulus, in case an action has an effect on an external field...
SVN:1.2[1664]
2011-11-14 10:43:06 +00:00
Denis Flaven
65a3755f81 - Regression from previous fix: don't Reload an object before saving it !
SVN:1.2[1662]
2011-11-10 16:37:18 +00:00
Denis Flaven
dc46c65499 - Don't activate triggers if the transition fails
- Reload the object, in case some custom action changed an external object

SVN:1.2[1659]
2011-11-10 10:12:43 +00:00
Denis Flaven
9d691c8e56 Removed obsolete code which caused a warning in bulk_stimulus
SVN:1.2[1658]
2011-11-10 10:07:28 +00:00
Denis Flaven
99f897bff7 Better error handling in case of OQL error
SVN:1.2[1657]
2011-11-09 17:07:25 +00:00
Denis Flaven
8d83447222 Added the capability for plug-ins to "listen" to add/remove attachment events.
SVN:1.2[1652]
2011-10-28 12:46:22 +00:00
Romain Quetiez
dcc8ad08a4 New helper class: TemplateString - to allow extended syntaxes such as $this->location_id->org_id->parent_id->name$... to be progressively introduced and replace the heavy ToArgs()
SVN:1.2[1646]
2011-10-24 13:45:49 +00:00
Denis Flaven
c1b0b73b51 Bug fix: Trac #494. It seems that PHPSoap does not understand the <wsdl:documentation> tag.
SVN:1.2[1644]
2011-10-21 08:42:13 +00:00
Romain Quetiez
81173decca Fixed issue: nobody in the list of persons to notify for portal users (security takes precedence)
SVN:1.2[1641]
2011-10-21 08:05:07 +00:00
Denis Flaven
9aca062bf5 Enhancement to provide a forward compatible API for some external plugins: support adding attachments to an email in a "clean" way.
SVN:1.2[1640]
2011-10-20 16:33:46 +00:00
Denis Flaven
09aba95d0a Fixed Trac #493: incorrect display of Users' Grant Matrix
SVN:1.2[1635]
2011-10-17 09:27:23 +00:00
Denis Flaven
1683ca2dd6 Merged some enhancements fro the trunk to better keep track of sent emails
SVN:1.2[1634]
2011-10-13 15:42:59 +00:00
Denis Flaven
9e732d6045 Fixed Trac #487: resizable text areas disappeared when located on the second tab !
SVN:1.2[1628]
2011-10-04 10:52:03 +00:00
Denis Flaven
69df343bd2 Automatic synchro of CAS/LDAP users
SVN:1.2[1627]
2011-10-03 14:07:29 +00:00
Denis Flaven
eb8f49ebfe Initializes the admin contact's phone number, in case it is a mandatory field in the data model...
SVN:1.2[1623]
2011-09-30 08:03:45 +00:00
Denis Flaven
398e294604 Prevent crash when trying to load the favicon during the setup !
SVN:1.2[1621]
2011-09-29 15:27:25 +00:00
Denis Flaven
d04c6bccd5 Added a link to a favicon (icon in the browser's bar and tab)
SVN:1.2[1619]
2011-09-29 14:54:03 +00:00
Denis Flaven
f00c7c6bc2 GetValueLabel is used in some dashboards... make sure that it is available for any attribute
SVN:1.2[1617]
2011-09-29 09:46:58 +00:00
Denis Flaven
d30e8c359f Make sure that the organisation's drop-down list is not bigger than the left menu...
SVN:1.2[1616]
2011-09-29 09:44:38 +00:00
Romain Quetiez
2bd4a61c00 #485 Export.php improved for integration into Excel / web queries (bug with IIS/HTTPS, limitation on the size of the OQL)
SVN:1.2[1613]
2011-09-29 08:12:28 +00:00
Romain Quetiez
ba3080594c #485 Export.php improved for integration into Excel / web queries (bug with IIS/HTTPS, limitation on the size of the OQL)
SVN:trunk[1612]
2011-09-29 08:07:37 +00:00
Romain Quetiez
e35c8323df Merge most recent (few) bug fixes from trunk
SVN:1.2[1611]
2011-09-28 14:38:37 +00:00
Romain Quetiez
e4e814281d #484 Fixed issue with IIS ("Wrong password" at first prompt)
SVN:1.2[1610]
2011-09-28 12:59:40 +00:00
Romain Quetiez
a3a94cccbb #484 Fixed issue with IIS ("Wrong password" at first prompt)
SVN:trunk[1609]
2011-09-28 12:55:15 +00:00
Denis Flaven
635cb424a2 Fixed Trac #482: OpenSearch broken.
SVN:1.2[1608]
2011-09-28 10:50:58 +00:00
Romain Quetiez
e8c8e4a0d7 #481 Special characters not transcribed correctly in Portal (regression in 1.2)
SVN:trunk[1607]
2011-09-28 10:17:53 +00:00
Denis Flaven
5b3350f6d5 Fixed Trac #482: link to OpenSearch Xml page was broken
SVN:trunk[1606]
2011-09-28 10:07:27 +00:00
Denis Flaven
b454b24e0f Rename the cron.params file to avoid overwriting the current config when updating.
SVN:trunk[1605]
2011-09-23 14:14:58 +00:00
Romain Quetiez
e95aa6cc69 Merged latest changes in module Attachments (bug fix on install and cosmetic improvements)
SVN:1.2[1604]
2011-09-23 13:49:26 +00:00
Romain Quetiez
c58fd17fc9 Fixed regression on attribute labels; introduced in [1582]
SVN:1.2[1603]
2011-09-23 13:36:57 +00:00
Romain Quetiez
099afb5451 Fixed regression on attribute labels; introduced in [1581]
SVN:trunk[1602]
2011-09-23 13:30:21 +00:00
Denis Flaven
ec226ce76d Cosmetic fix: the "loading..." indicator was visible/spinning when reloading any other field of the form !
SVN:trunk[1601]
2011-09-22 16:37:47 +00:00
Denis Flaven
5080bd58d5 Removed some Debug/Warning messages
SVN:trunk[1600]
2011-09-22 16:35:33 +00:00
Romain Quetiez
efdec7a343 #478 Fixed issue in the audit: the results are wrong whenever an organization is selected
SVN:1.2[1599]
2011-09-22 12:08:11 +00:00
Denis Flaven
5ec37fd26a - Fix a problem with the upgrade (case sensitive table name & prefix)
SVN:trunk[1598]
2011-09-22 11:58:42 +00:00
Romain Quetiez
2352c05d36 Fixed security issue: the attachments were visible by anybody (by forming URLs manually), whatever the allowed organizations. The change requires the execution of the setup/migration procedure.
SVN:1.2[1597]
2011-09-22 11:58:31 +00:00
Denis Flaven
8ae92cb50e - Fix a problem with the upgrade (case sensitive table name & prefix)
- Display a message when there is no attachment

SVN:trunk[1596]
2011-09-22 11:53:49 +00:00
Romain Quetiez
f82a4ada23 #478 Fixed issue in the audit: the results are wrong whenever an organization is selected
SVN:trunk[1595]
2011-09-22 11:40:30 +00:00
Denis Flaven
e5ce12ed0a Make the template system work for real !
SVN:trunk[1594]
2011-09-22 11:15:40 +00:00
Denis Flaven
428f1a26cc Typo ! Impact: Unknown ?
SVN:trunk[1593]
2011-09-22 11:08:34 +00:00
Romain Quetiez
9976999a88 Portal: updated dictionary for new buttton "reopen request"
SVN:trunk[1592]
2011-09-22 10:08:36 +00:00
Romain Quetiez
da2b8ab4c0 Fixed security issue: the attachments were visible by anybody (by forming URLs manually), whatever the allowed organizations. The change requires the execution of the setup/migration procedure.
SVN:trunk[1591]
2011-09-22 09:04:12 +00:00
Romain Quetiez
0de75db474 Portal (regression with the latest implementation, causing a warning)
SVN:trunk[1590]
2011-09-21 12:59:16 +00:00
Romain Quetiez
23634964a5 #477 Could not specify more than one reconciliation key (regression) + took the opportunity to enhance protection against XSS injection (using column names in the data)
SVN:1.2[1589]
2011-09-21 12:39:22 +00:00
Romain Quetiez
b014596172 #477 Could not specify more than one reconciliation key (regression) + took the opportunity to enhance protection against XSS injection (using column names in the data)
SVN:trunk[1588]
2011-09-21 12:27:08 +00:00
Romain Quetiez
b46ed4764d Fixed bug in the new portal: the wizard validation was inoperant when several selection lists were proposed
SVN:trunk[1587]
2011-09-20 13:50:11 +00:00
Romain Quetiez
2b1aecda53 Fixed recent regression on the portal (confusion btw GetContactId and GetUserId)
SVN:trunk[1586]
2011-09-20 08:22:54 +00:00
Romain Quetiez
619252db99 Merge fix on previous change (fixed #473, but getting a warning)
SVN:1.2[1585]
2011-09-19 11:49:43 +00:00
Romain Quetiez
19318973ca Fixed warning (strict standards) on previous fix
SVN:trunk[1584]
2011-09-19 11:44:04 +00:00
Romain Quetiez
ca4dbd833c (record merge info)
SVN:1.2[1583]
2011-09-19 10:58:40 +00:00
Romain Quetiez
f62a3b22a3 #473 Could not load NW interfaces (reconciliation issue) - merged from trunk
SVN:1.2[1582]
2011-09-19 10:55:24 +00:00
Romain Quetiez
cac76a7e08 #473 Could not load NW interfaces (reconciliation issue)
SVN:trunk[1581]
2011-09-19 10:36:47 +00:00
Romain Quetiez
88416bca5d Created branch 1.2
SVN:1.2[1580]
2011-09-19 10:30:29 +00:00
Romain Quetiez
abd645ca98 Fixed regressions in the portal
SVN:trunk[1579]
2011-09-15 15:25:30 +00:00
Romain Quetiez
7301cb9369 Updated the dictionnaries for the latest changes into the portal
SVN:trunk[1578]
2011-09-15 10:26:50 +00:00
Romain Quetiez
559de3d38f Portal reworked (code factorization, allowing for paginated lists) + added the list of closed tickets (+search)
SVN:trunk[1577]
2011-09-15 10:06:46 +00:00
Denis Flaven
552ffd79b1 Always use a drop-down list for external keys in search forms
SVN:trunk[1575]
2011-09-14 07:38:40 +00:00
Denis Flaven
aae8ca7b8b Added credentials for the security advices
SVN:trunk[1574]
2011-09-13 14:58:40 +00:00
Denis Flaven
13c636cab6 Prevent email header injection
SVN:trunk[1573]
2011-09-13 14:55:34 +00:00
Denis Flaven
cc40fc5d91 Exclude a (risky) and unused file for the build
SVN:trunk[1572]
2011-09-13 14:38:52 +00:00
Denis Flaven
bddfdb4a28 Fixed Trac #468: wrong path to the doc#installationInstructions
SVN:trunk[1571]
2011-09-12 11:22:29 +00:00
Denis Flaven
6bc639c6ce Enhanced error message in case of "file too big error" (more user friendly and not admin oriented)
SVN:trunk[1570]
2011-09-12 09:48:54 +00:00
Denis Flaven
9b8ae03413 - Properly display names containing XML entities (& < > and ")
- Don't drag items by their (invisible) tooltip !

SVN:trunk[1569]
2011-09-10 16:24:26 +00:00
Denis Flaven
17f00198d3 Fix for #404: context was lost when performing a drill-down in the flash navigator.
SVN:trunk[1568]
2011-09-10 16:20:50 +00:00
Denis Flaven
5041ec2e0c Regression on accentuated characters due to bad (forgotten) encoding on htmlentities (Trac #446)
SVN:trunk[1567]
2011-09-09 16:18:01 +00:00
Denis Flaven
ee4f7e5b6a Don't forget to track the count of updated objects...
SVN:trunk[1566]
2011-09-09 16:11:51 +00:00
Denis Flaven
cbb40b85dc Typo in a (not yet used) function !
SVN:trunk[1565]
2011-09-08 15:29:35 +00:00
Denis Flaven
9aca772209 Fix for Trac#446: prevent XSS vulnerabilities
SVN:trunk[1564]
2011-09-08 13:33:47 +00:00
Denis Flaven
c4db9cd84e More fixes for Trac#446: XSS vulnerabilities with vectors containing double quotes
SVN:trunk[1563]
2011-09-08 13:21:32 +00:00
Romain Quetiez
205e80f8a5 #446 XSS vector through the page title
SVN:trunk[1562]
2011-09-08 10:30:18 +00:00
Romain Quetiez
06e9bd0c25 #446 XSS vector on the login web page
SVN:trunk[1561]
2011-09-08 10:28:14 +00:00
Denis Flaven
1c812f8b34 Bug fix: subsequent audit results were wrong when a 'negative' rule was used.
SVN:trunk[1560]
2011-09-07 12:12:10 +00:00
Romain Quetiez
f3c5759721 Updated the readme file
SVN:trunk[1559]
2011-09-07 07:58:22 +00:00
Denis Flaven
69368a39cb Fix radio buttons for enum values.
SVN:trunk[1558]
2011-09-06 12:47:42 +00:00
Denis Flaven
ab5849b3cd Fix: properly manage validation field for vertical radio buttons.
SVN:trunk[1557]
2011-09-06 10:25:06 +00:00
Denis Flaven
1ab796bd40 One more fix for #404: context was lost when performing a bulk delete.
SVN:trunk[1556]
2011-09-06 08:07:18 +00:00
Denis Flaven
c1221054b4 Prevent a crash when displaying the details of a change (from the CSV "history" tab)
SVN:trunk[1555]
2011-09-05 16:28:31 +00:00
Denis Flaven
3bd681bc9d Bug fix: hyperlink to create a new object was wrong (typo)
SVN:trunk[1554]
2011-09-02 15:54:32 +00:00
Denis Flaven
b33989ec62 Added the ability to specify programmatically the scope for "favorite organizations". Note the the end-user can still restrict this list even further using the "Preferences" page.
SVN:trunk[1553]
2011-09-01 14:06:51 +00:00
Denis Flaven
b3121eebae Typos in the Brazilian localization, found by Bruno Cassaro. Thanks Bruno !
SVN:trunk[1552]
2011-09-01 13:07:09 +00:00
Denis Flaven
7d8971139b Missing sanitization filter for 1 parameter: fixed !
SVN:trunk[1551]
2011-09-01 11:50:34 +00:00
Denis Flaven
04f20860dc Add the name of the synchro data source as an external field in case we need to make a CSV export
SVN:trunk[1550]
2011-09-01 10:50:57 +00:00
Denis Flaven
8f21b9dabb Bug fix: prevent a warning when doing modify-all as a non-admin user.
SVN:trunk[1549]
2011-09-01 10:49:56 +00:00
Romain Quetiez
eb89610465 Readme file ready for release 1.2
SVN:trunk[1548]
2011-08-31 15:37:48 +00:00
Denis Flaven
13f4e90ee6 Make sure that we trigger a change event whenever we pickup a different value for an external key (either via the magnifier button or via the hierarchy button)
SVN:trunk[1547]
2011-08-31 14:39:55 +00:00
Denis Flaven
29f1dd5a69 Prevent an exception in some (rare?) conditions where an incorrect value was set in a temporary object....cf Trac #466
SVN:trunk[1546]
2011-08-31 14:28:41 +00:00
Romain Quetiez
a7e937ec58 Regression: the default language was German!
SVN:trunk[1545]
2011-08-31 13:09:50 +00:00
Denis Flaven
bc2a8a8c4a Improved verification to the PHP file upload settings to avoid troubles later... (Trac #284)
SVN:trunk[1544]
2011-08-31 09:03:26 +00:00
Denis Flaven
c9b0a2b561 Enhance ObjectDetailsTemplate to manage bulk actions and synchronized attributes.
SVN:trunk[1543]
2011-08-30 15:47:57 +00:00
Romain Quetiez
5fcea9bf69 #437 Regressions in the beta - wrong reporting of the bulk update
SVN:trunk[1542]
2011-08-30 15:09:54 +00:00
Denis Flaven
3b42c86f46 Regression due to the interaction of the two previous fixes. (Trac #444 and Trac #448)
SVN:trunk[1541]
2011-08-30 11:12:14 +00:00
Romain Quetiez
038fe30fbe #363 Charts not displaying with IE8 + IIS + HTTPS
SVN:trunk[1540]
2011-08-30 10:13:58 +00:00
Denis Flaven
aa95e51e00 Fixed Trac #444: preserve sort order and page size when reloading a paginated list.
SVN:trunk[1539]
2011-08-30 09:38:06 +00:00
Romain Quetiez
6a78c7dcc2 Internal: Fixed regression introduced in [1365] and present in the beta version (overviews not working with HTTPS)
SVN:trunk[1538]
2011-08-30 09:20:29 +00:00
Romain Quetiez
17aa1d1fc0 #464 While upgrading iTop, copy the values from change/start_date to ticket/start_date (iif the current value is null)
SVN:trunk[1537]
2011-08-29 16:28:08 +00:00
Romain Quetiez
24244f1bac Rollback: restored attributes removed by mistake
SVN:trunk[1536]
2011-08-29 16:26:17 +00:00
Romain Quetiez
f7be35848c Internal: detect unused columns while upgrading
SVN:trunk[1535]
2011-08-29 15:37:58 +00:00
Denis Flaven
1aa7ff14fe Removing duplicate fields
SVN:trunk[1534]
2011-08-29 15:02:59 +00:00
Denis Flaven
c33a508376 Removing duplicate fields
SVN:trunk[1533]
2011-08-29 15:02:12 +00:00
Romain Quetiez
37ec8b12f3 Upgrade/toolkit: improved the data sources update procedure (no need to create "direct" linkset attributes, remove old attributes, more verbose)
SVN:trunk[1532]
2011-08-29 13:23:57 +00:00
Romain Quetiez
dde3efc0c7 Upgrade: adjust data sources, and be more verbose about upgrades in the DB (HKeys and data sources)
SVN:trunk[1531]
2011-08-29 13:20:44 +00:00
Romain Quetiez
54f3dec7a9 Upgrade: fails to recreate a view when is has become invalid (missing attribute)
SVN:trunk[1530]
2011-08-29 13:18:30 +00:00
Denis Flaven
6be497ee7d Fixed Trac#465: incorrect logic when resetting the 'ConnectedToInterface'
SVN:trunk[1529]
2011-08-29 11:55:13 +00:00
Denis Flaven
5d9d44dc5e Fix: detection of the Suhosin extension during the installation and tell the user if the get_max_value is too small.
SVN:trunk[1528]
2011-08-29 11:49:22 +00:00
Denis Flaven
d547394ba2 Fixed Trac#448: paginated display broken after reloading a page containing a list where the page size is set to 'All'
SVN:trunk[1527]
2011-08-26 11:07:29 +00:00
Denis Flaven
ace0a3e278 Finishing fix of Trac449:display selection of favorite organizations
SVN:trunk[1526]
2011-08-26 10:45:46 +00:00
Denis Flaven
dd9cb27971 Fixed Trac #449: properly reload the current selection when the list of Favorite Organizations is a paginated list.
SVN:trunk[1525]
2011-08-26 10:34:54 +00:00
Denis Flaven
a3dc8ab3d7 Added the ability to reload a selection fro a paginated list.
SVN:trunk[1524]
2011-08-26 10:33:37 +00:00
Denis Flaven
496bf386be Force the rebuilding of hierarchical keys on every upgrade, since in 1.2-beta the rebuilding of HK was buggy. (May be the cause of the bugs: #459, #460 and #461)
SVN:trunk[1523]
2011-08-26 09:08:54 +00:00
Denis Flaven
c337616fea Fix: regression for tickets with just a default initial state.
SVN:trunk[1522]
2011-08-26 07:26:30 +00:00
Denis Flaven
186ba76092 Added a flag to force the import to cinutnue even in case of SQL error... useful for debugging don't use in production ;-)
SVN:trunk[1521]
2011-08-25 17:37:56 +00:00
Denis Flaven
20a06c9212 Fixed a warning...
SVN:trunk[1520]
2011-08-25 17:03:12 +00:00
Romain Quetiez
e515dfb434 Cosmetics: regression due to an unnecessary protection against XSS attacks
SVN:trunk[1519]
2011-08-25 16:35:38 +00:00
Romain Quetiez
2ee85dd407 Customization: added a check against reuse of an attribute code (collision can happen easily with inheritance)
SVN:trunk[1518]
2011-08-25 16:10:57 +00:00
Denis Flaven
6df6e4a9cc - Allow creation of an ticket in a different initial state via the new 'initial_state_path' attribute.
- Support update of CaseLog fields in bulk_modify mode.

SVN:trunk[1517]
2011-08-25 16:04:58 +00:00
Romain Quetiez
c74c955973 Internal: it is possible to override the user authorized organizations
SVN:trunk[1516]
2011-08-25 15:45:45 +00:00
Romain Quetiez
a3a4fd0a75 Dictionary: English was proposed twice in the list of available languages!
SVN:trunk[1515]
2011-08-25 12:01:04 +00:00
Romain Quetiez
c7f3ac0361 Internal: suppressed a warning on ormCaseLog
SVN:trunk[1514]
2011-08-25 11:57:18 +00:00
Romain Quetiez
21002574ce Notifications: case log in plain text (this->case_log) or the latest entry (this->head(case_log))
SVN:trunk[1513]
2011-08-25 11:49:15 +00:00
Romain Quetiez
64cae5b58b Portal: activate TriggerOnPortalUpdate
SVN:trunk[1512]
2011-08-25 11:46:23 +00:00
Romain Quetiez
cc1105ff60 Email test: under IIS it was not detecting Windows correctly, and the help message was therefore completely wrong.
SVN:trunk[1511]
2011-08-25 10:04:21 +00:00
Romain Quetiez
71655f0632 Fixed regression (shortcut actions, display a list of objects not deriving from cmdbAbstract)
SVN:trunk[1510]
2011-08-25 09:29:52 +00:00
Denis Flaven
6e4e5be35d Allow TriggerOnPortalUpdate to work also on derived classes: i.e a trigger defined for the class 'Ticket' will be called when a 'UserRequest' (derived from Ticket) will be updated from the portal.
SVN:trunk[1509]
2011-08-25 08:03:39 +00:00
Denis Flaven
872a424a78 Bug fix: allow modifying an object as if in target state, before applying the stimulus (cf PortalWebpage).
SVN:trunk[1508]
2011-08-24 16:00:28 +00:00
Denis Flaven
612c355e03 Bug fix: allow modifying an object as if in target state, before applying the stimulus (cf PortalWebpage).
SVN:trunk[1507]
2011-08-24 15:58:56 +00:00
Denis Flaven
ffa9b21364 Bug fix: allow modifying an object as if in target state, before applying the stimulus (cf PortalWebpage).
SVN:trunk[1506]
2011-08-24 15:58:22 +00:00
Denis Flaven
180311fd0a Fixed a side effect of Trac#446 (XSS)
SVN:trunk[1505]
2011-08-24 15:56:48 +00:00
Denis Flaven
16b7714139 Default shortcut actions are now a parameter
SVN:trunk[1504]
2011-08-24 14:11:57 +00:00
Denis Flaven
c6865cf63d Default shortcut actions are now a parameter
SVN:trunk[1503]
2011-08-24 14:11:25 +00:00
Denis Flaven
905d9b5931 Apply organization filtering to subclasses of Organization as well.
SVN:trunk[1502]
2011-08-24 13:54:27 +00:00
Denis Flaven
0850370275 Bug fix: let accented characters pass through the autocomplete
SVN:trunk[1501]
2011-08-24 13:53:19 +00:00
Romain Quetiez
38591f444e Fixed regression on latest fix (Hkeys and inheritance)
SVN:trunk[1500]
2011-08-24 10:49:39 +00:00
Denis Flaven
ae36aa1f74 German localization update, thanks to Stephan Rosenke.
SVN:trunk[1499]
2011-08-23 16:55:01 +00:00
Denis Flaven
264af56591 Pass the final class to GetShortcutActions
SVN:trunk[1498]
2011-08-23 13:56:09 +00:00
Denis Flaven
0a2c9d0e37 Automatic rebuild of the dictionary list during setup, based on the content of the 'dictionaries' folder.
SVN:trunk[1497]
2011-08-23 13:13:08 +00:00
Denis Flaven
9d9d53c967 Fix regression on hierarchical keys
SVN:trunk[1496]
2011-08-23 11:14:25 +00:00
Denis Flaven
54315f41e4 Bug fix: computation of allowed stimuli was wrong
SVN:trunk[1495]
2011-08-23 09:17:19 +00:00
Denis Flaven
a04e7ea375 Bug fix in HierarchicalKey: host class can be different from target class in case of derived classes.
SVN:trunk[1494]
2011-08-23 07:24:55 +00:00
Erwan Taloc
795296e6e3 update after test made by Erwan
SVN:trunk[1493]
2011-08-23 07:13:28 +00:00
Denis Flaven
98ac85c098 Added the display of the total count of objects above 'group by' blocks.
SVN:trunk[1492]
2011-08-22 16:42:28 +00:00
Romain Quetiez
e53c07393c Internal: improved the API of PortalWebPage
SVN:trunk[1491]
2011-08-22 10:09:21 +00:00
Denis Flaven
48d66447b7 Support an abstract "Organization" class: if it's the case don't create any Org neither Person during the setup.
SVN:trunk[1490]
2011-08-22 10:06:48 +00:00
Romain Quetiez
54b4f67ed6 Fixed regression due to the enhanced security (ignore a field in CSV import)
SVN:trunk[1489]
2011-08-22 08:49:52 +00:00
Denis Flaven
9836797da9 Regression due to XSS fix (#446): auto-refresh block was showing an assertion failed message. Fixed.
SVN:trunk[1488]
2011-08-22 08:37:08 +00:00
Romain Quetiez
931a260435 Fixed regression due to the enhanced security (param file)
SVN:trunk[1487]
2011-08-22 08:32:25 +00:00
Denis Flaven
2a6d36b9cd Bug fix: (post 1.2-beta) warning message (undefined variable aFavoriteActions) when displaying a list for a non-admin user...
SVN:trunk[1486]
2011-08-22 08:19:35 +00:00
Denis Flaven
9420c14c13 Fixed a (post 1.2-beta) regression: bulk modify and bluk apply stimulus were broken.
SVN:trunk[1485]
2011-08-22 08:18:07 +00:00
Romain Quetiez
272807ba56 Export.php - fixed a regression (specifying no field list resulting in an error)
SVN:trunk[1484]
2011-08-22 07:38:38 +00:00
Denis Flaven
d05ea1863c Fixed a (post 1.2-beta) regression: bulk modify and bluk apply stimulus were broken.
SVN:trunk[1483]
2011-08-21 16:41:23 +00:00
Denis Flaven
6c8e021727 Fixed Trac# 457: crash when deleting two organizations.
SVN:trunk[1482]
2011-08-19 17:14:06 +00:00
Romain Quetiez
266135b1b9 #452 Export.php - field list can be specified also for HTML output
SVN:trunk[1481]
2011-08-19 16:14:50 +00:00
Denis Flaven
02fc610a18 Bug fix: "shortcut" actions were not perserving the current tab. Fixed.
SVN:trunk[1480]
2011-08-19 16:08:27 +00:00
Denis Flaven
e2aa3cc69f Enhancement: provide a warning (popup) message when navigating away from an edition form.
SVN:trunk[1479]
2011-08-19 15:50:17 +00:00
Denis Flaven
de516c0ce4 Fixed Trac #458: back button was asking to fill the mandatory fields !
SVN:trunk[1478]
2011-08-19 15:41:05 +00:00
Romain Quetiez
92ac1fe2ca #148 Allow overloading attribute/enum labels in the dictionary
SVN:trunk[1477]
2011-08-19 15:30:43 +00:00
Romain Quetiez
cc7844ea10 Security: protected bulk modify against HTTP/Post piracy
SVN:trunk[1476]
2011-08-19 15:26:05 +00:00
Denis Flaven
22bdc02b1b Support the selection (via an autocomplete) in a list that contains duplicates
SVN:trunk[1475]
2011-08-19 15:00:33 +00:00
Romain Quetiez
e8586515e3 Fixed regression (HKeys)
SVN:trunk[1474]
2011-08-19 08:51:16 +00:00
Romain Quetiez
071a30d928 Cosmetic on the portal
SVN:trunk[1473]
2011-08-19 07:42:19 +00:00
Denis Flaven
488f1c47bf Fixed Trac #456: 'contact_list' was considered as read-only on tickets.
SVN:trunk[1472]
2011-08-19 07:32:19 +00:00
Romain Quetiez
c15976f148 Internal: leverage display block for displaying link sets in the portal
SVN:trunk[1471]
2011-08-18 16:32:31 +00:00
Romain Quetiez
6f8e2e60ce Internal: the transaction mechanism was inoperant when a form was built within the target page.
SVN:trunk[1470]
2011-08-18 15:00:39 +00:00
Denis Flaven
b7b8da0848 Fixed the computation of IPs in a subnet that failed (returned negative numbers) on some versions of PHP compiled in 32-bit.
SVN:trunk[1469]
2011-08-18 12:05:30 +00:00
Denis Flaven
2f1803b3b6 A mandatory case log field is now considered as 'filled' if it contains a previous entry
SVN:trunk[1468]
2011-08-18 10:45:41 +00:00
Denis Flaven
58e61c9d6b A mandatory case log field is now considered as 'filled' if it contains a previous entry
SVN:trunk[1467]
2011-08-18 10:44:37 +00:00
Denis Flaven
ddd98b9335 Different display for 'Date' fields: shorter field than DateTime since there is no "time" part.
SVN:trunk[1466]
2011-08-18 09:51:10 +00:00
Denis Flaven
278b84ee38 The default value for Date fields is different than for DateTime fields: no 'time' part at the end (use the attribute's own format)
SVN:trunk[1465]
2011-08-18 09:50:16 +00:00
Denis Flaven
c0764bce74 Added smart search for 'Date' fields (and not only DateTime)
SVN:trunk[1464]
2011-08-18 09:48:44 +00:00
Denis Flaven
7cf0e2f747 Bug fix: incorrect detection of the need to fix HK, leading to incorrect data in case of upgrade.
SVN:trunk[1463]
2011-08-18 07:01:08 +00:00
Romain Quetiez
c7e8627679 Fixed regression on the paginated lists
SVN:trunk[1462]
2011-08-17 15:56:34 +00:00
Denis Flaven
1c7d5b8fd2 Added support for an abstract Organization (or Person) class during setup !
SVN:trunk[1461]
2011-08-17 15:20:32 +00:00
Denis Flaven
18217e4adb Bug fix: (side effect of fixing #445) paginate the lists when performing a selection.
SVN:trunk[1460]
2011-08-16 17:07:54 +00:00
Denis Flaven
1357e7e225 Bug fix: paginated display was always displaying 5 items by default...
SVN:trunk[1459]
2011-08-16 16:42:02 +00:00
Denis Flaven
a941c2d14e Allow updating/recomputing of read-only attributes on the fly in the edit form.
SVN:trunk[1458]
2011-08-16 16:16:26 +00:00
Denis Flaven
cb55a75bcf Allow updating/recomputing of read-only attributes on the fly in the edit form.
Also fixed a regerssion due to #446

SVN:trunk[1457]
2011-08-16 15:58:09 +00:00
Denis Flaven
1e20253229 Bug fix: don't assume that the hierachical key is called 'parent_id'
SVN:trunk[1456]
2011-08-16 15:54:22 +00:00
Denis Flaven
53a48dc8e0 Fixed Trac #447: interfaces not showing up on the details of a server when an org is selected: there were collisions in the internal query parameters names ! This is now fixed.
SVN:trunk[1455]
2011-08-16 10:01:14 +00:00
Denis Flaven
2ad9d69396 Implemented the OQL operator ABOVE (and its variants ABOVE STRICT, NOT ABOVE and NOT ABOVE STRICT) that returns the (indirect) parents of a given node in a hierarchy. It's the opposite to 'BELOW' that returns the (indirect) children.
SVN:trunk[1454]
2011-08-16 08:14:11 +00:00
Denis Flaven
74baca3a7b Enhanced interface for complex SLA computations...
SVN:trunk[1453]
2011-08-15 14:06:03 +00:00
Denis Flaven
2bd8700c90 Implementing Trac #419: provide means for the toolkit to fix synchro data sources
SVN:trunk[1452]
2011-08-15 14:01:51 +00:00
Denis Flaven
51bd6cdf97 #446 continuing: sanitizing parameters...
SVN:trunk[1451]
2011-08-15 13:55:59 +00:00
Denis Flaven
b02021a4ff Still fixing regressions caused by Trac#446: XSS vulnerabilities...
SVN:trunk[1450]
2011-08-12 10:06:33 +00:00
Denis Flaven
96f3350029 Fixed the display of 'Used IP Addresses' (i.e. Network interfaces) in the details of a Subnet object.
SVN:trunk[1449]
2011-08-12 09:19:53 +00:00
Romain Quetiez
e2e4c53b0d Fix after security fix
SVN:trunk[1448]
2011-08-11 16:31:59 +00:00
Denis Flaven
9c6605f7e7 Allow export of the config information for documentation purposes
SVN:trunk[1447]
2011-08-11 12:01:53 +00:00
Denis Flaven
f481652666 Trac #445: output of export.php should not be "paginated" !
Bug fix: the number of items displayed in the "paginated" view should be "min_display_limit", as listed in the drop down-box and not always 10 !

SVN:trunk[1446]
2011-08-11 11:59:55 +00:00
Denis Flaven
212389f43e One more regression due to #446: fixed !
SVN:trunk[1445]
2011-08-11 11:57:44 +00:00
Denis Flaven
f68680ada1 Still working on #446: oops, one parameter missing...
SVN:trunk[1444]
2011-08-11 10:53:37 +00:00
Denis Flaven
6859326646 Fixed Trac#446: XSS vulnerabilities... to be tested !
Also fixed the display/download links on documents that were both doing exactly the same thing !

SVN:trunk[1443]
2011-08-11 10:17:03 +00:00
Romain Quetiez
a129c9814f Readme for 1.2 Beta
SVN:trunk[1441]
2011-08-09 09:37:48 +00:00
Denis Flaven
05ee0caec2 Fixed the "more information" url in the itop-config-mgmt module
SVN:trunk[1440]
2011-08-09 08:55:29 +00:00
Denis Flaven
6fff9d6a20 Make the 'agent_id' visible in the state "new" to allow the creation and assigment of a ticket in one click.
SVN:trunk[1439]
2011-08-09 08:34:14 +00:00
Denis Flaven
d2955557bf Allow $SERVER_NAME$ as a placeholder for the server's name in the application root url. Useful for multiple virtual hosts or test systems using DHCP...
SVN:trunk[1438]
2011-08-09 07:57:11 +00:00
Denis Flaven
aa00cd9ae7 "Shortcut" actions are displayed as buttons on the same line as the usual "Actions" button.
SVN:trunk[1437]
2011-08-09 07:51:08 +00:00
Denis Flaven
aa9d9ed578 New config parameter: buttons_position: top | bottom | both
SVN:trunk[1436]
2011-08-09 07:47:50 +00:00
Romain Quetiez
9bd6fa61c5 SQLBlock - removed Warnings in case of empty data set
SVN:trunk[1435]
2011-08-08 16:02:28 +00:00
Denis Flaven
f16997fb2d Productivity enhancement: apply directly the 'next_action' when creating or modifying an object with a life-cycle !
SVN:trunk[1434]
2011-08-08 15:40:51 +00:00
Romain Quetiez
f4c1cf0818 Fixed typo
SVN:trunk[1433]
2011-08-08 14:24:35 +00:00
Denis Flaven
01dd63f623 Cleanup of the way objects are displayed/edited: DisplayBareProperties is now used for displaying (i.e. read-only) or modifying/creating an object.
SVN:trunk[1432]
2011-08-08 12:52:32 +00:00
Denis Flaven
3393808c7a - Enhancement: can now specify 'order_by' in 'list' templates.
- New 'Shortcut Actions' displayed as buttons next to the 'Actions' popup menu.

SVN:trunk[1431]
2011-08-08 12:35:43 +00:00
Denis Flaven
772c892b15 New option DEL_MOVEUP (move the children up one level) for 'on_target_delete' for HierarchicalKey attributes.
SVN:trunk[1430]
2011-08-07 12:24:45 +00:00
Denis Flaven
435d943f47 Cleanup of the way objects are displayed/edited: DisplayBareProperties is now used for displaying (i.e. read-only) or modifying/creating an object. The means that:
1) the display/edition can be customized by overloading this method
2) the plug-ins's method OnDisplayProperties is now called in edition as well

A new class of template is introduced for building custom object displays: ObjectDetailsTemplate.

SVN:trunk[1429]
2011-08-07 08:12:07 +00:00
Denis Flaven
eab1060f8e Adapted the portal to support enhanced attachments either in 'properties' or 'relations'... this is transparent for the end-user of the portal.
SVN:trunk[1428]
2011-08-07 07:55:16 +00:00
Denis Flaven
cb8774370f Enhancement: new configuration parameter 'position' to enable 'attachments' to be displayed either as a separate tab 'Attachments' on inline in the 'Properties' tab (for example when used with a custom 'DisplayBareProperties'.)
SVN:trunk[1427]
2011-08-07 07:52:39 +00:00
Denis Flaven
23b1d15b64 New attribute 'display_style' for Strings, Enums and ExternalKeys: when the list is short, display it as a set of radio buttons instead of a drop-down list. Possible values: 'radio', 'radio_vertical' and 'radio_horizontal'. ('radio' == 'radio_vertical').
SVN:trunk[1426]
2011-08-06 09:51:06 +00:00
Denis Flaven
61727aca02 New configuration parameter: display_actions_at_top: avoid scrolling to see the buttons when assigning a ticket !
SVN:trunk[1425]
2011-08-05 13:28:21 +00:00
Denis Flaven
8cfebdf723 - New configuration parameter deadline_format to specify how to display Deadlines (date or time difference or a mix of the two)
SVN:trunk[1424]
2011-08-05 13:08:56 +00:00
Denis Flaven
506702c50b Enhancement: added the capability to filter (based on user's defined preferences the list of organizations displayed in the drop-down menu)
SVN:trunk[1423]
2011-08-05 11:45:12 +00:00
Denis Flaven
b9de1df6a8 Release note review
SVN:trunk[1422]
2011-08-03 13:49:27 +00:00
Denis Flaven
a7175007be Preparing for the 1.2-beta release
SVN:trunk[1421]
2011-08-03 10:37:55 +00:00
Denis Flaven
5d8acbb41a New type of trigger: TriggerOnPortalUpdate, called when the end-user updates a ticket from the portal.
SVN:trunk[1420]
2011-08-03 10:36:34 +00:00
Denis Flaven
3ccbeac996 Oops, missing Portuguese (Brazilian) dictionary files...
SVN:trunk[1419]
2011-08-03 09:25:19 +00:00
Denis Flaven
1643ba8e9c Added support for the 'Attachments' plug-in into the portal
SVN:trunk[1418]
2011-08-02 10:36:43 +00:00
Denis Flaven
768dbd8946 New module to easily manage attachments
SVN:trunk[1417]
2011-08-02 10:29:59 +00:00
Denis Flaven
c2d02a2394 Put back wsdl documentation
SVN:trunk[1416]
2011-08-02 08:30:43 +00:00
Denis Flaven
b26f2738f6 German localization enhancement by Stephan Rosenke. Thanks Stephan !
SVN:trunk[1415]
2011-08-02 07:53:39 +00:00
Denis Flaven
781ec7e33a In CLI mode, do not depend on the current directory: the script can be run from anywhere.
SVN:trunk[1414]
2011-08-01 16:13:37 +00:00
Denis Flaven
d09db3a920 Better error message if the configuration file exists but is not readable
SVN:trunk[1413]
2011-08-01 16:12:24 +00:00
Denis Flaven
998a8692cb Use a hierarchical key for the parent/child relationship with groups
SVN:trunk[1412]
2011-08-01 15:53:55 +00:00
Denis Flaven
b83ac447e8 Don't make the case log hidden, since it's not hidden in the portal !
SVN:trunk[1411]
2011-08-01 15:46:23 +00:00
Denis Flaven
6688f1811e Improved error handling when loading linkedset as attributes in one go
SVN:trunk[1410]
2011-08-01 15:08:22 +00:00
Denis Flaven
ec26750b58 Bug fix: when changing the currently selected organization, go back to the initial (Welcome) menu instead of trying to stay on the same menu... which caused troubles (e.g. "New Contact" => assertion failed)
SVN:trunk[1409]
2011-08-01 14:17:43 +00:00
Denis Flaven
0f0abc0501 Added a new web service to create UserRequest tickets (similarly to Incidents tickets). Based on code from Vincenzo Todisco.
SVN:trunk[1408]
2011-08-01 14:07:54 +00:00
Denis Flaven
9ad6f2c994 Draft of the 1.2 readme file...
SVN:trunk[1407]
2011-08-01 13:50:07 +00:00
Denis Flaven
abab47558b Adding Japanese translation kindly provided by Tadeshi Kaneda
SVN:trunk[1406]
2011-08-01 13:34:48 +00:00
Denis Flaven
f3147be8f6 Adding Japanese translation
SVN:trunk[1405]
2011-08-01 13:33:34 +00:00
Denis Flaven
af185b79c8 Bug fix: missing title for the menu 'All Opened Changes'
SVN:trunk[1404]
2011-08-01 12:50:26 +00:00
Denis Flaven
3fc686e403 Bug fix: do not modify the page's address (by changing the final anchor) when clicking on a page in a paginated display. Otherwise this interferes with the tabbed navigation.
SVN:trunk[1403]
2011-08-01 12:37:05 +00:00
Denis Flaven
f5ea073c2b Bug fix: when removing a module (like Incident Management) that contained Triggers to such objects, the remaining triggers must be deleted because they reference a non-existing class.
SVN:trunk[1402]
2011-08-01 11:51:11 +00:00
Denis Flaven
aa6d7578d1 Fixed issues when adding/removing modules during the setup:
- When adding modules: the data model was not refreshed in the cache before attempting to load "structure" (or "sample") data
- When removing a module: remaining (invalid) triggers were still used.

SVN:trunk[1401]
2011-08-01 10:30:22 +00:00
Denis Flaven
05338caa23 Modified misleading/outdated comment in the configuration file.
SVN:trunk[1400]
2011-08-01 10:24:36 +00:00
Denis Flaven
a6ac78d7c1 Fix: Make sure that the flash object respects the z-order otherwise the hierarchy/organization picker appears behind the Flash in Chrome and IE.
SVN:trunk[1399]
2011-07-31 19:38:27 +00:00
Denis Flaven
9bcf78bfd6 Enhancement: the number of items is displayed (statically) in the header of the each "details" tab.
SVN:trunk[1398]
2011-07-31 10:45:03 +00:00
Denis Flaven
9c97df5186 MapContextParam: call the parent just in case...
SVN:trunk[1397]
2011-07-31 09:40:00 +00:00
Denis Flaven
c2a8fd4e09 Enhancement: allow to search on Organization's parent and Location's parent.
SVN:trunk[1396]
2011-07-31 09:38:26 +00:00
Denis Flaven
c8b6ec08e7 Bug fix: properly process field names followed by a star (which simply indicates an important field in the CSV import)
SVN:trunk[1395]
2011-07-31 09:30:55 +00:00
Denis Flaven
4293230416 Don't display an error (assertion failed) if the user selects nothing (i.e -- select one --) in the "CSV template" tab.
SVN:trunk[1394]
2011-07-31 09:12:41 +00:00
Denis Flaven
bfddec242b - Fixed the combination of the "PointingTo" conditions, especially when combining several "BELOW" conditions for the same criteria (used for security and context purposes)
- Make sure that the "security" limitiation provided by GetSelectFilter is applied only once to a given filter to avoid the creation of unneeded complex queries

SVN:trunk[1393]
2011-07-31 09:01:45 +00:00
Denis Flaven
ee3652acad Added a useful function for debugging: DebugBacktrace which provides a "light" version of PHP's built-in debug_backtrace().
SVN:trunk[1392]
2011-07-31 08:57:04 +00:00
Denis Flaven
5baa213e6a Better initialization of objects from the "Context" values:
- map the parameters (for example for Provider Contract)
- set the default values when creating a "secondary" object via the (+) button

SVN:trunk[1391]
2011-07-31 08:54:59 +00:00
Denis Flaven
ca8ea8dd02 Fixed the parsing of OQL error messages
SVN:trunk[1390]
2011-07-30 17:25:49 +00:00
Denis Flaven
308d2626a9 Added test cases for the new BELOW operator
SVN:trunk[1389]
2011-07-30 17:23:39 +00:00
Denis Flaven
8cab8dd7b7 Filter audit results using the hierarchies
SVN:trunk[1388]
2011-07-29 10:29:28 +00:00
Denis Flaven
0a5e37c592 Oops: Make sure that the default add-on for SLA computation is enabled by default
SVN:trunk[1387]
2011-07-29 10:27:37 +00:00
Denis Flaven
72326435ce Make sure that the default add-on for SLA computation is enabled by default
SVN:trunk[1386]
2011-07-29 10:14:44 +00:00
Denis Flaven
ca9f17d6e1 Fixed a bug when using a hierarchy of locations, since locatins genreally depends on the object's organization
SVN:trunk[1385]
2011-07-29 10:09:14 +00:00
Denis Flaven
ff89c4d424 CAS authentication improvements:
- Check if the user is part of a group (memberOf)
- Fixed the use of the 'redirect_service' when logging-out

SVN:trunk[1384]
2011-07-28 17:39:49 +00:00
Denis Flaven
fa3b7ce545 Thumbs.db has nothing to do in SVN
SVN:trunk[1383]
2011-07-28 15:21:33 +00:00
Denis Flaven
c85feb7cea - Use the new HierarchicalKeys for Organization and Locations and use the hierarchy of organization for the profiles/user rights.
SVN:trunk[1382]
2011-07-28 15:14:49 +00:00
Denis Flaven
d50f812694 Fix: broken context usage when no context (neither org nor menu) at all
SVN:trunk[1381]
2011-07-28 15:12:16 +00:00
Denis Flaven
c7e27a836a Make sure that the root URL ends with a slash
SVN:trunk[1380]
2011-07-28 13:45:51 +00:00
Denis Flaven
c8a1380bef - Fixed the reporting about the previous version
SVN:trunk[1379]
2011-07-28 13:19:58 +00:00
Denis Flaven
7732c9bc6a Exclude build.bash from the build
SVN:trunk[1378]
2011-07-28 11:26:58 +00:00
Denis Flaven
82c57972c6 Fixing bug #404: context lost when doing certain actions. What was fixed:
- Run Query
- Display Data Model Schema
- Drill-down in charts (OQL & SQL)
- Paginated lists (actually a regression)

What remains:
- Global search...
- Drill-down in Flash "impacts / depends on"

SVN:trunk[1377]
2011-07-27 16:39:17 +00:00
Denis Flaven
0cc0c820a5 Fixed Trac #410: added translation for ticket status (and other enum fields) when displaying the History tab.
SVN:trunk[1376]
2011-07-27 13:06:45 +00:00
Denis Flaven
9150a569a7 Make sure that the dependent fields are initialized in the proper order when applying a stimulus on a n object.
SVN:trunk[1375]
2011-07-27 12:55:16 +00:00
Denis Flaven
3c76b90a48 Added an option to the paginated display: display all elements on one page.
SVN:trunk[1374]
2011-07-27 10:24:06 +00:00
Denis Flaven
5f2a5d9cfa - Fixed Trac #433: triggers creation was incorrect when iTop was installed with a 'prefix' for the DB tables.
- Fixed a bug due to the previous renaming of UpdateObject...

SVN:trunk[1372]
2011-07-26 16:45:02 +00:00
Denis Flaven
4e40702809 Fixed the construction of the menus' URLs:
- The context was not passed all the time (due to typos)
- When the context was empty an extra ampersand was added at the end of the URL, which caused a malformed URL for the 'tab selector' when modifying an object. (i.e the object always opened on the 'Properties' tab instead of the current tab).

SVN:trunk[1371]
2011-07-26 16:22:24 +00:00
Denis Flaven
a2b8813628 - Renamed the method 'UpdateObject' into 'UpdateObjectFromPostedForm' to avoid misunderstandings.
- Fixed (again !) Trac #427: unable to empty a linkset when editing an object.

SVN:trunk[1370]
2011-07-26 16:18:19 +00:00
Denis Flaven
751ab5a4b4 Implemented enhancement #130: keywords to narrow the scope of the global search
SVN:trunk[1369]
2011-07-26 14:18:33 +00:00
Denis Flaven
b6bcade4c0 Better (?) handling of deletion issues during the synchro...
SVN:trunk[1368]
2011-07-26 13:27:03 +00:00
Denis Flaven
d6be6ca92c Fix display issues with the portal's top menu bar.
SVN:trunk[1367]
2011-07-26 13:25:37 +00:00
Denis Flaven
9024e0b2db Use absolute URLs as much as possible to be independent from the page being executed...
SVN:trunk[1366]
2011-07-26 13:24:28 +00:00
Denis Flaven
ecca1aa070 Use absolute URLs as much as possible to be independent from the page being executed...
SVN:trunk[1365]
2011-07-26 13:22:45 +00:00
Denis Flaven
3fde682653 Make sure that the AJax calls use a full/absolute path to the page they call so that they can be embedded anywhere inside the application (i.e. in plug-ins supplied pages as well as 'regular' app pages).
SVN:trunk[1364]
2011-07-26 12:21:53 +00:00
Denis Flaven
aee8a98d84 Implemented two new options for CAS:
- logout_redirect_service
- memberOf

SVN:trunk[1363]
2011-07-26 09:43:21 +00:00
Denis Flaven
3ab670e8c2 Implemented two new options for CAS:
- logout_redirect_service
- memberOf

SVN:trunk[1362]
2011-07-26 09:42:46 +00:00
Denis Flaven
1fc7ce3b81 - Allow search forms to be open by default
- Don't make textarea resizable

SVN:trunk[1361]
2011-07-26 09:41:27 +00:00
Denis Flaven
e8c44951a1 Added two new options for CAS:
- logout_redirect_service
- memberOf

SVN:trunk[1360]
2011-07-26 09:39:45 +00:00
Denis Flaven
c11ca679d4 - Make sure that resulsts tables are always sortable.
SVN:trunk[1359]
2011-07-25 14:32:11 +00:00
Denis Flaven
46781c349f - Setup tested under IE8
- Added migration code, during the setup, for the hierarchical keys

SVN:trunk[1358]
2011-07-25 14:14:05 +00:00
Denis Flaven
189b802452 - Always display the number of elements (and the number of elements selected) when displaying a list.
- Nicer display of paginated lists

SVN:trunk[1357]
2011-07-25 12:25:50 +00:00
Denis Flaven
6b7687c80b - Nicer display of paginated lists
SVN:trunk[1356]
2011-07-25 12:24:23 +00:00
Denis Flaven
906abd5fe6 - Always display the number of elements (and the number of elements selected) when displaying a list.
- Nicer display of paginated lists

SVN:trunk[1355]
2011-07-25 12:23:40 +00:00
Denis Flaven
0c539aada9 Always display the number of elements (and the number of elements selected) when displaying a list.
SVN:trunk[1354]
2011-07-25 12:22:49 +00:00
Denis Flaven
a3611f7f63 Added support of hierarchy in the manipulation of external keys:
- widget

SVN:trunk[1353]
2011-07-22 12:21:21 +00:00
Denis Flaven
d62d6e14c8 Added support of hierarchy in the manipulation of external keys:
- widget

SVN:trunk[1352]
2011-07-22 12:15:49 +00:00
Denis Flaven
4cd4d91225 Added support of hierarchy in the manipulation of external keys:
- widget
- search criteria

SVN:trunk[1351]
2011-07-22 12:15:25 +00:00
Denis Flaven
5257287421 Added support of hierarchy in the manipulation of external keys:
- widget
- search criteria

SVN:trunk[1350]
2011-07-22 12:14:59 +00:00
Denis Flaven
7e60a9fce7 Implementation of a new type of ExternalKey attribute: HierarchicalKey. This attribute implements the "nested set" model and is used to define a hierarchy of an arbitrary depth of objects of the same class. With this new feature it is possible to retrieve in one OQL query (and in one sql query as well) all the children of a given organization.
I'm still keeping (commented out) some of the traces helpful for debugging the construction of the OQL queries.

SVN:trunk[1349]
2011-07-22 12:07:09 +00:00
Denis Flaven
b80cc36fb5 TO BE TESTED: New step in the wizard confirmation of the URL to be used for accessing the application.
SVN:trunk[1348]
2011-07-22 11:55:41 +00:00
Denis Flaven
0e75824247 For the setup: try to make the URL detection work even if the actual PHP file is not part of the URL (i.e when index.php is implicitely added when browsing a folder)
SVN:trunk[1347]
2011-07-22 11:53:02 +00:00
Denis Flaven
7470c8e72e Use the SLAComputation utility to allow plug-ins to implement more complex SLA computation schemes.
SVN:trunk[1346]
2011-07-18 15:08:44 +00:00
Denis Flaven
a04f0ee816 Helper module to plug complex SLA computation schemes. This basic modules performs the simplest computation corresponding to a 24x7 (no holidays) model.
SVN:trunk[1345]
2011-07-18 15:00:50 +00:00
Denis Flaven
d37244e6e2 - Search forms are now expandable/collapsible in the portal, like in the main UI
SVN:trunk[1344]
2011-07-12 11:07:56 +00:00
Denis Flaven
82c4f43c4f Manage properly default parameters for linksets
SVN:trunk[1343]
2011-07-12 11:07:04 +00:00
Romain Quetiez
1c2c244273 Veepee - fixed issue
SVN:trunk[1342]
2011-07-08 12:34:07 +00:00
Romain Quetiez
a991a84a8e New feature: online help on search inputs (date format and operators)
SVN:trunk[1341]
2011-07-08 11:40:57 +00:00
Romain Quetiez
532912984d Preset the object creation form with values (scalars or lists) by the mean of GET arguments. E.g. .../UI.php&operation=new&class=Team&default[org_id]=161&default[member_list][-1234][id]=&default[member_list][-1234][role]=manager
SVN:trunk[1340]
2011-07-07 15:45:35 +00:00
Romain Quetiez
265ef1e1ce Typo in french dictionary
SVN:trunk[1339]
2011-07-07 09:34:40 +00:00
Denis Flaven
70ad369ad6 - removed some debug traces !!
SVN:trunk[1337]
2011-07-06 17:12:18 +00:00
Denis Flaven
723685b4cb - Fixed Trac #429: web browser can crash when a text field contains several times the same URL !!!
SVN:trunk[1336]
2011-07-06 17:09:36 +00:00
Denis Flaven
061711afc8 Added support for OnFormCancel
SVN:trunk[1335]
2011-07-06 16:29:40 +00:00
Denis Flaven
8b6a8f02a4 - Bug fix: n:n wizard, context was lost when searching for objects of a derived class to be added.
- Bug fix: 'Apply stimulus multiple" was saying: "Please select at least one object"

SVN:trunk[1334]
2011-07-06 16:23:54 +00:00
Denis Flaven
893ec0f097 - Allow plug-ins to record specific changes in the object's history
SVN:trunk[1333]
2011-07-06 16:21:19 +00:00
Denis Flaven
7c9d4c76a9 Protect against a multiple stimulus on a set based on an abstract class.
SVN:trunk[1332]
2011-07-05 14:07:02 +00:00
Denis Flaven
52fb63c0ee Handle the OnBeforeUnload events to call OnFormCancel handlers when needed so that the plug-ins have a chance to perform some cleanup.
SVN:trunk[1328]
2011-07-05 08:46:31 +00:00
Denis Flaven
8a547bf104 Internal regressions fixes !!!
SVN:trunk[1327]
2011-07-04 16:36:07 +00:00
Denis Flaven
0019ab216a Fixed a typo: utils::ReadMultipleSelection
SVN:trunk[1326]
2011-07-04 15:44:07 +00:00
Denis Flaven
8d52cd3a58 Fixed a typo: utils::ReadMultipleSelection
SVN:trunk[1325]
2011-07-04 15:02:36 +00:00
Romain Quetiez
c7fbe56423 PPortal web page improvements: protected update feature (class/attcodes explicitely restricted)
SVN:trunk[1324]
2011-07-04 09:54:58 +00:00
Denis Flaven
5ff5ea71de Fixed Trac#424: error when updating the Data Synchro statistics
SVN:trunk[1323]
2011-07-04 08:29:16 +00:00
Denis Flaven
6297526da6 Fixed Trac #427: unable to remove all items from a linkset when editing an object.
SVN:trunk[1322]
2011-07-04 08:21:19 +00:00
Romain Quetiez
56ac89f6a6 Portal web page improvements: wizard buttons and welcome message
SVN:trunk[1321]
2011-07-04 07:26:16 +00:00
Romain Quetiez
aa46ab1a67 Portal users: limit their access depending on their organization!!!!
SVN:trunk[1320]
2011-07-01 15:09:29 +00:00
Romain Quetiez
645b02b2d1 #415 Could not limit user on some organization (symptom: wrong queries... org_id does not exist...)
SVN:trunk[1319]
2011-07-01 15:08:38 +00:00
Romain Quetiez
b2c5f183ec Portal web page improvements: integrating the attachments
SVN:trunk[1318]
2011-07-01 07:48:09 +00:00
Romain Quetiez
c6b60731d8 Internal cosmetic on duration attribute
SVN:trunk[1317]
2011-07-01 07:43:53 +00:00
Denis Flaven
fd2f40f070 - Protect against invalid attributes...
- Use the new absolute URL mechanism
- Added custom sort and Zebra tables for non paginated lists

SVN:trunk[1316]
2011-06-30 17:08:59 +00:00
Denis Flaven
9fef41404f - Added drill-down capability for OQL charts (pie and bars)
- fixed asbolute root path for drill down links

SVN:trunk[1315]
2011-06-30 16:04:18 +00:00
Denis Flaven
017aec3ae8 Added drill-down capability to the SQL blocks
SVN:trunk[1314]
2011-06-30 15:34:56 +00:00
Denis Flaven
2ae4aca687 Added support of 'drill-down' (i.e on_click) on bar charts
SVN:trunk[1313]
2011-06-30 14:38:13 +00:00
Denis Flaven
692fd91801 Finalizing the pagination: a few bug fixes and some cleanup...
SVN:trunk[1312]
2011-06-29 15:09:10 +00:00
Denis Flaven
12ec9c3ba1 Finalizing the pagination: a few bug fixes and some cleanup...
SVN:trunk[1311]
2011-06-29 15:08:36 +00:00
Romain Quetiez
ac5e40f4ed Factorized some code into PortalWebPage (still needs to be used in the std portal implementation)
SVN:trunk[1310]
2011-06-29 09:10:07 +00:00
Denis Flaven
f44afb8ee6 New implementation for displaying long lists: pagination
SVN:trunk[1309]
2011-06-29 08:57:39 +00:00
Denis Flaven
9e01277e49 New implementation for displaying long lists: pagination
SVN:trunk[1308]
2011-06-29 08:56:27 +00:00
Denis Flaven
73dc5eb922 New implementation for displaying long lists: pagination
SVN:trunk[1307]
2011-06-29 08:53:26 +00:00
Romain Quetiez
a5091d9af0 Fixed regression: magic_quote_runtime could be deprecated with recent versions of PHP (setup)
SVN:trunk[1306]
2011-06-28 15:13:10 +00:00
Romain Quetiez
a573d3cfa0 #423 Finalized
SVN:trunk[1305]
2011-06-28 14:28:01 +00:00
Romain Quetiez
c4b7497770 #423 Fixed issues with application root URL = f(mode CLI, modules, web server techno, etc.)
SVN:trunk[1304]
2011-06-28 10:30:03 +00:00
Romain Quetiez
1964658584 Fixed an issue in the internal error reporting (user rights not sufficient to update an object)
SVN:trunk[1303]
2011-06-28 10:23:41 +00:00
Romain Quetiez
077b7be2a4 Fixed regressions with DBObjectSet, impacting the new paginated lists and their menus
SVN:trunk[1302]
2011-06-28 09:32:13 +00:00
Denis Flaven
22c6df1a7a Fixed Trac #422 (detection of magic_quotes_runtime)
SVN:trunk[1301]
2011-06-24 14:46:21 +00:00
Romain Quetiez
54d5497f0a Fixed issues with pagination + core limitations in the use of Object Sets (wrong filter when adding objects to a set)
SVN:trunk[1300]
2011-06-24 09:53:45 +00:00
Romain Quetiez
9d2a8d0a67 Fixed regression with the display of lists based on class that is not a leaf (aka standalone) class
SVN:trunk[1299]
2011-06-23 12:32:15 +00:00
Denis Flaven
20024729ec New implementation for displaying long lists: pagination
SVN:trunk[1298]
2011-06-23 11:01:33 +00:00
Denis Flaven
43315f50ea New implementation for displaying long lists: pagination
SVN:trunk[1297]
2011-06-23 11:01:03 +00:00
Denis Flaven
46edbbbd2b New implementation for displaying long lists: pagination
SVN:trunk[1296]
2011-06-23 10:47:05 +00:00
Denis Flaven
dc3713f0ea New implementation for displaying long lists: pagination
SVN:trunk[1295]
2011-06-23 10:46:10 +00:00
Denis Flaven
01a4a04364 New implementation for displaying long lists: pagination
SVN:trunk[1294]
2011-06-23 10:43:41 +00:00
Romain Quetiez
7384191fb6 Fixed issues in ExtKey Widget
SVN:trunk[1293]
2011-06-22 15:26:36 +00:00
Romain Quetiez
b8c930016f Cosmetic
SVN:trunk[1292]
2011-06-22 08:16:59 +00:00
Romain Quetiez
5d37201391 Fixed issue in the computation of the application absolute path (Windows)
SVN:trunk[1291]
2011-06-22 08:15:30 +00:00
Romain Quetiez
2c8963784c #420 - Data synchro logs: increased the size of the attribute last_error
SVN:trunk[1290]
2011-06-21 15:01:56 +00:00
Romain Quetiez
c42fa13b92 Templates: new type of block = sqlblock, allows for displaying tables/charts based in SQL queries (much quicker for Group By operations)
SVN:trunk[1289]
2011-06-21 13:12:02 +00:00
Romain Quetiez
c02d62044c Dashboard templates: fixed issue with asynchronous mode (still some cosmetic issues) with itopblock and the table format
SVN:trunk[1288]
2011-06-21 13:10:11 +00:00
Denis Flaven
7bcb4ed3b2 New implementation of GetAbsoluteUrlRootPath that no longer requires any parameter.
SVN:trunk[1287]
2011-06-20 14:18:24 +00:00
Denis Flaven
834e9c48e1 Added a display value for the null (i.e empty) value of a combo/autocomplete.
SVN:trunk[1286]
2011-06-20 14:17:24 +00:00
Denis Flaven
ddfc84db6a - New implementation of the UIExtKeyWidget that is no longer limited to editing an attribute of an object
- When needed the drop-down list of organizations is replaced by an autocomplete

SVN:trunk[1285]
2011-06-15 17:06:46 +00:00
Denis Flaven
b4a7d0b86c - New implementation of the UIExtKeyWidget that is no longer limited to editing an attribute of an object
- When needed the drop-down list of organizations is replaced by an autocomplete

SVN:trunk[1284]
2011-06-15 17:06:26 +00:00
Denis Flaven
02cafd0e0b - New implementation of the UIExtKeyWidget that is no longer limited to editing an attribute of an object
- When needed the drop-down list of organizations is replaced by an autocomplete

SVN:trunk[1283]
2011-06-15 17:05:58 +00:00
Denis Flaven
f5891a531e New icon to trigger the filtering on organizations
SVN:trunk[1282]
2011-06-15 17:01:44 +00:00
Romain Quetiez
4681b03646 #122 Optimized the load of data set (do not load unused columns, was provoking the swapping of MySQL tmp memory tables)
SVN:trunk[1281]
2011-06-15 11:59:25 +00:00
Denis Flaven
733953ac99 CAS integration: added support of JA-SIG Central Authentication Service (CAS) with log-off support, using phpCAS API.
SVN:trunk[1280]
2011-06-10 14:51:17 +00:00
Romain Quetiez
4837984ac3 Optimization: autocomplete = do not load every object when determining the list of matches
SVN:trunk[1279]
2011-06-10 09:02:42 +00:00
Romain Quetiez
4efd93defe Optimization: cache the Count of items in an object set
SVN:trunk[1278]
2011-06-08 14:42:51 +00:00
Romain Quetiez
35f7d143b8 Optimization: displaying 1000 object would take real long if many organizations are loaded into iTop (querying all the orgs for each object)
SVN:trunk[1277]
2011-06-08 14:31:22 +00:00
Denis Flaven
d48fd1a12e First prototype (not yet tested) of CAS integration.
SVN:trunk[1276]
2011-06-08 13:34:43 +00:00
Romain Quetiez
a0900cd732 Optimization: do not load the full set of items when it comes to displaying an autocomplete!
SVN:trunk[1275]
2011-06-08 13:30:56 +00:00
Romain Quetiez
64b4922499 Fixed issue in the data model consistency check
SVN:trunk[1274]
2011-05-24 10:26:16 +00:00
Romain Quetiez
4574126428 #408 Case log not working with PHP < 5.3 - the fix preserves the compatibility with installed version (but the dates are lost)
SVN:trunk[1273]
2011-05-23 14:56:09 +00:00
Romain Quetiez
9704dd8e35 Improved import.php and synchro_import.php: added 'date_format' (example: %d/%m/%Y %H:%i:%s)
SVN:trunk[1272]
2011-05-23 13:42:33 +00:00
Romain Quetiez
f8d794bc93 Reduces the annoyance of bug #408 (dates not visible in the case log if PHP < 5.3)
SVN:trunk[1271]
2011-05-20 13:42:57 +00:00
Romain Quetiez
5c7c7b98ee Dehardcoded against 'ticket_log', allowing for several case log attributes
SVN:trunk[1270]
2011-05-19 14:38:46 +00:00
Romain Quetiez
3826c1f886 #405 Could not install without the module 'User Request Management'
SVN:trunk[1269]
2011-05-13 16:00:21 +00:00
Romain Quetiez
58844b04ef #403 Partial installation not working (error on ticket form)
SVN:trunk[1268]
2011-05-13 15:09:55 +00:00
Romain Quetiez
178f7f3426 Typo in dictionary
SVN:trunk[1267]
2011-05-06 09:05:22 +00:00
Denis Flaven
8b0214eeee Preparing for the 1.1 release.
SVN:trunk[1265]
2011-05-04 08:56:59 +00:00
Denis Flaven
c6454c5a8e Completed the Portuguese/Brazilian translation, thanks to Marco Tulio !
SVN:trunk[1264]
2011-05-02 15:36:32 +00:00
Denis Flaven
6fd3bdbef4 Final touch to the 1.1 build: readme "touch" and "doc" review.
SVN:trunk[1263]
2011-05-02 13:18:12 +00:00
Denis Flaven
4a12c531e6 Last finishing touch to the Italian localization. Now 100% complete !
SVN:trunk[1262]
2011-05-02 13:06:37 +00:00
Denis Flaven
df086c8ce2 - Better display of the "Resolved Request" form, where the user can submit their satisfaction & feedbacks. Now aligned with the display of the ticket's details.
SVN:trunk[1261]
2011-05-02 12:58:32 +00:00
Romain Quetiez
d66e413289 Typo in french dictionary
SVN:trunk[1260]
2011-05-02 12:37:14 +00:00
Romain Quetiez
938d383efd #379 GetAbsoluteUrlRoot becomes GetAbsoluteUrlAppRoot which will simplify the development of plugins, fixed a cosmetic issue in export.php (format: html + iTop not installed in the url root path)
SVN:trunk[1259]
2011-05-02 09:34:45 +00:00
Romain Quetiez
cc35e41028 Ooooops -removed debugging traces
SVN:trunk[1258]
2011-05-02 08:48:46 +00:00
Denis Flaven
0771fd0636 Completion of the Italian localization !
SVN:trunk[1257]
2011-04-29 14:26:17 +00:00
Denis Flaven
e4fa7ba983 Properly manage carriage returns/line feeds in CaseLog records.
SVN:trunk[1256]
2011-04-29 13:57:46 +00:00
Denis Flaven
109e8f6157 Undoing previous commit - keep the old icon, shouldn't have been changed.
SVN:trunk[1255]
2011-04-29 13:53:37 +00:00
Romain Quetiez
99bce469a1 CSV import: regression due to a recent enhancement (labels) and the fact that some labels are redundant (e.g. "Location" used both for Server/location_id and Server/location_name
SVN:trunk[1254]
2011-04-29 12:30:56 +00:00
Denis Flaven
e439797767 Fixed Character encoding issues in the Hungarian translation.
SVN:trunk[1253]
2011-04-29 09:48:56 +00:00
Denis Flaven
7f17acf553 Added Hungarian translation (and fixed the default dictionaries for Italian as well).
SVN:trunk[1252]
2011-04-28 17:23:45 +00:00
Denis Flaven
5e64834b06 Fixed Trac #301: don't force users back into the portal if they are not "portal" users.
SVN:trunk[1251]
2011-04-28 15:43:44 +00:00
Romain Quetiez
79fbec3675 Readme updated with latest fixes
SVN:trunk[1250]
2011-04-28 15:41:46 +00:00
Denis Flaven
f4e796f607 Implemented Trac #347: Allow portal users to update their tickets by adding a comment which gets appended to the log.
SVN:trunk[1249]
2011-04-28 15:31:22 +00:00
Romain Quetiez
0d710d0464 #355 (continuation of the fix) import.php to support localized names in the specification of reconciliation keys, and allowing to specify an external key though it is given as an external field in the input columns
SVN:trunk[1248]
2011-04-28 14:02:01 +00:00
Romain Quetiez
40701f3f36 Added helper tools to ease the setup of cron.php
SVN:trunk[1247]
2011-04-28 12:02:44 +00:00
Romain Quetiez
fcabb8fc43 CRON default duration set to 10 minutes
SVN:trunk[1246]
2011-04-28 08:47:44 +00:00
Romain Quetiez
4c64419f19 Finalized the doc and readme for release 1.1
SVN:trunk[1245]
2011-04-28 08:44:46 +00:00
Romain Quetiez
c8c388dac5 Using iTop in mode CLI: let PHP display the fatal error "unknown function mysql_connect:
SVN:trunk[1244]
2011-04-28 07:50:22 +00:00
Romain Quetiez
374858ef73 Fixed bug: Web services in CLI mode failing with an error when attempting to include APPROOT
SVN:trunk[1243]
2011-04-28 07:28:40 +00:00
Romain Quetiez
d45149a327 Readme for 1.1 RC (draft)
SVN:trunk[1242]
2011-04-27 08:39:13 +00:00
Denis Flaven
0ea9968797 Fixed Trac #391: Support Agent profile was wrong (no rights to modify UserRequest tickets).
SVN:trunk[1241]
2011-04-27 08:06:13 +00:00
Denis Flaven
b68ac3916f Aligned the display of the case log (and properties) of a ticket in the User Portal to what is done in the normal UI: better look (multi-column, fieldsets, wider case log at the bottom).
SVN:trunk[1240]
2011-04-26 16:49:28 +00:00
Romain Quetiez
e5c46340d1 Plugin API: added OnIsModified()
SVN:trunk[1239]
2011-04-26 16:03:01 +00:00
Romain Quetiez
1e6887062f Data synchro: added the support of link sets (to import user accounts)
SVN:trunk[1238]
2011-04-26 15:29:16 +00:00
Romain Quetiez
fc0f6b636e Data sync: fixed issue with the check while creating a new data source (depending on the target class)
SVN:trunk[1237]
2011-04-26 15:24:13 +00:00
Denis Flaven
bcb1864963 Fixed Trac#385: clearing an autocomplete foeld (for instance in a search form) now has an immediate effect.
SVN:trunk[1236]
2011-04-26 13:41:08 +00:00
Denis Flaven
3a1932b742 Typo: double PHP closing tag !
SVN:trunk[1235]
2011-04-26 13:38:56 +00:00
Denis Flaven
438f7f19c0 Italian localization
SVN:trunk[1234]
2011-04-26 13:37:58 +00:00
Denis Flaven
15b8b18b90 Adding Italian localization, thanks to Marialaura Colantoni
SVN:trunk[1233]
2011-04-22 15:59:31 +00:00
Denis Flaven
b9f467f08f Dictionary files that follow the naming convention <Lang>.dict.<ModuleName>.php are now loaded automatically without the need to specify them explicitely in the module definition file.
SVN:trunk[1232]
2011-04-22 15:53:21 +00:00
Denis Flaven
9f779b8dfe English dictionary cleanup/completion.
SVN:trunk[1231]
2011-04-22 15:51:23 +00:00
Denis Flaven
8ce3c48446 New option group_by_expr for "group_by' display blocks (to be used in templates) to specify a PHP expression to use for the group by. This allows to build dashboards where dates are grouped by the day of the month, for example.
SVN:trunk[1230]
2011-04-22 15:49:01 +00:00
Denis Flaven
f84d91e482 Removed the 'bgiframe' javascript , which was designed for fixing IE6 issues only and causes troubles with IE9.
SVN:trunk[1229]
2011-04-22 15:45:19 +00:00
Denis Flaven
c6493f6cdc Dictionary files that follow the naming convention <Lang>.dict.<ModuleName>.php are now loaded automatically without the need to specify them explicitely in the module definition file.
SVN:trunk[1228]
2011-04-22 15:44:50 +00:00
Romain Quetiez
fb87911677 #378 Data Synchro - leave the replica in state 'synchronized' if failing to update (update then delete)
SVN:trunk[1227]
2011-04-22 14:52:33 +00:00
Romain Quetiez
60b2162d84 Data synchro: added notifications in case of error + fixed a bug in the error reporting (reconciliation on null values, last error was not recorded)
SVN:trunk[1226]
2011-04-22 13:54:16 +00:00
Denis Flaven
e42b0513a0 Removed the 'bgiframe' javascript , which was designed for fixing IE6 issues only and causes troubles with IE9.
SVN:trunk[1225]
2011-04-22 13:30:41 +00:00
Romain Quetiez
f92a7df522 Data synchro: added "contact to notify in case of error"
SVN:trunk[1224]
2011-04-21 09:30:30 +00:00
Romain Quetiez
b7bd1a5943 Data synchro: if the object is deleted from within iTop, do cleanup sync table and replica as well
SVN:trunk[1223]
2011-04-21 09:04:34 +00:00
Denis Flaven
69f21b9b79 - English dictionary completion for 1.1 !
SVN:trunk[1222]
2011-04-20 16:11:47 +00:00
Romain Quetiez
6614a90e38 Wiki formatting: automatic detection of urls
SVN:trunk[1221]
2011-04-20 11:47:21 +00:00
Romain Quetiez
88a29fd8d1 #370 standard argument for CLI/REST services: param_file
SVN:trunk[1220]
2011-04-19 15:48:39 +00:00
Denis Flaven
7e2982b848 Added methods to trace the completion of the localization.
SVN:trunk[1219]
2011-04-19 13:22:18 +00:00
Denis Flaven
ed5d59153b Update/cleanup to the French dictionary.
SVN:trunk[1218]
2011-04-19 13:21:01 +00:00
Romain Quetiez
ab3fd7f1b4 Internal: keep track of class declaration source files
SVN:trunk[1217]
2011-04-19 12:22:32 +00:00
Denis Flaven
6e685feb9f Fixed the creation of the "Portal" profile that now behaves like a standard profile and therefore requires the proper rights.
SVN:trunk[1216]
2011-04-13 13:11:51 +00:00
Denis Flaven
d8c5f26aed Fix for IE8: On IE <button type="submit"> does not submit the form if an onClick action is specified !
SVN:trunk[1215]
2011-04-13 09:53:59 +00:00
Romain Quetiez
ada0b310ae cron.php - Fixed error message
SVN:trunk[1214]
2011-04-13 09:16:37 +00:00
Denis Flaven
1f43ba3654 Oops: missing file in the commit.
SVN:trunk[1213]
2011-04-13 09:16:07 +00:00
Denis Flaven
cb1628c759 Documentation updated for the 1.1-beta release. Still to be finalized for 1.1-RC.
SVN:trunk[1212]
2011-04-12 13:09:46 +00:00
Romain Quetiez
605edc261d Readme file ok for the Beta
SVN:trunk[1211]
2011-04-12 13:04:20 +00:00
Denis Flaven
46e7bbe2c8 Bug fix: prevent (infinite) recursion when building search form with external keys, that point to search form with external keys, etc...
Now support nested search dialogs properly...

SVN:trunk[1210]
2011-04-12 09:37:52 +00:00
Romain Quetiez
a6ac44204c Readme for 1.1 beta (draft)
SVN:trunk[1209]
2011-04-12 08:51:10 +00:00
Denis Flaven
af63233fac Styles fix for IE8.
SVN:trunk[1208]
2011-04-11 16:18:20 +00:00
Romain Quetiez
b1b913d891 Fixed mix btw French and English dictionaries (regression)
SVN:trunk[1207]
2011-04-11 16:18:14 +00:00
Denis Flaven
be5bbdf26c IE8 bug: one comma too many !
SVN:trunk[1206]
2011-04-11 16:17:25 +00:00
Denis Flaven
b03e9a969c Relative path to the setup's documentation.
SVN:trunk[1205]
2011-04-11 12:35:48 +00:00
Denis Flaven
c56c662be7 French translation cleanup: removed the doubled backslahes \\
SVN:trunk[1204]
2011-04-11 12:13:20 +00:00
Denis Flaven
6d34c2aa93 - Partial bug fix: enhancement to support extkey widgets (autocomplete) in nested search forms... still not completely fixed, bug showing some progress.
SVN:trunk[1203]
2011-04-11 12:11:57 +00:00
Denis Flaven
af20723c8c Fix the display width of case logs. Make sure that the field wraps even in case of very long strings inside the field.
SVN:trunk[1202]
2011-04-11 11:54:15 +00:00
Denis Flaven
35f09c3091 Don't use removed a field !
SVN:trunk[1201]
2011-04-11 10:27:12 +00:00
Denis Flaven
5f04a54df3 Profiles adjustements: make some links delete-able by Service Mgrs and Problem Mgrs.
SVN:trunk[1200]
2011-04-11 09:20:57 +00:00
Denis Flaven
19bbde6144 - Cleanup of the dictionary usage.
- Improvements to the French translation.

SVN:trunk[1199]
2011-04-11 09:11:00 +00:00
Denis Flaven
6fe81320c0 - English dictionary completion.
SVN:trunk[1198]
2011-04-11 08:39:18 +00:00
Erwan Taloc
d1c808b2c3 Update change Mgmt Module to display properly fields
Update French dictionary for Problem Management

SVN:trunk[1197]
2011-04-08 13:02:09 +00:00
Erwan Taloc
e3697c37f3 Mise à jour DEL MANUAL for SoftwareInstances
SVN:trunk[1196]
2011-04-08 12:42:18 +00:00
Denis Flaven
a9c6d81130 - Dictionary entries (partial) for the SynchroDataSource objects
SVN:trunk[1195]
2011-04-08 12:26:05 +00:00
Romain Quetiez
8ff40fb4b8 Deletion: entirely reviewed to take into account the objects being synchronized by an external data source, or the plugins constraints.
SVN:trunk[1194]
2011-04-08 11:29:25 +00:00
Denis Flaven
037d6cc4ba - Special handling (using some custom code - temporary solution) of the 'ticket_log' attribute: the attribute is displayed at the bottom of the "Properties" page and takes the whole width of the page.
SVN:trunk[1193]
2011-04-08 10:22:18 +00:00
Denis Flaven
4b1726c1ca Proper display of the menu !
SVN:trunk[1192]
2011-04-08 10:09:52 +00:00
Erwan Taloc
0fac58248e Update Display for tickets.
Add naming convention for Person and Database Instances

SVN:trunk[1191]
2011-04-07 19:09:42 +00:00
Denis Flaven
3a486f8edd - Adjusted the default ITIL profiles definitions
SVN:trunk[1190]
2011-04-07 16:12:07 +00:00
Denis Flaven
4fefaa5658 Make sure that we initialize the list of modules with just the default config and not the previous config. Setup now supports removing modules (even if the actual data are NOT removed from the database, yet).
SVN:trunk[1189]
2011-04-07 08:22:57 +00:00
Denis Flaven
65ef621e6f - Bug fix: Bulk modify was failing on a list of tickets in different states.
SVN:trunk[1188]
2011-04-07 07:47:28 +00:00
Denis Flaven
1a818f309d - Revised styles for a nicer/cleaner display of the details and forms.
SVN:trunk[1187]
2011-04-07 07:44:09 +00:00
Denis Flaven
1a74fe1ec3 Bug fix: when doing a bulk modify (or bulk apply stimulus) the external keys that were read-only in the edition form were displayed as "ClassName #id" instead of using their friendly name. This is now fixed, but requires a load of the target object.
SVN:trunk[1186]
2011-04-06 19:13:08 +00:00
Denis Flaven
089a9fcf4a - Make sure that the data (smaples and structure) from hidden modules are loaded as well. (Symptom: sample EmailNotifications were not loaded)
- Make sure that the "synchrodatasource" file gets loaded as part of the "standard" app modules, even when upgrading "in-place" an existing iTop configuration file.

SVN:trunk[1185]
2011-04-06 18:42:27 +00:00
Denis Flaven
e1df33c7d0 - Make the triggers and email action search-able and export/import-able using the standard user interface.
SVN:trunk[1184]
2011-04-06 18:40:22 +00:00
Denis Flaven
ee0fcdd42e Fixed Trac #371: popup dialog's dimensions (welcome screen and create or lookup dialogs) are now adjusted to fit into the screen.
SVN:trunk[1183]
2011-04-06 18:21:43 +00:00
Denis Flaven
7908b87881 - Make sure that the search form preserves it's "action" (i.e. target page) when reloading (when specifying a derived class). This was breaking the UniversalSearch page.
- Prepare for the style cleanup
- Don't display the menu to create a new 'Email Notification" when listing the notifications sent on a ticket (in the Notifications tab) !

SVN:trunk[1182]
2011-04-06 16:39:42 +00:00
Denis Flaven
8e359682ae - Make the navigation (Back / Cancel) work properly on bulk actions.
- Prepare for the style cleanup.

SVN:trunk[1181]
2011-04-06 16:34:44 +00:00
Denis Flaven
8f2089e1f6 - Fixed an error appearing only for non admins.
- Admin menu should never appear for non-admins, even empty
- Synchro Data Source objects are for admins only

SVN:trunk[1180]
2011-04-06 15:18:59 +00:00
Denis Flaven
8d61af3d22 Adjusting the French translation.
SVN:trunk[1179]
2011-04-06 09:43:35 +00:00
Denis Flaven
5e234eefe9 Special class/style for form details.
SVN:trunk[1178]
2011-04-05 13:42:43 +00:00
Romain Quetiez
25c529a797 #359 Dehardcoded the timezone (while preserving 'Europe/Paris' as the default)
SVN:trunk[1177]
2011-04-05 12:22:38 +00:00
Denis Flaven
446a8f74fb Enhancement of the forms presentation.
SVN:trunk[1176]
2011-04-05 12:13:44 +00:00
Denis Flaven
144af46e8b Fixed Track #375: Display scroll bars appropriately when dealing with big CSV load jobs.
SVN:trunk[1175]
2011-04-04 17:19:09 +00:00
Romain Quetiez
d33217285a New option: apc_cache.query_ttl (defaults to 3600s)
SVN:trunk[1174]
2011-04-04 16:20:18 +00:00
Romain Quetiez
6ff5b499b0 AttributeCaseLog finalized (history, easy migration of AttributeText, wiki formatting)
SVN:trunk[1173]
2011-04-04 14:15:33 +00:00
Denis Flaven
0c084c0b17 Delayed startup for all non-important javascript effects to speed-up the display of the pages.
SVN:trunk[1172]
2011-04-04 14:11:07 +00:00
Romain Quetiez
36dd9fc05e New option: apc_cache.enabled = true by default (beta)
SVN:trunk[1171]
2011-04-04 14:04:30 +00:00
Denis Flaven
4febe204e1 - Finishing touch to the DataExchange: various cosmetic fixes
SVN:trunk[1170]
2011-04-04 13:03:11 +00:00
Denis Flaven
9e2c556805 Load the config before using it !
SVN:trunk[1169]
2011-04-04 10:18:03 +00:00
Denis Flaven
3a0be981d6 Added the detection & logging of APC.
SVN:trunk[1168]
2011-04-04 09:57:35 +00:00
Romain Quetiez
44f661cea4 APC cache: fixed an issue with cache reset
SVN:trunk[1167]
2011-04-04 08:58:59 +00:00
Denis Flaven
195c1dabf8 New type of Attribute "CaseLog" (under construction !)
SVN:trunk[1166]
2011-04-04 08:37:30 +00:00
Denis Flaven
ce13b05363 Fixed Trac#367: typo !
SVN:trunk[1165]
2011-04-01 10:48:11 +00:00
Denis Flaven
be4674de11 Fixed Trac#368: (regression compared to 1.0.2) textarea was too small when exporting a list as CSV.
SVN:trunk[1164]
2011-04-01 10:43:07 +00:00
Denis Flaven
911d4177cc - Various fixes an finishing touch to the setup: support of "named" root modules, streamlined back/next processing, cleaner "summary" screen, etc...
SVN:trunk[1163]
2011-04-01 10:02:40 +00:00
Denis Flaven
237e36f562 - Protect against javascript js files being kept in the browser's cache when upgrading an iTop instance.
SVN:trunk[1162]
2011-04-01 09:58:53 +00:00
Romain Quetiez
5fa64ab3d2 Deletion: the message "object deleted" was displayed twice since the last review of the deletion
SVN:trunk[1161]
2011-04-01 07:29:08 +00:00
Romain Quetiez
ad98b8893f Cosmetic: changed error message when dependencies cannot be solved
SVN:trunk[1160]
2011-04-01 07:15:09 +00:00
Romain Quetiez
851b41670e New setup: fixed bug in the HTML (missing Next button on IE8)
SVN:trunk[1159]
2011-03-31 13:03:09 +00:00
Romain Quetiez
d4321ec1ce #366 Global search case sensitive or not working at all (issue with COLLATION)
SVN:trunk[1158]
2011-03-31 08:29:02 +00:00
Denis Flaven
e3ac7067f7 New implementation of the setup:
- All actions are performed asynchronously at the end of the setup
- Supports upgrading and reinstalling (to add modules)

SVN:trunk[1157]
2011-03-30 17:28:01 +00:00
Denis Flaven
eb3d226b3d Change the default collation to be consistent with the DB definition.
SVN:trunk[1156]
2011-03-30 15:37:10 +00:00
Romain Quetiez
5a30986690 Setup: Speedup profiles creation, and implemented incremental update for application upgrade
SVN:trunk[1155]
2011-03-30 08:34:39 +00:00
Romain Quetiez
b423e98295 Optimizations:
- Setup: grouped CREATE TABLE / ALTER TABLE statements in one single CREATE table
- Every page: cache the prepared queries and data model into APC
Cleanup: removed unused verb RegisterPlugin
Fix: GetObject could fail (could not find the reference from within the forum)

SVN:trunk[1154]
2011-03-30 08:30:42 +00:00
Romain Quetiez
bdf46e8136 Optimization in the setup: 10 queries to insert the 1500 action grant records
SVN:trunk[1153]
2011-03-29 14:43:22 +00:00
Romain Quetiez
d4bfa4c48f Optimization in the setup: 10 queries to insert the 1500 action grant records
SVN:trunk[1152]
2011-03-29 14:28:47 +00:00
Romain Quetiez
30a1528a28 Removed the AttributeWikiText which was strictly equivalent to AttributeText
SVN:trunk[1151]
2011-03-29 14:13:16 +00:00
Romain Quetiez
7ae02a7c5b Enablers for the current setup improvements
SVN:trunk[1150]
2011-03-28 14:03:34 +00:00
Denis Flaven
e5682fd2e9 Plug-ins integration: added the ability to manage attachments while creating a new object.
SVN:trunk[1149]
2011-03-25 17:09:50 +00:00
Romain Quetiez
c1b5614268 New verb for application extensions: OnFormCancel
SVN:trunk[1148]
2011-03-25 13:50:49 +00:00
Denis Flaven
5ad7ea1b7b Fixed Trac #365: Give the user some feedback when the password was successfully changed/set. Note that iTop does not check that the new password is different from the old one.
SVN:trunk[1147]
2011-03-24 17:34:00 +00:00
Romain Quetiez
30f4ff8765 Fixed a bug with APC version < 3.0.7
SVN:trunk[1146]
2011-03-24 17:01:59 +00:00
Denis Flaven
bec8b57fe1 Implementation of bulk modify and bulk apply stimulus... to be tested !
SVN:trunk[1145]
2011-03-23 16:22:35 +00:00
Romain Quetiez
9b50124513 Dev: improved performance measure tooling
SVN:trunk[1144]
2011-03-23 14:09:51 +00:00
Denis Flaven
c9b4468f17 Experimental support of APC to speed-up the application.
SVN:trunk[1143]
2011-03-23 14:09:39 +00:00
Romain Quetiez
3790c8f7d5 Fixed a regression in the deletion (and simplified the algorithm, though more queries will be issued)
SVN:trunk[1142]
2011-03-23 08:38:49 +00:00
Romain Quetiez
8f4ee29c69 #362 New capability for attributes derived from AttributeString: specify a validation_pattern (regexp)
SVN:trunk[1141]
2011-03-21 16:06:41 +00:00
Romain Quetiez
cf737bb8ad Added a query usage example with REGEXP
SVN:trunk[1140]
2011-03-21 15:28:31 +00:00
Romain Quetiez
a222b33566 CRON - admin only + queues with timer (field 'planned')
SVN:trunk[1139]
2011-03-21 15:17:08 +00:00
Romain Quetiez
78396eafe3 Cron - enabled mode CLI
SVN:trunk[1138]
2011-03-21 11:41:08 +00:00
Romain Quetiez
de5ccf5908 Background processes - API ready for periodicity management
SVN:trunk[1137]
2011-03-21 11:17:42 +00:00
Romain Quetiez
c3bd0b1b9e Check SLA for tickets, integrated into the internal CRON architecture (and moved into the Tickets module)
SVN:trunk[1136]
2011-03-21 10:57:37 +00:00
Romain Quetiez
736247f6e1 Email sent in asynchronous mode: forgot cron.php
SVN:trunk[1135]
2011-03-18 12:17:04 +00:00
Romain Quetiez
3074683274 Email sent in asynchronous mode: forgot two files...
SVN:trunk[1134]
2011-03-18 12:13:04 +00:00
Denis Flaven
4929f94c20 Protect the output of the config file against values containing quotes.
SVN:trunk[1133]
2011-03-18 11:22:23 +00:00
Romain Quetiez
b8b20f82d7 Email sent in asynchronous mode (established the base for an application internal CRON, task queue, etc.) with adjustable configuration (disable by default). Also improved the OQL: IS_NULL() and REGEXP have been added.
SVN:trunk[1132]
2011-03-18 11:15:09 +00:00
Romain Quetiez
7989cf622f CSV import: fixed a few issues (restricted to N-N links) + added arguments to the export page, to allow for exporting N-N links
SVN:trunk[1130]
2011-03-15 12:19:04 +00:00
Romain Quetiez
f3cc490295 #328 Added the capability to import/export link sets in CSV format
SVN:trunk[1129]
2011-03-14 14:11:08 +00:00
Romain Quetiez
52a47b193d #360 Wrong COUNT when using JOINS (+ other conditions)
SVN:trunk[1128]
2011-03-11 17:47:03 +00:00
Denis Flaven
cfbf77544e Adjust the relative path to 'ajax.render.php' so that it can be called from the portal pages as well.
SVN:trunk[1125]
2011-03-11 11:11:56 +00:00
Romain Quetiez
0b32f511b8 Plugin API - alpha version
SVN:trunk[1124]
2011-03-11 11:04:50 +00:00
Denis Flaven
bca713a964 Search forms enhancement: when a search criteria is an external (foreign) key, use an autocomplete instead of of drop-down list, when the number of different values is too big, as in other forms.
SVN:trunk[1123]
2011-03-09 16:39:58 +00:00
Romain Quetiez
692f7060ea #355 CSV Import (non interactive) now supporting localized column headers, making it possible to import directly data generated by the interactive export. NOTE: to achieve this, the default separator is now the coma (whereas the default separator in XCel sheets is the semicolumn)
SVN:trunk[1122]
2011-03-09 09:19:03 +00:00
Romain Quetiez
4fa9933dc7 #340 Fixed OQL parsing issue - parameters in IN()/NOT IN() clauses
SVN:trunk[1121]
2011-03-08 15:51:11 +00:00
Denis Flaven
45134e182d Fixed Trac#313: Provider contracts are filtered on the 'provider_id' - for filtering in the UI via the drop-down list of Organizations and for the security profiles ("Allowed Organizations"). The mapping for 'org_id', if any, is now taken into account by the security.
SVN:trunk[1120]
2011-03-08 12:31:16 +00:00
Romain Quetiez
38a502aa25 #271 Internal - Removed a workaround made unnecessary with fix [1108]
SVN:trunk[1119]
2011-03-08 12:23:04 +00:00
Denis Flaven
49e05acd4b Fixed Trac #156: make sure the hierarchical ZLists are supported everywhere (final cleanup).
SVN:trunk[1118]
2011-03-08 11:19:38 +00:00
Denis Flaven
089407119b Thanks to Schlobinux for the fix of Trac#336.
SVN:trunk[1117]
2011-03-08 10:52:58 +00:00
Denis Flaven
6262fa1d26 Fix Trac #336: verification of the directory of the temporary config file was wrong... however the script still assumes that the temporary config file and the final one are stored in the same place... at the root of the iTop installation.
SVN:trunk[1116]
2011-03-08 10:48:35 +00:00
Romain Quetiez
c4cca2b2f8 #348 Multi-column queries not working fine with open joins and if null values to be displayed
SVN:trunk[1115]
2011-03-08 10:46:03 +00:00
Denis Flaven
d5353c111c Fixed Trac#356 (Audit results filtered by context) and #357 (Audit results list not expandable)
SVN:trunk[1114]
2011-03-08 10:31:13 +00:00
Denis Flaven
fd79d30483 Fixed Trac #353: no menu for DBServerInstance objects.
SVN:trunk[1113]
2011-03-07 17:12:30 +00:00
Denis Flaven
d708ef585b Fixed Trac#344: default search behavior for enumerated attributes (and similar types: 'Class', 'Language' and 'FinalClass') is now a strict '=' instead of 'contains'.
SVN:trunk[1112]
2011-03-07 17:06:17 +00:00
Romain Quetiez
6ac06d7e47 #352 Web Service CreateTicket: Search the service subcategory given the found service_id (if not already specified)
SVN:trunk[1111]
2011-03-07 16:58:46 +00:00
Romain Quetiez
019888caff #305 Specified the charset in any call to htmlentities()
SVN:trunk[1110]
2011-03-07 16:43:20 +00:00
Romain Quetiez
e36646a3e6 Fixed undocumented issue: in read-only mode, stimulus where still allowed
SVN:trunk[1109]
2011-03-07 16:40:26 +00:00
Romain Quetiez
8b6672c0dd Data Exchange - Fixed issue in DBObjectSet, doubling the count of SynchroAttribute initially created
SVN:trunk[1108]
2011-03-03 08:34:24 +00:00
Denis Flaven
3d4e76d8b0 Synchro Data Sources Implementation on going...
SVN:trunk[1107]
2011-03-02 17:06:56 +00:00
Romain Quetiez
cf8174d54e Data Exchange - Improved to allow the import of complex attributes like passwords and documents + few fixes
SVN:trunk[1106]
2011-03-02 14:38:12 +00:00
Denis Flaven
33f1ec8bf3 Data Exchange implementation in progress...
SVN:trunk[1105]
2011-03-02 10:49:12 +00:00
Denis Flaven
be1d8674f3 Data Exchange implementation in progress...
SVN:trunk[1104]
2011-03-02 09:12:15 +00:00
Romain Quetiez
76b5bfb19e Data Exchange - Cleanup
SVN:trunk[1103]
2011-03-01 16:33:09 +00:00
Romain Quetiez
bddb8b4c92 Data Exchange - Format and save traces (config option: synchro_trace)
SVN:trunk[1102]
2011-03-01 16:21:04 +00:00
Romain Quetiez
67f8ddf5a8 Data Exchange - Implemented reconciliation on external keys
SVN:trunk[1101]
2011-03-01 13:47:09 +00:00
Denis Flaven
f3f2eb5c79 Synchro Data Sources Implementation on going...
SVN:trunk[1100]
2011-03-01 09:01:44 +00:00
Romain Quetiez
a1b9bdaf66 Data Exchange - Improved handling of deletion (inc. the reporting of it)
SVN:trunk[1099]
2011-02-25 17:22:51 +00:00
Denis Flaven
e020bad17d Synchro Data Sources Implementation on going...
SVN:trunk[1098]
2011-02-24 18:45:13 +00:00
Romain Quetiez
36278d59a8 Data Exchange - Implemented checks on sync startup (user identity, task state, protection against entire obsolescence) and added a "last error" into the logs
SVN:trunk[1097]
2011-02-24 17:21:48 +00:00
Denis Flaven
20d0d33b60 Synchro Data Sources Implementation on going...
SVN:trunk[1096]
2011-02-24 17:09:50 +00:00
Romain Quetiez
573712e9af Data Exchange - Fixed issue when a field is selected for reconciliation but not for update
SVN:trunk[1095]
2011-02-24 15:37:21 +00:00
Romain Quetiez
5897ae5bb9 Data Exchange - Simulation in synchro_import.php now relying on MySQL transactions
SVN:trunk[1094]
2011-02-24 08:47:46 +00:00
Romain Quetiez
cd71f02fad Data Exchange - Implemented reconciliation options + cosmetics on synchro_exec
SVN:trunk[1093]
2011-02-23 17:32:21 +00:00
Denis Flaven
e4df8c8c92 Added synchron statistics and their first display...
SVN:trunk[1092]
2011-02-23 16:49:00 +00:00
Romain Quetiez
d1879d0433 Data Exchange - Simulate mode on synchro_exec + cleanup in traces + handling of null values
SVN:trunk[1091]
2011-02-23 14:55:51 +00:00
Denis Flaven
9e636b1ce5 New display of the "Synchro status/log"
SVN:trunk[1090]
2011-02-23 14:37:23 +00:00
Denis Flaven
cccea50159 Added an extra parameter 'simulate'
SVN:trunk[1089]
2011-02-22 15:21:40 +00:00
Romain Quetiez
3441911781 Fixed regression on AttributeInteger
SVN:trunk[1088]
2011-02-22 14:26:00 +00:00
Romain Quetiez
c97f4d5ee7 Data Exchange - Log statistics
SVN:trunk[1087]
2011-02-22 14:20:46 +00:00
Romain Quetiez
4c637548ac Fixed regression in the audit (new way to translate OQL expression having an impact on DBObjectSearch::MergeWith)
SVN:trunk[1086]
2011-02-21 16:35:47 +00:00
Denis Flaven
721ca8c652 Continuing the implementation of the DataExchange
SVN:trunk[1085]
2011-02-16 17:31:32 +00:00
Romain Quetiez
293877d78a Data Exchange - Replica objects must not be derived from cmdbAbstractObject
SVN:trunk[1084]
2011-02-11 13:15:41 +00:00
Romain Quetiez
d92f89fbe6 Data Exchange - Finalized deletion, changed the definition of attributes (update/reconcile), added an automated test
SVN:trunk[1083]
2011-02-11 09:01:16 +00:00
Romain Quetiez
1da6a264d0 Automatic deletion of links lnkSolutionToCI
SVN:trunk[1082]
2011-02-10 15:13:24 +00:00
Denis Flaven
89b58d44cd Removed a "assertion failed" error message.
SVN:trunk[1080]
2011-02-09 09:44:00 +00:00
Denis Flaven
0b93e6f79e Fixed an incorrect detection of the maximum recursion level
SVN:trunk[1079]
2011-02-08 16:25:18 +00:00
Denis Flaven
eb0ba24d7d - Data Exchange implementation... in progress.
SVN:trunk[1078]
2011-02-08 13:34:47 +00:00
Romain Quetiez
64521eb758 Fixed regression (implementation of the data exchange)
SVN:trunk[1074]
2011-02-07 16:29:49 +00:00
Denis Flaven
2d65325f6f New configuration setting (and new class of Log objects) to keep track of the application's usage: an entry in the log is added each time a user connects to the application. (This feature is disabled by default)
SVN:trunk[1073]
2011-02-07 15:55:39 +00:00
Denis Flaven
a97238c3cd Fixed Trac #351: undefined variable sClass...
SVN:trunk[1072]
2011-02-07 15:51:24 +00:00
Romain Quetiez
ce993b60e4 Data Exchange - Removed the state 'deleted': instead, delete the replica!
SVN:trunk[1068]
2011-02-03 16:39:58 +00:00
Romain Quetiez
283f7dc9f8 CSV import web service - cosmetics on the reporting in case the data set is empty
SVN:trunk[1067]
2011-02-03 15:50:48 +00:00
Romain Quetiez
4441fb41b9 Data Exchange - Fixed a corner case issue (a replica going directly from new to obsolete, then touched again -> back into the picture)
SVN:trunk[1066]
2011-02-03 15:36:37 +00:00
Romain Quetiez
34322045df Data Exchange - forgot a change in the previous commit
SVN:trunk[1065]
2011-02-03 09:57:47 +00:00
Romain Quetiez
b73da47775 Data Exchange - new web service to update data tables
SVN:trunk[1064]
2011-02-03 09:55:17 +00:00
Denis Flaven
3d8ffba2fa Mention that the database user must have the "CREATE VIEW and TRIGGER" privileges for the setup to work fine.
SVN:trunk[1063]
2011-02-03 09:41:32 +00:00
Denis Flaven
f9a380b12d DataExchange: implementation in progress.
SVN:trunk[1062]
2011-02-02 14:48:45 +00:00
Romain Quetiez
a9a530a2cb Core: Join any table to an OQL query (prerequisite to Data Exchange)
SVN:trunk[1061]
2011-02-01 16:54:10 +00:00
Romain Quetiez
ba822a655e Wiki: add links to objects in text attributes
SVN:trunk[1060]
2011-02-01 13:40:51 +00:00
Romain Quetiez
20ec91e9f3 Data ExchangeData Exchange - data structure (ready for sync)
SVN:trunk[1059]
2011-02-01 12:56:26 +00:00
Romain Quetiez
735a9729c0 Data Exchange - data structure
SVN:trunk[1058]
2011-01-31 15:53:07 +00:00
Romain Quetiez
1a52f4de72 #149 Implemented friendly names
SVN:trunk[1057]
2011-01-26 09:43:35 +00:00
Denis Flaven
cb0610bf0b Readme for iTop 1.0.2
SVN:trunk[1055]
2011-01-18 11:38:24 +00:00
Denis Flaven
20ea4644b4 Remove an ambiguous naming when performing a CSV import of DBServerInstance objects.
SVN:trunk[1054]
2011-01-18 11:37:21 +00:00
Denis Flaven
fde336d8dd Cosmetics: make the login & change password form look the same on all browsers.
SVN:trunk[1053]
2011-01-18 09:07:46 +00:00
Denis Flaven
bc78b19ba7 Fixed Trac #348: no validation needed when pressing "Restart".
SVN:trunk[1052]
2011-01-18 09:00:26 +00:00
Denis Flaven
a4883076f8 Fixed Trac #338: when updating a 'dependent' field, don't forget to cascade the refresh in case this field has its own dependent fields.
SVN:trunk[1051]
2011-01-17 17:11:03 +00:00
Denis Flaven
57a0e2d47e Fixed Trac #345: hidden or read-only parameters in a form were not taken into account for computing the allowed values.
SVN:trunk[1050]
2011-01-17 15:13:28 +00:00
Denis Flaven
5a41992739 Trying to make CKEditor work with the "ExtKey" widget. (Trac #343)
Seems to be functional but there is still an "uncaught exception" that pops up from nowhere when closing the dialog.

SVN:trunk[1049]
2011-01-10 18:15:15 +00:00
Denis Flaven
15e07b69d6 Fixed Trac #341: broken form when an external key is part of the attrbiutes of an n-n link !
SVN:trunk[1048]
2011-01-10 18:07:54 +00:00
Denis Flaven
f6bfcb8355 Preparing the readme for the 1.0.2 release
SVN:trunk[1047]
2011-01-04 09:44:47 +00:00
Denis Flaven
019959504f Added the ability to (easily) attach files to a user request from the "portal" page. (French translation)
SVN:trunk[1046]
2011-01-04 09:35:17 +00:00
Denis Flaven
331b7ec2f0 Added the ability to (easily) attach files to a user request from the "portal" page.
SVN:trunk[1045]
2011-01-03 16:39:16 +00:00
Romain Quetiez
56ddf960a5 Readme for 1.0.2 -draft
SVN:trunk[1044]
2011-01-03 16:05:09 +00:00
Denis Flaven
35429228a2 Fixed a typo in German translation (Trac #339), thanks to ulmerspatz and Jonathan Lucas
SVN:trunk[1043]
2011-01-03 15:02:05 +00:00
Denis Flaven
78256bae0b - Display PHP errors during setup instead of hiding them ! (Trac #321)
- Set a longer timeout during setup (Trac #314)

SVN:trunk[1042]
2011-01-03 14:56:28 +00:00
Denis Flaven
8145c23899 Avoid using 'gethostname()' which is not always available.
SVN:trunk[1041]
2011-01-03 14:38:58 +00:00
Denis Flaven
3b629ab83c SVN:trunk[1040] 2011-01-03 13:46:06 +00:00
Denis Flaven
abc2c7b5e1 Small fix: using an unassigned variable.
SVN:trunk[1039]
2011-01-03 13:02:17 +00:00
Denis Flaven
e1d7e17c5d Added support for hierarchical ZLists when checking the data model consistency
SVN:trunk[1038]
2011-01-03 12:58:21 +00:00
Denis Flaven
64f452caba FIxed the processing of hierarchical ZLists to keep the display order when plain fields and fieldsets are mixed at the same level.
SVN:trunk[1037]
2011-01-03 12:56:07 +00:00
Denis Flaven
a8a77fdebb Make sure that the "+" (Create) button is never displayed for an abstract class.
SVN:trunk[1036]
2011-01-03 12:54:05 +00:00
Romain Quetiez
83e7e9c44b Chinese: added to the readme.txt
SVN:trunk[1035]
2010-12-20 13:47:06 +00:00
Romain Quetiez
6c73b3ed2e Localized in chinese
SVN:trunk[1034]
2010-12-20 13:44:15 +00:00
Romain Quetiez
adfed90733 Localized in turkish
SVN:trunk[1033]
2010-12-20 11:48:34 +00:00
Denis Flaven
c6a6af0aa2 Including approot is not needed here !
SVN:trunk[1032]
2010-12-20 11:45:38 +00:00
Denis Flaven
19463b370c - Updates to the Spanish localization
SVN:trunk[1031]
2010-12-20 11:30:16 +00:00
Denis Flaven
6bc3a80c8c - Small updates to the German localization
SVN:trunk[1030]
2010-12-20 11:28:50 +00:00
Denis Flaven
de4945bca6 - Added the russian localization (thanks to Vladimir Shilov)
SVN:trunk[1029]
2010-12-20 11:17:05 +00:00
Denis Flaven
6dd3eb9970 - Added the russian localization (thanks to Vladimir Shilov)
SVN:trunk[1028]
2010-12-20 11:13:54 +00:00
Denis Flaven
511c703b61 Bug fix: history of encrypted fields was not recorded properly.
SVN:trunk[1027]
2010-12-15 16:33:08 +00:00
Romain Quetiez
21722b9e80 Internal: added an API for logging tools events
SVN:trunk[1026]
2010-12-10 15:19:18 +00:00
Denis Flaven
203887589f - Yet another IE fix...
SVN:trunk[1025]
2010-12-10 13:58:12 +00:00
Denis Flaven
028f23214d - Fixed the CSV "confirmation pie chart" to work under IE & enhanced the look of the chart by removing unused values.
SVN:trunk[1024]
2010-12-10 13:43:55 +00:00
Romain Quetiez
b89a4d32d1 Improved the detection of MySQL Slave status
SVN:trunk[1023]
2010-12-09 10:04:38 +00:00
Romain Quetiez
b6883ed3b4 Internal: added an helper to get the currently loaded config file
SVN:trunk[1022]
2010-12-08 15:29:30 +00:00
Denis Flaven
6338775506 Split the usage of the iTop logo: one logo to be displayed internally (once logged) one externally (login/logoff).
SVN:trunk[1021]
2010-12-08 09:43:56 +00:00
Denis Flaven
25ea409228 Build the menus BEFORE the actual display of the page content... since the content is the result of a menu !
SVN:trunk[1020]
2010-12-07 19:54:27 +00:00
Denis Flaven
6a72ceb685 Patch for supporting a data model without any Person.
SVN:trunk[1019]
2010-12-07 15:24:16 +00:00
Denis Flaven
235203b3a0 The hyperlink to the online-help file is now configurable
SVN:trunk[1018]
2010-12-07 15:15:43 +00:00
Denis Flaven
2b9beb971b For fine-grained user rights detection...
SVN:trunk[1017]
2010-12-07 15:13:41 +00:00
Denis Flaven
5ff5e3f1a7 Patch for supporting a data model without any Person.
SVN:trunk[1016]
2010-12-07 15:06:17 +00:00
Denis Flaven
e3caff6689 Patch for supporting a data model without any Organization.
SVN:trunk[1015]
2010-12-07 14:55:40 +00:00
Romain Quetiez
59970be867 Menus created via a handler, at runtime
SVN:trunk[1014]
2010-12-07 14:32:13 +00:00
Romain Quetiez
98cfcc9cb8 Fixed an issue in the display of CSV imports history
SVN:trunk[1013]
2010-12-07 13:46:22 +00:00
Romain Quetiez
e66f06cda2 Internal: improved the user management API ChangePassword()
SVN:trunk[1012]
2010-12-06 17:07:07 +00:00
Romain Quetiez
35fe0b9ef5 Fixed bug in CSV sync mode (class given by the scope)
SVN:trunk[1011]
2010-12-06 15:58:37 +00:00
Romain Quetiez
cde184e2a3 Allow a module to provide a handler to override application settings: OnMetaModelStarted()
SVN:trunk[1010]
2010-12-06 09:14:20 +00:00
Denis Flaven
df8f4449e8 Fix for Trac #337: email validation. Use a simpler regular expression that is much faster to execute.
SVN:trunk[1009]
2010-12-03 12:03:05 +00:00
Romain Quetiez
b225b621b7 Cosmetic issue with the banner when the application is fully accessible
SVN:trunk[1008]
2010-12-03 10:28:25 +00:00
Romain Quetiez
d85aba8ebc Improved change tracking: user login replaced by the full name if available
Added a tab into the CSV import: browse the CSV imports history
Finalized the read-only mode (distinguish between users and everybody, admin message displayed on top of the main screen)

SVN:trunk[1007]
2010-12-03 10:18:28 +00:00
Denis Flaven
53d5867b93 Patch to support a different data model where contacts are not part of an org
SVN:trunk[1006]
2010-12-03 09:10:15 +00:00
Romain Quetiez
d4eaf43257 Fixed cosmetic issues in the CSV import (related to the recent changes)
SVN:trunk[1005]
2010-12-01 16:27:11 +00:00
Denis Flaven
dc96cbc482 - Ask for confirmation when doing a CSV import/synchro that is considered as "risky" (based on thresholds from the config file)
- Added a "Restart" button to quickly start over a CSV import/synchro

SVN:trunk[1004]
2010-12-01 15:21:29 +00:00
Denis Flaven
73e9107ae2 - Added the new "synchro" mode to the CSV load page.
SVN:trunk[1003]
2010-12-01 10:27:10 +00:00
Denis Flaven
9d1df1b799 - Bug fix: when creating a new object the "Cancel" button must go somewhere !
SVN:trunk[1002]
2010-11-30 15:55:40 +00:00
Romain Quetiez
018344578e Internal: BulkChange improved with synchro mode
SVN:trunk[1001]
2010-11-30 15:32:30 +00:00
Denis Flaven
bb4c6aecfa Added the capability to enable/disable menus based on the rights to apply a given stimulus.
SVN:trunk[1000]
2010-11-30 15:16:17 +00:00
Denis Flaven
06bb4a4f03 - Bug fix: support resizable elements inside tabs.
SVN:trunk[999]
2010-11-30 14:54:03 +00:00
Denis Flaven
dfe3ced440 - Provide some feedback while loading the "creation" dialog in case of a "SELECT".
SVN:trunk[998]
2010-11-30 14:27:11 +00:00
Denis Flaven
922d1dc734 Added the capability to enable/disable menus based on the rights to apply a given stimulus.
SVN:trunk[997]
2010-11-30 14:26:17 +00:00
Denis Flaven
bf2654409b Debug of the ExtKeyWidget...
SVN:trunk[996]
2010-11-30 13:51:46 +00:00
Denis Flaven
b6a001fedc - Cosmetics: prevent the extkey widget to warp.
SVN:trunk[995]
2010-11-30 13:22:12 +00:00
Denis Flaven
d8f2979c5a - Fixed Trac #318 (and #335): added the check of the mandatory DOM extension.
SVN:trunk[994]
2010-11-29 18:27:44 +00:00
Denis Flaven
7f8f4f5aab Exclude the special "data loader" tool from the standard build
SVN:trunk[993]
2010-11-29 15:33:27 +00:00
Romain Quetiez
653229b1bd XML data loader: fixed issue with transations
SVN:trunk[992]
2010-11-29 14:42:42 +00:00
Romain Quetiez
2b69c5210f Fixed issues in the compatibility with config files generated with 1.0
SVN:trunk[991]
2010-11-29 13:26:18 +00:00
Denis Flaven
7531dd8b19 Align properly the 'validation_error' icon in forms.
SVN:trunk[990]
2010-11-29 13:04:50 +00:00
Denis Flaven
49e101403f Small fix of unassigned variable when editing ext keys.
SVN:trunk[989]
2010-11-29 12:28:47 +00:00
Denis Flaven
d10c3ace5d Renamed 'autocompleteWidget' to 'extkeyWidget' since it's not always an autocomplete...
SVN:trunk[988]
2010-11-29 10:43:06 +00:00
Denis Flaven
4a6bc8a896 - added the ability to create objects pointed by ExtKeys even when the edit mode is a drop-down list and not an autocomplete
- made this behavior configurable globally or per external key, using the config-flag/option: allow_target_creation.

SVN:trunk[987]
2010-11-29 10:35:18 +00:00
Romain Quetiez
c428e07c4b XML data loader to request for credentials
SVN:trunk[986]
2010-11-29 10:19:33 +00:00
Romain Quetiez
540eb5f272 Moved the standards menus into the "welcome" module
SVN:trunk[985]
2010-11-29 09:17:44 +00:00
Romain Quetiez
699679318a Welcome menu (forgot at previous commit)
SVN:trunk[984]
2010-11-26 16:39:41 +00:00
Denis Flaven
4bd217d178 Keep backward compatibility with *old* config files without the 'webservices' entry in the config-file.
SVN:trunk[983]
2010-11-26 16:22:20 +00:00
Romain Quetiez
e37f6a0954 Welcome page moved out the application, into a dedicated module: itop-welcome-itil
SVN:trunk[982]
2010-11-26 15:59:41 +00:00
Romain Quetiez
9f000c15ff Cosmetic on setup: perform post DB install in the same page as admin account creation, and hide ticket prerequisites module
SVN:trunk[981]
2010-11-26 15:57:11 +00:00
Romain Quetiez
7d13ec00e4 User profiles: created in dedicated module itop-profiles-itil
SVN:trunk[980]
2010-11-26 15:55:38 +00:00
Denis Flaven
c8384cc8a4 Handle filtering of non-existent attributes in hierarchical ZLists.
SVN:trunk[979]
2010-11-26 13:25:00 +00:00
Denis Flaven
9e70feb29d - Fixed bug #334: proper handling of the "remove objects" button (was working only for the first linkset in the object).
- Improved feedback while searching and reloading added objects.

SVN:trunk[978]
2010-11-26 13:19:13 +00:00
Denis Flaven
ced4bf4259 - Fixed Trac #333: organizations' drop-down list is truncated on IE when the name of an organization is too long.
SVN:trunk[977]
2010-11-26 11:16:55 +00:00
Denis Flaven
51fa310664 - Fixed Trac #332: improved usability of the CSV import wizard with IE8.
SVN:trunk[976]
2010-11-26 10:43:25 +00:00
Romain Quetiez
64044e47e1 Modularity: allow a module to execute some specific installation procedures (customize the config file, do something in the database)
SVN:trunk[975]
2010-11-25 17:15:12 +00:00
Romain Quetiez
ebf9910579 #331 Import.php could not be run in HTTP mode (when PHP running in CGI mode) - fix getting more bullet proof
SVN:trunk[974]
2010-11-25 09:52:22 +00:00
Romain Quetiez
a60709a354 #331 Import.php could not be run in HTTP mode (when PHP running in CGI mode)
SVN:trunk[973]
2010-11-25 09:44:42 +00:00
Romain Quetiez
c63d25e223 Read-only mode relying successively on a DB property, and an application setting
SVN:trunk[972]
2010-11-24 16:52:55 +00:00
Romain Quetiez
7fbcdc407e Added class DBProperty
SVN:trunk[971]
2010-11-24 16:28:13 +00:00
Romain Quetiez
35c50d6689 Ajax pages: exceptions are traced into error.log
SVN:trunk[970]
2010-11-24 14:00:24 +00:00
Romain Quetiez
ff112faf5a Removed PHP "warning"
SVN:trunk[969]
2010-11-24 09:05:35 +00:00
Romain Quetiez
5ecbc66d7e Fixed regressions in the user portal
SVN:trunk[968]
2010-11-24 09:03:20 +00:00
Romain Quetiez
dc3a99200f Added an helper function to report the current configuration
SVN:trunk[967]
2010-11-23 17:07:51 +00:00
Romain Quetiez
40a613b4db Cleanup: replaced remaining occurences of ISO-8859-1
SVN:trunk[966]
2010-11-23 16:18:48 +00:00
Romain Quetiez
fcbd9b8911 Improved Web services: opened to services coming from an optional module
SVN:trunk[965]
2010-11-23 16:16:01 +00:00
Denis Flaven
9dd2061f60 Do not assume that a User is linked to a Person !
SVN:trunk[964]
2010-11-23 13:36:53 +00:00
Denis Flaven
2c4bdf6398 - Fixed the detection of relative path in the config file to make it compatible with *nix
SVN:trunk[963]
2010-11-23 11:54:41 +00:00
Romain Quetiez
d8bb6a45b2 REVIEWED THE FILE INCLUSION POLICY
- includes are relative to the application root folder, aka APPROOT
- changed the config file, while preserving the compatibility with older installs

SVN:trunk[962]
2010-11-22 17:53:52 +00:00
Romain Quetiez
d0f168adbb Read-only mode - draft
SVN:trunk[961]
2010-11-22 14:13:49 +00:00
Denis Flaven
b30d6c4888 - Safer way to pass information through the WizardHelper JS object.
- Removed an unneeded size=100% that bothers IE.

SVN:trunk[960]
2010-11-22 13:27:41 +00:00
Denis Flaven
ed39fa2c96 Continuing the 'autocomplete' debug.
SVN:trunk[959]
2010-11-22 13:21:45 +00:00
Denis Flaven
92045ef15f Continuing the 'autocomplete' debug.
SVN:trunk[958]
2010-11-22 12:52:29 +00:00
Denis Flaven
956ebb1962 Force a dummy timezone to prevent a warning during the setup...
SVN:trunk[957]
2010-11-22 12:36:38 +00:00
Denis Flaven
a1cc8deb47 Debugging of the autocomplete on IE8.
SVN:trunk[956]
2010-11-22 12:35:46 +00:00
Denis Flaven
0306c6691a - Implementing the creation of objects on the fly when editing an extrernal key... still to be fully tested.
SVN:trunk[955]
2010-11-22 10:44:43 +00:00
Romain Quetiez
d098bae484 French is french, not english
SVN:trunk[954]
2010-11-22 10:23:38 +00:00
Romain Quetiez
a524100d99 Fixed typo in French dictionary
SVN:trunk[953]
2010-11-22 10:20:09 +00:00
Romain Quetiez
cf888ea165 Added attribute types into the dictionary
SVN:trunk[952]
2010-11-22 10:06:52 +00:00
Romain Quetiez
8f7be02bc2 Clarified the states / attributes flags for the user requests
SVN:trunk[951]
2010-11-22 10:02:04 +00:00
Romain Quetiez
8e125cb743 Fixed issue in the lifecycle generation tool (escape double quotes)
SVN:trunk[950]
2010-11-19 15:34:11 +00:00
Denis Flaven
a97e2825b1 Make sure that each input field gets its own unique ID.
SVN:trunk[949]
2010-11-18 17:37:30 +00:00
Romain Quetiez
738d90d592 Regression on N-N links creation - passing over to Denis
SVN:trunk[948]
2010-11-18 17:09:02 +00:00
Denis Flaven
dc9a52c9e0 Improved implementation of the 'autocomplete' input and fix of quite a few related issue with aysnchronous inputs. Autocompletes are now restricted to external keys only.
Some details:
- Autocomplete now matches on 'contains' instead of 'begins with'
- The minimum size of this match is configurable in the config file and per attribute ('min_autocomplete_chars').
- The maximum size that turns a drop-down list into an autocomplete is configurable in the config-file and per attribute ('max_combo_length').
- Better feedback when expanding/collapsing search results lists.
- 'Pointer' cursor on the link to Expand/Collapse results lists.
- The 'mandatory' state of an attribute is no longer lost when some part of a form is reloaded asynchronously

SVN:trunk[947]
2010-11-18 16:41:09 +00:00
Romain Quetiez
5ea71a3d51 #320 Integrated an HTML Editor -still, no attribute has been changed, because it would require a migration procedure... to be continued
SVN:trunk[946]
2010-11-16 16:16:47 +00:00
Denis Flaven
8d80d73f35 - Allow DBObjects to be deleted by the standard UI 'Delete', which may be useful in case a DBObject has to be deleted as a dependent object of a CMDBObject.
SVN:trunk[945]
2010-11-16 13:21:21 +00:00
Denis Flaven
99907a92ea Use XMLPage passthrough mode to speed up and consume less memory for big XML exports.
SVN:trunk[944]
2010-11-12 16:49:47 +00:00
Denis Flaven
259b266a19 - Keep track of the object at the source of any email notification for further correlation (either in the user's mailbox or for automatic processing of incoming emails)
SVN:trunk[943]
2010-11-12 16:34:50 +00:00
Denis Flaven
effa212261 - Added a 'pre' method for transparent support of the CLI (Command Line Interface) mode.
SVN:trunk[942]
2010-11-12 16:28:17 +00:00
Denis Flaven
1a92a7b4f3 Ready for 1.0.1 release
SVN:trunk[940]
2010-11-03 15:33:46 +00:00
Romain Quetiez
4338bce526 Readme draft for 1.0.1
SVN:trunk[939]
2010-11-03 13:06:52 +00:00
Denis Flaven
4572bdbb02 Nicer display of the CSV import results...
SVN:trunk[938]
2010-11-02 16:33:26 +00:00
Denis Flaven
fcd72fed82 Fix for Trac #315: default organization not handled properly when there is just one organization allowed for the user.
SVN:trunk[937]
2010-11-02 16:30:46 +00:00
Romain Quetiez
1800120762 #311 CSV import: Improved the reporting on external keys (and changed a little the behavior)
SVN:trunk[936]
2010-11-02 16:29:41 +00:00
Denis Flaven
e5f0460703 AutoComplete usage: code cleanup
SVN:trunk[935]
2010-11-02 10:16:24 +00:00
Denis Flaven
72dbb9cb8f Fixed Trac #312: initial form validation for the "apply stimulus/change state" wizard.
SVN:trunk[934]
2010-11-02 09:29:55 +00:00
Romain Quetiez
562cfde587 #308 Free IPs: do not show the subnet address (the first one)
SVN:trunk[933]
2010-11-01 08:37:21 +00:00
Denis Flaven
6fe25d8b57 Fixed Trac #309 : Missing php-ofc-library files
SVN:trunk[932]
2010-10-29 11:11:09 +00:00
Romain Quetiez
248cdcea8c #286 Issue with HTTPS - reviewed the fix implemented in [896]
SVN:trunk[931]
2010-10-28 12:55:51 +00:00
Denis Flaven
0b95b3799e Fixed Trac #307: prevent form submission when the value typed into an autocomplete field does not correspond to a valid value.
SVN:trunk[930]
2010-10-26 08:12:31 +00:00
Denis Flaven
05a2443afe The previous fix for Trac #276 broke the auto mapping of external keys... now fixed.
SVN:trunk[929]
2010-10-25 17:05:12 +00:00
Denis Flaven
1860521e74 Fixed Trac #306: corrupted password when user creation fails at first attempt.
SVN:trunk[928]
2010-10-25 15:49:20 +00:00
Denis Flaven
8d39ddded6 Do not create a "mailto" hyperlink for empty email addresses.
SVN:trunk[927]
2010-10-25 14:27:48 +00:00
Denis Flaven
fd3317e99e Fixed the "Relationships" Flash navigator so that it works also on Safari. (tested with Safari 5.0.2 on Windows)
SVN:trunk[926]
2010-10-25 14:14:29 +00:00
Denis Flaven
7651aaed81 - Fixed the search form, and also fixed the search/selection of objects to link (n:n links) that was broken on IE8.
SVN:trunk[925]
2010-10-25 14:12:26 +00:00
Romain Quetiez
a5d2d067ff #284 Do not forget to adjust both upload_max_filesize AND post_max_size
SVN:trunk[924]
2010-10-25 11:33:48 +00:00
Denis Flaven
b27fda4cf5 German localization update. Thanks to ITOMIG.
SVN:trunk[923]
2010-10-25 08:19:50 +00:00
Romain Quetiez
2834c073cd #304 Fixed OQL issue (regression when using time intervals)
SVN:trunk[922]
2010-10-25 08:12:17 +00:00
Denis Flaven
97f36bd7e8 Fix to prevent IE 8 from running in IE7 compatibility mode... to be tested...
SVN:trunk[921]
2010-10-25 08:04:46 +00:00
Romain Quetiez
3d299f015b #246 Implemented the CLI mode for import.php
SVN:trunk[920]
2010-10-22 22:22:13 +00:00
Denis Flaven
8a5ed95c80 - Integrating the Brazilian transalation from Marco Tulio...
SVN:trunk[919]
2010-10-22 16:55:41 +00:00
Denis Flaven
f4b29d152b Special passthrough mode for big XML pages output.
SVN:trunk[918]
2010-10-22 16:46:53 +00:00
Denis Flaven
463bc0873b Allow n:n links to link several times to the same remote object (if "duplicates)=> true in the linkedset definition)
SVN:trunk[917]
2010-10-22 10:45:12 +00:00
Denis Flaven
368ea1cfdb SVN:trunk[916] 2010-10-22 10:42:39 +00:00
Denis Flaven
1b618ff57c (Partial) fix for Trac #285: turn email fields into click-able mailto: hyperlinks.
SVN:trunk[915]
2010-10-22 10:33:53 +00:00
Romain Quetiez
70149af5d6 Fixed a bug in the XML encoding function
SVN:trunk[914]
2010-10-22 07:47:05 +00:00
Denis Flaven
006453678b Fixed Trac#300: each iTop instance now uses its own name for the cookie storing the session ID. Therefore several instances can coexist independently on the same server.
SVN:trunk[913]
2010-10-22 06:09:51 +00:00
Denis Flaven
135353aa76 Fixed Trac #258: cleaner handling of search forms...
SVN:trunk[912]
2010-10-21 15:39:30 +00:00
Romain Quetiez
ddd52554f1 Fixed issues with the search form and context and page args... not finished
SVN:trunk[911]
2010-10-21 14:28:40 +00:00
Denis Flaven
22cf8e4986 Fixed Trac #292: enums can now be null (if allowed) !
SVN:trunk[910]
2010-10-21 09:23:41 +00:00
Denis Flaven
931075687a Fix for Trac #289: setup now checks that the "setup" directory is writeable.
SVN:trunk[909]
2010-10-20 16:20:52 +00:00
Denis Flaven
adaf3a376c Fixed Trac #258: cleanup of application context parameters.
SVN:trunk[908]
2010-10-20 15:55:30 +00:00
Romain Quetiez
1808e5fe65 Fixed #302, Ticket icons were not always displayed (+ error message on some installations)
SVN:trunk[907]
2010-10-20 14:48:45 +00:00
Romain Quetiez
cab0eb7758 #297 Fixed SOAP unit tests and improved the reporting when a reconciliation on an external key has failed
SVN:trunk[906]
2010-10-20 13:11:50 +00:00
Romain Quetiez
7e06dd100a #293 Added IP address in the lists of interfaces
SVN:trunk[905]
2010-10-20 10:35:36 +00:00
Denis Flaven
f145b872de - Implemented some hints to help users find out what are the mandatory fields for a CSV import (Trac #276). Though not 100% bullet-proof.
- Continue to implement support of hierarchical ZLists in modification forms.

SVN:trunk[904]
2010-10-19 15:03:24 +00:00
Denis Flaven
b66e489ec8 - Fixed Trac #298: use the proper content-type for CSV files to prevent the let the browser pick the most appropriate application to open such files.
SVN:trunk[903]
2010-10-19 14:15:25 +00:00
Denis Flaven
63da528882 Fixed Trac #245: Search form now retains the base class that was used when displaying the form. After searching a Person it is possible to select "Contact" and perform another search on Contacts.
SVN:trunk[902]
2010-10-19 14:07:14 +00:00
Denis Flaven
ff80b06ea2 - Fixed Trac #284: do not "consume" a transaction until it really worked.
SVN:trunk[901]
2010-10-19 13:42:54 +00:00
Denis Flaven
e9304bbcfa - new implementation (database independent) of the transaction mechanism, that prevents a user from submitting the same form twice.
SVN:trunk[900]
2010-10-19 13:20:23 +00:00
Romain Quetiez
0c34b47aac Fixed regression on the previous fix (change in the prototype of MakeQuery): this was impacting update/delete on a single object => applied to all objects of the same root class!
SVN:trunk[899]
2010-10-19 13:14:19 +00:00
Denis Flaven
484d4d1679 Fix Trac #296: Incorrect display of Service/Subcategory localized characters in the portal.
SVN:trunk[898]
2010-10-19 12:54:13 +00:00
Denis Flaven
4b5a25ea59 Fixed Trac #278: better detection of all PHP mandatory modules.
SVN:trunk[897]
2010-10-19 12:45:48 +00:00
Denis Flaven
7153162696 Fixed Trac #286: incorrect detection of HTTPS on IIS/ISAPI. Thanks to cprobst for reporting it.
SVN:trunk[896]
2010-10-19 12:34:33 +00:00
Romain Quetiez
fb59939d57 #288 Fixed OQL issues, related to multi-columns usages
SVN:trunk[895]
2010-10-14 16:56:42 +00:00
Romain Quetiez
629a87c99b #282 Fixed bug in OQL interpretation (functions requiring class aliasing)
SVN:trunk[894]
2010-10-13 19:51:36 +00:00
Romain Quetiez
3d4e0da019 Typo in dictionary (contract: start datA)
SVN:trunk[893]
2010-10-13 16:54:08 +00:00
Romain Quetiez
1e1e10aa00 #111 Improved the data loader, and added a REST service to load data from a file
SVN:trunk[892]
2010-10-13 16:36:51 +00:00
Romain Quetiez
0fff433e90 #283 Fixed issue with the default value of Enum attributes
SVN:trunk[891]
2010-10-13 08:23:05 +00:00
Romain Quetiez
05dbcb0a8b Fixed limitation: tickets named automatically even if a name is specified (attribute : ref) ; this is stopper when importing tickets from an existing workflow tool
SVN:trunk[890]
2010-10-12 16:04:09 +00:00
Romain Quetiez
bc6a3ab485 Fixed issues in DB integrity check
SVN:trunk[889]
2010-10-06 15:59:33 +00:00
566 changed files with 73743 additions and 16592 deletions

View File

@@ -149,6 +149,7 @@ class UserRightsMatrix extends UserRightsAddOnAPI
return ($oUser->GetKey() == 1);
}
// Deprecated - create a new module !
public function Setup()
{
// Users must be added manually
@@ -273,7 +274,7 @@ class UserRightsMatrix extends UserRightsAddOnAPI
return true;
}
public function GetSelectFilter($oUser, $sClass)
public function GetSelectFilter($oUser, $sClass, $aSettings = array())
{
$oNullFilter = new DBObjectSearch($sClass);
return $oNullFilter;

View File

@@ -42,17 +42,12 @@ class UserRightsNull extends UserRightsAddOnAPI
return true;
}
public function Setup()
{
return true;
}
public function Init()
{
return true;
}
public function GetSelectFilter($oUser, $sClass)
public function GetSelectFilter($oUser, $sClass, $aSettings = array())
{
$oNullFilter = new DBObjectSearch($sClass);
return $oNullFilter;

File diff suppressed because it is too large Load Diff

View File

@@ -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+'));
@@ -119,7 +119,7 @@ class URP_Profiles extends UserRightsBaseClass
$oGrant = $oUserRights->GetClassStimulusGrant($this->GetKey(), $sClass, $sStimulusCode);
if (is_object($oGrant) && ($oGrant->Get('permission') == 'yes'))
{
$aStimuli[] = '<span title="'.$sStimulusCode.': '.htmlentities($oStimulus->GetDescription()).'">'.htmlentities($oStimulus->GetLabel()).'</span>';
$aStimuli[] = '<span title="'.$sStimulusCode.': '.htmlentities($oStimulus->GetDescription(), ENT_QUOTES, 'UTF-8').'">'.htmlentities($oStimulus->GetLabel(), ENT_QUOTES, 'UTF-8').'</span>';
}
}
$sStimuli = implode(', ', $aStimuli);
@@ -658,19 +658,10 @@ class UserRightsProjection extends UserRightsAddOnAPI
// See implementation of userrightsprofile
}
public function Setup()
{
SetupProfiles::ComputeITILProfiles();
//SetupProfiles::ComputeBasicProfiles();
SetupProfiles::DoCreateDimensions();
SetupProfiles::DoCreateProfiles();
return true;
}
public function Init()
{
MetaModel::RegisterPlugin('userrights', 'ACbyProfile', array($this, 'CacheData'));
// CacheData to be invoked in a module extension
//MetaModel::RegisterPlugin('userrights', 'ACbyProfile', array($this, 'CacheData'));
}
protected $m_aDimensions = array(); // id -> object
@@ -743,7 +734,7 @@ exit;
return true;
}
public function GetSelectFilter($oUser, $sClass)
public function GetSelectFilter($oUser, $sClass, $aSettings = array())
{
$aConditions = array();
foreach ($this->m_aDimensions as $iDimension => $oDimension)
@@ -1256,343 +1247,6 @@ exit;
}
}
//
// Create simple profiles into our user management model:
// - administrator
// - readers
// - contributors
//
class SetupProfiles
{
protected static $m_aDimensions = array(
'organization' => array(
'description' => '',
'type' => 'Organization',
),
);
protected static $m_aActions = array(
UR_ACTION_READ => 'Read',
UR_ACTION_MODIFY => 'Modify',
UR_ACTION_DELETE => 'Delete',
UR_ACTION_BULK_READ => 'Bulk Read',
UR_ACTION_BULK_MODIFY => 'Bulk Modify',
UR_ACTION_BULK_DELETE => 'Bulk Delete',
);
// Note: It is possible to specify the same class in several modules
//
protected static $m_aModules = array();
protected static $m_aProfiles = array();
protected static function DoCreateClassProjection($iDimension, $sClass)
{
$oNewObj = MetaModel::NewObject("URP_ClassProjection");
$oNewObj->Set('dimensionid', $iDimension);
$oNewObj->Set('class', $sClass);
$oNewObj->Set('attribute', '');
$iId = $oNewObj->DBInsertNoReload();
return $iId;
}
protected static function DoCreateDimension($sName, $aDimensionData)
{
$oNewObj = MetaModel::NewObject("URP_Dimensions");
$oNewObj->Set('name', $sName);
$oNewObj->Set('description', $aDimensionData['description']);
$oNewObj->Set('type', $aDimensionData['type']);
$iId = $oNewObj->DBInsertNoReload();
return $iId;
}
protected static function DoCreateProfileProjection($iProfile, $iDimension)
{
$oNewObj = MetaModel::NewObject("URP_ProfileProjection");
$oNewObj->Set('profileid', $iProfile);
$oNewObj->Set('dimensionid', $iDimension);
$oNewObj->Set('value', '<any>');
$oNewObj->Set('attribute', '');
$iId = $oNewObj->DBInsertNoReload();
return $iId;
}
protected static function DoCreateActionGrant($iProfile, $iAction, $sClass, $bPermission = true)
{
$oNewObj = MetaModel::NewObject("URP_ActionGrant");
$oNewObj->Set('profileid', $iProfile);
$oNewObj->Set('permission', $bPermission ? 'yes' : 'no');
$oNewObj->Set('class', $sClass);
$oNewObj->Set('action', self::$m_aActions[$iAction]);
$iId = $oNewObj->DBInsertNoReload();
return $iId;
}
protected static function DoCreateStimulusGrant($iProfile, $sStimulusCode, $sClass)
{
$oNewObj = MetaModel::NewObject("URP_StimulusGrant");
$oNewObj->Set('profileid', $iProfile);
$oNewObj->Set('permission', 'yes');
$oNewObj->Set('class', $sClass);
$oNewObj->Set('stimulus', $sStimulusCode);
$iId = $oNewObj->DBInsertNoReload();
return $iId;
}
protected static function DoCreateAdminProfile()
{
$oNewObj = MetaModel::NewObject("URP_Profiles");
$oNewObj->Set('name', 'Administrator');
$oNewObj->Set('description', 'Has the rights on everything (bypassing any control)');
$iNewId = $oNewObj->DBInsertNoReload();
if ($iNewId != ADMIN_PROFILE_ID)
{
throw new CoreException('Admin profile could not be created with its standard id', array('requested'=>ADMIN_PROFILE_ID, 'obtained'=>$iNewId));
}
}
protected static function DoCreateOneProfile($sName, $aProfileData)
{
$sDescription = $aProfileData['description'];
if (strlen(trim($aProfileData['write_modules'])) == 0)
{
$aWriteModules = array();
}
else
{
$aWriteModules = explode(',', trim($aProfileData['write_modules']));
}
$aStimuli = $aProfileData['stimuli'];
$oNewObj = MetaModel::NewObject("URP_Profiles");
$oNewObj->Set('name', $sName);
$oNewObj->Set('description', $sDescription);
$iProfile = $oNewObj->DBInsertNoReload();
// Project in every dimension
//
$oDimensionSet = new DBObjectSet(DBObjectSearch::FromOQL_AllData("SELECT URP_Dimensions"));
while ($oDimension = $oDimensionSet->Fetch())
{
$iDimension = $oDimension->GetKey();
self::DoCreateProfileProjection($iProfile, $iDimension);
}
// Grant read rights for everything
//
foreach (MetaModel::GetClasses('bizmodel') as $sClass)
{
// Skip non instantiable classes
if (MetaModel::IsAbstract($sClass)) continue;
self::DoCreateActionGrant($iProfile, UR_ACTION_READ, $sClass);
self::DoCreateActionGrant($iProfile, UR_ACTION_BULK_READ, $sClass);
}
// Grant write for given modules
// Start by compiling the information, because some modules may overlap
$aWriteableClasses = array();
foreach ($aWriteModules as $sModule)
{
//$oPage->p('Granting write access for the module"'.$sModule.'" - '.count(self::$m_aModules[$sModule]).' classes');
foreach (self::$m_aModules[$sModule] as $sClass)
{
$aWriteableClasses[$sClass] = true;
}
}
foreach ($aWriteableClasses as $sClass => $foo)
{
// Skip non instantiable classes
if (MetaModel::IsAbstract($sClass)) continue;
if (!MetaModel::IsValidClass($sClass))
{
throw new CoreException("Invalid class name '$sClass'");
}
self::DoCreateActionGrant($iProfile, UR_ACTION_MODIFY, $sClass);
self::DoCreateActionGrant($iProfile, UR_ACTION_DELETE, $sClass);
self::DoCreateActionGrant($iProfile, UR_ACTION_BULK_MODIFY, $sClass);
// By default, do not allow bulk deletion operations for standard users
// self::DoCreateActionGrant($iProfile, UR_ACTION_BULK_DELETE, $sClass);
}
// Grant stimuli for given classes
foreach ($aStimuli as $sClass => $sAllowedStimuli)
{
if (!MetaModel::IsValidClass($sClass))
{
// Could be a class defined in a module that wasn't installed
continue;
//throw new CoreException("Invalid class name '$sClass'");
}
if ($sAllowedStimuli == 'any')
{
$aAllowedStimuli = array_keys(MetaModel::EnumStimuli($sClass));
}
elseif ($sAllowedStimuli == 'none')
{
$aAllowedStimuli = array();
}
else
{
$aAllowedStimuli = explode(',', $sAllowedStimuli);
}
foreach ($aAllowedStimuli as $sStimulusCode)
{
self::DoCreateStimulusGrant($iProfile, $sStimulusCode, $sClass);
}
}
}
public static function DoCreateDimensions()
{
$aClass = MetaModel::GetClasses();
foreach(self::$m_aDimensions as $sName => $aDimensionData)
{
$iDimension = self::DoCreateDimension($sName, $aDimensionData);
foreach($aClass as $sClass)
{
// Skip non instantiable classes
if (MetaModel::IsAbstract($sClass)) continue;
if (!MetaModel::IsValidClass($sClass))
{
throw new CoreException("Invalid class name '$sClass'");
}
self::DoCreateClassProjection($iDimension, $sClass);
}
}
}
public static function DoCreateProfiles()
{
self::DoCreateAdminProfile();
foreach(self::$m_aProfiles as $sName => $aProfileData)
{
self::DoCreateOneProfile($sName, $aProfileData);
}
}
public static function ComputeBasicProfiles()
{
// In this profiling scheme, one single module represents all the classes
//
self::$m_aModules = array(
'UserData' => MetaModel::GetClasses('bizmodel'),
);
self::$m_aProfiles = array(
'Reader' => array(
'description' => 'Person having a ready-only access to the data',
'write_modules' => '',
'stimuli' => array(
),
),
'Writer' => array(
'description' => 'Contributor to the contents (read + write access)',
'write_modules' => 'UserData',
'stimuli' => array(
// any class => 'any'
),
),
);
}
public static function ComputeITILProfiles()
{
// In this profiling scheme, modules are based on ITIL recommendations
//
self::$m_aModules = array(
/*
'WriteModule' => array(
'someclass',
'anotherclass',
),
*/
'General' => MetaModel::GetClasses('structure'),
'Documentation' => MetaModel::GetClasses('documentation'),
'Configuration' => MetaModel::GetClasses('configmgmt'),
'Incident' => MetaModel::GetClasses('incidentmgmt'),
'Problem' => MetaModel::GetClasses('problemmgmt'),
'Change' => MetaModel::GetClasses('changemgmt'),
'Service' => MetaModel::GetClasses('servicemgmt'),
'Call' => MetaModel::GetClasses('requestmgmt'),
'KnownError' => MetaModel::GetClasses('knownerrormgmt'),
);
self::$m_aProfiles = array(
'Configuration Manager' => array(
'description' => 'Person in charge of the documentation of the managed CIs',
'write_modules' => 'General,Documentation,Configuration',
'stimuli' => array(
//'bizServer' => 'none',
//'bizContract' => 'none',
//'bizIncidentTicket' => 'none',
//'bizChangeTicket' => 'any',
),
),
'Service Desk Agent' => array(
'description' => 'Person in charge of creating incident reports',
'write_modules' => 'Incident,Call',
'stimuli' => array(
'Incident' => 'ev_assign',
'UserRequest' => 'ev_assign',
),
),
'Support Agent' => array(
'description' => 'Person analyzing and solving the current incidents or problems',
'write_modules' => 'Incident,Problem,KnownError',
'stimuli' => array(
'Incident' => 'ev_assign,ev_reassign,ev_resolve,ev_close',
'UserRequest' => 'ev_assign,ev_reassign,ev_resolve,ev_close,ev_freeze',
),
),
'Change Implementor' => array(
'description' => 'Person executing the changes',
'write_modules' => 'Change',
'stimuli' => array(
'NormalChange' => 'ev_plan,ev_replan,ev_implement,ev_monitor',
'EmergencyChange' => 'ev_plan,ev_replan,ev_implement,ev_monitor',
'RoutineChange' => 'ev_plan,ev_replan,ev_implement,ev_monitor',
),
),
'Change Supervisor' => array(
'description' => 'Person responsible for the overall change execution',
'write_modules' => 'Change',
'stimuli' => array(
'NormalChange' => 'ev_validate,ev_reject,ev_assign,ev_reopen,ev_finish',
'EmergencyChange' => 'ev_assign,ev_reopen,ev_finish',
'RoutineChange' => 'ev_assign,ev_reopen,ev_finish',
),
),
'Change Approver' => array(
'description' => 'Person who could be impacted by some changes',
'write_modules' => 'Change',
'stimuli' => array(
'NormalChange' => 'ev_approve,ev_notapprove',
'EmergencyChange' => 'ev_approve,ev_notapprove',
'RoutineChange' => 'none',
),
),
'Service Manager' => array(
'description' => 'Person responsible for the service delivered to the [internal] customer',
'write_modules' => 'Service',
'stimuli' => array(
),
),
'Document author' => array(
'description' => 'Any person who could contribute to documentation',
'write_modules' => 'Documentation',
'stimuli' => array(
),
),
);
}
}
UserRights::SelectModule('UserRightsProjection');

View File

@@ -24,7 +24,7 @@
* @license http://www.opensource.org/licenses/gpl-3.0.html LGPL
*/
require_once("../application/webpage.class.inc.php");
require_once(APPROOT."/application/webpage.class.inc.php");
class ajax_page extends WebPage
{
@@ -33,6 +33,9 @@ class ajax_page extends WebPage
* @var Hash
*/
protected $m_sReadyScript;
protected $m_sCurrentTab;
protected $m_sCurrentTabContainer;
protected $m_aTabs;
/**
* constructor for the web page
@@ -42,10 +45,53 @@ 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 = '')
{
$this->m_aTabs[$sTabContainer] = array('content' =>'', 'prefix' => $sPrefix);
$this->add("\$Tabs:$sTabContainer\$");
}
public function AddToTab($sTabContainer, $sTabLabel, $sHtml)
{
if (!isset($this->m_aTabs[$sTabContainer]['content'][$sTabLabel]))
{
// Set the content of the tab
$this->m_aTabs[$sTabContainer]['content'][$sTabLabel] = $sHtml;
}
else
{
// Append to the content of the tab
$this->m_aTabs[$sTabContainer]['content'][$sTabLabel] .= $sHtml;
}
}
public function SetCurrentTabContainer($sTabContainer = '')
{
$sPreviousTabContainer = $this->m_sCurrentTabContainer;
$this->m_sCurrentTabContainer = $sTabContainer;
return $sPreviousTabContainer;
}
public function SetCurrentTab($sTabLabel = '')
{
$sPreviousTab = $this->m_sCurrentTab;
$this->m_sCurrentTab = $sTabLabel;
return $sPreviousTab;
}
public function GetCurrentTab()
{
return $this->m_sCurrentTab;
}
/**
* Echoes the content of the whole page
@@ -53,22 +99,117 @@ class ajax_page extends WebPage
*/
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(
<<<EOF
// The "tab widgets" to handle.
var tabs = $('div[id^=tabbedContent]');
// This selector will be reused when selecting actual tab widget A elements.
var tab_a_selector = 'ul.ui-tabs-nav a';
// Enable tabs on all tab widgets. The `event` property must be overridden so
// that the tabs aren't changed on click, and any custom event name can be
// specified. Note that if you define a callback for the 'select' event, it
// will be executed for the selected tab whenever the hash changes.
tabs.tabs({ event: 'change' });
// Define our own click handler for the tabs, overriding the default.
tabs.find( tab_a_selector ).click(function()
{
var state = {};
// Get the id of this tab widget.
var id = $(this).closest( 'div[id^=tabbedContent]' ).attr( 'id' );
// Get the index of this tab.
var idx = $(this).parent().prevAll().length;
// Set the state!
state[ id ] = idx;
$.bbq.pushState( state );
});
EOF
);
}
// Render the tabs in the page (if any)
foreach($this->m_aTabs as $sTabContainerName => $aTabContainer)
{
$sTabs = '';
$m_aTabs = $aTabContainer['content'];
$sPrefix = $aTabContainer['prefix'];
$container_index = 0;
if (count($m_aTabs) > 0)
{
$sTabs = "<!-- tabs -->\n<div id=\"tabbedContent_{$sPrefix}{$container_index}\" class=\"light\">\n";
$sTabs .= "<ul>\n";
// Display the unordered list that will be rendered as the tabs
$i = 0;
foreach($m_aTabs as $sTabName => $sTabContent)
{
$sTabs .= "<li><a href=\"#tab_{$sPrefix}$i\" class=\"tab\"><span>".htmlentities($sTabName, ENT_QUOTES, 'UTF-8')."</span></a></li>\n";
$i++;
}
$sTabs .= "</ul>\n";
// Now add the content of the tabs themselves
$i = 0;
foreach($m_aTabs as $sTabName => $sTabContent)
{
$sTabs .= "<div id=\"tab_{$sPrefix}$i\">".$sTabContent."</div>\n";
$i++;
}
$sTabs .= "</div>\n<!-- end of tabs-->\n";
}
$this->s_content = str_replace("\$Tabs:$sTabContainerName\$", $sTabs, $this->s_content);
$container_index++;
}
$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)
{
echo "<script type=\"text/javascript\">\n";
echo implode("\n", $this->a_scripts);
echo "\n</script>\n";
}
if (!empty($this->s_deferred_content))
{
echo "<script type=\"text/javascript\">\n";
echo "\$('body').append('".addslashes(str_replace("\n", '', $this->s_deferred_content))."');\n";
echo "\n</script>\n";
}
if (!empty($this->m_sReadyScript))
{
echo "<script>\n";
echo "<script type=\"text/javascript\">\n";
echo $this->m_sReadyScript; // Ready Scripts are output as simple scripts
echo "</script>\n";
echo "\n</script>\n";
}
if (trim($s_captured_output) != "")
{
echo $s_captured_output;
echo self::FilterXSS($s_captured_output);
}
}
@@ -81,6 +222,76 @@ class ajax_page extends WebPage
public function small_p($sText)
{
}
public function add($sHtml)
{
if (!empty($this->m_sCurrentTabContainer) && !empty($this->m_sCurrentTab))
{
$this->AddToTab($this->m_sCurrentTabContainer, $this->m_sCurrentTab, $sHtml);
}
else
{
parent::add($sHtml);
}
}
/**
* Records the current state of the 'html' part of the page output
* @return mixed The current state of the 'html' output
*/
public function start_capture()
{
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)
@@ -89,11 +300,23 @@ class ajax_page extends WebPage
*/
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;
}
/**
* Cannot be called in this context, since Ajax pages do not share
* any context with the calling page !!
*/
public function GetUniqueId()
{
assert(false);
return 0;
}
public static function FilterXSS($sHTML)
{
return str_ireplace(array('<script', '</script>'), array('<!-- <removed-script', '</removed-script> -->'), $sHTML);
}
}
?>

View File

@@ -23,13 +23,15 @@
* @license http://www.opensource.org/licenses/gpl-3.0.html LGPL
*/
require_once('../application/applicationcontext.class.inc.php');
require_once('../application/cmdbabstract.class.inc.php');
require_once('../application/displayblock.class.inc.php');
require_once('../application/audit.category.class.inc.php');
require_once('../application/audit.rule.class.inc.php');
//require_once('../application/menunode.class.inc.php');
require_once('../application/utils.inc.php');
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');
class ApplicationException extends CoreException
{

View File

@@ -23,7 +23,44 @@
* @license http://www.opensource.org/licenses/gpl-3.0.html LGPL
*/
require_once("../application/utils.inc.php");
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,22 +95,56 @@ class ApplicationContext
*/
protected function ReadContext()
{
if (empty(self::$aDefaultValues))
if (!isset(self::$aDefaultValues))
{
self::$aDefaultValues = array();
$aContext = utils::ReadParam('c', array());
foreach($this->aNames as $sName)
{
$sValue = utils::ReadParam($sName, '');
$sValue = isset($aContext[$sName]) ? $aContext[$sName] : '';
// TO DO: check if some of the context parameters are mandatory (or have default values)
if (!empty($sValue))
{
self::$aDefaultValues[$sName] = $sValue;
}
// Hmm, there must be a better (more generic) way to handle the case below:
// When there is only one possible (allowed) organization, the context must be
// fixed to this org
if ($sName == 'org_id')
{
if (MetaModel::IsValidClass('Organization'))
{
$oSearchFilter = new DBObjectSearch('Organization');
$oSearchFilter->SetModifierProperty('UserRightsGetSelectFilter', 'bSearchMode', true);
$oSet = new CMDBObjectSet($oSearchFilter);
$iCount = $oSet->Count();
if ($iCount == 1)
{
// Only one possible value for org_id, set it in the context
$oOrg = $oSet->Fetch();
self::$aDefaultValues[$sName] = $oOrg->GetKey();
}
}
}
}
}
$this->aValues = self::$aDefaultValues;
}
/**
* Returns the current value for the given parameter
* @param string $sParamName Name of the parameter to read
* @return mixed The value for this parameter
*/
public function GetCurrentValue($sParamName, $defaultValue = '')
{
if (isset($this->aValues[$sParamName]))
{
return $this->aValues[$sParamName];
}
return $defaultValue;
}
/**
* Returns the context as string with the format name1=value1&name2=value2....
* return string The context as a string to be appended to an href property
@@ -79,7 +154,7 @@ class ApplicationContext
$aParams = array();
foreach($this->aValues as $sName => $sValue)
{
$aParams[] = $sName.'='.urlencode($sValue);
$aParams[] = "c[$sName]".'='.urlencode($sValue);
}
return implode("&", $aParams);
}
@@ -93,7 +168,7 @@ class ApplicationContext
$sContext = "";
foreach($this->aValues as $sName => $sValue)
{
$sContext .= "<input type=\"hidden\" name=\"$sName\" value=\"$sValue\" />\n";
$sContext .= "<input type=\"hidden\" name=\"c[$sName]\" value=\"".htmlentities($sValue, ENT_QUOTES, 'UTF-8')."\" />\n";
}
return $sContext;
}
@@ -104,7 +179,12 @@ class ApplicationContext
*/
public function GetAsHash()
{
return $this->aValues;
$aReturn = array();
foreach($this->aValues as $sName => $sValue)
{
$aReturn["c[$sName]"] = $sValue;
}
return $aReturn;
}
/**
@@ -128,5 +208,154 @@ 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 '';
}
}
protected static $m_aPluginProperties = null;
/**
* Load plugin properties for the current session
* @return void
*/
protected static function LoadPluginProperties()
{
if (isset($_SESSION['PluginProperties']))
{
self::$m_aPluginProperties = $_SESSION['PluginProperties'];
}
else
{
self::$m_aPluginProperties = array();
}
}
/**
* Set plugin properties
* @param sPluginClass string Class implementing any plugin interface
* @param sProperty string Name of the property
* @param value scalar Value (numeric or string)
* @return void
*/
public static function SetPluginProperty($sPluginClass, $sProperty, $value)
{
if (is_null(self::$m_aPluginProperties)) self::LoadPluginProperties();
self::$m_aPluginProperties[$sPluginClass][$sProperty] = $value;
$_SESSION['PluginProperties'][$sPluginClass][$sProperty] = $value;
}
/**
* Get plugin properties
* @param sPluginClass string Class implementing any plugin interface
* @return array of sProperty=>value pairs
*/
public static function GetPluginProperties($sPluginClass)
{
if (is_null(self::$m_aPluginProperties)) self::LoadPluginProperties();
if (array_key_exists($sPluginClass, self::$m_aPluginProperties))
{
return self::$m_aPluginProperties[$sPluginClass];
}
else
{
return array();
}
}
}
?>

View File

@@ -0,0 +1,51 @@
<?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
/**
* Class iPlugin
* Management of application plugin
*
* @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
*/
interface iApplicationUIExtension
{
public function OnDisplayProperties($oObject, WebPage $oPage, $bEditMode = false);
public function OnDisplayRelations($oObject, WebPage $oPage, $bEditMode = false);
public function OnFormSubmit($oObject, $sFormPrefix = '');
public function OnFormCancel($sTempId); // temp id is made of session_id and transaction_id, it identifies the object in a unique way
public function EnumUsedAttributes($oObject); // Not yet implemented
public function GetIcon($oObject); // Not yet implemented
public function GetHilightClass($oObject);
public function EnumAllowedActions(DBObjectSet $oSet);
}
interface iApplicationObjectExtension
{
public function OnIsModified($oObject);
public function OnCheckToWrite($oObject);
public function OnCheckToDelete($oObject);
public function OnDBUpdate($oObject, $oChange = null);
public function OnDBInsert($oObject, $oChange = null);
public function OnDBDelete($oObject, $oChange = null);
}
?>

View File

@@ -25,7 +25,7 @@
* @license http://www.opensource.org/licenses/gpl-3.0.html LGPL
*/
require_once('../application/cmdbabstract.class.inc.php');
require_once(APPROOT.'/application/cmdbabstract.class.inc.php');
class AuditCategory extends cmdbAbstractObject
{

View File

@@ -26,7 +26,7 @@
* @license http://www.opensource.org/licenses/gpl-3.0.html LGPL
*/
require_once('../application/audit.category.class.inc.php');
require_once(APPROOT.'/application/audit.category.class.inc.php');
class AuditRule extends cmdbAbstractObject
{

View File

@@ -0,0 +1,88 @@
<?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
/**
* CLI page
* The page adds the content-type text/XML and the encoding into the headers
*
* @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");
class CLIPage
{
function __construct($s_title)
{
}
public function output()
{
}
public function add($sText)
{
echo $sText;
}
public function p($sText)
{
echo $sText."\n";
}
public function pre($sText)
{
echo $sText."\n";
}
public function add_comment($sText)
{
echo "#".$sText."\n";
}
public function table($aConfig, $aData, $aParams = array())
{
$aCells = array();
foreach($aConfig as $sName=>$aDef)
{
if (strlen($aDef['description']) > 0)
{
$aCells[] = $aDef['label'].' ('.$aDef['description'].')';
}
else
{
$aCells[] = $aDef['label'];
}
}
echo implode(';', $aCells)."\n";
foreach($aData as $aRow)
{
$aCells = array();
foreach($aConfig as $sName=>$aAttribs)
{
$sValue = $aRow["$sName"];
$aCells[] = $sValue;
}
echo implode(';', $aCells)."\n";
}
}
}
?>

File diff suppressed because it is too large Load Diff

View File

@@ -24,14 +24,14 @@
* @license http://www.opensource.org/licenses/gpl-3.0.html LGPL
*/
require_once("../application/webpage.class.inc.php");
require_once(APPROOT."/application/webpage.class.inc.php");
class CSVPage extends WebPage
{
function __construct($s_title)
{
parent::__construct($s_title);
$this->add_header("Content-type: text/html; charset=iso-8859-1");
$this->add_header("Content-type: text/html; charset=utf-8");
$this->add_header("Cache-control: no-cache");
}

View File

@@ -23,8 +23,8 @@
* @license http://www.opensource.org/licenses/gpl-3.0.html LGPL
*/
require_once('../application/webpage.class.inc.php');
require_once('../application/utils.inc.php');
require_once(APPROOT.'/application/webpage.class.inc.php');
require_once(APPROOT.'/application/utils.inc.php');
/**
* Helper class to manage 'blocks' of HTML pieces that are parts of a page and contain some list of cmdb objects
*
@@ -178,43 +178,13 @@ 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())
{
$sHtml = '';
$aExtraParams = array_merge($aExtraParams, $this->m_aParams);
$aExtraParams['block_id'] = $sId;
$aExtraParams['currentId'] = $sId;
$sExtraParams = addslashes(str_replace('"', "'", json_encode($aExtraParams))); // JSON encode, change the style of the quotes and escape them
$bAutoReload = false;
@@ -224,14 +194,14 @@ class DisplayBlock
{
case 'fast':
$bAutoReload = true;
$iReloadInterval = utils::GetConfig()->GetFastReloadInterval()*1000;
$iReloadInterval = MetaModel::GetConfig()->GetFastReloadInterval()*1000;
break;
case 'standard':
case 'true':
case true:
$bAutoReload = true;
$iReloadInterval = utils::GetConfig()->GetStandardReloadInterval()*1000;
$iReloadInterval = MetaModel::GetConfig()->GetStandardReloadInterval()*1000;
break;
default:
@@ -253,7 +223,7 @@ class DisplayBlock
{
// render now
$sHtml .= "<div id=\"$sId\" class=\"display_block\">\n";
$sHtml .= $this->GetRenderContent($oPage, $aExtraParams);
$sHtml .= $this->GetRenderContent($oPage, $aExtraParams, $sId);
$sHtml .= "</div>\n";
}
else
@@ -262,51 +232,38 @@ 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;
}
public function RenderContent(WebPage $oPage, $aExtraParams = array())
{
$oPage->add($this->GetRenderContent($oPage, $aExtraParams));
if (empty($aExtraParams['currentId']))
{
$sId = $oPage->GetUniqueId(); // Works only if the page is not an Ajax one !
}
else
{
$sId = $aExtraParams['currentId'];
}
$oPage->add($this->GetRenderContent($oPage, $aExtraParams, $sId));
}
public function GetRenderContent(WebPage $oPage, $aExtraParams = array())
public function GetRenderContent(WebPage $oPage, $aExtraParams = array(), $sId)
{
$sHtml = '';
// Add the extra params into the filter if they make sense for such a filter
@@ -320,21 +277,67 @@ class DisplayBlock
}
if ($this->m_sStyle != 'links')
{
$aFilterCodes = array_keys(MetaModel::GetClassFilterDefs($this->m_oFilter->GetClass()));
$oAppContext = new ApplicationContext();
$sClass = $this->m_oFilter->GetClass();
$aFilterCodes = array_keys(MetaModel::GetClassFilterDefs($sClass));
$aCallSpec = array($sClass, 'MapContextParam');
foreach($oAppContext->GetNames() as $sContextParam)
{
$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);
if (!is_null($sParamValue))
{
$aExtraParams[$sParamCode] = $sParamValue;
}
}
}
foreach($aFilterCodes as $sFilterCode)
{
$sExternalFilterValue = utils::ReadParam($sFilterCode, '');
$sExternalFilterValue = utils::ReadParam($sFilterCode, '', false, 'raw_data');
$condition = null;
if (isset($aExtraParams[$sFilterCode]))
{
$this->m_oFilter->AddCondition($sFilterCode, trim($aExtraParams[$sFilterCode])); // Use the default 'loose' operator
$condition = $aExtraParams[$sFilterCode];
}
else if ($bDoSearch && $sExternalFilterValue != "")
// else if ($bDoSearch && $sExternalFilterValue != "")
if ($bDoSearch && $sExternalFilterValue != "")
{
$this->m_oFilter->AddCondition($sFilterCode, trim($sExternalFilterValue)); // Use the default 'loose' operator
// Search takes precedence over context params...
unset($aExtraParams[$sFilterCode]);
$condition = trim($sExternalFilterValue);
}
if (!is_null($condition))
{
$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)
{
@@ -344,9 +347,21 @@ 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())
{
$sValue = $oObj->Get($sGroupByField);
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;
$sLabels[$sValue] = $oObj->GetAsHtml($sGroupByField);
}
@@ -357,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
@@ -410,7 +427,15 @@ class DisplayBlock
$aKeys = array();
foreach($aGroupByFields as $aField)
{
$aKeys[$aField['alias'].'.'.$aField['att_code']] = $aObjects[$aField['alias']]->Get($aField['att_code']);
$sAlias = $aField['alias'];
if (is_null($aObjects[$sAlias]))
{
$aKeys[$sAlias.'.'.$aField['att_code']] = '';
}
else
{
$aKeys[$sAlias.'.'.$aField['att_code']] = $aObjects[$sAlias]->Get($aField['att_code']);
}
}
$sCategory = implode($aKeys, ' ');
$aResults[$sCategory][] = $aObjects;
@@ -438,7 +463,11 @@ class DisplayBlock
$aSimpleArray = array();
foreach($aObjects as $aRow)
{
$aSimpleArray[] = $aRow[$aDisplayAliases[0]];
$oObj = $aRow[$aDisplayAliases[0]];
if (!is_null($oObj))
{
$aSimpleArray[] = $oObj;
}
}
$oSet = CMDBObjectSet::FromArray($this->m_oFilter->GetClass(), $aSimpleArray);
$sHtml .= "<tr><td>".cmdbAbstractObject::GetDisplaySet($oPage, $oSet, $aExtraParams)."</td></tr>\n";
@@ -524,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");
}
}
}
@@ -560,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");
}
}
}
@@ -582,10 +611,10 @@ class DisplayBlock
$aFilterCodes = array_keys(MetaModel::GetClassFilterDefs($this->m_oFilter->GetClass()));
foreach($oAppContext->GetNames() as $sFilterCode)
{
$sContextParamValue = trim(utils::ReadParam($sFilterCode, null));
$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();
@@ -596,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&filter='.$this->m_oFilter->serialize();
$sHyperlink = utils::GetAbsoluteUrlAppRoot().'pages/UI.php?operation=search&'.$oAppContext->GetForLink().'&filter='.$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>';
@@ -604,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;
@@ -624,10 +653,10 @@ class DisplayBlock
$aFilterCodes = array_keys(MetaModel::GetClassFilterDefs($this->m_oFilter->GetClass()));
foreach($oAppContext->GetNames() as $sFilterCode)
{
$sContextParamValue = trim(utils::ReadParam($sFilterCode, null));
$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();
@@ -650,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&filter='.$oFilter->serialize();
$sHyperlink = utils::GetAbsoluteUrlAppRoot().'pages/UI.php?operation=search&'.$oAppContext->GetForLink().'&filter='.$oFilter->serialize();
$aCounts[$sStateValue] = "<a href=\"$sHyperlink\">{$aCounts[$sStateValue]}</a>";
}
}
@@ -666,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&filter='.$this->m_oFilter->serialize();
$sHyperlink = utils::GetAbsoluteUrlAppRoot().'pages/UI.php?operation=search&'.$oAppContext->GetForLink().'&filter='.$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);
@@ -695,40 +717,91 @@ class DisplayBlock
break;
case 'search':
static $iSearchSectionId = 1;
$sStyle = (isset($aExtraParams['open']) && ($aExtraParams['open'] == 'true')) ? 'SearchDrawer' : 'SearchDrawer DrawerClosed';
$sHtml .= "<div id=\"Search_$iSearchSectionId\" class=\"$sStyle\">\n";
$sHtml .= "<div id=\"ds_$sId\" class=\"$sStyle\">\n";
$oPage->add_ready_script(
<<<EOF
$("#LnkSearch_$iSearchSectionId").click( function() {
$("#Search_$iSearchSectionId").slideToggle('normal', function() { $("#Search_$iSearchSectionId").parent().resize(); } );
$("#LnkSearch_$iSearchSectionId").toggleClass('open');
$("#dh_$sId").click( function() {
$("#ds_$sId").slideToggle('normal', function() { $("#ds_$sId").parent().resize(); } );
$("#dh_$sId").toggleClass('open');
});
EOF
);
$aExtraParams['currentId'] = $sId;
$sHtml .= cmdbAbstractObject::GetSearchForm($oPage, $this->m_oSet, $aExtraParams);
$sHtml .= "</div>\n";
$sHtml .= "<div class=\"HRDrawer\"></div>\n";
$sHtml .= "<div id=\"LnkSearch_$iSearchSectionId\" class=\"DrawerHandle\">".Dict::S('UI:SearchToggle')."</div>\n";
$iSearchSectionId++;
$sHtml .= "<div id=\"dh_$sId\" class=\"DrawerHandle\">".Dict::S('UI:SearchToggle')."</div>\n";
break;
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'] : '';
$sGroupByExpr = isset($aExtraParams['group_by_expr']) ? '&params[group_by_expr]='.$aExtraParams['group_by_expr'] : '';
$sFilter = $this->m_oFilter->serialize();
$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&params[group_by]=$sGroupBy&params[chart_type]=$sChartType&params[chart_title]=$sTitle&filter=".$sFilter)."\"}, {wmode: 'transparent'} );\n");
{\"data-file\":\"".urlencode(utils::GetAbsoluteUrlAppRoot()."pages/ajax.render.php?operation=open_flash_chart&params[group_by]=$sGroupBy{$sGroupByExpr}&params[chart_type]=$sChartType&params[chart_title]=$sTitle&params[currentId]=$sId&id=$sId&filter=".$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':
include '../pages/php-ofc-library/open-flash-chart.php';
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)
@@ -742,18 +815,28 @@ EOF
$aGroupBy = array();
while($oObj = $this->m_oSet->Fetch())
{
$sValue = $oObj->Get($sGroupByField);
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();
$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;
@@ -798,14 +881,23 @@ EOF
$aGroupBy = array();
while($oObj = $this->m_oSet->Fetch())
{
$sValue = $oObj->Get($sGroupByField);
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();
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;
}
@@ -830,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
}
}
}
/**
@@ -845,7 +974,7 @@ EOF
*/
class HistoryBlock extends DisplayBlock
{
public function GetRenderContent(WebPage $oPage, $aExtraParams = array())
public function GetRenderContent(WebPage $oPage, $aExtraParams = array(), $sId)
{
$sHtml = '';
$oSet = new CMDBObjectSet($this->m_oFilter, array('date'=>false));
@@ -909,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;
@@ -927,16 +1056,22 @@ class MenuBlock extends DisplayBlock
* an object in with the same tab active by default as the tab that was active when selecting
* the "Modify..." action.
*/
public function GetRenderContent(WebPage $oPage, $aExtraParams = array())
public function GetRenderContent(WebPage $oPage, $aExtraParams = array(), $sId)
{
$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']))
{
@@ -950,12 +1085,12 @@ class MenuBlock extends DisplayBlock
$sDefault.= "&default[$sKey]=$sValue";
}
}
$bIsCreationAllowed = (UserRights::IsActionAllowed($sClass, UR_ACTION_MODIFY) == UR_ALLOWED_YES);
switch($oSet->Count())
{
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 ($bIsCreationAllowed) { $aActions['UI:Menu:New'] = array ('label' => Dict::S('UI:Menu:New'), 'url' => "{$sRootUrl}pages/$sUIPage?operation=new&class=$sClass{$sContext}{$sDefault}"); }
break;
case 1:
@@ -968,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 ($bIsCreationAllowed) { $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:
@@ -999,23 +1133,23 @@ 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");
$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=$sFilter&format=csv{$sContext}");
}
else
$this->AddMenuSeparator($aActions);
foreach (MetaModel::EnumPlugins('iApplicationUIExtension') as $oExtensionInstance)
{
// 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"); }
$oSet->Rewind();
foreach($oExtensionInstance->EnumAllowedActions($oSet) as $sLabel => $sUrl)
{
$aActions[$sLabel] = array ('label' => $sLabel, 'url' => $sUrl);
}
}
break;
@@ -1032,36 +1166,131 @@ 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' => 'Modify All...', 'url' => "../pages/$sUIPage?operation=modify_all&filter=$sFilter&$sContext"); }
if ($bIsBulkDeleteAllowed) { $aActions[] = array ('label' => Dict::S('UI:Menu:BulkDelete'), 'url' => "../pages/$sUIPage?operation=select_for_deletion&filter=$sFilter&$sContext"); }
if ($bIsCreationAllowed) { $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=$sFilter{$sContext}"); }
if ($bIsBulkDeleteAllowed) { $aActions['UI:Menu:BulkDelete'] = array ('label' => Dict::S('UI:Menu:BulkDelete'), 'url' => "{$sRootUrl}pages/$sUIPage?operation=select_for_deletion&filter=$sFilter{$sContext}"); }
// Stimuli
$aStates = MetaModel::EnumStates($sClass);
// 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();
$aStates = array();
while($oObj = $oSet->Fetch())
{
$aStates[$oObj->GetState()] = $oObj->GetState();
}
$oSet->Rewind();
if (count($aStates) == 1)
{
// All objects are in the same state...
$sState = array_pop($aStates);
$aTransitions = Metamodel::EnumTransitions($sClass, $sState);
if (count($aTransitions))
{
$this->AddMenuSeparator($aActions);
$aStimuli = Metamodel::EnumStimuli($sClass);
foreach($aTransitions as $sStimulusCode => $aTransitionDef)
{
$oChecker = new StimulusChecker($this->m_oFilter, $sState, $sStimulusCode);
$iActionAllowed = (get_class($aStimuli[$sStimulusCode]) == 'StimulusUserAction') ? $oChecker->IsAllowed() : UR_ALLOWED_NO;
switch($iActionAllowed)
{
case UR_ALLOWED_YES:
case UR_ALLOWED_DEPENDS:
$aActions[$sStimulusCode] = array('label' => $aStimuli[$sStimulusCode]->GetLabel(), 'url' => "{$sRootUrl}pages/UI.php?operation=select_bulk_stimulus&stimulus=$sStimulusCode&state=$sState&class=$sClass&filter=$sFilter{$sContext}");
break;
default:
// Do nothing
}
}
}
}
}
$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=$sFilter{$sContext}"));
$aActions['UI:Menu:CSVExport'] = array ('label' => Dict::S('UI:Menu:CSVExport'), 'url' => "{$sRootUrl}pages/$sUIPage?operation=search&filter=$sFilter&format=csv{$sContext}");
}
$this->AddMenuSeparator($aActions);
foreach (MetaModel::EnumPlugins('iApplicationUIExtension') as $oExtensionInstance)
{
$oSet->Rewind();
foreach($oExtensionInstance->EnumAllowedActions($oSet) as $sLabel => $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)
{
@@ -1082,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' => '');
}
}
}

View File

@@ -23,7 +23,7 @@
* @license http://www.opensource.org/licenses/gpl-3.0.html LGPL
*/
require_once('../application/cmdbabstract.class.inc.php');
require_once(APPROOT.'/application/cmdbabstract.class.inc.php');
/**
* This class manages the input/output tasks

File diff suppressed because it is too large Load Diff

View File

@@ -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();
}

View File

@@ -23,15 +23,18 @@
* @license http://www.opensource.org/licenses/gpl-3.0.html LGPL
*/
require_once("../application/nicewebpage.class.inc.php");
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");
parent::__construct(Dict::S("UI:iTopLogin"));
$this->add_style(<<<EOF
body {
background: #eee;
@@ -68,6 +71,10 @@ body {
border-left: 1px solid #000;
border-right: 1px solid #000;
border-top: 0;
text-align: center;
}
#pwd, #user,#old_pwd, #new_pwd, #retype_new_pwd {
width: 10em;
}
.center {
text-align: center;
@@ -84,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));
@@ -99,29 +117,37 @@ 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.png\"></a></div>\n");
$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");
$this->add("<div id=\"login\">\n");
$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
{
$this->add("<p>".Dict::S('UI:Login:IdentifyYourself')."</p>\n");
}
$this->add("<form method=\"post\">\n");
$this->add("<table>\n");
$this->add("<tr><td><label for=\"user\">".Dict::S('UI:Login:UserNamePrompt').":</label></td><td><input id=\"user\" type=\"text\" name=\"auth_user\" value=\"$sAuthUser\" /></td></tr>\n");
$this->add("<tr><td><label for=\"pwd\">".Dict::S('UI:Login:PasswordPrompt').":</label></td><td><input id=\"pwd\" type=\"password\" name=\"auth_pwd\" value=\"$sAuthPwd\" /></td></tr>\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=\"".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;
}
@@ -129,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');
@@ -159,10 +184,10 @@ EOF
$this->add("<p class=\"hilite\">".Dict::S('UI:Login:IncorrectOldPassword')."</p>\n");
}
$this->add("<form method=\"post\">\n");
$this->add("<table>\n");
$this->add("<tr><td><label for=\"old_pwd\">".Dict::S('UI:Login:OldPasswordPrompt').":</label></td><td><input type=\"password\" id=\"old_pwd\" name=\"old_pwd\" value=\"\" /></td></tr>\n");
$this->add("<tr><td><label for=\"new_pwd\">".Dict::S('UI:Login:NewPasswordPrompt').":</label></td><td><input type=\"password\" id=\"new_pwd\" name=\"new_pwd\" value=\"\" /></td></tr>\n");
$this->add("<tr><td><label for=\"retype_new_pwd\">".Dict::S('UI:Login:RetypeNewPasswordPrompt').":</label></td><td><input type=\"password\" id=\"retype_new_pwd\" name=\"retype_new_pwd\" value=\"\" /></td></tr>\n");
$this->add("<table width=\"100%\">\n");
$this->add("<tr><td style=\"text-align:right\"><label for=\"old_pwd\">".Dict::S('UI:Login:OldPasswordPrompt').":</label></td><td style=\"text-align:left\"><input type=\"password\" id=\"old_pwd\" name=\"old_pwd\" value=\"\" /></td></tr>\n");
$this->add("<tr><td style=\"text-align:right\"><label for=\"new_pwd\">".Dict::S('UI:Login:NewPasswordPrompt').":</label></td><td style=\"text-align:left\"><input type=\"password\" id=\"new_pwd\" name=\"new_pwd\" value=\"\" /></td></tr>\n");
$this->add("<tr><td style=\"text-align:right\"><label for=\"retype_new_pwd\">".Dict::S('UI:Login:RetypeNewPasswordPrompt').":</label></td><td style=\"text-align:left\"><input type=\"password\" id=\"retype_new_pwd\" name=\"retype_new_pwd\" value=\"\" /></td></tr>\n");
$this->add("<tr><td colspan=\"2\" class=\"center v-spacer\"> <input type=\"button\" onClick=\"GoBack();\" value=\"".Dict::S('UI:Button:Cancel')."\" />&nbsp;&nbsp;<input type=\"submit\" onClick=\"return DoCheckPwd();\" value=\"".Dict::S('UI:Button:ChangePassword')."\" /></td></tr>\n");
$this->add("</table>\n");
$this->add("<input type=\"hidden\" name=\"loginop\" value=\"do_change_pwd\" />\n");
@@ -194,14 +219,14 @@ EOF
static function SecureConnectionRequired()
{
return utils::GetConfig()->GetSecureConnectionRequired();
return MetaModel::GetConfig()->GetSecureConnectionRequired();
}
static function IsConnectionSecure()
{
$bSecured = false;
if ( !empty($_SERVER['HTTPS']) && ($_SERVER['HTTPS']!= 'off') )
if (isset($_SERVER['HTTPS']) && ($_SERVER['HTTPS']!='off'))
{
$bSecured = true;
}
@@ -212,13 +237,11 @@ 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 = utils::GetConfig()->GetAllowedLoginTypes();
$aAllowedLoginTypes = MetaModel::GetConfig()->GetAllowedLoginTypes();
if (isset($_SESSION['auth_user']))
{
@@ -237,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';
@@ -266,12 +301,10 @@ EOF
case 'external':
// Web server supplied authentication
$bExternalAuth = false;
$sExtAuthVar = utils::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';
@@ -280,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;
@@ -310,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 */);
@@ -322,6 +356,16 @@ EOF
{
// User is Ok, let's save it in the session and proceed with normal login
UserRights::Login($sAuthUser, $sAuthentication); // Login & set the user's language
if (MetaModel::GetConfig()->Get('log_usage'))
{
$oLog = new EventLoginUsage();
$oLog->Set('userinfo', UserRights::GetUser());
$oLog->Set('user_id', UserRights::GetUserObject()->GetKey());
$oLog->Set('message', 'Successful login');
$oLog->DBInsertNoReload();
}
$_SESSION['auth_user'] = $sAuthUser;
$_SESSION['login_mode'] = $sLoginMode;
}
@@ -338,7 +382,9 @@ EOF
*/
static function DoLogin($bMustBeAdmin = false, $bIsAllowedToPortalUsers = false)
{
$sMessage = ''; // In case we need to return a message to the calling web page
$operation = utils::ReadParam('loginop', '');
session_name(MetaModel::GetConfig()->Get('session_name'));
session_start();
if ($operation == 'logoff')
@@ -349,7 +395,7 @@ EOF
}
else
{
$aAllowedLoginTypes = utils::GetConfig()->GetAllowedLoginTypes();
$aAllowedLoginTypes = MetaModel::GetConfig()->GetAllowedLoginTypes();
if (count($aAllowedLoginTypes) > 0)
{
$sLoginMode = $aAllowedLoginTypes[0];
@@ -378,33 +424,34 @@ 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();
$oPage->DisplayChangePwdForm(true); // old pwd was wrong
$oPage->output();
}
$sMessage = Dict::S('UI:Login:PasswordChanged');
}
self::Login();
if ($bMustBeAdmin && !UserRights::IsAdministrator())
{
require_once('../setup/setuppage.class.inc.php');
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
?>

View File

@@ -23,8 +23,8 @@
* @license http://www.opensource.org/licenses/gpl-3.0.html LGPL
*/
require_once('../application/utils.inc.php');
require_once('../application/template.class.inc.php');
require_once(APPROOT.'/application/utils.inc.php');
require_once(APPROOT.'/application/template.class.inc.php');
/**
@@ -61,30 +61,73 @@ 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
* of the data model objects
*/
static public function InsertMenu(MenuNode $oMenuNode, $iParentIndex = -1, $fRank)
static public function InsertMenu(MenuNode $oMenuNode, $iParentIndex, $fRank)
{
$index = self::GetMenuIndexById($oMenuNode->GetMenuId());
if ($index == -1)
{
// The menu does not already exist, insert it
$index = count(self::$aMenusIndex);
self::$aMenusIndex[$index] = array( 'node' => $oMenuNode, 'children' => array());
if ($iParentIndex == -1)
{
$sParentId = '';
self::$aRootMenus[] = array ('rank' => $fRank, 'index' => $index);
}
else
{
$sParentId = self::$aMenusIndex[$iParentIndex]['node']->GetMenuId();
self::$aMenusIndex[$iParentIndex]['children'][] = array ('rank' => $fRank, 'index' => $index);
}
// Note: At the time when 'parent', 'rank' and 'source_file' have been added for the reflection API,
// they were not used to display the menus (redundant or unused)
//
$aBacktrace = debug_backtrace();
$sFile = $aBacktrace[2]["file"];
self::$aMenusIndex[$index] = array('node' => $oMenuNode, 'children' => array(), 'parent' => $sParentId, 'rank' => $fRank, 'source_file' => $sFile);
}
else
{
// the menu already exists, let's combine the conditions that make it visible
self::$aMenusIndex[$index]['node']->AddCondition($oMenuNode);
}
return $index;
}
/**
* Reflection API - Get menu entries
*/
static public function ReflectionMenuNodes()
{
return self::$aMenusIndex;
}
/**
* Entry point to display the whole menu into the web page, used by iTopWebPage
@@ -98,7 +141,6 @@ class ApplicationMenu
foreach(self::$aRootMenus as $aMenu)
{
$oMenuNode = self::GetMenuNode($aMenu['index']);
if (($oMenuNode->GetMenuId() == 'AdminTools') && (!UserRights::IsAdministrator())) continue; // Don't display the admin menu for non admin users
if (!$oMenuNode->IsEnabled()) continue; // Don't display a non-enabled menu
$oPage->AddToMenu('<h3>'.$oMenuNode->GetTitle().'</h3>');
$oPage->AddToMenu('<div>');
@@ -218,7 +260,8 @@ class ApplicationMenu
*/
static public function GetActiveNodeId()
{
$iMenuIndex = utils::ReadParam('menu', -1);
$oAppContext = new ApplicationContext();
$iMenuIndex = $oAppContext->GetCurrentValue('menu', -1);
if ($iMenuIndex == -1)
{
@@ -263,20 +306,30 @@ abstract class MenuNode
protected $sMenuId;
protected $index;
/**
* Properties reflecting how the node has been declared
*/
protected $aReflectionProperties;
/**
* 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_aEnableStimuli;
/**
* Create a menu item, sets the condition to have it displayed and inserts it into the application's main menu
@@ -284,18 +337,33 @@ abstract class MenuNode
* @param integer $iParentIndex ID of the parent menu, pass -1 for top level (group) items
* @param float $fRank Number used to order the list, any number will do, but for a given level (i.e same parent) all menus are sorted based on this value
* @param string $sEnableClass Name of class of object
* @param integer $iActionCode Either UR_ACTION_READ, UR_ACTION_MODIFY, UR_ACTION_DELETE, UR_ACTION_BULKREAD, UR_ACTION_BULKMODIFY or UR_ACTION_BULKDELETE
* @param mixed $iActionCode UR_ACTION_READ, UR_ACTION_MODIFY, UR_ACTION_DELETE, UR_ACTION_BULKREAD, UR_ACTION_BULKMODIFY or UR_ACTION_BULKDELETE
* @param integer $iAllowedResults Expected "rights" for the action: either UR_ALLOWED_YES, UR_ALLOWED_NO, UR_ALLOWED_DEPENDS or a mix of them...
* @param string $sEnableStimulus The user can see this menu if she/he has enough rights to apply this stimulus
* @return MenuNode
*/
public function __construct($sMenuId, $iParentIndex = -1, $fRank = 0, $sEnableClass = null, $iActionCode = null, $iAllowedResults = UR_ALLOWED_YES)
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->aReflectionProperties = array();
if (strlen($sEnableClass) > 0)
{
$this->aReflectionProperties['enable_class'] = $sEnableClass;
$this->aReflectionProperties['enable_action'] = $iActionCode;
$this->aReflectionProperties['enable_permission'] = $iAllowedResults;
$this->aReflectionProperties['enable_stimulus'] = $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);
}
public function ReflectionProperties()
{
return $this->aReflectionProperties;
}
public function GetMenuId()
{
@@ -319,27 +387,58 @@ abstract class MenuNode
public function GetHyperlink($aExtraParams)
{
$aExtraParams['menu'] = $this->GetIndex();
return $this->AddParams('../pages/UI.php', $aExtraParams);
$aExtraParams['c[menu]'] = $this->GetIndex();
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)
{
$iResult = UserRights::IsActionAllowed($this->m_sEnableClass, $this->m_iEnableAction);
if (($iResult & $this->m_iEnableActionResults))
if (MetaModel::IsValidClass($sClass))
{
return true;
if ($this->m_aEnableStimuli[$index] != null)
{
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;
}
}
}
else
{
return false;
}
}
return false;
}
return true;
}
@@ -381,9 +480,9 @@ class MenuGroup extends MenuNode
* @param integer $iAllowedResults Expected "rights" for the action: either UR_ALLOWED_YES, UR_ALLOWED_NO, UR_ALLOWED_DEPENDS or a mix of them...
* @return MenuGroup
*/
public function __construct($sMenuId, $fRank, $sEnableClass = null, $iActionCode = null, $iAllowedResults = UR_ALLOWED_YES)
public function __construct($sMenuId, $fRank, $sEnableClass = null, $iActionCode = null, $iAllowedResults = UR_ALLOWED_YES, $sEnableStimulus = null)
{
parent::__construct($sMenuId, -1 /* no parent, groups are at root level */, $fRank, $sEnableClass, $iActionCode, $iAllowedResults);
parent::__construct($sMenuId, -1 /* no parent, groups are at root level */, $fRank, $sEnableClass, $iActionCode, $iAllowedResults, $sEnableStimulus);
}
public function RenderContent(WebPage $oPage, $aExtraParams = array())
@@ -411,10 +510,11 @@ class TemplateMenuNode extends MenuNode
* @param integer $iAllowedResults Expected "rights" for the action: either UR_ALLOWED_YES, UR_ALLOWED_NO, UR_ALLOWED_DEPENDS or a mix of them...
* @return MenuNode
*/
public function __construct($sMenuId, $sTemplateFile, $iParentIndex, $fRank = 0, $sEnableClass = null, $iActionCode = null, $iAllowedResults = UR_ALLOWED_YES)
public function __construct($sMenuId, $sTemplateFile, $iParentIndex, $fRank = 0, $sEnableClass = null, $iActionCode = null, $iAllowedResults = UR_ALLOWED_YES, $sEnableStimulus = null)
{
parent::__construct($sMenuId, $iParentIndex, $fRank, $sEnableClass, $iActionCode, $iAllowedResults);
parent::__construct($sMenuId, $iParentIndex, $fRank, $sEnableClass, $iActionCode, $iAllowedResults, $sEnableStimulus);
$this->sTemplateFile = $sTemplateFile;
$this->aReflectionProperties['template_file'] = $sTemplateFile;
}
public function GetHyperlink($aExtraParams)
@@ -466,13 +566,15 @@ class OQLMenuNode extends MenuNode
* @param integer $iAllowedResults Expected "rights" for the action: either UR_ALLOWED_YES, UR_ALLOWED_NO, UR_ALLOWED_DEPENDS or a mix of them...
* @return MenuNode
*/
public function __construct($sMenuId, $sOQL, $iParentIndex, $fRank = 0, $bSearch = false, $sEnableClass = null, $iActionCode = null, $iAllowedResults = UR_ALLOWED_YES)
public function __construct($sMenuId, $sOQL, $iParentIndex, $fRank = 0, $bSearch = false, $sEnableClass = null, $iActionCode = null, $iAllowedResults = UR_ALLOWED_YES, $sEnableStimulus = null)
{
parent::__construct($sMenuId, $iParentIndex, $fRank, $sEnableClass, $iActionCode, $iAllowedResults);
parent::__construct($sMenuId, $iParentIndex, $fRank, $sEnableClass, $iActionCode, $iAllowedResults, $sEnableStimulus);
$this->sPageTitle = "Menu:$sMenuId+";
$this->sOQL = $sOQL;
$this->bSearch = $bSearch;
$this->m_aParams = array();
$this->aReflectionProperties['oql'] = $sOQL;
$this->aReflectionProperties['do_search'] = $bSearch;
// Enhancement: we could set as the "enable" condition that the user has enough rights to "read" the objects
// of the class specified by the OQL...
}
@@ -484,6 +586,10 @@ class OQLMenuNode extends MenuNode
public function SetParameters($aParams)
{
$this->m_aParams = $aParams;
foreach($aParams as $sKey => $value)
{
$this->aReflectionProperties[$sKey] = $value;
}
}
public function RenderContent(WebPage $oPage, $aExtraParams = array())
@@ -545,11 +651,12 @@ class SearchMenuNode extends MenuNode
* @param integer $iAllowedResults Expected "rights" for the action: either UR_ALLOWED_YES, UR_ALLOWED_NO, UR_ALLOWED_DEPENDS or a mix of them...
* @return MenuNode
*/
public function __construct($sMenuId, $sClass, $iParentIndex, $fRank = 0, $bSearch = false, $sEnableClass = null, $iActionCode = null, $iAllowedResults = UR_ALLOWED_YES)
public function __construct($sMenuId, $sClass, $iParentIndex, $fRank = 0, $bSearch = false, $sEnableClass = null, $iActionCode = null, $iAllowedResults = UR_ALLOWED_YES, $sEnableStimulus = null)
{
parent::__construct($sMenuId, $iParentIndex, $fRank, $sEnableClass, $iActionCode, $iAllowedResults);
parent::__construct($sMenuId, $iParentIndex, $fRank, $sEnableClass, $iActionCode, $iAllowedResults, $sEnableStimulus);
$this->sPageTitle = "Menu:$sMenuId+";
$this->sClass = $sClass;
$this->aReflectionProperties['class'] = $sClass;
}
public function RenderContent(WebPage $oPage, $aExtraParams = array())
@@ -585,15 +692,16 @@ class WebPageMenuNode extends MenuNode
* @param integer $iAllowedResults Expected "rights" for the action: either UR_ALLOWED_YES, UR_ALLOWED_NO, UR_ALLOWED_DEPENDS or a mix of them...
* @return MenuNode
*/
public function __construct($sMenuId, $sHyperlink, $iParentIndex, $fRank = 0, $sEnableClass = null, $iActionCode = null, $iAllowedResults = UR_ALLOWED_YES)
public function __construct($sMenuId, $sHyperlink, $iParentIndex, $fRank = 0, $sEnableClass = null, $iActionCode = null, $iAllowedResults = UR_ALLOWED_YES, $sEnableStimulus = null)
{
parent::__construct($sMenuId, $iParentIndex, $fRank, $sEnableClass, $iActionCode, $iAllowedResults);
parent::__construct($sMenuId, $iParentIndex, $fRank, $sEnableClass, $iActionCode, $iAllowedResults, $sEnableStimulus);
$this->sHyperlink = $sHyperlink;
$this->aReflectionProperties['url'] = $sHyperlink;
}
public function GetHyperlink($aExtraParams)
{
$aExtraParams['menu'] = $this->GetIndex();
$aExtraParams['c[menu]'] = $this->GetIndex();
return $this->AddParams( $this->sHyperlink, $aExtraParams);
}
@@ -626,12 +734,13 @@ class NewObjectMenuNode extends MenuNode
{
parent::__construct($sMenuId, $iParentIndex, $fRank);
$this->sClass = $sClass;
$this->aReflectionProperties['class'] = $sClass;
}
public function GetHyperlink($aExtraParams)
{
$sHyperlink = '../pages/UI.php?operation=new&class='.$this->sClass;
$aExtraParams['menu'] = $this->GetIndex();
$sHyperlink = utils::GetAbsoluteUrlAppRoot().'pages/UI.php?operation=new&class='.$this->sClass;
$aExtraParams['c[menu]'] = $this->GetIndex();
return $this->AddParams($sHyperlink, $aExtraParams);
}

View File

@@ -23,7 +23,7 @@
* @license http://www.opensource.org/licenses/gpl-3.0.html LGPL
*/
require_once("../application/webpage.class.inc.php");
require_once(APPROOT."/application/webpage.class.inc.php");
/**
* Web page with some associated CSS and scripts (jquery) for a fancier display
*/

View File

@@ -23,9 +23,21 @@
* @license http://www.opensource.org/licenses/gpl-3.0.html LGPL
*/
require_once("../application/nicewebpage.class.inc.php");
require_once("../application/applicationcontext.class.inc.php");
require_once("../application/user.preferences.class.inc.php");
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");
@@ -58,15 +75,16 @@ class PortalWebPage extends NiceWebPage
$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.bgiframe.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.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
@@ -107,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',
@@ -118,7 +134,8 @@ 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,16 +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()
{
$this->AddMenuButton('logoff', 'Portal:Disconnect', '../pages/logoff.php?portal=1'); // This menu is always present and is the last one
$sMenu = '';
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>&nbsp;");
//$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>&nbsp;<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>&nbsp;$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
);
}
}
?>
?>

View 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>');
}
}
}
?>

View 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) &lt; 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. &lt; 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
);
}
}
?>

View File

@@ -23,8 +23,8 @@
* @license http://www.opensource.org/licenses/gpl-3.0.html LGPL
*/
require_once('../core/cmdbobject.class.inc.php');
require_once('../application/utils.inc.php');
require_once(APPROOT.'/core/cmdbobject.class.inc.php');
require_once(APPROOT.'/application/utils.inc.php');
MetaModel::Startup(ITOP_CONFIG_FILE);

View File

@@ -23,7 +23,7 @@
* @license http://www.opensource.org/licenses/gpl-3.0.html LGPL
*/
require_once('../application/displayblock.class.inc.php');
require_once(APPROOT.'/application/displayblock.class.inc.php');
/**
* This class manages the special template format used internally to build the iTop web pages
*/
@@ -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;
}
@@ -161,7 +169,7 @@ class DisplayTemplate
$oPage->AddTabContainer('Tabs_'.$iTabContainerCount);
$oPage->SetCurrentTabContainer('Tabs_'.$iTabContainerCount);
$iTabContainerCount++;
//$oPage->p('Content:<pre>'.htmlentities($sContent).'</pre>');
//$oPage->p('Content:<pre>'.htmlentities($sContent, ENT_QUOTES, 'UTF-8').'</pre>');
$oTemplate = new DisplayTemplate($sContent);
$oTemplate->Render($oPage, array()); // no params to apply, they have already been applied
$oPage->SetCurrentTabContainer('');
@@ -185,7 +193,7 @@ class DisplayTemplate
$oPage->SetCurrentTab(Dict::S(str_replace('_', ' ', $aAttributes['name'])));
$oTemplate = new DisplayTemplate($sContent);
$oTemplate->Render($oPage, array()); // no params to apply, they have already been applied
//$oPage->p('iTop Tab Content:<pre>'.htmlentities($sContent).'</pre>');
//$oPage->p('iTop Tab Content:<pre>'.htmlentities($sContent, ENT_QUOTES, 'UTF-8').'</pre>');
$oPage->SetCurrentTab('');
break;
@@ -195,7 +203,7 @@ class DisplayTemplate
$oPage->StartCollapsibleSection(Dict::S($sName), $bOpen);
$oTemplate = new DisplayTemplate($sContent);
$oTemplate->Render($oPage, array()); // no params to apply, they have already been applied
//$oPage->p('iTop Tab Content:<pre>'.htmlentities($sContent).'</pre>');
//$oPage->p('iTop Tab Content:<pre>'.htmlentities($sContent, ENT_QUOTES, 'UTF-8').'</pre>');
$oPage->EndCollapsibleSection();
break;
@@ -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;
@@ -218,8 +231,8 @@ class DisplayTemplate
*/
static public function UnitTest()
{
require_once('../application/startup.inc.php');
require_once("../application/itopwebpage.class.inc.php");
require_once(APPROOT.'/application/startup.inc.php');
require_once(APPROOT."/application/itopwebpage.class.inc.php");
$sTemplate = '<div class="page_header">
<div class="actions_details"><a href="#"><span>Actions</span></a></div>
@@ -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>
@@ -240,14 +252,151 @@ class DisplayTemplate
</itoptab>
</itoptabs>';
$oPage = new iTopWebPage('Unit Test', 3);
//$oPage->add("Template content: <pre>".htmlentities($sTemplate)."</pre>\n");
$oPage = new iTopWebPage('Unit Test');
//$oPage->add("Template content: <pre>".htmlentities($sTemplate, ENT_QUOTES, 'UTF-8')."</pre>\n");
$oTemplate = new DisplayTemplate($sTemplate);
$oTemplate->Render($oPage, array('class'=>'Network device','pkey'=> 271, 'name' => 'deliversw01.mecanorama.fr', 'org_id' => 3));
$oPage->output();
}
}
//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 = "&nbsp;<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();
?>

View File

@@ -1,4 +1,4 @@
<div style="width:100%;background: url(../images/welcome.jpg) top left no-repeat;">
<div style="width:100%;background: #fff url(../images/welcome.jpg) top left no-repeat;">
<style>
.dashboard {
vertical-align:top;

View File

@@ -17,94 +17,81 @@
/**
* This class records the pending "transactions" corresponding to forms that have not been
* submitted yet, in order to prevent double submissions. When created a transaction remains valid
* until it is "used" by calling IsTransactionValid once, or until it
* expires (delay = TRANSACTION_EXPIRATION_DELAY, defaults to 4 hours)
* until the user's session expires
* @package iTop
*/
// How long a "transaction" is considered valid, i.e. when a form is submitted
// if the form dates back from too long a time, it is considered invalid. This is
// because since HTTP is not a connected protocol, we cannot know when a user disconnects
// from the application (maybe just by closing her browser), so we keep track - in the database - of all pending
// forms that have not yet been submitted. To limit this list we consider that after some time
// a "transaction" is no loger valid an gets purged from the table
define ('TRANSACTION_EXPIRATION_DELAY', 3600*4); // default: 4h
require_once('../core/dbobject.class.php');
class privUITransaction extends DBObject
class privUITransaction
{
public static function Init()
{
$aParams = array
(
"category" => "gui",
"key_type" => "autoincrement",
"name_attcode" => "expiration_date",
"state_attcode" => "",
"reconc_keys" => array(),
"db_table" => "priv_transaction",
"db_key_field" => "id",
"db_finalclass_field" => "",
);
MetaModel::Init_Params($aParams);
MetaModel::Init_AddAttribute(new AttributeDateTime("expiration_date", array("allowed_values"=>null, "sql"=>"expiration_date", "default_value"=>"", "is_null_allowed"=>false, "depends_on"=>array())));
MetaModel::Init_SetZListItems('details', array('expiration_date')); // Attributes to be displayed for the complete details
MetaModel::Init_SetZListItems('list', array('expiration_date')); // Attributes to be displayed for a list
}
/**
* Create a new transaction, store it in the database and return its id
* Create a new transaction id, store it in the session and return its id
* @param void
* @return int The identifier of the new transaction
*/
public static function GetNewTransactionId()
{
// First remove all the expired transactions...
self::CleanupExpiredTransactions();
$oTransaction = new privUITransaction();
$sDate = date('Y-m-d H:i:s', time()+TRANSACTION_EXPIRATION_DELAY);
$oTransaction->Set('expiration_date', $sDate); // 4 h delay by default
$oTransaction->DBInsert();
return sprintf("%d", $oTransaction->GetKey());
if (!isset($_SESSION['transactions']))
{
$_SESSION['transactions'] = array();
}
// Strictly speaking, the two lines below should be grouped together
// by a critical section
// sem_acquire($rSemIdentified);
$id = str_replace(array('.', ' '), '', microtime()); //1 + count($_SESSION['transactions']);
$_SESSION['transactions'][$id] = true;
// sem_release($rSemIdentified);
return (string)$id;
}
/**
* Check whether a transaction is valid or not and remove the valid transaction from
* the database so that another call to IsTransactionValid for the same transaction
* Check whether a transaction is valid or not and (optionally) remove the valid transaction from
* the session so that another call to IsTransactionValid for the same transaction id
* will return false
* @param int $id Identifier of the transaction, as returned by GetNewTransactionId
* @param bool $bRemoveTransaction True if the transaction must be removed
* @return bool True if the transaction is valid, false otherwise
*/
public static function IsTransactionValid($id)
public static function IsTransactionValid($id, $bRemoveTransaction = true)
{
// First remove all the expired transactions...
self::CleanupExpiredTransactions();
// TO DO put a critical section around this part to be 100% safe...
// sem_acquire(...)
$bResult = false;
$oTransaction = MetaModel::GetObject('privUITransaction', $id, false /* MustBeFound */);
if ($oTransaction)
$bResult = false;
if (isset($_SESSION['transactions']))
{
$bResult = true;
$oTransaction->DBDelete();
// Strictly speaking, the eight lines below should be grouped together
// inside the same critical section as above
// sem_acquire($rSemIdentified);
if (isset($_SESSION['transactions'][$id]))
{
$bResult = true;
if ($bRemoveTransaction)
{
unset($_SESSION['transactions'][$id]);
}
}
// sem_release($rSemIdentified);
}
// sem_release(...)
return $bResult;
}
/**
* Remove from the database all transactions that have expired
* Removes the transaction specified by its id
* @param int $id The Identifier (as returned by GetNewTranscationId) of the transaction to be removed.
* @return void
*/
protected static function CleanupExpiredTransactions()
public static function RemoveTransaction($id)
{
$sQuery = 'SELECT privUITransaction WHERE expiration_date < NOW()';
$oSearch = DBObjectSearch::FromOQL($sQuery);
$oSet = new DBObjectSet($oSearch);
while($oTransaction = $oSet->Fetch())
if (isset($_SESSION['transactions']))
{
$oTransaction->DBDelete();
}
// Strictly speaking, the three lines below should be grouped together
// inside the same critical section as above
// sem_acquire($rSemIdentified);
if (isset($_SESSION['transactions'][$id]))
{
unset($_SESSION['transactions'][$id]);
}
// sem_release($rSemIdentified);
}
}
}
?>

View File

@@ -0,0 +1,580 @@
<?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
/**
* Class UIExtKeyWidget
* UI wdiget for displaying and editing external keys when
* A simple drop-down list is not enough...
*
* The layout is the following
*
* +-- #label_<id> (input)-------+ +-----------+
* | | | Browse... |
* +-----------------------------+ +-----------+
*
* And the popup dialog has the following layout:
*
* +------------------- ac_dlg_<id> (div)-----------+
* + +--- ds_<id> (div)---------------------------+ |
* | | +------------- fs_<id> (form)------------+ | |
* | | | +--------+---+ | | |
* | | | | Class | V | | | |
* | | | +--------+---+ | | |
* | | | | | |
* | | | S e a r c h F o r m | | |
* | | | +--------+ | | |
* | | | | Search | | | |
* | | | +--------+ | | |
* | | +----------------------------------------+ | |
* | +--------------+-dh_<id>-+--------------------+ |
* | \ Search / |
* | +------+ |
* | +--- fr_<id> (form)--------------------------+ |
* | | +------------ dr_<id> (div)--------------+ | |
* | | | | | |
* | | | S e a r c h R e s u l t s | | |
* | | | | | |
* | | +----------------------------------------+ | |
* | | +--------+ +-----+ | |
* | | | Cancel | | Add | | |
* | | +--------+ +-----+ | |
* | +--------------------------------------------+ |
* +------------------------------------------------+
* @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/displayblock.class.inc.php');
class UIExtKeyWidget
{
protected $iId;
protected $sTargetClass;
protected $sAttCode;
protected $bSearchMode;
//public function __construct($sAttCode, $sClass, $sTitle, $oAllowedValues, $value, $iInputId, $bMandatory, $sNameSuffix = '', $sFieldPrefix = '', $sFormPrefix = '')
static public function DisplayFromAttCode($oPage, $sAttCode, $sClass, $sTitle, $oAllowedValues, $value, $iInputId, $bMandatory, $sFieldName = '', $sFormPrefix = '', $aArgs, $bSearchMode = false)
{
$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, $bSearchMode);
return $oWidget->Display($oPage, $iMaxComboLength, $bAllowTargetCreation, $sTitle, $oAllowedValues, $value, $iInputId, $bMandatory, $sFieldName, $sFormPrefix, $aArgs, null, $sDisplayStyle);
}
public function __construct($sTargetClass, $iInputId, $sAttCode = '', $bSearchMode = false)
{
$this->sTargetClass = $sTargetClass;
$this->iId = $iInputId;
$this->sAttCode = $sAttCode;
$this->bSearchMode = $bSearchMode;
}
/**
* Get the HTML fragment corresponding to the linkset editing widget
* @param WebPage $oP The web page used for all the output
* @param Hash $aArgs Extra context arguments
* @return string The HTML fragment to be inserted into the page
*/
public function Display(WebPage $oPage, $iMaxComboLength, $bAllowTargetCreation, $sTitle, $oAllowedValues, $value, $iInputId, $bMandatory, $sFieldName, $sFormPrefix = '', $aArgs = array(), $bSearchMode = null, $sDisplayStyle = 'select')
{
if (!is_null($bSearchMode))
{
$this->bSearchMode = $bSearchMode;
}
$sTitle = addslashes($sTitle);
$oPage->add_linked_script('../js/extkeywidget.js');
$oPage->add_linked_script('../js/forms-json-utils.js');
$bCreate = (!$this->bSearchMode) && (!MetaModel::IsAbstract($this->sTargetClass)) && (UserRights::IsActionAllowed($this->sTargetClass, UR_ACTION_BULK_MODIFY) && $bAllowTargetCreation);
$bExtensions = true;
$sMessage = Dict::S('UI:Message:EmptyList:UseSearchForm');
$sAttrFieldPrefix = ($this->bSearchMode) ? '' : 'attr_';
$sHTMLValue = "<span style=\"white-space:nowrap\">"; // no wrap
$sFilter = addslashes($oAllowedValues->GetFilter()->ToOQL());
if($this->bSearchMode)
{
$sWizHelper = 'null';
$sWizHelperJSON = "''";
$sJSSearchMode = 'true';
}
else
{
if (isset($aArgs['wizHelper']))
{
$sWizHelper = $aArgs['wizHelper'];
}
else
{
$sWizHelper = 'oWizardHelper'.$sFormPrefix;
}
$sWizHelperJSON = $sWizHelper.'.UpdateWizardToJSON()';
$sJSSearchMode = 'false';
}
if (is_null($oAllowedValues))
{
throw new Exception('Implementation: null value for allowed values definition');
}
elseif ($oAllowedValues->Count() < $iMaxComboLength)
{
// Discrete list of values, use a SELECT or RADIO buttons depending on the config
switch($sDisplayStyle)
{
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())
{
$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 ($this->bSearchMode)
{
$sDisplayValue = isset($aArgs['sDefaultValue']) ? $aArgs['sDefaultValue'] : Dict::S('UI:SearchValue:Any');
$sHTMLValue .= "<option value=\"\">$sDisplayValue</option>\n";
}
else
{
$sHTMLValue .= "<option value=\"\">".Dict::S('UI:SelectOne')."</option>\n";
}
$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->sTargetClass}', '$sFilter', '$sTitle', true, $sWizHelper, '{$this->sAttCode}', $sJSSearchMode);
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 (is_null($value) || ($value == 0)) // Null values are displayed as ''
{
$sDisplayValue = isset($aArgs['sDefaultValue']) ? $aArgs['sDefaultValue'] : '';
}
else
{
$sDisplayValue = $this->GetObjectName($value);
}
$iMinChars = isset($aArgs['iMinChars']) ? $aArgs['iMinChars'] : 3; //@@@ $this->oAttDef->GetMinAutoCompleteChars();
$iFieldSize = isset($aArgs['iFieldSize']) ? $aArgs['iFieldSize'] : 30; //@@@ $this->oAttDef->GetMaxSize();
// the input for the auto-complete
$sHTMLValue = "<input count=\"".$oAllowedValues->Count()."\" type=\"text\" id=\"label_$this->iId\" size=\"$iFieldSize\" value=\"$sDisplayValue\"/>&nbsp;";
$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();\"/>&nbsp;";
// another hidden input to store & pass the object's Id
$sHTMLValue .= "<input type=\"hidden\" id=\"$this->iId\" name=\"{$sAttrFieldPrefix}{$sFieldName}\" value=\"$value\" />\n";
$JSSearchMode = $this->bSearchMode ? 'true' : 'false';
// Scripts to start the autocomplete and bind some events to it
$oPage->add_ready_script(
<<<EOF
oACWidget_{$this->iId} = new ExtKeyWidget('{$this->iId}', '{$this->sTargetClass}', '$sFilter', '$sTitle', false, $sWizHelper, '{$this->sAttCode}', $sJSSearchMode);
oACWidget_{$this->iId}.emptyHtml = "<div style=\"background: #fff; border:0; text-align:center; vertical-align:middle;\"><p>$sMessage</p></div>";
$('#label_$this->iId').autocomplete(GetAbsoluteUrlAppRoot()+'pages/ajax.render.php', { scroll:true, minChars:{$iMinChars}, autoFill:false, matchContains:true, mustMatch: true, keyHolder:'#{$this->iId}', extraParams:{operation:'ac_extkey', sTargetClass:'{$this->sTargetClass}',sFilter:'$sFilter',bSearchMode:$JSSearchMode, json: function() { return $sWizHelperJSON; } }});
$('#label_$this->iId').keyup(function() { if ($(this).val() == '') { $('#$this->iId').val(''); } } ); // Useful for search forms: empty value in the "label", means no value, immediatly !
$('#label_$this->iId').result( function(event, data, formatted) { OnAutoComplete('{$this->iId}', event, data, formatted); } );
$('#$this->iId').bind('update', function() { oACWidget_{$this->iId}.Update(); } );
if ($('#ac_dlg_{$this->iId}').length == 0)
{
$('body').append('<div id="ac_dlg_{$this->iId}"></div>');
}
EOF
);
}
if ($bExtensions && MetaModel::IsHierarchicalClass($this->sTargetClass) !== false)
{
$sHTMLValue .= "<img id=\"mini_tree_{$this->iId}\" style=\"border:0;vertical-align:middle;cursor:pointer;\" src=\"../images/mini_tree.gif\" onClick=\"oACWidget_{$this->iId}.HKDisplay();\"/>&nbsp;";
$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();\"/>&nbsp;";
$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>"; // end of no wrap
return $sHTMLValue;
}
public function GetSearchDialog(WebPage $oPage, $sTitle, $oCurrObject = null)
{
$sHTML = '<div class="wizContainer" style="vertical-align:top;"><div id="dc_'.$this->iId.'">';
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
{
$aParams = array();
$oFilter = new DBObjectSearch($this->sTargetClass);
}
$oFilter->SetModifierProperty('UserRightsGetSelectFilter', 'bSearchMode', $this->bSearchMode);
$oBlock = new DisplayBlock($oFilter, 'search', false, $aParams);
$sHTML .= $oBlock->GetDisplay($oPage, $this->iId, array('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";
$sHTML .= "<div style=\"background: #fff; border:0; text-align:center; vertical-align:middle;\"><p>".Dict::S('UI:Message:EmptyList:UseSearchForm')."</p></div>\n";
$sHTML .= "</div>\n";
$sHTML .= "<input type=\"button\" id=\"btn_cancel_{$this->iId}\" value=\"".Dict::S('UI:Button:Cancel')."\" onClick=\"$('#ac_dlg_{$this->iId}').dialog('close');\">&nbsp;&nbsp;";
$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($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 });
$('#fs_{$this->iId}').bind('submit.uiAutocomplete', oACWidget_{$this->iId}.DoSearchObjects);
$('#dc_{$this->iId}').resize(oACWidget_{$this->iId}.UpdateSizes);
EOF
);
$oPage->add($sHTML);
}
/**
* Search for objects to be selected
* @param WebPage $oP The page used for the output (usually an AjaxWebPage)
* @param string $sRemoteClass Name of the "remote" class to perform the search on, must be a derived class of sTargetClass
* @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, $sFilter, $sRemoteClass = '', $oObj = null)
{
if (is_null($sFilter))
{
throw new Exception('Implementation: null value for allowed values definition');
}
try
{
if ($sRemoteClass != $this->sTargetClass)
{
//$oBaseClassFilter = DBObjectSearch::FromOQL($sFilter);
//$oFilter = new DBObjectSearch($sRemoteClass);
//$oFilter->AddConditionExpression($oBaseClassFilter->GetCriteria());
//$oFilter->TransferConditionExpression($oBaseClassFilter, array());
//$oFilter->TransferConditionExpression($oBaseClassFilter, array($this->sTargetClass => array('*' => $sRemoteClass.'_'.strtolower($this->sTargetClass))));
$sFilter = str_replace(" $this->sTargetClass ", " $sRemoteClass ", $sFilter);
$sFilter = str_replace("`$this->sTargetClass`", "`$sRemoteClass`", $sFilter);
$oFilter = DBObjectSearch::FromOQL($sFilter);
}
else
{
$oFilter = DBObjectSearch::FromOQL($sFilter);
}
//$oP->p($oFilter->ToOQL());
$oFilter->SetModifierProperty('UserRightsGetSelectFilter', 'bSearchMode', $this->bSearchMode);
$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);
$oFilter->SetModifierProperty('UserRightsGetSelectFilter', 'bSearchMode', $this->bSearchMode);
//$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
$oValuesSet->SetModifierProperty('UserRightsGetSelectFilter', 'bSearchMode', $this->bSearchMode);
$aValues = $oValuesSet->GetValues(array('this' => $oObj), $sContains);
foreach($aValues as $sKey => $sFriendlyName)
{
$oP->add(trim($sFriendlyName)."\t".$sKey."\n");
}
}
/**
* Get the display name of the selected object, to fill back the autocomplete
*/
public function GetObjectName($iObjId)
{
$aModifierProps = array();
$aModifierProps['UserRightsGetSelectFilter']['bSearchMode'] = $this->bSearchMode;
$oObj = MetaModel::GetObject($this->sTargetClass, $iObjId, false, false, $aModifierProps);
if ($oObj)
{
return $oObj->GetName();
}
else
{
return '';
}
}
/**
* Get the form to create a new object of the 'target' class
*/
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)."&nbsp;".Dict::Format('UI:CreationTitle_Class', MetaModel::GetName($this->sTargetClass))."</h1>\n");
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");
$oPage->add_ready_script("$('#dcr_{$this->iId} form').removeAttr('onsubmit');");
$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);
$oFilter->SetModifierProperty('UserRightsGetSelectFilter', 'bSearchMode', $this->bSearchMode);
$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);
$oFilter->SetModifierProperty('UserRightsGetSelectFilter', 'bSearchMode', $this->bSearchMode);
$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');\">&nbsp;&nbsp;");
$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->UpdateObjectFromPostedForm($this->iId);
if (count($aErrors) == 0)
{
$oMyChange = MetaModel::NewObject("CMDBChange");
$oMyChange->Set("date", time());
$sUserString = CMDBChange::GetCurrentUserName();
$oMyChange->Set("userinfo", $sUserString);
$iChangeId = $oMyChange->DBInsert();
$oObj->DBInsertTracked($oMyChange);
return array('name' => $oObj->GetName(), 'id' => $oObj->GetKey());
}
else
{
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.'>&nbsp;';
}
else
{
$sSelect = '<input type="radio" value="'.$aNodes[$id]->GetKey().'" name="selectObject" '.$sChecked.'>&nbsp;';
}
}
$oP->add('<li>'.$sSelect.$aNodes[$id]->GetHyperlink());
$this->DumpNodes($oP, $id, $aTree, $aNodes, $currValue);
$oP->add("</li>\n");
}
$oP->add("</ul>\n");
}
}
}
?>

View File

@@ -0,0 +1,87 @@
<?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
/**
* Class UIHTMLEditorWidget
* UI wdiget for displaying and editing one-way encrypted passwords
*
* @author Phil Eddies
* @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
*/
class UIHTMLEditorWidget
{
protected $m_iId;
protected $m_sAttCode;
protected $m_sNameSuffix;
protected $m_sFieldPrefix;
protected $m_sHelpText;
protected $m_sValidationField;
protected $m_sValue;
protected $m_sMandatory;
public function __construct($iInputId, $sAttCode, $sNameSuffix, $sFieldPrefix, $sHelpText, $sValidationField, $sValue, $sMandatory)
{
$this->m_iId = $iInputId;
$this->m_sAttCode = $sAttCode;
$this->m_sNameSuffix = $sNameSuffix;
$this->m_sHelpText = $sHelpText;
$this->m_sValidationField = $sValidationField;
$this->m_sValue = $sValue;
$this->m_sMandatory = $sMandatory;
$this->m_sFieldPrefix = $sFieldPrefix;
}
/**
* Get the HTML fragment corresponding to the HTML editor widget
* @param WebPage $oP The web page used for all the output
* @param Hash $aArgs Extra context arguments
* @return string The HTML fragment to be inserted into the page
*/
public function Display(WebPage $oPage, $aArgs = array())
{
$iId = $this->m_iId;
$sCode = $this->m_sAttCode.$this->m_sNameSuffix;
$sValue = $this->m_sValue;
$sHelpText = $this->m_sHelpText;
$sValidationField = $this->m_sValidationField;
$sHtmlValue = "<table><tr><td><textarea class=\"htmlEditor\" title=\"$sHelpText\" name=\"attr_{$this->m_sFieldPrefix}{$sCode}\" rows=\"10\" cols=\"10\" id=\"$iId\">$sValue</textarea></td><td>$sValidationField</td></tr></table>";
// Replace the text area with CKEditor
// To change the default settings of the editor,
// a) edit the file /js/ckeditor/config.js
// b) or override some of the configuration settings, using the second parameter of ckeditor()
$sLanguage = strtolower(trim(UserRights::GetUserLanguage()));
$oPage->add_ready_script("$('#$iId').ckeditor(function() { /* callback code */ }, { language : '$sLanguage' , contentsLanguage : '$sLanguage', extraPlugins: 'disabler' });"); // Transform $iId into a CKEdit
// Please read...
// ValidateCKEditField triggers a timer... calling itself indefinitely
// This design was the quickest way to achieve the field validation (only checking if the field is blank)
// because the ckeditor does not fire events like "change" or "keyup", etc.
// See http://dev.ckeditor.com/ticket/900 => won't fix
// The most relevant solution would be to implement a plugin to CKEdit, and handle the internal events like: setData, insertHtml, insertElement, loadSnapshot, key, afterUndo, afterRedo
// Could also be bound to 'instanceReady.ckeditor'
$oPage->add_ready_script("$('#$iId').bind('validate', function(evt, sFormId) { return ValidateCKEditField('$iId', '', {$this->m_sMandatory}, sFormId, '') } );\n");
$oPage->add_ready_script("$('#$iId').bind('update', function() { BlockField('cke_$iId', $('#$iId').attr('disabled')); } );\n");
return $sHtmlValue;
}
}
?>

View File

@@ -23,8 +23,8 @@
* @license http://www.opensource.org/licenses/gpl-3.0.html LGPL
*/
require_once('../application/webpage.class.inc.php');
require_once('../application/displayblock.class.inc.php');
require_once(APPROOT.'/application/webpage.class.inc.php');
require_once(APPROOT.'/application/displayblock.class.inc.php');
class UILinksWidget
{
@@ -34,22 +34,24 @@ class UILinksWidget
protected $m_iInputId;
protected $m_aAttributes;
protected $m_sExtKeyToRemote;
protected $m_sExtKeyToMe;
protected $m_sLinkedClass;
protected $m_sRemoteClass;
protected static $iWidgetIndex = 0;
protected $m_bDuplicatesAllowed;
public function __construct($sClass, $sAttCode, $iInputId, $sNameSuffix = '')
public function __construct($sClass, $sAttCode, $iInputId, $sNameSuffix = '', $bDuplicatesAllowed = false)
{
$this->m_sClass = $sClass;
$this->m_sAttCode = $sAttCode;
$this->m_sNameSuffix = $sNameSuffix;
$this->m_iInputId = $iInputId;
$this->m_bDuplicatesAllowed = $bDuplicatesAllowed;
$this->m_aEditableFields = array();
self::$iWidgetIndex++;
$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();
@@ -58,15 +60,16 @@ class UILinksWidget
$this->m_aEditableFields = array();
$this->m_aTableConfig = array();
$this->m_aTableConfig['form::checkbox'] = array( 'label' => "<input class=\"select_all\" type=\"checkbox\" value=\"1\" onChange=\"var value = this.checked; $('#linkedset_{$this->m_sAttCode}{$this->m_sNameSuffix} .selection').each( function() { this.checked = value; } ); oWidget".self::$iWidgetIndex.".OnSelectChange();\">", 'description' => Dict::S('UI:SelectAllToggle+'));
$this->m_aTableConfig['form::checkbox'] = array( 'label' => "<input class=\"select_all\" type=\"checkbox\" value=\"1\" onClick=\"CheckAll('#linkedset_{$this->m_sAttCode}{$this->m_sNameSuffix} .selection', this.checked); oWidget".$this->m_iInputId.".OnSelectChange();\">", 'description' => Dict::S('UI:SelectAllToggle+'));
foreach(MetaModel::ListAttributeDefs($this->m_sLinkedClass) as $sAttCode=>$oAttDef)
foreach(MetaModel::FlattenZList(MetaModel::GetZListItems($this->m_sLinkedClass, 'list')) as $sAttCode)
{
$oAttDef = MetaModel::GetAttributeDef($this->m_sLinkedClass, $sAttCode);
if ($sStateAttCode == $sAttCode)
{
// State attribute is always hidden from the UI
}
else if (!$oAttDef->IsExternalField() && ($sAttCode != $sExtKeyToMe) && ($sAttCode != $this->m_sExtKeyToRemote) && ($sAttCode != 'finalclass'))
else if ($oAttDef->IsWritable() && ($sAttCode != $sExtKeyToMe) && ($sAttCode != $this->m_sExtKeyToRemote) && ($sAttCode != 'finalclass'))
{
$iFlags = MetaModel::GetAttributeFlags($this->m_sLinkedClass, $sDefaultState, $sAttCode);
if ( !($iFlags & OPT_ATT_HIDDEN) && !($iFlags & OPT_ATT_READONLY) )
@@ -97,39 +100,98 @@ 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();
$aFieldsMap = array();
if(is_object($linkObjOrId))
{
$key = $linkObjOrId->GetKey();
$iRemoteObjKey = $linkObjOrId->Get($this->m_sExtKeyToRemote);
$sPrefix .= "[$key][";
$sNameSuffix = "]"; // To make a tabular form
$aArgs['prefix'] = $sPrefix;
$aRow['form::checkbox'] = "<input class=\"selection\" type=\"checkbox\" onChange=\"oWidget".self::$iWidgetIndex.".OnSelectChange();\" value=\"$key\">";
$aArgs['wizHelper'] = "oWizardHelper{$this->m_iInputId}{$key}";
$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)
{
$sFieldId = $this->m_iInputId.'_'.$sFieldCode.'['.$linkObjOrId->GetKey().']';
$sSafeId = self::MakeID($sFieldId);
$oAttDef = MetaModel::GetAttributeDef($this->m_sLinkedClass, $sFieldCode);
$aRow[$sFieldCode] = cmdbAbstractObject::GetFormElementForField($oP, $this->m_sLinkedClass, $sFieldCode, $oAttDef, $linkObjOrId->Get($sFieldCode), '' /* DisplayValue */, $key, $sNameSuffix, 0, $aArgs);
$aRow[$sFieldCode] = cmdbAbstractObject::GetFormElementForField($oP, $this->m_sLinkedClass, $sFieldCode, $oAttDef, $linkObjOrId->Get($sFieldCode), '' /* DisplayValue */, $sSafeId, $sNameSuffix, 0, $aArgs);
$aFieldsMap[$sFieldCode] = $sSafeId;
}
$sState = $linkObjOrId->GetState();
}
else
{
// form for creating a new record
$sPrefix .= "[$linkObjOrId][";
$iRemoteObjKey = -$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 also fills the related external fields
$sNameSuffix = "]"; // To make a tabular form
$aArgs['prefix'] = $sPrefix;
$aRow['form::checkbox'] = "<input class=\"selection\" type=\"checkbox\" onChange=\"oWidget".self::$iWidgetIndex.".OnSelectChange();\" value=\"$linkObjOrId\">";
$aArgs['wizHelper'] = "oWizardHelper{$this->m_iInputId}_".(-$linkObjOrId);
$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)
{
$sFieldId = $this->m_iInputId.'_'.$sFieldCode.'['.$linkObjOrId.']';
$sSafeId = self::MakeID($sFieldId);
$oAttDef = MetaModel::GetAttributeDef($this->m_sLinkedClass, $sFieldCode);
$aRow[$sFieldCode] = cmdbAbstractObject::GetFormElementForField($oP, $this->m_sLinkedClass, $sFieldCode, $oAttDef, '' /* TO DO/ call GetDefaultValue($oObject->ToArgs()) */, '' /* DisplayValue */, '' /* id */, $sNameSuffix, 0, $aArgs);
$aRow[$sFieldCode] = cmdbAbstractObject::GetFormElementForField($oP, $this->m_sLinkedClass, $sFieldCode, $oAttDef, '' /* TO DO/ call GetDefaultValue($oObject->ToArgs()) */, '' /* DisplayValue */, $sSafeId /* id */, $sNameSuffix, 0, $aArgs);
$aFieldsMap[$sFieldCode] = $sSafeId;
}
$sState = '';
$oP->add_script(
<<<EOF
$(".date-pick").datepicker({
showOn: 'button',
buttonImage: '../images/calendar.png',
buttonImageOnly: true,
dateFormat: 'yy-mm-dd',
constrainInput: false,
changeMonth: true,
changeYear: true
});
$(".datetime-pick").datepicker({
showOn: 'button',
buttonImage: '../images/calendar.png',
buttonImageOnly: true,
dateFormat: 'yy-mm-dd 00:00:00',
constrainInput: false,
changeMonth: true,
changeYear: true
});
EOF
);
}
$sExtKeyToMeId = self::MakeID($sPrefix.$this->m_sExtKeyToMe);
$aFieldsMap[$this->m_sExtKeyToMe] = $sExtKeyToMeId;
$aRow['form::checkbox'] .= "<input type=\"hidden\" id=\"$sExtKeyToMeId\" value=\"".$oCurrentObj->GetKey()."\">";
$sExtKeyToRemoteId = self::MakeID($sPrefix.$this->m_sExtKeyToRemote);
$aFieldsMap[$this->m_sExtKeyToRemote] = $sExtKeyToRemoteId;
$aRow['form::checkbox'] .= "<input type=\"hidden\" id=\"$sExtKeyToRemoteId\" value=\"$iRemoteObjKey\">";
$iFieldsCount = count($aFieldsMap);
$sJsonFieldsMap = json_encode($aFieldsMap);
$oP->add_script(
<<<EOF
var {$aArgs['wizHelper']} = new WizardHelper('{$this->m_sLinkedClass}', '', '$sState');
{$aArgs['wizHelper']}.SetFieldsMap($sJsonFieldsMap);
{$aArgs['wizHelper']}.SetFieldsCount($iFieldsCount);
EOF
);
$aRow['static::key'] = $oLinkedObj->GetHyperLink();
foreach(MetaModel::GetZListItems($this->m_sRemoteClass, 'list') as $sFieldCode)
{
@@ -137,6 +199,11 @@ class UILinksWidget
}
return $aRow;
}
protected function MakeID($sName)
{
return str_replace(array('[', ']'), '_', $sName);
}
/**
* Display one row of the whole form
@@ -178,17 +245,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
@@ -203,11 +270,12 @@ 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)
{
$iWidgetIndex = self::$iWidgetIndex;
$sHtmlValue = '';
$sTargetClass = self::GetTargetClass($this->m_sClass, $this->m_sAttCode);
$sHtmlValue .= "<div id=\"linkedset_{$this->m_sAttCode}{$this->m_sNameSuffix}\">\n";
@@ -216,112 +284,35 @@ 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$iWidgetIndex = new LinksWidget('{$this->m_sAttCode}{$this->m_sNameSuffix}', '{$this->m_sClass}', '{$this->m_sAttCode}', '{$this->m_iInputId}', '{$this->m_sNameSuffix}');
oWidget$iWidgetIndex.Init();
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;\">&nbsp;&nbsp;&nbsp;<img src=\"../images/tv-item-last.gif\">&nbsp;&nbsp;<input id=\"{$this->m_sAttCode}{$this->m_sNameSuffix}_btnRemove\" type=\"button\" value=\"".Dict::S('UI:RemoveLinkedObjectsOf_Class')."\" onClick=\"oWidget$iWidgetIndex.RemoveSelected();\" >";
$sHtmlValue .= "&nbsp;&nbsp;&nbsp;<input id=\"{$this->m_sAttCode}{$this->m_sNameSuffix}_btnAdd\" type=\"button\" value=\"".Dict::Format('UI:AddLinkedObjectsOf_Class', MetaModel::GetName($this->m_sRemoteClass))."\" onClick=\"oWidget$iWidgetIndex.AddObjects();\"></span>\n";
$sHtmlValue .= "<span style=\"float:left;\">&nbsp;&nbsp;&nbsp;<img src=\"../images/tv-item-last.gif\">&nbsp;&nbsp;<input id=\"{$this->m_sAttCode}{$this->m_sNameSuffix}_btnRemove\" type=\"button\" value=\"".Dict::S('UI:RemoveLinkedObjectsOf_Class')."\" onClick=\"oWidget{$this->m_iInputId}.RemoveSelected();\" >";
$sHtmlValue .= "&nbsp;&nbsp;&nbsp;<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>&nbsp;</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;
}
/**
* This static function is called by the Ajax Page when there is a need to fill an autocomplete combo
* @param $oPage WebPage The ajax page used for the output (sent back to the browser)
* @param $sClass string The name of the class of the current object being edited
* @param $sAttCode string The name of the attribute being edited
* @param $sName string The partial name that was typed by the user
* @param $iMaxCount integer The maximum number of items to return
* @return void
*/
static public function Autocomplete(WebPage $oPage, $sClass, $sAttCode, $sName, $iMaxCount)
{
// #@# todo - add context information, otherwise any value will be authorized for external keys
$aAllowedValues = MetaModel::GetAllowedValues_att($sClass, $sAttCode, array() /* $aArgs */, $sName);
if ($aAllowedValues != null)
{
$iCount = $iMaxCount;
foreach($aAllowedValues as $key => $value)
{
$oPage->add($value."|".$key."\n");
$iCount--;
if ($iCount == 0) break;
}
}
else // No limitation to the allowed values
{
// Search for all the object of the linked class
$oAttDef = $oAttDef = MetaModel::GetAttributeDef($sClass, $sAttCode);
$sLinkedClass = $oAttDef->GetLinkedClass();
$sSearchClass = self::GetTargetClass($sClass, $sAttCode);
$oFilter = new DBObjectSearch($sSearchClass);
$sSearchAttCode = MetaModel::GetNameAttributeCode($sSearchClass);
$oFilter->AddCondition($sSearchAttCode, $sName, 'Begins with');
$oSet = new CMDBObjectSet($oFilter, array($sSearchAttCode => true));
$iCount = 0;
while( ($iCount < $iMaxCount) && ($oObj = $oSet->fetch()) )
{
$oPage->add($oObj->GetName()."|".$oObj->GetKey()."\n");
$iCount++;
}
}
}
/**
* This static function is called by the Ajax Page display a set of objects being linked
* to the object being created
* @param $oPage WebPage The ajax page used for the put^put (sent back to the browser
* @param $sClass string The name of the 'linking class' which is the class of the objects to display
* @param $sSet JSON serialized set of objects
* @param $sExtKeyToMe Name of the attribute in sClass that is pointing to a given object
* @param $iObjectId The id of the object $sExtKeyToMe is pointing to
* @return void
*/
static public function RenderSet($oPage, $sClass, $sJSONSet, $sExtKeyToMe, $sExtKeyToRemote, $iObjectId)
{
$aSet = json_decode($sJSONSet, true); // true means hash array instead of object
$oSet = CMDBObjectSet::FromScratch($sClass);
foreach($aSet as $aObject)
{
$oObj = MetaModel::NewObject($sClass);
foreach($aObject as $sAttCode => $value)
{
$oAttDef = MetaModel::GetAttributeDef($sClass, $sAttCode);
if ($oAttDef->IsExternalKey() && ($value != 0))
{
$oTargetObj = MetaModel::GetObject($oAttDef->GetTargetClass(), $value); // @@ optimization, don't do & query per object in the set !
$oObj->Set($sAttCode, $oTargetObj);
}
else
{
$oObj->Set($sAttCode, $value);
}
}
$oSet->AddObject($oObj);
}
$aExtraParams = array();
$aExtraParams['link_attr'] = $sExtKeyToMe;
$aExtraParams['object_id'] = $iObjectId;
$aExtraParams['target_attr'] = $sExtKeyToRemote;
$aExtraParams['menu'] = false;
$aExtraParams['select'] = false;
$aExtraParams['view_link'] = false;
cmdbAbstractObject::DisplaySet($oPage, $oSet, $aExtraParams);
}
protected static function GetTargetClass($sClass, $sAttCode)
{
$oAttDef = MetaModel::GetAttributeDef($sClass, $sAttCode);
@@ -341,28 +332,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";
$iWidgetIndex = self::$iWidgetIndex;
$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$iWidgetIndex.DoAddObjects(this.id);\">\n";
$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');\">&nbsp;&nbsp;<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');\">&nbsp;&nbsp;<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_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$iWidgetIndex.UpdateSizes });");
$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$iWidgetIndex.SearchObjectsToAdd);");
$oPage->add_ready_script("$('#SearchFormToAdd_{$this->m_sAttCode}{$this->m_sNameSuffix}').resize(oWidget$iWidgetIndex.UpdateSizes);");
return $sHtml;
$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);");
}
/**
@@ -383,7 +372,7 @@ EOF
// No remote class specified use the one defined in the linkedset
$oFilter = new DBObjectSearch($this->m_sRemoteClass);
}
if (count($aAlreadyLinkedIds) > 0)
if (!$this->m_bDuplicatesAllowed && count($aAlreadyLinkedIds) > 0)
{
// Positive IDs correspond to existing link records
// negative IDs correspond to "remote" objects to be linked
@@ -416,18 +405,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
@@ -436,5 +426,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);
}
}
}
}
}
?>

View File

@@ -24,8 +24,8 @@
* @license http://www.opensource.org/licenses/gpl-3.0.html LGPL
*/
require_once('../application/webpage.class.inc.php');
require_once('../application/displayblock.class.inc.php');
require_once(APPROOT.'/application/webpage.class.inc.php');
require_once(APPROOT.'/application/displayblock.class.inc.php');
class UIPasswordWidget
{
@@ -52,17 +52,34 @@ class UIPasswordWidget
{
$sCode = $this->sAttCode.$this->sNameSuffix;
$iWidgetIndex = self::$iWidgetIndex;
$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="*****"/>&nbsp;<span id="v_'.$this->iId.'"></span><br/>';
$sHtmlValue .= '<input type="password" maxlength="255" id="'.$this->iId.'_confirm" value="*****"/> '.Dict::S('UI:PasswordConfirm').' <input 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="0"/>';
$sHtmlValue = '<input type="password" maxlength="255" name="attr_'.$sCode.'[value]" id="'.$this->iId.'" value="'.htmlentities($sPasswordValue, ENT_QUOTES, 'UTF-8').'"/>&nbsp;<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', 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
$oPage->add_ready_script("$('#{$this->iId}_confirm').bind('keyup change', function(evt, sFormId) { return ValidatePasswordField('$this->iId', sFormId) } );"); // Bind to a custom event: validate
$oPage->add_ready_script("$('#{$this->iId}').bind('update', function(evt, sFormId)
{
if ($(this).attr('disabled'))
{
$('#{$this->iId}_confirm').attr('disabled', 'disabled');
$('#{$this->iId}_changed').attr('disabled', 'disabled');
$('#{$this->iId}_reset').attr('disabled', 'disabled');
}
else
{
$('#{$this->iId}_confirm').removeAttr('disabled');
$('#{$this->iId}_changed').removeAttr('disabled');
$('#{$this->iId}_reset').removeAttr('disabled');
}
}
);"); // Bind to a custom event: update to handle enabling/disabling
return $sHtmlValue;
}
}
?>
?>

View File

@@ -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( '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( '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( '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())

View File

@@ -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());
@@ -227,7 +225,7 @@ $sJSHandlerCode
// Now use the dependencies between the fields to order them
// Start from the order of the 'details'
$aList = MetaModel::GetZListItems($this->m_sClass, 'details');
$aList = MetaModel::FlattenZlist(MetaModel::GetZListItems($this->m_sClass, 'details'));
$index = 0;
$aOrder = array();
foreach($aFields as $sAttCode => $void)

View File

@@ -22,8 +22,8 @@
* @author Denis Flaven <denis.flaven@combodo.com>
* @license http://www.opensource.org/licenses/gpl-3.0.html LGPL
*/
require_once('../core/dbobject.class.php');
require_once('../core/userrights.class.inc.php');
require_once(APPROOT.'/core/dbobject.class.php');
require_once(APPROOT.'/core/userrights.class.inc.php');
/**
* This class is used to store, in a persistent manner, user related settings (preferences)
@@ -169,9 +169,9 @@ class appUserPreferences extends DBObject
* Overloading this function here to secure a fix done right before the release
* The real fix should be to implement this verb in DBObject
*/
public function DBDeleteTracked(CMDBChange $oChange, $bSkipStrongSecurity = null)
public function DBDeleteTracked(CMDBChange $oChange, $bSkipStrongSecurity = null, &$oDeletionPlan = null)
{
$this->DBDelete();
$this->DBDelete($oDeletionPlan);
}
}
?>

View File

@@ -23,10 +23,11 @@
* @license http://www.opensource.org/licenses/gpl-3.0.html LGPL
*/
require_once('../core/config.class.inc.php');
require_once('../application/transaction.class.inc.php');
require_once(APPROOT.'/core/config.class.inc.php');
require_once(APPROOT.'/application/transaction.class.inc.php');
define('ITOP_CONFIG_FILE', '../config-itop.php');
define('ITOP_CONFIG_FILE', APPROOT.'/config-itop.php');
define('SERVER_NAME_PLACEHOLDER', '$SERVER_NAME$');
class FileUploadException extends Exception
{
@@ -41,12 +42,89 @@ 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)
{
if (!file_exists($sParamFile))
{
throw new Exception("Could not find the parameter file: '$sParamFile'");
}
if (!is_readable($sParamFile))
{
throw new Exception("Could not load parameter file: '$sParamFile'");
}
$sParams = file_get_contents($sParamFile);
if (is_null(self::$m_aParamsFromFile))
{
self::$m_aParamsFromFile = array();
}
$aParamLines = explode("\n", $sParams);
foreach ($aParamLines as $sLine)
{
$sLine = trim($sLine);
// Ignore the line after a '#'
if (($iCommentPos = strpos($sLine, '#')) !== false)
{
$sLine = substr($sLine, 0, $iCommentPos);
$sLine = trim($sLine);
}
// Note: the line is supposed to be already trimmed
if (preg_match('/^(\S*)\s*=(.*)$/', $sLine, $aMatches))
{
$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, 'raw_data');
foreach(explode(',', $sFileSpec) as $sFile)
{
$sFile = trim($sFile);
if (!empty($sFile))
{
self::LoadParamFile($sFile);
}
}
}
/**
* 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()
{
global $argv;
if (isset($argv))
$sSAPIName = php_sapi_name();
$sCleanName = strtolower(trim($sSAPIName));
if ($sCleanName == 'cli')
{
return true;
}
@@ -57,10 +135,19 @@ class utils
}
public static function ReadParam($sName, $defaultValue = "", $bAllowCLI = false)
public static function ReadParam($sName, $defaultValue = "", $bAllowCLI = false, $sSanitizationFilter = 'parameter')
{
global $argv;
$retValue = $defaultValue;
if (!is_null(self::$m_aParamsFromFile))
{
if (isset(self::$m_aParamsFromFile[$sName]))
{
$retValue = self::$m_aParamsFromFile[$sName];
}
}
if (isset($_REQUEST[$sName]))
{
$retValue = $_REQUEST[$sName];
@@ -75,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
@@ -115,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:
@@ -140,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;
}
@@ -152,14 +326,56 @@ 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();
}
public static function IsTransactionValid($sId)
public static function IsTransactionValid($sId, $bRemoveTransaction = true)
{
return privUITransaction::IsTransactionValid($sId);
return privUITransaction::IsTransactionValid($sId, $bRemoveTransaction);
}
public static function RemoveTransaction($sId)
{
return privUITransaction::RemoveTransaction($sId);
}
public static function ReadFromFile($sFileName)
@@ -168,28 +384,6 @@ class utils
return file_get_contents($sFileName);
}
/**
* Specify the application config file
* @param string path to the config file
* @return void
*/
public static function SpecifyConfigFile($sFilePath)
{
self::$m_sConfigFile = $sFilePath;
}
/**
* Get access to the application config file
* @param none
* @return Config The Config object initialized from the application config file
*/
public static function GetConfig()
{
if (self::$m_oConfig == null)
{
self::$m_oConfig = new Config(self::$m_sConfigFile);
}
return self::$m_oConfig;
}
/**
* Helper function to convert a value expressed in a 'user friendly format'
* as in php.ini, e.g. 256k, 2M, 1G etc. Into a number of bytes
@@ -217,38 +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 = $_SERVER['SERVER_NAME'];
if (self::GetConfig()->GetSecureConnectionRequired() || self::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']) ? 'https' : 'http';
if ($sProtocol == 'http')
if (isset($_SERVER['SERVER_NAME']))
{
$sPort = ($_SERVER['SERVER_PORT'] == 80) ? '' : ':'.$_SERVER['SERVER_PORT'];
$sServerName = $_SERVER['SERVER_NAME'];
}
else
{
$sPort = ($_SERVER['SERVER_PORT'] == 443) ? '' : ':'.$_SERVER['SERVER_PORT'];
// 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)
@@ -265,48 +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;
}
$sPath = $_SERVER['REQUEST_URI'];
// 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);
/**
* 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;
$sAppRootPos = strpos($sAbsoluteUrl, $sCurrentRelativePath);
if ($sAppRootPos !== false)
{
$sAppRootUrl = substr($sAbsoluteUrl, 0, $sAppRootPos); // remove the current page and path
}
else
{
// 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 $sAppRootUrl;
}
/**
* 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
* 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 GetAbsoluteUrlRoot($bForceHTTPS = false)
static public function GetAbsoluteUrlModulesRoot()
{
$sAbsoluteUrl = self::GetAbsoluteUrl(false, $bForceHTTPS); // False => Don't get the query string
$sServerPos = 3 + strpos($sAbsoluteUrl, '://');
$iFirstSlashPos = strpos($sAbsoluteUrl, '/', $sServerPos);
if ($iFirstSlashPos !== false)
{
$sAbsoluteUrl = substr($sAbsoluteUrl, 0, $iFirstSlashPos); // remove the current page, keep just the path, without the first /
}
return $sAbsoluteUrl;
$sUrl = self::GetAbsoluteUrlAppRoot().'modules/';
return $sUrl;
}
/**
@@ -318,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);
}
}
?>

View File

@@ -45,7 +45,14 @@ class WebPage
protected $a_include_stylesheets;
protected $a_headers;
protected $a_base;
protected $iNextId;
protected $iTransactionId;
protected $sContentType;
protected $sContentDisposition;
protected $sContentFileName;
protected $s_sOutputFormat;
protected $a_OutputOptions;
public function __construct($s_title)
{
$this->s_title = $s_title;
@@ -57,6 +64,13 @@ class WebPage
$this->a_linked_stylesheets = array();
$this->a_headers = array();
$this->a_base = array( 'href' => '', 'target' => '');
$this->iNextId = 0;
$this->iTransactionId = 0;
$this->sContentType = '';
$this->sContentDisposition = '';
$this->sContentFileName = '';
$this->s_OutputFormat = utils::ReadParam('output_format', 'html');
$this->a_OutputOptions = array();
ob_start(); // Start capturing the output
}
@@ -86,11 +100,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;
}
@@ -103,6 +117,14 @@ class WebPage
$this->add($this->GetP($s_html));
}
/**
* Add a pre-formatted text to the body of the page
*/
public function pre($s_html)
{
$this->add('<pre>'.$s_html.'</pre>');
}
/**
* Add a paragraph to the body of the page
*/
@@ -142,27 +164,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] === '') ? '&nbsp;' : $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] === '') ? '&nbsp;' : $aRow[$sName];
$sHtml .= "<td $sClass>$sValue</td>";
}
$sHtml .= "</tr>";
return $sHtml;
}
/**
* Add some Javascript to the header of the page
@@ -192,7 +220,7 @@ class WebPage
*/
public function add_linked_script($s_linked_script)
{
$this->a_linked_scripts[] = $s_linked_script;
$this->a_linked_scripts[$s_linked_script] = $s_linked_script;
}
/**
@@ -228,13 +256,35 @@ 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
*/
public function GetDetails($aFields)
{
$sHtml = "<table>\n";
$sHtml = "<table class=\"details\">\n";
$sHtml .= "<tbody>\n";
foreach($aFields as $aAttrib)
{
@@ -248,12 +298,62 @@ class WebPage
{
$sHtml .= "<td class=\"label\">".$aAttrib['label']."</td><td>".$aAttrib['value']."</td>\n";
}
$sComment = (isset($aAttrib['comments'])) ? $aAttrib['comments'] : '&nbsp;';
$sInfo = (isset($aAttrib['infos'])) ? $aAttrib['infos'] : '&nbsp;';
$sHtml .= "<td>$sComment</td><td>$sInfo</td>\n";
$sHtml .= "</tr>\n";
}
$sHtml .= "</tbody>\n";
$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}\">&nbsp;$display_value</label>&nbsp;";
if ($bVertical)
{
if ($idx == 0)
{
// Validation icon at the end of the first line
$sHTMLValue .= "&nbsp;{$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 .= "&nbsp;{$sValidationField}\n";
}
return $sHTMLValue;
}
/**
* Outputs (via some echo) the complete HTML page by assembling all its elements
@@ -269,11 +369,21 @@ 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)
{
$s_script .= "?itopversion=".ITOP_VERSION;
}
else
{
$s_script .= "&itopversion=".ITOP_VERSION;
}
echo "<script type=\"text/javascript\" src=\"$s_script\"></script>\n";
}
if (count($this->a_scripts)>0)
@@ -307,14 +417,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 $this->s_deferred_content;
echo '<div id="at_the_end">'.self::FilterXSS($this->s_deferred_content).'</div>';
echo "</body>\n";
echo "</html>\n";
}
@@ -350,5 +464,122 @@ class WebPage
}
return $sTag;
}
/**
* Get an ID (for any kind of HTML tag) that is guaranteed unique in this page
* @return int The unique ID (in this page)
*/
public function GetUniqueId()
{
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
* @return void
*/
public function SetTransactionId($iTransactionId)
{
$this->iTransactionId = $iTransactionId;
}
/**
* Returns the transactionId of the current form
* @return integer The current transactionID
*/
public function GetTransactionId()
{
return $this->iTransactionId;
}
public static function FilterXSS($sHTML)
{
return str_ireplace('<script', '&lt;script', $sHTML);
}
/**
* What is the currently selected output format
* @return string The selected output format: html, pdf...
*/
public function GetOutputFormat()
{
return $this->s_OutputFormat;
}
/**
* Check whether the desired output format is possible or not
* @param string $sOutputFormat The desired output format: html, pdf...
* @return bool True if the format is Ok, false otherwise
*/
function IsOutputFormatAvailable($sOutputFormat)
{
$bResult = false;
switch($sOutputFormat)
{
case 'html':
$bResult = true; // Always supported
break;
case 'pdf':
$bResult = @is_readable(APPROOT.'lib/MPDF/mpdf.php');
break;
}
return $bResult;
}
/**
* Retrieves the value of a named output option for the given format
* @param string $sFormat The format: html or pdf
* @param string $sOptionName The name of the option
* @return mixed false if the option was never set or the options's value
*/
public function GetOutputOption($sFormat, $sOptionName)
{
if (isset($this->a_OutputOptions[$sFormat][$sOptionName]))
{
return $this->a_OutputOptions[$sFormat][$sOptionName];
}
return false;
}
/**
* Sets a named output option for the given format
* @param string $sFormat The format for which to set the option: html or pdf
* @param string $sOptionName the name of the option
* @param mixed $sValue The value of the option
*/
public function SetOutputOption($sFormat, $sOptionName, $sValue)
{
if (!isset($this->a_OutputOptions[$sFormat]))
{
$this->a_OutputOptions[$sFormat] = array($sOptionName => $sValue);
}
else
{
$this->a_OutputOptions[$sFormat][$sOptionName] = $sValue;
}
}
}
?>
?>

View File

@@ -23,7 +23,7 @@
* @license http://www.opensource.org/licenses/gpl-3.0.html LGPL
*/
require_once('../application/uiwizard.class.inc.php');
require_once(APPROOT.'/application/uiwizard.class.inc.php');
class WizardHelper
{
@@ -50,8 +50,8 @@ class WizardHelper
foreach($this->m_aData['m_oCurrentValues'] as $sAttCode => $value)
{
// Because this is stored in a Javascript array, unused indexes
// are filled with null values
if ( ($sAttCode !='id') && ($sAttCode !== false) && ($value !== null))
// are filled with null values and unused keys (stored as strings) contain $$NULL$$
if ( ($sAttCode !='id') && ($sAttCode !== false) && ($value !== null) && ($value !== '$$NULL$$'))
{
$oAttDef = MetaModel::GetAttributeDef($this->m_aData['m_sClass'], $sAttCode);
if (($oAttDef->IsLinkSet()) && ($value != '') )
@@ -98,7 +98,7 @@ class WizardHelper
{
if ($bReadUploadedFiles)
{
$oDocument = utils::ReadPostedDocument('file_'.$sAttCode);
$oDocument = utils::ReadPostedDocument('attr_'.$sAttCode, 'fcontents');
$oObj->Set($sAttCode, $oDocument);
}
else
@@ -121,6 +121,11 @@ class WizardHelper
}
}
}
if (isset($this->m_aData['m_sState']) && !empty($this->m_aData['m_sState']))
{
$oObj->Set(MetaModel::GetStateAttributeCode($this->m_aData['m_sClass']), $this->m_aData['m_sState']);
}
$oObj->DoComputeValues();
return $oObj;
}
@@ -227,6 +232,11 @@ class WizardHelper
return $this->m_aData['m_sClass'];
}
public function GetFormPrefix()
{
return $this->m_aData['m_sFormPrefix'];
}
public function GetIdForField($sFieldName)
{
$sResult = '';

View File

@@ -23,30 +23,70 @@
* @license http://www.opensource.org/licenses/gpl-3.0.html LGPL
*/
require_once("../application/webpage.class.inc.php");
require_once(APPROOT."/application/webpage.class.inc.php");
/**
* Simple web page with no includes or fancy formatting, useful to generateXML documents
* The page adds the content-type text/XML and the encoding into the headers
*/
class XMLPage extends WebPage
{
function __construct($s_title)
/**
* For big XML files, it's better NOT to store everything in memory and output the XML piece by piece
*/
var $m_bPassThrough;
var $m_bHeaderSent;
function __construct($s_title, $bPassThrough = false)
{
parent::__construct($s_title);
$this->add_header("Content-type: text/xml; charset=utf-8");
$this->m_bPassThrough = $bPassThrough;
$this->m_bHeaderSent = false;
$this->add_header("Content-type: text/xml; charset=utf-8");
$this->add_header("Cache-control: no-cache");
$this->add_header("Content-location: export.xml");
$this->add("<?xml version=\"1.0\" encoding=\"UTF-8\"?".">\n");
}
public function output()
{
$this->add_header("Content-Length: ".strlen(trim($this->s_content)));
foreach($this->a_headers as $s_header)
{
header($s_header);
}
echo trim($this->s_content);
if (!$this->m_bPassThrough)
{
$this->add("<?xml version=\"1.0\" encoding=\"UTF-8\"?".">\n");
$this->add_header("Content-Length: ".strlen(trim($this->s_content)));
foreach($this->a_headers as $s_header)
{
header($s_header);
}
echo trim($this->s_content);
}
}
public function add($sText)
{
if (!$this->m_bPassThrough)
{
parent::add($sText);
}
else
{
if ($this->m_bHeaderSent)
{
echo $sText;
}
else
{
$s_captured_output = ob_get_contents();
ob_end_clean();
foreach($this->a_headers as $s_header)
{
header($s_header);
}
echo "<?xml version=\"1.0\" encoding=\"UTF-8\"?".">\n";
echo trim($s_captured_output);
echo trim($this->s_content);
echo $sText;
$this->m_bHeaderSent = true;
}
}
}
public function small_p($sText)

12
approot.inc.php Normal file
View File

@@ -0,0 +1,12 @@
<?php
define('APPROOT', dirname(__FILE__).'/');
define('MODULESROOT', APPROOT.'modules/');
if (function_exists('microtime'))
{
$fItopStarted = microtime(true);
}
else
{
$fItopStarted = 1000 * time();
}
?>

View File

@@ -443,9 +443,9 @@ class Str
public static function pure2html($pure, $maxLength = false)
{
// Check for HTML entities, but be careful the DB is in UTF-8
return $maxLength
? htmlentities(substr($pure, 0, $maxLength), ENT_COMPAT, 'UTF-8')
: htmlentities($pure, ENT_COMPAT, 'UTF-8');
return $maxLength
? htmlentities(substr($pure, 0, $maxLength), ENT_QUOTES, 'UTF-8')
: htmlentities($pure, ENT_QUOTES, 'UTF-8');
}
public static function pure2sql($pure, $maxLength = false)
{
@@ -488,7 +488,7 @@ class Str
*/
protected static function xmlencode($string)
{
return self::xmlentities(iconv("ISO-8859-1", "UTF-8//IGNORE",$string));
return self::xmlentities(iconv("UTF-8", "UTF-8//IGNORE",$string));
}
public static function islowcase($sString)

View File

@@ -24,7 +24,8 @@
*/
require_once('../core/email.class.inc.php');
require_once(APPROOT.'/core/asynctask.class.inc.php');
require_once(APPROOT.'/core/email.class.inc.php');
/**
* A user defined action, to customize the application
@@ -41,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",
@@ -105,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" => "",
@@ -134,11 +135,11 @@ class ActionEmail extends ActionNotification
{
$aParams = array
(
"category" => "core/cmdb",
"category" => "core/cmdb,bizmodel",
"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" => "",
@@ -162,7 +163,7 @@ class ActionEmail extends ActionNotification
MetaModel::Init_SetZListItems('details', array('name', 'description', 'status', 'test_recipient', 'from', 'reply_to', 'to', 'cc', 'bcc', 'subject', 'body', 'importance', 'trigger_list')); // Attributes to be displayed for the complete details
MetaModel::Init_SetZListItems('list', array('name', 'status', 'to', 'subject')); // Attributes to be displayed for a list
// Search criteria
// MetaModel::Init_SetZListItems('standard_search', array('name')); // Criteria of the std search form
MetaModel::Init_SetZListItems('standard_search', array('name','description', 'status', 'subject')); // Criteria of the std search form
// MetaModel::Init_SetZListItems('advanced_search', array('name')); // Criteria of the advanced search form
}
@@ -182,6 +183,7 @@ class ActionEmail extends ActionNotification
try
{
$oSearch = DBObjectSearch::FromOQL($sOQL);
$oSearch->AllowAllData();
}
catch (OQLException $e)
{
@@ -219,113 +221,94 @@ class ActionEmail extends ActionNotification
public function DoExecute($oTrigger, $aContextArgs)
{
$this->m_iRecipients = 0;
$this->m_aMailErrors = array();
$bRes = false; // until we do succeed in sending the email
try
{
// 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);
$oEmail = new EMail();
if ($this->IsBeingTested())
{
$oEmail->SetSubject('TEST['.$sSubject.']');
$sTestBody = $sBody;
$sTestBody .= "<div style=\"border: dashed;\">\n";
$sTestBody .= "<h1>Testing email notification ".$this->GetHyperlink()."</h1>\n";
$sTestBody .= "<p>The email should be sent with the following properties\n";
$sTestBody .= "<ul>\n";
$sTestBody .= "<li>TO: $sTo</li>\n";
$sTestBody .= "<li>CC: $sCC</li>\n";
$sTestBody .= "<li>BCC: $sBCC</li>\n";
$sTestBody .= "<li>From: $sFrom</li>\n";
$sTestBody .= "<li>Reply-To: $sReplyTo</li>\n";
$sTestBody .= "</ul>\n";
$sTestBody .= "</p>\n";
$sTestBody .= "</div>\n";
$oEmail->SetBody($sTestBody);
$oEmail->SetRecipientTO($this->Get('test_recipient'));
$oEmail->SetRecipientFrom($this->Get('test_recipient'));
}
else
{
$oEmail->SetSubject($sSubject);
$oEmail->SetBody($sBody);
$oEmail->SetRecipientTO($sTo);
$oEmail->SetRecipientCC($sCC);
$oEmail->SetRecipientBCC($sBCC);
$oEmail->SetRecipientFrom($sFrom);
$oEmail->SetRecipientReplyTo($sReplyTo);
}
if (empty($this->m_aMailErrors))
{
if ($this->m_iRecipients == 0)
{
$this->m_aMailErrors[] = 'No recipient';
}
else
{
$oKPI = new ExecutionKPI();
$this->m_aMailErrors = array_merge($this->m_aMailErrors, $oEmail->Send());
$oKPI->ComputeStats('Send mail', $sTo);
}
}
}
catch (Exception $e)
{
$this->m_aMailErrors[] = $e->getMessage();
}
if (MetaModel::IsLogEnabledNotification())
{
$oLog = new EventNotificationEmail();
if (empty($this->m_aMailErrors))
if ($this->IsBeingTested())
{
if ($this->IsBeingTested())
{
$oLog->Set('message', 'TEST - Notification sent ('.$this->Get('test_recipient').')');
}
else
{
$oLog->Set('message', 'Notification sent');
}
$oLog->Set('message', 'TEST - Notification sent ('.$this->Get('test_recipient').')');
}
else
{
if (is_array($this->m_aMailErrors) && count($this->m_aMailErrors) > 0)
{
$sError = implode(', ', $this->m_aMailErrors);
}
else
{
$sError = 'Unknown reason';
}
if ($this->IsBeingTested())
{
$oLog->Set('message', 'TEST - Notification was not sent: '.$sError);
}
else
{
$oLog->Set('message', 'Notification was not sent: '.$sError);
}
$oLog->Set('message', 'Notification pending');
}
$oLog->Set('userinfo', UserRights::GetUser());
$oLog->Set('trigger_id', $oTrigger->GetKey());
$oLog->Set('action_id', $this->GetKey());
$oLog->Set('object_id', $aContextArgs['this->object()']->GetKey());
// Must be inserted now so that it gets a valid id that will make the link
// between an eventual asynchronous task (queued) and the log
$oLog->DBInsertNoReload();
}
else
{
$oLog = null;
}
try
{
$sRes = $this->_DoExecute($oTrigger, $aContextArgs, $oLog);
if ($this->IsBeingTested())
{
$sPrefix = 'TEST ('.$this->Get('test_recipient').') - ';
}
else
{
$sPrefix = '';
}
$oLog->Set('message', $sPrefix.$sRes);
}
catch (Exception $e)
{
if ($oLog)
{
$oLog->Set('message', 'Error: '.$e->getMessage());
}
}
if ($oLog)
{
$oLog->DBUpdate();
}
}
protected function _DoExecute($oTrigger, $aContextArgs, &$oLog)
{
$sPreviousUrlMaker = ApplicationContext::SetUrlMakerClass();
$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);
if (!is_null($oLog))
{
// Note: we have to secure this because those values are calculated
// inside the try statement, and we would like to keep track of as
// many data as we could while some variables may still be undefined
@@ -335,8 +318,78 @@ class ActionEmail extends ActionNotification
if (isset($sFrom)) $oLog->Set('from', $sFrom);
if (isset($sSubject)) $oLog->Set('subject', $sSubject);
if (isset($sBody)) $oLog->Set('body', $sBody);
$oLog->DBInsertNoReload();
}
$oEmail = new EMail('', '', '', $aHeaders);
if ($this->IsBeingTested())
{
$oEmail->SetSubject('TEST['.$sSubject.']');
$sTestBody = $sBody;
$sTestBody .= "<div style=\"border: dashed;\">\n";
$sTestBody .= "<h1>Testing email notification ".$this->GetHyperlink()."</h1>\n";
$sTestBody .= "<p>The email should be sent with the following properties\n";
$sTestBody .= "<ul>\n";
$sTestBody .= "<li>TO: $sTo</li>\n";
$sTestBody .= "<li>CC: $sCC</li>\n";
$sTestBody .= "<li>BCC: $sBCC</li>\n";
$sTestBody .= "<li>From: $sFrom</li>\n";
$sTestBody .= "<li>Reply-To: $sReplyTo</li>\n";
$sTestBody .= "<li>References: $sReference</li>\n";
$sTestBody .= "</ul>\n";
$sTestBody .= "</p>\n";
$sTestBody .= "</div>\n";
$oEmail->SetBody($sTestBody);
$oEmail->SetRecipientTO($this->Get('test_recipient'));
$oEmail->SetRecipientFrom($this->Get('test_recipient'));
$oEmail->SetReferences($sReference);
}
else
{
$oEmail->SetSubject($sSubject);
$oEmail->SetBody($sBody);
$oEmail->SetRecipientTO($sTo);
$oEmail->SetRecipientCC($sCC);
$oEmail->SetRecipientBCC($sBCC);
$oEmail->SetRecipientFrom($sFrom);
$oEmail->SetRecipientReplyTo($sReplyTo);
$oEmail->SetReferences($sReference);
}
if (empty($this->m_aMailErrors))
{
if ($this->m_iRecipients == 0)
{
return 'No recipient';
}
else
{
$iRes = $oEmail->Send($aErrors, false, $oLog); // allow asynchronous mode
switch ($iRes)
{
case EMAIL_SEND_OK:
return "Sent";
case EMAIL_SEND_PENDING:
return "Pending";
case EMAIL_SEND_ERROR:
return "Errors: ".implode(', ', $aErrors);
}
}
}
else
{
if (is_array($this->m_aMailErrors) && count($this->m_aMailErrors) > 0)
{
$sError = implode(', ', $this->m_aMailErrors);
}
else
{
$sError = 'Unknown reason';
}
return 'Notification was not sent: '.$sError;
}
}
}
?>
?>

View File

@@ -142,7 +142,7 @@ class iTopArchive
public function WriteCatalog()
{
$sXml = "<?xml version=\"1.0\" encoding=\"iso-8859-1\"?".">\n"; // split the XML closing tag that disturbs PSPad's syntax coloring
$sXml = "<?xml version=\"1.0\" encoding=\"utf-8\"?".">\n"; // split the XML closing tag that disturbs PSPad's syntax coloring
$sXml .= "<archive version=\"1.0\">\n";
$sXml .= "<title>{$this->m_sTitle}</title>\n";
$sXml .= "<description>{$this->m_sDescription}</description>\n";

View File

@@ -0,0 +1,192 @@
<?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 classes (internal): user defined actions
*
* @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
*/
class ExecAsyncTask implements iBackgroundProcess
{
public function GetPeriodicity()
{
return 2; // seconds
}
public function Process($iTimeLimit)
{
$sOQL = "SELECT AsyncTask WHERE ISNULL(started) AND (ISNULL(planned) OR (planned < NOW()))";
$oSet = new CMDBObjectSet(DBObjectSearch::FromOQL($sOQL), array('created' => true) /* order by*/, array());
$iProcessed = 0;
while ((time() < $iTimeLimit) && ($oTask = $oSet->Fetch()))
{
$oTask->Set('started', time());
$oTask->DBUpdate();
$oTask->Process();
$iProcessed++;
$oTask->DBDelete();
}
if ($iProcessed == $oSet->Count())
{
return "processed $iProcessed tasks";
}
else
{
return "processed $iProcessed tasks (remaining: ".($oSet->Count() - $iProcessed).")";
}
}
}
/**
* A
*
* @package iTopORM
*/
abstract class AsyncTask extends DBObject
{
public static function Init()
{
$aParams = array
(
"category" => "core/cmdb",
"key_type" => "autoincrement",
"name_attcode" => array('created'),
"state_attcode" => "",
"reconc_keys" => array(),
"db_table" => "priv_async_task",
"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 AttributeDateTime("created", array("allowed_values"=>null, "sql"=>"created", "default_value"=>"", "is_null_allowed"=>false, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeDateTime("started", array("allowed_values"=>null, "sql"=>"started", "default_value"=>"", "is_null_allowed"=>true, "depends_on"=>array())));
// planned... still not used - reserved for timer management
MetaModel::Init_AddAttribute(new AttributeDateTime("planned", array("allowed_values"=>null, "sql"=>"planned", "default_value"=>"", "is_null_allowed"=>true, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeExternalKey("event_id", array("targetclass"=>"Event", "jointype"=> "", "allowed_values"=>null, "sql"=>"event_id", "is_null_allowed"=>true, "on_target_delete"=>DEL_SILENT, "depends_on"=>array())));
// Display lists
// MetaModel::Init_SetZListItems('details', array()); // Attributes to be displayed for the complete details
// MetaModel::Init_SetZListItems('list', array()); // 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
}
protected function OnInsert()
{
$this->Set('created', time());
}
public function Process()
{
$sStatus = $this->DoProcess();
if ($this->Get('event_id') != 0)
{
$oEventLog = MetaModel::GetObject('Event', $this->Get('event_id'));
$oEventLog->Set('message', $sStatus);
$oEventLog->DBUpdate();
}
}
abstract public function DoProcess();
}
/**
* An email notification
*
* @package iTopORM
*/
class AsyncSendEmail extends AsyncTask
{
public static function Init()
{
$aParams = array
(
"category" => "core/cmdb",
"key_type" => "autoincrement",
"name_attcode" => "created",
"state_attcode" => "",
"reconc_keys" => array(),
"db_table" => "priv_async_send_email",
"db_key_field" => "id",
"db_finalclass_field" => "",
"display_template" => "",
);
MetaModel::Init_Params($aParams);
MetaModel::Init_InheritAttributes();
MetaModel::Init_AddAttribute(new AttributeText("to", array("allowed_values"=>null, "sql"=>"to", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeText("subject", array("allowed_values"=>null, "sql"=>"subject", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeLongText("body", array("allowed_values"=>null, "sql"=>"body", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeText("header", array("allowed_values"=>null, "sql"=>"header", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array())));
// Display lists
// MetaModel::Init_SetZListItems('details', array('name', 'description', 'status', 'test_recipient', 'from', 'reply_to', 'to', 'cc', 'bcc', 'subject', 'body', 'importance', 'trigger_list')); // Attributes to be displayed for the complete details
// MetaModel::Init_SetZListItems('list', array('name', 'status', 'to', 'subject')); // Attributes to be displayed for a list
// Search criteria
// MetaModel::Init_SetZListItems('standard_search', array('name')); // Criteria of the std search form
// MetaModel::Init_SetZListItems('advanced_search', array('name')); // Criteria of the advanced search form
}
static public function AddToQueue($sTo, $sSubject, $sBody, $aHeaders, $oLog)
{
$oNew = MetaModel::NewObject(__class__);
if ($oLog)
{
$oNew->Set('event_id', $oLog->GetKey());
}
$oNew->Set('to', $sTo);
$oNew->Set('subject', $sSubject);
$oNew->Set('body', $sBody);
$sHeaders = serialize($aHeaders);
$oNew->Set('header', $sHeaders);
$oNew->DBInsert();
}
public function DoProcess()
{
$sTo = $this->Get('to');
$sSubject = $this->Get('subject');
$sBody = $this->Get('body');
$sHeaders = $this->Get('header');
$aHeaders = unserialize($sHeaders);
$oEmail = new EMail($sTo, $sSubject, $sBody, $aHeaders);
$iRes = $oEmail->Send($aIssues, true /* force synchro !!!!! */);
switch ($iRes)
{
case EMAIL_SEND_OK:
return "Sent";
case EMAIL_SEND_PENDING:
return "Bug - the email should be sent in synchronous mode";
case EMAIL_SEND_ERROR:
return "Failed: ".implode(', ', $aIssues);
}
}
}
?>

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,33 @@
<?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
/**
* Class BackgroundProcess
* Any extension that must be called regularly to be executed in the background
*
* @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
*/
interface iBackgroundProcess
{
public function GetPeriodicity();
public function Process($iUnixTimeLimit);
}
?>

View File

@@ -52,19 +52,13 @@ abstract class CellChangeSpec
$this->m_sOql = $sOql;
}
static protected function ValueAsHtml($value)
public function GetPureValue()
{
if (MetaModel::IsValidObject($value))
{
return $value->GetHyperLink();
}
else
{
return htmlentities($value, ENT_QUOTES, 'UTF-8');
}
// Todo - distinguish both values
return $this->m_proposedValue;
}
public function GetValue()
public function GetDisplayableValue()
{
return $this->m_proposedValue;
}
@@ -101,10 +95,10 @@ class CellStatus_Modify extends CellChangeSpec
return 'Modified';
}
public function GetPreviousValue()
{
return $this->m_previousValue;
}
//public function GetPreviousValue()
//{
// return $this->m_previousValue;
//}
}
class CellStatus_Issue extends CellStatus_Modify
@@ -127,6 +121,33 @@ class CellStatus_Issue extends CellStatus_Modify
}
}
class CellStatus_SearchIssue extends CellStatus_Issue
{
public function __construct()
{
parent::__construct(null, null, null);
}
public function GetDescription()
{
return 'No match';
}
}
class CellStatus_NullIssue extends CellStatus_Issue
{
public function __construct()
{
parent::__construct(null, null, null);
}
public function GetDescription()
{
return 'Missing mandatory value';
}
}
class CellStatus_Ambiguous extends CellStatus_Issue
{
protected $m_iCount;
@@ -192,6 +213,14 @@ class RowStatus_Modify extends RowStatus
}
}
class RowStatus_Disappeared extends RowStatus_Modify
{
public function GetDescription()
{
return "disappeared, changed ".$this->m_iChanged." cols";
}
}
class RowStatus_Issue extends RowStatus
{
protected $m_sReason;
@@ -220,17 +249,39 @@ class BulkChange
// #@# todo: rename the variables to sColIndex
protected $m_aAttList; // attcode => iCol
protected $m_aExtKeys; // aExtKeys[sExtKeyAttCode][sExtReconcKeyAttCode] = iCol;
protected $m_aReconcilKeys;// attcode (attcode = 'id' for the pkey)
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)
public function __construct($sClass, $aData, $aAttList, $aExtKeys, $aReconcilKeys, $sSynchroScope = null, $aOnDisappear = null, $sDateFormat = null)
{
$this->m_sClass = $sClass;
$this->m_aData = $aData;
$this->m_aAttList = $aAttList;
$this->m_aReconcilKeys = $aReconcilKeys;
$this->m_aExtKeys = $aExtKeys;
$this->m_sSynchroScope = $sSynchroScope;
$this->m_aOnDisappear = $aOnDisappear;
$this->m_sDateFormat = $sDateFormat;
}
protected $m_bReportHtml = false;
protected $m_sReportCsvSep = ',';
protected $m_sReportCsvDelimiter = '"';
public function SetReportHtml()
{
$this->m_bReportHtml = true;
}
public function SetReportCsv($sSeparator = ',', $sDelimiter = '"')
{
$this->m_bReportHtml = false;
$this->m_sReportCsvSep = $sSeparator;
$this->m_sReportCsvDelimiter = $sDelimiter;
}
protected function ResolveExternalKey($aRowData, $sAttCode, &$aResults)
{
$oExtKey = MetaModel::GetAttributeDef($this->m_sClass, $sAttCode);
@@ -247,6 +298,21 @@ class BulkChange
return array($oReconFilter->ToOql(), $aKeys);
}
// Returns true if the CSV data specifies that the external key must be left undefined
protected function IsNullExternalKeySpec($aRowData, $sAttCode)
{
$oExtKey = MetaModel::GetAttributeDef($this->m_sClass, $sAttCode);
foreach ($this->m_aExtKeys[$sAttCode] as $sForeignAttCode => $iCol)
{
// The foreign attribute is one of our reconciliation key
if (strlen($aRowData[$iCol]) > 0)
{
return false;
}
}
return true;
}
protected function PrepareObject(&$oTargetObj, $aRowData, &$aErrors)
{
$aResults = array();
@@ -260,36 +326,49 @@ class BulkChange
// if (!array_key_exists($sAttCode, $this->m_aAttList)) continue;
$oExtKey = MetaModel::GetAttributeDef(get_class($oTargetObj), $sAttCode);
$oReconFilter = new CMDBSearchFilter($oExtKey->GetTargetClass());
foreach ($aKeyConfig as $sForeignAttCode => $iCol)
if ($this->IsNullExternalKeySpec($aRowData, $sAttCode))
{
// The foreign attribute is one of our reconciliation key
$oReconFilter->AddCondition($sForeignAttCode, $aRowData[$iCol], '=');
$aResults[$iCol] = new CellStatus_Void($aRowData[$iCol]);
}
$oExtObjects = new CMDBObjectSet($oReconFilter);
switch($oExtObjects->Count())
{
case 0:
foreach ($aKeyConfig as $sForeignAttCode => $iCol)
{
$aResults[$iCol] = new CellStatus_Void($aRowData[$iCol]);
}
if ($oExtKey->IsNullAllowed())
{
$oTargetObj->Set($sAttCode, $oExtKey->GetNullValue());
$aResults[$sAttCode]= new CellStatus_Issue(null, $oTargetObj->Get($sAttCode), 'Object not found');
$aResults[$sAttCode]= new CellStatus_Void($oExtKey->GetNullValue());
}
else
{
$aErrors[$sAttCode] = "Object not found";
$aResults[$sAttCode]= new CellStatus_Issue(null, $oTargetObj->Get($sAttCode), 'Object not found');
$aErrors[$sAttCode] = "Null not allowed";
$aResults[$sAttCode]= new CellStatus_Issue(null, $oTargetObj->Get($sAttCode), 'Null not allowed');
}
}
else
{
$oReconFilter = new CMDBSearchFilter($oExtKey->GetTargetClass());
foreach ($aKeyConfig as $sForeignAttCode => $iCol)
{
// The foreign attribute is one of our reconciliation key
$oReconFilter->AddCondition($sForeignAttCode, $aRowData[$iCol], '=');
$aResults[$iCol] = new CellStatus_Void($aRowData[$iCol]);
}
$oExtObjects = new CMDBObjectSet($oReconFilter);
switch($oExtObjects->Count())
{
case 0:
$aErrors[$sAttCode] = "Object not found";
$aResults[$sAttCode]= new CellStatus_SearchIssue();
break;
case 1:
// Do change the external key attribute
$oForeignObj = $oExtObjects->Fetch();
$oTargetObj->Set($sAttCode, $oForeignObj->GetKey());
break;
default:
$aErrors[$sAttCode] = "Found ".$oExtObjects->Count()." matches";
$aResults[$sAttCode]= new CellStatus_Ambiguous($oTargetObj->Get($sAttCode), $oExtObjects->Count(), $oReconFilter->ToOql());
}
break;
case 1:
// Do change the external key attribute
$oForeignObj = $oExtObjects->Fetch();
$oTargetObj->Set($sAttCode, $oForeignObj->GetKey());
break;
default:
$aErrors[$sAttCode] = "Found ".$oExtObjects->Count()." matches";
$aResults[$sAttCode]= new CellStatus_Ambiguous($oTargetObj->Get($sAttCode), $oExtObjects->Count(), $oReconFilter->ToOql());
}
// Report
@@ -321,15 +400,37 @@ class BulkChange
// skip the private key, if any
if ($sAttCode == 'id') continue;
$res = $oTargetObj->CheckValue($sAttCode, $aRowData[$iCol]);
if ($res === true)
$oAttDef = MetaModel::GetAttributeDef($this->m_sClass, $sAttCode);
$aReasons = array();
$iFlags = $oTargetObj->GetAttributeFlags($sAttCode, $aReasons);
if ( (($iFlags & OPT_ATT_READONLY) == OPT_ATT_READONLY) && ( $oTargetObj->Get($sAttCode) != $aRowData[$iCol]) )
{
$oTargetObj->Set($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
{
$oSet = $oAttDef->MakeValueFromString($aRowData[$iCol]);
$oTargetObj->Set($sAttCode, $oSet);
}
catch(CoreException $e)
{
$aErrors[$sAttCode] = "Failed to process input: ".$e->getMessage();
}
}
else
{
// $res is a string with the error description
$aErrors[$sAttCode] = "Unexpected value for attribute '$sAttCode': $res";
$res = $oTargetObj->CheckValue($sAttCode, $aRowData[$iCol]);
if ($res === true)
{
$oTargetObj->Set($sAttCode, $aRowData[$iCol]);
}
else
{
// $res is a string with the error description
$aErrors[$sAttCode] = "Unexpected value for attribute '$sAttCode': $res";
}
}
}
@@ -342,25 +443,38 @@ class BulkChange
{
$aResults[$iCol]= new CellStatus_Void($aRowData[$iCol]);
}
if (isset($aErrors[$sAttCode]))
else
{
$aResults[$iCol]= new CellStatus_Issue($oTargetObj->Get($sAttCode), $oTargetObj->GetOriginal($sAttCode), $aErrors[$sAttCode]);
}
elseif (array_key_exists($sAttCode, $aChangedFields))
{
if ($oTargetObj->IsNew())
if ($this->m_bReportHtml)
{
$aResults[$iCol]= new CellStatus_Void($oTargetObj->Get($sAttCode));
$sCurValue = $oTargetObj->GetAsHTML($sAttCode);
$sOrigValue = $oTargetObj->GetOriginalAsHTML($sAttCode);
}
else
{
$aResults[$iCol]= new CellStatus_Modify($oTargetObj->Get($sAttCode), $oTargetObj->GetOriginal($sAttCode));
$sCurValue = $oTargetObj->GetAsCSV($sAttCode, $this->m_sReportCsvSep, $this->m_sReportCsvDelimiter);
$sOrigValue = $oTargetObj->GetOriginalAsCSV($sAttCode, $this->m_sReportCsvSep, $this->m_sReportCsvDelimiter);
}
if (isset($aErrors[$sAttCode]))
{
$aResults[$iCol]= new CellStatus_Issue($sCurValue, $sOrigValue, $aErrors[$sAttCode]);
}
elseif (array_key_exists($sAttCode, $aChangedFields))
{
if ($oTargetObj->IsNew())
{
$aResults[$iCol]= new CellStatus_Void($sCurValue);
}
else
{
$aResults[$iCol]= new CellStatus_Modify($sCurValue, $sOrigValue);
}
}
else
{
// By default... nothing happens
$aResults[$iCol]= new CellStatus_Void($aRowData[$iCol]);
}
}
else
{
// By default... nothing happens
$aResults[$iCol]= new CellStatus_Void($aRowData[$iCol]);
}
}
@@ -375,6 +489,70 @@ class BulkChange
return $aResults;
}
protected function PrepareMissingObject(&$oTargetObj, &$aErrors)
{
$aResults = array();
$aErrors = array();
// External keys
//
foreach($this->m_aExtKeys as $sAttCode => $aKeyConfig)
{
//$oExtKey = MetaModel::GetAttributeDef(get_class($oTargetObj), $sAttCode);
$aResults[$sAttCode]= new CellStatus_Void($oTargetObj->Get($sAttCode));
foreach ($aKeyConfig as $sForeignAttCode => $iCol)
{
$aResults[$iCol] = new CellStatus_Void('?');
}
}
// Update attributes
//
foreach($this->m_aOnDisappear as $sAttCode => $value)
{
if (!MetaModel::IsValidAttCode(get_class($oTargetObj), $sAttCode))
{
throw new BulkChangeException('Invalid attribute code', array('class' => get_class($oTargetObj), 'attcode' => $sAttCode));
}
$oTargetObj->Set($sAttCode, $value);
if (!array_key_exists($sAttCode, $this->m_aAttList))
{
// #@# will be out of the reporting... (counted anyway)
}
}
// Reporting on fields
//
$aChangedFields = $oTargetObj->ListChanges();
foreach ($this->m_aAttList as $sAttCode => $iCol)
{
if ($sAttCode == 'id')
{
$aResults[$iCol]= new CellStatus_Void($oTargetObj->GetKey());
}
if (array_key_exists($sAttCode, $aChangedFields))
{
$aResults[$iCol]= new CellStatus_Modify($oTargetObj->Get($sAttCode), $oTargetObj->GetOriginal($sAttCode));
}
else
{
// By default... nothing happens
$aResults[$iCol]= new CellStatus_Void($oTargetObj->Get($sAttCode));
}
}
// Checks
//
$res = $oTargetObj->CheckConsistency();
if ($res !== true)
{
// $res contains the error description
$aErrors["GLOBAL"] = "Attributes not consistent with each others: $res";
}
return $aResults;
}
protected function CreateObject(&$aResult, $iRow, $aRowData, CMDBChange $oChange = null)
{
@@ -385,7 +563,7 @@ class BulkChange
{
$sErrors = implode(', ', $aErrors);
$aResult[$iRow]["__STATUS__"] = new RowStatus_Issue("Unexpected attribute value(s)");
return;
return $oTargetObj;
}
// Check that any external key will have a value proposed
@@ -404,7 +582,7 @@ class BulkChange
{
$sMissingKeys = implode(', ', $aMissingKeys);
$aResult[$iRow]["__STATUS__"] = new RowStatus_Issue("Could not be created, due to missing external key(s): $sMissingKeys");
return;
return $oTargetObj;
}
// Optionaly record the results
@@ -422,6 +600,7 @@ class BulkChange
$aResult[$iRow]["finalclass"] = get_class($oTargetObj);
$aResult[$iRow]["id"] = new CellStatus_Void(0);
}
return $oTargetObj;
}
protected function UpdateObject(&$aResult, $iRow, $oTargetObj, $aRowData, CMDBChange $oChange = null)
@@ -449,7 +628,14 @@ class BulkChange
//
if ($oChange)
{
$oTargetObj->DBUpdateTracked($oChange);
try
{
$oTargetObj->DBUpdateTracked($oChange);
}
catch(CoreException $e)
{
$aResult[$iRow]["__STATUS__"] = new RowStatus_Issue($e->getMessage());
}
}
}
else
@@ -457,16 +643,116 @@ class BulkChange
$aResult[$iRow]["__STATUS__"] = new RowStatus_NoChange();
}
}
protected function UpdateMissingObject(&$aResult, $iRow, $oTargetObj, CMDBChange $oChange = null)
{
$aResult[$iRow] = $this->PrepareMissingObject($oTargetObj, $aErrors);
// Reporting
//
$aResult[$iRow]["finalclass"] = get_class($oTargetObj);
$aResult[$iRow]["id"] = new CellStatus_Void($oTargetObj->GetKey());
if (count($aErrors) > 0)
{
$sErrors = implode(', ', $aErrors);
$aResult[$iRow]["__STATUS__"] = new RowStatus_Issue("Unexpected attribute value(s)");
return;
}
$aChangedFields = $oTargetObj->ListChanges();
if (count($aChangedFields) > 0)
{
$aResult[$iRow]["__STATUS__"] = new RowStatus_Disappeared(count($aChangedFields));
// Optionaly record the results
//
if ($oChange)
{
try
{
$oTargetObj->DBUpdateTracked($oChange);
}
catch(CoreException $e)
{
$aResult[$iRow]["__STATUS__"] = new RowStatus_Issue($e->getMessage());
}
}
}
else
{
$aResult[$iRow]["__STATUS__"] = new RowStatus_Disappeared(0);
}
}
public function Process(CMDBChange $oChange = null)
{
// Note: $oChange can be null, in which case the aim is to check what would be done
// Debug...
//
if (false)
{
echo "<pre>\n";
echo "Attributes:\n";
print_r($this->m_aAttList);
echo "ExtKeys:\n";
print_r($this->m_aExtKeys);
echo "Reconciliation:\n";
print_r($this->m_aReconcilKeys);
echo "Synchro scope:\n";
print_r($this->m_sSynchroScope);
echo "Synchro changes:\n";
print_r($this->m_aOnDisappear);
//echo "Data:\n";
//print_r($this->m_aData);
echo "</pre>\n";
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
//
$aResult = array();
if (!is_null($this->m_sSynchroScope))
{
$aVisited = 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)
@@ -474,22 +760,38 @@ class BulkChange
$valuecondition = null;
if (array_key_exists($sAttCode, $this->m_aExtKeys))
{
// The value has to be found or verified
list($sQuery, $aMatches) = $this->ResolveExternalKey($aRowData, $sAttCode, $aResult[$iRow]);
if (count($aMatches) == 1)
if ($this->IsNullExternalKeySpec($aRowData, $sAttCode))
{
$oRemoteObj = reset($aMatches); // first item
$valuecondition = $oRemoteObj->GetKey();
$aResult[$iRow][$sAttCode] = new CellStatus_Void($oRemoteObj->GetKey());
}
elseif (count($aMatches) == 0)
{
$aResult[$iRow][$sAttCode] = new CellStatus_Issue(null, null, 'object not found');
}
$oExtKey = MetaModel::GetAttributeDef($this->m_sClass, $sAttCode);
if ($oExtKey->IsNullAllowed())
{
$valuecondition = $oExtKey->GetNullValue();
$aResult[$iRow][$sAttCode] = new CellStatus_Void($oExtKey->GetNullValue());
}
else
{
$aResult[$iRow][$sAttCode] = new CellStatus_NullIssue();
}
}
else
{
$aResult[$iRow][$sAttCode] = new CellStatus_Ambiguous(null, count($aMatches), $sQuery);
// The value has to be found or verified
list($sQuery, $aMatches) = $this->ResolveExternalKey($aRowData, $sAttCode, $aResult[$iRow]);
if (count($aMatches) == 1)
{
$oRemoteObj = reset($aMatches); // first item
$valuecondition = $oRemoteObj->GetKey();
$aResult[$iRow][$sAttCode] = new CellStatus_Void($oRemoteObj->GetKey());
}
elseif (count($aMatches) == 0)
{
$aResult[$iRow][$sAttCode] = new CellStatus_SearchIssue();
}
else
{
$aResult[$iRow][$sAttCode] = new CellStatus_Ambiguous(null, count($aMatches), $sQuery);
}
}
}
else
@@ -517,13 +819,18 @@ class BulkChange
switch($oReconciliationSet->Count())
{
case 0:
$this->CreateObject($aResult, $iRow, $aRowData, $oChange);
$oTargetObj = $this->CreateObject($aResult, $iRow, $aRowData, $oChange);
// $aResult[$iRow]["__STATUS__"]=> set in CreateObject
$aVisited[] = $oTargetObj->GetKey();
break;
case 1:
$oTargetObj = $oReconciliationSet->Fetch();
$this->UpdateObject($aResult, $iRow, $oTargetObj, $aRowData, $oChange);
// $aResult[$iRow]["__STATUS__"]=> set in UpdateObject
if (!is_null($this->m_sSynchroScope))
{
$aVisited[] = $oTargetObj->GetKey();
}
break;
default:
// Found several matches, ambiguous
@@ -532,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]))
@@ -546,7 +873,10 @@ class BulkChange
if (!array_key_exists($sAttCode, $aResult[$iRow]))
{
$aResult[$iRow][$sAttCode] = new CellStatus_Void('n/a');
foreach ($aForeignAtts as $sForeignAttCode => $iCol)
}
foreach ($aForeignAtts as $sForeignAttCode => $iCol)
{
if (!array_key_exists($iCol, $aResult[$iRow]))
{
// The foreign attribute is one of our reconciliation key
$aResult[$iRow][$iCol] = new CellStatus_Void($aRowData[$iCol]);
@@ -554,8 +884,331 @@ class BulkChange
}
}
}
return $aResult;
}
/**
* Display the history of bulk imports
*/
static function DisplayImportHistory(WebPage $oPage, $bFromAjax = false, $bShowAll = false)
{
$sAjaxDivId = "CSVImportHistory";
if (!$bFromAjax)
{
$oPage->add('<div id="'.$sAjaxDivId.'">');
}
$oPage->p(Dict::S('UI:History:BulkImports+'));
$oBulkChangeSearch = DBObjectSearch::FromOQL("SELECT CMDBChange WHERE userinfo LIKE '%(CSV)'");
$iQueryLimit = $bShowAll ? 0 : MetaModel::GetConfig()->GetMaxDisplayLimit() + 1;
$oBulkChanges = new DBObjectSet($oBulkChangeSearch, array('date' => false), array(), null, $iQueryLimit);
$oAppContext = new ApplicationContext();
$bLimitExceeded = false;
if ($oBulkChanges->Count() > MetaModel::GetConfig()->GetMaxDisplayLimit())
{
$bLimitExceeded = true;
if (!$bShowAll)
{
$iMaxObjects = MetaModel::GetConfig()->GetMinDisplayLimit();
$oBulkChanges->SetLimit($iMaxObjects);
}
}
$oBulkChanges->Seek(0);
$aDetails = array();
while ($oChange = $oBulkChanges->Fetch())
{
$sDate = '<a href="?step=10&changeid='.$oChange->GetKey().'&'.$oAppContext->GetForLink().'">'.$oChange->Get('date').'</a>';
$sUser = $oChange->GetUserName();
if (preg_match('/^(.*)\\(CSV\\)$/i', $oChange->Get('userinfo'), $aMatches))
{
$sUser = $aMatches[1];
}
else
{
$sUser = $oChange->Get('userinfo');
}
$oOpSearch = DBObjectSearch::FromOQL("SELECT CMDBChangeOpCreate WHERE change = :change_id");
$oOpSet = new DBObjectSet($oOpSearch, array(), array('change_id' => $oChange->GetKey()));
$iCreated = $oOpSet->Count();
// Get the class from the first item found (assumption: a CSV load is done for a single class)
if ($oCreateOp = $oOpSet->Fetch())
{
$sClass = $oCreateOp->Get('objclass');
}
$oOpSearch = DBObjectSearch::FromOQL("SELECT CMDBChangeOpSetAttribute WHERE change = :change_id");
$oOpSet = new DBObjectSet($oOpSearch, array(), array('change_id' => $oChange->GetKey()));
$aModified = array();
$aAttList = array();
while ($oModified = $oOpSet->Fetch())
{
// Get the class (if not done earlier on object creation)
$sClass = $oModified->Get('objclass');
$iKey = $oModified->Get('objkey');
$sAttCode = $oModified->Get('attcode');
$aAttList[$sClass][$sAttCode] = true;
$aModified["$sClass::$iKey"] = true;
}
$iModified = count($aModified);
// Assumption: there is only one class of objects being loaded
// Then the last class found gives us the class for every object
if ( ($iModified > 0) || ($iCreated > 0))
{
$aDetails[] = array('date' => $sDate, 'user' => $sUser, 'class' => $sClass, 'created' => $iCreated, 'modified' => $iModified);
}
}
$aConfig = array( 'date' => array('label' => Dict::S('UI:History:Date'), 'description' => Dict::S('UI:History:Date+')),
'user' => array('label' => Dict::S('UI:History:User'), 'description' => Dict::S('UI:History:User+')),
'class' => array('label' => Dict::S('Core:AttributeClass'), 'description' => Dict::S('Core:AttributeClass+')),
'created' => array('label' => Dict::S('UI:History:StatsCreations'), 'description' => Dict::S('UI:History:StatsCreations+')),
'modified' => array('label' => Dict::S('UI:History:StatsModifs'), 'description' => Dict::S('UI:History:StatsModifs+')),
);
if ($bLimitExceeded)
{
if ($bShowAll)
{
// Collapsible list
$oPage->add('<p>'.Dict::Format('UI:CountOfResults', $oBulkChanges->Count()).'&nbsp;&nbsp;<a class="truncated" onclick="OnTruncatedHistoryToggle(false);">'.Dict::S('UI:CollapseList').'</a></p>');
}
else
{
// Truncated list
$iMinDisplayLimit = MetaModel::GetConfig()->GetMinDisplayLimit();
$sCollapsedLabel = Dict::Format('UI:TruncatedResults', $iMinDisplayLimit, $oBulkChanges->Count());
$sLinkLabel = Dict::S('UI:DisplayAll');
$oPage->add('<p>'.$sCollapsedLabel.'&nbsp;&nbsp;<a class="truncated" onclick="OnTruncatedHistoryToggle(true);">'.$sLinkLabel.'</p>');
$oPage->add_ready_script(
<<<EOF
$('#$sAjaxDivId table.listResults').addClass('truncated');
$('#$sAjaxDivId table.listResults tr:last td').addClass('truncated');
EOF
);
$sAppContext = $oAppContext->GetForLink();
$oPage->add_script(
<<<EOF
function OnTruncatedHistoryToggle(bShowAll)
{
$.get(GetAbsoluteUrlAppRoot()+'pages/ajax.render.php?{$sAppContext}', {operation: 'displayCSVHistory', showall: bShowAll}, function(data)
{
$('#$sAjaxDivId').html(data);
var table = $('#$sAjaxDivId .listResults');
table.tableHover(); // hover tables
table.tablesorter( { widgets: ['myZebra', 'truncatedList']} ); // sortable and zebra tables
}
);
}
EOF
);
}
}
else
{
// Normal display - full list without any decoration
}
$oPage->table($aConfig, $aDetails);
if (!$bFromAjax)
{
$oPage->add('</div>');
}
}
/**
* Display the details of an import
*/
static function DisplayImportHistoryDetails(iTopWebPage $oPage, $iChange)
{
if ($iChange == 0)
{
throw new Exception("Missing parameter changeid");
}
$oChange = MetaModel::GetObject('CMDBChange', $iChange, false);
if (is_null($oChange))
{
throw new Exception("Unknown change: $iChange");
}
$oPage->add("<div><p><h1>".Dict::Format('UI:History:BulkImportDetails', $oChange->Get('date'), $oChange->GetUserName())."</h1></p></div>\n");
// Assumption : change made one single class of objects
$aObjects = array();
$aAttributes = array(); // array of attcode => occurences
$oOpSearch = DBObjectSearch::FromOQL("SELECT CMDBChangeOp WHERE change = :change_id");
$oOpSet = new DBObjectSet($oOpSearch, array(), array('change_id' => $iChange));
while ($oOperation = $oOpSet->Fetch())
{
$sClass = $oOperation->Get('objclass');
$iKey = $oOperation->Get('objkey');
$iObjId = "$sClass::$iKey";
if (!isset($aObjects[$iObjId]))
{
$aObjects[$iObjId] = array();
$aObjects[$iObjId]['__class__'] = $sClass;
$aObjects[$iObjId]['__id__'] = $iKey;
}
if (get_class($oOperation) == 'CMDBChangeOpCreate')
{
$aObjects[$iObjId]['__created__'] = true;
}
elseif ($oOperation instanceof CMDBChangeOpSetAttribute)
{
$sAttCode = $oOperation->Get('attcode');
if (get_class($oOperation) == 'CMDBChangeOpSetAttributeScalar')
{
$oAttDef = MetaModel::GetAttributeDef($sClass, $sAttCode);
if ($oAttDef->IsExternalKey())
{
$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
{
$sOldValue = $oOperation->GetAsHTML('oldvalue');
$sNewValue = $oOperation->GetAsHTML('newvalue');
}
$aObjects[$iObjId][$sAttCode] = $sOldValue.' -&gt; '.$sNewValue;
}
else
{
$aObjects[$iObjId][$sAttCode] = 'n/a';
}
if (isset($aAttributes[$sAttCode]))
{
$aAttributes[$sAttCode]++;
}
else
{
$aAttributes[$sAttCode] = 1;
}
}
}
$aDetails = array();
foreach($aObjects as $iUId => $aObjData)
{
$aRow = array();
$oObject = MetaModel::GetObject($aObjData['__class__'], $aObjData['__id__'], false);
if (is_null($oObject))
{
$aRow['object'] = $aObjData['__class__'].'::'.$aObjData['__id__'].' (deleted)';
}
else
{
$aRow['object'] = $oObject->GetHyperlink();
}
if (isset($aObjData['__created__']))
{
$aRow['operation'] = Dict::S('Change:ObjectCreated');
}
else
{
$aRow['operation'] = Dict::S('Change:ObjectModified');
}
foreach ($aAttributes as $sAttCode => $iOccurences)
{
if (isset($aObjData[$sAttCode]))
{
$aRow[$sAttCode] = $aObjData[$sAttCode];
}
elseif (!is_null($oObject))
{
// This is the current vaslue: $oObject->GetAsHtml($sAttCode)
// whereas we are displaying the value that was set at the time
// the object was created
// This requires addtional coding...let's do that later
$aRow[$sAttCode] = '';
}
else
{
$aRow[$sAttCode] = '';
}
}
$aDetails[] = $aRow;
}
$aConfig = array();
$aConfig['object'] = array('label' => MetaModel::GetName($sClass), 'description' => MetaModel::GetClassDescription($sClass));
$aConfig['operation'] = array('label' => Dict::S('UI:History:Changes'), 'description' => Dict::S('UI:History:Changes+'));
foreach ($aAttributes as $sAttCode => $iOccurences)
{
$aConfig[$sAttCode] = array('label' => MetaModel::GetLabel($sClass, $sAttCode), 'description' => MetaModel::GetDescription($sClass, $sAttCode));
}
$oPage->table($aConfig, $aDetails);
}
/**
* Get the user friendly name for an 'extended' attribute code i.e 'name', becomes 'Name' and 'org_id->name' becomes 'Organization->Name'
* @param string $sClassName The name of the class
* @param string $sAttCodeEx Either an attribute code or ext_key_name->att_code
* @return string A user friendly format of the string: AttributeName or AttributeName->ExtAttributeName
*/
public static function GetFriendlyAttCodeName($sClassName, $sAttCodeEx)
{
$sFriendlyName = '';
if (preg_match('/(.+)->(.+)/', $sAttCodeEx, $aMatches) > 0)
{
$sAttribute = $aMatches[1];
$sField = $aMatches[2];
$oAttDef = MetaModel::GetAttributeDef($sClassName, $sAttribute);
if ($oAttDef->IsExternalKey())
{
$sTargetClass = $oAttDef->GetTargetClass();
$oTargetAttDef = MetaModel::GetAttributeDef($sTargetClass, $sField);
$sFriendlyName = $oAttDef->GetLabel().'->'.$oTargetAttDef->GetLabel();
}
else
{
// hum, hum... should never happen, we'd better raise an exception
throw(new Exception(Dict::Format('UI:CSVImport:ErrorExtendedAttCode', $sAttCodeEx, $sAttribute, $sClassName)));
}
}
else
{
if ($sAttCodeEx == 'id')
{
$sFriendlyName = Dict::S('UI:CSVImport:idField');
}
else
{
$oAttDef = MetaModel::GetAttributeDef($sClassName, $sAttCodeEx);
$sFriendlyName = $oAttDef->GetLabel();
}
}
return $sFriendlyName;
}
}

View File

@@ -49,6 +49,34 @@ class CMDBChange extends DBObject
MetaModel::Init_AddAttribute(new AttributeDateTime("date", array("allowed_values"=>null, "sql"=>"date", "default_value"=>"", "is_null_allowed"=>false, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeString("userinfo", array("allowed_values"=>null, "sql"=>"userinfo", "default_value"=>null, "is_null_allowed"=>true, "depends_on"=>array())));
}
// Helper to keep track of the author of a given change,
// taking into account a variety of cases (contact attached or not, impersonation)
static public function GetCurrentUserName()
{
if (UserRights::IsImpersonated())
{
$sUserString = Dict::Format('UI:Archive_User_OnBehalfOf_User', UserRights::GetRealUserFriendlyName(), UserRights::GetUserFriendlyName());
}
else
{
$sUserString = UserRights::GetUserFriendlyName();
}
return $sUserString;
}
public function GetUserName()
{
if (preg_match('/^(.*)\\(CSV\\)$/i', $this->Get('userinfo'), $aMatches))
{
$sUser = $aMatches[1];
}
else
{
$sUser = $this->Get('userinfo');
}
return $sUser;
}
}
?>

View File

@@ -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
@@ -232,7 +248,14 @@ class CMDBChangeOpSetAttributeScalar extends CMDBChangeOpSetAttribute
}
else
{
$sResult = Dict::Format('Change:AttName_SetTo_NewValue_PreviousValue_OldValue', $sAttName, $sNewValue, $sOldValue);
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($bIsHtml && $oAttDef->IsExternalKey())
@@ -241,6 +264,14 @@ class CMDBChangeOpSetAttributeScalar extends CMDBChangeOpSetAttribute
$sFrom = MetaModel::GetHyperLink($sTargetClass, $sOldValue);
$sTo = MetaModel::GetHyperLink($sTargetClass, $sNewValue);
$sResult = "$sAttName set to $sTo (previous: $sFrom)";
if (strlen($sFrom) == 0)
{
$sResult = Dict::Format('Change:AttName_SetTo', $sAttName, $sTo);
}
else
{
$sResult = Dict::Format('Change:AttName_SetTo_NewValue_PreviousValue_OldValue', $sAttName, $sTo, $sFrom);
}
}
elseif ($oAttDef instanceOf AttributeBlob)
{
@@ -248,7 +279,14 @@ class CMDBChangeOpSetAttributeScalar extends CMDBChangeOpSetAttribute
}
else
{
$sResult = Dict::Format('Change:AttName_SetTo_NewValue_PreviousValue_OldValue', $sAttName, $sNewValue, $sOldValue);
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);
}
}
}
return $sResult;
@@ -475,4 +513,98 @@ class CMDBChangeOpSetAttributeText extends CMDBChangeOpSetAttribute
}
}
/**
* Record the modification of a caselog (text)
* since the caselog itself stores the history
* of its entries, there is no need to duplicate
* the text here
*
* @package iTopORM
*/
class CMDBChangeOpSetAttributeCaseLog extends CMDBChangeOpSetAttribute
{
public static function Init()
{
$aParams = array
(
"category" => "core/cmdb",
"key_type" => "",
"name_attcode" => "change",
"state_attcode" => "",
"reconc_keys" => array(),
"db_table" => "priv_changeop_setatt_log",
"db_key_field" => "id",
"db_finalclass_field" => "",
);
MetaModel::Init_Params($aParams);
MetaModel::Init_InheritAttributes();
MetaModel::Init_AddAttribute(new AttributeInteger("lastentry", array("allowed_values"=>null, "sql"=>"lastentry", "default_value"=>0, "is_null_allowed"=>true, "depends_on"=>array())));
// Display lists
MetaModel::Init_SetZListItems('details', array('date', 'userinfo', 'attcode')); // Attributes to be displayed for the complete details
MetaModel::Init_SetZListItems('list', array('date', 'userinfo', 'attcode')); // Attributes to be displayed for a list
}
/**
* Describe (as a text string) the modifications corresponding to this change
*/
public function GetDescription()
{
// Temporary, until we change the options of GetDescription() -needs a more global revision
$bIsHtml = true;
$sResult = '';
$oTargetObjectClass = $this->Get('objclass');
$oTargetObjectKey = $this->Get('objkey');
$oTargetSearch = new DBObjectSearch($oTargetObjectClass);
$oTargetSearch->AddCondition('id', $oTargetObjectKey, '=');
$oMonoObjectSet = new DBObjectSet($oTargetSearch);
if (UserRights::IsActionAllowedOnAttribute($this->Get('objclass'), $this->Get('attcode'), UR_ACTION_READ, $oMonoObjectSet) == UR_ALLOWED_YES)
{
$oAttDef = MetaModel::GetAttributeDef($this->Get('objclass'), $this->Get('attcode'));
$sAttName = $oAttDef->GetLabel();
$sResult = Dict::Format('Change:AttName_EntryAdded', $sAttName);
}
return $sResult;
}
}
/**
* 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');
}
}
?>

View File

@@ -59,6 +59,10 @@ require_once('dbobject.class.php');
require_once('dbobjectsearch.class.php');
require_once('dbobjectset.class.php');
require_once('backgroundprocess.inc.php');
require_once('asynctask.class.inc.php');
require_once('dbproperty.class.inc.php');
// db change tracking data model
require_once('cmdbchange.class.inc.php');
require_once('cmdbchangeop.class.inc.php');
@@ -72,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');
@@ -88,6 +93,23 @@ abstract class CMDBObject extends DBObject
protected static $m_oCurrChange = null;
public static function SetCurrentChange(CMDBChange $oChange)
{
self::$m_oCurrChange = $oChange;
}
//
// Todo: simplify the APIs and do not pass the current change as an argument anymore
// SetCurrentChange to be invoked in very few cases (UI.php, CSV import, Data synchro)
// GetCurrentChange to be called ONCE (!) by CMDBChangeOp::OnInsert ($this->Set('change', ..GetCurrentChange())
// GetCurrentChange to create a default change if not already done in the current context
//
public static function GetCurrentChange()
{
return self::$m_oCurrChange;
}
private function RecordObjCreation(CMDBChange $oChange)
{
$oMyChangeOp = MetaModel::NewObject("CMDBChangeOpCreate");
@@ -150,7 +172,7 @@ abstract class CMDBObject extends DBObject
{
$original = '';
}
$oMyChangeOp->Set("prevdata", $original);
$oMyChangeOp->Set("prevstring", $original);
$iId = $oMyChangeOp->DBInsertNoReload();
}
elseif ($oAttDef instanceOf AttributeBlob)
@@ -173,6 +195,17 @@ abstract class CMDBObject extends DBObject
$oMyChangeOp->Set("prevdata", $original);
$iId = $oMyChangeOp->DBInsertNoReload();
}
elseif ($oAttDef instanceOf AttributeCaseLog)
{
$oMyChangeOp = MetaModel::NewObject("CMDBChangeOpSetAttributeCaseLog");
$oMyChangeOp->Set("change", $oChange->GetKey());
$oMyChangeOp->Set("objclass", get_class($this));
$oMyChangeOp->Set("objkey", $this->GetKey());
$oMyChangeOp->Set("attcode", $sAttCode);
$oMyChangeOp->Set("lastentry", $value->GetLatestEntryIndex());
$iId = $oMyChangeOp->DBInsertNoReload();
}
elseif ($oAttDef instanceOf AttributeText)
{
// Data blobs
@@ -185,6 +218,10 @@ abstract class CMDBObject extends DBObject
if (array_key_exists($sAttCode, $aOrigValues))
{
$original = $aOrigValues[$sAttCode];
if ($original instanceof ormCaseLog)
{
$original = $original->GetText();
}
}
else
{
@@ -232,7 +269,7 @@ abstract class CMDBObject extends DBObject
// and we decided that it was too risky to activate it
// Anyhow, users willing to have a very strong security could set
// skip_strong_security = 0, in the config file
$bSkipStrongSecurity = utils::GetConfig()->Get('skip_strong_security');
$bSkipStrongSecurity = MetaModel::GetConfig()->Get('skip_strong_security');
}
if (!$bSkipStrongSecurity)
{
@@ -260,9 +297,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;
}
@@ -270,9 +308,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;
}
@@ -301,9 +340,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)
@@ -328,9 +368,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()
@@ -350,28 +391,29 @@ abstract class CMDBObject extends DBObject
return $ret;
}
public function DBDelete()
public function DBDelete(&$oDeletionPlan = null)
{
if(!self::$m_oCurrChange)
{
throw new CoreException("DBDelete() could not be used here, please use DBDeleteTracked() instead");
}
return $this->DBDeleteTracked_Internal();
return $this->DBDeleteTracked_Internal($oDeletionPlan);
}
public function DBDeleteTracked(CMDBChange $oChange, $bSkipStrongSecurity = null)
public function DBDeleteTracked(CMDBChange $oChange, $bSkipStrongSecurity = null, &$oDeletionPlan = null)
{
$this->CheckUserRights($bSkipStrongSecurity, UR_ACTION_DELETE);
$oPreviousChange = self::$m_oCurrChange;
self::$m_oCurrChange = $oChange;
$this->DBDeleteTracked_Internal();
self::$m_oCurrChange = null;
$this->DBDeleteTracked_Internal($oDeletionPlan);
self::$m_oCurrChange = $oPreviousChange;
}
protected function DBDeleteTracked_Internal()
protected function DBDeleteTracked_Internal(&$oDeletionPlan = null)
{
$prevkey = $this->GetKey();
$ret = parent::DBDelete();
$ret = parent::DBDelete($oDeletionPlan);
$this->RecordObjDeletion(self::$m_oCurrChange, $prevkey);
return $ret;
}
@@ -387,9 +429,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)
@@ -426,9 +469,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)
@@ -479,24 +523,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,

View File

@@ -56,7 +56,7 @@ class CMDBSource
self::$m_sDBUser = $sUser;
self::$m_sDBPwd = $sPwd;
self::$m_sDBName = $sSource;
if (!self::$m_resDBLink = @mysql_pconnect($sServer, $sUser, $sPwd))
if (!self::$m_resDBLink = mysql_connect($sServer, $sUser, $sPwd))
{
throw new MySQLException('Could not connect to the DB server', array('host'=>$sServer, 'user'=>$sUser));
}
@@ -84,6 +84,17 @@ class CMDBSource
}
}
public static function SetTimezone($sTimezone = null)
{
// Note: requires the installation of MySQL special tables,
// otherwise, only 'SYSTEM' or "+10:00' may be specified which is NOT sufficient because of day light saving times
if (!is_null($sTimezone))
{
$sQuotedTimezone = self::Quote($sTimezone);
self::Query("SET time_zone = $sQuotedTimezone");
}
}
public static function ListDB()
{
$aDBs = self::QueryToCol('SHOW DATABASES', 'Database');
@@ -243,6 +254,31 @@ class CMDBSource
return false;
}
public static function DeleteFrom($sSQLQuery)
{
self::Query($sSQLQuery);
}
public static function QueryToScalar($sSql)
{
$result = mysql_query($sSql, self::$m_resDBLink);
if (!$result)
{
throw new MySQLException('Failed to issue SQL query', array('query' => $sSql));
}
if ($aRow = mysql_fetch_array($result, MYSQL_BOTH))
{
$res = $aRow[0];
}
else
{
mysql_free_result($result);
throw new MySQLException('Found no result for query', array('query' => $sSql));
}
mysql_free_result($result);
return $res;
}
public static function QueryToArray($sSql)
{
$aData = array();
@@ -533,6 +569,51 @@ class CMDBSource
// so far, only one line...
return implode(', ', $aRes);
}
/**
* Determine the slave status of the server
* @return bool true if the server is slave
*/
public static function IsSlaveServer()
{
try
{
$result = self::Query('SHOW SLAVE STATUS');
}
catch(MySQLException $e)
{
throw new CoreException("Current user not allowed to check the status", array('mysql_error' => $e->getMessage()));
}
if (mysql_num_rows($result) == 0)
{
return false;
}
// Returns one single row anytime
$aRow = mysql_fetch_array($result, MYSQL_ASSOC);
mysql_free_result($result);
if (!isset($aRow['Slave_IO_Running']))
{
return false;
}
if (!isset($aRow['Slave_SQL_Running']))
{
return false;
}
// If at least one slave thread is running, then we consider that the slave is enabled
if ($aRow['Slave_IO_Running'] == 'Yes')
{
return true;
}
if ($aRow['Slave_SQL_Running'] == 'Yes')
{
return true;
}
return false;
}
}

View File

@@ -14,10 +14,16 @@
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
define('ITOP_APPLICATION', 'iTop');
define('ITOP_VERSION', '$ITOP_VERSION$');
define('ITOP_REVISION', '$WCREV$');
define('ITOP_BUILD_DATE', '$WCNOW$');
define('ACCESS_USER_WRITE', 1);
define('ACCESS_ADMIN_WRITE', 2);
define('ACCESS_FULL', ACCESS_USER_WRITE | ACCESS_ADMIN_WRITE);
define('ACCESS_READONLY', 0);
/**
* Configuration read/write
*
@@ -34,7 +40,7 @@ class ConfigException extends CoreException
}
define ('DEFAULT_CHARACTER_SET', 'utf8');
define ('DEFAULT_COLLATION', 'utf8_general_ci');
define ('DEFAULT_COLLATION', 'utf8_unicode_ci');
define ('DEFAULT_LOG_GLOBAL', true);
define ('DEFAULT_LOG_NOTIFICATION', true);
@@ -52,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...
@@ -70,6 +75,7 @@ class Config
protected $m_aAppModules;
protected $m_aDataModels;
protected $m_aWebServiceCategories;
protected $m_aAddons;
protected $m_aDictionaries;
@@ -78,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)',
@@ -88,7 +102,7 @@ class Config
),
'skip_check_ext_keys' => array(
'type' => 'bool',
'description' => 'Disable external key check when checking the value of attribtutes',
'description' => 'Disable external key check when checking the value of attributes',
'default' => false,
'value' => false,
'source_of_value' => '',
@@ -110,12 +124,372 @@ 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',
'default' => 'iTop',
'value' => '',
'source_of_value' => '',
'show_in_conf_sample' => true,
),
'max_combo_length' => array(
'type' => 'integer',
'description' => 'The maximum number of elements in a drop-down list. If more then an autocomplete will be used',
'default' => 50,
'value' => 50,
'source_of_value' => '',
'show_in_conf_sample' => false,
),
'min_autocomplete_chars' => array(
'type' => 'integer',
'description' => 'The minimum number of characters to type in order to trigger the "autocomplete" behavior',
'default' => 3,
'value' => 3,
'source_of_value' => '',
'show_in_conf_sample' => false,
),
'allow_target_creation' => array(
'type' => 'bool',
'description' => 'Displays the + button on external keys to create target objects',
'default' => true,
'value' => true,
'source_of_value' => '',
'show_in_conf_sample' => false,
),
// Levels that trigger a confirmation in the CSV import/synchro wizard
'csv_import_min_object_confirmation' => array(
'type' => 'integer',
'description' => 'Minimum number of objects to check for the confirmation percentages',
'default' => 3,
'value' => 3,
'source_of_value' => '',
'show_in_conf_sample' => false,
),
'csv_import_errors_percentage' => array(
'type' => 'integer',
'description' => 'Percentage of errors that trigger a confirmation in the CSV import',
'default' => 50,
'value' => 50,
'source_of_value' => '',
'show_in_conf_sample' => false,
),
'csv_import_modifications_percentage' => array(
'type' => 'integer',
'description' => 'Percentage of modifications that trigger a confirmation in the CSV import',
'default' => 50,
'value' => 50,
'source_of_value' => '',
'show_in_conf_sample' => false,
),
'csv_import_creations_percentage' => array(
'type' => 'integer',
'description' => 'Percentage of creations that trigger a confirmation in the CSV import',
'default' => 50,
'value' => 50,
'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)',
'default' => ACCESS_FULL,
'value' => ACCESS_FULL,
'source_of_value' => '',
'show_in_conf_sample' => true,
),
'access_message' => array(
'type' => 'string',
'description' => 'Message displayed to the users when there is any access restriction',
'default' => 'iTop is temporarily frozen, please wait... (the admin team)',
'value' => '',
'source_of_value' => '',
'show_in_conf_sample' => true,
),
'online_help' => array(
'type' => 'string',
'description' => 'Hyperlink to the online-help web page',
'default' => 'http://www.combodo.com/itop-help',
'value' => '',
'source_of_value' => '',
'show_in_conf_sample' => true,
),
'log_usage' => array(
'type' => 'bool',
'description' => 'Log the usage of the application (i.e. the date/time and the user name of each login)',
'default' => false,
'value' => false,
'source_of_value' => '',
'show_in_conf_sample' => false,
),
'synchro_trace' => array(
'type' => 'string',
'description' => 'Synchronization details: none, display, save (includes \'display\')',
'default' => 'none',
'value' => 'none',
'source_of_value' => '',
'show_in_conf_sample' => true,
),
'link_set_item_separator' => array(
'type' => 'string',
'description' => 'Link set from string: line separator',
'default' => '|',
'value' => '|',
'source_of_value' => '',
'show_in_conf_sample' => true,
),
'link_set_attribute_separator' => array(
'type' => 'string',
'description' => 'Link set from string: attribute separator',
'default' => ';',
'value' => ';',
'source_of_value' => '',
'show_in_conf_sample' => true,
),
'link_set_value_separator' => array(
'type' => 'string',
'description' => 'Link set from string: value separator (between the attcode and the value itself',
'default' => ':',
'value' => ':',
'source_of_value' => '',
'show_in_conf_sample' => true,
),
'link_set_attribute_qualifier' => array(
'type' => 'string',
'description' => 'Link set from string: attribute qualifier (encloses both the attcode and the value)',
'default' => "'",
'value' => "'",
'source_of_value' => '',
'show_in_conf_sample' => true,
),
'cron_max_execution_time' => array(
'type' => 'integer',
'description' => 'Duration (seconds) of the page cron.php, must be shorter than php setting max_execution_time and shorter than the web server response timeout',
'default' => 600,
'value' => 600,
'source_of_value' => '',
'show_in_conf_sample' => true,
),
'cron_sleep' => array(
'type' => 'integer',
'description' => 'Duration (seconds) before cron.php checks again if something must be done',
'default' => 2,
'value' => 2,
'source_of_value' => '',
'show_in_conf_sample' => false,
),
'email_asynchronous' => array(
'type' => 'bool',
'description' => 'If set, the emails are sent off line, which requires cron.php to be activated. Exception: some features like the email test utility will force the serialized mode',
'default' => false,
'value' => false,
'source_of_value' => '',
'show_in_conf_sample' => true,
),
'apc_cache.enabled' => array(
'type' => 'bool',
'description' => 'If set, the APC cache is allowed (the PHP extension must also be active)',
'default' => true,
'value' => true,
'source_of_value' => '',
'show_in_conf_sample' => true,
),
'apc_cache.query_ttl' => array(
'type' => 'integer',
'description' => 'Time to live set in APC for the prepared queries (seconds - 0 means no timeout)',
'default' => 3600,
'value' => 3600,
'source_of_value' => '',
'show_in_conf_sample' => true,
),
'timezone' => array(
'type' => 'string',
'description' => 'Timezone (reference: http://php.net/manual/en/timezones.php). If empty, it will be left unchanged and MUST be explicitely configured in PHP',
// examples... not used (nor 'description')
'examples' => array('America/Sao_Paulo', 'America/New_York (standing for EDT)', 'America/Los_Angeles (standing for PDT)', 'Asia/Istanbul', 'Asia/Singapore', 'Africa/Casablanca', 'Australia/Sydney'),
'default' => 'Europe/Paris',
'value' => 'Europe/Paris',
'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')
{
@@ -137,7 +511,6 @@ class Config
default:
throw new CoreException('Unknown type for setting', array('property' => $sPropCode, 'type' => $sType));
}
$this->m_aSettings[$sPropCode]['value'] = $value;
$this->m_aSettings[$sPropCode]['source_of_value'] = $sSourceDesc;
@@ -195,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
*/
@@ -235,36 +601,31 @@ class Config
$this->m_sFile = $sConfigFile;
$this->m_aAppModules = array(
// Some default modules, always present can be move to an official iTop Module later if needed
'../application/transaction.class.inc.php',
'../application/menunode.class.inc.php',
'../application/user.preferences.class.inc.php',
'../application/audit.rule.class.inc.php',
// Romain - That's dirty, because those 3 classes are in fact part of the core
'application/transaction.class.inc.php',
'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
// the core, PLUS I needed the includes to be there also for the setup
// to create the tables.
'../core/event.class.inc.php',
'../core/action.class.inc.php',
'../core/trigger.class.inc.php',
'core/event.class.inc.php',
'core/action.class.inc.php',
'core/trigger.class.inc.php',
'synchro/synchrodatasource.class.inc.php',
);
$this->m_aDataModels = array();
$this->m_aWebServiceCategories = array(
'webservices/webservices.basic.php',
);
$this->m_aAddons = array(
// Default AddOn, always present can be moved to an official iTop Module later if needed
'user rights' => '../addons/userrights/userrightsprofile.class.inc.php',
'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
);
$this->m_aDictionaries = self::ScanDictionariesDir();
foreach($this->m_aSettings as $sPropCode => $aSettingInfo)
{
$this->m_aSettings[$sPropCode]['value'] = $aSettingInfo['default'];
@@ -288,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;
@@ -302,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)
@@ -310,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)
@@ -337,7 +713,7 @@ class Config
if (strlen($sNoise) > 0)
{
// Note: sNoise is an html output, but so far it was ok for me (e.g. showing the entire call stack)
throw new ConfigException('Syntax error in configuration file', array('file' => $sConfigFile, 'error' => '<tt>'.htmlentities($sNoise).'</tt>'));
throw new ConfigException('Syntax error in configuration file', array('file' => $sConfigFile, 'error' => '<tt>'.htmlentities($sNoise, ENT_QUOTES, 'UTF-8').'</tt>'));
}
if (!isset($MySettings) || !is_array($MySettings))
@@ -362,7 +738,8 @@ class Config
}
if (!array_key_exists('user rights', $MyModules['addons']))
{
$MyModules['addons']['user rights'] = '../addons/userrights/userrightsnull.class.inc.php';
// Add one, by default
$MyModules['addons']['user rights'] = '/addons/userrights/userrightsnull.class.inc.php';
}
if (!array_key_exists('dictionaries', $MyModules))
{
@@ -370,6 +747,10 @@ class Config
}
$this->m_aAppModules = $MyModules['application'];
$this->m_aDataModels = $MyModules['business'];
if (isset($MyModules['webservices']))
{
$this->m_aWebServiceCategories = $MyModules['webservices'];
}
$this->m_aAddons = $MyModules['addons'];
$this->m_aDictionaries = $MyModules['dictionaries'];
@@ -405,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();
@@ -418,22 +798,8 @@ class Config
protected function Verify()
{
foreach ($this->m_aAppModules as $sModule => $sToInclude)
{
$this->CheckFile('application module', $sToInclude);
}
foreach ($this->m_aDataModels as $sModule => $sToInclude)
{
$this->CheckFile('business model', $sToInclude);
}
foreach ($this->m_aAddons as $sModule => $sToInclude)
{
$this->CheckFile('addon module', $sToInclude);
}
foreach ($this->m_aDictionaries as $sModule => $sToInclude)
{
$this->CheckFile('dictionary', $sToInclude);
}
// Files are verified later on, just before using them -see MetaModel::Plugin()
// (we have their final path at that point)
}
public function GetModuleSetting($sModule, $sProperty, $defaultvalue = null)
@@ -468,6 +834,15 @@ class Config
$this->m_aDataModels = $aDataModels;
}
public function GetWebServiceCategories()
{
return $this->m_aWebServiceCategories;
}
public function SetWebServiceCategories($aWebServiceCategories)
{
$this->m_aWebServiceCategories = $aWebServiceCategories;
}
public function GetAddons()
{
return $this->m_aAddons;
@@ -586,11 +961,6 @@ class Config
return $this->m_bSecureConnectionRequired;
}
public function GetHttpsHyperlinks()
{
return $this->m_bHttpsHyperlinks;
}
public function GetDefaultLanguage()
{
return $this->m_sDefaultLanguage;
@@ -696,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;
@@ -734,7 +1099,73 @@ class Config
{
return is_writable($this->m_sFile);
}
public function GetLoadedFile()
{
return $this->m_sFile;
}
/**
* Render the configuration as an associative array
* @return boolean True otherwise throws an Exception
*/
public function ToArray()
{
$aSettings = array();
foreach($this->m_aSettings as $sPropCode => $aSettingInfo)
{
$aSettings[$sPropCode] = $aSettingInfo['value'];
}
$aSettings['db_host'] = $this->m_sDBHost;
$aSettings['db_user'] = $this->m_sDBUser;
$aSettings['db_pwd'] = $this->m_sDBPwd;
$aSettings['db_name'] = $this->m_sDBName;
$aSettings['db_subname'] = $this->m_sDBSubname;
$aSettings['db_character_set'] = $this->m_sDBCharacterSet;
$aSettings['db_collation'] = $this->m_sDBCollation;
$aSettings['log_global'] = $this->m_bLogGlobal;
$aSettings['log_notification'] = $this->m_bLogNotification;
$aSettings['log_issue'] = $this->m_bLogIssue;
$aSettings['log_web_service'] = $this->m_bLogWebService;
$aSettings['min_display_limit'] = $this->m_iMinDisplayLimit;
$aSettings['max_display_limit'] = $this->m_iMaxDisplayLimit;
$aSettings['standard_reload_interval'] = $this->m_iStandardReloadInterval;
$aSettings['fast_reload_interval'] = $this->m_iFastReloadInterval;
$aSettings['secure_connection_required'] = $this->m_bSecureConnectionRequired;
$aSettings['default_language'] = $this->m_sDefaultLanguage;
$aSettings['allowed_login_types'] = $this->m_sAllowedLoginTypes;
$aSettings['encryption_key'] = $this->m_sEncryptionKey;
$aSettings['csv_import_charsets'] = $this->m_aCharsets;
foreach ($this->m_aModuleSettings as $sModule => $aProperties)
{
foreach ($aProperties as $sProperty => $value)
{
$aSettings['module_settings'][$sModule][$sProperty] = $value;
}
}
foreach($this->m_aAppModules as $sFile)
{
$aSettings['application_list'][] = $sFile;
}
foreach($this->m_aDataModels as $sFile)
{
$aSettings['datamodel_list'][] = $sFile;
}
foreach($this->m_aWebServiceCategories as $sFile)
{
$aSettings['webservice_list'][] = $sFile;
}
foreach($this->m_aAddons as $sKey => $sFile)
{
$aSettings['addon_list'][] = $sFile;
}
foreach($this->m_aDictionaries as $sFile)
{
$aSettings['dictionary_list'][] = $sFile;
}
return $aSettings;
}
/**
* Write the configuration to a file (php format) that can be reloaded later
* By default write to the same file that was specified when constructing the object
@@ -772,7 +1203,7 @@ class Config
$sSeenAs = $aSettingInfo['value'] ? '1' : '0';
break;
default:
$sSeenAs = "'".$aSettingInfo['value']."'";
$sSeenAs = "'".addslashes($aSettingInfo['value'])."'";
}
fwrite($hFile, "\t'$sPropCode' => $sSeenAs,\n");
}
@@ -794,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");
@@ -819,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");
@@ -835,6 +1265,12 @@ class Config
fwrite($hFile, "\t\t'$sFile',\n");
}
fwrite($hFile, "\t),\n");
fwrite($hFile, "\t'webservices' => array (\n");
foreach($this->m_aWebServiceCategories as $sFile)
{
fwrite($hFile, "\t\t'$sFile',\n");
}
fwrite($hFile, "\t),\n");
fwrite($hFile, "\t'addons' => array (\n");
foreach($this->m_aAddons as $sKey => $sFile)
{
@@ -856,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;
}
}
?>

View File

@@ -40,6 +40,8 @@ define('evTEXTQUAL', 3); // used for escaping as well
define('evOTHERCHAR', 4);
define('evEND', 5);
define('NULL_VALUE', '<NULL>');
/**
* CSVParser
@@ -82,6 +84,10 @@ class CSVParser
{
$sCell = $this->m_sCurrCell;
}
if ($sCell == NULL_VALUE)
{
$sCell = null;
}
if (!is_null($aFieldMap))
{
@@ -178,6 +184,7 @@ class CSVParser
{
if ($i == $iDataLength)
{
$c = null;
$iEvent = evEND;
}
else

File diff suppressed because it is too large Load Diff

View File

@@ -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,29 @@ class DBObjectSearch
$this->m_aPointingTo = array();
$this->m_aReferencedBy = array();
$this->m_aRelatedTo = array();
$this->m_bDataFiltered = false;
$this->m_aParentConditions = array();
$this->m_aModifierProperties = 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()
@@ -100,6 +128,23 @@ class DBObjectSearch
}
public function SetModifierProperty($sPluginClass, $sProperty, $value)
{
$this->m_aModifierProperties[$sPluginClass][$sProperty] = $value;
}
public function GetModifierProperties($sPluginClass)
{
if (array_key_exists($sPluginClass, $this->m_aModifierProperties))
{
return $this->m_aModifierProperties[$sPluginClass];
}
else
{
return array();
}
}
public function IsAny()
{
// #@# todo - if (!$this->m_oSearchCondition->IsTrue()) return false;
@@ -107,6 +152,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 +161,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 +229,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 +248,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 +275,11 @@ class DBObjectSearch
$aConditions[] = implode(" and ", $aCondReferred);
}
foreach ($this->m_aParentConditions as $aRelInfo)
{
$aCondReferred[] = $this->DescribeConditionParent($aRelInfo);
}
return implode(" and ", $aConditions);
}
@@ -209,23 +302,88 @@ class DBObjectSearch
protected function TransferConditionExpression($oFilter, $aTranslation)
{
$oTranslated = $oFilter->GetCriteria()->Translate($aTranslation, false);
// 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);
}
public function AddNameCondition($sName)
{
$oValueExpr = new ScalarExpression($sName);
$oNameExpr = new FieldExpression('friendlyname', $this->GetClassAlias());
$oNewCondition = new BinaryExpression($oNameExpr, '=', $oValueExpr);
$this->AddConditionExpression($oNewCondition);
}
public function AddCondition($sFilterCode, $value, $sOpCode = null)
{
MyHelpers::CheckKeyInArray('filter code', $sFilterCode, MetaModel::GetClassFilterDefs($this->GetClass()));
@@ -312,30 +470,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)
@@ -347,16 +588,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");
@@ -366,20 +608,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;
}
}
@@ -423,6 +686,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);
@@ -455,9 +719,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)
{
@@ -476,7 +746,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 = "")
@@ -497,20 +767,47 @@ 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);
return base64_encode(serialize(array($sOql, $this->m_aParams)));
return base64_encode(serialize(array($sOql, $this->m_aParams, $this->m_aModifierProperties)));
}
static public function unserialize($sValue)
@@ -521,7 +818,9 @@ class DBObjectSearch
// We've tried to use gzcompress/gzuncompress, but for some specific queries
// it was not working at all (See Trac #193)
// gzuncompress was issuing a warning "data error" and the return object was null
return self::FromOQL($sOql, $aParams);
$oRetFilter = self::FromOQL($sOql, $aParams);
$oRetFilter->m_aModifierProperties = $aData[2];
return $oRetFilter;
}
// SImple BUt Structured Query Languag - SubuSQL
@@ -642,10 +941,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)
{
@@ -722,11 +1066,25 @@ class DBObjectSearch
}
elseif ($oExpression instanceof ListOqlExpression)
{
return new ListExpression($oExpression->GetItems());
$aItems = array();
foreach ($oExpression->GetItems() as $oItemExpression)
{
$aItems[] = $this->OQLExpressionToCondition($sQuery, $oItemExpression, $aClassAliases);
}
return new ListExpression($aItems);
}
elseif ($oExpression instanceof FunctionOqlExpression)
{
return new FunctionExpression($oExpression->GetVerb(), $oExpression->GetArgs());
$aArgs = array();
foreach ($oExpression->GetArgs() as $oArgExpression)
{
$aArgs[] = $this->OQLExpressionToCondition($sQuery, $oArgExpression, $aClassAliases);
}
return new FunctionExpression($oExpression->GetVerb(), $aArgs);
}
elseif ($oExpression instanceof IntervalOqlExpression)
{
return new IntervalExpression($oExpression->GetValue(), $oExpression->GetUnit());
}
else
{
@@ -844,7 +1202,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);
}
}
}
@@ -860,6 +1249,7 @@ class DBObjectSearch
}
$aSelected[$sClassToSelect] = $aAliases[$sClassToSelect];
}
$oResultFilter->m_aClasses = $aAliases;
$oResultFilter->SetSelectedClasses($aSelected);
$oConditionTree = $oOqlQuery->GetCondition();

View File

@@ -32,23 +32,28 @@
class DBObjectSet
{
private $m_oFilter;
private $m_aAddedIds; // Ids of objects added (discrete lists)
private $m_aOrderBy;
public $m_bLoaded;
private $m_aData;
private $m_aId2Row;
private $m_iCurrRow;
public function __construct(DBObjectSearch $oFilter, $aOrderBy = array(), $aArgs = array(), $iLimitCount = 0, $iLimitStart = 0)
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_bLoaded = false;
$this->m_aData = array(); // array of (row => array of (classalias) => object)
$this->m_aId2Row = array();
$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)
$this->m_iCurrRow = 0;
}
@@ -76,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));
@@ -85,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;
@@ -95,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;
}
@@ -158,6 +202,53 @@ class DBObjectSet
return $aRet;
}
public function ToArrayOfValues()
{
if (!$this->m_bLoaded) $this->Load();
$aSelectedClasses = $this->m_oFilter->GetSelectedClasses();
$aRet = array();
foreach($this->m_aData as $iRow => $aObjects)
{
foreach($aObjects as $sClassAlias => $oObject)
{
if (is_null($oObject))
{
$aRet[$iRow][$sClassAlias.'.'.'id'] = null;
}
else
{
$aRet[$iRow][$sClassAlias.'.'.'id'] = $oObject->GetKey();
}
if (is_null($oObject))
{
$sClass = $aSelectedClasses[$sClassAlias];
}
else
{
$sClass = get_class($oObject);
}
foreach(MetaModel::ListAttributeDefs($sClass) as $sAttCode => $oAttDef)
{
if ($oAttDef->IsScalar())
{
$sAttName = $sClassAlias.'.'.$sAttCode;
if (is_null($oObject))
{
$aRet[$iRow][$sAttName] = null;
}
else
{
$aRet[$iRow][$sAttName] = $oObject->Get($sAttCode);
}
}
}
}
}
return $aRet;
}
public function GetColumnAsArray($sAttCode, $bWithId = true)
{
$aRet = array();
@@ -178,7 +269,20 @@ class DBObjectSet
public function GetFilter()
{
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()
@@ -196,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;
@@ -215,13 +324,16 @@ class DBObjectSet
public function Load()
{
if ($this->m_bLoaded) return;
// Note: it is mandatory to set this value now, to protect against reentrance
$this->m_bLoaded = true;
if ($this->m_iLimitCount > 0)
{
$sSQL = MetaModel::MakeSelectQuery($this->m_oFilter, $this->m_aOrderBy, $this->m_aArgs, $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);
$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;
@@ -232,25 +344,42 @@ class DBObjectSet
$aObjects = array();
foreach ($this->m_oFilter->GetSelectedClasses() as $sClassAlias => $sClass)
{
$oObject = MetaModel::GetObjectByRow($sClass, $aRow, $sClassAlias);
if (is_null($aRow[$sClassAlias.'id']))
{
$oObject = null;
}
else
{
$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);
$this->m_bLoaded = true;
}
public function Count()
{
$sSQL = MetaModel::MakeSelectQuery($this->m_oFilter, $this->m_aOrderBy, $this->m_aArgs, 0, 0, true);
$resQuery = CMDBSource::Query($sSQL);
if (!$resQuery) return 0;
$aRow = CMDBSource::FetchArray($resQuery);
CMDBSource::FreeResult($resQuery);
return $aRow['COUNT'];
if ($this->m_bLoaded && ($this->m_iLimitCount == 0) && ($this->m_iLimitStart == 0))
{
return count($this->m_aData);
}
else
{
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;
}
}
public function Fetch($sClassAlias = '')
@@ -289,7 +418,10 @@ class DBObjectSet
public function Rewind()
{
$this->Seek(0);
if ($this->m_bLoaded)
{
$this->Seek(0);
}
}
public function Seek($iRow)
@@ -302,6 +434,8 @@ class DBObjectSet
public function AddObject($oObject, $sClassAlias = '')
{
if (!$this->m_bLoaded) $this->Load();
if (strlen($sClassAlias) == 0)
{
$sClassAlias = $this->m_oFilter->GetClassAlias();
@@ -309,22 +443,37 @@ class DBObjectSet
$iNextPos = count($this->m_aData);
$this->m_aData[$iNextPos][$sClassAlias] = $oObject;
$this->m_aId2Row[$sClassAlias][$oObject->GetKey()] = $iNextPos;
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();
$iNextPos = count($this->m_aData);
foreach ($aObjectArray as $sClassAlias => $oObject)
{
$this->m_aData[$iNextPos][$sClassAlias] = $oObject;
$this->m_aId2Row[$sClassAlias][$oObject->GetKey()] = $iNextPos;
if (!is_null($oObject))
{
$this->m_aId2Row[$sClassAlias][$oObject->GetKey()] = $iNextPos;
if (!$bInternalLoad)
{
$this->m_aAddedIds[$oObject->GetKey()] = true;
}
}
}
}
public function AddObjectArray($aObjects, $sClassAlias = '')
{
if (!$this->m_bLoaded) $this->Load();
// #@# todo - add a check on the object class ?
foreach ($aObjects as $oObj)
{
@@ -369,6 +518,43 @@ class DBObjectSet
return $oNewSet;
}
// Note: This verb works only with objects existing in the database
//
public function HasSameContents($oObjectSet)
{
if ($this->GetRootClass() != $oObjectSet->GetRootClass())
{
return false;
}
if (!$this->m_bLoaded) $this->Load();
if ($this->Count() != $oObjectSet->Count())
{
return false;
}
$sClassAlias = $this->m_oFilter->GetClassAlias();
$oObjectSet->Rewind();
while ($oObject = $oObjectSet->Fetch())
{
$iObjectKey = $oObject->GetKey();
if ($iObjectKey < 0)
{
return false;
}
if (!array_key_exists($iObjectKey, $this->m_aId2Row[$sClassAlias]))
{
return false;
}
$iRow = $this->m_aId2Row[$sClassAlias][$iObjectKey];
$oSibling = $this->m_aData[$iRow][$sClassAlias];
if (!$oObject->Equals($oSibling))
{
return false;
}
}
return true;
}
public function CreateDelta($oObjectSet)
{
if ($this->GetRootClass() != $oObjectSet->GetRootClass())
@@ -413,6 +599,156 @@ class DBObjectSet
}
return $aRelatedObjs;
}
/**
* Builds an object that contains the values that are common to all the objects
* in the set. If for a given attribute, objects in the set have various values
* then the resulting object will contain null for this value.
* @param $aValues Hash Output: the distribution of the values, in the set, for each attribute
* @return Object
*/
public function ComputeCommonObject(&$aValues)
{
$sClass = $this->GetClass();
$aList = MetaModel::ListAttributeDefs($sClass);
$aValues = array();
foreach($aList as $sAttCode => $oAttDef)
{
if ($oAttDef->IsScalar())
{
$aValues[$sAttCode] = array();
}
}
$this->Rewind();
while($oObj = $this->Fetch())
{
foreach($aList as $sAttCode => $oAttDef)
{
if ($oAttDef->IsScalar() && $oAttDef->IsWritable())
{
$currValue = $oObj->Get($sAttCode);
if (is_object($currValue)) continue; // Skip non scalar values...
if(!array_key_exists($currValue, $aValues[$sAttCode]))
{
$aValues[$sAttCode][$currValue] = array('count' => 1, 'display' => $oObj->GetAsHTML($sAttCode));
}
else
{
$aValues[$sAttCode][$currValue]['count']++;
}
}
}
}
foreach($aValues as $sAttCode => $aMultiValues)
{
if (count($aMultiValues) > 1)
{
uasort($aValues[$sAttCode], 'HashCountComparison');
}
}
// Now create an object that has values for the homogenous values only
$oCommonObj = new $sClass(); // @@ What if the class is abstract ?
$aComments = array();
$iFormId = cmdbAbstractObject::GetNextFormId(); // Identifier that prefixes all the form fields
$sReadyScript = '';
$aDependsOn = array();
$sFormPrefix = '2_';
foreach($aList as $sAttCode => $oAttDef)
{
if ($oAttDef->IsScalar() && $oAttDef->IsWritable())
{
if ($oAttDef->GetEditClass() == 'One Way Password')
{
$oCommonObj->Set($sAttCode, null);
}
else
{
$iCount = count($aValues[$sAttCode]);
if ($iCount == 1)
{
// Homogenous value
reset($aValues[$sAttCode]);
$aKeys = array_keys($aValues[$sAttCode]);
$currValue = $aKeys[0]; // The only value is the first key
$oCommonObj->Set($sAttCode, $currValue);
}
else
{
// Non-homogenous value
$oCommonObj->Set($sAttCode, null);
}
}
}
}
$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);
}
}
/**
* Helper function to perform a custom sort of a hash array
*/
function HashCountComparison($a, $b) // Sort descending on 'count'
{
if ($a['count'] == $b['count'])
{
return 0;
}
return ($a['count'] > $b['count']) ? -1 : 1;
}
?>

View File

@@ -0,0 +1,159 @@
<?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
/**
* Database properties - manage database instances in a complex installation
*
* @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
*/
/**
* A database property
*
* @package iTopORM
*/
class DBProperty extends DBObject
{
public static function Init()
{
$aParams = array
(
"category" => "cloud",
"key_type" => "autoincrement",
"name_attcode" => "name",
"state_attcode" => "",
"reconc_keys" => array(),
"db_table" => "priv_db_properties",
"db_key_field" => "id",
"db_finalclass_field" => "",
);
MetaModel::Init_Params($aParams);
//MetaModel::Init_InheritAttributes();
MetaModel::Init_AddAttribute(new AttributeString("name", array("allowed_values"=>null, "sql"=>"name", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeString("description", array("allowed_values"=>null, "sql"=>"description", "default_value"=>null, "is_null_allowed"=>true, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeString("value", array("allowed_values"=>null, "sql"=>"value", "default_value"=>null, "is_null_allowed"=>true, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeDateTime("change_date", array("allowed_values"=>null, "sql"=>"change_date", "default_value"=>"", "is_null_allowed"=>false, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeString("change_comment", array("allowed_values"=>null, "sql"=>"change_comment", "default_value"=>null, "is_null_allowed"=>true, "depends_on"=>array())));
}
/**
* Helper to check wether the table has been created into the DB
* (this table did not exist in 1.0.1 and older versions)
*/
public static function IsInstalled()
{
$sTable = MetaModel::DBGetTable(__CLASS__);
if (CMDBSource::IsTable($sTable))
{
return true;
}
else
{
return false;
}
return false;
}
public static function SetProperty($sName, $sValue, $sComment = '', $sDescription = null)
{
try
{
$oSearch = DBObjectSearch::FromOQL('SELECT DBProperty WHERE name = :name');
$oSet = new DBObjectSet($oSearch, array(), array('name' => $sName));
if ($oSet->Count() == 0)
{
$oProp = new DBProperty();
$oProp->Set('name', $sName);
$oProp->Set('description', $sDescription);
$oProp->Set('value', $sValue);
$oProp->Set('change_date', time());
$oProp->Set('change_comment', $sComment);
$oProp->DBInsert();
}
elseif ($oSet->Count() == 1)
{
$oProp = $oSet->fetch();
if (!is_null($sDescription))
{
$oProp->Set('description', $sDescription);
}
$oProp->Set('value', $sValue);
$oProp->Set('change_date', time());
$oProp->Set('change_comment', $sComment);
$oProp->DBUpdate();
}
else
{
// Houston...
throw new CoreException('duplicate db property');
}
}
catch (MySQLException $e)
{
// This might be because the table could not be found,
// let's check it and discard silently if this is really the case
if (self::IsInstalled())
{
throw $e;
}
IssueLog::Error('Attempting to write a DBProperty while the module has not been installed');
}
}
public static function GetProperty($sName, $default = null)
{
try
{
$oSearch = DBObjectSearch::FromOQL('SELECT DBProperty WHERE name = :name');
$oSet = new DBObjectSet($oSearch, array(), array('name' => $sName));
$iCount = $oSet->Count();
if ($iCount == 0)
{
//throw new CoreException('unknown db property', array('name' => $sName));
$sValue = $default;
}
elseif ($iCount == 1)
{
$oProp = $oSet->fetch();
$sValue = $oProp->Get('value');
}
else
{
// $iCount > 1
// Houston...
throw new CoreException('duplicate db property', array('name' => $sName, 'count' => $iCount));
}
}
catch (MySQLException $e)
{
// This might be because the table could not be found,
// let's check it and discard silently if this is really the case
if (self::IsInstalled())
{
throw $e;
}
$sValue = $default;
}
return $sValue;
}
}
?>

View File

@@ -0,0 +1,288 @@
<?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
/**
* Class dbObject: the root of persistent classes
*
* @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
*/
class DeleteException extends CoreException
{
}
/**
* Deletion plan (other objects to be deleted/modified, eventual issues, etc.)
*
* @package iTopORM
*/
class DeletionPlan
{
//protected $m_aIssues;
protected $m_bFoundStopper;
protected $m_bFoundSecurityIssue;
protected $m_bFoundManualDelete;
protected $m_bFoundManualOperation;
protected $m_iToDelete;
protected $m_iToUpdate;
protected $m_aToDelete;
protected $m_aToUpdate;
protected static $m_aModeUpdate = array(
DEL_SILENT => array(
DEL_SILENT => DEL_SILENT,
DEL_AUTO => DEL_AUTO,
DEL_MANUAL => DEL_MANUAL
),
DEL_MANUAL => array(
DEL_SILENT => DEL_MANUAL,
DEL_AUTO => DEL_AUTO,
DEL_MANUAL => DEL_MANUAL
),
DEL_AUTO => array(
DEL_SILENT => DEL_AUTO,
DEL_AUTO => DEL_AUTO,
DEL_MANUAL => DEL_AUTO
)
);
public function __construct()
{
$this->m_iToDelete = 0;
$this->m_iToUpdate = 0;
$this->m_aToDelete = array();
$this->m_aToUpdate = array();
$this->m_bFoundStopper = false;
$this->m_bFoundSecurityIssue = false;
$this->m_bFoundManualDelete = false;
$this->m_bFoundManualOperation = false;
}
public function ComputeResults()
{
foreach($this->m_aToDelete as $sClass => $aToDelete)
{
foreach($aToDelete as $iId => $aData)
{
$this->m_iToDelete++;
if (isset($aData['issue']))
{
$this->m_bFoundStopper = true;
$this->m_bFoundManualOperation = true;
if (isset($aData['issue_security']))
{
$this->m_bFoundSecurityIssue = true;
}
}
if ($aData['mode'] == DEL_MANUAL)
{
$this->m_bFoundStopper = true;
$this->m_bFoundManualDelete = true;
}
}
}
foreach($this->m_aToUpdate as $sClass => $aToUpdate)
{
foreach($aToUpdate as $iId => $aData)
{
$this->m_iToUpdate++;
$oObject = $aData['to_reset'];
$aExtKeyLabels = array();
foreach ($aData['attributes'] as $sRemoteExtKey => $aRemoteAttDef)
{
$oObject->Set($sRemoteExtKey, $aData['values'][$sRemoteExtKey]);
$aExtKeyLabels[] = $aRemoteAttDef->GetLabel();
}
$this->m_aToUpdate[$sClass][$iId]['attributes_list'] = implode(', ', $aExtKeyLabels);
list($bRes, $aIssues, $bSecurityIssues) = $oObject->CheckToWrite();
if (!$bRes)
{
$this->m_aToUpdate[$sClass][$iId]['issue'] = implode(', ', $aIssues);
$this->m_bFoundStopper = true;
if ($bSecurityIssues)
{
$this->m_aToUpdate[$sClass][$iId]['issue_security'] = true;
$this->m_bFoundSecurityIssue = true;
}
}
}
}
}
public function GetIssues()
{
$aIssues = array();
foreach ($this->m_aToDelete as $sClass => $aToDelete)
{
foreach ($aToDelete as $iId => $aData)
{
if (isset($aData['issue']))
{
$aIssues[] = $aData['issue'];
}
}
}
foreach ($this->m_aToUpdate as $sClass => $aToUpdate)
{
foreach ($aToUpdate as $iId => $aData)
{
if (isset($aData['issue']))
{
$aIssues[] = $aData['issue'];
}
}
}
return $aIssues;
}
public function ListDeletes()
{
return $this->m_aToDelete;
}
public function ListUpdates()
{
return $this->m_aToUpdate;
}
public function GetTargetCount()
{
return $this->m_iToDelete + $this->m_iToUpdate;
}
public function FoundStopper()
{
return $this->m_bFoundStopper;
}
public function FoundSecurityIssue()
{
return $this->m_bFoundSecurityIssue;
}
public function FoundManualOperation()
{
return $this->m_bFoundManualOperation;
}
public function FoundManualDelete()
{
return $this->m_bFoundManualDelete;
}
public function FoundManualUpdate()
{
}
public function AddToDelete($oObject, $iDeletionMode = null)
{
if (is_null($iDeletionMode))
{
$bRequestedExplicitely = true;
$iDeletionMode = DEL_AUTO;
}
else
{
$bRequestedExplicitely = false;
}
$sClass = get_class($oObject);
$iId = $oObject->GetKey();
if (isset($this->m_aToUpdate[$sClass][$iId]))
{
unset($this->m_aToUpdate[$sClass][$iId]);
}
if (isset($this->m_aToDelete[$sClass][$iId]))
{
if ($this->m_aToDelete[$sClass][$iId]['requested_explicitely'])
{
// No change: let it in mode DEL_AUTO
}
else
{
$iPrevDeletionMode = $this->m_aToDelete[$sClass][$iId]['mode'];
$iNewDeletionMode = self::$m_aModeUpdate[$iPrevDeletionMode][$iDeletionMode];
$this->m_aToDelete[$sClass][$iId]['mode'] = $iNewDeletionMode;
if ($bRequestedExplicitely)
{
// This object was in the root list
$this->m_aToDelete[$sClass][$iId]['requested_explicitely'] = true;
$this->m_aToDelete[$sClass][$iId]['mode'] = DEL_AUTO;
}
}
}
else
{
$this->m_aToDelete[$sClass][$iId] = array(
'to_delete' => $oObject,
'mode' => $iDeletionMode,
'requested_explicitely' => $bRequestedExplicitely,
);
}
}
public function SetDeletionIssues($oObject, $aIssues, $bSecurityIssue)
{
if (count($aIssues) > 0)
{
$sClass = get_class($oObject);
$iId = $oObject->GetKey();
$this->m_aToDelete[$sClass][$iId]['issue'] = implode(', ', $aIssues);
if ($bSecurityIssue)
{
$this->m_aToDelete[$sClass][$iId]['issue_security'] = true;
}
}
}
public function AddToUpdate($oObject, $oAttDef, $value = 0)
{
$sClass = get_class($oObject);
$iId = $oObject->GetKey();
if (isset($this->m_aToDelete[$sClass][$iId]))
{
// skip... it should be deleted anyhow !
}
else
{
if (!isset($this->m_aToUpdate[$sClass][$iId]))
{
$this->m_aToUpdate[$sClass][$iId] = array(
'to_reset' => $oObject,
);
}
$this->m_aToUpdate[$sClass][$iId]['attributes'][$oAttDef->GetCode()] = $oAttDef;
$this->m_aToUpdate[$sClass][$iId]['values'][$oAttDef->GetCode()] = $value;
}
}
}
?>

View File

@@ -1,228 +1,332 @@
<?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
/**
* Class Dict
* Management of localizable strings
*
* @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
*/
class DictException extends CoreException
{
}
class DictExceptionUnknownLanguage extends DictException
{
public function __construct($sLanguageCode)
{
$aContext = array();
$aContext['language_code'] = $sLanguageCode;
parent::__construct('Unknown localization language', $aContext);
}
}
class DictExceptionMissingString extends DictException
{
public function __construct($sLanguageCode, $sStringCode)
{
$aContext = array();
$aContext['language_code'] = $sLanguageCode;
$aContext['string_code'] = $sStringCode;
parent::__construct('Missing localized string', $aContext);
}
}
define('DICT_ERR_STRING', 1); // when a string is missing, return the identifier
define('DICT_ERR_EXCEPTION', 2); // when a string is missing, throw an exception
//define('DICT_ERR_LOG', 3); // when a string is missing, log an error
class Dict
{
protected static $m_iErrorMode = DICT_ERR_STRING;
protected static $m_sDefaultLanguage = 'EN US';
protected static $m_sCurrentLanguage = null; // No language selected by default
protected static $m_aLanguages = array(); // array( code => array( 'description' => '...', 'localized_description' => '...') ...)
protected static $m_aData = array();
public static function SetDefaultLanguage($sLanguageCode)
{
if (!array_key_exists($sLanguageCode, self::$m_aLanguages))
{
throw new DictExceptionUnknownLanguage($sLanguageCode);
}
self::$m_sDefaultLanguage = $sLanguageCode;
}
public static function SetUserLanguage($sLanguageCode)
{
if (!array_key_exists($sLanguageCode, self::$m_aLanguages))
{
throw new DictExceptionUnknownLanguage($sLanguageCode);
}
self::$m_sCurrentLanguage = $sLanguageCode;
}
public static function GetCurrentLanguage()
{
if (self::$m_sCurrentLanguage == null) // May happen when no user is logged in (i.e login screen, non authentifed page)
{
// In which case let's use the default language
return self::$m_sDefaultLanguage;
}
return self::$m_sCurrentLanguage;
}
//returns a hash array( code => array( 'description' => '...', 'localized_description' => '...') ...)
public static function GetLanguages()
{
return self::$m_aLanguages;
}
// iErrorMode from {DICT_ERR_STRING, DICT_ERR_EXCEPTION}
public static function SetErrorMode($iErrorMode)
{
self::$m_iErrorMode = $iErrorMode;
}
public static function S($sStringCode, $sDefault = null)
{
// Attempt to find the string in the user language
//
if (!array_key_exists(self::GetCurrentLanguage(), self::$m_aData))
{
// It may happen, when something happens before the dictionnaries get loaded
return $sStringCode;
}
$aCurrentDictionary = self::$m_aData[self::GetCurrentLanguage()];
if (array_key_exists($sStringCode, $aCurrentDictionary))
{
return $aCurrentDictionary[$sStringCode];
}
// Attempt to find the string in the default language
//
$aDefaultDictionary = self::$m_aData[self::$m_sDefaultLanguage];
if (array_key_exists($sStringCode, $aDefaultDictionary))
{
return $aDefaultDictionary[$sStringCode];
}
// Could not find the string...
//
switch (self::$m_iErrorMode)
{
case DICT_ERR_STRING:
if (is_null($sDefault))
{
return $sStringCode;
}
else
{
return $sDefault;
}
break;
case DICT_ERR_EXCEPTION:
default:
throw new DictExceptionMissingString(self::$m_sCurrentLanguage, $sStringCode);
break;
}
return 'bug!';
}
public static function Format($sFormatCode /*, ... arguments ....*/)
{
$sLocalizedFormat = self::S($sFormatCode);
$aArguments = func_get_args();
if ($sLocalizedFormat == $sFormatCode)
{
// Make sure the information will be displayed (ex: an error occuring before the dictionary gets loaded)
return $sFormatCode.' - '.implode(', ', $aArguments);
}
array_shift($aArguments);
return vsprintf($sLocalizedFormat, $aArguments);
}
// sLanguageCode: Code identifying the language i.e. FR-FR
// sEnglishLanguageDesc: Description of the language code, in English. i.e. French (France)
// sLocalizedLanguageDesc: Description of the language code, in its own language. i.e. Français (France)
// aEntries: Hash array of dictionnary entries
public static function Add($sLanguageCode, $sEnglishLanguageDesc, $sLocalizedLanguageDesc, $aEntries)
{
if (!array_key_exists($sLanguageCode, self::$m_aLanguages))
{
self::$m_aLanguages[$sLanguageCode] = array('description' => $sEnglishLanguageDesc, 'localized_description' => $sLocalizedLanguageDesc);
self::$m_aData[$sLanguageCode] = array();
}
self::$m_aData[$sLanguageCode] = array_merge(self::$m_aData[$sLanguageCode], $aEntries);
}
public static function MakeStats($sLanguageCode, $sLanguageRef = 'EN US')
{
$aMissing = array(); // Strings missing for the target language
$aUnexpected = array(); // Strings defined for the target language, but not found in the reference dictionary
$aNotTranslated = array(); // Strings having the same value in both dictionaries
$aOK = array(); // Strings having different values in both dictionaries
foreach (self::$m_aData[$sLanguageRef] as $sStringCode => $sValue)
{
if (!array_key_exists($sStringCode, self::$m_aData[$sLanguageCode]))
{
$aMissing[$sStringCode] = $sValue;
}
}
foreach (self::$m_aData[$sLanguageCode] as $sStringCode => $sValue)
{
if (!array_key_exists($sStringCode, self::$m_aData[$sLanguageRef]))
{
$aUnexpected[$sStringCode] = $sValue;
}
else
{
// The value exists in the reference
$sRefValue = self::$m_aData[$sLanguageRef][$sStringCode];
if ($sValue == $sRefValue)
{
$aNotTranslated[$sStringCode] = $sValue;
}
else
{
$aOK[$sStringCode] = $sValue;
}
}
}
return array($aMissing, $aUnexpected, $aNotTranslated, $aOK);
}
public static function Dump()
{
MyHelpers::var_dump_html(self::$m_aData);
}
}
?>
<?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
/**
* Class Dict
* Management of localizable strings
*
* @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
*/
class DictException extends CoreException
{
}
class DictExceptionUnknownLanguage extends DictException
{
public function __construct($sLanguageCode)
{
$aContext = array();
$aContext['language_code'] = $sLanguageCode;
parent::__construct('Unknown localization language', $aContext);
}
}
class DictExceptionMissingString extends DictException
{
public function __construct($sLanguageCode, $sStringCode)
{
$aContext = array();
$aContext['language_code'] = $sLanguageCode;
$aContext['string_code'] = $sStringCode;
parent::__construct('Missing localized string', $aContext);
}
}
define('DICT_ERR_STRING', 1); // when a string is missing, return the identifier
define('DICT_ERR_EXCEPTION', 2); // when a string is missing, throw an exception
//define('DICT_ERR_LOG', 3); // when a string is missing, log an error
class Dict
{
protected static $m_bTraceFiles = false;
protected static $m_aEntryFiles = array();
protected static $m_iErrorMode = DICT_ERR_STRING;
protected static $m_sDefaultLanguage = 'EN US';
protected static $m_sCurrentLanguage = null; // No language selected by default
protected static $m_aLanguages = array(); // array( code => array( 'description' => '...', 'localized_description' => '...') ...)
protected static $m_aData = array();
public static function EnableTraceFiles()
{
self::$m_bTraceFiles = true;
}
public static function GetEntryFiles()
{
return self::$m_aEntryFiles;
}
public static function SetDefaultLanguage($sLanguageCode)
{
if (!array_key_exists($sLanguageCode, self::$m_aLanguages))
{
throw new DictExceptionUnknownLanguage($sLanguageCode);
}
self::$m_sDefaultLanguage = $sLanguageCode;
}
public static function SetUserLanguage($sLanguageCode)
{
if (!array_key_exists($sLanguageCode, self::$m_aLanguages))
{
throw new DictExceptionUnknownLanguage($sLanguageCode);
}
self::$m_sCurrentLanguage = $sLanguageCode;
}
public static function GetUserLanguage()
{
if (self::$m_sCurrentLanguage == null) // May happen when no user is logged in (i.e login screen, non authentifed page)
{
// In which case let's use the default language
return self::$m_sDefaultLanguage;
}
return self::$m_sCurrentLanguage;
}
//returns a hash array( code => array( 'description' => '...', 'localized_description' => '...') ...)
public static function GetLanguages()
{
return self::$m_aLanguages;
}
// iErrorMode from {DICT_ERR_STRING, DICT_ERR_EXCEPTION}
public static function SetErrorMode($iErrorMode)
{
self::$m_iErrorMode = $iErrorMode;
}
public static function S($sStringCode, $sDefault = null)
{
// Attempt to find the string in the user language
//
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::GetUserLanguage()];
if (array_key_exists($sStringCode, $aCurrentDictionary))
{
return $aCurrentDictionary[$sStringCode];
}
// Attempt to find the string in the default language
//
$aDefaultDictionary = self::$m_aData[self::$m_sDefaultLanguage];
if (array_key_exists($sStringCode, $aDefaultDictionary))
{
return $aDefaultDictionary[$sStringCode];
}
// Attempt to find the string in english
//
$aDefaultDictionary = self::$m_aData['EN US'];
if (array_key_exists($sStringCode, $aDefaultDictionary))
{
return $aDefaultDictionary[$sStringCode];
}
// Could not find the string...
//
switch (self::$m_iErrorMode)
{
case DICT_ERR_STRING:
if (is_null($sDefault))
{
return $sStringCode;
}
else
{
return $sDefault;
}
break;
case DICT_ERR_EXCEPTION:
default:
throw new DictExceptionMissingString(self::$m_sCurrentLanguage, $sStringCode);
break;
}
return 'bug!';
}
public static function Format($sFormatCode /*, ... arguments ....*/)
{
$sLocalizedFormat = self::S($sFormatCode);
$aArguments = func_get_args();
array_shift($aArguments);
if ($sLocalizedFormat == $sFormatCode)
{
// Make sure the information will be displayed (ex: an error occuring before the dictionary gets loaded)
return $sFormatCode.' - '.implode(', ', $aArguments);
}
return vsprintf($sLocalizedFormat, $aArguments);
}
// sLanguageCode: Code identifying the language i.e. FR-FR
// sEnglishLanguageDesc: Description of the language code, in English. i.e. French (France)
// sLocalizedLanguageDesc: Description of the language code, in its own language. i.e. Français (France)
// aEntries: Hash array of dictionnary entries
// ~~ or ~* can be used to indicate entries still to be translated.
public static function Add($sLanguageCode, $sEnglishLanguageDesc, $sLocalizedLanguageDesc, $aEntries)
{
if (self::$m_bTraceFiles)
{
$aBacktrace = debug_backtrace();
$sFile = $aBacktrace[0]["file"];
foreach($aEntries as $sKey => $sValue)
{
self::$m_aEntryFiles[$sLanguageCode][$sKey] = array(
'file' => $sFile,
'value' => $sValue
);
}
}
if (!array_key_exists($sLanguageCode, self::$m_aLanguages))
{
self::$m_aLanguages[$sLanguageCode] = array('description' => $sEnglishLanguageDesc, 'localized_description' => $sLocalizedLanguageDesc);
self::$m_aData[$sLanguageCode] = array();
}
foreach($aEntries as $sCode => $sValue)
{
self::$m_aData[$sLanguageCode][$sCode] = self::FilterString($sValue);
}
}
/**
* Clone a string in every language (if it exists in that language)
*/
public static function CloneString($sSourceCode, $sDestCode)
{
foreach(self::$m_aLanguages as $sLanguageCode => $foo)
{
if (isset(self::$m_aData[$sLanguageCode][$sSourceCode]))
{
self::$m_aData[$sLanguageCode][$sDestCode] = self::$m_aData[$sLanguageCode][$sSourceCode];
}
}
}
public static function MakeStats($sLanguageCode, $sLanguageRef = 'EN US')
{
$aMissing = array(); // Strings missing for the target language
$aUnexpected = array(); // Strings defined for the target language, but not found in the reference dictionary
$aNotTranslated = array(); // Strings having the same value in both dictionaries
$aOK = array(); // Strings having different values in both dictionaries
foreach (self::$m_aData[$sLanguageRef] as $sStringCode => $sValue)
{
if (!array_key_exists($sStringCode, self::$m_aData[$sLanguageCode]))
{
$aMissing[$sStringCode] = $sValue;
}
}
foreach (self::$m_aData[$sLanguageCode] as $sStringCode => $sValue)
{
if (!array_key_exists($sStringCode, self::$m_aData[$sLanguageRef]))
{
$aUnexpected[$sStringCode] = $sValue;
}
else
{
// The value exists in the reference
$sRefValue = self::$m_aData[$sLanguageRef][$sStringCode];
if ($sValue == $sRefValue)
{
$aNotTranslated[$sStringCode] = $sValue;
}
else
{
$aOK[$sStringCode] = $sValue;
}
}
}
return array($aMissing, $aUnexpected, $aNotTranslated, $aOK);
}
public static function Dump()
{
MyHelpers::var_dump_html(self::$m_aData);
}
public static function InCache($sApplicationPrefix)
{
if (function_exists('apc_fetch'))
{
$bResult = false;
// Note: For versions of APC older than 3.0.17, fetch() accepts only one parameter
//
self::$m_aData = apc_fetch($sApplicationPrefix.'-dict');
if (is_bool(self::$m_aData) && (self::$m_aData === false))
{
self::$m_aData = array();
}
else
{
self::$m_aLanguages = apc_fetch($sApplicationPrefix.'-languages');
if (is_bool(self::$m_aLanguages) && (self::$m_aLanguages === false))
{
self::$m_aLanguages = array();
}
else
{
$bResult = true;
}
}
return $bResult;
}
return false;
}
public static function InitCache($sApplicationPrefix)
{
if (function_exists('apc_store'))
{
apc_store($sApplicationPrefix.'-languages', self::$m_aLanguages);
apc_store($sApplicationPrefix.'-dict', self::$m_aData);
}
}
public static function ResetCache($sApplicationPrefix)
{
if (function_exists('apc_delete'))
{
apc_delete($sApplicationPrefix.'-languages');
apc_delete($sApplicationPrefix.'-dict');
}
}
protected static function FilterString($s)
{
return str_replace(array('~~', '~*'), '', $s);
}
}
?>

View File

@@ -24,22 +24,28 @@
* @license http://www.opensource.org/licenses/gpl-3.0.html LGPL
*/
define ('EMAIL_SEND_OK', 0);
define ('EMAIL_SEND_PENDING', 1);
define ('EMAIL_SEND_ERROR', 2);
class EMail
{
protected $m_sBody;
protected $m_sSubject;
protected $m_sTo;
protected $m_aHeaders; // array of key=>value
protected $m_aAttachments;
public function __construct()
public function __construct($sTo = '', $sSubject = '', $sBody = '', $aHeaders = array())
{
$this->m_sTo = '';
$this->m_sSubject = '';
$this->m_sBody = '';
$this->m_aHeaders = array();
$this->m_sTo = $sTo;
$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
// executed in the background, while making sure that any issue would be reported clearly
protected $m_aMailErrors; //array of strings explaining the issues
@@ -50,14 +56,33 @@ class EMail
$this->m_aMailErrors[] = $sCleanMessage;
}
protected function SendAsynchronous(&$aIssues, $oLog = null)
{
try
{
AsyncSendEmail::AddToQueue($this->m_sTo, $this->m_sSubject, $this->m_sBody, $this->m_aHeaders, $oLog);
}
catch(Exception $e)
{
$aIssues = array($e->GetMessage());
return EMAIL_SEND_ERROR;
}
$aIssues = array();
return EMAIL_SEND_PENDING;
}
// returns a list of issues if any
public function Send()
protected function SendSynchronous(&$aIssues, $oLog = null)
{
$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";
@@ -69,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
);
@@ -79,10 +104,40 @@ class EMail
{
$this->m_aMailErrors[] = 'Unknown reason';
}
return $this->m_aMailErrors;
if (count($this->m_aMailErrors) > 0)
{
$aIssues = $this->m_aMailErrors;
return EMAIL_SEND_ERROR;
}
else
{
$aIssues = array();
return EMAIL_SEND_OK;
}
}
protected function AddToHeader($sKey, $sValue)
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);
}
else
{
$bConfigASYNC = MetaModel::GetConfig()->Get('email_asynchronous');
if ($bConfigASYNC)
{
return $this->SendAsynchronous($aIssues, $oLog);
}
else
{
return $this->SendSynchronous($aIssues, $oLog);
}
}
}
public function AddToHeader($sKey, $sValue)
{
if (strlen($sValue) > 0)
{
@@ -90,6 +145,16 @@ class EMail
}
}
public function SetMessageId($sId)
{
$this->AddToHeader('Message-ID', $sId);
}
public function SetReferences($sReferences)
{
$this->AddToHeader('References', $sReferences);
}
public function SetBody($sBody)
{
$this->m_sBody = $sBody;
@@ -130,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);
}
}
?>
?>

View File

@@ -25,7 +25,7 @@
* @license http://www.opensource.org/licenses/gpl-3.0.html LGPL
*/
class Event extends cmdbAbstractObject
class Event extends DBObject implements iDisplay
{
public static function Init()
{
@@ -46,14 +46,77 @@ class Event extends cmdbAbstractObject
MetaModel::Init_AddAttribute(new AttributeText("message", array("allowed_values"=>null, "sql"=>"message", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeDateTime("date", array("allowed_values"=>null, "sql"=>"date", "default_value"=>"", "is_null_allowed"=>false, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeString("userinfo", array("allowed_values"=>null, "sql"=>"userinfo", "default_value"=>null, "is_null_allowed"=>true, "depends_on"=>array())));
// MetaModel::Init_AddAttribute(new AttributeString("userinfo", array("allowed_values"=>null, "sql"=>"userinfo", "default_value"=>null, "is_null_allowed"=>true, "depends_on"=>array())));
// Display lists
MetaModel::Init_SetZListItems('details', array('message', 'date', 'userinfo')); // Attributes to be displayed for the complete details
MetaModel::Init_SetZListItems('details', array('date', 'message', 'userinfo')); // Attributes to be displayed for the complete details
MetaModel::Init_SetZListItems('list', array('date', 'finalclass', 'message')); // 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
}
/**
* Maps the given context parameter name to the appropriate filter/search code for this class
* @param string $sContextParam Name of the context parameter, i.e. 'org_id'
* @return string Filter code, i.e. 'customer_id'
*/
public static function MapContextParam($sContextParam)
{
if ($sContextParam == 'menu')
{
return null;
}
else
{
return $sContextParam;
}
}
/**
* This function returns a 'hilight' CSS class, used to hilight a given row in a table
* There are currently (i.e defined in the CSS) 4 possible values HILIGHT_CLASS_CRITICAL,
* HILIGHT_CLASS_WARNING, HILIGHT_CLASS_OK, HILIGHT_CLASS_NONE
* To Be overridden by derived classes
* @param void
* @return String The desired higlight class for the object/row
*/
public function GetHilightClass()
{
// Possible return values are:
// HILIGHT_CLASS_CRITICAL, HILIGHT_CLASS_WARNING, HILIGHT_CLASS_OK, HILIGHT_CLASS_NONE
return HILIGHT_CLASS_NONE; // Not hilighted by default
}
public static function GetUIPage()
{
return 'UI.php';
}
function DisplayDetails(WebPage $oPage, $bEditMode = false)
{
// Object's details
//$this->DisplayBareHeader($oPage, $bEditMode);
$oPage->AddTabContainer(OBJECT_PROPERTIES_TAB);
$oPage->SetCurrentTabContainer(OBJECT_PROPERTIES_TAB);
$oPage->SetCurrentTab(Dict::S('UI:PropertiesTab'));
$this->DisplayBareProperties($oPage, $bEditMode);
}
function DisplayBareProperties(WebPage $oPage, $bEditMode = false, $sPrefix = '', $aExtraParams = array())
{
if ($bEditMode) return; // Not editable
$aDetails = array();
$sClass = get_class($this);
$aZList = MetaModel::FlattenZlist(MetaModel::GetZListItems($sClass, 'details'));
foreach( $aZList as $sAttCode)
{
$sDisplayValue = $this->GetAsHTML($sAttCode);
$aDetails[] = array('label' => '<span title="'.MetaModel::GetDescription($sClass, $sAttCode).'">'.MetaModel::GetLabel($sClass, $sAttCode).'</span>', 'value' => $sDisplayValue);
}
$oPage->Details($aDetails);
}
}
class EventNotification extends Event
@@ -79,8 +142,8 @@ class EventNotification extends Event
MetaModel::Init_AddAttribute(new AttributeInteger("object_id", array("allowed_values"=>null, "sql"=>"object_id", "default_value"=>0, "is_null_allowed"=>false, "depends_on"=>array())));
// Display lists
MetaModel::Init_SetZListItems('details', array('date', 'userinfo', 'trigger_id', 'action_id', 'object_id')); // Attributes to be displayed for the complete details
MetaModel::Init_SetZListItems('list', array('date', 'userinfo')); // Attributes to be displayed for a list
MetaModel::Init_SetZListItems('details', array('date', 'message', 'userinfo', 'trigger_id', 'action_id', 'object_id')); // Attributes to be displayed for the complete details
MetaModel::Init_SetZListItems('list', array('date', 'message')); // 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
@@ -111,11 +174,11 @@ 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
MetaModel::Init_SetZListItems('list', array('date', 'userinfo', 'message', 'to', 'subject')); // Attributes to be displayed for a list
MetaModel::Init_SetZListItems('list', array('date', 'message', 'to', 'subject')); // Attributes to be displayed for a list
// Search criteria
// MetaModel::Init_SetZListItems('standard_search', array('name')); // Criteria of the std search form
@@ -258,4 +321,43 @@ class EventWebService extends Event
}
}
class EventLoginUsage extends Event
{
public static function Init()
{
$aParams = array
(
"category" => "core/cmdb,view_in_gui",
"key_type" => "autoincrement",
"name_attcode" => "",
"state_attcode" => "",
"reconc_keys" => array(),
"db_table" => "priv_event_loginusage",
"db_key_field" => "id",
"db_finalclass_field" => "",
);
MetaModel::Init_Params($aParams);
MetaModel::Init_InheritAttributes();
MetaModel::Init_AddAttribute(new AttributeExternalKey("user_id", array("targetclass"=>"User", "jointype"=> "", "allowed_values"=>null, "sql"=>"user_id", "is_null_allowed"=>false, "on_target_delete"=>DEL_MANUAL, "depends_on"=>array())));
$aZList = array('date', 'user_id');
if (MetaModel::IsValidAttCode('Contact', 'name'))
{
MetaModel::Init_AddAttribute(new AttributeExternalField("contact_name", array("allowed_values"=>null, "extkey_attcode"=>"user_id", "target_attcode"=>"contactid", "is_null_allowed"=>true, "depends_on"=>array())));
$aZList[] = 'contact_name';
}
if (MetaModel::IsValidAttCode('Contact', 'email'))
{
MetaModel::Init_AddAttribute(new AttributeExternalField("contact_email", array("allowed_values"=>null, "extkey_attcode"=>"user_id", "target_attcode"=>"email", "is_null_allowed"=>true, "depends_on"=>array())));
$aZList[] = 'contact_email';
}
// Display lists
MetaModel::Init_SetZListItems('details', array_merge($aZList, array('userinfo', 'message'))); // Attributes to be displayed for the complete details
MetaModel::Init_SetZListItems('list', array_merge($aZList, array('userinfo'))); // Attributes to be displayed for a list
// Search criteria
MetaModel::Init_SetZListItems('standard_search', $aZList); // Criteria of the std search form
// MetaModel::Init_SetZListItems('advanced_search', array('name')); // Criteria of the advanced search form
}
}
?>

View File

@@ -30,16 +30,22 @@ class MissingQueryArgument extends CoreException
abstract class Expression
{
// recursive translation of identifiers
abstract public function Translate($aTranslationData, $bMatchAll = true);
abstract public function GetUnresolvedFields($sAlias, &$aUnresolved);
abstract public function Translate($aTranslationData, $bMatchAll = true, $bMarkFieldsAsResolved = true);
// 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 !
@@ -66,6 +72,12 @@ abstract class Expression
return $oExpression;
}
static public function FromSQL($sSQL)
{
$oSql = new SQLExpression($sSQL);
return $oSql;
}
public function LogAnd($oExpr)
{
if ($this->IsTrue()) return clone $oExpr;
@@ -77,8 +89,60 @@ abstract class Expression
{
return new BinaryExpression($this, 'OR', $oExpr);
}
abstract public function RenameParam($sOldName, $sNewName);
}
class SQLExpression extends Expression
{
protected $m_sSQL;
public function __construct($sSQL)
{
$this->m_sSQL = $sSQL;
}
public function IsTrue()
{
return false;
}
// recursive rendering
public function Render(&$aArgs = null, $bRetrofitParams = false)
{
return $this->m_sSQL;
}
public function ApplyParameters($aArgs)
{
}
public function GetUnresolvedFields($sAlias, &$aUnresolved)
{
}
public function Translate($aTranslationData, $bMatchAll = true, $bMarkFieldsAsResolved = true)
{
return clone $this;
}
public function ListRequiredFields()
{
return array();
}
public function ListConstantFields()
{
return array();
}
public function RenameParam($sOldName, $sNewName)
{
// Do nothing, since there is nothing to rename
}
}
class BinaryExpression extends Expression
{
@@ -114,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;
@@ -142,11 +206,37 @@ class BinaryExpression extends Expression
$sRight = $this->GetRightExpr()->Render($aArgs, $bRetrofitParams);
return "($sLeft $sOperator $sRight)";
}
public function Translate($aTranslationData, $bMatchAll = true)
public function ApplyParameters($aArgs)
{
$oLeft = $this->GetLeftExpr()->Translate($aTranslationData, $bMatchAll);
$oRight = $this->GetRightExpr()->Translate($aTranslationData, $bMatchAll);
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);
$this->GetRightExpr()->GetUnresolvedFields($sAlias, $aUnresolved);
}
public function Translate($aTranslationData, $bMatchAll = true, $bMarkFieldsAsResolved = true)
{
$oLeft = $this->GetLeftExpr()->Translate($aTranslationData, $bMatchAll, $bMarkFieldsAsResolved);
$oRight = $this->GetRightExpr()->Translate($aTranslationData, $bMatchAll, $bMarkFieldsAsResolved);
return new BinaryExpression($oLeft, $this->GetOperator(), $oRight);
}
@@ -156,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);
}
}
@@ -182,19 +316,18 @@ 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 Translate($aTranslationData, $bMatchAll = true)
public function ApplyParameters($aArgs)
{
}
public function GetUnresolvedFields($sAlias, &$aUnresolved)
{
}
public function Translate($aTranslationData, $bMatchAll = true, $bMarkFieldsAsResolved = true)
{
return clone $this;
}
@@ -203,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
@@ -275,7 +419,21 @@ class FieldExpression extends UnaryExpression
return "`{$this->m_sParent}`.`{$this->m_sName}`";
}
public function Translate($aTranslationData, $bMatchAll = true)
public function ListRequiredFields()
{
return array($this->m_sParent.'.'.$this->m_sName);
}
public function GetUnresolvedFields($sAlias, &$aUnresolved)
{
if ($this->m_sParent == $sAlias)
{
// Add a reference to the field
$aUnresolved[$this->m_sName] = $this;
}
}
public function Translate($aTranslationData, $bMatchAll = true, $bMarkFieldsAsResolved = true)
{
if (!array_key_exists($this->m_sParent, $aTranslationData))
{
@@ -292,21 +450,35 @@ class FieldExpression extends UnaryExpression
}
$sNewParent = $aTranslationData[$this->m_sParent]['*'];
$sNewName = $this->m_sName;
if ($bMarkFieldsAsResolved)
{
$oRet = new FieldExpressionResolved($sNewName, $sNewParent);
}
else
{
$oRet = new FieldExpression($sNewName, $sNewParent);
}
}
else
{
$sNewParent = $aTranslationData[$this->m_sParent][$this->m_sName][0];
$sNewName = $aTranslationData[$this->m_sParent][$this->m_sName][1];
$oRet = $aTranslationData[$this->m_sParent][$this->m_sName];
}
return new FieldExpression($sNewName, $sNewParent);
}
public function ListRequiredFields()
{
return array($this->m_sParent.'.'.$this->m_sName);
return $oRet;
}
}
// Has been resolved into an SQL expression
class FieldExpressionResolved extends FieldExpression
{
public function GetUnresolvedFields($sAlias, &$aUnresolved)
{
}
public function Translate($aTranslationData, $bMatchAll = true, $bMarkFieldsAsResolved = true)
{
return clone $this;
}
}
class VariableExpression extends UnaryExpression
{
@@ -340,7 +512,7 @@ class VariableExpression extends UnaryExpression
}
elseif ($bRetrofitParams)
{
//$aArgs[$this->m_sName] = null;
$aArgs[$this->m_sName] = null;
return ':'.$this->m_sName;
}
else
@@ -348,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!
@@ -393,12 +587,36 @@ class ListExpression extends Expression
return '('.implode(', ', $aRes).')';
}
public function Translate($aTranslationData, $bMatchAll = true)
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)
{
$oExpr->GetUnresolvedFields($sAlias, $aUnresolved);
}
}
public function Translate($aTranslationData, $bMatchAll = true, $bMarkFieldsAsResolved = true)
{
$aRes = array();
foreach ($this->m_aExpressions as $oExpr)
{
$aRes[] = $oExpr->Translate($aTranslationData, $bMatchAll);
$aRes[] = $oExpr->Translate($aTranslationData, $bMatchAll, $bMarkFieldsAsResolved);
}
return new ListExpression($aRes);
}
@@ -412,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);
}
}
}
@@ -453,12 +690,36 @@ class FunctionExpression extends Expression
return $this->m_sVerb.'('.implode(', ', $aRes).')';
}
public function Translate($aTranslationData, $bMatchAll = true)
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)
{
$oExpr->GetUnresolvedFields($sAlias, $aUnresolved);
}
}
public function Translate($aTranslationData, $bMatchAll = true, $bMarkFieldsAsResolved = true)
{
$aRes = array();
foreach ($this->m_aArgs as $oExpr)
{
$aRes[] = $oExpr->Translate($aTranslationData, $bMatchAll);
$aRes[] = $oExpr->Translate($aTranslationData, $bMatchAll, $bMarkFieldsAsResolved);
}
return new FunctionExpression($this->m_sVerb, $aRes);
}
@@ -472,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
@@ -507,15 +786,42 @@ class IntervalExpression extends Expression
return 'INTERVAL '.$this->m_oValue->Render($aArgs, $bRetrofitParams).' '.$this->m_sUnit;
}
public function Translate($aTranslationData, $bMatchAll = true)
public function ApplyParameters($aArgs)
{
return new IntervalExpression($this->m_oValue->Translate($aTranslationData, $bMatchAll), $this->m_sUnit);
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);
}
public function Translate($aTranslationData, $bMatchAll = true, $bMarkFieldsAsResolved = true)
{
return new IntervalExpression($this->m_oValue->Translate($aTranslationData, $bMatchAll, $bMarkFieldsAsResolved), $this->m_sUnit);
}
public function ListRequiredFields()
{
return array();
}
public function ListConstantFields()
{
return array();
}
public function RenameParam($sOldName, $sNewName)
{
$this->m_oValue->RenameParam($sOldName, $sNewName);
}
}
class CharConcatExpression extends Expression
@@ -551,12 +857,36 @@ class CharConcatExpression extends Expression
return "CAST(CONCAT(".implode(', ', $aRes).") AS CHAR)";
}
public function Translate($aTranslationData, $bMatchAll = true)
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)
{
$oExpr->GetUnresolvedFields($sAlias, $aUnresolved);
}
}
public function Translate($aTranslationData, $bMatchAll = true, $bMarkFieldsAsResolved = true)
{
$aRes = array();
foreach ($this->m_aExpressions as $oExpr)
{
$aRes[] = $oExpr->Translate($aTranslationData, $bMatchAll);
$aRes[] = $oExpr->Translate($aTranslationData, $bMatchAll, $bMarkFieldsAsResolved);
}
return new CharConcatExpression($aRes);
}
@@ -570,6 +900,135 @@ 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);
}
}
}
class CharConcatWSExpression extends CharConcatExpression
{
protected $m_separator;
public function __construct($separator, $aExpressions)
{
$this->m_separator = $separator;
parent::__construct($aExpressions);
}
// recursive rendering
public function Render(&$aArgs = null, $bRetrofitParams = false)
{
$aRes = array();
foreach ($this->m_aExpressions as $oExpr)
{
$sCol = $oExpr->Render($aArgs, $bRetrofitParams);
// Concat will be globally NULL if one single argument is null !
$aRes[] = "COALESCE($sCol, '')";
}
$sSep = CMDBSource::Quote($this->m_separator);
return "CAST(CONCAT_WS($sSep, ".implode(', ', $aRes).") AS CHAR)";
}
}
class QueryBuilderExpressions
{
protected $m_oConditionExpr;
protected $m_aSelectExpr;
protected $m_aJoinFields;
public function __construct($oCondition)
{
$this->m_oConditionExpr = $oCondition;
$this->m_aSelectExpr = array();
$this->m_aJoinFields = array();
}
public function GetSelect()
{
return $this->m_aSelectExpr;
}
public function GetCondition()
{
return $this->m_oConditionExpr;
}
public function PopJoinField()
{
return array_pop($this->m_aJoinFields);
}
public function AddSelect($sAttAlias, $oExpression)
{
$this->m_aSelectExpr[$sAttAlias] = $oExpression;
}
//$oConditionTree = $oConditionTree->LogAnd($oFinalClassRestriction);
public function AddCondition($oExpression)
{
$this->m_oConditionExpr = $this->m_oConditionExpr->LogAnd($oExpression);
}
public function PushJoinField($oExpression)
{
array_push($this->m_aJoinFields, $oExpression);
}
public function GetUnresolvedFields($sAlias, &$aUnresolved)
{
$this->m_oConditionExpr->GetUnresolvedFields($sAlias, $aUnresolved);
foreach($this->m_aSelectExpr as $sColAlias => $oExpr)
{
$oExpr->GetUnresolvedFields($sAlias, $aUnresolved);
}
foreach($this->m_aJoinFields as $oExpression)
{
$oExpression->GetUnresolvedFields($sAlias, $aUnresolved);
}
}
public function Translate($aTranslationData, $bMatchAll = true, $bMarkFieldsAsResolved = true)
{
$this->m_oConditionExpr = $this->m_oConditionExpr->Translate($aTranslationData, $bMatchAll, $bMarkFieldsAsResolved);
foreach($this->m_aSelectExpr as $sColAlias => $oExpr)
{
$this->m_aSelectExpr[$sColAlias] = $oExpr->Translate($aTranslationData, $bMatchAll, $bMarkFieldsAsResolved);
}
foreach($this->m_aJoinFields as $index => $oExpression)
{
$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);
}
}
}
?>

View File

@@ -50,6 +50,7 @@ abstract class FilterDefinition
$this->ConsistencyCheck();
}
// Left here for backward compatibility, deprecated in 2.0
public function OverloadParams($aParams)
{
foreach ($aParams as $sParam => $value)
@@ -198,10 +199,10 @@ class FilterFromAttribute extends FilterDefinition
return $oAttDef->GetValuesDef();
}
public function GetAllowedValues($aArgs = array(), $sBeginsWith = '')
public function GetAllowedValues($aArgs = array(), $sContains = '')
{
$oAttDef = $this->Get("refattribute");
return $oAttDef->GetAllowedValues($aArgs, $sBeginsWith);
return $oAttDef->GetAllowedValues($aArgs, $sContains);
}
public function GetOperators()

View File

@@ -191,6 +191,25 @@ 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
{
public function __construct()
{
global $fItopStarted;
$this->m_fStarted = $fItopStarted;
}
}
?>

View File

@@ -1,120 +1,146 @@
<?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
/**
* File logging
*
* @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
*/
class FileLog
{
protected $m_sFile = ''; // log is disabled if this is empty
public function __construct($sFileName = '')
{
$this->m_sFile = $sFileName;
}
public function Error($sText)
{
self::Write("Error | ".$sText);
}
public function Warning($sText)
{
self::Write("Warning | ".$sText);
}
public function Info($sText)
{
self::Write("Info | ".$sText);
}
public function Ok($sText)
{
self::Write("Ok | ".$sText);
}
protected function Write($sText)
{
if (strlen($this->m_sFile) == 0) return;
$hLogFile = @fopen($this->m_sFile, 'a');
if ($hLogFile !== false)
{
$sDate = date('Y-m-d H:i:s');
fwrite($hLogFile, "$sDate | $sText\n");
fclose($hLogFile);
}
}
}
class SetupLog
{
protected static $m_oFileLog;
public static function Enable($sTargetFile)
{
self::$m_oFileLog = new FileLog($sTargetFile);
}
public static function Error($sText)
{
self::$m_oFileLog->Error($sText);
}
public static function Warning($sText)
{
self::$m_oFileLog->Warning($sText);
}
public static function Info($sText)
{
self::$m_oFileLog->Info($sText);
}
public static function Ok($sText)
{
self::$m_oFileLog->Ok($sText);
}
}
class IssueLog
{
protected static $m_oFileLog;
public static function Enable($sTargetFile)
{
self::$m_oFileLog = new FileLog($sTargetFile);
}
public static function Error($sText)
{
self::$m_oFileLog->Error($sText);
}
public static function Warning($sText)
{
self::$m_oFileLog->Warning($sText);
}
public static function Info($sText)
{
self::$m_oFileLog->Info($sText);
}
public static function Ok($sText)
{
self::$m_oFileLog->Ok($sText);
}
}
?>
<?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
/**
* File logging
*
* @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
*/
class FileLog
{
protected $m_sFile = ''; // log is disabled if this is empty
public function __construct($sFileName = '')
{
$this->m_sFile = $sFileName;
}
public function Error($sText)
{
self::Write("Error | ".$sText);
}
public function Warning($sText)
{
self::Write("Warning | ".$sText);
}
public function Info($sText)
{
self::Write("Info | ".$sText);
}
public function Ok($sText)
{
self::Write("Ok | ".$sText);
}
protected function Write($sText)
{
if (strlen($this->m_sFile) == 0) return;
$hLogFile = @fopen($this->m_sFile, 'a');
if ($hLogFile !== false)
{
$sDate = date('Y-m-d H:i:s');
fwrite($hLogFile, "$sDate | $sText\n");
fclose($hLogFile);
}
}
}
class SetupLog
{
protected static $m_oFileLog;
public static function Enable($sTargetFile)
{
self::$m_oFileLog = new FileLog($sTargetFile);
}
public static function Error($sText)
{
self::$m_oFileLog->Error($sText);
}
public static function Warning($sText)
{
self::$m_oFileLog->Warning($sText);
}
public static function Info($sText)
{
self::$m_oFileLog->Info($sText);
}
public static function Ok($sText)
{
self::$m_oFileLog->Ok($sText);
}
}
class IssueLog
{
protected static $m_oFileLog;
public static function Enable($sTargetFile)
{
self::$m_oFileLog = new FileLog($sTargetFile);
}
public static function Error($sText)
{
self::$m_oFileLog->Error($sText);
}
public static function Warning($sText)
{
self::$m_oFileLog->Warning($sText);
}
public static function Info($sText)
{
self::$m_oFileLog->Info($sText);
}
public static function Ok($sText)
{
self::$m_oFileLog->Ok($sText);
}
}
class ToolsLog
{
protected static $m_oFileLog;
public static function Enable($sTargetFile)
{
self::$m_oFileLog = new FileLog($sTargetFile);
}
public static function Error($sText)
{
self::$m_oFileLog->Error($sText);
}
public static function Warning($sText)
{
self::$m_oFileLog->Warning($sText);
}
public static function Info($sText)
{
self::$m_oFileLog->Info($sText);
}
public static function Ok($sText)
{
self::$m_oFileLog->Ok($sText);
}
}
?>

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,31 @@
<?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
/**
* Any extension to hook the initialization of the metamodel
*
* @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
*/
interface iOnClassInitialization
{
public function OnAfterClassInitialization($sClass);
}
?>

View File

@@ -0,0 +1,37 @@
<?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
/**
* Class ModuleHandler
* Defines the API to implement module specific actions during page execution
*
* @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 ModuleHandlerAPI
{
public static function OnMetaModelStarted()
{
}
public static function OnMenuCreation()
{
}
}
?>

4
core/oql/build.bash Executable file
View 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

View File

@@ -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

View File

@@ -1,5 +1,29 @@
<?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
/**
* OQL syntax analyzer, to be used prior to run the lexical analyzer
*
* @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
*/
// Notes (from the source file: oql-lexer.plex) - Romain
//
// The strval rule is a little bit cryptic.
@@ -80,153 +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/',
'/^,/',
'/^\\(/',
'/^\\)/',
'/^=/',
'/^!=/',
'/^>/',
'/^</',
'/^>=/',
'/^<=/',
'/^LIKE/',
'/^NOT LIKE/',
'/^IN/',
'/^NOT IN/',
'/^INTERVAL/',
'/^IF/',
'/^ELT/',
'/^COALESCE/',
'/^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
@@ -314,204 +348,254 @@ class OQLLexerRaw
function yy_r1_16($yy_subpatterns)
{
$this->token = OQLParser::EQ;
$this->token = OQLParser::REGEXP;
}
function yy_r1_17($yy_subpatterns)
{
$this->token = OQLParser::NOT_EQ;
$this->token = OQLParser::EQ;
}
function yy_r1_18($yy_subpatterns)
{
$this->token = OQLParser::GT;
$this->token = OQLParser::NOT_EQ;
}
function yy_r1_19($yy_subpatterns)
{
$this->token = OQLParser::LT;
$this->token = OQLParser::GT;
}
function yy_r1_20($yy_subpatterns)
{
$this->token = OQLParser::GE;
$this->token = OQLParser::LT;
}
function yy_r1_21($yy_subpatterns)
{
$this->token = OQLParser::LE;
$this->token = OQLParser::GE;
}
function yy_r1_22($yy_subpatterns)
{
$this->token = OQLParser::LIKE;
$this->token = OQLParser::LE;
}
function yy_r1_23($yy_subpatterns)
{
$this->token = OQLParser::NOT_LIKE;
$this->token = OQLParser::LIKE;
}
function yy_r1_24($yy_subpatterns)
{
$this->token = OQLParser::IN;
$this->token = OQLParser::NOT_LIKE;
}
function yy_r1_25($yy_subpatterns)
{
$this->token = OQLParser::NOT_IN;
$this->token = OQLParser::IN;
}
function yy_r1_26($yy_subpatterns)
{
$this->token = OQLParser::INTERVAL;
$this->token = OQLParser::NOT_IN;
}
function yy_r1_27($yy_subpatterns)
{
$this->token = OQLParser::F_IF;
$this->token = OQLParser::INTERVAL;
}
function yy_r1_28($yy_subpatterns)
{
$this->token = OQLParser::F_ELT;
$this->token = OQLParser::F_IF;
}
function yy_r1_29($yy_subpatterns)
{
$this->token = OQLParser::F_COALESCE;
$this->token = OQLParser::F_ELT;
}
function yy_r1_30($yy_subpatterns)
{
$this->token = OQLParser::F_CONCAT;
$this->token = OQLParser::F_COALESCE;
}
function yy_r1_31($yy_subpatterns)
{
$this->token = OQLParser::F_SUBSTR;
$this->token = OQLParser::F_ISNULL;
}
function yy_r1_32($yy_subpatterns)
{
$this->token = OQLParser::F_TRIM;
$this->token = OQLParser::F_CONCAT;
}
function yy_r1_33($yy_subpatterns)
{
$this->token = OQLParser::F_DATE;
$this->token = OQLParser::F_SUBSTR;
}
function yy_r1_34($yy_subpatterns)
{
$this->token = OQLParser::F_DATE_FORMAT;
$this->token = OQLParser::F_TRIM;
}
function yy_r1_35($yy_subpatterns)
{
$this->token = OQLParser::F_CURRENT_DATE;
$this->token = OQLParser::F_DATE;
}
function yy_r1_36($yy_subpatterns)
{
$this->token = OQLParser::F_NOW;
$this->token = OQLParser::F_DATE_FORMAT;
}
function yy_r1_37($yy_subpatterns)
{
$this->token = OQLParser::F_TIME;
$this->token = OQLParser::F_CURRENT_DATE;
}
function yy_r1_38($yy_subpatterns)
{
$this->token = OQLParser::F_TO_DAYS;
$this->token = OQLParser::F_NOW;
}
function yy_r1_39($yy_subpatterns)
{
$this->token = OQLParser::F_FROM_DAYS;
$this->token = OQLParser::F_TIME;
}
function yy_r1_40($yy_subpatterns)
{
$this->token = OQLParser::F_YEAR;
$this->token = OQLParser::F_TO_DAYS;
}
function yy_r1_41($yy_subpatterns)
{
$this->token = OQLParser::F_MONTH;
$this->token = OQLParser::F_FROM_DAYS;
}
function yy_r1_42($yy_subpatterns)
{
$this->token = OQLParser::F_DAY;
$this->token = OQLParser::F_YEAR;
}
function yy_r1_43($yy_subpatterns)
{
$this->token = OQLParser::F_HOUR;
$this->token = OQLParser::F_MONTH;
}
function yy_r1_44($yy_subpatterns)
{
$this->token = OQLParser::F_MINUTE;
$this->token = OQLParser::F_DAY;
}
function yy_r1_45($yy_subpatterns)
{
$this->token = OQLParser::F_SECOND;
$this->token = OQLParser::F_HOUR;
}
function yy_r1_46($yy_subpatterns)
{
$this->token = OQLParser::F_DATE_ADD;
$this->token = OQLParser::F_MINUTE;
}
function yy_r1_47($yy_subpatterns)
{
$this->token = OQLParser::F_DATE_SUB;
$this->token = OQLParser::F_SECOND;
}
function yy_r1_48($yy_subpatterns)
{
$this->token = OQLParser::F_ROUND;
$this->token = OQLParser::F_DATE_ADD;
}
function yy_r1_49($yy_subpatterns)
{
$this->token = OQLParser::F_FLOOR;
$this->token = OQLParser::F_DATE_SUB;
}
function yy_r1_50($yy_subpatterns)
{
$this->token = OQLParser::F_INET_ATON;
$this->token = OQLParser::F_ROUND;
}
function yy_r1_51($yy_subpatterns)
{
$this->token = OQLParser::F_INET_NTOA;
$this->token = OQLParser::F_FLOOR;
}
function yy_r1_52($yy_subpatterns)
{
$this->token = OQLParser::NUMVAL;
$this->token = OQLParser::F_INET_ATON;
}
function yy_r1_53($yy_subpatterns)
{
$this->token = OQLParser::STRVAL;
$this->token = OQLParser::F_INET_NTOA;
}
function yy_r1_54($yy_subpatterns)
{
$this->token = OQLParser::NAME;
$this->token = OQLParser::BELOW;
}
function yy_r1_55($yy_subpatterns)
{
$this->token = OQLParser::VARNAME;
$this->token = OQLParser::BELOW_STRICT;
}
function yy_r1_56($yy_subpatterns)
{
$this->token = OQLParser::NOT_BELOW;
}
function yy_r1_57($yy_subpatterns)
{
$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;

View File

@@ -94,6 +94,7 @@ math_plus = "+"
math_minus = "-"
log_and = "AND"
log_or = "OR"
regexp = "REGEXP"
eq = "="
not_eq = "!="
gt = ">"
@@ -108,6 +109,7 @@ interval = "INTERVAL"
f_if = "IF"
f_elt = "ELT"
f_coalesce = "COALESCE"
f_isnull = "ISNULL"
f_concat = "CONCAT"
f_substr = "SUBSTR"
f_trim = "TRIM"
@@ -130,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]*)/
@@ -186,6 +212,9 @@ par_open {
par_close {
$this->token = OQLParser::PAR_CLOSE;
}
regexp {
$this->token = OQLParser::REGEXP;
}
eq {
$this->token = OQLParser::EQ;
}
@@ -228,6 +257,9 @@ f_elt {
f_coalesce {
$this->token = OQLParser::F_COALESCE;
}
f_isnull {
$this->token = OQLParser::F_ISNULL;
}
f_concat {
$this->token = OQLParser::F_CONCAT;
}
@@ -294,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;
}

File diff suppressed because it is too large Load Diff

View File

@@ -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; }
@@ -101,13 +109,13 @@ expression_prio4(A) ::= expression_prio3(X). { A = X; }
expression_prio4(A) ::= expression_prio4(X) operator4(Y) expression_prio3(Z). { A = new BinaryOqlExpression(X, Y, Z); }
list(A) ::= PAR_OPEN scalar_list(X) PAR_CLOSE. {
list(A) ::= PAR_OPEN list_items(X) PAR_CLOSE. {
A = new ListOqlExpression(X);
}
scalar_list(A) ::= scalar(X). {
list_items(A) ::= expression_prio4(X). {
A = array(X);
}
scalar_list(A) ::= scalar_list(L) COMA scalar(X). {
list_items(A) ::= list_items(L) COMA expression_prio4(X). {
array_push(L, X);
A = L;
}
@@ -164,6 +172,7 @@ str_value(A) ::= STRVAL(X). {A=stripslashes(substr(X, 1, strlen(X) - 2));}
operator1(A) ::= num_operator1(X). {A=X;}
operator2(A) ::= num_operator2(X). {A=X;}
operator2(A) ::= str_operator(X). {A=X;}
operator2(A) ::= REGEXP(X). {A=X;}
operator2(A) ::= EQ(X). {A=X;}
operator2(A) ::= NOT_EQ(X). {A=X;}
operator3(A) ::= LOG_AND(X). {A=X;}
@@ -187,6 +196,7 @@ list_operator(A) ::= NOT_IN(X). {A=X;}
func_name(A) ::= F_IF(X). { A=X; }
func_name(A) ::= F_ELT(X). { A=X; }
func_name(A) ::= F_COALESCE(X). { A=X; }
func_name(A) ::= F_ISNULL(X). { A=X; }
func_name(A) ::= F_CONCAT(X). { A=X; }
func_name(A) ::= F_SUBSTR(X). { A=X; }
func_name(A) ::= F_TRIM(X). { A=X; }

View File

@@ -52,19 +52,19 @@ class OQLException extends CoreException
public function getHtmlDesc($sHighlightHtmlBegin = '<b>', $sHighlightHtmlEnd = '</b>')
{
$sRet = htmlentities($this->m_MyIssue.", found '".$this->m_sUnexpected."' in: ");
$sRet .= htmlentities(substr($this->m_sInput, 0, $this->m_iCol));
$sRet .= $sHighlightHtmlBegin.htmlentities(substr($this->m_sInput, $this->m_iCol, strlen($this->m_sUnexpected))).$sHighlightHtmlEnd;
$sRet .= htmlentities(substr($this->m_sInput, $this->m_iCol + strlen($this->m_sUnexpected)));
$sRet = htmlentities($this->m_MyIssue.", found '".$this->m_sUnexpected."' in: ", ENT_QUOTES, 'UTF-8');
$sRet .= htmlentities(substr($this->m_sInput, 0, $this->m_iCol), ENT_QUOTES, 'UTF-8');
$sRet .= $sHighlightHtmlBegin.htmlentities(substr($this->m_sInput, $this->m_iCol, strlen($this->m_sUnexpected)), ENT_QUOTES, 'UTF-8').$sHighlightHtmlEnd;
$sRet .= htmlentities(substr($this->m_sInput, $this->m_iCol + strlen($this->m_sUnexpected)), ENT_QUOTES, 'UTF-8');
if (!is_null($this->m_aExpecting) && (count($this->m_aExpecting) > 0))
{
$sExpectations = '{'.implode(', ', $this->m_aExpecting).'}';
$sRet .= ", expecting ".htmlentities($sExpectations);
$sRet .= ", expecting ".htmlentities($sExpectations, ENT_QUOTES, 'UTF-8');
$sSuggest = self::FindClosestString($this->m_sUnexpected, $this->m_aExpecting);
if (strlen($sSuggest) > 0)
{
$sRet .= ", I would suggest to use '$sHighlightHtmlBegin".htmlentities($sSuggest)."$sHighlightHtmlEnd'";
$sRet .= ", I would suggest to use '$sHighlightHtmlBegin".htmlentities($sSuggest, ENT_QUOTES, 'UTF-8')."$sHighlightHtmlEnd'";
}
}

View File

@@ -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

View File

@@ -0,0 +1,203 @@
<?php
// Copyright (C) 2011 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
define('CASELOG_VISIBLE_ITEMS', 2);
define('CASELOG_SEPARATOR', "\n".'========== %1$s : %2$s (%3$d) ============'."\n\n");
//require_once(APPROOT.'/core/userrights.class.inc.php');
//require_once(APPROOT.'/application/webpage.class.inc.php');
/**
* Class to store a "case log" in a structured way, keeping track of its successive entries
*/
class ormCaseLog {
protected $m_sLog;
protected $m_aIndex;
/**
* Initializes the log with the first (initial) entry
* @param $sLog string The text of the whole case log
* @param $aIndex hash The case log index
*/
public function __construct($sLog = '', $aIndex = array())
{
$this->m_sLog = $sLog;
$this->m_aIndex = $aIndex;
}
public function GetText()
{
return $this->m_sLog;
}
public function GetIndex()
{
return $this->m_aIndex;
}
public function __toString()
{
return $this->m_sLog;
}
public function GetAsHTML(WebPage $oP = null, $bEditMode = false, $aTransfoHandler = null)
{
$sHtml = '<table style="width:100%;table-layout:fixed"><tr><td>'; // Use table-layout:fixed to force the with to be independent from the actual content
$iPos = 0;
for($index=count($this->m_aIndex)-1 ; $index >= 0 ; $index--)
{
if ($index < count($this->m_aIndex) - CASELOG_VISIBLE_ITEMS)
{
$sOpen = '';
$sDisplay = 'style="display:none;"';
}
else
{
$sOpen = ' open';
$sDisplay = '';
}
$iPos += $this->m_aIndex[$index]['separator_length'];
$sTextEntry = substr($this->m_sLog, $iPos, $this->m_aIndex[$index]['text_length']);
$sTextEntry = str_replace(array("\r\n", "\n", "\r"), "<br/>", htmlentities($sTextEntry, ENT_QUOTES, 'UTF-8'));
if (!is_null($aTransfoHandler))
{
$sTextEntry = call_user_func($aTransfoHandler, $sTextEntry);
}
$iPos += $this->m_aIndex[$index]['text_length'];
$sEntry = '<div class="caselog_header'.$sOpen.'">';
// 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;
$sEntry .= '</div>';
$sHtml = $sHtml.$sEntry;
}
// Process the case of an eventual remainder (quick migration of AttributeText fields)
if ($iPos < (strlen($this->m_sLog) - 1))
{
$sTextEntry = substr($this->m_sLog, $iPos);
$sTextEntry = str_replace(array("\r\n", "\n", "\r"), "<br/>", htmlentities($sTextEntry, ENT_QUOTES, 'UTF-8'));
if (!is_null($aTransfoHandler))
{
$sTextEntry = call_user_func($aTransfoHandler, $sTextEntry);
}
if (count($this->m_aIndex) == 0)
{
$sHtml .= '<div class="caselog_entry open">';
$sHtml .= $sTextEntry;
$sHtml .= '</div>';
}
else
{
if (count($this->m_aIndex) - CASELOG_VISIBLE_ITEMS > 0)
{
$sOpen = '';
$sDisplay = 'style="display:none;"';
}
else
{
$sOpen = ' open';
$sDisplay = '';
}
$sHtml .= '<div class="caselog_header'.$sOpen.'">';
$sHtml .= Dict::S('UI:CaseLog:InitialValue');
$sHtml .= '</div>';
$sHtml .= '<div class="caselog_entry"'.$sDisplay.'>';
$sHtml .= $sTextEntry;
$sHtml .= '</div>';
}
}
$sHtml .= '</td></tr></table>';
return $sHtml;
}
/**
* 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, $sOnBehalfOf = '')
{
$sDate = date(Dict::S('UI:CaseLog:DateFormat'));
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' => $sOnBehalfOf,
'user_id' => $iUserId,
'date' => time(),
'text_length' => $iTextlength,
'separator_length' => $iSepLength,
);
}
/**
* Get the latest entry from the log
* @return string
*/
public function GetLatestEntry()
{
$aLastEntry = end($this->m_aIndex);
$sRes = substr($this->m_sLog, $aLastEntry['separator_length'], $aLastEntry['text_length']);
return $sRes;
}
/**
* Get the index of the latest entry from the log
* @return integer
*/
public function GetLatestEntryIndex()
{
$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;
}
}
?>

View File

@@ -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";
}
}
?>

View File

@@ -14,7 +14,7 @@
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
require_once('../core/simplecrypt.class.inc.php');
require_once(APPROOT.'/core/simplecrypt.class.inc.php');
/**
* ormPassword

View File

@@ -0,0 +1,74 @@
<?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
/**
* Associated with the metamodel -> MakeQuery/MakeQuerySingleTable
*
* @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
*/
class QueryBuilderContext
{
protected $m_oRootFilter;
protected $m_aClassAliases;
protected $m_aTableAliases;
protected $m_aModifierProperties;
public $m_oQBExpressions;
public function __construct($oFilter, $aModifierProperties)
{
$this->m_oRootFilter = $oFilter;
$this->m_oQBExpressions = new QueryBuilderExpressions($oFilter->GetCriteria());
$this->m_aClassAliases = $oFilter->GetJoinedClasses();
$this->m_aTableAliases = array();
$this->m_aModifierProperties = $aModifierProperties;
}
public function GetRootFilter()
{
return $this->m_oRootFilter;
}
public function GenerateTableAlias($sNewName, $sRealName)
{
return MetaModel::GenerateUniqueAlias($this->m_aTableAliases, $sNewName, $sRealName);
}
public function GenerateClassAlias($sNewName, $sRealName)
{
return MetaModel::GenerateUniqueAlias($this->m_aClassAliases, $sNewName, $sRealName);
}
public function GetModifierProperties($sPluginClass)
{
if (array_key_exists($sPluginClass, $this->m_aModifierProperties))
{
return $this->m_aModifierProperties[$sPluginClass];
}
else
{
return array();
}
}
}
?>

View File

@@ -0,0 +1,33 @@
<?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
/**
* Interface iQueryModifier
* Defines the API to tweak queries (e.g. translate data on the fly)
*
* @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
*/
interface iQueryModifier
{
public function __construct();
public function GetFieldExpression(QueryBuilderContext &$oBuild, $sClass, $sAttCode, $sColId, Expression $oFieldSQLExp, SQLQuery &$oSelect);
}
?>

View File

@@ -35,36 +35,19 @@
require_once('cmdbsource.class.inc.php');
class SQLExpression extends BinaryExpression
{
}
class ScalarSQLExpression extends ScalarExpression
{
}
class TrueSQLExpression extends TrueExpression
{
}
class FieldSQLExpression extends FieldExpression
{
}
class VariableSQLExpression extends VariableExpression
{
}
class SQLQuery
{
private $m_SourceOQL = '';
private $m_sTable = '';
private $m_sTableAlias = '';
private $m_aFields = array();
private $m_oConditionExpr = null;
private $m_aFullTextNeedles = array();
private $m_bToDelete = true; // The current table must be listed for deletion ?
private $m_aValues = array(); // Values to set in case of an update query
private $m_oSelectedIdField = null;
private $m_aJoinSelects = array();
public function __construct($sTable, $sTableAlias, $aFields, $oConditionExpr, $aFullTextNeedles, $bToDelete = true, $aValues = array())
public function __construct($sTable, $sTableAlias, $aFields, $bToDelete = true, $aValues = array(), $oSelectedIdField = null)
{
// This check is not needed but for developping purposes
//if (!CMDBSource::IsTable($sTable))
@@ -79,18 +62,25 @@ class SQLQuery
$this->m_sTable = $sTable;
$this->m_sTableAlias = $sTableAlias;
$this->m_aFields = $aFields;
$this->m_oConditionExpr = $oConditionExpr;
if (is_null($oConditionExpr))
{
$this->m_oConditionExpr = new TrueExpression;
}
else if (!$oConditionExpr instanceof Expression)
{
throw new CoreException('Invalid type for condition, expecting an Expression', array('class' => get_class($oConditionExpr)));
}
$this->m_aFullTextNeedles = $aFullTextNeedles;
$this->m_oConditionExpr = null;
$this->m_bToDelete = $bToDelete;
$this->m_aValues = $aValues;
$this->m_oSelectedIdField = $oSelectedIdField;
}
public function GetTableAlias()
{
return $this->m_sTableAlias;
}
public function SetSourceOQL($sOQL)
{
$this->m_SourceOQL = $sOQL;
}
public function GetSourceOQL()
{
return $this->m_SourceOQL;
}
public function DisplayHtml()
@@ -108,16 +98,6 @@ class SQLQuery
echo "<b>$this->m_sTable</b>$sFields<br/>\n";
// #@# todo - display html of an expression tree
//$this->m_oConditionExpr->DisplayHtml()
if (count($this->m_aFullTextNeedles) > 0)
{
echo "Full text criteria...<br/>\n";
echo "<ul class=\"treeview\">\n";
foreach ($this->m_aFullTextNeedles as $sFTNeedle)
{
echo "<li>$sFTNeedle</li>\n";
}
echo "</ul>";
}
if (count($this->m_aJoinSelects) > 0)
{
echo "Joined to...<br/>\n";
@@ -126,11 +106,20 @@ class SQLQuery
{
$sJoinType = $aJoinInfo["jointype"];
$oSQLQuery = $aJoinInfo["select"];
$sLeftField = $aJoinInfo["leftfield"];
$sRightField = $aJoinInfo["rightfield"];
$sRightTableAlias = $aJoinInfo["righttablealias"];
if (isset($aJoinInfo["on_expression"]))
{
$sOnCondition = $aJoinInfo["on_expression"]->Render();
echo "<li>Join '$sJoinType', $sLeftField, $sRightTableAlias.$sRightField".$oSQLQuery->DisplayHtml()."</li>\n";
echo "<li>Join '$sJoinType', ON ($sOnCondition)".$oSQLQuery->DisplayHtml()."</li>\n";
}
else
{
$sLeftField = $aJoinInfo["leftfield"];
$sRightField = $aJoinInfo["rightfield"];
$sRightTableAlias = $aJoinInfo["righttablealias"];
echo "<li>Join '$sJoinType', $sLeftField, $sRightTableAlias.$sRightField".$oSQLQuery->DisplayHtml()."</li>\n";
}
}
echo "</ul>";
}
@@ -139,13 +128,19 @@ class SQLQuery
$oCondition = null;
$aDelTables = array();
$aSetValues = array();
$this->privRender($aFrom, $aFields, $oCondition, $aDelTables, $aSetValues);
$aSelectedIdFields = array();
$this->privRender($aFrom, $aFields, $oCondition, $aDelTables, $aSetValues, $aSelectedIdFields);
echo "From ...<br/>\n";
echo "<pre style=\"font-size: smaller;\">\n";
print_r($aFrom);
echo "</pre>";
}
public function SetSelect($aExpressions)
{
$this->m_aFields = $aExpressions;
}
public function SetCondition($oConditionExpr)
{
$this->m_oConditionExpr = $oConditionExpr;
@@ -153,7 +148,14 @@ class SQLQuery
public function AddCondition($oConditionExpr)
{
$this->m_oConditionExpr->LogAnd($oConditionExpr);
if (is_null($this->m_oConditionExpr))
{
$this->m_oConditionExpr = $oConditionExpr;
}
else
{
$this->m_oConditionExpr->LogAnd($oConditionExpr);
}
}
private function AddJoin($sJoinType, $oSQLQuery, $sLeftField, $sRightField, $sRightTableAlias = '')
@@ -175,7 +177,6 @@ class SQLQuery
// {
// throw new CoreException("Unknown field '$sRightField' in table '".$sRightTable."'");
// }
$this->m_aJoinSelects[] = array(
"jointype" => $sJoinType,
"select" => $oSQLQuery,
@@ -184,14 +185,49 @@ 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)
{
return $this->AddJoin("left", $oSQLQuery, $sLeftField, $sRightField);
}
public function AddInnerJoinEx(SQLQuery $oSQLQuery, Expression $oOnExpression)
{
$this->m_aJoinSelects[] = array(
"jointype" => 'inner',
"select" => $oSQLQuery,
"on_expression" => $oOnExpression
);
}
public function AddLeftJoinEx(SQLQuery $oSQLQuery, Expression $oOnExpression)
{
$this->m_aJoinSelects[] = array(
"jointype" => 'left',
"select" => $oSQLQuery,
"on_expression" => $oOnExpression
);
}
// Interface, build the SQL query
public function RenderDelete($aArgs = array())
@@ -202,7 +238,8 @@ class SQLQuery
$oCondition = null;
$aDelTables = array();
$aSetValues = array();
$this->privRender($aFrom, $aFields, $oCondition, $aDelTables, $aSetValues);
$aSelectedIdFields = array();
$this->privRender($aFrom, $aFields, $oCondition, $aDelTables, $aSetValues, $aSelectedIdFields);
// Target: DELETE myAlias1, myAlias2 FROM t1 as myAlias1, t2 as myAlias2, t3 as topreserve WHERE ...
@@ -216,8 +253,15 @@ class SQLQuery
throw new CoreException("Building a request wich will delete every object of a given table -looks suspicious- please use truncate instead...");
}
*/
$sWhere = self::ClauseWhere($oCondition, $aArgs);
return "DELETE $sDelete FROM $sFrom WHERE $sWhere";
if (is_null($oCondition))
{
// Delete all !!!
}
else
{
$sWhere = self::ClauseWhere($oCondition, $aArgs);
return "DELETE $sDelete FROM $sFrom WHERE $sWhere";
}
}
// Interface, build the SQL query
@@ -229,8 +273,8 @@ class SQLQuery
$oCondition = null;
$aDelTables = array();
$aSetValues = array();
$this->privRender($aFrom, $aFields, $oCondition, $aDelTables, $aSetValues);
$aSelectedIdFields = array();
$this->privRender($aFrom, $aFields, $oCondition, $aDelTables, $aSetValues, $aSelectedIdFields);
$sFrom = self::ClauseFrom($aFrom);
$sValues = self::ClauseValues($aSetValues);
$sWhere = self::ClauseWhere($oCondition, $aArgs);
@@ -246,13 +290,22 @@ class SQLQuery
$oCondition = null;
$aDelTables = array();
$aSetValues = array();
$this->privRender($aFrom, $aFields, $oCondition, $aDelTables, $aSetValues);
$aSelectedIdFields = array();
$this->privRender($aFrom, $aFields, $oCondition, $aDelTables, $aSetValues, $aSelectedIdFields);
$sFrom = self::ClauseFrom($aFrom);
$sWhere = self::ClauseWhere($oCondition, $aArgs);
if ($bGetCount)
{
$sSQL = "SELECT COUNT(*) AS COUNT FROM $sFrom WHERE $sWhere";
if (count($aSelectedIdFields) > 0)
{
$sIDFields = implode(', ', $aSelectedIdFields);
$sSQL = "SELECT COUNT(DISTINCT $sIDFields) AS COUNT FROM $sFrom WHERE $sWhere";
}
else
{
$sSQL = "SELECT COUNT(*) AS COUNT FROM $sFrom WHERE $sWhere";
}
}
else
{
@@ -309,6 +362,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"];
@@ -338,7 +392,14 @@ class SQLQuery
private static function ClauseWhere($oConditionExpr, $aArgs = array())
{
return $oConditionExpr->Render($aArgs);
if (is_null($oConditionExpr))
{
return '1';
}
else
{
return $oConditionExpr->Render($aArgs);
}
}
private static function ClauseOrderBy($aOrderBy)
@@ -353,43 +414,14 @@ class SQLQuery
}
// Purpose: prepare the query data, once for all
private function privRender(&$aFrom, &$aFields, &$oCondition, &$aDelTables, &$aSetValues)
private function privRender(&$aFrom, &$aFields, &$oCondition, &$aDelTables, &$aSetValues, &$aSelectedIdFields)
{
$sTableAlias = $this->privRenderSingleTable($aFrom, $aFields, $aDelTables, $aSetValues);
// Add the full text search condition, based on each and every requested field
//
// To be updated with a real full text search based on the mySQL settings
// (then it might move somewhere else !)
//
$sTableAlias = $this->privRenderSingleTable($aFrom, $aFields, $aDelTables, $aSetValues, $aSelectedIdFields, '', array('jointype' => 'first'));
$oCondition = $this->m_oConditionExpr;
if ((count($aFields) > 0) && (count($this->m_aFullTextNeedles) > 0))
{
$aFieldExp = array();
foreach ($aFields as $sField)
{
// This is TEMPORARY (that's why it is weird, actually)
// Full text match will be done as an expression in the filter condition
// $sField is already a string `table`.`column`
// Let's make an expression out of it (again !)
$aFieldExp[] = Expression::FromOQL($sField);
}
$oFullTextExpr = new CharConcatExpression($aFieldExp);
// The cast is necessary because the CONCAT result in a binary string:
// if any of the field is a binary string => case sensitive comparison
//
foreach($this->m_aFullTextNeedles as $sFTNeedle)
{
$oNewCond = new BinaryExpression($oFullTextExpr, 'LIKE', new ScalarExpression("%$sFTNeedle%"));
$oCondition = $oCondition->LogAnd($oNewCond);
}
}
return $sTableAlias;
}
private function privRenderSingleTable(&$aFrom, &$aFields, &$aDelTables, &$aSetValues, $sJoinType = 'first', $sCallerAlias = '', $sLeftField = '', $sRightField = '', $sRightTableAlias = '')
private function privRenderSingleTable(&$aFrom, &$aFields, &$aDelTables, &$aSetValues, &$aSelectedIdFields, $sCallerAlias = '', $aJoinData)
{
$aActualTableFields = CMDBSource::GetTableFieldsList($this->m_sTable);
@@ -397,20 +429,72 @@ 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"=>"");
break;
case "inner":
case "left":
// table or tablealias ???
$aFrom[$this->m_sTableAlias] = array("jointype"=>$sJoinType, "tablename"=>$this->m_sTable, "joincondition"=>"$sJoinCond");
if (isset($aJoinData["on_expression"]))
{
$sJoinCond = $aJoinData["on_expression"]->Render();
}
else
{
$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;
}
@@ -419,31 +503,31 @@ class SQLQuery
//
foreach($this->m_aFields as $sAlias => $oExpression)
{
$sTable = $oExpression->GetParent();
$sColumn = $oExpression->GetName();
$aFields["`$sAlias`"] = $oExpression->Render();
}
if ($this->m_bToDelete)
{
$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!
}
if (!is_null($this->m_oSelectedIdField))
{
$aSelectedIdFields[] = $this->m_oSelectedIdField->Render();
}
// loop on joins, to complete the list of tables/fields/conditions
//
$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"];
$sJoinTableAlias = $oRightSelect->privRenderSingleTable($aTempFrom, $aFields, $aDelTables, $aSetValues, $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;

View 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);
}
}
?>

View File

@@ -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" => "",
@@ -105,6 +105,34 @@ abstract class TriggerOnObject extends Trigger
// MetaModel::Init_SetZListItems('advanced_search', array('name')); // Criteria of the advanced search form
}
}
/**
* To trigger notifications when a ticket is updated from the portal
*/
class TriggerOnPortalUpdate extends TriggerOnObject
{
public static function Init()
{
$aParams = array
(
"category" => "core/cmdb,bizmodel",
"key_type" => "autoincrement",
"name_attcode" => "description",
"state_attcode" => "",
"reconc_keys" => array('description'),
"db_table" => "priv_trigger_onportalupdate",
"db_key_field" => "id",
"db_finalclass_field" => "",
"display_template" => "",
);
MetaModel::Init_Params($aParams);
MetaModel::Init_InheritAttributes();
// Display lists
MetaModel::Init_SetZListItems('details', array('description', 'target_class', 'action_list')); // Attributes to be displayed for the complete details
MetaModel::Init_SetZListItems('list', array('finalclass', 'target_class', 'description')); // Attributes to be displayed for a list
// Search criteria
}
}
abstract class TriggerOnStateChange extends TriggerOnObject
{
@@ -116,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" => "",
@@ -130,7 +158,7 @@ abstract class TriggerOnStateChange extends TriggerOnObject
MetaModel::Init_SetZListItems('details', array('description', 'target_class', 'state', 'action_list')); // Attributes to be displayed for the complete details
MetaModel::Init_SetZListItems('list', array('finalclass', 'target_class', 'state')); // 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('standard_search', array('description', 'target_class', 'state')); // Criteria of the std search form
// MetaModel::Init_SetZListItems('advanced_search', array('name')); // Criteria of the advanced search form
}
}
@@ -141,11 +169,11 @@ class TriggerOnStateEnter extends TriggerOnStateChange
{
$aParams = array
(
"category" => "core/cmdb",
"category" => "core/cmdb,bizmodel",
"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" => "",
@@ -158,7 +186,7 @@ class TriggerOnStateEnter extends TriggerOnStateChange
MetaModel::Init_SetZListItems('details', array('description', 'target_class', 'state', 'action_list')); // Attributes to be displayed for the complete details
MetaModel::Init_SetZListItems('list', array('target_class', 'state')); // 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('standard_search', array('description', 'target_class', 'state')); // Criteria of the std search form
// MetaModel::Init_SetZListItems('advanced_search', array('name')); // Criteria of the advanced search form
}
}
@@ -169,11 +197,11 @@ class TriggerOnStateLeave extends TriggerOnStateChange
{
$aParams = array
(
"category" => "core/cmdb",
"category" => "core/cmdb,bizmodel",
"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" => "",
@@ -186,7 +214,7 @@ class TriggerOnStateLeave extends TriggerOnStateChange
MetaModel::Init_SetZListItems('details', array('description', 'target_class', 'state', 'action_list')); // Attributes to be displayed for the complete details
MetaModel::Init_SetZListItems('list', array('target_class', 'state')); // Attributes to be displayed for a list
// Search criteria
// MetaModel::Init_SetZListItems('standard_search', array('')); // Criteria of the std search form
MetaModel::Init_SetZListItems('standard_search', array('description', 'target_class', 'state')); // Criteria of the std search form
// MetaModel::Init_SetZListItems('advanced_search', array('')); // Criteria of the advanced search form
}
}
@@ -197,11 +225,11 @@ class TriggerOnObjectCreate extends TriggerOnObject
{
$aParams = array
(
"category" => "core/cmdb",
"category" => "core/cmdb,bizmodel",
"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" => "",
@@ -214,7 +242,7 @@ class TriggerOnObjectCreate extends TriggerOnObject
MetaModel::Init_SetZListItems('details', array('description', 'target_class', 'action_list')); // Attributes to be displayed for the complete details
MetaModel::Init_SetZListItems('list', array('finalclass', 'target_class')); // 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('standard_search', array('description', 'target_class')); // Criteria of the std search form
// MetaModel::Init_SetZListItems('advanced_search', array('name')); // Criteria of the advanced search form
}
}
@@ -225,11 +253,11 @@ class lnkTriggerAction extends cmdbAbstractObject
{
$aParams = array
(
"category" => "core/cmdb",
"category" => "core/cmdb,bizmodel",
"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" => "",

View File

@@ -50,13 +50,12 @@ define('UR_ACTION_APPLICATION_DEFINED', 10000); // Application specific actions
*/
abstract class UserRightsAddOnAPI
{
abstract public function Setup(); // initial installation
abstract public function CreateAdministrator($sAdminUser, $sAdminPwd, $sLanguage = 'EN US'); // could be used during initial installation
abstract public function Init(); // loads data (possible optimizations)
// Used to build select queries showing only objects visible for the given user
abstract public function GetSelectFilter($sLogin, $sClass); // returns a filter object
abstract public function GetSelectFilter($sLogin, $sClass, $aSettings = array()); // returns a filter object
abstract public function IsActionAllowed($oUser, $sClass, $iActionCode, /*dbObjectSet*/ $oInstanceSet = null);
abstract public function IsStimulusAllowed($oUser, $sClass, $sStimulusCode, /*dbObjectSet*/ $oInstanceSet = null);
@@ -111,6 +110,35 @@ abstract class User extends cmdbAbstractObject
abstract public function CanChangePassword();
abstract public function ChangePassword($sOldPassword, $sNewPassword);
/*
* Compute a name in best effort mode
*/
public function GetFriendlyName()
{
if (!MetaModel::IsValidAttCode(get_class($this), 'contactid'))
{
return $this->Get('login');
}
if ($this->Get('contactid') != 0)
{
$sFirstName = $this->Get('first_name');
$sLastName = $this->Get('last_name');
$sEmail = $this->Get('email');
if (strlen($sFirstName) > 0)
{
return "$sFirstName $sLastName";
}
elseif (strlen($sEmail) > 0)
{
return "$sLastName <$sEmail>";
}
else
{
return $sLastName;
}
}
}
/*
* Overload the standard behavior
*/
@@ -132,8 +160,7 @@ abstract class User extends cmdbAbstractObject
}
// Check that this user has at least one profile assigned
$oSet = $this->Get('profile_list');
$aProfileLinks = $oSet->ToArray();
if (count($aProfileLinks) == 0)
if ($oSet->Count() == 0)
{
$this->m_aCheckIssues[] = Dict::Format('Class:User/Error:AtLeastOneProfileIsNeeded');
}
@@ -174,7 +201,7 @@ abstract class User extends cmdbAbstractObject
{
if (UserRights::IsStimulusAllowed($sClass, $sStimulusCode, null, $this))
{
$aStimuli[] = '<span title="'.$sStimulusCode.': '.htmlentities($oStimulus->GetDescription()).'">'.htmlentities($oStimulus->GetLabel()).'</span>';
$aStimuli[] = '<span title="'.$sStimulusCode.': '.htmlentities($oStimulus->GetDescription(), ENT_QUOTES, 'UTF-8').'">'.htmlentities($oStimulus->GetLabel(), ENT_QUOTES, 'UTF-8').'</span>';
}
}
$sStimuli = implode(', ', $aStimuli);
@@ -268,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
*
@@ -278,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)
{
@@ -297,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;
@@ -310,15 +376,6 @@ class UserRights
return $bRes;
}
// Installation (e.g: give default values for users)
public static function Setup()
{
// to be discussed...
$bRes = self::$m_oAddOn->Setup();
self::FlushPrivileges(true /* reset admin cache */);
return $bRes;
}
protected static function IsLoggedIn()
{
if (self::$m_oUser == null)
@@ -343,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))
@@ -372,6 +446,11 @@ class UserRights
public static function CanChangePassword()
{
if (MetaModel::DBIsReadOnly())
{
return false;
}
if (!is_null(self::$m_oUser))
{
return self::$m_oUser->CanChangePassword();
@@ -382,27 +461,24 @@ class UserRights
}
}
public static function CanLogOff()
public static function ChangePassword($sOldPassword, $sNewPassword, $sName = '')
{
if (!is_null(self::$m_oUser))
if (empty($sName))
{
return self::$m_oUser->CanLogOff();
$oUser = self::$m_oUser;
}
else
{
return false;
// find the id out of the login string
$oUser = self::FindUser($sName);
}
}
public static function ChangePassword($sCurrentPassword, $sNewPassword)
{
if (!is_null(self::$m_oUser))
if (is_null($oUser))
{
return self::$m_oUser->ChangePassword($sCurrentPassword, $sNewPassword);
return false;
}
else
{
return false;
return $oUser->ChangePassword($sOldPassword, $sNewPassword);
}
}
@@ -438,6 +514,18 @@ class UserRights
}
}
public static function GetUserObject()
{
if (is_null(self::$m_oUser))
{
return null;
}
else
{
return self::$m_oUser;
}
}
public static function GetUserLanguage()
{
if (is_null(self::$m_oUser))
@@ -488,9 +576,31 @@ class UserRights
{
return '';
}
if (!MetaModel::IsValidAttCode(get_class($oUser), 'contactid'))
{
return '';
}
return $oUser->Get('contactid');
}
// Render the user name in best effort mode
public static function GetUserFriendlyName($sName = '')
{
if (empty($sName))
{
$oUser = self::$m_oUser;
}
else
{
$oUser = FindUser($sName);
}
if (is_null($oUser))
{
return '';
}
return $oUser->GetFriendlyName();
}
public static function IsImpersonated()
{
if (is_null(self::$m_oRealUser))
@@ -518,6 +628,15 @@ class UserRights
return self::$m_oRealUser->GetKey();
}
public static function GetRealUserFriendlyName()
{
if (is_null(self::$m_oRealUser))
{
return '';
}
return self::$m_oRealUser->GetFriendlyName();
}
protected static function CheckLogin()
{
if (!self::IsLoggedIn())
@@ -528,18 +647,16 @@ class UserRights
return true;
}
public static function GetSelectFilter($sClass)
public static function GetSelectFilter($sClass, $aSettings = array())
{
// When initializing, we need to let everything pass trough
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'))
{
return self::$m_oAddOn->GetSelectFilter(self::$m_oUser, $sClass);
return self::$m_oAddOn->GetSelectFilter(self::$m_oUser, $sClass, $aSettings);
}
else
{
@@ -552,14 +669,18 @@ class UserRights
// When initializing, we need to let everything pass trough
if (!self::CheckLogin()) return true;
if (MetaModel::DBIsReadOnly())
{
if ($iActionCode == UR_ACTION_MODIFY) return false;
if ($iActionCode == UR_ACTION_DELETE) return false;
if ($iActionCode == UR_ACTION_BULK_MODIFY) return false;
if ($iActionCode == UR_ACTION_BULK_DELETE) return false;
}
if (self::IsAdministrator($oUser)) return true;
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;
@@ -582,6 +703,11 @@ class UserRights
// When initializing, we need to let everything pass trough
if (!self::CheckLogin()) return true;
if (MetaModel::DBIsReadOnly())
{
return false;
}
if (self::IsAdministrator($oUser)) return true;
if (MetaModel::HasCategory($sClass, 'bizmodel'))
@@ -604,6 +730,14 @@ class UserRights
// When initializing, we need to let everything pass trough
if (!self::CheckLogin()) return true;
if (MetaModel::DBIsReadOnly())
{
if ($iActionCode == UR_ACTION_MODIFY) return false;
if ($iActionCode == UR_ACTION_DELETE) return false;
if ($iActionCode == UR_ACTION_BULK_MODIFY) return false;
if ($iActionCode == UR_ACTION_BULK_DELETE) return false;
}
if (self::IsAdministrator($oUser)) return true;
// this module is forbidden for non admins
@@ -720,4 +854,506 @@ class UserRights
}
}
/**
* Helper class to get the number/list of items for which a given action is allowed/possible
*/
class ActionChecker
{
var $oFilter;
var $iActionCode;
var $iAllowedCount = null;
var $aAllowedIDs = null;
public function __construct(DBObjectSearch $oFilter, $iActionCode)
{
$this->oFilter = $oFilter;
$this->iActionCode = $iActionCode;
$this->iAllowedCount = null;
$this->aAllowedIDs = null;
}
/**
* returns the number of objects for which the action is allowed
* @return integer The number of "allowed" objects 0..N
*/
public function GetAllowedCount()
{
if ($this->iAllowedCount == null) $this->CheckObjects();
return $this->iAllowedCount;
}
/**
* If IsAllowed returned UR_ALLOWED_DEPENDS, this methods returns
* an array of ObjKey => Status (true|false)
* @return array
*/
public function GetAllowedIDs()
{
if ($this->aAllowedIDs == null) $this->IsAllowed();
return $this->aAllowedIDs;
}
/**
* Check if the speficied stimulus is allowed for the set of objects
* @return UR_ALLOWED_YES, UR_ALLOWED_NO or UR_ALLOWED_DEPENDS
*/
public function IsAllowed()
{
$sClass = $this->oFilter->GetClass();
$oSet = new DBObjectSet($this->oFilter);
$iActionAllowed = UserRights::IsActionAllowed($sClass, $this->iActionCode, $oSet);
if ($iActionAllowed == UR_ALLOWED_DEPENDS)
{
// Check for each object if the action is allowed or not
$this->aAllowedIDs = array();
$oSet->Rewind();
$this->iAllowedCount = 0;
while($oObj = $oSet->Fetch())
{
$oObjSet = DBObjectSet::FromArray($sClass, array($oObj));
if (UserRights::IsActionAllowed($sClass, $this->iActionCode, $oObjSet) == UR_ALLOWED_NO)
{
$this->aAllowedIDs[$oObj->GetKey()] = false;
}
else
{
// Assume UR_ALLOWED_YES, since there is just one object !
$this->aAllowedIDs[$oObj->GetKey()] = true;
$this->iAllowedCount++;
}
}
}
else if ($iActionAllowed == UR_ALLOWED_YES)
{
$this->iAllowedCount = $oSet->Count();
$this->aAllowedIDs = array(); // Optimization: not filled when Ok for all objects
}
else // UR_ALLOWED_NO
{
$this->iAllowedCount = 0;
$this->aAllowedIDs = array();
}
return $iActionAllowed;
}
}
/**
* Helper class to get the number/list of items for which a given stimulus can be applied (allowed & possible)
*/
class StimulusChecker extends ActionChecker
{
var $sState = null;
public function __construct(DBObjectSearch $oFilter, $sState, $iStimulusCode)
{
parent::__construct($oFilter, $iStimulusCode);
$this->sState = $sState;
}
/**
* Check if the speficied stimulus is allowed for the set of objects
* @return UR_ALLOWED_YES, UR_ALLOWED_NO or UR_ALLOWED_DEPENDS
*/
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)
{
$this->iAllowedCount = 0;
$this->aAllowedIDs = array();
}
else // Even if UR_ALLOWED_YES, we need to check if each object is in the appropriate state
{
// Hmmm, may not be needed right now because we limit the "multiple" action to object in
// the same state... may be useful later on if we want to extend this behavior...
// Check for each object if the action is allowed or not
$this->aAllowedIDs = array();
$oSet->Rewind();
$iAllowedCount = 0;
$iActionAllowed = UR_ALLOWED_DEPENDS;
while($oObj = $oSet->Fetch())
{
$aTransitions = $oObj->EnumTransitions();
if (array_key_exists($this->iActionCode, $aTransitions))
{
// Temporary optimization possible: since the current implementation
// 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::IsStimulusAllowed($sClass, $this->iActionCode, $oObjSet))
{
$this->aAllowedIDs[$oObj->GetKey()] = false;
}
else
{
// Assume UR_ALLOWED_YES, since there is just one object !
$this->aAllowedIDs[$oObj->GetKey()] = true;
$this->iState = $oObj->GetState();
$this->iAllowedCount++;
}
}
else
{
$this->aAllowedIDs[$oObj->GetKey()] = false;
}
}
}
if ($this->iAllowedCount == $oSet->Count())
{
$iActionAllowed = UR_ALLOWED_YES;
}
if ($this->iAllowedCount == 0)
{
$iActionAllowed = UR_ALLOWED_NO;
}
return $iActionAllowed;
}
public function GetState()
{
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');
?>

View File

@@ -51,30 +51,31 @@ abstract class ValueSetDefinition
}
public function GetValues($aArgs, $sBeginsWith = '')
public function GetValues($aArgs, $sContains = '')
{
if (!$this->m_bIsLoaded)
{
$this->LoadValues($aArgs);
$this->m_bIsLoaded = true;
}
if (strlen($sBeginsWith) == 0)
if (strlen($sContains) == 0)
{
// No filtering
$aRet = $this->m_aValues;
}
else
{
$iCheckedLen = strlen($sBeginsWith);
$sBeginsWith = strtolower($sBeginsWith);
// Filter on results containing the needle <sContain>
$aRet = array();
foreach ($this->m_aValues as $sKey=>$sValue)
{
if (strtolower(substr($sValue, 0, $iCheckedLen)) == $sBeginsWith)
if (stripos($sValue, $sContains) !== false)
{
$aRet[$sKey] = $sValue;
}
}
}
// Sort on the display value
asort($aRet);
return $aRet;
}
@@ -90,21 +91,76 @@ 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;
private $m_aModifierProperties;
public function __construct($sFilterExp, $sValueAttCode = '', $aOrderBy = array(), $bAllowAllData = false)
public function __construct($sFilterExp, $sValueAttCode = '', $aOrderBy = array(), $bAllowAllData = false, $aModifierProperties = array())
{
$this->m_sContains = '';
$this->m_sFilterExpr = $sFilterExp;
$this->m_sValueAttCode = $sValueAttCode;
$this->m_aOrderBy = $aOrderBy;
$this->m_bAllowAllData = $bAllowAllData;
$this->m_aModifierProperties = $aModifierProperties;
$this->m_aExtraConditions = array();
}
protected function LoadValues($aArgs)
public function SetModifierProperty($sPluginClass, $sProperty, $value)
{
$this->m_aModifierProperties[$sPluginClass][$sProperty] = $value;
}
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);
}
foreach($this->m_aModifierProperties as $sPluginClass => $aProperties)
{
foreach ($aProperties as $sProperty => $value)
{
$oFilter->SetModifierProperty($sPluginClass, $sProperty, $value);
}
}
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)
@@ -116,6 +172,22 @@ class ValueSetObjects extends ValueSetDefinition
$oFilter = DBObjectSearch::FromOQL($this->m_sFilterExpr);
}
if (!$oFilter) return false;
foreach($this->m_aExtraConditions as $oExtraFilter)
{
$oFilter->MergeWith($oExtraFilter);
}
foreach($this->m_aModifierProperties as $sPluginClass => $aProperties)
{
foreach ($aProperties as $sProperty => $value)
{
$oFilter->SetModifierProperty($sPluginClass, $sProperty, $value);
}
}
$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())
@@ -136,6 +208,11 @@ class ValueSetObjects extends ValueSetDefinition
{
return 'Filter: '.$this->m_sFilterExpr;
}
public function GetFilterExpression()
{
return $this->m_sFilterExpr;
}
}
@@ -200,7 +277,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;
@@ -227,6 +304,13 @@ class ValueSetEnum extends ValueSetDefinition
$this->m_values = $Values;
}
// Helper to export the datat model
public function GetValueList()
{
$this->LoadValues($aArgs = array());
return $this->m_aValues;
}
protected function LoadValues($aArgs)
{
if (is_array($this->m_values))
@@ -252,6 +336,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

View File

@@ -35,7 +35,7 @@
}
.ac_loading {
background: white url('indicator.gif') right center no-repeat;
background: white url('../images/indicator.gif') right center no-repeat;
}
.ac_odd {

View File

@@ -1,8 +1,7 @@
/* CSS Document */
body {
font-family: Tahoma, Verdana, Arial, Helevtica;
font-family: Tahoma, Verdana, Arial, Helvetica;
font-size: 10pt;
background-color: #fff;
color:#000000;
margin: 0; /* Remove body margin/padding */
padding: 0;
@@ -10,7 +9,7 @@ body {
}
.raw_output {
font-family: Courier-New, Courier, Arial, Helevtica;
font-family: Courier-New, Courier, Arial, Helvetica;
font-size: 8pt;
background-color: #eeeeee;
color: #000000;
@@ -60,6 +59,7 @@ table.listContainer {
padding: 0;
margin:0;
width: 97%;
clear: both;
}
tr.containerHeader, tr.containerHeader td {
@@ -126,9 +126,9 @@ th.headerSortDown {
td {
font-family: Tahoma, Verdana, Arial, Helvetica;
font-size: 8pt;
font-size: 12px;
color:#696969;
background-color: #ffffff;
nobackground-color: #ffffff;
padding: 0px;
}
@@ -139,12 +139,45 @@ tr.clicked td {
}
td.label {
vertical-align: top;
}
td.label span {
font-family: Tahoma, Verdana, Arial, Helvetica;
font-size: 12px;
color: #000000;
background-color:#f6f6f6;
padding: 0.25em;
font-weight:bold;
padding: 5px;
padding-right: 10px;
font-weight:bold;
vertical-align: top;
text-align: right;
display: block;
}
fieldset td.label span {
padding: 3px;
padding-right: 10px;
}
fieldset {
margin-top: 3px;
-moz-border-radius: 6px;
-webkit-border-radius: 6px;
border-radius: 6px;
border-style: solid;
border-color: #ddd;
}
legend {
font-family: Tahoma, Verdana, Arial, Helvetica;
font-size: 12px;
padding:8px;
color: #fff;
background-color: #1C94C4;
font-weight: bold;
-moz-border-radius: 6px;
-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 {
@@ -160,7 +193,7 @@ p a:hover, td a:hover {
background: url(../images/mini-arrow-orange.gif) no-repeat left;
}
td a.no-arrow, td a.no-arrow:visited {
td a.no-arrow, td a.no-arrow:visited, .SearchDrawer a.no-arrow, .SearchDrawer a.no-arrow:visited {
text-decoration:none;
color:#000000;
padding-left:0px;
@@ -172,6 +205,19 @@ td a.no-arrow:hover {
padding-left:0px;
background: inherit;
}
td a.mailto, td a.mailto:visited {
text-decoration:none;
color:#000000;
padding-left:20px;
background: url(../images/mail.png) no-repeat left;
}
td a.mailto:hover {
text-decoration:underline;
color:#EB8F00;
padding-left:20px;
background: url(../images/mail.png) no-repeat left;
}
a.small_action {
font-family: Tahoma, Verdana, Arial, Helvetica;
font-size: 8pt;
@@ -360,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;
@@ -372,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;
@@ -781,7 +829,7 @@ div#inner_menu {
}
div#logo {
height: 70px;
width: 100%;
nowidth: 100%;
text-align: center;
}
div#logo div {
@@ -794,10 +842,18 @@ div#logo div {
background: url(../images/banner-bkg.png) repeat-x scroll 0 0 transparent;
text-align: right;
}
#admin-banner {
float: left;
margin-top: 2px;
padding: 8px;
border: 1px solid #c33;
background-color: #fee;
-moz-border-radius: 0.5em;
}
#global-search {
height: 55px;
float: right;
background: url(../images/banner-search.png) no-repeat left;
background: url(../images/banner-search.png) no-repeat;
nopadding-top: 15px;
text-align: right;
overflow-y: hidden;
@@ -817,7 +873,7 @@ div#logo div {
#global-search > form input[type="text"] {
border: 0;
height: 18px;
width: 180px;E8FFD3
width: 180px;
padding-top: 4;
background: transparent;
}
@@ -856,4 +912,203 @@ div.footer{
#SearchResultsToAdd table.listResults tbody {
height: 300px;
overflow-y: auto;
}
tr.row_unchanged td {
border-bottom: 1px #ccc solid;
padding: 2px;
}
.wizContainer table tr.row_error td {
border-bottom: 1px #ccc solid;
background-color: #fdd;
padding: 2px;
}
tr.row_modified td {
border-bottom: 1px #ccc solid;
padding: 2px;
}
tr.row_added td {
border-bottom: 1px #ccc solid;
padding: 2px;
}
a.truncated {
cursor: pointer;
}
.org_combo
{
font-size:x-small;
width: auto;
max-width: 200px;
}
span.form_validation {
width:24px;
text-align:center;
}
.notification {
border: 1px solid #c33;
background-color: #fee;
padding: 0.5em;
margin: 0.5em;
text-align:center;
width: 95%;
-moz-border-radius: 0.5em;
}
.wiki_broken_link {
text-decoration: line-through;
}
.synoptics, .synoptics tr td {
background: transparent;
padding:10px;
font-size:1em;
vertical-align:middle;
color:#fff;
text-align:center;
}
.synoptics tr td.arrow {
color:#333;
border-top: 1px dashed #333;
width:100px;
}
.synoptics tr.synoptics_header td {
color:#000; font-size:1em;
vertical-align:middle;
text-align:center;
}
.mono_value {
display: inline-block;
background-color: #3c3;
color: #fff;
font-weight:bold;
padding: 3px;
padding-left: 5px;
padding-right: 5px;
margin-left:3px;
-moz-border-radius: 10px;
-webkit-border-radius: 10px;
border-radius: 10px;
}
.multi_values {
display: inline-block;
background-color: #c33;
color: #fff;
font-weight:bold;
padding: 3px;
padding-left: 5px;
padding-right: 5px;
margin-left:3px;
-moz-border-radius: 10px;
-webkit-border-radius: 10px;
border-radius: 10px;
}
.caselog {
overflow-x: hidden;
display: block;
overflow-y: auto;
border: 1px #ddd solid;
font-family: Tahoma, Verdana, Arial, Helvetica;
font-size: 12px;
}
.caselog_input_header {
padding-top:3px;
padding-bottom:3px;
border-top:1px solid #fff;
background: #ddd;
width:100%;
}
.caselog_header {
padding:3px;
border-top:1px solid #fff;
background: #ddd url(../images/plus.gif) left no-repeat;
padding-left: 16px;
cursor: pointer;
width:100%;
}
.caselog_header.open {
background: #ddd url(../images/minus.gif) left no-repeat;
}
.caselog_entry {
padding:3px;
padding-left: 16px;
border-bottom:1px #999 solid;
margin-left:0;
margin-right:0;
white-space: pre-wrap; /* css-3 */
white-space: -moz-pre-wrap; /* Mozilla, since 1999 */
white-space: -pre-wrap; /* Opera 4-6 */
white-space: -o-pre-wrap; /* Opera 7 */
word-wrap: break-word; /* Internet Explorer 5.5+, CSS3 */
}
table.details {
border-collapse: collapse;
noborder-bottom: 2px #fff solid;
width:100%;
}
table.details>tbody>tr>td {
border-bottom: 2px #ddd solid;
padding-bottom: 5px;
padding-top: 3px;
}
fieldset table.details>tbody>tr>td {
padding-top: 3px;
background: transparent;
border: 0;
}
.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%;
}

15
css/print.css Normal file
View File

@@ -0,0 +1,15 @@
@CHARSET "UTF-8";
#left-pane { display: none; }
span.ui-layout-resizer { display: none; }
#header-logo { display: none; }
#logo { display: none; }
div.header-menu { display:none; }
div.footer { display:none; }
#top-bar { display: none; }
#menu { display: none; }
div.actions_button { display:none; }
div.itop_popup { display:none; }
div.HRDrawer { display:none; }
div.DrawerHandle { display:none; }
a.tab { display:none; }
div.itop-tab { border: #ccc 1px solid; margin-top: 1em; padding-bottom:1em; }

View File

@@ -1,387 +1,523 @@
<?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
*/
//////////////////////////////////////////////////////////////////////
// Classes in 'core/cmdb'
//////////////////////////////////////////////////////////////////////
//
//
// Class: CMDBChange
//
Dict::Add('DE DE', 'German', 'Deutsch', array(
'Class:CMDBChange' => 'Change',
'Class:CMDBChange+' => 'Changes Tracking',
'Class:CMDBChange/Attribute:date' => 'Datum',
'Class:CMDBChange/Attribute:date+' => 'Datum und Uhrzeit der Änderungen',
'Class:CMDBChange/Attribute:userinfo' => 'Sonstige Informationen',
'Class:CMDBChange/Attribute:userinfo+' => 'Aufruferdefinierte Informationen',
));
//
// Class: CMDBChangeOp
//
Dict::Add('DE DE', 'German', 'Deutsch', array(
'Class:CMDBChangeOp' => 'Change Operation',
'Class:CMDBChangeOp+' => 'Change operations tracking',
'Class:CMDBChangeOp/Attribute:change' => 'Change',
'Class:CMDBChangeOp/Attribute:change+' => 'Change',
'Class:CMDBChangeOp/Attribute:date' => 'Datum',
'Class:CMDBChangeOp/Attribute:date+' => 'Datum und Uhrzeit der Änderungen',
'Class:CMDBChangeOp/Attribute:userinfo' => 'Benutzer',
'Class:CMDBChangeOp/Attribute:userinfo+' => 'Wer führte diese Änderung durch',
'Class:CMDBChangeOp/Attribute:objclass' => 'Objektklasse',
'Class:CMDBChangeOp/Attribute:objclass+' => 'Objektklasse',
'Class:CMDBChangeOp/Attribute:objkey' => 'Objekt-ID',
'Class:CMDBChangeOp/Attribute:objkey+' => 'Objekt-ID',
'Class:CMDBChangeOp/Attribute:finalclass' => 'Typ',
'Class:CMDBChangeOp/Attribute:finalclass+' => '',
));
//
// Class: CMDBChangeOpCreate
//
Dict::Add('DE DE', 'German', 'Deutsch', array(
'Class:CMDBChangeOpCreate' => 'Objekterstellung',
'Class:CMDBChangeOpCreate+' => 'Protokoll der Objekterstellung',
));
//
// Class: CMDBChangeOpDelete
//
Dict::Add('DE DE', 'German', 'Deutsch', array(
'Class:CMDBChangeOpDelete' => 'Objektlöschung',
'Class:CMDBChangeOpDelete+' => 'Protokoll der Objektlöschung',
));
//
// Class: CMDBChangeOpSetAttribute
//
Dict::Add('DE DE', 'German', 'Deutsch', array(
'Class:CMDBChangeOpSetAttribute' => 'Objektänderung',
'Class:CMDBChangeOpSetAttribute+' => 'Protokoll der Objektänderungen',
'Class:CMDBChangeOpSetAttribute/Attribute:attcode' => 'Attribut',
'Class:CMDBChangeOpSetAttribute/Attribute:attcode+' => 'Code der geänderten Eigenschaft',
));
//
// Class: CMDBChangeOpSetAttributeScalar
//
Dict::Add('DE DE', 'German', 'Deutsch', array(
'Class:CMDBChangeOpSetAttributeScalar' => 'Eigenschaften ändern',
'Class:CMDBChangeOpSetAttributeScalar+' => 'Aufzeichnen der Änderungen am Objekt',
'Class:CMDBChangeOpSetAttributeScalar/Attribute:oldvalue' => 'Vorheriger Wert',
'Class:CMDBChangeOpSetAttributeScalar/Attribute:oldvalue+' => 'Vorheriger Wert des Attributes',
'Class:CMDBChangeOpSetAttributeScalar/Attribute:newvalue' => 'Neuer Wert',
'Class:CMDBChangeOpSetAttributeScalar/Attribute:newvalue+' => 'Neuer Wert des Attributes',
));
// Used by CMDBChangeOp... & derived classes
Dict::Add('DE DE', 'German', 'Deutsch', array(
'Change:ObjectCreated' => 'Objekt erstellt',
'Change:ObjectDeleted' => 'Objekt erstellt',
'Change:AttName_SetTo_NewValue_PreviousValue_OldValue' => '%1$s geändert zu %2$s (vorheriger Wert: %3$s)',
'Change:Text_AppendedTo_AttName' => '%1$s zugefügt an %2$s',
'Change:AttName_Changed_PreviousValue_OldValue' => '%1$s modifiziert, vorheriger Wert: %2$s',
'Change:AttName_Changed' => '%1$s modifiziert',
));
//
// Class: CMDBChangeOpSetAttributeBlob
//
Dict::Add('DE DE', 'German', 'Deutsch', array(
'Class:CMDBChangeOpSetAttributeBlob' => 'Daten ändern',
'Class:CMDBChangeOpSetAttributeBlob+' => 'Aufzeichnen der Data Changes',
'Class:CMDBChangeOpSetAttributeBlob/Attribute:prevdata' => 'Vorherige Daten',
'Class:CMDBChangeOpSetAttributeBlob/Attribute:prevdata+' => 'Vorherige Inhalte des Attributes',
));
//
// Class: CMDBChangeOpSetAttributeText
//
Dict::Add('DE DE', 'German', 'Deutsch', array(
'Class:CMDBChangeOpSetAttributeText' => 'Text ändern',
'Class:CMDBChangeOpSetAttributeText+' => 'Aufzeichnen der Textänderung',
'Class:CMDBChangeOpSetAttributeText/Attribute:prevdata' => 'Vorherige Daten',
'Class:CMDBChangeOpSetAttributeText/Attribute:prevdata+' => 'Vorherige Inhalte des Attributes',
));
//
// Class: Event
//
Dict::Add('DE DE', 'German', 'Deutsch', array(
'Class:Event' => 'Log Event',
'Class:Event+' => 'Ein anwendungsinterner Event',
'Class:Event/Attribute:message' => 'Nachricht',
'Class:Event/Attribute:message+' => 'Kurze Beschreibung des Events',
'Class:Event/Attribute:date' => 'Datum',
'Class:Event/Attribute:date+' => 'Datum und Uhrzeit der Änderungen',
'Class:Event/Attribute:userinfo' => 'Benutzer-Information',
'Class:Event/Attribute:userinfo+' => 'Identifikation des Benutzer, der die Aktion ausführte, die diesen Event ausgelöst hat',
'Class:Event/Attribute:finalclass' => 'Typ',
'Class:Event/Attribute:finalclass+' => '',
));
//
// Class: EventNotification
//
Dict::Add('DE DE', 'German', 'Deutsch', array(
'Class:EventNotification' => 'Notification Event',
'Class:EventNotification+' => 'Protokollierung der gesendeten Benachrichtigungen',
'Class:EventNotification/Attribute:trigger_id' => 'Trigger',
'Class:EventNotification/Attribute:trigger_id+' => 'Benutzerkonto',
'Class:EventNotification/Attribute:action_id' => 'Benutzer',
'Class:EventNotification/Attribute:action_id+' => 'Benutzerkonto',
'Class:EventNotification/Attribute:object_id' => 'Objekt-ID',
'Class:EventNotification/Attribute:object_id+' => 'Objekt-ID (Klasse, die von Trigger definiert wurde?)',
));
//
// Class: EventNotificationEmail
//
Dict::Add('DE DE', 'German', 'Deutsch', array(
'Class:EventNotificationEmail' => 'Email Emission Event',
'Class:EventNotificationEmail+' => 'Verfolgung einer Email, die gesendet wurde',
'Class:EventNotificationEmail/Attribute:to' => 'An',
'Class:EventNotificationEmail/Attribute:to+' => 'An',
'Class:EventNotificationEmail/Attribute:cc' => 'Kopie an',
'Class:EventNotificationEmail/Attribute:cc+' => 'Kopie an',
'Class:EventNotificationEmail/Attribute:bcc' => 'Blindkopie (BCC)',
'Class:EventNotificationEmail/Attribute:bcc+' => 'Blindkopie (BCC)',
'Class:EventNotificationEmail/Attribute:from' => 'Von',
'Class:EventNotificationEmail/Attribute:from+' => 'Absender der Nachricht',
'Class:EventNotificationEmail/Attribute:subject' => 'Betreff',
'Class:EventNotificationEmail/Attribute:subject+' => 'Betreff',
'Class:EventNotificationEmail/Attribute:body' => 'Inhalt der Nachricht',
'Class:EventNotificationEmail/Attribute:body+' => 'Inhalt der Nachricht',
));
//
// Class: EventIssue
//
Dict::Add('DE DE', 'German', 'Deutsch', array(
'Class:EventIssue' => 'Issue Event',
'Class:EventIssue+' => 'Protokollierung einer Issue (Warnungen, Fehler, etc.)',
'Class:EventIssue/Attribute:issue' => 'Issue',
'Class:EventIssue/Attribute:issue+' => 'Was passierte?',
'Class:EventIssue/Attribute:impact' => 'Auswirkungen',
'Class:EventIssue/Attribute:impact+' => 'Was waren die Auswirkungen?',
'Class:EventIssue/Attribute:page' => 'Seite',
'Class:EventIssue/Attribute:page+' => 'HTTP entry point',
'Class:EventIssue/Attribute:arguments_post' => 'Eingegebene Arguments',
'Class:EventIssue/Attribute:arguments_post+' => 'HTTP POST-Argumente',
'Class:EventIssue/Attribute:arguments_get' => 'URL-Argumente',
'Class:EventIssue/Attribute:arguments_get+' => 'HTTP GET-Argumente',
'Class:EventIssue/Attribute:callstack' => 'Callstack',
'Class:EventIssue/Attribute:callstack+' => 'Call stack',
'Class:EventIssue/Attribute:data' => 'Daten',
'Class:EventIssue/Attribute:data+' => 'Mehr Informationen',
));
//
// Class: EventWebService
//
Dict::Add('DE DE', 'German', 'Deutsch', array(
'Class:EventWebService' => 'Web Service Event',
'Class:EventWebService+' => 'Protokollierung eines Web Service Calls',
'Class:EventWebService/Attribute:verb' => 'Verb',
'Class:EventWebService/Attribute:verb+' => 'Name der Operation',
'Class:EventWebService/Attribute:result' => 'Ergebnis',
'Class:EventWebService/Attribute:result+' => 'Gesamterfolg/-misserfolg',
'Class:EventWebService/Attribute:log_info' => 'Informations-Protokollierung',
'Class:EventWebService/Attribute:log_info+' => 'Ergebnis der Informations-Protokollierung',
'Class:EventWebService/Attribute:log_warning' => 'Warnungs-Protokollierung',
'Class:EventWebService/Attribute:log_warning+' => 'Ergebnis der Warnungs-Protokollierung',
'Class:EventWebService/Attribute:log_error' => 'Fehler-Protokollierung',
'Class:EventWebService/Attribute:log_error+' => 'Ergebnis der Fehler-Protokollierung',
'Class:EventWebService/Attribute:data' => 'Daten',
'Class:EventWebService/Attribute:data+' => 'Ergebnisdaten',
));
//
// Class: Action
//
Dict::Add('DE DE', 'German', 'Deutsch', array(
'Class:Action' => 'Benutzerdefinierte Aktion',
'Class:Action+' => 'Benutzerdefinierte Aktionen',
'Class:Action/Attribute:name' => 'Name',
'Class:Action/Attribute:name+' => '',
'Class:Action/Attribute:description' => 'Beschreibung',
'Class:Action/Attribute:description+' => '',
'Class:Action/Attribute:status' => 'Status',
'Class:Action/Attribute:status+' => 'Im Einsatz oder?',
'Class:Action/Attribute:status/Value:test' => 'Wird getestet',
'Class:Action/Attribute:status/Value:test+' => 'Wird getestet',
'Class:Action/Attribute:status/Value:enabled' => 'Im Einsatz',
'Class:Action/Attribute:status/Value:enabled+' => 'Im Einsatz',
'Class:Action/Attribute:status/Value:disabled' => 'Inaktiv',
'Class:Action/Attribute:status/Value:disabled+' => 'Inaktiv',
'Class:Action/Attribute:trigger_list' => 'Zugehörige Trigger',
'Class:Action/Attribute:trigger_list+' => 'Trigger, die mit dieser Aktion verknüpft sind',
'Class:Action/Attribute:finalclass' => 'Typ',
'Class:Action/Attribute:finalclass+' => '',
));
//
// Class: ActionNotification
//
Dict::Add('DE DE', 'German', 'Deutsch', array(
'Class:ActionNotification' => 'Benachrichtigung',
'Class:ActionNotification+' => 'Benachrichtigung (Kurzbeschreibung)',
));
//
// Class: ActionEmail
//
Dict::Add('DE DE', 'German', 'Deutsch', array(
'Class:ActionEmail' => 'Email-Benachrichtigung',
'Class:ActionEmail+' => '',
'Class:ActionEmail/Attribute:test_recipient' => 'Testempfänger',
'Class:ActionEmail/Attribute:test_recipient+' => 'Empfänger im Fall eines "Test"-Status',
'Class:ActionEmail/Attribute:from' => 'Von',
'Class:ActionEmail/Attribute:from+' => 'Wird im Email-Header mitgesendet',
'Class:ActionEmail/Attribute:reply_to' => 'Antworten an',
'Class:ActionEmail/Attribute:reply_to+' => 'Wird im Email-Header mitgesendet',
'Class:ActionEmail/Attribute:to' => 'An',
'Class:ActionEmail/Attribute:to+' => 'Empfänger der Nachricht',
'Class:ActionEmail/Attribute:cc' => 'Kopie an',
'Class:ActionEmail/Attribute:cc+' => 'Kopie an',
'Class:ActionEmail/Attribute:bcc' => 'Blindkopie (BCC)',
'Class:ActionEmail/Attribute:bcc+' => 'Blindkopie (BCC)',
'Class:ActionEmail/Attribute:subject' => 'Betreff',
'Class:ActionEmail/Attribute:subject+' => 'Betreff der Email',
'Class:ActionEmail/Attribute:body' => 'Inhalt der Nachricht',
'Class:ActionEmail/Attribute:body+' => 'Inhalt der Nachricht',
'Class:ActionEmail/Attribute:importance' => 'Priorität',
'Class:ActionEmail/Attribute:importance+' => 'Prioritätseinstufung',
'Class:ActionEmail/Attribute:importance/Value:low' => 'niedrig',
'Class:ActionEmail/Attribute:importance/Value:low+' => 'niedrig',
'Class:ActionEmail/Attribute:importance/Value:normal' => 'normal',
'Class:ActionEmail/Attribute:importance/Value:normal+' => 'normal',
'Class:ActionEmail/Attribute:importance/Value:high' => 'hoch',
'Class:ActionEmail/Attribute:importance/Value:high+' => 'hoch',
));
//
// Class: Trigger
//
Dict::Add('DE DE', 'German', 'Deutsch', array(
'Class:Trigger' => 'Trigger',
'Class:Trigger+' => 'Custom event handler',
'Class:Trigger/Attribute:description' => 'Beschreibung',
'Class:Trigger/Attribute:description+' => 'Kurzbeschreibung',
'Class:Trigger/Attribute:action_list' => 'Verbundene Trigger-Aktionen',
'Class:Trigger/Attribute:action_list+' => 'Aktionen, die ausgeführt werden, wenn der Trigger aktiviert ist',
'Class:Trigger/Attribute:finalclass' => 'Typ',
'Class:Trigger/Attribute:finalclass+' => '',
));
//
// Class: TriggerOnObject
//
Dict::Add('DE DE', 'German', 'Deutsch', array(
'Class:TriggerOnObject' => 'Trigger (klassenunabhängig)',
'Class:TriggerOnObject+' => 'Trigger einer gegebenen Klasse an Objekten',
'Class:TriggerOnObject/Attribute:target_class' => 'Zielklasse',
'Class:TriggerOnObject/Attribute:target_class+' => '',
));
//
// Class: TriggerOnStateChange
//
Dict::Add('DE DE', 'German', 'Deutsch', array(
'Class:TriggerOnStateChange' => 'Trigger (bei Statusänderung)',
'Class:TriggerOnStateChange+' => 'Trigger bei Änderung des Objektstatus',
'Class:TriggerOnStateChange/Attribute:state' => 'Status',
'Class:TriggerOnStateChange/Attribute:state+' => '',
));
//
// Class: TriggerOnStateEnter
//
Dict::Add('DE DE', 'German', 'Deutsch', array(
'Class:TriggerOnStateEnter' => 'Trigger (beim Eintritt eines Status)',
'Class:TriggerOnStateEnter+' => 'Trigger bei Eintritt einer Objektstatusänderungg',
));
//
// Class: TriggerOnStateLeave
//
Dict::Add('DE DE', 'German', 'Deutsch', array(
'Class:TriggerOnStateLeave' => 'Trigger (beim Verlassen eines Status)',
'Class:TriggerOnStateLeave+' => 'Trigger beim Verlassen einer Objektstatusänderungg',
));
//
// Class: TriggerOnObjectCreate
//
Dict::Add('DE DE', 'German', 'Deutsch', array(
'Class:TriggerOnObjectCreate' => 'Trigger (bei Objekterstellung)',
'Class:TriggerOnObjectCreate+' => 'Trigger bei Objekterstellung (einer Kindklasse) einer gegebenen Klasse',
));
//
// Class: lnkTriggerAction
//
Dict::Add('DE DE', 'German', 'Deutsch', array(
'Class:lnkTriggerAction' => 'Aktion/Trigger',
'Class:lnkTriggerAction+' => 'Verknüpfung zwischen einem Trigger und einer Aktion',
'Class:lnkTriggerAction/Attribute:action_id' => 'Aktion',
'Class:lnkTriggerAction/Attribute:action_id+' => 'Die auszuführende Aktion',
'Class:lnkTriggerAction/Attribute:action_name' => 'Aktion',
'Class:lnkTriggerAction/Attribute:action_name+' => '',
'Class:lnkTriggerAction/Attribute:trigger_id' => 'Trigger',
'Class:lnkTriggerAction/Attribute:trigger_id+' => '',
'Class:lnkTriggerAction/Attribute:trigger_name' => 'Trigger',
'Class:lnkTriggerAction/Attribute:trigger_name+' => '',
'Class:lnkTriggerAction/Attribute:order' => 'Reihenfolge',
'Class:lnkTriggerAction/Attribute:order+' => 'Reihenfolge der Aktionsausführungen',
));
?>
<?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>
* @author Stephan Rosenke <stephan.rosenke@itomig.de>
* @licence http://www.opensource.org/licenses/gpl-3.0.html LGPL
*/
Dict::Add('DE DE', 'German', 'Deutsch', array(
'Class:ActionEmail' => 'Email-Benachrichtigung',
'Class:ActionEmail+' => '',
'Class:ActionEmail/Attribute:test_recipient' => 'Testempfänger',
'Class:ActionEmail/Attribute:test_recipient+' => 'Empfänger im Fall eines "Test"-Status',
'Class:ActionEmail/Attribute:from' => 'Von',
'Class:ActionEmail/Attribute:from+' => 'Wird im Email-Header mitgesendet',
'Class:ActionEmail/Attribute:reply_to' => 'Antworten an',
'Class:ActionEmail/Attribute:reply_to+' => 'Wird im Email-Header mitgesendet',
'Class:ActionEmail/Attribute:to' => 'An',
'Class:ActionEmail/Attribute:to+' => 'Empfänger der Nachricht',
'Class:ActionEmail/Attribute:cc' => 'Kopie an',
'Class:ActionEmail/Attribute:cc+' => 'Kopie an',
'Class:ActionEmail/Attribute:bcc' => 'Blindkopie (BCC)',
'Class:ActionEmail/Attribute:bcc+' => 'Blindkopie (BCC)',
'Class:ActionEmail/Attribute:subject' => 'Betreff',
'Class:ActionEmail/Attribute:subject+' => 'Betreff der Email',
'Class:ActionEmail/Attribute:body' => 'Inhalt der Nachricht',
'Class:ActionEmail/Attribute:body+' => 'Inhalt der Nachricht',
'Class:ActionEmail/Attribute:importance' => 'Priorität',
'Class:ActionEmail/Attribute:importance+' => 'Prioritätseinstufung',
'Class:ActionEmail/Attribute:importance/Value:high' => 'hoch',
'Class:ActionEmail/Attribute:importance/Value:high+' => 'hoch',
'Class:ActionEmail/Attribute:importance/Value:low' => 'niedrig',
'Class:ActionEmail/Attribute:importance/Value:low+' => 'niedrig',
'Class:ActionEmail/Attribute:importance/Value:normal' => 'normal',
'Class:ActionEmail/Attribute:importance/Value:normal+' => 'normal',
'Class:TriggerOnStateEnter' => 'Trigger (beim Eintritt eines Status)',
'Class:TriggerOnStateEnter+' => 'Trigger bei Eintritt einer Objektstatusänderung',
'Class:TriggerOnStateLeave' => 'Trigger (beim Verlassen eines Status)',
'Class:TriggerOnStateLeave+' => 'Trigger beim Verlassen einer Objektstatusänderung',
'Class:TriggerOnObjectCreate' => 'Trigger (bei Objekterstellung)',
'Class:TriggerOnObjectCreate+' => 'Trigger bei Objekterstellung (einer Kindklasse) einer gegebenen Klasse',
'Class:lnkTriggerAction' => 'Aktion/Trigger',
'Class:lnkTriggerAction+' => 'Verknüpfung zwischen einem Trigger und einer Aktion',
'Class:lnkTriggerAction/Attribute:action_id' => 'Aktion',
'Class:lnkTriggerAction/Attribute:action_id+' => 'Die auszuführende Aktion',
'Class:lnkTriggerAction/Attribute:trigger_id' => 'Trigger',
'Class:lnkTriggerAction/Attribute:trigger_id+' => '',
'Class:lnkTriggerAction/Attribute:order' => 'Reihenfolge',
'Class:lnkTriggerAction/Attribute:order+' => 'Reihenfolge der Aktionsausführungen',
'Class:AsyncSendEmail' => 'Email (asynchron)',
'Class:AsyncSendEmail/Attribute:to' => 'An',
'Class:AsyncSendEmail/Attribute:subject' => 'Betreff',
'Class:CMDBChange' => 'Change',
'Class:CMDBChange+' => 'Protokollierung der Changes',
'Class:CMDBChange/Attribute:date' => 'Datum',
'Class:CMDBChange/Attribute:date+' => 'Datum und Uhrzeit der Änderungen',
'Class:CMDBChange/Attribute:userinfo' => 'Sonstige Informationen',
'Class:CMDBChange/Attribute:userinfo+' => 'Aufruferdefinierte Informationen',
'Class:CMDBChangeOp' => 'Change-Operation',
'Class:CMDBChangeOp+' => 'Protokoll der Change-Operation',
'Class:CMDBChangeOp/Attribute:change' => 'Change',
'Class:CMDBChangeOp/Attribute:change+' => 'Change',
'Class:CMDBChangeOp/Attribute:objclass' => 'Objektklasse',
'Class:CMDBChangeOp/Attribute:objclass+' => 'Objektklasse',
'Class:CMDBChangeOp/Attribute:objkey' => 'Objekt-ID',
'Class:CMDBChangeOp/Attribute:objkey+' => 'Objekt-ID',
'Class:CMDBChangeOp/Attribute:finalclass' => 'Typ',
'Class:CMDBChangeOp/Attribute:finalclass+' => '',
'Class:CMDBChangeOpCreate' => 'Objekterstellung',
'Class:CMDBChangeOpCreate+' => 'Protokoll der Objekterstellung',
'Class:CMDBChangeOpDelete' => 'Objektlöschung',
'Class:CMDBChangeOpDelete+' => 'Protokoll der Objektlöschung',
'Class:CMDBChangeOpSetAttribute' => 'Objektänderung',
'Class:CMDBChangeOpSetAttribute+' => 'Protokoll der Objektänderungen',
'Class:CMDBChangeOpSetAttribute/Attribute:attcode' => 'Attribut',
'Class:CMDBChangeOpSetAttribute/Attribute:attcode+' => 'Code der geänderten Eigenschaft',
'Class:CMDBChangeOpSetAttributeScalar' => 'Eigenschaften ändern',
'Class:CMDBChangeOpSetAttributeScalar+' => 'Aufzeichnen der Änderungen am Objekt',
'Class:CMDBChangeOpSetAttributeScalar/Attribute:oldvalue' => 'Vorheriger Wert',
'Class:CMDBChangeOpSetAttributeScalar/Attribute:oldvalue+' => 'Vorheriger Wert des Attributes',
'Class:CMDBChangeOpSetAttributeScalar/Attribute:newvalue' => 'Neuer Wert',
'Class:CMDBChangeOpSetAttributeScalar/Attribute:newvalue+' => 'Neuer Wert des Attributes',
'Class:CMDBChangeOpSetAttributeBlob' => 'Daten ändern',
'Class:CMDBChangeOpSetAttributeBlob+' => 'Aufzeichnen der Datenänderung',
'Class:CMDBChangeOpSetAttributeBlob/Attribute:prevdata' => 'Vorherige Daten',
'Class:CMDBChangeOpSetAttributeBlob/Attribute:prevdata+' => 'Vorherige Inhalte des Attributes',
'Class:CMDBChangeOpSetAttributeOneWayPassword' => 'Verschlüsseltes Passwort',
'Class:CMDBChangeOpSetAttributeOneWayPassword/Attribute:prev_pwd' => 'Vorheriger Wert',
'Class:CMDBChangeOpSetAttributeEncrypted' => 'Verschlüsseltes Feld',
'Class:CMDBChangeOpSetAttributeEncrypted/Attribute:prevstring' => 'Vorheriger Wert',
'Class:CMDBChangeOpSetAttributeText' => 'Text ändern',
'Class:CMDBChangeOpSetAttributeText+' => 'Aufzeichnen der Textänderung',
'Class:CMDBChangeOpSetAttributeText/Attribute:prevdata' => 'Vorherige Daten',
'Class:CMDBChangeOpSetAttributeText/Attribute:prevdata+' => 'Vorherige Inhalte des Attributes',
'Class:CMDBChangeOpSetAttributeCaseLog' => 'Fall-Protokoll',
'Class:CMDBChangeOpSetAttributeCaseLog/Attribute:lastentry' => 'letzter Eintrag',
'Class:Event' => 'Log Event',
'Class:Event+' => 'Ein anwendungsinterner Event',
'Class:Event/Attribute:message' => 'Nachricht',
'Class:Event/Attribute:message+' => 'Kurze Beschreibung des Events',
'Class:Event/Attribute:date' => 'Datum',
'Class:Event/Attribute:date+' => 'Datum und Uhrzeit der Änderungen',
'Class:Event/Attribute:userinfo' => 'Benutzer-Information',
'Class:Event/Attribute:userinfo+' => 'Identifikation des Benutzer, der die Aktion ausführte, die diesen Event ausgelöst hat',
'Class:Event/Attribute:finalclass' => 'Typ',
'Class:Event/Attribute:finalclass+' => '',
'Class:EventNotification' => 'Notification Event',
'Class:EventNotification+' => 'Protokollierung der gesendeten Benachrichtigungen',
'Class:EventNotification/Attribute:trigger_id' => 'Trigger',
'Class:EventNotification/Attribute:trigger_id+' => 'Benutzerkonto',
'Class:EventNotification/Attribute:action_id' => 'Benutzer',
'Class:EventNotification/Attribute:action_id+' => 'Benutzerkonto',
'Class:EventNotification/Attribute:object_id' => 'Objekt-ID',
'Class:EventNotification/Attribute:object_id+' => 'Objekt-ID (Klasse, die von Trigger definiert wurde?)',
'Class:EventNotificationEmail' => 'Email Emission Event',
'Class:EventNotificationEmail+' => 'Verfolgung einer Email, die gesendet wurde',
'Class:EventNotificationEmail/Attribute:to' => 'An',
'Class:EventNotificationEmail/Attribute:to+' => 'An',
'Class:EventNotificationEmail/Attribute:cc' => 'Kopie an',
'Class:EventNotificationEmail/Attribute:cc+' => 'Kopie an',
'Class:EventNotificationEmail/Attribute:bcc' => 'Blindkopie (BCC)',
'Class:EventNotificationEmail/Attribute:bcc+' => 'Blindkopie (BCC)',
'Class:EventNotificationEmail/Attribute:from' => 'Von',
'Class:EventNotificationEmail/Attribute:from+' => 'Absender der Nachricht',
'Class:EventNotificationEmail/Attribute:subject' => 'Betreff',
'Class:EventNotificationEmail/Attribute:subject+' => 'Betreff',
'Class:EventNotificationEmail/Attribute:body' => 'Inhalt der Nachricht',
'Class:EventNotificationEmail/Attribute:body+' => 'Inhalt der Nachricht',
'Class:EventIssue' => 'Issue Event',
'Class:EventIssue+' => 'Protokollierung einer Issue (Warnungen, Fehler, etc.)',
'Class:EventIssue/Attribute:issue' => 'Issue',
'Class:EventIssue/Attribute:issue+' => 'Was passierte?',
'Class:EventIssue/Attribute:impact' => 'Auswirkungen',
'Class:EventIssue/Attribute:impact+' => 'Was waren die Auswirkungen?',
'Class:EventIssue/Attribute:page' => 'Seite',
'Class:EventIssue/Attribute:page+' => 'HTTP entry point',
'Class:EventIssue/Attribute:arguments_post' => 'Eingegebene Arguments',
'Class:EventIssue/Attribute:arguments_post+' => 'HTTP POST-Argumente',
'Class:EventIssue/Attribute:arguments_get' => 'URL-Argumente',
'Class:EventIssue/Attribute:arguments_get+' => 'HTTP GET-Argumente',
'Class:EventIssue/Attribute:callstack' => 'Callstack',
'Class:EventIssue/Attribute:callstack+' => 'Call stack',
'Class:EventIssue/Attribute:data' => 'Daten',
'Class:EventIssue/Attribute:data+' => 'Mehr Informationen',
'Class:EventWebService' => 'Web Service Event',
'Class:EventWebService+' => 'Protokollierung eines Web Service Calls',
'Class:EventWebService/Attribute:verb' => 'Verb',
'Class:EventWebService/Attribute:verb+' => 'Name der Operation',
'Class:EventWebService/Attribute:result' => 'Ergebnis',
'Class:EventWebService/Attribute:result+' => 'Gesamterfolg/-misserfolg',
'Class:EventWebService/Attribute:log_info' => 'Informations-Protokollierung',
'Class:EventWebService/Attribute:log_info+' => 'Ergebnis der Informations-Protokollierung',
'Class:EventWebService/Attribute:log_warning' => 'Warnungs-Protokollierung',
'Class:EventWebService/Attribute:log_warning+' => 'Ergebnis der Warnungs-Protokollierung',
'Class:EventWebService/Attribute:log_error' => 'Fehler-Protokollierung',
'Class:EventWebService/Attribute:log_error+' => 'Ergebnis der Fehler-Protokollierung',
'Class:EventWebService/Attribute:data' => 'Daten',
'Class:EventWebService/Attribute:data+' => 'Ergebnisdaten',
'Class:EventLoginUsage' => 'Login Benutzung',
'Class:EventLoginUsage+' => '',
'Class:EventLoginUsage/Attribute:user_id' => 'Login',
'Class:EventLoginUsage/Attribute:user_id+' => '',
'Class:TriggerOnPortalUpdate' => 'Trigger (Update durch Portal)',
'Class:TriggerOnPortalUpdate+' => '',
'Class:SynchroDataSource' => 'Synchronisations-Datenquelle',
'Class:SynchroDataSource/Attribute:name' => 'Name',
'Class:SynchroDataSource/Attribute:name+' => 'Name',
'Class:SynchroDataSource/Attribute:description' => 'Beschreibung',
'Class:SynchroDataSource/Attribute:status' => 'Status',
'Class:SynchroDataSource/Attribute:status/Value:implementation' => 'Implementation',
'Class:SynchroDataSource/Attribute:status/Value:obsolete' => 'Obsolet',
'Class:SynchroDataSource/Attribute:status/Value:production' => 'Produktion',
'Class:SynchroDataSource/Attribute:user_id' => 'Benutzer',
'Class:SynchroDataSource/Attribute:notify_contact_id' => 'zu benachrichtigender Kontakt',
'Class:SynchroDataSource/Attribute:notify_contact_id+' => 'Kontakt, der im Fehlerfall benachrichtigt werden muß',
'Class:SynchroDataSource/Attribute:scope_class' => 'Ziel-Klasse',
'Class:SynchroDataSource/Attribute:scope_restriction' => 'Anwendungsbereich',
'Class:SynchroDataSource/Attribute:full_load_periodicity' => 'Intervall zwischen zwei vollständigen Reloads',
'Class:SynchroDataSource/Attribute:full_load_periodicity+' => 'Ein vollständiger Reload des gesamten Datenbestands muß mindestens in diesem Intervall erfolgen',
'Class:SynchroDataSource/Attribute:reconciliation_policy' => 'Abgleichsvorgehen',
'Class:SynchroDataSource/Attribute:reconciliation_policy/Value:use_attributes' => 'Attribute benutzen',
'Class:SynchroDataSource/Attribute:reconciliation_policy/Value:use_primary_key' => 'Feld primary_key benutzen',
'Class:SynchroDataSource/Attribute:action_on_zero' => 'Verhalten bei keinen Treffern',
'Class:SynchroDataSource/Attribute:action_on_zero+' => 'Verhalten, wenn die Suche keine Objekte zurückgibt',
'Class:SynchroDataSource/Attribute:action_on_zero/Value:create' => 'Erzeugen',
'Class:SynchroDataSource/Attribute:action_on_zero/Value:error' => 'Fehler',
'Class:SynchroDataSource/Attribute:action_on_one' => 'Verhalten bei einem Treffer',
'Class:SynchroDataSource/Attribute:action_on_one+' => 'Verhalten, wenn die Suche genau ein Objekt zurückgibt',
'Class:SynchroDataSource/Attribute:action_on_one/Value:error' => 'Fehler',
'Class:SynchroDataSource/Attribute:action_on_one/Value:update' => 'Update',
'Class:SynchroDataSource/Attribute:action_on_multiple' => 'Verhalten bei vielen Treffern',
'Class:SynchroDataSource/Attribute:action_on_multiple+' => 'Verhalten, wenn die Suche mehr als ein Objekt zurückgibt',
'Class:SynchroDataSource/Attribute:action_on_multiple/Value:create' => 'Erzeugen',
'Class:SynchroDataSource/Attribute:action_on_multiple/Value:error' => 'Fehler',
'Class:SynchroDataSource/Attribute:action_on_multiple/Value:take_first' => 'ersten Treffer benutzen',
'Class:SynchroDataSource/Attribute:delete_policy' => 'Löschungs-Policy',
'Class:SynchroDataSource/Attribute:delete_policy/Value:delete' => 'Löschen',
'Class:SynchroDataSource/Attribute:delete_policy/Value:ignore' => 'Ignorieren',
'Class:SynchroDataSource/Attribute:delete_policy/Value:update' => 'Update',
'Class:SynchroDataSource/Attribute:delete_policy/Value:update_then_delete' => 'Update, danach Löschen',
'Class:SynchroDataSource/Attribute:delete_policy_update' => 'Update-Regeln',
'Class:SynchroDataSource/Attribute:delete_policy_update+' => 'Syntax: Feld_Name:Wert; ...',
'Class:SynchroDataSource/Attribute:delete_policy_retention' => 'Zeitraum bis zur endgültigen Löschung',
'Class:SynchroDataSource/Attribute:delete_policy_retention+' => 'Zeitraum, nach dem ein obsoletes Objekt endgültig gelöscht wird',
'Class:SynchroDataSource/Attribute:attribute_list' => 'Liste der Attribute',
'Class:SynchroDataSource/Attribute:user_delete_policy' => 'zugelassene Benutzer',
'Class:SynchroDataSource/Attribute:user_delete_policy+' => 'Benutzer, die synchronisierte Objekte löschen dürfen',
'Class:SynchroDataSource/Attribute:user_delete_policy/Value:administrators' => 'nur Administratoren',
'Class:SynchroDataSource/Attribute:user_delete_policy/Value:everybody' => 'Jeder darf solche Objekte löschen',
'Class:SynchroDataSource/Attribute:user_delete_policy/Value:nobody' => 'Niemand',
'Class:SynchroDataSource/Attribute:url_icon' => 'Hyperlink zum Icon',
'Class:SynchroDataSource/Attribute:url_icon+' => 'Ein (kleines) Bild verlinken, das die Applikation repräsentiert, mit der iTop synchronisiert wird',
'Class:SynchroDataSource/Attribute:url_application' => 'Hyperlink zur Applikation',
'Class:SynchroDataSource/Attribute:url_application+' => 'Hyperlink zum iTop Objekt in der externen Applikation mit der iTop synchronisiert wird (falls anwendbar). Mögliche Platzhalter: $this->attribute$ und $replica->primary_key$',
'Class:SynchroAttribute' => 'Synchronisations-Attribut',
'Class:SynchroAttribute/Attribute:sync_source_id' => 'Synchronisations-Datenquelle',
'Class:SynchroAttribute/Attribute:attcode' => 'Attributs-Code',
'Class:SynchroAttribute/Attribute:update' => 'Update',
'Class:SynchroAttribute/Attribute:reconcile' => 'Abgleich',
'Class:SynchroAttribute/Attribute:update_policy' => 'Update Policy',
'Class:SynchroAttribute/Attribute:update_policy/Value:master_locked' => 'gesperrt',
'Class:SynchroAttribute/Attribute:update_policy/Value:master_unlocked' => 'entsperrt',
'Class:SynchroAttribute/Attribute:update_policy/Value:write_if_empty' => 'Initialisieren falls leer',
'Class:SynchroAttribute/Attribute:finalclass' => 'Klasse',
'Class:SynchroAttExtKey' => 'Synchronisations-Attribut (Externer Schlüssel)',
'Class:SynchroAttExtKey/Attribute:reconciliation_attcode' => 'Abgleichsattribut',
'Class:SynchroAttLinkSet' => 'Synchronisations-Attribut (Linkset)',
'Class:SynchroAttLinkSet/Attribute:row_separator' => 'Reihen-Trenner',
'Class:SynchroAttLinkSet/Attribute:attribute_separator' => 'Attributs-Trenner',
'Class:SynchroLog' => 'Synchronisations-Protokoll',
'Class:SynchroLog/Attribute:sync_source_id' => 'Synchronisations-Datenquelle',
'Class:SynchroLog/Attribute:start_date' => 'Anfangsdatum',
'Class:SynchroLog/Attribute:end_date' => 'Enddatum',
'Class:SynchroLog/Attribute:status' => 'Status',
'Class:SynchroLog/Attribute:status/Value:completed' => 'vervollständigt',
'Class:SynchroLog/Attribute:status/Value:error' => 'Fehler',
'Class:SynchroLog/Attribute:status/Value:running' => 'noch in Betrieb',
'Class:SynchroLog/Attribute:stats_nb_replica_seen' => 'Nb replica vorhanden',
'Class:SynchroLog/Attribute:stats_nb_replica_total' => 'Nb replica insgesamt',
'Class:SynchroLog/Attribute:stats_nb_obj_deleted' => 'Nb Objekte gelöscht',
'Class:SynchroLog/Attribute:stats_nb_obj_deleted_errors' => 'Nb Fehler während des Löschvorgangs',
'Class:SynchroLog/Attribute:stats_nb_obj_obsoleted' => 'Nb Objekte obsolet',
'Class:SynchroLog/Attribute:stats_nb_obj_obsoleted_errors' => 'Nb Fehler während des Obsolet-Machens',
'Class:SynchroLog/Attribute:stats_nb_obj_created' => 'Nb Objekte erzeugt',
'Class:SynchroLog/Attribute:stats_nb_obj_created_errors' => 'Nb oder Fehler während der Erzeugung',
'Class:SynchroLog/Attribute:stats_nb_obj_updated' => 'Nb Objekte aktualisiert',
'Class:SynchroLog/Attribute:stats_nb_obj_updated_errors' => 'Nb Fehler während der Aktualisierung',
'Class:SynchroLog/Attribute:stats_nb_replica_reconciled_errors' => 'Nb Fehler während des Abgleichs',
'Class:SynchroLog/Attribute:stats_nb_replica_disappeared_no_action' => 'Nb replica verschwunden',
'Class:SynchroLog/Attribute:stats_nb_obj_new_updated' => 'Nb Objekte aktualisiert',
'Class:SynchroLog/Attribute:stats_nb_obj_new_unchanged' => 'Nb Objekte nicht verändert',
'Class:SynchroLog/Attribute:last_error' => 'Letzter Fehler',
'Class:SynchroLog/Attribute:traces' => 'Traces',
'Class:SynchroReplica' => 'Synchronisations-Replica',
'Class:SynchroReplica/Attribute:sync_source_id' => 'Synchronisations-Datenquelle',
'Class:SynchroReplica/Attribute:dest_id' => 'Ziel-Objekt (ID)',
'Class:SynchroReplica/Attribute:dest_class' => 'Ziel-Typ',
'Class:SynchroReplica/Attribute:status_last_seen' => 'Zuletzt gesehen',
'Class:SynchroReplica/Attribute:status' => 'Status',
'Class:SynchroReplica/Attribute:status/Value:modified' => 'Modifiziert',
'Class:SynchroReplica/Attribute:status/Value:new' => 'Neu',
'Class:SynchroReplica/Attribute:status/Value:obsolete' => 'Obsolete',
'Class:SynchroReplica/Attribute:status/Value:orphan' => 'Verwaist',
'Class:SynchroReplica/Attribute:status/Value:synchronized' => 'Synchronisiert',
'Class:SynchroReplica/Attribute:status_dest_creator' => 'Objekt erzeugt',
'Class:SynchroReplica/Attribute:status_last_error' => 'Letzter Fehler',
'Class:SynchroReplica/Attribute:status_last_warning' => 'Letzte Warnung',
'Class:SynchroReplica/Attribute:info_creation_date' => 'Erzeugungs-Datum',
'Class:SynchroReplica/Attribute:info_last_modified' => 'Datum der letzten Modifikation',
'Class:SynchroDataSource/Attribute:database_table_name' => 'Datenbanktabelle',
'Class:SynchroDataSource/Attribute:database_table_name+' => 'Name der Tabelle, die Speicherung der Daten aus dieser Datenquelle. Ein Default-Name wird automatisch berechnet, wenn dieses Feld leer gelassen wird.',
'Class:SynchroDataSource/Error:DataTableAlreadyExists' => 'Tabelle %1$s existiert bereits in der Datenbank. Bitte benutzen Sie einen anderen Namen für die Datenbanktabelle aus dieser Datenquelle.',
'Class:appUserPreferences' => 'Benutzer-Voreinstellungen',
'Class:appUserPreferences/Attribute:userid' => 'Benutzer',
'Class:appUserPreferences/Attribute:preferences' => 'Voreinstellungen',
'Core:AttributeLinkedSet' => 'Array von Objekten',
'Core:AttributeLinkedSet+' => 'Beliebige Art von Objekten der [subclass] der selben Klasse',
'Core:AttributeLinkedSetIndirect' => 'Array von Objekten (N-N)',
'Core:AttributeLinkedSetIndirect+' => 'Beliebige Art von Objekten der [subclass] der selben Klasse',
'Core:AttributeInteger' => 'Integer',
'Core:AttributeInteger+' => 'Numerischer Wert (kann negativ sein)',
'Core:AttributeDecimal' => 'Decimal',
'Core:AttributeDecimal+' => 'Dezimaler Wert (kann negativ sein)',
'Core:AttributeBoolean' => 'Boolean',
'Core:AttributeBoolean+' => 'Boolscher Wert',
'Core:AttributeString' => 'String',
'Core:AttributeString+' => 'Alphanumerischer String',
'Core:AttributeClass' => 'Klasse',
'Core:AttributeClass+' => 'Klasse',
'Core:AttributeApplicationLanguage' => 'Benutzersprache',
'Core:AttributeApplicationLanguage+' => 'Sprache und Land (DE DE)',
'Core:AttributeFinalClass' => 'Finale Klasse (auto)',
'Core:AttributeFinalClass+' => 'Echte Klasse des Objekt (automatisch erstellt durch den Core)',
'Core:AttributePassword' => 'Passwort',
'Core:AttributePassword+' => 'Passwort eines externen Geräts',
'Core:AttributeEncryptedString' => 'verschlüsselter String',
'Core:AttributeEncryptedString+' => 'mit einem lokalen Schüssel verschlüsselter String',
'Core:AttributeText' => 'Text',
'Core:AttributeText+' => 'Mehrzeiliger String',
'Core:AttributeHTML' => 'HTML',
'Core:AttributeHTML+' => 'HTML-String',
'Core:AttributeEmailAddress' => 'Email-Adresse',
'Core:AttributeEmailAddress+' => 'Email-Adresse',
'Core:AttributeIPAddress' => 'IP-Adresse',
'Core:AttributeIPAddress+' => 'IP-Adresse',
'Core:AttributeOQL' => 'OQL',
'Core:AttributeOQL+' => 'Object-Query-Langage-Ausdruck',
'Core:AttributeEnum' => 'Enum',
'Core:AttributeEnum+' => 'Liste vordefinierter alphanumerischer Strings',
'Core:AttributeTemplateString' => 'Vorlagen-String',
'Core:AttributeTemplateString+' => 'String mit Platzhaltern',
'Core:AttributeTemplateText' => 'Vorlagen-Text',
'Core:AttributeTemplateText+' => 'Text mit Platzhaltern',
'Core:AttributeTemplateHTML' => 'Vorlagen-HTML',
'Core:AttributeTemplateHTML+' => 'HTML mit Platzhaltern',
'Core:AttributeDateTime' => 'Datum/Uhrzeit',
'Core:AttributeDateTime+' => 'Datum und Uhrzeit (Jahr-Monat-Tag 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>&gt;</b><em>date</em><br/>
<b>&lt;</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' => 'Datum',
'Core:AttributeDate+' => 'Datum (Jahr-Monat-Tag)',
'Core:AttributeDate?SmartSearch' => '
<p>
Date format:<br/>
<b>yyyy-mm-dd</b><br/>
Example: 2011-07-19
</p>
<p>
Operators:<br/>
<b>&gt;</b><em>date</em><br/>
<b>&lt;</b><em>date</em><br/>
<b>[</b><em>date</em>,<em>date</em><b>]</b>
</p>~~',
'Core:AttributeDeadline' => 'Frist',
'Core:AttributeDeadline+' => 'relativ zur aktuellen Zeit angezeigtes Datum',
'Core:AttributeExternalKey' => 'Externer Schlüssel',
'Core:AttributeExternalKey+' => 'Externer (oder fremder) Schlüssel',
'Core:AttributeExternalField' => 'Externes Feld',
'Core:AttributeExternalField+' => 'durch einen externen Schlüssel abgebildetes Feld',
'Core:AttributeURL' => 'URL',
'Core:AttributeURL+' => 'Absolute oder relative URL als Text-String',
'Core:AttributeBlob' => 'Blob',
'Core:AttributeBlob+' => 'Beliebiger binärer Inhalt (Dokument)',
'Core:AttributeOneWayPassword' => 'gehashtes Passwort',
'Core:AttributeOneWayPassword+' => 'gehashtes Passwort',
'Core:AttributeTable' => 'Tabelle',
'Core:AttributeTable+' => 'Indiziertes Array mit zwei Dimensionen',
'Core:AttributePropertySet' => 'Eigenschaften',
'Core:AttributePropertySet+' => 'Liste typloser Eigenschaften (Name und Wert)',
'Class:CMDBChangeOp/Attribute:date' => 'Datum',
'Class:CMDBChangeOp/Attribute:date+' => 'Datum und Uhrzeit der Änderungen',
'Class:CMDBChangeOp/Attribute:userinfo' => 'Benutzer',
'Class:CMDBChangeOp/Attribute:userinfo+' => 'Wer führte diese Änderung durch',
'Change:ObjectCreated' => 'Objekt erstellt',
'Change:ObjectDeleted' => 'Objekt gelöscht',
'Change:ObjectModified' => 'Objekt geändert',
'Change:AttName_SetTo_NewValue_PreviousValue_OldValue' => '%1$s geändert zu %2$s (vorheriger Wert: %3$s)',
'Change:AttName_SetTo' => '%1$s geändert zu %2$s',
'Change:Text_AppendedTo_AttName' => '%1$s zugefügt an %2$s',
'Change:AttName_Changed_PreviousValue_OldValue' => '%1$s modifiziert, vorheriger Wert: %2$s',
'Change:AttName_Changed' => '%1$s modifiziert',
'Change:AttName_EntryAdded' => '%1$s modifizeiert, neuer Eintrag hinzugefügt.',
'Class:EventLoginUsage/Attribute:contact_name' => 'User Name',
'Class:EventLoginUsage/Attribute:contact_name+' => '',
'Class:EventLoginUsage/Attribute:contact_email' => 'User Email',
'Class:EventLoginUsage/Attribute:contact_email+' => '',
'Class:Action' => 'Benutzerdefinierte Aktion',
'Class:Action+' => 'Benutzerdefinierte Aktionen',
'Class:Action/Attribute:name' => 'Name',
'Class:Action/Attribute:name+' => '',
'Class:Action/Attribute:description' => 'Beschreibung',
'Class:Action/Attribute:description+' => '',
'Class:Action/Attribute:status' => 'Status',
'Class:Action/Attribute:status+' => 'Im Einsatz oder ?',
'Class:Action/Attribute:status/Value:test' => 'Wird getestet',
'Class:Action/Attribute:status/Value:test+' => 'Wird getestet',
'Class:Action/Attribute:status/Value:enabled' => 'Im Einsatz',
'Class:Action/Attribute:status/Value:enabled+' => 'Im Einsatz',
'Class:Action/Attribute:status/Value:disabled' => 'Inaktiv',
'Class:Action/Attribute:status/Value:disabled+' => 'Inaktiv',
'Class:Action/Attribute:trigger_list' => 'Zugehörige Trigger',
'Class:Action/Attribute:trigger_list+' => 'Trigger, die mit dieser Aktion verknüpft sind',
'Class:Action/Attribute:finalclass' => 'Typ',
'Class:Action/Attribute:finalclass+' => '',
'Class:ActionNotification' => 'Benachrichtigung',
'Class:ActionNotification+' => 'Benachrichtigung (Kurzbeschreibung)',
'Class:Trigger' => 'Trigger',
'Class:Trigger+' => 'Definierbarer Ereignis-Handler',
'Class:Trigger/Attribute:description' => 'Beschreibung',
'Class:Trigger/Attribute:description+' => 'Kurzbeschreibung',
'Class:Trigger/Attribute:action_list' => 'Verbundene Trigger-Aktionen',
'Class:Trigger/Attribute:action_list+' => 'Aktionen, die ausgeführt werden, wenn der Trigger aktiviert ist',
'Class:Trigger/Attribute:finalclass' => 'Typ',
'Class:Trigger/Attribute:finalclass+' => '',
'Class:TriggerOnObject' => 'Trigger (klassenunabhängig)',
'Class:TriggerOnObject+' => 'Trigger einer gegebenen Klasse an Objekten',
'Class:TriggerOnObject/Attribute:target_class' => 'Zielklasse',
'Class:TriggerOnObject/Attribute:target_class+' => '',
'Class:TriggerOnStateChange' => 'Trigger (bei Statusänderung)',
'Class:TriggerOnStateChange+' => 'Trigger bei Änderung des Objektstatus',
'Class:TriggerOnStateChange/Attribute:state' => 'Status',
'Class:TriggerOnStateChange/Attribute:state+' => '',
'Class:lnkTriggerAction/Attribute:action_name' => 'Aktion',
'Class:lnkTriggerAction/Attribute:action_name+' => '',
'Class:lnkTriggerAction/Attribute:trigger_name' => 'Trigger',
'Class:lnkTriggerAction/Attribute:trigger_name+' => '',
'Class:SynchroDataSource/Attribute:delete_policy/Value:never' => 'Niemand',
'Class:SynchroDataSource/Attribute:delete_policy/Value:depends' => 'nur Administratoren',
'Class:SynchroDataSource/Attribute:delete_policy/Value:always' => 'Alle zugelassenen Benutzer',
'SynchroDataSource:Description' => 'Beschreibung',
'SynchroDataSource:Reconciliation' => 'Suche &amp; Abgleich',
'SynchroDataSource:Deletion' => 'Löschregeln',
'SynchroDataSource:Status' => 'Status',
'SynchroDataSource:Information' => 'Information',
'SynchroDataSource:Definition' => 'Definition',
'Core:SynchroAttributes' => 'Attribute',
'Core:SynchroStatus' => 'Status',
'Core:Synchro:ErrorsLabel' => 'Fehler',
'Core:Synchro:CreatedLabel' => 'erzeugt',
'Core:Synchro:ModifiedLabel' => 'modifiziert',
'Core:Synchro:UnchangedLabel' => 'unverändert',
'Core:Synchro:ReconciledErrorsLabel' => 'Fehler',
'Core:Synchro:ReconciledLabel' => 'abgeglichen',
'Core:Synchro:ReconciledNewLabel' => 'erzeugt',
'Core:SynchroReconcile:Yes' => 'Ja',
'Core:SynchroReconcile:No' => 'Nein',
'Core:SynchroUpdate:Yes' => 'Ja',
'Core:SynchroUpdate:No' => 'Nein',
'Core:Synchro:LastestStatus' => 'Neuester Status',
'Core:Synchro:History' => 'Synchronisations-Verlauf',
'Core:Synchro:NeverRun' => 'Synchronisation noch nicht erfolgt. Kein Protokoll verfügbar.',
'Core:Synchro:SynchroEndedOn_Date' => 'Die letzte Synchronisation endete um %1$s.',
'Core:Synchro:SynchroRunningStartedOn_Date' => 'Die Synchronisation, die um $1$s gestartet wurde, läuft noch ...',
'Menu:DataSources' => 'Datenquellen für die Synchronisation',
'Menu:DataSources+' => 'Alle Datenquellen für die Synchronisation',
'Core:Synchro:label_repl_ignored' => 'Ignoriert (%1$s)',
'Core:Synchro:label_repl_disappeared' => 'Verschwunden (%1$s)',
'Core:Synchro:label_repl_existing' => 'Vorhanden (%1$s)',
'Core:Synchro:label_repl_new' => 'Neu (%1$s)',
'Core:Synchro:label_obj_deleted' => 'gelöscht (%1$s)',
'Core:Synchro:label_obj_obsoleted' => 'obsolet (%1$s)',
'Core:Synchro:label_obj_disappeared_errors' => 'Fehler (%1$s)',
'Core:Synchro:label_obj_disappeared_no_action' => 'Keine Aktion (%1$s)',
'Core:Synchro:label_obj_unchanged' => 'unverändert (%1$s)',
'Core:Synchro:label_obj_updated' => 'Updated (%1$s)',
'Core:Synchro:label_obj_updated_errors' => 'Fehler (%1$s)',
'Core:Synchro:label_obj_new_unchanged' => 'unverändert (%1$s)',
'Core:Synchro:label_obj_new_updated' => 'updated (%1$s)',
'Core:Synchro:label_obj_created' => 'erzeugt (%1$s)',
'Core:Synchro:label_obj_new_errors' => 'Fehler (%1$s)',
'Core:SynchroLogTitle' => '%1$s - %2$s',
'Core:Synchro:Nb_Replica' => 'Replica verarbeitet: %1$s',
'Core:Synchro:Nb_Class:Objects' => '%1$s: %2$s',
'Class:SynchroDataSource/Error:AtLeastOneReconciliationKeyMustBeSpecified' => 'Mindestens ein Abgleichsschlüssel muß angegeben werden oder das Abgleichsvorgehen muß den primären Schlüssel verwenden.',
'Class:SynchroDataSource/Error:DeleteRetentionDurationMustBeSpecified' => 'Der Zeitraum bis zur endgültigen Löschung muß angegeben werden, da die Objekte nach einer Kennzeichnung als obsolet gelöscht werden.',
'Class:SynchroDataSource/Error:DeletePolicyUpdateMustBeSpecified' => 'Obsolete Objekte werden aktualisiert, aber es wurde keine Aktualisierung angegeben.',
'Core:SynchroReplica:PublicData' => 'Öffentliche Daten',
'Core:SynchroReplica:PrivateDetails' => 'Private Hinweise',
'Core:SynchroReplica:BackToDataSource' => 'Zurück zur Synchronisations-Datenquelle: %1$s',
'Core:SynchroReplica:ListOfReplicas' => 'Liste der Replica',
'Core:SynchroAttExtKey:ReconciliationById' => 'id (Primärschlüssel)',
'Core:SynchroAtt:attcode' => 'Attribut',
'Core:SynchroAtt:attcode+' => 'Feld des Objekts',
'Core:SynchroAtt:reconciliation' => 'Abgleich',
'Core:SynchroAtt:reconciliation+' => 'Für die Suche genutzt',
'Core:SynchroAtt:update' => 'Update',
'Core:SynchroAtt:update+' => 'Für die Aktualisierung des Objekts benutzt',
'Core:SynchroAtt:update_policy' => 'Update Policy',
'Core:SynchroAtt:update_policy+' => 'Verhalten des aktualisierten Feld',
'Core:SynchroAtt:reconciliation_attcode' => 'Abgleichsschlüssel',
'Core:SynchroAtt:reconciliation_attcode+' => 'Attributscode für den Abgleich über einen externen Schlüssel',
'Core:SyncDataExchangeComment' => '(DataExchange)',
'Core:Synchro:ListOfDataSources' => 'Liste der Datenquellen:',
'Core:Synchro:LastSynchro' => 'Letzte Synchronisation:',
'Core:Synchro:ThisObjectIsSynchronized' => 'Dieses Objekt wird mit einer externen Datenquelle synchronisiert',
'Core:Synchro:TheObjectWasCreatedBy_Source' => 'Das Objekt wurde durch die externe Datenquelle %1$s <b>erzeugt</b>',
'Core:Synchro:TheObjectCanBeDeletedBy_Source' => 'Das Objekt kann durch die externe Datenquelle %1$s <b>gelöscht werden</b>.',
'Core:Synchro:TheObjectCannotBeDeletedByUser_Source' => 'Sie <b>können das Objekt nicht löschen</b>, weil es zur externen Datenquelle %1$s gehört',
'TitleSynchroExecution' => 'Ausführung der Synchronisation',
'Class:SynchroDataSource:DataTable' => 'Datenbanktabelle: %1$s',
'Core:SyncDataSourceObsolete' => 'Die Datenquelle ist als obsolet markiert. Operation abgebrochen.',
'Core:SyncDataSourceAccessRestriction' => 'Nur Administratoren oder die in der Datenquelle angegebenen Benutzer können diese Operation ausführen. Operation abgebrochen.',
'Core:SyncTooManyMissingReplicas' => 'Alle Einträge wurden seit längerem nicht aktualisiert, alle Objekte könnten gelöscht werden. Bitte überprüfen Sie die Funktionalität der Synchronisation. Operation abgebrochen.',
'Core:Synchro:ListReplicas_AllReplicas_Errors_Warnings' => '%1$s Replicas, %2$s Fehler, %3$s Warnung(en).',
'Core:SynchroReplica:TargetObject' => 'Synchronisiertes Objekt: %1$s',
'Class:AsyncSendEmail/Attribute:body' => 'Body',
'Class:AsyncSendEmail/Attribute:header' => 'Header',
'Core:Duration_Seconds' => '%1$ds',
'Core:Duration_Minutes_Seconds' => '%1$dmin %2$ds',
'Core:Duration_Hours_Minutes_Seconds' => '%1$dh %2$dmin %3$ds',
'Core:Duration_Days_Hours_Minutes_Seconds' => '%1$sd %2$dh %3$dmin %4$ds',
));
?>

File diff suppressed because it is too large Load Diff

View File

@@ -23,6 +23,131 @@
* @license http://www.opensource.org/licenses/gpl-3.0.html LGPL
*/
Dict::Add('EN US', 'English', 'English', array(
'Core:AttributeLinkedSet' => 'Array of objects',
'Core:AttributeLinkedSet+' => 'Any kind of objects of the same class or subclass',
'Core:AttributeLinkedSetIndirect' => 'Array of objects (N-N)',
'Core:AttributeLinkedSetIndirect+' => 'Any kind of objects [subclass] of the same class',
'Core:AttributeInteger' => 'Integer',
'Core:AttributeInteger+' => 'Numeric value (could be negative)',
'Core:AttributeDecimal' => 'Decimal',
'Core:AttributeDecimal+' => 'Decimal value (could be negative)',
'Core:AttributeBoolean' => 'Boolean',
'Core:AttributeBoolean+' => 'Boolean',
'Core:AttributeString' => 'String',
'Core:AttributeString+' => 'Alphanumeric string',
'Core:AttributeClass' => 'Class',
'Core:AttributeClass+' => 'Class',
'Core:AttributeApplicationLanguage' => 'User language',
'Core:AttributeApplicationLanguage+' => 'Language and country (EN US)',
'Core:AttributeFinalClass' => 'Class (auto)',
'Core:AttributeFinalClass+' => 'Real class of the object (automatically created by the core)',
'Core:AttributePassword' => 'Password',
'Core:AttributePassword+' => 'Password of an external device',
'Core:AttributeEncryptedString' => 'Encrypted string',
'Core:AttributeEncryptedString+' => 'String encrypted with a local key',
'Core:AttributeText' => 'Text',
'Core:AttributeText+' => 'Multiline character string',
'Core:AttributeHTML' => 'HTML',
'Core:AttributeHTML+' => 'HTML string',
'Core:AttributeEmailAddress' => 'Email address',
'Core:AttributeEmailAddress+' => 'Email address',
'Core:AttributeIPAddress' => 'IP address',
'Core:AttributeIPAddress+' => 'IP address',
'Core:AttributeOQL' => 'OQL',
'Core:AttributeOQL+' => 'Object Query Langage expression',
'Core:AttributeEnum' => 'Enum',
'Core:AttributeEnum+' => 'List of predefined alphanumeric strings',
'Core:AttributeTemplateString' => 'Template string',
'Core:AttributeTemplateString+' => 'String containing placeholders',
'Core:AttributeTemplateText' => 'Template text',
'Core:AttributeTemplateText+' => 'Text containing placeholders',
'Core:AttributeTemplateHTML' => 'Template HTML',
'Core:AttributeTemplateHTML+' => 'HTML containing placeholders',
'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>&gt;</b><em>date</em><br/>
<b>&lt;</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>&gt;</b><em>date</em><br/>
<b>&lt;</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',
'Core:AttributeExternalKey' => 'External key',
'Core:AttributeExternalKey+' => 'External (or foreign) key',
'Core:AttributeExternalField' => 'External field',
'Core:AttributeExternalField+' => 'Field mapped to an external key',
'Core:AttributeURL' => 'URL',
'Core:AttributeURL+' => 'Absolute or relative URL as a text string',
'Core:AttributeBlob' => 'Blob',
'Core:AttributeBlob+' => 'Any binary content (document)',
'Core:AttributeOneWayPassword' => 'One way password',
'Core:AttributeOneWayPassword+' => 'One way encrypted (hashed) password',
'Core:AttributeTable' => 'Table',
'Core:AttributeTable+' => 'Indexed array having two dimensions',
'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' => 'Friendly name',
'Core:FriendlyName-Description' => 'Friendly name',
));
//////////////////////////////////////////////////////////////////////
// Classes in 'core/cmdb'
@@ -108,10 +233,13 @@ Dict::Add('EN US', 'English', 'English', array(
Dict::Add('EN US', 'English', 'English', array(
'Change:ObjectCreated' => 'Object created',
'Change:ObjectDeleted' => 'Object deleted',
'Change:ObjectModified' => 'Object modified',
'Change:AttName_SetTo_NewValue_PreviousValue_OldValue' => '%1$s set to %2$s (previous value: %3$s)',
'Change:AttName_SetTo' => '%1$s set to %2$s',
'Change:Text_AppendedTo_AttName' => '%1$s appended to %2$s',
'Change:AttName_Changed_PreviousValue_OldValue' => '%1$s modified, previous value: %2$s',
'Change:AttName_Changed' => '%1$s modified',
'Change:AttName_EntryAdded' => '%1$s modified, new entry added.',
));
//
@@ -143,13 +271,13 @@ Dict::Add('EN US', 'English', 'English', array(
Dict::Add('EN US', 'English', 'English', array(
'Class:Event' => 'Log Event',
'Class:Event+' => 'An application internal event',
'Class:Event/Attribute:message' => 'message',
'Class:Event/Attribute:message' => 'Message',
'Class:Event/Attribute:message+' => 'short description of the event',
'Class:Event/Attribute:date' => 'date',
'Class:Event/Attribute:date' => 'Date',
'Class:Event/Attribute:date+' => 'date and time at which the changes have been recorded',
'Class:Event/Attribute:userinfo' => 'user info',
'Class:Event/Attribute:userinfo' => 'User info',
'Class:Event/Attribute:userinfo+' => 'identification of the user that was doing the action that triggered this event',
'Class:Event/Attribute:finalclass' => 'type',
'Class:Event/Attribute:finalclass' => 'Type',
'Class:Event/Attribute:finalclass+' => '',
));
@@ -233,6 +361,21 @@ Dict::Add('EN US', 'English', 'English', array(
'Class:EventWebService/Attribute:data+' => 'Result data',
));
//
// Class: EventLoginUsage
//
Dict::Add('EN US', 'English', 'English', array(
'Class:EventLoginUsage' => 'Login Usage',
'Class:EventLoginUsage+' => 'Connection to the application',
'Class:EventLoginUsage/Attribute:user_id' => 'Login',
'Class:EventLoginUsage/Attribute:user_id+' => 'Login',
'Class:EventLoginUsage/Attribute:contact_name' => 'User Name',
'Class:EventLoginUsage/Attribute:contact_name+' => 'User Name',
'Class:EventLoginUsage/Attribute:contact_email' => 'User Email',
'Class:EventLoginUsage/Attribute:contact_email+' => 'Email Address of the User',
));
//
// Class: Action
//
@@ -326,6 +469,15 @@ Dict::Add('EN US', 'English', 'English', array(
'Class:TriggerOnObject/Attribute:target_class+' => '',
));
//
// Class: TriggerOnPortalUpdate
//
Dict::Add('EN US', 'English', 'English', array(
'Class:TriggerOnPortalUpdate' => 'Trigger (when updated from the portal)',
'Class:TriggerOnPortalUpdate+' => 'Trigger on a end-user\'s update from the portal',
));
//
// Class: TriggerOnStateChange
//
@@ -383,5 +535,226 @@ Dict::Add('EN US', 'English', 'English', array(
'Class:lnkTriggerAction/Attribute:order+' => 'Actions execution order',
));
//
// Synchro Data Source
//
Dict::Add('EN US', 'English', 'English', array(
'Class:SynchroDataSource/Attribute:name' => 'Name',
'Class:SynchroDataSource/Attribute:name+' => 'Name',
'Class:SynchroDataSource/Attribute:description' => 'Description',
'Class:SynchroDataSource/Attribute:status' => 'Status', //TODO: enum values
'Class:SynchroDataSource/Attribute:scope_class' => 'Target class',
'Class:SynchroDataSource/Attribute:user_id' => 'User',
'Class:SynchroDataSource/Attribute:notify_contact_id' => 'Contact to notify',
'Class:SynchroDataSource/Attribute:notify_contact_id+' => 'Contact to notify in case of error',
'Class:SynchroDataSource/Attribute:url_icon' => 'Icon\'s hyperlink',
'Class:SynchroDataSource/Attribute:url_icon+' => 'Hyperlink a (small) image representing the application with which iTop is synchronized',
'Class:SynchroDataSource/Attribute:url_application' => 'Application\'s hyperlink',
'Class:SynchroDataSource/Attribute:url_application+' => 'Hyperlink to the iTop object in the external application with which iTop is synchronized (if applicable). Possible placeholders: $this->attribute$ and $replica->primary_key$',
'Class:SynchroDataSource/Attribute:reconciliation_policy' => 'Reconciliation policy', //TODO enum values
'Class:SynchroDataSource/Attribute:full_load_periodicity' => 'Full load interval',
'Class:SynchroDataSource/Attribute:full_load_periodicity+' => 'A complete reload of all data must occur at least as often as specified here',
'Class:SynchroDataSource/Attribute:action_on_zero' => 'Action on zero',
'Class:SynchroDataSource/Attribute:action_on_zero+' => 'Action taken when the search returns no object',
'Class:SynchroDataSource/Attribute:action_on_one' => 'Action on one',
'Class:SynchroDataSource/Attribute:action_on_one+' => 'Action taken when the search returns exactly one object',
'Class:SynchroDataSource/Attribute:action_on_multiple' => 'Action on many',
'Class:SynchroDataSource/Attribute:action_on_multiple+' => 'Action taken when the search returns more than one object',
'Class:SynchroDataSource/Attribute:user_delete_policy' => 'Users allowed',
'Class:SynchroDataSource/Attribute:user_delete_policy+' => 'Who is allowed to delete synchronized objects',
'Class:SynchroDataSource/Attribute:user_delete_policy' => 'Users allowed',
'Class:SynchroDataSource/Attribute:delete_policy/Value:never' => 'Nobody',
'Class:SynchroDataSource/Attribute:delete_policy/Value:depends' => 'Administrators only',
'Class:SynchroDataSource/Attribute:delete_policy/Value:always' => 'All allowed users',
'Class:SynchroDataSource/Attribute:delete_policy_update' => 'Update rules',
'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 &amp; reconciliation',
'SynchroDataSource:Deletion' => 'Deletion rules',
'SynchroDataSource:Status' => 'Status',
'SynchroDataSource:Information' => 'Information',
'SynchroDataSource:Definition' => 'Definition',
'Core:SynchroAttributes' => 'Attributes',
'Core:SynchroStatus' => 'Status',
'Core:Synchro:ErrorsLabel' => 'Errors',
'Core:Synchro:CreatedLabel' => 'Created',
'Core:Synchro:ModifiedLabel' => 'Modified',
'Core:Synchro:UnchangedLabel' => 'Unchanged',
'Core:Synchro:ReconciledErrorsLabel' => 'Errors',
'Core:Synchro:ReconciledLabel' => 'Reconciled',
'Core:Synchro:ReconciledNewLabel' => 'Created',
'Core:SynchroReconcile:Yes' => 'Yes',
'Core:SynchroReconcile:No' => 'No',
'Core:SynchroUpdate:Yes' => 'Yes',
'Core:SynchroUpdate:No' => 'No',
'Core:Synchro:LastestStatus' => 'Latest Status',
'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...',
'Menu:DataSources' => 'Synchronization Data Sources',
'Menu:DataSources+' => 'All Synchronization Data Sources',
'Core:Synchro:label_repl_ignored' => 'Ignored (%1$s)',
'Core:Synchro:label_repl_disappeared' => 'Disappeared (%1$s)',
'Core:Synchro:label_repl_existing' => 'Existing (%1$s)',
'Core:Synchro:label_repl_new' => 'New (%1$s)',
'Core:Synchro:label_obj_deleted' => 'Deleted (%1$s)',
'Core:Synchro:label_obj_obsoleted' => 'Obsoleted (%1$s)',
'Core:Synchro:label_obj_disappeared_errors' => 'Errors (%1$s)',
'Core:Synchro:label_obj_disappeared_no_action' => 'No Action (%1$s)',
'Core:Synchro:label_obj_unchanged' => 'Unchanged (%1$s)',
'Core:Synchro:label_obj_updated' => 'Updated (%1$s)',
'Core:Synchro:label_obj_updated_errors' => 'Errors (%1$s)',
'Core:Synchro:label_obj_new_unchanged' => 'Unchanged (%1$s)',
'Core:Synchro:label_obj_new_updated' => 'Updated (%1$s)',
'Core:Synchro:label_obj_created' => 'Created (%1$s)',
'Core:Synchro:label_obj_new_errors' => 'Errors (%1$s)',
'Core:Synchro:History' => 'Synchronization History',
'Core:SynchroLogTitle' => '%1$s - %2$s',
'Core:Synchro:Nb_Replica' => 'Replica processed: %1$s',
'Core:Synchro:Nb_Class:Objects' => '%1$s: %2$s',
'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',
'Core:SynchroReplica:ListOfReplicas' => 'List of Replica',
'Core:SynchroAttExtKey:ReconciliationById' => 'id (Primary Key)',
'Core:SynchroAtt:attcode' => 'Attribute',
'Core:SynchroAtt:attcode+' => 'Field of the object',
'Core:SynchroAtt:reconciliation' => 'Reconciliation ?',
'Core:SynchroAtt:reconciliation+' => 'Used for searching',
'Core:SynchroAtt:update' => 'Update ?',
'Core:SynchroAtt:update+' => 'Used to update the object',
'Core:SynchroAtt:update_policy' => 'Update Policy',
'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' => '(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',
'Core:Synchro:TheObjectWasCreatedBy_Source' => 'The object was <b>created</b> by the external data source %1$s',
'Core:Synchro:TheObjectCanBeDeletedBy_Source' => 'The object <b>can be deleted</b> by the external data source %1$s',
'Core:Synchro:TheObjectCannotBeDeletedByUser_Source' => 'You <b>cannot delete the object</b> because it is owned by the external data source %1$s',
'TitleSynchroExecution' => 'Execution of the synchronization',
'Class:SynchroDataSource:DataTable' => 'Database table: %1$s',
'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',
'Class:AsyncSendEmail/Attribute:body' => 'Body',
'Class:AsyncSendEmail/Attribute:header' => 'Header',
'Class:CMDBChangeOpSetAttributeOneWayPassword' => 'Encrypted Password',
'Class:CMDBChangeOpSetAttributeOneWayPassword/Attribute:prev_pwd' => 'Previous Value',
'Class:CMDBChangeOpSetAttributeEncrypted' => 'Encrypted Field',
'Class:CMDBChangeOpSetAttributeEncrypted/Attribute:prevstring' => 'Previous Value',
'Class:CMDBChangeOpSetAttributeCaseLog' => 'Case Log',
'Class:CMDBChangeOpSetAttributeCaseLog/Attribute:lastentry' => 'Last Entry',
'Class:SynchroDataSource' => 'Synchro Data Source',
'Class:SynchroDataSource/Attribute:status/Value:implementation' => 'Implementation',
'Class:SynchroDataSource/Attribute:status/Value:obsolete' => 'Obsolete',
'Class:SynchroDataSource/Attribute:status/Value:production' => 'Production',
'Class:SynchroDataSource/Attribute:scope_restriction' => 'Scope restriction',
'Class:SynchroDataSource/Attribute:reconciliation_policy/Value:use_attributes' => 'Use the attributes',
'Class:SynchroDataSource/Attribute:reconciliation_policy/Value:use_primary_key' => 'Use the primary_key field',
'Class:SynchroDataSource/Attribute:action_on_zero/Value:create' => 'Create',
'Class:SynchroDataSource/Attribute:action_on_zero/Value:error' => 'Error',
'Class:SynchroDataSource/Attribute:action_on_one/Value:error' => 'Error',
'Class:SynchroDataSource/Attribute:action_on_one/Value:update' => 'Update',
'Class:SynchroDataSource/Attribute:action_on_multiple/Value:create' => 'Create',
'Class:SynchroDataSource/Attribute:action_on_multiple/Value:error' => 'Error',
'Class:SynchroDataSource/Attribute:action_on_multiple/Value:take_first' => 'Take the first one (random?)',
'Class:SynchroDataSource/Attribute:delete_policy' => 'Delete Policy',
'Class:SynchroDataSource/Attribute:delete_policy/Value:delete' => 'Delete',
'Class:SynchroDataSource/Attribute:delete_policy/Value:ignore' => 'Ignore',
'Class:SynchroDataSource/Attribute:delete_policy/Value:update' => 'Update',
'Class:SynchroDataSource/Attribute:delete_policy/Value:update_then_delete' => 'Update then Delete',
'Class:SynchroDataSource/Attribute:attribute_list' => 'Attributes List',
'Class:SynchroDataSource/Attribute:user_delete_policy/Value:administrators' => 'Administrators only',
'Class:SynchroDataSource/Attribute:user_delete_policy/Value:everybody' => 'Everybody allowed to delete such objects',
'Class:SynchroDataSource/Attribute:user_delete_policy/Value:nobody' => 'Nobody',
'Class:SynchroAttribute' => 'Synchro Attribute',
'Class:SynchroAttribute/Attribute:sync_source_id' => 'Sycnhro Data Source',
'Class:SynchroAttribute/Attribute:attcode' => 'Attribute Code',
'Class:SynchroAttribute/Attribute:update' => 'Update',
'Class:SynchroAttribute/Attribute:reconcile' => 'Reconcile',
'Class:SynchroAttribute/Attribute:update_policy' => 'Update Policy',
'Class:SynchroAttribute/Attribute:update_policy/Value:master_locked' => 'Locked',
'Class:SynchroAttribute/Attribute:update_policy/Value:master_unlocked' => 'Unlocked',
'Class:SynchroAttribute/Attribute:update_policy/Value:write_if_empty' => 'Initialize if empty',
'Class:SynchroAttribute/Attribute:finalclass' => 'Class',
'Class:SynchroAttExtKey' => 'Synchro Attribute (ExtKey)',
'Class:SynchroAttExtKey/Attribute:reconciliation_attcode' => 'Reconciliation Attribute',
'Class:SynchroAttLinkSet' => 'Synchro Attribute (Linkset)',
'Class:SynchroAttLinkSet/Attribute:row_separator' => 'Rows separator',
'Class:SynchroAttLinkSet/Attribute:attribute_separator' => 'Attributes separator',
'Class:SynchroLog' => 'Synchr Log',
'Class:SynchroLog/Attribute:sync_source_id' => 'Synchro Data Source',
'Class:SynchroLog/Attribute:start_date' => 'Start Date',
'Class:SynchroLog/Attribute:end_date' => 'End Date',
'Class:SynchroLog/Attribute:status' => 'Status',
'Class:SynchroLog/Attribute:status/Value:completed' => 'Completed',
'Class:SynchroLog/Attribute:status/Value:error' => 'Error',
'Class:SynchroLog/Attribute:status/Value:running' => 'Still Running',
'Class:SynchroLog/Attribute:stats_nb_replica_seen' => 'Nb replica seen',
'Class:SynchroLog/Attribute:stats_nb_replica_total' => 'Nb replica total',
'Class:SynchroLog/Attribute:stats_nb_obj_deleted' => 'Nb objects deleted',
'Class:SynchroLog/Attribute:stats_nb_obj_deleted_errors' => 'Nb of errors while deleting',
'Class:SynchroLog/Attribute:stats_nb_obj_obsoleted' => 'Nb objects obsoleted',
'Class:SynchroLog/Attribute:stats_nb_obj_obsoleted_errors' => 'Nb of errors while obsoleting',
'Class:SynchroLog/Attribute:stats_nb_obj_created' => 'Nb objects created',
'Class:SynchroLog/Attribute:stats_nb_obj_created_errors' => 'Nb or errors while creating',
'Class:SynchroLog/Attribute:stats_nb_obj_updated' => 'Nb objects updated',
'Class:SynchroLog/Attribute:stats_nb_obj_updated_errors' => 'Nb errors while updating',
'Class:SynchroLog/Attribute:stats_nb_replica_reconciled_errors' => 'Nb of errors during reconciliation',
'Class:SynchroLog/Attribute:stats_nb_replica_disappeared_no_action' => 'Nb replica disappeared',
'Class:SynchroLog/Attribute:stats_nb_obj_new_updated' => 'Nb objects updated',
'Class:SynchroLog/Attribute:stats_nb_obj_new_unchanged' => 'Nb objects unchanged',
'Class:SynchroLog/Attribute:last_error' => 'Last error',
'Class:SynchroLog/Attribute:traces' => 'Traces',
'Class:SynchroReplica' => 'Synchro Replica',
'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' => 'Last seen',
'Class:SynchroReplica/Attribute:status' => 'Status',
'Class:SynchroReplica/Attribute:status/Value:modified' => 'Modified',
'Class:SynchroReplica/Attribute:status/Value:new' => 'New',
'Class:SynchroReplica/Attribute:status/Value:obsolete' => 'Obsolete',
'Class:SynchroReplica/Attribute:status/Value:orphan' => 'Orphan',
'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)',
));
//
// Attribute Duration
//
Dict::Add('EN US', 'English', 'English', array(
'Core:Duration_Seconds' => '%1$ds',
'Core:Duration_Minutes_Seconds' =>'%1$dmin %2$ds',
'Core:Duration_Hours_Minutes_Seconds' => '%1$dh %2$dmin %3$ds',
'Core:Duration_Days_Hours_Minutes_Seconds' => '%1$sd %2$dh %3$dmin %4$ds',
));
?>

View File

@@ -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'
//////////////////////////////////////////////////////////////////////
@@ -336,6 +356,7 @@ Dict::Add('EN US', 'English', 'English', array(
'UI:Button:Cancel' => 'Cancel',
'UI:Button:Apply' => 'Apply',
'UI:Button:Back' => ' << Back ',
'UI:Button:Restart' => ' |<< Restart ',
'UI:Button:Next' => ' Next >> ',
'UI:Button:Finish' => ' Finish ',
'UI:Button:DoImport' => ' Run the Import ! ',
@@ -366,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.',
'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".',
@@ -398,14 +419,24 @@ Dict::Add('EN US', 'English', 'English', array(
'UI:History:LastModified_On_By' => 'Last modified on %1$s by %2$s.',
'UI:HistoryTab' => 'History',
'UI:NotificationsTab' => 'Notifications',
'UI:History:BulkImports' => 'History',
'UI:History:BulkImports+' => 'List of CSV imports (latest import first)',
'UI:History:BulkImportDetails' => 'Changes resulting from the CSV import performed on %1$s (by %2$s)',
'UI:History:Date' => 'Date',
'UI:History:Date+' => 'Date of the change',
'UI:History:User' => 'User',
'UI:History:User+' => 'User who made the change',
'UI:History:Changes' => 'Changes',
'UI:History:Changes+' => 'Changes made to the object',
'UI:History:StatsCreations' => 'Created',
'UI:History:StatsCreations+' => 'Count of objects created',
'UI:History:StatsModifs' => 'Modified',
'UI:History:StatsModifs+' => 'Count of objects modified',
'UI:History:StatsDeletes' => 'Deleted',
'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...',
@@ -418,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',
@@ -437,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',
@@ -446,6 +480,9 @@ Dict::Add('EN US', 'English', 'English', array(
'UI:LogOff:ThankYou' => 'Thank you for using iTop',
'UI:LogOff:ClickHereToLoginAgain' => 'Click here to login again...',
'UI:ChangePwdMenu' => 'Change Password...',
'UI:Login:PasswordChanged' => 'Password successfully set !',
'UI:AccessRO-All' => 'iTop is read-only',
'UI:AccessRO-Users' => 'iTop is read-only for end-users',
'UI:Login:RetypePwdDoesNotMatch' => 'New password and retyped new password do not match !',
'UI:Button:Login' => 'Enter iTop',
'UI:Login:Error:AccessRestricted' => 'iTop access is restricted. Please, contact an iTop administrator.',
@@ -461,6 +498,7 @@ Dict::Add('EN US', 'English', 'English', array(
'UI:CSVImport:idField' => 'id (Primary Key)',
'UI:Title:BulkImport' => 'iTop - Bulk import',
'UI:Title:BulkImport+' => 'CSV Import Wizard',
'UI:Title:BulkSynchro_nbItem_ofClass_class' => 'Synchronization of %1$d objects of class %2$s',
'UI:CSVImport:ClassesSelectOne' => '-- select one --',
'UI:CSVImport:ErrorExtendedAttCode' => 'Internal error: "%1$s" is an incorrect code because "%2$s" is NOT an external key of the class "%3$s"',
'UI:CSVImport:ObjectsWillStayUnchanged' => '%1$d objects(s) will stay unchanged.',
@@ -517,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',
@@ -529,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',
@@ -589,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: ',
@@ -603,15 +643,17 @@ 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',
'UI:Delete:NotAllowedToDelete' => 'You are not allowed to delete this object',
'UI:Delete:NotAllowedToUpdate_Fields' => 'You are not allowed to update the following field(s): %1$s',
'UI:Error:NotEnoughRightsToDelete' => 'This object could not be deleted because the current user do not have sufficient rights',
'UI:Error:CannotDeleteBecause' => 'This object could not be deleted because: %1$s',
'UI:Error:CannotDeleteBecauseOfDepencies' => 'This object could not be deleted because some manual operations must be performed prior to that',
'UI:Error:CannotDeleteBecauseManualOpNeeded' => 'This object could not be deleted because some manual operations must be performed prior to that',
'UI:Archive_User_OnBehalfOf_User' => '%1$s on behalf of %2$s',
'UI:Delete:Deleted' => 'deleted',
'UI:Delete:AutomaticallyDeleted' => 'automatically deleted',
'UI:Delete:AutomaticResetOf_Fields' => 'automatic reset of field(s): %1$s',
'UI:Delete:CleaningUpRefencesTo_Object' => 'Cleaning up all references to %1$s...',
@@ -620,8 +662,9 @@ Dict::Add('EN US', 'English', 'English', array(
'UI:Delete:_Name_Class_Deleted' => '%1$s - %2$s deleted.',
'UI:Delete:ConfirmDeletionOf_Name' => 'Deletion of %1$s',
'UI:Delete:ConfirmDeletionOf_Count_ObjectsOf_Class' => 'Deletion of %1$d objects of class %2$s',
'UI:Delete:ShouldBeDeletedAtomaticallyButNotAllowed' => 'Should be automaticaly deleted, but you are not allowed to do so',
'UI:Delete:MustBeDeletedManuallyButNotAllowed' => 'Must be deleted manually - but you are not allowed to delete this object, please contact your application admin',
'UI:Delete:CannotDeleteBecause' => 'Could not be deleted: %1$s',
'UI:Delete:ShouldBeDeletedAtomaticallyButNotPossible' => 'Should be automaticaly deleted, but this is not feasible: %1$s',
'UI:Delete:MustBeDeletedManuallyButNotPossible' => 'Must be deleted manually, but this is not feasible: %1$s',
'UI:Delete:WillBeDeletedAutomatically' => 'Will be automaticaly deleted',
'UI:Delete:MustBeDeletedManually' => 'Must be deleted manually',
'UI:Delete:CannotUpdateBecause_Issue' => 'Should be automatically updated, but: %1$s',
@@ -802,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',
@@ -842,14 +888,20 @@ When associated with a trigger, each action is given an "order" number, specifyi
'UI:DisplayThisMessageAtStartup' => 'Display this message at startup',
'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',
@@ -857,12 +909,61 @@ 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',
'Portal:AddAttachment' => ' Add Attachment ',
'Portal:RemoveAttachment' => ' Remove Attachment ',
'Portal:Attachment_No_To_Ticket_Name' => 'Attachment #%1$d to %2$s (%3$s)',
'Enum:Undefined' => 'Undefined',
'UI:DurationForm_Days_Hours_Minutes_Seconds' => '%1$s Days %2$s Hours %3$s Minutes %4$s Seconds',
'UI:ModifyAllPageTitle' => 'Modify All',
'UI:Modify_N_ObjectsOf_Class' => 'Modifying %1$d objects of class %2$s',
'UI:Modify_M_ObjectsOf_Class_OutOf_N' => 'Modifying %1$d objects of class %2$s out of %3$d',
'UI:Menu:ModifyAll' => 'Modify...',
'UI:Button:ModifyAll' => 'Modify All',
'UI:Button:PreviewModifications' => 'Preview Modifications >>',
'UI:ModifiedObject' => 'Object Modified',
'UI:BulkModifyStatus' => 'Operation',
'UI:BulkModifyStatus+' => 'Status of the operation',
'UI:BulkModifyErrors' => 'Errors (if any)',
'UI:BulkModifyErrors+' => 'Errors preventing the modification',
'UI:BulkModifyStatusOk' => 'Ok',
'UI:BulkModifyStatusError' => 'Error',
'UI:BulkModifyStatusModified' => 'Modified',
'UI:BulkModifyStatusSkipped' => 'Skipped',
'UI:BulkModify_Count_DistinctValues' => '%1$d distinct values:',
'UI:BulkModify:Value_Exists_N_Times' => '%1$s, %2$d time(s)',
'UI:BulkModify:N_MoreValues' => '%1$d more values...',
'UI:AttemptingToSetAReadOnlyAttribute_Name' => 'Attempting to set the read-only field: %1$s',
'UI:FailedToApplyStimuli' => 'The action has failed.',
'UI:StimulusModify_N_ObjectsOf_Class' => '%1$s: Modifying %2$d objects of class %3$s',
'UI:CaseLogTypeYourTextHere' => 'Type your text here:',
'UI:CaseLog:DateFormat' => 'Y-m-d H:i:s',
'UI:CaseLog:Header_Date_UserName' => '%1$s - %2$s:',
'UI:CaseLog:InitialValue' => 'Initial value:',
'UI:AttemptingToSetASlaveAttribute_Name' => 'The field %1$s is not writable because it is mastered by the data synchronization. Value not set.',
'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: ',
'UI:Button:Refresh' => 'Refresh',
'UI:iTopLogin' => 'iTop Login',
));
?>

View File

@@ -29,6 +29,99 @@
//////////////////////////////////////////////////////////////////////
//
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',
'Core:AttributeLinkedSetIndirect' => 'Array of objects (N-N)',
'Core:AttributeLinkedSetIndirect+' => 'Any kind of objects [subclass] of the same class',
'Core:AttributeInteger' => 'Integer',
'Core:AttributeInteger+' => 'Numeric value (could be negative)',
'Core:AttributeDecimal' => 'Decimal',
'Core:AttributeDecimal+' => 'Decimal value (could be negative)',
'Core:AttributeBoolean' => 'Boolean',
'Core:AttributeBoolean+' => 'Boolean',
'Core:AttributeString' => 'String',
'Core:AttributeString+' => 'Alphanumeric string',
'Core:AttributeClass' => 'Class',
'Core:AttributeClass+' => 'Class',
'Core:AttributeApplicationLanguage' => 'User language',
'Core:AttributeApplicationLanguage+' => 'Language and country (EN US)',
'Core:AttributeFinalClass' => 'Class (auto)',
'Core:AttributeFinalClass+' => 'Real class of the object (automatically created by the core)',
'Core:AttributePassword' => 'Password',
'Core:AttributePassword+' => 'Password of an external device',
'Core:AttributeEncryptedString' => 'Encrypted string',
'Core:AttributeEncryptedString+' => 'String encrypted with a local key',
'Core:AttributeText' => 'Text',
'Core:AttributeText+' => 'Multiline character string',
'Core:AttributeHTML' => 'HTML',
'Core:AttributeHTML+' => 'HTML string',
'Core:AttributeEmailAddress' => 'Email address',
'Core:AttributeEmailAddress+' => 'Email address',
'Core:AttributeIPAddress' => 'IP address',
'Core:AttributeIPAddress+' => 'IP address',
'Core:AttributeOQL' => 'OQL',
'Core:AttributeOQL+' => 'Object Query Langage expression',
'Core:AttributeEnum' => 'Enum',
'Core:AttributeEnum+' => 'List of predefined alphanumeric strings',
'Core:AttributeTemplateString' => 'Template string',
'Core:AttributeTemplateString+' => 'String containing placeholders',
'Core:AttributeTemplateText' => 'Template text',
'Core:AttributeTemplateText+' => 'Text containing placeholders',
'Core:AttributeTemplateHTML' => 'Template HTML',
'Core:AttributeTemplateHTML+' => 'HTML containing placeholders',
'Core:AttributeDateTime' => 'Date/time',
'Core:AttributeDateTime+' => 'Date and time (year-month-day hh:mm:ss)',
'Core:AttributeDate' => 'Date',
'Core:AttributeDate+' => 'Date (year-month-day)',
'Core:AttributeDeadline' => 'Deadline',
'Core:AttributeDeadline+' => 'Date, displayed relatively to the current time',
'Core:AttributeExternalKey' => 'External key',
'Core:AttributeExternalKey+' => 'External (or foreign) key',
'Core:AttributeExternalField' => 'External field',
'Core:AttributeExternalField+' => 'Field mapped from an external key',
'Core:AttributeURL' => 'URL',
'Core:AttributeURL+' => 'Absolute or relative URL as a text string',
'Core:AttributeBlob' => 'Blob',
'Core:AttributeBlob+' => 'Any binary content (document)',
'Core:AttributeOneWayPassword' => 'One way password',
'Core:AttributeOneWayPassword+' => 'One way encrypted (hashed) password',
'Core:AttributeTable' => 'Table',
'Core:AttributeTable+' => 'Indexed array having two dimensions',
'Core:AttributePropertySet' => 'Properties',
'Core:AttributePropertySet+' => 'List of untyped properties (name and value)',
));
//
// Class: CMDBChange
//
@@ -107,6 +200,7 @@ Dict::Add('ES CR', 'Spanish', 'Español, Castellano', array(
// Used by CMDBChangeOp... & derived classes
Dict::Add('ES CR', 'Spanish', 'Español, Castellano', array(
'Change:AttName_SetTo_NewValue_PreviousValue_OldValue' => '%1$s modificado en %2$s (valor anterior: %3$s)',
'Change:AttName_SetTo' => '%1$s modificado en %2$s',
'Change:Text_AppendedTo_AttName' => '%1$s añadido a %2$s',
'Change:AttName_Changed_PreviousValue_OldValue' => '%1$s modificado, valor anterior: %2$s',
'Change:AttName_Changed' => '%1$s modificado',

View File

@@ -304,494 +304,499 @@ Dict::Add('ES CR', 'Spanish', 'Español, Castellano', array(
'Menu:WelcomeMenuPage+' => 'Bienvenido a iTop',
'UI:WelcomeMenu:Title' => 'Bienvenido a iTop',
'UI:WelcomeMenu:LeftBlock' => '<p>iTop es un completo; portal IT funcioanl basado en código abierto (OpenSource).</p>
'UI:WelcomeMenu:LeftBlock' => '<p>iTop es un completo; portal IT funcional basado en código abierto (OpenSource).</p>
<ul>Incluye:
<li>Una CMDB competa (Configuration management database) para documentar y manejar el inverntario de TI..</li>
<li>Un módul de gestión de incidentes, para llevar la trazabilidad y comunicar los eventos que estan afectando IT.</li>
<li>Un módulo de gestion de cambio para planear y llevar la trazabilidad hechos al ambiente de TI.</li>
<li>Un módulo de gestion de cambio para planear y llevar la trazabilidad de cambios hechos al ambiente de TI.</li>
<li>Una base de conocimiento para acelerar la correción de incidentes.</li>
<li>Un moódulo de Cortes/Caídas para documentar todas las caídas planeadas o no y notificar a los contactods del caso.</li>
<li>Tableros de controles para rapidamente tener visión general del ambiente TI..</li>
</ul>
<p>All the modules can be setup, step by step, indepently of each other.</p>',
<p>Todos los modulos pueden ser configurados, paso a paso, individual e independientemente de los otros.</p>',
'UI:WelcomeMenu:RightBlock' => '<p>iTop is service provider oriented, it allows IT engineers to manage easily multiple customers or organizations.
<ul>iTop, delivers a feature-rich set of business processes that:
<li>Enhances IT management effectiveness</li>
<li>Drives IT operations performance</li>
<li>Improves customer satisfaction and provides executives with insights into business performance.</li>
'UI:WelcomeMenu:RightBlock' => '<p>iTop esta orientada a los proveedores de servicios, le permite a los Ingenieros de TI administrar facilmente multiples clientes y organizaciones.
<ul>iTop, provee un conjunto de funciones de procesos de negocio que:
<li>Mejora Enhances IT management effectiveness</li>
<li>Dirige el desempeño de la operaciones de TI</li>
<li>Incrementa la satisfaccion del cliente y provee a los ejecutivos con detalles del desempeño del negocio.</li>
</ul>
</p>
<p>iTop is completely opened to be integrated within your current IT Management infrastructure.</p>
<p>iTop es completamente abierto para ser integrado con su actual infraestructura de Gestion de TI.</p>
<p>
<ul>Adopting this new generation of IT Operational portal will help you to:
<li>Better manage a more and more complex IT environment.</li>
<li>Implement ITIL processes at your own pace.</li>
<li>Manage the most important asset of your IT: Documentation.</li>
<ul>Adoptar esta nueva generacion de portales de operaciones de TI le ayudara a:
<li>Mejorar gestion de entornos de TI mas y mas complejos.</li>
<li>Implementar los procesos de ITIL a su propio ritmo.</li>
<li>Administrar el bien mas importante de su TI: Documentacion.</li>
</ul>
</p>',
'UI:WelcomeMenu:MyCalls' => 'My requests',
'UI:WelcomeMenu:MyIncidents' => 'Incidents assigned to me',
'UI:AllOrganizations' => ' All Organizations ',
'UI:YourSearch' => 'Your Search',
'UI:LoggedAsMessage' => 'Logged in as %1$s',
'UI:LoggedAsMessage+Admin' => 'Logged in as %1$s (Administrator)',
'UI:Button:Logoff' => 'Log off',
'UI:Button:GlobalSearch' => 'Search',
'UI:Button:Search' => ' Search ',
'UI:Button:Query' => ' Query ',
'UI:WelcomeMenu:MyCalls' => 'Mis solicitudes',
'UI:WelcomeMenu:MyIncidents' => 'Incidentes asignados a mi',
'UI:AllOrganizations' => ' Todas las Organizaciones',
'UI:YourSearch' => 'Su busqueda',
'UI:LoggedAsMessage' => 'Conectado como %1$s',
'UI:LoggedAsMessage+Admin' => 'Conectado como %1$s (Administrator)',
'UI:Button:Logoff' => 'Cerrar sesion',
'UI:Button:GlobalSearch' => 'Buscar',
'UI:Button:Search' => ' Buscar ',
'UI:Button:Query' => ' Consulta ',
'UI:Button:Ok' => 'Ok',
'UI:Button:Cancel' => 'Cancel',
'UI:Button:Apply' => 'Apply',
'UI:Button:Back' => ' << Back ',
'UI:Button:Next' => ' Next >> ',
'UI:Button:Finish' => ' Finish ',
'UI:Button:DoImport' => ' Run the Import ! ',
'UI:Button:Done' => ' Done ',
'UI:Button:SimulateImport' => ' Simulate the Import ',
'UI:Button:Test' => 'Test!',
'UI:Button:Evaluate' => ' Evaluate ',
'UI:Button:AddObject' => ' Add... ',
'UI:Button:BrowseObjects' => ' Browse... ',
'UI:Button:Add' => ' Add ',
'UI:Button:AddToList' => ' << Add ',
'UI:Button:RemoveFromList' => ' Remove >> ',
'UI:Button:FilterList' => ' Filter... ',
'UI:Button:Create' => ' Create ',
'UI:Button:Delete' => ' Delete ! ',
'UI:Button:ChangePassword' => ' Change Password ',
'UI:Button:ResetPassword' => ' Reset Password ',
'UI:Button:Cancel' => 'Cancelar',
'UI:Button:Apply' => 'Aplicar',
'UI:Button:Back' => ' << Anterior ',
'UI:Button:Next' => ' Siguiente >> ',
'UI:Button:Finish' => ' Finalizar ',
'UI:Button:DoImport' => ' Importar los datos ! ',
'UI:Button:Done' => ' Listo ',
'UI:Button:SimulateImport' => ' Simular la Importacion ',
'UI:Button:Test' => 'Probar!',
'UI:Button:Evaluate' => ' Evaluar ',
'UI:Button:AddObject' => ' Agregar... ',
'UI:Button:BrowseObjects' => ' Examinar... ',
'UI:Button:Add' => ' agregar ',
'UI:Button:AddToList' => ' << Agregar ',
'UI:Button:RemoveFromList' => ' Remover >> ',
'UI:Button:FilterList' => ' Filtrar... ',
'UI:Button:Create' => ' Crear ',
'UI:Button:Delete' => ' Borrar! ',
'UI:Button:ChangePassword' => ' Cambiar Contraseña',
'UI:Button:ResetPassword' => ' Restablecer Contraseña',
'UI:SearchToggle' => 'Search',
'UI:SearchToggle' => 'Buscar',
'UI:ClickToCreateNew' => 'Crear un nuevo %1$s',
'UI:SearchFor_Class' => 'Buscar %1$s objetos',
'UI:NoObjectToDisplay' => 'Ningún objeto para visualizar.',
'UI:Error:MandatoryTemplateParameter_object_id' => 'Parameter object_id is mandatory when link_attr is specified. Check the definition of the display template.',
'UI:Error:MandatoryTemplateParameter_target_attr' => 'Parameter target_attr is mandatory when link_attr is specified. Check the definition of the display template.',
'UI:Error:MandatoryTemplateParameter_group_by' => 'Parameter group_by is mandatory. Check the definition of the display template.',
'UI:Error:InvalidGroupByFields' => 'Invalid list of fields to group by: "%1$s".',
'UI:Error:UnsupportedStyleOfBlock' => 'Error: unsupported style of block: "%1$s".',
'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.',
'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".',
'UI:Error:UploadStoppedByExtension_FileName' => 'Upload stopped by extension. (Original file name = "%1$s").',
'UI:Error:UploadFailedUnknownCause_Code' => 'File upload failed, unknown cause. (Error code = "%1$s").',
'UI:Error:MandatoryTemplateParameter_object_id' => 'El parametro object_id es obligatorio cuando link_attr es especificado. Verifique la definicion de la plantilla de visualizacion.',
'UI:Error:MandatoryTemplateParameter_target_attr' => 'El parametro target_attr es obligatorio cuando link_attr es especificado. Verifique la definicion de la plantilla de visualizacion.',
'UI:Error:MandatoryTemplateParameter_group_by' => 'El parametro group_by es obligatorio. Verifique la definicion de la plantilla de visualizacion.',
'UI:Error:InvalidGroupByFields' => 'La lista de campos para agrupar por: "%1$s" es invalida.',
'UI:Error:UnsupportedStyleOfBlock' => 'Error: Estilo de bloque no soportado: "%1$s".',
'UI:Error:IncorrectLinkDefinition_LinkedClass_Class' => 'Definicio de vinculo incorrecto: la clase de objeto a administrar : %1$s no fue encontrada como clave externa en la clase %2$s',
'UI:Error:Object_Class_Id_NotFound' => 'No se encontro el objeto: %1$s:%2$d.',
'UI:Error:WizardCircularReferenceInDependencies' => 'Error: Verifique el modelo de datos, Existen referencias cisculares en la dependencias entre los campos.',
'UI:Error:UploadedFileTooBig' => 'archivo cargado es muy grande. (tamaño maximo permitido es de %1$s. Verifique su configuracion de PHP para upload_max_filesize.',
'UI:Error:UploadedFileTruncated.' => 'El archivo cargado ha sido truncado!',
'UI:Error:NoTmpDir' => 'El directorio temporal no ha sido definido.',
'UI:Error:CannotWriteToTmp_Dir' => 'No fue posible escribir el archivo temporal al disco. upload_tmp_dir = "%1$s".',
'UI:Error:UploadStoppedByExtension_FileName' => 'Carga de archivo interrumpida por la extension. (Nombre de archivo original = "%1$s").',
'UI:Error:UploadFailedUnknownCause_Code' => 'Carga de archivo fallida, causa desconocida. (Codigo de error = "%1$s").',
'UI:Error:1ParametersMissing' => 'Error: the following parameter must be specified for this operation: %1$s.',
'UI:Error:2ParametersMissing' => 'Error: the following parameters must be specified for this operation: %1$s and %2$s.',
'UI:Error:3ParametersMissing' => 'Error: the following parameters must be specified for this operation: %1$s, %2$s and %3$s.',
'UI:Error:4ParametersMissing' => 'Error: the following parameters must be specified for this operation: %1$s, %2$s, %3$s and %4$s.',
'UI:Error:IncorrectOQLQuery_Message' => 'Error: incorrect OQL query: %1$s',
'UI:Error:AnErrorOccuredWhileRunningTheQuery_Message' => 'An error occured while running the query: %1$s',
'UI:Error:ObjectAlreadyUpdated' => 'Error: the object has already been updated.',
'UI:Error:ObjectCannotBeUpdated' => 'Error: object cannot be updated.',
'UI:Error:ObjectsAlreadyDeleted' => 'Error: objects have already been deleted!',
'UI:Error:BulkDeleteNotAllowedOn_Class' => 'You are not allowed to perform a bulk delete of objects of class %1$s',
'UI:Error:DeleteNotAllowedOn_Class' => 'You are not allowed to delete objects of class %1$s',
'UI:Error:BulkModifyNotAllowedOn_Class' => 'You are not allowed to perform a bulk update of objects of class %1$s',
'UI:Error:ObjectAlreadyCloned' => 'Error: the object has already been cloned!',
'UI:Error:ObjectAlreadyCreated' => 'Error: the object has already been created!',
'UI:Error:Invalid_Stimulus_On_Object_In_State' => 'Error: invalid stimulus "%1$s" on object %2$s in state "%3$s".',
'UI:Error:1ParametersMissing' => 'Error: El siguiente parametro debe ser especificado para esta operacion: %1$s.',
'UI:Error:2ParametersMissing' => 'Error: Los siguientes parametros deben ser especificados para esta operacion: %1$s and %2$s.',
'UI:Error:3ParametersMissing' => 'Error: Los siguientes parametros deben ser especificados para esta operacion: %1$s, %2$s and %3$s.',
'UI:Error:4ParametersMissing' => 'Error: Los siguientes parametros deben ser especificados para esta operacion: %1$s, %2$s, %3$s and %4$s.',
'UI:Error:IncorrectOQLQuery_Message' => 'Error: Consulta OQL incorrecta: %1$s',
'UI:Error:AnErrorOccuredWhileRunningTheQuery_Message' => 'Se ha producido un error al ejecutar la consulta: %1$s',
'UI:Error:ObjectAlreadyUpdated' => 'Error: el objeta ha sido previamente actualizado.',
'UI:Error:ObjectCannotBeUpdated' => 'Error: el objeto no puede ser actualizado.',
'UI:Error:ObjectsAlreadyDeleted' => 'Error: los objetos ya han sido borrados!',
'UI:Error:BulkDeleteNotAllowedOn_Class' => 'No esta autorizado a borrar un lote de de objetos de la clase %1$s',
'UI:Error:DeleteNotAllowedOn_Class' => 'No esta autorizado a borrar objetos del la clase %1$s',
'UI:Error:BulkModifyNotAllowedOn_Class' => 'No esta autorizado a actualizar un lote de de objetos de la clase %1$s',
'UI:Error:ObjectAlreadyCloned' => 'Error: el objeto ha sido previamente duplicado!',
'UI:Error:ObjectAlreadyCreated' => 'Error: el objeto ha sido previamente creado!',
'UI:Error:Invalid_Stimulus_On_Object_In_State' => 'Error: estimulo invalido "%1$s" en objeto %2$s en estado "%3$s".',
'UI:GroupBy:Count' => 'Count',
'UI:GroupBy:Count+' => 'Number of elements',
'UI:CountOfObjects' => '%1$d objects matching the criteria.',
'UI_CountOfObjectsShort' => '%1$d objects.',
'UI:NoObject_Class_ToDisplay' => 'No %1$s to display',
'UI:History:LastModified_On_By' => 'Last modified on %1$s by %2$s.',
'UI:HistoryTab' => 'History',
'UI:History:Date' => 'Date',
'UI:History:Date+' => 'Date of the change',
'UI:History:User' => 'User',
'UI:History:User+' => 'User who made the change',
'UI:History:Changes' => 'Changes',
'UI:History:Changes+' => 'Changes made to the object',
'UI:Loading' => 'Loading...',
'UI:Menu:Actions' => 'Actions',
'UI:Menu:New' => 'New...',
'UI:Menu:Add' => 'Add...',
'UI:Menu:Manage' => 'Manage...',
'UI:GroupBy:Count' => 'Cuenta',
'UI:GroupBy:Count+' => 'Numero de elementoso',
'UI:CountOfObjects' => '%1$d objetos cumplen criterio.',
'UI_CountOfObjectsShort' => '%1$d objetos.',
'UI:NoObject_Class_ToDisplay' => 'No hay %1$s para mostrar',
'UI:History:LastModified_On_By' => 'Ultima modificacion el %1$s por %2$s.',
'UI:HistoryTab' => 'Historia',
'UI:History:Date' => 'Fecha',
'UI:History:Date+' => 'Fecha del Cambio',
'UI:History:User' => 'Usuario',
'UI:History:User+' => 'Usuario que hizo el cambio',
'UI:History:Changes' => 'Cambios',
'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',
'UI:History:StatsModifs' => 'Modified',
'UI:History:StatsModifs+' => 'Count of objects modified',
'UI:History:StatsDeletes' => 'Deleted',
'UI:History:StatsDeletes+' => 'Count of objects deleted',
'UI:Menu:EMail' => 'eMail',
'UI:Menu:CSVExport' => 'CSV Export',
'UI:Menu:Modify' => 'Modify...',
'UI:Menu:Delete' => 'Delete...',
'UI:Menu:Manage' => 'Manage...',
'UI:Menu:BulkDelete' => 'Delete...',
'UI:UndefinedObject' => 'undefined',
'UI:Document:OpenInNewWindow:Download' => 'Open in new window: %1$s, Download: %2$s',
'UI:SelectAllToggle+' => 'Select / Deselect All',
'UI:TruncatedResults' => '%1$d objects displayed out of %2$d',
'UI:DisplayAll' => 'Display All',
'UI:CountOfResults' => '%1$d object(s)',
'UI:ChangesLogTitle' => 'Changes log (%1$d):',
'UI:EmptyChangesLogTitle' => 'Changes log is empty',
'UI:Menu:CSVExport' => 'exportar a CSV',
'UI:Menu:Modify' => 'Modificar...',
'UI:Menu:Delete' => 'Borrar...',
'UI:Menu:Manage' => 'Administrar...',
'UI:Menu:BulkDelete' => 'Borrar...',
'UI:UndefinedObject' => 'indefinido',
'UI:Document:OpenInNewWindow:Download' => 'abrir en nueva ventana: %1$s, Descargar: %2$s',
'UI:SelectAllToggle+' => 'Seleccionar / Deseleccionar Todo',
'UI:TruncatedResults' => 'Mostrando %1$d objetos de %2$d',
'UI:DisplayAll' => 'Mostrar todo',
'UI:CountOfResults' => '%1$d objeto(s)',
'UI:ChangesLogTitle' => 'Registro de cambios (%1$d):',
'UI:EmptyChangesLogTitle' => 'Registro de cambios esta vacio',
'UI:SearchFor_Class_Objects' => 'Buscar %1$s objetos',
'UI:OQLQueryBuilderTitle' => 'OQL Query Builder',
'UI:OQLQueryTab' => 'OQL Query',
'UI:SimpleSearchTab' => 'Simple Search',
'UI:Details+' => 'Details',
'UI:SearchValue:Any' => '* Any *',
'UI:SearchValue:Mixed' => '* mixed *',
'UI:SelectOne' => '-- select one --',
'UI:Login:Welcome' => 'Welcome to iTop!',
'UI:Login:IncorrectLoginPassword' => 'Incorrect login/password, please try again.',
'UI:Login:IdentifyYourself' => 'Identify yourself before continuing',
'UI:Login:UserNamePrompt' => 'User Name',
'UI:Login:PasswordPrompt' => 'Password',
'UI:Login:ChangeYourPassword' => 'Change Your Password',
'UI:Login:OldPasswordPrompt' => 'Old password',
'UI:Login:NewPasswordPrompt' => 'New password',
'UI:Login:RetypeNewPasswordPrompt' => 'Retype new password',
'UI:Login:IncorrectOldPassword' => 'Error: the old password is incorrect',
'UI:LogOffMenu' => 'Log off',
'UI:ChangePwdMenu' => 'Change Password...',
'UI:Login:RetypePwdDoesNotMatch' => 'New password and retyped new password do not match !',
'UI:Button:Login' => 'Enter iTop',
'UI:Login:Error:AccessRestricted' => 'iTop access is restricted. Please, contact an iTop administrator.',
'UI:Login:Error:AccessAdmin' => 'Access restricted to people having administrator privileges. Please, contact an iTop administrator.',
'UI:CSVImport:MappingSelectOne' => '-- select one --',
'UI:CSVImport:MappingNotApplicable' => '-- ignore this field --',
'UI:CSVImport:NoData' => 'Empty data set..., please provide some data!',
'UI:Title:DataPreview' => 'Data Preview',
'UI:CSVImport:ErrorOnlyOneColumn' => 'Error: The data contains only one column. Did you select the appropriate separator character?',
'UI:CSVImport:FieldName' => 'Field %1$d',
'UI:CSVImport:DataLine1' => 'Data Line 1',
'UI:CSVImport:DataLine2' => 'Data Line 2',
'UI:CSVImport:idField' => 'id (Primary Key)',
'UI:Title:BulkImport' => 'iTop - Bulk import',
'UI:Title:BulkImport+' => 'CSV Import Wizard',
'UI:CSVImport:ClassesSelectOne' => '-- select one --',
'UI:CSVImport:ErrorExtendedAttCode' => 'Internal error: "%1$s" is an incorrect code because "%2$s" is NOT an external key of the class "%3$s"',
'UI:CSVImport:ObjectsWillStayUnchanged' => '%1$d objects(s) will stay unchanged.',
'UI:CSVImport:ObjectsWillBeModified' => '%1$d objects(s) will be modified.',
'UI:CSVImport:ObjectsWillBeAdded' => '%1$d objects(s) will be added.',
'UI:CSVImport:ObjectsWillHaveErrors' => '%1$d objects(s) will have errors.',
'UI:OQLQueryBuilderTitle' => 'Constructor de consultas OQL',
'UI:OQLQueryTab' => 'Consulta OQL',
'UI:SimpleSearchTab' => 'Busqueda simple',
'UI:Details+' => 'Detalles',
'UI:SearchValue:Any' => '* Cualquiera *',
'UI:SearchValue:Mixed' => '* mezclado *',
'UI:SelectOne' => '-- Seleccione uno --',
'UI:Login:Welcome' => 'Bienvenido a iTop!',
'UI:Login:IncorrectLoginPassword' => 'Usuario/Contraseña incorrecto, por favor intente otra vez.',
'UI:Login:IdentifyYourself' => 'Identifiquese antes de continuar',
'UI:Login:UserNamePrompt' => 'Nombre de Usuario',
'UI:Login:PasswordPrompt' => 'Contraseña',
'UI:Login:ChangeYourPassword' => 'Cambien su Contraseña',
'UI:Login:OldPasswordPrompt' => 'Contraseña Anterior',
'UI:Login:NewPasswordPrompt' => 'Contraseña Nueva',
'UI:Login:RetypeNewPasswordPrompt' => 'Reintroduzca Nueva contraseña',
'UI:Login:IncorrectOldPassword' => 'Error: la contraseña anterior es incorrecta',
'UI:LogOffMenu' => 'Cerrar sesion',
'UI:ChangePwdMenu' => 'Cambiar Contraseña...',
'UI:AccessRO-All' => 'iTop is read-only',
'UI:AccessRO-Users' => 'iTop is read-only for end-users',
'UI:Login:Error:AccessRestricted' => 'El acceso a iTop esta restringido. Por favor contacte al administrador de iTop.',
'UI:Login:Error:AccessAdmin' => 'Acceso restringido a usuarios con privilegio de administrador. Por favor contacte al administrador de iTop.',
'UI:CSVImport:MappingSelectOne' => '-- seleccione uno --',
'UI:CSVImport:MappingNotApplicable' => '-- ignore este campo --',
'UI:CSVImport:NoData' => 'Conjunto de datos vacio..., pro favor provea alguna data!',
'UI:Title:DataPreview' => 'Vista previa de datos',
'UI:CSVImport:ErrorOnlyOneColumn' => 'Error: La data solo contiene una columna. Selecciono el separador de campos adecuado?',
'UI:CSVImport:FieldName' => 'Campo %1$d',
'UI:CSVImport:DataLine1' => 'Linea de datos 1',
'UI:CSVImport:DataLine2' => 'Linea de datos 2',
'UI:CSVImport:idField' => 'id (Clave primaria)',
'UI:Title:BulkImport' => 'iTop - Importacion por lotes',
'UI:Title:BulkImport+' => 'Asistente de importar CSV',
'UI:CSVImport:ClassesSelectOne' => '-- seleccione uno --',
'UI:CSVImport:ErrorExtendedAttCode' => 'error interno: "%1$s" es un codigo incorrecto debido a que "%2$s" NO es una clave externa de la clase "%3$s"',
'UI:CSVImport:ObjectsWillStayUnchanged' => '%1$d objeto(s) permanecera sin cambio.',
'UI:CSVImport:ObjectsWillBeModified' => '%1$d objeto(s) sera modificado.',
'UI:CSVImport:ObjectsWillBeAdded' => '%1$d objeto(s) sera agregado.',
'UI:CSVImport:ObjectsWillHaveErrors' => '%1$d objeto(s) tendra error.',
'UI:CSVImport:ObjectsRemainedUnchanged' => '%1$d objects(s) remained unchanged.',
'UI:CSVImport:ObjectsWereModified' => '%1$d objects(s) were modified.',
'UI:CSVImport:ObjectsWereAdded' => '%1$d objects(s) were added.',
'UI:CSVImport:ObjectsHadErrors' => '%1$d objects(s) had errors.',
'UI:Title:CSVImportStep2' => 'Step 2 of 5: CSV data options',
'UI:Title:CSVImportStep3' => 'Step 3 of 5: Data mapping',
'UI:Title:CSVImportStep4' => 'Step 4 of 5: Import simulation',
'UI:Title:CSVImportStep5' => 'Step 5 of 5: Import completed',
'UI:CSVImport:LinesNotImported' => 'Lines that could not be loaded:',
'UI:CSVImport:LinesNotImported+' => 'The following lines have not been imported because they contain errors',
'UI:CSVImport:SeparatorComma+' => ', (comma)',
'UI:CSVImport:SeparatorSemicolon+' => '; (semicolon)',
'UI:CSVImport:SeparatorTab+' => 'tab',
'UI:CSVImport:SeparatorOther' => 'other:',
'UI:CSVImport:QualifierDoubleQuote+' => '" (double quote)',
'UI:CSVImport:QualifierSimpleQuote+' => '\' (simple quote)',
'UI:CSVImport:QualifierOther' => 'other:',
'UI:CSVImport:TreatFirstLineAsHeader' => 'Treat the first line as a header (column names)',
'UI:CSVImport:Skip_N_LinesAtTheBeginning' => 'Skip %1$s line(s) at the beginning of the file',
'UI:CSVImport:CSVDataPreview' => 'CSV Data Preview',
'UI:CSVImport:SelectFile' => 'Select the file to import:',
'UI:CSVImport:Tab:LoadFromFile' => 'Load from a file',
'UI:CSVImport:Tab:CopyPaste' => 'Copy and paste data',
'UI:CSVImport:Tab:Templates' => 'Templates',
'UI:CSVImport:PasteData' => 'Paste the data to import:',
'UI:CSVImport:PickClassForTemplate' => 'Pick the template to download: ',
'UI:CSVImport:SeparatorCharacter' => 'Separator character:',
'UI:CSVImport:TextQualifierCharacter' => 'Text qualifier character',
'UI:CSVImport:CommentsAndHeader' => 'Comments and header',
'UI:CSVImport:SelectClass' => 'Select the class to import:',
'UI:CSVImport:AdvancedMode' => 'Advanced mode',
'UI:CSVImport:AdvancedMode+' => 'In advanced mode the "id" (primary key) of the objects can be used to update and rename objects.' .
'However the column "id" (if present) can only be used as a search criteria and can not be combined with any other search criteria.',
'UI:CSVImport:SelectAClassFirst' => 'To configure the mapping, select a class first.',
'UI:CSVImport:HeaderFields' => 'Fields',
'UI:CSVImport:HeaderMappings' => 'Mappings',
'UI:CSVImport:HeaderSearch' => 'Search?',
'UI:CSVImport:AlertIncompleteMapping' => 'Please select a mapping for every field.',
'UI:CSVImport:AlertNoSearchCriteria' => 'Please select at least one search criteria',
'UI:CSVImport:ObjectsWereModified' => '%1$d objeto(s) sera modificado.',
'UI:CSVImport:ObjectsWereAdded' => '%1$d objeto(s) fue agregado.',
'UI:CSVImport:ObjectsHadErrors' => '%1$d objeto(s) tuvo errores.',
'UI:Title:CSVImportStep2' => 'Paso 2 de 5: opciones de datos CSV',
'UI:Title:CSVImportStep3' => 'Paso 3 de 5: mapeo de datos',
'UI:Title:CSVImportStep4' => 'Paso 4 de 5: simular la importacion',
'UI:Title:CSVImportStep5' => 'Paso 5 de 5: importacion completada',
'UI:CSVImport:LinesNotImported' => 'Lineas que no pudieron ser cargadas:',
'UI:CSVImport:LinesNotImported+' => 'Las siguientes lineas no pudieron ser importadas porque contienen errores',
'UI:CSVImport:SeparatorComma+' => ', (coma)',
'UI:CSVImport:SeparatorSemicolon+' => '; (punto y coma)',
'UI:CSVImport:SeparatorTab+' => 'tabulador',
'UI:CSVImport:SeparatorOther' => 'otro:',
'UI:CSVImport:QualifierDoubleQuote+' => '" (comilla doble)',
'UI:CSVImport:QualifierSimpleQuote+' => '\' (comilla simple)',
'UI:CSVImport:QualifierOther' => 'otro:',
'UI:CSVImport:TreatFirstLineAsHeader' => 'Use la primera linea como encabezado de columna(nombre de columnas))',
'UI:CSVImport:Skip_N_LinesAtTheBeginning' => 'Omitir %1$s linea(s) al inicio de el archivo',
'UI:CSVImport:CSVDataPreview' => 'Vista previa de los datos CSV',
'UI:CSVImport:SelectFile' => 'Seleccione el archivo a importar:',
'UI:CSVImport:Tab:LoadFromFile' => 'Cargar desde archivo',
'UI:CSVImport:Tab:CopyPaste' => 'Copiar y pegar data',
'UI:CSVImport:Tab:Templates' => 'Plantillas',
'UI:CSVImport:PasteData' => 'Pegue la data a importar:',
'UI:CSVImport:PickClassForTemplate' => 'seleccione la plantilla a descargar: ',
'UI:CSVImport:SeparatorCharacter' => 'Caracter separador:',
'UI:CSVImport:TextQualifierCharacter' => 'Caracter para calificar como texto',
'UI:CSVImport:CommentsAndHeader' => 'Comentarios y encabezado',
'UI:CSVImport:SelectClass' => 'Seleccione la clase a importar:',
'UI:CSVImport:AdvancedMode' => 'Modo avanzado',
'UI:CSVImport:AdvancedMode+' => 'En modo avanzado el "id" (clave primaria) de los objetos puede ser usado para actualizar y renombrar objetos.' .
'Sin embargo, la columna "id" (si esta presente) solo puede ser usado como criterio de busqueda y no puede ser combinado con ningun otro criterio de busqueda.',
'UI:CSVImport:SelectAClassFirst' => 'Para configurar el mapeo, primero seleccione un clase.',
'UI:CSVImport:HeaderFields' => 'Campos',
'UI:CSVImport:HeaderMappings' => 'Mapeo',
'UI:CSVImport:HeaderSearch' => 'Buscar?',
'UI:CSVImport:AlertIncompleteMapping' => 'Por favor seleccione un mapeo para cada categoria.',
'UI:CSVImport:AlertNoSearchCriteria' => 'Por favor seleccione al menos un criterio de busqueda',
'UI:UniversalSearchTitle' => 'iTop - Universal Search',
'UI:UniversalSearchTitle' => 'iTop - Busqueda Universal',
'UI:UniversalSearch:Error' => 'Error: %1$s',
'UI:UniversalSearch:LabelSelectTheClass' => 'Select the class to search: ',
'UI:UniversalSearch:LabelSelectTheClass' => 'Seleccione la clase a buscar: ',
'UI:Audit:Title' => 'iTop - CMDB Audit',
'UI:Audit:InteractiveAudit' => 'Interactive Audit',
'UI:Audit:HeaderAuditRule' => 'Audit Rule',
'UI:Audit:HeaderNbObjects' => '# Objects',
'UI:Audit:HeaderNbErrors' => '# Errors',
'UI:Audit:Title' => 'iTop - Auditoria a CMDB',
'UI:Audit:InteractiveAudit' => 'Auditoria Interactiva',
'UI:Audit:HeaderAuditRule' => 'Reglas de Auditoria',
'UI:Audit:HeaderNbObjects' => '# Objetos',
'UI:Audit:HeaderNbErrors' => '# Errores',
'UI:Audit:PercentageOk' => '% Ok',
'UI:RunQuery:Title' => 'iTop - OQL Query Evaluation',
'UI:RunQuery:QueryExamples' => 'Query Examples',
'UI:RunQuery:HeaderPurpose' => 'Purpose',
'UI:RunQuery:HeaderPurpose+' => 'Explanation about the query',
'UI:RunQuery:HeaderOQLExpression' => 'OQL Expression',
'UI:RunQuery:HeaderOQLExpression+' => 'The query in OQL syntax',
'UI:RunQuery:ExpressionToEvaluate' => 'Expression to evaluate: ',
'UI:RunQuery:MoreInfo' => 'More information about the query: ',
'UI:RunQuery:DevelopedQuery' => 'Redevelopped query expression: ',
'UI:RunQuery:SerializedFilter' => 'Serialized filter: ',
'UI:RunQuery:Error' => 'An error occured while running the query: %1$s',
'UI:RunQuery:Title' => 'iTop - Evaluacion de consultas OQL',
'UI:RunQuery:QueryExamples' => 'Explorador de Consultas',
'UI:RunQuery:HeaderPurpose' => 'Proposito',
'UI:RunQuery:HeaderPurpose+' => 'Explicacion acerca de la consulta',
'UI:RunQuery:HeaderOQLExpression' => 'Expresion OQL',
'UI:RunQuery:HeaderOQLExpression+' => 'La consulta en syntaxis OQL',
'UI:RunQuery:ExpressionToEvaluate' => 'Expresion a evaluar: ',
'UI:RunQuery:MoreInfo' => 'Mas informacion acerca de la consulta: ',
'UI:RunQuery:DevelopedQuery' => 'Expresion de consulta rediseñada: ',
'UI:RunQuery:SerializedFilter' => 'Filtro de serializacion: ',
'UI:RunQuery:Error' => 'Ha ocurrido un error al ejecutar la consulta: %1$s',
'UI:Schema:Title' => 'iTop objects schema',
'UI:Schema:CategoryMenuItem' => 'Category <b>%1$s</b>',
'UI:Schema:Relationships' => 'Relationships',
'UI:Schema:AbstractClass' => 'Abstract class: no object from this class can be instantiated.',
'UI:Schema:NonAbstractClass' => 'Non abstract class: objects from this class can be instantiated.',
'UI:Schema:ClassHierarchyTitle' => 'Class hierarchy',
'UI:Schema:AllClasses' => 'All classes',
'UI:Schema:ExternalKey_To' => 'External key to %1$s',
'UI:Schema:Columns_Description' => 'Columns: <em>%1$s</em>',
'UI:Schema:Default_Description' => 'Default: "%1$s"',
'UI:Schema:NullAllowed' => 'Null Allowed',
'UI:Schema:NullNotAllowed' => 'Null NOT Allowed',
'UI:Schema:Attributes' => 'Attributes',
'UI:Schema:AttributeCode' => 'Attribute Code',
'UI:Schema:AttributeCode+' => 'Internal code of the attribute',
'UI:Schema:Label' => 'Label',
'UI:Schema:Label+' => 'Label of the attribute',
'UI:Schema:Type' => 'Type',
'UI:Schema:Title' => 'Esquema de objetos iTop',
'UI:Schema:CategoryMenuItem' => 'Categoria <b>%1$s</b>',
'UI:Schema:Relationships' => 'Relaciones',
'UI:Schema:AbstractClass' => 'Clase abstracta: ningun objeto de esta clase puede ser representado.',
'UI:Schema:NonAbstractClass' => 'Clase no abstracta: objetos de esta clase pueden ser representados.',
'UI:Schema:ClassHierarchyTitle' => 'Jerarquia de clases',
'UI:Schema:AllClasses' => 'Todas las clases',
'UI:Schema:ExternalKey_To' => 'clave externa a %1$s',
'UI:Schema:Columns_Description' => 'Columnas: <em>%1$s</em>',
'UI:Schema:Default_Description' => 'Predeterminar: "%1$s"',
'UI:Schema:NullAllowed' => 'Permite Null',
'UI:Schema:NullNotAllowed' => 'NO permite Null',
'UI:Schema:Attributes' => 'Atributos',
'UI:Schema:AttributeCode' => 'Codigo de Atributo',
'UI:Schema:AttributeCode+' => 'Codigo interno del atributo',
'UI:Schema:Label' => 'Etiqueta',
'UI:Schema:Label+' => 'Etiqueta del atributo',
'UI:Schema:Type' => 'Tipo',
'UI:Schema:Type+' => 'Data type of the attribute',
'UI:Schema:Origin' => 'Origin',
'UI:Schema:Origin+' => 'The base class in which this attribute is defined',
'UI:Schema:Description' => 'Description',
'UI:Schema:Description+' => 'Description of the attribute',
'UI:Schema:AllowedValues' => 'Allowed values',
'UI:Schema:AllowedValues+' => 'Restrictions on the possible values for this attribute',
'UI:Schema:MoreInfo' => 'More info',
'UI:Schema:MoreInfo+' => 'More information about the field defined in the database',
'UI:Schema:SearchCriteria' => 'Search criteria',
'UI:Schema:FilterCode' => 'Filter code',
'UI:Schema:FilterCode+' => 'Code of this search criteria',
'UI:Schema:FilterDescription' => 'Description',
'UI:Schema:FilterDescription+' => 'Description of this search criteria',
'UI:Schema:AvailOperators' => 'Available operators',
'UI:Schema:AvailOperators+' => 'Possible operators for this search criteria',
'UI:Schema:ChildClasses' => 'Child classes',
'UI:Schema:ReferencingClasses' => 'Referencing classes',
'UI:Schema:RelatedClasses' => 'Related classes',
'UI:Schema:LifeCycle' => 'Life cycle',
'UI:Schema:Triggers' => 'Triggers',
'UI:Schema:Relation_Code_Description' => 'Relation <em>%1$s</em> (%2$s)',
'UI:Schema:RelationDown_Description' => 'Down: %1$s',
'UI:Schema:RelationUp_Description' => 'Up: %1$s',
'UI:Schema:RelationPropagates' => '%1$s: propagate to %2$d levels, query: %3$s',
'UI:Schema:RelationDoesNotPropagate' => '%1$s: does not propagates (%2$d levels), query: %3$s',
'UI:Schema:Class_ReferencingClasses_From_By' => '%1$s is referenced by the class %2$s via the field %3$s',
'UI:Schema:Class_IsLinkedTo_Class_Via_ClassAndAttribute' => '%1$s is linked to %2$s via %3$s::<em>%4$s</em>',
'UI:Schema:Links:1-n' => 'Classes pointing to %1$s (1:n links):',
'UI:Schema:Links:n-n' => 'Classes linked to %1$s (n:n links):',
'UI:Schema:Links:All' => 'Graph of all related classes',
'UI:Schema:NoLifeCyle' => 'There is no life cycle defined for this class.',
'UI:Schema:LifeCycleTransitions' => 'Transitions',
'UI:Schema:LifeCyleAttributeOptions' => 'Attribute options',
'UI:Schema:LifeCycleHiddenAttribute' => 'Hidden',
'UI:Schema:LifeCycleReadOnlyAttribute' => 'Read-only',
'UI:Schema:LifeCycleMandatoryAttribute' => 'Mandatory',
'UI:Schema:LifeCycleAttributeMustChange' => 'Must change',
'UI:Schema:LifeCycleAttributeMustPrompt' => 'User will be prompted to change the value',
'UI:Schema:LifeCycleEmptyList' => 'empty list',
'UI:Schema:Type+' => 'Tipo de dato del atributo',
'UI:Schema:Origin' => 'Origen',
'UI:Schema:Origin+' => 'La clase base en donde esta definido este atributo',
'UI:Schema:Description' => 'Descripcion',
'UI:Schema:Description+' => 'Descripcion del atributo',
'UI:Schema:AllowedValues' => 'Valores permitidos',
'UI:Schema:AllowedValues+' => 'Restricciones en los posibles valores para este atributo',
'UI:Schema:MoreInfo' => 'Mas informacion',
'UI:Schema:MoreInfo+' => 'Mas informacion acerca del campo definido en la base de datos',
'UI:Schema:SearchCriteria' => 'Criterio de busqueda',
'UI:Schema:FilterCode' => 'Codigo de filtro',
'UI:Schema:FilterCode+' => 'Codigo de este criterio de busqueda',
'UI:Schema:FilterDescription' => 'Descripcion',
'UI:Schema:FilterDescription+' => 'Descripcion de este criterio de busqueda',
'UI:Schema:AvailOperators' => 'Operadores disponibles',
'UI:Schema:AvailOperators+' => 'Operadores posibles para este criterio de busqueda',
'UI:Schema:ChildClasses' => 'Clases menores',
'UI:Schema:ReferencingClasses' => 'Clases de referencia',
'UI:Schema:RelatedClasses' => 'Clases relacionadas',
'UI:Schema:LifeCycle' => 'Ciclo de vida',
'UI:Schema:Triggers' => 'Gatillos',
'UI:Schema:Relation_Code_Description' => 'Relacion <em>%1$s</em> (%2$s)',
'UI:Schema:RelationDown_Description' => 'Abajo: %1$s',
'UI:Schema:RelationUp_Description' => 'Arriba: %1$s',
'UI:Schema:RelationPropagates' => '%1$s: propagar a %2$d niveles, consulta: %3$s',
'UI:Schema:RelationDoesNotPropagate' => '%1$s: no se propaga(%2$d nivel), consulta: %3$s',
'UI:Schema:Class_ReferencingClasses_From_By' => '%1$s esta referenciado por la clase %2$s a travez de el campo %3$s',
'UI:Schema:Class_IsLinkedTo_Class_Via_ClassAndAttribute' => '%1$s esta vinculado a %2$s a travez de %3$s::<em>%4$s</em>',
'UI:Schema:Links:1-n' => 'Clases apuntando a %1$s (1:n enlaces):',
'UI:Schema:Links:n-n' => 'Clases apuntando a %1$s (n:n enlaces):',
'UI:Schema:Links:All' => 'Grafico de todos los casos relacionados',
'UI:Schema:NoLifeCyle' => 'No hay ciclo de vida definido para esta clase.',
'UI:Schema:LifeCycleTransitions' => 'Transiciones',
'UI:Schema:LifeCyleAttributeOptions' => 'Opciones del atributo',
'UI:Schema:LifeCycleHiddenAttribute' => 'Oculto',
'UI:Schema:LifeCycleReadOnlyAttribute' => 'Solo-lectrura',
'UI:Schema:LifeCycleMandatoryAttribute' => 'Mandatorio',
'UI:Schema:LifeCycleAttributeMustChange' => 'Debe cambiar',
'UI:Schema:LifeCycleAttributeMustPrompt' => 'Se le pedira al usuario que cambie el valor',
'UI:Schema:LifeCycleEmptyList' => 'lista vacia',
'UI:LinksWidget:Autocomplete+' => 'Type the first 3 characters...',
'UI:Combo:SelectValue' => '--- select a value ---',
'UI:Label:SelectedObjects' => 'Selected objects: ',
'UI:Label:AvailableObjects' => 'Available objects: ',
'UI:Link_Class_Attributes' => '%1$s attributes',
'UI:SelectAllToggle+' => 'Select All / Deselect All',
'UI:AddObjectsOf_Class_LinkedWith_Class_Instance' => 'Add %1$s objects linked with %2$s: %3$s',
'UI:ManageObjectsOf_Class_LinkedWith_Class_Instance' => 'Manage %1$s objects linked with %2$s: %3$s',
'UI:AddLinkedObjectsOf_Class' => 'Add %1$ss...',
'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:LinksWidget:Autocomplete+' => 'Escriba los primeros 3 caracteres...',
'UI:Combo:SelectValue' => '--- seleccione un valor ---',
'UI:Label:SelectedObjects' => 'Objetos seleccionados: ',
'UI:Label:AvailableObjects' => 'Objetos disponibles: ',
'UI:Link_Class_Attributes' => '%1$s atributos',
'UI:SelectAllToggle+' => 'Seleccionar todo / Deseleccionar todo',
'UI:AddObjectsOf_Class_LinkedWith_Class_Instance' => 'Agregar %1$s objetos vinculados con %2$s: %3$s',
'UI:ManageObjectsOf_Class_LinkedWith_Class_Instance' => 'Administrar %1$s objetos vinculados con %2$s: %3$s',
'UI:AddLinkedObjectsOf_Class' => 'Agregar %1$ss...',
'UI:RemoveLinkedObjectsOf_Class' => 'Eliminar los objetos seleccionados',
'UI:Message:EmptyList:UseAdd' => 'La lista esta vaica, use el boton Agregar... para agregar elementos.',
'UI:Message:EmptyList:UseSearchForm' => 'Use la forma arriba para buscar objetos a ser agregados.',
'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',
'UI:Delete:NotAllowedToDelete' => 'You are not allowed to delete this object',
'UI:Delete:NotAllowedToUpdate_Fields' => 'You are not allowed to update the following field(s): %1$s',
'UI:Error:NotEnoughRightsToDelete' => 'This object could not be deleted because the current user do not have sufficient rights',
'UI:Error:CannotDeleteBecauseOfDepencies' => 'This object could not be deleted because some manual operations must be performed prior to that',
'UI:Archive_User_OnBehalfOf_User' => '%1$s on behalf of %2$s',
'UI:Delete:AutomaticallyDeleted' => 'automatically deleted',
'UI:Delete:AutomaticResetOf_Fields' => 'automatic reset of field(s): %1$s',
'UI:Delete:CleaningUpRefencesTo_Object' => 'Cleaning up all references to %1$s...',
'UI:Delete:CleaningUpRefencesTo_Several_ObjectsOf_Class' => 'Cleaning up all references to %1$d objects of class %2$s...',
'UI:Delete:Done+' => 'What was done...',
'UI:Delete:_Name_Class_Deleted' => '%1$s - %2$s deleted.',
'UI:Delete:ConfirmDeletionOf_Name' => 'Deletion of %1$s',
'UI:Delete:ConfirmDeletionOf_Count_ObjectsOf_Class' => 'Deletion of %1$d objects of class %2$s',
'UI:Delete:ShouldBeDeletedAtomaticallyButNotAllowed' => 'Should be automaticaly deleted, but you are not allowed to do so',
'UI:Delete:MustBeDeletedManuallyButNotAllowed' => 'Must be deleted manually - but you are not allowed to delete this object, please contact your application admin',
'UI:Delete:WillBeDeletedAutomatically' => 'Will be automaticaly deleted',
'UI:Delete:MustBeDeletedManually' => 'Must be deleted manually',
'UI:Delete:CannotUpdateBecause_Issue' => 'Should be automatically updated, but: %1$s',
'UI:Delete:WillAutomaticallyUpdate_Fields' => 'will be automaticaly updated (reset: %1$s)',
'UI:Delete:Count_Objects/LinksReferencing_Object' => '%1$d objects/links are referencing %2$s',
'UI:Delete:Count_Objects/LinksReferencingTheObjects' => '%1$d objects/links are referencing some of the objects to be deleted',
'UI:Delete:ReferencesMustBeDeletedToEnsureIntegrity' => 'To ensure Database integrity, any reference should be further eliminated',
'UI:Delete:Consequence+' => 'What will be done',
'UI:Delete:SorryDeletionNotAllowed' => 'Sorry, you are not allowed to delete this object, see the detailed explanations above',
'UI:Delete:PleaseDoTheManualOperations' => 'Please perform the manual operations listed above prior to requesting the deletion of this object',
'UI:Delect:Confirm_Object' => 'Please confirm that you want to delete %1$s.',
'UI:Delect:Confirm_Count_ObjectsOf_Class' => 'Please confirm that you want to delete the following %1$d objects of class %2$s.',
'UI:WelcomeToITop' => 'Welcome to iTop',
'UI:DetailsPageTitle' => 'iTop - %1$s - %2$s details',
'UI:Wizard:FinalStepTitle' => 'Paso final: Confirmacion',
'UI:Title:DeletionOf_Object' => 'Borrado de %1$s',
'UI:Title:BulkDeletionOf_Count_ObjectsOf_Class' => 'Borrado por lote de %1$d objetos de la clase %2$s',
'UI:Delete:NotAllowedToDelete' => 'No esta autorizado para borrar este objeto',
'UI:Delete:NotAllowedToUpdate_Fields' => 'No esta autorizado para actualizar el siguiente campo(s): %1$s',
'UI:Error:NotEnoughRightsToDelete' => 'Este objeto no pudo ser borrado porque el usuario actual no posee suficientes permisos',
'UI:Error:CannotDeleteBecauseOfDepencies' => 'Este objeto no pudo ser borrado porque algunas operaciones manuales deben ser ejecutadas antes de eso',
'UI:Archive_User_OnBehalfOf_User' => '%1$s en nombre de %2$s',
'UI:Delete:AutomaticallyDeleted' => 'Borrado automaticamente',
'UI:Delete:AutomaticResetOf_Fields' => 'reinicio automatico de campo(s): %1$s',
'UI:Delete:CleaningUpRefencesTo_Object' => 'Limpiando todas las referencias a %1$s...',
'UI:Delete:CleaningUpRefencesTo_Several_ObjectsOf_Class' => 'Limpiando todas las referencias a %1$d objetos de la clase %2$s...',
'UI:Delete:Done+' => 'Lo que se hizo...',
'UI:Delete:_Name_Class_Deleted' => '%1$s - %2$s borrado.',
'UI:Delete:ConfirmDeletionOf_Name' => 'Borrado de %1$s',
'UI:Delete:ConfirmDeletionOf_Count_ObjectsOf_Class' => 'Borrado de %1$d objetos de al clase %2$s',
// 'UI:Delete:ShouldBeDeletedAtomaticallyButNotPossible' => 'Beberia ser eliminado automaticamente, pero usted no esta autorizado para hacerlo',
// 'UI:Delete:MustBeDeletedManuallyButNotPossible' => 'Debe ser borrado manualmente - pero usted no esta autorizado para borrar este objeto, por favor contacte al administrador de la aplicacion',
'UI:Delete:WillBeDeletedAutomatically' => 'Sera borrado automaticamente',
'UI:Delete:MustBeDeletedManually' => 'Debe ser borrado manualmente',
'UI:Delete:CannotUpdateBecause_Issue' => 'Debe ser actualizado automaticamente, pero: %1$s',
'UI:Delete:WillAutomaticallyUpdate_Fields' => 'sera actualizado automaticamente (reset: %1$s)',
'UI:Delete:Count_Objects/LinksReferencing_Object' => '%1$d objetos/vinculos estan referenciando %2$s',
'UI:Delete:Count_Objects/LinksReferencingTheObjects' => '%1$d objetos/vinculos estan referenciando algunos de los objetos a ser borrados',
'UI:Delete:ReferencesMustBeDeletedToEnsureIntegrity' => 'Para asegurar la integridad de la Base de Datos, cualquier referencia debera ser completamente eliminada',
'UI:Delete:Consequence+' => 'Lo que se hara',
'UI:Delete:SorryDeletionNotAllowed' => 'Disculpe, usted no esta autorizado a eliminar este objeto, vea la explciacion detallada abajo',
'UI:Delete:PleaseDoTheManualOperations' => 'Por favor ejecute las operaciones manuales antes de eliminar este objeto',
'UI:Delect:Confirm_Object' => 'Por favor confirme que quiere borrar %1$s.',
'UI:Delect:Confirm_Count_ObjectsOf_Class' => 'Port favor confirme que quiere eliminar los siguientes %1$d objeto de la clase %2$s.',
'UI:WelcomeToITop' => 'Bienvenido a iTop',
'UI:DetailsPageTitle' => 'iTop - %1$s - %2$s detalles',
'UI:ErrorPageTitle' => 'iTop - Error',
'UI:ObjectDoesNotExist' => 'Sorry, this object does not exist (or you are not allowed to view it).',
'UI:SearchResultsPageTitle' => 'iTop - Search Results',
'UI:Search:NoSearch' => 'Nothing to search for',
'UI:FullTextSearchTitle_Text' => 'Results for "%1$s":',
'UI:Search:Count_ObjectsOf_Class_Found' => '%1$d object(s) of class %2$s found.',
'UI:Search:NoObjectFound' => 'No object found.',
'UI:ModificationPageTitle_Object_Class' => 'iTop - %1$s - %2$s modification',
'UI:ModificationTitle_Class_Object' => 'Modification of %1$s: <span class=\"hilite\">%2$s</span>',
'UI:ClonePageTitle_Object_Class' => 'iTop - Clone %1$s - %2$s modification',
'UI:CloneTitle_Class_Object' => 'Clone of %1$s: <span class=\"hilite\">%2$s</span>',
'UI:CreationPageTitle_Class' => 'iTop - Creation of a new %1$s ',
'UI:CreationTitle_Class' => 'Creation of a new %1$s',
'UI:SelectTheTypeOf_Class_ToCreate' => 'Select the type of %1$s to create:',
'UI:Class_Object_NotUpdated' => 'No change detected, %1$s (%2$s) has <strong>not</strong> been modified.',
'UI:Class_Object_Updated' => '%1$s (%2$s) updated.',
'UI:BulkDeletePageTitle' => 'iTop - Bulk Delete',
'UI:BulkDeleteTitle' => 'Select the objects you want to delete:',
'UI:PageTitle:ObjectCreated' => 'iTop Object Created.',
'UI:Title:Object_Of_Class_Created' => '%1$s - %2$s created.',
'UI:Apply_Stimulus_On_Object_In_State_ToTarget_State' => 'Applying %1$s on object: %2$s in state %3$s to target state: %4$s.',
'UI:ObjectCouldNotBeWritten' => 'The object could not be written: %1$s',
'UI:PageTitle:FatalError' => 'iTop - Fatal Error',
'UI:FatalErrorMessage' => 'Fatal error, iTop cannot continue.',
'UI:SystemIntrusion' => 'Access denied. You have trying to perform an operation that is not allowed for you.',
'UI:ObjectDoesNotExist' => 'Disculpe, este objeto no existe (o no esta autorizado para verlo).',
'UI:SearchResultsPageTitle' => 'iTop - Resultados de la Busqueda',
'UI:Search:NoSearch' => 'Nada para buscar',
'UI:FullTextSearchTitle_Text' => 'Resultados para "%1$s":',
'UI:Search:Count_ObjectsOf_Class_Found' => '%1$d objeto(s) de la clase %2$s encontrado(s).',
'UI:Search:NoObjectFound' => 'No se encontraron objetos.',
'UI:ModificationPageTitle_Object_Class' => 'iTop - %1$s - %2$s modificacion',
'UI:ModificationTitle_Class_Object' => 'Modificacion de %1$s: <span class=\"hilite\">%2$s</span>',
'UI:ClonePageTitle_Object_Class' => 'iTop - Duplicar %1$s - %2$s modificacion',
'UI:CloneTitle_Class_Object' => 'Duplicado de %1$s: <span class=\"hilite\">%2$s</span>',
'UI:CreationPageTitle_Class' => 'iTop - Creacion de un nuevo %1$s ',
'UI:CreationTitle_Class' => 'Creacion de un nuevo %1$s',
'UI:SelectTheTypeOf_Class_ToCreate' => 'Seleccione el tipo de %1$s a crear:',
'UI:Class_Object_NotUpdated' => 'No se detectaron cambios, %1$s (%2$s) <strong>no</strong> fue modificado.',
'UI:Class_Object_Updated' => '%1$s (%2$s) actualizado.',
'UI:BulkDeletePageTitle' => 'iTop - Eliminar por lote',
'UI:BulkDeleteTitle' => 'Seleccione los objetos que desea eliminar:',
'UI:PageTitle:ObjectCreated' => 'Objeto de iTop creado.',
'UI:Title:Object_Of_Class_Created' => '%1$s - %2$s creado.',
'UI:Apply_Stimulus_On_Object_In_State_ToTarget_State' => 'Aplicando %1$s en el objeto: %2$s en estado %3$s al estado deseado: %4$s.',
'UI:ObjectCouldNotBeWritten' => 'el objeto no pudo ser escrito: %1$s',
'UI:PageTitle:FatalError' => 'iTop - Error Fatal',
'UI:FatalErrorMessage' => 'Error fatal, iTop no puede continuar.',
'UI:SystemIntrusion' => 'Acceso denegado. Esta tratando de ejecutar una operacion no permitida para usted.',
'UI:Error_Details' => 'Error: %1$s.',
'UI:PageTitle:ClassProjections' => 'iTop user management - class projections',
'UI:PageTitle:ProfileProjections' => 'iTop user management - profile projections',
'UI:UserManagement:Class' => 'Class',
'UI:UserManagement:Class+' => 'Class of objects',
'UI:UserManagement:ProjectedObject' => 'Object',
'UI:UserManagement:ProjectedObject+' => 'Projected object',
'UI:UserManagement:AnyObject' => '* any *',
'UI:UserManagement:User' => 'User',
'UI:UserManagement:User+' => 'User involved in the projection',
'UI:UserManagement:Profile' => 'Profile',
'UI:UserManagement:Profile+' => 'Profile in which the projection is specified',
'UI:UserManagement:Action:Read' => 'Read',
'UI:UserManagement:Action:Read+' => 'Read/display objects',
'UI:UserManagement:Action:Modify' => 'Modify',
'UI:UserManagement:Action:Modify+' => 'Create and edit (modify) objects',
'UI:UserManagement:Action:Delete' => 'Delete',
'UI:UserManagement:Action:Delete+' => 'Delete objects',
'UI:UserManagement:Action:BulkRead' => 'Bulk Read (Export)',
'UI:UserManagement:Action:BulkRead+' => 'List objects or export massively',
'UI:UserManagement:Action:BulkModify' => 'Bulk Modify',
'UI:UserManagement:Action:BulkModify+' => 'Massively create/edit (CSV import)',
'UI:UserManagement:Action:BulkDelete' => 'Bulk Delete',
'UI:UserManagement:Action:BulkDelete+' => 'Massively delete objects',
'UI:PageTitle:ClassProjections' => 'Administracion de usuarios iTop - proyecciones de clases',
'UI:PageTitle:ProfileProjections' => 'Administracion de usuarios iTop - proyecciones de perfil',
'UI:UserManagement:Class' => 'Clase',
'UI:UserManagement:Class+' => 'Clase de objetos',
'UI:UserManagement:ProjectedObject' => 'Objeto',
'UI:UserManagement:ProjectedObject+' => 'Objeto proyectado',
'UI:UserManagement:AnyObject' => '* cualquiera *',
'UI:UserManagement:User' => 'Usuario',
'UI:UserManagement:User+' => 'Usuario implicado en la proyeccion',
'UI:UserManagement:Profile' => 'Perfil',
'UI:UserManagement:Profile+' => 'Perfil en el cual se especifico la proyeccion',
'UI:UserManagement:Action:Read' => 'Leer',
'UI:UserManagement:Action:Read+' => 'Leer/Mostrar objetos',
'UI:UserManagement:Action:Modify' => 'Modificar',
'UI:UserManagement:Action:Modify+' => 'Crear y editar (modificar) objetos',
'UI:UserManagement:Action:Delete' => 'Eliminar',
'UI:UserManagement:Action:Delete+' => 'Eliminar objetos',
'UI:UserManagement:Action:BulkRead' => 'Lectura por lote (Exportar)',
'UI:UserManagement:Action:BulkRead+' => 'Listar objetos o exportar masivamente',
'UI:UserManagement:Action:BulkModify' => 'Modificacion masiva',
'UI:UserManagement:Action:BulkModify+' => 'Crear/Editar masivamente (importar CSV)',
'UI:UserManagement:Action:BulkDelete' => 'eliminacion masiva',
'UI:UserManagement:Action:BulkDelete+' => 'eliminacion masiva de objetos',
'UI:UserManagement:Action:Stimuli' => 'Stimuli',
'UI:UserManagement:Action:Stimuli+' => 'Allowed (compound) actions',
'UI:UserManagement:Action' => 'Action',
'UI:UserManagement:Action+' => 'Action performed by the user',
'UI:UserManagement:TitleActions' => 'Actions',
'UI:UserManagement:Permission' => 'Permission',
'UI:UserManagement:Permission+' => 'User\'s permissions',
'UI:UserManagement:Attributes' => 'Attributes',
'UI:UserManagement:ActionAllowed:Yes' => 'Yes',
'UI:UserManagement:Action:Stimuli+' => 'Acciones (compound) permitidas',
'UI:UserManagement:Action' => 'Accion',
'UI:UserManagement:Action+' => 'Accion ejecutada por el usuario',
'UI:UserManagement:TitleActions' => 'Acciones',
'UI:UserManagement:Permission' => 'Permisos',
'UI:UserManagement:Permission+' => 'Permisos de usuario',
'UI:UserManagement:Attributes' => 'Atributos',
'UI:UserManagement:ActionAllowed:Yes' => 'Si',
'UI:UserManagement:ActionAllowed:No' => 'No',
'UI:UserManagement:AdminProfile+' => 'Administrators have full read/write access to all objects in the database.',
'UI:UserManagement:AdminProfile+' => 'Los administradores tienen acceso total de lectura/escritura para todos los objetos en la base de datos.',
'UI:UserManagement:NoLifeCycleApplicable' => 'N/A',
'UI:UserManagement:NoLifeCycleApplicable+' => 'No lifecycle has been defined for this class',
'UI:UserManagement:GrantMatrix' => 'Grant Matrix',
'UI:UserManagement:LinkBetween_User_And_Profile' => 'Link between %1$s and %2$s',
'UI:UserManagement:NoLifeCycleApplicable+' => 'No se ha definido ciclo de vida para esta clase',
'UI:UserManagement:GrantMatrix' => 'Matriz de acceso',
'UI:UserManagement:LinkBetween_User_And_Profile' => 'Vinculo entre %1$s y %2$s',
'Menu:AdminTools' => 'Admin tools',
'Menu:AdminTools+' => 'Administration tools',
'Menu:AdminTools?' => 'Tools accessible only to users having the administrator profile',
'Menu:AdminTools' => 'Herramientas Administrativas',
'Menu:AdminTools+' => 'Herramientas de administracion',
'Menu:AdminTools?' => 'Herramientas accesibles soloa usuariso con perfil de administrador',
'UI:ChangeManagementMenu' => 'Change Management',
'UI:ChangeManagementMenu+' => 'Change Management',
'UI:ChangeManagementMenu:Title' => 'Changes Overview',
'UI-ChangeManagementMenu-ChangesByType' => 'Changes by type',
'UI-ChangeManagementMenu-ChangesByStatus' => 'Changes by status',
'UI-ChangeManagementMenu-ChangesByWorkgroup' => 'Changes by workgroup',
'UI-ChangeManagementMenu-ChangesNotYetAssigned' => 'Changes not yet assigned',
'UI:ChangeManagementMenu' => 'Control de Cambios',
'UI:ChangeManagementMenu+' => 'Control de Cambios',
'UI:ChangeManagementMenu:Title' => 'Sumario de cambios',
'UI-ChangeManagementMenu-ChangesByType' => 'Cambios por tipo',
'UI-ChangeManagementMenu-ChangesByStatus' => 'Cambios por estado',
'UI-ChangeManagementMenu-ChangesByWorkgroup' => 'Cambios por grupo de trabajo',
'UI-ChangeManagementMenu-ChangesNotYetAssigned' => 'Cambios no asignados aun',
'UI:ConfigurationItemsMenu'=> 'Configuration Items',
'UI:ConfigurationItemsMenu+'=> 'All Devices',
'UI:ConfigurationItemsMenu:Title' => 'Configuration Items Overview',
'UI-ConfigurationItemsMenu-ServersByCriticity' => 'Servers by criticity',
'UI-ConfigurationItemsMenu-PCsByCriticity' => 'PCs by criticity',
'UI-ConfigurationItemsMenu-NWDevicesByCriticity' => 'Network devices by criticity',
'UI-ConfigurationItemsMenu-ApplicationsByCriticity' => 'Applications by criticity',
'UI:ConfigurationItemsMenu'=> 'Elementos de configuracion',
'UI:ConfigurationItemsMenu+'=> 'Todos los dispositivos',
'UI:ConfigurationItemsMenu:Title' => 'Sumario de Elementos de Configuracion',
'UI-ConfigurationItemsMenu-ServersByCriticity' => 'Servidores por criticidad',
'UI-ConfigurationItemsMenu-PCsByCriticity' => 'PCs por criticidad',
'UI-ConfigurationItemsMenu-NWDevicesByCriticity' => 'Dispositivos de red por criticidad',
'UI-ConfigurationItemsMenu-ApplicationsByCriticity' => 'Aplicaciones por criticidad',
'UI:ConfigurationManagementMenu' => 'Configuration Management',
'UI:ConfigurationManagementMenu+' => 'Configuration Management',
'UI:ConfigurationManagementMenu:Title' => 'Infrastructure Overview',
'UI-ConfigurationManagementMenu-InfraByType' => 'Infrastructure objects by type',
'UI-ConfigurationManagementMenu-InfraByStatus' => 'Infrastructure objects by status',
'UI:ConfigurationManagementMenu' => 'Gestion de la Configuracion',
'UI:ConfigurationManagementMenu+' => 'Gestion de la Configuracion',
'UI:ConfigurationManagementMenu:Title' => 'Sumario de Infrastructura',
'UI-ConfigurationManagementMenu-InfraByType' => 'Objetos de infrastructura por tipo',
'UI-ConfigurationManagementMenu-InfraByStatus' => 'Objetos de infraestructura por estatus',
'UI:ConfigMgmtMenuOverview:Title' => 'Dashboard for Configuration Management',
'UI-ConfigMgmtMenuOverview-FunctionalCIbyStatus' => 'Configuration Items by status',
'UI-ConfigMgmtMenuOverview-FunctionalCIByType' => 'Configuration Items by type',
'UI:ConfigMgmtMenuOverview:Title' => 'Panel de control for Gestion de la Configuracion',
'UI-ConfigMgmtMenuOverview-FunctionalCIbyStatus' => 'Elementos de la configuracion por estado',
'UI-ConfigMgmtMenuOverview-FunctionalCIByType' => 'elementos de configuracion por tipo',
'UI:RequestMgmtMenuOverview:Title' => 'Dashboard for Request Management',
'UI-RequestManagementOverview-RequestByService' => 'User Requests by service',
'UI-RequestManagementOverview-RequestByPriority' => 'User Requests by priority',
'UI-RequestManagementOverview-RequestUnassigned' => 'User Requests not yet assigned to an agent',
'UI:RequestMgmtMenuOverview:Title' => 'Panel de control for Gestion de Solicitudes',
'UI-RequestManagementOverview-RequestByService' => 'Solicitudes de usuario por servicio',
'UI-RequestManagementOverview-RequestByPriority' => 'Solicitudes de usuario por prioridad',
'UI-RequestManagementOverview-RequestUnassigned' => 'Solicitudes de usuario sin asignar a un agente',
'UI:IncidentMgmtMenuOverview:Title' => 'Dashboard for Incident Management',
'UI-IncidentManagementOverview-IncidentByService' => 'Incidents by service',
'UI-IncidentManagementOverview-IncidentByPriority' => 'Incident by priority',
'UI-IncidentManagementOverview-IncidentUnassigned' => 'Incidents not yet assigned to an agent',
'UI:IncidentMgmtMenuOverview:Title' => 'Panel de control for Gestion de Incidentes',
'UI-IncidentManagementOverview-IncidentByService' => 'Incidentes por servicio',
'UI-IncidentManagementOverview-IncidentByPriority' => 'Incidentes por prioridad',
'UI-IncidentManagementOverview-IncidentUnassigned' => 'Incidentes no asignados a un agente',
'UI:ChangeMgmtMenuOverview:Title' => 'Dashboard for Change Management',
'UI-ChangeManagementOverview-ChangeByType' => 'Changes by type',
'UI-ChangeManagementOverview-ChangeUnassigned' => 'Changes not yet assigned to an agent',
'UI-ChangeManagementOverview-ChangeWithOutage' => 'Outages due to changes',
'UI:ChangeMgmtMenuOverview:Title' => 'Panel de control for Control de Cambios',
'UI-ChangeManagementOverview-ChangeByType' => 'Cambios por tipo',
'UI-ChangeManagementOverview-ChangeUnassigned' => 'Cambios no asignados a un agente',
'UI-ChangeManagementOverview-ChangeWithOutage' => 'Interrupciones de servicios debida a cambios',
'UI:ServiceMgmtMenuOverview:Title' => 'Dashboard for Service Management',
'UI-ServiceManagementOverview-CustomerContractToRenew' => 'Customer contracts to be renewed in 30 days',
'UI-ServiceManagementOverview-ProviderContractToRenew' => 'Provider contracts to be renewed in 30 days',
'UI:ServiceMgmtMenuOverview:Title' => 'Panel de control for Gestion de Servicios',
'UI-ServiceManagementOverview-CustomerContractToRenew' => 'Contratos de usuario a ser renovados en 30 dias',
'UI-ServiceManagementOverview-ProviderContractToRenew' => 'contratos de proveedores a ser renovados en 30 dias',
'UI:ContactsMenu' => 'Contacts',
'UI:ContactsMenu+' => 'Contacts',
'UI:ContactsMenu:Title' => 'Contacts Overview',
'UI-ContactsMenu-ContactsByLocation' => 'Contacts by location',
'UI-ContactsMenu-ContactsByType' => 'Contacts by type',
'UI-ContactsMenu-ContactsByStatus' => 'Contacts by status',
'UI:ContactsMenu' => 'Contactos',
'UI:ContactsMenu+' => 'Contactos',
'UI:ContactsMenu:Title' => 'Sumario de Contactos',
'UI-ContactsMenu-ContactsByLocation' => 'Contactos por ubicacion',
'UI-ContactsMenu-ContactsByType' => 'Contactos por tipo',
'UI-ContactsMenu-ContactsByStatus' => 'Contactos por estado',
'Menu:CSVImportMenu' => 'CSV import',
'Menu:CSVImportMenu+' => 'Bulk creation or update',
'Menu:CSVImportMenu' => 'Importar CSV',
'Menu:CSVImportMenu+' => 'Creacion o actualizacion masiva',
'Menu:DataModelMenu' => 'Data Model',
'Menu:DataModelMenu+' => 'Overview of the Data Model',
'Menu:DataModelMenu' => 'Modelo de Datos',
'Menu:DataModelMenu+' => 'Sumario del Modelo de Datos',
'Menu:ExportMenu' => 'Export',
'Menu:ExportMenu+' => 'Export the results of any query in HTML, CSV or XML',
'Menu:ExportMenu' => 'Exportar',
'Menu:ExportMenu+' => 'Exportar los resultados de cualquier consulta eb HTML, CSV o XML',
'Menu:NotificationsMenu' => 'Notifications',
'Menu:NotificationsMenu+' => 'Configuration of the Notifications',
'UI:NotificationsMenu:Title' => 'Configuration of the <span class="hilite">Notifications</span>',
'UI:NotificationsMenu:Help' => 'Help',
'UI:NotificationsMenu:HelpContent' => '<p>In iTop the notifications are fully customizable. They are based on two sets of objects: <i>triggers and actions</i>.</p>
<p><i><b>Triggers</b></i> define when a notification will be executed. There are 3 types of triggers for covering 3 differents phases of an object life cycle:
'Menu:NotificationsMenu' => 'Notificaciones',
'Menu:NotificationsMenu+' => 'Configuracion de las Notificaciones',
'UI:NotificationsMenu:Title' => 'Configuracion de las <span class="hilite">Notificaciones</span>',
'UI:NotificationsMenu:Help' => 'Ayuda',
'UI:NotificationsMenu:HelpContent' => '<p>En iTop las notificaciones son completamente personalizables. Estan basadas en dos conjuntos de objetos: <i>Gatuillos y acciones</i>.</p>
<p><i><b>Gatillos</b></i> definen cuando una notificacion debe ser ejecutada. existen 3 tipos de gatillos para cubrir las 3 diferentes fases del ciclo de vida de un objeto:
<ol>
<li>the "OnCreate" triggers get executed when an object of the specified class is created</li>
<li>the "OnStateEnter" triggers get executed before an object of the given class enters a specified state (coming from another state)</li>
<li>the "OnStateLeave" triggers get executed when an object of the given class is leaving a specified state</li>
<li>los gatillos "OnCreate" son ejecutados cuando un objeto de la clase especificada es creado</li>
<li>los gatillos "OnStateEnter" son ejecutados antes de que un determinado objeto entre un estado especificado (viniendo de otro estado)</li>
<li>los gatillos "OnStateLeave" son ejecutados cuando un objeto de clase determinada deja un estado especificado</li>
</ol>
</p>
<p>
<i><b>Actions</b></i> define the actions to be performed when the triggers execute. For now there is only one kind of action consisting in sending an email message.
Such actions also define the template to be used for sending the email as well as the other parameters of the message like the recipients, importance, etc.
<i><b>Acciones</b></i> definen las acciones a ser ejecutadas cuando los gatillos se disparan, por ahora el unico tipo de accion consiste en enviar un mensaje de correo.
Tales acciones tambien definen la plantilla a ser usada para enviar el correo asi como otros parametros del mensaje como receptor, importancia, etc.
</p>
<p>A special page: <a href="../setup/email.test.php" target="_blank">email.test.php</a> is available for testing and troubleshooting your PHP mail configuration.</p>
<p>To be executed, actions must be associated to triggers.
When associated with a trigger, each action is given an "order" number, specifying in which order the actions are to be executed.</p>',
<p>Una pagina especial: <a href="../setup/email.test.php" target="_blank">email.test.php</a> esta disponible para pruebar y diagnosticar su configuracion de correo de PHP.</p>
<p>Para ser ejecutadas, las acciones deben estar asociadas con los gatillos.
Cuando se asocien con un gatillo, cada accion recibe un numero de "orden", esto especifica en que orden se ejecutaran las acciones.</p>',
'UI:NotificationsMenu:Triggers' => 'Disparadores',
'UI:NotificationsMenu:AvailableTriggers' => 'Disparadores disponiblesAvailable triggers',
'UI:NotificationsMenu:AvailableTriggers' => 'Disparadores disponibles',
'UI:NotificationsMenu:OnCreate' => 'cuando un objeto es creado',
'UI:NotificationsMenu:OnStateEnter' => 'Cuando un objeto entra a un estado específico',
'UI:NotificationsMenu:OnStateLeave' => 'Cuando un objeto sale de un estado específico',
@@ -823,7 +828,7 @@ When associated with a trigger, each action is given an "order" number, specifyi
'Menu:UserAccountsMenu:Title' => 'Cuentas de usuario',
'UI:iTopVersion:Short' => 'iTop versión %1$s',
'UI:iTopVersion:Long' => 'iTop versión %1$s-%2$s built on %3$s',
'UI:iTopVersion:Long' => 'iTop versión %1$s-%2$s compilada en %3$s',
'UI:PropertiesTab' => 'Propiedades',
'UI:OpenDocumentInNewWindow_' => 'Abra este documento en una ventana nueva: %1$s',
@@ -836,7 +841,9 @@ When associated with a trigger, each action is given an "order" number, specifyi
'UI:Deadline_Hours_Minutes' => '%1$dh %2$dmin',
'UI:Deadline_Days_Hours_Minutes' => '%1$dd %2$dh %3$dmin',
'UI:Help' => 'Ayuda',
'UI:PasswordConfirm' => '(Confirm)',
'UI:PasswordConfirm' => '(Confirmar)',
'Enum:Undefined' => 'Indefinido',
));
?>

View File

@@ -15,373 +15,613 @@
// 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
* @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
*/
//////////////////////////////////////////////////////////////////////
// Classes in 'core/cmdb'
//////////////////////////////////////////////////////////////////////
//
//
// Class: CMDBChange
//
Dict::Add('FR FR', 'French', 'Français', array(
'Class:CMDBChange' => 'change',
'Class:CMDBChange+' => 'Changes tracking',
'Class:CMDBChange/Attribute:date' => 'date',
'Class:CMDBChange/Attribute:date+' => 'date and time at which the changes have been recorded',
'Class:CMDBChange/Attribute:userinfo' => 'misc. info',
'Class:CMDBChange/Attribute:userinfo+' => 'caller\'s defined information',
));
//
// Class: CMDBChangeOp
//
Dict::Add('FR FR', 'French', 'Français', array(
'Class:CMDBChangeOp' => 'change operation',
'Class:CMDBChangeOp+' => 'Change operations tracking',
'Class:CMDBChangeOp/Attribute:change' => 'change',
'Class:CMDBChangeOp/Attribute:change+' => 'change',
'Class:CMDBChangeOp/Attribute:date' => 'date',
'Class:CMDBChangeOp/Attribute:date+' => 'date and time of the change',
'Class:CMDBChangeOp/Attribute:userinfo' => 'user',
'Class:CMDBChangeOp/Attribute:userinfo+' => 'who made this change',
'Class:CMDBChangeOp/Attribute:objclass' => 'object class',
'Class:CMDBChangeOp/Attribute:objclass+' => 'object class',
'Class:CMDBChangeOp/Attribute:objkey' => 'object id',
'Class:CMDBChangeOp/Attribute:objkey+' => 'object id',
'Class:CMDBChangeOp/Attribute:finalclass' => 'type',
'Class:CMDBChangeOp/Attribute:finalclass+' => '',
));
//
// Class: CMDBChangeOpCreate
//
Dict::Add('FR FR', 'French', 'Français', array(
'Class:CMDBChangeOpCreate' => 'object creation',
'Class:CMDBChangeOpCreate+' => 'Object creation tracking',
));
//
// Class: CMDBChangeOpDelete
//
Dict::Add('FR FR', 'French', 'Français', array(
'Class:CMDBChangeOpDelete' => 'object deletion',
'Class:CMDBChangeOpDelete+' => 'Object deletion tracking',
));
//
// Class: CMDBChangeOpSetAttribute
//
Dict::Add('FR FR', 'French', 'Français', array(
'Class:CMDBChangeOpSetAttribute' => 'object change',
'Class:CMDBChangeOpSetAttribute+' => 'Object properties change tracking',
'Class:CMDBChangeOpSetAttribute/Attribute:attcode' => 'Attribute',
'Class:CMDBChangeOpSetAttribute/Attribute:attcode+' => 'code of the modified property',
));
//
// Class: CMDBChangeOpSetAttributeScalar
//
Dict::Add('FR FR', 'French', 'Français', array(
'Class:CMDBChangeOpSetAttributeScalar' => 'property change',
'Class:CMDBChangeOpSetAttributeScalar+' => 'Object scalar properties change tracking',
'Class:CMDBChangeOpSetAttributeScalar/Attribute:oldvalue' => 'Previous value',
'Class:CMDBChangeOpSetAttributeScalar/Attribute:oldvalue+' => 'previous value of the attribute',
'Class:CMDBChangeOpSetAttributeScalar/Attribute:newvalue' => 'New value',
'Class:CMDBChangeOpSetAttributeScalar/Attribute:newvalue+' => 'new value of the attribute',
));
// Used by CMDBChangeOp... & derived classes
Dict::Add('FR FR', 'French', 'Français', array(
'Change:ObjectCreated' => 'Elément créé',
'Change:ObjectDeleted' => 'Elément effacé',
'Change:AttName_SetTo_NewValue_PreviousValue_OldValue' => '%1$s modifié en %2$s (ancienne valeur: %3$s)',
'Change:Text_AppendedTo_AttName' => '%1$s ajouté à %2$s',
'Change:AttName_Changed_PreviousValue_OldValue' => '%1$s modifié, ancienne valeur: %2$s',
'Change:AttName_Changed' => '%1$s modifié',
));
//
// Class: CMDBChangeOpSetAttributeBlob
//
Dict::Add('FR FR', 'French', 'Français', array(
'Class:CMDBChangeOpSetAttributeBlob' => 'data change',
'Class:CMDBChangeOpSetAttributeBlob+' => 'data change tracking',
'Class:CMDBChangeOpSetAttributeBlob/Attribute:prevdata' => 'Previous data',
'Class:CMDBChangeOpSetAttributeBlob/Attribute:prevdata+' => 'previous contents of the attribute',
));
//
// Class: CMDBChangeOpSetAttributeText
//
Dict::Add('FR FR', 'French', 'Français', array(
'Class:CMDBChangeOpSetAttributeText' => 'text change',
'Class:CMDBChangeOpSetAttributeText+' => 'text change tracking',
'Class:CMDBChangeOpSetAttributeText/Attribute:prevdata' => 'Previous data',
'Class:CMDBChangeOpSetAttributeText/Attribute:prevdata+' => 'previous contents of the attribute',
));
//
// Class: Event
//
Dict::Add('FR FR', 'French', 'Français', array(
'Class:Event' => 'Log Event',
'Class:Event+' => 'An application internal event',
'Class:Event/Attribute:message' => 'message',
'Class:Event/Attribute:message+' => 'short description of the event',
'Class:Event/Attribute:date' => 'date',
'Class:Event/Attribute:date+' => 'date and time at which the changes have been recorded',
'Class:Event/Attribute:userinfo' => 'user info',
'Class:Event/Attribute:userinfo+' => 'identification of the user that was doing the action that triggered this event',
'Class:Event/Attribute:finalclass' => 'type',
'Class:Event/Attribute:finalclass+' => '',
));
//
// Class: EventNotification
//
Dict::Add('FR FR', 'French', 'Français', array(
'Class:EventNotification' => 'Notification event',
'Class:EventNotification+' => 'Trace of a notification that has been sent',
'Class:EventNotification/Attribute:trigger_id' => 'Trigger',
'Class:EventNotification/Attribute:trigger_id+' => 'user account',
'Class:EventNotification/Attribute:action_id' => 'user',
'Class:EventNotification/Attribute:action_id+' => 'user account',
'Class:EventNotification/Attribute:object_id' => 'Object id',
'Class:EventNotification/Attribute:object_id+' => 'object id (class defined by the trigger ?)',
));
//
// Class: EventNotificationEmail
//
Dict::Add('FR FR', 'French', 'Français', array(
'Class:EventNotificationEmail' => 'Email emission event',
'Class:EventNotificationEmail+' => 'Trace of an email that has been sent',
'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+' => 'Sender of the message',
'Class:EventNotificationEmail/Attribute:subject' => 'Subject',
'Class:EventNotificationEmail/Attribute:subject+' => 'Subject',
'Class:EventNotificationEmail/Attribute:body' => 'Body',
'Class:EventNotificationEmail/Attribute:body+' => 'Body',
));
//
// Class: EventIssue
//
Dict::Add('FR FR', 'French', 'Français', array(
'Class:EventIssue' => 'Issue event',
'Class:EventIssue+' => 'Trace of an issue (warning, error, etc.)',
'Class:EventIssue/Attribute:issue' => 'Issue',
'Class:EventIssue/Attribute:issue+' => 'What happened',
'Class:EventIssue/Attribute:impact' => 'Impact',
'Class:EventIssue/Attribute:impact+' => 'What are the consequences',
'Class:EventIssue/Attribute:page' => 'Page',
'Class:EventIssue/Attribute:page+' => 'HTTP entry point',
'Class:EventIssue/Attribute:arguments_post' => 'Posted arguments',
'Class:EventIssue/Attribute:arguments_post+' => 'HTTP POST arguments',
'Class:EventIssue/Attribute:arguments_get' => 'URL arguments',
'Class:EventIssue/Attribute:arguments_get+' => 'HTTP GET arguments',
'Class:EventIssue/Attribute:callstack' => 'Callstack',
'Class:EventIssue/Attribute:callstack+' => 'Call stack',
'Class:EventIssue/Attribute:data' => 'Data',
'Class:EventIssue/Attribute:data+' => 'More information',
));
//
// Class: EventWebService
//
Dict::Add('FR FR', 'French', 'Français', array(
'Class:EventWebService' => 'Web service event',
'Class:EventWebService+' => 'Trace of an web service call',
'Class:EventWebService/Attribute:verb' => 'Verb',
'Class:EventWebService/Attribute:verb+' => 'Name of the operation',
'Class:EventWebService/Attribute:result' => 'Result',
'Class:EventWebService/Attribute:result+' => 'Overall success/failure',
'Class:EventWebService/Attribute:log_info' => 'Info log',
'Class:EventWebService/Attribute:log_info+' => 'Result info log',
'Class:EventWebService/Attribute:log_warning' => 'Warning log',
'Class:EventWebService/Attribute:log_warning+' => 'Result warning log',
'Class:EventWebService/Attribute:log_error' => 'Error log',
'Class:EventWebService/Attribute:log_error+' => 'Result error log',
'Class:EventWebService/Attribute:data' => 'Data',
'Class:EventWebService/Attribute:data+' => 'Result data',
));
//
// Class: Action
//
Dict::Add('FR FR', 'French', 'Français', array(
'Class:Action' => 'action',
'Class:Action+' => 'Custom action',
'Class:Action/Attribute:name' => 'Name',
'Class:Action/Attribute:name+' => 'label',
'Class:Action/Attribute:description' => 'Description',
'Class:Action/Attribute:description+' => 'one line description',
'Class:Action/Attribute:status' => 'Status',
'Class:Action/Attribute:status+' => 'In production or ?',
'Class:Action/Attribute:status/Value:test' => 'Being tested',
'Class:Action/Attribute:status/Value:test+' => 'Being tested',
'Class:Action/Attribute:status/Value:enabled' => 'In production',
'Class:Action/Attribute:status/Value:enabled+' => 'In production',
'Class:Action/Attribute:status/Value:disabled' => 'Inactive',
'Class:Action/Attribute:status/Value:disabled+' => 'Inactive',
'Class:Action/Attribute:trigger_list' => 'Related Triggers',
'Class:Action/Attribute:trigger_list+' => 'Triggers linked to this action',
'Class:Action/Attribute:finalclass' => 'Type',
'Class:Action/Attribute:finalclass+' => '',
));
//
// Class: ActionNotification
//
Dict::Add('FR FR', 'French', 'Français', array(
'Class:ActionNotification' => 'notification',
'Class:ActionNotification+' => 'Notification (abstract)',
));
//
// Class: ActionEmail
//
Dict::Add('FR FR', 'French', 'Français', array(
'Class:ActionEmail' => 'email notification',
'Class:ActionEmail+' => 'Action: Email notification',
'Class:ActionEmail/Attribute:test_recipient' => 'Test recipient',
'Class:ActionEmail/Attribute:test_recipient+' => 'Detination in case status is set to "Test"',
'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+' => 'Destination of the email',
'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+' => 'Title of the email',
'Class:ActionEmail/Attribute:body' => 'body',
'Class:ActionEmail/Attribute:body+' => 'Contents of the email',
'Class:ActionEmail/Attribute:importance' => 'importance',
'Class:ActionEmail/Attribute:importance+' => 'Importance flag',
'Class:ActionEmail/Attribute:importance/Value:low' => 'low',
'Class:ActionEmail/Attribute:importance/Value:low+' => 'low',
'Class:ActionEmail/Attribute:importance/Value:normal' => 'normal',
'Class:ActionEmail/Attribute:importance/Value:normal+' => 'normal',
'Class:ActionEmail/Attribute:importance/Value:high' => 'high',
'Class:ActionEmail/Attribute:importance/Value:high+' => 'high',
));
'Class:ActionEmail/Attribute:test_recipient' => 'Destinataire de test',
'Class:ActionEmail/Attribute:test_recipient+' => '',
'Class:ActionEmail/Attribute:from' => 'De',
'Class:ActionEmail/Attribute:from+' => '',
'Class:ActionEmail/Attribute:reply_to' => 'Répondre à',
'Class:ActionEmail/Attribute:reply_to+' => '',
'Class:ActionEmail/Attribute:to' => 'A',
'Class:ActionEmail/Attribute:to+' => '',
'Class:ActionEmail/Attribute:cc' => 'Copie',
'Class:ActionEmail/Attribute:cc+' => '',
'Class:ActionEmail/Attribute:bcc' => 'Copie Cachée',
'Class:ActionEmail/Attribute:bcc+' => '',
'Class:ActionEmail/Attribute:subject' => 'Sujet',
'Class:ActionEmail/Attribute:subject+' => '',
'Class:ActionEmail/Attribute:body' => 'Message',
'Class:ActionEmail/Attribute:body+' => '',
'Class:ActionEmail/Attribute:importance' => 'Importance',
'Class:ActionEmail/Attribute:importance+' => '',
'Class:ActionEmail/Attribute:importance/Value:high' => 'Haute',
'Class:ActionEmail/Attribute:importance/Value:high+' => '',
'Class:ActionEmail/Attribute:importance/Value:low' => 'Basse',
'Class:ActionEmail/Attribute:importance/Value:low+' => '',
'Class:ActionEmail/Attribute:importance/Value:normal' => 'Normale',
'Class:ActionEmail/Attribute:importance/Value:normal+' => '',
'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 quittant un état',
'Class:TriggerOnStateLeave+' => '',
'Class:TriggerOnObjectCreate' => 'Déclencheur sur la création d\'un objet',
'Class:TriggerOnObjectCreate+' => '',
'Class:lnkTriggerAction' => 'Actions-Déclencheur',
'Class:lnkTriggerAction+' => '',
'Class:lnkTriggerAction/Attribute:action_id' => 'Action',
'Class:lnkTriggerAction/Attribute:action_id+' => '',
'Class:lnkTriggerAction/Attribute:action_name' => 'Nom de l\'action',
'Class:lnkTriggerAction/Attribute:action_name+' => '',
'Class:lnkTriggerAction/Attribute:trigger_id' => 'Déclencheur',
'Class:lnkTriggerAction/Attribute:trigger_id+' => '',
'Class:lnkTriggerAction/Attribute:trigger_name' => 'Nom du déclencheur',
'Class:lnkTriggerAction/Attribute:trigger_name+' => '',
'Class:lnkTriggerAction/Attribute:order' => 'Ordre',
'Class:lnkTriggerAction/Attribute:order+' => '',
'Class:AsyncSendEmail' => 'Envoi d\'Email Asynchrone',
'Class:AsyncSendEmail+' => '',
'Class:AsyncSendEmail/Attribute:to' => 'A',
'Class:AsyncSendEmail/Attribute:to+' => '',
'Class:AsyncSendEmail/Attribute:subject' => 'Sujet',
'Class:AsyncSendEmail/Attribute:subject+' => '',
'Class:AsyncSendEmail/Attribute:body' => 'Message',
'Class:AsyncSendEmail/Attribute:body+' => '',
'Class:AsyncSendEmail/Attribute:header' => 'En-tête',
'Class:AsyncSendEmail/Attribute:header+' => '',
'Class:CMDBChange' => 'Modification',
'Class:CMDBChange+' => '',
'Class:CMDBChange/Attribute:date' => 'Date',
'Class:CMDBChange/Attribute:date+' => '',
'Class:CMDBChange/Attribute:userinfo' => 'Autres informations',
'Class:CMDBChange/Attribute:userinfo+' => '',
'Class:CMDBChangeOp' => 'Operation de changement',
'Class:CMDBChangeOp+' => '',
'Class:CMDBChangeOp/Attribute:change' => 'Modification',
'Class:CMDBChangeOp/Attribute:change+' => '',
'Class:CMDBChangeOp/Attribute:date' => 'Date',
'Class:CMDBChangeOp/Attribute:date+' => '',
'Class:CMDBChangeOp/Attribute:userinfo' => 'Utilisateur',
'Class:CMDBChangeOp/Attribute:userinfo+' => '',
'Class:CMDBChangeOp/Attribute:objclass' => 'Type d\'objet',
'Class:CMDBChangeOp/Attribute:objclass+' => '',
'Class:CMDBChangeOp/Attribute:objkey' => 'Clé',
'Class:CMDBChangeOp/Attribute:objkey+' => '',
'Class:CMDBChangeOp/Attribute:finalclass' => 'Type',
'Class:CMDBChangeOp/Attribute:finalclass+' => '',
'Class:CMDBChangeOpCreate' => 'Création de l\'objet',
'Class:CMDBChangeOpCreate+' => '',
'Class:CMDBChangeOpDelete' => 'Effacement de l\'objet',
'Class:CMDBChangeOpDelete+' => '',
'Class:CMDBChangeOpSetAttribute' => 'Modification de l\'objet',
'Class:CMDBChangeOpSetAttribute+' => '',
'Class:CMDBChangeOpSetAttribute/Attribute:attcode' => 'Champ',
'Class:CMDBChangeOpSetAttribute/Attribute:attcode+' => '',
'Class:CMDBChangeOpSetAttributeScalar' => 'Modification de valeur',
'Class:CMDBChangeOpSetAttributeScalar+' => '',
'Class:CMDBChangeOpSetAttributeScalar/Attribute:oldvalue' => 'Ancienne valeur',
'Class:CMDBChangeOpSetAttributeScalar/Attribute:oldvalue+' => '',
'Class:CMDBChangeOpSetAttributeScalar/Attribute:newvalue' => 'Nouvelle valeur',
'Class:CMDBChangeOpSetAttributeScalar/Attribute:newvalue+' => '',
'Class:CMDBChangeOpSetAttributeBlob' => 'Modification de données',
'Class:CMDBChangeOpSetAttributeBlob+' => '',
'Class:CMDBChangeOpSetAttributeBlob/Attribute:prevdata' => 'Ancienne valeur',
'Class:CMDBChangeOpSetAttributeBlob/Attribute:prevdata+' => '',
'Class:CMDBChangeOpSetAttributeOneWayPassword' => 'Mot de passe chiffré',
'Class:CMDBChangeOpSetAttributeOneWayPassword+' => '',
'Class:CMDBChangeOpSetAttributeOneWayPassword/Attribute:prev_pwd' => 'Ancien mot de passe',
'Class:CMDBChangeOpSetAttributeOneWayPassword/Attribute:prev_pwd+' => '',
'Class:CMDBChangeOpSetAttributeEncrypted' => 'Champ chiffré',
'Class:CMDBChangeOpSetAttributeEncrypted+' => '',
'Class:CMDBChangeOpSetAttributeEncrypted/Attribute:prevstring' => 'Ancienne valeur',
'Class:CMDBChangeOpSetAttributeEncrypted/Attribute:prevstring+' => '',
'Class:CMDBChangeOpSetAttributeText' => 'Modification de texte',
'Class:CMDBChangeOpSetAttributeText+' => '',
'Class:CMDBChangeOpSetAttributeText/Attribute:prevdata' => 'Ancienne valeur',
'Class:CMDBChangeOpSetAttributeText/Attribute:prevdata+' => '',
'Class:CMDBChangeOpSetAttributeCaseLog' => 'Archive de journal',
'Class:CMDBChangeOpSetAttributeCaseLog+' => '',
'Class:CMDBChangeOpSetAttributeCaseLog/Attribute:lastentry' => 'Dernière entrée',
'Class:CMDBChangeOpSetAttributeCaseLog/Attribute:lastentry+' => '',
'Class:Event' => 'Evenement',
'Class:Event+' => '',
'Class:Event/Attribute:message' => 'Message',
'Class:Event/Attribute:message+' => '',
'Class:Event/Attribute:date' => 'Date',
'Class:Event/Attribute:date+' => '',
'Class:Event/Attribute:userinfo' => 'Utilisateur',
'Class:Event/Attribute:userinfo+' => '',
'Class:Event/Attribute:finalclass' => 'Type',
'Class:Event/Attribute:finalclass+' => '',
'Class:EventNotification' => 'Notification',
'Class:EventNotification+' => '',
'Class:EventNotification/Attribute:trigger_id' => 'Déclencheur',
'Class:EventNotification/Attribute:trigger_id+' => '',
'Class:EventNotification/Attribute:action_id' => 'Action',
'Class:EventNotification/Attribute:action_id+' => '',
'Class:EventNotification/Attribute:object_id' => 'Objet',
'Class:EventNotification/Attribute:object_id+' => '',
'Class:EventNotificationEmail' => 'Envoi d\'Email',
'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' => 'De',
'Class:EventNotificationEmail/Attribute:from+' => '',
'Class:EventNotificationEmail/Attribute:subject' => 'Sujet',
'Class:EventNotificationEmail/Attribute:subject+' => '',
'Class:EventNotificationEmail/Attribute:body' => 'Message',
'Class:EventNotificationEmail/Attribute:body+' => '',
'Class:EventIssue' => 'Erreur',
'Class:EventIssue+' => '',
'Class:EventIssue/Attribute:issue' => 'Erreur',
'Class:EventIssue/Attribute:issue+' => '',
'Class:EventIssue/Attribute:impact' => 'Impact',
'Class:EventIssue/Attribute:impact+' => '',
'Class:EventIssue/Attribute:page' => 'Page Web',
'Class:EventIssue/Attribute:page+' => '',
'Class:EventIssue/Attribute:arguments_post' => 'Arguments (POST)',
'Class:EventIssue/Attribute:arguments_post+' => '',
'Class:EventIssue/Attribute:arguments_get' => 'Arguments (GET)',
'Class:EventIssue/Attribute:arguments_get+' => '',
'Class:EventIssue/Attribute:callstack' => 'Pile d\'appel',
'Class:EventIssue/Attribute:callstack+' => '',
'Class:EventIssue/Attribute:data' => 'Données',
'Class:EventIssue/Attribute:data+' => '',
'Class:EventWebService' => 'Appel de webservice',
'Class:EventWebService+' => '',
'Class:EventWebService/Attribute:verb' => 'Verbe',
'Class:EventWebService/Attribute:verb+' => '',
'Class:EventWebService/Attribute:result' => 'Résultat',
'Class:EventWebService/Attribute:result+' => '',
'Class:EventWebService/Attribute:log_info' => 'Informations',
'Class:EventWebService/Attribute:log_info+' => '',
'Class:EventWebService/Attribute:log_warning' => 'Avertissement',
'Class:EventWebService/Attribute:log_warning+' => '',
'Class:EventWebService/Attribute:log_error' => 'Erreurs',
'Class:EventWebService/Attribute:log_error+' => '',
'Class:EventWebService/Attribute:data' => 'Données',
'Class:EventWebService/Attribute:data+' => '',
'Class:EventLoginUsage' => 'Utilisation de l\'application',
'Class:EventLoginUsage+' => '',
'Class:EventLoginUsage/Attribute:user_id' => 'Login',
'Class:EventLoginUsage/Attribute:user_id+' => '',
'Class:EventLoginUsage/Attribute:contact_name' => 'Nom de l\'utilisateur',
'Class:EventLoginUsage/Attribute:contact_name+' => '',
'Class:EventLoginUsage/Attribute:contact_email' => 'Email',
'Class:EventLoginUsage/Attribute:contact_email+' => '',
'Class:SynchroDataSource' => 'Source de données',
'Class:SynchroDataSource+' => '',
'Class:SynchroDataSource/Attribute:name' => 'Nom',
'Class:SynchroDataSource/Attribute:name+' => '',
'Class:SynchroDataSource/Attribute:description' => 'Description',
'Class:SynchroDataSource/Attribute:description+' => '',
'Class:SynchroDataSource/Attribute:status' => 'Etat',
'Class:SynchroDataSource/Attribute:status+' => '',
'Class:SynchroDataSource/Attribute:status/Value:implementation' => 'Implémentation',
'Class:SynchroDataSource/Attribute:status/Value:implementation+' => '',
'Class:SynchroDataSource/Attribute:status/Value:obsolete' => 'Obsolete',
'Class:SynchroDataSource/Attribute:status/Value:obsolete+' => '',
'Class:SynchroDataSource/Attribute:status/Value:production' => 'Production',
'Class:SynchroDataSource/Attribute:status/Value:production+' => '',
'Class:SynchroDataSource/Attribute:user_id' => 'Utilisateur',
'Class:SynchroDataSource/Attribute:user_id+' => 'Seul cet utilisateur (et les administrateurs) peuvent exécuter cette synchronisation',
'Class:SynchroDataSource/Attribute:notify_contact_id' => 'Contact à notifier',
'Class:SynchroDataSource/Attribute:notify_contact_id+' => 'Contact à notifier en cas d\'erreur',
'Class:SynchroDataSource/Attribute:scope_class' => 'Type cible',
'Class:SynchroDataSource/Attribute:scope_class+' => 'Type d\'objets à synchroniser',
'Class:SynchroDataSource/Attribute:scope_restriction' => 'Restriction',
'Class:SynchroDataSource/Attribute:scope_restriction+' => '',
'Class:SynchroDataSource/Attribute:full_load_periodicity' => 'Obsolescence après',
'Class:SynchroDataSource/Attribute:full_load_periodicity+' => 'Un objet est considéré comme obsolète s\'il n\'apparaît pas dans les données au delà de cette durée',
'Class:SynchroDataSource/Attribute:reconciliation_policy' => 'Politique de recherche',
'Class:SynchroDataSource/Attribute:reconciliation_policy+' => '',
'Class:SynchroDataSource/Attribute:reconciliation_policy/Value:use_attributes' => 'Utiliser les champs',
'Class:SynchroDataSource/Attribute:reconciliation_policy/Value:use_attributes+' => '',
'Class:SynchroDataSource/Attribute:reconciliation_policy/Value:use_primary_key' => 'Utiliser la clé primaire',
'Class:SynchroDataSource/Attribute:reconciliation_policy/Value:use_primary_key+' => '',
'Class:SynchroDataSource/Attribute:action_on_zero' => 'Action si zéro',
'Class:SynchroDataSource/Attribute:action_on_zero+' => '',
'Class:SynchroDataSource/Attribute:action_on_zero/Value:create' => 'Créer',
'Class:SynchroDataSource/Attribute:action_on_zero/Value:create+' => '',
'Class:SynchroDataSource/Attribute:action_on_zero/Value:error' => 'Erreur',
'Class:SynchroDataSource/Attribute:action_on_zero/Value:error+' => '',
'Class:SynchroDataSource/Attribute:action_on_one' => 'Action si un',
'Class:SynchroDataSource/Attribute:action_on_one+' => '',
'Class:SynchroDataSource/Attribute:action_on_one/Value:error' => 'Erreur',
'Class:SynchroDataSource/Attribute:action_on_one/Value:error+' => '',
'Class:SynchroDataSource/Attribute:action_on_one/Value:update' => 'Mettre à jour',
'Class:SynchroDataSource/Attribute:action_on_one/Value:update+' => '',
'Class:SynchroDataSource/Attribute:action_on_multiple' => 'Action si plusieurs',
'Class:SynchroDataSource/Attribute:action_on_multiple+' => '',
'Class:SynchroDataSource/Attribute:action_on_multiple/Value:create' => 'Créer',
'Class:SynchroDataSource/Attribute:action_on_multiple/Value:create+' => '',
'Class:SynchroDataSource/Attribute:action_on_multiple/Value:error' => 'Erreur',
'Class:SynchroDataSource/Attribute:action_on_multiple/Value:error+' => '',
'Class:SynchroDataSource/Attribute:action_on_multiple/Value:take_first' => 'Prendre le premier',
'Class:SynchroDataSource/Attribute:action_on_multiple/Value:take_first+' => '',
'Class:SynchroDataSource/Attribute:delete_policy' => 'Politique d\'effacement',
'Class:SynchroDataSource/Attribute:delete_policy+' => 'Façon dont sont traités les objets obsolètes',
'Class:SynchroDataSource/Attribute:delete_policy/Value:delete' => 'Effacer',
'Class:SynchroDataSource/Attribute:delete_policy/Value:delete+' => '',
'Class:SynchroDataSource/Attribute:delete_policy/Value:ignore' => 'Ignorer',
'Class:SynchroDataSource/Attribute:delete_policy/Value:ignore+' => '',
'Class:SynchroDataSource/Attribute:delete_policy/Value:update' => 'Mettre à jour',
'Class:SynchroDataSource/Attribute:delete_policy/Value:update+' => '',
'Class:SynchroDataSource/Attribute:delete_policy/Value:update_then_delete' => 'Mettre à jour puis effacer',
'Class:SynchroDataSource/Attribute:delete_policy/Value:update_then_delete+' => '',
'Class:SynchroDataSource/Attribute:delete_policy_update' => 'Mise à jour',
'Class:SynchroDataSource/Attribute:delete_policy_update+' => 'Format: nom_de_champ:valeur; ...',
'Class:SynchroDataSource/Attribute:delete_policy_retention' => 'Durée de rétention',
'Class:SynchroDataSource/Attribute:delete_policy_retention+' => 'Si la politique est \'Mettre à jour puis effacer\', les objets obsolètes sont encore conservés pendant cette durée avant d\'être effacés',
'Class:SynchroDataSource/Attribute:attribute_list' => 'Liste des champs',
'Class:SynchroDataSource/Attribute:attribute_list+' => '',
'Class:SynchroDataSource/Attribute:user_delete_policy' => 'Utilisateurs autorisés',
'Class:SynchroDataSource/Attribute:user_delete_policy+' => 'Quels utilisateurs sont autorisés à effacer des objets synchronisés',
'Class:SynchroDataSource/Attribute:user_delete_policy/Value:administrators' => 'Seulement les administrateurs',
'Class:SynchroDataSource/Attribute:user_delete_policy/Value:administrators+' => '',
'Class:SynchroDataSource/Attribute:user_delete_policy/Value:everybody' => 'Tous les utilisateurs autorisés',
'Class:SynchroDataSource/Attribute:user_delete_policy/Value:everybody+' => '',
'Class:SynchroDataSource/Attribute:user_delete_policy/Value:nobody' => 'Personne',
'Class:SynchroDataSource/Attribute:user_delete_policy/Value:nobody+' => '',
'Class:SynchroDataSource/Attribute:url_icon' => 'Icône (hyperlien)',
'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',
'Class:SynchroAttribute/Attribute:sync_source_id+' => '',
'Class:SynchroAttribute/Attribute:attcode' => 'Champ',
'Class:SynchroAttribute/Attribute:attcode+' => '',
'Class:SynchroAttribute/Attribute:update' => 'Mise à jour',
'Class:SynchroAttribute/Attribute:update+' => '',
'Class:SynchroAttribute/Attribute:reconcile' => 'Recherche',
'Class:SynchroAttribute/Attribute:reconcile+' => '',
'Class:SynchroAttribute/Attribute:update_policy' => 'Politique de mise à jour',
'Class:SynchroAttribute/Attribute:update_policy+' => '',
'Class:SynchroAttribute/Attribute:update_policy/Value:master_locked' => 'Maître (verrouillé)',
'Class:SynchroAttribute/Attribute:update_policy/Value:master_locked+' => '',
'Class:SynchroAttribute/Attribute:update_policy/Value:master_unlocked' => 'Maître (non-verrouillé)',
'Class:SynchroAttribute/Attribute:update_policy/Value:master_unlocked+' => '',
'Class:SynchroAttribute/Attribute:update_policy/Value:write_if_empty' => 'Ecrire si le champ est vide',
'Class:SynchroAttribute/Attribute:update_policy/Value:write_if_empty+' => '',
'Class:SynchroAttribute/Attribute:finalclass' => 'Type',
'Class:SynchroAttribute/Attribute:finalclass+' => '',
'Class:SynchroAttExtKey' => 'Synchro Clé Externe',
'Class:SynchroAttExtKey+' => '',
'Class:SynchroAttExtKey/Attribute:reconciliation_attcode' => 'Champ',
'Class:SynchroAttExtKey/Attribute:reconciliation_attcode+' => '',
'Class:SynchroAttLinkSet' => 'Synchro Linkset',
'Class:SynchroAttLinkSet+' => '',
'Class:SynchroAttLinkSet/Attribute:row_separator' => 'Séparateur de colonnes',
'Class:SynchroAttLinkSet/Attribute:row_separator+' => '',
'Class:SynchroAttLinkSet/Attribute:attribute_separator' => 'Séparateur de champs',
'Class:SynchroAttLinkSet/Attribute:attribute_separator+' => '',
'Class:SynchroLog' => 'Journal de Synchro',
'Class:SynchroLog+' => '',
'Class:SynchroLog/Attribute:sync_source_id' => 'Source de données',
'Class:SynchroLog/Attribute:sync_source_id+' => '',
'Class:SynchroLog/Attribute:start_date' => 'Date/heure de début',
'Class:SynchroLog/Attribute:start_date+' => '',
'Class:SynchroLog/Attribute:end_date' => 'Date/heure de fin',
'Class:SynchroLog/Attribute:end_date+' => '',
'Class:SynchroLog/Attribute:status' => 'Etat',
'Class:SynchroLog/Attribute:status+' => '',
'Class:SynchroLog/Attribute:status/Value:completed' => 'Terminé Ok',
'Class:SynchroLog/Attribute:status/Value:completed+' => '',
'Class:SynchroLog/Attribute:status/Value:error' => 'Erreur',
'Class:SynchroLog/Attribute:status/Value:error+' => '',
'Class:SynchroLog/Attribute:status/Value:running' => 'En cours',
'Class:SynchroLog/Attribute:status/Value:running+' => '',
'Class:SynchroLog/Attribute:stats_nb_replica_seen' => 'Nb de réplicas vus',
'Class:SynchroLog/Attribute:stats_nb_replica_seen+' => '',
'Class:SynchroLog/Attribute:stats_nb_replica_total' => 'Nb total de réplicas',
'Class:SynchroLog/Attribute:stats_nb_replica_total+' => '',
'Class:SynchroLog/Attribute:stats_nb_obj_deleted' => 'Nb d\'objets effacés',
'Class:SynchroLog/Attribute:stats_nb_obj_deleted+' => '',
'Class:SynchroLog/Attribute:stats_nb_obj_deleted_errors' => 'Nb d\'erreurs lors de l\'effacement',
'Class:SynchroLog/Attribute:stats_nb_obj_deleted_errors+' => '',
'Class:SynchroLog/Attribute:stats_nb_obj_obsoleted' => 'Nb d\'objets obsolètés',
'Class:SynchroLog/Attribute:stats_nb_obj_obsoleted+' => '',
'Class:SynchroLog/Attribute:stats_nb_obj_obsoleted_errors' => 'Nb d\'erreurs lors de l\'obsolescence',
'Class:SynchroLog/Attribute:stats_nb_obj_obsoleted_errors+' => '',
'Class:SynchroLog/Attribute:stats_nb_obj_created' => 'Nb d\'objets créés',
'Class:SynchroLog/Attribute:stats_nb_obj_created+' => '',
'Class:SynchroLog/Attribute:stats_nb_obj_created_errors' => 'Nb d\'erreurs lors de la création',
'Class:SynchroLog/Attribute:stats_nb_obj_created_errors+' => '',
'Class:SynchroLog/Attribute:stats_nb_obj_updated' => 'Nb d\'objets mis à jour',
'Class:SynchroLog/Attribute:stats_nb_obj_updated+' => '',
'Class:SynchroLog/Attribute:stats_nb_obj_updated_errors' => 'Nb d\erreurs lors de la mise à jour',
'Class:SynchroLog/Attribute:stats_nb_obj_updated_errors+' => '',
'Class:SynchroLog/Attribute:stats_nb_replica_reconciled_errors' => 'Nb d\'erreurs lors de la réconciliation',
'Class:SynchroLog/Attribute:stats_nb_replica_reconciled_errors+' => '',
'Class:SynchroLog/Attribute:stats_nb_replica_disappeared_no_action' => 'Nb d\'objets disparus',
'Class:SynchroLog/Attribute:stats_nb_replica_disappeared_no_action+' => '',
'Class:SynchroLog/Attribute:stats_nb_obj_new_updated' => 'Nb d\'objets (nouveaux) mis à jour',
'Class:SynchroLog/Attribute:stats_nb_obj_new_updated+' => '',
'Class:SynchroLog/Attribute:stats_nb_obj_new_unchanged' => 'Nb d\'objets (nouveaux) inchangés',
'Class:SynchroLog/Attribute:stats_nb_obj_new_unchanged+' => '',
'Class:SynchroLog/Attribute:last_error' => 'Dernière erreur',
'Class:SynchroLog/Attribute:last_error+' => '',
'Class:SynchroLog/Attribute:traces' => 'Traces',
'Class:SynchroLog/Attribute:traces+' => '',
'Class:SynchroReplica' => 'Réplica de Synchronisation',
'Class:SynchroReplica+' => '',
'Class:SynchroReplica/Attribute:sync_source_id' => 'Source de données',
'Class:SynchroReplica/Attribute:sync_source_id+' => '',
'Class:SynchroReplica/Attribute:base_class' => 'Type de base',
'Class:SynchroReplica/Attribute:base_class+' => '',
'Class:SynchroReplica/Attribute:dest_id' => 'Objet destination',
'Class:SynchroReplica/Attribute:dest_id+' => '',
'Class:SynchroReplica/Attribute:dest_class' => 'Type de l\'objet',
'Class:SynchroReplica/Attribute:dest_class+' => '',
'Class:SynchroReplica/Attribute:status_last_seen' => 'Dernière détection',
'Class:SynchroReplica/Attribute:status_last_seen+' => '',
'Class:SynchroReplica/Attribute:status' => 'Etat',
'Class:SynchroReplica/Attribute:status+' => '',
'Class:SynchroReplica/Attribute:status/Value:modified' => 'Modifié',
'Class:SynchroReplica/Attribute:status/Value:modified+' => '',
'Class:SynchroReplica/Attribute:status/Value:new' => 'Nouveau',
'Class:SynchroReplica/Attribute:status/Value:new+' => '',
'Class:SynchroReplica/Attribute:status/Value:obsolete' => 'Obsolete',
'Class:SynchroReplica/Attribute:status/Value:obsolete+' => '',
'Class:SynchroReplica/Attribute:status/Value:orphan' => 'Orphelin',
'Class:SynchroReplica/Attribute:status/Value:orphan+' => '',
'Class:SynchroReplica/Attribute:status/Value:synchronized' => 'Synchronisé',
'Class:SynchroReplica/Attribute:status/Value:synchronized+' => '',
'Class:SynchroReplica/Attribute:status_dest_creator' => 'Créé par la source ?',
'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',
'Class:SynchroReplica/Attribute:info_last_modified+' => '',
'Class:appUserPreferences' => 'Préférences utilisateur',
'Class:appUserPreferences+' => '',
'Class:appUserPreferences/Attribute:userid' => 'Utilisateur',
'Class:appUserPreferences/Attribute:userid+' => '',
'Class:appUserPreferences/Attribute:preferences' => 'Préférences',
'Class:appUserPreferences/Attribute:preferences+' => '',
'Core:AttributeLinkedSet' => 'Objets liés (1-n)',
'Core:AttributeLinkedSet+' => 'Liste d\'objets d\'une classe donnée et pointant sur l\'objet courant',
'Core:AttributeLinkedSetIndirect' => 'Objets liés (1-n)',
'Core:AttributeLinkedSetIndirect+' => 'Liste d\'objets d\'une classe donnée et liés à l\'objet courant via une classe intermédiaire',
'Core:AttributeInteger' => 'Nombre entier',
'Core:AttributeInteger+' => 'Valeur numérique entière',
'Core:AttributeDecimal' => 'Nombre décimal',
'Core:AttributeDecimal+' => 'Valeur numérique décimale',
'Core:AttributeBoolean' => 'Booléen',
'Core:AttributeBoolean+' => 'Booléen',
'Core:AttributeString' => 'Chaîne de caractères',
'Core:AttributeString+' => 'Chaîne de caractères (limitée à une ligne)',
'Core:AttributeClass' => 'Classe',
'Core:AttributeClass+' => 'Classe d\'objets',
'Core:AttributeApplicationLanguage' => 'Langue',
'Core:AttributeApplicationLanguage+' => 'Codes langue et pays (EN US)',
'Core:AttributeFinalClass' => 'Classe',
'Core:AttributeFinalClass+' => 'Classe réelle de l\'objet (attribut créé automatiquement)',
'Core:AttributePassword' => 'Mot de passe',
'Core:AttributePassword+' => 'Mot de passe qui peut être lu en clair',
'Core:AttributeEncryptedString' => 'Chaîne encryptée',
'Core:AttributeEncryptedString+' => 'Chaîne encryptée avec une clé locale',
'Core:AttributeText' => 'Texte',
'Core:AttributeText+' => 'Chaîne de caractères de plusieurs lignes',
'Core:AttributeHTML' => 'HTML',
'Core:AttributeHTML+' => 'Texte formatté en HTML',
'Core:AttributeEmailAddress' => 'Adresse électronique',
'Core:AttributeEmailAddress+' => 'Adresse électronique (xxxx@yyy.zzz)',
'Core:AttributeIPAddress' => 'Adresse IP',
'Core:AttributeIPAddress+' => 'Adresse IP',
'Core:AttributeOQL' => 'Expression OQL',
'Core:AttributeOQL+' => 'Expression formattée en "Object Query Language"',
'Core:AttributeEnum' => 'Enumération',
'Core:AttributeEnum+' => 'Valeur choisie parmi un liste de chaîne de caractères',
'Core:AttributeTemplateString' => 'Modèle de chaîne de caractères',
'Core:AttributeTemplateString+' => 'Chaîne de caractères d\'une ligne, contenant des espaces réservés pour des données iTop',
'Core:AttributeTemplateText' => 'Modèle de texte',
'Core:AttributeTemplateText+' => 'Texte contenant des espaces réservés pour des données iTop',
'Core:AttributeTemplateHTML' => 'Modèle HTML',
'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>&gt;</b><em>date</em><br/>
<b>&lt;</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>&gt;</b><em>date</em><br/>
<b>&lt;</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',
'Core:AttributeExternalKey+' => 'Clé externe',
'Core:AttributeExternalField' => 'Attribut externe',
'Core:AttributeExternalField+' => 'Copie de la valeur d\'un attribut de l\'objet lié par une clé externe',
'Core:AttributeURL' => 'URL',
'Core:AttributeURL+' => 'URL absolue ou relative',
'Core:AttributeBlob' => 'Blob',
'Core:AttributeBlob+' => 'Contenu binaire (document)',
'Core:AttributeOneWayPassword' => 'Mot de passe "one way"',
'Core:AttributeOneWayPassword+' => 'Mot de passe qui peut être vérifié mais jamais lu en clair',
'Core:AttributeTable' => 'Table',
'Core:AttributeTable+' => 'Tableau à deux dimensions',
'Core:AttributePropertySet' => 'Propriétés',
'Core:AttributePropertySet+' => 'Liste de propriétés (nom et valeur) non typées',
//
// Class: Trigger
//
'Core:AttributeFriendlyName' => 'Nom usuel (convivial)',
'Core:AttributeFriendlyName+' => 'Attribut créé automatiquement ; sa valeur est calculée d\'après d\'autres attributs',
Dict::Add('FR FR', 'French', 'Français', array(
'Class:Trigger' => 'trigger',
'Class:Trigger+' => 'Custom event handler',
'Core:FriendlyName-Label' => 'Nom',
'Core:FriendlyName-Description' => 'Nom usuel',
'Change:ObjectCreated' => 'Elément créé',
'Change:ObjectDeleted' => 'Elément effacé',
'Change:ObjectModified' => 'Elément modifié',
'Change:AttName_SetTo_NewValue_PreviousValue_OldValue' => '%1$s modifié en %2$s (ancienne valeur: %3$s)',
'Change:AttName_SetTo' => '%1$s modifié en %2$s',
'Change:Text_AppendedTo_AttName' => '%1$s ajouté à %2$s',
'Change:AttName_Changed_PreviousValue_OldValue' => '%1$s modifié, ancienne valeur: %2$s',
'Change:AttName_Changed' => '%1$s modifié',
'Change:AttName_EntryAdded' => '%1$s champ modifié, une nouvelle entrée a été ajoutée',
'Class:Action' => 'Action',
'Class:Action+' => 'Action spécifique',
'Class:Action/Attribute:name' => 'Nom',
'Class:Action/Attribute:name+' => 'Label',
'Class:Action/Attribute:description' => 'Description',
'Class:Action/Attribute:description+' => '',
'Class:Action/Attribute:status' => 'Etat',
'Class:Action/Attribute:status+' => '',
'Class:Action/Attribute:status/Value:test' => 'En test',
'Class:Action/Attribute:status/Value:test+' => '',
'Class:Action/Attribute:status/Value:enabled' => 'En production',
'Class:Action/Attribute:status/Value:enabled+' => '',
'Class:Action/Attribute:status/Value:disabled' => 'Inactive',
'Class:Action/Attribute:status/Value:disabled+' => '',
'Class:Action/Attribute:trigger_list' => 'Déclencheurs liés',
'Class:Action/Attribute:trigger_list+' => '',
'Class:Action/Attribute:finalclass' => 'Type',
'Class:Action/Attribute:finalclass+' => '',
'Class:ActionNotification' => 'notification',
'Class:ActionNotification+' => '',
'Class:Trigger' => 'Déclencheur',
'Class:Trigger+' => '',
'Class:Trigger/Attribute:description' => 'Description',
'Class:Trigger/Attribute:description+' => 'one line description',
'Class:Trigger/Attribute:action_list' => 'Triggered actions',
'Class:Trigger/Attribute:action_list+' => 'Actions performed when the trigger is activated',
'Class:Trigger/Attribute:description+' => '',
'Class:Trigger/Attribute:action_list' => 'Actions déclenchées',
'Class:Trigger/Attribute:action_list+' => '',
'Class:Trigger/Attribute:finalclass' => 'Type',
'Class:Trigger/Attribute:finalclass+' => '',
));
//
// Class: TriggerOnObject
//
Dict::Add('FR FR', 'French', 'Français', array(
'Class:TriggerOnObject' => 'Trigger on a class of objects',
'Class:TriggerOnObject+' => 'Trigger on a given class of objects',
'Class:TriggerOnObject/Attribute:target_class' => 'Target class',
'Class:TriggerOnObject+' => '',
'Class:TriggerOnObject/Attribute:target_class' => 'Classe cible',
'Class:TriggerOnObject/Attribute:target_class+' => 'label',
));
//
// Class: TriggerOnStateChange
//
Dict::Add('FR FR', 'French', 'Français', array(
'Class:TriggerOnStateChange' => 'Trigger on object state change',
'Class:TriggerOnStateChange+' => 'Trigger on object state change',
'Class:TriggerOnStateChange/Attribute:state' => 'State',
'Class:TriggerOnStateChange+' => '',
'Class:TriggerOnStateChange/Attribute:state' => 'Etat',
'Class:TriggerOnStateChange/Attribute:state+' => 'label',
'Class:SynchroDataSource/Attribute:delete_policy/Value:never' => 'Personne',
'Class:SynchroDataSource/Attribute:delete_policy/Value:depends' => 'Uniquement les administrateurs',
'Class:SynchroDataSource/Attribute:delete_policy/Value:always' => 'Tous les utilisateurs autorisés',
'SynchroDataSource:Description' => 'Description',
'SynchroDataSource:Reconciliation' => 'Recherche et réconciliation',
'SynchroDataSource:Deletion' => 'Règles d\'effacement',
'SynchroDataSource:Status' => 'Etat',
'SynchroDataSource:Information' => 'Information',
'SynchroDataSource:Definition' => 'Définition',
'Core:SynchroAttributes' => 'Champs',
'Core:SynchroStatus' => 'Etat',
'Core:Synchro:ErrorsLabel' => 'Erreurs',
'Core:Synchro:CreatedLabel' => 'Créations',
'Core:Synchro:ModifiedLabel' => 'Modifications',
'Core:Synchro:UnchangedLabel' => 'Sans changement',
'Core:Synchro:ReconciledErrorsLabel' => 'Erreurs',
'Core:Synchro:ReconciledLabel' => 'Trouvés',
'Core:Synchro:ReconciledNewLabel' => 'Créations',
'Core:SynchroReconcile:Yes' => 'Oui',
'Core:SynchroReconcile:No' => 'Non',
'Core:SynchroUpdate:Yes' => 'Oui',
'Core:SynchroUpdate:No' => 'Non',
'Core:Synchro:LastestStatus' => 'Dernier état',
'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)',
'Menu:DataSources' => 'Synchronisation',
'Menu:DataSources+' => '',
'Core:Synchro:label_repl_ignored' => 'Ignorés (%1$s)',
'Core:Synchro:label_repl_disappeared' => 'Disparus (%1$s)',
'Core:Synchro:label_repl_existing' => 'Existants (%1$s)',
'Core:Synchro:label_repl_new' => 'Nouveau (%1$s)',
'Core:Synchro:label_obj_deleted' => 'Effacés (%1$s)',
'Core:Synchro:label_obj_obsoleted' => 'Obsoletés (%1$s)',
'Core:Synchro:label_obj_disappeared_errors' => 'Erreurs (%1$s)',
'Core:Synchro:label_obj_disappeared_no_action' => 'Aucune action (%1$s)',
'Core:Synchro:label_obj_unchanged' => 'Sans changement (%1$s)',
'Core:Synchro:label_obj_updated' => 'Mis à jour (%1$s)',
'Core:Synchro:label_obj_updated_errors' => 'Erreurs (%1$s)',
'Core:Synchro:label_obj_new_unchanged' => 'Sans changement (%1$s)',
'Core:Synchro:label_obj_new_updated' => 'Mis à jour (%1$s)',
'Core:Synchro:label_obj_created' => 'Créations (%1$s)',
'Core:Synchro:label_obj_new_errors' => 'Erreurs (%1$s)',
'Core:SynchroLogTitle' => '%1$s - %2$s',
'Core:Synchro:Nb_Replica' => 'Replica traités: %1$s',
'Core:Synchro:Nb_Class:Objects' => '%1$s: %2$s',
'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',
'Core:SynchroReplica:ListOfReplicas' => 'Liste des réplica',
'Core:SynchroAttExtKey:ReconciliationById' => 'id (clé primaire)',
'Core:SynchroAtt:attcode' => 'Champ',
'Core:SynchroAtt:attcode+' => '',
'Core:SynchroAtt:reconciliation' => 'Réconciliation ?',
'Core:SynchroAtt:reconciliation+' => '',
'Core:SynchroAtt:update' => 'Mise jour ?',
'Core:SynchroAtt:update+' => '',
'Core:SynchroAtt:update_policy' => 'Politique de mise à jour',
'Core:SynchroAtt:update_policy+' => '',
'Core:SynchroAtt:reconciliation_attcode' => 'Clé de recherche',
'Core:SynchroAtt:reconciliation_attcode+' => '',
'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',
'Core:Synchro:TheObjectWasCreatedBy_Source' => 'Cet objet a été <b>créé</b> par la source de données %1$s',
'Core:Synchro:TheObjectCanBeDeletedBy_Source' => 'Cet objet <b>peut être effacé/b> par la source de données %1$s',
'Core:Synchro:TheObjectCannotBeDeletedByUser_Source' => 'Vous <b>ne pouvez pas effacer</b> cet objet car il est géré par le source de données %1$s',
'TitleSynchroExecution' => 'Exécution de la synchronisation',
'Class:SynchroDataSource:DataTable' => 'Table contenant les données: %1$s',
'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',
'Core:Duration_Days_Hours_Minutes_Seconds' => '%1$sj %2$dh %3$dmin %4$ds',
));
//
// Class: TriggerOnStateEnter
//
Dict::Add('FR FR', 'French', 'Français', array(
'Class:TriggerOnStateEnter' => 'Trigger on object entering a state',
'Class:TriggerOnStateEnter+' => 'Trigger on object state change - entering',
));
//
// Class: TriggerOnStateLeave
//
Dict::Add('FR FR', 'French', 'Français', array(
'Class:TriggerOnStateLeave' => 'Trigger on object leaving a state',
'Class:TriggerOnStateLeave+' => 'Trigger on object state change - leaving',
));
//
// Class: TriggerOnObjectCreate
//
Dict::Add('FR FR', 'French', 'Français', array(
'Class:TriggerOnObjectCreate' => 'Trigger on object creation',
'Class:TriggerOnObjectCreate+' => 'Trigger on object creation of [a child class of] the given class',
));
//
// Class: lnkTriggerAction
//
Dict::Add('FR FR', 'French', 'Français', array(
'Class:lnkTriggerAction' => 'Actions-Trigger',
'Class:lnkTriggerAction+' => 'Link between a trigger and an action',
'Class:lnkTriggerAction/Attribute:action_id' => 'Action',
'Class:lnkTriggerAction/Attribute:action_id+' => 'The action to be executed',
'Class:lnkTriggerAction/Attribute:action_name' => 'Action Name',
'Class:lnkTriggerAction/Attribute:action_name+' => 'Name of the action',
'Class:lnkTriggerAction/Attribute:trigger_id' => 'Trigger',
'Class:lnkTriggerAction/Attribute:trigger_id+' => 'Trigger',
'Class:lnkTriggerAction/Attribute:trigger_name' => 'Trigger Name',
'Class:lnkTriggerAction/Attribute:trigger_name+' => 'Name of the trigger',
'Class:lnkTriggerAction/Attribute:order' => 'Order',
'Class:lnkTriggerAction/Attribute:order+' => 'Actions execution order',
));
?>
?>

View File

@@ -15,46 +15,12 @@
// 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
* @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
*/
//////////////////////////////////////////////////////////////////////
// Classes in 'gui'
//////////////////////////////////////////////////////////////////////
//
//////////////////////////////////////////////////////////////////////
// Classes in 'application'
//////////////////////////////////////////////////////////////////////
//
//
// Class: AuditCategory
//
Dict::Add('FR FR', 'French', 'Français', array(
'Class:AuditCategory' => 'Catégorie d\'audit',
'Class:AuditCategory+' => 'A section inside the overall audit',
'Class:AuditCategory/Attribute:name' => 'Nom',
'Class:AuditCategory/Attribute:name+' => 'Nom raccourci',
'Class:AuditCategory/Attribute:description' => 'Description',
'Class:AuditCategory/Attribute:description+' => 'Description',
'Class:AuditCategory/Attribute:definition_set' => 'Ensemble de définition',
'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: AuditRule
//
Dict::Add('FR FR', 'French', 'Français', array(
'Class:AuditRule' => 'Règle d\'audit',
'Class:AuditRule+' => '',
@@ -66,26 +32,106 @@ Dict::Add('FR FR', 'French', 'Français', array(
'Class:AuditRule/Attribute:query+' => 'Expression OQL de calcul des éléments incorrects',
'Class:AuditRule/Attribute:valid_flag' => 'Interprétation',
'Class:AuditRule/Attribute:valid_flag+' => 'La requête définit-elle les éléments valides ?',
'Class:AuditRule/Attribute:valid_flag/Value:true' => 'Objets valides',
'Class:AuditRule/Attribute:valid_flag/Value:true+' => '',
'Class:AuditRule/Attribute:valid_flag/Value:false' => 'Objets incorrects',
'Class:AuditRule/Attribute:valid_flag/Value:false+' => '',
'Class:AuditRule/Attribute:valid_flag/Value:true' => 'Objets valides',
'Class:AuditRule/Attribute:valid_flag/Value:true+' => '',
'Class:AuditRule/Attribute:category_id' => 'Catégorie',
'Class:AuditRule/Attribute:category_id+' => '',
'Class:AuditRule/Attribute:category_name' => 'Category',
'Class:AuditRule/Attribute:category_name' => 'Categorie',
'Class:AuditRule/Attribute:category_name+' => '',
));
//////////////////////////////////////////////////////////////////////
// Classes in 'addon/userrights'
//////////////////////////////////////////////////////////////////////
//
//
// Class: User
//
Dict::Add('FR FR', 'French', 'Français', array(
'Class:AuditCategory' => 'Catégorie d\'audit',
'Class:AuditCategory+' => 'Une section de l\'audit',
'Class:AuditCategory/Attribute:name' => 'Nom',
'Class:AuditCategory/Attribute:name+' => 'Nom raccourci',
'Class:AuditCategory/Attribute:description' => 'Description',
'Class:AuditCategory/Attribute:description+' => 'Description',
'Class:AuditCategory/Attribute:definition_set' => 'Ensemble de définition',
'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',
'Class:URP_Profiles/Attribute:name+' => '',
'Class:URP_Profiles/Attribute:description' => 'Description',
'Class:URP_Profiles/Attribute:description+' => '',
'Class:URP_Profiles/Attribute:user_list' => 'Utilisateurs',
'Class:URP_Profiles/Attribute:user_list+' => 'Comptes utilisateur (logins) ayant ce profil',
'Class:URP_UserProfile' => 'Utilisateur/Profil',
'Class:URP_UserProfile+' => '',
'Class:URP_UserProfile/Attribute:userid' => 'Utilisateur',
'Class:URP_UserProfile/Attribute:userid+' => '',
'Class:URP_UserProfile/Attribute:userlogin' => 'Login',
'Class:URP_UserProfile/Attribute:userlogin+' => '',
'Class:URP_UserProfile/Attribute:profileid' => 'Profil',
'Class:URP_UserProfile/Attribute:profileid+' => '',
'Class:URP_UserProfile/Attribute:profile' => 'Profil',
'Class:URP_UserProfile/Attribute:profile+' => '',
'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+' => 'Organisations permises pour l\'utilisateur',
'Class:URP_UserOrg/Attribute:userid' => 'Utilisateur',
'Class:URP_UserOrg/Attribute:userid+' => '',
'Class:URP_UserOrg/Attribute:userlogin' => 'Login',
'Class:URP_UserOrg/Attribute:userlogin+' => '',
'Class:URP_UserOrg/Attribute:allowed_org_id' => 'Organisation',
'Class:URP_UserOrg/Attribute:allowed_org_id+' => '',
'Class:URP_UserOrg/Attribute:allowed_org_name' => 'Organisation',
'Class:URP_UserOrg/Attribute:allowed_org_name+' => '',
'Class:URP_UserOrg/Attribute:reason' => 'Raison',
'Class:URP_UserOrg/Attribute:reason+' => 'Justifie la permission de voir les données de cette organisation',
'Class:URP_ActionGrant' => 'action_permission',
'Class:URP_ActionGrant+' => 'permissions on classes',
'Class:URP_ActionGrant/Attribute:profileid' => 'Profile',
'Class:URP_ActionGrant/Attribute:profileid+' => 'usage profile',
'Class:URP_ActionGrant/Attribute:profile' => 'Profile',
'Class:URP_ActionGrant/Attribute:profile+' => 'usage profile',
'Class:URP_ActionGrant/Attribute:class' => 'Class',
'Class:URP_ActionGrant/Attribute:class+' => 'Target class',
'Class:URP_ActionGrant/Attribute:permission' => 'Permission',
'Class:URP_ActionGrant/Attribute:permission+' => 'allowed or not allowed?',
'Class:URP_ActionGrant/Attribute:permission/Value:no' => 'no',
'Class:URP_ActionGrant/Attribute:permission/Value:no+' => 'no',
'Class:URP_ActionGrant/Attribute:permission/Value:yes' => 'yes',
'Class:URP_ActionGrant/Attribute:permission/Value:yes+' => 'yes',
'Class:URP_ActionGrant/Attribute:action' => 'Action',
'Class:URP_ActionGrant/Attribute:action+' => 'operations to perform on the given class',
'Class:URP_StimulusGrant' => 'stimulus_permission',
'Class:URP_StimulusGrant+' => 'permissions on stimilus in the life cycle of the object',
'Class:URP_StimulusGrant/Attribute:profileid' => 'Profile',
'Class:URP_StimulusGrant/Attribute:profileid+' => 'usage profile',
'Class:URP_StimulusGrant/Attribute:profile' => 'Profile',
'Class:URP_StimulusGrant/Attribute:profile+' => 'usage profile',
'Class:URP_StimulusGrant/Attribute:class' => 'Class',
'Class:URP_StimulusGrant/Attribute:class+' => 'Target class',
'Class:URP_StimulusGrant/Attribute:permission' => 'Permission',
'Class:URP_StimulusGrant/Attribute:permission+' => 'allowed or not allowed?',
'Class:URP_StimulusGrant/Attribute:permission/Value:no' => 'no',
'Class:URP_StimulusGrant/Attribute:permission/Value:no+' => 'no',
'Class:URP_StimulusGrant/Attribute:permission/Value:yes' => 'yes',
'Class:URP_StimulusGrant/Attribute:permission/Value:yes+' => 'yes',
'Class:URP_StimulusGrant/Attribute:stimulus' => 'Stimulus',
'Class:URP_StimulusGrant/Attribute:stimulus+' => 'stimulus code',
'Class:URP_AttributeGrant' => 'attribute_permission',
'Class:URP_AttributeGrant+' => 'permissions at the attributes level',
'Class:URP_AttributeGrant/Attribute:actiongrantid' => 'Action grant',
'Class:URP_AttributeGrant/Attribute:actiongrantid+' => 'action grant',
'Class:URP_AttributeGrant/Attribute:attcode' => 'Attribute',
'Class:URP_AttributeGrant/Attribute:attcode+' => 'attribute code',
'Class:User' => 'Utilisateur',
'Class:User+' => 'Compte utilisateur',
'Class:User/Attribute:finalclass' => 'Type de compte',
@@ -110,31 +156,8 @@ Dict::Add('FR FR', 'French', 'Français', array(
'Class:User/Attribute:profile_list+' => 'Rôles, ouvrants les droits d\'accès',
'Class:User/Attribute:allowed_org_list' => 'Organisations permises',
'Class:User/Attribute:allowed_org_list+' => 'L\'utilisateur a le droit de voir les données des organisations listées ici. Si aucune organisation n\'est spécifiée, alors aucune restriction ne s\'applique.',
'Class:User/Error:LoginMustBeUnique' => 'Le login doit être unique - "%1s" est déjà utilisé.',
'Class:User/Error:AtLeastOneProfileIsNeeded' => 'L\'utilisateur doit avoir au moins un profil.',
));
//
// Class: URP_Profiles
//
Dict::Add('FR FR', 'French', 'Français', array(
'Class:URP_Profiles' => 'Profil',
'Class:URP_Profiles+' => 'Profil utilisateur',
'Class:URP_Profiles/Attribute:name' => 'Nom',
'Class:URP_Profiles/Attribute:name+' => '',
'Class:URP_Profiles/Attribute:description' => 'Description',
'Class:URP_Profiles/Attribute:description+' => '',
'Class:URP_Profiles/Attribute:user_list' => 'Utilisateurs',
'Class:URP_Profiles/Attribute:user_list+' => 'Comptes utilisateur (logins) ayant ce profil',
));
//
// Class: URP_Dimensions
//
Dict::Add('FR FR', 'French', 'Français', array(
'Class:URP_Dimensions' => 'Dimension',
'Class:URP_Dimensions+' => 'Dimension applicative (défini des silos)',
'Class:URP_Dimensions/Attribute:name' => 'Nom',
@@ -143,51 +166,6 @@ Dict::Add('FR FR', 'French', 'Français', array(
'Class:URP_Dimensions/Attribute:description+' => '',
'Class:URP_Dimensions/Attribute:type' => 'Type',
'Class:URP_Dimensions/Attribute:type+' => 'Nom de classe ou type de données (unité de projection)',
));
//
// Class: URP_UserProfile
//
Dict::Add('FR FR', 'French', 'Français', array(
'Class:URP_UserProfile' => 'Utilisateur/Profil',
'Class:URP_UserProfile+' => '',
'Class:URP_UserProfile/Attribute:userid' => 'Utilisateur',
'Class:URP_UserProfile/Attribute:userid+' => '',
'Class:URP_UserProfile/Attribute:userlogin' => 'Login',
'Class:URP_UserProfile/Attribute:userlogin+' => '',
'Class:URP_UserProfile/Attribute:profileid' => 'Profil',
'Class:URP_UserProfile/Attribute:profileid+' => '',
'Class:URP_UserProfile/Attribute:profile' => 'Profil',
'Class:URP_UserProfile/Attribute:profile+' => '',
'Class:URP_UserProfile/Attribute:reason' => 'Raison',
'Class:URP_UserProfile/Attribute:reason+' => 'Justifie le rôle affecté à cet utilisateur',
));
//
// Class: URP_UserOrg
//
Dict::Add('FR FR', 'French', 'Français', array(
'Class:URP_UserOrg' => 'Utilisateur/Organisation',
'Class:URP_UserOrg+' => 'Organizations permises pour l\'utilisateur',
'Class:URP_UserOrg/Attribute:userid' => 'Utilisateur',
'Class:URP_UserOrg/Attribute:userid+' => '',
'Class:URP_UserOrg/Attribute:userlogin' => 'Login',
'Class:URP_UserOrg/Attribute:userlogin+' => '',
'Class:URP_UserOrg/Attribute:allowed_org_id' => 'Organisation',
'Class:URP_UserOrg/Attribute:allowed_org_id+' => '',
'Class:URP_UserOrg/Attribute:allowed_org_name' => 'Organisation',
'Class:URP_UserOrg/Attribute:allowed_org_name+' => '',
'Class:URP_UserOrg/Attribute:reason' => 'Raison',
'Class:URP_UserOrg/Attribute:reason+' => 'Justifie la permission de voir les données de cette organisation',
));
//
// Class: URP_ProfileProjection
//
Dict::Add('FR FR', 'French', 'Français', array(
'Class:URP_ProfileProjection' => 'profile_projection',
'Class:URP_ProfileProjection+' => 'profile projections',
'Class:URP_ProfileProjection/Attribute:dimensionid' => 'Dimension',
@@ -202,13 +180,6 @@ Dict::Add('FR FR', 'French', 'Français', array(
'Class:URP_ProfileProjection/Attribute:value+' => 'OQL expression (using $user) | constant | | +attribute code',
'Class:URP_ProfileProjection/Attribute:attribute' => 'Attribute',
'Class:URP_ProfileProjection/Attribute:attribute+' => 'Target attribute code (optional)',
));
//
// Class: URP_ClassProjection
//
Dict::Add('FR FR', 'French', 'Français', array(
'Class:URP_ClassProjection' => 'class_projection',
'Class:URP_ClassProjection+' => 'class projections',
'Class:URP_ClassProjection/Attribute:dimensionid' => 'Dimension',
@@ -221,78 +192,11 @@ Dict::Add('FR FR', 'French', 'Français', array(
'Class:URP_ClassProjection/Attribute:value+' => 'OQL expression (using $this) | constant | | +attribute code',
'Class:URP_ClassProjection/Attribute:attribute' => 'Attribute',
'Class:URP_ClassProjection/Attribute:attribute+' => 'Target attribute code (optional)',
));
//
// Class: URP_ActionGrant
//
Dict::Add('FR FR', 'French', 'Français', array(
'Class:URP_ActionGrant' => 'action_permission',
'Class:URP_ActionGrant+' => 'permissions on classes',
'Class:URP_ActionGrant/Attribute:profileid' => 'Profile',
'Class:URP_ActionGrant/Attribute:profileid+' => 'usage profile',
'Class:URP_ActionGrant/Attribute:profile' => 'Profile',
'Class:URP_ActionGrant/Attribute:profile+' => 'usage profile',
'Class:URP_ActionGrant/Attribute:class' => 'Class',
'Class:URP_ActionGrant/Attribute:class+' => 'Target class',
'Class:URP_ActionGrant/Attribute:permission' => 'Permission',
'Class:URP_ActionGrant/Attribute:permission+' => 'allowed or not allowed?',
'Class:URP_ActionGrant/Attribute:permission/Value:yes' => 'yes',
'Class:URP_ActionGrant/Attribute:permission/Value:yes+' => 'yes',
'Class:URP_ActionGrant/Attribute:permission/Value:no' => 'no',
'Class:URP_ActionGrant/Attribute:permission/Value:no+' => 'no',
'Class:URP_ActionGrant/Attribute:action' => 'Action',
'Class:URP_ActionGrant/Attribute:action+' => 'operations to perform on the given class',
));
//
// Class: URP_StimulusGrant
//
Dict::Add('FR FR', 'French', 'Français', array(
'Class:URP_StimulusGrant' => 'stimulus_permission',
'Class:URP_StimulusGrant+' => 'permissions on stimilus in the life cycle of the object',
'Class:URP_StimulusGrant/Attribute:profileid' => 'Profile',
'Class:URP_StimulusGrant/Attribute:profileid+' => 'usage profile',
'Class:URP_StimulusGrant/Attribute:profile' => 'Profile',
'Class:URP_StimulusGrant/Attribute:profile+' => 'usage profile',
'Class:URP_StimulusGrant/Attribute:class' => 'Class',
'Class:URP_StimulusGrant/Attribute:class+' => 'Target class',
'Class:URP_StimulusGrant/Attribute:permission' => 'Permission',
'Class:URP_StimulusGrant/Attribute:permission+' => 'allowed or not allowed?',
'Class:URP_StimulusGrant/Attribute:permission/Value:yes' => 'yes',
'Class:URP_StimulusGrant/Attribute:permission/Value:yes+' => 'yes',
'Class:URP_StimulusGrant/Attribute:permission/Value:no' => 'no',
'Class:URP_StimulusGrant/Attribute:permission/Value:no+' => 'no',
'Class:URP_StimulusGrant/Attribute:stimulus' => 'Stimulus',
'Class:URP_StimulusGrant/Attribute:stimulus+' => 'stimulus code',
));
//
// Class: URP_AttributeGrant
//
Dict::Add('FR FR', 'French', 'Français', array(
'Class:URP_AttributeGrant' => 'attribute_permission',
'Class:URP_AttributeGrant+' => 'permissions at the attributes level',
'Class:URP_AttributeGrant/Attribute:actiongrantid' => 'Action grant',
'Class:URP_AttributeGrant/Attribute:actiongrantid+' => 'action grant',
'Class:URP_AttributeGrant/Attribute:attcode' => 'Attribute',
'Class:URP_AttributeGrant/Attribute:attcode+' => 'attribute code',
));
//
// String from the User Interface: menu, messages, buttons, etc...
//
Dict::Add('FR FR', 'French', 'Français', array(
'Menu:WelcomeMenu' => 'Bienvenue',
'Menu:WelcomeMenu+' => 'Bienvenue dans iTop',
'Menu:WelcomeMenuPage' => 'Bienvenue',
'Menu:WelcomeMenuPage+' => 'Bienvenue dans iTop',
'UI:WelcomeMenu:Title' => 'Bienvenue dans iTop',
'UI:WelcomeMenu:LeftBlock' => '<p>iTop est un portail opérationnel complet et libre pour gérer votre SI.</p>
<ul>il contient:
<li>Une base de gestion des configuration (CMDB - Configuration management database) pour documenter et gérer votre parc informatique.</li>
@@ -303,7 +207,6 @@ Dict::Add('FR FR', 'French', 'Français', array(
<li>Des tableaux de bord pour avoir rapidement une vue synthétique de votre SI.</li>
</ul>
<p>Tous ces modules peuvent être installés séparément, à votre rythme.</p>',
'UI:WelcomeMenu:RightBlock' => '<p>iTop a été conçu pour les fournisseurs de service, il permet à vos équipes IT de gérer facilement de multiples clients et organisations.
<ul>iTop fournit un riche ensemble de processus métier&nbsp;pour:
<li>Augmenter l\'efficacité de la gestion de votre SI</li>
@@ -319,25 +222,24 @@ Dict::Add('FR FR', 'French', 'Français', array(
<li>Contrôllez l\'actif le plus important de votre SI&nbsp;: la documentation.</li>
</ul>
</p>',
'UI:WelcomeMenu:AllOpenRequests' => 'Requêtes en cours: %1$d',
'UI:WelcomeMenu:MyCalls' => 'Mes Appels Support',
'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)',
'UI:Button:Logoff' => 'Déconnexion',
'UI:Button:GlobalSearch' => 'Rechercher',
'UI:Button:Search' => 'Rechercher',
'UI:Button:Query' => ' Lancer la requête ',
'UI:Button:Ok' => 'Ok',
'UI:Button:Cancel' => 'Annuler',
'UI:Button:Apply' => 'Appliquer',
'UI:Button:Back' => ' << Retour ',
'UI:Button:Restart' => ' |<< Recommencer ',
'UI:Button:Next' => ' Suite >> ',
'UI:Button:Finish' => ' Terminer ',
'UI:Button:DoImport' => ' Lancer l\'import ! ',
@@ -355,26 +257,24 @@ Dict::Add('FR FR', 'French', 'Français', array(
'UI:Button:Delete' => ' Supprimer ! ',
'UI:Button:ChangePassword' => ' Changer ! ',
'UI:Button:ResetPassword' => ' Ràz du mot de passe ',
'UI:SearchToggle' => 'Recherche',
'UI:ClickToCreateNew' => 'Créer un nouvel objet de type %1$s',
'UI:SearchFor_Class' => 'Rechercher des objets de type %1$s',
'UI:NoObjectToDisplay' => 'Aucun objet à afficher.',
'UI:Error:MandatoryTemplateParameter_object_id' => 'Le paramètre object_id est obligatoire quand link_attr est spécifié. Vérifiez la définition du modèle.',
'UI:Error:MandatoryTemplateParameter_link_attr' => 'Le paramètre target_attr est obligatoire quand link_attr est spécifié. Vérifiez la définition du modèle.',
'UI:Error:MandatoryTemplateParameter_target_attr' => 'Le paramètre taarget_attr est obligatoire quand link_attr est spécifié. Vérifiez la définition du modèle.',
'UI:Error:MandatoryTemplateParameter_group_by' => 'Le paramètre group_by est obligatoire. Vérifiez la définition du modèle.',
'UI:Error:InvalidGroupByFields' => 'Liste des champs "group by" incorrecte: "%1$s".',
'UI:Error:UnsupportedStyleOfBlock' => 'Erreur: style de bloc("%1$s") inconnu.',
'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 de la variable upload_max_filesize 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".',
'UI:Error:UploadStoppedByExtension_FileName' => 'Téléchargement arrêté à cause de l\'extension. (Nom du fichier original = "%1$s").',
'UI:Error:UploadFailedUnknownCause_Code' => 'Le téléchargement a échoué pour une raison inconnue. (Code d\'erreur = "%1$s").',
'UI:Error:1ParametersMissing' => 'Erreur: Pour effectuer cette opération il manque le paramètre suivant: %1$s.',
'UI:Error:2ParametersMissing' => 'Erreur: Pour effectuer cette opération il manque les paramètres suivants: %1$s and %2$s.',
'UI:Error:3ParametersMissing' => 'Erreur: Pour effectuer cette opération il manque les paramètres suivants: %1$s, %2$s and %3$s.',
@@ -390,7 +290,6 @@ Dict::Add('FR FR', 'French', 'Français', array(
'UI:Error:ObjectAlreadyCloned' => 'Erreur: l\'objet a déjà été dupliqué !',
'UI:Error:ObjectAlreadyCreated' => 'Erreur: l\'objet a déjà été créé !',
'UI:Error:Invalid_Stimulus_On_Object_In_State' => 'Erreur: le stimulus "%1$s" n\'est pas valide pour l\'objet %2$s dans l\'état "%3$s".',
'UI:GroupBy:Count' => 'Nombre',
'UI:GroupBy:Count+' => 'Nombre d\'éléments',
'UI:CountOfObjects' => '%1$d objets correspondants aux critères.',
@@ -399,14 +298,24 @@ Dict::Add('FR FR', 'French', 'Français', array(
'UI:History:LastModified_On_By' => 'Dernière modification par %2$s le %1$s.',
'UI:HistoryTab' => 'Historique',
'UI:NotificationsTab' => 'Notifications',
'UI:History:BulkImports' => 'Historique',
'UI:History:BulkImports+' => 'Liste des imports CSV (le dernier est en haut de la liste)',
'UI:History:BulkImportDetails' => 'Changements résultant de l\'import CSV du %1$s (auteur: %2$s)',
'UI:History:Date' => 'Date',
'UI:History:Date+' => 'Date de modification',
'UI:History:User' => 'Utilisateur',
'UI:History:User+' => 'Utilisateur qui a fait la modification',
'UI:History:Changes' => 'Changements',
'UI:History:Changes+' => 'Changements sur cet objet',
'UI:History:StatsCreations' => 'Créés',
'UI:History:StatsCreations+' => 'Nombre d\'objets créés',
'UI:History:StatsModifs' => 'Modifiés',
'UI:History:StatsModifs+' => 'Nombre d\'objets modifiés',
'UI:History:StatsDeletes' => 'Effacés',
'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...',
@@ -414,12 +323,13 @@ Dict::Add('FR FR', 'French', 'Français', array(
'UI:Menu:CSVExport' => 'Exporter en CSV',
'UI:Menu:Modify' => 'Modifier...',
'UI:Menu:Delete' => 'Supprimer...',
'UI:Menu:Manage' => 'Gérer...',
'UI:Menu:BulkDelete' => 'Supprimer...',
'UI:UndefinedObject' => 'non défini',
'UI:Document:OpenInNewWindow:Download' => 'Ouvrir dans un nouvelle fenêtre: %1$s, Télécharger: %2$s',
'UI:SelectAllToggle+' => 'Tout Sélectionner / Tout Désélectionner',
'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)',
@@ -447,6 +357,9 @@ Dict::Add('FR FR', 'French', 'Français', array(
'UI:LogOff:ThankYou' => 'Merci d\'avoir utilisé iTop',
'UI:LogOff:ClickHereToLoginAgain' => 'Cliquez ici pour vous reconnecter...',
'UI:ChangePwdMenu' => 'Changer de mot de passe...',
'UI:Login:PasswordChanged' => 'Mot de passe mis à jour !',
'UI:AccessRO-All' => 'iTop est en lecture seule',
'UI:AccessRO-Users' => 'iTop est en lecture seule pour les utilisateurs finaux',
'UI:Login:RetypePwdDoesNotMatch' => 'Les deux saisies du nouveau mot de passe ne sont pas identiques !',
'UI:Button:Login' => 'Entrer dans iTop',
'UI:Login:Error:AccessRestricted' => 'L\'accès à iTop est soumis à autorisation. Merci de contacter votre administrateur iTop.',
@@ -462,6 +375,7 @@ Dict::Add('FR FR', 'French', 'Français', array(
'UI:CSVImport:idField' => 'id (Clef primaire)',
'UI:Title:BulkImport' => 'iTop - Import massif',
'UI:Title:BulkImport+' => 'Assistant d\'import CSV',
'UI:Title:BulkSynchro_nbItem_ofClass_class' => 'Synchronisation de %1$d éléments de type %2$s',
'UI:CSVImport:ClassesSelectOne' => '-- choisir une valeur --',
'UI:CSVImport:ErrorExtendedAttCode' => 'Erreur interne: "%1$s" n\'est pas une code correct car "%2$s" n\'est pas une clef externe de la classe "%3$s"',
'UI:CSVImport:ObjectsWillStayUnchanged' => '%1$d objets(s) resteront inchangés.',
@@ -494,35 +408,30 @@ Dict::Add('FR FR', 'French', 'Français', array(
'UI:CSVImport:Tab:Templates' => 'Modèles',
'UI:CSVImport:PasteData' => 'Collez ici les données à importer:',
'UI:CSVImport:PickClassForTemplate' => 'Choisissez un modèle à télécharger: ',
'UI:CSVImport:SeparatorCharacter' => 'Caractère séparateur:',
'UI:CSVImport:TextQualifierCharacter' => 'Entourage des champs texte',
'UI:CSVImport:CommentsAndHeader' => 'En-tête et commentaires',
'UI:CSVImport:SeparatorCharacter' => 'Separator character:',
'UI:CSVImport:TextQualifierCharacter' => 'Text qualifier character',
'UI:CSVImport:CommentsAndHeader' => 'Comments and header',
'UI:CSVImport:SeparatorCharacter' => 'Séparateur:',
'UI:CSVImport:TextQualifierCharacter' => 'Délimiteur de texte',
'UI:CSVImport:CommentsAndHeader' => 'Commentaires et en-tête',
'UI:CSVImport:SelectClass' => 'Sélectionner le type d\'objets à importer:',
'UI:CSVImport:AdvancedMode' => 'Mode expert',
'UI:CSVImport:AdvancedMode+' => 'En mode expert, l\'"id" (clef primaire) des objets peut être utilisé pour renommer des objets.' .
'Cependant la colonne "id" (si elle est présente) ne peut être utilisée que comme clef de recherche et ne peut pas être combinée avec une autre clef de recherche.',
'UI:CSVImport:AdvancedMode+' => 'En mode expert, l\'"id" (clef primaire) des objets peut être utilisé pour renommer des objets.Cependant la colonne "id" (si elle est présente) ne peut être utilisée que comme clef de recherche et ne peut pas être combinée avec une autre clef de recherche.',
'UI:CSVImport:SelectAClassFirst' => 'Pour configurer la correspondance, choississez d\'abord un type ci-dessus.',
'UI:CSVImport:HeaderFields' => 'Champs',
'UI:CSVImport:HeaderMappings' => 'Correspondance',
'UI:CSVImport:HeaderSearch' => 'Recherche ?',
'UI:CSVImport:AlertIncompleteMapping' => 'Veuillez choisir le correspondance de chacun des champs.',
'UI:CSVImport:AlertNoSearchCriteria' => 'Veuillez choisir au moins une clef de recherche.',
'UI:CSVImport:Encoding' => 'Encodage des caractères',
'UI:CSVImport:Encoding' => 'Encodage des caractères',
'UI:UniversalSearchTitle' => 'iTop - Recherche Universelle',
'UI:UniversalSearch:Error' => 'Erreur : %1$s',
'UI:UniversalSearch:LabelSelectTheClass' => 'Sélectionnez le type d\'objets à rechercher : ',
'UI:Audit:Title' => 'iTop - Audit de la CMDB',
'UI:Audit:InteractiveAudit' => 'Audit Interactif',
'UI:Audit:HeaderAuditRule' => 'Règle d\'audit',
'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',
@@ -534,7 +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',
@@ -593,13 +502,12 @@ Dict::Add('FR FR', 'French', 'Français', array(
'UI:Schema:LifeCycleAttributeMustChange' => 'Doit changer',
'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 la requête',
'UI:Combo:SelectValue' => '--- choisissez une valeur ---',
'UI:Label:SelectedObjects' => 'Objets sélectionnés: ',
'UI:Label:AvailableObjects' => 'Objets disponibles: ',
'UI:Link_Class_Attributes' => 'Attributs du type %1$s',
'UI:SelectAllToggle+' => 'Tout sélectionner / Tout déselectionner',
'UI:AddObjectsOf_Class_LinkedWith_Class_Instance' => 'Ajouter des objets de type %1$s liés à %3$s (%2$s)',
'UI:AddObjectsOf_Class_LinkedWith_Class' => 'Ajouter des objets de type %1$s à lier à cet objet de type %2$s',
'UI:ManageObjectsOf_Class_LinkedWith_Class_Instance' => 'Gérer les objets de type %1$s liés à %3$s (%2$s)',
@@ -607,15 +515,17 @@ Dict::Add('FR FR', 'French', 'Français', array(
'UI:RemoveLinkedObjectsOf_Class' => 'Enlever les objets sélectionnés',
'UI:Message:EmptyList:UseAdd' => 'La liste est vide, utilisez le bouton "Ajouter..." pour ajouter des objets.',
'UI:Message:EmptyList:UseSearchForm' => 'Utilisez le formulaire de recherche ci-dessus pour trouver les objets à ajouter.',
'UI:Wizard:FinalStepTitle' => 'Dernière étape: confirmation',
'UI:Title:DeletionOf_Object' => 'Suppression de %1$s',
'UI:Title:BulkDeletionOf_Count_ObjectsOf_Class' => 'Suppression massive de %1$d objets de type %2$s',
'UI:Delete:NotAllowedToDelete' => 'Vous n\'êtes pas autorisé à supprimer cet objet',
'UI:Delete:NotAllowedToUpdate_Fields' => 'Vous n\'êtes pas autorisé à mettre à jour les champs suivants : %1$s',
'UI:Error:NotEnoughRightsToDelete' => 'Cet objet ne peut pas être supprimé car l\'utilisateur courant n\'a pas les droits nécessaires.',
'UI:Error:CannotDeleteBecause' => 'Cet objet ne peut pas être effacé. Raison: %1$s',
'UI:Error:CannotDeleteBecauseOfDepencies' => 'Cet objet ne peut pas être supprimé, des opérations manuelles sont nécessaire avant sa suppression.',
'UI:Error:CannotDeleteBecauseManualOpNeeded' => 'Des opération manuelles sont nécessaires avant de pouvoir effacer cet objet',
'UI:Archive_User_OnBehalfOf_User' => '%1$s pour %2$s',
'UI:Delete:Deleted' => 'supprimé',
'UI:Delete:AutomaticallyDeleted' => 'supprimé automatiquement',
'UI:Delete:AutomaticResetOf_Fields' => 'mise à jour automatique des champ(s): %1$s',
'UI:Delete:CleaningUpRefencesTo_Object' => 'Suppression de toutes les références vers %1$s...',
@@ -624,14 +534,15 @@ Dict::Add('FR FR', 'French', 'Français', array(
'UI:Delete:_Name_Class_Deleted' => ' %2$s %1$s supprimé.',
'UI:Delete:ConfirmDeletionOf_Name' => 'Suppression de %1$s',
'UI:Delete:ConfirmDeletionOf_Count_ObjectsOf_Class' => 'Suppression de %1$d objets de type %2$s',
'UI:Delete:ShouldBeDeletedAtomaticallyButNotAllowed' => 'Devrait être supprimé automatiquement, mais vous n\'avez pas le droit d\'effectuer cette opération.',
'UI:Delete:MustBeDeletedManuallyButNotAllowed' => 'Doit être supprimé manuellement - mais vous n\'avez pas le droit de supprimer cet objet, contactez votre administrateur pour régler ce problème',
'UI:Delete:CannotDeleteBecause' => 'Ne peux pas être supprimé: %1$s',
'UI:Delete:ShouldBeDeletedAtomaticallyButNotPossible' => 'Devrait être supprimé automatiquement, mais cela n\'est pas possible: %1$s',
'UI:Delete:MustBeDeletedManuallyButNotPossible' => 'Doit être supprimé manuellement, mais cela n\'est pas possible: %1$s',
'UI:Delete:WillBeDeletedAutomatically' => 'Sera supprimé automatiquement',
'UI:Delete:MustBeDeletedManually' => 'Doit être supprimé manuellement',
'UI:Delete:CannotUpdateBecause_Issue' => 'Devrait être mis à jour automatiquement, mais: %1$s',
'UI:Delete:WillAutomaticallyUpdate_Fields' => 'Va être mis à jour automatiquement (champs impactés : %1$s)',
'UI:Delete:Count_Objects/LinksReferencing_Object' => '%1$d objets ou liens font référence à %2$s',
'UI:Delete:Count_Objects/LinksReferencingTheObjects' => '%1$d objets ou liens font référence à certain des objets à supprimer',
'UI:Delete:Count_Objects/LinksReferencingTheObjects' => '%1$d objets ou liens font référence à certain des objets à supprimer',
'UI:Delete:ReferencesMustBeDeletedToEnsureIntegrity' => 'pour garantir l\'intégrité de la base de données, toutes les références doivent être supprimées.',
'UI:Delete:Consequence+' => 'Ce qui va être effectué',
'UI:Delete:SorryDeletionNotAllowed' => 'Désolé, vous n\'êtes pas autorisé à supprimer cette objet. Voir les explications détaillées ci-dessus.',
@@ -648,9 +559,9 @@ Dict::Add('FR FR', 'French', 'Français', array(
'UI:Search:Count_ObjectsOf_Class_Found' => 'Trouvé %1$d objet(s) de type %2$s.',
'UI:Search:NoObjectFound' => 'Aucun objet trouvé.',
'UI:ModificationPageTitle_Object_Class' => 'iTop - %2$s - Modification de %1$s',
'UI:ModificationTitle_Class_Object' => '%1$s - Modification de <span class=\"hilite\">%2$s</span>',
'UI:ModificationTitle_Class_Object' => '%1$s - Modification de <span class="hilite">%2$s</span>',
'UI:ClonePageTitle_Object_Class' => 'iTop - %2$s - Duplication de %1$s',
'UI:CloneTitle_Class_Object' => ' %1$s - Duplication de <span class=\"hilite\">%2$s</span>',
'UI:CloneTitle_Class_Object' => ' %1$s - Duplication de <span class="hilite">%2$s</span>',
'UI:CreationPageTitle_Class' => 'iTop - Création d\'un objet de type %1$s ',
'UI:CreationTitle_Class' => 'Création d\'un objet de type %1$s',
'UI:SelectTheTypeOf_Class_ToCreate' => 'Sélectionnez le type de %1$s à créer :',
@@ -663,11 +574,10 @@ Dict::Add('FR FR', 'French', 'Français', array(
'UI:Apply_Stimulus_On_Object_In_State_ToTarget_State' => '%1$s pour %2$s de l\'état %3$s vers l\'état %4$s.',
'UI:ObjectCouldNotBeWritten' => 'L\'objet ne peut pas être enregistré: %1$s',
'UI:PageTitle:FatalError' => 'iTop - Erreur Fatale',
'UI:FatalErrorMessage' => 'Erreur fatale, iTop ne peut pas continuer.',
'UI:SystemIntrusion' => 'Accès non autorisé. Vous êtes en train de d\'effectuer une opération qui ne vous est pas permise.',
'UI:FatalErrorMessage' => 'Erreur fatale, iTop ne peut pas continuer.',
'UI:Error_Details' => 'Erreur: %1$s.',
'UI:PageTitle:ClassProjections' => 'iTop gestion des utilisateurs - projections des classes',
'UI:PageTitle:ClassProjections' => 'iTop gestion des utilisateurs - projections des classes',
'UI:PageTitle:ProfileProjections' => 'iTop gestion des utilisateurs - projections des profils',
'UI:UserManagement:Class' => 'Type',
'UI:UserManagement:Class+' => 'Type des objets',
@@ -704,16 +614,11 @@ Dict::Add('FR FR', 'French', 'Français', array(
'UI:UserManagement:NoLifeCycleApplicable' => 'N/A',
'UI:UserManagement:NoLifeCycleApplicable+' => 'Aucun cycle de vie n\'est défini pour ce type d\'objets.',
'UI:UserManagement:GrantMatrix' => 'Matrice des droits',
'UI:USerManagement:LinkBetween_User_And_Profile' => 'Lien entre %1$s et %2$s',
'UI:USerManagement:LinkBetween_User_And_Org' => 'Lien entre %1$s et %2$s',
'UI:UserManagement:LinkBetween_User_And_Profile' => 'Lien entre %1$s et %2$s',
'UI:UserManagement:LinkBetween_User_And_Org' => 'Lien entre %1$s et %2$s',
'Menu:AdminTools' => 'Outils d\'admin',
'Menu:AdminTools+' => 'Outils d\'administration',
'Menu:AdminTools?' => 'Ces outils sont accessibles uniquement aux utilisateurs possédant le profil Administrateur.',
'UI:AuditMenu' => 'Audit',
'UI:AuditMenu+' => 'Audit',
'UI:ChangeManagementMenu' => 'Gestion du Changement',
'UI:ChangeManagementMenu+' => 'Gestion du Changement',
'UI:ChangeManagementMenu:Title' => 'Résumé des changements',
@@ -721,67 +626,48 @@ Dict::Add('FR FR', 'French', 'Français', array(
'UI-ChangeManagementMenu-ChangesByStatus' => 'Changements par état',
'UI-ChangeManagementMenu-ChangesByWorkgroup' => 'Changements par workgroup',
'UI-ChangeManagementMenu-ChangesNotYetAssigned' => 'Changements en attente d\'assignation',
'UI:ConfigurationItemsMenu'=> 'Actifs (CIs)',
'UI:ConfigurationItemsMenu+'=> 'Tous les actifs',
'UI:ConfigurationItemsMenu' => 'Actifs (CIs)',
'UI:ConfigurationItemsMenu+' => 'Tous les actifs',
'UI:ConfigurationItemsMenu:Title' => 'Résumé des actifs (CIs)',
'UI-ConfigurationItemsMenu-ServersByCriticity' => 'Serveurs par criticité',
'UI-ConfigurationItemsMenu-PCsByCriticity' => 'PCs par criticité',
'UI-ConfigurationItemsMenu-NWDevicesByCriticity' => 'Equipements réseau par criticité',
'UI-ConfigurationItemsMenu-ApplicationsByCriticity' => 'Applications par criticité',
'UI:ConfigurationManagementMenu' => 'Gestion de Configuration',
'UI:ConfigurationManagementMenu+' => 'Gestion de Configuration',
'UI:ConfigurationManagementMenu:Title' => 'Résumé de l\'Infrastructure',
'UI-ConfigurationManagementMenu-InfraByType' => 'Nombre d\'éléments par type',
'UI-ConfigurationManagementMenu-InfraByStatus' => 'Nombre d\'éléments par état',
'UI:ConfigMgmtMenuOverview:Title' => 'Tableau de bord de la Gestion de Configuration',
'UI-ConfigMgmtMenuOverview-FunctionalCIbyStatus' => 'Actifs par état',
'UI-ConfigMgmtMenuOverview-FunctionalCIByType' => 'Actifs par type',
'UI:RequestMgmtMenuOverview:Title' => 'Tableau de bord de la Gestion des Demandes Utilisateurs',
'UI-RequestManagementOverview-RequestByService' => 'Demandes par service',
'UI-RequestManagementOverview-RequestByPriority' => 'Demandes par priorité',
'UI-RequestManagementOverview-RequestUnassigned' => 'Demandes non affectées à un agent',
'UI:IncidentMgmtMenuOverview:Title' => 'Tableau de bord de la Gestion des Incidents',
'UI-IncidentManagementOverview-IncidentByService' => 'Incidents par service',
'UI-IncidentManagementOverview-IncidentByPriority' => 'Incidents par priorité',
'UI-IncidentManagementOverview-IncidentUnassigned' => 'Incidents non affectés à un agent',
'UI:ChangeMgmtMenuOverview:Title' => 'Tableau de bord de la Gestion des Changements',
'UI-ChangeManagementOverview-ChangeByType' => 'Changes par type',
'UI-ChangeManagementOverview-ChangeUnassigned' => 'Changes non affectés à un agent',
'UI-ChangeManagementOverview-ChangeWithOutage' => 'Interruptions de service liées à un changement',
'UI:ServiceMgmtMenuOverview:Title' => 'Tableau de bord de la Gestion des Services',
'UI-ServiceManagementOverview-CustomerContractToRenew' => 'Contrats clients à renouveler dans les 30 jours',
'UI-ServiceManagementOverview-ProviderContractToRenew' => 'Contrats fournisseurs à renouveler dans les 30 jours',
'UI:ConfigMgmtMenuOverview:Title' => 'Tableau de bord de la Gestion de Configuration',
'UI-ConfigMgmtMenuOverview-FunctionalCIbyStatus' => 'Actifs par état',
'UI-ConfigMgmtMenuOverview-FunctionalCIByType' => 'Actifs par type',
'UI:RequestMgmtMenuOverview:Title' => 'Tableau de bord de la Gestion des Demandes Utilisateurs',
'UI-RequestManagementOverview-RequestByService' => 'Demandes par service',
'UI-RequestManagementOverview-RequestByPriority' => 'Demandes par priorité',
'UI-RequestManagementOverview-RequestUnassigned' => 'Demandes non affectées à un agent',
'UI:IncidentMgmtMenuOverview:Title' => 'Tableau de bord de la Gestion des Incidents',
'UI-IncidentManagementOverview-IncidentByService' => 'Incidents par service',
'UI-IncidentManagementOverview-IncidentByPriority' => 'Incidents par priorité',
'UI-IncidentManagementOverview-IncidentUnassigned' => 'Incidents non affectés à un agent',
'UI:ChangeMgmtMenuOverview:Title' => 'Tableau de bord de la Gestion des Changements',
'UI-ChangeManagementOverview-ChangeByType' => 'Changes par type',
'UI-ChangeManagementOverview-ChangeUnassigned' => 'Changes non affectés à un agent',
'UI-ChangeManagementOverview-ChangeWithOutage' => 'Interruptions de service liées à un changement',
'UI:ServiceMgmtMenuOverview:Title' => 'Tableau de bord de la Gestion des Services',
'UI-ServiceManagementOverview-CustomerContractToRenew' => 'Contrats clients à renouveler dans les 30 jours',
'UI-ServiceManagementOverview-ProviderContractToRenew' => 'Contrats fournisseurs à renouveler dans les 30 jours',
'UI:ContactsMenu' => 'Contacts',
'UI:ContactsMenu+' => 'Contacts',
'UI:ContactsMenu:Title' => 'Résumé des contacts',
'UI-ContactsMenu-ContactsByLocation' => 'Contacts par emplacement',
'UI-ContactsMenu-ContactsByType' => 'Contacts par type',
'UI-ContactsMenu-ContactsByStatus' => 'Contacts par état',
'Menu:CSVImportMenu' => 'Import CSV',
'Menu:CSVImportMenu+' => 'Import ou mise à jour en masse',
'Menu:DataModelMenu' => 'Modèle de Données',
'Menu:DataModelMenu+' => 'Résumé du Modèle de Données',
'Menu:ExportMenu' => 'Exportation',
'Menu:ExportMenu+' => 'Exportation des résultats d\'une requête en HTML, CSV ou XML',
'UI:IncidentManagementMenu:Title' => 'Résumé des incidents',
'UI-IncidentManagementMenu-IncidentsByType' => 'Incidents par type',
'UI-IncidentManagementMenu-IncidentsByStatus' => 'Incidents par état',
'UI-IncidentManagementMenu-IncidentsByWorkgroup' => 'Incidents par workgroup',
'UI-IncidentManagementMenu-IncidentsNotYetAssigned' => 'Incidents en attente d\'assignation',
'Menu:NotificationsMenu' => 'Notifications',
'Menu:NotificationsMenu+' => 'Configuration des Notifications',
'UI:NotificationsMenu:Title' => 'Configuration des <span class="hilite">Notifications</span>',
@@ -807,43 +693,38 @@ Lors de l\'association à un déclencheur, on attribue à chaque action un numé
'UI:NotificationsMenu:OnStateLeave' => 'Quand un objet quitte un état donné',
'UI:NotificationsMenu:Actions' => 'Actions',
'UI:NotificationsMenu:AvailableActions' => 'Actions existantes',
'Menu:AuditCategories' => 'Catégories d\'audit',
'Menu:AuditCategories+' => 'Catégories d\'audit',
'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',
'Menu:UniversalSearchMenu+' => 'Rechercher n\'importe quel objet...',
'Menu:ApplicationLogMenu' => 'Application Log',
'Menu:ApplicationLogMenu+' => 'Application Log',
'Menu:ApplicationLogMenu:Title' => 'Application Log',
'Menu:UserManagementMenu' => 'Gestion des Utilisateurs',
'Menu:UserManagementMenu+' => 'Gestion des Utilisateurs',
'Menu:ProfilesMenu' => 'Profils',
'Menu:ProfilesMenu+' => 'Profils',
'Menu:ProfilesMenu:Title' => 'Profils',
'Menu:UserAccountsMenu' => 'Comptes Utilisateur',
'Menu:UserAccountsMenu+' => 'Comptes Utilisateur',
'MenuUI:UserAccountsMenu:Title' => 'Comptes Utilisateur',
'Menu:UserAccountsMenu' => 'Comptes Utilisateurs',
'Menu:UserAccountsMenu+' => 'Comptes Utilisateurs',
'Menu:UserAccountsMenu:Title' => 'Comptes Utilisateusr',
'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 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',
'UI:Deadline_LessThan1Min' => '< 1 min',
'UI:Deadline_Minutes' => '%1$d min',
'UI:Deadline_Hours_Minutes' => '%1$dh %2$dmin',
'UI:Deadline_LessThan1Min' => '< 1 min',
'UI:Deadline_Minutes' => '%1$d min',
'UI:Deadline_Hours_Minutes' => '%1$dh %2$dmin',
'UI:Deadline_Days_Hours_Minutes' => '%1$dj %2$dh %3$dmin',
'UI:Help' => 'Aide',
'UI:PasswordConfirm' => '(Confirmer)',
@@ -851,25 +732,80 @@ 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:ResolvedRequests' => 'Mes requêtes résolues',
'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',
'Portal:SelectSubcategoryFrom_Service' => 'Choisissez une sous-catégorie du service %1$s:',
'Portal:PleaseSelectAServiceSubCategory' => 'Veuillez choisir une sous-catégorie',
'Portal:PleaseSelectAServiceSubCategory' => 'Veuillez choisir une sous-catégorie',
'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',
'Portal:AddAttachment' => ' Ajouter une pièce jointe ',
'Portal:RemoveAttachment' => ' Enlever la pièce jointe ',
'Portal:Attachment_No_To_Ticket_Name' => 'Pièce jointe #%1$d à %2$s (%3$s)',
'Enum:Undefined' => 'Non défini',
'UI:DurationForm_Days_Hours_Minutes_Seconds' => '%1$s J %2$s H %3$s min %4$s s',
'UI:ModifyAllPageTitle' => 'Modification par lots',
'UI:Modify_N_ObjectsOf_Class' => 'Modification de %1$d objet(s) de type %2$s',
'UI:Modify_M_ObjectsOf_Class_OutOf_N' => 'Modification de %1$d (sur %3$d) objets de type %2$s',
'UI:Menu:ModifyAll' => 'Modifier...',
'UI:Button:ModifyAll' => 'Modifier',
'UI:Button:PreviewModifications' => 'Aperçu des modifications >>',
'UI:ModifiedObject' => 'Objet Modifié',
'UI:BulkModifyStatus' => 'Opération',
'UI:BulkModifyStatus+' => '',
'UI:BulkModifyErrors' => 'Erreur',
'UI:BulkModifyErrors+' => '',
'UI:BulkModifyStatusOk' => 'Ok',
'UI:BulkModifyStatusError' => 'Erreur',
'UI:BulkModifyStatusModified' => 'Modifié',
'UI:BulkModifyStatusSkipped' => 'Ignoré',
'UI:BulkModify_Count_DistinctValues' => '%1$d valeurs distinctes:',
'UI:BulkModify:Value_Exists_N_Times' => '%1$s, %2$d fois',
'UI:BulkModify:N_MoreValues' => '%1$d valeurs supplémentaires...',
'UI:AttemptingToSetAReadOnlyAttribute_Name' => 'Tentative de modification du champ en lecture seule: %1$s',
'UI:FailedToApplyStimuli' => 'L\'action a échoué',
'UI:StimulusModify_N_ObjectsOf_Class' => '%1$s: Modification de %2$d objet(s) de type %3$s',
'UI:CaseLogTypeYourTextHere' => 'Nouvelle entrée ci-dessous:',
'UI:CaseLog:DateFormat' => 'Y-m-d H:i:s',
'UI:CaseLog:Header_Date_UserName' => '%1$s - %2$s:',
'UI:CaseLog:InitialValue' => 'Valeur initiale:',
'UI:AttemptingToSetASlaveAttribute_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 ignorée.',
'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: ',
'UI:Button:Refresh' => 'Rafraîchir',
));
?>

View File

@@ -0,0 +1,481 @@
<?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('HU HU', 'Hungarian', 'Magyar', array(
'Class:ActionEmail' => 'E-mail értesítés',
'Class:ActionEmail+' => '',
'Class:ActionEmail/Attribute:test_recipient' => 'Teszt címzett',
'Class:ActionEmail/Attribute:test_recipient+' => '',
'Class:ActionEmail/Attribute:from' => 'Feladó',
'Class:ActionEmail/Attribute:from+' => '',
'Class:ActionEmail/Attribute:reply_to' => 'Válasz',
'Class:ActionEmail/Attribute:reply_to+' => '',
'Class:ActionEmail/Attribute:to' => 'Címzett',
'Class:ActionEmail/Attribute:to+' => '',
'Class:ActionEmail/Attribute:cc' => 'Másolatot kap',
'Class:ActionEmail/Attribute:cc+' => '',
'Class:ActionEmail/Attribute:bcc' => 'Titkos másolatot kap',
'Class:ActionEmail/Attribute:bcc+' => '',
'Class:ActionEmail/Attribute:subject' => 'Tárgy',
'Class:ActionEmail/Attribute:subject+' => '',
'Class:ActionEmail/Attribute:body' => 'Szöveg',
'Class:ActionEmail/Attribute:body+' => '',
'Class:ActionEmail/Attribute:importance' => 'Fontosság',
'Class:ActionEmail/Attribute:importance+' => '',
'Class:ActionEmail/Attribute:importance/Value:high' => 'Fontos',
'Class:ActionEmail/Attribute:importance/Value:high+' => '',
'Class:ActionEmail/Attribute:importance/Value:low' => 'Nem fontos',
'Class:ActionEmail/Attribute:importance/Value:low+' => '',
'Class:ActionEmail/Attribute:importance/Value:normal' => 'Normál',
'Class:ActionEmail/Attribute:importance/Value:normal+' => '',
'Class:TriggerOnStateEnter' => 'Kiváltó ok (állapotba belépés)',
'Class:TriggerOnStateEnter+' => '',
'Class:TriggerOnStateLeave' => 'Kiváltó ok (állapot elhagyás)',
'Class:TriggerOnStateLeave+' => '',
'Class:TriggerOnObjectCreate' => 'Kiváltó ok (objektum létrehozás)',
'Class:TriggerOnObjectCreate+' => '',
'Class:lnkTriggerAction' => 'Akció / Kiváltó ok',
'Class:lnkTriggerAction+' => '',
'Class:lnkTriggerAction/Attribute:action_id' => 'Akció',
'Class:lnkTriggerAction/Attribute:action_id+' => '',
'Class:lnkTriggerAction/Attribute:trigger_id' => 'Kiváltó ok',
'Class:lnkTriggerAction/Attribute:trigger_id+' => '',
'Class:lnkTriggerAction/Attribute:order' => 'Sorrend',
'Class:lnkTriggerAction/Attribute:order+' => '',
'Class:AsyncSendEmail' => 'E-mail (aszinkron)',
'Class:AsyncSendEmail/Attribute:to' => 'Címzett',
'Class:AsyncSendEmail/Attribute:subject' => 'Tárgy',
'Class:AsyncSendEmail/Attribute:body' => 'Szöveg',
'Class:AsyncSendEmail/Attribute:header' => 'Fejléc',
'Class:CMDBChange' => 'Változás',
'Class:CMDBChange+' => '',
'Class:CMDBChange/Attribute:date' => 'Dátum',
'Class:CMDBChange/Attribute:date+' => '',
'Class:CMDBChange/Attribute:userinfo' => 'Egyéb információ',
'Class:CMDBChange/Attribute:userinfo+' => '',
'Class:CMDBChangeOp' => 'Változtatás művelet',
'Class:CMDBChangeOp+' => '',
'Class:CMDBChangeOp/Attribute:change' => 'Válktozás',
'Class:CMDBChangeOp/Attribute:change+' => '',
'Class:CMDBChangeOp/Attribute:objclass' => 'Objektum osztály',
'Class:CMDBChangeOp/Attribute:objclass+' => '',
'Class:CMDBChangeOp/Attribute:objkey' => 'Objektum azonosító',
'Class:CMDBChangeOp/Attribute:objkey+' => '',
'Class:CMDBChangeOp/Attribute:finalclass' => 'Típus',
'Class:CMDBChangeOp/Attribute:finalclass+' => '',
'Class:CMDBChangeOpCreate' => 'Objektum létrehozás',
'Class:CMDBChangeOpCreate+' => '',
'Class:CMDBChangeOpDelete' => 'Objektum törlés',
'Class:CMDBChangeOpDelete+' => '',
'Class:CMDBChangeOpSetAttribute' => 'Objektum változtatás',
'Class:CMDBChangeOpSetAttribute+' => '',
'Class:CMDBChangeOpSetAttribute/Attribute:attcode' => 'Attribútum',
'Class:CMDBChangeOpSetAttribute/Attribute:attcode+' => '',
'Class:CMDBChangeOpSetAttributeScalar' => 'Tulajdonság változtatás',
'Class:CMDBChangeOpSetAttributeScalar+' => '',
'Class:CMDBChangeOpSetAttributeScalar/Attribute:oldvalue' => 'Előző érték',
'Class:CMDBChangeOpSetAttributeScalar/Attribute:oldvalue+' => '',
'Class:CMDBChangeOpSetAttributeScalar/Attribute:newvalue' => 'Új érték',
'Class:CMDBChangeOpSetAttributeScalar/Attribute:newvalue+' => '',
'Class:CMDBChangeOpSetAttributeBlob' => 'Módosítás dátuma',
'Class:CMDBChangeOpSetAttributeBlob+' => '',
'Class:CMDBChangeOpSetAttributeBlob/Attribute:prevdata' => 'Előző adat',
'Class:CMDBChangeOpSetAttributeBlob/Attribute:prevdata+' => '',
'Class:CMDBChangeOpSetAttributeOneWayPassword' => 'Titkosított jelszó',
'Class:CMDBChangeOpSetAttributeOneWayPassword/Attribute:prev_pwd' => 'Előző érték',
'Class:CMDBChangeOpSetAttributeEncrypted' => 'Titkosított mező',
'Class:CMDBChangeOpSetAttributeEncrypted/Attribute:prevstring' => 'Előző érték',
'Class:CMDBChangeOpSetAttributeText' => 'Szöveg változás',
'Class:CMDBChangeOpSetAttributeText+' => '',
'Class:CMDBChangeOpSetAttributeText/Attribute:prevdata' => 'Előző adat',
'Class:CMDBChangeOpSetAttributeText/Attribute:prevdata+' => '',
'Class:CMDBChangeOpSetAttributeCaseLog' => 'Esemény napló',
'Class:CMDBChangeOpSetAttributeCaseLog/Attribute:lastentry' => 'Utolsó bejegyzés',
'Class:Event' => 'Napló esemény',
'Class:Event+' => '',
'Class:Event/Attribute:message' => 'Üzenet',
'Class:Event/Attribute:message+' => '',
'Class:Event/Attribute:date' => 'Dátum',
'Class:Event/Attribute:date+' => '',
'Class:Event/Attribute:userinfo' => 'Felhasználói információ',
'Class:Event/Attribute:userinfo+' => '',
'Class:Event/Attribute:finalclass' => 'Típus',
'Class:Event/Attribute:finalclass+' => '',
'Class:EventNotification' => 'Értesítés esemény',
'Class:EventNotification+' => '',
'Class:EventNotification/Attribute:trigger_id' => 'Kiváltó ok',
'Class:EventNotification/Attribute:trigger_id+' => '',
'Class:EventNotification/Attribute:action_id' => 'Felhasználó',
'Class:EventNotification/Attribute:action_id+' => '',
'Class:EventNotification/Attribute:object_id' => 'Objektum azonosító',
'Class:EventNotification/Attribute:object_id+' => '',
'Class:EventNotificationEmail' => 'E-mail küldés esemény',
'Class:EventNotificationEmail+' => '',
'Class:EventNotificationEmail/Attribute:to' => 'Címzett',
'Class:EventNotificationEmail/Attribute:to+' => '',
'Class:EventNotificationEmail/Attribute:cc' => 'Másolatot kap',
'Class:EventNotificationEmail/Attribute:cc+' => '',
'Class:EventNotificationEmail/Attribute:bcc' => 'Titkos másolatot kap',
'Class:EventNotificationEmail/Attribute:bcc+' => '',
'Class:EventNotificationEmail/Attribute:from' => 'Feladó',
'Class:EventNotificationEmail/Attribute:from+' => '',
'Class:EventNotificationEmail/Attribute:subject' => 'Tárgy',
'Class:EventNotificationEmail/Attribute:subject+' => '',
'Class:EventNotificationEmail/Attribute:body' => 'Szöveg',
'Class:EventNotificationEmail/Attribute:body+' => '',
'Class:EventIssue' => 'Kérés esemény',
'Class:EventIssue+' => '',
'Class:EventIssue/Attribute:issue' => 'Kérés',
'Class:EventIssue/Attribute:issue+' => '',
'Class:EventIssue/Attribute:impact' => 'Hatás',
'Class:EventIssue/Attribute:impact+' => '',
'Class:EventIssue/Attribute:page' => 'Oldal',
'Class:EventIssue/Attribute:page+' => '',
'Class:EventIssue/Attribute:arguments_post' => 'Kérés részletei',
'Class:EventIssue/Attribute:arguments_post+' => '',
'Class:EventIssue/Attribute:arguments_get' => 'URL ',
'Class:EventIssue/Attribute:arguments_get+' => '',
'Class:EventIssue/Attribute:callstack' => 'Híváslista',
'Class:EventIssue/Attribute:callstack+' => '',
'Class:EventIssue/Attribute:data' => 'Dátum',
'Class:EventIssue/Attribute:data+' => '',
'Class:EventWebService' => 'Web szolgáltatás esemény',
'Class:EventWebService+' => '',
'Class:EventWebService/Attribute:verb' => 'Kérés',
'Class:EventWebService/Attribute:verb+' => '',
'Class:EventWebService/Attribute:result' => 'Eredmény',
'Class:EventWebService/Attribute:result+' => '',
'Class:EventWebService/Attribute:log_info' => 'Info napló',
'Class:EventWebService/Attribute:log_info+' => '',
'Class:EventWebService/Attribute:log_warning' => 'Warning napló',
'Class:EventWebService/Attribute:log_warning+' => '',
'Class:EventWebService/Attribute:log_error' => 'Error napló',
'Class:EventWebService/Attribute:log_error+' => '',
'Class:EventWebService/Attribute:data' => 'Adat',
'Class:EventWebService/Attribute:data+' => '',
'Class:EventLoginUsage' => 'Belépés esemény',
'Class:EventLoginUsage+' => '',
'Class:EventLoginUsage/Attribute:user_id' => 'Felhasználó név',
'Class:EventLoginUsage/Attribute:user_id+' => '',
'Class:SynchroDataSource' => 'Szinkron adatforrás',
'Class:SynchroDataSource/Attribute:name' => 'Neve',
'Class:SynchroDataSource/Attribute:name+' => '',
'Class:SynchroDataSource/Attribute:description' => 'Leírás',
'Class:SynchroDataSource/Attribute:status' => 'Státusz',
'Class:SynchroDataSource/Attribute:status/Value:implementation' => 'Megvalósított',
'Class:SynchroDataSource/Attribute:status/Value:obsolete' => 'Elavult',
'Class:SynchroDataSource/Attribute:status/Value:production' => 'Éles üzemben',
'Class:SynchroDataSource/Attribute:user_id' => 'Felhasználó',
'Class:SynchroDataSource/Attribute:scope_class' => 'Cél osztály',
'Class:SynchroDataSource/Attribute:scope_restriction' => 'Tartalom szűkítés',
'Class:SynchroDataSource/Attribute:full_load_periodicity' => 'Teljesen feltöltött intervallum',
'Class:SynchroDataSource/Attribute:full_load_periodicity+' => '',
'Class:SynchroDataSource/Attribute:reconciliation_policy' => 'Egyeztetési szabály',
'Class:SynchroDataSource/Attribute:reconciliation_policy/Value:use_attributes' => 'A következő attribútum használata',
'Class:SynchroDataSource/Attribute:reconciliation_policy/Value:use_primary_key' => 'Elsődleges kulcs használata',
'Class:SynchroDataSource/Attribute:action_on_zero' => 'Action on zero',
'Class:SynchroDataSource/Attribute:action_on_zero+' => '',
'Class:SynchroDataSource/Attribute:action_on_zero/Value:create' => 'Létrehozás',
'Class:SynchroDataSource/Attribute:action_on_zero/Value:error' => 'Hiba',
'Class:SynchroDataSource/Attribute:action_on_one' => 'Action on one',
'Class:SynchroDataSource/Attribute:action_on_one+' => '',
'Class:SynchroDataSource/Attribute:action_on_one/Value:error' => 'Hiba',
'Class:SynchroDataSource/Attribute:action_on_one/Value:update' => 'Firssítés',
'Class:SynchroDataSource/Attribute:action_on_multiple' => 'Action on many',
'Class:SynchroDataSource/Attribute:action_on_multiple+' => '',
'Class:SynchroDataSource/Attribute:action_on_multiple/Value:create' => 'Létrehozás',
'Class:SynchroDataSource/Attribute:action_on_multiple/Value:error' => 'Hiba',
'Class:SynchroDataSource/Attribute:action_on_multiple/Value:take_first' => 'Take the first one (véletlen?)',
'Class:SynchroDataSource/Attribute:delete_policy' => 'Törlési szabály',
'Class:SynchroDataSource/Attribute:delete_policy/Value:delete' => 'Törlés',
'Class:SynchroDataSource/Attribute:delete_policy/Value:ignore' => 'Figyelmen kívül hagyás',
'Class:SynchroDataSource/Attribute:delete_policy/Value:update' => 'Frissítés',
'Class:SynchroDataSource/Attribute:delete_policy/Value:update_then_delete' => 'Frissítés után törlés',
'Class:SynchroDataSource/Attribute:delete_policy_update' => 'Szabályok frissítése',
'Class:SynchroDataSource/Attribute:delete_policy_update+' => '',
'Class:SynchroDataSource/Attribute:delete_policy_retention' => 'Késleltetés időtartama',
'Class:SynchroDataSource/Attribute:delete_policy_retention+' => '',
'Class:SynchroDataSource/Attribute:attribute_list' => 'Attribútum lista',
'Class:SynchroDataSource/Attribute:user_delete_policy' => 'Engedélyezett felhasználók',
'Class:SynchroDataSource/Attribute:user_delete_policy+' => '',
'Class:SynchroDataSource/Attribute:user_delete_policy/Value:administrators' => 'Csak rendszergazdák',
'Class:SynchroDataSource/Attribute:user_delete_policy/Value:everybody' => 'Mindenkinek engedélyezett az objektumok törlése',
'Class:SynchroDataSource/Attribute:user_delete_policy/Value:nobody' => 'Senki',
'Class:SynchroDataSource/Attribute:url_icon' => 'Ikonok URL-je',
'Class:SynchroDataSource/Attribute:url_icon+' => '',
'Class:SynchroDataSource/Attribute:url_application' => 'Alkalmazások URL-je',
'Class:SynchroDataSource/Attribute:url_application+' => '',
'Class:SynchroAttribute' => 'Szinkron attribútumok',
'Class:SynchroAttribute/Attribute:sync_source_id' => 'Szinkron adatforrás',
'Class:SynchroAttribute/Attribute:attcode' => 'Kód',
'Class:SynchroAttribute/Attribute:update' => 'Frissítés',
'Class:SynchroAttribute/Attribute:reconcile' => 'Egyeztetés',
'Class:SynchroAttribute/Attribute:update_policy' => 'Frissítési irányelv',
'Class:SynchroAttribute/Attribute:update_policy/Value:master_locked' => 'Locked',
'Class:SynchroAttribute/Attribute:update_policy/Value:master_unlocked' => 'Unlocked',
'Class:SynchroAttribute/Attribute:update_policy/Value:write_if_empty' => 'Inicializálás ha üres',
'Class:SynchroAttribute/Attribute:finalclass' => 'Osztály',
'Class:SynchroAttExtKey' => 'Szinkron attribútum (ExtKey)',
'Class:SynchroAttExtKey/Attribute:reconciliation_attcode' => 'Egyeztetés attribútuma',
'Class:SynchroAttLinkSet' => 'Szinkron attribútum (Linkset)',
'Class:SynchroAttLinkSet/Attribute:row_separator' => 'Sor elválasztó',
'Class:SynchroAttLinkSet/Attribute:attribute_separator' => 'Attribútum elválasztó',
'Class:SynchroLog' => 'Szinkron napló',
'Class:SynchroLog/Attribute:sync_source_id' => 'Szinkron adatforrás',
'Class:SynchroLog/Attribute:start_date' => 'Kezdés dátuma',
'Class:SynchroLog/Attribute:end_date' => 'Befejezés dátuma',
'Class:SynchroLog/Attribute:status' => 'Státusz',
'Class:SynchroLog/Attribute:status/Value:completed' => 'Hibátlanul lefutott',
'Class:SynchroLog/Attribute:status/Value:error' => 'Hibás',
'Class:SynchroLog/Attribute:status/Value:running' => 'Még fut',
'Class:SynchroLog/Attribute:stats_nb_replica_seen' => 'Nb replikáció létrejött',
'Class:SynchroLog/Attribute:stats_nb_replica_total' => 'Nb replikáció összesen',
'Class:SynchroLog/Attribute:stats_nb_obj_deleted' => 'Nb objektumok törölve',
'Class:SynchroLog/Attribute:stats_nb_obj_deleted_errors' => 'Nb hibái törlés közben',
'Class:SynchroLog/Attribute:stats_nb_obj_obsoleted' => 'Nb objketumok elavultak',
'Class:SynchroLog/Attribute:stats_nb_obj_obsoleted_errors' => 'Nb hibák elavulás közben',
'Class:SynchroLog/Attribute:stats_nb_obj_created' => 'Nb objketumok létrehozva',
'Class:SynchroLog/Attribute:stats_nb_obj_created_errors' => 'Nb hibák létrehozás közben',
'Class:SynchroLog/Attribute:stats_nb_obj_updated' => 'Nb objektum frissítve',
'Class:SynchroLog/Attribute:stats_nb_obj_updated_errors' => 'Nb hibák firssítés közben',
'Class:SynchroLog/Attribute:stats_nb_replica_reconciled_errors' => 'Nb hibák rekonsziliálás közben',
'Class:SynchroLog/Attribute:stats_nb_replica_disappeared_no_action' => 'Nb replikáció eltűnt',
'Class:SynchroLog/Attribute:stats_nb_obj_new_updated' => 'Nb objketumok frissítve',
'Class:SynchroLog/Attribute:stats_nb_obj_new_unchanged' => 'Nb objketumok változatlanok',
'Class:SynchroLog/Attribute:last_error' => 'Utolsó hiba',
'Class:SynchroLog/Attribute:traces' => 'Trace',
'Class:SynchroReplica' => 'Szinkron másolat',
'Class:SynchroReplica/Attribute:sync_source_id' => 'Szinkron adatforrás',
'Class:SynchroReplica/Attribute:dest_id' => 'Cél objektum azonosító',
'Class:SynchroReplica/Attribute:dest_class' => 'Cél típusa',
'Class:SynchroReplica/Attribute:status_last_seen' => 'Utolsó megtekintett',
'Class:SynchroReplica/Attribute:status' => 'Státusz',
'Class:SynchroReplica/Attribute:status/Value:modified' => 'Módosított',
'Class:SynchroReplica/Attribute:status/Value:new' => 'Új',
'Class:SynchroReplica/Attribute:status/Value:obsolete' => 'Elavult',
'Class:SynchroReplica/Attribute:status/Value:orphan' => 'Árva',
'Class:SynchroReplica/Attribute:status/Value:synchronized' => 'Szinkronizált',
'Class:SynchroReplica/Attribute:status_dest_creator' => 'Objektum létrehozott?',
'Class:SynchroReplica/Attribute:status_last_error' => 'Utolsó hiba',
'Class:SynchroReplica/Attribute:info_creation_date' => 'Létrehozás dátuma',
'Class:SynchroReplica/Attribute:info_last_modified' => 'Utolsó módosítás dátuma',
'Class:appUserPreferences' => 'Felhasználói beállítások',
'Class:appUserPreferences/Attribute:userid' => 'Felhasználó',
'Class:appUserPreferences/Attribute:preferences' => 'Beállítások',
'Core:AttributeLinkedSet' => 'Objektum tömbök',
'Core:AttributeLinkedSet+' => '',
'Core:AttributeLinkedSetIndirect' => 'Objektum tömbök (N-N)',
'Core:AttributeLinkedSetIndirect+' => '',
'Core:AttributeInteger' => 'Integer',
'Core:AttributeInteger+' => '',
'Core:AttributeDecimal' => 'Decimal',
'Core:AttributeDecimal+' => '',
'Core:AttributeBoolean' => 'Boolean',
'Core:AttributeBoolean+' => '',
'Core:AttributeString' => 'String',
'Core:AttributeString+' => '',
'Core:AttributeClass' => 'Class',
'Core:AttributeClass+' => '',
'Core:AttributeApplicationLanguage' => 'Alkalmazás nyelve',
'Core:AttributeApplicationLanguage+' => '',
'Core:AttributeFinalClass' => 'Class (auto)',
'Core:AttributeFinalClass+' => '',
'Core:AttributePassword' => 'Jelszó',
'Core:AttributePassword+' => '',
'Core:AttributeEncryptedString' => 'Encrypted string',
'Core:AttributeEncryptedString+' => '',
'Core:AttributeText' => 'Text',
'Core:AttributeText+' => '',
'Core:AttributeHTML' => 'HTML',
'Core:AttributeHTML+' => '',
'Core:AttributeEmailAddress' => 'E-mail cím',
'Core:AttributeEmailAddress+' => '',
'Core:AttributeIPAddress' => 'IP cím',
'Core:AttributeIPAddress+' => '',
'Core:AttributeOQL' => 'OQL',
'Core:AttributeOQL+' => '',
'Core:AttributeEnum' => 'Enum',
'Core:AttributeEnum+' => '',
'Core:AttributeTemplateString' => 'Sablon szöveg',
'Core:AttributeTemplateString+' => '',
'Core:AttributeTemplateText' => 'Sablon szöveg',
'Core:AttributeTemplateText+' => '',
'Core:AttributeTemplateHTML' => 'Sablon HTML',
'Core:AttributeTemplateHTML+' => '',
'Core:AttributeDateTime' => 'Date/time',
'Core:AttributeDateTime+' => '',
'Core:AttributeDate' => 'Date',
'Core:AttributeDate+' => '',
'Core:AttributeDeadline' => 'Határidő',
'Core:AttributeDeadline+' => '',
'Core:AttributeExternalKey' => 'Külső kulcs',
'Core:AttributeExternalKey+' => '',
'Core:AttributeExternalField' => 'Külső mező',
'Core:AttributeExternalField+' => '',
'Core:AttributeURL' => 'URL',
'Core:AttributeURL+' => '',
'Core:AttributeBlob' => 'Blob',
'Core:AttributeBlob+' => '',
'Core:AttributeOneWayPassword' => 'One way password',
'Core:AttributeOneWayPassword+' => '',
'Core:AttributeTable' => 'Table',
'Core:AttributeTable+' => '',
'Core:AttributePropertySet' => 'Tulajdonságok',
'Core:AttributePropertySet+' => '',
'Class:CMDBChangeOp/Attribute:date' => 'Dátum',
'Class:CMDBChangeOp/Attribute:date+' => '',
'Class:CMDBChangeOp/Attribute:userinfo' => 'Felhasználó',
'Class:CMDBChangeOp/Attribute:userinfo+' => '',
'Change:ObjectCreated' => 'Objektum létrehozva',
'Change:ObjectDeleted' => 'Objektum törölve',
'Change:ObjectModified' => 'Objektum módosítva',
'Change:AttName_SetTo_NewValue_PreviousValue_OldValue' => '%1$s új értéke: %2$s (előző értéke: %3$s)',
'Change:AttName_SetTo' => '%1$s új értéke %2$s',
'Change:Text_AppendedTo_AttName' => '%1$s hozzáfűzve %2$s',
'Change:AttName_Changed_PreviousValue_OldValue' => '%1$s módosítva, előző érték: %2$s',
'Change:AttName_Changed' => '%1$s módosítva',
'Change:AttName_EntryAdded' => '%1$s módosítva, új bejegyzés hozzáadva.',
'Class:EventLoginUsage/Attribute:contact_name' => 'Felhasználó neve',
'Class:EventLoginUsage/Attribute:contact_name+' => '',
'Class:EventLoginUsage/Attribute:contact_email' => 'Felhasználó e-mail',
'Class:EventLoginUsage/Attribute:contact_email+' => '',
'Class:Action' => 'Egyedi akciók',
'Class:Action+' => '',
'Class:Action/Attribute:name' => 'Neve',
'Class:Action/Attribute:name+' => '',
'Class:Action/Attribute:description' => 'Leírás',
'Class:Action/Attribute:description+' => '',
'Class:Action/Attribute:status' => 'Státusz',
'Class:Action/Attribute:status+' => '',
'Class:Action/Attribute:status/Value:test' => 'Tesztelés alatt',
'Class:Action/Attribute:status/Value:test+' => '',
'Class:Action/Attribute:status/Value:enabled' => 'Éles üzemeben',
'Class:Action/Attribute:status/Value:enabled+' => '',
'Class:Action/Attribute:status/Value:disabled' => 'Inaktív',
'Class:Action/Attribute:status/Value:disabled+' => '',
'Class:Action/Attribute:trigger_list' => 'Kapcsolódó kiváltó okok',
'Class:Action/Attribute:trigger_list+' => '',
'Class:Action/Attribute:finalclass' => 'Típus',
'Class:Action/Attribute:finalclass+' => '',
'Class:ActionNotification' => 'Értesítés',
'Class:ActionNotification+' => '',
'Class:Trigger' => 'Kiváltó ok',
'Class:Trigger+' => '',
'Class:Trigger/Attribute:description' => 'Leírás',
'Class:Trigger/Attribute:description+' => '',
'Class:Trigger/Attribute:action_list' => 'Kiváltott akció',
'Class:Trigger/Attribute:action_list+' => '',
'Class:Trigger/Attribute:finalclass' => 'Típus',
'Class:Trigger/Attribute:finalclass+' => '',
'Class:TriggerOnObject' => 'Kiváltó ok (osztály függő)',
'Class:TriggerOnObject+' => '',
'Class:TriggerOnObject/Attribute:target_class' => 'Cél osztály',
'Class:TriggerOnObject/Attribute:target_class+' => '',
'Class:TriggerOnStateChange' => 'Kiváltó ok (állapot változás)',
'Class:TriggerOnStateChange+' => '',
'Class:TriggerOnStateChange/Attribute:state' => 'Állapot',
'Class:TriggerOnStateChange/Attribute:state+' => '',
'Class:lnkTriggerAction/Attribute:action_name' => 'Akció',
'Class:lnkTriggerAction/Attribute:action_name+' => '',
'Class:lnkTriggerAction/Attribute:trigger_name' => 'Kiváltó ok',
'Class:lnkTriggerAction/Attribute:trigger_name+' => '',
'Class:SynchroDataSource/Attribute:delete_policy/Value:never' => 'Senki',
'Class:SynchroDataSource/Attribute:delete_policy/Value:depends' => 'Csak adminisztrátorok',
'Class:SynchroDataSource/Attribute:delete_policy/Value:always' => 'Tíltott felhasználók',
'SynchroDataSource:Description' => 'Leírás',
'SynchroDataSource:Reconciliation' => 'Keresés &amp; rekponsziliálás',
'SynchroDataSource:Deletion' => 'Törlés szabályai',
'SynchroDataSource:Status' => 'Státusz',
'SynchroDataSource:Information' => 'Információ',
'SynchroDataSource:Definition' => 'Meghatározás',
'Core:SynchroAttributes' => 'Attribútumok',
'Core:SynchroStatus' => 'Státusz',
'Core:Synchro:ErrorsLabel' => 'Hibák',
'Core:Synchro:CreatedLabel' => 'Létrehozva',
'Core:Synchro:ModifiedLabel' => 'Módosítva',
'Core:Synchro:UnchangedLabel' => 'Változatlan',
'Core:Synchro:ReconciledErrorsLabel' => 'Hibák',
'Core:Synchro:ReconciledLabel' => 'Rekonsziliált',
'Core:Synchro:ReconciledNewLabel' => 'Létrehozva',
'Core:SynchroReconcile:Yes' => 'Igen',
'Core:SynchroReconcile:No' => 'Nem',
'Core:SynchroUpdate:Yes' => 'Igen',
'Core:SynchroUpdate:No' => 'Nem',
'Core:Synchro:LastestStatus' => 'Utolsó státusz',
'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.',
'Menu:DataSources' => 'Szinkronizált adatforrások',
'Menu:DataSources+' => '',
'Core:Synchro:label_repl_ignored' => 'Figyelmen kívül hagyott (%1$s)',
'Core:Synchro:label_repl_disappeared' => 'Elveszett (%1$s)',
'Core:Synchro:label_repl_existing' => 'Létező (%1$s)',
'Core:Synchro:label_repl_new' => 'Új (%1$s)',
'Core:Synchro:label_obj_deleted' => 'Törölt (%1$s)',
'Core:Synchro:label_obj_obsoleted' => 'Elavult (%1$s)',
'Core:Synchro:label_obj_disappeared_errors' => 'Hibák (%1$s)',
'Core:Synchro:label_obj_disappeared_no_action' => 'Beavatkozás nem szükséges (%1$s)',
'Core:Synchro:label_obj_unchanged' => 'Változatan (%1$s)',
'Core:Synchro:label_obj_updated' => 'Frisített (%1$s)',
'Core:Synchro:label_obj_updated_errors' => 'Hibák (%1$s)',
'Core:Synchro:label_obj_new_unchanged' => 'Változatlan (%1$s)',
'Core:Synchro:label_obj_new_updated' => 'Frissített (%1$s)',
'Core:Synchro:label_obj_created' => 'Létrehozott (%1$s)',
'Core:Synchro:label_obj_new_errors' => 'Hibák (%1$s)',
'Core:SynchroLogTitle' => '%1$s - %2$s',
'Core:Synchro:Nb_Replica' => 'Másolat elkészítve: %1$s',
'Core:Synchro:Nb_Class:Objects' => '%1$s: %2$s',
'Class:SynchroDataSource/Error:AtLeastOneReconciliationKeyMustBeSpecified' => 'Egyeztetéshez legalább egy kulcsot meg kell adni, egyébként az egyeztetés az elsődleges kulcs alapján történik.',
'Class:SynchroDataSource/Error:DeleteRetentionDurationMustBeSpecified' => 'A törlés késleltetésének időtartamát meg kell adni, egyébként az objektum törölve lesz annak elavulttá minősítése után.',
'Class:SynchroDataSource/Error:DeletePolicyUpdateMustBeSpecified' => 'Lejárt objektumok frissítése nem tud megtörténni.',
'Core:SynchroReplica:PublicData' => 'Publikus adatok',
'Core:SynchroReplica:PrivateDetails' => 'Privát adatok',
'Core:SynchroReplica:BackToDataSource' => 'Vissza a következő szinkron adatforráshoz: %1$s',
'Core:SynchroReplica:ListOfReplicas' => 'Másolatok listája',
'Core:SynchroAttExtKey:ReconciliationById' => 'Azonosító (Elsődleges kulcs)',
'Core:SynchroAtt:attcode' => 'Attribútum',
'Core:SynchroAtt:attcode+' => '',
'Core:SynchroAtt:reconciliation' => 'Egyeztetés?',
'Core:SynchroAtt:reconciliation+' => '',
'Core:SynchroAtt:update' => 'Frissített?',
'Core:SynchroAtt:update+' => '',
'Core:SynchroAtt:update_policy' => 'Frissítési szabály',
'Core:SynchroAtt:update_policy+' => '',
'Core:SynchroAtt:reconciliation_attcode' => 'Egyeztetés kulcsa',
'Core:SynchroAtt:reconciliation_attcode+' => '',
'Core:SyncDataExchangeComment' => '(DataExchange)',
'Core:Synchro:ListOfDataSources' => 'Adatforrások listája',
'Core:Synchro:LastSynchro' => 'Utolsó szimkronizáció',
'Core:Synchro:ThisObjectIsSynchronized' => 'Az objektum szinkronizálva a külső adatforrással.',
'Core:Synchro:TheObjectWasCreatedBy_Source' => 'Objektum <b>létrehozva</b> a következő adatforrásban: %1$s',
'Core:Synchro:TheObjectCanBeDeletedBy_Source' => 'Objektum <b>törölhető</b> a következő külső adatforrásból: %1$s',
'Core:Synchro:TheObjectCannotBeDeletedByUser_Source' => '<b>Objektum nem törölhető</b> mert egy másik adatforrás (%1$s) tulajdona',
'TitleSynchroExecution' => 'Szinkronizáció végrehajtás',
'Class:SynchroDataSource:DataTable' => 'Adatbázis tábla: %1$s',
'Core:SyncDataSourceObsolete' => 'Az adatforrás elvalultnak van jelölve. Művelet visszavonva.',
'Core:SyncDataSourceAccessRestriction' => 'Csak az adminisztrátor vagy speciális jogokkal rendelkező felhasználó futtathatja a műveletet. Művelet visszavonva.',
'Core:SyncTooManyMissingReplicas' => 'Import során az összes másolat elveszett. Az import valóban lefutott? Művelet visszavonva.',
'Core:Duration_Seconds' => '%1$sds',
'Core:Duration_Minutes_Seconds' => '%1$sdmin %2$sds',
'Core:Duration_Hours_Minutes_Seconds' => '%1$sdh %2$sdmin %3$sds',
'Core:Duration_Days_Hours_Minutes_Seconds' => '%1$sd %2$sdh %3$sdmin %4$ds',
));
?>

View File

@@ -0,0 +1,777 @@
<?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('HU HU', 'Hungarian', 'Magyar', array(
'Class:AuditRule' => 'Auditálási szabály',
'Class:AuditRule+' => '',
'Class:AuditRule/Attribute:name' => 'Szabály neve',
'Class:AuditRule/Attribute:name+' => '',
'Class:AuditRule/Attribute:description' => 'Auditálási szabály leírása',
'Class:AuditRule/Attribute:description+' => '',
'Class:AuditRule/Attribute:query' => 'Futtatandó lekérdezés',
'Class:AuditRule/Attribute:query+' => '',
'Class:AuditRule/Attribute:valid_flag' => 'Érvényes objektum?',
'Class:AuditRule/Attribute:valid_flag+' => '',
'Class:AuditRule/Attribute:valid_flag/Value:false' => 'hamis',
'Class:AuditRule/Attribute:valid_flag/Value:false+' => '',
'Class:AuditRule/Attribute:valid_flag/Value:true' => 'igaz',
'Class:AuditRule/Attribute:valid_flag/Value:true+' => '',
'Class:AuditRule/Attribute:category_id' => 'Kategória',
'Class:AuditRule/Attribute:category_id+' => '',
'Class:AuditCategory' => 'Audit kategória',
'Class:AuditCategory+' => '',
'Class:AuditCategory/Attribute:name' => 'Kategória neve',
'Class:AuditCategory/Attribute:name+' => '',
'Class:AuditCategory/Attribute:description' => 'Audit kategória leírása',
'Class:AuditCategory/Attribute:description+' => '',
'Class:AuditCategory/Attribute:definition_set' => 'Meghatározás halmaz',
'Class:AuditCategory/Attribute:definition_set+' => '',
'Class:AuditCategory/Attribute:rules_list' => 'Audit szabályok',
'Class:AuditCategory/Attribute:rules_list+' => '',
'Class:URP_Profiles' => 'Profil',
'Class:URP_Profiles+' => '',
'Class:URP_Profiles/Attribute:name' => 'Neve',
'Class:URP_Profiles/Attribute:name+' => '',
'Class:URP_Profiles/Attribute:description' => 'Leírás',
'Class:URP_Profiles/Attribute:description+' => '',
'Class:URP_Profiles/Attribute:user_list' => 'Felhasználók',
'Class:URP_Profiles/Attribute:user_list+' => '',
'Class:URP_UserProfile' => 'Profilhoz rendelt felhasználók',
'Class:URP_UserProfile+' => '',
'Class:URP_UserProfile/Attribute:userid' => 'Felhasználó',
'Class:URP_UserProfile/Attribute:userid+' => '',
'Class:URP_UserProfile/Attribute:profileid' => 'Profil',
'Class:URP_UserProfile/Attribute:profileid+' => '',
'Class:URP_UserProfile/Attribute:reason' => 'Ok',
'Class:URP_UserProfile/Attribute:reason+' => '',
'Class:URP_UserOrg' => 'Felhasználó szervezeti egysége',
'Class:URP_UserOrg+' => '',
'Class:URP_UserOrg/Attribute:userid' => 'Felhasználó',
'Class:URP_UserOrg/Attribute:userid+' => '',
'Class:URP_UserOrg/Attribute:allowed_org_id' => 'Szervezeti egység',
'Class:URP_UserOrg/Attribute:allowed_org_id+' => '',
'Class:URP_UserOrg/Attribute:reason' => 'Ok',
'Class:URP_UserOrg/Attribute:reason+' => '',
'Class:URP_ActionGrant' => 'action_permission',
'Class:URP_ActionGrant+' => '',
'Class:URP_ActionGrant/Attribute:profileid' => 'Profil',
'Class:URP_ActionGrant/Attribute:profileid+' => '',
'Class:URP_ActionGrant/Attribute:class' => 'Osztály',
'Class:URP_ActionGrant/Attribute:class+' => '',
'Class:URP_ActionGrant/Attribute:permission' => 'Hozzáférés',
'Class:URP_ActionGrant/Attribute:permission+' => '',
'Class:URP_ActionGrant/Attribute:permission/Value:no' => 'Nem',
'Class:URP_ActionGrant/Attribute:permission/Value:no+' => '',
'Class:URP_ActionGrant/Attribute:permission/Value:yes' => 'Igen',
'Class:URP_ActionGrant/Attribute:permission/Value:yes+' => '',
'Class:URP_ActionGrant/Attribute:action' => 'Akció',
'Class:URP_ActionGrant/Attribute:action+' => '',
'Class:URP_StimulusGrant' => 'stimulus_permission',
'Class:URP_StimulusGrant+' => '',
'Class:URP_StimulusGrant/Attribute:profileid' => 'Profil',
'Class:URP_StimulusGrant/Attribute:profileid+' => '',
'Class:URP_StimulusGrant/Attribute:class' => 'Osztály',
'Class:URP_StimulusGrant/Attribute:class+' => '',
'Class:URP_StimulusGrant/Attribute:permission' => 'Hozzáférés',
'Class:URP_StimulusGrant/Attribute:permission+' => '',
'Class:URP_StimulusGrant/Attribute:permission/Value:no' => 'Nem',
'Class:URP_StimulusGrant/Attribute:permission/Value:no+' => '',
'Class:URP_StimulusGrant/Attribute:permission/Value:yes' => 'Igen',
'Class:URP_StimulusGrant/Attribute:permission/Value:yes+' => '',
'Class:URP_StimulusGrant/Attribute:stimulus' => 'Stimulus',
'Class:URP_StimulusGrant/Attribute:stimulus+' => '',
'Class:URP_AttributeGrant' => 'attribute_permission',
'Class:URP_AttributeGrant+' => '',
'Class:URP_AttributeGrant/Attribute:actiongrantid' => 'Akció engedély',
'Class:URP_AttributeGrant/Attribute:actiongrantid+' => '',
'Class:URP_AttributeGrant/Attribute:attcode' => 'Attribútum',
'Class:URP_AttributeGrant/Attribute:attcode+' => '',
'Class:AuditRule/Attribute:category_name' => 'Kategória',
'Class:AuditRule/Attribute:category_name+' => '',
'Class:User' => 'Felhasználó',
'Class:User+' => '',
'Class:User/Attribute:finalclass' => 'Felhasználó típusa',
'Class:User/Attribute:finalclass+' => '',
'Class:User/Attribute:contactid' => 'Kapcsolattartó (személy)',
'Class:User/Attribute:contactid+' => '',
'Class:User/Attribute:last_name' => 'Családnév',
'Class:User/Attribute:last_name+' => '',
'Class:User/Attribute:first_name' => 'Keresztnév',
'Class:User/Attribute:first_name+' => '',
'Class:User/Attribute:email' => 'E-mail',
'Class:User/Attribute:email+' => '',
'Class:User/Attribute:login' => 'Bejelentkezési név',
'Class:User/Attribute:login+' => '',
'Class:User/Attribute:language' => 'Nyelv',
'Class:User/Attribute:language+' => '',
'Class:User/Attribute:language/Value:EN US' => 'Angol',
'Class:User/Attribute:language/Value:EN US+' => '',
'Class:User/Attribute:language/Value:HU HU' => 'Magyar',
'Class:User/Attribute:language/Value:HU HU+' => '',
'Class:User/Attribute:language/Value:FR FR' => 'Francia',
'Class:User/Attribute:language/Value:FR FR+' => '',
'Class:User/Attribute:profile_list' => 'Profil',
'Class:User/Attribute:profile_list+' => '',
'Class:User/Attribute:allowed_org_list' => 'Engedélyezett szervezeti egységek',
'Class:User/Attribute:allowed_org_list+' => '',
'Class:User/Error:LoginMustBeUnique' => 'Bejelentkezési névnek egyedinek kell lennie - "%1s" már létezik.',
'Class:User/Error:AtLeastOneProfileIsNeeded' => 'Legalább egy profilt a felhasználóhoz kell rendelni.',
'Class:URP_Dimensions' => 'Dimenzió',
'Class:URP_Dimensions+' => '',
'Class:URP_Dimensions/Attribute:name' => 'Neve',
'Class:URP_Dimensions/Attribute:name+' => '',
'Class:URP_Dimensions/Attribute:description' => 'Leírás',
'Class:URP_Dimensions/Attribute:description+' => '',
'Class:URP_Dimensions/Attribute:type' => 'Típus',
'Class:URP_Dimensions/Attribute:type+' => '',
'Class:URP_UserProfile/Attribute:userlogin' => 'Bejelentkezési név',
'Class:URP_UserProfile/Attribute:userlogin+' => '',
'Class:URP_UserProfile/Attribute:profile' => 'Profil',
'Class:URP_UserProfile/Attribute:profile+' => '',
'Class:URP_UserOrg/Attribute:userlogin' => 'Bejelentkezési név',
'Class:URP_UserOrg/Attribute:userlogin+' => '',
'Class:URP_UserOrg/Attribute:allowed_org_name' => 'Szervezeti egység',
'Class:URP_UserOrg/Attribute:allowed_org_name+' => '',
'Class:URP_ProfileProjection' => 'profile_projection',
'Class:URP_ProfileProjection+' => '',
'Class:URP_ProfileProjection/Attribute:dimensionid' => 'Dimenzió',
'Class:URP_ProfileProjection/Attribute:dimensionid+' => '',
'Class:URP_ProfileProjection/Attribute:dimension' => 'Dimenzió',
'Class:URP_ProfileProjection/Attribute:dimension+' => '',
'Class:URP_ProfileProjection/Attribute:profileid' => 'Profil',
'Class:URP_ProfileProjection/Attribute:profileid+' => '',
'Class:URP_ProfileProjection/Attribute:profile' => 'Profil',
'Class:URP_ProfileProjection/Attribute:profile+' => '',
'Class:URP_ProfileProjection/Attribute:value' => 'Érték',
'Class:URP_ProfileProjection/Attribute:value+' => '',
'Class:URP_ProfileProjection/Attribute:attribute' => 'Attribútum',
'Class:URP_ProfileProjection/Attribute:attribute+' => '',
'Class:URP_ClassProjection' => 'class_projection',
'Class:URP_ClassProjection+' => '',
'Class:URP_ClassProjection/Attribute:dimensionid' => 'Dimenzió',
'Class:URP_ClassProjection/Attribute:dimensionid+' => '',
'Class:URP_ClassProjection/Attribute:dimension' => 'Dimenzió',
'Class:URP_ClassProjection/Attribute:dimension+' => '',
'Class:URP_ClassProjection/Attribute:class' => 'Osztály',
'Class:URP_ClassProjection/Attribute:class+' => '',
'Class:URP_ClassProjection/Attribute:value' => 'Érték',
'Class:URP_ClassProjection/Attribute:value+' => '',
'Class:URP_ClassProjection/Attribute:attribute' => 'Attribútum',
'Class:URP_ClassProjection/Attribute:attribute+' => '',
'Class:URP_ActionGrant/Attribute:profile' => 'Profil',
'Class:URP_ActionGrant/Attribute:profile+' => '',
'Class:URP_StimulusGrant/Attribute:profile' => 'Profil',
'Class:URP_StimulusGrant/Attribute:profile+' => '',
'Menu:WelcomeMenu' => 'Üdvözlöm',
'Menu:WelcomeMenu+' => '',
'Menu:WelcomeMenuPage' => 'Üdvözlöm',
'Menu:WelcomeMenuPage+' => '',
'UI:WelcomeMenu:Title' => 'Üdvözli az iTop',
'UI:WelcomeMenu:LeftBlock' => '<p>iTop egy teljeskörű, OpenSource, IT üzemeltetés támogató portál.</p>
<ul>A következőket tartalmazza:
<li>Teljeskörű CMDB (Konfiguráció menedzsment adatbázis) az IT eszközök dokumentálására és verzió kezelésére.</li>
<li>Incidens menedzsment modul az összes IT-hez kapcsolódó kérés életciklusának követésére.</li>
<li>Változás menedzsment modul az IT infrastruktúra változásainak nyomonkövetésére és tervezésére.</li>
<li>Ismert hibák adatbázisa az incidens kezelés sebességének növelésére.</li>
<li>Üzmeszünet modul az összes tervezett leállás tervezésére és azzal kapcsolatos kommunikáció támogatására.</li>
<li>Dashboard-ok az IT infrastruktúra pillanatnyi állapotának gyors áttekintésére.</li>
</ul>
<p>Mindegyik modul önállóan telepíthető és használható.</p>',
'UI:WelcomeMenu:RightBlock' => '<p>iTop egy szolgáltatás orientált megoldás, amely segít az IT szakembereknek több ügyfél és szervezet egyidejű menedzselését.
<ul>az iTop az üzleti folyamatok javításához egy hatékony eszköz, mert:
<li>javítja az IT menedzsment hatékonyságát</li>
<li>növeli IT üzemeltetés teljesítményét</li>
<li>növeli az ügyfél elégedettséget és a vezetők számára lehetőséget ad az üzleti teljesítmény növelésére</li>
</ul>
</p>
<p>Az iTop teljesn nyílt ezért, egyszerűen integrálható a jelenlegi IT infrastruktúrába</p>
<p>
<ul>Az üzemeltetési portál bevezetésével:
<li>jobban menedzselhető az egyre komplexebb IT infrstruktúra</li>
<li>az ITIL folyamatok bevezetésre kerülnek</li>
<li>hatékonyan tudja kezelni az egyik legfontosabb IT eszközt, a dokumentációt.</li>
</ul>
</p>',
'UI:WelcomeMenu:AllOpenRequests' => 'Összes nyitott kérés: %1$d',
'UI:WelcomeMenu:MyCalls' => 'Saját kérések',
'UI:WelcomeMenu:OpenIncidents' => 'Nyitott incidensek: %1$d',
'UI:WelcomeMenu:AllConfigItems' => 'Konfigurációs elemek: %1$d',
'UI:WelcomeMenu:MyIncidents' => 'Hozzám rendelt incidensek',
'UI:AllOrganizations' => 'Összes szervezeti egység',
'UI:YourSearch' => 'Saját keresések',
'UI:LoggedAsMessage' => 'Bejelentkezve %1$s',
'UI:LoggedAsMessage+Admin' => 'Bejelentkezve %1$s (Administrator)',
'UI:Button:Logoff' => 'Kijelentkezés',
'UI:Button:GlobalSearch' => 'Keresés',
'UI:Button:Search' => ' Keresés',
'UI:Button:Query' => ' Lekérdezés',
'UI:Button:Ok' => 'OK',
'UI:Button:Cancel' => 'Mégse',
'UI:Button:Apply' => 'Alkalmazás',
'UI:Button:Back' => ' << Vissza',
'UI:Button:Restart' => ' |<< Újraindítás',
'UI:Button:Next' => ' Következő >>',
'UI:Button:Finish' => ' Befejezés',
'UI:Button:DoImport' => ' Importálás indítása',
'UI:Button:Done' => ' Kész',
'UI:Button:SimulateImport' => ' Import szimulálása',
'UI:Button:Test' => 'Teszt!',
'UI:Button:Evaluate' => ' Értékelés',
'UI:Button:AddObject' => ' Hozzáad...',
'UI:Button:BrowseObjects' => ' Böngészés...',
'UI:Button:Add' => ' Hozzáad ',
'UI:Button:AddToList' => ' << Hozzáad ',
'UI:Button:RemoveFromList' => ' Eltávolít >> ',
'UI:Button:FilterList' => ' Szűrés... ',
'UI:Button:Create' => ' Létrehoz',
'UI:Button:Delete' => ' Töröl !',
'UI:Button:ChangePassword' => ' Jelszó változtatás',
'UI:Button:ResetPassword' => ' Jelszó változtatás',
'UI:SearchToggle' => 'Keresés',
'UI:ClickToCreateNew' => 'Új %1$s létrehozása',
'UI:SearchFor_Class' => '%1$s objektumok keresése',
'UI:NoObjectToDisplay' => 'Nincs megjeleníthető objektum',
'UI:Error:MandatoryTemplateParameter_object_id' => 'object_id pareméter kötelező a link_attr megadásánál. Ellenőrizze a sablon definíciót.',
'UI:Error:MandatoryTemplateParameter_target_attr' => 'target_attr pareméter kötelező a link_attr megadásánál. Ellenőrizze a sablon definíciót.',
'UI:Error:MandatoryTemplateParameter_group_by' => 'group_by paraméter kötelező. Ellenőrizze a sablon definíciót.',
'UI:Error:InvalidGroupByFields' => 'Csoportosításnál használt érvénytelen mezők: "%1$s".',
'UI:Error:UnsupportedStyleOfBlock' => 'Hiba: nem támogatott stílus tömb: "%1$s".',
'UI:Error:IncorrectLinkDefinition_LinkedClass_Class' => 'Nem megfelelő kapcsolat meghatározás: kapcsolódó osztály: %1$s nem külső kulcs a %2$s osztályban',
'UI:Error:Object_Class_Id_NotFound' => 'Objektum: %1$s:%2$d nem található.',
'UI:Error:WizardCircularReferenceInDependencies' => 'Hiba: Körkörös hivatkozás az egymásra mutató mezők között. Ellenőrizze az adatmodelt.',
'UI:Error:UploadedFileTooBig' => 'Feltöltendő fájl túl nagy. (Maximális méret: %1$s). Ellenőroizze a PHP konfigurációs fájlban az upload_max_filesize és post_max_size beállításokat.',
'UI:Error:UploadedFileTruncated.' => 'Feltöltött fájl átméretezett!',
'UI:Error:NoTmpDir' => 'Az átmeneti könyvtár nem meghatározott.',
'UI:Error:CannotWriteToTmp_Dir' => 'Az átmeneti fájl nem írható. upload_tmp_dir = "%1$s".',
'UI:Error:UploadStoppedByExtension_FileName' => 'Feltöltés megállt a fájl kiterjesztés miatt. (Eredeti fájl név = "%1$s").',
'UI:Error:UploadFailedUnknownCause_Code' => 'Fájl feltöltés sikertelen ismeretlen hiba miatt. (Hibakód = "%1$s").',
'UI:Error:1ParametersMissing' => 'Hiba: a következő paramétert meg kell adni ennél a műveletnél: %1$s.',
'UI:Error:2ParametersMissing' => 'Hiba: a következő paramétereket meg kell adni ennél a műveletnél: %1$s és %2$s.',
'UI:Error:3ParametersMissing' => 'Hiba: a következő paramétereket meg kell adni ennél a műveletnél: %1$s, %2$s és %3$s.',
'UI:Error:4ParametersMissing' => 'Hiba: a következő paramétereket meg kell adni ennél a műveletnél: %1$s, %2$s, %3$s és %4$s.',
'UI:Error:IncorrectOQLQuery_Message' => 'Hiba: nem megfelelő OQL lekérdezés: %1$',
'UI:Error:AnErrorOccuredWhileRunningTheQuery_Message' => 'Hiba történt a lekérdezs futtatása közben: %1$s',
'UI:Error:ObjectAlreadyUpdated' => 'Hiba: az objketum már korábban módosításra került.',
'UI:Error:ObjectCannotBeUpdated' => 'Hiba: az objektum nem frissíthető.',
'UI:Error:ObjectsAlreadyDeleted' => 'Hiba: az objektum már korában törlésre került!',
'UI:Error:BulkDeleteNotAllowedOn_Class' => 'Az osztály objektumainak tömeges törlése nem engedélyezett %1$s',
'UI:Error:DeleteNotAllowedOn_Class' => 'Az osztály objektumainak törlése nem engedélyezett %1$s',
'UI:Error:BulkModifyNotAllowedOn_Class' => 'Az osztály objektumainak tömeges frissítése nem engedélyezett %1$s',
'UI:Error:ObjectAlreadyCloned' => 'Hiba: az objektum már klónozott!',
'UI:Error:ObjectAlreadyCreated' => 'Hiba: az objekltum már létrehozva!',
'UI:Error:Invalid_Stimulus_On_Object_In_State' => 'Hiba: érvénytelen stimulus "%1$s" a következő objektum %2$s következő állapotában "%3$s".',
'UI:GroupBy:Count' => 'Számossága',
'UI:GroupBy:Count+' => '',
'UI:CountOfObjects' => '%1$d darab objektum felel meg a kritériumoknak.',
'UI_CountOfObjectsShort' => '%1$d objketum.',
'UI:NoObject_Class_ToDisplay' => 'Nincs megjeleníthető %1$s',
'UI:History:LastModified_On_By' => 'Utolsó módosítást a következő objektumon %1$s %2$s végezte.',
'UI:HistoryTab' => 'Törénet',
'UI:NotificationsTab' => 'Értesítés',
'UI:History:BulkImports' => 'Történet',
'UI:History:BulkImports+' => '',
'UI:History:BulkImportDetails' => 'CSV import végrehajtva: %1$s (%2$s által)',
'UI:History:Date' => 'Dátum',
'UI:History:Date+' => '',
'UI:History:User' => 'Felhasználó',
'UI:History:User+' => '',
'UI:History:Changes' => 'Változások',
'UI:History:Changes+' => '',
'UI:History:StatsCreations' => 'Létrehozva',
'UI:History:StatsCreations+' => '',
'UI:History:StatsModifs' => 'Módosítva',
'UI:History:StatsModifs+' => '',
'UI:History:StatsDeletes' => 'Törölve',
'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...',
'UI:Menu:EMail' => 'e-mail',
'UI:Menu:CSVExport' => 'CSV export',
'UI:Menu:Modify' => 'Módosít...',
'UI:Menu:Delete' => 'Töröl...',
'UI:Menu:BulkDelete' => 'Töröl...',
'UI:UndefinedObject' => 'nem meghatározott',
'UI:Document:OpenInNewWindow:Download' => 'Megnyitás új ablakban: %1$s, Letöltés: %2$s',
'UI:SelectAllToggle+' => '',
'UI:TruncatedResults' => '%1$d objektum megjelenítve %2$d példányból',
'UI:DisplayAll' => 'Összes megjelenítése',
'UI:CollapseList' => 'Elemek',
'UI:CountOfResults' => '%1$d objektum',
'UI:ChangesLogTitle' => 'Változás napló (%1$d):',
'UI:EmptyChangesLogTitle' => 'Változás napló üres',
'UI:SearchFor_Class_Objects' => 'Keresés %1$s objektumra',
'UI:OQLQueryBuilderTitle' => 'OQL lekérdezés szerkesztő',
'UI:OQLQueryTab' => 'OQL lekérdezés',
'UI:SimpleSearchTab' => 'Egyszerű keresés',
'UI:Details+' => '',
'UI:SearchValue:Any' => '* Any *',
'UI:SearchValue:Mixed' => '* mixed *',
'UI:SelectOne' => '-- válasszon ki egyet --',
'UI:Login:Welcome' => 'Üdvözli az iTop!',
'UI:Login:IncorrectLoginPassword' => 'Nem megfelelő bejelentkezési név/jelszó, kérjük próbálja újra.',
'UI:Login:IdentifyYourself' => 'Folytatás előtt azonosítsa magát',
'UI:Login:UserNamePrompt' => 'Felhasználó név',
'UI:Login:PasswordPrompt' => 'Jelszó',
'UI:Login:ChangeYourPassword' => 'Jelszó változtatás',
'UI:Login:OldPasswordPrompt' => 'Jelenlegi jelszó',
'UI:Login:NewPasswordPrompt' => 'Új jelszó',
'UI:Login:RetypeNewPasswordPrompt' => 'Új jelszó ismét',
'UI:Login:IncorrectOldPassword' => 'Hiba: a jelenlegi jelszó hibás',
'UI:LogOffMenu' => 'Kilépés',
'UI:LogOff:ThankYou' => 'Köszönjük, hogy az iTop-ot használja!',
'UI:LogOff:ClickHereToLoginAgain' => 'Ismételt bejelentkezéshez kattintson ide',
'UI:ChangePwdMenu' => 'Jelszó módosítás...',
'UI:Login:PasswordChanged' => 'Jelszó sikeresen beállítva!',
'UI:AccessRO-All' => 'iTop csak olvasás módban',
'UI:AccessRO-Users' => 'iTop csak olvasás módban a végfelhasználók számára',
'UI:Login:RetypePwdDoesNotMatch' => 'Az új jelszó és ismételten beírt érték nem egyezik!',
'UI:Button:Login' => 'Belépés az iTop alkalmazásba',
'UI:Login:Error:AccessRestricted' => 'iTop hozzáférés korlátozva. Kérem forduljon az iTop adminisztrátorhoz!',
'UI:Login:Error:AccessAdmin' => 'Adminisztrátori hozzáférés korlátozott. Kérem forduljon az iTop adminisztrátorhoz!',
'UI:CSVImport:MappingSelectOne' => '-- válasszon ki egyet --',
'UI:CSVImport:MappingNotApplicable' => '-- mező figyelmen kívül hagyása --',
'UI:CSVImport:NoData' => 'Üres mező..., kérem agyjon meg adatot!',
'UI:Title:DataPreview' => 'Adatok előnézete',
'UI:CSVImport:ErrorOnlyOneColumn' => 'Hiba: Az import fájl egyetlen oszlopot tartalmaz. A megfelelő elválasztó karaktert adta meg?',
'UI:CSVImport:FieldName' => 'Mező %1$d',
'UI:CSVImport:DataLine1' => 'Adatsor 1',
'UI:CSVImport:DataLine2' => 'Adatsor 2',
'UI:CSVImport:idField' => 'id (elsődeges kulcs)',
'UI:Title:BulkImport' => 'iTop - tömeges betöltés',
'UI:Title:BulkImport+' => '',
'UI:Title:BulkSynchro_nbItem_ofClass_class' => '%2$s osztály %1$d objektumának szinkronizációja',
'UI:CSVImport:ClassesSelectOne' => '-- válasszon ki egyet --',
'UI:CSVImport:ErrorExtendedAttCode' => 'Belső hiba: "%1$s" nem megfelelő kód, mert "%2$s" nem külső kulcsa a "%3$s" osztálynak',
'UI:CSVImport:ObjectsWillStayUnchanged' => '%1$d objektumok változatlanok maradnak.',
'UI:CSVImport:ObjectsWillBeModified' => '%1$d objektumok fognak megváltozni.',
'UI:CSVImport:ObjectsWillBeAdded' => '%1$d objektumok hozzáadásra kerülnek.',
'UI:CSVImport:ObjectsWillHaveErrors' => '%1$d objektumok hibásak lesznek.',
'UI:CSVImport:ObjectsRemainedUnchanged' => '%1$d objektumok változatlanak maradtak',
'UI:CSVImport:ObjectsWereModified' => '%1$d objektumok módosításra kerültek.',
'UI:CSVImport:ObjectsWereAdded' => '%1$d objektumok hozzáadásra kerültek.',
'UI:CSVImport:ObjectsHadErrors' => '%1$d objkektumok hibásak.',
'UI:Title:CSVImportStep2' => '2. lépés az 5-ből: CSV adat opciók',
'UI:Title:CSVImportStep3' => '3. lépés az 5-ből: Adatok összerendelés',
'UI:Title:CSVImportStep4' => '4. lépés az 5-ből: Import szimuláció',
'UI:Title:CSVImportStep5' => '5. lépés az 5-ből: Import befejezve',
'UI:CSVImport:LinesNotImported' => 'Sorok, melyek nem lettek betöltve:',
'UI:CSVImport:LinesNotImported+' => '',
'UI:CSVImport:SeparatorComma+' => '',
'UI:CSVImport:SeparatorSemicolon+' => '',
'UI:CSVImport:SeparatorTab+' => '',
'UI:CSVImport:SeparatorOther' => 'egyéb:',
'UI:CSVImport:QualifierDoubleQuote+' => '',
'UI:CSVImport:QualifierSimpleQuote+' => '',
'UI:CSVImport:QualifierOther' => 'egyéb:',
'UI:CSVImport:TreatFirstLineAsHeader' => 'Első sor fejléc információkat tartalmaz (oszlopok nevei)',
'UI:CSVImport:Skip_N_LinesAtTheBeginning' => '%1$s sorok kihagyása a fájl elejéről',
'UI:CSVImport:CSVDataPreview' => 'CSV adat előnézet',
'UI:CSVImport:SelectFile' => 'Import fájl kiválasztása:',
'UI:CSVImport:Tab:LoadFromFile' => 'Betöltés fájlból',
'UI:CSVImport:Tab:CopyPaste' => 'Adat másolás és beillesztés',
'UI:CSVImport:Tab:Templates' => 'Sablonok',
'UI:CSVImport:PasteData' => 'Import adatok beillesztése:',
'UI:CSVImport:PickClassForTemplate' => 'Letöltendő sablon kiválasztása:',
'UI:CSVImport:SeparatorCharacter' => 'Elválasztó karakter:',
'UI:CSVImport:TextQualifierCharacter' => 'Szöveg qualifier karakter',
'UI:CSVImport:CommentsAndHeader' => 'Megjegyzések és fejléc',
'UI:CSVImport:SelectClass' => 'Importálandó osztály kiválasztása:',
'UI:CSVImport:AdvancedMode' => 'Haladó mód',
'UI:CSVImport:AdvancedMode+' => '',
'UI:CSVImport:SelectAClassFirst' => 'Adat összerendeléshez elöször válassza ki az osztályt.',
'UI:CSVImport:HeaderFields' => 'Mező',
'UI:CSVImport:HeaderMappings' => 'Összerendelés',
'UI:CSVImport:HeaderSearch' => 'Keresés?',
'UI:CSVImport:AlertIncompleteMapping' => 'Kérem adja meg az összes mezőre az összerendelési szabályokat.',
'UI:CSVImport:AlertNoSearchCriteria' => 'Kérem adjon eg legalább egy keresési kritériumot',
'UI:CSVImport:Encoding' => 'Karakter kódolása',
'UI:UniversalSearchTitle' => 'iTop - Univerzális kereső',
'UI:UniversalSearch:Error' => 'Hiba: %1$s',
'UI:UniversalSearch:LabelSelectTheClass' => 'Keresendő osztály kiválasztása:',
'UI:Audit:Title' => 'iTop - CMDB Audit',
'UI:Audit:InteractiveAudit' => 'Interaktív Audit',
'UI:Audit:HeaderAuditRule' => 'Audit szabály',
'UI:Audit:HeaderNbObjects' => '# Objektumok',
'UI:Audit:HeaderNbErrors' => '# Hibák',
'UI:Audit:PercentageOk' => '% OK',
'UI:RunQuery:Title' => 'iTop - OQL lekérdezés értékelés',
'UI:RunQuery:QueryExamples' => 'Lekérdezés példák',
'UI:RunQuery:HeaderPurpose' => 'Cél',
'UI:RunQuery:HeaderPurpose+' => '',
'UI:RunQuery:HeaderOQLExpression' => 'OQL kifejezés',
'UI:RunQuery:HeaderOQLExpression+' => '',
'UI:RunQuery:ExpressionToEvaluate' => 'Értékelendő kifejezés: ',
'UI:RunQuery:MoreInfo' => 'Több információ a lekérdezésről: ',
'UI:RunQuery:DevelopedQuery' => 'Újraírt lekérdező értékelés: ',
'UI:RunQuery:SerializedFilter' => 'Szerializált szűrő: ',
'UI:RunQuery:Error' => 'A lekérdezés futtatása közben a következő hiba jelentkezett: %1$s',
'UI:Schema:Title' => 'iTop objektum séma',
'UI:Schema:CategoryMenuItem' => '<b>%1$s</b> kategória',
'UI:Schema:Relationships' => 'Kapcsolatok',
'UI:Schema:AbstractClass' => 'Absztrakt osztály: nem példányosítható belőle objektum.',
'UI:Schema:NonAbstractClass' => 'Nem absztrakt osztály: objektum példányosítható belőle.',
'UI:Schema:ClassHierarchyTitle' => 'Osztály hierarchia',
'UI:Schema:AllClasses' => 'Összes osztály',
'UI:Schema:ExternalKey_To' => 'Külső kulcs %1$s-hoz',
'UI:Schema:Columns_Description' => 'Oszlopok: <em>%1$s</em>',
'UI:Schema:Default_Description' => 'Alapértelmezett: "%1$s"',
'UI:Schema:NullAllowed' => 'Null érték engedélyezett',
'UI:Schema:NullNotAllowed' => 'Null érték nem engedélyezett',
'UI:Schema:Attributes' => 'Attribútumok',
'UI:Schema:AttributeCode' => 'Attribútum kód',
'UI:Schema:AttributeCode+' => '',
'UI:Schema:Label' => 'Cimke',
'UI:Schema:Label+' => '',
'UI:Schema:Type' => 'Típus',
'UI:Schema:Type+' => '',
'UI:Schema:Origin' => 'Származás',
'UI:Schema:Origin+' => '',
'UI:Schema:Description' => 'Leírás',
'UI:Schema:Description+' => '',
'UI:Schema:AllowedValues' => 'Engedélyezett értékek',
'UI:Schema:AllowedValues+' => '',
'UI:Schema:MoreInfo' => 'Több információ',
'UI:Schema:MoreInfo+' => '',
'UI:Schema:SearchCriteria' => 'Keresési kritériumok',
'UI:Schema:FilterCode' => 'Szűrő kód',
'UI:Schema:FilterCode+' => '',
'UI:Schema:FilterDescription' => 'Leírás',
'UI:Schema:FilterDescription+' => '',
'UI:Schema:AvailOperators' => 'Elérhető műveletek',
'UI:Schema:AvailOperators+' => '',
'UI:Schema:ChildClasses' => 'Leszármazott osztályok',
'UI:Schema:ReferencingClasses' => 'Referált osztályok',
'UI:Schema:RelatedClasses' => 'Kapcsolódó osztályok',
'UI:Schema:LifeCycle' => 'Életciklus',
'UI:Schema:Triggers' => 'Kiváltó okok',
'UI:Schema:Relation_Code_Description' => 'Kapcsolat <em>%1$s</em> (%2$s)',
'UI:Schema:RelationDown_Description' => 'Lenn: %1$s',
'UI:Schema:RelationUp_Description' => 'Fenn: %1$s',
'UI:Schema:RelationPropagates' => '%1$s: kiterjesztése %2$d szintre, lekérdezés: %3$s',
'UI:Schema:RelationDoesNotPropagate' => '%1$s: nincs kiterjesztve (%2$d szintekre), lekérdezés: %3$s',
'UI:Schema:Class_ReferencingClasses_From_By' => '%1$s hivatkozva %2$s az osztályban %3$s mezőn keresztül',
'UI:Schema:Class_IsLinkedTo_Class_Via_ClassAndAttribute' => '%1$s hozzácsatolva %2$s-hoz %3$s-n keresztül::<em>%4$s</em>',
'UI:Schema:Links:1-n' => 'A következő osztályok mutatnak %1$s-ra (1:n kapcsolat):',
'UI:Schema:Links:n-n' => 'A következő osztályok mutatnak %1$s-ra (n:n kapcsolat):',
'UI:Schema:Links:All' => 'Össze kapcsolódó osztály grafikonja',
'UI:Schema:NoLifeCyle' => 'Nincs életciklus rendelve ehhez az osztályhoz.',
'UI:Schema:LifeCycleTransitions' => 'Átmenetek',
'UI:Schema:LifeCyleAttributeOptions' => 'Attribútum opciók',
'UI:Schema:LifeCycleHiddenAttribute' => 'Rejtett',
'UI:Schema:LifeCycleReadOnlyAttribute' => 'Csak olvasható',
'UI:Schema:LifeCycleMandatoryAttribute' => 'Kötelező',
'UI:Schema:LifeCycleAttributeMustChange' => 'Változtatni kell',
'UI:Schema:LifeCycleAttributeMustPrompt' => 'Felhasználó kéri a változtatását',
'UI:Schema:LifeCycleEmptyList' => 'üres lista',
'UI:LinksWidget:Autocomplete+' => '',
'UI:Combo:SelectValue' => '--- válasszon értéket ---',
'UI:Label:SelectedObjects' => 'Kiválasztott objektumok: ',
'UI:Label:AvailableObjects' => 'Lehetséges objektumok: ',
'UI:Link_Class_Attributes' => '%1$s attribútumai',
'UI:AddObjectsOf_Class_LinkedWith_Class_Instance' => '%1$s objektumok hozzáadása %2$s osztályhoz kapcsolással: %3$s',
'UI:AddObjectsOf_Class_LinkedWith_Class' => '%1$s objektumok hozzáadása %2$s osztályhoz csatolással',
'UI:ManageObjectsOf_Class_LinkedWith_Class_Instance' => '%2$s osztályhoz kapcsolt %1$s objektumok kezelése: %3$s',
'UI:AddLinkedObjectsOf_Class' => 'Hozzáadás %1$s osztályhoz',
'UI:RemoveLinkedObjectsOf_Class' => 'Kiválasztott objektum eltávolítása',
'UI:Message:EmptyList:UseAdd' => 'A lista üres, használja a "Hozzáadás..." gombot az elemekre.',
'UI:Message:EmptyList:UseSearchForm' => 'Használja a kereső formot a hozzáadandó objektumok kiválasztásához.',
'UI:Wizard:FinalStepTitle' => 'Utolsó lépés: megerősítés',
'UI:Title:DeletionOf_Object' => '%1$s törlése',
'UI:Title:BulkDeletionOf_Count_ObjectsOf_Class' => '%2$s osztály %1$d objektumának tömeges törlése',
'UI:Delete:NotAllowedToDelete' => 'Nem enegedélyezett az objektum törlése',
'UI:Delete:NotAllowedToUpdate_Fields' => 'A következő mező módosítása nem engedélyezett: %1$s',
'UI:Error:NotEnoughRightsToDelete' => 'Az objektum nem törölhető, mert a felhasználónak nincs elegendő joga',
'UI:Error:CannotDeleteBecause' => 'Az objektum nem törölhető, mert: %1$s',
'UI:Error:CannotDeleteBecauseOfDepencies' => 'Az objektum nem törölhető, mert néhány hozzá kapcsolódó magasabb prioritású manuális művelet végrehajtásra vár',
'UI:Error:CannotDeleteBecauseManualOpNeeded' => 'Az objektum nem törölhető, mert néhány hozzá kapcsolódó magasabb prioritású manuális művelet végrehajtásra vár',
'UI:Archive_User_OnBehalfOf_User' => '%1$s felhasználó %2$s nevében',
'UI:Delete:Deleted' => 'törölt',
'UI:Delete:AutomaticallyDeleted' => 'automatikusan törölt',
'UI:Delete:AutomaticResetOf_Fields' => ' következő mezők automatikus újratöltése: %1$s',
'UI:Delete:CleaningUpRefencesTo_Object' => 'Összes referencia tisztítása %1$s...',
'UI:Delete:CleaningUpRefencesTo_Several_ObjectsOf_Class' => '%2$s osztály %1$d objektumára mutató referenciák tisztítása',
'UI:Delete:Done+' => '',
'UI:Delete:_Name_Class_Deleted' => '%1$s - %2$s törölve.',
'UI:Delete:ConfirmDeletionOf_Name' => '%1$s törlése',
'UI:Delete:ConfirmDeletionOf_Count_ObjectsOf_Class' => '%2$s osztály %1$d objektumának törlése',
'UI:Delete:CannotDeleteBecause' => 'Sikertelenül töröltek: %1$s',
'UI:Delete:ShouldBeDeletedAtomaticallyButNotPossible' => 'Automatikusan kellett volna törlődniük, de a művelet nem volt végrehajtható: %1$s',
'UI:Delete:MustBeDeletedManuallyButNotPossible' => 'Manuállis törlés nem végrehajtható: %1$s',
'UI:Delete:WillBeDeletedAutomatically' => 'Automatikusan lesznek törölve',
'UI:Delete:MustBeDeletedManually' => 'Manuálisan törlendők',
'UI:Delete:CannotUpdateBecause_Issue' => 'Automatikus frissítés sikeretelen: %1$s',
'UI:Delete:WillAutomaticallyUpdate_Fields' => 'Automatikusan lesznek frissítve (reset: %1$s)',
'UI:Delete:Count_Objects/LinksReferencing_Object' => '%1$d objektumok / kapcsolatok hivatkoznak erre: %2$s',
'UI:Delete:Count_Objects/LinksReferencingTheObjects' => '%1$d objektumok / kapcsolatok hivatkoznak törlendő objektumokra',
'UI:Delete:ReferencesMustBeDeletedToEnsureIntegrity' => 'Adatbázis integritás ellenőrzés szükséges. Néhány hivatkozás megszüntetésre kerül.',
'UI:Delete:Consequence+' => '',
'UI:Delete:SorryDeletionNotAllowed' => 'Az objektum törlése nem engedélyezett. Részletes magyarázat a következő sorokban.',
'UI:Delete:PleaseDoTheManualOperations' => 'Kérem hajtsa végre a következő listában található műveleteket manuálisan az objektum törlésének kéréséhez',
'UI:Delect:Confirm_Object' => 'Kérjük hagyja jóvá a %1$s törlését!',
'UI:Delect:Confirm_Count_ObjectsOf_Class' => 'Kérjük hagyja jóvá a %2$s ostály %1$d objektumának törlését!',
'UI:WelcomeToITop' => 'Üdvözli az iTop',
'UI:DetailsPageTitle' => 'iTop - %1$s - %2$s részletek',
'UI:ErrorPageTitle' => 'iTop - Hiba',
'UI:ObjectDoesNotExist' => 'Sajnálom ez az objektum nem létezik (vagy a megtekintése nem engedélyezett a felhasználó számára).',
'UI:SearchResultsPageTitle' => 'iTop - Keresés eredményei',
'UI:Search:NoSearch' => 'Nincs keresés',
'UI:FullTextSearchTitle_Text' => '"%1$s" keresés eredményei:',
'UI:Search:Count_ObjectsOf_Class_Found' => '%2$s osztály %1$d objektuma',
'UI:Search:NoObjectFound' => 'Objektum nem található',
'UI:ModificationPageTitle_Object_Class' => 'iTop - %1$s - %2$s módosítása',
'UI:ModificationTitle_Class_Object' => '%1$s: <span class=\"hilite\">%2$s</span> módosítása',
'UI:ClonePageTitle_Object_Class' => 'iTop - %1$s - %2$s klón módosítása',
'UI:CloneTitle_Class_Object' => '%1$s: <span class=\"hilite\">%2$s</span> klón',
'UI:CreationPageTitle_Class' => 'iTop - %1$s létrehozása',
'UI:CreationTitle_Class' => '%1$s létrehozása',
'UI:SelectTheTypeOf_Class_ToCreate' => 'Válassza ki a létrehozni kívánt %1$s osztály típusát:',
'UI:Class_Object_NotUpdated' => 'Változás nem történt, %1$s (%2$s) <strong>NEM</strong> lett módosítva.',
'UI:Class_Object_Updated' => '%1$s (%2$s) frissítve.',
'UI:BulkDeletePageTitle' => 'iTop - Tömeges törlés',
'UI:BulkDeleteTitle' => 'Válassza ki a törölni kívánt objektumokat:',
'UI:PageTitle:ObjectCreated' => 'iTop objektum létrehozva.',
'UI:Title:Object_Of_Class_Created' => '%1$s - %2$s létrehozva.',
'UI:Apply_Stimulus_On_Object_In_State_ToTarget_State' => 'Alkalmazva %1$s objektumon: %2$s.Kinduló állapot: %3$s cél állapot: %4$s.',
'UI:ObjectCouldNotBeWritten' => 'Au objektum írása sikertlen: %1$s',
'UI:PageTitle:FatalError' => 'iTop - Fatális hiba',
'UI:SystemIntrusion' => 'Hozzáférés megtagadva. A művelet végrehajtása nem engedélyezett.',
'UI:FatalErrorMessage' => 'Fatális hiba, iTop nem tudja a működését folytatni',
'UI:Error_Details' => 'Hiba: %1$s.',
'UI:PageTitle:ClassProjections' => 'iTop felhasználó menedzsmet - osztály nézet',
'UI:PageTitle:ProfileProjections' => 'iTop felhasználó menedzsmet - profil nézet',
'UI:UserManagement:Class' => 'Osztály',
'UI:UserManagement:Class+' => '',
'UI:UserManagement:ProjectedObject' => 'Objektum',
'UI:UserManagement:ProjectedObject+' => '',
'UI:UserManagement:AnyObject' => '* any *',
'UI:UserManagement:User' => 'Felhasználó',
'UI:UserManagement:User+' => '',
'UI:UserManagement:Profile' => 'Profil',
'UI:UserManagement:Profile+' => '',
'UI:UserManagement:Action:Read' => 'Olvas',
'UI:UserManagement:Action:Read+' => '',
'UI:UserManagement:Action:Modify' => 'Módosít',
'UI:UserManagement:Action:Modify+' => '',
'UI:UserManagement:Action:Delete' => 'Töröl',
'UI:UserManagement:Action:Delete+' => '',
'UI:UserManagement:Action:BulkRead' => 'Tömeges beolvasás (Export)',
'UI:UserManagement:Action:BulkRead+' => '',
'UI:UserManagement:Action:BulkModify' => 'Tömeges módosítás',
'UI:UserManagement:Action:BulkModify+' => '',
'UI:UserManagement:Action:BulkDelete' => 'Tömeges törlés',
'UI:UserManagement:Action:BulkDelete+' => '',
'UI:UserManagement:Action:Stimuli' => 'Stimuli',
'UI:UserManagement:Action:Stimuli+' => '',
'UI:UserManagement:Action' => 'Akció',
'UI:UserManagement:Action+' => '',
'UI:UserManagement:TitleActions' => 'Akciók',
'UI:UserManagement:Permission' => 'Engedély',
'UI:UserManagement:Permission+' => '',
'UI:UserManagement:Attributes' => 'Attribútumok',
'UI:UserManagement:ActionAllowed:Yes' => 'Igen',
'UI:UserManagement:ActionAllowed:No' => 'Nem',
'UI:UserManagement:AdminProfile+' => '',
'UI:UserManagement:NoLifeCycleApplicable' => 'N/A',
'UI:UserManagement:NoLifeCycleApplicable+' => '',
'UI:UserManagement:GrantMatrix' => 'Jogosutlsági mátrix',
'UI:UserManagement:LinkBetween_User_And_Profile' => 'Kapcsolat %1$s és %2$s között',
'UI:UserManagement:LinkBetween_User_And_Org' => 'Kapcsolat %1$s és %2$s között',
'Menu:AdminTools' => 'Adminisztrációs eszközök',
'Menu:AdminTools+' => '',
'Menu:AdminTools?' => 'Eszközök csak az adminisztrátori profilhoz rendlet felhasználók számára elérhetők.',
'UI:ChangeManagementMenu' => 'Változás menedzsment',
'UI:ChangeManagementMenu+' => '',
'UI:ChangeManagementMenu:Title' => 'Változás áttekintése',
'UI-ChangeManagementMenu-ChangesByType' => 'Változások típusok szerint',
'UI-ChangeManagementMenu-ChangesByStatus' => 'Változások státusz szerint',
'UI-ChangeManagementMenu-ChangesByWorkgroup' => 'Változások csoportok szerint',
'UI-ChangeManagementMenu-ChangesNotYetAssigned' => 'Még nem kiosztott változások',
'UI:ConfigurationItemsMenu' => 'Konfigurációs elemek',
'UI:ConfigurationItemsMenu+' => '',
'UI:ConfigurationItemsMenu:Title' => 'Konfigurációs elemek áttekintése',
'UI-ConfigurationItemsMenu-ServersByCriticity' => 'Szerverek kritikusság szerint',
'UI-ConfigurationItemsMenu-PCsByCriticity' => 'PC-k kritikusság szerint',
'UI-ConfigurationItemsMenu-NWDevicesByCriticity' => 'Hálózati eszközök kritikusság szerint',
'UI-ConfigurationItemsMenu-ApplicationsByCriticity' => 'Alkalmazások kritikusság szerint',
'UI:ConfigurationManagementMenu' => 'Konfiguráció menedzsment',
'UI:ConfigurationManagementMenu+' => '',
'UI:ConfigurationManagementMenu:Title' => 'Infrastruktúra áttekintő',
'UI-ConfigurationManagementMenu-InfraByType' => 'Infrastruktúra objetumok típusok szerint',
'UI-ConfigurationManagementMenu-InfraByStatus' => 'Infrastruktúra objetumok státuszok szerint',
'UI:ConfigMgmtMenuOverview:Title' => 'Konfiguráció menedzsment dashboard',
'UI-ConfigMgmtMenuOverview-FunctionalCIbyStatus' => 'Konfigurációs elemek státusz szerint',
'UI-ConfigMgmtMenuOverview-FunctionalCIByType' => 'Konfigurációs elemek típus szerint',
'UI:RequestMgmtMenuOverview:Title' => 'Igény menedzsment dashboard',
'UI-RequestManagementOverview-RequestByService' => 'Felhasználói kérések szolgáltatásonként',
'UI-RequestManagementOverview-RequestByPriority' => 'Felhasználói kérések prioritás szerint',
'UI-RequestManagementOverview-RequestUnassigned' => 'Felhasználói kérések, amelyek még nem lettek felelőshöz rendelve',
'UI:IncidentMgmtMenuOverview:Title' => 'Incidens menedzsment dashboard',
'UI-IncidentManagementOverview-IncidentByService' => 'Incidensek szolgáltatásonként',
'UI-IncidentManagementOverview-IncidentByPriority' => 'Incidensek prioritás szerint',
'UI-IncidentManagementOverview-IncidentUnassigned' => 'Incidensek, amelyek még nem lettek felelőshöz rendelve',
'UI:ChangeMgmtMenuOverview:Title' => 'Változás menedzsment dashboard',
'UI-ChangeManagementOverview-ChangeByType' => 'Változások típusonként',
'UI-ChangeManagementOverview-ChangeUnassigned' => 'Változások, amelyek még nem lettek felelőshöz rendelve',
'UI-ChangeManagementOverview-ChangeWithOutage' => 'Változások által okozott leállási idő',
'UI:ServiceMgmtMenuOverview:Title' => 'Szolgáltatás menedszment dashboard',
'UI-ServiceManagementOverview-CustomerContractToRenew' => 'A következő 30 napban lejáró ügyfél szerződések',
'UI-ServiceManagementOverview-ProviderContractToRenew' => 'A következő 30 napban lejáró szállítói szerződések',
'UI:ContactsMenu' => 'Kapcsolattartók',
'UI:ContactsMenu+' => '',
'UI:ContactsMenu:Title' => 'Kapcsolattartó áttekintő',
'UI-ContactsMenu-ContactsByLocation' => 'Kapcsolattartók földrajzi hely szerint',
'UI-ContactsMenu-ContactsByType' => 'Kapcsolattartók típus szerint',
'UI-ContactsMenu-ContactsByStatus' => 'Kapcsolattartók státusz szerint',
'Menu:CSVImportMenu' => 'CSV import',
'Menu:CSVImportMenu+' => '',
'Menu:DataModelMenu' => 'Adatmodell',
'Menu:DataModelMenu+' => '',
'Menu:ExportMenu' => 'Export',
'Menu:ExportMenu+' => '',
'Menu:NotificationsMenu' => 'Értesítések',
'Menu:NotificationsMenu+' => '',
'UI:NotificationsMenu:Title' => '<span class="hilite">Értesítések</span> beállítása',
'UI:NotificationsMenu:Help' => 'Segítség',
'UI:NotificationsMenu:HelpContent' => '<p>Az iTop alkalmazásban az értesítések teljesen testreszabhatók. Értesítések az objektumok két csoportjára épülnek: <i>kiváltó okok és akciók</i>.</p>
<p><i><b>Kiváltó ok</b></i> határozza meg mikor kell az értesítést végrehajtani. Kiváltó okoknak 2 típusa van az objektum életciklius három fázisának lefedésére:
<ol>
<li>"OnCreate" kiváltó ok egy objektum létrehozása</li>
<li>"OnStateEnter" kiváltó ok egy adott objektum állapot változása - az új objektum állapot elérése előtt váltódik ki</li>
<li>"OnStateLeave" kiváltó ok egy adott objektum állapot változása - az új objektum állapot elhagyása után váltódik ki</li>
</ol>
</p>
<p>
<i><b>Akciók</b></i> határozzák meg mit kell végrehjatani a kiváltó ok bekövetkezésekor. Jelenleg egyetlen akció fajta van: e-mail küldés.Természetesen az egyedi akciókbna meg lehet határozni a levél alapját képző sablont és az abba beépülő speciális paramétereket, pl.: címzett, fontossás, stb.
</p>
<p>Speciális oldal: <a href="../setup/email.test.php" target="_blank">email.test.php</a> oldalon keresztül a PHP mail konfiguráció tesztelhető.</p>
<p>Akció végrehjatásához azt kiváltó okhoz kell rendelni.
Akció kiváltó okhoz rendelésekor kap egy sorszámot , amely meghatározza az akciók végrehatási sorrendjét.</p>',
'UI:NotificationsMenu:Triggers' => 'Kiváltó okok',
'UI:NotificationsMenu:AvailableTriggers' => 'Lehetséges kiváltó okok',
'UI:NotificationsMenu:OnCreate' => 'Objektum létrehozás',
'UI:NotificationsMenu:OnStateEnter' => 'Objketum állapotba való belépése',
'UI:NotificationsMenu:OnStateLeave' => 'Objektum állotból való kilépése',
'UI:NotificationsMenu:Actions' => 'Akciók',
'UI:NotificationsMenu:AvailableActions' => 'Lehetséges akciók',
'Menu:AuditCategories' => 'Audit kategóriák',
'Menu:AuditCategories+' => '',
'Menu:Notifications:Title' => 'Audit kategóriák',
'Menu:RunQueriesMenu' => 'Lekérdezés futtatás',
'Menu:RunQueriesMenu+' => '',
'Menu:DataAdministration' => 'Adat adminisztráció',
'Menu:DataAdministration+' => '',
'Menu:UniversalSearchMenu' => 'Univerzális keresés',
'Menu:UniversalSearchMenu+' => '',
'Menu:ApplicationLogMenu' => 'Alkalmazás napló',
'Menu:ApplicationLogMenu+' => '',
'Menu:ApplicationLogMenu:Title' => 'Alkalmazás napló',
'Menu:UserManagementMenu' => 'Felhasználó menedzsment',
'Menu:UserManagementMenu+' => '',
'Menu:ProfilesMenu' => 'Profilok',
'Menu:ProfilesMenu+' => '',
'Menu:ProfilesMenu:Title' => 'Profilok',
'Menu:UserAccountsMenu' => 'Felhasználói fiókok',
'Menu:UserAccountsMenu+' => '',
'Menu:UserAccountsMenu:Title' => 'Felhasználói fiókok',
'UI:iTopVersion:Short' => 'iTop verzió: %1$s',
'UI:iTopVersion:Long' => 'iTop verzió: %1$s-%2$s %3$s',
'UI:PropertiesTab' => 'Tulajdonságok',
'UI:OpenDocumentInNewWindow_' => 'A követekező dokumentum megnyitása új ablakban: %1$s',
'UI:DownloadDocument_' => 'A következő dokuemntum letöltése: %1$s',
'UI:Document:NoPreview' => 'Nem elérhető előnézet ehhez a dokuemntumhoz',
'UI:DeadlineMissedBy_duration' => 'Elmulsztva %1$s által',
'UI:Deadline_LessThan1Min' => '< 1 perc',
'UI:Deadline_Minutes' => '%1$d perc',
'UI:Deadline_Hours_Minutes' => '%1$dóra %2$dperc',
'UI:Deadline_Days_Hours_Minutes' => '%1$nap %2$dóra %3$dperc',
'UI:Help' => 'Segítség',
'UI:PasswordConfirm' => '(Jóváhagyás)',
'UI:BeforeAdding_Class_ObjectsSaveThisObject' => '%1$s objektumok hozzáadása előtt mentse ezt az objektumot',
'UI:DisplayThisMessageAtStartup' => 'Az üzenet megjelenítése indításkor',
'UI:RelationshipGraph' => 'Grafikus nézet',
'UI:RelationshipList' => 'Lista',
'UI:OperationCancelled' => 'Művelet visszavonva',
'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',
'Portal:SelectSubcategoryFrom_Service' => 'Válassza ki a %1$s szolgáltatás alkategóriáját:',
'Portal:PleaseSelectAServiceSubCategory' => 'Kérem válasszon egy alkategóriát',
'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',
'Portal:AddAttachment' => 'Csatolmány hozzáadása',
'Portal:RemoveAttachment' => 'Csatolmány eltávolítása',
'Portal:Attachment_No_To_Ticket_Name' => 'Csatolmányok: #%1$d a %2$s (%3$s) hibajegyhez',
'Enum:Undefined' => 'Nem meghatározott',
'UI:DurationForm_Days_Hours_Minutes_Seconds' => '%1$s nap %2$s óra %3$s perc %4$s másodperc',
'UI:ModifyAllPageTitle' => 'Összes módosítása',
'UI:Modify_N_ObjectsOf_Class' => '%2$s osztály %1$d objketumainak módosítása',
'UI:Modify_M_ObjectsOf_Class_OutOf_N' => '%2$s osztály %1$d objektumának módosítása, kivéve: %3$d',
'UI:Menu:ModifyAll' => 'Módosítás...',
'UI:Button:ModifyAll' => 'Összes módosítása',
'UI:Button:PreviewModifications' => 'Módosítások előnézete >>',
'UI:ModifiedObject' => 'Objektum módosítva',
'UI:BulkModifyStatus' => 'Művelet',
'UI:BulkModifyStatus+' => '',
'UI:BulkModifyErrors' => 'Hibák (ha vannak)',
'UI:BulkModifyErrors+' => '',
'UI:BulkModifyStatusOk' => 'OK',
'UI:BulkModifyStatusError' => 'Hiba',
'UI:BulkModifyStatusModified' => 'Módosítva',
'UI:BulkModifyStatusSkipped' => 'Átugorva',
'UI:BulkModify_Count_DistinctValues' => '%1$d eltérő értékek:',
'UI:BulkModify:Value_Exists_N_Times' => '%1$s *, %2$d *',
'UI:BulkModify:N_MoreValues' => '%1$d további értékei ...',
'UI:AttemptingToSetAReadOnlyAttribute_Name' => 'Kísérlet a következő csak olvaható mező beállítására: %1$s',
'UI:FailedToApplyStimuli' => 'A művelet sikertelen',
'UI:StimulusModify_N_ObjectsOf_Class' => '%1$s: %3$s osztály %2$d objketumainak módosítása',
'UI:CaseLogTypeYourTextHere' => 'Írjon ide:',
'UI:CaseLog:DateFormat' => 'Y-m-d H:i:s',
'UI:CaseLog:Header_Date_UserName' => '%1$s - %2$s:',
'UI:CaseLog:InitialValue' => 'Kezdeti érték:',
'UI:AttemptingToSetASlaveAttribute_Name' => '%1$s mező nem írható, mert a szinkronizációnál használt kulcs. Érték nem lett beállítva.',
'UI:ActionNotAllowed' => 'Ennek a műveletnek a végrehajtása nem engedélyezett ezen az objektumon.',
'UI:BulkAction:NoObjectSelected' => 'Válasszon ki legalább egy objketumot a művelet végrehajtásához',
'UI:AttemptingToChangeASlaveAttribute_Name' => '%1$s mező nem írható, mert a szinkronizációnál használt kulcs. Érték változatlan maradt.',
'UI:Button:Refresh' => 'Frissítés',
));
?>

View File

@@ -0,0 +1,757 @@
<?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
*/
Dict::Add('IT IT', 'Italian', 'Italiano', array(
'Core:AttributeLinkedSet' => 'Array di oggetti',
'Core:AttributeLinkedSet+' => 'Ogni tipo di oggetto della stessa classe o sottoclasse',
'Core:AttributeLinkedSetIndirect' => 'Array di oggetti (N-N)',
'Core:AttributeLinkedSetIndirect+' => 'ogni tipo di oggetti [sottoclasse] della stessa classe',
'Core:AttributeInteger' => 'Integer',
'Core:AttributeInteger+' => 'Valore numerico (non può essere negativo)',
'Core:AttributeDecimal' => 'Decimal',
'Core:AttributeDecimal+' => 'valore decimale (non può essere negativo)',
'Core:AttributeBoolean' => 'Booleano',
'Core:AttributeBoolean+' => 'Booleano',
'Core:AttributeString' => 'Stringa',
'Core:AttributeString+' => 'Stringa alfanumerica',
'Core:AttributeClass' => 'Classe',
'Core:AttributeClass+' => 'Classe',
'Core:AttributeApplicationLanguage' => 'Lingua Utente',
'Core:AttributeApplicationLanguage+' => 'Lingua e Paese (EN US)',
'Core:AttributeFinalClass' => 'Classe (auto)',
'Core:AttributeFinalClass+' => 'Classe reale dell\'oggetto (automaticamente creata dal core)',
'Core:AttributePassword' => 'Password',
'Core:AttributePassword+' => 'Password per un dispositivo',
'Core:AttributeEncryptedString' => 'Stringa criptata',
'Core:AttributeEncryptedString+' => 'Stringa cripta con una chiave locale',
'Core:AttributeText' => 'Testo',
'Core:AttributeText+' => 'Stringa di caratteri multilinea',
'Core:AttributeHTML' => 'HTML',
'Core:AttributeHTML+' => 'Stringa HTML',
'Core:AttributeEmailAddress' => 'Indirizzo Email',
'Core:AttributeEmailAddress+' => 'Indirizzo Email',
'Core:AttributeIPAddress' => 'Indirizzo IP',
'Core:AttributeIPAddress+' => 'Indirizzo IP',
'Core:AttributeOQL' => 'OQL',
'Core:AttributeOQL+' => 'Espressione Object Query Langage',
'Core:AttributeEnum' => 'Enum',
'Core:AttributeEnum+' => 'Lista di stringe alfanumeriche predefinite',
'Core:AttributeTemplateString' => 'Stringa Template',
'Core:AttributeTemplateString+' => 'Segnaposto contenente stringhe',
'Core:AttributeTemplateText' => 'Testo Template',
'Core:AttributeTemplateText+' => 'Segnaposto contenente testo',
'Core:AttributeTemplateHTML' => 'HTML Template',
'Core:AttributeTemplateHTML+' => 'Segnaposto contenente HTML',
'Core:AttributeDateTime' => 'Data/ora',
'Core:AttributeDateTime+' => 'Data e ora (anno-mese-giorno hh:mm:ss)',
'Core:AttributeDateTime?SmartSearch' => '
<p>
Formato data:<br/>
<b>aaaa-mm-gg hh:mm:ss</b><br/>
Esempio: 2011-07-19 18:40:00
</p>
<p>
Operatori:<br/>
<b>&gt;</b><em>data</em><br/>
<b>&lt;</b><em>data</em><br/>
<b>[</b><em>data</em>,<em>data</em><b>]</b>
</p>
<p>
Se \'oraè omessa, di default è 00:00:00
</p>',
'Core:AttributeDate' => 'Data',
'Core:AttributeDate+' => 'Data (anno-mese-giorno)',
'Core:AttributeDate?SmartSearch' => '
<p>
Formato data:<br/>
<b>aaaa-mm-gg</b><br/>
Esempio: 2011-07-19
</p>
<p>
Operatori:<br/>
<b>&gt;</b><em>data</em><br/>
<b>&lt;</b><em>data</em><br/>
<b>[</b><em>data</em>,<em>data</em><b>]</b>
</p>',
'Core:AttributeDeadline' => 'Scadenza',
'Core:AttributeDeadline+' => 'Data visualizza relativa al tempo attuale',
'Core:AttributeExternalKey' => 'Chiave esterna',
'Core:AttributeExternalKey+' => 'Chiave esterna (o straniera)',
'Core:AttributeExternalField' => 'Campo esterno',
'Core:AttributeExternalField+' => 'Campo mappato con una chiave esterna',
'Core:AttributeURL' => 'URL',
'Core:AttributeURL+' => 'URL assoluto o relativo, come una stringa di testo',
'Core:AttributeBlob' => 'Blob',
'Core:AttributeBlob+' => 'Ogni contenuto binario (documento)',
'Core:AttributeOneWayPassword' => 'Password a senso unico',
'Core:AttributeOneWayPassword+' => 'Password criptata (hashed) a senso unico',
'Core:AttributeTable' => 'Tabella',
'Core:AttributeTable+' => 'Array indicizzato a due dimensioni',
'Core:AttributePropertySet' => 'Proprietà',
'Core:AttributePropertySet+' => 'Elenco delle proprietà non tipizzati (nome and valore)',
'Core:AttributeFriendlyName' => 'Friendly name',
'Core:AttributeFriendlyName+' => 'Attributo creato automaticamente, il nome descrittivo viene calcolato dopo diversi attributi',
'Core:FriendlyName-Label' => 'Nome',
'Core:FriendlyName-Description' => 'Friendly name',
));
//////////////////////////////////////////////////////////////////////
// Classes in 'core/cmdb'
//////////////////////////////////////////////////////////////////////
//
//
// Class: CMDBChange
//
Dict::Add('IT IT', 'Italian', 'Italiano', array(
'Class:CMDBChange' => 'Cambio',
'Class:CMDBChange+' => 'Rilevamento delle modifiche',
'Class:CMDBChange/Attribute:date' => 'data',
'Class:CMDBChange/Attribute:date+' => 'data e l\'ora in cui i cambiamenti sono stati registrati',
'Class:CMDBChange/Attribute:userinfo' => 'misc. info',
'Class:CMDBChange/Attribute:userinfo+' => 'informazioni definite dal richiedente',
));
//
// Class: CMDBChangeOp
//
Dict::Add('IT IT', 'Italian', 'Italiano', array(
'Class:CMDBChangeOp' => 'Operazione di cambio',
'Class:CMDBChangeOp+' => 'Rilevamento delle operazioni di cambio',
'Class:CMDBChangeOp/Attribute:change' => 'cambio',
'Class:CMDBChangeOp/Attribute:change+' => 'cambio',
'Class:CMDBChangeOp/Attribute:date' => 'data',
'Class:CMDBChangeOp/Attribute:date+' => 'data e ora del cambio',
'Class:CMDBChangeOp/Attribute:userinfo' => 'utente',
'Class:CMDBChangeOp/Attribute:userinfo+' => 'chi ha fatto questo cambio',
'Class:CMDBChangeOp/Attribute:objclass' => 'classe oggetto',
'Class:CMDBChangeOp/Attribute:objclass+' => 'classe oggetto',
'Class:CMDBChangeOp/Attribute:objkey' => 'oggetto id',
'Class:CMDBChangeOp/Attribute:objkey+' => 'ooggetto id',
'Class:CMDBChangeOp/Attribute:finalclass' => 'tipo',
'Class:CMDBChangeOp/Attribute:finalclass+' => '',
));
//
// Class: CMDBChangeOpCreate
//
Dict::Add('IT IT', 'Italian', 'Italiano', array(
'Class:CMDBChangeOpCreate' => 'creazione oggetto',
'Class:CMDBChangeOpCreate+' => 'Rilevamento creazione oggetto',
));
//
// Class: CMDBChangeOpDelete
//
Dict::Add('IT IT', 'Italian', 'Italiano', array(
'Class:CMDBChangeOpDelete' => 'cancellazione oggetto',
'Class:CMDBChangeOpDelete+' => 'Rilevamento cancellazione oggetto',
));
//
// Class: CMDBChangeOpSetAttribute
//
Dict::Add('IT IT', 'Italian', 'Italiano', array(
'Class:CMDBChangeOpSetAttribute' => 'cambio oggetto',
'Class:CMDBChangeOpSetAttribute+' => 'Rilevamento modifiche delle proprietà dell\'oggetto',
'Class:CMDBChangeOpSetAttribute/Attribute:attcode' => 'Attributo',
'Class:CMDBChangeOpSetAttribute/Attribute:attcode+' => 'ccodice della proprietà modificata',
));
//
// Class: CMDBChangeOpSetAttributeScalar
//
Dict::Add('IT IT', 'Italian', 'Italiano', array(
'Class:CMDBChangeOpSetAttributeScalar' => 'proprietà cambio',
'Class:CMDBChangeOpSetAttributeScalar+' => 'Rilevamento delle modifiche delle proprietà scalari dell\'oggetto',
'Class:CMDBChangeOpSetAttributeScalar/Attribute:oldvalue' => 'Valore precedente',
'Class:CMDBChangeOpSetAttributeScalar/Attribute:oldvalue+' => 'valore precedente dell\'attributo',
'Class:CMDBChangeOpSetAttributeScalar/Attribute:newvalue' => 'Nuovo valore',
'Class:CMDBChangeOpSetAttributeScalar/Attribute:newvalue+' => 'nuovo valore dell\'attributo',
));
// Used by CMDBChangeOp... & derived classes
Dict::Add('IT IT', 'Italian', 'Italiano', array(
'Change:ObjectCreated' => 'Oggetto creato',
'Change:ObjectDeleted' => 'Oggetto cancellato',
'Change:ObjectModified' => 'Oggetto modificato',
'Change:AttName_SetTo_NewValue_PreviousValue_OldValue' => '%1$s settato a %2$s (valore precedente: %3$s)',
'Change:AttName_SetTo' => '%1$s settato a %2$s',
'Change:Text_AppendedTo_AttName' => '%1$s allegato a %2$s',
'Change:AttName_Changed_PreviousValue_OldValue' => '%1$s modificato, valore precedente: %2$s',
'Change:AttName_Changed' => '%1$s modificato',
'Change:AttName_EntryAdded' => '%1$s modificato, nuova voce aggiunta.',
));
//
// Class: CMDBChangeOpSetAttributeBlob
//
Dict::Add('IT IT', 'Italian', 'Italiano', array(
'Class:CMDBChangeOpSetAttributeBlob' => 'dati del cambio',
'Class:CMDBChangeOpSetAttributeBlob+' => 'rilevamento dati del cambio',
'Class:CMDBChangeOpSetAttributeBlob/Attribute:prevdata' => 'Dati precedente',
'Class:CMDBChangeOpSetAttributeBlob/Attribute:prevdata+' => 'contenuto precedente dell\'attributo',
));
//
// Class: CMDBChangeOpSetAttributeText
//
Dict::Add('IT IT', 'Italian', 'Italiano', array(
'Class:CMDBChangeOpSetAttributeText' => 'cambio testo',
'Class:CMDBChangeOpSetAttributeText+' => 'rilevamento cambio testo',
'Class:CMDBChangeOpSetAttributeText/Attribute:prevdata' => 'Dati precendenti',
'Class:CMDBChangeOpSetAttributeText/Attribute:prevdata+' => 'contenuto precedente dell\'attributo',
));
//
// Class: Event
//
Dict::Add('IT IT', 'Italian', 'Italiano', array(
'Class:Event' => 'Log Evento',
'Class:Event+' => 'Un\'applicazione evento interno',
'Class:Event/Attribute:message' => 'Messagio',
'Class:Event/Attribute:message+' => 'breve descrizione dell\'evento',
'Class:Event/Attribute:date' => 'Data',
'Class:Event/Attribute:date+' => 'data e ora a cui in cambio è stato registrato',
'Class:Event/Attribute:userinfo' => 'Info Utente',
'Class:Event/Attribute:userinfo+' => 'l\'identificazione dell\'utente che stava facendo l\'azione che ha attivato questo evento',
'Class:Event/Attribute:finalclass' => 'Tipo',
'Class:Event/Attribute:finalclass+' => '',
));
//
// Class: EventNotification
//
Dict::Add('IT IT', 'Italian', 'Italiano', array(
'Class:EventNotification' => 'Notifica dell\'evento',
'Class:EventNotification+' => 'Traccia di una notifica che è stato inviato',
'Class:EventNotification/Attribute:trigger_id' => 'Trigger',
'Class:EventNotification/Attribute:trigger_id+' => 'account utente',
'Class:EventNotification/Attribute:action_id' => 'utente',
'Class:EventNotification/Attribute:action_id+' => 'account utente',
'Class:EventNotification/Attribute:object_id' => 'Id oggetto',
'Class:EventNotification/Attribute:object_id+' => 'Id oggetto (classe definita dal trigger ?)',
));
//
// Class: EventNotificationEmail
//
Dict::Add('IT IT', 'Italian', 'Italiano', array(
'Class:EventNotificationEmail' => 'Emissione evento Email',
'Class:EventNotificationEmail+' => 'Traccia di una e-mail che è stato inviata',
'Class:EventNotificationEmail/Attribute:to' => 'A',
'Class:EventNotificationEmail/Attribute:to+' => 'A',
'Class:EventNotificationEmail/Attribute:cc' => 'CC',
'Class:EventNotificationEmail/Attribute:cc+' => 'CC',
'Class:EventNotificationEmail/Attribute:bcc' => 'BCC',
'Class:EventNotificationEmail/Attribute:bcc+' => 'BCC',
'Class:EventNotificationEmail/Attribute:from' => 'Da',
'Class:EventNotificationEmail/Attribute:from+' => 'Mittente del messaggio',
'Class:EventNotificationEmail/Attribute:subject' => 'Oggetto',
'Class:EventNotificationEmail/Attribute:subject+' => 'Oggetto',
'Class:EventNotificationEmail/Attribute:body' => 'Corpo',
'Class:EventNotificationEmail/Attribute:body+' => 'Corpo',
));
//
// Class: EventIssue
//
Dict::Add('IT IT', 'Italian', 'Italiano', array(
'Class:EventIssue' => 'Evento Problematico',
'Class:EventIssue+' => 'Traccia di un problema (avviso, errore, etc)',
'Class:EventIssue/Attribute:issue' => 'Problema',
'Class:EventIssue/Attribute:issue+' => 'Cosa è successo',
'Class:EventIssue/Attribute:impact' => 'Impatto',
'Class:EventIssue/Attribute:impact+' => 'Quali sono le conseguenze',
'Class:EventIssue/Attribute:page' => 'Pagina',
'Class:EventIssue/Attribute:page+' => 'Punto di ingresso HTTP',
'Class:EventIssue/Attribute:arguments_post' => 'Argomenti inviati',
'Class:EventIssue/Attribute:arguments_post+' => 'Argomenti POST HTTP',
'Class:EventIssue/Attribute:arguments_get' => 'Argomenti URL',
'Class:EventIssue/Attribute:arguments_get+' => 'Argomenti GET HTTP',
'Class:EventIssue/Attribute:callstack' => 'Pila di chiamate',
'Class:EventIssue/Attribute:callstack+' => 'Pila di chiamate',
'Class:EventIssue/Attribute:data' => 'Dati',
'Class:EventIssue/Attribute:data+' => 'Informazioni aggiuntive',
));
//
// Class: EventWebService
//
Dict::Add('IT IT', 'Italian', 'Italiano', array(
'Class:EventWebService' => 'Evento di servizio web',
'Class:EventWebService+' => 'Traccia di una chiamata di servizio web',
'Class:EventWebService/Attribute:verb' => 'Verbo',
'Class:EventWebService/Attribute:verb+' => 'Nome dell\'operazione',
'Class:EventWebService/Attribute:result' => 'Risultato',
'Class:EventWebService/Attribute:result+' => 'In generale successo/insuccesso',
'Class:EventWebService/Attribute:log_info' => 'Info log',
'Class:EventWebService/Attribute:log_info+' => 'Risultati info log',
'Class:EventWebService/Attribute:log_warning' => 'Warning log',
'Class:EventWebService/Attribute:log_warning+' => 'Risultati warning log',
'Class:EventWebService/Attribute:log_error' => 'Error log',
'Class:EventWebService/Attribute:log_error+' => 'Risultati error log',
'Class:EventWebService/Attribute:data' => 'Dati',
'Class:EventWebService/Attribute:data+' => 'Risultati dei dati',
));
//
// Class: EventLoginUsage
//
Dict::Add('IT IT', 'Italian', 'Italiano', array(
'Class:EventLoginUsage' => 'Uso Login',
'Class:EventLoginUsage+' => 'Connessione all\'applicazione',
'Class:EventLoginUsage/Attribute:user_id' => 'Login',
'Class:EventLoginUsage/Attribute:user_id+' => 'Login',
'Class:EventLoginUsage/Attribute:contact_name' => 'User Name',
'Class:EventLoginUsage/Attribute:contact_name+' => 'User Name',
'Class:EventLoginUsage/Attribute:contact_email' => 'User Email',
'Class:EventLoginUsage/Attribute:contact_email+' => 'Indirizzo email dell\'utente',
));
//
// Class: Action
//
Dict::Add('IT IT', 'Italian', 'Italiano', array(
'Class:Action' => 'Azione personalizzata',
'Class:Action+' => 'Azione definita dall\'utente',
'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+' => 'In produzione o ?',
'Class:Action/Attribute:status/Value:test' => 'In fase di test',
'Class:Action/Attribute:status/Value:test+' => 'In fase di test',
'Class:Action/Attribute:status/Value:enabled' => 'In produzione',
'Class:Action/Attribute:status/Value:enabled+' => 'In produzione',
'Class:Action/Attribute:status/Value:disabled' => 'Inattivo',
'Class:Action/Attribute:status/Value:disabled+' => 'Inattivo',
'Class:Action/Attribute:trigger_list' => 'Triggers correlati',
'Class:Action/Attribute:trigger_list+' => 'Triggers colleagati a questa azione',
'Class:Action/Attribute:finalclass' => 'Tipo',
'Class:Action/Attribute:finalclass+' => '',
));
//
// Class: ActionNotification
//
Dict::Add('IT IT', 'Italian', 'Italiano', array(
'Class:ActionNotification' => 'Notifica',
'Class:ActionNotification+' => 'Notifica (sommario)',
));
//
// Class: ActionEmail
//
Dict::Add('IT IT', 'Italian', 'Italiano', array(
'Class:ActionEmail' => 'Email 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+' => 'Destinatario dell\'email',
'Class:ActionEmail/Attribute:cc' => 'Cc',
'Class:ActionEmail/Attribute:cc+' => 'Copia Carbone',
'Class:ActionEmail/Attribute:bcc' => 'BCC',
'Class:ActionEmail/Attribute:bcc+' => 'Copia Carbone Nascosta',
'Class:ActionEmail/Attribute:subject' => 'Oggetto',
'Class:ActionEmail/Attribute:subject+' => 'Titolo dell\'email',
'Class:ActionEmail/Attribute:body' => 'corpo',
'Class:ActionEmail/Attribute:body+' => 'Contenuto dell\'email',
'Class:ActionEmail/Attribute:importance' => 'Priorità',
'Class:ActionEmail/Attribute:importance+' => 'Priorità',
'Class:ActionEmail/Attribute:importance/Value:low' => 'bassa',
'Class:ActionEmail/Attribute:importance/Value:low+' => 'bassa',
'Class:ActionEmail/Attribute:importance/Value:normal' => 'normale',
'Class:ActionEmail/Attribute:importance/Value:normal+' => 'normale',
'Class:ActionEmail/Attribute:importance/Value:high' => 'alta',
'Class:ActionEmail/Attribute:importance/Value:high+' => 'alta',
));
//
// Class: Trigger
//
Dict::Add('IT IT', 'Italian', 'Italiano', array(
'Class:Trigger' => 'Trigger',
'Class:Trigger+' => 'Gestore di eventi personalizzati',
'Class:Trigger/Attribute:description' => 'Descrizione',
'Class:Trigger/Attribute:description+' => 'una linea di descrizione',
'Class:Trigger/Attribute:action_list' => 'Azioni triggerate',
'Class:Trigger/Attribute:action_list+' => 'Azioni eseguite quando il trigger viene attivato ',
'Class:Trigger/Attribute:finalclass' => 'Tipo',
'Class:Trigger/Attribute:finalclass+' => '',
));
//
// Class: TriggerOnObject
//
Dict::Add('IT IT', 'Italian', 'Italiano', array(
'Class:TriggerOnObject' => 'Trigger (classe dipendente)',
'Class:TriggerOnObject+' => 'Trigger su una determinata classe di oggetti',
'Class:TriggerOnObject/Attribute:target_class' => 'Classe Bersaglio',
'Class:TriggerOnObject/Attribute:target_class+' => '',
));
//
// Class: TriggerOnPortalUpdate
//
Dict::Add('IT IT', 'Italian', 'Italiano', array(
'Class:TriggerOnPortalUpdate' => 'Trigger (dopo l\'aggiornamento dal portale )',
'Class:TriggerOnPortalUpdate+' => 'Trigger sull\'aggiornamento dell\'utente dal portale',
));
//
// Class: TriggerOnStateChange
//
Dict::Add('IT IT', 'Italian', 'Italiano', array(
'Class:TriggerOnStateChange' => 'Trigger (su cambio stato)',
'Class:TriggerOnStateChange+' => 'Trigger su cambio stato di un oggetto',
'Class:TriggerOnStateChange/Attribute:state' => 'Stato',
'Class:TriggerOnStateChange/Attribute:state+' => '',
));
//
// Class: TriggerOnStateEnter
//
Dict::Add('IT IT', 'Italian', 'Italiano', array(
'Class:TriggerOnStateEnter' => 'Trigger (all\'entrata di uno stato)',
'Class:TriggerOnStateEnter+' => 'Trigger su cambio stato di un oggetto - entrata',
));
//
// Class: TriggerOnStateLeave
//
Dict::Add('IT IT', 'Italian', 'Italiano', array(
'Class:TriggerOnStateLeave' => 'Trigger (all\'uscita di uno stato)',
'Class:TriggerOnStateLeave+' => 'Trigger su cambio stato di un oggetto - uscita',
));
//
// Class: TriggerOnObjectCreate
//
Dict::Add('IT IT', 'Italian', 'Italiano', array(
'Class:TriggerOnObjectCreate' => 'Trigger (sulla creazione)',
'Class:TriggerOnObjectCreate+' => 'Trigger sulla creazione di un oggetto [una classe figlia di] di una data classe',
));
//
// Class: lnkTriggerAction
//
Dict::Add('IT IT', 'Italian', 'Italiano', array(
'Class:lnkTriggerAction' => 'Azione/Trigger',
'Class:lnkTriggerAction+' => 'Collegamento tra trigger e azione',
'Class:lnkTriggerAction/Attribute:action_id' => 'Azione',
'Class:lnkTriggerAction/Attribute:action_id+' => 'Azione da eseguire',
'Class:lnkTriggerAction/Attribute:action_name' => 'Azione',
'Class:lnkTriggerAction/Attribute:action_name+' => '',
'Class:lnkTriggerAction/Attribute:trigger_id' => 'Trigger',
'Class:lnkTriggerAction/Attribute:trigger_id+' => '',
'Class:lnkTriggerAction/Attribute:trigger_name' => 'Trigger',
'Class:lnkTriggerAction/Attribute:trigger_name+' => '',
'Class:lnkTriggerAction/Attribute:order' => 'Ordine',
'Class:lnkTriggerAction/Attribute:order+' => 'Ordine di esecuzione delle azioni',
));
//
// Synchro Data Source
//
Dict::Add('IT IT', 'Italian', 'Italiano', array(
'Class:SynchroDataSource/Attribute:name' => 'Nome',
'Class:SynchroDataSource/Attribute:name+' => 'Nome',
'Class:SynchroDataSource/Attribute:description' => 'Descrizione',
'Class:SynchroDataSource/Attribute:status' => 'Stato', //TODO: enum values
'Class:SynchroDataSource/Attribute:scope_class' => 'Classe bersaglio',
'Class:SynchroDataSource/Attribute:user_id' => 'Utente',
'Class:SynchroDataSource/Attribute:notify_contact_id' => 'Contatto a cui notificare',
'Class:SynchroDataSource/Attribute:notify_contact_id+' => 'Contatto a cui notificare in caso di errore ',
'Class:SynchroDataSource/Attribute:url_icon' => 'Icona del collegamento ipertestuale',
'Class:SynchroDataSource/Attribute:url_icon+' => 'Una (piccola) immagine del collegamento ipertestuale che rappresenta l\'applicazione con cui è sincronizzato QiTop',
'Class:SynchroDataSource/Attribute:url_application' => 'Collegamento ipertestuale all\'applicazione',
'Class:SynchroDataSource/Attribute:url_application+' => 'Collegamento ipertestuale all\'oggetto ITOP nell\'applicazione esterna con la quale QiTop è sincronizzato (se applicabile). Possibili segnaposto: $this->attribute$ e $replica->primary_key$',
'Class:SynchroDataSource/Attribute:reconciliation_policy' => 'Policy di riconciliazione', //TODO enum values
'Class:SynchroDataSource/Attribute:full_load_periodicity' => 'Intervallo di pieno carico',
'Class:SynchroDataSource/Attribute:full_load_periodicity+' => 'Una ricarica completa di tutti i dati deve verificarsi almeno come specificato qui',
'Class:SynchroDataSource/Attribute:action_on_zero' => 'Azione su zero',
'Class:SynchroDataSource/Attribute:action_on_zero+' => 'Azione da eseguire quando la ricerca non restituisce alcun oggetto',
'Class:SynchroDataSource/Attribute:action_on_one' => 'Azione su uno',
'Class:SynchroDataSource/Attribute:action_on_one+' => 'Azione da eseguire quando la ricerca restituisce esattamente un oggetto',
'Class:SynchroDataSource/Attribute:action_on_multiple' => 'Azione su molti',
'Class:SynchroDataSource/Attribute:action_on_multiple+' => 'Azione da eseguire quando la ricerca restituisce più di un oggetto',
'Class:SynchroDataSource/Attribute:user_delete_policy' => 'Utenti autorizati',
'Class:SynchroDataSource/Attribute:user_delete_policy+' => 'Chi è autorizato a cancellare gli oggetti sincronizzati',
'Class:SynchroDataSource/Attribute:user_delete_policy' => 'Utenti autorizati',
'Class:SynchroDataSource/Attribute:delete_policy/Value:never' => 'Nessuno',
'Class:SynchroDataSource/Attribute:delete_policy/Value:depends' => 'Solo l\'amministratore',
'Class:SynchroDataSource/Attribute:delete_policy/Value:always' => 'Tutti gli utenti sono autorizzati',
'Class:SynchroDataSource/Attribute:delete_policy_update' => 'Regole per l\'aggiornamento',
'Class:SynchroDataSource/Attribute:delete_policy_update+' => 'Sintassi: nome_del_campo:valore; ...',
'Class:SynchroDataSource/Attribute:delete_policy_retention' => 'Durata della conservazione',
'Class:SynchroDataSource/Attribute:delete_policy_retention+' => 'Quanto tempo un oggetto obsoleto è tenuto prima di essere eliminato',
'SynchroDataSource:Description' => 'Descrizione',
'SynchroDataSource:Reconciliation' => 'Ricerca &amp; reconciliazione',
'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' => 'Riconciliato',
'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:Synchro:History' => 'Storia della sincronizzazione',
'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+' => 'Campo dell\'oggetto',
'Core:SynchroAtt:reconciliation' => 'Riconciliazione ?',
'Core:SynchroAtt:reconciliation+' => 'Usato per la ricerca',
'Core:SynchroAtt:update' => 'Aggiornamento ?',
'Core:SynchroAtt:update+' => 'Usato per aggiornare l\'oggetto',
'Core:SynchroAtt:update_policy' => 'Policy di aggiornamento',
'Core:SynchroAtt:update_policy+' => 'Comportamento del campo aggiornato',
'Core:SynchroAtt:reconciliation_attcode' => 'Chiave di riconciliazione',
'Core:SynchroAtt:reconciliation_attcode+' => 'Codice attributo per la chiave esterna di riconciliazione',
'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:SyncSplitModeCLIOnly' => 'La sincronizzazione può essere eseguita in blocchi solo se eseguito in modalità CLI',
'Core:Synchro:ListReplicas_AllReplicas_Errors_Warnings' => '%1$s repliche, %2$s errore(i), %3$s warning(s).',
'Core:SynchroReplica:TargetObject' => 'Oggetto Sincronizzato: %1$s',
'Class:AsyncSendEmail' => 'Email (asincrono)',
'Class:AsyncSendEmail/Attribute:to' => 'A',
'Class:AsyncSendEmail/Attribute:subject' => 'Oggetto',
'Class:AsyncSendEmail/Attribute:body' => 'Corpo',
'Class:AsyncSendEmail/Attribute:header' => 'Intestazione',
'Class:CMDBChangeOpSetAttributeOneWayPassword' => 'Password criptata',
'Class:CMDBChangeOpSetAttributeOneWayPassword/Attribute:prev_pwd' => 'Valore Precedente',
'Class:CMDBChangeOpSetAttributeEncrypted' => 'Campo criptato',
'Class:CMDBChangeOpSetAttributeEncrypted/Attribute:prevstring' => 'Valore Precedente',
'Class:CMDBChangeOpSetAttributeCaseLog' => 'Log della casistica',
'Class:CMDBChangeOpSetAttributeCaseLog/Attribute:lastentry' => 'Ultima voce',
'Class:SynchroDataSource' => 'Sorgente sincronizzazione dati',
'Class:SynchroDataSource/Attribute:status/Value:implementation' => 'Implementazione',
'Class:SynchroDataSource/Attribute:status/Value:obsolete' => 'Obsoleto',
'Class:SynchroDataSource/Attribute:status/Value:production' => 'Produzione',
'Class:SynchroDataSource/Attribute:scope_restriction' => 'Campo di restrizione',
'Class:SynchroDataSource/Attribute:reconciliation_policy/Value:use_attributes' => 'Utilizzare gli attributi',
'Class:SynchroDataSource/Attribute:reconciliation_policy/Value:use_primary_key' => 'Utilizzare il campo della chiave primaria',
'Class:SynchroDataSource/Attribute:action_on_zero/Value:create' => 'Crea',
'Class:SynchroDataSource/Attribute:action_on_zero/Value:error' => 'Errore',
'Class:SynchroDataSource/Attribute:action_on_one/Value:error' => 'Errore',
'Class:SynchroDataSource/Attribute:action_on_one/Value:update' => 'Aggiornamento',
'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' => 'Prendi il primo (casualmente?)',
'Class:SynchroDataSource/Attribute:delete_policy' => 'Policy di cancellazione',
'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:attribute_list' => 'Lista degli attributi',
'Class:SynchroDataSource/Attribute:user_delete_policy/Value:administrators' => 'Solo Amministratore',
'Class:SynchroDataSource/Attribute:user_delete_policy/Value:everybody' => 'Tutti sono autorizzati a cancellare gli oggetti',
'Class:SynchroDataSource/Attribute:user_delete_policy/Value:nobody' => 'Nessuno',
'Class:SynchroAttribute' => 'Attributo di sincronizzazione',
'Class:SynchroAttribute/Attribute:sync_source_id' => 'Sorgente dati per la sincronizzazione',
'Class:SynchroAttribute/Attribute:attcode' => 'Codice Attributo',
'Class:SynchroAttribute/Attribute:update' => 'Aggiorna',
'Class:SynchroAttribute/Attribute:reconcile' => 'Riconcilia',
'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 riga',
'Class:SynchroAttLinkSet/Attribute:attribute_separator' => 'Attributi separatori',
'Class:SynchroLog' => 'Sincro Log',
'Class:SynchroLog/Attribute:sync_source_id' => 'Sorgente dati per la sincronizzazione',
'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' => 'N. di replica viste',
'Class:SynchroLog/Attribute:stats_nb_replica_total' => 'N. di replica totali',
'Class:SynchroLog/Attribute:stats_nb_obj_deleted' => 'N. di oggetti cancellati',
'Class:SynchroLog/Attribute:stats_nb_obj_deleted_errors' => 'N. di errori durante l\'eliminazione',
'Class:SynchroLog/Attribute:stats_nb_obj_obsoleted' => 'N. di oggetti obsoleti',
'Class:SynchroLog/Attribute:stats_nb_obj_obsoleted_errors' => 'N. di errori durante l\'invecchiamento',
'Class:SynchroLog/Attribute:stats_nb_obj_created' => 'N. di oggetti creati',
'Class:SynchroLog/Attribute:stats_nb_obj_created_errors' => 'N. di errori durante la creazione',
'Class:SynchroLog/Attribute:stats_nb_obj_updated' => 'N. di oggetti aggiornati',
'Class:SynchroLog/Attribute:stats_nb_obj_updated_errors' => 'N. di errori durante l\'aggiornamento',
'Class:SynchroLog/Attribute:stats_nb_replica_reconciled_errors' => 'N. di errori durante la riconcilazione',
'Class:SynchroLog/Attribute:stats_nb_replica_disappeared_no_action' => 'N. di repliche scomparse',
'Class:SynchroLog/Attribute:stats_nb_obj_new_updated' => 'N. di oggetti aggiornati',
'Class:SynchroLog/Attribute:stats_nb_obj_new_unchanged' => 'N. di oggetti non modificati',
'Class:SynchroLog/Attribute:last_error' => 'Ultimo eroore',
'Class:SynchroLog/Attribute:traces' => 'Tracce',
'Class:SynchroReplica' => 'Synchro Replica',
'Class:SynchroReplica/Attribute:sync_source_id' => 'Sorgente dati per la sincronizzazione',
'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' => 'Utimo errore',
'Class:SynchroReplica/Attribute:status_last_warning' => 'Warnings',
'Class:SynchroReplica/Attribute:info_creation_date' => 'Data di creazione',
'Class:SynchroReplica/Attribute:info_last_modified' => 'Data di ultima modifica',
'Class:appUserPreferences' => 'Preferenze utente',
'Class:appUserPreferences/Attribute:userid' => 'Utente',
'Class:appUserPreferences/Attribute:preferences' => 'Prefs',
'Core:ExecProcess:Code1' => 'Comando errato o comando finito con errori (es. errato nome dello script)',
'Core:ExecProcess:Code255' => 'PHP Error (parsing, or runtime)',
));
//
// Attribute Duration
//
Dict::Add('IT IT', 'Italian', 'Italiano', array(
'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',
));
?>

View File

@@ -0,0 +1,913 @@
<?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
*/
//////////////////////////////////////////////////////////////////////
// Classes in 'gui'
//////////////////////////////////////////////////////////////////////
//
//////////////////////////////////////////////////////////////////////
// Classes in 'application'
//////////////////////////////////////////////////////////////////////
//
//
// Class: AuditCategory
//
Dict::Add('IT IT', 'Italian', 'Italiano', array(
'Class:AuditCategory' => 'Categoria di Audit',
'Class:AuditCategory+' => 'Una sezione all\'interno del controllo globale',
'Class:AuditCategory/Attribute:name' => 'Nome della categoria',
'Class:AuditCategory/Attribute:name+' => 'Abbreviazione per questa categoria',
'Class:AuditCategory/Attribute:description' => 'Descrizione della categoria di Audit',
'Class:AuditCategory/Attribute:description+' => 'Descrizione dettagliata della categoria di audit',
'Class:AuditCategory/Attribute:definition_set' => 'Insieme di definizione',
'Class:AuditCategory/Attribute:definition_set+' => 'Espressione OQLche definisce l\'insieme di oggetti da controllare',
'Class:AuditCategory/Attribute:rules_list' => 'Regole di Audit',
'Class:AuditCategory/Attribute:rules_list+' => 'Regolele di audit per queste categorie',
));
//
// Class: AuditRule
//
Dict::Add('IT IT', 'Italian', 'Italiano', array(
'Class:AuditRule' => 'Regola di Audit',
'Class:AuditRule+' => '',
'Class:AuditRule/Attribute:name' => 'Nome della regola',
'Class:AuditRule/Attribute:name+' => '',
'Class:AuditRule/Attribute:description' => 'Descrizione della regola di Audit',
'Class:AuditRule/Attribute:description+' => 'Descrizione dettagliata per questa regola di audit ',
'Class:AuditRule/Attribute:query' => 'Query da eseguire',
'Class:AuditRule/Attribute:query+' => 'Espressio OQL da eseguire',
'Class:AuditRule/Attribute:valid_flag' => 'Oggetti validi?',
'Class:AuditRule/Attribute:valid_flag+' => 'Vero se la regola ritorna oggetti validi, falso altrimenti ',
'Class:AuditRule/Attribute:valid_flag/Value:true' => 'vero',
'Class:AuditRule/Attribute:valid_flag/Value:true+' => 'vero',
'Class:AuditRule/Attribute:valid_flag/Value:false' => 'falso',
'Class:AuditRule/Attribute:valid_flag/Value:false+' => 'falso',
'Class:AuditRule/Attribute:category_id' => 'Categoria',
'Class:AuditRule/Attribute:category_id+' => 'Categoria per questa regola',
'Class:AuditRule/Attribute:category_name' => 'Categoria',
'Class:AuditRule/Attribute:category_name+' => 'Nome della categoria per questa regola',
));
//
// Class: QueryOQL
//
Dict::Add('IT IT', 'Italian', 'Italiano', array(
'Class:Query' => 'Query',
'Class:Query+' => 'Una query è un insieme di dati definito in modo dinamico',
'Class:Query/Attribute:name' => 'Nome',
'Class:Query/Attribute:name+' => 'Identificativi della query',
'Class:Query/Attribute:description' => 'Descrizione',
'Class:Query/Attribute:description+' => 'Descrizione dettagliata della query(scopo, usagoetc.)',
'Class:Query/Attribute:fields' => 'Campi',
'Class:Query/Attribute:fields+' => 'Lista di attributi separati da virgola (o alias.attributo) per l\'esportazione',
'Class:QueryOQL' => 'OQL Query',
'Class:QueryOQL+' => 'Una query basata su Object Query Language',
'Class:QueryOQL/Attribute:oql' => 'Espressione',
'Class:QueryOQL/Attribute:oql+' => 'Espressione OQL',
));
//////////////////////////////////////////////////////////////////////
// Classes in 'addon/userrights'
//////////////////////////////////////////////////////////////////////
//
//
// Class: User
//
Dict::Add('IT IT', 'Italian', 'Italiano', array(
'Class:User' => 'Utente',
'Class:User+' => 'Login Utente',
'Class:User/Attribute:finalclass' => 'Tipo di account',
'Class:User/Attribute:finalclass+' => '',
'Class:User/Attribute:contactid' => 'Contatto (persona)',
'Class:User/Attribute:contactid+' => 'Dettagli personali per dati aziendali',
'Class:User/Attribute:last_name' => 'Cognome',
'Class:User/Attribute:last_name+' => 'Cognome del contatto corrispondente',
'Class:User/Attribute:first_name' => 'Nome',
'Class:User/Attribute:first_name+' => 'Nome del contatto corrispondente',
'Class:User/Attribute:email' => 'Email',
'Class:User/Attribute:email+' => 'Email del contatto corrispondente',
'Class:User/Attribute:login' => 'Login',
'Class:User/Attribute:login+' => 'Stringa di identificazione dell\'utente',
'Class:User/Attribute:language' => 'Lingua',
'Class:User/Attribute:language+' => 'Lingua utente',
'Class:User/Attribute:language/Value:EN US' => 'English',
'Class:User/Attribute:language/Value:EN US+' => 'English (U.S.)',
'Class:User/Attribute:language/Value:IT IT' => 'Italiano',
'Class:User/Attribute:language/Value:IT IT+' => 'Italiano (IT)',
'Class:User/Attribute:language/Value:FR FR' => 'French',
'Class:User/Attribute:language/Value:FR FR+' => 'French (France)',
'Class:User/Attribute:profile_list' => 'Profili',
'Class:User/Attribute:profile_list+' => 'Regole per la concessione dei diritti per quella persona',
'Class:User/Attribute:allowed_org_list' => 'Organizzazione Consentite',
'Class:User/Attribute:allowed_org_list+' => 'L\'utente finale è autorizzato a vedere i dati appartenenti alle seguenti organizzazioni. Se non è specificato organizzazione, vi è alcuna restrizione.',
'Class:User/Error:LoginMustBeUnique' => 'Il Login deve essere unico - "%1s" già usato',
'Class:User/Error:AtLeastOneProfileIsNeeded' => 'Almeno un profilo deve essere assegnato all\'utente.',
));
//
// Class: URP_Profiles
//
Dict::Add('IT IT', 'Italian', 'Italiano', array(
'Class:URP_Profiles' => 'Profilo',
'Class:URP_Profiles+' => '',
'Class:URP_Profiles/Attribute:name' => 'Nome',
'Class:URP_Profiles/Attribute:name+' => '',
'Class:URP_Profiles/Attribute:description' => 'Descrizione',
'Class:URP_Profiles/Attribute:description+' => 'una linea di descrizione',
'Class:URP_Profiles/Attribute:user_list' => 'Utenti',
'Class:URP_Profiles/Attribute:user_list+' => 'Persone che hanno questo ruuolo',
));
//
// Class: URP_Dimensions
//
Dict::Add('IT IT', 'Italian', 'Italiano', array(
'Class:URP_Dimensions' => 'dimensione',
'Class:URP_Dimensions+' => 'dimensione dell\'applicazione (definizione di silos))',
'Class:URP_Dimensions/Attribute:name' => 'Nome',
'Class:URP_Dimensions/Attribute:name+' => 'etichetta',
'Class:URP_Dimensions/Attribute:description' => 'Descrizione',
'Class:URP_Dimensions/Attribute:description+' => 'una linea di descrizione',
'Class:URP_Dimensions/Attribute:type' => 'Tipo',
'Class:URP_Dimensions/Attribute:type+' => 'nome della classe o tipo di dato (proiezione dell\'unità)',
));
//
// Class: URP_UserProfile
//
Dict::Add('IT IT', 'Italian', 'Italiano', array(
'Class:URP_UserProfile' => 'Utente da Profilare',
'Class:URP_UserProfile+' => '',
'Class:URP_UserProfile/Attribute:userid' => 'Utente',
'Class:URP_UserProfile/Attribute:userid+' => '',
'Class:URP_UserProfile/Attribute:userlogin' => 'Login',
'Class:URP_UserProfile/Attribute:userlogin+' => 'User\'s login',
'Class:URP_UserProfile/Attribute:profileid' => 'Profilo',
'Class:URP_UserProfile/Attribute:profileid+' => 'utilizzo del profilo',
'Class:URP_UserProfile/Attribute:profile' => 'Profilo',
'Class:URP_UserProfile/Attribute:profile+' => 'Nome del profilo',
'Class:URP_UserProfile/Attribute:reason' => 'Motivo',
'Class:URP_UserProfile/Attribute:reason+' => 'spiega perchè questo utente dovrebbe avere questo ruolo',
));
//
// Class: URP_UserOrg
//
Dict::Add('IT IT', 'Italian', 'Italiano', array(
'Class:URP_UserOrg' => 'Organizzazione dell\'utente',
'Class:URP_UserOrg+' => '',
'Class:URP_UserOrg/Attribute:userid' => 'Utente',
'Class:URP_UserOrg/Attribute:userid+' => 'Account Utente',
'Class:URP_UserOrg/Attribute:userlogin' => 'Login',
'Class:URP_UserOrg/Attribute:userlogin+' => 'Login Utente',
'Class:URP_UserOrg/Attribute:allowed_org_id' => 'Organizazione',
'Class:URP_UserOrg/Attribute:allowed_org_id+' => 'Organizzazione permesse',
'Class:URP_UserOrg/Attribute:allowed_org_name' => 'Organizzazione',
'Class:URP_UserOrg/Attribute:allowed_org_name+' => 'Organizzazione permesse',
'Class:URP_UserOrg/Attribute:reason' => 'Motivo',
'Class:URP_UserOrg/Attribute:reason+' => '',
));
//
// Class: URP_ProfileProjection
//
Dict::Add('IT IT', 'Italian', 'Italiano', array(
'Class:URP_ProfileProjection' => 'profile_projection',
'Class:URP_ProfileProjection+' => 'proiezioni di profilo',
'Class:URP_ProfileProjection/Attribute:dimensionid' => 'Dimensione',
'Class:URP_ProfileProjection/Attribute:dimensionid+' => 'dimensione applicazione',
'Class:URP_ProfileProjection/Attribute:dimension' => 'Dimensione',
'Class:URP_ProfileProjection/Attribute:dimension+' => 'dimensione applicazione',
'Class:URP_ProfileProjection/Attribute:profileid' => 'Profilo',
'Class:URP_ProfileProjection/Attribute:profileid+' => 'utilizzo di profilo',
'Class:URP_ProfileProjection/Attribute:profile' => 'Profilo',
'Class:URP_ProfileProjection/Attribute:profile+' => 'Nome del profilo',
'Class:URP_ProfileProjection/Attribute:value' => 'Valore dell\'espressione',
'Class:URP_ProfileProjection/Attribute:value+' => 'Espressione OQL (uso $user) | constante| | +codice attributo',
'Class:URP_ProfileProjection/Attribute:attribute' => 'Attributo',
'Class:URP_ProfileProjection/Attribute:attribute+' => 'Codice attributo bersaglio (opzionale)',
));
//
// Class: URP_ClassProjection
//
Dict::Add('IT IT', 'Italian', 'Italiano', array(
'Class:URP_ClassProjection' => 'class_projection',
'Class:URP_ClassProjection+' => 'proiezioni di classe',
'Class:URP_ClassProjection/Attribute:dimensionid' => 'Dimensione',
'Class:URP_ClassProjection/Attribute:dimensionid+' => 'dimensione dell\'applicazione',
'Class:URP_ClassProjection/Attribute:dimension' => 'Dimensione',
'Class:URP_ClassProjection/Attribute:dimension+' => 'dimensione applicazione',
'Class:URP_ClassProjection/Attribute:class' => 'Classe',
'Class:URP_ClassProjection/Attribute:class+' => 'Classe bersaglio',
'Class:URP_ClassProjection/Attribute:value' => 'Valore dell\'espressione',
'Class:URP_ClassProjection/Attribute:value+' => 'Espressione OQL (uso $this) | constante| | +codice attributo',
'Class:URP_ClassProjection/Attribute:attribute' => 'Attributo',
'Class:URP_ClassProjection/Attribute:attribute+' => 'Codice attributo bersaglio (opzionale)',
));
//
// Class: URP_ActionGrant
//
Dict::Add('IT IT', 'Italian', 'Italiano', array(
'Class:URP_ActionGrant' => 'azione_autorizzazione',
'Class:URP_ActionGrant+' => 'permesso su classi',
'Class:URP_ActionGrant/Attribute:profileid' => 'Profilo',
'Class:URP_ActionGrant/Attribute:profileid+' => 'Utilizzo del profilo',
'Class:URP_ActionGrant/Attribute:profile' => 'Profilo',
'Class:URP_ActionGrant/Attribute:profile+' => 'Utilizzo del profilo',
'Class:URP_ActionGrant/Attribute:class' => 'Classe',
'Class:URP_ActionGrant/Attribute:class+' => 'Classe bersaglio',
'Class:URP_ActionGrant/Attribute:permission' => 'Autorizzazione',
'Class:URP_ActionGrant/Attribute:permission+' => 'permesso non permesso',
'Class:URP_ActionGrant/Attribute:permission/Value:yes' => 'si',
'Class:URP_ActionGrant/Attribute:permission/Value:yes+' => 'si',
'Class:URP_ActionGrant/Attribute:permission/Value:no' => 'no',
'Class:URP_ActionGrant/Attribute:permission/Value:no+' => 'no',
'Class:URP_ActionGrant/Attribute:action' => 'Azione',
'Class:URP_ActionGrant/Attribute:action+' => 'operazioni da effettuare sulla data classe',
));
//
// Class: URP_StimulusGrant
//
Dict::Add('IT IT', 'Italian', 'Italiano', array(
'Class:URP_ActionGrant/Attribute:action' => 'Azione',
'Class:URP_ActionGrant/Attribute:action+' => '',
'Class:URP_StimulusGrant' => 'stimulus_autorizzazione',
'Class:URP_StimulusGrant+' => '',
'Class:URP_StimulusGrant/Attribute:profileid' => 'Profilo',
'Class:URP_StimulusGrant/Attribute:profileid+' => '',
'Class:URP_StimulusGrant/Attribute:class' => 'Classe',
'Class:URP_StimulusGrant/Attribute:class+' => '',
'Class:URP_StimulusGrant/Attribute:permission' => 'Autorizzazione',
'Class:URP_StimulusGrant/Attribute:permission+' => '',
'Class:URP_StimulusGrant/Attribute:permission/Value:yes' => 'si',
'Class:URP_StimulusGrant/Attribute:permission/Value:yes+' => 'si',
'Class:URP_StimulusGrant/Attribute:permission/Value:no' => 'no',
'Class:URP_StimulusGrant/Attribute:permission/Value:no+' => 'no',
'Class:URP_StimulusGrant/Attribute:stimulus' => 'Stimulus',
'Class:URP_StimulusGrant/Attribute:stimulus+' => 'Codice per lo Stimolus',
));
//
// Class: URP_AttributeGrant
//
Dict::Add('IT IT', 'Italian', 'Italiano', array(
'Class:URP_AttributeGrant' => 'attributo_autorizzazione',
'Class:URP_AttributeGrant+' => 'autorizzazioni a livello di attributi',
'Class:URP_AttributeGrant/Attribute:actiongrantid' => 'Azione di sovvenzione',
'Class:URP_AttributeGrant/Attribute:actiongrantid+' => 'azione di sovvenzione',
'Class:URP_AttributeGrant/Attribute:attcode' => 'Attributo',
'Class:URP_AttributeGrant/Attribute:attcode+' => 'codice attributo',
));
//
// String from the User Interface: menu, messages, buttons, etc...
//
Dict::Add('IT IT', 'Italian', 'Italiano', array(
'Menu:WelcomeMenu' => 'Benveuto',
'Menu:WelcomeMenu+' => '',
'Menu:WelcomeMenuPage' => 'Benvenuto',
'Menu:WelcomeMenuPage+' => '',
'UI:WelcomeMenu:Title' => 'Benveuto su iTop',
'UI:WelcomeMenu:LeftBlock' => '<p>iTop è un completo Portale Funzionale IT, Open Source.</p>
<ul>Esso include:
<li>Un completo CMDB (Configuration management database) per documentare e gestire l\'IT di inventario.</li>
<li>Un modulo di gestione degli incidenti per monitorare e comunicare su tutte le problematiche che si verificano nel settore IT.</li>
<li>Un modulo di gestione delle modifiche per pianificare e monitorare i cambiamenti all\'ambiente IT.</li>
<li>Una banca dati errori noti per accelerare la risoluzione di incidenti.</li>
<li>Un modulo di interruzione per documentare tutte le interruzioni pianificate e notificare gli opportuni contatti.</li>
<li>Un cruscotto per ottenere rapidamente una panoramica del sistema IT.</li>
</ul>
<p>Tutti i moduli possono essere installati, passo dopo passo, indipendentemente l\'uno dall\'altro.</p>',
'UI:WelcomeMenu:RightBlock' => '<p>iTop è fornitore di servizi di orientamento, che consente ai progettisti di gestire più o organizzazioni o clienti con facilità.
<ul>>iTop, offre un set ricco di funzionalità dei processi di business che:
<li>Migliora l\'efficacia di gestione IT</li>
<li>Guida le prestazione delle operazioni IT</li>
<li>Migliora la soddisfazione del cliente e fornisce ai dirigenti un idea della performance del business.</li>
</ul>
</p>
<p>iTop è completamente aperto per essere integrato all\'interno della vostra infrastruttura di gestione dell\'IT.</p>
<p>
<ul>L\'adozione di questa nuova generazione di portale funzionale IT vi aiuterà a:
<li>Meglio gestire un ambiente IT sempre più complesso.</li>
<li>Implementare i processi ITIL al proprio ritmo.</li>
<li>Gestire la risorsa più importante della tua IT: Documentazione.</li>
</ul>
</p>',
'UI:WelcomeMenu:AllOpenRequests' => 'Apri le richieste: %1$d',
'UI:WelcomeMenu:MyCalls' => 'Le mie richieste',
'UI:WelcomeMenu:OpenIncidents' => 'Apri gli incidenti: %1$d',
'UI:WelcomeMenu:AllConfigItems' => 'Elementi di Configurazione (CI): %1$d',
'UI:WelcomeMenu:MyIncidents' => 'Incidenti assegnati a me',
'UI:AllOrganizations' => ' Tutte le Organizzazioni ',
'UI:YourSearch' => 'La tua Cerca',
'UI:LoggedAsMessage' => 'Logged come %1$s',
'UI:LoggedAsMessage+Admin' => 'Logged come %1$s (Amministratore)',
'UI:Button:Logoff' => 'Log off',
'UI:Button:GlobalSearch' => 'Cerca',
'UI:Button:Search' => ' Cerca',
'UI:Button:Query' => ' Domanda',
'UI:Button:Ok' => 'Ok',
'UI:Button:Cancel' => 'Cancella',
'UI:Button:Apply' => 'Applica',
'UI:Button:Back' => ' << Indietro',
'UI:Button:Restart' => ' |<< Riavvia',
'UI:Button:Next' => ' Prossimo >> ',
'UI:Button:Finish' => ' Fine',
'UI:Button:DoImport' => ' Esegui le Imporazioni ! ~~',
'UI:Button:Done' => ' Fatto',
'UI:Button:SimulateImport' => ' Simula l\'Importazione ~~',
'UI:Button:Test' => 'Testa!',
'UI:Button:Evaluate' => ' Valuta',
'UI:Button:AddObject' => ' Aggiungi... ~~',
'UI:Button:BrowseObjects' => ' Sfoglia... ~~',
'UI:Button:Add' => ' Aggiungi ~~',
'UI:Button:AddToList' => ' << Aggiungi ~~',
'UI:Button:RemoveFromList' => ' Rimuovi >> ~~',
'UI:Button:FilterList' => ' Filtra... ~~',
'UI:Button:Create' => ' Crea ~~',
'UI:Button:Delete' => ' Cancella ! ~~',
'UI:Button:ChangePassword' => ' Cambia Password ~~',
'UI:Button:ResetPassword' => ' Resetta Password ~~',
'UI:SearchToggle' => 'Cerca',
'UI:ClickToCreateNew' => 'Crea un nuovo %1$s~~',
'UI:SearchFor_Class' => 'Cerca l\'oggetto %1$s',
'UI:NoObjectToDisplay' => 'Nessun oggetto da mostrare.',
'UI:Error:MandatoryTemplateParameter_object_id' => 'Object_id parametro è obbligatorio quando link_attr è specificato. Verificare la definizione del modello di display.',
'UI:Error:MandatoryTemplateParameter_target_attr' => 'Target_attr parametro è obbligatorio quando link_attr è specificato. Verificare la definizione del modello di display.',
'UI:Error:MandatoryTemplateParameter_group_by' => 'Il parametro è group_by obbligatoria. Verificare la definizione del modello di display.',
'UI:Error:InvalidGroupByFields' => 'Elenco di campi non valido per il raggruppamento: "%1$s".',
'UI:Error:UnsupportedStyleOfBlock' => 'Errore: Stile non supportato di blocco: "%1$s".',
'UI:Error:IncorrectLinkDefinition_LinkedClass_Class' => 'Errata definizione di link: la classe di oggetti da gestire: %1$s non è stato trovato come chiave esterna nella classe %2$s',
'UI:Error:Object_Class_Id_NotFound' => 'Oggetto: %1$s:%2$d non trovato.',
'UI:Error:WizardCircularReferenceInDependencies' => 'Errore: Riferimento circolare nelle dipendenze tra i campi, controllare il modello di dati.',
'UI:Error:UploadedFileTooBig' => 'Il file caricato è troppo grande. (dimensione massima consentita è di %1$s). Verificare di configurazione di PHP per upload_max_filesize e post_max_size.',
'UI:Error:UploadedFileTruncated.' => 'Il file caricato è stata troncato !',
'UI:Error:NoTmpDir' => 'La directory temporanea non è definita.',
'UI:Error:CannotWriteToTmp_Dir' => 'Impossibile scrivere il file temporaneo sul disco. upload_tmp_dir = "%1$s".',
'UI:Error:UploadStoppedByExtension_FileName' => 'Caricamento fermato per estensione. (Nome del file originale = "%1$s").',
'UI:Error:UploadFailedUnknownCause_Code' => 'Il caricamento del file non riuscito, causa sconosciuta. (Codice errore = "%1$s").',
'UI:Error:1ParametersMissing' => 'Errore: il seguente parametro deve essere specificato per questa operazione: %1$s.',
'UI:Error:2ParametersMissing' => 'Errore: i seguenti parametri devono essere specificati per questa operazione: %1$s e %2$s.',
'UI:Error:3ParametersMissing' => 'Errore: i seguenti parametri devono essere specificati per questa operazione: %1$s, %2$s e %3$s.',
'UI:Error:4ParametersMissing' => 'Errore: i seguenti parametri devono essere specificati per questa operazione: %1$s, %2$s, %3$s e %4$s.',
'UI:Error:IncorrectOQLQuery_Message' => 'Errore: errata OQL query: %1$s',
'UI:Error:AnErrorOccuredWhileRunningTheQuery_Message' => 'Si è verificato un errore durante l\'esecuzione della query: %1$s',
'UI:Error:ObjectAlreadyUpdated' => 'Errore: l\'oggetto è già stato aggiornato.',
'UI:Error:ObjectCannotBeUpdated' => 'Errore: oggetto non può essere aggiornato.',
'UI:Error:ObjectsAlreadyDeleted' => 'Errore: gli oggetti sono già stati eliminati!',
'UI:Error:BulkDeleteNotAllowedOn_Class' => 'Non hai i permessi per eseguire una eliminazione collettiva degli oggetti della classe %1$s',
'UI:Error:DeleteNotAllowedOn_Class' => 'Non ti è permesso di eliminare gli oggetti della classe %1$s',
'UI:Error:BulkModifyNotAllowedOn_Class' => 'Non hai i permessi per eseguire un aggiornamento collettivo degli oggetti della classe %1$s',
'UI:Error:ObjectAlreadyCloned' => 'Errore: l\'oggetto è già stato clonato!',
'UI:Error:ObjectAlreadyCreated' => 'Errore: l\'oggetto è già stato creato!',
'UI:Error:Invalid_Stimulus_On_Object_In_State' => 'Errore: stimolo non valido "%1$s" su un oggetto %2$s nello stato "%3$s".',
'UI:GroupBy:Count' => 'Conteggio',
'UI:GroupBy:Count+' => '',
'UI:CountOfObjects' => '%1$d oggetti corrispondenti ai criteri.',
'UI_CountOfObjectsShort' => '%1$d oggetti.',
'UI:NoObject_Class_ToDisplay' => 'No %1$s da visualizzare',
'UI:History:LastModified_On_By' => 'Ultima modifica %1$s da %2$s.',
'UI:HistoryTab' => 'Storia',
'UI:NotificationsTab' => 'Notifiche',
'UI:History:BulkImports' => 'Storia',
'UI:History:BulkImports+' => 'Elenco delle importazioni CSV (primo ultimo)',
'UI:History:BulkImportDetails' => 'Modifiche derivanti dai importazione CSV eseguita su %1$s (da %2$s)',
'UI:History:Date' => 'Data',
'UI:History:Date+' => '',
'UI:History:User' => 'Utente',
'UI:History:User+' => '',
'UI:History:Changes' => 'Modifiche',
'UI:History:Changes+' => '',
'UI:History:StatsCreations' => 'Creato',
'UI:History:StatsCreations+' => '',
'UI:History:StatsModifs' => 'Modificato',
'UI:History:StatsModifs+' => '',
'UI:History:StatsDeletes' => 'Cancellato',
'UI:History:StatsDeletes+' => '',
'UI:Loading' => 'Caricamento...',
'UI:Menu:Actions' => 'Azioni',
'UI:Menu:OtherActions' => 'Altre Azioni',
'UI:Menu:New' => 'Nuovo...',
'UI:Menu:Add' => 'Aggiungi...',
'UI:Menu:Manage' => 'Gestischi...',
'UI:Menu:EMail' => 'eMail',
'UI:Menu:CSVExport' => 'CSV Export',
'UI:Menu:Modify' => 'Modifica...',
'UI:Menu:Delete' => 'Cancella...',
'UI:Menu:Manage' => 'Gestisci...',
'UI:Menu:BulkDelete' => 'Cancella...',
'UI:UndefinedObject' => 'non definito',
'UI:Document:OpenInNewWindow:Download' => 'Apri in una nuova finestra: %1$s, Scarica: %2$s',
'UI:SelectAllToggle+' => '',
'UI:TruncatedResults' => '%1$d oggetti visualizzati su %2$d',
'UI:DisplayAll' => 'Mostra tutto',
'UI:CollapseList' => 'Collassa',
'UI:CountOfResults' => '%1$d oggetto(i)',
'UI:ChangesLogTitle' => 'Log delle modifiche (%1$d):',
'UI:EmptyChangesLogTitle' => 'Log delle modifiche è vuoto',
'UI:SearchFor_Class_Objects' => 'Cerca per %1$s Oggetti',
'UI:OQLQueryBuilderTitle' => 'OQL Query Builder',
'UI:OQLQueryTab' => 'OQL Query',
'UI:SimpleSearchTab' => 'Ricerca semplice',
'UI:Details+' => '',
'UI:SearchValue:Any' => '* Qualsiasi *',
'UI:SearchValue:Mixed' => '* misti *',
'UI:SelectOne' => '-- selezionare uno --',
'UI:Login:Welcome' => 'Benvenuti su iTop!',
'UI:Login:IncorrectLoginPassword' => 'Errato login/password, si prega di riprovare.',
'UI:Login:IdentifyYourself' => 'Identifica te stesso prima di continuare',
'UI:Login:UserNamePrompt' => 'Nome Utente',
'UI:Login:PasswordPrompt' => 'Password',
'UI:Login:ChangeYourPassword' => 'Cambia la tua password',
'UI:Login:OldPasswordPrompt' => 'Vecchia password',
'UI:Login:NewPasswordPrompt' => 'Nuova password',
'UI:Login:RetypeNewPasswordPrompt' => 'Riscrivi la nuova password',
'UI:Login:IncorrectOldPassword' => 'Errore: la vecchia password non è corretta',
'UI:LogOffMenu' => 'Log off',
'UI:LogOff:ThankYou' => 'Grazie per aver scelto iTop',
'UI:LogOff:ClickHereToLoginAgain' => 'Clicca qui per effettuare il login di nuovo...',
'UI:ChangePwdMenu' => 'Cambia Password...',
'UI:AccessRO-All' => 'iTop è di sola lettura',
'UI:AccessRO-Users' => 'iTop è di sola lettura per gli utenti finali',
'UI:Login:RetypePwdDoesNotMatch' => 'Nuova password e la nuova password digitata nuovamente non corrispondono !',
'UI:Button:Login' => 'Entra in iTop',
'UI:Login:Error:AccessRestricted' => 'L\'accesso a iTop è limitato. Si prega di contattare un amministratore iTop.',
'UI:Login:Error:AccessAdmin' => 'Accesso limitato alle persone che hanno privilegi di amministratore. Si prega di contattare un amministratore iTop.',
'UI:CSVImport:MappingSelectOne' => '-- seleziona uno --',
'UI:CSVImport:MappingNotApplicable' => '-- ignora questo campo --',
'UI:CSVImport:NoData' => 'Insieme di dati vuoto ..., si prega di fornire alcuni dati!',
'UI:Title:DataPreview' => 'Anteprima dati',
'UI:CSVImport:ErrorOnlyOneColumn' => 'Errore: I dati contengono solo una colonna. Avete selezionato il carattere separatore appropriato?',
'UI:CSVImport:FieldName' => 'Campo %1$d',
'UI:CSVImport:DataLine1' => 'Dati Linea 1',
'UI:CSVImport:DataLine2' => 'Dati Linea 2',
'UI:CSVImport:idField' => 'id (Chiave Primaria)',
'UI:Title:BulkImport' => 'iTop - importazione collettiva',
'UI:Title:BulkImport+' => '',
'UI:Title:BulkSynchro_nbItem_ofClass_class' => 'Sincronizzazione di %1$d oggetti della classe %2$s',
'UI:CSVImport:ClassesSelectOne' => '-- seleziona uno --',
'UI:CSVImport:ErrorExtendedAttCode' => 'Errore interno: "%1$s" è un codice errato, perché "%2$s" NON è una chiave esterna della classe "%3$s"',
'UI:CSVImport:ObjectsWillStayUnchanged' => '%1$d oggetto(i) rimarrà invariato.',
'UI:CSVImport:ObjectsWillBeModified' => '%1$d oggetto(i) sarà modificato.',
'UI:CSVImport:ObjectsWillBeAdded' => '%1$d oggetto(i) sarà aggiunto.',
'UI:CSVImport:ObjectsWillHaveErrors' => '%1$d oggetto(i) avranno i errori.',
'UI:CSVImport:ObjectsRemainedUnchanged' => '%1$d oggetto(i) è rimasto invariato.',
'UI:CSVImport:ObjectsWereModified' => '%1$d oggetto(i) sono stati modificati.',
'UI:CSVImport:ObjectsWereAdded' => '%1$d oggetto(i) sono stati aggiunti.',
'UI:CSVImport:ObjectsHadErrors' => '%1$d oggetto(i) hanno avuto errori.',
'UI:Title:CSVImportStep2' => 'Step 2 of 5: opzioni dati CVS',
'UI:Title:CSVImportStep3' => 'Step 3 of 5: Mappatura dei dati',
'UI:Title:CSVImportStep4' => 'Step 4 of 5: Importa simulazione',
'UI:Title:CSVImportStep5' => 'Step 5 of 5: Importazione completata',
'UI:CSVImport:LinesNotImported' => 'Linee che non possono essere caricate:',
'UI:CSVImport:LinesNotImported+' => '',
'UI:CSVImport:SeparatorComma+' => '',
'UI:CSVImport:SeparatorSemicolon+' => '',
'UI:CSVImport:SeparatorTab+' => '',
'UI:CSVImport:SeparatorOther' => 'altri:',
'UI:CSVImport:QualifierDoubleQuote+' => '',
'UI:CSVImport:QualifierSimpleQuote+' => '',
'UI:CSVImport:QualifierOther' => 'other:~~',
'UI:CSVImport:TreatFirstLineAsHeader' => 'Tratta la prima riga come intestazione (nomi di colonna)',
'UI:CSVImport:Skip_N_LinesAtTheBeginning' => 'Salta le linee %1$s all\'inzio del file',
'UI:CSVImport:CSVDataPreview' => 'CSV Anteprima dei dati',
'UI:CSVImport:SelectFile' => 'Selezionare il file da importare:',
'UI:CSVImport:Tab:LoadFromFile' => 'Carica da un file',
'UI:CSVImport:Tab:CopyPaste' => 'Copia e incolla i dati',
'UI:CSVImport:Tab:Templates' => 'Modelli',
'UI:CSVImport:PasteData' => 'Incolla i dati da importare:',
'UI:CSVImport:PickClassForTemplate' => 'Scegli il modello da scaricare: ',
'UI:CSVImport:SeparatorCharacter' => 'Separatore di carattere:',
'UI:CSVImport:TextQualifierCharacter' => 'Testo di qualificazione carattere',
'UI:CSVImport:CommentsAndHeader' => 'Commenti e intestazione',
'UI:CSVImport:SelectClass' => 'Selezionare la classe da importare:',
'UI:CSVImport:AdvancedMode' => 'Modalità avanzata',
'UI:CSVImport:AdvancedMode+' => '',
'UI:CSVImport:SelectAClassFirst' => 'Per configurare il mapping, selezionare prima una classe.',
'UI:CSVImport:HeaderFields' => 'Campi',
'UI:CSVImport:HeaderMappings' => 'Mappings',
'UI:CSVImport:HeaderSearch' => 'Cerca?',
'UI:CSVImport:AlertIncompleteMapping' => 'Per favore seleziona una mappatura per ogni campo.',
'UI:CSVImport:AlertNoSearchCriteria' => 'Per favore seleziona almeno un criterio di ricerca',
'UI:CSVImport:Encoding' => 'Codifica dei caratteri',
'UI:UniversalSearchTitle' => 'iTop - Ricerca Universale',
'UI:UniversalSearch:Error' => 'Errore: %1$s~~',
'UI:UniversalSearch:LabelSelectTheClass' => 'Seleziona la classe per la ricerca: ',
'UI:Audit:Title' => 'iTop - CMDB Audit~~',
'UI:Audit:InteractiveAudit' => 'Audit Interattivo',
'UI:Audit:HeaderAuditRule' => 'Regole di Audit',
'UI:Audit:HeaderNbObjects' => '# Oggetti',
'UI:Audit:HeaderNbErrors' => '# Errori',
'UI:Audit:PercentageOk' => '% Ok',
'UI:RunQuery:Title' => 'iTop - Valutazione Query OQL',
'UI:RunQuery:QueryExamples' => 'Esempi di Query',
'UI:RunQuery:HeaderPurpose' => 'Scopo',
'UI:RunQuery:HeaderPurpose+' => '',
'UI:RunQuery:HeaderOQLExpression' => 'Espressioni OQL',
'UI:RunQuery:HeaderOQLExpression+' => '',
'UI:RunQuery:ExpressionToEvaluate' => 'Espressione da valutare: ',
'UI:RunQuery:MoreInfo' => 'Maggiori informazioni sulla query: ',
'UI:RunQuery:DevelopedQuery' => 'Espressione della query riqualificata:',
'UI:RunQuery:SerializedFilter' => 'Filtro pubblicato: ',
'UI:RunQuery:Error' => 'Si è verificato un errore durante l\'esecuzione della query: %1$s',
'UI:Schema:Title' => 'iTop schema degli oggetti',
'UI:Schema:CategoryMenuItem' => 'Categoria <b>%1$s</b>',
'UI:Schema:Relationships' => 'Relazioni',
'UI:Schema:AbstractClass' => 'Classe astratta: nessun oggetto da questa classe può essere istanziato.',
'UI:Schema:NonAbstractClass' => 'Classe non-astratta: oggetti da questa classe possono essere istanziati.',
'UI:Schema:ClassHierarchyTitle' => 'Gerarchia delle classi',
'UI:Schema:AllClasses' => 'Tutte le classi',
'UI:Schema:ExternalKey_To' => 'Chiave esterna %1$s',
'UI:Schema:Columns_Description' => 'Colonne: <em>%1$s</em>',
'UI:Schema:Default_Description' => 'Default: "%1$s"',
'UI:Schema:NullAllowed' => 'Null consentito',
'UI:Schema:NullNotAllowed' => 'Null NON consentito',
'UI:Schema:Attributes' => 'Attributi',
'UI:Schema:AttributeCode' => 'Codice attributo',
'UI:Schema:AttributeCode+' => '',
'UI:Schema:Label' => 'Etichetta',
'UI:Schema:Label+' => '',
'UI:Schema:Type' => 'Tipo',
'UI:Schema:Type+' => '',
'UI:Schema:Origin' => 'Origine',
'UI:Schema:Origin+' => '',
'UI:Schema:Description' => 'Descrizione',
'UI:Schema:Description+' => '',
'UI:Schema:AllowedValues' => 'Valori consentiti',
'UI:Schema:AllowedValues+' => '',
'UI:Schema:MoreInfo' => 'Maggiori informazioni',
'UI:Schema:MoreInfo+' => '',
'UI:Schema:SearchCriteria' => 'Criteri di ricerca',
'UI:Schema:FilterCode' => 'Codice di filtro',
'UI:Schema:FilterCode+' => '',
'UI:Schema:FilterDescription' => 'Descrizione',
'UI:Schema:FilterDescription+' => '',
'UI:Schema:AvailOperators' => 'Operatori disponibili',
'UI:Schema:AvailOperators+' => '',
'UI:Schema:ChildClasses' => 'Classi figlio',
'UI:Schema:ReferencingClasses' => 'Classi di rifermento',
'UI:Schema:RelatedClasses' => 'Classi correlate',
'UI:Schema:LifeCycle' => 'Ciclo di vita',
'UI:Schema:Triggers' => 'Triggers',
'UI:Schema:Relation_Code_Description' => 'Relazione <em>%1$s</em> (%2$s)',
'UI:Schema:RelationDown_Description' => 'Giù: %1$s',
'UI:Schema:RelationUp_Description' => 'Su: %1$s',
'UI:Schema:RelationPropagates' => '%1$s: propagato al livello %2$d, query: %3$s',
'UI:Schema:RelationDoesNotPropagate' => '%1$s: non si propaga a (%2$d livelli), query: %3$s',
'UI:Schema:Class_ReferencingClasses_From_By' => '%1$s fa riferimento la classe %2$s tramite il campo %3$s',
'UI:Schema:Class_IsLinkedTo_Class_Via_ClassAndAttribute' => '%1$s è legata alla %2$s via %3$s::<em>%4$s</em>',
'UI:Schema:Links:1-n' => 'Classi che puntano a %1$s (1:n links):',
'UI:Schema:Links:n-n' => 'Classi legati alla %1$s (n:n links):',
'UI:Schema:Links:All' => 'Grafico di tutte le classi correlate',
'UI:Schema:NoLifeCyle' => 'Non vi è alcun ciclo di vita definito per questa classe.',
'UI:Schema:LifeCycleTransitions' => 'Transizioni',
'UI:Schema:LifeCyleAttributeOptions' => 'Opzioni per l\'attributo',
'UI:Schema:LifeCycleHiddenAttribute' => 'Nascosto',
'UI:Schema:LifeCycleReadOnlyAttribute' => 'Di sola lettura',
'UI:Schema:LifeCycleMandatoryAttribute' => 'Obbigatorio',
'UI:Schema:LifeCycleAttributeMustChange' => 'Deve cambiare',
'UI:Schema:LifeCycleAttributeMustPrompt' => 'All\'utente verrà richiesto di modificare il valore',
'UI:Schema:LifeCycleEmptyList' => 'lista vuota',
'UI:LinksWidget:Autocomplete+' => '',
'UI:Combo:SelectValue' => '--- seleziona un valore ---',
'UI:Label:SelectedObjects' => 'oggetti selezionati: ',
'UI:Label:AvailableObjects' => 'Oggetti disponibili: ',
'UI:Link_Class_Attributes' => '%1$s attributi',
'UI:AddObjectsOf_Class_LinkedWith_Class_Instance' => 'Aggiungi l\'oggeto %1$s collegato con %2$s: %3$s',
'UI:AddObjectsOf_Class_LinkedWith_Class' => 'Aggiungi l\'oggeto %1$s al collegamento con %2$s',
'UI:ManageObjectsOf_Class_LinkedWith_Class_Instance' => 'Gestisci l\'oggetto %1$s collegato con %2$s: %3$s',
'UI:AddLinkedObjectsOf_Class' => 'Aggiungi %1$s...',
'UI:RemoveLinkedObjectsOf_Class' => 'Rimuovi gli oggetti selezionati',
'UI:Message:EmptyList:UseAdd' => 'La lista è vuota, utilizzare il pulsante "Aggiungi ..." per aggiungere elementi.',
'UI:Message:EmptyList:UseSearchForm' => 'Utilizza il modulo di ricerca qui sopra per cercare oggetti da aggiungere.',
'UI:Wizard:FinalStepTitle' => 'Passo finale: la conferma',
'UI:Title:DeletionOf_Object' => 'Soppressione di %1$s',
'UI:Title:BulkDeletionOf_Count_ObjectsOf_Class' => 'Cancellazione collettiva di %1$d oggetti della classe %2$s',
'UI:Delete:NotAllowedToDelete' => 'Non ti è permesso di eliminare l\'oggetto',
'UI:Delete:NotAllowedToUpdate_Fields' => 'Non hai i permessi per aggiornare il seguente campo(i): %1$s',
'UI:Error:NotEnoughRightsToDelete' => 'Questo oggetto non può essere cancellato perché l\'utente corrente non dispone dei diritti necessari',
'UI:Error:CannotDeleteBecause' => 'Questo oggetto non può essere cancellato perchè: %1$s~~',
'UI:Error:CannotDeleteBecauseOfDepencies' => 'Questo oggetto non può essere cancellato perché alcune operazioni manuali devono essere effettuate prima di questo',
'UI:Error:CannotDeleteBecauseManualOpNeeded' => 'Questo oggetto non può essere cancellato perché alcune operazioni manuali devono essere effettuate prima di questo',
'UI:Archive_User_OnBehalfOf_User' => '%1$s a nome di %2$s',
'UI:Delete:Deleted' => 'deleted~~',
'UI:Delete:AutomaticallyDeleted' => 'automaticamente eliminato',
'UI:Delete:AutomaticResetOf_Fields' => 'ripristino automatico del campo(i): %1$s',
'UI:Delete:CleaningUpRefencesTo_Object' => 'Pulizia di tutti i riferimenti a %1$s...',
'UI:Delete:CleaningUpRefencesTo_Several_ObjectsOf_Class' => 'Pulizia di tutti i riferimenti a %1$d oggetti di classe %2$s...',
'UI:Delete:Done+' => '',
'UI:Delete:_Name_Class_Deleted' => '%1$s - %2$s cancellato.',
'UI:Delete:ConfirmDeletionOf_Name' => 'Soppressione di %1$s',
'UI:Delete:ConfirmDeletionOf_Count_ObjectsOf_Class' => 'Soppressione di %1$d oggetti di classe %2$s',
'UI:Delete:CannotDeleteBecause' => 'Non può essere cancellato: %1$s~~',
'UI:Delete:ShouldBeDeletedAtomaticallyButNotPossible' => 'Dovrebbe essere eliminato automaticamente, ma questo non è fattibile: %1$s~~',
'UI:Delete:MustBeDeletedManuallyButNotPossible' => 'Deve essere cancellato manualmente, ma questo non è fattibile: %1$s~~',
'UI:Delete:WillBeDeletedAutomatically' => 'Sarà cancellato automaticamente',
'UI:Delete:MustBeDeletedManually' => 'Deve essere cancellato manualmente',
'UI:Delete:CannotUpdateBecause_Issue' => 'Dovrebbero essere automaticamente aggiornati, ma: %1$s~~',
'UI:Delete:WillAutomaticallyUpdate_Fields' => 'Sarà automaticamente aggiornato (reset: %1$s)~~',
'UI:Delete:Count_Objects/LinksReferencing_Object' => '%1$d oggetti/link fanno riferimento %2$s',
'UI:Delete:Count_Objects/LinksReferencingTheObjects' => '%1$d oggetti / link fanno riferimento alcuni degli oggetti da eliminare',
'UI:Delete:ReferencesMustBeDeletedToEnsureIntegrity' => 'Per garantire l\'integrità del database, ogni riferimento dovrebbe essere ulteriormente eliminato',
'UI:Delete:Consequence+' => '',
'UI:Delete:SorryDeletionNotAllowed' => 'Spiacenti, non sei autorizzato a cancellare questo oggetto, vedere le spiegazioni di cui sopra',
'UI:Delete:PleaseDoTheManualOperations' => 'Si prega di eseguire le operazioni manuali di cui sopra prima di richiedere la cancellazione di questo oggetto',
'UI:Delect:Confirm_Object' => 'Si prega di confermare che si desidera eliminare %1$s.',
'UI:Delect:Confirm_Count_ObjectsOf_Class' => 'Si prega di confermare che si desidera eliminare i seguenti oggetti %1$d della classe %2$s.',
'UI:WelcomeToITop' => 'Benvenuto su iTop',
'UI:DetailsPageTitle' => 'iTop - %1$s - %2$s dettagli',
'UI:ErrorPageTitle' => 'iTop - Errore',
'UI:ObjectDoesNotExist' => 'Spiacenti, questo oggetto non esiste (o non si è autorizzati per vederlo).',
'UI:SearchResultsPageTitle' => 'iTop - Risultati della ricerca',
'UI:Search:NoSearch' => 'Niente da ricercare',
'UI:FullTextSearchTitle_Text' => 'Risultati per "%1$s":',
'UI:Search:Count_ObjectsOf_Class_Found' => 'Trovato l\'oggetto(i) %1$d della classe %2$s.',
'UI:Search:NoObjectFound' => 'Nessun oggetto trovato.',
'UI:ModificationPageTitle_Object_Class' => 'iTop - %1$s - %2$s modifica',
'UI:ModificationTitle_Class_Object' => 'Modifica di %1$s: <span class=\"hilite\">%2$s</span>',
'UI:ClonePageTitle_Object_Class' => 'iTop - Clone %1$s - %2$s modifica',
'UI:CloneTitle_Class_Object' => 'Clone di %1$s: <span class=\"hilite\">%2$s</span>',
'UI:CreationPageTitle_Class' => 'iTop - Creazione di un nuovo %1$s ',
'UI:CreationTitle_Class' => 'Creazione di un nuovo %1$s',
'UI:SelectTheTypeOf_Class_ToCreate' => 'Seleziona il tipo di %1$s da creare:',
'UI:Class_Object_NotUpdated' => 'Nessun cambiamento rilevato, %1$s (%2$s) <strong>non</strong> è stato modificato.',
'UI:Class_Object_Updated' => '%1$s (%2$s) aggiornato.',
'UI:BulkDeletePageTitle' => 'iTop - Eliminazione collettiva',
'UI:BulkDeleteTitle' => 'Seleziona gli oggetti che si desidera eliminare:',
'UI:PageTitle:ObjectCreated' => 'iTop Oggetto Creato.',
'UI:Title:Object_Of_Class_Created' => '%1$s - %2$s creato.',
'UI:Apply_Stimulus_On_Object_In_State_ToTarget_State' => 'Applicazione %1$s all\'oggetto: %2$s nello stato %3$s allo stato target: %4$s.',
'UI:ObjectCouldNotBeWritten' => 'L\'oggetto non può essere scritto: %1$s~~',
'UI:PageTitle:FatalError' => 'iTop - Fatal Error',
'UI:SystemIntrusion' => 'Accesso negato. Hai cercato di eseguire un\'operazione che non ti è consentita.',
'UI:FatalErrorMessage' => 'Fatal error, iTop non può continuare.',
'UI:Error_Details' => 'Errore: %1$s.',
'UI:PageTitle:ClassProjections' => 'iTop gestione degli utenti - proiezioni classe',
'UI:PageTitle:ProfileProjections' => 'iTop gestione degli utenti - proiezioni profilo',
'UI:UserManagement:Class' => 'Classe',
'UI:UserManagement:Class+' => '',
'UI:UserManagement:ProjectedObject' => 'Oggetto',
'UI:UserManagement:ProjectedObject+' => '',
'UI:UserManagement:AnyObject' => '* qualsiasi *',
'UI:UserManagement:User' => 'Utente',
'UI:UserManagement:User+' => '',
'UI:UserManagement:Profile' => 'Profilo',
'UI:UserManagement:Profile+' => '',
'UI:UserManagement:Action:Read' => 'Leggi',
'UI:UserManagement:Action:Read+' => '',
'UI:UserManagement:Action:Modify' => 'Modifica',
'UI:UserManagement:Action:Modify+' => '',
'UI:UserManagement:Action:Delete' => 'Cancella',
'UI:UserManagement:Action:Delete+' => '',
'UI:UserManagement:Action:BulkRead' => 'Leggi Bulk (Export)',
'UI:UserManagement:Action:BulkRead+' => '',
'UI:UserManagement:Action:BulkModify' => 'Modifica Bulk',
'UI:UserManagement:Action:BulkModify+' => '',
'UI:UserManagement:Action:BulkDelete' => 'Cancella Bulk ',
'UI:UserManagement:Action:BulkDelete+' => '',
'UI:UserManagement:Action:Stimuli' => 'Stimoli',
'UI:UserManagement:Action:Stimuli+' => '',
'UI:UserManagement:Action' => 'Azione',
'UI:UserManagement:Action+' => '',
'UI:UserManagement:TitleActions' => 'Azioni',
'UI:UserManagement:Permission' => 'Autorizzazione',
'UI:UserManagement:Permission+' => '',
'UI:UserManagement:Attributes' => 'Attributi',
'UI:UserManagement:ActionAllowed:Yes' => 'Si',
'UI:UserManagement:ActionAllowed:No' => 'No',
'UI:UserManagement:AdminProfile+' => '',
'UI:UserManagement:NoLifeCycleApplicable' => 'N/A',
'UI:UserManagement:NoLifeCycleApplicable+' => '',
'UI:UserManagement:GrantMatrix' => 'Grant Matrix',
'UI:UserManagement:LinkBetween_User_And_Profile' => 'Collegamento tra %1$s e %2$s',
'UI:UserManagement:LinkBetween_User_And_Org' => 'Collegamento tra %1$s e %2$s',
'Menu:AdminTools' => 'Strumenti di amministrazione',
'Menu:AdminTools+' => '',
'Menu:AdminTools?' => 'Strumenti accessibile solo agli utenti con il profilo di amministratore',
'UI:ChangeManagementMenu' => 'Gestione Cambi',
'UI:ChangeManagementMenu+' => '',
'UI:ChangeManagementMenu:Title' => 'Panoramica dei cambi',
'UI-ChangeManagementMenu-ChangesByType' => 'Cambi per tipo',
'UI-ChangeManagementMenu-ChangesByStatus' => 'Cambi per stato',
'UI-ChangeManagementMenu-ChangesByWorkgroup' => 'Cambi per gruppi di lavoro',
'UI-ChangeManagementMenu-ChangesNotYetAssigned' => 'Cambi non ancora assegnati',
'UI:ConfigurationItemsMenu' => 'Configuration Items',
'UI:ConfigurationItemsMenu+' => '',
'UI:ConfigurationItemsMenu:Title' => 'Configuration Items Panoramica',
'UI-ConfigurationItemsMenu-ServersByCriticity' => 'Server per criticità',
'UI-ConfigurationItemsMenu-PCsByCriticity' => 'PCs per criticità',
'UI-ConfigurationItemsMenu-NWDevicesByCriticity' => 'Dispositivi di rete per criticità',
'UI-ConfigurationItemsMenu-ApplicationsByCriticity' => 'Applicazioni per criticità',
'UI:ConfigurationManagementMenu' => 'Gestione Configurazione',
'UI:ConfigurationManagementMenu+' => '',
'UI:ConfigurationManagementMenu:Title' => 'Panoramica delle infrastrutture',
'UI-ConfigurationManagementMenu-InfraByType' => 'Oggetti infrastruttutura per tipo',
'UI-ConfigurationManagementMenu-InfraByStatus' => 'Oggetti infrastruttutura per stato',
'UI:ConfigMgmtMenuOverview:Title' => 'Cruscotto per Gestione configurazione',
'UI-ConfigMgmtMenuOverview-FunctionalCIbyStatus' => 'Configuration Items per stato',
'UI-ConfigMgmtMenuOverview-FunctionalCIByType' => 'Configuration Items per tipo',
'UI:RequestMgmtMenuOverview:Title' => 'Cruscotto per Gestione Richieste',
'UI-RequestManagementOverview-RequestByService' => 'Richieste degli utenti per servizio',
'UI-RequestManagementOverview-RequestByPriority' => 'Richieste degli utenti per priorità',
'UI-RequestManagementOverview-RequestUnassigned' => 'Richieste degli utenti non ancora assegnate ad un agente',
'UI:IncidentMgmtMenuOverview:Title' => 'Cruscotto Gestione degli Incidenti',
'UI-IncidentManagementOverview-IncidentByService' => 'Incidenti per servizio',
'UI-IncidentManagementOverview-IncidentByPriority' => 'Incidenti per priorità',
'UI-IncidentManagementOverview-IncidentUnassigned' => 'Incidenti non ancora assegnati ad un agente',
'UI:ChangeMgmtMenuOverview:Title' => 'Cruscotto per Gestione dei Cambi',
'UI-ChangeManagementOverview-ChangeByType' => 'Cambi per tipo',
'UI-ChangeManagementOverview-ChangeUnassigned' => 'Cambi non ancora assegnati ad un agente',
'UI-ChangeManagementOverview-ChangeWithOutage' => 'Interruzioni dovute ai cambi',
'UI:ServiceMgmtMenuOverview:Title' => 'Cruscotto per Gestione dei Cambi',
'UI-ServiceManagementOverview-CustomerContractToRenew' => 'Contratti con i clienti da rinnovarsi in 30 giorni',
'UI-ServiceManagementOverview-ProviderContractToRenew' => 'Contratti con i fornitori da rinnovarsi in 30 giorni',
'UI:ContactsMenu' => 'Contatti',
'UI:ContactsMenu+' => '',
'UI:ContactsMenu:Title' => 'Contatti Panoramica',
'UI-ContactsMenu-ContactsByLocation' => 'Contatti per localizzazione',
'UI-ContactsMenu-ContactsByType' => 'Contatti per tipo',
'UI-ContactsMenu-ContactsByStatus' => 'Contatti per stato',
'Menu:CSVImportMenu' => 'Importazione CSV',
'Menu:CSVImportMenu+' => '',
'Menu:DataModelMenu' => 'Modello Dati',
'Menu:DataModelMenu+' => '',
'Menu:ExportMenu' => 'Esporta',
'Menu:ExportMenu+' => '',
'Menu:NotificationsMenu' => 'Notifiche',
'Menu:NotificationsMenu+' => '',
'UI:NotificationsMenu:Title' => 'Configurazione delle <span class="hilite">Notifiche</span>',
'UI:NotificationsMenu:Help' => 'Aiuto',
'UI:NotificationsMenu:HelpContent' => '<p>In iTop le notifiche sono completamente personalizzabili. Essi si basano su due serie di oggetti: <i>trigger e azioni</i>.</p>
<p><i><b>Triggers</b></i> per definire quando una notifica verrà eseguita. Ci sono 3 tipi di trigger per la copertura di 3 fasi differenti del ciclo di vita di un oggetto:
<ol>
<li>the "OnCreate" trigger vengono eseguiti quando un oggetto della classe specificata viene creata</li>
<li>the "OnStateEnter" trigger vengono eseguiti prima che un oggetto della classe data entra in uno stato specifico (provenienti da un altro Stato)</li>
<li>the "OnStateLeave" trigger vengono eseguiti quando un oggetto della classe lascia uno stato specificato</li>
</ol>
</p>
<p>
<i><b>Azioni</b></i> definire le azioni da eseguire quando il trigger vengono eseguiti. Per ora c\'è solo un tipo di azione consiste nel mandare un messaggio email.
Inoltre, tali azioni definiscono il modello da utilizzare per l\'invio della e-mail così come gli altri parametri del messaggio come, l\'importanza dei destinatari, etc
</p>
<p>Una Pagina speciale: <a href="../setup/email.test.php" target="_blank">email.test.php</a> è disponibile per il testing e la risoluzione dei problemi di configurazione PHP mail.</p>
<p>Per essere eseguite, le azioni devono essere associate ai trigger.
Quando è associata a un trigger, ad ogni azione è assegnato un numero "ordine", che specifica in quale ordine le azioni devono essere eseguite.</p>',
'UI:NotificationsMenu:Triggers' => 'Triggers',
'UI:NotificationsMenu:AvailableTriggers' => 'Triggers Disponibili',
'UI:NotificationsMenu:OnCreate' => 'When an object is created~~',
'UI:NotificationsMenu:OnStateEnter' => 'Quando un oggetto viene creato',
'UI:NotificationsMenu:OnStateLeave' => 'Quando un oggetto lascia un determinato stato',
'UI:NotificationsMenu:Actions' => 'Azioni',
'UI:NotificationsMenu:AvailableActions' => 'Azioni disponibili',
'Menu:AuditCategories' => 'Categorie di Audit',
'Menu:AuditCategories+' => '',
'Menu:Notifications:Title' => 'Categorie di Audit',
'Menu:RunQueriesMenu' => 'Esegui query',
'Menu:RunQueriesMenu+' => '',
'Menu:DataAdministration' => 'Dati di amministrazione',
'Menu:DataAdministration+' => '',
'Menu:UniversalSearchMenu' => 'Ricerca universale',
'Menu:UniversalSearchMenu+' => '',
'Menu:ApplicationLogMenu' => 'Log dell\'applicazione',
'Menu:ApplicationLogMenu+' => '',
'Menu:ApplicationLogMenu:Title' => 'Log dell\'applicazione',
'Menu:UserManagementMenu' => 'Gestione degli utenti',
'Menu:UserManagementMenu+' => '',
'Menu:ProfilesMenu' => 'Profili',
'Menu:ProfilesMenu+' => '',
'Menu:ProfilesMenu:Title' => 'Profili',
'Menu:UserAccountsMenu' => 'Account utente',
'Menu:UserAccountsMenu+' => '',
'Menu:UserAccountsMenu:Title' => 'Account utente',
'UI:iTopVersion:Short' => 'Versione iTop %1$s',
'UI:iTopVersion:Long' => 'Versione iTop %1$s-%2$s costruita il %3$s',
'UI:PropertiesTab' => 'Proprietà',
'UI:OpenDocumentInNewWindow_' => 'Apri questo documento in una nuova finestra: %1$s',
'UI:DownloadDocument_' => 'Scarica questo documento: %1$s',
'UI:Document:NoPreview' => 'Non è disponibile un\'anteprima per questo tipo di documento',
'UI:DeadlineMissedBy_duration' => 'Mancati %1$s',
'UI:Deadline_LessThan1Min' => '< 1 min',
'UI:Deadline_Minutes' => '%1$d min',
'UI:Deadline_Hours_Minutes' => '%1$dh %2$dmin',
'UI:Deadline_Days_Hours_Minutes' => '%1$dg %2$dh %3$dmin',
'UI:Help' => 'Aiuto',
'UI:PasswordConfirm' => '(Conferma)',
'UI:BeforeAdding_Class_ObjectsSaveThisObject' => 'Prima di aggiungere più %1$s oggetti, salva questo oggetto.',
'UI:DisplayThisMessageAtStartup' => 'Visualizza questo messaggio in fase di avvio',
'UI:RelationshipGraph' => 'Visualizzazione grafica',
'UI:RelationshipList' => 'Lista',
'UI:OperationCancelled' => 'Operazione Annullata',
'Portal:Title' => 'Portale Utente iTop',
'Portal:Refresh' => 'Ricarica',
'Portal:Back' => 'Indietro',
'Portal:WelcomeUserOrg' => 'Welcome %1$s, from %2$s',
'Portal:ShowOngoing' => 'Show open requests',
'Portal:ShowClosed' => 'Show closed requests',
'Portal:CreateNewRequest' => 'Crea una nuova richiesta',
'Portal:ChangeMyPassword' => 'Cambia la mia password',
'Portal:Disconnect' => 'Disconnetti',
'Portal:OpenRequests' => 'Le mie richieste aperte',
'Portal:ClosedRequests' => 'My closed requests',
'Portal:ResolvedRequests' => 'Le mie richieste risolte',
'Portal:SelectService' => 'Seleziona un servizio dal catalogo:',
'Portal:PleaseSelectOneService' => 'Si prega di selezionare un servizio',
'Portal:SelectSubcategoryFrom_Service' => 'Seleziona una sotto-categoria per il servizio %1$s:',
'Portal:PleaseSelectAServiceSubCategory' => 'Si prega di selezionare una delle sottocategorie',
'Portal:DescriptionOfTheRequest' => 'Inserisci la descrizione della tua richiesta:',
'Portal:TitleRequestDetailsFor_Request' => 'Dettagli per la richiesta %1$s:',
'Portal:NoOpenRequest' => 'Nessuna richiesta in questa categoria.',
'Portal:NoClosedRequest' => 'Nessuna richiesta in questa categoria.',
'Portal:Button:ReopenTicket' => 'Reopen this ticket',
'Portal:Button:CloseTicket' => 'Chiudi questo ticket',
'Portal:Button:UpdateRequest' => 'Update the request',
'Portal:EnterYourCommentsOnTicket' => 'Inserisci il tuo commento sulla risoluzione di questo ticket:',
'Portal:ErrorNoContactForThisUser' => 'Errore: l\'utente corrente non è associato ad un Contatto/Persona. Si prega di contattare l\'amministratore.',
'Portal:Attachments' => 'Allegati',
'Portal:AddAttachment' => ' Aggiungi allegati ',
'Portal:RemoveAttachment' => ' Rimuovi allegati ',
'Portal:Attachment_No_To_Ticket_Name' => 'Allegato #%1$d a %2$s (%3$s)',
'Enum:Undefined' => 'Non definito',
'UI:DurationForm_Days_Hours_Minutes_Seconds' => '%1$s Giorni %2$s Ore %3$s Minuti %4$s Secondi',
'UI:ModifyAllPageTitle' => 'Modifica Tutto',
'UI:Modify_N_ObjectsOf_Class' => 'Modifica %1$d oggetto della classe %2$s',
'UI:Modify_M_ObjectsOf_Class_OutOf_N' => 'Modifica %1$d oggetto della classe %2$s fuori da %3$d~~',
'UI:Menu:ModifyAll' => 'Modifica...',
'UI:Button:ModifyAll' => 'Modifica tutto',
'UI:Button:PreviewModifications' => 'Anteprima Modifiche >>~~',
'UI:ModifiedObject' => 'Oggetto Modificato',
'UI:BulkModifyStatus' => 'Operazioni',
'UI:BulkModifyStatus+' => '',
'UI:BulkModifyErrors' => 'Errori (eventuali)',
'UI:BulkModifyErrors+' => '',
'UI:BulkModifyStatusOk' => 'Ok',
'UI:BulkModifyStatusError' => 'Errore',
'UI:BulkModifyStatusModified' => 'Modificato',
'UI:BulkModifyStatusSkipped' => 'Saltato',
'UI:BulkModify_Count_DistinctValues' => '%1$d valori distinti:',
'UI:BulkModify:Value_Exists_N_Times' => '%1$s, %2$d volta(e)',
'UI:BulkModify:N_MoreValues' => '%1$d più valori...~~',
'UI:AttemptingToSetAReadOnlyAttribute_Name' => 'Tentativo di impostare il campo di sola lettura: %1$s',
'UI:FailedToApplyStimuli' => 'L\'azione non è riuscita.',
'UI:StimulusModify_N_ObjectsOf_Class' => '%1$s: Modifica %2$d oggetti della classe %3$s~~',
'UI:CaseLogTypeYourTextHere' => 'Digitare il tuo testo qui:',
'UI:CaseLog:DateFormat' => 'A-m-g H:m:s',
'UI:CaseLog:Header_Date_UserName' => '%1$s - %2$s:~~',
'UI:CaseLog:InitialValue' => 'Valore iniziale:',
'UI:AttemptingToSetASlaveAttribute_Name' => 'Il campo %1$s on è scrivibile, perché è comandato dalla sincronizzazione dei dati. Valore non impostato.',
'UI:ActionNotAllowed' => 'Non hai i permessi per eseguire questa azione su questi oggetti.',
'UI:BulkAction:NoObjectSelected' => 'Si prega di selezionare almeno un oggetto per eseguire questa operazione',
'UI:AttemptingToChangeASlaveAttribute_Name' => 'Il campo %1$s on è scrivibile, perché è comandato dalla sincronizzazione dei dati. Valore rimane invariato.',
'UI:Button:Refresh' => 'Ricarica',
));
?>

Some files were not shown because too many files have changed in this diff Show More