Compare commits

...

1188 Commits

Author SHA1 Message Date
Eric
fc24746862 N°2847 - Fix "Add some criterion..." message on OQL menus 2020-11-24 15:38:04 +01:00
Eric
d0baf298be N°2847 - Datatable Fix n-n links 2020-11-24 14:54:32 +01:00
acognet
fb70026966 N°2847 - Tranform old itop datatable to jquery DataTable - Fix management of button "Add" step 2 2020-11-24 14:21:28 +01:00
Molkobain
ad19a89fc5 N°2847 - Fix iTopWebPage's header / footer API layout 2020-11-24 13:30:29 +01:00
Eric
7b937016d0 N°2847 - Datatable sortable columns tooltip 2020-11-24 11:37:23 +01:00
Eric
e8f7c7dafe N°2847 - Datatable cursor on sortable columns 2020-11-24 11:32:53 +01:00
Eric
d9264e5181 N°2847 - Datatable Fix external keys "undefined" 2020-11-24 11:25:26 +01:00
Pierre Goiffon
f893603332 🔧 editor config : else on same line in JS 2020-11-24 11:03:59 +01:00
Stephen Abello
a49a56def8 N°2847 Correctly center external key value on edition 2020-11-24 09:35:09 +01:00
Molkobain
2f138db4ac N°2847 - Work on object details structure 2020-11-23 23:17:12 +01:00
Molkobain
8d19958d6d N°2847 - ActivityPanel: Rework for new UX in edition/creation
- Hide main action buttons
- Remove activity tab entry form
- Send caselogs value with global form
2020-11-23 23:17:12 +01:00
acognet
11b6429e3c N°2847 - Tranform old itop datatable to jquery DataTable - Fix management of button "Add" 2020-11-23 19:59:55 +01:00
Eric
dccffc91b1 N°2847 - Datatable Fix preferences 2020-11-23 17:54:00 +01:00
Pierre Goiffon
6c5e1c429f 🎨 Remove auto closing tags for CSS
We have an HTML 5 Doctype, we're not using XHTML anymore
2020-11-23 15:09:45 +01:00
Molkobain
7d0f1f46d3 N°2847 - ActivityPanel: Rework for new UX
- Add MetaModel::GetCaseLogs($sClass) function
- Rename ActivityNewEntryForm to CaseLogEntryForm
- Rework ActivityPanel and CaseLogEntryForm markup / CSS
- Change for 1 CaseLogEntryForm per tab (caselogs and activity) with specific "Add entry..." choices
2020-11-23 11:11:05 +01:00
Molkobain
1e7d4e5c31 N°2847 - PopoverMenu: Fix quotes not being escaped in JS menu items 2020-11-23 10:08:21 +01:00
Molkobain
b12dadb0dc N°2847 - Button: Fix icon right margin and missing data role in markup 2020-11-23 10:08:20 +01:00
Molkobain
c6506c9f13 N°2847 - UIContentBlock: Rename AddDataAttributes method and fix PHPDoc 2020-11-23 10:08:18 +01:00
Molkobain
af11577450 N°2847 - iTopWebPage: Remove deprecated JS FixPaneVis() function (not used anymore since 3.0.0) 2020-11-23 10:08:17 +01:00
Molkobain
91ab66453b Remove jQuery Migrate "traces" logs, keeping only "warnings" 2020-11-23 10:08:16 +01:00
Stephen Abello
b1102bc68c N°2847 Re-generate precompiled css files 2020-11-20 10:45:16 +01:00
Stephen Abello
0443197c04 N°2847 Move Advance search css from light-grey to a dedicated file and tweak its style for 3.0 2020-11-20 10:32:52 +01:00
Eric
32e0c8f9bf N°2847 - Datatable modal dialogs 2020-11-19 17:45:46 +01:00
Eric
26d912f059 Fix breadcrumb 2020-11-19 16:02:11 +01:00
Molkobain
3cb5f3d07e N°2847 - Improve fatal error page message 2020-11-19 14:53:23 +01:00
Molkobain
675a408ab9 N°2847 - Activity panel: Pass host object display mode 2020-11-19 13:45:10 +01:00
Stephen Abello
2f938814e0 N°2847 Forgot to include aef77d8 illustration file in fatal errors alpha/development message 2020-11-19 13:43:05 +01:00
Stephen Abello
8042afa20f N°2847 Light fix to setup style 2020-11-19 13:39:27 +01:00
Stephen Abello
aef77d8f93 N°2847 Add message on alpha/development fatal error pages 🤫 2020-11-19 13:39:04 +01:00
Stephen Abello
05c53d35b7 N°2847 Update login screen style to better fit with iTop 3.0 2020-11-19 11:00:41 +01:00
Stephen Abello
ea169e8358 N°2847 Fix User menu not displaying on carret click 2020-11-19 10:45:39 +01:00
Stephen Abello
28e80e5568 N°2847 Finish style and refactor SCSS for datatables 2020-11-19 10:36:01 +01:00
BenGrenoble
487e0ad5a7 N°3440 Datamodel correction following Eric input 2020-11-18 16:19:16 +01:00
acognet
106dfc63d5 N°2847 - Tranform old itop datatable to jquery DataTable - manage popup "Configure this list" 2020-11-18 12:31:42 +01:00
acognet
5115db1b01 N°2847 - Tranform old itop datatable to jquery DataTable - add new style for MenuBlock 2020-11-17 15:18:05 +01:00
acognet
9621ff4d5e N°2847 - Tranform old itop datatable to jquery DataTable - fix diplay 2020-11-17 11:54:52 +01:00
Eric
1c5cb4e125 Fix datamodel 2020-11-17 10:50:49 +01:00
Stephen Abello
dc6a900f6d N°2847 Add css class to TagSet and Password input error message 2020-11-17 10:43:28 +01:00
Stephen Abello
0d23faba1c N°2847 Fix select input and duration input elements going to newline 2020-11-17 10:42:55 +01:00
Stephen Abello
c861941e92 N°2847 Fix input background color on error 2020-11-17 10:41:10 +01:00
Eric
313df4551f N°2847 - Datatable Fix selection 2020-11-17 09:42:26 +01:00
Pierre Goiffon
07cc8bf508 N°3436 fix Setup
Was blocked because using iTop 3.0.0 with datamodels/2.x dir : \SetupUtils::GetCompatibleDataModelDir wasn't ok with that :o)
This method is no more present, and we're calling \SetupUtils::GetLatestDataModelDir only
In other words, we're picking the latest datamodel/*.x dir (greatest number)
2020-11-16 17:51:52 +01:00
Pierre Goiffon
c2e31de263 🎨 SetupUtils fix methods modifiers + formatting 2020-11-16 17:39:32 +01:00
Eric
103b5bfd22 Merge remote-tracking branch 'origin/datatable' into feature/backoffice-full-moon-design 2020-11-16 15:24:07 +01:00
Eric
4c78ecab91 N°2847 - Datatables WIP 2020-11-16 15:02:02 +01:00
Pierre Goiffon
48bf954387 🔊 DisplayBlock add error message on error if user is admin
Previously only an IssueLog was made, which was confusing
The log is limited to admin users as it contains the exception message, which could expose sensitive info
2020-11-16 11:21:20 +01:00
Eric
89c35f0345 N°2847 - Datatables Fix external keys search 2020-11-16 11:04:16 +01:00
Eric
434c829f7e Fix update objects 2020-11-16 11:04:16 +01:00
Eric
4c8a8fc510 N°2847 - Datatables Fix external keys search 2020-11-16 11:04:16 +01:00
acognet
0a02c10287 N°2847 - Tranform old itop datatable to jquery DataTable - fix diplay 2020-11-16 10:40:35 +01:00
Molkobain
d4516c214c N°2847 - Input : Fix vertical alignment and horizontal padding 2020-11-15 17:56:32 +01:00
Molkobain
931225ed5a N°2847 - Activity panel: Work on the global UX
- Fix collapse/expand icon not toggling
2020-11-15 17:56:32 +01:00
Stephen Abello
18ed151e50 N°2847 Add placeholder to menu filter 2020-11-13 10:05:48 +01:00
acognet
0046834b2c N°2847 - Tranform old itop datatable to jquery DataTable - add sort 2020-11-13 08:51:16 +01:00
acognet
6835ebd11d N°2847 - Tranform old itop datatable to jquery DataTable - show + button in search box 2020-11-12 12:35:11 +01:00
Eric
62880b04eb N°2847 - Datatables pagination CSS 2020-11-12 11:59:56 +01:00
Eric
6d82a85b12 N°2847 - Datatables for forms 2020-11-12 11:44:06 +01:00
Stephen Abello
64134ff428 N°2847 Add silo selector to navigation menu 2020-11-12 11:00:59 +01:00
Stephen Abello
c7661bcfcf Update TODO format 2020-11-12 11:00:59 +01:00
Eric
291041610b set_time_limit accept only int in PHP7.4 2020-11-12 10:57:13 +01:00
Molkobain
a729c6c1e3 Fix typo (thanks @steffunky) 2020-11-12 09:42:39 +01:00
Eric
23452804aa N°2847 - Datatables for static data 2020-11-10 17:30:53 +01:00
Molkobain
1098182720 Update pre-compiled themes 2020-11-10 16:28:17 +01:00
Molkobain
77ecd055b4 N°2847 - Fix crash when object with state attribute has no state defined 2020-11-10 15:55:20 +01:00
Molkobain
38fbc49e51 N°2844 - Fix layout for object creation and edition pages (activity panel, title, ...) 2020-11-10 15:41:33 +01:00
Molkobain
f9b905403d N°3389 - Add integration test (XML version and app. core version must be aligned from now on) 2020-11-10 10:33:22 +01:00
Molkobain
96130735c4 N°3287 - Add french translations 2020-11-10 09:46:00 +01:00
Molkobain
448afc640d Internal: Change XML version from 1.8 to 3.0 as it will now follow iTop core version numbering 2020-11-09 19:48:28 +01:00
Molkobain
f2ff5a4e83 N°3203 - Datamodel: Add semantic for image & state attributes Part. II 2020-11-09 15:44:45 +01:00
Pierre Goiffon
b44e6a4a53 Fix ThemeHandlerTest
Regression introduced by f718b26b : the test expected SCSS file was modified in sync with modifications done in iTop SCSS files. No need to do that as this file is only used in this test.
2020-11-09 15:15:12 +01:00
Eric
866a93c0c8 Fix unit tests 2020-11-09 11:57:56 +01:00
Eric
d7b1e60219 Merge remote-tracking branch 'origin/feature/backoffice-full-moon-design' into datatable 2020-11-09 11:33:48 +01:00
Pierre Goiffon
63d52787f0 Commit CSS modified by d76e425 2020-11-09 09:37:29 +01:00
Eric
bc809b0f3b N°2847 - cleanup code 2020-11-09 08:00:26 +01:00
Eric
f64cad75cd Fix error when history contains a now invalid attribute 2020-11-06 14:55:59 +01:00
Eric
6237b5565c N°2847 - Fix panel toolbars 2020-11-06 09:08:12 +01:00
Molkobain
d76e4255f2 N°2950 - Fix syntax highlighting (CKEditor) not working on AttributeHTML
- Fix for not supported attributes (HTML)
- Migrate selectors for new backoffice markup
2020-11-04 17:25:25 +01:00
Molkobain
fa0bb2b466 N°3203 - Fix regression: PHP notice on object with no class icon 2020-11-04 16:15:18 +01:00
Molkobain
8954d02796 PHPDoc & warnings suppression 2020-11-04 16:15:17 +01:00
Eric
87a2d30c78 N°2847 - revert fieldset style for extensions before 3.0.0 2020-11-04 14:21:28 +01:00
acognet
f718b26b7b N°2847 - Tranform old itop datatable to jquery DataTable 2020-11-04 13:36:20 +01:00
Eric
7cfd888516 N°2847 - fieldset style for extensions before 3.0.0 2020-11-04 12:02:49 +01:00
Eric
cd10c41362 N°2847 - fieldset style for extensions before 3.0.0 2020-11-04 11:50:38 +01:00
Eric
eb391d52fc N°2847 - fieldset style for extensions before 3.0.0 2020-11-04 11:30:46 +01:00
Eric
1fc54edf21 N°2847 - Fix ajax tabs 2020-11-04 10:28:40 +01:00
Eric
cfbfaad154 N°2847 - Dashboards edition 2020-11-03 16:15:03 +01:00
Molkobain
b7543b54e8 N°2847 - Field: Restore HTML metadata lost during migration, add missing ID in template 2020-11-03 15:10:15 +01:00
Molkobain
10afd1cede N°2847 - Panel: Fix top padding being too small since integration with tab containers 2020-11-02 18:04:03 +01:00
Molkobain
b454958742 N°2847 - Refactor Button block for a better use of semantic colors, also change "primary" action color to something less flashy 2020-11-02 17:39:10 +01:00
Molkobain
680f522065 N°2847 - Refactor color palettes SCSS files for a better comprehension 2020-11-02 16:38:01 +01:00
Molkobain
50421f4753 N°3203 - Datamodel: Add semantic for image & state attributes Part. I 2020-11-02 14:51:25 +01:00
Pierre Goiffon
7864461d85 Merge remote-tracking branch 'origin/develop' into feature/backoffice-full-moon-design
# Conflicts:
#	core/cmdbobject.class.inc.php
#	datamodels/2.x/itop-bridge-cmdb-ticket/datamodel.itop-bridge-cmdb-ticket.xml
#	datamodels/2.x/itop-structure/datamodel.itop-structure.xml
2020-11-02 10:30:44 +01:00
Eric
be338e385b N°2847 - Dashboards 2020-11-02 09:59:31 +01:00
Pierre Goiffon
235b4be790 Merge remote-tracking branch 'origin/support/2.7' into develop 2020-10-30 18:09:44 +01:00
Pierre Goiffon
66273ebd39 Merge remote-tracking branch 'origin/support/2.7.2' into support/2.7 2020-10-30 18:08:01 +01:00
BenGrenoble
dfcc3b22a6 Location/physicaldevice_list from structure to bridge. 2020-10-30 16:47:19 +01:00
Eric
eebc29d2bb N°3111 - Fix Portal export
(cherry picked from commit d3b57c3bda)
2020-10-30 14:16:57 +01:00
Pierre Goiffon
512b415bd6 N°3065 add test case in comment 2020-10-30 11:30:22 +01:00
Eric
f3e47a15f6 N°2847 - Dashlet fix header dynamic 2020-10-30 10:39:58 +01:00
Stephen Abello
a70ed7fcc2 N°2847 Lighter error display on inputs firts validation
Note: Doesn't work with tagsets and enumsets
2020-10-30 10:13:59 +01:00
Eric
c43d52277c N°2847 - Dashlet header static and text 2020-10-29 18:06:04 +01:00
Eric
8a1d17551b N°2847 - Dashlet badge 2020-10-29 17:08:03 +01:00
Eric
6e584cded4 N°2847 - Dashlet group by 2020-10-29 16:15:24 +01:00
Eric
6c7efb2448 N°2847 - Dashlet header dynamic and badges 2020-10-29 15:20:44 +01:00
Stephen Abello
3548d5e264 N°2847 Fix inputs border color 2020-10-29 10:10:35 +01:00
Pierre Goiffon
906c8855b0 🔊 When error during CoreUpdate, show full file path instead of only basename 2020-10-28 18:32:49 +01:00
Eric
bd606ca3f9 N°2847 - Move dashboard title and menu to the top bar 2020-10-28 15:43:42 +01:00
BenGrenoble
6c5c71a0ee Contracts_list/Services_list from structure to bridge cmdb ticket 2020-10-28 14:08:00 +01:00
BenGrenoble
dfd9dd3352 Move cis_list from DocumentNote, DocumentWeb, DocumentFile to bridge cmdb ticket 2020-10-28 10:01:55 +01:00
BenGrenoble
6583c9495a Translation Fieldset person 2020-10-28 09:17:58 +01:00
BenGrenoble
93132dc3b4 Person_list in location 2020-10-28 08:49:05 +01:00
BenGrenoble
f257dcfb85 ConfigManagementCI and CI+ in structure dict 2020-10-28 08:48:46 +01:00
Pierre Goiffon
776f32dbe1 🎨 Block ID generation : less risk of id collision
Reported by NonSecureUniqidUsageInspection : when calling \uniqid we should provide true as second parameter.

But was causing issues as the generated string could contain a dot, and this is used in CSS and JQuery selectors (for example a "my.id" cannot be used in #my.id selector)

So we're just replacing dots with hyphens !

Was discussed with @Molkobain in 0119f6c395
2020-10-27 16:58:25 +01:00
Pierre Goiffon
97d322a059 📝 N°3218 Add some PHPDoc on current change set/get 2020-10-27 15:17:17 +01:00
Eric
8502fa7721 N°3294 - Display and refresh counters in OQL menu entries 2020-10-27 15:11:30 +01:00
Eric
48b3716278 N°3294 - Fix CSS typo 2020-10-27 11:43:31 +01:00
Pierre Goiffon
5f9cdc0431 Merge remote-tracking branch 'origin/support/2.7' into develop
# Conflicts:
#	test/integration/iTopModulesPhpVersionChecklistTest.php
2020-10-27 10:48:39 +01:00
acognet
ada7f30793 N°3139 - import csv : hyperlink not clickable - replace htmlentities with utils::HtmlEntities() to ensure that the same options are used application wide. 2020-10-27 09:59:05 +01:00
Pierre Goiffon
b065d13374 Integration tests : add itop-community group 2020-10-27 09:46:03 +01:00
Pierre Goiffon
1f092f8418 🎨 Integration test code formatting 2020-10-27 09:45:26 +01:00
Pierre Goiffon
6df74073a7 🐛 Fix \Combodo\iTop\Application\UI\UIBlock::GenerateId 2020-10-27 08:42:25 +01:00
Stephen Abello
b59c40570b N°2847 WIP First iteration on form inputs 2020-10-26 17:05:57 +01:00
Pierre Goiffon
444f60c251 Merge remote-tracking branch 'origin/develop' into feature/backoffice-full-moon-design
# Conflicts:
#	core/cmdbobject.class.inc.php
2020-10-26 14:31:49 +01:00
Pierre Goiffon
2425ccb8f2 Merge remote-tracking branch 'origin/support/2.7' into develop
# Conflicts:
#	css/css-variables.scss
#	datamodels/2.x/version.xml
2020-10-26 14:30:33 +01:00
Eric
4fd65a8a62 N°3294 - WIP: Introduce counter in OQL menu entries 2020-10-26 13:37:32 +01:00
Eric
664d3251cc N°3294 - WIP: Introduce counter in OQL menu entries 2020-10-26 12:07:09 +01:00
Molkobain
f31f991365 N°2836 - Portal: Fix image coverage of the medallion 2020-10-25 15:37:07 +01:00
Molkobain
bb1a8a92dd N°2847 - Fix Quick create / Global search drawer position when closed and history full (10 items) 2020-10-25 00:01:58 +02:00
Molkobain
27e1f3d64b N°2836 - Portal: Introduce bubbles conversation as default caselog rendering 2020-10-24 15:22:42 +02:00
Molkobain
95a2ffa0f2 N°2224 - Portal: Enable tooltips for object's attributes description in dynamically added content as well (AJAX, forms, ...) 2020-10-22 21:29:53 +02:00
Molkobain
b1e29cbd81 Fix call to Field::AddMetadata() to remove $sValue as null (regression introduced in cfd9dba6) 2020-10-22 21:28:52 +02:00
Molkobain
2e97b3b593 N°2847 - Add reminders / info message for refactoring 2020-10-22 16:11:58 +02:00
Molkobain
e419060e8a Add type hinting to methods parameters 2020-10-22 16:06:00 +02:00
Molkobain
cfd9dba66e N°2224 - Portal: Enable tooltips for object's attributes description 2020-10-22 16:05:59 +02:00
Molkobain
f72ddd72f3 N°2847 - Tooltip: Add new "Tippy" and "Popper" libs to the portal 2020-10-22 16:05:59 +02:00
Molkobain
d85d29155f N°2847 - Tooltip: Improve mechanism to instantiate them only once 2020-10-22 16:05:59 +02:00
Molkobain
91ee5ebfeb N°2847 - Tooltip: Move new wrappers from CombodoBackofficeToolbox into CombodoGlobalToolbox so it can be used in any GUIs 2020-10-22 16:05:59 +02:00
Molkobain
a6ea75f5fe N°2847 - Rename backoffice.js into backoffice/toolbox.js for better consistency with other toolboxes 2020-10-22 16:05:58 +02:00
Molkobain
dc789f51e9 Warnings suppression 2020-10-22 16:05:58 +02:00
Molkobain
116c0c0138 Portal: Fix double HTML encoding of fields metadata (label, raw value) 2020-10-22 16:05:58 +02:00
Pierre Goiffon
65d6947e52 🔖 Prepare 2.7.2 version 2020-10-22 15:06:48 +02:00
Pierre Goiffon
ba54b47f7d Merge remote-tracking branch 'origin/support/2.6' into support/2.7 2020-10-22 10:27:36 +02:00
Pierre Goiffon
65e43e8d04 🔧 remove .gitflow as we don't have any master branch anymore 2020-10-22 10:10:15 +02:00
Pierre Goiffon
7fa7ebb59c 📝 Fix 2.9.0 version present in deprecated mentions 2020-10-21 19:24:24 +02:00
Pierre Goiffon
0119f6c395 UiBlock : fix typo + inspections 2020-10-21 19:08:17 +02:00
Pierre Goiffon
c8a30b0ccb 📝 N°2286 jquery-layout not used in the whole console anymore 2020-10-21 16:06:06 +02:00
Pierre Goiffon
8e31d77afb N°2591 fix deprecated info 2020-10-21 12:09:06 +02:00
Pierre Goiffon
c7dce73116 Remove dataprovider in iTopModulesPhpVersionIntegrationTest::testITopModulesPhpVersion (#175)
Remove dataprovider in \Combodo\iTop\Test\UnitTest\Integration\iTopModulesPhpVersionIntegrationTest::testITopModulesPhpVersion
The dataprovider was slow, and was very fragile because it contained much PHP code : as seen in 2221e05 when an error appears here it is very difficult to trace :/
So now we have a traditional PHPUnit test method, and still we are testing everytime all modules (not stopping on the first error : we have only one assert at the end instead of an assert per module), and also we're getting the list of modules having errors at the end
2020-10-20 17:10:36 +02:00
Molkobain
71bb071f38 N°2907 - Keep (standard) read-only tabs visible in edit mode
Specifics:
    - User / Grant matrix
    - Subnet / IP Usage
    - Incident / Known errors
    - UserRequest (Simple/ITIL) / Known errors
Generics:
    - History (moved to activity panel)
    - Notifications
2020-10-19 22:21:33 +02:00
Molkobain
deda05351b N°3182 - Show menu group initials when no CSS decoration classes specified 2020-10-19 21:23:07 +02:00
Pierre Goiffon
5d1de543cc Merge remote-tracking branch 'origin/develop' into feature/backoffice-full-moon-design
# Conflicts:
#	core/metamodel.class.php
2020-10-19 15:46:16 +02:00
Pierre Goiffon
be9a428529 Merge remote-tracking branch 'origin/support/2.7' into develop 2020-10-19 15:38:11 +02:00
Pierre Goiffon
adb4e77c8d 🎨 MetaModel : function modifiers order + little formatting 2020-10-19 15:36:56 +02:00
Pierre Goiffon
d3cf7176da 📝 MetaModel : add comment on @deprecated added in 9c75cb4537 2020-10-19 15:34:15 +02:00
Pierre Goiffon
1cfb52d220 🐛 Fix CoreException constructor generating a warning on PHP >= 7.2
In the CoreException constructor, we're using the $aContextData parameter to do a count(), a foreach(), and uses values as string.
Only a null check was done.
Now we are also checking that the value is_array().
As others checks (Countable, Iterable, __toString() impl) are quite difficult depending on the PHP version we're running, we didn't add any other checks.

The call in \MatchExpression::__construct (added in 05a0d612) was passing directly an Expression object. We could embed it in an array, but the object hierarchy isn't implementing __toString so we would have another bug.
In consequence we removed this parameter.
2020-10-19 11:57:53 +02:00
odain
e7360661be N°3381 - finish integrating healthcheck status.php page 2020-10-19 11:42:48 +02:00
Pierre Goiffon
18d5231900 N°3332 Security hardening 2020-10-19 09:25:30 +02:00
Pierre Goiffon
e6539ccb6e 🔧 Update .editorconfig : braces on next line for classes and functions 2020-10-19 09:09:31 +02:00
acognet
96332b7885 N°3139 - import csv : hyperlink not clickable 2020-10-16 14:15:51 +02:00
Molkobain
6edb308480 N°3379 - Introduce more modern tooltip lib. in the backoffice
- Allow usage of quotes, especially in attributes description
- Allow line breaks, especially in attributes description
- Allow better positioning (automatic) when close to the screen limits
- Allow HTML (careful about XSS), content is sanitized by default
2020-10-16 11:10:51 +02:00
acognet
557b9be795 N°3377 - Allow to get data of current user - Fix Exception when using :current_user->... for non admin users 2020-10-15 17:31:25 +02:00
Pierre Goiffon
43a4d9fcd2 📝 PHPDoc for \cmdbAbstractObject::GetDisplaySet 2020-10-15 16:07:02 +02:00
Molkobain
9a47e3cf74 N°2844 - Continue work on object details: Quick fixes for alpha, will need to be refactored
- Improve display of details in creation/modification/transition modes
2020-10-15 15:55:05 +02:00
Molkobain
e7f01e7597 N°2847 - Alert: Improve spacing when followed by another alter or something else 2020-10-15 15:55:04 +02:00
Vincent Dumas
910358e04d #2639 Enrich tooltips for Action class 2020-10-15 13:12:59 +02:00
odain
4eebb538df 💚 add beforeSetup phpunit group to run test before setup 2020-10-14 18:09:23 +02:00
odain
d304284e36 💚 cleanup 2020-10-14 13:13:25 +02:00
odain
6e6557e909 💚 add beforeSetup phpunit group to run test before setup 2020-10-14 13:03:44 +02:00
Pierre Goiffon
548342159b Merge remote-tracking branch 'origin/develop' into feature/backoffice-full-moon-design 2020-10-14 11:41:58 +02:00
Pierre Goiffon
2221e0541c 🐛 Fix version methods throwing exceptions with version 3.0.0 2020-10-14 11:31:02 +02:00
Molkobain
b15ed80732 Internal: Replace references to iTop 2.8.0 with iTop 3.0.0 2020-10-14 10:16:49 +02:00
Molkobain
986c08aa81 Merge remote-tracking branch 'origin/develop' into feature/backoffice-full-moon-design 2020-10-14 10:09:14 +02:00
Molkobain
8e6351d346 Internal: Replace references to iTop 2.8.0 with iTop 3.0.0 2020-10-14 10:04:10 +02:00
Molkobain
9b19ae5944 Merge remote-tracking branch 'origin/support/2.7' into develop 2020-10-14 09:54:22 +02:00
Molkobain
e35965c065 N°2982 - Move precompiled files to proper module and update XML migration functions 2020-10-14 09:49:21 +02:00
Pierre Goiffon
75ebecddd5 Merge remote-tracking branch 'origin/support/2.6' into support/2.7
# Conflicts:
#	datamodels/2.x/itop-portal-base/portal/src/controllers/userprofilebrickcontroller.class.inc.php
#	datamodels/2.x/itop-portal-base/portal/src/helpers/applicationhelper.class.inc.php
2020-10-14 09:19:07 +02:00
Pierre Goiffon
5fee2438ab Fix comments : iTop 2.8.0 renamed to 3.0.0 2020-10-14 09:06:07 +02:00
Pierre Goiffon
5b2c279eac Merge remote-tracking branch 'origin/develop' into feature/backoffice-full-moon-design
# Conflicts:
#	js/components/breadcrumbs.js
2020-10-12 12:51:05 +02:00
Pierre Goiffon
72fc22c49a Merge remote-tracking branch 'origin/support/2.7' into develop 2020-10-12 12:49:17 +02:00
Pierre Goiffon
2d130cbba8 Merge remote-tracking branch 'origin/support/2.6' into support/2.7
# Conflicts:
#	test/core/UserRightsTest.php
#	test/setup_params/default-params.xml
2020-10-12 12:47:58 +02:00
Pierre Goiffon
8b1c20cc11 N°3332 Security hardening 2020-10-12 12:40:51 +02:00
Molkobain
b7b1ef1a1f Fix double-encoded breadcrumbs entry introduced by 1e634a8bba 2020-10-09 20:54:51 +02:00
Molkobain
64a96ac001 N°2847 - Dashboard: Improve grid alignments and design of the badge dashlet 2020-10-09 18:42:53 +02:00
Thomas Casteleyn
eb3ad0999a Cleanup utils::GetSessionLog() (#172) 2020-10-09 15:59:24 +02:00
odain
df5aacca42 💚 use new ci validation 2020-10-09 10:08:31 +02:00
Molkobain
ecf678f39f N°2847 - Quick create: Refactor history truncation 2020-10-09 09:49:26 +02:00
Molkobain
5bc01d3950 N°2847 - Global search: Add config. parameter for max. history results ('global_search.max_history_results') 2020-10-09 09:49:26 +02:00
Stephen Abello
2ae50dfb06 N°2847 Fix Activity new entry form caselog picker disappearing after submitting once 2020-10-09 09:26:39 +02:00
Stephen Abello
b25a6a2f04 N°2847 Correctly open/close Activity new entry form 2020-10-09 09:26:39 +02:00
Molkobain
1bd9d35979 N°2847 - Quick create: Add config. parameter for max. history results ('quick_create.max_history_results') 2020-10-09 09:21:37 +02:00
Molkobain
1dd4d1479c N°2847 - Tab container: Fix min width (alignment with medallion) with short tab labels 2020-10-09 00:06:21 +02:00
Molkobain
00212e8127 N°2847 - Dashboard: Start rework for demo 2020-10-09 00:04:13 +02:00
Molkobain
061f3e9f51 N°2847 - Quick create: Add config. parameter for max. autocomplete results ('quick_create.max_autocomplete_results') 2020-10-08 18:17:35 +02:00
Stephen Abello
e6111609b0 N°3208 Finish Quick object creation component 2020-10-08 17:15:27 +02:00
Molkobain
3556a95f3b N°2847 - Tab container: Fix tab content horizontal alignment 2020-10-08 17:01:59 +02:00
Pierre Goiffon
82735254e7 Compiled CSS
As generated by the setup
2020-10-08 16:27:05 +02:00
Molkobain
44351784e6 N°2847 - Work on the tab container
- Fix CSS class names on vertical mode
- Add class constants
2020-10-08 16:25:45 +02:00
Molkobain
f87002dce3 Introduce CombodoBackofficeToolbox like in the portal to:
- Avoid name collision with other libs for our functions
- Document a set a function developers can use in their extensions, will be completed as things progress
2020-10-08 15:06:22 +02:00
Molkobain
c616e9b65f Remove swfobject.js from iTopWebPage as it was lost during previous merge 2020-10-08 14:38:34 +02:00
Stephen Abello
03418663f2 N°2847 Small scss fix to style JQuery UI modals 2020-10-08 13:30:31 +02:00
Stephen Abello
5a072c75eb N°2847 Fix object details width when using vertical tabs 2020-10-08 10:38:56 +02:00
Pierre Goiffon
10a945eb92 Merge remote-tracking branch 'origin/develop' into feature/backoffice-full-moon-design 2020-10-07 18:48:56 +02:00
Pierre Goiffon
6239c29422 Fix tests
3 files having wrong datamodel XML version
2020-10-07 18:48:46 +02:00
Pierre Goiffon
bb53aef09f Merge remote-tracking branch 'origin/support/2.7' into develop
# Conflicts:
#	application/datamodel.application.xml
2020-10-07 18:37:06 +02:00
Stephen Abello
6cbc7fdb20 N°2847 Fix hardcoded values for Activity New Entry object 2020-10-07 17:01:44 +02:00
Stephen Abello
6a87ce48e1 N°2847 Renamed and moved files for Activity New Entry (thanks to @Molkobain comment on 157e0a6) 2020-10-07 17:01:44 +02:00
Stephen Abello
7770cb31fb N°2847 Add vertical tab options to object details 2020-10-07 17:01:44 +02:00
Pierre Goiffon
06acac97ba Fix tests
* update datamodel XML version
* Remove \Combodo\iTop\Test\UnitTest\Core\OQLTest::testTypeErrorQueryParser
2020-10-07 16:21:36 +02:00
Molkobain
3adcee6da8 Fix regression introduced in 3b6a03d703 2020-10-07 16:01:23 +02:00
Molkobain
ff3ade7d62 Missing parts of the previous merge 2020-10-07 15:32:18 +02:00
Molkobain
ad59e81144 N°2847 - Activity panel: Improve width when expanded 2020-10-07 13:33:38 +02:00
acognet
2d6d1132c7 N°3262 - Avoid PHP notices on DBObject core code 2020-10-07 13:26:38 +02:00
Molkobain
67ab33e727 Merge branch 'feature/backoffice-full-moon-design' of https://github.com/Combodo/iTop into feature/backoffice-full-moon-design 2020-10-07 13:25:12 +02:00
Molkobain
e81e3a0f1c Merge remote-tracking branch 'origin/develop' into feature/backoffice-full-moon-design 2020-10-07 13:18:14 +02:00
Stephen Abello
e89afa163e N°2847 Remove RichText from preferences 2020-10-07 11:36:44 +02:00
Molkobain
e48d257b00 Merge remote-tracking branch 'origin/develop' into feature/backoffice-full-moon-design
# Conflicts:
#	application/ajaxwebpage.class.inc.php
#	application/csvpage.class.inc.php
#	application/displayblock.class.inc.php
#	application/itopwebpage.class.inc.php
#	application/utils.inc.php
#	application/webpage.class.inc.php
#	application/xmlpage.class.inc.php
#	datamodels/2.x/itop-config-mgmt/datamodel.itop-config-mgmt.xml
#	datamodels/2.x/itop-knownerror-light/datamodel.itop-knownerror-light.xml
#	datamodels/2.x/itop-service-mgmt/datamodel.itop-service-mgmt.xml
#	datamodels/2.x/itop-tickets/datamodel.itop-tickets.xml
#	js/components/breadcrumbs.js
#	pages/navigator.php
#	test/core/DBSearchTest.php
2020-10-07 11:36:15 +02:00
BenGrenoble
51669d0479 Fix datamodel Navigation rules and module parameters 2020-10-07 11:08:11 +02:00
BenGrenoble
f983655c68 Fix datamodel Branding 2020-10-07 11:07:34 +02:00
Stephen Abello
157e0a6915 N°2847 Add backend for new entry form for activity panel 2020-10-07 09:46:23 +02:00
Pierre Goiffon
7d26b6092e Merge remote-tracking branch 'origin/support/2.7' into develop
# Conflicts:
#	.idea/codeStyles/codeStyleConfig.xml
#	.idea/inspectionProfiles/Combodo.xml
2020-10-06 10:42:55 +02:00
Molkobain
f5e92359d9 N°2847 - Form: Fix return type in Form::GetAction() 2020-10-05 17:13:32 +02:00
Molkobain
8994f82e0f N°2847 - Fieldset: Fix alignement/positionning with siblings, parent (also some renaming and variables extraction) 2020-10-05 17:03:17 +02:00
Molkobain
8551322cd7 N°2847 - Multi columns layout: Fix alignment with parent (also some renaming to match conventions) 2020-10-05 16:26:41 +02:00
acognet
ed0e16494d N°3335 - Fix test 2020-10-05 16:23:56 +02:00
Pierre Goiffon
a765eb8725 Merge remote-tracking branch 'origin/support/2.6' into support/2.7
# Conflicts:
#	application/ajaxwebpage.class.inc.php
#	application/csvpage.class.inc.php
2020-10-05 16:12:49 +02:00
Molkobain
be075dd695 N°2847 - Object details: Fix alert messages overlapping header and multicolumn layout 2020-10-05 15:53:45 +02:00
Eric
1f53757318 N°3248 - code hardening
(cherry picked from commit 6a25933744)
(cherry picked from commit f74c78d61c)
2020-10-05 14:54:17 +02:00
Pierre Goiffon
090119147c 🎨 PHP formatting 2020-10-05 14:42:03 +02:00
Pierre Goiffon
1551694198 N°3317 Security hardening 2020-10-05 14:42:03 +02:00
Molkobain
0691fca412 Add @since to newly created constants 2020-10-05 13:22:29 +02:00
Molkobain
3298966174 N°3279 - Change "user_id" from integer to external 2020-10-05 13:21:27 +02:00
Molkobain
79514358db N°2847 - Tab container: Fix some issues
- Fix extra tabs list being behind the tab content
- Sanitize tab ID in the HTML
2020-10-05 11:03:23 +02:00
Molkobain
aa38be4578 Improve JSDoc of IsElementVisibleToTheUser() 2020-10-05 11:03:22 +02:00
Molkobain
e911290b3d Improve utils::Sanitize()
- Add class constants for $sSanitizationFilter values (You should use them instead of hard-coding the value, for example: utils::ENUM_SANIZATION_FILTER_XXX)
- Fix "element_identifier" filter of utils::Sanitize() to keep "-" character
- Add 'sanitize_identifier' filter to TWIG
2020-10-05 11:03:22 +02:00
Molkobain
dc24bbcd97 N°2847 - Comment old history tab (waiting for decision on the DisplayBareHistory before removing it) 2020-10-05 08:45:12 +02:00
Molkobain
ea8a8e3afa N°2847 - Add lifecycle states default colors 2020-10-05 08:43:32 +02:00
Molkobain
6fb5d20971 N°2847 - Tab container: Improve global look & feel; responsive tabs. 2020-10-04 23:22:41 +02:00
Molkobain
b3522017e7 Add new JS helper to know if an element is visible to user 2020-10-04 18:37:12 +02:00
Molkobain
e5b22d270e N°2847 - Add SCSS helper for hyperlinks to inherit colors from their parent instead of being of the default color (brand primary) 2020-10-03 23:41:50 +02:00
Molkobain
b8af22baad N°2847 - Fix object details being too wide 2020-10-02 22:09:18 +02:00
Molkobain
5626da7a5e N°2847 - Object details: Preliminary work
- Add ObjectFactory for ObjectDetails, ObjectCard, ...
- Update SCSS files to integrate its components

Note: A big part of the CSS is hardcoded in cmdbAbstract for now as we still need to discuss / work on the migration of the cmdbAbstract APIs (DisplayBareHeader, DisplayBareProperties, ...)
2020-10-02 11:40:46 +02:00
Molkobain
79ad75a2c2 N°2847 - Panel: Fix padding / font size 2020-10-02 11:40:26 +02:00
Molkobain
41c833d0c6 N°2847 - Work on TabContainer: Move SCSS and HTML files to the layout folder 2020-10-02 11:40:26 +02:00
Molkobain
29f58103b0 N°2847 - Comment (temp) migrated parts of the iTopWebPage 2020-10-02 11:40:26 +02:00
Molkobain
15a9856f89 N°2847 - Rework of Panel block
- Add 2 separate content areas (main and toolbar)
- Improve HTML template with header
- Prepare ObjectDetails block based on a panel
2020-10-02 11:40:25 +02:00
Stephen Abello
b3bb77c8ee N°2847 Finish UX/UI for new caselog entry 2020-10-02 10:54:40 +02:00
Stephen Abello
c2fe1bc5cb N°2847 Add new entry form for activity panel (static atm) 2020-10-02 10:54:39 +02:00
BenGrenoble
5d7ae38adf Merge remote-tracking branch 'origin/support/2.7' into support/2.7 2020-10-02 10:51:59 +02:00
BenGrenoble
2e08ae571a 3354 change sie by Sie 2020-10-02 10:51:25 +02:00
Molkobain
7f56911f41 Code cleanup 2020-10-01 22:07:41 +02:00
Molkobain
83a547bbf4 N°2844 - Fix mixed up activity entries
Note: Re-display the history tab for now so we can check consistency between history tab and activity panel
2020-10-01 22:02:03 +02:00
Pierre Goiffon
37522459a8 N°3351 restore LogKPI calls in portal index 2020-10-01 18:02:31 +02:00
Molkobain
8e16d537ff N°2847 - Fix crash on object edition due to TitleFactory::MakeForObjectDetails() refactor 2020-10-01 17:50:59 +02:00
Molkobain
d9fe4599ff N°2847 - Fix tabs being centered instead of being align on the left 2020-10-01 17:49:10 +02:00
Molkobain
50bf0c9a27 N°2847 - Rework of TabContainer / Tab
- Add JS widget to handle front-end logic and for better encapsulation
- Move SCSS files to match convention
- Update SCSS files
- Remove unused SCSS file
- Move HTML templates to match convention
- Remove unused HTML template
- Renamed codes and folders to match convention
- Update PHPDoc
- Reformat code
- Remove usage of return type hinting when using "self"
2020-10-01 17:33:27 +02:00
Molkobain
261131d6d7 PHPDoc and code cleanup 2020-10-01 17:33:26 +02:00
Molkobain
5276b48ed4 N°2847 - Rework of MultiColumn / Column
- Remove unused HTML template
- Move SCSS files to match convention
- Move Column under MultiColumn to match convention (eg. ActivityPanel, PopoverMenu)
- Update PHPDoc
2020-10-01 17:33:26 +02:00
Molkobain
6fd56f750e N°2847 - UIContentBlock: Change code from "contentblock" to "content-block" to match convention 2020-10-01 17:33:25 +02:00
Molkobain
57fda98981 Reformat code 2020-10-01 17:33:24 +02:00
Molkobain
ce001a8097 N°2847 - Rework on iUIContentBlock and PageContent
* Add new Trait tUIContentAreas to handle multiple content areas across UIBlock classes (extracted from PageContent)
* Remove return type hinting in some method when type was "self" or the class itself when it's meant to be overloaded (works only with PHP 7.4+)
* Update some PHPDoc
* Reformat some brackets
2020-10-01 17:33:24 +02:00
Molkobain
d49dd8b993 N°2847 - Start classes icon update 2020-10-01 17:33:23 +02:00
Molkobain
eeec5989d9 Visual tests: Fix panels title 2020-10-01 17:22:28 +02:00
Molkobain
f25ef7f5ac N°2847 - Prepare object details header for demo (will be reworked) 2020-10-01 17:22:27 +02:00
Pierre Goiffon
db8c26da17 📝 update PHPDoc for \Expression::IsTrue 2020-10-01 17:02:22 +02:00
BenGrenoble
93c91c4077 3354 remove now from "Bitte bestätigen sie, dass jetzt ein Backup erstellen wollen now." 2020-10-01 15:11:07 +02:00
Pierre Goiffon
e4b3871947 📝 PHPDoc for \Expression::IsTrue 2020-10-01 14:51:28 +02:00
Pierre Goiffon
b2474d3368 N°3324 Portal fix ignore_silo when using nested query in scopes
The AllowAllData attribute wasn't updated in the nested queries.
It is now set both when calling DBObjectSearch::AllowAllData and when creating a new nested query (\DBObjectSearch::AddConditionExpression)
2020-10-01 12:15:34 +02:00
Pierre Goiffon
6cd0670d6b 🎨 Fix parameter for all DBSearch::AllowAllData impl 2020-10-01 10:09:34 +02:00
Pierre Goiffon
e9f81bd978 🔧 Update .Editorconfig for braces always at eol 2020-10-01 10:09:34 +02:00
odain
5862ecde69 N°3117: force itop-structure loading during setup 2020-09-30 17:32:07 +02:00
Molkobain
f8129fab74 N°2899 - Setup: Fix "For CryptoEngine ..." mandatory PHP extension introduced in the previous commit 2020-09-30 16:22:35 +02:00
odain
ee9343cf40 N°3117: fix refactor regarding itop-structure setup 2020-09-30 16:00:36 +02:00
Molkobain
1b2dd04409 N°2899 - Setup: Remove mbstring from optional PHP extensions now that it is mandatory (7d1a61a2f) (Thanks @Hispka !) 2020-09-30 14:38:55 +02:00
Eric
40f3d6efbe N°2847 - fix newsroom target for links 2020-09-30 11:59:22 +02:00
Eric
5c07591519 N°2847 - fix newsroom target for links 2020-09-30 11:56:55 +02:00
Eric
f0f7653884 N°2847 - revert fix inline scripts 2020-09-30 10:54:34 +02:00
Stephen Abello
de54d28c6b N°2847 Fix newsroom not being displayed with block render changes 2020-09-30 10:40:41 +02:00
Eric
292457595c N°2847 - Fix inline scripts 2020-09-30 10:36:01 +02:00
Eric
0cc5dc0471 N°3317 - Add http headers 2020-09-30 10:18:44 +02:00
Eric
a99f03e510 N°2847 - Edit/Create objects 2020-09-30 09:56:03 +02:00
Stephen Abello
fd3f972948 N°2847 Add RichText input 2020-09-30 09:42:36 +02:00
Stephen Abello
12bf77d9ca N°2847 Refactor Inputs components 2020-09-30 09:42:36 +02:00
Stephen Abello
c0337eaa23 N°2847 Fix twig missing templates (missing file or wrong case) 2020-09-30 09:42:36 +02:00
Eric
b8d71b2bfb N°2847 - Edit/Create objects 2020-09-29 17:35:02 +02:00
Thomas Casteleyn
5ef6b6c5d0 Cleanup references to Flash (#163)
All remaining Flash files are removed. Dependent Combodo extensions will me modified for iTop 2.8.0 (Combodo ref N°3344, N°3345)

Old swf_navigator operation in UI.php was kept for compatibility but is deprecated

Co-authored-by: Molkobain <guillaume.lajarige@combodo.com>
Co-authored-by: Pierre Goiffon <pierre.goiffon@combodo.com>
Co-authored-by: rquetiez <romain.quetiez@combodo.com>
2020-09-29 15:56:08 +02:00
Eric
078f81e853 N°2847 - Shortcut buttons look 2020-09-29 15:02:05 +02:00
odain
20ce42b24b Reintegrate validation tests to ease iTop release management from develop
- N°3053 - Check XML conversion methods
     - N°3059 - Automatically set the documentation URLs
     - N°3052 - Check community modules XML version against latest version
     - N°3054 - Check community modules version against major version
     - N°3062 - setup.css file integrity test
     - N°3060 - Check consistency between the list of modules and installation.xml
     - N°3061 - Automatically check the installation.xml consistency
     - N°3268 Add test to check dictionary files: make sure that the Dict::Add declarations match the file name
2020-09-29 14:43:51 +02:00
Eric
11a79501da N°988 - Backoffice: Hide empty fieldsets in object details 2020-09-29 14:21:01 +02:00
Eric
d86e904e18 N°3317 - Add http headers 2020-09-29 14:11:11 +02:00
Eric
bef1832ac7 N°3317 - Add http headers 2020-09-29 14:07:24 +02:00
Eric
5a46bb8461 N°3320: Do not display empty tabs 2020-09-29 11:23:49 +02:00
Molkobain
3dc7b66f6f N°2847 - Code clean up
* Fix TWIG exceptions due non existent JS templates for ajax tab
* Fix DisplayBlock::GetRenderContent and HistoryBlock::GetRenderContent signature mismatch warning
* Add return type hinting on ButtonFactory methods
* Rename ButtonFactory::MakeAlternativeNeutralActionButton() to ButtonFactory::MakeLinkNeutral()
* Add ButtonFactory::MakeLinkNeutral() to visual test page
* Fix button spacing/padding when only icon or label
2020-09-29 10:35:16 +02:00
acognet
05a0d61244 N°3335 - Notifications on threshold don't work when trigger is created on iTop 2.7.1 - nicer fix 2020-09-29 10:27:05 +02:00
Eric
2b0bdda1e0 Fix type hinting 2020-09-29 09:23:13 +02:00
acognet
80b3212a19 N°3335 - Notifications on threshold don't work when trigger is created on iTop 2.7.1 2020-09-29 09:12:47 +02:00
Molkobain
794ee89d12 N°2847 - Fix "quick create" history display 2020-09-28 17:14:46 +02:00
Molkobain
c37aabfc8c N°2847 - Fix TWIG exceptions due non existent JS templates 2020-09-28 17:14:13 +02:00
Molkobain
987ab4cbfb PHPDoc and code cleanup 2020-09-28 16:54:58 +02:00
Molkobain
0aaa0a33bf N°2847 - Remove history tab from object details 2020-09-28 16:37:39 +02:00
odain
3fd9aa01ed Merge branch 'feature/b3217-2dev' into develop 2020-09-28 16:35:22 +02:00
odain
97380fd5f4 N°3117 Refactor of datamodel and dictionnaries for the sake of modularity
- New module itop-bridge-cmdb-ticket to cope with the need to install only the CMDB or/and ticketing
	- New module itop-structure to hold declarations required by iTop independently from ITIL. Note that these declarations should ideally be moved to application/datamodel.application.xml or core/datamodel.core.xml. Anyhow, the compiler suffers a few limitations and it has been decided to create this module as a workaround.
	- Split of known-error module into itop-faq-light and itop-knownerror-light
2020-09-28 16:34:06 +02:00
odain
bcd41dfe96 Merge branch 'feature/b3217-squash' into develop 2020-09-28 15:08:57 +02:00
odain
54eb86a16b N°3117 Refactor of datamodel and dictionnaries for the sake of modularity
- New module itop-bridge-cmdb-ticket to cope with the need to install only the CMDB or/and ticketing
	- New module itop-structure to hold declarations required by iTop independently from ITIL. Note that these declarations should ideally be moved to application/datamodel.application.xml or core/datamodel.core.xml. Anyhow, the compiler suffers a few limitations and it has been decided to create this module as a workaround.
	- Split of known-error module into itop-faq-light and itop-knownerror-light
2020-09-28 15:08:21 +02:00
Molkobain
794d4f1e0e N°3310 - Fix corrupted backups when a file has a size which is a multiple of 512 bytes 2020-09-28 14:31:36 +02:00
Molkobain
389b61d3a8 Fix missing author information in composer.json for TCPDF lib. 2020-09-28 14:29:51 +02:00
Molkobain
0948e80060 N°3320 - Fix empty tabs being displayed (misuse of the API or user rights) 2020-09-28 14:10:19 +02:00
Eric
795b28263a N°2847 - Fixed unit tests 2020-09-28 11:23:31 +02:00
Eric
8306ce36a0 N°2847 - Fixed multi-column bottom margin 2020-09-25 18:21:23 +02:00
Eric
6c46c7ff3a N°2847 - Fixed configuration editor 2020-09-25 18:16:05 +02:00
Eric
bfd4ba16d9 N°2847 - Action buttons 2020-09-25 16:02:18 +02:00
odain
9520d2794f 💚 fix ci Serialization of 'ReflectionClass' is not allowed 2020-09-25 10:29:48 +02:00
Pierre Goiffon
e2c67dfcc4 Merge remote-tracking branch 'origin/support/2.6' into support/2.7 2020-09-25 08:57:08 +02:00
odain
4e0eed6e13 N°3270 Notify on expiration not sending notification (trigger exception)
add boilerplate function and use it to intercept/enrich trigger exception loops
2020-09-25 07:18:14 +02:00
Pierre Goiffon
45e366745d N°3333 Security hardening 2020-09-24 17:34:57 +02:00
Eric
6969e4db1b N°2847 - Title CSS 2020-09-24 15:12:25 +02:00
Pierre Goiffon
661d84fc77 ThemeHandlerTest : fix tmp dir clean up 2020-09-24 14:17:08 +02:00
Pierre Goiffon
9eac12bd9c Fix CSS precompilation signature check on non Linux OS
* fix images paths comparison
* fix MD5

Were depending on platform : \ThemeHandlerTest::testGetIncludedImages test passed on Linux, not on Windows due to different DIRECTORY_SEPARATOR
2020-09-24 12:38:16 +02:00
Eric
ecd5a7aadf N°2847 - FieldSet, MultiColumn, Tab for object details CSS 2020-09-24 10:45:14 +02:00
Pierre Goiffon
1e634a8bba N°3332 Security hardening 2020-09-23 17:17:05 +02:00
Eric
7bf473d2a3 N°2847 - FieldSet, MultiColumn, Tab CSS 2020-09-23 14:51:18 +02:00
Eric
98d2e42bad N°2847 - FieldSet and Fields 2020-09-23 08:55:58 +02:00
Pierre Goiffon
9e9b192b3c N°2214 Blocks execution for PHP < 7.0.0
As older PHP version can cause multiple problems, and we still use lots of requires that can generate PARSE_ERROR on such version, we chose to add this very low-level control. Therefore user will get a clear error message, and oldest PHP version will be blocked in the whole application.
2020-09-22 15:35:13 +02:00
Pierre Goiffon
98789f28bb N°3198 Relations Table Mode : control duplicates server side 2020-09-22 13:32:32 +02:00
Eric
33f11d2a43 N°2847 - Form and Input WIP 2020-09-22 13:26:14 +02:00
Eric
94b9a9bb75 N°3309 - Spelling mistake 2020-09-22 12:51:43 +02:00
Eric
0c90b701ea N°3283 - Spelling mistake 2020-09-22 12:45:19 +02:00
Eric
58961cd4ec N°3318 - don't display error details 2020-09-22 11:57:43 +02:00
Eric
1453558f3e N°3317 - Add http headers 2020-09-22 11:39:19 +02:00
Eric
c6df0b6d7d N°3311 - Stop capturing output before sending backup file (avoid memory problem) 2020-09-22 11:03:59 +02:00
Eric
40efaf0360 N°2847 - Tab Management 2020-09-22 08:24:18 +02:00
Pierre Goiffon
7c3659d5ba 🔧 Remove versionned PHPStorm files
Those files were duplicates of the .editorconfig file

.editorconfig was pushed with ecd8f40c0f for 2.7.0 and should be the only source of the IDE / editor configuration

This generic format is implemented in PHPStorm since v2019.2 (see https://blog.jetbrains.com/idea/2019/06/managing-code-style-on-a-directory-level-with-editorconfig/)
To check if your IDE / editor supports it, check https://editorconfig.org/
2020-09-18 18:26:31 +02:00
Eric
74160d2447 N°2847 - Add Title component
* Add id to button factory
 * Rework of Configuration File Editor page
2020-09-18 18:16:09 +02:00
Eric
08eada82f4 N°2847 - Fix External key selection 2020-09-18 18:16:09 +02:00
Eric
9cd719ab56 N°2847 - Separate inline scripts and css from html in the rendering of pages 2020-09-18 18:16:09 +02:00
Eric
e83dfe5982 N°2847 - refactor twigs 2020-09-18 18:16:08 +02:00
Pierre Goiffon
077ac81208 Merge remote-tracking branch 'origin/develop' into feature/backoffice-full-moon-design 2020-09-18 14:24:19 +02:00
Pierre Goiffon
36f8344ec9 Merge remote-tracking branch 'origin/support/2.7' into develop
# Conflicts:
#	js/table-selectable-lines.js
2020-09-18 14:23:36 +02:00
Pierre Goiffon
dd942997cb 🎨 Fix invalid formatting introduced in 827b4b5bbe 2020-09-18 14:22:28 +02:00
Pierre Goiffon
57fea03745 🔧 Fix editorconfig for JS files 2020-09-18 14:21:47 +02:00
Pierre Goiffon
827b4b5bbe 🎨 Fix string delimiter
Thanks @jbostoen for pointing this out (see discussion in 0773660ef2)
2020-09-18 14:15:41 +02:00
Pierre Goiffon
745e4aa424 Merge remote-tracking branch 'origin/develop' into feature/backoffice-full-moon-design
# Conflicts:
#	webservices/import.php
2020-09-18 10:48:34 +02:00
Pierre Goiffon
5405ae1d91 Merge remote-tracking branch 'origin/support/2.7' into develop 2020-09-18 10:47:30 +02:00
Pierre Goiffon
ed1bb3e93a N°2214 Add PHP check in CLI scripts : 2nd code review with Romain
- fix wrong test in \SetupUtils::CheckPhpAndExtensions
- fix \SetupUtils::CheckGraphviz consumers in WizardStep : do not assume that only one CheckResult is returned... doing a for each loop instead !
- json_encode prb on Windows : pull up default messages from consumers to \SetupUtils::CheckGraphviz (was introduced in 6e754d4fa5)
2020-09-18 10:43:39 +02:00
Pierre Goiffon
7de59c1977 Update .editorconfig 2020-09-18 10:19:38 +02:00
Pierre Goiffon
0773660ef2 N°3198 Relations Table Mode : update table select line script
Was selecting line when clicking in the ext key widget (drop-down using Selectize, search/add widgets)
2020-09-17 14:48:00 +02:00
Eric
68b8490288 N°2847 - Refactor 2020-09-17 11:01:41 +02:00
Eric
f100e9bd09 N°2957 - allow empty class parameter 2020-09-16 17:57:38 +02:00
Eric
0ffe76e359 N°2847 - Fix Global search 2020-09-16 17:38:46 +02:00
Eric
e3739641b4 N°2847 - Ajax page javascripts 2020-09-16 17:16:01 +02:00
Eric
410a637598 N°2847 - Tab Management - iTop Pages refactoring - introduction of UIContentBlock as base block 2020-09-16 12:00:48 +02:00
Pierre Goiffon
c34c4bc09d 📝 Fix CRUD wiki page URL
was linking to Combodo private wiki :/, now is the public one \o/
Many thanks @Hipska !
2020-09-14 15:05:44 +02:00
Pierre Goiffon
eded4814a1 Merge remote-tracking branch 'origin/support/2.7' into develop 2020-09-14 14:27:18 +02:00
Pierre Goiffon
bced819b3f 📝 N°2293 PHPDoc for DBObject::GetOriginal 2020-09-14 14:26:29 +02:00
Pierre Goiffon
b9f9322418 N°2214 Remove type hinting in SetuUtils for compatibility issues
This file needs to be able to run on very old PHP versions !
2020-09-14 11:38:55 +02:00
Pierre Goiffon
4badb90344 N°2214 Cron : remove :void to keep compatibility with PHP < 7.1
see https://www.php.net/manual/fr/migration71.new-features.php#migration71.new-features.void-functions
2020-09-14 11:02:18 +02:00
Thomas Casteleyn
0542a8e4f8 Synchro cleanup (#157)
* Cleanup duplicate code
* Document undocumented parameter
* Removed duplicate code for consistency
2020-09-14 09:53:40 +02:00
Pierre Goiffon
f0434f9125 🎨 N°2214 In SetupUtils::Check* methods : replace debug SetupLog calls by CheckResult::TRACE objects
This is the caller responsibility to log using the correct classes !
Also we need to remove this dependency O:)

Modifications:
* reverts e8e259dde9 as SetupPage is no longer called since N°2522 / c4b7be5b6f
* \SetupUtils::Log : remove useless final, add PHPDoc and type hinting to modified methods
* add PHPDoc and type hinting to modified methods
* add \CheckResult::TRACE
* replace SetupLog::Log calls by CheckResult::TRACE
* modify SetupUtils::Check* callers to handle the new TRACE severity
2020-09-11 18:37:30 +02:00
acognet
23136bdf00 N°3303 - Bug on Mass update of actions (notification) 2020-09-11 09:53:23 +02:00
Lars Kaltefleiter
43cadb0ede N°3287 - Set from display name / label in action email
Co-authored-by: Thomas Casteleyn <thomas.casteleyn@me.com>
2020-09-11 09:50:14 +02:00
Pierre Goiffon
11f00cc229 N°2214 PHP version check in CLI scripts : remove some checks in CLI, and various improvements
Initial commit : b7136c0b7a

Removed checks : see \SetupUtils::CheckPhpAndExtensions PHPDoc

Other improvements :
* add PhpDoc on new public method \SetupUtils::CheckPhpAndExtensions
* add type hinting and new format on SetupUtils new methods
* refactor CheckResult[] filter method to be more generic
2020-09-10 16:52:47 +02:00
Stephen Abello
163c1ebc91 N°2847 Add disabled state for Button component 2020-09-10 15:33:35 +02:00
Eric
580e8ffa08 N°2847 - Refactor Web Pages classes - add deprecated files for extensions compatibility 2020-09-10 11:35:21 +02:00
rquetiez
f5a3bb2baa N°3251 - Null in data synchro (fixes the regression introduced in a1f5d80)
- restore the initial behavior, thanks to hipska through PR#166
- refactor so as to make it clear that no SQL injection is possible (and will never be)
- add PHPUnit tests on the data synchronization => up to 20s to execute
- fix utils::ExeciTopScript to alow its usage within the automated test
2020-09-09 22:41:13 +02:00
Eric
63f8ec594c N°2847 - Refactor Web Pages classes - Add UIBlockManager to the WebPage 2020-09-09 18:10:06 +02:00
Eric
2df2392cc6 Fix images in form edition 2020-09-09 14:27:58 +02:00
odain
d2e5e96a63 💚 fix remaining failed tests after merge 2020-09-09 06:52:09 +02:00
Molkobain
8193ada159 Merge remote-tracking branch 'origin/develop' into feature/backoffice-full-moon-design
# Conflicts:
#	composer.json
#	css/light-grey.scss
#	lib/composer/autoload_classmap.php
#	lib/composer/autoload_static.php
2020-09-08 17:30:32 +02:00
Eric
46fe1661db Display modal 2020-09-08 17:20:13 +02:00
odain
2ff6658a56 Merge branch 'develop' into feature/b3217-2dev 2020-09-08 17:00:41 +02:00
Benjamin Planque
f25cd70e73 datamodel and dictionnaries refactoring/cleanup 2020-09-08 16:36:21 +02:00
odain
b5cfd1c61e 💚 uncomment test 2020-09-08 11:36:42 +02:00
Molkobain
3c9c3204ac N°2847 - Update folders order 2020-09-08 10:11:21 +02:00
odain
7ab274cb7b 💚 fix test after merge 2020-09-08 09:21:06 +02:00
Molkobain
7d1a61a2f9 N°2899 - Setup: Add mbstring as mandatory PHP extension 2020-09-08 09:12:43 +02:00
odain
3c299654e3 N°3265 - Log stacktrace when cron exception raised with debug enabled 2020-09-07 16:57:27 +02:00
odain
1eba8ba4ac Merge branch 'support/2.7' into develop 2020-09-07 16:48:15 +02:00
odain
98c371c5cf add new code style for brackets 2020-09-07 16:12:12 +02:00
Thomas Casteleyn
9daf23576d Update the movie icon with a flat design 2020-09-07 15:20:08 +02:00
Thomas Casteleyn
b9f23177e7 Add attachment icon for movie files 2020-09-07 15:20:08 +02:00
acognet
1e0415e902 3234 - php 5.6 compatibility 2020-09-07 12:14:38 +02:00
Thomas Casteleyn
6542cf9d30 Add missing "
Co-authored-by: Eric Espié <eric.espie@combodo.com>
2020-09-06 20:30:36 +02:00
Thomas Casteleyn
610e74e642 Fix filename headers when downloading 2020-09-06 20:30:36 +02:00
Eric
dbada2f72a N°3238 - Fix multi-words search in FilterBrick and ManageBrick 2020-09-04 17:34:59 +02:00
OИUЯd da silva
c3ecd51153 Merge pull request #134 from itomig-de/feature/IsWriteAllowed
Enable external classes to use bypass function as well
2020-09-04 10:26:30 +02:00
Eric
9694e9848d N°3285 - Fix Standard Global Search: multiple words search 2020-09-04 09:27:39 +02:00
bruno-ds
fe87700135 Un-deprecate ItopExtensionsExtraRoutes::AddRoutes(...)
we had imagined it as a compatibility layer for migrating from Silex to Symfony,
but it must'nt be deprecated until we provide a new API (ideally based on a scan of yaml configuration file?)
2020-09-03 16:43:30 +02:00
Eric
ff722b579b Fix Dependent attributes update on DBObject::Set() 2020-09-03 12:57:01 +02:00
Eric
7107c2f616 N°3260 - Fix rendering of an ExternalField on a Text with XML content (format transitivity) 2020-09-02 18:15:31 +02:00
Eric
92e0f101d7 N°3260 - Fix rendering of an ExternalField on a Text with XML content (format transitivity) 2020-09-02 17:58:04 +02:00
Eric
7e0fbd8c25 revert file 2020-09-02 15:42:44 +02:00
Eric
9f592223d9 Add Cron info to the report 2020-09-02 14:41:06 +02:00
Molkobain
99fc41a0f8 PHPDoc & code cleanup 2020-09-02 12:01:35 +02:00
Eric
76fbd3790f N°3123 - Update the list of required PHP extensions 2020-09-02 10:47:42 +02:00
Eric
d3b57c3bda N°3111 - Fix Portal export 2020-09-01 17:17:01 +02:00
acognet
a61ffaf3c0 N°3184 - Upgrade JQuery UI (iTop 2.8) 2020-09-01 16:36:49 +02:00
acognet
29624bc5c5 N°3163 - Portal Filters doesn't work 2020-09-01 14:16:16 +02:00
acognet
d09f3f4f83 N°3149 - Change Color of Brick Search on Portail with extension Custom 2020-09-01 10:55:48 +02:00
acognet
cc6ab8a7b7 N°3184 - Upgrade JQuery UI (iTop 2.8) 2020-09-01 09:06:14 +02:00
acognet
432a565221 N°2508 - Include Obsolescence icon within list and autocomplete 2020-09-01 09:06:14 +02:00
acognet
f774a90b7e N°3146 - Affichage des class user dans l'import CSV 2020-08-31 17:15:59 +02:00
acognet
fef8038f70 N°3261 - Configure this list : sort icon disappears when descending sort is selected 2020-08-31 15:11:47 +02:00
bruno-ds
7d8aaf91db :greenheart: test readability 2020-08-31 14:48:49 +02:00
bruno-ds
2806a76c1d :greenheart: test readability 2020-08-31 14:47:55 +02:00
Molkobain
eb99dc9f3f Add Lucas Mindêllo de Andrade (a.k.a @rokam) to the contributors list, huge thank you!
Note: We start to put GitHub aliases next to the full name of contributors. If you want yours to be added/updated, just comment this commit 🖖
2020-08-31 13:17:47 +02:00
Lucas Mindêllo de Andrade
f59f2b2109 Update PT BR translations (#159)
* Correct threshold translation
* Better translation for closed requests
* itop-portal better translation
* Fixed typo
* Missing PT-BR translations
* Removed ~~ from translated messages

Co-authored-by: Lucas Mindêllo de Andrade <lucas.rokam@gmail.com>
2020-08-31 13:12:20 +02:00
Eric
328ec52c88 N°3162 - Remove default admin phone number (can be incompatible with validation pattern) 2020-08-31 11:38:24 +02:00
Molkobain
2840f6930b N°2847 - Navigation menu: Fix newsroom icon color on hover 2020-08-28 22:15:47 +02:00
Molkobain
c50b6c806a N°2847 - Navigation menu: Fix user picture size / position when image is taller than wide 2020-08-28 22:11:36 +02:00
odain
84cd18bcb8 💚 fix test to make conversion functions exist for any one found in datamodels files (itop pro version) 2020-08-28 21:05:04 +02:00
Molkobain
c2fcadd54d N°2847 - Add optional user_id to CMDBChange
Important: This can make the setup / toolkit to take a very long time on large databases as the "priv_change" table is one of the largest. SQL queries to run and/or a migration tool will be provided when 2.8.0 will be released.
2020-08-28 19:46:40 +02:00
odain
26ba45a8da 💚 fix test to make conversion functions exist for any one found in datamodels files 2020-08-28 18:35:05 +02:00
Eric
70734e2b71 N°3188 - Fix LIfeCycle visualization details
Fix js broken by the fix of N°309
2020-08-28 17:28:52 +02:00
odain
4cc31bf941 💚 fix test to make conversion functions exist for any one found in datamodels files 2020-08-28 17:23:02 +02:00
odain
0d878a52a2 💚 fix test to make conversion functions exist for any one found in datamodels files 2020-08-28 16:48:04 +02:00
Eric
d1af851fcd N°2591 - API : deprecate \CMDBObject::CheckUserRights 2020-08-28 14:48:00 +02:00
Eric
ec72d1c767 N°3078 - Fix error on login while in maintenance mode
Fix infinite loop on login failure
2020-08-28 14:26:42 +02:00
Molkobain
3add77308a N°2847 - ActivityPanel: Fix entry's author info for CMDBChangeOp 2020-08-27 18:57:41 +02:00
Eric
bb892cc180 N°3078 - Fix error on login while in maintenance mode 2020-08-27 17:10:37 +02:00
Molkobain
d0ea3665be PHPDoc & code cleanup 2020-08-27 16:37:18 +02:00
Molkobain
ae19737472 PHPDoc & code cleanup 2020-08-27 16:23:29 +02:00
Molkobain
4c236b4422 N°2847 - Breadcrumbs: Fix type hint in SetNewEntry ($aNewEntry can be null) 2020-08-27 16:15:07 +02:00
acognet
c4b7be5b6f N°2522 - API : Deprecate SetupPage:log* 2020-08-27 11:17:42 +02:00
Eric
1afc6cd4c5 N°2363 - Fix typo 2020-08-27 10:50:34 +02:00
Eric
3b6a03d703 Fix warning if not countable 2020-08-27 09:57:00 +02:00
odain
a4842f9e5c N°2996 - Remove iTop version from css-variable.scss
Fix PCRE non backward compatibility between PHP 7.2 and 7.3
2020-08-27 09:37:10 +02:00
Molkobain
0bef32cf8d N°2847 - Alert & Panel: Add top spacing, fix border-radius and reorder some parts of the SCSS 2020-08-26 22:15:50 +02:00
Molkobain
825c70c001 Introduce type hinting in methods prototype (PHP >= 7.1) 2020-08-26 21:22:39 +02:00
Molkobain
77cd764b1c PHPDoc & code cleanup 2020-08-26 21:22:25 +02:00
Molkobain
2864d48fa7 N°2847 - Flag TODOs as 2.8.0 so we don't forget any 2020-08-26 20:37:22 +02:00
Molkobain
b5c97e35bf Add visibility to class constants (PHP >= 7.1) 2020-08-26 19:02:53 +02:00
odain
9a0d9d2c38 Merge branch 'feature/fast-theme-compilation2' into develop
N°2982 - speedup themes/scss compilation during setup
N°2996 - Remove iTop version from css-variable.scss
2020-08-26 17:59:31 +02:00
Molkobain
8bdaec0129 N°2847 - Alert & Panel: Improve factories, add color schemes, add visual tests 2020-08-26 17:45:22 +02:00
Molkobain
3b0ca9d771 N°2847 - Add "information" semantic to color palette, reorder colors like a rainbow 🌈 2020-08-26 17:45:22 +02:00
Molkobain
fa406c1f17 PHPDoc & code cleanup 2020-08-26 17:45:22 +02:00
odain
dd18430e70 remove GetCompiledModuleVersion deprecation 2020-08-26 16:33:49 +02:00
Molkobain
7f3c10b69d Merge remote-tracking branch 'origin/develop' into feature/backoffice-full-moon-design 2020-08-26 16:09:23 +02:00
Molkobain
0a5e4effc0 N°2847 - Fix Html and Panel namespaces 2020-08-26 16:05:33 +02:00
Molkobain
737e17066f N°2847 - Add page for visual testing of blocks 2020-08-26 16:03:34 +02:00
Molkobain
8108dc8803 N°2847 - Button: Reformat SCSS file 2020-08-26 16:03:34 +02:00
Molkobain
61ec7f8053 N°2847 - Button: Add factory, color constants and refactor existing code to use the factory 2020-08-26 16:03:33 +02:00
Molkobain
d5f44ffd7b N°2847 - Alert: Add factory and color constants 2020-08-26 16:03:33 +02:00
Molkobain
d2bf4de84c N°2847 - Refactor some early choices
- TWIG: Change calls to object methods from simple notation (eg. oObject.Id) to complete notation (eg. oObject.GetId()) to avoid confusion with use of arrays and variables (eg. aObject.sId)
- UIBlock: $sId should not be first parameter as most of the time it can be ignored and generated by the system
- NewsroomMenu: Rename method for something more less ambiguous
- Html: Embed content in <div /> so we can easily find all such HTML fragments in the UI
2020-08-26 16:03:33 +02:00
Molkobain
5320f69c44 PHPDoc & code cleanup 2020-08-26 16:03:32 +02:00
Molkobain
eb1322dc3e N°2847 - iTopWebPage: Continue cleanup of the legacy code 2020-08-26 16:03:32 +02:00
odain
e8e259dde9 N°2214 - Add a PHP version check in CLI PHP scripts- fix import.php script 2020-08-26 15:56:11 +02:00
Eric
5df7c8bb07 Add Async tasks info 2020-08-26 16:12:22 +02:00
Eric
bf142e5e07 Add Async tasks info 2020-08-26 13:11:04 +02:00
odain
8319d655b9 💚 renaming postbuild test folder + fix tests 2020-08-26 12:42:48 +02:00
odain
f5c8411a07 💚 ThemeHandlerTest: test fix + enhance failure messages 2020-08-26 12:09:55 +02:00
Eric
2ad4fd1707 N°580 - Autocomplete with namesakes. Complement for select. Fix error when no complement specified 2020-08-25 13:12:53 +02:00
Eric
761c2a46a3 N°3234 - Cron rework
* some timezone refactors occurred
2020-08-25 11:20:17 +02:00
odain
c986927de9 CI switching 2020-08-24 14:11:25 +02:00
Eric
e8eb6d0e31 N°3249 - N°2957 - Revert one file per class => generate all the classes in the same file: model.<module>.php to address forward declaration of classes 2020-08-24 12:41:49 +02:00
Eric
077772ea9c N°2969 - moved dictionaries 2020-08-24 09:31:34 +02:00
acognet
4618f12d8a N°3234 - Notify on expiration not sending notifications 2020-08-21 18:50:27 +02:00
rquetiez
3119af6c29 N°3268 Add test to check dictionary files: make sure that the Dict::Add declarations match the file name 2020-08-21 17:43:40 +02:00
Molkobain
83ef7cff8a N°3267 - Webservices: Fix optional headers not being taken into account 2020-08-21 16:55:03 +02:00
Stephen Abello
93eace9e5b N°2847 Fix preference page width 2020-08-21 14:02:41 +02:00
odain
d12e2e592a N°3265 - Log stacktrace when cron exception raised with debug enabled 2020-08-21 10:25:05 +02:00
acognet
2142ffedc3 Add PHP Warning for misused of the function OptimizeColumnLoad 2020-08-20 16:44:44 +02:00
acognet
23c0a67914 N°580 - Autocomplete with namesakes. Complement for select 2020-08-20 16:42:43 +02:00
Eric
3b00911f62 Merge branch 'GurneyHallack-feature/api-core_get' into develop 2020-08-20 15:46:19 +02:00
Eric
b9b1e436ec Merge branch 'feature/api-core_get' of https://github.com/GurneyHallack/iTop into GurneyHallack-feature/api-core_get 2020-08-20 15:44:52 +02:00
Eric
87312d4457 N°2969 - Fix relative path of dictionaries 2020-08-20 14:45:43 +02:00
Stephen Abello
9dcb4bbfe5 N°2847 First step to convert user preferences page to our new design 2020-08-20 11:14:15 +02:00
Stephen Abello
11f27019e4 N°2847 - Add Html component
- Fix icons on buttons
- Comment some rules from legacy css
2020-08-20 11:14:15 +02:00
Stephen Abello
dd81c76aaa N°2847 Add margin to panels and buttons siblings 2020-08-20 11:14:14 +02:00
Pierre Goiffon
4e5bbcde35 N°3198 n:n relations in edit mode : refresh remote class fields on extkey change 2020-08-19 16:06:37 +02:00
Pierre Goiffon
7d7270296e 🎨 📝 format & add comment 2020-08-19 16:06:37 +02:00
Pierre Goiffon
44e188fa2c N°3198 n:n relations in edit mode : extkey to remote class is now editable 2020-08-19 16:06:11 +02:00
Molkobain
e6bab46854 Add unit tests for XML migration from 1.8 > 1.7 and 1.7 > 1.6 2020-08-19 11:36:40 +02:00
Molkobain
0a4ce0865e Increase XML version to 1.8 2020-08-19 11:12:39 +02:00
Molkobain
da1d3db204 N°2847 - Activity panel: Fix filtering on CMDBChangeOp entries 2020-08-19 11:01:13 +02:00
Molkobain
880be200ae Revert "N°2847 Fix first and last popover menu item border radius"
This reverts commit 417008f5
2020-08-19 10:23:40 +02:00
Molkobain
c5b8d3fa72 Merge remote-tracking branch 'origin/develop' into feature/backoffice-full-moon-design
# Conflicts:
#	application/datamodel.application.xml
#	application/itopwebpage.class.inc.php
#	css/light-grey.scss
2020-08-19 10:20:37 +02:00
Stephen Abello
417008f549 N°2847 Fix first and last popover menu item border radius 2020-08-19 10:12:04 +02:00
Molkobain
8077e5aa62 PHPDoc & code cleanup 2020-08-19 10:09:02 +02:00
Molkobain
2ce1c2efec N°2847 - Work on the ActivityPanel and PopoverMenu features
- Deprecate cmdbAbstractObject::DisplayBareHistory() as history will be replace by ActivityPanel
- Rename illustrations to original filenames to find source more easily
- Remove unused "max_history_case_log_entry_length" config. parameter
- Activity panel: Introduce iCMDBChangeOp and iCMDBChangeOpSetAttribute interface for better dependency injection
- Activity panel: Add placeholder when no entry
- Activity panel: Fix tab toolbar icons color
- Activity panel: Add history entries (entries after the first 50 are not loaded yet)
- Popover menu: Fix no border-radius on first/last entries hover
2020-08-19 10:09:01 +02:00
Pierre Goiffon
c69e83f779 Merge remote-tracking branch 'origin/support/2.7' into develop 2020-08-18 17:50:39 +02:00
Eric
6a25933744 N°3248 - code hardening 2020-08-18 17:21:48 +02:00
odain
91006351d3 Fix tests 💚 2020-08-18 17:20:47 +02:00
Pierre Goiffon
208ccfe3ab N°3257 Fix cannot create objects with AttributeImage from extkey widget on PHP 7.4 2020-08-18 17:13:37 +02:00
Eric
f74c78d61c N°3248 - code hardening 2020-08-18 17:02:46 +02:00
acognet
e43f55df03 N°2508 - Include Obsolescence icon within list and autocomplete 2020-08-18 15:55:03 +02:00
acognet
0f741f28f3 N°2508 - Include Obsolescence icon within list and autocomplete 2020-08-18 15:14:50 +02:00
Eric
6176af089c N°3256 - Invalid filter parameter, when using & (ampersand) in filter parameter (OQL Query) 2020-08-18 14:41:18 +02:00
acognet
4d2633a9ea N°2508 - Include Obsolescence icon within list and autocomplete 2020-08-18 14:19:36 +02:00
Eric
c5d265f66b N°3249 - Fix move To Production. Fix compiler code generation broken by N°2957 2020-08-18 14:17:01 +02:00
Eric
0311fe330b Fix setup CSS 2020-08-18 14:14:52 +02:00
acognet
4648e436ac N°2508 - Include Obsolescence icon within list and autocomplete 2020-08-18 12:42:48 +02:00
Stephen Abello
e39947f72c N°2847 Add semantic colors to alert and panel component 2020-08-18 12:06:18 +02:00
Stephen Abello
74db53d51d N°2847 Add alert component 2020-08-18 12:03:21 +02:00
odain
0b9ba4d053 Merge branch 'feature/release-checklist-2.7' into develop 2020-08-18 10:31:02 +02:00
acognet
700d11fa8f N°2508 - Include Obsolescence icon within list and autocomplete 2020-08-18 10:19:01 +02:00
acognet
f64e081c1f Remove file unused 2020-08-18 10:19:01 +02:00
acognet
54b6a29ba0 N°2393 - API : Font Awesome remove v4 compatibility 2020-08-18 10:19:00 +02:00
acognet
e0bf262343 N°2534 - dashboard: bug with autorefresh that deactivates filtering on organizations 2020-08-18 10:19:00 +02:00
Pierre Goiffon
3a276715d6 📝 SECURITY : fix typo 2020-08-18 09:18:37 +02:00
Stephen Abello
9516e7f023 N°2847 Add panel component 2020-08-17 17:02:57 +02:00
Stephen Abello
223b063c60 N°2847 Fix button component comment and trailing space 2020-08-17 17:02:57 +02:00
Molkobain
fabc92eb89 N°2847 - Activity panel: Fix glitch on closed case log entry 2020-08-17 10:00:44 +02:00
Pierre Goiffon
71848cb56b Merge branch 'support/2.7' into develop
# Conflicts:
#	.jenkins/bin/tests/phpunit.sh
#	Jenkinsfile
#	core/config.class.inc.php
#	core/dbobjectsearch.class.php
#	core/ormlinkset.class.inc.php
#	datamodels/2.x/combodo-db-tools/dbtools.php
#	dictionaries/nl.dictionary.itop.ui.php
2020-08-17 09:36:43 +02:00
Molkobain
d011c4e8f5 N°2847 - Global search: Fix past queries not displaying 2020-08-17 09:31:10 +02:00
Molkobain
46909c210c N°2847 - Activity panel: Display only necessary toolbar actions in the "Activity" tab 2020-08-17 08:38:44 +02:00
odain-cbd
71b725420a Merge branch 'develop' into feature/fast-theme-compilation2 2020-08-17 00:18:15 +02:00
rquetiez
fcd4ad6872 N°3052 add the core/application XML files and rewrite the test for two benefits:
a - the latest XML version is currently not correlated with the the version of iTop (though it seems to be)
b - see the converted XML... that could be saved to fix the report
2020-08-14 19:57:38 +02:00
Molkobain
e3f1deda00 N°2847 - Activity panel: Fix case log entries highlight strip when closed 2020-08-14 18:12:35 +02:00
odain
a538e3c1a2 N°2996 Remove iTop version from css variables
- $version does not exit anymore in css-variables.css. now its value is computed during setup and equals setup timestamp instead.
    - use precompiled files (declared in datamodels XML files) to check if theme compilation is required or not.
    - referenced images in scss files are included in precompiled file signatures just like scss files md5sum.
    - images declared in scss files with v=$version are reloaded automatically on browser side after each theme compilation (see xxx.png?v=timestamp)
    - precompiled files are replaced if theme compilation occurred. this will avoid same time consuming operation at next setup.
    - code cleanup: arrays / variables renamed
2020-08-14 17:03:16 +02:00
Stephen Abello
ac91c4d970 N°2847 Fix default action type value for Button constructor 2020-08-14 17:02:35 +02:00
Stephen Abello
3ffe3dd4bd N°2847 Add Button component 2020-08-14 16:26:16 +02:00
Stephen Abello
f70065b2fc N°2847 Add a border radius variable to scss 2020-08-14 16:26:16 +02:00
Stephen Abello
4b98f2ac25 N°2847 Add secondary color variables 2020-08-14 16:26:16 +02:00
Molkobain
398621693e N°2847 - Activity panel: Several improvements
- Improve display of code snippets
- Improve code structure for loops on case log colors
2020-08-14 12:18:47 +02:00
Molkobain
b9d7967c0e N°2847 - Activity panel: Add highlight color on case log entries 2020-08-14 10:41:51 +02:00
Molkobain
0c5c2eccad N°2847 - Navigation menu: Minor adjustments
- Adjust some sizes and colors on the navigation menu to match mockups
- Fix menu groups displaying over the user picture when menu is expanded
- Partially fix notification menu positioning
- Extract some sizes into variables for the popover menu
2020-08-13 23:34:18 +02:00
rquetiez
a1f5d8041e N°3251 (see also PR#152) - CSV data synchro allows "<NULL>" to be interpreted as "Let the attribute unchanged for the current row" 2020-08-13 21:49:30 +02:00
rquetiez
d679deba02 refactor CSV Parser unit tests from the old home-made framework into PHP Unit, and add new test to check that <NULL> is parsed as a real null value 2020-08-13 21:12:50 +02:00
Molkobain
df20d10afa N°2847 - Add activity panel to object details (and some variables renaming) 2020-08-13 18:57:07 +02:00
Molkobain
f2725c5a5c Add $bAllowDefaultPicture parameter to UserRights::GetContactPictureAbsUrl() to return null instead of the default picture 2020-08-13 17:46:48 +02:00
Pierre Goiffon
91c6916d86 🐛 Fix setup homepage error with PHP < 7.1.0
Was due to const visibility added in ormLinkSet class in commit b58a084d

This isn't supported before PHP 7.1.0, see https://www.php.net/manual/fr/language.oop5.constants.php :
> As of PHP 7.1.0 visibility modifiers are allowed for class constants.
2020-08-13 15:29:27 +02:00
Molkobain
f90a5b77ad Fix UserRights::GetContactPictureAbsUrl() when using optional $sLogin parameter 2020-08-13 14:47:07 +02:00
Molkobain
703161157b Fix UserRights::GetUserId() when using optional $sLogin parameter 2020-08-13 14:08:54 +02:00
Molkobain
55c896bcd3 Internal - Add parameter $aDesiredAttTypes to the MetaModel::GetAttributesList() to filter the result on some attribute types only 2020-08-13 14:08:54 +02:00
Molkobain
ef844c396e N°2847 - Add UIBlock::GetBlockCode() method to get the code within a TWIG no matter the object class (easier than calling the right class constant) 2020-08-13 14:08:54 +02:00
Molkobain
dfdeb21023 PHPDoc & code cleanup 2020-08-13 14:08:53 +02:00
Stephen Abello
47c0f946b3 N°2847 Better handle of weird shaped images for square logo and full logo 2020-08-12 15:07:33 +02:00
acognet
f90105c107 N°2534 - dashboard: bug with autorefresh that deactivates filtering on organizations 2020-08-12 14:18:05 +02:00
Stephen Abello
b0973263e3 N°2847 Add background color to user menu odd sections 2020-08-12 11:36:57 +02:00
Stephen Abello
4be0d8895d N°2847 Refactor newrooms with variables 2020-08-12 11:04:24 +02:00
Stephen Abello
6436e8cef4 N°2847 Add an indication on newsroom toggler when there is new messages 2020-08-12 09:30:19 +02:00
Stephen Abello
f8b6b37288 N°2847 Recolor svg illustrations with itop's primary color 2020-08-10 16:56:00 +02:00
Stephen Abello
8996117929 Allow additional paths for Twig Helper and add images/ to iTop webpage and block renderer paths 2020-08-10 16:56:00 +02:00
Molkobain
9be4743cf6 Internal - UserRights: Rename 1 var. and 1 method to something more meaningful 2020-08-10 14:49:19 +02:00
Stephen Abello
4195cd011c N°2847 * Fix wrong image name for default placeholder
* Close popupmenu when clicking on toggler a second time
* Fix an error in newsroom menu
2020-08-10 14:16:43 +02:00
Stephen Abello
440cda87b1 N°2847 Add full logo to expanded navigation menu 2020-08-10 12:14:09 +02:00
Molkobain
efb3f7f9cd Internal - Rework on User and UserRights classes:
- PHPDoc
- Add User::GetInitials() method
- Fix several calls to UserRights::FindUser()
- Add UserRights::GetUserInitials()
- Change usage of DBObject->Get('friendlyname') to DBObject->GetRawName()
2020-08-10 11:52:06 +02:00
odain
e5487edbfb Merge remote-tracking branch 'remotes/origin/feature/perf-serialization' into develop 2020-08-10 11:10:44 +02:00
odain-cbd
3cae585f78 Merge pull request #154 from Combodo/revert-136-feature/fast-theme-compilation
Revert "Faster compilation of themes"
2020-08-07 16:20:38 +02:00
odain-cbd
7b8c390a80 Revert "Faster compilation of themes" 2020-08-07 16:20:12 +02:00
odain-cbd
c3b9c6963e Merge pull request #136 from Combodo/feature/fast-theme-compilation
Faster compilation of themes
2020-08-07 16:13:09 +02:00
odain-cbd
e907c7825a Merge branch 'develop' into feature/fast-theme-compilation 2020-08-07 16:12:47 +02:00
Stephen Abello
ea7924663a N°2847 Add a user placeholder image selector in user preferences (poc, need to cleanup) 2020-08-07 15:42:10 +02:00
odain
a35b2d83b7 Cancel functionnal changes to make sure they are ok in next release (develop/2.8) first 2020-08-07 15:17:24 +02:00
odain
8902d6e532 CI migration/automation + new test to ease iTop release management
- new Jenkinsfile and .jenkins removal to launch phpunit/behat tests
triggered on both iTop build and push.
 - N°3053 - Check XML conversion methods
 - N°3057 - New build recipe
 - N°3059 - Automatically set the documentation URLs
 - N°3052 - Check community modules XML version against latest version
 - N°3054 - Check community modules version against major version
 - N°3062 - setup.css file integrity test
 - N°3060 - Check consistency between the list of modules and installation.xml
 - Add exclusion group for CI
 - N°3061 - Automatically check the installation.xml consistency
2020-08-07 14:48:51 +02:00
Stephen Abello
93871308d1 N°2847 Update newsroom templates with new variable in twig files 2020-08-07 09:25:33 +02:00
Molkobain
f20310b437 N°2847 - Change calls to methods in TWIG to something more meaningful to avoid consufion between methods, properties and array keys 2020-08-06 17:47:15 +02:00
Molkobain
af87a04d13 N°2847 - Add page content layout feature 2020-08-06 17:47:15 +02:00
Molkobain
521536526e N°2847 - GlobalSearch: Disable browser auto completion and fix past queries icon URL 2020-08-06 17:47:14 +02:00
Molkobain
1e3771dffa N°2847 - Fix content parameters (eg. aPage) not passed in subblocks 2020-08-06 17:47:14 +02:00
Molkobain
6666f3d033 N°2847 - Switch "AdminTools" and "ConfigTools" menu groups icon 2020-08-06 17:47:14 +02:00
Molkobain
470b566c1a N°2847 - Rework iTopWebPage layout (WIP Part X)
- iTopWebPage: Remove AddToMenu() method
- SCSS: Fix content areas height to occupy max. available space
2020-08-06 17:47:14 +02:00
Molkobain
c81f521d2e N°2847 - Uncomment some parts of the old CSS file to improve rendering while developing 2020-08-06 17:47:14 +02:00
Molkobain
3ed73ac020 N°2847 - Fix UI block var name being different across the different templates (painful when working with derivated block classes) 2020-08-06 17:47:14 +02:00
Molkobain
1604e233f9 PHPDoc & code cleanup 2020-08-06 17:47:14 +02:00
Pierre Goiffon
46f8fadac0 Merge remote-tracking branch 'origin/develop' into feature/backoffice-full-moon-design 2020-08-06 17:37:56 +02:00
Pierre Goiffon
001e937568 N°2330 / N°3009 update PHP version in composer.json 2020-08-06 17:36:23 +02:00
odain
94ffcf4207 💚 use proper namespace 2020-08-06 15:39:19 +02:00
Stephen Abello
7b139ea893 N°2847 Typo in dict + a bit of css for newroom menu toggler in user menu 2020-08-06 15:21:09 +02:00
odain
76274557a3 N°3061 - :green_hear fix test 2020-08-06 14:52:48 +02:00
Stephen Abello
1231528ab5 N°2847 Newsroom menu : Delete debug messages and update a bit of scss 2020-08-06 14:41:35 +02:00
Stephen Abello
a5216de232 N°2847 First iteration for newsroom menu:
* Kept old js widget but refactored/tweak'd it with some of our new conventions
* Added a newsroom menu component extending popupmenu
* Working as in 2.7
Still todo :
* Add variables for scss file
* Use wiget variables for most of js widget
* Correctly place the popup (absolute with <> containers ? poppers.js ? )
* Intialize toggler red bubble when new messages are in
* Replace hardcoded text in usermenu with correct dict entry updated with the nb of new message
* Only allow to open the popup when ajax calls are done
2020-08-06 14:36:07 +02:00
odain
87b027e3bf N°3054/3052 - rename exclusion group for CI to skipPostBuild 2020-08-06 11:02:57 +02:00
odain
b0609e86d1 N°3060 - filter modules autoinstalled in checklist test 2020-08-06 11:00:53 +02:00
odain
b9145ca996 N°3060 - filter modules autoinstalled in checklist test 2020-08-06 10:51:39 +02:00
bruno-ds
4e0c6e5614 move tests from
- within checklist test suite
 - to standard test suite + excluded from the checklist
2020-08-06 09:55:06 +02:00
bruno-ds
da34383363 fix checklist unit tests 2020-08-06 08:57:41 +02:00
odain
b628bb5e80 add a comment 2020-08-05 15:38:43 +02:00
odain
4c294cb09c N°3060 - :green_heart fix text name collision 2020-08-05 15:38:28 +02:00
odain
dc5ee13ed1 N°3060 - Check consistency between the list of modules and installation.xml 2020-08-05 15:25:15 +02:00
odain
8707ae6024 💚 fix StatusTest.php 2020-08-05 14:53:57 +02:00
odain
ec0f726c26 💚 fix tests 2020-08-05 14:39:00 +02:00
odain
66d6db5174 add detailed info inside StatusTest.php 2020-08-05 14:25:59 +02:00
odain
2493fd57b2 add detailed info inside StatusTest.php 2020-08-05 14:19:39 +02:00
odain
e3a653010a adapt StatusTests.php to work on both iTop repository and packaged zip 2020-08-05 12:03:35 +02:00
odain
c98c364714 adapt UtilsTests.php to work on both iTop repository and packaged zip 2020-08-05 11:38:27 +02:00
odain
a545bb8729 detailed unit test failure messages 2020-08-05 11:12:28 +02:00
Pierre Goiffon
c9dab08324 💚 Fix DBSearchTest::testSelectInWithVariableExpressions 2020-08-04 15:36:53 +02:00
Stephen Abello
18b653f641 N°2847 Handle no contact linked to user on usr menu icon hover 2020-08-04 14:44:42 +02:00
odain
56e2f63385 enhance phpunit test messages in case of failure 2020-08-04 14:13:41 +02:00
bruno-ds
4f04031183 .make builder robustness 2020-08-04 13:56:53 +02:00
bruno-ds
cdc3bbcb0c unitTest: better error message 2020-08-04 13:56:27 +02:00
Stephen Abello
2db7611368 N°2847 Fix wrong variable use in popover menu scss 2020-08-04 13:54:18 +02:00
Stephen Abello
f4f846496b N°2847 Add Separator item to popover menu items 2020-08-04 13:49:51 +02:00
Molkobain
d6ab310d24 N°3233 - Fix unit test and autoloader due to folders renaming in /sources 2020-08-04 13:26:58 +02:00
Molkobain
bc4b36fda6 N°3233 - Remove "display_template" from object details page 2020-08-04 13:26:57 +02:00
Molkobain
c61a66ca69 N°3233 - Remove "display_template" from datamodel classes 2020-08-04 13:26:57 +02:00
Molkobain
bd0480b5c5 N°3233 - Remove "display_template" from the metamodel and compiler 2020-08-04 13:26:57 +02:00
Molkobain
c93c53488d N°3185 - Rename tag to "main_logo_compact" and complete XML migration methods 2020-08-04 13:26:57 +02:00
Molkobain
19b5290e80 N°3231 - Allow browser access to static resources files in the /lib folder 2020-08-04 13:26:57 +02:00
Molkobain
a15235d522 N°2847 - Global Search: Fix class images URL, rename internal variable 2020-08-04 13:26:57 +02:00
Stephen Abello
c7e95676d2 N°2847 Fix first and last section border radius for popover menu 2020-08-04 12:13:39 +02:00
Stephen Abello
4aeb3ed448 N°2847 Cleanup scss with helpers 2020-08-04 12:00:03 +02:00
Stephen Abello
4e7b68aa9a N°2847 Open user menu when clicking user picture or user welcome message 2020-08-04 11:53:44 +02:00
Stephen Abello
e22c36c503 N°2847 Add tooltip to user menu picture and rework these dictionary entries 2020-08-04 10:02:56 +02:00
Stephen Abello
7264defc35 N°2847 Add padding to user menu message caret 2020-08-04 10:02:13 +02:00
Pierre Goiffon
07bd6b8539 N°3219 cron : reset CMDBChange for each process 2020-08-04 09:44:20 +02:00
Stephen Abello
baa2fb2906 Rename a NavigationMenu method (see ed1f3aa950 (r41148365)) 2020-08-04 09:27:55 +02:00
Stephen Abello
1d954b80a8 Rename a dictionnary entry (see ed1f3aa950 (r41148310)) 2020-08-04 09:27:12 +02:00
Stephen Abello
1d13181135 Split a scss variable in two (see ed1f3aa950 (r41148286)) 2020-08-04 09:26:12 +02:00
Stephen Abello
ed1f3aa950 N°2847 Add bottom menu part :
* Notifications icon
* User icon
* Extended user data
Still todo:
* Initialize Newsroom and feed infos to template
* Initialize User popover menu
2020-08-03 17:07:21 +02:00
Molkobain
e2e62eca5e N°2847 - Rework iTopWebPage layout (WIP Part IX)
- Refactor some CSS classes to something more semantic and cross app (.ibo-<COMPONENT>--is-<STATE> => .ibo-<STATE>)
- AjaxWebPage: Deprecated AddToMenu method
2020-08-03 11:27:06 +02:00
Stephen Abello
a85c7e9f8f Add Popover menu and subitems such as URL and JS items. 2020-08-03 11:16:54 +02:00
Molkobain
ac2280df50 N°2847 - Breadcrumbs: Rollback try to hide first elements when too many elements 2020-08-03 09:26:02 +02:00
Molkobain
61d611c136 N°2847 - Rework iTopWebPage layout (WIP Part VIII)
- Navigation menu: Change scrollbar color to something more visible
- Navigation menu: Close drawer when filter focused and "Escape" key hit
- Top bar: Fix element's ID in its standard delivery
- Top bar: Fix drawers opening under the top bar but above the main content
- iTopWebPage: Add AddUiBlock() method to easily add a layout/component in the page
- iTopWebPage: Fix Header/Footer parts (formerly North/South Panels) and Banner part
- WebPage: Handle duplicate stylesheets (like it was already doing for JS scripts)
2020-08-02 21:35:33 +02:00
Molkobain
f59de920c1 PHPDoc & code cleanup 2020-08-02 21:18:23 +02:00
Molkobain
7b13078bf9 N°2847 - Rework iTopWebPage layout (WIP Part VII)
- Breadcrumbs: Hide first elements when not enough space to show them all
- iTopWebPage: Temporary fix for modals in order to enable // dev. on the linkedsets refactoring
2020-07-30 17:57:36 +02:00
Molkobain
3406ebf1fd Merge remote-tracking branch 'origin/develop' into feature/backoffice-full-moon-design 2020-07-30 15:23:06 +02:00
Molkobain
1f0211b45a N°2847 - Rework iTopWebPage layout (WIP Part VI)
- iTopWebPage: Restore "open search" feature
- iTopWebPage: Change all resources URL to absolute in order to benefit from the "duplicate removal" benefits
- iTopWebPage: Remove obsolete method IsMenuPaneVisible()
- Config: Add new parameters quick_create.enabled / global_search.enabled / breadcrumb.enabled
- utils: Add new GetAppRevisionNumber() method
- Introduce iUIBlock interface for UI layouts, components, ...
- Introduce BlockRenderer to properly render blocks
- Add "render_block" function to TwigHelper to render blocks directly from TWIG
- Refactor layouts and components into proper block classes to fit the new architecture
2020-07-30 15:22:17 +02:00
Molkobain
b207ae1bb3 PHPDoc & code cleanup 2020-07-30 15:22:16 +02:00
Molkobain
e788a44382 TwigHelper: Add file type constants for an easier use by the service consumers 2020-07-30 15:22:16 +02:00
Molkobain
71dbccd034 N°3216 - Refactor form files to be part of the autoloader 2020-07-30 15:22:16 +02:00
Molkobain
3df3619b7c N°3215 - Refactor renderer files to be part of the autoloader 2020-07-30 15:22:16 +02:00
Molkobain
a969d352ec N°2847 - Rework iTopWebPage layout (WIP Part V)
- iTopWebPage: Restore "open search" feature
2020-07-30 15:22:16 +02:00
Molkobain
59b6dd735e Add helpers to retrieve some of the current contact data in UserRights 2020-07-30 15:22:16 +02:00
Molkobain
1766d42350 Internal: Refactor some harcoded attribute codes into constants in UserRights 2020-07-30 15:22:16 +02:00
Molkobain
3b6654588a N°2847 - Change images paths and names to something more functional 2020-07-30 15:22:16 +02:00
Pierre Goiffon
b58a084de5 N°2334 n:n relations : same fields displayed in EDIT and VIEW modes
Before we were only showing lnk fields in VIEW, and lnk+remote in EDIT (excluding some fields, see below).
Now by default (as this is customizable in VIEW mode) we have the same !

Rules to choose fields are moved from \UILinksWidget::__construct to :
  * \MetaModel::GetZListAttDefsFilteredForIndirectRemoteClass
  * \MetaModel::GetZListAttDefsFilteredForIndirectLinkClass
2020-07-30 11:40:54 +02:00
Pierre Goiffon
5d686d733f 🔧 Disable useless inspections 2020-07-30 11:33:57 +02:00
Pierre Goiffon
1148449bb7 📝 Add missing @since on \DBSearch::GetFirstResult 2020-07-29 17:21:15 +02:00
Pierre Goiffon
ea92973e9b 📝 PHPDoc for DisplayBlock 2020-07-29 12:23:15 +02:00
Pierre Goiffon
14505fc5e6 🔧 Change SlowArrayOperationsInLoopInspection from error to warning 2020-07-29 12:22:52 +02:00
jbostoen
11d418fd49 🌐 Dutch translations: fix use of ITOP_APPLICATION, ITOP_APPLICATION_SHORT
* Fix incorrect ITOP_APPLICATION, ITOP_APPLICATION_SHORT
2020-07-28 16:26:16 +02:00
Pierre Goiffon
90b60f90ae Update files version to 2.8.0 2020-07-28 11:40:16 +02:00
Pierre Goiffon
a26c2cbcdb 📝 Add phpdoc on DBObjectSearch method 2020-07-28 11:35:30 +02:00
Pierre Goiffon
cc708f6ccc 🙈 Add temp ignore rules 2020-07-28 11:03:59 +02:00
Molkobain
d4694b271f N°2847 - Rework iTopWebPage layout (WIP Part IV)
- iTopWebPage: Clean up some commented sections
- iTopWebPage: Marked some new methods as @internal
- iTopWebPage: Restore page content to allow // developments
- Quick create: Add quick object creation box to the top bar
- Global search: Improve cinematic with other widgets
- Components / Layouts: Move JS parts to iTopWebPage, will be put in dedicated PHP helpers later
2020-07-27 15:09:35 +02:00
Molkobain
d56f6e684a N°2847 - Add Bulma SCSS lib. 2020-07-27 15:09:35 +02:00
Molkobain
8999108fe3 Clean unwanted committed changes 2020-07-27 15:09:35 +02:00
Molkobain
929eccc88d Protect directory listing of /mode_modules 2020-07-27 15:09:34 +02:00
Molkobain
75812ca151 N°2847 - Rework iTopWebPage layout (WIP Part III)
- iTopWebPage: Fix top bar actions drawers opening under the advanced search widget
2020-07-27 15:09:34 +02:00
Molkobain
ec238569c4 Add method to get allowed classes for specific action (read/modify/...) and categories (bizmodel, ...) 2020-07-27 15:09:34 +02:00
Molkobain
b6117b157c PHPDoc & code cleanup 2020-07-27 15:09:34 +02:00
Molkobain
b3dcfea8dc N°3207 - Global search: Introduce new widget 2020-07-27 15:09:34 +02:00
Molkobain
00dc1d3f3b PHPDoc & code cleanup 2020-07-27 15:09:34 +02:00
Molkobain
da5d55a542 Fix appUserPreferences type hinting as it accepts more than just strings 2020-07-27 15:09:34 +02:00
Molkobain
6a3bbd8d49 N°2847 - SCSS: Refactor some variables names and some patterns into helpers 2020-07-27 15:09:34 +02:00
Molkobain
46deb9590d N°3199 - Add tippyjs / popper.js JS libs (introducing NPM dependencies management system for JS/CSS libs) 2020-07-27 15:09:34 +02:00
Molkobain
20ed4fe2d1 N°2847 - Theme: Add elevations as SCSS and CSS variables 2020-07-27 15:09:33 +02:00
Molkobain
87d7693be5 N°2847 - Rework iTopWebPage layout (WIP Part III)
- iTopWebPage: Extract processing in dedicated functions
- iTopWebPage: Add tooltips base feature
- iTopWebPage: Fix JS dictionaries
- iTopWebPage: Extract inline JS to dedicated file
- Top bar: Visual improvements
- Nav. menu: Visual improvements
- Nav. menu: Tooltip improvement
- Nav. menu: Toggle state preference saved
- Nav. menu: Add menus filter feature
- Breadcrumbs: Handle elements overflow
2020-07-27 15:09:33 +02:00
Molkobain
fa153d8504 N°3185 - Datamodel: Add square logo in branding 2020-07-27 15:09:33 +02:00
Molkobain
5d3009646a N°3182 - Datamodel: Add icon to menu groups 2020-07-27 15:09:33 +02:00
Molkobain
ec70d3546d PHPDoc & code cleanup 2020-07-27 15:09:33 +02:00
Molkobain
10a14a3844 N°3182 - Add support for MenuGroup CSS icon in the XML datamodel
- Introduce itop_design v1.8
- Default CSS classes are 'fas fa-ellipsis-v' from FontAwesome
- New tags <style><decoration_classes>xxx yyy</decoration_classes></style> under the <menu xsi:type="MenuGroup"> tag
2020-07-27 15:09:33 +02:00
Molkobain
0516862632 N°2847 - Rework of iTopWebPage: Preliminary work on the page content 2020-07-27 15:09:33 +02:00
Molkobain
ad379d3ef4 N°2847 - Rollback fix on pages <base> URL tag (to much consequences)
Fixing the base URL tag on WebPage and derivated classes would require to migrate all extensions which use the add_linked_script / add_linked_stylesheet functions with a relative URL, which is almost all extensions. So the benefit isn't worth the workload.

Note: We could have migrate extensions by replacing "../images|js|css/xxx.yyy" with utils::GetAbsoluteUrlAppRoot()."images|js|css/xxx.yyy" to make them compatible with iTop 2.8 and previous versions. But as said before, much work.
2020-07-27 15:09:33 +02:00
Molkobain
8efd8008fc N°2847 - Rework of the global iTopWebPage layout (Part II)
- Optimize TWIG templates includes (don't pass context to autonomous components)
- Preliminary work of the top bar and breadcrumbs features
- Removal of images dedicated to the breadcrumbs feature
2020-07-27 15:09:33 +02:00
Molkobain
6f9565d979 Remove duplicated entries from .gitignore 2020-07-27 15:09:32 +02:00
Molkobain
6f3ec99501 N°2847 - Update UI components dictionaries 2020-07-27 15:09:32 +02:00
Molkobain
ab681b0954 N°2847 - Rework of the global iTopWebPage layout (Part I)
- Rework of the iTopWebPage class
- Use of TWIG templates
- Preliminary work of the navigation menu
2020-07-27 15:09:32 +02:00
Molkobain
c9b80074f4 Add helper to know if we currently are in "debug" mode
Can be used to enable more features / debugging tools throughout the application.
2020-07-27 15:09:32 +02:00
Molkobain
f5df442e8b N°2847 - Improve SCSS files structure
- Refactor some mixins into helpers
- CSS3 variables set via SCSS variables are now using "interpolation" (#{$my-var} instead of just $my-var) to be compatible with more SCSS compiler
- Overloading some Bulma variables such as font-family
2020-07-27 15:09:32 +02:00
Molkobain
fab58d503b TwigBase: Change "add_itop_version" TWIG function to use cache buster timestamp 2020-07-27 15:09:32 +02:00
Molkobain
1a3411e99d TwigBase: Add 2 TWIG functions (get_absolute_url_app_root / get_absolute_url_modules_root) 2020-07-27 15:09:32 +02:00
Molkobain
ddcd6d4e91 N°2847 - Remove POC page 2020-07-27 15:09:32 +02:00
Molkobain
9eb826bb0b Add support for dictionaries in sub-folders of /dictionaries 2020-07-27 15:09:32 +02:00
Molkobain
a88df33167 Add SASS converter cache to .gitignore 2020-07-27 15:09:32 +02:00
Molkobain
ec48b397ad Code cleanup & PHPDoc 2020-07-27 15:09:31 +02:00
Molkobain
f8af900c73 N°2847 - WIP: Sync. commit 2020-07-27 15:09:31 +02:00
Molkobain
7d4455baf4 N°2847 - Start rework of the CSS/JS/TWIG files structure 2020-07-27 15:09:31 +02:00
Molkobain
e37c620d2d PHPDoc & code cleanup 2020-07-24 14:11:30 +02:00
Molkobain
dd4ef8f91a N°2870 - Portal: Fix "Notice: Undefined index: UI:PropertiesTab" on object form 2020-07-24 14:08:33 +02:00
bruno-ds
5edcc91182 CI: release checklist test suite config file 2020-07-24 09:10:04 +02:00
bruno-ds
e2b5992e80 n°3062 - css generator on build 2020-07-24 09:08:45 +02:00
bruno-ds
a2af061a34 n°3057 - bugfix & output improvement 2020-07-24 09:07:43 +02:00
Eric
ace676dc24 N°2585 - Fix alias problem in portal scopes
The re-aliasing map structure now allows multiple mapping for the same alias (used for the translations of UNIONS)
2020-07-23 16:41:57 +02:00
Eric
8122270476 N°3176 - OQL: Fix malformed UNION queries in portal scopes
Fix regression in Unit tests
2020-07-22 17:30:38 +02:00
bruno DA SILVA
a53ce32e54 N°3062 - setup.css file integrity test
this is for the task : "Generate setup.css at build time"
2020-07-22 17:09:51 +02:00
Eric
1f66d53ab4 N°3176 - OQL: Fix malformed UNION queries in portal scopes
Fixed AddCondition_ReferencedBy() for unions (regression introduced by N°2970)
2020-07-22 16:09:08 +02:00
Eric
dfaeca43e4 N°3148 - OQL request malformed
Fix variables in ListExpression
2020-07-22 10:06:11 +02:00
odain
08414296b6 tmp work: save timestamp + few fixes 2020-07-21 23:22:50 +02:00
Eric
5b04143711 N°3111 - Fix Portal export 2020-07-21 16:39:55 +02:00
Eric
bd14096d43 N°3150 - Wrong count for archived objects 2020-07-21 14:21:55 +02:00
Eric
3b20be05cb 3189 - DBTools enhancements
* Add CLI command bin/report.php to generate report offline
* Keep the latest report in log/dbtools-report.log in order to visualize it with "Log management" menu
2020-07-21 14:08:36 +02:00
Pierre Goiffon
06ee1f3a15 N°2284 add @since in old autocomplete widget file 2020-07-20 10:38:55 +02:00
Eric
27ed1f3307 N°2957 - Fix required files and generate files into src/Model 2020-07-20 09:58:51 +02:00
Thomas Casteleyn
4f72336301 Suggest correct filename on download 2020-07-17 13:17:18 +02:00
Thomas Casteleyn
868c157ae4 Change lifecycle generation to SVG instead of PNG 2020-07-17 13:17:18 +02:00
Thomas Casteleyn
c2b72c7688 More memory efficient image pass through 2020-07-17 13:17:18 +02:00
odain
307713d326 N°2996 - Remove iTop version from css-variable.scss
Include images in precompilation check
2020-07-16 18:41:55 +02:00
odain
2d8b888a18 N°2982 - speedup themes/scss compilation during setup 2020-07-16 18:41:01 +02:00
Denis Flaven
6b2b56cf72 Faster compilation of themes
- Ability to provided precompiled themes in the datamodel
- Check that a precompiled theme is still up-to-date based on a signature
2020-07-16 18:33:13 +02:00
Eric
fdec608c3e N°3174 - Remove stack trace from MySQLException 2020-07-16 18:09:44 +02:00
Eric
72cb3de50d N°3173 - Installation issue with PHP 7.4 (fix php notice) 2020-07-16 17:23:21 +02:00
bruno DA SILVA
52baed7960 3054 - whoop fix duplicated class name 2020-07-16 17:20:25 +02:00
bruno DA SILVA
7ae895d701 3054 - Check community modules version against major version 2020-07-16 16:56:49 +02:00
bruno DA SILVA
120452d2ee 3052 - follow 919a7a8ef5 folder renaming 2020-07-16 16:47:40 +02:00
bruno DA SILVA
25791a1d18 3052 - Check community modules XML version against latest version 2020-07-16 16:45:20 +02:00
odain
919a7a8ef5 PS-4 folder renaming 2020-07-16 16:43:43 +02:00
odain
da0e0a99c7 revert to no behat tests 2020-07-16 16:16:17 +02:00
bruno DA SILVA
82ba53d40b 3059 - Automatically set the documentation URLs 2020-07-16 16:11:46 +02:00
odain
7ed1feff3e test phpunit + behat 2020-07-16 15:47:20 +02:00
odain
6bdfdad09f test phpunit + behat 2020-07-16 15:44:47 +02:00
odain
8c3417adeb work locally 2020-07-16 15:38:23 +02:00
Eric
c03d32b423 N°3180 - Allow HTML in dictionary for login screen ('UI:Login:About') 2020-07-16 15:28:49 +02:00
Eric
e4ab543aff Disable twig cache for developers (instead of having config flag) 2020-07-16 15:07:03 +02:00
Eric
11ef705816 N°2969 - change dictionaries folder from dictionary to dictionaries 2020-07-16 14:52:03 +02:00
odain
b3b440362a N°3057 - New build recipe: start only 2020-07-16 14:19:38 +02:00
odain
ee9e747b1c stop working/debugging locally 2020-07-16 09:46:31 +02:00
odain
1baf8a6424 use all phpunit as usual 2020-07-16 09:35:10 +02:00
odain
7a89bfc108 fix ci: force authent-local conf to be able to create admin in a test 2020-07-16 09:08:31 +02:00
odain
68c7b9a0e8 fix test that breaks config-itop.php 2020-07-15 19:56:25 +02:00
odain
9e3b1bfc78 use less tests + try sth 2020-07-15 19:47:35 +02:00
odain
01f9a6f758 fix test dependency: require admin user 2020-07-15 17:54:24 +02:00
odain
8e028753b7 without use config-itop.php inside backup 2020-07-15 17:38:18 +02:00
odain
343d626025 without backup again 2020-07-15 16:55:47 +02:00
odain
6078f39730 fix config_itop.php in backup 2020-07-15 16:51:47 +02:00
odain
78dc57bdb5 remove dump from backup 2020-07-15 16:40:14 +02:00
odain
94a468efc8 again 2020-07-15 16:34:42 +02:00
odain
864572c02a fix setup in freshinstall mode 2020-07-15 16:06:07 +02:00
odain
d353d56e7b add exception in test failed 2020-07-15 11:13:48 +02:00
odain
a3e6600195 try with a backup file 2020-07-15 11:04:16 +02:00
odain
51ab8706e8 fix setup file 2020-07-15 10:51:28 +02:00
odain
24f832de78 fix xml test file 2020-07-15 09:40:13 +02:00
Eric
7e970ee93c N°3015 - fix notice 2020-07-15 09:38:33 +02:00
Eric
e7fa9eda65 Use configuration for enabling twig cache 2020-07-15 09:33:54 +02:00
odain
e295226bd6 work locally 2020-07-15 08:08:11 +02:00
odain
78d23261ca use itop_infra ci 2020-07-13 17:02:32 +02:00
Eric
edefa4da4f N°2330 - set the php minimum version to 7.2 2020-07-13 15:35:18 +02:00
odain
4ba76f95b2 N°3053 - Check XML conversion methods 2020-07-13 10:56:45 +02:00
Eric
6320879fe1 Add a cleanup file to the database integrity report.
Use it for fast database cleanup (removal of all broken entries) when you don't want to try recovering inconsistent records.
Note that you may need multiple report to eliminate all the inconsistencies.
2020-07-10 17:57:13 +02:00
Romain Quetiez
acf0548c4c N°3171 - Friendly name and obsolescence flag not refreshed (#151)
- Compute any type of expression on server side
- Recompute friendly name and obsolescence flag on server side (DBOBject)
- Bonus : compute dependency for external keys
2020-07-10 17:26:37 +02:00
Eric
b1fa429234 N°2957 - Better check of the class parameter in requests 2020-07-10 14:41:38 +02:00
Eric
78516f437a N°2957 - Compile classes in separated files 2020-07-10 14:41:08 +02:00
Denis Flaven
ea75092bb3 N°3166 - fix for a crash in expressioncache
iTop was crashing if the expression/format for the name of a class contained a quote (')
2020-07-10 11:27:43 +02:00
acognet
df4dfe4803 N°2284 - Replace JQuery Autocompleter plugin by JQuery UI Autocomplete widget
N°2390 - Auto-complete - Relevant results in first
2020-07-09 09:14:44 +02:00
acognet
fddf30e6c3 N°2956 - Upgrade jQuery to v3.5.1 2020-07-09 09:07:11 +02:00
Eric
b718e26c7f N°2969 - Add support for dictionaries folder in modules 2020-07-08 15:21:07 +02:00
Eric
e564f71c14 N°2986 - Reintegrate application menus from "welcome itil" into application 2020-07-08 11:49:52 +02:00
Eric
4f3931e828 N°2370 - Remove MySQL views in iTop, moved to "combodo-views" extension 2020-07-08 10:33:15 +02:00
Eric
d73fdce3c5 Fix legacy regression 2020-07-07 13:58:36 +02:00
acognet
0787c622d4 N°2738 - Remove unused dict keys 2020-07-06 13:43:46 +02:00
annProg
4c11eb099b fix: Typology translation for zh_cn 2020-07-04 22:52:38 +02:00
acognet
9628a1d028 N°2284 - Replace JQuery Autocompleter plugin by JQuery UI Autocomplete widget and start of bug 2390 - Auto-complete - Relevant results in first 2020-07-02 11:46:51 +02:00
acognet
5585385d08 N°2393 - API : Font Awesome remove v4 compatibility 2020-07-02 11:03:05 +02:00
acognet
98870b06e3 2548 - API : remove \DBObject::GetRelationQueries overrides in default datamodel 2020-07-01 16:28:20 +02:00
bruno DA SILVA
46d91322c1 n°2556 - fix errors in the merge of support/2.7 into develop
The cherry picks resulted in an out of order apply of the commits, the result was that the wrong code was keeped
2020-07-01 15:41:46 +02:00
acognet
ca28f8f3c4 2393 - API : Font Awesome remove v4 compatibility 2020-06-30 16:28:15 +02:00
acognet
0aaa55b35b 3009 - PHP Minimum version raised to 7.1 2020-06-30 10:10:00 +02:00
acognet
e9a1167da6 N°2363 - API : deprecate old linkedset update pattern 2020-06-30 09:02:42 +02:00
acognet
a67fce66fc N°2999 - Optimize OQL 2020-06-26 16:42:03 +02:00
acognet
491d1d7d53 N°API : remove CMDBSource::GetNextInsertId 2020-06-26 16:20:15 +02:00
acognet
54b48dc908 N°2372 - API : remove \MetaModel::EnumLinksClasses and \MetaModel::EnumLinkingClasses 2020-06-26 16:17:04 +02:00
acognet
dadeab58eb N°852 - Cleanup: remove deprecated impact analysis algorithm and clean up old broken test 2020-06-26 15:03:10 +02:00
acognet
0ecdc6620b N°852 - Cleanup: remove deprecated impact analysis algorithm 2020-06-26 15:02:30 +02:00
acognet
80161b909e N°2362 - API : remove DBInsertTracked / DBUpdateTracked 2020-06-26 14:16:14 +02:00
Pierre Goiffon
888232e8c3 Merge remote-tracking branch 'origin/support/2.7' into develop
# Conflicts:
#	test/core/HTMLDOMSanitizerTest.php
2020-06-26 10:53:49 +02:00
Eric
94f9b16c03 N°2589 - Infinite loops when logging with a Contact having a non empty TagSet field
Add ListParameters to DBSearch for nested queries
2020-06-24 15:18:11 +02:00
acognet
311aeb0b07 N°2589 - Infinite loops when logging with a Contact having a non empty TagSet field 2020-06-24 12:09:55 +02:00
Pierre Goiffon
d904883bdd 📝 CONTRIBUTING : fix release branch naming 2020-06-23 17:48:42 +02:00
acognet
68fe3f01be Spelling corrections 2020-06-23 17:38:24 +02:00
bruno DA SILVA
35d2c3afac uses the conventionnal host 2020-06-23 15:10:09 +02:00
Molkobain
7cee8c3cd0 Update README.md 2020-06-23 15:05:41 +02:00
Molkobain
27622bbcec Update readme.txt 2020-06-23 15:05:38 +02:00
bruno DA SILVA
219270ce81 Removes latest versions to ease maintenance 2020-06-23 14:59:11 +02:00
OИUЯd da silva
16dd47a3b9 simplify the readme (#143)
Removes latest versions to ease maintenance
2020-06-23 14:51:52 +02:00
Molkobain
70835984de Add "software requirements" section to README
At first I added a complete section with a table and all currently supported versions of iTop, then @bruno-ds pointed out that it would only be redundant with the wiki page and just another source of information to maintain (which is totally true, thanks!). So instead it's just a simple link in the "resources" section.
2020-06-23 14:23:15 +02:00
acognet
7ce94486bd Spelling correction 2020-06-23 13:49:53 +02:00
Pierre Goiffon
d9224f43f2 AttributeImage : remove useless override
The previous code was removed in d5b0bb02, and until then the method was just calling the parent doing nothing more
2020-06-23 11:39:51 +02:00
acognet
6523b34d58 Update version number for 2.7.1 2020-06-23 11:19:44 +02:00
bruno DA SILVA
be20705449 Add unit test.
unit test the behaviour of the removal of the blacklisted html tags

this is in fact an adaptation of the test added for the rolled-back feature of the n°2556.
This feature has been postponed to the 2.8 due to performance scaling issues.
2020-06-22 16:13:31 +02:00
Molkobain
5b9643d6fb Update PHPDoc 2020-06-22 16:06:21 +02:00
acognet
e7abaa2838 Update dictionnaries 2020-06-22 15:50:18 +02:00
bruno DA SILVA
d3525190d5 N°2556 - Html sanitization preserve content of removed tags (except for a forbidden list)
forbidden list: see $aTagsContentRemovableList

(cherry picked from commit 746b47bb0e)
(cherry picked from commit 79909fadc0)
2020-06-22 11:40:38 +02:00
Pierre Goiffon
f20808d929 Merge remote-tracking branch 'origin/support/2.7' into develop 2020-06-22 11:39:44 +02:00
Pierre Goiffon
8d73eb6dff Revert "N°2556 - Html sanitization preserve content of removed tags (except for a forbidden list)"
This reverts commit 746b47bb0e.
Revert "N°2556 - Repair CI"

This reverts commit 79909fadc0.
2020-06-22 11:36:46 +02:00
acognet
f84995a58f N°309 - Afficher les arbres pliés ou dépliés 2020-06-19 18:45:26 +02:00
Pierre Goiffon
aee80e41ca N°2214 Fix typo in method name
Introduced in b7136c0b7a
Many Thanks @jbostoen !
2020-06-19 13:47:15 +02:00
acognet
7f66e26b5f Merge remote-tracking branch 'origin/support/2.7' into support/2.7 2020-06-19 12:27:35 +02:00
acognet
a6639b067f N°309 - Afficher les arbres pliés ou dépliés 2020-06-19 12:26:08 +02:00
Pierre Goiffon
8a6d66effd 📝 Fix PHPDoc 2020-06-18 11:08:18 +02:00
Pierre Goiffon
6885d64124 📝 N°1418 DBObject PHPDoc 2020-06-17 19:03:29 +02:00
acognet
6fa153ae8b N°3107 - Remove code merged by mistake 2020-06-17 15:20:52 +02:00
acognet
e226222c2a N°3102 - widget regression: OQL syntax error now crash the page instead of displaying an error in place of the widget 2020-06-17 11:11:48 +02:00
Pierre Goiffon
aca0143e89 📝 PHPDoc for BackgroundProcess exceptions 2020-06-17 09:25:38 +02:00
Pierre Goiffon
1968c60770 📝 \DBObjectSet::ToArray PHPDoc 2020-06-16 12:32:57 +02:00
Pierre Goiffon
56ea6c8848 N°2214 fix @since after cherry-pick 2020-06-15 16:22:04 +02:00
Pierre Goiffon
26014f410a Set back version for 2.7.1
Was set to 2.8 by mistake in 23afee51 (PR #125 that was rebased in GitHub web)
2020-06-15 15:49:01 +02:00
Pierre Goiffon
b7136c0b7a N°2214 Add PHP check in CLI scripts
It is quite common that the PHP interpreter that is launched in CLI is different that the one used by the webserver. So iTop code launched by CLI could run in a context that doesn't meet iTop requirements !

This adds in the following scripts the same control that is done on the setup wizard first step :
* cron.php
* backup, check-backup
* export, exportv2
* bulk import
* synchro-exec, synchro-import

If the check throws at least one error then the script is stopped with an appropriate message, and a log is made (IssueLog, Error level, CLI channel)

(cherry picked from commit c768e18e2b : no risk taken for 2.7.1, so cherry picked for 2.8.0)
2020-06-15 15:20:17 +02:00
Pierre Goiffon
ea94986247 Merge remote-tracking branch 'origin/support/2.7' into develop 2020-06-15 15:19:12 +02:00
Pierre Goiffon
8912618732 Revert "N°2214 Add PHP check in CLI scripts"
This reverts commit c768e18e2b.
No risk taken for the 2.7.1 : this will be included but for 2.8 !
2020-06-15 15:18:26 +02:00
Eric
7bee718a13 N°3775 - Dashboard Definition with unknown class leads to an error 2020-06-15 14:53:58 +02:00
odain
d8363067e6 ci 2 new options: coverture + run only one test 💚
try to have coverture option
2020-06-15 10:32:47 +02:00
Pierre Goiffon
2705543efd N°2997 new test for AbstractWeeklyScheduledProcess
Document the way GetNextOccurrence works O:)
2020-06-12 18:20:07 +02:00
Pierre Goiffon
1e6b885301 SetupUtils : add missing public access keyword for methods 2020-06-12 16:50:04 +02:00
Pierre Goiffon
c768e18e2b N°2214 Add PHP check in CLI scripts
It is quite common that the PHP interpreter that is launched in CLI is different that the one used by the webserver. So iTop code launched by CLI could run in a context that doesn't meet iTop requirements !

This adds in the following scripts the same control that is done on the setup wizard first step :
* cron.php
* backup, check-backup
* export, exportv2
* bulk import
* synchro-exec, synchro-import

If the check throws at least one error then the script is stopped with an appropriate message, and a log is made (IssueLog, Error level, CLI channel)
2020-06-12 16:46:37 +02:00
odain
6e4f9a9b93 small fix 2020-06-12 09:14:09 +02:00
odain
29c4ca7e65 revert lib/composer/autoload unwanted commit 2020-06-11 21:33:54 +02:00
odain
4d3aefe2a4 fix all the tests 2020-06-11 21:29:03 +02:00
Eric
d4b93f3bf0 N°2641 - Create a dedicated ErrorPage for fatal errors 2020-06-11 17:16:47 +02:00
acognet
6354c62c2b N°3012 - Fix blocking MTT/MTP when /extensions 2020-06-11 14:13:27 +02:00
acognet
cf8a12fe95 PMP light first version - small evolutions 2020-06-10 10:44:18 +02:00
acognet
36804dfcf4 N°3098 - Portal with IE : apply a transition ends with blank page 2020-06-10 10:44:17 +02:00
odain
c798e0a9cd fix absolute path test failure 2020-06-08 16:56:29 +02:00
Eric
6966c0498a N°3071 - fix missing index for AttributeSet (for migration) 2020-06-08 16:50:32 +02:00
Eric
bbffc40ee0 N°3074 - Fix dashlet creation for IE 2020-06-08 16:20:41 +02:00
odain
1b9c7b7766 fix test failed due to different absolute paths 2020-06-08 15:32:57 +02:00
odain
19ee8e4071 add recurseMkdir 2020-06-08 14:49:16 +02:00
Thomas Casteleyn
b302569feb Update Dutch SynchroAttribute::update_policy translation 2020-06-08 13:02:57 +02:00
odain
4741012fb9 debug testcase failed 2020-06-08 11:26:12 +02:00
odain
f5886f603b themehandler better test failure feedback 2020-06-08 10:57:57 +02:00
odain
d82086240b Merge branch 'feature/bug2996-checklist-compilation' into feature/fast-theme-compilation 2020-06-08 09:39:33 +02:00
odain
f47b16c571 adapt precompiled styles 2020-06-08 09:38:39 +02:00
odain
728b082a7d remove version from css-variables.scss 2020-06-08 09:35:12 +02:00
odain
31482ccef7 make sure GetCompiledModuleVersion returns timestamp 2020-06-08 09:34:45 +02:00
odain
ca99e612cf clean .make from css-variable version update 2020-06-08 09:33:51 +02:00
acognet
1b7473365d N°3075 - Fix syntax error with PHP 5.6 and TCPDF 6.3.4 2020-06-05 17:03:46 +02:00
Eric
0b84e809f6 Add cache to twig templates 2020-06-05 15:52:26 +02:00
acognet
a858362622 N°3080 - Portal cannot display more 10 attachments 2020-06-05 09:42:04 +02:00
odain
c9c833a868 IssueLog instead of echo in ThemeHandler 2020-06-04 22:50:45 +02:00
odain
7cad4ac444 adapt testValidatePrecompiledStyles 2020-06-04 22:47:50 +02:00
odain
001680906d molkobain remarks in PR 2020-06-04 21:58:03 +02:00
odain-cbd
ed355cb8cf Update application/themehandler.class.inc.php
Co-authored-by: Molkobain <guillaume.lajarige@combodo.com>
2020-06-04 21:52:02 +02:00
odain-cbd
fa036ee724 Update application/themehandler.class.inc.php
Co-authored-by: Molkobain <guillaume.lajarige@combodo.com>
2020-06-04 21:47:02 +02:00
odain-cbd
e04548a61c Update application/themehandler.class.inc.php
Co-authored-by: Molkobain <guillaume.lajarige@combodo.com>
2020-06-04 21:45:29 +02:00
odain-cbd
25c55bdaf4 Update application/themehandler.class.inc.php
Co-authored-by: Molkobain <guillaume.lajarige@combodo.com>
2020-06-04 21:43:17 +02:00
odain-cbd
c1c43c7d5d Update application/themehandler.class.inc.php
Co-authored-by: Molkobain <guillaume.lajarige@combodo.com>
2020-06-04 21:43:00 +02:00
Eric
d195c2b4c9 N°3071 - fix missing index for AttributeSet 2020-06-04 17:04:07 +02:00
acognet
28b75f29e5 N°3020 - Recurring PHP Notice with itop-fence "Undefined index: login_temp_auth_user 2020-06-04 16:21:07 +02:00
odain
b970d81272 Merge branch 'develop' into feature/fast-theme-compilation 2020-06-04 14:45:11 +02:00
Eric
9d8a7bf561 N°3007 - Warn the user that installing a patch on a non conform install is not recommended 2020-06-04 10:38:58 +02:00
odain
b7ffa9e3c0 bug2996: include images in precompiled signature 2020-06-04 08:55:28 +02:00
Eric
8064a20718 N°2970 - Reset conditions of joined filter because they can be used later by the Filter() method 2020-06-03 11:47:12 +02:00
odain
e94d5418f4 Merge branch 'develop' into feature/bug2996-checklist-compilation 2020-06-03 11:32:26 +02:00
acognet
f301a283e2 N°3015 - Fix "Undefined index: login_mode" Notice 2020-06-02 16:04:50 +02:00
Pierre Goiffon
e6a8f492d5 N°3049 Fix notice when having an ENUM field with values containing parenthesis 2020-05-28 15:38:21 +02:00
Pierre Goiffon
336637a7a4 SetupLog : ease changing manually the default level
In setup no conf file available so the log_level_min config option cannot be read
A solution is to manually change this constant
2020-05-28 11:40:22 +02:00
acognet
0e5a501b2a N°3012 - Fix blocking MTT/MTP when /extensions 2020-05-27 10:13:44 +02:00
acognet
59af58a173 N°3008 - Align transition form markup metadata to regular form in the backoffice 2020-05-27 10:00:20 +02:00
acognet
7f922560ba N°1976 - Duplicate Service on Customer Contract - formating code 2020-05-27 09:35:02 +02:00
acognet
d2e286345e N°1976 - Duplicate Service on Customer Contract 2020-05-27 09:30:52 +02:00
Pierre Goiffon
44008fc179 Merge remote-tracking branch 'origin/support/2.7' into develop 2020-05-26 12:26:44 +02:00
Pierre Goiffon
fb120bdc7c Merge remote-tracking branch 'origin/support/2.7.0' into support/2.7 2020-05-26 08:44:21 +02:00
Pierre Goiffon
5548997f3e 📝 README : fix for 2.7.0-2 2020-05-26 08:43:11 +02:00
bruno DA SILVA
156828c448 Merge branch 'feature/2958_unescape_slack' into support/2.7 2020-05-25 16:07:05 +02:00
bruno DA SILVA
04ef2b0454 2958 - test a restore 2020-05-25 15:52:37 +02:00
bruno DA SILVA
076d2e3d46 2958 - test a failure 2020-05-25 15:51:42 +02:00
bruno DA SILVA
0c6ab86e54 2958 - Slack notification : fix escaped branch name 2020-05-25 15:34:18 +02:00
bruno DA SILVA
876db3e58f 2958 - Slack notification : fix escaped branch name 2020-05-25 15:32:16 +02:00
Molkobain
5f7fe345cc Update README with iTop 2.7.0-2 information 2020-05-20 10:23:18 +02:00
Molkobain
cb6f78c9e3 Update README with iTop 2.7.0-2 information 2020-05-20 10:22:34 +02:00
acognet
8c86908652 N°3023 - Portal: Fix filter brick input not working in IE11 2020-05-19 10:17:27 +02:00
acognet
7e69256cb4 N°2668 - Notifications - Export wrong attribut format in html 2020-05-18 21:52:31 +02:00
acognet
83e3c089a4 N°1976 - Duplicate Service on Customer Contract 2020-05-18 21:51:29 +02:00
Pierre Goiffon
0d1059a8fc Merge remote-tracking branch 'origin/support/2.6' into support/2.7
# Conflicts:
#	application/utils.inc.php
#	conf/web.config
#	datamodels/2.x/itop-backup/ajax.backup.php
#	datamodels/2.x/itop-backup/status.php
2020-05-18 09:24:46 +02:00
Eric
e2f15ca24a 🌐 Add ES_CR translations to Application Upgrade Menu
From PR#128 by Federico Lazcano
2020-05-15 14:39:22 +02:00
Eric
7628b85b70 🌐 Add ES CR translations for DB Tools
From PR#127 by Federico Lazcano
2020-05-15 14:13:24 +02:00
Eric
525f600c18 🌐 Config Menu title should be uppercase
From PR#126 by Federico Lazcano
2020-05-15 14:04:15 +02:00
Pierre Goiffon
0ffa2850ea Deadlock log : log inside a dedicated log file instead of creating an EventIssue object (#139)
First log implementation (75730ee) was creating EventIssue objects, and was rollbacking transaction if it exists

The new one has some benefits :

* always log one line by default in log/error.log, but details must be activated though config (channels `Deadlock-WaitTimeout` and `Deadlock-Found`)
* detailed logs are in a dedicated file (log/deadlock.log) : 
  - easier for our clients to get and share
  - has rotation by default
  - looking at the file size is a direct way to know if error happened
  - more compliant to industry standards !
* the transaction stays untouched, so that the consumer can do whatever it prefers
2020-05-14 17:49:05 +02:00
Eric
fa3610cfee N°2641 - Create a dedicated ErrorPage for fatal errors
Fix fatal errors being logged in setup.log instead of error.log
2020-05-14 14:37:38 +02:00
acognet
898ee95a2c N°1997 - dbClick to exit the "description" field when creating an incident on the portal 2020-05-14 13:03:49 +02:00
Pierre Goiffon
730570f1f8 📝 MFCompiler language injection 2020-05-14 11:43:57 +02:00
Pierre Goiffon
80ce1eb125 N°2984 Security hardening 2020-05-14 11:33:48 +02:00
Pierre Goiffon
228a945da9 N°2984 Security hardening 2020-05-14 11:26:35 +02:00
bruno DA SILVA
79909fadc0 N°2556 - Repair CI 2020-05-14 10:49:31 +02:00
bruno DA SILVA
746b47bb0e N°2556 - Html sanitization preserve content of removed tags (except for a forbidden list)
forbidden list: see $aTagsContentRemovableList
2020-05-14 10:33:30 +02:00
acognet
150d3e096d N°2346 - Function GetTrackOrigin() doesn't return good value during csvimport 2020-05-13 23:55:26 +02:00
Thomas Casteleyn
c2f62a13e6 Fix duplicate version loading (#141) 2020-05-13 14:53:47 +02:00
Thomas Casteleyn
23afee514d 🌐 Update nl.dictionary.itop.ui.php (#125) 2020-05-13 14:38:32 +02:00
acognet
48c5698f08 N°2934 - Backoffice theme: Add variable for menu group background color 2020-05-13 12:22:35 +02:00
acognet
1a4ee0f977 N°1953 - Dashlet Title alignment not consistent : Left on List, Center on Table/Pie/Chart 2020-05-13 12:22:35 +02:00
Eric
1ca39618e1 N°1610 - Fix [DBObject] ExecAction - apply_stimulus
removed unnecessary test
2020-05-13 11:38:22 +02:00
Eric
7bb1f9f423 N°2937 - fix export error on EventIssue object 2020-05-13 11:24:34 +02:00
Pierre Goiffon
834297e675 N°2985 Security hardening (#140)
Thanks @bruno-ds  for the review !
2020-05-13 10:04:40 +02:00
bruno DA SILVA
21c2574cd9 N°2358 - Fix deletion of a single replica within a list 2020-05-13 09:37:36 +02:00
Pierre Goiffon
6d9923be68 AbstractWeeklyScheduledProcess fix typo and add @noinspection 2020-05-13 08:45:03 +02:00
bruno DA SILVA
839bbc425f N°2901 Add log to help diagnose lost InlineImage
they are disabled by default, use this to enable:
 ```
 'log_level_min' => array(
 		'InlineImage' => LogAPI::LEVEL_TRACE,
 		'UserRequest' => LogAPI::LEVEL_TRACE,
 	),
```
2020-05-12 15:34:13 +02:00
acognet
70cc19768a N°1953 - Dashlet Title alignment not consistent : Left on List, Center on Table/Pie/Chart 2020-05-12 14:48:56 +02:00
acognet
873d109b98 N°1910 - iTop - Search on Text contains "_" not working - move correction in other place 2020-05-12 14:48:16 +02:00
Eric
a81950571a N°1598 - Fix regression on modify 2020-05-12 14:21:34 +02:00
Eric
bcd9679957 N°3006 - Fix filtering an UNION with parent class 2020-05-12 12:08:18 +02:00
Eric
2c10913fe5 N°2093 - Keep object values when a stimulus action fails 2020-05-12 11:29:30 +02:00
Eric
0342b89481 N°1598 - warning for bad stimulus instead of fatal error 2020-05-12 11:01:04 +02:00
Pierre Goiffon
3c9318d56a N°2990 Fix count warning on audit OQL error 2020-05-12 09:41:24 +02:00
Pierre Goiffon
30d10b6f11 N°2990 Security hardening 2020-05-12 09:40:58 +02:00
acognet
3fd55c6dd6 N°1693 - the history of AttributeEncryptedString must not interpret HTML tags 2020-05-11 12:14:55 +02:00
Pierre Goiffon
f8e39877b3 N°2988 Security hardening 2020-05-07 11:49:58 +02:00
Pierre Goiffon
0a3f7d7ef7 N°2989 ajax.backup small updates
* update copyright
* in messages replace iTop by constant
2020-05-07 11:18:21 +02:00
Pierre Goiffon
222eb47bd2 N°2989 ajax.backup : refactor exit conditions
Adding a die() call so that we are sure to exit on errors !
2020-05-07 10:49:05 +02:00
Eric
c15b3462d1 N°2945 - Adding an empty file as an attachment is generating a fatal error
Changed error message
2020-05-07 08:49:05 +02:00
Pierre Goiffon
32f05ea917 👥 Added Pascal Schirrmann as contributor (N°2980, thanks to him !) 2020-05-07 08:36:53 +02:00
Molkobain
6a50b55a2a N°1598 - Improve user feedback on invalid transition: Display a better error message to the user in the portal 2020-05-06 16:58:25 +02:00
Eric
72f11c6a4d N°2815 - Fix basic authentication with Apache
Added support for REDIRECT_HTTP_AUTHORIZATION
2020-05-06 11:35:56 +02:00
Eric
609ea47f7b PHPDoc 2020-05-06 10:29:47 +02:00
Pierre Goiffon
74b3cfd46c Merge remote-tracking branch 'origin/support/2.7.0' into support/2.7 2020-05-06 10:13:15 +02:00
acognet
f7ea6c09cd N°2589 - Infinite loops when logging with a Contact having a non empty TagSet field 2020-05-05 19:00:24 +02:00
acognet
526a7f9817 N°1910 - iTop - Search on Text contains "_" not working - convert _ to \_ in javascript 2020-05-05 18:36:38 +02:00
Eric
5ccb1ef72a N°1662 - Fix Auto-complete on external key ignore obsolescence user preference
ValueSetObjects now consider obsolete data
2020-05-05 11:14:59 +02:00
Pierre Goiffon
180da03f08 N°2980 Fix backup not executed anymore
Regression introduced by #89
2020-05-05 09:00:40 +02:00
Pierre Goiffon
7ec7626aa0 N°2977 PHP Doc change 2020-05-04 18:13:40 +02:00
Eric
f92a980b4d N°2974 - Fix Global Search doesn't search in external field.
For External Field, allow the search also for FriendlyNames.
2020-05-04 18:13:18 +02:00
Pierre Goiffon
5d7582bb6f N°2977 LogAPI : restore default log level to OK, and really allow LEVEL_DEFAULT overloads
* Level was changed by mistake to trace with refactoring in 289171b9
Thanks @v-dumas !

* self wouldn't allow to override
see https://www.php.net/manual/fr/language.oop5.late-static-bindings.php
Thanks @bruno-ds !

* improve PHPDoc !
2020-05-04 16:55:46 +02:00
odain
d13591ca85 create parameters.json folder when necessary 2020-05-04 15:24:45 +02:00
odain
f88f321d79 avoid to read SCSS signature when no file touched and itop theme loading only + create parameters.json folder when necessary 2020-05-04 15:16:50 +02:00
odain
c1b3cb1e7b avoid to read SCSS signature when no file touched and itop theme loading only + create parameters.json folder when necessary 2020-05-04 15:16:26 +02:00
odain
d43c72b3ac avoid to read SCSS signature when no file touched and itop theme loading only 2020-05-04 14:42:55 +02:00
odain
1457faa53a add precompiled themes validation test 2020-05-04 14:15:33 +02:00
bruno DA SILVA
7a40db94fb 2424 - Better messages when an object update fail & removed an unwanted webserver error log entry 2020-05-04 12:00:30 +02:00
Eric
843798505a N°2974 - Fix Global Search doesn't search in external field
The IsSearchable() check was wrong for some attributes
2020-05-04 11:40:02 +02:00
odain
3ee4b564f0 add a test to always validate datamodel declared precompiled CSS 2020-05-04 11:16:51 +02:00
odain
0988c8ccbf Mock compiler caller for test + Cover with tests + small css compilation fixes 2020-05-02 00:45:15 +02:00
Pierre Goiffon
bf13f9fc8a N°2975 improve RotatingLogFileNameBuilder next cron occurrence computation 2020-04-30 08:41:55 +02:00
Pierre Goiffon
289171b9f1 N°2977 LogAPI : allow to overwrite the default log level 2020-04-29 15:16:45 +02:00
Pierre Goiffon
9b065ffb0a Merge remote-tracking branch 'origin/support/2.7.0' into support/2.7
# Conflicts:
#	datamodels/2.x/itop-attachments/renderers.itop-attachments.php
2020-04-29 09:00:10 +02:00
Pierre Goiffon
96d888fcf3 N°2968 fix email-reply notification not updated
- add a specific container for attachments list, upload button and #attachment_plugin hidden input is outside of it
- refactor code between abstract class and implementation, add some comments
- now refreshes only the attachment list instead of the whole content
2020-04-28 17:47:20 +02:00
Vladimir Kunin
a182a37139 Add Russian translations for 2.7.0-1 (rebased) 2020-04-28 08:42:17 +02:00
Pierre Goiffon
accda04a37 Hierarchical selection popup : now collapsed by default, and collapse all / expand all buttons (#132)
The collapse all / expand all is not printed if no child exists
Combodo implementation of PR #87
2020-04-27 11:21:37 +02:00
Pierre Goiffon
23c15c1b6c Revert "N°2902 - Intersect with union generates unwanted alias renaming"
This reverts commit 866e4ab995.

Fix isn't yet commited, so we don't want to break the build.
The fix will be done in the hotfix/2902_intersect_alias branch
2020-04-27 09:36:38 +02:00
Eric
866e4ab995 N°2902 - Intersect with union generates unwanted alias renaming 2020-04-24 18:32:40 +02:00
Pierre Goiffon
f364e7b043 N°2923 Datatable : fix var name typo
Thanks @bruno-ds !
2020-04-24 18:28:50 +02:00
Pierre Goiffon
42afe033ef N°2923 Datatable : use container id instead of externally generated id 2020-04-24 17:16:47 +02:00
Eric
75730eeea0 Log database deadlocks in EventIssue 2020-04-23 15:25:12 +02:00
Denis Flaven
5cfa06e36f Faster compilation of themes
- Ability to provided precompiled themes in the datamodel
- Check that a precompiled theme is still up-to-date based on a signature
2020-04-22 16:11:02 +02:00
Pierre Goiffon
58fd8709be Merge remote-tracking branch 'origin/support/2.6' into support/2.7
# Conflicts:
#	css/css-variables.scss
#	datamodels/2.x/authent-external/module.authent-external.php
#	datamodels/2.x/authent-ldap/module.authent-ldap.php
#	datamodels/2.x/authent-local/module.authent-local.php
#	datamodels/2.x/combodo-db-tools/module.combodo-db-tools.php
#	datamodels/2.x/itop-backup/module.itop-backup.php
#	datamodels/2.x/itop-bridge-virtualization-storage/module.itop-bridge-virtualization-storage.php
#	datamodels/2.x/itop-change-mgmt-itil/module.itop-change-mgmt-itil.php
#	datamodels/2.x/itop-change-mgmt/module.itop-change-mgmt.php
#	datamodels/2.x/itop-config-mgmt/module.itop-config-mgmt.php
#	datamodels/2.x/itop-config/module.itop-config.php
#	datamodels/2.x/itop-datacenter-mgmt/module.itop-datacenter-mgmt.php
#	datamodels/2.x/itop-endusers-devices/module.itop-endusers-devices.php
#	datamodels/2.x/itop-full-itil/module.itop-full-itil.php
#	datamodels/2.x/itop-hub-connector/module.itop-hub-connector.php
#	datamodels/2.x/itop-incident-mgmt-itil/module.itop-incident-mgmt-itil.php
#	datamodels/2.x/itop-knownerror-mgmt/module.itop-knownerror-mgmt.php
#	datamodels/2.x/itop-portal-base/module.itop-portal-base.php
#	datamodels/2.x/itop-portal/module.itop-portal.php
#	datamodels/2.x/itop-problem-mgmt/module.itop-problem-mgmt.php
#	datamodels/2.x/itop-profiles-itil/module.itop-profiles-itil.php
#	datamodels/2.x/itop-request-mgmt-itil/module.itop-request-mgmt-itil.php
#	datamodels/2.x/itop-request-mgmt/module.itop-request-mgmt.php
#	datamodels/2.x/itop-service-mgmt-provider/module.itop-service-mgmt-provider.php
#	datamodels/2.x/itop-service-mgmt/module.itop-service-mgmt.php
#	datamodels/2.x/itop-sla-computation/module.itop-sla-computation.php
#	datamodels/2.x/itop-storage-mgmt/module.itop-storage-mgmt.php
#	datamodels/2.x/itop-tickets/module.itop-tickets.php
#	datamodels/2.x/itop-virtualization-mgmt/module.itop-virtualization-mgmt.php
#	datamodels/2.x/itop-welcome-itil/module.itop-welcome-itil.php
#	datamodels/2.x/version.xml
2020-04-22 11:14:59 +02:00
Eric
f18ea18a5b N°2936 - TLs option is not set for restore function 2020-04-21 16:59:16 +02:00
Pierre Goiffon
1904bfdba6 css-variables : update to 2.7.0-2 2020-04-21 16:35:41 +02:00
acognet
e1949cd3eb N°2509 - Change Columns via "Configure this list" show obsolete data though user preferences is "not shown obsolete data" 2020-04-21 12:45:59 +02:00
Eric
1b2d3d1e84 N°2952 - Provisioning for hybrid auth fails
Changed Origin for change to an allowed value
2020-04-21 11:59:48 +02:00
Pierre Goiffon
c5b1f02d2b 🔖 Update versions to 2.6.4 2020-04-21 08:52:42 +02:00
Pierre Goiffon
f81ab4d71a 🚀 Release tool to update versions
Was already comitted in 2.7 branch (fd1e17cc)
2020-04-21 08:50:25 +02:00
acognet
0b95dbee7f N°1588 - Count on Managed Brick sometimes wrong 2020-04-20 16:31:56 +02:00
Pierre Goiffon
8de4c0360d Merge remote-tracking branch 'origin/support/2.7' into develop 2020-04-20 16:08:15 +02:00
Pierre Goiffon
db593ff85e Merge remote-tracking branch 'origin/support/2.6' into support/2.7
# Conflicts:
#	application/loginwebpage.class.inc.php
#	application/menunode.class.inc.php
#	datamodels/2.x/itop-portal-base/portal/src/controllers/aggregatepagebrickcontroller.class.inc.php
#	datamodels/2.x/itop-portal-base/portal/src/controllers/userprofilebrickcontroller.class.inc.php
#	datamodels/2.x/itop-portal-base/portal/src/views/bricks/manage/popup-export-excel.html.twig
#	pages/ajax.render.php
2020-04-20 16:05:56 +02:00
Eric Espié
1f750bb12d N°2902 Fix alias renaming when already exists in one OQL of an UNION
The legacy impl is not modified
2020-04-20 14:59:56 +02:00
Pierre Goiffon
4ee66377ce Merge commit '15e5e21a89a3d3214dace82b8765a47e304a8f29' into support/2.7 2020-04-20 14:21:55 +02:00
Eric
432a950f8c N°2945 - Fix fatal error when adding empty attachment
alert when empty attachment is detected
2020-04-20 10:54:27 +02:00
Molkobain
24130dd94f Change version number to 2.8.0-dev 2020-04-14 18:01:30 +02:00
acognet
bbc751bee4 N°2383 - GetAttributeFlag ignored on form refresh with dependent field 2020-04-14 17:56:27 +02:00
acognet
a77ba2fbab N°2564 - Stop copy after "<" character in a Copy operation on a Transition - change only in Copy function 2020-04-14 17:56:27 +02:00
Eric
5b60ec9edf N°2919 - Dashboard - Fix dashboard not saved
the sanitization was too strong. Some names can contain ':'
2020-04-10 18:11:36 +02:00
Eric
b88b9dabdb N°2919 - Dashboard - Fix dashboard not saved
The sanitization was too strong. Some names can contain ':'
2020-04-09 17:59:52 +02:00
Eric
06b17e82db N°2755 - Security hardening 2020-04-09 11:03:07 +02:00
Eric
2add79a473 N°2853 - Security hardening 2020-04-09 10:55:17 +02:00
Lars Hippler
427326d074 Enable external classes (i.e. iApplicationObjectExtension) to use bypass function as well 2020-04-08 17:24:12 +02:00
Molkobain
3103f361a4 Update 2.7.0-1 release date 2020-04-08 11:02:03 +02:00
Eric
3a37e24496 N°2306 - Security hardening 2020-04-08 09:28:20 +02:00
Pierre Goiffon
59cc6d3f76 📝 CONTRIBUTING : fix unecessary escape 2020-04-07 15:33:26 +02:00
Pierre Goiffon
ee37373cfa 📝 CONTRIBUTING : branch model paragraph small changes 2020-04-07 15:24:56 +02:00
acognet
621295199c N°1402 - Attribut File cannot be emptied Add a trash next to the name of the file 2020-04-06 16:36:46 +02:00
Eric
b1d703bff3 N°1671 Portal: Fix Aggregate Brick when user profile is not allowed to see one of the sub-brick 2020-04-06 14:07:42 +02:00
Eric
a3a34a94e7 N°1355 - Security hardening 2020-04-06 11:47:57 +02:00
Stephen Abello
6edc365685 N°2742 - HTML files preview are now raw text only 2020-04-06 09:47:24 +02:00
Stephen Abello
4b7f736af0 N°2755 - Security hardening 2020-04-06 09:42:41 +02:00
Stephen Abello
016fbaed36 N°2755 - Security hardening 2020-04-06 09:42:15 +02:00
Stephen Abello
bfcd137e52 N°2853 - Security hardening
(cherry picked from commit d01caaf4e4)
2020-04-06 09:37:58 +02:00
Pierre Goiffon
56d9653f15 📝 CONTRIBUTING : modify branch model
We are renaming the master branch, so using a custom GitFlow branch model :)
2020-04-06 09:32:23 +02:00
Stephen Abello
f9af8fc912 N°2855 - Security hardening
(cherry picked from commit c5c7fd5c85)
2020-04-06 09:20:02 +02:00
Eric
c1a7a36896 Compatibility with MySQL 5.6 2020-04-06 09:02:06 +02:00
Pierre Goiffon
d5670abdcc 📝 Fix PHPDoc for \MFElement::_FindNode
Introduced in 4688c92e
2020-04-06 08:57:23 +02:00
Pierre Goiffon
0360a3160d Merge remote-tracking branch 'origin/releases/germanium' into develop
# Conflicts:
#	setup/modelfactory.class.inc.php
2020-04-06 08:47:22 +02:00
Thomas Casteleyn
bcd21aefb4 📝 DBObject fix wrong PHPDoc (#133)
Thanks to @Hipska !
2020-04-06 08:32:31 +02:00
acognet
d5fe653e51 N°2848 - Align creation and update message on portal to console message - add a comment for next time 2020-04-02 20:31:06 +02:00
acognet
fc2fb235a2 N°1344 - Save without all mandatory attributes (ajax reload not finished) 2020-04-02 17:46:18 +02:00
acognet
d7211509bd N°1062 - Portal : autocomplete and search = broken : change the max size of the list 2020-04-02 17:29:39 +02:00
acognet
c182b1a01f N°2848 - Align creation and update message on portal to console message 2020-04-02 11:50:01 +02:00
Eric
15e5e21a89 Compatibility with MySQL 5.6 2020-04-01 17:37:55 +02:00
acognet
ee0d231426 N°2895 - Tab dictionnary entries not taken in account in "Printer Friendly Version" screen 2020-04-01 01:05:13 +02:00
acognet
3282b46c9b N°2395 - Error in file light-gray.scss 2020-04-01 00:01:26 +02:00
acognet
05649ba50f Merge branch 'master' of github.com:Combodo/iTop 2020-03-31 23:48:35 +02:00
acognet
40efc4cbb1 N°1062 - Portal : autocomplete and search = broken 2020-03-31 23:47:46 +02:00
Molkobain
30034d381b Update version number to 2.7.0-1 2020-03-31 09:47:37 +02:00
Molkobain
986eb90546 N°2893 - Fix DataModel Viewer not supporting special chars in class name (eg. ") 2020-03-31 09:40:31 +02:00
Pierre Goiffon
3cbcdd4f13 🎨 MFElement : fix access modifiers & PHPDoc 2020-03-31 08:53:22 +02:00
odain
c46d0f5662 N°2888 Impossibility to import iTop User with password policy 2020-03-30 17:48:01 +02:00
Pierre Goiffon
eb41d3e2ef 📝 Fix erroneous PHPDoc for InlineImageGC 2020-03-30 17:09:04 +02:00
acognet
c6b16bb52e N°2119 - Dashlet Header statistic on ExternalKey, display id instead of name 2020-03-30 16:24:12 +02:00
acognet
95adbbb58f N°1181 - List of searchable classes in SearchMenuNode - add user rights tests 2020-03-30 16:23:23 +02:00
acognet
60f5c60059 N°1796 - Search : false criteria after using the magnifier 2020-03-30 16:19:23 +02:00
acognet
c0284ecc3b N°1953 - Dashlet Title alignment not consistent : Left on List, Center on Table/Pie/Chart 2020-03-30 16:18:43 +02:00
acognet
fc7b772ba3 N°1910 - iTop - Search on Text contains "_" not working
_ is a special caracter in mysql -> replace with \_
2020-03-30 16:13:47 +02:00
Pierre Goiffon
b2454d44ae 👥 Added @ousret to the contributor list
See #99
Thanks to him !
2020-03-30 08:39:35 +02:00
TAHRI Ahmed R
79cfb95f6e Support array for json_data posted in rest/json service (#99)
Previous syntax :
```
CURLOPT_POSTFIELDS => array(
	'auth_user' => 'admin',
	'auth_pwd' => 'admin',
	'json_data' => '{
	   "operation": "core/get",
	   "class": "Person",
	   "key": "SELECT Person", "limit": "10", "page": "1"
	}'
);
```

Now we can also use :
```
CURLOPT_POSTFIELDS => array(
	'auth_user' => 'admin',
	'auth_pwd' => 'admin',
	"json_data[operation]" => "core/get",
	"json_data[class]" => "Person",
	"json_data[key]" => "SELECT Person",
	"json_data[limit]" => 10,
	"json_data[page]" => 1
);
```
2020-03-27 18:11:09 +01:00
Pierre Goiffon
ff2e1a3507 Fix syntax error in core/email.class.inc.php
Missing ";" at the end of line :/
Introduced by 503afb98
2020-03-27 16:43:03 +01:00
Lars Hippler
503afb9831 Make it possible to add return path for mails (#95) 2020-03-27 16:20:59 +01:00
Pierre Goiffon
b6772917ae Merge branch 'release/2.7.0' into develop
# Conflicts:
#	.make/license/gen-community-license.sh
#	setup/licenses/community-licenses.xml
2020-03-27 15:20:08 +01:00
Pierre Goiffon
011d742ae3 N°2891 📌 add mbstring as optional extension 2020-03-27 14:41:59 +01:00
Pierre Goiffon
5b496f4d15 N°2866 Change "cron" case in labels as it is not an acronym
Thanks @Hipska for the feedback done in Combodo/iTop#124 !
2020-03-26 11:15:47 +01:00
Pierre Goiffon
97f4c32271 N°2881 Improve robustnedd of \ModuleInstallerAPI::RenameEnumValueInDB
Was causing errors when migrating from datamodels where the fields were not enum yet (this method is usually launched using \ModuleInstallerAPI::BeforeDatabaseCreation, so before an ALTER could be done to the column)
2020-03-26 10:18:34 +01:00
Pierre Goiffon
c002ca7902 setup.css : update .css that was not up to date :/ 2020-03-26 10:13:10 +01:00
Pierre Goiffon
ff22074418 🎨 setup.css : remove warnings & unused code
Removed unused legacy code :
* #header>H1 : a noline-height ugly when renamed to line-height, seems totally unused when noline-height
* table.formTable : cellpadding & cellspacing
2020-03-26 10:09:08 +01:00
Pierre Goiffon
84968ff550 Merge remote-tracking branch 'origin/release/2.7.0' 2020-03-26 08:50:14 +01:00
bruno DA SILVA
46151c87c0 N°2888 Check password policy only if field set with a string
Some callers are setting the field using an ormPassword object containing hashed password + salt

examples:
 - csv import
 - data synchro
 - ...
2020-03-25 12:43:41 +01:00
Pierre Goiffon
75a900c6f8 🚀 Tool to batch update XML datamodel version 2020-03-24 16:46:48 +01:00
Molkobain
e8c9d99783 Increase XML version to v1.7 2020-03-24 14:06:41 +01:00
bruno DA SILVA
00971f9ec7 rollback on two composer options: adding them made no sense since this file is not meant to handle dependencies but just use the autoloader (dependencies are handled by the one a the root of the project) 2020-03-21 16:17:45 +01:00
bruno DA SILVA
a3a97fa228 added missing composer config for the portal's composer.json
- php 5.6+
 - dump the autoloader as optimized as possible
2020-03-21 16:13:28 +01:00
bruno DA SILVA
18c4ca9131 🐛 fix Cannot connect to the MySQL server for the CI's unattended_install 2020-03-20 15:15:29 +01:00
Eric
1600302ad9 N°2869 - Removed Check for bad finalclass in root classes (already done) 2020-03-19 15:40:52 +01:00
Eric
a9c3a1b782 N°2869 - Check for bad finalclass in root classes (Allow all non-abstract child classes) 2020-03-19 10:01:16 +01:00
Eric
74848254a4 N°2869 - Check for bad finalclass in root classes 2020-03-18 14:10:35 +01:00
Eric
d7d9bfe0fd N°2869 - Check for bad finalclass in intermediate classes 2020-03-18 10:09:05 +01:00
odain
dd96dec100 Fix license file generation; exclude itop-portal-base 2020-03-18 08:42:55 +01:00
Pierre Goiffon
16ff51f3b7 📄 Update licenses after generation tool upgrade
See 76d26e8e
2020-03-18 08:15:09 +01:00
odain
466ddf768e Fix license generation tool 2020-03-17 18:59:29 +01:00
odain
76d26e8ef9 Fix license generation tool 2020-03-17 18:59:18 +01:00
Pierre Goiffon
27c651b33c 📄 Remove itop-portal-base from license file 2020-03-17 18:08:49 +01:00
Pierre Goiffon
32375265cb 📄 Remove 2.x/authent-cas from license file 2020-03-17 17:47:25 +01:00
Pierre Goiffon
0cba163dc9 🔖 Update version to final in iTop files 2020-03-17 16:50:45 +01:00
Pierre Goiffon
fd1e17cc32 🚀 Release tool to update versions 2020-03-17 16:49:05 +01:00
Eric
d85e1906b7 N°2746 - New Attribute Enum Set
XML migration from 1.7 to 1.6
2020-03-17 12:03:10 +01:00
Pierre Goiffon
f8df84aa7b Update dict for 2.7.0-RC 2020-03-17 10:55:53 +01:00
Eric
c26b9459bb N°2869 - Fix 2.7 Migration
Run UPDATE requests just after the corresponding ALTER TABLE requests
2020-03-16 18:49:12 +01:00
Molkobain
4f7676c42d N°2735 - Rollback previous "fixes" to keep the simple ID policy in the Designer and a unique ID generation at runtime 2020-03-16 12:17:09 +01:00
Molkobain
ceddafaebe N°2735 - Rename parameter for better consistency 2020-03-16 12:17:09 +01:00
Stephen Abello
950640babe N°1986 - Revert feature 2020-03-13 10:24:25 +01:00
jbostoen
11e6be1037 🌐 Added NL translations (#124)
Co-authored-by: jbostoen <->
2020-03-13 09:42:37 +01:00
Molkobain
29d963317f N°2735 - Fix dashlet ID generation to have the "CUSTOM" prefix only at runtime 2020-03-12 16:46:15 +01:00
Molkobain
dd300e075c N°2735 - Fix dashlet edition in the Designer (property form ID was not matching dashlet's) 2020-03-12 16:46:03 +01:00
Molkobain
774ace2302 Fix icon select widget to be compatible with iTop 2.7 2020-03-12 14:16:03 +01:00
Molkobain
bbfddea93d Open new_dashlet_id operation for Designer 2020-03-12 14:16:02 +01:00
Stephen Abello
c5c7fd5c85 N°2855 - Security hardening 2020-03-12 14:13:17 +01:00
odain
b526d6422b Adding a test to cover selectin/cmdb code
cleanup
2020-03-12 10:55:18 +01:00
jbostoen
5d4b9f4a89 🌐 Fix typos in English translation (#123) 2020-03-12 08:51:40 +01:00
Stephen Abello
d01caaf4e4 N°2853 - Security hardening 2020-03-10 10:23:38 +01:00
Pierre Goiffon
63c02ff33d 📝 Fix PHPDoc typo 2020-03-09 16:00:15 +01:00
Pierre Goiffon
f895821db9 ⚗️ CONTRIBUTING : added some emoji O:) 2020-03-06 20:52:33 +01:00
bruno DA SILVA
19f34d1a72 composer reflexion: list outdated packages 2020-03-05 11:33:36 +01:00
Pierre Goiffon
7ff1a03a3c N°2820 monthly log rotation : restore default config 2020-03-04 16:04:19 +01:00
Pierre Goiffon
eadc3b72c2 📝 N°2793 log rotation add PHPDoc about timezones 2020-03-04 14:23:34 +01:00
odain
c06f8e9a98 N°2793 log rotation test : fix timezone issues 2020-03-04 12:05:42 +01:00
Pierre Goiffon
6675d7d42a N°2793 Test log rotation 2020-03-04 09:21:05 +01:00
Eric
afc118e9c2 🐛 fix GetAsPlainText() on EnumSet 2020-03-03 17:34:15 +01:00
Pierre Goiffon
f36fcb2a2d N°2820 Log rotation : change default from weekly to monthly 2020-03-03 15:31:11 +01:00
Eric
f062af367d N°2826 - Bad SQL request for group by with data-localizer
Unit tests to check the fix in data-localizer
2020-03-03 15:25:12 +01:00
Pierre Goiffon
29d24faf52 N°2793 Log rotation : fix no rotation :/
Was caused by erroneous file exists test
2020-03-03 10:18:09 +01:00
Pierre Goiffon
33f3f2810e N°2793 Log rotation : add file exists check in the lock 2020-03-02 18:33:00 +01:00
Pierre Goiffon
fad00200b6 🔧 PHPStorm remove is_null() rewrite inspection 2020-03-02 15:56:26 +01:00
Pierre Goiffon
56ef6feadf N°2820 Log rotation : new MonthlyRotatingLogFileNameBuilder class 2020-03-02 15:52:59 +01:00
Pierre Goiffon
2be16f9078 N°2793 Log rotation (#117)
Now log file name is unchanged : current log is still /log/error.log \o/

Rotation check (using file last modification time) is done :
* on each file write : we don't want to miss calls if session last from 23:59:59 to 00:01 for example ! Though the filemtime() call is done once per session to lower performance impacts
* using a new background process (LogFileRotationProcess)

File renaming on setup is therefore removed.
Also the interface is renamed (from ILogFileNameBuilder to iLogFileNameBuilder) to conform to iTop convention.
2020-03-02 15:01:12 +01:00
Eric
6874aed4a2 N°1627 - Ticket ref sometimes duplicate
add MakeInsertQuery() to legacy
2020-03-02 12:04:12 +01:00
Pierre Goiffon
07b8830436 N°2814 Fix cannot authenticate in some HTTP calls
basic mode was forced in 0dd1f26b
scripts concerned :
* synchro/synchro_import.php
* webservices/cron.php
* webservices/import.php
2020-03-02 11:56:00 +01:00
Molkobain
39d3e00ba1 N°2822 - Fix timeout message through AJAX calls in the Portal 2020-02-28 16:53:16 +01:00
Stephen Abello
ffa43160bf N°1164 #1491 - Add padding and border to code blocks 2020-02-28 16:42:46 +01:00
Pierre Goiffon
a45d1336f4 🎨 Change \ormStopWatch::ComputeGoal for IDE convencience, add phpdoc 2020-02-28 12:02:20 +01:00
Federico Lazcano
5a287fabba 🌐 Typo in ES_CR User Requests 2020-02-28 08:23:34 +01:00
Federico Lazcano
da86ee4114 🌐 Typo in ES_CR Incidents 2020-02-28 08:22:59 +01:00
Federico Lazcano
5157788afe 🌐 Typo in ES_CR User Requests 2020-02-28 08:22:14 +01:00
Molkobain
386e25efd6 N°2314 - Remove basque-red, ocean-blue and test-blue from default themes 2020-02-27 15:41:54 +01:00
Molkobain
649e2f8e6a Internal: Remove unused import 2020-02-27 15:10:41 +01:00
Molkobain
3c3d744747 N°2314 - Refactor part of the compilation in dedicated helpers 2020-02-27 15:09:57 +01:00
Molkobain
1371eee826 N°2735 - Continue rework of the dashlet id generation: Dashlet could not be added in the Designer 2020-02-27 11:54:20 +01:00
Molkobain
6645a5053f N°2806 - Fix errors on legacy portal "portal" tag during migration to iTop 2.7 2020-02-26 17:17:56 +01:00
Molkobain
e2a3e0e74f N°2735 - Continue rework of the dashlet id generation:
- Move generation from DashboardLayout to Dashboard
- Migrate dashlet user preference in RuntimeDashboard only (and not in DesignTimeDashboard)
2020-02-26 16:29:32 +01:00
Molkobain
401f82062a N°2735 - Make sure to always have the dashboard (sanitized) id for dashlets rendering 2020-02-26 12:10:18 +01:00
Molkobain
5a01a76f80 N°2735 - Add new sanitize filter ('element_identifier') for dashboard identifier 2020-02-26 12:10:18 +01:00
Pierre Goiffon
3e5520d079 N°2735 Fix new dashlet id didn't contain dashboard id 2020-02-26 09:13:19 +01:00
Pierre Goiffon
beef2a89a3 N°2684 Remove upgrade from another repository
This upgrade procedure was :
* dangerous : running two iTop of different versions on the same database should not be done
* insufficient : just /extensions/* was copied, not any Hub or Designer data, no log, no instance.txt, ...
2020-02-25 18:01:59 +01:00
Molkobain
2f920cbb46 Internal: PHPDoc and warnings suppression 2020-02-25 17:45:18 +01:00
Molkobain
4688c92e7c Internal: PHPDoc and warnings suppression 2020-02-25 15:44:26 +01:00
Pierre Goiffon
feae36e5b8 N°2735 Fix dashlet id duplicates when moving dashlet from one cell to another 2020-02-25 15:43:20 +01:00
Stephen Abello
92ae0e72e1 N°2314 - Markup extensibility: Add a variable for hovered table lines background color 2020-02-25 15:14:12 +01:00
Stephen Abello
ed030403aa N°2112 - Remove unused legacy portal conf variable and its usage 2020-02-25 14:00:58 +01:00
Pierre Goiffon
dfc894f6fd N°2735 Fix cannot edit new dashlet properties regression
Was introduced by cf83bc73
2020-02-25 11:17:52 +01:00
Stephen Abello
368b49ef8f N°2314 - Markup extensibility: Fix table sorter icons in html export pages 2020-02-25 10:36:56 +01:00
Stephen Abello
ccfd3848fb N°1164 #1491 - Fix syntax code highlighting display in CaseLog/HTML fields 2020-02-25 09:54:18 +01:00
Molkobain
ea59f7bc23 N°2314 - Markup extensibility: Add metadata to caselogs in the admin. console 2020-02-24 18:22:01 +01:00
Molkobain
9d6ed7f489 N°2806 - Fix errors on legacy portal constants during migration to iTop 2.7 2020-02-24 17:03:13 +01:00
Molkobain
0aa006f7c4 Internal: Fix typo in PHPDoc 2020-02-24 16:47:10 +01:00
Molkobain
c669d6951b PHPDoc and warnings suppression 2020-02-24 16:36:31 +01:00
Molkobain
9412f260ae PHPDoc 2020-02-24 11:01:24 +01:00
Molkobain
9781a11988 N°2803 - Regression: Fix "forgot_password" parameter not working anymore 2020-02-24 10:58:24 +01:00
Molkobain
1ed0210fe2 N°2799 - Fix double encoding in "top-list" display mode of the ManageBrick 2020-02-24 09:47:22 +01:00
Molkobain
1ce5ec73ea N°2798 - Fix unable to submit portal forms (Regression from dba6e8ce) 2020-02-24 09:24:23 +01:00
Eric
98304e2bda N°2596 - Allow '1' as true value for boolean in XML files 2020-02-21 18:14:03 +01:00
Pierre Goiffon
04fc58b55c 📝 Some @since annotations were missing complete version (ex 2.5 instead of 2.5.0) 2020-02-21 18:05:30 +01:00
Eric
096c3a3f13 N°2772 - Revert the loading of JS Dict in setup pages 2020-02-21 17:15:12 +01:00
Eric
87e22163d7 N°2037 - Add Twig template rendering to the WebPage 2020-02-21 14:35:25 +01:00
acognet
4cc8b89f4e N°2037 - New dashlet Gantt - add method to insert twig in an existing page 2020-02-21 12:09:15 +01:00
Pierre Goiffon
19809249a2 📝 Update PHPDoc for StopWatches interfaces 2020-02-20 18:01:09 +01:00
Molkobain
7347eed3ac PHPDoc 2020-02-20 17:43:14 +01:00
Molkobain
69d816e345 N°2275 - Add XML delta cleanup on datamodel BC breaking changes introduced in 2.7.0 2020-02-20 17:43:14 +01:00
Vincent Dumas
4008cb7688 Add blocks to enable customization 2020-02-20 17:18:39 +01:00
Lars Hippler
41a1bede70 🌐 Update DE-dictionary for iTop 2.7.0 (#113)
Many thanks @r0ert !
2020-02-20 16:04:24 +01:00
odain
e12845e412 N°2651 - Remove test directories from lib 2020-02-20 15:03:36 +01:00
odain
b30ad45792 N°2651 - Fix missing autoload 2020-02-20 14:58:39 +01:00
odain
84a11fb3c1 added namespace + mv iTopComposer + optimize FileIterator 2020-02-20 14:56:08 +01:00
Pierre Goiffon
ee39a387db N°2651 Remove tests from lib : browse dirs using SPL classes instead of GLOB 2020-02-20 14:56:08 +01:00
bruno DA SILVA
e3c6ac814e N°2651 - Removal of "Test" dirs within dependencies handled using composer 2020-02-20 14:56:08 +01:00
Eric
d668d65c70 N°2772 - Fix errors during upgrade. Prevent JS Dict load for setup pages. 2020-02-20 14:45:39 +01:00
Pierre Goiffon
e21e7c9cf0 🌐 N°2795 Fix dict typos 2020-02-20 09:36:33 +01:00
bruno DA SILVA
27a0de1da1 N°2154 - fix server crash in rare cases
Under undetermined circumstances, `exec('php -v')` called the current script triggering an infinite loop crashing the server
problem reported by @molkobain
see: https://stackoverflow.com/questions/43728378/running-php-files-through-shell-exec
2020-02-19 15:43:33 +01:00
Molkobain
d76e54996c PHPDoc 2020-02-19 11:54:50 +01:00
Pierre Goiffon
a4710f7542 N°2760 Abstract classes for extension API interfaces : remove return; for @return void methods 2020-02-18 18:15:45 +01:00
Eric
98a9c680c5 🐛 Updated rest example 2020-02-18 17:02:13 +01:00
Pierre Goiffon
a92157f763 N°2790 fix collapsibleLabel
* change icon when label closed
* fix switch in about dialog for licenses details
2020-02-18 16:34:51 +01:00
bruno DA SILVA
412f1a394f N°2574 - 💚 fix unit test
The behaviours has changed since the "password_renewed_date" is not changed only after the inter/update and no more just aftyer the $oUserLocal->Set('password')
2020-02-18 14:49:53 +01:00
Molkobain
dba6e8ce1a Fix images being too wide in HTML fields and caselogs in the end-users portal
Regression introduced in a previous version of iTop.
2020-02-17 16:29:21 +01:00
Molkobain
a127ca9ca0 N°2313 - Fix regression: No more validation message on password update in the end-users portal 2020-02-17 15:51:38 +01:00
Molkobain
0b5ee1e05c Internal: Fix typo in PHPDoc 2020-02-17 11:24:20 +01:00
Eric
f94e86ecea 🐛 Add missing function 2020-02-14 17:18:00 +01:00
Pierre Goiffon
fe770f36c5 N°2634 / N°2735 Migrate dashlet user prefs to new dashlet ID format 2020-02-14 15:59:09 +01:00
Pierre Goiffon
cf83bc7364 N°2634 / N°2735 Fix dashlets identifiers : was causing prb on widget init, prefs save
Dashlet id now includes :
* "CUSTOM-" if dashlet is contained in a custom dashboard, nothing elsewhere
* the ID of the dashboard
  - for menus : menu id escaped for HTML
  - for AttributeDashboard : <class>__<field>
* the row / cell / dashlet idx

Examples :
CUSTOM-UserRequestOverview_IDrow1-col0-0
Organization__overview_IDrow1-col0-12
2020-02-14 15:59:09 +01:00
Eric
76982a2846 Revert Last change. The values are already protected at this stage. 2020-02-14 15:42:05 +01:00
bruno DA SILVA
4cedd30625 N°2574 - bugfix and UI
- 🐛 fix regression preventing automatic update of password_renewed_date
 - 💄 add a "general information" fieldset
2020-02-13 15:23:56 +01:00
bruno DA SILVA
a86079c477 N°2154 - 🐛 fix an awful typo producing a nonsense
I'm sorry!
2020-02-13 15:21:01 +01:00
Eric
128a237392 N°2746 - Fix Tags configuration screen (removed EnumSet from tag editable list) 2020-02-13 12:31:22 +01:00
Eric
0ecfffe413 N°2746 - Fix export separator 2020-02-13 12:12:35 +01:00
Eric
ef3bdd63a4 N°2746 - Fix search from shortcut 2020-02-13 11:56:19 +01:00
Eric
585135c6c7 N°2758 - Keep AddCondition to avoid BC break 2020-02-13 11:56:01 +01:00
Eric
b3faa96a45 🌐 Add Trigger context label 2020-02-13 09:53:55 +01:00
Eric
6f04525cdf 🎨 cleanup code 2020-02-13 09:49:58 +01:00
Pierre Goiffon
03834fedb8 N°2369 deprecate MySQL views 2020-02-12 18:11:12 +01:00
Vincent Dumas
6bde8e867f Move menu "Universal Search" under "Query" 2020-02-12 18:01:38 +01:00
Molkobain
0e3d195250 N°2275 - Fix XML delta computation putting flags on wrong XML levels 2020-02-12 17:40:53 +01:00
Pierre Goiffon
fae8c9edbd N°2780 Add ContextTag::TAG_CONSOLE for ajax operations 2020-02-12 17:20:10 +01:00
Pierre Goiffon
133d267aca N°2329 Update TCPDF to version fixing unlink bug
Was updated to 6.3.2 fot PHP 7.4 compat, but this version had a regression (issue 159 in the original repo)
This commit integrates 6.3.4 that includes a fix for issue 159
2020-02-12 15:23:57 +01:00
Stephen Abello
166986f336 N°2314 - Markup extensibility: Replace some hardcoded values by overloadable variables 2020-02-12 14:53:19 +01:00
Stephen Abello
f76d649d1a Wee cleanup 2020-02-12 14:53:19 +01:00
Stephen Abello
30747b92c7 N°2755 - Security hardening 2020-02-12 14:53:19 +01:00
Stephen Abello
12ce718662 Internal: Add HtmlEntityDecode() to utils, a counterpart to HtmlEntities() 2020-02-12 14:53:19 +01:00
Molkobain
a1cdb46663 Internal: Refactor newsroom SCSS rules to real SCSS 2020-02-12 14:20:27 +01:00
Pierre Goiffon
824d8398a3 N°2634 / N°2735 Allow saving list prefs for all DashletObjectList
The id generated for the dashlets in the markup is the one used in the saved appUserPreferences. As no control is done during compilation nor in the Designer editor, we could have duplicates.
The first fix (081ba68a) was adding a generated suffix, but for default dashlet this was generated each time so the id was different on every page load ! For custom dashlets as their definition was saved in a XML file it was ok.
This new fix adds a prefix containing row and col id, so every time the id is the same. No duplicates should be found in the same cell.
2020-02-12 14:07:57 +01:00
Eric
406774aa15 N°2746 - Fix Import/Export using labels or code 2020-02-12 12:08:40 +01:00
Pierre Goiffon
dd8712e2e8 📝 Add more doc for \DBObject::GetAsHTML 2020-02-12 11:44:00 +01:00
Eric
767bcdf117 N°2746 - Fix unit tests (typo) 2020-02-11 17:00:55 +01:00
Eric
5e060737df N°2746 - Fix unit tests 2020-02-11 16:46:24 +01:00
Eric
d9bf0fe012 N°2746 - Fix breadcrumb for search of enumSet 2020-02-11 16:02:55 +01:00
Eric
93c9783b1a N°2746 - Fix empty search for TagSet 2020-02-11 14:51:22 +01:00
Eric
e9c1467026 N°2746 - Fix "Modify All" fatal error 2020-02-11 14:35:38 +01:00
Eric
863cb4cad6 N°2758 - Allow only one condition on ValueSetDef and restore cache 2020-02-11 11:54:00 +01:00
Pierre Goiffon
94b70fc473 N°2776 ObjectFormManager : change transaction scope
* move ApplyStimulus & triggers out of the transaction
* move \utils::RemoveTransaction to a finally block
2020-02-11 11:36:59 +01:00
Pierre Goiffon
4dc383cba8 N°2684 Fix setup broke when upgrading with a config file from another directory
In the moduleschoice screens we were using a wrong approot_url !
2020-02-11 09:41:48 +01:00
Pierre Goiffon
55d8a2316a 📝 GetAttributeFlags PHPDoc revised 2020-02-11 08:34:57 +01:00
Stephen Abello
fe8f274c14 N°2314 - Markup extensibility: Replace a hardcoded value by an overloadable variable 2020-02-10 15:33:47 +01:00
Stephen Abello
72fad49c4e N°2314 - Markup extensibility: Add default color to body node 2020-02-10 15:33:47 +01:00
Eric
888d0775e6 N°2758 - Removed ValueSetDef cache 2020-02-10 14:29:28 +01:00
Molkobain
db19f71758 N°2771 - Fix "Unknown form type" when changing user language in portal 2020-02-10 14:20:11 +01:00
Molkobain
a259443735 N°2314 - Markup extensibility: Add attribute flags as metadata to object forms 2020-02-10 13:27:36 +01:00
Pierre Goiffon
58e8ca1f50 📝 GetAttributeFlags PHPDoc 2020-02-10 09:56:31 +01:00
Pierre Goiffon
ab79426508 N°2293 some PHPDoc update 2020-02-07 18:21:02 +01:00
bruno DA SILVA
7e61917521 N°524 - password validity message can be superseded with conf 2020-02-07 17:25:17 +01:00
Molkobain
e42aab30a5 Internal: Fix regression introduced in 3d2a844f ("Close" button always displayed in object forms in IE) 2020-02-07 17:22:41 +01:00
Molkobain
a79ef0bd51 Update (massively) translations before iTop 2.7 release 2020-02-07 16:51:21 +01:00
Eric
5d88391109 N°2758 - Reset ValueSetDef cache when modifying some parameters 2020-02-07 14:27:22 +01:00
Molkobain
c56c04d84d N°2760 - Ease API interfaces implementation through abstract classes 2020-02-06 18:09:59 +01:00
Molkobain
f2b8f50a94 Internal: Add Anne to the sample data to welcome her! 👋 2020-02-06 18:07:51 +01:00
Molkobain
9de11a29fb PHPDoc 2020-02-06 16:25:25 +01:00
Molkobain
6537e00453 Internal: Add Matthieu to the sample data to welcome him! 👋 2020-02-06 15:53:26 +01:00
Eric
dd5f4909da Fix warning 2020-02-06 15:01:02 +01:00
Stephen Abello
ed67df734f N°2755 - Security hardening 2020-02-06 14:50:27 +01:00
Stephen Abello
44894526f1 N°2742 - HTML files preview are now raw text only 2020-02-06 14:27:13 +01:00
xtophe38
de78963b30 Fix DataAdministration translation to be aligned with other menus 2020-02-06 14:25:52 +01:00
bruno DA SILVA
948fd6f0ce N°2154 - improve robustness of submitted config validator
thanks to @molkobain 's awful provider's using PHP 4.4 within CLI
2020-02-06 14:07:39 +01:00
bruno DA SILVA
214dbeef5b N°2154 - var into string patterns can now also be enabled using server vars
- usage: $_SERVER['ITOP_CONFIG_PLACEHOLDERS']
 - plus removal of useless log Trace since this code is too early in iTop's init process for this feature
2020-02-06 14:05:08 +01:00
bruno DA SILVA
f2fbd8457d N°2498 - Authorize map extension
so as `.js.map` is not forbidden by apache
2020-02-06 14:05:08 +01:00
Molkobain
6a432c6a25 N°2757 - Fix count in group by dashlets 2020-02-06 12:12:27 +01:00
Molkobain
e96a8387a0 N°2750 - Regression: Fix default user profile image not shown in portal due to N°2060 2020-02-06 10:06:18 +01:00
Pierre Goiffon
f3576cffb0 📝 README : remove 2.4.* version as this branch isn't supported anymore by Combodo 2020-02-05 14:51:46 +01:00
Molkobain
c5625e6a8d Internal: Fix setup headers style due to 71708cf 2020-02-05 14:49:33 +01:00
Molkobain
3d2a844fef N°2313 - Markup extensibility: Improve success message display during the workflow 2020-02-05 12:10:15 +01:00
Molkobain
110a030902 PHPDoc 2020-02-05 12:10:15 +01:00
Stephen Abello
5ccd885607 Remove DB Tools from excluded modules 2020-02-05 12:04:26 +01:00
Stephen Abello
e5c6efbe69 Merge branch 'master' into develop
# Conflicts:
#	README.md
2020-02-05 11:24:44 +01:00
Stephen Abello
bd083d632f Update readme for 2.6.3 release 2020-02-05 11:22:39 +01:00
Stephen Abello
65b8132914 N°2314 - Markup extensibility: Fix collapsible icons in "About iTop" modal 2020-02-05 09:47:27 +01:00
Eric
3c2130aa72 N°2321 - Fix SQL request generation for inherited magic attributes 2020-02-04 15:54:03 +01:00
Stephen Abello
e70a2f75d3 N°2748 - Fix regression introduced by 71f5d29c, CKEditor's paragraph spacing wasn't coherent with how it's displayed in iTop 2020-02-04 11:41:10 +01:00
Molkobain
fe8e6ba4b0 N°2314 - Markup extensibility: Fix UI elements not using main colors variables 2020-02-04 10:32:57 +01:00
Eric
008614fde6 N°2321 - Fix SQL request generation for inherited magic attributes 2020-02-04 10:28:35 +01:00
Molkobain
ac6e60f5a1 N°2595 - Reorganize admin. console menus: Change new menu groups IDs to avoid collision with existing extensions 2020-02-04 09:50:11 +01:00
Stephen Abello
bf18d623d6 N°2314 - Markup extensibility: Add 2 additional themes for the backoffice
Adds a colored top bar to easily identify different environments (tests, production, ...)
2020-02-03 16:17:46 +01:00
Stephen Abello
10d04756ee N°2314 - Markup extensibility: Fall back on iTop's default theme when a non existing theme is selected 2020-02-03 15:12:59 +01:00
bruno DA SILVA
6e927114e0 N°2154 - 💚 fix tests
- the correct file is now versioned
2020-02-03 12:04:51 +01:00
Pierre Goiffon
682c24a873 N°2293 DBUpdate : save changed fields and corresponding previous values (#111)
* N°2293 DBUpdate : save changed fields and corresponding previous values for callbacks
* update PHPDoc
* remove m_aChanges and ListChangesUpdated() that were introduced in 2.7.0-beta
* add m_aPreviousValuesForUpdatedAttributes and ListPreviousValuesForUpdatedAttributes()

* :memo Woops forgot to change one PHPDoc

* 📝 Some more PHPDoc O:)

* 📝 Add more info in .doc README

* 📝 Well, again some PHPDoc O:)

* 📝 Replace inline @link by @see
@link are for URI, see https://docs.phpdoc.org/latest/references/phpdoc/inline-tags/link.html
2020-01-31 18:01:26 +01:00
bruno DA SILVA
d4b4ced649 🌐 update dictionaries
- set the translation as requested by Q&A
2020-01-31 17:29:38 +01:00
bruno DA SILVA
c2589492d9 📝 documentation generator dependencies handling improvement
- ignore /.doc/vendor
 - uses a lock file (at /.doc/composer.lock)
2020-01-31 17:29:38 +01:00
bruno DA SILVA
15c9cf926e 2154 - preserve "var" in conf
- add possibility to inject var using string patterns (ie: `'%env(DB_HOST)?:localhost%`)
 - on WriteToFile, preserve the non interpreted value when the interpreted value is kept the same
 - added unit tests for both behaviours
 - minor bugfix (default value in comment was wrong) and code readability improvements
2020-01-31 17:29:37 +01:00
Molkobain
78d4c8c7c7 Internal: Fix typo 2020-01-31 17:22:57 +01:00
Eric
d9e8eed084 💚 Fix CI on TagSet search (request have changed) 2020-01-31 16:13:59 +01:00
Eric
ebe86d09ee N°985 - Add applicable contexts on Trigger (logs) 2020-01-30 16:18:49 +01:00
Eric
5e5d368299 N°2657 - MTP : Progress Bar has disappeared (Search exact match) 2020-01-30 16:02:16 +01:00
Molkobain
f990a83453 N°2060 - Migrate error page to the Symfony framework 2020-01-30 13:56:32 +01:00
Molkobain
c6325dce8e Internal: Fix autoloader path for Symfony bin/console utility 2020-01-30 13:56:32 +01:00
Eric
bbca1625fb N°2657 - MTP : Progress Bar has disappeared (Search exact match) 2020-01-30 12:31:22 +01:00
Pierre Goiffon
53975d1d8f 📝 Replace inline @link by @see
@link are for URI, see https://docs.phpdoc.org/latest/references/phpdoc/inline-tags/link.html
2020-01-30 09:35:25 +01:00
Pierre Goiffon
1358bf9b7f 📝 Well, again some PHPDoc O:) 2020-01-30 09:25:53 +01:00
Pierre Goiffon
7c17be4db6 📝 Add more info in .doc README 2020-01-30 09:22:38 +01:00
Pierre Goiffon
367a92b711 📝 Some more PHPDoc O:) 2020-01-30 08:39:18 +01:00
Pierre Goiffon
0a3201dd41 :memo Woops forgot to change one PHPDoc 2020-01-29 18:43:46 +01:00
Pierre Goiffon
d82690dd84 N°2293 DBUpdate : save changed fields and corresponding previous values for callbacks
* update PHPDoc
* remove m_aChanges and ListChangesUpdated() that were introduced in 2.7.0-beta
* add m_aPreviousValuesForUpdatedAttributes and ListPreviousValuesForUpdatedAttributes()
2020-01-29 18:36:46 +01:00
Eric
7f9e4385ac N°2657 - MTP : Progress Bar has disappeared (support any code length) 2020-01-29 18:01:17 +01:00
Stephen Abello
aa3e284af3 Update README for 2.7.0-beta2 2020-01-29 16:59:16 +01:00
Molkobain
bd9da07734 Merge branch 'support/2.5' 2020-01-22 09:55:50 +01:00
Molkobain
3dbbf296b8 Exclude combodo-db-tools module from packages by default 2020-01-22 09:10:54 +01:00
odain
75ba9101a6 add tests to cover this change 2019-12-20 16:13:52 +01:00
odain
df64c184b6 Merge branch 'develop' into feature/perf-serialization 2019-12-20 10:49:29 +01:00
bruno DA SILVA
1ab09702d9 [POC] reduce metamodel serialized size by storing class name instead of class instance. This could be extended to more properties 2019-03-26 14:49:19 +01:00
Guy Couronné
618326d01f Correction unknown attribute id
operation : "core/get"
class : "NetworkDevice"
output_fields : "id,friendlyname" 
key : "SELECT NetworkDevice"

Code 100 “Error: Unknown attribute id from class NetworkDevice”
2019-03-18 08:53:50 +01:00
Guy Couronné
9b8dace833 Optimize Column load when using api core/get
Getting in SQL only desired columns to show
Used when output_fields != '*' || '*+'

Signed-off-by: Guy Couronné <gcouronne@sapiens.biz>
2019-03-15 11:17:58 +01:00
4132 changed files with 151561 additions and 205507 deletions

View File

@@ -23,7 +23,7 @@ Some iTop specific tags were added :
### known limitations:
#### `@see` tags must be very specific:
* always prefix class members with `ClassName::`
* always prefix class members (attributes or methods) with `ClassName::` (do not use self)
* for methods always suffix them with `()`,
* do not reference variables since they are not documented. If you have to, always prefix them with `$`

3015
.doc/composer.lock generated Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -1,3 +1,5 @@
root = true
[*]
charset = utf-8
end_of_line = lf
@@ -11,7 +13,7 @@ ij_formatter_off_tag = @formatter:off
ij_formatter_on_tag = @formatter:on
ij_formatter_tags_enabled = false
ij_smart_tabs = false
ij_visual_guides = 80, 120, 140
ij_visual_guides = 80,120
ij_wrap_on_typing = true
[*.css]
@@ -20,7 +22,8 @@ ij_smart_tabs = true
ij_css_align_closing_brace_with_properties = false
ij_css_blank_lines_around_nested_selector = 1
ij_css_blank_lines_between_blocks = 1
ij_css_brace_placement = 0
ij_css_brace_placement = end_of_line
ij_css_enforce_quotes_on_format = false
ij_css_hex_color_long_format = false
ij_css_hex_color_lower_case = false
ij_css_hex_color_short_format = false
@@ -31,52 +34,8 @@ ij_css_keep_single_line_blocks = false
ij_css_properties_order = font,font-family,font-size,font-weight,font-style,font-variant,font-size-adjust,font-stretch,line-height,position,z-index,top,right,bottom,left,display,visibility,float,clear,overflow,overflow-x,overflow-y,clip,zoom,align-content,align-items,align-self,flex,flex-flow,flex-basis,flex-direction,flex-grow,flex-shrink,flex-wrap,justify-content,order,box-sizing,width,min-width,max-width,height,min-height,max-height,margin,margin-top,margin-right,margin-bottom,margin-left,padding,padding-top,padding-right,padding-bottom,padding-left,table-layout,empty-cells,caption-side,border-spacing,border-collapse,list-style,list-style-position,list-style-type,list-style-image,content,quotes,counter-reset,counter-increment,resize,cursor,user-select,nav-index,nav-up,nav-right,nav-down,nav-left,transition,transition-delay,transition-timing-function,transition-duration,transition-property,transform,transform-origin,animation,animation-name,animation-duration,animation-play-state,animation-timing-function,animation-delay,animation-iteration-count,animation-direction,text-align,text-align-last,vertical-align,white-space,text-decoration,text-emphasis,text-emphasis-color,text-emphasis-style,text-emphasis-position,text-indent,text-justify,letter-spacing,word-spacing,text-outline,text-transform,text-wrap,text-overflow,text-overflow-ellipsis,text-overflow-mode,word-wrap,word-break,tab-size,hyphens,pointer-events,opacity,color,border,border-width,border-style,border-color,border-top,border-top-width,border-top-style,border-top-color,border-right,border-right-width,border-right-style,border-right-color,border-bottom,border-bottom-width,border-bottom-style,border-bottom-color,border-left,border-left-width,border-left-style,border-left-color,border-radius,border-top-left-radius,border-top-right-radius,border-bottom-right-radius,border-bottom-left-radius,border-image,border-image-source,border-image-slice,border-image-width,border-image-outset,border-image-repeat,outline,outline-width,outline-style,outline-color,outline-offset,background,background-color,background-image,background-repeat,background-attachment,background-position,background-position-x,background-position-y,background-clip,background-origin,background-size,box-decoration-break,box-shadow,text-shadow
ij_css_space_after_colon = true
ij_css_space_before_opening_brace = true
ij_css_value_alignment = 0
[*.csv]
max_line_length = 2147483647
ij_wrap_on_typing = false
ij_csv_wrap_long_lines = false
[*.feature]
indent_size = 2
ij_gherkin_keep_indents_on_empty_lines = false
[*.less]
indent_size = 2
ij_less_align_closing_brace_with_properties = false
ij_less_blank_lines_around_nested_selector = 1
ij_less_blank_lines_between_blocks = 1
ij_less_brace_placement = 0
ij_less_hex_color_long_format = false
ij_less_hex_color_lower_case = false
ij_less_hex_color_short_format = false
ij_less_hex_color_upper_case = false
ij_less_keep_blank_lines_in_code = 2
ij_less_keep_indents_on_empty_lines = false
ij_less_keep_single_line_blocks = false
ij_less_properties_order = font,font-family,font-size,font-weight,font-style,font-variant,font-size-adjust,font-stretch,line-height,position,z-index,top,right,bottom,left,display,visibility,float,clear,overflow,overflow-x,overflow-y,clip,zoom,align-content,align-items,align-self,flex,flex-flow,flex-basis,flex-direction,flex-grow,flex-shrink,flex-wrap,justify-content,order,box-sizing,width,min-width,max-width,height,min-height,max-height,margin,margin-top,margin-right,margin-bottom,margin-left,padding,padding-top,padding-right,padding-bottom,padding-left,table-layout,empty-cells,caption-side,border-spacing,border-collapse,list-style,list-style-position,list-style-type,list-style-image,content,quotes,counter-reset,counter-increment,resize,cursor,user-select,nav-index,nav-up,nav-right,nav-down,nav-left,transition,transition-delay,transition-timing-function,transition-duration,transition-property,transform,transform-origin,animation,animation-name,animation-duration,animation-play-state,animation-timing-function,animation-delay,animation-iteration-count,animation-direction,text-align,text-align-last,vertical-align,white-space,text-decoration,text-emphasis,text-emphasis-color,text-emphasis-style,text-emphasis-position,text-indent,text-justify,letter-spacing,word-spacing,text-outline,text-transform,text-wrap,text-overflow,text-overflow-ellipsis,text-overflow-mode,word-wrap,word-break,tab-size,hyphens,pointer-events,opacity,color,border,border-width,border-style,border-color,border-top,border-top-width,border-top-style,border-top-color,border-right,border-right-width,border-right-style,border-right-color,border-bottom,border-bottom-width,border-bottom-style,border-bottom-color,border-left,border-left-width,border-left-style,border-left-color,border-radius,border-top-left-radius,border-top-right-radius,border-bottom-right-radius,border-bottom-left-radius,border-image,border-image-source,border-image-slice,border-image-width,border-image-outset,border-image-repeat,outline,outline-width,outline-style,outline-color,outline-offset,background,background-color,background-image,background-repeat,background-attachment,background-position,background-position-x,background-position-y,background-clip,background-origin,background-size,box-decoration-break,box-shadow,text-shadow
ij_less_space_after_colon = true
ij_less_space_before_opening_brace = true
ij_less_value_alignment = 0
[*.sass]
indent_size = 2
ij_sass_align_closing_brace_with_properties = false
ij_sass_blank_lines_around_nested_selector = 1
ij_sass_blank_lines_between_blocks = 1
ij_sass_brace_placement = 0
ij_sass_hex_color_long_format = false
ij_sass_hex_color_lower_case = false
ij_sass_hex_color_short_format = false
ij_sass_hex_color_upper_case = false
ij_sass_keep_blank_lines_in_code = 2
ij_sass_keep_indents_on_empty_lines = false
ij_sass_keep_single_line_blocks = false
ij_sass_properties_order = font,font-family,font-size,font-weight,font-style,font-variant,font-size-adjust,font-stretch,line-height,position,z-index,top,right,bottom,left,display,visibility,float,clear,overflow,overflow-x,overflow-y,clip,zoom,align-content,align-items,align-self,flex,flex-flow,flex-basis,flex-direction,flex-grow,flex-shrink,flex-wrap,justify-content,order,box-sizing,width,min-width,max-width,height,min-height,max-height,margin,margin-top,margin-right,margin-bottom,margin-left,padding,padding-top,padding-right,padding-bottom,padding-left,table-layout,empty-cells,caption-side,border-spacing,border-collapse,list-style,list-style-position,list-style-type,list-style-image,content,quotes,counter-reset,counter-increment,resize,cursor,user-select,nav-index,nav-up,nav-right,nav-down,nav-left,transition,transition-delay,transition-timing-function,transition-duration,transition-property,transform,transform-origin,animation,animation-name,animation-duration,animation-play-state,animation-timing-function,animation-delay,animation-iteration-count,animation-direction,text-align,text-align-last,vertical-align,white-space,text-decoration,text-emphasis,text-emphasis-color,text-emphasis-style,text-emphasis-position,text-indent,text-justify,letter-spacing,word-spacing,text-outline,text-transform,text-wrap,text-overflow,text-overflow-ellipsis,text-overflow-mode,word-wrap,word-break,tab-size,hyphens,pointer-events,opacity,color,border,border-width,border-style,border-color,border-top,border-top-width,border-top-style,border-top-color,border-right,border-right-width,border-right-style,border-right-color,border-bottom,border-bottom-width,border-bottom-style,border-bottom-color,border-left,border-left-width,border-left-style,border-left-color,border-radius,border-top-left-radius,border-top-right-radius,border-bottom-right-radius,border-bottom-left-radius,border-image,border-image-source,border-image-slice,border-image-width,border-image-outset,border-image-repeat,outline,outline-width,outline-style,outline-color,outline-offset,background,background-color,background-image,background-repeat,background-attachment,background-position,background-position-x,background-position-y,background-clip,background-origin,background-size,box-decoration-break,box-shadow,text-shadow
ij_sass_space_after_colon = true
ij_sass_space_before_opening_brace = true
ij_sass_value_alignment = 0
ij_css_use_double_quotes = true
ij_css_value_alignment = do_not_align
[*.scss]
indent_style = tab
@@ -84,6 +43,7 @@ ij_scss_align_closing_brace_with_properties = false
ij_scss_blank_lines_around_nested_selector = 1
ij_scss_blank_lines_between_blocks = 1
ij_scss_brace_placement = 0
ij_scss_enforce_quotes_on_format = false
ij_scss_hex_color_long_format = false
ij_scss_hex_color_lower_case = false
ij_scss_hex_color_short_format = false
@@ -94,6 +54,7 @@ ij_scss_keep_single_line_blocks = false
ij_scss_properties_order = font,font-family,font-size,font-weight,font-style,font-variant,font-size-adjust,font-stretch,line-height,position,z-index,top,right,bottom,left,display,visibility,float,clear,overflow,overflow-x,overflow-y,clip,zoom,align-content,align-items,align-self,flex,flex-flow,flex-basis,flex-direction,flex-grow,flex-shrink,flex-wrap,justify-content,order,box-sizing,width,min-width,max-width,height,min-height,max-height,margin,margin-top,margin-right,margin-bottom,margin-left,padding,padding-top,padding-right,padding-bottom,padding-left,table-layout,empty-cells,caption-side,border-spacing,border-collapse,list-style,list-style-position,list-style-type,list-style-image,content,quotes,counter-reset,counter-increment,resize,cursor,user-select,nav-index,nav-up,nav-right,nav-down,nav-left,transition,transition-delay,transition-timing-function,transition-duration,transition-property,transform,transform-origin,animation,animation-name,animation-duration,animation-play-state,animation-timing-function,animation-delay,animation-iteration-count,animation-direction,text-align,text-align-last,vertical-align,white-space,text-decoration,text-emphasis,text-emphasis-color,text-emphasis-style,text-emphasis-position,text-indent,text-justify,letter-spacing,word-spacing,text-outline,text-transform,text-wrap,text-overflow,text-overflow-ellipsis,text-overflow-mode,word-wrap,word-break,tab-size,hyphens,pointer-events,opacity,color,border,border-width,border-style,border-color,border-top,border-top-width,border-top-style,border-top-color,border-right,border-right-width,border-right-style,border-right-color,border-bottom,border-bottom-width,border-bottom-style,border-bottom-color,border-left,border-left-width,border-left-style,border-left-color,border-radius,border-top-left-radius,border-top-right-radius,border-bottom-right-radius,border-bottom-left-radius,border-image,border-image-source,border-image-slice,border-image-width,border-image-outset,border-image-repeat,outline,outline-width,outline-style,outline-color,outline-offset,background,background-color,background-image,background-repeat,background-attachment,background-position,background-position-x,background-position-y,background-clip,background-origin,background-size,box-decoration-break,box-shadow,text-shadow
ij_scss_space_after_colon = true
ij_scss_space_before_opening_brace = true
ij_scss_use_double_quotes = true
ij_scss_value_alignment = 0
[*.twig]
@@ -101,6 +62,7 @@ indent_style = tab
ij_smart_tabs = true
ij_wrap_on_typing = false
ij_twig_keep_indents_on_empty_lines = false
ij_twig_spaces_inside_comments_delimiters = true
ij_twig_spaces_inside_delimiters = true
ij_twig_spaces_inside_variable_delimiters = true
@@ -112,6 +74,36 @@ ij_editorconfig_space_before_colon = false
ij_editorconfig_space_before_comma = false
ij_editorconfig_spaces_around_assignment_operators = true
[{*.ant,*.fxml,*.jhm,*.jnlp,*.jrxml,*.rng,*.tld,*.wsdl,*.xml,*.xsd,*.xsl,*.xslt,*.xul,phpunit.xml.dist}]
indent_size = 2
tab_width = 2
ij_smart_tabs = true
ij_xml_align_attributes = true
ij_xml_align_text = false
ij_xml_attribute_wrap = normal
ij_xml_block_comment_at_first_column = true
ij_xml_keep_blank_lines = 2
ij_xml_keep_indents_on_empty_lines = false
ij_xml_keep_line_breaks = false
ij_xml_keep_line_breaks_in_text = true
ij_xml_keep_whitespaces = false
ij_xml_keep_whitespaces_around_cdata = preserve
ij_xml_keep_whitespaces_inside_cdata = true
ij_xml_line_comment_at_first_column = true
ij_xml_space_after_tag_name = false
ij_xml_space_around_equals_in_attribute = false
ij_xml_space_inside_empty_tag = false
ij_xml_text_wrap = normal
[{*.bash,*.sh,*.zsh}]
indent_size = 2
tab_width = 2
ij_shell_binary_ops_start_line = false
ij_shell_keep_column_alignment_padding = false
ij_shell_minify_program = false
ij_shell_redirect_followed_by_space = false
ij_shell_switch_cases_indented = false
[{*.cjs,*.js}]
indent_style = tab
ij_continuation_indent_size = 4
@@ -134,13 +126,13 @@ ij_javascript_array_initializer_wrap = off
ij_javascript_assignment_wrap = off
ij_javascript_binary_operation_sign_on_next_line = false
ij_javascript_binary_operation_wrap = off
ij_javascript_blacklist_imports = rxjs/Rx,node_modules/**/*
ij_javascript_blacklist_imports = rxjs/Rx,node_modules/**,**/node_modules/**,@angular/material,@angular/material/typings/**
ij_javascript_blank_lines_after_imports = 1
ij_javascript_blank_lines_around_class = 1
ij_javascript_blank_lines_around_field = 0
ij_javascript_blank_lines_around_function = 1
ij_javascript_blank_lines_around_method = 1
ij_javascript_block_brace_style = next_line
ij_javascript_block_brace_style = end_of_line
ij_javascript_call_parameters_new_line_after_left_paren = false
ij_javascript_call_parameters_right_paren_on_new_line = false
ij_javascript_call_parameters_wrap = off
@@ -148,15 +140,15 @@ ij_javascript_catch_on_new_line = false
ij_javascript_chained_call_dot_on_new_line = true
ij_javascript_class_brace_style = end_of_line
ij_javascript_comma_on_new_line = false
ij_javascript_do_while_brace_force = never
ij_javascript_else_on_new_line = true
ij_javascript_do_while_brace_force = always
ij_javascript_else_on_new_line = false
ij_javascript_enforce_trailing_comma = keep
ij_javascript_extends_keyword_wrap = off
ij_javascript_extends_list_wrap = off
ij_javascript_field_prefix = _
ij_javascript_file_name_style = relaxed
ij_javascript_finally_on_new_line = false
ij_javascript_for_brace_force = never
ij_javascript_for_brace_force = always
ij_javascript_for_statement_new_line_after_left_paren = false
ij_javascript_for_statement_right_paren_on_new_line = false
ij_javascript_for_statement_wrap = off
@@ -192,6 +184,9 @@ ij_javascript_parentheses_expression_new_line_after_left_paren = false
ij_javascript_parentheses_expression_right_paren_on_new_line = false
ij_javascript_place_assignment_sign_on_next_line = false
ij_javascript_prefer_as_type_cast = false
ij_javascript_prefer_explicit_types_function_expression_returns = false
ij_javascript_prefer_explicit_types_function_returns = false
ij_javascript_prefer_explicit_types_vars_fields = false
ij_javascript_prefer_parameters_wrap = false
ij_javascript_reformat_c_style_comments = false
ij_javascript_space_after_colon = true
@@ -272,11 +267,11 @@ ij_javascript_use_path_mapping = always
ij_javascript_use_public_modifier = false
ij_javascript_use_semicolon_after_statement = true
ij_javascript_var_declaration_wrap = normal
ij_javascript_while_brace_force = never
ij_javascript_while_brace_force = always
ij_javascript_while_on_new_line = false
ij_javascript_wrap_comments = false
[{*.module,*.hphp,*.phtml,*.php5,*.php4,*.php,*.ctp,*.inc}]
[{*.ctp,*.hphp,*.inc,*.module,*.php,*.php4,*.php5,*.phtml}]
indent_style = tab
ij_continuation_indent_size = 4
ij_smart_tabs = true
@@ -296,12 +291,13 @@ ij_php_align_multiline_parameters_in_calls = false
ij_php_align_multiline_ternary_operation = false
ij_php_align_phpdoc_comments = false
ij_php_align_phpdoc_param_names = false
ij_php_anonymous_brace_style = end_of_line
ij_php_api_weight = 1
ij_php_array_initializer_new_line_after_left_brace = true
ij_php_array_initializer_right_brace_on_new_line = true
ij_php_array_initializer_wrap = on_every_item
ij_php_assignment_wrap = off
ij_php_author_weight = 7
ij_php_author_weight = 8
ij_php_binary_operation_sign_on_next_line = false
ij_php_binary_operation_wrap = off
ij_php_blank_lines_after_class_header = 0
@@ -318,7 +314,8 @@ ij_php_blank_lines_before_imports = 1
ij_php_blank_lines_before_method_body = 0
ij_php_blank_lines_before_package = 1
ij_php_blank_lines_before_return_statement = 1
ij_php_block_brace_style = next_line
ij_php_blank_lines_between_imports = 0
ij_php_block_brace_style = end_of_line
ij_php_call_parameters_new_line_after_left_paren = false
ij_php_call_parameters_right_paren_on_new_line = false
ij_php_call_parameters_wrap = normal
@@ -328,11 +325,11 @@ ij_php_class_brace_style = next_line
ij_php_comma_after_last_array_element = true
ij_php_concat_spaces = false
ij_php_copyright_weight = 28
ij_php_deprecated_weight = 28
ij_php_deprecated_weight = 2
ij_php_do_while_brace_force = always
ij_php_else_if_style = as_is
ij_php_else_on_new_line = true
ij_php_example_weight = 3
ij_php_else_on_new_line = false
ij_php_example_weight = 4
ij_php_extends_keyword_wrap = off
ij_php_extends_list_wrap = off
ij_php_fields_default_visibility = private
@@ -343,6 +340,8 @@ ij_php_for_statement_new_line_after_left_paren = false
ij_php_for_statement_right_paren_on_new_line = false
ij_php_for_statement_wrap = off
ij_php_force_short_declaration_array_style = false
ij_php_getters_setters_naming_style = camel_case
ij_php_getters_setters_order_style = getters_first
ij_php_global_weight = 28
ij_php_group_use_wrap = on_every_item
ij_php_if_brace_force = always
@@ -362,7 +361,8 @@ ij_php_keep_control_statement_in_one_line = true
ij_php_keep_first_column_comment = true
ij_php_keep_indents_on_empty_lines = false
ij_php_keep_line_breaks = true
ij_php_keep_rparen_and_lbrace_on_one_line = true
ij_php_keep_rparen_and_lbrace_on_one_line = false
ij_php_keep_simple_classes_in_one_line = false
ij_php_keep_simple_methods_in_one_line = false
ij_php_lambda_brace_style = end_of_line
ij_php_license_weight = 28
@@ -370,6 +370,7 @@ ij_php_line_comment_add_space = false
ij_php_line_comment_at_first_column = true
ij_php_link_weight = 28
ij_php_lower_case_boolean_const = true
ij_php_lower_case_keywords = true
ij_php_lower_case_null_const = true
ij_php_method_brace_style = next_line
ij_php_method_call_chain_wrap = off
@@ -380,9 +381,10 @@ ij_php_method_weight = 28
ij_php_modifier_list_wrap = false
ij_php_multiline_chained_calls_semicolon_on_new_line = false
ij_php_namespace_brace_style = 1
ij_php_new_line_after_php_opening_tag = false
ij_php_null_type_position = in_the_end
ij_php_package_weight = 28
ij_php_param_weight = 4
ij_php_param_weight = 5
ij_php_parentheses_expression_new_line_after_left_paren = false
ij_php_parentheses_expression_right_paren_on_new_line = false
ij_php_phpdoc_blank_line_before_tags = true
@@ -399,8 +401,8 @@ ij_php_property_read_weight = 28
ij_php_property_weight = 28
ij_php_property_write_weight = 28
ij_php_return_type_on_new_line = false
ij_php_return_weight = 5
ij_php_see_weight = 2
ij_php_return_weight = 6
ij_php_see_weight = 3
ij_php_since_weight = 28
ij_php_sort_phpdoc_elements = true
ij_php_space_after_colon = true
@@ -433,6 +435,7 @@ ij_php_space_before_method_call_parentheses = false
ij_php_space_before_method_left_brace = true
ij_php_space_before_method_parentheses = false
ij_php_space_before_quest = true
ij_php_space_before_short_closure_left_parenthesis = false
ij_php_space_before_switch_left_brace = true
ij_php_space_before_switch_parentheses = true
ij_php_space_before_try_left_brace = true
@@ -465,11 +468,11 @@ ij_php_spaces_within_parentheses = false
ij_php_spaces_within_short_echo_tags = true
ij_php_spaces_within_switch_parentheses = false
ij_php_spaces_within_while_parentheses = false
ij_php_special_else_if_treatment = false
ij_php_special_else_if_treatment = true
ij_php_subpackage_weight = 28
ij_php_ternary_operation_signs_on_next_line = false
ij_php_ternary_operation_wrap = off
ij_php_throws_weight = 6
ij_php_throws_weight = 7
ij_php_todo_weight = 28
ij_php_unknown_tag_weight = 28
ij_php_upper_case_boolean_const = false
@@ -481,7 +484,20 @@ ij_php_version_weight = 28
ij_php_while_brace_force = always
ij_php_while_on_new_line = false
[{*.sht,*.htm,*.html,*.shtm,*.shtml}]
[{*.har,*.jsb2,*.jsb3,*.json,.babelrc,.eslintrc,.stylelintrc,bowerrc,composer.lock,jest.config}]
indent_size = 2
ij_json_keep_blank_lines_in_code = 0
ij_json_keep_indents_on_empty_lines = false
ij_json_keep_line_breaks = true
ij_json_space_after_colon = true
ij_json_space_after_comma = true
ij_json_space_before_colon = true
ij_json_space_before_comma = false
ij_json_spaces_within_braces = false
ij_json_spaces_within_brackets = false
ij_json_wrap_long_lines = false
[{*.htm,*.html,*.sht,*.shtm,*.shtml}]
indent_style = tab
ij_smart_tabs = true
ij_html_add_new_line_before_tags = body,div,p,form,h1,h2,h3
@@ -503,209 +519,18 @@ ij_html_keep_whitespaces_inside = span,pre,textarea
ij_html_line_comment_at_first_column = true
ij_html_new_line_after_last_attribute = never
ij_html_new_line_before_first_attribute = never
ij_html_quote_style = double
ij_html_quote_style = none
ij_html_remove_new_line_before_tags = br
ij_html_space_after_tag_name = false
ij_html_space_around_equality_in_attribute = false
ij_html_space_inside_empty_tag = false
ij_html_text_wrap = normal
ij_html_uniform_ident = false
[{*.ts,*.ats}]
ij_continuation_indent_size = 4
ij_typescript_align_imports = false
ij_typescript_align_multiline_array_initializer_expression = false
ij_typescript_align_multiline_binary_operation = false
ij_typescript_align_multiline_chained_methods = false
ij_typescript_align_multiline_extends_list = false
ij_typescript_align_multiline_for = true
ij_typescript_align_multiline_parameters = true
ij_typescript_align_multiline_parameters_in_calls = false
ij_typescript_align_multiline_ternary_operation = false
ij_typescript_align_object_properties = 0
ij_typescript_align_union_types = false
ij_typescript_align_var_statements = 0
ij_typescript_array_initializer_new_line_after_left_brace = false
ij_typescript_array_initializer_right_brace_on_new_line = false
ij_typescript_array_initializer_wrap = off
ij_typescript_assignment_wrap = off
ij_typescript_binary_operation_sign_on_next_line = false
ij_typescript_binary_operation_wrap = off
ij_typescript_blacklist_imports = rxjs/Rx,node_modules/**/*
ij_typescript_blank_lines_after_imports = 1
ij_typescript_blank_lines_around_class = 1
ij_typescript_blank_lines_around_field = 0
ij_typescript_blank_lines_around_field_in_interface = 0
ij_typescript_blank_lines_around_function = 1
ij_typescript_blank_lines_around_method = 1
ij_typescript_blank_lines_around_method_in_interface = 1
ij_typescript_block_brace_style = end_of_line
ij_typescript_call_parameters_new_line_after_left_paren = false
ij_typescript_call_parameters_right_paren_on_new_line = false
ij_typescript_call_parameters_wrap = off
ij_typescript_catch_on_new_line = false
ij_typescript_chained_call_dot_on_new_line = true
ij_typescript_class_brace_style = end_of_line
ij_typescript_comma_on_new_line = false
ij_typescript_do_while_brace_force = never
ij_typescript_else_on_new_line = false
ij_typescript_enforce_trailing_comma = keep
ij_typescript_extends_keyword_wrap = off
ij_typescript_extends_list_wrap = off
ij_typescript_field_prefix = _
ij_typescript_file_name_style = relaxed
ij_typescript_finally_on_new_line = false
ij_typescript_for_brace_force = never
ij_typescript_for_statement_new_line_after_left_paren = false
ij_typescript_for_statement_right_paren_on_new_line = false
ij_typescript_for_statement_wrap = off
ij_typescript_force_quote_style = false
ij_typescript_force_semicolon_style = false
ij_typescript_function_expression_brace_style = end_of_line
ij_typescript_if_brace_force = never
ij_typescript_import_merge_members = global
ij_typescript_import_prefer_absolute_path = global
ij_typescript_import_sort_members = true
ij_typescript_import_sort_module_name = false
ij_typescript_import_use_node_resolution = true
ij_typescript_imports_wrap = on_every_item
ij_typescript_indent_case_from_switch = true
ij_typescript_indent_chained_calls = true
ij_typescript_indent_package_children = 0
ij_typescript_jsdoc_include_types = false
ij_typescript_jsx_attribute_value = braces
ij_typescript_keep_blank_lines_in_code = 2
ij_typescript_keep_first_column_comment = true
ij_typescript_keep_indents_on_empty_lines = false
ij_typescript_keep_line_breaks = true
ij_typescript_keep_simple_blocks_in_one_line = false
ij_typescript_keep_simple_methods_in_one_line = false
ij_typescript_line_comment_add_space = true
ij_typescript_line_comment_at_first_column = false
ij_typescript_method_brace_style = end_of_line
ij_typescript_method_call_chain_wrap = off
ij_typescript_method_parameters_new_line_after_left_paren = false
ij_typescript_method_parameters_right_paren_on_new_line = false
ij_typescript_method_parameters_wrap = off
ij_typescript_object_literal_wrap = on_every_item
ij_typescript_parentheses_expression_new_line_after_left_paren = false
ij_typescript_parentheses_expression_right_paren_on_new_line = false
ij_typescript_place_assignment_sign_on_next_line = false
ij_typescript_prefer_as_type_cast = false
ij_typescript_prefer_parameters_wrap = false
ij_typescript_reformat_c_style_comments = false
ij_typescript_space_after_colon = true
ij_typescript_space_after_comma = true
ij_typescript_space_after_dots_in_rest_parameter = false
ij_typescript_space_after_generator_mult = true
ij_typescript_space_after_property_colon = true
ij_typescript_space_after_quest = true
ij_typescript_space_after_type_colon = true
ij_typescript_space_after_unary_not = false
ij_typescript_space_before_async_arrow_lparen = true
ij_typescript_space_before_catch_keyword = true
ij_typescript_space_before_catch_left_brace = true
ij_typescript_space_before_catch_parentheses = true
ij_typescript_space_before_class_lbrace = true
ij_typescript_space_before_class_left_brace = true
ij_typescript_space_before_colon = true
ij_typescript_space_before_comma = false
ij_typescript_space_before_do_left_brace = true
ij_typescript_space_before_else_keyword = true
ij_typescript_space_before_else_left_brace = true
ij_typescript_space_before_finally_keyword = true
ij_typescript_space_before_finally_left_brace = true
ij_typescript_space_before_for_left_brace = true
ij_typescript_space_before_for_parentheses = true
ij_typescript_space_before_for_semicolon = false
ij_typescript_space_before_function_left_parenth = true
ij_typescript_space_before_generator_mult = false
ij_typescript_space_before_if_left_brace = true
ij_typescript_space_before_if_parentheses = true
ij_typescript_space_before_method_call_parentheses = false
ij_typescript_space_before_method_left_brace = true
ij_typescript_space_before_method_parentheses = false
ij_typescript_space_before_property_colon = false
ij_typescript_space_before_quest = true
ij_typescript_space_before_switch_left_brace = true
ij_typescript_space_before_switch_parentheses = true
ij_typescript_space_before_try_left_brace = true
ij_typescript_space_before_type_colon = false
ij_typescript_space_before_unary_not = false
ij_typescript_space_before_while_keyword = true
ij_typescript_space_before_while_left_brace = true
ij_typescript_space_before_while_parentheses = true
ij_typescript_spaces_around_additive_operators = true
ij_typescript_spaces_around_arrow_function_operator = true
ij_typescript_spaces_around_assignment_operators = true
ij_typescript_spaces_around_bitwise_operators = true
ij_typescript_spaces_around_equality_operators = true
ij_typescript_spaces_around_logical_operators = true
ij_typescript_spaces_around_multiplicative_operators = true
ij_typescript_spaces_around_relational_operators = true
ij_typescript_spaces_around_shift_operators = true
ij_typescript_spaces_around_unary_operator = false
ij_typescript_spaces_within_array_initializer_brackets = false
ij_typescript_spaces_within_brackets = false
ij_typescript_spaces_within_catch_parentheses = false
ij_typescript_spaces_within_for_parentheses = false
ij_typescript_spaces_within_if_parentheses = false
ij_typescript_spaces_within_imports = false
ij_typescript_spaces_within_interpolation_expressions = false
ij_typescript_spaces_within_method_call_parentheses = false
ij_typescript_spaces_within_method_parentheses = false
ij_typescript_spaces_within_object_literal_braces = false
ij_typescript_spaces_within_object_type_braces = true
ij_typescript_spaces_within_parentheses = false
ij_typescript_spaces_within_switch_parentheses = false
ij_typescript_spaces_within_type_assertion = false
ij_typescript_spaces_within_union_types = true
ij_typescript_spaces_within_while_parentheses = false
ij_typescript_special_else_if_treatment = true
ij_typescript_ternary_operation_signs_on_next_line = false
ij_typescript_ternary_operation_wrap = off
ij_typescript_union_types_wrap = on_every_item
ij_typescript_use_chained_calls_group_indents = false
ij_typescript_use_double_quotes = true
ij_typescript_use_explicit_js_extension = global
ij_typescript_use_path_mapping = always
ij_typescript_use_public_modifier = false
ij_typescript_use_semicolon_after_statement = true
ij_typescript_var_declaration_wrap = normal
ij_typescript_while_brace_force = never
ij_typescript_while_on_new_line = false
ij_typescript_wrap_comments = false
[{*.yml,*.yaml}]
[{*.yaml,*.yml}]
indent_size = 2
ij_continuation_indent_size = 2
ij_yaml_keep_indents_on_empty_lines = false
ij_yaml_keep_line_breaks = true
[{*.zsh,*.bash,*.sh}]
ij_shell_binary_ops_start_line = false
ij_shell_keep_column_alignment_padding = false
ij_shell_minify_program = false
ij_shell_redirect_followed_by_space = false
ij_shell_switch_cases_indented = false
[{.stylelintrc,.eslintrc,.babelrc,jest.config,*.bowerrc,*.jsb3,*.jsb2,*.json}]
indent_size = 2
ij_json_keep_blank_lines_in_code = 0
ij_json_keep_indents_on_empty_lines = false
ij_json_keep_line_breaks = true
ij_json_space_after_colon = true
ij_json_space_after_comma = true
ij_json_space_before_colon = true
ij_json_space_before_comma = false
ij_json_spaces_within_braces = false
ij_json_spaces_within_brackets = false
ij_json_wrap_long_lines = false
[{phpunit.xml.dist,*.jhm,*.rng,*.wsdl,*.fxml,*.xslt,*.jrxml,*.ant,*.xul,*.xsl,*.xsd,*.tld,*.jnlp,*.xml}]
indent_size = 2
indent_style = tab
tab_width = 2
ij_smart_tabs = true
ij_xml_block_comment_at_first_column = true
ij_xml_keep_indents_on_empty_lines = false
ij_xml_line_comment_at_first_column = true
ij_yaml_space_before_colon = true
ij_yaml_spaces_within_braces = true
ij_yaml_spaces_within_brackets = true

View File

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

31
.gitignore vendored
View File

@@ -1,4 +1,15 @@
################################### Temporary ignore rules during 2.8 UI/UX dev - START
/css/backoffice/main.css
# Sass converter
/**/.sass-cache/
################################### Temporary ignore rules during 2.8 UI/UX dev - END
# no slash at the end to handle also symlinks
/toolkit
/env-*
@@ -6,16 +17,16 @@
# maintenance mode (N°2240)
/.maintenance
# listing prevention in conf directory
# composer reserver directory, from sources, populate/update using "composer install"
vendor/*
test/vendor/*
# all conf but listing prevention
/conf/**
!/conf/.htaccess
!/conf/index.php
!/conf/web.config
# composer reserver directory, from sources, populate/update using "composer install"
vendor/*
test/vendor/*
# all datas but listing prevention
/data/**
!/data/.htaccess
@@ -35,11 +46,10 @@ test/vendor/*
# Jetbrains
/.idea/**
!/.idea/encodings.xml
!/.idea/codeStyles
!/.idea/codeStyles/*
!/.idea/inspectionProfiles
!/.idea/inspectionProfiles/*
# doc. generation
/.doc/vendor
#phpdocumentor temp file
ast.dump
@@ -131,3 +141,4 @@ local.properties
.scala_dependencies
.worksheet
/css/setup.css

View File

@@ -1,74 +0,0 @@
<component name="ProjectCodeStyleConfiguration">
<code_scheme name="Project" version="173">
<option name="LINE_SEPARATOR" value="&#10;" />
<option name="RIGHT_MARGIN" value="140" />
<option name="WRAP_WHEN_TYPING_REACHES_RIGHT_MARGIN" value="true" />
<option name="SOFT_MARGINS" value="140" />
<HTMLCodeStyleSettings>
<option name="HTML_DO_NOT_INDENT_CHILDREN_OF" value="html,body,thead,tbody,tfoot,style,script,head" />
</HTMLCodeStyleSettings>
<JSCodeStyleSettings version="0">
<option name="USE_CHAINED_CALLS_GROUP_INDENTS" value="true" />
</JSCodeStyleSettings>
<PHPCodeStyleSettings>
<option name="CONCAT_SPACES" value="false" />
<option name="COMMA_AFTER_LAST_ARRAY_ELEMENT" value="true" />
<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="THROWS_WEIGHT" value="6" />
<option name="PARAM_WEIGHT" value="4" />
<option name="RETURN_WEIGHT" value="5" />
<option name="AUTHOR_WEIGHT" value="7" />
<option name="INTERNAL_WEIGHT" value="0" />
<option name="API_WEIGHT" value="1" />
<option name="EXAMPLE_WEIGHT" value="3" />
<option name="SEE_WEIGHT" value="2" />
<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>
<XML>
<option name="XML_TEXT_WRAP" value="0" />
<option name="XML_KEEP_LINE_BREAKS" value="false" />
<option name="XML_KEEP_WHITE_SPACES_INSIDE_CDATA" value="true" />
</XML>
<codeStyleSettings language="JavaScript">
<option name="BRACE_STYLE" value="2" />
<option name="ELSE_ON_NEW_LINE" value="true" />
<option name="SPACE_AROUND_ADDITIVE_OPERATORS" value="false" />
<option name="IF_BRACE_FORCE" value="3" />
<indentOptions>
<option name="USE_TAB_CHARACTER" value="true" />
</indentOptions>
</codeStyleSettings>
<codeStyleSettings language="PHP">
<option name="BLANK_LINES_AFTER_PACKAGE" value="1" />
<option name="BRACE_STYLE" value="2" />
<option name="ELSE_ON_NEW_LINE" value="true" />
<option name="CATCH_ON_NEW_LINE" value="true" />
<option name="FINALLY_ON_NEW_LINE" value="true" />
<option name="ALIGN_MULTILINE_PARAMETERS" 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">
<option name="WRAP_ON_TYPING" value="1" />
</codeStyleSettings>
</code_scheme>
</component>

View File

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

6
.idea/encodings.xml generated
View File

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

View File

@@ -1,170 +0,0 @@
<component name="InspectionProjectProfileManager">
<profile version="1.0">
<option name="myName" value="Combodo" />
<inspection_tool class="CascadeStringReplacementInspection" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="ForgottenDebugOutputInspection" enabled="true" level="ERROR" enabled_by_default="true">
<option name="configuration">
<list>
<option value="\Codeception\Util\Debug::debug" />
<option value="\Codeception\Util\Debug::pause" />
<option value="\Doctrine\Common\Util\Debug::dump" />
<option value="\Doctrine\Common\Util\Debug::export" />
<option value="\Illuminate\Support\Debug\Dumper::dump" />
<option value="\Symfony\Component\Debug\Debug::enable" />
<option value="\Symfony\Component\Debug\DebugClassLoader::enable" />
<option value="\Symfony\Component\Debug\ErrorHandler::register" />
<option value="\Symfony\Component\Debug\ExceptionHandler::register" />
<option value="\TYPO3\CMS\Core\Utility\DebugUtility::debug" />
<option value="\Zend\Debug\Debug::dump" />
<option value="\Zend\Di\Display\Console::export" />
<option value="dd" />
<option value="debug_print_backtrace" />
<option value="debug_zval_dump" />
<option value="dpm" />
<option value="dpq" />
<option value="dsm" />
<option value="dump" />
<option value="dvm" />
<option value="error_log" />
<option value="kpr" />
<option value="phpinfo" />
<option value="print_r" />
<option value="var_dump" />
<option value="var_export" />
<option value="xdebug_break" />
<option value="xdebug_call_class" />
<option value="xdebug_call_file" />
<option value="xdebug_call_function" />
<option value="xdebug_call_line" />
<option value="xdebug_code_coverage_started" />
<option value="xdebug_debug_zval" />
<option value="xdebug_debug_zval_stdout" />
<option value="xdebug_dump_superglobals" />
<option value="xdebug_enable" />
<option value="xdebug_get_code_coverage" />
<option value="xdebug_get_collected_errors" />
<option value="xdebug_get_declared_vars" />
<option value="xdebug_get_function_stack" />
<option value="xdebug_get_headers" />
<option value="xdebug_get_monitored_functions" />
<option value="xdebug_get_profiler_filename" />
<option value="xdebug_get_stack_depth" />
<option value="xdebug_get_tracefile_name" />
<option value="xdebug_is_enabled" />
<option value="xdebug_memory_usage" />
<option value="xdebug_peak_memory_usage" />
<option value="xdebug_print_function_stack" />
<option value="xdebug_start_code_coverage" />
<option value="xdebug_start_error_collection" />
<option value="xdebug_start_function_monitor" />
<option value="xdebug_start_trace" />
<option value="xdebug_stop_code_coverage" />
<option value="xdebug_stop_error_collection" />
<option value="xdebug_stop_function_monitor" />
<option value="xdebug_stop_trace" />
<option value="xdebug_time_index" />
<option value="xdebug_var_dump" />
</list>
</option>
<option name="migratedIntoUserSpace" value="true" />
</inspection_tool>
<inspection_tool class="HtmlRequiredAltAttribute" enabled="true" level="WEAK WARNING" enabled_by_default="true" />
<inspection_tool class="HtmlRequiredLangAttribute" enabled="true" level="WEAK WARNING" enabled_by_default="true" />
<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="PhpComposerExtensionStubsInspection" 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="PhpShortOpenTagInspection" 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="SecurityAdvisoriesInspection" enabled="true" level="WARNING" enabled_by_default="true">
<option name="optionConfiguration">
<list>
<option value="barryvdh/laravel-debugbar" />
<option value="behat/behat" />
<option value="brianium/paratest" />
<option value="codeception/codeception" />
<option value="codedungeon/phpunit-result-printer" />
<option value="composer/composer" />
<option value="doctrine/coding-standard" />
<option value="filp/whoops" />
<option value="friendsofphp/php-cs-fixer" />
<option value="humbug/humbug" />
<option value="infection/infection" />
<option value="jakub-onderka/php-parallel-lint" />
<option value="johnkary/phpunit-speedtrap" />
<option value="kalessil/production-dependencies-guard" />
<option value="mikey179/vfsStream" />
<option value="mockery/mockery" />
<option value="mybuilder/phpunit-accelerator" />
<option value="orchestra/testbench" />
<option value="pdepend/pdepend" />
<option value="phan/phan" />
<option value="phing/phing" />
<option value="phpcompatibility/php-compatibility" />
<option value="phpmd/phpmd" />
<option value="phpro/grumphp" />
<option value="phpspec/phpspec" />
<option value="phpspec/prophecy" />
<option value="phpstan/phpstan" />
<option value="phpunit/phpunit" />
<option value="povils/phpmnd" />
<option value="roave/security-advisories" />
<option value="satooshi/php-coveralls" />
<option value="sebastian/phpcpd" />
<option value="slevomat/coding-standard" />
<option value="spatie/phpunit-watcher" />
<option value="squizlabs/php_codesniffer" />
<option value="sstalle/php7cc" />
<option value="symfony/debug" />
<option value="symfony/maker-bundle" />
<option value="symfony/phpunit-bridge" />
<option value="symfony/var-dumper" />
<option value="vimeo/psalm" />
<option value="wimg/php-compatibility" />
<option value="wp-coding-standards/wpcs" />
<option value="yiisoft/yii2-coding-standards" />
<option value="yiisoft/yii2-debug" />
<option value="yiisoft/yii2-gii" />
<option value="zendframework/zend-coding-standard" />
<option value="zendframework/zend-debug" />
<option value="zendframework/zend-test" />
</list>
</option>
</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

@@ -1,19 +0,0 @@
<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

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

View File

@@ -1,16 +0,0 @@
#!/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 https://www.combodo.com/documentation/iTopDataModelToolkit-2.3.zip > toolkit.zip
unzip toolkit.zip
rm toolkit.zip
cp -r .jenkins/configuration/default-environment/unattended_install/* toolkit

View File

@@ -1,11 +0,0 @@
#!/usr/bin/env bash
set -x
# on the root dir
# composer install -a # => Not needed anymore (libs were added to git with N°2435)
# under the test dir
cd test
composer install

View File

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

View File

@@ -1,22 +0,0 @@
#!/usr/bin/env bash
set -x
cd test
export DEBUG_UNIT_TEST=0
RUN_NONREG_TESTS=0
if [ $# -ge 1 -a "x$1" == "xtrue" ]
then
export DEBUG_UNIT_TEST=1
else
export DEBUG_UNIT_TEST=0
fi
if [ $# -ge 2 -a "x$2" == "xtrue" ]
then
php vendor/bin/phpunit --log-junit ../var/test/phpunit-log.junit.xml --teamcity
else
#echo php vendor/bin/phpunit --log-junit ../var/test/phpunit-log.junit.xml --teamcity
php vendor/bin/phpunit --log-junit ../var/test/phpunit-log.junit.xml --exclude-group OQL --teamcity
fi

View File

@@ -1,8 +0,0 @@
#!/usr/bin/env bash
set -x
chmod 666 conf/production/config-itop.php
cd toolkit
php unattended_install.php --response_file=default-params.xml --clean=true

View File

@@ -1,284 +0,0 @@
<?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',
'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',
// 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(
'authent-local' => array (
'password_validation.pattern' => '',
),
'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

@@ -1,72 +0,0 @@
<?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>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

@@ -1,208 +0,0 @@
<?php
/**
* Copyright (C) 2013-2019 Combodo SARL
*
* This file is part of iTop.
*
* iTop is free software; you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* iTop is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
*/
//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;
}

View File

@@ -0,0 +1,90 @@
<?php
$iBeginTime = time();
chdir(__DIR__);
$aCommands = [
'php composer/rmDeniedTestDir.php',
'php build/commands/setupCssCompiler.php',
// 'bash /tmp/gabuzomeu.sh',
];
$aFailedCommands=[];
foreach ($aCommands as $sCommand)
{
if (!ExecCommand($sCommand))
{
$aFailedCommands[] = $sCommand;
}
}
$iElapsed = time() - $iBeginTime;
if (count($aFailedCommands))
{
fwrite(STDERR, "\nafterBuild execution failed! (in ${iElapsed}s)\n");
fwrite(STDERR, "List of failling commands:\n - " . implode("\n - ", $aFailedCommands) . "\n");
exit(1);
}
echo "\nDone (${iElapsed}s)\n";
exit(0);
/**
* Executes a command and returns an array with exit code, stdout and stderr content
*
* @param string $cmd - Command to execute
*
* @return bool
* @throws \Exception
*/
function ExecCommand($cmd) {
$iBeginTime = time();
echo sprintf("command: %s", str_pad("$cmd ", 50));
$descriptorspec = array(
0 => array("pipe", "r"), // stdin
1 => array("pipe", "w"), // stdout
2 => array("pipe", "w"), // stderr
);
$process = proc_open($cmd, $descriptorspec, $pipes, __DIR__ . '/..', null);
$stdout = stream_get_contents($pipes[1]);
fclose($pipes[1]);
$stderr = stream_get_contents($pipes[2]);
fclose($pipes[2]);
$iCode = proc_close($process);
$bSuccess = (0 === $iCode);
$iElapsed = time() - $iBeginTime;
if (!$bSuccess) {
fwrite(STDERR, sprintf(
"\nCOMMAND FAILED! (%s) \n - status:%s \n - stderr:%s \n - stdout: %s\n - elapsed:%ss\n\n",
$cmd,
$iCode,
rtrim($stderr),
rtrim($stdout),
$iElapsed
));
}
else
{
echo "| elapsed:${iElapsed}s \n";
}
if (!empty($stderr))
{
fwrite(STDERR, "$stderr\n");
}
if (!empty($stdout))
{
echo "stdout :$stdout\n\n";
}
return $bSuccess;
}

View File

@@ -0,0 +1,51 @@
<?php
/**
* Copyright (C) 2010-2020 Combodo SARL
*
* This file is part of iTop.
*
* iTop is free software; you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* iTop is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with iTop. If not, see <http: *www.gnu.org/licenses/>
*
*/
use Combodo\iTop\Composer\iTopComposer;
$iTopFolder = __DIR__."/../../../";
require_once("$iTopFolder/approot.inc.php");
require_once(APPROOT."/application/utils.inc.php");
if (php_sapi_name() !== 'cli')
{
throw new \Exception('This script can only run from CLI');
}
$sCssFile = APPROOT.'/css/setup.css';
if (file_exists($sCssFile))
{
fwrite(STDERR, "$sCssFile already exists (it should not), removing it.");
if (!unlink($sCssFile))
{
fwrite(STDERR, "Failed to remove $sCssFile, exiting.");
exit(1);
}
}
$sCssRelPath = utils::GetCSSFromSASS('css/setup.scss');
if (!file_exists($sCssFile))
{
fwrite(STDERR, "Failed to compile $sCssFile, exiting.");
exit(1);
}

View File

@@ -0,0 +1,98 @@
<?php
/**
* Copyright (C) 2010-2020 Combodo SARL
*
* This file is part of iTop.
*
* iTop is free software; you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* iTop is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with iTop. If not, see <http: *www.gnu.org/licenses/>
*
*/
$iTopFolder = __DIR__ . "/../../" ;
require_once ("$iTopFolder/approot.inc.php");
$sApproot = APPROOT;
$aTrace = array();
$aParamsConfig = array(
'composer-path' => array(
'default' => 'composer.phar',
)
);
$aParamsConfigNotFound = array_flip(array_keys($aParamsConfig));
$aGivenArgs = $argv;
unset($aGivenArgs[0]);
$aParams = array();
foreach ($aParamsConfig as $sParam => $aConfig)
{
$bParamsFound = false;
foreach ($aGivenArgs as $sGivenArg)
{
if (preg_match("/--$sParam(?:=(?<value>.*))?$/", $sGivenArg, $aMatches))
{
$aParams[$sParam] =
isset($aMatches['value'])
? $aMatches['value']
: true
;
$bParamsFound = true;
unset($aGivenArgs[$sGivenArg]);
}
}
if ($bParamsFound)
{
unset($aParamsConfigNotFound[$sParam]);
}
}
foreach ($aParamsConfigNotFound as $sParamsConfigNotFound => $void)
{
if (isset($aParamsConfig[$sParamsConfigNotFound]['default']))
{
$aParams[$sParamsConfigNotFound] = $aParamsConfig[$sParamsConfigNotFound]['default'];
$aTrace[] = "\e[1;30mUsing default value '{$aParams[$sParamsConfigNotFound]}' for '$sParamsConfigNotFound'\e[0m\n";
continue;
}
die("Missing '$sParamsConfigNotFound'");
}
echo "This command aims at helping you find upgradable dependencies\n";
echo "\e[0;33mBeware of the version colored in orange, they probably introduce BC breaks!\e[0m\n";
$sCommand = "{$aParams['composer-path']} show -loD --working-dir=$sApproot --ansi";
$execCode = exec($sCommand, $output);
$sOutput = implode("\n", $output)."\n";
if (!$execCode)
{
echo "\e[41mFailed to execute '$sCommand'\e[0m\n";
echo "Trace: \n".implode("\n", $aTrace);
}
else
{
$iCountDepdendenciesFound = count($output);
$iCountBc = substr_count($sOutput, '[33m');
echo sprintf("Found \033[44m%d\033[0m upgradable dependencies, including \e[41m%s BC break\e[0m 😱 :\n\n", $iCountDepdendenciesFound, $iCountBc);
}
echo $sOutput;

View File

@@ -0,0 +1,57 @@
<?php
/**
* Copyright (C) 2010-2020 Combodo SARL
*
* This file is part of iTop.
*
* iTop is free software; you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* iTop is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with iTop. If not, see <http: *www.gnu.org/licenses/>
*
*/
use Combodo\iTop\Composer\iTopComposer;
$iTopFolder = __DIR__ . "/../../" ;
require_once ("$iTopFolder/approot.inc.php");
require_once (APPROOT."/setup/setuputils.class.inc.php");
if (php_sapi_name() !== 'cli')
{
throw new \Exception('This script can only run from CLI');
}
clearstatcache();
$oiTopComposer = new iTopComposer();
$aDeniedButStillPresent = $oiTopComposer->ListDeniedButStillPresent();
foreach ($aDeniedButStillPresent as $sDir)
{
if (! preg_match('#[tT]ests?/?$#', $sDir))
{
echo "\nfound INVALID denied test dir: '$sDir'\n";
throw new \Exception("$sDir must end with /Test/ or /test/");
}
try
{
SetupUtils::rrmdir($sDir);
echo "Remove denied test dir: '$sDir'\n";
}
catch (\Exception $e)
{
echo "\nFAILED to remove denied test dir: '$sDir'\n";
}
}

View File

@@ -34,7 +34,13 @@ do
then
continue
fi
if [ "$subfolder" == "datamodels" ]
then
if [ $(find $l -name module*.php|wc -l) -ne 0 -o $(echo "$l"|grep -c "itop-portal-base") -ne 0 ]
then
continue
fi
fi
dir=$(dirname $(dirname $l))
prod=$(echo $l| sed "s|$dir/||1")
echo $l $subfolder

View File

@@ -0,0 +1,47 @@
<?php
/*******************************************************************************
* Tool to automate version update before release
*
* Will update version in the following files :
*
* * datamodels/2.x/.../module.*.php
* * datamodels/2.x/version.xml
* * css/css-variables.scss $version
*
* Usage :
* `php .make\release\update-versions.php "2.7.0-rc"`
*
* @since 2.7.0
******************************************************************************/
require_once (__DIR__.'/../../approot.inc.php');
require_once (__DIR__.DIRECTORY_SEPARATOR.'update.classes.inc.php');
/** @var \FileVersionUpdater[] $aFilesUpdaters */
$aFilesUpdaters = array(
new iTopVersionFileUpdater(),
new CssVariablesFileUpdater(),
new DatamodelsModulesFiles(),
);
if (count($argv) === 1)
{
echo '/!\ You must pass the new version as parameter';
exit(1);
}
$sVersionLabel = $argv[1];
if (empty($sVersionLabel))
{
echo 'Version passed as parameter is empty !';
exit(2);
}
foreach ($aFilesUpdaters as $oFileVersionUpdater)
{
$oFileVersionUpdater->UpdateAllFiles($sVersionLabel);
}

View File

@@ -0,0 +1,36 @@
<?php
/*******************************************************************************
* Tool to automate datamodel version update in XML
*
* Will update version in the following files :
*
* datamodels/2.x/.../datamodel.*.xml
*
* Usage :
* `php .make\release\update-xml.php "1.7"`
*
* @since 2.7.0
******************************************************************************/
require_once (__DIR__.'/../../approot.inc.php');
require_once (__DIR__.DIRECTORY_SEPARATOR.'update.classes.inc.php');
if (count($argv) === 1)
{
echo '/!\ You must pass the new version as parameter';
exit(1);
}
$sVersionLabel = $argv[1];
if (empty($sVersionLabel))
{
echo 'Version passed as parameter is empty !';
exit(2);
}
$oFileVersionUpdater = new DatamodelsXmlFiles();
$oFileVersionUpdater->UpdateAllFiles($sVersionLabel);

View File

@@ -0,0 +1,169 @@
<?php
/*******************************************************************************
* Classes for updater tools
*
* @see update-versions.php
* @see update-xml.php
******************************************************************************/
require_once (__DIR__.'/../../approot.inc.php');
abstract class FileVersionUpdater
{
/**
* @return string[] full path of files to modify
*/
abstract public function GetFiles();
/**
* Warnign : will consume lots of memory on larger files !
*
* @param string $sVersionLabel
* @param string $sFileContent
* @param string $sFileFullPath
*
* @return string file content with replaced values
*/
abstract public function UpdateFileContent($sVersionLabel, $sFileContent, $sFileFullPath);
public function UpdateAllFiles($sVersionLabel)
{
$aFilesToUpdate = $this->GetFiles();
$sFileUpdaterName = get_class($this);
echo "# Updater : $sFileUpdaterName\n";
foreach ($aFilesToUpdate as $sFileToUpdateFullPath)
{
try
{
$sCurrentFileContent = file_get_contents($sFileToUpdateFullPath);
$sNewFileContent = $this->UpdateFileContent($sVersionLabel, $sCurrentFileContent, $sFileToUpdateFullPath);
file_put_contents($sFileToUpdateFullPath, $sNewFileContent);
echo " - $sFileToUpdateFullPath : OK !\n";
}
catch (Exception $e)
{
echo " - $sFileToUpdateFullPath : Error :(\n";
}
}
}
}
abstract class AbstractSingleFileVersionUpdater extends FileVersionUpdater
{
private $sFileToUpdate;
public function __construct($sFileToUpdate)
{
$this->sFileToUpdate = $sFileToUpdate;
}
public function GetFiles()
{
return array(APPROOT.$this->sFileToUpdate);
}
}
class iTopVersionFileUpdater extends AbstractSingleFileVersionUpdater
{
public function __construct()
{
parent::__construct('datamodels/2.x/version.xml');
}
/**
* @inheritDoc
*/
public function UpdateFileContent($sVersionLabel, $sFileContent, $sFileFullPath)
{
return preg_replace(
'/(<version>)[^<]*(<\/version>)/',
'${1}'.$sVersionLabel.'${2}',
$sFileContent
);
}
}
class CssVariablesFileUpdater extends AbstractSingleFileVersionUpdater
{
public function __construct()
{
parent::__construct('css/css-variables.scss');
}
/**
* @inheritDoc
*/
public function UpdateFileContent($sVersionLabel, $sFileContent, $sFileFullPath)
{
return preg_replace(
'/(\$version: "v)[^"]*(";)/',
'${1}'.$sVersionLabel.'${2}',
$sFileContent
);
}
}
abstract class AbstractGlobFileVersionUpdater extends FileVersionUpdater
{
protected $sGlobPattern;
public function __construct($sGlobPattern)
{
$this->sGlobPattern = $sGlobPattern;
}
public function GetFiles()
{
return glob($this->sGlobPattern);
}
}
class DatamodelsModulesFiles extends AbstractGlobFileVersionUpdater
{
public function __construct()
{
parent::__construct(APPROOT.'datamodels/2.x/*/module.*.php');
}
/**
* @inheritDoc
*/
public function UpdateFileContent($sVersionLabel, $sFileContent, $sFileFullPath)
{
$sModulePath = realpath($sFileFullPath);
$sModuleFileName = basename($sModulePath, 1);
$sModuleName = preg_replace('/[^.]+\.([^.]+)\.php/', '$1', $sModuleFileName);
return preg_replace(
"/('$sModuleName\/)[^']+(')/",
'${1}'.$sVersionLabel.'${2}',
$sFileContent
);
}
}
class DatamodelsXmlFiles extends AbstractGlobFileVersionUpdater
{
public function __construct()
{
parent::__construct(APPROOT.'datamodels/2.x/*/datamodel.*.xml');
}
/**
* @inheritDoc
*/
public function UpdateFileContent($sVersionLabel, $sFileContent, $sFileFullPath)
{
return preg_replace(
'/(<itop_design .* version=")[^"]+(">)/',
'${1}'.$sVersionLabel.'${2}',
$sFileContent
);
}
}

View File

@@ -10,8 +10,8 @@ Here are some guidelines that will help us integrate your work!
### Subjects
You are welcome to create pull requests on any of those subjects:
* 🐛 `:bug:` bug fix
* 🌐 `:globe_with_meridians:` translation / i18n / l10n
* 🐛 bug fix
* 🌐 translation / i18n / l10n
If you want to implement a **new feature**, please [create a corresponding ticket](https://sourceforge.net/p/itop/tickets/new/) for review.
If you ever want to begin implementation, do so in a fork, and add a link to the corresponding commits in the ticket.
@@ -27,7 +27,7 @@ If you have an idea you're sure would benefit to all of iTop users, you may
[create a corresponding ticket](https://sourceforge.net/p/itop/tickets/new/) to submit it, but be warned that there are lots of good
reasons to refuse such changes.
### License
### 📄 License
iTop is distributed under the AGPL-3.0 license (see the [license.txt] file),
your code must comply with this license.
@@ -37,58 +37,69 @@ If you want to use another license, you may [create an extension][wiki new ext].
[wiki new ext]: https://www.itophub.io/wiki/page?id=latest%3Acustomization%3Astart#by_writing_your_own_extension
## Branch model
## 🔀 iTop branch model
TL;DR:
> **create a fork from iTop main repository,
> create a branch based on the develop branch**
When we first start with Git, we were using the [GitFlow](https://nvie.com/posts/a-successful-git-branching-model/) branch model. As
there was some confusions about branches to use for current developed release and previous maintained release, and also because we were
using just a very few of the GitFlow commands, we decided to add just a little modification to this branch model : since april 2020
we don't have anymore a `master` branch.
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:
Here are the branches we use and their meaning :
- develop: ongoing development version
- release/\*: if present, that means we are working on a beta version
- master: previous stable version
- support/\*: maintenance branches for older versions
- `develop`: ongoing development version
- `release/*`: if present, that means we are working on a alpha/beta/rc version for shipping
- `support/*`: maintenance branches for older versions
For example, if no beta version is currently ongoing we could have:
For example, if no version is currently prepared for shipping we could have:
- develop containing future 2.8.0 version
- master containing 2.7.x maintenance version
- support/2.6 containing 2.6.x maintenance version
- support/2.5 containing 2.5.x maintenance version
- `develop` containing future 3.0.0 version
- `support/2.7`: 2.7.x maintenance version
- `support/2.6`: 2.6.x maintenance version
- `support/2.5`: 2.5.x maintenance version
In this example, when 2.8.0-beta is shipped that will become:
In this example, when 3.0.0-beta is shipped that will become:
- develop: future 2.9.0 version
- release/2.8: 2.8.0-beta
- master: 2.7.x maintenance version
- support/2.6 containing 2.6.x maintenance version
- support/2.5 containing 2.5.x maintenance version
- `develop`: future 3.1.0 version
- `release/3.0.0`: 3.0.0-beta
- `support/2.7`: 2.7.x maintenance version
- `support/2.6`: 2.6.x maintenance version
- `support/2.5`: 2.5.x maintenance version
And when 2.8.0 final will be out:
And when 3.0.0 final will be out:
- develop: future 2.9.0 version
- master: 2.8.x maintenance version
- support/2.7 : 2.7.x maintenance version
- support/2.6 containing 2.6.x maintenance version
- support/2.5 containing 2.5.x maintenance version
- `develop`: future 3.1.0 version
- `support/2.8`: 2.8.x maintenance version (will host developments for 3.0.1)
- `support/2.7`: 2.7.x maintenance version
- `support/2.6`: 2.6.x maintenance version
- `support/2.5`: 2.5.x maintenance version
Most of the time you should based your developments on the develop branch.
That may be different if you want to fix a bug, please use develop anyway and ask in your PR if rebase is possible.
Also note that we have a "micro-version" concept : each of those versions have a very small amount of modifications. They are made from
`support/*` branches as well. For example 2.6.2-1 and 2.6.2-2 were made from the `support/2.6.2` branch.
## Coding
### PHP styleguide
Please follow [our guidelines](https://www.itophub.io/wiki/page?id=latest%3Acustomization%3Acoding_standards).
### 🌐 Translations
A [dedicated page](https://www.itophub.io/wiki/page?id=latest%3Acustomization%3Atranslation) is available in the official wiki.
### Tests
### Where to start ?
1. Create a fork from our repository (see [Working with forks - GitHub Help](https://help.github.com/en/github/collaborating-with-issues-and-pull-requests/working-with-forks))
2. Create a branch in this fork, based on the develop branch
3. Code !
Do create a dedicated branch for each modification you want to propose : if you don't it will be very hard to merge back your work !
Most of the time you should based your developments on the develop branch.
That may be different if you want to fix a bug, please use develop anyway and ask in your PR if rebase is possible.
### 🎨 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.
@@ -117,7 +128,7 @@ Our tests are located in the `test/` directory, containing a PHPUnit config file
* 💄 `:lipstick:` Updating the UI and style files.
## Pull request
## 👥 Pull request
When your code is working, please:

74
Jenkinsfile vendored
View File

@@ -1,69 +1,11 @@
pipeline {
agent any
parameters {
booleanParam(name: 'debugMode', defaultValue: 'false', description: 'Debug mode?')
booleanParam(name: 'runNonRegOQLTests', defaultValue: 'false', description: 'Do You want to run legacy OQL regression tests?')
}
stages {
def infra
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'
}
}
}
}
node(){
checkout scm
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 ${debugMode} ${runNonRegOQLTests}'
}
}
}
}
}
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')
}
infra = load '/var/lib/jenkins/workspace/itop-test-infra_master/src/Infra.groovy'
}
infra.call()

View File

@@ -21,21 +21,35 @@ iTop also offers mass import tools and web services to integrate with your IT
- [Data synchronization][18] (for data federation)
## Latest release
- [Changes since the previous version][62]
- [New features][63]
- [Installation notes][64]
- [Download][65]
[62]: https://www.itophub.io/wiki/page?id=latest:release:change_log
[63]: https://www.itophub.io/wiki/page?id=latest:release:start
[64]: https://www.itophub.io/wiki/page?id=latest:install:start
[65]: https://sourceforge.net/projects/itop/files/latest/download
## Resources
- [iTop Forums][1]: community support
- [iTop Tickets][2]: for feature requests and bug reports
- [Releases download][3]
- [Documentation][4] covering both iTop and its official extensions
- [iTop Hub][5] : discover and install extensions !
- [Software requirements][4]
- [Documentation][5] covering both iTop and its official extensions
- [iTop Hub][6] : discover and install extensions !
[1]: https://sourceforge.net/p/itop/discussion/
[2]: https://sourceforge.net/p/itop/tickets/
[3]: https://sourceforge.net/projects/itop/files/itop/
[4]: https://www.itophub.io/wiki
[5]: https://store.itophub.io/en_US/
[4]: https://www.itophub.io/wiki/page?id=latest:install:upgrading_itop
[5]: https://www.itophub.io/wiki
[6]: https://store.itophub.io/en_US/
[10]: https://www.itophub.io/wiki/page?id=latest%3Adatamodel%3Astart#configuration_management_cmdb
[11]: https://www.itophub.io/wiki/page?id=latest%3Adatamodel%3Astart#ticketing
@@ -49,61 +63,6 @@ iTop also offers mass import tools and web services to integrate with your IT
## Last releases
### Versions 2.7.*
- 2.7.0-beta published on December 18, 2019
- [Changes since the previous version][62]
- [New features][63]
- [Migration notes][64]
- [Download iTop 2.7.0-beta][65]
[62]: https://www.itophub.io/wiki/page?id=2_7_0:release:change_log
[63]: https://www.itophub.io/wiki/page?id=2_7_0:release:2_7_whats_new
[64]: https://www.itophub.io/wiki/page?id=2_7_0:install:260_to_270_migration_notes
[65]: https://sourceforge.net/projects/itop/files/itop/2.7.0-beta
### Versions 2.6.*
- 2.6.0 published on January 9, 2019
- [Changes since the previous version][58]
- [New features][59]
- [Migration notes][60]
- [Download iTop 2.6.1][61]
[58]: https://www.itophub.io/wiki/page?id=2_6_0:release:change_log
[59]: https://www.itophub.io/wiki/page?id=2_6_0:release:2_6_whats_new
[60]: https://www.itophub.io/wiki/page?id=2_6_0:install:250_to_260_migration_notes
[61]: https://sourceforge.net/projects/itop/files/itop/2.6.1
### Versions 2.5.*
- 2.5.0 published on July 11, 2018
- [Changes since the previous version][54]
- [New features][55]
- [Migration notes][56]
- [Download iTop 2.5.1][57]
[54]: https://www.itophub.io/wiki/page?id=2_5_0:release:change_log
[55]: https://www.itophub.io/wiki/page?id=2_5_0:release:2_5_whats_new
[56]: https://www.itophub.io/wiki/page?id=2_5_0:install:240_to_250_migration_notes
[57]: https://sourceforge.net/projects/itop/files/itop/2.5.1
### Versions 2.4.*
- 2.4.0 published on November 16, 2017
- [Changes since the previous version][50]
- [New features][51]
- [Migration notes][52]
- [Download iTop 2.4.1][53]
[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
## About Us
iTop development is sponsored, led and supported by [Combodo][0].
@@ -119,10 +78,10 @@ We would like to give a special thank you to the people from the community who c
- Alves, David
- Beck, Pedro
- Bilger, Jean-François
- Bostoen, Jeffrey
- Bostoen, Jeffrey (a.k.a @jbostoen)
- Cardoso, Anderson
- Cassaro, Bruno
- Casteleyn, Thomas
- Casteleyn, Thomas (a.k.a @Hipska)
- Castro, Randall Badilla
- Colantoni, Maria Laura
- Couronné, Guy
@@ -138,6 +97,7 @@ We would like to give a special thank you to the people from the community who c
- Lazcano, Federico
- Lucas, Jonathan
- Malik, Remie
- Mindêllo de Andrade, Lucas (a.k.a @rokam)
- Rosenke, Stephan
- Seki, Shoji
- Shilov, Vladimir

View File

@@ -9,7 +9,7 @@ responsible disclosure and will make every effort to acknowledge your contributi
### iTop vulnerabilities
Please send a procedure to reproduce iTop vulnerabilities to [itop-security@combodo.com](mailto:itop-security@combodo.com).
You can send us a standard "given / then / when" report, including iTop version, impacts, and maybe installed modules or data if they are
You can send us a standard "given / when / then" report, including iTop version, impacts, and maybe installed modules or data if they are
needed to reproduce.
### Dependencies vulnerabilities

View File

@@ -55,7 +55,6 @@ class URP_Profiles extends UserRightsBaseClassGUI
"db_table" => "priv_urp_profiles",
"db_key_field" => "id",
"db_finalclass_field" => "",
"display_template" => "",
);
MetaModel::Init_Params($aParams);
//MetaModel::Init_InheritAttributes();
@@ -170,11 +169,9 @@ class URP_Profiles extends UserRightsBaseClassGUI
function DisplayBareRelations(WebPage $oPage, $bEditMode = false)
{
parent::DisplayBareRelations($oPage, $bEditMode);
if (!$bEditMode)
{
$oPage->SetCurrentTab('UI:UserManagement:GrantMatrix');
$this->DoShowGrantSumary($oPage);
}
$oPage->SetCurrentTab('UI:UserManagement:GrantMatrix');
$this->DoShowGrantSumary($oPage);
}
public static function GetReadOnlyAttributes()
@@ -243,7 +240,6 @@ class URP_UserProfile extends UserRightsBaseClassGUI
"db_table" => "priv_urp_userprofile",
"db_key_field" => "id",
"db_finalclass_field" => "",
"display_template" => "",
);
MetaModel::Init_Params($aParams);
//MetaModel::Init_InheritAttributes();
@@ -349,7 +345,6 @@ class URP_UserOrg extends UserRightsBaseClassGUI
"db_table" => "priv_urp_userorg",
"db_key_field" => "id",
"db_finalclass_field" => "",
"display_template" => "",
);
MetaModel::Init_Params($aParams);
//MetaModel::Init_InheritAttributes();
@@ -434,7 +429,7 @@ class UserRightsProfile extends UserRightsAddOnAPI
// Support drastic data model changes: no organization class (or not writable)!
if (MetaModel::IsValidClass('Organization') && !MetaModel::IsAbstract('Organization'))
{
$oOrg = new Organization();
$oOrg = MetaModel::NewObject('Organization');
$oOrg->Set('name', 'My Company/Department');
$oOrg->Set('code', 'SOMECODE');
$iOrgId = $oOrg->DBInsertNoReload();
@@ -442,17 +437,13 @@ class UserRightsProfile extends UserRightsAddOnAPI
// Support drastic data model changes: no Person class (or not writable)!
if (MetaModel::IsValidClass('Person') && !MetaModel::IsAbstract('Person'))
{
$oContact = new Person();
$oContact = MetaModel::NewObject('Person');
$oContact->Set('name', 'My last name');
$oContact->Set('first_name', 'My first name');
if (MetaModel::IsValidAttCode('Person', 'org_id'))
{
$oContact->Set('org_id', $iOrgId);
}
if (MetaModel::IsValidAttCode('Person', 'phone'))
{
$oContact->Set('phone', '+00 000 000 000');
}
$oContact->Set('email', 'my.email@foo.org');
$iContactId = $oContact->DBInsertNoReload();
}
@@ -561,7 +552,7 @@ class UserRightsProfile extends UserRightsAddOnAPI
/**
* @param $oUser User
* @return array
* @return bool
*/
public function IsAdministrator($oUser)
{
@@ -571,16 +562,22 @@ class UserRightsProfile extends UserRightsAddOnAPI
/**
* @param $oUser User
* @return array
* @return bool
*/
public function IsPortalUser($oUser)
{
// UserRights caches the list for us
return UserRights::HasProfile(PORTAL_PROFILE_NAME, $oUser);
}
/**
* @param $oUser User
* @return bool
*
* @return array
* @throws \ArchivedObjectException
* @throws \CoreException
* @throws \CoreUnexpectedValue
* @throws \MySQLException
*/
public function ListProfiles($oUser)
{

View File

@@ -77,7 +77,6 @@ class URP_Profiles extends UserRightsBaseClassGUI
"db_table" => "priv_urp_profiles",
"db_key_field" => "id",
"db_finalclass_field" => "",
"display_template" => "",
);
MetaModel::Init_Params($aParams);
//MetaModel::Init_InheritAttributes();
@@ -312,11 +311,9 @@ class URP_Profiles extends UserRightsBaseClassGUI
function DisplayBareRelations(WebPage $oPage, $bEditMode = false)
{
parent::DisplayBareRelations($oPage, $bEditMode);
if (!$bEditMode)
{
$oPage->SetCurrentTab('UI:UserManagement:GrantMatrix');
$this->DoShowGrantSumary($oPage);
}
$oPage->SetCurrentTab('UI:UserManagement:GrantMatrix');
$this->DoShowGrantSumary($oPage);
}
}
@@ -336,7 +333,6 @@ class URP_UserProfile extends UserRightsBaseClassGUI
"db_table" => "priv_urp_userprofile",
"db_key_field" => "id",
"db_finalclass_field" => "",
"display_template" => "",
);
MetaModel::Init_Params($aParams);
//MetaModel::Init_InheritAttributes();
@@ -376,7 +372,6 @@ class URP_UserOrg extends UserRightsBaseClassGUI
"db_table" => "priv_urp_userorg",
"db_key_field" => "id",
"db_finalclass_field" => "",
"display_template" => "",
);
MetaModel::Init_Params($aParams);
//MetaModel::Init_InheritAttributes();
@@ -417,7 +412,6 @@ class URP_ActionGrant extends UserRightsBaseClass
"db_table" => "priv_urp_grant_actions",
"db_key_field" => "id",
"db_finalclass_field" => "",
"display_template" => "",
);
MetaModel::Init_Params($aParams);
//MetaModel::Init_InheritAttributes();
@@ -454,7 +448,6 @@ class URP_StimulusGrant extends UserRightsBaseClass
"db_table" => "priv_urp_grant_stimulus",
"db_key_field" => "id",
"db_finalclass_field" => "",
"display_template" => "",
);
MetaModel::Init_Params($aParams);
//MetaModel::Init_InheritAttributes();
@@ -491,7 +484,6 @@ class URP_AttributeGrant extends UserRightsBaseClass
"db_table" => "priv_urp_grant_attributes",
"db_key_field" => "id",
"db_finalclass_field" => "",
"display_template" => "",
);
MetaModel::Init_Params($aParams);
//MetaModel::Init_InheritAttributes();
@@ -535,7 +527,7 @@ class UserRightsProfile extends UserRightsAddOnAPI
// Support drastic data model changes: no organization class (or not writable)!
if (MetaModel::IsValidClass('Organization') && !MetaModel::IsAbstract('Organization'))
{
$oOrg = new Organization();
$oOrg = MetaModel::NewObject('Organization');
$oOrg->Set('name', 'My Company/Department');
$oOrg->Set('code', 'SOMECODE');
$oOrg::SetCurrentChange($oChange);
@@ -544,17 +536,13 @@ class UserRightsProfile extends UserRightsAddOnAPI
// Support drastic data model changes: no Person class (or not writable)!
if (MetaModel::IsValidClass('Person') && !MetaModel::IsAbstract('Person'))
{
$oContact = new Person();
$oContact = MetaModel::NewObject('Person');
$oContact->Set('name', 'My last name');
$oContact->Set('first_name', 'My first name');
if (MetaModel::IsValidAttCode('Person', 'org_id'))
{
$oContact->Set('org_id', $iOrgId);
}
if (MetaModel::IsValidAttCode('Person', 'phone'))
{
$oContact->Set('phone', '+00 000 000 000');
}
$oContact->Set('email', 'my.email@foo.org');
$oContact::SetCurrentChange($oChange);
$iContactId = $oContact->DBInsertNoReload();
@@ -711,7 +699,7 @@ class UserRightsProfile extends UserRightsAddOnAPI
public function LoadCache()
{
if (!is_null($this->m_aProfiles)) return;
if (!is_null($this->m_aProfiles)) return false;
// Could be loaded in a shared memory (?)
$oKPI = new ExecutionKPI();

View File

@@ -58,7 +58,6 @@ class URP_Profiles extends UserRightsBaseClass
"db_table" => "priv_urp_profiles",
"db_key_field" => "id",
"db_finalclass_field" => "",
"display_template" => "",
);
MetaModel::Init_Params($aParams);
//MetaModel::Init_InheritAttributes();
@@ -144,11 +143,9 @@ class URP_Profiles extends UserRightsBaseClass
function DisplayBareRelations(WebPage $oPage, $bEditMode = false)
{
parent::DisplayBareRelations($oPage, $bEditMode);
if (!$bEditMode)
{
$oPage->SetCurrentTab('UI:UserManagement:GrantMatrix');
$this->DoShowGrantSumary($oPage);
}
$oPage->SetCurrentTab('UI:UserManagement:GrantMatrix');
$this->DoShowGrantSumary($oPage);
}
}
@@ -167,7 +164,6 @@ class URP_Dimensions extends UserRightsBaseClass
"db_table" => "priv_urp_dimensions",
"db_key_field" => "id",
"db_finalclass_field" => "",
"display_template" => "",
);
MetaModel::Init_Params($aParams);
//MetaModel::Init_InheritAttributes();
@@ -280,7 +276,6 @@ class URP_UserProfile extends UserRightsBaseClass
"db_table" => "priv_urp_userprofile",
"db_key_field" => "id",
"db_finalclass_field" => "",
"display_template" => "",
);
MetaModel::Init_Params($aParams);
//MetaModel::Init_InheritAttributes();
@@ -321,7 +316,6 @@ class URP_ProfileProjection extends UserRightsBaseClass
"db_table" => "priv_urp_profileprojection",
"db_key_field" => "id",
"db_finalclass_field" => "",
"display_template" => "",
);
MetaModel::Init_Params($aParams);
//MetaModel::Init_InheritAttributes();
@@ -402,7 +396,6 @@ class URP_ClassProjection extends UserRightsBaseClass
"db_table" => "priv_urp_classprojection",
"db_key_field" => "id",
"db_finalclass_field" => "",
"display_template" => "",
);
MetaModel::Init_Params($aParams);
//MetaModel::Init_InheritAttributes();
@@ -474,7 +467,6 @@ class URP_ActionGrant extends UserRightsBaseClass
"db_table" => "priv_urp_grant_actions",
"db_key_field" => "id",
"db_finalclass_field" => "",
"display_template" => "",
);
MetaModel::Init_Params($aParams);
//MetaModel::Init_InheritAttributes();
@@ -511,7 +503,6 @@ class URP_StimulusGrant extends UserRightsBaseClass
"db_table" => "priv_urp_grant_stimulus",
"db_key_field" => "id",
"db_finalclass_field" => "",
"display_template" => "",
);
MetaModel::Init_Params($aParams);
//MetaModel::Init_InheritAttributes();
@@ -548,7 +539,6 @@ class URP_AttributeGrant extends UserRightsBaseClass
"db_table" => "priv_urp_grant_attributes",
"db_key_field" => "id",
"db_finalclass_field" => "",
"display_template" => "",
);
MetaModel::Init_Params($aParams);
//MetaModel::Init_InheritAttributes();

View File

@@ -30,8 +30,11 @@ function mb_str_replace($search, $replace, $subject, &$count = 0) {
$replacements = array_pad($replacements, count($searches), '');
foreach ($searches as $key => $search) {
$parts = mb_split(preg_quote($search), $subject);
$count += count($parts) - 1;
$subject = implode($replacements[$key], $parts);
if (is_array($parts))
{
$count += count($parts) - 1;
$subject = implode($replacements[$key], $parts);
}
}
} else {
// Call mb_str_replace for each subject in array, recursively

View File

@@ -1,414 +1,16 @@
<?php
/**
* Copyright (C) 2013-2020 Combodo SARL
*
* This file is part of iTop.
*
* iTop is free software; you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* iTop is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* @deprecated will be removed in 3.1.0 - moved to sources/application/WebPage/AjaxPage.php
* @license http://opensource.org/licenses/AGPL-3.0
* @copyright Copyright (C) 2010-2020 Combodo SARL
*/
require_once(APPROOT."/application/webpage.class.inc.php");
class ajax_page extends WebPage implements iTabbedPage
/**
* Class ajax_page
* @deprecated will be removed in 3.1.0 - moved to AjaxPage
*/
class ajax_page extends AjaxPage
{
/**
* Jquery style ready script
* @var array
*/
protected $m_sReadyScript;
protected $m_oTabs;
private $m_sMenu; // If set, then the menu will be updated
/**
* constructor for the web page
* @param string $s_title Not used
*/
function __construct($s_title)
{
$sPrintable = utils::ReadParam('printable', '0');
$bPrintable = ($sPrintable == '1');
parent::__construct($s_title, $bPrintable);
$this->m_sReadyScript = "";
//$this->add_header("Content-type: text/html; charset=utf-8");
$this->add_header("Cache-control: no-cache");
$this->m_oTabs = new TabManager();
$this->sContentType = 'text/html';
$this->sContentDisposition = 'inline';
$this->m_sMenu = "";
utils::InitArchiveMode();
}
/**
* @inheritDoc
* @throws \Exception
*/
public function AddTabContainer($sTabContainer, $sPrefix = '')
{
$this->add($this->m_oTabs->AddTabContainer($sTabContainer, $sPrefix));
}
/**
* @inheritDoc
* @throws \Exception
*/
public function AddToTab($sTabContainer, $sTabCode, $sHtml)
{
$this->add($this->m_oTabs->AddToTab($sTabContainer, $sTabCode, $sHtml));
}
/**
* @inheritDoc
*/
public function SetCurrentTabContainer($sTabContainer = '')
{
return $this->m_oTabs->SetCurrentTabContainer($sTabContainer);
}
/**
* @inheritDoc
*/
public function SetCurrentTab($sTabCode = '', $sTabTitle = null)
{
return $this->m_oTabs->SetCurrentTab($sTabCode, $sTabTitle);
}
/**
* @inheritDoc
* @throws \Exception
*/
public function AddAjaxTab($sTabCode, $sUrl, $bCache = true, $sTabTitle = null)
{
$this->add($this->m_oTabs->AddAjaxTab($sTabCode, $sUrl, $bCache, $sTabTitle));
}
/**
* @inheritDoc
*/
public function GetCurrentTab()
{
return $this->m_oTabs->GetCurrentTab();
}
/**
* @inheritDoc
*/
public function RemoveTab($sTabCode, $sTabContainer = null)
{
$this->m_oTabs->RemoveTab($sTabCode, $sTabContainer);
}
/**
* @inheritDoc
*/
public function FindTab($sPattern, $sTabContainer = null)
{
return $this->m_oTabs->FindTab($sPattern, $sTabContainer);
}
/**
* Make the given tab the active one, as if it were clicked
* DOES NOT WORK: apparently in the *old* version of jquery
* that we are using this is not supported... TO DO upgrade
* the whole jquery bundle...
*/
public function SelectTab($sTabContainer, $sTabCode)
{
$this->add_ready_script($this->m_oTabs->SelectTab($sTabContainer, $sTabCode));
}
/**
* @param string $sHtml
*/
public function AddToMenu($sHtml)
{
$this->m_sMenu .= $sHtml;
}
/**
* @inheritDoc
*/
public function output()
{
if (!empty($this->sContentType))
{
$this->add_header('Content-type: '.$this->sContentType);
}
if (!empty($this->sContentDisposition))
{
$this->add_header('Content-Disposition: '.$this->sContentDisposition.'; filename="'.$this->sContentFileName.'"');
}
foreach($this->a_headers as $s_header)
{
header($s_header);
}
if ($this->m_oTabs->TabsContainerCount() > 0)
{
$this->add_ready_script(
<<<EOF
// The "tab widgets" to handle.
var tabs = $('div[id^=tabbedContent]');
// Ugly patch for a change in the behavior of jQuery UI:
// Before jQuery UI 1.9, tabs were always considered as "local" (opposed to Ajax)
// when their href was beginning by #. Starting with 1.9, a <base> tag in the page
// is taken into account and causes "local" tabs to be considered as Ajax
// unless their URL is equal to the URL of the page...
if ($('base').length > 0)
{
$('div[id^=tabbedContent] > ul > li > a').each(function() {
var sHash = location.hash;
var sCleanLocation = location.href.toString().replace(sHash, '').replace(/#$/, '');
$(this).attr("href", sCleanLocation+$(this).attr("href"));
});
}
if ($.bbq)
{
// This selector will be reused when selecting actual tab widget A elements.
var tab_a_selector = 'ul.ui-tabs-nav a';
// Enable tabs on all tab widgets. The `event` property must be overridden so
// that the tabs aren't changed on click, and any custom event name can be
// specified. Note that if you define a callback for the 'select' event, it
// will be executed for the selected tab whenever the hash changes.
tabs.tabs({ event: 'change' });
// Define our own click handler for the tabs, overriding the default.
tabs.find( tab_a_selector ).click(function()
{
var state = {};
// Get the id of this tab widget.
var id = $(this).closest( 'div[id^=tabbedContent]' ).attr( 'id' );
// Get the index of this tab.
var idx = $(this).parent().prevAll().length;
// Set the state!
state[ id ] = idx;
$.bbq.pushState( state );
});
}
else
{
tabs.tabs();
}
EOF
);
}
// Render the tabs in the page (if any)
$this->s_content = $this->m_oTabs->RenderIntoContent($this->s_content, $this);
// Additional UI widgets to be activated inside the ajax fragment
// Important: Testing the content type is not enough because some ajax handlers have not correctly positionned the flag (e.g json response corrupted by the script)
if (($this->sContentType == 'text/html') && (preg_match('/class="date-pick"/', $this->s_content) || preg_match('/class="datetime-pick"/', $this->s_content)) )
{
$this->add_ready_script(
<<<EOF
PrepareWidgets();
EOF
);
}
$this->outputCollapsibleSectionInit();
$oKPI = new ExecutionKPI();
$s_captured_output = $this->ob_get_clean_safe();
if (($this->sContentType == 'text/html') && ($this->sContentDisposition == 'inline'))
{
// inline content != attachment && html => filter all scripts for malicious XSS scripts
echo self::FilterXSS($this->s_content);
}
else
{
echo $this->s_content;
}
if (!empty($this->m_sMenu))
{
$uid = time();
echo "<div id=\"accordion_temp_$uid\">\n";
echo "<div id=\"accordion\">\n";
echo "<!-- Beginning of the accordion menu -->\n";
echo self::FilterXSS($this->m_sMenu);
echo "<!-- End of the accordion menu-->\n";
echo "</div>\n";
echo "</div>\n";
echo "<script type=\"text/javascript\">\n";
echo "$('#inner_menu').html($('#accordion_temp_$uid').html());\n";
echo "$('#accordion_temp_$uid').remove();\n";
echo "\n</script>\n";
}
//echo $this->s_deferred_content;
if (count($this->a_scripts) > 0)
{
echo "<script type=\"text/javascript\">\n";
echo implode("\n", $this->a_scripts);
echo "\n</script>\n";
}
if (count($this->a_linked_scripts) > 0)
{
echo "<script type=\"text/javascript\">\n";
foreach($this->a_linked_scripts as $sScriptUrl)
{
echo '$.getScript('.json_encode($sScriptUrl).");\n";
}
echo "\n</script>\n";
}
if (!empty($this->s_deferred_content))
{
echo "<script type=\"text/javascript\">\n";
echo "\$('body').append('".addslashes(str_replace("\n", '', $this->s_deferred_content))."');\n";
echo "\n</script>\n";
}
if (!empty($this->m_sReadyScript))
{
echo "<script type=\"text/javascript\">\n";
echo $this->m_sReadyScript; // Ready Scripts are output as simple scripts
echo "\n</script>\n";
}
if(count($this->a_linked_stylesheets) > 0)
{
echo "<script type=\"text/javascript\">";
foreach($this->a_linked_stylesheets as $aStylesheet)
{
$sStylesheetUrl = $aStylesheet['link'];
echo "if (!$('link[href=\"{$sStylesheetUrl}\"]').length) $('<link href=\"{$sStylesheetUrl}\" rel=\"stylesheet\">').appendTo('head');\n";
}
echo "\n</script>\n";
}
if (trim($s_captured_output) != "")
{
echo self::FilterXSS($s_captured_output);
}
$oKPI->ComputeAndReport('Echoing');
if (class_exists('DBSearch'))
{
DBSearch::RecordQueryTrace();
}
if (class_exists('ExecutionKPI'))
{
ExecutionKPI::ReportStats();
}
}
/**
* Adds a paragraph with a smaller font into the page
* NOT implemented (i.e does nothing)
* @param string $sText Content of the (small) paragraph
* @return void
*/
public function small_p($sText)
{
}
/**
* @inheritDoc
* @throws \Exception
*/
public function add($sHtml)
{
if (($this->m_oTabs->GetCurrentTabContainer() != '') && ($this->m_oTabs->GetCurrentTab() != ''))
{
$this->m_oTabs->AddToTab($this->m_oTabs->GetCurrentTabContainer(), $this->m_oTabs->GetCurrentTab(), $sHtml);
}
else
{
parent::add($sHtml);
}
}
/**
* @inheritDoc
*/
public function start_capture()
{
$sCurrentTabContainer = $this->m_oTabs->GetCurrentTabContainer();
$sCurrentTab = $this->m_oTabs->GetCurrentTab();
if (!empty($sCurrentTabContainer) && !empty($sCurrentTab))
{
$iOffset = $this->m_oTabs->GetCurrentTabLength();
return array('tc' => $sCurrentTabContainer, 'tab' => $sCurrentTab, 'offset' => $iOffset);
}
else
{
return parent::start_capture();
}
}
/**
* @inheritDoc
*/
public function end_capture($offset)
{
if (is_array($offset))
{
if ($this->m_oTabs->TabExists($offset['tc'], $offset['tab']))
{
$sCaptured = $this->m_oTabs->TruncateTab($offset['tc'], $offset['tab'], $offset['offset']);
}
else
{
$sCaptured = '';
}
}
else
{
$sCaptured = parent::end_capture($offset);
}
return $sCaptured;
}
/**
* @inheritDoc
*/
public function add_at_the_end($s_html, $sId = '')
{
if ($sId != '')
{
$this->add_script("$('#{$sId}').remove();"); // Remove any previous instance of the same Id
}
$this->s_deferred_content .= $s_html;
}
/**
* @inheritDoc
*/
public function add_ready_script($sScript)
{
$this->m_sReadyScript .= $sScript."\n";
}
/**
* @inheritDoc
*/
public function GetUniqueId()
{
assert(false);
return 0;
}
/**
* @inheritDoc
*/
public static function FilterXSS($sHTML)
{
return str_ireplace(array('<script', '</script>'), array('<!-- <removed-script', '</removed-script> -->'), $sHTML);
}
}

View File

@@ -37,4 +37,3 @@ require_once(APPROOT.'/application/utils.inc.php');
class ApplicationException extends CoreException
{
}
?>

View File

@@ -24,19 +24,23 @@
* @license http://opensource.org/licenses/AGPL-3.0
*/
use Combodo\iTop\Application\UI\Component\Input\InputFactory;
use Combodo\iTop\Application\UI\Layout\UIContentBlock;
use Combodo\iTop\Application\UI\UIBlock;
require_once(APPROOT."/application/utils.inc.php");
/**
* Interface for directing end-users to the relevant application
*/
*/
interface iDBObjectURLMaker
{
/**
* @param string $sClass
* @param string $iId
*
* @return string
*/
/**
* @param string $sClass
* @param string $iId
*
* @return string
*/
public static function MakeObjectURL($sClass, $iId);
}
@@ -200,23 +204,46 @@ class ApplicationContext
}
return implode("&", $aParams);
}
/**
* @since 3.0.0 N°2534 - dashboard: bug with autorefresh that deactivates filtering on organisation
* Returns the params as c[menu]:..., c[org_id]:....
* @return string The params
*/
public function GetForPostParams()
{
return json_encode($this->aValues);
}
/**
* Returns the context as sequence of input tags to be inserted inside a <form> tag
*
* @return string The context as a sequence of <input type="hidden" /> tags
*/
public function GetForForm()
{
$sContext = "";
foreach($this->aValues as $sName => $sValue)
{
foreach ($this->aValues as $sName => $sValue) {
$sContext .= "<input type=\"hidden\" name=\"c[$sName]\" value=\"".htmlentities($sValue, ENT_QUOTES, 'UTF-8')."\" />\n";
}
return $sContext;
}
/**
* Returns the context as sequence of input tags to be inserted inside a <form> tag
*
*/
public function GetForFormBlock(): UIBlock
{
$oContext = new UIContentBlock();
foreach ($this->aValues as $sName => $sValue) {
$oContext->AddSubBlock(InputFactory::MakeForHidden('c[$sName]', utils::HtmlEntities($sValue)));
}
return $oContext;
}
/**
* Returns the context as a hash array 'parameter_name' => value
*
* @return array The context information
*/
public function GetAsHash()

View File

@@ -1,20 +1,22 @@
<?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/>
/**
* Copyright (C) 2013-2020 Combodo SARL
*
* This file is part of iTop.
*
* iTop is free software; you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* iTop is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
*/
use Symfony\Component\DependencyInjection\Container;
@@ -30,6 +32,7 @@ require_once(APPROOT.'application/newsroomprovider.class.inc.php');
* @copyright Copyright (C) 2010-2012 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
* @package Extensibility
* @since 2.7.0
*/
interface iLoginExtension
{
@@ -41,6 +44,9 @@ interface iLoginExtension
public function ListSupportedLoginModes();
}
/**
* @since 2.7.0
*/
interface iLoginFSMExtension extends iLoginExtension
{
/**
@@ -58,8 +64,14 @@ interface iLoginFSMExtension extends iLoginExtension
public function LoginAction($sLoginState, &$iErrorCode);
}
/**
* @since 2.7.0
*/
abstract class AbstractLoginFSMExtension implements iLoginFSMExtension
{
/**
* @inheritDoc
*/
public abstract function ListSupportedLoginModes();
/**
@@ -151,27 +163,50 @@ abstract class AbstractLoginFSMExtension implements iLoginFSMExtension
return LoginWebPage::LOGIN_FSM_CONTINUE;
}
/**
* @param int $iErrorCode (see LoginWebPage::EXIT_CODE_...)
*
* @return int LoginWebPage::LOGIN_FSM_RETURN_ERROR, LoginWebPage::LOGIN_FSM_RETURN_OK or LoginWebPage::LOGIN_FSM_RETURN_IGNORE
*/
protected function OnCredentialsOK(&$iErrorCode)
{
return LoginWebPage::LOGIN_FSM_CONTINUE;
}
/**
* @param int $iErrorCode (see LoginWebPage::EXIT_CODE_...)
*
* @return int LoginWebPage::LOGIN_FSM_RETURN_ERROR, LoginWebPage::LOGIN_FSM_RETURN_OK or LoginWebPage::LOGIN_FSM_RETURN_IGNORE
*/
protected function OnUsersOK(&$iErrorCode)
{
return LoginWebPage::LOGIN_FSM_CONTINUE;
}
/**
* @param int $iErrorCode (see LoginWebPage::EXIT_CODE_...)
*
* @return int LoginWebPage::LOGIN_FSM_RETURN_ERROR, LoginWebPage::LOGIN_FSM_RETURN_OK or LoginWebPage::LOGIN_FSM_RETURN_IGNORE
*/
protected function OnConnected(&$iErrorCode)
{
return LoginWebPage::LOGIN_FSM_CONTINUE;
}
/**
* @param int $iErrorCode (see LoginWebPage::EXIT_CODE_...)
*
* @return int LoginWebPage::LOGIN_FSM_RETURN_ERROR, LoginWebPage::LOGIN_FSM_RETURN_OK or LoginWebPage::LOGIN_FSM_RETURN_IGNORE
*/
protected function OnError(&$iErrorCode)
{
return LoginWebPage::LOGIN_FSM_CONTINUE;
}
}
/**
* @since 2.7.0
*/
interface iLogoutExtension extends iLoginExtension
{
/**
@@ -180,6 +215,9 @@ interface iLogoutExtension extends iLoginExtension
public function LogoutAction();
}
/**
* @since 2.7.0
*/
interface iLoginUIExtension extends iLoginExtension
{
/**
@@ -188,7 +226,11 @@ interface iLoginUIExtension extends iLoginExtension
public function GetTwigContext();
}
/**
* @api
* @package Extensibility
* @since 2.7.0
*/
interface iPreferencesExtension
{
/**
@@ -206,6 +248,33 @@ interface iPreferencesExtension
public function ApplyPreferences(WebPage $oPage, $sOperation);
}
/**
* Extend this class instead of implementing iPreferencesExtension if you don't need to overload all methods
*
* @api
* @package Extensibility
* @since 2.7.0
*/
abstract class AbstractPreferencesExtension implements iPreferencesExtension
{
/**
* @inheritDoc
*/
public function DisplayPreferences(WebPage $oPage)
{
// Do nothing
}
/**
* @inheritDoc
*/
public function ApplyPreferences(WebPage $oPage, $sOperation)
{
// Do nothing
}
}
/**
* Implement this interface to change the behavior of the GUI for some objects.
*
@@ -366,6 +435,77 @@ interface iApplicationUIExtension
public function EnumAllowedActions(DBObjectSet $oSet);
}
/**
* Extend this class instead of implementing iApplicationUIExtension if you don't need to overload
*
* @api
* @package Extensibility
* @since 2.7.0
*/
abstract class AbstractApplicationUIExtension implements iApplicationUIExtension
{
/**
* @inheritDoc
*/
public function OnDisplayProperties($oObject, WebPage $oPage, $bEditMode = false)
{
}
/**
* @inheritDoc
*/
public function OnDisplayRelations($oObject, WebPage $oPage, $bEditMode = false)
{
}
/**
* @inheritDoc
*/
public function OnFormSubmit($oObject, $sFormPrefix = '')
{
}
/**
* @inheritDoc
*/
public function OnFormCancel($sTempId)
{
}
/**
* @inheritDoc
*/
public function EnumUsedAttributes($oObject)
{
return array();
}
/**
* @inheritDoc
*/
public function GetIcon($oObject)
{
return '';
}
/**
* @inheritDoc
*/
public function GetHilightClass($oObject)
{
return HILIGHT_CLASS_NONE;
}
/**
* @inheritDoc
*/
public function EnumAllowedActions(DBObjectSet $oSet)
{
return array();
}
}
/**
* Implement this interface to perform specific things when objects are manipulated
*
@@ -393,7 +533,7 @@ interface iApplicationObjectExtension
public function OnIsModified($oObject);
/**
* Invoked to determine wether an object can be written to the database
* Invoked to determine whether an object can be written to the database
*
* The GUI calls this verb and reports any issue.
* Anyhow, this API can be called in other contexts such as the CSV import tool.
@@ -421,7 +561,10 @@ interface iApplicationObjectExtension
* Invoked when an object is updated into the database. The method is called right <b>after</b> the object has been written to the
* database.
*
* Changes made to the object can be get using {@link $oObject::ListChangesUpdated()}. Do not call {@link \DBObject::ListChanges} for this purpose because it will be empty as the object has already be written to DB!
* Useful methods you can call on $oObject :
*
* * {@see DBObject::ListPreviousValuesForUpdatedAttributes()} : list of changed attributes and their values before the change
* * {@see DBObject::Get()} : for a given attribute the new value that was persisted
*
* @param \cmdbAbstractObject $oObject The target object
* @param CMDBChange|null $oChange A change context. Since 2.0 it is fine to ignore it, as the framework does maintain this information
@@ -429,7 +572,7 @@ interface iApplicationObjectExtension
*
* @return void
*
* @since 2.7.0 N°2293 can access object changes by calling {@link $oObject::ListChangesUpdated()}
* @since 2.7.0 N°2293 can access object changes by calling {@see DBObject::ListPreviousValuesForUpdatedAttributes()} on $oObject
*/
public function OnDBUpdate($oObject, $oChange = null);
@@ -460,6 +603,62 @@ interface iApplicationObjectExtension
public function OnDBDelete($oObject, $oChange = null);
}
/**
* Extend this class instead of iApplicationObjectExtension if you don't need to overload all methods
*
* @api
* @package Extensibility
* @since 2.7.0
*/
abstract class AbstractApplicationObjectExtension implements iApplicationObjectExtension
{
/**
* @inheritDoc
*/
public function OnIsModified($oObject)
{
return false;
}
/**
* @inheritDoc
*/
public function OnCheckToWrite($oObject)
{
return array();
}
/**
* @inheritDoc
*/
public function OnCheckToDelete($oObject)
{
return array();
}
/**
* @inheritDoc
*/
public function OnDBUpdate($oObject, $oChange = null)
{
}
/**
* @inheritDoc
*/
public function OnDBInsert($oObject, $oChange = null)
{
}
/**
* @inheritDoc
*/
public function OnDBDelete($oObject, $oChange = null)
{
}
}
/**
* New extension to add menu items in the "popup" menus inside iTop. Provides a greater flexibility than
* iApplicationUIExtension::EnumAllowedActions.
@@ -586,7 +785,6 @@ abstract class ApplicationPopupMenuItem
*
* @param string $sUID The unique identifier of this menu in iTop... make sure you pass something unique enough
* @param string $sLabel The display label of the menu (must be localized)
* @param array $aCssClasses The CSS classes to add to the menu
*/
public function __construct($sUID, $sLabel)
{
@@ -671,7 +869,7 @@ abstract class ApplicationPopupMenuItem
class URLPopupMenuItem extends ApplicationPopupMenuItem
{
/** @ignore */
protected $sURL;
protected $sUrl;
/** @ignore */
protected $sTarget;
@@ -680,20 +878,32 @@ class URLPopupMenuItem extends ApplicationPopupMenuItem
*
* @param string $sUID The unique identifier of this menu in iTop... make sure you pass something unique enough
* @param string $sLabel The display label of the menu (must be localized)
* @param string $sURL If the menu is an hyperlink, provide the absolute hyperlink here
* @param string $sUrl If the menu is an hyperlink, provide the absolute hyperlink here
* @param string $sTarget In case the menu is an hyperlink and a specific target is needed (_blank for example), pass it here
*/
public function __construct($sUID, $sLabel, $sURL, $sTarget = '_top')
public function __construct($sUID, $sLabel, $sUrl, $sTarget = '_top')
{
parent::__construct($sUID, $sLabel);
$this->sURL = $sURL;
$this->sUrl = $sUrl;
$this->sTarget = $sTarget;
}
/** @ignore */
public function GetMenuItem()
{
return array('label' => $this->GetLabel(), 'url' => $this->sURL, 'target' => $this->sTarget, 'css_classes' => $this->aCssClasses);
return array('label' => $this->GetLabel(), 'url' => $this->GetUrl(), 'target' => $this-> GetTarget(), 'css_classes' => $this->aCssClasses);
}
/** @ignore */
public function GetUrl()
{
return $this->sUrl;
}
/** @ignore */
public function GetTarget()
{
return $this->sTarget;
}
}
@@ -707,7 +917,9 @@ class URLPopupMenuItem extends ApplicationPopupMenuItem
class JSPopupMenuItem extends ApplicationPopupMenuItem
{
/** @ignore */
protected $sJSCode;
protected $sJsCode;
/** @ignore */
protected $sUrl;
/** @ignore */
protected $aIncludeJSFiles;
@@ -725,7 +937,8 @@ class JSPopupMenuItem extends ApplicationPopupMenuItem
public function __construct($sUID, $sLabel, $sJSCode, $aIncludeJSFiles = array())
{
parent::__construct($sUID, $sLabel);
$this->sJSCode = $sJSCode;
$this->sJsCode = $sJSCode;
$this->sUrl = '#';
$this->aIncludeJSFiles = $aIncludeJSFiles;
}
@@ -735,9 +948,9 @@ class JSPopupMenuItem extends ApplicationPopupMenuItem
// Note: the semicolumn is a must here!
return array(
'label' => $this->GetLabel(),
'onclick' => $this->sJSCode.'; return false;',
'url' => '#',
'css_classes' => $this->aCssClasses,
'onclick' => $this->GetJsCode().'; return false;',
'url' => $this->GetUrl(),
'css_classes' => $this->GetCssClasses(),
);
}
@@ -746,6 +959,18 @@ class JSPopupMenuItem extends ApplicationPopupMenuItem
{
return $this->aIncludeJSFiles;
}
/** @ignore */
public function GetJsCode()
{
return $this->sJsCode;
}
/** @ignore */
public function GetUrl()
{
return $this->sUrl;
}
}
/**
@@ -821,7 +1046,7 @@ class JSButtonItem extends JSPopupMenuItem
interface iPageUIExtension
{
/**
* Add content to the North pane
* Add content to the header of the page
*
* @param iTopWebPage $oPage The page to insert stuff into.
*
@@ -830,7 +1055,7 @@ interface iPageUIExtension
public function GetNorthPaneHtml(iTopWebPage $oPage);
/**
* Add content to the South pane
* Add content to the footer of the page
*
* @param iTopWebPage $oPage The page to insert stuff into.
*
@@ -848,6 +1073,41 @@ interface iPageUIExtension
public function GetBannerHtml(iTopWebPage $oPage);
}
/**
* Extend this class instead of iPageUIExtension if you don't need to overload all methods
*
* @api
* @package Extensibility
* @since 2.7.0
*/
abstract class AbstractPageUIExtension implements iPageUIExtension
{
/**
* @inheritDoc
*/
public function GetNorthPaneHtml(iTopWebPage $oPage)
{
return '';
}
/**
* @inheritDoc
*/
public function GetSouthPaneHtml(iTopWebPage $oPage)
{
return '';
}
/**
* @inheritDoc
*/
public function GetBannerHtml(iTopWebPage $oPage)
{
return '';
}
}
/**
* Implement this interface to add content to any enhanced portal page
*
@@ -855,7 +1115,7 @@ interface iPageUIExtension
*
* @api
* @package Extensibility
* @since 2.4
* @since 2.4.0
*/
interface iPortalUIExtension
{
@@ -1079,11 +1339,6 @@ class RestResult
/**
* Default constructor - ok!
*
* @param DBObject $oObject The object being reported
* @param string $sAttCode The attribute code (must be valid)
*
* @return string A scalar representation of the value
*/
public function __construct()
{

View File

@@ -43,7 +43,6 @@ class AuditRule extends cmdbAbstractObject
"db_table" => "priv_auditrule",
"db_key_field" => "id",
"db_finalclass_field" => "",
"display_template" => "",
);
MetaModel::Init_Params($aParams);
MetaModel::Init_AddAttribute(new AttributeString("name", array("allowed_values"=>null, "sql"=>"name", "default_value"=>"", "is_null_allowed"=>false, "depends_on"=>array())));

View File

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

View File

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

File diff suppressed because it is too large Load Diff

View File

@@ -1,111 +1,7 @@
<?php
// Copyright (C) 2010-2015 Combodo SARL
//
// This file is part of iTop.
//
// iTop is free software; you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// iTop is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with iTop. If not, see <http://www.gnu.org/licenses/>
/**
* Simple web page with no includes or fancy formatting, useful to generateXML documents
* The page adds the content-type text/XML and the encoding into the headers
*
* @copyright Copyright (C) 2010-2015 Combodo SARL
* @deprecated will be removed in 3.1.0 - moved to sources/application/WebPage/CSVPage.php
* @license http://opensource.org/licenses/AGPL-3.0
* @copyright Copyright (C) 2010-2020 Combodo SARL
*/
require_once(APPROOT."/application/webpage.class.inc.php");
class CSVPage extends WebPage
{
function __construct($s_title)
{
parent::__construct($s_title);
$this->add_header("Content-type: text/plain; charset=".self::PAGES_CHARSET);
$this->add_header("Cache-control: no-cache");
//$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

@@ -17,6 +17,11 @@
* You should have received a copy of the GNU Affero General Public License
*/
use Combodo\iTop\Application\UI\Component\Button\ButtonFactory;
use Combodo\iTop\Application\UI\Component\Toolbar\Toolbar;
use Combodo\iTop\Application\UI\Component\DataTable\DataTableSettings;
require_once(APPROOT.'application/dashboardlayout.class.inc.php');
require_once(APPROOT.'application/dashlet.class.inc.php');
require_once(APPROOT.'core/modelreflection.class.inc.php');
@@ -176,12 +181,6 @@ abstract class Dashboard
protected function InitDashletFromDOMNode($oDomNode)
{
$sId = $oDomNode->getAttribute('id');
// To avoid collision with other dashlets with the same ID we suffix it. Collisions typically happen with extensions.
// Note: The check is done so we don't append it at each save of the dashboard.
if(strpos($sId, 'uniqid_') === false)
{
$sId .= '_uniqid_' . uniqid();
}
$sDashletType = $oDomNode->getAttribute('xsi:type');
@@ -341,6 +340,25 @@ abstract class Dashboard
}
/**
* @return mixed
*/
public function GetId()
{
return $this->sId;
}
/**
* Return a sanitize ID for usages in XML/HTML attributes
*
* @return string
* @since 2.7.0
*/
public function GetSanitizedId()
{
return utils::Sanitize($this->GetId(), '', 'element_identifier');
}
/**
* @return string
*/
@@ -478,7 +496,7 @@ abstract class Dashboard
$("#attr_auto_reload_sec").prop('disabled', !$(this).is(':checked'));
} );
$('#select_layout').buttonset();
$('#select_layout').controlgroup();
$('#select_dashlet').droppable({
accept: '.dashlet',
drop: function(event, ui) {
@@ -516,13 +534,37 @@ EOF
*/
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>');
if (!array_key_exists('dashboard_div_id', $aExtraParams)) {
$aExtraParams['dashboard_div_id'] = utils::Sanitize($this->GetId(), '', 'element_identifier');
}
$sTitleForHTML = utils::HtmlEntities(Dict::S($this->sTitle));
$sHtml = "<div class=\"ibo-top-bar--toolbar-dashboard-title\">{$sTitleForHTML}</div>";
if ($oPage instanceof iTopWebPage) {
$oTopBar = $oPage->GetTopBarLayout();
$oToolbar = new Toolbar();
$oTopBar->SetToolbar($oToolbar);
$oToolbar->AddHtml($sHtml);
} else {
$oPage->add_script(<<<JS
$(".ibo-top-bar--toolbar-dashboard-title").html("$sTitleForHTML");
JS
);
}
$oLayout = new $this->sLayoutClass;
/** @var \DashboardLayoutMultiCol $oLayout */
$oLayout = new $this->sLayoutClass();
foreach ($this->aCells as $iCellIdx => $aDashlets) {
foreach ($aDashlets as $oDashlet) {
$aDashletCoordinates = $oLayout->GetDashletCoordinates($iCellIdx);
$this->PrepareDashletForRendering($oDashlet, $aDashletCoordinates, $aExtraParams);
}
}
$oLayout->Render($oPage, $this->aCells, $bEditMode, $aExtraParams);
if (!$bEditMode)
{
if (!$bEditMode) {
$oPage->add_linked_script('../js/dashlet.js');
$oPage->add_linked_script('../js/dashboard.js');
}
@@ -561,19 +603,21 @@ EOF
// 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>');
/** @var \DashboardLayoutMultiCol $oLayout */
$oLayout = new $this->sLayoutClass();
$oPage->add('<div id="dashlet_properties" style="text-align:center">');
foreach($this->aCells as $aCell)
foreach($this->aCells as $iCellIdx => $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">');
$oPage->add('<div class="dashlet_properties" id="dashlet_properties_'.$oDashlet->GetID().'" style="display:none">');
$oForm = $oDashlet->GetForm();
$this->SetFormParams($oForm, $aExtraParams);
$oForm->RenderAsPropertySheet($oPage, false, '.itop-dashboard');
$oForm->RenderAsPropertySheet($oPage, false, '.itop-dashboard');
$oPage->add('</div>');
}
}
@@ -633,6 +677,18 @@ EOF
return $iNewId + 1;
}
/**
* Prepare dashlet for rendering (eg. change its ID or another processing).
* Meant to be overloaded.
*
* @param \Dashlet $oDashlet
* @param array $aCoordinates
* @param array $aExtraParams
*
* @return void
*/
abstract protected function PrepareDashletForRendering(Dashlet $oDashlet, $aCoordinates, $aExtraParams = array());
/**
* @param \DesignerForm $oForm
* @param array $aExtraParams
@@ -657,11 +713,34 @@ EOF
}
/**
* @return mixed
* N°2634: we must have a unique id per dashlet!
* To avoid collision with other dashlets with the same ID we prefix it with row/cell id
* Collisions typically happen with extensions.
*
* @param boolean $bIsCustomized
* @param string $sDashboardDivId
* @param int $iRow
* @param int $iCol
* @param string $sDashletOrigId
*
* @return string
*
* @since 2.7.0 N°2735
*/
public function GetId()
public static function GetDashletUniqueId($bIsCustomized, $sDashboardDivId, $iRow, $iCol, $sDashletOrigId)
{
return $this->sId;
if(strpos($sDashletOrigId, '_ID_row') !== false)
{
return $sDashletOrigId;
}
$sDashletId = $sDashboardDivId."_ID_row".$iRow."_col".$iCol."_".$sDashletOrigId;
if ($bIsCustomized)
{
$sDashletId = 'CUSTOM_'.$sDashletId;
}
return $sDashletId;
}
}
@@ -670,12 +749,12 @@ EOF
*/
class RuntimeDashboard extends Dashboard
{
/** @var bool $bCustomized */
protected $bCustomized;
/** @var string $sDefinitionFile */
private $sDefinitionFile = '';
/** @var null $sReloadURL */
private $sReloadURL = null;
/** @var bool $bCustomized */
protected $bCustomized;
/**
* @inheritDoc
@@ -683,12 +762,22 @@ class RuntimeDashboard extends Dashboard
public function __construct($sId)
{
parent::__construct($sId);
$this->bCustomized = false;
$this->oMetaModel = new ModelReflectionRuntime();
$this->bCustomized = false;
}
/**
* @return bool
* @since 2.7.0
*/
public function GetCustomFlag()
{
return $this->bCustomized;
}
/**
* @param bool $bCustomized
* @since 2.7.0
*/
public function SetCustomFlag($bCustomized)
{
@@ -846,13 +935,16 @@ class RuntimeDashboard extends Dashboard
if (!$bEditMode && !$oPage->IsPrintableVersion())
{
$sId = $this->GetId();
$sDivId = preg_replace('/[^a-zA-Z0-9_]/', '', $sId);
$sDivId = utils::Sanitize($sId, '', 'element_identifier');
if ($this->GetAutoReload())
{
$sFile = addslashes($this->GetDefinitionFile());
$sExtraParams = json_encode($aAjaxParams);
$iReloadInterval = 1000 * $this->GetAutoReloadInterval();
$sReloadURL = $this->GetReloadURL();
$oAppContext = new ApplicationContext();
$sContext=$oAppContext->GetForPostParams();
//$sContext is named "c" because it use the existing code for context parameters c[org_id] and c[menu]
$oPage->add_script(
<<<EOF
if (typeof(AutoReloadDashboardId$sDivId) !== 'undefined')
@@ -866,14 +958,14 @@ class RuntimeDashboard extends Dashboard
function ReloadDashboard$sDivId()
{
// Do not reload when a dialog box is active
if (!($('.ui-dialog:visible').length > 0) && $('.dashboard_contents#$sDivId').is(':visible'))
if (!($('.ui-dialog:visible').length > 0) && $('.ibo-dashboard#$sDivId').is(':visible'))
{
$('.dashboard_contents#$sDivId').block();
$('.ibo-dashboard#$sDivId').block();
$.post(GetAbsoluteUrlAppRoot()+'pages/ajax.render.php',
{ operation: 'reload_dashboard', dashboard_id: '$sId', file: '$sFile', extra_params: $sExtraParams, reload_url: '$sReloadURL'},
{ operation: 'reload_dashboard', dashboard_id: '$sId', file: '$sFile', extra_params: $sExtraParams, c: $sContext, reload_url: '$sReloadURL'},
function(data){
$('.dashboard_contents#$sDivId').html(data);
$('.dashboard_contents#$sDivId').unblock();
$('.ibo-dashboard#$sDivId').html(data);
$('.ibo-dashboard#$sDivId').unblock();
}
);
}
@@ -903,52 +995,58 @@ EOF
}
/**
* @param \iTopWebPage $oPage
* @param WebPage $oPage
* @param array $aAjaxParams
*
* @throws \CoreException
* @throws \CoreUnexpectedValue
* @throws \MySQLException
*/
protected function RenderSelector($oPage, $aAjaxParams = array())
protected function RenderSelector(WebPage $oPage, $aAjaxParams = array())
{
$sId = $this->GetId();
$sDivId = preg_replace('/[^a-zA-Z0-9_]/', '', $sId);
$sDivId = utils::Sanitize($sId, '', 'element_identifier');
$sExtraParams = json_encode($aAjaxParams);
$sSelectorHtml = '<div class="dashboard-selector">';
if ($this->HasCustomDashboard())
{
$sSelectorHtml = '<div class="ibo-top-bar--toolbar-dashboard-selector">';
if ($this->HasCustomDashboard()) {
$bStandardSelected = appUserPreferences::GetPref('display_original_dashboard_'.$sId, false);
$sStandard = Dict::S('UI:Toggle:StandardDashboard');
$sSelectorHtml .= '<div class="selector-label">'.$sStandard.'</div>';
$sSelectorHtml .= '<label class="switch"><input type="checkbox" onchange="ToggleDashboardSelector'.$sDivId.'();" '.($bStandardSelected ? '' : 'checked').'><span class="slider round"></span></label></input></label>';
$sCustom = Dict::S('UI:Toggle:CustomDashboard');
$sSelectorHtml .= '<div class="selector-label">'.$sCustom.'</div>';
}
$sSelectorHtml .= '</div>';
$sSelectorHtml = addslashes($sSelectorHtml);
$sFile = addslashes($this->GetDefinitionFile());
$sReloadURL = $this->GetReloadURL();
$oPage->add_ready_script(
<<<EOF
$('.dashboard-title').after('$sSelectorHtml');
EOF
);
if ($oPage instanceof iTopWebPage) {
$oToolbar = $oPage->GetTopBarLayout()->GetToolbar();
$oToolbar->AddHtml($sSelectorHtml);
$oPage->add_script(
<<<EOF
$oPage->add_script(
<<<EOF
function ToggleDashboardSelector$sDivId()
{
$('.dashboard_contents#$sDivId').block();
$('.ibo-dashboard#$sDivId').block();
$.post(GetAbsoluteUrlAppRoot()+'pages/ajax.render.php',
{ operation: 'toggle_dashboard', dashboard_id: '$sId', file: '$sFile', extra_params: $sExtraParams, reload_url: '$sReloadURL' },
function(data) {
$('.dashboard_contents#$sDivId').html(data);
$('.dashboard_contents#$sDivId').unblock();
$('.ibo-dashboard#$sDivId').html(data);
$('.ibo-dashboard#$sDivId').unblock();
}
);
}
EOF
);
);
} else {
$sSelectorHtml = addslashes($sSelectorHtml);
$oPage->add_script(<<<JS
$(".ibo-top-bar--toolbar-dashboard-selector").replaceWith("$sSelectorHtml");
JS
);
}
}
/**
@@ -980,43 +1078,67 @@ EOF
*/
protected function RenderEditionTools(WebPage $oPage, $aExtraParams)
{
if (!($oPage instanceof iTopWebPage)) {
return;
}
$oPage->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/jquery.iframe-transport.js');
$oPage->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/jquery.fileupload.js');
$sEditMenu = "<div id=\"DashboardMenu\"><ul><li><i class=\"top-right-icon icon-additional-arrow fas fa-pencil-alt\"></i><ul>";
$sId = utils::Sanitize($this->GetId(), '', 'element_identifier');
$sMenuTogglerId = "ibo-dashboard-menu-toggler-{$sId}";
$sPopoverMenuId = "ibo-dashboard-menu-popover-{$sId}";
$sName = 'UI:Dashboard:Actions';
$oToolbar = $oPage->GetTopBarLayout()->GetToolbar();
$oActionButton = ButtonFactory::MakeLinkNeutral('', '', 'fas fa-ellipsis-v', $sName, '', $sMenuTogglerId);
$oActionButton->AddCSSClasses("ibo-top-bar--toolbar-dashboard-menu-toggler");
$oToolbar->AddSubBlock($oActionButton);
$aActions = array();
$sFile = addslashes($this->sDefinitionFile);
$sJSExtraParams = json_encode($aExtraParams);
$bCanEdit = true;
if ($this->HasCustomDashboard())
{
if ($this->HasCustomDashboard()) {
$bCanEdit = !appUserPreferences::GetPref('display_original_dashboard_'.$this->GetId(), false);
}
if ($bCanEdit)
{
if ($bCanEdit) {
$oEdit = new JSPopupMenuItem('UI:Dashboard:Edit', Dict::S('UI:Dashboard:Edit'), "return EditDashboard('{$this->sId}', '$sFile', $sJSExtraParams)");
$aActions[$oEdit->GetUID()] = $oEdit->GetMenuItem();
}
if ($this->bCustomized)
{
if ($this->bCustomized) {
$oRevert = new JSPopupMenuItem('UI:Dashboard:RevertConfirm', Dict::S('UI:Dashboard:Revert'),
"if (confirm('".addslashes(Dict::S('UI:Dashboard:RevertConfirm'))."')) return RevertDashboard('{$this->sId}', $sJSExtraParams); else return false");
"if (confirm('".addslashes(Dict::S('UI:Dashboard:RevertConfirm'))."')) return RevertDashboard('{$this->sId}', $sJSExtraParams); else return false");
$aActions[$oRevert->GetUID()] = $oRevert->GetMenuItem();
}
utils::GetPopupMenuItems($oPage, iPopupMenuExtension::MENU_DASHBOARD_ACTIONS, $this, $aActions);
$sEditMenu .= $oPage->RenderPopupMenuItems($aActions);
$sEditMenu = addslashes($sEditMenu);
$sReloadURL = $this->GetReloadURL();
$oPage->add_ready_script(
<<<EOF
$('.dashboard-title').after('$sEditMenu');
$('#DashboardMenu>ul').popupmenu();
$oToolbar->AddSubBlock($oPage->GetPopoverMenu($sPopoverMenuId, $aActions));
$oActionButton->AddCSSClasses('ibo-action-button')
->SetJsCode(<<<JS
$("#{$sPopoverMenuId}").popover_menu({toggler: "#{$sMenuTogglerId}"});
$('#{$sMenuTogglerId}').on('click', function(oEvent) {
var oEventTarget = $('#{$sMenuTogglerId}');
var aEventTargetPos = oEventTarget.position();
var popover = $("#{$sPopoverMenuId}");
EOF
);
popover.css({
// 'top': (aEventTargetPos.top + parseInt(oEventTarget.css('marginTop'), 10) + oEventTarget.height()) + 'px',
// 'left': (aEventTargetPos.left + parseInt(oEventTarget.css('marginLeft'), 10) + oEventTarget.width() - popover.width()) + 'px',
'top': (aEventTargetPos.top + oEventTarget.outerHeight(true)) + 'px',
'left': (aEventTargetPos.left + oEventTarget.outerWidth(true) - popover.width()) + 'px',
'z-index': 10060
});
popover.popover_menu("togglePopup");
});
JS
);
$sReloadURL = $this->GetReloadURL();
$oPage->add_script(
<<<EOF
<<<EOF
function EditDashboard(sId, sDashboardFile, aExtraParams)
{
$.post(GetAbsoluteUrlAppRoot()+'pages/ajax.render.php', {operation: 'dashboard_editor', id: sId, file: sDashboardFile, extra_params: aExtraParams, reload_url: '$sReloadURL'},
@@ -1098,9 +1220,11 @@ EOF
{
$aRenderParams = $aExtraParams;
}
$aRenderParams['dashboard_div_id'] = $aExtraParams['dashboard_div_id'];
$sJSExtraParams = json_encode($aExtraParams);
$oPage->add('<div id="dashboard_editor">');
$oPage->add('<div class="ui-layout-center">');
$this->SetCustomFlag(true);
$this->Render($oPage, true, $aRenderParams);
$oPage->add('</div>');
$oPage->add('<div class="ui-layout-east">');
@@ -1129,7 +1253,7 @@ EOF
$sAutoApplyConfirmationMessage = addslashes(Dict::S('UI:AutoApplyConfirmationMessage'));
$oPage->add_ready_script(
<<<EOF
<<<JS
window.bLeavingOnUserAction = false;
$('#dashboard_editor').dialog({
@@ -1172,10 +1296,15 @@ $('#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', file: '$sFile', extra_params: $sJSExtraParams, reload_url: '$sReloadURL'},
render_to: '$sUrl', render_parameters: {operation: 'render_dashboard', file: '$sFile', extra_params: $sJSExtraParams, reload_url: '$sReloadURL'},
dashboard_id: '$sId',
layout_class: '$sLayoutClass',
title: '$sTitle',
auto_reload: $sAutoReload,
auto_reload_sec: $sAutoReloadSec,
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'}
});
@@ -1214,7 +1343,7 @@ window.onbeforeunload = function() {
}
// return nothing ! safer for IE
};
EOF
JS
);
$oPage->add_ready_script("");
}
@@ -1354,7 +1483,7 @@ EOF
$sCancelButtonLabel = Dict::S('UI:Button:Cancel');
$oPage->add_ready_script(
<<<EOF
<<<JS
$('#dashlet_creation_dlg').dialog({
width: 600,
modal: true,
@@ -1383,7 +1512,7 @@ $('#dashlet_creation_dlg').dialog({
],
close: function() { $(this).remove(); }
});
EOF
JS
);
}
@@ -1418,4 +1547,88 @@ EOF
{
$this->sReloadURL = $sReloadURL;
}
/**
* @inheritDoc
*/
protected function PrepareDashletForRendering(Dashlet $oDashlet, $aCoordinates, $aExtraParams = array())
{
$sDashletIdOrig = $oDashlet->GetID();
$sDashboardSanitizedId = $this->GetSanitizedId();
$sDashletIdNew = static::GetDashletUniqueId($this->GetCustomFlag(), $sDashboardSanitizedId, $aCoordinates[1], $aCoordinates[0], $sDashletIdOrig);
$oDashlet->SetID($sDashletIdNew);
$this->UpdateDashletUserPrefs($oDashlet, $sDashletIdOrig, $aExtraParams);
}
/**
* Migrate dashlet specific prefs to new format
* Before 2.7.0 we were using the same for dashboard menu or dashboard attributes, standard or custom :
* <alias>-<class>|Dashlet<idx_dashlet>
* Since 2.7.0 it is the following, with a "CUSTOM_" prefix if necessary :
* * dashboard menu : <dashboard_id>_IDrow<row_idx>-col<col_idx>-<dashlet_idx>
* * dashboard attribute : <class>__<attcode>_IDrow<row_idx>-col<col_idx>-<dashlet_idx>
*
* @param \Dashlet $oDashlet
* @param string $sDashletIdOrig
*
* @param array $aExtraParams
*
* @since 2.7.0 N°2735
*/
private function UpdateDashletUserPrefs(Dashlet $oDashlet, $sDashletIdOrig, array $aExtraParams)
{
$bIsDashletWithListPref = ($oDashlet instanceof DashletObjectList);
if (!$bIsDashletWithListPref)
{
return;
}
/** @var \DashletObjectList $oDashlet */
$bDashletIdInNewFormat = ($sDashletIdOrig === $oDashlet->GetID());
if ($bDashletIdInNewFormat)
{
return;
}
$sNewPrefKey = $this->GetDashletObjectListAppUserPreferencesPrefix($oDashlet, $aExtraParams, $oDashlet->GetID());
$sPrefValueForNewKey = appUserPreferences::GetPref($sNewPrefKey, null);
$bHasPrefInNewFormat = ($sPrefValueForNewKey !== null);
if ($bHasPrefInNewFormat)
{
return;
}
$sOldPrefKey = $this->GetDashletObjectListAppUserPreferencesPrefix($oDashlet, $aExtraParams, $sDashletIdOrig);
$sPrefValueForOldKey = appUserPreferences::GetPref($sOldPrefKey, null);
$bHasPrefInOldFormat = ($sPrefValueForOldKey !== null);
if (!$bHasPrefInOldFormat)
{
return;
}
appUserPreferences::SetPref($sNewPrefKey, $sPrefValueForOldKey);
appUserPreferences::UnsetPref($sOldPrefKey);
}
/**
* @param \DashletObjectList $oDashlet
* @param array $aExtraParams
* @param string $sDashletId
*
* @return string
* @since 2.7.0
*/
private function GetDashletObjectListAppUserPreferencesPrefix(DashletObjectList $oDashlet, $aExtraParams, $sDashletId)
{
$sDataTableId = Dashlet::APPUSERPREFERENCES_PREFIX.$sDashletId;
$aClassAliases = array();
try {
$oFilter = $oDashlet->GetDBSearch($aExtraParams);
$aClassAliases = $oFilter->GetSelectedClasses();
} catch (Exception $e) {
//on error, return default value
return null;
}
return DataTableSettings::GetAppUserPreferenceKey($aClassAliases, $sDataTableId);
}
}

View File

@@ -15,25 +15,30 @@
//
// You should have received a copy of the GNU Affero General Public License
// along with iTop. If not, see <http://www.gnu.org/licenses/>
use Combodo\iTop\Application\UI\Component\Html\Html;
use Combodo\iTop\Application\UI\Layout\Dashboard\DashboardColumn;
use Combodo\iTop\Application\UI\Layout\Dashboard\DashboardLayout as UIDashboardLayout;
use Combodo\iTop\Application\UI\Layout\Dashboard\DashboardRow;
/**
* Dashboard presentation
*
*
* @copyright Copyright (C) 2010-2012 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
*/
abstract class DashboardLayout
{
public function __construct()
{
}
abstract public function Render($oPage, $aDashlets, $bEditMode = false);
/**
* @param int $iCellIdx
*
* @return array Containing 2 scalars: Col number and row number (starting from 0)
* @since 2.7.0
*/
abstract public function GetDashletCoordinates($iCellIdx);
static public function GetInfo()
public static function GetInfo()
{
return array(
'label' => '',
@@ -51,7 +56,7 @@ abstract class DashboardLayoutMultiCol extends DashboardLayout
{
$this->iNbCols = 1;
}
protected function TrimCell($aDashlets)
{
$aKeys = array_reverse(array_keys($aDashlets));
@@ -61,7 +66,7 @@ abstract class DashboardLayoutMultiCol extends DashboardLayout
{
/** @var \Dashlet $oDashlet */
$oDashlet = $aDashlets[$aKeys[$idx]];
if ($oDashlet->IsVisible())
if ($oDashlet::IsVisible())
{
$bNoVisibleFound = false;
}
@@ -110,61 +115,64 @@ abstract class DashboardLayoutMultiCol extends DashboardLayout
{
// Trim the list of cells to remove the invisible/empty ones at the end of the array
$aCells = $this->TrimCellsArray($aCells);
$oPage->add('<table style="width:100%;table-layout:fixed;"><tbody>');
$oDashboardLayout = new UIDashboardLayout();
$oPage->AddUiBlock($oDashboardLayout);
$iCellIdx = 0;
$fColSize = 100 / $this->iNbCols;
$sStyle = $bEditMode ? 'border: 1px #ccc dashed; width:'.$fColSize.'%;' : 'width: '.$fColSize.'%;';
$sClass = $bEditMode ? 'layout_cell edit_mode' : 'dashboard';
$iNbRows = ceil(count($aCells) / $this->iNbCols);
for($iRows = 0; $iRows < $iNbRows; $iRows++)
{
$oPage->add('<tr>');
for($iCols = 0; $iCols < $this->iNbCols; $iCols++)
{
$sCellClass = ($iRows == $iNbRows-1) ? $sClass.' layout_last_used_rank' : $sClass;
$oPage->add("<td style=\"$sStyle\" class=\"$sCellClass\" data-dashboard-cell-index=\"$iCellIdx\">");
if (array_key_exists($iCellIdx, $aCells))
{
for ($iRows = 0; $iRows < $iNbRows; $iRows++) {
$oDashboardRow = new DashboardRow();
$oDashboardLayout->AddDashboardRow($oDashboardRow);
for ($iCols = 0; $iCols < $this->iNbCols; $iCols++) {
$oDashboardColumn = new DashboardColumn($bEditMode);
$oDashboardColumn->SetCellIndex($iCellIdx);
$oDashboardRow->AddDashboardColumn($oDashboardColumn);
if (array_key_exists($iCellIdx, $aCells)) {
$aDashlets = $aCells[$iCellIdx];
if (count($aDashlets) > 0)
{
if (count($aDashlets) > 0) {
/** @var \Dashlet $oDashlet */
foreach($aDashlets as $oDashlet)
{
if ($oDashlet->IsVisible())
{
$oDashlet->DoRender($oPage, $bEditMode, true /* bEnclosingDiv */, $aExtraParams);
foreach ($aDashlets as $oDashlet) {
if ($oDashlet::IsVisible()) {
$oDashboardColumn->AddUIBlock($oDashlet->DoRender($oPage, $bEditMode, true /* bEnclosingDiv */, $aExtraParams));
}
}
} else {
$oDashboardColumn->AddUIBlock(new Html('&nbsp;'));
}
else
{
$oPage->add('&nbsp;');
}
} else {
$oDashboardColumn->AddUIBlock(new Html('&nbsp;'));
}
else
{
$oPage->add('&nbsp;');
}
$oPage->add('</td>');
$iCellIdx++;
}
$oPage->add('</tr>');
}
if ($bEditMode) // Add one row for extensibility
{
$sStyle = 'style="border: 1px #ccc dashed; width:'.$fColSize.'%;" class="layout_cell edit_mode layout_extension" data-dashboard-cell-index="'.$iCellIdx.'"';
$oPage->add('<tr>');
for($iCols = 0; $iCols < $this->iNbCols; $iCols++)
{
$oPage->add("<td $sStyle>");
$oPage->add('&nbsp;');
$oPage->add('</td>');
$oDashboardRow = new DashboardRow();
$oDashboardLayout->AddDashboardRow($oDashboardRow);
for ($iCols = 0; $iCols < $this->iNbCols; $iCols++) {
$oDashboardColumn = new DashboardColumn($bEditMode, true);
$oDashboardRow->AddDashboardColumn($oDashboardColumn);
$oDashboardColumn->AddUIBlock(new Html('&nbsp;'));
}
$oPage->add('</tr>');
}
$oPage->add('</tbody></table>');
return;
}
/**
* @inheritDoc
*/
public function GetDashletCoordinates($iCellIdx)
{
$iColNumber = (int) $iCellIdx % $this->iNbCols;
$iRowNumber = (int) floor($iCellIdx / $this->iNbCols);
return array($iColNumber, $iRowNumber);
}
}

View File

@@ -16,6 +16,13 @@
// You should have received a copy of the GNU Affero General Public License
// along with iTop. If not, see <http://www.gnu.org/licenses/>
use Combodo\iTop\Application\UI\Component\Dashlet\DashletContainer;
use Combodo\iTop\Application\UI\Component\Dashlet\DashletFactory;
use Combodo\iTop\Application\UI\Component\Html\Html;
use Combodo\iTop\Application\UI\Component\Panel\PanelFactory;
use Combodo\iTop\Application\UI\iUIBlock;
use Combodo\iTop\Application\UI\UIBlock;
require_once(APPROOT.'application/forms.class.inc.php');
/**
@@ -26,6 +33,9 @@ require_once(APPROOT.'application/forms.class.inc.php');
*/
abstract class Dashlet
{
/** @var string */
const APPUSERPREFERENCES_PREFIX = 'Dashlet';
protected $oModelReflection;
protected $sId;
protected $bRedrawNeeded;
@@ -47,7 +57,7 @@ abstract class Dashlet
$this->bRedrawNeeded = true; // By default: redraw each time a property changes
$this->bFormRedrawNeeded = false; // By default: no need to redraw the form (independent fields)
$this->aProperties = array(); // By default: there is no property
$this->aCSSClasses = array('dashlet');
$this->aCSSClasses = array('ibo-dashlet');
$this->sDashletType = get_class($this);
}
@@ -63,21 +73,17 @@ abstract class Dashlet
{
$refValue = $this->aProperties[$sProperty];
$sRefType = gettype($refValue);
if (gettype($sValue) == $sRefType)
{
if (gettype($sValue) == $sRefType) {
// Do not change anything in that case!
$ret = $sValue;
}
elseif ($sRefType == 'boolean')
{
} elseif ($sRefType == 'boolean') {
$ret = ($sValue == 'true');
}
elseif ($sRefType == 'array')
{
} elseif ($sRefType == 'array') {
$ret = explode(',', $sValue);
}
else
{
} elseif (is_array($sValue)) {
$ret = $sValue;
} else {
$ret = $sValue;
settype($ret, $sRefType);
}
@@ -188,10 +194,8 @@ abstract class Dashlet
*/
public function FromParams($aParams)
{
foreach ($this->aProperties as $sProperty => $value)
{
if (array_key_exists($sProperty, $aParams))
{
foreach ($this->aProperties as $sProperty => $value) {
if (array_key_exists($sProperty, $aParams)) {
$this->aProperties[$sProperty] = $aParams[$sProperty];
}
}
@@ -204,79 +208,59 @@ abstract class Dashlet
* @param bool $bEnclosingDiv
* @param array $aExtraParams
*/
public function DoRender($oPage, $bEditMode = false, $bEnclosingDiv = true, $aExtraParams = array())
public function DoRender($oPage, $bEditMode = false, $bEnclosingDiv = true, $aExtraParams = array()): UIBlock
{
$sCSSClasses = implode(' ', $this->aCSSClasses);
$sId = $this->GetID();
if ($bEnclosingDiv)
{
if ($bEditMode)
{
$oPage->add('<div class="'.$sCSSClasses.'" id="dashlet_'.$sId.'">');
$sCSSClasses = implode(' ', $this->aCSSClasses);
if ($bEnclosingDiv) {
if ($bEditMode) {
$oDashletContainer = new DashletContainer("dashlet_{$sId}");
} else {
$oDashletContainer = new DashletContainer();
}
else
{
$oPage->add('<div class="'.$sCSSClasses.'">');
}
}
else
{
foreach ($this->aCSSClasses as $sCSSClass)
{
$oDashletContainer->AddCSSClasses($sCSSClasses);
} else {
$oDashletContainer = new DashletContainer();
foreach ($this->aCSSClasses as $sCSSClass) {
$oPage->add_ready_script("$('#dashlet_".$sId."').addClass('$sCSSClass');");
}
}
try
{
if (get_class($this->oModelReflection) == 'ModelReflectionRuntime')
{
$this->Render($oPage, $bEditMode, $aExtraParams);
try {
if (get_class($this->oModelReflection) == 'ModelReflectionRuntime') {
$oBlock = $this->Render($oPage, $bEditMode, $aExtraParams);
} else {
$oBlock = $this->RenderNoData($oPage, $bEditMode, $aExtraParams);
}
else
{
$this->RenderNoData($oPage, $bEditMode, $aExtraParams);
}
}
catch(UnknownClassOqlException $e)
{
$oDashletContainer->AddSubBlock($oBlock);
} catch (UnknownClassOqlException $e) {
// Maybe the class is part of a non-installed module, fail silently
// Except in Edit mode
if ($bEditMode)
{
$oPage->add('<div class="dashlet-content">');
$oPage->add('<h2>'.$e->GetUserFriendlyDescription().'</h2>');
$oPage->add('</div>');
if ($bEditMode) {
$oDashletContainer->AddCSSClasses("dashlet-content");
$oDashletContainer->AddHtml('<h2>'.$e->GetUserFriendlyDescription().'</h2>');
}
}
catch(OqlException $e)
{
$oPage->add('<div class="dashlet-content">');
$oPage->p($e->GetUserFriendlyDescription());
$oPage->add('</div>');
}
catch(Exception $e)
{
$oPage->add('<div class="dashlet-content">');
$oPage->p($e->getMessage());
$oPage->add('</div>');
} catch (OqlException $e) {
$oDashletContainer->AddCSSClasses("dashlet-content");
$oDashletContainer->AddHtml('<p>'.$e->GetUserFriendlyDescription().'</p>');
} catch (Exception $e) {
$oDashletContainer->AddCSSClasses("dashlet-content");
$oDashletContainer->AddHtml('<p>'.$e->getMessage().'</p>');
}
if ($bEnclosingDiv)
{
$oPage->add('</div>');
}
if ($bEditMode)
{
if ($bEditMode) {
$sClass = get_class($this);
$sType = $this->sDashletType;
$oPage->add_ready_script(
<<<EOF
<<<EOF
$('#dashlet_$sId').dashlet({dashlet_id: '$sId', dashlet_class: '$sClass', 'dashlet_type': '$sType'});
EOF
);
}
return $oDashletContainer;
}
/**
@@ -300,7 +284,7 @@ EOF
* @param bool $bEditMode
* @param array $aExtraParams
*
* @return mixed
* @return iUIBlock
*/
abstract public function Render($oPage, $bEditMode = false, $aExtraParams = array());
@@ -310,10 +294,12 @@ EOF
* @param \WebPage $oPage
* @param bool $bEditMode
* @param array $aExtraParams
*
* @return iUIBlock
*/
public function RenderNoData($oPage, $bEditMode = false, $aExtraParams = array())
{
$this->Render($oPage, $bEditMode, $aExtraParams);
return $this->Render($oPage, $bEditMode, $aExtraParams);
}
/**
@@ -514,7 +500,7 @@ EOF
*
* Used as a fallback in iTop for unknown dashlet classes.
*
* @since 2.5
* @since 2.5.0
*/
class DashletUnknown extends Dashlet
{
@@ -613,15 +599,15 @@ class DashletUnknown extends Dashlet
{
$aInfos = static::GetInfo();
$sIconUrl = utils::GetAbsoluteUrlAppRoot().$aInfos['icon'];
$sIconUrl = utils::HtmlEntities(utils::GetAbsoluteUrlAppRoot().$aInfos['icon']);
$sExplainText = ($bEditMode) ? Dict::Format('UI:DashletUnknown:RenderText:Edit', $this->GetDashletType()) : Dict::S('UI:DashletUnknown:RenderText:View');
$oPage->add('<div class="dashlet-content">');
$oDashletContainer = new DashletContainer(null, 'dashlet-content');
$oPage->add('<div class="dashlet-ukn-image"><img src="'.utils::HtmlEntities($sIconUrl).'" /></div>');
$oPage->add('<div class="dashlet-ukn-text">'.$sExplainText.'</div>');
$oDashletContainer->AddHtml('<div class="dashlet-ukn-image"><img src="'.$sIconUrl.'" /></div>');
$oDashletContainer->AddHtml('<div class="dashlet-ukn-text">'.$sExplainText.'</div>');
$oPage->add('</div>');
return $oDashletContainer;
}
/**
@@ -633,15 +619,15 @@ class DashletUnknown extends Dashlet
{
$aInfos = static::GetInfo();
$sIconUrl = utils::GetAbsoluteUrlAppRoot().$aInfos['icon'];
$sIconUrl = utils::HtmlEntities(utils::GetAbsoluteUrlAppRoot().$aInfos['icon']);
$sExplainText = Dict::Format('UI:DashletUnknown:RenderNoDataText:Edit', $this->GetDashletType());
$oPage->add('<div class="dashlet-content">');
$oDashletContainer = new DashletContainer(null, 'dashlet-content');
$oPage->add('<div class="dashlet-ukn-image"><img src="'.utils::HtmlEntities($sIconUrl).'" /></div>');
$oPage->add('<div class="dashlet-ukn-text">'.$sExplainText.'</div>');
$oDashletContainer->AddHtml('<div class="dashlet-ukn-image"><img src="'.$sIconUrl.'" /></div>');
$oDashletContainer->AddHtml('<div class="dashlet-ukn-text">'.$sExplainText.'</div>');
$oPage->add('</div>');
return $oDashletContainer;
}
/**
@@ -760,9 +746,9 @@ class DashletProxy extends DashletUnknown
public function Render($oPage, $bEditMode = false, $aExtraParams = array())
{
// This should never be called.
$oPage->add('<div class="dashlet-content">');
$oPage->add('<div>This dashlet is not supposed to be rendered as it is just a proxy for third-party widgets.</div>');
$oPage->add('</div>');
$oDashletContainer = new DashletContainer(null, 'dashlet-content');
$oDashletContainer->AddHtml('<div>This dashlet is not supposed to be rendered as it is just a proxy for third-party widgets.</div>');
return $oDashletContainer;
}
/**
@@ -774,15 +760,17 @@ class DashletProxy extends DashletUnknown
{
$aInfos = static::GetInfo();
$sIconUrl = utils::GetAbsoluteUrlAppRoot().$aInfos['icon'];
$sIconUrl = utils::HtmlEntities(utils::GetAbsoluteUrlAppRoot().$aInfos['icon']);
$sExplainText = Dict::Format('UI:DashletProxy:RenderNoDataText:Edit', $this->GetDashletType());
$oPage->add('<div class="dashlet-content">');
$oDashletContainer = new DashletContainer(null, 'dashlet-content');
$oPage->add('<div class="dashlet-pxy-image"><img src="'.utils::HtmlEntities($sIconUrl).'" /></div>');
$oPage->add('<div class="dashlet-pxy-text">'.$sExplainText.'</div>');
$sHtml = '';
$sHtml .= '<div class="dashlet-pxy-image"><img src="'.$sIconUrl.'" /></div>';
$sHtml .= '<div class="dashlet-pxy-text">'.$sExplainText.'</div>';
$oPage->add('</div>');
$oDashletContainer->AddHtml($sHtml);
return $oDashletContainer;
}
/**
@@ -813,7 +801,7 @@ class DashletEmptyCell extends Dashlet
*/
public function Render($oPage, $bEditMode = false, $aExtraParams = array())
{
$oPage->add('&nbsp;');
return new Html('&nbsp;');
}
/**
@@ -860,11 +848,12 @@ class DashletPlainText extends Dashlet
*/
public function Render($oPage, $bEditMode = false, $aExtraParams = array())
{
$sText = htmlentities($this->aProperties['text'], ENT_QUOTES, 'UTF-8');
$sText = utils::HtmlEntities($this->aProperties['text']);
$sText = str_replace(array("\r\n", "\n", "\r"), "<br/>", $sText);
$sId = 'plaintext_'.($bEditMode? 'edit_' : '').$this->sId;
$oPage->add('<div id="'.$sId.'" class="dashlet-content">'.$sText.'</div>');
$sId = 'plaintext_'.($bEditMode ? 'edit_' : '').$this->sId;
return DashletFactory::MakeForDashletText($sId, $sText);
}
/**
@@ -913,37 +902,20 @@ class DashletObjectList extends Dashlet
public function Render($oPage, $bEditMode = false, $aExtraParams = array())
{
$sTitle = $this->aProperties['title'];
$sQuery = $this->aProperties['query'];
$sShowMenu = $this->aProperties['menu'] ? '1' : '0';
$oPage->add('<div class="dashlet-content">');
$sHtmlTitle = htmlentities(Dict::S($sTitle), ENT_QUOTES, 'UTF-8'); // done in the itop block
if ($sHtmlTitle != '')
{
$oPage->add('<h1>'.$sHtmlTitle.'</h1>');
}
if (isset($aExtraParams['query_params']))
{
$aQueryParams = $aExtraParams['query_params'];
}
elseif (isset($aExtraParams['this->class']) && isset($aExtraParams['this->id']))
{
$oObj = MetaModel::GetObject($aExtraParams['this->class'], $aExtraParams['this->id']);
$aQueryParams = $oObj->ToArgsForQuery();
}
else
{
$aQueryParams = array();
}
$oFilter = DBObjectSearch::FromOQL($sQuery, $aQueryParams);
$oPanel = PanelFactory::MakeNeutral(Dict::S($sTitle));
$oFilter = $this->GetDBSearch($aExtraParams);
$oBlock = new DisplayBlock($oFilter, 'list');
$aParams = array(
'menu' => $sShowMenu,
'table_id' => 'Dashlet'.$this->sId,
'table_id' => self::APPUSERPREFERENCES_PREFIX.$this->sId,
);
$sBlockId = 'block_'.$this->sId.($bEditMode ? '_edit' : ''); // make a unique id (edition occurring in the same DOM)
$oBlock->Display($oPage, $sBlockId, array_merge($aExtraParams, $aParams));
$oPage->add('</div>');
$oBlock->DisplayIntoContentBlock($oPanel, $oPage, $sBlockId, array_merge($aExtraParams, $aParams));
return $oPanel;
}
/**
@@ -956,23 +928,36 @@ class DashletObjectList extends Dashlet
$bShowMenu = $this->aProperties['menu'];
$oPage->add('<div class="dashlet-content">');
$sHtmlTitle = htmlentities($this->oModelReflection->DictString($sTitle), ENT_QUOTES, 'UTF-8'); // done in the itop block
if ($sHtmlTitle != '')
{
$sHtmlTitle = utils::HtmlEntities($this->oModelReflection->DictString($sTitle)); // done in the itop block
if ($sHtmlTitle != '') {
$oPage->add('<h1>'.$sHtmlTitle.'</h1>');
}
$oQuery = $this->oModelReflection->GetQuery($sQuery);
$sClass = $oQuery->GetClass();
$oPage->add('<div id="block_fake_'.$this->sId.'" class="display_block">');
$oPage->p(Dict::S('UI:NoObjectToDisplay'));
if ($bShowMenu)
{
if ($bShowMenu) {
$oPage->p('<a>'.Dict::Format('UI:ClickToCreateNew', $this->oModelReflection->GetName($sClass)).'</a>');
}
$oPage->add('</div>');
$oPage->add('</div>');
}
public function GetDBSearch($aExtraParams = array())
{
$sQuery = $this->aProperties['query'];
if (isset($aExtraParams['query_params'])) {
$aQueryParams = $aExtraParams['query_params'];
} elseif (isset($aExtraParams['this->class']) && isset($aExtraParams['this->id'])) {
$oObj = MetaModel::GetObject($aExtraParams['this->class'], $aExtraParams['this->id']);
$aQueryParams = $oObj->ToArgsForQuery();
} else {
$aQueryParams = array();
}
return DBObjectSearch::FromOQL($sQuery, $aQueryParams);
}
/**
* @inheritdoc
*/
@@ -1112,7 +1097,7 @@ abstract class DashletGroupBy extends Dashlet
$this->sFunction = null;
}
if (empty($this->aProperties['order_direction']))
if ((!is_null($this->sClass)) && empty($this->aProperties['order_direction']))
{
$aAttributeTypes = $this->oModelReflection->ListAttributes($this->sClass);
if (isset($aAttributeTypes[$this->sGroupByAttCode]))
@@ -1190,93 +1175,81 @@ abstract class DashletGroupBy extends Dashlet
$sStyle = $this->aProperties['style'];
// First perform the query - if the OQL is not ok, it will generate an exception : no need to go further
if (isset($aExtraParams['query_params']))
{
if (isset($aExtraParams['query_params'])) {
$aQueryParams = $aExtraParams['query_params'];
}
elseif (isset($aExtraParams['this->class']) && isset($aExtraParams['this->id']))
{
} elseif (isset($aExtraParams['this->class']) && isset($aExtraParams['this->id'])) {
$oObj = MetaModel::GetObject($aExtraParams['this->class'], $aExtraParams['this->id']);
$aQueryParams = $oObj->ToArgsForQuery();
}
else
{
} else {
$aQueryParams = array();
}
$oFilter = DBObjectSearch::FromOQL($sQuery, $aQueryParams);
$oFilter->SetShowObsoleteData(utils::ShowObsoleteData());
$sClass = $oFilter->GetClass();
if (!$this->oModelReflection->IsValidAttCode($sClass, $this->sGroupByAttCode))
{
$oPage->add('<p>'.Dict::S('UI:DashletGroupBy:MissingGroupBy').'</p>');
if (!$this->oModelReflection->IsValidAttCode($sClass, $this->sGroupByAttCode)) {
return new Html('<p>'.Dict::S('UI:DashletGroupBy:MissingGroupBy').'</p>');
}
else
{
switch($sStyle)
{
case 'bars':
$sType = 'chart';
$aParams = array(
'chart_type' => 'bars',
'chart_title' => $sTitle,
'group_by' => $this->sGroupByExpr,
'group_by_label' => $this->sGroupByLabel,
'aggregation_function' => $this->sAggregationFunction,
'aggregation_attribute' => $this->sAggregationAttribute,
'limit' => $this->sLimit,
'order_direction' => $this->sOrderDirection,
'order_by' => $this->sOrderBy,
);
$sHtmlTitle = ''; // done in the itop block
break;
case 'pie':
$sType = 'chart';
$aParams = array(
'chart_type' => 'pie',
'chart_title' => $sTitle,
'group_by' => $this->sGroupByExpr,
'group_by_label' => $this->sGroupByLabel,
'aggregation_function' => $this->sAggregationFunction,
'aggregation_attribute' => $this->sAggregationAttribute,
'limit' => $this->sLimit,
'order_direction' => $this->sOrderDirection,
'order_by' => $this->sOrderBy,
);
$sHtmlTitle = ''; // done in the itop block
break;
switch ($sStyle) {
case 'bars':
$sType = 'chart';
$aParams = array(
'chart_type' => 'bars',
'chart_title' => $sTitle,
'group_by' => $this->sGroupByExpr,
'group_by_label' => $this->sGroupByLabel,
'aggregation_function' => $this->sAggregationFunction,
'aggregation_attribute' => $this->sAggregationAttribute,
'limit' => $this->sLimit,
'order_direction' => $this->sOrderDirection,
'order_by' => $this->sOrderBy,
);
$sHtmlTitle = ''; // done in the itop block
break;
case 'table':
default:
$sHtmlTitle = htmlentities(Dict::S($sTitle), ENT_QUOTES, 'UTF-8'); // done in the itop block
$sType = 'count';
$aParams = array(
'group_by' => $this->sGroupByExpr,
'group_by_label' => $this->sGroupByLabel,
'aggregation_function' => $this->sAggregationFunction,
'aggregation_attribute' => $this->sAggregationAttribute,
'limit' => $this->sLimit,
'order_direction' => $this->sOrderDirection,
'order_by' => $this->sOrderBy,
);
break;
}
case 'pie':
$sType = 'chart';
$aParams = array(
'chart_type' => 'pie',
'chart_title' => $sTitle,
'group_by' => $this->sGroupByExpr,
'group_by_label' => $this->sGroupByLabel,
'aggregation_function' => $this->sAggregationFunction,
'aggregation_attribute' => $this->sAggregationAttribute,
'limit' => $this->sLimit,
'order_direction' => $this->sOrderDirection,
'order_by' => $this->sOrderBy,
);
$sHtmlTitle = ''; // done in the itop block
break;
$oPage->add('<div style="text-align:center" class="dashlet-content">');
if ($sHtmlTitle != '')
{
$oPage->add('<h1>'.$sHtmlTitle.'</h1>');
}
$sBlockId = 'block_'.$this->sId.($bEditMode ? '_edit' : ''); // make a unique id (edition occuring in the same DOM)
$oBlock = new DisplayBlock($oFilter, $sType);
$oBlock->Display($oPage, $sBlockId, array_merge($aExtraParams, $aParams));
if($bEditMode)
{
$oPage->add('<div class="dashlet-blocker"></div>');
}
$oPage->add('</div>');
case 'table':
default:
$sHtmlTitle = utils::HtmlEntities(Dict::S($sTitle)); // done in the itop block
$sType = 'count';
$aParams = array(
'group_by' => $this->sGroupByExpr,
'group_by_label' => $this->sGroupByLabel,
'aggregation_function' => $this->sAggregationFunction,
'aggregation_attribute' => $this->sAggregationAttribute,
'limit' => $this->sLimit,
'order_direction' => $this->sOrderDirection,
'order_by' => $this->sOrderBy,
);
break;
}
$oPanel = PanelFactory::MakeNeutral(Dict::S($sTitle));
$sBlockId = 'block_'.$this->sId.($bEditMode ? '_edit' : ''); // make a unique id (edition occurring in the same DOM)
$oBlock = new DisplayBlock($oFilter, $sType);
$oBlock->DisplayIntoContentBlock($oPanel, $oPage, $sBlockId, array_merge($aExtraParams, $aParams));
if ($bEditMode) {
$oPanel->AddHtml('<div class="dashlet-blocker"></div>');
}
return $oPanel;
}
/**
@@ -1359,9 +1332,9 @@ abstract class DashletGroupBy extends Dashlet
*/
public function RenderNoData($oPage, $bEditMode = false, $aExtraParams = array())
{
$oPage->add('<div class="dashlet-content">');
$oPage->add('error!');
$oPage->add('</div>');
$oDashletContainer = new DashletContainer(null, 'dashlet-content');
$oDashletContainer->AddHtml('error!');
return $oDashletContainer;
}
/**
@@ -1682,26 +1655,27 @@ class DashletGroupByPie extends DashletGroupBy
*/
public function RenderNoData($oPage, $bEditMode = false, $aExtraParams = array())
{
$oDashletContainer = new DashletContainer(null, 'dashlet-content');
$sTitle = $this->aProperties['title'];
$sBlockId = 'block_fake_'.$this->sId.($bEditMode ? '_edit' : ''); // make a unique id (edition occuring in the same DOM)
$HTMLsTitle = ($sTitle != '') ? '<h1 style="text-align:center">'.htmlentities($sTitle, ENT_QUOTES, 'UTF-8').'</h1>' : '';
$oPage->add("<div style=\"background-color:#fff;padding:0.25em;\">$HTMLsTitle<div id=\"$sBlockId\" style=\"background-color:#fff;\"></div></div>");
$HTMLsTitle = ($sTitle != '') ? '<h1 style="text-align:center">'.utils::HtmlEntities($sTitle).'</h1>' : '';
$oDashletContainer->AddHtml("<div style=\"background-color:#fff;padding:0.25em;\">$HTMLsTitle<div id=\"$sBlockId\" style=\"background-color:#fff;\"></div></div>");
$aDisplayValues = $this->MakeSimulatedData();
$aColumns = array();
$aNames = array();
foreach($aDisplayValues as $idx => $aValue)
{
foreach ($aDisplayValues as $idx => $aValue) {
$aColumns[] = array('series_'.$idx, (int)$aValue['value']);
$aNames['series_'.$idx] = $aValue['label'];
}
$sJSColumns = json_encode($aColumns);
$sJSNames = json_encode($aNames);
$oPage->add_ready_script(
<<<EOF
<<<EOF
window.setTimeout(function() {
var chart = c3.generate({
bindto: '#{$sBlockId}',
@@ -1722,6 +1696,8 @@ var chart = c3.generate({
});}, 100);
EOF
);
return $oDashletContainer;
}
}
@@ -1754,25 +1730,26 @@ class DashletGroupByBars extends DashletGroupBy
*/
public function RenderNoData($oPage, $bEditMode = false, $aExtraParams = array())
{
$oDashletContainer = new DashletContainer(null, 'dashlet-content');
$sTitle = $this->aProperties['title'];
$sBlockId = 'block_fake_'.$this->sId.($bEditMode ? '_edit' : ''); // make a unique id (edition occuring in the same DOM)
$HTMLsTitle = ($sTitle != '') ? '<h1 style="text-align:center">'.htmlentities($sTitle, ENT_QUOTES, 'UTF-8').'</h1>' : '';
$oPage->add("<div style=\"background-color:#fff;padding:0.25em;\">$HTMLsTitle<div id=\"$sBlockId\" style=\"background-color:#fff;\"></div></div>");
$HTMLsTitle = ($sTitle != '') ? '<h1 style="text-align:center">'.utils::HtmlEntities($sTitle).'</h1>' : '';
$oDashletContainer->AddHtml("<div style=\"background-color:#fff;padding:0.25em;\">$HTMLsTitle<div id=\"$sBlockId\" style=\"background-color:#fff;\"></div></div>");
$aDisplayValues = $this->MakeSimulatedData();
$aNames = array();
foreach($aDisplayValues as $idx => $aValue)
{
foreach ($aDisplayValues as $idx => $aValue) {
$aNames[$idx] = $aValue['label'];
}
$sJSNames = json_encode($aNames);
$sJson = json_encode($aDisplayValues);
$oPage->add_ready_script(
<<<EOF
<<<EOF
window.setTimeout(function() {
var chart = c3.generate({
bindto: '#{$sBlockId}',
@@ -1820,6 +1797,8 @@ window.setTimeout(function() {
}, 100);
EOF
);
return $oDashletContainer;
}
}
@@ -1851,40 +1830,44 @@ class DashletGroupByTable extends DashletGroupBy
*/
public function RenderNoData($oPage, $bEditMode = false, $aExtraParams = array())
{
$oDashletContainer = new DashletContainer();
$aDisplayValues = $this->MakeSimulatedData();
$iTotal = 0;
foreach($aDisplayValues as $iRow => $aDisplayData)
{
foreach ($aDisplayValues as $iRow => $aDisplayData) {
$iTotal += $aDisplayData['value'];
}
$oPage->add('<div class="dashlet-content">');
$sBlockId = 'block_fake_'.$this->sId.($bEditMode ? '_edit' : ''); // make a unique id (edition occuring in the same DOM)
$oPage->add('<div id="'.$sBlockId.'" class="display_block">');
$oPage->add('<p>'.Dict::Format('UI:Pagination:HeaderNoSelection', $iTotal).'</p>');
$oPage->add('<table class="listResults">');
$oPage->add('<thead>');
$oPage->add('<tr>');
$oPage->add('<th class="header" title="">'.$this->sGroupByLabel.'</th>');
$oPage->add('<th class="header" title="'.Dict::S('UI:GroupBy:Count+').'">'.Dict::S('UI:GroupBy:Count').'</th>');
$oPage->add('</tr>');
$oPage->add('</thead>');
$oPage->add('<tbody>');
foreach($aDisplayValues as $aDisplayData)
{
$oPage->add('<tr class="even">');
$oPage->add('<td class=""><span title="Active">'.$aDisplayData['label'].'</span></td>');
$oPage->add('<td class=""><a>'.$aDisplayData['value'].'</a></td>');
$oPage->add('</tr>');
$sHtml = '';
$sHtml .= '<div id="'.$sBlockId.'" class="display_block">';
$sHtml .= '<div class="dashlet-content">';
$sHtml .= '<p>'.Dict::Format('UI:Pagination:HeaderNoSelection', $iTotal).'</p>';
$sHtml .= '<table class="listResults">';
$sHtml .= '<thead>';
$sHtml .= '<tr>';
$sHtml .= '<th class="header" title="">'.$this->sGroupByLabel.'</th>';
$sHtml .= '<th class="header" title="'.Dict::S('UI:GroupBy:Count+').'">'.Dict::S('UI:GroupBy:Count').'</th>';
$sHtml .= '</tr>';
$sHtml .= '</thead>';
$sHtml .= '<tbody>';
foreach ($aDisplayValues as $aDisplayData) {
$sHtml .= '<tr class="even">';
$sHtml .= '<td class=""><span title="Active">'.$aDisplayData['label'].'</span></td>';
$sHtml .= '<td class=""><a>'.$aDisplayData['value'].'</a></td>';
$sHtml .= '</tr>';
}
$oPage->add('</tbody>');
$oPage->add('</table>');
$oPage->add('</div>');
$sHtml .= '</tbody>';
$sHtml .= '</table>';
$sHtml .= '</div>';
$oPage->add('</div>');
$sHtml .= '</div>';
$oDashletContainer->AddHtml($sHtml);
return $oDashletContainer;
}
}
@@ -1907,20 +1890,13 @@ class DashletHeaderStatic extends Dashlet
*/
public function Render($oPage, $bEditMode = false, $aExtraParams = array())
{
$sTitle = $this->aProperties['title'];
$sTitle = utils::HtmlEntities($this->aProperties['title']);
$sIcon = $this->aProperties['icon'];
$oIconSelect = $this->oModelReflection->GetIconSelectionField('icon');
$sIconPath = $oIconSelect->MakeFileUrl($sIcon);
$sIconPath = utils::HtmlEntities($oIconSelect->MakeFileUrl($sIcon));
$oPage->add('<div class="dashlet-content">');
$oPage->add('<div class="main_header">');
$oPage->add('<img src="'.utils::HtmlEntities($sIconPath).'">');
$oPage->add('<h1>'.$this->oModelReflection->DictString($sTitle).'</h1>');
$oPage->add('</div>');
$oPage->add('</div>');
return DashletFactory::MakeForDashletHeaderStatic($this->oModelReflection->DictString($sTitle), $sIconPath);
}
/**
@@ -2037,18 +2013,17 @@ class DashletHeaderDynamic extends Dashlet
*/
public function Render($oPage, $bEditMode = false, $aExtraParams = array())
{
$sTitle = $this->aProperties['title'];
$sTitle = utils::HtmlEntities($this->aProperties['title']);
$sIcon = $this->aProperties['icon'];
$sSubtitle = $this->aProperties['subtitle'];
$sSubtitle = utils::HtmlEntities($this->aProperties['subtitle']);
$sQuery = $this->aProperties['query'];
$sGroupBy = $this->aProperties['group_by'];
$oIconSelect = $this->oModelReflection->GetIconSelectionField('icon');
$sIconPath = $oIconSelect->MakeFileUrl($sIcon);
$sIconPath = utils::HtmlEntities($oIconSelect->MakeFileUrl($sIcon));
$aValues = $this->GetValues();
if (count($aValues) > 0)
{
if (count($aValues) > 0) {
// Stats grouped by <group_by>
$sCSV = implode(',', $aValues);
$aParams = array(
@@ -2058,9 +2033,7 @@ class DashletHeaderDynamic extends Dashlet
'status_codes[block]' => $sCSV,
'context_filter' => 1,
);
}
else
{
} else {
// Simple stats
$aParams = array(
'title[block]' => $sTitle,
@@ -2069,31 +2042,29 @@ class DashletHeaderDynamic extends Dashlet
);
}
$oPage->add('<div class="dashlet-content">');
$oPage->add('<div class="main_header">');
$oPanel = PanelFactory::MakeEnhancedNeutral(Dict::S(str_replace('_', ':', $sTitle)), $sIconPath);
$oPage->add('<img src="'.utils::HtmlEntities($sIconPath).'">');
if (isset($aExtraParams['query_params']))
{
if (isset($aExtraParams['query_params'])) {
$aQueryParams = $aExtraParams['query_params'];
}
elseif (isset($aExtraParams['this->class']))
{
} elseif (isset($aExtraParams['this->class'])) {
$oObj = MetaModel::GetObject($aExtraParams['this->class'], $aExtraParams['this->id']);
$aQueryParams = $oObj->ToArgsForQuery();
}
else
{
} else {
$aQueryParams = array();
}
$oFilter = DBObjectSearch::FromOQL($sQuery, $aQueryParams);
$oBlock = new DisplayBlock($oFilter, 'summary');
$sBlockId = 'block_'.$this->sId.($bEditMode ? '_edit' : ''); // make a unique id (edition occuring in the same DOM)
$oBlock->Display($oPage, $sBlockId, array_merge($aExtraParams, $aParams));
$oBlock->DisplayIntoContentBlock($oPanel, $oPage, $sBlockId, array_merge($aExtraParams, $aParams));
$oPage->add('</div>');
$oPage->add('</div>');
$oSubTitle = $oPanel->GetSubTitle();
$oSet = new DBObjectSet($oFilter);
$iCount = $oSet->Count();
$oAppContext = new ApplicationContext();
$sHyperlink = utils::GetAbsoluteUrlAppRoot().'pages/UI.php?operation=search&'.$oAppContext->GetForLink().'&filter='.rawurlencode($oFilter->serialize());
$oSubTitle->AddHtml('<a class="summary" href="'.$sHyperlink.'">'.Dict::Format(str_replace('_', ':', $sSubtitle), $iCount).'</a>');
return $oPanel;
}
/**
@@ -2101,9 +2072,9 @@ class DashletHeaderDynamic extends Dashlet
*/
public function RenderNoData($oPage, $bEditMode = false, $aExtraParams = array())
{
$sTitle = $this->aProperties['title'];
$sTitle = utils::HtmlEntities($this->aProperties['title']);
$sIcon = $this->aProperties['icon'];
$sSubtitle = $this->aProperties['subtitle'];
$sSubtitle = utils::HtmlEntities($this->aProperties['subtitle']);
$sQuery = $this->aProperties['query'];
$sGroupBy = $this->aProperties['group_by'];
@@ -2111,48 +2082,50 @@ class DashletHeaderDynamic extends Dashlet
$sClass = $oQuery->GetClass();
$oIconSelect = $this->oModelReflection->GetIconSelectionField('icon');
$sIconPath = $oIconSelect->MakeFileUrl($sIcon);
$sIconPath = utils::HtmlEntities($oIconSelect->MakeFileUrl($sIcon));
$oPage->add('<div class="dashlet-content">');
$oPage->add('<div class="main_header">');
$oDashletContainer = new DashletContainer(null, 'dashlet-content');
$oPage->add('<img src="'.utils::HtmlEntities($sIconPath).'">');
$sHtml = '';
$sHtml .= '<img src="'.$sIconPath.'">';
$sBlockId = 'block_fake_'.$this->sId.($bEditMode ? '_edit' : ''); // make a unique id (edition occuring in the same DOM)
$iTotal = 0;
$aValues = $this->GetValues();
$oPage->add('<div class="display_block" id="'.$sBlockId.'">');
$oPage->add('<div class="summary-details">');
$oPage->add('<table><tbody>');
$oPage->add('<tr>');
foreach ($aValues as $sValue)
{
$sHtml .= '<div class="display_block" id="'.$sBlockId.'">';
$sHtml .= '<div class="summary-details">';
$sHtml .= '<table><tbody>';
$sHtml .= '<tr>';
foreach ($aValues as $sValue) {
$sValueLabel = $this->oModelReflection->GetValueLabel($sClass, $sGroupBy, $sValue);
$oPage->add(' <th>'.$sValueLabel.'</th>');
$sHtml .= ' <th>'.$sValueLabel.'</th>';
}
$oPage->add('</tr>');
$oPage->add('<tr>');
foreach ($aValues as $sValue)
{
$iCount = (int) rand(2, 100);
$sHtml .= '</tr>';
$sHtml .= '<tr>';
foreach ($aValues as $sValue) {
$iCount = (int)rand(2, 100);
$iTotal += $iCount;
$oPage->add(' <td>'.$iCount.'</td>');
$sHtml .= ' <td>'.$iCount.'</td>';
}
$oPage->add('</tr>');
$oPage->add('</tbody></table>');
$oPage->add('</div>');
$sHtml .= '</tr>';
$sHtml .= '</tbody></table>';
$sHtml .= '</div>';
$sTitle = $this->oModelReflection->DictString($sTitle);
$sSubtitle = $this->oModelReflection->DictFormat($sSubtitle, $iTotal);
$oPage->add('<h1>'.$sTitle.'</h1>');
$oPage->add('<a class="summary">'.$sSubtitle.'</a>');
$oPage->add('</div>');
$sHtml .= '<h1>'.utils::HtmlEntities($sTitle).'</h1>';
$sHtml .= '<a class="summary">'.utils::HtmlEntities($sSubtitle).'</a>';
$sHtml .= '</div>';
$sHtml .= '</div>';
$oDashletContainer->AddHtml($sHtml);
return $oDashletContainer;
$oPage->add('</div>');
$oPage->add('</div>');
}
/**
@@ -2297,8 +2270,8 @@ class DashletBadge extends Dashlet
{
parent::__construct($oModelReflection, $sId);
$this->aProperties['class'] = 'Contact';
$this->aCSSClasses[] = 'dashlet-inline';
$this->aCSSClasses[] = 'dashlet-badge';
$this->aCSSClasses[] = 'ibo-dashlet--is-inline';
$this->aCSSClasses[] = 'ibo-dashlet-badge';
}
/**
@@ -2308,17 +2281,16 @@ class DashletBadge extends Dashlet
*/
public function Render($oPage, $bEditMode = false, $aExtraParams = array())
{
$oDashletContainer = new DashletContainer($this->sId, 'dashlet-content');
$sClass = $this->aProperties['class'];
$oPage->add('<div class="dashlet-content">');
$oFilter = new DBObjectSearch($sClass);
$oBlock = new DisplayBlock($oFilter, 'actions');
$aExtraParams['context_filter'] = 1;
$sBlockId = 'block_'.$this->sId.($bEditMode ? '_edit' : ''); // make a unique id (edition occurring in the same DOM)
$oBlock->Display($oPage, $sBlockId, $aExtraParams);
$oBlock->DisplayIntoContentBlock($oDashletContainer, $oPage, $sBlockId, $aExtraParams);
$oPage->add('</div>');
return $oDashletContainer;
}
/**
@@ -2326,25 +2298,25 @@ class DashletBadge extends Dashlet
*/
public function RenderNoData($oPage, $bEditMode = false, $aExtraParams = array())
{
$sClass = $this->aProperties['class'];
$oDashletContainer = new DashletContainer($this->sId, 'dashlet-content');
$sClass = $this->aProperties['class'];
$sIconUrl = $this->oModelReflection->GetClassIcon($sClass, false);
$sClassLabel = $this->oModelReflection->GetName($sClass);
$oPage->add('<div class="dashlet-content">');
$sHtml = '';
$sHtml .= '<div id="block_fake_'.$this->sId.'" class="display_block">';
$sHtml .= '<p>';
$sHtml .= ' <a class="actions"><img src="'.utils::HtmlEntities($sIconUrl).'" style="vertical-align:middle;float;left;margin-right:10px;border:0;">'.$sClassLabel.': 947</a>';
$sHtml .= '</p>';
$sHtml .= '<p>';
$sHtml .= ' <a>'.Dict::Format('UI:ClickToCreateNew', $sClassLabel).'</a>';
$sHtml .= '</p>';
$sHtml .= '</div>';
$oPage->add('<div id="block_fake_'.$this->sId.'" class="display_block">');
$oPage->add('<p>');
$oPage->add(' <a class="actions"><img src="'.utils::HtmlEntities($sIconUrl).'" style="vertical-align:middle;float;left;margin-right:10px;border:0;">'.$sClassLabel.': 947</a>');
$oPage->add('</p>');
$oPage->add('<p>');
$oPage->add(' <a>'.Dict::Format('UI:ClickToCreateNew', $sClassLabel).'</a>');
$oPage->add(' <br/>');
$oPage->add(' <a>'.Dict::Format('UI:SearchFor_Class', $sClassLabel).'</a>');
$oPage->add('</p>');
$oPage->add('</div>');
$oDashletContainer->AddHtml($sHtml);
$oPage->add('</div>');
return $oDashletContainer;
}
static protected $aClassList = null;

View File

@@ -1,5 +1,46 @@
<?xml version="1.0" encoding="UTF-8"?>
<itop_design xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="1.6">
<itop_design xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="3.0">
<classes>
<class id="AbstractResource" _delta="define">
<parent>cmdbAbstractObject</parent>
<properties>
<comment>/* Resource access control abstraction. Can be herited by abstract resource access control classes. Generaly controlled using UR_ACTION_MODIFY access right. */</comment>
<abstract>true</abstract>
</properties>
<presentation/>
<methods/>
</class>
<class id="ResourceAdminMenu" _delta="define">
<parent>AbstractResource</parent>
<properties>
<comment>/* AdminTools menu access control. */</comment>
<abstract>true</abstract>
<category>grant_by_profile</category>
</properties>
<presentation/>
<methods/>
</class>
<class id="ResourceRunQueriesMenu" _delta="define">
<parent>AbstractResource</parent>
<properties>
<comment>/* RunQueriesMenu menu access control. */</comment>
<abstract>true</abstract>
<category>grant_by_profile</category>
</properties>
<presentation/>
<methods/>
</class>
<class id="ResourceSystemMenu" _delta="define">
<parent>AbstractResource</parent>
<properties>
<comment>/* System menu access control. */</comment>
<abstract>true</abstract>
<category>grant_by_profile</category>
</properties>
<presentation/>
<methods/>
</class>
</classes>
<portals>
<portal id="backoffice" _delta="define">
<url>pages/UI.php</url>
@@ -12,13 +53,351 @@
</portal>
</portals>
<menus>
<menu id="WelcomeMenu" xsi:type="MenuGroup" _delta="define">
<rank>10</rank>
<style>
<decoration_classes>fas fa-home</decoration_classes>
</style>
</menu>
<menu id="WelcomeMenuPage" xsi:type="DashboardMenuNode" _delta="define">
<rank>10</rank>
<parent>WelcomeMenu</parent>
<definition>
<layout>DashboardLayoutOneCol</layout>
<title/>
<cells>
<cell id="0">
<rank>0</rank>
<dashlets>
</dashlets>
</cell>
</cells>
</definition>
</menu>
<menu id="MyShortcuts" xsi:type="ShortcutContainerMenuNode" _delta="define">
<rank>20</rank>
<parent>WelcomeMenu</parent>
</menu>
<menu id="UserManagement" xsi:type="TemplateMenuNode" _delta="define">
<rank>10</rank>
<parent>AdminTools</parent>
<template_file/>
</menu>
<menu id="UserAccountsMenu" xsi:type="OQLMenuNode" _delta="define">
<rank>11</rank>
<parent>UserManagement</parent>
<oql><![CDATA[SELECT User]]></oql>
<do_search>1</do_search>
<search_form_open>1</search_form_open>
<enable_class>User</enable_class>
<enable_action>UR_ACTION_MODIFY</enable_action>
</menu>
<menu id="ProfilesMenu" xsi:type="OQLMenuNode" _delta="define">
<rank>12</rank>
<parent>UserManagement</parent>
<oql><![CDATA[SELECT URP_Profiles]]></oql>
<do_search>1</do_search>
<enable_class>URP_Profiles</enable_class>
<enable_action>UR_ACTION_MODIFY</enable_action>
</menu>
<menu id="AuditCategories" xsi:type="OQLMenuNode" _delta="define">
<rank>20</rank>
<parent>AdminTools</parent>
<oql><![CDATA[SELECT AuditCategory]]></oql>
<do_search>1</do_search>
<enable_class>AuditCategory</enable_class>
<enable_action>UR_ACTION_MODIFY</enable_action>
</menu>
<menu id="Queries" xsi:type="TemplateMenuNode" _delta="define">
<rank>30</rank>
<parent>AdminTools</parent>
<template_file/>
</menu>
<menu id="RunQueriesMenu" xsi:type="WebPageMenuNode" _delta="define">
<rank>31</rank>
<parent>Queries</parent>
<url>$pages/run_query.php</url>
<enable_class>ResourceRunQueriesMenu</enable_class>
<enable_action>UR_ACTION_MODIFY</enable_action>
</menu>
<menu id="QueryMenu" xsi:type="OQLMenuNode" _delta="define">
<rank>32</rank>
<parent>Queries</parent>
<oql><![CDATA[SELECT Query]]></oql>
<do_search>1</do_search>
<enable_class>Query</enable_class>
<enable_action>UR_ACTION_MODIFY</enable_action>
</menu>
<menu id="ExportMenu" xsi:type="WebPageMenuNode" _delta="define">
<rank>33</rank>
<parent>Queries</parent>
<url>$webservices/export-v2.php?interactive=1</url>
<enable_class>ResourceAdminMenu</enable_class>
<enable_action>UR_ACTION_MODIFY</enable_action>
</menu>
<menu id="DataModelMenu" xsi:type="WebPageMenuNode" _delta="define">
<rank>40</rank>
<parent>AdminTools</parent>
<url>$pages/schema.php</url>
<enable_class>ResourceRunQueriesMenu</enable_class>
<enable_action>UR_ACTION_MODIFY</enable_action>
</menu>
<menu id="UniversalSearchMenu" xsi:type="WebPageMenuNode" _delta="define">
<rank>35</rank>
<parent>Queries</parent>
<url>$pages/UniversalSearch.php</url>
<enable_class>ResourceAdminMenu</enable_class>
<enable_action>UR_ACTION_MODIFY</enable_action>
</menu>
<menu id="ConfigurationTools" xsi:type="MenuGroup" _delta="define_if_not_exists">
<rank>90</rank>
<style>
<decoration_classes>fas fa-cog</decoration_classes>
</style>
</menu>
<menu id="DataSources" xsi:type="OQLMenuNode" _delta="define">
<rank>20</rank>
<parent>ConfigurationTools</parent>
<oql><![CDATA[SELECT SynchroDataSource]]></oql>
<do_search>1</do_search>
<enable_class>SynchroDataSource</enable_class>
<enable_action>UR_ACTION_MODIFY</enable_action>
</menu>
<menu id="NotificationsMenu" xsi:type="WebPageMenuNode" _delta="define">
<rank>40</rank>
<parent>ConfigurationTools</parent>
<url>$pages/notifications.php</url>
<enable_class>Trigger</enable_class>
<enable_action>UR_ACTION_MODIFY</enable_action>
</menu>
<menu id="AdminTools" xsi:type="MenuGroup" _delta="define">
<rank>80</rank>
<style>
<decoration_classes>fas fa-tools</decoration_classes>
</style>
</menu>
<menu id="System" xsi:type="MenuGroup" _delta="define">
<menu id="SystemTools" xsi:type="MenuGroup" _delta="define">
<rank>100</rank>
<enable_class>ResourceSystemMenu</enable_class>
<enable_action>UR_ACTION_MODIFY</enable_action>
<style>
<decoration_classes>fas fa-terminal</decoration_classes>
</style>
</menu>
</menus>
<meta>
<classes>
<class id="cmdbAbstractObject" _delta="define">
<methods>
<method id="Set">
<arguments>
<argument id="1">
<type>attcode</type>
<mandatory>true</mandatory>
<type_restrictions>
<operation>deny</operation>
<types>
<type id="AttributeStopWatch"/>
<type id="AttributeSubItem"/>
<type id="AttributeExternalField"/>
<type id="AttributeLinkedSetIndirect"/>
<type id="AttributeLinkedSet"/>
<type id="AttributeImage"/>
<type id="AttributeBlob"/>
</types>
</type_restrictions>
</argument>
<argument id="2">
<type>string</type>
<mandatory>true</mandatory>
</argument>
</arguments>
</method>
<method id="SetIfNull">
<arguments>
<argument id="1">
<type>attcode</type>
<mandatory>true</mandatory>
<type_restrictions>
<operation>deny</operation>
<types>
<type id="AttributeStopWatch"/>
<type id="AttributeSubItem"/>
<type id="AttributeExternalField"/>
<type id="AttributeLinkedSetIndirect"/>
<type id="AttributeLinkedSet"/>
<type id="AttributeImage"/>
<type id="AttributeBlob"/>
</types>
</type_restrictions>
</argument>
<argument id="2">
<type>string</type>
<mandatory>true</mandatory>
</argument>
</arguments>
</method>
<method id="SetCurrentDate">
<arguments>
<argument id="1">
<type>attcode</type>
<mandatory>true</mandatory>
<type_restrictions>
<operation>allow</operation>
<types>
<type id="AttributeDate"/>
<type id="AttributeDateTime"/>
<type id="AttributeString"/>
</types>
</type_restrictions>
</argument>
</arguments>
</method>
<method id="SetCurrentUser">
<arguments>
<argument id="1">
<type>attcode</type>
<mandatory>true</mandatory>
<type_restrictions>
<operation>allow</operation>
<types>
<type id="AttributeExternalKey"/>
<type id="AttributeInteger"/>
<type id="AttributeString"/>
</types>
</type_restrictions>
</argument>
</arguments>
</method>
<method id="SetCurrentPerson">
<arguments>
<argument id="1">
<type>attcode</type>
<mandatory>true</mandatory>
<type_restrictions>
<operation>allow</operation>
<types>
<type id="AttributeExternalKey"/>
<type id="AttributeInteger"/>
<type id="AttributeString"/>
</types>
</type_restrictions>
</argument>
</arguments>
</method>
<method id="SetElapsedTime">
<arguments>
<argument id="1">
<type>attcode</type>
<mandatory>true</mandatory>
<type_restrictions>
<operation>allow</operation>
<types>
<type id="AttributeDuration"/>
</types>
</type_restrictions>
</argument>
<argument id="2">
<type>attcode</type>
<mandatory>true</mandatory>
<type_restrictions>
<operation>allow</operation>
<types>
<type id="AttributeDate"/>
<type id="AttributeDateTime"/>
</types>
</type_restrictions>
</argument>
<argument id="3">
<type>string</type>
<mandatory>false</mandatory>
</argument>
</arguments>
</method>
<method id="Reset">
<arguments>
<argument id="1">
<type>attcode</type>
<mandatory>true</mandatory>
<type_restrictions>
<operation>deny</operation>
<types>
<type id="AttributeStopWatch"/>
<type id="AttributeSubItem"/>
<type id="AttributeExternalField"/>
</types>
</type_restrictions>
</argument>
</arguments>
</method>
<method id="ResetStopWatch">
<arguments>
<argument id="1">
<type>attcode</type>
<mandatory>true</mandatory>
<type_restrictions>
<operation>allow</operation>
<types>
<type id="AttributeStopWatch"/>
</types>
</type_restrictions>
</argument>
</arguments>
</method>
<method id="Copy">
<arguments>
<argument id="1">
<type>attcode</type>
<mandatory>true</mandatory>
<type_restrictions>
<operation>deny</operation>
<types>
<type id="AttributeStopWatch"/>
<type id="AttributeSubItem"/>
<type id="AttributeExternalField"/>
</types>
</type_restrictions>
</argument>
<argument id="2">
<type>attcode</type>
<mandatory>true</mandatory>
</argument>
</arguments>
</method>
<method id="ApplyStimulus">
<arguments>
<argument id="1">
<type>string</type>
<mandatory>true</mandatory>
</argument>
</arguments>
</method>
<method id="PrefillCreationForm">
<arguments>
<argument id="1">
<type>reference</type>
<mandatory>true</mandatory>
</argument>
</arguments>
</method>
<method id="PrefillTransitionForm">
<arguments>
<argument id="1">
<type>reference</type>
<mandatory>true</mandatory>
</argument>
</arguments>
</method>
<method id="PrefillSearchForm">
<arguments>
<argument id="1">
<type>reference</type>
<mandatory>true</mandatory>
</argument>
</arguments>
</method>
</methods>
</class>
</classes>
</meta>
</itop_design>

View File

@@ -1,4 +1,7 @@
<?php
use Combodo\iTop\Renderer\BlockRenderer;
/**
* Copyright (C) 2013-2020 Combodo SARL
*
@@ -20,19 +23,21 @@
class DataTable
{
protected $iListId; // Unique ID inside the web page
/** @var string */
private $sDatatableContainerId;
protected $sTableId; // identifier for saving the settings (combined with the class aliases)
protected $oSet; // The set of objects to display
protected $aClassAliases; // The aliases (alias => class) inside the set
protected $iNbObjects; // Total number of objects inthe set
protected $iNbObjects; // Total number of objects in the set
protected $bUseCustomSettings; // Whether or not the current display uses custom settings
protected $oDefaultSettings; // the default settings for displaying such a list
protected $bShowObsoleteData;
/**
* @param $iListId mixed Unique ID for this div/table in the page
* @param $oSet DBObjectSet The set of data to display
* @param $aClassAliases array The list of classes/aliases to be displayed in this set $sAlias => $sClassName
* @param $sTableId mixed A string (or null) identifying this table in order to persist its settings
* @param string $iListId Unique ID for this div/table in the page
* @param DBObjectSet $oSet The set of data to display
* @param array$aClassAliases The list of classes/aliases to be displayed in this set $sAlias => $sClassName
* @param string $sTableId A string (or null) identifying this table in order to persist its settings
*
* @throws \CoreException
* @throws \MissingQueryArgument
@@ -42,6 +47,7 @@ class DataTable
public function __construct($iListId, $oSet, $aClassAliases, $sTableId = null)
{
$this->iListId = utils::GetSafeId($iListId); // Make a "safe" ID for jQuery
$this->sDatatableContainerId = 'datatable_'.utils::GetSafeId($iListId);
$this->oSet = $oSet;
$this->aClassAliases = $aClassAliases;
$this->sTableId = $sTableId;
@@ -154,18 +160,18 @@ class DataTable
$sPager = $this->GetPager($oPage, $iPageSize, $iDefaultPageSize, $iPageIndex);
$sActionsMenu = '';
$sToolkitMenu = '';
if ($bActionsMenu)
{
if ($bActionsMenu) {
$sActionsMenu = $this->GetActionsMenu($oPage, $aExtraParams);
}
if ($bToolkitMenu)
{
$sToolkitMenu = $this->GetToolkitMenu($oPage, $aExtraParams);
}
// if ($bToolkitMenu)
// {
// $sToolkitMenu = $this->GetToolkitMenu($oPage, $aExtraParams);
// }
$sDataTable = $this->GetHTMLTable($oPage, $aColumns, $sSelectMode, $iPageSize, $bViewLink, $aExtraParams);
$sConfigDlg = $this->GetTableConfigDlg($oPage, $aColumns, $bViewLink, $iDefaultPageSize);
$sHtml = "<table id=\"datatable_{$this->iListId}\" class=\"datatable\">";
$sHtml = "<table id=\"{$this->sDatatableContainerId}\" class=\"datatable\">";
$sHtml .= "<tr><td>";
$sHtml .= "<table style=\"width:100%;\">";
$sHtml .= "<tr><td class=\"pagination_container\">$sObjectsCount</td><td class=\"menucontainer\">$sToolkitMenu $sActionsMenu</td></tr>";
@@ -201,11 +207,11 @@ class DataTable
$aOptions['oDefaultSettings'] = $this->GetAsHash($this->oDefaultSettings);
}
$sJSOptions = json_encode($aOptions);
$oPage->add_ready_script("$('#datatable_{$this->iListId}').datatable($sJSOptions);");
$oPage->add_ready_script("$('#{$this->sDatatableContainerId}').datatable($sJSOptions);");
return $sHtml;
}
/**
* When refreshing the body of a paginated table, get the rows of the table (inside the TBODY)
* return string The HTML rows to insert inside the <tbody> node
@@ -352,9 +358,18 @@ EOF;
protected function GetActionsMenu(WebPage $oPage, $aExtraParams)
{
$oMenuBlock = new MenuBlock($this->oSet->GetFilter(), 'list');
$sHtml = $oMenuBlock->GetRenderContent($oPage, $aExtraParams, $this->iListId);
return $sHtml;
$oBlock = $oMenuBlock->GetRenderContent($oPage, $aExtraParams, $this->iListId);
foreach ($oBlock->GetCssFilesUrlRecursively(true) as $sFileAbsUrl) {
$oPage->add_linked_stylesheet($sFileAbsUrl);
}
// JS files
foreach ($oBlock->GetJsFilesUrlRecursively(true) as $sFileAbsUrl) {
$oPage->add_linked_script($sFileAbsUrl);
}
$oPage->RenderInlineScriptsAndCSSRecursively($oBlock);
return BlockRenderer::RenderBlockTemplates($oBlock);
}
/**
@@ -418,15 +433,15 @@ EOF;
$sHtml .= "<input id=\"dtbl_dlg_all_{$this->iListId}\" type=\"radio\" name=\"scope\" $sGenericChecked value=\"defaults\"><label for=\"dtbl_dlg_all_{$this->iListId}\">&nbsp;".Dict::S('UI:ForAllLists').'</label></p>';
$sHtml .= "</fieldset>";
$sHtml .= '<table style="width:100%"><tr><td style="text-align:center;">';
$sHtml .= '<button type="button" onclick="$(\'#datatable_'.$this->iListId.'\').datatable(\'onDlgCancel\'); $(\'#datatable_dlg_'.$this->iListId.'\').dialog(\'close\')">'.Dict::S('UI:Button:Cancel').'</button>';
$sHtml .= '<button type="button" onclick="$(\'#'.$this->sDatatableContainerId.'\').datatable(\'onDlgCancel\'); $(\'#datatable_dlg_'.$this->iListId.'\').dialog(\'close\')">'.Dict::S('UI:Button:Cancel').'</button>';
$sHtml .= '</td><td style="text-align:center;">';
$sHtml .= '<button type="submit" onclick="$(\'#datatable_'.$this->iListId.'\').datatable(\'onDlgOk\');$(\'#datatable_dlg_'.$this->iListId.'\').dialog(\'close\');">'.Dict::S('UI:Button:Ok').'</button>';
$sHtml .= '<button type="submit" onclick="$(\'#'.$this->sDatatableContainerId.'\').datatable(\'onDlgOk\');$(\'#datatable_dlg_'.$this->iListId.'\').dialog(\'close\');">'.Dict::S('UI:Button:Ok').'</button>';
$sHtml .= '</td></tr></table>';
$sHtml .= "</form>";
$sHtml .= "</div>";
$sDlgTitle = addslashes(Dict::S('UI:ListConfigurationTitle'));
$oPage->add_ready_script("$('#datatable_dlg_{$this->iListId}').dialog({autoOpen: false, title: '$sDlgTitle', width: 500, close: function() { $('#datatable_{$this->iListId}').datatable('onDlgCancel'); } });");
$oPage->add_ready_script("$('#datatable_dlg_{$this->iListId}').dialog({autoOpen: false, title: '$sDlgTitle', width: 500, close: function() { $('#{$this->sDatatableContainerId}').datatable('onDlgCancel'); } });");
return $sHtml;
}
@@ -510,6 +525,7 @@ EOF;
return $aAttribs;
}
/**
* @param $aColumns
* @param $sSelectMode
@@ -745,12 +761,25 @@ EOF;
}
$sOQL = addslashes($this->oSet->GetFilter()->serialize());
$oPage->add_ready_script(
<<<EOF
var oTable = $('#{$this->iListId} table.listResults');
<<<JS
var oTable = $('#{$this->sDatatableContainerId} table.listResults');
oTable.tableHover();
oTable.tablesorter( { $sHeaders widgets: ['myZebra', 'truncatedList']} ).tablesorterPager({container: $('#pager{$this->iListId}'), totalRows:$iCount, size: $iPageSize, filter: '$sOQL', extra_params: '$sExtraParams', select_mode: '$sSelectModeJS', displayKey: $sDisplayKey, table_id: '{$this->iListId}', columns: $sJSColumns, class_aliases: $sJSClassAliases $sCssCount});
EOF
);
oTable
.tablesorter({ $sHeaders widgets: ['myZebra', 'truncatedList']})
.tablesorterPager({
container: $('#pager{$this->iListId}'),
totalRows:$iCount,
size: $iPageSize,
filter: '$sOQL',
extra_params: '$sExtraParams',
select_mode: '$sSelectModeJS',
displayKey: $sDisplayKey,
table_id: '{$this->sDatatableContainerId}',
columns: $sJSColumns,
class_aliases: $sJSClassAliases $sCssCount
});
JS
);
if ($sFakeSortList != '')
{
$oPage->add_ready_script("oTable.trigger(\"fakesorton\", [$sFakeSortList]);");
@@ -844,387 +873,3 @@ class PrintableDataTable extends DataTable
return $sHtml;
}
}
class DataTableSettings implements Serializable
{
public $aClassAliases;
public $sTableId;
public $iDefaultPageSize;
public $aColumns;
/**
* DataTableSettings constructor.
*
* @param $aClassAliases
* @param null $sTableId
*/
public function __construct($aClassAliases, $sTableId = null)
{
$this->aClassAliases = $aClassAliases;
$this->sTableId = $sTableId;
$this->iDefaultPageSize = 10;
$this->aColumns = array();
}
/**
* @param $iDefaultPageSize
* @param $aSortOrder
* @param $aColumns
*/
protected function Init($iDefaultPageSize, $aSortOrder, $aColumns)
{
$this->iDefaultPageSize = $iDefaultPageSize;
$this->aColumns = $aColumns;
$this->FixVisibleColumns();
}
/**
* @return string
*/
public function serialize()
{
// Save only the 'visible' columns
$aColumns = array();
foreach($this->aClassAliases as $sAlias => $sClass)
{
$aColumns[$sAlias] = array();
foreach($this->aColumns[$sAlias] as $sAttCode => $aData)
{
unset($aData['label']); // Don't save the display name
unset($aData['alias']); // Don't save the alias (redundant)
unset($aData['code']); // Don't save the code (redundant)
if ($aData['checked'])
{
$aColumns[$sAlias][$sAttCode] = $aData;
}
}
}
return serialize(
array(
'iDefaultPageSize' => $this->iDefaultPageSize,
'aColumns' => $aColumns,
)
);
}
/**
* @param string $sData
*
* @throws \Exception
*/
public function unserialize($sData)
{
$aData = unserialize($sData);
$this->iDefaultPageSize = $aData['iDefaultPageSize'];
$this->aColumns = $aData['aColumns'];
foreach($this->aClassAliases as $sAlias => $sClass)
{
foreach($this->aColumns[$sAlias] as $sAttCode => $aData)
{
$aFieldData = false;
if ($sAttCode == '_key_')
{
$aFieldData = $this->GetFieldData($sAlias, $sAttCode, null, true /* bChecked */, $aData['sort']);
}
else if (MetaModel::isValidAttCode($sClass, $sAttCode))
{
$oAttDef = MetaModel::GetAttributeDef($sClass, $sAttCode);
$aFieldData = $this->GetFieldData($sAlias, $sAttCode, $oAttDef, true /* bChecked */, $aData['sort']);
}
if ($aFieldData)
{
$this->aColumns[$sAlias][$sAttCode] = $aFieldData;
}
else
{
unset($this->aColumns[$sAlias][$sAttCode]);
}
}
}
$this->FixVisibleColumns();
}
/**
* @param $aClassAliases
* @param $bViewLink
* @param $aDefaultLists
*
* @return \DataTableSettings
* @throws \CoreException
* @throws \DictExceptionMissingString
*/
static public function GetDataModelSettings($aClassAliases, $bViewLink, $aDefaultLists)
{
$oSettings = new DataTableSettings($aClassAliases);
// Retrieve the class specific settings for each class/alias based on the 'list' ZList
//TODO let the caller pass some other default settings (another Zlist, extre fields...)
$aColumns = array();
foreach($aClassAliases as $sAlias => $sClass)
{
if ($aDefaultLists == null)
{
$aList = cmdbAbstract::FlattenZList(MetaModel::GetZListItems($sClass, 'list'));
}
else
{
$aList = $aDefaultLists[$sAlias];
}
$aSortOrder = MetaModel::GetOrderByDefault($sClass);
if ($bViewLink)
{
$sSort = 'none';
if(array_key_exists('friendlyname', $aSortOrder))
{
$sSort = $aSortOrder['friendlyname'] ? 'asc' : 'desc';
}
$sNormalizedFName = MetaModel::NormalizeFieldSpec($sClass, 'friendlyname');
if(array_key_exists($sNormalizedFName, $aSortOrder))
{
$sSort = $aSortOrder[$sNormalizedFName] ? 'asc' : 'desc';
}
$aColumns[$sAlias]['_key_'] = $oSettings->GetFieldData($sAlias, '_key_', null, true /* bChecked */, $sSort);
}
foreach($aList as $sAttCode)
{
$sSort = 'none';
if(array_key_exists($sAttCode, $aSortOrder))
{
$sSort = $aSortOrder[$sAttCode] ? 'asc' : 'desc';
}
$oAttDef = Metamodel::GetAttributeDef($sClass, $sAttCode);
$aFieldData = $oSettings->GetFieldData($sAlias, $sAttCode, $oAttDef, true /* bChecked */, $sSort);
if ($aFieldData) $aColumns[$sAlias][$sAttCode] = $aFieldData;
}
}
$iDefaultPageSize = appUserPreferences::GetPref('default_page_size', MetaModel::GetConfig()->GetMinDisplayLimit());
$oSettings->Init($iDefaultPageSize, $aSortOrder, $aColumns);
return $oSettings;
}
/**
* @throws \CoreException
*/
protected function FixVisibleColumns()
{
foreach($this->aClassAliases as $sAlias => $sClass)
{
if (!isset($this->aColumns[$sAlias]))
{
continue;
}
foreach($this->aColumns[$sAlias] as $sAttCode => $aData)
{
// Remove non-existent columns
// TODO: check if the existing ones are still valid (in case their type changed)
if (($sAttCode != '_key_') && (!MetaModel::IsValidAttCode($sClass, $sAttCode)))
{
unset($this->aColumns[$sAlias][$sAttCode]);
}
}
$aList = MetaModel::ListAttributeDefs($sClass);
// Add the other (non visible ones), sorted in alphabetical order
$aTempData = array();
foreach($aList as $sAttCode => $oAttDef)
{
if ( (!array_key_exists($sAttCode, $this->aColumns[$sAlias])) && (!($oAttDef instanceof AttributeLinkedSet || $oAttDef instanceof AttributeDashboard)))
{
$aFieldData = $this->GetFieldData($sAlias, $sAttCode, $oAttDef, false /* bChecked */, 'none');
if ($aFieldData) $aTempData[$aFieldData['label']] = $aFieldData;
}
}
ksort($aTempData);
foreach($aTempData as $sLabel => $aFieldData)
{
$this->aColumns[$sAlias][$aFieldData['code']] = $aFieldData;
}
}
}
/**
* @param $aClassAliases
* @param null $sTableId
* @param bool $bOnlyOnTable
*
* @return \DataTableSettings|null
* @throws \Exception
*/
static public function GetTableSettings($aClassAliases, $sTableId = null, $bOnlyOnTable = false)
{
$pref = null;
$oSettings = new DataTableSettings($aClassAliases, $sTableId);
if ($sTableId != null)
{
// An identified table, let's fetch its own settings (if any)
$pref = appUserPreferences::GetPref($oSettings->GetPrefsKey($sTableId), null);
}
if ($pref == null)
{
if (!$bOnlyOnTable)
{
// Try the global preferred values for this class / set of classes
$pref = appUserPreferences::GetPref($oSettings->GetPrefsKey(null), null);
}
if ($pref == null)
{
// no such settings, use the default values provided by the data model
return null;
}
}
$oSettings->unserialize($pref);
return $oSettings;
}
/**
* @return array
*/
public function GetSortOrder()
{
$aSortOrder = array();
foreach($this->aColumns as $sAlias => $aColumns)
{
foreach($aColumns as $aColumn)
{
if ($aColumn['sort'] != 'none')
{
$sCode = ($aColumn['code'] == '_key_') ? 'friendlyname' : $aColumn['code'];
$aSortOrder[$sCode] = ($aColumn['sort']=='asc'); // true for ascending, false for descending
}
}
break; // TODO: For now the Set object supports only sorting on the first class of the set
}
return $aSortOrder;
}
/**
* @param null $sTargetTableId
*
* @return bool
*/
public function Save($sTargetTableId = null)
{
$sSaveId = is_null($sTargetTableId) ? $this->sTableId : $sTargetTableId;
if ($sSaveId == null) return false; // Cannot save, the table is not identified, use SaveAsDefault instead
$sSettings = $this->serialize();
appUserPreferences::SetPref($this->GetPrefsKey($sSaveId), $sSettings);
return true;
}
/**
* @return bool
*/
public function SaveAsDefault()
{
$sSettings = $this->serialize();
appUserPreferences::SetPref($this->GetPrefsKey(null), $sSettings);
return true;
}
/**
* Clear the preferences for this particular table
* @param $bResetAll boolean If true,the settings for all tables of the same class(es)/alias(es) are reset
*/
public function ResetToDefault($bResetAll)
{
if (($this->sTableId == null) && (!$bResetAll)) return false; // Cannot reset, the table is not identified, use force $bResetAll instead
if ($bResetAll)
{
// Turn the key into a suitable PCRE pattern
$sKey = $this->GetPrefsKey(null);
$sPattern = str_replace(array('|'), array('\\|'), $sKey); // escape the | character
$sPattern = '#^'.str_replace(array('*'), array('.*'), $sPattern).'$#'; // Don't use slash as the delimiter since it's used in our key to delimit aliases
appUserPreferences::UnsetPref($sPattern, true);
}
else
{
appUserPreferences::UnsetPref($this->GetPrefsKey($this->sTableId), false);
}
return true;
}
/**
* @param null $sTableId
*
* @return string
*/
protected function GetPrefsKey($sTableId = null)
{
if ($sTableId == null) $sTableId = '*';
$aKeys = array();
foreach($this->aClassAliases as $sAlias => $sClass)
{
$aKeys[] = $sAlias.'-'.$sClass;
}
return implode('/', $aKeys).'|'.$sTableId;
}
/**
* @param $sAlias
* @param $sAttCode
* @param $oAttDef
* @param $bChecked
* @param $sSort
*
* @return array|bool
* @throws \CoreException
* @throws \DictExceptionMissingString
*/
protected function GetFieldData($sAlias, $sAttCode, $oAttDef, $bChecked, $sSort)
{
$ret = false;
if ($sAttCode == '_key_')
{
$sLabel = Dict::Format('UI:ExtKey_AsLink', MetaModel::GetName($this->aClassAliases[$sAlias]));
$ret = array(
'label' => $sLabel,
'checked' => true,
'disabled' => true,
'alias' => $sAlias,
'code' => $sAttCode,
'sort' => $sSort,
);
}
else if (!$oAttDef->IsLinkSet())
{
$sLabel = $oAttDef->GetLabel();
if ($oAttDef->IsExternalKey())
{
$sLabel = Dict::Format('UI:ExtKey_AsLink', $oAttDef->GetLabel());
}
else if ($oAttDef->IsExternalField())
{
if ($oAttDef->IsFriendlyName())
{
$sLabel = Dict::Format('UI:ExtKey_AsFriendlyName', $oAttDef->GetLabel());
}
else
{
$oExtAttDef = $oAttDef->GetExtAttDef();
$sLabel = Dict::Format('UI:ExtField_AsRemoteField', $oAttDef->GetLabel(), $oExtAttDef->GetLabel());
}
}
elseif ($oAttDef instanceof AttributeFriendlyName)
{
$sLabel = Dict::Format('UI:ExtKey_AsFriendlyName', $oAttDef->GetLabel());
}
$ret = array(
'label' => $sLabel,
'checked' => $bChecked,
'disabled' => false,
'alias' => $sAlias,
'code' => $sAttCode,
'sort' => $sSort,
);
}
return $ret;
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,7 @@
<?php
/**
* @deprecated will be removed in 3.1.0 - moved to sources/application/WebPage/ErrorPage.php
* @license http://opensource.org/licenses/AGPL-3.0
* @copyright Copyright (C) 2010-2020 Combodo SARL
*/

View File

@@ -44,7 +44,6 @@ class InputOutputTask extends cmdbAbstractObject
"db_table" => "priv_iotask",
"db_key_field" => "id",
"db_finalclass_field" => "",
"display_template" => "",
);
MetaModel::Init_Params($aParams);
MetaModel::Init_AddAttribute(new AttributeString("name", array("allowed_values"=>null, "sql"=>"name", "default_value"=>"", "is_null_allowed"=>false, "depends_on"=>array())));

File diff suppressed because it is too large Load Diff

View File

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

View File

@@ -26,6 +26,10 @@ class LoginBasic extends AbstractLoginFSMExtension
{
$_SESSION['login_mode'] = 'basic';
}
elseif (isset($_SERVER['REDIRECT_HTTP_AUTHORIZATION']) && !empty($_SERVER['REDIRECT_HTTP_AUTHORIZATION']))
{
$_SESSION['login_mode'] = 'basic';
}
elseif (isset($_SERVER['PHP_AUTH_USER']))
{
$_SESSION['login_mode'] = 'basic';
@@ -36,7 +40,7 @@ class LoginBasic extends AbstractLoginFSMExtension
protected function OnReadCredentials(&$iErrorCode)
{
if ($_SESSION['login_mode'] == 'basic')
if (!isset($_SESSION['login_mode']) || $_SESSION['login_mode'] == 'basic')
{
list($sAuthUser, $sAuthPwd) = $this->GetAuthUserAndPassword();
$_SESSION['login_temp_auth_user'] = $sAuthUser;
@@ -92,9 +96,19 @@ class LoginBasic extends AbstractLoginFSMExtension
{
$sAuthUser = '';
$sAuthPwd = null;
$sAuthorization = '';
if (isset($_SERVER['HTTP_AUTHORIZATION']) && !empty($_SERVER['HTTP_AUTHORIZATION']))
{
list($sAuthUser, $sAuthPwd) = explode(':', base64_decode(substr($_SERVER['HTTP_AUTHORIZATION'], 6)));
$sAuthorization = $_SERVER['HTTP_AUTHORIZATION'];
}
elseif (isset($_SERVER['REDIRECT_HTTP_AUTHORIZATION']) && !empty($_SERVER['REDIRECT_HTTP_AUTHORIZATION']))
{
$sAuthorization = $_SERVER['REDIRECT_HTTP_AUTHORIZATION'];
}
if (!empty($sAuthorization))
{
list($sAuthUser, $sAuthPwd) = explode(':', base64_decode(substr($sAuthorization, 6)));
}
else
{
@@ -121,4 +135,4 @@ class LoginBasic extends AbstractLoginFSMExtension
}
return array($sAuthUser, $sAuthPwd);
}
}
}

View File

@@ -67,6 +67,15 @@ class LoginExternal extends AbstractLoginFSMExtension
return LoginWebPage::LOGIN_FSM_CONTINUE;
}
protected function OnError(&$iErrorCode)
{
if ($_SESSION['login_mode'] == 'external')
{
LoginWebPage::HTTP401Error();
}
return LoginWebPage::LOGIN_FSM_CONTINUE;
}
/**
* @return bool
*/

View File

@@ -1,12 +1,15 @@
<?php
/**
* Class LoginForm
*
* @copyright Copyright (C) 2010-2019 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
/**
* Class LoginForm
*
* @since 2.7.0
*/
class LoginForm extends AbstractLoginFSMExtension implements iLoginUIExtension
{
private $bForceFormOnError = false;
@@ -21,6 +24,9 @@ class LoginForm extends AbstractLoginFSMExtension implements iLoginUIExtension
return array('form');
}
/**
* @inheritDoc
*/
protected function OnReadCredentials(&$iErrorCode)
{
if (!isset($_SESSION['login_mode']) || ($_SESSION['login_mode'] == 'form'))
@@ -51,6 +57,9 @@ class LoginForm extends AbstractLoginFSMExtension implements iLoginUIExtension
return LoginWebPage::LOGIN_FSM_CONTINUE;
}
/**
* @inheritDoc
*/
protected function OnCheckCredentials(&$iErrorCode)
{
if ($_SESSION['login_mode'] == 'form')
@@ -66,6 +75,9 @@ class LoginForm extends AbstractLoginFSMExtension implements iLoginUIExtension
return LoginWebPage::LOGIN_FSM_CONTINUE;
}
/**
* @inheritDoc
*/
protected function OnCredentialsOK(&$iErrorCode)
{
if ($_SESSION['login_mode'] == 'form')
@@ -85,6 +97,9 @@ class LoginForm extends AbstractLoginFSMExtension implements iLoginUIExtension
return LoginWebPage::LOGIN_FSM_CONTINUE;
}
/**
* @inheritDoc
*/
protected function OnError(&$iErrorCode)
{
if ($_SESSION['login_mode'] == 'form')
@@ -94,6 +109,9 @@ class LoginForm extends AbstractLoginFSMExtension implements iLoginUIExtension
return LoginWebPage::LOGIN_FSM_CONTINUE;
}
/**
* @inheritDoc
*/
protected function OnConnected(&$iErrorCode)
{
if ($_SESSION['login_mode'] == 'form')
@@ -105,7 +123,7 @@ class LoginForm extends AbstractLoginFSMExtension implements iLoginUIExtension
}
/**
* @return LoginTwigContext
* @inheritDoc
* @throws \Exception
*/
public function GetTwigContext()
@@ -125,7 +143,7 @@ class LoginForm extends AbstractLoginFSMExtension implements iLoginUIExtension
$oLoginContext->AddBlockExtension('login_submit', new LoginBlockExtension('extensionblock/loginformsubmit.html.twig'));
$oLoginContext->AddBlockExtension('login_form_footer', new LoginBlockExtension('extensionblock/loginformfooter.html.twig'));
$bEnableResetPassword = empty(MetaModel::GetConfig()->Get('forgot_password')) ? true : MetaModel::GetConfig()->Get('forgot_password');
$bEnableResetPassword = MetaModel::GetConfig()->Get('forgot_password');
$sResetPasswordUrl = utils::GetAbsoluteUrlAppRoot() . 'pages/UI.php?loginop=forgot_pwd';
$aData = array(
'bEnableResetPassword' => $bEnableResetPassword,

View File

@@ -224,7 +224,7 @@ class LoginTwigRenderer
}
$oCoreLoader = new Twig_Loader_Filesystem(array(), APPROOT.'templates');
$aCoreTemplatesPaths = array('login', 'login/password');
$aCoreTemplatesPaths = array('pages/login', 'pages/login/password');
// Having this path declared after the plugins let the plugins replace the core templates
$oCoreLoader->setPaths($aCoreTemplatesPaths);
// Having the core templates accessible within a different namespace offer the possibility to extend them while replacing them

View File

@@ -78,21 +78,22 @@ class LoginWebPage extends NiceWebPage
public function __construct($sTitle = null)
{
if($sTitle === null)
{
$sTitle = Dict::S('UI:Login:Title');
}
if ($sTitle === null) {
$sTitle = Dict::S('UI:Login:Title');
}
parent::__construct($sTitle);
$this->SetStyleSheet();
$this->add_header("Cache-control: no-cache");
$this->add_header('Cache-control: no-cache, no-store, must-revalidate');
$this->add_header('Pragma: no-cache');
$this->add_header('Expires: 0');
$this->add_header('X-Frame-Options: deny');
}
public function SetStyleSheet()
{
$this->add_linked_stylesheet(utils::GetAbsoluteUrlAppRoot().'css/login.css');
$this->add_linked_stylesheet(utils::GetAbsoluteUrlAppRoot().'css/font-awesome/css/all.min.css');
$this->add_linked_stylesheet(utils::GetAbsoluteUrlAppRoot().'css/font-awesome/css/v4-shims.min.css');
}
public static function SetLoginFailedMessage($sMessage)
@@ -100,6 +101,44 @@ class LoginWebPage extends NiceWebPage
self::$m_sLoginFailedMessage = $sMessage;
}
/**
* @param $oUser
* @param array $aProfiles
*
* @return array
* @throws \CoreException
* @throws \CoreUnexpectedValue
*/
public static function SynchronizeProfiles(&$oUser, array $aProfiles, $sOrigin)
{
$oProfilesSet = $oUser->Get(profile_list);
//delete old profiles
$aExistingProfiles = [];
while ($oProfile = $oProfilesSet->Fetch())
{
array_push($aExistingProfiles, $oProfile->Get('profileid'));
$iArrayKey = array_search($oProfile->Get('profileid'), $aProfiles);
if (!$iArrayKey)
{
$oProfilesSet->RemoveItem($oProfile->Get('profileid'));
}
else
{
unset($aProfiles[$iArrayKey]);
}
}
//add profiles not already linked with user
foreach ($aProfiles as $iProfileId)
{
$oLink = new URP_UserProfile();
$oLink->Set('profileid', $iProfileId);
$oLink->Set('reason', $sOrigin);
$oProfilesSet->AddItem(MetaModel::NewObject('URP_UserProfile', array('profileid' => $iProfileId, 'reason' => $sOrigin)));
}
$oUser->Set('profile_list', $oProfilesSet);
}
public function DisplayLoginHeader($bMainAppLogo = false)
{
$sLogo = 'itop-logo-external.png';
@@ -316,7 +355,7 @@ class LoginWebPage extends NiceWebPage
{
$aVars['bBadToken'] = false;
// Trash the token and change the password
$oUser->Set('reset_pwd_token', '');
$oUser->Set('reset_pwd_token', new ormPassword());
$oUser->AllowWrite(true);
$oUser->SetPassword($sNewPwd); // Does record the change into the DB
$aVars['sUrl'] = utils::GetAbsoluteUrlAppRoot();
@@ -790,12 +829,13 @@ class LoginWebPage extends NiceWebPage
$oPerson = null;
try
{
$sOrigin = 'External User provisioning';
CMDBObject::SetTrackOrigin('custom-extension');
$sInfo = 'External User provisioning';
if (isset($_SESSION['login_mode']))
{
$sOrigin .= " ({$_SESSION['login_mode']})";
$sInfo .= " ({$_SESSION['login_mode']})";
}
CMDBObject::SetTrackOrigin($sOrigin);
CMDBObject::SetTrackInfo($sInfo);
$oPerson = MetaModel::NewObject('Person');
$oPerson->Set('first_name', $sFirstName);
@@ -843,6 +883,14 @@ class LoginWebPage extends NiceWebPage
$oUser = null;
try
{
CMDBObject::SetTrackOrigin('custom-extension');
$sInfo = 'External User provisioning';
if (isset($_SESSION['login_mode']))
{
$sInfo .= " ({$_SESSION['login_mode']})";
}
CMDBObject::SetTrackInfo($sInfo);
$oUser = MetaModel::GetObjectByName('UserExternal', $sAuthUser, false);
if (is_null($oUser))
{
@@ -877,20 +925,12 @@ class LoginWebPage extends NiceWebPage
}
// Now synchronize the profiles
$oProfilesSet = DBObjectSet::FromScratch('URP_UserProfile');
$sOrigin = 'External User provisioning';
if (isset($_SESSION['login_mode']))
{
$sOrigin .= " ({$_SESSION['login_mode']})";
}
foreach ($aProfiles as $iProfileId)
{
$oLink = new URP_UserProfile();
$oLink->Set('profileid', $iProfileId);
$oLink->Set('reason', $sOrigin);
$oProfilesSet->AddObject($oLink);
}
$oUser->Set('profile_list', $oProfilesSet);
$aExistingProfiles = self::SynchronizeProfiles($oUser, $aProfiles, $sOrigin);
if ($oUser->IsModified())
{
$oUser->DBWrite();
@@ -985,7 +1025,7 @@ class LoginWebPage extends NiceWebPage
else
{
require_once(APPROOT.'/setup/setuppage.class.inc.php');
$oP = new SetupPage(Dict::S('UI:PageTitle:FatalError'));
$oP = new ErrorPage(Dict::S('UI:PageTitle:FatalError'));
$oP->add("<h1>".Dict::S('UI:Login:Error:AccessAdmin')."</h1>\n");
$oP->p("<a href=\"".utils::GetAbsoluteUrlAppRoot()."pages/logoff.php\">".Dict::S('UI:LogOffMenu')."</a>");
$oP->output();

View File

@@ -34,7 +34,7 @@ function _MaintenanceSetupPageMessage($sTitle, $sMessage)
@include_once(APPROOT.'setup/setuppage.class.inc.php');
if (class_exists('SetupPage'))
{
$oP = new SetupPage($sTitle);
$oP = new ErrorPage($sTitle);
$oP->p("<h2 class=\"center\">$sMessage</h2>");
$oP->add_ready_script(
<<<JS

View File

@@ -17,6 +17,8 @@
* You should have received a copy of the GNU Affero General Public License
*/
use Combodo\iTop\Application\UI\Component\Title\TitleFactory;
require_once(APPROOT.'/application/utils.inc.php');
require_once(APPROOT.'/application/template.class.inc.php');
require_once(APPROOT."/application/user.dashboard.class.inc.php");
@@ -51,7 +53,10 @@ require_once(APPROOT."/application/user.dashboard.class.inc.php");
* new OQLMenuNode('PersonsMenu', 'SELECT bizPerson', $oContactsMenu->GetIndex(), 0);
*
*/
/**
* Class ApplicationMenu
*/
class ApplicationMenu
{
/**
@@ -71,7 +76,10 @@ class ApplicationMenu
*/
static $sFavoriteSiloQuery = 'SELECT Organization';
static public function LoadAdditionalMenus()
/**
* @return void
*/
public static function LoadAdditionalMenus()
{
if (!self::$bAdditionalMenusLoaded)
{
@@ -97,10 +105,10 @@ class ApplicationMenu
/**
* Set the query used to limit the list of displayed organizations in the drop-down menu
* @param $sOQL string The OQL query returning a list of Organization objects
* @param string $sOQL The OQL query returning a list of Organization objects
* @return void
*/
static public function SetFavoriteSiloQuery($sOQL)
public static function SetFavoriteSiloQuery($sOQL)
{
self::$sFavoriteSiloQuery = $sOQL;
}
@@ -109,7 +117,7 @@ class ApplicationMenu
* Get the query used to limit the list of displayed organizations in the drop-down menu
* @return string The OQL query returning a list of Organization objects
*/
static public function GetFavoriteSiloQuery()
public static function GetFavoriteSiloQuery()
{
return self::$sFavoriteSiloQuery;
}
@@ -117,18 +125,18 @@ class ApplicationMenu
/**
* Check whether a menu Id is enabled or not
*
* @param $sMenuId
* @param string $sMenuId
*
* @throws \Exception
*/
static public function CheckMenuIdEnabled($sMenuId)
public static function CheckMenuIdEnabled($sMenuId)
{
self::LoadAdditionalMenus();
$oMenuNode = self::GetMenuNode(self::GetMenuIndexById($sMenuId));
if (is_null($oMenuNode) || !$oMenuNode->IsEnabled())
{
require_once(APPROOT.'/setup/setuppage.class.inc.php');
$oP = new SetupPage(Dict::S('UI:PageTitle:FatalError'));
$oP = new ErrorPage(Dict::S('UI:PageTitle:FatalError'));
$oP->add("<h1>".Dict::S('UI:Login:Error:AccessRestricted')."</h1>\n");
$oP->p("<a href=\"".utils::GetAbsoluteUrlAppRoot()."pages/logoff.php\">".Dict::S('UI:LogOffMenu')."</a>");
$oP->output();
@@ -140,11 +148,11 @@ class ApplicationMenu
* Main function to add a menu entry into the application, can be called during the definition
* of the data model objects
* @param MenuNode $oMenuNode
* @param $iParentIndex
* @param $fRank
* @param int $iParentIndex
* @param float $fRank
* @return int
*/
static public function InsertMenu(MenuNode $oMenuNode, $iParentIndex, $fRank)
public static function InsertMenu(MenuNode $oMenuNode, $iParentIndex, $fRank)
{
$index = self::GetMenuIndexById($oMenuNode->GetMenuId());
if ($index == -1)
@@ -185,20 +193,154 @@ class ApplicationMenu
/**
* Reflection API - Get menu entries
*
* @return array
*/
static public function ReflectionMenuNodes()
public static function ReflectionMenuNodes()
{
self::LoadAdditionalMenus();
return self::$aMenusIndex;
}
/**
* Get entries count for all the menus
*
* @param array $aExtraParams
*
* @return array
* @throws \DictExceptionMissingString
* @since 3.0.0
*/
public static function GetMenusCount($aExtraParams = array())
{
$aMenuGroups = static::GetMenuGroups($aExtraParams);
$aMenusCount = [];
foreach ($aMenuGroups as $aMenuGroup) {
$aSubMenuNodes = $aMenuGroup['aSubMenuNodes'];
$aMenusCount = array_merge($aMenusCount, static::GetSubMenusCount($aSubMenuNodes));
}
return $aMenusCount;
}
/**
* Recurse sub menus for counts
*
* @param array $aSubMenuNodes
*
* @return array
* @since 3.0.0
*/
private static function GetSubMenusCount(array $aSubMenuNodes)
{
$aSubMenusCount = [];
foreach ($aSubMenuNodes as $aSubMenuNode) {
if ($aSubMenuNode['bHasCount']) {
$oMenuNode = static::GetMenuNode(static::GetMenuIndexById($aSubMenuNode['sId']));
$aSubMenusCount[$aSubMenuNode['sId']] = $oMenuNode->GetEntriesCount();
}
$aSubMenusCount = array_merge($aSubMenusCount, static::GetSubMenusCount($aSubMenuNode['aSubMenuNodes']));
}
return $aSubMenusCount;
}
/**
* Return an array of menu groups
*
* @param array $aExtraParams
*
* @return array
* @throws \DictExceptionMissingString
* @since 3.0.0
*/
public static function GetMenuGroups($aExtraParams = array())
{
self::LoadAdditionalMenus();
// Sort the root menu based on the rank
usort(self::$aRootMenus, array('ApplicationMenu', 'CompareOnRank'));
$aMenuGroups = [];
foreach(static::$aRootMenus as $aMenuGroup)
{
if(!static::CanDisplayMenu($aMenuGroup))
{
continue;
}
$sMenuGroupIdx = $aMenuGroup['index'];
/** @var \MenuGroup $oMenuNode */
$oMenuNode = static::GetMenuNode($sMenuGroupIdx);
$aMenuGroups[] = [
'sId' => $oMenuNode->GetMenuID(),
'sIconCssClasses' => $oMenuNode->GetDecorationClasses(),
'sInitials' => $oMenuNode->GetInitials(),
'sTitle' => $oMenuNode->GetTitle(),
'aSubMenuNodes' => static::GetSubMenuNodes($sMenuGroupIdx, $aExtraParams),
];
}
return $aMenuGroups;
}
/**
* Return an array of sub-menu nodes for $sMenuGroupIdx
*
* @param string $sMenuGroupIdx
* @param array $aExtraParams
*
* @return array
* @throws \DictExceptionMissingString
* @throws \Exception
* @since 3.0.0
*/
public static function GetSubMenuNodes($sMenuGroupIdx, $aExtraParams = array())
{
$aSubMenuItems = self::GetChildren($sMenuGroupIdx);
// Sort the children based on the rank
usort($aSubMenuItems, array('ApplicationMenu', 'CompareOnRank'));
$aSubMenuNodes = [];
foreach($aSubMenuItems as $aSubMenuItem)
{
if(!static::CanDisplayMenu($aSubMenuItem))
{
continue;
}
$sSubMenuItemIdx = $aSubMenuItem['index'];
$oSubMenuNode = static::GetMenuNode($sSubMenuItemIdx);
if(!$oSubMenuNode->IsEnabled())
{
continue;
}
$aSubMenuNodes[] = [
'sId' => $oSubMenuNode->GetMenuId(),
'sTitle' => $oSubMenuNode->GetTitle(),
'bHasCount' => $oSubMenuNode->HasCount(),
'sUrl' => $oSubMenuNode->GetHyperlink($aExtraParams),
'bOpenInNewWindow' => $oSubMenuNode->IsHyperLinkInNewWindow(),
'aSubMenuNodes' => static::GetSubMenuNodes($sSubMenuItemIdx, $aExtraParams),
];
}
return $aSubMenuNodes;
}
/**
* Entry point to display the whole menu into the web page, used by iTopWebPage
* @param \WebPage $oPage
* @param $aExtraParams
* @param array $aExtraParams
* @throws DictExceptionMissingString
*
* @deprecated Will be removed in 3.0.0, use static::GetMenuGroups() instead
*/
static public function DisplayMenu($oPage, $aExtraParams)
public static function DisplayMenu($oPage, $aExtraParams)
{
self::LoadAdditionalMenus();
// Sort the root menu based on the rank
@@ -237,7 +379,7 @@ EOF
* @param array $aMenu menu entry
* @return bool true if at least one menu is enabled
*/
static private function CanDisplayMenu($aMenu)
private static function CanDisplayMenu($aMenu)
{
$oMenuNode = self::GetMenuNode($aMenu['index']);
if ($oMenuNode->IsEnabled())
@@ -263,14 +405,18 @@ EOF
/**
* Handles the display of the sub-menus (called recursively if necessary)
*
* @param \WebPage $oPage
* @param array $aMenus
* @param array $aExtraParams
* @param int $iActiveMenu
* @return true if the currently selected menu is one of the submenus
*
* @return bool True if the currently selected menu is one of the submenus
* @throws DictExceptionMissingString
* @throws \Exception
* @deprecated Will be removed in 3.0.0, use static::GetSubMenuNodes() instead
*/
static protected function DisplaySubMenu($oPage, $aMenus, $aExtraParams, $iActiveMenu = -1)
protected static function DisplaySubMenu($oPage, $aMenus, $aExtraParams, $iActiveMenu = -1)
{
// Sort the menu based on the rank
$bActive = false;
@@ -301,7 +447,7 @@ EOF
$sLinkTarget .= ' target="_blank"';
}
$sURL = '"'.$oMenu->GetHyperlink($aExtraParams).'"'.$sLinkTarget;
$sTitle = $oMenu->GetTitle();
$sTitle = utils::HtmlEntities($oMenu->GetTitle());
$sItemHtml .= "<a href={$sURL}>{$sTitle}</a>";
}
else
@@ -327,11 +473,11 @@ EOF
/**
* Helper function to sort the menus based on their rank
* @param $a
* @param $b
* @param array $a
* @param array $b
* @return int
*/
static public function CompareOnRank($a, $b)
public static function CompareOnRank($a, $b)
{
$result = 1;
if ($a['rank'] == $b['rank'])
@@ -350,7 +496,7 @@ EOF
* @param int $index
* @return MenuNode|null
*/
static public function GetMenuNode($index)
public static function GetMenuNode($index)
{
return isset(self::$aMenusIndex[$index]) ? self::$aMenusIndex[$index]['node'] : null;
}
@@ -360,7 +506,7 @@ EOF
* @param int $index
* @return array
*/
static public function GetChildren($index)
public static function GetChildren($index)
{
return self::$aMenusIndex[$index]['children'];
}
@@ -370,7 +516,7 @@ EOF
* @param string $sTitle Title of the menu (as passed when creating the menu)
* @return integer ID of the menu, or -1 if not found
*/
static public function GetMenuIndexById($sTitle)
public static function GetMenuIndexById($sTitle)
{
$index = -1;
/** @var MenuNode[] $aMenu */
@@ -389,7 +535,7 @@ EOF
* Retrieves the currently active menu (if any, otherwise the first menu is the default)
* @return string The Id of the currently active menu
*/
static public function GetActiveNodeId()
public static function GetActiveNodeId()
{
$oAppContext = new ApplicationContext();
$sMenuId = $oAppContext->GetCurrentValue('menu', null);
@@ -403,7 +549,7 @@ EOF
/**
* @return null|string
*/
static public function GetDefaultMenuId()
public static function GetDefaultMenuId()
{
static $sDefaultMenuId = null;
if (is_null($sDefaultMenuId))
@@ -423,7 +569,7 @@ EOF
* @param $sMenuId
* @return string
*/
static public function GetRootMenuId($sMenuId)
public static function GetRootMenuId($sMenuId)
{
$iMenuIndex = self::GetMenuIndexById($sMenuId);
if ($iMenuIndex == -1)
@@ -560,29 +706,45 @@ abstract class MenuNode
/**
* @return string
* @throws DictExceptionMissingString
*/
public function GetTitle()
{
return Dict::S("Menu:$this->sMenuId", str_replace('_', ' ', $this->sMenuId));
}
/**
* Indicates if the page corresponding to this menu node is countable
*
* @return bool true if corresponding page is countable
* @since 3.0.0
*/
public function HasCount()
{
return false;
}
/**
* Get the number of entries of the page corresponding to this menu item.
*
* @return int the number of entries
* @since 3.0.0
*/
public function GetEntriesCount()
{
return 0;
}
/**
* @return string
* @throws DictExceptionMissingString
*/
public function GetLabel()
{
$sRet = Dict::S("Menu:$this->sMenuId+", "");
if ($sRet === '')
{
if ($this->iParentIndex != -1)
{
if ($sRet === '') {
if ($this->iParentIndex != -1) {
$oParentMenu = ApplicationMenu::GetMenuNode($this->iParentIndex);
$sRet = $oParentMenu->GetTitle().' / '.$this->GetTitle();
}
else
{
} else {
$sRet = $this->GetTitle();
}
//$sRet = $this->GetTitle();
@@ -597,7 +759,10 @@ abstract class MenuNode
{
return $this->index;
}
/**
* @return void
*/
public function PopulateChildMenus()
{
foreach (ApplicationMenu::GetChildren($this->GetIndex()) as $aMenu)
@@ -692,8 +857,8 @@ abstract class MenuNode
public abstract function RenderContent(WebPage $oPage, $aExtraParams = array());
/**
* @param $sHyperlink
* @param $aExtraParams
* @param string $sHyperlink
* @param array $aExtraParams
* @return string
*/
protected function AddParams($sHyperlink, $aExtraParams)
@@ -722,23 +887,68 @@ abstract class MenuNode
*/
class MenuGroup extends MenuNode
{
/** @var string DEFAULT_DECORATION_CLASSES Set to null by default so it is replaced by initials when none is specified */
const DEFAULT_DECORATION_CLASSES = null;
/** @var string The CSS classes used to display the menu group's icon */
protected $sDecorationClasses = self::DEFAULT_DECORATION_CLASSES;
/**
* Create a top-level menu group and inserts it into the application's main menu
*
* @param string $sMenuId Unique identifier of the menu (used to identify the menu for bookmarking, and for getting the labels from the dictionary)
* @param float $fRank Number used to order the list, the groups are sorted based on this value
* @param string|null $sDecorationClasses CSS classes used to display the menu group's icon
* @param string $sEnableClass Name of class of object
* @param integer $iActionCode Either UR_ACTION_READ, UR_ACTION_MODIFY, UR_ACTION_DELETE, UR_ACTION_BULKREAD, UR_ACTION_BULKMODIFY or UR_ACTION_BULKDELETE
* @param integer $iAllowedResults Expected "rights" for the action: either UR_ALLOWED_YES, UR_ALLOWED_NO, UR_ALLOWED_DEPENDS or a mix of them...
* @param string $sEnableStimulus
*/
public function __construct($sMenuId, $fRank, $sEnableClass = null, $iActionCode = null, $iAllowedResults = UR_ALLOWED_YES, $sEnableStimulus = null)
public function __construct($sMenuId, $fRank, $sDecorationClasses = null, $sEnableClass = null, $iActionCode = null, $iAllowedResults = UR_ALLOWED_YES, $sEnableStimulus = null)
{
parent::__construct($sMenuId, -1 /* no parent, groups are at root level */, $fRank, $sEnableClass, $iActionCode, $iAllowedResults, $sEnableStimulus);
if(!empty($sDecorationClasses))
{
$this->sDecorationClasses = $sDecorationClasses;
}
}
/**
* @param WebPage $oPage
* @param array $aExtraParams
* Return true if the menu group has some decoration classes
*
* @return bool
* @since 3.0.0
*/
public function HasDecorationClasses()
{
return (empty($this->GetDecorationClasses()) === false);
}
/**
* Return the CSS classes used for decorating the menu group (typically the icon in the navigation menu)
*
* @return string
* @since 3.0.0
*/
public function GetDecorationClasses()
{
return $this->sDecorationClasses;
}
/**
* Returns the initials of the menu group, used by the rendering in case there is no decoration classes
*
* @return string
* @since 3.0.0
*/
public function GetInitials()
{
return mb_substr($this->GetTitle(), 0, 1);
}
/**
* @inheritDoc
*/
public function RenderContent(WebPage $oPage, $aExtraParams = array())
{
@@ -776,8 +986,7 @@ class TemplateMenuNode extends MenuNode
}
/**
* @param $aExtraParams
* @return string
* @inheritDoc
*/
public function GetHyperlink($aExtraParams)
{
@@ -786,10 +995,8 @@ class TemplateMenuNode extends MenuNode
}
/**
* @param WebPage $oPage
* @param array $aExtraParams
* @return mixed|void
* @throws DictExceptionMissingString
* @inheritDoc
* @throws \Exception
*/
public function RenderContent(WebPage $oPage, $aExtraParams = array())
{
@@ -878,12 +1085,8 @@ class OQLMenuNode extends MenuNode
}
/**
* @param WebPage $oPage
* @param array $aExtraParams
* @return mixed|void
* @throws CoreException
* @throws DictExceptionMissingString
* @throws OQLException
* @inheritDoc
* @throws \Exception
*/
public function RenderContent(WebPage $oPage, $aExtraParams = array())
{
@@ -902,11 +1105,11 @@ class OQLMenuNode extends MenuNode
}
/**
* @param $sOql
* @param $sTitle
* @param $sUsageId
* @param $bSearchPane
* @param $bSearchOpen
* @param string $sOql
* @param string $sTitle
* @param string $sUsageId
* @param bool $bSearchPane
* @param bool $bSearchOpen
* @param WebPage $oPage
* @param array $aExtraParams
* @param bool $bEnableBreadcrumb
@@ -918,30 +1121,51 @@ class OQLMenuNode extends MenuNode
{
$sUsageId = utils::GetSafeId($sUsageId);
$oSearch = DBObjectSearch::FromOQL($sOql);
$sIcon = MetaModel::GetClassIcon($oSearch->GetClass());
//$sIcon = MetaModel::GetClassIcon($oSearch->GetClass(), false);
if ($bSearchPane)
{
if ($bSearchPane) {
$aParams = array_merge(array('open' => $bSearchOpen, 'table_id' => $sUsageId), $aExtraParams);
$oBlock = new DisplayBlock($oSearch, 'search', false /* Asynchronous */, $aParams);
$oBlock->Display($oPage, 0);
}
$oPage->add("<p class=\"page-header\">$sIcon ".Dict::S($sTitle)."</p>");
//$oPage->add("<p class=\"page-header\">$sIcon ".utils::HtmlEntities(Dict::S($sTitle))."</p>");
$oPage->add("<div class='sf_results_area'>");
$oTitle = TitleFactory::MakeForPage($sTitle);
$oPage->AddUiBlock($oTitle);
$aParams = array_merge(array('table_id' => $sUsageId), $aExtraParams);
$oBlock = new DisplayBlock($oSearch, 'list', false /* Asynchronous */, $aParams);
$oBlock->Display($oPage, $sUsageId);
if ($bEnableBreadcrumb && ($oPage instanceof iTopWebPage))
{
$oPage->add("</div>");
if ($bEnableBreadcrumb && ($oPage instanceof iTopWebPage)) {
// Breadcrumb
//$iCount = $oBlock->GetDisplayedCount();
$sPageId = "ui-search-".$oSearch->GetClass();
$sLabel = MetaModel::GetName($oSearch->GetClass());
$oPage->SetBreadCrumbEntry($sPageId, $sLabel, $sTitle, '', '../images/breadcrumb-search.png');
$oPage->SetBreadCrumbEntry($sPageId, $sLabel, $sTitle, '', 'fas fa-list', iTopWebPage::ENUM_BREADCRUMB_ENTRY_ICON_TYPE_CSS_CLASSES);
}
}
public function HasCount()
{
return true;
}
public function GetEntriesCount()
{
// Count the entries up to 99
$oSet = new DBObjectSet(DBSearch::FromOQL($this->sOQL));
$iCount = $oSet->CountWithLimit(99);
if ($iCount > 99) {
$iCount = "99+";
}
return $iCount;
}
}
/**
@@ -979,16 +1203,14 @@ class SearchMenuNode extends MenuNode
}
/**
* @param \iTopWebPage $oPage
* @param array $aExtraParams
* @return mixed|void
* @throws DictExceptionMissingString
* @throws Exception
* @inheritDoc
* @throws \DictExceptionMissingString
* @throws \Exception
*/
public function RenderContent(WebPage $oPage, $aExtraParams = array())
{
ApplicationMenu::CheckMenuIdEnabled($this->GetMenuId());
$oPage->SetBreadCrumbEntry("menu-".$this->sMenuId, $this->GetTitle(), '', '', utils::GetAbsoluteUrlAppRoot().'images/breadcrumb-search.png');
$oPage->SetBreadCrumbEntry("menu-".$this->sMenuId, $this->GetTitle(), '', '', 'fas fa-search', iTopWebPage::ENUM_BREADCRUMB_ENTRY_ICON_TYPE_CSS_CLASSES);
$oSearch = new DBObjectSearch($this->sClass);
$aParams = array_merge(array('table_id' => 'Menu_'.utils::GetSafeId($this->GetMenuId())), $aExtraParams);
@@ -1039,8 +1261,7 @@ class WebPageMenuNode extends MenuNode
}
/**
* @param array $aExtraParams
* @return string
* @inheritDoc
*/
public function GetHyperlink($aExtraParams)
{
@@ -1048,14 +1269,16 @@ class WebPageMenuNode extends MenuNode
return $this->AddParams( $this->sHyperlink, $aExtraParams);
}
/**
* @inheritDoc
*/
public function IsHyperLinkInNewWindow()
{
return $this->bIsLinkInNewWindow;
}
/**
* @param WebPage $oPage
* @param array $aExtraParams
* @inheritDoc
*/
public function RenderContent(WebPage $oPage, $aExtraParams = array())
{
@@ -1096,10 +1319,7 @@ class NewObjectMenuNode extends MenuNode
}
/**
* @param string[] $aExtraParams
*
* @return string
* @throws \Exception
* @inheritDoc
*/
public function GetHyperlink($aExtraParams)
{
@@ -1133,8 +1353,7 @@ class NewObjectMenuNode extends MenuNode
}
/**
* @param WebPage $oPage
* @param string[] $aExtraParams
* @inheritDoc
*/
public function RenderContent(WebPage $oPage, $aExtraParams = array())
{
@@ -1172,8 +1391,7 @@ class DashboardMenuNode extends MenuNode
}
/**
* @param string[] $aExtraParams
* @return string
* @inheritDoc
*/
public function GetHyperlink($aExtraParams)
{
@@ -1192,10 +1410,8 @@ class DashboardMenuNode extends MenuNode
}
/**
* @param \iTopWebPage $oPage
* @param string[] $aExtraParams
* @throws CoreException
* @throws Exception
* @inheritDoc
* @throws \Exception
*/
public function RenderContent(WebPage $oPage, $aExtraParams = array())
{
@@ -1203,8 +1419,9 @@ class DashboardMenuNode extends MenuNode
$oDashboard = $this->GetDashboard();
if ($oDashboard != null)
{
$sDivId = preg_replace('/[^a-zA-Z0-9_]/', '', $this->sMenuId);
$oPage->add('<div class="dashboard_contents" id="'.$sDivId.'">');
$sDivId = utils::Sanitize($this->sMenuId, '', 'element_identifier');
$oPage->add('<div class="ibo-dashboard" id="'.$sDivId.'">');
$aExtraParams['dashboard_div_id'] = $sDivId;
$oDashboard->SetReloadURL($this->GetHyperlink($aExtraParams));
$oDashboard->Render($oPage, false, $aExtraParams);
$oPage->add('</div>');
@@ -1230,13 +1447,13 @@ class DashboardMenuNode extends MenuNode
}
if ($this->sMenuId == ApplicationMenu::GetDefaultMenuId())
{
$sIcon = '../images/breadcrumb_home.png';
$sIcon = 'fas fa-home';
}
else
{
$sIcon = '../images/breadcrumb-dashboard.png';
$sIcon = 'fas fa-chart-pie';
}
$oPage->SetBreadCrumbEntry("ui-dashboard-".$this->sMenuId, $this->GetTitle(), $sDescription, '', $sIcon);
$oPage->SetBreadCrumbEntry("ui-dashboard-".$this->sMenuId, $this->GetTitle(), $sDescription, '', $sIcon, iTopWebPage::ENUM_BREADCRUMB_ENTRY_ICON_TYPE_CSS_CLASSES);
}
}
else
@@ -1289,8 +1506,7 @@ class DashboardMenuNode extends MenuNode
class ShortcutContainerMenuNode extends MenuNode
{
/**
* @param string[] $aExtraParams
* @return string
* @inheritDoc
*/
public function GetHyperlink($aExtraParams)
{
@@ -1298,15 +1514,14 @@ class ShortcutContainerMenuNode extends MenuNode
}
/**
* @param WebPage $oPage
* @param string[] $aExtraParams
* @return mixed|void
* @inheritDoc
*/
public function RenderContent(WebPage $oPage, $aExtraParams = array())
{
}
/**
* @inheritDoc
* @throws CoreException
* @throws Exception
*/
@@ -1361,9 +1576,7 @@ class ShortcutMenuNode extends MenuNode
}
/**
* @param string[] $aExtraParams
* @return string
* @throws CoreException
* @inheritDoc
*/
public function GetHyperlink($aExtraParams)
{
@@ -1381,10 +1594,8 @@ class ShortcutMenuNode extends MenuNode
}
/**
* @param WebPage $oPage
* @param string[] $aExtraParams
* @return mixed|void
* @throws DictExceptionMissingString
* @inheritDoc
* @throws \Exception
*/
public function RenderContent(WebPage $oPage, $aExtraParams = array())
{
@@ -1393,8 +1604,9 @@ class ShortcutMenuNode extends MenuNode
}
/**
* @return string
* @throws CoreException
* @inheritDoc
*
* @throws \Exception
*/
public function GetTitle()
{
@@ -1402,8 +1614,9 @@ class ShortcutMenuNode extends MenuNode
}
/**
* @return string
* @throws CoreException
* @inheritDoc
*
* @throws \Exception
*/
public function GetLabel()
{

View File

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

View File

@@ -1,248 +1,7 @@
<?php
/**
* Copyright (C) 2013-2019 Combodo SARL
*
* This file is part of iTop.
*
* iTop is free software; you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* iTop is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* @deprecated will be removed in 3.1.0 - moved to sources/application/WebPage/PDFPage.php
* @license http://opensource.org/licenses/AGPL-3.0
* @copyright Copyright (C) 2010-2020 Combodo SARL
*/
require_once(APPROOT.'application/utils.inc.php');
/**
* Custom class derived from TCPDF for providing custom headers and footers
*
* @author denis
*
*/
class iTopPDF extends TCPDF
{
protected $sDocumentTitle;
/**
* Shortcut for {@link TCPDF::SetFont}, to use the font configured
*
* @param string $style
* @param int $size
* @param string $fontfile
* @param string $subset
* @param bool $out
*
* @uses \TCPDF::SetFont()
* @uses \iTopPDF::GetPdfFont()
* @since 2.7
*/
public function SetFontParams($style, $size, $fontfile='', $subset='default', $out=true)
{
$siTopFont = self::GetPdfFont();
$this->SetFont($siTopFont, $style, $size, $fontfile, $subset, $out);
}
public function SetDocumentTitle($sDocumentTitle)
{
$this->sDocumentTitle = $sDocumentTitle;
}
/**
* Builds the custom header. Called for each new page.
*
* @see TCPDF::Header()
*/
public function Header()
{
// Title
// Set font
$this->SetFontParams('B', 10);
$iPageNumberWidth = 25;
$aMargins = $this->getMargins();
// Display the title (centered)
$this->SetXY($aMargins['left'] + $iPageNumberWidth, 0);
$this->MultiCell($this->getPageWidth() - $aMargins['left'] - $aMargins['right'] - 2 * $iPageNumberWidth, 15, $this->sDocumentTitle,
0, 'C', false, 0 /* $ln */, '', '', true, 0, false, true, 15, 'M' /* $valign */);
$this->SetFontParams('', 10);
// Display the page number (right aligned)
// Warning: the 'R'ight alignment does not work when using placeholders like $this->getAliasNumPage() or $this->getAliasNbPages()
$this->MultiCell($iPageNumberWidth, 15, Dict::Format('Core:BulkExport:PDF:PageNumber', $this->page), 0, 'R', false, 0 /* $ln */, '',
'', true, 0, false, true, 15, 'M' /* $valign */);
// Branding logo
$sBrandingIcon = APPROOT.'images/itop-logo.png';
if (file_exists(MODULESROOT.'branding/main-logo.png'))
{
$sBrandingIcon = MODULESROOT.'branding/main-logo.png';
}
$this->Image($sBrandingIcon, $aMargins['left'], 5, 0, 10);
}
// Page footer
public function Footer()
{
// No footer
}
/**
* dejavusans is a UTF-8 Unicode font. Standard PDF fonts like helvetica or times new roman are NOT UTF-8
* @return string font in the config file (export_pdf_font)
*/
public static function GetPdfFont()
{
$oConfig = utils::GetConfig();
$sPdfFont = $oConfig->Get('export_pdf_font');
return $sPdfFont;
}
}
/**
* Special class of WebPage for printing into a PDF document
*/
class PDFPage extends WebPage
{
/** @var \iTopPDF Instance of the TCPDF object for creating the PDF */
protected $oPdf;
public function __construct($s_title, $sPageFormat = 'A4', $sPageOrientation = 'L')
{
parent::__construct($s_title);
define(K_PATH_FONTS, APPROOT.'lib/combodo/tcpdf/fonts');
$this->oPdf = new iTopPDF($sPageOrientation, 'mm', $sPageFormat, true, self::PAGES_CHARSET, false);
// set document information
$this->oPdf->SetCreator(PDF_CREATOR);
$this->oPdf->SetAuthor('iTop');
$this->oPdf->SetTitle($s_title);
$this->oPdf->SetDocumentTitle($s_title);
$this->oPdf->setFontSubsetting(true);
// dejavusans is a UTF-8 Unicode font. Standard PDF fonts like helvetica or times new roman are NOT UTF-8
$this->oPdf->SetFontParams('', 10, '', true);
// set auto page breaks
$this->oPdf->SetAutoPageBreak(true, 15); // 15 mm break margin at the bottom
$this->oPdf->SetTopMargin(15);
// Add a page, we're ready to start
$this->oPdf->AddPage();
$this->SetContentDisposition('inline', $s_title.'.pdf');
$this->SetDefaultStyle();
}
/**
* Sets a default style (suitable for printing) to be included each time $this->oPdf->writeHTML() is called
*/
protected function SetDefaultStyle()
{
$this->add_style(
<<<EOF
table {
padding: 2pt;
}
table.listResults td {
border: 0.5pt solid #000 ;
}
table.listResults th {
background-color: #eee;
border: 0.5pt solid #000 ;
}
a {
text-decoration: none;
color: #000;
}
table.section td {
vertical-align: middle;
font-size: 10pt;
background-color:#eee;
}
td.icon {
width: 30px;
}
EOF
);
}
/**
* Get access to the underlying TCPDF object
*
* @return \iTopPDF
*/
public function get_tcpdf()
{
$this->flush();
return $this->oPdf;
}
/**
* Writes the currently buffered HTML content into the PDF. This can be useful:
* - to sync the flow in case you want to access the underlying TCPDF object for some specific/graphic output
* - to process the HTML by smaller chunks instead of processing the whole page at once for performance reasons
*/
public function flush()
{
if (strlen($this->s_content) > 0)
{
$sHtml = '';
if (count($this->a_styles) > 0)
{
$sHtml .= "<style>\n".implode("\n", $this->a_styles)."\n</style>\n";
}
$sHtml .= $this->s_content;
$this->oPdf->writeHTML($sHtml); // The style(s) must be supplied each time we call writeHtml
$this->s_content = '';
}
}
/**
* Whether or not the page is a PDF page
*
* @return boolean
*/
public function is_pdf()
{
return true;
}
/**
* Generates the PDF document and returns the PDF content as a string
*
* @return string
* @see WebPage::output()
*/
public function output()
{
$this->add_header('Content-type: application/x-pdf');
if (!empty($this->sContentDisposition))
{
$this->add_header('Content-Disposition: '.$this->sContentDisposition.'; filename="'.$this->sContentFileName.'"');
}
foreach ($this->a_headers as $s_header)
{
header($s_header);
}
$this->flush();
echo $this->oPdf->Output($this->s_title.'.pdf', 'S');
}
public function get_pdf()
{
$this->flush();
return $this->oPdf->Output($this->s_title.'.pdf', 'S');
}
}

View File

@@ -40,7 +40,6 @@ abstract class Query extends cmdbAbstractObject
"db_table" => "priv_query",
"db_key_field" => "id",
"db_finalclass_field" => "realclass",
"display_template" => "",
);
MetaModel::Init_Params($aParams);
//MetaModel::Init_InheritAttributes();
@@ -72,7 +71,6 @@ class QueryOQL extends Query
"db_table" => "priv_query_oql",
"db_key_field" => "id",
"db_finalclass_field" => "",
"display_template" => "",
);
MetaModel::Init_Params($aParams);
MetaModel::Init_InheritAttributes();

View File

@@ -15,6 +15,7 @@
//
// You should have received a copy of the GNU Affero General Public License
// along with iTop. If not, see <http://www.gnu.org/licenses/>
use Combodo\iTop\Application\UI\Component\DataTable\DataTableSettings;
/**
@@ -39,7 +40,6 @@ abstract class Shortcut extends DBObject implements iDisplay
"db_table" => "priv_shortcut",
"db_key_field" => "id",
"db_finalclass_field" => "realclass",
"display_template" => "",
);
MetaModel::Init_Params($aParams);
//MetaModel::Init_InheritAttributes();
@@ -161,7 +161,6 @@ class ShortcutOQL extends Shortcut
"db_table" => "priv_shortcut_oql",
"db_key_field" => "id",
"db_finalclass_field" => "",
"display_template" => "",
);
MetaModel::Init_Params($aParams);
MetaModel::Init_InheritAttributes();

View File

@@ -35,7 +35,17 @@ register_shutdown_function(function()
$sReservedMemory = null;
if (!is_null($err = error_get_last()) && ($err['type'] == E_ERROR))
{
IssueLog::error($err['message']);
// Remove stack trace from MySQLException
$sMessage = $err['message'];
if (strpos($sMessage, 'MySQLException') !== false)
{
$iStackTracePos = strpos($sMessage, 'Stack trace:');
if ($iStackTracePos !== false)
{
$sMessage = substr($sMessage, 0, $iStackTracePos);
}
}
IssueLog::error($sMessage);
if (strpos($err['message'], 'Allowed memory size of') !== false)
{
$sLimit = ini_get('memory_limit');

View File

@@ -20,6 +20,8 @@
require_once(APPROOT.'/application/displayblock.class.inc.php');
/**
* This class manages the special template format used internally to build the iTop web pages
*
* @deprecated Since 3.0.0
*/
class DisplayTemplate
{

View File

@@ -17,8 +17,6 @@
* You should have received a copy of the GNU Affero General Public License
*/
use ScssPhp\ScssPhp\Compiler;
/**
* Class ThemeHandler
*
@@ -27,57 +25,162 @@ use ScssPhp\ScssPhp\Compiler;
*/
class ThemeHandler
{
const IMAGE_EXTENSIONS = ['png', 'gif', 'jpg', 'jpeg'];
private static $oCompileCSSService;
public static function GetAppRootWithSlashes()
{
return str_replace('\\', '/', APPROOT);
}
/**
* Return the absolute URL for the default theme CSS file
* Return default theme name and parameters
*
* @return array
* @since 2.7.0
*/
public static function GetDefaultThemeInformation()
{
return [
'name' => 'light-grey',
'parameters' => [
'variables' => [],
'imports' => [
'css-variables' => '../css/css-variables.scss',
],
'stylesheets' => [
'jqueryui' => '../css/ui-lightness/jqueryui.scss',
'main' => '../css/light-grey.scss',
],
],
];
}
/**
* Return the ID of the theme currently defined in the config. file
*
* @return string
*/
public static function GetCurrentThemeId()
{
try
{
if (is_null(MetaModel::GetConfig()))
{
throw new CoreException('no config');
}
$sThemeId = MetaModel::GetConfig()->Get('backoffice_default_theme');
}
catch(CoreException $oCompileException)
{
// Fallback on our default theme in case the config. is not available yet
$aDefaultTheme = ThemeHandler::GetDefaultThemeInformation();
$sThemeId = $aDefaultTheme['name'];
}
return $sThemeId;
}
/**
* Return the absolute path of the compiled theme folder.
*
* @param string $sThemeId
*
* @return string
*/
public static function GetCompiledThemeFolderAbsolutePath($sThemeId)
{
return APPROOT.'env-'.utils::GetCurrentEnvironment().'/branding/themes/'.$sThemeId.'/';
}
/**
* Return the absolute URL for the current theme CSS file
*
* @return string
* @throws \Exception
*/
public static function GetDefaultThemeUrl()
public static function GetCurrentThemeUrl()
{
$sThemeId = MetaModel::GetConfig()->Get('backoffice_default_theme');
static::CompileTheme($sThemeId);
try
{
// Try to compile theme defined in the configuration
$sThemeId = static::GetCurrentThemeId();
static::CompileTheme($sThemeId);
}
catch(CoreException $oCompileException)
{
// Fallback on our default theme (should always be compilable) in case the previous theme doesn't exists
$aDefaultTheme = ThemeHandler::GetDefaultThemeInformation();
$sThemeId = $aDefaultTheme['name'];
$sDefaultThemeDirPath = static::GetCompiledThemeFolderAbsolutePath($sThemeId);
// Create our theme dir if it doesn't exist (XML theme node removed, renamed etc..)
if(!is_dir($sDefaultThemeDirPath))
{
SetupUtils::builddir($sDefaultThemeDirPath);
}
static::CompileTheme($sThemeId, false, "", $aDefaultTheme['parameters']);
}
// Return absolute url to theme compiled css
return utils::GetAbsoluteUrlModulesRoot().'/branding/themes/'.$sThemeId.'/main.css';
return utils::GetAbsoluteUrlModulesRoot().'branding/themes/'.$sThemeId.'/main.css';
}
/**
* Compile the $sThemeId theme
* Compile the $sThemeId theme, the actual compilation is skipped when either
* 1) The produced CSS file exists and is more recent than any of its components (imports, stylesheets)
* 2) The produced CSS file exists and its signature is equal to the expected signature (imports, stylesheets, variables)
*
* @param string $sThemeId
* @param boolean $bSetup
* @param string $sSetupCompilationTimestamp : setup compilation timestamp in micro secunds
* @param array|null $aThemeParameters Parameters (variables, imports, stylesheets) for the theme, if not passed, will be retrieved from compiled DM
* @param array|null $aImportsPaths Paths where imports can be found. Must end with '/'
* @param string|null $sWorkingPath Path of the folder used during compilation. Must end with a '/'
*
* @throws \CoreException
* @return boolean: indicate whether theme compilation occured
*/
public static function CompileTheme($sThemeId, $aThemeParameters = null, $aImportsPaths = null, $sWorkingPath = null)
public static function CompileTheme($sThemeId, $bSetup=false, $sSetupCompilationTimestamp="", $aThemeParameters = null, $aImportsPaths = null, $sWorkingPath = null)
{
if ($sSetupCompilationTimestamp==="")
{
$sSetupCompilationTimestamp = microtime(true);
}
$sSetupCompilationTimestampInSecunds = (strpos($sSetupCompilationTimestamp, '.') !==false) ? explode('.', $sSetupCompilationTimestamp)[0] : $sSetupCompilationTimestamp;
$sEnv = APPROOT.'env-'.utils::GetCurrentEnvironment().'/';
// Default working path
if($sWorkingPath === null)
{
$sWorkingPath = APPROOT.'env-'.utils::GetCurrentEnvironment().'/';
$sWorkingPath = $sEnv;
}
// Default import paths (env-*)
if($aImportsPaths === null)
{
$aImportsPaths = array(
APPROOT.'env-'.utils::GetCurrentEnvironment().'/',
);
$aImportsPaths = [ $sEnv];
}
// Note: We do NOT check that the folder exists!
$sThemeFolderPath = $sWorkingPath.'/branding/themes/'.$sThemeId.'/';
$sThemeCssPath = $sThemeFolderPath.'main.css';
// Save parameters if passed...
// Save parameters if passed... (typically during DM compilation)
if(is_array($aThemeParameters))
{
if (!is_dir($sThemeFolderPath))
{
mkdir($sWorkingPath.'/branding/');
mkdir($sWorkingPath.'/branding/themes/');
}
file_put_contents($sThemeFolderPath.'/theme-parameters.json', json_encode($aThemeParameters));
}
// ... Otherwise, retrieve them from compiled DM
// ... Otherwise, retrieve them from compiled DM (typically when switching current theme in the config. file)
else
{
$aThemeParameters = json_decode(@file_get_contents($sThemeFolderPath.'theme-parameters.json'), true);
@@ -87,31 +190,588 @@ class ThemeHandler
}
}
$aThemeParametersWithVersion = self::CloneThemeParameterAndIncludeVersion($aThemeParameters, $sSetupCompilationTimestampInSecunds);
$sTmpThemeScssContent = '';
$iStyleLastModified = 0;
clearstatcache();
// Loading files to import and stylesheet to compile, also getting most recent modification time on overall files
$aStylesheetFiles = [];
foreach ($aThemeParameters['imports'] as $sImport)
{
$sTmpThemeScssContent .= '@import "'.$sImport.'";'."\n";
$iImportLastModified = @filemtime($sWorkingPath.$sImport);
$sFile = static::FindStylesheetFile($sImport, $aImportsPaths);
$iImportLastModified = @filemtime($sFile);
$aStylesheetFiles[] = $sFile;
$iStyleLastModified = $iStyleLastModified < $iImportLastModified ? $iImportLastModified : $iStyleLastModified;
}
foreach ($aThemeParameters['stylesheets'] as $sStylesheet)
{
$sTmpThemeScssContent .= '@import "'.$sStylesheet.'";'."\n";
$iStylesheetLastModified = @filemtime($sWorkingPath.$sStylesheet);
$sFile = static::FindStylesheetFile($sStylesheet, $aImportsPaths);
$iStylesheetLastModified = @filemtime($sFile);
$aStylesheetFiles[] = $sFile;
$iStyleLastModified = $iStyleLastModified < $iStylesheetLastModified ? $iStylesheetLastModified : $iStyleLastModified;
}
// Checking if our compiled css is outdated
if (!file_exists($sThemeCssPath) || (is_writable($sThemeFolderPath) && (@filemtime($sThemeCssPath) < $iStyleLastModified)))
$aIncludedImages=static::GetIncludedImages($aThemeParametersWithVersion, $aStylesheetFiles, $sThemeId);
foreach ($aIncludedImages as $sImage)
{
$sTmpThemeCssContent = utils::CompileCSSFromSASS($sTmpThemeScssContent, $aImportsPaths, $aThemeParameters['variables']);
file_put_contents($sThemeCssPath, $sTmpThemeCssContent);
if (is_file($sImage))
{
$iStylesheetLastModified = @filemtime($sImage);
$iStyleLastModified = $iStyleLastModified < $iStylesheetLastModified ? $iStylesheetLastModified : $iStyleLastModified;
}
}
// Checking if our compiled css is outdated
$iFilemetime = @filemtime($sThemeCssPath);
$bFileExists = file_exists($sThemeCssPath);
$bVarSignatureChanged=false;
if ($bFileExists && $bSetup)
{
$sPrecompiledSignature = static::GetSignature($sThemeCssPath);
//check variable signature has changed which is independant from any file modification
if (!empty($sPrecompiledSignature)){
$sPreviousVariableSignature = static::GetVarSignature($sPrecompiledSignature);
$sCurrentVariableSignature = md5(json_encode($aThemeParameters['variables']));
$bVarSignatureChanged= ($sPreviousVariableSignature!==$sCurrentVariableSignature);
}
}
if (!$bFileExists || $bVarSignatureChanged || (is_writable($sThemeFolderPath) && ($iFilemetime < $iStyleLastModified)))
{
// Dates don't match. Second chance: check if the already compiled stylesheet exists and is consistent based on its signature
$sActualSignature = static::ComputeSignature($aThemeParameters, $aImportsPaths, $aIncludedImages);
if ($bFileExists && !$bSetup)
{
$sPrecompiledSignature = static::GetSignature($sThemeCssPath);
}
if (!empty($sPrecompiledSignature) && $sActualSignature == $sPrecompiledSignature)
{
touch($sThemeCssPath); // Stylesheet is up to date, mark it as more recent to speedup next time
}
else
{
// Alas, we really need to recompile
// Add the signature to the generated CSS file so that the file can be used as a precompiled stylesheet if needed
$sSignatureComment =
<<<CSS
/*
=== SIGNATURE BEGIN ===
$sActualSignature
=== SIGNATURE END ===
*/
CSS;
if (!static::$oCompileCSSService)
{
static::$oCompileCSSService = new CompileCSSService();
}
//store it again to change $version with latest compiled time
$sTmpThemeCssContent = static::$oCompileCSSService->CompileCSSFromSASS($sTmpThemeScssContent, $aImportsPaths,
$aThemeParametersWithVersion);
file_put_contents($sThemeFolderPath.'/theme-parameters.json', json_encode($aThemeParameters));
file_put_contents($sThemeCssPath, $sSignatureComment.$sTmpThemeCssContent);
SetupLog::Info("Theme $sThemeId file compiled.");
return true;
}
}
return false;
}
/**
* Compute the signature of a theme defined by its theme parameters. The signature is a JSON structure of
* 1) one MD5 of all the variables/values (JSON encoded)
* 2) the MD5 of each stylesheet file
* 3) the MD5 of each import file
* 3) the MD5 of each images referenced in style sheets
*
* @param string[] $aThemeParameters
* @param string[] $aImportsPaths
* @param string[] $aIncludedImages
*
* @return string
* @throws \Exception
*/
public static function ComputeSignature($aThemeParameters, $aImportsPaths, $aIncludedImages)
{
$aSignature = [
'variables' => md5(json_encode($aThemeParameters['variables'])),
'stylesheets' => [],
'imports' => [],
'images' => []
];
foreach ($aThemeParameters['imports'] as $key => $sImport)
{
$sFile = static::FindStylesheetFile($sImport, $aImportsPaths);
$aSignature['stylesheets'][$key] = md5_file($sFile);
}
foreach ($aThemeParameters['stylesheets'] as $key => $sStylesheet)
{
$sFile = static::FindStylesheetFile($sStylesheet, $aImportsPaths);
$aSignature['stylesheets'][$key] = md5_file($sFile);
}
foreach ($aIncludedImages as $sImage)
{
if (is_file($sImage)) {
$sUri = str_replace(self::GetAppRootWithSlashes(), '', $sImage);
$aSignature['images'][$sUri] = md5_file($sImage);
}
}
return json_encode($aSignature);
}
/**
* Search for images referenced in stylesheet files
*
* @param array $aThemeParametersVariables
* @param array $aStylesheetFiles
* @param string $sThemeId : used only for logging purpose
*
* @return array complete path of the images, but with slashes as dir separator instead of DIRECTORY_SEPARATOR
* @since 3.0.0
*/
public static function GetIncludedImages($aThemeParametersVariables, $aStylesheetFiles, $sThemeId)
{
$sTargetThemeFolderPath = static::GetCompiledThemeFolderAbsolutePath($sThemeId);
$aCompleteUrls = [];
$aToCompleteUrls = [];
$aMissingVariables = [];
$aFoundVariables = ['version'=>''];
$aMap = [
'aCompleteUrls' => $aCompleteUrls,
'aToCompleteUrls' => $aToCompleteUrls,
'aMissingVariables' => $aMissingVariables,
'aFoundVariables' => $aFoundVariables,
];
foreach ($aStylesheetFiles as $sStylesheetFile)
{
$aRes = static::GetAllUrlFromScss($aThemeParametersVariables, $sStylesheetFile);
/** @var array $aVal */
foreach($aMap as $key => $aVal)
{
if (array_key_exists($key, $aMap))
{
$aMap[$key] = array_merge($aVal, $aRes[$key]);
}
}
}
$aMap = static::ResolveUncompleteUrlsFromScss($aMap, $aThemeParametersVariables, $aStylesheetFiles);
$aImages = [];
foreach ($aMap ['aCompleteUrls'] as $sUri => $sUrl)
{
$sImg = $sUrl;
if (preg_match("/(.*)\?/", $sUrl, $aMatches))
{
$sImg=$aMatches[1];
}
if (static::HasImageExtension($sImg)
&& ! array_key_exists($sImg, $aImages))
{
$sFilePath = realpath($sImg);
if ($sFilePath !== false) {
$sFilePathWithSlashes = str_replace('\\', '/', $sFilePath);
$aImages[$sImg] = $sFilePathWithSlashes;
continue;
}
$sCanonicalPath = static::CanonicalizePath($sTargetThemeFolderPath.'/'.$sImg);
$sFilePath = realpath($sCanonicalPath);
if ($sFilePath !== false) {
$sFilePathWithSlashes = str_replace('\\', '/', $sFilePath);
$aImages[$sImg] = $sFilePathWithSlashes;
continue;
}
SetupLog::Warning("Cannot find $sCanonicalPath ($sImg) during SCSS $sThemeId precompilation");
}
}
return array_values($aImages);
}
/**
* Reduce path without using realpath (works only when file exists)
* @param $path
*
* @return string
*/
public static function CanonicalizePath($path)
{
$path = explode('/', str_replace('//','/', $path));
$stack = array();
foreach ($path as $seg) {
if ($seg == '..') {
// Ignore this segment, remove last segment from stack
array_pop($stack);
continue;
}
if ($seg == '.') {
// Ignore this segment
continue;
}
$stack[] = $seg;
}
return implode('/', $stack);
}
/**
* Complete url using provided variables. Example with $var=1: XX + $var => XX1
* @param $aMap
* @param $aThemeParametersVariables
* @param $aStylesheetFile
*
* @return mixed
*/
public static function ResolveUncompleteUrlsFromScss($aMap, $aThemeParametersVariables, $aStylesheetFile)
{
$sContent="";
foreach ($aStylesheetFile as $sStylesheetFile)
{
if (is_file($sStylesheetFile))
{
$sContent .= '\n' . file_get_contents($sStylesheetFile);
}
}
$aMissingVariables=$aMap['aMissingVariables'];
$aFoundVariables=$aMap['aFoundVariables'];
$aToCompleteUrls=$aMap['aToCompleteUrls'];
$aCompleteUrls=$aMap['aCompleteUrls'];
list($aMissingVariables, $aFoundVariables) = static::FindMissingVariables($aThemeParametersVariables, $aMissingVariables, $aFoundVariables, $sContent, true);
list($aToCompleteUrls, $aCompleteUrls) = static::ResolveUrls($aFoundVariables, $aToCompleteUrls, $aCompleteUrls);
$aMap['aMissingVariables']=$aMissingVariables;
$aMap['aFoundVariables']=$aFoundVariables;
$aMap['aToCompleteUrls']=$aToCompleteUrls;
$aMap['aCompleteUrls']=$aCompleteUrls;
return $aMap;
}
/**
* Find missing variable values from SCSS content based on their name.
*
* @param $aThemeParametersVariables
* @param $aMissingVariables
* @param $aFoundVariables
* @param $sContent : scss content
* @param bool $bForceEmptyValueWhenNotFound
*
* @return array
*/
public static function FindMissingVariables($aThemeParametersVariables, $aMissingVariables, $aFoundVariables, $sContent, $bForceEmptyValueWhenNotFound=false)
{
$aNewMissingVars = [];
if (!empty($aMissingVariables))
{
foreach ($aMissingVariables as $var)
{
if (array_key_exists($var, $aThemeParametersVariables))
{
$aFoundVariables[$var] = $aThemeParametersVariables[$var];
}
else
{
if (preg_match_all("/\\\$$var\s*:\s*[\"']{0,1}(.*)[\"']{0,1};/", $sContent, $aValues))
{
$sValue = $aValues[1][0];
if (preg_match_all("/([^!]+)!/", $sValue, $aSubValues))
{
$sValue = trim($aSubValues[1][0], ' "\'');
}
if (strpos($sValue, '$') === false)
{
$aFoundVariables[$var] = $sValue;
}
else{
$aNewMissingVars[] = $var;
}
}
else
{
if ($bForceEmptyValueWhenNotFound)
{
$aFoundVariables[$var] = '';
}
else
{
$aNewMissingVars[] = $var;
}
}
}
}
}
return [ $aNewMissingVars, $aFoundVariables ];
}
/**
* @param $aFoundVariables
* @param array $aToCompleteUrls
* @param array $aCompleteUrls
*
* @return array
*/
public static function ResolveUrls($aFoundVariables, array $aToCompleteUrls, array $aCompleteUrls)
{
if (!empty($aFoundVariables))
{
$aFoundVariablesWithEmptyValue = [];
foreach ($aFoundVariables as $aFoundVariable => $sValue)
{
$aFoundVariablesWithEmptyValue[$aFoundVariable] = '';
}
foreach ($aToCompleteUrls as $sUrlTemplate)
{
unset($aToCompleteUrls[$sUrlTemplate]);
$sResolvedUrl = static::ResolveUrl($sUrlTemplate, $aFoundVariables);
if ($sResolvedUrl == false)
{
$aToCompleteUrls[$sUrlTemplate] = $sUrlTemplate;
}
else
{
$sUri = static::ResolveUrl($sUrlTemplate, $aFoundVariablesWithEmptyValue);
$aExplodedUri = explode('?', $sUri);
if (empty($aExplodedUri))
{
$aCompleteUrls[$sUri] = $sResolvedUrl;
}
else
{
$aCompleteUrls[$aExplodedUri[0]] = $sResolvedUrl;
}
}
}
}
return [ $aToCompleteUrls, $aCompleteUrls];
}
/**
* Find all referenced URLs from a SCSS file.
* @param $aThemeParametersVariables
* @param $sStylesheetFile
*
* @return array
*/
public static function GetAllUrlFromScss($aThemeParametersVariables, $sStylesheetFile)
{
$aCompleteUrls = [];
$aToCompleteUrls = [];
$aMissingVariables = [];
$aFoundVariables = [];
if (is_file($sStylesheetFile))
{
$sContent = file_get_contents($sStylesheetFile);
if (preg_match_all("/url\s*\((.*)\)/", $sContent, $aMatches))
{
foreach ($aMatches[1] as $path)
{
if (!array_key_exists($path, $aCompleteUrls)
&& !array_key_exists($path, $aToCompleteUrls))
{
if (preg_match_all("/\\$([\w\-_]+)/", $path, $aCurrentVars))
{
/** @var string $aCurrentVars */
foreach ($aCurrentVars[1] as $var)
{
if (!array_key_exists($var, $aMissingVariables))
{
$aMissingVariables[$var] = $var;
}
}
$aToCompleteUrls[$path] = $path;
}
else
{
$aCompleteUrls[$path] = trim($path, "\"'");
}
}
}
}
if (!empty($aMissingVariables))
{
list($aMissingVariables, $aFoundVariables) = static::FindMissingVariables($aThemeParametersVariables, $aMissingVariables, $aFoundVariables, $sContent);
list($aToCompleteUrls, $aCompleteUrls) = static::ResolveUrls($aFoundVariables, $aToCompleteUrls, $aCompleteUrls);
}
}
return [
'aCompleteUrls' => $aCompleteUrls,
'aToCompleteUrls' => $aToCompleteUrls,
'aMissingVariables' => $aMissingVariables,
'aFoundVariables' => $aFoundVariables
];
}
/**
* Calculate url based on its template + variables.
* @param $sUrlTemplate
* @param $aFoundVariables
*
* @return bool|string
*/
public static function ResolveUrl($sUrlTemplate, $aFoundVariables)
{
$aPattern= [];
$aReplacement= [];
foreach ($aFoundVariables as $aFoundVariable => $aFoundVariableValue)
{
//XX + $key + YY
$aPattern[]="/['\"]\s*\+\s*\\\$" . $aFoundVariable . "[\s\+]+\s*['\"]/";
$aReplacement[]=$aFoundVariableValue;
//$key + YY
$aPattern[]="/\\\$" . $aFoundVariable. "[\s\+]+\s*['\"]/";
$aReplacement[]=$aFoundVariableValue;
//XX + $key
$aPattern[]="/['\"]\s*[\+\s]+\\\$" . $aFoundVariable . "$/";
$aReplacement[]=$aFoundVariableValue;
}
$sResolvedUrl=preg_replace($aPattern, $aReplacement, $sUrlTemplate);
if (strpos($sResolvedUrl, "+")!==false)
{
return false;
}
return trim($sResolvedUrl, "\"'");
}
/**
* indicate whether a string ends with image suffix.
* @param $path
*
* @return bool
*/
private static function HasImageExtension($path)
{
foreach (static::IMAGE_EXTENSIONS as $sExt)
{
if (endsWith($path, $sExt))
{
return true;
}
}
return false;
}
/**
* Extract the signature for a generated CSS file. The signature MUST be alone one line immediately
* followed (on the next line) by the === SIGNATURE END === pattern
*
* Note the signature can be place anywhere in the CSS file (obviously inside a CSS comment !) but the
* function will be faster if the signature is at the beginning of the file (since the file is scanned from the start)
*
* @param $sFilepath
*
* @return string
*/
public static function GetSignature($sFilepath)
{
$sPreviousLine = '';
$hFile = @fopen($sFilepath, "r");
if ($hFile !== false)
{
$sLine = '';
do
{
$sPreviousLine = $sLine;
$sLine = rtrim(fgets($hFile)); // Remove the trailing \n
}
while (($sLine !== false) && ($sLine != '=== SIGNATURE END ==='));
fclose($hFile);
}
return $sPreviousLine;
}
public static function GetVarSignature($JsonSignature)
{
$aJsonArray = json_decode($JsonSignature, true);
if (array_key_exists('variables', $aJsonArray))
{
return $aJsonArray['variables'];
}
return false;
}
/**
* Find the given file in the list of ImportsPaths directory
* @param string $sFile
* @param string[] $aImportsPaths
* @throws Exception
* @return string
*/
public static function FindStylesheetFile($sFile, $aImportsPaths)
{
foreach($aImportsPaths as $sPath)
{
$sImportedFile = realpath($sPath.'/'.$sFile);
if (file_exists($sImportedFile))
{
return $sImportedFile;
}
}
return ''; // Not found, fail silently, maybe the SCSS compiler knowns better...
}
public static function MockCompileCSSService($oCompileCSSServiceMock)
{
static::$oCompileCSSService = $oCompileCSSServiceMock;
}
/**
* Clone variable array and include $version with bSetupCompilationTimestamp value
* @param $aThemeParameters
* @param $bSetupCompilationTimestamp
*
* @return array
*/
public static function CloneThemeParameterAndIncludeVersion($aThemeParameters, $bSetupCompilationTimestamp)
{
$aThemeParametersVariable = [];
if (array_key_exists('variables', $aThemeParameters))
{
if (is_array($aThemeParameters['variables']))
{
$aThemeParametersVariable = array_merge([], $aThemeParameters['variables']);
}
}
$aThemeParametersVariable['$version'] = $bSetupCompilationTimestamp;
return $aThemeParametersVariable;
}
}
class CompileCSSService
{
/**
* CompileCSSService constructor.
*/
public function __construct()
{
}
public function CompileCSSFromSASS($sSassContent, $aImportPaths = [], $aVariables = []){
return utils::CompileCSSFromSASS($sSassContent, $aImportPaths, $aVariables);
}
}

View File

@@ -234,7 +234,14 @@ class privUITransactionFile
*/
public static function IsTransactionValid($id, $bRemoveTransaction = true)
{
$sFilepath = APPROOT.'data/transactions/'.$id;
// Constraint the transaction file within APPROOT.'data/transactions'
$sTransactionDir = realpath(APPROOT.'data/transactions');
$sFilepath = utils::RealPath($sTransactionDir.'/'.$id, $sTransactionDir);
if (($sFilepath === false) || (strlen($sTransactionDir) == strlen($sFilepath)))
{
return false;
}
clearstatcache(true, $sFilepath);
$bResult = file_exists($sFilepath);
if ($bResult)

View File

@@ -17,7 +17,6 @@
* You should have received a copy of the GNU Affero General Public License
*/
require_once(APPROOT.'/application/webpage.class.inc.php');
require_once(APPROOT.'/application/displayblock.class.inc.php');
/**
@@ -68,6 +67,7 @@ class UIExtKeyWidget
protected $iId;
protected $sTargetClass;
protected $sAttCode;
//@deprecated
protected $bSearchMode;
//public function __construct($sAttCode, $sClass, $sTitle, $oAllowedValues, $value, $iInputId, $bMandatory, $sNameSuffix = '', $sFieldPrefix = '', $sFormPrefix = '')
@@ -86,7 +86,29 @@ class UIExtKeyWidget
$sDisplayStyle = 'select'; // In search mode, always use a drop-down list
}
$oWidget = new UIExtKeyWidget($sTargetClass, $iInputId, $sAttCode, $bSearchMode);
return $oWidget->Display($oPage, $iMaxComboLength, $bAllowTargetCreation, $sTitle, $oAllowedValues, $value, $iInputId, $bMandatory, $sFieldName, $sFormPrefix, $aArgs, null, $sDisplayStyle);
if(!$bSearchMode)
{
switch($sDisplayStyle)
{
case 'radio':
case 'radio_horizontal':
case 'radio_vertical':
return $oWidget->DisplayRadio($oPage, $iMaxComboLength, $bAllowTargetCreation, $oAllowedValues, $value, $sFieldName, $sDisplayStyle);
break;
case 'select':
case 'list':
default:
return $oWidget->DisplaySelect($oPage, $iMaxComboLength, $bAllowTargetCreation, $sTitle, $oAllowedValues, $value,
$bMandatory, $sFieldName, $sFormPrefix, $aArgs);
}
}
else
{
return $oWidget->Display($oPage, $iMaxComboLength, $bAllowTargetCreation, $sTitle, $oAllowedValues, $value, $iInputId, $bMandatory, $sFieldName, $sFormPrefix, $aArgs, null, $sDisplayStyle);
}
}
public function __construct($sTargetClass, $iInputId, $sAttCode = '', $bSearchMode = false)
@@ -98,6 +120,291 @@ class UIExtKeyWidget
}
/**
* @since 3.0.0 N°2508 - Include Obsolescence icon within list and autocomplete
* Get the HTML fragment corresponding to the ext key editing widget
* @param WebPage $oP The web page used for all the output
* @param array $aArgs Extra context arguments
* @return string The HTML fragment to be inserted into the page
*/
public function DisplaySelect(WebPage $oPage, $iMaxComboLength, $bAllowTargetCreation, $sTitle, DBObjectset $oAllowedValues, $value, $bMandatory, $sFieldName, $sFormPrefix = '', $aArgs = array())
{
$sTitle = addslashes($sTitle);
$oPage->add_linked_script('../js/extkeywidget.js');
$oPage->add_linked_script('../js/forms-json-utils.js');
$bCreate = (!$this->bSearchMode) && (UserRights::IsActionAllowed($this->sTargetClass, UR_ACTION_BULK_MODIFY) && $bAllowTargetCreation);
$bExtensions = true;
$sMessage = Dict::S('UI:Message:EmptyList:UseSearchForm');
$sAttrFieldPrefix = ($this->bSearchMode) ? '' : 'attr_';
$sHTMLValue = "<div class=\"field_input_zone field_input_extkey ibo-input-wrapper ibo-input-select-wrapper\" data-validation=\"untouched\">";
$sFilter = addslashes($oAllowedValues->GetFilter()->ToOQL());
if($this->bSearchMode)
{
$sWizHelper = 'null';
$sWizHelperJSON = "''";
$sJSSearchMode = 'true';
}
else
{
if (isset($aArgs['wizHelper']))
{
$sWizHelper = $aArgs['wizHelper'];
}
else
{
$sWizHelper = 'oWizardHelper'.$sFormPrefix;
}
$sWizHelperJSON = $sWizHelper.'.UpdateWizardToJSON()';
$sJSSearchMode = 'false';
}
if (is_null($oAllowedValues))
{
throw new Exception('Implementation: null value for allowed values definition');
}
$oAllowedValues->SetShowObsoleteData(utils::ShowObsoleteData());
// Don't automatically launch the search if the table is huge
$bDoSearch = !utils::IsHighCardinality($this->sTargetClass);
$sJSDoSearch = $bDoSearch ? 'true' : 'false';
// We just need to compare the number of entries with MaxComboLength, so no need to get the real count.
if (!$oAllowedValues->CountExceeds($iMaxComboLength))
{
// Discrete list of values, use a SELECT or RADIO buttons depending on the config
$sHelpText = ''; //$this->oAttDef->GetHelpOnEdition();
//$sHTMLValue .= "<div class=\"field_select_wrapper\">\n";
$aOptions = [];
$sDisplayValue = "";
$aOption = [];
$aOption['value'] = "";
$aOption['label'] = Dict::S('UI:SelectOne');
array_push($aOptions,$aOption);
$oAllowedValues->Rewind();
$bAddingValue=false;
$aComplementAttributeSpec = MetaModel::GetComplementAttributeSpec($oAllowedValues->GetClass());
$sFormatAdditionalField = $aComplementAttributeSpec[0];
$aAdditionalField = $aComplementAttributeSpec[1];
if (count($aAdditionalField)>0)
{
$bAddingValue=true;
}
while($oObj = $oAllowedValues->Fetch())
{
$aOption=[];
$aOption['value'] = $oObj->GetKey();
$aOption['label'] = $oObj->GetName();//.'<span class=\"object-ref-icon fas fa-eye-slash object-obsolete fa-1x fa-fw\"></span>';
if (($oAllowedValues->Count() == 1) && ($bMandatory == 'true') )
{
// When there is only once choice, select it by default
$sDisplayValue=$oObj->GetName();
if($value != $oObj->GetKey())
{
$oPage->add_ready_script(
<<<EOF
$('#$this->iId').attr('data-validate','dependencies');
EOF
);
}
}
else
{
if ((is_array($value) && in_array($oObj->GetKey(), $value)) || ($value == $oObj->GetKey()))
{
$sDisplayValue=$oObj->GetKey();
// $sHTMLValue.="<div class='item' data-value='".$oObj->GetKey)."'>".$oObj->GetName()."</div>";
}
}
if ($oObj->IsObsolete()){
$aOption['obsolescence_flag'] ="1";
}
if ($bAddingValue)
{
$aArguments = [];
foreach ($aAdditionalField as $sAdditionalField)
{
array_push($aArguments,$oObj->Get($sAdditionalField));
}
$aOption['additional_field'] = vsprintf($sFormatAdditionalField, $aArguments);
}
array_push($aOptions,$aOption);
}
$sHTMLValue .= "<select title=\"$sHelpText\" name=\"{$sAttrFieldPrefix}{$sFieldName}\" id=\"$this->iId\"></select>";
$sJsonOptions=json_encode($aOptions);
$oPage->add_ready_script(
<<<EOF
oACWidget_{$this->iId} = new ExtKeyWidget('{$this->iId}', '{$this->sTargetClass}', '$sFilter', '$sTitle', true, $sWizHelper, '{$this->sAttCode}', $sJSSearchMode, $sJSDoSearch);
oACWidget_{$this->iId}.emptyHtml = "<div style=\"background: #fff; border:0; text-align:center; vertical-align:middle;\"><p>$sMessage</p></div>";
oACWidget_{$this->iId}.AddSelectize('$sJsonOptions','$sDisplayValue');
$('#$this->iId').bind('update', function() { oACWidget_{$this->iId}.Update(); } );
$('#$this->iId').bind('change', function() { $(this).trigger('extkeychange') } );
EOF
);
}
else
{
// Too many choices, use an autocomplete
// Check that the given value is allowed
$oSearch = $oAllowedValues->GetFilter();
$oSearch->AddCondition('id', $value);
$oSet = new DBObjectSet($oSearch);
if ($oSet->Count() == 0)
{
$value = null;
}
if (is_null($value) || ($value == 0)) // Null values are displayed as ''
{
$sDisplayValue = isset($aArgs['sDefaultValue']) ? $aArgs['sDefaultValue'] : '';
}
else
{
$sDisplayValue = $this->GetObjectName($value);
}
$iMinChars = isset($aArgs['iMinChars']) ? $aArgs['iMinChars'] : 2; //@@@ $this->oAttDef->GetMinAutoCompleteChars();
// the input for the auto-complete
$sHTMLValue .= "<input class=\"field_autocomplete ibo-input ibo-input-select ibo-input-select-autocomplete\" type=\"text\" id=\"label_$this->iId\" value=\"$sDisplayValue\"/>";
$sHTMLValue .= "<div class=\"field_input_btn ibo-input-select--action-button ibo-input-select--action-button--search\" id=\"mini_search_{$this->iId}\" onClick=\"oACWidget_{$this->iId}.Search();\"><i class=\"fas fa-search\"></i></div>";
// another hidden input to store & pass the object's Id
$sHTMLValue .= "<input type=\"hidden\" id=\"$this->iId\" name=\"{$sAttrFieldPrefix}{$sFieldName}\" value=\"".htmlentities($value, ENT_QUOTES, 'UTF-8')."\" />\n";
$JSSearchMode = $this->bSearchMode ? 'true' : 'false';
// Scripts to start the autocomplete and bind some events to it
$oPage->add_ready_script(
<<<EOF
oACWidget_{$this->iId} = new ExtKeyWidget('{$this->iId}', '{$this->sTargetClass}', '$sFilter', '$sTitle', false, $sWizHelper, '{$this->sAttCode}', $sJSSearchMode, $sJSDoSearch);
oACWidget_{$this->iId}.emptyHtml = "<div style=\"background: #fff; border:0; text-align:center; vertical-align:middle;\"><p>$sMessage</p></div>";
oACWidget_{$this->iId}.AddAutocomplete($iMinChars, $sWizHelperJSON);
if ($('#ac_dlg_{$this->iId}').length == 0)
{
$('body').append('<div id="ac_dlg_{$this->iId}"></div>');
}
EOF
);
}
if ($bExtensions && MetaModel::IsHierarchicalClass($this->sTargetClass) !== false)
{
$sHTMLValue .= "<div class=\"field_input_btn ibo-input-select--action-button ibo-input-select--action-button--hierarchy\" id=\"mini_tree_{$this->iId}\" onClick=\"oACWidget_{$this->iId}.HKDisplay();\"><i class=\"fas fa-sitemap\"></i></div>";
$oPage->add_ready_script(
<<<JS
if ($('#ac_tree_{$this->iId}').length == 0)
{
$('body').append('<div id="ac_tree_{$this->iId}"></div>');
}
JS
);
}
if ($bCreate && $bExtensions)
{
$sCallbackName = (MetaModel::IsAbstract($this->sTargetClass)) ? 'SelectObjectClass' : 'CreateObject';
$sHTMLValue .= "<div class=\"field_input_btn ibo-input-select--action-button ibo-input-select--action-button--create\" id=\"mini_add_{$this->iId}\" onClick=\"oACWidget_{$this->iId}.{$sCallbackName}();\"><i class=\"fas fa-plus\"></i></div>";
$oPage->add_ready_script(
<<<JS
if ($('#ajax_{$this->iId}').length == 0)
{
$('body').append('<div id="ajax_{$this->iId}"></div>');
}
JS
);
}
$sHTMLValue .= "</div>";
$sHTMLValue .= "<span class=\"form_validation ibo-field-validation\" id=\"v_{$this->iId}\"></span><span class=\"field_status\" id=\"fstatus_{$this->iId}\"></span>";
return $sHTMLValue;
}
/**
* @since 3.0.0 N°2508 - Include Obsolescence icon within list and autocomplete
* Get the HTML fragment corresponding to the ext key editing widget
* @param WebPage $oP The web page used for all the output
* @param array $aArgs Extra context arguments
* @return string The HTML fragment to be inserted into the page
*/
public function DisplayRadio(WebPage $oPage, $iMaxComboLength, $bAllowTargetCreation, DBObjectset $oAllowedValues, $value, $sFieldName, $sDisplayStyle)
{
$oPage->add_linked_script('../js/forms-json-utils.js');
$bCreate = (!$this->bSearchMode) && (UserRights::IsActionAllowed($this->sTargetClass, UR_ACTION_BULK_MODIFY) && $bAllowTargetCreation);
$bExtensions = true;
$sAttrFieldPrefix = ($this->bSearchMode) ? '' : 'attr_';
$sHTMLValue = "<div class=\"field_input_zone field_input_extkey\">";
if (is_null($oAllowedValues))
{
throw new Exception('Implementation: null value for allowed values definition');
}
$oAllowedValues->SetShowObsoleteData(utils::ShowObsoleteData());
// We just need to compare the number of entries with MaxComboLength, so no need to get the real count.
if (!$oAllowedValues->CountExceeds($iMaxComboLength))
{
// Discrete list of values, use a SELECT or RADIO buttons depending on the config
$sValidationField = null;
$bVertical = ($sDisplayStyle != 'radio_horizontal');
$bExtensions = false;
$oAllowedValues->Rewind();
$aAllowedValues = array();
while($oObj = $oAllowedValues->Fetch())
{
$aAllowedValues[$oObj->GetKey()] = $oObj->GetName();
}
$sHTMLValue .= $oPage->GetRadioButtons($aAllowedValues, $value, $this->iId, "{$sAttrFieldPrefix}{$sFieldName}", false /* $bMandatory will be placed manually */, $bVertical, $sValidationField);
$aEventsList[] ='change';
}
else
{
$sHTMLValue .= "unable to display. Too much values";
}
$sHTMLValue .= '<div class="ibo-input-select--action-buttons">';
if ($bExtensions && MetaModel::IsHierarchicalClass($this->sTargetClass) !== false)
{
$sHTMLValue .= "<span class=\"field_input_btn\"><div class=\"mini_button\" id=\"mini_tree_{$this->iId}\" onClick=\"oACWidget_{$this->iId}.HKDisplay();\"><i class=\"fas fa-sitemap\"></i></div></span>";
$oPage->add_ready_script(
<<<JS
if ($('#ac_tree_{$this->iId}').length == 0)
{
$('body').append('<div id="ac_tree_{$this->iId}"></div>');
}
JS
);
}
if ($bCreate && $bExtensions)
{
$sCallbackName = (MetaModel::IsAbstract($this->sTargetClass)) ? 'SelectObjectClass' : 'CreateObject';
$sHTMLValue .= "<span class=\"field_input_btn\"><div class=\"mini_button\" id=\"mini_add_{$this->iId}\" onClick=\"oACWidget_{$this->iId}.{$sCallbackName}();\"><i class=\"fas fa-plus\"></i></div></span>";
$oPage->add_ready_script(
<<<JS
if ($('#ajax_{$this->iId}').length == 0)
{
$('body').append('<div id="ajax_{$this->iId}"></div>');
}
JS
);
}
$sHTMLValue .= "</div>";
$sHTMLValue .= "</div>";
// Note: This test is no longer necessary as we changed the markup to extract validation decoration in the standard .field_input_xxx container
//if (($sDisplayStyle == 'select') || ($sDisplayStyle == 'list'))
//{
$sHTMLValue .= "<span class=\"form_validation ibo-field-validation\" id=\"v_{$this->iId}\"></span><span class=\"field_status\" id=\"fstatus_{$this->iId}\"></span>";
//}
return $sHTMLValue;
}
/**
* @deprecated Use DisplayBob
* Get the HTML fragment corresponding to the ext key editing widget
* @param WebPage $oP The web page used for all the output
* @param array $aArgs Extra context arguments
@@ -239,7 +546,7 @@ EOF
$oPage->add_ready_script("$('.multiselect').multiselect($sJSOptions);");
}
$oPage->add_ready_script(
<<<EOF
<<<EOF
oACWidget_{$this->iId} = new ExtKeyWidget('{$this->iId}', '{$this->sTargetClass}', '$sFilter', '$sTitle', true, $sWizHelper, '{$this->sAttCode}', $sJSSearchMode, $sJSDoSearch);
oACWidget_{$this->iId}.emptyHtml = "<div style=\"background: #fff; border:0; text-align:center; vertical-align:middle;\"><p>$sMessage</p></div>";
$('#$this->iId').bind('update', function() { oACWidget_{$this->iId}.Update(); } );
@@ -269,10 +576,10 @@ EOF
{
$sDisplayValue = $this->GetObjectName($value);
}
$iMinChars = isset($aArgs['iMinChars']) ? $aArgs['iMinChars'] : 3; //@@@ $this->oAttDef->GetMinAutoCompleteChars();
$iMinChars = isset($aArgs['iMinChars']) ? $aArgs['iMinChars'] : 2; //@@@ $this->oAttDef->GetMinAutoCompleteChars();
// the input for the auto-complete
$sHTMLValue .= "<input class=\"field_autocomplete\" type=\"text\" id=\"label_$this->iId\" value=\"$sDisplayValue\"/>";
$sHTMLValue .= "<input class=\"field_autocomplete ibo-input-select\" type=\"text\" id=\"label_$this->iId\" value=\"$sDisplayValue\"/>";
$sHTMLValue .= "<span class=\"field_input_btn\"><div class=\"mini_button\" id=\"mini_search_{$this->iId}\" onClick=\"oACWidget_{$this->iId}.Search();\"><i class=\"fas fa-search\"></i></div></span>";
// another hidden input to store & pass the object's Id
@@ -281,106 +588,100 @@ EOF
$JSSearchMode = $this->bSearchMode ? 'true' : 'false';
// Scripts to start the autocomplete and bind some events to it
$oPage->add_ready_script(
<<<EOF
<<<EOF
oACWidget_{$this->iId} = new ExtKeyWidget('{$this->iId}', '{$this->sTargetClass}', '$sFilter', '$sTitle', false, $sWizHelper, '{$this->sAttCode}', $sJSSearchMode, $sJSDoSearch);
oACWidget_{$this->iId}.emptyHtml = "<div style=\"background: #fff; border:0; text-align:center; vertical-align:middle;\"><p>$sMessage</p></div>";
$('#label_$this->iId').autocomplete(GetAbsoluteUrlAppRoot()+'pages/ajax.render.php', { scroll:true, minChars:{$iMinChars}, autoFill:false, matchContains:true, mustMatch: true, keyHolder:'#{$this->iId}', extraParams:{operation:'ac_extkey', sTargetClass:'{$this->sTargetClass}',sFilter:'$sFilter',bSearchMode:$JSSearchMode, json: function() { return $sWizHelperJSON; } }});
$('#label_$this->iId').keyup(function() { if ($(this).val() == '') { $('#$this->iId').val(''); } } ); // Useful for search forms: empty value in the "label", means no value, immediatly !
$('#label_$this->iId').result( function(event, data, formatted) { OnAutoComplete('{$this->iId}', event, data, formatted); } );
$('#$this->iId').bind('update', function() { oACWidget_{$this->iId}.Update(); } );
oACWidget_{$this->iId}.AddAutocomplete($iMinChars, $sWizHelperJSON);
if ($('#ac_dlg_{$this->iId}').length == 0)
{
$('body').append('<div id="ac_dlg_{$this->iId}"></div>');
}
EOF
);
);
}
if ($bExtensions && MetaModel::IsHierarchicalClass($this->sTargetClass) !== false)
{
$sHTMLValue .= "<span class=\"field_input_btn\"><div class=\"mini_button\" id=\"mini_tree_{$this->iId}\" onClick=\"oACWidget_{$this->iId}.HKDisplay();\"><i class=\"fas fa-sitemap\"></i></div></span>";
$sHTMLValue .= "<span class=\"field_input_btn\"><div class=\"ibo-input-select--action-button\" id=\"mini_tree_{$this->iId}\" onClick=\"oACWidget_{$this->iId}.HKDisplay();\"><i class=\"fas fa-sitemap\"></i></div></span>";
$oPage->add_ready_script(
<<<EOF
<<<JS
if ($('#ac_tree_{$this->iId}').length == 0)
{
$('body').append('<div id="ac_tree_{$this->iId}"></div>');
}
EOF
JS
);
}
if ($bCreate && $bExtensions)
{
$sCallbackName = (MetaModel::IsAbstract($this->sTargetClass)) ? 'SelectObjectClass' : 'CreateObject';
$sHTMLValue .= "<span class=\"field_input_btn\"><div class=\"mini_button\" id=\"mini_add_{$this->iId}\" onClick=\"oACWidget_{$this->iId}.{$sCallbackName}();\"><i class=\"fas fa-plus\"></i></div></span>";
$sHTMLValue .= "<span class=\"field_input_btn\"><div class=\"ibo-input-select--action-button\" id=\"mini_add_{$this->iId}\" onClick=\"oACWidget_{$this->iId}.{$sCallbackName}();\"><i class=\"fas fa-plus\"></i></div></span>";
$oPage->add_ready_script(
<<<EOF
<<<JS
if ($('#ajax_{$this->iId}').length == 0)
{
$('body').append('<div id="ajax_{$this->iId}"></div>');
}
EOF
JS
);
}
$sHTMLValue .= "</div>";
// Note: This test is no longer necessary as we changed the markup to extract validation decoration in the standard .field_input_xxx container
//if (($sDisplayStyle == 'select') || ($sDisplayStyle == 'list'))
//{
$sHTMLValue .= "<span class=\"form_validation\" id=\"v_{$this->iId}\"></span><span class=\"field_status\" id=\"fstatus_{$this->iId}\"></span>";
//}
$sHTMLValue .= "<span class=\"form_validation ibo-field-validation\" id=\"v_{$this->iId}\"></span><span class=\"field_status\" id=\"fstatus_{$this->iId}\"></span>";
return $sHTMLValue;
}
public function GetSearchDialog(WebPage $oPage, $sTitle, $oCurrObject = null)
{
$sHTML = '<div class="wizContainer" style="vertical-align:top;"><div id="dc_'.$this->iId.'">';
$oPage->add('<div class="wizContainer" style="vertical-align:top;"><div id="dc_'.$this->iId.'">');
if ( ($oCurrObject != null) && ($this->sAttCode != ''))
{
if (($oCurrObject != null) && ($this->sAttCode != '')) {
$oAttDef = MetaModel::GetAttributeDef(get_class($oCurrObject), $this->sAttCode);
/** @var \DBObject $oCurrObject */
$aArgs = $oCurrObject->ToArgsForQuery();
$aParams = array('query_params' => $aArgs);
$oSet = $oAttDef->GetAllowedValuesAsObjectSet($aArgs);
$oFilter = $oSet->GetFilter();
}
else
{
} else {
$aParams = array();
$oFilter = new DBObjectSearch($this->sTargetClass);
}
$oFilter->SetModifierProperty('UserRightsGetSelectFilter', 'bSearchMode', $this->bSearchMode);
$oBlock = new DisplayBlock($oFilter, 'search', false, $aParams);
$sHTML .= $oBlock->GetDisplay($oPage, $this->iId,
array(
'menu' => false,
'currentId' => $this->iId,
'table_id' => "dr_{$this->iId}",
'table_inner_id' => "{$this->iId}_results",
'selection_mode' => true,
'selection_type' => 'single',
'cssCount' => '#count_'.$this->iId)
);
$sHTML .= "<form id=\"fr_{$this->iId}\" OnSubmit=\"return oACWidget_{$this->iId}.DoOk();\">\n";
$sHTML .= "<div id=\"dr_{$this->iId}\" style=\"vertical-align:top;background: #fff;height:100%;overflow:auto;padding:0;border:0;\">\n";
$sHTML .= "<div style=\"background: #fff; border:0; text-align:center; vertical-align:middle;\"><p>".Dict::S('UI:Message:EmptyList:UseSearchForm')."</p></div>\n";
$sHTML .= "</div>\n";
$sHTML .= "<input type=\"button\" id=\"btn_cancel_{$this->iId}\" value=\"".Dict::S('UI:Button:Cancel')."\" onClick=\"$('#ac_dlg_{$this->iId}').dialog('close');\">&nbsp;&nbsp;";
$sHTML .= "<input type=\"button\" id=\"btn_ok_{$this->iId}\" value=\"".Dict::S('UI:Button:Ok')."\" onClick=\"oACWidget_{$this->iId}.DoOk();\">";
$sHTML .= "<input type=\"hidden\" id=\"count_{$this->iId}\" value=\"0\">";
$sHTML .= "</form>\n";
$sHTML .= '</div></div>';
$oPage->AddUiBlock($oBlock->GetDisplay($oPage, $this->iId,
array(
'menu' => false,
'currentId' => $this->iId,
'table_id' => "dr_{$this->iId}",
'table_inner_id' => "{$this->iId}_results",
'selection_mode' => true,
'selection_type' => 'single',
'cssCount' => '#count_'.$this->iId
)
));
$sCancel = Dict::S('UI:Button:Cancel');
$sOK = Dict::S('UI:Button:Ok');
$sEmptyList = Dict::S('UI:Message:EmptyList:UseSearchForm');
$oPage->add(<<<HTML
<form id="fr_{$this->iId}" OnSubmit="return oACWidget_{$this->iId}.DoOk();">
<div id="dr_{$this->iId}" style="vertical-align:top;background: #fff;height:100%;overflow:auto;padding:0;border:0;">
<div style="background: #fff; border:0; text-align:center; vertical-align:middle;"><p>{$sEmptyList}</p></div>
</div>
<input type="button" id="btn_cancel_{$this->iId}" value="{$sCancel}" onClick="$('#ac_dlg_{$this->iId}').dialog('close');">&nbsp;&nbsp;
<input type="button" id="btn_ok_{$this->iId}_results" value="{$sOK}" onClick="oACWidget_{$this->iId}.DoOk();">
<input type="hidden" id="count_{$this->iId}_results" value="0">
</form>
</div></div>
HTML
);
$sDialogTitle = addslashes($sTitle);
$oPage->add_ready_script(
<<<EOF
$oPage->add_ready_script(<<<JS
$('#ac_dlg_{$this->iId}').dialog({ width: $(window).width()*0.8, height: $(window).height()*0.8, autoOpen: false, modal: true, title: '$sDialogTitle', resizeStop: oACWidget_{$this->iId}.UpdateSizes, close: oACWidget_{$this->iId}.OnClose });
$('#fs_{$this->iId}').bind('submit.uiAutocomplete', oACWidget_{$this->iId}.DoSearchObjects);
$('#dc_{$this->iId}').resize(oACWidget_{$this->iId}.UpdateSizes);
EOF
);
$oPage->add($sHTML);
JS
);
}
/**
@@ -436,32 +737,53 @@ EOF
// Current extkey value, so we can display event if it is not available anymore (eg. archived).
$iCurrentExtKeyId = (is_null($oObj) || $this->sAttCode === '') ? 0 : $oObj->Get($this->sAttCode);
$oValuesSet = new ValueSetObjects($sFilter, 'friendlyname'); // Bypass GetName() to avoid the encoding by htmlentities
$iMax = 150;
$oValuesSet->SetLimit($iMax);
$oValuesSet->SetSort(false);
$oValuesSet->SetModifierProperty('UserRightsGetSelectFilter', 'bSearchMode', $this->bSearchMode);
$oValuesSet->SetLimit($iMax);
$aValuesContains = $oValuesSet->GetValues(array('this' => $oObj, 'current_extkey_id' => $iCurrentExtKeyId), $sContains, 'contains');
$aValuesContains = $oValuesSet->GetValuesForAutocomplete(array('this' => $oObj, 'current_extkey_id' => $iCurrentExtKeyId), $sContains, 'start_with');
asort($aValuesContains);
$aValues = array();
foreach($aValuesContains as $sKey => $sFriendlyName)
$aValues = $aValuesContains;
if (sizeof($aValues) < $iMax)
{
if (!isset($aValues[$sKey]))
$aValuesContains = $oValuesSet->GetValuesForAutocomplete(array('this' => $oObj, 'current_extkey_id' => $iCurrentExtKeyId), $sContains, 'contains');
asort($aValuesContains);
$iSize = sizeof($aValuesContains);
foreach ($aValuesContains as $sKey => $sFriendlyName)
{
$aValues[$sKey] = $sFriendlyName;
if (!isset($aValues[$sKey]))
{
$aValues[$sKey] = $sFriendlyName;
if (++$iSize >= $iMax)
{
break;
}
}
}
}
elseif (!in_array($sContains, $aValues))
{
$aValuesEquals = $oValuesSet->GetValuesForAutocomplete(array('this' => $oObj, 'current_extkey_id' => $iCurrentExtKeyId), $sContains, 'equals');
$aValues = array_merge($aValuesEquals, $aValues);
}
switch($sOutputFormat)
{
case static::ENUM_OUTPUT_FORMAT_JSON:
$aJsonMap = array();
foreach ($aValues as $sKey => $sLabel)
foreach ($aValues as $sKey => $aValue)
{
$aJsonMap[] = array('value' => $sKey, 'label' => $sLabel);
if ($aValue['additional_field'] != '')
{
$aJsonMap[] = array('value' => $sKey, 'label' => $aValue['label'], 'obsolescence_flag' => $aValue['obsolescence_flag'], 'additional_field' => $aValue['additional_field']);
}
else
{
$aJsonMap[] = array('value' => $sKey, 'label' => $aValue['label'], 'obsolescence_flag' => $aValue['obsolescence_flag']);
}
}
$oP->SetContentType('application/json');
@@ -469,9 +791,9 @@ EOF
break;
case static::ENUM_OUTPUT_FORMAT_CSV:
foreach($aValues as $sKey => $sFriendlyName)
foreach($aValues as $sKey => $aValue)
{
$oP->add(trim($sFriendlyName)."\t".$sKey."\n");
$oP->add(trim($aValue['label'])."\t".$sKey."\n");
}
break;
default:
@@ -636,15 +958,22 @@ HTML
$oSet->SetShowObsoleteData(utils::ShowObsoleteData());
$sHKAttCode = MetaModel::IsHierarchicalClass($this->sTargetClass);
$this->DumpTree($oPage, $oSet, $sHKAttCode, $currValue);
$bHasChildLeafs = $this->DumpTree($oPage, $oSet, $sHKAttCode, $currValue);
$oPage->add('</td></tr></table>');
$oPage->add('</div>');
if ($bHasChildLeafs)
{
$oPage->add('<div class="treecontrol" id="treecontrolid"><a href="?#">'.Dict::S("UI:Treeview:CollapseAll").'</a> | <a href="?#">'.Dict::S("UI:Treeview:ExpandAll").'</a></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("\$('#tree_$this->iId ul').treeview({ control: '#treecontrolid', persist: 'false'});\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");
}
@@ -673,6 +1002,18 @@ HTML
}
}
/**
* @param WebPage $oP
* @param \DBObjectSet $oSet
* @param string $sParentAttCode
* @param string $currValue
*
* @return bool true if there are at least one child leaf, false if only roots nodes are present
* @throws \ArchivedObjectException
* @throws \CoreException
* @throws \CoreUnexpectedValue
* @throws \MySQLException
*/
function DumpTree($oP, $oSet, $sParentAttCode, $currValue)
{
$aTree = array();
@@ -701,6 +1042,9 @@ HTML
{
$this->DumpNodes($oP, $iRootId, $aTree, $aNodes, $currValue);
}
$bHasOnlyRootNodes = (count($aTree) === 1);
return !$bHasOnlyRootNodes;
}
function DumpNodes($oP, $iRootId, $aTree, $aNodes, $currValue)
@@ -728,7 +1072,7 @@ HTML
$sSelect = '<input id="input_'.$fUniqueId.'_'.$aNodes[$id]->GetKey().'" type="radio" value="'.$aNodes[$id]->GetKey().'" name="selectObject" '.$sChecked.'>&nbsp;';
}
}
$oP->add('<li>'.$sSelect.'<label for="input_'.$fUniqueId.'_'.$aNodes[$id]->GetKey().'">'.$aNodes[$id]->GetName().'</label>');
$oP->add('<li class="closed">'.$sSelect.'<label for="input_'.$fUniqueId.'_'.$aNodes[$id]->GetKey().'">'.$aNodes[$id]->GetName().'</label>');
$this->DumpNodes($oP, $id, $aTree, $aNodes, $currValue);
$oP->add("</li>\n");
}

View File

@@ -184,7 +184,7 @@ class UILinksWidgetDirect
// For security reasons: check that the "proposed" class is actually a subclass of the linked class
// and that the current user is allowed to create objects of this class
$sRealClass = '';
$oPage->add('<div class="wizContainer" style="vertical-align:top;"><div>');
//$oPage->add('<div class="wizContainer" style="vertical-align:top;"><div>');
$aSubClasses = MetaModel::EnumChildClasses($this->sLinkedClass, ENUM_CHILD_CLASSES_ALL); // Including the specified class itself
$aPossibleClasses = array();
foreach($aSubClasses as $sCandidateClass)
@@ -294,20 +294,17 @@ class UILinksWidgetDirect
*/
public function GetObjectsSelectionDlg($oPage, $oCurrentObj, $aAlreadyLinked, $aPrefillFormParam = array())
{
$sHtml = "<div class=\"wizContainer\" style=\"vertical-align:top;\">\n";
//$oPage->add("<div class=\"wizContainer\" style=\"vertical-align:top;\">\n");
$oHiddenFilter = new DBObjectSearch($this->sLinkedClass);
if (($oCurrentObj != null) && MetaModel::IsSameFamilyBranch($this->sLinkedClass, $this->sClass))
{
if (($oCurrentObj != null) && MetaModel::IsSameFamilyBranch($this->sLinkedClass, $this->sClass)) {
// Prevent linking to self if the linked object is of the same family
// and already present in the database
if (!$oCurrentObj->IsNew())
{
if (!$oCurrentObj->IsNew()) {
$oHiddenFilter->AddCondition('id', $oCurrentObj->GetKey(), '!=');
}
}
if (count($aAlreadyLinked) > 0)
{
if (count($aAlreadyLinked) > 0) {
$oHiddenFilter->AddCondition('id', $aAlreadyLinked, 'NOTIN');
}
$oHiddenCriteria = $oHiddenFilter->GetCriteria();
@@ -319,18 +316,14 @@ class UILinksWidgetDirect
if ($valuesDef === null)
{
$oFilter = new DBObjectSearch($this->sLinkedClass);
}
else
{
if (!$valuesDef instanceof ValueSetObjects)
{
} else {
if (!$valuesDef instanceof ValueSetObjects) {
throw new Exception('Error: only ValueSetObjects are supported for "allowed_values" in AttributeLinkedSet ('.$this->sClass.'/'.$this->sAttCode.').');
}
$oFilter = DBObjectSearch::FromOQL($valuesDef->GetFilterExpression());
}
if ($oCurrentObj != null)
{
if ($oCurrentObj != null) {
$this->SetSearchDefaultFromContext($oCurrentObj, $oFilter);
$aArgs = array_merge($oCurrentObj->ToArgs('this'), $oFilter->GetInternalParams());
@@ -339,7 +332,7 @@ class UILinksWidgetDirect
$oCurrentObj->PrefillForm('search', $aPrefillFormParam);
}
$oBlock = new DisplayBlock($oFilter, 'search', false);
$sHtml .= $oBlock->GetDisplay($oPage, "SearchFormToAdd_{$this->sInputid}",
$oPage->AddUiBlock($oBlock->GetDisplay($oPage, "SearchFormToAdd_{$this->sInputid}",
array(
'result_list_outer_selector' => "SearchResultsToAdd_{$this->sInputid}",
'table_id' => "add_{$this->sInputid}",
@@ -349,16 +342,21 @@ class UILinksWidgetDirect
'query_params' => $oFilter->GetInternalParams(),
'hidden_criteria' => $sHiddenCriteria,
)
);
$sHtml .= "<form id=\"ObjectsAddForm_{$this->sInputid}\">\n";
$sHtml .= "<div id=\"SearchResultsToAdd_{$this->sInputid}\" style=\"vertical-align:top;background: #fff;height:100%;overflow:auto;padding:0;border:0;\">\n";
$sHtml .= "<div style=\"background: #fff; border:0; text-align:center; vertical-align:middle;\"><p>".Dict::S('UI:Message:EmptyList:UseSearchForm')."</p></div>\n";
$sHtml .= "</div>\n";
$sHtml .= "<input type=\"hidden\" id=\"count_{$this->sInputid}\" value=\"0\"/>";
$sHtml .= "<button type=\"button\" class=\"cancel\">".Dict::S('UI:Button:Cancel')."</button>&nbsp;&nbsp;<button type=\"button\" class=\"ok\" disabled=\"disabled\">".Dict::S('UI:Button:Add')."</button>";
$sHtml .= "</div>\n";
$sHtml .= "</form>\n";
$oPage->add($sHtml);
));
$sEmptyList = Dict::S('UI:Message:EmptyList:UseSearchForm');
$sCancel = Dict::S('UI:Button:Cancel');
$sAdd = Dict::S('UI:Button:Add');
$oPage->add(<<<HTML
<form id="ObjectsAddForm_{$this->sInputid}">
<div id="SearchResultsToAdd_{$this->sInputid}" style="vertical-align:top;background: #fff;height:100%;overflow:auto;padding:0;border:0;">
<div style="background: #fff; border:0; text-align:center; vertical-align:middle;"><p>{$sEmptyList}</p></div>
</div>
<input type="hidden" id="count_{$this->sInputid}" value="0"/>
<button type="button" class="cancel">{$sCancel}</button>&nbsp;&nbsp;<button type="button" class="ok" disabled="disabled">{$sAdd}</button>
</form>
HTML
);
}
/**

View File

@@ -24,7 +24,10 @@
* @license http://opensource.org/licenses/AGPL-3.0
*/
require_once(APPROOT.'application/webpage.class.inc.php');
use Combodo\iTop\Application\UI\Component\DataTable\DataTableFactory;
use Combodo\iTop\Application\UI\Component\DataTable\StaticTable\FormTableRow\FormTableRow;
use Combodo\iTop\Renderer\BlockRenderer;
require_once(APPROOT.'application/displayblock.class.inc.php');
class UILinksWidget
@@ -39,6 +42,7 @@ class UILinksWidget
protected $m_sLinkedClass;
protected $m_sRemoteClass;
protected $m_bDuplicatesAllowed;
/** @var string[] list of editables attcodes */
protected $m_aEditableFields;
protected $m_aTableConfig;
@@ -46,7 +50,7 @@ class UILinksWidget
* UILinksWidget constructor.
*
* @param string $sClass
* @param string $sAttCode
* @param string $sAttCode AttributeLinkedSetIndirect attcode
* @param int $iInputId
* @param string $sNameSuffix
* @param bool $bDuplicatesAllowed
@@ -73,41 +77,36 @@ class UILinksWidget
/** @var AttributeExternalKey $oLinkingAttDef */
$oLinkingAttDef = MetaModel::GetAttributeDef($this->m_sLinkedClass, $this->m_sExtKeyToRemote);
$this->m_sRemoteClass = $oLinkingAttDef->GetTargetClass();
$sExtKeyToMe = $oAttDef->GetExtKeyToMe();
$sStateAttCode = MetaModel::GetStateAttributeCode($this->m_sClass);
$sDefaultState = MetaModel::GetDefaultState($this->m_sClass);
$this->m_aEditableFields = array();
$this->m_aTableConfig = array();
$this->m_aTableConfig['form::checkbox'] = array( 'label' => "<input class=\"select_all\" type=\"checkbox\" value=\"1\" onClick=\"CheckAll('#linkedset_{$this->m_sAttCode}{$this->m_sNameSuffix} .selection', this.checked); oWidget".$this->m_iInputId.".OnSelectChange();\">", 'description' => Dict::S('UI:SelectAllToggle+'));
$this->m_aTableConfig['form::checkbox'] = array(
'label' => "<input class=\"select_all\" type=\"checkbox\" value=\"1\" onClick=\"CheckAll('#linkedset_{$this->m_sAttCode}{$this->m_sNameSuffix} .selection', this.checked); oWidget".$this->m_iInputId.".OnSelectChange();\">",
'description' => Dict::S('UI:SelectAllToggle+'),
);
foreach(MetaModel::FlattenZList(MetaModel::GetZListItems($this->m_sLinkedClass, 'list')) as $sAttCode)
$aLnkAttDefsToDisplay = MetaModel::GetZListAttDefsFilteredForIndirectLinkClass($sClass, $sAttCode);
foreach ($aLnkAttDefsToDisplay as $oLnkAttDef)
{
$oAttDef = MetaModel::GetAttributeDef($this->m_sLinkedClass, $sAttCode);
if ($sStateAttCode == $sAttCode)
{
// State attribute is always hidden from the UI
}
else if ($oAttDef->IsWritable() && ($sAttCode != $sExtKeyToMe) && ($sAttCode != $this->m_sExtKeyToRemote) && ($sAttCode != 'finalclass'))
{
$iFlags = MetaModel::GetAttributeFlags($this->m_sLinkedClass, $sDefaultState, $sAttCode);
if ( !($iFlags & OPT_ATT_HIDDEN) && !($iFlags & OPT_ATT_READONLY) )
{
$this->m_aEditableFields[] = $sAttCode;
$this->m_aTableConfig[$sAttCode] = array( 'label' => $oAttDef->GetLabel(), 'description' => $oAttDef->GetDescription());
}
}
$sLnkAttCode = $oLnkAttDef->GetCode();
$this->m_aEditableFields[] = $sLnkAttCode;
$this->m_aTableConfig[$sLnkAttCode] = array('label' => $oLnkAttDef->GetLabel(), 'description' => $oLnkAttDef->GetDescription());
}
$this->m_aTableConfig['static::key'] = array( 'label' => MetaModel::GetName($this->m_sRemoteClass), 'description' => MetaModel::GetClassDescription($this->m_sRemoteClass));
foreach(MetaModel::GetZListItems($this->m_sRemoteClass, 'list') as $sFieldCode)
$this->m_aTableConfig['static::key'] = array(
'label' => MetaModel::GetName($this->m_sRemoteClass),
'description' => MetaModel::GetClassDescription($this->m_sRemoteClass),
);
$this->m_aEditableFields[] = $this->m_sExtKeyToRemote;
$aRemoteAttDefsToDisplay = MetaModel::GetZListAttDefsFilteredForIndirectRemoteClass($this->m_sRemoteClass);
foreach ($aRemoteAttDefsToDisplay as $oRemoteAttDef)
{
// TO DO: check the state of the attribute: hidden or visible ?
if ($sFieldCode != 'finalclass')
{
$oAttDef = MetaModel::GetAttributeDef($this->m_sRemoteClass, $sFieldCode);
$this->m_aTableConfig['static::'.$sFieldCode] = array( 'label' => $oAttDef->GetLabel(), 'description' => $oAttDef->GetDescription());
}
$sRemoteAttCode = $oRemoteAttDef->GetCode();
$this->m_aTableConfig['static::'.$sRemoteAttCode] = array(
'label' => $oRemoteAttDef->GetLabel(),
'description' => $oRemoteAttDef->GetDescription(),
);
}
}
@@ -116,7 +115,7 @@ class UILinksWidget
*
* @param WebPage $oP Web page used for the ouput
* @param DBObject $oLinkedObj Remote object
* @param mixed $linkObjOrId Either the object linked or a unique number for new link records to add
* @param DBObject|int $linkObjOrId Either the lnk object or a unique number for new link records to add
* @param array $aArgs Extra context arguments
* @param DBObject $oCurrentObj The object to which all the elements of the linked set refer to
* @param int $iUniqueId A unique identifier of new links
@@ -134,43 +133,39 @@ class UILinksWidget
$aRow = array();
$aFieldsMap = array();
$iKey = 0;
if(is_object($linkObjOrId) && (!$linkObjOrId->IsNew()))
if (is_object($linkObjOrId) && (!$linkObjOrId->IsNew()))
{
$iKey = $linkObjOrId->GetKey();
$iRemoteObjKey = $linkObjOrId->Get($this->m_sExtKeyToRemote);
$iRemoteObjKey = $linkObjOrId->Get($this->m_sExtKeyToRemote);
$sPrefix .= "[$iKey][";
$sNameSuffix = "]"; // To make a tabular form
$aArgs['prefix'] = $sPrefix;
$aArgs['wizHelper'] = "oWizardHelper{$this->m_iInputId}{$iKey}";
$aArgs['this'] = $linkObjOrId;
if($bReadOnly)
{
$aRow['form::checkbox'] = "";
foreach($this->m_aEditableFields as $sFieldCode)
{
$sDisplayValue = $linkObjOrId->GetEditValue($sFieldCode);
$aRow[$sFieldCode] = $sDisplayValue;
}
}
else
{
$aRow['form::checkbox'] = "<input class=\"selection\" data-remote-id=\"$iRemoteObjKey\" data-link-id=\"$iKey\" data-unique-id=\"$iUniqueId\" type=\"checkbox\" onClick=\"oWidget".$this->m_iInputId.".OnSelectChange();\" value=\"$iKey\">";
foreach($this->m_aEditableFields as $sFieldCode)
{
$sFieldId = $this->m_iInputId.'_'.$sFieldCode.'['.$linkObjOrId->GetKey().']';
$sSafeId = utils::GetSafeId($sFieldId);
$sValue = $linkObjOrId->Get($sFieldCode);
$sDisplayValue = $linkObjOrId->GetEditValue($sFieldCode);
$oAttDef = MetaModel::GetAttributeDef($this->m_sLinkedClass, $sFieldCode);
$aRow[$sFieldCode] = '<div class="field_container" style="border:none;"><div class="field_data"><div class="field_value">'.
cmdbAbstractObject::GetFormElementForField($oP, $this->m_sLinkedClass, $sFieldCode, $oAttDef, $sValue, $sDisplayValue, $sSafeId, $sNameSuffix, 0, $aArgs).
'</div></div></div>';
$aFieldsMap[$sFieldCode] = $sSafeId;
}
}
if ($bReadOnly)
{
$aRow['form::checkbox'] = "";
foreach ($this->m_aEditableFields as $sFieldCode)
{
$sDisplayValue = $linkObjOrId->GetEditValue($sFieldCode);
$aRow[$sFieldCode] = $sDisplayValue;
}
}
else
{
$aRow['form::checkbox'] = "<input class=\"selection\" data-remote-id=\"$iRemoteObjKey\" data-link-id=\"$iKey\" data-unique-id=\"$iUniqueId\" type=\"checkbox\" onClick=\"oWidget".$this->m_iInputId.".OnSelectChange();\" value=\"$iKey\">";
foreach ($this->m_aEditableFields as $sFieldCode)
{
$sSafeFieldId = $this->GetFieldId($linkObjOrId->GetKey(), $sFieldCode);
$this->AddRowForFieldCode($aRow, $sFieldCode, $aArgs, $linkObjOrId, $oP, $sNameSuffix, $sSafeFieldId);
$aFieldsMap[$sFieldCode] = $sSafeFieldId;
}
}
$sState = $linkObjOrId->GetState();
$sRemoteKeySafeFieldId = $this->GetFieldId($aArgs['this']->GetKey(), $this->m_sExtKeyToRemote);;
}
else
{
@@ -180,15 +175,18 @@ class UILinksWidget
// New link existing only in memory
$oNewLinkObj = $linkObjOrId;
$iRemoteObjKey = $oNewLinkObj->Get($this->m_sExtKeyToRemote);
$oNewLinkObj->Set($this->m_sExtKeyToMe, $oCurrentObj); // Setting the extkey with the object also fills the related external fields
$oNewLinkObj->Set($this->m_sExtKeyToMe,
$oCurrentObj); // Setting the extkey with the object also fills the related external fields
}
else
{
$iRemoteObjKey = $linkObjOrId;
$oNewLinkObj = MetaModel::NewObject($this->m_sLinkedClass);
$oRemoteObj = MetaModel::GetObject($this->m_sRemoteClass, $iRemoteObjKey);
$oNewLinkObj->Set($this->m_sExtKeyToRemote, $oRemoteObj); // Setting the extkey with the object alsoo fills the related external fields
$oNewLinkObj->Set($this->m_sExtKeyToMe, $oCurrentObj); // Setting the extkey with the object also fills the related external fields
$oNewLinkObj->Set($this->m_sExtKeyToRemote,
$oRemoteObj); // Setting the extkey with the object alsoo fills the related external fields
$oNewLinkObj->Set($this->m_sExtKeyToMe,
$oCurrentObj); // Setting the extkey with the object also fills the related external fields
}
$sPrefix .= "[-$iUniqueId][";
$sNameSuffix = "]"; // To make a tabular form
@@ -222,112 +220,150 @@ EOF
foreach($this->m_aEditableFields as $sFieldCode)
{
$sFieldId = $this->m_iInputId.'_'.$sFieldCode.'['.-$iUniqueId.']';
$sSafeId = utils::GetSafeId($sFieldId);
$sSafeFieldId = $this->GetFieldId($iUniqueId, $sFieldCode);
$this->AddRowForFieldCode($aRow, $sFieldCode, $aArgs, $oNewLinkObj, $oP, $sNameSuffix, $sSafeFieldId);
$aFieldsMap[$sFieldCode] = $sSafeFieldId;
$sValue = $oNewLinkObj->Get($sFieldCode);
$sDisplayValue = $oNewLinkObj->GetEditValue($sFieldCode);
$oAttDef = MetaModel::GetAttributeDef($this->m_sLinkedClass, $sFieldCode);
$aRow[$sFieldCode] = '<div class="field_container" style="border:none;"><div class="field_data"><div class="field_value">'.
cmdbAbstractObject::GetFormElementForField($oP, $this->m_sLinkedClass, $sFieldCode, $oAttDef, $sValue, $sDisplayValue, $sSafeId /* id */, $sNameSuffix, 0, $aArgs).
'</div></div></div>';
$aFieldsMap[$sFieldCode] = $sSafeId;
$oP->add_ready_script(<<<EOF
$oP->add_ready_script(
<<<JS
oWidget{$this->m_iInputId}.OnValueChange($iKey, $iUniqueId, '$sFieldCode', '$sValue');
EOF
);
JS
);
}
$sState = '';
$sRemoteKeySafeFieldId = $this->GetFieldId($iUniqueId, $this->m_sExtKeyToRemote);
}
if(!$bReadOnly)
{
$sExtKeyToMeId = utils::GetSafeId($sPrefix.$this->m_sExtKeyToMe);
$aFieldsMap[$this->m_sExtKeyToMe] = $sExtKeyToMeId;
$aRow['form::checkbox'] .= "<input type=\"hidden\" id=\"$sExtKeyToMeId\" value=\"".$oCurrentObj->GetKey()."\">";
$sExtKeyToRemoteId = utils::GetSafeId($sPrefix.$this->m_sExtKeyToRemote);
$aFieldsMap[$this->m_sExtKeyToRemote] = $sExtKeyToRemoteId;
$aRow['form::checkbox'] .= "<input type=\"hidden\" id=\"$sExtKeyToRemoteId\" value=\"$iRemoteObjKey\">";
}
$iFieldsCount = count($aFieldsMap);
$sJsonFieldsMap = json_encode($aFieldsMap);
$oP->add_script(
<<<EOF
var {$aArgs['wizHelper']} = new WizardHelper('{$this->m_sLinkedClass}', '', '$sState');
{$aArgs['wizHelper']}.SetFieldsMap($sJsonFieldsMap);
{$aArgs['wizHelper']}.SetFieldsCount($iFieldsCount);
EOF
);
$aRow['static::key'] = $oLinkedObj->GetHyperLink();
foreach(MetaModel::GetZListItems($this->m_sRemoteClass, 'list') as $sFieldCode)
if (!$bReadOnly)
{
$aRow['static::'.$sFieldCode] = $oLinkedObj->GetAsHTML($sFieldCode);
$sExtKeyToMeId = utils::GetSafeId($sPrefix.$this->m_sExtKeyToMe);
$aFieldsMap[$this->m_sExtKeyToMe] = $sExtKeyToMeId;
$aRow['form::checkbox'] .= "<input type=\"hidden\" id=\"$sExtKeyToMeId\" value=\"".$oCurrentObj->GetKey()."\">";
$sExtKeyToRemoteId = utils::GetSafeId($sPrefix.$this->m_sExtKeyToRemote);
$aFieldsMap[$this->m_sExtKeyToRemote] = $sExtKeyToRemoteId;
$aRow['form::checkbox'] .= "<input type=\"hidden\" id=\"$sExtKeyToRemoteId\" value=\"$iRemoteObjKey\">";
}
// Adding fields from remote class
// all fields are embedded in a span + added to $aFieldsMap array so that we can refresh them after extkey change
$aRemoteFieldsMap = [];
foreach (MetaModel::GetZListItems($this->m_sRemoteClass, 'list') as $sFieldCode)
{
$sSafeFieldId = $this->GetFieldId($aArgs['this']->GetKey(), $sFieldCode);
$aRow['static::'.$sFieldCode] = "<span id='field_$sSafeFieldId'>".$oLinkedObj->GetAsHTML($sFieldCode).'</span>';
$aRemoteFieldsMap[$sFieldCode] = $sSafeFieldId;
}
// id field is needed so that remote object could be load server side
$aRemoteFieldsMap['id'] = $sRemoteKeySafeFieldId;
// Generate WizardHelper to update dependant fields
$this->AddWizardHelperInit($oP, $aArgs['wizHelper'], $this->m_sLinkedClass, $sState, $aFieldsMap);
//instantiate specific WizarHelper instance for remote class fields refresh
$bHasExtKeyUpdatingRemoteClassFields = (
array_key_exists('replaceDependenciesByRemoteClassFields', $aArgs)
&& ($aArgs['replaceDependenciesByRemoteClassFields'])
);
if ($bHasExtKeyUpdatingRemoteClassFields)
{
$this->AddWizardHelperInit($oP, $aArgs['wizHelperRemote'], $this->m_sRemoteClass, $sState, $aRemoteFieldsMap);
}
return $aRow;
}
/**
* Display one row of the whole form
* @param WebPage $oP
* @param array $aConfig
* @param array $aRow
* @param int $iRowId
* @return string
*/
protected function DisplayFormRow(WebPage $oP, $aConfig, $aRow, $iRowId)
private function AddRowForFieldCode(&$aRow, $sFieldCode, &$aArgs, $oLnk, $oP, $sNameSuffix, $sSafeFieldId): void
{
$sHtml = '';
$sHtml .= "<tr id=\"{$this->m_sAttCode}{$this->m_sNameSuffix}_row_$iRowId\">\n";
foreach($aConfig as $sName=>$void)
if (($sFieldCode === $this->m_sExtKeyToRemote))
{
$sHtml .= "<td>".$aRow[$sName]."</td>\n";
// current field is the lnk extkey to the remote class
$aArgs['replaceDependenciesByRemoteClassFields'] = true;
$sRowFieldCode = 'static::key';
$aArgs['wizHelperRemote'] = $aArgs['wizHelper'].'_remote';
$aRemoteAttDefs = MetaModel::GetZListAttDefsFilteredForIndirectRemoteClass($this->m_sRemoteClass);
$aRemoteCodes = array_map(
function ($value) {
return $value->GetCode();
},
$aRemoteAttDefs
);
$aArgs['remoteCodes'] = $aRemoteCodes;
}
$sHtml .= "</tr>\n";
return $sHtml;
else
{
$aArgs['replaceDependenciesByRemoteClassFields'] = false;
$sRowFieldCode = $sFieldCode;
}
$sValue = $oLnk->Get($sFieldCode);
$sDisplayValue = $oLnk->GetEditValue($sFieldCode);
$oAttDef = MetaModel::GetAttributeDef($this->m_sLinkedClass, $sFieldCode);
$aRow[$sRowFieldCode] = '<div class="field_container" style="border:none;"><div class="field_data"><div class="field_value">'
.cmdbAbstractObject::GetFormElementForField(
$oP,
$this->m_sLinkedClass,
$sFieldCode,
$oAttDef,
$sValue,
$sDisplayValue,
$sSafeFieldId,
$sNameSuffix,
0,
$aArgs
)
.'</div></div></div>';
}
private function GetFieldId($iLnkId, $sFieldCode, $bSafe = true)
{
$sFieldId = $this->m_iInputId.'_'.$sFieldCode.'['.$iLnkId.']';
return ($bSafe) ? utils::GetSafeId($sFieldId) : $sFieldId;
}
private function AddWizardHelperInit($oP, $sWizardHelperVarName, $sWizardHelperClass, $sState, $aFieldsMap): void
{
$iFieldsCount = count($aFieldsMap);
$sJsonFieldsMap = json_encode($aFieldsMap);
$oP->add_script(
<<<JS
var $sWizardHelperVarName = new WizardHelper('$sWizardHelperClass', '', '$sState');
$sWizardHelperVarName.SetFieldsMap($sJsonFieldsMap);
$sWizardHelperVarName.SetFieldsCount($iFieldsCount);
$sWizardHelperVarName.SetReturnNotEditableFields(true);
$sWizardHelperVarName.SetWizHelperJsVarName('$sWizardHelperVarName');
JS
);
}
/**
* Display the table with the form for editing all the links at once
*
* @param WebPage $oP The web page used for the output
* @param array $aConfig The table's header configuration
* @param array $aData The tabular data to be displayed
*
* @return string Html fragment representing the form table
* @throws \ReflectionException
* @throws \Twig\Error\LoaderError
* @throws \Twig\Error\RuntimeError
* @throws \Twig\Error\SyntaxError
*/
protected function DisplayFormTable(WebPage $oP, $aConfig, $aData)
{
$sHtml = "<input type=\"hidden\" name=\"attr_{$this->m_sAttCode}{$this->m_sNameSuffix}\" value=\"\">";
$sHtml .= "<table class=\"listResults\">\n";
// Header
$sHtml .= "<thead>\n";
$sHtml .= "<tr>\n";
foreach($aConfig as $sName=>$aDef)
$oTable = DataTableFactory::MakeForForm("{$this->m_sAttCode}{$this->m_sNameSuffix}", $aConfig);
foreach ($aData as $iRowId => $aRow)
{
$sHtml .= "<th title=\"".$aDef['description']."\">".$aDef['label']."</th>\n";
}
$sHtml .= "</tr>\n";
$sHtml .= "</thead>\n";
// Content
$sHtml .= "</tbody>\n";
$sEmptyRowStyle = '';
if (count($aData) != 0)
{
$sEmptyRowStyle = 'style="display:none;"';
$oRow = new FormTableRow("{$this->m_sAttCode}{$this->m_sNameSuffix}", $aConfig, $aRow, $iRowId);
$oTable->AddRow($oRow);
}
foreach($aData as $iRowId => $aRow)
{
$sHtml .= $this->DisplayFormRow($oP, $aConfig, $aRow, $iRowId);
}
$sHtml .= "<tr $sEmptyRowStyle id=\"{$this->m_sAttCode}{$this->m_sNameSuffix}_empty_row\"><td colspan=\"".count($aConfig)."\" style=\"text-align:center;\">".Dict::S('UI:Message:EmptyList:UseAdd')."</td></tr>";
$sHtml .= "</tbody>\n";
// Footer
$sHtml .= "</table>\n";
$sHtml = BlockRenderer::RenderBlockTemplates($oTable);
return $sHtml;
}
@@ -360,20 +396,21 @@ EOF
$bDoSearch = !utils::IsHighCardinality($this->m_sRemoteClass);
$sJSDoSearch = $bDoSearch ? 'true' : 'false';
$sWizHelper = 'oWizardHelper'.$sFormPrefix;
$oPage->add_ready_script(<<<EOF
oWidget{$this->m_iInputId} = new LinksWidget('{$this->m_sAttCode}{$this->m_sNameSuffix}', '{$this->m_sClass}', '{$this->m_sAttCode}', '{$this->m_iInputId}', '{$this->m_sNameSuffix}', $sDuplicates, $sWizHelper, '{$this->m_sExtKeyToRemote}', $sJSDoSearch);
oWidget{$this->m_iInputId}.Init();
EOF
$oPage->add_ready_script(<<<JS
oWidget{$this->m_iInputId} = new LinksWidget('{$this->m_sAttCode}{$this->m_sNameSuffix}', '{$this->m_sClass}', '{$this->m_sAttCode}', '{$this->m_iInputId}', '{$this->m_sNameSuffix}', $sDuplicates, $sWizHelper, '{$this->m_sExtKeyToRemote}', $sJSDoSearch);
oWidget{$this->m_iInputId}.Init();
JS
);
while($oCurrentLink = $oValue->Fetch())
while ($oCurrentLink = $oValue->Fetch())
{
// We try to retrieve the remote object as usual
$oLinkedObj = MetaModel::GetObject($this->m_sRemoteClass, $oCurrentLink->Get($this->m_sExtKeyToRemote), false /* Must not be found */);
// We try to retrieve the remote object as usual
$oLinkedObj = MetaModel::GetObject($this->m_sRemoteClass, $oCurrentLink->Get($this->m_sExtKeyToRemote),
false /* Must not be found */);
// If successful, it means that we can edit its link
if($oLinkedObj !== null)
{
$bReadOnly = false;
if ($oLinkedObj !== null)
{
$bReadOnly = false;
}
// Else we retrieve it without restrictions (silos) and will display its link as readonly
else
@@ -393,6 +430,7 @@ EOF
$aForm[$key] = $this->GetFormRow($oPage, $oLinkedObj, $oCurrentLink, $aArgs, $oCurrentObj, $key, $bReadOnly);
}
$sHtmlValue .= $this->DisplayFormTable($oPage, $this->m_aTableConfig, $aForm);
// To prevent adding forms inside the main form
$sHtmlValue .= "<span style=\"float:left;\">&nbsp;&nbsp;&nbsp;<img src=\"../images/tv-item-last.gif\">&nbsp;&nbsp;<input id=\"{$this->m_sAttCode}{$this->m_sNameSuffix}_btnRemove\" type=\"button\" value=\"".Dict::S('UI:RemoveLinkedObjectsOf_Class')."\" onClick=\"oWidget{$this->m_iInputId}.RemoveSelected();\" >";
$sHtmlValue .= "&nbsp;&nbsp;&nbsp;<input id=\"{$this->m_sAttCode}{$this->m_sNameSuffix}_btnAdd\" type=\"button\" value=\"".Dict::Format('UI:AddLinkedObjectsOf_Class', MetaModel::GetName($this->m_sRemoteClass))."\" onClick=\"oWidget{$this->m_iInputId}.AddObjects();\"><span id=\"{$this->m_sAttCode}{$this->m_sNameSuffix}_indicatorAdd\"></span></span>\n";
@@ -443,53 +481,55 @@ EOF
*/
public function GetObjectPickerDialog($oPage, $oCurrentObj, $sJson, $aAlreadyLinkedIds = array(), $aPrefillFormParam = array())
{
$sHtml = "<div class=\"wizContainer\" style=\"vertical-align:top;\">\n";
//$oPage->add("<div class=\"wizContainer\" style=\"vertical-align:top;\">\n");
$oAlreadyLinkedFilter = new DBObjectSearch($this->m_sRemoteClass);
if (!$this->m_bDuplicatesAllowed && count($aAlreadyLinkedIds) > 0)
{
if (!$this->m_bDuplicatesAllowed && count($aAlreadyLinkedIds) > 0) {
$oAlreadyLinkedFilter->AddCondition('id', $aAlreadyLinkedIds, 'NOTIN');
$oAlreadyLinkedExpression = $oAlreadyLinkedFilter->GetCriteria();
$sAlreadyLinkedExpression = $oAlreadyLinkedExpression->Render();
}
else
{
$sAlreadyLinkedExpression = $oAlreadyLinkedExpression->RenderExpression();
} else {
$sAlreadyLinkedExpression = '';
}
$oFilter = new DBObjectSearch($this->m_sRemoteClass);
if(!empty($oCurrentObj))
{
if (!empty($oCurrentObj)) {
$this->SetSearchDefaultFromContext($oCurrentObj, $oFilter);
$aPrefillFormParam['filter'] = $oFilter;
$aPrefillFormParam['dest_class'] = $this->m_sRemoteClass;
$oCurrentObj->PrefillForm('search', $aPrefillFormParam);
}
$oBlock = new DisplayBlock($oFilter, 'search', false);
$sHtml .= $oBlock->GetDisplay($oPage, "SearchFormToAdd_{$this->m_sAttCode}{$this->m_sNameSuffix}",
$oPage->AddUiBlock($oBlock->GetDisplay($oPage, "SearchFormToAdd_{$this->m_sAttCode}{$this->m_sNameSuffix}",
array(
'menu' => false,
'result_list_outer_selector' => "SearchResultsToAdd_{$this->m_sAttCode}{$this->m_sNameSuffix}",
'table_id' => 'add_'.$this->m_sAttCode,
'table_id' => "add_{$this->m_sAttCode}{$this->m_sNameSuffix}",
'table_inner_id' => "ResultsToAdd_{$this->m_sAttCode}{$this->m_sNameSuffix}",
'selection_mode' => true,
'json' => $sJson,
'cssCount' => '#count_'.$this->m_sAttCode.$this->m_sNameSuffix,
'query_params' => $oFilter->GetInternalParams(),
'hidden_criteria' => $sAlreadyLinkedExpression,
));
$sHtml .= "<form id=\"ObjectsAddForm_{$this->m_sAttCode}{$this->m_sNameSuffix}\">\n";
$sHtml .= "<div id=\"SearchResultsToAdd_{$this->m_sAttCode}{$this->m_sNameSuffix}\" style=\"vertical-align:top;background: #fff;height:100%;overflow:auto;padding:0;border:0;\">\n";
$sHtml .= "<div style=\"background: #fff; border:0; text-align:center; vertical-align:middle;\"><p>".Dict::S('UI:Message:EmptyList:UseSearchForm')."</p></div>\n";
$sHtml .= "</div>\n";
$sHtml .= "<input type=\"hidden\" id=\"count_{$this->m_sAttCode}{$this->m_sNameSuffix}\" value=\"0\"/>";
$sHtml .= "<input type=\"button\" value=\"".Dict::S('UI:Button:Cancel')."\" onClick=\"$('#dlg_{$this->m_sAttCode}{$this->m_sNameSuffix}').dialog('close');\">&nbsp;&nbsp;<input id=\"btn_ok_{$this->m_sAttCode}{$this->m_sNameSuffix}\" disabled=\"disabled\" type=\"button\" onclick=\"return oWidget{$this->m_iInputId}.DoAddObjects(this.id);\" value=\"".Dict::S('UI:Button:Add')."\">";
$sHtml .= "</div>\n";
$sHtml .= "</form>\n";
$oPage->add($sHtml);
$oPage->add_ready_script("$('#dlg_{$this->m_sAttCode}{$this->m_sNameSuffix}').dialog({ width: $(window).width()*0.8, height: $(window).height()*0.8, autoOpen: false, modal: true, resizeStop: oWidget{$this->m_iInputId}.UpdateSizes });");
$oPage->add_ready_script("$('#dlg_{$this->m_sAttCode}{$this->m_sNameSuffix}').dialog('option', {title:'".addslashes(Dict::Format('UI:AddObjectsOf_Class_LinkedWith_Class', MetaModel::GetName($this->m_sLinkedClass), MetaModel::GetName($this->m_sClass)))."'});");
)));
$sEmptyList = Dict::S('UI:Message:EmptyList:UseSearchForm');
$sCancel = Dict::S('UI:Button:Cancel');
$sAdd = Dict::S('UI:Button:Add');
$oPage->add(<<<HTML
<form id="ObjectsAddForm_{$this->m_sAttCode}{$this->m_sNameSuffix}">
<div id="SearchResultsToAdd_{$this->m_sAttCode}{$this->m_sNameSuffix}" style="vertical-align:top;background: #fff;height:100%;overflow:auto;padding:0;border:0;">
<div style="background: #fff; border:0; text-align:center; vertical-align:middle;"><p>{$sEmptyList}</p></div>
</div>
<input type="hidden" id="count_{$this->m_sAttCode}{$this->m_sNameSuffix}" value="0"/>
<input type="button" value="{$sCancel}" onClick="$('#dlg_{$this->m_sAttCode}{$this->m_sNameSuffix}').dialog('close');">&nbsp;&nbsp;
<input id="btn_ok_add_{$this->m_sAttCode}{$this->m_sNameSuffix}" disabled="disabled" type="button" onclick="return oWidget{$this->m_iInputId}.DoAddObjects(this.id);" value="{$sAdd}">
</form>
HTML
);
$oPage->add_ready_script("$('#dlg_{$this->m_sAttCode}{$this->m_sNameSuffix}').dialog({ width: $(window).width()*0.8, height: $(window).height()*0.8, title:'".addslashes(Dict::Format('UI:AddObjectsOf_Class_LinkedWith_Class', MetaModel::GetName($this->m_sLinkedClass), MetaModel::GetName($this->m_sClass)))."' , autoOpen: false, modal: true, resizeStop: oWidget{$this->m_iInputId}.UpdateSizes });");
$oPage->add_ready_script("$('#SearchFormToAdd_{$this->m_sAttCode}{$this->m_sNameSuffix} form').bind('submit.uilinksWizard', oWidget{$this->m_iInputId}.SearchObjectsToAdd);");
$oPage->add_ready_script("$('#SearchFormToAdd_{$this->m_sAttCode}{$this->m_sNameSuffix}').resize(oWidget{$this->m_iInputId}.UpdateSizes);");
}
@@ -547,7 +587,8 @@ EOF
if (is_object($oLinkedObj))
{
$aRow = $this->GetFormRow($oP, $oLinkedObj, $iObjectId, array(), $oCurrentObj, $iAdditionId); // Not yet created link get negative Ids
$oP->add($this->DisplayFormRow($oP, $this->m_aTableConfig, $aRow, -$iAdditionId));
$oRow = new FormTableRow("{$this->m_sAttCode}{$this->m_sNameSuffix}", $this->m_aTableConfig, $aRow, -$iAdditionId);
$oP->AddUiBlock($oRow);
$iAdditionId++;
}
else

View File

@@ -24,7 +24,6 @@
* @license http://opensource.org/licenses/AGPL-3.0
*/
require_once(APPROOT.'/application/webpage.class.inc.php');
require_once(APPROOT.'/application/displayblock.class.inc.php');
class UIPasswordWidget
@@ -66,7 +65,7 @@ class UIPasswordWidget
$sHtmlValue .= '<input type="hidden" id="'.$this->iId.'_changed" name="attr_'.$sCode.'[changed]" value="'.$sChangedValue.'"/>';
$sHtmlValue .= '</div>';
$sHtmlValue .= '<span class="form_validation" id="v_'.$this->iId.'"></span><span class="field_status" id="fstatus_'.$this->iId.'"></span>';
$sHtmlValue .= '<span class="form_validation ibo-field-validation" id="v_'.$this->iId.'"></span><span class="field_status" id="fstatus_'.$this->iId.'"></span>';
$oPage->add_ready_script("$('#$this->iId').bind('keyup change', function(evt) { return PasswordFieldChanged('$this->iId') } );"); // Bind to a custom event: validate
$oPage->add_ready_script("$('#$this->iId').bind('keyup change validate', function(evt, sFormId) { return ValidatePasswordField('$this->iId', sFormId) } );"); // Bind to a custom event: validate

View File

@@ -21,7 +21,6 @@
*/
require_once(APPROOT.'/application/webpage.class.inc.php');
require_once(APPROOT.'/application/displayblock.class.inc.php');
class UISearchFormForeignKeys
@@ -41,12 +40,11 @@ class UISearchFormForeignKeys
*/
public function ShowModalSearchForeignKeys($oPage, $sTitle)
{
$sHtml = "<div class=\"wizContainer\" style=\"vertical-align:top;\">\n";
$oFilter = new DBObjectSearch($this->m_sRemoteClass);
$oBlock = new DisplayBlock($oFilter, 'search', false);
$sHtml .= $oBlock->GetDisplay($oPage, "SearchFormToAdd_{$this->m_iInputId}",
$oPage->AddUiBlock($oBlock->GetDisplay($oPage, "SearchFormToAdd_{$this->m_iInputId}",
array(
'menu' => false,
'result_list_outer_selector' => "SearchResultsToAdd_{$this->m_iInputId}",
@@ -55,16 +53,23 @@ class UISearchFormForeignKeys
'selection_mode' => true,
'cssCount' => "#count_{$this->m_iInputId}",
'query_params' => $oFilter->GetInternalParams(),
));
$sHtml .= "<form id=\"ObjectsAddForm_{$this->m_iInputId}\">\n";
$sHtml .= "<div id=\"SearchResultsToAdd_{$this->m_iInputId}\" style=\"vertical-align:top;background: #fff;height:100%;overflow:auto;padding:0;border:0;\">\n";
$sHtml .= "<div style=\"background: #fff; border:0; text-align:center; vertical-align:middle;\"><p>".Dict::S('UI:Message:EmptyList:UseSearchForm')."</p></div>\n";
$sHtml .= "</div>\n";
$sHtml .= "<input type=\"hidden\" id=\"count_{$this->m_iInputId}\" value=\"0\"/>";
$sHtml .= "<input type=\"button\" value=\"".Dict::S('UI:Button:Cancel')."\" onClick=\"$('#dlg_{$this->m_iInputId}').dialog('close');\">&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);
)));
$sEmptyList = Dict::S('UI:Message:EmptyList:UseSearchForm');
$sCancel = Dict::S('UI:Button:Cancel');
$sAdd = Dict::S('UI:Button:Add');
$oPage->add(<<<HTML
<form id="ObjectsAddForm_{$this->m_iInputId}">
<div id="SearchResultsToAdd_{$this->m_iInputId}" style="vertical-align:top;background: #fff;height:100%;overflow:auto;padding:0;border:0;">
<div style="background: #fff; border:0; text-align:center; vertical-align:middle;"><p>{$sEmptyList}</p></div>
</div>
<input type="hidden" id="count_{$this->m_iInputId}" value="0"/>
<input type="button" value="{$sCancel}" onClick="$('#dlg_{$this->m_iInputId}').dialog('close');">&nbsp;&nbsp;
<input id="btn_ok_add_{$this->m_iInputId}" disabled="disabled" type="button" onclick="return oForeignKeysWidget{$this->m_iInputId}.DoAddObjects(this.id);" value="{$sAdd}">
</form>
HTML
);
$oPage->add_ready_script("$('#dlg_{$this->m_iInputId}').dialog({ width: $(window).width()*0.8, height: $(window).height()*0.8, autoOpen: false, modal: true, resizeStop: oForeignKeysWidget{$this->m_iInputId}.UpdateSizes });");
$oPage->add_ready_script("$('#dlg_{$this->m_iInputId}').dialog('option', {title:'$sTitle'});");
$oPage->add_ready_script("$('#SearchFormToAdd_{$this->m_iInputId} form').bind('submit.uilinksWizard', oForeignKeysWidget{$this->m_iInputId}.SearchObjectsToAdd);");
@@ -112,4 +117,4 @@ class UISearchFormForeignKeys
array('menu' => false, 'cssCount' => "#count_{$this->m_iInputId}", 'selection_mode' => true, 'table_id' => "add_{$this->m_iInputId}"));
}
}
}

View File

@@ -34,16 +34,21 @@ require_once(APPROOT.'/core/userrights.class.inc.php');
*/
class appUserPreferences extends DBObject
{
static $oUserPrefs = null; // Local cache
private static $oUserPrefs = null; // Local cache
/**
* Get the value of the given property/preference
* If not set, the default value will be returned
*
* @param string $sCode Code/Name of the property to set
* @param string $sDefaultValue The default value
* @return string The value of the property for the current user
* @param mixed $defaultValue The default value
*
* @return mixed The value of the property for the current user
* @throws \CoreException
* @throws \CoreUnexpectedValue
* @throws \MySQLException
*/
static function GetPref($sCode, $sDefaultValue)
public static function GetPref($sCode, $defaultValue)
{
if (self::$oUserPrefs == null)
{
@@ -56,40 +61,52 @@ class appUserPreferences extends DBObject
}
else
{
return $sDefaultValue;
return $defaultValue;
}
}
/**
* Set the value for a given preference, and stores it into the database
*
* @param string $sCode Code/Name of the property/preference to set
* @param string $sValue Value to set
* @param mixed $value Value to set
*
* @return void
* @throws \CoreException
* @throws \CoreUnexpectedValue
* @throws \MySQLException
*/
static function SetPref($sCode, $sValue)
public static function SetPref($sCode, $value)
{
if (self::$oUserPrefs == null)
{
self::Load();
}
$aPrefs = self::$oUserPrefs->Get('preferences');
if (array_key_exists($sCode, $aPrefs) && ($aPrefs[$sCode] === $sValue))
if (array_key_exists($sCode, $aPrefs) && ($aPrefs[$sCode] === $value))
{
// Do not write it again
}
else
{
$aPrefs[$sCode] = $sValue;
$aPrefs[$sCode] = $value;
self::$oUserPrefs->Set('preferences', $aPrefs);
self::Save();
}
}
/**
* Clears the value for a given preference (or list of preferences that matches a pattern), and updates the database
* @param string $sPattern Code/Pattern of the properties/preferences to reset
*
* @param string $sCodeOrPattern Code/Pattern of the properties/preferences to reset
* @param boolean $bPattern Whether or not the supplied code is a PCRE pattern
*
* @return void
* @throws \CoreException
* @throws \CoreUnexpectedValue
* @throws \MySQLException
*/
static function UnsetPref($sCodeOrPattern, $bPattern = false)
public static function UnsetPref($sCodeOrPattern, $bPattern = false)
{
if (self::$oUserPrefs == null)
{
@@ -119,12 +136,16 @@ class appUserPreferences extends DBObject
self::Save();
}
}
/**
* Call this function to get all the preferences for the user, packed as a JSON object
*
* @return string JSON representation of the preferences
* @throws \CoreException
* @throws \CoreUnexpectedValue
* @throws \MySQLException
*/
static function GetAsJSON()
public static function GetAsJSON()
{
if (self::$oUserPrefs == null)
{
@@ -136,20 +157,30 @@ class appUserPreferences extends DBObject
/**
* Call this function if the user has changed (like when doing a logoff...)
*
* @return void
*/
static public function ResetPreferences()
public static function ResetPreferences()
{
self::$oUserPrefs = null;
}
/**
* Call this function to ERASE all the preferences from the current user
*
* @return void
*/
static public function ClearPreferences()
public static function ClearPreferences()
{
self::$oUserPrefs = null;
}
static protected function Save()
/**
* Save preferences in the DB
*
* @return void;
*/
protected static function Save()
{
if (self::$oUserPrefs != null)
{
@@ -161,12 +192,17 @@ class appUserPreferences extends DBObject
}
}
}
/**
* Loads the preferences for the current user, creating the record in the database
* if needed
*
* @return void;
* @throws \CoreException
* @throws \CoreUnexpectedValue
* @throws \MySQLException
*/
static protected function Load()
protected static function Load()
{
if (self::$oUserPrefs != null) return;
$oSearch = new DBObjectSearch('appUserPreferences');
@@ -193,6 +229,9 @@ class appUserPreferences extends DBObject
self::$oUserPrefs = $oObj;
}
/**
* @throws \CoreException
*/
public static function Init()
{
$aParams = array
@@ -213,9 +252,22 @@ class appUserPreferences extends DBObject
}
/**
* Overloading this function here to secure a fix done right before the release
* The real fix should be to implement this verb in DBObject
*/
* Overloading this function here to secure a fix done right before the release
* The real fix should be to implement this verb in DBObject
*
* @param \CMDBChange $oChange
* @param bool|null $bSkipStrongSecurity
* @param \DeletionPlan|null $oDeletionPlan
*
* @throws \ArchivedObjectException
* @throws \CoreCannotSaveObjectException
* @throws \CoreException
* @throws \CoreUnexpectedValue
* @throws \DeleteException
* @throws \MySQLException
* @throws \MySQLHasGoneAwayException
* @throws \OQLException
*/
public function DBDeleteTracked(CMDBChange $oChange, $bSkipStrongSecurity = null, &$oDeletionPlan = null)
{
utils::PushArchiveMode(false);

View File

@@ -44,6 +44,57 @@ class FileUploadException extends Exception
*/
class utils
{
/**
* @var string
* @since 3.0.0
*/
public const ENUM_SANITIZATION_FILTER_INTEGER = 'integer';
/**
* @var string
* @since 3.0.0
*/
public const ENUM_SANITIZATION_FILTER_CLASS = 'class';
/**
* @var string
* @since 3.0.0
*/
public const ENUM_SANITIZATION_FILTER_STRING = 'string';
/**
* @var string
* @since 3.0.0
*/
public const ENUM_SANITIZATION_FILTER_CONTEXT_PARAM = 'context_param';
/**
* @var string
* @since 3.0.0
*/
public const ENUM_SANITIZATION_FILTER_PARAMETER = 'parameter';
/**
* @var string
* @since 3.0.0
*/
public const ENUM_SANITIZATION_FILTER_FIELD_NAME = 'field_name';
/**
* @var string
* @since 3.0.0
*/
public const ENUM_SANITIZATION_FILTER_TRANSACTION_ID = 'transaction_id';
/**
* @var string For XML / HTML node identifiers
* @since 3.0.0
*/
public const ENUM_SANITIZATION_FILTER_ELEMENT_IDENTIFIER = 'element_identifier';
/**
* @var string
* @since 3.0.0
*/
public const ENUM_SANITIZATION_FILTER_RAW_DATA = 'raw_data';
/**
* @var string
* @since 3.0.0
*/
public const DEFAULT_SANITIZATION_FILTER = self::ENUM_SANITIZATION_FILTER_RAW_DATA;
/**
* Cache when getting config from disk or set externally (using {@link SetConfig})
* @internal
@@ -275,37 +326,40 @@ class utils
/**
* @param string|string[] $value
* @param string $sSanitizationFilter one of : integer, class, string, context_param, parameter, field_name,
* transaction_id, parameter, raw_data
* element_identifier, transaction_id, parameter, raw_data
*
* @return string|string[]|bool boolean for :
* * the 'class' filter (true if valid, false otherwise)
* * if the filter fails (@see \filter_var())
*
* @since 2.5.2 2.6.0 new 'transaction_id' filter
* @since 2.7.0 new 'element_identifier' filter
*
* @throws \CoreException
*/
protected static function Sanitize_Internal($value, $sSanitizationFilter)
{
switch ($sSanitizationFilter)
{
case 'integer':
case static::ENUM_SANITIZATION_FILTER_INTEGER:
$retValue = filter_var($value, FILTER_SANITIZE_NUMBER_INT);
break;
case 'class':
case static::ENUM_SANITIZATION_FILTER_CLASS:
$retValue = $value;
if (!MetaModel::IsValidClass($value))
{
$retValue = false;
if (($value != '') && !MetaModel::IsValidClass($value)) {
throw new CoreException(Dict::Format('UI:OQL:UnknownClassNoFix', utils::HtmlEntities($value)));
}
break;
case 'string':
case static::ENUM_SANITIZATION_FILTER_STRING:
$retValue = filter_var($value, FILTER_SANITIZE_SPECIAL_CHARS);
break;
case 'context_param':
case 'parameter':
case 'field_name':
case static::ENUM_SANITIZATION_FILTER_CONTEXT_PARAM:
case static::ENUM_SANITIZATION_FILTER_PARAMETER:
case static::ENUM_SANITIZATION_FILTER_FIELD_NAME:
case static::ENUM_SANITIZATION_FILTER_TRANSACTION_ID:
if (is_array($value))
{
$retValue = array();
@@ -323,7 +377,7 @@ class utils
{
switch ($sSanitizationFilter)
{
case 'transaction_id':
case static::ENUM_SANITIZATION_FILTER_TRANSACTION_ID:
// same as parameter type but keep the dot character
// see N°1835 : when using file transaction_id on Windows you get *.tmp tokens
// it must be included at the regexp beginning otherwise you'll get an invalid character error
@@ -331,18 +385,18 @@ class utils
array("options" => array("regexp" => '/^[\. A-Za-z0-9_=-]*$/')));
break;
case 'parameter':
case static::ENUM_SANITIZATION_FILTER_PARAMETER:
$retValue = filter_var($value, FILTER_VALIDATE_REGEXP,
array("options" => array("regexp" => '/^[ A-Za-z0-9_=-]*$/'))); // the '=', '%3D, '%2B', '%2F'
// characters are used in serialized filters (starting 2.5, only the url encoded versions are presents, but the "=" is kept for BC)
break;
case 'field_name':
case static::ENUM_SANITIZATION_FILTER_FIELD_NAME:
$retValue = filter_var($value, FILTER_VALIDATE_REGEXP,
array("options" => array("regexp" => '/^[A-Za-z0-9_]+(->[A-Za-z0-9_]+)*$/'))); // att_code or att_code->name or AttCode->Name or AttCode->Key2->Name
break;
case 'context_param':
case static::ENUM_SANITIZATION_FILTER_CONTEXT_PARAM:
$retValue = filter_var($value, FILTER_VALIDATE_REGEXP,
array("options" => array("regexp" => '/^[ A-Za-z0-9_=%:+-]*$/')));
break;
@@ -351,8 +405,12 @@ class utils
}
break;
case static::ENUM_SANITIZATION_FILTER_ELEMENT_IDENTIFIER:
$retValue = preg_replace('/[^a-zA-Z0-9_-]/', '', $value);
break;
default:
case 'raw_data':
case static::ENUM_SANITIZATION_FILTER_RAW_DATA:
$retValue = $value;
// Do nothing
}
@@ -485,6 +543,18 @@ class utils
// Paginated selection
$aSelectedIds = utils::ReadParam('storedSelection', array());
$aSelectedObjIds = utils::ReadParam('selectObject', array());
//it means that the user has selected all the results of the search query
if (count($aSelectedObjIds) > 0 )
{
$sFilter=utils::ReadParam("sFilter",'',false,'raw_data');
if ($sFilter!='')
{
$oFullSetFilter=DBSearch::unserialize($sFilter);
}
}
if (count($aSelectedIds) > 0 )
{
if ($sSelectionMode == 'positive')
@@ -748,19 +818,22 @@ class utils
return new Config();
}
public static function InitTimeZone() {
$oConfig = self::GetConfig();
public static function InitTimeZone($oConfig = null)
{
if (is_null($oConfig))
{
$oConfig = self::GetConfig();
}
$sItopTimeZone = $oConfig->Get('timezone');
if (!empty($sItopTimeZone))
{
date_default_timezone_set($sItopTimeZone);
}
else
{
// Leave as is... up to the admin to set a value somewhere...
// see http://php.net/manual/en/datetime.configuration.php#ini.date.timezone
}
// else
// {
// // Leave as is... up to the admin to set a value somewhere...
// // see http://php.net/manual/en/datetime.configuration.php#ini.date.timezone
// }
}
/**
@@ -889,6 +962,28 @@ class utils
return $sAppRootUrl;
}
/**
* Return the complete revision number of the application
*
* @return string
* @since 3.0.0
*/
public static function GetAppRevisionNumber()
{
if (ITOP_REVISION == 'svn')
{
// This is NOT a version built using the build system, just display the main version
$sRevisionNumber = Dict::Format('UI:iTopVersion:Short', ITOP_APPLICATION, ITOP_VERSION);
}
else
{
// This is a build made from SVN, let display the full information
$sRevisionNumber = Dict::Format('UI:iTopVersion:Long', ITOP_APPLICATION, ITOP_VERSION, ITOP_REVISION, ITOP_BUILD_DATE);
}
return $sRevisionNumber;
}
/**
* Helper to handle the variety of HTTP servers
* See N°286 (fixed in [896]), and N°634 (this fix)
@@ -922,16 +1017,11 @@ class utils
/**
* Get the _SESSION variable for logging purpose
* @return false|string
* @return string
*/
public static function GetSessionLog()
{
ob_start();
print_r($_SESSION);
$sSessionLog = ob_get_contents();
ob_end_clean();
return $sSessionLog;
return print_r($_SESSION, true);
}
static function DebugBacktrace($iLimit = 5)
@@ -975,19 +1065,19 @@ class utils
throw new Exception("The path to php must not be empty. Please set a value for 'php_path' in your configuration file.");
}
$sAuthUser = self::ReadParam('auth_user', '', 'raw_data');
$sAuthPwd = self::ReadParam('auth_pwd', '', 'raw_data');
$sParamFile = self::GetParamSourceFile('auth_user');
if (is_null($sParamFile))
{
if (!isset($aArguments['auth_user'])) {
$sAuthUser = self::ReadParam('auth_user', '', 'raw_data');
$aArguments['auth_user'] = $sAuthUser;
}
if (!isset($aArguments['auth_pwd'])) {
$sAuthPwd = self::ReadParam('auth_pwd', '', 'raw_data');
$aArguments['auth_pwd'] = $sAuthPwd;
}
else
{
if (!isset($aArguments['param_file'])) {
$sParamFile = self::ReadParam('param_file', '', 'raw_data');
$aArguments['param_file'] = $sParamFile;
}
$aArgs = array();
foreach($aArguments as $sName => $value)
{
@@ -1139,6 +1229,7 @@ class utils
new JSPopupMenuItem('UI:Menu:ExportXLSX', Dict::S('ExcelExporter:ExportMenu'), "ExportListDlg('$sOQL', '', 'xlsx', ".json_encode(Dict::S('ExcelExporter:ExportMenu')).")"),
new SeparatorPopupMenuItem(),
new URLPopupMenuItem('UI:Menu:PrintableVersion', Dict::S('UI:Menu:PrintableVersion'), $sUrl.'&printable=1', '_blank'),
new JSPopupMenuItem('UI:Menu:SwitchTabMode', Dict::S('UI:Menu:SwitchTabMode'), "SwitchTabMode()"),
);
break;
@@ -1369,13 +1460,12 @@ class utils
// For instance fopen does not allow to work around the bug: http://stackoverflow.com/questions/18191672/php-curl-ssl-routinesssl23-get-server-helloreason1112
// by setting the SSLVERSION to 3 as done below.
$aHeaders = explode("\n", $sOptionnalHeaders);
// N°3267 - Webservices: Fix optional headers not being taken into account
// See https://www.php.net/curl_setopt CURLOPT_HTTPHEADER
$aHTTPHeaders = array();
foreach($aHeaders as $sHeaderString)
{
if(preg_match('/^([^:]): (.+)$/', $sHeaderString, $aMatches))
{
$aHTTPHeaders[$aMatches[1]] = $aMatches[2];
}
$aHTTPHeaders[] = trim($sHeaderString);
}
// Default options, can be overloaded/extended with the 4th parameter of this method, see above $aCurlOptions
$aOptions = array(
@@ -1505,6 +1595,17 @@ class utils
public static function HtmlEntities($sValue)
{
return htmlentities($sValue, ENT_QUOTES, 'UTF-8');
}
/**
* Helper to encapsulation iTop's html_entity_decode
* @param string $sValue
* @return string
* @since 2.7.0
*/
public static function HtmlEntityDecode($sValue)
{
return html_entity_decode($sValue, ENT_QUOTES, 'UTF-8');
}
/**
@@ -1596,7 +1697,7 @@ class utils
set_time_limit(0);
// Compiling SASS
$sCss = $oSass->compile($sSassContent);
set_time_limit($iCurrentMaxExecTime);
set_time_limit(intval($iCurrentMaxExecTime));
return $sCss;
}
@@ -2052,13 +2153,53 @@ class utils
*/
public static function GetCacheBusterTimestamp()
{
if(!defined('COMPILATION_TIMESTAMP'))
{
if (!defined('COMPILATION_TIMESTAMP')) {
return ITOP_VERSION;
}
return COMPILATION_TIMESTAMP;
}
/**
* @return string eg : '2_7_0' ITOP_VERSION is '2.7.1-dev'
*/
public static function GetItopVersionWikiSyntax() {
$sMinorVersion = self::GetItopMinorVersion();
return str_replace('.', '_', $sMinorVersion).'_0';
}
/**
* @param string $sPatchVersion if non provided, will call GetItopPatchVersion
*
* @return string eg 2.7 if ITOP_VERSION is '2.7.0-dev'
* @throws \Exception
*/
public static function GetItopMinorVersion($sPatchVersion = null) {
if (is_null($sPatchVersion)) {
$sPatchVersion = self::GetItopPatchVersion();
}
$aExplodedVersion = explode('.', $sPatchVersion);
if (count($aExplodedVersion) < 2) {
throw new Exception('iTop version is wrongfully configured!');
}
if (($aExplodedVersion[0] == '') || ($aExplodedVersion[1] == '')) {
throw new Exception('iTop version is wrongfully configured!');
}
return sprintf('%d.%d', $aExplodedVersion[0], $aExplodedVersion[1]);
}
/**
* @return string eg '2.7.0' if ITOP_VERSION is '2.7.0-dev'
*/
public static function GetItopPatchVersion() {
$aExplodedVersion = explode('-', ITOP_VERSION);
return $aExplodedVersion[0];
}
/**
* Check if the given class if configured as a high cardinality class.
*
@@ -2088,6 +2229,18 @@ class utils
return ITOP_REVISION === 'svn';
}
/**
* Check if debug is enabled in the current environment.
* Currently just checking if the "debug=true" parameter is in the URL, but could be more complex.
*
* @return bool
* @since 3.0.0
*/
public static function IsDebugEnabled()
{
return utils::ReadParam('debug') === 'true';
}
/**
* @see https://php.net/manual/en/function.finfo-file.php
*
@@ -2159,13 +2312,13 @@ class utils
* @param string $sPath for example '/var/www/html/itop/data/backups/manual/itop_27-2019-10-03_15_35.tar.gz'
* @param string $sBasePath for example '/var/www/html/itop/data/'
*
* @return bool false if path :
* @return bool|string false if path :
* * invalid
* * not allowed
* * not contained in base path
* Otherwise return the real path (see realpath())
*
* @since 2.7.0 N°2538
* @since 2.6.5 2.7.0 N°2538
*/
final public static function RealPath($sPath, $sBasePath)
{
@@ -2250,4 +2403,38 @@ class utils
{
return str_replace(' ', '', ucwords(strtr($sInput, '_-', ' ')));
}
public static function FilterXSS($sHTML)
{
return str_ireplace('<script', '&lt;script', $sHTML);
}
/**
* @param \cmdbAbstractObject $oCmdbAbstract
* @param \Exception $oException
*
* @throws \Exception
* @since 2.7.2/ 3.0.0
*/
public static function EnrichRaisedException($oCmdbAbstract, $oException)
{
if (is_null($oCmdbAbstract) ||
! is_a($oCmdbAbstract, \cmdbAbstractObject::class))
{
throw $oException;
}
$sCmdbAbstractInfo = str_replace("\n", '', "" . $oCmdbAbstract);
$sMessage = $oException->getMessage() . " (" . $sCmdbAbstractInfo . ")";
$e = new CoreException($sMessage, null, '', $oException);
throw $e;
}
/**
* @since 3.0.0
*/
public static function IsEasterEggAllowed(){
return (stripos(ITOP_VERSION, 'alpha') !== false) || utils::IsDevelopmentEnvironment();
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -335,20 +335,41 @@ class WizardHelper
{
$sResult = $this->m_aData['m_oFieldsMap'][$sFieldName];
}
return $sResult;
}
public function GetReturnNotEditableFields()
{
return $this->m_aData['m_bReturnNotEditableFields'] ?? false;
}
/**
* @return string JS code to be executed for fields update
* @since 3.0.0 N°3198
*/
public function GetJsForUpdateFields()
{
$sWizardHelperJsVar = ($this->m_aData['m_sWizHelperJsVarName']) ?? 'oWizardHelper'.$this->GetFormPrefix();
$sWizardHelperJson = $this->ToJSON();
return <<<JS
{$sWizardHelperJsVar}.m_oData = {$sWizardHelperJson};
{$sWizardHelperJsVar}.UpdateFields();
JS;
}
static function ParseJsonSet($oMe, $sLinkClass, $sExtKeyToMe, $sJsonSet)
{
$aSet = json_decode($sJsonSet, true); // true means hash array instead of object
$oSet = CMDBObjectSet::FromScratch($sLinkClass);
foreach($aSet as $aLinkObj)
foreach ($aSet as $aLinkObj)
{
$oLink = MetaModel::NewObject($sLinkClass);
foreach($aLinkObj as $sAttCode => $value)
foreach ($aLinkObj as $sAttCode => $value)
{
$oAttDef = MetaModel::GetAttributeDef($sLinkClass, $sAttCode);
if (($oAttDef->IsExternalKey()) && ($value != '') && ($value > 0))
if (($oAttDef->IsExternalKey()) && ($value != '') && ($value > 0))
{
// For external keys: load the target object so that external fields
// get filled too

View File

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

View File

@@ -1,7 +1,7 @@
<?php
/**
* Copyright (C) 2013-2019 Combodo SARL
* Copyright (C) 2013-2020 Combodo SARL
*
* This file is part of iTop.
*
@@ -18,16 +18,31 @@
* You should have received a copy of the GNU Affero General Public License
*/
/**
* Checks PHP version
*
* This is a hard-coded check that limits errors : we are stopping for anything < PHP 7.0.0
* The "real one" will be done in {@link \SetupUtils::CheckPhpVersion()}
*
* @since 3.0.0 N°2214
*/
$bIsValidPhpVersion = false;
if (PHP_MAJOR_VERSION >= 7) {
$bIsValidPhpVersion = true;
} else {
echo 'Your PHP version ('.PHP_VERSION.') isn\'t supported.';
exit(-1);
}
define('ITOP_DEFAULT_ENV', 'production');
define('MAINTENANCE_MODE_FILE', APPROOT.'data/.maintenance');
define('READONLY_MODE_FILE', APPROOT.'data/.readonly');
if (function_exists('microtime'))
{
if (function_exists('microtime')) {
$fItopStarted = microtime(true);
}
else
{
} else {
$fItopStarted = 1000 * time();
}

View File

@@ -2,7 +2,7 @@
"type": "project",
"license": "AGPLv3",
"require": {
"php": ">=5.6.0",
"php": ">=7.1.3",
"ext-ctype": "*",
"ext-dom": "*",
"ext-gd": "*",
@@ -10,9 +10,9 @@
"ext-json": "*",
"ext-mysqli": "*",
"ext-soap": "*",
"combodo/tcpdf": "6.3.2",
"combodo/tcpdf": "6.3.5",
"nikic/php-parser": "^3.1",
"pear/archive_tar": "1.4.9",
"pear/archive_tar": "1.4.10",
"pelago/emogrifier": "2.1.0",
"scssphp/scssphp": "1.0.6",
"swiftmailer/swiftmailer": "5.4.12",
@@ -37,7 +37,7 @@
},
"config": {
"platform": {
"php": "5.6.0"
"php": "7.2.0"
},
"vendor-dir": "lib",
"preferred-install": {
@@ -50,7 +50,11 @@
"classmap": [
"core",
"application",
"sources/application"
"sources/application",
"sources/Composer",
"sources/Controller",
"sources/Form",
"sources/Renderer"
],
"exclude-from-classmap": [
"core/dbobjectsearch.class.php",
@@ -59,6 +63,7 @@
"core/legacy/querybuildercontextlegacy.class.inc.php",
"core/querybuilderexpressions.class.inc.php",
"core/legacy/querybuilderexpressionslegacy.class.inc.php",
"application/startup.inc.php",
"application/loginform.class.inc.php",
"application/loginbasic.class.inc.php",
"application/logindefault.class.inc.php",
@@ -74,5 +79,10 @@
"allow-contrib": false,
"require": "3.4.*"
}
},
"scripts": {
"post-install-cmd": ["@rmDeniedTestDir"],
"post-update-cmd": ["@rmDeniedTestDir"],
"rmDeniedTestDir": "@php .make/composer/rmDeniedTestDir.php"
}
}

29
composer.lock generated
View File

@@ -4,20 +4,20 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "3e413c47265b246174add07c2c91b5e9",
"content-hash": "27af144ea2acf2c138f587052a4ceddc",
"packages": [
{
"name": "combodo/tcpdf",
"version": "6.3.2",
"version": "6.3.5",
"source": {
"type": "git",
"url": "https://github.com/combodo-itop-libs/TCPDF.git",
"reference": "2723050de47c8cbd78293656d896c0000442e23a"
"reference": "aedd4b7b8cf7fcc24e617c405c9d3304150f4b94"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/combodo-itop-libs/TCPDF/zipball/2723050de47c8cbd78293656d896c0000442e23a",
"reference": "2723050de47c8cbd78293656d896c0000442e23a",
"url": "https://api.github.com/repos/combodo-itop-libs/TCPDF/zipball/aedd4b7b8cf7fcc24e617c405c9d3304150f4b94",
"reference": "aedd4b7b8cf7fcc24e617c405c9d3304150f4b94",
"shasum": ""
},
"require": {
@@ -49,9 +49,14 @@
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"LGPL-3.0"
"LGPL-3.0-only"
],
"authors": [
{
"name": "Nicola Asuni",
"email": "info@tecnick.com",
"role": "lead"
},
{
"name": "Combodo",
"email": "contact@combodo.com"
@@ -59,7 +64,7 @@
],
"description": "TCPDF fork adding requirements for iTop: Specific fonts.",
"homepage": "https://github.com/combodo-itop-libs/TCPDF",
"time": "2020-01-08T16:22:40+00:00"
"time": "2020-09-28T12:19:09+00:00"
},
{
"name": "nikic/php-parser",
@@ -163,16 +168,16 @@
},
{
"name": "pear/archive_tar",
"version": "1.4.9",
"version": "1.4.10",
"source": {
"type": "git",
"url": "https://github.com/pear/Archive_Tar.git",
"reference": "c5b00053770e1d72128252c62c2c1a12c26639f0"
"reference": "bbb4f10f71a1da2715ec6d9a683f4f23c507a49b"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/pear/Archive_Tar/zipball/c5b00053770e1d72128252c62c2c1a12c26639f0",
"reference": "c5b00053770e1d72128252c62c2c1a12c26639f0",
"url": "https://api.github.com/repos/pear/Archive_Tar/zipball/bbb4f10f71a1da2715ec6d9a683f4f23c507a49b",
"reference": "bbb4f10f71a1da2715ec6d9a683f4f23c507a49b",
"shasum": ""
},
"require": {
@@ -225,7 +230,7 @@
"archive",
"tar"
],
"time": "2019-12-04T10:17:28+00:00"
"time": "2020-09-15T14:13:23+00:00"
},
{
"name": "pear/console_getopt",

View File

@@ -1,8 +1,13 @@
<?xml version="1.0" encoding="utf-8" ?>
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<system.web>
<authorization>
<deny users="*" /> <!-- Denies all users -->
</authorization>
</system.web>
<system.webServer>
<security>
<requestFiltering>
<fileExtensions applyToWebDAV="false" allowUnlisted="false"></fileExtensions>
</requestFiltering>
<authorization>
<deny users="*" /> <!-- Denies all users -->
</authorization>
</security>
</system.webServer>
</configuration>

View File

@@ -35,6 +35,10 @@ require_once(APPROOT.'/core/email.class.inc.php');
*/
abstract class Action extends cmdbAbstractObject
{
/**
* @throws \CoreException
* @throws \Exception
*/
public static function Init()
{
$aParams = array
@@ -47,7 +51,6 @@ abstract class Action extends cmdbAbstractObject
"db_table" => "priv_action",
"db_key_field" => "id",
"db_finalclass_field" => "realclass",
"display_template" => "",
);
MetaModel::Init_Params($aParams);
//MetaModel::Init_InheritAttributes();
@@ -57,15 +60,32 @@ abstract class Action extends cmdbAbstractObject
MetaModel::Init_AddAttribute(new AttributeLinkedSetIndirect("trigger_list", array("linked_class"=>"lnkTriggerAction", "ext_key_to_me"=>"action_id", "ext_key_to_remote"=>"trigger_id", "allowed_values"=>null, "count_min"=>0, "count_max"=>0, "depends_on"=>array())));
// Display lists
MetaModel::Init_SetZListItems('details', array('name', 'description', 'status', 'trigger_list')); // Attributes to be displayed for the complete details
MetaModel::Init_SetZListItems('list', array('finalclass', 'name', 'description', 'status')); // Attributes to be displayed for a list
// - Attributes to be displayed for the complete details
MetaModel::Init_SetZListItems('details', array('name', 'description', 'status', 'trigger_list'));
// - Attributes to be displayed for a list
MetaModel::Init_SetZListItems('list', array('finalclass', 'name', 'description', 'status'));
// Search criteria
MetaModel::Init_SetZListItems('default_search', array('name', 'description', 'status')); // Criteria of the std search form
// MetaModel::Init_SetZListItems('advanced_search', array('name')); // Criteria of the advanced search form
// - Criteria of the std search form
MetaModel::Init_SetZListItems('default_search', array('name', 'description', 'status'));
// - Criteria of the advanced search form
// MetaModel::Init_SetZListItems('advanced_search', array('name'));
}
/**
* Encapsulate the execution of the action and handle failure & logging
*
* @param \Trigger $oTrigger
* @param array $aContextArgs
*
* @return mixed
*/
abstract public function DoExecute($oTrigger, $aContextArgs);
/**
* @return bool
* @throws \ArchivedObjectException
* @throws \CoreException
*/
public function IsActive()
{
switch($this->Get('status'))
@@ -79,6 +99,13 @@ abstract class Action extends cmdbAbstractObject
}
}
/**
* Return true if the current action status is set on "test"
*
* @return bool
* @throws \ArchivedObjectException
* @throws \CoreException
*/
public function IsBeingTested()
{
switch($this->Get('status'))
@@ -99,6 +126,10 @@ abstract class Action extends cmdbAbstractObject
*/
abstract class ActionNotification extends Action
{
/**
* @inheritDoc
* @throws \CoreException
*/
public static function Init()
{
$aParams = array
@@ -111,17 +142,20 @@ abstract class ActionNotification extends Action
"db_table" => "priv_action_notification",
"db_key_field" => "id",
"db_finalclass_field" => "",
"display_template" => "",
);
MetaModel::Init_Params($aParams);
MetaModel::Init_InheritAttributes();
// Display lists
MetaModel::Init_SetZListItems('details', array('name', 'description', 'status', 'trigger_list')); // Attributes to be displayed for the complete details
MetaModel::Init_SetZListItems('list', array('finalclass', 'name', 'description', 'status')); // Attributes to be displayed for a list
// - Attributes to be displayed for the complete details
MetaModel::Init_SetZListItems('details', array('name', 'description', 'status', 'trigger_list'));
// - Attributes to be displayed for a list
MetaModel::Init_SetZListItems('list', array('finalclass', 'name', 'description', 'status'));
// Search criteria
// MetaModel::Init_SetZListItems('standard_search', array('name')); // Criteria of the std search form
// MetaModel::Init_SetZListItems('advanced_search', array('name')); // Criteria of the advanced search form
// - Criteria of the std search form
// MetaModel::Init_SetZListItems('standard_search', array('name'));
// - Criteria of the advanced search form
// MetaModel::Init_SetZListItems('advanced_search', array('name'));
}
}
@@ -132,6 +166,9 @@ abstract class ActionNotification extends Action
*/
class ActionEmail extends ActionNotification
{
/**
* @inheritDoc
*/
public static function Init()
{
$aParams = array
@@ -144,7 +181,6 @@ class ActionEmail extends ActionNotification
"db_table" => "priv_action_email",
"db_key_field" => "id",
"db_finalclass_field" => "",
"display_template" => "",
);
MetaModel::Init_Params($aParams);
MetaModel::Init_InheritAttributes();
@@ -152,7 +188,9 @@ class ActionEmail extends ActionNotification
MetaModel::Init_AddAttribute(new AttributeEmailAddress("test_recipient", array("allowed_values"=>null, "sql"=>"test_recipient", "default_value"=>"", "is_null_allowed"=>true, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeString("from", array("allowed_values"=>null, "sql"=>"from", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeString("from_label", array("allowed_values"=>null, "sql"=>"from_label", "default_value"=>null, "is_null_allowed"=>true, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeString("reply_to", array("allowed_values"=>null, "sql"=>"reply_to", "default_value"=>null, "is_null_allowed"=>true, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeString("reply_to_label", array("allowed_values"=>null, "sql"=>"reply_to_label", "default_value"=>null, "is_null_allowed"=>true, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeOQL("to", array("allowed_values"=>null, "sql"=>"to", "default_value"=>null, "is_null_allowed"=>true, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeOQL("cc", array("allowed_values"=>null, "sql"=>"cc", "default_value"=>null, "is_null_allowed"=>true, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeOQL("bcc", array("allowed_values"=>null, "sql"=>"bcc", "default_value"=>null, "is_null_allowed"=>true, "depends_on"=>array())));
@@ -161,11 +199,15 @@ class ActionEmail extends ActionNotification
MetaModel::Init_AddAttribute(new AttributeEnum("importance", array("allowed_values"=>new ValueSetEnum('low,normal,high'), "sql"=>"importance", "default_value"=>'normal', "is_null_allowed"=>false, "depends_on"=>array())));
// Display lists
MetaModel::Init_SetZListItems('details', array('name', 'description', 'status', 'test_recipient', 'from', 'reply_to', 'to', 'cc', 'bcc', 'subject', 'body', 'importance', 'trigger_list')); // Attributes to be displayed for the complete details
MetaModel::Init_SetZListItems('list', array('name', 'status', 'to', 'subject')); // Attributes to be displayed for a list
// - Attributes to be displayed for the complete details
MetaModel::Init_SetZListItems('details', array('name', 'description', 'status', 'test_recipient', 'from', 'from_label', 'reply_to', 'reply_to_label', 'to', 'cc', 'bcc', 'subject', 'body', 'importance', 'trigger_list'));
// - Attributes to be displayed for a list
MetaModel::Init_SetZListItems('list', array('name', 'status', 'to', 'subject'));
// Search criteria
MetaModel::Init_SetZListItems('standard_search', array('name','description', 'status', 'subject')); // Criteria of the std search form
// MetaModel::Init_SetZListItems('advanced_search', array('name')); // Criteria of the advanced search form
// - Criteria of the std search form
MetaModel::Init_SetZListItems('standard_search', array('name','description', 'status', 'subject'));
// - Criteria of the advanced search form
// MetaModel::Init_SetZListItems('advanced_search', array('name'));
}
// count the recipients found
@@ -175,7 +217,18 @@ class ActionEmail extends ActionNotification
// executed in the background, while making sure that any issue would be reported clearly
protected $m_aMailErrors; //array of strings explaining the issue
// returns a the list of emails as a string, or a detailed error description
/**
* Return a the list of emails as a string, or a detailed error description
*
* @param string $sRecipAttCode
* @param array $aArgs
*
* @return string
* @throws \ArchivedObjectException
* @throws \CoreException
* @throws \CoreUnexpectedValue
* @throws \MySQLException
*/
protected function FindRecipients($sRecipAttCode, $aArgs)
{
$sOQL = $this->Get($sRecipAttCode);
@@ -224,9 +277,7 @@ class ActionEmail extends ActionNotification
}
/**
* @param \Trigger $oTrigger
* @param array $aContextArgs
*
* @inheritDoc
* @throws \CoreException
* @throws \CoreUnexpectedValue
* @throws \CoreWarning
@@ -306,6 +357,7 @@ class ActionEmail extends ActionNotification
*
* @return string
* @throws \CoreException
* @throws \Exception
*/
protected function _DoExecute($oTrigger, $aContextArgs, &$oLog)
{
@@ -316,15 +368,17 @@ class ActionEmail extends ActionNotification
$this->m_aMailErrors = array();
$bRes = false; // until we do succeed in sending the email
// Determine recicipients
// Determine recipients
//
$sTo = $this->FindRecipients('to', $aContextArgs);
$sCC = $this->FindRecipients('cc', $aContextArgs);
$sBCC = $this->FindRecipients('bcc', $aContextArgs);
$sFrom = MetaModel::ApplyParams($this->Get('from'), $aContextArgs);
$sFromLabel = MetaModel::ApplyParams($this->Get('from_label'), $aContextArgs);
$sReplyTo = MetaModel::ApplyParams($this->Get('reply_to'), $aContextArgs);
$sReplyToLabel = MetaModel::ApplyParams($this->Get('reply_to_label'), $aContextArgs);
$sSubject = MetaModel::ApplyParams($this->Get('subject'), $aContextArgs);
$sBody = MetaModel::ApplyParams($this->Get('body'), $aContextArgs);
@@ -347,7 +401,7 @@ class ActionEmail extends ActionNotification
if (isset($sTo)) $oLog->Set('to', $sTo);
if (isset($sCC)) $oLog->Set('cc', $sCC);
if (isset($sBCC)) $oLog->Set('bcc', $sBCC);
if (isset($sFrom)) $oLog->Set('from', $sFrom);
if (isset($sFrom)) $oLog->Set('from', empty($sFromLabel) ? $sFrom : "$sFromLabel <$sFrom>");
if (isset($sSubject)) $oLog->Set('subject', $sSubject);
if (isset($sBody)) $oLog->Set('body', $sBody);
}
@@ -367,15 +421,15 @@ class ActionEmail extends ActionNotification
$sTestBody .= "<li>TO: $sTo</li>\n";
$sTestBody .= "<li>CC: $sCC</li>\n";
$sTestBody .= "<li>BCC: $sBCC</li>\n";
$sTestBody .= "<li>From: $sFrom</li>\n";
$sTestBody .= "<li>Reply-To: $sReplyTo</li>\n";
$sTestBody .= empty($sFromLabel) ? "<li>From: $sFrom</li>\n": "<li>From: $sFromLabel &lt;$sFrom&gt;</li>\n";
$sTestBody .= empty($sReplyToLabel) ? "<li>Reply-To: $sReplyTo</li>\n": "<li>Reply-To: $sReplyToLabel &lt;$sReplyTo&gt;</li>\n";
$sTestBody .= "<li>References: $sReference</li>\n";
$sTestBody .= "</ul>\n";
$sTestBody .= "</p>\n";
$sTestBody .= "</div>\n";
$oEmail->SetBody($sTestBody, 'text/html', $sStyles);
$oEmail->SetRecipientTO($this->Get('test_recipient'));
$oEmail->SetRecipientFrom($sFrom);
$oEmail->SetRecipientFrom($sFrom, $sFromLabel);
$oEmail->SetReferences($sReference);
$oEmail->SetMessageId($sMessageId);
}
@@ -386,8 +440,8 @@ class ActionEmail extends ActionNotification
$oEmail->SetRecipientTO($sTo);
$oEmail->SetRecipientCC($sCC);
$oEmail->SetRecipientBCC($sBCC);
$oEmail->SetRecipientFrom($sFrom);
$oEmail->SetRecipientReplyTo($sReplyTo);
$oEmail->SetRecipientFrom($sFrom, $sFromLabel);
$oEmail->SetRecipientReplyTo($sReplyTo, $sReplyToLabel);
$oEmail->SetReferences($sReference);
$oEmail->SetMessageId($sMessageId);
}
@@ -439,4 +493,3 @@ class ActionEmail extends ActionNotification
}
}
}
?>

View File

@@ -65,6 +65,10 @@ class ExecAsyncTask implements iBackgroundProcess
*/
abstract class AsyncTask extends DBObject
{
/**
* @throws \CoreException
* @throws \Exception
*/
public static function Init()
{
$aParams = array
@@ -77,7 +81,6 @@ abstract class AsyncTask extends DBObject
"db_table" => "priv_async_task",
"db_key_field" => "id",
"db_finalclass_field" => "realclass",
"display_template" => "",
);
MetaModel::Init_Params($aParams);
@@ -285,11 +288,13 @@ abstract class AsyncTask extends DBObject
/**
* Throws an exception (message and code)
*
* @return string
*/
abstract public function DoProcess();
/**
* Describes the error codes that DoProcess can return by the mean of exceptions
* Describes the error codes that DoProcess can return by the mean of exceptions
*/
static public function EnumErrorCodes()
{
@@ -316,7 +321,6 @@ class AsyncSendEmail extends AsyncTask
"db_table" => "priv_async_send_email",
"db_key_field" => "id",
"db_finalclass_field" => "",
"display_template" => "",
);
MetaModel::Init_Params($aParams);
MetaModel::Init_InheritAttributes();
@@ -352,6 +356,11 @@ class AsyncSendEmail extends AsyncTask
$oNew->DBInsert();
}
/**
* @inheritDoc
* @throws \ArchivedObjectException
* @throws \CoreException
*/
public function DoProcess()
{
$sMessage = $this->Get('message');

View File

@@ -18,6 +18,7 @@
*/
use Combodo\iTop\Form\Field\LabelField;
use Combodo\iTop\Form\Field\TextAreaField;
use Combodo\iTop\Form\Validator\NotEmptyExtKeyValidator;
use Combodo\iTop\Form\Validator\Validator;
@@ -30,13 +31,9 @@ require_once('ormlinkset.class.inc.php');
require_once('ormset.class.inc.php');
require_once('ormtagset.class.inc.php');
require_once('htmlsanitizer.class.inc.php');
require_once(APPROOT.'sources/autoload.php');
require_once('customfieldshandler.class.inc.php');
require_once('ormcustomfieldsvalue.class.inc.php');
require_once('datetimeformat.class.inc.php');
// This should be changed to a use when we go full-namespace
require_once(APPROOT.'sources/form/validator/validator.class.inc.php');
require_once(APPROOT.'sources/form/validator/notemptyextkeyvalidator.class.inc.php');
/**
* MissingColumnException - sent if an attribute is being created but the column is missing in the row
@@ -156,7 +153,7 @@ abstract class AttributeDefinition
*/
public function IsSearchable()
{
return static::SEARCH_WIDGET_TYPE != static::SEARCH_WIDGET_TYPE_RAW;
return $this->GetSearchType() != static::SEARCH_WIDGET_TYPE_RAW;
}
/** @var string */
@@ -294,7 +291,7 @@ abstract class AttributeDefinition
* @param \DBObject $oHostObject
* @param $value Object error if any, null otherwise
*
* @return bool
* @return bool|string true for no errors, false or error message otherwise
*/
public function CheckValue(DBObject $oHostObject, $value)
{
@@ -1029,13 +1026,34 @@ abstract class AttributeDefinition
$oFormField->AddValidator(new Validator($this->GetValidationPattern()));
}
// Description
$sAttDescription = $this->GetDescription();
if(!empty($sAttDescription))
{
$oFormField->SetDescription($this->GetDescription());
}
// Metadata
$oFormField->AddMetadata('attribute-code', $this->GetCode());
$oFormField->AddMetadata('attribute-type', get_class($this));
$oFormField->AddMetadata('attribute-label', utils::HtmlEntities($this->GetLabel()));
$oFormField->AddMetadata('attribute-label', $this->GetLabel());
// - Attribute flags
$aPossibleAttFlags = MetaModel::EnumPossibleAttributeFlags();
foreach($aPossibleAttFlags as $sFlagCode => $iFlagValue)
{
// Note: Skip normal flag as we don't need it.
if($sFlagCode === 'normal')
{
continue;
}
$sFormattedFlagCode = str_ireplace('_', '-', $sFlagCode);
$sFormattedFlagValue = (($iFlags & $iFlagValue) === $iFlagValue) ? 'true' : 'false';
$oFormField->AddMetadata('attribute-flag-'.$sFormattedFlagCode, $sFormattedFlagValue);
}
// - Value raw
if ($this::IsScalar())
{
$oFormField->AddMetadata('value-raw', utils::HtmlEntities($oObject->Get($this->GetCode())));
$oFormField->AddMetadata('value-raw', (string) $oObject->Get($this->GetCode()));
}
return $oFormField;
@@ -1255,6 +1273,15 @@ abstract class AttributeDefinition
{
return (string)$value;
}
/*
* return string
*/
public function GetRenderForDataTable(string $sClassAlias) :string
{
$sRenderFunction = "return data;";
return $sRenderFunction;
}
}
class AttributeDashboard extends AttributeDefinition
@@ -2258,22 +2285,17 @@ class AttributeLinkedSetIndirect extends AttributeLinkedSet
/** @var \AttributeExternalKey $oExtKeyToRemote */
$oExtKeyToRemote = MetaModel::GetAttributeDef($this->GetLinkedClass(), $this->GetExtKeyToRemote());
$sRemoteClass = $oExtKeyToRemote->GetTargetClass();
foreach(MetaModel::ListAttributeDefs($sRemoteClass) as $sRemoteAttCode => $oRemoteAttDef)
{
if (!$oRemoteAttDef instanceof AttributeLinkedSetIndirect)
{
foreach(MetaModel::ListAttributeDefs($sRemoteClass) as $sRemoteAttCode => $oRemoteAttDef) {
if (!$oRemoteAttDef instanceof AttributeLinkedSetIndirect) {
continue;
}
if ($oRemoteAttDef->GetLinkedClass() != $this->GetLinkedClass())
{
if ($oRemoteAttDef->GetLinkedClass() != $this->GetLinkedClass()) {
continue;
}
if ($oRemoteAttDef->GetExtKeyToMe() != $this->GetExtKeyToRemote())
{
if ($oRemoteAttDef->GetExtKeyToMe() != $this->GetExtKeyToRemote()) {
continue;
}
if ($oRemoteAttDef->GetExtKeyToRemote() != $this->GetExtKeyToMe())
{
if ($oRemoteAttDef->GetExtKeyToRemote() != $this->GetExtKeyToMe()) {
continue;
}
$oRet = $oRemoteAttDef;
@@ -3726,7 +3748,7 @@ class AttributeFinalClass extends AttributeString
/**
* @return bool
* @since 2.7
* @since 2.7.0 N°2272 OQL perf finalclass in all intermediary tables
*/
public function CopyOnAllTables()
{
@@ -4380,7 +4402,7 @@ class AttributeLongText extends AttributeText
{
// Is there a way to know the current limitation for mysql?
// See mysql_field_len()
return 65535 * 1024; // Limited... still 64 Mb!
return 65535 * 1024; // Limited... still 64 MB!
}
}
@@ -4979,6 +5001,7 @@ class AttributePhoneNumber extends AttributeString
return '<a class="tel" href="'.$sUrl.'"><span class="text_decoration '.$sUrlDecorationClass.'"></span>'.parent::GetAsHTML($sValue).'</a>';
}
}
/**
@@ -6639,6 +6662,23 @@ class AttributeExternalKey extends AttributeDBFieldVoid
return (int)$proposedValue;
}
public function GetPrerequisiteAttributes($sClass = null)
{
$aAttributes = parent::GetPrerequisiteAttributes($sClass);
$oExpression = DBSearch::FromOQL($this->GetValuesDef()->GetFilterExpression())->GetCriteria();
foreach ($oExpression->GetParameters('this') as $sAttCode)
{
// Skip the id as it cannot change anyway
if ($sAttCode =='id') continue;
if (!in_array($sAttCode, $aAttributes))
{
$aAttributes[] = $sAttCode;
}
}
return $aAttributes;
}
public function GetMaximumComboLength()
{
return $this->GetOptional('max_combo_length', MetaModel::GetConfig()->Get('max_combo_length'));
@@ -6744,8 +6784,7 @@ class AttributeExternalKey extends AttributeDBFieldVoid
public function GetAsHTML($sValue, $oHostObject = null, $bLocalize = true)
{
if (!is_null($oHostObject))
{
if (!is_null($oHostObject)) {
return $oHostObject->GetAsHTML($this->GetCode(), $oHostObject);
}
@@ -6884,7 +6923,7 @@ class AttributeHierarchicalKey extends AttributeExternalKey
if ($oFilter)
{
$oValSetDef = $this->GetValuesDef();
$oValSetDef->AddCondition($oFilter);
$oValSetDef->SetCondition($oFilter);
return $oValSetDef->GetValues($aArgs, $sContains);
}
@@ -6900,7 +6939,7 @@ class AttributeHierarchicalKey extends AttributeExternalKey
$oFilter = $this->GetHierachicalFilter($aArgs, $sContains, $iAdditionalValue);
if ($oFilter)
{
$oValSetDef->AddCondition($oFilter);
$oValSetDef->SetCondition($oFilter);
}
$oSet = $oValSetDef->ToObjectSet($aArgs, $sContains, $iAdditionalValue);
@@ -7001,6 +7040,15 @@ class AttributeExternalField extends AttributeDefinition
return self::SEARCH_WIDGET_TYPE_RAW;
}
function IsSearchable()
{
if ($this->IsFriendlyName())
{
return true;
}
return parent::IsSearchable();
}
public static function ListExpectedParams()
{
return array_merge(parent::ListExpectedParams(), array("extkey_attcode", "target_attcode"));
@@ -7426,6 +7474,12 @@ class AttributeExternalField extends AttributeDefinition
}
}
parent::MakeFormField($oObject, $oFormField);
if ($oFormField instanceof TextAreaField) {
if (method_exists($oRemoteAttDef, 'GetFormat')) {
/** @var \Combodo\iTop\Form\Field\TextAreaField $oFormField */
$oFormField->SetFormat($oRemoteAttDef->GetFormat());
}
}
// Manually setting for remote ExternalKey, otherwise, the id would be displayed.
if ($oRemoteAttDef instanceof AttributeExternalKey)
@@ -7443,6 +7497,16 @@ class AttributeExternalField extends AttributeDefinition
{
return false;
}
public function GetFormat()
{
$oRemoteAttDef = $this->GetExtAttDef();
if (method_exists($oRemoteAttDef, 'GetFormat')) {
/** @var \Combodo\iTop\Form\Field\TextAreaField $oFormField */
return $oRemoteAttDef->GetFormat();
}
return 'text';
}
}
@@ -7692,10 +7756,17 @@ class AttributeBlob extends AttributeDefinition
// (temporary tables created on disk)
// We will have to remove the blobs from the list of attributes when doing the select
// then the use of Get() should finalize the load
if ($value instanceOf ormDocument && !$value->IsEmpty())
if ($value instanceOf ormDocument)
{
$aValues = array();
$aValues[$this->GetCode().'_data'] = $value->GetData();
if (!$value->IsEmpty())
{
$aValues[$this->GetCode().'_data'] = $value->GetData();
}
else
{
$aValues[$this->GetCode().'_data'] = '';
}
$aValues[$this->GetCode().'_mimetype'] = $value->GetMimeType();
$aValues[$this->GetCode().'_filename'] = $value->GetFileName();
}
@@ -7915,18 +7986,6 @@ class AttributeImage extends AttributeBlob
return "Image";
}
/**
* {@inheritDoc}
* @see AttributeBlob::MakeRealValue()
*/
public function MakeRealValue($proposedValue, $oHostObj)
{
$oDoc = parent::MakeRealValue($proposedValue, $oHostObj);
// The validation of the MIME Type is done by CheckFormat below
return $oDoc;
}
/**
* Check that the supplied ormDocument actually contains an image
* {@inheritDoc}
@@ -9611,7 +9670,7 @@ class AttributePropertySet extends AttributeTable
$sValue = '*****';
}
$sRes .= "<TR>";
$sCell = str_replace("\n", "<br>\n", Str::pure2html((string)$sValue));
$sCell = str_replace("\n", "<br>\n", Str::pure2html(@(string)$sValue));
$sRes .= "<TD class=\"label\">$sProperty</TD><TD>$sCell</TD>";
$sRes .= "</TR>";
}
@@ -9705,21 +9764,6 @@ abstract class AttributeSet extends AttributeDBFieldVoid
return array_merge(parent::ListExpectedParams(), array('is_null_allowed', 'max_items'));
}
/**
* Allowed values are mandatory for this attribute to be modified
*
* @param array $aArgs
* @param string $sContains
*
* @return array|null
* @throws \CoreException
* @throws \OQLException
*/
public function GetAllowedValues($aArgs = array(), $sContains = '')
{
return parent::GetAllowedValues($aArgs, $sContains);
}
/**
* Allowed different values for the set values are mandatory for this attribute to be modified
*
@@ -9852,16 +9896,16 @@ abstract class AttributeSet extends AttributeDBFieldVoid
return 255;
}
public function FromStringToArray($proposedValue)
public function FromStringToArray($proposedValue, $sDefaultSepItem = ',')
{
$aValues = array();
if (!empty($proposedValue))
{
$sSepItem = MetaModel::GetConfig()->Get('tag_set_item_separator');
// convert also , separated strings
if ($sSepItem !== ',')
if ($sSepItem !== $sDefaultSepItem)
{
$proposedValue = str_replace(',', $sSepItem, $proposedValue);
$proposedValue = str_replace($sDefaultSepItem, $sSepItem, $proposedValue);
}
foreach(explode($sSepItem, $proposedValue) as $sCode)
{
@@ -9904,10 +9948,18 @@ abstract class AttributeSet extends AttributeDBFieldVoid
public function MakeRealValue($proposedValue, $oHostObj, $bIgnoreErrors = false)
{
$oSet = new ormSet(MetaModel::GetAttributeOrigin($this->GetHostClass(), $this->GetCode()), $this->GetCode(), $this->GetMaxItems());
$aAllowedValues = $this->GetPossibleValues();
if (is_string($proposedValue) && !empty($proposedValue))
{
$proposedValue = trim("$proposedValue");
$aValues = $this->FromStringToArray($proposedValue);
foreach ($aValues as $i => $sValue)
{
if (!isset($aAllowedValues[$sValue]))
{
unset($aValues[$i]);
}
}
$oSet->SetValues($aValues);
}
elseif ($proposedValue instanceof ormSet)
@@ -10109,10 +10161,6 @@ abstract class AttributeSet extends AttributeDBFieldVoid
$aValues = $value->GetValues();
}
$sRes = implode($sSepItem, $aValues);
if (!empty($sRes))
{
$sRes = "{$sSepItem}{$sRes}{$sSepItem}";
}
}
else
{
@@ -10136,14 +10184,32 @@ abstract class AttributeSet extends AttributeDBFieldVoid
class AttributeEnumSet extends AttributeSet
{
const SEARCH_WIDGET_TYPE = self::SEARCH_WIDGET_TYPE_TAG_SET;
public static function ListExpectedParams()
{
return array_merge(parent::ListExpectedParams(), array('possible_values', 'is_null_allowed', 'max_items'));
}
public function GetMaxSize()
{
$aRawValues = $this->GetRawPossibleValues();
$iMaxItems = $this->GetMaxItems();
$aLengths = array();
foreach (array_keys($aRawValues) as $sKey)
{
$aLengths[] = strlen($sKey);
}
rsort($aLengths, SORT_NUMERIC);
$iMaxSize = 2;
for ($i = 0; $i < min($iMaxItems, count($aLengths)); $i++)
{
$iMaxSize += $aLengths[$i] + 1;
}
return max(255, $iMaxSize);
}
private function GetRawPossibleValues($aArgs = array(), $sContains = '')
{
/** @var ValueSetEnumPadded $oValSetDef */
$oValSetDef = $this->Get('possible_values');
if (!$oValSetDef)
{
@@ -10167,8 +10233,13 @@ class AttributeEnumSet extends AttributeSet
public function GetValueLabel($sValue)
{
if ($sValue instanceof ormSet)
{
$sValue = implode(', ', $sValue->GetValues());
}
$aValues = $this->GetRawPossibleValues();
if (isset($aValues[$sValue]))
if (is_array($aValues) && is_string($sValue) && isset($aValues[$sValue]))
{
$sValue = $aValues[$sValue];
}
@@ -10184,9 +10255,14 @@ class AttributeEnumSet extends AttributeSet
$sLabel = $this->SearchLabel('/Attribute:'.$this->m_sCode.'/Value:'.$sValue, null, true /*user lang*/);
if (is_null($sLabel))
{
$sDefault = str_replace('_', ' ', $sValue);
// Browse the hierarchy again, accepting default (english) translations
$sLabel = $this->SearchLabel('/Attribute:'.$this->m_sCode.'/Value:'.$sValue, $sDefault, false);
$sLabel = $this->SearchLabel('/Attribute:'.$this->m_sCode.'/Value:'.$sValue, null, false);
if (is_null($sLabel))
{
$sDefault = trim(str_replace('_', ' ', $sValue));
// Browse the hierarchy again, accepting default (english) translations
$sLabel = $this->SearchLabel('/Attribute:'.$this->m_sCode.'/Value:'.$sDefault, $sDefault, false);
}
}
}
@@ -10245,6 +10321,123 @@ class AttributeEnumSet extends AttributeSet
return $sRes;
}
/**
* @param ormSet $value
* @param string $sSeparator
* @param string $sTextQualifier
* @param \DBObject $oHostObject
* @param bool $bLocalize
* @param bool $bConvertToPlainText
*
* @return mixed|string
* @throws \Exception
*/
public function GetAsCSV($value, $sSeparator = ',', $sTextQualifier = '"', $oHostObject = null, $bLocalize = true, $bConvertToPlainText = false)
{
$sSepItem = MetaModel::GetConfig()->Get('tag_set_item_separator');
if (is_object($value) && ($value instanceof ormSet))
{
$aValues = $value->GetValues();
if ($bLocalize)
{
$aLocalizedValues = array();
foreach($aValues as $sValue)
{
$aLocalizedValues[] = $this->GetValueLabel($sValue);
}
$aValues = $aLocalizedValues;
}
$sRes = implode($sSepItem, $aValues);
}
else
{
$sRes = '';
}
return "{$sTextQualifier}{$sRes}{$sTextQualifier}";
}
/**
* Get the value from a given string (plain text, CSV import)
*
* @param string $sProposedValue
* @param bool $bLocalizedValue
* @param string $sSepItem
* @param string $sSepAttribute
* @param string $sSepValue
* @param string $sAttributeQualifier
*
* @return mixed null if no match could be found
* @throws \Exception
*/
public function MakeValueFromString($sProposedValue, $bLocalizedValue = false, $sSepItem = null, $sSepAttribute = null, $sSepValue = null, $sAttributeQualifier = null)
{
if ($bLocalizedValue)
{
// Lookup for the values matching the input
//
$aValues = $this->FromStringToArray($sProposedValue);
$aFoundValues = array();
$aRawValues = $this->GetPossibleValues();
foreach ($aValues as $sValue)
{
$bFound = false;
foreach ($aRawValues as $sCode => $sRawValue)
{
if ($sValue == $sRawValue)
{
$aFoundValues[] = $sCode;
$bFound = true;
break;
}
}
if (!$bFound)
{
// Not found, break the import
return null;
}
}
return $this->MakeRealValue(implode(',', $aFoundValues), null);
}
else
{
return $this->MakeRealValue($sProposedValue, null, false);
}
}
/**
* @param string $proposedValue Search string used for MATCHES
*
* @param string $sDefaultSepItem word separator to extract items
*
* @return array of EnumSet codes
* @throws \Exception
*/
public function FromStringToArray($proposedValue, $sDefaultSepItem = ',')
{
$aValues = array();
if (!empty($proposedValue))
{
$sSepItem = MetaModel::GetConfig()->Get('tag_set_item_separator');
// convert also other separators
if ($sSepItem !== $sDefaultSepItem)
{
$proposedValue = str_replace($sDefaultSepItem, $sSepItem, $proposedValue);
}
foreach(explode($sSepItem, $proposedValue) as $sCode)
{
$sValue = trim($sCode);
if (strlen($sValue) > 2)
{
$sLabel = $this->GetValueLabel($sValue);
$aValues[$sLabel] = $sValue;
}
}
}
return $aValues;
}
}
@@ -10687,7 +10880,7 @@ class AttributeQueryAttCodeSet extends AttributeSet
* Multi value list of tags
*
* @see TagSetFieldData
* @since 2.6 N°931 tag fields
* @since 2.6.0 N°931 tag fields
*/
class AttributeTagSet extends AttributeSet
{
@@ -10766,7 +10959,7 @@ class AttributeTagSet extends AttributeSet
return json_encode($aJson);
}
public function FromStringToArray($proposedValue)
public function FromStringToArray($proposedValue, $sDefaultSepItem = ',')
{
$aValues = array();
if (!empty($proposedValue))
@@ -11410,7 +11603,17 @@ class AttributeFriendlyName extends AttributeDefinition
public function GetPrerequisiteAttributes($sClass = null)
{
return $this->GetOptional("depends_on", array());
// Code duplicated with AttributeObsolescenceFlag
$aAttributes = $this->GetOptional("depends_on", array());
$oExpression = $this->GetOQLExpression();
foreach ($oExpression->ListRequiredFields() as $sClass => $sAttCode)
{
if (!in_array($sAttCode, $aAttributes))
{
$aAttributes[] = $sAttCode;
}
}
return $aAttributes;
}
public static function IsScalar()
@@ -12642,7 +12845,17 @@ class AttributeObsolescenceFlag extends AttributeBoolean
public function GetPrerequisiteAttributes($sClass = null)
{
return $this->GetOptional("depends_on", array());
// Code duplicated with AttributeFriendlyName
$aAttributes = $this->GetOptional("depends_on", array());
$oExpression = $this->GetOQLExpression();
foreach ($oExpression->ListRequiredFields() as $sClass => $sAttCode)
{
if (!in_array($sAttCode, $aAttributes))
{
$aAttributes[] = $sAttCode;
}
}
return $aAttributes;
}
public function IsDirectField()

View File

@@ -1,29 +1,23 @@
<?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 (C) 2010-2020 Combodo SARL
*
* @copyright Copyright (C) 2010-2012 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
* 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
*/
interface iProcess
{
/**
@@ -78,21 +72,27 @@ interface iScheduledProcess extends iProcess
* * week_days
* * time
*
* Param names and some of their default values are in constant that can be overriden.
* Param names and some of their default values are in constant that can be overridden.
*
* Other info (module name and time default value) should be provided using a method that needs to be implemented.
*
* @since 2.7.0
* @since 2.7.0 PR #89
* @since 2.7.0-2 N°2580 Fix {@link GetNextOccurrence} returning wrong value
*/
abstract class AbstractWeeklyScheduledProcess implements iScheduledProcess
{
// param have default names/values but can be overriden
// param have default names/values but can be overridden
const MODULE_SETTING_ENABLED = 'enabled';
const DEFAULT_MODULE_SETTING_ENABLED = true;
const MODULE_SETTING_WEEKDAYS = 'week_days';
const DEFAULT_MODULE_SETTING_WEEKDAYS = 'monday, tuesday, wednesday, thursday, friday, saturday, sunday';
const MODULE_SETTING_TIME = 'time';
/**
* @var Config can be used to mock config for tests
*/
protected $oConfig;
/**
* Module must be declared in each implementation
*
@@ -106,6 +106,20 @@ abstract class AbstractWeeklyScheduledProcess implements iScheduledProcess
*/
abstract protected function GetDefaultModuleSettingTime();
/**
* @return \Config
*/
public function getOConfig()
{
if (!isset($this->oConfig))
{
$this->oConfig = MetaModel::GetConfig();
}
return $this->oConfig;
}
/**
* Interpret current setting for the week days
*
@@ -124,7 +138,7 @@ abstract class AbstractWeeklyScheduledProcess implements iScheduledProcess
'sunday' => 7,
);
$aDays = array();
$sWeekDays = MetaModel::GetConfig()->GetModuleSetting(
$sWeekDays = $this->getOConfig()->GetModuleSetting(
$this->GetModuleName(),
static::MODULE_SETTING_WEEKDAYS,
static::DEFAULT_MODULE_SETTING_WEEKDAYS
@@ -157,18 +171,20 @@ abstract class AbstractWeeklyScheduledProcess implements iScheduledProcess
}
/**
* Gives the exact time at which the process must be run next time
* @param string $sCurrentTime Date string to extract time dependency
* this parameter is not present in the interface but as it is optional it's ok
*
* @return DateTime
* @throws Exception
* @return DateTime the exact time at which the process must be run next time
* @throws \ProcessInvalidConfigException
*/
public function GetNextOccurrence()
public function GetNextOccurrence($sCurrentTime = 'now')
{
$bEnabled = MetaModel::GetConfig()->GetModuleSetting(
$bEnabled = $this->getOConfig()->GetModuleSetting(
$this->GetModuleName(),
static::MODULE_SETTING_ENABLED,
static::DEFAULT_MODULE_SETTING_ENABLED
);
if (!$bEnabled)
{
return new DateTime('3000-01-01');
@@ -180,7 +196,7 @@ abstract class AbstractWeeklyScheduledProcess implements iScheduledProcess
// 2nd - Find the next active week day
//
$sProcessTime = MetaModel::GetConfig()->GetModuleSetting(
$sProcessTime = $this->getOConfig()->GetModuleSetting(
$this->GetModuleName(),
static::MODULE_SETTING_TIME,
static::GetDefaultModuleSettingTime()
@@ -189,9 +205,11 @@ abstract class AbstractWeeklyScheduledProcess implements iScheduledProcess
{
throw new ProcessInvalidConfigException($this->GetModuleName().": wrong format for setting '".static::MODULE_SETTING_TIME."' (found '$sProcessTime')");
}
$oNow = new DateTime();
$oNow = new DateTime($sCurrentTime);
$iNextPos = false;
for ($iDay = $oNow->format('N'); $iDay <= 7; $iDay++)
$sDay = $oNow->format('N');
for ($iDay = (int) $sDay; $iDay <= 7; $iDay++)
{
$iNextPos = array_search($iDay, $aDays, true);
if ($iNextPos !== false)
@@ -241,13 +259,14 @@ abstract class AbstractWeeklyScheduledProcess implements iScheduledProcess
/**
* Exception for {@link iProcess} implementations.<br>
* An error happened during the processing but we can go on with the next implementations.
* @since 2.5.0 N°1195
*/
class ProcessException extends CoreException
{
}
/**
* @since 2.7.0
* @since 2.7.0 PR #89
*/
class ProcessInvalidConfigException extends ProcessException
{
@@ -257,6 +276,7 @@ class ProcessInvalidConfigException extends ProcessException
* Class ProcessFatalException
* Exception for iProcess implementations.<br>
* A big error occurred, we have to stop the iProcess processing.
* @since 2.5.0 N°1195
*/
class ProcessFatalException extends CoreException
{

View File

@@ -26,6 +26,24 @@
*/
class BackgroundTask extends DBObject
{
protected $bDebug = false;
/**
* @return bool
*/
public function IsDebug()
{
return $this->bDebug;
}
/**
* @param bool $bDebug
*/
public function SetDebug($bDebug)
{
$this->bDebug = $bDebug;
}
public static function Init()
{
$aParams = array
@@ -38,7 +56,6 @@ class BackgroundTask extends DBObject
"db_table" => "priv_backgroundtask",
"db_key_field" => "id",
"db_finalclass_field" => "",
"display_template" => "",
);
MetaModel::Init_Params($aParams);
@@ -54,7 +71,7 @@ class BackgroundTask extends DBObject
MetaModel::Init_AddAttribute(new AttributeDecimal("average_run_duration", array("allowed_values"=>null, "sql"=>"average_run_duration", "digits"=> 8, "decimals"=> 3, "default_value"=>"0", "is_null_allowed"=>true, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeBoolean("running", array("allowed_values"=>null, "sql"=>"running", "default_value"=>false, "is_null_allowed"=>false, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeEnum("status", array("allowed_values"=>new ValueSetEnum('active,paused'), "sql"=>"status", "default_value"=>'active', "is_null_allowed"=>false, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeEnum("status", array("allowed_values"=>new ValueSetEnum('active,paused,removed'), "sql"=>"status", "default_value"=>'active', "is_null_allowed"=>false, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeString("system_user", array("allowed_values"=>null, "sql"=>"system_user", "default_value"=>null, "is_null_allowed"=>true, "depends_on"=>array())));
}

View File

@@ -309,7 +309,7 @@ class BulkChange
$value = $oForeignAtt->MakeValueFromString($aRowData[$iCol], $this->m_bLocalizedValues);
}
$oReconFilter->AddCondition($sForeignAttCode, $value, '=');
$aResults[$iCol] = new CellStatus_Void($aRowData[$iCol]);
$aResults[$iCol] = new CellStatus_Void(utils::HtmlEntities($aRowData[$iCol]));
}
$oExtObjects = new CMDBObjectSet($oReconFilter);
@@ -363,6 +363,7 @@ class BulkChange
foreach ($aKeyConfig as $sForeignAttCode => $iCol)
{
// Default reporting
// $aRowData[$iCol] is always null
$aResults[$iCol] = new CellStatus_Void($aRowData[$iCol]);
}
if ($oExtKey->IsNullAllowed())
@@ -395,7 +396,7 @@ class BulkChange
}
$aCacheKeys[] = $value;
$oReconFilter->AddCondition($sForeignAttCode, $value, '=');
$aResults[$iCol] = new CellStatus_Void($aRowData[$iCol]);
$aResults[$iCol] = new CellStatus_Void(utils::HtmlEntities($aRowData[$iCol]));
}
$sCacheKey = implode('_|_', $aCacheKeys); // Unique key for this query...
$iForeignKey = null;
@@ -465,7 +466,7 @@ class BulkChange
foreach ($aKeyConfig as $sForeignAttCode => $iCol)
{
// Report the change on reconciliation values as well
$aResults[$iCol] = new CellStatus_Modify($aRowData[$iCol]);
$aResults[$iCol] = new CellStatus_Modify(utils::HtmlEntities($aRowData[$iCol]));
}
}
}
@@ -538,7 +539,7 @@ class BulkChange
{
if ($sAttCode == 'id')
{
$aResults[$iCol]= new CellStatus_Void($aRowData[$iCol]);
$aResults[$iCol]= new CellStatus_Void(utils::HtmlEntities($aRowData[$iCol]));
}
else
{
@@ -554,7 +555,7 @@ class BulkChange
}
if (isset($aErrors[$sAttCode]))
{
$aResults[$iCol]= new CellStatus_Issue($aRowData[$iCol], $sOrigValue, $aErrors[$sAttCode]);
$aResults[$iCol]= new CellStatus_Issue(utils::HtmlEntities($aRowData[$iCol]), $sOrigValue, $aErrors[$sAttCode]);
}
elseif (array_key_exists($sAttCode, $aChangedFields))
{
@@ -577,7 +578,7 @@ class BulkChange
}
else
{
$aResults[$iCol]= new CellStatus_Void($aRowData[$iCol]);
$aResults[$iCol]= new CellStatus_Void(utils::HtmlEntities($aRowData[$iCol]));
}
}
}
@@ -924,7 +925,7 @@ class BulkChange
{
// Leave the cell unchanged
$aResult[$iRow]["__STATUS__"]= new RowStatus_Issue(Dict::S('UI:CSVReport-Row-Issue-DateFormat'));
$aResult[$iRow][$sAttCode] = new CellStatus_Issue(null, $this->m_aData[$iRow][$iCol], Dict::S('UI:CSVReport-Row-Issue-DateFormat'));
$aResult[$iRow][$sAttCode] = new CellStatus_Issue(null, utils::HtmlEntities($this->m_aData[$iRow][$iCol]), Dict::S('UI:CSVReport-Row-Issue-DateFormat'));
}
}
}
@@ -947,7 +948,7 @@ class BulkChange
$iLoopTimeLimit = MetaModel::GetConfig()->Get('max_execution_time_per_loop');
foreach($this->m_aData as $iRow => $aRowData)
{
set_time_limit($iLoopTimeLimit);
set_time_limit(intval($iLoopTimeLimit));
if (isset($aResult[$iRow]["__STATUS__"]))
{
// An issue at the earlier steps - skip the rest
@@ -1066,13 +1067,13 @@ class BulkChange
$iObj = $oObj->GetKey();
if (!in_array($iObj, $aVisited))
{
set_time_limit($iLoopTimeLimit);
set_time_limit(intval($iLoopTimeLimit));
$iRow++;
$this->UpdateMissingObject($aResult, $iRow, $oObj, $oChange);
}
}
}
set_time_limit($iPreviousTimeLimit);
set_time_limit(itval($iPreviousTimeLimit));
// Fill in the blanks - the result matrix is expected to be 100% complete
//
@@ -1082,7 +1083,7 @@ class BulkChange
{
if (!array_key_exists($iCol, $aResult[$iRow]))
{
$aResult[$iRow][$iCol] = new CellStatus_Void($aRowData[$iCol]);
$aResult[$iRow][$iCol] = new CellStatus_Void(utils::HtmlEntities($aRowData[$iCol]));
}
}
foreach($this->m_aExtKeys as $sAttCode => $aForeignAtts)
@@ -1096,7 +1097,7 @@ class BulkChange
if (!array_key_exists($iCol, $aResult[$iRow]))
{
// The foreign attribute is one of our reconciliation key
$aResult[$iRow][$iCol] = new CellStatus_Void($aRowData[$iCol]);
$aResult[$iRow][$iCol] = new CellStatus_Void(utils::HtmlEntities($aRowData[$iCol]));
}
}
}

View File

@@ -345,10 +345,10 @@ abstract class BulkExport
$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('localize_output', $this->bLocalizeOutput);
}
$this->oBulkExportResult->Set('status_info', json_encode($this->GetStatusInfo()));
$this->oBulkExportResult->Set('temp_file_path', $this->sTmpFile);
utils::PushArchiveMode(false);
$ret = $this->oBulkExportResult->DBWrite();
utils::PopArchiveMode();
@@ -420,6 +420,11 @@ abstract class BulkExport
public function GetStatistics()
{
}
public function SetFields($sFields)
{
}
public function GetDownloadFileName()

View File

@@ -52,12 +52,18 @@ class CMDBChange extends DBObject
//MetaModel::Init_InheritAttributes();
MetaModel::Init_AddAttribute(new AttributeDateTime("date", array("allowed_values"=>null, "sql"=>"date", "default_value"=>"", "is_null_allowed"=>false, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeString("userinfo", array("allowed_values"=>null, "sql"=>"userinfo", "default_value"=>null, "is_null_allowed"=>true, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeExternalKey("user_id", array("allowed_values"=>null, "sql"=>"user_id", "targetclass"=>"User", "is_null_allowed"=>true, "on_target_delete"=>DEL_MANUAL, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeEnum("origin", array("allowed_values"=>new ValueSetEnum('interactive,csv-interactive,csv-import.php,webservice-soap,webservice-rest,synchro-data-source,email-processing,custom-extension'), "sql"=>"origin", "default_value"=>"interactive", "is_null_allowed"=>true, "depends_on"=>array())));
}
// Helper to keep track of the author of a given change,
// taking into account a variety of cases (contact attached or not, impersonation)
static public function GetCurrentUserName()
/**
* Helper to keep track of the author of a given change,
* taking into account a variety of cases (contact attached or not, impersonation)
*
* @return string
* @throws \OQLException
*/
public static function GetCurrentUserName()
{
if (UserRights::IsImpersonated())
{
@@ -70,6 +76,19 @@ class CMDBChange extends DBObject
return $sUserString;
}
/**
* Return the current user
*
* @return string|null
* @throws \OQLException
* @since 3.0.0
*/
public static function GetCurrentUserId()
{
// Note: We might have use only UserRights::GetRealUserId() as it would have done the same thing in the end
return UserRights::IsImpersonated() ? UserRights::GetRealUserId() : UserRights::GetUserId();
}
public function GetUserName()
{
if (preg_match('/^(.*)\\(CSV\\)$/i', $this->Get('userinfo'), $aMatches))
@@ -83,5 +102,3 @@ class CMDBChange extends DBObject
return $sUser;
}
}
?>

View File

@@ -31,7 +31,22 @@
* @package iTopORM
*/
class CMDBChangeOp extends DBObject
/**
* Interface iCMDBChangeOp
*
* @since 3.0.0
*/
interface iCMDBChangeOp
{
/**
* Describe (as a text string) the modifications corresponding to this change
*
* @return string
*/
public function GetDescription();
}
class CMDBChangeOp extends DBObject implements iCMDBChangeOp
{
public static function Init()
{
@@ -54,6 +69,7 @@ class CMDBChangeOp extends DBObject
MetaModel::Init_AddAttribute(new AttributeExternalKey("change", array("allowed_values"=>null, "sql"=>"changeid", "targetclass"=>"CMDBChange", "is_null_allowed"=>false, "on_target_delete"=>DEL_MANUAL, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeExternalField("date", array("allowed_values"=>null, "extkey_attcode"=>"change", "target_attcode"=>"date")));
MetaModel::Init_AddAttribute(new AttributeExternalField("userinfo", array("allowed_values"=>null, "extkey_attcode"=>"change", "target_attcode"=>"userinfo")));
MetaModel::Init_AddAttribute(new AttributeExternalField("user_id", array("allowed_values"=>null, "extkey_attcode"=>"change", "target_attcode"=>"user_id")));
MetaModel::Init_AddAttribute(new AttributeString("objclass", array("allowed_values"=>null, "sql"=>"objclass", "default_value"=>"", "is_null_allowed"=>false, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeObjectKey("objkey", array("allowed_values"=>null, "class_attcode"=>"objclass", "sql"=>"objkey", "is_null_allowed"=>false, "depends_on"=>array())));
@@ -62,7 +78,7 @@ class CMDBChangeOp extends DBObject
}
/**
* Describe (as a text string) the modifications corresponding to this change
* @inheritDoc
*/
public function GetDescription()
{
@@ -83,8 +99,6 @@ class CMDBChangeOp extends DBObject
}
}
/**
* Record the creation of an object
*
@@ -92,6 +106,9 @@ class CMDBChangeOp extends DBObject
*/
class CMDBChangeOpCreate extends CMDBChangeOp
{
/**
* @inheritDoc
*/
public static function Init()
{
$aParams = array
@@ -110,7 +127,7 @@ class CMDBChangeOpCreate extends CMDBChangeOp
}
/**
* Describe (as a text string) the modifications corresponding to this change
* @inheritDoc
*/
public function GetDescription()
{
@@ -118,7 +135,6 @@ class CMDBChangeOpCreate extends CMDBChangeOp
}
}
/**
* Record the deletion of an object
*
@@ -126,6 +142,9 @@ class CMDBChangeOpCreate extends CMDBChangeOp
*/
class CMDBChangeOpDelete extends CMDBChangeOp
{
/**
* @inheritDoc
*/
public static function Init()
{
$aParams = array
@@ -147,16 +166,16 @@ class CMDBChangeOpDelete extends CMDBChangeOp
// Last friendly name of the object
MetaModel::Init_AddAttribute(new AttributeString("fname", array("allowed_values"=>null, "sql"=>"fname", "default_value"=>"", "is_null_allowed"=>true, "depends_on"=>array())));
}
/**
* Describe (as a text string) the modifications corresponding to this change
*/
* @inheritDoc
*/
public function GetDescription()
{
return Dict::S('Change:ObjectDeleted');
}
}
/**
* Record the modification of an attribute (abstract)
*
@@ -164,6 +183,9 @@ class CMDBChangeOpDelete extends CMDBChangeOp
*/
class CMDBChangeOpSetAttribute extends CMDBChangeOp
{
/**
* @inheritDoc
*/
public static function Init()
{
$aParams = array
@@ -194,6 +216,9 @@ class CMDBChangeOpSetAttribute extends CMDBChangeOp
*/
class CMDBChangeOpSetAttributeScalar extends CMDBChangeOpSetAttribute
{
/**
* @inheritDoc
*/
public static function Init()
{
$aParams = array
@@ -216,10 +241,10 @@ class CMDBChangeOpSetAttributeScalar extends CMDBChangeOpSetAttribute
MetaModel::Init_SetZListItems('details', array('date', 'userinfo', 'attcode', 'oldvalue', 'newvalue')); // Attributes to be displayed for the complete details
MetaModel::Init_SetZListItems('list', array('date', 'userinfo', 'attcode', 'oldvalue', 'newvalue')); // Attributes to be displayed for a list
}
/**
* Describe (as a text string) the modifications corresponding to this change
*/
* @inheritDoc
*/
public function GetDescription()
{
$sResult = '';
@@ -250,7 +275,10 @@ class CMDBChangeOpSetAttributeScalar extends CMDBChangeOpSetAttribute
*/
class CMDBChangeOpSetAttributeTagSet extends CMDBChangeOpSetAttribute
{
public static function Init()
/**
* @inheritDoc
*/
public static function Init()
{
$aParams = array
(
@@ -273,10 +301,10 @@ class CMDBChangeOpSetAttributeTagSet extends CMDBChangeOpSetAttribute
MetaModel::Init_SetZListItems('list', array('date', 'userinfo', 'attcode', 'oldvalue', 'newvalue')); // Attributes to be displayed for a list
}
/**
* Describe (as a text string) the modifications corresponding to this change
*/
public function GetDescription()
/**
* @inheritDoc
*/
public function GetDescription()
{
$sResult = '';
$sTargetObjectClass = $this->Get('objclass');
@@ -307,6 +335,9 @@ class CMDBChangeOpSetAttributeTagSet extends CMDBChangeOpSetAttribute
*/
class CMDBChangeOpSetAttributeURL extends CMDBChangeOpSetAttribute
{
/**
* @inheritDoc
*/
public static function Init()
{
$aParams = array
@@ -329,10 +360,10 @@ class CMDBChangeOpSetAttributeURL extends CMDBChangeOpSetAttribute
MetaModel::Init_SetZListItems('details', array('date', 'userinfo', 'attcode', 'oldvalue', 'newvalue')); // Attributes to be displayed for the complete details
MetaModel::Init_SetZListItems('list', array('date', 'userinfo', 'attcode', 'oldvalue', 'newvalue')); // Attributes to be displayed for a list
}
/**
* Describe (as a text string) the modifications corresponding to this change
*/
* @inheritDoc
*/
public function GetDescription()
{
$sResult = '';
@@ -363,6 +394,9 @@ class CMDBChangeOpSetAttributeURL extends CMDBChangeOpSetAttribute
*/
class CMDBChangeOpSetAttributeBlob extends CMDBChangeOpSetAttribute
{
/**
* @inheritDoc
*/
public static function Init()
{
$aParams = array
@@ -384,10 +418,10 @@ class CMDBChangeOpSetAttributeBlob extends CMDBChangeOpSetAttribute
MetaModel::Init_SetZListItems('details', array('date', 'userinfo', 'attcode')); // Attributes to be displayed for the complete details
MetaModel::Init_SetZListItems('list', array('date', 'userinfo', 'attcode')); // Attributes to be displayed for a list
}
/**
* Describe (as a text string) the modifications corresponding to this change
*/
* @inheritDoc
*/
public function GetDescription()
{
// Temporary, until we change the options of GetDescription() -needs a more global revision
@@ -430,11 +464,15 @@ class CMDBChangeOpSetAttributeBlob extends CMDBChangeOpSetAttribute
return $sResult;
}
}
/**
* Safely record the modification of one way encrypted password
*/
class CMDBChangeOpSetAttributeOneWayPassword extends CMDBChangeOpSetAttribute
{
/**
* @inheritDoc
*/
public static function Init()
{
$aParams = array
@@ -456,10 +494,10 @@ class CMDBChangeOpSetAttributeOneWayPassword extends CMDBChangeOpSetAttribute
MetaModel::Init_SetZListItems('details', array('date', 'userinfo', 'attcode')); // Attributes to be displayed for the complete details
MetaModel::Init_SetZListItems('list', array('date', 'userinfo', 'attcode')); // Attributes to be displayed for a list
}
/**
* Describe (as a text string) the modifications corresponding to this change
*/
* @inheritDoc
*/
public function GetDescription()
{
// Temporary, until we change the options of GetDescription() -needs a more global revision
@@ -495,6 +533,9 @@ class CMDBChangeOpSetAttributeOneWayPassword extends CMDBChangeOpSetAttribute
*/
class CMDBChangeOpSetAttributeEncrypted extends CMDBChangeOpSetAttribute
{
/**
* @inheritDoc
*/
public static function Init()
{
$aParams = array
@@ -516,10 +557,10 @@ class CMDBChangeOpSetAttributeEncrypted extends CMDBChangeOpSetAttribute
MetaModel::Init_SetZListItems('details', array('date', 'userinfo', 'attcode')); // Attributes to be displayed for the complete details
MetaModel::Init_SetZListItems('list', array('date', 'userinfo', 'attcode')); // Attributes to be displayed for a list
}
/**
* Describe (as a text string) the modifications corresponding to this change
*/
* @inheritDoc
*/
public function GetDescription()
{
// Temporary, until we change the options of GetDescription() -needs a more global revision
@@ -544,7 +585,7 @@ class CMDBChangeOpSetAttributeEncrypted extends CMDBChangeOpSetAttribute
// The attribute was renamed or removed from the object ?
$sAttName = $this->Get('attcode');
}
$sPrevString = $this->Get('prevstring');
$sPrevString = $this->GetAsHTML('prevstring');
$sResult = Dict::Format('Change:AttName_Changed_PreviousValue_OldValue', $sAttName, $sPrevString);
}
return $sResult;
@@ -558,6 +599,9 @@ class CMDBChangeOpSetAttributeEncrypted extends CMDBChangeOpSetAttribute
*/
class CMDBChangeOpSetAttributeText extends CMDBChangeOpSetAttribute
{
/**
* @inheritDoc
*/
public static function Init()
{
$aParams = array
@@ -579,10 +623,10 @@ class CMDBChangeOpSetAttributeText extends CMDBChangeOpSetAttribute
MetaModel::Init_SetZListItems('details', array('date', 'userinfo', 'attcode')); // Attributes to be displayed for the complete details
MetaModel::Init_SetZListItems('list', array('date', 'userinfo', 'attcode')); // Attributes to be displayed for a list
}
/**
* Describe (as a text string) the modifications corresponding to this change
*/
* @inheritDoc
*/
public function GetDescription()
{
// Temporary, until we change the options of GetDescription() -needs a more global revision
@@ -623,6 +667,9 @@ class CMDBChangeOpSetAttributeText extends CMDBChangeOpSetAttribute
*/
class CMDBChangeOpSetAttributeLongText extends CMDBChangeOpSetAttribute
{
/**
* @inheritDoc
*/
public static function Init()
{
$aParams = array
@@ -644,10 +691,10 @@ class CMDBChangeOpSetAttributeLongText extends CMDBChangeOpSetAttribute
MetaModel::Init_SetZListItems('details', array('date', 'userinfo', 'attcode')); // Attributes to be displayed for the complete details
MetaModel::Init_SetZListItems('list', array('date', 'userinfo', 'attcode')); // Attributes to be displayed for a list
}
/**
* Describe (as a text string) the modifications corresponding to this change
*/
* @inheritDoc
*/
public function GetDescription()
{
$sResult = '';
@@ -685,6 +732,9 @@ class CMDBChangeOpSetAttributeLongText extends CMDBChangeOpSetAttribute
*/
class CMDBChangeOpSetAttributeHTML extends CMDBChangeOpSetAttributeLongText
{
/**
* @inheritDoc
*/
public static function Init()
{
$aParams = array
@@ -705,8 +755,9 @@ class CMDBChangeOpSetAttributeHTML extends CMDBChangeOpSetAttributeLongText
MetaModel::Init_SetZListItems('details', array('date', 'userinfo', 'attcode')); // Attributes to be displayed for the complete details
MetaModel::Init_SetZListItems('list', array('date', 'userinfo', 'attcode')); // Attributes to be displayed for a list
}
/**
* Describe (as a text string) the modifications corresponding to this change
* @inheritDoc
*/
public function GetDescription()
{
@@ -748,6 +799,9 @@ class CMDBChangeOpSetAttributeHTML extends CMDBChangeOpSetAttributeLongText
*/
class CMDBChangeOpSetAttributeCaseLog extends CMDBChangeOpSetAttribute
{
/**
* @inheritDoc
*/
public static function Init()
{
$aParams = array
@@ -769,10 +823,10 @@ class CMDBChangeOpSetAttributeCaseLog extends CMDBChangeOpSetAttribute
MetaModel::Init_SetZListItems('details', array('date', 'userinfo', 'attcode')); // Attributes to be displayed for the complete details
MetaModel::Init_SetZListItems('list', array('date', 'userinfo', 'attcode')); // Attributes to be displayed for a list
}
/**
* Describe (as a text string) the modifications corresponding to this change
*/
* @inheritDoc
*/
public function GetDescription()
{
// Temporary, until we change the options of GetDescription() -needs a more global revision
@@ -799,14 +853,18 @@ class CMDBChangeOpSetAttributeCaseLog extends CMDBChangeOpSetAttribute
}
$oObj = $oMonoObjectSet->Fetch();
$oCaseLog = $oObj->Get($this->Get('attcode'));
$iMaxVisibleLength = MetaModel::getConfig()->Get('max_history_case_log_entry_length', 0);
$sTextEntry = '<div class="history_entry history_entry_truncated"><div class="history_html_content">'.$oCaseLog->GetEntryAt($this->Get('lastentry')).'</div></div>';
$sResult = Dict::Format('Change:AttName_EntryAdded', $sAttName, $sTextEntry);
}
return $sResult;
}
/**
* @param string $sRawText
*
* @return string
*/
protected function ToHtml($sRawText)
{
return str_replace(array("\r\n", "\n", "\r"), "<br/>", htmlentities($sRawText, ENT_QUOTES, 'UTF-8'));
@@ -820,6 +878,9 @@ class CMDBChangeOpSetAttributeCaseLog extends CMDBChangeOpSetAttribute
*/
class CMDBChangeOpPlugin extends CMDBChangeOp
{
/**
* @inheritDoc
*/
public static function Init()
{
$aParams = array
@@ -841,10 +902,10 @@ class CMDBChangeOpPlugin extends CMDBChangeOp
*/
MetaModel::Init_InheritAttributes();
}
/**
* Describe (as a text string) the modifications corresponding to this change
*/
* @inheritDoc
*/
public function GetDescription()
{
return $this->Get('description');
@@ -858,6 +919,9 @@ class CMDBChangeOpPlugin extends CMDBChangeOp
*/
abstract class CMDBChangeOpSetAttributeLinks extends CMDBChangeOpSetAttribute
{
/**
* @inheritDoc
*/
public static function Init()
{
$aParams = array
@@ -888,6 +952,9 @@ abstract class CMDBChangeOpSetAttributeLinks extends CMDBChangeOpSetAttribute
*/
class CMDBChangeOpSetAttributeLinksAddRemove extends CMDBChangeOpSetAttributeLinks
{
/**
* @inheritDoc
*/
public static function Init()
{
$aParams = array
@@ -908,8 +975,8 @@ class CMDBChangeOpSetAttributeLinksAddRemove extends CMDBChangeOpSetAttributeLin
}
/**
* Describe (as a text string) the modifications corresponding to this change
*/
* @inheritDoc
*/
public function GetDescription()
{
$sResult = '';
@@ -952,6 +1019,9 @@ class CMDBChangeOpSetAttributeLinksAddRemove extends CMDBChangeOpSetAttributeLin
*/
class CMDBChangeOpSetAttributeLinksTune extends CMDBChangeOpSetAttributeLinks
{
/**
* @inheritDoc
*/
public static function Init()
{
$aParams = array
@@ -972,8 +1042,8 @@ class CMDBChangeOpSetAttributeLinksTune extends CMDBChangeOpSetAttributeLinks
}
/**
* Describe (as a text string) the modifications corresponding to this change
*/
* @inheritDoc
*/
public function GetDescription()
{
$sResult = '';
@@ -1039,6 +1109,9 @@ class CMDBChangeOpSetAttributeLinksTune extends CMDBChangeOpSetAttributeLinks
*/
class CMDBChangeOpSetAttributeCustomFields extends CMDBChangeOpSetAttribute
{
/**
* @inheritDoc
*/
public static function Init()
{
$aParams = array
@@ -1062,7 +1135,7 @@ class CMDBChangeOpSetAttributeCustomFields extends CMDBChangeOpSetAttribute
}
/**
* Describe (as a text string) the modifications corresponding to this change
* @inheritDoc
*/
public function GetDescription()
{

View File

@@ -94,12 +94,23 @@ abstract class CMDBObject extends DBObject
// Note: this value is static, but that could be changed because it is sometimes a real issue (see update of interfaces / connected_to
protected static $m_oCurrChange = null;
protected static $m_sInfo = null; // null => the information is built in a standard way
protected static $m_sUserId = null; // null => the user doing the change is unknown
protected static $m_sOrigin = null; // null => the origin is 'interactive'
/**
* Specify another change (this is mainly for backward compatibility)
* Specify the change to be used by the API to attach any CMDBChangeOp* object created
*
* @see SetTrackInfo if CurrentChange is null, then a new one will be create using trackinfo
*
* @param CMDBChange|null $oChange use null so that the API will recreate a new CMDBChange using TrackInfo & TrackOrigin
* If providing a CMDBChange, you should persist it first ! Indeed the API will automatically create CMDBChangeOp (see
* \CMDBObject::RecordObjCreation / RecordAttChange / RecordObjDeletion for example) and link them to the current change : in
* consequence this CMDBChange must have a key set !
*
* @since 2.7.2 N°3219 can now reset CMDBChange by passing null
* @since 2.7.2 N°3218 PHPDoc about persisting the $oChange parameter first
*/
public static function SetCurrentChange(CMDBChange $oChange)
public static function SetCurrentChange($oChange)
{
self::$m_oCurrChange = $oChange;
}
@@ -112,7 +123,11 @@ abstract class CMDBObject extends DBObject
// GetCurrentChange to create a default change if not already done in the current context
//
/**
* Get a change record (create it if not existing)
* @param bool $bAutoCreate if true calls {@link CreateChange} to get a new persisted object
*
* @return \CMDBChange
*
* @uses CreateChange
*/
public static function GetCurrentChange($bAutoCreate = true)
{
@@ -126,20 +141,44 @@ abstract class CMDBObject extends DBObject
/**
* Override the additional information (defaulting to user name)
* A call to this verb should replace every occurence of
* $oMyChange = MetaModel::NewObject("CMDBChange");
* $oMyChange = MetaModel::NewObject("CMDBChange");
* $oMyChange->Set("date", time());
* $oMyChange->Set("userinfo", 'this is done by ... for ...');
* $iChangeId = $oMyChange->DBInsert();
*/
*
* @see SetCurrentChange to specify a CMDBObject instance instead
*
* @param string $sInfo
*/
public static function SetTrackInfo($sInfo)
{
self::$m_sInfo = $sInfo;
}
/**
* Provide information about the user doing the change
*
* @see static::SetTrackInfo
* @see static::SetCurrentChange
*
* @param string $sId ID of the user doing the change, null if not done by a user (eg. background task)
*
* @since 3.0.0
*/
public static function SetTrackUserId($sId)
{
self::$m_sUserId = $sId;
}
/**
* Provides information about the origin of the change
* @param $sOrigin String: one of: interactive, csv-interactive, csv-import.php, webservice-soap, webservice-rest, syncho-data-source, email-processing, custom-extension
*/
*
* @see SetTrackInfo
* @see SetCurrentChange to specify a CMDBObject instance instead
*
* @param $sOrigin String: one of: interactive, csv-interactive, csv-import.php, webservice-soap, webservice-rest, syncho-data-source,
* email-processing, custom-extension
*/
public static function SetTrackOrigin($sOrigin)
{
self::$m_sOrigin = $sOrigin;
@@ -159,6 +198,25 @@ abstract class CMDBObject extends DBObject
return self::$m_sInfo;
}
}
/**
* Get the ID of the user doing the change (defaulting to null)
*
* @return string|null
* @throws \OQLException
* @since 3.0.0
*/
protected static function GetTrackUserId()
{
if (is_null(self::$m_sUserId))
{
return CMDBChange::GetCurrentUserId();
}
else
{
return self::$m_sUserId;
}
}
/**
* Get the 'origin' information (defaulting to 'interactive')
@@ -174,15 +232,26 @@ abstract class CMDBObject extends DBObject
return self::$m_sOrigin;
}
}
/**
* Create a standard change record (done here 99% of the time, and nearly once per page)
*/
* Set to {@link $m_oCurrChange} a standard change record (done here 99% of the time, and nearly once per page)
*
* The CMDBChange is persisted so that it has a key > 0, and any new CMDBChangeOp can link to it
*
* @throws \ArchivedObjectException
* @throws \CoreCannotSaveObjectException
* @throws \CoreException
* @throws \CoreUnexpectedValue
* @throws \CoreWarning
* @throws \MySQLException
* @throws \OQLException
*/
protected static function CreateChange()
{
self::$m_oCurrChange = MetaModel::NewObject("CMDBChange");
self::$m_oCurrChange->Set("date", time());
self::$m_oCurrChange->Set("userinfo", self::GetTrackInfo());
self::$m_oCurrChange->Set("user_id", self::GetTrackUserId());
self::$m_oCurrChange->Set("origin", self::GetTrackOrigin());
self::$m_oCurrChange->DBInsert();
}
@@ -488,7 +557,14 @@ abstract class CMDBObject extends DBObject
/**
* Helper to ultimately check user rights before writing (Insert, Update or Delete)
* The check should never fail, because the UI should prevent from such a usage
* Anyhow, if the user has found a workaround... the security gets enforced here
* Anyhow, if the user has found a workaround... the security gets enforced here
*
* @deprecated 3.0.0 N°2591 will be removed in 3.1.0
*
* @param bool $bSkipStrongSecurity
* @param int $iActionCode
*
* @throws \SecurityException
*/
protected function CheckUserRights($bSkipStrongSecurity, $iActionCode)
{
@@ -513,83 +589,6 @@ abstract class CMDBObject extends DBObject
}
}
/**
* @deprecated 2.7.0 N°2361 simply use {@link DBInsert} instead, that will automatically create and persist a CMDBChange object.
* If you need to persist your own, call {@link CMDBObject::SetCurrentChange} before.
*
* @param \CMDBChange $oChange
* @param null $bSkipStrongSecurity
*
* @return int|null
* @throws \ArchivedObjectException
* @throws \CoreCannotSaveObjectException
* @throws \CoreException
* @throws \CoreUnexpectedValue
* @throws \CoreWarning
* @throws \MySQLException
* @throws \OQLException
* @throws \SecurityException
*/
public function DBInsertTracked(CMDBChange $oChange, $bSkipStrongSecurity = null)
{
self::SetCurrentChange($oChange);
$this->CheckUserRights($bSkipStrongSecurity, UR_ACTION_MODIFY);
$ret = $this->DBInsertTracked_Internal();
return $ret;
}
/**
* @deprecated 2.7.0 N°2361 simply use {@link DBInsertNoReload} instead, that will automatically create and persist a CMDBChange object.
* If you need to persist your own, call {@link CMDBObject::SetCurrentChange} before.
*
* @param \CMDBChange $oChange
* @param null $bSkipStrongSecurity
*
* @return int
* @throws \ArchivedObjectException
* @throws \CoreCannotSaveObjectException
* @throws \CoreException
* @throws \CoreUnexpectedValue
* @throws \CoreWarning
* @throws \MySQLException
* @throws \OQLException
* @throws \SecurityException
*/
public function DBInsertTrackedNoReload(CMDBChange $oChange, $bSkipStrongSecurity = null)
{
self::SetCurrentChange($oChange);
$this->CheckUserRights($bSkipStrongSecurity, UR_ACTION_MODIFY);
$ret = $this->DBInsertTracked_Internal(true);
return $ret;
}
/**
* @deprecated 2.7.0 N°2361 simply use {@link DBInsert} or {@link DBInsertNoReload} instead
*
* @param bool $bDoNotReload
*
* @return integer Identifier of the created object
* @throws \ArchivedObjectException
* @throws \CoreCannotSaveObjectException
* @throws \CoreException
* @throws \CoreUnexpectedValue
* @throws \CoreWarning
* @throws \MySQLException
* @throws \OQLException
*/
protected function DBInsertTracked_Internal($bDoNotReload = false)
{
if ($bDoNotReload)
{
$ret = $this->DBInsertNoReload();
}
else
{
$ret = $this->DBInsert();
}
return $ret;
}
public function DBClone($newKey = null)
{
return $this->DBCloneTracked_Internal();
@@ -622,24 +621,6 @@ abstract class CMDBObject extends DBObject
return $ret;
}
/**
* @deprecated 2.7.0 N°2361 simply use {@link DBUpdate} instead, that will automatically create and persist a CMDBChange object.
* If you need to persist your own, call {@link CMDBObject::SetCurrentChange} before.
*
* @param \CMDBChange $oChange
* @param null $bSkipStrongSecurity
*
* @return int|void
* @throws \CoreCannotSaveObjectException
* @throws \CoreException
* @throws \SecurityException
*/
public function DBUpdateTracked(CMDBChange $oChange, $bSkipStrongSecurity = null)
{
self::SetCurrentChange($oChange);
$this->CheckUserRights($bSkipStrongSecurity, UR_ACTION_MODIFY);
$this->DBUpdate();
}
/**
* @param null $oDeletionPlan
@@ -659,31 +640,6 @@ abstract class CMDBObject extends DBObject
return $this->DBDeleteTracked_Internal($oDeletionPlan);
}
/**
* @deprecated 2.7.0 N°2361 simply use {@link DBDelete} instead, that will automatically create and persist a CMDBChange object.
* If you need to persist your own, call {@link CMDBObject::SetCurrentChange} before.
*
* @param \CMDBChange $oChange
* @param null $bSkipStrongSecurity
* @param null $oDeletionPlan
*
* @throws \ArchivedObjectException
* @throws \CoreCannotSaveObjectException
* @throws \CoreException
* @throws \CoreUnexpectedValue
* @throws \DeleteException
* @throws \MySQLException
* @throws \MySQLHasGoneAwayException
* @throws \OQLException
* @throws \SecurityException
*/
public function DBDeleteTracked(CMDBChange $oChange, $bSkipStrongSecurity = null, &$oDeletionPlan = null)
{
self::SetCurrentChange($oChange);
$this->CheckUserRights($bSkipStrongSecurity, UR_ACTION_DELETE);
$this->DBDeleteTracked_Internal($oDeletionPlan);
}
/**
* @param null $oDeletionPlan
*

View File

@@ -64,7 +64,7 @@ class MySQLException extends CoreException
/**
* Class MySQLQueryHasNoResultException
*
* @since 2.5
* @since 2.5.0
*/
class MySQLQueryHasNoResultException extends MySQLException
{
@@ -74,7 +74,7 @@ class MySQLQueryHasNoResultException extends MySQLException
/**
* Class MySQLHasGoneAwayException
*
* @since 2.5
* @since 2.5.0
* @see itop bug 1195
* @see https://dev.mysql.com/doc/refman/5.7/en/gone-away.html
*/
@@ -119,19 +119,30 @@ class CMDBSource
const ENUM_DB_VENDOR_MYSQL = 'MySQL';
const ENUM_DB_VENDOR_MARIADB = 'MariaDB';
const ENUM_DB_VENDOR_PERCONA = 'Percona';
/**
* Error: 1205 SQLSTATE: HY000 (ER_LOCK_WAIT_TIMEOUT)
* Message: Lock wait timeout exceeded; try restarting transaction
*/
const MYSQL_ERRNO_WAIT_TIMEOUT = 1205;
/**
* Error: 1213 SQLSTATE: 40001 (ER_LOCK_DEADLOCK)
* Message: Deadlock found when trying to get lock; try restarting transaction
*/
const MYSQL_ERRNO_DEADLOCK = 1213;
protected static $m_sDBHost;
protected static $m_sDBUser;
protected static $m_sDBPwd;
protected static $m_sDBName;
/**
* @var boolean
* @since 2.5 N°1260 MySQL TLS first implementation
* @since 2.5.0 N°1260 MySQL TLS first implementation
*/
protected static $m_bDBTlsEnabled;
/**
* @var string
* @since 2.5 N°1260 MySQL TLS first implementation
* @since 2.5.0 N°1260 MySQL TLS first implementation
*/
protected static $m_sDBTlsCA;
@@ -661,6 +672,7 @@ class CMDBSource
}
catch (mysqli_sql_exception $e)
{
self::LogDeadLock($e);
throw new MySQLException('Failed to issue SQL query', array('query' => $sSql, $e));
}
$oKPI->ComputeStats('Query exec (mySQL)', $sSql);
@@ -674,13 +686,55 @@ class CMDBSource
{
throw new MySQLHasGoneAwayException(self::GetError(), $aContext);
}
throw new MySQLException('Failed to issue SQL query', $aContext);
$e = new MySQLException('Failed to issue SQL query', $aContext);
self::LogDeadLock($e);
throw $e;
}
return $oResult;
}
/**
* @param \Exception $e
*
* @since 2.7.1
*/
private static function LogDeadLock(Exception $e)
{
// checks MySQL error code
$iMySqlErrorNo = self::$m_oMysqli->errno;
if (!in_array($iMySqlErrorNo, array(self::MYSQL_ERRNO_WAIT_TIMEOUT, self::MYSQL_ERRNO_DEADLOCK)))
{
return;
}
// Get error info
$sUser = UserRights::GetUser();
$oError = self::$m_oMysqli->query('SHOW ENGINE INNODB STATUS');
if ($oError !== false)
{
$aData = $oError->fetch_all(MYSQLI_ASSOC);
$sInnodbStatus = $aData[0];
}
else
{
$sInnodbStatus = 'Get status query cannot execute';
}
// log !
$sMessage = "deadlock detected: user= $sUser; errno=$iMySqlErrorNo";
$aLogContext = array(
'userinfo' => $sUser,
'errno' => $iMySqlErrorNo,
'ex_msg' => $e->getMessage(),
'callstack' => $e->getTraceAsString(),
'data' => $sInnodbStatus,
);
DeadLockLog::Info($sMessage, $iMySqlErrorNo, $aLogContext);
IssueLog::Error($sMessage, 'DeadLock', $e->getMessage());
}
/**
* If nested transaction, we are not starting a new one : only one global transaction will exist.
*
@@ -805,25 +859,6 @@ class CMDBSource
self::$m_iTransactionLevel = 0;
}
/**
*
* @deprecated 2.7.0 N°1627 use ItopCounter instead
*
* @param string $sTable
*
* @return int
* @throws \MySQLException
* @throws \MySQLHasGoneAwayException
*/
public static function GetNextInsertId($sTable)
{
$sSQL = "SHOW TABLE STATUS LIKE '$sTable'";
$oResult = self::Query($sSQL);
$aRow = $oResult->fetch_assoc();
return $aRow['Auto_increment'];
}
public static function GetInsertId()
{
$iRes = self::$m_oMysqli->insert_id;
@@ -1194,9 +1229,9 @@ class CMDBSource
*/
private static function GetFieldDataTypeAndOptions($sCompleteFieldType)
{
preg_match('/^([a-zA-Z]+)(\(([^\)]+)\))?( .+)?$/', $sCompleteFieldType, $aMatches);
preg_match('/^([a-zA-Z]+)(\(([^\)]+)\))?( .+)?/', $sCompleteFieldType, $aMatches);
$sDataType = $aMatches[1];
$sDataType = isset($aMatches[1]) ? $aMatches[1] : '';
$sTypeOptions = isset($aMatches[2]) ? $aMatches[3] : '';
$sOtherOptions = isset($aMatches[4]) ? $aMatches[4] : '';
@@ -1390,7 +1425,7 @@ class CMDBSource
* @return string query to upgrade table charset and collation if needed, null if not
* @throws \MySQLException
*
* @since 2.5 N°1001 switch to utf8mb4
* @since 2.5.0 N°1001 switch to utf8mb4
* @see https://dev.mysql.com/doc/refman/5.7/en/charset-table.html
*/
public static function DBCheckTableCharsetAndCollation($sTableName)
@@ -1540,7 +1575,7 @@ class CMDBSource
* @return string query to upgrade database charset and collation if needed, null if not
* @throws \MySQLException
*
* @since 2.5 N°1001 switch to utf8mb4
* @since 2.5.0 N°1001 switch to utf8mb4
* @see https://dev.mysql.com/doc/refman/5.7/en/charset-database.html
*/
public static function DBCheckCharsetAndCollation()

View File

@@ -1,35 +1,44 @@
<?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/>
/**
* Copyright (C) 2010-2020 Combodo SARL
*
* This file is part of iTop.
*
* iTop is free software; you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* iTop is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with iTop. If not, see <http://www.gnu.org/licenses/>
*/
/**
* Any extension to compute things like a stop watch deadline or working hours
* 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
* Metric computing for stop watches.
* Can be used for AttributeStopWatch goal (iTop XML node xpath: /itop_design/classes/class/fields/field/goal)
*/
interface iMetricComputer
{
public static function GetDescription();
/**
* @param \DBObject $oObject
*
* @return float number of seconds for the time limit
*/
public function ComputeMetric($oObject);
}
@@ -41,21 +50,21 @@ 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
* @param DBObject $oObject The object for which to compute the deadline
* @param integer $iDuration The duration (in seconds) in the future
* @param DateTime $oStartDate The starting point for the computation
*
* @return DateTime The date/time corresponding to a given delay in the future from the present
* considering only the valid (open) hours for a specified object
*/
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
* @param DBObject $oObject The object for which to compute the duration
* @param DateTime $oStartDate The starting point for the computation (default = now)
* @param DateTime $oEndDate The ending point for the computation (default = now)
*
* @return integer The duration (number of seconds) elapsed between two given dates, considering only open hours
*/
public function GetOpenDuration($oObject, DateTime $oStartDate, DateTime $oEndDate);
}
@@ -87,12 +96,7 @@ class DefaultWorkingTimeComputer implements iWorkingTimeComputer
}
/**
* 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
* @inheritDoc
*/
public function GetDeadline($oObject, $iDuration, DateTime $oStartDate)
{
@@ -113,11 +117,7 @@ class DefaultWorkingTimeComputer implements iWorkingTimeComputer
}
/**
* 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
* @inheritDoc
*/
public function GetOpenDuration($oObject, DateTime $oStartDate, DateTime $oEndDate)
{
@@ -134,6 +134,3 @@ class DefaultWorkingTimeComputer implements iWorkingTimeComputer
return $iDuration;
}
}
?>

File diff suppressed because it is too large Load Diff

View File

@@ -28,31 +28,39 @@
class CoreException extends Exception
{
public function __construct($sIssue, $aContextData = null, $sImpact = '')
/**
* CoreException constructor.
*
* @param string $sIssue error message
* @param array|null $aContextData key/value array, value MUST implements _toString
* @param string $sImpact
* @param Exception|null $oPrevious
*/
public function __construct($sIssue, $aContextData = null, $sImpact = '', $oPrevious = null)
{
$this->m_sIssue = $sIssue;
$this->m_sImpact = $sImpact;
$this->m_aContextData = $aContextData ? $aContextData : array();
if (is_array($aContextData)) {
$this->m_aContextData = $aContextData;
} else {
$this->m_aContextData = [];
}
$sMessage = $sIssue;
if (!empty($sImpact)) $sMessage .= "($sImpact)";
if (count($this->m_aContextData) > 0)
{
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))
{
foreach ($this->m_aContextData as $sKey => $value) {
if (is_array($value)) {
$aPairs = array();
foreach($value as $key => $val)
{
if (is_array($val))
{
foreach ($value as $key => $val) {
if (is_array($val)) {
$aPairs[] = $key.'=>('.implode(', ', $val).')';
}
else
{
} else {
$aPairs[] = $key.'=>'.$val;
}
}
@@ -66,7 +74,7 @@ class CoreException extends Exception
}
$sMessage .= implode(', ', $aContextItems);
}
parent::__construct($sMessage, 0);
parent::__construct($sMessage, 0, $oPrevious);
}
/**
@@ -81,6 +89,16 @@ class CoreException extends Exception
return $this->getMessage();
}
/**
* getTraceAsString() cannot be overrided and it is limited as only current exception stack is returned.
* we need stack of all previous exceptions
* @uses __tostring() already does the work.
* @since 2.7.2/ 3.0.0
*/
public function getFullStackTraceAsString(){
return "" . $this;
}
public function getTraceAsHtml()
{
$aBackTrace = $this->getTrace();
@@ -115,7 +133,7 @@ class CoreException extends Exception
* @see \DBObject::DBInsertNoReload()
* @see \DBObject::DBUpdate()
*
* @since 2.6 N°659 uniqueness constraint
* @since 2.6.0 N°659 uniqueness constraint
*/
class CoreCannotSaveObjectException extends CoreException
{

View File

@@ -301,7 +301,7 @@ EOF
}
while($aRow = $oSet->FetchAssoc())
{
set_time_limit($iLoopTimeLimit);
set_time_limit(intval($iLoopTimeLimit));
$aData = array();
foreach($this->aStatusInfo['fields'] as $iCol => $aFieldSpec)
{
@@ -339,7 +339,7 @@ EOF
// Restore original date & time formats
AttributeDateTime::SetFormat($oPrevDateTimeFormat);
AttributeDate::SetFormat($oPrevDateFormat);
set_time_limit($iPreviousTimeLimit);
set_time_limit(intval($iPreviousTimeLimit));
$this->aStatusInfo['position'] += $this->iChunkSize;
if ($this->aStatusInfo['total'] == 0)
{

View File

@@ -135,7 +135,7 @@ class CSVParser
// More time for the next row
if ($this->m_iTimeLimitPerRow !== null)
{
set_time_limit($this->m_iTimeLimitPerRow);
set_time_limit(intval($this->m_iTimeLimitPerRow));
}
}
protected function __AddCellTrimmed($c = null, $aFieldMap = null)
@@ -194,7 +194,7 @@ class CSVParser
{
// Give some time for the first row
$iTimeLimit = ini_get('max_execution_time');
set_time_limit($this->m_iTimeLimitPerRow);
set_time_limit(intval($this->m_iTimeLimitPerRow));
}
for($i = 0; $i <= $iDataLength ; $i++)
{
@@ -255,7 +255,7 @@ class CSVParser
if ($iTimeLimit !== null)
{
// Restore the previous time limit
set_time_limit($iTimeLimit);
set_time_limit(intval($iTimeLimit));
}
return $this->m_aDataSet;
}

View File

@@ -1,11 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<itop_design xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="1.6">
<itop_design xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="3.0">
<user_rights>
<profiles>
<profile id="1024" _delta="define">
<name>REST Services User</name>
<description>Only users having this profile are allowed to use the REST Web Services (unless 'secure_rest_services' is set to false in the configuration file).</description>
<groups />
<description>Only users having this profile are allowed to use the REST Web Services (unless 'secure_rest_services' is set to false
in the configuration file).
</description>
<groups/>
</profile>
</profiles>
</user_rights>

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