Compare commits

...

2340 Commits

Author SHA1 Message Date
Eric
a2ddb30f78 N°1420 - Autocomplete fix keyboard behavior (compatibility fix) 2018-12-19 17:39:35 +01:00
Eric
75fbb831c9 Fix Setup hardening 2018-12-19 17:10:02 +01:00
Molkobain
3219957eed Internal: Fix regression introduced during XSS protection on tag sets 2018-12-19 11:43:50 +01:00
Eric
44671a5085 Fix typos in configuration description 2018-12-19 09:02:49 +01:00
Purple Grape
bc4873dfe5 🌐 update 2.6 chinese translation and corresponding licences (#45)
* Update zh_cn.dict.authent-external.php

* Update zh_cn.dict.authent-ldap.php

* Update zh_cn.dict.authent-local.php

* Update zh_cn.dict.itop-attachments.php

* Update zh_cn.dict.itop-backup.php

* Update zh_cn.dict.itop-change-mgmt-itil.php

* Update zh_cn.dict.itop-change-mgmt.php

* Update zh_cn.dict.itop-config-mgmt.php

* Update zh_cn.dict.itop-config.php

* Update zh_cn.dict.itop-datacenter-mgmt.php

* Update zh.dict.itop-endusers-devices.php

* Update zh_cn.dict.itop-hub-connector.php

* Update zh_cn.dict.itop-incident-mgmt-itil.php

* Update zh_cn.dict.itop-knownerror-mgmt.php

* Update zh_cn.dict.itop-portal-base.php

* Update zh_cn.dict.itop-portal-base.php

* Update zh_cn.dict.itop-problem-mgmt.php

* Update zh_cn.dict.itop-request-mgmt-itil.php

* Update zh_cn.dict.itop-request-mgmt.php

* Update zh_cn.dict.itop-welcome-itil.php

* Update zh_cn.dict.itop-tickets.php

* Update zh_cn.dict.itop-service-mgmt-provider.php

* Update zh_cn.dict.itop-service-mgmt.php

* Update zh_cn.dictionary.itop.core.php

* Update zh_cn.dictionary.itop.ui.php
2018-12-18 18:11:20 +01:00
Eric
92657951c7 N°1408 - Dashboard Attribute (removed from "Properties" tab in edition) 2018-12-18 16:32:46 +01:00
Eric
8b2c18ab8c N°1420 - Autocomplete fix keyboard behavior 2018-12-18 16:00:29 +01:00
Pierre Goiffon
18999f29c5 🐛 Fix PHP syntax error in itop-chg-mgmt NL dict file 2018-12-18 15:30:23 +01:00
Pierre Goiffon
e8075bf5fd 🌐 Remove useless dict keys (see PR #38) 2018-12-18 15:24:17 +01:00
Pierre Goiffon
5338325a73 👥 Add contributor : jboesten / Jeffrey 2018-12-18 15:12:32 +01:00
Pierre Goiffon
4d3810a10d 🌐 New Dutch translations
Integrated directly from PR #38 as rebase and squash seems very difficult
Many thanks @jbostoen and @Hipska !
2018-12-18 15:10:38 +01:00
Pierre Goiffon
672bc471be N°1885 move back php-gd from mandatory extension to optional 2018-12-18 11:15:56 +01:00
Pierre Goiffon
3089cbc2bc 💡 Add some PhpDoc 2018-12-18 11:15:55 +01:00
Molkobain
ce9416d887 N°1878 Request Template: Fix history updated even if template not updated
When editing the object, the hidden input is not initialized correctly with the values from the form. This is due to a timing issue among async processes. To fix that, we made sure the WizardHelper updates the input value before submit. The real fix would be to better handle the subform building process.
2018-12-18 11:08:54 +01:00
Pierre Goiffon
473d1fb756 Fix 2.5 merge error 2018-12-17 17:12:30 +01:00
Pierre Goiffon
b880ca05a5 Merge remote-tracking branch 'origin/support/2.5' into release/2.6
# Conflicts:
#	composer.json
#	setup/setuputils.class.inc.php
2018-12-17 17:04:39 +01:00
Molkobain
cbc9784d21 N°1882 Internal: Fix regression on organization autocomplete (left menu) that could not be emptied 2018-12-17 16:46:39 +01:00
Pierre Goiffon
faba67b292 N°1885 add php-gd as a mandatory extension 2018-12-17 15:52:06 +01:00
Molkobain
16cb1bbbbf N°1843 Portal: Fix inline images being displayed too large sometimes in forms 2018-12-17 15:27:15 +01:00
Molkobain
a1c2b809ba 🌐 N°1839 Update translations for TriggerOnThresholdReached 2018-12-17 15:27:15 +01:00
Stephen Abello
c9691457b8 Prepare datamodels' versions for 2.6.0 release 2018-12-17 15:10:37 +01:00
“purplegrape”
9828b905b2 rename chinese translation file from zh.dict*php to zh_cn.dict*php .
in case guys from HongKong ,TaiWan or Singapore wana have their own translations.
2018-12-17 11:16:25 +01:00
Molkobain
9ef6c78395 N°1637 Portal: Add form mode (create/edit/view) to information passed to iPopupMenuExtension on object details 2018-12-17 09:53:13 +01:00
Molkobain
81f70c4c58 N°1637 Portal: Add CSS/JS hook on object forms (form mode: create/edit/view) 2018-12-17 09:51:47 +01:00
Molkobain
869f590bf4 N°657 Portal: Fix modal not closing when pressing "esc" key 2018-12-14 19:06:14 +01:00
Molkobain
3b6aa7eaf5 N°1879 Additional fix for default print format of dashboards 2018-12-14 17:31:43 +01:00
Molkobain
53ef2b0b5d N°1171 Portal: Add CSS/JS hooks in navigation menu to identify bricks 2018-12-14 17:26:55 +01:00
Molkobain
4dfe6fc817 N°1220 Portal: Fix logo displayed not wide enough when it has a small height 2018-12-14 17:06:37 +01:00
Molkobain
260143050e N°1880 Fix logo url not pointing to the portal home page instead of the 'app_icon_url' parameter's value 2018-12-14 17:01:22 +01:00
Molkobain
6adde38399 N°1880 Fix logo url not pointing to the portal home page instead of the 'app_icon_url' parameter's value 2018-12-14 16:54:51 +01:00
Molkobain
76a40b2f45 N°1879 Change default print format for dashboards to "A4 Landscape" 2018-12-14 16:03:56 +01:00
Denis Flaven
77c2537df7 Zoom-in cursor on zoomable images
(for browsers supporting the zoom-in cursor: i.e. not IE)
2018-12-14 15:12:52 +01:00
Molkobain
6a88f622ad N°1839 Update TriggerOnThresholdReached to select attribute from a set of valid attributes instead of typing it manually 2018-12-14 11:51:14 +01:00
Molkobain
9b5d8b8a01 N°931 Fix bug when max allowed items set to 1 2018-12-14 11:11:59 +01:00
Molkobain
b4448c5bb9 Code cleanup 2018-12-14 10:00:29 +01:00
Denis Flaven
7faf3258f7 Setup hardening. 2018-12-13 18:12:58 +01:00
Denis Flaven
cb3440c85d Setup hardening. 2018-12-13 18:12:03 +01:00
Denis Flaven
7c0d03ea3b Cosmetics on setup (Licenses prompt)
Limit the height of the list of licences (displaying a scrollbar if
needed) so that the page fits on screen.
2018-12-13 12:12:28 +01:00
Denis Flaven
d1837377a4 Merge branch 'release/2.6' of https://github.com/Combodo/iTop.git into release/2.6 2018-12-13 11:47:41 +01:00
Denis Flaven
1c3a503a82 N°1872 Regression when editing query phrasebook entries. Fixed. 2018-12-13 11:46:39 +01:00
Molkobain
daafa9123c N°1852 Fix loss of inline images and attachments when user has been logged off 2018-12-13 11:35:00 +01:00
Molkobain
5a1b6e43c9 N°1835 Internal: Fix regression introduced by commit 36d47c2 2018-12-13 11:18:25 +01:00
Molkobain
81d502cae8 N°1835 Internal: Fix regression introduced by commit 36d47c2 2018-12-12 20:56:07 +01:00
Molkobain
4a99ed2ad8 N°1835 Internal: Fix regression introduced by commit 36d47c2 2018-12-12 19:51:06 +01:00
Vladimir Kunin
7016724abc Show resolution_date in resolved problem details. 2018-12-12 11:38:07 +01:00
Molkobain
0a8e3f099e N°1864 Portal: Add notification placeholders for portal links in edit or view mode 2018-12-12 10:04:00 +01:00
Pierre Goiffon
45910dc115 Merge remote-tracking branch 'origin/support/2.5' into release/2.6
# Conflicts:
#	datamodels/2.x/itop-config-mgmt/zh.dict.itop-config-mgmt.php
#	dictionaries/zh.dictionary.itop.ui.php
2018-12-11 17:23:34 +01:00
Pierre Goiffon
afd6428411 💡 @var on iApplicationObjectExtension calls 2018-12-11 17:19:52 +01:00
Eric
7eb419507b N°1420 - Perf autocomplete (remove almost duplicated requests) 2018-12-11 16:39:57 +01:00
Eric
8400eb910f N°1420 - Perf autocomplete (remove almost duplicated requests) 2018-12-11 16:35:31 +01:00
Eric
b38d33d7a6 N°1420 - Perf autocomplete (remove almost duplicated requests) 2018-12-11 16:23:08 +01:00
Pierre Goiffon
b4a6d378ab N°1827 fix freeze on object creation when changing dependant field, if object has hidden TagSet field 2018-12-11 15:54:33 +01:00
Eric
44b7821015 N°1846 - Fix Object Copier: Create Ticket from CI, duplicate links 2018-12-11 15:26:24 +01:00
Pierre Goiffon
52ac819c1f N°1835 wooops fix previous commit 2018-12-11 10:25:48 +01:00
Pierre Goiffon
c4ba1d55ac 🔊 N°1835 log error when transaction_id invalid in UI.php 2018-12-11 10:09:50 +01:00
Molkobain
85acac60c7 💪 Fix execution notice 2018-12-11 09:54:09 +01:00
Purple Grape
23ee8d6a14 Update zh.dict.itop-config-mgmt.php
add two empty lines against english  ,small translation improvement
2018-12-11 09:16:38 +01:00
Pierre Goiffon
2154916848 ZH translation : remove unecessary '~~' 2018-12-11 09:08:40 +01:00
Purple Grape
d3fd81545a Update zh.dictionary.itop.ui.php
fix one line missing and small translation improvement
2018-12-11 09:06:22 +01:00
Molkobain
f54da5f9a6 Internal: Debug trace when InlineImage::FinalizeInlineImages() fails to retrieve transaction ID 2018-12-10 17:44:49 +01:00
Pierre Goiffon
36d47c2274 N°1835 fix transaction_id lost with session
* transaction_id are now stored by default in file instead of session ("transaction_storage" config parameter : default value was 'Session', it is now 'File')
* session_regenerate_id() call can be disabled using "regenerate_session_id_enabled" config parameter
* new 'transaction_id' parameter type to allow dots (with a file storage, transaction_id equals the temp file name and on Windows we're getting *.tmp)
2018-12-10 17:39:07 +01:00
Eric
bd082c0a6e N°917 - Rolled back fields to AttributeText until AttributeQueryAttCodeSet can manage fields order correctly 2018-12-10 15:25:22 +01:00
Stephen Abello
fb028710e0 Datamodel viewer: Fix an issue where OQL Filters were truncated 2018-12-10 15:10:58 +01:00
Stephen Abello
29dd196193 N°1848: Fix timeout regression on impact analysis' tooltip 2018-12-10 10:01:48 +01:00
Pierre Goiffon
80a8f7a888 Update translation files 2018-12-10 08:46:02 +01:00
Pierre Goiffon
7f497fe3be Merge remote-tracking branch 'origin/support/2.5' into release/2.6
# Conflicts:
#	datamodels/2.x/itop-attachments/zh.dict.itop-attachments.php
#	datamodels/2.x/itop-backup/zh.dict.itop-backup.php
#	datamodels/2.x/itop-change-mgmt-itil/zh.dict.itop-change-mgmt-itil.php
#	datamodels/2.x/itop-change-mgmt/zh.dict.itop-change-mgmt.php
#	datamodels/2.x/itop-config-mgmt/es_cr.dict.itop-config-mgmt.php
#	datamodels/2.x/itop-config-mgmt/zh.dict.itop-config-mgmt.php
#	datamodels/2.x/itop-config/zh.dict.itop-config.php
#	datamodels/2.x/itop-datacenter-mgmt/zh.dict.itop-datacenter-mgmt.php
#	datamodels/2.x/itop-hub-connector/zh.dict.itop-hub-connector.php
#	datamodels/2.x/itop-incident-mgmt-itil/zh.dict.itop-incident-mgmt-itil.php
#	datamodels/2.x/itop-knownerror-mgmt/zh.dict.itop-knownerror-mgmt.php
#	datamodels/2.x/itop-portal-base/zh.dict.itop-portal-base.php
#	datamodels/2.x/itop-problem-mgmt/es_cr.dict.itop-problem-mgmt.php
#	datamodels/2.x/itop-problem-mgmt/zh.dict.itop-problem-mgmt.php
#	datamodels/2.x/itop-request-mgmt-itil/es_cr.dict.itop-request-mgmt-itil.php
#	datamodels/2.x/itop-request-mgmt-itil/zh.dict.itop-request-mgmt-itil.php
#	datamodels/2.x/itop-request-mgmt/es_cr.dict.itop-request-mgmt.php
#	datamodels/2.x/itop-request-mgmt/zh.dict.itop-request-mgmt.php
#	datamodels/2.x/itop-service-mgmt-provider/zh.dict.itop-service-mgmt-provider.php
#	datamodels/2.x/itop-service-mgmt/zh.dict.itop-service-mgmt.php
#	datamodels/2.x/itop-tickets/zh.dict.itop-tickets.php
#	datamodels/2.x/itop-welcome-itil/zh.dict.itop-welcome-itil.php
#	dictionaries/zh.dictionary.itop.core.php
#	dictionaries/zh.dictionary.itop.ui.php
2018-12-10 08:38:19 +01:00
Molkobain
59570f3a21 Update spanish translations (thanks to Miguel Turrubiates) 2018-12-07 19:32:27 +01:00
Eric
53fe826f9f Autocomplete: Prevent the RETURN key to submit form if no value is set 2018-12-07 16:06:52 +01:00
Molkobain
56b4ecb4ce 🌐 Update spanish translations (thanks to Miguel Turrubiates! ✌) 2018-12-07 14:25:17 +01:00
Pierre Goiffon
d17717e4b5 👥 Add @purplegrape to the contributor's list (PR #24, thank you !) 2018-12-07 11:23:55 +01:00
Molkobain
68da3a4aad Change default attachments (and inline images) lifetime to 1 day instead of 1 hour 2018-12-07 11:16:41 +01:00
Molkobain
855480fd7b PHPDoc 2018-12-07 11:16:41 +01:00
Pierre Goiffon
79200e8f96 🙈 Update gitignore to handle toolkit symlinks 2018-12-07 11:13:51 +01:00
Purple Grape
7d43ae40b8 Support/2.5 (#24)
* Update zh.dict.authent-ldap.php

* Update zh.dict.authent-local.php

* Create zh.dict.itop-attachments.php

* Create zh.dict.itop-backup.php

* Update zh.dict.itop-change-mgmt-itil.php

* Create zh.dict.itop-change-mgmt.php

* Update zh.dict.itop-config-mgmt.php

* Create zh.dict.itop-config.php

* Create zh.dict.itop-datacenter-mgmt.php

* Create zh.dict.itop-hub-connector.php

* Create zh.dict.itop-incident-mgmt-itil.php

* Update zh.dict.itop-knownerror-mgmt.php

* Create zh.dict.itop-portal-base.php

* Update zh.dict.itop-problem-mgmt.php

* Create zh.dict.itop-request-mgmt-itil.php

* Create zh.dict.itop-request-mgmt.php

* Create zh.dict.itop-service-mgmt-provider.php

* Update zh.dict.itop-service-mgmt.php

* Update zh.dict.itop-tickets.php

* Update zh.dict.itop-welcome-itil.php

* Update zh.dictionary.itop.ui.php

* Update zh.dictionary.itop.core.php
2018-12-07 10:38:50 +01:00
Denis Flaven
540bc3a54b Newsroom finalization & integration tests. 2018-12-06 15:38:29 +01:00
Stephen Abello
35752a8041 N°1837: Internal: fix regression on data synchronized attributes display 2018-12-06 15:05:13 +01:00
Molkobain
2baa95ff6d N°1841 Portal: Service catalog items not collapsed / expended as expected 2018-12-06 10:43:25 +01:00
Lars Hippler
86dce21849 Some small typo fixes in German translations
Fix typo in German dashlet translations (Group by sum)
Fix typo in German translation (config-saved)
2018-12-06 08:51:42 +01:00
Pierre Goiffon
fca5a625d2 🐛 N°1834 Query Phrasebook : fix fields dictionary key 2018-12-05 16:58:34 +01:00
Eric
2766fad61a Autocomplete: select automatically the first entry with the RETURN key 2018-12-05 12:01:32 +01:00
Pierre Goiffon
c6da1db72b 🔒 N°1802 add auth to check-backup.php 2018-12-05 11:37:42 +01:00
Pierre Goiffon
843c06b007 🚸 improves backup/check-backup
* backup.php now handles calls from datamodels (approot)
* fix check-backup sample cli
* better error on check-backup invalid check_ticket_itop cli parameter
2018-12-05 11:37:42 +01:00
Pierre Goiffon
7cf7628b8f 🔧 N°1802 update backup.params.distrib 2018-12-05 11:18:49 +01:00
Pierre Goiffon
41b096ba76 🔧 N°1802 rename itop_root config file parameter to itop_backup_incident 2018-12-05 10:45:14 +01:00
Eric
2a4bd4b0dc 💚 N°1825 - Fix ormset control when no limit 2018-12-05 10:10:45 +01:00
Eric
f4f5281769 💚 N°1825 - Fix tagset control when no limit 2018-12-05 10:08:40 +01:00
Eric
a4a09cd8c7 N°1825 - Fix TagSet code numeric generate a Fatal Error 2018-12-05 09:39:41 +01:00
Eric
831b18b4d2 Force the number of Tags in ormTagSet 2018-12-05 09:04:30 +01:00
Eric
e4e5f627c4 Display error log if UpdateObjectFromPostedForm fails when modifying an object in console 2018-12-05 09:04:30 +01:00
Denis Flaven
53e532cbaf 🐛 N°1822 fix for the autocomplete on IE.
Support of some accents (western languages) on IE, complete support of
all unicode accents on browsers supporting String.normalize.
2018-12-04 15:07:46 +01:00
Eric
3fa0cbf0fe Merge remote-tracking branch 'origin/support/2.5' into release/2.6 2018-12-04 14:57:56 +01:00
Eric
6450d2339f N°1826 - Fix Error in PDF export with php 7.1 2018-12-04 14:55:57 +01:00
Eric
af8b06dda6 💚 Display error log instead of fatal error in case of Exception when modifying an object in console 2018-12-04 11:33:32 +01:00
Stephen Abello
72e2473444 N°1811: Fix regression in impact analysis: misplaced tooltips on Chrome 2018-12-04 10:58:49 +01:00
Eric
6e31a040b2 Display error log instead of fatal error in case of Exception when modifying an object in console 2018-12-04 10:49:30 +01:00
Molkobain
0c8dd6fd1b N°562 Notifications: Add support for placeholders in HTML hyperlinks (regular href, mailto, ...) 2018-12-04 10:22:31 +01:00
Pierre Goiffon
6c07688c34 N°1815 TagSet widget : change filter callback to an anonymous function, fix String obj conversion bug 2018-12-04 09:53:45 +01:00
Pierre Goiffon
598c22a285 🏁 N°1815 fix tagset widget parse error in MSIE all versions 2018-12-03 17:31:57 +01:00
Denis Flaven
d392b9c0f6 Adaptation of the Hub URLs for the newsroom. 2018-12-03 17:26:22 +01:00
Eric
387c166985 Fix Remote User synchro 2018-12-03 11:33:15 +01:00
Stephen Abello
9115bc118d 🌐 N°1809: Refactor Triggers' help section and add new triggers description 2018-12-03 11:26:23 +01:00
Eric
aca11ac966 Fix AttributeSet wrong error on number of tags in creation 2018-12-03 11:01:54 +01:00
Eric
c15d626095 Fix AttributeSet history database field size (was too short) 2018-12-03 09:27:56 +01:00
Molkobain
79d00b9fe6 Add CONTRIBUTING.md 2018-12-03 08:31:59 +01:00
Pierre Goiffon
a92e2fd882 📦 Update datamodels versions from 2.5.0 to 2.6.0 2018-11-30 18:25:20 +01:00
Eric
7ed51984c7 N°944 - Fix bad xml when attributes name has been changed and redefinition of label is required and cache is regenerated 2018-11-30 14:28:26 +01:00
Pierre Goiffon
cdf11a3485 GitFlow autoconfig file 2018-11-30 11:39:20 +01:00
Eric
bbefd22950 Version 2.6.0 2018-11-29 09:19:55 +01:00
Eric
e08369122d Merge remote-tracking branch 'origin/support/2.5' into release/2.6
# Conflicts:
#	core/config.class.inc.php
#	css/css-variables.scss
#	css/light-grey.css
2018-11-29 09:10:34 +01:00
Eric
0ce0572c40 N°1783 - Search : fix error when searching for a quote in a text field 2018-11-28 14:52:51 +01:00
Molkobain
9d19556419 Internal: Remove wrongly added default search criterion on FAQ (Introduced in commit 5f7e8c9) 2018-11-28 14:52:51 +01:00
Molkobain
67c0e0eb1c Fix iTop version that stayed to "2.5.0-beta" for the release 2018-11-28 14:52:50 +01:00
Pierre Goiffon
c5d0dd05b9 🔒 N°1802 itop-backup : move iTop root to config file 2018-11-28 14:49:49 +01:00
Molkobain
4e1f877ab4 Internal: Add new Person in the sample data to welcome Alexia a.k.a "Simone de Beauvoir"! 👋 2018-11-28 14:41:58 +01:00
Eric
0e0d254188 N°1783 - fix unit tests 2018-11-28 14:41:08 +01:00
Eric
992421292c N°1783 - Search : fix error when searching for a quote in a text field 2018-11-28 14:26:13 +01:00
Eric
47cb4feeeb N°1783 - Search : fix error when searching for a quote in a text field 2018-11-28 14:16:03 +01:00
Molkobain
76acd8fe9e Internal: Remove wrongly added default search criterion on FAQ (Introduced in commit 5f7e8c9) 2018-11-28 10:07:05 +01:00
Molkobain
961b1570e8 Fix iTop version that stayed to "2.5.0-beta" for the release 2018-11-27 17:57:15 +01:00
Molkobain
88dea990e1 (Cherry pick from revision 19d4de4) N°1737 Fix tags sanitization in search criteria 2018-11-27 17:57:15 +01:00
Molkobain
19d4de482d N°1737 Fix tags sanitization in search criteria 2018-11-27 17:43:21 +01:00
Pierre Goiffon
d2505d15fe 🔒 N°1802 itop-backup : move iTop root to config file 2018-11-27 11:09:14 +01:00
Eric
122c3a9542 N°1779 - Fix Excel Export from a search result when object contains AttributeDashboard 2018-11-27 10:11:01 +01:00
Eric
15d9ba9906 N°917 - Add AttributeSubItem to the exclusion list of the trigger attributes 2018-11-27 09:36:50 +01:00
Eric
95a22a1a7e N°1799 - Fix TTO and TTR not recomputed when change on priority 2018-11-27 09:36:50 +01:00
Pierre Goiffon
5309aa225a Merge remote-tracking branch 'origin/support/2.5' into release/2.6
# Conflicts:
#	application/utils.inc.php
#	js/dashboard.js
#	pages/ajax.render.php
2018-11-26 18:28:42 +01:00
Eric
c0cd450c5f Add the user_id to the log_kpi instead of * 2018-11-26 15:26:25 +01:00
Eric
d831549c7b Add User Id on KPI 2018-11-26 15:24:38 +01:00
Pierre Goiffon
0f20f9ca5d 🔒 N°1795 prevent CSRF on dashboard import 2018-11-26 15:17:53 +01:00
Pierre Goiffon
d5568afc68 🔒 N°1795 prevent XSS on some fields 2018-11-23 18:00:26 +01:00
Pierre Goiffon
44d7abac6e 🎨 check-backup : improve code readability
move exit conditions on top to avoid if/else nightmare
2018-11-23 17:58:21 +01:00
Denis
1b4b71cb35 Prevent a catchable fatal error when using memcache(d) as the session handler (regression introduced when fixing n°1778). 2018-11-23 16:56:07 +01:00
Pierre Goiffon
f37f3c4c22 iconv was missing (used in export) 2018-11-23 16:35:46 +01:00
Pierre Goiffon
83b3fb80d5 🎨 N°659 uniqueness constraint : more possibilities to customize check
* 2 methods called per rule instead of only one
* now we're getting the rule id as parameter
2018-11-23 16:35:46 +01:00
Pierre Goiffon
c242f90440 N°659 uniqueness constraint : fix class used in the dict key for the error message
It has to be the rule root class, not the current class
2018-11-23 09:44:42 +01:00
Pierre Goiffon
e4912ee175 🎨 PhpDoc
(cherry picked from commit d3aeb807d433e656df22f166387230b431656f58)
2018-11-22 17:40:37 +01:00
Molkobain
83e1f35f9c N°1792 Fix error message in browser console "Failed to load resource: ERR_INVALID_URL" 2018-11-22 16:59:08 +01:00
Denis Flaven
c42333d085 N°1718 Make attribute image zoomable 2018-11-22 16:06:23 +01:00
Eric
c4c0b0f630 💄 rework of the slider button 2018-11-22 15:24:30 +01:00
Eric
aec3c34eea N°1787 - Fix execution warning 2018-11-22 14:17:45 +01:00
Molkobain
c4ff20b9fb N°1789 Internal: Fix regression introduced in 6a6c069 2018-11-22 10:49:02 +01:00
Molkobain
c7ce35a877 Merge branch 'release/2.6' of https://github.com/Combodo/iTop into release/2.6 2018-11-22 10:36:27 +01:00
Denis Flaven
5ccfa24b27 iTop Newsroom implementation - painfully merged manually... 2018-11-21 19:36:51 +01:00
Molkobain
1c6a6edf5a Merge branch 'release/2.6' of https://github.com/Combodo/iTop into release/2.6 2018-11-21 18:50:29 +01:00
Pierre Goiffon
a659de9c9b Merge remote-tracking branch 'origin/support/2.5' into release/2.6
# Conflicts:
#	datamodels/2.x/itop-portal-base/portal/src/controllers/browsebrickcontroller.class.inc.php
2018-11-21 18:14:13 +01:00
Molkobain
8530db347b N°1788 Portal: Fix regression, icons not displayed in service catalog (introduced in ab1715ed) 2018-11-21 17:35:33 +01:00
Molkobain
29e28dedf1 Internal: Fix SASS to CSS convert for urls with query string (parameters after the "?") 2018-11-21 17:16:57 +01:00
Molkobain
3aed65c921 (cherry picked from 854bb81) N°1779 Fix none draggable columns in exports (Excel, CSV, ...)
- Fix AjaxWebPage load of linked stylesheets
- Remove unnecessary imports of JS/CSS files
2018-11-21 16:13:11 +01:00
Molkobain
0acc0b4a74 PHPDoc 2018-11-21 16:09:16 +01:00
Molkobain
c300e46480 N°1779 Fix none draggable columns in exports (Excel, CSV, ...)
- Fix AjaxWebPage load of linked stylesheets
- Remove unnecessary imports of JS/CSS files
2018-11-21 15:55:45 +01:00
Eric
0a3f076335 1784 - Fix Toolkit error on decimals 2018-11-21 15:11:19 +01:00
Eric
12d9551845 N°1706 - Fix error display when object cannot be saved 2018-11-21 14:26:50 +01:00
Vladimir Kunin
0d6c799f9c RU: name_brand iqueness rule and type phone in Model; person is mandatory error in User; all core attributes. 2018-11-21 14:22:46 +01:00
Eric
a395f5b63c N°1583 - No filter applied if only one org defined 2018-11-21 11:25:24 +01:00
Eric
cf0ad59ec5 N°1754 - Linkset and CheckToWrite: Loss of links on error during creation 2018-11-21 10:34:06 +01:00
Eric
2e46fa50b3 🌐 Update dictionaries with new missing entries 2018-11-21 10:25:58 +01:00
Molkobain
5a30a3dcb3 N°1750 Portal: Fix broken attachment preview and link on object creation (worked on object edition) 2018-11-21 10:08:27 +01:00
Eric
f9bb2e7a14 💚 N°1583 - user_manager User cannot create a User without Contact (fixed CI) 2018-11-20 18:03:08 +01:00
Eric
57e8b9faaf N°1583 - user_manager User cannot create a User without Contact 2018-11-20 15:43:05 +01:00
chifu1234
c737b83eb5 Update metamodel.class.php (Cherry picked from branch develop 91f1598) 2018-11-20 15:22:59 +01:00
Pierre Goiffon
5c91a1a612 🌐 RU for itop-config-mgmt : put back 2 missing keys for name_brand uniqueness rule in Model class 2018-11-20 11:53:13 +01:00
Pierre Goiffon
0c49641094 N°659 Uniqueness rules : description and error message are now picked in dictionaries entries with the $sClassName/UniquenessRule:$sUniquenessRuleId convention 2018-11-20 11:42:25 +01:00
Molkobain
99e909dae4 N°1702 Change "description" & "error_message" properties from hardcoded string to dictionary entries
New convention is:
- Class:<class>/UniquenessRule:<rule_code> for the error message
- Class:<class>/UniquenessRule:<rule_code>+ for the description of the rule itself
2018-11-19 18:18:35 +01:00
Molkobain
ecf34b47cb Code cleanup 2018-11-19 12:17:35 +01:00
Molkobain
949b4495fc Revert "Code cleanup" from commit ac89b2d 2018-11-19 12:16:22 +01:00
Eric
bd7e0174f3 🎨 Code refactor proposed by jbostoen 2018-11-19 11:31:57 +01:00
Molkobain
ac89b2dc44 Code cleanup 2018-11-19 11:28:38 +01:00
Molkobain
7e3fceb7dc N°1758 Fix read only attributes on bulk apply stimulus 2018-11-16 17:42:21 +01:00
Eric
b28ed08a85 🐎 N°1668 - Perf: avoid object update parse hidden LinkedSet attribute 2018-11-16 17:27:42 +01:00
Stephen Abello
a488c42dca N°721: ResolveFrom now only set attributes mandatory in resolved & closed states that aren't already set 2018-11-16 17:20:11 +01:00
Pierre Goiffon
62bc6714e0 N°1746 add another log in CK image upload : when mime type is not an image 2018-11-16 15:24:15 +01:00
Eric
9c9ebeeceb N°1763 - Fix autocomplete and accents 2018-11-16 15:17:49 +01:00
Molkobain
fb233709e0 Search: Fix search submit after closing an empty criterion 2018-11-16 11:37:48 +01:00
Eric
9169cced20 Merge remote-tracking branch 'origin/support/2.5' into release/2.6 2018-11-16 11:33:33 +01:00
Eric
9ceb8e9f0b N°1765 - Fix Organization filter and UNION filter in ExternalKey search 2018-11-16 11:31:36 +01:00
Eric
1db9708624 Merge remote-tracking branch 'origin/support/2.5' into release/2.6 2018-11-16 10:36:24 +01:00
Eric
5cedcb2389 N°1620: Fix 'forgot your password?' error when resetting password 2018-11-16 10:34:12 +01:00
Molkobain
52b42d0210 PHPDoc 2018-11-16 09:31:24 +01:00
Kamil Konečný
67f5f09530 Title field XSS vulnerability solution. 2018-11-16 08:59:50 +01:00
Eric
b9e0747825 N°1074 - ExternalField default label is now "key_name->label" 2018-11-15 17:33:42 +01:00
Eric
e44ed248ef N°1659 - Don't use anymore the current organization in the external key search (and n-n) 2018-11-15 17:07:31 +01:00
Stephen Abello
b0c120d7fd N°1728: Display error on setup for unsupported MySQL 8+ versions (MariaDB & Percona not affected) 2018-11-15 15:04:44 +01:00
Molkobain
177b6d1757 N°1750 Portal: Fix broken attachment preview and link on object creation (worked on object edition) 2018-11-15 14:29:52 +01:00
Eric
ff39b7bc51 N°1759 - Fix setup error on abstract class not existing 2018-11-15 10:59:28 +01:00
Eric
7401e88844 N°1408 - Dashboard Attribute (tab order) 2018-11-14 17:56:02 +01:00
Eric
b1e1e29254 N°244 - Object Copier: copy attachments 2018-11-14 17:20:40 +01:00
Eric
ffac3250af N°1408 - Dashboard Attribute (removed from "Properties" tab) 2018-11-14 17:20:40 +01:00
Eric
e9fb885d34 N°1408 - Dashboard Attribute (dictionary) 2018-11-14 17:20:40 +01:00
Eric
b87037d187 code cleanup 2018-11-14 17:20:40 +01:00
Pierre Goiffon
a97680fb04 N°931 fix TagSet regression (not displayed correctly in the console)
introduced in f9b2fda092
2018-11-14 15:37:08 +01:00
Stephen Abello
798e526010 N°1758: Fix regression on bulk transition due to filter format changes 2018-11-14 15:25:27 +01:00
Stephen Abello
d344478b48 N°1408: Fix AttributeDashboard for portal 2018-11-14 12:11:42 +01:00
Stephen Abello
b898a09c4c N°1728: Display error on setup for unsupported MySQL 8+ versions (MariaDB & Percona not affected) 2018-11-14 10:13:08 +01:00
Pierre Goiffon
17589e060a Merge branch 'support/2.5' into release/2.6 2018-11-14 10:04:29 +01:00
Pierre Goiffon
7e4f235c59 N°1761 fix MetaModel class not found when calling utils method 2018-11-14 10:04:15 +01:00
Molkobain
7867cc1dca N° 688 Portal: Fix enum attributes sort order in ManageBrick (eg. Ongoing requests). Now sorted by code like in the admin. console 2018-11-13 19:31:46 +01:00
Molkobain
114b18d7c8 Portal: Add HTML hooks in object forms to know object's class and ID (useful for CSS /JS hacks) 2018-11-13 16:01:19 +01:00
Eric
5baff6257b N°1754 - Linkset and CheckToWrite: Loss of links on error during creation 2018-11-13 15:37:10 +01:00
Pierre Goiffon
8264d21520 Add Nould to contributors list (PR #20) 2018-11-13 14:48:14 +01:00
Kamil Konečný
8bd10a2d11 Session id regeneration on login. 2018-11-13 14:28:08 +01:00
jbostoen
cce88f09b0 Versoin 20181113-1219
* additional strings
2018-11-13 13:40:57 +01:00
Lars Hippler
26475ad10f Add missing German translations related to 4072ed0 2018-11-13 13:40:01 +01:00
Molkobain
c1a81e4f0d N°944 Fix wrong XML generated when attribute name has been changed and redefinition of label is required 2018-11-13 11:48:27 +01:00
Vladimir Kunin
4a5cb23730 Add Russian translations for TagSetFieldData fields 2018-11-13 11:26:39 +01:00
Eric
f0e5128fb5 N°1740 - Class Query invalid Datamodel - Attention: Setup mandatory when applying this (core datamodel migration) 2018-11-13 11:18:10 +01:00
Eric
63b08b0e70 Merge remote-tracking branch 'origin/support/2.5' into release/2.6
# Conflicts:
#	sources/application/search/searchform.class.inc.php
2018-11-13 11:11:15 +01:00
Pierre Goiffon
4072ed09ac N°931 TagSet : add missing translations for TagSetFieldData fields 2018-11-13 10:55:46 +01:00
Eric
c722d64850 N°1706 - Fix problem with user_manager profile 2018-11-13 08:50:49 +01:00
Molkobain
70137808f0 PHPDoc 2018-11-12 21:36:03 +01:00
Stephen Abello
36ade3b15c N°1727: Fix non disappearing tooltip for mandatory HTML field 2018-11-12 17:42:56 +01:00
Vladimir Kunin
6b5f32611d Russian lang for 2.6-beta 2018-11-12 11:36:43 +01:00
Pierre Goiffon
43bfe06882 Merge branch 'support/2.5' into release/2.6 2018-11-09 17:39:17 +01:00
Pierre Goiffon
6f79c16ba0 N°1746 add a log when CK image upload fails 2018-11-09 17:39:03 +01:00
Eric
29df8f8f92 N°1737 - Tags HTML sanitization for display of labels 2018-11-09 10:09:42 +01:00
Eric
216d965d76 N°1724 - Fix external key search error when an UNION is used as a filter in the datamodel 2018-11-09 09:13:59 +01:00
Eric
95fce0eefb Fix audit bug (DBUnionSearch::AddConditionForInOperatorUsingParam() does not exist) when category is a UNION and rule flag 'Valid objects?' is 'true' and there are invalid entries in the result of the audit. 2018-11-09 09:13:18 +01:00
Eric
841127c131 N°828 - GetSelectFilter issue with DBUnionSearch 2018-11-09 09:11:25 +01:00
Eric
405b1b8e6f N°917 - Trigger on object update: limit the fields proposed to the ones that can be updated 2018-11-08 14:36:15 +01:00
Eric
b050210737 N°1374 - Fix TTR deadline wrong value when re-assigning overdue tickets outside open hours 2018-11-08 08:55:48 +01:00
Eric
ed02e3522e code cleanup 2018-11-08 08:55:48 +01:00
Eric
a327b5fb5e Allow an alternative SQL generation from OQL (same as 2.3.0) 2018-11-08 08:55:48 +01:00
Pierre Goiffon
f9b2fda092 N°931 fix link for TagSet in portal lists
- they were linking to a console search
- now will filter the list using the label
2018-11-07 18:06:59 +01:00
Molkobain
0d082bf378 N°1487 Search: Removing an empty criterion doesn't refresh the results anymore 2018-11-07 14:44:37 +01:00
steffunky
d8cef95d56 N°1639: Add white-space style to CKEditor whitelist 2018-11-07 12:15:10 +01:00
steffunky
2258e8c652 N°1650: Add vertical-align style to CKEditor whitelist 2018-11-07 12:14:47 +01:00
Molkobain
5e19d338b9 N°1537 Fix "Demandeur" not updated on Change objects in french version only.
caller_id and requestor_id had the same labels which was misleading in transitions.
2018-11-07 11:36:11 +01:00
Molkobain
14ecfc4ce8 Add Jeffrey Bostoen, larhip & chifu1234 to the contributors list! Many thanks to them 🙌 2018-11-07 11:10:59 +01:00
steffunky
170d84d635 N°1061: Remove bold on "auto_select" lines in setup "ready to install" step 2018-11-07 10:08:55 +01:00
Lars Hippler
a962f6535e Add German translations regarding release 2.6
especially AttributeTag, AttributeOverview and uniqueness rules translations
2018-11-07 09:30:20 +01:00
Pierre Goiffon
a4055c4a74 Change comments to use same tickets ref syntax 2018-11-06 17:36:14 +01:00
Molkobain
9ed550ee7f N°562 Notifications: Add support for placeholders in HTML hyperlinks (regular href, mailto, ...) 2018-11-06 17:35:17 +01:00
steffunky
00bd7583f7 N°1053: Set the first day of the week on date/time picker to a language based setting
* Update moment.js
* Add locales to moment.js
* Align console & portal on the same moment.js library
2018-11-06 11:06:07 +01:00
Eric
e4619fbc0f N°1724 - Fix external key search error when an UNION is used as a filter in the datamodel 2018-11-06 10:01:36 +01:00
Eric
518d94f5f3 Fix audit bug (DBUnionSearch::AddConditionForInOperatorUsingParam() does not exist) when category is a UNION and rule flag 'Valid objects?' is 'true' and there are invalid entries in the result of the audit. 2018-11-06 08:49:35 +01:00
Eric
389a1791d7 N°828 - GetSelectFilter issue with DBUnionSearch 2018-11-06 08:49:35 +01:00
Thomas Casteleyn
54eb41b66f Fix typo Incident Impact (report PR#10)
(cherry picked from commit 676b83519a)
2018-11-05 17:00:20 +01:00
Pierre Goiffon
ede2673ba5 Fix uniqueness PHPUnit tests - 2nd commit (forgot to change annotation) 2018-11-05 16:02:15 +01:00
Pierre Goiffon
dd50c99ec4 Fix uniqueness PHPUnit tests 2018-11-05 15:52:35 +01:00
Pierre Goiffon
357555e507 AttributeImage : add css classes to be able to style 2018-11-05 11:54:35 +01:00
Pierre Goiffon
1f6a51b31f Some refactoring in AttributeImage URL generation 2018-11-05 11:54:35 +01:00
Molkobain
6d4cf71197 N°567 Enhance WikiText URLs synthax (usage of IDs and labels supported)
[[<objClass>:<objName|objId>|<label>]]
 <label> is optional

 Examples:
 - [[Server:db1.tnut.com]]
 - [[Server:123]]
 - [[Server:db1.tnut.com|Production server]]
 - [[Server:123|Production server]]
2018-11-05 11:29:06 +01:00
steffunky
87f898d29d Fix a typo in Dutch translations 2018-11-05 11:23:38 +01:00
jbostoen
d5576522ae Version 20181102-1455
* quick first translation
2018-11-05 11:03:52 +01:00
Molkobain
6addd9acec Update dictionaries for all languages to iTop 2.6 2018-11-02 11:52:33 +01:00
Molkobain
9b5942bf4e Remove duplicate entries in english dictionaries 2018-11-02 11:40:05 +01:00
Molkobain
9faa4e4cbd Update english dictionaries' file comment 2018-11-02 11:02:34 +01:00
Molkobain
8b80bd71e7 N°1714 Tags: Add default search criteria 2018-11-02 09:42:54 +01:00
Molkobain
8989206461 (Cherry pick 5f7e8c9 from branch support/2.5) N°1715 Search: Add default criteria for FAQ, FAQCategory & KnownError classes. 2018-11-02 09:04:02 +01:00
Molkobain
5f7e8c9229 N°1715 Search: Add default criteria for FAQ, FAQCategory & KnownError classes. 2018-11-02 08:50:56 +01:00
Molkobain
89a21c8e44 Code cleanup
Remove ending "?>" from dictionary files before updating all languages.
2018-11-01 15:35:49 +01:00
Molkobain
a7ec6e5ca0 Internal: Remove unused dictionary file. 2018-11-01 15:35:49 +01:00
steffunky
a08675352a N°1687: Fix typos in German translation (thanks to ITOMIG) 2018-10-31 12:04:13 +01:00
steffunky
7158b1f787 N°1504: Add a translation for the top left "Page" string on PDF export 2018-10-31 10:21:43 +01:00
Eric
3925ad252f Fixed execution warning in search (not visible in production) 2018-10-31 09:00:15 +01:00
Pierre Goiffon
f3fd47a792 N°659 PHPUnit to test uniqueness rule validity check... and debug tested method (woops ! unit test will save the world ;) ) 2018-10-30 18:01:35 +01:00
steffunky
af92f58265 N°1704: Upgrade portal datetime picker widget & moment.js for jQuery 3 compatibility 2018-10-30 15:51:19 +01:00
Pierre Goiffon
81b5f18579 N°1707 fix mandatory TagSet were not highlighted in the console 2018-10-30 15:06:47 +01:00
Molkobain
184c0cb84b Fix visual glitch in icon select widget 2018-10-30 10:53:50 +01:00
Eric
c892862822 N°1202 - Fix History on Decimal. No diff when modify only trailing 0s. 2018-10-30 09:13:52 +01:00
Pierre Goiffon
b61d1feec4 Update README after 2.6.0-beta release 2018-10-29 16:49:22 +01:00
Molkobain
a73ff16642 Merge pull request #7 from Super-Visions/feature/dutch-dict
Another update for Dutch dictionary

(cherry picked from commit 0e2c8ff220)
2018-10-29 12:11:32 +01:00
Pierre Goiffon
7763983ef4 N°1408 fix Organization.overview EN and FR dict keys 2018-10-24 14:58:24 +02:00
Pierre Goiffon
35f7fe98ae update versions 2018-10-24 10:35:11 +02:00
Pierre Goiffon
533acbde8d Update README 2018-10-24 10:35:00 +02:00
Pierre Goiffon
d72da422de PHPDoc 2018-10-24 10:35:00 +02:00
Pierre Goiffon
891608f812 N°1408 Organization.overview dashboard is now editable 2018-10-24 10:00:52 +02:00
Pierre Goiffon
e66da81a20 N°1408 new AttributeDashboard : Organization.overview 2018-10-23 18:37:39 +02:00
Eric
cae0cd00c2 DBSearch: Fix serialization rework (missing internal parameters) 2018-10-23 17:23:43 +02:00
Eric
32fc87023c AttributeDashboard support Dashlet Badge in XML files (fix the <class> collision) 2018-10-23 16:14:30 +02:00
Molkobain
0021482c1b Internal jQuery 3 migration fix 2018-10-23 15:43:31 +02:00
Molkobain
276427e3df PHPDoc 2018-10-23 15:43:31 +02:00
Eric
7b49bde3ad Dashlet "Header with statistics" query parameter changed to a text area 2018-10-23 15:15:35 +02:00
Eric
a94d940bd3 DBSearch: Fix serialization rework in bulk modify 2018-10-23 15:08:40 +02:00
Eric
313c3c6fc3 Code cleanup 2018-10-23 15:08:40 +02:00
Eric
de86f71c90 Fix error on Tag Admin screen when no TagSet attribute is defined 2018-10-23 15:08:40 +02:00
Eric
098b0531d8 Remove the generation of an additional class TagFieldData for AttributeDashboard 2018-10-23 15:08:40 +02:00
Pierre Goiffon
34552214bf N°1703 The dates are no longer reset when inserting a Ticket
Could cause problems when importing using REST API or using form prefill
2018-10-23 14:17:03 +02:00
Eric
d61a8ba160 DBSearch: Fix serialization rework 2018-10-22 18:59:38 +02:00
Pierre Goiffon
84ebca58ac N°931 TagSet : FAQ.domains is now displayes in the portal (FAQ list and details form) 2018-10-22 18:39:31 +02:00
Pierre Goiffon
def4c54d26 N°659 Console & Portal now we have same object save error messages and sessionmessages
* create new CoreCannotSaveException
* throw this exception in DBInsertNoReload/DBUpdate if CheckToWrite fails
* console : change UI.php code to catch this exception instead of calling CheckToWrite itself (was called twice :(( )
* portal : specific catch for the new exception
* portal : get and displays session messages
2018-10-22 17:11:08 +02:00
Pierre Goiffon
027b0fcff7 N°659 use header message to display uniqueness errors on object creation / modification 2018-10-22 17:11:08 +02:00
Pierre Goiffon
fc0cb44a84 Reformat iTopWebPage 2018-10-22 17:11:08 +02:00
Pierre Goiffon
574d72b0e7 N°659 Add uniqueness checks
* modify compiler to save the new rules
* add check on object save (\DBObject::DoCheckUniqueness)
* default model : add uniqueness rules on Brand, Model, Person
2018-10-22 17:11:07 +02:00
Pierre Goiffon
cd5e1afb2b DBSearch: Fix serialization rework, use htmlentities 2018-10-22 15:51:28 +02:00
Eric
0298d6bc19 DBSearch: Fix serialization rework 2018-10-22 15:37:32 +02:00
Eric
60d2fd4f7e N°1408 - Fix specific dashboard display without context 2018-10-22 12:26:56 +02:00
Thomas Casteleyn
5faa0ffe08 Update Dutch dictionary for attachments (#6)
(Thanks to @Hipska !)
2018-10-20 00:20:31 +02:00
Eric
705ce02580 Setup steps duration 2018-10-19 17:18:39 +02:00
Eric
78c674a989 DBSearch serialization rework 2018-10-19 16:02:07 +02:00
Eric
84d9be3293 Strengthen the SQL creation from OQL 2018-10-19 15:58:50 +02:00
Thomas Casteleyn
30c622052e Fix integer validation in dashlet forms
Mandatory integer fields were valid even when empty. (Thanks @Hipska for the fix!)
2018-10-19 15:06:56 +02:00
Eric
ada56da63e Fix multiple TagSet creation in the same object 2018-10-19 11:16:34 +02:00
Pierre Goiffon
78b626bbd2 JenkinsFile : add fixed notification 2018-10-18 15:44:35 +02:00
Pierre Goiffon
823311dc86 Update jenkins conf 2018-10-18 15:12:59 +02:00
Pierre Goiffon
21c5638e1e Merge branch 'support/2.5' into develop
# Conflicts:
#	application/applicationextension.inc.php
#	application/dashlet.class.inc.php
#	application/itopwebpage.class.inc.php
#	application/loginwebpage.class.inc.php
#	application/menunode.class.inc.php
#	application/nicewebpage.class.inc.php
#	application/query.class.inc.php
#	application/utils.inc.php
#	application/webpage.class.inc.php
#	application/wizardhelper.class.inc.php
#	core/action.class.inc.php
#	core/attributedef.class.inc.php
#	core/cmdbchangeop.class.inc.php
#	core/cmdbobject.class.inc.php
#	core/cmdbsource.class.inc.php
#	core/config.class.inc.php
#	core/dbobject.class.php
#	core/dbobjectsearch.class.php
#	core/dbobjectset.class.php
#	core/kpi.class.inc.php
#	core/modelreflection.class.inc.php
#	core/modulehandler.class.inc.php
#	core/oql/expression.class.inc.php
#	core/oql/oql-lexer.plex
#	core/oql/oql-parser.y
#	core/oql/oqlquery.class.inc.php
#	core/ormpassword.class.inc.php
#	core/sqlobjectquery.class.inc.php
#	core/sqlquery.class.inc.php
#	core/sqlunionquery.class.inc.php
#	core/trigger.class.inc.php
#	core/userrights.class.inc.php
#	css/light-grey.scss
#	datamodels/2.x/itop-backup/status.php
#	datamodels/2.x/itop-config/config.php
#	datamodels/2.x/itop-full-itil/datamodel.itop-full-itil.xml
#	datamodels/2.x/itop-knownerror-mgmt/en.dict.itop-knownerror-mgmt.php
#	datamodels/2.x/itop-knownerror-mgmt/module.itop-knownerror-mgmt.php
#	datamodels/2.x/itop-portal-base/portal/src/controllers/abstractcontroller.class.inc.php
#	datamodels/2.x/itop-portal-base/portal/src/controllers/brickcontroller.class.inc.php
#	datamodels/2.x/itop-portal-base/portal/src/controllers/browsebrickcontroller.class.inc.php
#	datamodels/2.x/itop-portal-base/portal/src/controllers/createbrickcontroller.class.inc.php
#	datamodels/2.x/itop-portal-base/portal/src/controllers/defaultcontroller.class.inc.php
#	datamodels/2.x/itop-portal-base/portal/src/controllers/managebrickcontroller.class.inc.php
#	datamodels/2.x/itop-portal-base/portal/src/controllers/objectcontroller.class.inc.php
#	datamodels/2.x/itop-portal-base/portal/src/controllers/userprofilebrickcontroller.class.inc.php
#	datamodels/2.x/itop-portal-base/portal/src/routers/abstractrouter.class.inc.php
#	datamodels/2.x/itop-portal-base/portal/src/routers/browsebrickrouter.class.inc.php
#	datamodels/2.x/itop-portal-base/portal/src/routers/createbrickrouter.class.inc.php
#	datamodels/2.x/itop-portal-base/portal/src/routers/defaultrouter.class.inc.php
#	datamodels/2.x/itop-portal-base/portal/src/routers/managebrickrouter.class.inc.php
#	datamodels/2.x/itop-portal-base/portal/src/routers/objectrouter.class.inc.php
#	datamodels/2.x/itop-portal-base/portal/src/routers/userprofilebrickrouter.class.inc.php
#	datamodels/2.x/itop-portal/datamodel.itop-portal.xml
#	datamodels/2.x/itop-tickets/en.dict.itop-tickets.php
#	dictionaries/da.dictionary.itop.core.php
#	dictionaries/da.dictionary.itop.ui.php
#	dictionaries/en.dictionary.itop.core.php
#	dictionaries/en.dictionary.itop.ui.php
#	dictionaries/fr.dictionary.itop.core.php
#	dictionaries/hu.dictionary.itop.core.php
#	dictionaries/it.dictionary.itop.core.php
#	dictionaries/nl.dictionary.itop.core.php
#	dictionaries/pt_br.dictionary.itop.core.php
#	dictionaries/tr.dictionary.itop.core.php
#	dictionaries/zh.dictionary.itop.core.php
#	js/forms-json-utils.js
#	js/jquery-migrate-1.4.1.min.js
#	js/jquery.layout.js
#	js/jquery.layout.min.js
#	js/jquery.tablesorter.pager.js
#	js/linkswidget.js
#	js/searchformforeignkeys.js
#	js/utils.js
#	js/wizardhelper.js
#	pages/schema.php
#	readme.txt
#	setup/ajax.dataloader.php
#	setup/xmldataloader.class.inc.php
#	sources/renderer/bootstrap/fieldrenderer/bssubformfieldrenderer.class.inc.php
#	sources/renderer/console/consoleformrenderer.class.inc.php
#	sources/renderer/console/fieldrenderer/consoleselectobjectfieldrenderer.class.inc.php
#	sources/renderer/console/fieldrenderer/consolesimplefieldrenderer.class.inc.php
#	sources/renderer/console/fieldrenderer/consolesubformfieldrenderer.class.inc.php
#	test/ItopDataTestCase.php
#	test/core/ormLinkSetTest.php
#	webservices/backoffice.dataloader.php
#	webservices/rest.php
2018-10-18 14:34:22 +02:00
Pierre Goiffon
588899db63 Convert all files from CrLf to Lf (preparing merge to develop) 2018-10-18 14:20:40 +02:00
Molkobain
a37698a9de Fix regression introduced in commit 10b7fa6 (Web queries have issue with line breaks in cell value) 2018-10-17 13:04:57 +02:00
bruno DA SILVA
02da84b4cf jenkins conf in .jenkins
- clearer dead ends
2018-10-16 10:57:17 +02:00
Eric
ebb5ede613 N°1408 - Asynchronous load of dashboard tab 2018-10-15 16:37:19 +02:00
Eric
db4b8b2f43 N°1408 - Dashboard selector 2018-10-15 16:37:18 +02:00
Eric
c17f7caa29 N°1408 - Dashboard selector 2018-10-15 16:37:18 +02:00
Eric
d7df975971 cleanup code 2018-10-15 16:37:18 +02:00
Eric
f3f70d6296 N°1408 - Dashboard Printer friendly page + user edit rights 2018-10-15 16:37:18 +02:00
Eric
256d4e2cb3 N°1408 - Revert dashboard field in datamodel 2018-10-15 16:37:18 +02:00
Eric
fb31c9006a N°1408 - Fix import dashboard 2018-10-15 16:37:18 +02:00
Eric
bf000e6a89 N°1408 - DBSearch Serialize refactor (json format) 2018-10-15 16:37:17 +02:00
Eric
94b4f10277 N°1408 - Fix Object print page for attributes dashboard 2018-10-15 16:37:17 +02:00
Eric
15671f6dd4 N°1408 - Use dashboards only in read-only mode 2018-10-15 16:37:17 +02:00
Eric
2460d2112f N°1408 - Auto-refresh dashboards 2018-10-15 16:37:17 +02:00
Eric
709badd0f7 N°1408 - Support contextual parameters in attributes dashboard 2018-10-15 16:37:17 +02:00
Eric
99153d02ee N°1408 - Support contextual parameters in attributes dashboard 2018-10-15 16:37:17 +02:00
Eric
4347b2c5ff N°1408 - Support contextual parameters in attributes dashboard 2018-10-15 16:37:17 +02:00
Eric
c13b6ea13a N°1408 - AttributeDashboard first implementation 2018-10-15 16:37:17 +02:00
Eric
6e5d4834f1 N°1408 - Move of the dashboard menu into the dashboard 2018-10-15 16:37:16 +02:00
Eric
9f489d8a59 cleanup code 2018-10-15 16:37:16 +02:00
Eric
c9be1a8e71 cleanup code 2018-10-15 16:37:16 +02:00
Pierre Goiffon
c1e2f35c96 N°931 TagSet : fix remove/add of a partial value in bulk edit 2018-10-15 11:45:29 +02:00
Pierre Goiffon
462148a12f N°931 TagSet POC : fix markup for preview 2018-10-15 11:35:59 +02:00
Pierre Goiffon
7e4edc6e3a Forms mandatory check : switch to first tab with error
(cherry picked from commit 80e6801db3e7770997e705d087e57b682e8df092)
2018-10-15 09:45:08 +02:00
bruno DA SILVA
452e7cce01 jenkins: default iTop isntance conf 2018-10-12 17:18:49 +02:00
bruno DA SILVA
cb7b5dfffb jenkins: default iTop isntance conf 2018-10-12 17:11:27 +02:00
steffunky
0a34fb7a7a N°1590: Advanced search: fixed a bug when selecting foreign keys would not add items (selectionMode is mandatory) 2018-10-12 11:06:31 +02:00
steffunky
11ba459d1b N°1590: Advanced search: fixed a bug when selecting foreign keys would not add items (selectionMode is mandatory) 2018-10-12 10:48:32 +02:00
Pierre Goiffon
460337954b CSS : remove duplicate declaration
(cherry picked from commit 7f99322da8896fa5120077381dc1a7fc9ff1f828)
2018-10-12 10:47:59 +02:00
Molkobain
215786d740 Update readme.txt for iTop 2.5.1 2018-10-10 14:40:08 +02:00
Molkobain
fe9ca2b9cc Update readme.txt for iTop 2.5.1 2018-10-10 14:38:18 +02:00
steffunky
41a479b48d N°1555: fixed a case where AttributeExternal field was pointing anything else than an ExternalKey and its label wouldn't show up on search criteria 2018-10-09 18:30:12 +02:00
steffunky
74a8c3f5bd N°1555: fixed a case where AttributeExternal field was pointing anything else than an ExternalKey and its label wouldn't show up on search criteria, remove duplicate catch 2018-10-09 18:27:36 +02:00
steffunky
3347d32f2a N°1555: fixed a case where AttributeExternal field was pointing anything else than an ExternalKey and its label wouldn't show up on search criteria 2018-10-09 18:25:48 +02:00
Pierre Goiffon
eb630efdf5 N°1658 update advanced search german translation (UI:Search:NoAutoSubmit:ExplainText) 2018-10-09 18:12:37 +02:00
Pierre Goiffon
91b7130671 N°1556 Advanced Search : fix removing only criteria in first row (was generating "AND 1") 2018-10-09 18:01:31 +02:00
Pierre Goiffon
80be4b4371 idea files improvements
- use Combodo preset
- JS code style (use tab for indentation, newlines in if/else statements)
2018-10-09 18:01:31 +02:00
Denis Flaven
21d7de7d8d Use a longer timeout to let the IFRAME load itself and inform iTop Hub
of the updated configuration. (Bug N°1672)
2018-10-09 17:36:30 +02:00
Pierre Goiffon
4c2be6b2c5 N°931 AttributeTagSet widget js wrapper : partial values can now be added with just a click 2018-10-09 09:04:21 +02:00
Pierre Goiffon
860bb6d615 N°931 AttributeTagSet widget js wrapper : fix remaining console.debug call, and fix indentations 2018-10-08 17:56:34 +02:00
Molkobain
4a431be0a9 (Cherry picked from commit 5099060) N°1203 : Correctly use 'from' field for test email notifications 2018-10-08 17:43:55 +02:00
Pierre Goiffon
950ffcde2b N°931 remove remaining references to Ticket.tagfield
(it was the old AttributeTagSet test, now we have FAQ.domains)
2018-10-08 15:45:50 +02:00
Molkobain
b84ac80aaa (Cherry pick from develop ab1715e) N°1576 Portal: Security hardening (missed one file in previous commit). 2018-10-08 13:05:45 +02:00
Pierre Goiffon
0580c71749 N°931 fix requirements for AttributeTagSet PhpUnit tests
* itop-kown-error-mgmt module
* creates a FAQCategory if needed
2018-10-08 11:58:45 +02:00
Pierre Goiffon
c66b0bea41 N°931 fix PhpUnit tests for TagSets (default datamodel doesn't have anymore Ticket.tagfield, but FAQ.domains) 2018-10-05 17:55:40 +02:00
Pierre Goiffon
7281bd4a1a N°931 default datamodel : remove Ticket.tagfield and add AttributeTagSet FAQ.domains 2018-10-05 17:37:23 +02:00
Pierre Goiffon
c9d73fc0c8 N°931 fix TagSet not saved on object creation 2018-10-05 17:12:58 +02:00
Pierre Goiffon
8720ac2b08 N°931 Fix import TagSet failing with multiple code values (using CLI with no_localize=1) 2018-10-05 09:18:23 +02:00
Pierre Goiffon
33e8b6a64c Switch back files from CrLf to Lf 2018-10-04 17:43:03 +02:00
Pierre Goiffon
d7cf339ab5 N°931 TagSet : adding widget JQuery plugin (Selectize.js) to the licences 2018-10-04 15:30:01 +02:00
Pierre Goiffon
714fada9f0 N°931 Fix TagSet export : with format=spreadsheet codes where always returned (now uses codes or labels according to what was set) 2018-10-04 15:00:33 +02:00
Pierre Goiffon
d36fd6a47d N°931 export localize option label : change FR value 2018-10-04 14:57:12 +02:00
Eric
b6d0843e55 Fix dashboard edition when a bad OQL is present in dashlet 'Group By' 2018-10-04 14:33:29 +02:00
Stephen
c0d83e96d8 Retrofit 2.5.1 fixes into develop (11308dc7, 1e0d654, 7fddd6ac, 12e9e453, cbe749af, 10b7fa60, c5f3598f, 396fc2cd) 2018-10-04 11:12:16 +02:00
Pierre Goiffon
3da6251cc7 N°931 change export localize option label
as attcodes, enum and tagset are concerned then the label don't contains anymore the field types impacted
also, we rephrased it to remove the negation and be clearer about the effect
2018-10-04 09:31:49 +02:00
Molkobain
396fc2cdcd N°1658 Fix hard-coded translation in search page when the form has not been automatically submitted. 2018-10-03 17:43:06 +02:00
Molkobain
11308dc76a N°1059 Fix new empty caselog entry on bulk modification. 2018-10-03 17:24:08 +02:00
Molkobain
7fddd6acdc N°1624 Fix bulk transition integrity exception when "org_id" was not checked. 2018-10-03 15:08:54 +02:00
Pierre Goiffon
1bf39aa092 N°931 fix XML export (node was always empty) 2018-10-03 10:53:34 +02:00
Molkobain
10b7fa6014 N°1647 Fix Excel web queries import. (JS script error popups) 2018-10-03 10:16:15 +02:00
Pierre Goiffon
3387d8fdd2 Fix XLSX export failing on PHP 7.1 on systems without "/tmp" path
Since PHP 7.1 tempnam() throws a notice if the dir parameter can't be used : bug #69489 in http://php.net/ChangeLog-7.php#7.1.0
2018-10-02 17:20:12 +02:00
Molkobain
cbe749af13 N°1645 Fix reset password dictionary entries (hyperlink had wrongly escaped characters) 2018-10-02 16:48:58 +02:00
Molkobain
c5f3598f4e N°1652 Fix broken search form when user has no read right on objects. 2018-10-02 16:40:26 +02:00
Pierre Goiffon
9f926fccd8 N°931 TagSet admin updates :
* when modifying tag, code field is read only if tag is used by at least one object
* "tag usage" tab : show only parent class
2018-10-02 16:36:49 +02:00
Pierre Goiffon
e9a77c798e Fix Contact data sample (reordering and remove duplicate id) 2018-10-02 15:01:30 +02:00
Molkobain
12e9e453d8 N°1644 Fix PHP 7.2 compatibility issue (count() on none array) 2018-10-02 14:57:51 +02:00
Stephen Abello
6e50a1c4be (Retrofit from develop 7d37b065) Form prefill: add possibility to change attributes flag on the fly 2018-10-02 11:11:46 +02:00
Guillaume Lajarige
e3e416b467 (Retrofit from deveop ab1715ed) N°1576 Portal: Security hardening. 2018-10-02 11:08:49 +02:00
Guillaume Lajarige
fcb6a4069a (Retrofit from develop 526d4c4d) N°1575 Portal: Security hardening. 2018-10-02 11:06:27 +02:00
Stephen Abello
02f83c4f52 (Retrofit from develop 9db47428) N°1559: Fixed external attributes selection on export form 2018-10-02 10:57:49 +02:00
Guillaume Lajarige
452c6c3df6 (Retrofit from develop 3d1ccf20) N°1566 Fix security message in the browser console ("Unsafe attempt to load URL data:image/svg+xml;utf8") 2018-10-02 10:56:19 +02:00
Guillaume Lajarige
2966efcfde (Retrofit from develop af43e22f) N°1578 Fix "Run Query" page hotkeys behavior in some configurations due to a wrong url. 2018-10-02 10:55:04 +02:00
Guillaume Lajarige
1cf36a5d01 (Retrofit from develop 5e1452f9) N°1580 Portal: Default image of image attributes not correctly displayed in object forms. 2018-10-02 10:52:22 +02:00
Molkobain
1973f7526e Update .gitignore to match the one from develop 2018-10-02 10:48:32 +02:00
Guillaume Lajarige
866dfe4531 (Retrofit from develop 07056613) N°1611 Fix "UTF-8 Characters Malformed" error due to wrong file encoding. 2018-10-02 10:38:27 +02:00
Molkobain
f617cb556b Merge branch 'support/2.5' of https://github.com/Combodo/iTop into support/2.5 2018-10-02 10:21:13 +02:00
Pierre Goiffon
29691a09fe .idea : use Combodo presets for code style and inspections 2018-10-02 09:11:56 +02:00
Eric
cb73c2a3f9 N°931: Unit tests for mysql stop words 2018-10-02 08:56:13 +02:00
Pierre Goiffon
713a41909b N°931 TagSet history : CSS and scss were out of sync 2018-10-01 19:02:39 +02:00
Steffunky
9972e253d5 enable jQuery migrate warning only in dev. environment 2018-10-01 16:17:41 +02:00
Eric
55309be9a1 N°917: AttributeQueryAttCodeSet support in XML definition 2018-10-01 15:52:36 +02:00
Eric
fd75f3af28 cleanup (fix error) 2018-10-01 15:36:47 +02:00
Eric
af7e5eb03e N°917: Display attcodes instead of labels in triggers and allow search on AttributeSet 2018-10-01 15:23:29 +02:00
Eric
b97ce7a25f N°917: Fix Ajax calls on objects containing AttributeSet 2018-10-01 15:22:31 +02:00
Molkobain
89d617c152 N°931 Better tooltips. 2018-10-01 12:30:16 +02:00
Molkobain
4595c565cc N°931 Portal: Start working on UI. 2018-10-01 09:27:07 +02:00
Eric
8f55d4054a N°917: Fix Search criterion when TagSet = 'tag1 tag2...' 2018-09-28 17:33:05 +02:00
Pierre Goiffon
2e255b10a7 Finish b931 2018-09-28 16:42:49 +02:00
Molkobain
cf9c1b52ed N°931 Portal integration due to AttributeSet refactoring. UI still to be done. 2018-09-28 16:34:52 +02:00
Eric
d3b3c44cbd N°917: Fix unit tests 2018-09-28 16:32:15 +02:00
Molkobain
edb25b6dca N°931 Internal: Move AttributeTagSet class. 2018-09-28 15:49:00 +02:00
Molkobain
4bf748641d N°931 UI: Display a regular tooltip instead of a qtip when item has no description. 2018-09-28 15:47:22 +02:00
Eric
16a6b70708 N°917: Fix unit tests 2018-09-28 15:36:13 +02:00
Eric
40355cb2d0 N°917: Fix refresh edit screen, avoid storing bad values in db 2018-09-28 12:08:35 +02:00
Eric
b52aaaadf2 N°917: Remove AttributeSet search 2018-09-28 12:08:34 +02:00
Pierre Goiffon
f55c0aa1c9 N°917: Fix TagSet search 2018-09-28 12:08:34 +02:00
Molkobain
333c51b0f9 N°931 Fix XSS in console. 2018-09-28 12:08:14 +02:00
Molkobain
46dee2919e Taxons: Fix item's remove box position. 2018-09-28 11:17:20 +02:00
Pierre Goiffon
799618dee7 N°931 AttributeSet widget : add charset parameter to htmlentities 2018-09-28 10:33:17 +02:00
Pierre Goiffon
96aaa0d8e1 N°931 TagSet in history : display "added" in bold and "removed" as striked 2018-09-28 10:33:17 +02:00
Molkobain
5556e3efec Taxons: Refactor of CSS for the console. 2018-09-28 09:40:46 +02:00
Pierre Goiffon
d8b2d4435a N°931 AttributeSet widget : keep initial removed values 2018-09-28 09:26:23 +02:00
Pierre Goiffon
a4315b4789 N°931 AttributeSet widget : better fix for crash when having a ' in the label
use htmlentities for input hidden value instead of a textarea display:none
2018-09-28 09:02:35 +02:00
Pierre Goiffon
3e8dd61607 N°931 AttributeSet widget : fix crash when having a ' in the label 2018-09-27 18:31:58 +02:00
Pierre Goiffon
1d28a67d21 N°931 TagSet widget enabling / disabling in bulk edit
- rename ToogleField -> ToggleField
- for the set input, use the same ID as other fields (used by ToggleField method)
- disable the set widget if needed on opening
- binds the update event to enable / disable at will
2018-09-27 17:29:36 +02:00
Eric
3a551e9cec N°917: Restrict "Attribute...AttCodeSet" to existing attributes on database write 2018-09-27 17:14:26 +02:00
Eric
cf6693a534 N°931: Fix tag css class 2018-09-27 16:47:14 +02:00
Eric
8c5c275952 N°931: Fix compiler (AttributeSet is abstract) 2018-09-27 16:47:14 +02:00
Molkobain
5fa4b4cb88 Taxons: Rework of CSS & markup in the console (portal still to come). 2018-09-27 16:45:04 +02:00
Eric
58525f247e N°917: AttributeDef CSS class 2018-09-27 15:57:08 +02:00
Eric
d78f19525e N°917: AttributeDef CSS class 2018-09-27 15:40:00 +02:00
Eric
5559c8205f Merge branch 'feature/AttributeSet' into feature/b931
# Conflicts:
#	core/attributedef.class.inc.php
2018-09-27 15:29:27 +02:00
Eric
2a6a97526d N°917: AttributeDef CSS class 2018-09-27 15:25:51 +02:00
bruno DA SILVA
1adea8f014 jenkins: slack notif on build fixed 2018-09-27 14:40:17 +02:00
Eric
29177ec86b N°917: New AttributeQueryAttCodeSet and enhanced Query phrase book 2018-09-27 14:37:50 +02:00
Pierre Goiffon
741e88e1f0 N°931 AttributeSet widget : little naming fixes 2018-09-27 12:05:45 +02:00
Pierre Goiffon
66bddc5730 N°931 AttributeSet CSS : fix remove box disappearing with long tag labels 2018-09-27 12:05:17 +02:00
Pierre Goiffon
6eaa7c0530 N°931 AttributeSet more generic CSS classes :
* more generic names
* use same classes in both view and edit
* in the scss file, 3 sections : attribute-set edition (with other field types styles), generic Selectize overridings, and styles for attribute-set items visualisation
2018-09-27 11:47:28 +02:00
Eric
b257fae03e N°917: Fix Unit tests 2018-09-27 11:44:28 +02:00
Eric
2d24324dea N°917: Fix AttributeClassState 2018-09-27 11:36:41 +02:00
Eric
ec597f697a N°917: Adapt to generic widget for set 2018-09-27 11:04:20 +02:00
Pierre Goiffon
3bed62a473 N°931 AttributeSet POC : now testing both widget for edition and CSS for viewing 2018-09-27 10:50:12 +02:00
Eric
b5f7227ecd N°917: Fix AttributeClassState 2018-09-27 10:49:33 +02:00
Eric
615adf8281 N°917: Trigger on delete 2018-09-27 10:49:32 +02:00
Eric
cb7bb3242a N°917: New AttributeClassState for triggers on state (entering or leaving a state) 2018-09-27 10:49:30 +02:00
Eric
4b08eea998 N°931: Fix Label protection for tags 2018-09-27 10:49:29 +02:00
Eric
01551942b3 N°917: Fix Bulk modify for AttCodeSet 2018-09-27 09:11:03 +02:00
Eric
720d334053 N°917: AttributeClassAttCodeSet created 2018-09-27 09:11:02 +02:00
Molkobain
9397d1ac2e Taxons: Add support in the portal (UI still to be done). 2018-09-26 17:13:55 +02:00
Pierre Goiffon
1530bb89fe N°931 TagSet widget and its POC are now more generic (to be used in all AttributeSet hierarchy) 2018-09-26 14:26:26 +02:00
bruno DA SILVA
a7000b2582 [WIP] jenkinsfile integration
cherry picked from commits :
79157c465a
e473c46dc3
148309245b
5dc39fe068
47c7a3c5e3
85b7e86e58
3fca465f1d
7955dd86f4
bef4ac83a4
bde83fc705
2018-09-26 09:00:25 +02:00
Thomas Casteleyn
f09683949d Add Dutch dictionary for incident management (#3)
Thanks to @Hipska!
2018-09-25 17:29:05 +02:00
Pierre Goiffon
e1f96974bb Merge branch 'develop' into feature/b931 2018-09-25 14:52:59 +02:00
Pierre Goiffon
1fc261937f Add toolkit to gitignore 2018-09-25 14:52:38 +02:00
Eric
a94211d3d3 Merge remote-tracking branch 'origin/develop' into feature/b931
# Conflicts:
#	.idea/inspectionProfiles/Combodo.xml
#	application/cmdbabstract.class.inc.php
#	core/attributedef.class.inc.php
#	css/light-grey.css
#	css/light-grey.scss
2018-09-25 12:03:44 +02:00
Eric
534f6b6a54 Merge branch 'feature/b917' into develop 2018-09-25 11:55:11 +02:00
Eric
901764bf70 N°917 - Add new trigger on object update 2018-09-25 11:29:15 +02:00
Eric
e67d6e8a80 N°917 - Add new trigger on object update 2018-09-25 10:38:01 +02:00
Molkobain
16476f736a Taxons: Add specific CSS class to tags so they can be easily stylized. 2018-09-24 16:38:11 +02:00
Eric
e9ecd89cda Code cleanup 2018-09-24 13:57:45 +02:00
Eric
55036511ab longer lines for PHP code format 2018-09-24 11:48:15 +02:00
Molkobain
3cf5d31f5d Start working on tags integration in the end-users portal. 2018-09-21 17:25:45 +02:00
Molkobain
84ae36cf1a Merge branch 'feature/b931' of https://github.com/Combodo/iTop into feature/b931 2018-09-21 17:24:56 +02:00
Molkobain
00515ac14a Refactor GetJSONForWidget helper (moved from cmdbAbstract to AttributeTagSet) 2018-09-21 17:24:34 +02:00
Eric
245612d0eb N°931: Tags dictionary and validation pattern 2018-09-21 16:56:53 +02:00
Eric
ae6e3b4f17 N°931: Tags Template format 2018-09-21 16:00:18 +02:00
Eric
12a3f1c36c N°931: Fix integrity controls (reserved word) 2018-09-21 15:59:54 +02:00
Eric
1af1e92b60 N°931: Fix error reporting for data synchro 2018-09-20 17:22:46 +02:00
Eric
a1ad7a5def N°931: Fix Search when screen is refreshed (number of selected criteria for tags) 2018-09-20 15:57:37 +02:00
Eric
398d1aa820 N°931: Limit the number of tags in the widget 2018-09-20 15:15:25 +02:00
Molkobain
38278f3432 Taxons: UI WIP. 2018-09-20 14:41:56 +02:00
Molkobain
baf4662ed8 Taxons: UI WIP. 2018-09-20 10:53:07 +02:00
Eric
cf07c9f1a2 N°931: Fix search when referencing a non existing tag 2018-09-20 10:31:02 +02:00
Eric
446bd0ad1f N°931: Rename Tag columns in database 2018-09-20 09:58:35 +02:00
Eric
3d5e46faac N°931: Fix Search when screen is refreshed 2018-09-19 17:21:05 +02:00
bruno DA SILVA
b8fba8997a Merge branch 'feature/jenkinsfile' into develop 2018-09-19 16:33:05 +02:00
Eric
a07c81d0d9 N°931: TagSetData table name 2018-09-19 16:18:09 +02:00
Eric
0252d091ca N°931: TagSetData table name 2018-09-19 16:07:10 +02:00
Molkobain
18d9ada58d N°1636 Fix concurrent lock not released on failed transition (in the console) 2018-09-19 15:56:50 +02:00
Molkobain
055d2cc62c Taxons: UI WIP. 2018-09-19 11:00:33 +02:00
Eric
e15c5c58d8 N°931: HTML 2018-09-19 10:19:16 +02:00
Eric
b734aca4d0 N°931: Fix History 2018-09-19 09:52:06 +02:00
Eric
e495b36dfb N°931: Add link to read-only HTML representation of tags 2018-09-18 17:34:03 +02:00
Eric
cdcfe03d67 N°931: Tag max number and max length per class and field (defined in xml) 2018-09-18 15:33:00 +02:00
Eric
2c6dc20046 N°931: "Empty" message added to the tag usage tab 2018-09-18 14:57:56 +02:00
Eric
a8c3b7ac2e N°931: Reformat 2018-09-18 14:16:30 +02:00
Eric
98572c6efb N°931: Tags admin menu (typo) 2018-09-18 13:57:46 +02:00
Eric
70840c53aa N°931: TagSetFieldData Fix bad name extract 2018-09-18 12:17:27 +02:00
Eric
9fbd27f3a8 N°931: Import/Export separator defined in configuration 2018-09-18 12:04:08 +02:00
Eric
c3c1897258 N°931: Tags data class display name 2018-09-18 11:38:34 +02:00
Eric
5403219746 N°931: Tags admin menu 2018-09-18 10:28:39 +02:00
Molkobain
fb08903a8a UI: Improve selected rows background color in tables. 2018-09-17 17:09:12 +02:00
Molkobain
416005654e Merge branch 'develop' of https://github.com/Combodo/iTop into develop 2018-09-17 17:07:52 +02:00
Eric
1debf77ab4 N°931: DBSearch AddCondition updated for tags 2018-09-17 12:46:46 +02:00
Eric
f1a8bb08da N°931: Fix integrity controls (tag code length) 2018-09-17 12:03:17 +02:00
Eric
7edff12bbf Merge remote-tracking branch 'origin/support/2.5' into develop
# Conflicts:
#	application/startup.inc.php
2018-09-17 11:47:47 +02:00
Eric
27332931d0 N°1626 - Error 500 when returning from a move to test 2018-09-17 11:42:32 +02:00
Molkobain
34d601f49c UI: Make caselog entries' header font a bit more tinier in enhanced portal. 2018-09-16 21:39:09 +02:00
Pierre Goiffon
ec38473d88 N°931 TagSet widget : disable/enable methods for mass edit (need to be plugged, but where ?!??) 2018-09-14 17:57:45 +02:00
Pierre Goiffon
875c77ae65 N°931 TagSet widget : fix empty widget on creation form
Now displays a placeholder
The + icon can't be used as is cause it's inserted with ::after, and without tags it can't be right aligned
2018-09-14 17:43:38 +02:00
Eric
75e24f9f79 Changed table selection background color 2018-09-14 17:26:06 +02:00
Eric
16a4662129 warnings reworked 2018-09-14 17:08:25 +02:00
Eric
1eda1eb9de N°931: cleanup code 2018-09-14 17:08:05 +02:00
Eric
d981fd35ef N°931: TagSet Fix CSV import 2018-09-14 14:55:41 +02:00
Pierre Goiffon
6f1dc44932 N°931 TagSet widget : fix added / removed not updating correctly
* move integrity checks from refresh method to add/remove callbacks
* use onInitialize callback for partial values instead of render
2018-09-14 14:50:24 +02:00
Pierre Goiffon
95b929dd27 N°931 TagSet widget POC HTML page 2018-09-13 18:15:58 +02:00
Eric
0c75b98f48 N°931: TagSet Fix Bulk update 2018-09-13 17:49:25 +02:00
Eric
ecc5a0bf8a N°931: TagSet Fix 'New...' object form 2018-09-13 17:06:58 +02:00
Pierre Goiffon
d9315bec84 N°931 integrate TagSet widget 2018-09-13 15:57:32 +02:00
Eric
d1ee7f4353 N°931: TagSet search (manage undefined values) unit tests 2018-09-12 18:17:17 +02:00
Eric
979095337b code cleanup 2018-09-12 15:35:18 +02:00
Eric
34b528b1f4 N°931: TagSet search unit tests 2018-09-12 15:34:37 +02:00
Eric
5ea056a3fc code cleanup 2018-09-12 15:14:27 +02:00
Eric
2ba31244c2 N°931: TagSet search form integration 2018-09-12 15:03:35 +02:00
Molkobain
3ea16694b4 Fix dictionary entry on linkedset tab that was adding a 's' on object class. (eg. "Add IP Addresss..." now becomes "Add IP Address objects...") 2018-09-12 11:02:02 +02:00
Molkobain
35e872310d Update dictionaries for ActionEmail class. (Missing uppercase on first letters) 2018-09-12 09:58:04 +02:00
Pierre Goiffon
b86b24d444 N°931 JS/CSS files for TagSet widget 2018-09-12 09:03:04 +02:00
Molkobain
45e1a6ffd6 PHP Documentation 2018-09-11 21:45:19 +02:00
Pierre Goiffon
c87f001956 Little modifications on PHPStorm code style & inspections 2018-09-11 18:44:44 +02:00
Eric
1fc3b3a4ed N°931: Integrity controls + unit tests 2018-09-11 17:27:27 +02:00
Eric
c706a2d77c N°931: Integrity controls 2018-09-11 12:40:46 +02:00
Eric
8577fc6701 N°931: Integrity controls 2018-09-11 12:22:50 +02:00
Eric
ead3067d49 Merge remote-tracking branch 'origin/support/2.5' into develop 2018-09-11 09:59:47 +02:00
Eric
4772b8c5bb PHPStorm config 2018-09-11 09:54:56 +02:00
Eric
36e32b23e2 N°1585: Fix request uri too long (search form) 2018-09-11 09:36:10 +02:00
Eric
6817cfbeea N°931: Integrity controls 2018-09-07 17:50:40 +02:00
bruno DA SILVA
f851238eab Merge branch 'develop' into feature/jenkinsfile 2018-09-07 15:11:14 +02:00
bruno DA SILVA
79157c465a [WIP] jenkinsfile integration 2018-09-07 14:52:22 +02:00
Pierre Goiffon
64438f6b6d idea : change XML indent 2018-09-06 18:35:51 +02:00
Pierre Goiffon
f2b914a4c5 N°931 change CSS for displaying TagSet datas 2018-09-06 18:34:23 +02:00
Pierre Goiffon
da71004898 N°931 update TagSet DataModel declaration parameters 2018-09-06 17:10:40 +02:00
Eric
e9019b294a Merge branch 'develop' into feature/jenkinsfile 2018-09-06 15:51:31 +02:00
Eric
e2c3ea22e4 N°931: Start bulk modify implementation 2018-09-06 15:42:10 +02:00
Eric
c7f3f20229 New Unit tests 2018-09-06 14:42:00 +02:00
bruno DA SILVA
46dc024335 Merge branch 'develop' into feature/jenkinsfile 2018-09-06 14:31:59 +02:00
Eric
34c68cfef0 Fix regression introduced in bugfix 1554 and detected by unit tests 2018-09-06 14:20:42 +02:00
Molkobain
d6a564a38b Add Thomas Casteleyn to the contributors list! :)
(I forgot him on the initial commit)
2018-09-06 11:32:38 +02:00
Pierre Goiffon
31c69088ca New contributor : Dennis Lanister (PR #1) 2018-09-06 10:14:24 +02:00
Dennis Lassiter
49bb8fd515 Fixed bug that caused memory_limit=-1 to lead to 'not enough memory' … (#1)
* Fixed bug that caused memory_limit=-1 to lead to 'not enough memory' error
* Added Unit Test to Memory Limit Check
2018-09-06 10:04:28 +02:00
Eric
b8f8a0d455 N°1585: Fix ajax request uri too long on auto-complete 2018-09-05 15:10:11 +02:00
Molkobain
374e34a8b8 Merge branch 'develop' of https://github.com/Combodo/iTop into develop 2018-09-05 15:07:34 +02:00
Molkobain
7ef1d72314 Add a "Contributors" in the READMME.md to thank all the contributors! :) 2018-09-05 15:06:56 +02:00
Eric
b9708c8d37 N°1585: Fix ajax request uri too long on auto-complete 2018-09-05 14:47:20 +02:00
bruno DA SILVA
5666a3d74c Merge branch 'develop' into feature/jenkinsfile 2018-09-05 10:12:13 +02:00
bruno DA SILVA
8004b411da gitignore
- add the test's  vendor dir
2018-09-05 10:11:09 +02:00
bruno DA SILVA
e473c46dc3 [WIP] jenkinsfile integration 2018-09-05 08:08:19 +02:00
bruno DA SILVA
148309245b [WIP] jenkinsfile integration 2018-09-05 08:00:07 +02:00
bruno DA SILVA
5dc39fe068 [WIP] jenkinsfile integration 2018-09-04 18:10:39 +02:00
bruno DA SILVA
47c7a3c5e3 [WIP] jenkinsfile integration 2018-09-04 18:05:19 +02:00
bruno DA SILVA
85b7e86e58 [WIP] jenkinsfile integration 2018-09-04 18:03:56 +02:00
Pierre Goiffon
f871581997 Merge branch 'develop' into feature/b931
# Conflicts:
#	application/applicationextension.inc.php
#	core/attributedef.class.inc.php
#	core/cmdbchangeop.class.inc.php
#	core/cmdbobject.class.inc.php
#	core/dbobjectsearch.class.php
#	core/oql/expression.class.inc.php
#	core/oql/oql-lexer.plex
#	core/oql/oql-parser.y
#	core/oql/oqlquery.class.inc.php
#	css/light-grey.scss
#	datamodels/2.x/itop-full-itil/datamodel.itop-full-itil.xml
#	datamodels/2.x/itop-portal/datamodel.itop-portal.xml
#	datamodels/2.x/itop-tickets/en.dict.itop-tickets.php
#	dictionaries/en.dictionary.itop.core.php
#	dictionaries/fr.dictionary.itop.core.php
#	setup/xmldataloader.class.inc.php
#	test/ItopDataTestCase.php
2018-09-04 18:02:51 +02:00
bruno DA SILVA
3fca465f1d [WIP] jenkinsfile integration 2018-09-04 18:02:12 +02:00
bruno DA SILVA
7955dd86f4 [WIP] jenkinsfile integration 2018-09-04 18:00:34 +02:00
Pierre Goiffon
40a4e6d7b0 Fix files using CrLf, convert them to Lf to have the whole repo using Lf
Warn your git config (core.autocrlf = input or true)
2018-09-04 17:59:51 +02:00
bruno DA SILVA
bef4ac83a4 [WIP] jenkinsfile integration 2018-09-04 17:58:20 +02:00
bruno DA SILVA
bde83fc705 [WIP] jenkinsfile integration 2018-09-04 17:53:18 +02:00
Pierre Goiffon
cad18bee73 SetupUtils : update comments to match current branch version 2018-09-04 12:02:16 +02:00
Eric
98e5eaa4e0 N°931: Add Delta management in ormTagSet (with unit tests) 2018-09-04 11:06:53 +02:00
Pierre Goiffon
3129e94363 Merge branch 'N°1620' into develop
# Conflicts:
#	sources/application/search/searchform.class.inc.php
2018-09-04 09:54:12 +02:00
bruno DA SILVA
7ac0e50bd9 phpstorm's line separator in edited files 2018-09-03 17:36:37 +02:00
Eric
10683d943f N°1620: Fix 'forgot your password?' link 2018-09-03 16:50:30 +02:00
Molkobain
9ad8c6a96d Add .idea project files 2018-09-03 15:53:00 +02:00
Molkobain
c74d9bbafb Add .gitignore 2018-09-03 15:51:43 +02:00
Eric
7d502fae23 N°931: TagSet : OQL Parse/Normalize unit tests 2018-09-03 15:18:19 +02:00
Pierre Goiffon
894eeef140 ignore : add extensions 2018-09-03 15:10:51 +02:00
bruno DA SILVA
7991069282 .gitignore completion
- cache
 - logs
 - composer's vendor dir
2018-09-03 12:13:57 +02:00
Eric
39f3972a24 N°931: TagSet : OQL Parsing unit tests 2018-08-31 18:02:22 +02:00
Pierre Goiffon
fc0e5ecd3b Ignore : add other shared files in index 2018-08-31 17:46:12 +02:00
Pierre Goiffon
8897d9f82b ignore : add other shared idea files in index 2018-08-31 17:36:52 +02:00
Eric
1329b5f684 N°931: TagSet : Set automatically the class and attcode from tag class name 2018-08-31 16:59:02 +02:00
Eric
e58bc738d0 N°931: TagSet : Parsing OQL 2018-08-31 15:58:55 +02:00
Denis Flaven
af63579f31 Rework of the readme... 2018-08-30 16:35:56 +02:00
Denis Flaven
55fad3a9ec Added .project files to ignore. 2018-08-30 15:32:41 +02:00
Eric
3250e0a1e6 N°931: TagSet - Support for removed tags in history 2018-08-30 12:42:56 +02:00
bruno DA SILVA
8df287f45e updated readme 2018-08-30 12:25:20 +02:00
Eric Espié
f458a77449 N°962: TagSet - Attribute definition (continued)
SVN:b931[6032]
2018-08-30 11:08:47 +02:00
Eric Espié
1953c05b33 N°962: TagSet - add label support
SVN:b931[6031]
2018-08-30 11:08:47 +02:00
Eric Espié
a03c553000 N°962: TagSet attribute definition dev (continued)
SVN:b931[6030]
2018-08-30 11:08:47 +02:00
Eric Espié
ecdc4076d9 N°962: TagSet Edition in string mode
SVN:b931[6029]
2018-08-30 11:08:47 +02:00
Eric Espié
cd2ea3793e N°962: TagSet Fix Attribute definition
SVN:b931[6028]
2018-08-30 11:08:47 +02:00
Pierre Goiffon
d40ffd944f Revert "@@@@ OQL parsing"
This reverts commit 0beafc1e9a7c4a629a458aec669aa5e11b27db49.

SVN:b931[6027]
2018-08-30 11:08:47 +02:00
Pierre Goiffon
0ee4b52baa N°931 rights on TagSetFieldData on ConfigurationManager profile
SVN:b931[6026]
2018-08-30 11:08:46 +02:00
Pierre Goiffon
5e7db7a27e @@@@ OQL parsing
SVN:b931[6025]
2018-08-30 11:08:46 +02:00
Eric Espié
9631021f84 N°962: TagSet Attribute definition and values (with unit tests on values)
SVN:b931[6024]
2018-08-30 11:08:46 +02:00
Pierre Goiffon
157193c831 N°931 Change default XML version and remove done TODOs
SVN:b931[6022]
2018-08-30 11:08:46 +02:00
Pierre Goiffon
1415f12506 composer.json : add missing ext-dom (iTopDesignFormat)
SVN:b931[6021]
2018-08-30 11:08:46 +02:00
Pierre Goiffon
4df497a768 N°931 Increment iTop XML version (1.5 -> 1.6)
SVN:b931[6020]
2018-08-30 11:08:46 +02:00
Eric Espié
9a13eb0f90 warnings cleanup, search mode switched to BOOLEAN
SVN:b931[6019]
2018-08-30 11:08:46 +02:00
Pierre Goiffon
eaa49bce05 N°931 woops forgot to rename TagSetFielData file name
SVN:b931[6018]
2018-08-30 11:08:46 +02:00
Pierre Goiffon
96334d859a Add shared idea file 2018-08-30 11:05:27 +02:00
Pierre Goiffon
13855b1501 Add .gitignore and README 2018-08-30 11:04:23 +02:00
Eric Espié
22df5d09fb Retrofit from trunk
N°1595 - Setup : Blocking error on backup failure [from revision 6010]

SVN:2.5[6023]
2018-08-28 12:14:56 +00:00
Eric Espié
277b24e2f0 warnings cleanup, search mode switched to BOOLEAN
SVN:trunk[6019]
2018-08-24 12:09:55 +00:00
Pierre Goiffon
abb2a2a6e2 N°931 new MatchExpression, allow to query the DB
SVN:trunk[6016]
2018-08-23 15:06:41 +00:00
Pierre Goiffon
961f5fd387 N°931 new TagField iTop class generated for each AttributeTag field
SVN:trunk[6015]
2018-08-23 15:06:17 +00:00
Pierre Goiffon
bdb62de81c N°931 new AttributeTag, handle field creation & update
SVN:trunk[6014]
2018-08-23 15:05:36 +00:00
Pierre Goiffon
422a850792 AttributeDefinition : fix lots of warnings
SVN:trunk[6013]
2018-08-23 14:55:33 +00:00
Eric Espié
1dfcc77098 N°1554: Search form - hide unknown external keys from the search criteria.
SVN:trunk[6012]
2018-08-23 12:32:37 +00:00
Eric Espié
13097d7e0e Fix excel export when reconciliation key list is containing empty keys.
Fix the compiler to avoid generating a reconciliation array not empty when
the tag is present in the xml definition of the class but no key is defined.

SVN:trunk[6011]
2018-08-23 08:22:44 +00:00
Eric Espié
ea9b7eddde N°1595 - Setup : Blocking error on backup failure
SVN:trunk[6010]
2018-08-22 10:16:35 +00:00
Guillaume Lajarige
07056613e5 N°1611 Fix "UTF-8 Characters Malformed" error due to wrong file encoding.
SVN:trunk[6009]
2018-08-21 10:29:46 +00:00
Pierre Goiffon
4d45793ec7 PHPDoc (schema)
SVN:trunk[6008]
2018-08-17 12:04:57 +00:00
Pierre Goiffon
931593a59e (Retrofit from trunk) N°1572 Add composer.json for PHP language level (r5967)
SVN:2.5[6007]
2018-08-17 08:42:41 +00:00
Pierre Goiffon
4718133ab6 PHPDoc
SVN:trunk[6006]
2018-08-16 13:17:56 +00:00
Pierre Goiffon
ba518fa975 PHPDoc
SVN:trunk[6005]
2018-08-16 12:36:24 +00:00
Pierre Goiffon
0311e78690 KPI : fix PHP notice var might be undefined
SVN:trunk[6004]
2018-08-16 12:36:11 +00:00
Stephen Abello
9db47428db N°1559: Fixed external attributes selection on export form
SVN:trunk[6003]
2018-08-14 13:19:36 +00:00
Stephen Abello
7092dc6f86 (Retrofit from trunk) German Translation: typos (UserRequest #18704)
SVN:2.5[6002]
2018-08-08 10:12:43 +00:00
Vincent Dumas
84dc3c2093 German Translation: typos (UserRequest #18704)
SVN:trunk[6001]
2018-08-08 09:18:25 +00:00
Stephen Abello
7d37b06555 Form prefill: add possibility to change attributes flag on the fly
SVN:trunk[6000]
2018-08-06 14:33:47 +00:00
Pierre Goiffon
6e6a89fb8c Selectable lines in tables : add an exclusion rule for click on padding/margin/border
SVN:trunk[5999]
2018-08-06 10:12:48 +00:00
Stephen Abello
135d9c5e55 Support any php default password hash algorithm change
SVN:trunk[5998]
2018-08-03 14:52:05 +00:00
Stephen Abello
dd46048ea6 Use a better algorithm to hash new passwords
SVN:trunk[5997]
2018-08-03 12:49:20 +00:00
Stephen Abello
8fe38b03f6 Added replacement for mcrypt removal in PHP 7.2, added stronger encryption options
SVN:trunk[5996]
2018-08-03 08:43:36 +00:00
Pierre Goiffon
0adadeb280 Remove old code that was here for old PHP version compatibility
SVN:trunk[5995]
2018-08-03 07:39:50 +00:00
Pierre Goiffon
775a5122c9 Selectable lines in tables can now be checked clicking anywhere in the line (previously this could only be done clicking on the checkbox)
SVN:trunk[5994]
2018-08-02 14:36:15 +00:00
Stephen Abello
5099060be2 N°1203 : Correctly use 'from' field for test email notifications
SVN:trunk[5993]
2018-08-02 08:34:58 +00:00
Pierre Goiffon
c3f80a5876 (Retrofit from trunk) N°1582 Fix audit when a current organization is set and there is an audit rule with valid=true
Was generating an OQL missing query argument error (r5991)

SVN:2.5[5992]
2018-08-01 09:13:15 +00:00
Pierre Goiffon
201c93e20a N°1582 Fix audit when a current organization is set and there is an audit rule with valid=true
Was generating an OQL missing query argument error

SVN:trunk[5991]
2018-08-01 09:12:00 +00:00
Stephen Abello
c852d91a72 Updated tcpdf to v6.2.17 for better compatibility with different PHP versions
SVN:trunk[5990]
2018-07-31 13:29:18 +00:00
Pierre Goiffon
821eb4df8c (Retrofit from trunk) PHP 7.2 compatibility: fix another count(null) (r5988)
SVN:2.5[5989]
2018-07-30 10:31:22 +00:00
Pierre Goiffon
a3c6e62bd5 PHP 7.2 compatibility: fix another count(null)
SVN:trunk[5988]
2018-07-30 10:30:16 +00:00
Pierre Goiffon
8cd18fe190 Setup : log in log/setup.log on PHP error (register_shutdown_function callback)
SVN:trunk[5987]
2018-07-26 14:54:45 +00:00
Guillaume Lajarige
5e1452f9b9 N°1580 Portal: Default image of image attributes not correctly displayed in object forms.
SVN:trunk[5986]
2018-07-26 14:22:15 +00:00
Guillaume Lajarige
b76de65886 Internal: Fix CSS typo.
SVN:trunk[5985]
2018-07-25 15:11:21 +00:00
Guillaume Lajarige
48b3bd8bf3 N°1579 Portal: Fix wrong pictogram placement on email & tel attributes in the ManageBrick.
SVN:trunk[5984]
2018-07-25 15:02:29 +00:00
Guillaume Lajarige
ab1715edec N°1576 Portal: Security hardening.
SVN:trunk[5983]
2018-07-25 14:48:11 +00:00
Guillaume Lajarige
3589783ee1 PHPDoc.
SVN:trunk[5982]
2018-07-25 13:09:35 +00:00
Guillaume Lajarige
af43e22f03 N°1578 Fix "Run Query" page hotkeys behavior in some configurations due to a wrong url.
SVN:trunk[5981]
2018-07-25 13:06:38 +00:00
Eric Espié
956f6403b8 Display error message for end users instead of blank screen
SVN:trunk[5980]
2018-07-25 08:02:28 +00:00
Pierre Goiffon
e276587fdc N°931 change iTop 2.6 MySQL requirements from 5.5.3 to 5.6 (to have fulltext on InnoDB)
SVN:2.5[5978]
2018-07-25 07:57:31 +00:00
Guillaume Lajarige
82ed1853fa Code cleanup.
SVN:trunk[5977]
2018-07-25 07:57:07 +00:00
Guillaume Lajarige
eb0403945b PHPDoc
SVN:trunk[5976]
2018-07-25 07:55:39 +00:00
Pierre Goiffon
3126af94ac N°931 change MySQL dependency from 5.5.3 to 5.6 (to have fulltext on InnoDB)
SVN:trunk[5974]
2018-07-25 07:51:47 +00:00
Guillaume Lajarige
e71ad536a9 Code cleanup
SVN:trunk[5973]
2018-07-25 07:23:52 +00:00
Guillaume Lajarige
d0322b471d PHPDoc
SVN:trunk[5972]
2018-07-24 16:03:15 +00:00
Guillaume Lajarige
a6af11e644 Code cleanup and PHPDoc.
SVN:trunk[5971]
2018-07-24 15:50:52 +00:00
Guillaume Lajarige
1809180d41 Internal: Portal: Fix router API that was never returning the right route.
SVN:trunk[5970]
2018-07-24 15:46:23 +00:00
Pierre Goiffon
9612b1b9e9 Fix non existing parameter passed to function
SVN:trunk[5969]
2018-07-24 15:36:26 +00:00
Guillaume Lajarige
526d4c4d15 N°1575 Portal: Security hardening.
SVN:trunk[5968]
2018-07-24 14:26:51 +00:00
Pierre Goiffon
3f4c824fd5 N°1572 composer.json : add PHP ext dependencies
SVN:trunk[5967]
2018-07-24 12:30:07 +00:00
Pierre Goiffon
9c25feb67c N°1572 Add composer.json for PHP language level
SVN:trunk[5965]
2018-07-24 12:17:05 +00:00
Stephen Abello
e31faf81a9 jQuery 3: patched layout library
SVN:trunk[5964]
2018-07-23 09:47:53 +00:00
Pierre Goiffon
6eb13c24aa JQuery 3 : oops use the REAL min file this time
SVN:trunk[5963]
2018-07-23 09:12:50 +00:00
Pierre Goiffon
dd20017b0a JQuery 3 : change JQuery min file
SVN:trunk[5962]
2018-07-23 09:09:49 +00:00
Stephen Abello
6630051ef3 Updated jQuery to v3.3.1
SVN:trunk[5961]
2018-07-23 06:58:30 +00:00
Vincent Dumas
a66d91c507 Fix duplicated label in French: Ticket.caller_id = Change.requestor_id by renaming the second
SVN:trunk[5960]
2018-07-20 13:08:30 +00:00
Vincent Dumas
2f34f0458b Fix XML bug: Duplicate id=team_id in state new.
SVN:trunk[5959]
2018-07-20 12:49:23 +00:00
Guillaume Lajarige
076abc8ae7 N°1568 Portal: Fix async error messages catching when submitting a form was redirecting to a modal that crashed (eg. Transition on object that failed to load)
SVN:trunk[5958]
2018-07-19 16:54:11 +00:00
Eric Espié
5134e57109 Search: better translation of search criteria in "natural language" for ISNULL function
SVN:trunk[5957]
2018-07-19 08:45:39 +00:00
Eric Espié
a454a43111 Retrofit from trunk
N°1556 - Search: Fix removing last criterion on a 'or' line resulted in 'OR 1'.
The empty OR condition is now removed completely from the screen and the criterion list.
[from revision 5951]

SVN:2.5[5956]
2018-07-19 08:17:46 +00:00
Eric Espié
045f58144e Retrofit from trunk
N°1553 - Search: Fix operator on indexed attributes.
It was previously always forced to '=', now it's only defaulted to '='
[from revision 5950]

SVN:2.5[5955]
2018-07-19 08:14:26 +00:00
Eric Espié
8ffea22f0e Retrofit from trunk
N°1561 - Fix auto-complete error when the friendlyname depends on other classes
[from revision 5948]

SVN:2.5[5954]
2018-07-19 08:10:32 +00:00
Eric Espié
c630676792 Retrofit from trunk
N°1555 - Search: ExternalField label not displayed.
The search is not restricted for external fields anymore.
[from revision 5945]

SVN:2.5[5953]
2018-07-19 08:06:39 +00:00
Guillaume Lajarige
3d1ccf2028 N°1566 Fix security message in the browser console ("Unsafe attempt to load URL data:image/svg+xml;utf8")
SVN:trunk[5952]
2018-07-18 14:40:12 +00:00
Eric Espié
60b980fbff N°1556 - Search: Fix removing last criterion on a 'or' line resulted in 'OR 1'.
The empty OR condition is now removed completely from the screen and the criterion list.

SVN:trunk[5951]
2018-07-18 14:08:56 +00:00
Eric Espié
df20f1b5ab N°1553 - Search: Fix operator on indexed attributes. It was previously always forced to '=', now it's only defaulted to '='
SVN:trunk[5950]
2018-07-18 13:13:02 +00:00
Eric Espié
27144f07b1 N°1561 - Fix auto-complete error when the friendlyname depends on other classes
SVN:trunk[5948]
2018-07-18 12:30:40 +00:00
Guillaume Lajarige
8135fdb9d2 Update spanish translations (Thanks to Miguel Turrubiates!)
SVN:trunk[5947]
2018-07-18 07:51:17 +00:00
Pierre Goiffon
985ad18048 REST service PHPDoc & code cleanup
SVN:trunk[5946]
2018-07-18 07:40:10 +00:00
Eric Espié
768ed2666d N°1555 - Search: ExternalField label not displayed.
The search is not restricted for external fields anymore.

SVN:trunk[5945]
2018-07-17 13:17:22 +00:00
Eric Espié
0bbb586094 Retrofit from trunk
Advanced search: Fix an error when using search form from an union.
[from revision 5940]

SVN:2.5[5944]
2018-07-17 12:23:27 +00:00
Eric Espié
efa1f4ee43 Retrofit from trunk
N°1551 - Search: selected org & default criteria
Display the default search criteria also when an org is selected.
The org restriction criterion is read only.
[from revision 5939]

SVN:2.5[5943]
2018-07-17 12:22:09 +00:00
Eric Espié
e184eb6aae Retrofit from trunk
DBObject->GetOriginal() hardening (now support attributes not set: for example sla_tto_passed for UserRequest until it is closed)
[from revision 5932]

SVN:2.5[5942]
2018-07-17 12:19:26 +00:00
Eric Espié
c289a53ed3 Advanced search: Fix an error when using search form from an union.
SVN:trunk[5940]
2018-07-17 12:04:53 +00:00
Eric Espié
5c206718c8 N°1551 - Search: selected org & default criteria
Display the default search criteria also when an org is selected.
The org restriction criterion is read only.

SVN:trunk[5939]
2018-07-17 12:01:29 +00:00
Eric Espié
d7f18e879a Automatic Tests: new ormLinkSet test
SVN:trunk[5938]
2018-07-13 12:34:45 +00:00
Eric Espié
4881a2c274 Better KPI navigation
SVN:trunk[5937]
2018-07-13 09:42:52 +00:00
Eric Espié
5eb5fa05bc cleanup code
SVN:trunk[5936]
2018-07-13 08:34:47 +00:00
Eric Espié
c7e0f36d7c N°1546 - Ticket JSON Export PHP Notice for pre-2.0 tickets
SVN:trunk[5935]
2018-07-13 07:47:13 +00:00
Pierre Goiffon
6e9fcb81f0 (Retrofit from trunk) Fix setup for PHP 5.5 (cannot use expression as default field value) (r5933)
SVN:2.5[5934]
2018-07-12 07:46:36 +00:00
Pierre Goiffon
54d54ca78e Fix setup for PHP 5.5 (cannot use expression as default field value)
SVN:trunk[5933]
2018-07-12 07:45:13 +00:00
Eric Espié
4cd591f81c DBObject->GetOriginal() hardening (now support attributes not set: for example sla_tto_passed for UserRequest until it is closed)
SVN:trunk[5932]
2018-07-11 13:40:38 +00:00
Denis Flaven
774ecb4003 (retrofit from trunk) Do not check if the organizations are allowed if there is no user logged in (use case: automatic synchro of users at connection time)
SVN:2.5[5931]
2018-07-05 13:02:10 +00:00
Denis Flaven
d21d732545 Do not check if the organizations are allowed if there is no user logged in (use case: automatic synchro of users at connection time)
SVN:trunk[5930]
2018-07-05 12:54:58 +00:00
Pierre Goiffon
ea4854d239 fix comment typo
SVN:trunk[5929]
2018-07-02 07:48:28 +00:00
Guillaume Lajarige
7ca95b9413 Code cleanup: Warning suppression & PHPDoc.
SVN:trunk[5928]
2018-06-29 17:14:13 +00:00
Guillaume Lajarige
00d0d383f8 Code cleanup: Warning suppression & PHPDoc.
SVN:trunk[5927]
2018-06-29 16:05:11 +00:00
Bruno Da Silva
401a8cdd77 Lab "performance"
- move some heavy introspection into cached part of MetaModel aka iterate over get_declared_classes() in order to check is_subclass_of($sPHPClass, 'ModuleHandlerAPI')
 - make use of an interface in order to rely on existing code

SVN:trunk[5926]
2018-06-29 13:00:18 +00:00
Guillaume Lajarige
b2384855fd Code cleanup: Warning suppression.
SVN:trunk[5925]
2018-06-28 15:33:29 +00:00
Guillaume Lajarige
602c087c29 N°1528 Portal: Add support for SCSS files through the PortalUIExtension API (only CSS were supported)
SVN:trunk[5924]
2018-06-28 14:51:31 +00:00
Guillaume Lajarige
0d96ed5436 Starting dev on iTop 2.6!
SVN:trunk[5923]
2018-06-28 08:27:15 +00:00
Guillaume Lajarige
c555d1274b Creating SVN branch for iTop 2.5
SVN:2.5[5920]
2018-06-28 08:22:50 +00:00
Pierre Goiffon
97fa3ac3b3 Fix portal DE translation (thanks again Lars Hippler / Itomig !)
SVN:trunk[5919]
2018-06-28 07:15:39 +00:00
Eric Espié
261bc83811 N°1479 : Fixed a bug where impact analysis zoom would affect other tabs' size #jfb :)
SVN:trunk[5918]
2018-06-27 15:42:32 +00:00
Vincent Dumas
2dbaf4dfa1 german translation for Graphique in Portal
SVN:trunk[5917]
2018-06-27 15:38:45 +00:00
Pierre Goiffon
5df9f38391 German translations update (many thanks Lars Hippler / Itomig !)
SVN:trunk[5916]
2018-06-27 15:14:19 +00:00
Eric Espié
93763c5932 N°1401 - External dashlet edition in the designer #jfb :)
SVN:trunk[5915]
2018-06-27 14:42:28 +00:00
Eric Espié
242caff990 N°1401 - External dashlet edition in the designer
SVN:trunk[5914]
2018-06-27 13:58:36 +00:00
Romain Quetiez
e97e9907c7 Releasing 2.5.0
SVN:trunk[5913]
2018-06-27 12:47:15 +00:00
Guillaume Lajarige
ac330b6665 Fix dashlet container CSS class for better positioning
SVN:trunk[5912]
2018-06-27 08:23:59 +00:00
Guillaume Lajarige
a4a70a1287 German translation placeholders for iTop 2.5
SVN:trunk[5911]
2018-06-26 15:36:55 +00:00
Vincent Dumas
dda8651ba2 Add default search criterion on SynchroDataSource
SVN:trunk[5910]
2018-06-25 15:57:06 +00:00
Guillaume Lajarige
83e2d48f4d N°1401 Fix none draggable third-party dashlets in a dashboard.
SVN:trunk[5909]
2018-06-25 14:17:41 +00:00
Vincent Dumas
a903711a7a Add default search criterion on Action and Profile classes
SVN:trunk[5908]
2018-06-25 13:23:35 +00:00
Vincent Dumas
9e17a611d2 Add 'name' and 'description' as default search criteria on QueryPhrase, Audit Category and Profile. Enable search bar on Profile and Audit Category menus.
SVN:trunk[5907]
2018-06-25 11:06:52 +00:00
Eric Espié
1e11ed3041 N°1381 - Search on string with index -> operator = (Fixed for derived classes)
SVN:trunk[5906]
2018-06-25 10:51:15 +00:00
Vincent Dumas
0449470cdf Add 'name' as default search criteria on QueryPhrase
SVN:trunk[5905]
2018-06-25 10:11:39 +00:00
Eric Espié
21a5a2d4ef N°1522 - Dashlet group by on stopwatch
SVN:trunk[5904]
2018-06-25 09:59:36 +00:00
Eric Espié
a848cb28f1 N°1436 - Access control updated for grant_by_profile categories of classes -
Fix access to internal classes form the core engine

SVN:trunk[5903]
2018-06-22 16:07:35 +00:00
Denis Flaven
b7ae6b143e Impact analysis performance enhancement: much better (and faster) processing of graphs containing loops.
SVN:trunk[5902]
2018-06-22 15:56:17 +00:00
Stephen Abello
ba0c18eec1 N°1479 : Fixed a bug where impact analysis zoom would affect other tabs' size
SVN:trunk[5901]
2018-06-22 13:51:21 +00:00
Guillaume Lajarige
61366b347d Code cleanup
SVN:trunk[5900]
2018-06-22 12:46:30 +00:00
Guillaume Lajarige
edab6643f6 Portal: Add default width and decoration class to FilterBrick.
SVN:trunk[5899]
2018-06-22 12:34:02 +00:00
Stephen Abello
ce36ef3aad N°1479 : Fixed a bug where impact analysis zoom would reduce div size
SVN:trunk[5898]
2018-06-22 07:58:48 +00:00
Stephen Abello
fdb439f054 N°1520 : URP_Profiles now has a default search criteria
SVN:trunk[5897]
2018-06-21 13:22:01 +00:00
Stephen Abello
2229f3f015 N°1395 : New Portuguese BR translations (thanks to Anderson Cardoso!)
SVN:trunk[5896]
2018-06-21 08:22:23 +00:00
Pierre Goiffon
18a5df1ce7 modify all in views : fix header checkbox not checked after check_all event fired
SVN:trunk[5895]
2018-06-19 10:05:57 +00:00
Eric Espié
f5cb29fadd N°1513 - Datamodel menu access control
SVN:trunk[5894]
2018-06-19 08:49:06 +00:00
Eric Espié
d929732fb6 N°1495 - Regression: Search on hierarchical key
SVN:trunk[5893]
2018-06-19 08:42:58 +00:00
Eric Espié
6c36f3bc7c N°1495 - Regression: Search on hierarchical key
SVN:trunk[5892]
2018-06-19 08:32:54 +00:00
Vincent Dumas
c6a59a5309 Suppression of obsolesence condition on Ticket (was creating performance issue)
SVN:trunk[5891]
2018-06-18 16:26:03 +00:00
Pierre Goiffon
b02c30a525 Translation keys available client side (Dict.S()) : format + JS/PHPDoc
SVN:trunk[5890]
2018-06-18 15:55:10 +00:00
Guillaume Lajarige
46a647ae66 N°1514 Add missing translations for advanced search.
SVN:trunk[5889]
2018-06-18 14:11:04 +00:00
Denis Flaven
8943a67f85 Officially support PHP 7.2.0.
SVN:trunk[5888]
2018-06-15 16:37:11 +00:00
Guillaume Lajarige
f132d751f5 N°1303 Portal: ManageBrick lists are now ordered regarding the datamodel definition (//class/properties/order).
SVN:trunk[5887]
2018-06-15 14:00:28 +00:00
Guillaume Lajarige
4ba8c9ff9e Fix default classes order by on DBObjectSet.
SVN:trunk[5886]
2018-06-15 13:42:00 +00:00
Guillaume Lajarige
955ae6c392 Portal: Remove unused folder.
SVN:trunk[5885]
2018-06-15 12:46:39 +00:00
Guillaume Lajarige
ed33b327fb Portal: Add XML comments to standard portal configuration.
SVN:trunk[5884]
2018-06-15 12:46:06 +00:00
Guillaume Lajarige
f8f7486be2 N°1244 Authorize "colspan" & "rowspan" attributes on "th" / "td" / "tr" tags in HTML fields.
SVN:trunk[5883]
2018-06-15 10:09:35 +00:00
Bruno Da Silva
3215875e5f N°462 : Added an information about file max size on portal forms
SVN:trunk[5882]
2018-06-15 09:57:02 +00:00
Guillaume Lajarige
62da90418a Portal: Default object forms are now more like in the administration console instead of just having their fields one after another. (BETA!)
SVN:trunk[5881]
2018-06-15 09:16:36 +00:00
Bruno Da Silva
7c620fae78 N°607 : Fixed an issue where a file on a transition form wouldn't be uploaded
SVN:trunk[5880]
2018-06-15 09:02:22 +00:00
Bruno Da Silva
daef0c3a8f N°1430 Fixed an issue on n-n Date attributes
SVN:trunk[5879]
2018-06-15 08:25:55 +00:00
Guillaume Lajarige
52b6d399a0 Portal: Remove copyright from page footer.
SVN:trunk[5878]
2018-06-15 08:10:11 +00:00
Guillaume Lajarige
f210f63ec4 Portal: Change ManageBrick XML definition for tile & page display modes.
SVN:trunk[5877]
2018-06-15 08:09:12 +00:00
Bruno Da Silva
41694050ea N°1498 Fixed an issue on Advanced search external key autocomplete where homonyms weren't displayed
SVN:trunk[5876]
2018-06-15 07:34:11 +00:00
Pierre Goiffon
3f612cfc90 some PHPDoc
SVN:trunk[5875]
2018-06-14 15:19:30 +00:00
Guillaume Lajarige
272acdd8d3 Portal: Fix OQL exception in ManageBrick when grouping tabs on an attribute (instead of sub OQLs).
SVN:trunk[5874]
2018-06-14 15:10:14 +00:00
Eric Espié
5a4375cb71 N°1485 - Search: "Undefined" on hierarchical key not working
SVN:trunk[5873]
2018-06-14 14:56:42 +00:00
Guillaume Lajarige
5b3d7e2354 Portal: Fix missing parameter in new ScopeValidatorHelper::AddScopeToQuery() method. "Read" scope was always applied!
SVN:trunk[5872]
2018-06-14 14:38:48 +00:00
Guillaume Lajarige
189cefac1b Portal: Forgot to commit generated CSS file.
SVN:trunk[5871]
2018-06-14 13:51:58 +00:00
Guillaume Lajarige
87d36914c4 Portal: Enhancements on ManageBrick badges UI.
SVN:trunk[5870]
2018-06-14 12:32:58 +00:00
Guillaume Lajarige
72e14805b1 Portal: Fix HTML tooltips in ManageBrick tiles.
SVN:trunk[5869]
2018-06-14 10:29:34 +00:00
Guillaume Lajarige
87e2f76793 Portal: Improvements on ManageBrick badge tiles UI.
SVN:trunk[5868]
2018-06-14 10:28:06 +00:00
Bruno Da Silva
8fbd53d72d N°1500 Advanced search on external keys performance
- bugfix: do not run both queries if nb result is >= 150

SVN:trunk[5864]
2018-06-14 08:14:53 +00:00
Guillaume Lajarige
586cc1f003 Portal: Fix regression introduced in r5862.
SVN:trunk[5863]
2018-06-14 07:12:38 +00:00
Guillaume Lajarige
a77753cfef Portal: Rework on ManageBrick to put D3/C3 in the portal core instead of using an external API.
SVN:trunk[5862]
2018-06-13 16:03:59 +00:00
Eric Espié
5e464ef3a2 N°1484 - Advanced search: empty/not empty not working
SVN:trunk[5861]
2018-06-13 15:22:43 +00:00
Guillaume Lajarige
0727c9774b Portal: Fixes on ManageBrick routes and display modes.
SVN:trunk[5860]
2018-06-13 15:21:45 +00:00
Bruno Da Silva
ee43a365dc N°1500 Advanced search on external keys performance
- first search using "equals" or "start with"
- then using "contains"
- search is triggered at two first chars

SVN:trunk[5859]
2018-06-13 13:36:31 +00:00
Eric Espié
d5ba0d9ed5 N°1401 - External dashlet edition in the designer
SVN:trunk[5858]
2018-06-13 11:46:37 +00:00
Stephen Abello
7031a52a43 N°1499 : Edge case where picking a datetime and pressing enter would not close the criterion
SVN:trunk[5857]
2018-06-13 09:49:49 +00:00
Stephen Abello
12af164dcc N°1482 : Retrocompatibility hack for non "standard" extensions' search form
SVN:trunk[5856]
2018-06-12 14:01:35 +00:00
Eric Espié
362cd72e87 N°1325 Dashboards: Unknown dashlets: keep the original type of the unknown dashlet
SVN:trunk[5855]
2018-06-12 08:56:41 +00:00
Guillaume Lajarige
cb19520b6b N°1453 Portal: Fix regression introduced by previous change.
SVN:trunk[5854]
2018-06-11 15:22:12 +00:00
Eric Espié
c74972488d Don't automatically launch the search results when coming from an object detail
SVN:trunk[5853]
2018-06-11 15:01:39 +00:00
Eric Espié
b78e40153f N°858 - Archive mode: WRITE write access menus disappear in archive mode
SVN:trunk[5852]
2018-06-11 14:32:17 +00:00
Eric Espié
f7212662b9 N°1420 - Performances enhancement (consider search auto-submit parameter)
SVN:trunk[5851]
2018-06-11 13:17:15 +00:00
Eric Espié
97c8e1f7a9 N° 1436 - Allowed orgs on Users not managed
SVN:trunk[5850]
2018-06-11 10:02:20 +00:00
Guillaume Lajarige
2afc6d1c62 N°1453 Portal: Fix ajax filter on ManageBrick that was looking on "standard_search" zlist attributes instead of the brick fields.
SVN:trunk[5849]
2018-06-11 07:55:40 +00:00
Guillaume Lajarige
708858da39 Portal: Fix regression in FilterBrick that crashes when pointing on a ManageBrick.
SVN:trunk[5848]
2018-06-08 16:33:55 +00:00
Stephen Abello
41dccb468e N°1236 : Added "approved" state to the tto active states
SVN:trunk[5847]
2018-06-08 14:17:44 +00:00
Eric Espié
36cfe9e5c2 N°1445 - Regression: User cannot change language
SVN:trunk[5846]
2018-06-08 13:18:06 +00:00
Eric Espié
1c7fd57f2e N°1431 - Dashlet: Tri sur le champ ou la fonction (Fix error on Pie chart)
SVN:trunk[5845]
2018-06-08 13:15:39 +00:00
Eric Espié
f920851420 N°1420 - Performances enhancement (enhance counts)
SVN:trunk[5844]
2018-06-08 13:13:33 +00:00
Stephen Abello
04b8fe3326 N°1496 : Fixed datamodel viewer for IE11 : IE doesn't support backtick character in JS
SVN:trunk[5843]
2018-06-08 13:02:19 +00:00
Eric Espié
9fb4374efa N°1420 - Performances enhancement (fix indexes generation)
SVN:trunk[5841]
2018-06-08 12:58:29 +00:00
Stephen Abello
885cabd6ef N°1479 : Fixed a regression where on impact analysis display, every tabs would be resized to 15px. Added css for advanced search for impact analysis & normal search
SVN:trunk[5840]
2018-06-08 10:17:58 +00:00
Eric Espié
e00f9c2a83 N°1420 - Performances enhancement (fix regression on yesterday commit)
SVN:trunk[5836]
2018-06-08 09:15:19 +00:00
Guillaume Lajarige
fe24eda4b4 N°1494 Portal: Fix images size on mosaic view. They could be too height sometimes.
SVN:trunk[5835]
2018-06-08 08:42:38 +00:00
Eric Espié
483d80b576 N°1420 - Performances enhancement (fix indexes generation)
SVN:trunk[5834]
2018-06-08 08:18:57 +00:00
Eric Espié
70a0a3c52e N°1420 - Performances enhancement
SVN:trunk[5833]
2018-06-07 15:06:38 +00:00
Denis Flaven
5b2f32c08a Enhancement of the data collection for iTop Hub: better detection of the web server version.
SVN:trunk[5831]
2018-06-07 11:46:45 +00:00
Stephen Abello
5bad1e1c88 N°1476 : Fixed a regression introduced in 2.5 where on changing final class on a n-n object selection form, checkboxes were lost.
SVN:trunk[5830]
2018-06-07 07:41:49 +00:00
Eric Espié
2706ebf638 Merged from 2.4
N°1488 - restore failed on production-modules [from revision 5827]

SVN:trunk[5828]
2018-06-05 14:14:37 +00:00
Denis Flaven
9fe3261424 Linked JS scripts can now be used in ajax pages. This is useful for IPopupMenu extensions which depend on a JS script and are loaded asynchronously when a list of objects changes (for example when changing the target class for a search)
SVN:trunk[5826]
2018-06-05 13:04:50 +00:00
Denis Flaven
9df087984f (Internal) declare the member variables with the correct names: declare what is actually used !!
SVN:trunk[5825]
2018-06-05 13:02:33 +00:00
Denis Flaven
cbb9bcd93d Proper use of the "304" (Not modified) HTTP header for InlineImages. Seems that FastCGI is more sensitive to incorrect HTTP headers than MPM...
SVN:trunk[5824]
2018-06-05 12:59:17 +00:00
Bruno Da Silva
ad8f7576e0 N°1381 Advanced search did not correctly compute indexes for "other" list of fields
SVN:trunk[5823]
2018-05-31 07:41:03 +00:00
Pierre Goiffon
e205d85728 Portal : new helper method to add scope to a DbSearch (moved from existing one in ManageBrick)
SVN:trunk[5822]
2018-05-30 16:44:23 +00:00
Guillaume Lajarige
a01d5c2760 Fix regression introduced in r5806. Making the ITSM Designer unstable when adding a new attribute to a class.
SVN:trunk[5821]
2018-05-30 16:03:33 +00:00
Stephen Abello
b57423386c N°1477 : fixed an issue where datamodel viewer couldn't load attributes' filters with backspaces in it
SVN:trunk[5818]
2018-05-30 07:46:27 +00:00
Vincent Dumas
22e525452a Rename the id of the Portal contact scope for administrator, as there was two scopes with id="all"
SVN:trunk[5817]
2018-05-29 16:12:08 +00:00
Vincent Dumas
6c84074b02 Enable CSV export of on-going and closed tickets from the User Portal
SVN:trunk[5816]
2018-05-28 15:57:20 +00:00
Denis Flaven
6cc4a6e1be PHP 7.2 compatibility: count(null) now generates a PHP warning !!
SVN:trunk[5815]
2018-05-28 14:08:31 +00:00
Eric Espié
04e41ab676 N°1431 - Sort on attribute or aggregation function
SVN:trunk[5814]
2018-05-25 15:38:36 +00:00
Guillaume Lajarige
3ad64d9823 N°1472 Portal: OQL optimization in ManageBrick when several UNIONs are used.
SVN:trunk[5812]
2018-05-23 15:00:41 +00:00
Eric Espié
8de7ff5470 Fix broken menus on search from dashlet header statistics
SVN:trunk[5811]
2018-05-23 14:50:17 +00:00
Stephen Abello
0a44f34c2c N°1444 : fixed regression introduced in [r5724] & [r5773]
SVN:trunk[5809]
2018-05-23 10:11:23 +00:00
Bruno Da Silva
4f900e36c1 Advanced search:
- deduplicate pre-existing criterion N°1454
- search's 'breadcrumb' and 'history.replaceState' now preserve the org_id parameter

SVN:trunk[5808]
2018-05-22 16:03:38 +00:00
Eric Espié
571d90618e cleanup code
SVN:trunk[5807]
2018-05-22 15:26:08 +00:00
Eric Espié
fe8436f2ad cleanup code
SVN:trunk[5806]
2018-05-22 15:14:51 +00:00
Eric Espié
a4459901e8 N°1429: Dashlet header statistics fix corresponding search criteria
SVN:trunk[5805]
2018-05-22 14:57:05 +00:00
Bruno Da Silva
bef8fd566f Advanced search: fix a side effect of the new behaviour "validate the draft" when the criteria is closed by a click outside of it's box
- when a criteria is being edited and the user click on search/refresh button, the search handler now update the criteria BEFORE making the ajax call

SVN:trunk[5804]
2018-05-22 13:20:07 +00:00
Bruno Da Silva
0f9994ac74 Advanced search: several improvements
- remove a side effect on script listening to the body (by removing an overly agressive top propagation on body listener)
- Submit on click outside of the criteria N°1381
- Do not auto submit when values do not changes N°1381	
- Open criteria on click on the bold part of the title was broken

SVN:trunk[5803]
2018-05-22 08:06:45 +00:00
Bruno Da Silva
8691ccc013 test: reduce the verbosity of test cases
SVN:trunk[5802]
2018-05-18 14:57:41 +00:00
Eric Espié
bac7b50090 N°1429 - Fix regression due to "Display results wrt obsolescence display choices"
SVN:trunk[5801]
2018-05-18 12:20:22 +00:00
Stephen Abello
39ff1e318c N°1319 & N°1203: Refactored [r5750]
SVN:trunk[5800]
2018-05-17 14:43:46 +00:00
Stephen Abello
1f8110573c N°1226 : When global searching with needles smaller than 'full_text_needle_min', exclude these needles from the search instead of stopping it
SVN:trunk[5799]
2018-05-17 14:16:18 +00:00
Eric Espié
7c128e0f6e DBSearch: test with only functions (no group by)
SVN:trunk[5798]
2018-05-17 12:00:28 +00:00
Romain Quetiez
11b50b4917 #815 Cosmetics on the documentation shown upon setup completion (Completing the iTop installation for workflow management): the file cron.params has been renamed into cron.distrib
SVN:trunk[5797]
2018-05-17 10:01:56 +00:00
Bruno Da Silva
9d771be8b2 N°955: fix the bugfix [r5766]
- handling of forbidden char code in the error message (happen for example on host error using a french windows), in this case a less verbose message is written in the table, and a issue log is written into the fs 
- apply for both synchronous and asynchronous

SVN:trunk[5796]
2018-05-17 09:55:58 +00:00
Bruno Da Silva
02315b8aa1 N°880: fix the bugfix [r5737]
- previous bugfix altered the cron frequency, this is not the desired behaviour, now the conf alter the lifetime of drafts's attachments
- apply for both inline images and attachments

SVN:trunk[5795]
2018-05-16 13:03:15 +00:00
Denis Flaven
7fb3d133e3 Typo in the CSS class name !!
SVN:trunk[5794]
2018-05-16 09:44:58 +00:00
Bruno Da Silva
65fb29a1d4 N°1226: code refactoring of the previously coded bugfix.
SVN:trunk[5793]
2018-05-16 08:07:00 +00:00
Bruno Da Silva
703a432f7b N°1173: code refactoring of the previously coded bugfix.
SVN:trunk[5792]
2018-05-16 08:01:59 +00:00
Eric Espié
4d37942717 cleanup
SVN:trunk[5791]
2018-05-15 15:53:59 +00:00
Eric Espié
137067ea43 cleanup and fix Group by queries
SVN:trunk[5790]
2018-05-15 15:12:57 +00:00
Stephen Abello
67e12dcc74 Type in revision nb
SVN:trunk[5789]
2018-05-15 14:48:05 +00:00
Eric Espié
911c0d2c1b N°1429 - Display results wrt obsolescence display choices
SVN:trunk[5788]
2018-05-15 13:39:22 +00:00
Eric Espié
4b9648affa N°1429 - fix value list display when editing a dynamic header dashlet in french
SVN:trunk[5787]
2018-05-15 13:20:42 +00:00
Eric Espié
804afa65f2 DBSearch: test with only functions (no group by)
SVN:trunk[5786]
2018-05-15 12:35:44 +00:00
Eric Espié
c56dc6cade code cleanup
SVN:trunk[5785]
2018-05-15 12:30:52 +00:00
Eric Espié
c4f7055e1a N°1330 - Fix broken sql requests due to the use of class instead of alias
SVN:trunk[5784]
2018-05-15 12:17:00 +00:00
Eric Espié
44b6dfab1d DBSearch: add test with only functions (no group by)
SVN:trunk[5782]
2018-05-15 08:59:49 +00:00
Eric Espié
50e79b8c97 Advanced search: fix date time i18n and 1 second/day add/remove on > and <
SVN:trunk[5781]
2018-05-15 08:33:54 +00:00
Bruno Da Silva
185825f83c advanced search: dates i18n tests
SVN:trunk[5780]
2018-05-15 08:17:02 +00:00
Eric Espié
c6be331f14 Code cleanup
SVN:trunk[5779]
2018-05-14 07:41:51 +00:00
Eric Espié
c0dd418992 N°478 - Access rights on admin menus and support for some classes not in XML (in OQL, dashlets and groups)
SVN:trunk[5778]
2018-05-11 13:58:27 +00:00
Pierre Goiffon
c03d5167f6 N°1418 audit : fix regression, error with union queries in AuditRule
SVN:trunk[5777]
2018-05-09 16:47:54 +00:00
Bruno Da Silva
56d625b7b9 PHPunit is now integrated through composer (inside the directory /test)
SVN:trunk[5776]
2018-05-04 16:13:26 +00:00
Bruno Da Silva
e74b23f305 PHPunit is now integrated through composer (inside the directory /test)
SVN:trunk[5775]
2018-05-04 15:59:34 +00:00
Pierre Goiffon
6e7d2abc9a N°1418 fix audit with valid_flag=true that were always failing
SVN:trunk[5773]
2018-05-04 15:10:25 +00:00
Pierre Goiffon
3bebb9bf0f convert inline comment to PHPDoc
SVN:trunk[5772]
2018-05-04 15:08:48 +00:00
Bruno Da Silva
1063697e85 N°865: exports (csv, xslx, pdf) LocalizeOutput option lost
- it happens when the export has more thant one chunk, stating the 2d chunk.
- this option is now persisted and restored on each chunk

SVN:trunk[5771]
2018-05-04 12:49:27 +00:00
Bruno Da Silva
7bdad90564 bugfix: sanitization filter "parameter" => Since the filter parameter is now url-encoded, it now may contains %3D, %2B and %2F (respectively =, + and /).
a migration note was written : https://wiki.combodo.com/doku.php?id=latest:install:240_to_250_migration_notes#param_filter

SVN:trunk[5770]
2018-05-04 10:13:29 +00:00
Stephen Abello
1dccc54814 N°1385 : Bare relation tabs on FunctionCI now correctly display item count according to user obsolescence preferences.
SVN:trunk[5769]
2018-05-04 09:52:47 +00:00
Stephen Abello
1c255213e1 N°974 : MySQL strict mode compatibility (null replaced 0000-00-00 00:00:00 for DateTime).
SVN:trunk[5768]
2018-05-04 08:29:32 +00:00
Stephen Abello
cb2c172483 N°1173 : mysqldump now correctly use 'mysql_bindir' parameter on setup & move to prod's backups
SVN:trunk[5767]
2018-05-03 15:00:13 +00:00
Stephen Abello
b43063a6d2 N°995 : Update notification status when its async task fail
SVN:trunk[5766]
2018-05-02 14:40:22 +00:00
Stephen Abello
3974406f1b N°1175 : Fixed missing params error occurring when resetting password from a notification linking to portal.
SVN:trunk[5763]
2018-05-02 08:19:27 +00:00
Eric Espié
21aed2d2e1 Advanced Search: Fix missing query internal params
SVN:trunk[5762]
2018-05-02 08:11:28 +00:00
Pierre Goiffon
820c257e96 N°1427 New method to fix timezone where datamodel is not yet loaded
SVN:trunk[5761]
2018-05-02 06:36:57 +00:00
Pierre Goiffon
56e5616080 N°1370 Portal badge : improve tile on low resolutions 2 (wooops pushed to soon)
SVN:trunk[5759]
2018-04-27 15:59:24 +00:00
Pierre Goiffon
6f7351ecc3 @@N°1370 Portal badge : improve tile on low resolutions
SVN:trunk[5758]
2018-04-27 15:53:34 +00:00
Eric Espié
8f56032d49 Fix Bug delete when the serialized filter contains %
SVN:trunk[5757]
2018-04-27 15:53:08 +00:00
Guillaume Lajarige
1b6ca2ed14 N°1425 Fix regression introduced in 2.4. Creation of an object in a specific state could result in a fatal error due to bad ormlinkSet initialization.
SVN:trunk[5755]
2018-04-27 14:17:55 +00:00
Stephen Abello
d956682b9f N°1285 & N°1278: Updated swiftmailer to v5.4.9
SVN:trunk[5754]
2018-04-27 14:06:51 +00:00
Stephen Abello
76759f1847 N°1424 : Sharing base compatibility fix
SVN:trunk[5751]
2018-04-27 12:14:39 +00:00
Stephen Abello
d441595ee6 N°1319 & N°1203: Added a conf params 'email_default_sender_address' and 'email_default_sender_label' that will be used if a mail has no sender set. (forgot password, test mail, test notification mail, data source fail notification)
SVN:trunk[5750]
2018-04-27 08:29:48 +00:00
Pierre Goiffon
2be0250aee N°1370 Portal badge : wooops forgot the .css as always :/
SVN:trunk[5744]
2018-04-26 13:08:43 +00:00
Pierre Goiffon
b2a3b10065 N°1370 Portal badge : tooltips for descriptions
SVN:trunk[5743]
2018-04-26 12:57:29 +00:00
Pierre Goiffon
22b181a8f7 N°1370 Portal badge : change some aligns + handle description correctly
SVN:trunk[5742]
2018-04-26 12:56:54 +00:00
Pierre Goiffon
71d07be646 N°1370 portal badges : number on top of the description and wider
SVN:trunk[5741]
2018-04-26 09:18:12 +00:00
Guillaume Lajarige
95e56e7148 Portal: Fix regression introduced in revision 5698.
SVN:trunk[5739]
2018-04-25 09:07:28 +00:00
Vincent Dumas
ec471520f2 Datamodel: Person phones now supports click to call.
SVN:trunk[5738]
2018-04-24 12:48:12 +00:00
Stephen Abello
65b516d761 N°880 : Added a conf param (inline_image_garbage_collector_interval)
SVN:trunk[5737]
2018-04-24 12:36:03 +00:00
Denis Flaven
7d45d5e0ce Cosmetics on the TLS option in the setup (prevent flashing of the hidden content)
SVN:trunk[5736]
2018-04-24 12:35:13 +00:00
Guillaume Lajarige
d8e3966825 Portal: Small CSS enhancements on ManageBrick.
SVN:trunk[5735]
2018-04-24 12:25:54 +00:00
Denis Flaven
65409373eb Enhancement: automatic re-ordering of the background tasks at each execution of cron.php so that one single task cannot use all the CPU time.
SVN:trunk[5734]
2018-04-24 12:12:36 +00:00
Denis Flaven
50a1449a2a Bug fix: background tasks should not echo anything, but unless return the string to output.
SVN:trunk[5733]
2018-04-24 12:08:36 +00:00
Stephen Abello
8150faaa40 N°1226 : On globalsearching, the searched text is now placed as input value instead of placeholder value
SVN:trunk[5732]
2018-04-24 12:06:04 +00:00
Eric Espié
019542ff10 iTop 2.5.0 beta
SVN:trunk[5731]
2018-04-24 11:58:50 +00:00
Bruno Da Silva
20def0de02 bugfix: advanced search
- dates has to handle two format : the user's current and the system storage yyy-mm-dd. the system is now only handled on load ans=d converted to the user's one.
- if the date is not parsable, the fallback is now the current date.
- removal of a no more needed date setter (leaved in the comments since it may be nescessary to re-add this if the UI changes again and if the less panel has to display the dates without time 
- factorisatoin of the date/time formating into a function

SVN:trunk[5730]
2018-04-24 07:25:26 +00:00
Eric Espié
4a30a875f0 iTop 2.5.0 beta
SVN:trunk[5729]
2018-04-23 15:48:24 +00:00
Eric Espié
61905f111b iTop 2.5.0 beta
SVN:trunk[5728]
2018-04-23 15:27:10 +00:00
Eric Espié
1832d72e51 Version 1.5 of XML datamodel
SVN:trunk[5727]
2018-04-23 15:14:11 +00:00
Eric Espié
4d63b9e463 Fix initial setup error (Notice: Undefined index: CharMaxLength)
SVN:trunk[5726]
2018-04-23 14:59:31 +00:00
Pierre Goiffon
7b54f51d75 N°1418 Audits Perf optimization for AuditRule with valid_flag=true and lots of negative records
Use a new helper method that don't parse values anymore on SELECT IN / NOT IN queries

SVN:trunk[5724]
2018-04-23 14:48:40 +00:00
Pierre Goiffon
eaf94bc10a Audit : some more PHPDoc
SVN:trunk[5723]
2018-04-23 14:46:37 +00:00
Stephen Abello
9d6b5d347c Datamodel viewer: autocomplete validation goes to selected class, autofocus on autocomplete field, delete input text button, add_init_script for itopwebpage class, fixed cases where default value and default null value were array instead of strings, visual tweaks
SVN:trunk[5722]
2018-04-23 14:25:28 +00:00
Bruno Da Silva
e82a16146e typo
SVN:trunk[5721]
2018-04-23 13:09:44 +00:00
Bruno Da Silva
9797021511 bugfix: advanced search
- dates has to handle two format : the user's current and the system storage yyy-mm-dd. the system is now only handled on load ans=d converted to the user's one.
- if the date is not parsable, the fallback is now the current date.
- removal of a no more needed date setter (leaved in the comments since it may be nescessary to re-add this if the UI changes again and if the less panel has to display the dates without time 
- factorisatoin of the date/time formating into a function

SVN:trunk[5720]
2018-04-23 12:20:48 +00:00
Vincent Dumas
c27a9e8193 Fix email typo in English dictionnary
SVN:trunk[5719]
2018-04-23 10:09:52 +00:00
Eric Espié
c5506dab5d Internal version => 2.5.0 (beta)
SVN:trunk[5718]
2018-04-23 07:37:25 +00:00
Eric Espié
d120109a78 Setup: Display the XML errors on the screen (cleanup deprecated functions)
SVN:trunk[5717]
2018-04-20 16:02:41 +00:00
Eric Espié
b529f3d4cc Setup: Display the XML errors on the screen
SVN:trunk[5716]
2018-04-20 15:56:53 +00:00
Vincent Dumas
ea11b76461 Fix typo in dictionnary
SVN:trunk[5715]
2018-04-20 15:12:42 +00:00
Vincent Dumas
09c54d4fed Fix DataSynchro Group to allow management of DataSynchros through WebServices for non admin users
SVN:trunk[5714]
2018-04-20 15:10:33 +00:00
Bruno Da Silva
c5f00c5363 bugfix: advanced search
- dates "<=" operator handling

SVN:trunk[5713]
2018-04-20 15:06:28 +00:00
Eric Espié
256808c473 Advanced Search: Date transform from < and > to <= and >= for the search
SVN:trunk[5712]
2018-04-20 14:54:32 +00:00
Bruno Da Silva
487d89d970 bugfix: advanced search
- datepicker not displayed in dialogs : because the datepicker had a lower z-index. It is now forced using the `beforeShow` datepicker's option so we do not force it globaly has if we had done this using the css

SVN:trunk[5711]
2018-04-20 14:50:48 +00:00
Bruno Da Silva
ed3665b8c5 bugfix: advanced search
- date i18n : non standard date formating was totally wrong, full rewrite of date parsing (in getter and setter) relying on datepicker and datetimepicker parsers (they are awfull)
- date "now" button do no more close the criteria
- ie9 compat. : use history.replaceState only if available in order to prevent bugs with ie9

SVN:trunk[5710]
2018-04-20 14:32:32 +00:00
Bruno Da Silva
ef7a9ff02e bugfix: query serialization edge case
it did break when a "+" was present in the url, a rawurlencode was added, it is backward compatible because for pre-existing string, there is no % present so the unserialization's rawurldecode is without BC effect.

SVN:trunk[5709]
2018-04-20 13:54:53 +00:00
Eric Espié
aa4416ac4e Advanced Search: Display links also when the object is not visible
SVN:trunk[5708]
2018-04-20 13:45:02 +00:00
Stephen Abello
c734eec9e1 N°729 Form prefill : Minor fix in variables naming
SVN:trunk[5707]
2018-04-20 13:42:12 +00:00
Eric Espié
e1caf61a18 N°1248 - Fix API access (back to the same behavior as 2.4.1)
SVN:trunk[5706]
2018-04-20 12:32:01 +00:00
Eric Espié
f7879256c1 N°1248 - Fix API access (back to the same behavior as 2.4.1)
SVN:trunk[5705]
2018-04-20 12:30:20 +00:00
Eric Espié
1c86eba9d9 N° 1001 - utf8-mb4 removed innodb_large_prefix requirement
SVN:trunk[5704]
2018-04-20 12:14:32 +00:00
Stephen Abello
6a089aa1b7 N°729 Form prefill : Included Contract case in the datamodel.
SVN:trunk[5703]
2018-04-20 10:07:43 +00:00
Guillaume Lajarige
9a3749c1ed Advanced search: Fix IE9 bug when trying to add a criteria.
SVN:trunk[5702]
2018-04-20 09:50:13 +00:00
Eric Espié
d82b755557 N° 1001 - Database index size changed to support utf8-mb4
SVN:trunk[5701]
2018-04-20 09:44:12 +00:00
Eric Espié
5b83f2a554 Fix setup (support for distrib > 9.x.x)
SVN:trunk[5700]
2018-04-20 09:40:27 +00:00
Guillaume Lajarige
1f2b01937b Advanced search: Code cleanup.
SVN:trunk[5699]
2018-04-20 09:01:48 +00:00
Guillaume Lajarige
18bd0ae096 N°1405 Add support of AttributePhoneNumber which allows launch of phone application on click.
SVN:trunk[5698]
2018-04-19 15:56:11 +00:00
Denis Flaven
512f368cbf (regression) Do not block the execution of the page (based on the access rights on the menu) since the page is used for all exports. The export will be blocked anyway if the user does not have the BULK_READ rights on the target class.
SVN:trunk[5697]
2018-04-19 13:43:53 +00:00
Guillaume Lajarige
853d9ee87f Advanced search: Update french translations.
SVN:trunk[5696]
2018-04-19 07:43:28 +00:00
Guillaume Lajarige
e9440d0d4c Advanced search: Fix criteria closed after search modal.
SVN:trunk[5695]
2018-04-19 07:37:11 +00:00
Bruno Da Silva
381a988f43 bugfix: iTop Hub compatibility repaired
the new abstract classes used by admin menu management broke iTop hub installer

SVN:trunk[5694]
2018-04-18 15:27:22 +00:00
Pierre Goiffon
5d6ec4ce56 N°1370 ManageBrick charts tile : integrate CSS in portal.scss
SVN:trunk[5693]
2018-04-18 15:16:04 +00:00
Eric Espié
182e644a33 Fix setup
SVN:trunk[5692]
2018-04-18 14:30:33 +00:00
Denis Flaven
c719fbf7fc Bug fix (regression): use a different endpoint (ajax.document.render.php) for the output of the JS dictionary since we use the JS dictionary also when there is no user logged in (like in the login page).
SVN:trunk[5691]
2018-04-18 13:54:24 +00:00
Denis Flaven
9c3b053727 (Enhancement for developers) Use a timestamp defined at compile time to workaround client-side caching problems during development.
SVN:trunk[5690]
2018-04-18 13:45:08 +00:00
Eric Espié
d32db977eb Fix unnecessary warning about not empty directory
SVN:trunk[5689]
2018-04-18 13:44:45 +00:00
Denis Flaven
1eca74180c Let us install using a non-secure connexion !
SVN:trunk[5688]
2018-04-18 13:01:19 +00:00
Guillaume Lajarige
0210e090f2 Advanced search: Client side handles hierarchical keys correctly.
SVN:trunk[5687]
2018-04-18 08:34:45 +00:00
Stephen Abello
baf413ee55 N°729 Form prefill : switched argument type for Designer to reference
SVN:trunk[5686]
2018-04-18 07:43:04 +00:00
Eric Espié
8e6c001bf3 Advanced Search: External keys hierarchical type
SVN:trunk[5685]
2018-04-18 07:42:30 +00:00
Guillaume Lajarige
127e940ed4 Advanced search: Fix auto-submit option ignored when removing a criteria.
SVN:trunk[5684]
2018-04-18 07:29:12 +00:00
Pierre Goiffon
aa8072118d N°1260 remove db_tls.verify_server_cert : the server cert verification is now based on the TLS CA parameter value
SVN:trunk[5683]
2018-04-18 07:26:11 +00:00
Pierre Goiffon
f07bbfa174 N°1260 MySQL TLS connection : change parameters to only enable checkbox + CA (remove client key, client cert, cappath, cipher)
SVN:trunk[5682]
2018-04-18 06:57:38 +00:00
Eric Espié
e3a2c5b05b Advanced Search: External keys default criteria are read-only and organizations are not hierarchical
SVN:trunk[5681]
2018-04-17 14:15:38 +00:00
Stephen Abello
3ba5e30a96 datamodel viewer : update compiled scss
SVN:trunk[5680]
2018-04-17 14:05:26 +00:00
Eric Espié
7bf49011a3 Advanced Search: n:n links default criteria are not read-only and organizations are hierarchical
SVN:trunk[5679]
2018-04-17 13:38:59 +00:00
Stephen Abello
bd84dd9f2c datamodel viewer : fixed related class display, displaying linkset on related class graph, open/close all items on lifecycle and visual fixes
SVN:trunk[5678]
2018-04-17 12:13:39 +00:00
Eric Espié
c3fbdc907c N°1248 - User Management: Check organization related to the current user
SVN:trunk[5677]
2018-04-17 10:22:12 +00:00
Pierre Goiffon
f7817714a8 N°1001 change constant with concatenation to attribute (to avoid crash in setup for older PHP versions)
SVN:trunk[5676]
2018-04-17 08:14:45 +00:00
Eric Espié
c485286114 Advanced Search: External keys to hierarchical class selects sub-classes as in previous version
SVN:trunk[5675]
2018-04-16 16:35:20 +00:00
Guillaume Lajarige
bd8e44f835 Advanced search: Fixes for autocomplete on external keys.
SVN:trunk[5674]
2018-04-16 15:44:39 +00:00
Guillaume Lajarige
eddf4226b7 Advanced search: Fixs for autocomplete on external keys.
SVN:trunk[5673]
2018-04-16 10:07:19 +00:00
Pierre Goiffon
804578e38d N°1370 fix ManageBrick details export
SVN:trunk[5672]
2018-04-16 07:05:34 +00:00
Bruno Da Silva
d464fe5d67 bugfix: when canceling a modification of an object, the JS displayed two alerts.
SVN:trunk[5671]
2018-04-13 16:05:42 +00:00
Pierre Goiffon
885428627f N°1370 fix Portal ManageBrick regression : can search again in table details view
SVN:trunk[5670]
2018-04-13 16:02:00 +00:00
Bruno Da Silva
4c90a90131 advanced search: bugfix
- adapt the js to IE needs (do not reduce the search bar when the user click on a select's option)

SVN:trunk[5669]
2018-04-13 15:56:08 +00:00
Eric Espié
ec2aadb7cf Advanced Search: Fix ExternalFields allowed values
SVN:trunk[5668]
2018-04-13 15:27:00 +00:00
Pierre Goiffon
9d5ab75dbd Backup/restore : apply COmbodo formatting
SVN:trunk[5667]
2018-04-13 14:49:27 +00:00
Eric Espié
d5b145e052 Advanced Search: Fix ExternalFields allowed values
SVN:trunk[5666]
2018-04-13 14:43:11 +00:00
Stephen Abello
163f5dba8a N°729 Form prefill : Minor fix for prefillSeachForm
SVN:trunk[5665]
2018-04-13 14:17:03 +00:00
Eric Espié
e026ecf92f N°1161 - Fix Dashlet Group By edition of multiple dashlets
SVN:trunk[5664]
2018-04-13 13:58:12 +00:00
Bruno Da Silva
dcda5084d0 advanced search: bugfix
- adapt the css to IE needs
- a translation key had been renamed without renaming all the usages in the code

SVN:trunk[5663]
2018-04-13 13:42:19 +00:00
Guillaume Lajarige
496441cae6 Advanced search: Search button icon switch between "refresh" and "search" depending on the auto-submit state.
SVN:trunk[5662]
2018-04-13 12:27:32 +00:00
Guillaume Lajarige
cf75937b1d Advanced search: Fix multiple undefined values bug on enum criteria.
SVN:trunk[5661]
2018-04-13 12:26:43 +00:00
Pierre Goiffon
d7fc003216 backup.php : some little PHPDoc
SVN:trunk[5660]
2018-04-13 10:09:31 +00:00
Pierre Goiffon
de54575e04 N°1260 fix DB restore regression
* add comments to explain use of the token file
* only pass current env to the ajax call (it is enough to load the corresponding config file and get everything we need !)
* DBRestore : initialize user & pwd as needed
* DBRestore : do not throw Exception anymore but only BackupException

SVN:trunk[5659]
2018-04-13 09:43:03 +00:00
Bruno Da Silva
12093c311c advanced search: bugfix
- the modal window did update the history which resulted in several border effect like having request string too long and crashing on several pages

SVN:trunk[5658]
2018-04-13 08:58:32 +00:00
Eric Espié
5b9ca03fa6 Advanced Search: Fix missing OQL for FunctionExpression
SVN:trunk[5657]
2018-04-13 08:57:57 +00:00
Bruno Da Silva
bb820ab388 advanced search: bugfix
- the modal window did update the history which resulted in several border effect like having request string too long and crashing on several pages

SVN:trunk[5656]
2018-04-13 08:57:36 +00:00
Eric Espié
c68f56ecd4 Advanced Search: Enhance Date conversion
SVN:trunk[5655]
2018-04-13 08:47:29 +00:00
Eric Espié
910bae64e9 Advanced Search: Code cleanup
SVN:trunk[5654]
2018-04-13 08:11:21 +00:00
Bruno Da Silva
40258fb02a advanced search: bugfix
- the modal window did update the history wich resulted in several border effect like having request string too long and crashing on several pages

SVN:trunk[5653]
2018-04-13 08:11:03 +00:00
Guillaume Lajarige
011ed65ea1 Advanced search: WIP auto submit.
SVN:trunk[5652]
2018-04-13 07:39:27 +00:00
Bruno Da Silva
411d934e6a advanced search: if the field has an index and the equals operator is available : force the default to the equals operator
SVN:trunk[5651]
2018-04-12 15:49:15 +00:00
Vincent Dumas
582de40960 Display the search criterion when displaying the content of a shortcut.
SVN:trunk[5650]
2018-04-12 15:40:46 +00:00
Vincent Dumas
79d7ac7c8e Typos in German dictionaries
SVN:trunk[5649]
2018-04-12 15:39:45 +00:00
Vincent Dumas
6d86bd516b Set default search criteria for objects + index on ticket's ref.
SVN:trunk[5648]
2018-04-12 15:38:18 +00:00
Bruno Da Silva
f71bf1416c advanced search: add the refresh button on objects list menu
SVN:trunk[5647]
2018-04-12 15:29:42 +00:00
Guillaume Lajarige
8a1a27ee19 Advanced search: Fix title highlighting on enum widget.
SVN:trunk[5646]
2018-04-12 15:22:46 +00:00
Guillaume Lajarige
dc30cb2e4a Advanced search: Merge due to recent sourceforge crash.
SVN:trunk[5645]
2018-04-12 14:54:11 +00:00
Pierre Goiffon
24e669c65b N°1370 Portal AggregatePageBrick : integrate dashboard brick extension
SVN:trunk[5644]
2018-04-12 14:28:41 +00:00
Pierre Goiffon
80e6ba2d96 N°1370 Portal ManageBrick : add "display_modes" XML node to set the display modes in brick tile and details views
SVN:trunk[5643]
2018-04-12 14:13:28 +00:00
Pierre Goiffon
beef4b2738 add .idea in gitignore
SVN:trunk[5642]
2018-04-12 14:12:52 +00:00
Eric Espié
56f1369000 Advanced Search: Fix Date conversion
SVN:trunk[5641]
2018-04-12 13:19:11 +00:00
Eric Espié
7bcde47081 N°1161 - Fix Dashlet Group By edition
SVN:trunk[5640]
2018-04-12 13:07:00 +00:00
Eric Espié
35663281fa Advanced Search: Fix Date conversion
SVN:trunk[5639]
2018-04-12 12:32:09 +00:00
Bruno Da Silva
0b8f75f799 advanced search - merged commit (since sourceforge has lost our commit, this is a manual merge all all losts)
SVN:trunk[5638]
2018-04-12 12:29:32 +00:00
Bruno Da Silva
7309c046ae remove .idea dir
SVN:trunk[5637]
2018-04-12 10:38:13 +00:00
Eric Espié
6dfd44b731 Advanced Search: Small bug fixes and enhancements
SVN:trunk[5636]
2018-04-12 09:51:32 +00:00
Pierre Goiffon
d6e7309c34 N°1370 portal : add charts capacity to the ManageBrick (restore 2018-04-10 revisions : r5646)
SVN:trunk[5635]
2018-04-12 08:55:16 +00:00
Pierre Goiffon
e15bad7d3b Advanced search improvements (restore 2018-04-10 revisions : r5643..r5645)
* Support for empty dates
* UNION OQLs don't crash the search
* Better support for 'not empty' searches

SVN:trunk[5634]
2018-04-12 08:54:36 +00:00
Pierre Goiffon
4450d6af2f HTMLSanitizer : add wiki ref to white lists and split declarations one per line (to ease SCM annotation) (restore 2018-04-10 revisions : r5642)
SVN:trunk[5633]
2018-04-12 08:54:21 +00:00
Pierre Goiffon
efa7a4ee55 Advanced search improvements (restore 2018-04-10 revisions : r5635..r5641)
* Add 'search_manual_submit' config parameter to manage auto-submit
* bugfixes
** date i18n is now handled (using two new options `datepicker.dateFormat` and `datepicker.timeFormat` computed from `AttributeDateTime::GetFormat()->ToDatePicker()`
** handling of `empty` `not empty` operator titles
*** it led to tohers bugfixes and a redesign of the `_computeTitle` (from overwriting to extension using ie `_computeBetweenDaysOperatorTitle`
*** some bug still remain, because autocomplete needs to been finished before checking on them
* Promote 'friendlyname' in the 'most popular' list
* bugfixes
** filters (criterions, enum and FK without autocomplete) now ignore accent on matching with user input
** this is done by using a pre-existing tool used only by the portal, so it was moved to the core (latinize.min.js)
* Integration with manual submit parameter on client side.
* bugfixes : history/breadcrumb had several c[menu] appended (one for each refresh)
* Fix various sanity bugs

SVN:trunk[5632]
2018-04-12 08:54:05 +00:00
Pierre Goiffon
757130847f Fix: disable the connection to iTopHub when running in demo mode (restore 2018-04-10 revisions : r5634)
SVN:trunk[5631]
2018-04-12 08:53:20 +00:00
Pierre Goiffon
c562098ef7 N°993: restrict the access to the REST/JSON web services to users having the profile "REST Services User" (restore 2018-04-10 revisions : r5632..r5633)
SVN:trunk[5630]
2018-04-12 08:53:02 +00:00
Pierre Goiffon
42606873af Advanced search improvements (restore 2018-04-10 revisions : r5629..r5631)
* Add support for default search criteria
* replace friendlyname by the class name for consistency
* WIP Client

SVN:trunk[5629]
2018-04-12 08:52:33 +00:00
Bruno Da Silva
df8b73999f advanced search: update history and breadcrumb on search
SVN:trunk[5628]
2018-04-09 14:25:41 +00:00
Eric Espié
234b0e6825 Advanced search: Sort Id with the other fields in "more criteria"
SVN:trunk[5627]
2018-04-09 11:51:29 +00:00
Bruno Da Silva
6ca9f8ad31 advanced search: removal of legacy_search_drawer_open
associated to this change, those wiki pages are altered : 
 - latest:admin:itop_configuration_file (`legacy_search_drawer_open` removal)
 - latest:customization:xml_reference (`search_form_open` default value changed)

SVN:trunk[5626]
2018-04-06 12:06:20 +00:00
Guillaume Lajarige
dbc0971b99 Advanced search: Widget refactoring to use _computeTitle method.
SVN:trunk[5625]
2018-04-06 10:06:03 +00:00
Eric Espié
26127c8218 N°1161 - Dashlet Group By traduction
SVN:trunk[5624]
2018-04-06 09:00:15 +00:00
Eric Espié
f4b8b4cae3 N°1161 - Dashlet Group By supports sum, average, min and max.
SVN:trunk[5623]
2018-04-06 08:53:30 +00:00
Stephen Abello
d641ff3ab7 N°729 Form prefill : XML additions for Designer purpose
SVN:trunk[5622]
2018-04-06 08:29:53 +00:00
Bruno Da Silva
a08904a936 advanced search: Tooltip on values
in case they are larger than input, it leverage the possibility to read their value rapidly

SVN:trunk[5621]
2018-04-05 15:43:40 +00:00
Guillaume Lajarige
c13158cdb5 Advanced search: Enum/ExtKey criterion now supports min_autocomplete_chars conf parameter in autocomplete.
SVN:trunk[5620]
2018-04-05 13:32:27 +00:00
Bruno Da Silva
70a8c50d47 advanced search: handle auto opening of the form + open "add criteria" if no result list.
SVN:trunk[5619]
2018-04-05 13:15:28 +00:00
Guillaume Lajarige
991c87530f Advanced search: Fixes on enum criteria.
SVN:trunk[5618]
2018-04-05 10:18:18 +00:00
Bruno Da Silva
9d5156e0e0 advanced search: bugfix on search criterion titles
SVN:trunk[5617]
2018-04-05 10:02:52 +00:00
Bruno Da Silva
ec3ac05a1f advanced search: enum title optimisation
if the title is too long, display a count of checked itemps

SVN:trunk[5616]
2018-04-05 10:01:23 +00:00
Bruno Da Silva
a20fe37e98 advanced search: bugfix on search criterion titles
SVN:trunk[5615]
2018-04-05 10:00:08 +00:00
Bruno Da Silva
ee76eaedd6 advanced search: numeric between UI (displayed using 1 line instead of 2)
SVN:trunk[5614]
2018-04-05 09:58:29 +00:00
Bruno Da Silva
b90b200cd1 advanced search: numeric between UI (displayed using 1 line instead of 2)
SVN:trunk[5613]
2018-04-05 09:42:55 +00:00
Bruno Da Silva
873af8865c advanced search: numeric between UI (displayed using 1 line instead of 2)
SVN:trunk[5612]
2018-04-05 09:35:25 +00:00
Guillaume Lajarige
906ac14fa9 Advanced search: Fix copied values through criterion on initialization.
SVN:trunk[5611]
2018-04-05 09:17:23 +00:00
Bruno Da Silva
fcffe9d188 advanced search: bugfix
FK search with negative selection was failling if the exclusion list was empty ("not in" cannot be apployed on an empty array)

SVN:trunk[5610]
2018-04-05 08:35:03 +00:00
Stephen Abello
a84748a544 N°729 Form prefill : Allow to overload new methods in order to prefill search forms, creation forms and transition forms
SVN:trunk[5609]
2018-04-05 08:17:19 +00:00
Guillaume Lajarige
320c7646f0 Advanced search: Alpha version.
SVN:trunk[5608]
2018-04-05 07:05:58 +00:00
Guillaume Lajarige
f4f3c3bd37 Portal: Update table's filter hotkeys.
SVN:trunk[5607]
2018-04-04 15:01:36 +00:00
Guillaume Lajarige
2bb6acfa22 Advanced search: UI/UX, WIP.
SVN:b1162[5606]
2018-04-04 13:32:20 +00:00
Guillaume Lajarige
da5a8b0fd1 Advanced search: UI/UX, WIP.
SVN:b1162[5605]
2018-04-04 12:54:18 +00:00
Denis Flaven
aa22956f87 Added two new glyphs (binoculars and binoculars-alt) to the Combodo font.
SVN:b1162[5604]
2018-04-04 08:36:41 +00:00
Eric Espié
8b300358e9 Advanced Search: Fix direct links search
SVN:b1162[5603]
2018-04-04 08:16:48 +00:00
Eric Espié
54c5edc5da Advanced Search: Auto-complete search on foreign keys
SVN:b1162[5600]
2018-04-04 07:02:02 +00:00
Bruno Da Silva
5f08d98f66 search widget : widget numeric bugfix for between
when a date was empty the datetime plugin added the hours as a suffix

SVN:b1162[5599]
2018-04-03 16:27:28 +00:00
Pierre Goiffon
4d45f8d012 N°1328 Fix CSV import : check if user has rights on imported class
SVN:trunk[5597]
2018-04-03 13:36:27 +00:00
Eric Espié
b1c48929e4 Advanced Search: Auto-complete search on foreign keys
SVN:b1162[5596]
2018-04-03 13:29:10 +00:00
Eric Espié
612479b632 Advanced Search: Support of regexp for strings
SVN:b1162[5595]
2018-04-03 13:16:04 +00:00
Eric Espié
013dcdf93e Advanced Search: Auto-complete search on foreign keys
SVN:b1162[5594]
2018-04-03 13:12:49 +00:00
Eric Espié
d22d3945ee Advanced Search: Auto-complete search on foreign keys + refactoring of table_id2
SVN:b1162[5593]
2018-04-03 07:37:04 +00:00
Eric Espié
d4960080ea Advanced Search: Auto-complete search on foreign keys
SVN:b1162[5592]
2018-03-30 15:23:41 +00:00
Bruno Da Silva
4bc3d0ce2d add AGPL licence to the file
SVN:b1162[5591]
2018-03-30 14:24:54 +00:00
Bruno Da Silva
e1243532ba search widget : SearchFormForeignKeys (modal with search for foreign keys)
SVN:b1162[5590]
2018-03-30 14:24:33 +00:00
Guillaume Lajarige
f41a80a309 Portal: Fix table filter trigger on "tab" key hit.
SVN:b1162[5589]
2018-03-30 13:12:02 +00:00
Eric Espié
b447418f07 Advanced Search: debug mode
SVN:b1162[5588]
2018-03-30 12:31:13 +00:00
Guillaume Lajarige
95b523c2fa Advanced search: UI/UX, WIP.
SVN:b1162[5587]
2018-03-30 12:24:55 +00:00
Eric Espié
7dadd6e410 Advanced Search: Auto-complete search on foreign keys
SVN:b1162[5586]
2018-03-30 12:07:58 +00:00
Eric Espié
8ec75b9d45 Advanced Search: Auto-complete search on foreign keys
SVN:b1162[5585]
2018-03-30 10:30:08 +00:00
Guillaume Lajarige
e4b3086429 Advanced search: UI/UX, WIP.
SVN:b1162[5584]
2018-03-30 09:50:22 +00:00
Eric Espié
c56bda2f60 Advanced Search: Support of external fields (as strings)
SVN:b1162[5583]
2018-03-30 08:44:14 +00:00
Eric Espié
56566d83fd Advanced Search: Fix PHP syntax
SVN:b1162[5582]
2018-03-30 08:02:53 +00:00
Guillaume Lajarige
0e4dc43171 Advanced search: UI/UX, form submit throttling.
SVN:b1162[5581]
2018-03-29 16:07:11 +00:00
Guillaume Lajarige
7154aa05a6 Advanced search: UI/UX, disable hierarchical search on ext. key for now.
SVN:b1162[5580]
2018-03-29 15:52:01 +00:00
Guillaume Lajarige
1e80d76383 Advanced search: UI/UX, minor dict. updates.
SVN:b1162[5579]
2018-03-29 15:50:48 +00:00
Guillaume Lajarige
0ca2e33e7c Advanced search: UI/UX, ext. key autocomplete no UI.
SVN:b1162[5578]
2018-03-29 15:50:18 +00:00
Pierre Goiffon
38b10b6c10 N°1330 Header with statistics dashlet perf improvements
Now uses one count + group by query instead of one count query per grouping value

SVN:trunk[5576]
2018-03-29 15:47:42 +00:00
Guillaume Lajarige
e9444d3055 Advanced search: UI/UX, remove [not_]empty operators on fields that can't be null.
SVN:b1162[5575]
2018-03-29 15:15:43 +00:00
Bruno Da Silva
7e884dc69f search widget : bugfix
if the selected operator is not the default one, open in "advanced" mode in order to be able to see the operator

SVN:b1162[5574]
2018-03-29 12:27:30 +00:00
Bruno Da Silva
24c7ff4cfa search widget : numeric => between has a little margin on top and bottom
SVN:b1162[5573]
2018-03-29 10:14:33 +00:00
Bruno Da Silva
456f8be6e5 search widget : numeric => between after the basic operators
SVN:b1162[5572]
2018-03-29 10:13:07 +00:00
Bruno Da Silva
dfab460478 search widget : bugfix
if the selected operator is not the default one, open in "advanced" mode in order to be able to see the operator

SVN:b1162[5571]
2018-03-29 10:12:20 +00:00
Eric Espié
04154fa40c Advanced Search: add target_class for the external keys
SVN:b1162[5570]
2018-03-29 09:21:43 +00:00
Eric Espié
6e9fab849c Advanced Search: add target_class for the external keys
SVN:b1162[5569]
2018-03-29 09:18:40 +00:00
Pierre Goiffon
06555eb03e Run query : add shortcut in submit title
SVN:trunk[5568]
2018-03-29 09:17:44 +00:00
Pierre Goiffon
6b8d1b4b76 N°1041 add shortcut in submit button title
SVN:trunk[5567]
2018-03-29 09:17:12 +00:00
Bruno Da Silva
73d9ea42f0 search widget : widget numeric => default operator is now equals
because of the id field who will be almost the only numeric field, searching by id is the most common use case

SVN:b1162[5566]
2018-03-29 09:14:28 +00:00
Eric Espié
06f648b714 Advanced Search: back to max_combo_length for the external keys
SVN:b1162[5565]
2018-03-29 08:54:03 +00:00
Eric Espié
155034092f Advanced Search: remove the conversion IN <=> NOT IN for external keys
SVN:b1162[5564]
2018-03-29 08:45:46 +00:00
Eric Espié
11af11b3be Advanced Search: add class alias in criterion
SVN:b1162[5563]
2018-03-29 08:06:16 +00:00
Bruno Da Silva
3246c36984 search widget : widget search history
SVN:b1162[5562]
2018-03-29 08:03:47 +00:00
Eric Espié
c12a5cc98b Advanced Search: Fix missing label
SVN:b1162[5561]
2018-03-29 07:12:31 +00:00
Eric Espié
18ee7b194d Advanced Search: Display of raw titles enhanced
SVN:b1162[5560]
2018-03-29 07:02:03 +00:00
Guillaume Lajarige
14c0733949 Advanced search: UI/UX WIP.
SVN:b1162[5559]
2018-03-28 19:38:08 +00:00
Eric Espié
f3a2a24ee4 Advanced Search: read-only selection criteria to add an object
SVN:b1162[5558]
2018-03-28 15:03:53 +00:00
Eric Espié
26ec1269a5 Advanced Search: read-only selection criteria to add an object
SVN:b1162[5557]
2018-03-28 14:57:54 +00:00
Eric Espié
2811eb66c5 Advanced Search: Removed external fields from the attribute list
SVN:b1162[5556]
2018-03-28 13:38:21 +00:00
Eric Espié
9b0ccb8943 Advanced Search: Unit tests and some fixes
SVN:b1162[5555]
2018-03-28 12:53:46 +00:00
Bruno Da Silva
e33bdab4e9 search widget : widget search history handling
new parameter "class_name"

SVN:b1162[5554]
2018-03-28 11:57:10 +00:00
Denis Flaven
573b5fc879 Fallback to the default language, for missing entries in the current language, in the dictionary passed client-side.
SVN:b1162[5553]
2018-03-28 11:29:18 +00:00
Eric Espié
678821d54d Advanced Search: generic title for raw filters on joined classes
SVN:b1162[5552]
2018-03-28 07:47:20 +00:00
Eric Espié
5772042dd3 Advanced Search: generic title for raw filters on joined classes
SVN:b1162[5551]
2018-03-28 07:46:47 +00:00
Bruno Da Silva
7868a38137 search widget : widget search history draft
SVN:b1162[5550]
2018-03-27 16:09:21 +00:00
Bruno Da Silva
7bccfef3bd search widget : widget search history draft
SVN:b1162[5549]
2018-03-27 16:02:58 +00:00
Bruno Da Silva
736838474a search widget : widget date/datetime => i18n
SVN:b1162[5548]
2018-03-27 13:57:33 +00:00
Eric Espié
d553fad58d Advanced Search: Fix hidden filter on direct links
SVN:b1162[5547]
2018-03-27 13:43:22 +00:00
Bruno Da Silva
9e66ef5460 search widget : widget datetime and numeric => fine tuning the UI
SVN:b1162[5546]
2018-03-27 13:19:30 +00:00
Eric Espié
9550ec6efd Advanced Search: unit tests
SVN:b1162[5545]
2018-03-27 12:33:01 +00:00
Eric Espié
bc9e1b1d94 Advanced Search: code hardening and unit tests
SVN:b1162[5544]
2018-03-27 10:14:27 +00:00
Guillaume Lajarige
7672858d6b Advanced search: UI/UX WIP, integration with endpoint.
SVN:b1162[5543]
2018-03-27 09:36:21 +00:00
Eric Espié
2a2a9ab8b7 Advanced Search: translations
SVN:b1162[5542]
2018-03-27 08:27:49 +00:00
Denis Flaven
d8354c6666 IE compatibility: polyfill implementation of Array.from().
SVN:b1162[5541]
2018-03-27 08:19:14 +00:00
Guillaume Lajarige
ba04725ee3 Advanced search: UI/UX WIP.
SVN:b1162[5540]
2018-03-27 08:18:42 +00:00
Eric Espié
7664633f18 Advanced Search: Hierarchical keys & unit tests
SVN:b1162[5539]
2018-03-27 08:13:48 +00:00
Guillaume Lajarige
edcc211988 Advanced search: UI/UX WIP.
SVN:b1162[5538]
2018-03-26 17:58:06 +00:00
Bruno Da Silva
389e8f2de6 search widget : widget datetime the "advanced" (datetime) mode and the "less" (date only) modes are now less linked over each other
if you choose a date, you loose the time. Previously, the time was keeped hiddenly.

SVN:b1162[5537]
2018-03-26 15:59:44 +00:00
Guillaume Lajarige
070ac49d1b Advanced search: UI/UX, improve "Add criteria" cinematic.
SVN:b1162[5536]
2018-03-26 15:58:03 +00:00
Bruno Da Silva
40dbb2ce17 search widget : widget numeric various modifications
- bugfix: when the value is given by the backen and is typed as an integer some strin operations failed, a switch has to be broken in several sub cases to handle this
- enhancement: the input is now typed as numeric so the browser prevent some miss-typing (like space and alpha)

SVN:b1162[5535]
2018-03-26 15:28:33 +00:00
Bruno Da Silva
cd5dd04352 search widget : widget date bugfix when enter key is used to submit
SVN:b1162[5534]
2018-03-26 15:24:22 +00:00
Bruno Da Silva
592792dd7a search widget : widget datetime : open in advanced mode by default if a time is given
SVN:b1162[5533]
2018-03-26 15:23:49 +00:00
Guillaume Lajarige
cfe892d35e Advanced search: UI/UX, moving "Add criteria" to the left and separating criterion with "and"s for a better understanding.
SVN:b1162[5532]
2018-03-26 15:23:34 +00:00
Eric Espié
e01f48303b Advanced Search: Fix labels for starts with and contains
SVN:b1162[5531]
2018-03-26 15:13:19 +00:00
Eric Espié
f0c8b348c6 Unit tests
SVN:b1162[5530]
2018-03-26 15:02:24 +00:00
Eric Espié
ac5d24a848 Advanced Search: reorder criterion by label ('raw' in front)
Fix non-string labels

SVN:b1162[5529]
2018-03-26 14:33:31 +00:00
Bruno Da Silva
e8a37ff0af search widget : widget numeric bugfix for between
SVN:b1162[5528]
2018-03-26 11:55:10 +00:00
Bruno Da Silva
a60a8c0c4f search widget : I was cleaning my keyboard ...
SVN:b1162[5527]
2018-03-26 09:12:48 +00:00
Bruno Da Silva
e78f8c803e search widget : between operator bugfixes
SVN:b1162[5526]
2018-03-26 09:10:33 +00:00
Guillaume Lajarige
6ea0ba52d1 Advanced search: UI/UX WIP.
SVN:b1162[5525]
2018-03-26 06:52:43 +00:00
Guillaume Lajarige
8b0d9670f9 Advanced search: UI/UX WIP.
SVN:b1162[5524]
2018-03-25 12:21:26 +00:00
Eric Espié
440dd90316 Advanced Search: Merge enums and external keys
SVN:b1162[5523]
2018-03-23 16:57:10 +00:00
Eric Espié
5f86a60954 Advanced Search: Undefined for enums
SVN:b1162[5518]
2018-03-23 16:32:23 +00:00
Eric Espié
50e0ea5ec5 Advanced Search: Undefined for enums and unit tests
SVN:b1162[5517]
2018-03-23 16:22:10 +00:00
Eric Espié
b566bead31 Advanced Search: Undefined for enums and unit tests
SVN:b1162[5516]
2018-03-23 16:05:37 +00:00
Guillaume Lajarige
52731d7b0a Advanced search: Integration with endpoint.
SVN:b1162[5515]
2018-03-23 15:39:34 +00:00
Eric Espié
465532014b Advanced Search: Undefined and Id first
SVN:b1162[5514]
2018-03-23 15:02:23 +00:00
Bruno Da Silva
7153ae9614 search widget : date and datetime widget
remove = operator

SVN:b1162[5513]
2018-03-23 14:58:37 +00:00
Bruno Da Silva
0feb0fe972 search widget : date and datetime widget
SVN:b1162[5512]
2018-03-23 14:56:16 +00:00
Bruno Da Silva
b3cdbfc71b search widget : date and datetime widget
SVN:b1162[5511]
2018-03-23 14:44:13 +00:00
Guillaume Lajarige
3a32bd62ef Advanced search: More criteria UX WIP.
SVN:b1162[5510]
2018-03-23 14:23:32 +00:00
Eric Espié
c1adf880a4 Advanced Search: Dates between
SVN:b1162[5509]
2018-03-23 14:03:58 +00:00
Eric Espié
b0332b6ef5 Advanced Search: Dates between
SVN:b1162[5508]
2018-03-23 13:55:44 +00:00
Eric Espié
965e7b48df Advanced Search: Dates between
SVN:b1162[5507]
2018-03-23 13:33:09 +00:00
Bruno Da Silva
27f41baa9a search widget : date and datetime widget
SVN:b1162[5506]
2018-03-23 10:44:04 +00:00
Eric Espié
43615450ad Advanced Search: Dates between
SVN:b1162[5505]
2018-03-23 10:41:37 +00:00
Bruno Da Silva
956b8958fb search widget : date and datetime widget
SVN:b1162[5504]
2018-03-23 09:53:49 +00:00
Eric Espié
024459408a Advanced Search: open/closed search form
SVN:b1162[5503]
2018-03-23 09:41:49 +00:00
Eric Espié
78ccc44014 Advanced Search: open/closed search form
SVN:b1162[5502]
2018-03-23 09:40:41 +00:00
Eric Espié
85397c4e28 Advanced Search: Dates between
SVN:b1162[5501]
2018-03-23 09:34:21 +00:00
Eric Espié
0253f7d069 Advanced Search: Dates between
SVN:b1162[5500]
2018-03-23 09:28:47 +00:00
Eric Espié
ddcb709fd1 Advanced Search: Dates between
SVN:b1162[5499]
2018-03-23 09:21:44 +00:00
Eric Espié
a7d11c6670 Advanced Search: Dates between
SVN:b1162[5498]
2018-03-23 09:00:57 +00:00
Guillaume Lajarige
bbb4959f22 Advanced search: UX on enum widget.
SVN:b1162[5497]
2018-03-22 18:15:56 +00:00
Guillaume Lajarige
254b3fe9aa Advanced search: UX on enum widget.
SVN:b1162[5496]
2018-03-22 17:56:19 +00:00
Eric Espié
35c016482b Advanced Search: Support of undefined values for enum and external keys
SVN:b1162[5495]
2018-03-22 17:36:29 +00:00
Eric Espié
62895eedb7 Advanced Search: Add Id in search forms
SVN:b1162[5494]
2018-03-22 16:59:42 +00:00
Guillaume Lajarige
32809ae7d4 Advanced search: WIP POC, UI/UX.
SVN:b1162[5493]
2018-03-22 16:52:35 +00:00
Eric Espié
73e1e3422d Advanced Search: Numeric fields and dates
SVN:b1162[5492]
2018-03-22 16:28:54 +00:00
Guillaume Lajarige
2d9041c045 Advanced search: WIP POC, UI/UX.
SVN:b1162[5491]
2018-03-22 08:07:50 +00:00
Bruno Da Silva
60d6bb79b3 search widget : date widget UI tests
SVN:b1162[5490]
2018-03-21 16:38:30 +00:00
Guillaume Lajarige
6afb3a06ac Advanced search: WIP POC, UI/UX.
SVN:b1162[5489]
2018-03-21 15:34:00 +00:00
Eric Espié
3cdf22e9b2 Advanced Search: resolve variables for the search screen
SVN:b1162[5488]
2018-03-21 13:45:37 +00:00
Eric Espié
b05b41c7cc Advanced Search: 'between' for numeric criteria
SVN:b1162[5487]
2018-03-21 13:12:13 +00:00
Guillaume Lajarige
114a340527 Advanced search: WIP POC, UI/UX.
SVN:b1162[5486]
2018-03-21 13:10:48 +00:00
Bruno Da Silva
cfa5163590 search widget : todo added
SVN:b1162[5485]
2018-03-21 12:37:59 +00:00
Bruno Da Silva
53535dd82d search widget : console.debug removal (woops)
SVN:b1162[5484]
2018-03-21 10:02:52 +00:00
Bruno Da Silva
34f17074ca search widget : numeric widget
SVN:b1162[5483]
2018-03-21 09:51:36 +00:00
Bruno Da Silva
157d404019 search widget : reload interval moved from oDisplayBlock->Display() to oDisplayBlock->Render()
SVN:b1162[5482]
2018-03-21 08:31:56 +00:00
Bruno Da Silva
d1ef987dca search widget : numeric widget between operator
SVN:b1162[5481]
2018-03-20 16:10:53 +00:00
Eric Espié
fd8c7c99bd Advanced Search: IN with all values => 'true'
SVN:b1162[5480]
2018-03-20 15:35:01 +00:00
Guillaume Lajarige
4295437b3e Advanced search: WIP POC, UI/UX.
SVN:b1162[5479]
2018-03-20 15:34:27 +00:00
Guillaume Lajarige
92a08a1865 Advanced search: WIP POC, UI/UX.
SVN:b1162[5478]
2018-03-20 15:12:36 +00:00
Eric Espié
fbd7abf4e2 Advanced Search: Fix 'undefined index error' in 'empty' operator
SVN:b1162[5477]
2018-03-20 15:07:19 +00:00
Eric Espié
306ec09118 Advanced Search: Support '=', '!=', 'IN' and 'NOT IN' for enums and external keys (with empty/not empty and IN)
SVN:b1162[5476]
2018-03-20 15:04:33 +00:00
Eric Espié
a5e41b224f Advanced Search: Support '=' for external keys
SVN:b1162[5475]
2018-03-20 14:44:43 +00:00
Eric Espié
4abcf75b34 Advanced Search: Revert Sort on allowed values (done by JavaScript)
SVN:b1162[5474]
2018-03-20 14:36:52 +00:00
Eric Espié
7131a505be Advanced Search: Sort allowed values
SVN:b1162[5473]
2018-03-20 14:28:40 +00:00
Eric Espié
9b42af0149 Advanced Search: Sort allowed values
SVN:b1162[5472]
2018-03-20 14:20:07 +00:00
Guillaume Lajarige
27b9748f86 Advanced search: WIP POC, UI/UX.
SVN:b1162[5471]
2018-03-20 14:17:08 +00:00
Eric Espié
1301aa5c35 Advanced Search: Fix shortcut menu with sub-classes
SVN:b1162[5470]
2018-03-20 14:12:16 +00:00
Bruno Da Silva
1b80789288 search widget : numeric widget
SVN:b1162[5469]
2018-03-20 13:58:33 +00:00
Guillaume Lajarige
ca0232ae7b Advanced search: WIP POC, UI/UX.
SVN:b1162[5468]
2018-03-20 13:44:10 +00:00
Bruno Da Silva
2fb0ecc446 search widget : default width for operator name
SVN:b1162[5467]
2018-03-20 13:03:44 +00:00
Bruno Da Silva
0c41db76e2 search widget : numeric widget
SVN:b1162[5466]
2018-03-20 13:02:51 +00:00
Eric Espié
e120b149dc Advanced Search: Fix shortcut menu with sub-classes
SVN:b1162[5465]
2018-03-20 12:50:30 +00:00
Eric Espié
e33596960a Advanced Search: Better support of dates in expressions
SVN:b1162[5464]
2018-03-20 10:38:52 +00:00
Bruno Da Silva
d04fb645ec search widget : delete the "oql" parameter once the widget is modified
SVN:b1162[5463]
2018-03-20 10:04:33 +00:00
Guillaume Lajarige
87c5ee67c0 Advanced search: I would like to dedicate this commit to my beloved colleague, eespie <3
SVN:b1162[5462]
2018-03-20 09:27:42 +00:00
Guillaume Lajarige
a53a046351 Advanced search: WIP POC, UI/UX.
SVN:b1162[5461]
2018-03-20 08:19:33 +00:00
Eric Espié
afda182b4e Advanced Search: typo
SVN:b1162[5460]
2018-03-19 15:51:42 +00:00
Eric Espié
d883e3e661 Advanced Search: Dictionary compatible with the setup
SVN:b1162[5459]
2018-03-19 15:44:23 +00:00
Eric Espié
c9526130b7 Advanced Search: Cleaner Dictionary entries
SVN:b1162[5458]
2018-03-19 14:32:43 +00:00
Eric Espié
d6e3c7d1b7 Advanced Search: more info on fields and criterion
SVN:b1162[5457]
2018-03-19 14:24:41 +00:00
Eric Espié
0fdf6bfbb2 Advanced Search: Hidden criterion
SVN:b1162[5456]
2018-03-19 10:45:34 +00:00
Eric Espié
e628c68f09 Advanced Search: Search on Details pages
SVN:b1162[5455]
2018-03-19 09:58:46 +00:00
Eric Espié
8f858c2ddf Advanced Search: Labels on raw expressions
SVN:b1162[5454]
2018-03-19 09:57:31 +00:00
Denis Flaven
f8f6e201b9 Advanced Search WIP: new mechanism for passing the dictionary to the client side. Hopefully faster than before thanks to the browser's cache.
SVN:b1162[5453]
2018-03-16 17:44:55 +00:00
Guillaume Lajarige
52f56e1bb0 Advanced search: WIP POC, UI/UX.
SVN:b1162[5452]
2018-03-16 15:12:25 +00:00
Eric Espié
187f7e591e Advanced Search: Links n:n
SVN:b1162[5451]
2018-03-16 14:35:25 +00:00
Eric Espié
272e8eac4f Advanced Search: Links n:1
SVN:b1162[5450]
2018-03-16 14:21:40 +00:00
Eric Espié
d423d741b2 Advanced Search: Links n:n
SVN:b1162[5449]
2018-03-16 13:21:11 +00:00
Eric Espié
102b2d76f4 Advanced Search: Links n:n
SVN:b1162[5448]
2018-03-16 13:13:54 +00:00
Eric Espié
bb31cedcba Advanced Search: Links n:n
SVN:b1162[5447]
2018-03-16 11:24:58 +00:00
Eric Espié
bf02e04ae5 Advanced Search: Links n:n
SVN:b1162[5446]
2018-03-16 10:59:33 +00:00
Pierre Goiffon
c66884be0a N°1001 setup : log all modifications done on the DB in a SQL file (/log/setup-queries-YYYY-MM-DD_HH-mm.sql)
SVN:trunk[5445]
2018-03-16 10:00:04 +00:00
Pierre Goiffon
e7b94d3132 N°1001 setup : database/tables/columns charset and collation conversion
* check DB charset/collation and do conversion if needed
* same for existing tables
* add both info in fields signatures, so that conversions will be trigerred if needed

SVN:trunk[5444]
2018-03-16 09:59:25 +00:00
Pierre Goiffon
b219161011 N°1001 switch DB charset from utf8 to utf8mb4 to allow characters outside of the BMP
* use centralized constants instead of literal values in code
* remove config parameters 'db_character_set' and 'db_collation'
* always fix charset when creating/altering column
* backup : use utf8mb4 only for mysqldump >= 5.5.33 (was introduced in 5.5.3 but only available in 5.5.33 for programs)

SVN:trunk[5443]
2018-03-16 09:59:16 +00:00
Pierre Goiffon
fd7d30333f N°1001 setup add check for new MySQL requirement innodb_large_prefix
if disabled indexes will be limited to 767 bytes, that means 191 car in the new iTop charset utf8mb4 although the varchar iTop use are 255 car long. So we NEED this parameter to be set to true (its default value is true only since MySQL 5.7.7, see https://dev.mysql.com/doc/refman/5.7/en/innodb-parameters.html#sysvar_innodb_large_prefix)

SVN:trunk[5442]
2018-03-16 09:58:44 +00:00
Guillaume Lajarige
d734cdaf48 Advanced search: WIP POC, UI/UX.
SVN:b1162[5441]
2018-03-16 09:44:34 +00:00
Guillaume Lajarige
f60d0b10e0 Advanced search: WIP POC, UI/UX.
SVN:b1162[5440]
2018-03-16 08:59:29 +00:00
Guillaume Lajarige
a1c6e32e28 Advanced search: WIP POC, UI/UX.
SVN:b1162[5439]
2018-03-16 08:08:24 +00:00
Eric Espié
156cb03069 Advanced Search: Links n:n
SVN:b1162[5438]
2018-03-15 17:34:17 +00:00
Denis Flaven
cdb75729cb Enhancement: make the deletion of a Synchro Data Source a bit more resistant, in case of a missing or already deleted data table.
SVN:trunk[5437]
2018-03-15 16:49:58 +00:00
Guillaume Lajarige
d1a812f04c Advanced search: WIP POC, UI/UX.
SVN:b1162[5436]
2018-03-15 14:38:10 +00:00
Bruno Da Silva
b190ba1268 search widget
temps traces

SVN:b1162[5435]
2018-03-15 14:01:04 +00:00
Guillaume Lajarige
87ed90a825 Advanced search: WIP POC, UI/UX.
SVN:b1162[5434]
2018-03-15 13:58:42 +00:00
Eric Espié
a03a4af1e6 Advanced Search: warnings and default div removed
SVN:b1162[5433]
2018-03-15 13:48:38 +00:00
Eric Espié
e48e4e7139 Advanced Search: Dates between
SVN:b1162[5432]
2018-03-15 13:35:35 +00:00
Eric Espié
6ef31b7983 Fix code typos
SVN:b1162[5431]
2018-03-15 13:33:16 +00:00
Guillaume Lajarige
d378658a62 Advanced search: WIP POC, UI/UX.
SVN:b1162[5430]
2018-03-15 08:36:45 +00:00
Bruno Da Silva
ed02758940 search widget
- displayBlock "list" aExtraParams exposition in js

SVN:b1162[5429]
2018-03-14 16:35:35 +00:00
Denis Flaven
b28c45c84c N°1354: use only hashed server side information as the local storage identifier.
SVN:trunk[5428]
2018-03-14 16:25:00 +00:00
Eric Espié
42af530c63 Advanced Search: widget types
SVN:b1162[5427]
2018-03-14 16:06:34 +00:00
Eric Espié
7c3de1e976 Advanced Search: widget types
SVN:b1162[5426]
2018-03-14 15:46:30 +00:00
Guillaume Lajarige
afdd43c5e3 Advanced search: WIP POC, UI/UX.
SVN:b1162[5425]
2018-03-14 13:00:08 +00:00
Bruno Da Silva
5bc756716e search widget
- ajax endpoint parameter reading refactoring
- displayBlock "list" aExtraParams exposition in js

SVN:b1162[5424]
2018-03-14 11:14:45 +00:00
Guillaume Lajarige
6a6c069896 Advanced search: WIP POC, integration with endpoint.
SVN:b1162[5423]
2018-03-14 11:03:32 +00:00
Eric Espié
9499799f80 Advanced Search: IN/NOT IN
SVN:b1162[5422]
2018-03-14 08:50:54 +00:00
Guillaume Lajarige
5632f9786c Advanced search: WIP POC, UI/UX.
SVN:b1162[5421]
2018-03-14 08:33:17 +00:00
Eric Espié
6f79e07e90 Advanced Search: NOT IN
SVN:b1162[5420]
2018-03-13 16:16:33 +00:00
Guillaume Lajarige
601f18bbab Advanced search: WIP POC, integration with endpoint.
SVN:b1162[5419]
2018-03-13 16:10:17 +00:00
Eric Espié
6f750cf584 Advanced Search: Unit tests
SVN:b1162[5418]
2018-03-13 16:06:15 +00:00
Eric Espié
3b7c92d022 Advanced Search: Field List
SVN:b1162[5417]
2018-03-13 16:04:11 +00:00
Eric Espié
af12b47c90 Advanced Search: Field List
SVN:b1162[5416]
2018-03-13 13:50:04 +00:00
Bruno Da Silva
2d9140e56c Search form
Result list now expose their extra params using jQuery().data() function

SVN:b1162[5415]
2018-03-13 13:03:14 +00:00
Bruno Da Silva
0351ff30b4 Search form
Result list now expose their extra params using jQuery().data() function

SVN:b1162[5414]
2018-03-13 13:00:14 +00:00
Eric Espié
6d13dac2c3 Advanced Search: Smart conversion
SVN:b1162[5413]
2018-03-13 11:15:29 +00:00
Guillaume Lajarige
e2174b9ad4 Advanced search: WIP POC, integration with endpoint.
SVN:b1162[5412]
2018-03-13 10:47:54 +00:00
Eric Espié
2038785b09 SVN:b1162[5411] 2018-03-13 10:27:08 +00:00
Bruno Da Silva
0c8650d2e5 Search form
jquery expect html responses to begin with a <

SVN:b1162[5410]
2018-03-13 10:22:48 +00:00
Eric Espié
3e7edea7be SVN:b1162[5409] 2018-03-13 09:56:34 +00:00
Eric Espié
b3d625b9fc Advanced Search
SVN:b1162[5408]
2018-03-13 08:11:01 +00:00
Eric Espié
d02fb69ca7 Advanced Search
SVN:b1162[5407]
2018-03-09 17:07:15 +00:00
Guillaume Lajarige
8cf4bc58a7 Advanced search: WIP POC, better criteria widget instanciation.
SVN:b1162[5406]
2018-03-09 16:38:30 +00:00
Guillaume Lajarige
b8aed0f004 Advanced search: WIP POC, integration with endpoint, add "list_params" parameter.
SVN:b1162[5405]
2018-03-09 16:28:46 +00:00
Guillaume Lajarige
03a6473bd4 Update portal portugues (brazilian) translations thanks to Pedro Beck!
SVN:trunk[5404]
2018-03-09 13:51:14 +00:00
Eric Espié
7d95c02b57 Advanced Search
SVN:b1162[5403]
2018-03-09 13:42:19 +00:00
Guillaume Lajarige
767507d195 Advanced search: WIP POC, integration with endpoint.
SVN:b1162[5402]
2018-03-09 13:34:04 +00:00
Guillaume Lajarige
1d96cbeb07 Advanced search: WIP POC, client widgets.
SVN:b1162[5401]
2018-03-09 13:18:56 +00:00
Guillaume Lajarige
0bf33ec7e9 Advanced search: WIP POC, integration with endpoint.
SVN:b1162[5400]
2018-03-09 11:10:03 +00:00
Eric Espié
37196b42ed Advanced Search
SVN:b1162[5399]
2018-03-09 09:36:58 +00:00
Eric Espié
5f7453d031 Advanced Search
SVN:b1162[5398]
2018-03-09 09:23:36 +00:00
Eric Espié
88b7ef5345 Advanced Search
Conversion to search form

SVN:b1162[5397]
2018-03-09 09:16:00 +00:00
Eric Espié
213d591eb0 Advanced Search
SVN:b1162[5396]
2018-03-09 08:43:28 +00:00
Eric Espié
c04f73e86b Advanced Search
Convert from raw OQL to search form widget operator

SVN:b1162[5395]
2018-03-08 17:01:17 +00:00
Guillaume Lajarige
2033c171f0 Advanced search: Integration with endpoint POC & WIP.
SVN:b1162[5394]
2018-03-08 16:50:10 +00:00
Eric Espié
8ce708dade Advanced Search
generate id on div "result list outer" and use this id on search widget initialisation

SVN:b1162[5393]
2018-03-08 14:53:57 +00:00
Eric Espié
fa60322ff1 Advanced Search
SVN:b1162[5392]
2018-03-08 13:49:00 +00:00
Eric Espié
e9bcd170c0 Advanced Search
SVN:b1162[5391]
2018-03-07 17:07:40 +00:00
Guillaume Lajarige
118b5c8a7d Advanced search: Initializing javascript widgets.
SVN:b1162[5390]
2018-03-07 16:43:20 +00:00
Guillaume Lajarige
b5bcfa8d90 Advanced search: WIP...
SVN:b1162[5389]
2018-03-07 16:21:44 +00:00
Eric Espié
e496ab06b2 Advanced Search
SVN:b1162[5388]
2018-03-07 16:10:09 +00:00
Vincent Dumas
d7c960e150 Enabling search and access control by organization on User class. Reworking fields displayed in Details and List as well.
SVN:trunk[5387]
2018-03-07 14:00:10 +00:00
Eric Espié
9de7b4ba35 Advanced Search
SVN:b1162[5386]
2018-03-06 16:18:12 +00:00
Guillaume Lajarige
bb1a18f187 SVN:b1162[5385] 2018-03-06 14:47:09 +00:00
Guillaume Lajarige
68cdd6b8a9 N°1325 Dashboards: Unknown dashlets (eg. from an uninstalled extension) no longer raise an exception, a fallback is displayed and the XML configuration is still available in editor.
SVN:trunk[5384]
2018-03-06 14:07:33 +00:00
Guillaume Lajarige
34dab0c498 Update licences copyright
SVN:trunk[5383]
2018-03-06 14:06:19 +00:00
Pierre Goiffon
f9511aba17 N°1030 Collapsible Sections :
* stop event propagation (was causing tab switching in notifications)
* save section state in localStorage

SVN:trunk[5382]
2018-03-05 15:50:38 +00:00
Pierre Goiffon
d96015f2c1 N°1260 new db_tls.verify_server_cert option to force server certificates check
SVN:trunk[5381]
2018-03-05 15:50:18 +00:00
Eric Espié
e66d577f21 N°478 - Customizable access to the 'Admin Tools'
SVN:trunk[5380]
2018-03-05 08:09:10 +00:00
Pierre Goiffon
47653eeba7 N°1260 PHPUnit for the Mysql CLI TLS options generation
SVN:trunk[5379]
2018-02-28 16:47:00 +00:00
Pierre Goiffon
a0463c85a1 N°1260 MySQL TLS connection : use less rectrictive flag (no server cert check)
SVN:trunk[5376]
2018-02-28 15:13:11 +00:00
Pierre Goiffon
519093dceb N°1260 fix backup classes to correctly uses DB parameters including TLS
* backup : add missing PHPDoc
* backup : use a config object instead of each parameter attribute
* CMDBSource::InitServerAndPort : remove static attribute dependency, change visibility
* setup : generate a config instance to use in backup
* backup : add TLS params if needed to the mysqldump call

SVN:trunk[5375]
2018-02-28 15:12:57 +00:00
Pierre Goiffon
08c5d0e4c1 N°1342 cron : fix iScheduledProcess implementations that were rescheduled on every cron start and so never processed :( (was introduced in r5371)
SVN:trunk[5374]
2018-02-27 16:38:38 +00:00
Eric Espié
cae4526b3b Performance enhancement. Avoid multiple count requests.
SVN:trunk[5373]
2018-02-27 15:54:30 +00:00
Pierre Goiffon
79381d7fd2 N°1342 cron : previous commit was to handle BackgroundTask pointing to non existing class (can happen after an extension removal)
add comment reflecting the class_exists() test purpose

SVN:trunk[5372]
2018-02-27 15:49:03 +00:00
Pierre Goiffon
d8c141b1c9 N°1342 cron task validity checks :
* checks are now made one by one
* new class_exists() test

SVN:trunk[5371]
2018-02-27 15:20:55 +00:00
Pierre Goiffon
3b3f4044cb N°1260 Mutex : fix merge error in mutex name init
SVN:trunk[5369]
2018-02-26 15:16:33 +00:00
Pierre Goiffon
c0256428f9 setup : keep code compatibility with old PHP version
Whatever are the iTop requirements, we will be able to show warnings/errors on the setup first screen

SVN:trunk[5368]
2018-02-26 14:27:47 +00:00
Eric Espié
85a5ddb980 N°478 - Customizable access to the 'Admin Tools'
- Display additional rights (grant_by_profile) in the grant matrix

SVN:trunk[5367]
2018-02-26 10:38:09 +00:00
Stephen Abello
06bc58f383 datamodel viewer : display children in search tree, search configured to "contains", viewed class is now added to the search input by default and more information about attribute null values/default values
SVN:trunk[5366]
2018-02-23 15:37:00 +00:00
Pierre Goiffon
b739c00414 N°1260 wrong function name called to check TLS connection
SVN:trunk[5365]
2018-02-23 14:19:32 +00:00
Eric Espié
d65bd97956 N°478 - Customizable access to the 'Admin Tools'
SVN:trunk[5364]
2018-02-23 11:13:07 +00:00
Pierre Goiffon
b952f9da4a N°942 allow to have no new PHP/MySQL requirements for next release
SVN:trunk[5363]
2018-02-22 14:28:52 +00:00
Stephen Abello
388b3257fc jQuery modernization : visual fix for the top left pin
SVN:trunk[5362]
2018-02-22 12:53:06 +00:00
Stephen Abello
6318077278 jQuery modernization : removed unused minified jquery-ui css & unused non-minified jquery-migrate 1.2.1 library
SVN:trunk[5361]
2018-02-22 10:14:26 +00:00
Stephen Abello
9fee51bafb jQuery modernization : included console's jquery/jquery-ui files in portal instead of its own files
SVN:trunk[5360]
2018-02-22 09:44:42 +00:00
Stephen Abello
397ec9587b jQuery modernization : updated jquery to 1.12.4, jquery-ui to 1.11.4 and jquery-migrate to 1.4.1
SVN:trunk[5359]
2018-02-22 09:28:08 +00:00
Stephen Abello
862d08f57d jQuery modernization : removed and replaced calls to deprecated methods in jquery 1.12.4
SVN:trunk[5358]
2018-02-22 09:24:42 +00:00
Stephen Abello
ebb541e4f5 jQuery modernization : updated libraries to a version compatible with jquery 1.12.4
SVN:trunk[5357]
2018-02-22 09:21:05 +00:00
Stephen Abello
e05d780bec jQuery modernization : removed unused javascript libraries and jquery-ui stylesheets
SVN:trunk[5356]
2018-02-22 09:18:42 +00:00
Guillaume Lajarige
84b383154d Update spanish translations (thanks to Miguel Turrubiates!)
SVN:trunk[5353]
2018-02-21 16:39:44 +00:00
Guillaume Lajarige
f458826643 Internal: Rename core english dictionary files to match standard convention.
SVN:trunk[5352]
2018-02-21 16:36:08 +00:00
Pierre Goiffon
5d808992e6 N°942 use expression in SetupUtils constant as this is allowed since PHP 5.6.0 and it is the new required version for iTop 2.5 (see http://php.net/manual/en/language.oop5.constants.php)
SVN:trunk[5351]
2018-02-21 16:35:19 +00:00
Eric Espié
03f9a9fcac N°1161 - Add functions, order by and limits to DBSearch::MakeGroupByQuery()
SVN:trunk[5350]
2018-02-16 12:59:35 +00:00
Eric Espié
7ea9b5b2f3 Unit tests with debug()
SVN:trunk[5349]
2018-02-16 08:16:36 +00:00
Eric Espié
b8fc24f093 Unit tests with debug()
SVN:trunk[5348]
2018-02-16 08:14:29 +00:00
Denis Flaven
bddba15403 Cleanup target build directory before building into it...
SVN:trunk[5345]
2018-02-13 11:01:11 +00:00
Eric Espié
894f1c4f28 Magic trick for windows. Sometimes the folder is empty but rmdir fails
SVN:trunk[5344]
2018-02-13 10:59:56 +00:00
Eric Espié
19665d4ad9 Computations are not allowed in defining constants
SVN:trunk[5343]
2018-02-12 16:15:46 +00:00
Denis Flaven
18a8e86b2a Bug fixes:
- support an upgrade of a givne component (same directory in data/production-modules)
- deployment no longer blocked after a failed attempt (cleanup of the data/production-build-modules directory)
- load of the "structural data" of newly added extensions

Enhancements:
- All traces go to log/setup.log, and  traces have been added to clearly identify the different phases of the deployment.

SVN:trunk[5341]
2018-02-12 12:31:20 +00:00
Guillaume Lajarige
3af724a941 Fix application being wrongly set to Archive Mode when it fails to retrieve an object from the database.
SVN:trunk[5340]
2018-02-12 12:28:10 +00:00
Eric Espié
5b378ee9dd N°1322 - Display of links now support both DBObjectSet and ormLinkSet
SVN:trunk[5339]
2018-02-09 15:32:15 +00:00
Denis Flaven
d5889a90d4 The Hub is alive ! Let's use the production URL.
SVN:trunk[5337]
2018-02-09 14:13:46 +00:00
Denis Flaven
81c8eb2830 N°1323: Bug fix for a crash with the error message: class 'cmdbAbstractObject' not found, in the last screen of the setup under very specific circumstances.
SVN:trunk[5336]
2018-02-09 14:04:52 +00:00
Denis Flaven
507a073203 N°1323: Bug fix for a crash with the error message: class 'cmdbAbstractObject' not found, in the last screen of the setup under very specific circumstances.
SVN:trunk[5333]
2018-02-09 13:44:48 +00:00
Denis Flaven
abe67d9e4e Added an extra safety check to detect inconsistencies between the added extensions and the choices made during the initial installation.
SVN:trunk[5318]
2018-02-09 08:43:42 +00:00
Vincent Dumas
741f44e8b7 dictionnary error 'criticity' replaced by 'criticality'
SVN:trunk[5317]
2018-02-08 15:57:57 +00:00
Pierre Goiffon
c715b9488a N°1260 MySQL connection : allow to use p: host prefix (persistent connection, see http://php.net/manual/en/mysqli.persistconns.php)
SVN:trunk[5316]
2018-02-08 14:22:27 +00:00
Pierre Goiffon
5107ef5119 N°1260 MySQL TLS connection : finalize setup warning message
SVN:trunk[5315]
2018-02-08 14:22:20 +00:00
Pierre Goiffon
ca28eeb596 N°1260 rename db_ssl* vars to db_tls (cause SSL is an old protocol and MySQL uses TLS)
Keep options label with SSL, to keep them aligned with the labels used in MySQL products and documentation

SVN:trunk[5314]
2018-02-08 14:22:14 +00:00
Pierre Goiffon
f51eb96c69 N°1260 MySQL TLS connection : do not use persistent connection in Mutex
SVN:trunk[5313]
2018-02-08 14:22:05 +00:00
Pierre Goiffon
b032299b05 N°1260 MySQL TLS connection : exception if the opened connection is not in TLS whereas TLS parameters were used to open it
SVN:trunk[5312]
2018-02-08 14:21:58 +00:00
Pierre Goiffon
5a2576bc29 N°1260 MySQL TLS connection : add options in setup
SVN:trunk[5311]
2018-02-08 14:21:51 +00:00
Pierre Goiffon
3375629d06 N°1260 MySQL TLS connection : add capath config for mysqli::ssl_set argument
SVN:trunk[5310]
2018-02-08 14:21:40 +00:00
Pierre Goiffon
37232bc222 N°1260 every classes creating a mysqli instance now use a dedicated method in CMDBSource
SVN:trunk[5309]
2018-02-08 14:21:33 +00:00
Pierre Goiffon
d2f0deec9c N°1260 Config : migrate DB* variables to the Get() model, create CMDBSource::InitFromConfig
SVN:trunk[5308]
2018-02-08 14:21:25 +00:00
Pierre Goiffon
5a25e44177 N°1260 MySQL TLS patch improvements :
* mysql connexion opening : simplify code
* rename DB_SSL_* variables to DB_SSL.*
* fix warnings when new param are not set
* persistent connection (host "p:" prefix) is used for every TLS connection
* add some missing @var

SVN:trunk[5307]
2018-02-08 14:21:06 +00:00
Pierre Goiffon
08d9d58894 N°1260 MySQL TLS connection : apply Hardis patch (many thanks !)
SVN:trunk[5306]
2018-02-08 14:20:58 +00:00
Guillaume Lajarige
0254a75c95 N°1280 Upgrade Silex library to 2.2 (Which is possible as iTop 2.5 requirements are now PHP 5.6+!)
SVN:trunk[5305]
2018-01-31 13:37:51 +00:00
Guillaume Lajarige
a7cfcefee2 Internal: PHPDoc update
SVN:trunk[5304]
2018-01-31 12:35:01 +00:00
Guillaume Lajarige
f78c057b45 Portal: Fix user profile edition due to recent user rights changes.
SVN:trunk[5303]
2018-01-31 12:31:45 +00:00
Guillaume Lajarige
4bd3084403 Fix regression introduced in r5298: Portal user could not change its preferences.
Removed the 'grant_by_profile' category check in UserRights::GetSelectFilter().

SVN:trunk[5302]
2018-01-31 12:29:20 +00:00
Pierre Goiffon
9d817f0c77 N°942 new requirements for iTop 2.5
SVN:trunk[5301]
2018-01-31 10:44:17 +00:00
Pierre Goiffon
68b8cc1d20 MetaModel : reduce code warnings and improve type hinting
SVN:trunk[5300]
2018-01-31 10:31:28 +00:00
Pierre Goiffon
fb8b0f4f65 PHPDoc for methods called by MetaModel
SVN:trunk[5299]
2018-01-31 10:31:23 +00:00
Eric Espié
94d45fc77f N°1248 - User Management Portal
* Added a new grant_by_profile category that allows to manage certain classes in addition to bizmodel with user profiles.
* The following classes have the new grant_by_profile category:
    User, UserInternal, UserLocal, UserLDAP, UserExternal, URP_UserProfile, URP_UserOrg
* For these classes, it is possible to manage access rights with user profiles for non-administrators.
* For these classes, the default behavior of SELECT requests changes from allowed to forbidden.
* For user profiles, the default behavior '*' is limited to the bizmodel category to keep the previous behavior of profiles, i. e. for classes in the grant_by_profile category, rights (including READ) must be given explicitly.
* New constraints have been added, so only an administrator can manage (attach or detach) the 'Administrator' profile.

SVN:trunk[5298]
2018-01-30 15:17:51 +00:00
Eric Espié
5144f62da9 UserRights Unit tests
SVN:trunk[5297]
2018-01-26 08:06:41 +00:00
Romain Quetiez
a58ba7fcc5 N°1287 Update the installation instructions (pointing to the wiki page), and fix the readme to point to the correct wiki pages
SVN:trunk[5295]
2018-01-25 11:05:12 +00:00
Romain Quetiez
17bec06c98 Cleanup - remove this index page not used anymore (and having broken links)
SVN:trunk[5294]
2018-01-25 10:50:50 +00:00
Guillaume Lajarige
d531ec846f Portal: CSS Fixes (lack of consistency with border-radius)
SVN:trunk[5293]
2018-01-24 14:21:36 +00:00
Guillaume Lajarige
07849922b8 Code cleanup
SVN:trunk[5292]
2018-01-23 14:53:14 +00:00
Denis Flaven
63ba267da0 Bug fixes:
- properly detect missing dependencies when deploying extensions from the Hub (and not only when deploying a 2nd time an extension, cf bug n°1284).
- setup hangs when upgrading to 2.4.1 with some "old" extensions in the "extensions" folder.

SVN:trunk[5290]
2018-01-23 10:37:50 +00:00
Pierre Goiffon
93526c8a44 N°942 PHP version not yet validated was incorrectly set to 7.1.9, fix it back to 7.2.0
SVN:trunk[5288]
2018-01-18 11:11:53 +00:00
Denis Flaven
c7c2f4a482 Bug fix: do not (try to) launch the backup if the backup detection told us that the backup is not possible!
SVN:trunk[5285]
2018-01-17 16:31:16 +00:00
Denis Flaven
dc0e739667 Fix for a problem breaking the mysqldump detection (when it fails on windows). Root cause: do not return/display the output of the shell command used to test mysqldump since (on windows) it may contain non-UTF-8 characters of an unknown character set and this breaks "UTF-8 picky" functions like json_encode.
SVN:trunk[5284]
2018-01-17 16:29:44 +00:00
Pierre Goiffon
e74b2e32c9 Remove file that do not belongs here
SVN:trunk[5282]
2018-01-17 14:49:54 +00:00
Romain Quetiez
a2dd9b1d48 Getting ready for the release of 2.4.1 in february
SVN:trunk[5279]
2018-01-17 13:10:57 +00:00
Denis Flaven
474fdc0473 Setup: special mapping for 2 extensions which code has changed...
SVN:trunk[5277]
2018-01-17 12:36:25 +00:00
Guillaume Lajarige
e6ab3ac9f9 N°1277 Portal: Improve error reporting when user with no associated contact logs in the portal.
SVN:trunk[5276]
2018-01-17 12:31:05 +00:00
Denis Flaven
ae59780297 The Hub Connects !!
Adding iTop Hub Connector.

SVN:trunk[5270]
2018-01-17 10:04:33 +00:00
Pierre Goiffon
cbdafbf264 Exclude for itop-hub-connector
SVN:trunk[5268]
2018-01-17 09:02:46 +00:00
Guillaume Lajarige
76fa4a3090 Portal: Fix CSS for selected rows in dataTables tables
SVN:trunk[5266]
2018-01-16 16:59:36 +00:00
Guillaume Lajarige
896c6b79db Internal: Portal code cleanup
SVN:trunk[5265]
2018-01-16 16:25:31 +00:00
Denis Flaven
bb052f30d6 Preparing for the Hub: better decouple the RunTimeEnvironment from the list of directories to scan/install in order to support installation from the Hub.
SVN:trunk[5264]
2018-01-16 16:24:38 +00:00
Stephen Abello
ebbff7f615 datamodel viewer : fixed case where no class name were given, cleaned up code
SVN:trunk[5263]
2018-01-16 15:56:25 +00:00
Guillaume Lajarige
9d76ac96bc N°984 Portal: Fix autocomplete field reset when changing value of parent field in request templates.
SVN:trunk[5261]
2018-01-16 15:37:28 +00:00
Guillaume Lajarige
1926a40277 Internal: PHPDoc
SVN:trunk[5260]
2018-01-16 15:32:11 +00:00
Pierre Goiffon
6cd108badf RelationGraph : some PHPDoc
SVN:trunk[5258]
2018-01-16 15:04:08 +00:00
Eric Espié
5993d74eec N°1246 - Fix Obsolete data visible in dependency graph.
* Fix a wrong transient OQL expression cache.

SVN:trunk[5257]
2018-01-16 15:01:33 +00:00
Guillaume Lajarige
84b98a2265 N°1276 Portal: Aligned drop-down list to autocomplete threshold behavior to console's behavior.
SVN:trunk[5255]
2018-01-16 14:24:24 +00:00
Eric Espié
0df071b4db Default class is Organization
SVN:trunk[5254]
2018-01-16 11:07:13 +00:00
Eric Espié
bfd092b499 N°1224 - The 2.4.x setup keep the selected choices from a 1.3.x version.
* The selection is kept even if the extension has a one more module than the 1.3.x

SVN:trunk[5252]
2018-01-16 10:38:17 +00:00
Eric Espié
23f2ea5031 N°1026 - Portal requests are too slow
* Counts on union requests are more optimized
* Requests for combo box values are more optimized

SVN:trunk[5249]
2018-01-15 15:16:20 +00:00
Stephen Abello
29165b8ef4 datamodel viewer : cleanup code, fixed links in tooltips and added a classname following while scrolling down the page
SVN:trunk[5247]
2018-01-12 16:32:10 +00:00
Pierre Goiffon
c862179465 N°942 set nex itop release MySQL requirement to 5.5.3 for utf8mb4
Update also the comments I forgot on the previous change (woooops), and the warning messages beginning with "error" (hahem)

SVN:trunk[5245]
2018-01-12 16:07:31 +00:00
Pierre Goiffon
7a371f8b26 N°942 next itop release PHP & MySQL requirements : use *.0 versions instead of the latests
SVN:trunk[5243]
2018-01-12 15:35:25 +00:00
Eric Espié
7a7b968c1b Cleanup code
SVN:trunk[5242]
2018-01-12 14:28:42 +00:00
Eric Espié
9571404907 Cleanup code
SVN:trunk[5240]
2018-01-12 13:37:40 +00:00
Pierre Goiffon
ae946f6821 N°942 change next itop release MySQL version requirement from 5.6 to 5.5, plus add some comments
SVN:trunk[5238]
2018-01-12 11:26:12 +00:00
Denis Flaven
6128625706 Fixed regression introduced by [r5235]: some directories (like data/production-modules) may not always exist... this should not stop the setup.
SVN:trunk[5237]
2018-01-11 17:23:01 +00:00
Denis Flaven
ea2a3c1980 Handle extensions with missing dependencies.
SVN:trunk[5235]
2018-01-11 10:49:18 +00:00
Denis Flaven
9b6814aee9 Typo
SVN:trunk[5234]
2018-01-11 10:38:30 +00:00
Denis Flaven
6544659251 Small setup refactoring for getting ready for the Hub.
SVN:trunk[5232]
2018-01-10 15:47:15 +00:00
Stephen Abello
dcff39da25 N°1147 Enable data synchronization for applications classes (Localized Data).
SVN:trunk[5230]
2018-01-10 14:10:29 +00:00
Pierre Goiffon
94ba32af57 Some PHPDoc
SVN:trunk[5229]
2018-01-10 14:08:36 +00:00
Pierre Goiffon
cc08613304 New method to test if a field is read only in the current DBObject state
SVN:trunk[5228]
2018-01-10 14:08:29 +00:00
Eric Espié
95941f4dc5 N°870 - Fix the display of archived objects in the dashlets when activating/deactivating the archive mode.
SVN:trunk[5226]
2018-01-10 13:39:41 +00:00
Guillaume Lajarige
3f2e20fe44 Portal: Change Ticket->public_log's flags in ev_reopen form. Now MUST_CHANGE instead of MUST_PROMPT.
SVN:trunk[5224]
2018-01-10 13:31:39 +00:00
Stephen Abello
67124a4104 datamode viewer : fix lifecycle image generation on Windows. (Error: "C:/Program does not exist")
SVN:trunk[5222]
2018-01-10 08:15:49 +00:00
Eric Espié
174bcf56d3 cleanup code
SVN:trunk[5221]
2018-01-10 07:58:51 +00:00
Romain Quetiez
d9fd3b47e1 Copyright updated to 2018
SVN:trunk[5220]
2018-01-09 16:41:30 +00:00
Eric Espié
89492f8904 N°870 - Avoid Obsolete data in audit results
SVN:trunk[5219]
2018-01-09 16:07:18 +00:00
Eric Espié
42dc73964c N°870 - Avoid Obsolete data export in CSV, Excel and PDF
SVN:trunk[5218]
2018-01-09 15:51:03 +00:00
Guillaume Lajarige
449316257a N°1247 Fix AttributeEnum display as vertical radio buttons in console UI.
SVN:trunk[5216]
2018-01-09 14:43:06 +00:00
Eric Espié
3b621adcb2 N°925 - Fix portal when request template field is in autocomplete mode with a wrong value
* No error is displayed, but the actual value is set to '0'

SVN:trunk[5215]
2018-01-09 13:57:29 +00:00
Pierre Goiffon
8d9d4e67ca N°942 setup : max version for PHP
SVN:trunk[5213]
2018-01-08 15:34:00 +00:00
Guillaume Lajarige
eb43a02bce Fix regression introduced in r5183.
SVN:trunk[5211]
2018-01-08 12:40:05 +00:00
Guillaume Lajarige
7f034f60d6 N°1254 Portal: Add CSS/JS hooks on object forms for the current state
- CSS class on <form> tag: form_object_state_<STATE_CODE>
- HTML attribute on <form> tag: data-object-state="<STATE_CODE>"

SVN:trunk[5209]
2018-01-08 12:09:35 +00:00
Guillaume Lajarige
c4cf10b6e6 N°1172.3 Portal: Objects and external keys in linkedsets (forms) now open in a modal dialog.
SVN:trunk[5207]
2018-01-08 11:36:22 +00:00
Stephen Abello
b2a1404ce0 datamode viewer revamped: Class search, new panel for class list, graphical representation of each class and its related classes, granularity on data display and a fix on lifecycle graph.
SVN:trunk[5206]
2018-01-05 15:18:56 +00:00
Pierre Goiffon
52a97db259 N°1253 Configuration editor : save/restore editor state on saving
SVN:trunk[5205]
2018-01-05 15:16:45 +00:00
Pierre Goiffon
e5ccb4271e HTMLDOMSanitizer remove duplicate code declaration
SVN:trunk[5204]
2018-01-04 17:30:26 +00:00
Pierre Goiffon
27a2614b7d N°801 allow block quotes in HTML Fields
add BLOCKQUOTE tag in the HTMLDOMSanitizer white list

SVN:trunk[5202]
2018-01-04 17:18:02 +00:00
Guillaume Lajarige
5cc39848ff Typo
SVN:trunk[5201]
2018-01-04 10:55:14 +00:00
Guillaume Lajarige
b9d719d636 N°1194 Portal: Support for MUST_CHANGE flag on CaseLog attributes in transitions.
SVN:trunk[5199]
2018-01-04 10:38:47 +00:00
Guillaume Lajarige
3e6b3a2755 N°1245 Fix MUST_CHANGE flag behavior on CaseLog attributes in the console.
SVN:trunk[5197]
2018-01-03 14:44:59 +00:00
Guillaume Lajarige
88167fb3ae N°1217.2 Console UI: Small enhancements on object properties display.
* HTML Attribute value not breaking on words anymore.
* Attribute label width bigger on single column display.

SVN:trunk[5194]
2018-01-03 09:41:58 +00:00
Guillaume Lajarige
b5685a9d76 Rollback modifications from r5192 as it introduced a regression.
JS escaping and previous value comparison strategies are to be define before going further with this matter.

SVN:trunk[5193]
2018-01-03 09:07:26 +00:00
Guillaume Lajarige
4c652a87c0 N°1243 Fix MUST_CHANGE/MANDATORY checks on transition in the console on an HTML Attribute.
SVN:trunk[5192]
2018-01-02 16:18:18 +00:00
Pierre Goiffon
1f8bd69aef N°942 setup : add checks for next iTop release requirements on PHP and MySQL versions
* new constants in SetupUtils
* renamed existing methods
* warning if PHP and MySQL versions are lower than expected

SVN:trunk[5190]
2018-01-02 16:04:26 +00:00
Guillaume Lajarige
71d9bb18e5 N°1172.2 Fix regression introduced in r5161 (Email notification crash because of portal urls)
SVN:trunk[5189]
2018-01-02 15:59:01 +00:00
Pierre Goiffon
067b3364ee Add some PHPDoc, fix some syntax (thanks to SonarLint !)
SVN:trunk[5188]
2018-01-02 14:20:02 +00:00
Pierre Goiffon
b2494ebaf7 Create abstract DBSearch#GetSQLQueryStructure() to allow "call hierarchy" to work
Visibility to public to allow testing

SVN:trunk[5187]
2018-01-02 14:19:54 +00:00
Eric Espié
f73ca10b6c N°1070: Enhance ergonomics of "Add To Dashboard..." popup window
* Larger window to avoid the scrollbar.
* Check the dashboards root parent access rights to generate the dashboards list proposed in the popup.

SVN:trunk[5185]
2018-01-02 13:08:14 +00:00
Guillaume Lajarige
fe23e099fe N°1227 New configuration parameter (disable_attachments_download_legacy_portal) to disable attachments download from the legacy portal. Default is "true"!
SVN:trunk[5183]
2017-12-29 13:54:20 +00:00
Guillaume Lajarige
333411535e N°1132 Add ContextTag on CRON background tasks (eg. "CRON:Task:<CLASS_NAME_OF_THE_CURRENT_TASK>").
Introduced for the "Mail to ticket automation" extension, so we know when a Ticket is created/updated from an email.

SVN:trunk[5181]
2017-12-29 09:55:36 +00:00
Guillaume Lajarige
cc6272e84a N°1143 Fix removed email links (mailto) in HTML attributes (CKEditor).
SVN:trunk[5179]
2017-12-28 15:34:24 +00:00
Guillaume Lajarige
c7857835c7 N°850 Show "delete" and "bulk delete" rights in user's grant matrix.
SVN:trunk[5177]
2017-12-28 10:37:04 +00:00
Guillaume Lajarige
9bfaf10468 N°624 Fix WYSIWYG feature in CaseLog / HTML attributes on transition.
SVN:trunk[5175]
2017-12-28 09:25:03 +00:00
Guillaume Lajarige
095d5c9442 Compiled CSS filed from previous commit (r5168)
SVN:trunk[5171]
2017-12-27 15:54:36 +00:00
Guillaume Lajarige
4fa6f85c2e N°1217 Console UI improvements in object forms.
- Columns size optimization.
- Tooltip on (none empty) String attribute so long value can be seen without scrolling to the end of the input.
- OQL attribute displayed as Text/HTML attributes.

SVN:trunk[5170]
2017-12-27 15:51:50 +00:00
Pierre Goiffon
76a9978fc5 N°1182 fix overlapping table in console dashlets : now we have a scrolling bar if necessary
SVN:trunk[5168]
2017-12-27 14:50:44 +00:00
Guillaume Lajarige
4b46b2776a N°916 Fix impact analysis relation upstream description.
Description was unique for both directions. Now 2 separate entries are used 'Realtion:<RELATION_CODE>/<DIRECTION>Stream+'.
Translations for existing languages are already done.

SVN:trunk[5166]
2017-12-27 09:59:21 +00:00
Eric Espié
907505ccf9 Fix and refactor based on unit tests results
SVN:trunk[5165]
2017-12-22 14:08:58 +00:00
Eric Espié
3e35dafefb Unit tests based on PHPUnit
These tests run with the sample datamodel and they don't commit any data (only some indexes are incremented).

To launch the test suite, run the following command from the test repository:
php.exe <PATH_TO>/phpunit.phar --configuration <PATH_TO>/test/PHPunit.xml

SVN:trunk[5164]
2017-12-22 13:37:26 +00:00
Eric Espié
11ee5126ef N°789 - Fix losing the additional links attributes values during impact analysis update
The issue was only visible when attributes were added to the links (FunctionalCIs and Contacts).
When a Ticket is modified, the impact analysis generate a new set of links for FunctionalCIs and Contacts.
If new attributes are added on links, the values were lost during the process.
Now existing links are kept along with the additional attributes values.

SVN:trunk[5162]
2017-12-22 13:09:21 +00:00
Guillaume Lajarige
37bdb1ba2f N°1172 Portal: Objects and external keys in linkedsets (forms) now have hyperlinks if access is authorized regarding the user's scopes.
SVN:trunk[5161]
2017-12-21 08:31:32 +00:00
Pierre Goiffon
a9fc1083c7 PHPDoc for AddModule()
SVN:trunk[5160]
2017-12-20 16:34:55 +00:00
Eric Espié
9be804fb35 N°1209 - Fix Organization selector width (missing button)
SVN:trunk[5157]
2017-12-15 13:17:23 +00:00
Eric Espié
38a466fc21 N°1209 - Fix Organization selector width (padding added)
SVN:trunk[5155]
2017-12-15 11:20:36 +00:00
Eric Espié
aa5ee45034 N°1209 - Fix Organization selector width
SVN:trunk[5154]
2017-12-15 09:48:13 +00:00
Denis Flaven
5b1e1d0d6a Enhancement: automatically recognize some well-know mutli-module extensions deployed using the old format (i.e. shipped without an extension.xml file) and emulate the new format for them in order to display a meaningful label and version in the setup and in the about box.
SVN:trunk[5152]
2017-12-14 12:11:51 +00:00
Romain Quetiez
a818a09469 N°1188 & N°1189 Too much disk space / memory used for backup / restore - completing the commit [r5144], because the PHP extension phar is no more required
SVN:trunk[5151]
2017-12-11 16:19:16 +00:00
Guillaume Lajarige
0d439a08fc Portal: Default brick icon classes were using a wrong constant and therefore not displaying correctly.
SVN:trunk[5150]
2017-12-05 10:24:02 +00:00
Pierre Goiffon
9032f25d64 CMDBSource : fix code errors and some warnings
SVN:trunk[5149]
2017-12-04 15:07:21 +00:00
Pierre Goiffon
28efea7ac1 N°1195 exception handling in cron.php
* cron.php : use exit(n°) instead of exit n°, and extract codes to constants
* CMDBSource : new MySQLHasGoneAwayException
* exits cron.php on MySQLHasGoneAwayException
* fix backgroundprocess PHPDoc
* new ProcessException and ProcessFatalException
* new cron.php catch blocks

SVN:trunk[5148]
2017-12-04 15:07:15 +00:00
Guillaume Lajarige
f2f0badc77 N°1199 Fixed "Notice: undefined index 0" in the portal. UserRequest/Incident::ComputePriority() was failing when attributes impact had no value.
SVN:trunk[5147]
2017-12-01 15:41:52 +00:00
Eric Espié
00e3d5c0d2 License reformat.
SVN:trunk[5146]
2017-11-30 09:23:26 +00:00
Eric Espié
c08edc207c N°1190 - Better error reporting and disk cleanup.
SVN:trunk[5145]
2017-11-30 08:58:58 +00:00
Eric Espié
6477e2e1bb N°1188 - Backup needs too much disk space
SVN:trunk[5144]
2017-11-30 08:52:44 +00:00
Eric Espié
694da178c4 N°1191 - Wrong file name for backup check.
SVN:trunk[5143]
2017-11-30 08:48:59 +00:00
Pierre Goiffon
d80b890cd0 Fix warnings and errors in SynchroReplica
SVN:trunk[5142]
2017-11-29 14:30:10 +00:00
Pierre Goiffon
6b9c038b31 Mutex : add some comments
SVN:trunk[5141]
2017-11-27 17:00:03 +00:00
Guillaume Lajarige
b071f920e9 Portal: Typo in SCSS variable.
SVN:trunk[5140]
2017-11-25 14:53:20 +00:00
Pierre Goiffon
3cd28d1559 Some PHPDoc and small reformat
SVN:trunk[5139]
2017-11-23 17:42:24 +00:00
Guillaume Lajarige
72563d8ef1 Internal: Typos in XML comments.
SVN:trunk[5138]
2017-11-23 09:34:26 +00:00
Eric Espié
375798a344 N°1070 - Enhance ergonomics of "Add To Dashboard..." popup window
SVN:trunk[5137]
2017-11-22 14:40:28 +00:00
Eric Espié
b401c65684 N°1163 - GET_LOCK 64 characters limitation in MySQL
SVN:trunk[5135]
2017-11-21 12:14:20 +00:00
Guillaume Lajarige
d7c78b3ce2 Portal: Updated SCSS to de-hardcode some values.
SVN:trunk[5134]
2017-11-20 14:29:40 +00:00
Eric Espié
4a4c03a225 N°1160 - Fix error when sending notification with list of links.
SVN:trunk[5132]
2017-11-17 14:43:01 +00:00
Eric Espié
85b31701f4 N°1156 - Manual backup can be very long
* The database is saved in last position to avoid overhead when generating the archive file

SVN:trunk[5130]
2017-11-16 14:00:41 +00:00
Guillaume Lajarige
28b3110895 N°1157 Portal: Exception raised in BrowseBrick when one of the levels had no scope.
SVN:trunk[5129]
2017-11-16 09:05:02 +00:00
Pierre Goiffon
011e6d895b N.1151 compiler : throw an exception if a module contains an unknown menuId reference
SVN:trunk[5128]
2017-11-10 13:42:55 +00:00
Vincent Dumas
0f7099acfa dictionnary typo on Notification header message
SVN:trunk[5126]
2017-11-03 09:03:14 +00:00
Eric Espié
96296fe211 Duration KPI added on sending email.
SVN:trunk[5125]
2017-11-02 16:43:00 +00:00
Pierre Goiffon
51a60e637c Some PHPDoc
SVN:trunk[5124]
2017-10-31 17:08:25 +00:00
Pierre Goiffon
078f13fdb1 applicationcontext CrLf to Lf conversion
SVN:trunk[5123]
2017-10-31 15:38:30 +00:00
Denis Flaven
c210afd086 (Regression) Fix display trouble for auto_reload menus. This was caused by a collision of HTML/DOM ids where the menu item of the left (accordion) menu had the same id as the div displaying the actual content in the right pane. This caused (when the id was a valid one !) the refresh of the content (list of objects) to occur INSIDE the accordion menu !
SVN:trunk[5121]
2017-10-31 10:29:05 +00:00
Guillaume Lajarige
81d9071b01 N°634.3 Portal: Argh!! Secondary actions menu in BrowseBrick was broken due to previous CSS "fixes"...
SVN:trunk[5119]
2017-10-30 16:03:58 +00:00
Romain Quetiez
94ca9c4df9 Ready for releasing...
SVN:trunk[5117]
2017-10-30 14:26:22 +00:00
Eric Espié
bff2ae319f 2.4.0 - New readme format.
SVN:trunk[5115]
2017-10-30 14:14:51 +00:00
Eric Espié
5bd30381cf Core russian translation kindly provided by Vladimir Kunin.
SVN:trunk[5113]
2017-10-30 11:34:39 +00:00
Pierre Goiffon
121a615ce3 UI.php : remove unused variables and change todo comment
SVN:trunk[5112]
2017-10-27 14:45:53 +00:00
Pierre Goiffon
5877b66c83 PHP Code Style : allow one line if with no braces
SVN:trunk[5111]
2017-10-27 14:45:47 +00:00
Stephen Abello
1ba86a91f9 added german translation for obsolescence. Thanks to ITOMIG.
SVN:trunk[5109]
2017-10-27 13:49:07 +00:00
Denis Flaven
e56847ee8d Simplification of the obsolescence conditions (N° 890) due to the risk of reaching the limit of 61 tables (N°1049)
SVN:trunk[5107]
2017-10-27 13:07:54 +00:00
Pierre Goiffon
1fbbfd1063 Portal SCSS : restore @extend inside @media, because this gives no error and do the job with scssphp lib
SVN:trunk[5105]
2017-10-27 08:56:59 +00:00
Pierre Goiffon
1fed66fff3 N.1117 some PHPDoc modifications
SVN:trunk[5104]
2017-10-27 08:56:45 +00:00
Guillaume Lajarige
c607a7e35d Internal: Updated modules version to 2.4.0 (as well as some copyright dates)
SVN:trunk[5103]
2017-10-27 08:53:39 +00:00
Pierre Goiffon
06d6968951 Fix invalid CSS and SCSS
SVN:trunk[5102]
2017-10-27 08:20:46 +00:00
Guillaume Lajarige
7ed8a9f638 N°1138 Portal: Scrollbar appeared sometimes in navigation menu when on the last brick.
SVN:trunk[5097]
2017-10-26 17:37:13 +00:00
Guillaume Lajarige
52595138cd N°930.2 Console UI: Better object details layout step 2.
SVN:trunk[5095]
2017-10-26 17:03:32 +00:00
Pierre Goiffon
eca2b01307 Code style : line endings Lf
SVN:trunk[5094]
2017-10-26 16:02:52 +00:00
Pierre Goiffon
df758679cc Change version number for static resources calls
SVN:trunk[5093]
2017-10-26 15:43:57 +00:00
Pierre Goiffon
6b6300d117 PHPStorm shared Inspections update : inconsistent line endings as WARN
SVN:trunk[5092]
2017-10-26 15:28:06 +00:00
Pierre Goiffon
b535e11f5a Change modules XML version to the latest (1.4)
SVN:trunk[5091]
2017-10-26 15:10:06 +00:00
Pierre Goiffon
a4ad8d0a61 Change version number in CSS url() calls
SVN:trunk[5090]
2017-10-26 09:28:22 +00:00
Pierre Goiffon
e66eb537d8 datatable refresh prb when source is in CrLf instead of Lf :
* add a try/catch block in the JS code
* properly escape string returned
This can happen for example when checking out with git-svn on Windows with core.autocrlf=auto

SVN:trunk[5089]
2017-10-26 08:58:23 +00:00
Pierre Goiffon
b8ef2e68ba Firsts settings for JS code style
SVN:trunk[5088]
2017-10-26 08:58:11 +00:00
Pierre Goiffon
30b10d3b6b Dict::S() PHPDoc modification
SVN:trunk[5087]
2017-10-26 08:57:54 +00:00
Eric Espié
f09347841c Fix utils::GetCurrentModuleUrl() introduced in revision 4920
SVN:trunk[5085]
2017-10-25 15:22:40 +00:00
Guillaume Lajarige
f87e8ca522 Translations: Added icon attribute for ServiceFamily and Service classes. English and French done, feel free to contribute for others ! :)
SVN:trunk[5080]
2017-10-24 15:13:51 +00:00
Guillaume Lajarige
2871f64f68 Internal: Updated sample data with avatar of new Combodo members ! (Bis)
SVN:trunk[5079]
2017-10-24 14:54:06 +00:00
Guillaume Lajarige
cd1c5f5799 Internal: Updated sample of ServiceFamily and Service classes to add icons (used in the mosaic mode of the portal's services catalog)
SVN:trunk[5078]
2017-10-24 14:39:03 +00:00
Pierre Goiffon
890fcac73f Fix another regression introduced in r5071 : module url were generated with arguments values that were url-encoded twice (so this leads to some errors when using them)
SVN:trunk[5077]
2017-10-24 14:02:59 +00:00
Guillaume Lajarige
d7851ed090 Internal: Updated sample data with avatar of new Combodo members !
SVN:trunk[5076]
2017-10-24 11:46:16 +00:00
Pierre Goiffon
678df3cc46 Fix regression introduced in r5071 (wooops), plus some PHPDoc
SVN:trunk[5074]
2017-10-24 08:07:07 +00:00
Eric Espié
2f48b2e302 N°1134 - Bad version number when MTP
* The order of the installed versions is changed when doing MTP.

SVN:trunk[5073]
2017-10-24 08:03:26 +00:00
Pierre Goiffon
a816a6ff8d cursor:pointer for label
SVN:trunk[5072]
2017-10-23 15:59:44 +00:00
Pierre Goiffon
b189d2a39b Split the method to get a module absolute URL into 3 different methods, to allow more flexibility (for example get the URL and the query string key/value array to construct a GET form)
SVN:trunk[5071]
2017-10-23 15:59:34 +00:00
Guillaume Lajarige
5424682fdb N°634.2 Portal: CSS fixes on mosaic mode of BroweseBrick
SVN:trunk[5070]
2017-10-23 15:43:18 +00:00
Guillaume Lajarige
ad3ce7c536 Internal: Updated module version (itop-portal, itop-portal-base)
SVN:trunk[5069]
2017-10-23 13:49:35 +00:00
Eric Espié
d4dd300e28 N°1131 - Setup: Can't add options to ITIL Ticketing in update mode
* Fix the alternative selection when updating the setup
* Uncheck options when the alternatives are deselected

SVN:trunk[5067]
2017-10-23 11:37:13 +00:00
Pierre Goiffon
99fd6b97db JQuery hotkeys plugin license
SVN:trunk[5066]
2017-10-23 09:09:56 +00:00
Pierre Goiffon
684e9e3537 Run query screen : new Ctrl+Return shortcut to execute query
SVN:trunk[5065]
2017-10-23 07:43:05 +00:00
Guillaume Lajarige
1bde863124 N°1123.5 Typo
SVN:trunk[5061]
2017-10-20 13:25:28 +00:00
Guillaume Lajarige
5c34e3d988 N°1123.4 AttributeImage: Better UI when editing in console. Also, export was showing url for empty value.
SVN:trunk[5060]
2017-10-20 13:22:38 +00:00
Eric Espié
b7c4e084f3 N°1131 - Setup: Can't add options to ITIL Ticketing in update mode
* Fix the disable attribute of the options

SVN:trunk[5057]
2017-10-20 11:54:05 +00:00
Guillaume Lajarige
36395ae355 N°642.3 Portal: Lifecycle: Exception on UserRequest opening due to a bad variable initialization.
SVN:trunk[5056]
2017-10-20 08:30:27 +00:00
Romain Quetiez
f4881d11c7 N.1100 Regression introduced in [r4943], aka 2.4 RC3, and causing error during MTP (accessing the wrong expression cache)
SVN:trunk[5054]
2017-10-19 19:06:40 +00:00
Eric Espié
bbde89e0f9 N°1109 - itop-object-copier Create ticket from CI was not adding the CI in the CI list of the newly created ticket.
* Fix 'add_to_list' command.
* Fix Adding a n-n link at the creation time.

SVN:trunk[5053]
2017-10-19 14:39:15 +00:00
Pierre Goiffon
fb22107be8 N.689 workaround on MySQL number of joins limit (61)
* change MySQLException to store initial exception code
* added a try/catch to launch query with full lazy load (no attr => only id)
* load finalClass field if needed (class is nor standalone nor a final leaf)

SVN:trunk[5051]
2017-10-19 13:43:06 +00:00
Pierre Goiffon
5ada93b46c N.689 throw Exception if querying without needed finalClass attribute, plus some PHPDoc
SVN:trunk[5050]
2017-10-19 13:42:56 +00:00
Guillaume Lajarige
b798b43733 N°1094 & N°1107 Portal: Mosaic mode in BrowseBrick displays icon nicely in IE9. Also, "name" on tiles doesn't break layout anymore when too long.
SVN:trunk[5046]
2017-10-19 12:57:44 +00:00
Guillaume Lajarige
1669eb3759 N°1071 UI: Better rendering for external keys in linkedset (no more wrapping)
SVN:trunk[5045]
2017-10-19 09:28:20 +00:00
Guillaume Lajarige
071316c606 N°1129.1 Support of $this->hyperlink(itop-portal)$ in notifications (only "portal" was implemented for the default portal).
SVN:trunk[5044]
2017-10-19 08:57:05 +00:00
Guillaume Lajarige
d8b5dd7bd2 N°1094.3 Portal: Forgot compiled .css on last commit. Not necessary but improves first page load after setup / MTP.
SVN:trunk[5042]
2017-10-18 14:58:23 +00:00
Guillaume Lajarige
868c1cface N°1123.3 Internal: Removed deprecated comment.
SVN:trunk[5040]
2017-10-18 14:50:39 +00:00
Guillaume Lajarige
8e83baf72b N°1094.2 Portal: Showing "icon" attribute on ServiceFamily and Service levels in "mosaic" mode of "services" BrowseBrick.
SVN:trunk[5038]
2017-10-18 14:29:53 +00:00
Guillaume Lajarige
54858c63f5 N°1094.1 Adding icon (AttributeImage) to ServiceFamily and Service classes
SVN:trunk[5037]
2017-10-18 14:27:40 +00:00
Guillaume Lajarige
bc3d03c462 N°1123.2 AttributeImage: default_image is no longer mandatory.
SVN:trunk[5036]
2017-10-18 13:46:17 +00:00
Eric Espié
c94476b9a2 N.1065 Fix performance issues.
* Added the bGetCount flag into the cache to differentiate the cache entries for COUNT only.

SVN:trunk[5034]
2017-10-18 12:53:23 +00:00
Guillaume Lajarige
73812dc400 N°1123 AttributeImage: PHP notice when displaying an object without default_image on a AttributeImage attribute.
SVN:trunk[5031]
2017-10-18 09:34:50 +00:00
Guillaume Lajarige
cfdc7eb74a N°911.2 Portal: Updated typeahead repository url in files headers.
SVN:trunk[5030]
2017-10-17 14:03:10 +00:00
Romain Quetiez
a0ad331023 Automatic tests: improved the automatic benchmark of all queries
SVN:trunk[5029]
2017-10-17 10:26:02 +00:00
Guillaume Lajarige
2561358f9d N°1122 Portal: Clean-up of 2 redundants JS files regarding the autocomplete inputs in forms.
SVN:trunk[5028]
2017-10-17 09:57:44 +00:00
Pierre Goiffon
3fd7dae8f9 N.1108 return exception if $bMustBeFound and result is archived
SVN:trunk[5025]
2017-10-16 14:42:17 +00:00
Guillaume Lajarige
426a0933b1 N°1092.1 Setup / MTP improvements regarding the environments folders:
- /env-production-build rights check before running setup
- /env-xxx-build is no longer deleted after MTT / MTP from the ITSM Designer. This prevents permissions issue when webserver user doesn't have suffisant rights on the root folder.

SVN:trunk[5023]
2017-10-13 13:25:20 +00:00
Eric Espié
2f8062d296 N°454 - Check data validity during CSV import
* The controls are only done on database integrity for the different keys.
* If retrofit to branch 2.4 take also the revisions: 4999, 5000, 5005, 5006

SVN:trunk[5022]
2017-10-13 12:28:09 +00:00
Romain Quetiez
d18165ebe9 Continuation of [r5015] Typo in FR dictionary, for SoftwareInstance/patch (backtick used instead of single quote)
SVN:trunk[5021]
2017-10-13 09:00:42 +00:00
Eric Espié
38796f9d0c N.1065 Fix performance issues.
* Does not cache requests containing "id NOT IN ..." (too specific)

SVN:trunk[5019]
2017-10-12 15:31:14 +00:00
Eric Espié
79b887d189 N°1110 - DataSynchro: PHP Notice Undefined Index
* Fix access to REQUEST_URI when called by script

SVN:trunk[5017]
2017-10-12 13:54:28 +00:00
Vincent Dumas
8dc92e7ccf FR dictionnary typo for Ticket status Waiting for approval
SVN:trunk[5015]
2017-10-12 13:31:56 +00:00
Eric Espié
e04e5913de N.1065 Fix performance issues.
* Does not cache requests containing "id IN ..." (too specific)

SVN:trunk[5012]
2017-10-12 11:58:48 +00:00
Eric Espié
5c734cdabc Message when no data are available
SVN:trunk[5011]
2017-10-12 11:54:02 +00:00
Guillaume Lajarige
f924e99f70 N°642.2 Portal: Lifecycle transitions security is now a blacklist instead of a white list. Making migration transparent and portal configuration easier.
SVN:trunk[5008]
2017-10-12 08:33:41 +00:00
Eric Espié
e179825896 N°1110 - DataSynchro: PHP Notice Undefined Index
* Fix access to REQUEST_URI when called by script

SVN:trunk[5007]
2017-10-12 07:52:39 +00:00
Eric Espié
94a561f0e4 N°454 - Check data validity during CSV import
* Cleanup expression construction

SVN:trunk[5006]
2017-10-12 07:43:36 +00:00
Eric Espié
56e14fc107 N°454 - Check data validity during CSV import
* "simulate" phase is more permissive on new hierarchical entries
* Better check during "apply" phase

SVN:trunk[5005]
2017-10-11 15:31:57 +00:00
Pierre Goiffon
29f0b74824 N.1108 Add PHPDoc
SVN:trunk[5004]
2017-10-11 13:20:42 +00:00
Pierre Goiffon
de682d5530 MetaModel code format
SVN:trunk[5003]
2017-10-11 13:20:24 +00:00
Pierre Goiffon
571a3341da Code style settings : fix function argument on new line
SVN:trunk[5002]
2017-10-11 13:20:05 +00:00
Pierre Goiffon
8edf7f2d60 Code Style settings modification
SVN:trunk[5001]
2017-10-11 09:43:30 +00:00
Eric Espié
5408545c07 N°454 - Check data validity during CSV import
* "simulate" phase is more permissive on new hierarchical entries
* Better check during "apply" phase

SVN:trunk[5000]
2017-10-11 09:28:23 +00:00
Eric Espié
d504fb209f N°454 - Check data validity during CSV import
* Added additional checks for external keys (including hierarchical ones)

SVN:trunk[4999]
2017-10-10 10:00:05 +00:00
Guillaume Lajarige
ee53c3a71e N°1107.1 Portal: Fixed image display in mosaic mode of BrowseBrick for Chrome and Firefox. IE still pending !
SVN:trunk[4998]
2017-10-09 13:58:05 +00:00
Eric Espié
bcf88d24f3 N°870: Bulk operation and obsolescence flag
* Avoid the hidden selection (and update) of obsolete data when the user does not want to see the obsolete data.

SVN:trunk[4997]
2017-10-09 11:58:10 +00:00
Eric Espié
b2935139b4 N.1065 Fix performance issues.
Cache display CSV format fix.

SVN:trunk[4996]
2017-10-06 15:09:01 +00:00
Romain Quetiez
635e7cfeec Fixed integration issue (possibly a regression): if an extension implements iApplicationExtension::OnDBInsert, and it calls DBWrite, then a fatal error occurs (call a member function on a null value). The error occurs for several types of attributes such as ormCustomField, ormCaseLog, ormLinkSet. The fix consists in aligning the internal values of a DBObject as soon as it has been written into the Database.
SVN:trunk[4993]
2017-10-06 14:06:01 +00:00
Eric Espié
49b6c3bed7 N.1065 Fix performance issues.
Add statistics on query table join optimization.

SVN:trunk[4992]
2017-10-06 13:53:06 +00:00
Denis Flaven
3f7ab67506 Preparing the connexion to the Hub.
SVN:trunk[4991]
2017-10-06 13:32:53 +00:00
Pierre Goiffon
df26833eb1 N.1065 When joining, reverse leaf-root order : now it's root first !
* decrease the amount of joins on obsolescence use cases
* should also improve other uses cases as most of the time we believe the attribute linked is in the root class !
* the root table join is done using expressions instead of OQL for perf reasons
* a where clause on finalclass is also added to avoid problems if the leaf table join is not used (would be removed during query optimization phase)

SVN:trunk[4983]
2017-10-05 15:53:44 +00:00
Guillaume Lajarige
df1ebaebf9 N°1104 DBObject::__toString() was way too verbose and returned all objects from linksets as string as well, causing memory limits.
SVN:trunk[4971]
2017-10-05 15:38:27 +00:00
Eric Espié
26bd04857d N°1098 Fix CSV import by id.
Fix a regression introduced in rev 4885.

SVN:trunk[4969]
2017-10-05 13:30:43 +00:00
Eric Espié
4c4ed14af5 N°1100 - External field pointing to a magic attribute
* A specific pass has been added in MetaModel::InitClasses() to generate the magic attributes before the external fields.

SVN:trunk[4968]
2017-10-05 10:13:14 +00:00
Romain Quetiez
f0c5a1b382 Automatic tests: improved the error reporting
SVN:trunk[4967]
2017-10-05 09:57:48 +00:00
Guillaume Lajarige
59ebc49d46 N°1025 Portal: Fixed regression introduced in r4863.
SVN:trunk[4966]
2017-10-05 09:48:29 +00:00
Eric Espié
bfde101f6b N.1065 Fix performance issues (unexpected objects reload).
* Fix regression in 2.4 into attribute optimization (archive_flag, obsolescence_flag).
* Fix attribute optimization (friendlyname for ExternalField pointing to ExternalKey)

SVN:trunk[4965]
2017-10-05 09:10:00 +00:00
Pierre Goiffon
2a0dce848c N.1041 little changes on trunk[4963] : uses NOWDOC instead of HEREDOC syntax, and some variable renaming
SVN:trunk[4964]
2017-10-04 09:45:13 +00:00
Pierre Goiffon
d759fed5e4 N.1041 configuration editor : add focus and ctrl+s shortcut
SVN:trunk[4963]
2017-10-04 09:32:59 +00:00
Pierre Goiffon
f731abe4e8 GitIgnore : .hacks/
SVN:trunk[4962]
2017-10-04 09:09:09 +00:00
Guillaume Lajarige
74111212a3 N°1065 Fixed a regression introduced in r4965.
SVN:trunk[4961]
2017-10-03 14:02:45 +00:00
Eric Espié
f86c1a87f9 N.1065 Fix performance issues.
Limit APC emulation cache entries to avoid disk saturation.
New configuration entry added: 'apc_cache_emulation.max_entries'.

SVN:trunk[4960]
2017-10-03 13:53:53 +00:00
Romain Quetiez
1f2493914f N.1065 and #372 Query build cache not efficient with global search (each search generates about 80 new entries in the APCu cache)
SVN:trunk[4959]
2017-10-03 11:35:21 +00:00
Guillaume Lajarige
e3efa7dc3d N°1065 Fixed a regression introduced in r4965.
SVN:trunk[4958]
2017-10-03 11:22:01 +00:00
Vincent Dumas
6612782021 FR dictionnary typo for obsolescence
SVN:trunk[4957]
2017-10-03 10:19:22 +00:00
Eric Espié
bdaabcea93 N.1065 Fix performance issues.
ormLinkSet creates the objects on demand.

SVN:trunk[4956]
2017-10-03 09:22:33 +00:00
Guillaume Lajarige
e6b6be2624 N°1034 New EventOnObject class to store explaination on object's updates
SVN:trunk[4955]
2017-10-03 08:19:05 +00:00
Eric Espié
b1f1c10878 APC emulation using files when APC or APCu is not installed.
SVN:trunk[4954]
2017-10-02 07:30:41 +00:00
Denis Flaven
d5b0bb021f N°1806, N°1069: CSV and Excel export and import of documents (files) and images as URLs.
SVN:trunk[4952]
2017-09-30 09:23:06 +00:00
Guillaume Lajarige
dd70275b41 N°653.2 Lifecycle: Fixed a regression introduced on r4767, transition buttons not working properly when editing an object.
SVN:trunk[4951]
2017-09-29 08:23:13 +00:00
Guillaume Lajarige
6aa782bd8b N°1082 Fixed a regression introduced with ormLinkSet rework: Modified links not updated.
SVN:trunk[4950]
2017-09-28 15:31:57 +00:00
Guillaume Lajarige
029545703f N°1067 Rework on ormLinkSet BC with DBObjectSet.
- PHP notice are not thrown anymore, see PHPDoc instead.
- GetColumnAsArray() introduced.

SVN:trunk[4949]
2017-09-28 11:33:19 +00:00
Guillaume Lajarige
8183674fc6 Internal: Typo in PHPDoc
SVN:trunk[4948]
2017-09-27 12:51:36 +00:00
Romain Quetiez
7391f64776 N.1072 Localization for magic attributes archive_date (completed the existing implementation) and obsolescence_date (full implementation)
SVN:trunk[4946]
2017-09-27 12:26:44 +00:00
Pierre Goiffon
776385cdc9 Fix regression introduced in trunk[4943]
SVN:trunk[4945]
2017-09-27 10:00:48 +00:00
Eric Espié
17bafc037c Code cleanup.
SVN:trunk[4944]
2017-09-27 09:44:19 +00:00
Eric Espié
e785352050 N.1065 Fix performance issues (caches added on query build)
SVN:trunk[4943]
2017-09-27 09:37:43 +00:00
Guillaume Lajarige
43e4408df1 N°1073 Reentrance issue on cmdbAbstractObject when coming from an extension implementing iApplicationObjectExtension.
SVN:trunk[4942]
2017-09-27 09:27:08 +00:00
Denis Flaven
78a68bb361 Internal: Make sure that UI dialogs are never bigger than the browser's window (not used in iTop though).
SVN:trunk[4940]
2017-09-26 09:58:20 +00:00
Guillaume Lajarige
ec2a2d3505 Internal: Changed way AttributeLinkedSet check if two ormLinkSet are equal.
SVN:trunk[4939]
2017-09-26 08:05:04 +00:00
Guillaume Lajarige
2625477d35 Internal: Typo in itop-tickets XML comments
SVN:trunk[4938]
2017-09-25 10:26:55 +00:00
Pierre Goiffon
a655dd639d Wooops fix some mistakes on .git* files
SVN:trunk[4937]
2017-09-22 16:05:00 +00:00
Romain Quetiez
3e61fd2452 N.707 Export of custom fields: improved the xlsx format and implemented the spreadsheet format (both are aligned)
SVN:trunk[4935]
2017-09-22 13:37:44 +00:00
Pierre Goiffon
c11753d91c Some JetBrains project configuration files
SVN:trunk[4934]
2017-09-21 15:02:46 +00:00
Pierre Goiffon
5884e6b3cf Add JetBrains files in .gitignore
SVN:trunk[4933]
2017-09-21 15:02:18 +00:00
Pierre Goiffon
46e4ba4518 Add a gitbugtraq file (https://github.com/mstrap/bugtraq)
SVN:trunk[4932]
2017-09-21 14:58:37 +00:00
Denis Flaven
a9c9e48cdb Added the open source logo as a character (uppercase letter O) to the font.
Increased the version number in the CSS to prevent caching/refresh issues.

SVN:trunk[4930]
2017-09-21 14:27:54 +00:00
Vincent Dumas
e32c1a4447 Standard DataModel: Add org_id and location_id to 'Rack' reconciliation keys. Mandatory for CSV import of CI on a Rack, when Rack name is not a unique identifier.
SVN:trunk[4929]
2017-09-21 13:52:01 +00:00
Romain Quetiez
fb99c25594 N°813 Enable bulk deletion of Data Synchro Replica
SVN:trunk[4927]
2017-09-21 10:09:45 +00:00
Eric Espié
6011aa2ac9 Configuration file editor:
- support syntax highlighting and checking (ace editor)
- better "apply" and "reset" buttons management
- limit code injection when checking the configuration
- better syntax checking for PHP7

SVN:trunk[4926]
2017-09-20 15:07:05 +00:00
Romain Quetiez
048c1ecf72 Code robustness: Though the commit [4922] solves the issue N.1052, it is safer to reset the cache as part of the "Commit" performed during the installation process.
SVN:trunk[4923]
2017-09-20 14:45:45 +00:00
Romain Quetiez
40360da454 N.1052 After a setup or MTP, the datamodel is not taken into account... until the web server gets restarted or the APC cache (user data) gets reset.
SVN:trunk[4922]
2017-09-20 14:41:45 +00:00
Eric Espié
0ce9ff4557 Allow modules to provide license file (license.<module_name>.xml) with same format as setup/licenses/community_license.xml
SVN:trunk[4921]
2017-09-20 09:21:31 +00:00
Eric Espié
625bfbb6fe Fix utils::GetCurrentModuleUrl() introduced in revision 4844
SVN:trunk[4920]
2017-09-19 08:12:39 +00:00
Guillaume Lajarige
4290d94841 N°1047.1 Internal: Modified some calls to the ITOP_XXX constants.
SVN:trunk[4915]
2017-09-15 15:46:03 +00:00
Guillaume Lajarige
8ff2151448 N°1006.2 Templates: $this->raw(attcode)$ can be used to display an date(time) attribute in the SQL format like before.
SVN:trunk[4914]
2017-09-15 14:26:15 +00:00
Guillaume Lajarige
610d69fb2e N°1006 Templates: Date & time format is now applied when using a date(time) attribute in a placeholder (eg. Notifications)
SVN:trunk[4913]
2017-09-15 13:49:25 +00:00
Guillaume Lajarige
822308b3a4 N°1019 Portal: OpenSans font embedded in iTop instead of fetching from google servers.
SVN:trunk[4912]
2017-09-15 09:18:51 +00:00
Guillaume Lajarige
c1d1e562ad N°762 Portal: Pre-filtering a browse brick in tree mode was making tree collapsing instead of showing results.
SVN:trunk[4911]
2017-09-14 15:10:57 +00:00
Guillaume Lajarige
379a0bd785 N°1038 Fatal error on transition with AttributeBlob or AttributeCaseLog
SVN:trunk[4907]
2017-09-13 15:59:06 +00:00
Denis Flaven
a477443c8d Adding E and F glyphs
SVN:trunk[4905]
2017-09-13 08:51:19 +00:00
Denis Flaven
ed693c03ab Combodo font enhancements.
SVN:trunk[4903]
2017-09-12 14:48:09 +00:00
Guillaume Lajarige
48f6635917 N°1029 Allowed portals are now displayed in the console user menu.
SVN:trunk[4901]
2017-09-08 09:39:31 +00:00
Guillaume Lajarige
d6707743a9 N°1024 Portal: New portal instances can now be XML only (through ITSM Designer), no more need for a dedicated module !
SVN:trunk[4900]
2017-09-07 16:03:55 +00:00
Guillaume Lajarige
6f474686ad N°1027 Internal
SVN:trunk[4899]
2017-09-07 16:01:02 +00:00
Guillaume Lajarige
affd8ea8a6 Internal: Code cleanup. Unecessary var_dump as it is already logged in the error log.
SVN:trunk[4898]
2017-09-06 18:56:08 +00:00
Romain Quetiez
abd2748a09 N.890.1 Move to test/prod failing with message "Unknown attribute org_id_archive_flag from class contact"
SVN:trunk[4897]
2017-09-06 15:31:42 +00:00
Guillaume Lajarige
6a1c9b9f26 N°1021 Regression introduced in r4841: Autocomplete failing with "Unknown filter code..."
SVN:trunk[4896]
2017-09-06 08:01:45 +00:00
Romain Quetiez
ac04aa3359 N.981 Regression introduced in [r4692]. It make sense to preserve the existing value... excepted when reloading some form elements (filtering depending on fields that have just been touched by the user).
SVN:trunk[4895]
2017-09-05 15:44:48 +00:00
Guillaume Lajarige
051d68c902 Internal: Completed documentation in itop-tickets datamodel.
SVN:trunk[4894]
2017-09-05 12:14:42 +00:00
Guillaume Lajarige
ce81f7abb6 Portal: Filter was not looking in the item description in tree mode.
SVN:trunk[4893]
2017-09-05 12:14:00 +00:00
Guillaume Lajarige
03fbde3403 N°769.1 Portal: Renamed "count per page" variable in bricks in order to prepare refactoring for bug N°769.
SVN:trunk[4892]
2017-09-04 15:56:18 +00:00
Guillaume Lajarige
59ddab9f94 N°781 Setup: New hook available after data load (ModuleInstaller::AfterDataLoad())
SVN:trunk[4891]
2017-09-04 10:46:33 +00:00
Denis Flaven
225cbb450e N°1012: The method "Set" cannot be used to initialize a Blob or an Image with a text string value. Do not let the user think it may work.
SVN:trunk[4890]
2017-09-04 10:33:54 +00:00
Romain Quetiez
7cace73844 N.1014 Fixed regressions introduced in the rework of MTP/MTT : test database named after test-build, and losing the data/delta.<nev>.xml file, and cleanup badly implemented
SVN:trunk[4889]
2017-09-01 14:44:28 +00:00
Vincent Dumas
2562d33997 German Dictionnaries for iTop version 1.4 from Itomig
SVN:trunk[4888]
2017-09-01 08:33:35 +00:00
Guillaume Lajarige
a1e5b32e49 N°976 PHP Warning on not initialized variable $sHTMLValue in cmdbAbstractObject::GetFormElementForField().
SVN:trunk[4887]
2017-08-31 14:52:44 +00:00
Guillaume Lajarige
0c5df83a95 N°817 Portal: Linkset widget opening was throwing a warning message on IE9.
SVN:trunk[4886]
2017-08-31 14:42:33 +00:00
Guillaume Lajarige
cf79456ff3 N°583.2 Fixed regression introduced in r4861.
SVN:trunk[4885]
2017-08-31 13:34:50 +00:00
Romain Quetiez
a0a378a91a N.948 - Obsolete objects become visible when navigating in paginated lists
SVN:trunk[4884]
2017-08-29 14:58:18 +00:00
Guillaume Lajarige
9cf42f6cc8 N°1002 Backup: '.' character in iTop instance path was causing a crash when trying to -temporary- replace them in the backup filename (due to compression lib limitations).
SVN:trunk[4883]
2017-08-29 14:30:46 +00:00
Denis Flaven
c022d12a0a N°409 - completely remove the use of Flash (via Open Flash Charts), and therefore remove the php-ofc library. iTop now uses c3.js and d3.js instead.
SVN:trunk[4882]
2017-08-29 10:07:27 +00:00
Romain Quetiez
3d72060bf5 N.890.1 and N.890.2: build a new run time environment into a separate "build" directory, then commit it by the mean of quick and bullet proof file copies/moves. Not yet used in the setup.
SVN:trunk[4881]
2017-08-29 08:08:24 +00:00
Guillaume Lajarige
43709576c0 N°554.3 Not displaying actions menu in n:n in read mode.
SVN:trunk[4880]
2017-08-28 10:13:53 +00:00
Guillaume Lajarige
8ca6610e75 N°858.2 Fixed regression introduced in r4716 making DataSynchro menu hidden from the Admin menu
SVN:trunk[4879]
2017-08-25 13:10:31 +00:00
Guillaume Lajarige
b02d347541 N°977 DataSynchro: Creation and edition was broken due to the new object set API from ormLinkSet.
Backward compatible method have been introduce to ensure plugins and modules compatibility. That being said they are already flagged as deprecated and should not be used.
New: Using those deprecated methods will raise a PHP deprecated error.

SVN:trunk[4878]
2017-08-25 13:06:21 +00:00
Guillaume Lajarige
a39789cf89 N°782.2 Linkset menu actions open in a new tab in edition mode only.
SVN:trunk[4877]
2017-08-25 09:36:16 +00:00
Guillaume Lajarige
58534dca39 N°782.1 New configuration parameter 'allow_menu_on_linkset' (boolean, default value false) to display actions in linkset in view mode (new, modify, delete, ...)
SVN:trunk[4876]
2017-08-25 08:35:59 +00:00
Guillaume Lajarige
538e9c11e8 N°779 Date format handling in LinkedSetIndirect was causing fatal error on object edition.
SVN:trunk[4875]
2017-08-24 13:24:46 +00:00
Romain Quetiez
cba6e8d8a3 890.3 Fixed regression introduced in commit 4870 - fatal error during a MTP from the designer
SVN:trunk[4874]
2017-08-23 15:31:08 +00:00
Guillaume Lajarige
fd9fe85ef3 N°844 Portal: ExternalField support in forms was not properly supporting external key as readonly.
SVN:trunk[4873]
2017-08-23 14:39:58 +00:00
Guillaume Lajarige
7ed3e10d0f N°978 Portal: Added cache delay to BrowseBrick item pictograms.
SVN:trunk[4872]
2017-08-22 12:34:12 +00:00
Guillaume Lajarige
fe98b850d1 N°978 Portal: Display / download of blob attributes and attachments in the portal was not compatible with portal configuration and silos by-passing.
SVN:trunk[4871]
2017-08-22 10:38:10 +00:00
Romain Quetiez
b1494d0dd9 N890.3 Archive mode toggle menu not visible after setup/MTP: the information is cached into the session and needs to be reset
SVN:trunk[4870]
2017-08-21 15:28:07 +00:00
Guillaume Lajarige
0655904683 N°849 Edition of an object with not allowed (silos) remote objects in a linkedset causes fatal error.
SVN:trunk[4869]
2017-08-21 10:12:19 +00:00
Guillaume Lajarige
bad5aff764 Internal: PHPDoc on some DBObjectSet methods.
SVN:trunk[4868]
2017-08-18 15:37:44 +00:00
Guillaume Lajarige
440f2639b5 N°498 Added some attributes to the HTML sanitizer (title for a tag, alt / title for img tag).
SVN:trunk[4867]
2017-08-18 13:59:49 +00:00
Guillaume Lajarige
5f2245595f N°313 Show product name on branding logo title instead of a generic "iTop" text.
SVN:trunk[4866]
2017-08-18 13:50:33 +00:00
Guillaume Lajarige
03db4e7a14 N°934 Hierarchy button loading indicator was not hidden on HK selection.
SVN:trunk[4865]
2017-08-18 12:55:59 +00:00
Guillaume Lajarige
04030e07e3 Internal: Removed PHP notices in ajax call from autocomplete fields in the console
SVN:trunk[4864]
2017-08-17 15:47:32 +00:00
Guillaume Lajarige
80832877eb N°984 Portal: Dependancies on autocomplete fields now works properly. (Changing value on a parent autcomplete was not resetting value on a dependant autocomplete field)
SVN:trunk[4863]
2017-08-17 15:21:17 +00:00
Guillaume Lajarige
aa63847502 N°991 Portal: Fixed a regression introduced in r4855 (N°743); request template selection was not working when several templates available.
SVN:trunk[4862]
2017-08-17 10:08:17 +00:00
Guillaume Lajarige
4171c5c35f N°583 CSV Import now supports friendlynames as reconciliation keys. More over, read-only attributes (friendlyname, obsolescence flag, ...) are forced to reconciliation scheme.
SVN:trunk[4861]
2017-08-17 09:51:38 +00:00
Guillaume Lajarige
8e06a95502 N°844 Portal: ExternalField support in forms has been improved (1 file missing from previous commit)
SVN:trunk[4860]
2017-08-16 09:41:21 +00:00
Guillaume Lajarige
1c84934777 N°649 Stop displaying Ticket objects in a CI's ongoing tickets tab when the impact code is 'not impacted'.
SVN:trunk[4859]
2017-08-11 09:52:38 +00:00
Guillaume Lajarige
0294f50339 N°410 Modal dialog's height for CSV export partially hidden because no scrollbar available.
SVN:trunk[4858]
2017-08-10 14:45:20 +00:00
Guillaume Lajarige
33098943a1 N°744 Portal: Prevented LinkedSet corruption through simultaneous updates. In the portal are now update incremantally like in the console. This needs to be tested with both 1:n and n:n LinkedSet
SVN:trunk[4857]
2017-08-10 13:55:41 +00:00
Guillaume Lajarige
b953a6ab3e N°377 Impact analysis: UI Glitch in tooltip when text was too long.
SVN:trunk[4856]
2017-08-09 15:09:35 +00:00
Guillaume Lajarige
7287cab6f4 N°743 Portal: Only editable fields are now passed in forms submit, fixing issue where a portal user could unwillingly change the UserRequest status if a Support Agent had assign the ticket while the portal user was editing.
SVN:trunk[4855]
2017-08-09 10:10:53 +00:00
Guillaume Lajarige
df4cad3ff1 N°844 Portal: ExternalField support in forms has been improved. For example, email and url links were not displayed as proper HTML.
SVN:trunk[4854]
2017-08-08 11:59:53 +00:00
Guillaume Lajarige
66b6206daf N°949 Cleaned up old datamodel (1.x) as it was no longer maintained and could not be upgraded.
SVN:trunk[4853]
2017-08-03 10:11:39 +00:00
Guillaume Lajarige
6f40459215 N°952 Portal: Added UI extension APIs similar to those used in the console (Experimental!)
SVN:trunk[4852]
2017-08-02 11:30:30 +00:00
Guillaume Lajarige
24430e630f N°969 Portal: ManageBrick tabs could show objects that were not supposed to be shown due to a bad OQL interpretation.
SVN:trunk[4851]
2017-08-01 14:14:32 +00:00
Guillaume Lajarige
3420db26a5 N°564 LoginWebPage title default value is now a dictionary entry ('UI:Login:Title'). Only english & french are available for now, feel free to contribute ! :)
SVN:trunk[4850]
2017-07-31 15:06:21 +00:00
Guillaume Lajarige
c27cafb02f N°642 Portal: Fixed bug in new stimulus form algorithm
SVN:trunk[4849]
2017-07-28 15:01:51 +00:00
Denis Flaven
09a2dbc185 Bug fix: for archive and obsolescence flags: the parent class may be a pure PHP class. Use ParentPersisteClass instead.
SVN:trunk[4848]
2017-07-28 12:02:03 +00:00
Denis Flaven
015c5b7a96 Bug fix: protect the setup from a fatal exception when encountering a module with no version number.
SVN:trunk[4847]
2017-07-26 15:46:57 +00:00
Denis Flaven
4710ae6eb7 No change (just a comment for better typing return values)
SVN:trunk[4846]
2017-07-26 08:21:36 +00:00
Denis Flaven
c6b98dd5c1 Bug fix: do NOT scan the whole "data" directory searching for extensions !!
SVN:trunk[4845]
2017-07-26 08:19:13 +00:00
Denis Flaven
61d3a4e48f (FAF for module developers): utilities to easily know the name/version/dir/URL of the current module and write module independent code !!
SVN:trunk[4844]
2017-07-21 13:55:22 +00:00
Denis Flaven
be4c1e2c1c Bug fix: prevent a crash of the setup when there is no "extensions" directory at all.
SVN:trunk[4843]
2017-07-20 13:37:07 +00:00
Denis Flaven
6f499dd36e N°954: don't use the same (re)naming scheme, or risk a "cannot redeclare class" error.
SVN:trunk[4842]
2017-07-20 13:32:46 +00:00
Guillaume Lajarige
03661158f1 N°934 Hierarchy button was no longer working when editing external key
SVN:trunk[4841]
2017-07-19 14:20:12 +00:00
Romain Quetiez
b9866008b2 Impact analysis: better error report if the data model defines redundancy on a unidirectional relation (make it easier to troubleshoot for consultants)
SVN:trunk[4840]
2017-07-19 12:53:38 +00:00
Guillaume Lajarige
2557d6e7d5 N°706 DBCollation config parameter is no longer forced during setup. It was for migrating iTop 2.0 but is now obsolete.
SVN:trunk[4839]
2017-07-18 13:41:51 +00:00
Guillaume Lajarige
79582b55a4 N°579: Creating an object with the [+] button on external key pointing to an abstract class.
SVN:trunk[4838]
2017-07-18 13:37:29 +00:00
Romain Quetiez
46b5293867 N.542, N.912 Finalized the API UserRights::Impersonate. This is an enabler for several enhancements.
SVN:trunk[4837]
2017-07-18 09:36:25 +00:00
Guillaume Lajarige
54ca6ad3d9 Portal: Improved debug informations on error page
SVN:trunk[4836]
2017-07-14 19:24:36 +00:00
Guillaume Lajarige
2ab8161182 N°911 Portal: Autocomplete fields were not showing all items when result count was below autocomplete display limit (eg. Showing only 2 elements out of 18 when display limit set to 20)
SVN:trunk[4835]
2017-07-13 11:39:36 +00:00
Romain Quetiez
3c7f5db5e7 N890.6 Obsolescence: if the expression defining the flag is evaluated to null, then consider the object as being NOT obsoleted. The workaround implemented in the reference datamodel has been removed (no need to use COALESCE anymore).
SVN:trunk[4834]
2017-07-13 09:36:57 +00:00
Vincent Dumas
e72bc65df8 Set Module id 2.4 and XML version 1.4
SVN:trunk[4833]
2017-07-12 09:19:24 +00:00
Denis Flaven
c039414adc Don't add a question mark at the end of the setup's Iframe URL.
SVN:trunk[4832]
2017-07-12 08:51:34 +00:00
Romain Quetiez
d45cbb36f7 Regression introduced in the rework of N-N link edition. Parsing error on PHP 5.3
SVN:trunk[4831]
2017-07-11 15:11:46 +00:00
Romain Quetiez
ba5dd94240 Fixed a regression introduced by the new layout of forms in the console : notices issued on the transition form
SVN:trunk[4830]
2017-07-11 09:43:33 +00:00
Denis Flaven
fe84cbd978 Remove (once more...) a warning at the end of the setup...
SVN:trunk[4829]
2017-07-11 09:33:43 +00:00
Romain Quetiez
f8ddcc7b70 Releasing 2.4.0-beta
SVN:trunk[4828]
2017-07-11 08:27:51 +00:00
Vincent Dumas
c0d7737872 ReleaseNotes: rephrasing
SVN:trunk[4827]
2017-07-11 08:10:07 +00:00
Guillaume Lajarige
97e6c53add Portal: Some fields were no longer mandatory due to a regression introduced by the flags on lifecycle
SVN:trunk[4826]
2017-07-10 15:48:50 +00:00
Vincent Dumas
68ac5d7300 DataModel: Remove Ticket Archiving by default
SVN:trunk[4825]
2017-07-10 13:44:09 +00:00
Vincent Dumas
e0eebc0b4e ReleaseNote: 2.4. beta
SVN:trunk[4824]
2017-07-10 13:43:18 +00:00
Denis Flaven
fb28de971c Remove a warning at the end of the setup...
SVN:trunk[4823]
2017-07-10 13:23:03 +00:00
Guillaume Lajarige
ae637c7c96 Console UI: Fixed glitch in object details layout
SVN:trunk[4822]
2017-07-10 10:01:03 +00:00
Denis Flaven
6bc24b6064 File names are now purely reltive to the module's root directory.
SVN:trunk[4821]
2017-07-10 09:49:50 +00:00
Guillaume Lajarige
db60dfb707 Console UI: Text fields validation fixed when coming back from fullscreen. Also, fixed seaarch dialog UI for ExtKeys
SVN:trunk[4820]
2017-07-10 09:44:31 +00:00
Vincent Dumas
ee2aa67959 DataModel: Obsolescence conditions, workaround a code issue by using COALESCE when an obsolescence condition can be NULL.
SVN:trunk[4819]
2017-07-10 07:59:53 +00:00
Guillaume Lajarige
eff42f5d3b Console UI: OneWayPassword attribute are now displayed properly according to the new layout
SVN:trunk[4818]
2017-07-10 07:11:06 +00:00
Guillaume Lajarige
3a1810bc42 Console UI: Calendar icon for date(time) fields is now bigger.
SVN:trunk[4817]
2017-07-09 16:32:15 +00:00
Guillaume Lajarige
1f1ab2b10c N°930 Better UI on object details part 2: Text type fields now handled properly and aligned with HTML type fields.
SVN:trunk[4816]
2017-07-09 13:44:42 +00:00
Denis Flaven
d0d9b1ce50 Improved way to track the choices made during the installation in order to:
1) Be able to proerly report this information
2) Make sure that the same (proper) choices are proposed upon update

SVN:trunk[4815]
2017-07-07 16:00:30 +00:00
Guillaume Lajarige
307145502c N°930 Better UI on object details part 1. (Careful, Bulf modify and CSV import might be partly broken...)
SVN:trunk[4814]
2017-07-07 15:32:50 +00:00
Denis Flaven
5c84703cf0 Adding identifiers into the installation wizard.
SVN:trunk[4813]
2017-07-07 15:30:20 +00:00
Denis Flaven
cb2745be24 Bumping the datamodel version number to 2.4.0 !!
SVN:trunk[4812]
2017-07-07 15:28:42 +00:00
Denis Flaven
b613b9b302 Cosmetics on the asychronous DB connection message.
SVN:trunk[4811]
2017-07-07 15:27:32 +00:00
Denis Flaven
624f6bcfc5 Added a "Set" method.
SVN:trunk[4810]
2017-07-07 15:26:31 +00:00
Denis Flaven
ce2f1edaac Identify the menu nodes by an ID for potential CSS styling.
SVN:trunk[4809]
2017-07-07 15:24:14 +00:00
Denis Flaven
140efb4240 Split of a too long code line !!
SVN:trunk[4808]
2017-07-07 15:23:20 +00:00
Romain Quetiez
e3847ac24b Archive: Experimental API DBSearch::DBBulkWriteArchiveFlag, to quickly archive a huge number of objects (minimizes the number of queries needed to do the job, skips object change handlers, and DOES NOT RECORD the change in the history of object changes -that limitation could be fixed later)
SVN:trunk[4807]
2017-07-07 14:12:19 +00:00
Romain Quetiez
b583bd2edc N.612 Regression introduced in the previous commit: on the setup conclusion page, the link to download the backup file does not work (and warning "unknown variable $sTruncatedFilePath')
SVN:trunk[4806]
2017-07-07 09:30:52 +00:00
Vincent Dumas
c654a2067d Dictionnary: English: Labels on Modify AttributeDuration, aligned to display mode
SVN:trunk[4805]
2017-07-07 09:07:55 +00:00
Guillaume Lajarige
3531d5c5b7 Removed JS console.log usages that would have made IE9 crash
SVN:trunk[4804]
2017-07-06 15:55:02 +00:00
Romain Quetiez
e31fa066fc N.612 Backup files could not exceed 4Gb (technology limitation). The fix consists in archiving the backup as a tar.gz instead of a zip. As a consequence, installing iTop now requires TWO additional PHP modules: phar/zlib. The zip module remains mandatory because it is used in other places. The restore utility accepts both legacy zip files and brand new tar.gz files. DBBackup::CreateZip is deprecated in favor of DBBackup::CreateCompressedBackup. DBRestore::RestoreFromZip is deprecated in favor of DBRestore::RestoreFromCompressedFile (which autodetects the format for backward compatibility).
SVN:trunk[4803]
2017-07-06 15:26:03 +00:00
Vincent Dumas
bc476295cb DataModel: obsolescence conditions: Added: Contact, Location, Org. Modified: Hypervisor, Ticket
SVN:trunk[4802]
2017-07-06 14:54:20 +00:00
Vincent Dumas
98781fac6d DataModel: Ticket obsolescence condition: fix issue with 'rejected' UserRequest which have no 'close_date'
SVN:trunk[4801]
2017-07-06 10:08:06 +00:00
Vincent Dumas
efeee395d1 DataModel: Bug on LogicalInterface obsolescence condition, status does not exist
SVN:trunk[4800]
2017-07-06 10:06:04 +00:00
Denis Flaven
b17505f86e Larger area to be able to add an extra icon/menu if needed.
SVN:trunk[4799]
2017-07-05 15:17:16 +00:00
Vincent Dumas
f89dd77dbc DataModel: definition of obsolescence condition per class
SVN:trunk[4798]
2017-07-05 14:31:17 +00:00
Vincent Dumas
f8b6fb51c2 Ticket transitions: 'reassign' force change of agent, agent and team in 'assigned' state are read-only, user satisfaction and user comment are read-only in 'closed' state.
In Enhanced Portal: 're-open' prompt for caselog and 'on-going tickets' brick has a modified label (english and french) and ticket count is now displayed on each tab.

SVN:trunk[4797]
2017-07-04 15:50:20 +00:00
Guillaume Lajarige
d80c2293dc N°380 Fixed UI in console, object details that were going over their container sometimes
SVN:trunk[4796]
2017-07-04 11:58:40 +00:00
Guillaume Lajarige
3cecdeff1c N°380 Fixed object header width in console UI.
SVN:trunk[4795]
2017-07-04 08:32:14 +00:00
Romain Quetiez
3f819eaa19 N.656 Allow DB writes during a backup
SVN:trunk[4794]
2017-07-04 06:55:41 +00:00
Guillaume Lajarige
01de060093 N°642 Portal: Flags on transition, fixed a bug with state form not reading DM flags correctly.
SVN:trunk[4793]
2017-07-03 15:37:11 +00:00
Denis Flaven
7c39a8baf1 [CKEditor] Enabled the "Source mode edition" button, by popular demand. Be aware that the resulting HTML source is anyhow filtered/validated/sanitized by CKEditor itself, then iTop.
SVN:trunk[4792]
2017-07-03 15:17:39 +00:00
Denis Flaven
ebcaaa089a Updated CKEditor to the latest version (4.7.1)
SVN:trunk[4791]
2017-07-03 15:11:06 +00:00
Guillaume Lajarige
121635d636 N°642 Portal: Flags on transition part 3
SVN:trunk[4790]
2017-07-03 14:24:59 +00:00
Guillaume Lajarige
68885496dd N°642 Portal: Flags on transition part 3, forms inheritance for stimuli.
SVN:trunk[4789]
2017-07-03 10:25:49 +00:00
Guillaume Lajarige
9a56c3acfd N°642 Portal: Flags on transition part 2. Fixed a bug on transition with field that should have been must_xxx from DM
SVN:trunk[4788]
2017-07-03 07:33:46 +00:00
Guillaume Lajarige
a0259636b1 N°642 Portal: Flags on transition part 2
SVN:trunk[4787]
2017-07-03 06:57:36 +00:00
Romain Quetiez
0844beca79 Obsolescence: do not lose external keys pointing to obsolete data
SVN:trunk[4786]
2017-06-30 14:06:08 +00:00
Romain Quetiez
dbe3e94d5c Obsolescence: audit errors reporting to include obsolete data as well as the audit execution does
SVN:trunk[4785]
2017-06-30 13:25:02 +00:00
Vincent Dumas
9a43083b3b Fix typos in German dictionary for UI
SVN:trunk[4784]
2017-06-30 13:20:02 +00:00
Romain Quetiez
c6e472b98b Archive mode: user preference "show obsolete data" is automatically checked, and disabled
SVN:trunk[4783]
2017-06-30 12:59:28 +00:00
Romain Quetiez
0834e36b38 Archive: fix dashboard management (edition, revert, from file) when archive mode is on
SVN:trunk[4782]
2017-06-30 12:51:09 +00:00
Romain Quetiez
f7cf825975 Archive: fix shortcut creation/renaming/deletion when archive mode is on
SVN:trunk[4781]
2017-06-30 12:21:28 +00:00
Romain Quetiez
189c03dfea Obsolescence: count mismatch for the global search feature
SVN:trunk[4780]
2017-06-30 12:14:31 +00:00
Romain Quetiez
990be7a105 Archive mode: fixed the recording of user preferences
SVN:trunk[4779]
2017-06-30 10:00:38 +00:00
Romain Quetiez
813c80499c Archive: fixed regression on the exports (N.890.8)
SVN:trunk[4778]
2017-06-30 08:21:43 +00:00
Guillaume Lajarige
495cedc04f Fixed UI in console edit forms that were going over their container sometimes
SVN:trunk[4777]
2017-06-29 15:49:57 +00:00
Romain Quetiez
cbf2919dcd Obsolescence: fixed the case when an external field points to an external key that is obsoletable (or archivable), causing an error during the setup (view could not be created)
SVN:trunk[4776]
2017-06-29 15:17:17 +00:00
Guillaume Lajarige
7cbdfaa5d4 Restoring /log/.htaccess filename which was renamed by mistake.
SVN:trunk[4775]
2017-06-29 08:29:33 +00:00
Guillaume Lajarige
374ce20d0c N°642 Portal: Flags on transition
SVN:trunk[4774]
2017-06-29 08:03:35 +00:00
Romain Quetiez
1dbc2051cc Obsolescence: fixed regression introduces in [r4766], count of 1-N link sets not matching the result set
SVN:trunk[4773]
2017-06-28 08:52:30 +00:00
Romain Quetiez
7e38d4be50 Fixed Regression introduced with the rework of N-N links (bug when creating software instances on a server)
SVN:trunk[4772]
2017-06-27 14:18:28 +00:00
Romain Quetiez
8451ffdfb4 Regression introduced with the implementation of obsolescence: first install not working (Access denied for user ''@localhost)
SVN:trunk[4771]
2017-06-27 13:58:38 +00:00
Romain Quetiez
c2b9716e28 Obsolescence: fixed OQL issue
SVN:trunk[4770]
2017-06-27 12:37:07 +00:00
Guillaume Lajarige
b15621639b N°653: Dependant fields on transitions was not using transition flags.
SVN:trunk[4769]
2017-06-27 10:14:58 +00:00
Guillaume Lajarige
4ca998ce91 N°642 Portal: Transitions configuration part 1.
SVN:trunk[4768]
2017-06-26 16:00:07 +00:00
Guillaume Lajarige
71ec3da4ac N°653 Portal: Lifecycle: Flags on transitions part 2
SVN:trunk[4767]
2017-06-22 13:38:45 +00:00
Romain Quetiez
43b8522b85 Rework of the edition of 1-N and N-N links: managed as a delta from the GUI down to the the lowest APIs.
- Fixes the management of obsolete linked data.
- N.744 Fixes concurrent modifications (example: a user modifies a team, another user modifies a person related to that same team). Still NOT fixed with the customer portal.
- N.849 Fixes links edition in the case some data are not allowed to the current user (organization silos) -TO BE TESTED
- #1145 Fixes the creation of duplicate links in one step (Server to NW Device)
- #1147 Fixes the update of duplicate links

SVN:trunk[4766]
2017-06-21 15:47:28 +00:00
Guillaume Lajarige
8b820ce403 N°900 Portal: Fixed wrong count on ManageBrick tabs
SVN:trunk[4765]
2017-06-20 15:28:31 +00:00
Guillaume Lajarige
4301a5d39d Portal: Fixed page scrolling when clicking on FilterBrick's tile on home page.
SVN:trunk[4764]
2017-06-20 14:22:18 +00:00
Guillaume Lajarige
51519a3659 Portal: Added TWIG hooks for logo overloading in the navigation menu.
SVN:trunk[4763]
2017-06-20 09:54:02 +00:00
Romain Quetiez
2693e81bad XML Customizations: when the parent class is unknown, the error is "unknown constant PARENT_NOT_FOUND"... which is a clue ;-)... now it says something far more accurate like "/itop_design/classes/class[MyCustomClass] at line 458: parent class 'SomeOtherCustomClass' could not be found"
SVN:trunk[4762]
2017-06-14 15:14:49 +00:00
Guillaume Lajarige
eca746f558 N°653 Ticket Lifecycle: Part 2, core & console done.
SVN:trunk[4761]
2017-06-09 07:06:40 +00:00
Denis Flaven
01865ed7f9 More meaningful default values for the version/revision of iTop.
SVN:trunk[4760]
2017-06-08 13:57:05 +00:00
Denis Flaven
14dfe04714 Instrumentation of the setup/compiler: dump the complete XML data model at the end of the installation.
SVN:trunk[4759]
2017-06-08 13:56:14 +00:00
Guillaume Lajarige
befa0b4429 N°900 Portal: Tabs in ManageBrick can now display the objects count.
SVN:trunk[4758]
2017-06-07 14:13:02 +00:00
Denis Flaven
68ff589f9c (refactoring) Generate database and "instance" UUIDs upon installation/upgrade.
SVN:trunk[4757]
2017-06-06 14:00:10 +00:00
Denis Flaven
04e1f32860 (refactoring) Added a method to generate UUIDs.
SVN:trunk[4756]
2017-06-06 13:59:01 +00:00
Romain Quetiez
636356f479 N.897 Object having too many external keys could not be recorded (61 tables)
SVN:trunk[4755]
2017-06-01 12:44:21 +00:00
Guillaume Lajarige
313ea72017 Portal: Added icons to error page buttons
SVN:trunk[4754]
2017-05-31 09:01:02 +00:00
Guillaume Lajarige
98b4a0178f Portal: Added a "Reload page" button on the error page.
SVN:trunk[4753]
2017-05-31 08:55:48 +00:00
Guillaume Lajarige
602be73d0b N°873 Portal: Picture/Preferences/Password forms can now be disabled in the user profile
SVN:trunk[4752]
2017-05-29 16:14:21 +00:00
Guillaume Lajarige
9bfc9a0a76 Portal: New customization hooks in user profile twig
SVN:trunk[4751]
2017-05-29 15:10:35 +00:00
Guillaume Lajarige
7e6a040983 Portal: User profile form was broken due to new display_mode property
SVN:trunk[4750]
2017-05-29 14:50:57 +00:00
Guillaume Lajarige
905d47cab5 Portal: CKEditor fields now have different height regarding the form layout (cosy, compact, dense)
SVN:trunk[4749]
2017-05-23 13:15:22 +00:00
Romain Quetiez
2118a5da71 N.667 Metamodel introspection (schema.php) to display lifecycle labels and codes (though the code were already visible in a tooltip).
SVN:trunk[4748]
2017-05-22 15:35:16 +00:00
Romain Quetiez
c2c0221535 N.542 Refactored the code so that query placeholders (current_contact->attcode or current_user->attcode) become available in template too.... BUT this will not work if the notifications are sent asynchronously (thus the logged in user is an account dedicated to the cron).
SVN:trunk[4747]
2017-05-22 14:57:03 +00:00
Romain Quetiez
ba0a9709f4 Test: fixed automated tests that were abusively failing due to a few new magic attributes
SVN:trunk[4746]
2017-05-22 14:04:50 +00:00
Romain Quetiez
80121b89c3 Obsolescence: background task setting (or resetting) the obsolescence date for obsolete data. The periodicity can be tuned by the mean of obsolescence.date_update_interval, defaulting to 10 minutes. Also renamed show_obsolete_data into obsolescence.show_obsolete_data for consistency.
SVN:trunk[4745]
2017-05-19 09:20:13 +00:00
Romain Quetiez
3b48428897 Internal: DBObjectSearch->AddCondition, allow the case $value = null (otherwise failing because the keyword null has not yet been implemented in OQL)
SVN:trunk[4744]
2017-05-19 09:15:22 +00:00
Guillaume Lajarige
018d6a98e9 Portal: Debug mode now logs external keys OQL queries used in forms. Helpful to understand the final query (DM OQL intersect Scope OQL)
SVN:trunk[4743]
2017-05-19 08:51:59 +00:00
Guillaume Lajarige
522108dc69 N°879 Portal: Notification URLs poiting to a portal were not working when several portal instances were configured.
SVN:trunk[4742]
2017-05-19 08:30:34 +00:00
Romain Quetiez
5451ced894 Obsolescence: hide rows for which any of the selected class is obsolete (SELECT a, b FROM ...)
SVN:trunk[4741]
2017-05-17 13:22:56 +00:00
Romain Quetiez
944c24e18f Internal: document variables to ease code browsing
SVN:trunk[4740]
2017-05-17 13:21:09 +00:00
Romain Quetiez
248f8d6fd4 Obsolescence: finalizing the implementation of the flag (hide obsolete objects, show an icon on hyperlinks and a tag on the object details, user preference defaulting to the new setting 'show_obsolete_data')
SVN:trunk[4739]
2017-05-17 08:51:10 +00:00
Guillaume Lajarige
ebe467b77a N°635 Portal: Final touches on forms layout refactoring
SVN:trunk[4738]
2017-05-16 14:50:51 +00:00
Guillaume Lajarige
e9b7ccd475 Advanced customization: New overridable verb DBObject::GetDefaultValue($sAttCode)
SVN:trunk[4737]
2017-05-16 09:50:24 +00:00
Guillaume Lajarige
b213f2baea N°635 Portal: Forms now have 3 differents layout (display_mode), see online documentation (when released) for more information.
SVN:trunk[4736]
2017-05-15 15:50:12 +00:00
Guillaume Lajarige
50970810d2 N°635 Portal: Forms now have 2 differents layout (display_mode), see online documentation (when released) for more information.
Note: This is a first step, some refactoring could be done soon.

SVN:trunk[4735]
2017-05-15 12:50:09 +00:00
Guillaume Lajarige
17fbc504e2 Internal: Added some PHP Doc in MetaModel class
SVN:trunk[4734]
2017-05-15 12:42:14 +00:00
Guillaume Lajarige
237980097d Portal: Form field with custom css classes in twig definition were not included in the form. (Note: The CSS class is still absent from the rendering but this is because of the field_set.js widget that needs some upgrade in the _prepareField method)
SVN:trunk[4733]
2017-05-12 12:58:05 +00:00
Romain Quetiez
44b53e40a0 Obsolescence: introduction of this new concept (wording could change later). The obsolescence of an object is computed after other attributes, by the mean of an OQL expression. The code has been refactored (again) so as to factorize between the computation of friendly names and the computation of obsolescence flags. The refactoring involved a significant AND RISKY change: external key friendly names (magic attributes) have been changed from AttributeFriendlyName to AttributeExternalField, which simplifies the SQL query build logic.
SVN:trunk[4732]
2017-05-11 11:58:42 +00:00
Guillaume Lajarige
6c6ad0a45b Portal: Fixed a regression introduced in r4724. User profile page could not be opened anymore.
SVN:trunk[4731]
2017-05-11 08:36:22 +00:00
Guillaume Lajarige
623fa8ec63 Portal: Fixed regression on always_show_submit form option
SVN:trunk[4730]
2017-05-10 15:48:57 +00:00
Guillaume Lajarige
02c79fd0a2 Portal: BrowseBrick: First level automatically opens when there is only one item in it, in order to display its subitems.
The opening of the root level is visible by the user so he can understand he is in a sublevel, not wondering where the root level went.

SVN:trunk[4729]
2017-05-10 15:22:13 +00:00
Guillaume Lajarige
05bb797768 Portal: Renamed Grid browse mode to Mosaic
SVN:trunk[4728]
2017-05-10 15:02:23 +00:00
Guillaume Lajarige
096cfdc529 Portal: BrowseBrick: Primary action is now also displayed in the secondary actions menu
SVN:trunk[4727]
2017-05-10 14:44:15 +00:00
Romain Quetiez
5354b0b32b Internal: getting rid of the unused API GetExtKeyFriends, which initialization was not compatible with the declaration of <extkey>_friendlyname as external fields
SVN:trunk[4726]
2017-05-10 14:34:40 +00:00
Guillaume Lajarige
88ec528071 N°635 Portal: Submit button in edit forms is now labelled "Update"
SVN:trunk[4725]
2017-05-10 14:33:44 +00:00
Guillaume Lajarige
5584d42813 N°635 Portal: Parameter to show submit ("Update") button in forms only when there is no transition available.
SVN:trunk[4724]
2017-05-10 14:28:07 +00:00
Vincent Dumas
b696b140b2 Fix typo in french label of lnkContractToDocument class name
SVN:trunk[4723]
2017-05-09 16:34:03 +00:00
Guillaume Lajarige
1de6ac1765 Portal: AttributeImage can now be displayed in forms
SVN:trunk[4722]
2017-05-09 12:27:25 +00:00
Romain Quetiez
d2d895fdf5 Archives: regression. Forms not working with various symptom having the same root cause: DBObject::Set issuing an exception "Attempting to set the value on the read-only attribute operational_status"
SVN:trunk[4721]
2017-05-09 12:07:43 +00:00
Romain Quetiez
a8ad3004ea Internal:
- code refactoring to generalize attributes based on an OQL expression (friendly name, obsolescence flag, ....). The intermediate class AttributeComputedFieldVoid has been swept in favor of the use of a new method: IsBasedOnOQLExpresssion.
- added an introspection API (experimental), allowing an external application to request for information about the capabilities of the framework (first step: list attributes and their main characteristics)

SVN:trunk[4720]
2017-05-05 15:08:49 +00:00
Guillaume Lajarige
b707db9364 Portal: Fixed action rules that were not working on CreateBrick
SVN:trunk[4719]
2017-05-03 14:29:48 +00:00
Guillaume Lajarige
36c53249a0 Portal: Performance optimization on ManageBrick
SVN:trunk[4718]
2017-05-03 12:39:25 +00:00
Guillaume Lajarige
f9ed88a084 Internal: OQL error reporting
SVN:trunk[4717]
2017-05-02 09:11:00 +00:00
Romain Quetiez
294964b227 N.858 (partial) Allow administrators to access the Admin tools menu even in Read-only modes (access_mode or Archive mode). Still, the Data administration menu gets hidden in Read-only modes.
SVN:trunk[4716]
2017-04-28 14:11:00 +00:00
Guillaume Lajarige
8a6fba1981 Portal: SecurityHelper now uses a cache when checking if an object is within a scope or not.
SVN:trunk[4715]
2017-04-28 09:46:05 +00:00
Guillaume Lajarige
1fe0ce5640 Portal: Optimize security helper by removing unnecessary MetaModel::GetObject() call as the check was already done by the scope query. This as significative impact on some pages.
SVN:trunk[4714]
2017-04-28 08:31:30 +00:00
Guillaume Lajarige
7bbe907edc Portal: ManageBrick optimization by loading "always_in_tables" attributes to avoid unnecessary object reloads
SVN:trunk[4713]
2017-04-28 08:20:21 +00:00
Romain Quetiez
6f7d364826 Cleanup: removed unnecessary code
SVN:trunk[4712]
2017-04-27 16:03:23 +00:00
Romain Quetiez
ea2681e08c Archives: added the option with_archive to export web services (defaults to 0)
SVN:trunk[4711]
2017-04-27 15:03:24 +00:00
Romain Quetiez
c66728e478 Cleanup: unused code
SVN:trunk[4710]
2017-04-27 14:02:02 +00:00
Guillaume Lajarige
ba9c6bd8b3 Portal: Twig cache is now disabled when debug option is activated
SVN:trunk[4709]
2017-04-27 13:30:54 +00:00
Romain Quetiez
b23b468c0f Cleanup: unused code
SVN:trunk[4708]
2017-04-27 12:54:18 +00:00
Romain Quetiez
f5144c2bb1 Archives: filter out archived objects from the impact analysis, even when in Archive Mode
SVN:trunk[4707]
2017-04-27 12:42:50 +00:00
Guillaume Lajarige
ee95dd2480 Portal: Worked on some CSS optimizations in forms
SVN:trunk[4706]
2017-04-27 11:40:05 +00:00
Guillaume Lajarige
c1805ce47f Portal: Person form defined in order to restrict the visible attributes
SVN:trunk[4705]
2017-04-27 11:39:05 +00:00
Romain Quetiez
23556e3a43 Archives: clean breadcrumb entry if attempting to navigate to the details of an archived object (while not being in archive mode)
SVN:trunk[4704]
2017-04-27 09:56:05 +00:00
Romain Quetiez
e70e1de75e Archives: archivability must be set on root classes
SVN:trunk[4703]
2017-04-27 09:27:02 +00:00
Romain Quetiez
091b989715 Internal: if an exception is thrown during the initialization of MetaModel, do not attempt to report it into the database (may still be not initialized)
SVN:trunk[4702]
2017-04-27 09:17:39 +00:00
Romain Quetiez
b238283104 Archives: show the menu 'activate archive mode' only if there is at least one archivable class
SVN:trunk[4701]
2017-04-27 08:53:23 +00:00
Romain Quetiez
de2eed5187 Archives: allow for the update of archive_flag even when in archive mode (therefore in read-only mode)
SVN:trunk[4700]
2017-04-27 08:45:07 +00:00
Romain Quetiez
8e046cafda Archives: default label for the magic attributes archive_flag and archive_date
SVN:trunk[4699]
2017-04-27 08:43:45 +00:00
Guillaume Lajarige
f02df401ff Portal: Primary action on a ServiceSubcategory of the services catalog is now the creation of a new UserRequest. Previous one (Viewing details of the ServiceSubcategory) now becomes the secondary action.
SVN:trunk[4698]
2017-04-27 08:23:53 +00:00
Romain Quetiez
28eba2512a Archives: cosmetics on object details
SVN:trunk[4697]
2017-04-26 15:48:57 +00:00
Romain Quetiez
e3931274ae Archives: refactoring of the API to enable/disable the archive mode
SVN:trunk[4696]
2017-04-26 15:48:24 +00:00
Guillaume Lajarige
a55245d203 Portal: Minor CSS fixes on Combodo BS theme.
SVN:trunk[4695]
2017-04-26 14:54:24 +00:00
Guillaume Lajarige
7b0acbdad3 Portal: BrowseBrick: Introducing new browse mode "grid". Also some UI improvements in other browse modes.
SVN:trunk[4694]
2017-04-26 13:20:31 +00:00
Romain Quetiez
9cc583c47b Archives: regression (warning during the setup)
SVN:trunk[4693]
2017-04-26 10:27:25 +00:00
Romain Quetiez
fa2fd6dcdf NEW! Archiving data. Archiving is a soft delete. It can be undone. Enter the archive mode to see all the data including archives (everything is read-only in that mode). Archiving must be enabled per class (data model). Archiving is achieved by the mean of the API DBObject::Archive (or Unarchive).
SVN:trunk[4692]
2017-04-26 09:52:20 +00:00
Guillaume Lajarige
9d242e1623 N°848 Portal: Option to display LinkedSet as opened in a form
SVN:trunk[4691]
2017-04-26 09:10:24 +00:00
Romain Quetiez
ec6a8537e9 Refactoring: font awesome can be used by all the application
SVN:trunk[4690]
2017-04-25 13:48:22 +00:00
Romain Quetiez
402e95b9e2 Reincorporate font-awesome into the core
SVN:trunk[4689]
2017-04-25 13:24:37 +00:00
Guillaume Lajarige
2fcf50bb88 N°653 Lifecycle flags can be defined on both states and transitions (Note: This is a beta version and need to be tested!)
SVN:trunk[4688]
2017-04-21 14:59:04 +00:00
Guillaume Lajarige
2e8c629195 N°829 Portal: AttributeUrl was not clickable in the new portal
SVN:trunk[4686]
2017-04-19 15:36:00 +00:00
Guillaume Lajarige
9c5b3818eb Portal: Refactor a security check to remove unnecessary security messages in error.log
SVN:trunk[4684]
2017-04-18 13:51:25 +00:00
Denis Flaven
c9bb27a3ff Declare the ApplyStimulus method, for use by the Designer.
SVN:trunk[4683]
2017-04-18 13:29:46 +00:00
Vincent Dumas
f96a2092e7 Readme iTop Community 2.3.4
SVN:trunk[4681]
2017-04-14 15:34:07 +00:00
Vincent Dumas
5dafb92dd3 LOCK TABLE MySQL privilege is required for iTop user to restore backups.
SVN:trunk[4679]
2017-04-13 09:46:07 +00:00
Guillaume Lajarige
63f0a0ef11 Internal: Added comment about portal logo priority order
SVN:trunk[4678]
2017-04-12 07:50:45 +00:00
Romain Quetiez
bb9236deae N.816 New parameter in the working time computer GetDeadline API: the 4th parameter is the threshold for which the deadline is being computed.
SVN:trunk[4675]
2017-04-06 19:07:08 +00:00
Romain Quetiez
1a66a6491a N.755 Case log preset by object copier is not correcly displayed in the object creation form (if combined with the copy of the previous log AND if that log has at least one entry). Has never worked.
SVN:trunk[4672]
2017-04-06 18:44:34 +00:00
Guillaume Lajarige
1528d85f5f N°637 Portal: Better feedback on exceptions and user session timeout on AJAX calls
SVN:trunk[4671]
2017-04-06 14:21:27 +00:00
Romain Quetiez
3773a88cc1 N.417 Object name displayed with html entities (e.g. "&" shown as "&amp;") when selecting/creating an object into an autocomplete
SVN:trunk[4670]
2017-04-05 14:39:13 +00:00
Romain Quetiez
856a73fb87 N.689 61 tables limit. INVESTIGATING the issue. Added a test to reproduce the issue on the standard data model, and a test to build statistics on the number of tables used by classes.
SVN:trunk[4669]
2017-04-05 12:58:33 +00:00
Romain Quetiez
d0bc9a0bb8 Automatic test suite: fixed warnings (benchmarked queries processed instantaneously);
SVN:trunk[4668]
2017-04-05 10:26:43 +00:00
Romain Quetiez
751b7c8560 N.755 Case log latest entry preset with a copy of a case log coming from another ticket. The log gets corrupted after adding a new entry.
SVN:trunk[4666]
2017-04-04 12:58:02 +00:00
Guillaume Lajarige
4fccae157b Portal: CaseLog fields value was kept in the form after object update instead of being reset.
SVN:trunk[4664]
2017-04-04 10:17:17 +00:00
Romain Quetiez
85dc7c9452 N.755 Case log latest entry preset with HTML code gets transformed into pure text
SVN:trunk[4662]
2017-04-04 09:25:02 +00:00
Guillaume Lajarige
1cf25e49ae N°807 Portal: add_to_list can now be used in action rules (Note: Works only for IndirectLinkedSet, not LinkedSet)
SVN:trunk[4660]
2017-04-04 09:07:06 +00:00
Guillaume Lajarige
ab6cd49fcb Portal: Fixed friendlyname fields rendered as mandatory when they should have been readonly.
SVN:trunk[4658]
2017-04-04 08:01:47 +00:00
Romain Quetiez
5411e60c81 N.755 (reduces the impact) Core API: Fixed the merging of several entries into a case log (calling several times DBObject::Set for a case log). The previous implementation did not work at all, leaving the data structure inconsistent. Moreover, the last text given is now inserted AFTER the text it is merged with (not on top of it) like in a normal text stream.
SVN:trunk[4657]
2017-04-03 20:56:47 +00:00
Denis Flaven
15da430459 N°686 - protect the edition of dashboards against a no-longer-existing class.
SVN:trunk[4655]
2017-04-03 14:49:49 +00:00
Romain Quetiez
5adb0fd556 N.447 Impact analysis: messing up redundancy settings (could either lead to wrong results or a fatal error if a relation is configured downstream)
SVN:trunk[4653]
2017-04-03 13:59:06 +00:00
Guillaume Lajarige
2876d7e08c N°806 Portal: Wrong form used in some inheritance cases.
SVN:trunk[4651]
2017-04-03 11:57:29 +00:00
Romain Quetiez
59c3f565a3 Fixes a regression introduced in [r4642]. N.450 Impact analysis. The previous fix aimed at generating more redundancy nodes, but in fact it generated too many in some circumstances.
SVN:trunk[4649]
2017-04-01 20:05:14 +00:00
Guillaume Lajarige
86191b36d8 DBObject::ExecActions : add_to_list action now accepts the source object id as first parameter
SVN:trunk[4647]
2017-03-31 15:18:50 +00:00
Vincent Dumas
b737252076 n°519 add examples to REST/JSON on updating CaseLog with Text format
SVN:trunk[4646]
2017-03-31 15:17:23 +00:00
Romain Quetiez
e688d04511 N.788 Impact analysis: graph not refreshed when trying to filter out some classes. The node removal algorithm has been improved in two places. 1) Do not create loops (i.e. an edge having both ends on the same node) when removing a node. 2) Correctly cleanup nodes having a loop (in case there is a loop in the original graph (defensive programming)
SVN:trunk[4644]
2017-03-31 14:48:30 +00:00
Romain Quetiez
76fd5c0b5f N.450 Impact analysis : missing edges (and redundancy) when two classes impact a given class and both relations use the same neighbour id (and if redundancy is enabled over both relations)
SVN:trunk[4642]
2017-03-31 14:34:43 +00:00
Guillaume Lajarige
d944f386ce N°800 Portal: log_kpi_duration / log_kpi_memory are now supported by the portal
SVN:trunk[4640]
2017-03-31 12:59:35 +00:00
Guillaume Lajarige
9f9fd8550f N°804 Portal: Object display crashed when a linkedset attribute has corrupted data (eg. an external key to 0)
SVN:trunk[4638]
2017-03-31 10:09:51 +00:00
Romain Quetiez
772954711a N.799 Setup failing (during database creation) with MetaEnum attribute having no mapping for the class they are declared in.
SVN:trunk[4636]
2017-03-30 19:23:43 +00:00
Romain Quetiez
3644553886 N.609 Some multi-column UNION queries failing with various symptoms such as "Class 'IT Department' not found" or "An object id must be an integer value"
SVN:trunk[4634]
2017-03-29 19:58:02 +00:00
Romain Quetiez
c073611597 N.710 Do not notify ignored when the impacted items is computed again. Side effect: PHP Notice: Undefined offset: N in .../itop-tickets/main.itop-tickets.php on line 263.
SVN:trunk[4632]
2017-03-29 10:02:14 +00:00
Romain Quetiez
802d20d554 N.780 Friendly name format ignored if only one attribute is used
SVN:trunk[4630]
2017-03-29 09:22:39 +00:00
Romain Quetiez
38c12104b3 N.740 Error when attempting to disable the logs. Took the opportunity to refactor, relying on late static bindings (requires PHP 5.3). The refactoring avoided the fix to be duplicated in three places.
SVN:trunk[4628]
2017-03-29 08:28:24 +00:00
Romain Quetiez
399662ef99 N.701 (continuation of [r4596] which introduced regressions on the handling of date fields)
SVN:trunk[4626]
2017-03-28 14:56:52 +00:00
Denis Flaven
3daf4c62db - Refactoring : structuration of the Exceptions thrown when the XML assembling fails
- Take into account the node specified as a parameter to saveXML()

SVN:trunk[4624]
2017-03-27 16:24:50 +00:00
Guillaume Lajarige
9937f62f9d N°641 Portal: Browse and Manage bricks now have an optional <opening_target> tag to choose how to open items (modal, new tab, current window).
SVN:trunk[4623]
2017-03-24 09:09:15 +00:00
Romain Quetiez
cf17e197ce N.760 XSS vulnerability
SVN:trunk[4621]
2017-03-23 16:32:56 +00:00
Romain Quetiez
2f8b5e5eeb N.519 REST/JSON Add a comment in pure text into the case log (only for add_item/items syntaxes, use format="text")
SVN:trunk[4619]
2017-03-23 15:16:30 +00:00
Romain Quetiez
d22fb83443 N.736 Ugly labels when hovering bar charts
SVN:trunk[4617]
2017-03-23 14:52:57 +00:00
Romain Quetiez
af093ba86a N.692 Config setting log_queries does not work? This setting has been deprecated (use log_kpi_duration instead) - Still the implementation of query logging remains (and is buggy) as it may be usefull in order to record and rebuild a complete set of queries.
SVN:trunk[4615]
2017-03-23 09:09:45 +00:00
Romain Quetiez
020f47ab2c Code cleanup: removed unused code
SVN:trunk[4614]
2017-03-22 21:24:50 +00:00
Romain Quetiez
8f0095f751 N.718 (continuation) Audit failing with message "Attempting to merge a filter of class A with a filter of class B" (regression introduced in branch 2.3)....
SVN:trunk[4612]
2017-03-22 20:59:33 +00:00
Romain Quetiez
b7fc2e4012 N.718 Audit failing with message "Attempting to merge a filter of class A with a filter of class B" (regression introduced in branch 2.3). There are circumstances for which the queries cannot (yet) be optimized (fallback to the original algorithm)
SVN:trunk[4611]
2017-03-22 20:53:40 +00:00
Guillaume Lajarige
1dcf830141 N°783 Attachments can now be readonly in some states. Use the new module parameter "readonly_states".
SVN:trunk[4610]
2017-03-22 15:08:34 +00:00
Romain Quetiez
a10cdaba74 N.779 PARTIAL FIX - Date fields in link sets cannot be edited if the date format differs from the native format (Y-m-d). Homogeneous way to call the API GetFormElementForField, with GetEditValue as the "display value". Still, submitting the form does not work.
SVN:trunk[4609]
2017-03-22 13:39:48 +00:00
Romain Quetiez
435a177283 Suppressed warnings due to the error reporting. When one of the arguments in the call stack is an array, a warning (Conversion of an array into a string) is issued at the time the EventIssue is being recorded. When a posted parameter is an array, the same warning is issued at the time and EventIssue is being displayed.
SVN:trunk[4608]
2017-03-22 12:43:12 +00:00
Vincent Dumas
d22d657886 #1439 fix erroneous internal comments within XML files
SVN:trunk[4607]
2017-03-21 17:35:38 +00:00
Guillaume Lajarige
1da5618204 N°606 Portal: Request template fields marked as invalid when a mandatory textarea field was empty.
SVN:trunk[4605]
2017-03-21 09:53:57 +00:00
Vincent Dumas
318c069f3d Corrigé une typo dans un dictionnaire français
SVN:trunk[4604]
2017-03-17 13:32:30 +00:00
Denis Flaven
d0267f60ae Make sure that the generated form field's IDs are valid ones.
SVN:trunk[4602]
2017-03-17 13:20:01 +00:00
Denis Flaven
ea3c7703c4 XML format 1.4, introducing the new "force" flag.
SVN:trunk[4601]
2017-03-17 13:15:13 +00:00
Guillaume Lajarige
95e04178ea N°636 Portal: Action buttons can now be added to object details page through the iPopupMenuItemExtension
SVN:trunk[4600]
2017-03-17 13:03:09 +00:00
Denis Flaven
cf0792cd64 More events from the property_field widgets to inform the enclosing form of the state changes.
SVN:trunk[4598]
2017-03-17 10:55:06 +00:00
Romain Quetiez
e41a8833e2 N.701 Data Synchro: dates can be reset by the mean of an empty string (still, integers and enums cannot be reset)
SVN:trunk[4596]
2017-03-17 09:14:11 +00:00
Romain Quetiez
0b2ce4289d 738 Setup not working if access_mode=2 and a synchro data source has a new attribute to create
SVN:trunk[4594]
2017-03-16 15:22:19 +00:00
Guillaume Lajarige
a13270ef91 N°772 Portal: Invalid URL in LinkedSet searchbox when editing an object (eg. Adding a Contact to an UserRequest)
SVN:trunk[4592]
2017-03-16 13:14:45 +00:00
Guillaume Lajarige
64ca121f5b Portal: Used BS breadcrumb in BrowseBrick instead of the previous which was home-made.
SVN:trunk[4591]
2017-03-15 17:03:32 +00:00
Romain Quetiez
0a5708272d N.678 Data synchro: a line break or '<' in the description breaks the synchronized objects edition form.
SVN:trunk[4589]
2017-03-15 14:41:12 +00:00
Guillaume Lajarige
fec15ffe66 Portal: FilterBrick: Value for placeholder and submit button can now be empty
SVN:trunk[4588]
2017-03-14 16:09:13 +00:00
Guillaume Lajarige
0b0340bf21 Internal: CSS optimization on portal BrowseBrick
SVN:trunk[4587]
2017-03-14 15:42:29 +00:00
Romain Quetiez
cf716ce2a3 N.598 Custom fields with autocomplete failing if the subfield depends on another subfield
SVN:trunk[4585]
2017-03-14 15:20:50 +00:00
Guillaume Lajarige
5ebcb41224 Portal: Added breadcrumbs to grid mode of the BrowseBrick
SVN:trunk[4584]
2017-03-14 13:59:05 +00:00
Romain Quetiez
2d9c0e16b9 N.569 Enable the browser built-in spell checker for the rich text editor
SVN:trunk[4582]
2017-03-14 13:42:20 +00:00
Romain Quetiez
20e0ab3d6e N.453 Emails coming from outlook. Many line breaks added when editing the ticket
SVN:trunk[4580]
2017-03-14 13:16:42 +00:00
Vincent Dumas
d94ccc441a N°675 enriched Dutch Dictionnaries for Enhanced portal
SVN:trunk[4579]
2017-03-14 09:49:58 +00:00
Vincent Dumas
fdff9e048b N°759 French Dictionnary typo on closed ticket value
SVN:trunk[4578]
2017-03-13 17:29:31 +00:00
Vincent Dumas
64e1d7e276 Problem management: german translations on values for field 'impact' were upside down compared to english values. Value 1 means high impact in all langage but German where is was 'Eine Person'. German has been aligned. German users, be cautious when upgrading to migrate your data.
SVN:trunk[4577]
2017-03-13 17:19:32 +00:00
Vincent Dumas
5f82c78dc7 #1314 (N°585,586,591) allow to use finalclass (sub-class name) as reconciliation key when loading by CSV import, relationship defined on an abstract class.
#1387 (N°577) fixing old issue with CSV import of relationship with Documents

SVN:trunk[4576]
2017-03-13 16:56:03 +00:00
Guillaume Lajarige
b3a0c6119e N°762: Portal: New filter brick that pre-filters a Browse or Manage brick results from the home page.
SVN:trunk[4575]
2017-03-13 14:06:43 +00:00
Romain Quetiez
342ac0444c N.757 Server log filled with warnings (ContextTag::Check)
SVN:trunk[4573]
2017-03-10 14:32:32 +00:00
Vincent Dumas
d9469360fe N°582 Typo on french user message used when changing user password
SVN:trunk[4572]
2017-03-09 10:41:37 +00:00
Vincent Dumas
0df420cd17 N°723 help message enhancement on 4th setup screen, about MySQL user required rights.
SVN:trunk[4571]
2017-03-08 14:16:29 +00:00
Guillaume Lajarige
ab44522016 N°636: Portal: Dictionnary entries can now be used in forms' twig (usage: {{'EntryToTranslate'|dict_s}}). Also, special characters (like 'é') are now supported.
SVN:trunk[4570]
2017-03-08 09:58:12 +00:00
Guillaume Lajarige
bc875653d2 Internal: Portal: Grid display optimization on BrowseBrick
SVN:trunk[4569]
2017-03-07 16:23:48 +00:00
Guillaume Lajarige
ee41204d6c N°565: Portal user and Portal power user scopes alignment in "Closed tickets" brick.
SVN:trunk[4568]
2017-03-07 14:53:57 +00:00
Guillaume Lajarige
c4d1113bb8 N°634: BrowseBrick Windows 8-style display (tiles). This is still a beta version.
SVN:trunk[4567]
2017-03-07 14:25:09 +00:00
Guillaume Lajarige
6582569150 Portal: Fixed home page <body> CSS class
SVN:trunk[4566]
2017-03-03 14:33:42 +00:00
Guillaume Lajarige
69d0ceaf5b Portal: Added CSS classes to <body> tag regarding the current page / brick so we can apply CSS style more precisely.
SVN:trunk[4565]
2017-03-03 13:09:08 +00:00
Denis Flaven
60165d5216 Bug fix: load modules before generating the WSDL file, since some modules may come with their own webservices.
SVN:trunk[4563]
2017-02-28 14:10:11 +00:00
Guillaume Lajarige
76ca7dc9e8 N°602: InlineImage "randomly" not available for display.
Adding an InlineImage while adding an object in a IndirectLinkedSet at the same time would attach the InlineImage to the linked object instead of the host one. If their organizations were different, it could result in a security issue, denying the display of the InlineImage.

SVN:trunk[4561]
2017-02-28 09:47:24 +00:00
Denis Flaven
fcc5342775 Bug fix: protect against a non existing Contact class (a rather drastic iTop customization!)
SVN:trunk[4559]
2017-02-24 14:09:44 +00:00
Guillaume Lajarige
b4534f455a Internal: Fixed the usage of a private function (from Symfony ExceptionHandler) in a derivated class (iTop ExceptionHandler).
SVN:trunk[4558]
2017-02-23 10:49:16 +00:00
Guillaume Lajarige
0d3203476c N°589 - Portal: Displaying a better error message when the portal crashes because the current contact's organization is not among the current user's allowed organizations. More over we introduced an exception handler to display a nicer web page and log the exception in the error log.
SVN:trunk[4557]
2017-02-23 10:07:12 +00:00
Guillaume Lajarige
9fa6157c37 N°587 - Portal: Fixed issue when using multiple action rules in a BrowseBrick and only one was actually used.
SVN:trunk[4556]
2017-02-21 14:26:07 +00:00
Guillaume Lajarige
2ee674f11b N°620 - Fixed regression introduced in r4519: Portal: Url in notifications were broken since iTop 2.3.3.
SVN:trunk[4554]
2017-02-21 09:06:03 +00:00
Guillaume Lajarige
820d7108e4 N°633 - Portal: CreateBrick now accepts abstract classes. This is a refactoring from an extension (CreateBrickExtended) that has been merge into the core.
SVN:trunk[4553]
2017-02-21 08:10:47 +00:00
Guillaume Lajarige
9a6a562ed2 N°619 - Portal: Other allowed portals (eg. the administration console or other portal instances) can now be opened in the current window or a new tab. This is a new xml property of the portal instance.
SVN:trunk[4552]
2017-02-21 08:04:46 +00:00
Guillaume Lajarige
f3f9e98aa4 Portal: Added some hooks in the main twig template
SVN:trunk[4551]
2017-02-10 10:06:38 +00:00
Denis Flaven
fc375da128 N° 615: spreadsheet export enhancement to remove unneeded line breaks.
SVN:trunk[4549]
2017-01-31 13:26:12 +00:00
Denis Flaven
172ceba464 N° 615: fixing the spreadsheet export (for integration into Excel) for HTML formatted text fields (e.g. ticket's description).
SVN:trunk[4547]
2017-01-18 15:17:07 +00:00
Guillaume Lajarige
ecae7ea983 Portal: Browse brick: List was displaying pagination when not necessary in some circonstancies.
SVN:trunk[4546]
2017-01-16 13:08:45 +00:00
Guillaume Lajarige
a204a786c0 Portal: Browse brick: Filtering in list view now looks up in all the displayed fields (<name_att /> and <fields /> of the brick configuration)
SVN:trunk[4545]
2017-01-11 16:32:37 +00:00
Denis Flaven
79a2ab8abd Getting ready for the release of iTop 2.3.3.
SVN:trunk[4542]
2016-12-22 15:14:04 +00:00
Guillaume Lajarige
af13b42eab Legacy portal: Since iTop 2.3, plain text caselog entries can no longer be toggled due to a bad jQuery selector. Only HTML entries were working.
SVN:trunk[4541]
2016-12-21 13:10:15 +00:00
Denis Flaven
75721091f2 Updated Russian dictionary, thanks to Vladimir Kunin.
Note: you can always get the latest version on Vladimir's github: https://github.com/itop-itsm-ru/itop-rus.

SVN:trunk[4540]
2016-12-19 16:34:23 +00:00
Romain Quetiez
6e327e245b N.497 Continuation of the fix done in [r4461], to correctly handle validation patterns containing a slash (AttributeURL in the enhanced customer portal). The initial fix has broken the validation of date (+time) fields because the slash was escaped twice, leading to an invalid regular expression. Requires testing of synchro, CSV import, console, customer portal...
SVN:trunk[4538]
2016-12-19 16:04:21 +00:00
Guillaume Lajarige
6bfead405d N.551: Correcting spanish translations in the new portal (When creating a new user request in full ITIL or changing password)
SVN:trunk[4536]
2016-12-19 10:15:46 +00:00
Denis Flaven
a4f5620076 N. 549: "Font" menu broken in case logs (console and legacy portal). The menu was showing <> instead of font names.
SVN:trunk[4534]
2016-12-19 10:09:48 +00:00
Guillaume Lajarige
134a427901 Portal: Added german dictionnary
SVN:trunk[4532]
2016-12-16 09:13:43 +00:00
Guillaume Lajarige
27c3facb2b Portal: Added an environment banner in the portal like in the console. It warns the user when he is browsing in an other mode than "production".
SVN:trunk[4531]
2016-12-15 15:02:26 +00:00
Denis Flaven
fa9848d1be CKEditor version 4.6.1 + color dialog (for choosing the color of a table cell)
SVN:trunk[4530]
2016-12-14 16:45:22 +00:00
Denis Flaven
1afd7d2ae4 Exclude non-needed folders from the build.
SVN:trunk[4529]
2016-12-14 15:53:20 +00:00
Guillaume Lajarige
c622efe95c Portal: Added itopversion to js/css file urls to prevent cache issues when upgrading.
SVN:trunk[4526]
2016-12-14 11:20:49 +00:00
Denis Flaven
c0949421ad Support of the "target" attribute for links.
SVN:trunk[4524]
2016-12-14 11:16:12 +00:00
Romain Quetiez
0e21edcc77 N.561 Could not add images into the description of a ticket in the legacy portal, and losing images added into the case log (update from the portal, issue occuring when the CRON is enabled)
SVN:trunk[4521]
2016-12-13 16:55:16 +00:00
Denis Flaven
df85186407 N. 481:
1) wiki text syntax was not displayed in the description or case logs of the tickets
2) when wiki text syntax was supported, the generated hyperlinks were pointing to the console (instead of the portal)

SVN:trunk[4519]
2016-12-13 16:16:13 +00:00
Romain Quetiez
403ecf7fba N.557 Date/date+time pickers in the legacy portal, not aligned with the configured date formats. Took the opportunity to implement time picking (thus aligned with any form of iTop)
SVN:trunk[4517]
2016-12-13 14:24:33 +00:00
Denis Flaven
d143f0880b N. 533: when reloading the ticket form (due to an alternate initial state path)
1) the value of some controls (non-text inputs in n:n links) was not preserved,
2) popup dialogs and CKEditor instances were not properly destroyed and re-created.

SVN:trunk[4515]
2016-12-13 10:54:45 +00:00
Guillaume Lajarige
c185e1fc4f Portal: LinkedSet label in forms can now be toggled by clicking on the field label (Was only working on the linkedset count and chevron)
SVN:trunk[4514]
2016-12-13 10:45:34 +00:00
Guillaume Lajarige
68c180f7eb N.474: Support for "file" attribute (AttributeBlob) in the portal. READONLY only for now.
SVN:trunk[4512]
2016-12-13 10:15:43 +00:00
Denis Flaven
c903fc2246 Support of text-align in the styles.
SVN:trunk[4511]
2016-12-08 13:58:01 +00:00
Denis Flaven
7d5898f302 Upgrade of CKEditor from 4.5.8 to 4.6.0 and addition of the formatting buttons:
- Font family
- Font Size
+ reordering of the toolbar buttons to have two lines of equivalent width.

SVN:trunk[4510]
2016-12-08 13:52:28 +00:00
Guillaume Lajarige
a4bdd3aaf4 N.551: Added spanish translations to the enhanced portal thanks to the community :)
SVN:trunk[4508]
2016-12-08 13:21:13 +00:00
Romain Quetiez
5bae9deecc N.545 HTML images not displayed when no login is required for the page.
SVN:trunk[4506]
2016-12-08 12:45:56 +00:00
Guillaume Lajarige
ffbd666aca N.481: Portal: Impossible to submit a form with a duration attribute. Also fixed the displayed value in tables (ManageBrick and BrowseBrick)
SVN:trunk[4504]
2016-12-08 11:36:54 +00:00
Romain Quetiez
4ec3aeec92 N.490 Losing carrier returns and rich text formatting when the latest comments are copied to child tickets
SVN:trunk[4501]
2016-12-08 10:24:06 +00:00
Guillaume Lajarige
c5a00a1bf1 N.546: Portal: Edit value in case log was kept after UserRequest update.
SVN:trunk[4500]
2016-12-08 10:18:59 +00:00
Romain Quetiez
1b1e91f0dc N.500 Changed the query to fetch tickets related to a CI, so as to make it unambiguous whatever customization is made to the datamodel.
SVN:trunk[4498]
2016-12-08 08:22:36 +00:00
Romain Quetiez
21fc272674 N.534 Cannot create a parent ticket from the ticket edition form. More generally, the object creation dialog box (opened by the mean of the PLUS button) fails as soon as any of the mandatory fields is an HTML field. Regression introduced in iTop 2.3.0, and due to HTML field edition widget (aka CKEditor)
SVN:trunk[4496]
2016-12-07 20:31:54 +00:00
Denis Flaven
5716c11450 N. 550 the OpCode cache may cause the upgrade of the datamodel to fail. Let's flush it after the compilation.
SVN:trunk[4494]
2016-12-07 13:13:36 +00:00
Romain Quetiez
f7e77e9fa6 N.539 Regression introduced in [r4451] on oct 7th. Some OQL were issuing a notice and some were generating a SQL query that would fail with error "Column 'functionalci_id' in where clause is ambiguous" (See CI details)
SVN:trunk[4492]
2016-12-05 12:52:08 +00:00
Romain Quetiez
ad8c3db6b4 Continuing [r4488] N.536 Regression introduced in [r4469] (N.505), itself fixing a regression introduced in [r4404]. REQUIRES TESTING
SVN:trunk[4490]
2016-12-05 09:59:19 +00:00
Romain Quetiez
d5c3b8d8e2 N.536 Regression introduced in [r4469] (N.505), itself fixing a regression introduced in [r4404]. REQUIRES TESTING
SVN:trunk[4488]
2016-12-02 20:37:13 +00:00
Romain Quetiez
6ac6aea29f N.480 Page broken (missing menu + ...) when bulk modifying Document Notes (having various values)
SVN:trunk[4486]
2016-12-01 14:06:02 +00:00
Romain Quetiez
7ce06c0797 Optimizations. Continuation of [r4423] and [r4471]. The optimization of the load of icons does not work depending on the itop installation directory and version of PHP (crc32 producing a negative value, not suitable for a class name).
SVN:trunk[4485]
2016-12-01 10:08:35 +00:00
Romain Quetiez
53bf1f424a N.502 Too many backups on sundays
SVN:trunk[4483]
2016-12-01 09:51:47 +00:00
Romain Quetiez
b793cded34 N.527 Enable the template placeholders for AttributeCustomFields
SVN:trunk[4481]
2016-11-25 16:37:31 +00:00
Romain Quetiez
47ec6d4917 N.523 UserRights::ListProfiles must return an empty array if nobody is currently logged in (instead of a FATAL ERROR).
SVN:trunk[4478]
2016-11-18 15:47:20 +00:00
Romain Quetiez
e586ba8d6e N.520 Setup: conflicts when a module in "extensions" is an upgrade of a module that already exists in datamodels/2.x. The most recent module must be installed and the older one must be ignored.
SVN:trunk[4477]
2016-11-17 15:45:34 +00:00
Romain Quetiez
8a913a18cf Cosmetics. Simplified the warning about editing the configuration file. No need to mention which sections can be edited, since ALL other sections have been moved out from the configuration file (includes and dictionnaries).
SVN:trunk[4475]
2016-11-08 16:36:53 +00:00
Denis Flaven
a09e579451 Support of non-case sensitive "forbidden values" in DesignerTextField
SVN:trunk[4473]
2016-11-04 15:58:59 +00:00
Denis Flaven
79c5dc2ce2 Support of "fileref" tags inside the definition of the class fields. Useful for the "default_image" tag of AttributeImage.
SVN:trunk[4472]
2016-11-04 13:34:17 +00:00
Romain Quetiez
95d7bc5319 Continuation of [r4423] Optimizing the scan of icons on disk. Added a LOCK_EX flag to prevent concurrent access related issues. Safe handing of collision on the cache key (used as a filename).
SVN:trunk[4471]
2016-10-28 14:03:17 +00:00
Romain Quetiez
d3f5d05063 N.505 Regression introduced in [r4404]. Security issue - Object visibility totally screwed the APC cache (user data) is enabled. This is a change in the way SQL queries are built and therefore requires testing.
SVN:trunk[4469]
2016-10-28 09:08:30 +00:00
Romain Quetiez
b30a35ceb5 N.504 Could not jump into the designer (APC, random)
SVN:trunk[4467]
2016-10-27 14:57:01 +00:00
Denis Flaven
fac22c9729 Bug fix: creating a new DOM Node containing the string "0" resulted in an empty node (no DOMText).
SVN:trunk[4466]
2016-10-27 08:36:26 +00:00
Romain Quetiez
44e329c38d Cleanup of unused and possibly confusing XML markup (parent node under class/presentation/details). Thanks to D. Gumble for reporting this.
SVN:trunk[4463]
2016-10-21 14:14:20 +00:00
Guillaume Lajarige
e48ad8cb61 #497 Portal : Could not update object due to "Warning: preg_match(): Unknown modifier '/'"
SVN:trunk[4461]
2016-10-21 08:29:36 +00:00
Guillaume Lajarige
359dc73526 #497 Portal : Could not update object due to "Warning: preg_match(): Unknown modifier '/'"
SVN:trunk[4460]
2016-10-20 15:45:17 +00:00
Romain Quetiez
8169e81e9a Automated tests: added tests following the latest optimizations of the query engine
SVN:trunk[4459]
2016-10-14 14:08:52 +00:00
Guillaume Lajarige
f62f087bcc #475 Portal : Could not upload attachments on IE9.
SVN:trunk[4457]
2016-10-14 09:56:45 +00:00
Romain Quetiez
4eb0b3086d N.466 HTML links with href="ftp://..." or "file://...". The filtering implemented by default (DOM Sanitization) now takes the configuration parameter url_validation_pattern into account. Thus aligning the behavior between HTML attributes and AttributeURL, and the automatic wiki formatting. By default, iTop allows the protocols http/https/ftp. To allow the 'file' protocol, edit the config file and change url_validation_pattern accordingly.
SVN:trunk[4455]
2016-10-10 16:01:46 +00:00
Guillaume Lajarige
1c81650572 Graph :
- Bar chart labels on x axis are now displayed vertically like in iTop 2.2. Also, when there are more than 24 labels, not all of them are displayed in order to keep the axis readable.
- Pie chart legend is now placed on the right side.

SVN:trunk[4453]
2016-10-10 13:14:13 +00:00
Romain Quetiez
59e3367da8 N.434 ... Continuation... Fixed regression introduced in [r4448]. OQL (parsed) queries are optimized too but the SQL query cannot be executed. See example herebelow:
SELECT
        UserRequest AS u
   JOIN Person AS p1 ON u.caller_id=p1.id
   JOIN Organization AS o1 ON p1.org_id=o1.id
   JOIN Person ON u.caller_id=Person.id
   JOIN Location AS l ON Person.location_id = l.id
WHERE Person.status='active' AND p1.status='inactive' AND l.country='France'


SVN:trunk[4451]
2016-10-07 13:15:30 +00:00
Guillaume Lajarige
2b4b0fed83 Portal : Final touch to AllowedOrganizations by settings ignore_silos to true for ServiceFamily/Service/ServiceSubcategory on the default portal configuration
SVN:trunk[4449]
2016-10-07 09:39:34 +00:00
Romain Quetiez
fe6ae6f2eb N.434 Optimized the DB queries. As an example, the query that shows the service catalog in the enhanced customer portal is now made of 5 nodes (at the class level) whereas it used to be made of 11 nodes... for the exact same results. This optimization impacts almost each queries built by iTop. The expected benefit can insignificant or not, depending on the cardinality of the data, the datamodel and the original OQL queries. We found one case where the query execution would apparently never end and it takes now less than a second. The risk with such a change is that is affects most of the queries built by iTop -requires testing!
SVN:trunk[4448]
2016-10-07 08:45:24 +00:00
Romain Quetiez
79d994acf7 N.444 ... fixing regression introduced in [r4438]
SVN:trunk[4441]
2016-10-04 13:15:33 +00:00
Romain Quetiez
9dbbb8e012 Fixed regression introduced in [r4415]: data model remains unchanged though the customizations have been successfully compiled (and taken into account in the DB). The fix consists in completing the implementation: the verb apc_cache_info was missing, preventing the cache from being reset by the setup. I took the opportunity to add other verbs of apc so as to make sure that the emulation be consistent with the emulation provided by older versions of apcu.
SVN:trunk[4440]
2016-10-03 12:47:13 +00:00
Romain Quetiez
17fafbf85b N.444 Two date picker icons (lifecycle shortcut to resolved state, or a datetime attribute on a link). Solved by a factorization of the widgets initialization so that the initialization be the same (must be idempotent)
SVN:trunk[4438]
2016-10-03 11:47:03 +00:00
Guillaume Lajarige
f3a6455ed8 Portal : Bug when adding item on the first LinkedSet of an edition form
SVN:trunk[4436]
2016-10-03 08:01:23 +00:00
Romain Quetiez
5336d9e965 Internal: improved the API robustness by throwing an exception as soon as DBObject::Set is called with a date badly formatted. This is in line with the assumption that internal DBObject values are always safe.
SVN:trunk[4435]
2016-09-30 14:22:13 +00:00
Romain Quetiez
97d11ba910 N.445 Specifying a date format (other than the default one) and allowing to create a user request in the resolved status results in an error when selecting the resolved status.
SVN:trunk[4433]
2016-09-30 14:16:35 +00:00
Guillaume Lajarige
2fa68a3abc Portal : Deadline attributes not displayed properly in ManageBrick
SVN:trunk[4431]
2016-09-30 12:50:32 +00:00
Guillaume Lajarige
a88365ca49 Resize on AttributeImage crashes when gd extension is not installed. Implemented a fallback so images are stored as is (original size) when gd extension is not available. A warning message is displayed during the setup.
SVN:trunk[4429]
2016-09-30 11:24:30 +00:00
Guillaume Lajarige
f3053c39c2 Portal : Allowed Organizations part for action rules.
SVN:trunk[4428]
2016-09-30 08:47:43 +00:00
Guillaume Lajarige
c7ac39b86a Portal : ManageBrick crashing when displaying an abstract class with child classes attributes
SVN:trunk[4426]
2016-09-30 07:12:16 +00:00
Guillaume Lajarige
88eece7188 Portal : Autocomplete bug with IE9 in forms
SVN:trunk[4424]
2016-09-29 10:16:30 +00:00
Romain Quetiez
b7d101cdfb Optimization: cache icons files (scan directories for the Icon selection edition widget) benefiting to each dashboard page (20% faster with PHP7 + OpCache + APCu)
SVN:trunk[4423]
2016-09-27 14:42:35 +00:00
Guillaume Lajarige
56ade2b44c Removed debug traces for AllowAllData
SVN:trunk[4422]
2016-09-27 13:04:16 +00:00
Romain Quetiez
2a38eb757d Code cleanup: remove unused code causing warnings with PHP7 (SQLBlock)
SVN:trunk[4421]
2016-09-27 12:41:52 +00:00
Guillaume Lajarige
954ba60611 Portal : Caching TWIG templates to improve performances
SVN:trunk[4420]
2016-09-27 12:29:25 +00:00
Guillaume Lajarige
f9a984f3e4 #1334 Portal : Sorting objects on BrowseBrick regarding the all classes' default order and not the first class' order only. (For example the services catalog might appear as sorted on the first column but not the second one)
SVN:trunk[4418]
2016-09-27 08:18:14 +00:00
Romain Quetiez
8fd9acb2ce N.440 Remote troubleshooting: when the REST/JSON API fails due to malformed utf8 characters, return a meaningful json error message (explain + debug information) instead of an empty response
SVN:trunk[4417]
2016-09-26 19:11:08 +00:00
Romain Quetiez
915a88afd4 N.441 Character "à" in a case log causing the REST/JSON API to fail if mbstring is not enabled
SVN:trunk[4416]
2016-09-26 18:45:32 +00:00
Romain Quetiez
c755b66d8c Optimization: make it less cumbersome to have the APC user cache enabled for PHP 5.5+. Prior to this enhancement, it used to require a compilation flag (for apcu) until PHP7... then it became mandatory to install a dedicated backward compatibility module named after apcu_bc. Now, having apcu installed and enabled is ENOUGH.
SVN:trunk[4415]
2016-09-26 15:54:41 +00:00
Romain Quetiez
2f8dc0fa0f Prerequisite for #1334. New API: DBObjectSet::SetOrderByClasses. Helper to sort on multicolumn queries (SELECT a, b FROM)
SVN:trunk[4413]
2016-09-23 15:05:06 +00:00
Guillaume Lajarige
a34747f893 Portal : Missing AllDataAllowed
SVN:trunk[4412]
2016-09-23 13:58:08 +00:00
Guillaume Lajarige
4dd6c813b1 Portal : Typo
SVN:trunk[4411]
2016-09-23 13:37:45 +00:00
Guillaume Lajarige
8e96094977 Portal : Allowed Organizations Part II. Made sur that the AllowAllData flag was passed everywhere it was necessary, only when it was necessary. This has been tested but needs MORE testing !
SVN:trunk[4409]
2016-09-22 09:30:12 +00:00
Guillaume Lajarige
dd41ebf861 Portal : Preserve debug parameter through urls
SVN:trunk[4408]
2016-09-22 09:24:07 +00:00
Guillaume Lajarige
f732df751c Portal : Renamed <ignore_allowed_organizations> to <ignore_silos> for a more generic aproch
SVN:trunk[4406]
2016-09-20 14:41:56 +00:00
Guillaume Lajarige
acfab8fb63 Portal : Allowed Organizations can now be applied on the portal scopes. Just set the <ignore_allowed_organizations> to true under the concerned <scope> tag.
SVN:trunk[4405]
2016-09-20 14:22:04 +00:00
Romain Quetiez
23193153c6 N°436 Core API: Correctly (mathematically!) handle the "allow all data" flag, with UNIONS and INTERSECTIONS. Requires testing
SVN:trunk[4404]
2016-09-19 13:08:32 +00:00
Romain Quetiez
a908dcd752 #1178 Internals: Object Update/Reload should never fail: as soon as a given object has been read in the current execution context, updating/reloading it is not an issue.
SVN:trunk[4402]
2016-09-15 10:01:32 +00:00
Romain Quetiez
b8a80cb267 #1325 Part III - Completing the fix by aligning the internal data structures of iTop... and possibly fix an issue (?) - Not recommended for a retrofit
SVN:trunk[4399]
2016-09-14 15:42:19 +00:00
Romain Quetiez
ad1412c7e2 #1325 Part II - Completing the fix by aligning the internal data structures of iTop... and possibly fix an issue (?) - Not recommended for a retrofit
SVN:trunk[4398]
2016-09-14 15:35:16 +00:00
Romain Quetiez
4bf51515be #1325 Could not declare an ext key to a subclass (view could not be created). This commit is minimalistic and aims at being retrofitted into the various branches of iTop. It will be followed by a second commit, which aims at completing the fix by aligning the internal data structures of iTop... and possibly fix an issue (?)
SVN:trunk[4397]
2016-09-14 15:24:03 +00:00
Guillaume Lajarige
05f97dd75f Portal : Optimized column load in ManageBrick and BrowseBrick to improve performances
SVN:trunk[4396]
2016-09-13 08:47:24 +00:00
Denis Flaven
90cab29a3c Enhancement:
- Add more debug traces (if 'synchro_trace' == 'save')
- Show debug traces (if any) at the bottom of the status page
- Protect against time differences between the MySQL server and the PHP server, when running 'synchro_import.php'

SVN:trunk[4394]
2016-09-12 12:47:40 +00:00
Romain Quetiez
445b488603 #1323 error.log polluted with the contents of each email sent (transport = PHPMail)
SVN:trunk[4392]
2016-09-07 12:40:12 +00:00
Romain Quetiez
7141e0f4b0 Fix for regression introduced in [r4384] and causing a blank screen when attempting to edit an object
SVN:trunk[4390]
2016-09-06 13:47:59 +00:00
Denis Flaven
ffc756e4a4 (regression from iTop 2.2.x) ExternalFields were not automatically reloaded when the corresponding external key changed.
SVN:trunk[4388]
2016-09-06 10:08:06 +00:00
Romain Quetiez
8bed267feb Fixed XSS vulnerability
SVN:trunk[4386]
2016-09-06 10:01:37 +00:00
Romain Quetiez
13933e488c Rich text editor: the Maximize button icon is missing if iTop is installed in a directory which name contains spaces
SVN:trunk[4384]
2016-09-06 09:35:28 +00:00
Guillaume Lajarige
d48f76e965 Portal : Added Location scope to standard portal configuration because of the implementation of r4380
SVN:trunk[4382]
2016-09-06 09:30:10 +00:00
Guillaume Lajarige
a025c95054 Portal : External keys OQL now intersect with scopes in forms!
SVN:trunk[4380]
2016-09-06 07:04:24 +00:00
Guillaume Lajarige
b2fa9c468f Portal : Added a new mode "apply_stimulus" for forms. This allows to add flags to attributes that are prompt during transitions.
SVN:trunk[4378]
2016-09-05 14:29:05 +00:00
Romain Quetiez
8feef7fd8a #1321 Losing table borders (notification templates and notes)
SVN:trunk[4376]
2016-09-05 13:01:08 +00:00
Guillaume Lajarige
8330f3d498 Portal : Request template OQL list fields marked as mandatory were not validated properly
SVN:trunk[4371]
2016-09-02 12:30:41 +00:00
Guillaume Lajarige
88e7bd225c Portal : Updated inline documentation of UserProfile brick's <fields /> tag for easiest comprehension.
SVN:trunk[4370]
2016-09-02 12:16:57 +00:00
Romain Quetiez
1b0f818c4b Forms (portal): fix the rendering of a TEXT AREA in read-only mode.
1) format=text -> several lines were displayed on a single line
2) format=html -> characters encoded twice

SVN:trunk[4369]
2016-09-02 12:11:16 +00:00
Guillaume Lajarige
32dc1225ca Portal : Fixed search on enum & finalclass as well as display value of enum and html images in lists. Also Fixed display of friendlyname in lists, which was not behaving well on abstract class when the it was composed of several fields in the child classes.
SVN:trunk[4364]
2016-09-01 10:29:04 +00:00
Guillaume Lajarige
2b35cf5047 Portal : IE9 fixes
- Remaining console.log() inthe field_set.js file
- Missing zoom-in / zoom-out mouse cursors on a object images (They are actually not available on IE9, so I put a pointing hand instead)
- Missing pointer cursors on CaseLog field collapsers

SVN:trunk[4362]
2016-08-31 15:59:09 +00:00
Denis Flaven
df66e28545 Bug fix: regression from 2.3.x: SOAP webservices were broken!
SVN:trunk[4360]
2016-08-31 14:56:21 +00:00
Romain Quetiez
0ab060c958 Improved the comments for access_mode in the config file
SVN:trunk[4359]
2016-08-31 08:22:56 +00:00
Denis Flaven
dfceef4ca6 Enhancement: protect RenameValueInDB from non-existent attributes.
SVN:trunk[4357]
2016-08-30 12:56:13 +00:00
Denis Flaven
49f82e6377 #1297: timezone configuration setting was inoperant.
SVN:trunk[4355]
2016-08-29 12:47:06 +00:00
Guillaume Lajarige
c5957f1146 Portal : Fixed a regression introduced by r4324 causing HTML entities on the browse brick.
SVN:trunk[4353]
2016-08-29 07:27:29 +00:00
Guillaume Lajarige
b357e7d7d6 Portal : Enhanced and refactored error feedback on ExternalKey / LinkedSet / CustomFields fields
SVN:trunk[4352]
2016-08-25 15:21:33 +00:00
Guillaume Lajarige
e7342b0eb8 Portal : Request template list fields now have the autocomplete option.
SVN:trunk[4351]
2016-08-25 13:52:41 +00:00
Guillaume Lajarige
f33f4e3406 Portal : Request template list fields now have the lookup/search option. (Autocomplete is still to be implemented!)
SVN:trunk[4350]
2016-08-25 13:11:34 +00:00
Romain Quetiez
3d57c720e0 Could not bulk import with the "final class" (interactive import).
SVN:trunk[4348]
2016-08-24 16:50:02 +00:00
Romain Quetiez
ef5d156b98 #1305 Issue with date/time inputs on Chrome: losing focus as soon as the date has been correctly typed, preventing the user from typing the time.
SVN:trunk[4346]
2016-08-23 18:43:41 +00:00
Guillaume Lajarige
8722447f2f Portal : Templates not working with OQL "list" fields. This only append when the field had too many items and was trying to render as an autocomplete.
SVN:trunk[4344]
2016-08-23 16:01:25 +00:00
Guillaume Lajarige
e6047dcbf5 Portal : Templates not working with OQL "list" fields. This only append when the field had too many items and was trying to render as an autocomplete.
SVN:trunk[4343]
2016-08-23 16:00:00 +00:00
Guillaume Lajarige
df1d10f1cb #1299 Portal : "Oops, could not load data" when creating request in Full ITIL instance when running PHP7. Cause was that PHP7 isn't able to understand the factory method invocation synthax, had to make it more simple with intermediate steps.
SVN:trunk[4336]
2016-08-23 11:23:12 +00:00
Guillaume Lajarige
d1dd60f928 #1281 Portal : Fixed a few hardcoded strings to dictionnaries
SVN:trunk[4335]
2016-08-23 09:25:13 +00:00
Guillaume Lajarige
7bea59fea1 Portal : Fixed a bug with external key as radio button in forms
SVN:trunk[4334]
2016-08-22 15:50:35 +00:00
Guillaume Lajarige
17703ce572 Portal : Fixed a bug on the default configuration that was displaying only UserRequest in the Closed requests brick instead of both UserRequest and Incident objects.
SVN:trunk[4333]
2016-08-22 14:55:57 +00:00
Guillaume Lajarige
6d556249aa #1284: Fixed portal issue when trying to re-open a ticket as a portal user. Cause was that the destination state had "must prompt" attributes that were all "read only" for the current user, making the entire form "read only" and therefore removing "submit" button. The user was the not able to complete the transition. Fix consists of skipping the form when all attributes are "read only" for the user.
Also :
- Refactored a portion of TWIG (Loader is now in an helper TWIG)
- Placed transition buttons to the right with the submit one as it was confusing

SVN:trunk[4332]
2016-08-22 14:51:10 +00:00
Guillaume Lajarige
16b5db448b #1281 : Service catalog brick had 2 hardcoded headers ("Service" and "Sous-Service")
SVN:trunk[4330]
2016-08-11 10:00:49 +00:00
Denis Flaven
8ef7f073b3 CSV export of audit results: pass the parameters as a POST since they may be too long to fit in the query string of the URL.
SVN:trunk[4328]
2016-08-11 09:44:31 +00:00
Denis Flaven
22c647e3f8 Cleanup a Notice message: align the prototype of DBDeleteSingleObject to the current one.
SVN:trunk[4326]
2016-08-11 09:38:14 +00:00
Denis Flaven
bf94dfa894 Bug fix: support the display of HTML fields in the lists in the new portal.
SVN:trunk[4324]
2016-08-11 09:28:23 +00:00
Guillaume Lajarige
43d3cfefb5 Portal : Removed console.log to prevent crashes on IE9
SVN:trunk[4323]
2016-08-11 08:55:38 +00:00
Denis Flaven
e0855093ea Cosmetics: Enlarge DateTime fields which were too narrow (the end of the time is not visible when editing).
SVN:trunk[4321]
2016-08-11 08:34:10 +00:00
Denis Flaven
c147062aaa Regression introduced after 2.3.0-beta [r4217]: broken links to donwload / display blobs.
SVN:trunk[4319]
2016-08-10 15:54:04 +00:00
Denis Flaven
480c2fab04 Performance optimization: do not load all the columns when it is not needed.
SVN:trunk[4317]
2016-08-10 14:56:59 +00:00
Denis Flaven
53fb619da1 Image upload inside CKEditor (via drag and drop) seems to be desactivated on IE9.
SVN:trunk[4315]
2016-08-05 10:18:22 +00:00
Denis Flaven
c0a7bbaa72 Remember that console.log breaks IE9 when the console is not open !!!
SVN:trunk[4313]
2016-08-05 10:05:08 +00:00
Denis Flaven
12b27778f5 Bug fix: properly disable the configuration editor in demo mode! (Regression)
SVN:trunk[4310]
2016-07-27 09:50:40 +00:00
Denis Flaven
babcd6a92a Increased version number of the module to 1.0.1 to reflect the change related to revision 4300 (support of custom controller in a brick).
SVN:trunk[4308]
2016-07-26 08:15:42 +00:00
Denis Flaven
d80d24c348 Disable PDF export if the PHP extension "GD" is not loaded.
SVN:trunk[4307]
2016-07-15 07:05:06 +00:00
Denis Flaven
2c78a91a00 Model factory: introduced a new variation of attribute _delta: delete_if_exists. Use this flag to delete a branch from the data model being hacked, without caring if it is already deleted (or non existing). This eases the burden of coping with different installation combinations.
SVN:trunk[4306]
2016-07-15 06:41:26 +00:00
Romain Quetiez
109e5dfe2c Releasing 2.3.1
SVN:trunk[4302]
2016-07-08 12:00:27 +00:00
Denis Flaven
93ff327b54 2.3.0 Regression: login_mode was broken !
SVN:trunk[4301]
2016-07-08 11:56:27 +00:00
Guillaume Lajarige
359c188089 Customer portal : Added possibility to give a controller action for a brick tile. This allows to use some logic in order to make a specific render relying for example on DB dataobjects
SVN:trunk[4300]
2016-07-08 09:32:43 +00:00
Denis Flaven
6682eafb4d Oops, missing on Czech translation file.
SVN:trunk[4297]
2016-07-07 09:48:13 +00:00
Denis Flaven
b64c79d34e Force the filename (with a .csv extension) when downloading the audit errors as a CSV file.
SVN:trunk[4294]
2016-07-06 10:34:07 +00:00
Denis Flaven
e553c0bbe1 Prevent timeouts during the (lengthy) PDF conversion...
SVN:trunk[4293]
2016-07-06 09:43:20 +00:00
Denis Flaven
18f15ba9cc Fixed the case for the Emogrifier includes.
SVN:trunk[4292]
2016-07-06 09:22:43 +00:00
Guillaume Lajarige
f4e45b6c8d Updated licenses with Font Awesome
SVN:trunk[4291]
2016-07-05 14:53:04 +00:00
Guillaume Lajarige
1013cbc22f Customers portal : Added generated css files to the SVN
SVN:trunk[4290]
2016-07-05 14:47:45 +00:00
Romain Quetiez
12c64bd6e5 Internal: enable/disable data localization
SVN:trunk[4289]
2016-07-05 14:44:08 +00:00
Denis Flaven
c209b75f6b Limit the height of the "licenses" in the about box.
SVN:trunk[4288]
2016-07-05 13:38:15 +00:00
Denis Flaven
775ed7d437 Regresssion of iTop 2.3.0 beta: properly load the metamodel from the environment.
SVN:trunk[4287]
2016-07-05 13:37:40 +00:00
Romain Quetiez
dee3d55af2 Code cleanup: removed unused parameter (not used, thus confusing)
SVN:trunk[4286]
2016-07-05 12:08:00 +00:00
Denis Flaven
0d48e40c18 Regresssion: properly compute & record the history of StopWatch's sub-items.
SVN:trunk[4285]
2016-07-05 12:07:20 +00:00
Denis Flaven
a0965c2a52 Use the configurable date & time format for displaying the history of StopWatches.
SVN:trunk[4284]
2016-07-05 11:57:16 +00:00
Romain Quetiez
daccb122ae Getting ready for the release of iTop 2.3.0
SVN:trunk[4283]
2016-07-05 10:23:56 +00:00
Romain Quetiez
0a8532e27a Getting ready for the release of iTop 2.3.0
SVN:trunk[4282]
2016-07-05 10:12:36 +00:00
Denis Flaven
e7adf6559f Updated Czech translation, thanks to Lukáš Dvořák !
SVN:trunk[4281]
2016-07-05 10:10:23 +00:00
Romain Quetiez
07db5855a2 Fixed regression in 2.3.0-beta: placeholder $public_log$ was generating a mix of plain text and HTML markup whereas only plain text is expected
SVN:trunk[4280]
2016-07-05 09:50:10 +00:00
Denis Flaven
db47b2d05c Collapse the search form at the top of the main page when displaying a list of objects (drill down from a chart...), except when the page is the result of filling this form and pressing search.
SVN:trunk[4279]
2016-07-05 09:32:56 +00:00
Denis Flaven
a2eab87b7b Properly handle the creation of objects which go outside of the silo.
SVN:trunk[4278]
2016-07-05 09:19:17 +00:00
Romain Quetiez
396c4564b4 HTML formatting: TWO fixes in one! Fixed a bug introduced in 2.3.0-beta: the stylesheet cannot be defined within the email templates (aka ActionEmail) anymore. Instead, a default (ready for use) stylesheet is provided into /css/email.css and it can be overriden by the configuration parameter email_css. The fix consists in transforming the stylesheet into inline style... which fixes a limitation of gmail and Outlook that support only the inline styles. The implementation relies on a new library: emogrifier. This library has been changed (home-made utility) to be compatible with PHP 5.3 (declaration of arrays).
SVN:trunk[4277]
2016-07-04 15:06:28 +00:00
Denis Flaven
8582f6da70 Enhancement: provide some feedback to the end-user in case of a fatal error during an interactive export.
SVN:trunk[4276]
2016-07-04 14:22:24 +00:00
Guillaume Lajarige
fc7a10ff03 Synchro : Change description attribute from AttributeString to AttributeText
SVN:trunk[4275]
2016-07-01 13:47:59 +00:00
Guillaume Lajarige
7330154dd0 Customers portal : Fixed css glitch on portal instances menu
SVN:trunk[4274]
2016-07-01 10:48:02 +00:00
Romain Quetiez
beb53fd9dc When iTop is in restricted access mode (access_mode=2), the upgrade is not completely performed (profiles not updated correctly)
SVN:trunk[4273]
2016-07-01 10:36:26 +00:00
Guillaume Lajarige
9dbad63d6f Synchro : Formated last synchro date in the tooltip when viewing an Object
SVN:trunk[4272]
2016-07-01 10:14:26 +00:00
Guillaume Lajarige
21e5ca484c Export : Formatting dates from subitems in CSV, Excel, PDF exports
SVN:trunk[4271]
2016-07-01 09:45:58 +00:00
Guillaume Lajarige
41bee2b9b2 Customers portal : Home page template could not be override since template refactoring
SVN:trunk[4270]
2016-07-01 06:43:14 +00:00
Guillaume Lajarige
41556ba00b Customers portal : Final touches on portal configuration
SVN:trunk[4269]
2016-06-30 12:07:17 +00:00
Romain Quetiez
33b46483a9 Placeholders in notification: fixed the error message when the given placeholder is invalid
SVN:trunk[4268]
2016-06-29 15:03:56 +00:00
Guillaume Lajarige
970f75d5e2 PDF export : Exporting objects with AttributeImage value to default was crashing due to a "division by zero". Fixed.
SVN:trunk[4267]
2016-06-29 14:05:24 +00:00
Romain Quetiez
3a25916f00 Data synchro: web service synchro_import - usage to expose the real default date format (mySQL datetime format)
SVN:trunk[4266]
2016-06-29 13:47:58 +00:00
Guillaume Lajarige
c44284dc3c Customers portal : Fixed a bug in UserRequest edition form that prevented user to submit. Validation method was returning false on reoslution_code. Fix was to not check validators on empty && none mandatory fields (on both client and server sides).
SVN:trunk[4265]
2016-06-29 08:58:19 +00:00
Guillaume Lajarige
0ac9e21e5e Customers portal : Fixed dynamic tiles on home page APIs
SVN:trunk[4264]
2016-06-28 11:05:29 +00:00
Guillaume Lajarige
17abb729e1 Customers portal : Fixed a bug in BrowseBrick APIs. Calls to static functions were made as $this->
SVN:trunk[4263]
2016-06-28 09:10:10 +00:00
Guillaume Lajarige
00d131e3fc Customers portal : Improved error message on autocomplete field when the portal configuration is incorrect
SVN:trunk[4262]
2016-06-28 08:22:10 +00:00
Romain Quetiez
9d05c1c79c Code freeze for 2.3.0
SVN:trunk[4261]
2016-06-24 10:11:54 +00:00
Guillaume Lajarige
71f3313070 Customers portal : Comment for context tag
SVN:trunk[4260]
2016-06-23 15:03:18 +00:00
Denis Flaven
18de167d5e Internal: context tags to (programmatically) identify the context of the execution.
SVN:trunk[4259]
2016-06-23 14:57:37 +00:00
Guillaume Lajarige
c177264113 Customers portal : Final touches on default portal configuration
SVN:trunk[4258]
2016-06-23 13:59:20 +00:00
Guillaume Lajarige
31cafcf2dd Customers portal : BrowseBrick : Extra field columns can be hidden in list mode while remaining filterable. (Use case example : Hide a "keywords" attribute to enable filtering on it)
SVN:trunk[4257]
2016-06-23 12:58:34 +00:00
Denis Flaven
1e6ab3bdf0 Support of Custom Fields in the Excel export... not really nice but should be usable.
SVN:trunk[4256]
2016-06-23 09:26:24 +00:00
Denis Flaven
0ab344edee Internal: Read-only fields are no longer stored in the form as hidden fields.
SVN:trunk[4255]
2016-06-23 09:25:34 +00:00
Guillaume Lajarige
f82b5833aa Customers portal : Fixed a bug on profile picture edition. Button was not working on Firefox.
SVN:trunk[4254]
2016-06-23 08:59:18 +00:00
Guillaume Lajarige
daea9f0925 DataModel : Reserved location_id field OQL filter in order to start the JOINs from the Location object. Otherwise the Intersect limitation was raising.
SVN:trunk[4253]
2016-06-23 08:47:11 +00:00
Romain Quetiez
ebd0ae85a4 Code refactoring : fix of #876 implemented in 2.0.3 as [r3161], moved to a place where it will fix other implementations of the setup
SVN:trunk[4252]
2016-06-23 08:14:43 +00:00
Guillaume Lajarige
3b1886a435 Customer portal : Fixed a regression in CSS, form field labels were no longer bold
SVN:trunk[4251]
2016-06-23 08:00:08 +00:00
Guillaume Lajarige
eabc2a4eab Customer portal : Readonly attachments when object is not longer editable
SVN:trunk[4250]
2016-06-23 07:54:00 +00:00
Guillaume Lajarige
29cd969d49 Customer portal : Security exception raised when adding contact on a new UserRequest / Incident. This was caused by a bug in the SecurityHelper while checking scopes for a class that had no objects yet. (R-011452)
SVN:trunk[4249]
2016-06-23 07:23:56 +00:00
Romain Quetiez
31a375f640 Custom fields: solidified the internal APIs against creative usages (null =>default value)
SVN:trunk[4248]
2016-06-22 14:12:53 +00:00
Denis Flaven
218a2e2f01 Security: prevent grouping on password fields since it may lead to disclosure of the encrypted version of the password.
SVN:trunk[4244]
2016-06-22 13:50:19 +00:00
Romain Quetiez
94295f11da Fixed a regression introduced in iTop 2.3.0-beta: menu collapse mechanism broken when adding a shortcut (but it is restored when reloading the whole page).
SVN:trunk[4243]
2016-06-22 13:46:40 +00:00
Denis Flaven
d7b58a7730 Properly sanitize the "switch_env" parameter and take it into account only if it contains a valid value.
SVN:trunk[4238]
2016-06-22 12:08:58 +00:00
Denis Flaven
04133a8853 #1167 Error while upgrading db model from v 2.1 to 2.2 with orphan attachments.
SVN:trunk[4237]
2016-06-22 12:03:36 +00:00
Denis Flaven
619fe22a15 File or image upload is not supported (and thus disabled) when using the [+] button to create a new object inside a popup dialog.
SVN:trunk[4236]
2016-06-22 12:01:23 +00:00
Guillaume Lajarige
8071962bf9 Customer portal : LinkedSet fields can now be display a specific list of attributes instead of the z-list 'list' attributes. This is defined in module_design/classes/class/lists/list (see example in itop-tickets/datamodel.itop-tickets.xml)
SVN:trunk[4235]
2016-06-22 08:56:47 +00:00
Romain Quetiez
9b87d15f9a User/status must be read-only in demo mode
SVN:trunk[4234]
2016-06-21 14:50:28 +00:00
Romain Quetiez
3c9072bb65 OQL: fixed an old limitation, hierarchies can now be expressed both ways. Example of a query that now works fine: SELECT Organization AS root JOIN Organization AS child ON child.parent_id BELOW root.id WHERE child.name LIKE 'Combodo'. In the previous implementation, the operator was interpreted as '='.
SVN:trunk[4233]
2016-06-21 14:38:08 +00:00
Denis Flaven
fa2c234a43 "Search Drawer" is closed by default, unless the configuration parameter "legacy_search_drawer" is set to "true".
SVN:trunk[4232]
2016-06-21 10:20:20 +00:00
Guillaume Lajarige
a0d16b868e Customer portal : Edit profile picture
SVN:trunk[4231]
2016-06-21 10:19:28 +00:00
Denis Flaven
2773419faa New field on the User class to enable/disable user accounts.
SVN:trunk[4230]
2016-06-21 09:22:14 +00:00
Romain Quetiez
f89fa885d2 A few updates of the readme (valuable for the beta!)
SVN:trunk[4229]
2016-06-20 15:29:04 +00:00
Romain Quetiez
b34ea69cb3 #1169 Broken link to iTop Wiki in itop-tickets.htm
SVN:trunk[4228]
2016-06-20 15:26:50 +00:00
Romain Quetiez
b54f78ab1a Internal: DBSearch::Intersect to throw an exception whenever any of the merged queries have a queried class that does not correspond to the first joined class. This is a limitation of the current implementation of Intersect. Allowing such use cases would require quite a rework of that API.
SVN:trunk[4227]
2016-06-20 14:05:11 +00:00
Romain Quetiez
963a09ba6f Internal: fixed regression introduced in iTop 2.3.0 beta: no error though a mandatory attribute of type HTML has been left empty
SVN:trunk[4226]
2016-06-20 10:15:12 +00:00
Denis Flaven
feebe3f9a9 Support of formatted case log edition (with inline images) in the legacy portal.
SVN:trunk[4225]
2016-06-17 09:41:59 +00:00
Denis Flaven
636cd646aa Impact analysis display: cosmetics on tooltips: widen a bit the tooltips and prevent the text from overflowing horizontally.
SVN:trunk[4224]
2016-06-17 08:52:12 +00:00
Denis Flaven
9b774d3f72 - Make sure that the CSV Parser has enough time to run on big amount of data.
- Speedup the display of the CSV Import interactive wizard by parsing only the needed lines of the CSV data (in the first steps of the wizard).

SVN:trunk[4223]
2016-06-17 08:41:20 +00:00
Romain Quetiez
12857ceba1 #1188 Advanced customizations: allow to define a new constant or a brand new class as part of a delta
SVN:trunk[4222]
2016-06-16 15:25:05 +00:00
Guillaume Lajarige
ff5a96f92d Customers portal : Added some IDs in the layout to create new hooks
SVN:trunk[4221]
2016-06-16 12:03:42 +00:00
Guillaume Lajarige
c4660f1caf Customers portal : CSS is now separated into a Bootstrap theme stylesheet and another one specific to the template. It is also based on SASS like the console CSSs
SVN:trunk[4220]
2016-06-16 09:51:18 +00:00
Denis Flaven
dc2ee3472b Enhanced display/edition of the "Reconciliation Key" column when defining the reconciliation using the attributes.
SVN:trunk[4219]
2016-06-16 09:10:21 +00:00
Denis Flaven
ce6ed190aa Automatically remove duplicated modules (by keeping only the most recent one) when loading modules, independently of the loading order.
SVN:trunk[4218]
2016-06-16 08:41:54 +00:00
Romain Quetiez
52309bb1e5 Improved images caching: since 2.3.0-beta, iTop handles inline images (case logs, ticket description) and a picture for a person (AttributeImage). This code refactoring handles a case where the browser checks for the validity of the image and the 304 response code can then be returned without checking anything because we assume that the URL of the image contains a signature of it (or the data cannot change -attachement and inline images are in this case).
SVN:trunk[4217]
2016-06-16 08:23:15 +00:00
Romain Quetiez
2e71aee720 Notice in schema.php (Admin tools / data model) when viewing the class UserRequest
SVN:trunk[4216]
2016-06-15 13:15:43 +00:00
Guillaume Lajarige
41cb94bcf0 SCSS Compilation : Disabled max_execution_time while compiling SCSS files as it can take a while (Set back to its original value afterwards).
SVN:trunk[4215]
2016-06-15 12:42:57 +00:00
Guillaume Lajarige
5b9d2182dd Customers portal : Added GetAbsoluteAppRoot() JS function to portal.
SVN:trunk[4214]
2016-06-15 12:23:38 +00:00
Guillaume Lajarige
e6fefcc361 Customers portal : Started CSS rework to simply change BS theme
SVN:trunk[4213]
2016-06-15 11:44:23 +00:00
Guillaume Lajarige
181e14f48e Customers portal : Started CSS rework to simply change BS theme
SVN:trunk[4212]
2016-06-15 11:43:18 +00:00
Denis Flaven
8446fb028d Make sure that the setup can be launched even if the 'php-zip' module is not installed.
SVN:trunk[4211]
2016-06-15 09:44:25 +00:00
Denis Flaven
d88249eabc Trying to protect the Synchro for timeouts, since the synchro may be launched from the web (as a "web service", especially by the "collectors"). To be validated further with large amounts of data.
SVN:trunk[4210]
2016-06-14 16:11:28 +00:00
Denis Flaven
304080d74d #1167 Error while upgrading db model from v 2.1 to 2.2 with orphan attachments.
SVN:trunk[4209]
2016-06-14 12:44:29 +00:00
Denis Flaven
f74afac781 #1199 Properly handle the icon of attachments without any extension.
SVN:trunk[4208]
2016-06-14 09:39:11 +00:00
Denis Flaven
066e7bedc1 #1205 Positioning of dropdown list of "Popup Menus" on Chrome (and IE 11) when the content has been scrolled
SVN:trunk[4207]
2016-06-14 09:22:32 +00:00
Denis Flaven
899ea36bcc Typo !
SVN:trunk[4206]
2016-06-14 08:36:54 +00:00
Guillaume Lajarige
8ed94c4609 Customers portal : Typo in reference module design
SVN:trunk[4205]
2016-06-13 15:48:31 +00:00
Guillaume Lajarige
5dc86ebc5d utils::GetCSSFromSASS() : Skip processing if file is already a .css
SVN:trunk[4204]
2016-06-13 13:46:30 +00:00
Denis Flaven
4f7cc48fd4 Replacing the SCSS->CSS conversion library by a newer one made by Leaf Corcoran: http://leafo.github.io/scssphp, tweaked to work on PHP 5.3
SVN:trunk[4203]
2016-06-13 12:57:17 +00:00
Guillaume Lajarige
dfa855b4f7 Customer portal : ExternalField form field was crashing due to a typo.
SVN:trunk[4202]
2016-06-13 12:52:35 +00:00
Denis Flaven
49aeeb0202 Replace the SCSS->CSS library by a more recent and powerful one
SVN:trunk[4201]
2016-06-13 12:49:57 +00:00
Guillaume Lajarige
c9a0d2bc80 Customer portal : Object search from attribute was crashing if object class had no friendlyname.
SVN:trunk[4200]
2016-06-13 12:36:12 +00:00
Guillaume Lajarige
4a63989237 Customer portal : Fixed external key validator. Could not contain '0'.
SVN:trunk[4199]
2016-06-13 12:33:00 +00:00
Guillaume Lajarige
bd4aca770e Customer portal : HTML Entities in pre-setted autocomplete fields
SVN:trunk[4198]
2016-06-13 10:03:46 +00:00
Guillaume Lajarige
a4adf0b9ba Customer portal : Small update of the BrowseBrick in order to set a default filter value
SVN:trunk[4197]
2016-06-10 17:46:52 +00:00
Romain Quetiez
e48a1b1645 #1249 Fixed regression introduced in [r3916] (iTop 2.3.0 beta): AttributeHTML not working if the sql column name differs from the attribute code
SVN:trunk[4196]
2016-06-10 14:23:31 +00:00
Romain Quetiez
09fad78952 #1223 Custom lifecycle actions: improved the reporting when an action returns false (class/function/id logged into error.log)+ the framework now considers that no return value is equivalent to 'true'
SVN:trunk[4195]
2016-06-10 13:59:56 +00:00
Romain Quetiez
2a62b43848 XML customizations: fixed regression introduced in [r4075] (2.3.0-beta), could not change the parent of a class (which should move the class into the internal hierarchy)
+ fixed two error messages

SVN:trunk[4194]
2016-06-10 12:43:53 +00:00
Romain Quetiez
e8fb1cf236 #1207 Customization: allow the implementation of interfaces by the mean of abstract classes
SVN:trunk[4193]
2016-06-09 15:24:21 +00:00
Romain Quetiez
ac2492958c #1162 Protect data/log against reading (support of apache 2.4) -requires testing
SVN:trunk[4192]
2016-06-09 15:11:16 +00:00
Romain Quetiez
ddfc20fb7d #1233 Spanish translation: InterfaCe + Solución Aplicativa
SVN:trunk[4191]
2016-06-09 14:42:31 +00:00
Romain Quetiez
3147f36d96 #1252 Setup: make the project compatible with Ansible deployment (the file "database exi.png" was in fact not used at all!)
SVN:trunk[4190]
2016-06-09 13:34:08 +00:00
Romain Quetiez
1d379245ee #1254 Setup: iTop 2.3.0 requires PHP 5.3.6 (HTML sanitizer using the API DOMDocument::saveHTML with an argument)
SVN:trunk[4189]
2016-06-09 13:22:56 +00:00
Guillaume Lajarige
cb0fa2a5c8 Customer portal : Autocomplete field was not updating dependant fields.
SVN:trunk[4188]
2016-06-08 12:25:10 +00:00
Romain Quetiez
4c59d64025 Extending action classes (notifications): objects listed twice (in the base classes and leaf classes) in the notification page (actions tab).
SVN:trunk[4187]
2016-06-08 10:21:58 +00:00
Romain Quetiez
c92b0ea8f7 Internal: Email generation - No need to force "Content-Transfer-Encoding: 8bit". The default is "quoted-printable" and works fine if the content is made of plain text. Leaving the 8bit encoding could work but in such a case, the statement should be:
$oEncoder = new Swift_Mime_ContentEncoder_PlainContentEncoder('8bit', true /*canonicalize*/);... otherwise the lines get truncated at random places (CRLF is assumed while PHP EOL is made of CR only!) -This has an impact on plain text email only.

SVN:trunk[4186]
2016-06-08 10:01:17 +00:00
Guillaume Lajarige
7ebb0c40f3 Customer portal : Updated object form manager to check if an AttributeType has the necessary API to be used in a form (instead of the temporary array enumerating available types)
SVN:trunk[4184]
2016-06-03 14:51:37 +00:00
Guillaume Lajarige
b24c2b8455 Customer portal : Improved user feedback on modal loading crashs
SVN:trunk[4183]
2016-06-03 14:50:17 +00:00
Guillaume Lajarige
281925755d Customer portal : Added info/warning/error messages to the issue log along some exceptions
SVN:trunk[4182]
2016-06-03 14:34:29 +00:00
Guillaume Lajarige
f5ae5f7c42 Customer portal : Added user feedback when modal dialog loading crashes server side
SVN:trunk[4181]
2016-06-03 13:59:06 +00:00
Guillaume Lajarige
80789ccaa9 Customer portal : Formatted date in case log entries header
SVN:trunk[4180]
2016-06-02 15:45:33 +00:00
Denis Flaven
54a40c42cd Fix: properly parse dates in synchro import. Thanks to Karl aka karkoff1212 for reporting the issue.
SVN:trunk[4179]
2016-06-02 15:12:57 +00:00
Guillaume Lajarige
2c5d95a638 Customer portal : Browse Brick : Secondary actions menu was not always opening over the right element.
SVN:trunk[4178]
2016-06-02 15:06:45 +00:00
Guillaume Lajarige
10ca60893b Customer portal : Typo in module design comment
SVN:trunk[4177]
2016-06-02 14:42:06 +00:00
Guillaume Lajarige
f86c4bb8fa Customer portal : Viewing an object now displays an edit button if the user is allowed to edit the viewed object.
SVN:trunk[4176]
2016-06-02 12:36:50 +00:00
Guillaume Lajarige
3edf777aa6 Customer portal : Manage Brick : Added an optional tag <opening_mode> to define how the objects should be open (Value can be edit|view, Default is edit). Note that even if the tag is set to edit, objects that the user isn't allowed to edit will open in view mode.
SVN:trunk[4175]
2016-06-02 11:54:25 +00:00
Guillaume Lajarige
8a2fbdfd56 Customer portal : Manage Brick : Now displays object from the oql_view scope instead of the oql_edit scope. However, opening an object will be in edition mode if the user is allowed to do so, iotherwise it will open in view mode
SVN:trunk[4174]
2016-06-02 09:29:14 +00:00
Guillaume Lajarige
07056013c2 Customer portal : Displays a message when viewing an object with no attachments in read only
SVN:trunk[4173]
2016-06-02 09:15:42 +00:00
Guillaume Lajarige
ae61a1e5eb Customer portal : SecurityHelper now outputs to IssueLog on negative result when debug mode is enabled. Warning : This ca be extremely verbose ! Use debug mode smartly.
SVN:trunk[4172]
2016-06-02 08:51:27 +00:00
Guillaume Lajarige
e0909766fd Customer portal : Manage Brick : Edit action hyperlink is now setted on the first column if there is no friendlyname. Until now, if no friendlyname was available on the object class, there was no was of editing the object.
SVN:trunk[4171]
2016-06-02 08:26:06 +00:00
Guillaume Lajarige
e9dde4ee58 Customer portal : Set autocomplete to "off" on the password form in user profile brick.
SVN:trunk[4170]
2016-06-02 07:54:57 +00:00
Guillaume Lajarige
0050de641a Customer portal : Added support for some AttributeType in forms (AttributeExternalField, AttributeHierarchicalkey, AttributeSubItem, AttributeDuration)
SVN:trunk[4169]
2016-06-02 07:47:28 +00:00
Guillaume Lajarige
445349d2d9 Customer portal : Manage brick : Displaying objects from a class without friendlyname raised an exception.
SVN:trunk[4168]
2016-06-02 07:22:32 +00:00
Guillaume Lajarige
d026c86c50 Customer portal : Fixed regression introduced by r4159. Preferences form in user profile was crashing.
SVN:trunk[4166]
2016-06-01 15:51:29 +00:00
Romain Quetiez
1fb346da67 #1235 Internal: DBObject API - external fields not up to date after changing the external key (though they seem to be in sync when inspecting the internal values, Get() does not return the expected value).
SVN:trunk[4165]
2016-06-01 14:13:20 +00:00
Romain Quetiez
df466faddf Demo mode: to not allow deleting neither changing the org of persons attached to a user account (this to make sure that the portal users will still have access to the customer portal)
SVN:trunk[4164]
2016-06-01 12:46:22 +00:00
Guillaume Lajarige
43106d3a77 #1251 Disabling log notification in config causes a fatal error
SVN:trunk[4163]
2016-06-01 09:15:24 +00:00
Denis Flaven
9fc3b52b24 Fix: cannot export an object with a property named "length" !!
SVN:trunk[4161]
2016-05-30 09:25:29 +00:00
Guillaume Lajarige
026edb523c Customer portal : Added support for demo mode
SVN:trunk[4160]
2016-05-30 09:00:02 +00:00
Guillaume Lajarige
f640558349 Customer portal : Added support for demo mode
SVN:trunk[4159]
2016-05-30 08:12:17 +00:00
Guillaume Lajarige
ae52521a3f Customer portal : Added highlight classes to items in the manage brick
SVN:trunk[4158]
2016-05-27 10:32:58 +00:00
Guillaume Lajarige
13ef1a4084 Customer portal : Changed behaviour of browse brick table in list mode. Now columns hide from left to right when screen is too narrow. As the table is based on a hierarchy, left columns are redundants and hence less important then those on the right. (Had to update dataTables files to get a fix on the responsive extension)
SVN:trunk[4157]
2016-05-27 08:37:10 +00:00
Romain Quetiez
a8f67116ea Customer portal: continuation of the previous commit... hopefully the last one before releasing 2.3.0 beta!
SVN:trunk[4156]
2016-05-26 10:00:21 +00:00
Romain Quetiez
af9bd61bb7 Preparing release 2.3.0 beta
SVN:trunk[4155]
2016-05-26 09:27:35 +00:00
Guillaume Lajarige
fdb0a8116c Customer portal : Changed user profile brick icon
SVN:trunk[4154]
2016-05-26 08:58:55 +00:00
Guillaume Lajarige
ffcc6ded74 Customer portal : Translated on going requests tabs
SVN:trunk[4153]
2016-05-25 15:45:17 +00:00
Guillaume Lajarige
6152277910 Customer portal : Home tile alignment to the left
SVN:trunk[4152]
2016-05-25 14:47:19 +00:00
Denis Flaven
62b47556bc Aligning version numbers for the modules modified since the last release.
SVN:trunk[4151]
2016-05-25 14:07:45 +00:00
Romain Quetiez
c9bfeedb50 Preparing release 2.3.0 beta
SVN:trunk[4150]
2016-05-25 13:54:08 +00:00
Guillaume Lajarige
0dcff56969 Customer portal : Good Vibrations ♫♫
SVN:trunk[4149]
2016-05-25 13:44:22 +00:00
Denis Flaven
16d0df2553 Regression fix: update read-only fields which are dependent from other fields.
SVN:trunk[4148]
2016-05-25 13:34:12 +00:00
Guillaume Lajarige
564b8a9726 Customer portal : User name truncation when too long on mobile UI
SVN:trunk[4147]
2016-05-25 13:23:37 +00:00
Romain Quetiez
3830d2414c New portal: Finalized the texts in the home view (and menus)
SVN:trunk[4146]
2016-05-25 13:07:50 +00:00
Guillaume Lajarige
2e6e6d52ca Customer portal : UI improvements on navigation menu
SVN:trunk[4145]
2016-05-25 13:00:05 +00:00
Denis Flaven
22f73506a2 Support for objects to go "out of the silo" during a transition by making sure that we can reload an object we've just saved.
SVN:trunk[4144]
2016-05-25 12:32:32 +00:00
Denis Flaven
fc4c3c9bb9 Improved the "closed requests" icon at small point sizes.
SVN:trunk[4143]
2016-05-25 12:26:50 +00:00
Guillaume Lajarige
461153967a Customer portal : Fixed a bug in brick layout title
SVN:trunk[4142]
2016-05-25 12:18:35 +00:00
Guillaume Lajarige
c4e20ea0fe Customer portal : Fixed a bug in sticky buttons
SVN:trunk[4141]
2016-05-25 11:27:35 +00:00
Guillaume Lajarige
1ea66646b6 Customer portal : Allowed HTML in tile description. Also fixed tile description css to avoid text wrapping under the decoration.
SVN:trunk[4140]
2016-05-25 09:44:30 +00:00
Denis Flaven
201f5118b3 Fine tuning of the default value for display_max_width.
SVN:trunk[4139]
2016-05-25 09:29:43 +00:00
Denis Flaven
4bebcdc63a No quotes around the default date and time format!
SVN:trunk[4138]
2016-05-25 09:28:40 +00:00
Guillaume Lajarige
f6b185388a Customer portal : Added background to user card
SVN:trunk[4137]
2016-05-25 09:16:34 +00:00
Denis Flaven
b97b9bf1d5 $this->head_html(log)$ and $this->head(log)$ now support both text and HTML case logs.
SVN:trunk[4136]
2016-05-25 08:59:26 +00:00
Guillaume Lajarige
eab0320ef0 Customer portal : Creating a request from services catalog now redirects to "on going requests" page
SVN:trunk[4135]
2016-05-25 08:33:02 +00:00
Romain Quetiez
93adab0644 New portal: IIS default config not handling correctly woff/svg files
SVN:trunk[4134]
2016-05-25 07:59:00 +00:00
Guillaume Lajarige
adc70103e0 Customer portal : UI improvements
SVN:trunk[4133]
2016-05-25 07:32:23 +00:00
Romain Quetiez
cf3d0bde5b Operational status: only in search forms (+ search results for Ticket)
SVN:trunk[4132]
2016-05-25 07:29:20 +00:00
Romain Quetiez
4187b074a9 ImageAttribute: only in XML version 1.3
SVN:trunk[4131]
2016-05-24 19:55:08 +00:00
Romain Quetiez
1a5637352b New attribute 'operational_status' : finalized with three values (ongoing, resolved and closed)
SVN:trunk[4130]
2016-05-24 16:03:47 +00:00
Romain Quetiez
1e719b97d8 New attribute: ImageAttribute
SVN:trunk[4129]
2016-05-24 15:29:44 +00:00
Denis Flaven
2299d23099 Adding an extra index to speed-up data synchronization for large volumes of data.
SVN:trunk[4128]
2016-05-24 13:49:34 +00:00
Denis Flaven
a91723befe Missing dictionary entry for the PDf export options.
SVN:trunk[4127]
2016-05-24 13:43:09 +00:00
Guillaume Lajarige
e1ea466053 Customer portal : New Combodo font and stylesheet to use some pictos as characters anywhere
SVN:trunk[4126]
2016-05-24 12:34:30 +00:00
Guillaume Lajarige
2c4ccd2302 Customer portal : Changed PortalURLMaker of default portal instance so generated links now point to an edit page instead of a view page.
SVN:trunk[4125]
2016-05-24 09:53:45 +00:00
Denis Flaven
930e51f94c Font plugin for CKEditor
SVN:trunk[4124]
2016-05-24 09:38:14 +00:00
Denis Flaven
534eef1f72 Font plugin for CKEditor
SVN:trunk[4123]
2016-05-24 09:37:32 +00:00
Guillaume Lajarige
89fa0365fd Customer portal : Services catalog displayed as a list by default
SVN:trunk[4122]
2016-05-24 09:34:17 +00:00
Guillaume Lajarige
9f8ed3ada3 Customer portal : Home UI improvements, added missing iTop logo
SVN:trunk[4121]
2016-05-24 09:26:35 +00:00
Denis Flaven
047fd088cc Excel export: write empty date (and time) cells as empty strings instead of zero (0) !
SVN:trunk[4120]
2016-05-23 16:24:12 +00:00
Denis Flaven
db010e4ddc Proper validation (and reporting) about date (and time) formats.
SVN:trunk[4119]
2016-05-23 16:11:27 +00:00
Guillaume Lajarige
bc6f73b9ec Customer portal : Fixed some bugs and rectified some default configuration parameters
- Form, ExternalKey autocomplete & regular search
- Portal power user being able to see all its silo tickets
- Worked on the UI

SVN:trunk[4118]
2016-05-23 15:31:02 +00:00
Denis Flaven
7761404755 Date and time format: exports finalization.
SVN:trunk[4117]
2016-05-23 14:39:21 +00:00
Denis Flaven
7a6e47f067 Properly display the date value (and not the current date) in the export preview.
SVN:trunk[4116]
2016-05-23 13:05:10 +00:00
Denis Flaven
409ca87f8c Initialize TimePicker in one call to prevent the time part from being reset as it happens when doing the same action in two passes (calling "options" the second time) !!
SVN:trunk[4115]
2016-05-23 12:35:36 +00:00
Guillaume Lajarige
6ce0940f67 Customer portal : Ordered languages in user preferences
SVN:trunk[4114]
2016-05-23 12:16:10 +00:00
Guillaume Lajarige
127d2a3295 Customer portal : Fixed exception in ManageBrick that was looking for objects out of its scope
SVN:trunk[4113]
2016-05-23 10:16:43 +00:00
Denis Flaven
f4ff96a552 InlineImage::FixUrls must be
1) idempotent
2) aligned with the syntax used by CKEditor
to prevent creating new entries in the history when nothing was modified.

SVN:trunk[4112]
2016-05-23 10:16:31 +00:00
Denis Flaven
64b3e12258 Updated C3Js to 0.4.11 to fix an issue (on click event) on Chrome.
SVN:trunk[4111]
2016-05-23 08:13:20 +00:00
Romain Quetiez
7aa1495c4a Customer Portal: simplified the contents of the home page (still requires icons and a review of the CSS)
SVN:trunk[4110]
2016-05-20 09:46:55 +00:00
Romain Quetiez
4a1ec12cba #1213 Losing SLA data when changing any attribute of an SLA.
SVN:trunk[4109]
2016-05-20 08:01:40 +00:00
Guillaume Lajarige
f4ab48a2d4 Customer portal : Disabled autocomplete on password fields in the user profile form
SVN:trunk[4108]
2016-05-19 15:23:40 +00:00
Guillaume Lajarige
eeb0d5c98c Customer portal : Look and feel WIP
SVN:trunk[4107]
2016-05-19 15:23:23 +00:00
Romain Quetiez
1ebafb0566 XSS: Fixed a regression caused by the fix [3994]. Object hyperlinks were escaped twice causing accuented characters displayed as '&acute;'. The API DBObject::MakeHyperLink has been clarified and the original fix moved elsewhere. The XSS injection that was not handled correctly prior to [3994] was in the display of an external key in the details of an object. To reproduce easily, inject some malicious characters in the name of the organization 'Demo' and view any object owned by Demo.
SVN:trunk[4106]
2016-05-19 09:51:09 +00:00
Denis Flaven
4a81d70bf6 Suppress a warning when exporting a case log to HTML... Limitation: be aware that wiki links are not transformed to hyperlinks in this case.
SVN:trunk[4105]
2016-05-18 09:33:17 +00:00
Guillaume Lajarige
ccc0c7e7aa Customer portal : Object search dialog when adding object to a linkedset doesn't show already added elements.
SVN:trunk[4104]
2016-05-18 09:15:44 +00:00
Guillaume Lajarige
788f7bb029 Customer portal : Adding object to linkedset could have result in duplicates. Fixed
SVN:trunk[4103]
2016-05-18 09:00:54 +00:00
Romain Quetiez
70774f1923 Model factory: _delta = if_exists, not working with <class> nodes
SVN:trunk[4102]
2016-05-18 08:22:17 +00:00
Denis Flaven
c914344a32 Security: do not show actual encrypted values, display '*****' instead.
SVN:trunk[4101]
2016-05-18 08:15:14 +00:00
Denis Flaven
3b38388c73 Support "recusrive placeholders" (i.e. $this->org_id->code$) inside notifications... when using the HTML notation (i.e. -> becomes -&gt;)
SVN:trunk[4100]
2016-05-17 19:01:22 +00:00
Guillaume Lajarige
d9a5b85c67 Customer portal : Fixed regression in request template that was introduced by #4095
SVN:trunk[4099]
2016-05-17 15:43:23 +00:00
Guillaume Lajarige
1aacf1adae Customer portal : UX adjustments on LinkedSet (Collapse toggler pictos, check all/none state)
SVN:trunk[4098]
2016-05-17 14:56:25 +00:00
Guillaume Lajarige
88866ac199 Customer portal : Form, sticky buttons as pictos only in both plain page and modal layouts. Also, pictos were added to regular bottom buttons
SVN:trunk[4097]
2016-05-17 14:55:05 +00:00
Denis Flaven
316d1f9b14 Validate date/time fields using their regular expression during an import (or synchro) to avoid passing wrong formats as-is (e.g. 01/02/16 can become 01/02/0016 instead of 01/02/2016 if you use the 4 digits format for years and pass only 2 digits !)
SVN:trunk[4096]
2016-05-17 14:51:42 +00:00
Romain Quetiez
6b465688a2 Custom Fields: API to detect forms containing only hidden fields
SVN:trunk[4095]
2016-05-17 14:09:38 +00:00
Guillaume Lajarige
6e8ee09399 Customer portal : Form, sticky buttons only when creating / editing objects
SVN:trunk[4094]
2016-05-16 17:20:36 +00:00
Guillaume Lajarige
754604b009 Customer portal : Preview for attachments
SVN:trunk[4093]
2016-05-15 09:43:53 +00:00
Guillaume Lajarige
7790f770a7 Customer portal : Form - Hiding templates when there is none in order to optimize form space (Actually hiding SubForm when there is only HiddenField)
SVN:trunk[4092]
2016-05-15 08:46:24 +00:00
Denis Flaven
72b4c549c7 Fix a regression (crash) when displaying deadline attributes.
SVN:trunk[4091]
2016-05-14 17:42:02 +00:00
Denis Flaven
1515178500 Validate date/time fields using their regular expression during an import to avoid passing wrong formats as-is (e.g. 01/02/16 can become 01/02/0016 instead of 01/02/2016 if you use the 4 digits format for years and pass only 2 digits !)
SVN:trunk[4090]
2016-05-14 17:38:07 +00:00
Denis Flaven
165dbaf245 Date and time format finalization for the exports:
- properly display the date and time as expected in the preview during an interactive export
- differentiate date vs date&time formats in the Excel export
- use the custom format in the default URL provided by the query phrasebook

SVN:trunk[4089]
2016-05-14 17:35:52 +00:00
Guillaume Lajarige
3c112eb078 Customer portal : LinkedSet widget UX improvements part 2 (Collapsing widget)
SVN:trunk[4088]
2016-05-14 17:23:43 +00:00
Denis Flaven
5540fdb7db Display the dates of the synchronization according to the date/time format defined for this language.
SVN:trunk[4087]
2016-05-14 17:06:47 +00:00
Denis Flaven
6e074f5486 Regression: properly initialize mandatory date (and time) attributes when using a custom date/time format.
SVN:trunk[4086]
2016-05-14 17:04:20 +00:00
Denis Flaven
636140bfdd Display the dates of the history according to the date/time format defined for this language.
SVN:trunk[4085]
2016-05-14 17:02:26 +00:00
Guillaume Lajarige
69165396d4 Customer portal : LinkedSet widget UX improvements part 1 (Check/Uncheck all)
SVN:trunk[4084]
2016-05-13 17:47:14 +00:00
Romain Quetiez
dab860cfbd Breadcrumb: reviewed icon and label for global search and search menus just openin a search form
SVN:trunk[4083]
2016-05-13 15:27:11 +00:00
Romain Quetiez
7380f56a50 Breadcrumb: reworked the disposition (when wrapping onto a second line, the last item could be strangely placed between both lines on Chrome)
SVN:trunk[4082]
2016-05-13 15:24:17 +00:00
Guillaume Lajarige
d0d761236b Customer portal : Improvements on form sticky buttons
SVN:trunk[4081]
2016-05-13 14:03:36 +00:00
Guillaume Lajarige
760f3a788e Customer portal : Added description to bricks. Displayed only in the home tiles.
SVN:trunk[4080]
2016-05-13 13:43:10 +00:00
Romain Quetiez
73274ec461 Customer portal: the list of service subcategories of a user request must be filtered on 'service request'
SVN:trunk[4079]
2016-05-13 13:33:05 +00:00
Guillaume Lajarige
291a5847f0 Customer portal : Portal logo source order is : "/images/itop-logo.png" < "/env-xxx/branding/portal-logo.png" < "value of //properties/logo of the portal module_design"
SVN:trunk[4078]
2016-05-13 12:06:35 +00:00
Guillaume Lajarige
2720f6e54b Customer portal : Sticky form button when form is to long to be fully displayed in the screen
SVN:trunk[4077]
2016-05-13 10:31:15 +00:00
Romain Quetiez
58b571f08a Model factory: handle the flag 'if_exists' when transforming XML from version 1.3 to older versions
SVN:trunk[4076]
2016-05-12 19:13:06 +00:00
Romain Quetiez
14a2d9960f Model factory: introduced a new variation of attribute _delta: if_exists. Use this flag to ignore a branch if the corresponding node does not exist in the data model being hacked. This is to reduce the burden of developping separate modules depending on the installation options.
SVN:trunk[4075]
2016-05-12 15:57:09 +00:00
Romain Quetiez
88c46813d9 Setup: improved the module ordering algorithm. If a module has several dependencies (inclusive OR), it must be installed after each and every of its dependency that has been selected for installation.
SVN:trunk[4074]
2016-05-12 15:50:54 +00:00
Guillaume Lajarige
bcb5e4304a Customer portal : BrowseBrick : Changed style of secondaries actions
SVN:trunk[4073]
2016-05-12 13:21:30 +00:00
Guillaume Lajarige
793d4f814d Customer portal : Tooltip not closing when opening a modal on mobile devices
SVN:trunk[4072]
2016-05-12 12:01:52 +00:00
Guillaume Lajarige
1693f73742 Customer portal : Finally translated form validation messages !
SVN:trunk[4071]
2016-05-12 10:47:38 +00:00
Guillaume Lajarige
4c9edf04dd Customer portal : Support for password field in the Bootstrap renderer
SVN:trunk[4070]
2016-05-12 10:25:07 +00:00
Guillaume Lajarige
9b11b12b07 Customer portal : Form adjustments on UserProfile brick
SVN:trunk[4069]
2016-05-12 10:24:23 +00:00
Guillaume Lajarige
6297809716 Customer portal : User Profile brick that allows basic Contact informations edition, password / preferences change from the portal
SVN:trunk[4068]
2016-05-12 10:22:23 +00:00
Guillaume Lajarige
6540c547a4 Customer portal : Fixed home tiles disposition algo
SVN:trunk[4067]
2016-05-12 10:19:30 +00:00
Romain Quetiez
9d8a2cb7bb Customer Portal: refactoring for the "new ticket" buttons, depending on the installation options (in particular, a full ITIL install has now two buttons)
SVN:trunk[4066]
2016-05-11 18:37:30 +00:00
Romain Quetiez
35c0bfea1c No need for bridge modules to be listed as installed modules in the about box. Still, they are listed in the "support information".
SVN:trunk[4065]
2016-05-11 18:32:54 +00:00
Denis Flaven
748c1853ec Programmatically allow to write on any object - if needed - independently of the profiles.
SVN:trunk[4064]
2016-05-11 16:13:48 +00:00
Guillaume Lajarige
0e5c2c3e80 Portal : Changed "no item" message for BrowseBrick
SVN:trunk[4063]
2016-05-11 14:23:35 +00:00
Denis Flaven
cc0019c090 Styles fine tuning and nicer display of the main menu (no more animation on initial load).
SVN:trunk[4062]
2016-05-11 14:20:02 +00:00
Denis Flaven
e00667c2e4 HTML texts: support of float (left/right) in the inline style tags.
SVN:trunk[4061]
2016-05-11 13:43:49 +00:00
Romain Quetiez
c1a4c0185b Customer Portal: exit if 1) there is neither UR nor INC tickets installed 2) the current login has no contact associated to it
SVN:trunk[4060]
2016-05-11 13:18:01 +00:00
Denis Flaven
1c997a5973 Removed "Essential" from the logo.
SVN:trunk[4059]
2016-05-11 13:18:00 +00:00
Romain Quetiez
236de6ce34 Customer Portal: renamed portal related modules (as seen in the about box)
SVN:trunk[4058]
2016-05-11 12:20:17 +00:00
Romain Quetiez
681e07ca73 Customer portal: do not install itop-portal-base if not required
SVN:trunk[4057]
2016-05-11 12:14:51 +00:00
Denis Flaven
e388e4b163 Bug fix: the result of CheckToWrite() was not taken into account (action failed silently) when creating an object using the [+] button inside a form.
SVN:trunk[4056]
2016-05-11 12:09:45 +00:00
Romain Quetiez
1018dc6e74 Customer portal: adjusted the versions of the recently updated module (inc. the XML format version raised to 1.3)
SVN:trunk[4055]
2016-05-11 12:05:03 +00:00
Romain Quetiez
06075805e0 Fixed regression introduced in [4022]: about box not displayed
SVN:trunk[4054]
2016-05-11 11:46:28 +00:00
Denis Flaven
37a6a5183d #1214: concurrent access lock not properly released when CheckToWrite() reports an error during a transition from one state to another.
SVN:trunk[4053]
2016-05-11 11:44:26 +00:00
Denis Flaven
ebd89194ee New flag to open/collapse the search form at the top of a page in an OQLMenuNode.
SVN:trunk[4052]
2016-05-11 10:07:36 +00:00
Romain Quetiez
243dee4312 Brand new customer portal - installed only if selected by the user in the installation wizard
SVN:trunk[4051]
2016-05-11 08:25:20 +00:00
Guillaume Lajarige
d677a20c96 Portal : Datamodel modifications to ensure setup modularity
SVN:trunk[4050]
2016-05-11 07:49:54 +00:00
Denis Flaven
ccddf1d4f0 Fix for editing HTML content containing html entities: & must be encoded as &amp; as well !!
SVN:trunk[4049]
2016-05-10 19:26:02 +00:00
Denis Flaven
1d3ab23699 Typo!
SVN:trunk[4048]
2016-05-10 17:21:44 +00:00
Romain Quetiez
0182822f76 Customer Portal: proposed by default for installation
SVN:trunk[4047]
2016-05-10 15:47:10 +00:00
Romain Quetiez
c911ce38a6 User request (all-in-one): the end-user can leave the request type undefined, in such a case, she can select any type of services and the request type gets computed when the requests is written to the DB. Still, this is possible to select a request type and the list of services is filled with the corresponding services. This behavior was necessary for the new user portal to work fine.
SVN:trunk[4046]
2016-05-10 15:38:10 +00:00
Denis Flaven
89328e1662 Prevent infinite cross-ticket recursion when propagating parent->child resolution in tickets.
SVN:trunk[4045]
2016-05-10 15:33:48 +00:00
Romain Quetiez
a618f2804b Brand new customer portal - alpha version: requires adjustments to work with various ticketing installation options
SVN:trunk[4044]
2016-05-10 15:04:44 +00:00
Denis Flaven
242f7785e6 Add the "filter" attribute into the details form of the TriggerOnThresholdReached class.
SVN:trunk[4043]
2016-05-10 14:00:34 +00:00
Denis Flaven
3335d0a453 Throw an expection in case of unexpected value for the _delta attribute in the XML...
SVN:trunk[4042]
2016-05-10 13:49:35 +00:00
Denis Flaven
1621f2ba31 Make the login page more mobile friendly.
SVN:trunk[4041]
2016-05-10 13:33:45 +00:00
Romain Quetiez
45ddc7f71b Internal: when uploading documents, get the mimetype from the file itself (if feasible) rather than relying on the mimetype of the HTTP header. This was already implemented but it was buggy and fell anytime into the fallback method.
SVN:trunk[4040]
2016-05-10 10:57:25 +00:00
Romain Quetiez
ae22bbbc81 Internal: added DBObject::RegisterURLMakerClass, to allow for overriding the standard behavior of template placeholders such as $this->org_id->hyperlink(portal)$
SVN:trunk[4039]
2016-05-09 16:01:56 +00:00
Denis Flaven
3e1607047e CKEditor's full screen mode is not supported on iOS (cf https://dev.ckeditor.com/ticket/8307)
SVN:trunk[4038]
2016-05-09 15:36:26 +00:00
Denis Flaven
da69985970 Preparing for 2.3.0 beta.
SVN:trunk[4037]
2016-05-04 12:29:33 +00:00
Romain Quetiez
6999458de6 Added credits for CKEditor (LGPL)
SVN:trunk[4036]
2016-05-04 12:23:29 +00:00
Denis Flaven
37a8db125a Portal users must now be able to add/remove links to Persons and CIs.
SVN:trunk[4035]
2016-05-04 12:17:48 +00:00
Denis Flaven
3d74c1ccaa More sample data: adding 1 Service Family for all IT services.
SVN:trunk[4034]
2016-05-04 12:16:12 +00:00
Romain Quetiez
6fae298c0c #185 Navigation Breadcrumb - Missing standard icon for classes not having a specific icon
SVN:trunk[4033]
2016-05-04 11:29:17 +00:00
Denis Flaven
e85c6ca0c5 Fix full screen button in CKEditor.
SVN:trunk[4032]
2016-05-04 10:35:12 +00:00
Guillaume Lajarige
aa788a7aad Portal : Finished integration of Date & DateTime attributes in forms
SVN:trunk[4031]
2016-05-04 10:04:06 +00:00
Denis Flaven
3c4845cf99 #1215: URL fields can now store up to 2048 characters
SVN:trunk[4030]
2016-05-04 09:55:24 +00:00
Guillaume Lajarige
2b12a86fa8 Portal : Finished integration of Date & DateTime attributes in forms
SVN:trunk[4029]
2016-05-04 09:42:14 +00:00
Denis Flaven
dc5040c1d2 Wiki syntax is supported in formatted (HTML) text fields as well as plain text areas.
SVN:trunk[4028]
2016-05-04 08:53:47 +00:00
Denis Flaven
b02e163ecc CKEditor integration fine tuning with a new "Maximize" button in the collapsed toolbar.
SVN:trunk[4027]
2016-05-04 08:26:14 +00:00
Romain Quetiez
0e25c9a7a1 #185 Navigation Breadcrumb - Do not generate new entries for "Preferences..." when the user is tuning the language
SVN:trunk[4026]
2016-05-04 07:51:06 +00:00
Guillaume Lajarige
79f73256d7 Support for Date and DateTime in portal
Fixed form validation on portal

SVN:trunk[4025]
2016-05-03 16:08:09 +00:00
Romain Quetiez
2513f0489c #185 Navigation Breadcrumb - Identify iTop by the Database and URL (to avoid messing up breadcrumbs when navigating between several instances of iTop - still buggy in case of reinstall)
SVN:trunk[4024]
2016-05-03 15:26:05 +00:00
Denis Flaven
3579f557d1 Support of date and time custom formats... for custom fields !!
SVN:trunk[4023]
2016-05-03 15:17:46 +00:00
Romain Quetiez
668e822fc6 #185 Navigation Breadcrumb - Beta version
- Any page has a breadcrumb (except if POST and a number of pages like "new object")
- Added Home + Menu buttons showed when the left pane is closed
- Configuration: breadcrumb.max_count (0 to disable)


SVN:trunk[4022]
2016-05-03 15:06:14 +00:00
Guillaume Lajarige
dd41dc05f5 Refactoring for AttributeDateTime in the portal
SVN:trunk[4021]
2016-05-03 14:44:12 +00:00
Guillaume Lajarige
f247b89342 Refactoring for AttributeDateTime in the portal
SVN:trunk[4020]
2016-05-03 14:40:56 +00:00
Denis Flaven
5386662146 Support of date and time custom formats... continuing towards the beta !
SVN:trunk[4019]
2016-05-03 09:56:02 +00:00
Romain Quetiez
7d4e9ce069 Refactoring: new API utils::GetCSSFromSASS
SVN:trunk[4018]
2016-04-29 08:04:44 +00:00
Denis Flaven
9fd07125e2 Helper class for date & time format conversions between the various conventions for expressing date & time formats.
SVN:trunk[4017]
2016-04-29 07:53:45 +00:00
Romain Quetiez
5d5b61d956 Wiki syntax: allow white spaces in the specification of a link to an object (form: [[<class>:<friendlyname>]])
SVN:trunk[4016]
2016-04-28 11:48:03 +00:00
Guillaume Lajarige
4d91e92344 Portal :
- Support for attachments in forms
- Added a loader on LinkedSet fields while form is retrieving information on server when adding objects

SVN:trunk[4014]
2016-04-28 08:22:46 +00:00
Guillaume Lajarige
75b32f2552 Attachments : Delete button's label of an attachment was hard-coded. Putted dictionnary entry instead.
SVN:trunk[4013]
2016-04-28 08:19:42 +00:00
Denis Flaven
8eba9ae714 Enhancement: Date and time formats are now configurable in iTop !! (beta version, beware!)
SVN:trunk[4011]
2016-04-22 09:26:27 +00:00
Romain Quetiez
b318d27b19 #1209 Setup or Backup failing with french error message 'Effacement du fichier ...' Regression introduced in [r3868]. Occurs when a backup fails and prevents users from seeing the mysql error report.
SVN:trunk[4010]
2016-04-22 09:26:16 +00:00
Guillaume Lajarige
90cdd28bc8 Portal : Slightly changed the GoHome() function regexp to preserve additional parameters
SVN:trunk[4009]
2016-04-21 13:19:19 +00:00
Denis Flaven
e51a6f8ff2 Bug fix: when a date/time format is specified, don't try to process columns named 'id' since obviously these are neither date/times nor a genuine attribute code.
SVN:trunk[4008]
2016-04-20 12:20:18 +00:00
Guillaume Lajarige
585a73e641 Fixed a typo in German translation files ("Deails für Benutzeranfrage" => "Details für Benutzeranfrage")
SVN:trunk[4007]
2016-04-19 14:41:59 +00:00
Romain Quetiez
2a835e5be4 Internal: query arguments could be array values, making it easier to build dynamic IN() clauses
SVN:trunk[4006]
2016-04-19 13:59:43 +00:00
Romain Quetiez
0386c53a6a #185 Navigation Breadcrumb - Fixed a regression introduced in [r4000]: default menu not displayed afer login
SVN:trunk[4005]
2016-04-19 13:55:12 +00:00
Guillaume Lajarige
e262dbfcf2 Portal : Fixed a bug in linkedset when removing last object
SVN:trunk[4004]
2016-04-19 13:47:24 +00:00
Guillaume Lajarige
8834e1b49c - Added support for ExternalKey, LinkedSet, linkedSetIndirect, CaseLog to the new portal
- Fixed some bugs on the customfields integration with he portal

SVN:trunk[4003]
2016-04-18 15:07:58 +00:00
Denis Flaven
c9c6b2f7d5 Replacing OpenFlashCharts by d3js and c3js: Farewell Flash ! (still an alpha version !)
SVN:trunk[4002]
2016-04-18 14:59:56 +00:00
Denis Flaven
7abb048b7c Replacing OpenFlashCharts by d3js and c3js: Farewell Flash ! (still an alpha version !)
SVN:trunk[4001]
2016-04-18 14:56:02 +00:00
Romain Quetiez
e27d61a525 #185 Navigation Breadcrumb - A beta version, based on the navigation history. Comments welcome!
SVN:trunk[4000]
2016-04-18 14:48:43 +00:00
Romain Quetiez
f436cece4a OQL arguments: when the value of a query argument is null, it must be considered as being a valid argument (was reported as missing). Improved the error reporting when the argument is in the form :this->attcode and the attcode is not valid for the class of 'this'.
SVN:trunk[3999]
2016-04-15 15:07:35 +00:00
Romain Quetiez
e7eb1ec7e3 CustomFields: simplified the wizard helper to cope with the edition in read-only mode (no need for the wizard helper to send the read-only/hidden values !)
SVN:trunk[3998]
2016-04-15 14:15:07 +00:00
Romain Quetiez
21564ff340 CustomFields: overload AttributeDefinition::Fingerprint
SVN:trunk[3997]
2016-04-15 09:05:39 +00:00
Denis Flaven
c32ef34307 Additional Dict entries for the bulk export parameters: keeping/removing HTML markup when exporting.
SVN:trunk[3996]
2016-04-15 08:51:52 +00:00
Romain Quetiez
2d05b110b8 Cosmetic: improved the feedback when an attribute edition control is being refreshed in the console
SVN:trunk[3995]
2016-04-11 19:02:54 +00:00
Romain Quetiez
25287a8c04 XSS: Correctly escape the name of an object when it is displayed within an hyperlink
SVN:trunk[3994]
2016-04-11 11:51:59 +00:00
Romain Quetiez
e877ec431f HTML to Text conversion not working if mb_string not present (verb mb_split)
SVN:trunk[3993]
2016-04-08 12:02:29 +00:00
Romain Quetiez
272051ea99 Internal: added verb ormCaseLog::GetAsArray()
SVN:trunk[3992]
2016-04-08 10:59:01 +00:00
Romain Quetiez
725c7d45d1 Internal: Implemented DBObject::ExecActions, enables scripting object preset/modifications
SVN:trunk[3991]
2016-04-08 07:34:38 +00:00
Denis Flaven
b991f0a6c6 Fix for a crash in the setup (regression) introduced by [r3978] (optimization of the load of dictionaries)
SVN:trunk[3990]
2016-04-07 16:11:10 +00:00
Denis Flaven
ed035b3699 YOU MUST RUN THE SETUP AFTER PERFORMING THIS UPDATE !!
- Better handling of  'auto_select' modules
- New way of implementing the "includes" of modules, now completely out of the configuration file !

SVN:trunk[3989]
2016-04-07 16:00:01 +00:00
Romain Quetiez
e9f57fd9e2 CustomFields: support of DurationField (started devs for DateField and DateTimeField)
SVN:trunk[3988]
2016-04-06 10:25:11 +00:00
Romain Quetiez
fd124ef53b CustomFields: support of RadioField or SelectObject +"radio" control
SVN:trunk[3987]
2016-04-06 09:21:01 +00:00
Romain Quetiez
0259071bdd Internal: fixed typo in utils::TextToHtml()
SVN:trunk[3986]
2016-04-06 09:17:10 +00:00
Denis Flaven
32ce26aa7d Fix for potential XSS vulnerability on uploaded file names. To be further tested before retrofitting in branches.
SVN:trunk[3985]
2016-04-05 16:15:29 +00:00
Romain Quetiez
3997ea3a23 CustomFields: support of TextAreaField
SVN:trunk[3984]
2016-04-05 13:12:25 +00:00
Romain Quetiez
f41c4f80f8 CustomFields: implemented the autocomplete behavior for SelectObjectField
SVN:trunk[3983]
2016-04-05 09:41:26 +00:00
Romain Quetiez
3eacf2e7fa Internal: typo in the reporting of page spurious chars
SVN:trunk[3982]
2016-04-05 08:52:57 +00:00
Romain Quetiez
c3f804bb29 CustomFields: fixed typos preventing fields from adding custom javascript/css files to the page
SVN:trunk[3981]
2016-04-05 08:46:51 +00:00
Guillaume Lajarige
1784653678 Cleanup and optimization of the handling/loading of the dictionary files.
SVN:trunk[3980]
2016-04-04 13:56:36 +00:00
Denis Flaven
447fc85867 Optimization: load "pdftage" (and thus tcpdf) only when needed.
SVN:trunk[3979]
2016-04-04 13:44:59 +00:00
Denis Flaven
f3773f6047 Cleanup and optimization of the handling/loading of the dictionary files.
SVN:trunk[3978]
2016-04-04 13:44:15 +00:00
Guillaume Lajarige
b741532231 New API for SelectObjectField, replaced OQL query by DBSearch
SVN:trunk[3977]
2016-04-04 10:22:57 +00:00
Romain Quetiez
f01bd61692 CustomFields: suppressed a warning when editing an object with a custom field being read-only
SVN:trunk[3976]
2016-04-04 10:00:54 +00:00
Romain Quetiez
a5d3208599 CustomFields: Attributes of type CustomFields must be removed when converting from 1.3 to 1.2
SVN:trunk[3975]
2016-03-31 15:00:02 +00:00
Guillaume Lajarige
f3cc54fe8d Updated licences file with Bootstrap and DataTables
SVN:trunk[3974]
2016-03-31 13:06:46 +00:00
Romain Quetiez
70e0fab267 Fixed regression introduced with [3912] and partially fixed in [3954] : when the autocomplete is active, then the search dialog was not working anymore.
SVN:trunk[3972]
2016-03-30 12:11:57 +00:00
Romain Quetiez
7868c4364c Label of the final class attribute could only be defined on the root class (overriding it in derived classes had no effect)
SVN:trunk[3971]
2016-03-29 14:22:13 +00:00
Guillaume Lajarige
2a5ca467fd Alpha 2.3.0 fixes :
- Multiple request templates on portal
- SelectField interface stabilization
- UI fixes on portal
- Forms updates on lifecycle

SVN:trunk[3970]
2016-03-29 12:33:08 +00:00
Romain Quetiez
2ab12d9d11 #1221 Exclude git folder from the copied folders, during the compilation process
SVN:trunk[3969]
2016-03-25 15:22:52 +00:00
Romain Quetiez
0104c3fe41 ResetStopWatch could not be used as a lifecycle action: the symptom is "The action has failed".
SVN:trunk[3967]
2016-03-25 10:02:29 +00:00
Romain Quetiez
847c1d2736 Custom fields: track the changes and improve the robustness with regards to the Exception thrown by the handler. Also fixed an issue with DBObject, causing the custom fields to be written several times if invoking DBUpdate more than once. Theoretically, this issue affects any type of attribute.
SVN:trunk[3966]
2016-03-24 10:49:04 +00:00
Romain Quetiez
922354320b Code refactoring: removed a debug trace
SVN:trunk[3965]
2016-03-24 10:40:54 +00:00
Romain Quetiez
462af27157 Custom fields: comparing two sets of values is delegated to the custom fields handler because the values must be interpreted before concluding (blind comparison resulted in objects being written though the values were equivalent)
SVN:trunk[3964]
2016-03-22 16:55:51 +00:00
Romain Quetiez
ea31d71d16 Custom fields: check data against the form prior to recording (do not rely solely on the HTML form)
SVN:trunk[3963]
2016-03-22 09:02:03 +00:00
Romain Quetiez
2150682a92 Custom fields: values not recorded if the user does not change any of the default values
SVN:trunk[3962]
2016-03-22 08:59:15 +00:00
Guillaume Lajarige
24fcb20927 Form : Started fix on CaseLog field in the portal. Only the edit value is now in the editor. Still have to display the history below.
SVN:trunk[3961]
2016-03-18 15:04:49 +00:00
Romain Quetiez
414b94405b Custom fields: better error reporting when an exception occurs while finalizing the form
SVN:trunk[3960]
2016-03-18 14:49:59 +00:00
Guillaume Lajarige
5328feb58b Form : Added LabelField class for forms.
SVN:trunk[3959]
2016-03-18 14:15:30 +00:00
Guillaume Lajarige
bc7176f07e Form : Fixed call to form_field::validate on fields with no form_field widget (typically LabelField)
SVN:trunk[3958]
2016-03-18 14:14:06 +00:00
Denis Flaven
8f4a8fc7be New icon for the new portal.
SVN:trunk[3957]
2016-03-18 11:40:38 +00:00
Romain Quetiez
81317d4df9 Custom fields: better error reporting when an exception occurs while finalizing the form
SVN:trunk[3956]
2016-03-18 10:35:09 +00:00
Guillaume Lajarige
af87ef3623 Form : Fixed dependancies check in Form::Finalize()
SVN:trunk[3955]
2016-03-17 15:25:33 +00:00
Romain Quetiez
c201ae4147 Fixed regression introduced with [3912] : autocomplete not working (new User request with lots of existing user requests)
SVN:trunk[3954]
2016-03-17 14:04:48 +00:00
Guillaume Lajarige
37e3cb6285 Form : Added some translations to the new form system
SVN:trunk[3953]
2016-03-16 16:46:58 +00:00
Guillaume Lajarige
4b7fb20eaf DBSearch : Allow join between DBUnionSearch by adding the DBUnionSearch::Join verb
SVN:trunk[3952]
2016-03-16 16:45:39 +00:00
Romain Quetiez
92d9c778e5 Prerequisites to the portal forms:
- finalize form fields in the order of their dependencies
- introduced the SelectObjectField which will implement an autocomplete (currently remains a drop-down whatever the number of items)
- code refactoring

SVN:trunk[3951]
2016-03-16 09:09:30 +00:00
Denis Flaven
1c90cd2312 Initial feedback whilie loading the 'list' tab of the impact analysis, useful when this tab is displayed first.
SVN:trunk[3949]
2016-03-15 09:39:59 +00:00
Romain Quetiez
4006fce0f2 Exclude magic parameters when listing query parameters (refactoring from run_query) This enables the use of magic parameters in the exports. The issue was less exposed in iTop 2.2.0 because only one single magic parameter was available.
SVN:trunk[3948]
2016-03-11 20:42:04 +00:00
Guillaume Lajarige
a31be78cbd CustomFields : Fixed a regression in field_set.js during validation due to touched_fields what were no longer in the form when switching templates
SVN:trunk[3947]
2016-03-11 16:03:19 +00:00
Romain Quetiez
f29af948be Custom fields: not all the values were correctly recorded (event name collision)
SVN:trunk[3946]
2016-03-11 15:05:59 +00:00
Guillaume Lajarige
44ba3d7bf8 CustomFields : Bootstrap integration
SVN:trunk[3945]
2016-03-11 14:34:16 +00:00
Guillaume Lajarige
7ea5176b56 CustomFields : Bootstrap integration
SVN:trunk[3944]
2016-03-11 12:42:21 +00:00
Romain Quetiez
e6887ab317 Custom fields: alpha version.
SVN:trunk[3943]
2016-03-10 16:55:13 +00:00
Denis Flaven
67c92ab946 Modified the "List" tab of the Impact Analysis to display only the actually impacted objects. The content of this tab is now refreshed every time the graph is rebuilt to take into account the "context" changes which causes the actual impact to change, or the filtering.
SVN:trunk[3941]
2016-03-09 18:05:14 +00:00
Guillaume Lajarige
daa090d4fe Prerequisites to the custom fields
SVN:trunk[3940]
2016-03-09 16:58:31 +00:00
Romain Quetiez
ced87e71cb Magic query arguments - fixed a regression: URL exceeding 4000 characters (!) because the serialized queries were including magic arguments. Those arguments must be computed right before executing the query. An alternative to this implementation could be to serialize a DBSearch with its parameters computed at serialization time.
SVN:trunk[3939]
2016-03-04 15:03:46 +00:00
Romain Quetiez
e26eed3142 #1210 (reopened) ...fixed a regression on commit [r3936]: dependent fields could not be loaded when there are link set attribute in the current form
SVN:trunk[3938]
2016-03-04 14:22:13 +00:00
Romain Quetiez
d33dad51f8 Prerequisites for custom fields
SVN:trunk[3937]
2016-03-02 16:16:42 +00:00
Romain Quetiez
37f6c6ed7d #1210 Dependant field not reset (servicesubcategory not reset when service is reset)
SVN:trunk[3936]
2016-03-01 14:29:35 +00:00
Denis Flaven
7e3d526de3 Background process for cleaning expired temporary attachments and inline images.
SVN:trunk[3935]
2016-02-29 17:20:43 +00:00
Denis Flaven
53029f9fc3 Optimization/bug (!): Never use the whole object as a placeholder in ApplyParams !!
SVN:trunk[3931]
2016-02-29 16:20:41 +00:00
Denis Flaven
22ccb317d6 Optimization: do not load all columns when checking if a CI is part of the "context" of a given ticket.
SVN:trunk[3929]
2016-02-29 15:47:52 +00:00
Guillaume Lajarige
ad91dc14b8 Prerequisites to the custom fields
SVN:trunk[3928]
2016-02-26 16:10:57 +00:00
Denis Flaven
6bd89f31d3 Prevent access to *any* InlineImage by just guessing its identifier, now an additional "secret" is needed, making it much harder to guess (but not 100% impossible, beware !)
SVN:trunk[3927]
2016-02-26 10:18:46 +00:00
Denis Flaven
608e94a613 Inline images in formatted case log & descriptions: beta version fixperms js The inline images are now no longer stored stored as Attachments but using a specific object InlineImage...
SVN:trunk[3926]
2016-02-25 15:06:04 +00:00
Denis Flaven
9c16b08e22 (HTML) Formatted Case Logs, Description and Notifications with inline images uploaded as Attachments. Beta Version !! - fix for missing magnificPopup()
SVN:trunk[3925]
2016-02-22 14:20:53 +00:00
Denis Flaven
63b6b95f71 Use one-way encryption for storing the token used for the "Forgotten password" feature.
SVN:trunk[3920]
2016-02-19 18:17:11 +00:00
Guillaume Lajarige
17127a5157 Prerequisites to the custom fields (and space tabs to regular tabs conversion on some files)
SVN:trunk[3919]
2016-02-19 16:43:28 +00:00
Romain Quetiez
bfadbc4098 Prerequisites for custom fields
SVN:trunk[3918]
2016-02-19 12:30:19 +00:00
Romain Quetiez
08c6bb5c5e Prerequisites for custom fields
SVN:trunk[3917]
2016-02-19 11:11:09 +00:00
Denis Flaven
4e24e9899e (HTML) Formatted Case Logs, Description and Notifications with inline images uploaded as Attachments. Beta Version !!
SVN:trunk[3916]
2016-02-19 10:03:59 +00:00
Denis Flaven
c72bdae8d7 Upgrading to CKEditor v4 !!
SVN:trunk[3915]
2016-02-19 09:32:58 +00:00
Denis Flaven
3687657dd7 Upgrading to CKEditor v4
SVN:trunk[3914]
2016-02-19 09:23:45 +00:00
Romain Quetiez
21f0adb41b Prerequisites for custom fields
SVN:trunk[3913]
2016-02-19 08:49:14 +00:00
Romain Quetiez
e0fad5e0e6 Magic query arguments:
- In addition to current_contact_id, the following arguments can be used in any OQL query (provided that the page running the query requires a  login): current_contact->attcode and current_user->attcode
- Code refactoring: magic arguments in one single place
- The "Run queries" page is now taking into account those magic arguments (do not prompt the end-user with these arguments!)

SVN:trunk[3912]
2016-02-17 18:55:46 +00:00
Guillaume Lajarige
77f8129fac Prerequisites to the custom fields
SVN:trunk[3911]
2016-02-12 13:44:10 +00:00
Guillaume Lajarige
064ae11ba8 Prerequisites to the custom fields
SVN:trunk[3910]
2016-02-11 15:25:03 +00:00
Guillaume Lajarige
d7a69118bc Prerequisites to the custom fields
SVN:trunk[3909]
2016-02-11 15:24:29 +00:00
Romain Quetiez
f2fabe4eec Prerequisites to the custom fields
SVN:trunk[3908]
2016-02-11 14:23:35 +00:00
Romain Quetiez
dc92e40429 Prerequisites to the custom fields
SVN:trunk[3907]
2016-02-11 10:55:41 +00:00
Guillaume Lajarige
9c080d51f7 Prerequisites to the custom fields
SVN:trunk[3903]
2016-02-11 10:26:06 +00:00
Denis Flaven
cf0541c93e #1202: Fix for a security vulnerability in the Configuration Editor.
SVN:trunk[3902]
2016-02-11 10:22:53 +00:00
Romain Quetiez
54be542355 Prerequisites to the custom fields
SVN:trunk[3901]
2016-02-10 15:46:05 +00:00
Romain Quetiez
225ace0d02 Preparing release 2.2.1
SVN:trunk[3898]
2016-02-03 13:16:40 +00:00
Romain Quetiez
ca24ae9632 #1196 Only administrators can add attachments by the mean of the REST/JSON API
SVN:trunk[3896]
2016-02-03 13:01:43 +00:00
Denis Flaven
9f69fd0811 #1193: When creating new object from tab with <edit_mode>add_only</edit_mode> id of the parent object was not transfered to the form. Fix provided by Vladimir Kunin. Thank you Vladimir.
SVN:trunk[3894]
2016-02-02 13:31:02 +00:00
Romain Quetiez
b978a5d219 Fixed regression introduced in [3852] : setup not working anymore ($_SESSION is unset and a notice is issued, which can prevent the install from completing, depending on your PHP error level).
SVN:trunk[3891]
2016-01-28 11:11:12 +00:00
Romain Quetiez
e7759aa79a Fixed regression introduced by [3857] : setup not working anymore (js files could not be loaded anymore)
SVN:trunk[3890]
2016-01-28 11:05:13 +00:00
Guillaume Lajarige
1f4ca07b5f Foundations for the new form system
SVN:trunk[3889]
2016-01-28 10:37:32 +00:00
Denis Flaven
3ecd768982 Enhanced statistics at the end of the setup.
SVN:trunk[3887]
2016-01-27 10:42:21 +00:00
Romain Quetiez
3cfcbeb654 Internal: fixed the verb DBObjectSearch::IsAny
SVN:trunk[3886]
2016-01-26 14:49:37 +00:00
Guillaume Lajarige
e1409ba39c Fixed a regression due to the DesignDocument factorisation :
- DesignDocument class : Namespace issue with DOMFormatException
- Compiler class : Parameters 2 & 3 of the DOMFormatException constructor needed to have a default value

SVN:trunk[3885]
2016-01-26 14:34:53 +00:00
Denis Flaven
172e255cc2 #1174: support HTML fields in the bulk modify forms (capability to enable/disable the field live)
SVN:trunk[3883]
2016-01-26 14:32:51 +00:00
Denis Flaven
ef6299c6b4 #1183: more refactoring and some robustness enhancements after tests on big datasets.
SVN:trunk[3881]
2016-01-26 13:22:47 +00:00
Denis Flaven
8a99b09e83 #1153: preserve leading zeroes (in "numeric" fields) in the Excel export.
SVN:trunk[3879]
2016-01-26 09:50:35 +00:00
Denis Flaven
9da19de860 Suppress "Notice" messages when iconv detects invalid UTF-8 characters, since it breaks the JSON output if display_errors in On...
SVN:trunk[3878]
2016-01-25 17:10:39 +00:00
Romain Quetiez
b8af72b402 Modules: added a mean to cache data that will be reset upon compilation. To be used in conjunction with ModuleDesign.
SVN:trunk[3877]
2016-01-25 16:47:05 +00:00
Denis Flaven
764c551f0f #1183: grouping threshold is now taken int account for "Depends on..." graphs (i.e. grouping backwards)
SVN:trunk[3875]
2016-01-25 14:33:00 +00:00
Denis Flaven
410c47178d #1176: empty placeholders are represented by an empty string as in previous version.
SVN:trunk[3873]
2016-01-25 12:46:56 +00:00
Denis Flaven
f53ce84f5d IconSelectorField (Design time !) can be read-only.
SVN:trunk[3871]
2016-01-21 16:02:42 +00:00
Romain Quetiez
ab0d425d93 XML: compilation error if there is no tag module_designs (completes revisions 3820 and 3861 which introduced the issue)
SVN:trunk[3870]
2016-01-21 15:36:23 +00:00
Romain Quetiez
95ca14b05c #1165 backup with errors fills up tmp-directories with lots of backup-files.
SVN:trunk[3868]
2016-01-21 14:55:31 +00:00
Denis Flaven
61e2f97d6c #1150: Spurious message "A restore is running..." - FIXED !
SVN:trunk[3864]
2016-01-20 15:56:09 +00:00
Romain Quetiez
9e6c024beb Model Factory: factorized duplicate code from ApplyChanges + fixed an issue in the error reporting
SVN:trunk[3863]
2016-01-20 13:01:58 +00:00
Guillaume Lajarige
879f5d89b9 Moved static method GetAllowedPortals() from LoginWebpage class to UserRights class.
SVN:trunk[3862]
2016-01-15 10:32:17 +00:00
Romain Quetiez
161041d379 XML: the images specified in the branding or in module_designs can be given as a fileref or a path relative to the env-production directory
SVN:trunk[3861]
2016-01-15 09:21:32 +00:00
Romain Quetiez
6d23d64e8f Code refactoring: eliminated duplicate code between MFDocument and ModuleDesign
SVN:trunk[3860]
2016-01-14 14:11:25 +00:00
Romain Quetiez
8c4e84dfaf New type of attribute: AttributeMetaEnum.
Designed to cope with the need to select tickets by operational status. The value of this attribute is computed by the framework. It depends on the actual ticket status (that attribute cannot be known by the root class because its definition varies from one type of ticket to another).
The data model has been enriched with the new attribute Ticket::operational_status. Its value is 'active' unless the ticket status is either 'rejected', 'resolved' or 'closed'. The existing dashboards have been left unchanged but should be revised to fully benefit from the new attribute (e.g. Open requests, Open problems, etc.)
Note: the alpha version of the compiler had already been committed by mistake a few days ago.

SVN:trunk[3859]
2016-01-13 14:35:21 +00:00
Romain Quetiez
706940769b Compiler: Model alterations not flattened prior to compilation (when using the setup UI) -no need for doing the job twice (compiling from within the toolkit)
SVN:trunk[3858]
2016-01-12 10:32:46 +00:00
Romain Quetiez
3fe2aa3b1d Portal: Use absolute URLs for js+css embedded into iTop (login prompt not working with the usage of symlinks or rewrite rules)
SVN:trunk[3857]
2016-01-12 09:15:37 +00:00
Guillaume Lajarige
1f4d7f2a32 Updated licenses with Silex
SVN:trunk[3856]
2016-01-11 15:34:33 +00:00
Guillaume Lajarige
57f0cce318 Added Silex framework
SVN:trunk[3855]
2016-01-11 15:32:14 +00:00
Romain Quetiez
e95d0a4722 Compiler: Model alterations not flattened prior to compilation (when using the setup UI)
SVN:trunk[3854]
2016-01-11 14:28:02 +00:00
Denis Flaven
f37030fe26 internal: new autoOpen flag.
SVN:trunk[3853]
2016-01-06 17:38:05 +00:00
Romain Quetiez
3be0bc8ca8 Improved the User Rights management API:
- new verbs: HasProfile and ListProfiles
- doing less queries (no need for listing all the profiles, caching the user profiles into the SESSION cookie
- did some code cleanup (unused variables)

SVN:trunk[3852]
2015-12-15 20:30:30 +00:00
Denis Flaven
65a7a8ee56 Properly read radio button values inside a form.
SVN:trunk[3849]
2015-12-14 13:02:08 +00:00
Romain Quetiez
ab38ce63a5 Portal: let the administrator specify an alternative URL for the portals (rewriting rules)
SVN:trunk[3848]
2015-12-10 13:06:42 +00:00
Denis Flaven
e92c6e5298 (internal) Remove _altered_in when exporting the delta.
SVN:trunk[3847]
2015-12-09 15:23:46 +00:00
Denis Flaven
76df404c8d Keep track of which module altered which node in the XML.
SVN:trunk[3845]
2015-12-09 14:56:51 +00:00
Guillaume Lajarige
d3a2841fef Error : Deleted files from a wrong commit.
SVN:trunk[3844]
2015-12-07 11:47:17 +00:00
Guillaume Lajarige
d60a4aa740 Portal : Sample to show how to alter a twig template in the portal. This sample replaces the main page layout by putting the navigation bar on the left side (except for mobile where it stays on the top).
SVN:trunk[3843]
2015-12-04 12:57:50 +00:00
Guillaume Lajarige
6538d7af1e DOMFormatException : Overloaded the constructor to add an optionnal parameter $node (\DOMNode) that will append informations about the node and the exception line number to $message.
SVN:trunk[3842]
2015-12-02 10:46:00 +00:00
Guillaume Lajarige
c69279ee20 Fixed a typo in ModuleDesignElement->Dump() function. Was creating an object of iTopDesignDocument class instead of ModuleDesign class.
SVN:trunk[3839]
2015-12-02 10:38:24 +00:00
Denis Flaven
a16e746aa1 Fixed the computation of the lowest common ancestor.
SVN:trunk[3837]
2015-12-02 10:32:37 +00:00
Romain Quetiez
b1f62c8409 Internal: dehardcoded OqlUnionQuery::GetClass against the metamodel reflection API
SVN:trunk[3836]
2015-12-01 16:23:35 +00:00
Romain Quetiez
4a85f7f12b Added AttributeDef::EnumTemplateVerbs, to generate the documentation about the available attribute formatting placeholders
SVN:trunk[3835]
2015-11-30 16:56:22 +00:00
Denis Flaven
818be68c2d Make sure we don't redefine CoreException.
SVN:trunk[3833]
2015-11-30 14:07:18 +00:00
Denis Flaven
7511391aed Added structured error reporting in case of missing dependencies for the modules to install.
SVN:trunk[3831]
2015-11-25 16:55:58 +00:00
Denis Flaven
d0a50adf32 Properly create DOMNodes with a text content (beware of XML entities inside the text)
SVN:trunk[3829]
2015-11-25 16:52:49 +00:00
Denis Flaven
c9576c696a Support validation patterns contains a forward slash
SVN:trunk[3827]
2015-11-25 16:49:20 +00:00
Guillaume Lajarige
908b442b26 Core : Added CloneWithAlias function to DBSearch class. It creates a new DBObjectSearch from a DBSearch with a new alias.
SVN:trunk[3826]
2015-11-25 11:16:30 +00:00
Denis Flaven
9687e9985e Support of derived classes in "add_remove" edition mode for AttributeLinkSet fields (the search form was not refreshing / loading properly when toggling the class to search for).
SVN:trunk[3822]
2015-11-20 14:16:07 +00:00
Romain Quetiez
07e4b18d06 #1173 Error during setup on a development system (XML containing unwanted text)
SVN:trunk[3821]
2015-11-16 15:16:28 +00:00
Romain Quetiez
93654dc656 Core: a module can have its own design defined in XML (/itop_design/modules_designs/module_design) and accessed at run time via the class ModuleDesign. Switching to XML version 1.3.
SVN:trunk[3820]
2015-11-10 12:39:45 +00:00
Denis Flaven
4be5334829 Make ReloadSearchForm work properly when the "submit" event handler is declared either with or without a "namespace" portion (e.g. 'submit.itop' vs 'submit')
SVN:trunk[3816]
2015-11-09 10:43:01 +00:00
Romain Quetiez
0f4301af01 Core API: added DBSearch:SetSelectedClasses
SVN:trunk[3815]
2015-11-09 10:35:51 +00:00
Romain Quetiez
b071c47674 PHP warning issued when the CSS is rebuilt (SASS lib)
SVN:trunk[3814]
2015-11-09 10:26:11 +00:00
Romain Quetiez
05e9f394f0 Improved the error reporting when assembling data model XML files (full path and line number of the faulty node)
SVN:trunk[3813]
2015-11-06 11:35:46 +00:00
Denis Flaven
2027becad2 #1164: typo in German localization.
SVN:trunk[3811]
2015-10-26 10:57:40 +00:00
Denis Flaven
e7170755d8 Support the download of "bigger-than-memory" backup files.
SVN:trunk[3809]
2015-10-26 10:38:57 +00:00
Romain Quetiez
d0a0d3c93c Fixed regressions due to the recent code refactoring [3803]
SVN:trunk[3807]
2015-10-12 15:35:05 +00:00
Denis Flaven
2db785477c Do NOT localize finalclass values in REST/JSON.
SVN:trunk[3805]
2015-10-12 12:39:09 +00:00
Denis Flaven
31ec3152f9 Code refactoring to make the OQL parsing self contained in the "oql" subdirectory.
SVN:trunk[3803]
2015-10-12 10:01:59 +00:00
Denis Flaven
7b8b469f5a Added a version number (arbitrary initialized to 2015-08-31 for iTop v2.2.0) to the OQL Lexer/parser.
SVN:trunk[3801]
2015-10-12 09:52:39 +00:00
Romain Quetiez
bc4737ac23 #1159 Cannot add edge (impact analysis not working)
SVN:trunk[3799]
2015-10-09 15:25:18 +00:00
Denis Flaven
6dc190d369 Do not rely on MetaModel::GetRootClass() to check the data model, use the abstraction of ModelReflection instead to keep the code portable.
SVN:trunk[3797]
2015-10-08 15:54:23 +00:00
Denis Flaven
9980d2e72a #1156: properly escape file paths containing spaces
SVN:trunk[3795]
2015-10-05 19:52:06 +00:00
Denis Flaven
2d34510f50 Better error reporting when the setup fails to create a directory.
SVN:trunk[3793]
2015-09-30 14:08:04 +00:00
Romain Quetiez
ef57f870ac Internal - MFFactory: fixed GetDelta when there is no change at all
SVN:trunk[3792]
2015-09-28 12:49:54 +00:00
4796 changed files with 563532 additions and 255214 deletions

9
.gitflow Normal file
View File

@@ -0,0 +1,9 @@
[gitflow "branch"]
master = master
develop = develop
[gitflow "prefix"]
feature = feature/
release = release/
hotfix = hotfix/
versiontag =
support = support/

123
.gitignore vendored Normal file
View File

@@ -0,0 +1,123 @@
/toolkit
/conf/*
/env-*/*
# composer reserver directory, from sources, populate/update using "composer install"
vendor/*
test/vendor/*
# all datas but listing prevention
data/*
!data/.htaccess
!data/index.php
!data/web.config
# iTop extensions
extensions/*
!extensions/readme.txt
# all logs but listing prevention
log/*
!log/.htaccess
!log/index.php
!log/web.config
# Jetbrains
.idea/**
!.idea/encodings.xml
!.idea/codeStyles
!.idea/codeStyles/*
!.idea/inspectionProfiles
!.idea/inspectionProfiles/*
# CMake
cmake-build-*/
# Mongo Explorer plugin
.idea/**/mongoSettings.xml
# File-based project format
*.iws
# IntelliJ
out/
# mpeltonen/sbt-idea plugin
.idea_modules/
# JIRA plugin
atlassian-ide-plugin.xml
# Cursive Clojure plugin
.idea/replstate.xml
# Crashlytics plugin (for Android Studio and IntelliJ)
com_crashlytics_export_strings.xml
crashlytics.properties
crashlytics-build.properties
fabric.properties
# Editor-based Rest Client
.idea/httpRequests
### Eclipse template
.metadata
tmp/
*.tmp
*.bak
*.swp
*~.nib
local.properties
.settings/
.loadpath
.recommenders
.project
# External tool builders
.externalToolBuilders/
# Locally stored "Eclipse launch configurations"
*.launch
# PyDev specific (Python IDE for Eclipse)
*.pydevproject
# CDT-specific (C/C++ Development Tooling)
.cproject
# CDT- autotools
.autotools
# Java annotation processor (APT)
.factorypath
# PDT-specific (PHP Development Tools)
.buildpath
# sbteclipse plugin
.target
# Tern plugin
.tern-project
# TeXlipse plugin
.texlipse
# STS (Spring Tool Suite)
.springBeans
# Code Recommenders
.recommenders/
# Annotation Processing
.apt_generated/
# Scala IDE specific (Scala & Java development for Eclipse)
.cache-main
.scala_dependencies
.worksheet

57
.idea/codeStyles/Project.xml generated Normal file
View File

@@ -0,0 +1,57 @@
<component name="ProjectCodeStyleConfiguration">
<code_scheme name="Project" version="173">
<option name="LINE_SEPARATOR" value="&#10;" />
<option name="RIGHT_MARGIN" value="320" />
<HTMLCodeStyleSettings>
<option name="HTML_DO_NOT_INDENT_CHILDREN_OF" value="html,body,thead,tbody,tfoot,script,style" />
<option name="HTML_DO_NOT_ALIGN_CHILDREN_OF_MIN_LINES" value="4" />
</HTMLCodeStyleSettings>
<PHPCodeStyleSettings>
<option name="CONCAT_SPACES" value="false" />
<option name="PHPDOC_BLANK_LINE_BEFORE_TAGS" value="true" />
<option name="PHPDOC_BLANK_LINES_AROUND_PARAMETERS" value="true" />
<option name="PHPDOC_WRAP_LONG_LINES" value="true" />
<option name="LOWER_CASE_BOOLEAN_CONST" value="true" />
<option name="LOWER_CASE_NULL_CONST" value="true" />
<option name="BLANK_LINES_BEFORE_RETURN_STATEMENT" value="1" />
<option name="KEEP_RPAREN_AND_LBRACE_ON_ONE_LINE" value="true" />
<option name="PHPDOC_USE_FQCN" value="true" />
</PHPCodeStyleSettings>
<codeStyleSettings language="JavaScript">
<option name="BRACE_STYLE" value="2" />
<option name="ELSE_ON_NEW_LINE" value="true" />
<option name="IF_BRACE_FORCE" value="3" />
<indentOptions>
<option name="USE_TAB_CHARACTER" value="true" />
</indentOptions>
</codeStyleSettings>
<codeStyleSettings language="PHP">
<option name="RIGHT_MARGIN" value="320" />
<option name="BLANK_LINES_AFTER_PACKAGE" value="1" />
<option name="BRACE_STYLE" value="2" />
<option name="ELSE_ON_NEW_LINE" value="true" />
<option name="ALIGN_MULTILINE_PARAMETERS" value="false" />
<option name="SPACE_BEFORE_FOR_PARENTHESES" value="false" />
<option name="CALL_PARAMETERS_WRAP" value="1" />
<option name="METHOD_PARAMETERS_WRAP" value="1" />
<option name="METHOD_PARAMETERS_LPAREN_ON_NEXT_LINE" value="true" />
<option name="METHOD_PARAMETERS_RPAREN_ON_NEXT_LINE" value="true" />
<option name="ARRAY_INITIALIZER_WRAP" value="5" />
<option name="ARRAY_INITIALIZER_LBRACE_ON_NEXT_LINE" value="true" />
<option name="ARRAY_INITIALIZER_RBRACE_ON_NEXT_LINE" value="true" />
<option name="IF_BRACE_FORCE" value="3" />
<option name="DOWHILE_BRACE_FORCE" value="3" />
<option name="WHILE_BRACE_FORCE" value="3" />
<option name="FOR_BRACE_FORCE" value="3" />
<indentOptions>
<option name="USE_TAB_CHARACTER" value="true" />
<option name="SMART_TABS" value="true" />
</indentOptions>
</codeStyleSettings>
<codeStyleSettings language="XML">
<indentOptions>
<option name="USE_TAB_CHARACTER" value="true" />
</indentOptions>
</codeStyleSettings>
</code_scheme>
</component>

5
.idea/codeStyles/codeStyleConfig.xml generated Normal file
View File

@@ -0,0 +1,5 @@
<component name="ProjectCodeStyleConfiguration">
<state>
<option name="PREFERRED_PROJECT_CODE_STYLE" value="Combodo" />
</state>
</component>

6
.idea/encodings.xml generated Normal file
View File

@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="Encoding" defaultCharsetForPropertiesFiles="UTF-8">
<file url="PROJECT" charset="UTF-8" />
</component>
</project>

44
.idea/inspectionProfiles/Combodo.xml generated Normal file
View File

@@ -0,0 +1,44 @@
<component name="InspectionProjectProfileManager">
<profile version="1.0">
<option name="myName" value="Combodo" />
<inspection_tool class="InconsistentLineSeparators" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="MysqlParsingInspection" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="PhpIncludeInspection" enabled="true" level="WEAK WARNING" enabled_by_default="true" />
<inspection_tool class="PhpMethodParametersCountMismatchInspection" enabled="true" level="ERROR" enabled_by_default="true" />
<inspection_tool class="PhpTooManyParametersInspection" enabled="true" level="WARNING" enabled_by_default="true">
<option name="limit" value="7" />
</inspection_tool>
<inspection_tool class="PhpUndefinedClassInspection" enabled="true" level="WARNING" enabled_by_default="true">
<option name="DONT_REPORT_MULTI_RESOLVE" value="true" />
</inspection_tool>
<inspection_tool class="PhpUndefinedMethodInspection" enabled="true" level="WEAK WARNING" enabled_by_default="true" />
<inspection_tool class="PhpUnhandledExceptionInspection" enabled="true" level="WEAK WARNING" enabled_by_default="true" />
<inspection_tool class="PhpUnusedLocalVariableInspection" enabled="true" level="WEAK WARNING" enabled_by_default="true">
<option name="DONT_REPORT_INSIDE_LIST" value="true" />
</inspection_tool>
<inspection_tool class="PhpUnusedParameterInspection" enabled="true" level="WEAK WARNING" enabled_by_default="true">
<option name="DONT_REPORT_ABSTRACT_CLASS" value="true" />
</inspection_tool>
<inspection_tool class="SqlAddNotNullColumnInspection" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="SqlAmbiguousColumnInspection" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="SqlAutoIncrementDuplicateInspection" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="SqlCheckUsingColumnsInspection" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="SqlConstantConditionInspection" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="SqlDeprecateTypeInspection" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="SqlDerivedTableAliasInspection" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="SqlDialectInspection" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="SqlDropIndexedColumnInspection" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="SqlIdentifierInspection" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="SqlInsertValuesInspection" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="SqlNoDataSourceInspection" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="SqlNullComparisonInspection" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="SqlPostgresqlSelectFromProcedureInspection" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="SqlResolveInspection" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="SqlShouldBeInGroupByInspection" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="SqlSideEffectsInspection" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="SqlSignatureInspection" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="SqlStorageInspection" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="SqlTypeInspection" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="SqlUnusedVariableInspection" enabled="false" level="WARNING" enabled_by_default="false" />
</profile>
</component>

View File

@@ -0,0 +1,19 @@
<component name="InspectionProjectProfileManager">
<profile version="1.0">
<option name="myName" value="Project Default" />
<inspection_tool class="InconsistentLineSeparators" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="PhpIncludeInspection" enabled="true" level="WEAK WARNING" enabled_by_default="true" />
<inspection_tool class="PhpMethodParametersCountMismatchInspection" enabled="true" level="ERROR" enabled_by_default="true" />
<inspection_tool class="PhpTooManyParametersInspection" enabled="true" level="WARNING" enabled_by_default="true">
<option name="limit" value="7" />
</inspection_tool>
<inspection_tool class="PhpUndefinedClassInspection" enabled="true" level="WARNING" enabled_by_default="true">
<option name="DONT_REPORT_MULTI_RESOLVE" value="true" />
</inspection_tool>
<inspection_tool class="PhpUnhandledExceptionInspection" enabled="true" level="WEAK WARNING" enabled_by_default="true" />
<inspection_tool class="PhpUnusedParameterInspection" enabled="true" level="WEAK WARNING" enabled_by_default="true">
<option name="DONT_REPORT_ABSTRACT_CLASS" value="true" />
</inspection_tool>
<inspection_tool class="SqlNoDataSourceInspection" enabled="false" level="WARNING" enabled_by_default="false" />
</profile>
</component>

View File

@@ -0,0 +1,7 @@
<component name="InspectionProjectProfileManager">
<settings>
<option name="projectProfile" value="Combodo" />
<option name="PROJECT_PROFILE" value="Combodo" />
<version value="1.0" />
</settings>
</component>

View File

View File

@@ -0,0 +1,14 @@
#!/usr/bin/env bash
set -x
# create target dirs
mkdir -p var
mkdir -p toolkit
# cleanup target dirs
rm -rf toolkit/*
# fill target dirs
curl http://www.combodo.com/documentation/iTopDataModelToolkit-2.3.zip | tar xvz --directory toolkit
cp -r .jenkins/configuration/default-environment/unattended_install/* toolkit

View File

@@ -0,0 +1,11 @@
#!/usr/bin/env bash
set -x
# on the root dir
composer install
# under the test dir
cd test
composer install

13
.jenkins/bin/init/debug.sh Executable file
View File

@@ -0,0 +1,13 @@
#!/usr/bin/env bash
set -x
whoami
pwd
ls
echo "$BRANCH_NAME:${BRANCH_NAME}"
echo "printenv :"
printenv

8
.jenkins/bin/tests/phpunit.sh Executable file
View File

@@ -0,0 +1,8 @@
#!/usr/bin/env bash
set -x
cd test
export DEBUG_UNIT_TEST="0"
php vendor/bin/phpunit --log-junit ../var/test/phpunit-log.junit.xml --teamcity

View File

@@ -0,0 +1,6 @@
#!/usr/bin/env bash
set -x
cd toolkit
php unattended_install.php default-params.xml

View File

@@ -0,0 +1,285 @@
<?php
/**
*
* Configuration file, generated by the iTop configuration wizard
*
* The file is used in MetaModel::LoadConfig() which does all the necessary initialization job
*
*/
$MySettings = array(
// access_message: Message displayed to the users when there is any access restriction
// default: 'iTop is temporarily frozen, please wait... (the admin team)'
'access_message' => 'iTop is temporarily frozen, please wait... (the admin team)',
// access_mode: Access mode: ACCESS_READONLY = 0, ACCESS_ADMIN_WRITE = 2, ACCESS_FULL = 3
// default: 3
'access_mode' => 3,
'allowed_login_types' => 'form|basic|external',
// apc_cache.enabled: If set, the APC cache is allowed (the PHP extension must also be active)
// default: true
'apc_cache.enabled' => true,
// apc_cache.query_ttl: Time to live set in APC for the prepared queries (seconds - 0 means no timeout)
// default: 3600
'apc_cache.query_ttl' => 3600,
// app_root_url: 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: ''
'app_root_url' => 'http://127.0.0.1/itop/svn/trunk/',
// buttons_position: Position of the forms buttons: bottom | top | both
// default: 'both'
'buttons_position' => 'both',
// cas_include_path: The path where to find the phpCAS library
// default: '/usr/share/php'
'cas_include_path' => '/usr/share/php',
// cron_max_execution_time: 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
'cron_max_execution_time' => 600,
// csv_file_default_charset: Character set used by default for downloading and uploading data as a CSV file. Warning: it is case sensitive (uppercase is preferable).
// default: 'ISO-8859-1'
'csv_file_default_charset' => 'ISO-8859-1',
'csv_import_charsets' => array (
),
// csv_import_history_display: Display the history tab in the import wizard
// default: false
'csv_import_history_display' => false,
// date_and_time_format: Format for date and time display (per language)
// default: array (
// 'default' =>
// array (
// 'date' => 'Y-m-d',
// 'time' => 'H:i:s',
// 'date_time' => '$date $time',
// ),
// )
'date_and_time_format' => array (
'default' =>
array (
'date' => 'Y-m-d',
'time' => 'H:i:s',
'date_time' => '$date $time',
),
'FR FR' =>
array (
'date' => 'd/m/Y',
'time' => 'H:i:s',
'date_time' => '$date $time',
),
),
'db_host' => '',
'db_name' => 'itop_ci_main',
'db_pwd' => 'IKnowYouSeeMeInJenkinsConf',
'db_subname' => '',
'db_user' => 'jenkins_itop',
// deadline_format: The format used for displaying "deadline" attributes: any string with the following placeholders: $date$, $difference$
// default: '$difference$'
'deadline_format' => '$difference$',
'default_language' => 'EN US',
// disable_attachments_download_legacy_portal: Disable attachments download from legacy portal
// default: true
'disable_attachments_download_legacy_portal' => true,
// draft_attachments_lifetime: Lifetime (in seconds) of drafts' attachments and inline images: after this duration, the garbage collector will delete them.
// default: 3600
'draft_attachments_lifetime' => 3600,
// email_asynchronous: 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
'email_asynchronous' => false,
// email_default_sender_address: Default address provided in the email from header field.
// default: ''
'email_default_sender_address' => '',
// email_default_sender_label: Default label provided in the email from header field.
// default: ''
'email_default_sender_label' => '',
// email_transport: Mean to send emails: PHPMail (uses the function mail()) or SMTP (implements the client protocole)
// default: 'PHPMail'
'email_transport' => 'SMTP',
// email_transport_smtp.host: host name or IP address (optional)
// default: 'localhost'
'email_transport_smtp.host' => 'smtp.combodo.com',
// email_transport_smtp.password: Authentication password (optional)
// default: ''
'email_transport_smtp.password' => 'IDoNotWork',
// email_transport_smtp.port: port number (optional)
// default: 25
'email_transport_smtp.port' => 25,
// email_transport_smtp.username: Authentication user (optional)
// default: ''
'email_transport_smtp.username' => 'test2@combodo.com',
// email_validation_pattern: Regular expression to validate/detect the format of an eMail address
// default: '[a-zA-Z0-9._&\'-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z0-9-]{2,}'
'email_validation_pattern' => '[a-zA-Z0-9._&\'-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z0-9-]{2,}',
'encryption_key' => '@iT0pEncr1pti0n!',
'ext_auth_variable' => '$_SERVER[\'REMOTE_USER\']',
'fast_reload_interval' => '60',
// graphviz_path: Path to the Graphviz "dot" executable for graphing objects lifecycle
// default: '/usr/bin/dot'
'graphviz_path' => '/usr/bin/dot',
// inline_image_max_display_width: The maximum width (in pixels) when displaying images inside an HTML formatted attribute. Images will be displayed using this this maximum width.
// default: '250'
'inline_image_max_display_width' => 250,
// inline_image_max_storage_width: The maximum width (in pixels) when uploading images to be used inside an HTML formatted attribute. Images larger than the given size will be downsampled before storing them in the database.
// default: '1600'
'inline_image_max_storage_width' => 1600,
// link_set_attribute_qualifier: Link set from string: attribute qualifier (encloses both the attcode and the value)
// default: '\''
'link_set_attribute_qualifier' => '\'',
// link_set_attribute_separator: Link set from string: attribute separator
// default: ';'
'link_set_attribute_separator' => ';',
// link_set_item_separator: Link set from string: line separator
// default: '|'
'link_set_item_separator' => '|',
// link_set_value_separator: Link set from string: value separator (between the attcode and the value itself
// default: ':'
'link_set_value_separator' => ':',
'log_global' => true,
'log_issue' => true,
'log_notification' => true,
'log_web_service' => true,
// max_combo_length: The maximum number of elements in a drop-down list. If more then an autocomplete will be used
// default: 50
'max_combo_length' => 50,
'max_display_limit' => '15',
// max_linkset_output: Maximum number of items shown when getting a list of related items in an email, using the form $this->some_list$. 0 means no limit.
// default: 100
'max_linkset_output' => 100,
'min_display_limit' => '10',
// online_help: Hyperlink to the online-help web page
// default: 'http://www.combodo.com/itop-help'
'online_help' => 'http://www.combodo.com/itop-help',
// php_path: Path to the php executable in CLI mode
// default: 'php'
'php_path' => 'php',
// portal_tickets: CSV list of classes supported in the portal
// default: 'UserRequest'
'portal_tickets' => 'UserRequest',
'query_cache_enabled' => true,
// search_manual_submit: Force manual submit of search requests (class => true)
// default: false
'search_manual_submit' => array (
'Person' => true,
),
'secure_connection_required' => false,
// session_name: The name of the cookie used to store the PHP session id
// default: 'iTop'
'session_name' => 'iTop',
// shortcut_actions: Actions that are available as direct buttons next to the "Actions" menu
// default: 'UI:Menu:Modify,UI:Menu:New'
'shortcut_actions' => 'UI:Menu:Modify,UI:Menu:New',
// source_dir: Source directory for the datamodel files. (which gets compiled to env-production).
// default: ''
'source_dir' => 'datamodels/2.x/',
'standard_reload_interval' => '300',
// synchro_trace: Synchronization details: none, display, save (includes 'display')
// default: 'none'
'synchro_trace' => 'none',
// timezone: Timezone (reference: http://php.net/manual/en/timezones.php). If empty, it will be left unchanged and MUST be explicitely configured in PHP
// default: 'Europe/Paris'
'timezone' => 'Europe/Paris',
// tracking_level_linked_set_default: Default tracking level if not explicitely set at the attribute level, for AttributeLinkedSet (defaults to NONE in case of a fresh install, LIST otherwise - this to preserve backward compatibility while upgrading from a version older than 2.0.3 - see TRAC #936)
// default: 1
'tracking_level_linked_set_default' => 0,
// url_validation_pattern: Regular expression to validate/detect the format of an URL (URL attributes and Wiki formatting for Text attributes)
// default: '(https?|ftp)\\://([a-zA-Z0-9+!*(),;?&=\\$_.-]+(\\:[a-zA-Z0-9+!*(),;?&=\\$_.-]+)?@)?([a-zA-Z0-9-.]{3,})(\\:[0-9]{2,5})?(/([a-zA-Z0-9%+\\$_-]\\.?)+)*/?(\\?[a-zA-Z+&\\$_.-][a-zA-Z0-9;:[\\]@&%=+/\\$_.-]*)?(#[a-zA-Z_.-][a-zA-Z0-9+\\$_.-]*)?'
'url_validation_pattern' => '(https?|ftp)\\://([a-zA-Z0-9+!*(),;?&=\\$_.-]+(\\:[a-zA-Z0-9+!*(),;?&=\\$_.-]+)?@)?([a-zA-Z0-9-.]{3,})(\\:[0-9]{2,5})?(/([a-zA-Z0-9%+\\$_-]\\.?)+)*/?(\\?[a-zA-Z+&\\$_.-][a-zA-Z0-9;:[\\]@&%=+/\\$_.-]*)?(#[a-zA-Z_.-][a-zA-Z0-9+\\$_.-]*)?',
);
/**
*
* Modules specific settings
*
*/
$MyModuleSettings = array(
'itop-attachments' => array (
'allowed_classes' => array (
0 => 'Ticket',
),
'position' => 'relations',
'preview_max_width' => 290,
),
'itop-backup' => array (
'mysql_bindir' => '',
'week_days' => 'monday, tuesday, wednesday, thursday, friday',
'time' => '23:30',
'retention_count' => 5,
'enabled' => true,
'debug' => false,
),
'molkobain-console-tooltips' => array (
'decoration_class' => 'fas fa-question',
'enabled' => true,
),
);
/**
*
* Data model modules to be loaded. Names are specified as relative paths
*
*/
$MyModules = array(
'addons' => array (
'user rights' => 'addons/userrights/userrightsprofile.class.inc.php',
),
);
?>

View File

@@ -0,0 +1,72 @@
<?xml version="1.0" encoding="UTF-8"?>
<installation>
<!-- On manual installs, this file is generated in setup/install-*.xml -->
<mode>upgrade</mode>
<preinstall>
<copies type="array"/>
</preinstall>
<source_dir>datamodels/2.x/</source_dir>
<datamodel_version>2.5.0</datamodel_version>
<previous_configuration_file>/var/lib/jenkins/workspace/iTop-CI/unattended_install/default-config-itop.php</previous_configuration_file>
<extensions_dir>extensions</extensions_dir>
<target_env>production</target_env>
<workspace_dir></workspace_dir>
<database>
<server></server>
<user>jenkins_itop</user>
<pwd>IKnowYouSeeMeInJenkinsConf</pwd>
<name>itop_ci</name>
<db_tls_enabled></db_tls_enabled>
<db_tls_ca></db_tls_ca>
<prefix></prefix>
</database>
<url>http://127.0.0.1/itop/svn/trunk/</url>
<graphviz_path>/usr/bin/dot</graphviz_path>
<admin_account>
<user>admin</user>
<pwd>admin</pwd>
<language>EN US</language>
</admin_account>
<language>EN US</language>
<selected_modules type="array">
<item>authent-external</item>
<item>authent-local</item>
<item>itop-backup</item>
<item>itop-config</item>
<item>itop-profiles-itil</item>
<item>itop-sla-computation</item>
<item>itop-tickets</item>
<item>itop-welcome-itil</item>
<item>itop-config-mgmt</item>
<item>itop-attachments</item>
<item>itop-datacenter-mgmt</item>
<item>itop-endusers-devices</item>
<item>itop-storage-mgmt</item>
<item>itop-virtualization-mgmt</item>
<item>itop-bridge-virtualization-storage</item>
<item>itop-service-mgmt</item>
<item>itop-request-mgmt</item>
<item>itop-portal</item>
<item>itop-portal-base</item>
<item>itop-change-mgmt</item>
<item>itop-knownerror-mgmt</item>
</selected_modules>
<selected_extensions type="array">
<item>itop-config-mgmt-core</item>
<item>itop-config-mgmt-datacenter</item>
<item>itop-config-mgmt-end-user</item>
<item>itop-config-mgmt-storage</item>
<item>itop-config-mgmt-virtualization</item>
<item>itop-service-mgmt-enterprise</item>
<item>itop-ticket-mgmt-simple-ticket</item>
<item>itop-ticket-mgmt-simple-ticket-enhanced-portal</item>
<item>itop-change-mgmt-simple</item>
<item>itop-kown-error-mgmt</item>
</selected_extensions>
<sample_data>1</sample_data>
<old_addon></old_addon>
<options>
<generate_config>1</generate_config>
</options>
<mysql_bindir></mysql_bindir>
</installation>

View File

@@ -0,0 +1,190 @@
<?php
//this scrit will be run under the ./toolkit directory, relatively to the document root
require_once('../approot.inc.php');
require_once(APPROOT.'/application/utils.inc.php');
require_once(APPROOT.'/application/clipage.class.inc.php');
require_once(APPROOT.'/core/config.class.inc.php');
require_once(APPROOT.'/core/log.class.inc.php');
require_once(APPROOT.'/core/kpi.class.inc.php');
require_once(APPROOT.'/core/cmdbsource.class.inc.php');
require_once(APPROOT.'/setup/setuppage.class.inc.php');
require_once(APPROOT.'/setup/wizardcontroller.class.inc.php');
require_once(APPROOT.'/setup/wizardsteps.class.inc.php');
require_once(APPROOT.'/setup/applicationinstaller.class.inc.php');
/////////////////////////////////////////////////
$sParamFile = utils::ReadParam('response_file', 'default-params.xml', true /* CLI allowed */, 'raw_data');
$bCheckConsistency = (utils::ReadParam('check_consistency', '0', true /* CLI allowed */) == '1');
$oParams = new XMLParameters($sParamFile);
$sMode = $oParams->Get('mode');
if ($sMode == 'install')
{
echo "Installation mode detected.\n";
$bClean = utils::ReadParam('clean', false, true /* CLI allowed */);
if ($bClean)
{
echo "Cleanup mode detected.\n";
$sTargetEnvironment = $oParams->Get('target_env', '');
if ($sTargetEnvironment == '')
{
$sTargetEnvironment = 'production';
}
$sTargetDir = APPROOT.'env-'.$sTargetEnvironment;
// Configuration file
$sConfigFile = APPCONF.$sTargetEnvironment.'/'.ITOP_CONFIG_FILE;
if (file_exists($sConfigFile))
{
echo "Trying to delete the configuration file: '$sConfigFile'.\n";
@chmod($sConfigFile, 0770); // RWX for owner and group, nothing for others
unlink($sConfigFile);
}
else
{
echo "No config file to delete ($sConfigFile does not exist).\n";
}
// env-xxx directory
if (file_exists($sTargetDir))
{
if (is_dir($sTargetDir))
{
echo "Emptying the target directory '$sTargetDir'.\n";
SetupUtils::tidydir($sTargetDir);
}
else
{
die("ERROR the target dir '$sTargetDir' exists, but is NOT a directory !!!\nExiting.\n");
}
}
else
{
echo "No target directory to delete ($sTargetDir does not exist).\n";
}
// Database
$aDBSettings = $oParams->Get('database', array());
$sDBServer = $aDBSettings['server'];
$sDBUser = $aDBSettings['user'];
$sDBPwd = $aDBSettings['pwd'];
$sDBName = $aDBSettings['name'];
$sDBPrefix = $aDBSettings['prefix'];
if ($sDBPrefix != '')
{
die("Cleanup not implemented for a partial database (prefix= '$sDBPrefix')\nExiting.");
}
$oMysqli = new mysqli($sDBServer, $sDBUser, $sDBPwd);
if ($oMysqli->connect_errno)
{
die("Cannot connect to the MySQL server (".$mysqli->connect_errno . ") ".$mysqli->connect_error."\nExiting");
}
else
{
if ($oMysqli->select_db($sDBName))
{
echo "Deleting database '$sDBName'\n";
$oMysqli->query("DROP DATABASE `$sDBName`");
}
else
{
echo "The database '$sDBName' does not seem to exist. Nothing to cleanup.\n";
}
}
}
}
$bHasErrors = false;
$aChecks = SetupUtils::CheckBackupPrerequisites(APPROOT.'data'); // mmm should be the backup destination dir
$aSelectedModules = $oParams->Get('selected_modules');
$sSourceDir = $oParams->Get('source_dir', 'datamodels/latest');
$sExtensionDir = $oParams->Get('extensions_dir', 'extensions');
$aChecks = array_merge($aChecks, SetupUtils::CheckSelectedModules($sSourceDir, $sExtensionDir, $aSelectedModules));
foreach($aChecks as $oCheckResult)
{
switch($oCheckResult->iSeverity)
{
case CheckResult::ERROR:
$bHasErrors = true;
$sHeader = "Error";
break;
case CheckResult::WARNING:
$sHeader = "Warning";
break;
case CheckResult::INFO:
default:
$sHeader = "Info";
break;
}
echo $sHeader.": ".$oCheckResult->sLabel;
if (strlen($oCheckResult->sDescription))
{
echo ' - '.$oCheckResult->sDescription;
}
echo "\n";
}
if ($bHasErrors)
{
echo "Encountered stopper issues. Aborting...\n";
die;
}
$bFoundIssues = false;
$bInstall = utils::ReadParam('install', true, true /* CLI allowed */);
if ($bInstall)
{
echo "Starting the unattended installation...\n";
$oWizard = new ApplicationInstaller($oParams);
$bRes = $oWizard->ExecuteAllSteps();
if (!$bRes)
{
echo "\nencountered installation issues!";
$bFoundIssues = true;
}
}
else
{
echo "No installation requested.\n";
}
if (!$bFoundIssues && $bCheckConsistency)
{
echo "Checking data model consistency.\n";
ob_start();
$sCheckRes = '';
try
{
MetaModel::CheckDefinitions(false);
$sCheckRes = ob_get_clean();
}
catch(Exception $e)
{
$sCheckRes = ob_get_clean()."\nException: ".$e->getMessage();
}
if (strlen($sCheckRes) > 0)
{
echo $sCheckRes;
echo "\nfound consistency issues!";
$bFoundIssues = true;
}
}
if (!$bFoundIssues)
{
// last line: used to check the install
// the only way to track issues in case of Fatal error or even parsing error!
echo "\ninstalled!";
exit;
}

100
CONTRIBUTING.md Normal file
View File

@@ -0,0 +1,100 @@
# Contributing to iTop
You want to contribute to iTop? Many thanks to you! 🎉 👍
Here are some guidelines that will help us integrate your work!
## Contributions
### Subjects
You are welcome to create pull requests on any of those subjects:
* 🐛 `:bug:` bug fix
* 🔒 `:lock:` security
* 🌐 `:globe_with_meridians:` translation
If you want to implement a **new feature**, please [create a corresponding ticket](https://sourceforge.net/p/itop/tickets/new/) for review.
If you ever want to begin implementation, do so in a fork, and add a link to the corresponding commits in the ticket.
### License
iTop is distributed under the AGPL-3.0 license (see the [license.txt] file),
your code must comply with this license.
If you want to use another license, you may [create an extension][wiki new ext].
[license.txt]: https://github.com/Combodo/iTop/blob/develop/license.txt
[wiki new ext]: https://www.itophub.io/wiki/page?id=latest%3Acustomization%3Astart#by_writing_your_own_extension
## Branch model
TL;DR:
> **create a fork from iTop main repository,
> create a branch based on either release branch if present, or develop otherwise**
We are using the [GitFlow](https://nvie.com/posts/a-successful-git-branching-model/) branch model. That means we have in our repo those
main branches:
- develop: ongoing development version
- release/*: if present, that means we are working on a beta version
- master: previous stable version
For example, if no beta version is currently ongoing we could have:
- develop containing 2.8 version
- master containing 2.7 version
In this example, when 2.8 beta is shipped that will become:
- develop: 2.9 version
- release/2.8: 2.8 beta
- master: 2.7 version
And when 2.8 final will be out:
- develop: 2.9 version
- master: 2.8 version
## Coding
### PHP styleguide
Please follow [our guidelines](https://www.itophub.io/wiki/page?id=latest%3Acustomization%3Acoding_standards).
### Tests
Please create tests that covers as much as possible the code you're submitting.
Our tests are located in the `test/` directory, containing a PHPUnit config file : `phpunit.xml.dist`.
### Git Commit Messages
* Describe the functional change instead of the technical modifications
* Use the present tense ("Add feature" not "Added feature")
* Use the imperative mood ("Move cursor to..." not "Moves cursor to...")
* Limit the first line to 72 characters or less
* Please start the commit message with an applicable emoji (following the [Gitmoji guide](https://gitmoji.carloscuesta.me/).). For example :
* 🌐 `:globe_with_meridians:` for translations
* 🎨 `:art:` when improving the format/structure of the code
* ⚡️ `:zap:` when improving performance
* 🐛 `:bug:` when fixing a bug
* 🔥 `:fire:` when removing code or files
* 💚 `:green_heart:` when fixing the CI build
*`:white_check_mark:` when adding tests
* 🔒 `:lock:` when dealing with security
* ⬆️ `:arrow_up:` when upgrading dependencies
* ⬇️ `:arrow_down:` when downgrading dependencies
* ♻️ `:recycle:` code refactoring
* 💄 `:lipstick:` Updating the UI and style files.
## Pull request
When your code is working, please:
* stash as much as possible your commits,
* rebase your branch on our repo last commit,
* create a pull request.
Detailed procedure to work on fork and create PR is available [in GitHub help pages](https://help.github.com/articles/creating-a-pull-request-from-a-fork/).

65
Jenkinsfile vendored Normal file
View File

@@ -0,0 +1,65 @@
pipeline {
agent any
stages {
stage('init') {
parallel {
stage('debug') {
steps {
sh './.jenkins/bin/init/debug.sh'
}
}
stage('append files to project') {
steps {
sh './.jenkins/bin/init/append_files.sh'
}
}
stage('composer install') {
steps {
sh './.jenkins/bin/init/composer_install.sh'
}
}
}
}
stage('unattended_install') {
parallel {
stage('unattended_install default env') {
steps {
sh './.jenkins/bin/unattended_install/default_env.sh'
}
}
}
}
stage('test') {
parallel {
stage('phpunit') {
steps {
sh './.jenkins/bin/tests/phpunit.sh'
}
}
}
}
}
post {
always {
junit 'var/test/phpunit-log.junit.xml'
}
failure {
slackSend(channel: "#jenkins-itop", color: '#FF0000', message: "Ho no! Build failed! (${currentBuild.result}), Job '${env.JOB_NAME} [${env.BUILD_NUMBER}]' (${env.BUILD_URL})")
}
fixed {
slackSend(channel: "#jenkins-itop", color: '#FFa500', message: "Yes! Build repaired! (${currentBuild.result}), Job '${env.JOB_NAME} [${env.BUILD_NUMBER}]' (${env.BUILD_URL})")
}
}
environment {
DEBUG_UNIT_TEST = '0'
}
options {
timeout(time: 20, unit: 'MINUTES')
}
}

141
README.md Normal file
View File

@@ -0,0 +1,141 @@
<p align="center"><a href="https://www.combodo.com/itop-193" target="_blank">
<img src="https://www.combodo.com/logos/logo-itop.svg">
</a></p>
# iTop - ITSM & CMDB
iTop stands for *IT Operations Portal*.
It is a complete open source, ITIL, web based service management tool including a fully customizable CMDB, a helpdesk system and a document management tool.
iTop also offers mass import tools and web services to integrate with your IT
## Features
- Fully configurable [Configuration Management (CMDB)][10]
- [HelpDesk][11] and Incident Management
- [Service and Contract Management][12]
- [Change][13] Management
- Configurable [SLA][14] Management
- Graphical [impact analysis][15]
- [CSV import][16] tool for any data
- Consistency [audit][17] to check data quality
- [Data synchronization][18] (for data federation)
## Resources
- [iTop Forums][1]: for support request
- [iTop Tickets][2]: for feature requests and bug reports
- [Releases download][3]
- [iTop documentation][4] for iTop and official extensions
- [iTop extensions][5] for discovering and installing extensions
## Releases
### Version 2.6
- [Changes since the previous version][58]
- [New features][59]
- [Migration notes][60]
- [Download iTop 2.6.0-beta][61]
### Version 2.5
- [Changes since the previous version][54]
- [New features][55]
- [Migration notes][56]
- [Download iTop 2.5.0][57]
### Version 2.4
- [Changes since the previous version][50]
- [New features][51]
- [Migration notes][52]
- [Download iTop 2.4.1][53]
# About Us
iTop development is sponsored, led and supported by [Combodo][0].
# Contributors
We would like to give a special thank you to the people from the community who contributed to this project, including:
- Alves, David
- Beck, Pedro
- Bilger, Jean-François
- Bostoen, Jeffrey
- Cardoso, Anderson
- Cassaro, Bruno
- Casteleyn, Thomas
- Castro, Randall Badilla
- Colantoni, Maria Laura
- Dvořák, Lukáš
- Goethals, Stefan
- Gumble, David
- Hippler, Lars
- Khamit, Shamil
- Konečný, Kamil
- Kunin, Vladimir
- Lassiter, Dennis
- Lucas, Jonathan
- Malik, Remie
- Rosenke, Stephan
- Seki, Shoji
- Shilov, Vladimir
- Tulio, Marco
- Turrubiates, Miguel
#### Aliases
- chifu1234
- cprobst
- jbostoen
- Karkoff1212
- larhip
- Laura
- Purple Grape
- Schlobinux
- theBigOne
- ulmerspatz
#### Companies
- Hardis
- ITOMIG
[0]: https://www.combodo.com
[1]: https://sourceforge.net/p/itop/discussion/
[2]: https://sourceforge.net/p/itop/tickets/
[3]: https://sourceforge.net/projects/itop/files/itop/
[4]: https://www.itophub.io/wiki
[5]: https://store.itophub.io/en_US/
[10]: https://www.itophub.io/wiki/page?id=2_5_0%3Adatamodel%3Astart#configuration_management_cmdb
[11]: https://www.itophub.io/wiki/page?id=2_5_0%3Adatamodel%3Astart#ticketing
[12]: https://www.itophub.io/wiki/page?id=2_5_0%3Adatamodel%3Astart#service_management
[13]: https://www.itophub.io/wiki/page?id=2_5_0%3Adatamodel%3Astart#change_management
[14]: https://www.itophub.io/wiki/page?id=2_5_0%3Aimplementation%3Astart#service_level_agreements_and_targets
[15]: https://www.itophub.io/wiki/page?id=2_5_0%3Auser%3Aactions#relations
[16]: https://www.itophub.io/wiki/page?id=2_5_0%3Auser%3Abulk_modify#uploading_data
[17]: https://www.itophub.io/wiki/page?id=2_5_0%3Aadmin%3Aaudit
[18]: https://www.itophub.io/wiki/page?id=2_5_0%3Aadvancedtopics%3Adata_synchro_overview
[50]: https://www.itophub.io/wiki/page?id=2_4_0:release:change_log
[51]: https://www.itophub.io/wiki/page?id=2_4_0:release:2_4_whats_new
[52]: https://www.itophub.io/wiki/page?id=2_4_0:install:230_to_240_migration_notes
[53]: https://sourceforge.net/projects/itop/files/itop/2.4.1/iTop-2.4.1-3714.zip/download
[54]: https://www.itophub.io/wiki/page?id=2_5_0:release:change_log
[55]: https://www.itophub.io/wiki/page?id=2_5_0:release:2_5_whats_new
[56]: https://www.itophub.io/wiki/page?id=2_5_0:install:240_to_250_migration_notes
[57]: https://sourceforge.net/projects/itop/files/itop/2.5.0/iTop-2.5.0-3935.zip/download
[58]: https://www.itophub.io/wiki/page?id=2_6_0:release:change_log
[59]: https://www.itophub.io/wiki/page?id=2_6_0:release:2_6_whats_new
[60]: https://www.itophub.io/wiki/page?id=2_6_0:install:250_to_260_migration_notes
[61]: https://sourceforge.net/projects/itop/files/itop/2.6.0-beta/iTop-2.6-beta-4146.zip/download

View File

@@ -1,368 +1,368 @@
<?php
// Copyright (C) 2010-2012 Combodo SARL
//
// This file is part of iTop.
//
// iTop is free software; you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// iTop is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with iTop. If not, see <http://www.gnu.org/licenses/>
/**
* UserRightsMatrix (User management Module)
*
* @copyright Copyright (C) 2010-2012 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
class UserRightsMatrixClassGrant extends DBObject
{
public static function Init()
{
$aParams = array
(
"category" => "addon/userrights",
"key_type" => "autoincrement",
"name_attcode" => "",
"state_attcode" => "",
"reconc_keys" => array(),
"db_table" => "priv_ur_matrixclasses",
"db_key_field" => "id",
"db_finalclass_field" => "",
);
MetaModel::Init_Params($aParams);
//MetaModel::Init_InheritAttributes();
MetaModel::Init_AddAttribute(new AttributeExternalKey("userid", array("targetclass"=>"User", "jointype"=> "", "allowed_values"=>null, "sql"=>"userid", "is_null_allowed"=>false, "on_target_delete"=>DEL_MANUAL, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeExternalField("login", array("allowed_values"=>null, "extkey_attcode"=> 'userid', "target_attcode"=>"login")));
MetaModel::Init_AddAttribute(new AttributeString("class", array("allowed_values"=>null, "sql"=>"class", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeString("action", array("allowed_values"=>null, "sql"=>"action", "default_value"=>"", "is_null_allowed"=>false, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeEnum("permission", array("allowed_values"=>new ValueSetEnum('yes,no'), "sql"=>"permission", "default_value"=>"yes", "is_null_allowed"=>false, "depends_on"=>array())));
}
}
class UserRightsMatrixClassStimulusGrant extends DBObject
{
public static function Init()
{
$aParams = array
(
"category" => "addon/userrights",
"key_type" => "autoincrement",
"name_attcode" => "",
"state_attcode" => "",
"reconc_keys" => array(),
"db_table" => "priv_ur_matrixclassesstimulus",
"db_key_field" => "id",
"db_finalclass_field" => "",
);
MetaModel::Init_Params($aParams);
//MetaModel::Init_InheritAttributes();
MetaModel::Init_AddAttribute(new AttributeExternalKey("userid", array("targetclass"=>"User", "jointype"=> "", "allowed_values"=>null, "sql"=>"userid", "is_null_allowed"=>false, "on_target_delete"=>DEL_MANUAL, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeExternalField("login", array("allowed_values"=>null, "extkey_attcode"=> 'userid', "target_attcode"=>"login")));
MetaModel::Init_AddAttribute(new AttributeString("class", array("allowed_values"=>null, "sql"=>"class", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeString("stimulus", array("allowed_values"=>null, "sql"=>"action", "default_value"=>"", "is_null_allowed"=>false, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeEnum("permission", array("allowed_values"=>new ValueSetEnum('yes,no'), "sql"=>"permission", "default_value"=>"yes", "is_null_allowed"=>false, "depends_on"=>array())));
}
}
class UserRightsMatrixAttributeGrant extends DBObject
{
public static function Init()
{
$aParams = array
(
"category" => "addon/userrights",
"key_type" => "autoincrement",
"name_attcode" => "",
"state_attcode" => "",
"reconc_keys" => array(),
"db_table" => "priv_ur_matrixattributes",
"db_key_field" => "id",
"db_finalclass_field" => "",
);
MetaModel::Init_Params($aParams);
//MetaModel::Init_InheritAttributes();
MetaModel::Init_AddAttribute(new AttributeExternalKey("userid", array("targetclass"=>"User", "jointype"=> "", "allowed_values"=>null, "sql"=>"userid", "is_null_allowed"=>false, "on_target_delete"=>DEL_MANUAL, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeExternalField("login", array("allowed_values"=>null, "extkey_attcode"=> 'userid', "target_attcode"=>"login")));
MetaModel::Init_AddAttribute(new AttributeString("class", array("allowed_values"=>null, "sql"=>"class", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeString("attcode", array("allowed_values"=>null, "sql"=>"attcode", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeString("action", array("allowed_values"=>null, "sql"=>"action", "default_value"=>"", "is_null_allowed"=>false, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeEnum("permission", array("allowed_values"=>new ValueSetEnum('yes,no'), "sql"=>"permission", "default_value"=>"yes", "is_null_allowed"=>false, "depends_on"=>array())));
}
}
class UserRightsMatrix extends UserRightsAddOnAPI
{
static public $m_aActionCodes = array(
UR_ACTION_READ => 'read',
UR_ACTION_MODIFY => 'modify',
UR_ACTION_DELETE => 'delete',
UR_ACTION_BULK_READ => 'bulk read',
UR_ACTION_BULK_MODIFY => 'bulk modify',
UR_ACTION_BULK_DELETE => 'bulk delete',
);
// Installation: create the very first user
public function CreateAdministrator($sAdminUser, $sAdminPwd, $sLanguage = 'EN US')
{
// Maybe we should check that no other user with userid == 0 exists
$oUser = new UserLocal();
$oUser->Set('login', $sAdminUser);
$oUser->Set('password', $sAdminPwd);
$oUser->Set('contactid', 1); // one is for root !
$oUser->Set('language', $sLanguage); // Language was chosen during the installation
// Create a change to record the history of the User object
$oChange = MetaModel::NewObject("CMDBChange");
$oChange->Set("date", time());
$oChange->Set("userinfo", "Initialization");
$iChangeId = $oChange->DBInsert();
// Now record the admin user object
$iUserId = $oUser->DBInsertTrackedNoReload($oChange, true /* skip security */);
$this->SetupUser($iUserId, true);
return true;
}
public function IsAdministrator($oUser)
{
return ($oUser->GetKey() == 1);
}
public function IsPortalUser($oUser)
{
return ($oUser->GetKey() == 1);
}
// Deprecated - create a new module !
public function Setup()
{
// Users must be added manually
// This procedure will then update the matrix when a new user is found or a new class/attribute appears
$oUserSet = new DBObjectSet(DBObjectSearch::FromOQL("SELECT User"));
while ($oUser = $oUserSet->Fetch())
{
$this->SetupUser($oUser->GetKey());
}
return true;
}
protected function SetupUser($iUserId, $bNewUser = false)
{
foreach(array('bizmodel', 'application', 'gui', 'core/cmdb') as $sCategory)
{
foreach (MetaModel::GetClasses($sCategory) as $sClass)
{
foreach (self::$m_aActionCodes as $iActionCode => $sAction)
{
if ($bNewUser)
{
$bAddCell = true;
}
else
{
$oSet = new DBObjectSet(DBObjectSearch::FromOQL("SELECT UserRightsMatrixClassGrant WHERE class = '$sClass' AND action = '$sAction' AND userid = $iUserId"));
$bAddCell = ($oSet->Count() < 1);
}
if ($bAddCell)
{
// Create a new entry
$oMyClassGrant = MetaModel::NewObject("UserRightsMatrixClassGrant");
$oMyClassGrant->Set("userid", $iUserId);
$oMyClassGrant->Set("class", $sClass);
$oMyClassGrant->Set("action", $sAction);
$oMyClassGrant->Set("permission", "yes");
$iId = $oMyClassGrant->DBInsertNoReload();
}
}
foreach (MetaModel::EnumStimuli($sClass) as $sStimulusCode => $oStimulus)
{
if ($bNewUser)
{
$bAddCell = true;
}
else
{
$oSet = new DBObjectSet(DBObjectSearch::FromOQL("SELECT UserRightsMatrixClassStimulusGrant WHERE class = '$sClass' AND stimulus = '$sStimulusCode' AND userid = $iUserId"));
$bAddCell = ($oSet->Count() < 1);
}
if ($bAddCell)
{
// Create a new entry
$oMyClassGrant = MetaModel::NewObject("UserRightsMatrixClassStimulusGrant");
$oMyClassGrant->Set("userid", $iUserId);
$oMyClassGrant->Set("class", $sClass);
$oMyClassGrant->Set("stimulus", $sStimulusCode);
$oMyClassGrant->Set("permission", "yes");
$iId = $oMyClassGrant->DBInsertNoReload();
}
}
foreach (MetaModel::GetAttributesList($sClass) as $sAttCode)
{
if ($bNewUser)
{
$bAddCell = true;
}
else
{
$oSet = new DBObjectSet(DBObjectSearch::FromOQL("SELECT UserRightsMatrixAttributeGrant WHERE class = '$sClass' AND attcode = '$sAttCode' AND userid = $iUserId"));
$bAddCell = ($oSet->Count() < 1);
}
if ($bAddCell)
{
foreach (array('read', 'modify') as $sAction)
{
// Create a new entry
$oMyAttGrant = MetaModel::NewObject("UserRightsMatrixAttributeGrant");
$oMyAttGrant->Set("userid", $iUserId);
$oMyAttGrant->Set("class", $sClass);
$oMyAttGrant->Set("attcode", $sAttCode);
$oMyAttGrant->Set("action", $sAction);
$oMyAttGrant->Set("permission", "yes");
$iId = $oMyAttGrant->DBInsertNoReload();
}
}
}
}
}
/*
// Create the "My Bookmarks" menu item (parent_id = 0, rank = 6)
if ($bNewUser)
{
$bAddMenu = true;
}
else
{
$oSet = new DBObjectSet(DBObjectSearch::FromOQL("SELECT menuNode WHERE type = 'user' AND parent_id = 0 AND user_id = $iUserId"));
$bAddMenu = ($oSet->Count() < 1);
}
if ($bAddMenu)
{
$oMenu = MetaModel::NewObject('menuNode');
$oMenu->Set('type', 'user');
$oMenu->Set('parent_id', 0); // It's a toplevel entry
$oMenu->Set('rank', 6); // Located just above the Admin Tools section (=7)
$oMenu->Set('name', 'My Bookmarks');
$oMenu->Set('label', 'My Favorite Items');
$oMenu->Set('hyperlink', 'UI.php');
$oMenu->Set('template', '<p></p><p></p><p style="text-align:center; font-family:Georgia, Times, serif; font-size:32px;">My bookmarks</p><p style="text-align:center; font-family:Georgia, Times, serif; font-size:14px;"><i>This section contains my most favorite search results</i></p>');
$oMenu->Set('user_id', $iUserId);
$oMenu->DBInsert();
}
*/
}
public function Init()
{
// Could be loaded in a shared memory (?)
return true;
}
public function GetSelectFilter($oUser, $sClass, $aSettings = array())
{
$oNullFilter = new DBObjectSearch($sClass);
return $oNullFilter;
}
public function IsActionAllowed($oUser, $sClass, $iActionCode, $oInstanceSet = null)
{
if (!array_key_exists($iActionCode, self::$m_aActionCodes))
{
return UR_ALLOWED_NO;
}
$sAction = self::$m_aActionCodes[$iActionCode];
$oSet = new DBObjectSet(DBObjectSearch::FromOQL("SELECT UserRightsMatrixClassGrant WHERE class = '$sClass' AND action = '$sAction' AND userid = '{$oUser->GetKey()}'"));
if ($oSet->Count() < 1)
{
return UR_ALLOWED_NO;
}
$oGrantRecord = $oSet->Fetch();
switch ($oGrantRecord->Get('permission'))
{
case 'yes':
$iRetCode = UR_ALLOWED_YES;
break;
case 'no':
default:
$iRetCode = UR_ALLOWED_NO;
break;
}
return $iRetCode;
}
public function IsActionAllowedOnAttribute($oUser, $sClass, $sAttCode, $iActionCode, $oInstanceSet = null)
{
if (!array_key_exists($iActionCode, self::$m_aActionCodes))
{
return UR_ALLOWED_NO;
}
$sAction = self::$m_aActionCodes[$iActionCode];
$oSet = new DBObjectSet(DBObjectSearch::FromOQL("SELECT UserRightsMatrixAttributeGrant WHERE class = '$sClass' AND attcode = '$sAttCode' AND action = '$sAction' AND userid = '{$oUser->GetKey()}'"));
if ($oSet->Count() < 1)
{
return UR_ALLOWED_NO;
}
$oGrantRecord = $oSet->Fetch();
switch ($oGrantRecord->Get('permission'))
{
case 'yes':
$iRetCode = UR_ALLOWED_YES;
break;
case 'no':
default:
$iRetCode = UR_ALLOWED_NO;
break;
}
return $iRetCode;
}
public function IsStimulusAllowed($oUser, $sClass, $sStimulusCode, $oInstanceSet = null)
{
$oSet = new DBObjectSet(DBObjectSearch::FromOQL("SELECT UserRightsMatrixClassStimulusGrant WHERE class = '$sClass' AND stimulus = '$sStimulusCode' AND userid = '{$oUser->GetKey()}'"));
if ($oSet->Count() < 1)
{
return UR_ALLOWED_NO;
}
$oGrantRecord = $oSet->Fetch();
switch ($oGrantRecord->Get('permission'))
{
case 'yes':
$iRetCode = UR_ALLOWED_YES;
break;
case 'no':
default:
$iRetCode = UR_ALLOWED_NO;
break;
}
return $iRetCode;
}
public function FlushPrivileges()
{
}
}
UserRights::SelectModule('UserRightsMatrix');
?>
<?php
// Copyright (C) 2010-2012 Combodo SARL
//
// This file is part of iTop.
//
// iTop is free software; you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// iTop is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with iTop. If not, see <http://www.gnu.org/licenses/>
/**
* UserRightsMatrix (User management Module)
*
* @copyright Copyright (C) 2010-2012 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
class UserRightsMatrixClassGrant extends DBObject
{
public static function Init()
{
$aParams = array
(
"category" => "addon/userrights",
"key_type" => "autoincrement",
"name_attcode" => "",
"state_attcode" => "",
"reconc_keys" => array(),
"db_table" => "priv_ur_matrixclasses",
"db_key_field" => "id",
"db_finalclass_field" => "",
);
MetaModel::Init_Params($aParams);
//MetaModel::Init_InheritAttributes();
MetaModel::Init_AddAttribute(new AttributeExternalKey("userid", array("targetclass"=>"User", "jointype"=> "", "allowed_values"=>null, "sql"=>"userid", "is_null_allowed"=>false, "on_target_delete"=>DEL_MANUAL, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeExternalField("login", array("allowed_values"=>null, "extkey_attcode"=> 'userid', "target_attcode"=>"login")));
MetaModel::Init_AddAttribute(new AttributeString("class", array("allowed_values"=>null, "sql"=>"class", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeString("action", array("allowed_values"=>null, "sql"=>"action", "default_value"=>"", "is_null_allowed"=>false, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeEnum("permission", array("allowed_values"=>new ValueSetEnum('yes,no'), "sql"=>"permission", "default_value"=>"yes", "is_null_allowed"=>false, "depends_on"=>array())));
}
}
class UserRightsMatrixClassStimulusGrant extends DBObject
{
public static function Init()
{
$aParams = array
(
"category" => "addon/userrights",
"key_type" => "autoincrement",
"name_attcode" => "",
"state_attcode" => "",
"reconc_keys" => array(),
"db_table" => "priv_ur_matrixclassesstimulus",
"db_key_field" => "id",
"db_finalclass_field" => "",
);
MetaModel::Init_Params($aParams);
//MetaModel::Init_InheritAttributes();
MetaModel::Init_AddAttribute(new AttributeExternalKey("userid", array("targetclass"=>"User", "jointype"=> "", "allowed_values"=>null, "sql"=>"userid", "is_null_allowed"=>false, "on_target_delete"=>DEL_MANUAL, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeExternalField("login", array("allowed_values"=>null, "extkey_attcode"=> 'userid', "target_attcode"=>"login")));
MetaModel::Init_AddAttribute(new AttributeString("class", array("allowed_values"=>null, "sql"=>"class", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeString("stimulus", array("allowed_values"=>null, "sql"=>"action", "default_value"=>"", "is_null_allowed"=>false, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeEnum("permission", array("allowed_values"=>new ValueSetEnum('yes,no'), "sql"=>"permission", "default_value"=>"yes", "is_null_allowed"=>false, "depends_on"=>array())));
}
}
class UserRightsMatrixAttributeGrant extends DBObject
{
public static function Init()
{
$aParams = array
(
"category" => "addon/userrights",
"key_type" => "autoincrement",
"name_attcode" => "",
"state_attcode" => "",
"reconc_keys" => array(),
"db_table" => "priv_ur_matrixattributes",
"db_key_field" => "id",
"db_finalclass_field" => "",
);
MetaModel::Init_Params($aParams);
//MetaModel::Init_InheritAttributes();
MetaModel::Init_AddAttribute(new AttributeExternalKey("userid", array("targetclass"=>"User", "jointype"=> "", "allowed_values"=>null, "sql"=>"userid", "is_null_allowed"=>false, "on_target_delete"=>DEL_MANUAL, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeExternalField("login", array("allowed_values"=>null, "extkey_attcode"=> 'userid', "target_attcode"=>"login")));
MetaModel::Init_AddAttribute(new AttributeString("class", array("allowed_values"=>null, "sql"=>"class", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeString("attcode", array("allowed_values"=>null, "sql"=>"attcode", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeString("action", array("allowed_values"=>null, "sql"=>"action", "default_value"=>"", "is_null_allowed"=>false, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeEnum("permission", array("allowed_values"=>new ValueSetEnum('yes,no'), "sql"=>"permission", "default_value"=>"yes", "is_null_allowed"=>false, "depends_on"=>array())));
}
}
class UserRightsMatrix extends UserRightsAddOnAPI
{
static public $m_aActionCodes = array(
UR_ACTION_READ => 'read',
UR_ACTION_MODIFY => 'modify',
UR_ACTION_DELETE => 'delete',
UR_ACTION_BULK_READ => 'bulk read',
UR_ACTION_BULK_MODIFY => 'bulk modify',
UR_ACTION_BULK_DELETE => 'bulk delete',
);
// Installation: create the very first user
public function CreateAdministrator($sAdminUser, $sAdminPwd, $sLanguage = 'EN US')
{
// Maybe we should check that no other user with userid == 0 exists
$oUser = new UserLocal();
$oUser->Set('login', $sAdminUser);
$oUser->Set('password', $sAdminPwd);
$oUser->Set('contactid', 1); // one is for root !
$oUser->Set('language', $sLanguage); // Language was chosen during the installation
// Create a change to record the history of the User object
$oChange = MetaModel::NewObject("CMDBChange");
$oChange->Set("date", time());
$oChange->Set("userinfo", "Initialization");
$iChangeId = $oChange->DBInsert();
// Now record the admin user object
$iUserId = $oUser->DBInsertTrackedNoReload($oChange, true /* skip security */);
$this->SetupUser($iUserId, true);
return true;
}
public function IsAdministrator($oUser)
{
return ($oUser->GetKey() == 1);
}
public function IsPortalUser($oUser)
{
return ($oUser->GetKey() == 1);
}
// Deprecated - create a new module !
public function Setup()
{
// Users must be added manually
// This procedure will then update the matrix when a new user is found or a new class/attribute appears
$oUserSet = new DBObjectSet(DBObjectSearch::FromOQL("SELECT User"));
while ($oUser = $oUserSet->Fetch())
{
$this->SetupUser($oUser->GetKey());
}
return true;
}
protected function SetupUser($iUserId, $bNewUser = false)
{
foreach(array('bizmodel', 'application', 'gui', 'core/cmdb') as $sCategory)
{
foreach (MetaModel::GetClasses($sCategory) as $sClass)
{
foreach (self::$m_aActionCodes as $iActionCode => $sAction)
{
if ($bNewUser)
{
$bAddCell = true;
}
else
{
$oSet = new DBObjectSet(DBObjectSearch::FromOQL("SELECT UserRightsMatrixClassGrant WHERE class = '$sClass' AND action = '$sAction' AND userid = $iUserId"));
$bAddCell = ($oSet->Count() < 1);
}
if ($bAddCell)
{
// Create a new entry
$oMyClassGrant = MetaModel::NewObject("UserRightsMatrixClassGrant");
$oMyClassGrant->Set("userid", $iUserId);
$oMyClassGrant->Set("class", $sClass);
$oMyClassGrant->Set("action", $sAction);
$oMyClassGrant->Set("permission", "yes");
$iId = $oMyClassGrant->DBInsertNoReload();
}
}
foreach (MetaModel::EnumStimuli($sClass) as $sStimulusCode => $oStimulus)
{
if ($bNewUser)
{
$bAddCell = true;
}
else
{
$oSet = new DBObjectSet(DBObjectSearch::FromOQL("SELECT UserRightsMatrixClassStimulusGrant WHERE class = '$sClass' AND stimulus = '$sStimulusCode' AND userid = $iUserId"));
$bAddCell = ($oSet->Count() < 1);
}
if ($bAddCell)
{
// Create a new entry
$oMyClassGrant = MetaModel::NewObject("UserRightsMatrixClassStimulusGrant");
$oMyClassGrant->Set("userid", $iUserId);
$oMyClassGrant->Set("class", $sClass);
$oMyClassGrant->Set("stimulus", $sStimulusCode);
$oMyClassGrant->Set("permission", "yes");
$iId = $oMyClassGrant->DBInsertNoReload();
}
}
foreach (MetaModel::GetAttributesList($sClass) as $sAttCode)
{
if ($bNewUser)
{
$bAddCell = true;
}
else
{
$oSet = new DBObjectSet(DBObjectSearch::FromOQL("SELECT UserRightsMatrixAttributeGrant WHERE class = '$sClass' AND attcode = '$sAttCode' AND userid = $iUserId"));
$bAddCell = ($oSet->Count() < 1);
}
if ($bAddCell)
{
foreach (array('read', 'modify') as $sAction)
{
// Create a new entry
$oMyAttGrant = MetaModel::NewObject("UserRightsMatrixAttributeGrant");
$oMyAttGrant->Set("userid", $iUserId);
$oMyAttGrant->Set("class", $sClass);
$oMyAttGrant->Set("attcode", $sAttCode);
$oMyAttGrant->Set("action", $sAction);
$oMyAttGrant->Set("permission", "yes");
$iId = $oMyAttGrant->DBInsertNoReload();
}
}
}
}
}
/*
// Create the "My Bookmarks" menu item (parent_id = 0, rank = 6)
if ($bNewUser)
{
$bAddMenu = true;
}
else
{
$oSet = new DBObjectSet(DBObjectSearch::FromOQL("SELECT menuNode WHERE type = 'user' AND parent_id = 0 AND user_id = $iUserId"));
$bAddMenu = ($oSet->Count() < 1);
}
if ($bAddMenu)
{
$oMenu = MetaModel::NewObject('menuNode');
$oMenu->Set('type', 'user');
$oMenu->Set('parent_id', 0); // It's a toplevel entry
$oMenu->Set('rank', 6); // Located just above the Admin Tools section (=7)
$oMenu->Set('name', 'My Bookmarks');
$oMenu->Set('label', 'My Favorite Items');
$oMenu->Set('hyperlink', 'UI.php');
$oMenu->Set('template', '<p></p><p></p><p style="text-align:center; font-family:Georgia, Times, serif; font-size:32px;">My bookmarks</p><p style="text-align:center; font-family:Georgia, Times, serif; font-size:14px;"><i>This section contains my most favorite search results</i></p>');
$oMenu->Set('user_id', $iUserId);
$oMenu->DBInsert();
}
*/
}
public function Init()
{
// Could be loaded in a shared memory (?)
return true;
}
public function GetSelectFilter($oUser, $sClass, $aSettings = array())
{
$oNullFilter = new DBObjectSearch($sClass);
return $oNullFilter;
}
public function IsActionAllowed($oUser, $sClass, $iActionCode, $oInstanceSet = null)
{
if (!array_key_exists($iActionCode, self::$m_aActionCodes))
{
return UR_ALLOWED_NO;
}
$sAction = self::$m_aActionCodes[$iActionCode];
$oSet = new DBObjectSet(DBObjectSearch::FromOQL("SELECT UserRightsMatrixClassGrant WHERE class = '$sClass' AND action = '$sAction' AND userid = '{$oUser->GetKey()}'"));
if ($oSet->Count() < 1)
{
return UR_ALLOWED_NO;
}
$oGrantRecord = $oSet->Fetch();
switch ($oGrantRecord->Get('permission'))
{
case 'yes':
$iRetCode = UR_ALLOWED_YES;
break;
case 'no':
default:
$iRetCode = UR_ALLOWED_NO;
break;
}
return $iRetCode;
}
public function IsActionAllowedOnAttribute($oUser, $sClass, $sAttCode, $iActionCode, $oInstanceSet = null)
{
if (!array_key_exists($iActionCode, self::$m_aActionCodes))
{
return UR_ALLOWED_NO;
}
$sAction = self::$m_aActionCodes[$iActionCode];
$oSet = new DBObjectSet(DBObjectSearch::FromOQL("SELECT UserRightsMatrixAttributeGrant WHERE class = '$sClass' AND attcode = '$sAttCode' AND action = '$sAction' AND userid = '{$oUser->GetKey()}'"));
if ($oSet->Count() < 1)
{
return UR_ALLOWED_NO;
}
$oGrantRecord = $oSet->Fetch();
switch ($oGrantRecord->Get('permission'))
{
case 'yes':
$iRetCode = UR_ALLOWED_YES;
break;
case 'no':
default:
$iRetCode = UR_ALLOWED_NO;
break;
}
return $iRetCode;
}
public function IsStimulusAllowed($oUser, $sClass, $sStimulusCode, $oInstanceSet = null)
{
$oSet = new DBObjectSet(DBObjectSearch::FromOQL("SELECT UserRightsMatrixClassStimulusGrant WHERE class = '$sClass' AND stimulus = '$sStimulusCode' AND userid = '{$oUser->GetKey()}'"));
if ($oSet->Count() < 1)
{
return UR_ALLOWED_NO;
}
$oGrantRecord = $oSet->Fetch();
switch ($oGrantRecord->Get('permission'))
{
case 'yes':
$iRetCode = UR_ALLOWED_YES;
break;
case 'no':
default:
$iRetCode = UR_ALLOWED_NO;
break;
}
return $iRetCode;
}
public function FlushPrivileges()
{
}
}
UserRights::SelectModule('UserRightsMatrix');
?>

View File

@@ -1,78 +1,78 @@
<?php
// Copyright (C) 2010-2012 Combodo SARL
//
// This file is part of iTop.
//
// iTop is free software; you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// iTop is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with iTop. If not, see <http://www.gnu.org/licenses/>
/**
* UserRightsNull
* User management Module - say Yeah! to everything
*
* @copyright Copyright (C) 2010-2012 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
class UserRightsNull extends UserRightsAddOnAPI
{
// Installation: create the very first user
public function CreateAdministrator($sAdminUser, $sAdminPwd, $sLanguage = 'EN US')
{
return true;
}
public function IsAdministrator($oUser)
{
return true;
}
public function IsPortalUser($oUser)
{
return true;
}
public function Init()
{
return true;
}
public function GetSelectFilter($oUser, $sClass, $aSettings = array())
{
$oNullFilter = new DBObjectSearch($sClass);
return $oNullFilter;
}
public function IsActionAllowed($oUser, $sClass, $iActionCode, $oInstanceSet = null)
{
return UR_ALLOWED_YES;
}
public function IsStimulusAllowed($oUser, $sClass, $sStimulusCode, $oInstanceSet = null)
{
return UR_ALLOWED_YES;
}
public function IsActionAllowedOnAttribute($oUser, $sClass, $sAttCode, $iActionCode, $oInstanceSet = null)
{
return UR_ALLOWED_YES;
}
public function FlushPrivileges()
{
}
}
UserRights::SelectModule('UserRightsNull');
?>
<?php
// Copyright (C) 2010-2012 Combodo SARL
//
// This file is part of iTop.
//
// iTop is free software; you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// iTop is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with iTop. If not, see <http://www.gnu.org/licenses/>
/**
* UserRightsNull
* User management Module - say Yeah! to everything
*
* @copyright Copyright (C) 2010-2012 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
class UserRightsNull extends UserRightsAddOnAPI
{
// Installation: create the very first user
public function CreateAdministrator($sAdminUser, $sAdminPwd, $sLanguage = 'EN US')
{
return true;
}
public function IsAdministrator($oUser)
{
return true;
}
public function IsPortalUser($oUser)
{
return true;
}
public function Init()
{
return true;
}
public function GetSelectFilter($oUser, $sClass, $aSettings = array())
{
$oNullFilter = new DBObjectSearch($sClass);
return $oNullFilter;
}
public function IsActionAllowed($oUser, $sClass, $iActionCode, $oInstanceSet = null)
{
return UR_ALLOWED_YES;
}
public function IsStimulusAllowed($oUser, $sClass, $sStimulusCode, $oInstanceSet = null)
{
return UR_ALLOWED_YES;
}
public function IsActionAllowedOnAttribute($oUser, $sClass, $sAttCode, $iActionCode, $oInstanceSet = null)
{
return UR_ALLOWED_YES;
}
public function FlushPrivileges()
{
}
}
UserRights::SelectModule('UserRightsNull');
?>

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

328
application/Html2Text.php Normal file
View File

@@ -0,0 +1,328 @@
<?php
namespace Html2Text;
if (!function_exists('mb_split'))
{
function mb_split($pattern, $subject, $limit = -1)
{
return preg_split('/'.$pattern.'/', $subject, $limit);
}
}
/**
* Replace all occurrences of the search string with the replacement string.
*
* @author Sean Murphy <sean@iamseanmurphy.com>
* @copyright Copyright 2012 Sean Murphy. All rights reserved.
* @license http://creativecommons.org/publicdomain/zero/1.0/
* @link http://php.net/manual/function.str-replace.php
*
* @param mixed $search
* @param mixed $replace
* @param mixed $subject
* @param int $count
* @return mixed
*/
function mb_str_replace($search, $replace, $subject, &$count = 0) {
if (!is_array($subject)) {
// Normalize $search and $replace so they are both arrays of the same length
$searches = is_array($search) ? array_values($search) : array($search);
$replacements = is_array($replace) ? array_values($replace) : array($replace);
$replacements = array_pad($replacements, count($searches), '');
foreach ($searches as $key => $search) {
$parts = mb_split(preg_quote($search), $subject);
$count += count($parts) - 1;
$subject = implode($replacements[$key], $parts);
}
} else {
// Call mb_str_replace for each subject in array, recursively
foreach ($subject as $key => $value) {
$subject[$key] = mb_str_replace($search, $replace, $value, $count);
}
}
return $subject;
}
/******************************************************************************
* Copyright (c) 2010 Jevon Wright and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* or
*
* LGPL which is available at http://www.gnu.org/licenses/lgpl.html
*
*
* Contributors:
* Jevon Wright - initial API and implementation
* Denis Flaven - some fixes for properly handling UTF-8 characters
****************************************************************************/
class Html2Text {
/**
* Tries to convert the given HTML into a plain text format - best suited for
* e-mail display, etc.
*
* <p>In particular, it tries to maintain the following features:
* <ul>
* <li>Links are maintained, with the 'href' copied over
* <li>Information in the &lt;head&gt; is lost
* </ul>
*
* @param string html the input HTML
* @return string the HTML converted, as best as possible, to text
* @throws Html2TextException if the HTML could not be loaded as a {@link DOMDocument}
*/
static function convert($html) {
// replace &nbsp; with spaces
$html = str_replace("&nbsp;", " ", $html);
$html = mb_str_replace("\xc2\xa0", " ", $html); // DO NOT USE str_replace since it breaks the "à" character which is \xc3 \xa0 in UTF-8
$html = static::fixNewlines($html);
$doc = new \DOMDocument();
if (!@$doc->loadHTML('<?xml encoding="UTF-8">'.$html)) // Forces the UTF-8 character set for HTML fragments
{
throw new Html2TextException("Could not load HTML - badly formed?", $html);
}
$output = static::iterateOverNode($doc);
// remove leading and trailing spaces on each line
$output = preg_replace("/[ \t]*\n[ \t]*/im", "\n", $output);
$output = preg_replace("/ *\t */im", "\t", $output);
// remove unnecessary empty lines
$output = preg_replace("/\n\n\n*/im", "\n\n", $output);
// remove leading and trailing whitespace
$output = trim($output);
return $output;
}
/**
* Unify newlines; in particular, \r\n becomes \n, and
* then \r becomes \n. This means that all newlines (Unix, Windows, Mac)
* all become \ns.
*
* @param string text text with any number of \r, \r\n and \n combinations
* @return string the fixed text
*/
static function fixNewlines($text) {
// replace \r\n to \n
$text = str_replace("\r\n", "\n", $text);
// remove \rs
$text = str_replace("\r", "\n", $text);
return $text;
}
static function nextChildName($node) {
// get the next child
$nextNode = $node->nextSibling;
while ($nextNode != null) {
if ($nextNode instanceof \DOMElement) {
break;
}
$nextNode = $nextNode->nextSibling;
}
$nextName = null;
if ($nextNode instanceof \DOMElement && $nextNode != null) {
$nextName = strtolower($nextNode->nodeName);
}
return $nextName;
}
static function prevChildName($node) {
// get the previous child
$nextNode = $node->previousSibling;
while ($nextNode != null) {
if ($nextNode instanceof \DOMElement) {
break;
}
$nextNode = $nextNode->previousSibling;
}
$nextName = null;
if ($nextNode instanceof \DOMElement && $nextNode != null) {
$nextName = strtolower($nextNode->nodeName);
}
return $nextName;
}
static function iterateOverNode($node) {
if ($node instanceof \DOMText) {
// Replace whitespace characters with a space (equivilant to \s)
return preg_replace("/[\\t\\n\\f\\r ]+/im", " ", $node->wholeText);
}
if ($node instanceof \DOMDocumentType) {
// ignore
return "";
}
$nextName = static::nextChildName($node);
$prevName = static::prevChildName($node);
$name = strtolower($node->nodeName);
// start whitespace
switch ($name) {
case "hr":
return "---------------------------------------------------------------\n";
case "style":
case "head":
case "title":
case "meta":
case "script":
// ignore these tags
return "";
case "h1":
case "h2":
case "h3":
case "h4":
case "h5":
case "h6":
case "ol":
case "ul":
// add two newlines, second line is added below
$output = "\n";
break;
case "td":
case "th":
// add tab char to separate table fields
$output = "\t";
break;
case "tr":
case "p":
case "div":
// add one line
$output = "\n";
break;
case "li":
$output = "- ";
break;
default:
// print out contents of unknown tags
$output = "";
break;
}
// debug
//$output .= "[$name,$nextName]";
if (isset($node->childNodes)) {
for ($i = 0; $i < $node->childNodes->length; $i++) {
$n = $node->childNodes->item($i);
$text = static::iterateOverNode($n);
$output .= $text;
}
}
// end whitespace
switch ($name) {
case "h1":
case "h2":
case "h3":
case "h4":
case "h5":
case "h6":
$output .= "\n";
break;
case "p":
case "br":
// add one line
if ($nextName != "div")
$output .= "\n";
break;
case "div":
// add one line only if the next child isn't a div
if ($nextName != "div" && $nextName != null)
$output .= "\n";
break;
case "a":
// links are returned in [text](link) format
$href = $node->getAttribute("href");
$output = trim($output);
// remove double [[ ]] s from linking images
if (substr($output, 0, 1) == "[" && substr($output, -1) == "]") {
$output = substr($output, 1, strlen($output) - 2);
// for linking images, the title of the <a> overrides the title of the <img>
if ($node->getAttribute("title")) {
$output = $node->getAttribute("title");
}
}
// if there is no link text, but a title attr
if (!$output && $node->getAttribute("title")) {
$output = $node->getAttribute("title");
}
if ($href == null) {
// it doesn't link anywhere
if ($node->getAttribute("name") != null) {
$output = "[$output]";
}
} else {
if ($href == $output || $href == "mailto:$output" || $href == "http://$output" || $href == "https://$output") {
// link to the same address: just use link
$output;
} else {
// replace it
if ($output) {
$output = "[$output]($href)";
} else {
// empty string
$output = $href;
}
}
}
// does the next node require additional whitespace?
switch ($nextName) {
case "h1": case "h2": case "h3": case "h4": case "h5": case "h6":
$output .= "\n";
break;
}
break;
case "img":
if ($node->getAttribute("title")) {
$output = "[" . $node->getAttribute("title") . "]";
} elseif ($node->getAttribute("alt")) {
$output = "[" . $node->getAttribute("alt") . "]";
} else {
$output = "";
}
break;
case "li":
$output .= "\n";
break;
default:
// do nothing
}
return $output;
}
}

View File

@@ -0,0 +1,28 @@
<?php
/******************************************************************************
* Copyright (c) 2010 Jevon Wright and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* or
*
* LGPL which is available at http://www.gnu.org/licenses/lgpl.html
*
*
* Contributors:
* Jevon Wright - initial API and implementation
****************************************************************************/
namespace Html2Text;
class Html2TextException extends \Exception {
var $more_info;
public function __construct($message = "", $more_info = "") {
parent::__construct($message);
$this->more_info = $more_info;
}
}

View File

@@ -1,397 +1,401 @@
<?php
// Copyright (C) 2010-2015 Combodo SARL
//
// This file is part of iTop.
//
// iTop is free software; you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// iTop is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with iTop. If not, see <http://www.gnu.org/licenses/>
/**
* Simple web page with no includes, header or fancy formatting, useful to
* generate HTML fragments when called by an AJAX method
*
* @copyright Copyright (C) 2010-2015 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
require_once(APPROOT."/application/webpage.class.inc.php");
class ajax_page extends WebPage implements iTabbedPage
{
/**
* Jquery style ready script
* @var Hash
*/
protected $m_sReadyScript;
protected $m_oTabs;
private $m_sMenu; // If set, then the menu will be updated
/**
* constructor for the web page
* @param string $s_title Not used
*/
function __construct($s_title)
{
$sPrintable = utils::ReadParam('printable', '0');
$bPrintable = ($sPrintable == '1');
parent::__construct($s_title, $bPrintable);
$this->m_sReadyScript = "";
//$this->add_header("Content-type: text/html; charset=utf-8");
$this->add_header("Cache-control: no-cache");
$this->m_oTabs = new TabManager();
$this->sContentType = 'text/html';
$this->sContentDisposition = 'inline';
$this->m_sMenu = "";
}
public function AddTabContainer($sTabContainer, $sPrefix = '')
{
$this->add($this->m_oTabs->AddTabContainer($sTabContainer, $sPrefix));
}
public function AddToTab($sTabContainer, $sTabLabel, $sHtml)
{
$this->add($this->m_oTabs->AddToTab($sTabContainer, $sTabLabel, $sHtml));
}
public function SetCurrentTabContainer($sTabContainer = '')
{
return $this->m_oTabs->SetCurrentTabContainer($sTabContainer);
}
public function SetCurrentTab($sTabLabel = '')
{
return $this->m_oTabs->SetCurrentTab($sTabLabel);
}
/**
* Add a tab which content will be loaded asynchronously via the supplied URL
*
* Limitations:
* Cross site scripting is not not allowed for security reasons. Use a normal tab with an IFRAME if you want to pull content from another server.
* Static content cannot be added inside such tabs.
*
* @param string $sTabLabel The (localised) label of the tab
* @param string $sUrl The URL to load (on the same server)
* @param boolean $bCache Whether or not to cache the content of the tab once it has been loaded. flase will cause the tab to be reloaded upon each activation.
* @since 2.0.3
*/
public function AddAjaxTab($sTabLabel, $sUrl, $bCache = true)
{
$this->add($this->m_oTabs->AddAjaxTab($sTabLabel, $sUrl, $bCache));
}
public function GetCurrentTab()
{
return $this->m_oTabs->GetCurrentTab();
}
public function RemoveTab($sTabLabel, $sTabContainer = null)
{
$this->m_oTabs->RemoveTab($sTabLabel, $sTabContainer);
}
/**
* Finds the tab whose title matches a given pattern
* @return mixed The name of the tab as a string or false if not found
*/
public function FindTab($sPattern, $sTabContainer = null)
{
return $this->m_oTabs->FindTab($sPattern, $sTabContainer);
}
/**
* Make the given tab the active one, as if it were clicked
* DOES NOT WORK: apparently in the *old* version of jquery
* that we are using this is not supported... TO DO upgrade
* the whole jquery bundle...
*/
public function SelectTab($sTabContainer, $sTabLabel)
{
$this->add_ready_script($this->m_oTabs->SelectTab($sTabContainer, $sTabLabel));
}
public function AddToMenu($sHtml)
{
$this->m_sMenu .= $sHtml;
}
/**
* Echoes the content of the whole page
* @return void
*/
public function output()
{
if (!empty($this->sContentType))
{
$this->add_header('Content-type: '.$this->sContentType);
}
if (!empty($this->sContentDisposition))
{
$this->add_header('Content-Disposition: '.$this->sContentDisposition.'; filename="'.$this->sContentFileName.'"');
}
foreach($this->a_headers as $s_header)
{
header($s_header);
}
if ($this->m_oTabs->TabsContainerCount() > 0)
{
$this->add_ready_script(
<<<EOF
// The "tab widgets" to handle.
var tabs = $('div[id^=tabbedContent]');
// Ugly patch for a change in the behavior of jQuery UI:
// Before jQuery UI 1.9, tabs were always considered as "local" (opposed to Ajax)
// when their href was beginning by #. Starting with 1.9, a <base> tag in the page
// is taken into account and causes "local" tabs to be considered as Ajax
// unless their URL is equal to the URL of the page...
if ($('base').length > 0)
{
$('div[id^=tabbedContent] > ul > li > a').each(function() {
var sHash = location.hash;
var sCleanLocation = location.href.toString().replace(sHash, '').replace(/#$/, '');
$(this).attr("href", sCleanLocation+$(this).attr("href"));
});
}
if ($.bbq)
{
// This selector will be reused when selecting actual tab widget A elements.
var tab_a_selector = 'ul.ui-tabs-nav a';
// Enable tabs on all tab widgets. The `event` property must be overridden so
// that the tabs aren't changed on click, and any custom event name can be
// specified. Note that if you define a callback for the 'select' event, it
// will be executed for the selected tab whenever the hash changes.
tabs.tabs({ event: 'change' });
// Define our own click handler for the tabs, overriding the default.
tabs.find( tab_a_selector ).click(function()
{
var state = {};
// Get the id of this tab widget.
var id = $(this).closest( 'div[id^=tabbedContent]' ).attr( 'id' );
// Get the index of this tab.
var idx = $(this).parent().prevAll().length;
// Set the state!
state[ id ] = idx;
$.bbq.pushState( state );
});
}
else
{
tabs.tabs();
}
EOF
);
}
// Render the tabs in the page (if any)
$this->s_content = $this->m_oTabs->RenderIntoContent($this->s_content, $this);
// Additional UI widgets to be activated inside the ajax fragment ??
if (($this->sContentType == 'text/html') && (preg_match('/class="date-pick"/', $this->s_content) || preg_match('/class="datetime-pick"/', $this->s_content)) )
{
$this->add_ready_script(
<<<EOF
$(".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
);
}
$s_captured_output = $this->ob_get_clean_safe();
if (($this->sContentType == 'text/html') && ($this->sContentDisposition == 'inline'))
{
// inline content != attachment && html => filter all scripts for malicious XSS scripts
echo self::FilterXSS($this->s_content);
}
else
{
echo $this->s_content;
}
if (!empty($this->m_sMenu))
{
$uid = time();
echo "<div id=\"accordion_temp_$uid\">\n";
echo "<div id=\"accordion\">\n";
echo "<!-- Beginning of the accordion menu -->\n";
echo self::FilterXSS($this->m_sMenu);
echo "<!-- End of the accordion menu-->\n";
echo "</div>\n";
echo "</div>\n";
echo "<script type=\"text/javascript\">\n";
echo "$('#inner_menu').html($('#accordion_temp_$uid').html());\n";
echo "$('#accordion_temp_$uid').remove();\n";
echo "$('#accordion').accordion({ header: 'h3', navigation: true, autoHeight: false, collapsible: false, icons: false });\n";
echo "\n</script>\n";
}
//echo $this->s_deferred_content;
if (count($this->a_scripts) > 0)
{
echo "<script type=\"text/javascript\">\n";
echo implode("\n", $this->a_scripts);
echo "\n</script>\n";
}
if (!empty($this->s_deferred_content))
{
echo "<script type=\"text/javascript\">\n";
echo "\$('body').append('".addslashes(str_replace("\n", '', $this->s_deferred_content))."');\n";
echo "\n</script>\n";
}
if (!empty($this->m_sReadyScript))
{
echo "<script type=\"text/javascript\">\n";
echo $this->m_sReadyScript; // Ready Scripts are output as simple scripts
echo "\n</script>\n";
}
if (trim($s_captured_output) != "")
{
echo self::FilterXSS($s_captured_output);
}
if (class_exists('DBSearch'))
{
DBSearch::RecordQueryTrace();
}
}
/**
* Adds a paragraph with a smaller font into the page
* NOT implemented (i.e does nothing)
* @param string $sText Content of the (small) paragraph
* @return void
*/
public function small_p($sText)
{
}
public function add($sHtml)
{
if (($this->m_oTabs->GetCurrentTabContainer() != '') && ($this->m_oTabs->GetCurrentTab() != ''))
{
$this->m_oTabs->AddToTab($this->m_oTabs->GetCurrentTabContainer(), $this->m_oTabs->GetCurrentTab(), $sHtml);
}
else
{
parent::add($sHtml);
}
}
/**
* Records the current state of the 'html' part of the page output
* @return mixed The current state of the 'html' output
*/
public function start_capture()
{
$sCurrentTabContainer = $this->m_oTabs->GetCurrentTabContainer();
$sCurrentTab = $this->m_oTabs->GetCurrentTab();
if (!empty($sCurrentTabContainer) && !empty($sCurrentTab))
{
$iOffset = $this->m_oTabs->GetCurrentTabLength();
return array('tc' => $sCurrentTabContainer, 'tab' => $sCurrentTab, 'offset' => $iOffset);
}
else
{
return parent::start_capture();
}
}
/**
* Returns the part of the html output that occurred since the call to start_capture
* and removes this part from the current html output
* @param $offset mixed The value returned by start_capture
* @return string The part of the html output that was added since the call to start_capture
*/
public function end_capture($offset)
{
if (is_array($offset))
{
if ($this->m_oTabs->TabExists($offset['tc'], $offset['tab']))
{
$sCaptured = $this->m_oTabs->TruncateTab($offset['tc'], $offset['tab'], $offset['offset']);
}
else
{
$sCaptured = '';
}
}
else
{
$sCaptured = parent::end_capture($offset);
}
return $sCaptured;
}
/**
* Add any text or HTML fragment (identified by an ID) at the end of the body of the page
* This is useful to add hidden content, DIVs or FORMs that should not
* be embedded into each other.
*/
public function add_at_the_end($s_html, $sId = '')
{
if ($sId != '')
{
$this->add_script("$('#{$sId}').remove();"); // Remove any previous instance of the same Id
}
$this->s_deferred_content .= $s_html;
}
/**
* Adds a script to be executed when the DOM is ready (typical JQuery use)
* NOT implemented in this version of the class.
* @return void
*/
public function add_ready_script($sScript)
{
$this->m_sReadyScript .= $sScript."\n";
}
/**
* Cannot be called in this context, since Ajax pages do not share
* any context with the calling page !!
*/
public function GetUniqueId()
{
assert(false);
return 0;
}
public static function FilterXSS($sHTML)
{
return str_ireplace(array('<script', '</script>'), array('<!-- <removed-script', '</removed-script> -->'), $sHTML);
}
}
<?php
// Copyright (C) 2010-2018 Combodo SARL
//
// This file is part of iTop.
//
// iTop is free software; you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// iTop is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with iTop. If not, see <http://www.gnu.org/licenses/>
/**
* Simple web page with no includes, header or fancy formatting, useful to
* generate HTML fragments when called by an AJAX method
*
* @copyright Copyright (C) 2010-2017 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
require_once(APPROOT."/application/webpage.class.inc.php");
class ajax_page extends WebPage implements iTabbedPage
{
/**
* Jquery style ready script
* @var Hash
*/
protected $m_sReadyScript;
protected $m_oTabs;
private $m_sMenu; // If set, then the menu will be updated
/**
* constructor for the web page
* @param string $s_title Not used
*/
function __construct($s_title)
{
$sPrintable = utils::ReadParam('printable', '0');
$bPrintable = ($sPrintable == '1');
parent::__construct($s_title, $bPrintable);
$this->m_sReadyScript = "";
//$this->add_header("Content-type: text/html; charset=utf-8");
$this->add_header("Cache-control: no-cache");
$this->m_oTabs = new TabManager();
$this->sContentType = 'text/html';
$this->sContentDisposition = 'inline';
$this->m_sMenu = "";
utils::InitArchiveMode();
}
public function AddTabContainer($sTabContainer, $sPrefix = '')
{
$this->add($this->m_oTabs->AddTabContainer($sTabContainer, $sPrefix));
}
public function AddToTab($sTabContainer, $sTabLabel, $sHtml)
{
$this->add($this->m_oTabs->AddToTab($sTabContainer, $sTabLabel, $sHtml));
}
public function SetCurrentTabContainer($sTabContainer = '')
{
return $this->m_oTabs->SetCurrentTabContainer($sTabContainer);
}
public function SetCurrentTab($sTabLabel = '')
{
return $this->m_oTabs->SetCurrentTab($sTabLabel);
}
/**
* Add a tab which content will be loaded asynchronously via the supplied URL
*
* Limitations:
* Cross site scripting is not not allowed for security reasons. Use a normal tab with an IFRAME if you want to pull content from another server.
* Static content cannot be added inside such tabs.
*
* @param string $sTabLabel The (localised) label of the tab
* @param string $sUrl The URL to load (on the same server)
* @param boolean $bCache Whether or not to cache the content of the tab once it has been loaded. flase will cause the tab to be reloaded upon each activation.
* @since 2.0.3
*/
public function AddAjaxTab($sTabLabel, $sUrl, $bCache = true)
{
$this->add($this->m_oTabs->AddAjaxTab($sTabLabel, $sUrl, $bCache));
}
public function GetCurrentTab()
{
return $this->m_oTabs->GetCurrentTab();
}
public function RemoveTab($sTabLabel, $sTabContainer = null)
{
$this->m_oTabs->RemoveTab($sTabLabel, $sTabContainer);
}
/**
* Finds the tab whose title matches a given pattern
* @return mixed The name of the tab as a string or false if not found
*/
public function FindTab($sPattern, $sTabContainer = null)
{
return $this->m_oTabs->FindTab($sPattern, $sTabContainer);
}
/**
* Make the given tab the active one, as if it were clicked
* DOES NOT WORK: apparently in the *old* version of jquery
* that we are using this is not supported... TO DO upgrade
* the whole jquery bundle...
*/
public function SelectTab($sTabContainer, $sTabLabel)
{
$this->add_ready_script($this->m_oTabs->SelectTab($sTabContainer, $sTabLabel));
}
public function AddToMenu($sHtml)
{
$this->m_sMenu .= $sHtml;
}
/**
* Echoes the content of the whole page
* @return void
*/
public function output()
{
if (!empty($this->sContentType))
{
$this->add_header('Content-type: '.$this->sContentType);
}
if (!empty($this->sContentDisposition))
{
$this->add_header('Content-Disposition: '.$this->sContentDisposition.'; filename="'.$this->sContentFileName.'"');
}
foreach($this->a_headers as $s_header)
{
header($s_header);
}
if ($this->m_oTabs->TabsContainerCount() > 0)
{
$this->add_ready_script(
<<<EOF
// The "tab widgets" to handle.
var tabs = $('div[id^=tabbedContent]');
// Ugly patch for a change in the behavior of jQuery UI:
// Before jQuery UI 1.9, tabs were always considered as "local" (opposed to Ajax)
// when their href was beginning by #. Starting with 1.9, a <base> tag in the page
// is taken into account and causes "local" tabs to be considered as Ajax
// unless their URL is equal to the URL of the page...
if ($('base').length > 0)
{
$('div[id^=tabbedContent] > ul > li > a').each(function() {
var sHash = location.hash;
var sCleanLocation = location.href.toString().replace(sHash, '').replace(/#$/, '');
$(this).attr("href", sCleanLocation+$(this).attr("href"));
});
}
if ($.bbq)
{
// This selector will be reused when selecting actual tab widget A elements.
var tab_a_selector = 'ul.ui-tabs-nav a';
// Enable tabs on all tab widgets. The `event` property must be overridden so
// that the tabs aren't changed on click, and any custom event name can be
// specified. Note that if you define a callback for the 'select' event, it
// will be executed for the selected tab whenever the hash changes.
tabs.tabs({ event: 'change' });
// Define our own click handler for the tabs, overriding the default.
tabs.find( tab_a_selector ).click(function()
{
var state = {};
// Get the id of this tab widget.
var id = $(this).closest( 'div[id^=tabbedContent]' ).attr( 'id' );
// Get the index of this tab.
var idx = $(this).parent().prevAll().length;
// Set the state!
state[ id ] = idx;
$.bbq.pushState( state );
});
}
else
{
tabs.tabs();
}
EOF
);
}
// Render the tabs in the page (if any)
$this->s_content = $this->m_oTabs->RenderIntoContent($this->s_content, $this);
// Additional UI widgets to be activated inside the ajax fragment
// Important: Testing the content type is not enough because some ajax handlers have not correctly positionned the flag (e.g json response corrupted by the script)
if (($this->sContentType == 'text/html') && (preg_match('/class="date-pick"/', $this->s_content) || preg_match('/class="datetime-pick"/', $this->s_content)) )
{
$this->add_ready_script(
<<<EOF
PrepareWidgets();
EOF
);
}
$s_captured_output = $this->ob_get_clean_safe();
if (($this->sContentType == 'text/html') && ($this->sContentDisposition == 'inline'))
{
// inline content != attachment && html => filter all scripts for malicious XSS scripts
echo self::FilterXSS($this->s_content);
}
else
{
echo $this->s_content;
}
if (!empty($this->m_sMenu))
{
$uid = time();
echo "<div id=\"accordion_temp_$uid\">\n";
echo "<div id=\"accordion\">\n";
echo "<!-- Beginning of the accordion menu -->\n";
echo self::FilterXSS($this->m_sMenu);
echo "<!-- End of the accordion menu-->\n";
echo "</div>\n";
echo "</div>\n";
echo "<script type=\"text/javascript\">\n";
echo "$('#inner_menu').html($('#accordion_temp_$uid').html());\n";
echo "$('#accordion_temp_$uid').remove();\n";
echo "\n</script>\n";
}
//echo $this->s_deferred_content;
if (count($this->a_scripts) > 0)
{
echo "<script type=\"text/javascript\">\n";
echo implode("\n", $this->a_scripts);
echo "\n</script>\n";
}
if (count($this->a_linked_scripts) > 0)
{
echo "<script type=\"text/javascript\">\n";
foreach($this->a_linked_scripts as $sScriptUrl)
{
echo '$.getScript('.json_encode($sScriptUrl).");\n";
}
echo "\n</script>\n";
}
if (!empty($this->s_deferred_content))
{
echo "<script type=\"text/javascript\">\n";
echo "\$('body').append('".addslashes(str_replace("\n", '', $this->s_deferred_content))."');\n";
echo "\n</script>\n";
}
if (!empty($this->m_sReadyScript))
{
echo "<script type=\"text/javascript\">\n";
echo $this->m_sReadyScript; // Ready Scripts are output as simple scripts
echo "\n</script>\n";
}
if(count($this->a_linked_stylesheets) > 0)
{
echo "<script type=\"text/javascript\">";
foreach($this->a_linked_stylesheets as $aStylesheet)
{
$sStylesheetUrl = $aStylesheet['link'];
echo "if (!$('link[href=\"{$sStylesheetUrl}\"]').length) $('<link href=\"{$sStylesheetUrl}\" rel=\"stylesheet\">').appendTo('head');\n";
}
echo "\n</script>\n";
}
if (trim($s_captured_output) != "")
{
echo self::FilterXSS($s_captured_output);
}
if (class_exists('DBSearch'))
{
DBSearch::RecordQueryTrace();
}
}
/**
* Adds a paragraph with a smaller font into the page
* NOT implemented (i.e does nothing)
* @param string $sText Content of the (small) paragraph
* @return void
*/
public function small_p($sText)
{
}
public function add($sHtml)
{
if (($this->m_oTabs->GetCurrentTabContainer() != '') && ($this->m_oTabs->GetCurrentTab() != ''))
{
$this->m_oTabs->AddToTab($this->m_oTabs->GetCurrentTabContainer(), $this->m_oTabs->GetCurrentTab(), $sHtml);
}
else
{
parent::add($sHtml);
}
}
/**
* Records the current state of the 'html' part of the page output
* @return mixed The current state of the 'html' output
*/
public function start_capture()
{
$sCurrentTabContainer = $this->m_oTabs->GetCurrentTabContainer();
$sCurrentTab = $this->m_oTabs->GetCurrentTab();
if (!empty($sCurrentTabContainer) && !empty($sCurrentTab))
{
$iOffset = $this->m_oTabs->GetCurrentTabLength();
return array('tc' => $sCurrentTabContainer, 'tab' => $sCurrentTab, 'offset' => $iOffset);
}
else
{
return parent::start_capture();
}
}
/**
* Returns the part of the html output that occurred since the call to start_capture
* and removes this part from the current html output
* @param $offset mixed The value returned by start_capture
* @return string The part of the html output that was added since the call to start_capture
*/
public function end_capture($offset)
{
if (is_array($offset))
{
if ($this->m_oTabs->TabExists($offset['tc'], $offset['tab']))
{
$sCaptured = $this->m_oTabs->TruncateTab($offset['tc'], $offset['tab'], $offset['offset']);
}
else
{
$sCaptured = '';
}
}
else
{
$sCaptured = parent::end_capture($offset);
}
return $sCaptured;
}
/**
* Add any text or HTML fragment (identified by an ID) at the end of the body of the page
* This is useful to add hidden content, DIVs or FORMs that should not
* be embedded into each other.
*/
public function add_at_the_end($s_html, $sId = '')
{
if ($sId != '')
{
$this->add_script("$('#{$sId}').remove();"); // Remove any previous instance of the same Id
}
$this->s_deferred_content .= $s_html;
}
/**
* Adds a script to be executed when the DOM is ready (typical JQuery use)
* NOT implemented in this version of the class.
* @return void
*/
public function add_ready_script($sScript)
{
$this->m_sReadyScript .= $sScript."\n";
}
/**
* Cannot be called in this context, since Ajax pages do not share
* any context with the calling page !!
*/
public function GetUniqueId()
{
assert(false);
return 0;
}
public static function FilterXSS($sHTML)
{
return str_ireplace(array('<script', '</script>'), array('<!-- <removed-script', '</removed-script> -->'), $sHTML);
}
}

View File

@@ -1,41 +1,40 @@
<?php
// Copyright (C) 2010-2012 Combodo SARL
//
// This file is part of iTop.
//
// iTop is free software; you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// iTop is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with iTop. If not, see <http://www.gnu.org/licenses/>
/**
* Includes all the classes to have the application up and running
*
* @copyright Copyright (C) 2010-2012 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
require_once(APPROOT.'/application/applicationcontext.class.inc.php');
require_once(APPROOT.'/application/cmdbabstract.class.inc.php');
require_once(APPROOT.'/application/displayblock.class.inc.php');
require_once(APPROOT.'/application/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.'/setup/moduleinstallation.class.inc.php');
//require_once(APPROOT.'/application/menunode.class.inc.php');
require_once(APPROOT.'/application/utils.inc.php');
class ApplicationException extends CoreException
{
}
?>
<?php
// Copyright (C) 2010-2012 Combodo SARL
//
// This file is part of iTop.
//
// iTop is free software; you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// iTop is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with iTop. If not, see <http://www.gnu.org/licenses/>
/**
* Includes all the classes to have the application up and running
*
* @copyright Copyright (C) 2010-2012 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
require_once(APPROOT.'/application/applicationcontext.class.inc.php');
require_once(APPROOT.'/application/cmdbabstract.class.inc.php');
require_once(APPROOT.'/application/displayblock.class.inc.php');
require_once(APPROOT.'/application/audit.category.class.inc.php');
require_once(APPROOT.'/application/audit.rule.class.inc.php');
require_once(APPROOT.'/application/query.class.inc.php');
require_once(APPROOT.'/setup/moduleinstallation.class.inc.php');
//require_once(APPROOT.'/application/menunode.class.inc.php');
require_once(APPROOT.'/application/utils.inc.php');
class ApplicationException extends CoreException
{
}
?>

View File

@@ -1,362 +1,409 @@
<?php
// Copyright (C) 2010-2012 Combodo SARL
//
// This file is part of iTop.
//
// iTop is free software; you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// iTop is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with iTop. If not, see <http://www.gnu.org/licenses/>
/**
* Class ApplicationContext
*
* @copyright Copyright (C) 2010-2012 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
require_once(APPROOT."/application/utils.inc.php");
/**
* Interface for directing end-users to the relevant application
*/
interface iDBObjectURLMaker
{
public static function MakeObjectURL($sClass, $iId);
}
/**
* Direct end-users to the standard iTop application: UI.php
*/
class iTopStandardURLMaker implements iDBObjectURLMaker
{
public static function MakeObjectURL($sClass, $iId)
{
$sPage = DBObject::ComputeStandardUIPage($sClass);
$sAbsoluteUrl = utils::GetAbsoluteUrlAppRoot();
$sUrl = "{$sAbsoluteUrl}pages/$sPage?operation=details&class=$sClass&id=$iId";
return $sUrl;
}
}
/**
* Direct end-users to the standard Portal application
*/
class PortalURLMaker implements iDBObjectURLMaker
{
public static function MakeObjectURL($sClass, $iId)
{
$sAbsoluteUrl = utils::GetAbsoluteUrlAppRoot();
$sUrl = "{$sAbsoluteUrl}portal/index.php?operation=details&class=$sClass&id=$iId";
return $sUrl;
}
}
/**
* Helper class to store and manipulate the parameters that make the application's context
*
* Usage:
* 1) Build the application's context by constructing the object
* (the object will read some of the page's parameters)
*
* 2) Add these parameters to hyperlinks or to forms using the helper, functions
* GetForLink(), GetForForm() or GetAsHash()
*/
class ApplicationContext
{
protected $aNames;
protected $aValues;
protected static $aDefaultValues; // Cache shared among all instances
public function __construct($bReadContext = true)
{
$this->aNames = array(
'org_id', 'menu'
);
if ($bReadContext)
{
$this->ReadContext();
}
}
/**
* Read the context directly in the PHP parameters (either POST or GET)
* return nothing
*/
protected function ReadContext()
{
if (!isset(self::$aDefaultValues))
{
self::$aDefaultValues = array();
$aContext = utils::ReadParam('c', array(), false, 'context_param');
foreach($this->aNames as $sName)
{
$sValue = isset($aContext[$sName]) ? $aContext[$sName] : '';
// TO DO: check if some of the context parameters are mandatory (or have default values)
if (!empty($sValue))
{
self::$aDefaultValues[$sName] = $sValue;
}
// Hmm, there must be a better (more generic) way to handle the case below:
// When there is only one possible (allowed) organization, the context must be
// fixed to this org
if ($sName == 'org_id')
{
if (MetaModel::IsValidClass('Organization'))
{
$oSearchFilter = new DBObjectSearch('Organization');
$oSearchFilter->SetModifierProperty('UserRightsGetSelectFilter', 'bSearchMode', true);
$oSet = new CMDBObjectSet($oSearchFilter);
$iCount = $oSet->Count();
if ($iCount == 1)
{
// Only one possible value for org_id, set it in the context
$oOrg = $oSet->Fetch();
self::$aDefaultValues[$sName] = $oOrg->GetKey();
}
}
}
}
}
$this->aValues = self::$aDefaultValues;
}
/**
* Returns the current value for the given parameter
* @param string $sParamName Name of the parameter to read
* @return mixed The value for this parameter
*/
public function GetCurrentValue($sParamName, $defaultValue = '')
{
if (isset($this->aValues[$sParamName]))
{
return $this->aValues[$sParamName];
}
return $defaultValue;
}
/**
* Returns the context as string with the format name1=value1&name2=value2....
* return string The context as a string to be appended to an href property
*/
public function GetForLink()
{
$aParams = array();
foreach($this->aValues as $sName => $sValue)
{
$aParams[] = "c[$sName]".'='.urlencode($sValue);
}
return implode("&", $aParams);
}
/**
* Returns the context as sequence of input tags to be inserted inside a <form> tag
* return string The context as a sequence of <input type="hidden" /> tags
*/
public function GetForForm()
{
$sContext = "";
foreach($this->aValues as $sName => $sValue)
{
$sContext .= "<input type=\"hidden\" name=\"c[$sName]\" value=\"".htmlentities($sValue, ENT_QUOTES, 'UTF-8')."\" />\n";
}
return $sContext;
}
/**
* Returns the context as a hash array 'parameter_name' => value
* return array The context information
*/
public function GetAsHash()
{
$aReturn = array();
foreach($this->aValues as $sName => $sValue)
{
$aReturn["c[$sName]"] = $sValue;
}
return $aReturn;
}
/**
* Returns an array of the context parameters NAMEs
* @return array The list of context parameters
*/
public function GetNames()
{
return $this->aNames;
}
/**
* Removes the specified parameter from the context, for example when the same parameter
* is already a search parameter
* @param string $sParamName Name of the parameter to remove
* @return none
*/
public function Reset($sParamName)
{
if (isset($this->aValues[$sParamName]))
{
unset($this->aValues[$sParamName]);
}
}
/**
* Initializes the given object with the default values provided by the context
*/
public function InitObjectFromContext(DBObject &$oObj)
{
$sClass = get_class($oObj);
foreach($this->GetNames() as $key)
{
$aCallSpec = array($sClass, 'MapContextParam');
if (is_callable($aCallSpec))
{
$sAttCode = call_user_func($aCallSpec, $key); // Returns null when there is no mapping for this parameter
if (MetaModel::IsValidAttCode($sClass, $sAttCode))
{
$oAttDef = MetaModel::GetAttributeDef($sClass, $sAttCode);
if ($oAttDef->IsWritable())
{
$value = $this->GetCurrentValue($key, null);
if (!is_null($value))
{
$oObj->Set($sAttCode, $value);
}
}
}
}
}
}
static $m_sUrlMakerClass = null;
/**
* Set the current application url provider
* @param sClass string Class implementing iDBObjectURLMaker
* @return void
*/
public static function SetUrlMakerClass($sClass = 'iTopStandardURLMaker')
{
$sPrevious = self::GetUrlMakerClass();
self::$m_sUrlMakerClass = $sClass;
$_SESSION['UrlMakerClass'] = $sClass;
return $sPrevious;
}
/**
* Get the current application url provider
* @return string the name of the class
*/
public static function GetUrlMakerClass()
{
if (is_null(self::$m_sUrlMakerClass))
{
if (isset($_SESSION['UrlMakerClass']))
{
self::$m_sUrlMakerClass = $_SESSION['UrlMakerClass'];
}
else
{
self::$m_sUrlMakerClass = 'iTopStandardURLMaker';
}
}
return self::$m_sUrlMakerClass;
}
/**
* Get the current application url provider
* @return string the name of the class
*/
public static function MakeObjectUrl($sObjClass, $sObjKey, $sUrlMakerClass = null, $bWithNavigationContext = true)
{
$oAppContext = new ApplicationContext();
if (is_null($sUrlMakerClass))
{
$sUrlMakerClass = self::GetUrlMakerClass();
}
$sUrl = call_user_func(array($sUrlMakerClass, 'MakeObjectUrl'), $sObjClass, $sObjKey);
if (strlen($sUrl) > 0)
{
if ($bWithNavigationContext)
{
return $sUrl."&".$oAppContext->GetForLink();
}
else
{
return $sUrl;
}
}
else
{
return '';
}
}
protected static $m_aPluginProperties = null;
/**
* Load plugin properties for the current session
* @return void
*/
protected static function LoadPluginProperties()
{
if (isset($_SESSION['PluginProperties']))
{
self::$m_aPluginProperties = $_SESSION['PluginProperties'];
}
else
{
self::$m_aPluginProperties = array();
}
}
/**
* Set plugin properties
* @param sPluginClass string Class implementing any plugin interface
* @param sProperty string Name of the property
* @param value scalar Value (numeric or string)
* @return void
*/
public static function SetPluginProperty($sPluginClass, $sProperty, $value)
{
if (is_null(self::$m_aPluginProperties)) self::LoadPluginProperties();
self::$m_aPluginProperties[$sPluginClass][$sProperty] = $value;
$_SESSION['PluginProperties'][$sPluginClass][$sProperty] = $value;
}
/**
* Get plugin properties
* @param sPluginClass string Class implementing any plugin interface
* @return array of sProperty=>value pairs
*/
public static function GetPluginProperties($sPluginClass)
{
if (is_null(self::$m_aPluginProperties)) self::LoadPluginProperties();
if (array_key_exists($sPluginClass, self::$m_aPluginProperties))
{
return self::$m_aPluginProperties[$sPluginClass];
}
else
{
return array();
}
}
}
?>
<?php
// Copyright (C) 2010-2018 Combodo SARL
//
// This file is part of iTop.
//
// iTop is free software; you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// iTop is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with iTop. If not, see <http://www.gnu.org/licenses/>
/**
* Class ApplicationContext
*
* @copyright Copyright (C) 2010-2018 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
require_once(APPROOT."/application/utils.inc.php");
/**
* Interface for directing end-users to the relevant application
*/
interface iDBObjectURLMaker
{
/**
* @param string $sClass
* @param string $iId
*
* @return string
*/
public static function MakeObjectURL($sClass, $iId);
}
/**
* Direct end-users to the standard iTop application: UI.php
*/
class iTopStandardURLMaker implements iDBObjectURLMaker
{
/**
* @param string $sClass
* @param string $iId
*
* @return string
* @throws \Exception
*/
public static function MakeObjectURL($sClass, $iId)
{
$sPage = DBObject::ComputeStandardUIPage($sClass);
$sAbsoluteUrl = utils::GetAbsoluteUrlAppRoot();
$sUrl = "{$sAbsoluteUrl}pages/$sPage?operation=details&class=$sClass&id=$iId";
return $sUrl;
}
}
/**
* Direct end-users to the standard Portal application
*/
class PortalURLMaker implements iDBObjectURLMaker
{
/**
* @param string $sClass
* @param string $iId
*
* @return string
* @throws \Exception
*/
public static function MakeObjectURL($sClass, $iId)
{
$sAbsoluteUrl = utils::GetAbsoluteUrlAppRoot();
$sUrl = "{$sAbsoluteUrl}portal/index.php?operation=details&class=$sClass&id=$iId";
return $sUrl;
}
}
/**
* Helper class to store and manipulate the parameters that make the application's context
*
* Usage:
* 1) Build the application's context by constructing the object
* (the object will read some of the page's parameters)
*
* 2) Add these parameters to hyperlinks or to forms using the helper, functions
* GetForLink(), GetForForm() or GetAsHash()
*/
class ApplicationContext
{
public static $m_sUrlMakerClass = null;
protected static $m_aPluginProperties = null;
protected static $aDefaultValues; // Cache shared among all instances
protected $aNames;
protected $aValues;
/**
* ApplicationContext constructor.
*
* @param bool $bReadContext
*
* @throws \Exception
*/
public function __construct($bReadContext = true)
{
$this->aNames = array(
'org_id', 'menu'
);
if ($bReadContext)
{
$this->ReadContext();
}
}
/**
* Read the context directly in the PHP parameters (either POST or GET)
* return nothing
*
* @throws \Exception
*/
protected function ReadContext()
{
if (!isset(self::$aDefaultValues))
{
self::$aDefaultValues = array();
$aContext = utils::ReadParam('c', array(), false, 'context_param');
foreach($this->aNames as $sName)
{
$sValue = isset($aContext[$sName]) ? $aContext[$sName] : '';
// TO DO: check if some of the context parameters are mandatory (or have default values)
if (!empty($sValue))
{
self::$aDefaultValues[$sName] = $sValue;
}
// Hmm, there must be a better (more generic) way to handle the case below:
// When there is only one possible (allowed) organization, the context must be
// fixed to this org unless there is only one organization in the system then
// no filter is applied
if ($sName == 'org_id')
{
if (MetaModel::IsValidClass('Organization'))
{
$oSearchFilter = new DBObjectSearch('Organization');
$oSet = new CMDBObjectSet($oSearchFilter);
$iCount = $oSet->CountWithLimit(2);
if ($iCount > 1)
{
$oSearchFilter->SetModifierProperty('UserRightsGetSelectFilter', 'bSearchMode', true);
$oSet = new CMDBObjectSet($oSearchFilter);
$iCount = $oSet->CountWithLimit(2);
if ($iCount == 1)
{
// Only one possible value for org_id, set it in the context
$oOrg = $oSet->Fetch();
self::$aDefaultValues[$sName] = $oOrg->GetKey();
}
}
}
}
}
}
$this->aValues = self::$aDefaultValues;
}
/**
* Returns the current value for the given parameter
*
* @param string $sParamName Name of the parameter to read
* @param string $defaultValue
*
* @return mixed The value for this parameter
*/
public function GetCurrentValue($sParamName, $defaultValue = '')
{
if (isset($this->aValues[$sParamName]))
{
return $this->aValues[$sParamName];
}
return $defaultValue;
}
/**
* Returns the context as string with the format name1=value1&name2=value2....
* @return string The context as a string to be appended to an href property
*/
public function GetForLink()
{
$aParams = array();
foreach($this->aValues as $sName => $sValue)
{
$aParams[] = "c[$sName]".'='.urlencode($sValue);
}
return implode("&", $aParams);
}
/**
* Returns the context as sequence of input tags to be inserted inside a <form> tag
* @return string The context as a sequence of <input type="hidden" /> tags
*/
public function GetForForm()
{
$sContext = "";
foreach($this->aValues as $sName => $sValue)
{
$sContext .= "<input type=\"hidden\" name=\"c[$sName]\" value=\"".htmlentities($sValue, ENT_QUOTES, 'UTF-8')."\" />\n";
}
return $sContext;
}
/**
* Returns the context as a hash array 'parameter_name' => value
* @return array The context information
*/
public function GetAsHash()
{
$aReturn = array();
foreach($this->aValues as $sName => $sValue)
{
$aReturn["c[$sName]"] = $sValue;
}
return $aReturn;
}
/**
* Returns an array of the context parameters NAMEs
* @return array The list of context parameters
*/
public function GetNames()
{
return $this->aNames;
}
/**
* Removes the specified parameter from the context, for example when the same parameter
* is already a search parameter
* @param string $sParamName Name of the parameter to remove
*/
public function Reset($sParamName)
{
if (isset($this->aValues[$sParamName]))
{
unset($this->aValues[$sParamName]);
}
}
/**
* Initializes the given object with the default values provided by the context
*
* @param \DBObject $oObj
*
* @throws \Exception
* @throws \CoreUnexpectedValue
*/
public function InitObjectFromContext(DBObject &$oObj)
{
$sClass = get_class($oObj);
foreach($this->GetNames() as $key)
{
$aCallSpec = array($sClass, 'MapContextParam');
if (is_callable($aCallSpec))
{
$sAttCode = call_user_func($aCallSpec, $key); // Returns null when there is no mapping for this parameter
if (MetaModel::IsValidAttCode($sClass, $sAttCode))
{
$oAttDef = MetaModel::GetAttributeDef($sClass, $sAttCode);
if ($oAttDef->IsWritable())
{
$value = $this->GetCurrentValue($key, null);
if (!is_null($value))
{
$oObj->Set($sAttCode, $value);
}
}
}
}
}
}
/**
* Set the current application url provider
* @param string $sClass Class implementing iDBObjectURLMaker
* @return string
*/
public static function SetUrlMakerClass($sClass = 'iTopStandardURLMaker')
{
$sPrevious = self::GetUrlMakerClass();
self::$m_sUrlMakerClass = $sClass;
$_SESSION['UrlMakerClass'] = $sClass;
return $sPrevious;
}
/**
* Get the current application url provider
* @return string the name of the class
*/
public static function GetUrlMakerClass()
{
if (is_null(self::$m_sUrlMakerClass))
{
if (isset($_SESSION['UrlMakerClass']))
{
self::$m_sUrlMakerClass = $_SESSION['UrlMakerClass'];
}
else
{
self::$m_sUrlMakerClass = 'iTopStandardURLMaker';
}
}
return self::$m_sUrlMakerClass;
}
/**
* Get the current application url provider
*
* @param string $sObjClass
* @param string $sObjKey
* @param null $sUrlMakerClass
* @param bool $bWithNavigationContext
*
* @return string the name of the class
* @throws \Exception
*/
public static function MakeObjectUrl($sObjClass, $sObjKey, $sUrlMakerClass = null, $bWithNavigationContext = true)
{
$oAppContext = new ApplicationContext();
if (is_null($sUrlMakerClass))
{
$sUrlMakerClass = self::GetUrlMakerClass();
}
$sUrl = call_user_func(array($sUrlMakerClass, 'MakeObjectUrl'), $sObjClass, $sObjKey);
if (strlen($sUrl) > 0)
{
if ($bWithNavigationContext)
{
return $sUrl."&".$oAppContext->GetForLink();
}
else
{
return $sUrl;
}
}
else
{
return '';
}
}
/**
* Load plugin properties for the current session
* @return void
*/
protected static function LoadPluginProperties()
{
if (isset($_SESSION['PluginProperties']))
{
self::$m_aPluginProperties = $_SESSION['PluginProperties'];
}
else
{
self::$m_aPluginProperties = array();
}
}
/**
* Set plugin properties
* @param string $sPluginClass Class implementing any plugin interface
* @param string $sProperty Name of the property
* @param mixed $value Value (numeric or string)
* @return void
*/
public static function SetPluginProperty($sPluginClass, $sProperty, $value)
{
if (is_null(self::$m_aPluginProperties)) self::LoadPluginProperties();
self::$m_aPluginProperties[$sPluginClass][$sProperty] = $value;
$_SESSION['PluginProperties'][$sPluginClass][$sProperty] = $value;
}
/**
* Get plugin properties
* @param string $sPluginClass Class implementing any plugin interface
* @return array of sProperty=>value pairs
*/
public static function GetPluginProperties($sPluginClass)
{
if (is_null(self::$m_aPluginProperties)) self::LoadPluginProperties();
if (array_key_exists($sPluginClass, self::$m_aPluginProperties))
{
return self::$m_aPluginProperties[$sPluginClass];
}
else
{
return array();
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,60 +1,60 @@
<?php
// Copyright (C) 2010-2012 Combodo SARL
//
// This file is part of iTop.
//
// iTop is free software; you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// iTop is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with iTop. If not, see <http://www.gnu.org/licenses/>
/**
* This class manages the audit "categories". Each category defines a set of objects
* to check and is linked to a set of rules that determine the valid or invalid objects
* inside the set
*
* @copyright Copyright (C) 2010-2012 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
require_once(APPROOT.'/application/cmdbabstract.class.inc.php');
class AuditCategory extends cmdbAbstractObject
{
public static function Init()
{
$aParams = array
(
"category" => "application",
"key_type" => "autoincrement",
"name_attcode" => "name",
"state_attcode" => "",
"reconc_keys" => array('name'),
"db_table" => "priv_auditcategory",
"db_key_field" => "id",
"db_finalclass_field" => "",
);
MetaModel::Init_Params($aParams);
MetaModel::Init_AddAttribute(new AttributeString("name", array("description"=>"Short name for this category", "allowed_values"=>null, "sql"=>"name", "default_value"=>"", "is_null_allowed"=>false, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeString("description", array("allowed_values"=>null, "sql"=>"description", "default_value"=>"", "is_null_allowed"=>true, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeOQL("definition_set", array("allowed_values"=>null, "sql"=>"definition_set", "default_value"=>"", "is_null_allowed"=>false, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeLinkedSet("rules_list", array("linked_class"=>"AuditRule", "ext_key_to_me"=>"category_id", "allowed_values"=>null, "count_min"=>0, "count_max"=>0, "depends_on"=>array(), "edit_mode" => LINKSET_EDITMODE_INPLACE, "tracking_level" => LINKSET_TRACKING_ALL)));
// Display lists
MetaModel::Init_SetZListItems('details', array('name', 'description', 'definition_set', 'rules_list')); // Attributes to be displayed for the complete details
MetaModel::Init_SetZListItems('list', array('description', )); // Attributes to be displayed for a list
// Search criteria
MetaModel::Init_SetZListItems('standard_search', array('name', 'description')); // Criteria of the std search form
MetaModel::Init_SetZListItems('advanced_search', array('name', 'description', 'definition_set')); // Criteria of the advanced search form
}
}
?>
<?php
// Copyright (C) 2010-2012 Combodo SARL
//
// This file is part of iTop.
//
// iTop is free software; you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// iTop is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with iTop. If not, see <http://www.gnu.org/licenses/>
/**
* This class manages the audit "categories". Each category defines a set of objects
* to check and is linked to a set of rules that determine the valid or invalid objects
* inside the set
*
* @copyright Copyright (C) 2010-2012 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
require_once(APPROOT.'/application/cmdbabstract.class.inc.php');
class AuditCategory extends cmdbAbstractObject
{
public static function Init()
{
$aParams = array
(
"category" => "application, grant_by_profile",
"key_type" => "autoincrement",
"name_attcode" => "name",
"state_attcode" => "",
"reconc_keys" => array('name'),
"db_table" => "priv_auditcategory",
"db_key_field" => "id",
"db_finalclass_field" => "",
);
MetaModel::Init_Params($aParams);
MetaModel::Init_AddAttribute(new AttributeString("name", array("description"=>"Short name for this category", "allowed_values"=>null, "sql"=>"name", "default_value"=>"", "is_null_allowed"=>false, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeString("description", array("allowed_values"=>null, "sql"=>"description", "default_value"=>"", "is_null_allowed"=>true, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeOQL("definition_set", array("allowed_values"=>null, "sql"=>"definition_set", "default_value"=>"", "is_null_allowed"=>false, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeLinkedSet("rules_list", array("linked_class"=>"AuditRule", "ext_key_to_me"=>"category_id", "allowed_values"=>null, "count_min"=>0, "count_max"=>0, "depends_on"=>array(), "edit_mode" => LINKSET_EDITMODE_INPLACE, "tracking_level" => LINKSET_TRACKING_ALL)));
// Display lists
MetaModel::Init_SetZListItems('details', array('name', 'description', 'definition_set', 'rules_list')); // Attributes to be displayed for the complete details
MetaModel::Init_SetZListItems('list', array('description', )); // Attributes to be displayed for a list
// Search criteria
MetaModel::Init_SetZListItems('standard_search', array('description', 'definition_set')); // Criteria of the std search form
MetaModel::Init_SetZListItems('default_search', array('name', 'description')); // Criteria of the default search form
}
}
?>

View File

@@ -1,64 +1,64 @@
<?php
// Copyright (C) 2010-2012 Combodo SARL
//
// This file is part of iTop.
//
// iTop is free software; you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// iTop is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with iTop. If not, see <http://www.gnu.org/licenses/>
/**
* This class manages the audit "rule" linked to a given audit category.
* Each rule is based on an OQL expression that returns either the "good" objects
* or the "bad" ones. The core audit engines computes the complement to the definition
* set when needed to obtain either the valid objects, or the ones with an error
*
* @copyright Copyright (C) 2010-2012 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
require_once(APPROOT.'/application/audit.category.class.inc.php');
class AuditRule extends cmdbAbstractObject
{
public static function Init()
{
$aParams = array
(
"category" => "application",
"key_type" => "autoincrement",
"name_attcode" => "name",
"state_attcode" => "",
"reconc_keys" => array('name'),
"db_table" => "priv_auditrule",
"db_key_field" => "id",
"db_finalclass_field" => "",
"display_template" => "",
);
MetaModel::Init_Params($aParams);
MetaModel::Init_AddAttribute(new AttributeString("name", array("allowed_values"=>null, "sql"=>"name", "default_value"=>"", "is_null_allowed"=>false, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeString("description", array("allowed_values"=>null, "sql"=>"description", "default_value"=>"", "is_null_allowed"=>true, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeOQL("query", array("allowed_values"=>null, "sql"=>"query", "default_value"=>"", "is_null_allowed"=>false, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeEnum("valid_flag", array("allowed_values"=>new ValueSetEnum('true,false'), "sql"=>"valid_flag", "default_value"=>"true", "is_null_allowed"=>false, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeExternalKey("category_id", array("allowed_values"=>null, "sql"=>"category_id", "targetclass"=>"AuditCategory", "is_null_allowed"=>false, "on_target_delete"=>DEL_MANUAL, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeExternalField("category_name", array("allowed_values"=>null, "extkey_attcode"=> 'category_id', "target_attcode"=>"name")));
// Display lists
MetaModel::Init_SetZListItems('details', array('category_id', 'name', 'description', 'query', 'valid_flag')); // Attributes to be displayed for the complete details
MetaModel::Init_SetZListItems('list', array('category_id', 'description', 'valid_flag')); // Attributes to be displayed for a list
// Search criteria
MetaModel::Init_SetZListItems('standard_search', array('category_id', 'name', 'description', 'valid_flag')); // Criteria of the std search form
MetaModel::Init_SetZListItems('advanced_search', array('category_id', 'name', 'description', 'valid_flag', 'query')); // Criteria of the advanced search form
}
}
?>
<?php
// Copyright (C) 2010-2012 Combodo SARL
//
// This file is part of iTop.
//
// iTop is free software; you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// iTop is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with iTop. If not, see <http://www.gnu.org/licenses/>
/**
* This class manages the audit "rule" linked to a given audit category.
* Each rule is based on an OQL expression that returns either the "good" objects
* or the "bad" ones. The core audit engines computes the complement to the definition
* set when needed to obtain either the valid objects, or the ones with an error
*
* @copyright Copyright (C) 2010-2012 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
require_once(APPROOT.'/application/audit.category.class.inc.php');
class AuditRule extends cmdbAbstractObject
{
public static function Init()
{
$aParams = array
(
"category" => "application, grant_by_profile",
"key_type" => "autoincrement",
"name_attcode" => "name",
"state_attcode" => "",
"reconc_keys" => array('name'),
"db_table" => "priv_auditrule",
"db_key_field" => "id",
"db_finalclass_field" => "",
"display_template" => "",
);
MetaModel::Init_Params($aParams);
MetaModel::Init_AddAttribute(new AttributeString("name", array("allowed_values"=>null, "sql"=>"name", "default_value"=>"", "is_null_allowed"=>false, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeString("description", array("allowed_values"=>null, "sql"=>"description", "default_value"=>"", "is_null_allowed"=>true, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeOQL("query", array("allowed_values"=>null, "sql"=>"query", "default_value"=>"", "is_null_allowed"=>false, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeEnum("valid_flag", array("allowed_values"=>new ValueSetEnum('true,false'), "sql"=>"valid_flag", "default_value"=>"true", "is_null_allowed"=>false, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeExternalKey("category_id", array("allowed_values"=>null, "sql"=>"category_id", "targetclass"=>"AuditCategory", "is_null_allowed"=>false, "on_target_delete"=>DEL_MANUAL, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeExternalField("category_name", array("allowed_values"=>null, "extkey_attcode"=> 'category_id', "target_attcode"=>"name")));
// Display lists
MetaModel::Init_SetZListItems('details', array('category_id', 'name', 'description', 'query', 'valid_flag')); // Attributes to be displayed for the complete details
MetaModel::Init_SetZListItems('list', array('category_id', 'description', 'valid_flag')); // Attributes to be displayed for a list
// Search criteria
MetaModel::Init_SetZListItems('standard_search', array('category_id', 'name', 'description', 'valid_flag', 'query')); // Criteria of the std search form
MetaModel::Init_SetZListItems('default_search', array('name', 'description', 'category_id')); // Criteria of the advanced search form
}
}
?>

View File

@@ -0,0 +1,84 @@
<?php
// Copyright (C) 2016 Combodo SARL
//
// This file is part of iTop.
//
// iTop is free software; you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// iTop is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with iTop. If not, see <http://www.gnu.org/licenses/>
/**
* Adapter class: when an API requires WebPage and you want to produce something else
*
* @copyright Copyright (C) 2016 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
require_once(APPROOT."/application/webpage.class.inc.php");
class CaptureWebPage extends WebPage
{
protected $aReadyScripts;
function __construct()
{
parent::__construct('capture web page');
$this->aReadyScripts = array();
}
public function GetHtml()
{
$trash = $this->ob_get_clean_safe();
return $this->s_content;
}
public function GetJS()
{
$sRet = implode("\n", $this->a_scripts);
if (!empty($this->s_deferred_content))
{
$sRet .= "\n\$('body').append('".addslashes(str_replace("\n", '', $this->s_deferred_content))."');";
}
return $sRet;
}
public function GetReadyJS()
{
return "\$(document).ready(function() {\n".implode("\n", $this->aReadyScripts)."\n});";
}
public function GetCSS()
{
return $this->a_styles;
}
public function GetJSFiles()
{
return $this->a_linked_scripts;
}
public function GetCSSFiles()
{
return $this->a_linked_stylesheets;
}
public function output()
{
throw new Exception(__method__.' should not be called');
}
public function add_ready_script($sScript)
{
$this->aReadyScripts[] = $sScript;
}
}

View File

@@ -1,97 +1,97 @@
<?php
// Copyright (C) 2010-2015 Combodo SARL
//
// This file is part of iTop.
//
// iTop is free software; you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// iTop is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with iTop. If not, see <http://www.gnu.org/licenses/>
/**
* CLI page
* The page adds the content-type text/XML and the encoding into the headers
*
* @copyright Copyright (C) 2010-2015 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
require_once(APPROOT."/application/webpage.class.inc.php");
class CLIPage implements Page
{
function __construct($s_title)
{
}
public function output()
{
if (class_exists('DBSearch'))
{
DBSearch::RecordQueryTrace();
}
if (class_exists('ExecutionKPI'))
{
ExecutionKPI::ReportStats();
}
}
public function add($sText)
{
echo $sText;
}
public function p($sText)
{
echo $sText."\n";
}
public function pre($sText)
{
echo $sText."\n";
}
public function add_comment($sText)
{
echo "#".$sText."\n";
}
public function table($aConfig, $aData, $aParams = array())
{
$aCells = array();
foreach($aConfig as $sName=>$aDef)
{
if (strlen($aDef['description']) > 0)
{
$aCells[] = $aDef['label'].' ('.$aDef['description'].')';
}
else
{
$aCells[] = $aDef['label'];
}
}
echo implode(';', $aCells)."\n";
foreach($aData as $aRow)
{
$aCells = array();
foreach($aConfig as $sName=>$aAttribs)
{
$sValue = $aRow["$sName"];
$aCells[] = $sValue;
}
echo implode(';', $aCells)."\n";
}
}
}
?>
<?php
// Copyright (C) 2010-2015 Combodo SARL
//
// This file is part of iTop.
//
// iTop is free software; you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// iTop is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with iTop. If not, see <http://www.gnu.org/licenses/>
/**
* CLI page
* The page adds the content-type text/XML and the encoding into the headers
*
* @copyright Copyright (C) 2010-2015 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
require_once(APPROOT."/application/webpage.class.inc.php");
class CLIPage implements Page
{
function __construct($s_title)
{
}
public function output()
{
if (class_exists('DBSearch'))
{
DBSearch::RecordQueryTrace();
}
if (class_exists('ExecutionKPI'))
{
ExecutionKPI::ReportStats();
}
}
public function add($sText)
{
echo $sText;
}
public function p($sText)
{
echo $sText."\n";
}
public function pre($sText)
{
echo $sText."\n";
}
public function add_comment($sText)
{
echo "#".$sText."\n";
}
public function table($aConfig, $aData, $aParams = array())
{
$aCells = array();
foreach($aConfig as $sName=>$aDef)
{
if (strlen($aDef['description']) > 0)
{
$aCells[] = $aDef['label'].' ('.$aDef['description'].')';
}
else
{
$aCells[] = $aDef['label'];
}
}
echo implode(';', $aCells)."\n";
foreach($aData as $aRow)
{
$aCells = array();
foreach($aConfig as $sName=>$aAttribs)
{
$sValue = $aRow["$sName"];
$aCells[] = $sValue;
}
echo implode(';', $aCells)."\n";
}
}
}
?>

File diff suppressed because it is too large Load Diff

View File

@@ -1,111 +1,111 @@
<?php
// Copyright (C) 2010-2015 Combodo SARL
//
// This file is part of iTop.
//
// iTop is free software; you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// iTop is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with iTop. If not, see <http://www.gnu.org/licenses/>
/**
* Simple web page with no includes or fancy formatting, useful to generateXML documents
* The page adds the content-type text/XML and the encoding into the headers
*
* @copyright Copyright (C) 2010-2015 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
require_once(APPROOT."/application/webpage.class.inc.php");
class CSVPage extends WebPage
{
function __construct($s_title)
{
parent::__construct($s_title);
$this->add_header("Content-type: text/plain; charset=utf-8");
$this->add_header("Cache-control: no-cache");
//$this->add_header("Content-Transfer-Encoding: binary");
}
public function output()
{
$this->add_header("Content-Length: ".strlen(trim($this->s_content)));
// Get the unexpected output but do nothing with it
$sTrash = $this->ob_get_clean_safe();
foreach($this->a_headers as $s_header)
{
header($s_header);
}
echo trim($this->s_content);
echo "\n";
if (class_exists('DBSearch'))
{
DBSearch::RecordQueryTrace();
}
if (class_exists('ExecutionKPI'))
{
ExecutionKPI::ReportStats();
}
}
public function small_p($sText)
{
}
public function add($sText)
{
$this->s_content .= $sText;
}
public function p($sText)
{
$this->s_content .= $sText."\n";
}
public function add_comment($sText)
{
$this->s_content .= "#".$sText."\n";
}
public function table($aConfig, $aData, $aParams = array())
{
$aCells = array();
foreach($aConfig as $sName=>$aDef)
{
if (strlen($aDef['description']) > 0)
{
$aCells[] = $aDef['label'].' ('.$aDef['description'].')';
}
else
{
$aCells[] = $aDef['label'];
}
}
$this->s_content .= implode(';', $aCells)."\n";
foreach($aData as $aRow)
{
$aCells = array();
foreach($aConfig as $sName=>$aAttribs)
{
$sValue = $aRow["$sName"];
$aCells[] = $sValue;
}
$this->s_content .= implode(';', $aCells)."\n";
}
}
}
<?php
// Copyright (C) 2010-2015 Combodo SARL
//
// This file is part of iTop.
//
// iTop is free software; you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// iTop is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with iTop. If not, see <http://www.gnu.org/licenses/>
/**
* Simple web page with no includes or fancy formatting, useful to generateXML documents
* The page adds the content-type text/XML and the encoding into the headers
*
* @copyright Copyright (C) 2010-2015 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
require_once(APPROOT."/application/webpage.class.inc.php");
class CSVPage extends WebPage
{
function __construct($s_title)
{
parent::__construct($s_title);
$this->add_header("Content-type: text/plain; charset=utf-8");
$this->add_header("Cache-control: no-cache");
//$this->add_header("Content-Transfer-Encoding: binary");
}
public function output()
{
$this->add_header("Content-Length: ".strlen(trim($this->s_content)));
// Get the unexpected output but do nothing with it
$sTrash = $this->ob_get_clean_safe();
foreach($this->a_headers as $s_header)
{
header($s_header);
}
echo trim($this->s_content);
echo "\n";
if (class_exists('DBSearch'))
{
DBSearch::RecordQueryTrace();
}
if (class_exists('ExecutionKPI'))
{
ExecutionKPI::ReportStats();
}
}
public function small_p($sText)
{
}
public function add($sText)
{
$this->s_content .= $sText;
}
public function p($sText)
{
$this->s_content .= $sText."\n";
}
public function add_comment($sText)
{
$this->s_content .= "#".$sText."\n";
}
public function table($aConfig, $aData, $aParams = array())
{
$aCells = array();
foreach($aConfig as $sName=>$aDef)
{
if (strlen($aDef['description']) > 0)
{
$aCells[] = $aDef['label'].' ('.$aDef['description'].')';
}
else
{
$aCells[] = $aDef['label'];
}
}
$this->s_content .= implode(';', $aCells)."\n";
foreach($aData as $aRow)
{
$aCells = array();
foreach($aConfig as $sName=>$aAttribs)
{
$sValue = $aRow["$sName"];
$aCells[] = $sValue;
}
$this->s_content .= implode(';', $aCells)."\n";
}
}
}

View File

@@ -1,5 +1,5 @@
<?php
// Copyright (C) 2010-2013 Combodo SARL
// Copyright (C) 2010-2017 Combodo SARL
//
// This file is part of iTop.
//
@@ -21,9 +21,10 @@ require_once(APPROOT.'application/dashlet.class.inc.php');
require_once(APPROOT.'core/modelreflection.class.inc.php');
/**
*
* A user editable dashboard page
*
* @copyright Copyright (C) 2010-2012 Combodo SARL
* @copyright Copyright (C) 2010-2017 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
abstract class Dashboard
@@ -49,6 +50,11 @@ abstract class Dashboard
$this->sId = $sId;
}
/**
* @param $sXml
*
* @throws \Exception
*/
public function FromXml($sXml)
{
$this->aCells = array(); // reset the content of the dashboard
@@ -100,10 +106,10 @@ abstract class Dashboard
$oCellsList = $oCellsNode->getElementsByTagName('cell');
$aCellOrder = array();
$iCellRank = 0;
/** @var \DOMElement $oCellNode */
foreach($oCellsList as $oCellNode)
{
$aDashletList = array();
$oCellRank = $oCellNode->getElementsByTagName('rank')->item(0);
$oCellRank = $oCellNode->getElementsByTagName('rank')->item(0);
if ($oCellRank)
{
$iCellRank = (float)$oCellRank->textContent;
@@ -113,17 +119,16 @@ abstract class Dashboard
$oDashletList = $oDashletsNode->getElementsByTagName('dashlet');
$iRank = 0;
$aDashletOrder = array();
/** @var \DOMElement $oDomNode */
foreach($oDashletList as $oDomNode)
{
$sDashletClass = $oDomNode->getAttribute('xsi:type');
$oRank = $oDomNode->getElementsByTagName('rank')->item(0);
if ($oRank)
{
$iRank = (float)$oRank->textContent;
}
$sId = $oDomNode->getAttribute('id');
$oNewDashlet = new $sDashletClass($this->oMetaModel, $sId);
$oNewDashlet->FromDOMNode($oDomNode);
$oNewDashlet = $this->InitDashletFromDOMNode($oDomNode);
$aDashletOrder[] = array('rank' => $iRank, 'dashlet' => $oNewDashlet);
}
usort($aDashletOrder, array(get_class($this), 'SortOnRank'));
@@ -147,12 +152,41 @@ abstract class Dashboard
}
}
/**
* @param \DOMElement $oDomNode
*
* @return mixed
*/
protected function InitDashletFromDOMNode($oDomNode)
{
$sId = $oDomNode->getAttribute('id');
$sDashletType = $oDomNode->getAttribute('xsi:type');
// Test if dashlet can be instanciated, otherwise (uninstalled, broken, ...) we display a placeholder
$sClass = static::GetDashletClassFromType($sDashletType);
/** @var \Dashlet $oNewDashlet */
$oNewDashlet = new $sClass($this->oMetaModel, $sId);
$oNewDashlet->SetDashletType($sDashletType);
$oNewDashlet->FromDOMNode($oDomNode);
return $oNewDashlet;
}
static function SortOnRank($aItem1, $aItem2)
{
return ($aItem1['rank'] > $aItem2['rank']) ? +1 : -1;
}
/**
* Error handler to turn XML loading warnings into exceptions
*
* @param $errno
* @param $errstr
* @param $errfile
* @param $errline
*
* @return bool
* @throws \DOMException
*/
public static function ErrorHandler($errno, $errstr, $errfile, $errline)
{
@@ -182,8 +216,12 @@ abstract class Dashboard
return $sXml;
}
/**
* @param \DOMElement $oDefinition
*/
public function ToDOMNode($oDefinition)
{
/** @var \DOMDocument $oDoc */
$oDoc = $oDefinition->ownerDocument;
$oNode = $oDoc->createElement('layout', $this->sLayoutClass);
@@ -215,12 +253,13 @@ abstract class Dashboard
$iDashletRank = 0;
$oDashletsNode = $oDoc->createElement('dashlets');
$oCellNode->appendChild($oDashletsNode);
/** @var \Dashlet $oDashlet */
foreach ($aCell as $oDashlet)
{
$oNode = $oDoc->createElement('dashlet');
$oDashletsNode->appendChild($oNode);
$oNode->setAttribute('id', $oDashlet->GetID());
$oNode->setAttribute('xsi:type', get_class($oDashlet));
$oNode->setAttribute('xsi:type', $oDashlet->GetDashletType());
$oDashletRank = $oDoc->createElement('rank', $iDashletRank);
$oNode->appendChild($oDashletRank);
$iDashletRank++;
@@ -244,8 +283,12 @@ abstract class Dashboard
{
$sDashletClass = $aDashletParams['dashlet_class'];
$sId = $aDashletParams['dashlet_id'];
/** @var \Dashlet $oNewDashlet */
$oNewDashlet = new $sDashletClass($this->oMetaModel, $sId);
if (isset($aDashletParams['dashlet_type']))
{
$oNewDashlet->SetDashletType($aDashletParams['dashlet_type']);
}
$oForm = $oNewDashlet->GetForm();
$oForm->SetParamsContainer($sId);
$oForm->SetPrefix('');
@@ -303,31 +346,28 @@ abstract class Dashboard
$this->iAutoReloadSec = max(MetaModel::GetConfig()->Get('min_reload_interval'), (int)$iAutoReloadSec);
}
/**
* @param \Dashlet $oDashlet
*/
public function AddDashlet($oDashlet)
{
$sId = $this->GetNewDashletId();
$oDashlet->SetId($sId);
$this->aCells[] = array($oDashlet);
}
public function Render($oPage, $bEditMode = false, $aExtraParams = array())
{
$oPage->add('<h1>'.htmlentities(Dict::S($this->sTitle), ENT_QUOTES, 'UTF-8', false).'</h1>');
$oLayout = new $this->sLayoutClass;
$oLayout->Render($oPage, $this->aCells, $bEditMode, $aExtraParams);
if (!$bEditMode)
{
$oPage->add_linked_script('../js/dashlet.js');
$oPage->add_linked_script('../js/dashboard.js');
}
}
public function RenderProperties($oPage)
/**
* @param \WebPage $oPage *
* @param array $aExtraParams
*
* @throws \ReflectionException
*/
public function RenderProperties($oPage, $aExtraParams = array())
{
// menu to pick a layout and edit other properties of the dashboard
$oPage->add('<div class="ui-widget-content ui-corner-all"><div class="ui-widget-header ui-corner-all" style="text-align:center; padding: 2px;">'.Dict::S('UI:DashboardEdit:Properties').'</div>');
$sUrl = utils::GetAbsoluteUrlAppRoot();
$oPage->add('<div style="text-align:center">'.Dict::S('UI:DashboardEdit:Layout').'</div>');
$oPage->add('<div id="select_layout" style="text-align:center">');
foreach( get_declared_classes() as $sLayoutClass)
@@ -345,13 +385,13 @@ abstract class Dashboard
}
}
$oPage->add('</div>');
$oForm = new DesignerForm();
$oField = new DesignerHiddenField('dashboard_id', '', $this->sId);
$oForm->AddField($oField);
$oField = new DesignerLongTextField('dashboard_title', Dict::S('UI:DashboardEdit:DashboardTitle'), $this->sTitle);
$oField = new DesignerTextField('dashboard_title', Dict::S('UI:DashboardEdit:DashboardTitle'), $this->sTitle);
$oForm->AddField($oField);
$oField = new DesignerBooleanField('auto_reload', Dict::S('UI:DashboardEdit:AutoReload'), $this->bAutoReload);
@@ -362,8 +402,8 @@ abstract class Dashboard
$oForm->AddField($oField);
$this->SetFormParams($oForm);
$oForm->RenderAsPropertySheet($oPage, false, '.itop-dashboard');
$this->SetFormParams($oForm, $aExtraParams);
$oForm->RenderAsPropertySheet($oPage, false, '.itop-dashboard');
$oPage->add('</div>');
@@ -407,17 +447,86 @@ abstract class Dashboard
EOF
);
}
public function RenderDashletsSelection($oPage)
/**
* @param \iTopWebPage $oPage
* @param bool $bEditMode
* @param array $aExtraParams
* @param bool $bCanEdit
*/
public function Render($oPage, $bEditMode = false, $aExtraParams = array(), $bCanEdit = true)
{
$oPage->add('<div class="dashboard-title-line"><div class="dashboard-title">'.htmlentities(Dict::S($this->sTitle), ENT_QUOTES, 'UTF-8', false).'</div></div>');
$oLayout = new $this->sLayoutClass;
/** @var \DashboardLayoutMultiCol $oLayout */
$oLayout->Render($oPage, $this->aCells, $bEditMode, $aExtraParams);
if (!$bEditMode)
{
$oPage->add_linked_script('../js/dashlet.js');
$oPage->add_linked_script('../js/dashboard.js');
}
}
public function RenderDashletsSelection(WebPage $oPage)
{
// Toolbox/palette to drag and drop dashlets
$oPage->add('<div class="ui-widget-content ui-corner-all"><div class="ui-widget-header ui-corner-all" style="text-align:center; padding: 2px;">'.Dict::S('UI:DashboardEdit:Dashlets').'</div>');
$sUrl = utils::GetAbsoluteUrlAppRoot();
$oPage->add('<div id="select_dashlet" style="text-align:center">');
$oPage->add('<div id="select_dashlet" style="text-align:center; max-height:120px; overflow-y:auto;">');
$aAvailableDashlets = $this->GetAvailableDashlets();
foreach($aAvailableDashlets as $sDashletClass => $aInfo)
{
$oPage->add('<span dashlet_class="'.$sDashletClass.'" class="dashlet_icon ui-widget-content ui-corner-all" id="dashlet_'.$sDashletClass.'" title="'.$aInfo['label'].'" style="width:34px; height:34px; display:inline-block; margin:2px;"><img src="'.$sUrl.$aInfo['icon'].'" /></span>');
}
$oPage->add('</div>');
$oPage->add('</div>');
$oPage->add_ready_script("$('.dashlet_icon').draggable({helper: 'clone', appendTo: 'body', zIndex: 10000, revert:'invalid'});");
}
public function RenderDashletsProperties(WebPage $oPage, $aExtraParams = array())
{
// Toolbox/palette to edit the properties of each dashlet
$oPage->add('<div class="ui-widget-content ui-corner-all"><div class="ui-widget-header ui-corner-all" style="text-align:center; padding: 2px;">'.Dict::S('UI:DashboardEdit:DashletProperties').'</div>');
$oPage->add('<div id="dashlet_properties" style="text-align:center">');
foreach($this->aCells as $aCell)
{
/** @var \Dashlet $oDashlet */
foreach($aCell as $oDashlet)
{
$sId = $oDashlet->GetID();
if ($oDashlet->IsVisible())
{
$oPage->add('<div class="dashlet_properties" id="dashlet_properties_'.$sId.'" style="display:none">');
$oForm = $oDashlet->GetForm();
$this->SetFormParams($oForm, $aExtraParams);
$oForm->RenderAsPropertySheet($oPage, false, '.itop-dashboard');
$oPage->add('</div>');
}
}
}
$oPage->add('</div>');
$oPage->add('</div>');
}
/**
* Return an array of dashlets available for selection.
*
* @return array
* @throws \ReflectionException
*/
protected function GetAvailableDashlets()
{
$aDashlets = array();
foreach( get_declared_classes() as $sDashletClass)
{
if (is_subclass_of($sDashletClass, 'Dashlet'))
// DashletUnknown is not among the selection as it is just a fallback for dashlets that can't instanciated.
if ( is_subclass_of($sDashletClass, 'Dashlet') && !in_array($sDashletClass, array('DashletUnknown', 'DashletProxy')) )
{
$oReflection = new ReflectionClass($sDashletClass);
if (!$oReflection->isAbstract())
@@ -428,42 +537,13 @@ EOF
{
$aCallSpec = array($sDashletClass, 'GetInfo');
$aInfo = call_user_func($aCallSpec);
$oPage->add('<span dashlet_class="'.$sDashletClass.'" class="dashlet_icon ui-widget-content ui-corner-all" id="dashlet_'.$sDashletClass.'" title="'.$aInfo['label'].'" style="width:34px; height:34px; display:inline-block; margin:2px;"><img src="'.$sUrl.$aInfo['icon'].'" /></span>');
$aDashlets[$sDashletClass] = $aInfo;
}
}
}
}
$oPage->add('</div>');
$oPage->add('</div>');
$oPage->add_ready_script("$('.dashlet_icon').draggable({helper: 'clone', appendTo: 'body', zIndex: 10000, revert:'invalid'});");
}
public function RenderDashletsProperties($oPage)
{
// Toolbox/palette to edit the properties of each dashlet
$oPage->add('<div class="ui-widget-content ui-corner-all"><div class="ui-widget-header ui-corner-all" style="text-align:center; padding: 2px;">'.Dict::S('UI:DashboardEdit:DashletProperties').'</div>');
$oPage->add('<div id="dashlet_properties" style="text-align:center">');
foreach($this->aCells as $aCell)
{
foreach($aCell as $oDashlet)
{
$sId = $oDashlet->GetID();
$sClass = get_class($oDashlet);
if ($oDashlet->IsVisible())
{
$oPage->add('<div class="dashlet_properties" id="dashlet_properties_'.$sId.'" style="display:none">');
$oForm = $oDashlet->GetForm();
$this->SetFormParams($oForm);
$oForm->RenderAsPropertySheet($oPage, false, '.itop-dashboard');
$oPage->add('</div>');
}
}
}
$oPage->add('</div>');
$oPage->add('</div>');
return $aDashlets;
}
protected function GetNewDashletId()
@@ -471,6 +551,7 @@ EOF
$iNewId = 0;
foreach($this->aCells as $aDashlets)
{
/** @var \Dashlet $oDashlet */
foreach($aDashlets as $oDashlet)
{
$iNewId = max($iNewId, (int)$oDashlet->GetID());
@@ -478,13 +559,39 @@ EOF
}
return $iNewId + 1;
}
abstract protected function SetFormParams($oForm);
/**
* @param $oForm
* @param array $aExtraParams
*
* @return mixed
*/
abstract protected function SetFormParams($oForm, $aExtraParams = array());
public static function GetDashletClassFromType($sType, $oFactory = null)
{
if (is_subclass_of($sType, 'Dashlet'))
{
return $sType;
}
return 'DashletUnknown';
}
/**
* @return mixed
*/
public function GetId()
{
return $this->sId;
}
}
class RuntimeDashboard extends Dashboard
{
protected $bCustomized;
private $sDefinitionFile = '';
private $sReloadURL = null;
public function __construct($sId)
{
@@ -497,10 +604,17 @@ class RuntimeDashboard extends Dashboard
{
$this->bCustomized = $bCustomized;
}
protected function SetFormParams($oForm)
/**
* @param \DesignerForm $oForm
*
* @param array $aExtraParams
*
* @throws \Exception
*/
protected function SetFormParams($oForm, $aExtraParams = array())
{
$oForm->SetSubmitParams(utils::GetAbsoluteUrlAppRoot().'pages/ajax.render.php', array('operation' => 'update_dashlet_property'));
$oForm->SetSubmitParams(utils::GetAbsoluteUrlAppRoot().'pages/ajax.render.php', array('operation' => 'update_dashlet_property', 'extra_params' => $aExtraParams));
}
public function Save()
@@ -515,8 +629,6 @@ class RuntimeDashboard extends Dashboard
// Assuming there is at most one couple {user, menu}!
$oUserDashboard = $oUDSet->Fetch();
$oUserDashboard->Set('contents', $sXml);
$oUserDashboard->DBUpdate();
}
else
{
@@ -525,9 +637,10 @@ class RuntimeDashboard extends Dashboard
$oUserDashboard->Set('user_id', UserRights::GetUserId());
$oUserDashboard->Set('menu_code', $this->sId);
$oUserDashboard->Set('contents', $sXml);
$oUserDashboard->DBInsert();
}
}
utils::PushArchiveMode(false);
$oUserDashboard->DBWrite();
utils::PopArchiveMode();
}
public function Revert()
@@ -540,44 +653,270 @@ class RuntimeDashboard extends Dashboard
{
// Assuming there is at most one couple {user, menu}!
$oUserDashboard = $oUDSet->Fetch();
utils::PushArchiveMode(false);
$oUserDashboard->DBDelete();
utils::PopArchiveMode();
}
}
public function RenderEditionTools($oPage)
/**
* @param string $sDashboardFile file name relative to the current module folder
* @param string $sDashBoardId code of the dashboard either menu_id or <class>__<attcode>
*
* @return null|RuntimeDashboard
* @throws \CoreException
* @throws \CoreUnexpectedValue
* @throws \MissingQueryArgument
* @throws \MySQLException
* @throws \MySQLHasGoneAwayException
*/
public static function GetDashboard($sDashboardFile, $sDashBoardId)
{
$bCustomized = false;
if (!appUserPreferences::GetPref('display_original_dashboard_'.$sDashBoardId, false))
{
// Search for an eventual user defined dashboard
$oUDSearch = new DBObjectSearch('UserDashboard');
$oUDSearch->AddCondition('user_id', UserRights::GetUserId(), '=');
$oUDSearch->AddCondition('menu_code', $sDashBoardId, '=');
$oUDSet = new DBObjectSet($oUDSearch);
if ($oUDSet->Count() > 0)
{
// Assuming there is at most one couple {user, menu}!
$oUserDashboard = $oUDSet->Fetch();
$sDashboardDefinition = $oUserDashboard->Get('contents');
$bCustomized = true;
}
else
{
$sDashboardDefinition = @file_get_contents($sDashboardFile);
}
}
else
{
$sDashboardDefinition = @file_get_contents($sDashboardFile);
}
if ($sDashboardDefinition !== false)
{
$oDashboard = new RuntimeDashboard($sDashBoardId);
$oDashboard->FromXml($sDashboardDefinition);
$oDashboard->SetCustomFlag($bCustomized);
$oDashboard->SetDefinitionFile($sDashboardFile);
}
else
{
$oDashboard = null;
}
return $oDashboard;
}
/**
* @param \iTopWebPage $oPage
* @param bool $bEditMode
* @param array $aExtraParams (class and id of the current object
*
* @throws \Exception
*/
public function Render($oPage, $bEditMode = false, $aExtraParams = array(), $bCanEdit = true)
{
if (!isset($aExtraParams['query_params']) && isset($aExtraParams['this->class']))
{
$oObj = MetaModel::GetObject($aExtraParams['this->class'], $aExtraParams['this->id']);
$aRenderParams = array('query_params' => $oObj->ToArgsForQuery());
}
else
{
$aRenderParams = $aExtraParams;
}
parent::Render($oPage, $bEditMode, $aRenderParams);
if (isset($aExtraParams['query_params']['this->object()']))
{
/** @var \DBObject $oObj */
$oObj = $aExtraParams['query_params']['this->object()'];
$aAjaxParams = array('this->class' => get_class($oObj), 'this->id' => $oObj->GetKey());
}
else
{
$aAjaxParams = $aExtraParams;
}
if (!$bEditMode && !$oPage->IsPrintableVersion())
{
$sId = $this->GetId();
$sDivId = preg_replace('/[^a-zA-Z0-9_]/', '', $sId);
if ($this->GetAutoReload())
{
$sFile = addslashes($this->GetDefinitionFile());
$sExtraParams = json_encode($aAjaxParams);
$iReloadInterval = 1000 * $this->GetAutoReloadInterval();
$sReloadURL = $this->GetReloadURL();
$oPage->add_script(
<<<EOF
if (typeof(AutoReloadDashboardId$sDivId) !== 'undefined')
{
clearInterval(AutoReloadDashboardId$sDivId);
delete AutoReloadDashboardId$sDivId;
}
AutoReloadDashboardId$sDivId = setInterval("ReloadDashboard$sDivId();", $iReloadInterval);
function ReloadDashboard$sDivId()
{
// Do not reload when a dialog box is active
if (!($('.ui-dialog:visible').length > 0) && $('.dashboard_contents#$sDivId').is(':visible'))
{
$('.dashboard_contents#$sDivId').block();
$.post(GetAbsoluteUrlAppRoot()+'pages/ajax.render.php',
{ operation: 'reload_dashboard', dashboard_id: '$sId', file: '$sFile', extra_params: $sExtraParams, reload_url: '$sReloadURL'},
function(data){
$('.dashboard_contents#$sDivId').html(data);
$('.dashboard_contents#$sDivId').unblock();
}
);
}
}
EOF
);
}
else
{
$oPage->add_script(
<<<EOF
if (typeof(AutoReloadDashboardId$sDivId) !== 'undefined')
{
clearInterval(AutoReloadDashboardId$sDivId);
delete AutoReloadDashboardId$sDivId;
}
EOF
);
}
if ($bCanEdit)
{
$this->RenderSelector($oPage, $aAjaxParams);
$this->RenderEditionTools($oPage, $aAjaxParams);
}
}
}
/**
* @param \iTopWebPage $oPage
* @param array $aAjaxParams
*/
protected function RenderSelector($oPage, $aAjaxParams = array())
{
$sId = $this->GetId();
$sDivId = preg_replace('/[^a-zA-Z0-9_]/', '', $sId);
$sExtraParams = json_encode($aAjaxParams);
$sSelectorHtml = '<div class="dashboard-selector">';
if ($this->HasCustomDashboard())
{
$bStandardSelected = appUserPreferences::GetPref('display_original_dashboard_'.$sId, false);
$sStandard = Dict::S('UI:Toggle:StandardDashboard');
$sSelectorHtml .= '<div class="selector-label">'.$sStandard.'</div>';
$sSelectorHtml .= '<label class="switch"><input type="checkbox" onchange="ToggleDashboardSelector'.$sDivId.'();" '.($bStandardSelected ? '' : 'checked').'><span class="slider round"></span></label></input></label>';
$sCustom = Dict::S('UI:Toggle:CustomDashboard');
$sSelectorHtml .= '<div class="selector-label">'.$sCustom.'</div>';
}
$sSelectorHtml .= '</div>';
$sSelectorHtml = addslashes($sSelectorHtml);
$sFile = addslashes($this->GetDefinitionFile());
$sReloadURL = $this->GetReloadURL();
$oPage->add_ready_script(
<<<EOF
$('.dashboard-title').after('$sSelectorHtml');
EOF
);
$oPage->add_script(
<<<EOF
function ToggleDashboardSelector$sDivId()
{
$('.dashboard_contents#$sDivId').block();
$.post(GetAbsoluteUrlAppRoot()+'pages/ajax.render.php',
{ operation: 'toggle_dashboard', dashboard_id: '$sId', file: '$sFile', extra_params: $sExtraParams, reload_url: '$sReloadURL' },
function(data) {
$('.dashboard_contents#$sDivId').html(data);
$('.dashboard_contents#$sDivId').unblock();
}
);
}
EOF
);
}
protected function HasCustomDashboard()
{
try
{
// Search for an eventual user defined dashboard
$oUDSearch = new DBObjectSearch('UserDashboard');
$oUDSearch->AddCondition('user_id', UserRights::GetUserId(), '=');
$oUDSearch->AddCondition('menu_code', $this->GetId(), '=');
$oUDSet = new DBObjectSet($oUDSearch);
return ($oUDSet->Count() > 0);
}
catch (Exception $e)
{
return false;
}
}
/**
* @param \WebPage $oPage
* @param array $aExtraParams
*
* @throws \Exception
*/
protected function RenderEditionTools(WebPage $oPage, $aExtraParams)
{
$oPage->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/jquery.iframe-transport.js');
$oPage->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/jquery.fileupload.js');
$sEditMenu = "<td><span id=\"DashboardMenu\"><ul><li><img src=\"../images/pencil-menu.png\"><ul>";
$sEditMenu = "<div id=\"DashboardMenu\"><ul><li><img src=\"../images/pencil-menu.png\"><ul>";
$aActions = array();
$oEdit = new JSPopupMenuItem('UI:Dashboard:Edit', Dict::S('UI:Dashboard:Edit'), "return EditDashboard('{$this->sId}')");
$aActions[$oEdit->GetUID()] = $oEdit->GetMenuItem();
$sFile = addslashes($this->sDefinitionFile);
$sJSExtraParams = json_encode($aExtraParams);
$bCanEdit = true;
if ($this->HasCustomDashboard())
{
$bCanEdit = !appUserPreferences::GetPref('display_original_dashboard_'.$this->GetId(), false);
}
if ($bCanEdit)
{
$oEdit = new JSPopupMenuItem('UI:Dashboard:Edit', Dict::S('UI:Dashboard:Edit'), "return EditDashboard('{$this->sId}', '$sFile', $sJSExtraParams)");
$aActions[$oEdit->GetUID()] = $oEdit->GetMenuItem();
}
if ($this->bCustomized)
{
$oRevert = new JSPopupMenuItem('UI:Dashboard:RevertConfirm', Dict::S('UI:Dashboard:Revert'),
"if (confirm('".addslashes(Dict::S('UI:Dashboard:RevertConfirm'))."')) return RevertDashboard('{$this->sId}'); else return false");
"if (confirm('".addslashes(Dict::S('UI:Dashboard:RevertConfirm'))."')) return RevertDashboard('{$this->sId}', $sJSExtraParams); else return false");
$aActions[$oRevert->GetUID()] = $oRevert->GetMenuItem();
}
utils::GetPopupMenuItems($oPage, iPopupMenuExtension::MENU_DASHBOARD_ACTIONS, $this, $aActions);
$sEditMenu .= $oPage->RenderPopupMenuItems($aActions);
$sEditMenu = addslashes($sEditMenu);
//$sEditBtn = addslashes('<div style="display: inline-block; height: 55px; width:200px;vertical-align:center;line-height:60px;text-align:left;"><button onclick="EditDashboard(\''.$this->sId.'\');">Edit This Page</button></div>');
$sReloadURL = $this->GetReloadURL();
$oPage->add_ready_script(
<<<EOF
$('#logOffBtn').parent().before('$sEditMenu');
$('.dashboard-title').after('$sEditMenu');
$('#DashboardMenu>ul').popupmenu();
EOF
);
$oPage->add_script(
<<<EOF
function EditDashboard(sId)
function EditDashboard(sId, sDashboardFile, aExtraParams)
{
$.post(GetAbsoluteUrlAppRoot()+'pages/ajax.render.php', {operation: 'dashboard_editor', id: sId},
$.post(GetAbsoluteUrlAppRoot()+'pages/ajax.render.php', {operation: 'dashboard_editor', id: sId, file: sDashboardFile, extra_params: aExtraParams, reload_url: '$sReloadURL'},
function(data)
{
$('body').append(data);
@@ -585,12 +924,12 @@ function EditDashboard(sId)
);
return false;
}
function RevertDashboard(sId)
function RevertDashboard(sId, aExtraParams)
{
$.post(GetAbsoluteUrlAppRoot()+'pages/ajax.render.php', {operation: 'revert_dashboard', dashboard_id: sId},
$.post(GetAbsoluteUrlAppRoot()+'pages/ajax.render.php', {operation: 'revert_dashboard', dashboard_id: sId, extra_params: aExtraParams, reload_url: '$sReloadURL'},
function(data)
{
$('body').append(data);
location.reload();
}
);
return false;
@@ -599,9 +938,14 @@ EOF
);
}
public function RenderProperties($oPage)
/**
* @param \WebPage $oPage
*
* @throws \ReflectionException
*/
public function RenderProperties($oPage, $aExtraParams = array())
{
parent::RenderProperties($oPage);
parent::RenderProperties($oPage, $aExtraParams);
$oPage->add_ready_script(
<<<EOF
@@ -632,16 +976,36 @@ EOF
}
public function RenderEditor($oPage)
/**
* @param \iTopWebPage $oPage
*
* @param array $aExtraParams
*
* @throws \ArchivedObjectException
* @throws \CoreException
* @throws \ReflectionException
* @throws \Exception
*/
public function RenderEditor($oPage, $aExtraParams = array())
{
if (isset($aExtraParams['this->class']))
{
$oObj = MetaModel::GetObject($aExtraParams['this->class'], $aExtraParams['this->id']);
$aRenderParams = array('query_params' => $oObj->ToArgsForQuery());
}
else
{
$aRenderParams = $aExtraParams;
}
$sJSExtraParams = json_encode($aExtraParams);
$oPage->add('<div id="dashboard_editor">');
$oPage->add('<div class="ui-layout-center">');
$this->Render($oPage, true);
$this->Render($oPage, true, $aRenderParams);
$oPage->add('</div>');
$oPage->add('<div class="ui-layout-east">');
$this->RenderProperties($oPage);
$this->RenderProperties($oPage, $aExtraParams);
$this->RenderDashletsSelection($oPage);
$this->RenderDashletsProperties($oPage);
$this->RenderDashletsProperties($oPage, $aExtraParams);
$oPage->add('</div>');
$oPage->add('<div id="event_bus"/>'); // For exchanging messages between the panes, same as in the designer
$oPage->add('</div>');
@@ -655,7 +1019,9 @@ EOF
$sAutoReload = $this->bAutoReload ? 'true' : 'false';
$sAutoReloadSec = (string) $this->iAutoReloadSec;
$sTitle = addslashes($this->sTitle);
$sFile = addslashes($this->GetDefinitionFile());
$sUrl = utils::GetAbsoluteUrlAppRoot().'pages/ajax.render.php';
$sReloadURL = $this->GetReloadURL();
$sExitConfirmationMessage = addslashes(Dict::S('UI:NavigateAwayConfirmationMessage'));
$sCancelConfirmationMessage = addslashes(Dict::S('UI:CancelConfirmationMessage'));
@@ -685,7 +1051,7 @@ $('#dashboard_editor').dialog({
}
}
window.bLeavingOnUserAction = true;
oDashboard.save();
oDashboard.save($(this));
} },
{ text: "$sCancelButtonLabel", click: function() {
var oDashboard = $('.itop-dashboard').data('itopRuntimedashboard');
@@ -707,8 +1073,8 @@ $('#dashboard_editor').dialog({
$('#dashboard_editor .ui-layout-center').runtimedashboard({
dashboard_id: '$sId', layout_class: '$sLayoutClass', title: '$sTitle',
auto_reload: $sAutoReload, auto_reload_sec: $sAutoReloadSec,
submit_to: '$sUrl', submit_parameters: {operation: 'save_dashboard'},
render_to: '$sUrl', render_parameters: {operation: 'render_dashboard'},
submit_to: '$sUrl', submit_parameters: {operation: 'save_dashboard', file: '$sFile', extra_params: $sJSExtraParams, reload_url: '$sReloadURL'},
render_to: '$sUrl', render_parameters: {operation: 'render_dashboard', file: '$sFile', extra_params: $sJSExtraParams, reload_url: '$sReloadURL'},
new_dashlet_parameters: {operation: 'new_dashlet'}
});
@@ -754,33 +1120,66 @@ EOF
public static function GetDashletCreationForm($sOQL = null)
{
$oAppContext = new ApplicationContext();
$sContextMenuId = $oAppContext->GetCurrentValue('menu', null);
$oForm = new DesignerForm();
// Get the list of all 'dashboard' menus in which we can insert a dashlet
$aAllMenus = ApplicationMenu::ReflectionMenuNodes();
$sRootMenuId = ApplicationMenu::GetRootMenuId($sContextMenuId);
$aAllowedDashboards = array();
foreach($aAllMenus as $idx => $aMenu)
$sDefaultDashboard = null;
// Store the parent menus for acces check
$aParentMenus = array();
foreach($aAllMenus as $idx => $aMenu)
{
/** @var MenuNode $oMenu */
$oMenu = $aMenu['node'];
if (count(ApplicationMenu::GetChildren($oMenu->GetIndex())) > 0)
{
$aParentMenus[$oMenu->GetMenuId()] = $aMenu;
}
}
foreach($aAllMenus as $idx => $aMenu)
{
$oMenu = $aMenu['node'];
$sParentId = $aMenu['parent'];
if ($oMenu instanceof DashboardMenuNode)
{
$sMenuLabel = $oMenu->GetTitle();
$sParentLabel = Dict::S('Menu:'.$sParentId);
if ($sParentLabel != $sMenuLabel)
{
$aAllowedDashboards[$oMenu->GetMenuId()] = $sParentLabel.' - '.$sMenuLabel;
}
else
{
$aAllowedDashboards[$oMenu->GetMenuId()] = $sMenuLabel;
}
}
if ($oMenu instanceof DashboardMenuNode)
{
// Get the root parent for access check
$sParentId = $aMenu['parent'];
$aParentMenu = $aParentMenus[$sParentId];
while (isset($aParentMenus[$aParentMenu['parent']]))
{
// grand parent exists
$sParentId = $aParentMenu['parent'];
$aParentMenu = $aParentMenus[$sParentId];
}
/** @var \MenuNode $oParentMenu */
$oParentMenu = $aParentMenu['node'];
if ($oMenu->IsEnabled() && $oParentMenu->IsEnabled())
{
$sMenuLabel = $oMenu->GetTitle();
$sParentLabel = Dict::S('Menu:'.$sParentId);
if ($sParentLabel != $sMenuLabel)
{
$aAllowedDashboards[$oMenu->GetMenuId()] = $sParentLabel.' - '.$sMenuLabel;
}
else
{
$aAllowedDashboards[$oMenu->GetMenuId()] = $sMenuLabel;
}
if (empty($sDefaultDashboard) && ($sRootMenuId == ApplicationMenu::GetRootMenuId($oMenu->GetMenuId())))
{
$sDefaultDashboard = $oMenu->GetMenuId();
}
}
}
}
asort($aAllowedDashboards);
$aKeys = array_keys($aAllowedDashboards); // Select the first one by default
$sDefaultDashboard = $aKeys[0];
$oField = new DesignerComboField('menu_id', Dict::S('UI:DashletCreation:Dashboard'), $sDefaultDashboard);
$oField->SetAllowedValues($aAllowedDashboards);
$oField->SetMandatory(true);
@@ -814,6 +1213,7 @@ EOF
{
$oSubForm = new DesignerForm();
$oMetaModel = new ModelReflectionRuntime();
/** @var \Dashlet $oDashlet */
$oDashlet = new $sDashletClass($oMetaModel, 0);
$oDashlet->GetPropertiesFieldsFromOQL($oSubForm, $sOQL);
@@ -824,7 +1224,11 @@ EOF
return $oForm;
}
/**
* @param \WebPage $oPage
* @param $sOQL
*/
public static function GetDashletCreationDlgFromOQL($oPage, $sOQL)
{
$oPage->add('<div id="dashlet_creation_dlg">');
@@ -841,7 +1245,7 @@ EOF
$oPage->add_ready_script(
<<<EOF
$('#dashlet_creation_dlg').dialog({
width: 400,
width: 600,
modal: true,
title: '$sDialogTitle',
buttons: [
@@ -871,4 +1275,30 @@ $('#dashlet_creation_dlg').dialog({
EOF
);
}
/**
* @return string
*/
public function GetDefinitionFile()
{
return $this->sDefinitionFile;
}
/**
* @param string $sDefinitionFile
*/
public function SetDefinitionFile($sDefinitionFile)
{
$this->sDefinitionFile = $sDefinitionFile;
}
public function GetReloadURL()
{
return $this->sReloadURL;
}
public function SetReloadURL($sReloadURL)
{
$this->sReloadURL = $sReloadURL;
}
}

View File

@@ -59,6 +59,7 @@ abstract class DashboardLayoutMultiCol extends DashboardLayout
$bNoVisibleFound = true;
while($idx < count($aKeys) && $bNoVisibleFound)
{
/** @var \Dashlet $oDashlet */
$oDashlet = $aDashlets[$aKeys[$idx]];
if ($oDashlet->IsVisible())
{
@@ -98,13 +99,19 @@ abstract class DashboardLayoutMultiCol extends DashboardLayout
return $aCells;
}
/**
* @param \WebPage $oPage
* @param $aCells
* @param bool $bEditMode
* @param array $aExtraParams
*/
public function Render($oPage, $aCells, $bEditMode = false, $aExtraParams = array())
{
// Trim the list of cells to remove the invisible/empty ones at the end of the array
$aCells = $this->TrimCellsArray($aCells);
$oPage->add('<table style="width:100%"><tbody>');
$oPage->add('<table style="width:100%;table-layout:fixed;"><tbody>');
$iCellIdx = 0;
$fColSize = 100 / $this->iNbCols;
$sStyle = $bEditMode ? 'border: 1px #ccc dashed; width:'.$fColSize.'%;' : 'width: '.$fColSize.'%;';
@@ -122,6 +129,7 @@ abstract class DashboardLayoutMultiCol extends DashboardLayout
$aDashlets = $aCells[$iCellIdx];
if (count($aDashlets) > 0)
{
/** @var \Dashlet $oDashlet */
foreach($aDashlets as $oDashlet)
{
if ($oDashlet->IsVisible())

File diff suppressed because it is too large Load Diff

View File

@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<itop_design>
<itop_design xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="1.6">
<portals>
<portal id="legacy_portal" _delta="define">
<url>portal/index.php</url>
@@ -19,4 +19,9 @@
</deny>
</portal>
</portals>
<menus>
<menu id="AdminTools" xsi:type="MenuGroup" _delta="define">
<rank>80</rank>
</menu>
</menus>
</itop_design>

View File

@@ -1,5 +1,5 @@
<?php
// Copyright (C) 2010-2015 Combodo SARL
// Copyright (C) 2010-2017 Combodo SARL
//
// This file is part of iTop.
//
@@ -18,7 +18,7 @@
/**
* Data Table to display a set of objects in a tabular manner in HTML
*
* @copyright Copyright (C) 2010-2015 Combodo SARL
* @copyright Copyright (C) 2010-2017 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
@@ -31,7 +31,8 @@ class DataTable
protected $iNbObjects; // Total number of objects inthe set
protected $bUseCustomSettings; // Whether or not the current display uses custom settings
protected $oDefaultSettings; // the default settings for displaying such a list
protected $bShowObsoleteData;
/**
* @param $iListId mixed Unique ID for this div/table in the page
* @param $oSet DBObjectSet The set of data to display
@@ -47,6 +48,7 @@ class DataTable
$this->iNbObjects = $oSet->Count();
$this->bUseCustomSettings = false;
$this->oDefaultSettings = null;
$this->bShowObsoleteData = $oSet->GetShowObsoleteData();
}
public function Display(WebPage $oPage, DataTableSettings $oSettings, $bActionsMenu, $sSelectMode, $bViewLink, $aExtraParams)
@@ -145,7 +147,9 @@ class DataTable
$sHtml .= "<tr><td class=\"datacontents\">$sDataTable</td></tr>";
$sHtml .= "</table>\n";
$oPage->add_at_the_end($sConfigDlg);
$aExtraParams['show_obsolete_data'] = $this->bShowObsoleteData;
$aOptions = array(
'sPersistentId' => '',
'sFilter' => $this->oSet->GetFilter()->serialize(),
@@ -170,6 +174,7 @@ class DataTable
}
$sJSOptions = json_encode($aOptions);
$oPage->add_ready_script("$('#datatable_{$this->iListId}').datatable($sJSOptions);");
return $sHtml;
}
@@ -293,7 +298,7 @@ EOF;
if (!$oPage->IsPrintableVersion())
{
$sMenuTitle = Dict::S('UI:ConfigureThisList');
$sHtml = '<div class="itop_popup toolkit_menu" id="tk_'.$this->iListId.'"><ul><li><img src="../images/toolkit_menu.png?itopversion='.ITOP_VERSION.'"><ul>';
$sHtml = '<div class="itop_popup toolkit_menu" id="tk_'.$this->iListId.'"><ul><li><img src="../images/toolkit_menu.png?t='.utils::GetCacheBusterTimestamp().'"><ul>';
$oMenuItem1 = new JSPopupMenuItem('iTop::ConfigureList', $sMenuTitle, "$('#datatable_dlg_".$this->iListId."').dialog('open');");
$aActions = array(
@@ -486,6 +491,7 @@ EOF;
{
$aExtraParams['query_params'][$sName] = $sValue;
}
$aExtraParams['show_obsolete_data'] = $this->bShowObsoleteData;
$sHtml .= "<tr><td>";
$sHtml .= $oPage->GetTable($aAttribs, $aValues);
@@ -566,33 +572,6 @@ EOF
{
$oPage->add_ready_script("oTable.trigger(\"fakesorton\", [$sFakeSortList]);");
}
//if ($iNbPages == 1)
if (false)
{
if (isset($aExtraParams['cssCount']))
{
$sCssCount = $aExtraParams['cssCount'];
if ($sSelectMode == 'single')
{
$sSelectSelector = ":radio[name^=selectObj]";
}
else if ($sSelectMode == 'multiple')
{
$sSelectSelector = ":checkbox[name^=selectObj]";
}
$oPage->add_ready_script(
<<<EOF
$('#{$this->iListId} table.listResults $sSelectSelector').change(function() {
var c = $('{$sCssCount}');
var v = $('#{$this->iListId} table.listResults $sSelectSelector:checked').length;
c.val(v);
$('#{$this->iListId} .selectedCount').text(v);
c.trigger('change');
});
EOF
);
}
}
return $sHtml;
}
@@ -601,7 +580,7 @@ EOF
$iPageSize = ($iDefaultPageSize < 1) ? 1 : $iDefaultPageSize;
$iPageIndex = 1 + floor($iStart / $iPageSize);
$sHtml = $this->GetPager($oPage, $iPageSize, $iDefaultPageSize, $iPageIndex);
$oPage->add_ready_script("$('#pager{$this->iListId}').html('".str_replace("\n", ' ', addslashes($sHtml))."');");
$oPage->add_ready_script("$('#pager{$this->iListId}').html('".json_encode($sHtml)."');");
if ($iDefaultPageSize < 1)
{
$oPage->add_ready_script("$('#pager{$this->iListId}').parent().hide()");
@@ -777,6 +756,10 @@ class DataTableSettings implements Serializable
{
foreach($this->aClassAliases as $sAlias => $sClass)
{
if (!isset($this->aColumns[$sAlias]))
{
continue;
}
foreach($this->aColumns[$sAlias] as $sAttCode => $aData)
{
// Remove non-existent columns
@@ -792,7 +775,7 @@ class DataTableSettings implements Serializable
$aTempData = array();
foreach($aList as $sAttCode => $oAttDef)
{
if ( (!array_key_exists($sAttCode, $this->aColumns[$sAlias])) && (!$oAttDef instanceof AttributeLinkSet))
if ( (!array_key_exists($sAttCode, $this->aColumns[$sAlias])) && (!($oAttDef instanceof AttributeLinkedSet || $oAttDef instanceof AttributeDashboard)))
{
$aFieldData = $this->GetFieldData($sAlias, $sAttCode, $oAttDef, false /* bChecked */, 'none');
if ($aFieldData) $aTempData[$aFieldData['label']] = $aFieldData;
@@ -928,8 +911,15 @@ class DataTableSettings implements Serializable
}
else if ($oAttDef->IsExternalField())
{
$oExtAttDef = $oAttDef->GetExtAttDef();
$sLabel = Dict::Format('UI:ExtField_AsRemoteField', $oAttDef->GetLabel(), $oExtAttDef->GetLabel());
if ($oAttDef->IsFriendlyName())
{
$sLabel = Dict::Format('UI:ExtKey_AsFriendlyName', $oAttDef->GetLabel());
}
else
{
$oExtAttDef = $oAttDef->GetExtAttDef();
$sLabel = Dict::Format('UI:ExtField_AsRemoteField', $oAttDef->GetLabel(), $oExtAttDef->GetLabel());
}
}
elseif ($oAttDef instanceof AttributeFriendlyName)
{

File diff suppressed because it is too large Load Diff

View File

@@ -462,7 +462,7 @@ class ExcelExporter
$this->aAuthorizedClasses = array();
foreach($aClasses as $sAlias => $sClassName)
{
if (UserRights::IsActionAllowed($sClassName, UR_ACTION_READ, $oSet) && (UR_ALLOWED_YES || UR_ALLOWED_DEPENDS))
if (UserRights::IsActionAllowed($sClassName, UR_ACTION_READ, $oSet) != UR_ALLOWED_NO)
{
$this->aAuthorizedClasses[$sAlias] = $sClassName;
}

View File

@@ -203,7 +203,7 @@ class DesignerForm
public function RenderAsPropertySheet($oP, $bReturnHTML = false, $sNotifyParentSelector = null)
{
$sReturn = '';
$sReturn = '';
$sActionUrl = addslashes($this->sSubmitTo);
$sJSSubmitParams = json_encode($this->aSubmitParams);
$sFormId = $this->GetFormId();
@@ -339,7 +339,7 @@ EOF
return '</tr>';
}
public function RenderAsDialog($oPage, $sDialogId, $sDialogTitle, $iDialogWidth, $sOkButtonLabel, $sIntroduction = null)
public function RenderAsDialog($oPage, $sDialogId, $sDialogTitle, $iDialogWidth, $sOkButtonLabel, $sIntroduction = null, $bAutoOpen = true)
{
$this->SetPrefix('dlg_'); // To make sure that the controls have different IDs that the property sheet which may be displayed at the same time
@@ -355,12 +355,15 @@ EOF
$this->Render($oPage);
$oPage->add('</div>');
$sAutoOpen = $bAutoOpen ? 'true' : 'false';
$oPage->add_ready_script(
<<<EOF
$('#$sDialogId').dialog({
height: 'auto',
maxHeight: $(window).height() - 8,
width: $iDialogWidth,
modal: true,
autoOpen: $sAutoOpen,
title: '$sDialogTitle',
buttons: [
{ text: "$sOkButtonLabel", click: function() {
@@ -375,9 +378,9 @@ $('#$sDialogId').dialog({
}
}
} },
{ text: "$sCancelButtonLabel", click: function() { KillAllMenus(); $(this).dialog( "close" ); $(this).remove(); } },
{ text: "$sCancelButtonLabel", click: function() { $(this).dialog( "close" ); $(this).remove(); } },
],
close: function() { KillAllMenus(); $(this).remove(); }
close: function() { $(this).remove(); }
});
var oForm = $('#$sDialogId form');
var sFormId = oForm.attr('id');
@@ -529,7 +532,7 @@ EOF
public function GetFieldId($sCode)
{
return $this->GetPrefix().'attr_'.$sCode;
return $this->GetPrefix().'attr_'.utils::GetSafeId($sCode.$this->GetSuffix());
}
public function GetFieldName($sCode)
@@ -679,6 +682,7 @@ class DesignerFormField
protected $sLabel;
protected $sCode;
protected $defaultValue;
/** @var \DesignerForm $oForm */
protected $oForm;
protected $bMandatory;
protected $bReadOnly;
@@ -704,8 +708,11 @@ class DesignerFormField
{
return $this->sCode;
}
public function SetForm($oForm)
/**
* @param \DesignerForm $oForm
*/
public function SetForm(\DesignerForm $oForm)
{
$this->oForm = $oForm;
}
@@ -879,7 +886,7 @@ class DesignerTextField extends DesignerFormField
$this->sValidationPattern = $sValidationPattern;
}
public function SetForbiddenValues($aValues, $sExplain)
public function SetForbiddenValues($aValues, $sExplain, $bCaseSensitive = true)
{
$aForbiddenValues = $aValues;
@@ -891,7 +898,7 @@ class DesignerTextField extends DesignerFormField
}
$this->aForbiddenValues[] = array('values' => $aForbiddenValues, 'message' => $sExplain);
$this->aForbiddenValues[] = array('values' => $aForbiddenValues, 'message' => $sExplain, 'case_sensitive' => $bCaseSensitive);
}
public function Render(WebPage $oP, $sFormId, $sRenderMode='dialog')
@@ -937,8 +944,8 @@ EOF
public function ReadParam(&$aValues)
{
parent::ReadParam($aValues);
if (($this->sValidationPattern != '') &&(!preg_match('/'.$this->sValidationPattern.'/', $aValues[$this->sCode])) )
$sPattern = '/'.str_replace('/', '\/', $this->sValidationPattern).'/'; // Escape the forward slashes since they are used as delimiters for preg_match
if (($this->sValidationPattern != '') && (!preg_match($sPattern, $aValues[$this->sCode])) )
{
$aValues[$this->sCode] = $this->defaultValue;
}
@@ -1336,7 +1343,7 @@ EOF
}
else
{
$sValue = '<img src="'.$this->MakeFileUrl($this->defaultValue).'" />';
$sValue = '<span style="display:inline-block;line-height:48px;height:48px;"><span><img style="vertical-align:middle" src="'.$this->aAllowedValues[$idx]['icon'].'" />&nbsp;'.htmlentities($this->aAllowedValues[$idx]['label'], ENT_QUOTES, 'UTF-8').'</span></span>';
}
$sReadOnly = $this->IsReadOnly() ? 'disabled' : '';
return array('label' => $this->sLabel, 'value' => $sValue);
@@ -1365,6 +1372,36 @@ class RunTimeIconSelectionField extends DesignerIconSelectionField
}
static protected function FindIconsOnDisk($sBaseDir, $sDir = '')
{
$aFiles = null;
$sKey = $sBaseDir.'/'.$sDir;
$sShortKey = abs(crc32($sKey));
$sCacheFile = utils::GetCachePath().'available-icons-'.$sShortKey.'.php';
$sCacheClass = 'AvailableIcons_'.$sShortKey;
if (file_exists($sCacheFile))
{
require_once($sCacheFile);
if ($sCacheClass::$sKey === $sKey) // crc32 collision detection
{
$aFiles = $sCacheClass::$aIconFiles;
}
}
if ($aFiles === null)
{
$aFiles = self::_FindIconsOnDisk($sBaseDir, $sDir);
$sAvailableIcons = '<?php'.PHP_EOL;
$sAvailableIcons .= '// Generated and used by '.__METHOD__.PHP_EOL;
$sAvailableIcons .= 'class '.$sCacheClass.PHP_EOL;
$sAvailableIcons .= '{'.PHP_EOL;
$sAvailableIcons .= ' static $sKey = '.var_export($sKey, true).';'.PHP_EOL;
$sAvailableIcons .= ' static $aIconFiles = '.var_export($aFiles, true).';'.PHP_EOL;
$sAvailableIcons .= '}'.PHP_EOL;
file_put_contents($sCacheFile, $sAvailableIcons, LOCK_EX);
}
return $aFiles;
}
static protected function _FindIconsOnDisk($sBaseDir, $sDir = '')
{
$aResult = array();
// Populate automatically the list of icon files
@@ -1376,7 +1413,7 @@ class RunTimeIconSelectionField extends DesignerIconSelectionField
if (($sFile != '.') && ($sFile != '..') && ($sFile != 'lifecycle') && is_dir($sBaseDir.'/'.$sDir.'/'.$sFile))
{
$sDirSubPath = ($sDir == '') ? $sFile : $sDir.'/'.$sFile;
$aResult = array_merge($aResult, self::FindIconsOnDisk($sBaseDir, $sDirSubPath));
$aResult = array_merge($aResult, self::_FindIconsOnDisk($sBaseDir, $sDirSubPath));
}
if (preg_match("/\.(png|jpg|jpeg|gif)$/i", $sFile, $aMatches)) // png, jp(e)g and gif are considered valid
{
@@ -1406,8 +1443,12 @@ class RunTimeIconSelectionField extends DesignerIconSelectionField
public function GetDefaultValue($sClass = 'Contact')
{
$sIconPath = MetaModel::GetClassIcon($sClass, false);
$sIcon = str_replace(utils::GetAbsoluteUrlModulesRoot(), '', $sIconPath);
$sIcon = '';
if (MetaModel::IsValidClass($sClass))
{
$sIconPath = MetaModel::GetClassIcon($sClass, false);
$sIcon = str_replace(utils::GetAbsoluteUrlModulesRoot(), '', $sIconPath);
}
return $sIcon;
}
}
@@ -1488,7 +1529,6 @@ class DesignerFormSelectorField extends DesignerFormField
public function AddSubForm($oSubForm, $sLabel, $sValue)
{
$idx = count($this->aSubForms);
$this->aSubForms[] = array('form' => $oSubForm, 'label' => $sLabel, 'value' => $sValue);
if ($sValue == $this->defaultRealValue)
{
@@ -1502,7 +1542,7 @@ class DesignerFormSelectorField extends DesignerFormField
$sId = $this->oForm->GetFieldId($this->sCode);
$sName = $this->oForm->GetFieldName($this->sCode);
$sReadOnly = $this->IsReadOnly() ? 'disabled="disabled"' : '';
$this->aCSSClasses[] = 'formSelector';
$sCSSClasses = '';
@@ -1518,8 +1558,6 @@ class DesignerFormSelectorField extends DesignerFormField
if ($this->IsReadOnly())
{
$aSelected = array();
$aHiddenValues = array();
$sDisplayValue = '';
$sHiddenValue = '';
foreach($this->aSubForms as $iKey => $aFormData)
@@ -1535,8 +1573,6 @@ class DesignerFormSelectorField extends DesignerFormField
}
else
{
$sHtml = "<select $sCSSClasses id=\"$sId\" name=\"$sName\" $sReadOnly>";
foreach($this->aSubForms as $iKey => $aFormData)
{
@@ -1552,7 +1588,6 @@ class DesignerFormSelectorField extends DesignerFormField
{
$sHtml .= '</td><td class="prop_icon prop_apply"><span title="Apply" class="ui-icon ui-icon-circle-check"/></td><td class="prop_icon prop_cancel"><span title="Revert" class="ui-icon ui-icon-circle-close"/></td></tr>';
}
foreach($this->aSubForms as $sKey => $aFormData)
{
$sId = $this->oForm->GetFieldId($this->sCode);
@@ -1578,25 +1613,7 @@ class DesignerFormSelectorField extends DesignerFormField
$oSubForm->SetHierarchyPath($sPath);
$oSubForm->SetDisplayed($sKey == $this->defaultValue);
$sState = ($sKey == $this->defaultValue) ? 'visible' : 'hidden';
//$sHtml .= "</tbody><tbody data-selector=\"$sSelector\" data-path=\"$sPath\" data-state=\"$sState\" $sStyle>";
$sHtml .= $oSubForm->RenderAsPropertySheet($oP, true);
$sState = $this->oForm->IsDisplayed() ? 'visible' : 'hidden';
$sParentStyle = '';
if ($oParent = $this->oForm->GetParentForm())
{
$sParentStyle = ($oParent->IsDisplayed()) ? '' : 'style="display:none"';
$sParentSelector = $oParent->GetHierarchyParent();
$sParentPath = $oParent->GetHierarchyPath();
}
else
{
$sParentSelector = '';
$sParentPath = '';
}
//$sHtml .= "</tbody><tbody data-selector=\"$sParentSelector\" data-path=\"$sParentPath\" data-state=\"$sState\" $sParentStyle>";
}
else
{
@@ -1644,7 +1661,6 @@ EOF
if ($selectedValue == $aFormData['value'])
{
$this->defaultValue =$iKey;
$aDefaultValues = $this->oForm->GetDefaultValues();
$oSubForm = $aFormData['form'];
$oSubForm->SetDefaultValues($aAllDefaultValues);
}

View File

@@ -1,69 +1,69 @@
<?php
// Copyright (C) 2010-2012 Combodo SARL
//
// This file is part of iTop.
//
// iTop is free software; you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// iTop is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with iTop. If not, see <http://www.gnu.org/licenses/>
/**
* Persistent class InputOutputTask
*
* @copyright Copyright (C) 2010-2012 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
require_once(APPROOT.'/application/cmdbabstract.class.inc.php');
/**
* This class manages the input/output tasks
* for synchronizing information with external data sources
*/
class InputOutputTask extends cmdbAbstractObject
{
public static function Init()
{
$aParams = array
(
"category" => "application",
"key_type" => "autoincrement",
"name_attcode" => "name",
"state_attcode" => "",
"reconc_keys" => array(),
"db_table" => "priv_iotask",
"db_key_field" => "id",
"db_finalclass_field" => "",
"display_template" => "",
);
MetaModel::Init_Params($aParams);
MetaModel::Init_AddAttribute(new AttributeString("name", array("allowed_values"=>null, "sql"=>"name", "default_value"=>"", "is_null_allowed"=>false, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeString("description", array("allowed_values"=>null, "sql"=>"description", "default_value"=>"", "is_null_allowed"=>true, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeEnum("category", array("allowed_values"=>new ValueSetEnum('Input, Ouput'), "sql"=>"category", "default_value"=>"Input", "is_null_allowed"=>false, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeEnum("source_type", array("allowed_values"=>new ValueSetEnum('File, Database, Web Service'), "sql"=>"source_type", "default_value"=>"File", "is_null_allowed"=>false, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeEnum("source_subtype", array("allowed_values"=>new ValueSetEnum('Oracle, MySQL, Postgress, MSSQL, SOAP, HTTP-Get, HTTP-Post, XML/RPC, CSV, XML, Excel'), "sql"=>"source_subtype", "default_value"=>"CSV", "is_null_allowed"=>false, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeString("source_path", array("allowed_values"=>null, "sql"=>"source_path", "default_value"=>"", "is_null_allowed"=>false, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeClass("objects_class", array("class_category"=>"", "more_values"=>"", "sql"=>"objects_class", "default_value"=>null, "is_null_allowed"=>true, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeEnum("test_mode", array("allowed_values"=>new ValueSetEnum('Yes,No'), "sql"=>"test_mode", "default_value"=>'No', "is_null_allowed"=>false, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeEnum("verbose_mode", array("allowed_values"=>new ValueSetEnum('Yes,No'), "sql"=>"verbose_mode", "default_value" => 'No', "is_null_allowed"=>false, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeEnum("options", array("allowed_values"=>new ValueSetEnum('Full, Update Only, Creation Only'), "sql"=>"options", "default_value"=> 'Full', "is_null_allowed"=>true, "depends_on"=>array())));
// Display lists
MetaModel::Init_SetZListItems('details', array('name', 'description', 'category', 'objects_class', 'source_type', 'source_subtype', 'source_path' , 'options', 'test_mode', 'verbose_mode')); // Attributes to be displayed for the complete details
MetaModel::Init_SetZListItems('list', array('description', 'category', 'objects_class', 'source_type', 'source_subtype', 'options')); // Attributes to be displayed for a list
// Search criteria
MetaModel::Init_SetZListItems('standard_search', array('name', 'category', 'objects_class', 'source_type', 'source_subtype')); // Criteria of the std search form
MetaModel::Init_SetZListItems('advanced_search', array('name', 'description', 'category', 'objects_class', 'source_type', 'source_subtype')); // Criteria of the advanced search form
}
}
?>
<?php
// Copyright (C) 2010-2012 Combodo SARL
//
// This file is part of iTop.
//
// iTop is free software; you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// iTop is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with iTop. If not, see <http://www.gnu.org/licenses/>
/**
* Persistent class InputOutputTask
*
* @copyright Copyright (C) 2010-2012 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
require_once(APPROOT.'/application/cmdbabstract.class.inc.php');
/**
* This class manages the input/output tasks
* for synchronizing information with external data sources
*/
class InputOutputTask extends cmdbAbstractObject
{
public static function Init()
{
$aParams = array
(
"category" => "application",
"key_type" => "autoincrement",
"name_attcode" => "name",
"state_attcode" => "",
"reconc_keys" => array(),
"db_table" => "priv_iotask",
"db_key_field" => "id",
"db_finalclass_field" => "",
"display_template" => "",
);
MetaModel::Init_Params($aParams);
MetaModel::Init_AddAttribute(new AttributeString("name", array("allowed_values"=>null, "sql"=>"name", "default_value"=>"", "is_null_allowed"=>false, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeString("description", array("allowed_values"=>null, "sql"=>"description", "default_value"=>"", "is_null_allowed"=>true, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeEnum("category", array("allowed_values"=>new ValueSetEnum('Input, Ouput'), "sql"=>"category", "default_value"=>"Input", "is_null_allowed"=>false, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeEnum("source_type", array("allowed_values"=>new ValueSetEnum('File, Database, Web Service'), "sql"=>"source_type", "default_value"=>"File", "is_null_allowed"=>false, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeEnum("source_subtype", array("allowed_values"=>new ValueSetEnum('Oracle, MySQL, Postgress, MSSQL, SOAP, HTTP-Get, HTTP-Post, XML/RPC, CSV, XML, Excel'), "sql"=>"source_subtype", "default_value"=>"CSV", "is_null_allowed"=>false, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeString("source_path", array("allowed_values"=>null, "sql"=>"source_path", "default_value"=>"", "is_null_allowed"=>false, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeClass("objects_class", array("class_category"=>"", "more_values"=>"", "sql"=>"objects_class", "default_value"=>null, "is_null_allowed"=>true, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeEnum("test_mode", array("allowed_values"=>new ValueSetEnum('Yes,No'), "sql"=>"test_mode", "default_value"=>'No', "is_null_allowed"=>false, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeEnum("verbose_mode", array("allowed_values"=>new ValueSetEnum('Yes,No'), "sql"=>"verbose_mode", "default_value" => 'No', "is_null_allowed"=>false, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeEnum("options", array("allowed_values"=>new ValueSetEnum('Full, Update Only, Creation Only'), "sql"=>"options", "default_value"=> 'Full', "is_null_allowed"=>true, "depends_on"=>array())));
// Display lists
MetaModel::Init_SetZListItems('details', array('name', 'description', 'category', 'objects_class', 'source_type', 'source_subtype', 'source_path' , 'options', 'test_mode', 'verbose_mode')); // Attributes to be displayed for the complete details
MetaModel::Init_SetZListItems('list', array('description', 'category', 'objects_class', 'source_type', 'source_subtype', 'options')); // Attributes to be displayed for a list
// Search criteria
MetaModel::Init_SetZListItems('standard_search', array('name', 'category', 'objects_class', 'source_type', 'source_subtype')); // Criteria of the std search form
MetaModel::Init_SetZListItems('advanced_search', array('name', 'description', 'category', 'objects_class', 'source_type', 'source_subtype')); // Criteria of the advanced search form
}
}
?>

File diff suppressed because it is too large Load Diff

View File

@@ -1,57 +1,57 @@
<?php
// Copyright (C) 2010-2012 Combodo SARL
//
// This file is part of iTop.
//
// iTop is free software; you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// iTop is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with iTop. If not, see <http://www.gnu.org/licenses/>
/**
* Class iTopWizardWebPage
*
* @copyright Copyright (C) 2010-2012 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
require_once('itopwebpage.class.inc.php');
/**
* Web page to display a wizard in the iTop framework
*/
class iTopWizardWebPage extends iTopWebPage
{
var $m_iCurrentStep;
var $m_aSteps;
public function __construct($sTitle, $currentOrganization, $iCurrentStep, $aSteps)
{
parent::__construct($sTitle." - step $iCurrentStep of ".count($aSteps)." - ".$aSteps[$iCurrentStep - 1], $currentOrganization);
$this->m_iCurrentStep = $iCurrentStep;
$this->m_aSteps = $aSteps;
}
public function output()
{
$aSteps = array();
$iIndex = 0;
foreach($this->m_aSteps as $sStepTitle)
{
$iIndex++;
$sStyle = ($iIndex == $this->m_iCurrentStep) ? 'wizActiveStep' : 'wizStep';
$aSteps[] = "<div class=\"$sStyle\"><span>$sStepTitle</span></div>";
}
$sWizardHeader = "<div class=\"wizHeader\"><h1>".htmlentities($this->s_title, ENT_QUOTES, 'UTF-8')."</h1>\n".implode("<div class=\"wizSeparator\"><img align=\"bottom\" src=\"../images/wizArrow.gif\"></div>", $aSteps)."<br style=\"clear:both;\"/></div>\n";
$this->s_content = "$sWizardHeader<div class=\"wizContainer\">".$this->s_content."</div>";
parent::output();
}
}
?>
<?php
// Copyright (C) 2010-2012 Combodo SARL
//
// This file is part of iTop.
//
// iTop is free software; you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// iTop is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with iTop. If not, see <http://www.gnu.org/licenses/>
/**
* Class iTopWizardWebPage
*
* @copyright Copyright (C) 2010-2012 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
require_once('itopwebpage.class.inc.php');
/**
* Web page to display a wizard in the iTop framework
*/
class iTopWizardWebPage extends iTopWebPage
{
var $m_iCurrentStep;
var $m_aSteps;
public function __construct($sTitle, $currentOrganization, $iCurrentStep, $aSteps)
{
parent::__construct($sTitle." - step $iCurrentStep of ".count($aSteps)." - ".$aSteps[$iCurrentStep - 1], $currentOrganization);
$this->m_iCurrentStep = $iCurrentStep;
$this->m_aSteps = $aSteps;
}
public function output()
{
$aSteps = array();
$iIndex = 0;
foreach($this->m_aSteps as $sStepTitle)
{
$iIndex++;
$sStyle = ($iIndex == $this->m_iCurrentStep) ? 'wizActiveStep' : 'wizStep';
$aSteps[] = "<div class=\"$sStyle\"><span>$sStepTitle</span></div>";
}
$sWizardHeader = "<div class=\"wizHeader\"><h1>".htmlentities($this->s_title, ENT_QUOTES, 'UTF-8')."</h1>\n".implode("<div class=\"wizSeparator\"><img align=\"bottom\" src=\"../images/wizArrow.gif\"></div>", $aSteps)."<br style=\"clear:both;\"/></div>\n";
$this->s_content = "$sWizardHeader<div class=\"wizContainer\">".$this->s_content."</div>";
parent::output();
}
}
?>

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,159 @@
<?php
// Copyright (C) 2010-2015 Combodo SARL
//
// This file is part of iTop.
//
// iTop is free software; you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// iTop is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with iTop. If not, see <http://www.gnu.org/licenses/>
/**
* A provider for messages to be displayed in the iTop Newsroom
*/
interface iNewsroomProvider
{
/**
* Inject the current configuration in the provider
* @param Config $oConfig
* @return void
*/
public function SetConfig(Config $oConfig);
/**
* Tells if this provider is enabled for the given user
* @param User $oUser The user for who to check if the provider is applicable.
* return bool
*/
public function IsApplicable(User $oUser = null);
/**
* The human readable (localized) label for this provider
* @return string
*/
public function GetLabel();
/**
* The URL to query (from the browser, using jsonp) to fetch all unread messages
* @return string
*/
public function GetFetchURL();
/**
* The URL to navigate to in order to display all messages
* @return string
*/
public function GetViewAllURL();
/**
* The URL to query(from the browser, using jsonp) to mark all unread messages as read
* @return string
*/
public function GetMarkAllAsReadURL();
/**
* Return the URL to configure the preferences for this provider or null is there is nothing to configure
* @return string|null
*/
public function GetPreferencesUrl();
/**
* Return an array key => value to be replaced in URL of the messages
* Example: '%itop_root%' => utils::GetAbsoluteUrlAppRoot();
* @return string[]
*/
public function GetPlaceholders();
/**
* The duration between to refreshes of the cache (in seconds)
* @return int
*/
public function GetTTL();
}
/**
* Basic implementation of a Newsroom provider, to be overloaded by your own provider implementation
*
*/
abstract class NewsroomProviderBase implements iNewsroomProvider
{
/**
* The current configuration parameters
* @var Config
*/
protected $oConfig;
public function __construct()
{
$this->oConfig = null;
}
/**
* {@inheritDoc}
* @see iNewsroomProvider::SetConfig()
*/
public function SetConfig(Config $oConfig)
{
$this->oConfig = $oConfig;
}
/**
* {@inheritDoc}
* @see iNewsroomProvider::GetPreferencesUrl()
*/
public function GetPreferencesUrl()
{
return null; // No preferences
}
/**
* {@inheritDoc}
* @see iNewsroomProvider::GetLabel()
*/
public abstract function GetLabel();
/**
* {@inheritDoc}
* @see iNewsroomProvider::GetFetchURL()
*/
public abstract function GetFetchURL();
/**
* {@inheritDoc}
* @see iNewsroomProvider::GetMarkAllURL()
*/
public abstract function GetMarkAllAsReadURL();
/**
* {@inheritDoc}
* @see iNewsroomProvider::GetViewAllURL()
*/
public abstract function GetViewAllURL();
public function IsApplicable(User $oUser = null)
{
return false;
}
/**
* {@inheritDoc}
* @see iNewsroomProvider::GetPlaceholders()
*/
public function GetPlaceholders()
{
return array(); // By default, empty set of placeholders
}
public function GetTTL()
{
return 10*60; // Refresh every 10 minutes
}
}

View File

@@ -1,231 +1,259 @@
<?php
// Copyright (C) 2010-2015 Combodo SARL
//
// This file is part of iTop.
//
// iTop is free software; you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// iTop is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with iTop. If not, see <http://www.gnu.org/licenses/>
/**
* Class NiceWebPage
*
* @copyright Copyright (C) 2010-2015 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
require_once(APPROOT."/application/webpage.class.inc.php");
/**
* Web page with some associated CSS and scripts (jquery) for a fancier display
*/
class NiceWebPage extends WebPage
{
var $m_aReadyScripts;
var $m_sRootUrl;
public function __construct($s_title, $bPrintable = false)
{
parent::__construct($s_title, $bPrintable);
$this->m_aReadyScripts = array();
$this->add_linked_script("../js/jquery-1.10.0.min.js");
$this->add_linked_script("../js/jquery-migrate-1.2.1.min.js"); // Needed since many other plugins still rely on oldies like $.browser
$this->add_linked_stylesheet('../css/ui-lightness/jquery-ui-1.10.3.custom.min.css');
$this->add_linked_script('../js/jquery-ui-1.10.3.custom.min.js');
$this->add_linked_script("../js/hovertip.js");
// table sorting
$this->add_linked_script("../js/jquery.tablesorter.js");
$this->add_linked_script("../js/jquery.tablesorter.pager.js");
$this->add_linked_script("../js/jquery.tablehover.js");
$this->add_linked_script('../js/field_sorter.js');
$this->add_linked_script('../js/datatable.js');
$this->add_linked_script("../js/jquery.positionBy.js");
$this->add_linked_script("../js/jquery.popupmenu.js");
$this->add_ready_script(
<<< EOF
//add new widget called TruncatedList to properly display truncated lists when they are sorted
$.tablesorter.addWidget({
// give the widget a id
id: "truncatedList",
// format is called when the on init and when a sorting has finished
format: function(table)
{
// Check if there is a "truncated" line
this.truncatedList = false;
if ($("tr td.truncated",table).length > 0)
{
this.truncatedList = true;
}
if (this.truncatedList)
{
$("tr td",table).removeClass('truncated');
$("tr:last td",table).addClass('truncated');
}
}
});
$.tablesorter.addWidget({
// give the widget a id
id: "myZebra",
// format is called when the on init and when a sorting has finished
format: function(table)
{
// Replace the 'red even' lines by 'red_even' since most browser do not support 2 classes selector in CSS, etc..
$("tbody tr:even",table).addClass('even');
$("tbody tr.red:even",table).removeClass('red').removeClass('even').addClass('red_even');
$("tbody tr.orange:even",table).removeClass('orange').removeClass('even').addClass('orange_even');
$("tbody tr.green:even",table).removeClass('green').removeClass('even').addClass('green_even');
// In case we sort again the table, we need to remove the added 'even' classes on odd rows
$("tbody tr:odd",table).removeClass('even');
$("tbody tr.red_even:odd",table).removeClass('even').removeClass('red_even').addClass('red');
$("tbody tr.orange_even:odd",table).removeClass('even').removeClass('orange_even').addClass('orange');
$("tbody tr.green_even:odd",table).removeClass('even').removeClass('green_even').addClass('green');
}
});
$("table.listResults").tableHover(); // hover tables
EOF
);
$this->add_saas("css/light-grey.scss");
$this->m_sRootUrl = $this->GetAbsoluteUrlAppRoot();
$sAbsURLAppRoot = addslashes($this->m_sRootUrl);
$sAbsURLModulesRoot = addslashes($this->GetAbsoluteUrlModulesRoot());
$sEnvironment = addslashes(utils::GetCurrentEnvironment());
$sAppContext = addslashes($this->GetApplicationContext());
$this->add_script(
<<<EOF
function GetAbsoluteUrlAppRoot()
{
return '$sAbsURLAppRoot';
}
function GetAbsoluteUrlModulesRoot()
{
return '$sAbsURLModulesRoot';
}
function GetAbsoluteUrlModulePage(sModule, sPage, aArguments)
{
// aArguments is optional, it default to an empty hash
aArguments = typeof aArguments !== 'undefined' ? aArguments : {};
var sUrl = '$sAbsURLAppRoot'+'pages/exec.php?exec_module='+sModule+'&exec_page='+sPage+'&exec_env='+'$sEnvironment';
for (var sArgName in aArguments)
{
if (aArguments.hasOwnProperty(sArgName))
{
sUrl = sUrl + '&'+sArgName+'='+aArguments[sArgname];
}
}
return sUrl;
}
function AddAppContext(sURL)
{
var sContext = '$sAppContext';
if (sContext.length > 0)
{
if (sURL.indexOf('?') == -1)
{
return sURL+'?'+sContext;
}
return sURL+'&'+sContext;
}
return sURL;
}
EOF
);
}
public function SetRootUrl($sRootUrl)
{
$this->m_sRootUrl = $sRootUrl;
}
public function small_p($sText)
{
$this->add("<p style=\"font-size:smaller\">$sText</p>\n");
}
public function GetAbsoluteUrlAppRoot()
{
return utils::GetAbsoluteUrlAppRoot();
}
public function GetAbsoluteUrlModulesRoot()
{
return utils::GetAbsoluteUrlModulesRoot();
}
function GetApplicationContext()
{
$oAppContext = new ApplicationContext();
return $oAppContext->GetForLink();
}
// By Rom, used by CSVImport and Advanced search
public function MakeClassesSelect($sName, $sDefaultValue, $iWidthPx, $iActionCode = null)
{
// $aTopLevelClasses = array('bizService', 'bizContact', 'logInfra', 'bizDocument');
// These are classes wich root class is cmdbAbstractObject !
$this->add("<select id=\"select_$sName\" name=\"$sName\">");
$aValidClasses = array();
foreach(MetaModel::GetClasses('bizmodel') as $sClassName)
{
if (is_null($iActionCode) || UserRights::IsActionAllowed($sClassName, $iActionCode))
{
$sSelected = ($sClassName == $sDefaultValue) ? " SELECTED" : "";
$sDescription = MetaModel::GetClassDescription($sClassName);
$sDisplayName = MetaModel::GetName($sClassName);
$aValidClasses[$sDisplayName] = "<option style=\"width: ".$iWidthPx." px;\" title=\"$sDescription\" value=\"$sClassName\"$sSelected>$sDisplayName</option>";
}
}
ksort($aValidClasses);
$this->add(implode("\n", $aValidClasses));
$this->add("</select>");
}
// By Rom, used by Advanced search
public function add_select($aChoices, $sName, $sDefaultValue, $iWidthPx)
{
$this->add("<select id=\"select_$sName\" name=\"$sName\">");
foreach($aChoices as $sKey => $sValue)
{
$sSelected = ($sKey == $sDefaultValue) ? " SELECTED" : "";
$this->add("<option style=\"width: ".$iWidthPx." px;\" value=\"".htmlspecialchars($sKey)."\"$sSelected>".htmlentities($sValue, ENT_QUOTES, 'UTF-8')."</option>");
}
$this->add("</select>");
}
public function add_ready_script($sScript)
{
$this->m_aReadyScripts[] = $sScript;
}
/**
* Outputs (via some echo) the complete HTML page by assembling all its elements
*/
public function output()
{
//$this->set_base($this->m_sRootUrl.'pages/');
if (count($this->m_aReadyScripts)>0)
{
$this->add_script("\$(document).ready(function() {\n".implode("\n", $this->m_aReadyScripts)."\n});");
}
parent::output();
}
}
?>
<?php
// Copyright (C) 2010-2016 Combodo SARL
//
// This file is part of iTop.
//
// iTop is free software; you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// iTop is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with iTop. If not, see <http://www.gnu.org/licenses/>
/**
* Class NiceWebPage
*
* @copyright Copyright (C) 2010-2016 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
require_once(APPROOT."/application/webpage.class.inc.php");
/**
* Web page with some associated CSS and scripts (jquery) for a fancier display
*/
class NiceWebPage extends WebPage
{
var $m_aReadyScripts;
var $m_sRootUrl;
public function __construct($s_title, $bPrintable = false)
{
parent::__construct($s_title, $bPrintable);
$this->m_aReadyScripts = array();
$this->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/jquery-3.3.1.min.js');
if(utils::IsDevelopmentEnvironment()) // Needed since many other plugins still rely on oldies like $.browser
{
$this->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/jquery-migrate-3.0.1.dev.js');
}
else
{
$this->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/jquery-migrate-3.0.1.prod.min.js');
}
$this->add_linked_stylesheet(utils::GetAbsoluteUrlAppRoot().'css/ui-lightness/jquery-ui-1.11.4.custom.css');
$this->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/jquery-ui-1.11.4.custom.min.js');
$this->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/utils.js');
$this->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/hovertip.js');
// table sorting
$this->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/jquery.tablesorter.js');
$this->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/jquery.tablesorter.pager.js');
$this->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/jquery.tablehover.js');
$this->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/table-selectable-lines.js');
$this->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/field_sorter.js');
$this->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/datatable.js');
$this->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/jquery.positionBy.js');
$this->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/jquery.popupmenu.js');
$this->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/searchformforeignkeys.js');
$this->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/latinise/latinise.min.js');
$this->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/search/search_form_handler.js');
$this->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/search/search_form_handler_history.js');
$this->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/search/search_form_criteria.js');
$this->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/search/search_form_criteria_raw.js');
$this->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/search/search_form_criteria_string.js');
$this->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/search/search_form_criteria_external_field.js');
$this->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/search/search_form_criteria_numeric.js');
$this->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/search/search_form_criteria_enum.js');
$this->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/search/search_form_criteria_tag_set.js');
$this->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/search/search_form_criteria_external_key.js');
$this->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/search/search_form_criteria_hierarchical_key.js');
$this->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/search/search_form_criteria_date_abstract.js');
$this->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/search/search_form_criteria_date.js');
$this->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/search/search_form_criteria_date_time.js');
$this->add_dict_entries('UI:Combo');
$this->add_ready_script(
<<< EOF
//add new widget called TruncatedList to properly display truncated lists when they are sorted
$.tablesorter.addWidget({
// give the widget a id
id: "truncatedList",
// format is called when the on init and when a sorting has finished
format: function(table)
{
// Check if there is a "truncated" line
this.truncatedList = false;
if ($("tr td.truncated",table).length > 0)
{
this.truncatedList = true;
}
if (this.truncatedList)
{
$("tr td",table).removeClass('truncated');
$("tr:last td",table).addClass('truncated');
}
}
});
$.tablesorter.addWidget({
// give the widget a id
id: "myZebra",
// format is called when the on init and when a sorting has finished
format: function(table)
{
// Replace the 'red even' lines by 'red_even' since most browser do not support 2 classes selector in CSS, etc..
$("tbody tr:even",table).addClass('even');
$("tbody tr.red:even",table).removeClass('red').removeClass('even').addClass('red_even');
$("tbody tr.orange:even",table).removeClass('orange').removeClass('even').addClass('orange_even');
$("tbody tr.green:even",table).removeClass('green').removeClass('even').addClass('green_even');
// In case we sort again the table, we need to remove the added 'even' classes on odd rows
$("tbody tr:odd",table).removeClass('even');
$("tbody tr.red_even:odd",table).removeClass('even').removeClass('red_even').addClass('red');
$("tbody tr.orange_even:odd",table).removeClass('even').removeClass('orange_even').addClass('orange');
$("tbody tr.green_even:odd",table).removeClass('even').removeClass('green_even').addClass('green');
}
});
$("table.listResults").tableHover(); // hover tables
EOF
);
$this->add_saas("css/light-grey.scss");
$this->m_sRootUrl = $this->GetAbsoluteUrlAppRoot();
$sAbsURLAppRoot = addslashes($this->m_sRootUrl);
$sAbsURLModulesRoot = addslashes($this->GetAbsoluteUrlModulesRoot());
$sEnvironment = addslashes(utils::GetCurrentEnvironment());
$sAppContext = addslashes($this->GetApplicationContext());
$this->add_script(
<<<EOF
function GetAbsoluteUrlAppRoot()
{
return '$sAbsURLAppRoot';
}
function GetAbsoluteUrlModulesRoot()
{
return '$sAbsURLModulesRoot';
}
function GetAbsoluteUrlModulePage(sModule, sPage, aArguments)
{
// aArguments is optional, it default to an empty hash
aArguments = typeof aArguments !== 'undefined' ? aArguments : {};
var sUrl = '$sAbsURLAppRoot'+'pages/exec.php?exec_module='+sModule+'&exec_page='+sPage+'&exec_env='+'$sEnvironment';
for (var sArgName in aArguments)
{
if (aArguments.hasOwnProperty(sArgName))
{
sUrl = sUrl + '&'+sArgName+'='+aArguments[sArgname];
}
}
return sUrl;
}
function AddAppContext(sURL)
{
var sContext = '$sAppContext';
if (sContext.length > 0)
{
if (sURL.indexOf('?') == -1)
{
return sURL+'?'+sContext;
}
return sURL+'&'+sContext;
}
return sURL;
}
EOF
);
}
public function SetRootUrl($sRootUrl)
{
$this->m_sRootUrl = $sRootUrl;
}
public function small_p($sText)
{
$this->add("<p style=\"font-size:smaller\">$sText</p>\n");
}
public function GetAbsoluteUrlAppRoot()
{
return utils::GetAbsoluteUrlAppRoot();
}
public function GetAbsoluteUrlModulesRoot()
{
return utils::GetAbsoluteUrlModulesRoot();
}
function GetApplicationContext()
{
$oAppContext = new ApplicationContext();
return $oAppContext->GetForLink();
}
// By Rom, used by CSVImport and Advanced search
public function MakeClassesSelect($sName, $sDefaultValue, $iWidthPx, $iActionCode = null)
{
// $aTopLevelClasses = array('bizService', 'bizContact', 'logInfra', 'bizDocument');
// These are classes wich root class is cmdbAbstractObject !
$this->add("<select id=\"select_$sName\" name=\"$sName\">");
$aValidClasses = array();
foreach(MetaModel::GetClasses('bizmodel') as $sClassName)
{
if (is_null($iActionCode) || UserRights::IsActionAllowed($sClassName, $iActionCode))
{
$sSelected = ($sClassName == $sDefaultValue) ? " SELECTED" : "";
$sDescription = MetaModel::GetClassDescription($sClassName);
$sDisplayName = MetaModel::GetName($sClassName);
$aValidClasses[$sDisplayName] = "<option style=\"width: ".$iWidthPx." px;\" title=\"$sDescription\" value=\"$sClassName\"$sSelected>$sDisplayName</option>";
}
}
ksort($aValidClasses);
$this->add(implode("\n", $aValidClasses));
$this->add("</select>");
}
// By Rom, used by Advanced search
public function add_select($aChoices, $sName, $sDefaultValue, $iWidthPx)
{
$this->add("<select id=\"select_$sName\" name=\"$sName\">");
foreach($aChoices as $sKey => $sValue)
{
$sSelected = ($sKey == $sDefaultValue) ? " SELECTED" : "";
$this->add("<option style=\"width: ".$iWidthPx." px;\" value=\"".htmlspecialchars($sKey)."\"$sSelected>".htmlentities($sValue, ENT_QUOTES, 'UTF-8')."</option>");
}
$this->add("</select>");
}
public function add_ready_script($sScript)
{
$this->m_aReadyScripts[] = $sScript;
}
/**
* Outputs (via some echo) the complete HTML page by assembling all its elements
*/
public function output()
{
//$this->set_base($this->m_sRootUrl.'pages/');
if (count($this->m_aReadyScripts)>0)
{
$this->add_script("\$(document).ready(function() {\n".implode("\n", $this->m_aReadyScripts)."\n});");
}
parent::output();
}
}
?>

View File

@@ -35,7 +35,7 @@ class iTopPDF extends TCPDF
// Display the page number (right aligned)
// Warning: the 'R'ight alignment does not work when using placeholders like $this->getAliasNumPage() or $this->getAliasNbPages()
$this->MultiCell($iPageNumberWidth, 15, 'Page '.$this->page, 0, 'R', false, 0 /* $ln */, '', '', true, 0, false, true, 15, 'M' /* $valign */);
$this->MultiCell($iPageNumberWidth, 15, Dict::Format('Core:BulkExport:PDF:PageNumber' ,$this->page), 0, 'R', false, 0 /* $ln */, '', '', true, 0, false, true, 15, 'M' /* $valign */);
// Branding logo
$sBrandingIcon = APPROOT.'images/itop-logo.png';

View File

@@ -13,20 +13,7 @@ class PortalDispatcher
public function IsUserAllowed()
{
$bRet = true;
if (array_key_exists('profile_list', $_SESSION))
{
$aProfiles = $_SESSION['profile_list'];
}
else
{
$oUser = UserRights::GetUserObject();
$oSet = $oUser->Get('profile_list');
while(($oLnkUserProfile = $oSet->Fetch()) !== null)
{
$aProfiles[] = $oLnkUserProfile->Get('profileid_friendlyname');
}
$_SESSION['profile_list'] = $aProfiles;
}
$aProfiles = UserRights::ListProfiles();
foreach($this->aData['deny'] as $sDeniedProfile)
{
@@ -55,7 +42,16 @@ class PortalDispatcher
public function GetURL()
{
return utils::GetAbsoluteUrlAppRoot().$this->aData['url'];
$aOverloads = MetaModel::GetConfig()->Get('portal_dispatch_urls');
if (array_key_exists($this->sPortalid, $aOverloads))
{
$sRet = $aOverloads[$this->sPortalid];
}
else
{
$sRet = utils::GetAbsoluteUrlAppRoot().$this->aData['url'];
}
return $sRet;
}
public function GetLabel()

View File

@@ -1,5 +1,5 @@
<?php
// Copyright (C) 2010-2013 Combodo SARL
// Copyright (C) 2010-2017 Combodo SARL
//
// This file is part of iTop.
//
@@ -19,7 +19,7 @@
/**
* Class PortalWebPage
*
* @copyright Copyright (C) 2010-2013 Combodo SARL
* @copyright Copyright (C) 2010-2017 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
@@ -49,9 +49,12 @@ class PortalWebPage extends NiceWebPage
*/
protected $m_sWelcomeMsg;
protected $m_aMenuButtons;
protected $m_oCtx;
public function __construct($sTitle, $sAlternateStyleSheet = '')
{
$this->m_oCtx = new ContextTag('GUI:Portal');
$this->m_sWelcomeMsg = '';
$this->m_aMenuButtons = array();
parent::__construct($sTitle);
@@ -93,15 +96,88 @@ class PortalWebPage extends NiceWebPage
$this->add_linked_script("../js/ckeditor/ckeditor.js");
$this->add_linked_script("../js/ckeditor/adapters/jquery.js");
$this->add_linked_script("../js/jquery-ui-timepicker-addon.js");
$this->add_linked_script("../js/jquery-ui-timepicker-addon-i18n.min.js");
$this->add_linked_stylesheet("../css/jquery-ui-timepicker-addon.css");
$sJSDisconnectedMessage = json_encode(Dict::S('UI:DisconnectedDlgMessage'));
$sJSTitle = json_encode(Dict::S('UI:DisconnectedDlgTitle'));
$sJSLoginAgain = json_encode(Dict::S('UI:LoginAgain'));
$sJSStayOnThePage = json_encode(Dict::S('UI:StayOnThePage'));
$sJSDaysMin = json_encode(array(Dict::S('DayOfWeek-Sunday-Min'), Dict::S('DayOfWeek-Monday-Min'), Dict::S('DayOfWeek-Tuesday-Min'), Dict::S('DayOfWeek-Wednesday-Min'),
Dict::S('DayOfWeek-Thursday-Min'), Dict::S('DayOfWeek-Friday-Min'), Dict::S('DayOfWeek-Saturday-Min')));
$sJSMonthsShort = json_encode(array(Dict::S('Month-01-Short'), Dict::S('Month-02-Short'), Dict::S('Month-03-Short'), Dict::S('Month-04-Short'), Dict::S('Month-05-Short'), Dict::S('Month-06-Short'),
Dict::S('Month-07-Short'), Dict::S('Month-08-Short'), Dict::S('Month-09-Short'), Dict::S('Month-10-Short'), Dict::S('Month-11-Short'), Dict::S('Month-12-Short')));
$iFirstDayOfWeek = (int) Dict::S('Calendar-FirstDayOfWeek');
$aDaysMin = array(Dict::S('DayOfWeek-Sunday-Min'), Dict::S('DayOfWeek-Monday-Min'), Dict::S('DayOfWeek-Tuesday-Min'), Dict::S('DayOfWeek-Wednesday-Min'),
Dict::S('DayOfWeek-Thursday-Min'), Dict::S('DayOfWeek-Friday-Min'), Dict::S('DayOfWeek-Saturday-Min'));
$aMonthsShort = array(Dict::S('Month-01-Short'), Dict::S('Month-02-Short'), Dict::S('Month-03-Short'), Dict::S('Month-04-Short'), Dict::S('Month-05-Short'), Dict::S('Month-06-Short'),
Dict::S('Month-07-Short'), Dict::S('Month-08-Short'), Dict::S('Month-09-Short'), Dict::S('Month-10-Short'), Dict::S('Month-11-Short'), Dict::S('Month-12-Short'));
$sTimeFormat = AttributeDateTime::GetFormat()->ToTimeFormat();
$oTimeFormat = new DateTimeFormat($sTimeFormat);
$sJSLangShort = json_encode(strtolower(substr(Dict::GetUserLanguage(), 0, 2)));
// Date picker options
$aPickerOptions = array(
'showOn' => 'button',
'buttonImage' => '../images/calendar.png',
'buttonImageOnly' => true,
'dateFormat' => AttributeDate::GetFormat()->ToDatePicker(),
'constrainInput' => false,
'changeMonth' => true,
'changeYear' => true,
'dayNamesMin' => $aDaysMin,
'monthNamesShort' => $aMonthsShort,
'firstDay' => (int) Dict::S('Calendar-FirstDayOfWeek'),
);
$sJSDatePickerOptions = json_encode($aPickerOptions);
// Time picker additional options
$aPickerOptions['showOn'] = '';
$aPickerOptions['buttonImage'] = null;
$aPickerOptions['timeFormat'] = $oTimeFormat->ToDatePicker();
$aPickerOptions['controlType'] = 'select';
$aPickerOptions['closeText'] = Dict::S('UI:Button:Ok');
$sJSDateTimePickerOptions = json_encode($aPickerOptions);
if ($sJSLangShort != '"en"')
{
// More options that cannot be passed via json_encode since they must be evaluated client-side
$aMoreJSOptions = ",
'timeText': $.timepicker.regional[$sJSLangShort].timeText,
'hourText': $.timepicker.regional[$sJSLangShort].hourText,
'minuteText': $.timepicker.regional[$sJSLangShort].minuteText,
'secondText': $.timepicker.regional[$sJSLangShort].secondText,
'currentText': $.timepicker.regional[$sJSLangShort].currentText
}";
$sJSDateTimePickerOptions = substr($sJSDateTimePickerOptions, 0, -1).$aMoreJSOptions;
}
$this->add_script(
<<< EOF
function PrepareWidgets()
{
// note: each action implemented here must be idempotent,
// because this helper function might be called several times on a given page
$(".date-pick").datepicker($sJSDatePickerOptions);
// Hack for the date and time picker addon issue on Chrome (see #1305)
// The workaround is to instantiate the widget on demand
// It relies on the same markup, thus reverting to the original implementation should be straightforward
$(".datetime-pick:not(.is-widget-ready)").each(function(){
var oInput = this;
$(oInput).addClass('is-widget-ready');
$('<img class="datetime-pick-button" src="../images/calendar.png">')
.insertAfter($(this))
.on('click', function(){
$(oInput)
.datetimepicker($sJSDateTimePickerOptions)
.datetimepicker('show')
.datetimepicker('option', 'onClose', function(dateText,inst){
$(oInput).datetimepicker('destroy');
})
.on('click keypress', function(){
$(oInput).datetimepicker('hide');
});
});
});
}
EOF
);
$this->add_ready_script(
<<<EOF
@@ -143,34 +219,10 @@ try
}
});
$(".date-pick").datepicker({
showOn: 'button',
buttonImage: '../images/calendar.png',
buttonImageOnly: true,
dateFormat: 'yy-mm-dd',
constrainInput: false,
changeMonth: true,
changeYear: true,
dayNamesMin: $sJSDaysMin,
monthNamesShort: $sJSMonthsShort,
firstDay: $iFirstDayOfWeek
});
$(".datetime-pick").datepicker({
showOn: 'button',
buttonImage: '../images/calendar.png',
buttonImageOnly: true,
dateFormat: 'yy-mm-dd 00:00:00',
constrainInput: false,
changeMonth: true,
changeYear: true,
dayNamesMin: $sJSDaysMin,
monthNamesShort: $sJSMonthsShort,
firstDay: $iFirstDayOfWeek
});
PrepareWidgets();
//$('.resizable').resizable(); // Make resizable everything that claims to be resizable !
$('.caselog_header').click( function () { $(this).toggleClass('open').next('.caselog_entry').toggle(); });
$('.caselog_header').click( function () { $(this).toggleClass('open').next('.caselog_entry,.caselog_entry_html').toggle(); });
$(document).ajaxSend(function(event, jqxhr, options) {
jqxhr.setRequestHeader('X-Combodo-Ajax', 'true');
@@ -260,7 +312,7 @@ EOF
{
var form = $('FORM');
form.unbind('submit'); // De-activate validation
window.location.href = window.location.href.replace(/[&?]operation=[^&]*/, '');
window.location.href = window.location.href.replace(/operation=[^&]*&?/, '');
return false;
}
@@ -335,7 +387,7 @@ EOF
{
$sReadOnly = Dict::S('UI:AccessRO-Users');
$sAdminMessage = trim(MetaModel::GetConfig()->Get('access_message'));
$sApplicationBanner .= '<div id="admin-banner">';
$sApplicationBanner .= '<div class="app-message">';
$sApplicationBanner .= '<img src="../images/locked.png" style="vertical-align:middle;">';
$sApplicationBanner .= '&nbsp;<b>'.$sReadOnly.'</b>';
if (strlen($sAdminMessage) > 0)
@@ -755,7 +807,7 @@ EOF
*/
public function DoUpdateObjectFromPostedForm(DBObject $oObj, $aAttList = null)
{
$sTransactionId = utils::ReadPostedParam('transaction_id', '');
$sTransactionId = utils::ReadPostedParam('transaction_id', '', 'transaction_id');
if (!utils::IsTransactionValid($sTransactionId))
{
throw new TransactionException();
@@ -764,7 +816,7 @@ EOF
$sClass = get_class($oObj);
$sStimulus = trim(utils::ReadPostedParam('apply_stimulus', ''));
$sTargetState = '';
$aExpectedAttributes = array();
if (!empty($sStimulus))
{
// Compute the target state
@@ -774,10 +826,10 @@ EOF
{
throw new ApplicationException(Dict::Format('UI:Error:Invalid_Stimulus_On_Object_In_State', $sStimulus, $oObj->GetName(), $oObj->GetStateLabel()));
}
$sTargetState = $aTransitions[$sStimulus]['target_state'];
}
$aExpectedAttributes = $oObj->GetTransitionAttributes($sStimulus /*, current state*/);
}
$oObj->UpdateObjectFromPostedForm('' /* form prefix */, $aAttList, $sTargetState);
$oObj->UpdateObjectFromPostedForm('' /* form prefix */, $aAttList, $aExpectedAttributes);
// Optional: apply a stimulus
//
@@ -900,7 +952,7 @@ EOF
$sTransactionId = utils::GetNewTransactionId();
$this->SetTransactionId($sTransactionId);
$this->add("<input type=\"hidden\" id=\"transaction_id\" name=\"transaction_id\" value=\"$sTransactionId\">\n");
$this->add_ready_script("$(window).unload(function() { OnUnload('$sTransactionId') } );\n");
$this->add_ready_script("$(window).on('unload', function() { OnUnload('$sTransactionId') } );\n");
}
public function WizardFormButtons($iButtonFlags)

View File

@@ -1,141 +1,178 @@
<?php
// Copyright (C) 2010-2015 Combodo SARL
//
// This file is part of iTop.
//
// iTop is free software; you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// iTop is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with iTop. If not, see <http://www.gnu.org/licenses/>
/**
* Persistent class Event and derived
* Application internal events
* There is also a file log
*
* @copyright Copyright (C) 2010-2015 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
abstract class Query extends cmdbAbstractObject
{
public static function Init()
{
$aParams = array
(
"category" => "core/cmdb,view_in_gui,application",
"key_type" => "autoincrement",
"name_attcode" => "name",
"state_attcode" => "",
"reconc_keys" => array(),
"db_table" => "priv_query",
"db_key_field" => "id",
"db_finalclass_field" => "realclass",
"display_template" => "",
);
MetaModel::Init_Params($aParams);
//MetaModel::Init_InheritAttributes();
MetaModel::Init_AddAttribute(new AttributeString("name", array("allowed_values"=>null, "sql"=>"name", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeText("description", array("allowed_values"=>null, "sql"=>"description", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeText("fields", array("allowed_values"=>null, "sql"=>"fields", "default_value"=>null, "is_null_allowed"=>true, "depends_on"=>array())));
// Display lists
MetaModel::Init_SetZListItems('details', array('name', 'description', 'fields')); // Attributes to be displayed for the complete details
MetaModel::Init_SetZListItems('list', array('description')); // Attributes to be displayed for a list
// Search criteria
MetaModel::Init_SetZListItems('standard_search', array('name', 'description', 'fields')); // Criteria of the std search form
// MetaModel::Init_SetZListItems('advanced_search', array('name')); // Criteria of the advanced search form
}
}
class QueryOQL extends Query
{
public static function Init()
{
$aParams = array
(
"category" => "core/cmdb,view_in_gui,application",
"key_type" => "autoincrement",
"name_attcode" => "name",
"state_attcode" => "",
"reconc_keys" => array(),
"db_table" => "priv_query_oql",
"db_key_field" => "id",
"db_finalclass_field" => "",
"display_template" => "",
);
MetaModel::Init_Params($aParams);
MetaModel::Init_InheritAttributes();
MetaModel::Init_AddAttribute(new AttributeOQL("oql", array("allowed_values"=>null, "sql"=>"oql", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array())));
// Display lists
MetaModel::Init_SetZListItems('details', array('name', 'description', 'oql', 'fields')); // Attributes to be displayed for the complete details
MetaModel::Init_SetZListItems('list', array('description')); // Attributes to be displayed for a list
// Search criteria
MetaModel::Init_SetZListItems('standard_search', array('name', 'description', 'fields', 'oql')); // Criteria of the std search form
// MetaModel::Init_SetZListItems('advanced_search', array('name')); // Criteria of the advanced search form
}
function DisplayBareProperties(WebPage $oPage, $bEditMode = false, $sPrefix = '', $aExtraParams = array())
{
$aFieldsMap = parent::DisplayBareProperties($oPage, $bEditMode, $sPrefix, $aExtraParams);
if (!$bEditMode)
{
$sFields = trim($this->Get('fields'));
$bExportV1Recommended = ($sFields == '');
if ($bExportV1Recommended)
{
$oFieldAttDef = MetaModel::GetAttributeDef('QueryOQL', 'fields');
$oPage->add('<div class="message message_error" style="padding-left: 30px;"><div style="padding: 10px;">'.Dict::Format('UI:Query:UrlV1', $oFieldAttDef->GetLabel()).'</div></div>');
$sUrl = utils::GetAbsoluteUrlAppRoot().'webservices/export.php?format=spreadsheet&login_mode=basic&query='.$this->GetKey();
}
else
{
$sUrl = utils::GetAbsoluteUrlAppRoot().'webservices/export-v2.php?format=spreadsheet&login_mode=basic&query='.$this->GetKey();
}
$sOql = $this->Get('oql');
$sMessage = null;
try
{
$oSearch = DBObjectSearch::FromOQL($sOql);
$aParameters = $oSearch->GetQueryParams();
foreach($aParameters as $sParam => $val)
{
$sUrl .= '&arg_'.$sParam.'=["'.$sParam.'"]';
}
$oPage->p(Dict::S('UI:Query:UrlForExcel').':<br/><textarea cols="80" rows="3" READONLY>'.$sUrl.'</textarea>');
if (count($aParameters) == 0)
{
$oBlock = new DisplayBlock($oSearch, 'list');
$aExtraParams = array(
//'menu' => $sShowMenu,
'table_id' => 'query_preview_'.$this->getKey(),
);
$sBlockId = 'block_query_preview_'.$this->GetKey(); // make a unique id (edition occuring in the same DOM)
$oBlock->Display($oPage, $sBlockId, $aExtraParams);
}
}
catch (OQLException $e)
{
$sMessage = '<div class="message message_error" style="padding-left: 30px;"><div style="padding: 10px;">'.Dict::Format('UI:RunQuery:Error', $e->getHtmlDesc()).'</div></div>';
$oPage->p($sMessage);
}
}
return $aFieldsMap;
}
}
?>
<?php
// Copyright (C) 2010-2015 Combodo SARL
//
// This file is part of iTop.
//
// iTop is free software; you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// iTop is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with iTop. If not, see <http://www.gnu.org/licenses/>
/**
* Persistent class Event and derived
* Application internal events
* There is also a file log
*
* @copyright Copyright (C) 2010-2015 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
abstract class Query extends cmdbAbstractObject
{
public static function Init()
{
$aParams = array
(
"category" => "core/cmdb,view_in_gui,application,grant_by_profile",
"key_type" => "autoincrement",
"name_attcode" => "name",
"state_attcode" => "",
"reconc_keys" => array(),
"db_table" => "priv_query",
"db_key_field" => "id",
"db_finalclass_field" => "realclass",
"display_template" => "",
);
MetaModel::Init_Params($aParams);
//MetaModel::Init_InheritAttributes();
MetaModel::Init_AddAttribute(new AttributeString("name", array("allowed_values"=>null, "sql"=>"name", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeText("description", array("allowed_values"=>null, "sql"=>"description", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array())));
// Display lists
MetaModel::Init_SetZListItems('details', array('name', 'description')); // Attributes to be displayed for the complete details
MetaModel::Init_SetZListItems('list', array('description')); // Attributes to be displayed for a list
// Search criteria
MetaModel::Init_SetZListItems('standard_search', array('name', 'description')); // Criteria of the std search form
MetaModel::Init_SetZListItems('default_search', array('name', 'description')); // Criteria of the default search form
// MetaModel::Init_SetZListItems('advanced_search', array('name')); // Criteria of the advanced search form
}
}
class QueryOQL extends Query
{
public static function Init()
{
$aParams = array
(
"category" => "core/cmdb,view_in_gui,application,grant_by_profile",
"key_type" => "autoincrement",
"name_attcode" => "name",
"state_attcode" => "",
"reconc_keys" => array(),
"db_table" => "priv_query_oql",
"db_key_field" => "id",
"db_finalclass_field" => "",
"display_template" => "",
);
MetaModel::Init_Params($aParams);
MetaModel::Init_InheritAttributes();
MetaModel::Init_AddAttribute(new AttributeOQL("oql", array("allowed_values"=>null, "sql"=>"oql", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeText("fields", array("allowed_values"=>null, "sql"=>"fields", "default_value"=>null, "is_null_allowed"=>true, "depends_on"=>array())));
// Rolled back to AttributeText until AttributeQueryAttCodeSet can manage fields order correctly
//MetaModel::Init_AddAttribute(new AttributeQueryAttCodeSet("fields", array("allowed_values"=>null,"max_items" => 1000, "query_field" => "oql", "sql"=>"fields", "default_value"=>null, "is_null_allowed"=>true, "depends_on"=>array('oql'))));
// Display lists
MetaModel::Init_SetZListItems('details', array('name', 'description', 'oql', 'fields')); // Attributes to be displayed for the complete details
MetaModel::Init_SetZListItems('list', array('description')); // Attributes to be displayed for a list
// Search criteria
MetaModel::Init_SetZListItems('standard_search', array('name', 'description', 'fields', 'oql')); // Criteria of the std search form
}
function DisplayBareProperties(WebPage $oPage, $bEditMode = false, $sPrefix = '', $aExtraParams = array())
{
$aFieldsMap = parent::DisplayBareProperties($oPage, $bEditMode, $sPrefix, $aExtraParams);
if (!$bEditMode)
{
$sFields = trim($this->Get('fields'));
$bExportV1Recommended = ($sFields == '');
if ($bExportV1Recommended)
{
$oFieldAttDef = MetaModel::GetAttributeDef('QueryOQL', 'fields');
$oPage->add('<div class="message message_error" style="padding-left: 30px;"><div style="padding: 10px;">'.Dict::Format('UI:Query:UrlV1', $oFieldAttDef->GetLabel()).'</div></div>');
$sUrl = utils::GetAbsoluteUrlAppRoot().'webservices/export.php?format=spreadsheet&login_mode=basic&query='.$this->GetKey();
}
else
{
$sUrl = utils::GetAbsoluteUrlAppRoot().'webservices/export-v2.php?format=spreadsheet&login_mode=basic&date_format='.urlencode((string)AttributeDateTime::GetFormat()).'&query='.$this->GetKey();
}
$sOql = $this->Get('oql');
$sMessage = null;
try
{
$oSearch = DBObjectSearch::FromOQL($sOql);
$aParameters = $oSearch->GetQueryParams();
foreach($aParameters as $sParam => $val)
{
$sUrl .= '&arg_'.$sParam.'=["'.$sParam.'"]';
}
$oPage->p(Dict::S('UI:Query:UrlForExcel').':<br/><textarea cols="80" rows="3" READONLY>'.$sUrl.'</textarea>');
if (count($aParameters) == 0)
{
$oBlock = new DisplayBlock($oSearch, 'list');
$aExtraParams = array(
//'menu' => $sShowMenu,
'table_id' => 'query_preview_'.$this->getKey(),
);
$sBlockId = 'block_query_preview_'.$this->GetKey(); // make a unique id (edition occuring in the same DOM)
$oBlock->Display($oPage, $sBlockId, $aExtraParams);
}
}
catch (OQLException $e)
{
$sMessage = '<div class="message message_error" style="padding-left: 30px;"><div style="padding: 10px;">'.Dict::Format('UI:RunQuery:Error', $e->getHtmlDesc()).'</div></div>';
$oPage->p($sMessage);
}
}
return $aFieldsMap;
}
// Rolled back until 'fields' can be properly managed by AttributeQueryAttCodeSet
//
// public function ComputeValues()
// {
// parent::ComputeValues();
//
// // Remove unwanted attribute codes
// $aChanges = $this->ListChanges();
// if (isset($aChanges['fields']))
// {
// $oAttDef = MetaModel::GetAttributeDef(get_class($this), 'fields');
// $aArgs = array('this' => $this);
// $aAllowedValues = $oAttDef->GetAllowedValues($aArgs);
//
// /** @var \ormSet $oValue */
// $oValue = $this->Get('fields');
// $aValues = $oValue->GetValues();
// $bChanged = false;
// foreach($aValues as $key => $sValue)
// {
// if (!isset($aAllowedValues[$sValue]))
// {
// unset($aValues[$key]);
// $bChanged = true;
// }
// }
// if ($bChanged)
// {
// $oValue->SetValues($aValues);
// $this->Set('fields', $oValue);
// }
// }
// }
}
?>

View File

@@ -1,338 +1,338 @@
<?php
// Copyright (C) 2010-2013 Combodo SARL
//
// This file is part of iTop.
//
// iTop is free software; you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// iTop is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with iTop. If not, see <http://www.gnu.org/licenses/>
/**
* Persistent class Shortcut and derived
* Shortcuts of any kind
*
* @copyright Copyright (C) 2010-2012 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
abstract class Shortcut extends DBObject implements iDisplay
{
public static function Init()
{
$aParams = array
(
"category" => "gui,view_in_gui",
"key_type" => "autoincrement",
"name_attcode" => "name",
"state_attcode" => "",
"reconc_keys" => array(),
"db_table" => "priv_shortcut",
"db_key_field" => "id",
"db_finalclass_field" => "realclass",
"display_template" => "",
);
MetaModel::Init_Params($aParams);
//MetaModel::Init_InheritAttributes();
MetaModel::Init_AddAttribute(new AttributeExternalKey("user_id", array("targetclass"=>"User", "allowed_values"=>null, "sql"=>"user_id", "is_null_allowed"=>true, "on_target_delete"=>DEL_AUTO, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeString("name", array("allowed_values"=>null, "sql"=>"name", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeText("context", array("allowed_values"=>null, "sql"=>"context", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array())));
// Display lists
MetaModel::Init_SetZListItems('details', array('name', 'context')); // Attributes to be displayed for the complete details
MetaModel::Init_SetZListItems('list', array('name')); // Attributes to be displayed for a list
// Search criteria
// MetaModel::Init_SetZListItems('standard_search', array('name')); // Criteria of the std search form
// MetaModel::Init_SetZListItems('advanced_search', array('name')); // Criteria of the advanced search form
}
abstract public function RenderContent(WebPage $oPage, $aExtraParams = array());
protected function OnInsert()
{
$this->Set('user_id', UserRights::GetUserId());
}
public function StartRenameDialog($oPage)
{
$oPage->add('<div id="shortcut_rename_dlg">');
$oForm = new DesignerForm();
$sDefault = $this->Get('name');
$oField = new DesignerTextField('name', Dict::S('Class:Shortcut/Attribute:name'), $sDefault);
$oField->SetMandatory(true);
$oForm->AddField($oField);
$oForm->Render($oPage);
$oPage->add('</div>');
$sDialogTitle = Dict::S('UI:ShortcutRenameDlg:Title');
$sOkButtonLabel = Dict::S('UI:Button:Ok');
$sCancelButtonLabel = Dict::S('UI:Button:Cancel');
$iShortcut = $this->GetKey();
$oPage->add_ready_script(
<<<EOF
function ShortcutRenameOK()
{
var oForm = $(this).find('form');
var sFormId = oForm.attr('id');
var oParams = null;
var aErrors = ValidateForm(sFormId, false);
if (aErrors.length == 0)
{
oParams = ReadFormParams(sFormId);
}
oParams.operation = 'shortcut_rename_go';
oParams.id = $iShortcut;
var me = $(this);
$.post(GetAbsoluteUrlAppRoot()+'pages/ajax.render.php', oParams, function(data) {
me.dialog( "close" );
me.remove();
$('body').append(data);
});
}
$('#shortcut_rename_dlg form').bind('submit', function() { return false; });
$('#shortcut_rename_dlg').dialog({
width: 400,
modal: true,
title: '$sDialogTitle',
buttons: [
{ text: "$sOkButtonLabel", click: ShortcutRenameOK},
{ text: "$sCancelButtonLabel", click: function() {
$(this).dialog( "close" ); $(this).remove();
} },
],
close: function() { $(this).remove(); }
});
EOF
);
}
// Minimual implementation of iDisplay: to make the shortcut be listable
//
public static function MapContextParam($sContextParam)
{
return (($sContextParam == 'menu') ? null : $sContextParam);
}
public function GetHilightClass()
{
return HILIGHT_CLASS_NONE;
}
public static function GetUIPage()
{
return '';
}
function DisplayDetails(WebPage $oPage, $bEditMode = false)
{
}
function DisplayBareProperties(WebPage $oPage, $bEditMode = false, $sPrefix = '', $aExtraParams = array())
{
return array();
}
// End of the minimal implementation of iDisplay
}
class ShortcutOQL extends Shortcut
{
public static function Init()
{
$aParams = array
(
"category" => "gui,view_in_gui",
"key_type" => "autoincrement",
"name_attcode" => "name",
"state_attcode" => "",
"reconc_keys" => array(),
"db_table" => "priv_shortcut_oql",
"db_key_field" => "id",
"db_finalclass_field" => "",
"display_template" => "",
);
MetaModel::Init_Params($aParams);
MetaModel::Init_InheritAttributes();
MetaModel::Init_AddAttribute(new AttributeOQL("oql", array("allowed_values"=>null, "sql"=>"oql", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeEnum("auto_reload", array("allowed_values"=>new ValueSetEnum('none,custom'), "sql"=>"auto_reload", "default_value"=>"none", "is_null_allowed"=>false, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeInteger("auto_reload_sec", array("allowed_values"=>null, "sql"=>"auto_reload_sec", "default_value"=>60, "is_null_allowed"=>false, "depends_on"=>array())));
// Display lists
MetaModel::Init_SetZListItems('details', array('name', 'context', 'oql')); // Attributes to be displayed for the complete details
MetaModel::Init_SetZListItems('list', array('name')); // Attributes to be displayed for a list
// Search criteria
// MetaModel::Init_SetZListItems('standard_search', array('name')); // Criteria of the std search form
// MetaModel::Init_SetZListItems('advanced_search', array('name')); // Criteria of the advanced search form
}
public function RenderContent(WebPage $oPage, $aExtraParams = array())
{
$oPage->set_title($this->Get('name'));
switch($this->Get('auto_reload'))
{
case 'custom':
$iRate = (int)$this->Get('auto_reload_sec');
if ($iRate > 0)
{
// Must a string otherwise it can be evaluated to 'true' and defaults to "standard" refresh rate!
$aExtraParams['auto_reload'] = (string)$iRate;
}
break;
default:
case 'none':
}
$bSearchPane = true;
$bSearchOpen = false;
try
{
OQLMenuNode::RenderOQLSearch($this->Get('oql'), $this->Get('name'), 'shortcut_'.$this->GetKey(), $bSearchPane, $bSearchOpen, $oPage, $aExtraParams);
}
catch (Exception $e)
{
throw new Exception("The OQL shortcut '".$this->Get('name')."' (id: ".$this->GetKey().") could not be displayed: ".$e->getMessage());
}
}
public function CloneTableSettings($sTableSettings)
{
$aTableSettings = json_decode($sTableSettings, true);
$oFilter = DBObjectSearch::FromOQL($this->Get('oql'));
$oCustomSettings = new DataTableSettings($oFilter->GetSelectedClasses());
$oCustomSettings->iDefaultPageSize = $aTableSettings['iPageSize'];
$oCustomSettings->aColumns = $aTableSettings['oColumns'];
$oCustomSettings->Save('shortcut_'.$this->GetKey());
}
public static function GetCreationForm($sOQL = null, $sTableSettings = null)
{
$oForm = new DesignerForm();
// Find a unique default name
// -> The class of the query + an index if necessary
if ($sOQL == null)
{
$sDefault = '';
}
else
{
$oBMSearch = new DBObjectSearch('Shortcut');
$oBMSearch->AddCondition('user_id', UserRights::GetUserId(), '=');
$oBMSet = new DBObjectSet($oBMSearch);
$aNames = $oBMSet->GetColumnAsArray('name');
$oSearch = DBObjectSearch::FromOQL($sOQL);
$sDefault = utils::MakeUniqueName($oSearch->GetClass(), $aNames);
}
$oField = new DesignerTextField('name', Dict::S('Class:Shortcut/Attribute:name'), $sDefault);
$oField->SetMandatory(true);
$oForm->AddField($oField);
/*
$oField = new DesignerComboField('auto_reload', Dict::S('Class:ShortcutOQL/Attribute:auto_reload'), 'none');
$oAttDef = MetaModel::GetAttributeDef(__class__, 'auto_reload');
$oField->SetAllowedValues($oAttDef->GetAllowedValues());
$oField->SetMandatory(true);
$oForm->AddField($oField);
*/
$oField = new DesignerBooleanField('auto_reload', Dict::S('Class:ShortcutOQL/Attribute:auto_reload'), false);
$oForm->AddField($oField);
$oField = new DesignerIntegerField('auto_reload_sec', Dict::S('Class:ShortcutOQL/Attribute:auto_reload_sec'), MetaModel::GetConfig()->GetStandardReloadInterval());
$oField->SetBoundaries(MetaModel::GetConfig()->Get('min_reload_interval'), null); // no upper limit
$oField->SetMandatory(false);
$oForm->AddField($oField);
$oField = new DesignerHiddenField('oql', '', $sOQL);
$oForm->AddField($oField);
$oField = new DesignerHiddenField('table_settings', '', $sTableSettings);
$oForm->AddField($oField);
return $oForm;
}
public static function GetCreationDlgFromOQL($oPage, $sOQL, $sTableSettings)
{
$oPage->add('<div id="shortcut_creation_dlg">');
$oForm = self::GetCreationForm($sOQL, $sTableSettings);
$oForm->Render($oPage);
$oPage->add('</div>');
$sDialogTitle = Dict::S('UI:ShortcutListDlg:Title');
$sOkButtonLabel = Dict::S('UI:Button:Ok');
$sCancelButtonLabel = Dict::S('UI:Button:Cancel');
$oAppContext = new ApplicationContext();
$sContext = $oAppContext->GetForLink();
$sRateTitle = addslashes(Dict::Format('Class:ShortcutOQL/Attribute:auto_reload_sec/tip', MetaModel::GetConfig()->Get('min_reload_interval')));
$oPage->add_ready_script(
<<<EOF
// Note: the title gets deleted by the validation mechanism
$("#attr_auto_reload_sec").tooltip({items: 'input', content: '$sRateTitle'});
$("#attr_auto_reload_sec").prop('disabled', !$('#attr_auto_reload').is(':checked'));
$('#attr_auto_reload').change( function(ev) {
$("#attr_auto_reload_sec").prop('disabled', !$(this).is(':checked'));
} );
function ShortcutCreationOK()
{
var oForm = $('#shortcut_creation_dlg form');
var sFormId = oForm.attr('id');
var oParams = null;
var aErrors = ValidateForm(sFormId, false);
if (aErrors.length == 0)
{
oParams = ReadFormParams(sFormId);
}
oParams.operation = 'shortcut_list_create';
var me = $('#shortcut_creation_dlg');
$.post(GetAbsoluteUrlAppRoot()+'pages/ajax.render.php?$sContext', oParams, function(data) {
me.dialog( "close" );
me.remove();
$('body').append(data);
});
}
$('#shortcut_creation_dlg form').bind('submit', function() { ShortcutCreationOK(); return false; });
$('#shortcut_creation_dlg').dialog({
width: 400,
modal: true,
title: '$sDialogTitle',
buttons: [
{ text: "$sOkButtonLabel", click: ShortcutCreationOK },
{ text: "$sCancelButtonLabel", click: function() {
$(this).dialog( "close" ); $(this).remove();
} },
],
close: function() { $(this).remove(); }
});
EOF
);
}
}
?>
<?php
// Copyright (C) 2010-2016 Combodo SARL
//
// This file is part of iTop.
//
// iTop is free software; you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// iTop is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with iTop. If not, see <http://www.gnu.org/licenses/>
/**
* Persistent class Shortcut and derived
* Shortcuts of any kind
*
* @copyright Copyright (C) 2010-2016 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
abstract class Shortcut extends DBObject implements iDisplay
{
public static function Init()
{
$aParams = array
(
"category" => "gui,view_in_gui",
"key_type" => "autoincrement",
"name_attcode" => "name",
"state_attcode" => "",
"reconc_keys" => array(),
"db_table" => "priv_shortcut",
"db_key_field" => "id",
"db_finalclass_field" => "realclass",
"display_template" => "",
);
MetaModel::Init_Params($aParams);
//MetaModel::Init_InheritAttributes();
MetaModel::Init_AddAttribute(new AttributeExternalKey("user_id", array("targetclass"=>"User", "allowed_values"=>null, "sql"=>"user_id", "is_null_allowed"=>true, "on_target_delete"=>DEL_AUTO, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeString("name", array("allowed_values"=>null, "sql"=>"name", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeText("context", array("allowed_values"=>null, "sql"=>"context", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array())));
// Display lists
MetaModel::Init_SetZListItems('details', array('name', 'context')); // Attributes to be displayed for the complete details
MetaModel::Init_SetZListItems('list', array('name')); // Attributes to be displayed for a list
// Search criteria
// MetaModel::Init_SetZListItems('standard_search', array('name')); // Criteria of the std search form
// MetaModel::Init_SetZListItems('advanced_search', array('name')); // Criteria of the advanced search form
}
abstract public function RenderContent(WebPage $oPage, $aExtraParams = array());
protected function OnInsert()
{
$this->Set('user_id', UserRights::GetUserId());
}
public function StartRenameDialog($oPage)
{
$oPage->add('<div id="shortcut_rename_dlg">');
$oForm = new DesignerForm();
$sDefault = $this->Get('name');
$oField = new DesignerTextField('name', Dict::S('Class:Shortcut/Attribute:name'), $sDefault);
$oField->SetMandatory(true);
$oForm->AddField($oField);
$oForm->Render($oPage);
$oPage->add('</div>');
$sDialogTitle = Dict::S('UI:ShortcutRenameDlg:Title');
$sOkButtonLabel = Dict::S('UI:Button:Ok');
$sCancelButtonLabel = Dict::S('UI:Button:Cancel');
$iShortcut = $this->GetKey();
$oPage->add_ready_script(
<<<EOF
function ShortcutRenameOK()
{
var oForm = $(this).find('form');
var sFormId = oForm.attr('id');
var oParams = null;
var aErrors = ValidateForm(sFormId, false);
if (aErrors.length == 0)
{
oParams = ReadFormParams(sFormId);
}
oParams.operation = 'shortcut_rename_go';
oParams.id = $iShortcut;
var me = $(this);
$.post(GetAbsoluteUrlAppRoot()+'pages/ajax.render.php', oParams, function(data) {
me.dialog( "close" );
me.remove();
$('body').append(data);
});
}
$('#shortcut_rename_dlg form').bind('submit', function() { return false; });
$('#shortcut_rename_dlg').dialog({
width: 400,
modal: true,
title: '$sDialogTitle',
buttons: [
{ text: "$sOkButtonLabel", click: ShortcutRenameOK},
{ text: "$sCancelButtonLabel", click: function() {
$(this).dialog( "close" ); $(this).remove();
} },
],
close: function() { $(this).remove(); }
});
EOF
);
}
// Minimual implementation of iDisplay: to make the shortcut be listable
//
public static function MapContextParam($sContextParam)
{
return (($sContextParam == 'menu') ? null : $sContextParam);
}
public function GetHilightClass()
{
return HILIGHT_CLASS_NONE;
}
public static function GetUIPage()
{
return '';
}
function DisplayDetails(WebPage $oPage, $bEditMode = false)
{
}
function DisplayBareProperties(WebPage $oPage, $bEditMode = false, $sPrefix = '', $aExtraParams = array())
{
return array();
}
// End of the minimal implementation of iDisplay
}
class ShortcutOQL extends Shortcut
{
public static function Init()
{
$aParams = array
(
"category" => "gui,view_in_gui",
"key_type" => "autoincrement",
"name_attcode" => "name",
"state_attcode" => "",
"reconc_keys" => array(),
"db_table" => "priv_shortcut_oql",
"db_key_field" => "id",
"db_finalclass_field" => "",
"display_template" => "",
);
MetaModel::Init_Params($aParams);
MetaModel::Init_InheritAttributes();
MetaModel::Init_AddAttribute(new AttributeOQL("oql", array("allowed_values"=>null, "sql"=>"oql", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeEnum("auto_reload", array("allowed_values"=>new ValueSetEnum('none,custom'), "sql"=>"auto_reload", "default_value"=>"none", "is_null_allowed"=>false, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeInteger("auto_reload_sec", array("allowed_values"=>null, "sql"=>"auto_reload_sec", "default_value"=>60, "is_null_allowed"=>false, "depends_on"=>array())));
// Display lists
MetaModel::Init_SetZListItems('details', array('name', 'context', 'oql')); // Attributes to be displayed for the complete details
MetaModel::Init_SetZListItems('list', array('name')); // Attributes to be displayed for a list
// Search criteria
// MetaModel::Init_SetZListItems('standard_search', array('name')); // Criteria of the std search form
// MetaModel::Init_SetZListItems('advanced_search', array('name')); // Criteria of the advanced search form
}
public function RenderContent(WebPage $oPage, $aExtraParams = array())
{
$oPage->set_title($this->Get('name'));
switch($this->Get('auto_reload'))
{
case 'custom':
$iRate = (int)$this->Get('auto_reload_sec');
if ($iRate > 0)
{
// Must a string otherwise it can be evaluated to 'true' and defaults to "standard" refresh rate!
$aExtraParams['auto_reload'] = (string)$iRate;
}
break;
default:
case 'none':
}
$bSearchPane = true;
$bSearchOpen = true;
try
{
OQLMenuNode::RenderOQLSearch($this->Get('oql'), $this->Get('name'), 'shortcut_'.$this->GetKey(), $bSearchPane, $bSearchOpen, $oPage, $aExtraParams, true);
}
catch (Exception $e)
{
throw new Exception("The OQL shortcut '".$this->Get('name')."' (id: ".$this->GetKey().") could not be displayed: ".$e->getMessage());
}
}
public function CloneTableSettings($sTableSettings)
{
$aTableSettings = json_decode($sTableSettings, true);
$oFilter = DBObjectSearch::FromOQL($this->Get('oql'));
$oCustomSettings = new DataTableSettings($oFilter->GetSelectedClasses());
$oCustomSettings->iDefaultPageSize = $aTableSettings['iPageSize'];
$oCustomSettings->aColumns = $aTableSettings['oColumns'];
$oCustomSettings->Save('shortcut_'.$this->GetKey());
}
public static function GetCreationForm($sOQL = null, $sTableSettings = null)
{
$oForm = new DesignerForm();
// Find a unique default name
// -> The class of the query + an index if necessary
if ($sOQL == null)
{
$sDefault = '';
}
else
{
$oBMSearch = new DBObjectSearch('Shortcut');
$oBMSearch->AddCondition('user_id', UserRights::GetUserId(), '=');
$oBMSet = new DBObjectSet($oBMSearch);
$aNames = $oBMSet->GetColumnAsArray('name');
$oSearch = DBObjectSearch::FromOQL($sOQL);
$sDefault = utils::MakeUniqueName($oSearch->GetClass(), $aNames);
}
$oField = new DesignerTextField('name', Dict::S('Class:Shortcut/Attribute:name'), $sDefault);
$oField->SetMandatory(true);
$oForm->AddField($oField);
/*
$oField = new DesignerComboField('auto_reload', Dict::S('Class:ShortcutOQL/Attribute:auto_reload'), 'none');
$oAttDef = MetaModel::GetAttributeDef(__class__, 'auto_reload');
$oField->SetAllowedValues($oAttDef->GetAllowedValues());
$oField->SetMandatory(true);
$oForm->AddField($oField);
*/
$oField = new DesignerBooleanField('auto_reload', Dict::S('Class:ShortcutOQL/Attribute:auto_reload'), false);
$oForm->AddField($oField);
$oField = new DesignerIntegerField('auto_reload_sec', Dict::S('Class:ShortcutOQL/Attribute:auto_reload_sec'), MetaModel::GetConfig()->GetStandardReloadInterval());
$oField->SetBoundaries(MetaModel::GetConfig()->Get('min_reload_interval'), null); // no upper limit
$oField->SetMandatory(false);
$oForm->AddField($oField);
$oField = new DesignerHiddenField('oql', '', $sOQL);
$oForm->AddField($oField);
$oField = new DesignerHiddenField('table_settings', '', $sTableSettings);
$oForm->AddField($oField);
return $oForm;
}
public static function GetCreationDlgFromOQL($oPage, $sOQL, $sTableSettings)
{
$oPage->add('<div id="shortcut_creation_dlg">');
$oForm = self::GetCreationForm($sOQL, $sTableSettings);
$oForm->Render($oPage);
$oPage->add('</div>');
$sDialogTitle = Dict::S('UI:ShortcutListDlg:Title');
$sOkButtonLabel = Dict::S('UI:Button:Ok');
$sCancelButtonLabel = Dict::S('UI:Button:Cancel');
$oAppContext = new ApplicationContext();
$sContext = $oAppContext->GetForLink();
$sRateTitle = addslashes(Dict::Format('Class:ShortcutOQL/Attribute:auto_reload_sec/tip', MetaModel::GetConfig()->Get('min_reload_interval')));
$oPage->add_ready_script(
<<<EOF
// Note: the title gets deleted by the validation mechanism
$("#attr_auto_reload_sec").tooltip({items: 'input', content: '$sRateTitle'});
$("#attr_auto_reload_sec").prop('disabled', !$('#attr_auto_reload').is(':checked'));
$('#attr_auto_reload').change( function(ev) {
$("#attr_auto_reload_sec").prop('disabled', !$(this).is(':checked'));
} );
function ShortcutCreationOK()
{
var oForm = $('#shortcut_creation_dlg form');
var sFormId = oForm.attr('id');
var oParams = null;
var aErrors = ValidateForm(sFormId, false);
if (aErrors.length == 0)
{
oParams = ReadFormParams(sFormId);
}
oParams.operation = 'shortcut_list_create';
var me = $('#shortcut_creation_dlg');
$.post(GetAbsoluteUrlAppRoot()+'pages/ajax.render.php?$sContext', oParams, function(data) {
me.dialog( "close" );
me.remove();
$('body').append(data);
});
}
$('#shortcut_creation_dlg form').bind('submit', function() { ShortcutCreationOK(); return false; });
$('#shortcut_creation_dlg').dialog({
width: 400,
modal: true,
title: '$sDialogTitle',
buttons: [
{ text: "$sOkButtonLabel", click: ShortcutCreationOK },
{ text: "$sCancelButtonLabel", click: function() {
$(this).dialog( "close" ); $(this).remove();
} },
],
close: function() { $(this).remove(); }
});
EOF
);
}
}
?>

View File

@@ -1,531 +0,0 @@
<?php
// Copyright (C) 2010-2012 Combodo SARL
//
// This file is part of iTop.
//
// iTop is free software; you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// iTop is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with iTop. If not, see <http://www.gnu.org/licenses/>
/**
* SqlBlock - display tables or charts, given an SQL query - use cautiously!
*
*
* @copyright Copyright (C) 2010-2012 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
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

@@ -1,49 +1,82 @@
<?php
// Copyright (C) 2010-2012 Combodo SARL
//
// This file is part of iTop.
//
// iTop is free software; you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// iTop is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with iTop. If not, see <http://www.gnu.org/licenses/>
/**
* File to include to initialize the datamodel in memory
*
* @copyright Copyright (C) 2010-2012 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
require_once(APPROOT.'/core/cmdbobject.class.inc.php');
require_once(APPROOT.'/application/utils.inc.php');
session_name('itop-'.md5(APPROOT));
session_start();
if (isset($_REQUEST['switch_env']))
{
$sEnv = $_REQUEST['switch_env'];
$_SESSION['itop_env'] = $sEnv;
// TODO: reset the credentials as well ??
}
else if (isset($_SESSION['itop_env']))
{
$sEnv = $_SESSION['itop_env'];
}
else
{
$sEnv = ITOP_DEFAULT_ENV;
$_SESSION['itop_env'] = ITOP_DEFAULT_ENV;
}
$sConfigFile = APPCONF.$sEnv.'/'.ITOP_CONFIG_FILE;
MetaModel::Startup($sConfigFile);
?>
<?php
// Copyright (C) 2010-2016 Combodo SARL
//
// This file is part of iTop.
//
// iTop is free software; you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// iTop is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with iTop. If not, see <http://www.gnu.org/licenses/>
/**
* File to include to initialize the datamodel in memory
*
* @copyright Copyright (C) 2010-2016 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
// This storage is freed on error (case of allowed memory exhausted)
$sReservedMemory = str_repeat('*', 1024 * 1024);
register_shutdown_function(function()
{
global $sReservedMemory;
$sReservedMemory = null;
if (!is_null($err = error_get_last()) && ($err['type'] == E_ERROR))
{
if (strpos($err['message'], 'Allowed memory size of') !== false)
{
$sLimit = ini_get('memory_limit');
echo "<p>iTop: Allowed memory size of $sLimit exhausted, contact your administrator to increase memory_limit in php.ini</p>\n";
}
else
{
echo "<p>iTop: An error occurred, check server error log for more information.</p>\n";
}
}
});
require_once(APPROOT.'/core/cmdbobject.class.inc.php');
require_once(APPROOT.'/application/utils.inc.php');
require_once(APPROOT.'/core/contexttag.class.inc.php');
session_name('itop-'.md5(APPROOT));
session_start();
$sSwitchEnv = utils::ReadParam('switch_env', null);
$bAllowCache = true;
if (($sSwitchEnv != null) && (file_exists(APPCONF.$sSwitchEnv.'/'.ITOP_CONFIG_FILE)) && isset($_SESSION['itop_env']) && ($_SESSION['itop_env'] !== $sSwitchEnv))
{
$_SESSION['itop_env'] = $sSwitchEnv;
$sEnv = $sSwitchEnv;
$bAllowCache = false;
// Reset the opcache since otherwise the PHP "model" files may still be cached !!
if (function_exists('opcache_reset'))
{
// Zend opcode cache
opcache_reset();
}
if (function_exists('apc_clear_cache'))
{
// APC(u) cache
apc_clear_cache();
}
// TODO: reset the credentials as well ??
}
else if (isset($_SESSION['itop_env']))
{
$sEnv = $_SESSION['itop_env'];
}
else
{
$sEnv = ITOP_DEFAULT_ENV;
$_SESSION['itop_env'] = ITOP_DEFAULT_ENV;
}
$sConfigFile = APPCONF.$sEnv.'/'.ITOP_CONFIG_FILE;
MetaModel::Startup($sConfigFile, false /* $bModelOnly */, $bAllowCache, false /* $bTraceSourceFiles */, $sEnv);

View File

@@ -1,423 +1,427 @@
<?php
// Copyright (C) 2010-2012 Combodo SARL
//
// This file is part of iTop.
//
// iTop is free software; you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// iTop is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with iTop. If not, see <http://www.gnu.org/licenses/>
/**
* Class DisplayTemplate
*
* @copyright Copyright (C) 2010-2012 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
require_once(APPROOT.'/application/displayblock.class.inc.php');
/**
* This class manages the special template format used internally to build the iTop web pages
*/
class DisplayTemplate
{
protected $m_sTemplate;
protected $m_aTags;
static protected $iBlockCount = 0;
public function __construct($sTemplate)
{
$this->m_aTags = array (
'itopblock',
'itopcheck',
'itoptabs',
'itoptab',
'itoptoggle',
'itopstring',
'sqlblock'
);
$this->m_sTemplate = $sTemplate;
}
public function Render(WebPage $oPage, $aParams = array())
{
$this->m_sTemplate = MetaModel::ApplyParams($this->m_sTemplate, $aParams);
$iStart = 0;
$iEnd = strlen($this->m_sTemplate);
$iCount = 0;
$iBeforeTagPos = $iStart;
$iAfterTagPos = $iStart;
while($sTag = $this->GetNextTag($iStart, $iEnd))
{
$sContent = $this->GetTagContent($sTag, $iStart, $iEnd);
$iAfterTagPos = $iEnd + strlen('</'.$sTag.'>');
$sOuterTag = substr($this->m_sTemplate, $iStart, $iAfterTagPos - $iStart);
$oPage->add(substr($this->m_sTemplate, $iBeforeTagPos, $iStart - $iBeforeTagPos));
if ($sTag == DisplayBlock::TAG_BLOCK)
{
try
{
$oBlock = DisplayBlock::FromTemplate($sOuterTag);
if (is_object($oBlock))
{
$oBlock->Display($oPage, 'block_'.self::$iBlockCount, $aParams);
}
}
catch(OQLException $e)
{
$oPage->p('Error in template (please contact your administrator) - Invalid query<!--'.$sOuterTag.'-->');
}
catch(Exception $e)
{
$oPage->p('Error in template (please contact your administrator)<!--'.$e->getMessage().'--><!--'.$sOuterTag.'-->');
}
self::$iBlockCount++;
}
else
{
$aAttributes = $this->GetTagAttributes($sTag, $iStart, $iEnd);
//$oPage->p("Tag: $sTag - ($iStart, $iEnd)");
$this->RenderTag($oPage, $sTag, $aAttributes, $sContent);
}
$iAfterTagPos = $iEnd + strlen('</'.$sTag.'>');
$iBeforeTagPos = $iAfterTagPos;
$iStart = $iEnd;
$iEnd = strlen($this->m_sTemplate);
$iCount++;
}
$oPage->add(substr($this->m_sTemplate, $iAfterTagPos));
}
public function GetNextTag(&$iStartPos, &$iEndPos)
{
$iChunkStartPos = $iStartPos;
$sNextTag = null;
$iStartPos = $iEndPos;
foreach($this->m_aTags as $sTag)
{
// Search for the opening tag
$iOpeningPos = stripos($this->m_sTemplate, '<'.$sTag.' ', $iChunkStartPos);
if ($iOpeningPos === false)
{
$iOpeningPos = stripos($this->m_sTemplate, '<'.$sTag.'>', $iChunkStartPos);
}
if ($iOpeningPos !== false)
{
$iClosingPos = stripos($this->m_sTemplate, '</'.$sTag.'>', $iOpeningPos);
}
if ( ($iOpeningPos !== false) && ($iClosingPos !== false))
{
if ($iOpeningPos < $iStartPos)
{
// This is the next tag
$iStartPos = $iOpeningPos;
$iEndPos = $iClosingPos;
$sNextTag = $sTag;
}
}
}
return $sNextTag;
}
public function GetTagContent($sTag, $iStartPos, $iEndPos)
{
$sContent = "";
$iContentStart = strpos($this->m_sTemplate, '>', $iStartPos); // Content of tag start immediatly after the first closing bracket
if ($iContentStart !== false)
{
$sContent = substr($this->m_sTemplate, 1+$iContentStart, $iEndPos - $iContentStart - 1);
}
return $sContent;
}
public function GetTagAttributes($sTag, $iStartPos, $iEndPos)
{
$aAttr = array();
$iAttrStart = strpos($this->m_sTemplate, ' ', $iStartPos); // Attributes start just after the first space
$iAttrEnd = strpos($this->m_sTemplate, '>', $iStartPos); // Attributes end just before the first closing bracket
if ( ($iAttrStart !== false) && ($iAttrEnd !== false) && ($iAttrEnd > $iAttrStart))
{
$sAttributes = substr($this->m_sTemplate, 1+$iAttrStart, $iAttrEnd - $iAttrStart - 1);
$aAttributes = explode(' ', $sAttributes);
foreach($aAttributes as $sAttr)
{
if ( preg_match('/(.+) *= *"(.+)"$/', $sAttr, $aMatches) )
{
$aAttr[strtolower($aMatches[1])] = $aMatches[2];
}
}
}
return $aAttr;
}
protected function RenderTag($oPage, $sTag, $aAttributes, $sContent)
{
static $iTabContainerCount = 0;
switch($sTag)
{
case 'itoptabs':
$oPage->AddTabContainer('Tabs_'.$iTabContainerCount);
$oPage->SetCurrentTabContainer('Tabs_'.$iTabContainerCount);
$iTabContainerCount++;
//$oPage->p('Content:<pre>'.htmlentities($sContent, ENT_QUOTES, 'UTF-8').'</pre>');
$oTemplate = new DisplayTemplate($sContent);
$oTemplate->Render($oPage, array()); // no params to apply, they have already been applied
$oPage->SetCurrentTabContainer('');
break;
case 'itopcheck':
$sClassName = $aAttributes['class'];
if (MetaModel::IsValidClass($sClassName) && UserRights::IsActionAllowed($sClassName, UR_ACTION_READ))
{
$oTemplate = new DisplayTemplate($sContent);
$oTemplate->Render($oPage, array()); // no params to apply, they have already been applied
}
else
{
// Leave a trace for those who'd like to understand why nothing is displayed
$oPage->add("<!-- class $sClassName does not exist, skipping some part of the template -->\n");
}
break;
case 'itoptab':
$oPage->SetCurrentTab(Dict::S(str_replace('_', ' ', $aAttributes['name'])));
$oTemplate = new DisplayTemplate($sContent);
$oTemplate->Render($oPage, array()); // no params to apply, they have already been applied
//$oPage->p('iTop Tab Content:<pre>'.htmlentities($sContent, ENT_QUOTES, 'UTF-8').'</pre>');
$oPage->SetCurrentTab('');
break;
case 'itoptoggle':
$sName = isset($aAttributes['name']) ? $aAttributes['name'] : 'Tagada';
$bOpen = isset($aAttributes['open']) ? $aAttributes['open'] : true;
$oPage->StartCollapsibleSection(Dict::S($sName), $bOpen);
$oTemplate = new DisplayTemplate($sContent);
$oTemplate->Render($oPage, array()); // no params to apply, they have already been applied
//$oPage->p('iTop Tab Content:<pre>'.htmlentities($sContent, ENT_QUOTES, 'UTF-8').'</pre>');
$oPage->EndCollapsibleSection();
break;
case 'itopstring':
$oPage->add(Dict::S($sContent));
break;
case 'sqlblock':
$oBlock = SqlBlock::FromTemplate($sContent);
$oBlock->RenderContent($oPage);
break;
case 'itopblock': // No longer used, handled by DisplayBlock::FromTemplate see above
$oPage->add("<!-- Application Error: should be handled by DisplayBlock::FromTemplate -->");
break;
default:
// Unknown tag, just ignore it or now -- output an HTML comment
$oPage->add("<!-- unsupported tag: $sTag -->");
}
}
/**
* Unit test
*/
static public function UnitTest()
{
require_once(APPROOT.'/application/startup.inc.php');
require_once(APPROOT."/application/itopwebpage.class.inc.php");
$sTemplate = '<div class="page_header">
<div class="actions_details"><a href="#"><span>Actions</span></a></div>
<h1>$class$: <span class="hilite">$name$</span></h1>
<itopblock blockclass="HistoryBlock" type="toggle" encoding="text/oql">SELECT CMDBChangeOp WHERE objkey = $id$ AND objclass = \'$class$\'</itopblock>
</div>
<img src="../../images/connect_to_network.png" style="margin-top:-10px; margin-right:10px; float:right">
<itoptabs>
<itoptab name="Interfaces">
<itopblock blockclass="DisplayBlock" type="list" encoding="text/oql">SELECT Interface AS i WHERE i.device_id = $id$</itopblock>
</itoptab>
<itoptab name="Contacts">
<itopblock blockclass="DisplayBlock" type="list" encoding="text/oql">SELECT Contact AS c JOIN lnkContactToCI AS l ON l.contact_id = c.id WHERE l.ci_id = $id$</itopblock>
</itoptab>
<itoptab name="Documents">
<itopblock blockclass="DisplayBlock" type="list" encoding="text/oql">SELECT Document AS d JOIN lnkDocumentToCI as l ON l.document_id = d.id WHERE l.ci_id = $id$)</itopblock>
</itoptab>
</itoptabs>';
$oPage = new iTopWebPage('Unit Test');
//$oPage->add("Template content: <pre>".htmlentities($sTemplate, ENT_QUOTES, 'UTF-8')."</pre>\n");
$oTemplate = new DisplayTemplate($sTemplate);
$oTemplate->Render($oPage, array('class'=>'Network device','pkey'=> 271, 'name' => 'deliversw01.mecanorama.fr', 'org_id' => 3));
$oPage->output();
}
}
/**
* Special type of template for displaying the details of an object
* On top of the defaut 'blocks' managed by the parent class, the following placeholders
* are available in such a template:
* $attribute_code$ An attribute of the object (in edit mode this is the input for the attribute)
* $attribute_code->label()$ The label of an attribute
* $PlugIn:plugInClass->properties()$ The ouput of OnDisplayProperties of the specified plugInClass
*/
class ObjectDetailsTemplate extends DisplayTemplate
{
public function __construct($sTemplate, $oObj, $sFormPrefix = '')
{
parent::__construct($sTemplate);
$this->m_oObj = $oObj;
$this->m_sPrefix = $sFormPrefix;
}
public function Render(WebPage $oPage, $aParams = array(), $bEditMode = false)
{
$sStateAttCode = MetaModel :: GetStateAttributeCode(get_class($this->m_oObj));
$aTemplateFields = array();
preg_match_all('/\\$this->([a-z0-9_]+)\\$/', $this->m_sTemplate, $aMatches);
foreach ($aMatches[1] as $sAttCode)
{
if (MetaModel::IsValidAttCode(get_class($this->m_oObj), $sAttCode))
{
$aTemplateFields[] = $sAttCode;
}
else
{
$aParams['this->'.$sAttCode] = "<!--Unknown attribute: $sAttCode-->";
}
}
preg_match_all('/\\$this->field\\(([a-z0-9_]+)\\)\\$/', $this->m_sTemplate, $aMatches);
foreach ($aMatches[1] as $sAttCode)
{
if (MetaModel::IsValidAttCode(get_class($this->m_oObj), $sAttCode))
{
$aTemplateFields[] = $sAttCode;
}
else
{
$aParams['this->field('.$sAttCode.')'] = "<!--Unknown attribute: $sAttCode-->";
}
}
$aFieldsComments = (isset($aParams['fieldsComments'])) ? $aParams['fieldsComments'] : array();
$aFieldsMap = array();
$sClass = get_class($this->m_oObj);
// Renders the fields used in the template
foreach(MetaModel::ListAttributeDefs(get_class($this->m_oObj)) as $sAttCode => $oAttDef)
{
$aParams['this->label('.$sAttCode.')'] = $oAttDef->GetLabel();
$aParams['this->comments('.$sAttCode.')'] = isset($aFieldsComments[$sAttCode]) ? $aFieldsComments[$sAttCode] : '';
$iInputId = '2_'.$sAttCode; // TODO: generate a real/unique prefix...
if (in_array($sAttCode, $aTemplateFields))
{
if ($this->m_oObj->IsNew())
{
$iFlags = $this->m_oObj->GetInitialStateAttributeFlags($sAttCode);
}
else
{
$iFlags = $this->m_oObj->GetAttributeFlags($sAttCode);
}
if (($iFlags & OPT_ATT_MANDATORY) && $this->m_oObj->IsNew())
{
$iFlags = $iFlags & ~OPT_ATT_READONLY; // Mandatory fields cannot be read-only when creating an object
}
if ((!$oAttDef->IsWritable()) || ($sStateAttCode == $sAttCode))
{
$iFlags = $iFlags | OPT_ATT_READONLY;
}
if ($iFlags & OPT_ATT_HIDDEN)
{
$aParams['this->label('.$sAttCode.')'] = '';
$aParams['this->field('.$sAttCode.')'] = '';
$aParams['this->comments('.$sAttCode.')'] = '';
$aParams['this->'.$sAttCode] = '';
}
else
{
if ($bEditMode && ($iFlags & (OPT_ATT_READONLY|OPT_ATT_SLAVE)))
{
// Check if the attribute is not read-only because of a synchro...
$aReasons = array();
$sSynchroIcon = '';
if ($iFlags & OPT_ATT_SLAVE)
{
$iSynchroFlags = $this->m_oObj->GetSynchroReplicaFlags($sAttCode, $aReasons);
$sSynchroIcon = "&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();
?>
<?php
// Copyright (C) 2010-2017 Combodo SARL
//
// This file is part of iTop.
//
// iTop is free software; you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// iTop is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with iTop. If not, see <http://www.gnu.org/licenses/>
/**
* Class DisplayTemplate
*
* @copyright Copyright (C) 2010-2017 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
require_once(APPROOT.'/application/displayblock.class.inc.php');
/**
* This class manages the special template format used internally to build the iTop web pages
*/
class DisplayTemplate
{
protected $m_sTemplate;
protected $m_aTags;
static protected $iBlockCount = 0;
public function __construct($sTemplate)
{
$this->m_aTags = array (
'itopblock',
'itopcheck',
'itoptabs',
'itoptab',
'itoptoggle',
'itopstring',
'sqlblock'
);
$this->m_sTemplate = $sTemplate;
}
public function Render(WebPage $oPage, $aParams = array())
{
$this->m_sTemplate = MetaModel::ApplyParams($this->m_sTemplate, $aParams);
$iStart = 0;
$iEnd = strlen($this->m_sTemplate);
$iCount = 0;
$iBeforeTagPos = $iStart;
$iAfterTagPos = $iStart;
while($sTag = $this->GetNextTag($iStart, $iEnd))
{
$sContent = $this->GetTagContent($sTag, $iStart, $iEnd);
$iAfterTagPos = $iEnd + strlen('</'.$sTag.'>');
$sOuterTag = substr($this->m_sTemplate, $iStart, $iAfterTagPos - $iStart);
$oPage->add(substr($this->m_sTemplate, $iBeforeTagPos, $iStart - $iBeforeTagPos));
if ($sTag == DisplayBlock::TAG_BLOCK)
{
try
{
$oBlock = DisplayBlock::FromTemplate($sOuterTag);
if (is_object($oBlock))
{
$oBlock->Display($oPage, 'block_'.self::$iBlockCount, $aParams);
}
}
catch(OQLException $e)
{
$oPage->p('Error in template (please contact your administrator) - Invalid query<!--'.$sOuterTag.'-->');
}
catch(Exception $e)
{
$oPage->p('Error in template (please contact your administrator)<!--'.$e->getMessage().'--><!--'.$sOuterTag.'-->');
}
self::$iBlockCount++;
}
else
{
$aAttributes = $this->GetTagAttributes($sTag, $iStart, $iEnd);
//$oPage->p("Tag: $sTag - ($iStart, $iEnd)");
$this->RenderTag($oPage, $sTag, $aAttributes, $sContent);
}
$iAfterTagPos = $iEnd + strlen('</'.$sTag.'>');
$iBeforeTagPos = $iAfterTagPos;
$iStart = $iEnd;
$iEnd = strlen($this->m_sTemplate);
$iCount++;
}
$oPage->add(substr($this->m_sTemplate, $iAfterTagPos));
}
public function GetNextTag(&$iStartPos, &$iEndPos)
{
$iChunkStartPos = $iStartPos;
$sNextTag = null;
$iStartPos = $iEndPos;
foreach($this->m_aTags as $sTag)
{
// Search for the opening tag
$iOpeningPos = stripos($this->m_sTemplate, '<'.$sTag.' ', $iChunkStartPos);
if ($iOpeningPos === false)
{
$iOpeningPos = stripos($this->m_sTemplate, '<'.$sTag.'>', $iChunkStartPos);
}
if ($iOpeningPos !== false)
{
$iClosingPos = stripos($this->m_sTemplate, '</'.$sTag.'>', $iOpeningPos);
}
if ( ($iOpeningPos !== false) && ($iClosingPos !== false))
{
if ($iOpeningPos < $iStartPos)
{
// This is the next tag
$iStartPos = $iOpeningPos;
$iEndPos = $iClosingPos;
$sNextTag = $sTag;
}
}
}
return $sNextTag;
}
public function GetTagContent($sTag, $iStartPos, $iEndPos)
{
$sContent = "";
$iContentStart = strpos($this->m_sTemplate, '>', $iStartPos); // Content of tag start immediatly after the first closing bracket
if ($iContentStart !== false)
{
$sContent = substr($this->m_sTemplate, 1+$iContentStart, $iEndPos - $iContentStart - 1);
}
return $sContent;
}
public function GetTagAttributes($sTag, $iStartPos, $iEndPos)
{
$aAttr = array();
$iAttrStart = strpos($this->m_sTemplate, ' ', $iStartPos); // Attributes start just after the first space
$iAttrEnd = strpos($this->m_sTemplate, '>', $iStartPos); // Attributes end just before the first closing bracket
if ( ($iAttrStart !== false) && ($iAttrEnd !== false) && ($iAttrEnd > $iAttrStart))
{
$sAttributes = substr($this->m_sTemplate, 1+$iAttrStart, $iAttrEnd - $iAttrStart - 1);
$aAttributes = explode(' ', $sAttributes);
foreach($aAttributes as $sAttr)
{
if ( preg_match('/(.+) *= *"(.+)"$/', $sAttr, $aMatches) )
{
$aAttr[strtolower($aMatches[1])] = $aMatches[2];
}
}
}
return $aAttr;
}
protected function RenderTag($oPage, $sTag, $aAttributes, $sContent)
{
static $iTabContainerCount = 0;
switch($sTag)
{
case 'itoptabs':
$oPage->AddTabContainer('Tabs_'.$iTabContainerCount);
$oPage->SetCurrentTabContainer('Tabs_'.$iTabContainerCount);
$iTabContainerCount++;
//$oPage->p('Content:<pre>'.htmlentities($sContent, ENT_QUOTES, 'UTF-8').'</pre>');
$oTemplate = new DisplayTemplate($sContent);
$oTemplate->Render($oPage, array()); // no params to apply, they have already been applied
$oPage->SetCurrentTabContainer('');
break;
case 'itopcheck':
$sClassName = $aAttributes['class'];
if (MetaModel::IsValidClass($sClassName) && UserRights::IsActionAllowed($sClassName, UR_ACTION_READ))
{
$oTemplate = new DisplayTemplate($sContent);
$oTemplate->Render($oPage, array()); // no params to apply, they have already been applied
}
else
{
// Leave a trace for those who'd like to understand why nothing is displayed
$oPage->add("<!-- class $sClassName does not exist, skipping some part of the template -->\n");
}
break;
case 'itoptab':
$oPage->SetCurrentTab(Dict::S(str_replace('_', ' ', $aAttributes['name'])));
$oTemplate = new DisplayTemplate($sContent);
$oTemplate->Render($oPage, array()); // no params to apply, they have already been applied
//$oPage->p('iTop Tab Content:<pre>'.htmlentities($sContent, ENT_QUOTES, 'UTF-8').'</pre>');
$oPage->SetCurrentTab('');
break;
case 'itoptoggle':
$sName = isset($aAttributes['name']) ? $aAttributes['name'] : 'Tagada';
$bOpen = isset($aAttributes['open']) ? $aAttributes['open'] : true;
$oPage->StartCollapsibleSection(Dict::S($sName), $bOpen);
$oTemplate = new DisplayTemplate($sContent);
$oTemplate->Render($oPage, array()); // no params to apply, they have already been applied
//$oPage->p('iTop Tab Content:<pre>'.htmlentities($sContent, ENT_QUOTES, 'UTF-8').'</pre>');
$oPage->EndCollapsibleSection();
break;
case 'itopstring':
$oPage->add(Dict::S($sContent));
break;
case 'sqlblock':
$oBlock = SqlBlock::FromTemplate($sContent);
$oBlock->RenderContent($oPage);
break;
case 'itopblock': // No longer used, handled by DisplayBlock::FromTemplate see above
$oPage->add("<!-- Application Error: should be handled by DisplayBlock::FromTemplate -->");
break;
default:
// Unknown tag, just ignore it or now -- output an HTML comment
$oPage->add("<!-- unsupported tag: $sTag -->");
}
}
/**
* Unit test
*/
static public function UnitTest()
{
require_once(APPROOT.'/application/startup.inc.php');
require_once(APPROOT."/application/itopwebpage.class.inc.php");
$sTemplate = '<div class="page_header">
<div class="actions_details"><a href="#"><span>Actions</span></a></div>
<h1>$class$: <span class="hilite">$name$</span></h1>
<itopblock blockclass="HistoryBlock" type="toggle" encoding="text/oql">SELECT CMDBChangeOp WHERE objkey = $id$ AND objclass = \'$class$\'</itopblock>
</div>
<img src="../../images/connect_to_network.png" style="margin-top:-10px; margin-right:10px; float:right">
<itoptabs>
<itoptab name="Interfaces">
<itopblock blockclass="DisplayBlock" type="list" encoding="text/oql">SELECT Interface AS i WHERE i.device_id = $id$</itopblock>
</itoptab>
<itoptab name="Contacts">
<itopblock blockclass="DisplayBlock" type="list" encoding="text/oql">SELECT Contact AS c JOIN lnkContactToCI AS l ON l.contact_id = c.id WHERE l.ci_id = $id$</itopblock>
</itoptab>
<itoptab name="Documents">
<itopblock blockclass="DisplayBlock" type="list" encoding="text/oql">SELECT Document AS d JOIN lnkDocumentToCI as l ON l.document_id = d.id WHERE l.ci_id = $id$)</itopblock>
</itoptab>
</itoptabs>';
$oPage = new iTopWebPage('Unit Test');
//$oPage->add("Template content: <pre>".htmlentities($sTemplate, ENT_QUOTES, 'UTF-8')."</pre>\n");
$oTemplate = new DisplayTemplate($sTemplate);
$oTemplate->Render($oPage, array('class'=>'Network device','pkey'=> 271, 'name' => 'deliversw01.mecanorama.fr', 'org_id' => 3));
$oPage->output();
}
}
/**
* Special type of template for displaying the details of an object
* On top of the defaut 'blocks' managed by the parent class, the following placeholders
* are available in such a template:
* $attribute_code$ An attribute of the object (in edit mode this is the input for the attribute)
* $attribute_code->label()$ The label of an attribute
* $PlugIn:plugInClass->properties()$ The ouput of OnDisplayProperties of the specified plugInClass
*/
class ObjectDetailsTemplate extends DisplayTemplate
{
public function __construct($sTemplate, $oObj, $sFormPrefix = '')
{
parent::__construct($sTemplate);
$this->m_oObj = $oObj;
$this->m_sPrefix = $sFormPrefix;
}
public function Render(WebPage $oPage, $aParams = array(), $bEditMode = false)
{
$sStateAttCode = MetaModel :: GetStateAttributeCode(get_class($this->m_oObj));
$aTemplateFields = array();
preg_match_all('/\\$this->([a-z0-9_]+)\\$/', $this->m_sTemplate, $aMatches);
foreach ($aMatches[1] as $sAttCode)
{
if (MetaModel::IsValidAttCode(get_class($this->m_oObj), $sAttCode))
{
$aTemplateFields[] = $sAttCode;
}
else
{
$aParams['this->'.$sAttCode] = "<!--Unknown attribute: $sAttCode-->";
}
}
preg_match_all('/\\$this->field\\(([a-z0-9_]+)\\)\\$/', $this->m_sTemplate, $aMatches);
foreach ($aMatches[1] as $sAttCode)
{
if (MetaModel::IsValidAttCode(get_class($this->m_oObj), $sAttCode))
{
$aTemplateFields[] = $sAttCode;
}
else
{
$aParams['this->field('.$sAttCode.')'] = "<!--Unknown attribute: $sAttCode-->";
}
}
$aFieldsComments = (isset($aParams['fieldsComments'])) ? $aParams['fieldsComments'] : array();
$aFieldsMap = array();
$sClass = get_class($this->m_oObj);
// Renders the fields used in the template
foreach(MetaModel::ListAttributeDefs(get_class($this->m_oObj)) as $sAttCode => $oAttDef)
{
$aParams['this->label('.$sAttCode.')'] = $oAttDef->GetLabel();
$aParams['this->comments('.$sAttCode.')'] = isset($aFieldsComments[$sAttCode]) ? $aFieldsComments[$sAttCode] : '';
$iInputId = '2_'.$sAttCode; // TODO: generate a real/unique prefix...
if (in_array($sAttCode, $aTemplateFields))
{
if ($this->m_oObj->IsNew())
{
$iFlags = $this->m_oObj->GetInitialStateAttributeFlags($sAttCode);
}
else
{
$iFlags = $this->m_oObj->GetAttributeFlags($sAttCode);
}
if (($iFlags & OPT_ATT_MANDATORY) && $this->m_oObj->IsNew())
{
$iFlags = $iFlags & ~OPT_ATT_READONLY; // Mandatory fields cannot be read-only when creating an object
}
if ((!$oAttDef->IsWritable()) || ($sStateAttCode == $sAttCode))
{
$iFlags = $iFlags | OPT_ATT_READONLY;
}
if ($iFlags & OPT_ATT_HIDDEN)
{
$aParams['this->label('.$sAttCode.')'] = '';
$aParams['this->field('.$sAttCode.')'] = '';
$aParams['this->comments('.$sAttCode.')'] = '';
$aParams['this->'.$sAttCode] = '';
}
else
{
if ($bEditMode && ($iFlags & (OPT_ATT_READONLY|OPT_ATT_SLAVE)))
{
// Check if the attribute is not read-only because of a synchro...
$aReasons = array();
$sSynchroIcon = '';
if ($iFlags & OPT_ATT_SLAVE)
{
$iSynchroFlags = $this->m_oObj->GetSynchroReplicaFlags($sAttCode, $aReasons);
$sSynchroIcon = "&nbsp;<img id=\"synchro_$iInputId\" src=\"../images/transp-lock.png\" style=\"vertical-align:middle\"/>";
$sTip = '';
foreach($aReasons as $aRow)
{
$sDescription = htmlentities($aRow['description'], ENT_QUOTES, 'UTF-8');
$sDescription = str_replace(array("\r\n", "\n"), "<br/>", $sDescription);
$sTip .= "<div class='synchro-source'>";
$sTip .= "<div class='synchro-source-title'>Synchronized with {$aRow['name']}</div>";
$sTip .= "<div class='synchro-source-description'>$sDescription</div>";
}
$oPage->add_ready_script("$('#synchro_$iInputId').qtip( { content: '$sTip', show: 'mouseover', hide: 'mouseout', style: { name: 'dark', tip: 'leftTop' }, position: { corner: { target: 'rightMiddle', tooltip: 'leftTop' }} } );");
}
// Attribute is read-only
$sHTMLValue = "<span id=\"field_{$iInputId}\">".$this->m_oObj->GetAsHTML($sAttCode);
$sHTMLValue .= '<input type="hidden" id="'.$iInputId.'" name="attr_'.$sAttCode.'" value="'.htmlentities($this->m_oObj->Get($sAttCode), ENT_QUOTES, 'UTF-8').'"/></span>';
$aFieldsMap[$sAttCode] = $iInputId;
$aParams['this->comments('.$sAttCode.')'] = $sSynchroIcon;
}
if ($bEditMode && !($iFlags & OPT_ATT_READONLY)) //TODO: check the data synchro status...
{
$aParams['this->field('.$sAttCode.')'] = "<span id=\"field_{$iInputId}\">".$this->m_oObj->GetFormElementForField($oPage, $sClass, $sAttCode, $oAttDef,
$this->m_oObj->Get($sAttCode),
$this->m_oObj->GetEditValue($sAttCode),
$iInputId, // InputID
'',
$iFlags,
array('this' => $this->m_oObj) // aArgs
).'</span>';
$aFieldsMap[$sAttCode] = $iInputId;
}
else
{
$aParams['this->field('.$sAttCode.')'] = $this->m_oObj->GetAsHTML($sAttCode);
}
$aParams['this->'.$sAttCode] = "<table class=\"field\"><tr><td class=\"label\">".$aParams['this->label('.$sAttCode.')'].":</td><td>".$aParams['this->field('.$sAttCode.')']."</td><td>".$aParams['this->comments('.$sAttCode.')']."</td></tr></table>";
}
}
}
// Renders the PlugIns used in the template
preg_match_all('/\\$PlugIn:([A-Za-z0-9_]+)->properties\\(\\)\\$/', $this->m_sTemplate, $aMatches);
$aPlugInProperties = $aMatches[1];
foreach($aPlugInProperties as $sPlugInClass)
{
$oInstance = MetaModel::GetPlugins('iApplicationUIExtension', $sPlugInClass);
if ($oInstance != null) // Safety check...
{
$offset = $oPage->start_capture();
$oInstance->OnDisplayProperties($this->m_oObj, $oPage, $bEditMode);
$sContent = $oPage->end_capture($offset);
$aParams["PlugIn:{$sPlugInClass}->properties()"]= $sContent;
}
else
{
$aParams["PlugIn:{$sPlugInClass}->properties()"]= "Missing PlugIn: $sPlugInClass";
}
}
$offset = $oPage->start_capture();
parent::Render($oPage, $aParams);
$sContent = $oPage->end_capture($offset);
// Remove empty table rows in case some attributes are hidden...
$sContent = preg_replace('/<tr[^>]*>\s*(<td[^>]*>\s*<\\/td>)+\s*<\\/tr>/im', '', $sContent);
$oPage->add($sContent);
return $aFieldsMap;
}
}
//DisplayTemplate::UnitTest();
?>

View File

@@ -1,12 +1,12 @@
<div class="page_header">
<itopblock blockclass="MenuBlock" type="popup" encoding="text/oql" label="Actions">SELECT $class$ WHERE id = $id$</itopblock>
<h1>$class$: <span class="hilite">$name$</span></h1>
<itopblock blockclass="HistoryBlock" type="toggle" encoding="text/oql">SELECT CMDBChangeOp WHERE objkey = $id$ AND objclass = '$class$'</itopblock>
</div>
<img src="../../images/clean.png" style="margin-top:-20px; margin-right:10px; float:right">
<itopblock blockclass="DisplayBlock" asynchronous="false" type="bare_details" encoding="text/oql">SELECT $class$ WHERE id = $id$</itopblock>
<itoptabs>
<itoptab name="Rules">
<itopblock blockclass="DisplayBlock" type="list" encoding="text/oql">SELECT AuditRule WHERE category_id = $id$</itopblock>
</itoptab>
</itoptabs>
<div class="page_header">
<itopblock blockclass="MenuBlock" type="popup" encoding="text/oql" label="Actions">SELECT $class$ WHERE id = $id$</itopblock>
<h1>$class$: <span class="hilite">$name$</span></h1>
<itopblock blockclass="HistoryBlock" type="toggle" encoding="text/oql">SELECT CMDBChangeOp WHERE objkey = $id$ AND objclass = '$class$'</itopblock>
</div>
<img src="../../images/clean.png" style="margin-top:-20px; margin-right:10px; float:right">
<itopblock blockclass="DisplayBlock" asynchronous="false" type="bare_details" encoding="text/oql">SELECT $class$ WHERE id = $id$</itopblock>
<itoptabs>
<itoptab name="Rules">
<itopblock blockclass="DisplayBlock" type="list" encoding="text/oql">SELECT AuditRule WHERE category_id = $id$</itopblock>
</itoptab>
</itoptabs>

View File

@@ -119,7 +119,7 @@ class privUITransactionSession
// Strictly speaking, the two lines below should be grouped together
// by a critical section
// sem_acquire($rSemIdentified);
$id = str_replace(array('.', ' '), '', microtime()); //1 + count($_SESSION['transactions']);
$id = static::GetUserPrefix() . str_replace(array('.', ' '), '', microtime()); //1 + count($_SESSION['transactions']);
$_SESSION['transactions'][$id] = true;
// sem_release($rSemIdentified);
@@ -174,6 +174,17 @@ class privUITransactionSession
// sem_release($rSemIdentified);
}
}
/**
* Returns a string to prefix transaction ID with info from the current user.
*
* @return string
*/
protected static function GetUserPrefix()
{
$sPrefix = 'u'.UserRights::GetUserId();
return $sPrefix.'-';
}
}
/**
@@ -206,7 +217,7 @@ class privUITransactionFile
throw new Exception('The directory "'.APPROOT.'data/transactions" must be writable to the application.');
}
self::CleanupOldTransactions();
$id = basename(tempnam(APPROOT.'data/transactions', self::GetUserPrefix()));
$id = basename(tempnam(APPROOT.'data/transactions', static::GetUserPrefix()));
self::Info('GetNewTransactionId: Created transaction: '.$id);
return (string)$id;
@@ -310,6 +321,11 @@ class privUITransactionFile
return $aResult;
}
/**
* Returns a prefix based on the user login instead of its ID for a better usage in tempnam()
*
* @inheritdoc
*/
protected static function GetUserPrefix()
{
$sPrefix = substr(UserRights::GetUser(), 0, 10);

View File

@@ -1,5 +1,5 @@
<?php
// Copyright (C) 2010-2012 Combodo SARL
// Copyright (C) 2010-2017 Combodo SARL
//
// This file is part of iTop.
//
@@ -19,15 +19,15 @@
* Class UIExtKeyWidget
* UI wdiget for displaying and editing external keys when
* A simple drop-down list is not enough...
*
*
* The layout is the following
*
*
* +-- #label_<id> (input)-------+ +-----------+
* | | | Browse... |
* +-----------------------------+ +-----------+
*
*
* And the popup dialog has the following layout:
*
*
* +------------------- ac_dlg_<id> (div)-----------+
* + +--- ds_<id> (div)---------------------------+ |
* | | +------------- fs_<id> (form)------------+ | |
@@ -54,20 +54,23 @@
* | | +--------+ +-----+ | |
* | +--------------------------------------------+ |
* +------------------------------------------------+
* @copyright Copyright (C) 2010-2012 Combodo SARL
* @copyright Copyright (C) 2010-2017 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
require_once(APPROOT.'/application/webpage.class.inc.php');
require_once(APPROOT.'/application/displayblock.class.inc.php');
class UIExtKeyWidget
class UIExtKeyWidget
{
const ENUM_OUTPUT_FORMAT_CSV = 'csv';
const ENUM_OUTPUT_FORMAT_JSON = 'json';
protected $iId;
protected $sTargetClass;
protected $sAttCode;
protected $bSearchMode;
//public function __construct($sAttCode, $sClass, $sTitle, $oAllowedValues, $value, $iInputId, $bMandatory, $sNameSuffix = '', $sFieldPrefix = '', $sFormPrefix = '')
static public function DisplayFromAttCode($oPage, $sAttCode, $sClass, $sTitle, $oAllowedValues, $value, $iInputId, $bMandatory, $sFieldName = '', $sFormPrefix = '', $aArgs, $bSearchMode = false)
{
@@ -94,36 +97,36 @@ class UIExtKeyWidget
$this->sAttCode = $sAttCode;
$this->bSearchMode = $bSearchMode;
}
/**
* Get the HTML fragment corresponding to the ext key editing widget
* @param WebPage $oP The web page used for all the output
* @param Hash $aArgs Extra context arguments
* @param array $aArgs Extra context arguments
* @return string The HTML fragment to be inserted into the page
*/
public function Display(WebPage $oPage, $iMaxComboLength, $bAllowTargetCreation, $sTitle, $oAllowedValues, $value, $iInputId, $bMandatory, $sFieldName, $sFormPrefix = '', $aArgs = array(), $bSearchMode = null, $sDisplayStyle = 'select', $bSearchMultiple = true)
public function Display(WebPage $oPage, $iMaxComboLength, $bAllowTargetCreation, $sTitle, DBObjectset $oAllowedValues, $value, $iInputId, $bMandatory, $sFieldName, $sFormPrefix = '', $aArgs = array(), $bSearchMode = null, $sDisplayStyle = 'select', $bSearchMultiple = true)
{
if (!is_null($bSearchMode))
{
$this->bSearchMode = $bSearchMode;
}
$sTitle = addslashes($sTitle);
$sTitle = addslashes($sTitle);
$oPage->add_linked_script('../js/extkeywidget.js');
$oPage->add_linked_script('../js/forms-json-utils.js');
$bCreate = (!$this->bSearchMode) && (!MetaModel::IsAbstract($this->sTargetClass)) && (UserRights::IsActionAllowed($this->sTargetClass, UR_ACTION_BULK_MODIFY) && $bAllowTargetCreation);
$bCreate = (!$this->bSearchMode) && (UserRights::IsActionAllowed($this->sTargetClass, UR_ACTION_BULK_MODIFY) && $bAllowTargetCreation);
$bExtensions = true;
$sMessage = Dict::S('UI:Message:EmptyList:UseSearchForm');
$sAttrFieldPrefix = ($this->bSearchMode) ? '' : 'attr_';
$sHTMLValue = "<span style=\"white-space:nowrap\">"; // no wrap
$sHTMLValue = "<div class=\"field_input_zone field_input_extkey\">";
$sFilter = addslashes($oAllowedValues->GetFilter()->ToOQL());
if($this->bSearchMode)
{
$sWizHelper = 'null';
$sWizHelperJSON = "''";
$sJSSearchMode = 'true';
}
}
else
{
if (isset($aArgs['wizHelper']))
@@ -141,16 +144,22 @@ class UIExtKeyWidget
{
throw new Exception('Implementation: null value for allowed values definition');
}
elseif ($oAllowedValues->Count() < $iMaxComboLength)
$oAllowedValues->SetShowObsoleteData(utils::ShowObsoleteData());
// Don't automatically launch the search if the table is huge
$bDoSearch = !utils::IsHighCardinality($this->sTargetClass);
$sJSDoSearch = $bDoSearch ? 'true' : 'false';
// We just need to compare the number of entries with MaxComboLength, so no need to get the real count.
if (!$oAllowedValues->CountExceeds($iMaxComboLength))
{
// Discrete list of values, use a SELECT or RADIO buttons depending on the config
// 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 = '';
$sValidationField = null;
$bVertical = ($sDisplayStyle != 'radio_horizontal');
$bExtensions = false;
$oAllowedValues->Rewind();
@@ -158,54 +167,57 @@ class UIExtKeyWidget
while($oObj = $oAllowedValues->Fetch())
{
$aAllowedValues[$oObj->GetKey()] = $oObj->GetName();
}
$sHTMLValue = $oPage->GetRadioButtons($aAllowedValues, $value, $this->iId, "{$sAttrFieldPrefix}{$sFieldName}", $bMandatory, $bVertical, $sValidationField);
}
$sHTMLValue .= $oPage->GetRadioButtons($aAllowedValues, $value, $this->iId, "{$sAttrFieldPrefix}{$sFieldName}", false /* $bMandatory will be placed manually */, $bVertical, $sValidationField);
$aEventsList[] ='change';
break;
case 'select':
case 'list':
default:
$sSelectMode = 'true';
$sHelpText = ''; //$this->oAttDef->GetHelpOnEdition();
$sHTMLValue .= "<div class=\"field_select_wrapper\">\n";
if ($this->bSearchMode)
{
if ($bSearchMultiple)
{
$sHTMLValue = "<select class=\"multiselect\" multiple title=\"$sHelpText\" name=\"{$sAttrFieldPrefix}{$sFieldName}[]\" id=\"$this->iId\">\n";
$sHTMLValue .= "<select class=\"multiselect\" multiple title=\"$sHelpText\" name=\"{$sAttrFieldPrefix}{$sFieldName}[]\" id=\"$this->iId\">\n";
}
else
{
$sHTMLValue = "<select title=\"$sHelpText\" name=\"{$sAttrFieldPrefix}{$sFieldName}\" id=\"$this->iId\">\n";
$sHTMLValue .= "<select title=\"$sHelpText\" name=\"{$sAttrFieldPrefix}{$sFieldName}\" id=\"$this->iId\">\n";
$sDisplayValue = isset($aArgs['sDefaultValue']) ? $aArgs['sDefaultValue'] : Dict::S('UI:SearchValue:Any');
$sHTMLValue .= "<option value=\"\">$sDisplayValue</option>\n";
}
}
else
{
$sHTMLValue = "<select title=\"$sHelpText\" name=\"{$sAttrFieldPrefix}{$sFieldName}\" id=\"$this->iId\">\n";
$sHTMLValue .= "<select title=\"$sHelpText\" name=\"{$sAttrFieldPrefix}{$sFieldName}\" id=\"$this->iId\">\n";
$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';
$sSelected = 'selected';
}
else
{
$sSelected = (is_array($value) && in_array($key, $value)) || ($value == $key) ? ' selected' : '';
$sSelected = (is_array($value) && in_array($key, $value)) || ($value == $key) ? 'selected' : '';
}
$sHTMLValue .= "<option value=\"$key\"$sSelected>$display_value</option>\n";
$sHTMLValue .= "<option value=\"$key\" $sSelected>$display_value</option>\n";
}
$sHTMLValue .= "</select>\n";
$sHTMLValue .= "</div>\n";
if (($this->bSearchMode) && $bSearchMultiple)
{
$aOptions = array(
@@ -221,7 +233,7 @@ class UIExtKeyWidget
}
$oPage->add_ready_script(
<<<EOF
oACWidget_{$this->iId} = new ExtKeyWidget('{$this->iId}', '{$this->sTargetClass}', '$sFilter', '$sTitle', true, $sWizHelper, '{$this->sAttCode}', $sJSSearchMode);
oACWidget_{$this->iId} = new ExtKeyWidget('{$this->iId}', '{$this->sTargetClass}', '$sFilter', '$sTitle', true, $sWizHelper, '{$this->sAttCode}', $sJSSearchMode, $sJSDoSearch);
oACWidget_{$this->iId}.emptyHtml = "<div style=\"background: #fff; border:0; text-align:center; vertical-align:middle;\"><p>$sMessage</p></div>";
$('#$this->iId').bind('update', function() { oACWidget_{$this->iId}.Update(); } );
$('#$this->iId').bind('change', function() { $(this).trigger('extkeychange') } );
@@ -233,8 +245,6 @@ EOF
else
{
// Too many choices, use an autocomplete
$sSelectMode = 'false';
// Check that the given value is allowed
$oSearch = $oAllowedValues->GetFilter();
$oSearch->AddCondition('id', $value);
@@ -253,20 +263,19 @@ EOF
$sDisplayValue = $this->GetObjectName($value);
}
$iMinChars = isset($aArgs['iMinChars']) ? $aArgs['iMinChars'] : 3; //@@@ $this->oAttDef->GetMinAutoCompleteChars();
$iFieldSize = isset($aArgs['iFieldSize']) ? $aArgs['iFieldSize'] : 20; //@@@ $this->oAttDef->GetMaxSize();
// the input for the auto-complete
$sHTMLValue = "<input 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?itopversion=".ITOP_VERSION."\" onClick=\"oACWidget_{$this->iId}.Search();\"/>";
$sHTMLValue .= "<input class=\"field_autocomplete\" type=\"text\" id=\"label_$this->iId\" value=\"$sDisplayValue\"/>";
$sHTMLValue .= "<span class=\"field_input_btn\"><img id=\"mini_search_{$this->iId}\" style=\"border:0;vertical-align:middle;cursor:pointer;\" src=\"../images/mini_search.gif?t=".utils::GetCacheBusterTimestamp()."\" onClick=\"oACWidget_{$this->iId}.Search();\"/></span>";
// another hidden input to store & pass the object's Id
$sHTMLValue .= "<input type=\"hidden\" id=\"$this->iId\" name=\"{$sAttrFieldPrefix}{$sFieldName}\" value=\"".htmlentities($value, ENT_QUOTES, 'UTF-8')."\" />\n";
$JSSearchMode = $this->bSearchMode ? 'true' : 'false';
$JSSearchMode = $this->bSearchMode ? 'true' : 'false';
// Scripts to start the autocomplete and bind some events to it
$oPage->add_ready_script(
<<<EOF
oACWidget_{$this->iId} = new ExtKeyWidget('{$this->iId}', '{$this->sTargetClass}', '$sFilter', '$sTitle', false, $sWizHelper, '{$this->sAttCode}', $sJSSearchMode);
oACWidget_{$this->iId} = new ExtKeyWidget('{$this->iId}', '{$this->sTargetClass}', '$sFilter', '$sTitle', false, $sWizHelper, '{$this->sAttCode}', $sJSSearchMode, $sJSDoSearch);
oACWidget_{$this->iId}.emptyHtml = "<div style=\"background: #fff; border:0; text-align:center; vertical-align:middle;\"><p>$sMessage</p></div>";
$('#label_$this->iId').autocomplete(GetAbsoluteUrlAppRoot()+'pages/ajax.render.php', { scroll:true, minChars:{$iMinChars}, autoFill:false, matchContains:true, mustMatch: true, keyHolder:'#{$this->iId}', extraParams:{operation:'ac_extkey', sTargetClass:'{$this->sTargetClass}',sFilter:'$sFilter',bSearchMode:$JSSearchMode, json: function() { return $sWizHelperJSON; } }});
$('#label_$this->iId').keyup(function() { if ($(this).val() == '') { $('#$this->iId').val(''); } } ); // Useful for search forms: empty value in the "label", means no value, immediatly !
@@ -281,7 +290,7 @@ 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?itopversion=".ITOP_VERSION."\" onClick=\"oACWidget_{$this->iId}.HKDisplay();\"/>&nbsp;";
$sHTMLValue .= "<span class=\"field_input_btn\"><img id=\"mini_tree_{$this->iId}\" style=\"border:0;vertical-align:middle;cursor:pointer;\" src=\"../images/mini_tree.gif?t=".utils::GetCacheBusterTimestamp()."\" onClick=\"oACWidget_{$this->iId}.HKDisplay();\"/></span>";
$oPage->add_ready_script(
<<<EOF
if ($('#ac_tree_{$this->iId}').length == 0)
@@ -293,7 +302,9 @@ EOF
}
if ($bCreate && $bExtensions)
{
$sHTMLValue .= "<img id=\"mini_add_{$this->iId}\" style=\"border:0;vertical-align:middle;cursor:pointer;\" src=\"../images/mini_add.gif?itopversion=".ITOP_VERSION."\" onClick=\"oACWidget_{$this->iId}.CreateObject();\"/>&nbsp;";
$sCallbackName = (MetaModel::IsAbstract($this->sTargetClass)) ? 'SelectObjectClass' : 'CreateObject';
$sHTMLValue .= "<span class=\"field_input_btn\"><img id=\"mini_add_{$this->iId}\" style=\"border:0;vertical-align:middle;cursor:pointer;\" src=\"../images/mini_add.gif?t=".utils::GetCacheBusterTimestamp()."\" onClick=\"oACWidget_{$this->iId}.{$sCallbackName}();\"/></span>";
$oPage->add_ready_script(
<<<EOF
if ($('#ajax_{$this->iId}').length == 0)
@@ -303,14 +314,17 @@ EOF
EOF
);
}
if (($sDisplayStyle == 'select') || ($sDisplayStyle == 'list'))
{
$sHTMLValue .= "<span id=\"v_{$this->iId}\"></span>";
}
$sHTMLValue .= "</span>"; // end of no wrap
$sHTMLValue .= "</div>";
// Note: This test is no longer necessary as we changed the markup to extract validation decoration in the standard .field_input_xxx container
//if (($sDisplayStyle == 'select') || ($sDisplayStyle == 'list'))
//{
$sHTMLValue .= "<span class=\"form_validation\" id=\"v_{$this->iId}\"></span><span class=\"field_status\" id=\"fstatus_{$this->iId}\"></span>";
//}
return $sHTMLValue;
}
public function GetSearchDialog(WebPage $oPage, $sTitle, $oCurrObject = null)
{
$sHTML = '<div class="wizContainer" style="vertical-align:top;"><div id="dc_'.$this->iId.'">';
@@ -318,7 +332,8 @@ EOF
if ( ($oCurrObject != null) && ($this->sAttCode != ''))
{
$oAttDef = MetaModel::GetAttributeDef(get_class($oCurrObject), $this->sAttCode);
$aArgs = array('this' => $oCurrObject);
/** @var \DBObject $oCurrObject */
$aArgs = $oCurrObject->ToArgsForQuery();
$aParams = array('query_params' => $aArgs);
$oSet = $oAttDef->GetAllowedValuesAsObjectSet($aArgs);
$oFilter = $oSet->GetFilter();
@@ -330,7 +345,16 @@ EOF
}
$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 .= $oBlock->GetDisplay($oPage, $this->iId,
array(
'menu' => false,
'currentId' => $this->iId,
'table_id' => "dr_{$this->iId}",
'table_inner_id' => "{$this->iId}_results",
'selection_mode' => true,
'selection_type' => 'single',
'cssCount' => '#count_'.$this->iId)
);
$sHTML .= "<form id=\"fr_{$this->iId}\" OnSubmit=\"return oACWidget_{$this->iId}.DoOk();\">\n";
$sHTML .= "<div id=\"dr_{$this->iId}\" style=\"vertical-align:top;background: #fff;height:100%;overflow:auto;padding:0;border:0;\">\n";
$sHTML .= "<div style=\"background: #fff; border:0; text-align:center; vertical-align:middle;\"><p>".Dict::S('UI:Message:EmptyList:UseSearchForm')."</p></div>\n";
@@ -354,9 +378,13 @@ EOF
/**
* Search for objects to be selected
*
* @param WebPage $oP The page used for the output (usually an AjaxWebPage)
* @param $sFilter
* @param string $sRemoteClass Name of the "remote" class to perform the search on, must be a derived class of m_sRemoteClass
* @param Array $aAlreadyLinkedIds List of IDs of objects of "remote" class already linked, to be filtered out of the search
* @param null $oObj
*
* @throws \OQLException
*/
public function SearchObjectsToSelect(WebPage $oP, $sFilter, $sRemoteClass = '', $oObj = null)
{
@@ -364,39 +392,87 @@ EOF
{
throw new Exception('Implementation: null value for allowed values definition');
}
$oFilter = DBObjectSearch::FromOQL($sFilter);
if (strlen($sRemoteClass) > 0)
{
$oFilter->ChangeClass($sRemoteClass);
}
$oFilter->SetModifierProperty('UserRightsGetSelectFilter', 'bSearchMode', $this->bSearchMode);
$oBlock = new DisplayBlock($oFilter, 'list', false, array('query_params' => array('this' => $oObj)));
// Current extkey value, so we can display event if it is not available anymore (eg. archived).
$iCurrentExtKeyId = (is_null($oObj)) ? 0 : $oObj->Get($this->sAttCode);
$oBlock = new DisplayBlock($oFilter, 'list_search', false, array('query_params' => array('this' => $oObj, 'current_extkey_id' => $iCurrentExtKeyId)));
$oBlock->Display($oP, $this->iId.'_results', array('this' => $oObj, 'cssCount'=> '#count_'.$this->iId, 'menu' => false, 'selection_mode' => true, 'selection_type' => 'single', 'table_id' => 'select_'.$this->sAttCode)); // Don't display the 'Actions' menu on the results
}
/**
* Search for objects to be selected
* @param WebPage $oP The page used for the output (usually an AjaxWebPage)
* @param string $sFilter The OQL expression used to define/limit limit the scope of possible values
* @param DBObject $oObj The current object for the OQL context
* @param string $sContains The text of the autocomplete to filter the results
*/
public function AutoComplete(WebPage $oP, $sFilter, $oObj = null, $sContains)
/**
* Search for objects to be selected
*
* @param WebPage $oP The page used for the output (usually an AjaxWebPage)
* @param string $sFilter The OQL expression used to define/limit limit the scope of possible values
* @param DBObject $oObj The current object for the OQL context
* @param string $sContains The text of the autocomplete to filter the results
* @param string $sOutputFormat
* @param null $sOperation for the values @see ValueSetObjects->LoadValues()
*
* @throws CoreException
* @throws OQLException
*/
public function AutoComplete(WebPage $oP, $sFilter, $oObj = null, $sContains, $sOutputFormat = self::ENUM_OUTPUT_FORMAT_CSV, $sOperation = null)
{
if (is_null($sFilter))
{
throw new Exception('Implementation: null value for allowed values definition');
}
// Current extkey value, so we can display event if it is not available anymore (eg. archived).
$iCurrentExtKeyId = (is_null($oObj) || $this->sAttCode === '') ? 0 : $oObj->Get($this->sAttCode);
$oValuesSet = new ValueSetObjects($sFilter, 'friendlyname'); // Bypass GetName() to avoid the encoding by htmlentities
$iMax = 150;
$oValuesSet->SetLimit($iMax);
$oValuesSet->SetSort(false);
$oValuesSet->SetModifierProperty('UserRightsGetSelectFilter', 'bSearchMode', $this->bSearchMode);
$aValues = $oValuesSet->GetValues(array('this' => $oObj), $sContains);
foreach($aValues as $sKey => $sFriendlyName)
$oValuesSet->SetLimit($iMax);
$aValuesContains = $oValuesSet->GetValues(array('this' => $oObj, 'current_extkey_id' => $iCurrentExtKeyId), $sContains, 'contains');
asort($aValuesContains);
$aValues = array();
foreach($aValuesContains as $sKey => $sFriendlyName)
{
$oP->add(trim($sFriendlyName)."\t".$sKey."\n");
if (!isset($aValues[$sKey]))
{
$aValues[$sKey] = $sFriendlyName;
}
}
switch($sOutputFormat)
{
case static::ENUM_OUTPUT_FORMAT_JSON:
$aJsonMap = array();
foreach ($aValues as $sKey => $sLabel)
{
$aJsonMap[] = array('value' => $sKey, 'label' => $sLabel);
}
$oP->SetContentType('application/json');
$oP->add(json_encode($aJsonMap));
break;
case static::ENUM_OUTPUT_FORMAT_CSV:
foreach($aValues as $sKey => $sFriendlyName)
{
$oP->add(trim($sFriendlyName)."\t".$sKey."\n");
}
break;
default:
throw new Exception('Invalid output format, "'.$sOutputFormat.'" given.');
break;
}
}
/**
* Get the display name of the selected object, to fill back the autocomplete
*/
@@ -415,11 +491,56 @@ EOF
return '';
}
}
/**
* Get the form to select a leaf class from the $this->sTargetClass (that should be abstract)
* Note: Inspired from UILinksWidgetDirect::GetObjectCreationDialog()
*
* @param WebPage $oPage
*
* @throws \CoreException
* @throws \DictExceptionMissingString
*/
public function GetClassSelectionForm(WebPage $oPage)
{
// For security reasons: check that the "proposed" class is actually a subclass of the linked class
// and that the current user is allowed to create objects of this class
$aSubClasses = MetaModel::EnumChildClasses($this->sTargetClass);
$aPossibleClasses = array();
foreach($aSubClasses as $sCandidateClass)
{
if (!MetaModel::IsAbstract($sCandidateClass) && (UserRights::IsActionAllowed($sCandidateClass, UR_ACTION_MODIFY) == UR_ALLOWED_YES))
{
$aPossibleClasses[$sCandidateClass] = MetaModel::GetName($sCandidateClass);
}
}
$sDialogTitle = '';
$oPage->add('<div id="ac_create_'.$this->iId.'"><div class="wizContainer" style="vertical-align:top;"><div id="dcr_'.$this->iId.'">');
$oPage->add('<form>');
$sClassLabel = MetaModel::GetName($this->sTargetClass);
$oPage->add('<p>'.Dict::Format('UI:SelectTheTypeOf_Class_ToCreate', $sClassLabel));
$oPage->add('<nobr><select name="class">');
asort($aPossibleClasses);
foreach($aPossibleClasses as $sClassName => $sClassLabel)
{
$oPage->add("<option value=\"$sClassName\">$sClassLabel</option>");
}
$oPage->add('</select>');
$oPage->add('&nbsp; <button type="submit" class="action" style="margin-top:15px;"><span>' . Dict::S('UI:Button:Ok') . '</span></button></nobr></p>');
$oPage->add('</form>');
$oPage->add('</div></div></div>');
$oPage->add_ready_script("\$('#ac_create_$this->iId').dialog({ width: 'auto', height: 'auto', maxHeight: $(window).height() - 50, autoOpen: false, modal: true, title: '$sDialogTitle'});\n");
$oPage->add_ready_script("$('#dcr_{$this->iId} form').removeAttr('onsubmit');");
$oPage->add_ready_script("$('#dcr_{$this->iId} form').bind('submit.uilinksWizard', oACWidget_{$this->iId}.DoSelectObjectClass);");
}
/**
* Get the form to create a new object of the 'target' class
*/
public function GetObjectCreationForm(WebPage $oPage, $oCurrObject)
public function GetObjectCreationForm(WebPage $oPage, $oCurrObject, $aPrefillFormParam)
{
// Set all the default values in an object and clone this "default" object
$oNewObj = MetaModel::NewObject($this->sTargetClass);
@@ -427,7 +548,7 @@ EOF
// 1st - set context values
$oAppContext = new ApplicationContext();
$oAppContext->InitObjectFromContext($oNewObj);
$oNewObj->PrefillForm('creation_from_extkey', $aPrefillFormParam);
// 2nd set the default values from the constraint on the external key... if any
if ( ($oCurrObject != null) && ($this->sAttCode != ''))
{
@@ -444,14 +565,24 @@ EOF
}
}
}
// 3rd - set values from the page argument 'default'
$oNewObj->UpdateObjectFromArg('default');
$sDialogTitle = '';
$oPage->add('<div id="ac_create_'.$this->iId.'"><div class="wizContainer" style="vertical-align:top;"><div id="dcr_'.$this->iId.'">');
$oPage->add("<h1>".MetaModel::GetClassIcon($this->sTargetClass)."&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));
$aFieldsFlags = array();
$aFieldsComments = array();
foreach(MetaModel::ListAttributeDefs($this->sTargetClass) as $sAttCode => $oAttDef)
{
if (($oAttDef instanceof AttributeBlob) || (false))
{
$aFieldsFlags[$sAttCode] = OPT_ATT_READONLY;
$aFieldsComments[$sAttCode] = '&nbsp;<img src="../images/transp-lock.png" style="vertical-align:middle" title="'.htmlentities(Dict::S('UI:UploadNotSupportedInThisMode')).'"/>';
}
}
cmdbAbstractObject::DisplayCreationForm($oPage, $this->sTargetClass, $oNewObj, array(), array('formPrefix' => $this->iId, 'noRelations' => true, 'fieldsFlags' => $aFieldsFlags, 'fieldsComments' => $aFieldsComments));
$oPage->add('</div></div></div>');
// $oPage->add_ready_script("\$('#ac_create_$this->iId').dialog({ width: $(window).width()*0.8, height: 'auto', autoOpen: false, modal: true, title: '$sDialogTitle'});\n");
$oPage->add_ready_script("\$('#ac_create_$this->iId').dialog({ width: 'auto', height: 'auto', maxHeight: $(window).height() - 50, autoOpen: false, modal: true, title: '$sDialogTitle'});\n");
@@ -471,21 +602,12 @@ EOF
{
throw new Exception('Implementation: null value for allowed values definition');
}
try
{
$oFilter = DBObjectSearch::FromOQL($sFilter);
$oFilter->SetModifierProperty('UserRightsGetSelectFilter', 'bSearchMode', $this->bSearchMode);
$oSet = new DBObjectSet($oFilter, array(), array('this' => $oObj));
}
catch(MissingQueryArgument $e)
{
// When used in a search form the $this parameter may be missing, in this case return all possible values...
// TODO check if we can improve this behavior...
$sOQL = 'SELECT '.$this->m_sTargetClass;
$oFilter = DBObjectSearch::FromOQL($sOQL);
$oFilter->SetModifierProperty('UserRightsGetSelectFilter', 'bSearchMode', $this->bSearchMode);
$oSet = new DBObjectSet($oFilter);
}
$oFilter = DBObjectSearch::FromOQL($sFilter);
$oFilter->SetModifierProperty('UserRightsGetSelectFilter', 'bSearchMode', $this->bSearchMode);
$oSet = new DBObjectSet($oFilter, array(), array('this' => $oObj, 'current_extkey_id' => $currValue));
$oSet->SetShowObsoleteData(utils::ShowObsoleteData());
$sHKAttCode = MetaModel::IsHierarchicalClass($this->sTargetClass);
$this->DumpTree($oPage, $oSet, $sHKAttCode, $currValue);
@@ -494,7 +616,7 @@ EOF
$oPage->add('</div>');
$oPage->add("<input type=\"button\" id=\"btn_cancel_{$this->iId}\" value=\"".Dict::S('UI:Button:Cancel')."\" onClick=\"$('#dlg_tree_{$this->iId}').dialog('close');\">&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");
@@ -505,16 +627,23 @@ EOF
*/
public function DoCreateObject($oPage)
{
$oObj = MetaModel::NewObject($this->sTargetClass);
$aErrors = $oObj->UpdateObjectFromPostedForm($this->iId);
if (count($aErrors) == 0)
try
{
$oObj->DBInsert();
return array('name' => $oObj->GetName(), 'id' => $oObj->GetKey());
$oObj = MetaModel::NewObject($this->sTargetClass);
$aErrors = $oObj->UpdateObjectFromPostedForm($this->iId);
if (count($aErrors) == 0)
{
$oObj->DBInsert();
return array('name' => $oObj->GetName(), 'id' => $oObj->GetKey());
}
else
{
return array('error' => implode(' ', $aErrors), 'id' => 0);
}
}
else
catch(Exception $e)
{
return array('name' => implode(' ', $aErrors), 'id' => 0);
return array('error' => $e->getMessage(), 'id' => 0);
}
}
@@ -532,7 +661,7 @@ EOF
$aTree[$iParentId][$oObj->GetKey()] = $oObj->GetName();
$aNodes[$oObj->GetKey()] = $oObj;
}
$aParents = array_keys($aTree);
$aRoots = array();
foreach($aParents as $id)
@@ -547,7 +676,7 @@ EOF
$this->DumpNodes($oP, $iRootId, $aTree, $aNodes, $currValue);
}
}
function DumpNodes($oP, $iRootId, $aTree, $aNodes, $currValue)
{
$bSelect = true;
@@ -582,4 +711,3 @@ EOF
}
}
?>

View File

@@ -1,5 +1,5 @@
<?php
// Copyright (C) 2010-2015 Combodo SARL
// Copyright (C) 2010-2016 Combodo SARL
//
// This file is part of iTop.
//
@@ -20,9 +20,8 @@
* Class UIHTMLEditorWidget
* UI wdiget for displaying and editing one-way encrypted passwords
*
* @author Phil Eddies
* @author Romain Quetiez
* @copyright Copyright (C) 2010-2015 Combodo SARL
* @copyright Copyright (C) 2010-2016 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
@@ -65,7 +64,7 @@ class UIHTMLEditorWidget
$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>";
$sHtmlValue = "<div class=\"field_input_zone field_input_html\"><textarea class=\"htmlEditor\" title=\"$sHelpText\" name=\"attr_{$this->m_sFieldPrefix}{$sCode}\" rows=\"10\" cols=\"10\" id=\"$iId\">$sValue</textarea></div>$sValidationField";
// Replace the text area with CKEditor
// To change the default settings of the editor,
@@ -99,9 +98,26 @@ class UIHTMLEditorWidget
// 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");
$oPage->add_ready_script(
<<<EOF
$('#$iId').bind('update', function(evt){
BlockField('cke_$iId', $('#$iId').prop('disabled'));
//Delayed execution - ckeditor must be properly initialized before setting readonly
var retryCount = 0;
var oMe = $('#$iId');
var delayedSetReadOnly = function () {
if (oMe.data('ckeditorInstance').editable() == undefined && retryCount++ < 10) {
setTimeout(delayedSetReadOnly, retryCount * 100); //Wait a while longer each iteration
}
else
{
oMe.data('ckeditorInstance').setReadOnly(oMe.prop('disabled'));
}
};
setTimeout(delayedSetReadOnly, 50);
});
EOF
);
return $sHtmlValue;
}
}
?>

View File

@@ -1,5 +1,5 @@
<?php
// Copyright (C) 2010-2015 Combodo SARL
// Copyright (C) 2010-2017 Combodo SARL
//
// This file is part of iTop.
//
@@ -19,7 +19,7 @@
/**
* Class UILinksWidgetDirect
*
* @copyright Copyright (C) 2010-2015 Combodo SARL
* @copyright Copyright (C) 2010-2017 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
@@ -30,7 +30,14 @@ class UILinksWidgetDirect
protected $sInputid;
protected $sNameSuffix;
protected $sLinkedClass;
/**
* UILinksWidgetDirect constructor.
* @param string $sClass
* @param string $sAttCode
* @param string $sInputId
* @param string $sNameSuffix
*/
public function __construct($sClass, $sAttCode, $sInputId, $sNameSuffix = '')
{
$this->sClass = $sClass;
@@ -71,8 +78,15 @@ class UILinksWidgetDirect
}
}
public function Display(WebPage $oPage, DBObjectSet $oValue, $aArgs = array(), $sFormPrefix, $oCurrentObj)
/**
* @param WebPage $oPage
* @param DBObjectSet|ormLinkSet $oValue
* @param array $aArgs
* @param string $sFormPrefix
* @param DBObject $oCurrentObj
*/
public function Display(WebPage $oPage, $oValue, $aArgs = array(), $sFormPrefix, $oCurrentObj)
{
$oLinksetDef = MetaModel::GetAttributeDef($this->sClass, $this->sAttCode);
switch($oLinksetDef->GetEditMode())
@@ -89,7 +103,7 @@ class UILinksWidgetDirect
$sDefault = "default[$sExtKeyToMe]=".$oCurrentObj->GetKey();
$oAppContext = new ApplicationContext();
$sParams = $oAppContext->GetForLink();
$oPage->p("<a target=\"_blank\" href=\"".utils::GetAbsoluteUrlAppRoot()."pages/UI.php?operation=new&class=$sTargetClass&$sParams{$sDefault}\">".Dict::Format('UI:ClickToCreateNew', Metamodel::GetName($sTargetClass))."</a>\n");
$oPage->p("<a target=\"_blank\" href=\"".utils::GetAbsoluteUrlAppRoot()."pages/UI.php?operation=new&class=$sTargetClass&$sParams&{$sDefault}\">".Dict::Format('UI:ClickToCreateNew', Metamodel::GetName($sTargetClass))."</a>\n");
}
$this->DisplayAsBlock($oPage, $oValue, $aArgs = array(), $sFormPrefix, $oCurrentObj, false /* bDisplayMenu*/);
break;
@@ -115,8 +129,16 @@ class UILinksWidgetDirect
$this->DisplayAsBlock($oPage, $oValue, $aArgs = array(), $sFormPrefix, $oCurrentObj, true /* bDisplayMenu*/);
}
}
protected function DisplayAsBlock(WebPage $oPage, DBObjectSet $oValue, $aArgs = array(), $sFormPrefix, $oCurrentObj, $bDisplayMenu)
/**
* @param WebPage $oPage
* @param DBObjectSet $oValue
* @param array $aArgs
* @param string $sFormPrefix
* @param DBObject $oCurrentObj
* @param bool $bDisplayMenu
*/
protected function DisplayAsBlock(WebPage $oPage, $oValue, $aArgs = array(), $sFormPrefix, $oCurrentObj, $bDisplayMenu)
{
$oLinksetDef = MetaModel::GetAttributeDef($this->sClass, $this->sAttCode);
$sTargetClass = $oLinksetDef->GetLinkedClass();
@@ -143,6 +165,7 @@ class UILinksWidgetDirect
'target_attr' => $oLinksetDef->GetExtKeyToMe(),
'object_id' => $oCurrentObj ? $oCurrentObj->GetKey() : null,
'menu' => $bDisplayMenu,
'menu_actions_target' => '_blank',
'default' => $aDefaults,
'table_id' => $this->sClass.'_'.$this->sAttCode,
);
@@ -151,46 +174,12 @@ class UILinksWidgetDirect
$oBlock->Display($oPage, $this->sInputid, $aParams);
}
}
protected function DisplayEditInPlace(WebPage $oPage, DBObjectSet $oValue, $aArgs = array(), $sFormPrefix, $oCurrentObj, $aButtons = array('create', 'delete'))
{
$aAttribs = $this->GetTableConfig();
$oValue->Rewind();
$oPage->add('<table class="listContainer" id="'.$this->sInputid.'"><tr><td>');
$aData = array();
while($oLinkObj = $oValue->Fetch())
{
$aRow = array();
$aRow['form::select'] = '<input type="checkbox" class="selectList'.$this->sInputid.'" value="'.$oLinkObj->GetKey().'"/>';
foreach($this->aZlist as $sLinkedAttCode)
{
$aRow[$sLinkedAttCode] = $oLinkObj->GetAsHTML($sLinkedAttCode);
}
$aData[] = $aRow;
}
$oPage->table($aAttribs, $aData);
$oPage->add('</td></tr></table>'); //listcontainer
$sInputName = $sFormPrefix.'attr_'.$this->sAttCode;
$aLabels = array(
'delete' => Dict::S('UI:Button:Delete'),
// 'modify' => 'Modify...' ,
'creation_title' => Dict::Format('UI:CreationTitle_Class', MetaModel::GetName($this->sLinkedClass)),
'create' => Dict::Format('UI:ClickToCreateNew', MetaModel::GetName($this->sLinkedClass)),
'remove' => Dict::S('UI:Button:Remove'),
'add' => Dict::Format('UI:AddAnExisting_Class', MetaModel::GetName($this->sLinkedClass)),
'selection_title' => Dict::Format('UI:SelectionOf_Class', MetaModel::GetName($this->sLinkedClass)),
);
$oContext = new ApplicationContext();
$sSubmitUrl = utils::GetAbsoluteUrlAppRoot().'pages/ajax.render.php?'.$oContext->GetForLink();
$sJSONLabels = json_encode($aLabels);
$sJSONButtons = json_encode($aButtons);
$sWizHelper = 'oWizardHelper'.$sFormPrefix;
$oPage->add_ready_script("$('#{$this->sInputid}').directlinks({class_name: '$this->sClass', att_code: '$this->sAttCode', input_name:'$sInputName', labels: $sJSONLabels, submit_to: '$sSubmitUrl', buttons: $sJSONButtons, oWizardHelper: $sWizHelper });");
}
public function GetObjectCreationDlg(WebPage $oPage, $sProposedRealClass = '')
/**
* @param WebPage $oPage
* @param string $sProposedRealClass
*/
public function GetObjectCreationDlg(WebPage $oPage, $sProposedRealClass = '', $oSourceObj = null)
{
// For security reasons: check that the "proposed" class is actually a subclass of the linked class
// and that the current user is allowed to create objects of this class
@@ -215,14 +204,17 @@ class UILinksWidgetDirect
$aKeys = array_keys($aPossibleClasses);
$sRealClass = $aKeys[0];
}
if ($sRealClass != '')
{
$oPage->add("<h1>".MetaModel::GetClassIcon($sRealClass)."&nbsp;".Dict::Format('UI:CreationTitle_Class', MetaModel::GetName($sRealClass))."</h1>\n");
$oLinksetDef = MetaModel::GetAttributeDef($this->sClass, $this->sAttCode);
$sExtKeyToMe = $oLinksetDef->GetExtKeyToMe();
$aFieldFlags = array( $sExtKeyToMe => OPT_ATT_HIDDEN);
cmdbAbstractObject::DisplayCreationForm($oPage, $sRealClass, null, array(), array('formPrefix' => $this->sInputid, 'noRelations' => true, 'fieldsFlags' => $aFieldFlags));
$oObj = DBObject::MakeDefaultInstance($sRealClass);
$aPrefillParam = array('source_obj' => $oSourceObj);
$oObj->PrefillForm('creation_from_editinplace', $aPrefillParam);
cmdbAbstractObject::DisplayCreationForm($oPage, $sRealClass, $oObj, array(), array('formPrefix' => $this->sInputid, 'noRelations' => true, 'fieldsFlags' => $aFieldFlags));
}
else
{
@@ -239,13 +231,89 @@ class UILinksWidgetDirect
}
$oPage->add('</div></div>');
}
public function GetObjectsSelectionDlg($oPage, $oCurrentObj)
/**
* @param WebPage $oPage
* @param DBObjectSet $oValue
* @param array $aArgs
* @param string $sFormPrefix
* @param DBObject $oCurrentObj
* @param array $aButtons
*/
protected function DisplayEditInPlace(WebPage $oPage, $oValue, $aArgs = array(), $sFormPrefix, $oCurrentObj, $aButtons = array('create', 'delete'))
{
$aAttribs = $this->GetTableConfig();
$oValue->Rewind();
$oPage->add('<table class="listContainer" id="'.$this->sInputid.'"><tr><td>');
$aData = array();
while($oLinkObj = $oValue->Fetch())
{
$aRow = array();
$aRow['form::select'] = '<input type="checkbox" class="selectList'.$this->sInputid.'" value="'.$oLinkObj->GetKey().'"/>';
foreach($this->aZlist as $sLinkedAttCode)
{
$aRow[$sLinkedAttCode] = $oLinkObj->GetAsHTML($sLinkedAttCode);
}
$aData[] = $aRow;
}
$oPage->table($aAttribs, $aData);
$oPage->add('</td></tr></table>'); //listcontainer
$sInputName = $sFormPrefix.'attr_'.$this->sAttCode;
$aLabels = array(
'delete' => Dict::S('UI:Button:Delete'),
// 'modify' => 'Modify...' ,
'creation_title' => Dict::Format('UI:CreationTitle_Class', MetaModel::GetName($this->sLinkedClass)),
'create' => Dict::Format('UI:ClickToCreateNew', MetaModel::GetName($this->sLinkedClass)),
'remove' => Dict::S('UI:Button:Remove'),
'add' => Dict::Format('UI:AddAnExisting_Class', MetaModel::GetName($this->sLinkedClass)),
'selection_title' => Dict::Format('UI:SelectionOf_Class', MetaModel::GetName($this->sLinkedClass)),
);
$oContext = new ApplicationContext();
$sSubmitUrl = utils::GetAbsoluteUrlAppRoot().'pages/ajax.render.php?'.$oContext->GetForLink();
$sJSONLabels = json_encode($aLabels);
$sJSONButtons = json_encode($aButtons);
$sWizHelper = 'oWizardHelper'.$sFormPrefix;
// Don't automatically launch the search if the table is huge
$bDoSearch = !utils::IsHighCardinality($this->sLinkedClass);
$sJSDoSearch = $bDoSearch ? 'true' : 'false';
$oPage->add_ready_script("$('#{$this->sInputid}').directlinks({class_name: '$this->sClass', att_code: '$this->sAttCode', input_name:'$sInputName', labels: $sJSONLabels, submit_to: '$sSubmitUrl', buttons: $sJSONButtons, oWizardHelper: $sWizHelper, do_search: $sJSDoSearch});");
}
/**
* @param WebPage $oPage
* @param DBObject $oCurrentObj
* @param $aAlreadyLinked
*
* @throws \CoreException
* @throws \Exception
* @throws \OQLException
*/
public function GetObjectsSelectionDlg($oPage, $oCurrentObj, $aAlreadyLinked)
{
$sHtml = "<div class=\"wizContainer\" style=\"vertical-align:top;\">\n";
$oLinksetDef = MetaModel::GetAttributeDef($this->sClass, $this->sAttCode);
$valuesDef = $oLinksetDef->GetValuesDef();
$oHiddenFilter = new DBObjectSearch($this->sLinkedClass);
if (($oCurrentObj != null) && MetaModel::IsSameFamilyBranch($this->sLinkedClass, $this->sClass))
{
// Prevent linking to self if the linked object is of the same family
// and already present in the database
if (!$oCurrentObj->IsNew())
{
$oHiddenFilter->AddCondition('id', $oCurrentObj->GetKey(), '!=');
}
}
if (count($aAlreadyLinked) > 0)
{
$oHiddenFilter->AddCondition('id', $aAlreadyLinked, 'NOTIN');
}
$oHiddenCriteria = $oHiddenFilter->GetCriteria();
$aArgs = $oHiddenFilter->GetInternalParams();
$sHiddenCriteria = $oHiddenCriteria->Render($aArgs);
$oLinkSetDef = MetaModel::GetAttributeDef($this->sClass, $this->sAttCode);
$valuesDef = $oLinkSetDef->GetValuesDef();
if ($valuesDef === null)
{
$oFilter = new DBObjectSearch($this->sLinkedClass);
@@ -258,12 +326,26 @@ class UILinksWidgetDirect
}
$oFilter = DBObjectSearch::FromOQL($valuesDef->GetFilterExpression());
}
if ($oCurrentObj != null)
{
$this->SetSearchDefaultFromContext($oCurrentObj, $oFilter);
$aArgs = array_merge($oCurrentObj->ToArgs('this'), $oFilter->GetInternalParams());
$oFilter->SetInternalParams($aArgs);
}
$oBlock = new DisplayBlock($oFilter, 'search', false);
$sHtml .= $oBlock->GetDisplay($oPage, "SearchFormToAdd_{$this->sInputid}", array('open' => true));
$sHtml .= $oBlock->GetDisplay($oPage, "SearchFormToAdd_{$this->sInputid}",
array(
'result_list_outer_selector' => "SearchResultsToAdd_{$this->sInputid}",
'table_id' => "add_{$this->sInputid}",
'table_inner_id' => "ResultsToAdd_{$this->sInputid}",
'selection_mode' => true,
'cssCount' => "#count_{$this->sInputid}",
'query_params' => $oFilter->GetInternalParams(),
'hidden_criteria' => $sHiddenCriteria,
)
);
$sHtml .= "<form id=\"ObjectsAddForm_{$this->sInputid}\">\n";
$sHtml .= "<div id=\"SearchResultsToAdd_{$this->sInputid}\" style=\"vertical-align:top;background: #fff;height:100%;overflow:auto;padding:0;border:0;\">\n";
$sHtml .= "<div style=\"background: #fff; border:0; text-align:center; vertical-align:middle;\"><p>".Dict::S('UI:Message:EmptyList:UseSearchForm')."</p></div>\n";
@@ -273,16 +355,15 @@ class UILinksWidgetDirect
$sHtml .= "</div>\n";
$sHtml .= "</form>\n";
$oPage->add($sHtml);
//$oPage->add_ready_script("$('#SearchFormToAdd_{$this->sAttCode}{$this->sNameSuffix} form').bind('submit.uilinksWizard', oWidget{$this->sInputId}.SearchObjectsToAdd);");
//$oPage->add_ready_script("$('#SearchFormToAdd_{$this->sAttCode}{$this->sNameSuffix}').resize(oWidget{$this->siInputId}.UpdateSizes);");
}
/**
* Search for objects to be linked to the current object (i.e "remote" objects)
* @param WebPage $oP The page used for the output (usually an AjaxWebPage)
* @param string $sRemoteClass Name of the "remote" class to perform the search on, must be a derived class of $this->sLinkedClass
* @param array $aAlreadyLinked Array of indentifiers of objects which are already linke to the current object (or about to be linked)
* @param DBObject $oCurrentObj The object currently being edited... if known...
* @throws Exception
*/
public function SearchObjectsToAdd(WebPage $oP, $sRemoteClass = '', $aAlreadyLinked = array(), $oCurrentObj = null)
{
@@ -290,11 +371,11 @@ class UILinksWidgetDirect
{
$sRemoteClass = $this->sLinkedClass;
}
$oLinksetDef = MetaModel::GetAttributeDef($this->sClass, $this->sAttCode);
$valuesDef = $oLinksetDef->GetValuesDef();
$oLinkSetDef = MetaModel::GetAttributeDef($this->sClass, $this->sAttCode);
$valuesDef = $oLinkSetDef->GetValuesDef();
if ($valuesDef === null)
{
$oFilter = new DBObjectSearch($this->sLinkedClass);
$oFilter = new DBObjectSearch($sRemoteClass);
}
else
{
@@ -308,7 +389,7 @@ class UILinksWidgetDirect
if (($oCurrentObj != null) && MetaModel::IsSameFamilyBranch($sRemoteClass, $this->sClass))
{
// Prevent linking to self if the linked object is of the same family
// and laready present in the database
// and already present in the database
if (!$oCurrentObj->IsNew())
{
$oFilter->AddCondition('id', $oCurrentObj->GetKey(), '!=');
@@ -320,6 +401,8 @@ class UILinksWidgetDirect
}
if ($oCurrentObj != null)
{
$this->SetSearchDefaultFromContext($oCurrentObj, $oFilter);
$aArgs = array_merge($oCurrentObj->ToArgs('this'), $oFilter->GetInternalParams());
$oFilter->SetInternalParams($aArgs);
}
@@ -327,6 +410,10 @@ class UILinksWidgetDirect
$oBlock->Display($oP, "ResultsToAdd_{$this->sInputid}", array('menu' => false, 'cssCount'=> '#count_'.$this->sInputid , 'selection_mode' => true, 'table_id' => 'add_'.$this->sInputid)); // Don't display the 'Actions' menu on the results
}
/**
* @param WebPage $oP
* @param $oFullSetFilter
*/
public function DoAddObjects(WebPage $oP, $oFullSetFilter)
{
$aLinkedObjectIds = utils::ReadMultipleSelection($oFullSetFilter);
@@ -354,7 +441,14 @@ class UILinksWidgetDirect
}
return $aAttribs;
}
/**
* @param WebPage $oPage
* @param string $sRealClass
* @param array $aValues
* @param int $iTempId
* @return mixed
*/
public function GetRow($oPage, $sRealClass, $aValues, $iTempId)
{
if ($sRealClass == '')
@@ -366,7 +460,13 @@ class UILinksWidgetDirect
return $this->GetObjectRow($oPage, $oLinkObj, $iTempId);
}
/**
* @param WebPage $oPage
* @param $oLinkObj
* @param int $iTempId
* @return mixed
*/
protected function GetObjectRow($oPage, $oLinkObj, $iTempId)
{
$aAttribs = $this->GetTableConfig();
@@ -382,7 +482,7 @@ class UILinksWidgetDirect
/**
* Initializes the default search parameters based on 1) a 'current' object and 2) the silos defined by the context
* @param DBObject $oSourceObj
* @param DBSearch $oSearch
* @param DBSearch|DBObjectSearch $oSearch
*/
protected function SetSearchDefaultFromContext($oSourceObj, &$oSearch)
{
@@ -401,7 +501,6 @@ class UILinksWidgetDirect
if (MetaModel::IsValidAttCode($sSrcClass, $sAttCode))
{
$oAttDef = MetaModel::GetAttributeDef($sSrcClass, $sAttCode);
$defaultValue = $oSourceObj->Get($sAttCode);
// Find the attcode for the same 'context' parameter in the destination class

File diff suppressed because it is too large Load Diff

View File

@@ -58,26 +58,32 @@ class UIPasswordWidget
$sConfirmPasswordValue = $aPasswordValues ? $aPasswordValues['confirm'] : '*****';
$sChangedValue = (($sPasswordValue != '*****') || ($sConfirmPasswordValue != '*****')) ? 1 : 0;
$sHtmlValue = '';
$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 .= '<div class="field_input_zone field_input_onewaypassword">';
$sHtmlValue .= '<input type="password" maxlength="255" name="attr_'.$sCode.'[value]" id="'.$this->iId.'" value="'.htmlentities($sPasswordValue, ENT_QUOTES, 'UTF-8').'"/>';
$sHtmlValue .= '<input type="password" maxlength="255" id="'.$this->iId.'_confirm" value="'.htmlentities($sConfirmPasswordValue, ENT_QUOTES, 'UTF-8').'" name="attr_'.$sCode.'[confirm]"/>';
$sHtmlValue .= '<span>'.Dict::S('UI:PasswordConfirm').'</span>';
$sHtmlValue .= '<input id="'.$this->iId.'_reset" type="button" value="'.Dict::S('UI:Button:ResetPassword').'" onClick="ResetPwd(\''.$this->iId.'\');">';
$sHtmlValue .= '<input type="hidden" id="'.$this->iId.'_changed" name="attr_'.$sCode.'[changed]" value="'.$sChangedValue.'"/>';
$sHtmlValue .= '</div>';
$sHtmlValue .= '<span class="form_validation" id="v_'.$this->iId.'"></span><span class="field_status" id="fstatus_'.$this->iId.'"></span>';
$oPage->add_ready_script("$('#$this->iId').bind('keyup change', function(evt) { return PasswordFieldChanged('$this->iId') } );"); // Bind to a custom event: validate
$oPage->add_ready_script("$('#$this->iId').bind('keyup change validate', function(evt, sFormId) { return ValidatePasswordField('$this->iId', sFormId) } );"); // Bind to a custom event: validate
$oPage->add_ready_script("$('#{$this->iId}_confirm').bind('keyup change', function(evt, sFormId) { return ValidatePasswordField('$this->iId', sFormId) } );"); // Bind to a custom event: validate
$oPage->add_ready_script("$('#{$this->iId}').bind('update', function(evt, sFormId)
{
if ($(this).attr('disabled'))
if ($(this).prop('disabled'))
{
$('#{$this->iId}_confirm').attr('disabled', 'disabled');
$('#{$this->iId}_changed').attr('disabled', 'disabled');
$('#{$this->iId}_reset').attr('disabled', 'disabled');
$('#{$this->iId}_confirm').prop('disabled', true);
$('#{$this->iId}_changed').prop('disabled', true);
$('#{$this->iId}_reset').prop('disabled', true);
}
else
{
$('#{$this->iId}_confirm').removeAttr('disabled');
$('#{$this->iId}_changed').removeAttr('disabled');
$('#{$this->iId}_reset').removeAttr('disabled');
$('#{$this->iId}_confirm').prop('disabled', false);
$('#{$this->iId}_changed').prop('disabled', false);
$('#{$this->iId}_reset').prop('disabled', false);
}
}
);"); // Bind to a custom event: update to handle enabling/disabling

View File

@@ -0,0 +1,115 @@
<?php
/**
*
* Copyright (C) 2010-2018 Combodo SARL
*
* This file is part of iTop.
*
* iTop is free software; you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* iTop is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with iTop. If not, see <http://www.gnu.org/licenses/>
*
*/
require_once(APPROOT.'/application/webpage.class.inc.php');
require_once(APPROOT.'/application/displayblock.class.inc.php');
class UISearchFormForeignKeys
{
public function __construct($sTargetClass, $iInputId = null)
{
$this->m_sRemoteClass = $sTargetClass;
$this->m_iInputId = $iInputId;
}
/**
* @param WebPage $oPage
*
* @param $sTitle
*
* @throws \Exception
*/
public function ShowModalSearchForeignKeys($oPage, $sTitle)
{
$sHtml = "<div class=\"wizContainer\" style=\"vertical-align:top;\">\n";
$oFilter = new DBObjectSearch($this->m_sRemoteClass);
$oBlock = new DisplayBlock($oFilter, 'search', false);
$sHtml .= $oBlock->GetDisplay($oPage, "SearchFormToAdd_{$this->m_iInputId}",
array(
'menu' => false,
'result_list_outer_selector' => "SearchResultsToAdd_{$this->m_iInputId}",
'table_id' => "add_{$this->m_iInputId}",
'table_inner_id' => "ResultsToAdd_{$this->m_iInputId}",
'selection_mode' => true,
'cssCount' => "#count_{$this->m_iInputId}",
'query_params' => $oFilter->GetInternalParams(),
));
$sHtml .= "<form id=\"ObjectsAddForm_{$this->m_iInputId}\">\n";
$sHtml .= "<div id=\"SearchResultsToAdd_{$this->m_iInputId}\" style=\"vertical-align:top;background: #fff;height:100%;overflow:auto;padding:0;border:0;\">\n";
$sHtml .= "<div style=\"background: #fff; border:0; text-align:center; vertical-align:middle;\"><p>".Dict::S('UI:Message:EmptyList:UseSearchForm')."</p></div>\n";
$sHtml .= "</div>\n";
$sHtml .= "<input type=\"hidden\" id=\"count_{$this->m_iInputId}\" value=\"0\"/>";
$sHtml .= "<input type=\"button\" value=\"".Dict::S('UI:Button:Cancel')."\" onClick=\"$('#dlg_{$this->m_iInputId}').dialog('close');\">&nbsp;&nbsp;<input id=\"btn_ok_{$this->m_iInputId}\" disabled=\"disabled\" type=\"button\" onclick=\"return oForeignKeysWidget{$this->m_iInputId}.DoAddObjects(this.id);\" value=\"".Dict::S('UI:Button:Add')."\">";
$sHtml .= "</div>\n";
$sHtml .= "</form>\n";
$oPage->add($sHtml);
$oPage->add_ready_script("$('#dlg_{$this->m_iInputId}').dialog({ width: $(window).width()*0.8, height: $(window).height()*0.8, autoOpen: false, modal: true, resizeStop: oForeignKeysWidget{$this->m_iInputId}.UpdateSizes });");
$oPage->add_ready_script("$('#dlg_{$this->m_iInputId}').dialog('option', {title:'$sTitle'});");
$oPage->add_ready_script("$('#SearchFormToAdd_{$this->m_iInputId} form').bind('submit.uilinksWizard', oForeignKeysWidget{$this->m_iInputId}.SearchObjectsToAdd);");
$oPage->add_ready_script("$('#SearchFormToAdd_{$this->m_iInputId}').resize(oForeignKeysWidget{$this->m_iInputId}.UpdateSizes);");
}
public function GetFullListForeignKeysFromSelection($oPage, $oFullSetFilter)
{
try
{
$aLinkedObjects = utils::ReadMultipleSelectionWithFriendlyname($oFullSetFilter);
$oPage->add(json_encode($aLinkedObjects));
}
catch (CoreException $e)
{
http_response_code(500);
$oPage->add(json_encode(array('error' => $e->GetMessage())));
IssueLog::Error($e->getMessage()."\nDebug trace:\n".$e->getTraceAsString());
}
}
/**
* Search for objects to be linked to the current object (i.e "remote" objects)
*
* @param WebPage $oP The page used for the output (usually an AjaxWebPage)
* @param string $sRemoteClass Name of the "remote" class to perform the search on, must be a derived class of m_sRemoteClass
*
* @throws \Exception
*/
public function ListResultsSearchForeignKeys(WebPage $oP, $sRemoteClass = '')
{
if ($sRemoteClass != '')
{
// assert(MetaModel::IsParentClass($this->m_sRemoteClass, $sRemoteClass));
$oFilter = new DBObjectSearch($sRemoteClass);
}
else
{
// No remote class specified use the one defined in the linkedset
$oFilter = new DBObjectSearch($this->m_sRemoteClass);
}
$oBlock = new DisplayBlock($oFilter, 'list', false);
$oBlock->Display($oP, "ResultsToAdd_{$this->m_iInputId}",
array('menu' => false, 'cssCount' => "#count_{$this->m_iInputId}", 'selection_mode' => true, 'table_id' => "add_{$this->m_iInputId}"));
}
}

View File

@@ -1,423 +0,0 @@
<?php
// Copyright (C) 2010-2012 Combodo SARL
//
// This file is part of iTop.
//
// iTop is free software; you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// iTop is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with iTop. If not, see <http://www.gnu.org/licenses/>
/**
* Class UILinksWizard
*
* @copyright Copyright (C) 2010-2012 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
class UILinksWizard
{
protected $m_sClass;
protected $m_sLinkageAttr;
protected $m_iObjectId;
protected $m_sLinkedClass;
protected $m_sLinkingAttCode;
protected $m_aEditableFields;
protected $m_aTableConfig;
public function __construct($sClass, $sLinkageAttr, $iObjectId, $sLinkedClass = '')
{
$this->m_sClass = $sClass;
$this->m_sLinkageAttr = $sLinkageAttr;
$this->m_iObjectId = $iObjectId;
$this->m_sLinkedClass = $sLinkedClass; // Will try to guess below, if it's empty
$this->m_sLinkingAttCode = ''; // Will be filled once we've found the attribute corresponding to the linked class
$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; $('.selection').each( function() { this.checked = value; } );OnSelectChange();\">", 'description' => Dict::S('UI:SelectAllToggle+'));
foreach(MetaModel::GetAttributesList($this->m_sClass) as $sAttCode)
{
$oAttDef = MetaModel::GetAttributeDef($this->m_sClass, $sAttCode);
if ($oAttDef->IsExternalKey() && ($sAttCode != $this->m_sLinkageAttr))
{
if (empty($this->m_sLinkedClass))
{
// This is a class of objects we can manage !
// Since nothing was specify, any class will do !
$this->m_sLinkedClass = $oAttDef->GetTargetClass();
$this->m_sLinkingAttCode = $sAttCode;
}
else if ($this->m_sLinkedClass == $oAttDef->GetTargetClass())
{
// This is the class of objects we want to manage !
$this->m_sLinkingAttCode = $sAttCode;
}
}
else if ( (!$oAttDef->IsExternalKey()) && (!$oAttDef->IsExternalField()))
{
$this->m_aEditableFields[] = $sAttCode;
$this->m_aTableConfig[$sAttCode] = array( 'label' => $oAttDef->GetLabel(), 'description' => $oAttDef->GetDescription());
}
}
if (empty($this->m_sLinkedClass))
{
throw( new Exception(Dict::Format('UI:Error:IncorrectLinkDefinition_LinkedClass_Class', $sLinkedClass, $sClass)));
}
foreach(MetaModel::GetZListItems($this->m_sLinkedClass, 'list') as $sFieldCode)
{
$oAttDef = MetaModel::GetAttributeDef($this->m_sLinkedClass, $sFieldCode);
$this->m_aTableConfig['static::'.$sFieldCode] = array( 'label' => $oAttDef->GetLabel(), 'description' => $oAttDef->GetDescription());
}
}
public function Display(WebPage $oP, $aExtraParams = array())
{
$oAttDef = MetaModel::GetAttributeDef($this->m_sClass, $this->m_sLinkageAttr);
$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->GetRawName());
$oP->add("<div class=\"wizContainer\">\n");
$oP->add("<form method=\"post\">\n");
$oP->add("<div class=\"page_header\">\n");
$oP->add("<input type=\"hidden\" id=\"linksToRemove\" name=\"linksToRemove\" value=\"\">\n");
$oP->add("<input type=\"hidden\" name=\"operation\" value=\"do_modify_links\">\n");
$oP->add("<input type=\"hidden\" name=\"class\" value=\"{$this->m_sClass}\">\n");
$oP->add("<input type=\"hidden\" name=\"linkage\" value=\"{$this->m_sLinkageAttr}\">\n");
$oP->add("<input type=\"hidden\" name=\"object_id\" value=\"{$this->m_iObjectId}\">\n");
$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(
<<<EOF
function OnSelectChange()
{
var nbChecked = $('.selection:checked').length;
if (nbChecked > 0)
{
$('#btnRemove').removeAttr('disabled');
}
else
{
$('#btnRemove').attr('disabled','disabled');
}
}
function RemoveSelected()
{
$('.selection:checked').each(
function()
{
$('#linksToRemove').val($('#linksToRemove').val() + ' ' + this.value);
$('#row_'+this.value).remove();
}
);
// Disable the button since all the selected items have been removed
$('#btnRemove').attr('disabled','disabled');
// Re-run the zebra plugin to properly highlight the remaining lines
$('.listResults').trigger('update');
}
function AddObjects()
{
// TO DO: compute the list of objects already linked with the current Object
$.post( GetAbsoluteUrlAppRoot()+'pages/ajax.render.php', { 'operation': 'addObjects',
'class': '{$this->m_sClass}',
'linkageAttr': '{$this->m_sLinkageAttr}',
'linkedClass': '{$this->m_sLinkedClass}',
'objectId': '{$this->m_iObjectId}'
},
function(data)
{
$('#ModalDlg').html(data);
dlgWidth = $(document).width() - 100;
$('#ModalDlg').css('width', dlgWidth);
$('#ModalDlg').css('left', 50);
$('#ModalDlg').css('top', 50);
$('#ModalDlg').dialog( 'open' );
},
'html'
);
}
function SearchObjectsToAdd(currentFormId)
{
var theMap = { 'class': '{$this->m_sClass}',
'linkageAttr': '{$this->m_sLinkageAttr}',
'linkedClass': '{$this->m_sLinkedClass}',
'objectId': '{$this->m_iObjectId}'
}
if ($('#'+currentFormId+' :input[name=class]').val() != undefined)
{
theMap.linkedClass = $('#'+currentFormId+' :input[name=class]').val();
}
// Gather the parameters from the search form
$('#'+currentFormId+' :input').each(
function(i)
{
if (this.name != '')
{
theMap[this.name] = this.value;
}
}
);
theMap['operation'] = 'searchObjectsToAdd';
// Run the query and display the results
$.post( GetAbsoluteUrlAppRoot()+'pages/ajax.render.php', theMap,
function(data)
{
$('#SearchResultsToAdd').html(data);
$('#SearchResultsToAdd .listResults').tablesorter( { headers: {0: false}}, widgets: ['myZebra', 'truncatedList']} ); // sortable and zebra tables
},
'html'
);
return false;
}
function DoAddObjects(currentFormId)
{
var theMap = { 'class': '{$this->m_sClass}',
'linkageAttr': '{$this->m_sLinkageAttr}',
'linkedClass': '{$this->m_sLinkedClass}',
'objectId': '{$this->m_iObjectId}'
}
// Gather the parameters from the search form
$('#'+currentFormId+' :input').each(
function(i)
{
if ( (this.name != '') && ((this.type != 'checkbox') || (this.checked)) )
{
//console.log(this.type);
arrayExpr = /\[\]$/;
if (arrayExpr.test(this.name))
{
// Array
if (theMap[this.name] == undefined)
{
theMap[this.name] = new Array();
}
theMap[this.name].push(this.value);
}
else
{
theMap[this.name] = this.value;
}
}
}
);
theMap['operation'] = 'doAddObjects';
// Run the query and display the results
$.post( GetAbsoluteUrlAppRoot()+'pages/ajax.render.php', theMap,
function(data)
{
//console.log('Data: ' + data);
if (data != '')
{
$('#empty_row').remove();
}
$('.listResults tbody').append(data);
$('.listResults').trigger('update');
$('.listResults').tablesorter( { headers: {0: false}}, widgets: ['myZebra', 'truncatedList']} ); // sortable and zebra tables
},
'html'
);
$('#ModalDlg').dialog('close');
return false;
}
function InitForm()
{
// make sure that the form is clean
$('.selection').each( function() { this.checked = false; });
$('#btnRemove').attr('disabled','disabled');
$('#linksToRemove').val('');
}
function SubmitHook()
{
var the_form = this;
SearchObjectsToAdd(the_form.id);
return false;
}
EOF
);
$oP->add_ready_script("InitForm();");
$oFilter = new DBObjectSearch($this->m_sClass);
$oFilter->AddCondition($this->m_sLinkageAttr, $this->m_iObjectId, '=');
$oSet = new DBObjectSet($oFilter);
$aForm = array();
while($oCurrentLink = $oSet->Fetch())
{
$aRow = array();
$key = $oCurrentLink->GetKey();
$oLinkedObj = MetaModel::GetObject($this->m_sLinkedClass, $oCurrentLink->Get($this->m_sLinkingAttCode));
$aForm[$key] = $this->GetFormRow($oP, $oLinkedObj, $oCurrentLink);
}
//var_dump($aTableLabels);
//var_dump($aForm);
$this->DisplayFormTable($oP, $this->m_aTableConfig, $aForm);
$oP->add("<span style=\"float:left;\">&nbsp;&nbsp;&nbsp;<img src=\"../images/tv-item-last.gif\">&nbsp;&nbsp;<input id=\"btnRemove\" type=\"button\" value=\"".Dict::S('UI:RemoveLinkedObjectsOf_Class')."\" onClick=\"RemoveSelected();\" >");
$oP->add("&nbsp;&nbsp;&nbsp;<input id=\"btnAdd\" type=\"button\" value=\"".Dict::Format('UI:AddLinkedObjectsOf_Class', MetaModel::GetName($this->m_sLinkedClass))."\" onClick=\"AddObjects();\"></span>\n");
$oP->add("<span style=\"float:right;\"><input id=\"btnCancel\" type=\"button\" value=\"".Dict::S('UI:Button:Cancel')."\" onClick=\"BackToDetails('".$sTargetClass."', ".$this->m_iObjectId.", '', '');\">");
$oP->add("&nbsp;&nbsp;&nbsp;<input id=\"btnOk\" type=\"submit\" value=\"".Dict::S('UI:Button:Ok')."\"></span>\n");
$oP->add("<span style=\"clear:both;\"><p>&nbsp;</p></span>\n");
$oP->add("</div>\n");
$oP->add("</form>\n");
if (isset($aExtraParams['StartWithAdd']) && ($aExtraParams['StartWithAdd']))
{
$oP->add_ready_script("AddObjects();");
}
}
protected function GetFormRow($oP, $oLinkedObj, $currentLink = null )
{
$aRow = array();
if(is_object($currentLink))
{
$key = $currentLink->GetKey();
$sNameSuffix = "[$key]"; // To make a tabular form
$aRow['form::checkbox'] = "<input class=\"selection\" type=\"checkbox\" onChange=\"OnSelectChange();\" value=\"$key\">";
$aRow['form::checkbox'] .= "<input type=\"hidden\" name=\"linkId[$key]\" value=\"$key\">";
foreach($this->m_aEditableFields as $sFieldCode)
{
$oAttDef = MetaModel::GetAttributeDef($this->m_sClass, $sFieldCode);
$aRow[$sFieldCode] = cmdbAbstractObject::GetFormElementForField($oP, $this->m_sClass, $sFieldCode, $oAttDef, $currentLink->Get($sFieldCode), '' /* DisplayValue */, $key, $sNameSuffix);
}
}
else
{
// form for creating a new record
$sNameSuffix = "[$currentLink]"; // To make a tabular form
$aRow['form::checkbox'] = "<input class=\"selection\" type=\"checkbox\" onChange=\"OnSelectChange();\" value=\"$currentLink\">";
$aRow['form::checkbox'] .= "<input type=\"hidden\" name=\"linkId[$currentLink]\" value=\"$currentLink\">";
foreach($this->m_aEditableFields as $sFieldCode)
{
$oAttDef = MetaModel::GetAttributeDef($this->m_sClass, $sFieldCode);
$aRow[$sFieldCode] = cmdbAbstractObject::GetFormElementForField($oP, $this->m_sClass, $sFieldCode, $oAttDef, '' /* TO DO/ call GetDefaultValue($oObject->ToArgs()) */, '' /* DisplayValue */, '' /* id */, $sNameSuffix);
}
}
foreach(MetaModel::GetZListItems($this->m_sLinkedClass, 'list') as $sFieldCode)
{
$aRow['static::'.$sFieldCode] = $oLinkedObj->GetAsHTML($sFieldCode);
}
return $aRow;
}
protected function DisplayFormTable(WebPage $oP, $aConfig, $aData)
{
$oP->add("<table class=\"listResults\">\n");
// Header
$oP->add("<thead>\n");
$oP->add("<tr>\n");
foreach($aConfig as $sName=>$aDef)
{
$oP->add("<th title=\"".$aDef['description']."\">".$aDef['label']."</th>\n");
}
$oP->add("</tr>\n");
$oP->add("</thead>\n");
// Content
$oP->add("</tbody>\n");
if (count($aData) == 0)
{
$oP->add("<tr id=\"empty_row\"><td colspan=\"".count($aConfig)."\" style=\"text-align:center;\">".Dict::S('UI:Message:EmptyList:UseAdd')."</td></td>");
}
else
{
foreach($aData as $iRowId => $aRow)
{
$this->DisplayFormRow($oP, $aConfig, $aRow, $iRowId);
}
}
$oP->add("</tbody>\n");
// Footer
$oP->add("</table>\n");
}
protected function DisplayFormRow(WebPage $oP, $aConfig, $aRow, $iRowId)
{
$oP->add("<tr id=\"row_$iRowId\">\n");
foreach($aConfig as $sName=>$void)
{
$oP->add("<td>".$aRow[$sName]."</td>\n");
}
$oP->add("</tr>\n");
}
public function DisplayAddForm(WebPage $oP)
{
$oAttDef = MetaModel::GetAttributeDef($this->m_sClass, $this->m_sLinkageAttr);
$sTargetClass = $oAttDef->GetTargetClass();
$oTargetObj = MetaModel::GetObject($sTargetClass, $this->m_iObjectId);
$oP->add("<div class=\"wizContainer\">\n");
//$oP->add("<div class=\"page_header\">\n");
//$oP->add("<h1>".Dict::Format('UI:AddObjectsOf_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");
$oFilter = new DBObjectSearch($this->m_sLinkedClass);
$oSet = new CMDBObjectSet($oFilter);
$oBlock = new DisplayBlock($oFilter, 'search', false);
$oBlock->Display($oP, 'SearchFormToAdd', array('open' => true));
$oP->Add("<form id=\"ObjectsAddForm\" OnSubmit=\"return DoAddObjects(this.id);\">\n");
$oP->Add("<div id=\"SearchResultsToAdd\">\n");
$oP->Add("<div style=\"height: 100px; background: #fff;border-color:#F6F6F1 #E6E6E1 #E6E6E1 #F6F6F1; border-style:solid; border-width:3px; text-align: center; vertical-align: center;\"><p>".Dict::S('UI:Message:EmptyList:UseSearchForm')."</p></div>\n");
$oP->Add("</div>\n");
$oP->add("<input type=\"button\" value=\"".Dict::S('UI:Button:Cancel')."\" onClick=\"$('#ModalDlg').dialog('close');\">&nbsp;&nbsp;<input type=\"submit\" value=\"".Dict::S('UI:Button:Add')."\">");
$oP->Add("</div>\n");
$oP->Add("</form>\n");
$oP->add_ready_script("$('#ModalDlg').dialog('option', {title:'".Dict::Format('UI:AddObjectsOf_Class_LinkedWith_Class_Instance', MetaModel::GetName($this->m_sLinkedClass), MetaModel::GetName(get_class($oTargetObj)), "<span class=\"hilite\">".$oTargetObj->GetHyperlink()."</span>")."'});");
$oP->add_ready_script("$('div#SearchFormToAdd form').bind('submit.uilinksWizard', SubmitHook);");
}
public function SearchObjectsToAdd(WebPage $oP)
{
//$oAttDef = MetaModel::GetAttributeDef($this->m_sClass, $this->m_sLinkageAttr);
$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)); // Don't display the 'Actions' menu on the results
}
public function DoAddObjects(WebPage $oP, $aLinkedObjectIds = array())
{
//$oAttDef = MetaModel::GetAttributeDef($this->m_sClass, $this->m_sLinkageAttr);
//$sTargetClass = $oAttDef->GetTargetClass();
//$oP->Add("<!-- nb of objects to add: ".count($aLinkedObjectIds)." -->\n"); // Just to make sure it's not empty
$aTable = array();
foreach($aLinkedObjectIds as $iObjectId)
{
$oLinkedObj = MetaModel::GetObject($this->m_sLinkedClass, $iObjectId);
if (is_object($oLinkedObj))
{
$aRow = $this->GetFormRow($oP, $oLinkedObj, -$iObjectId ); // Not yet created link get negative Ids
$this->DisplayFormRow($oP, $this->m_aTableConfig, $aRow, -$iObjectId);
}
else
{
echo Dict::Format('UI:Error:Object_Class_Id_NotFound', $this->m_sLinkedClass, $iObjectId);
}
}
//var_dump($aTable);
//$oP->Add("<!-- end of added list -->\n"); // Just to make sure it's not empty
}
}
?>

View File

@@ -1,331 +1,331 @@
<?php
// Copyright (C) 2010-2012 Combodo SARL
//
// This file is part of iTop.
//
// iTop is free software; you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// iTop is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with iTop. If not, see <http://www.gnu.org/licenses/>
/**
* Class UIWizard
*
* @copyright Copyright (C) 2010-2012 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
class UIWizard
{
protected $m_oPage;
protected $m_sClass;
protected $m_sTargetState;
protected $m_aWizardSteps;
public function __construct($oPage, $sClass, $sTargetState = '')
{
$this->m_oPage = $oPage;
$this->m_sClass = $sClass;
if (empty($sTargetState))
{
$sTargetState = MetaModel::GetDefaultState($sClass);
}
$this->m_sTargetState = $sTargetState;
$this->m_aWizardSteps = $this->ComputeWizardStructure();
}
public function GetObjectClass() { return $this->m_sClass; }
public function GetTargetState() { return $this->m_sTargetState; }
public function GetWizardStructure() { return $this->m_aWizardSteps; }
/**
* Displays one step of the wizard
*/
public function DisplayWizardStep($aStep, $iStepIndex, &$iMaxInputId, &$aFieldsMap, $bFinishEnabled = false, $aArgs = array())
{
if ($iStepIndex == 1) // one big form that contains everything, to make sure that the uploaded files are posted too
{
$this->m_oPage->add("<form method=\"post\" enctype=\"multipart/form-data\" action=\"".utils::GetAbsoluteUrlAppRoot()."pages/UI.php\">\n");
}
$this->m_oPage->add("<div class=\"wizContainer\" id=\"wizStep$iStepIndex\" style=\"display:none;\">\n");
$this->m_oPage->add("<a name=\"step$iStepIndex\" />\n");
$aStates = MetaModel::EnumStates($this->m_sClass);
$aDetails = array();
$sJSHandlerCode = ''; // Javascript code to be executed each time this step of the wizard is entered
foreach($aStep as $sAttCode)
{
$oAttDef = MetaModel::GetAttributeDef($this->m_sClass, $sAttCode);
if ($oAttDef->IsWritable())
{
$sAttLabel = $oAttDef->GetLabel();
$iOptions = isset($aStates[$this->m_sTargetState]['attribute_list'][$sAttCode]) ? $aStates[$this->m_sTargetState]['attribute_list'][$sAttCode] : 0;
$aPrerequisites = $oAttDef->GetPrerequisiteAttributes();
if ($iOptions & (OPT_ATT_MANDATORY | OPT_ATT_MUSTCHANGE | OPT_ATT_MUSTPROMPT))
{
$aFields[$sAttCode] = array();
foreach($aPrerequisites as $sCode)
{
$aFields[$sAttCode][$sCode] = '';
}
}
if (count($aPrerequisites) > 0)
{
$aOptions[] = 'Prerequisites: '.implode(', ', $aPrerequisites);
}
$sFieldFlag = (($iOptions & (OPT_ATT_MANDATORY | OPT_ATT_MUSTCHANGE)) || (!$oAttDef->IsNullAllowed()) )? ' <span class="hilite">*</span>' : '';
$oDefaultValuesSet = $oAttDef->GetDefaultValue(/* $oObject->ToArgs() */); // @@@ TO DO: get the object's current value if the object exists
$sHTMLValue = cmdbAbstractObject::GetFormElementForField($this->m_oPage, $this->m_sClass, $sAttCode, $oAttDef, $oDefaultValuesSet, '', "att_$iMaxInputId", '', $iOptions, $aArgs);
$aFieldsMap["att_$iMaxInputId"] = $sAttCode;
$aDetails[] = array('label' => '<span title="'.$oAttDef->GetDescription().'">'.$oAttDef->GetLabel().$sFieldFlag.'</span>', 'value' => "<span id=\"field_att_$iMaxInputId\">$sHTMLValue</span>");
if ($oAttDef->GetValuesDef() != null)
{
$sJSHandlerCode .= "\toWizardHelper.RequestAllowedValues('$sAttCode');\n";
}
if ($oAttDef->GetDefaultValue() != null)
{
$sJSHandlerCode .= "\toWizardHelper.RequestDefaultValue('$sAttCode');\n";
}
if ($oAttDef->IsLinkSet())
{
$sJSHandlerCode .= "\toLinkWidgetatt_$iMaxInputId.Init();";
}
$iMaxInputId++;
}
}
//$aDetails[] = array('label' => '', 'value' => '<input type="button" value="Next &gt;&gt;">');
$this->m_oPage->details($aDetails);
$sBackButtonDisabled = ($iStepIndex <= 1) ? 'disabled' : '';
$sDisabled = $bFinishEnabled ? '' : 'disabled';
$nbSteps = count($this->m_aWizardSteps['mandatory']) + count($this->m_aWizardSteps['optional']);
$this->m_oPage->add("<div style=\"text-align:center\">
<input type=\"button\" value=\"".Dict::S('UI:Button:Back')."\" $sBackButtonDisabled onClick=\"GoToStep($iStepIndex, $iStepIndex - 1)\" />
<input type=\"button\" value=\"".Dict::S('UI:Button:Next')."\" onClick=\"GoToStep($iStepIndex, 1+$iStepIndex)\" />
<input type=\"button\" value=\"".Dict::S('UI:Button:Finish')."\" $sDisabled onClick=\"GoToStep($iStepIndex, 1+$nbSteps)\" />
</div>\n");
$this->m_oPage->add_script("
function OnEnterStep{$iStepIndex}()
{
oWizardHelper.ResetQuery();
oWizardHelper.UpdateWizard();
$sJSHandlerCode
oWizardHelper.AjaxQueryServer();
}
");
$this->m_oPage->add("</div>\n\n");
}
/**
* Display the final step of the wizard: a confirmation screen
*/
public function DisplayFinalStep($iStepIndex, $aFieldsMap)
{
$oAppContext = new ApplicationContext();
$this->m_oPage->add("<div class=\"wizContainer\" id=\"wizStep$iStepIndex\" style=\"display:none;\">\n");
$this->m_oPage->add("<a name=\"step$iStepIndex\" />\n");
$this->m_oPage->P(Dict::S('UI:Wizard:FinalStepTitle'));
$this->m_oPage->add("<input type=\"hidden\" name=\"operation\" value=\"wizard_apply_new\" />\n");
$this->m_oPage->add("<input type=\"hidden\" name=\"transaction_id\" value=\"".utils::GetNewTransactionId()."\" />\n");
$this->m_oPage->add("<input type=\"hidden\" id=\"wizard_json_obj\" name=\"json_obj\" value=\"\" />\n");
$sScript = "function OnEnterStep$iStepIndex() {\n";
foreach($aFieldsMap as $iInputId => $sAttCode)
{
$sScript .= "\toWizardHelper.UpdateCurrentValue('$sAttCode');\n";
}
$sScript .= "\toWizardHelper.Preview('object_preview');\n";
$sScript .= "\t$('#wizard_json_obj').val(oWizardHelper.ToJSON());\n";
$sScript .= "}\n";
$this->m_oPage->add_script($sScript);
$this->m_oPage->add("<div id=\"object_preview\">\n");
$this->m_oPage->add("</div>\n");
$this->m_oPage->add($oAppContext->GetForForm());
$this->m_oPage->add("<input type=\"button\" value=\"".Dict::S('UI:Button:Back')."\" onClick=\"GoToStep($iStepIndex, $iStepIndex - 1)\" />");
$this->m_oPage->add("<input type=\"submit\" value=\"Create ".MetaModel::GetName($this->m_sClass)."\" />\n");
$this->m_oPage->add("</div>\n");
$this->m_oPage->add("</form>\n");
}
/**
* Compute the order of the fields & pages in the wizard
* @param $oPage iTopWebPage The current page (used to display error messages)
* @param $sClass string Name of the class
* @param $sStateCode string Code of the target state of the object
* @return hash Two dimensional array: each element represents the list of fields for a given page
*/
protected function ComputeWizardStructure()
{
$aWizardSteps = array( 'mandatory' => array(), 'optional' => array());
$aFieldsDone = array(); // Store all the fields that are already covered by a previous step of the wizard
$aStates = MetaModel::EnumStates($this->m_sClass);
$sStateAttCode = MetaModel::GetStateAttributeCode($this->m_sClass);
$aMandatoryAttributes = array();
// Some attributes are always mandatory independently of the state machine (if any)
foreach(MetaModel::GetAttributesList($this->m_sClass) as $sAttCode)
{
$oAttDef = MetaModel::GetAttributeDef($this->m_sClass, $sAttCode);
if (!$oAttDef->IsExternalField() && !$oAttDef->IsNullAllowed() &&
$oAttDef->IsWritable() && ($sAttCode != $sStateAttCode) )
{
$aMandatoryAttributes[$sAttCode] = OPT_ATT_MANDATORY;
}
}
// Now check the attributes that are mandatory in the specified state
if ( (!empty($this->m_sTargetState)) && (count($aStates[$this->m_sTargetState]['attribute_list']) > 0) )
{
// Check all the fields that *must* be included in the wizard for this
// particular target state
$aFields = array();
foreach($aStates[$this->m_sTargetState]['attribute_list'] as $sAttCode => $iOptions)
{
if ( (isset($aMandatoryAttributes[$sAttCode])) &&
($aMandatoryAttributes[$sAttCode] & (OPT_ATT_MANDATORY | OPT_ATT_MUSTCHANGE | OPT_ATT_MUSTPROMPT)) )
{
$aMandatoryAttributes[$sAttCode] |= $iOptions;
}
else
{
$aMandatoryAttributes[$sAttCode] = $iOptions;
}
}
}
// Check all the fields that *must* be included in the wizard
// i.e. all mandatory, must-change or must-prompt fields that are
// not also read-only or hidden.
// Some fields may be required (null not allowed) from the database
// perspective, but hidden or read-only from the user interface perspective
$aFields = array();
foreach($aMandatoryAttributes as $sAttCode => $iOptions)
{
if ( ($iOptions & (OPT_ATT_MANDATORY | OPT_ATT_MUSTCHANGE | OPT_ATT_MUSTPROMPT)) &&
!($iOptions & (OPT_ATT_READONLY | OPT_ATT_HIDDEN)) )
{
$oAttDef = MetaModel::GetAttributeDef($this->m_sClass, $sAttCode);
$aPrerequisites = $oAttDef->GetPrerequisiteAttributes();
$aFields[$sAttCode] = array();
foreach($aPrerequisites as $sCode)
{
$aFields[$sAttCode][$sCode] = '';
}
}
}
// Now use the dependencies between the fields to order them
// Start from the order of the 'details'
$aList = MetaModel::FlattenZlist(MetaModel::GetZListItems($this->m_sClass, 'details'));
$index = 0;
$aOrder = array();
foreach($aFields as $sAttCode => $void)
{
$aOrder[$sAttCode] = 999; // At the end of the list...
}
foreach($aList as $sAttCode)
{
if (array_key_exists($sAttCode, $aFields))
{
$aOrder[$sAttCode] = $index;
}
$index++;
}
foreach($aFields as $sAttCode => $aDependencies)
{
// All fields with no remaining dependencies can be entered at this
// step of the wizard
if (count($aDependencies) > 0)
{
$iMaxPos = 0;
// Remove this field from the dependencies of the other fields
foreach($aDependencies as $sDependentAttCode => $void)
{
// position the current field after the ones it depends on
$iMaxPos = max($iMaxPos, 1+$aOrder[$sDependentAttCode]);
}
}
}
asort($aOrder);
$aCurrentStep = array();
foreach($aOrder as $sAttCode => $rank)
{
$aCurrentStep[] = $sAttCode;
$aFieldsDone[$sAttCode] = '';
}
$aWizardSteps['mandatory'][] = $aCurrentStep;
// Now computes the steps to fill the optional fields
$aFields = array(); // reset
foreach(MetaModel::ListAttributeDefs($this->m_sClass) as $sAttCode=>$oAttDef)
{
$iOptions = (isset($aStates[$this->m_sTargetState]['attribute_list'][$sAttCode])) ? $aStates[$this->m_sTargetState]['attribute_list'][$sAttCode] : 0;
if ( ($sStateAttCode != $sAttCode) &&
(!$oAttDef->IsExternalField()) &&
(($iOptions & (OPT_ATT_HIDDEN | OPT_ATT_READONLY)) == 0) &&
(!isset($aFieldsDone[$sAttCode])) )
{
// 'State', external fields, read-only and hidden fields
// and fields that are already listed in the wizard
// are removed from the 'optional' part of the wizard
$oAttDef = MetaModel::GetAttributeDef($this->m_sClass, $sAttCode);
$aPrerequisites = $oAttDef->GetPrerequisiteAttributes();
$aFields[$sAttCode] = array();
foreach($aPrerequisites as $sCode)
{
if (!isset($aFieldsDone[$sCode]))
{
// retain only the dependencies that were not covered
// in the 'mandatory' part of the wizard
$aFields[$sAttCode][$sCode] = '';
}
}
}
}
// Now use the dependencies between the fields to order them
while(count($aFields) > 0)
{
$aCurrentStep = array();
foreach($aFields as $sAttCode => $aDependencies)
{
// All fields with no remaining dependencies can be entered at this
// step of the wizard
if (count($aDependencies) == 0)
{
$aCurrentStep[] = $sAttCode;
$aFieldsDone[$sAttCode] = '';
unset($aFields[$sAttCode]);
// Remove this field from the dependencies of the other fields
foreach($aFields as $sUpdatedCode => $aDummy)
{
// remove the dependency
unset($aFields[$sUpdatedCode][$sAttCode]);
}
}
}
if (count($aCurrentStep) == 0)
{
// This step of the wizard would contain NO field !
$this->m_oPage->add(Dict::S('UI:Error:WizardCircularReferenceInDependencies'));
print_r($aFields);
break;
}
$aWizardSteps['optional'][] = $aCurrentStep;
}
return $aWizardSteps;
}
}
?>
<?php
// Copyright (C) 2010-2012 Combodo SARL
//
// This file is part of iTop.
//
// iTop is free software; you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// iTop is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with iTop. If not, see <http://www.gnu.org/licenses/>
/**
* Class UIWizard
*
* @copyright Copyright (C) 2010-2012 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
class UIWizard
{
protected $m_oPage;
protected $m_sClass;
protected $m_sTargetState;
protected $m_aWizardSteps;
public function __construct($oPage, $sClass, $sTargetState = '')
{
$this->m_oPage = $oPage;
$this->m_sClass = $sClass;
if (empty($sTargetState))
{
$sTargetState = MetaModel::GetDefaultState($sClass);
}
$this->m_sTargetState = $sTargetState;
$this->m_aWizardSteps = $this->ComputeWizardStructure();
}
public function GetObjectClass() { return $this->m_sClass; }
public function GetTargetState() { return $this->m_sTargetState; }
public function GetWizardStructure() { return $this->m_aWizardSteps; }
/**
* Displays one step of the wizard
*/
public function DisplayWizardStep($aStep, $iStepIndex, &$iMaxInputId, &$aFieldsMap, $bFinishEnabled = false, $aArgs = array())
{
if ($iStepIndex == 1) // one big form that contains everything, to make sure that the uploaded files are posted too
{
$this->m_oPage->add("<form method=\"post\" enctype=\"multipart/form-data\" action=\"".utils::GetAbsoluteUrlAppRoot()."pages/UI.php\">\n");
}
$this->m_oPage->add("<div class=\"wizContainer\" id=\"wizStep$iStepIndex\" style=\"display:none;\">\n");
$this->m_oPage->add("<a name=\"step$iStepIndex\" />\n");
$aStates = MetaModel::EnumStates($this->m_sClass);
$aDetails = array();
$sJSHandlerCode = ''; // Javascript code to be executed each time this step of the wizard is entered
foreach($aStep as $sAttCode)
{
$oAttDef = MetaModel::GetAttributeDef($this->m_sClass, $sAttCode);
if ($oAttDef->IsWritable())
{
$sAttLabel = $oAttDef->GetLabel();
$iOptions = isset($aStates[$this->m_sTargetState]['attribute_list'][$sAttCode]) ? $aStates[$this->m_sTargetState]['attribute_list'][$sAttCode] : 0;
$aPrerequisites = $oAttDef->GetPrerequisiteAttributes();
if ($iOptions & (OPT_ATT_MANDATORY | OPT_ATT_MUSTCHANGE | OPT_ATT_MUSTPROMPT))
{
$aFields[$sAttCode] = array();
foreach($aPrerequisites as $sCode)
{
$aFields[$sAttCode][$sCode] = '';
}
}
if (count($aPrerequisites) > 0)
{
$aOptions[] = 'Prerequisites: '.implode(', ', $aPrerequisites);
}
$sFieldFlag = (($iOptions & (OPT_ATT_MANDATORY | OPT_ATT_MUSTCHANGE)) || (!$oAttDef->IsNullAllowed()) )? ' <span class="hilite">*</span>' : '';
$oDefaultValuesSet = $oAttDef->GetDefaultValue(/* $oObject->ToArgs() */); // @@@ TO DO: get the object's current value if the object exists
$sHTMLValue = cmdbAbstractObject::GetFormElementForField($this->m_oPage, $this->m_sClass, $sAttCode, $oAttDef, $oDefaultValuesSet, '', "att_$iMaxInputId", '', $iOptions, $aArgs);
$aFieldsMap["att_$iMaxInputId"] = $sAttCode;
$aDetails[] = array('label' => '<span title="'.$oAttDef->GetDescription().'">'.$oAttDef->GetLabel().$sFieldFlag.'</span>', 'value' => "<span id=\"field_att_$iMaxInputId\">$sHTMLValue</span>");
if ($oAttDef->GetValuesDef() != null)
{
$sJSHandlerCode .= "\toWizardHelper.RequestAllowedValues('$sAttCode');\n";
}
if ($oAttDef->GetDefaultValue() != null)
{
$sJSHandlerCode .= "\toWizardHelper.RequestDefaultValue('$sAttCode');\n";
}
if ($oAttDef->IsLinkSet())
{
$sJSHandlerCode .= "\toLinkWidgetatt_$iMaxInputId.Init();";
}
$iMaxInputId++;
}
}
//$aDetails[] = array('label' => '', 'value' => '<input type="button" value="Next &gt;&gt;">');
$this->m_oPage->details($aDetails);
$sBackButtonDisabled = ($iStepIndex <= 1) ? 'disabled' : '';
$sDisabled = $bFinishEnabled ? '' : 'disabled';
$nbSteps = count($this->m_aWizardSteps['mandatory']) + count($this->m_aWizardSteps['optional']);
$this->m_oPage->add("<div style=\"text-align:center\">
<input type=\"button\" value=\"".Dict::S('UI:Button:Back')."\" $sBackButtonDisabled onClick=\"GoToStep($iStepIndex, $iStepIndex - 1)\" />
<input type=\"button\" value=\"".Dict::S('UI:Button:Next')."\" onClick=\"GoToStep($iStepIndex, 1+$iStepIndex)\" />
<input type=\"button\" value=\"".Dict::S('UI:Button:Finish')."\" $sDisabled onClick=\"GoToStep($iStepIndex, 1+$nbSteps)\" />
</div>\n");
$this->m_oPage->add_script("
function OnEnterStep{$iStepIndex}()
{
oWizardHelper.ResetQuery();
oWizardHelper.UpdateWizard();
$sJSHandlerCode
oWizardHelper.AjaxQueryServer();
}
");
$this->m_oPage->add("</div>\n\n");
}
/**
* Display the final step of the wizard: a confirmation screen
*/
public function DisplayFinalStep($iStepIndex, $aFieldsMap)
{
$oAppContext = new ApplicationContext();
$this->m_oPage->add("<div class=\"wizContainer\" id=\"wizStep$iStepIndex\" style=\"display:none;\">\n");
$this->m_oPage->add("<a name=\"step$iStepIndex\" />\n");
$this->m_oPage->P(Dict::S('UI:Wizard:FinalStepTitle'));
$this->m_oPage->add("<input type=\"hidden\" name=\"operation\" value=\"wizard_apply_new\" />\n");
$this->m_oPage->add("<input type=\"hidden\" name=\"transaction_id\" value=\"".utils::GetNewTransactionId()."\" />\n");
$this->m_oPage->add("<input type=\"hidden\" id=\"wizard_json_obj\" name=\"json_obj\" value=\"\" />\n");
$sScript = "function OnEnterStep$iStepIndex() {\n";
foreach($aFieldsMap as $iInputId => $sAttCode)
{
$sScript .= "\toWizardHelper.UpdateCurrentValue('$sAttCode');\n";
}
$sScript .= "\toWizardHelper.Preview('object_preview');\n";
$sScript .= "\t$('#wizard_json_obj').val(oWizardHelper.ToJSON());\n";
$sScript .= "}\n";
$this->m_oPage->add_script($sScript);
$this->m_oPage->add("<div id=\"object_preview\">\n");
$this->m_oPage->add("</div>\n");
$this->m_oPage->add($oAppContext->GetForForm());
$this->m_oPage->add("<input type=\"button\" value=\"".Dict::S('UI:Button:Back')."\" onClick=\"GoToStep($iStepIndex, $iStepIndex - 1)\" />");
$this->m_oPage->add("<input type=\"submit\" value=\"Create ".MetaModel::GetName($this->m_sClass)."\" />\n");
$this->m_oPage->add("</div>\n");
$this->m_oPage->add("</form>\n");
}
/**
* Compute the order of the fields & pages in the wizard
* @param $oPage iTopWebPage The current page (used to display error messages)
* @param $sClass string Name of the class
* @param $sStateCode string Code of the target state of the object
* @return hash Two dimensional array: each element represents the list of fields for a given page
*/
protected function ComputeWizardStructure()
{
$aWizardSteps = array( 'mandatory' => array(), 'optional' => array());
$aFieldsDone = array(); // Store all the fields that are already covered by a previous step of the wizard
$aStates = MetaModel::EnumStates($this->m_sClass);
$sStateAttCode = MetaModel::GetStateAttributeCode($this->m_sClass);
$aMandatoryAttributes = array();
// Some attributes are always mandatory independently of the state machine (if any)
foreach(MetaModel::GetAttributesList($this->m_sClass) as $sAttCode)
{
$oAttDef = MetaModel::GetAttributeDef($this->m_sClass, $sAttCode);
if (!$oAttDef->IsExternalField() && !$oAttDef->IsNullAllowed() &&
$oAttDef->IsWritable() && ($sAttCode != $sStateAttCode) )
{
$aMandatoryAttributes[$sAttCode] = OPT_ATT_MANDATORY;
}
}
// Now check the attributes that are mandatory in the specified state
if ( (!empty($this->m_sTargetState)) && (count($aStates[$this->m_sTargetState]['attribute_list']) > 0) )
{
// Check all the fields that *must* be included in the wizard for this
// particular target state
$aFields = array();
foreach($aStates[$this->m_sTargetState]['attribute_list'] as $sAttCode => $iOptions)
{
if ( (isset($aMandatoryAttributes[$sAttCode])) &&
($aMandatoryAttributes[$sAttCode] & (OPT_ATT_MANDATORY | OPT_ATT_MUSTCHANGE | OPT_ATT_MUSTPROMPT)) )
{
$aMandatoryAttributes[$sAttCode] |= $iOptions;
}
else
{
$aMandatoryAttributes[$sAttCode] = $iOptions;
}
}
}
// Check all the fields that *must* be included in the wizard
// i.e. all mandatory, must-change or must-prompt fields that are
// not also read-only or hidden.
// Some fields may be required (null not allowed) from the database
// perspective, but hidden or read-only from the user interface perspective
$aFields = array();
foreach($aMandatoryAttributes as $sAttCode => $iOptions)
{
if ( ($iOptions & (OPT_ATT_MANDATORY | OPT_ATT_MUSTCHANGE | OPT_ATT_MUSTPROMPT)) &&
!($iOptions & (OPT_ATT_READONLY | OPT_ATT_HIDDEN)) )
{
$oAttDef = MetaModel::GetAttributeDef($this->m_sClass, $sAttCode);
$aPrerequisites = $oAttDef->GetPrerequisiteAttributes();
$aFields[$sAttCode] = array();
foreach($aPrerequisites as $sCode)
{
$aFields[$sAttCode][$sCode] = '';
}
}
}
// Now use the dependencies between the fields to order them
// Start from the order of the 'details'
$aList = MetaModel::FlattenZlist(MetaModel::GetZListItems($this->m_sClass, 'details'));
$index = 0;
$aOrder = array();
foreach($aFields as $sAttCode => $void)
{
$aOrder[$sAttCode] = 999; // At the end of the list...
}
foreach($aList as $sAttCode)
{
if (array_key_exists($sAttCode, $aFields))
{
$aOrder[$sAttCode] = $index;
}
$index++;
}
foreach($aFields as $sAttCode => $aDependencies)
{
// All fields with no remaining dependencies can be entered at this
// step of the wizard
if (count($aDependencies) > 0)
{
$iMaxPos = 0;
// Remove this field from the dependencies of the other fields
foreach($aDependencies as $sDependentAttCode => $void)
{
// position the current field after the ones it depends on
$iMaxPos = max($iMaxPos, 1+$aOrder[$sDependentAttCode]);
}
}
}
asort($aOrder);
$aCurrentStep = array();
foreach($aOrder as $sAttCode => $rank)
{
$aCurrentStep[] = $sAttCode;
$aFieldsDone[$sAttCode] = '';
}
$aWizardSteps['mandatory'][] = $aCurrentStep;
// Now computes the steps to fill the optional fields
$aFields = array(); // reset
foreach(MetaModel::ListAttributeDefs($this->m_sClass) as $sAttCode=>$oAttDef)
{
$iOptions = (isset($aStates[$this->m_sTargetState]['attribute_list'][$sAttCode])) ? $aStates[$this->m_sTargetState]['attribute_list'][$sAttCode] : 0;
if ( ($sStateAttCode != $sAttCode) &&
(!$oAttDef->IsExternalField()) &&
(($iOptions & (OPT_ATT_HIDDEN | OPT_ATT_READONLY)) == 0) &&
(!isset($aFieldsDone[$sAttCode])) )
{
// 'State', external fields, read-only and hidden fields
// and fields that are already listed in the wizard
// are removed from the 'optional' part of the wizard
$oAttDef = MetaModel::GetAttributeDef($this->m_sClass, $sAttCode);
$aPrerequisites = $oAttDef->GetPrerequisiteAttributes();
$aFields[$sAttCode] = array();
foreach($aPrerequisites as $sCode)
{
if (!isset($aFieldsDone[$sCode]))
{
// retain only the dependencies that were not covered
// in the 'mandatory' part of the wizard
$aFields[$sAttCode][$sCode] = '';
}
}
}
}
// Now use the dependencies between the fields to order them
while(count($aFields) > 0)
{
$aCurrentStep = array();
foreach($aFields as $sAttCode => $aDependencies)
{
// All fields with no remaining dependencies can be entered at this
// step of the wizard
if (count($aDependencies) == 0)
{
$aCurrentStep[] = $sAttCode;
$aFieldsDone[$sAttCode] = '';
unset($aFields[$sAttCode]);
// Remove this field from the dependencies of the other fields
foreach($aFields as $sUpdatedCode => $aDummy)
{
// remove the dependency
unset($aFields[$sUpdatedCode][$sAttCode]);
}
}
}
if (count($aCurrentStep) == 0)
{
// This step of the wizard would contain NO field !
$this->m_oPage->add(Dict::S('UI:Error:WizardCircularReferenceInDependencies'));
print_r($aFields);
break;
}
$aWizardSteps['optional'][] = $aCurrentStep;
}
return $aWizardSteps;
}
}
?>

View File

@@ -1,5 +1,5 @@
<?php
// Copyright (C) 2010-2012 Combodo SARL
// Copyright (C) 2010-2017 Combodo SARL
//
// This file is part of iTop.
//
@@ -19,7 +19,7 @@
/**
* Store and retrieve user's preferences (i.e persistent per user settings)
*
* @copyright Copyright (C) 2010-2012 Combodo SARL
* @copyright Copyright (C) 2010-2017 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
require_once(APPROOT.'/core/dbobject.class.php');
@@ -50,7 +50,7 @@ class appUserPreferences extends DBObject
self::Load();
}
$aPrefs = self::$oUserPrefs->Get('preferences');
if (isset($aPrefs[$sCode]))
if (array_key_exists($sCode, $aPrefs))
{
return $aPrefs[$sCode];
}
@@ -72,9 +72,16 @@ class appUserPreferences extends DBObject
self::Load();
}
$aPrefs = self::$oUserPrefs->Get('preferences');
$aPrefs[$sCode] = $sValue;
self::$oUserPrefs->Set('preferences', $aPrefs);
self::Save();
if (array_key_exists($sCode, $aPrefs) && ($aPrefs[$sCode] === $sValue))
{
// Do not write it again
}
else
{
$aPrefs[$sCode] = $sValue;
self::$oUserPrefs->Set('preferences', $aPrefs);
self::Save();
}
}
/**
@@ -148,7 +155,9 @@ class appUserPreferences extends DBObject
{
if (self::$oUserPrefs->IsModified())
{
utils::PushArchiveMode(false);
self::$oUserPrefs->DBUpdate();
utils::PopArchiveMode();
}
}
}
@@ -172,7 +181,9 @@ class appUserPreferences extends DBObject
$oObj->Set('preferences', array()); // Default preferences: an empty array
try
{
utils::PushArchiveMode(false);
$oObj->DBInsert();
utils::PopArchiveMode();
}
catch(Exception $e)
{
@@ -207,7 +218,8 @@ class appUserPreferences extends DBObject
*/
public function DBDeleteTracked(CMDBChange $oChange, $bSkipStrongSecurity = null, &$oDeletionPlan = null)
{
utils::PushArchiveMode(false);
$this->DBDelete($oDeletionPlan);
utils::PopArchiveMode();
}
}
?>

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,287 +1,369 @@
<?php
// Copyright (C) 2010-2012 Combodo SARL
//
// This file is part of iTop.
//
// iTop is free software; you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// iTop is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with iTop. If not, see <http://www.gnu.org/licenses/>
/**
* Class WizardHelper
*
* @copyright Copyright (C) 2010-2012 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
require_once(APPROOT.'/application/uiwizard.class.inc.php');
class WizardHelper
{
protected $m_aData;
public function __construct()
{
}
/**
* Constructs the PHP target object from the parameters sent to the web page by the wizard
* @param boolean $bReadUploadedFiles True to also ready any uploaded file (for blob/document fields)
* @return object
*/
public function GetTargetObject($bReadUploadedFiles = false)
{
if (isset($this->m_aData['m_oCurrentValues']['id']))
{
$oObj = MetaModel::GetObject($this->m_aData['m_sClass'], $this->m_aData['m_oCurrentValues']['id']);
}
else
{
$oObj = MetaModel::NewObject($this->m_aData['m_sClass']);
}
foreach($this->m_aData['m_oCurrentValues'] as $sAttCode => $value)
{
// Because this is stored in a Javascript array, unused indexes
// are filled with null values and unused keys (stored as strings) contain $$NULL$$
if ( ($sAttCode !='id') && ($sAttCode !== false) && ($value !== null) && ($value !== '$$NULL$$'))
{
$oAttDef = MetaModel::GetAttributeDef($this->m_aData['m_sClass'], $sAttCode);
if (($oAttDef->IsLinkSet()) && ($value != '') )
{
// special handling for lists
// assumes this is handled as an array of objects
// thus encoded in json like: [ { name:'link1', 'id': 123}, { name:'link2', 'id': 124}...]
$aData = json_decode($value, true); // true means decode as a hash array (not an object)
// Check what are the meaningful attributes
$aFields = $this->GetLinkedWizardStructure($oAttDef);
$sLinkedClass = $oAttDef->GetLinkedClass();
$aLinkedObjectsArray = array();
if (!is_array($aData))
{
echo ("aData: '$aData' (value: '$value')\n");
}
foreach($aData as $aLinkedObject)
{
$oLinkedObj = MetaModel::NewObject($sLinkedClass);
foreach($aFields as $sLinkedAttCode)
{
if ( isset($aLinkedObject[$sLinkedAttCode]) && ($aLinkedObject[$sLinkedAttCode] !== null) )
{
$sLinkedAttDef = MetaModel::GetAttributeDef($sLinkedClass, $sLinkedAttCode);
if (($sLinkedAttDef->IsExternalKey()) && ($aLinkedObject[$sLinkedAttCode] != '') && ($aLinkedObject[$sLinkedAttCode] > 0) )
{
// For external keys: load the target object so that external fields
// get filled too
$oTargetObj = MetaModel::GetObject($sLinkedAttDef->GetTargetClass(), $aLinkedObject[$sLinkedAttCode]);
$oLinkedObj->Set($sLinkedAttCode, $oTargetObj);
}
else
{
$oLinkedObj->Set($sLinkedAttCode, $aLinkedObject[$sLinkedAttCode]);
}
}
}
$aLinkedObjectsArray[] = $oLinkedObj;
}
$oSet = DBObjectSet::FromArray($sLinkedClass, $aLinkedObjectsArray);
$oObj->Set($sAttCode, $oSet);
}
else if ( $oAttDef->GetEditClass() == 'Document' )
{
if ($bReadUploadedFiles)
{
$oDocument = utils::ReadPostedDocument('attr_'.$sAttCode, 'fcontents');
$oObj->Set($sAttCode, $oDocument);
}
else
{
// Create a new empty document, just for displaying the file name
$oDocument = new ormDocument(null, '', $value);
$oObj->Set($sAttCode, $oDocument);
}
}
else if (($oAttDef->IsExternalKey()) && (!empty($value)) && ($value > 0) )
{
// For external keys: load the target object so that external fields
// get filled too
$oTargetObj = MetaModel::GetObject($oAttDef->GetTargetClass(), $value, false);
if ($oTargetObj)
{
$oObj->Set($sAttCode, $oTargetObj);
}
else
{
// May happen for security reasons (portal, see ticket #1074)
$oObj->Set($sAttCode, $value);
}
}
else
{
$oObj->Set($sAttCode, $value);
}
}
}
if (isset($this->m_aData['m_sState']) && !empty($this->m_aData['m_sState']))
{
$oObj->Set(MetaModel::GetStateAttributeCode($this->m_aData['m_sClass']), $this->m_aData['m_sState']);
}
$oObj->DoComputeValues();
return $oObj;
}
public function GetFieldsForDefaultValue()
{
return $this->m_aData['m_aDefaultValueRequested'];
}
public function SetDefaultValue($sAttCode, $value)
{
// Protect against a request for a non existing field
if (isset($this->m_aData['m_oFieldsMap'][$sAttCode]))
{
$oAttDef = MetaModel::GetAttributeDef($this->m_aData['m_sClass'], $sAttCode);
if ($oAttDef->GetEditClass() == 'List')
{
// special handling for lists
// this as to be handled as an array of objects
// thus encoded in json like: [ { name:'link1', 'id': 123}, { name:'link2', 'id': 124}...]
// NOT YET IMPLEMENTED !!
$sLinkedClass = $oAttDef->GetLinkedClass();
$oSet = $value;
$aData = array();
$aFields = $this->GetLinkedWizardStructure($oAttDef);
while($oSet->fetch())
{
foreach($aFields as $sLinkedAttCode)
{
$aRow[$sAttCode] = $oLinkedObj->Get($sLinkedAttCode);
}
$aData[] = $aRow;
}
$this->m_aData['m_oDefaultValue'][$sAttCode] = json_encode($aData);
}
else
{
// Normal handling for all other scalar attributes
$this->m_aData['m_oDefaultValue'][$sAttCode] = $value;
}
}
}
public function GetFieldsForAllowedValues()
{
return $this->m_aData['m_aAllowedValuesRequested'];
}
public function SetAllowedValuesHtml($sAttCode, $sHtml)
{
// Protect against a request for a non existing field
if (isset($this->m_aData['m_oFieldsMap'][$sAttCode]))
{
$this->m_aData['m_oAllowedValues'][$sAttCode] = $sHtml;
}
}
public function ToJSON()
{
return json_encode($this->m_aData);
}
static public function FromJSON($sJSON)
{
$oWizHelper = new WizardHelper();
if (get_magic_quotes_gpc())
{
$sJSON = stripslashes($sJSON);
}
$aData = json_decode($sJSON, true); // true means hash array instead of object
$oWizHelper->m_aData = $aData;
return $oWizHelper;
}
protected function GetLinkedWizardStructure($oAttDef)
{
$oWizard = new UIWizard(null, $oAttDef->GetLinkedClass());
$aWizardSteps = $oWizard->GetWizardStructure();
$aFields = array();
$sExtKeyToMeCode = $oAttDef->GetExtKeyToMe();
// Retrieve as a flat list, all the attributes that are needed to create
// an object of the linked class and put them into a flat array, except
// the attribute 'ext_key_to_me' which is a constant in our case
foreach($aWizardSteps as $sDummy => $aMainSteps)
{
// 2 entries: 'mandatory' and 'optional'
foreach($aMainSteps as $aSteps)
{
// One entry for each step of the wizard
foreach($aSteps as $sAttCode)
{
if ($sAttCode != $sExtKeyToMeCode)
{
$aFields[] = $sAttCode;
}
}
}
}
return $aFields;
}
public function GetTargetClass()
{
return $this->m_aData['m_sClass'];
}
public function GetFormPrefix()
{
return $this->m_aData['m_sFormPrefix'];
}
public function GetIdForField($sFieldName)
{
$sResult = '';
// It may happen that the field we'd like to update does not
// exist in the form. For example, if the field should be hidden/read-only
// in the current state of the object
if (isset($this->m_aData['m_oFieldsMap'][$sFieldName]))
{
$sResult = $this->m_aData['m_oFieldsMap'][$sFieldName];
}
return $sResult;
}
static function ParseJsonSet($oMe, $sLinkClass, $sExtKeyToMe, $sJsonSet)
{
$aSet = json_decode($sJsonSet, true); // true means hash array instead of object
$oSet = CMDBObjectSet::FromScratch($sLinkClass);
foreach($aSet as $aLinkObj)
{
$oLink = MetaModel::NewObject($sLinkClass);
foreach($aLinkObj as $sAttCode => $value)
{
$oAttDef = MetaModel::GetAttributeDef($sLinkClass, $sAttCode);
if (($oAttDef->IsExternalKey()) && ($value != '') && ($value > 0))
{
// For external keys: load the target object so that external fields
// get filled too
$oTargetObj = MetaModel::GetObject($oAttDef->GetTargetClass(), $value);
$oLink->Set($sAttCode, $oTargetObj);
}
$oLink->Set($sAttCode, $value);
}
$oLink->Set($sExtKeyToMe, $oMe->GetKey());
$oSet->AddObject($oLink);
}
return $oSet;
}
}
?>
<?php
// Copyright (C) 2010-2016 Combodo SARL
//
// This file is part of iTop.
//
// iTop is free software; you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// iTop is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with iTop. If not, see <http://www.gnu.org/licenses/>
/**
* Class WizardHelper
*
* @copyright Copyright (C) 2010-2016 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
require_once(APPROOT.'/application/uiwizard.class.inc.php');
class WizardHelper
{
protected $m_aData;
public function __construct()
{
}
/**
* Constructs the PHP target object from the parameters sent to the web page by the wizard
* @param boolean $bReadUploadedFiles True to also read any uploaded file (for blob/document fields)
* @return object
*/
public function GetTargetObject($bReadUploadedFiles = false)
{
if (isset($this->m_aData['m_oCurrentValues']['id']))
{
$oObj = MetaModel::GetObject($this->m_aData['m_sClass'], $this->m_aData['m_oCurrentValues']['id']);
}
else
{
$oObj = MetaModel::NewObject($this->m_aData['m_sClass']);
}
foreach($this->m_aData['m_oCurrentValues'] as $sAttCode => $value)
{
// Because this is stored in a Javascript array, unused indexes
// are filled with null values and unused keys (stored as strings) contain $$NULL$$
if ( ($sAttCode !='id') && ($value !== '$$NULL$$'))
{
$oAttDef = MetaModel::GetAttributeDef($this->m_aData['m_sClass'], $sAttCode);
if (($oAttDef->IsLinkSet()) && ($value != '') )
{
// special handling for lists
// assumes this is handled as an array of objects
// thus encoded in json like: [ { name:'link1', 'id': 123}, { name:'link2', 'id': 124}...]
$aData = json_decode($value, true); // true means decode as a hash array (not an object)
// Check what are the meaningful attributes
$aFields = $this->GetLinkedWizardStructure($oAttDef);
$sLinkedClass = $oAttDef->GetLinkedClass();
$aLinkedObjectsArray = array();
if (!is_array($aData))
{
echo ("aData: '$aData' (value: '$value')\n");
}
foreach($aData as $aLinkedObject)
{
$oLinkedObj = MetaModel::NewObject($sLinkedClass);
foreach($aFields as $sLinkedAttCode)
{
if ( isset($aLinkedObject[$sLinkedAttCode]) && ($aLinkedObject[$sLinkedAttCode] !== null) )
{
$sLinkedAttDef = MetaModel::GetAttributeDef($sLinkedClass, $sLinkedAttCode);
if (($sLinkedAttDef->IsExternalKey()) && ($aLinkedObject[$sLinkedAttCode] != '') && ($aLinkedObject[$sLinkedAttCode] > 0) )
{
// For external keys: load the target object so that external fields
// get filled too
$oTargetObj = MetaModel::GetObject($sLinkedAttDef->GetTargetClass(), $aLinkedObject[$sLinkedAttCode]);
$oLinkedObj->Set($sLinkedAttCode, $oTargetObj);
}
elseif($sLinkedAttDef instanceof AttributeDateTime)
{
$sDateClass = get_class($sLinkedAttDef);
$sDate = $aLinkedObject[$sLinkedAttCode];
if($sDate !== null && $sDate !== '')
{
$oDateTimeFormat = $sDateClass::GetFormat();
$oDate = $oDateTimeFormat->Parse($sDate);
if ($sDateClass == "AttributeDate")
{
$sDate = $oDate->format('Y-m-d');
}
else
{
$sDate = $oDate->format('Y-m-d H:i:s');
}
}
$oLinkedObj->Set($sLinkedAttCode, $sDate);
}
else
{
$oLinkedObj->Set($sLinkedAttCode, $aLinkedObject[$sLinkedAttCode]);
}
}
}
$aLinkedObjectsArray[] = $oLinkedObj;
}
$oSet = DBObjectSet::FromArray($sLinkedClass, $aLinkedObjectsArray);
$oObj->Set($sAttCode, $oSet);
}
else if ( $oAttDef->GetEditClass() == 'Document' )
{
if ($bReadUploadedFiles)
{
$oDocument = utils::ReadPostedDocument('attr_'.$sAttCode, 'fcontents');
$oObj->Set($sAttCode, $oDocument);
}
else
{
// Create a new empty document, just for displaying the file name
$oDocument = new ormDocument(null, '', $value);
$oObj->Set($sAttCode, $oDocument);
}
}
else if ( $oAttDef->GetEditClass() == 'Image' )
{
if ($bReadUploadedFiles)
{
$oDocument = utils::ReadPostedDocument('attr_'.$sAttCode, 'fcontents');
$oObj->Set($sAttCode, $oDocument);
}
else
{
// Create a new empty document, just for displaying the file name
$oDocument = new ormDocument(null, '', $value);
$oObj->Set($sAttCode, $oDocument);
}
}
else if (($oAttDef->IsExternalKey()) && (!empty($value)) && ($value > 0) )
{
// For external keys: load the target object so that external fields
// get filled too
$oTargetObj = MetaModel::GetObject($oAttDef->GetTargetClass(), $value, false);
if ($oTargetObj)
{
$oObj->Set($sAttCode, $oTargetObj);
}
else
{
// May happen for security reasons (portal, see ticket N°1074)
$oObj->Set($sAttCode, $value);
}
}
else if ($oAttDef instanceof AttributeDateTime) // AttributeDate is derived from AttributeDateTime
{
if ($value != null)
{
$oDate = $oAttDef->GetFormat()->Parse($value);
if ($oDate instanceof DateTime)
{
$value = $oDate->format($oAttDef->GetInternalFormat());
}
else
{
$value = null;
}
}
$oObj->Set($sAttCode, $value);
}
else if ($oAttDef instanceof AttributeTagSet) // AttributeDate is derived from AttributeDateTime
{
if (is_null($value))
{
// happens if field is hidden (see N°1827)
$value = array();
}
else
{
$value = json_decode($value, true);
}
$oTagSet = new ormTagSet(get_class($oObj), $sAttCode, $oAttDef->GetMaxItems());
$oTagSet->SetValues($value['orig_value']);
$oTagSet->ApplyDelta($value);
$oObj->Set($sAttCode, $oTagSet);
}
else if ($oAttDef instanceof AttributeSet) // AttributeDate is derived from AttributeDateTime
{
$value = json_decode($value, true);
$oTagSet = new ormSet(get_class($oObj), $sAttCode, $oAttDef->GetMaxItems());
$oTagSet->SetValues($value['orig_value']);
$oTagSet->ApplyDelta($value);
$oObj->Set($sAttCode, $oTagSet);
}
else
{
$oObj->Set($sAttCode, $value);
}
}
}
if (isset($this->m_aData['m_sState']) && !empty($this->m_aData['m_sState']))
{
$oObj->Set(MetaModel::GetStateAttributeCode($this->m_aData['m_sClass']), $this->m_aData['m_sState']);
}
$oObj->DoComputeValues();
return $oObj;
}
public function GetFieldsForDefaultValue()
{
return $this->m_aData['m_aDefaultValueRequested'];
}
public function SetDefaultValue($sAttCode, $value)
{
// Protect against a request for a non existing field
if (isset($this->m_aData['m_oFieldsMap'][$sAttCode]))
{
$oAttDef = MetaModel::GetAttributeDef($this->m_aData['m_sClass'], $sAttCode);
if ($oAttDef->GetEditClass() == 'List')
{
// special handling for lists
// this as to be handled as an array of objects
// thus encoded in json like: [ { name:'link1', 'id': 123}, { name:'link2', 'id': 124}...]
// NOT YET IMPLEMENTED !!
$oSet = $value;
$aData = array();
$aFields = $this->GetLinkedWizardStructure($oAttDef);
while($oLinkedObj = $oSet->fetch())
{
foreach($aFields as $sLinkedAttCode)
{
$aRow[$sAttCode] = $oLinkedObj->Get($sLinkedAttCode);
}
$aData[] = $aRow;
}
$this->m_aData['m_oDefaultValue'][$sAttCode] = json_encode($aData);
}
else
{
// Normal handling for all other scalar attributes
$this->m_aData['m_oDefaultValue'][$sAttCode] = $value;
}
}
}
public function GetFieldsForAllowedValues()
{
return $this->m_aData['m_aAllowedValuesRequested'];
}
public function SetAllowedValuesHtml($sAttCode, $sHtml)
{
// Protect against a request for a non existing field
if (isset($this->m_aData['m_oFieldsMap'][$sAttCode]))
{
$this->m_aData['m_oAllowedValues'][$sAttCode] = $sHtml;
}
}
public function ToJSON()
{
return json_encode($this->m_aData);
}
static public function FromJSON($sJSON)
{
$oWizHelper = new WizardHelper();
if (get_magic_quotes_gpc())
{
$sJSON = stripslashes($sJSON);
}
$aData = json_decode($sJSON, true); // true means hash array instead of object
$oWizHelper->m_aData = $aData;
return $oWizHelper;
}
protected function GetLinkedWizardStructure($oAttDef)
{
$oWizard = new UIWizard(null, $oAttDef->GetLinkedClass());
$aWizardSteps = $oWizard->GetWizardStructure();
$aFields = array();
$sExtKeyToMeCode = $oAttDef->GetExtKeyToMe();
// Retrieve as a flat list, all the attributes that are needed to create
// an object of the linked class and put them into a flat array, except
// the attribute 'ext_key_to_me' which is a constant in our case
foreach($aWizardSteps as $sDummy => $aMainSteps)
{
// 2 entries: 'mandatory' and 'optional'
foreach($aMainSteps as $aSteps)
{
// One entry for each step of the wizard
foreach($aSteps as $sAttCode)
{
if ($sAttCode != $sExtKeyToMeCode)
{
$aFields[] = $sAttCode;
}
}
}
}
return $aFields;
}
public function GetTargetClass()
{
return $this->m_aData['m_sClass'];
}
public function GetFormPrefix()
{
return $this->m_aData['m_sFormPrefix'];
}
public function GetInitialState()
{
return isset($this->m_aData['m_sInitialState']) ? $this->m_aData['m_sInitialState'] : null;
}
public function GetStimulus()
{
return isset($this->m_aData['m_sStimulus']) ? $this->m_aData['m_sStimulus'] : null;
}
public function GetIdForField($sFieldName)
{
$sResult = '';
// It may happen that the field we'd like to update does not
// exist in the form. For example, if the field should be hidden/read-only
// in the current state of the object
if (isset($this->m_aData['m_oFieldsMap'][$sFieldName]))
{
$sResult = $this->m_aData['m_oFieldsMap'][$sFieldName];
}
return $sResult;
}
static function ParseJsonSet($oMe, $sLinkClass, $sExtKeyToMe, $sJsonSet)
{
$aSet = json_decode($sJsonSet, true); // true means hash array instead of object
$oSet = CMDBObjectSet::FromScratch($sLinkClass);
foreach($aSet as $aLinkObj)
{
$oLink = MetaModel::NewObject($sLinkClass);
foreach($aLinkObj as $sAttCode => $value)
{
$oAttDef = MetaModel::GetAttributeDef($sLinkClass, $sAttCode);
if (($oAttDef->IsExternalKey()) && ($value != '') && ($value > 0))
{
// For external keys: load the target object so that external fields
// get filled too
$oTargetObj = MetaModel::GetObject($oAttDef->GetTargetClass(), $value);
$oLink->Set($sAttCode, $oTargetObj);
}
$oLink->Set($sAttCode, $value);
}
$oLink->Set($sExtKeyToMe, $oMe->GetKey());
$oSet->AddObject($oLink);
}
return $oSet;
}
}

View File

@@ -13,6 +13,8 @@ Class XLSXWriter
protected $shared_strings = array();//unique set
protected $shared_string_count = 0;//count of non-unique references to the unique set
protected $temp_files = array();
protected $date_format = 'YYYY-MM-DD';
protected $date_time_format = 'YYYY-MM-DD\ HH:MM:SS';
public function __construct(){}
public function setAuthor($author='') { $this->author=$author; }
@@ -26,9 +28,19 @@ Class XLSXWriter
}
}
public function setDateFormat($date_format)
{
$this->date_format = $date_format;
}
public function setDateTimeFormat($date_time_format)
{
$this->date_time_format = $date_time_format;
}
protected function tempFilename()
{
$filename = tempnam("/tmp", "xlsx_writer_");
$filename = tempnam(SetupUtils::GettmpDir(), 'xlsx_writer_');
$this->temp_files[] = $filename;
return $filename;
}
@@ -152,18 +164,14 @@ Class XLSXWriter
{
static $styles = array('money'=>1,'dollar'=>1,'datetime'=>2,'date'=>3,'string'=>0);
$cell = self::xlsCell($row_number, $column_number);
$s = isset($styles[$cell_format]) ? $styles[$cell_format] : '0';
$s = isset($styles[$cell_format]) && ($value !== '') ? $styles[$cell_format] : '0';
if (is_numeric($value)) {
if (is_int($value) || is_float($value)) {
fwrite($fd,'<c r="'.$cell.'" s="'.$s.'" t="n"><v>'.($value*1).'</v></c>');//int,float, etc
} else if ($cell_format=='date') {
} else if (($cell_format=='date') && ($value != '')) {
fwrite($fd,'<c r="'.$cell.'" s="'.$s.'" t="n"><v>'.intval(self::convert_date_time($value)).'</v></c>');
} else if ($cell_format=='datetime') {
if ($value === '') {
fwrite($fd,'<c r="'.$cell.'" s="0"/>');
} else {
fwrite($fd,'<c r="'.$cell.'" s="'.$s.'" t="n"><v>'.self::convert_date_time($value).'</v></c>');
}
} else if (($cell_format=='datetime') && ($value != '')) {
fwrite($fd,'<c r="'.$cell.'" s="'.$s.'" t="n"><v>'.self::convert_date_time($value).'</v></c>');
} else if ($value==''){
fwrite($fd,'<c r="'.$cell.'" s="'.$s.'"/>');
} else if ($value{0}=='='){
@@ -183,8 +191,8 @@ Class XLSXWriter
fwrite($fd, '<numFmts count="4">');
fwrite($fd, '<numFmt formatCode="GENERAL" numFmtId="164"/>');
fwrite($fd, '<numFmt formatCode="[$$-1009]#,##0.00;[RED]\-[$$-1009]#,##0.00" numFmtId="165"/>');
fwrite($fd, '<numFmt formatCode="YYYY-MM-DD\ HH:MM:SS" numFmtId="166"/>');
fwrite($fd, '<numFmt formatCode="YYYY-MM-DD" numFmtId="167"/>');
fwrite($fd, '<numFmt formatCode="'.$this->date_time_format.'" numFmtId="166"/>');
fwrite($fd, '<numFmt formatCode="'.$this->date_format.'" numFmtId="167"/>');
fwrite($fd, '</numFmts>');
fwrite($fd, '<fonts count="4">');
fwrite($fd, '<font><name val="Arial"/><charset val="1"/><family val="2"/><sz val="10"/></font>');

View File

@@ -1,106 +1,106 @@
<?php
// Copyright (C) 2010-2015 Combodo SARL
//
// This file is part of iTop.
//
// iTop is free software; you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// iTop is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with iTop. If not, see <http://www.gnu.org/licenses/>
/**
* Class XMLPage
*
* @copyright Copyright (C) 2010-2015 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
require_once(APPROOT."/application/webpage.class.inc.php");
/**
* Simple web page with no includes or fancy formatting, useful to generateXML documents
* The page adds the content-type text/XML and the encoding into the headers
*/
class XMLPage extends WebPage
{
/**
* For big XML files, it's better NOT to store everything in memory and output the XML piece by piece
*/
var $m_bPassThrough;
var $m_bHeaderSent;
function __construct($s_title, $bPassThrough = false)
{
parent::__construct($s_title);
$this->m_bPassThrough = $bPassThrough;
$this->m_bHeaderSent = false;
$this->add_header("Content-type: text/xml; charset=utf-8");
$this->add_header("Cache-control: no-cache");
$this->add_header("Content-location: export.xml");
}
public function output()
{
if (!$this->m_bPassThrough)
{
// Get the unexpected output but do nothing with it
$sTrash = $this->ob_get_clean_safe();
$this->s_content = "<?xml version=\"1.0\" encoding=\"UTF-8\"?".">\n".trim($this->s_content);
$this->add_header("Content-Length: ".strlen($this->s_content));
foreach($this->a_headers as $s_header)
{
header($s_header);
}
echo $this->s_content;
}
if (class_exists('DBSearch'))
{
DBSearch::RecordQueryTrace();
}
}
public function add($sText)
{
if (!$this->m_bPassThrough)
{
parent::add($sText);
}
else
{
if ($this->m_bHeaderSent)
{
echo $sText;
}
else
{
$s_captured_output = $this->ob_get_clean_safe();
foreach($this->a_headers as $s_header)
{
header($s_header);
}
echo "<?xml version=\"1.0\" encoding=\"UTF-8\"?".">\n";
echo trim($s_captured_output);
echo trim($this->s_content);
echo $sText;
$this->m_bHeaderSent = true;
}
}
}
public function small_p($sText)
{
}
public function table($aConfig, $aData, $aParams = array())
{
}
}
<?php
// Copyright (C) 2010-2015 Combodo SARL
//
// This file is part of iTop.
//
// iTop is free software; you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// iTop is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with iTop. If not, see <http://www.gnu.org/licenses/>
/**
* Class XMLPage
*
* @copyright Copyright (C) 2010-2015 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
require_once(APPROOT."/application/webpage.class.inc.php");
/**
* Simple web page with no includes or fancy formatting, useful to generateXML documents
* The page adds the content-type text/XML and the encoding into the headers
*/
class XMLPage extends WebPage
{
/**
* For big XML files, it's better NOT to store everything in memory and output the XML piece by piece
*/
var $m_bPassThrough;
var $m_bHeaderSent;
function __construct($s_title, $bPassThrough = false)
{
parent::__construct($s_title);
$this->m_bPassThrough = $bPassThrough;
$this->m_bHeaderSent = false;
$this->add_header("Content-type: text/xml; charset=utf-8");
$this->add_header("Cache-control: no-cache");
$this->add_header("Content-location: export.xml");
}
public function output()
{
if (!$this->m_bPassThrough)
{
// Get the unexpected output but do nothing with it
$sTrash = $this->ob_get_clean_safe();
$this->s_content = "<?xml version=\"1.0\" encoding=\"UTF-8\"?".">\n".trim($this->s_content);
$this->add_header("Content-Length: ".strlen($this->s_content));
foreach($this->a_headers as $s_header)
{
header($s_header);
}
echo $this->s_content;
}
if (class_exists('DBSearch'))
{
DBSearch::RecordQueryTrace();
}
}
public function add($sText)
{
if (!$this->m_bPassThrough)
{
parent::add($sText);
}
else
{
if ($this->m_bHeaderSent)
{
echo $sText;
}
else
{
$s_captured_output = $this->ob_get_clean_safe();
foreach($this->a_headers as $s_header)
{
header($s_header);
}
echo "<?xml version=\"1.0\" encoding=\"UTF-8\"?".">\n";
echo trim($s_captured_output);
echo trim($this->s_content);
echo $sText;
$this->m_bHeaderSent = true;
}
}
}
public function small_p($sText)
{
}
public function table($aConfig, $aData, $aParams = array())
{
}
}

21
composer.json Normal file
View File

@@ -0,0 +1,21 @@
{
"require": {
"php": ">=5.6.0",
"ext-mysql": "*",
"ext-ldap": "*",
"ext-mcrypt": "*",
"ext-cli": "*",
"ext-soap": "*",
"ext-json": "*",
"ext-zip": "*",
"ext-mysqli": "*",
"ext-dom": "*",
"ext-iconv": "*",
"ext-gd": "*"
},
"config": {
"platform": {
"php": "5.6.0"
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,411 +1,442 @@
<?php
// Copyright (C) 2010-2012 Combodo SARL
//
// This file is part of iTop.
//
// iTop is free software; you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// iTop is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with iTop. If not, see <http://www.gnu.org/licenses/>
/**
* Persistent classes (internal): user defined actions
*
* @copyright Copyright (C) 2010-2012 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
require_once(APPROOT.'/core/asynctask.class.inc.php');
require_once(APPROOT.'/core/email.class.inc.php');
/**
* A user defined action, to customize the application
*
* @package iTopORM
*/
abstract class Action extends cmdbAbstractObject
{
public static function Init()
{
$aParams = array
(
"category" => "core/cmdb",
"key_type" => "autoincrement",
"name_attcode" => "name",
"state_attcode" => "",
"reconc_keys" => array('name'),
"db_table" => "priv_action",
"db_key_field" => "id",
"db_finalclass_field" => "realclass",
"display_template" => "",
);
MetaModel::Init_Params($aParams);
//MetaModel::Init_InheritAttributes();
MetaModel::Init_AddAttribute(new AttributeString("name", array("allowed_values"=>null, "sql"=>"name", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeString("description", array("allowed_values"=>null, "sql"=>"description", "default_value"=>null, "is_null_allowed"=>true, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeEnum("status", array("allowed_values"=>new ValueSetEnum(array('test'=>'Being tested' ,'enabled'=>'In production', 'disabled'=>'Inactive')), "sql"=>"status", "default_value"=>"test", "is_null_allowed"=>false, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeLinkedSetIndirect("trigger_list", array("linked_class"=>"lnkTriggerAction", "ext_key_to_me"=>"action_id", "ext_key_to_remote"=>"trigger_id", "allowed_values"=>null, "count_min"=>0, "count_max"=>0, "depends_on"=>array())));
// Display lists
MetaModel::Init_SetZListItems('details', array('name', 'description', 'status', 'trigger_list')); // Attributes to be displayed for the complete details
MetaModel::Init_SetZListItems('list', array('finalclass', 'name', 'description', 'status')); // Attributes to be displayed for a list
// Search criteria
// MetaModel::Init_SetZListItems('standard_search', array('name')); // Criteria of the std search form
// MetaModel::Init_SetZListItems('advanced_search', array('name')); // Criteria of the advanced search form
}
abstract public function DoExecute($oTrigger, $aContextArgs);
public function IsActive()
{
switch($this->Get('status'))
{
case 'enabled':
case 'test':
return true;
default:
return false;
}
}
public function IsBeingTested()
{
switch($this->Get('status'))
{
case 'test':
return true;
default:
return false;
}
}
}
/**
* A notification
*
* @package iTopORM
*/
abstract class ActionNotification extends Action
{
public static function Init()
{
$aParams = array
(
"category" => "core/cmdb",
"key_type" => "autoincrement",
"name_attcode" => "name",
"state_attcode" => "",
"reconc_keys" => array('name'),
"db_table" => "priv_action_notification",
"db_key_field" => "id",
"db_finalclass_field" => "",
"display_template" => "",
);
MetaModel::Init_Params($aParams);
MetaModel::Init_InheritAttributes();
// Display lists
MetaModel::Init_SetZListItems('details', array('name', 'description', 'status', 'trigger_list')); // Attributes to be displayed for the complete details
MetaModel::Init_SetZListItems('list', array('finalclass', 'name', 'description', 'status')); // Attributes to be displayed for a list
// Search criteria
// MetaModel::Init_SetZListItems('standard_search', array('name')); // Criteria of the std search form
// MetaModel::Init_SetZListItems('advanced_search', array('name')); // Criteria of the advanced search form
}
}
/**
* An email notification
*
* @package iTopORM
*/
class ActionEmail extends ActionNotification
{
public static function Init()
{
$aParams = array
(
"category" => "core/cmdb,application",
"key_type" => "autoincrement",
"name_attcode" => "name",
"state_attcode" => "",
"reconc_keys" => array('name'),
"db_table" => "priv_action_email",
"db_key_field" => "id",
"db_finalclass_field" => "",
"display_template" => "",
);
MetaModel::Init_Params($aParams);
MetaModel::Init_InheritAttributes();
MetaModel::Init_AddAttribute(new AttributeEmailAddress("test_recipient", array("allowed_values"=>null, "sql"=>"test_recipient", "default_value"=>"", "is_null_allowed"=>true, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeString("from", array("allowed_values"=>null, "sql"=>"from", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeString("reply_to", array("allowed_values"=>null, "sql"=>"reply_to", "default_value"=>null, "is_null_allowed"=>true, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeOQL("to", array("allowed_values"=>null, "sql"=>"to", "default_value"=>null, "is_null_allowed"=>true, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeOQL("cc", array("allowed_values"=>null, "sql"=>"cc", "default_value"=>null, "is_null_allowed"=>true, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeOQL("bcc", array("allowed_values"=>null, "sql"=>"bcc", "default_value"=>null, "is_null_allowed"=>true, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeTemplateString("subject", array("allowed_values"=>null, "sql"=>"subject", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeTemplateText("body", array("allowed_values"=>null, "sql"=>"body", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeEnum("importance", array("allowed_values"=>new ValueSetEnum('low,normal,high'), "sql"=>"importance", "default_value"=>'normal', "is_null_allowed"=>false, "depends_on"=>array())));
// Display lists
MetaModel::Init_SetZListItems('details', array('name', 'description', 'status', 'test_recipient', 'from', 'reply_to', 'to', 'cc', 'bcc', 'subject', 'body', 'importance', 'trigger_list')); // Attributes to be displayed for the complete details
MetaModel::Init_SetZListItems('list', array('name', 'status', 'to', 'subject')); // Attributes to be displayed for a list
// Search criteria
MetaModel::Init_SetZListItems('standard_search', array('name','description', 'status', 'subject')); // Criteria of the std search form
// MetaModel::Init_SetZListItems('advanced_search', array('name')); // Criteria of the advanced search form
}
// count the recipients found
protected $m_iRecipients;
// Errors management : not that simple because we need that function to be
// executed in the background, while making sure that any issue would be reported clearly
protected $m_aMailErrors; //array of strings explaining the issue
// returns a the list of emails as a string, or a detailed error description
protected function FindRecipients($sRecipAttCode, $aArgs)
{
$sOQL = $this->Get($sRecipAttCode);
if (strlen($sOQL) == '') return '';
try
{
$oSearch = DBObjectSearch::FromOQL($sOQL);
$oSearch->AllowAllData();
}
catch (OQLException $e)
{
$this->m_aMailErrors[] = "query syntax error for recipient '$sRecipAttCode'";
return $e->getMessage();
}
$sClass = $oSearch->GetClass();
// Determine the email attribute (the first one will be our choice)
foreach (MetaModel::ListAttributeDefs($sClass) as $sAttCode => $oAttDef)
{
if ($oAttDef instanceof AttributeEmailAddress)
{
$sEmailAttCode = $sAttCode;
// we've got one, exit the loop
break;
}
}
if (!isset($sEmailAttCode))
{
$this->m_aMailErrors[] = "wrong target for recipient '$sRecipAttCode'";
return "The objects of the class '$sClass' do not have any email attribute";
}
$oSet = new DBObjectSet($oSearch, array() /* order */, $aArgs);
$aRecipients = array();
while ($oObj = $oSet->Fetch())
{
$sAddress = trim($oObj->Get($sEmailAttCode));
if (strlen($sAddress) > 0)
{
$aRecipients[] = $sAddress;
$this->m_iRecipients++;
}
}
return implode(', ', $aRecipients);
}
public function DoExecute($oTrigger, $aContextArgs)
{
if (MetaModel::IsLogEnabledNotification())
{
$oLog = new EventNotificationEmail();
if ($this->IsBeingTested())
{
$oLog->Set('message', 'TEST - Notification sent ('.$this->Get('test_recipient').')');
}
else
{
$oLog->Set('message', 'Notification pending');
}
$oLog->Set('userinfo', UserRights::GetUser());
$oLog->Set('trigger_id', $oTrigger->GetKey());
$oLog->Set('action_id', $this->GetKey());
$oLog->Set('object_id', $aContextArgs['this->object()']->GetKey());
// Must be inserted now so that it gets a valid id that will make the link
// between an eventual asynchronous task (queued) and the log
$oLog->DBInsertNoReload();
}
else
{
$oLog = null;
}
try
{
$sRes = $this->_DoExecute($oTrigger, $aContextArgs, $oLog);
if ($this->IsBeingTested())
{
$sPrefix = 'TEST ('.$this->Get('test_recipient').') - ';
}
else
{
$sPrefix = '';
}
$oLog->Set('message', $sPrefix.$sRes);
}
catch (Exception $e)
{
if ($oLog)
{
$oLog->Set('message', 'Error: '.$e->getMessage());
}
}
if ($oLog)
{
$oLog->DBUpdate();
}
}
protected function _DoExecute($oTrigger, $aContextArgs, &$oLog)
{
$sPreviousUrlMaker = ApplicationContext::SetUrlMakerClass();
try
{
$this->m_iRecipients = 0;
$this->m_aMailErrors = array();
$bRes = false; // until we do succeed in sending the email
// Determine recicipients
//
$sTo = $this->FindRecipients('to', $aContextArgs);
$sCC = $this->FindRecipients('cc', $aContextArgs);
$sBCC = $this->FindRecipients('bcc', $aContextArgs);
$sFrom = MetaModel::ApplyParams($this->Get('from'), $aContextArgs);
$sReplyTo = MetaModel::ApplyParams($this->Get('reply_to'), $aContextArgs);
$sSubject = MetaModel::ApplyParams($this->Get('subject'), $aContextArgs);
$sBody = MetaModel::ApplyParams($this->Get('body'), $aContextArgs);
$oObj = $aContextArgs['this->object()'];
$sMessageId = sprintf('iTop_%s_%d_%f@%s.openitop.org', get_class($oObj), $oObj->GetKey(), microtime(true /* get as float*/), MetaModel::GetEnvironmentId());
$sReference = '<'.$sMessageId.'>';
}
catch(Exception $e)
{
ApplicationContext::SetUrlMakerClass($sPreviousUrlMaker);
throw $e;
}
ApplicationContext::SetUrlMakerClass($sPreviousUrlMaker);
if (!is_null($oLog))
{
// Note: we have to secure this because those values are calculated
// inside the try statement, and we would like to keep track of as
// many data as we could while some variables may still be undefined
if (isset($sTo)) $oLog->Set('to', $sTo);
if (isset($sCC)) $oLog->Set('cc', $sCC);
if (isset($sBCC)) $oLog->Set('bcc', $sBCC);
if (isset($sFrom)) $oLog->Set('from', $sFrom);
if (isset($sSubject)) $oLog->Set('subject', $sSubject);
if (isset($sBody)) $oLog->Set('body', $sBody);
}
$oEmail = new EMail();
if ($this->IsBeingTested())
{
$oEmail->SetSubject('TEST['.$sSubject.']');
$sTestBody = $sBody;
$sTestBody .= "<div style=\"border: dashed;\">\n";
$sTestBody .= "<h1>Testing email notification ".$this->GetHyperlink()."</h1>\n";
$sTestBody .= "<p>The email should be sent with the following properties\n";
$sTestBody .= "<ul>\n";
$sTestBody .= "<li>TO: $sTo</li>\n";
$sTestBody .= "<li>CC: $sCC</li>\n";
$sTestBody .= "<li>BCC: $sBCC</li>\n";
$sTestBody .= "<li>From: $sFrom</li>\n";
$sTestBody .= "<li>Reply-To: $sReplyTo</li>\n";
$sTestBody .= "<li>References: $sReference</li>\n";
$sTestBody .= "</ul>\n";
$sTestBody .= "</p>\n";
$sTestBody .= "</div>\n";
$oEmail->SetBody($sTestBody);
$oEmail->SetRecipientTO($this->Get('test_recipient'));
$oEmail->SetRecipientFrom($this->Get('test_recipient'));
$oEmail->SetReferences($sReference);
$oEmail->SetMessageId($sMessageId);
}
else
{
$oEmail->SetSubject($sSubject);
$oEmail->SetBody($sBody);
$oEmail->SetRecipientTO($sTo);
$oEmail->SetRecipientCC($sCC);
$oEmail->SetRecipientBCC($sBCC);
$oEmail->SetRecipientFrom($sFrom);
$oEmail->SetRecipientReplyTo($sReplyTo);
$oEmail->SetReferences($sReference);
$oEmail->SetMessageId($sMessageId);
}
if (isset($aContextArgs['attachments']))
{
$aAttachmentReport = array();
foreach($aContextArgs['attachments'] as $oDocument)
{
$oEmail->AddAttachment($oDocument->GetData(), $oDocument->GetFileName(), $oDocument->GetMimeType());
$aAttachmentReport[] = array($oDocument->GetFileName(), $oDocument->GetMimeType(), strlen($oDocument->GetData()));
}
$oLog->Set('attachments', $aAttachmentReport);
}
if (empty($this->m_aMailErrors))
{
if ($this->m_iRecipients == 0)
{
return 'No recipient';
}
else
{
$iRes = $oEmail->Send($aErrors, false, $oLog); // allow asynchronous mode
switch ($iRes)
{
case EMAIL_SEND_OK:
return "Sent";
case EMAIL_SEND_PENDING:
return "Pending";
case EMAIL_SEND_ERROR:
return "Errors: ".implode(', ', $aErrors);
}
}
}
else
{
if (is_array($this->m_aMailErrors) && count($this->m_aMailErrors) > 0)
{
$sError = implode(', ', $this->m_aMailErrors);
}
else
{
$sError = 'Unknown reason';
}
return 'Notification was not sent: '.$sError;
}
}
}
?>
<?php
// Copyright (C) 2010-2016 Combodo SARL
//
// This file is part of iTop.
//
// iTop is free software; you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// iTop is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with iTop. If not, see <http://www.gnu.org/licenses/>
/**
* Persistent classes (internal): user defined actions
*
* @copyright Copyright (C) 2010-2016 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
require_once(APPROOT.'/core/asynctask.class.inc.php');
require_once(APPROOT.'/core/email.class.inc.php');
/**
* A user defined action, to customize the application
*
* @package iTopORM
*/
abstract class Action extends cmdbAbstractObject
{
public static function Init()
{
$aParams = array
(
"category" => "grant_by_profile,core/cmdb",
"key_type" => "autoincrement",
"name_attcode" => "name",
"state_attcode" => "",
"reconc_keys" => array('name'),
"db_table" => "priv_action",
"db_key_field" => "id",
"db_finalclass_field" => "realclass",
"display_template" => "",
);
MetaModel::Init_Params($aParams);
//MetaModel::Init_InheritAttributes();
MetaModel::Init_AddAttribute(new AttributeString("name", array("allowed_values"=>null, "sql"=>"name", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeString("description", array("allowed_values"=>null, "sql"=>"description", "default_value"=>null, "is_null_allowed"=>true, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeEnum("status", array("allowed_values"=>new ValueSetEnum(array('test'=>'Being tested' ,'enabled'=>'In production', 'disabled'=>'Inactive')), "sql"=>"status", "default_value"=>"test", "is_null_allowed"=>false, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeLinkedSetIndirect("trigger_list", array("linked_class"=>"lnkTriggerAction", "ext_key_to_me"=>"action_id", "ext_key_to_remote"=>"trigger_id", "allowed_values"=>null, "count_min"=>0, "count_max"=>0, "depends_on"=>array())));
// Display lists
MetaModel::Init_SetZListItems('details', array('name', 'description', 'status', 'trigger_list')); // Attributes to be displayed for the complete details
MetaModel::Init_SetZListItems('list', array('finalclass', 'name', 'description', 'status')); // Attributes to be displayed for a list
// Search criteria
MetaModel::Init_SetZListItems('default_search', array('name', 'description', 'status')); // Criteria of the std search form
// MetaModel::Init_SetZListItems('advanced_search', array('name')); // Criteria of the advanced search form
}
abstract public function DoExecute($oTrigger, $aContextArgs);
public function IsActive()
{
switch($this->Get('status'))
{
case 'enabled':
case 'test':
return true;
default:
return false;
}
}
public function IsBeingTested()
{
switch($this->Get('status'))
{
case 'test':
return true;
default:
return false;
}
}
}
/**
* A notification
*
* @package iTopORM
*/
abstract class ActionNotification extends Action
{
public static function Init()
{
$aParams = array
(
"category" => "grant_by_profile,core/cmdb",
"key_type" => "autoincrement",
"name_attcode" => "name",
"state_attcode" => "",
"reconc_keys" => array('name'),
"db_table" => "priv_action_notification",
"db_key_field" => "id",
"db_finalclass_field" => "",
"display_template" => "",
);
MetaModel::Init_Params($aParams);
MetaModel::Init_InheritAttributes();
// Display lists
MetaModel::Init_SetZListItems('details', array('name', 'description', 'status', 'trigger_list')); // Attributes to be displayed for the complete details
MetaModel::Init_SetZListItems('list', array('finalclass', 'name', 'description', 'status')); // Attributes to be displayed for a list
// Search criteria
// MetaModel::Init_SetZListItems('standard_search', array('name')); // Criteria of the std search form
// MetaModel::Init_SetZListItems('advanced_search', array('name')); // Criteria of the advanced search form
}
}
/**
* An email notification
*
* @package iTopORM
*/
class ActionEmail extends ActionNotification
{
public static function Init()
{
$aParams = array
(
"category" => "grant_by_profile,core/cmdb,application",
"key_type" => "autoincrement",
"name_attcode" => "name",
"state_attcode" => "",
"reconc_keys" => array('name'),
"db_table" => "priv_action_email",
"db_key_field" => "id",
"db_finalclass_field" => "",
"display_template" => "",
);
MetaModel::Init_Params($aParams);
MetaModel::Init_InheritAttributes();
MetaModel::Init_AddAttribute(new AttributeEmailAddress("test_recipient", array("allowed_values"=>null, "sql"=>"test_recipient", "default_value"=>"", "is_null_allowed"=>true, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeString("from", array("allowed_values"=>null, "sql"=>"from", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeString("reply_to", array("allowed_values"=>null, "sql"=>"reply_to", "default_value"=>null, "is_null_allowed"=>true, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeOQL("to", array("allowed_values"=>null, "sql"=>"to", "default_value"=>null, "is_null_allowed"=>true, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeOQL("cc", array("allowed_values"=>null, "sql"=>"cc", "default_value"=>null, "is_null_allowed"=>true, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeOQL("bcc", array("allowed_values"=>null, "sql"=>"bcc", "default_value"=>null, "is_null_allowed"=>true, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeTemplateString("subject", array("allowed_values"=>null, "sql"=>"subject", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeTemplateHTML("body", array("allowed_values"=>null, "sql"=>"body", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeEnum("importance", array("allowed_values"=>new ValueSetEnum('low,normal,high'), "sql"=>"importance", "default_value"=>'normal', "is_null_allowed"=>false, "depends_on"=>array())));
// Display lists
MetaModel::Init_SetZListItems('details', array('name', 'description', 'status', 'test_recipient', 'from', 'reply_to', 'to', 'cc', 'bcc', 'subject', 'body', 'importance', 'trigger_list')); // Attributes to be displayed for the complete details
MetaModel::Init_SetZListItems('list', array('name', 'status', 'to', 'subject')); // Attributes to be displayed for a list
// Search criteria
MetaModel::Init_SetZListItems('standard_search', array('name','description', 'status', 'subject')); // Criteria of the std search form
// MetaModel::Init_SetZListItems('advanced_search', array('name')); // Criteria of the advanced search form
}
// count the recipients found
protected $m_iRecipients;
// Errors management : not that simple because we need that function to be
// executed in the background, while making sure that any issue would be reported clearly
protected $m_aMailErrors; //array of strings explaining the issue
// returns a the list of emails as a string, or a detailed error description
protected function FindRecipients($sRecipAttCode, $aArgs)
{
$sOQL = $this->Get($sRecipAttCode);
if (strlen($sOQL) == '') return '';
try
{
$oSearch = DBObjectSearch::FromOQL($sOQL);
$oSearch->AllowAllData();
}
catch (OQLException $e)
{
$this->m_aMailErrors[] = "query syntax error for recipient '$sRecipAttCode'";
return $e->getMessage();
}
$sClass = $oSearch->GetClass();
// Determine the email attribute (the first one will be our choice)
foreach (MetaModel::ListAttributeDefs($sClass) as $sAttCode => $oAttDef)
{
if ($oAttDef instanceof AttributeEmailAddress)
{
$sEmailAttCode = $sAttCode;
// we've got one, exit the loop
break;
}
}
if (!isset($sEmailAttCode))
{
$this->m_aMailErrors[] = "wrong target for recipient '$sRecipAttCode'";
return "The objects of the class '$sClass' do not have any email attribute";
}
$oSet = new DBObjectSet($oSearch, array() /* order */, $aArgs);
$aRecipients = array();
while ($oObj = $oSet->Fetch())
{
$sAddress = trim($oObj->Get($sEmailAttCode));
if (strlen($sAddress) > 0)
{
$aRecipients[] = $sAddress;
$this->m_iRecipients++;
}
}
return implode(', ', $aRecipients);
}
/**
* @param \Trigger $oTrigger
* @param array $aContextArgs
*
* @throws \CoreException
* @throws \CoreUnexpectedValue
* @throws \CoreWarning
*/
public function DoExecute($oTrigger, $aContextArgs)
{
if (MetaModel::IsLogEnabledNotification())
{
$oLog = new EventNotificationEmail();
if ($this->IsBeingTested())
{
$oLog->Set('message', 'TEST - Notification sent ('.$this->Get('test_recipient').')');
}
else
{
$oLog->Set('message', 'Notification pending');
}
$oLog->Set('userinfo', UserRights::GetUser());
$oLog->Set('trigger_id', $oTrigger->GetKey());
$oLog->Set('action_id', $this->GetKey());
$oLog->Set('object_id', $aContextArgs['this->object()']->GetKey());
// Must be inserted now so that it gets a valid id that will make the link
// between an eventual asynchronous task (queued) and the log
$oLog->DBInsertNoReload();
}
else
{
$oLog = null;
}
try
{
$sRes = $this->_DoExecute($oTrigger, $aContextArgs, $oLog);
if ($this->IsBeingTested())
{
$sPrefix = 'TEST ('.$this->Get('test_recipient').') - ';
}
else
{
$sPrefix = '';
}
if ($oLog)
{
$oLog->Set('message', $sPrefix . $sRes);
$oLog->DBUpdate();
}
}
catch (Exception $e)
{
if ($oLog)
{
$oLog->Set('message', 'Error: '.$e->getMessage());
try
{
$oLog->DBUpdate();
}
catch (Exception $eSecondTryUpdate)
{
IssueLog::Error("Failed to process email ".$oLog->GetKey()." - reason: ".$e->getMessage()."\nTrace:\n".$e->getTraceAsString());
$oLog->Set('message', 'Error: more details in the log for email "'.$oLog->GetKey().'"');
$oLog->DBUpdate();
}
}
}
}
/**
* @param \Trigger $oTrigger
* @param array $aContextArgs
* @param \EventNotification $oLog
*
* @return string
* @throws \CoreException
*/
protected function _DoExecute($oTrigger, $aContextArgs, &$oLog)
{
$sPreviousUrlMaker = ApplicationContext::SetUrlMakerClass();
try
{
$this->m_iRecipients = 0;
$this->m_aMailErrors = array();
$bRes = false; // until we do succeed in sending the email
// Determine recicipients
//
$sTo = $this->FindRecipients('to', $aContextArgs);
$sCC = $this->FindRecipients('cc', $aContextArgs);
$sBCC = $this->FindRecipients('bcc', $aContextArgs);
$sFrom = MetaModel::ApplyParams($this->Get('from'), $aContextArgs);
$sReplyTo = MetaModel::ApplyParams($this->Get('reply_to'), $aContextArgs);
$sSubject = MetaModel::ApplyParams($this->Get('subject'), $aContextArgs);
$sBody = MetaModel::ApplyParams($this->Get('body'), $aContextArgs);
$oObj = $aContextArgs['this->object()'];
$sMessageId = sprintf('iTop_%s_%d_%f@%s.openitop.org', get_class($oObj), $oObj->GetKey(), microtime(true /* get as float*/), MetaModel::GetEnvironmentId());
$sReference = '<'.$sMessageId.'>';
}
catch(Exception $e)
{
ApplicationContext::SetUrlMakerClass($sPreviousUrlMaker);
throw $e;
}
ApplicationContext::SetUrlMakerClass($sPreviousUrlMaker);
if (!is_null($oLog))
{
// Note: we have to secure this because those values are calculated
// inside the try statement, and we would like to keep track of as
// many data as we could while some variables may still be undefined
if (isset($sTo)) $oLog->Set('to', $sTo);
if (isset($sCC)) $oLog->Set('cc', $sCC);
if (isset($sBCC)) $oLog->Set('bcc', $sBCC);
if (isset($sFrom)) $oLog->Set('from', $sFrom);
if (isset($sSubject)) $oLog->Set('subject', $sSubject);
if (isset($sBody)) $oLog->Set('body', $sBody);
}
$sStyles = file_get_contents(APPROOT.'css/email.css');
$sStyles .= MetaModel::GetConfig()->Get('email_css');
$oEmail = new EMail();
if ($this->IsBeingTested())
{
$oEmail->SetSubject('TEST['.$sSubject.']');
$sTestBody = $sBody;
$sTestBody .= "<div style=\"border: dashed;\">\n";
$sTestBody .= "<h1>Testing email notification ".$this->GetHyperlink()."</h1>\n";
$sTestBody .= "<p>The email should be sent with the following properties\n";
$sTestBody .= "<ul>\n";
$sTestBody .= "<li>TO: $sTo</li>\n";
$sTestBody .= "<li>CC: $sCC</li>\n";
$sTestBody .= "<li>BCC: $sBCC</li>\n";
$sTestBody .= "<li>From: $sFrom</li>\n";
$sTestBody .= "<li>Reply-To: $sReplyTo</li>\n";
$sTestBody .= "<li>References: $sReference</li>\n";
$sTestBody .= "</ul>\n";
$sTestBody .= "</p>\n";
$sTestBody .= "</div>\n";
$oEmail->SetBody($sTestBody, 'text/html', $sStyles);
$oEmail->SetRecipientTO($this->Get('test_recipient'));
$oEmail->SetRecipientFrom($sFrom);
$oEmail->SetReferences($sReference);
$oEmail->SetMessageId($sMessageId);
}
else
{
$oEmail->SetSubject($sSubject);
$oEmail->SetBody($sBody, 'text/html', $sStyles);
$oEmail->SetRecipientTO($sTo);
$oEmail->SetRecipientCC($sCC);
$oEmail->SetRecipientBCC($sBCC);
$oEmail->SetRecipientFrom($sFrom);
$oEmail->SetRecipientReplyTo($sReplyTo);
$oEmail->SetReferences($sReference);
$oEmail->SetMessageId($sMessageId);
}
if (isset($aContextArgs['attachments']))
{
$aAttachmentReport = array();
foreach($aContextArgs['attachments'] as $oDocument)
{
$oEmail->AddAttachment($oDocument->GetData(), $oDocument->GetFileName(), $oDocument->GetMimeType());
$aAttachmentReport[] = array($oDocument->GetFileName(), $oDocument->GetMimeType(), strlen($oDocument->GetData()));
}
$oLog->Set('attachments', $aAttachmentReport);
}
if (empty($this->m_aMailErrors))
{
if ($this->m_iRecipients == 0)
{
return 'No recipient';
}
else
{
$iRes = $oEmail->Send($aErrors, false, $oLog); // allow asynchronous mode
switch ($iRes)
{
case EMAIL_SEND_OK:
return "Sent";
case EMAIL_SEND_PENDING:
return "Pending";
case EMAIL_SEND_ERROR:
return "Errors: ".implode(', ', $aErrors);
}
}
}
else
{
if (is_array($this->m_aMailErrors) && count($this->m_aMailErrors) > 0)
{
$sError = implode(', ', $this->m_aMailErrors);
}
else
{
$sError = 'Unknown reason';
}
return 'Notification was not sent: '.$sError;
}
}
}
?>

98
core/apc-compat.php Normal file
View File

@@ -0,0 +1,98 @@
<?php
// Copyright (C) 2016-2017 Combodo SARL
//
// This file is part of iTop.
//
// iTop is free software; you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// iTop is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with iTop. If not, see <http://www.gnu.org/licenses/>
// Emulate the API of APC, over APCU
// Note: for PHP < 7, this compatibility used to be provided by APCU itself (if compiled with some options)
// for PHP 7+, it can be provided by the mean of apcu_bc, which is not so simple to install
// The current emulation aims at skipping this complexity
if (!function_exists('apc_store') && function_exists('apcu_store'))
{
function apc_add($key, $var, $ttl = 0)
{
return apcu_add($key, $var, $ttl);
}
function apc_cache_info($cache_type = '', $limited = false)
{
return apcu_cache_info($limited);
}
function apc_cas($key, $old, $new)
{
return apcu_cas($key, $old, $new);
}
function apc_clear_cache($cache_type = '')
{
return apcu_clear_cache();
}
function apc_dec($key, $step = 1, &$success = null)
{
apcu_dec($key, $step, $success);
}
function apc_delete($key)
{
return apcu_delete($key);
}
function apc_exists($keys)
{
return apcu_exists($keys);
}
function apc_fetch($key)
{
return apcu_fetch($key);
}
function apc_inc($key, $step = 1, &$success = null)
{
apcu_inc($key, $step, $success);
}
function apc_sma_info($limited = false)
{
return apcu_sma_info($limited);
}
function apc_store($key, $var, $ttl = 0)
{
return apcu_store($key, $var, $ttl);
}
}
/**
* Returns user cache info... beware of the format of the returned structure that may vary (See usages)
* @return array
*/
function apc_cache_info_compat()
{
if (!function_exists('apc_cache_info')) return array();
$oFunction = new ReflectionFunction('apc_cache_info');
if ($oFunction->getNumberOfParameters() != 2)
{
// Beware: APCu behaves slightly differently from APC !!
// Worse: the compatibility layer integrated into APC differs from apcu-bc (testing the number of parameters is a must)
// In CLI mode (PHP > 7) apc_cache_info returns null and outputs an error message.
$aCacheUserData = @apc_cache_info();
}
else
{
$aCacheUserData = @apc_cache_info('user');
}
return $aCacheUserData;
}
// Cache emulation
if (!function_exists('apc_store'))
{
require_once(APPROOT.'core/apc-emulation.php');
}

333
core/apc-emulation.php Normal file
View File

@@ -0,0 +1,333 @@
<?php
// Copyright (c) 2010-2017 Combodo SARL
//
// This file is part of iTop.
//
// iTop is free software; you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// iTop is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with iTop. If not, see <http://www.gnu.org/licenses/>
//
/**
* Date: 27/09/2017
*/
/**
* @param string $cache_type
* @param bool $limited
* @return array|bool
*/
function apc_cache_info($cache_type = '', $limited = false)
{
$aInfo = array();
$sRootCacheDir = apcFile::GetCacheFileName();
$aInfo['cache_list'] = apcFile::GetCacheEntries($sRootCacheDir);
return $aInfo;
}
/**
* @param array|string $key
* @param $var
* @param int $ttl
* @return array|bool
*/
function apc_store($key, $var = NULL, $ttl = 0)
{
if (is_array($key))
{
$aResult = array();
foreach($key as $sKey => $value)
{
$aResult[] = apcFile::StoreOneFile($sKey, $value, $ttl);
}
return $aResult;
}
return apcFile::StoreOneFile($key, $var, $ttl);
}
/**
* @param $key string|array
* @return mixed
*/
function apc_fetch($key)
{
if (is_array($key))
{
$aResult = array();
foreach($key as $sKey)
{
$aResult[$sKey] = apcFile::FetchOneFile($sKey);
}
return $aResult;
}
return apcFile::FetchOneFile($key);
}
/**
* @param string $cache_type
* @return bool
*/
function apc_clear_cache($cache_type = '')
{
apcFile::DeleteEntry(utils::GetCachePath());
return true;
}
/**
* @param $key
* @return bool|string[]
*/
function apc_delete($key)
{
if (empty($key))
{
return false;
}
$bRet1 = apcFile::DeleteEntry(apcFile::GetCacheFileName($key));
$bRet2 = apcFile::DeleteEntry(apcFile::GetCacheFileName('-'.$key));
return $bRet1 || $bRet2;
}
class apcFile
{
// Check only once per request
static public $aFilesByTime = null;
static public $iFileCount = 0;
/** Get the file name corresponding to the cache entry.
* If an empty key is provided, the root of the cache is returned.
* @param $sKey
* @return string
*/
static public function GetCacheFileName($sKey = '')
{
$sPath = str_replace(array(' ', '/', '\\', '.'), '-', $sKey);
return utils::GetCachePath().'apc-emul/'.$sPath;
}
/** Get the list of entries from a starting folder.
* @param $sEntry string starting folder.
* @return array list of entries stored into array of key 'info'
*/
static public function GetCacheEntries($sEntry)
{
$aResult = array();
if (is_dir($sEntry))
{
$aFiles = array_diff(scandir($sEntry), array('.', '..'));
foreach($aFiles as $sFile)
{
$sSubFile = $sEntry.'/'.$sFile;
$aResult = array_merge($aResult, self::GetCacheEntries($sSubFile));
}
}
else
{
$sKey = basename($sEntry);
if (strpos($sKey, '-') === 0)
{
$sKey = substr($sKey, 1);
}
$aResult[] = array('info' => $sKey);
}
return $aResult;
}
/** Delete one cache entry.
* @param $sCache
* @return bool true if the entry was deleted false if error occurs (like entry did not exist).
*/
static public function DeleteEntry($sCache)
{
if (is_dir($sCache))
{
$aFiles = array_diff(scandir($sCache), array('.', '..'));
foreach($aFiles as $sFile)
{
$sSubFile = $sCache.'/'.$sFile;
if (!self::DeleteEntry($sSubFile))
{
return false;
}
}
if (!@rmdir($sCache))
{
return false;
}
}
else
{
if (!@unlink($sCache))
{
return false;
}
}
self::ResetFileCount();
return true;
}
/** Get one cache entry content.
* @param $sKey
* @return bool|mixed
*/
static public function FetchOneFile($sKey)
{
// Try the 'TTLed' version
$sValue = self::ReadCacheLocked(self::GetCacheFileName('-'.$sKey));
if ($sValue === false)
{
$sValue = self::ReadCacheLocked(self::GetCacheFileName($sKey));
if ($sValue === false)
{
return false;
}
}
$oRes = @unserialize($sValue);
return $oRes;
}
/** Add one cache entry.
* @param string $sKey
* @param $value
* @param int $iTTL time to live
* @return bool
*/
static public function StoreOneFile($sKey, $value, $iTTL)
{
if (empty($sKey))
{
return false;
}
@unlink(self::GetCacheFileName($sKey));
@unlink(self::GetCacheFileName('-'.$sKey));
if ($iTTL > 0)
{
// hint for ttl management
$sKey = '-'.$sKey;
}
$sFilename = self::GetCacheFileName($sKey);
// try to create the folder
$sDirname = dirname($sFilename);
if (!file_exists($sDirname))
{
if (!@mkdir($sDirname, 0755, true))
{
return false;
}
}
$bRes = !(@file_put_contents($sFilename, serialize($value), LOCK_EX) === false);
self::AddFile($sFilename);
return $bRes;
}
/** Manage the cache files when adding a new cache entry:
* remove older files if the mamximum is reached.
* @param $sNewFilename
*/
static protected function AddFile($sNewFilename)
{
if (strpos(basename($sNewFilename), '-') !== 0)
{
return;
}
$iMaxFiles = MetaModel::GetConfig()->Get('apc_cache_emulation.max_entries');
if ($iMaxFiles == 0)
{
return;
}
if (!self::$aFilesByTime)
{
self::ListFilesByTime();
self::$iFileCount = count(self::$aFilesByTime);
if ($iMaxFiles !== 0)
{
asort(self::$aFilesByTime);
}
}
else
{
self::$aFilesByTime[$sNewFilename] = time();
self::$iFileCount++;
}
if (self::$iFileCount > $iMaxFiles)
{
$iFileNbToRemove = self::$iFileCount - $iMaxFiles;
foreach(self::$aFilesByTime as $sFileToRemove => $iTime)
{
@unlink($sFileToRemove);
if (--$iFileNbToRemove === 0)
{
break;
}
}
self::$aFilesByTime = array_slice(self::$aFilesByTime, self::$iFileCount - $iMaxFiles, null, true);
self::$iFileCount = $iMaxFiles;
}
}
/** Get the list of files with their associated access time
* @param string $sCheck Directory to scan
*/
static protected function ListFilesByTime($sCheck = null)
{
if (empty($sCheck))
{
$sCheck = self::GetCacheFileName();
}
// Garbage collection
$aFiles = array_diff(@scandir($sCheck), array('.', '..'));
foreach($aFiles as $sFile)
{
$sSubFile = $sCheck.'/'.$sFile;
if (is_dir($sSubFile))
{
self::ListFilesByTime($sSubFile);
}
else
{
if (strpos(basename($sSubFile), '-') === 0)
{
self::$aFilesByTime[$sSubFile] = @fileatime($sSubFile);
}
}
}
}
/** Read the content of one cache file under lock protection
* @param $sFilename
* @return bool|string the content of the cache entry or false if error
*/
static protected function ReadCacheLocked($sFilename)
{
$file = @fopen($sFilename, 'r');
if ($file === false)
{
return false;
}
flock($file, LOCK_SH);
$sContent = @fread($file, @filesize($sFilename));
flock($file, LOCK_UN);
fclose($file);
return $sContent;
}
static protected function ResetFileCount()
{
self::$aFilesByTime = null;
self::$iFileCount = 0;
}
}

View File

@@ -1,335 +1,335 @@
<?php
// Copyright (C) 2010-2012 Combodo SARL
//
// This file is part of iTop.
//
// iTop is free software; you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// iTop is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with iTop. If not, see <http://www.gnu.org/licenses/>
/**
* Utility to import/export the DB from/to a ZIP file
*
* @copyright Copyright (C) 2010-2012 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
/**
* iTopArchive a class to manipulate (read/write) iTop archives with their catalog
* Each iTop archive is a zip file that contains (at the root of the archive)
* a file called catalog.xml holding the description of the archive
*/
class iTopArchive
{
const read = 0;
const create = ZipArchive::CREATE;
protected $m_sZipPath;
protected $m_oZip;
protected $m_sVersion;
protected $m_sTitle;
protected $m_sDescription;
protected $m_aPackages;
protected $m_aErrorMessages;
/**
* Construct an iTopArchive object
* @param $sArchivePath string The full path the archive file
* @param $iMode integrer Either iTopArchive::read for reading an existing archive or iTopArchive::create for creating a new one. Updating is not supported (yet)
*/
public function __construct($sArchivePath, $iMode = iTopArchive::read)
{
$this->m_sZipPath = $sArchivePath;
$this->m_oZip = new ZipArchive();
$this->m_oZip->open($this->m_sZipPath, $iMode);
$this->m_aErrorMessages = array();
$this->m_sVersion = '1.0';
$this->m_sTitle = '';
$this->m_sDescription = '';
$this->m_aPackages = array();
}
public function SetTitle($sTitle)
{
$this->m_sTitle = $sTitle;
}
public function SetDescription($sDescription)
{
$this->m_sDescription = $sDescription;
}
public function GetTitle()
{
return $this->m_sTitle;
}
public function GetDescription()
{
return $this->m_sDescription;
}
public function GetPackages()
{
return $this->m_aPackages;
}
public function __destruct()
{
$this->m_oZip->close();
}
/**
* Get the error message explaining the latest error encountered
* @return array All the error messages encountered during the validation
*/
public function GetErrors()
{
return $this->m_aErrorMessages;
}
/**
* Read the catalog from the archive (zip) file
* @param sPath string Path the the zip file
* @return boolean True in case of success, false otherwise
*/
public function ReadCatalog()
{
if ($this->IsValid())
{
$sXmlCatalog = $this->m_oZip->getFromName('catalog.xml');
$oParser = xml_parser_create();
xml_parse_into_struct($oParser, $sXmlCatalog, $aValues, $aIndexes);
xml_parser_free($oParser);
$iIndex = $aIndexes['ARCHIVE'][0];
$this->m_sVersion = $aValues[$iIndex]['attributes']['VERSION'];
$iIndex = $aIndexes['TITLE'][0];
$this->m_sTitle = $aValues[$iIndex]['value'];
$iIndex = $aIndexes['DESCRIPTION'][0];
if (array_key_exists('value', $aValues[$iIndex]))
{
// #@# implement a get_array_value(array, key, default) ?
$this->m_sDescription = $aValues[$iIndex]['value'];
}
foreach($aIndexes['PACKAGE'] as $iIndex)
{
$this->m_aPackages[$aValues[$iIndex]['attributes']['HREF']] = array( 'type' => $aValues[$iIndex]['attributes']['TYPE'], 'title'=> $aValues[$iIndex]['attributes']['TITLE'], 'description' => $aValues[$iIndex]['value']);
}
//echo "Archive path: {$this->m_sZipPath}<br/>\n";
//echo "Archive format version: {$this->m_sVersion}<br/>\n";
//echo "Title: {$this->m_sTitle}<br/>\n";
//echo "Description: {$this->m_sDescription}<br/>\n";
//foreach($this->m_aPackages as $aFile)
//{
// echo "{$aFile['title']} ({$aFile['type']}): {$aFile['description']}<br/>\n";
//}
}
return true;
}
public function WriteCatalog()
{
$sXml = "<?xml version=\"1.0\" encoding=\"utf-8\"?".">\n"; // split the XML closing tag that disturbs PSPad's syntax coloring
$sXml .= "<archive version=\"1.0\">\n";
$sXml .= "<title>{$this->m_sTitle}</title>\n";
$sXml .= "<description>{$this->m_sDescription}</description>\n";
foreach($this->m_aPackages as $sFileName => $aFile)
{
$sXml .= "<package title=\"{$aFile['title']}\" type=\"{$aFile['type']}\" href=\"$sFileName\">{$aFile['description']}</package>\n";
}
$sXml .= "</archive>";
$this->m_oZip->addFromString('catalog.xml', $sXml);
}
/**
* Add a package to the archive
* @param string $sExternalFilePath The path to the file to be added to the archive as a package (directories are not yet implemented)
* @param string $sFilePath The name of the file inside the archive
* @param string $sTitle A short title for this package
* @param string $sType Type of the package. SQL scripts must be of type 'text/sql'
* @param string $sDescription A longer description of the purpose of this package
* @return none
*/
public function AddPackage($sExternalFilePath, $sFilePath, $sTitle, $sType, $sDescription)
{
$this->m_aPackages[$sFilePath] = array('title' => $sTitle, 'type' => $sType, 'description' => $sDescription);
$this->m_oZip->addFile($sExternalFilePath, $sFilePath);
}
/**
* Reads the contents of the given file from the archive
* @param string $sFileName The path to the file inside the archive
* @return string The content of the file read from the archive
*/
public function GetFileContents($sFileName)
{
return $this->m_oZip->getFromName($sFileName);
}
/**
* Extracts the contents of the given file from the archive
* @param string $sFileName The path to the file inside the archive
* @param string $sDestinationFileName The path of the file to write
* @return none
*/
public function ExtractToFile($sFileName, $sDestinationFileName)
{
$iBufferSize = 64 * 1024; // Read 64K at a time
$oZipStream = $this->m_oZip->getStream($sFileName);
$oDestinationStream = fopen($sDestinationFileName, 'wb');
while (!feof($oZipStream)) {
$sContents = fread($oZipStream, $iBufferSize);
fwrite($oDestinationStream, $sContents);
}
fclose($oZipStream);
fclose($oDestinationStream);
}
/**
* Apply a SQL script taken from the archive. The package must be listed in the catalog and of type text/sql
* @param string $sFileName The path to the SQL package inside the archive
* @return boolean false in case of error, true otherwise
*/
public function ImportSql($sFileName, $sDatabase = 'itop')
{
if ( ($this->m_oZip->locateName($sFileName) == false) || (!isset($this->m_aPackages[$sFileName])) || ($this->m_aPackages[$sFileName]['type'] != 'text/sql'))
{
// invalid type or not listed in the catalog
return false;
}
$sTempName = tempnam("../tmp/", "sql");
//echo "Extracting to: '$sTempName'<br/>\n";
$this->ExtractToFile($sFileName, $sTempName);
// Note: the command line below works on Windows with the right path to mysql !!!
$sCommandLine = 'type "'.$sTempName.'" | "/iTop/MySQL Server 5.0/bin/mysql.exe" -u root '.$sDatabase;
//echo "Executing: '$sCommandLine'<br/>\n";
exec($sCommandLine, $aOutput, $iRet);
//echo "Return code: $iRet<br/>\n";
//echo "Output:<br/><pre>\n";
//print_r($aOutput);
//echo "</pre><br/>\n";
unlink($sTempName);
return ($iRet == 0);
}
/**
* Dumps some part of the specified MySQL database into the archive as a text/sql package
* @param $sTitle string A short title for this SQL script
* @param $sDescription string A longer description of the purpose of this SQL script
* @param $sFileName string The name of the package inside the archive
* @param $sDatabase string name of the database
* @param $aTables array array or table names. If empty, all tables are dumped
* @param $bStructureOnly boolean Whether or not to dump the data or just the schema
* @return boolean False in case of error, true otherwise
*/
public function AddDatabaseDump($sTitle, $sDescription, $sFileName, $sDatabase = 'itop', $aTables = array(), $bStructureOnly = true)
{
$sTempName = tempnam("../tmp/", "sql");
$sNoData = $bStructureOnly ? "--no-data" : "";
$sCommandLine = "\"/iTop/MySQL Server 5.0/bin/mysqldump.exe\" --user=root --opt $sNoData --result-file=$sTempName $sDatabase ".implode(" ", $aTables);
//echo "Executing command: '$sCommandLine'<br/>\n";
exec($sCommandLine, $aOutput, $iRet);
//echo "Return code: $iRet<br/>\n";
//echo "Output:<br/><pre>\n";
//print_r($aOutput);
//echo "</pre><br/>\n";
if ($iRet == 0)
{
$this->AddPackage($sTempName, $sFileName, $sTitle, 'text/sql', $sDescription);
}
//unlink($sTempName);
return ($iRet == 0);
}
/**
* Check the consistency of the archive
* @return boolean True if the archive file is consistent
*/
public function IsValid()
{
// TO DO: use a DTD to validate the XML instead of this hand-made validation
$bResult = true;
$aMandatoryTags = array('ARCHIVE' => array('VERSION'),
'TITLE' => array(),
'DESCRIPTION' => array(),
'PACKAGE' => array('TYPE', 'HREF', 'TITLE'));
$sXmlCatalog = $this->m_oZip->getFromName('catalog.xml');
$oParser = xml_parser_create();
xml_parse_into_struct($oParser, $sXmlCatalog, $aValues, $aIndexes);
xml_parser_free($oParser);
foreach($aMandatoryTags as $sTag => $aAttributes)
{
// Check that all the required tags are present
if (!isset($aIndexes[$sTag]))
{
$this->m_aErrorMessages[] = "The XML catalog does not contain the mandatory tag $sTag.";
$bResult = false;
}
else
{
foreach($aIndexes[$sTag] as $iIndex)
{
switch($aValues[$iIndex]['type'])
{
case 'complete':
case 'open':
// Check that all the required attributes are present
foreach($aAttributes as $sAttribute)
{
if (!isset($aValues[$iIndex]['attributes'][$sAttribute]))
{
$this->m_aErrorMessages[] = "The tag $sTag ($iIndex) does not contain the required attribute $sAttribute.";
}
}
break;
default:
// ignore other type of tags: close or cdata
}
}
}
}
return $bResult;
}
}
/*
// Unit test - reading an archive
$sArchivePath = '../tmp/archive.zip';
$oArchive = new iTopArchive($sArchivePath, iTopArchive::read);
$oArchive->ReadCatalog();
$oArchive->ImportSql('full_backup.sql');
// Writing an archive --
$sArchivePath = '../tmp/archive2.zip';
$oArchive = new iTopArchive($sArchivePath, iTopArchive::create);
$oArchive->SetTitle('First Archive !');
$oArchive->SetDescription('This is just a test. Does not contain a lot of useful data.');
$oArchive->AddPackage('../tmp/schema.sql', 'test.sql', 'this is just a test', 'text/sql', 'My first attempt at creating an archive from PHP...');
$oArchive->WriteCatalog();
$sArchivePath = '../tmp/archive2.zip';
$oArchive = new iTopArchive($sArchivePath, iTopArchive::create);
$oArchive->SetTitle('First Archive !');
$oArchive->SetDescription('This is just a test. Does not contain a lot of useful data.');
$oArchive->AddDatabaseDump('Test', 'This is my first automatic dump', 'schema.sql', 'itop', array('objects'));
$oArchive->WriteCatalog();
*/
?>
<?php
// Copyright (C) 2010-2012 Combodo SARL
//
// This file is part of iTop.
//
// iTop is free software; you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// iTop is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with iTop. If not, see <http://www.gnu.org/licenses/>
/**
* Utility to import/export the DB from/to a ZIP file
*
* @copyright Copyright (C) 2010-2012 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
/**
* iTopArchive a class to manipulate (read/write) iTop archives with their catalog
* Each iTop archive is a zip file that contains (at the root of the archive)
* a file called catalog.xml holding the description of the archive
*/
class iTopArchive
{
const read = 0;
const create = ZipArchive::CREATE;
protected $m_sZipPath;
protected $m_oZip;
protected $m_sVersion;
protected $m_sTitle;
protected $m_sDescription;
protected $m_aPackages;
protected $m_aErrorMessages;
/**
* Construct an iTopArchive object
* @param $sArchivePath string The full path the archive file
* @param $iMode integrer Either iTopArchive::read for reading an existing archive or iTopArchive::create for creating a new one. Updating is not supported (yet)
*/
public function __construct($sArchivePath, $iMode = iTopArchive::read)
{
$this->m_sZipPath = $sArchivePath;
$this->m_oZip = new ZipArchive();
$this->m_oZip->open($this->m_sZipPath, $iMode);
$this->m_aErrorMessages = array();
$this->m_sVersion = '1.0';
$this->m_sTitle = '';
$this->m_sDescription = '';
$this->m_aPackages = array();
}
public function SetTitle($sTitle)
{
$this->m_sTitle = $sTitle;
}
public function SetDescription($sDescription)
{
$this->m_sDescription = $sDescription;
}
public function GetTitle()
{
return $this->m_sTitle;
}
public function GetDescription()
{
return $this->m_sDescription;
}
public function GetPackages()
{
return $this->m_aPackages;
}
public function __destruct()
{
$this->m_oZip->close();
}
/**
* Get the error message explaining the latest error encountered
* @return array All the error messages encountered during the validation
*/
public function GetErrors()
{
return $this->m_aErrorMessages;
}
/**
* Read the catalog from the archive (zip) file
* @param sPath string Path the the zip file
* @return boolean True in case of success, false otherwise
*/
public function ReadCatalog()
{
if ($this->IsValid())
{
$sXmlCatalog = $this->m_oZip->getFromName('catalog.xml');
$oParser = xml_parser_create();
xml_parse_into_struct($oParser, $sXmlCatalog, $aValues, $aIndexes);
xml_parser_free($oParser);
$iIndex = $aIndexes['ARCHIVE'][0];
$this->m_sVersion = $aValues[$iIndex]['attributes']['VERSION'];
$iIndex = $aIndexes['TITLE'][0];
$this->m_sTitle = $aValues[$iIndex]['value'];
$iIndex = $aIndexes['DESCRIPTION'][0];
if (array_key_exists('value', $aValues[$iIndex]))
{
// #@# implement a get_array_value(array, key, default) ?
$this->m_sDescription = $aValues[$iIndex]['value'];
}
foreach($aIndexes['PACKAGE'] as $iIndex)
{
$this->m_aPackages[$aValues[$iIndex]['attributes']['HREF']] = array( 'type' => $aValues[$iIndex]['attributes']['TYPE'], 'title'=> $aValues[$iIndex]['attributes']['TITLE'], 'description' => $aValues[$iIndex]['value']);
}
//echo "Archive path: {$this->m_sZipPath}<br/>\n";
//echo "Archive format version: {$this->m_sVersion}<br/>\n";
//echo "Title: {$this->m_sTitle}<br/>\n";
//echo "Description: {$this->m_sDescription}<br/>\n";
//foreach($this->m_aPackages as $aFile)
//{
// echo "{$aFile['title']} ({$aFile['type']}): {$aFile['description']}<br/>\n";
//}
}
return true;
}
public function WriteCatalog()
{
$sXml = "<?xml version=\"1.0\" encoding=\"utf-8\"?".">\n"; // split the XML closing tag that disturbs PSPad's syntax coloring
$sXml .= "<archive version=\"1.0\">\n";
$sXml .= "<title>{$this->m_sTitle}</title>\n";
$sXml .= "<description>{$this->m_sDescription}</description>\n";
foreach($this->m_aPackages as $sFileName => $aFile)
{
$sXml .= "<package title=\"{$aFile['title']}\" type=\"{$aFile['type']}\" href=\"$sFileName\">{$aFile['description']}</package>\n";
}
$sXml .= "</archive>";
$this->m_oZip->addFromString('catalog.xml', $sXml);
}
/**
* Add a package to the archive
* @param string $sExternalFilePath The path to the file to be added to the archive as a package (directories are not yet implemented)
* @param string $sFilePath The name of the file inside the archive
* @param string $sTitle A short title for this package
* @param string $sType Type of the package. SQL scripts must be of type 'text/sql'
* @param string $sDescription A longer description of the purpose of this package
* @return none
*/
public function AddPackage($sExternalFilePath, $sFilePath, $sTitle, $sType, $sDescription)
{
$this->m_aPackages[$sFilePath] = array('title' => $sTitle, 'type' => $sType, 'description' => $sDescription);
$this->m_oZip->addFile($sExternalFilePath, $sFilePath);
}
/**
* Reads the contents of the given file from the archive
* @param string $sFileName The path to the file inside the archive
* @return string The content of the file read from the archive
*/
public function GetFileContents($sFileName)
{
return $this->m_oZip->getFromName($sFileName);
}
/**
* Extracts the contents of the given file from the archive
* @param string $sFileName The path to the file inside the archive
* @param string $sDestinationFileName The path of the file to write
* @return none
*/
public function ExtractToFile($sFileName, $sDestinationFileName)
{
$iBufferSize = 64 * 1024; // Read 64K at a time
$oZipStream = $this->m_oZip->getStream($sFileName);
$oDestinationStream = fopen($sDestinationFileName, 'wb');
while (!feof($oZipStream)) {
$sContents = fread($oZipStream, $iBufferSize);
fwrite($oDestinationStream, $sContents);
}
fclose($oZipStream);
fclose($oDestinationStream);
}
/**
* Apply a SQL script taken from the archive. The package must be listed in the catalog and of type text/sql
* @param string $sFileName The path to the SQL package inside the archive
* @return boolean false in case of error, true otherwise
*/
public function ImportSql($sFileName, $sDatabase = 'itop')
{
if ( ($this->m_oZip->locateName($sFileName) == false) || (!isset($this->m_aPackages[$sFileName])) || ($this->m_aPackages[$sFileName]['type'] != 'text/sql'))
{
// invalid type or not listed in the catalog
return false;
}
$sTempName = tempnam("../tmp/", "sql");
//echo "Extracting to: '$sTempName'<br/>\n";
$this->ExtractToFile($sFileName, $sTempName);
// Note: the command line below works on Windows with the right path to mysql !!!
$sCommandLine = 'type "'.$sTempName.'" | "/iTop/MySQL Server 5.0/bin/mysql.exe" -u root '.$sDatabase;
//echo "Executing: '$sCommandLine'<br/>\n";
exec($sCommandLine, $aOutput, $iRet);
//echo "Return code: $iRet<br/>\n";
//echo "Output:<br/><pre>\n";
//print_r($aOutput);
//echo "</pre><br/>\n";
unlink($sTempName);
return ($iRet == 0);
}
/**
* Dumps some part of the specified MySQL database into the archive as a text/sql package
* @param $sTitle string A short title for this SQL script
* @param $sDescription string A longer description of the purpose of this SQL script
* @param $sFileName string The name of the package inside the archive
* @param $sDatabase string name of the database
* @param $aTables array array or table names. If empty, all tables are dumped
* @param $bStructureOnly boolean Whether or not to dump the data or just the schema
* @return boolean False in case of error, true otherwise
*/
public function AddDatabaseDump($sTitle, $sDescription, $sFileName, $sDatabase = 'itop', $aTables = array(), $bStructureOnly = true)
{
$sTempName = tempnam("../tmp/", "sql");
$sNoData = $bStructureOnly ? "--no-data" : "";
$sCommandLine = "\"/iTop/MySQL Server 5.0/bin/mysqldump.exe\" --user=root --opt $sNoData --result-file=$sTempName $sDatabase ".implode(" ", $aTables);
//echo "Executing command: '$sCommandLine'<br/>\n";
exec($sCommandLine, $aOutput, $iRet);
//echo "Return code: $iRet<br/>\n";
//echo "Output:<br/><pre>\n";
//print_r($aOutput);
//echo "</pre><br/>\n";
if ($iRet == 0)
{
$this->AddPackage($sTempName, $sFileName, $sTitle, 'text/sql', $sDescription);
}
//unlink($sTempName);
return ($iRet == 0);
}
/**
* Check the consistency of the archive
* @return boolean True if the archive file is consistent
*/
public function IsValid()
{
// TO DO: use a DTD to validate the XML instead of this hand-made validation
$bResult = true;
$aMandatoryTags = array('ARCHIVE' => array('VERSION'),
'TITLE' => array(),
'DESCRIPTION' => array(),
'PACKAGE' => array('TYPE', 'HREF', 'TITLE'));
$sXmlCatalog = $this->m_oZip->getFromName('catalog.xml');
$oParser = xml_parser_create();
xml_parse_into_struct($oParser, $sXmlCatalog, $aValues, $aIndexes);
xml_parser_free($oParser);
foreach($aMandatoryTags as $sTag => $aAttributes)
{
// Check that all the required tags are present
if (!isset($aIndexes[$sTag]))
{
$this->m_aErrorMessages[] = "The XML catalog does not contain the mandatory tag $sTag.";
$bResult = false;
}
else
{
foreach($aIndexes[$sTag] as $iIndex)
{
switch($aValues[$iIndex]['type'])
{
case 'complete':
case 'open':
// Check that all the required attributes are present
foreach($aAttributes as $sAttribute)
{
if (!isset($aValues[$iIndex]['attributes'][$sAttribute]))
{
$this->m_aErrorMessages[] = "The tag $sTag ($iIndex) does not contain the required attribute $sAttribute.";
}
}
break;
default:
// ignore other type of tags: close or cdata
}
}
}
}
return $bResult;
}
}
/*
// Unit test - reading an archive
$sArchivePath = '../tmp/archive.zip';
$oArchive = new iTopArchive($sArchivePath, iTopArchive::read);
$oArchive->ReadCatalog();
$oArchive->ImportSql('full_backup.sql');
// Writing an archive --
$sArchivePath = '../tmp/archive2.zip';
$oArchive = new iTopArchive($sArchivePath, iTopArchive::create);
$oArchive->SetTitle('First Archive !');
$oArchive->SetDescription('This is just a test. Does not contain a lot of useful data.');
$oArchive->AddPackage('../tmp/schema.sql', 'test.sql', 'this is just a test', 'text/sql', 'My first attempt at creating an archive from PHP...');
$oArchive->WriteCatalog();
$sArchivePath = '../tmp/archive2.zip';
$oArchive = new iTopArchive($sArchivePath, iTopArchive::create);
$oArchive->SetTitle('First Archive !');
$oArchive->SetDescription('This is just a test. Does not contain a lot of useful data.');
$oArchive->AddDatabaseDump('Test', 'This is my first automatic dump', 'schema.sql', 'itop', array('objects'));
$oArchive->WriteCatalog();
*/
?>

View File

@@ -1,359 +1,385 @@
<?php
// Copyright (C) 2010-2012 Combodo SARL
//
// This file is part of iTop.
//
// iTop is free software; you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// iTop is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with iTop. If not, see <http://www.gnu.org/licenses/>
/**
* Persistent classes (internal): user defined actions
*
* @copyright Copyright (C) 2010-2012 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
class ExecAsyncTask implements iBackgroundProcess
{
public function GetPeriodicity()
{
return 2; // seconds
}
public function Process($iTimeLimit)
{
$sNow = date('Y-m-d H:i:s');
// Criteria: planned, and expected to occur... ASAP or in the past
$sOQL = "SELECT AsyncTask WHERE (status = 'planned') AND (ISNULL(planned) OR (planned < '$sNow'))";
$iProcessed = 0;
while (time() < $iTimeLimit)
{
// Next one ?
$oSet = new CMDBObjectSet(DBObjectSearch::FromOQL($sOQL), array('created' => true) /* order by*/, array(), null, 1 /* limit count */);
$oTask = $oSet->Fetch();
if (is_null($oTask))
{
// Nothing to be done
break;
}
$iProcessed++;
if ($oTask->Process())
{
$oTask->DBDelete();
}
}
return "processed $iProcessed tasks";
}
}
/**
* 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);
// Null is allowed to ease the migration from iTop 2.0.2 and earlier, when the status did not exist, and because the default value is not taken into account in the SQL definition
// The value is set from null to planned in the setup program
MetaModel::Init_AddAttribute(new AttributeEnum("status", array("allowed_values"=>new ValueSetEnum('planned,running,idle,error'), "sql"=>"status", "default_value"=>"planned", "is_null_allowed"=>true, "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())));
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())));
MetaModel::Init_AddAttribute(new AttributeInteger("remaining_retries", array("allowed_values"=>null, "sql"=>"remaining_retries", "default_value"=>0, "is_null_allowed"=>true, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeInteger("last_error_code", array("allowed_values"=>null, "sql"=>"last_error_code", "default_value"=>0, "is_null_allowed"=>true, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeString("last_error", array("allowed_values"=>null, "sql"=>"last_error", "default_value"=>'', "is_null_allowed"=>true, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeDateTime("last_attempt", array("allowed_values"=>null, "sql"=>"last_attempt", "default_value"=>"", "is_null_allowed"=>true, "depends_on"=>array())));
}
/**
* Every is fine
*/
const OK = 0;
/**
* The task no longer exists
*/
const DELETED = 1;
/**
* The task is already being executed
*/
const ALREADY_RUNNING = 2;
/**
* The current process requests the ownership on the task.
* In case the task can be accessed concurrently, this function can be overloaded to add a critical section.
* The function must not block the caller if another process is already owning the task
*
* @return integer A code among OK/DELETED/ALREADY_RUNNING.
*/
public function MarkAsRunning()
{
try
{
if ($this->Get('status') == 'running')
{
return self::ALREADY_RUNNING;
}
else
{
$this->Set('status', 'running');
$this->Set('started', time());
$this->DBUpdate();
return self::OK;
}
}
catch(Exception $e)
{
// Corrupted task !! (for example: "Failed to reload object")
IssueLog::Error('Failed to process async task #'.$this->GetKey().' - reason: '.$e->getMessage().' - fatal error, deleting the task.');
if ($this->Get('event_id') != 0)
{
$oEventLog = MetaModel::GetObject('Event', $this->Get('event_id'));
$oEventLog->Set('message', 'Failed, corrupted data: '.$e->getMessage());
$oEventLog->DBUpdate();
}
$this->DBDelete();
return self::DELETED;
}
}
public function GetRetryDelay($iErrorCode = null)
{
$iRetryDelay = 600;
$aRetries = MetaModel::GetConfig()->Get('async_task_retries', array());
if (is_array($aRetries) && array_key_exists(get_class($this), $aRetries))
{
$aConfig = $aRetries[get_class($this)];
$iRetryDelay = $aConfig['retry_delay'];
}
return $iRetryDelay;
}
public function GetMaxRetries($iErrorCode = null)
{
$iMaxRetries = 0;
$aRetries = MetaModel::GetConfig()->Get('async_task_retries', array());
if (is_array($aRetries) && array_key_exists(get_class($this), $aRetries))
{
$aConfig = $aRetries[get_class($this)];
$iMaxRetries = $aConfig['max_retries'];
}
}
/**
* Override to notify people that a task cannot be performed
*/
protected function OnDefinitiveFailure()
{
}
protected function OnInsert()
{
$this->Set('created', time());
}
/**
* @return boolean True if the task record can be deleted
*/
public function Process()
{
// By default: consider that the task is not completed
$bRet = false;
// Attempt to take the ownership
$iStatus = $this->MarkAsRunning();
if ($iStatus == self::OK)
{
try
{
$sStatus = $this->DoProcess();
if ($this->Get('event_id') != 0)
{
$oEventLog = MetaModel::GetObject('Event', $this->Get('event_id'));
$oEventLog->Set('message', $sStatus);
$oEventLog->DBUpdate();
}
$bRet = true;
}
catch(Exception $e)
{
$this->HandleError($e->getMessage(), $e->getCode());
}
}
else
{
// Already done or being handled by another process... skip...
$bRet = false;
}
return $bRet;
}
/**
* Overridable to extend the behavior in case of error (logging)
*/
protected function HandleError($sErrorMessage, $iErrorCode)
{
if ($this->Get('last_attempt') == '')
{
// First attempt
$this->Set('remaining_retries', $this->GetMaxRetries($iErrorCode));
}
$this->Set('last_error', $sErrorMessage);
$this->Set('last_error_code', $iErrorCode); // Note: can be ZERO !!!
$this->Set('last_attempt', time());
$iRemaining = $this->Get('remaining_retries');
if ($iRemaining > 0)
{
$iRetryDelay = $this->GetRetryDelay($iErrorCode);
IssueLog::Info('Failed to process async task #'.$this->GetKey().' - reason: '.$sErrorMessage.' - remaining retries: '.$iRemaining.' - next retry in '.$iRetryDelay.'s');
$this->Set('remaining_retries', $iRemaining - 1);
$this->Set('status', 'planned');
$this->Set('started', null);
$this->Set('planned', time() + $iRetryDelay);
}
else
{
IssueLog::Error('Failed to process async task #'.$this->GetKey().' - reason: '.$sErrorMessage);
$this->Set('status', 'error');
$this->Set('started', null);
$this->Set('planned', null);
$this->OnDefinitiveFailure();
}
$this->DBUpdate();
}
/**
* Throws an exception (message and code)
*/
abstract public function DoProcess();
/**
* Describes the error codes that DoProcess can return by the mean of exceptions
*/
static public function EnumErrorCodes()
{
return array();
}
}
/**
* 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 AttributeInteger("version", array("allowed_values"=>null, "sql"=>"version", "default_value"=>Email::ORIGINAL_FORMAT, "is_null_allowed"=>false, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeText("to", array("allowed_values"=>null, "sql"=>"to", "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"=>false, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeLongText("message", array("allowed_values"=>null, "sql"=>"message", "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(EMail $oEMail, $oLog)
{
$oNew = MetaModel::NewObject(__class__);
if ($oLog)
{
$oNew->Set('event_id', $oLog->GetKey());
}
$oNew->Set('to', $oEMail->GetRecipientTO(true /* string */));
$oNew->Set('subject', $oEMail->GetSubject());
// $oNew->Set('version', 1);
// $sMessage = serialize($oEMail);
$oNew->Set('version', 2);
$sMessage = $oEMail->SerializeV2();
$oNew->Set('message', $sMessage);
$oNew->DBInsert();
}
public function DoProcess()
{
$sMessage = $this->Get('message');
$iVersion = (int) $this->Get('version');
switch($iVersion)
{
case Email::FORMAT_V2:
$oEMail = Email::UnSerializeV2($sMessage);
break;
case Email::ORIGINAL_FORMAT:
$oEMail = unserialize($sMessage);
break;
default:
return 'Unknown version of the serialization format: '.$iVersion;
}
$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);
}
}
}
?>
<?php
// Copyright (C) 2010-2012 Combodo SARL
//
// This file is part of iTop.
//
// iTop is free software; you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// iTop is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with iTop. If not, see <http://www.gnu.org/licenses/>
/**
* Persistent classes (internal): user defined actions
*
* @copyright Copyright (C) 2010-2012 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
class ExecAsyncTask implements iBackgroundProcess
{
public function GetPeriodicity()
{
return 2; // seconds
}
public function Process($iTimeLimit)
{
$sNow = date(AttributeDateTime::GetSQLFormat());
// Criteria: planned, and expected to occur... ASAP or in the past
$sOQL = "SELECT AsyncTask WHERE (status = 'planned') AND (ISNULL(planned) OR (planned < '$sNow'))";
$iProcessed = 0;
while (time() < $iTimeLimit)
{
// Next one ?
$oSet = new CMDBObjectSet(DBObjectSearch::FromOQL($sOQL), array('created' => true) /* order by*/, array(), null, 1 /* limit count */);
$oTask = $oSet->Fetch();
if (is_null($oTask))
{
// Nothing to be done
break;
}
$iProcessed++;
if ($oTask->Process())
{
$oTask->DBDelete();
}
}
return "processed $iProcessed tasks";
}
}
/**
* 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);
// Null is allowed to ease the migration from iTop 2.0.2 and earlier, when the status did not exist, and because the default value is not taken into account in the SQL definition
// The value is set from null to planned in the setup program
MetaModel::Init_AddAttribute(new AttributeEnum("status", array("allowed_values"=>new ValueSetEnum('planned,running,idle,error'), "sql"=>"status", "default_value"=>"planned", "is_null_allowed"=>true, "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())));
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())));
MetaModel::Init_AddAttribute(new AttributeInteger("remaining_retries", array("allowed_values"=>null, "sql"=>"remaining_retries", "default_value"=>0, "is_null_allowed"=>true, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeInteger("last_error_code", array("allowed_values"=>null, "sql"=>"last_error_code", "default_value"=>0, "is_null_allowed"=>true, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeString("last_error", array("allowed_values"=>null, "sql"=>"last_error", "default_value"=>'', "is_null_allowed"=>true, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeDateTime("last_attempt", array("allowed_values"=>null, "sql"=>"last_attempt", "default_value"=>"", "is_null_allowed"=>true, "depends_on"=>array())));
}
/**
* Every is fine
*/
const OK = 0;
/**
* The task no longer exists
*/
const DELETED = 1;
/**
* The task is already being executed
*/
const ALREADY_RUNNING = 2;
/**
* The current process requests the ownership on the task.
* In case the task can be accessed concurrently, this function can be overloaded to add a critical section.
* The function must not block the caller if another process is already owning the task
*
* @return integer A code among OK/DELETED/ALREADY_RUNNING.
*/
public function MarkAsRunning()
{
try
{
if ($this->Get('status') == 'running')
{
return self::ALREADY_RUNNING;
}
else
{
$this->Set('status', 'running');
$this->Set('started', time());
$this->DBUpdate();
return self::OK;
}
}
catch(Exception $e)
{
// Corrupted task !! (for example: "Failed to reload object")
IssueLog::Error('Failed to process async task #'.$this->GetKey().' - reason: '.$e->getMessage().' - fatal error, deleting the task.');
if ($this->Get('event_id') != 0)
{
$oEventLog = MetaModel::GetObject('Event', $this->Get('event_id'));
$oEventLog->Set('message', 'Failed, corrupted data: '.$e->getMessage());
$oEventLog->DBUpdate();
}
$this->DBDelete();
return self::DELETED;
}
}
public function GetRetryDelay($iErrorCode = null)
{
$iRetryDelay = 600;
$aRetries = MetaModel::GetConfig()->Get('async_task_retries', array());
if (is_array($aRetries) && array_key_exists(get_class($this), $aRetries))
{
$aConfig = $aRetries[get_class($this)];
$iRetryDelay = $aConfig['retry_delay'];
}
return $iRetryDelay;
}
public function GetMaxRetries($iErrorCode = null)
{
$iMaxRetries = 0;
$aRetries = MetaModel::GetConfig()->Get('async_task_retries', array());
if (is_array($aRetries) && array_key_exists(get_class($this), $aRetries))
{
$aConfig = $aRetries[get_class($this)];
$iMaxRetries = $aConfig['max_retries'];
}
}
/**
* Override to notify people that a task cannot be performed
*/
protected function OnDefinitiveFailure()
{
}
protected function OnInsert()
{
$this->Set('created', time());
}
/**
* @return boolean True if the task record can be deleted
*/
public function Process()
{
// By default: consider that the task is not completed
$bRet = false;
// Attempt to take the ownership
$iStatus = $this->MarkAsRunning();
if ($iStatus == self::OK)
{
try
{
$sStatus = $this->DoProcess();
if ($this->Get('event_id') != 0)
{
$oEventLog = MetaModel::GetObject('Event', $this->Get('event_id'));
$oEventLog->Set('message', $sStatus);
$oEventLog->DBUpdate();
}
$bRet = true;
} catch (Exception $e)
{
$this->HandleError($e->getMessage(), $e->getCode());
}
}
else
{
// Already done or being handled by another process... skip...
$bRet = false;
}
return $bRet;
}
/**
* Overridable to extend the behavior in case of error (logging)
*/
protected function HandleError($sErrorMessage, $iErrorCode)
{
if ($this->Get('last_attempt') == '')
{
// First attempt
$this->Set('remaining_retries', $this->GetMaxRetries($iErrorCode));
}
$this->Set('last_error', $sErrorMessage);
$this->Set('last_error_code', $iErrorCode); // Note: can be ZERO !!!
$this->Set('last_attempt', time());
$iRemaining = $this->Get('remaining_retries');
if ($iRemaining > 0)
{
$iRetryDelay = $this->GetRetryDelay($iErrorCode);
IssueLog::Info('Failed to process async task #'.$this->GetKey().' - reason: '.$sErrorMessage.' - remaining retries: '.$iRemaining.' - next retry in '.$iRetryDelay.'s');
if ($this->Get('event_id') != 0)
{
$oEventLog = MetaModel::GetObject('Event', $this->Get('event_id'));
$oEventLog->Set('message', "$sErrorMessage\nFailed to process async task. Remaining retries: '.$iRemaining.'. Next retry in '.$iRetryDelay.'s'");
try
{
$oEventLog->DBUpdate();
}
catch (Exception $e)
{
$oEventLog->Set('message', "Failed to process async task. Remaining retries: '.$iRemaining.'. Next retry in '.$iRetryDelay.'s', more details in the log");
$oEventLog->DBUpdate();
}
}
$this->Set('remaining_retries', $iRemaining - 1);
$this->Set('status', 'planned');
$this->Set('started', null);
$this->Set('planned', time() + $iRetryDelay);
}
else
{
IssueLog::Error('Failed to process async task #'.$this->GetKey().' - reason: '.$sErrorMessage);
if ($this->Get('event_id') != 0)
{
$oEventLog = MetaModel::GetObject('Event', $this->Get('event_id'));
$oEventLog->Set('message', "$sErrorMessage\nFailed to process async task.");
try
{
$oEventLog->DBUpdate();
}
catch (Exception $e)
{
$oEventLog->Set('message', 'Failed to process async task, more details in the log');
$oEventLog->DBUpdate();
}
}
$this->Set('status', 'error');
$this->Set('started', null);
$this->Set('planned', null);
$this->OnDefinitiveFailure();
}
$this->DBUpdate();
}
/**
* Throws an exception (message and code)
*/
abstract public function DoProcess();
/**
* Describes the error codes that DoProcess can return by the mean of exceptions
*/
static public function EnumErrorCodes()
{
return array();
}
}
/**
* 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 AttributeInteger("version", array("allowed_values"=>null, "sql"=>"version", "default_value"=>Email::ORIGINAL_FORMAT, "is_null_allowed"=>false, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeText("to", array("allowed_values"=>null, "sql"=>"to", "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"=>false, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeLongText("message", array("allowed_values"=>null, "sql"=>"message", "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(EMail $oEMail, $oLog)
{
$oNew = MetaModel::NewObject(__class__);
if ($oLog)
{
$oNew->Set('event_id', $oLog->GetKey());
}
$oNew->Set('to', $oEMail->GetRecipientTO(true /* string */));
$oNew->Set('subject', $oEMail->GetSubject());
// $oNew->Set('version', 1);
// $sMessage = serialize($oEMail);
$oNew->Set('version', 2);
$sMessage = $oEMail->SerializeV2();
$oNew->Set('message', $sMessage);
$oNew->DBInsert();
}
public function DoProcess()
{
$sMessage = $this->Get('message');
$iVersion = (int) $this->Get('version');
switch($iVersion)
{
case Email::FORMAT_V2:
$oEMail = Email::UnSerializeV2($sMessage);
break;
case Email::ORIGINAL_FORMAT:
$oEMail = unserialize($sMessage);
break;
default:
return 'Unknown version of the serialization format: '.$iVersion;
}
$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

39
core/autoload.php Normal file
View File

@@ -0,0 +1,39 @@
<?php
// Copyright (C) 2016 Combodo SARL
//
// This file is part of iTop.
//
// iTop is free software; you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// iTop is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with iTop. If not, see <http://www.gnu.org/licenses/>
MetaModel::IncludeModule('application/transaction.class.inc.php');
MetaModel::IncludeModule('application/menunode.class.inc.php');
MetaModel::IncludeModule('application/user.preferences.class.inc.php');
MetaModel::IncludeModule('application/user.dashboard.class.inc.php');
MetaModel::IncludeModule('application/audit.rule.class.inc.php');
MetaModel::IncludeModule('application/query.class.inc.php');
MetaModel::IncludeModule('setup/moduleinstallation.class.inc.php');
MetaModel::IncludeModule('core/event.class.inc.php');
MetaModel::IncludeModule('core/action.class.inc.php');
MetaModel::IncludeModule('core/trigger.class.inc.php');
MetaModel::IncludeModule('core/bulkexport.class.inc.php');
MetaModel::IncludeModule('core/ownershiplock.class.inc.php');
MetaModel::IncludeModule('core/tagsetfield.class.inc.php');
MetaModel::IncludeModule('synchro/synchrodatasource.class.inc.php');
MetaModel::IncludeModule('core/backgroundtask.class.inc.php');
MetaModel::IncludeModule('core/inlineimage.class.inc.php');
MetaModel::IncludeModule('webservices/webservices.basic.php');
//MetaModel::IncludeModule('addons', 'user rights', 'addons/userrights/userrightsprofile.class.inc.php');

55
core/background.inc.php Normal file
View File

@@ -0,0 +1,55 @@
<?php
// Copyright (C) 2017 Combodo SARL
//
// This file is part of iTop.
//
// iTop is free software; you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// iTop is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with iTop. If not, see <http://www.gnu.org/licenses/>
/**
* Tasks performed in the background
*
* @copyright Copyright (C) 2017 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
class ObsolescenceDateUpdater implements iBackgroundProcess
{
public function GetPeriodicity()
{
return MetaModel::GetConfig()->Get('obsolescence.date_update_interval'); // 10 mn
}
public function Process($iUnixTimeLimit)
{
$iCountSet = 0;
$iCountReset = 0;
$iClasses = 0;
foreach (MetaModel::EnumObsoletableClasses() as $sClass)
{
$oObsoletedToday = new DBObjectSearch($sClass);
$oObsoletedToday->AddCondition('obsolescence_flag', 1, '=');
$oObsoletedToday->AddCondition('obsolescence_date', null, '=');
$sToday = date(AttributeDate::GetSQLFormat());
$iCountSet += MetaModel::BulkUpdate($oObsoletedToday, array('obsolescence_date' => $sToday));
$oObsoletedToday = new DBObjectSearch($sClass);
$oObsoletedToday->AddCondition('obsolescence_flag', 1, '!=');
$oObsoletedToday->AddCondition('obsolescence_date', null, '!=');
$iCountReset += MetaModel::BulkUpdate($oObsoletedToday, array('obsolescence_date' => null));
}
return "Obsolescence date updated (classes: $iClasses ; set: $iCountSet ; reset: $iCountReset)\n";
}
}

View File

@@ -1,67 +1,88 @@
<?php
// Copyright (C) 2010-2013 Combodo SARL
//
// This file is part of iTop.
//
// iTop is free software; you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// iTop is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with iTop. If not, see <http://www.gnu.org/licenses/>
/**
* interface iProcess
* Something that can be executed
*
* @copyright Copyright (C) 2010-2012 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
interface iProcess
{
public function Process($iUnixTimeLimit);
}
/**
* interface iBackgroundProcess
* Any extension that must be called regularly to be executed in the background
*
* @copyright Copyright (C) 2010-2012 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
interface iBackgroundProcess extends iProcess
{
/*
Gives the repetition rate in seconds
@returns integer
*/
public function GetPeriodicity();
}
/**
* interface iScheduledProcess
* A variant of process that must be called at specific times
*
* @copyright Copyright (C) 2013 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
interface iScheduledProcess extends iProcess
{
/*
Gives the exact time at which the process must be run next time
@returns DateTime
*/
public function GetNextOccurrence();
}
?>
<?php
// Copyright (C) 2010-2013 Combodo SARL
//
// This file is part of iTop.
//
// iTop is free software; you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// iTop is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with iTop. If not, see <http://www.gnu.org/licenses/>
/**
* interface iProcess
* Something that can be executed
*
* @copyright Copyright (C) 2010-2012 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
interface iProcess
{
/**
* @param int $iUnixTimeLimit
*
* @return string status message
* @throws \ProcessException
* @throws \ProcessFatalException
* @throws MySQLHasGoneAwayException
*/
public function Process($iUnixTimeLimit);
}
/**
* interface iBackgroundProcess
* Any extension that must be called regularly to be executed in the background
*
* @copyright Copyright (C) 2010-2012 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
interface iBackgroundProcess extends iProcess
{
/**
* @return int repetition rate in seconds
*/
public function GetPeriodicity();
}
/**
* interface iScheduledProcess
* A variant of process that must be called at specific times
*
* @copyright Copyright (C) 2013 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
interface iScheduledProcess extends iProcess
{
/**
* @return DateTime exact time at which the process must be run next time
*/
public function GetNextOccurrence();
}
/**
* Class ProcessException
* Exception for iProcess implementations.<br>
* An error happened during the processing but we can go on with the next implementations.
*/
class ProcessException extends CoreException
{
}
/**
* Class ProcessFatalException
* Exception for iProcess implementations.<br>
* A big error occurred, we have to stop the iProcess processing.
*/
class ProcessFatalException extends CoreException
{
}

File diff suppressed because it is too large Load Diff

View File

@@ -73,8 +73,14 @@ class BulkExportResult extends DBObject
MetaModel::Init_AddAttribute(new AttributeString("temp_file_path", array("allowed_values"=>null, "sql"=>"temp_file_path", "default_value"=>'', "is_null_allowed"=>true, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeLongText("search", array("allowed_values"=>null, "sql"=>"search", "default_value"=>'', "is_null_allowed"=>false, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeLongText("status_info", array("allowed_values"=>null, "sql"=>"status_info", "default_value"=>'', "is_null_allowed"=>false, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeBoolean("localize_output", array("allowed_values"=>null, "sql"=>"localize_output", "default_value"=>true, "is_null_allowed"=>true, "depends_on"=>array())));
}
/**
* @throws CoreUnexpectedValue
* @throws Exception
*/
public function ComputeValues()
{
$this->Set('user_id', UserRights::GetUserId());
@@ -95,7 +101,7 @@ class BulkExportResultGC implements iBackgroundProcess
public function Process($iTimeLimit)
{
$sDateLimit = date('Y-m-d H:i:s', time() - 24*3600); // Every BulkExportResult older than one day will be deleted
$sDateLimit = date(AttributeDateTime::GetSQLFormat(), time() - 24*3600); // Every BulkExportResult older than one day will be deleted
$sOQL = "SELECT BulkExportResult WHERE created < '$sDateLimit'";
$iProcessed = 0;
@@ -112,7 +118,9 @@ class BulkExportResultGC implements iBackgroundProcess
}
$iProcessed++;
@unlink($oResult->Get('temp_file_path'));
utils::PushArchiveMode(false);
$oResult->DBDelete();
utils::PopArchiveMode();
}
return "Cleaned $iProcessed old export results(s).";
}
@@ -145,13 +153,16 @@ abstract class BulkExport
$this->sTmpFile = '';
$this->bLocalizeOutput = false;
}
/**
* Find the first class capable of exporting the data in the given format
* @param string $sFormat The lowercase format (e.g. html, csv, spreadsheet, xlsx, xml, json, pdf...)
* @param DBSearch $oSearch The search/filter defining the set of objects to export or null when listing the supported formats
* @return iBulkExport|NULL
*/
/**
* Find the first class capable of exporting the data in the given format
*
* @param string $sFormatCode The lowercase format (e.g. html, csv, spreadsheet, xlsx, xml, json, pdf...)
* @param DBSearch $oSearch The search/filter defining the set of objects to export or null when listing the supported formats
*
* @return BulkExport|null
* @throws ReflectionException
*/
static public function FindExporter($sFormatCode, $oSearch = null)
{
foreach(get_declared_classes() as $sPHPClass)
@@ -172,12 +183,17 @@ abstract class BulkExport
}
return null;
}
/**
* Find the exporter corresponding to the given persistent token
* @param int $iPersistentToken The identifier of the BulkExportResult object storing the information
* @return iBulkExport|NULL
*/
/**
* Find the exporter corresponding to the given persistent token
*
* @param int $iPersistentToken The identifier of the BulkExportResult object storing the information
*
* @return iBulkExport|null
* @throws ArchivedObjectException
* @throws CoreException
* @throws ReflectionException
*/
static public function FindExporterFromToken($iPersistentToken = null)
{
$oBulkExporter = null;
@@ -186,7 +202,7 @@ abstract class BulkExport
{
$sFormatCode = $oInfo->Get('format');
$oSearch = DBObjectSearch::unserialize($oInfo->Get('search'));
$oBulkExporter = self::FindExporter($sFormatCode, $oSearch);
if ($oBulkExporter)
{
@@ -194,13 +210,21 @@ abstract class BulkExport
$oBulkExporter->SetObjectList($oSearch);
$oBulkExporter->SetChunkSize($oInfo->Get('chunk_size'));
$oBulkExporter->SetStatusInfo(json_decode($oInfo->Get('status_info'), true));
$oBulkExporter->SetLocalizeOutput($oInfo->Get('localize_output'));
$oBulkExporter->sTmpFile = $oInfo->Get('temp_file_path');
$oBulkExporter->oBulkExportResult = $oInfo;
}
}
return $oBulkExporter;
}
/**
* @param $data
* @throws Exception
*/
public function AppendToTmpFile($data)
{
if ($this->sTmpFile == '')
@@ -219,10 +243,10 @@ abstract class BulkExport
{
return $this->sTmpFile;
}
/**
* Lists all possible export formats. The output is a hash array in the form: 'format_code' => 'localized format label'
* @return multitype:string
* @return array :string
*/
static public function FindSupportedFormats()
{
@@ -248,6 +272,14 @@ abstract class BulkExport
{
$this->iChunkSize = $iChunkSize;
}
/**
* @param $bLocalizeOutput
*/
public function SetLocalizeOutput($bLocalizeOutput)
{
$this->bLocalizeOutput = $bLocalizeOutput;
}
/**
* (non-PHPdoc)
@@ -286,13 +318,21 @@ abstract class BulkExport
{
}
/**
* @return string
*/
public function GetHeader()
{
return '';
}
abstract public function GetNextChunk(&$aStatus);
/**
* @return string
*/
public function GetFooter()
{
return '';
}
public function SaveState()
@@ -302,11 +342,15 @@ abstract class BulkExport
$this->oBulkExportResult = new BulkExportResult();
$this->oBulkExportResult->Set('format', $this->sFormatCode);
$this->oBulkExportResult->Set('search', $this->oSearch->serialize());
$this->oBulkExportResult->Set('chunk_size', $this->iChunkSize);
$this->oBulkExportResult->Set('temp_file_path', $this->sTmpFile);
}
$this->oBulkExportResult->Set('chunk_size', $this->iChunkSize);
$this->oBulkExportResult->Set('temp_file_path', $this->sTmpFile);
$this->oBulkExportResult->Set('localize_output', $this->bLocalizeOutput);
}
$this->oBulkExportResult->Set('status_info', json_encode($this->GetStatusInfo()));
return $this->oBulkExportResult->DBWrite();
utils::PushArchiveMode(false);
$ret = $this->oBulkExportResult->DBWrite();
utils::PopArchiveMode();
return $ret;
}
public function Cleanup()
@@ -318,7 +362,9 @@ abstract class BulkExport
{
@unlink($sFilename);
}
utils::PushArchiveMode(false);
$this->oBulkExportResult->DBDelete();
utils::PopArchiveMode();
}
}
@@ -348,13 +394,21 @@ abstract class BulkExport
{
}
/**
* @return string
*/
public function GetMimeType()
{
return '';
}
/**
* @return string
*/
public function GetFileExtension()
{
return '';
}
public function GetCharacterSet()
{
@@ -381,6 +435,11 @@ abstract class BulkExport
return $this->aStatusInfo;
}
/**
* @param $sExtension
* @return string
* @throws Exception
*/
protected function MakeTmpFile($sExtension)
{
if(!is_dir(APPROOT."data/bulk_export"))
@@ -394,7 +453,6 @@ abstract class BulkExport
}
$iNum = rand();
$sFileName = '';
do
{
$iNum++;
@@ -412,7 +470,11 @@ abstract class BulkExport
// The built-in exports
require_once(APPROOT.'core/tabularbulkexport.class.inc.php');
require_once(APPROOT.'core/htmlbulkexport.class.inc.php');
require_once(APPROOT.'core/pdfbulkexport.class.inc.php');
if (extension_loaded('gd'))
{
// PDF export - via TCPDF - requires GD
require_once(APPROOT.'core/pdfbulkexport.class.inc.php');
}
require_once(APPROOT.'core/csvbulkexport.class.inc.php');
require_once(APPROOT.'core/excelbulkexport.class.inc.php');
require_once(APPROOT.'core/spreadsheetbulkexport.class.inc.php');

View File

@@ -1,87 +1,87 @@
<?php
// Copyright (C) 2010-2012 Combodo SARL
//
// This file is part of iTop.
//
// iTop is free software; you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// iTop is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with iTop. If not, see <http://www.gnu.org/licenses/>
/**
* Persistent class (internal) cmdbChange
*
* @copyright Copyright (C) 2010-2012 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
/**
* A change as requested/validated at once by user, may groups many atomic changes
*
* @package iTopORM
*/
class CMDBChange extends DBObject
{
public static function Init()
{
$aParams = array
(
"category" => "core/cmdb",
"key_type" => "autoincrement",
"name_attcode" => "date",
"state_attcode" => "",
"reconc_keys" => array(),
"db_table" => "priv_change",
"db_key_field" => "id",
"db_finalclass_field" => "",
'indexes' => array(
array('origin'),
)
);
MetaModel::Init_Params($aParams);
//MetaModel::Init_InheritAttributes();
MetaModel::Init_AddAttribute(new AttributeDateTime("date", array("allowed_values"=>null, "sql"=>"date", "default_value"=>"", "is_null_allowed"=>false, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeString("userinfo", array("allowed_values"=>null, "sql"=>"userinfo", "default_value"=>null, "is_null_allowed"=>true, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeEnum("origin", array("allowed_values"=>new ValueSetEnum('interactive,csv-interactive,csv-import.php,webservice-soap,webservice-rest,synchro-data-source,email-processing,custom-extension'), "sql"=>"origin", "default_value"=>"interactive", "is_null_allowed"=>true, "depends_on"=>array())));
}
// Helper to keep track of the author of a given change,
// taking into account a variety of cases (contact attached or not, impersonation)
static public function GetCurrentUserName()
{
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;
}
}
?>
<?php
// Copyright (C) 2010-2012 Combodo SARL
//
// This file is part of iTop.
//
// iTop is free software; you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// iTop is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with iTop. If not, see <http://www.gnu.org/licenses/>
/**
* Persistent class (internal) cmdbChange
*
* @copyright Copyright (C) 2010-2012 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
/**
* A change as requested/validated at once by user, may groups many atomic changes
*
* @package iTopORM
*/
class CMDBChange extends DBObject
{
public static function Init()
{
$aParams = array
(
"category" => "core/cmdb",
"key_type" => "autoincrement",
"name_attcode" => "date",
"state_attcode" => "",
"reconc_keys" => array(),
"db_table" => "priv_change",
"db_key_field" => "id",
"db_finalclass_field" => "",
'indexes' => array(
array('origin'),
)
);
MetaModel::Init_Params($aParams);
//MetaModel::Init_InheritAttributes();
MetaModel::Init_AddAttribute(new AttributeDateTime("date", array("allowed_values"=>null, "sql"=>"date", "default_value"=>"", "is_null_allowed"=>false, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeString("userinfo", array("allowed_values"=>null, "sql"=>"userinfo", "default_value"=>null, "is_null_allowed"=>true, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeEnum("origin", array("allowed_values"=>new ValueSetEnum('interactive,csv-interactive,csv-import.php,webservice-soap,webservice-rest,synchro-data-source,email-processing,custom-extension'), "sql"=>"origin", "default_value"=>"interactive", "is_null_allowed"=>true, "depends_on"=>array())));
}
// Helper to keep track of the author of a given change,
// taking into account a variety of cases (contact attached or not, impersonation)
static public function GetCurrentUserName()
{
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;
}
}
?>

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,139 +1,139 @@
<?php
// Copyright (C) 2010-2014 Combodo SARL
//
// This file is part of iTop.
//
// iTop is free software; you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// iTop is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with iTop. If not, see <http://www.gnu.org/licenses/>
/**
* Any extension to compute things like a stop watch deadline or working hours
*
* @copyright Copyright (C) 2010-2012 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
/**
* Metric computing for stop watches
*/
interface iMetricComputer
{
public static function GetDescription();
public function ComputeMetric($oObject);
}
/**
* Working time computing for stop watches
*/
interface iWorkingTimeComputer
{
public static function GetDescription();
/**
* Get the date/time corresponding to a given delay in the future from the present
* considering only the valid (open) hours for a specified object
* @param $oObject DBObject The object for which to compute the deadline
* @param $iDuration integer The duration (in seconds) in the future
* @param $oStartDate DateTime The starting point for the computation
* @return DateTime The date/time for the deadline
*/
public function GetDeadline($oObject, $iDuration, DateTime $oStartDate);
/**
* Get duration (considering only open hours) elapsed bewteen two given DateTimes
* @param $oObject DBObject The object for which to compute the duration
* @param $oStartDate DateTime The starting point for the computation (default = now)
* @param $oEndDate DateTime The ending point for the computation (default = now)
* @return integer The duration (number of seconds) of open hours elapsed between the two dates
*/
public function GetOpenDuration($oObject, DateTime $oStartDate, DateTime $oEndDate);
}
/**
* Default implementation oof deadline computing: NO deadline
*/
class DefaultMetricComputer implements iMetricComputer
{
public static function GetDescription()
{
return "Null";
}
public function ComputeMetric($oObject)
{
return null;
}
}
/**
* Default implementation of working time computing
*/
class DefaultWorkingTimeComputer implements iWorkingTimeComputer
{
public static function GetDescription()
{
return "24x7, no holidays";
}
/**
* Get the date/time corresponding to a given delay in the future from the present
* considering only the valid (open) hours for a specified object
* @param $oObject DBObject The object for which to compute the deadline
* @param $iDuration integer The duration (in seconds) in the future
* @param $oStartDate DateTime The starting point for the computation
* @return DateTime The date/time for the deadline
*/
public function GetDeadline($oObject, $iDuration, DateTime $oStartDate)
{
if (class_exists('WorkingTimeRecorder'))
{
WorkingTimeRecorder::Trace(WorkingTimeRecorder::TRACE_DEBUG, __class__.'::'.__function__);
}
//echo "GetDeadline - default: ".$oStartDate->format('Y-m-d H:i:s')." + $iDuration<br/>\n";
// Default implementation: 24x7, no holidays: to compute the deadline, just add
// the specified duration to the given date/time
$oResult = clone $oStartDate;
$oResult->modify('+'.$iDuration.' seconds');
if (class_exists('WorkingTimeRecorder'))
{
WorkingTimeRecorder::SetValues($oStartDate->format('U'), $oResult->format('U'), $iDuration, WorkingTimeRecorder::COMPUTED_END);
}
return $oResult;
}
/**
* Get duration (considering only open hours) elapsed bewteen two given DateTimes
* @param $oObject DBObject The object for which to compute the duration
* @param $oStartDate DateTime The starting point for the computation (default = now)
* @param $oEndDate DateTime The ending point for the computation (default = now)
* @return integer The duration (number of seconds) of open hours elapsed between the two dates
*/
public function GetOpenDuration($oObject, DateTime $oStartDate, DateTime $oEndDate)
{
if (class_exists('WorkingTimeRecorder'))
{
WorkingTimeRecorder::Trace(WorkingTimeRecorder::TRACE_DEBUG, __class__.'::'.__function__);
}
//echo "GetOpenDuration - default: ".$oStartDate->format('Y-m-d H:i:s')." to ".$oEndDate->format('Y-m-d H:i:s')."<br/>\n";
$iDuration = abs($oEndDate->format('U') - $oStartDate->format('U'));
if (class_exists('WorkingTimeRecorder'))
{
WorkingTimeRecorder::SetValues($oStartDate->format('U'), $oEndDate->format('U'), $iDuration, WorkingTimeRecorder::COMPUTED_DURATION);
}
return $iDuration;
}
}
?>
<?php
// Copyright (C) 2010-2014 Combodo SARL
//
// This file is part of iTop.
//
// iTop is free software; you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// iTop is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with iTop. If not, see <http://www.gnu.org/licenses/>
/**
* Any extension to compute things like a stop watch deadline or working hours
*
* @copyright Copyright (C) 2010-2012 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
/**
* Metric computing for stop watches
*/
interface iMetricComputer
{
public static function GetDescription();
public function ComputeMetric($oObject);
}
/**
* Working time computing for stop watches
*/
interface iWorkingTimeComputer
{
public static function GetDescription();
/**
* Get the date/time corresponding to a given delay in the future from the present
* considering only the valid (open) hours for a specified object
* @param $oObject DBObject The object for which to compute the deadline
* @param $iDuration integer The duration (in seconds) in the future
* @param $oStartDate DateTime The starting point for the computation
* @return DateTime The date/time for the deadline
*/
public function GetDeadline($oObject, $iDuration, DateTime $oStartDate);
/**
* Get duration (considering only open hours) elapsed bewteen two given DateTimes
* @param $oObject DBObject The object for which to compute the duration
* @param $oStartDate DateTime The starting point for the computation (default = now)
* @param $oEndDate DateTime The ending point for the computation (default = now)
* @return integer The duration (number of seconds) of open hours elapsed between the two dates
*/
public function GetOpenDuration($oObject, DateTime $oStartDate, DateTime $oEndDate);
}
/**
* Default implementation oof deadline computing: NO deadline
*/
class DefaultMetricComputer implements iMetricComputer
{
public static function GetDescription()
{
return "Null";
}
public function ComputeMetric($oObject)
{
return null;
}
}
/**
* Default implementation of working time computing
*/
class DefaultWorkingTimeComputer implements iWorkingTimeComputer
{
public static function GetDescription()
{
return "24x7, no holidays";
}
/**
* Get the date/time corresponding to a given delay in the future from the present
* considering only the valid (open) hours for a specified object
* @param $oObject DBObject The object for which to compute the deadline
* @param $iDuration integer The duration (in seconds) in the future
* @param $oStartDate DateTime The starting point for the computation
* @return DateTime The date/time for the deadline
*/
public function GetDeadline($oObject, $iDuration, DateTime $oStartDate)
{
if (class_exists('WorkingTimeRecorder'))
{
WorkingTimeRecorder::Trace(WorkingTimeRecorder::TRACE_DEBUG, __class__.'::'.__function__);
}
//echo "GetDeadline - default: ".$oStartDate->format('Y-m-d H:i:s')." + $iDuration<br/>\n";
// Default implementation: 24x7, no holidays: to compute the deadline, just add
// the specified duration to the given date/time
$oResult = clone $oStartDate;
$oResult->modify('+'.$iDuration.' seconds');
if (class_exists('WorkingTimeRecorder'))
{
WorkingTimeRecorder::SetValues($oStartDate->format('U'), $oResult->format('U'), $iDuration, WorkingTimeRecorder::COMPUTED_END);
}
return $oResult;
}
/**
* Get duration (considering only open hours) elapsed bewteen two given DateTimes
* @param $oObject DBObject The object for which to compute the duration
* @param $oStartDate DateTime The starting point for the computation (default = now)
* @param $oEndDate DateTime The ending point for the computation (default = now)
* @return integer The duration (number of seconds) of open hours elapsed between the two dates
*/
public function GetOpenDuration($oObject, DateTime $oStartDate, DateTime $oEndDate)
{
if (class_exists('WorkingTimeRecorder'))
{
WorkingTimeRecorder::Trace(WorkingTimeRecorder::TRACE_DEBUG, __class__.'::'.__function__);
}
//echo "GetOpenDuration - default: ".$oStartDate->format('Y-m-d H:i:s')." to ".$oEndDate->format('Y-m-d H:i:s')."<br/>\n";
$iDuration = abs($oEndDate->format('U') - $oStartDate->format('U'));
if (class_exists('WorkingTimeRecorder'))
{
WorkingTimeRecorder::SetValues($oStartDate->format('U'), $oEndDate->format('U'), $iDuration, WorkingTimeRecorder::COMPUTED_DURATION);
}
return $iDuration;
}
}
?>

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,75 @@
<?php
// Copyright (C) 2016-2017 Combodo SARL
//
// This file is part of iTop.
//
// iTop is free software; you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// iTop is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with iTop. If not, see <http://www.gnu.org/licenses/>
/**
* Simple helper class for keeping track of the context inside the call stack
*
* To check (anywhere in the code) if a particular context tag is present
* in the call stack simply do:
*
* if (ContextTag::Check(<the_tag>)) ...
*
* For example to know if the code is being executed in the context of a portal do:
*
* if (ContextTag::Check('GUI:Portal'))
*
* @copyright Copyright (C) 2016-2017 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
class ContextTag
{
protected static $aStack = array();
/**
* Store a context tag on the stack
* @param string $sTag
*/
public function __construct($sTag)
{
static::$aStack[] = $sTag;
}
/**
* Cleanup the context stack
*/
public function __destruct()
{
array_pop(static::$aStack);
}
/**
* Check if a given tag is present in the stack
* @param string $sTag
* @return bool
*/
public static function Check($sTag)
{
return in_array($sTag, static::$aStack);
}
/**
* Get the whole stack as an array
* @return hash
*/
public static function GetStack()
{
return static::$aStack;
}
}

View File

@@ -1,115 +1,204 @@
<?php
// Copyright (C) 2010-2012 Combodo SARL
//
// This file is part of iTop.
//
// iTop is free software; you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// iTop is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with iTop. If not, see <http://www.gnu.org/licenses/>
/**
* Exception management
*
* @copyright Copyright (C) 2010-2012 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
class CoreException extends Exception
{
public function __construct($sIssue, $aContextData = null, $sImpact = '')
{
$this->m_sIssue = $sIssue;
$this->m_sImpact = $sImpact;
$this->m_aContextData = $aContextData ? $aContextData : array();
$sMessage = $sIssue;
if (!empty($sImpact)) $sMessage .= "($sImpact)";
if (count($this->m_aContextData) > 0)
{
$sMessage .= ": ";
$aContextItems = array();
foreach($this->m_aContextData as $sKey => $value)
{
if (is_array($value))
{
$aPairs = array();
foreach($value as $key => $val)
{
if (is_array($val))
{
$aPairs[] = $key.'=>('.implode(', ', $val).')';
}
else
{
$aPairs[] = $key.'=>'.$val;
}
}
$sValue = '{'.implode('; ', $aPairs).'}';
}
else
{
$sValue = $value;
}
$aContextItems[] = "$sKey = $sValue";
}
$sMessage .= implode(', ', $aContextItems);
}
parent::__construct($sMessage, 0);
}
public function getHtmlDesc($sHighlightHtmlBegin = '<b>', $sHighlightHtmlEnd = '</b>')
{
return $this->getMessage();
}
public function getTraceAsHtml()
{
$aBackTrace = $this->getTrace();
return MyHelpers::get_callstack_html(0, $this->getTrace());
// return "<pre>\n".$this->getTraceAsString()."</pre>\n";
}
public function addInfo($sKey, $value)
{
$this->m_aContextData[$sKey] = $value;
}
public function getIssue()
{
return $this->m_sIssue;
}
public function getImpact()
{
return $this->m_sImpact;
}
public function getContextData()
{
return $this->m_aContextData;
}
}
class CoreWarning extends CoreException
{
}
class CoreUnexpectedValue extends CoreException
{
}
class SecurityException extends CoreException
{
}
?>
<?php
// Copyright (C) 2010-2012 Combodo SARL
//
// This file is part of iTop.
//
// iTop is free software; you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// iTop is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with iTop. If not, see <http://www.gnu.org/licenses/>
/**
* Exception management
*
* @copyright Copyright (C) 2010-2012 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
class CoreException extends Exception
{
public function __construct($sIssue, $aContextData = null, $sImpact = '')
{
$this->m_sIssue = $sIssue;
$this->m_sImpact = $sImpact;
$this->m_aContextData = $aContextData ? $aContextData : array();
$sMessage = $sIssue;
if (!empty($sImpact)) $sMessage .= "($sImpact)";
if (count($this->m_aContextData) > 0)
{
$sMessage .= ": ";
$aContextItems = array();
foreach($this->m_aContextData as $sKey => $value)
{
if (is_array($value))
{
$aPairs = array();
foreach($value as $key => $val)
{
if (is_array($val))
{
$aPairs[] = $key.'=>('.implode(', ', $val).')';
}
else
{
$aPairs[] = $key.'=>'.$val;
}
}
$sValue = '{'.implode('; ', $aPairs).'}';
}
else
{
$sValue = $value;
}
$aContextItems[] = "$sKey = $sValue";
}
$sMessage .= implode(', ', $aContextItems);
}
parent::__construct($sMessage, 0);
}
/**
* @return string code and message for log purposes
*/
public function getInfoLog()
{
return 'error_code='.$this->getCode().', message="'.$this->getMessage().'"';
}
public function getHtmlDesc($sHighlightHtmlBegin = '<b>', $sHighlightHtmlEnd = '</b>')
{
return $this->getMessage();
}
public function getTraceAsHtml()
{
$aBackTrace = $this->getTrace();
return MyHelpers::get_callstack_html(0, $this->getTrace());
// return "<pre>\n".$this->getTraceAsString()."</pre>\n";
}
public function addInfo($sKey, $value)
{
$this->m_aContextData[$sKey] = $value;
}
public function getIssue()
{
return $this->m_sIssue;
}
public function getImpact()
{
return $this->m_sImpact;
}
public function getContextData()
{
return $this->m_aContextData;
}
}
/**
* Class CoreCannotSaveObjectException
*
* Specialized exception to raise if {@link DBObject::CheckToWrite()} fails, which allow easy data retrieval
*
* @see \DBObject::DBInsertNoReload()
* @see \DBObject::DBUpdate()
*
* @since 2.6 N°659 uniqueness constraint
*/
class CoreCannotSaveObjectException extends CoreException
{
/** @var string[] */
private $aIssues;
/** @var int */
private $iObjectId;
/** @var string */
private $sObjectClass;
/**
* CoreCannotSaveObjectException constructor.
*
* @param array $aContextData containing at least those keys : issues, id, class
*/
public function __construct($aContextData)
{
$this->aIssues = $aContextData['issues'];
$this->iObjectId = $aContextData['id'];
$this->sObjectClass = $aContextData['class'];
$sIssues = implode(', ', $this->aIssues);
parent::__construct($sIssues, $aContextData);
}
/**
* @return string
*/
public function getHtmlMessage()
{
$sTitle = Dict::S('UI:Error:SaveFailed');
$sContent = "<span><strong>{$sTitle}</strong></span>";
if (count($this->aIssues) == 1)
{
$sContent .= " <span>{$this->aIssues[0]}</span>";
}
else
{
$sContent .= '<ul>';
foreach ($this->aIssues as $sError)
{
$sContent .= "<li>$sError</li>";
}
$sContent .= '</ul>';
}
return $sContent;
}
public function getIssues()
{
return $this->aIssues;
}
public function getObjectId()
{
return $this->iObjectId;
}
public function getObjectClass()
{
return $this->sObjectClass;
}
}
class CoreWarning extends CoreException
{
}
class CoreUnexpectedValue extends CoreException
{
}
class SecurityException extends CoreException
{
}
/**
* Throwned when querying on an object that exists in the database but is archived
*
* @see N.1108
*/
class ArchivedObjectException extends CoreException
{
}

View File

@@ -1,5 +1,5 @@
<?php
// Copyright (C) 2015 Combodo SARL
// Copyright (C) 2015-2016 Combodo SARL
//
// This file is part of iTop.
//
@@ -19,7 +19,7 @@
/**
* Bulk export: CSV export
*
* @copyright Copyright (C) 2015 Combodo SARL
* @copyright Copyright (C) 2015-2016 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
@@ -33,6 +33,8 @@ class CSVBulkExport extends TabularBulkExport
$oP->p(" *\tcharset: (optional) character set for encoding the result (default is 'UTF-8').");
$oP->p(" *\ttext-qualifier: (optional) character to be used around text strings (default is '\"').");
$oP->p(" *\tno_localize: set to 1 to retrieve non-localized values (for instance for ENUM values). Default is 0 (= localized values)");
$oP->p(" *\tformatted_text: set to 1 to export case logs and formatted text fields with their HTML markup. Default is 0 (= plain text)");
$oP->p(" *\tdate_format: the format to use when exporting date and time fields (default = the SQL format used in the user interface). e.g. 'Y-m-d H:i:s'");
}
public function ReadParameters()
@@ -55,6 +57,25 @@ class CSVBulkExport extends TabularBulkExport
}
$this->aStatusInfo['charset'] = strtoupper(utils::ReadParam('charset', 'UTF-8', true, 'raw_data'));
$this->aStatusInfo['formatted_text'] = (bool)utils::ReadParam('formatted_text', 0, true);
$sDateFormatRadio = utils::ReadParam('csv_date_format_radio', '');
switch($sDateFormatRadio)
{
case 'default':
// Export from the UI => format = same as is the UI
$this->aStatusInfo['date_format'] = (string)AttributeDateTime::GetFormat();
break;
case 'custom':
// Custom format specified from the UI
$this->aStatusInfo['date_format'] = utils::ReadParam('date_format', (string)AttributeDateTime::GetFormat(), true, 'raw_data');
break;
default:
// Export from the command line (or scripted) => default format is SQL, as in previous versions of iTop, unless specified otherwise
$this->aStatusInfo['date_format'] = utils::ReadParam('date_format', (string)AttributeDateTime::GetSQLFormat(), true, 'raw_data');
}
}
@@ -79,7 +100,7 @@ class CSVBulkExport extends TabularBulkExport
public function EnumFormParts()
{
return array_merge(parent::EnumFormParts(), array('csv_options' => array('separator', 'charset', 'text-qualifier', 'no_localize') ,'interactive_fields_csv' => array('interactive_fields_csv')));
return array_merge(parent::EnumFormParts(), array('csv_options' => array('separator', 'charset', 'text-qualifier', 'no_localize', 'formatted_text') ,'interactive_fields_csv' => array('interactive_fields_csv')));
}
public function DisplayFormPart(WebPage $oP, $sPartId)
@@ -95,6 +116,7 @@ class CSVBulkExport extends TabularBulkExport
$oP->add('<table class="export_parameters"><tr><td style="vertical-align:top">');
$oP->add('<h3>'.Dict::S('UI:CSVImport:SeparatorCharacter').'</h3>');
$sRawSeparator = utils::ReadParam('separator', ',', true, 'raw_data');
$sCustomDateTimeFormat = utils::ReadParam('', ',', true, 'raw_data');
$aSep = array(
';' => Dict::S('UI:CSVImport:SeparatorSemicolon+'),
',' => Dict::S('UI:CSVImport:SeparatorComma+'),
@@ -157,9 +179,35 @@ class CSVBulkExport extends TabularBulkExport
}
$oP->add('</select>');
$sChecked = (utils::ReadParam('formatted_text', 0) == 1) ? ' checked ' : '';
$oP->add('<h3>'.Dict::S('Core:BulkExport:TextFormat').'</h3>');
$oP->add('<input type="checkbox" id="csv_formatted_text" name="formatted_text" value="1"'.$sChecked.'><label for="csv_formatted_text"> '.Dict::S('Core:BulkExport:OptionFormattedText').'</label>');
$oP->add('</td><td style="vertical-align:top">');
$sDateTimeFormat = utils::ReadParam('date_format', (string)AttributeDateTime::GetFormat(), true, 'raw_data');
$sDefaultChecked = ($sDateTimeFormat == (string)AttributeDateTime::GetFormat()) ? ' checked' : '';
$sCustomChecked = ($sDateTimeFormat !== (string)AttributeDateTime::GetFormat()) ? ' checked' : '';
$oP->add('<h3>'.Dict::S('Core:BulkExport:DateTimeFormat').'</h3>');
$sDefaultFormat = htmlentities((string)AttributeDateTime::GetFormat(), ENT_QUOTES, 'UTF-8');
$sExample = htmlentities(date((string)AttributeDateTime::GetFormat()), ENT_QUOTES, 'UTF-8');
$oP->add('<input type="radio" id="csv_date_time_format_default" name="csv_date_format_radio" value="default"'.$sDefaultChecked.'><label for="csv_date_time_format_default"> '.Dict::Format('Core:BulkExport:DateTimeFormatDefault_Example', $sDefaultFormat, $sExample).'</label><br/>');
$sFormatInput = '<input type="text" size="15" name="date_format" id="csv_custom_date_time_format" title="" value="'.htmlentities($sDateTimeFormat, ENT_QUOTES, 'UTF-8').'"/>';
$oP->add('<input type="radio" id="csv_date_time_format_custom" name="csv_date_format_radio" value="custom"'.$sCustomChecked.'><label for="csv_date_time_format_custom"> '.Dict::Format('Core:BulkExport:DateTimeFormatCustom_Format', $sFormatInput).'</label>');
$oP->add('</td></tr></table>');
$oP->add('</fieldset>');
$sJSTooltip = json_encode('<div class="date_format_tooltip">'.Dict::S('UI:CSVImport:CustomDateTimeFormatTooltip').'</div>');
$oP->add_ready_script(
<<<EOF
$('#csv_custom_date_time_format').tooltip({content: function() { return $sJSTooltip; } });
$('#form_part_csv_options').on('preview_updated', function() { FormatDatesInPreview('csv', 'csv'); });
$('#csv_date_time_format_default').on('click', function() { FormatDatesInPreview('csv', 'csv'); });
$('#csv_date_time_format_custom').on('click', function() { FormatDatesInPreview('csv', 'csv'); });
$('#csv_custom_date_time_format').on('click', function() { $('#csv_date_time_format_custom').prop('checked', true); FormatDatesInPreview('csv', 'csv'); }).on('keyup', function() { FormatDatesInPreview('csv', 'csv'); });
EOF
);
break;
@@ -169,7 +217,16 @@ class CSVBulkExport extends TabularBulkExport
}
protected function GetSampleData($oObj, $sAttCode)
{
{
if ($sAttCode != 'id')
{
$oAttDef = MetaModel::GetAttributeDef(get_class($oObj), $sAttCode);
if ($oAttDef instanceof AttributeDateTime) // AttributeDate is derived from AttributeDateTime
{
$sClass = (get_class($oAttDef) == 'AttributeDateTime') ? 'user-formatted-date-time' : 'user-formatted-date';
return '<div class="'.$sClass.'" data-date="'.$oObj->Get($sAttCode).'">'.htmlentities($oAttDef->GetEditValue($oObj->Get($sAttCode), $oObj), ENT_QUOTES, 'UTF-8').'</div>';
}
}
return '<div class="text-preview">'.htmlentities($this->GetValue($oObj, $sAttCode), ENT_QUOTES, 'UTF-8').'</div>';
}
@@ -182,7 +239,7 @@ class CSVBulkExport extends TabularBulkExport
break;
default:
$sRet = trim($oObj->GetAsCSV($sAttCode), '"');
$sRet = trim($oObj->GetAsCSV($sAttCode), '"');
}
return $sRet;
}
@@ -209,8 +266,8 @@ class CSVBulkExport extends TabularBulkExport
if ($this->aStatusInfo['charset'] != 'UTF-8')
{
// Note: due to bugs in the glibc library it's safer to call iconv on the smallest possible string
// and thus to convert field by field and not the whole row or file at once (see ticket #991)
$aData[$idx] = iconv('UTF-8', $this->aStatusInfo['charset'].'//IGNORE//TRANSLIT', $aData[$idx]);
// and thus to convert field by field and not the whole row or file at once (see ticket 991)
$aData[$idx] = @iconv('UTF-8', $this->aStatusInfo['charset'].'//IGNORE//TRANSLIT', $aData[$idx]);
}
}
$sData = implode($this->aStatusInfo['separator'], $aData)."\n";
@@ -231,6 +288,17 @@ class CSVBulkExport extends TabularBulkExport
$sData = '';
$iPreviousTimeLimit = ini_get('max_execution_time');
$iLoopTimeLimit = MetaModel::GetConfig()->Get('max_execution_time_per_loop');
$sExportDateTimeFormat = $this->aStatusInfo['date_format'];
$oPrevDateTimeFormat = AttributeDateTime::GetFormat();
$oPrevDateFormat = AttributeDate::GetFormat();
if ($sExportDateTimeFormat !== (string)$oPrevDateTimeFormat)
{
// Change date & time formats
$oDateTimeFormat = new DateTimeFormat($sExportDateTimeFormat);
$oDateFormat = new DateTimeFormat($oDateTimeFormat->ToDateFormat());
AttributeDateTime::SetFormat($oDateTimeFormat);
AttributeDate::SetFormat($oDateFormat);
}
while($aRow = $oSet->FetchAssoc())
{
set_time_limit($iLoopTimeLimit);
@@ -251,14 +319,14 @@ class CSVBulkExport extends TabularBulkExport
break;
default:
$sField = $oObj->GetAsCSV($sAttCode, $this->aStatusInfo['separator'], $this->aStatusInfo['text_qualifier'], $this->bLocalizeOutput);
$sField = $oObj->GetAsCSV($sAttCode, $this->aStatusInfo['separator'], $this->aStatusInfo['text_qualifier'], $this->bLocalizeOutput, !$this->aStatusInfo['formatted_text']);
}
}
if ($this->aStatusInfo['charset'] != 'UTF-8')
{
// Note: due to bugs in the glibc library it's safer to call iconv on the smallest possible string
// and thus to convert field by field and not the whole row or file at once (see ticket #991)
$aData[] = iconv('UTF-8', $this->aStatusInfo['charset'].'//IGNORE//TRANSLIT', $sField);
// and thus to convert field by field and not the whole row or file at once (see ticket 991)
$aData[] = @iconv('UTF-8', $this->aStatusInfo['charset'].'//IGNORE//TRANSLIT', $sField);
}
else
{
@@ -268,6 +336,9 @@ class CSVBulkExport extends TabularBulkExport
$sData .= implode($this->aStatusInfo['separator'], $aData)."\n";
$iCount++;
}
// Restore original date & time formats
AttributeDateTime::SetFormat($oPrevDateTimeFormat);
AttributeDate::SetFormat($oPrevDateFormat);
set_time_limit($iPreviousTimeLimit);
$this->aStatusInfo['position'] += $this->iChunkSize;
if ($this->aStatusInfo['total'] == 0)

View File

@@ -1,251 +1,271 @@
<?php
// Copyright (C) 2010-2012 Combodo SARL
//
// This file is part of iTop.
//
// iTop is free software; you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// iTop is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with iTop. If not, see <http://www.gnu.org/licenses/>
/**
* CSV parser
*
* @copyright Copyright (C) 2010-2012 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
class CSVParserException extends CoreException
{
}
define('stSTARTING', 1); //grey zone: the type is undetermined
define('stRAW', 2); //building a non-qualified string
define('stQUALIFIED', 3); //building qualified string
define('stESCAPED', 4); //just encountered an escape char
define('evBLANK', 0);
define('evSEPARATOR', 1);
define('evNEWLINE', 2);
define('evTEXTQUAL', 3); // used for escaping as well
define('evOTHERCHAR', 4);
define('evEND', 5);
define('NULL_VALUE', '<NULL>');
/**
* CSVParser
*
* @package iTopORM
*/
class CSVParser
{
private $m_sCSVData;
private $m_sSep;
private $m_sTextQualifier;
public function __construct($sTxt, $sSep = ',', $sTextQualifier = '"')
{
$this->m_sCSVData = str_replace("\r\n", "\n", $sTxt);
$this->m_sSep = $sSep;
$this->m_sTextQualifier = $sTextQualifier;
}
protected $m_sCurrCell = '';
protected $m_aCurrRow = array();
protected $m_iToSkip = 0;
protected $m_aDataSet = array();
protected function __AddChar($c)
{
$this->m_sCurrCell .= $c;
}
protected function __ClearCell()
{
$this->m_sCurrCell = '';
}
protected function __AddCell($c = null, $aFieldMap = null, $bTrimSpaces = false)
{
if ($bTrimSpaces)
{
$sCell = trim($this->m_sCurrCell);
}
else
{
$sCell = $this->m_sCurrCell;
}
if ($sCell == NULL_VALUE)
{
$sCell = null;
}
if (!is_null($aFieldMap))
{
$iNextCol = count($this->m_aCurrRow);
$iNextName = $aFieldMap[$iNextCol];
$this->m_aCurrRow[$iNextName] = $sCell;
}
else
{
$this->m_aCurrRow[] = $sCell;
}
$this->m_sCurrCell = '';
}
protected function __AddRow($c = null, $aFieldMap = null, $bTrimSpaces = false)
{
$this->__AddCell($c, $aFieldMap, $bTrimSpaces);
if ($this->m_iToSkip > 0)
{
$this->m_iToSkip--;
}
elseif (count($this->m_aCurrRow) > 1)
{
$this->m_aDataSet[] = $this->m_aCurrRow;
}
elseif (count($this->m_aCurrRow) == 1)
{
// Get the unique value
$aValues = array_values($this->m_aCurrRow);
$sValue = $aValues[0];
if (strlen($sValue) > 0)
{
$this->m_aDataSet[] = $this->m_aCurrRow;
}
}
else
{
// blank line, skip silently
}
$this->m_aCurrRow = array();
}
protected function __AddCellTrimmed($c = null, $aFieldMap = null)
{
$this->__AddCell($c, $aFieldMap, true);
}
protected function __AddRowTrimmed($c = null, $aFieldMap = null)
{
$this->__AddRow($c, $aFieldMap, true);
}
function ToArray($iToSkip = 1, $aFieldMap = null, $iMax = 0)
{
$aTransitions = array();
$aTransitions[stSTARTING][evBLANK] = array('', stSTARTING);
$aTransitions[stSTARTING][evSEPARATOR] = array('__AddCell', stSTARTING);
$aTransitions[stSTARTING][evNEWLINE] = array('__AddRow', stSTARTING);
$aTransitions[stSTARTING][evTEXTQUAL] = array('', stQUALIFIED);
$aTransitions[stSTARTING][evOTHERCHAR] = array('__AddChar', stRAW);
$aTransitions[stSTARTING][evEND] = array('__AddRow', stSTARTING);
$aTransitions[stRAW][evBLANK] = array('__AddChar', stRAW);
$aTransitions[stRAW][evSEPARATOR] = array('__AddCellTrimmed', stSTARTING);
$aTransitions[stRAW][evNEWLINE] = array('__AddRowTrimmed', stSTARTING);
$aTransitions[stRAW][evTEXTQUAL] = array('__AddChar', stRAW);
$aTransitions[stRAW][evOTHERCHAR] = array('__AddChar', stRAW);
$aTransitions[stRAW][evEND] = array('__AddRowTrimmed', stSTARTING);
$aTransitions[stQUALIFIED][evBLANK] = array('__AddChar', stQUALIFIED);
$aTransitions[stQUALIFIED][evSEPARATOR] = array('__AddChar', stQUALIFIED);
$aTransitions[stQUALIFIED][evNEWLINE] = array('__AddChar', stQUALIFIED);
$aTransitions[stQUALIFIED][evTEXTQUAL] = array('', stESCAPED);
$aTransitions[stQUALIFIED][evOTHERCHAR] = array('__AddChar', stQUALIFIED);
$aTransitions[stQUALIFIED][evEND] = array('__AddRow', stSTARTING);
$aTransitions[stESCAPED][evBLANK] = array('', stESCAPED);
$aTransitions[stESCAPED][evSEPARATOR] = array('__AddCell', stSTARTING);
$aTransitions[stESCAPED][evNEWLINE] = array('__AddRow', stSTARTING);
$aTransitions[stESCAPED][evTEXTQUAL] = array('__AddChar', stQUALIFIED);
$aTransitions[stESCAPED][evOTHERCHAR] = array('__AddChar', stSTARTING);
$aTransitions[stESCAPED][evEND] = array('__AddRow', stSTARTING);
// Reset parser variables
$this->m_sCurrCell = '';
$this->m_aCurrRow = array();
$this->m_iToSkip = $iToSkip;
$this->m_aDataSet = array();
$iDataLength = strlen($this->m_sCSVData);
$iState = stSTARTING;
for($i = 0; $i <= $iDataLength ; $i++)
{
if ($i == $iDataLength)
{
$c = null;
$iEvent = evEND;
}
else
{
$c = $this->m_sCSVData[$i];
if ($c == $this->m_sSep)
{
$iEvent = evSEPARATOR;
}
elseif ($c == ' ')
{
$iEvent = evBLANK;
}
elseif ($c == "\t")
{
$iEvent = evBLANK;
}
elseif ($c == "\n")
{
$iEvent = evNEWLINE;
}
elseif ($c == $this->m_sTextQualifier)
{
$iEvent = evTEXTQUAL;
}
else
{
$iEvent = evOTHERCHAR;
}
}
$sAction = $aTransitions[$iState][$iEvent][0];
$iState = $aTransitions[$iState][$iEvent][1];
if (!empty($sAction))
{
$aCallSpec = array($this, $sAction);
if (is_callable($aCallSpec))
{
call_user_func($aCallSpec, $c, $aFieldMap);
}
else
{
throw new CSVParserException("CSVParser: unknown verb '$sAction'");
}
}
$iLineCount = count($this->m_aDataSet);
if (($iMax > 0) && ($iLineCount >= $iMax)) break;
}
return $this->m_aDataSet;
}
public function ListFields()
{
$aHeader = $this->ToArray(0, null, 1);
return $aHeader[0];
}
}
?>
<?php
// Copyright (C) 2010-2012 Combodo SARL
//
// This file is part of iTop.
//
// iTop is free software; you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// iTop is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with iTop. If not, see <http://www.gnu.org/licenses/>
/**
* CSV parser
*
* @copyright Copyright (C) 2010-2012 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
class CSVParserException extends CoreException
{
}
define('stSTARTING', 1); //grey zone: the type is undetermined
define('stRAW', 2); //building a non-qualified string
define('stQUALIFIED', 3); //building qualified string
define('stESCAPED', 4); //just encountered an escape char
define('evBLANK', 0);
define('evSEPARATOR', 1);
define('evNEWLINE', 2);
define('evTEXTQUAL', 3); // used for escaping as well
define('evOTHERCHAR', 4);
define('evEND', 5);
define('NULL_VALUE', '<NULL>');
/**
* CSVParser
*
* @package iTopORM
*/
class CSVParser
{
private $m_sCSVData;
private $m_sSep;
private $m_sTextQualifier;
private $m_iTimeLimitPerRow;
public function __construct($sTxt, $sSep = ',', $sTextQualifier = '"', $iTimeLimitPerRow = null)
{
$this->m_sCSVData = str_replace("\r\n", "\n", $sTxt);
$this->m_sSep = $sSep;
$this->m_sTextQualifier = $sTextQualifier;
$this->m_iTimeLimitPerRow = $iTimeLimitPerRow;
}
protected $m_sCurrCell = '';
protected $m_aCurrRow = array();
protected $m_iToSkip = 0;
protected $m_aDataSet = array();
protected function __AddChar($c)
{
$this->m_sCurrCell .= $c;
}
protected function __ClearCell()
{
$this->m_sCurrCell = '';
}
protected function __AddCell($c = null, $aFieldMap = null, $bTrimSpaces = false)
{
if ($bTrimSpaces)
{
$sCell = trim($this->m_sCurrCell);
}
else
{
$sCell = $this->m_sCurrCell;
}
if ($sCell == NULL_VALUE)
{
$sCell = null;
}
if (!is_null($aFieldMap))
{
$iNextCol = count($this->m_aCurrRow);
$iNextName = $aFieldMap[$iNextCol];
$this->m_aCurrRow[$iNextName] = $sCell;
}
else
{
$this->m_aCurrRow[] = $sCell;
}
$this->m_sCurrCell = '';
}
protected function __AddRow($c = null, $aFieldMap = null, $bTrimSpaces = false)
{
$this->__AddCell($c, $aFieldMap, $bTrimSpaces);
if ($this->m_iToSkip > 0)
{
$this->m_iToSkip--;
}
elseif (count($this->m_aCurrRow) > 1)
{
$this->m_aDataSet[] = $this->m_aCurrRow;
}
elseif (count($this->m_aCurrRow) == 1)
{
// Get the unique value
$aValues = array_values($this->m_aCurrRow);
$sValue = $aValues[0];
if (strlen($sValue) > 0)
{
$this->m_aDataSet[] = $this->m_aCurrRow;
}
}
else
{
// blank line, skip silently
}
$this->m_aCurrRow = array();
// More time for the next row
if ($this->m_iTimeLimitPerRow !== null)
{
set_time_limit($this->m_iTimeLimitPerRow);
}
}
protected function __AddCellTrimmed($c = null, $aFieldMap = null)
{
$this->__AddCell($c, $aFieldMap, true);
}
protected function __AddRowTrimmed($c = null, $aFieldMap = null)
{
$this->__AddRow($c, $aFieldMap, true);
}
function ToArray($iToSkip = 1, $aFieldMap = null, $iMax = 0)
{
$aTransitions = array();
$aTransitions[stSTARTING][evBLANK] = array('', stSTARTING);
$aTransitions[stSTARTING][evSEPARATOR] = array('__AddCell', stSTARTING);
$aTransitions[stSTARTING][evNEWLINE] = array('__AddRow', stSTARTING);
$aTransitions[stSTARTING][evTEXTQUAL] = array('', stQUALIFIED);
$aTransitions[stSTARTING][evOTHERCHAR] = array('__AddChar', stRAW);
$aTransitions[stSTARTING][evEND] = array('__AddRow', stSTARTING);
$aTransitions[stRAW][evBLANK] = array('__AddChar', stRAW);
$aTransitions[stRAW][evSEPARATOR] = array('__AddCellTrimmed', stSTARTING);
$aTransitions[stRAW][evNEWLINE] = array('__AddRowTrimmed', stSTARTING);
$aTransitions[stRAW][evTEXTQUAL] = array('__AddChar', stRAW);
$aTransitions[stRAW][evOTHERCHAR] = array('__AddChar', stRAW);
$aTransitions[stRAW][evEND] = array('__AddRowTrimmed', stSTARTING);
$aTransitions[stQUALIFIED][evBLANK] = array('__AddChar', stQUALIFIED);
$aTransitions[stQUALIFIED][evSEPARATOR] = array('__AddChar', stQUALIFIED);
$aTransitions[stQUALIFIED][evNEWLINE] = array('__AddChar', stQUALIFIED);
$aTransitions[stQUALIFIED][evTEXTQUAL] = array('', stESCAPED);
$aTransitions[stQUALIFIED][evOTHERCHAR] = array('__AddChar', stQUALIFIED);
$aTransitions[stQUALIFIED][evEND] = array('__AddRow', stSTARTING);
$aTransitions[stESCAPED][evBLANK] = array('', stESCAPED);
$aTransitions[stESCAPED][evSEPARATOR] = array('__AddCell', stSTARTING);
$aTransitions[stESCAPED][evNEWLINE] = array('__AddRow', stSTARTING);
$aTransitions[stESCAPED][evTEXTQUAL] = array('__AddChar', stQUALIFIED);
$aTransitions[stESCAPED][evOTHERCHAR] = array('__AddChar', stSTARTING);
$aTransitions[stESCAPED][evEND] = array('__AddRow', stSTARTING);
// Reset parser variables
$this->m_sCurrCell = '';
$this->m_aCurrRow = array();
$this->m_iToSkip = $iToSkip;
$this->m_aDataSet = array();
$iDataLength = strlen($this->m_sCSVData);
$iState = stSTARTING;
$iTimeLimit = null;
if ($this->m_iTimeLimitPerRow !== null)
{
// Give some time for the first row
$iTimeLimit = ini_get('max_execution_time');
set_time_limit($this->m_iTimeLimitPerRow);
}
for($i = 0; $i <= $iDataLength ; $i++)
{
if ($i == $iDataLength)
{
$c = null;
$iEvent = evEND;
}
else
{
$c = $this->m_sCSVData[$i];
if ($c == $this->m_sSep)
{
$iEvent = evSEPARATOR;
}
elseif ($c == ' ')
{
$iEvent = evBLANK;
}
elseif ($c == "\t")
{
$iEvent = evBLANK;
}
elseif ($c == "\n")
{
$iEvent = evNEWLINE;
}
elseif ($c == $this->m_sTextQualifier)
{
$iEvent = evTEXTQUAL;
}
else
{
$iEvent = evOTHERCHAR;
}
}
$sAction = $aTransitions[$iState][$iEvent][0];
$iState = $aTransitions[$iState][$iEvent][1];
if (!empty($sAction))
{
$aCallSpec = array($this, $sAction);
if (is_callable($aCallSpec))
{
call_user_func($aCallSpec, $c, $aFieldMap);
}
else
{
throw new CSVParserException("CSVParser: unknown verb '$sAction'");
}
}
$iLineCount = count($this->m_aDataSet);
if (($iMax > 0) && ($iLineCount >= $iMax)) break;
}
if ($iTimeLimit !== null)
{
// Restore the previous time limit
set_time_limit($iTimeLimit);
}
return $this->m_aDataSet;
}
public function ListFields()
{
$aHeader = $this->ToArray(0, null, 1);
return $aHeader[0];
}
}
?>

View File

@@ -0,0 +1,140 @@
<?php
// Copyright (C) 2016 Combodo SARL
//
// This file is part of iTop.
//
// iTop is free software; you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// iTop is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with iTop. If not, see <http://www.gnu.org/licenses/>
use Combodo\iTop\Form\Form;
use Combodo\iTop\Form\FormManager;
/**
* Base class to implement a handler for AttributeCustomFields
*
* @copyright Copyright (C) 2016 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
abstract class CustomFieldsHandler
{
protected $sAttCode;
protected $aValues;
protected $oForm;
/**
* This constructor's prototype must be frozen.
* Any specific behavior must be implemented in BuildForm()
*
* @param $sAttCode
*/
final public function __construct($sAttCode)
{
$this->sAttCode = $sAttCode;
$this->aValues = null;
}
abstract public function BuildForm(DBObject $oHostObject, $sFormId);
/**
*
* @return \Combodo\iTop\Form\Form
*/
public function GetForm()
{
return $this->oForm;
}
public function SetCurrentValues($aValues)
{
$this->aValues = $aValues;
}
static public function GetPrerequisiteAttributes($sClass = null)
{
return array();
}
/**
* List the available verbs for 'GetForTemplate'
*/
static public function EnumTemplateVerbs()
{
return array();
}
/**
* Get various representations of the value, for insertion into a template (e.g. in Notifications)
* @param $aValues array The current values
* @param $sVerb string The verb specifying the representation of the value
* @param $bLocalize bool Whether or not to localize the value
* @return string
*/
abstract public function GetForTemplate($aValues, $sVerb, $bLocalize = true);
/**
* @param $aValues
* @param bool|true $bLocalize
* @return mixed
*/
abstract public function GetAsHTML($aValues, $bLocalize = true);
/**
* @param $aValues
* @param bool|true $bLocalize
* @return mixed
*/
abstract public function GetAsXML($aValues, $bLocalize = true);
/**
* @param $aValues
* @param string $sSeparator
* @param string $sTextQualifier
* @param bool|true $bLocalize
* @return mixed
*/
abstract public function GetAsCSV($aValues, $sSeparator = ',', $sTextQualifier = '"', $bLocalize = true);
/**
* @param DBObject $oHostObject
* @return array Associative array id => value
*/
abstract public function ReadValues(DBObject $oHostObject);
/**
* Record the data (currently in the processing of recording the host object)
* It is assumed that the data has been checked prior to calling Write()
* @param DBObject $oHostObject
* @param array Associative array id => value
*/
abstract public function WriteValues(DBObject $oHostObject, $aValues);
/**
* Cleanup data upon object deletion (object id still available here)
* @param DBObject $oHostObject
*/
abstract public function DeleteValues(DBObject $oHostObject);
/**
* @param $aValuesA
* @param $aValuesB
* @return bool
*/
abstract public function CompareValues($aValuesA, $aValuesB);
/**
* String representation of the value, must depend solely on the semantics
* @return string
*/
abstract public function GetValueFingerprint();
}

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