Compare commits

..

196 Commits

Author SHA1 Message Date
jf-cbd
6105255d76 Improve logs readability 2025-03-06 11:46:00 +01:00
jf-cbd
f3909eb50a Improve tests readability 2025-03-06 10:41:52 +01:00
jf-cbd
7f2a1a6416 N°4459 and N°7640 - Workaround for sodium default encrypted key invalid 2025-03-06 10:41:26 +01:00
jf-cbd
32dbf1490c WIP 2025-03-05 17:24:28 +01:00
jf-cbd
2dc9f5dcc6 WIP 2025-03-05 16:49:51 +01:00
jf-cbd
200b148c86 WIP 2025-03-05 16:28:29 +01:00
jf-cbd
6fcbf68013 WIP 2025-03-05 15:44:22 +01:00
jf-cbd
2fedfa1b4c WIP 2025-03-05 14:35:51 +01:00
jf-cbd
755ac3a15c WIP 2025-03-03 18:28:15 +01:00
jf-cbd
01e2d3b317 WIP 2025-03-03 17:27:36 +01:00
jf-cbd
39fd258544 Fix tests 2025-03-03 15:43:10 +01:00
jf-cbd
f58a2be620 N°8231 - making rest api log more readable 2025-03-03 15:00:54 +01:00
jf-cbd
e8c622a15d Making JSON more readable 2025-02-28 16:35:59 +01:00
jf-cbd
783fa01fc9 Fix tests 2025-02-28 16:19:09 +01:00
jf-cbd
b1f49ae487 Clean test 2025-02-28 15:51:11 +01:00
jf-cbd
896069d64b WIP 2025-02-28 11:45:44 +01:00
jf-cbd
85434578d3 WIP 2025-02-28 11:00:24 +01:00
jf-cbd
e142fba0e6 WIP 2025-02-28 10:50:06 +01:00
jf-cbd
c9f32311b4 WIP 2025-02-27 17:56:46 +01:00
jf-cbd
a9e10742ec WIP 2025-02-27 17:26:14 +01:00
jf-cbd
cb2a093498 WIP 2025-02-27 16:00:58 +01:00
denis.flaven@combodo.com
944b1f557d Work in progress 2025-02-27 12:17:52 +01:00
denis.flaven@combodo.com
affed69999 Version number bump. 2025-02-07 10:09:48 +01:00
denis.flaven@combodo.com
d5754fc568 N°8135 - Bump datamodel version. 2025-01-31 17:04:56 +01:00
jf-cbd
44290db312 N°8134 - Portal user profile is broken, regression from 7776 2025-01-28 10:23:44 +01:00
jf-cbd
c49ceae75e Fix HandleForm call 2025-01-21 16:46:15 +01:00
jf-cbd
8980f627e9 Fix format 2025-01-21 12:09:06 +01:00
jf-cbd
160bfd714b N°7776 remove twig from ajax calls 2025-01-20 15:41:22 +01:00
jf-cbd
8d58372074 Update unattended installation script documentation 2025-01-16 17:13:26 +01:00
Eric Espie
37fc1a5723 N°7810 - security hardening 2024-12-27 09:04:28 +01:00
jf-cbd
95aa444ee6 Security hardening 2024-12-13 16:48:13 +01:00
jf-cbd
f5de808c7c Security hardening (#685)
* security hardening
2024-12-13 15:09:18 +01:00
Benjamin Dalsass
e03033ce52 N°7219 - Fatal error following dashboard modification when dashboard title contains an é 2024-11-27 09:40:22 +01:00
jf-cbd
374b35f78a 🚀 Fix GitHub action 2024-11-07 14:50:46 +01:00
jf-cbd
04bd8cc5ce 🚀 Update GitHub actions to improve PR classification 2024-10-22 16:07:47 +02:00
denis.flaven@combodo.com
8cb701bda3 🔖 Prepare 2.7.11 version 2024-09-26 16:53:24 +02:00
jf-cbd
1b29746806 Rename github token 2024-09-23 17:14:41 +02:00
jf-cbd
fb9c317256 Add an action in the workflow to automatically add pull requests to the Combodo PRs dashboard 2024-09-23 14:43:33 +02:00
Eric Espie
0904a21e3f Cleanup ItopTestCase 2024-06-24 11:50:37 +02:00
Molkobain
82d11eeb47 N°7127 - Upgrade handlebars.js to v4.7.8 2024-06-21 11:19:39 +02:00
Eric Espie
142d6c8993 N°7533 - Detect and warns on Galera clusters 2024-06-20 11:06:57 +02:00
Timothee
320922a13d N°7545 Correctly display error message 2024-06-17 16:49:33 +02:00
Eric Espie
f03d731b1d N°7533 - Prevent installation of iTop on Galera clusters 2024-06-12 16:14:23 +02:00
Eric Espie
8be7628668 N°7548 - Code hardening 2024-05-29 18:11:36 +02:00
Eric Espie
62caf16153 N°7364 - Code hardening 2024-05-21 14:20:30 +02:00
odain
163a3afc0f N°7426 - no session created - replace php_sapi_name() by PHP_SAPI in unattended 2024-05-16 15:31:08 +02:00
odain
f8b54be896 N°7426 - no session created - replace php_sapi_name() by PHP_SAPI 2024-05-16 14:10:54 +02:00
Romain Quetiez
53dc452d61 Avoid unnecessary custom test environment compilations (base compilation of file modification time) 2024-05-16 09:53:04 +02:00
Romain Quetiez
ccaf2dc5b7 Make the tests compatible with windows (and linux) 2024-05-16 09:53:04 +02:00
Molkobain
5d5df5ad1a N°7255 - Fix misc. stylesheets not working in portal since N°7047 2024-05-07 10:37:39 +02:00
Molkobain
32140b360f Cherry pick fixes from 59a955f4 2024-04-29 11:45:09 +02:00
jf-cbd
d85767a838 Update test to run only on commmunity builds 2024-04-24 11:14:40 +02:00
jf-cbd
eeec57536b Security hardening 2024-04-23 11:55:39 +02:00
Molkobain
16ff6341d0 N°7455 - Fix regression from 4c784886, wrong class tested 2024-04-19 09:14:53 +02:00
Molkobain
9dab8679d6 N°7448 - Update dictionary entry 2024-04-18 18:44:20 +02:00
Molkobain
4c78488644 N°7455 - Ensure form renderer class extends FormRenderer 2024-04-18 18:15:02 +02:00
odain
b65e931c4c N°7439 - setup wizard broken on essential targets after fresh install via unattended CLI 2024-04-15 09:57:54 +02:00
odain
6cb3519308 N°7407 - test readability 2024-04-12 16:59:56 +02:00
odain
cfb9fae648 N°7407 - fix previous commit 2024-04-12 16:49:11 +02:00
odain
f4e791734f N°7407 - remove phpunit annotation 2024-04-12 14:49:20 +02:00
odain
6653ab0668 N°7407 - fix missing extension installation via unattended from production-modules or extension folder 2024-04-12 13:25:40 +02:00
odain
7ab258ba03 N°7439 - setup wizard broken on essential targets 2024-04-12 11:32:04 +02:00
odain
b5af30a93f N°7407 - refactor unattended tests to make work anywhere 2024-04-12 11:32:04 +02:00
Molkobain
bbfa601ab1 N°7446 - Add temporary workaround to fix an issue due to DB views creation. 2024-04-12 09:59:14 +02:00
odain
172b1cb1ff N°7407 - add phpunit annotation to exclude tests on top of targets 2024-04-11 18:54:43 +02:00
Molkobain
ca356859a3 N°7446 - Add comment for better understanding 2024-04-11 16:55:48 +02:00
Molkobain
5efe294895 N°7446 - Fix custom datamodel test class not creating DB tables correctly 2024-04-11 16:50:27 +02:00
odain
e0170ccc7e N°7407 - InstallationFileServiceTest relies on local installation.xml to reduce maintenance 2024-04-10 14:05:39 +02:00
odain
3b78885f38 N°7407 - unattended test cleanup for PHP 8.x deprecations 2024-04-09 11:06:03 +02:00
odain
ed562c9f73 N°7407 - fix unattended test enhancement 2024-04-09 10:02:06 +02:00
odain-cbd
85c576a986 N°7407 - N°7306 - Ease iTop installation via unattended CLI by using installation.xml choices (#641)
* N°7306 - Use iTop configuration settings to run unattended installation (instead of XML file settings)

* 7306 - fix infinite loop with db_tls.ca null

* 7306 - complete fields to use from itop configuration instead of XML setup

* fix using default language from conf

* 6365 - temp work

* 6365 - add option to select modules from installation.xml

* 6365-select modules option in unattended install

* 6365 - pass env to service + debug failed test

* 6365 - debug ci again + separate process annotation

* 6365 - fix test + cleanup

* 6365 - ci using use_installation_xml mode

* 6365 - ci using use_installation_xml mode

* 6365 - pass selected_modules to unattended

* N°6365 - Compute selected modules based on selected extensions coming from XML setup

* switch constr parameters and fix call from unattended cli

* 6365 - use use_installation_xml for unattended install only when no selected modules already provided

* test ci XML setup including selected extensions but no modules

* test ci installing iTop without selected modules/extenesions: guess via installation.xml

* same but without even providing XML setup - comment it in ci_description.ini

* 7306 - cleanup requires

* use infra master

* N°6365 - make current unattended CLI work with any iTop version (CLIPage compatibility)

* N°6365 - log which modules will be installed during setup

* N°6365 - unattended documentation + bash helper

* 6365- fix warning due to copies index access

* 6365 - enhance traces feedback to understant which and how modules are computes

* 6365 - enhance bash CLI + doc

* 6365 - fix require clipage compatibility

* 6365 - add return for better cli ouput

* 6365 - enhance ouput messages

* Document the usage and harmonize argument names (still not perfect)

* 6365 - fix use of new param param-file

* 6365 - fix test + vardump cleanup

* N°6365 - use underscore for unattended install options as advices in the PR

* 6365 -enhance test by using PHP_BINARY

---------

Co-authored-by: Romain Quetiez <romain.quetiez@combodo.com>
2024-04-09 10:00:58 +02:00
odain-cbd
5a34c76cc4 N°5120 - Unattended install : use cty toolkit version (#624)
* N°5120 - Unattended install : use cty toolkit version

* N°5120 - CLI mode validation

* 5120 - bring CI enhancements

* 5120 - bring back saas use-itop-config option: to read db settings from conf directly

* 5120 - move unattended script in setup folder/unattended-install

* 5120 - use-itop-config option: take db_tls_enabled and db_tls_ca into account

* 5120 - move test

* 5120 - put ci enhancements back - logs and conf preservation with install mode

* 5120 - keep PR simple - remove saas use-itop-config option for now

* 5120 - remove ci enhancement to preserve configuration

* Update setup/unattended-install/README.md

Co-authored-by: Thomas Casteleyn <thomas.casteleyn@super-visions.com>

* 5120 - documentation

* 5120 - fix log level

* 5120 - fix test

* fix phpunit test comment

---------

Co-authored-by: Thomas Casteleyn <thomas.casteleyn@super-visions.com>
2024-03-29 11:09:27 +01:00
Molkobain
da99a250bf N°7075 - Add check for Content Security Policies (CSP) in the setup 2024-03-21 14:20:22 +01:00
Pierre Goiffon
dbd5ba0377 N°7302 Fix SetupUtilsTest::testHumanReadableSize 2024-03-13 09:56:31 +01:00
Pierre Goiffon
5d6f293956 N°7302 Report SetupUtilsTest::testHumanReadableSize in the 2.7 branch 2024-03-13 09:48:46 +01:00
Pierre Goiffon
986c24d777 N°7302 Fix unit name in \SetupUtils::HumanReadableSize (#626) 2024-03-12 18:09:29 +01:00
Pierre Goiffon
763112c179 N°7344 rest.php core/get : add try/catch around query execution (#622)
Co-authored-by: Thomas Casteleyn <thomas.casteleyn@super-visions.com>
Co-authored-by: Molkobain <lajarige.guillaume@free.fr>
2024-03-12 18:08:04 +01:00
Pierre Goiffon
a5efd981d8 N°7343 Catch ParseError when loading dict files in setup (#615) 2024-03-12 18:05:38 +01:00
Pierre Goiffon
2922b22478 \DBObject::GetSearchForUniquenessRule remove wrong @api 2024-03-12 17:34:28 +01:00
Pierre Goiffon
2af05a437e N°4314 - Fix Uniqueness rules not working with Silo
(cherry picked from commit e8c11f38d2)
2024-03-12 17:32:56 +01:00
Molkobain
a9f8dcc5e8 N°7122 N°4164 - Portal: Hide log off button when user can't actually log off (eg. SSO using SAML or other providers) (#599)
* N°7122 N°4164 - Portal: Hide log off button when user can't actually log off (eg. SSO using SAML or other providers)

* N°7122 - Fix typo

Co-authored-by: Thomas Casteleyn <thomas.casteleyn@super-visions.com>

---------

Co-authored-by: Thomas Casteleyn <thomas.casteleyn@super-visions.com>
2024-03-11 21:13:09 +01:00
Pierre Goiffon
c325294e17 N°6599 Update moment from 2.22.2 to 2.30.1 2024-03-11 16:39:05 +01:00
Pierre Goiffon
da490739be 💡 Fix \CMDBSource::Query phpdoc block 2024-03-07 11:10:53 +01:00
Pierre Goiffon
b867faa355 Fix DBObjectTest
Error was "Class 'Combodo\iTop\Test\UnitTest\Core\DBObjectSet' not found"
2024-03-04 08:09:35 +01:00
jf-cbd
7453cc184f ✏️ fix a typo 2024-03-01 17:25:08 +01:00
Anne-Catherine
473cf004b6 N°6968 - Audit duration : add of a rule multiplie by 4 the time of response (#575) 2024-02-29 16:33:04 +01:00
Pierre Goiffon
f6fec506b1 💡 Some PHPDoc hints on value types to pass to DBObject::Set 2024-02-20 12:10:00 +01:00
Molkobain
5c12151c26 📝 Update PR template 2024-02-19 09:46:12 +01:00
Pierre Goiffon
5d6c4939f6 N°7245 Bettor logs on RunTimeEnvironment::CallInstallerHandlers exceptions (#606) 2024-02-14 11:01:12 +01:00
Molkobain
1b3a2c8470 N°5775 - Show error message to user in case of issue during token generation 2024-01-24 14:49:51 +01:00
Dennis Lassiter
618d8e6468 N°5775 - Allow configuration of OAuth client on MS Azure with single tenant (#553)
* Add Tenant-Support for Azure OAuthClient

* Improvement: Make tenant required

* Improvment: Removed check for null-value

Since last commit, the "tenant"-field either set to a custom value or "common" by default. It is not allowed to be null

* Add field description

---------

Co-authored-by: Molkobain <lajarige.guillaume@free.fr>
2024-01-24 14:38:54 +01:00
Molkobain
01a955a16f 📝 Add PR template 2024-01-16 19:42:39 +01:00
Anne-Catherine
87582a021b N°6993 - Error message on bulk transition on object containing a null blob (#596) 2024-01-15 15:49:19 +01:00
odain
9830178a47 N°7085 - ci restore runTestsInSeparateProcesses 2024-01-12 08:36:15 +01:00
odain-cbd
c140ebcb6b N°7085 - Fix infinite loop in login page until fatal error occurs (#592)
* N°7085 - login page infinite loop until fatal error- add Config->AddAllowedLoginTypes

* N°7085 - reproduce issue via a test

* N°7085-fix infinite loop

* N°7085 - ci: fix config file rights in tearDown

* N°7085 - ci: fix config file rights in tearDown (again)

* N°7085 - ci: fix config file content

* N°7085 - ci : add runTestsInSeparateProcesses

* Update core/config.class.inc.php

Co-authored-by: Molkobain <lajarige.guillaume@free.fr>

* N°7085 - exit -1 + enhance log message

* PR feedbacks from Romain regarding LoginTest annotations

---------

Co-authored-by: Molkobain <lajarige.guillaume@free.fr>
2024-01-12 08:13:40 +01:00
Molkobain
7a0a4e377b N°7137 - Fix regression from 7fffbb60, missing "default_value" parameter 2024-01-11 16:40:40 +01:00
Thomas Casteleyn
7fffbb60e9 N°7137 - DataSynchro: Remove "Organization" as default value for SynchroReplica->dest_class (#551) 2024-01-11 15:38:02 +01:00
Pierre Goiffon
2fd9523c16 🔖 Prepare 2.7.10 version 2024-01-05 15:50:41 +01:00
Pierre Goiffon
a4f6f6e877 N°4368 Fix CORB blocking regression (#598)
Don't send X-Content-Type-Options HTTP header for certain WebPage impl to workaround CORB blocking
To disable globally this new behavior introduced in 9865bf07, set the `security.enable_header_xcontent_type_options` config parameter to false

Thanks @Molkobain for the review !
2024-01-05 10:41:18 +01:00
Molkobain
94c604a6af N°3062 - Fix setup.css compilation test to ensure that it is versioned correctly. 2023-12-21 12:00:26 +01:00
Pierre Goiffon
6995a3c641 N°6889 backup mysqldump call : restore possibility to connect using socket protocol (#591)
With previous fix (N°6123) we forced to use the tcp protocol each time. This was blocking for users wanting to connect using the socket protocol on localhost.

Now for localhost we will : 
- send both port and protocol arguments if the `db_host` config parameter does contain a port
- don't send any of the port or protocol arguments if `db_host` doesn't contain a port
2023-12-20 15:19:50 +01:00
Pierre Goiffon
9865bf0779 N°4368 add sending X-Content-Type-Options HTTP header
Replace in consumers the \WebPage::add_xframe_options call by \WebPage::add_http_headers
2023-12-19 18:25:26 +01:00
Pierre Goiffon
d5449cca42 💡 iTopMutex: add link to mysql doc 2023-12-08 17:20:37 +01:00
Molkobain
5d38d22c50 N°7023 - Fix regression from the initial fix that throw exceptions even for ext. keys set programatically (eg. ComputeValues), which we still want to allow 2023-12-06 16:27:37 +01:00
Pierre Goiffon
99d69493d1 N°7023 - Update tests so that we are now checking negative ext. keys 2023-12-04 22:36:26 +01:00
Molkobain
c9bb628c30 N°7023 - Improve debug message on portal \DBObject::CheckChangedExtKeysValues() call 2023-12-04 22:36:09 +01:00
Molkobain
08e8d15d78 N°7023 - Fix check to write error when adding a contact on a new user request on the end-users portal 2023-12-04 22:35:07 +01:00
Molkobain
7b59df216b N°7005 - Fix portal stylesheets not being re-compiled when outdated
Stylesheets should remain as a relative path in the portal configuration, only when consumed by the TWIG should they become URLs

Note that if not absolute, URLs will be append to ITOP/pages/
2023-11-24 16:40:58 +01:00
Molkobain
cb5eab812e N°938 - Update compiled portal stylesheet 2023-11-24 16:22:36 +01:00
Anne-Catherine
c9b73a7fe2 N°938 - Improve print of portal object page and portal dashboard page (#537)
N°938 - Improve print of portal object page and portal dashboard page
2023-11-24 15:17:42 +01:00
Molkobain
3b2da39469 N°6989 - Security hardening 2023-11-22 18:02:50 +01:00
odain
fc22d91232 N°6949 - Run subset of itop core unit tests after the setup when validating a module github code 2023-11-22 10:14:58 +01:00
Stephen Abello
b10bcb976d N°6951 - Security hardening 2023-11-21 09:42:11 +01:00
Pierre Goiffon
5a43448644 N°6458 Security hardening 2023-11-15 11:14:07 +01:00
Pierre Goiffon
77409eed99 🎨 DBObject small phpdoc fixes 2023-11-13 16:25:37 +01:00
Anne-Catherine
83a70daf68 N°6887 - Fix excessive OQL requests to display user's grant matrix (#564)
* N°6887 - Fix excessive OQL requests to display user's grant matrix

* N°6887 - Rename variable and add PHPDoc

---------

Co-authored-by: Molkobain <lajarige.guillaume@free.fr>
2023-11-08 14:57:28 +01:00
Molkobain
a49a4e6c2b N°6886 - Add OAuth tests folder to removable directories list 2023-10-30 16:54:28 +01:00
Romain Quetiez
7419749ba6 Prerequisites for boosting tests 2023-10-26 20:51:28 +02:00
Romain Quetiez
037dfe1df6 Optimize tests execution time 2023-10-25 17:51:12 +02:00
Romain Quetiez
0b26d45014 Prerequisites for boosting tests 2023-10-25 17:50:41 +02:00
Molkobain
4fd8177165 N°3715 - Fix unit tests 2023-10-23 14:55:06 +02:00
Anne-Catherine
a2cdf214f0 N°3715 - Export above 1000 entries ignore obsolete data from user preference (#468)
* N°3715 - Export above 10000 entries ignore obsolete data from user preference
2023-10-20 17:02:16 +02:00
Anne-Catherine
013173019f N°2909 - Search on Enum, Date, TagSet,... with index fails (#496) 2023-10-20 16:45:35 +02:00
Stephen Abello
9469681a0c N°6777 - Security hardening 2023-10-17 09:12:40 +02:00
Pierre Goiffon
c72cb7e70e N°6606 security hardening 2023-10-13 17:15:37 +02:00
Pierre Goiffon
9df92665e0 N°6606 Backport of utils::ENUM_SANITIZATION_FILTER_* constants
Were introduced in 3.0.0, but not added to the support/2.7 branch
2023-10-13 17:10:35 +02:00
Molkobain
8ecebee511 PHP unit tests: Fix typo for "final private" methods as they can't be both 2023-09-20 16:11:39 +02:00
Pierre Goiffon
35cd965360 N°6629 Update ci_description php_version 2023-09-19 12:25:40 +02:00
Pierre Goiffon
e5dd51f637 N°6600 Portal download attachment : don't display anymore SQL query on attachment not found error (#525) 2023-09-19 09:54:43 +02:00
Molkobain
0a6c82dfe1 N°6752 - PHP unit tests: Fix typo in postbuild_integration.xml.dist 2023-09-19 08:37:46 +02:00
Molkobain
24c0f4950f Add missing .htaccess / web.config files in .gitignore for /extensions folder 2023-09-18 15:26:06 +02:00
Molkobain
d4dbbc59d4 N°6754 - PHP unit tests: Add local PHPUnit XML files to .gitignore 2023-09-18 15:23:52 +02:00
Molkobain
dc0cd44c79 N°6752 - PHP unit tests: Migrate usages of unitestautoload.php to composer autoloader 2023-09-18 15:14:44 +02:00
odain
6c6131ce03 N°5491 - test enhancement to reduce false positive 2023-09-15 10:07:42 +02:00
odain-cbd
e76728b2bf N°5491 - Inconsistent dictionnary entries regarding arguments to pass to Dict::Format-test first (#545) 2023-09-13 12:02:49 +02:00
Pierre Goiffon
e946fc65fc N°6709 New ItopTestCase::RequireOnceCurrentModuleFile 2023-09-07 14:38:19 +02:00
Pierre Goiffon
0d8ff7bbac N°6629 Set commit tests back to Mysql
For now we have perf issues on Jenkins with MariaDB (see N°6694)
2023-09-04 10:25:41 +02:00
Anne-Catherine
bf768311c2 N°5136 - "Select All objects" add obsolete objects even if the parameter show obsolete data is not activated (#467) 2023-08-31 15:13:20 +02:00
Molkobain
a8c689c6c0 N°6436 - Add unit test to ensure that we don't lose an API during merge between branches 2023-08-18 09:55:45 +02:00
Molkobain
1990ccb5d8 N°6436 - Move interfaces enumeration from 1 line to 1 line / interface (and re-ordered them) for easier merges in newer branches 2023-08-18 09:52:55 +02:00
Molkobain
e107be56e4 N°6097 - Tests: Fix missing hook entry in PHPUnit XML file that led to compiled environment being re-build for each test case 2023-08-18 09:51:15 +02:00
Molkobain
ed6df77cbb N°6097 - Tests: Optimize performances by creating custom env. only once and re-using it across test classes 2023-08-10 15:45:39 +02:00
Molkobain
1ad28312ec N°6097 - Tests: Introduce autoloader for "utility" classes and move them to a sub-folder for better organization as folder was still messy
Note that unittestautoload.php is now useless. We just keep for now until everything is migrated (projects / branches / modules)
2023-08-10 15:45:39 +02:00
Molkobain
f002aa04cd N°6097 - Tests: Enable PHP unit tests on a custom DataModel 2023-08-10 15:45:39 +02:00
Molkobain
b86d70623e N°6097 - Tests: Temporarily add test case for the new ItopCustomDatamodelTestCase class 2023-08-10 15:45:39 +02:00
Molkobain
fe3467309d N°6097 - Tests: Refactor base test classes for better extensibility 2023-08-10 15:45:39 +02:00
Molkobain
851ab9c356 N°6097 - Add \utils::GetDataPath() method to avoid duplicating manual path build 2023-08-10 15:45:39 +02:00
Molkobain
aef3c2e609 N°6097 - Fix \CMDBSource::DropDB() not resetting cache like \CMDBSource::DropTable() which can lead to errors when trying to re-create it afterwards 2023-08-10 15:45:39 +02:00
Pierre Goiffon
6d13397ba1 Add other integration tests in the beforeSetup group
All of those tests can be ran without a running iTop instance, and are blocking
2023-08-08 15:33:09 +02:00
Pierre Goiffon
c0c8a13864 💡 \MetaModel::GetObject : remove documented throw Exception 2023-08-04 14:55:38 +02:00
Pierre Goiffon
cd9beec313 Merge remote-tracking branch 'origin/support/2.6' into support/2.7 2023-07-26 12:07:09 +02:00
Pierre Goiffon
8295eaed90 Merge remote-tracking branch 'origin/support/2.5' into support/2.6 2023-07-26 12:06:32 +02:00
Eric Espie
5475b9fbbe N°3454 - MoveToProd in 2 steps - fix utils::GetCurrentModuleName() 2023-07-25 17:44:43 +02:00
Eric Espie
6f8e7c7002 N°3454 - MoveToProd in 2 steps - fix utils::GetCurrentModuleUrl() 2023-07-25 17:20:37 +02:00
Pierre Goiffon
bc7c1b4744 N°6590 Fix DictionariesConsistencyTest for PL dict files 2023-07-24 11:14:37 +02:00
Eric Espie
4d8246c4d8 N°6436 - Integrate Performance Audit pre requisite in iTop Pro 2.7.9 (changed config variable name) 2023-07-19 15:13:43 +02:00
Eric Espie
5c61d725e1 N°6436 - Integrate Performance Audit pre requisite in iTop Pro 2.7.9 (changed config variable name) 2023-07-19 15:06:00 +02:00
Eric Espie
2c4cad4dac N°6436 - Integrate Performance Audit pre requisite in iTop Pro 2.7.9 (avoid unnecessary calls) 2023-07-19 10:37:41 +02:00
Eric Espie
da45651121 Merge branch 'feature/6548_Hide_DBHost_and_DBUser_in_log' into support/2.7 2023-07-18 09:34:48 +02:00
Eric Espie
d388ce9a06 Merge branch 'feature/6548_Hide_DBHost_and_DBUser_in_log' into support/2.7 2023-07-18 09:17:40 +02:00
Eric Espie
47e71d8838 Merge branch 'feature/6436-Integrate_Performance_Audit_extensibility' into support/2.7 2023-07-18 09:17:05 +02:00
Stephen Abello
2b5973ec67 N°6436 - Integrate Performance Audit pre requisite in iTop Pro 2.7.9 2023-07-18 09:15:37 +02:00
Eric Espie
78396d8e4a 6548 - [ER] Hide DBHost and DBUser in log 2023-07-10 17:37:27 +02:00
Stephen Abello
9afc22bd8f N°6123 - Add tests and comments 2023-07-07 09:29:15 +02:00
Pierre Goiffon
264a8cd70a N°6494 - Some tests are run twice, some never
(cherry picked from commit a2a0b2cd0b)

(cherry picked from commit 4c9ea0c9d4)

# Conflicts:
#	tests/php-unit-tests/integration-tests/DictionariesConsistencyTest.php
2023-07-06 15:45:09 +02:00
Stephen Abello
aa1834170b N°6427 - Fix SwiftMailer not retrieving sendmail path 2023-07-06 14:31:54 +02:00
Stephen Abello
f94d67ab35 N°6340 - Fix permission refused when sending an email and renewing OAuth token in synchronous mode 2023-07-06 10:28:10 +02:00
Stephen Abello
3048c8c41f N°5560 - Display an error when trying to regenerate an expired OAuth token 2023-07-06 09:52:00 +02:00
Stephen Abello
246e4a9f50 N°6123 - Fix warnings when launching a backup on MariaDB > v10.6.1 with localhost dbhost 2023-07-06 09:28:01 +02:00
Molkobain
6d58adb6dd N°6359 - Fix JS crash due to new version trying to detect MSIE browser through a dependency that we don't have.
Cherry-picked from f889c53d71
2023-07-05 08:41:00 +02:00
Pierre Goiffon
5a0b5364d6 N°4698 setup/phpinfo.php : if no iTop installation then display a proper message instead of an exception (#265) 2023-06-14 10:18:38 +02:00
Pierre Goiffon
76eed2eba0 N°6098 updateLicenses script : check availability of the required JQ command (#458)
This packaging script requires both bash and the JQ command when running on Windows.
If the later isn't available, it will run without throwing an error...

With this change the script will now check directly at launch for the JQ command availability, and exit in error if it isn't.
2023-06-14 10:17:00 +02:00
Eric Espie
1ec671ef61 N°6351 - code hardening 2023-06-14 09:08:42 +02:00
Eric Espie
72716b7ec8 N°6396 - Protect URL display 2023-06-12 11:36:51 +02:00
Eric Espie
4f999de844 N°6359 - ⬆️ Update jQuery BBQ (from https://github.com/cee-chen/jquery-bbq) 2023-06-08 14:30:09 +02:00
odain
ea49c0a87c enable authent-cas in ci 2023-06-07 21:44:17 +02:00
odain
6cc971849b ci: enhance AddProfile 2023-06-07 21:44:00 +02:00
Pierre Goiffon
2405810864 N°6238 Security hardening 2023-06-07 16:45:35 +02:00
Eric Espie
fff46d99fc N°6358 - Login REST API - renamed test 2023-06-07 15:31:51 +02:00
odain
3a891f707c ci: enhance AddProfile test method to work with any User (not only UserLocal) 2023-06-07 15:06:28 +02:00
odain
8b6ea43ebe N°6358 - Login REST API - fix cas + add tests 2023-06-07 15:05:32 +02:00
Eric Espie
90cf7502e8 N°6358 - Login REST API 2023-06-07 10:09:30 +02:00
Eric Espie
c596fa2967 N°6358 - Login API REST 2023-06-07 09:17:24 +02:00
Timothee
a45177410e N°6350 - Fixing phpunit test 2023-06-06 16:47:06 +02:00
Eric Espie
9e96ea2873 N°6350 - code hardening 2023-06-01 15:35:56 +02:00
Eric Espie
1172159745 N°6351 - code hardening 2023-06-01 15:12:50 +02:00
Pierre Goiffon
fa038ded3d N°6254 ItopDataTestCase::CreateUserRequest : fix new argument default value
Was creating error Too few arguments passed
2023-04-26 16:42:27 +02:00
Pierre Goiffon
e7ea1b831c N°6254 ItopDataTestCase::CreateUserRequest : now pass fields values as array
More versatile way of doing things !
2023-04-26 16:22:26 +02:00
Molkobain
4aff65f98b N°6217 - Add accessiblity meta data for title on "Power menu" 2023-04-25 21:51:32 +02:00
acognet
3c94974d9d N°541 - Dashlets: Improve readability when to much labels (pie chart) or too long labels (bar chart) 2023-04-25 12:09:11 +02:00
Molkobain
fbd72b2783 N°6217 - Add accessiblity meta data for title on "Power menu" 2023-04-20 11:03:43 +02:00
Anne-Catherine
4e95ca3c7b N°541 - Dashlets: Improve readability when to much labels (pie chart) or too long labels (bar chart) (#452)
* N°541 - Dashlets: Improve readability when to much labels (pie chart) or too long labels (bar chart)
2023-04-13 11:23:20 +02:00
Pierre Goiffon
1114ed9562 N°6099 DeadLockLog : improve documentation and use existing constants (#441) 2023-04-12 10:21:34 +02:00
Pierre Goiffon
34368fe795 N°6173 \HTMLSanitizer::Sanitize : Fix handling only svg_sanitizer (#450) 2023-04-11 17:52:41 +02:00
Molkobain
0f016d7511 N°6112 - Dashboard: Improve robustness by trimming dashlet ID returned by server 2023-03-17 15:37:57 +01:00
odain
0001e8ffc4 💚 use new ci validation 2020-10-09 10:13:51 +02:00
4147 changed files with 87519 additions and 273636 deletions

View File

@@ -77,20 +77,24 @@ Then, **for a method** of an eligible class:
:notebook: as spaces are used to mark code, the templates (`.doc/phpdoc-templates/combodo-wiki/*`) have very few indentation, thus they are awful to read (sorry).
## Installation
## Installation
```
cd .doc
composer require phpdocumentor/phpdocumentor:~2 --dev
```
## Generation
`./bin/build-doc-object-manipulation` and `./bin/build-doc-extensions` contains examples of doc. generation, beware: they have to be called from the .doc directory:
```shell
cd /path/to/itop/.doc
./bin/build-doc-object-manipulation
```
the resulting documentation is written into `data/phpdocumentor/output`
1. Switch to this directory : `cd /path/to/itop/.doc`
2. `composer install`
3. `./bin/build-doc-object-manipulation`
3. `./bin/build-doc-extensions`
4. Get the generated files from `/path/to/itop/data/phpdocumentor/output`
## Dokuwiki requirements
* the template uses the [wrap plugin](https://www.dokuwiki.org/plugin:wrap).

View File

@@ -1,6 +1,6 @@
#!/bin/sh -x
rm -rf /tmp/phpdoc-twig-cache/ && rm -rf data/phpdocumentor/output/extensions/ && rm -rf data/phpdocumentor/temp/extensions/ && ./vendor/bin/phpdoc -c ./phpdoc-extensions.dist.xml -vvv
rm -rf /tmp/phpdoc-twig-cache/ && rm -rf data/phpdocumentor/output/extensions/ && rm -rf data/phpdocumentor/temp/extensions/ && .doc/vendor/bin/phpdoc -c .doc/phpdoc-extensions.dist.xml -vvv
# now wee need to lowercase every generated file because dokuwiki can't handle uppercase
cd ../data/phpdocumentor/output/extensions/ && for i in $(ls | grep [A-Z]); do mv -i $i $(echo $i | tr 'A-Z' 'a-z'); done
cd data/phpdocumentor/output/extensions/ && for i in $( ls | grep [A-Z] ); do mv -i $i `echo $i | tr 'A-Z' 'a-z'`; done

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 MiB

View File

@@ -11,7 +11,7 @@ tab_width = 4
ij_continuation_indent_size = 8
ij_formatter_off_tag = @formatter:off
ij_formatter_on_tag = @formatter:on
ij_formatter_tags_enabled = true
ij_formatter_tags_enabled = false
ij_smart_tabs = false
ij_visual_guides = 300
ij_wrap_on_typing = true
@@ -78,7 +78,7 @@ 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}]
[{*.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
@@ -280,17 +280,16 @@ ij_javascript_while_brace_force = always
ij_javascript_while_on_new_line = false
ij_javascript_wrap_comments = false
[{*.ctp,*.hphp,*.inc,*.module,*.php,*.php4,*.php5,*.phtml}]
[{*.ctp, *.hphp, *.inc, *.module, *.php, *.php4, *.php5, *.phtml}]
indent_style = tab
ij_continuation_indent_size = 4
ij_smart_tabs = true
ij_wrap_on_typing = false
ij_php_align_assignments = false
ij_php_align_class_constants = true
ij_php_align_class_constants = false
ij_php_align_group_field_declarations = false
ij_php_align_inline_comments = false
ij_php_align_key_value_pairs = true
ij_php_align_match_arm_bodies = false
ij_php_align_multiline_array_initializer_expression = true
ij_php_align_multiline_binary_operation = false
ij_php_align_multiline_chained_methods = false
@@ -299,7 +298,6 @@ ij_php_align_multiline_for = true
ij_php_align_multiline_parameters = false
ij_php_align_multiline_parameters_in_calls = false
ij_php_align_multiline_ternary_operation = false
ij_php_align_named_arguments = false
ij_php_align_phpdoc_comments = false
ij_php_align_phpdoc_param_names = false
ij_php_anonymous_brace_style = end_of_line
@@ -419,7 +417,6 @@ ij_php_see_weight = 3
ij_php_since_weight = 28
ij_php_sort_phpdoc_elements = true
ij_php_space_after_colon = true
ij_php_space_after_colon_in_enum_backed_type = true
ij_php_space_after_colon_in_named_argument = true
ij_php_space_after_colon_in_return_type = true
ij_php_space_after_comma = true
@@ -434,7 +431,6 @@ ij_php_space_before_catch_parentheses = true
ij_php_space_before_class_left_brace = true
ij_php_space_before_closure_left_parenthesis = true
ij_php_space_before_colon = true
ij_php_space_before_colon_in_enum_backed_type = false
ij_php_space_before_colon_in_named_argument = false
ij_php_space_before_colon_in_return_type = false
ij_php_space_before_comma = false
@@ -470,7 +466,6 @@ ij_php_spaces_around_equality_operators = true
ij_php_spaces_around_logical_operators = true
ij_php_spaces_around_multiplicative_operators = true
ij_php_spaces_around_null_coalesce_operator = true
ij_php_spaces_around_pipe_in_union_type = false
ij_php_spaces_around_relational_operators = true
ij_php_spaces_around_shift_operators = true
ij_php_spaces_around_unary_operator = false
@@ -545,6 +540,7 @@ 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
[{*.markdown,*.md}]
ij_visual_guides = none

83
.github/pull_request_template.md vendored Normal file
View File

@@ -0,0 +1,83 @@
<!--
IMPORTANT: Please follow the guidelines within this PR template before submitting it, it will greatly help us process your PR. 🙏
Any PRs not following the guidelines or with missing information will not be considered.
-->
## Base information
| Question | Answer
|---------------------------------------------------------------|--------
| Related to a SourceForge thead / Another PR / Combodo ticket? | <!-- Put the URL -->
| Type of change? | Bug fix / Enhancement / Translations
## Symptom (bug) / Objective (enhancement)
<!--
If it's a bug
- Explain the symptom in details
- If possible put error messages, logs or screenshots (you can paste image directly in this editor).
If it's an enhancement
- Describe what is blocking you, what is the objective with as much details as possible.
- Add screenshots if it's related to UI.
-->
## Reproduction procedure (bug)
<!--
Remove this section only if it's NOT a bug.
Otherwise, explain step by step how to reproduce the issue on a standard iTop Community.
If it requires a custom datamodel, provide the minimal XML delta to reproduce it on a standard iTop Community.
-->
1. On iTop x.y.z <!-- Put complete iTop version (eg. 3.1.0-2) -->
2. With PHP x.y.z <!-- Put complete PHP version (eg. 8.1.24) -->
2. First go there
2. Then do that
3. ...
4. Finally, see that...
## Cause (bug)
<!--
Remove this section only if it's NOT a bug.
Otherwise, explain what is the cause of the issue (where in the code and why)
-->
## Proposed solution (bug and enhancement)
<!--
Explain in details how you are proposing to solve this:
- What did you do in the code and why
- If you changed something in the UI, put before / after screenshots (you can paste image directly in this editor)
-->
## Checklist before requesting a review
<!--
Don't remove these lines, check them once done.
-->
- [ ] I have performed a self-review of my code
- [ ] I have tested all changes I made on an iTop instance
- [ ] I have added a unit test, otherwise I have explained why I couldn't
- [ ] Is the PR clear and detailed enough so anyone can understand digging in the code?
## Checklist of things to do before PR is ready to merge
<!--
Things that needs to be done in the PR before it can be considered as ready to be merged
Examples:
- Changes requested in the review
- Unit test to add
- Dictionary entries to translate
- ...
-->
- [ ] ...
- [ ] ...
- [ ] ...

43
.github/workflows/action.yml vendored Normal file
View File

@@ -0,0 +1,43 @@
name: Add PRs to Combodo PRs Dashboard
on:
pull_request_target:
types:
- opened
jobs:
add-to-project:
name: Add PR to Combodo Project
runs-on: ubuntu-latest
steps:
- name: Check if author is a member of the organization
id: check-membership
run: |
ORG="Combodo"
AUTHOR=$(jq -r .pull_request.user.login "$GITHUB_EVENT_PATH")
RESPONSE=$(curl -s -o /dev/null -w "%{http_code}" -H "Authorization: token ${{ secrets.PR_AUTOMATICALLY_ADD_TO_PROJECT }}" \
"https://api.github.com/orgs/$ORG/members/$AUTHOR")
if [ "$RESPONSE" == "404" ]; then
echo "project_url=https://github.com/orgs/Combodo/projects/5" >> $GITHUB_ENV
echo "is_member=false" >> $GITHUB_ENV
else
echo "project_url=https://github.com/orgs/Combodo/projects/4" >> $GITHUB_ENV
echo "is_member=true" >> $GITHUB_ENV
fi
- name: Add internal tag if member
if: env.is_member == 'true'
run: |
curl -X POST -H "Authorization: token ${{ secrets.PR_AUTOMATICALLY_ADD_TO_PROJECT }}" \
-H "Accept: application/vnd.github.v3+json" \
https://api.github.com/repos/Combodo/iTop/issues/${{ github.event.pull_request.number }}/labels \
-d '{"labels":["internal"]}'
env:
is_member: ${{ env.is_member }}
- name: Add PR to the appropriate project
uses: actions/add-to-project@v1.0.2
with:
project-url: ${{ env.project_url }}
github-token: ${{ secrets.PR_AUTOMATICALLY_ADD_TO_PROJECT }}

19
.gitignore vendored
View File

@@ -1,15 +1,4 @@
################################### 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-*
@@ -32,12 +21,12 @@ tests/*/vendor/*
!/data/.htaccess
!/data/index.php
!/data/web.config
!/data/exclude.txt
!/data/.compilation-symlinks
# iTop extensions
/extensions/**
!/extensions/.htaccess
!/extensions/readme.txt
!/extensions/web.config
# all logs but listing prevention
/log/**
@@ -45,8 +34,10 @@ tests/*/vendor/*
!/log/index.php
!/log/web.config
# PHPUnit cache file
# PHPUnit: Cache file, local XML working copies
/tests/php-unit-tests/.phpunit.result.cache
/tests/php-unit-tests/phpunit.xml
/tests/php-unit-tests/postbuild_integration.xml
# Jetbrains

View File

@@ -1,7 +1,7 @@
<?php
/**
* Copyright (C) 2010-2021 Combodo SARL
* Copyright (C) 2010-2020 Combodo SARL
*
* This file is part of iTop.
*
@@ -27,7 +27,7 @@ $iTopFolder = __DIR__."/../../../";
require_once("$iTopFolder/approot.inc.php");
require_once(APPROOT."/application/utils.inc.php");
if (php_sapi_name() !== 'cli')
if (PHP_SAPI !== 'cli')
{
throw new \Exception('This script can only run from CLI');
}
@@ -48,4 +48,4 @@ if (!file_exists($sCssFile))
{
fwrite(STDERR, "Failed to compile $sCssFile, exiting.");
exit(1);
}
}

View File

@@ -1,6 +1,6 @@
<?php
/**
* Copyright (C) 2010-2021 Combodo SARL
* Copyright (C) 2010-2020 Combodo SARL
*
* This file is part of iTop.
*

View File

@@ -1,6 +1,6 @@
<?php
/**
* Copyright (C) 2010-2021 Combodo SARL
* Copyright (C) 2010-2020 Combodo SARL
*
* This file is part of iTop.
*
@@ -26,7 +26,7 @@ $iTopFolder = __DIR__ . "/../../" ;
require_once ("$iTopFolder/approot.inc.php");
require_once (APPROOT."/setup/setuputils.class.inc.php");
if (php_sapi_name() !== 'cli')
if (PHP_SAPI !== 'cli')
{
throw new \Exception('This script can only run from CLI');
}
@@ -70,4 +70,4 @@ if (false === empty($aMissing)) {
echo "Some new tests dirs exists !\n"
.' They must be declared either in the allowed or denied list in '.iTopComposer::class." (see N°2651).\n"
.' List of dirs:'."\n".var_export($aMissing, true);
}
}

View File

@@ -1,13 +0,0 @@
# Git hooks for iTop
## ❓ Goal
Those [git hooks](https://git-scm.com/docs/githooks) aims to ease developing on [iTop](https://github.com/Combodo/iTop).
## ☑ Available hooks
* pre-commit : rejects commit if you have at least one SCSS file staged, and no CSS file
## ⚙ Install
Just run install.php !

View File

@@ -1,26 +0,0 @@
<?php
$aHooks = [
'pre-commit.php',
];
$sAppRoot = dirname(__DIR__, 2);
foreach ($aHooks as $sSourceHookFileName) {
echo "Processing for `{$sSourceHookFileName}`...\n";
$sSourceHookPath = __DIR__.DIRECTORY_SEPARATOR.$sSourceHookFileName;
$aPathParts = pathinfo($sSourceHookFileName);
$sTargetHookPath = $sAppRoot.DIRECTORY_SEPARATOR.'.git'.DIRECTORY_SEPARATOR.'hooks'.DIRECTORY_SEPARATOR.$aPathParts['filename'];
if (file_exists($sTargetHookPath) || is_link($sTargetHookPath)) {
echo "Existing $sTargetHookPath ! Removing...";
unlink($sTargetHookPath);
echo "OK !\n";
}
echo "Creating symlink for hook in $sTargetHookPath...";
symlink($sSourceHookPath, $sTargetHookPath);
echo "OK !\n";
}

View File

@@ -1,49 +0,0 @@
#!/usr/bin/php
<?php
/**
* Reject any commit containing .scss files, but no .css file !
*/
echo "Checking files staged...\n";
$sFilesToCommit = shell_exec('git diff --cached --name-only --diff-filter=ACMRT');
$aFilesToCommit = explode("\n", $sFilesToCommit);
$aScssFiles = GetFilesWithExtension('scss', $aFilesToCommit);
if (count($aScssFiles) === 0) {
echo "No scss file : OK to go !\n";
exit(0);
}
$aCssFiles = GetFilesWithExtension('css', $aFilesToCommit);
if (count($aCssFiles) === 0) {
echo "There are SCSS files staged but no CSS file : REJECTING commit.\n";
echo "You must add the compiled SCSS files by running the setup !\n";
exit(1);
}
echo "We have SCSS but also CSS => OK to commit !\n";
exit(0);
function GetFilesWithExtension($sExtension, $aFiles) {
return array_filter(
$aFiles,
function($item) use ($sExtension) {
return (endsWith($item, '.'.$sExtension));
}
);
}
function endsWith( $haystack, $needle ) {
$length = strlen( $needle );
if( !$length ) {
return true;
}
return substr( $haystack, -$length ) === $needle;
}
function exitWithMessage($sMessage, $iCode) {
echo $sMessage;
exit($iCode);
}

View File

@@ -19,17 +19,24 @@
* The target license file path is in `$xmlFilePath`
*/
$iTopFolder = __DIR__ . "/../../" ;
$xmlFilePath = $iTopFolder . "setup/licenses/community-licenses.xml";
$iTopFolder = __DIR__."/../../";
$xmlFilePath = $iTopFolder."setup/licenses/community-licenses.xml";
function get_scope($product_node)
{
$jqExec = shell_exec("jq -V"); // a param is mandatory otherwise the script will freeze
if ((null === $jqExec) || (false === $jqExec)) {
echo "/!\ JQ is required but cannot be launched :( \n";
echo "Check this script PHPDoc block for instructions\n";
die(-1);
}
function get_scope($product_node) {
$scope = $product_node->getAttribute("scope");
if ($scope === "")
{ //put iTop first
if ($scope === "") { //put iTop first
return "aaaaaaaaa";
}
return $scope;
}

View File

@@ -25,6 +25,7 @@ require_once (__DIR__.DIRECTORY_SEPARATOR.'update.classes.inc.php');
/** @var \FileVersionUpdater[] $aFilesUpdaters */
$aFilesUpdaters = array(
new iTopVersionFileUpdater(),
new CssVariablesFileUpdater(),
new DatamodelsModulesFiles(),
new ConstantFileUpdater('ITOP_CORE_VERSION', 'approot.inc.php'),
);

View File

@@ -123,6 +123,26 @@ class iTopVersionFileUpdater extends AbstractSingleFileVersionUpdater
}
}
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;

View File

@@ -42,7 +42,7 @@ If you want to use another license, you may [create an extension][wiki new ext].
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 a `master` branch anymore.
we don't have anymore a `master` branch.
Here are the branches we use and their meaning :
@@ -52,23 +52,23 @@ Here are the branches we use and their meaning :
For example, if no version is currently prepared for shipping we could have:
- `develop` containing future 3.0.0 version
- `develop` containing future 2.8.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 3.0.0-beta is shipped that will become:
In this example, when 2.8.0-beta is shipped that will become:
- `develop`: future 3.1.0 version
- `release/3.0.0`: 3.0.0-beta
- `develop`: future 2.9.0 version
- `release/2.8`: 2.8.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 3.0.0 final will be out:
And when 2.8.0 final will be out:
- `develop`: future 3.1.0 version
- `support/3.0`: 3.0.x maintenance version (will host developments for 3.0.1)
- `develop`: future 2.9.0 version
- `support/2.8`: 2.8.x maintenance version (will host developments for 2.8.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
@@ -125,7 +125,8 @@ Our tests are located in the `test/` directory, containing a PHPUnit config file
* ⬆️ `:arrow_up:` when upgrading dependencies
* ⬇️ `:arrow_down:` when downgrading dependencies
* ♻️ `:recycle:` code refactoring
* 💄 `:lipstick:` Updating the UI and style files.
* 💄 `:lipstick:` Updating the UI and style files.
## 👥 Pull request
@@ -136,25 +137,3 @@ When your code is working, please:
* create a pull request.
Detailed procedure to work on fork and create PR is available [in GitHub help pages](https://help.github.com/articles/creating-a-pull-request-from-a-fork/).
You might check the ["Allow edits from maintainers" PR checkbox][allow_edits_checkbox] to ease review.
[allow_edits_checkbox]: https://docs.github.com/en/github/collaborating-with-issues-and-pull-requests/working-with-forks/allowing-changes-to-a-pull-request-branch-created-from-a-fork#enabling-repository-maintainer-permissions-on-existing-pull-requests
### 🙏 We are thankful
We are thankful for all your contributions to the iTop universe! As a thank you gift, we will send stickers to every iTop (& extensions) contributors!
Stickers' design might change from one year to another. For the first year we wanted to try a "craft beer label" look, see examples below:
* Bug hunter: Fix a bug
* Translator: Add/update translations
* White hat: Find and/or fix a vulnerability
* Contributor: Contribute by finding a bug, making an extension or any other way
* Partner: For Combodo's official partners
* Graduated: Follow a Combodo's iTop training
* Ambassador: Outstanding community contributors
* Beta tester: Test and give feedback on beta releases
* Extension developer: Develop and publish an extension
![](.doc/contributing-guide/contributing-stickers-side-by-side.png)

115
README.md
View File

@@ -1,11 +1,13 @@
<p align="center"><a href="https://www.combodo.com/itop-193" target="_blank">
<img src="https://www.combodo.com/logos/logo-itop-baseline.svg" width=350>
<img src="https://www.combodo.com/logos/logo-itop.svg">
</a></p>
iTop stands for IT Operations Portal. It is a complete open source and web based IT service management platform including a fully customizable CMDB, a helpdesk system and a document management tool. It is ITIL compliant and easily customizable and extensible thanks to a high number of adds-on and web services to integrate with your IT.
iTop also offers mass import tools to help you being even more efficient.
# iTop - ITSM & CMDB
iTop stands for *IT Operations Portal*.
It is a complete open source, ITIL, web based service management tool including a fully customizable CMDB, a helpdesk system and a document management tool.
iTop also offers mass import tools and web services to integrate with your IT
## Features
- Fully configurable [Configuration Management (CMDB)][10]
@@ -21,10 +23,10 @@ iTop also offers mass import tools to help you being even more efficient.
## Latest release
- [Changes since the previous version][62]
- [New features][63]
- [Installation notes][64]
- [Download][65]
- [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
@@ -37,17 +39,16 @@ iTop also offers mass import tools to help you being even more efficient.
- [iTop Forums][1]: community support
- [iTop Tickets][2]: for feature requests and bug reports
- [Releases download][3]
- [Software requirements][4]
- [Documentation][5] covering both iTop and its official extensions
- [iTop Hub][6] : discover and install extensions !
- [Documentation][4] covering both iTop and its official extensions
- [iTop Hub][5] : 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/page?id=latest:install:upgrading_itop
[5]: https://www.itophub.io/wiki
[6]: https://store.itophub.io/en_US/
[4]: https://www.itophub.io/wiki
[5]: 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
@@ -70,59 +71,51 @@ iTop development is sponsored, led and supported by [Combodo][0].
## Contributors
We would like to give a special thank you 🤗 to the people from the community who contributed to this project, including:
We would like to give a special thank you to the people from the community who contributed to this project, including:
### Names
- Alves, David
- Beck, Pedro
- Beer, Christian (a.k.a [@ChristianBeer](https://www.github.com/ChristianBeer))
- Bilger, Jean-François
- Bostoen, Jeffrey (a.k.a [@jbostoen](https://www.github.com/jbostoen))
- Cardoso, Anderson
- Cassaro, Bruno
- Casteleyn, Thomas (a.k.a [@Hipska](https://www.github.com/Hipska))
- Castro, Randall Badilla
- Colantoni, Maria Laura
- Couronné, Guy
- Dvořák, Lukáš
- Goethals, Stefan
- Gumble, David
- Kaltefleiter, Lars (a.k.a [@larhip](https://www.github.com/larhip))
- Khamit, Shamil
- Kincel, Martin
- Konečný, Kamil
- Kunin, Vladimir
- Lassiter, Dennis
- Lazcano, Federico
- Lucas, Jonathan
- Alves, David
- Beck, Pedro
- Bilger, Jean-François
- Bostoen, Jeffrey
- Cardoso, Anderson
- Cassaro, Bruno
- Casteleyn, Thomas
- Castro, Randall Badilla
- Colantoni, Maria Laura
- Couronné, Guy
- Dvořák, Lukáš
- Goethals, Stefan
- Gumble, David
- Hippler, Lars
- Khamit, Shamil
- Kincel, Martin
- Konečný, Kamil
- Kunin, Vladimir
- Lassiter, Dennis
- Lazcano, Federico
- Lucas, Jonathan
- Malik, Remie
- Mindêllo de Andrade, Lucas (a.k.a [@rokam](https://www.github.com/rokam))
- Raenker, Martin
- Mindêllo de Andrade, Lucas (a.k.a @rokam)
- Rosenke, Stephan
- Seki, Shoji
- Shilov, Vladimir
- Stukalov, Ilya (a.k.a [@ilya](https://www.github.com/ilya)-stukalov)
- Tulio, Marco
- Turrubiates, Miguel
- Seki, Shoji
- Shilov, Vladimir
- Tulio, Marco
- Turrubiates, Miguel
### Aliases
- chifu1234
- cprobst
- DudekArtur
- Karkoff1212
- Laura
- nv35
- Purple Grape
- Schlobinux
- theBigOne
- ulmerspatz
- chifu1234
- cprobst
- Karkoff1212
- larhip
- Laura
- Purple Grape
- Schlobinux
- theBigOne
- ulmerspatz
### Companies
- [Hardis](https://www.hardis-group.com/)
- [ITOMIG](https://www.itomig.de/)
- [Pimkie](https://www.pimkie.com/)
- [Super-Visions](https://www.super-visions.com/)
- Hardis
- ITOMIG
- Pimkie

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 / when / then" report, including iTop version, impacts, and maybe installed modules or data if they are
You can send us a standard "given / then / when" report, including iTop version, impacts, and maybe installed modules or data if they are
needed to reproduce.
### Dependencies vulnerabilities

View File

@@ -1,5 +1,5 @@
<?php
// Copyright (C) 2010-2021 Combodo SARL
// Copyright (C) 2010-2012 Combodo SARL
//
// This file is part of iTop.
//
@@ -19,7 +19,7 @@
/**
* UserRightsMatrix (User management Module)
*
* @copyright Copyright (C) 2010-2021 Combodo SARL
* @copyright Copyright (C) 2010-2012 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/

View File

@@ -1,5 +1,5 @@
<?php
// Copyright (C) 2010-2021 Combodo SARL
// Copyright (C) 2010-2012 Combodo SARL
//
// This file is part of iTop.
//
@@ -20,7 +20,7 @@
* UserRightsNull
* User management Module - say Yeah! to everything
*
* @copyright Copyright (C) 2010-2021 Combodo SARL
* @copyright Copyright (C) 2010-2012 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/

View File

@@ -1,7 +1,20 @@
<?php
/*
* @copyright Copyright (C) 2010-2021 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
/**
* 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
*/
define('ADMIN_PROFILE_NAME', 'Administrator');
@@ -34,7 +47,7 @@ class URP_Profiles extends UserRightsBaseClassGUI
{
$aParams = array
(
"category" => "addon/userrights,grant_by_profile,filter",
"category" => "addon/userrights,grant_by_profile",
"key_type" => "autoincrement",
"name_attcode" => "name",
"state_attcode" => "",
@@ -42,6 +55,7 @@ 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();
@@ -156,9 +170,11 @@ class URP_Profiles extends UserRightsBaseClassGUI
function DisplayBareRelations(WebPage $oPage, $bEditMode = false)
{
parent::DisplayBareRelations($oPage, $bEditMode);
$oPage->SetCurrentTab('UI:UserManagement:GrantMatrix');
$this->DoShowGrantSumary($oPage);
if (!$bEditMode)
{
$oPage->SetCurrentTab('UI:UserManagement:GrantMatrix');
$this->DoShowGrantSumary($oPage);
}
}
public static function GetReadOnlyAttributes()
@@ -219,14 +235,15 @@ class URP_UserProfile extends UserRightsBaseClassGUI
{
$aParams = array
(
"category" => "addon/userrights,grant_by_profile,filter",
"category" => "addon/userrights,grant_by_profile",
"key_type" => "autoincrement",
"name_attcode" => array("userlogin", "profile"),
"name_attcode" => "userid",
"state_attcode" => "",
"reconc_keys" => array(),
"db_table" => "priv_urp_userprofile",
"db_key_field" => "id",
"db_finalclass_field" => "",
"display_template" => "",
);
MetaModel::Init_Params($aParams);
//MetaModel::Init_InheritAttributes();
@@ -246,54 +263,22 @@ class URP_UserProfile extends UserRightsBaseClassGUI
MetaModel::Init_SetZListItems('advanced_search', array('userid', 'profileid')); // Criteria of the advanced search form
}
public function CheckToDelete(&$oDeletionPlan)
public function GetName()
{
if (MetaModel::GetConfig()->Get('demo_mode')) {
// Users deletion is NOT allowed in demo mode
$oDeletionPlan->AddToDelete($this, null);
$oDeletionPlan->SetDeletionIssues($this, array('deletion not allowed in demo mode.'), true);
$oDeletionPlan->ComputeResults();
return false;
}
try {
$this->CheckIfProfileIsAllowed(UR_ACTION_DELETE);
}
catch (SecurityException $e) {
// Users deletion is NOT allowed
$oDeletionPlan->AddToDelete($this, null);
$oDeletionPlan->SetDeletionIssues($this, [$e->getMessage()], true);
$oDeletionPlan->ComputeResults();
return false;
}
return parent::CheckToDelete($oDeletionPlan);
return Dict::Format('UI:UserManagement:LinkBetween_User_And_Profile', $this->Get('userlogin'), $this->Get('profile'));
}
public function DoCheckToDelete(&$oDeletionPlan)
public function CheckToDelete(&$oDeletionPlan)
{
if (MetaModel::GetConfig()->Get('demo_mode')) {
if (MetaModel::GetConfig()->Get('demo_mode'))
{
// Users deletion is NOT allowed in demo mode
$oDeletionPlan->AddToDelete($this, null);
$oDeletionPlan->SetDeletionIssues($this, array('deletion not allowed in demo mode.'), true);
$oDeletionPlan->ComputeResults();
return false;
}
try {
$this->CheckIfProfileIsAllowed(UR_ACTION_DELETE);
}
catch (SecurityException $e) {
// Users deletion is NOT allowed
$oDeletionPlan->AddToDelete($this, null);
$oDeletionPlan->SetDeletionIssues($this, [$e->getMessage()], true);
$oDeletionPlan->ComputeResults();
return false;
}
return parent::DoCheckToDelete($oDeletionPlan);
return parent::CheckToDelete($oDeletionPlan);
}
protected function OnInsert()
@@ -308,6 +293,7 @@ class URP_UserProfile extends UserRightsBaseClassGUI
protected function OnDelete()
{
$this->CheckIfProfileIsAllowed(UR_ACTION_DELETE);
}
/**
@@ -357,12 +343,13 @@ class URP_UserOrg extends UserRightsBaseClassGUI
(
"category" => "addon/userrights,grant_by_profile",
"key_type" => "autoincrement",
"name_attcode" => array("userlogin", "allowed_org_name"),
"name_attcode" => "userid",
"state_attcode" => "",
"reconc_keys" => array(),
"db_table" => "priv_urp_userorg",
"db_key_field" => "id",
"db_finalclass_field" => "",
"display_template" => "",
);
MetaModel::Init_Params($aParams);
//MetaModel::Init_InheritAttributes();
@@ -382,6 +369,12 @@ class URP_UserOrg extends UserRightsBaseClassGUI
MetaModel::Init_SetZListItems('advanced_search', array('userid', 'allowed_org_id')); // Criteria of the advanced search form
}
public function GetName()
{
return Dict::Format('UI:UserManagement:LinkBetween_User_And_Org', $this->Get('userlogin'), $this->Get('allowed_org_name'));
}
protected function OnInsert()
{
$this->CheckIfOrgIsAllowed();
@@ -432,6 +425,12 @@ class UserRightsProfile extends UserRightsAddOnAPI
UR_ACTION_BULK_DELETE => 'bd',
);
/**
* @var array $aUsersProfilesList Cache of users' profiles. Hash array of user ID => [profile ID => profile friendlyname, profile ID => profile friendlyname, ...]
* @since 2.7.10 3.0.4 3.1.1 3.2.0 N°6887
*/
private $aUsersProfilesList = [];
// Installation: create the very first user
public function CreateAdministrator($sAdminUser, $sAdminPwd, $sLanguage = 'EN US')
{
@@ -610,115 +609,30 @@ class UserRightsProfile extends UserRightsAddOnAPI
{
$this->LoadCache();
// Let us pass an administrator for bypassing the grant matrix check in order to test this method without the need to set up a complex profile
// In the nominal case Administrators never end up here (since they completely bypass GetSelectFilter)
if (!static::IsAdministrator($oUser) && (MetaModel::HasCategory($sClass, 'silo') || MetaModel::HasCategory($sClass, 'bizmodel')))
$aObjectPermissions = $this->GetUserActionGrant($oUser, $sClass, UR_ACTION_READ);
if ($aObjectPermissions['permission'] == UR_ALLOWED_NO)
{
// N°4354 - Categories 'silo' and 'bizmodel' do check the grant matrix. Whereas 'filter' always allows to read (but the result can be filtered)
$aObjectPermissions = $this->GetUserActionGrant($oUser, $sClass, UR_ACTION_READ);
if ($aObjectPermissions['permission'] == UR_ALLOWED_NO)
{
return false;
}
return false;
}
$oFilter = true;
$aConditions = array();
// Determine if this class is part of a silo and build the filter for it
// Determine how to position the objects of this class
//
$sAttCode = self::GetOwnerOrganizationAttCode($sClass);
if (!is_null($sAttCode))
if (is_null($sAttCode))
{
$aUserOrgs = $this->GetUserOrgs($oUser, $sClass);
if (count($aUserOrgs) > 0)
{
$oFilter = $this->MakeSelectFilter($sClass, $aUserOrgs, $aSettings, $sAttCode);
}
// else: No org means 'any org'
// No filtering for this object
return true;
}
// else: No silo for this class
// Specific conditions to hide, for non-administrators, the Administrator Users, the Administrator Profile and related links
// Note: when logged as an administrator, GetSelectFilter is completely bypassed.
if ($this->AdministratorsAreHidden())
// Position the user
//
$aUserOrgs = $this->GetUserOrgs($oUser, $sClass);
if (count($aUserOrgs) == 0)
{
if ($sClass == 'URP_Profiles')
{
$oExpression = new FieldExpression('id', $sClass);
$oScalarExpr = new ScalarExpression(1);
$aConditions[] = new BinaryExpression($oExpression, '!=', $oScalarExpr);
}
else if (($sClass == 'URP_UserProfile') || ($sClass == 'User') || (is_subclass_of($sClass, 'User')))
{
$aAdministrators = $this->GetAdministrators();
if (count($aAdministrators) > 0)
{
$sAttCode = ($sClass == 'URP_UserProfile') ? 'userid' : 'id';
$oExpression = new FieldExpression($sAttCode, $sClass);
$oListExpr = ListExpression::FromScalars($aAdministrators);
$aConditions[] = new BinaryExpression($oExpression, 'NOT IN', $oListExpr);
}
}
// No org means 'any org'
return true;
}
// Handling of the added conditions
if (count($aConditions) > 0)
{
if($oFilter === true)
{
// No 'silo' filter, let's build a clean one
$oFilter = new DBObjectSearch($sClass);
}
// Add the conditions to the filter
foreach($aConditions as $oCondition)
{
$oFilter->AddConditionExpression($oCondition);
}
}
return $oFilter;
}
/**
* Retrieve (and memoize) the list of administrator accounts.
* Note that there should always be at least one administrator account
* @return number[]
*/
private function GetAdministrators()
{
static $aAdministrators = null;
if ($aAdministrators === null)
{
// Find all administrators
$aAdministrators = array();
$oAdministratorsFilter = new DBObjectSearch('User');
$oLnkFilter = new DBObjectSearch('URP_UserProfile');
$oExpression = new FieldExpression('profileid', 'URP_UserProfile');
$oScalarExpr = new ScalarExpression(1);
$oCondition = new BinaryExpression($oExpression, '=', $oScalarExpr);
$oLnkFilter->AddConditionExpression($oCondition);
$oAdministratorsFilter->AddCondition_ReferencedBy($oLnkFilter, 'userid');
$oAdministratorsFilter->AllowAllData(true); // Mandatory to prevent infinite recursion !!
$oSet = new DBObjectSet($oAdministratorsFilter);
$oSet->OptimizeColumnLoad(array('User' => array('login')));
while($oUser = $oSet->Fetch())
{
$aAdministrators[] = $oUser->GetKey();
}
}
return $aAdministrators;
}
/**
* Whether or not to hide the 'Administrator' profile and the administrator accounts
* @return boolean
*/
private function AdministratorsAreHidden()
{
return ((bool)MetaModel::GetConfig()->Get('security.hide_administrators'));
return $this->MakeSelectFilter($sClass, $aUserOrgs, $aSettings, $sAttCode);
}
@@ -746,8 +660,12 @@ class UserRightsProfile extends UserRightsAddOnAPI
$sAction = self::$m_aActionCodes[$iActionCode];
$bStatus = null;
// Cache user's profiles
if(false === array_key_exists($iUser, $this->aUsersProfilesList)){
$this->aUsersProfilesList[$iUser] = UserRights::ListProfiles($oUser);
}
// Call the API of UserRights because it caches the list for us
foreach(UserRights::ListProfiles($oUser) as $iProfile => $oProfile)
foreach($this->aUsersProfilesList[$iUser] as $iProfile => $oProfile)
{
$bGrant = $this->GetProfileActionGrant($iProfile, $sClass, $sAction);
if (!is_null($bGrant))
@@ -873,11 +791,16 @@ class UserRightsProfile extends UserRightsAddOnAPI
// Note: this code is VERY close to the code of IsActionAllowed()
$iUser = $oUser->GetKey();
// Cache user's profiles
if(false === array_key_exists($iUser, $this->aUsersProfilesList)){
$this->aUsersProfilesList[$iUser] = UserRights::ListProfiles($oUser);
}
// Note: The object set is ignored because it was interesting to optimize for huge data sets
// and acceptable to consider only the root class of the object set
$bStatus = null;
// Call the API of UserRights because it caches the list for us
foreach(UserRights::ListProfiles($oUser) as $iProfile => $oProfile)
foreach($this->aUsersProfilesList[$iUser] as $iProfile => $oProfile)
{
$bGrant = $this->GetClassStimulusGrant($iProfile, $sClass, $sStimulusCode);
if (!is_null($bGrant))
@@ -906,8 +829,9 @@ class UserRightsProfile extends UserRightsAddOnAPI
}
/**
* Find out which attribute is corresponding the the dimension 'owner org'
* returns null if no such attribute has been found (no filtering should occur)
* @param string $sClass
* @return string|null Find out which attribute is corresponding the dimension 'owner org'
* returns null if no such attribute has been found (no filtering should occur)
*/
public static function GetOwnerOrganizationAttCode($sClass)
{

View File

@@ -1,6 +1,6 @@
<?php
/**
* Copyright (C) 2013-2021 Combodo SARL
* Copyright (C) 2013-2020 Combodo SARL
*
* This file is part of iTop.
*
@@ -77,6 +77,7 @@ 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();
@@ -311,9 +312,11 @@ class URP_Profiles extends UserRightsBaseClassGUI
function DisplayBareRelations(WebPage $oPage, $bEditMode = false)
{
parent::DisplayBareRelations($oPage, $bEditMode);
$oPage->SetCurrentTab('UI:UserManagement:GrantMatrix');
$this->DoShowGrantSumary($oPage);
if (!$bEditMode)
{
$oPage->SetCurrentTab('UI:UserManagement:GrantMatrix');
$this->DoShowGrantSumary($oPage);
}
}
}
@@ -327,12 +330,13 @@ class URP_UserProfile extends UserRightsBaseClassGUI
(
"category" => "addon/userrights",
"key_type" => "autoincrement",
"name_attcode" => array("userlogin", "profile"),
"name_attcode" => "userid",
"state_attcode" => "",
"reconc_keys" => array(),
"db_table" => "priv_urp_userprofile",
"db_key_field" => "id",
"db_finalclass_field" => "",
"display_template" => "",
);
MetaModel::Init_Params($aParams);
//MetaModel::Init_InheritAttributes();
@@ -351,6 +355,11 @@ class URP_UserProfile extends UserRightsBaseClassGUI
MetaModel::Init_SetZListItems('standard_search', array('userid', 'profileid')); // Criteria of the std search form
MetaModel::Init_SetZListItems('advanced_search', array('userid', 'profileid')); // Criteria of the advanced search form
}
public function GetName()
{
return Dict::Format('UI:UserManagement:LinkBetween_User_And_Profile', $this->Get('userlogin'), $this->Get('profile'));
}
}
class URP_UserOrg extends UserRightsBaseClassGUI
@@ -361,12 +370,13 @@ class URP_UserOrg extends UserRightsBaseClassGUI
(
"category" => "addon/userrights",
"key_type" => "autoincrement",
"name_attcode" => array("userlogin", "allowed_org_name"),
"name_attcode" => "userid",
"state_attcode" => "",
"reconc_keys" => array(),
"db_table" => "priv_urp_userorg",
"db_key_field" => "id",
"db_finalclass_field" => "",
"display_template" => "",
);
MetaModel::Init_Params($aParams);
//MetaModel::Init_InheritAttributes();
@@ -385,6 +395,11 @@ class URP_UserOrg extends UserRightsBaseClassGUI
MetaModel::Init_SetZListItems('standard_search', array('userid', 'allowed_org_id')); // Criteria of the std search form
MetaModel::Init_SetZListItems('advanced_search', array('userid', 'allowed_org_id')); // Criteria of the advanced search form
}
public function GetName()
{
return Dict::Format('UI:UserManagement:LinkBetween_User_And_Org', $this->Get('userlogin'), $this->Get('allowed_org_name'));
}
}
@@ -402,6 +417,7 @@ 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();
@@ -438,6 +454,7 @@ 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();
@@ -474,6 +491,7 @@ 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();
@@ -586,10 +604,10 @@ class UserRightsProfile extends UserRightsAddOnAPI
/**
* Read and cache organizations allowed to the given user
*
* @param $oUser
* @param $sClass (not used here but can be used in overloads)
* @param User $oUser
* @param string $sClass (not used here but can be used in overloads)
*
* @return array
* @return array keys of the User allowed org
* @throws \CoreException
* @throws \Exception
*/

View File

@@ -1,6 +1,6 @@
<?php
/**
* Copyright (C) 2013-2021 Combodo SARL
* Copyright (C) 2013-2020 Combodo SARL
*
* This file is part of iTop.
*
@@ -58,6 +58,7 @@ 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();
@@ -143,9 +144,11 @@ class URP_Profiles extends UserRightsBaseClass
function DisplayBareRelations(WebPage $oPage, $bEditMode = false)
{
parent::DisplayBareRelations($oPage, $bEditMode);
$oPage->SetCurrentTab('UI:UserManagement:GrantMatrix');
$this->DoShowGrantSumary($oPage);
if (!$bEditMode)
{
$oPage->SetCurrentTab('UI:UserManagement:GrantMatrix');
$this->DoShowGrantSumary($oPage);
}
}
}
@@ -164,6 +167,7 @@ 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();
@@ -270,12 +274,13 @@ class URP_UserProfile extends UserRightsBaseClass
(
"category" => "addon/userrights",
"key_type" => "autoincrement",
"name_attcode" => array("userlogin", "profile"),
"name_attcode" => "userid",
"state_attcode" => "",
"reconc_keys" => array(),
"db_table" => "priv_urp_userprofile",
"db_key_field" => "id",
"db_finalclass_field" => "",
"display_template" => "",
);
MetaModel::Init_Params($aParams);
//MetaModel::Init_InheritAttributes();
@@ -294,6 +299,11 @@ class URP_UserProfile extends UserRightsBaseClass
MetaModel::Init_SetZListItems('standard_search', array('userid', 'profileid')); // Criteria of the std search form
MetaModel::Init_SetZListItems('advanced_search', array('userid', 'profileid')); // Criteria of the advanced search form
}
public function GetName()
{
return Dict::Format('UI:UserManagement:LinkBetween_User_And_Profile', $this->Get('userlogin'), $this->Get('profile'));
}
}
@@ -311,6 +321,7 @@ 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();
@@ -391,6 +402,7 @@ 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();
@@ -462,6 +474,7 @@ 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();
@@ -498,6 +511,7 @@ 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();
@@ -534,6 +548,7 @@ 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

@@ -1,60 +0,0 @@
<?php
/*
* @copyright Copyright (C) 2010-2021 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
/**
* Class DBSearchHelper
*
* @since 3.0.0
*/
class DBSearchHelper
{
/**
* Add context filter to DBUnionSearch
*
* @param \DBSearch|null $oSearch
*
* @throws \Exception
* @since 3.0.0
*/
public static function AddContextFilter(?DBSearch $oSearch): void
{
$oAppContext = new ApplicationContext();
$sClass = $oSearch->GetClass();
foreach ($oAppContext->GetNames() as $key) {
// Find the value of the object corresponding to each 'context' parameter
$aCallSpec = [$sClass, 'MapContextParam'];
$sAttCode = '';
if (is_callable($aCallSpec)) {
$sAttCode = call_user_func($aCallSpec, $key); // Returns null when there is no mapping for this parameter
}
if (MetaModel::IsValidAttCode($sClass, $sAttCode)) {
// Add Hierarchical condition if hierarchical key
$oAttDef = MetaModel::GetAttributeDef($sClass, $sAttCode);
if (isset($oAttDef) && ($oAttDef->IsExternalKey())) {
$iDefaultValue = intval($oAppContext->GetCurrentValue($key));
if ($iDefaultValue != 0) {
try {
/** @var AttributeExternalKey $oAttDef */
$sTargetClass = $oAttDef->GetTargetClass();
$sHierarchicalKeyCode = MetaModel::IsHierarchicalClass($sTargetClass);
if ($sHierarchicalKeyCode !== false) {
$oFilter = new DBObjectSearch($sTargetClass);
$oFilter->AddCondition('id', $iDefaultValue);
$oHKFilter = new DBObjectSearch($sTargetClass);
$oHKFilter->AddCondition_PointingTo($oFilter, $sHierarchicalKeyCode, TREE_OPERATOR_BELOW);
$oSearch->AddCondition_PointingTo($oHKFilter, $sAttCode);
}
}
catch (Exception $e) {
// If filtering fails just ignore it
}
}
}
}
}
}
}

View File

@@ -30,11 +30,8 @@ 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);
if (is_array($parts))
{
$count += count($parts) - 1;
$subject = implode($replacements[$key], $parts);
}
$count += count($parts) - 1;
$subject = implode($replacements[$key], $parts);
}
} else {
// Call mb_str_replace for each subject in array, recursively

View File

@@ -1,20 +1,425 @@
<?php
/**
* @deprecated will be removed in 3.1.0 - moved to sources/application/WebPage/AjaxPage.php, now loadable using autoloader
* @license http://opensource.org/licenses/AGPL-3.0
* @copyright Copyright (C) 2010-2021 Combodo SARL
*/
// cannot notify depreciation for now as this is still MASSIVELY used in iTop core !
//DeprecatedCallsLog::NotifyDeprecatedFile('moved to sources/application/WebPage/AjaxPage.php, now loadable using autoloader');
/**
* Class ajax_page
* Copyright (C) 2013-2020 Combodo SARL
*
* @deprecated will be removed in 3.1.0 - moved to AjaxPage
* 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
*/
class ajax_page extends AjaxPage
{
require_once(APPROOT."/application/webpage.class.inc.php");
class ajax_page extends WebPage implements iTabbedPage
{
/**
* 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->no_cache();
$this->add_http_headers();
$this->m_oTabs = new TabManager();
$this->sContentType = 'text/html';
$this->sContentDisposition = 'inline';
$this->m_sMenu = "";
utils::InitArchiveMode();
}
/**
* Disabling sending the header so that resource won't be blocked by CORB. See parent method documentation.
* @return void
* @since 2.7.10 3.0.4 3.1.2 3.2.0 N°4368 method creation
*/
public function add_xcontent_type_options()
{
// Nothing to do !
}
/**
* @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

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

View File

@@ -1,5 +1,5 @@
<?php
// Copyright (C) 2010-2021 Combodo SARL
// Copyright (C) 2010-2018 Combodo SARL
//
// This file is part of iTop.
//
@@ -20,28 +20,23 @@
/**
* Class ApplicationContext
*
* @copyright Copyright (C) 2010-2021 Combodo SARL
* @copyright Copyright (C) 2010-2018 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
use Combodo\iTop\Application\Helper\Session;
use Combodo\iTop\Application\UI\Base\Component\Input\InputUIBlockFactory;
use Combodo\iTop\Application\UI\Base\Layout\UIContentBlock;
use Combodo\iTop\Application\UI\Base\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);
}
@@ -205,60 +200,23 @@ 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 an array of input blocks
*
* @return array The context as a sequence of <input type="hidden" /> tags
* @since 3.0.0
*/
public function GetForUIForm()
{
$aContextInputBlocks = [];
foreach ($this->aValues as $sName => $sValue) {
$aContextInputBlocks[] = InputUIBlockFactory::MakeForHidden("c[$sName]", htmlentities($sValue, ENT_QUOTES, 'UTF-8'));
}
return $aContextInputBlocks;
}
/**
* 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(InputUIBlockFactory::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()
@@ -336,7 +294,7 @@ class ApplicationContext
$sPrevious = self::GetUrlMakerClass();
self::$m_sUrlMakerClass = $sClass;
Session::Set('UrlMakerClass', $sClass);
$_SESSION['UrlMakerClass'] = $sClass;
return $sPrevious;
}
@@ -349,9 +307,9 @@ class ApplicationContext
{
if (is_null(self::$m_sUrlMakerClass))
{
if (Session::IsSet('UrlMakerClass'))
if (isset($_SESSION['UrlMakerClass']))
{
self::$m_sUrlMakerClass = Session::Get('UrlMakerClass');
self::$m_sUrlMakerClass = $_SESSION['UrlMakerClass'];
}
else
{
@@ -376,19 +334,26 @@ class ApplicationContext
{
$oAppContext = new ApplicationContext();
if (is_null($sUrlMakerClass)) {
$sUrlMakerClass = self::GetUrlMakerClass();
}
if (is_null($sUrlMakerClass))
{
$sUrlMakerClass = self::GetUrlMakerClass();
}
$sUrl = call_user_func(array($sUrlMakerClass, 'MakeObjectUrl'), $sObjClass, $sObjKey);
if (utils::StrLen($sUrl) > 0) {
if ($bWithNavigationContext) {
return $sUrl."&".$oAppContext->GetForLink();
} else {
return $sUrl;
}
} else {
return '';
}
if (strlen($sUrl) > 0)
{
if ($bWithNavigationContext)
{
return $sUrl."&".$oAppContext->GetForLink();
}
else
{
return $sUrl;
}
}
else
{
return '';
}
}
/**
@@ -397,9 +362,9 @@ class ApplicationContext
*/
protected static function LoadPluginProperties()
{
if (Session::IsSet('PluginProperties'))
if (isset($_SESSION['PluginProperties']))
{
self::$m_aPluginProperties = Session::Get('PluginProperties');
self::$m_aPluginProperties = $_SESSION['PluginProperties'];
}
else
{
@@ -419,7 +384,7 @@ class ApplicationContext
if (is_null(self::$m_aPluginProperties)) self::LoadPluginProperties();
self::$m_aPluginProperties[$sPluginClass][$sProperty] = $value;
Session::Set(['PluginProperties', $sPluginClass, $sProperty], $value);
$_SESSION['PluginProperties'][$sPluginClass][$sProperty] = $value;
}
/**

View File

@@ -1,7 +1,7 @@
<?php
/**
* Copyright (C) 2013-2021 Combodo SARL
* Copyright (C) 2013-2020 Combodo SARL
*
* This file is part of iTop.
*
@@ -18,7 +18,6 @@
* You should have received a copy of the GNU Affero General Public License
*/
use Combodo\iTop\Application\UI\Base\iUIBlock;
use Symfony\Component\DependencyInjection\Container;
require_once(APPROOT.'application/newsroomprovider.class.inc.php');
@@ -31,7 +30,7 @@ require_once(APPROOT.'application/newsroomprovider.class.inc.php');
*
* @api
* @package LoginExtensibilityAPI
* @copyright Copyright (C) 2010-2021 Combodo SARL
* @copyright Copyright (C) 2010-2012 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
* @since 2.7.0
*/
@@ -461,7 +460,7 @@ interface iApplicationUIExtension
* @api
* @param DBObjectSet $oSet A set of persistent objects (DBObject)
*
* @return array
* @return string[string]
*/
public function EnumAllowedActions(DBObjectSet $oSet);
}
@@ -821,10 +820,6 @@ abstract class ApplicationPopupMenuItem
/** @ignore */
protected $sLabel;
/** @ignore */
protected $sTooltip;
/** @ignore */
protected $sIconClass;
/** @ignore */
protected $aCssClasses;
/**
@@ -839,8 +834,6 @@ abstract class ApplicationPopupMenuItem
{
$this->sUID = $sUID;
$this->sLabel = $sLabel;
$this->sTooltip = '';
$this->sIconClass = '';
$this->aCssClasses = array();
}
@@ -897,47 +890,6 @@ abstract class ApplicationPopupMenuItem
$this->aCssClasses[] = $sCssClass;
}
/**
* @param $sTooltip
*
* @since 3.0.0
*/
public function SetTooltip($sTooltip)
{
$this->sTooltip = $sTooltip;
}
/**
* @return string
*
* @since 3.0.0
*/
public function GetTooltip()
{
return $this->sTooltip;
}
/**
* @param $sIconClass
*
* @since 3.0.0
*/
public function SetIconClass($sIconClass)
{
$this->sIconClass = $sIconClass;
}
/**
* @return string
*
* @since 3.0.0
*/
public function GetIconClass()
{
return $this->sIconClass;
}
/**
* Returns the components to create a popup menu item in HTML
*
@@ -956,8 +908,6 @@ abstract class ApplicationPopupMenuItem
/**
* Class for adding an item into a popup menu that browses to the given URL
*
* Note: This works only in the backoffice, {@see \URLButtonItem} for the end-user portal
*
* @api
* @package UIExtensibilityAPI
* @since 2.0
@@ -965,7 +915,7 @@ abstract class ApplicationPopupMenuItem
class URLPopupMenuItem extends ApplicationPopupMenuItem
{
/** @ignore */
protected $sUrl;
protected $sURL;
/** @ignore */
protected $sTarget;
@@ -975,46 +925,26 @@ class URLPopupMenuItem extends ApplicationPopupMenuItem
* @api
* @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->GetUrl(),
'target' => $this-> GetTarget(),
'css_classes' => $this->aCssClasses,
'icon_class' => $this->sIconClass,
'tooltip' => $this->sTooltip
);
}
/** @ignore */
public function GetUrl()
{
return $this->sUrl;
}
/** @ignore */
public function GetTarget()
{
return $this->sTarget;
return array('label' => $this->GetLabel(), 'url' => $this->sURL, 'target' => $this->sTarget, 'css_classes' => $this->aCssClasses);
}
}
/**
* Class for adding an item into a popup menu that triggers some Javascript code
*
* Note: This works only in the backoffice, {@see \JSButtonItem} for the end-user portal
*
* @api
* @package UIExtensibilityAPI
* @since 2.0
@@ -1022,9 +952,7 @@ class URLPopupMenuItem extends ApplicationPopupMenuItem
class JSPopupMenuItem extends ApplicationPopupMenuItem
{
/** @ignore */
protected $sJsCode;
/** @ignore */
protected $sUrl;
protected $sJSCode;
/** @ignore */
protected $aIncludeJSFiles;
@@ -1042,8 +970,7 @@ class JSPopupMenuItem extends ApplicationPopupMenuItem
public function __construct($sUID, $sLabel, $sJSCode, $aIncludeJSFiles = array())
{
parent::__construct($sUID, $sLabel);
$this->sJsCode = $sJSCode;
$this->sUrl = '#';
$this->sJSCode = $sJSCode;
$this->aIncludeJSFiles = $aIncludeJSFiles;
}
@@ -1053,11 +980,9 @@ class JSPopupMenuItem extends ApplicationPopupMenuItem
// Note: the semicolumn is a must here!
return array(
'label' => $this->GetLabel(),
'onclick' => $this->GetJsCode().'; return false;',
'url' => $this->GetUrl(),
'css_classes' => $this->GetCssClasses(),
'icon_class' => $this->sIconClass,
'tooltip' => $this->sTooltip
'onclick' => $this->sJSCode.'; return false;',
'url' => '#',
'css_classes' => $this->aCssClasses,
);
}
@@ -1066,18 +991,6 @@ class JSPopupMenuItem extends ApplicationPopupMenuItem
{
return $this->aIncludeJSFiles;
}
/** @ignore */
public function GetJsCode()
{
return $this->sJsCode;
}
/** @ignore */
public function GetUrl()
{
return $this->sUrl;
}
}
/**
@@ -1150,14 +1063,11 @@ class JSButtonItem extends JSPopupMenuItem
* @api
* @package UIExtensibilityAPI
* @since 2.0
* @deprecated 3.0.0 If you need to include:
* * JS/CSS files/snippets, use {@see \iBackofficeLinkedScriptsExtension}, {@see \iBackofficeLinkedStylesheetsExtension}, etc instead
* * HTML (and optionally JS/CSS), use {@see \iPageUIBlockExtension} to manipulate {@see \Combodo\iTop\Application\UI\Base\UIBlock} instead
*/
interface iPageUIExtension
{
/**
* Add content to the header of the page
* Add content to the North pane
*
* @api
* @param iTopWebPage $oPage The page to insert stuff into.
@@ -1167,7 +1077,7 @@ interface iPageUIExtension
public function GetNorthPaneHtml(iTopWebPage $oPage);
/**
* Add content to the footer of the page
* Add content to the South pane
*
* @api
* @param iTopWebPage $oPage The page to insert stuff into.
@@ -1187,56 +1097,12 @@ interface iPageUIExtension
public function GetBannerHtml(iTopWebPage $oPage);
}
/**
* Implement this interface to add content to any iTopWebPage
*
* There are 3 places where content can be added:
*
* * The north pane: (normaly empty/hidden) at the top of the page, spanning the whole
* width of the page
* * The south pane: (normaly empty/hidden) at the bottom of the page, spanning the whole
* width of the page
* * The admin banner (two tones gray background) at the left of the global search.
* Limited space, use it for short messages
*
* Each of the methods of this interface is supposed to return the HTML to be inserted at
* the specified place and can use the passed iTopWebPage object to add javascript or CSS definitions
*
* @api
* @package UIBlockExtensibilityAPI
* @since 3.0.0
*/
interface iPageUIBlockExtension
{
/**
* Add content to the "admin banner"
*
* @return iUIBlock|null The Block to add into the page
*/
public function GetBannerBlock();
/**
* Add content to the header of the page
*
* @return iUIBlock|null The Block to add into the page
*/
public function GetHeaderBlock();
/**
* Add content to the footer of the page
*
* @return iUIBlock|null The Block to add into the page
*/
public function GetFooterBlock();
}
/**
* Extend this class instead of iPageUIExtension if you don't need to overload all methods
*
* @api
* @package UIExtensibilityAPI
* @since 2.7.0
* @deprecated since 3.0.0 use AbstractPageUIBlockExtension instead
*/
abstract class AbstractPageUIExtension implements iPageUIExtension
{
@@ -1245,8 +1111,6 @@ abstract class AbstractPageUIExtension implements iPageUIExtension
*/
public function GetNorthPaneHtml(iTopWebPage $oPage)
{
DeprecatedCallsLog::NotifyDeprecatedPhpMethod('use iPageUIBlockExtension instead');
return '';
}
@@ -1255,8 +1119,6 @@ abstract class AbstractPageUIExtension implements iPageUIExtension
*/
public function GetSouthPaneHtml(iTopWebPage $oPage)
{
DeprecatedCallsLog::NotifyDeprecatedPhpMethod('use iPageUIBlockExtension instead');
return '';
}
@@ -1265,201 +1127,11 @@ abstract class AbstractPageUIExtension implements iPageUIExtension
*/
public function GetBannerHtml(iTopWebPage $oPage)
{
DeprecatedCallsLog::NotifyDeprecatedPhpMethod('use iPageUIBlockExtension instead');
return '';
}
}
/**
* Extend this class instead of iPageUIExtension if you don't need to overload all methods
*
* @api
* @package UIBlockExtensibilityAPI
* @since 3.0.0
*/
abstract class AbstractPageUIBlockExtension implements iPageUIBlockExtension
{
/**
* @inheritDoc
*/
public function GetBannerBlock()
{
return null;
}
/**
* @inheritDoc
*/
public function GetHeaderBlock()
{
return null;
}
/**
* @inheritDoc
*/
public function GetFooterBlock()
{
return null;
}
}
/**
* Implement this interface to add script (JS) files to the backoffice pages
*
* @see \iTopWebPage::$a_linked_scripts
* @api
* @package BackofficeUIExtensibilityAPI
* @since 3.0.0
*/
interface iBackofficeLinkedScriptsExtension
{
/**
* @see \iTopWebPage::$a_linked_scripts Each script will be included using this property
* @return array An array of absolute URLs to the files to include
*/
public function GetLinkedScriptsAbsUrls(): array;
}
/**
* Implement this interface to add inline script (JS) to the backoffice pages' head.
* Will be executed first, BEFORE the DOM interpretation.
*
* @see \iTopWebPage::$a_early_scripts
* @api
* @package BackofficeUIExtensibilityAPI
* @since 3.0.0
*/
interface iBackofficeEarlyScriptExtension
{
/**
* @see \iTopWebPage::$a_early_scripts
* @return string
*/
public function GetEarlyScript(): string;
}
/**
* Implement this interface to add inline script (JS) to the backoffice pages that will be executed immediately, without waiting for the DOM to be ready.
*
* @see \iTopWebPage::$a_scripts
* @api
* @package BackofficeUIExtensibilityAPI
* @since 3.0.0
*/
interface iBackofficeScriptExtension
{
/**
* @see \iTopWebPage::$a_scripts
* @return string
*/
public function GetScript(): string;
}
/**
* Implement this interface to add inline script (JS) to the backoffice pages that will be executed right when the DOM is ready.
*
* @see \iTopWebPage::$a_init_scripts
* @api
* @package BackofficeUIExtensibilityAPI
* @since 3.0.0
*/
interface iBackofficeInitScriptExtension
{
/**
* @see \iTopWebPage::$a_init_scripts
* @return string
*/
public function GetInitScript(): string;
}
/**
* Implement this interface to add inline script (JS) to the backoffice pages that will be executed slightly AFTER the DOM is ready (just after the init. scripts).
*
* @see \iTopWebPage::$a_ready_scripts
* @api
* @package BackofficeUIExtensibilityAPI
* @since 3.0.0
*/
interface iBackofficeReadyScriptExtension
{
/**
* @see \iTopWebPage::$a_ready_scripts
* @return string
*/
public function GetReadyScript(): string;
}
/**
* Implement this interface to add stylesheets (CSS) to the backoffice pages
*
* @see \iTopWebPage::$a_linked_stylesheets
* @api
* @package BackofficeUIExtensibilityAPI
* @since 3.0.0
*/
interface iBackofficeLinkedStylesheetsExtension
{
/**
* @see \iTopWebPage::$a_linked_stylesheets
* @return array An array of absolute URLs to the files to include
*/
public function GetLinkedStylesheetsAbsUrls(): array;
}
/**
* Implement this interface to add inline style (CSS) to the backoffice pages' head.
*
* @see \iTopWebPage::$a_styles
* @api
* @package BackofficeUIExtensibilityAPI
* @since 3.0.0
*/
interface iBackofficeStyleExtension
{
/**
* @see \iTopWebPage::$a_styles
* @return string
*/
public function GetStyle(): string;
}
/**
* Implement this interface to add Dict entries
*
* @see \iTopWebPage::$a_dict_entries
* @api
* @package BackofficeUIExtensibilityAPI
* @since 3.0.0
*/
interface iBackofficeDictEntriesExtension
{
/**
* @see \iTopWebPage::a_dict_entries
* @return array
*/
public function GetDictEntries(): array;
}
/**
* Implement this interface to add Dict entries prefixes
*
* @see \iTopWebPage::$a_dict_entries_prefixes
* @api
* @package BackofficeUIExtensibilityAPI
* @since 3.0.0
*/
interface iBackofficeDictEntriesPrefixesExtension
{
/**
* @see \iTopWebPage::a_dict_entries_prefixes
* @return array
*/
public function GetDictEntriesPrefixes(): array;
}
/**
* Implement this interface to add content to any enhanced portal page
*
@@ -1644,6 +1316,11 @@ interface iRestServiceProvider
public function ExecOperation($sVersion, $sVerb, $aParams);
}
interface iRestInputSanitizer
{
public function SanitizeJsonInput(string $sJsonInput): string;
}
/**
* Minimal REST response structure. Derive this structure to add response data and error codes.
*
@@ -1733,6 +1410,14 @@ class RestResult
* @api
*/
public $message;
/**
* Sanitize the content of this result to hide sensitive information
*/
public function SanitizeContent()
{
// The default implementation does nothing
}
}
/**
@@ -1949,6 +1634,8 @@ class RestUtils
*
* @return DBObject The object found
* @throws Exception If the input structure is not valid or it could not find exactly one object
*
* @see DBObject::CheckChangedExtKeysValues() generic method to check that we can access the linked object isn't used in that use case because values can be literal, OQL, friendlyname
*/
public static function FindObjectFromKey($sClass, $key, $bAllowNullValue = false)
{
@@ -2035,8 +1722,16 @@ class RestUtils
elseif (is_string($key))
{
// OQL
$oSearch = DBObjectSearch::FromOQL($key);
}
try {
$oSearch = DBObjectSearch::FromOQL($key);
} catch (Exception $e) {
throw new CoreOqlException('Query failed to execute', [
'query' => $key,
'exception_class' => get_class($e),
'exception_message' => $e->getMessage(),
]);
}
}
else
{
throw new Exception("Wrong format for key");
@@ -2185,4 +1880,28 @@ class RestUtils
interface iModuleExtension
{
public function __construct();
}
/**
* KPI logging extensibility point
*
* KPI Logger extension
*/
interface iKPILoggerExtension
{
/**
* Init the statistics collected
*
* @return void
*/
public function InitStats();
/**
* Add a new KPI to the stats
*
* @param \Combodo\iTop\Core\Kpi\KpiLogData $oKPILogData
*
* @return mixed
*/
public function LogOperation($oKPILogData);
}

View File

@@ -1,5 +1,5 @@
<?php
// Copyright (C) 2010-2021 Combodo SARL
// Copyright (C) 2010-2012 Combodo SARL
//
// This file is part of iTop.
//
@@ -22,7 +22,7 @@
* to check and is linked to a set of rules that determine the valid or invalid objects
* inside the set
*
* @copyright Copyright (C) 2010-2021 Combodo SARL
* @copyright Copyright (C) 2010-2012 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/

View File

@@ -1,5 +1,5 @@
<?php
// Copyright (C) 2010-2021 Combodo SARL
// Copyright (C) 2010-2012 Combodo SARL
//
// This file is part of iTop.
//
@@ -23,7 +23,7 @@
* or the "bad" ones. The core audit engines computes the complement to the definition
* set when needed to obtain either the valid objects, or the ones with an error
*
* @copyright Copyright (C) 2010-2021 Combodo SARL
* @copyright Copyright (C) 2010-2012 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
@@ -43,6 +43,7 @@ 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,8 +1,84 @@
<?php
// Copyright (C) 2016 Combodo SARL
//
// This file is part of iTop.
//
// iTop is free software; you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// iTop is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with iTop. If not, see <http://www.gnu.org/licenses/>
/**
* @deprecated will be removed in 3.1.0 - moved to sources/application/WebPage/CaptureWebPage.php, now loadable using autoloader
* Adapter class: when an API requires WebPage and you want to produce something else
*
* @copyright Copyright (C) 2016 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
* @copyright Copyright (C) 2010-2021 Combodo SARL
*/
DeprecatedCallsLog::NotifyDeprecatedFile('moved to sources/application/WebPage/CaptureWebPage.php, now loadable using autoloader');
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,8 +1,97 @@
<?php
// Copyright (C) 2010-2015 Combodo SARL
//
// This file is part of iTop.
//
// iTop is free software; you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// iTop is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with iTop. If not, see <http://www.gnu.org/licenses/>
/**
* @deprecated will be removed in 3.1.0 - moved to sources/application/WebPage/CLIPage.php, now loadable using autoloader
* CLI page
* The page adds the content-type text/XML and the encoding into the headers
*
* @copyright Copyright (C) 2010-2015 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
* @copyright Copyright (C) 2010-2021 Combodo SARL
*/
DeprecatedCallsLog::NotifyDeprecatedFile('moved to sources/application/WebPage/CLIPage.php, now loadable using autoloader');
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,38 +0,0 @@
<?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
*/
/**
* Class CompileCSSService : used to ease testing ThemeHander class via mocks
*
* @author Olivier DAIN <olivier.dain@combodo.com>
* @since 3.0.0 N°2982
*/
class CompileCSSService
{
/**
* CompileCSSService constructor.
*/
public function __construct()
{
}
public function CompileCSSFromSASS($sSassContent, $aImportPaths = [], $aVariables = []){
return utils::CompileCSSFromSASS($sSassContent, $aImportPaths, $aVariables);
}
}

View File

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

View File

@@ -1,15 +1,22 @@
<?php
/*
* @copyright Copyright (C) 2010-2021 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
/**
* 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
*/
use Combodo\iTop\Application\UI\Base\Component\Button\ButtonUIBlockFactory;
use Combodo\iTop\Application\UI\Base\Component\DataTable\DataTableSettings;
use Combodo\iTop\Application\UI\Base\Component\PopoverMenu\PopoverMenu;
use Combodo\iTop\Application\UI\Base\Component\Toolbar\ToolbarUIBlockFactory;
use Combodo\iTop\Application\UI\Base\Layout\Dashboard\DashboardLayout as DashboardLayoutUIBlock;
require_once(APPROOT.'application/dashboardlayout.class.inc.php');
require_once(APPROOT.'application/dashlet.class.inc.php');
require_once(APPROOT.'core/modelreflection.class.inc.php');
@@ -431,19 +438,22 @@ abstract class Dashboard
public function RenderProperties($oPage, $aExtraParams = array())
{
// menu to pick a layout and edit other properties of the dashboard
$oPage->add('<div class="ui-widget-content ui-corner-all ibo-dashboard-editor--properties"><div class="ui-widget-header ui-corner-all ibo-dashboard-editor--properties-title">'.Dict::S('UI:DashboardEdit:Properties').'</div>');
$oPage->add('<div class="ui-widget-content ui-corner-all"><div class="ui-widget-header ui-corner-all" style="text-align:center; padding: 2px;">'.Dict::S('UI:DashboardEdit:Properties').'</div>');
$sUrl = utils::GetAbsoluteUrlAppRoot();
$oPage->add('<div class="ibo-dashboard-editor--properties-subtitle" data-role="ibo-dashboard-editor--properties-subtitle">'.Dict::S('UI:DashboardEdit:Layout').'</div>');
$oPage->add('<div id="select_layout" class="ibo-dashboard-editor--layout-list" data-role="ibo-dashboard-editor--layout-list">');
foreach (get_declared_classes() as $sLayoutClass) {
if (is_subclass_of($sLayoutClass, 'DashboardLayout')) {
$oPage->add('<div style="text-align:center">'.Dict::S('UI:DashboardEdit:Layout').'</div>');
$oPage->add('<div id="select_layout" style="text-align:center">');
foreach( get_declared_classes() as $sLayoutClass)
{
if (is_subclass_of($sLayoutClass, 'DashboardLayout'))
{
$oReflection = new ReflectionClass($sLayoutClass);
if (!$oReflection->isAbstract()) {
if (!$oReflection->isAbstract())
{
$aCallSpec = array($sLayoutClass, 'GetInfo');
$aInfo = call_user_func($aCallSpec);
$sChecked = ($this->sLayoutClass == $sLayoutClass) ? 'checked' : '';
$oPage->add('<input type="radio" name="layout_class" '.$sChecked.' value="'.$sLayoutClass.'" id="layout_'.$sLayoutClass.'"><label for="layout_'.$sLayoutClass.'"><img src="'.$sUrl.$aInfo['icon'].'" class="ibo-dashboard--properties--icon" data-role="ibo-dashboard--properties--icon"/></label>'); // title="" on either the img or the label does nothing !
$oPage->add('<input type="radio" name="layout_class" '.$sChecked.' value="'.$sLayoutClass.'" id="layout_'.$sLayoutClass.'"><label for="layout_'.$sLayoutClass.'"><img src="'.$sUrl.$aInfo['icon'].'" /></label>'); // title="" on either the img or the label does nothing !
}
}
}
@@ -474,15 +484,14 @@ abstract class Dashboard
$oPage->add_ready_script(
<<<EOF
// Note: the title gets deleted by the validation mechanism
$("#attr_auto_reload_sec").attr('data-tooltip-content', '$sRateTitle');
CombodoTooltip.InitTooltipFromMarkup($("#attr_auto_reload_sec"));
$("#attr_auto_reload_sec").tooltip({items: 'input', content: '$sRateTitle'});
$("#attr_auto_reload_sec").prop('disabled', !$('#attr_auto_reload').is(':checked'));
$('#attr_auto_reload').change( function(ev) {
$("#attr_auto_reload_sec").prop('disabled', !$(this).is(':checked'));
} );
$('#select_layout').controlgroup();
$('#select_layout').buttonset();
$('#select_dashlet').droppable({
accept: '.dashlet',
drop: function(event, ui) {
@@ -492,7 +501,7 @@ abstract class Dashboard
},
});
$('#event_bus').on('dashlet-selected', function(event, data){
$('#event_bus').bind('dashlet-selected', function(event, data){
var sDashletId = data.dashlet_id;
var sPropId = 'dashlet_properties_'+sDashletId;
$('.dashlet_properties').each(function() {
@@ -517,55 +526,34 @@ EOF
* @param bool $bEditMode
* @param array $aExtraParams
* @param bool $bCanEdit
*
* @return \Combodo\iTop\Application\UI\Base\Layout\Dashboard\DashboardLayout
*/
public function Render($oPage, $bEditMode = false, $aExtraParams = array(), $bCanEdit = true)
{
if (!array_key_exists('dashboard_div_id', $aExtraParams)) {
if (!array_key_exists('dashboard_div_id', $aExtraParams))
{
$aExtraParams['dashboard_div_id'] = utils::Sanitize($this->GetId(), '', 'element_identifier');
}
$oPage->add('<div class="dashboard-title-line"><div class="dashboard-title">'.htmlentities(Dict::S($this->sTitle), ENT_QUOTES, 'UTF-8', false).'</div></div>');
/** @var \DashboardLayoutMultiCol $oLayout */
$oLayout = new $this->sLayoutClass();
foreach ($this->aCells as $iCellIdx => $aDashlets) {
foreach ($aDashlets as $oDashlet) {
foreach($this->aCells as $iCellIdx => $aDashlets)
{
foreach($aDashlets as $oDashlet)
{
$aDashletCoordinates = $oLayout->GetDashletCoordinates($iCellIdx);
$this->PrepareDashletForRendering($oDashlet, $aDashletCoordinates, $aExtraParams);
}
}
$oDashboard = $oLayout->Render($oPage, $this->aCells, $bEditMode, $aExtraParams);
$oPage->AddUiBlock($oDashboard);
$bFromDasboardPage = isset($aExtraParams['from_dashboard_page']) ? isset($aExtraParams['from_dashboard_page']) : false;
if ($bFromDasboardPage) {
$sTitleForHTML = utils::HtmlEntities(Dict::S($this->sTitle));
$sHtml = "<div class=\"ibo-top-bar--toolbar-dashboard-title\" title=\"{$sTitleForHTML}\">{$sTitleForHTML}</div>";
if ($oPage instanceof iTopWebPage) {
$oTopBar = $oPage->GetTopBarLayout();
$oToolbar = ToolbarUIBlockFactory::MakeStandard();
$oTopBar->SetToolbar($oToolbar);
$oToolbar->AddHtml($sHtml);
} else {
$oPage->add_script(<<<JS
$(".ibo-top-bar--toolbar-dashboard-title").html("$sTitleForHTML").attr("title", $('<div>').html("$sTitleForHTML").text());
JS
);
}
} else {
$oDashboard->SetTitle(Dict::S($this->sTitle));
}
if (!$bEditMode) {
$oLayout->Render($oPage, $this->aCells, $bEditMode, $aExtraParams);
if (!$bEditMode)
{
$oPage->add_linked_script('../js/dashlet.js');
$oPage->add_linked_script('../js/dashboard.js');
}
return $oDashboard;
}
/**
@@ -577,18 +565,19 @@ JS
public function RenderDashletsSelection(WebPage $oPage)
{
// Toolbox/palette to drag and drop dashlets
$oPage->add('<div class="ui-widget-content ui-corner-all ibo-dashboard--available-dashlets"><div class="ui-widget-header ui-corner-all ibo-dashboard--available-dashlet--title">'.Dict::S('UI:DashboardEdit:Dashlets').'</div>');
$oPage->add('<div class="ui-widget-content ui-corner-all"><div class="ui-widget-header ui-corner-all" style="text-align:center; padding: 2px;">'.Dict::S('UI:DashboardEdit:Dashlets').'</div>');
$sUrl = utils::GetAbsoluteUrlAppRoot();
$oPage->add('<div id="select_dashlet" class="ibo-dashboard--available-dashlets--list" data-role="ibo-dashboard--available-dashlets--list">');
$oPage->add('<div id="select_dashlet" style="text-align:center; max-height:120px; overflow-y:auto;">');
$aAvailableDashlets = $this->GetAvailableDashlets();
foreach ($aAvailableDashlets as $sDashletClass => $aInfo) {
$oPage->add('<span dashlet_class="'.$sDashletClass.'" class="ibo-dashboard-editor--available-dashlet-icon dashlet_icon ui-widget-content ui-corner-all" data-role="ibo-dashboard-editor--available-dashlet-icon" id="dashlet_'.$sDashletClass.'" data-tooltip-content="'.$aInfo['label'].'" title="'.$aInfo['label'].'"><img src="'.$sUrl.$aInfo['icon'].'" /></span>');
foreach($aAvailableDashlets as $sDashletClass => $aInfo)
{
$oPage->add('<span dashlet_class="'.$sDashletClass.'" class="dashlet_icon ui-widget-content ui-corner-all" id="dashlet_'.$sDashletClass.'" title="'.$aInfo['label'].'" style="width:34px; height:34px; display:inline-block; margin:2px;"><img src="'.$sUrl.$aInfo['icon'].'" /></span>');
}
$oPage->add('</div>');
$oPage->add('</div>');
$oPage->add_ready_script("$('.dashlet_icon').draggable({cursor: 'move', helper: 'clone', appendTo: 'body', zIndex: 10000, revert:'invalid'});");
$oPage->add_ready_script("$('.dashlet_icon').draggable({helper: 'clone', appendTo: 'body', zIndex: 10000, revert:'invalid'});");
}
/**
@@ -598,12 +587,12 @@ JS
public function RenderDashletsProperties(WebPage $oPage, $aExtraParams = array())
{
// Toolbox/palette to edit the properties of each dashlet
$oPage->add('<div class="ui-widget-content ui-corner-all ibo-dashlet--properties"><div class="ui-widget-header ui-corner-all ibo-dashlet--properties--title">'.Dict::S('UI:DashboardEdit:DashletProperties').'</div>');
$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">');
$oPage->add('<div id="dashlet_properties" style="text-align:center">');
foreach($this->aCells as $iCellIdx => $aCell)
{
/** @var \Dashlet $oDashlet */
@@ -636,13 +625,16 @@ JS
foreach( get_declared_classes() as $sDashletClass)
{
// DashletUnknown is not among the selection as it is just a fallback for dashlets that can't instantiated.
if (is_subclass_of($sDashletClass, 'Dashlet') && !in_array($sDashletClass, array('DashletUnknown', 'DashletProxy'))) {
// DashletUnknown is not among the selection as it is just a fallback for dashlets that can't instanciated.
if ( is_subclass_of($sDashletClass, 'Dashlet') && !in_array($sDashletClass, array('DashletUnknown', 'DashletProxy')) )
{
$oReflection = new ReflectionClass($sDashletClass);
if (!$oReflection->isAbstract()) {
if (!$oReflection->isAbstract())
{
$aCallSpec = array($sDashletClass, 'IsVisible');
$bVisible = call_user_func($aCallSpec);
if ($bVisible) {
if ($bVisible)
{
$aCallSpec = array($sDashletClass, 'GetInfo');
$aInfo = call_user_func($aCallSpec);
$aDashlets[$sDashletClass] = $aInfo;
@@ -789,7 +781,6 @@ class RuntimeDashboard extends Dashboard
/**
* @inheritDoc
* @return bool $bIsNew
* @throws \Exception
*/
public function Save()
@@ -799,7 +790,6 @@ class RuntimeDashboard extends Dashboard
$oUDSearch->AddCondition('user_id', UserRights::GetUserId(), '=');
$oUDSearch->AddCondition('menu_code', $this->sId, '=');
$oUDSet = new DBObjectSet($oUDSearch);
$bIsNew = false;
if ($oUDSet->Count() > 0)
{
// Assuming there is at most one couple {user, menu}!
@@ -813,12 +803,10 @@ class RuntimeDashboard extends Dashboard
$oUserDashboard->Set('user_id', UserRights::GetUserId());
$oUserDashboard->Set('menu_code', $this->sId);
$oUserDashboard->Set('contents', $sXml);
$bIsNew = true;
}
utils::PushArchiveMode(false);
$oUserDashboard->DBWrite();
utils::PopArchiveMode();
return $bIsNew;
}
/**
@@ -895,53 +883,11 @@ class RuntimeDashboard extends Dashboard
$oDashboard->FromXml($sDashboardDefinition);
$oDashboard->SetCustomFlag($bCustomized);
$oDashboard->SetDefinitionFile($sDashboardFileSanitized);
} else {
}
else
{
$oDashboard = null;
}
return $oDashboard;
}
/**
* @param string $sDashboardFile file name relative to the current module folder
* @param string $sDashBoardId code of the dashboard either menu_id or <class>__<attcode>
*
* @return null|RuntimeDashboard
* @throws \CoreException
* @throws \CoreUnexpectedValue
* @throws \MissingQueryArgument
* @throws \MySQLException
* @throws \MySQLHasGoneAwayException
* @throws \Exception
*/
public static function GetDashboardToEdit($sDashboardFile, $sDashBoardId)
{
$bCustomized = false;
// Search for an eventual user defined dashboard
$oUDSearch = new DBObjectSearch('UserDashboard');
$oUDSearch->AddCondition('user_id', UserRights::GetUserId(), '=');
$oUDSearch->AddCondition('menu_code', $sDashBoardId, '=');
$oUDSet = new DBObjectSet($oUDSearch);
if ($oUDSet->Count() > 0) {
// Assuming there is at most one couple {user, menu}!
$oUserDashboard = $oUDSet->Fetch();
$sDashboardDefinition = $oUserDashboard->Get('contents');
$bCustomized = true;
} else {
$sDashboardDefinition = @file_get_contents($sDashboardFile);
}
if ($sDashboardDefinition !== false) {
$oDashboard = new RuntimeDashboard($sDashBoardId);
$oDashboard->FromXml($sDashboardDefinition);
$oDashboard->SetCustomFlag($bCustomized);
$oDashboard->SetDefinitionFile($sDashboardFile);
} else {
$oDashboard = null;
}
return $oDashboard;
}
@@ -951,33 +897,40 @@ class RuntimeDashboard extends Dashboard
*/
public function Render($oPage, $bEditMode = false, $aExtraParams = array(), $bCanEdit = true)
{
if (!isset($aExtraParams['query_params']) && isset($aExtraParams['this->class'])) {
if (!isset($aExtraParams['query_params']) && isset($aExtraParams['this->class']))
{
$oObj = MetaModel::GetObject($aExtraParams['this->class'], $aExtraParams['this->id']);
$aRenderParams = array('query_params' => $oObj->ToArgsForQuery());
} else {
}
else
{
$aRenderParams = $aExtraParams;
}
$oDashboard = parent::Render($oPage, $bEditMode, $aRenderParams);
parent::Render($oPage, $bEditMode, $aRenderParams);
if (isset($aExtraParams['query_params']['this->object()'])) {
if (isset($aExtraParams['query_params']['this->object()']))
{
/** @var \DBObject $oObj */
$oObj = $aExtraParams['query_params']['this->object()'];
$aAjaxParams = array('this->class' => get_class($oObj), 'this->id' => $oObj->GetKey());
if (isset($aExtraParams['from_dashboard_page'])) {
$aAjaxParams['from_dashboard_page'] = $aExtraParams['from_dashboard_page'];
}
} else {
}
else
{
$aAjaxParams = $aExtraParams;
}
if (!$bEditMode && !$oPage->IsPrintableVersion()) {
if (!$bEditMode && !$oPage->IsPrintableVersion())
{
$sId = $this->GetId();
$sDivId = utils::Sanitize($sId, '', 'element_identifier');
if ($this->GetAutoReload()) {
if ($this->GetAutoReload())
{
$sFile = addslashes($this->GetDefinitionFile());
$sExtraParams = json_encode($aAjaxParams);
$iReloadInterval = 1000 * $this->GetAutoReloadInterval();
$sReloadURL = $this->GetReloadURL();
$oPage->add_script(
<<<JS
<<<EOF
if (typeof(AutoReloadDashboardId$sDivId) !== 'undefined')
{
clearInterval(AutoReloadDashboardId$sDivId);
@@ -989,18 +942,25 @@ class RuntimeDashboard extends Dashboard
function ReloadDashboard$sDivId()
{
// Do not reload when a dialog box is active
if (!($('.ui-dialog:visible').length > 0) && $('.ibo-dashboard#$sDivId').is(':visible'))
if (!($('.ui-dialog:visible').length > 0) && $('.dashboard_contents#$sDivId').is(':visible'))
{
updateDashboard$sDivId();
$('.dashboard_contents#$sDivId').block();
$.post(GetAbsoluteUrlAppRoot()+'pages/ajax.render.php',
{ operation: 'reload_dashboard', dashboard_id: '$sId', file: '$sFile', extra_params: $sExtraParams, reload_url: '$sReloadURL'},
function(data){
$('.dashboard_contents#$sDivId').html(data);
$('.dashboard_contents#$sDivId').unblock();
}
);
}
}
JS
EOF
);
}
else
{
$oPage->add_script(
<<<EOF
<<<EOF
if (typeof(AutoReloadDashboardId$sDivId) !== 'undefined')
{
clearInterval(AutoReloadDashboardId$sDivId);
@@ -1010,75 +970,60 @@ EOF
);
}
if ($bCanEdit) {
$this->RenderSelector($oPage, $oDashboard, $aAjaxParams);
$this->RenderEditionTools($oPage, $oDashboard, $aAjaxParams);
if ($bCanEdit)
{
$this->RenderSelector($oPage, $aAjaxParams);
$this->RenderEditionTools($oPage, $aAjaxParams);
}
}
}
/**
* @param WebPage $oPage
* @param \Combodo\iTop\Application\UI\Base\Layout\Dashboard\DashboardLayout $oDashboard
* @param bool $bFromDashboardPage
* @param \iTopWebPage $oPage
* @param array $aAjaxParams
*
* @throws \CoreException
* @throws \CoreUnexpectedValue
* @throws \MySQLException
*/
protected function RenderSelector(WebPage $oPage, DashboardLayoutUIBlock $oDashboard, $aAjaxParams = array())
protected function RenderSelector($oPage, $aAjaxParams = array())
{
if (!$this->HasCustomDashboard()) {
return;
}
$sId = $this->GetId();
$sDivId = utils::Sanitize($sId, '', 'element_identifier');
$sExtraParams = json_encode($aAjaxParams);
$sSwitchToStandard = Dict::S('UI:Toggle:SwitchToStandardDashboard');
$sSwitchToCustom = Dict::S('UI:Toggle:SwitchToCustomDashboard');
$bStandardSelected = appUserPreferences::GetPref('display_original_dashboard_'.$sId, false);
$sSelectorHtml = '<div class="dashboard-selector">';
if ($this->HasCustomDashboard())
{
$bStandardSelected = appUserPreferences::GetPref('display_original_dashboard_'.$sId, false);
$sStandard = Dict::S('UI:Toggle:StandardDashboard');
$sSelectorHtml .= '<div class="selector-label">'.$sStandard.'</div>';
$sSelectorHtml .= '<label class="switch"><input type="checkbox" onchange="ToggleDashboardSelector'.$sDivId.'();" '.($bStandardSelected ? '' : 'checked').'><span class="slider round"></span></label></input></label>';
$sCustom = Dict::S('UI:Toggle:CustomDashboard');
$sSelectorHtml .= '<div class="selector-label">'.$sCustom.'</div>';
$sSelectorHtml = '<div id="ibo-dashboard-selector'.$sDivId.'" class="ibo-dashboard--selector" data-tooltip-content="'.($bStandardSelected ? $sSwitchToCustom : $sSwitchToStandard).'">';
$sSelectorHtml .= '<label class="ibo-dashboard--switch"><input type="checkbox" onchange="ToggleDashboardSelector'.$sDivId.'();" '.($bStandardSelected ? '' : 'checked').'><span class="ibo-dashboard--slider"></span></label></input></label>';
}
$sSelectorHtml .= '</div>';
$sSelectorHtml = addslashes($sSelectorHtml);
$sFile = addslashes($this->GetDefinitionFile());
$sReloadURL = $this->GetReloadURL();
$bFromDashboardPage = isset($aAjaxParams['from_dashboard_page']) ? isset($aAjaxParams['from_dashboard_page']) : false;
if ($bFromDashboardPage) {
if ($oPage instanceof iTopWebPage) {
$oToolbar = $oPage->GetTopBarLayout()->GetToolbar();
$oToolbar->AddHtml($sSelectorHtml);
}
} else {
$oToolbar = $oDashboard->GetToolbar();
$oToolbar->AddHtml($sSelectorHtml);
}
$oPage->add_ready_script(
<<<EOF
$('.dashboard-title').after('$sSelectorHtml');
EOF
);
$oPage->add_script(
<<<JS
<<<EOF
function ToggleDashboardSelector$sDivId()
{
var dashboard = $('.ibo-dashboard#$sDivId')
dashboard.block();
$('.dashboard_contents#$sDivId').block();
$.post(GetAbsoluteUrlAppRoot()+'pages/ajax.render.php',
{ operation: 'toggle_dashboard', dashboard_id: '$sId', file: '$sFile', extra_params: $sExtraParams, reload_url: '$sReloadURL' },
function(data) {
dashboard.html(data);
dashboard.unblock();
if ($('#ibo-dashboard-selector$sDivId input').prop("checked")) {
$('#ibo-dashboard-selector$sDivId').attr('data-tooltip-content', '$sSwitchToStandard');
} else {
$('#ibo-dashboard-selector$sDivId').attr('data-tooltip-content', '$sSwitchToCustom');
}
CombodoTooltip.InitAllNonInstantiatedTooltips($('#ibo-dashboard-selector$sDivId').parent(), true);
$('.dashboard_contents#$sDivId').html(data);
$('.dashboard_contents#$sDivId').unblock();
}
);
}
JS
EOF
);
}
@@ -1109,59 +1054,45 @@ JS
*
* @throws \Exception
*/
protected function RenderEditionTools(WebPage $oPage, DashboardLayoutUIBlock $oDashboard, $aExtraParams)
protected function RenderEditionTools(WebPage $oPage, $aExtraParams)
{
$oPage->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/jquery.iframe-transport.js');
$oPage->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/jquery.fileupload.js');
$sId = utils::Sanitize($this->GetId(), '', 'element_identifier');
$sMenuTogglerId = "ibo-dashboard-menu-toggler-{$sId}";
$sPopoverMenuId = "ibo-dashboard-menu-popover-{$sId}";
$sName = 'UI:Dashboard:Actions';
$bFromDashboardPage = isset($aExtraParams['from_dashboard_page']) ? isset($aExtraParams['from_dashboard_page']) : false;
if ($bFromDashboardPage) {
if (!($oPage instanceof iTopWebPage)) {
// TODO 3.0 change the menu
return;
}
$oToolbar = $oPage->GetTopBarLayout()->GetToolbar();
} else {
$oToolbar = $oDashboard->GetToolbar();
}
$oActionButton = ButtonUIBlockFactory::MakeIconAction('fas fa-ellipsis-v', Dict::S($sName), $sName, '', false, $sMenuTogglerId)
->AddCSSClass('ibo-top-bar--toolbar-dashboard-menu-toggler')
->AddCSSClass('ibo-action-button');
$oToolbar->AddSubBlock($oActionButton);
$sEditMenu = "<div id=\"DashboardMenu\"><ul><li><i class=\"top-right-icon icon-additional-arrow fas fa-pencil-alt\"></i><ul>";
$aActions = array();
$sFile = addslashes($this->sDefinitionFile);
$sJSExtraParams = json_encode($aExtraParams);
if ($this->HasCustomDashboard()) {
$oEdit = new JSPopupMenuItem('UI:Dashboard:Edit', Dict::S('UI:Dashboard:EditCustom'), "return EditDashboard('{$this->sId}', '$sFile', $sJSExtraParams)");
$aActions[$oEdit->GetUID()] = $oEdit->GetMenuItem();
$oRevert = new JSPopupMenuItem('UI:Dashboard:RevertConfirm', Dict::S('UI:Dashboard:DeleteCustom'),
"if (confirm('".addslashes(Dict::S('UI:Dashboard:RevertConfirm'))."')) return RevertDashboard('{$this->sId}', $sJSExtraParams); else return false");
$aActions[$oRevert->GetUID()] = $oRevert->GetMenuItem();
} else {
$oEdit = new JSPopupMenuItem('UI:Dashboard:Edit', Dict::S('UI:Dashboard:CreateCustom'), "return EditDashboard('{$this->sId}', '$sFile', $sJSExtraParams)");
$bCanEdit = true;
if ($this->HasCustomDashboard())
{
$bCanEdit = !appUserPreferences::GetPref('display_original_dashboard_'.$this->GetId(), false);
}
if ($bCanEdit)
{
$oEdit = new JSPopupMenuItem('UI:Dashboard:Edit', Dict::S('UI:Dashboard:Edit'), "return EditDashboard('{$this->sId}', '$sFile', $sJSExtraParams)");
$aActions[$oEdit->GetUID()] = $oEdit->GetMenuItem();
}
if ($this->bCustomized)
{
$oRevert = new JSPopupMenuItem('UI:Dashboard:RevertConfirm', Dict::S('UI:Dashboard:Revert'),
"if (confirm('".addslashes(Dict::S('UI:Dashboard:RevertConfirm'))."')) return RevertDashboard('{$this->sId}', $sJSExtraParams); else return false");
$aActions[$oRevert->GetUID()] = $oRevert->GetMenuItem();
}
utils::GetPopupMenuItems($oPage, iPopupMenuExtension::MENU_DASHBOARD_ACTIONS, $this, $aActions);
$oActionsMenu = $oPage->GetPopoverMenu($sPopoverMenuId, $aActions)
->SetTogglerJSSelector("#$sMenuTogglerId")
->SetContainer(PopoverMenu::ENUM_CONTAINER_BODY);
$oToolbar->AddSubBlock($oActionButton)
->AddSubBlock($oActionsMenu);
$sEditMenu .= $oPage->RenderPopupMenuItems($aActions);
$sEditMenu = addslashes($sEditMenu);
$sReloadURL = $this->GetReloadURL();
$oPage->add_ready_script(
<<<EOF
$('.dashboard-title').after('$sEditMenu');
$('#DashboardMenu>ul').popupmenu();
EOF
);
$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'},
@@ -1195,7 +1126,7 @@ EOF
$oPage->add_ready_script(
<<<EOF
$('#select_layout input').on('click', function() {
$('#select_layout input').click( function() {
var sLayoutClass = $(this).val();
$('.itop-dashboard').runtimedashboard('option', {layout_class: sLayoutClass});
} );
@@ -1234,37 +1165,40 @@ EOF
*/
public function RenderEditor($oPage, $aExtraParams = array())
{
if (isset($aExtraParams['this->class'])) {
if (isset($aExtraParams['this->class']))
{
$oObj = MetaModel::GetObject($aExtraParams['this->class'], $aExtraParams['this->id']);
$aRenderParams = array('query_params' => $oObj->ToArgsForQuery());
} else {
}
else
{
$aRenderParams = $aExtraParams;
}
$aRenderParams['dashboard_div_id'] = $aExtraParams['dashboard_div_id'];
$sJSExtraParams = json_encode($aExtraParams);
$oPage->add('<div id="dashboard_editor" class="ibo-dashboard-editor" data-role="ibo-dashboard-editor">');
$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 ibo-dashboard-editor--pane" data-role="ibo-dashboard-editor--pane">');
$oPage->add('<div class="ui-layout-east">');
$this->RenderProperties($oPage, $aExtraParams);
$this->RenderDashletsSelection($oPage);
$this->RenderDashletsProperties($oPage, $aExtraParams);
$oPage->add('</div>');
$oPage->add('<div id="event_bus"/>'); // For exchanging messages between the panes, same as in the designer
$oPage->add('</div>');
$sDialogTitle = Dict::S('UI:DashboardEdit:Title');
$sOkButtonLabel = Dict::S('UI:Button:Save');
$sCancelButtonLabel = Dict::S('UI:Button:Cancel');
$sId = addslashes($this->sId);
$sLayoutClass = addslashes($this->sLayoutClass);
$sId = json_encode($this->sId);
$sLayoutClass = json_encode($this->sLayoutClass);
$sAutoReload = $this->bAutoReload ? 'true' : 'false';
$sAutoReloadSec = (string) $this->iAutoReloadSec;
$sTitle = addslashes($this->sTitle);
$sFile = addslashes($this->GetDefinitionFile());
$sTitle = json_encode($this->sTitle);
$sFile = json_encode($this->GetDefinitionFile());
$sUrl = utils::GetAbsoluteUrlAppRoot().'pages/ajax.render.php';
$sReloadURL = $this->GetReloadURL();
@@ -1282,24 +1216,7 @@ $('#dashboard_editor').dialog({
modal: true,
title: '$sDialogTitle',
buttons: [
{ text: "$sCancelButtonLabel",
class: "ibo-is-alternative",
click: function() {
var oDashboard = $('.itop-dashboard').data('itopRuntimedashboard');
if (oDashboard.is_modified())
{
if (!confirm('$sCancelConfirmationMessage'))
{
return;
}
}
window.bLeavingOnUserAction = true;
$(this).dialog( "close" );
$(this).remove();
} },
{ text: "$sOkButtonLabel",
class: "ibo-is-primary",
click: function() {
{ text: "$sOkButtonLabel", click: function() {
var oDashboard = $('.itop-dashboard').data('itopRuntimedashboard');
if (oDashboard.is_dirty())
{
@@ -1315,33 +1232,50 @@ $('#dashboard_editor').dialog({
window.bLeavingOnUserAction = true;
oDashboard.save($(this));
} },
{ text: "$sCancelButtonLabel", click: function() {
var oDashboard = $('.itop-dashboard').data('itopRuntimedashboard');
if (oDashboard.is_modified())
{
if (!confirm('$sCancelConfirmationMessage'))
{
return;
}
}
window.bLeavingOnUserAction = true;
$(this).dialog( "close" );
$(this).remove();
} },
],
close: function() { $(this).remove(); }
});
$('#dashboard_editor .ui-layout-center').runtimedashboard({
dashboard_id: '$sId',
layout_class: '$sLayoutClass',
title: '$sTitle',
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'},
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'},
render_parameters: {operation: 'render_dashboard', file: $sFile, extra_params: $sJSExtraParams, reload_url: '$sReloadURL'},
new_dashlet_parameters: {operation: 'new_dashlet'}
});
var dashboard_prop_size = GetUserPreference('dashboard_prop_size', 400);
$('#dashboard_editor > .itop-dashboard').width($('#dashboard_editor').width() - dashboard_prop_size);
// We check when we finish click on the pane with the resize slider
// if the pane size changed (% 5px), if it's the case we save the value in userpref
$('#dashboard_editor > .itop-dashboard').on('mouseup',function (){
var iWidthDiff = $(this).width() - ($('#dashboard_editor').width() - dashboard_prop_size);
if( Math.abs(iWidthDiff) > 5){
dashboard_prop_size = iWidthDiff;
SetUserPreference('dashboard_prop_size', $('#dashboard_editor').width() - $(this).width(), true);
dashboard_prop_size = GetUserPreference('dashboard_prop_size', 350);
$('#dashboard_editor').layout({
east: {
minSize: 200,
size: dashboard_prop_size,
togglerLength_open: 0,
togglerLength_closed: 0,
onresize_end: function(name, elt, state, options, layout)
{
if (state.isSliding == false)
{
SetUserPreference('dashboard_prop_size', state.size, true);
}
},
}
});
@@ -1503,37 +1437,32 @@ JS
$sCancelButtonLabel = Dict::S('UI:Button:Cancel');
$oPage->add_ready_script(
<<<JS
<<<JS
$('#dashlet_creation_dlg').dialog({
width: 600,
modal: true,
title: '$sDialogTitle',
buttons: [
{ text: "$sCancelButtonLabel",
click: function() {
{ text: "$sOkButtonLabel", click: function() {
var oForm = $(this).find('form');
var sFormId = oForm.attr('id');
var oParams = null;
var aErrors = ValidateForm(sFormId, false);
if (aErrors.length == 0)
{
oParams = ReadFormParams(sFormId);
}
oParams.operation = 'add_dashlet';
var me = $(this);
$.post(GetAbsoluteUrlAppRoot()+'pages/ajax.render.php', oParams, function(data) {
me.dialog( "close" );
me.remove();
$('body').append(data);
});
} },
{ text: "$sCancelButtonLabel", click: function() {
$(this).dialog( "close" ); $(this).remove();
} ,
'class': 'ibo-button ibo-is-alternative ibo-is-neutral action cancel'
},
{ text: "$sOkButtonLabel",
click: function() {
var oForm = $(this).find('form');
var sFormId = oForm.attr('id');
var oParams = null;
var aErrors = ValidateForm(sFormId, false);
if (aErrors.length == 0)
{
oParams = ReadFormParams(sFormId);
}
oParams.operation = 'add_dashlet';
var me = $(this);
$.post(GetAbsoluteUrlAppRoot()+'pages/ajax.render.php', oParams, function(data) {
me.dialog( "close" );
me.remove();
$('body').append(data);
});
},
'class': 'ibo-button ibo-is-regular ibo-is-primary action' }
} },
],
close: function() { $(this).remove(); }
});
@@ -1670,10 +1599,12 @@ JS
{
$sDataTableId = Dashlet::APPUSERPREFERENCES_PREFIX.$sDashletId;
$aClassAliases = array();
try {
try{
$oFilter = $oDashlet->GetDBSearch($aExtraParams);
$aClassAliases = $oFilter->GetSelectedClasses();
} catch (Exception $e) {
}
catch (Exception $e)
{
//on error, return default value
return null;
}

View File

@@ -1,5 +1,5 @@
<?php
// Copyright (C) 2010-2021 Combodo SARL
// Copyright (C) 2010-2012 Combodo SARL
//
// This file is part of iTop.
//
@@ -15,17 +15,15 @@
//
// 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\Base\Component\Html\Html;
use Combodo\iTop\Application\UI\Base\Layout\Dashboard\DashboardColumn;
use Combodo\iTop\Application\UI\Base\Layout\Dashboard\DashboardLayout as DashboardLayoutUIBlock;
use Combodo\iTop\Application\UI\Base\Layout\Dashboard\DashboardRow;
/**
* Dashboard presentation
*
* @copyright Copyright (C) 2010-2021 Combodo SARL
*
* @copyright Copyright (C) 2010-2012 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
*/
abstract class DashboardLayout
{
abstract public function Render($oPage, $aDashlets, $bEditMode = false);
@@ -116,59 +114,61 @@ 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);
$oDashboardLayout = new DashboardLayoutUIBlock();
//$oPage->AddUiBlock($oDashboardLayout);
$oPage->add('<table style="width:100%;table-layout:fixed;"><tbody>');
$iCellIdx = 0;
$fColSize = 100 / $this->iNbCols;
$sStyle = $bEditMode ? 'border: 1px #ccc dashed; width:'.$fColSize.'%;' : 'width: '.$fColSize.'%;';
$sClass = $bEditMode ? 'layout_cell edit_mode' : 'dashboard';
$iNbRows = ceil(count($aCells) / $this->iNbCols);
//Js given by each dashlet to reload
$sJSReload = "";
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)) {
for($iRows = 0; $iRows < $iNbRows; $iRows++)
{
$oPage->add("<tr data-dashboard-row-index=\"$iRows\">");
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-column-index=\"$iCols\" data-dashboard-cell-index=\"$iCellIdx\">");
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()) {
$oDashboardColumn->AddUIBlock($oDashlet->DoRender($oPage, $bEditMode, true /* bEnclosingDiv */, $aExtraParams));
foreach($aDashlets as $oDashlet)
{
if ($oDashlet::IsVisible())
{
$oDashlet->DoRender($oPage, $bEditMode, true /* bEnclosingDiv */, $aExtraParams);
}
}
} else {
$oDashboardColumn->AddUIBlock(new Html('&nbsp;'));
}
} else {
$oDashboardColumn->AddUIBlock(new Html('&nbsp;'));
else
{
$oPage->add('&nbsp;');
}
}
else
{
$oPage->add('&nbsp;');
}
$oPage->add('</td>');
$iCellIdx++;
}
$sJSReload .= $oDashboardRow->GetJSRefreshCallback()." ";
$oPage->add('</tr>');
}
$oPage->add_script("function updateDashboard".$aExtraParams['dashboard_div_id']."(){".$sJSReload."}");
if ($bEditMode) // Add one row for extensibility
{
$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;'));
$sStyle = 'style="border: 1px #ccc dashed; width:'.$fColSize.'%;" class="layout_cell edit_mode layout_extension" data-dashboard-cell-index="'.$iCellIdx.'"';
$oPage->add("<tr data-dashboard-row-index=\"$iRows\">");
for($iCols = 0; $iCols < $this->iNbCols; $iCols++)
{
$oPage->add("<td $sStyle data-dashboard-column-index=\"$iCols\">");
$oPage->add('&nbsp;');
$oPage->add('</td>');
}
$oPage->add('</tr>');
}
return $oDashboardLayout;
$oPage->add('</tbody></table>');
}
/**

File diff suppressed because it is too large Load Diff

View File

@@ -1,46 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<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>
<itop_design xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="1.7">
<portals>
<portal id="backoffice" _delta="define">
<url>pages/UI.php</url>
@@ -53,424 +12,13 @@
</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>Menu:WelcomeMenuPage</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="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="AddValue">
<arguments>
<argument id="1">
<type>attcode</type>
<mandatory>true</mandatory>
<type_restrictions>
<operation>allow</operation>
<types>
<type id="AttributeInteger"/>
<type id="AttributeDecimal"/>
<type id="AttributePercentage"/>
<type id="AttributeDuration"/>
</types>
</type_restrictions>
</argument>
<argument id="2">
<type>string</type>
<mandatory>false</mandatory>
</argument>
</arguments>
</method>
<method id="SetComputedDate">
<arguments>
<argument id="1">
<type>attcode</type>
<mandatory>true</mandatory>
<type_restrictions>
<operation>allow</operation>
<types>
<type id="AttributeDate"/>
<type id="AttributeDateTime"/>
</types>
</type_restrictions>
</argument>
<argument id="2">
<type>string</type>
<mandatory>false</mandatory>
</argument>
<argument id="3">
<type>attcode</type>
<mandatory>false</mandatory>
<type_restrictions>
<operation>allow</operation>
<types>
<type id="AttributeDate"/>
<type id="AttributeDateTime"/>
</types>
</type_restrictions>
</argument>
</arguments>
</method>
<method id="SetComputedDateIfNull">
<arguments>
<argument id="1">
<type>attcode</type>
<mandatory>true</mandatory>
<type_restrictions>
<operation>allow</operation>
<types>
<type id="AttributeDate"/>
<type id="AttributeDateTime"/>
</types>
</type_restrictions>
</argument>
<argument id="2">
<type>string</type>
<mandatory>false</mandatory>
</argument>
<argument id="3">
<type>attcode</type>
<mandatory>false</mandatory>
<type_restrictions>
<operation>allow</operation>
<types>
<type id="AttributeDate"/>
<type id="AttributeDateTime"/>
</types>
</type_restrictions>
</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="SetCurrentDateIfNull">
<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>
</methods>
</class>
</classes>
</meta>
</itop_design>

View File

@@ -1,9 +1,6 @@
<?php
use Combodo\iTop\Renderer\Console\ConsoleBlockRenderer;
/**
* Copyright (C) 2013-2021 Combodo SARL
* Copyright (C) 2013-2020 Combodo SARL
*
* This file is part of iTop.
*
@@ -18,8 +15,6 @@ use Combodo\iTop\Renderer\Console\ConsoleBlockRenderer;
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
*
* @deprecated since 3.0.0 use Combodo\iTop\Application\UI\Base\Component\DataTable\Datatable
*/
class DataTable
@@ -30,7 +25,7 @@ class DataTable
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 in the set
protected $iNbObjects; // Total number of objects inthe set
protected $bUseCustomSettings; // Whether or not the current display uses custom settings
protected $oDefaultSettings; // the default settings for displaying such a list
protected $bShowObsoleteData;
@@ -48,7 +43,6 @@ class DataTable
*/
public function __construct($iListId, $oSet, $aClassAliases, $sTableId = null)
{
DeprecatedCallsLog::NotifyDeprecatedPhpMethod('use Combodo\iTop\Application\UI\Base\Component\DataTable\Datatable');
$this->iListId = utils::GetSafeId($iListId); // Make a "safe" ID for jQuery
$this->sDatatableContainerId = 'datatable_'.utils::GetSafeId($iListId);
$this->oSet = $oSet;
@@ -116,7 +110,8 @@ class DataTable
// See if this column is a must to load
$sClass = $this->aClassAliases[$sAlias];
$oAttDef = MetaModel::GetAttributeDef($sClass, $sAttCode);
if ($oAttDef->AlwaysLoadInTables()) {
if ($oAttDef->alwaysLoadInTables())
{
$aColumnsToLoad[$sAlias][] = $sAttCode;
}
}
@@ -162,17 +157,17 @@ 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=\"{$this->sDatatableContainerId}\" class=\"datatable\">";
$sHtml .= "<tr><td>";
$sHtml .= "<table style=\"width:100%;\">";
@@ -213,7 +208,7 @@ class DataTable
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,26 +347,17 @@ EOF;
* @param $aExtraParams
*
* @return string
* @throws \ApplicationException
* @throws \ArchivedObjectException
* @throws \CoreException
* @throws \CoreUnexpectedValue
* @throws \DictExceptionMissingString
* @throws \MissingQueryArgument
* @throws \MySQLException
* @throws \MySQLHasGoneAwayException
* @throws \OQLException
* @throws \ReflectionException
* @throws \Twig\Error\LoaderError
* @throws \Twig\Error\RuntimeError
* @throws \Twig\Error\SyntaxError
*/
protected function GetActionsMenu(WebPage $oPage, $aExtraParams)
{
$oMenuBlock = new MenuBlock($this->oSet->GetFilter(), 'list');
$oBlock = $oMenuBlock->GetRenderContent($oPage, $aExtraParams, $this->iListId);
return ConsoleBlockRenderer::RenderBlockTemplateInPage($oPage, $oBlock);
$sHtml = $oMenuBlock->GetRenderContent($oPage, $aExtraParams, $this->iListId);
return $sHtml;
}
/**
@@ -386,7 +372,7 @@ EOF;
if (!$oPage->IsPrintableVersion())
{
$sMenuTitle = Dict::S('UI:ConfigureThisList');
$sHtml = '<div class="itop_popup toolkit_menu" id="tk_'.$this->iListId.'"><ul><li><i class="fas fa-tools"></i><i class="fas fa-caret-down"></i><ul>';
$sHtml = '<div class="itop_popup toolkit_menu" id="tk_'.$this->iListId.'"><ul><li aria-label="'.Dict::S('UI:Menu:Toolkit').'"><i class="fas fa-tools"></i><i class="fas fa-caret-down"></i><ul>';
$oMenuItem1 = new JSPopupMenuItem('iTop::ConfigureList', $sMenuTitle, "$('#datatable_dlg_".$this->iListId."').dialog('open');");
$aActions = array(
@@ -527,7 +513,6 @@ EOF;
return $aAttribs;
}
/**
* @param $aColumns
* @param $sSelectMode
@@ -875,3 +860,396 @@ 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)
{
return static::GetAppUserPreferenceKey($this->aClassAliases, $sTableId);
}
public static function GetAppUserPreferenceKey($aClassAliases, $sTableId)
{
if ($sTableId === null)
{
$sTableId = '*';
}
$aKeys = array();
foreach($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

@@ -1,8 +1,82 @@
<?php
/**
* @deprecated will be removed in 3.1.0 - moved to sources/application/WebPage/ErrorPage.php, now loadable using autoloader
* @copyright Copyright (C) 2010-2020 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
* @copyright Copyright (C) 2010-2021 Combodo SARL
*/
DeprecatedCallsLog::NotifyDeprecatedFile('moved to sources/application/WebPage/ErrorPage.php, now loadable using autoloader');
class ErrorPage extends NiceWebPage
{
public function __construct($sTitle)
{
parent::__construct($sTitle);
$this->add_linked_script("../js/jquery.blockUI.js");
$this->add_linked_script("../setup/setup.js");
$this->add_saas("css/setup.scss");
}
public function info($sText)
{
$this->add("<p class=\"info\">$sText</p>\n");
$this->log_info($sText);
}
public function ok($sText)
{
$this->add("<div class=\"message message-valid\"><span class=\"message-title\">Success:</span>$sText</div>");
$this->log_ok($sText);
}
public function warning($sText)
{
$this->add("<div class=\"message message-warning\"><span class=\"message-title\">Warning:</span>$sText</div>");
$this->log_warning($sText);
}
public function error($sText)
{
$this->add("<div class=\"message message-error\">$sText</div>");
$this->log_error($sText);
}
public function output()
{
$sLogo = utils::GetAbsoluteUrlAppRoot().'/images/itop-logo.png';
$sTimeStamp = utils::GetCacheBusterTimestamp();
$sTitle = utils::HtmlEntities($this->s_title);
$this->s_content = <<<HTML
<div id="header" class="error_page">
<h1><a href="http://www.combodo.com/itop" target="_blank"><img title="iTop by Combodo" alt=" " src="{$sLogo}?t={$sTimeStamp}"></a>&nbsp;{$sTitle}</h1>
</div>
<div id="setup" class="error_page">
{$this->s_content}
</div>
HTML;
return parent::output();
}
public static function log_error($sText)
{
IssueLog::Error($sText);
}
public static function log_warning($sText)
{
IssueLog::Warning($sText);
}
public static function log_info($sText)
{
IssueLog::Info($sText);
}
public static function log_ok($sText)
{
IssueLog::Ok($sText);
}
public static function log($sText)
{
IssueLog::Ok($sText);
}
}

View File

@@ -1,9 +0,0 @@
<?php
/*
* @copyright Copyright (C) 2010-2021 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
class ApplicationException extends CoreException
{
}

View File

@@ -1,14 +0,0 @@
<?php
/*
* @copyright Copyright (C) 2010-2021 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
/**
* Thrown when querying on an object that exists in the database but is archived
*
* @since 2.5.1 N°1108
*/
class ArchivedObjectException extends CoreException
{
}

View File

@@ -1,9 +0,0 @@
<?php
/*
* @copyright Copyright (C) 2010-2021 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
class BulkChangeException extends CoreException
{
}

View File

@@ -1,9 +0,0 @@
<?php
/*
* @copyright Copyright (C) 2010-2021 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
class CSVParserException extends CoreException
{
}

View File

@@ -1,9 +0,0 @@
<?php
/*
* @copyright Copyright (C) 2010-2021 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
class ConfigException extends CoreException
{
}

View File

@@ -1,77 +0,0 @@
<?php
/*
* @copyright Copyright (C) 2010-2021 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
/**
* Class CoreCannotSaveObjectException
*
* Specialized exception to raise if {@link DBObject::CheckToWrite()} fails, which allow easy data retrieval
*
* @see \DBObject::DBInsertNoReload()
* @see \DBObject::DBUpdate()
*
* @since 2.6.0 N°659 uniqueness constraint
*/
class CoreCannotSaveObjectException extends CoreException
{
/** @var string[] */
private $aIssues;
/** @var int */
private $iObjectId;
/** @var string */
private $sObjectClass;
/**
* CoreCannotSaveObjectException constructor.
*
* @param array $aContextData containing at least those keys : issues, id, class
*/
public function __construct($aContextData, $oPrevious = null)
{
$this->aIssues = $aContextData['issues'];
$this->iObjectId = $aContextData['id'];
$this->sObjectClass = $aContextData['class'];
$sIssues = implode(', ', $this->aIssues);
parent::__construct($sIssues, $aContextData, '', $oPrevious);
}
/**
* @return string
*/
public function getHtmlMessage()
{
$sTitle = Dict::S('UI:Error:SaveFailed');
$sContent = "<span><strong>".utils::HtmlEntities($sTitle)."</strong></span>";
if (count($this->aIssues) == 1) {
$sIssue = reset($this->aIssues);
$sContent .= " <span>".utils::HtmlEntities($sIssue)."</span>";
} else {
$sContent .= '<ul>';
foreach ($this->aIssues as $sError) {
$sContent .= "<li>".utils::HtmlEntities($sError)."</li>";
}
$sContent .= '</ul>';
}
return $sContent;
}
public function getIssues()
{
return $this->aIssues;
}
public function getObjectId()
{
return $this->iObjectId;
}
public function getObjectClass()
{
return $this->sObjectClass;
}
}

View File

@@ -1,108 +0,0 @@
<?php
/*
* @copyright Copyright (C) 2010-2021 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
class CoreException extends Exception
{
/**
* 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;
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) {
$sMessage .= ": ";
$aContextItems = array();
foreach ($this->m_aContextData as $sKey => $value) {
if (is_array($value)) {
$aPairs = array();
foreach ($value as $key => $val) {
if (is_array($val)) {
$aPairs[] = $key.'=>('.implode(', ', $val).')';
} else {
$aPairs[] = $key.'=>'.$val;
}
}
$sValue = '{'.implode('; ', $aPairs).'}';
} else {
$sValue = $value;
}
$aContextItems[] = "$sKey = $sValue";
}
$sMessage .= implode(', ', $aContextItems);
}
parent::__construct($sMessage, 0, $oPrevious);
}
/**
* @return string code and message for log purposes
*/
public function getInfoLog()
{
return 'error_code='.$this->getCode().', message="'.$this->getMessage().'"';
}
public function getHtmlDesc($sHighlightHtmlBegin = '<b>', $sHighlightHtmlEnd = '</b>')
{
return $this->getMessage();
}
/**
* 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();
return MyHelpers::get_callstack_html(0, $this->getTrace());
// return "<pre>\n".$this->getTraceAsString()."</pre>\n";
}
public function addInfo($sKey, $value)
{
$this->m_aContextData[$sKey] = $value;
}
public function getIssue()
{
return $this->m_sIssue;
}
public function getImpact()
{
return $this->m_sImpact;
}
public function getContextData()
{
return $this->m_aContextData;
}
}

View File

@@ -1,13 +0,0 @@
<?php
/*
* @copyright Copyright (C) 2010-2021 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
/**
* @since 2.7.0 N°2555
*/
class CorePortalInvalidActionRuleException extends CoreException
{
}

View File

@@ -1,17 +0,0 @@
<?php
/*
* @copyright Copyright (C) 2010-2021 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
/**
* @since 3.0.0 N°3522
*/
class CoreTemplateException extends CoreException
{
public function __construct(Exception $oTwigException, string $sTemplatePath)
{
$sMessage = "Twig Exception when rendering '$sTemplatePath' : ".$oTwigException->getMessage();
parent::__construct($sMessage, null, '', $oTwigException);
}
}

View File

@@ -1,9 +0,0 @@
<?php
/*
* @copyright Copyright (C) 2010-2021 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
class CoreUnexpectedValue extends CoreException
{
}

View File

@@ -1,9 +0,0 @@
<?php
/*
* @copyright Copyright (C) 2010-2021 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
class CoreWarning extends CoreException
{
}

View File

@@ -1,9 +0,0 @@
<?php
/*
* @copyright Copyright (C) 2010-2021 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
class DeleteException extends CoreException
{
}

View File

@@ -1,14 +0,0 @@
<?php
/*
* @copyright Copyright (C) 2010-2021 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
/**
* A parameter stored in the {@link Config} is invalid
*
* @since 2.7.0
*/
class InvalidConfigParamException extends CoreException
{
}

View File

@@ -1,14 +0,0 @@
<?php
/*
* @copyright Copyright (C) 2010-2021 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
/**
* Thrown when the password is not valid
*
* @since 2.7.0
*/
class InvalidPasswordAttributeOneWayPassword extends CoreException
{
}

View File

@@ -1,13 +0,0 @@
<?php
/**
* @copyright Copyright (C) 2010-2021 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
namespace Combodo\iTop\Application\TwigBase\Controller;
use Exception;
class PageNotFoundException extends Exception
{
}

View File

@@ -1,9 +0,0 @@
<?php
/*
* @copyright Copyright (C) 2010-2021 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
class SecurityException extends CoreException
{
}

View File

@@ -1,9 +0,0 @@
<?php
/*
* @copyright Copyright (C) 2010-2021 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
class SynchroExceptionNotStarted extends CoreException
{
}

View File

@@ -1,9 +0,0 @@
<?php
/*
* @copyright Copyright (C) 2010-2021 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
class UserRightException extends CoreException
{
}

View File

@@ -1,9 +0,0 @@
<?php
/*
* @copyright Copyright (C) 2010-2021 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
class DictException extends CoreException
{
}

View File

@@ -1,16 +0,0 @@
<?php
/*
* @copyright Copyright (C) 2010-2021 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
class DictExceptionMissingString extends DictException
{
public function __construct($sLanguageCode, $sStringCode)
{
$aContext = array();
$aContext['language_code'] = $sLanguageCode;
$aContext['string_code'] = $sStringCode;
parent::__construct('Missing localized string', $aContext);
}
}

View File

@@ -1,15 +0,0 @@
<?php
/*
* @copyright Copyright (C) 2010-2021 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
class DictExceptionUnknownLanguage extends DictException
{
public function __construct($sLanguageCode)
{
$aContext = array();
$aContext['language_code'] = $sLanguageCode;
parent::__construct('Unknown localization language', $aContext);
}
}

View File

@@ -1,39 +0,0 @@
<?php
/*
* @copyright Copyright (C) 2010-2021 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
class MySQLException extends CoreException
{
/**
* MySQLException constructor.
*
* @param string $sIssue
* @param array $aContext
* @param \Exception $oException
* @param \mysqli $oMysqli to use when working with a custom mysqli instance
*/
public function __construct($sIssue, $aContext, $oException = null, $oMysqli = null)
{
if ($oException != null) {
$aContext['mysql_errno'] = $oException->getCode();
$this->code = $oException->getCode();
$aContext['mysql_error'] = $oException->getMessage();
} else if ($oMysqli != null) {
$aContext['mysql_errno'] = $oMysqli->errno;
$this->code = $oMysqli->errno;
$aContext['mysql_error'] = $oMysqli->error;
} else {
$aContext['mysql_errno'] = CMDBSource::GetErrNo();
$this->code = CMDBSource::GetErrNo();
$aContext['mysql_error'] = CMDBSource::GetError();
}
parent::__construct($sIssue, $aContext);
//if is connection error, don't log the default message with password in
if (mysqli_connect_errno()) {
error_log($this->message);
error_reporting(0);
}
}
}

View File

@@ -1,32 +0,0 @@
<?php
/*
* @copyright Copyright (C) 2010-2021 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
/**
* Class MySQLHasGoneAwayException
*
* @see https://dev.mysql.com/doc/refman/5.7/en/gone-away.html
* @since 2.5.0 N°1195
*/
class MySQLHasGoneAwayException extends MySQLException
{
/**
* can not be a constant before PHP 5.6 (http://php.net/manual/fr/language.oop5.constants.php)
*
* @return int[]
*/
public static function getErrorCodes()
{
return array(
2006,
2013,
);
}
public function __construct($sIssue, $aContext)
{
parent::__construct($sIssue, $aContext, null);
}
}

View File

@@ -1,13 +0,0 @@
<?php
/*
* @copyright Copyright (C) 2010-2021 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
/**
* @since 2.7.0 N°679
*/
class MySQLNoTransactionException extends MySQLException
{
}

View File

@@ -1,15 +0,0 @@
<?php
/*
* @copyright Copyright (C) 2010-2021 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
/**
* Class MySQLQueryHasNoResultException
*
* @since 2.5.0
*/
class MySQLQueryHasNoResultException extends MySQLException
{
}

View File

@@ -1,13 +0,0 @@
<?php
/*
* @copyright Copyright (C) 2010-2021 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
/**
* @since 2.7.8 3.0.3 3.1.0 N°5538
*/
class MySQLTransactionNotClosedException extends MySQLException
{
}

View File

@@ -1,13 +0,0 @@
<?php
/*
* @copyright Copyright (C) 2010-2021 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
/**
* @since 2.7.0 N°2555
*/
class CoreOqlException extends CoreException
{
}

View File

@@ -1,13 +0,0 @@
<?php
/*
* @copyright Copyright (C) 2010-2021 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
/**
* @since 2.7.0 N°2555
*/
class CoreOqlMultipleResultsForbiddenException extends CoreOqlException
{
}

View File

@@ -1,15 +0,0 @@
<?php
/*
* @copyright Copyright (C) 2010-2021 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
/**
* 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
{
}

View File

@@ -1,16 +0,0 @@
<?php
/*
* @copyright Copyright (C) 2010-2021 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
/**
* 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

@@ -1,12 +0,0 @@
<?php
/*
* @copyright Copyright (C) 2010-2021 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
/**
* @since 2.7.0 PR #89
*/
class ProcessInvalidConfigException extends ProcessException
{
}

View File

@@ -1,114 +0,0 @@
<?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
*/
/**
* Class FindStylesheetObject: dedicated class to store computations made in method ThemeHandler::FindStylesheetFile.
* @author Olivier DAIN <olivier.dain@combodo.com>
* @since 3.0.0 N°3588
*/
class FindStylesheetObject{
//file URIs
private $aStylesheetFileURIs;
//fill paths
private $aStylesheetImportPaths;
private $aAllStylesheetFilePaths;
private $sLastStyleSheetPath;
private $iLastModified;
/**
* FindStylesheetObject constructor.
*/
public function __construct()
{
$this->aStylesheetFileURIs = [];
$this->aStylesheetImportPaths = [];
$this->aAllStylesheetFilePaths = [];
$this->sLastStyleSheetPath = "";
$this->iLastModified = 0;
}
public function GetLastStylesheetFile(): string
{
return $this->sLastStyleSheetPath;
}
public function GetImportPaths(): array
{
return $this->aStylesheetImportPaths;
}
/**
* @return array : main stylesheets URIs
*/
public function GetStylesheetFileURIs(): array
{
return $this->aStylesheetFileURIs;
}
public function GetLastModified() : int
{
return $this->iLastModified;
}
/**
* @return array : main stylesheets paths + included files paths
*/
public function GetAllStylesheetPaths(): array
{
return $this->aAllStylesheetFilePaths;
}
/**
* @return string : last found stylesheet URI
*/
public function GetLastStyleSheetPath(): string
{
return $this->sLastStyleSheetPath;
}
public function AddStylesheet(string $sStylesheetFileURI, string $sStylesheetFilePath): void
{
$this->aStylesheetFileURIs[] = $sStylesheetFileURI;
$this->aAllStylesheetFilePaths[] = $sStylesheetFilePath;
$this->sLastStyleSheetPath = $sStylesheetFilePath;
}
public function AlreadyFetched(string $sStylesheetFilePath) : bool {
return in_array($sStylesheetFilePath, $this->aAllStylesheetFilePaths);
}
public function AddImport(string $sStylesheetFileURI, string $sStylesheetFilePath): void
{
$this->aStylesheetImportPaths[$sStylesheetFileURI] = $sStylesheetFilePath;
$this->aAllStylesheetFilePaths[] = $sStylesheetFilePath;
}
public function UpdateLastModified(string $sStylesheetFile): void
{
$this->iLastModified = max($this->iLastModified, @filemtime($sStylesheetFile));
}
public function ResetLastStyleSheet(): void
{
$this->sLastStyleSheetPath = "";
}
}

View File

@@ -1,5 +1,5 @@
<?php
// Copyright (C) 2010-2021 Combodo SARL
// Copyright (C) 2010-2012 Combodo SARL
//
// This file is part of iTop.
//
@@ -20,7 +20,7 @@
* Helper class to build interactive forms to be used either in stand-alone
* modal dialog or in "property-sheet" panes.
*
* @copyright Copyright (C) 2010-2021 Combodo SARL
* @copyright Copyright (C) 2010-2012 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
class DesignerForm
@@ -102,27 +102,23 @@ class DesignerForm
$sReturn .= '<fieldset>';
$sReturn .= '<legend>'.$sLabel.'</legend>';
}
/** @var \DesignerFormField $oField */
foreach($aFields as $oField) {
foreach($aFields as $oField)
{
$aRow = $oField->Render($oP, $sFormId);
if ($oField->IsVisible()) {
$sValidation = '<span class="prop_apply ibo-prop--apply ibo-button ibo-is-alternative">'.$this->GetValidationArea($oField->GetFieldId()).'</span>';
if ($oField->IsVisible())
{
$sValidation = '&nbsp;<span class="prop_apply">'.$this->GetValidationArea($oField->GetFieldId()).'</span>';
$sField = $aRow['value'].$sValidation;
$aDetails[] = array(
'label' => $aRow['label'],
'value' => $sField,
'attcode' => $oField->GetCode(),
'attlabel' => $aRow['label'],
'inputid' => $this->GetFieldId($oField->GetCode()),
'inputtype' => $oField->GetInputType(),
);
} else {
$aDetails[] = array('label' => $aRow['label'], 'value' => $sField);
}
else
{
$sHiddenFields .= $aRow['value'];
}
}
$sReturn .= $oP->GetDetails($aDetails);
if ($sLabel != '') {
if ($sLabel != '')
{
$sReturn .= '</fieldset>';
}
}
@@ -211,41 +207,51 @@ class DesignerForm
$sActionUrl = addslashes($this->sSubmitTo);
$sJSSubmitParams = json_encode($this->aSubmitParams);
$sFormId = $this->GetFormId();
if ($this->oParentForm == null) {
if ($this->oParentForm == null)
{
$sReturn = '<form id="'.$sFormId.'" onsubmit="return false;">';
$sReturn .= '<table class="prop_table">';
$sReturn .= '<thead><tr><th class="ibo-prop-header">'.Dict::S('UI:Form:Property').'</th><th class="ibo-prop-header">'.Dict::S('UI:Form:Value').'</th><th colspan="2" class="ibo-prop-header">&nbsp;</th></tr></thead><tbody>';
$sReturn .= '<thead><tr><th class="prop_header">'.Dict::S('UI:Form:Property').'</th><th class="prop_header">'.Dict::S('UI:Form:Value').'</th><th colspan="2" class="prop_header">&nbsp;</th></tr></thead><tbody>';
}
$sHiddenFields = '';
foreach ($this->aFieldSets as $sLabel => $aFields) {
foreach($this->aFieldSets as $sLabel => $aFields)
{
$aDetails = array();
if ($sLabel != '') {
if ($sLabel != '')
{
$sReturn .= $this->StartRow().'<th colspan="4">'.$sLabel.'</th>'.$this->EndRow();
}
foreach ($aFields as $oField) {
foreach($aFields as $oField)
{
$aRow = $oField->Render($oP, $sFormId, 'property');
if ($oField->IsVisible()) {
if ($oField->IsVisible())
{
$sFieldId = $this->GetFieldId($oField->GetCode());
$sValidation = $this->GetValidationArea($sFieldId, '<div class="ibo-button ibo-is-alternative ibo-is-success" data-tooltip-content="'.Dict::Format('UI:DashboardEdit:Apply').'"><i class="fas fa-check"></i></div>');
$sValidationFields = '</td><td class="prop_icon prop_apply ibo-prop--apply" >'.$sValidation.'</td><td class="prop_icon prop_cancel ibo-prop--cancel"><span><div class="ibo-button ibo-is-alternative ibo-is-neutral" data-tooltip-content="'.Dict::Format('UI:DashboardEdit:Revert').'"><i class="fas fa-undo"></i></div></span></td>'
.$this->EndRow();
if (is_null($aRow['label'])) {
$sValidation = $this->GetValidationArea($sFieldId, '<span title="Apply" class="ui-icon ui-icon-circle-check"/>');
$sValidationFields = '</td><td class="prop_icon prop_apply">'.$sValidation.'</td><td class="prop_icon prop_cancel"><span title="Revert" class="ui-icon ui-icon-circle-close"/></td>'.$this->EndRow();
$sPath = $this->GetHierarchyPath().'/'.$oField->GetCode();
if (is_null($aRow['label']))
{
$sReturn .= $this->StartRow($sFieldId).'<td class="prop_value" colspan="2">'.$aRow['value'];
} else {
}
else
{
$sReturn .= $this->StartRow($sFieldId).'<td class="prop_label">'.$aRow['label'].'</td><td class="prop_value">'.$aRow['value'];
}
if (!($oField instanceof DesignerFormSelectorField) && !($oField instanceof DesignerMultipleSubFormField)) {
if (!($oField instanceof DesignerFormSelectorField) && !($oField instanceof DesignerMultipleSubFormField))
{
$sReturn .= $sValidationFields;
}
$sNotifyParentSelectorJS = is_null($sNotifyParentSelector) ? 'null' : "'".addslashes($sNotifyParentSelector)."'";
$sAutoApply = $oField->IsAutoApply() ? 'true' : 'false';
$sHandlerEquals = $oField->GetHandlerEquals();
$sHandlerGetValue = $oField->GetHandlerGetValue();
$sWidgetClass = $oField->GetWidgetClass();
$sJSExtraParams = '';
if (count($oField->GetWidgetExtraParams()) > 0)
@@ -260,7 +266,6 @@ class DesignerForm
$this->AddReadyScript(
<<<EOF
$('#row_$sFieldId').$sWidgetClass({parent_selector: $sNotifyParentSelectorJS, field_id: '$sFieldId', equals: $sHandlerEquals, get_field_value: $sHandlerGetValue, auto_apply: $sAutoApply, value: '', submit_to: '$sActionUrl', submit_parameters: $sJSSubmitParams $sJSExtraParams });
CombodoTooltip.InitTooltipFromMarkup($('#$sFormId [data-tooltip-content]'));
EOF
);
}
@@ -286,6 +291,7 @@ EOF
}
$this->AddReadyScript(
<<<EOF
$('.prop_table').tableHover();
var idx = 0;
$('.prop_table tbody tr').each(function() {
if ((idx % 2) == 0)
@@ -354,7 +360,7 @@ EOF
<<<EOF
$('#$sDialogId').dialog({
height: 'auto',
maxHeight: $(window).height() * 0.9,
maxHeight: $(window).height() - 8,
width: $iDialogWidth,
modal: true,
autoOpen: $sAutoOpen,
@@ -542,7 +548,7 @@ EOF
public function GetValidationArea($sId, $sContent = '')
{
return "<span id=\"v_{$sId}\">$sContent</span>";
return "<span style=\"display:inline-block;width:20px;\" id=\"v_{$sId}\"><span class=\"ui-icon ui-icon-alert\"></span>$sContent</span>";
}
public function GetAsyncActionClass()
{
@@ -710,27 +716,11 @@ class DesignerFormField
$this->bMandatory = false;
$this->bReadOnly = false;
$this->bAutoApply = false;
$this->aCSSClasses = [];
if (ContextTag::Check(ContextTag::TAG_CONSOLE)) {
$this->aCSSClasses[] = 'ibo-input';
}
$this->aCSSClasses = array();
$this->bDisplayed = true;
$this->aWidgetExtraParams = array();
}
/**
* Important, for now we use constants from the \cmdbAbstractObject class, introducing a coupling that should not exist.
* This has been traced under N°4241 and will be discussed during the next modernization batch.
*
* @return string|null Return the input type of the field
* @see \cmdbAbstractObject::ENUM_INPUT_TYPE_XXX
* @since 3.0.0
*/
public function GetInputType(): ?string
{
return cmdbAbstractObject::ENUM_INPUT_TYPE_SINGLE_INPUT;
}
/**
* @return string
*/
@@ -1030,10 +1020,10 @@ class DesignerTextField extends DesignerFormField
$sMandatory = $this->bMandatory ? 'true' : 'false';
$oP->add_ready_script(
<<<EOF
$('#$sId').on('change keyup validate', function() { ValidateWithPattern('$sId', $sMandatory, '$sPattern', $(this).closest('form').attr('id'), $sForbiddenValues); } );
$('#$sId').bind('change keyup validate', function() { ValidateWithPattern('$sId', $sMandatory, '$sPattern', $(this).closest('form').attr('id'), $sForbiddenValues); } );
{
var myTimer = null;
$('#$sId').on('keyup', function() { clearTimeout(myTimer); myTimer = setTimeout(function() { $('#$sId').trigger('change', {} ); }, 100); });
$('#$sId').bind('keyup', function() { clearTimeout(myTimer); myTimer = setTimeout(function() { $('#$sId').trigger('change', {} ); }, 100); });
}
EOF
);
@@ -1065,23 +1055,6 @@ EOF
class DesignerLongTextField extends DesignerTextField
{
public function __construct($sCode, $sLabel = '', $defaultValue = '')
{
parent::__construct($sCode, $sLabel, $defaultValue);
if (ContextTag::Check(ContextTag::TAG_CONSOLE)) {
$this->aCSSClasses[] = 'ibo-input-text';
}
}
/**
* @inheritDoc
*/
public function GetInputType(): string
{
return cmdbAbstractObject::ENUM_INPUT_TYPE_TEXTAREA;
}
public function Render(WebPage $oP, $sFormId, $sRenderMode='dialog')
{
$sId = $this->oForm->GetFieldId($this->sCode);
@@ -1105,10 +1078,10 @@ class DesignerLongTextField extends DesignerTextField
{
$oP->add_ready_script(
<<<EOF
$('#$sId').on('change keyup validate', function() { ValidateWithPattern('$sId', $sMandatory, '$sPattern', $(this).closest('form').attr('id'), $sForbiddenValues); } );
$('#$sId').bind('change keyup validate', function() { ValidateWithPattern('$sId', $sMandatory, '$sPattern', $(this).closest('form').attr('id'), $sForbiddenValues); } );
{
var myTimer = null;
$('#$sId').on('keyup', function() { clearTimeout(myTimer); myTimer = setTimeout(function() { $('#$sId').trigger('change', {} ); }, 100); });
$('#$sId').bind('keyup', function() { clearTimeout(myTimer); myTimer = setTimeout(function() { $('#$sId').trigger('change', {} ); }, 100); });
}
EOF
);
@@ -1156,10 +1129,10 @@ class DesignerIntegerField extends DesignerFormField
$sMandatory = $this->bMandatory ? 'true' : 'false';
$oP->add_ready_script(
<<<EOF
$('#$sId').on('change keyup validate', function() { ValidateInteger('$sId', $sMandatory, $(this).closest('form').attr('id'), $sMin, $sMax); } );
$('#$sId').bind('change keyup validate', function() { ValidateInteger('$sId', $sMandatory, $(this).closest('form').attr('id'), $sMin, $sMax); } );
{
var myTimer = null;
$('#$sId').on('keyup', function() { clearTimeout(myTimer); myTimer = setTimeout(function() { $('#$sId').trigger('change', {} ); }, 100); });
$('#$sId').bind('keyup', function() { clearTimeout(myTimer); myTimer = setTimeout(function() { $('#$sId').trigger('change', {} ); }, 100); });
}
EOF
);
@@ -1206,34 +1179,12 @@ class DesignerComboField extends DesignerFormField
$this->bOtherChoices = false;
$this->sNullLabel = Dict::S('UI:SelectOne');
if (ContextTag::Check(ContextTag::TAG_CONSOLE)) {
$this->aCSSClasses[] = 'ibo-input-select';
}
$this->bAutoApply = true;
$this->bSorted = true; // Sorted by default
}
/**
* @inheritDoc
*/
public function GetInputType(): ?string
public function SetAllowedValues($aAllowedValues)
{
if ($this->bMultipleSelection) {
return cmdbAbstractObject::ENUM_INPUT_TYPE_DROPDOWN_MULTIPLE_CHOICES;
}
else {
return cmdbAbstractObject::ENUM_INPUT_TYPE_DROPDOWN_RAW;
}
}
public function SetAllowedValues(?array $aAllowedValues)
{
// Make sure to have an actual array for values
if (is_null($aAllowedValues)) {
$aAllowedValues = [];
}
$this->aAllowedValues = $aAllowedValues;
}
@@ -1310,11 +1261,11 @@ class DesignerComboField extends DesignerFormField
{
if ($this->bMultipleSelection)
{
$sHtml = "<span><select $sCSSClasses multiple size=\"8\"id=\"$sId\" name=\"$sName\">";
$sHtml = "<select $sCSSClasses multiple size=\"8\"id=\"$sId\" name=\"$sName\">";
}
else
{
$sHtml = "<span class=\"ibo-input-select-wrapper\"><select $sCSSClasses id=\"$sId\" name=\"$sName\">";
$sHtml = "<select $sCSSClasses id=\"$sId\" name=\"$sName\">";
if ($this->sNullLabel != '')
{
$sHtml .= "<option value=\"\">".$this->sNullLabel."</option>";
@@ -1330,19 +1281,18 @@ class DesignerComboField extends DesignerFormField
$sHtmlValue = str_replace(' ', '&nbsp;', $sDisplayValue);
$sHtml .= "<option value=\"".htmlentities($sKey, ENT_QUOTES, 'UTF-8')."\" $sSelected>$sHtmlValue</option>";
}
$sHtml .= "</select></span>";
$sHtml .= "</select>";
if ($this->bOtherChoices)
{
$sHtml .= '<br/><input type="checkbox" id="other_chk_'.$sId.'"><label for="other_chk_'.$sId.'">&nbsp;Other:</label>&nbsp;<input type="text" id="other_'.$sId.'" name="other_'.$sName.'" size="30"/>';
}
$oP->add_ready_script(
<<<EOF
$('#$sId').on('change validate', function() { ValidateWithPattern('$sId', $sMandatory, '', $(this).closest('form').attr('id'), null, null); } );
$('#$sId').bind('change validate', function() { ValidateWithPattern('$sId', $sMandatory, '', $(this).closest('form').attr('id'), null, null); } );
EOF
);
}
return array('label' => $this->sLabel, 'value' => $sHtml);
}
public function ReadParam(&$aValues)
@@ -1361,17 +1311,6 @@ class DesignerBooleanField extends DesignerFormField
{
parent::__construct($sCode, $sLabel, $defaultValue);
$this->bAutoApply = true;
if (ContextTag::Check(ContextTag::TAG_CONSOLE)) {
$this->aCSSClasses[] = 'ibo-input-checkbox';
}
}
/**
* @inheritDoc
*/
public function GetInputType(): ?string
{
return cmdbAbstractObject::ENUM_INPUT_TYPE_CHECKBOX;
}
public function Render(WebPage $oP, $sFormId, $sRenderMode='dialog')
@@ -1432,14 +1371,6 @@ class DesignerHiddenField extends DesignerFormField
{
parent::__construct($sCode, $sLabel, $defaultValue);
}
/**
* @inheritDoc
*/
public function GetInputType(): ?string
{
return null;
}
public function IsVisible()
{
@@ -1467,14 +1398,6 @@ class DesignerIconSelectionField extends DesignerFormField
$this->bAutoApply = true;
$this->sUploadUrl = null;
}
/**
* @inheritDoc
*/
public function GetInputType(): ?string
{
return cmdbAbstractObject::ENUM_INPUT_TYPE_DROPDOWN_DECORATED;
}
public function SetAllowedValues($aAllowedValues)
{
@@ -1491,33 +1414,28 @@ class DesignerIconSelectionField extends DesignerFormField
$sId = $this->oForm->GetFieldId($this->sCode);
$sName = $this->oForm->GetFieldName($this->sCode);
$idx = 0;
$idxFallback = 0;
foreach ($this->aAllowedValues as $index => $aValue) {
if ($aValue['value'] == $this->defaultValue) {
foreach($this->aAllowedValues as $index => $aValue)
{
if ($aValue['value'] == $this->defaultValue)
{
$idx = $index;
break;
}
//fallback if url of default value contains ../
//for contact, icon is http://localhost/env-production/itop-structure/../../images/icons/icons8-customer.svg => not found http://localhost/images/icons/icons8-customer.svg
if (basename($aValue['value']) == basename($this->defaultValue)) {
$idxFallback = $index;
}
}
if ($idx == 0) {
$idx = $idxFallback;
}
$sJSItems = json_encode($this->aAllowedValues);
$sPostUploadTo = ($this->sUploadUrl == null) ? 'null' : "'{$this->sUploadUrl}'";
if (!$this->IsReadOnly()) {
if (!$this->IsReadOnly())
{
$sDefaultValue = ($this->defaultValue !== '') ? $this->defaultValue : $this->aAllowedValues[$idx]['value'];
$sCSSClasses = ContextTag::Check(ContextTag::TAG_CONSOLE) ? 'class="ibo-input-select-wrapper"' : '';
$sValue = "<span $sCSSClasses><input type=\"hidden\" id=\"$sId\" name=\"$sName\" value=\"{$sDefaultValue}\"/></span>";
$sValue = "<input type=\"hidden\" id=\"$sId\" name=\"$sName\" value=\"{$sDefaultValue}\"/>";
$oP->add_ready_script(
<<<EOF
<<<EOF
$('#$sId').icon_select({current_idx: $idx, items: $sJSItems, post_upload_to: $sPostUploadTo});
EOF
);
} else {
}
else
{
$sValue = '<span style="display:inline-block;line-height:48px;height:48px;"><span><img style="vertical-align:middle" src="'.$this->aAllowedValues[$idx]['icon'].'" />&nbsp;'.htmlentities($this->aAllowedValues[$idx]['label'], ENT_QUOTES, 'UTF-8').'</span></span>';
}
$sReadOnly = $this->IsReadOnly() ? 'disabled' : '';
@@ -1532,21 +1450,18 @@ class RunTimeIconSelectionField extends DesignerIconSelectionField
public function __construct($sCode, $sLabel = '', $defaultValue = '')
{
parent::__construct($sCode, $sLabel, $defaultValue);
$aFolderList = [
APPROOT.'env-'.utils::GetCurrentEnvironment() => utils::GetAbsoluteUrlModulesRoot(),
APPROOT.'images/icons' => utils::GetAbsoluteUrlAppRoot().'images/icons',
];
if (count(self::$aAllIcons) == 0) {
foreach ($aFolderList as $sFolderPath => $sUrlPrefix) {
$aIcons = self::FindIconsOnDisk($sFolderPath);
ksort($aIcons);
foreach ($aIcons as $sFilePath) {
self::$aAllIcons[] = array('value' => $sFilePath, 'label' => basename($sFilePath), 'icon' => $sUrlPrefix.$sFilePath);
}
}
if (count(self::$aAllIcons) == 0)
{
self::$aAllIcons = self::FindIconsOnDisk(APPROOT.'env-'.utils::GetCurrentEnvironment());
ksort(self::$aAllIcons);
}
$this->SetAllowedValues(self::$aAllIcons);
$aValues = array();
foreach(self::$aAllIcons as $sFilePath)
{
$aValues[] = array('value' => $sFilePath, 'label' => basename($sFilePath), 'icon' => utils::GetAbsoluteUrlModulesRoot().$sFilePath);
}
$this->SetAllowedValues($aValues);
}
static protected function FindIconsOnDisk($sBaseDir, $sDir = '')
@@ -1577,29 +1492,26 @@ class RunTimeIconSelectionField extends DesignerIconSelectionField
SetupUtils::builddir(dirname($sCacheFile));
file_put_contents($sCacheFile, $sAvailableIcons, LOCK_EX);
}
return $aFiles;
}
static protected function _FindIconsOnDisk($sBaseDir, $sDir = '', &$aFilesSpecs = [])
static protected function _FindIconsOnDisk($sBaseDir, $sDir = '')
{
$aResult = [];
$aResult = array();
// Populate automatically the list of icon files
if ($hDir = @opendir($sBaseDir.'/'.$sDir)) {
while (($sFile = readdir($hDir)) !== false) {
if ($hDir = @opendir($sBaseDir.'/'.$sDir))
{
while (($sFile = readdir($hDir)) !== false)
{
$aMatches = array();
if (($sFile != '.') && ($sFile != '..') && ($sFile != 'lifecycle') && is_dir($sBaseDir.'/'.$sDir.'/'.$sFile)) {
if (($sFile != '.') && ($sFile != '..') && ($sFile != 'lifecycle') && is_dir($sBaseDir.'/'.$sDir.'/'.$sFile))
{
$sDirSubPath = ($sDir == '') ? $sFile : $sDir.'/'.$sFile;
$aResult = array_merge($aResult, self::_FindIconsOnDisk($sBaseDir, $sDirSubPath, $aFilesSpecs));
$aResult = array_merge($aResult, self::_FindIconsOnDisk($sBaseDir, $sDirSubPath));
}
$sSize = filesize($sBaseDir.'/'.$sDir.'/'.$sFile);
if (isset($aFilesSpecs[$sFile]) && $aFilesSpecs[$sFile] == $sSize) {
continue;
}
if (preg_match("/\.(png|jpg|jpeg|gif|svg)$/i", $sFile, $aMatches)) // png, jp(e)g, gif and svg are considered valid
if (preg_match("/\.(png|jpg|jpeg|gif)$/i", $sFile, $aMatches)) // png, jp(e)g and gif are considered valid
{
$aResult[$sFile.'_'.$sDir] = $sDir.'/'.$sFile;
$aFilesSpecs[$sFile] = $sSize;
}
}
closedir($hDir);
@@ -1645,14 +1557,6 @@ class DesignerSortableField extends DesignerFormField
parent::__construct($sCode, $sLabel, $defaultValue);
$this->aAllowedValues = array();
}
/**
* @inheritDoc
*/
public function GetInputType(): ?string
{
return null;
}
public function SetAllowedValues($aAllowedValues)
{
@@ -1689,17 +1593,6 @@ class DesignerFormSelectorField extends DesignerFormField
$this->defaultRealValue = $defaultValue;
$this->aSubForms = array();
$this->bSorted = true;
if (ContextTag::Check(ContextTag::TAG_CONSOLE)) {
$this->aCSSClasses[] = 'ibo-input-select';
}
}
/**
* @inheritDoc
*/
public function GetInputType(): ?string
{
return null;
}
public function IsSorted()
@@ -1742,23 +1635,27 @@ class DesignerFormSelectorField extends DesignerFormField
{
$sId = $this->oForm->GetFieldId($this->sCode);
$sName = $this->oForm->GetFieldName($this->sCode);
$sReadOnly = $this->IsReadOnly() ? 'disabled="disabled"' : '';
$sReadOnly = $this->IsReadOnly() ? 'disabled="disabled"' : '';
$this->aCSSClasses[] = 'formSelector';
$sCSSClasses = '';
if (count($this->aCSSClasses) > 0) {
if (count($this->aCSSClasses) > 0)
{
$sCSSClasses = 'class="'.implode(' ', $this->aCSSClasses).'"';
}
if ($this->IsSorted()) {
if ($this->IsSorted())
{
uasort($this->aSubForms, array(get_class($this), 'SortOnFormLabel'));
}
if ($this->IsReadOnly()) {
if ($this->IsReadOnly())
{
$sDisplayValue = '';
$sHiddenValue = '';
foreach ($this->aSubForms as $iKey => $aFormData) {
foreach($this->aSubForms as $iKey => $aFormData)
{
if ($iKey == $this->defaultValue) // Default value is actually the index
{
$sDisplayValue = htmlentities($aFormData['label'], ENT_QUOTES, 'UTF-8');
@@ -1767,29 +1664,35 @@ class DesignerFormSelectorField extends DesignerFormField
}
}
$sHtml = "<span $sCSSClasses>".$sDisplayValue.$sHiddenValue."</span>";
} else {
$sHtml = "<span class=\"ibo-input-select-wrapper\"><select $sCSSClasses id=\"$sId\" name=\"$sName\" $sReadOnly>";
foreach ($this->aSubForms as $iKey => $aFormData) {
}
else
{
$sHtml = "<select $sCSSClasses id=\"$sId\" name=\"$sName\" $sReadOnly>";
foreach($this->aSubForms as $iKey => $aFormData)
{
$sDisplayValue = htmlentities($aFormData['label'], ENT_QUOTES, 'UTF-8');
$sValue = htmlentities($aFormData['value'], ENT_QUOTES, 'UTF-8');
$sSelected = ($iKey == $this->defaultValue) ? 'selected' : '';
$sHtml .= "<option data-value=\"$sValue\" value=\"$iKey\" $sSelected>".$sDisplayValue."</option>";
}
$sHtml .= "</select></span>";
$sHtml .= "</select>";
}
if ($sRenderMode == 'property') {
$sHtml .= '</td><td class="prop_icon prop_apply ibo-prop--apply"><span><button class="ibo-button ibo-is-alternative ibo-is-success" data-tooltip-content="'.Dict::Format('UI:DashboardEdit:Apply').'"><i class="fas fa-check"></i></button></span></td><td class="prop_icon prop_cancel ibo-prop--cancel"><span><button class="ibo-button ibo-is-alternative ibo-is-neutral" data-tooltip-content="'.Dict::Format('UI:DashboardEdit:Revert').'"><i class="fas fa-times"></i></button></span></td></tr>';
if ($sRenderMode == 'property')
{
$sHtml .= '</td><td class="prop_icon prop_apply"><span title="Apply" class="ui-icon ui-icon-circle-check"/></td><td class="prop_icon prop_cancel"><span title="Revert" class="ui-icon ui-icon-circle-close"/></td></tr>';
}
foreach ($this->aSubForms as $sKey => $aFormData) {
foreach($this->aSubForms as $sKey => $aFormData)
{
$sId = $this->oForm->GetFieldId($this->sCode);
$sStyle = (($sKey == $this->defaultValue) && $this->oForm->IsDisplayed()) ? '' : 'style="display:none"';
$oSubForm = $aFormData['form'];
$oSubForm->SetParentForm($this->oForm);
$oSubForm->CopySubmitParams($this->oForm);
$oSubForm->SetPrefix($this->oForm->GetPrefix().$sKey.'_');
if ($sRenderMode == 'property') {
if ($sRenderMode == 'property')
{
// Note: Managing the visibility of nested subforms had several implications
// 1) Attributes are displayed in a table and we have to group them in as many tbodys as necessary to hide/show the various options depending on the current selection
// 2) It is not possible to nest tbody tags. Therefore, it is not possible to manage the visibility the same way as it is done for the dialog mode (using nested divs).
@@ -1823,7 +1726,7 @@ class DesignerFormSelectorField extends DesignerFormField
{
$oP->add_ready_script(
<<<EOF
$('#$sId').on('change reverted', function() { $('.subform_{$sId}').hide(); $('.{$sId}_'+this.value).show(); } );
$('#$sId').bind('change reverted', function() { $('.subform_{$sId}').hide(); $('.{$sId}_'+this.value).show(); } );
EOF
);
}
@@ -1887,14 +1790,6 @@ class DesignerSubFormField extends DesignerFormField
parent::__construct('', $sLabel, '');
$this->oSubForm = $oSubForm;
}
/**
* @inheritDoc
*/
public function GetInputType(): ?string
{
return null;
}
public function Render(WebPage $oP, $sFormId, $sRenderMode='dialog')
{
@@ -1939,14 +1834,6 @@ class DesignerStaticTextField extends DesignerFormField
parent::__construct($sCode, $sLabel, $defaultValue);
}
/**
* @inheritDoc
*/
public function GetInputType(): ?string
{
return null;
}
public function Render(WebPage $oP, $sFormId, $sRenderMode='dialog')
{
return array('label' => $this->sLabel, 'value' => $this->defaultValue);

View File

@@ -1,5 +1,5 @@
<?php
// Copyright (C) 2010-2021 Combodo SARL
// Copyright (C) 2010-2012 Combodo SARL
//
// This file is part of iTop.
//
@@ -20,7 +20,7 @@
/**
* Persistent class InputOutputTask
*
* @copyright Copyright (C) 2010-2021 Combodo SARL
* @copyright Copyright (C) 2010-2012 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
@@ -44,6 +44,7 @@ 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,8 +1,57 @@
<?php
// Copyright (C) 2010-2012 Combodo SARL
//
// This file is part of iTop.
//
// iTop is free software; you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// iTop is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with iTop. If not, see <http://www.gnu.org/licenses/>
/**
* @deprecated will be removed in 3.1.0 - moved to sources/application/WebPage/iTopWizardWebPage.php, now loadable using autoloader
* Class iTopWizardWebPage
*
* @copyright Copyright (C) 2010-2012 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
* @copyright Copyright (C) 2010-2021 Combodo SARL
*/
DeprecatedCallsLog::NotifyDeprecatedFile('moved to sources/application/WebPage/iTopWizardWebPage.php, now loadable using autoloader');
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

@@ -1,11 +1,8 @@
<?php
use Combodo\iTop\Application\Helper\Session;
/**
* Class LoginBasic
*
* @copyright Copyright (C) 2010-2021 Combodo SARL
* @copyright Copyright (C) 2010-2019 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
@@ -23,19 +20,19 @@ class LoginBasic extends AbstractLoginFSMExtension
protected function OnModeDetection(&$iErrorCode)
{
if (!Session::IsSet('login_mode'))
if (!isset($_SESSION['login_mode']))
{
if (isset($_SERVER['HTTP_AUTHORIZATION']) && !empty($_SERVER['HTTP_AUTHORIZATION']))
{
Session::Set('login_mode', 'basic');
$_SESSION['login_mode'] = 'basic';
}
elseif (isset($_SERVER['REDIRECT_HTTP_AUTHORIZATION']) && !empty($_SERVER['REDIRECT_HTTP_AUTHORIZATION']))
{
Session::Set('login_mode', 'basic');
$_SESSION['login_mode'] = 'basic';
}
elseif (isset($_SERVER['PHP_AUTH_USER']))
{
Session::Set('login_mode', 'basic');
$_SESSION['login_mode'] = 'basic';
}
}
return LoginWebPage::LOGIN_FSM_CONTINUE;
@@ -43,10 +40,10 @@ class LoginBasic extends AbstractLoginFSMExtension
protected function OnReadCredentials(&$iErrorCode)
{
if (!Session::IsSet('login_mode') || Session::Get('login_mode') == 'basic')
if (!isset($_SESSION['login_mode']) || $_SESSION['login_mode'] == 'basic')
{
list($sAuthUser) = $this->GetAuthUserAndPassword();
Session::Set('login_temp_auth_user', $sAuthUser);
list($sAuthUser, $sAuthPwd) = $this->GetAuthUserAndPassword();
$_SESSION['login_temp_auth_user'] = $sAuthUser;
}
return LoginWebPage::LOGIN_FSM_CONTINUE;
}
@@ -54,32 +51,39 @@ class LoginBasic extends AbstractLoginFSMExtension
protected function OnCheckCredentials(&$iErrorCode)
{
if (Session::Get('login_mode') == 'basic')
if (isset($_SESSION['login_mode']) && $_SESSION['login_mode'] == 'basic')
{
list($sAuthUser, $sAuthPwd) = $this->GetAuthUserAndPassword();
if (!UserRights::CheckCredentials($sAuthUser, $sAuthPwd, Session::Get('login_mode'), 'internal'))
if (!UserRights::CheckCredentials($sAuthUser, $sAuthPwd, $_SESSION['login_mode'], 'internal'))
{
$iErrorCode = LoginWebPage::EXIT_CODE_WRONGCREDENTIALS;
return LoginWebPage::LOGIN_FSM_ERROR;
}
Session::Set('auth_user', $sAuthUser);
// Save the checked user
$_SESSION['auth_user'] = $sAuthUser;
}
return LoginWebPage::LOGIN_FSM_CONTINUE;
}
protected function OnCredentialsOK(&$iErrorCode)
{
if (Session::Get('login_mode') == 'basic')
if (isset($_SESSION['login_mode']) && $_SESSION['login_mode'] == 'basic')
{
LoginWebPage::OnLoginSuccess(Session::Get('auth_user'), 'internal', Session::Get('login_mode'));
$sAuthUser = $_SESSION['auth_user'];
LoginWebPage::OnLoginSuccess($sAuthUser, 'internal', $_SESSION['login_mode']);
}
return LoginWebPage::LOGIN_FSM_CONTINUE;
}
protected function OnError(&$iErrorCode)
{
if (Session::Get('login_mode') == 'basic')
if (isset($_SESSION['login_mode']) && $_SESSION['login_mode'] == 'basic')
{
$iOnExit = LoginWebPage::getIOnExit();
if ($iOnExit === LoginWebPage::EXIT_RETURN)
{
return LoginWebPage::LOGIN_FSM_RETURN; // Error, exit FSM
}
LoginWebPage::HTTP401Error();
}
return LoginWebPage::LOGIN_FSM_CONTINUE;
@@ -87,9 +91,9 @@ class LoginBasic extends AbstractLoginFSMExtension
protected function OnConnected(&$iErrorCode)
{
if (Session::Get('login_mode') == 'basic')
if (isset($_SESSION['login_mode']) && $_SESSION['login_mode'] == 'basic')
{
Session::Set('can_logoff', true);
$_SESSION['can_logoff'] = true;
return LoginWebPage::CheckLoggedUser($iErrorCode);
}
return LoginWebPage::LOGIN_FSM_CONTINUE;

View File

@@ -1,11 +1,9 @@
<?php
/**
* @copyright Copyright (C) 2010-2021 Combodo SARL
* @copyright Copyright (C) 2010-2019 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
use Combodo\iTop\Application\Helper\Session;
/**
* Class LoginDefaultBefore
*/
@@ -25,7 +23,7 @@ class LoginDefaultBefore extends AbstractLoginFSMExtension
{
$iErrorCode = LoginWebPage::EXIT_CODE_OK;
Session::Unset('login_temp_auth_user');
unset($_SESSION['login_temp_auth_user']);
// Check if proposed login mode is present and allowed
$aAllowedLoginTypes = MetaModel::GetConfig()->GetAllowedLoginTypes();
@@ -34,11 +32,11 @@ class LoginDefaultBefore extends AbstractLoginFSMExtension
if ($index !== false)
{
// Force login mode
Session::Set('login_mode', $sProposedLoginMode);
$_SESSION['login_mode'] = $sProposedLoginMode;
}
else
{
Session::Unset('login_mode');
unset($_SESSION['login_mode']);
}
return LoginWebPage::LOGIN_FSM_CONTINUE;
}
@@ -79,7 +77,7 @@ class LoginDefaultAfter extends AbstractLoginFSMExtension implements iLogoutExte
{
self::ResetLoginSession();
$iOnExit = LoginWebPage::getIOnExit();
if ($iOnExit == LoginWebPage::EXIT_RETURN)
if ($iOnExit === LoginWebPage::EXIT_RETURN)
{
return LoginWebPage::LOGIN_FSM_RETURN; // Error, exit FSM
}
@@ -93,8 +91,14 @@ class LoginDefaultAfter extends AbstractLoginFSMExtension implements iLogoutExte
protected function OnCredentialsOk(&$iErrorCode)
{
if (!Session::IsSet('login_mode'))
if (!isset($_SESSION['login_mode']))
{
// N°6358 - if EXIT_RETURN was asked, send an error
if (LoginWebPage::getIOnExit() === LoginWebPage::EXIT_RETURN) {
$iErrorCode = LoginWebPage::EXIT_CODE_WRONGCREDENTIALS;
return LoginWebPage::LOGIN_FSM_ERROR;
}
// If no plugin validated the user, exit
self::ResetLoginSession();
exit();
@@ -112,7 +116,12 @@ class LoginDefaultAfter extends AbstractLoginFSMExtension implements iLogoutExte
protected function OnConnected(&$iErrorCode)
{
Session::Unset('login_temp_auth_user');
unset($_SESSION['login_temp_auth_user']);
if (is_null(UserRights::GetUserObject())){
//N°7085 avoid infinite loop
IssueLog::Error("No user logged in. exit");
exit(-1);
}
return LoginWebPage::LOGIN_FSM_CONTINUE;
}
@@ -120,12 +129,12 @@ class LoginDefaultAfter extends AbstractLoginFSMExtension implements iLogoutExte
private static function ResetLoginSession()
{
LoginWebPage::ResetSession();
foreach (Session::ListVariables() as $sKey)
foreach (array_keys($_SESSION) as $sKey)
{
if (utils::StartsWith($sKey, 'login_'))
{
Session::Unset($sKey);
unset($_SESSION[$sKey]);
}
}
}
}
}

View File

@@ -1,11 +1,9 @@
<?php
use Combodo\iTop\Application\Helper\Session;
/**
* Class LoginExternal
*
* @copyright Copyright (C) 2010-2021 Combodo SARL
* @copyright Copyright (C) 2010-2019 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
@@ -24,12 +22,12 @@ class LoginExternal extends AbstractLoginFSMExtension
protected function OnModeDetection(&$iErrorCode)
{
if (!Session::IsSet('login_mode'))
if (!isset($_SESSION['login_mode']))
{
$sAuthUser = $this->GetAuthUser();
if ($sAuthUser && (strlen($sAuthUser) > 0))
{
Session::Set('login_mode', 'external');
$_SESSION['login_mode'] = 'external';
}
}
return LoginWebPage::LOGIN_FSM_CONTINUE;
@@ -37,33 +35,35 @@ class LoginExternal extends AbstractLoginFSMExtension
protected function OnCheckCredentials(&$iErrorCode)
{
if (Session::Get('login_mode') == 'external')
if (isset($_SESSION['login_mode']) && $_SESSION['login_mode'] == 'external')
{
$sAuthUser = $this->GetAuthUser();
if (!UserRights::CheckCredentials($sAuthUser, '', Session::Get('login_mode'), 'external'))
if (!UserRights::CheckCredentials($sAuthUser, '', $_SESSION['login_mode'], 'external'))
{
$iErrorCode = LoginWebPage::EXIT_CODE_WRONGCREDENTIALS;
return LoginWebPage::LOGIN_FSM_ERROR;
}
Session::Set('auth_user', $sAuthUser);
// Save the checked user
$_SESSION['auth_user'] = $sAuthUser;
}
return LoginWebPage::LOGIN_FSM_CONTINUE;
}
protected function OnCredentialsOK(&$iErrorCode)
{
if (Session::Get('login_mode') == 'external')
if (isset($_SESSION['login_mode']) && $_SESSION['login_mode'] == 'external')
{
LoginWebPage::OnLoginSuccess(Session::Get('auth_user'), 'external', Session::Get('login_mode'));
$sAuthUser = $_SESSION['auth_user'];
LoginWebPage::OnLoginSuccess($sAuthUser, 'external', $_SESSION['login_mode']);
}
return LoginWebPage::LOGIN_FSM_CONTINUE;
}
protected function OnConnected(&$iErrorCode)
{
if (Session::Get('login_mode') == 'external')
if (isset($_SESSION['login_mode']) && $_SESSION['login_mode'] == 'external')
{
Session::Set('can_logoff', false);
$_SESSION['can_logoff'] = false;
return LoginWebPage::CheckLoggedUser($iErrorCode);
}
return LoginWebPage::LOGIN_FSM_CONTINUE;
@@ -71,8 +71,13 @@ class LoginExternal extends AbstractLoginFSMExtension
protected function OnError(&$iErrorCode)
{
if (Session::Get('login_mode') == 'external')
if (isset($_SESSION['login_mode']) && $_SESSION['login_mode'] == 'external')
{
$iOnExit = LoginWebPage::getIOnExit();
if ($iOnExit === LoginWebPage::EXIT_RETURN)
{
return LoginWebPage::LOGIN_FSM_RETURN; // Error, exit FSM
}
LoginWebPage::HTTP401Error();
}
return LoginWebPage::LOGIN_FSM_CONTINUE;

View File

@@ -1,12 +1,10 @@
<?php
/**
* @copyright Copyright (C) 2010-2021 Combodo SARL
* @copyright Copyright (C) 2010-2019 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
use Combodo\iTop\Application\Helper\Session;
/**
* Class LoginForm
*
@@ -31,7 +29,8 @@ class LoginForm extends AbstractLoginFSMExtension implements iLoginUIExtension
*/
protected function OnReadCredentials(&$iErrorCode)
{
if (!Session::IsSet('login_mode') || Session::Get('login_mode') == 'form') {
if (!isset($_SESSION['login_mode']) || ($_SESSION['login_mode'] == 'form'))
{
$sAuthUser = utils::ReadPostedParam('auth_user', '', 'raw_data');
$sAuthPwd = utils::ReadPostedParam('auth_pwd', null, 'raw_data');
if ($this->bForceFormOnError || empty($sAuthUser) || empty($sAuthPwd))
@@ -44,6 +43,10 @@ class LoginForm extends AbstractLoginFSMExtension implements iLoginUIExtension
exit;
}
if (LoginWebPage::getIOnExit() === LoginWebPage::EXIT_RETURN) {
return LoginWebPage::LOGIN_FSM_CONTINUE;
}
// No credentials yet, display the form
$oPage = LoginWebPage::NewLoginWebPage();
$oPage->DisplayLoginForm($this->bForceFormOnError);
@@ -51,8 +54,9 @@ class LoginForm extends AbstractLoginFSMExtension implements iLoginUIExtension
$this->bForceFormOnError = false;
exit;
}
Session::Set('login_temp_auth_user', $sAuthUser);
Session::Set('login_mode', 'form');
$_SESSION['login_temp_auth_user'] = $sAuthUser;
$_SESSION['login_mode'] = 'form';
}
return LoginWebPage::LOGIN_FSM_CONTINUE;
}
@@ -62,16 +66,17 @@ class LoginForm extends AbstractLoginFSMExtension implements iLoginUIExtension
*/
protected function OnCheckCredentials(&$iErrorCode)
{
if (Session::Get('login_mode') == 'form')
if (isset($_SESSION['login_mode']) && $_SESSION['login_mode'] == 'form')
{
$sAuthUser = utils::ReadPostedParam('auth_user', '', 'raw_data');
$sAuthPwd = utils::ReadPostedParam('auth_pwd', null, 'raw_data');
if (!UserRights::CheckCredentials($sAuthUser, $sAuthPwd, Session::Get('login_mode'), 'internal'))
if (!UserRights::CheckCredentials($sAuthUser, $sAuthPwd, $_SESSION['login_mode'], 'internal'))
{
$iErrorCode = LoginWebPage::EXIT_CODE_WRONGCREDENTIALS;
return LoginWebPage::LOGIN_FSM_ERROR;
}
Session::Set('auth_user', $sAuthUser);
// Save the checked user
$_SESSION['auth_user'] = $sAuthUser;
}
return LoginWebPage::LOGIN_FSM_CONTINUE;
}
@@ -81,10 +86,11 @@ class LoginForm extends AbstractLoginFSMExtension implements iLoginUIExtension
*/
protected function OnCredentialsOK(&$iErrorCode)
{
if (Session::Get('login_mode') == 'form')
if (isset($_SESSION['login_mode']) && $_SESSION['login_mode'] == 'form')
{
$sAuthUser = $_SESSION['auth_user'];
// Store 'auth_user' in session for further use
LoginWebPage::OnLoginSuccess(Session::Get('auth_user'), 'internal', Session::Get('login_mode'));
LoginWebPage::OnLoginSuccess($sAuthUser, 'internal', $_SESSION['login_mode']);
}
return LoginWebPage::LOGIN_FSM_CONTINUE;
}
@@ -94,7 +100,7 @@ class LoginForm extends AbstractLoginFSMExtension implements iLoginUIExtension
*/
protected function OnError(&$iErrorCode)
{
if (Session::Get('login_mode') == 'form')
if (isset($_SESSION['login_mode']) && $_SESSION['login_mode'] == 'form')
{
$this->bForceFormOnError = true;
}
@@ -106,9 +112,9 @@ class LoginForm extends AbstractLoginFSMExtension implements iLoginUIExtension
*/
protected function OnConnected(&$iErrorCode)
{
if (Session::Get('login_mode') == 'form')
if (isset($_SESSION['login_mode']) && $_SESSION['login_mode'] == 'form')
{
Session::Set('can_logoff', true);
$_SESSION['can_logoff'] = true;
return LoginWebPage::CheckLoggedUser($iErrorCode);
}
return LoginWebPage::LOGIN_FSM_CONTINUE;

View File

@@ -2,12 +2,11 @@
/**
*
* @copyright Copyright (C) 2010-2021 Combodo SARL
* @copyright Copyright (C) 2010-2019 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
use Combodo\iTop\Application\Branding;
use Combodo\iTop\TwigExtension;
/**
@@ -225,7 +224,7 @@ class LoginTwigRenderer
}
$oCoreLoader = new Twig_Loader_Filesystem(array(), APPROOT.'templates');
$aCoreTemplatesPaths = array('pages/login', 'pages/login/password');
$aCoreTemplatesPaths = array('login', '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
@@ -239,9 +238,16 @@ class LoginTwigRenderer
public function GetDefaultVars()
{
$sLogo = 'itop-logo-external.png';
$sBrandingLogo = 'login-logo.png';
$sVersionShort = Dict::Format('UI:iTopVersion:Short', ITOP_APPLICATION, ITOP_VERSION);
$sIconUrl = Utils::GetConfig()->Get('app_icon_url');
$sDisplayIcon = Branding::GetLoginLogoAbsoluteUrl();
$sDisplayIcon = utils::GetAbsoluteUrlAppRoot().'images/'.$sLogo.'?t='.utils::GetCacheBusterTimestamp();
if (file_exists(MODULESROOT.'branding/'.$sBrandingLogo))
{
$sDisplayIcon = utils::GetAbsoluteUrlModulesRoot().'branding/'.$sBrandingLogo.'?t='.utils::GetCacheBusterTimestamp();
}
$aVars = array(
'sAppRootUrl' => utils::GetAbsoluteUrlAppRoot(),

View File

@@ -1,11 +1,9 @@
<?php
use Combodo\iTop\Application\Helper\Session;
/**
* Class LoginURL
*
* @copyright Copyright (C) 2010-2021 Combodo SARL
* @copyright Copyright (C) 2010-2019 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
@@ -28,13 +26,13 @@ class LoginURL extends AbstractLoginFSMExtension
protected function OnModeDetection(&$iErrorCode)
{
if (!Session::IsSet('login_mode') && !$this->bErrorOccurred)
if (!isset($_SESSION['login_mode']) && !$this->bErrorOccurred)
{
$sAuthUser = utils::ReadParam('auth_user', '', false, 'raw_data');
$sAuthPwd = utils::ReadParam('auth_pwd', null, false, 'raw_data');
if (!empty($sAuthUser) && !empty($sAuthPwd))
{
Session::Set('login_mode', 'url');
$_SESSION['login_mode'] = 'url';
}
}
return LoginWebPage::LOGIN_FSM_CONTINUE;
@@ -42,41 +40,43 @@ class LoginURL extends AbstractLoginFSMExtension
protected function OnReadCredentials(&$iErrorCode)
{
if (Session::Get('login_mode') == 'url')
if (isset($_SESSION['login_mode']) && $_SESSION['login_mode'] == 'url')
{
Session::Set('login_temp_auth_user', utils::ReadParam('auth_user', '', false, 'raw_data'));
$_SESSION['login_temp_auth_user'] = utils::ReadParam('auth_user', '', false, 'raw_data');
}
return LoginWebPage::LOGIN_FSM_CONTINUE;
}
protected function OnCheckCredentials(&$iErrorCode)
{
if (Session::Get('login_mode') == 'url')
if (isset($_SESSION['login_mode']) && $_SESSION['login_mode'] == 'url')
{
$sAuthUser = utils::ReadParam('auth_user', '', false, 'raw_data');
$sAuthPwd = utils::ReadParam('auth_pwd', null, false, 'raw_data');
if (!UserRights::CheckCredentials($sAuthUser, $sAuthPwd, Session::Get('login_mode'), 'internal'))
if (!UserRights::CheckCredentials($sAuthUser, $sAuthPwd, $_SESSION['login_mode'], 'internal'))
{
$iErrorCode = LoginWebPage::EXIT_CODE_WRONGCREDENTIALS;
return LoginWebPage::LOGIN_FSM_ERROR;
}
Session::Set('auth_user', $sAuthUser);
// Save the checked user
$_SESSION['auth_user'] = $sAuthUser;
}
return LoginWebPage::LOGIN_FSM_CONTINUE;
}
protected function OnCredentialsOK(&$iErrorCode)
{
if (Session::Get('login_mode') == 'url')
if (isset($_SESSION['login_mode']) && $_SESSION['login_mode'] == 'url')
{
LoginWebPage::OnLoginSuccess(Session::Get('auth_user'), 'internal', Session::Get('login_mode'));
$sAuthUser = $_SESSION['auth_user'];
LoginWebPage::OnLoginSuccess($sAuthUser, 'internal', $_SESSION['login_mode']);
}
return LoginWebPage::LOGIN_FSM_CONTINUE;
}
protected function OnError(&$iErrorCode)
{
if (Session::Get('login_mode') == 'url')
if (isset($_SESSION['login_mode']) && $_SESSION['login_mode'] == 'url')
{
$this->bErrorOccurred = true;
}
@@ -85,9 +85,9 @@ class LoginURL extends AbstractLoginFSMExtension
protected function OnConnected(&$iErrorCode)
{
if (Session::Get('login_mode') == 'url')
if ($_SESSION['login_mode'] == 'url')
{
Session::Set('can_logoff', true);
$_SESSION['can_logoff'] = true;
return LoginWebPage::CheckLoggedUser($iErrorCode);
}
return LoginWebPage::LOGIN_FSM_CONTINUE;

View File

@@ -1,5 +1,5 @@
<?php
// Copyright (C) 2010-2021 Combodo SARL
// Copyright (C) 2010-2017 Combodo SARL
//
// This file is part of iTop.
//
@@ -20,13 +20,10 @@
/**
* Class LoginWebPage
*
* @copyright Copyright (C) 2010-2021 Combodo SARL
* @copyright Copyright (C) 2010-2017 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
use Combodo\iTop\Application\Branding;
use Combodo\iTop\Application\Helper\Session;
/**
* Web page used for displaying the login form
*/
@@ -35,7 +32,7 @@ class LoginWebPage extends NiceWebPage
{
const EXIT_PROMPT = 0;
const EXIT_HTTP_401 = 1;
const EXIT_RETURN = 2;
const EXIT_RETURN = 2; // Non interactive mode (ajax, rest, ...)
const EXIT_CODE_OK = 0;
const EXIT_CODE_MISSINGLOGIN = 1;
@@ -88,13 +85,14 @@ class LoginWebPage extends NiceWebPage
parent::__construct($sTitle);
$this->SetStyleSheet();
$this->no_cache();
$this->add_xframe_options();
$this->add_http_headers();
}
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)
@@ -102,49 +100,18 @@ 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';
$sBrandingLogo = 'login-logo.png';
$sVersionShort = Dict::Format('UI:iTopVersion:Short', ITOP_APPLICATION, ITOP_VERSION);
$sIconUrl = Utils::GetConfig()->Get('app_icon_url');
$sDisplayIcon = Branding::GetLoginLogoAbsoluteUrl();
$sDisplayIcon = utils::GetAbsoluteUrlAppRoot().'images/'.$sLogo.'?t='.utils::GetCacheBusterTimestamp();
if (file_exists(MODULESROOT.'branding/'.$sBrandingLogo))
{
$sDisplayIcon = utils::GetAbsoluteUrlModulesRoot().'branding/'.$sBrandingLogo.'?t='.utils::GetCacheBusterTimestamp();
}
$this->add("<div id=\"login-logo\"><a href=\"".htmlentities($sIconUrl, ENT_QUOTES,
self::PAGES_CHARSET)."\"><img title=\"$sVersionShort\" src=\"$sDisplayIcon\"></a></div>\n");
}
@@ -385,14 +352,20 @@ class LoginWebPage extends NiceWebPage
$this->output();
}
public static function ResetSession()
public static function ResetSession($bFullCleanup = false)
{
// Unset all of the session variables.
Session::Unset('auth_user');
Session::Unset('login_state');
Session::Unset('can_logoff');
Session::Unset('archive_mode');
Session::Unset('impersonate_user');
if ($bFullCleanup) {
// Unset all of the session variables.
foreach (array_keys($_SESSION) as $sKey) {
unset($_SESSION[$sKey]);
}
} else {
unset($_SESSION['auth_user']);
unset($_SESSION['login_state']);
unset($_SESSION['can_logoff']);
unset($_SESSION['archive_mode']);
unset($_SESSION['impersonate_user']);
}
UserRights::_ResetSessionCache();
// If it's desired to kill the session, also delete the session cookie.
// Note: This will destroy the session, and not just the session data!
@@ -438,11 +411,11 @@ class LoginWebPage extends NiceWebPage
}
$bLoginDebug = MetaModel::GetConfig()->Get('login_debug');
if (Session::Get('login_state') == self::LOGIN_STATE_ERROR)
if (!isset($_SESSION['login_state']) || ($_SESSION['login_state'] == self::LOGIN_STATE_ERROR))
{
Session::Set('login_state', self::LOGIN_STATE_START);
$_SESSION['login_state'] = self::LOGIN_STATE_START;
}
$sLoginState = Session::Get('login_state');
$sLoginState = $_SESSION['login_state'];
$sSessionLog = '';
if ($bLoginDebug)
@@ -483,7 +456,6 @@ class LoginWebPage extends NiceWebPage
$iResponse = $oLoginFSMExtensionInstance->LoginAction($sLoginState, $iErrorCode);
if ($iResponse == self::LOGIN_FSM_RETURN)
{
Session::WriteClose();
return $iErrorCode; // Asked to exit FSM, generally login OK
}
if ($iResponse == self::LOGIN_FSM_ERROR)
@@ -497,7 +469,7 @@ class LoginWebPage extends NiceWebPage
// Every plugin has nothing else to do in this state, go forward
$sLoginState = self::AdvanceLoginFSMState($sLoginState);
Session::Set('login_state', $sLoginState);
$_SESSION['login_state'] = $sLoginState;
}
catch (Exception $e)
{
@@ -523,7 +495,7 @@ class LoginWebPage extends NiceWebPage
if ($bFilterWithMode)
{
$sCurrentLoginMode = Session::Get('login_mode', '');
$sCurrentLoginMode = isset($_SESSION['login_mode']) ? $_SESSION['login_mode'] : '';
}
else
{
@@ -662,8 +634,8 @@ class LoginWebPage extends NiceWebPage
$oLog->DBInsertNoReload();
}
Session::Set('auth_user', $sAuthUser);
Session::Set('login_mode', $sLoginMode);
$_SESSION['auth_user'] = $sAuthUser;
$_SESSION['login_mode'] = $sLoginMode;
UserRights::_InitSessionCache();
}
@@ -678,10 +650,10 @@ class LoginWebPage extends NiceWebPage
*/
public static function CheckLoggedUser(&$iErrorCode)
{
if (Session::IsSet('auth_user'))
if (isset($_SESSION['auth_user']))
{
// Already authenticated
$bRet = UserRights::Login(Session::Get('auth_user')); // Login & set the user's language
$bRet = UserRights::Login($_SESSION['auth_user']); // Login & set the user's language
if ($bRet)
{
$iErrorCode = self::EXIT_CODE_OK;
@@ -709,11 +681,11 @@ class LoginWebPage extends NiceWebPage
public static function SetLoginModeAndReload($sNewLoginMode)
{
if (Session::Get('login_mode') == $sNewLoginMode)
if (isset($_SESSION['login_mode']) && ($_SESSION['login_mode'] == $sNewLoginMode))
{
return;
}
Session::Set('login_mode', $sNewLoginMode);
$_SESSION['login_mode'] = $sNewLoginMode;
self::HTTPReload();
}
@@ -826,9 +798,9 @@ class LoginWebPage extends NiceWebPage
{
CMDBObject::SetTrackOrigin('custom-extension');
$sInfo = 'External User provisioning';
if (Session::IsSet('login_mode'))
if (isset($_SESSION['login_mode']))
{
$sInfo .= " (".Session::Get('login_mode').")";
$sInfo .= " ({$_SESSION['login_mode']})";
}
CMDBObject::SetTrackInfo($sInfo);
@@ -880,9 +852,9 @@ class LoginWebPage extends NiceWebPage
{
CMDBObject::SetTrackOrigin('custom-extension');
$sInfo = 'External User provisioning';
if (Session::IsSet('login_mode'))
if (isset($_SESSION['login_mode']))
{
$sInfo .= " (".Session::Get('login_mode').")";
$sInfo .= " ({$_SESSION['login_mode']})";
}
CMDBObject::SetTrackInfo($sInfo);
@@ -920,12 +892,20 @@ class LoginWebPage extends NiceWebPage
}
// Now synchronize the profiles
$oProfilesSet = DBObjectSet::FromScratch('URP_UserProfile');
$sOrigin = 'External User provisioning';
if (Session::IsSet('login_mode'))
if (isset($_SESSION['login_mode']))
{
$sOrigin .= " (".Session::Get('login_mode').")";
$sOrigin .= " ({$_SESSION['login_mode']})";
}
$aExistingProfiles = self::SynchronizeProfiles($oUser, $aProfiles, $sOrigin);
foreach ($aProfiles as $iProfileId)
{
$oLink = new URP_UserProfile();
$oLink->Set('profileid', $iProfileId);
$oLink->Set('reason', $sOrigin);
$oProfilesSet->AddObject($oLink);
}
$oUser->Set('profile_list', $oProfilesSet);
if ($oUser->IsModified())
{
$oUser->DBWrite();
@@ -957,7 +937,7 @@ class LoginWebPage extends NiceWebPage
}
else
{
if ($iOnExit == self::EXIT_RETURN)
if ($iOnExit === self::EXIT_RETURN)
{
return self::EXIT_CODE_PORTALUSERNOTAUTHORIZED;
}
@@ -1008,11 +988,12 @@ class LoginWebPage extends NiceWebPage
$sMessage = self::HandleOperations($operation); // May exit directly
$iRet = self::Login($iOnExit);
if ($iRet == self::EXIT_CODE_OK)
{
if ($bMustBeAdmin && !UserRights::IsAdministrator())
{
if ($iOnExit == self::EXIT_RETURN)
if ($iOnExit === self::EXIT_RETURN)
{
return self::EXIT_CODE_MUSTBEADMIN;
}
@@ -1028,7 +1009,7 @@ class LoginWebPage extends NiceWebPage
}
$iRet = call_user_func(array(self::$sHandlerClass, 'ChangeLocation'), $sRequestedPortalId, $iOnExit);
}
if ($iOnExit == self::EXIT_RETURN)
if ($iOnExit === self::EXIT_RETURN)
{
return $iRet;
}
@@ -1087,23 +1068,19 @@ class LoginWebPage extends NiceWebPage
}
else if ($operation == 'change_pwd')
{
if (Session::IsSet('auth_user'))
if (isset($_SESSION['auth_user']))
{
$sAuthUser = Session::Get('auth_user');
$sIssue = Session::Get('pwd_issue');
Session::Unset('pwd_issue');
$bFailedLogin = ($sIssue != null); // Force the "failed login" flag to display the "issue" message
$sAuthUser = $_SESSION['auth_user'];
UserRights::Login($sAuthUser); // Set the user's language
$oPage = self::NewLoginWebPage();
$oPage->DisplayChangePwdForm($bFailedLogin, $sIssue);
$oPage->DisplayChangePwdForm();
$oPage->output();
exit;
}
}
else if ($operation == 'check_pwd_policy')
{
$sAuthUser = Session::Get('auth_user');
$sAuthUser = $_SESSION['auth_user'];
UserRights::Login($sAuthUser); // Set the user's language
$aPwdMap = array();
@@ -1121,9 +1098,9 @@ class LoginWebPage extends NiceWebPage
}
if ($operation == 'do_change_pwd')
{
if (Session::IsSet('auth_user'))
if (isset($_SESSION['auth_user']))
{
$sAuthUser = Session::Get('auth_user');
$sAuthUser = $_SESSION['auth_user'];
UserRights::Login($sAuthUser); // Set the user's language
$sOldPwd = utils::ReadPostedParam('old_pwd', '', 'raw_data');
$sNewPwd = utils::ReadPostedParam('new_pwd', '', 'raw_data');

View File

@@ -1,6 +1,6 @@
<?php
/**
* Copyright (C) 2013-2021 Combodo SARL
* Copyright (C) 2013-2019 Combodo SARL
*
* This file is part of iTop.
*
@@ -77,28 +77,17 @@ function _MaintenanceHtmlMessage($sMessage)
*/
function _MaintenanceJsonMessage($sTitle, $sMessage)
{
if (class_exists('JsonPage'))
@include_once(APPROOT."/application/ajaxwebpage.class.inc.php");
if (class_exists('ajax_page'))
{
$oP = new JsonPage($sTitle);
$oP = new ajax_page($sTitle);
$oP->add_header('Access-Control-Allow-Origin: *');
$aMessage = [
'code' => 100,
'message' =>$sMessage
];
$oP->AddData($aMessage);
$oP->SetContentType('application/json');
$oP->add('{"code":100, "message":"'.$sMessage.'"}');
$oP->Output();
} else {
@include_once(APPROOT."/application/ajaxwebpage.class.inc.php");
if (class_exists('ajax_page')) {
$oP = new ajax_page($sTitle);
$oP->add_header('Access-Control-Allow-Origin: *');
$oP->SetContentType('application/json');
$oP->add('{"code":100, "message":"'.$sMessage.'"}');
$oP->Output();
} else {
_MaintenanceTextMessage($sMessage);
}
}
else
{
_MaintenanceTextMessage($sMessage);
}
}

View File

@@ -1,11 +1,22 @@
<?php
/*
* @copyright Copyright (C) 2010-2021 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
/**
* 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
*/
use Combodo\iTop\Application\Helper\WebResourcesHelper;
require_once(APPROOT.'/application/utils.inc.php');
require_once(APPROOT.'/application/template.class.inc.php');
require_once(APPROOT."/application/user.dashboard.class.inc.php");
@@ -40,10 +51,7 @@ require_once(APPROOT."/application/user.dashboard.class.inc.php");
* new OQLMenuNode('PersonsMenu', 'SELECT bizPerson', $oContactsMenu->GetIndex(), 0);
*
*/
/**
* Class ApplicationMenu
*/
class ApplicationMenu
{
/**
@@ -58,19 +66,12 @@ class ApplicationMenu
* @var array
*/
static $aMenusIndex = array();
/**
* @var array
*/
static $aMenusById = [];
/**
* @var string
*/
static $sFavoriteSiloQuery = 'SELECT Organization';
/**
* @return void
*/
public static function LoadAdditionalMenus()
static public function LoadAdditionalMenus()
{
if (!self::$bAdditionalMenusLoaded)
{
@@ -96,10 +97,10 @@ class ApplicationMenu
/**
* Set the query used to limit the list of displayed organizations in the drop-down menu
* @param string $sOQL The OQL query returning a list of Organization objects
* @param $sOQL string The OQL query returning a list of Organization objects
* @return void
*/
public static function SetFavoriteSiloQuery($sOQL)
static public function SetFavoriteSiloQuery($sOQL)
{
self::$sFavoriteSiloQuery = $sOQL;
}
@@ -108,7 +109,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
*/
public static function GetFavoriteSiloQuery()
static public function GetFavoriteSiloQuery()
{
return self::$sFavoriteSiloQuery;
}
@@ -116,11 +117,11 @@ class ApplicationMenu
/**
* Check whether a menu Id is enabled or not
*
* @param string $sMenuId
* @param $sMenuId
*
* @throws \Exception
*/
public static function CheckMenuIdEnabled($sMenuId)
static public function CheckMenuIdEnabled($sMenuId)
{
self::LoadAdditionalMenus();
$oMenuNode = self::GetMenuNode(self::GetMenuIndexById($sMenuId));
@@ -139,11 +140,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 int $iParentIndex
* @param float $fRank
* @param $iParentIndex
* @param $fRank
* @return int
*/
public static function InsertMenu(MenuNode $oMenuNode, $iParentIndex, $fRank)
static public function InsertMenu(MenuNode $oMenuNode, $iParentIndex, $fRank)
{
$index = self::GetMenuIndexById($oMenuNode->GetMenuId());
if ($index == -1)
@@ -170,7 +171,6 @@ class ApplicationMenu
$aBacktrace = debug_backtrace();
$sFile = isset($aBacktrace[2]["file"]) ? $aBacktrace[2]["file"] : $aBacktrace[1]["file"];
self::$aMenusIndex[$index] = array('node' => $oMenuNode, 'children' => array(), 'parent' => $sParentId, 'rank' => $fRank, 'source_file' => $sFile);
self::$aMenusById[$oMenuNode->GetMenuId()] = $index;
}
else
{
@@ -185,174 +185,30 @@ class ApplicationMenu
/**
* Reflection API - Get menu entries
*
* @return array
*/
public static function ReflectionMenuNodes()
static public 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);
if (!($oMenuNode instanceof MenuGroup)) {
IssueLog::Error('Menu node was not displayed as a menu group as it is actually not a menu group', LogChannels::CONSOLE, [
'menu_node_class' => get_class($oMenuNode),
'menu_node_label' => $oMenuNode->GetLabel(),
]);
continue;
}
$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 array $aExtraParams
* @param $aExtraParams
* @throws DictExceptionMissingString
*
* @deprecated Will be removed in 3.0.0, use static::GetMenuGroups() instead
*/
public static function DisplayMenu($oPage, $aExtraParams)
static public function DisplayMenu($oPage, $aExtraParams)
{
DeprecatedCallsLog::NotifyDeprecatedPhpMethod('use static::GetMenuGroups() instead');
self::LoadAdditionalMenus();
// Sort the root menu based on the rank
usort(self::$aRootMenus, array('ApplicationMenu', 'CompareOnRank'));
$iAccordion = 0;
$iActiveAccordion = $iAccordion;
$iActiveMenu = self::GetMenuIndexById(self::GetActiveNodeId());
foreach (self::$aRootMenus as $aMenu) {
if (!self::CanDisplayMenu($aMenu)) {
continue;
}
foreach(self::$aRootMenus as $aMenu)
{
if (!self::CanDisplayMenu($aMenu)) { continue; }
$oMenuNode = self::GetMenuNode($aMenu['index']);
$oPage->AddToMenu('<h3 id="'.utils::GetSafeId('AccordionMenu_'.$oMenuNode->GetMenuID()).'" class="navigation-menu-group" data-menu-id="'.$oMenuNode->GetMenuId().'">'.$oMenuNode->GetTitle().'</h3>');
$oPage->AddToMenu('<div>');
@@ -381,7 +237,7 @@ EOF
* @param array $aMenu menu entry
* @return bool true if at least one menu is enabled
*/
private static function CanDisplayMenu($aMenu)
static private function CanDisplayMenu($aMenu)
{
$oMenuNode = self::GetMenuNode($aMenu['index']);
if ($oMenuNode->IsEnabled())
@@ -413,19 +269,19 @@ EOF
* @param array $aExtraParams
* @param int $iActiveMenu
*
* @return bool True if the currently selected menu is one of the submenus
* @return 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
*/
protected static function DisplaySubMenu($oPage, $aMenus, $aExtraParams, $iActiveMenu = -1)
static protected function DisplaySubMenu($oPage, $aMenus, $aExtraParams, $iActiveMenu = -1)
{
DeprecatedCallsLog::NotifyDeprecatedPhpMethod('use static::GetSubMenuNodes() instead');
// Sort the menu based on the rank
$bActive = false;
usort($aMenus, array('ApplicationMenu', 'CompareOnRank'));
foreach ($aMenus as $aMenu) {
if (!self::CanDisplayMenu($aMenu)) {
foreach($aMenus as $aMenu)
{
if (!self::CanDisplayMenu($aMenu))
{
continue;
}
$index = $aMenu['index'];
@@ -474,11 +330,11 @@ EOF
/**
* Helper function to sort the menus based on their rank
* @param array $a
* @param array $b
* @param $a
* @param $b
* @return int
*/
public static function CompareOnRank($a, $b)
static public function CompareOnRank($a, $b)
{
$result = 1;
if ($a['rank'] == $b['rank'])
@@ -497,7 +353,7 @@ EOF
* @param int $index
* @return MenuNode|null
*/
public static function GetMenuNode($index)
static public function GetMenuNode($index)
{
return isset(self::$aMenusIndex[$index]) ? self::$aMenusIndex[$index]['node'] : null;
}
@@ -507,7 +363,7 @@ EOF
* @param int $index
* @return array
*/
public static function GetChildren($index)
static public function GetChildren($index)
{
return self::$aMenusIndex[$index]['children'];
}
@@ -517,20 +373,26 @@ 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
*/
public static function GetMenuIndexById($sTitle)
static public function GetMenuIndexById($sTitle)
{
if (isset(self::$aMenusById[$sTitle])) {
return self::$aMenusById[$sTitle];
$index = -1;
/** @var MenuNode[] $aMenu */
foreach(self::$aMenusIndex as $aMenu)
{
if ($aMenu['node']->GetMenuId() == $sTitle)
{
$index = $aMenu['node']->GetIndex();
break;
}
}
return -1;
return $index;
}
/**
* Retrieves the currently active menu (if any, otherwise the first menu is the default)
* @return string The Id of the currently active menu
*/
public static function GetActiveNodeId()
static public function GetActiveNodeId()
{
$oAppContext = new ApplicationContext();
$sMenuId = $oAppContext->GetCurrentValue('menu', null);
@@ -544,7 +406,7 @@ EOF
/**
* @return null|string
*/
public static function GetDefaultMenuId()
static public function GetDefaultMenuId()
{
static $sDefaultMenuId = null;
if (is_null($sDefaultMenuId))
@@ -564,7 +426,7 @@ EOF
* @param $sMenuId
* @return string
*/
public static function GetRootMenuId($sMenuId)
static public function GetRootMenuId($sMenuId)
{
$iMenuIndex = self::GetMenuIndexById($sMenuId);
if ($iMenuIndex == -1)
@@ -661,7 +523,8 @@ abstract class MenuNode
$this->sMenuId = $sMenuId;
$this->iParentIndex = $iParentIndex;
$this->aReflectionProperties = array();
if (utils::IsNotNullOrEmptyString($sEnableClass)) {
if (strlen($sEnableClass) > 0)
{
$this->aReflectionProperties['enable_class'] = $sEnableClass;
$this->aReflectionProperties['enable_action'] = $iActionCode;
$this->aReflectionProperties['enable_permission'] = $iAllowedResults;
@@ -700,62 +563,29 @@ 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;
}
protected function GetEntriesCountFromOQL(string $sOQL)
{
// Count the entries up to 99
$oSearch = DBSearch::FromOQL($sOQL);
$oSearch->SetShowObsoleteData(utils::ShowObsoleteData());
DBSearchHelper::AddContextFilter($oSearch);
$oSet = new DBObjectSet($oSearch);
$iCount = $oSet->CountWithLimit(99);
if ($iCount > 99) {
$iCount = "99+";
}
return $iCount;
}
/**
* 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();
@@ -770,10 +600,7 @@ abstract class MenuNode
{
return $this->index;
}
/**
* @return void
*/
public function PopulateChildMenus()
{
foreach (ApplicationMenu::GetChildren($this->GetIndex()) as $aMenu)
@@ -898,64 +725,18 @@ 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, $sDecorationClasses = null, $sEnableClass = null, $iActionCode = null, $iAllowedResults = UR_ALLOWED_YES, $sEnableStimulus = null)
public function __construct($sMenuId, $fRank, $sEnableClass = null, $iActionCode = null, $iAllowedResults = UR_ALLOWED_YES, $sEnableStimulus = null)
{
parent::__construct($sMenuId, -1 /* no parent, groups are at root level */, $fRank, $sEnableClass, $iActionCode, $iAllowedResults, $sEnableStimulus);
if(!empty($sDecorationClasses))
{
$this->sDecorationClasses = $sDecorationClasses;
}
}
/**
* 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);
}
/**
@@ -1132,45 +913,30 @@ class OQLMenuNode extends MenuNode
{
$sUsageId = utils::GetSafeId($sUsageId);
$oSearch = DBObjectSearch::FromOQL($sOql);
$sClass= $oSearch->GetClass();
$sIcon = MetaModel::GetClassIcon($sClass, false);
if ($bSearchPane) {
$aParams = array_merge(['open' => $bSearchOpen, 'table_id' => $sUsageId, 'submit_on_load' => false], $aExtraParams);
$sIcon = MetaModel::GetClassIcon($oSearch->GetClass());
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("<div class='sf_results_area ibo-add-margin-top-250' data-target='search_results'>");
}
else {
$oPage->add("<div class='sf_results_area' data-target='search_results'>");
}
$aExtraParams['panel_class'] =$sClass;
$aExtraParams['panel_title'] = $sTitle;
$aExtraParams['panel_icon'] = $sIcon;
$oPage->add("<p class=\"page-header\">$sIcon ".utils::HtmlEntities(Dict::S($sTitle))."</p>");
$aParams = array_merge(array('table_id' => $sUsageId), $aExtraParams);
$oBlock = new DisplayBlock($oSearch, 'list', false /* Asynchronous */, $aParams);
$oBlock->Display($oPage, $sUsageId);
$oPage->add("</div>");
if ($bEnableBreadcrumb && ($oPage instanceof iTopWebPage)) {
if ($bEnableBreadcrumb && ($oPage instanceof iTopWebPage))
{
// Breadcrumb
//$iCount = $oBlock->GetDisplayedCount();
$sPageId = "ui-search-".$oSearch->GetClass();
$sLabel = MetaModel::GetName($oSearch->GetClass());
$oPage->SetBreadCrumbEntry($sPageId, $sLabel, $sTitle, '', 'fas fa-list', iTopWebPage::ENUM_BREADCRUMB_ENTRY_ICON_TYPE_CSS_CLASSES);
$oPage->SetBreadCrumbEntry($sPageId, $sLabel, $sTitle, '', '../images/breadcrumb-search.png');
}
}
public function HasCount()
{
return true;
}
public function GetEntriesCount()
{
return $this->GetEntriesCountFromOQL($this->sOQL);
}
}
/**
@@ -1215,11 +981,10 @@ class SearchMenuNode extends MenuNode
public function RenderContent(WebPage $oPage, $aExtraParams = array())
{
ApplicationMenu::CheckMenuIdEnabled($this->GetMenuId());
$oPage->SetBreadCrumbEntry("menu-".$this->sMenuId, $this->GetTitle(), '', '', 'fas fa-search', iTopWebPage::ENUM_BREADCRUMB_ENTRY_ICON_TYPE_CSS_CLASSES);
$oPage->SetBreadCrumbEntry("menu-".$this->sMenuId, $this->GetTitle(), '', '', utils::GetAbsoluteUrlAppRoot().'images/breadcrumb-search.png');
$oSearch = new DBObjectSearch($this->sClass);
$sUsageId = 'Menu_'.utils::GetSafeId($this->GetMenuId());
$aParams = array_merge(array('table_id' =>$sUsageId), $aExtraParams);
$aParams = array_merge(array('table_id' => 'Menu_'.utils::GetSafeId($this->GetMenuId())), $aExtraParams);
$oBlock = new DisplayBlock($oSearch, 'search', false /* Asynchronous */, $aParams);
$oBlock->Display($oPage, 0);
}
@@ -1425,35 +1190,41 @@ class DashboardMenuNode extends MenuNode
$oDashboard = $this->GetDashboard();
if ($oDashboard != null)
{
WebResourcesHelper::EnableC3JSToWebPage($oPage);
$sDivId = utils::Sanitize($this->sMenuId, '', 'element_identifier');
$oPage->add('<div id="'.$sDivId.'" class="ibo-dashboard" data-role="ibo-dashboard">');
$oPage->add('<div class="dashboard_contents" id="'.$sDivId.'">');
$aExtraParams['dashboard_div_id'] = $sDivId;
$aExtraParams['from_dashboard_page'] = true;
$oDashboard->SetReloadURL($this->GetHyperlink($aExtraParams));
$oDashboard->Render($oPage, false, $aExtraParams);
$oPage->add('</div>');
$bEdit = utils::ReadParam('edit', false);
if ($bEdit) {
if ($bEdit)
{
$sId = addslashes($this->sMenuId);
$oPage->add_ready_script("EditDashboard('$sId');");
} else {
}
else
{
$oParentMenu = ApplicationMenu::GetMenuNode($this->iParentIndex);
$sParentTitle = $oParentMenu->GetTitle();
$sThisTitle = $this->GetTitle();
if ($sParentTitle != $sThisTitle) {
if ($sParentTitle != $sThisTitle)
{
$sDescription = $sParentTitle.' / '.$sThisTitle;
} else {
}
else
{
$sDescription = $sThisTitle;
}
if ($this->sMenuId == ApplicationMenu::GetDefaultMenuId()) {
$sIcon = 'fas fa-home';
} else {
$sIcon = 'fas fa-chart-pie';
if ($this->sMenuId == ApplicationMenu::GetDefaultMenuId())
{
$sIcon = '../images/breadcrumb_home.png';
}
$oPage->SetBreadCrumbEntry("ui-dashboard-".$this->sMenuId, $this->GetTitle(), $sDescription, '', $sIcon, iTopWebPage::ENUM_BREADCRUMB_ENTRY_ICON_TYPE_CSS_CLASSES);
else
{
$sIcon = '../images/breadcrumb-dashboard.png';
}
$oPage->SetBreadCrumbEntry("ui-dashboard-".$this->sMenuId, $this->GetTitle(), $sDescription, '', $sIcon);
}
}
else
@@ -1622,23 +1393,5 @@ class ShortcutMenuNode extends MenuNode
{
return $this->oShortcut->Get('name');
}
/**
* 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 true;
}
public function GetEntriesCount()
{
return $this->GetEntriesCountFromOQL($this->oShortcut->Get('oql'));
}
}

View File

@@ -1,5 +1,5 @@
<?php
// Copyright (C) 2010-2021 Combodo SARL
// Copyright (C) 2010-2015 Combodo SARL
//
// This file is part of iTop.
//

View File

@@ -1,8 +1,262 @@
<?php
/**
* @deprecated will be removed in 3.1.0 - moved to sources/application/WebPage/NiceWebPage.php, now loadable using autoloader
* @license http://opensource.org/licenses/AGPL-3.0
* @copyright Copyright (C) 2010-2021 Combodo SARL
* 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
*/
DeprecatedCallsLog::NotifyDeprecatedFile('moved to sources/application/WebPage/NiceWebPage.php, now loadable using autoloader');
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::GetCurrentThemeUrl();
$this->add_linked_stylesheet($sCssThemeUrl);
}
}

View File

@@ -1,8 +1,248 @@
<?php
/**
* @deprecated will be removed in 3.1.0 - moved to sources/application/WebPage/PDFPage.php, now loadable using autoloader
* @license http://opensource.org/licenses/AGPL-3.0
* @copyright Copyright (C) 2010-2021 Combodo SARL
* 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
*/
DeprecatedCallsLog::NotifyDeprecatedFile('moved to sources/application/WebPage/PDFPage.php, now loadable using autoloader');
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.0
*/
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

@@ -1,34 +1,33 @@
<?php
/*
* Copyright (C) 2010-2021 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
*/
// 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/>
use Combodo\iTop\Application\UI\Base\Component\Alert\AlertUIBlockFactory;
use Combodo\iTop\Application\UI\Base\Component\Field\Field;
use Combodo\iTop\Application\UI\Base\Component\Field\FieldUIBlockFactory;
use Combodo\iTop\Application\UI\Base\Component\Html\Html;
use Combodo\iTop\Application\UI\Base\Component\Input\TextArea;
/**
* Persistent class Event and derived
* Application internal events
* There is also a file log
*
* @copyright Copyright (C) 2010-2015 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
abstract class Query extends cmdbAbstractObject
{
/**
* @throws \CoreException
* @since 3.0.0 N°3227 add is_template field for predefined queries
*/
public static function Init()
{
$aParams = array
@@ -41,41 +40,20 @@ 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();
MetaModel::Init_AddAttribute(new AttributeString("name", array("allowed_values"=>null, "sql"=>"name", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeText("description", array("allowed_values"=>null, "sql"=>"description", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeString("name", array(
"allowed_values" => null,
"sql" => "name",
"default_value" => null,
"is_null_allowed" => false,
"depends_on" => array(),
)));
MetaModel::Init_AddAttribute(new AttributeText("description", array(
"allowed_values" => null,
"sql" => "description",
"default_value" => null,
"is_null_allowed" => false,
"depends_on" => array(),
)));
MetaModel::Init_AddAttribute(new AttributeEnum("is_template", array(
'allowed_values' => new ValueSetEnum('yes,no'),
'sql' => 'is_template',
'default_value' => 'no',
'is_null_allowed' => false,
'depends_on' => [],
'display_style' => 'radio_horizontal',
)));
// Display lists
MetaModel::Init_SetZListItems('details',
array('name', 'is_template', 'description')); // Attributes to be displayed for the complete details
MetaModel::Init_SetZListItems('details', array('name', 'description')); // Attributes to be displayed for the complete details
MetaModel::Init_SetZListItems('list', array('description')); // Attributes to be displayed for a list
// Search criteria
MetaModel::Init_SetZListItems('standard_search', array('name', 'description', 'is_template')); // Criteria of the std search form
MetaModel::Init_SetZListItems('default_search',
array('name', 'description', 'is_template')); // Criteria of the default search form
MetaModel::Init_SetZListItems('standard_search', array('name', 'description')); // Criteria of the std search form
MetaModel::Init_SetZListItems('default_search', array('name', 'description')); // Criteria of the default search form
// MetaModel::Init_SetZListItems('advanced_search', array('name')); // Criteria of the advanced search form
}
}
@@ -90,73 +68,59 @@ class QueryOQL extends Query
"key_type" => "autoincrement",
"name_attcode" => "name",
"state_attcode" => "",
"reconc_keys" => array('oql', 'is_template'),
"reconc_keys" => array(),
"db_table" => "priv_query_oql",
"db_key_field" => "id",
"db_finalclass_field" => "",
"display_template" => "",
);
MetaModel::Init_Params($aParams);
MetaModel::Init_InheritAttributes();
MetaModel::Init_AddAttribute(new AttributeOQL("oql", array(
"allowed_values" => null,
"sql" => "oql",
"default_value" => null,
"is_null_allowed" => false,
"depends_on" => array(),
)));
MetaModel::Init_AddAttribute(new AttributeText("fields", array(
"allowed_values" => null,
"sql" => "fields",
"default_value" => null,
"is_null_allowed" => true,
"depends_on" => array(),
)));
MetaModel::Init_AddAttribute(new AttributeOQL("oql", array("allowed_values"=>null, "sql"=>"oql", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeText("fields", array("allowed_values"=>null, "sql"=>"fields", "default_value"=>null, "is_null_allowed"=>true, "depends_on"=>array())));
// Rolled back to AttributeText until AttributeQueryAttCodeSet can manage fields order correctly
//MetaModel::Init_AddAttribute(new AttributeQueryAttCodeSet("fields", array("allowed_values"=>null,"max_items" => 1000, "query_field" => "oql", "sql"=>"fields", "default_value"=>null, "is_null_allowed"=>true, "depends_on"=>array('oql'))));
// Display lists
MetaModel::Init_SetZListItems('details',
array('name', 'is_template', 'description', 'oql', 'fields')); // Attributes to be displayed for the complete details
MetaModel::Init_SetZListItems('details', array('name', 'description', 'oql', 'fields')); // Attributes to be displayed for the complete details
MetaModel::Init_SetZListItems('list', array('description')); // Attributes to be displayed for a list
// Search criteria
MetaModel::Init_SetZListItems('standard_search',
array('name', 'description', 'is_template', 'fields', 'oql')); // Criteria of the std search form
MetaModel::Init_SetZListItems('standard_search', array('name', 'description', 'fields', 'oql')); // Criteria of the std search form
}
function DisplayBareProperties(WebPage $oPage, $bEditMode = false, $sPrefix = '', $aExtraParams = array())
{
$aFieldsMap = parent::DisplayBareProperties($oPage, $bEditMode, $sPrefix, $aExtraParams);
$oPage->add_script("$('[name=\"attr_oql\"]').addClass('ibo-query-oql ibo-is-code'); $('[data-attribute-code=\"oql\"]').addClass('ibo-query-oql ibo-is-code');");
if (!$bEditMode) {
if (!$bEditMode)
{
$sFields = trim($this->Get('fields'));
$bExportV1Recommended = ($sFields == '');
if ($bExportV1Recommended) {
if ($bExportV1Recommended)
{
$oFieldAttDef = MetaModel::GetAttributeDef('QueryOQL', 'fields');
$oAlert = AlertUIBlockFactory::MakeForFailure()
->SetIsClosable(false)
->SetIsCollapsible(false);
$oAlert->AddCSSClass('mb-5');
$oAlert->AddSubBlock(new Html(Dict::Format('UI:Query:UrlV1', '')));
$oPage->AddSubBlock($oAlert);
$oPage->add('<div class="message message_error" style="padding-left: 30px;"><div style="padding: 10px;">'.Dict::Format('UI:Query:UrlV1', $oFieldAttDef->GetLabel()).'</div></div>');
$sUrl = utils::GetAbsoluteUrlAppRoot().'webservices/export.php?format=spreadsheet&login_mode=basic&query='.$this->GetKey();
} else {
}
else
{
$sUrl = utils::GetAbsoluteUrlAppRoot().'webservices/export-v2.php?format=spreadsheet&login_mode=basic&date_format='.urlencode((string)AttributeDateTime::GetFormat()).'&query='.$this->GetKey();
}
$sOql = $this->Get('oql');
$sMessage = null;
try {
try
{
$oSearch = DBObjectSearch::FromOQL($sOql);
$aParameters = $oSearch->GetQueryParams();
foreach ($aParameters as $sParam => $val) {
foreach($aParameters as $sParam => $val)
{
$sUrl .= '&arg_'.$sParam.'=["'.$sParam.'"]';
}
$oTextArea = new TextArea("", $sUrl, null, 80, 3);
$oFieldUrl = FieldUIBlockFactory::MakeFromObject(Dict::S('UI:Query:UrlForExcel'), $oTextArea, Field::ENUM_FIELD_LAYOUT_LARGE);
$oPage->AddSubBlock($oFieldUrl);
$oPage->p(Dict::S('UI:Query:UrlForExcel').':<br/><textarea cols="80" rows="3" READONLY>'.$sUrl.'</textarea>');
if (count($aParameters) == 0) {
if (count($aParameters) == 0)
{
$oBlock = new DisplayBlock($oSearch, 'list');
$aExtraParams = array(
//'menu' => $sShowMenu,
@@ -166,13 +130,10 @@ class QueryOQL extends Query
$oBlock->Display($oPage, $sBlockId, $aExtraParams);
}
}
catch
(OQLException $e) {
$oAlert = AlertUIBlockFactory::MakeForFailure(Dict::Format('UI:RunQuery:Error'), $e->getHtmlDesc())
->SetIsClosable(false)
->SetIsCollapsible(false);
$oAlert->AddCSSClass('mb-5');
$oPage->AddSubBlock($oAlert);
catch (OQLException $e)
{
$sMessage = '<div class="message message_error" style="padding-left: 30px;"><div style="padding: 10px;">'.Dict::Format('UI:RunQuery:Error', $e->getHtmlDesc()).'</div></div>';
$oPage->p($sMessage);
}
}
return $aFieldsMap;

View File

@@ -1,5 +1,5 @@
<?php
// Copyright (C) 2010-2021 Combodo SARL
// Copyright (C) 2010-2016 Combodo SARL
//
// This file is part of iTop.
//
@@ -15,14 +15,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\Base\Component\DataTable\DataTableSettings;
/**
* Persistent class Shortcut and derived
* Shortcuts of any kind
*
* @copyright Copyright (C) 2010-2021 Combodo SARL
* @copyright Copyright (C) 2010-2016 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
@@ -40,6 +39,7 @@ 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();
@@ -101,7 +101,7 @@ function ShortcutRenameOK()
});
}
$('#shortcut_rename_dlg form').on('submit', function() { return false; });
$('#shortcut_rename_dlg form').bind('submit', function() { return false; });
$('#shortcut_rename_dlg').dialog({
width: 400,
@@ -161,6 +161,7 @@ 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();
@@ -286,10 +287,10 @@ class ShortcutOQL extends Shortcut
$sRateTitle = addslashes(Dict::Format('Class:ShortcutOQL/Attribute:auto_reload_sec/tip', MetaModel::GetConfig()->Get('min_reload_interval')));
$oPage->add_ready_script(
<<<JS
<<<EOF
// Note: the title gets deleted by the validation mechanism
$("#attr_auto_reload_sec").attr('data-tooltip-content', '$sRateTitle');
CombodoTooltip.InitTooltipFromMarkup($("#attr_auto_reload_sec"));
$("#attr_auto_reload_sec").tooltip({items: 'input', content: '$sRateTitle'});
$("#attr_auto_reload_sec").prop('disabled', !$('#attr_auto_reload').is(':checked'));
$('#attr_auto_reload').change( function(ev) {
@@ -315,30 +316,23 @@ function ShortcutCreationOK()
});
}
$('#shortcut_creation_dlg form').on('submit', function() { ShortcutCreationOK(); return false; });
$('#shortcut_creation_dlg form').bind('submit', function() { ShortcutCreationOK(); return false; });
$('#shortcut_creation_dlg').dialog({
width: 400,
modal: true,
title: '$sDialogTitle',
buttons: [
{
text: "$sCancelButtonLabel",
class: "ibo-is-alternative",
click: function() {
$(this).dialog( "close" );
$(this).remove();
}
},
{
text: "$sOkButtonLabel",
class: "ibo-is-primary",
click: ShortcutCreationOK
},
{ text: "$sOkButtonLabel", click: ShortcutCreationOK },
{ text: "$sCancelButtonLabel", click: function() {
$(this).dialog( "close" ); $(this).remove();
} },
],
close: function() { $(this).remove(); }
});
JS
EOF
);
}
}
?>

View File

@@ -1,5 +1,5 @@
<?php
// Copyright (C) 2010-2021 Combodo SARL
// Copyright (C) 2010-2016 Combodo SARL
//
// This file is part of iTop.
//
@@ -15,24 +15,18 @@
//
// 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\Helper\Session;
require_once(APPROOT.'/core/cmdbobject.class.inc.php');
require_once(APPROOT.'/application/utils.inc.php');
require_once(APPROOT.'/core/contexttag.class.inc.php');
require_once(APPROOT.'/core/kpi.class.inc.php');
/**
* File to include to initialize the datamodel in memory
*
* @copyright Copyright (C) 2010-2021 Combodo SARL
* @copyright Copyright (C) 2010-2019 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
ExecutionKPI::EnableDuration(1);
ExecutionKPI::EnableMemory(1);
// This storage is freed on error (case of allowed memory exhausted)
$sReservedMemory = str_repeat('*', 1024 * 1024);
register_shutdown_function(function()
@@ -64,15 +58,14 @@ register_shutdown_function(function()
}
}
});
$oKPI = new ExecutionKPI();
Session::Start();
$oKPI->ComputeAndReport("Session Start");
session_name('itop-'.md5(APPROOT));
session_start();
$sSwitchEnv = utils::ReadParam('switch_env', null);
$bAllowCache = true;
if (($sSwitchEnv != null) && file_exists(APPCONF.$sSwitchEnv.'/'.ITOP_CONFIG_FILE) &&( Session::Get('itop_env') !== $sSwitchEnv))
if (($sSwitchEnv != null) && (file_exists(APPCONF.$sSwitchEnv.'/'.ITOP_CONFIG_FILE)) && isset($_SESSION['itop_env']) && ($_SESSION['itop_env'] !== $sSwitchEnv))
{
Session::Set('itop_env', $sSwitchEnv);
$_SESSION['itop_env'] = $sSwitchEnv;
$sEnv = $sSwitchEnv;
$bAllowCache = false;
// Reset the opcache since otherwise the PHP "model" files may still be cached !!
@@ -88,14 +81,20 @@ if (($sSwitchEnv != null) && file_exists(APPCONF.$sSwitchEnv.'/'.ITOP_CONFIG_FIL
}
// TODO: reset the credentials as well ??
}
else if (Session::IsSet('itop_env'))
else if (isset($_SESSION['itop_env']))
{
$sEnv = Session::Get('itop_env');
$sEnv = $_SESSION['itop_env'];
}
else
{
$sEnv = ITOP_DEFAULT_ENV;
Session::Set('itop_env', ITOP_DEFAULT_ENV);
$_SESSION['itop_env'] = ITOP_DEFAULT_ENV;
}
$sConfigFile = APPCONF.$sEnv.'/'.ITOP_CONFIG_FILE;
MetaModel::Startup($sConfigFile, false /* $bModelOnly */, $bAllowCache, false /* $bTraceSourceFiles */, $sEnv);
try {
MetaModel::Startup($sConfigFile, false /* $bModelOnly */, $bAllowCache, false /* $bTraceSourceFiles */, $sEnv);
}
catch (MySQLException $e) {
IssueLog::Debug($e->getMessage());
throw new MySQLException('Could not connect to the DB server', []);
}

View File

@@ -1,6 +1,6 @@
<?php
/**
* Copyright (C) 2013-2021 Combodo SARL
* Copyright (C) 2013-2020 Combodo SARL
*
* This file is part of iTop.
*
@@ -20,8 +20,6 @@
require_once(APPROOT.'/application/displayblock.class.inc.php');
/**
* This class manages the special template format used internally to build the iTop web pages
*
* @deprecated 3.0.0
*/
class DisplayTemplate
{
@@ -31,15 +29,14 @@ class DisplayTemplate
public function __construct($sTemplate)
{
DeprecatedCallsLog::NotifyDeprecatedPhpMethod();
$this->m_aTags = array(
$this->m_aTags = array (
'itopblock',
'itopcheck',
'itoptabs',
'itoptab',
'itoptoggle',
'itopstring',
'sqlblock',
'sqlblock'
);
$this->m_sTemplate = $sTemplate;
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,35 +0,0 @@
<?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
*/
/**
* Class ThemeHandlerService : used to ease testing MFCompiler::CompileThemes class via mocks
*
* @author Olivier DAIN <olivier.dain@combodo.com>
* @since 3.0.0 N°2982
*/
class ThemeHandlerService
{
public function __construct()
{
}
public function CompileTheme($sThemeId, $bSetup = false, $sSetupCompilationTimestamp = "", $aThemeParameters = null, $aImportsPaths = null, $sWorkingPath = null){
return ThemeHandler::CompileTheme($sThemeId, $bSetup, $sSetupCompilationTimestamp, $aThemeParameters, $aImportsPaths, $sWorkingPath);
}
}

View File

@@ -1,5 +1,5 @@
<?php
// Copyright (C) 2010-2021 Combodo SARL
// Copyright (C) 2010-2015 Combodo SARL
//
// This file is part of iTop.
//
@@ -15,7 +15,6 @@
//
// 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\Helper\Session;
/**
* This class records the pending "transactions" corresponding to forms that have not been
@@ -24,7 +23,7 @@ use Combodo\iTop\Application\Helper\Session;
* which choice is configured via the parameter 'transaction_storage'
*
* @package iTop
* @copyright Copyright (C) 2010-2021 Combodo SARL
* @copyright Copyright (C) 2010-2012 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
class privUITransaction
@@ -102,8 +101,6 @@ class privUITransaction
*
* Warning, since 2.6.0 the session is regenerated on each login (see PR #20) !
* Also, we saw some problems when using memcached as the PHP session implementation (see N°1835)
*
* @see \Combodo\iTop\Application\Helper\Session
*/
class privUITransactionSession
{
@@ -114,15 +111,15 @@ class privUITransactionSession
*/
public static function GetNewTransactionId()
{
if (!Session::IsSet('transactions'))
if (!isset($_SESSION['transactions']))
{
Session::Set('transactions', []);
$_SESSION['transactions'] = array();
}
// Strictly speaking, the two lines below should be grouped together
// by a critical section
// sem_acquire($rSemIdentified);
$id = static::GetUserPrefix() . str_replace(array('.', ' '), '', microtime());
Session::Set(['transactions', $id], true);
$id = static::GetUserPrefix() . str_replace(array('.', ' '), '', microtime()); //1 + count($_SESSION['transactions']);
$_SESSION['transactions'][$id] = true;
// sem_release($rSemIdentified);
return (string)$id;
@@ -139,17 +136,17 @@ class privUITransactionSession
public static function IsTransactionValid($id, $bRemoveTransaction = true)
{
$bResult = false;
if (Session::IsSet('transactions'))
if (isset($_SESSION['transactions']))
{
// Strictly speaking, the eight lines below should be grouped together
// inside the same critical section as above
// sem_acquire($rSemIdentified);
if (Session::IsSet(['transactions', $id]))
if (isset($_SESSION['transactions'][$id]))
{
$bResult = true;
if ($bRemoveTransaction)
{
Session::Unset(['transactions', $id]);
unset($_SESSION['transactions'][$id]);
}
}
// sem_release($rSemIdentified);
@@ -164,14 +161,14 @@ class privUITransactionSession
*/
public static function RemoveTransaction($id)
{
if (Session::IsSet('transactions'))
if (isset($_SESSION['transactions']))
{
// Strictly speaking, the three lines below should be grouped together
// inside the same critical section as above
// sem_acquire($rSemIdentified);
if (Session::IsSet(['transactions', $id]))
if (isset($_SESSION['transactions'][$id]))
{
Session::Unset(['transactions', $id]);
unset($_SESSION['transactions'][$id]);
}
// sem_release($rSemIdentified);
}

View File

@@ -2,7 +2,6 @@
namespace Combodo\iTop;
use AttributeDate;
use AttributeDateTime;
use Dict;
use Exception;
@@ -11,13 +10,6 @@ use Twig_SimpleFilter;
use Twig_SimpleFunction;
use utils;
/**
* Class TwigExtension
*
* @author Guillaume Lajarige <guillaume.lajarige@combodo.com>
* @package Combodo\iTop
* @deprecated 3.1.0 N°4034
*/
class TwigExtension
{
/**
@@ -55,10 +47,6 @@ class TwigExtension
{
return AttributeDateTime::GetFormat()->Format($sDate);
}
if (preg_match('@^\d\d\d\d-\d\d-\d\d$@', trim($sDate)))
{
return AttributeDate::GetFormat()->Format($sDate);
}
}
catch (Exception $e)
{
@@ -91,14 +79,30 @@ class TwigExtension
// Filter to add itopversion to an url
$oTwigEnv->addFilter(new Twig_SimpleFilter('add_itop_version', function ($sUrl) {
$sUrl = utils::AddParameterToUrl($sUrl, 'itopversion', ITOP_VERSION);
if (strpos($sUrl, '?') === false)
{
$sUrl = $sUrl."?itopversion=".ITOP_VERSION;
}
else
{
$sUrl = $sUrl."&itopversion=".ITOP_VERSION;
}
return $sUrl;
}));
// Filter to add a module's version to an url
$oTwigEnv->addFilter(new Twig_SimpleFilter('add_module_version', function ($sUrl, $sModuleName) {
$sModuleVersion = utils::GetCompiledModuleVersion($sModuleName);
$sUrl = utils::AddParameterToUrl($sUrl, 'moduleversion', $sModuleVersion);
if (strpos($sUrl, '?') === false)
{
$sUrl = $sUrl."?moduleversion=".$sModuleVersion;
}
else
{
$sUrl = $sUrl."&moduleversion=".$sModuleVersion;
}
return $sUrl;
}));
@@ -124,5 +128,4 @@ class TwigExtension
return utils::GetAbsoluteUrlModulePage($sModuleName, $sPage);
}));
}
}

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