mirror of
https://github.com/Combodo/iTop.git
synced 2026-05-01 14:38:47 +02:00
Compare commits
175 Commits
form-sdk-p
...
support/3.
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8f2c990065 | ||
|
|
03437c3453 | ||
|
|
33a51b47bf | ||
|
|
e768cc1c0c | ||
|
|
f6741a6306 | ||
|
|
1ec8aca12d | ||
|
|
39011faedd | ||
|
|
46f8f5faeb | ||
|
|
170d24d0ad | ||
|
|
89231976f8 | ||
|
|
f0a95cbb3d | ||
|
|
30f720b9ad | ||
|
|
87dd003a6d | ||
|
|
7201bef8db | ||
|
|
af01ff9e62 | ||
|
|
ab1290dfd0 | ||
|
|
68d14c4de6 | ||
|
|
a96e1c286d | ||
|
|
b799be3cb7 | ||
|
|
d000d93b19 | ||
|
|
9f25635a64 | ||
|
|
6bd34dc73e | ||
|
|
9dc3c56689 | ||
|
|
effd35c3e6 | ||
|
|
f1735767c3 | ||
|
|
00735f0c54 | ||
|
|
882390e8d6 | ||
|
|
5d0da47f21 | ||
|
|
4eadff7f3b | ||
|
|
f66ce1c956 | ||
|
|
802f9f3e08 | ||
|
|
5c5d98bb78 | ||
|
|
a08a9b43f3 | ||
|
|
abd85ff4db | ||
|
|
81f328b26e | ||
|
|
9a2c8f10bf | ||
|
|
3cdadf3c6e | ||
|
|
a6295f1b14 | ||
|
|
e467ca83cf | ||
|
|
7791585387 | ||
|
|
3406ca79de | ||
|
|
91ad01055e | ||
|
|
804cdffe42 | ||
|
|
5f4affc896 | ||
|
|
042fee2360 | ||
|
|
7f8ec25977 | ||
|
|
41f8437c23 | ||
|
|
df8b25d4b4 | ||
|
|
511dabe2b0 | ||
|
|
0c517f254c | ||
|
|
c56c7a1f9d | ||
|
|
fb2f0f1447 | ||
|
|
b3223eb9b6 | ||
|
|
458a996c29 | ||
|
|
c61b21559c | ||
|
|
ed33238750 | ||
|
|
272678b8cd | ||
|
|
170014e8f0 | ||
|
|
006f666089 | ||
|
|
2a16143e53 | ||
|
|
eabbe2f00b | ||
|
|
58790bc352 | ||
|
|
28db230697 | ||
|
|
4fe61cbdc7 | ||
|
|
e2994b645b | ||
|
|
9fca81cc32 | ||
|
|
9792358aea | ||
|
|
7bfa14a874 | ||
|
|
9236449b21 | ||
|
|
ab8e7bd15e | ||
|
|
307c308eb0 | ||
|
|
61e5536b50 | ||
|
|
104dd1970f | ||
|
|
929b8b9eca | ||
|
|
3b8e079cf1 | ||
|
|
fc967c06ce | ||
|
|
d4821b7edc | ||
|
|
62e09f1224 | ||
|
|
f82389d156 | ||
|
|
f558093f5d | ||
|
|
5201a1ed3b | ||
|
|
29920bfeb7 | ||
|
|
aede5ea7b8 | ||
|
|
da6c443a35 | ||
|
|
9c39efd9af | ||
|
|
d5f2303ed2 | ||
|
|
48e584503e | ||
|
|
454a1b26eb | ||
|
|
330539abd2 | ||
|
|
5357a0c060 | ||
|
|
fc22cce037 | ||
|
|
34c8a57814 | ||
|
|
2247691e58 | ||
|
|
076d49abc2 | ||
|
|
9fd0ffd84e | ||
|
|
d2f67dcb3c | ||
|
|
d5706fcbef | ||
|
|
807f2a88bc | ||
|
|
9d3311e623 | ||
|
|
9bf2cb7e1d | ||
|
|
54909520e9 | ||
|
|
d124f8ee58 | ||
|
|
3b62597092 | ||
|
|
c0a2771d4e | ||
|
|
6bd5a7b634 | ||
|
|
82b7ef86c7 | ||
|
|
4f878536a8 | ||
|
|
d937ec0350 | ||
|
|
985db46960 | ||
|
|
01adaadfad | ||
|
|
643752f8e7 | ||
|
|
0e0c09c420 | ||
|
|
f34373be6d | ||
|
|
4dba47798c | ||
|
|
49a7f3118d | ||
|
|
09afcb229c | ||
|
|
3df4ddc696 | ||
|
|
1fe401c102 | ||
|
|
6cb08ba361 | ||
|
|
f9db405343 | ||
|
|
4f1f144c51 | ||
|
|
ef8ade5d20 | ||
|
|
0b242d872a | ||
|
|
d9261b8342 | ||
|
|
4187f552a9 | ||
|
|
7f7ce0837e | ||
|
|
fd10887849 | ||
|
|
7df09541ac | ||
|
|
6d5660ca67 | ||
|
|
0013b8cfee | ||
|
|
7fb0ae48f9 | ||
|
|
e89a8edae0 | ||
|
|
5b7a5e14a3 | ||
|
|
2b1ecf15b4 | ||
|
|
f6366057c9 | ||
|
|
67018b9b17 | ||
|
|
8597dea398 | ||
|
|
a6972af266 | ||
|
|
066b27c982 | ||
|
|
283de1ef7c | ||
|
|
8b00016115 | ||
|
|
b5c79e1d75 | ||
|
|
80d4e65a81 | ||
|
|
4a9a85458d | ||
|
|
890a2568c8 | ||
|
|
12f23113f5 | ||
|
|
26f21ee6eb | ||
|
|
adfa800063 | ||
|
|
5df936c587 | ||
|
|
8056a63e82 | ||
|
|
4f845c63cf | ||
|
|
6226ac8746 | ||
|
|
e661e0bdbb | ||
|
|
1d52665012 | ||
|
|
4aa0c19183 | ||
|
|
809d4cd665 | ||
|
|
0c3bc7f35b | ||
|
|
778c16da86 | ||
|
|
5045ec4afa | ||
|
|
88e0f17164 | ||
|
|
de54676b9f | ||
|
|
e5129c9618 | ||
|
|
d0f816109b | ||
|
|
05642cdf84 | ||
|
|
031305cfbf | ||
|
|
471422b274 | ||
|
|
5573a222c8 | ||
|
|
83eb2b81e3 | ||
|
|
86d2a3424d | ||
|
|
cd1c6f5ec5 | ||
|
|
2ee30692ff | ||
|
|
9aa13f57d8 | ||
|
|
f9d9fcc440 | ||
|
|
a4a05a2579 | ||
|
|
f44468b7a1 |
111
.doc/itop-version-history.md
Normal file
111
.doc/itop-version-history.md
Normal file
@@ -0,0 +1,111 @@
|
||||
# iTop version history
|
||||
|
||||
```mermaid
|
||||
%%{init: { 'logLevel': 'debug', 'theme': 'base', 'themeVariables': {
|
||||
'git0': 'lawngreen',
|
||||
'git3': 'dodgerblue',
|
||||
'git4': 'grey',
|
||||
'git5': 'grey',
|
||||
'git6': 'grey',
|
||||
'git7': 'grey',
|
||||
'git8': 'grey'
|
||||
}, 'gitGraph': {'showBranches': true,'mainBranchName': 'develop','rotateCommitLabel': true}} }%%
|
||||
gitGraph
|
||||
commit id: "2016-07-06" tag: "2.3.0" type: HIGHLIGHT
|
||||
branch support/2.3 order: 900
|
||||
commit id: "2016-07-08" tag: "2.3.1"
|
||||
commit id: "2016-12-22" tag: "2.3.3"
|
||||
commit id: "2017-04-14" tag: "2.3.4"
|
||||
checkout develop
|
||||
commit id: "2017-07-12" tag: "2.4.0-beta" type: REVERSE
|
||||
commit id: "2017-11-16" tag: "2.4.0" type: HIGHLIGHT
|
||||
branch support/2.4 order: 890
|
||||
commit id: "2018-02-14" tag: "2.4.1"
|
||||
checkout develop
|
||||
commit id: "2018-04-25" tag: "2.5.0-beta" type: REVERSE
|
||||
checkout support/2.4
|
||||
commit id: "2018-06-14" tag: "2.4.2"
|
||||
checkout develop
|
||||
commit id: "2018-06-27" tag: "2.5.0" type: HIGHLIGHT
|
||||
branch support/2.5 order: 880
|
||||
checkout develop
|
||||
commit id: "2019-01-09" tag: "2.6.0" type: HIGHLIGHT
|
||||
branch support/2.6 order: 870
|
||||
commit id: "2019-03-28" tag: "2.6.1"
|
||||
checkout develop
|
||||
commit id: "2019-12-18" tag: "2.7.0-beta" type: REVERSE
|
||||
checkout support/2.5
|
||||
commit id: "2020-01-22" tag: "2.5.4"
|
||||
checkout support/2.6
|
||||
commit id: "2020-01-23" tag: "2.6.3"
|
||||
checkout develop
|
||||
commit id: "2020-01-29" tag: "2.7.0-beta2" type: REVERSE
|
||||
commit id: "2020-04-01" tag: "2.7.0-1" type: HIGHLIGHT
|
||||
checkout support/2.6
|
||||
commit id: "2020-04-22" tag: "2.6.4"
|
||||
checkout develop
|
||||
branch support/2.7 order: 860
|
||||
commit id: "2020-06-26" tag: "2.7.1"
|
||||
checkout support/2.7
|
||||
commit id: "2020-12-09" tag: "2.7.3"
|
||||
commit id: "2021-03-31" tag: "2.7.4"
|
||||
checkout develop
|
||||
commit id: "2021-04-06" tag: "3.0.0-beta" type: REVERSE
|
||||
checkout support/2.7
|
||||
commit id: "2021-07-05" tag: "2.7.5"
|
||||
checkout develop
|
||||
commit id: "2021-07-05." tag: "3.0.0-beta2" type: REVERSE
|
||||
checkout support/2.7
|
||||
commit id: "2021-12-17" tag: "2.7.6"
|
||||
checkout develop
|
||||
commit id: "2022-01-04" tag: "3.0.0" type: HIGHLIGHT
|
||||
branch support/3.0 order: 850
|
||||
commit id: "2022-04-08" tag: "3.0.1"
|
||||
checkout support/2.7
|
||||
commit id: "2022-07-11" tag: "2.7.7"
|
||||
checkout support/3.0
|
||||
commit id: "2022-09-12" tag: "3.0.2-1"
|
||||
checkout develop
|
||||
checkout support/2.7
|
||||
commit id: "2022-12-28" tag: "2.7.8"
|
||||
checkout support/3.0
|
||||
commit id: "2023-04-12" tag: "3.0.3"
|
||||
checkout develop
|
||||
commit id: "2023-06-19" tag: "3.1.0-beta" type: REVERSE
|
||||
commit id: "2023-07-26" tag: "3.1.0-1" type: HIGHLIGHT
|
||||
branch support/3.1 order: 840
|
||||
checkout support/3.1
|
||||
commit id: "2023-08-09" tag: "3.1.0-2"
|
||||
checkout support/2.7
|
||||
commit id: "2023-08-10" tag: "2.7.9"
|
||||
checkout support/3.1
|
||||
commit id: "2023-12-20" tag: "3.1.1"
|
||||
checkout develop
|
||||
commit id: "2024-01-15" tag: "Start 3.2" type: HIGHLIGHT
|
||||
branch support/3.2 order: 830
|
||||
checkout support/2.7
|
||||
commit id: "2024-01-17a" tag: "2.7.10"
|
||||
checkout support/3.0
|
||||
commit id: "2024-01-17b" tag: "3.0.4"
|
||||
checkout support/2.7
|
||||
commit id: "2024-09-28" tag: "2.7.11"
|
||||
checkout support/3.1
|
||||
commit id: "2024-09-27" tag: "3.1.2"
|
||||
checkout support/3.2
|
||||
commit id: "2024-06-25" tag: "3.2.0-beta1" type: REVERSE
|
||||
commit id: "2024-08-07" tag: "3.2.0"
|
||||
checkout support/2.7
|
||||
commit id: "2025-02-07a" tag: "2.7.12"
|
||||
checkout support/3.1
|
||||
commit id: "2025-02-07b" tag: "3.1.3"
|
||||
checkout support/3.2
|
||||
commit id: "2025-02-07c " tag: "3.2.1"
|
||||
commit id: "2025-03-31 " tag: "3.2.1-1"
|
||||
commit id: "2025-07-28 " tag: "3.2.2"
|
||||
checkout support/2.7
|
||||
commit id: "2025-09-25" tag: "2.7.13"
|
||||
checkout support/3.2
|
||||
commit id: "2026-04-27 " tag: "3.2.3"
|
||||
```
|
||||
|
||||
To learn more, check the [iTop community versions history on the official wiki](https://www.itophub.io/wiki/page?id=latest:release:start).
|
||||
59
.github/ISSUE_TEMPLATE/bug.yml
vendored
Normal file
59
.github/ISSUE_TEMPLATE/bug.yml
vendored
Normal file
@@ -0,0 +1,59 @@
|
||||
name: "Bug report"
|
||||
description: "Report a bug that you identified in iTop, with the steps to reproduce it and the expected vs actual behavior. If you have an improvement proposition, please use the 'Enhancement suggestion' template instead."
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
Please explain why you're creating this issue :
|
||||
- Are you willing to create a PR for the bug fix ? If so, we'll indicate in the issue if we're interested in it.
|
||||
- Then, please describe how to reproduce the issue.
|
||||
|
||||
- type: dropdown
|
||||
id: willing_to_pr
|
||||
attributes:
|
||||
label: Are you willing to create (at a later stage) a PR for that?
|
||||
options:
|
||||
- Yes
|
||||
- No
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: input
|
||||
id: itop_version
|
||||
attributes:
|
||||
label: iTop version
|
||||
description: "Complete iTop version (e.g., 3.2.3)"
|
||||
validations:
|
||||
required: false
|
||||
|
||||
- type: input
|
||||
id: php_version
|
||||
attributes:
|
||||
label: PHP version
|
||||
description: "Complete PHP version (e.g., 8.4.20)"
|
||||
validations:
|
||||
required: false
|
||||
|
||||
- type: textarea
|
||||
id: reproduction_steps
|
||||
attributes:
|
||||
label: Reproduction procedure
|
||||
description: |
|
||||
Please 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.
|
||||
placeholder: |
|
||||
1. First go there
|
||||
2. Then do that
|
||||
3. ...
|
||||
4. Finally, see that... (what is expected and what is actually happening)
|
||||
validations:
|
||||
required: false
|
||||
|
||||
- type: upload
|
||||
id: additional_info
|
||||
attributes:
|
||||
label: Additional information (if needed)
|
||||
description: "Add/drag and drop screenshots, logs or any files that can be relevant for your issue."
|
||||
validations:
|
||||
required: false
|
||||
accept: ".png, .jpg, .jpeg, .gif, .webp, .log, .txt, .json, .csv, .xml, .zip, .tar.gz"
|
||||
54
.github/ISSUE_TEMPLATE/enhancement.yml
vendored
Normal file
54
.github/ISSUE_TEMPLATE/enhancement.yml
vendored
Normal file
@@ -0,0 +1,54 @@
|
||||
name: "Enhancement suggestion"
|
||||
description: "Suggest an improvement to iTop, with a clear description of the expected behavior and the benefits it would bring. If you identified a bug and have an improvement proposition, please use the 'Bug report' template instead."
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
Please explain why you're creating this issue :
|
||||
- Are you willing to create a PR for this enhancement ? If so, we'll indicate in the issue if we're interested in it.
|
||||
- Then, please describe what's your improvement proposition.
|
||||
|
||||
- type: dropdown
|
||||
id: willing_to_pr
|
||||
attributes:
|
||||
label: Are you willing to create (at a later stage) a PR for that?
|
||||
options:
|
||||
- Yes
|
||||
- No
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: input
|
||||
id: itop_version
|
||||
attributes:
|
||||
label: iTop version
|
||||
description: "Complete iTop version (e.g., 3.2.3)"
|
||||
validations:
|
||||
required: false
|
||||
|
||||
- type: input
|
||||
id: php_version
|
||||
attributes:
|
||||
label: PHP version
|
||||
description: "Complete PHP version (e.g., 8.4.20)"
|
||||
validations:
|
||||
required: false
|
||||
|
||||
- type: textarea
|
||||
id: enhancement_details
|
||||
attributes:
|
||||
label: Enhancement details
|
||||
description: |
|
||||
Please explain what you want to improve, and your proposition to make it better.
|
||||
If it requires a custom datamodel, provide the minimal XML delta to reproduce it.
|
||||
validations:
|
||||
required: false
|
||||
|
||||
- type: upload
|
||||
id: additional_info
|
||||
attributes:
|
||||
label: Additional information (if needed)
|
||||
description: "Add/drag and drop screenshots, logs or any files that can be relevant for your issue."
|
||||
validations:
|
||||
required: false
|
||||
accept: ".png, .jpg, .jpeg, .gif, .webp, .log, .txt, .json, .csv, .xml, .zip, .tar.gz"
|
||||
61
.github/pull_request_template.md
vendored
61
.github/pull_request_template.md
vendored
@@ -1,83 +1,76 @@
|
||||
<!--
|
||||
IMPORTANT: Before creating your PR, please create an issue first to know if Combodo is interested in your contribution (not needed for translations PR).
|
||||
Since we may refuse a PR, it's preferable to create an issue first, to avoid spending time coding something that won't be accepted.
|
||||
|
||||
IMPORTANT: Please follow the guidelines within this PR template before submitting it, it will greatly help us process your PR. 🙏
|
||||
Once you've done it, and we confirmed we're interested in it, 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
|
||||
|
||||
| Question | Answer |
|
||||
|---------------------------------------------------------------------------------|--------------------------------------|
|
||||
| Related to a SourceForge thread / Another PR / A GitHub Issue / 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.
|
||||
- Describe what is blocking you, what is the objective with as many 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.
|
||||
|
||||
Please 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...
|
||||
3. First go there
|
||||
4. Then do that
|
||||
5. ...
|
||||
6. Finally, see that... (what is expected and what is actually happening)
|
||||
|
||||
## Reproduction procedure (enhancement - if needed)
|
||||
|
||||
<!--
|
||||
Please explain how we can reproduce the feature/behavior you want to improve, and what's your proposition to make it better.
|
||||
Add screenshots if it's related to UI.
|
||||
If it requires a custom datamodel, provide the minimal XML delta to reproduce it on a standard iTop Community.
|
||||
-->
|
||||
|
||||
## 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
|
||||
- ...
|
||||
-->
|
||||
|
||||
- [ ] ...
|
||||
- [ ] ...
|
||||
- [ ] ...
|
||||
- [ ] Is the PR clear and detailed enough so anyone can understand without digging in the code?
|
||||
14
.github/workflows/action.yml
vendored
14
.github/workflows/action.yml
vendored
@@ -26,13 +26,23 @@ jobs:
|
||||
|
||||
fi
|
||||
|
||||
- name: Add internal tag if member
|
||||
- name: Add internal tag if member of the organization
|
||||
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"]}'
|
||||
|
||||
- name: Set PR author as assignee if member of the organization
|
||||
if: env.is_member == 'true'
|
||||
run: |
|
||||
curl -L \
|
||||
-X POST \
|
||||
-H "Accept: application/vnd.github+json" \
|
||||
-H "Authorization: Bearer ${{ secrets.PR_AUTOMATICALLY_ADD_TO_PROJECT }}" \
|
||||
https://api.github.com/repos/Combodo/iTop/issues/${{ github.event.pull_request.number }}/assignees \
|
||||
-d '{"assignees":["${{ github.event.pull_request.user.login }}"]}'
|
||||
env:
|
||||
is_member: ${{ env.is_member }}
|
||||
|
||||
@@ -40,4 +50,4 @@ jobs:
|
||||
uses: actions/add-to-project@v1.0.2
|
||||
with:
|
||||
project-url: ${{ env.project_url }}
|
||||
github-token: ${{ secrets.PR_AUTOMATICALLY_ADD_TO_PROJECT }}
|
||||
github-token: ${{ secrets.PR_AUTOMATICALLY_ADD_TO_PROJECT }}
|
||||
|
||||
3
.gitignore
vendored
3
.gitignore
vendored
@@ -58,6 +58,9 @@ tests/*/vendor/*
|
||||
/tests/php-unit-tests/phpunit.xml
|
||||
/tests/php-unit-tests/postbuild_integration.xml
|
||||
|
||||
# PHP CS Fixer: Cache file
|
||||
/.php-cs-fixer.cache
|
||||
|
||||
|
||||
# Jetbrains
|
||||
/.idea/**
|
||||
|
||||
@@ -199,7 +199,7 @@ class DatamodelsXmlFiles extends AbstractGlobFileVersionUpdater
|
||||
libxml_clear_errors();
|
||||
$oFileXml->formatOutput = true;
|
||||
$oFileXml->preserveWhiteSpace = false;
|
||||
$oFileXml->loadXML($sFileContent);
|
||||
$oFileXml->loadXML($sFileContent, LIBXML_BIGLINES);
|
||||
|
||||
$oFileItopFormat = new iTopDesignFormat($oFileXml);
|
||||
|
||||
|
||||
@@ -4,30 +4,33 @@ You want to contribute to iTop? Many thanks to you! 🎉 👍
|
||||
|
||||
Here are some guidelines that will help us integrate your work!
|
||||
|
||||
|
||||
## Contributions
|
||||
|
||||
### Subjects
|
||||
|
||||
You are welcome to create pull requests on any of those subjects:
|
||||
|
||||
* 🐛 bug fix
|
||||
* 🌐 translation / i18n / l10n
|
||||
* 🚸 enhancement
|
||||
|
||||
If you want to implement a **new feature**, please [create a corresponding ticket](https://sourceforge.net/p/itop/tickets/new/) for review.
|
||||
If you ever want to begin implementation, do so in a fork, and add a link to the corresponding commits in the ticket.
|
||||
But before creating a PR, please [create a corresponding issue][itop-issues] for review.
|
||||
We should review within two weeks, and get back to you to indicate if we're interested in your proposal or not.
|
||||
If you don't create an issue, you won't know if we're interested in your contribution, and you may spend time coding something that won't be accepted.
|
||||
If you ever want to begin implementation, do so in a fork, and add a link to the corresponding commits in the issue.
|
||||
|
||||
For all **security related subjects**, please see our [security policy](SECURITY.md).
|
||||
|
||||
All **datamodel modification** should be done in an extension. Beware that such change would
|
||||
impact all existing customers, and could prevent them from
|
||||
upgrading!
|
||||
Combodo has a long experience of datamodel changes: they are very disruptive!
|
||||
All **datamodel modification** should be done in an extension. Beware that such change would
|
||||
impact all existing customers, and could prevent them from upgrading!
|
||||
Combodo has a long experience of datamodel changes: they are very disruptive!
|
||||
This is why we avoid them in iTop core, especially the changes on existing objects/fields.
|
||||
If you have an idea you're sure would benefit to all of iTop users, you may
|
||||
[create a corresponding ticket](https://sourceforge.net/p/itop/tickets/new/) to submit it, but be warned that there are lots of good
|
||||
If you have an idea you're sure would benefit to all of iTop users, you may
|
||||
[create a corresponding issue][itop-issues] to submit it, but be warned that there are lots of good
|
||||
reasons to refuse such changes.
|
||||
|
||||
### 📄 License and copyright
|
||||
|
||||
iTop is distributed under the AGPL-3.0 license (see the [license.txt] file).
|
||||
|
||||
The iTop repository is divided in three parts: iTop (mainly PHP/JS/XML sources and dictionaries), images, and third-party libraries.
|
||||
@@ -37,48 +40,33 @@ Anyhow, you are encouraged to signal your contribution by the mean of `@author`
|
||||
If you want to use another license or keep the code ownership (copyright), you may [create an extension][wiki new ext].
|
||||
|
||||
[license.txt]: https://github.com/Combodo/iTop/blob/develop/license.txt
|
||||
[wiki new ext]: https://www.itophub.io/wiki/page?id=latest%3Acustomization%3Astart#by_writing_your_own_extension
|
||||
|
||||
[itop-issues]: https://github.com/Combodo/iTop/issues
|
||||
|
||||
[wiki new ext]: https://www.itophub.io/wiki/page?id=latest%3Acustomization%3Astart#by_writing_your_own_extension
|
||||
|
||||
## 🔀 iTop branch model
|
||||
|
||||
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.
|
||||
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.
|
||||
|
||||
Here are the branches we use and their meaning :
|
||||
Here are the branches we use and their meaning :
|
||||
|
||||
- `develop`: ongoing development version
|
||||
- `release/*`: if present, that means we are working on a alpha/beta/rc version for shipping
|
||||
- `support/*`: maintenance branches for older versions
|
||||
|
||||
For example, if no version is currently prepared for shipping we could have:
|
||||
|
||||
- `develop` containing future 3.1.0 version
|
||||
- `support/3.0`: 3.0.x maintenance version
|
||||
- `support/2.7`: 2.7.x maintenance version
|
||||
- `support/2.6`: 2.6.x maintenance version
|
||||
- `develop` containing future 3.3.0 version
|
||||
- `support/3.2`: 3.2.x maintenance version
|
||||
|
||||
In this example, when 3.1.0-beta is shipped that will become:
|
||||
|
||||
- `develop`: future 3.2.0 version
|
||||
- `release/3.1.0`: 3.1.0-beta
|
||||
- `support/3.0`: 3.0.x maintenance version
|
||||
- `support/2.7`: 2.7.x maintenance version
|
||||
- `support/2.6`: 2.6.x maintenance version
|
||||
|
||||
And when 3.1.0 final will be out:
|
||||
|
||||
- `develop`: future 3.2.0 version
|
||||
- `support/3.1`: 3.1.x maintenance version (will host developments for 3.1.1)
|
||||
- `support/3.0`: 3.0.x maintenance version
|
||||
- `support/2.7`: 2.7.x maintenance version
|
||||
- `support/2.6`: 2.6.x maintenance version
|
||||
|
||||
Also note that we have a "micro-version" concept : each of those versions have a very small amount of modifications. They are made from
|
||||
`support/*` branches as well. For example 2.6.2-1 and 2.6.2-2 were made from the `support/2.6.2` branch.
|
||||
And when 3.3.0 will be out:
|
||||
|
||||
- `develop`: future 3.4.0 version
|
||||
- `support/3.3`: 3.3.x maintenance version (will host developments for 3.3.1)
|
||||
- `support/3.2`: 3.2.x maintenance version
|
||||
|
||||
## Coding
|
||||
|
||||
@@ -92,12 +80,11 @@ A [dedicated page](https://www.itophub.io/wiki/page?id=latest%3Acustomization%3A
|
||||
2. Create a branch in this fork, based on the develop branch
|
||||
3. Code !
|
||||
|
||||
Do create a dedicated branch for each modification you want to propose : if you don't it will be very hard to merge back your work !
|
||||
Do create a dedicated branch for each modification you want to propose : if you don't, it will be very hard to merge back your work !
|
||||
|
||||
Most of the time you should based your developments on the develop branch.
|
||||
Most of the time you should base your developments on the develop branch.
|
||||
That may be different if you want to fix a bug, please use develop anyway and ask in your PR if rebase is possible.
|
||||
|
||||
|
||||
### 🎨 PHP styleguide
|
||||
|
||||
Please follow [our guidelines](https://www.itophub.io/wiki/page?id=latest%3Acustomization%3Acoding_standards).
|
||||
@@ -106,7 +93,7 @@ Please follow [our guidelines](https://www.itophub.io/wiki/page?id=latest%3Acust
|
||||
|
||||
Please create tests that covers as much as possible the code you're submitting.
|
||||
|
||||
Our tests are located in the `test/` directory, containing a PHPUnit config file : `phpunit.xml.dist`.
|
||||
Our tests are located in the `tests/` directory, containing a PHPUnit config file : `phpunit.xml.dist`.
|
||||
|
||||
### Git Commit Messages
|
||||
|
||||
@@ -138,14 +125,14 @@ When your code is working, please:
|
||||
* Rebase your branch on our repo last commit,
|
||||
* Create a pull request. _Detailed procedure to work on fork and create PR is available [in GitHub help pages](https://help.github.com/articles/creating-a-pull-request-from-a-fork/)_.
|
||||
* Pull request description: mind to add all the information useful to understand why you're suggesting this modification and anything necessary to dive into your work. Especially:
|
||||
- Bugfixes: exact steps to reproduce the bug (given/when/then), description of the bug cause and what solution is implemented
|
||||
- Enhancements: use cases, implementation details if needed
|
||||
* Mind to check the "[Allow edits from maintainers](https://docs.github.com/en/github-ae@latest/pull-requests/collaborating-with-pull-requests/working-with-forks/allowing-changes-to-a-pull-request-branch-created-from-a-fork)" option ! (note that if you are working with an org fork, this option [won't be available](https://github.com/orgs/community/discussions/5634))
|
||||
|
||||
- Bugfixes: exact steps to reproduce the bug (given/when/then), description of the bug cause and what solution is implemented
|
||||
- Enhancements: use cases, implementation details if needed
|
||||
* Mind to check the "[Allow edits from maintainers](https://docs.github.com/en/github-ae@latest/pull-requests/collaborating-with-pull-requests/working-with-forks/allowing-changes-to-a-pull-request-branch-created-from-a-fork)" option ! (note that if you are working with an org fork, this
|
||||
option [won't be available](https://github.com/orgs/community/discussions/5634))
|
||||
|
||||
## 🙏 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!
|
||||
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!
|
||||
|
||||
We have one sticker per contribution type. You might get multiple stickers with one contribution though :)
|
||||
|
||||
@@ -157,8 +144,4 @@ We have one sticker per contribution type. You might get multiple stickers with
|
||||
* 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
|
||||
|
||||
Here is the design of each stickers for year 2024:
|
||||
|
||||

|
||||
* Extension developer: Develop and publish an extension
|
||||
@@ -1,9 +1,10 @@
|
||||
<?php
|
||||
|
||||
// Copyright (C) 2010-2024 Combodo SAS
|
||||
//
|
||||
// This file is part of iTop.
|
||||
//
|
||||
// iTop is free software; you can redistribute it and/or modify
|
||||
// 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.
|
||||
@@ -23,30 +24,29 @@
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
|
||||
class UserRightsMatrixClassGrant extends DBObject
|
||||
{
|
||||
public static function Init()
|
||||
{
|
||||
$aParams = array
|
||||
(
|
||||
$aParams =
|
||||
[
|
||||
"category" => "addon/userrights",
|
||||
"key_type" => "autoincrement",
|
||||
"name_attcode" => "",
|
||||
"state_attcode" => "",
|
||||
"reconc_keys" => array(),
|
||||
"reconc_keys" => [],
|
||||
"db_table" => "priv_ur_matrixclasses",
|
||||
"db_key_field" => "id",
|
||||
"db_finalclass_field" => "",
|
||||
);
|
||||
];
|
||||
MetaModel::Init_Params($aParams);
|
||||
//MetaModel::Init_InheritAttributes();
|
||||
MetaModel::Init_AddAttribute(new AttributeExternalKey("userid", array("targetclass"=>"User", "jointype"=> "", "allowed_values"=>null, "sql"=>"userid", "is_null_allowed"=>false, "on_target_delete"=>DEL_MANUAL, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeExternalField("login", array("allowed_values"=>null, "extkey_attcode"=> 'userid', "target_attcode"=>"login")));
|
||||
MetaModel::Init_AddAttribute(new AttributeString("class", array("allowed_values"=>null, "sql"=>"class", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeExternalKey("userid", ["targetclass" => "User", "jointype" => "", "allowed_values" => null, "sql" => "userid", "is_null_allowed" => false, "on_target_delete" => DEL_MANUAL, "depends_on" => []]));
|
||||
MetaModel::Init_AddAttribute(new AttributeExternalField("login", ["allowed_values" => null, "extkey_attcode" => 'userid', "target_attcode" => "login"]));
|
||||
MetaModel::Init_AddAttribute(new AttributeString("class", ["allowed_values" => null, "sql" => "class", "default_value" => null, "is_null_allowed" => false, "depends_on" => []]));
|
||||
|
||||
MetaModel::Init_AddAttribute(new AttributeString("action", array("allowed_values"=>null, "sql"=>"action", "default_value"=>"", "is_null_allowed"=>false, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeEnum("permission", array("allowed_values"=>new ValueSetEnum('yes,no'), "sql"=>"permission", "default_value"=>"yes", "is_null_allowed"=>false, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeString("action", ["allowed_values" => null, "sql" => "action", "default_value" => "", "is_null_allowed" => false, "depends_on" => []]));
|
||||
MetaModel::Init_AddAttribute(new AttributeEnum("permission", ["allowed_values" => new ValueSetEnum('yes,no'), "sql" => "permission", "default_value" => "yes", "is_null_allowed" => false, "depends_on" => []]));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -54,25 +54,25 @@ class UserRightsMatrixClassStimulusGrant extends DBObject
|
||||
{
|
||||
public static function Init()
|
||||
{
|
||||
$aParams = array
|
||||
(
|
||||
$aParams =
|
||||
[
|
||||
"category" => "addon/userrights",
|
||||
"key_type" => "autoincrement",
|
||||
"name_attcode" => "",
|
||||
"state_attcode" => "",
|
||||
"reconc_keys" => array(),
|
||||
"reconc_keys" => [],
|
||||
"db_table" => "priv_ur_matrixclassesstimulus",
|
||||
"db_key_field" => "id",
|
||||
"db_finalclass_field" => "",
|
||||
);
|
||||
];
|
||||
MetaModel::Init_Params($aParams);
|
||||
//MetaModel::Init_InheritAttributes();
|
||||
MetaModel::Init_AddAttribute(new AttributeExternalKey("userid", array("targetclass"=>"User", "jointype"=> "", "allowed_values"=>null, "sql"=>"userid", "is_null_allowed"=>false, "on_target_delete"=>DEL_MANUAL, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeExternalField("login", array("allowed_values"=>null, "extkey_attcode"=> 'userid', "target_attcode"=>"login")));
|
||||
MetaModel::Init_AddAttribute(new AttributeString("class", array("allowed_values"=>null, "sql"=>"class", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeExternalKey("userid", ["targetclass" => "User", "jointype" => "", "allowed_values" => null, "sql" => "userid", "is_null_allowed" => false, "on_target_delete" => DEL_MANUAL, "depends_on" => []]));
|
||||
MetaModel::Init_AddAttribute(new AttributeExternalField("login", ["allowed_values" => null, "extkey_attcode" => 'userid', "target_attcode" => "login"]));
|
||||
MetaModel::Init_AddAttribute(new AttributeString("class", ["allowed_values" => null, "sql" => "class", "default_value" => null, "is_null_allowed" => false, "depends_on" => []]));
|
||||
|
||||
MetaModel::Init_AddAttribute(new AttributeString("stimulus", array("allowed_values"=>null, "sql"=>"action", "default_value"=>"", "is_null_allowed"=>false, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeEnum("permission", array("allowed_values"=>new ValueSetEnum('yes,no'), "sql"=>"permission", "default_value"=>"yes", "is_null_allowed"=>false, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeString("stimulus", ["allowed_values" => null, "sql" => "action", "default_value" => "", "is_null_allowed" => false, "depends_on" => []]));
|
||||
MetaModel::Init_AddAttribute(new AttributeEnum("permission", ["allowed_values" => new ValueSetEnum('yes,no'), "sql" => "permission", "default_value" => "yes", "is_null_allowed" => false, "depends_on" => []]));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -80,42 +80,39 @@ class UserRightsMatrixAttributeGrant extends DBObject
|
||||
{
|
||||
public static function Init()
|
||||
{
|
||||
$aParams = array
|
||||
(
|
||||
$aParams =
|
||||
[
|
||||
"category" => "addon/userrights",
|
||||
"key_type" => "autoincrement",
|
||||
"name_attcode" => "",
|
||||
"state_attcode" => "",
|
||||
"reconc_keys" => array(),
|
||||
"reconc_keys" => [],
|
||||
"db_table" => "priv_ur_matrixattributes",
|
||||
"db_key_field" => "id",
|
||||
"db_finalclass_field" => "",
|
||||
);
|
||||
];
|
||||
MetaModel::Init_Params($aParams);
|
||||
//MetaModel::Init_InheritAttributes();
|
||||
MetaModel::Init_AddAttribute(new AttributeExternalKey("userid", array("targetclass"=>"User", "jointype"=> "", "allowed_values"=>null, "sql"=>"userid", "is_null_allowed"=>false, "on_target_delete"=>DEL_MANUAL, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeExternalField("login", array("allowed_values"=>null, "extkey_attcode"=> 'userid', "target_attcode"=>"login")));
|
||||
MetaModel::Init_AddAttribute(new AttributeString("class", array("allowed_values"=>null, "sql"=>"class", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeString("attcode", array("allowed_values"=>null, "sql"=>"attcode", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeExternalKey("userid", ["targetclass" => "User", "jointype" => "", "allowed_values" => null, "sql" => "userid", "is_null_allowed" => false, "on_target_delete" => DEL_MANUAL, "depends_on" => []]));
|
||||
MetaModel::Init_AddAttribute(new AttributeExternalField("login", ["allowed_values" => null, "extkey_attcode" => 'userid', "target_attcode" => "login"]));
|
||||
MetaModel::Init_AddAttribute(new AttributeString("class", ["allowed_values" => null, "sql" => "class", "default_value" => null, "is_null_allowed" => false, "depends_on" => []]));
|
||||
MetaModel::Init_AddAttribute(new AttributeString("attcode", ["allowed_values" => null, "sql" => "attcode", "default_value" => null, "is_null_allowed" => false, "depends_on" => []]));
|
||||
|
||||
MetaModel::Init_AddAttribute(new AttributeString("action", array("allowed_values"=>null, "sql"=>"action", "default_value"=>"", "is_null_allowed"=>false, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeEnum("permission", array("allowed_values"=>new ValueSetEnum('yes,no'), "sql"=>"permission", "default_value"=>"yes", "is_null_allowed"=>false, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeString("action", ["allowed_values" => null, "sql" => "action", "default_value" => "", "is_null_allowed" => false, "depends_on" => []]));
|
||||
MetaModel::Init_AddAttribute(new AttributeEnum("permission", ["allowed_values" => new ValueSetEnum('yes,no'), "sql" => "permission", "default_value" => "yes", "is_null_allowed" => false, "depends_on" => []]));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
class UserRightsMatrix extends UserRightsAddOnAPI
|
||||
{
|
||||
static public $m_aActionCodes = array(
|
||||
public static $m_aActionCodes = [
|
||||
UR_ACTION_READ => 'read',
|
||||
UR_ACTION_MODIFY => 'modify',
|
||||
UR_ACTION_DELETE => 'delete',
|
||||
UR_ACTION_BULK_READ => 'bulk read',
|
||||
UR_ACTION_BULK_MODIFY => 'bulk modify',
|
||||
UR_ACTION_BULK_DELETE => 'bulk delete',
|
||||
);
|
||||
];
|
||||
|
||||
// Installation: create the very first user
|
||||
public function CreateAdministrator($sAdminUser, $sAdminPwd, $sLanguage = 'EN US')
|
||||
@@ -149,8 +146,7 @@ class UserRightsMatrix extends UserRightsAddOnAPI
|
||||
// Users must be added manually
|
||||
// This procedure will then update the matrix when a new user is found or a new class/attribute appears
|
||||
$oUserSet = new DBObjectSet(DBObjectSearch::FromOQL("SELECT User"));
|
||||
while ($oUser = $oUserSet->Fetch())
|
||||
{
|
||||
while ($oUser = $oUserSet->Fetch()) {
|
||||
$this->SetupUser($oUser->GetKey());
|
||||
}
|
||||
return true;
|
||||
@@ -158,23 +154,16 @@ class UserRightsMatrix extends UserRightsAddOnAPI
|
||||
|
||||
protected function SetupUser($iUserId, $bNewUser = false)
|
||||
{
|
||||
foreach(array('bizmodel', 'application', 'gui', 'core/cmdb') as $sCategory)
|
||||
{
|
||||
foreach (MetaModel::GetClasses($sCategory) as $sClass)
|
||||
{
|
||||
foreach (self::$m_aActionCodes as $iActionCode => $sAction)
|
||||
{
|
||||
if ($bNewUser)
|
||||
{
|
||||
foreach (['bizmodel', 'application', 'gui', 'core/cmdb'] as $sCategory) {
|
||||
foreach (MetaModel::GetClasses($sCategory) as $sClass) {
|
||||
foreach (self::$m_aActionCodes as $iActionCode => $sAction) {
|
||||
if ($bNewUser) {
|
||||
$bAddCell = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
$oSet = new DBObjectSet(DBObjectSearch::FromOQL("SELECT UserRightsMatrixClassGrant WHERE class = '$sClass' AND action = '$sAction' AND userid = $iUserId"));
|
||||
$bAddCell = ($oSet->Count() < 1);
|
||||
}
|
||||
if ($bAddCell)
|
||||
{
|
||||
if ($bAddCell) {
|
||||
// Create a new entry
|
||||
$oMyClassGrant = MetaModel::NewObject("UserRightsMatrixClassGrant");
|
||||
$oMyClassGrant->Set("userid", $iUserId);
|
||||
@@ -184,19 +173,14 @@ class UserRightsMatrix extends UserRightsAddOnAPI
|
||||
$iId = $oMyClassGrant->DBInsertNoReload();
|
||||
}
|
||||
}
|
||||
foreach (MetaModel::EnumStimuli($sClass) as $sStimulusCode => $oStimulus)
|
||||
{
|
||||
if ($bNewUser)
|
||||
{
|
||||
foreach (MetaModel::EnumStimuli($sClass) as $sStimulusCode => $oStimulus) {
|
||||
if ($bNewUser) {
|
||||
$bAddCell = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
$oSet = new DBObjectSet(DBObjectSearch::FromOQL("SELECT UserRightsMatrixClassStimulusGrant WHERE class = '$sClass' AND stimulus = '$sStimulusCode' AND userid = $iUserId"));
|
||||
$bAddCell = ($oSet->Count() < 1);
|
||||
}
|
||||
if ($bAddCell)
|
||||
{
|
||||
if ($bAddCell) {
|
||||
// Create a new entry
|
||||
$oMyClassGrant = MetaModel::NewObject("UserRightsMatrixClassStimulusGrant");
|
||||
$oMyClassGrant->Set("userid", $iUserId);
|
||||
@@ -206,21 +190,15 @@ class UserRightsMatrix extends UserRightsAddOnAPI
|
||||
$iId = $oMyClassGrant->DBInsertNoReload();
|
||||
}
|
||||
}
|
||||
foreach (MetaModel::GetAttributesList($sClass) as $sAttCode)
|
||||
{
|
||||
if ($bNewUser)
|
||||
{
|
||||
foreach (MetaModel::GetAttributesList($sClass) as $sAttCode) {
|
||||
if ($bNewUser) {
|
||||
$bAddCell = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
$oSet = new DBObjectSet(DBObjectSearch::FromOQL("SELECT UserRightsMatrixAttributeGrant WHERE class = '$sClass' AND attcode = '$sAttCode' AND userid = $iUserId"));
|
||||
$bAddCell = ($oSet->Count() < 1);
|
||||
}
|
||||
if ($bAddCell)
|
||||
{
|
||||
foreach (array('read', 'modify') as $sAction)
|
||||
{
|
||||
if ($bAddCell) {
|
||||
foreach (['read', 'modify'] as $sAction) {
|
||||
// Create a new entry
|
||||
$oMyAttGrant = MetaModel::NewObject("UserRightsMatrixAttributeGrant");
|
||||
$oMyAttGrant->Set("userid", $iUserId);
|
||||
@@ -261,14 +239,13 @@ class UserRightsMatrix extends UserRightsAddOnAPI
|
||||
*/
|
||||
}
|
||||
|
||||
|
||||
public function Init()
|
||||
{
|
||||
// Could be loaded in a shared memory (?)
|
||||
return true;
|
||||
}
|
||||
|
||||
public function GetSelectFilter($oUser, $sClass, $aSettings = array())
|
||||
public function GetSelectFilter($oUser, $sClass, $aSettings = [])
|
||||
{
|
||||
$oNullFilter = new DBObjectSearch($sClass);
|
||||
return $oNullFilter;
|
||||
@@ -276,21 +253,18 @@ class UserRightsMatrix extends UserRightsAddOnAPI
|
||||
|
||||
public function IsActionAllowed($oUser, $sClass, $iActionCode, $oInstanceSet = null)
|
||||
{
|
||||
if (!array_key_exists($iActionCode, self::$m_aActionCodes))
|
||||
{
|
||||
if (!array_key_exists($iActionCode, self::$m_aActionCodes)) {
|
||||
return UR_ALLOWED_NO;
|
||||
}
|
||||
$sAction = self::$m_aActionCodes[$iActionCode];
|
||||
|
||||
$oSet = new DBObjectSet(DBObjectSearch::FromOQL("SELECT UserRightsMatrixClassGrant WHERE class = '$sClass' AND action = '$sAction' AND userid = '{$oUser->GetKey()}'"));
|
||||
if ($oSet->Count() < 1)
|
||||
{
|
||||
if ($oSet->Count() < 1) {
|
||||
return UR_ALLOWED_NO;
|
||||
}
|
||||
|
||||
$oGrantRecord = $oSet->Fetch();
|
||||
switch ($oGrantRecord->Get('permission'))
|
||||
{
|
||||
switch ($oGrantRecord->Get('permission')) {
|
||||
case 'yes':
|
||||
$iRetCode = UR_ALLOWED_YES;
|
||||
break;
|
||||
@@ -304,21 +278,18 @@ class UserRightsMatrix extends UserRightsAddOnAPI
|
||||
|
||||
public function IsActionAllowedOnAttribute($oUser, $sClass, $sAttCode, $iActionCode, $oInstanceSet = null)
|
||||
{
|
||||
if (!array_key_exists($iActionCode, self::$m_aActionCodes))
|
||||
{
|
||||
if (!array_key_exists($iActionCode, self::$m_aActionCodes)) {
|
||||
return UR_ALLOWED_NO;
|
||||
}
|
||||
$sAction = self::$m_aActionCodes[$iActionCode];
|
||||
|
||||
$oSet = new DBObjectSet(DBObjectSearch::FromOQL("SELECT UserRightsMatrixAttributeGrant WHERE class = '$sClass' AND attcode = '$sAttCode' AND action = '$sAction' AND userid = '{$oUser->GetKey()}'"));
|
||||
if ($oSet->Count() < 1)
|
||||
{
|
||||
if ($oSet->Count() < 1) {
|
||||
return UR_ALLOWED_NO;
|
||||
}
|
||||
|
||||
$oGrantRecord = $oSet->Fetch();
|
||||
switch ($oGrantRecord->Get('permission'))
|
||||
{
|
||||
switch ($oGrantRecord->Get('permission')) {
|
||||
case 'yes':
|
||||
$iRetCode = UR_ALLOWED_YES;
|
||||
break;
|
||||
@@ -333,14 +304,12 @@ class UserRightsMatrix extends UserRightsAddOnAPI
|
||||
public function IsStimulusAllowed($oUser, $sClass, $sStimulusCode, $oInstanceSet = null)
|
||||
{
|
||||
$oSet = new DBObjectSet(DBObjectSearch::FromOQL("SELECT UserRightsMatrixClassStimulusGrant WHERE class = '$sClass' AND stimulus = '$sStimulusCode' AND userid = '{$oUser->GetKey()}'"));
|
||||
if ($oSet->Count() < 1)
|
||||
{
|
||||
if ($oSet->Count() < 1) {
|
||||
return UR_ALLOWED_NO;
|
||||
}
|
||||
|
||||
$oGrantRecord = $oSet->Fetch();
|
||||
switch ($oGrantRecord->Get('permission'))
|
||||
{
|
||||
switch ($oGrantRecord->Get('permission')) {
|
||||
case 'yes':
|
||||
$iRetCode = UR_ALLOWED_YES;
|
||||
break;
|
||||
@@ -358,5 +327,3 @@ class UserRightsMatrix extends UserRightsAddOnAPI
|
||||
}
|
||||
|
||||
UserRights::SelectModule('UserRightsMatrix');
|
||||
|
||||
?>
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
<?php
|
||||
|
||||
// Copyright (C) 2010-2024 Combodo SAS
|
||||
//
|
||||
// This file is part of iTop.
|
||||
//
|
||||
// iTop is free software; you can redistribute it and/or modify
|
||||
// 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.
|
||||
@@ -47,7 +48,7 @@ class UserRightsNull extends UserRightsAddOnAPI
|
||||
return true;
|
||||
}
|
||||
|
||||
public function GetSelectFilter($oUser, $sClass, $aSettings = array())
|
||||
public function GetSelectFilter($oUser, $sClass, $aSettings = [])
|
||||
{
|
||||
$oNullFilter = new DBObjectSearch($sClass);
|
||||
return $oNullFilter;
|
||||
@@ -74,5 +75,3 @@ class UserRightsNull extends UserRightsAddOnAPI
|
||||
}
|
||||
|
||||
UserRights::SelectModule('UserRightsNull');
|
||||
|
||||
?>
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* @copyright Copyright (C) 2010-2024 Combodo SAS
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
@@ -29,56 +30,52 @@ class UserRightsBaseClassGUI extends cmdbAbstractObject
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class URP_Profiles extends UserRightsBaseClassGUI
|
||||
{
|
||||
public static function Init()
|
||||
{
|
||||
$aParams = array
|
||||
(
|
||||
$aParams =
|
||||
[
|
||||
"category" => "addon/userrights,grant_by_profile,filter",
|
||||
"key_type" => "autoincrement",
|
||||
"name_attcode" => "name",
|
||||
"complementary_name_attcode" => array('description'),
|
||||
"complementary_name_attcode" => ['description'],
|
||||
"state_attcode" => "",
|
||||
"reconc_keys" => array(),
|
||||
"reconc_keys" => [],
|
||||
"db_table" => "priv_urp_profiles",
|
||||
"db_key_field" => "id",
|
||||
"db_finalclass_field" => "",
|
||||
);
|
||||
];
|
||||
MetaModel::Init_Params($aParams);
|
||||
//MetaModel::Init_InheritAttributes();
|
||||
MetaModel::Init_AddAttribute(new AttributeString("name", array("allowed_values"=>null, "sql"=>"name", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeString("description", array("allowed_values"=>null, "sql"=>"description", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeString("name", ["allowed_values" => null, "sql" => "name", "default_value" => null, "is_null_allowed" => false, "depends_on" => []]));
|
||||
MetaModel::Init_AddAttribute(new AttributeString("description", ["allowed_values" => null, "sql" => "description", "default_value" => null, "is_null_allowed" => false, "depends_on" => []]));
|
||||
|
||||
MetaModel::Init_AddAttribute(new AttributeLinkedSetIndirect("user_list", array("linked_class"=>"URP_UserProfile", "ext_key_to_me"=>"profileid", "ext_key_to_remote"=>"userid", "allowed_values"=>null, "count_min"=>1, "count_max"=>0, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeLinkedSetIndirect("user_list", ["linked_class" => "URP_UserProfile", "ext_key_to_me" => "profileid", "ext_key_to_remote" => "userid", "allowed_values" => null, "count_min" => 1, "count_max" => 0, "depends_on" => []]));
|
||||
|
||||
// Display lists
|
||||
MetaModel::Init_SetZListItems('details', array('name', 'description', 'user_list')); // Attributes to be displayed for the complete details
|
||||
MetaModel::Init_SetZListItems('list', array('description')); // Attributes to be displayed for a list
|
||||
MetaModel::Init_SetZListItems('details', ['name', 'description', 'user_list']); // Attributes to be displayed for the complete details
|
||||
MetaModel::Init_SetZListItems('list', ['description']); // Attributes to be displayed for a list
|
||||
// Search criteria
|
||||
MetaModel::Init_SetZListItems('standard_search', array('name','description')); // Criteria of the std search form
|
||||
MetaModel::Init_SetZListItems('default_search', array ('name','description'));
|
||||
MetaModel::Init_SetZListItems('standard_search', ['name','description']); // Criteria of the std search form
|
||||
MetaModel::Init_SetZListItems('default_search', ['name','description']);
|
||||
}
|
||||
|
||||
protected static $m_aCacheProfiles = null;
|
||||
|
||||
public static function DoCreateProfile($sName, $sDescription)
|
||||
{
|
||||
if (is_null(self::$m_aCacheProfiles))
|
||||
{
|
||||
self::$m_aCacheProfiles = array();
|
||||
if (is_null(self::$m_aCacheProfiles)) {
|
||||
self::$m_aCacheProfiles = [];
|
||||
$oFilterAll = new DBObjectSearch('URP_Profiles');
|
||||
$oSet = new DBObjectSet($oFilterAll);
|
||||
while ($oProfile = $oSet->Fetch())
|
||||
{
|
||||
while ($oProfile = $oSet->Fetch()) {
|
||||
self::$m_aCacheProfiles[$oProfile->Get('name')] = $oProfile->GetKey();
|
||||
}
|
||||
}
|
||||
|
||||
$sCacheKey = $sName;
|
||||
if (isset(self::$m_aCacheProfiles[$sCacheKey]))
|
||||
{
|
||||
if (isset(self::$m_aCacheProfiles[$sCacheKey])) {
|
||||
return self::$m_aCacheProfiles[$sCacheKey];
|
||||
}
|
||||
$oNewObj = MetaModel::NewObject("URP_Profiles");
|
||||
@@ -89,27 +86,21 @@ class URP_Profiles extends UserRightsBaseClassGUI
|
||||
return $iId;
|
||||
}
|
||||
|
||||
function GetGrantAsHtml($oUserRights, $sClass, $sAction)
|
||||
public function GetGrantAsHtml($oUserRights, $sClass, $sAction)
|
||||
{
|
||||
$bGrant = $oUserRights->GetProfileActionGrant($this->GetKey(), $sClass, $sAction);
|
||||
if (is_null($bGrant))
|
||||
{
|
||||
return '<span style="background-color: #ffdddd;">'.Dict::S('UI:UserManagement:ActionAllowed:No').'</span>';
|
||||
}
|
||||
elseif ($bGrant)
|
||||
{
|
||||
return '<span style="background-color: #ddffdd;">'.Dict::S('UI:UserManagement:ActionAllowed:Yes').'</span>';
|
||||
}
|
||||
else
|
||||
{
|
||||
return '<span style="background-color: #ffdddd;">'.Dict::S('UI:UserManagement:ActionAllowed:No').'</span>';
|
||||
if (is_null($bGrant)) {
|
||||
return '<span class="ibo-user-rights ibo-is-failure">'.Dict::S('UI:UserManagement:ActionAllowed:No').'</span>';
|
||||
} elseif ($bGrant) {
|
||||
return '<span class="ibo-user-rights ibo-is-success">'.Dict::S('UI:UserManagement:ActionAllowed:Yes').'</span>';
|
||||
} else {
|
||||
return '<span class="ibo-user-rights ibo-is-failure">'.Dict::S('UI:UserManagement:ActionAllowed:No').'</span>';
|
||||
}
|
||||
}
|
||||
|
||||
function DoShowGrantSumary($oPage)
|
||||
public function DoShowGrantSumary($oPage)
|
||||
{
|
||||
if ($this->GetRawName() == "Administrator")
|
||||
{
|
||||
if ($this->GetRawName() == "Administrator") {
|
||||
// Looks dirty, but ok that's THE ONE
|
||||
$oPage->p(Dict::S('UI:UserManagement:AdminProfile+'));
|
||||
return;
|
||||
@@ -118,21 +109,18 @@ class URP_Profiles extends UserRightsBaseClassGUI
|
||||
// Note: for sure, we assume that the instance is derived from UserRightsProfile
|
||||
$oUserRights = UserRights::GetModuleInstance();
|
||||
|
||||
$aDisplayData = array();
|
||||
foreach (MetaModel::GetClasses('bizmodel,grant_by_profile') as $sClass)
|
||||
{
|
||||
$aStimuli = array();
|
||||
foreach (MetaModel::EnumStimuli($sClass) as $sStimulusCode => $oStimulus)
|
||||
{
|
||||
$aDisplayData = [];
|
||||
foreach (MetaModel::GetClasses('bizmodel,grant_by_profile') as $sClass) {
|
||||
$aStimuli = [];
|
||||
foreach (MetaModel::EnumStimuli($sClass) as $sStimulusCode => $oStimulus) {
|
||||
$bGrant = $oUserRights->GetClassStimulusGrant($this->GetKey(), $sClass, $sStimulusCode);
|
||||
if ($bGrant === true)
|
||||
{
|
||||
if ($bGrant === true) {
|
||||
$aStimuli[] = '<span title="'.$sStimulusCode.': '.utils::EscapeHtml($oStimulus->GetDescription()).'">'.utils::EscapeHtml($oStimulus->GetLabel()).'</span>';
|
||||
}
|
||||
}
|
||||
$sStimuli = implode(', ', $aStimuli);
|
||||
|
||||
$aDisplayData[] = array(
|
||||
$aDisplayData[] = [
|
||||
'class' => MetaModel::GetName($sClass),
|
||||
'read' => $this->GetGrantAsHtml($oUserRights, $sClass, 'r'),
|
||||
'bulkread' => $this->GetGrantAsHtml($oUserRights, $sClass, 'br'),
|
||||
@@ -141,22 +129,22 @@ class URP_Profiles extends UserRightsBaseClassGUI
|
||||
'delete' => $this->GetGrantAsHtml($oUserRights, $sClass, 'd'),
|
||||
'bulkdelete' => $this->GetGrantAsHtml($oUserRights, $sClass, 'bd'),
|
||||
'stimuli' => $sStimuli,
|
||||
);
|
||||
];
|
||||
}
|
||||
|
||||
$aDisplayConfig = array();
|
||||
$aDisplayConfig['class'] = array('label' => Dict::S('UI:UserManagement:Class'), 'description' => Dict::S('UI:UserManagement:Class+'));
|
||||
$aDisplayConfig['read'] = array('label' => Dict::S('UI:UserManagement:Action:Read'), 'description' => Dict::S('UI:UserManagement:Action:Read+'));
|
||||
$aDisplayConfig['bulkread'] = array('label' => Dict::S('UI:UserManagement:Action:BulkRead'), 'description' => Dict::S('UI:UserManagement:Action:BulkRead+'));
|
||||
$aDisplayConfig['write'] = array('label' => Dict::S('UI:UserManagement:Action:Modify'), 'description' => Dict::S('UI:UserManagement:Action:Modify+'));
|
||||
$aDisplayConfig['bulkwrite'] = array('label' => Dict::S('UI:UserManagement:Action:BulkModify'), 'description' => Dict::S('UI:UserManagement:Action:BulkModify+'));
|
||||
$aDisplayConfig['delete'] = array('label' => Dict::S('UI:UserManagement:Action:Delete'), 'description' => Dict::S('UI:UserManagement:Action:Delete+'));
|
||||
$aDisplayConfig['bulkdelete'] = array('label' => Dict::S('UI:UserManagement:Action:BulkDelete'), 'description' => Dict::S('UI:UserManagement:Action:BulkDelete+'));
|
||||
$aDisplayConfig['stimuli'] = array('label' => Dict::S('UI:UserManagement:Action:Stimuli'), 'description' => Dict::S('UI:UserManagement:Action:Stimuli+'));
|
||||
$aDisplayConfig = [];
|
||||
$aDisplayConfig['class'] = ['label' => Dict::S('UI:UserManagement:Class'), 'description' => Dict::S('UI:UserManagement:Class+')];
|
||||
$aDisplayConfig['read'] = ['label' => Dict::S('UI:UserManagement:Action:Read'), 'description' => Dict::S('UI:UserManagement:Action:Read+')];
|
||||
$aDisplayConfig['bulkread'] = ['label' => Dict::S('UI:UserManagement:Action:BulkRead'), 'description' => Dict::S('UI:UserManagement:Action:BulkRead+')];
|
||||
$aDisplayConfig['write'] = ['label' => Dict::S('UI:UserManagement:Action:Modify'), 'description' => Dict::S('UI:UserManagement:Action:Modify+')];
|
||||
$aDisplayConfig['bulkwrite'] = ['label' => Dict::S('UI:UserManagement:Action:BulkModify'), 'description' => Dict::S('UI:UserManagement:Action:BulkModify+')];
|
||||
$aDisplayConfig['delete'] = ['label' => Dict::S('UI:UserManagement:Action:Delete'), 'description' => Dict::S('UI:UserManagement:Action:Delete+')];
|
||||
$aDisplayConfig['bulkdelete'] = ['label' => Dict::S('UI:UserManagement:Action:BulkDelete'), 'description' => Dict::S('UI:UserManagement:Action:BulkDelete+')];
|
||||
$aDisplayConfig['stimuli'] = ['label' => Dict::S('UI:UserManagement:Action:Stimuli'), 'description' => Dict::S('UI:UserManagement:Action:Stimuli+')];
|
||||
$oPage->table($aDisplayConfig, $aDisplayData);
|
||||
}
|
||||
|
||||
function DisplayBareRelations(WebPage $oPage, $bEditMode = false)
|
||||
public function DisplayBareRelations(WebPage $oPage, $bEditMode = false)
|
||||
{
|
||||
parent::DisplayBareRelations($oPage, $bEditMode);
|
||||
|
||||
@@ -166,10 +154,9 @@ class URP_Profiles extends UserRightsBaseClassGUI
|
||||
|
||||
public static function GetReadOnlyAttributes()
|
||||
{
|
||||
return array('name', 'description');
|
||||
return ['name', 'description'];
|
||||
}
|
||||
|
||||
|
||||
// returns an array of id => array of column => php value(so-called "real value")
|
||||
public static function GetPredefinedObjects()
|
||||
{
|
||||
@@ -181,15 +168,13 @@ class URP_Profiles extends UserRightsBaseClassGUI
|
||||
protected function OnDelete()
|
||||
{
|
||||
// Don't remove admin profile
|
||||
if ($this->Get('name') === ADMIN_PROFILE_NAME)
|
||||
{
|
||||
if ($this->Get('name') === ADMIN_PROFILE_NAME) {
|
||||
throw new SecurityException(Dict::Format('UI:Login:Error:AccessAdmin'));
|
||||
}
|
||||
|
||||
// Note: this may break the rule that says: "a user must have at least ONE profile" !
|
||||
$oLnkSet = $this->Get('user_list');
|
||||
while($oLnk = $oLnkSet->Fetch())
|
||||
{
|
||||
while ($oLnk = $oLnkSet->Fetch()) {
|
||||
$oLnk->DBDelete();
|
||||
}
|
||||
}
|
||||
@@ -202,11 +187,10 @@ class URP_Profiles extends UserRightsBaseClassGUI
|
||||
* @param $sTargetState string The target state in which to evalutate the flags, if empty the current state will be used
|
||||
* @return integer Flags: the binary combination of the flags applicable to this attribute
|
||||
*/
|
||||
public function GetAttributeFlags($sAttCode, &$aReasons = array(), $sTargetState = '')
|
||||
public function GetAttributeFlags($sAttCode, &$aReasons = [], $sTargetState = '')
|
||||
{
|
||||
$iFlags = parent::GetAttributeFlags($sAttCode, $aReasons, $sTargetState);
|
||||
if (MetaModel::GetConfig()->Get('demo_mode'))
|
||||
{
|
||||
if (MetaModel::GetConfig()->Get('demo_mode')) {
|
||||
$aReasons[] = 'Sorry, profiles are read-only in the demonstration mode!';
|
||||
$iFlags |= OPT_ATT_READONLY;
|
||||
}
|
||||
@@ -214,52 +198,52 @@ class URP_Profiles extends UserRightsBaseClassGUI
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
class URP_UserProfile extends UserRightsBaseClassGUI
|
||||
{
|
||||
public static function Init()
|
||||
{
|
||||
$aParams = array
|
||||
(
|
||||
$aParams =
|
||||
[
|
||||
"category" => "addon/userrights,grant_by_profile,filter",
|
||||
"key_type" => "autoincrement",
|
||||
"name_attcode" => array("userlogin", "profile"),
|
||||
"name_attcode" => ["userlogin", "profile"],
|
||||
"state_attcode" => "",
|
||||
"reconc_keys" => array(),
|
||||
"reconc_keys" => [],
|
||||
"db_table" => "priv_urp_userprofile",
|
||||
"db_key_field" => "id",
|
||||
"db_finalclass_field" => "",
|
||||
"is_link" => true, /** @since 3.1.0 N°6482 */
|
||||
'uniqueness_rules' => array(
|
||||
'no_duplicate' => array(
|
||||
'attributes' => array(
|
||||
'uniqueness_rules' => [
|
||||
'no_duplicate' => [
|
||||
'attributes' => [
|
||||
0 => 'userid',
|
||||
1 => 'profileid',
|
||||
),
|
||||
],
|
||||
'filter' => '',
|
||||
'disabled' => false,
|
||||
'is_blocking' => true,
|
||||
),
|
||||
),
|
||||
);
|
||||
],
|
||||
],
|
||||
];
|
||||
MetaModel::Init_Params($aParams);
|
||||
//MetaModel::Init_InheritAttributes();
|
||||
MetaModel::Init_AddAttribute(new AttributeExternalKey("userid", array("targetclass" => "User", "jointype" => "", "allowed_values" => null, "sql" => "userid", "is_null_allowed" => false, "on_target_delete" => DEL_AUTO, "depends_on" => array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeExternalField("userlogin", array("allowed_values" => null, "extkey_attcode" => 'userid', "target_attcode" => "login")));
|
||||
MetaModel::Init_AddAttribute(new AttributeExternalKey("userid", ["targetclass" => "User", "jointype" => "", "allowed_values" => null, "sql" => "userid", "is_null_allowed" => false, "on_target_delete" => DEL_AUTO, "depends_on" => []]));
|
||||
MetaModel::Init_AddAttribute(new AttributeExternalField("userlogin", ["allowed_values" => null, "extkey_attcode" => 'userid', "target_attcode" => "login"]));
|
||||
|
||||
MetaModel::Init_AddAttribute(new AttributeExternalKey("profileid",
|
||||
array("targetclass" => "URP_Profiles", "jointype" => "", "allowed_values" => null, "sql" => "profileid", "is_null_allowed" => false, "on_target_delete" => DEL_AUTO, "depends_on" => array(), "allow_target_creation" => false)));
|
||||
MetaModel::Init_AddAttribute(new AttributeExternalField("profile", array("allowed_values" => null, "extkey_attcode" => 'profileid', "target_attcode" => "name")));
|
||||
MetaModel::Init_AddAttribute(new AttributeExternalKey(
|
||||
"profileid",
|
||||
["targetclass" => "URP_Profiles", "jointype" => "", "allowed_values" => null, "sql" => "profileid", "is_null_allowed" => false, "on_target_delete" => DEL_AUTO, "depends_on" => [], "allow_target_creation" => false]
|
||||
));
|
||||
MetaModel::Init_AddAttribute(new AttributeExternalField("profile", ["allowed_values" => null, "extkey_attcode" => 'profileid', "target_attcode" => "name"]));
|
||||
|
||||
MetaModel::Init_AddAttribute(new AttributeString("reason", array("allowed_values" => null, "sql" => "description", "default_value" => null, "is_null_allowed" => true, "depends_on" => array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeString("reason", ["allowed_values" => null, "sql" => "description", "default_value" => null, "is_null_allowed" => true, "depends_on" => []]));
|
||||
|
||||
// Display lists
|
||||
MetaModel::Init_SetZListItems('details', array('userid', 'profileid', 'reason')); // Attributes to be displayed for the complete details
|
||||
MetaModel::Init_SetZListItems('list', array('userid', 'profileid', 'reason')); // Attributes to be displayed for a list
|
||||
MetaModel::Init_SetZListItems('details', ['userid', 'profileid', 'reason']); // Attributes to be displayed for the complete details
|
||||
MetaModel::Init_SetZListItems('list', ['userid', 'profileid', 'reason']); // Attributes to be displayed for a list
|
||||
// Search criteria
|
||||
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
|
||||
MetaModel::Init_SetZListItems('standard_search', ['userid', 'profileid']); // Criteria of the std search form
|
||||
MetaModel::Init_SetZListItems('advanced_search', ['userid', 'profileid']); // Criteria of the advanced search form
|
||||
}
|
||||
|
||||
public function CheckToDelete(&$oDeletionPlan)
|
||||
@@ -267,15 +251,14 @@ class URP_UserProfile extends UserRightsBaseClassGUI
|
||||
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->SetDeletionIssues($this, ['deletion not allowed in demo mode.'], true);
|
||||
$oDeletionPlan->ComputeResults();
|
||||
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
$this->CheckIfProfileIsAllowed(UR_ACTION_DELETE);
|
||||
}
|
||||
catch (SecurityException $e) {
|
||||
} catch (SecurityException $e) {
|
||||
// Users deletion is NOT allowed
|
||||
$oDeletionPlan->AddToDelete($this, null);
|
||||
$oDeletionPlan->SetDeletionIssues($this, [$e->getMessage()], true);
|
||||
@@ -292,15 +275,14 @@ class URP_UserProfile extends UserRightsBaseClassGUI
|
||||
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->SetDeletionIssues($this, ['deletion not allowed in demo mode.'], true);
|
||||
$oDeletionPlan->ComputeResults();
|
||||
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
$this->CheckIfProfileIsAllowed(UR_ACTION_DELETE);
|
||||
}
|
||||
catch (SecurityException $e) {
|
||||
} catch (SecurityException $e) {
|
||||
// Users deletion is NOT allowed
|
||||
$oDeletionPlan->AddToDelete($this, null);
|
||||
$oDeletionPlan->SetDeletionIssues($this, [$e->getMessage()], true);
|
||||
@@ -336,29 +318,26 @@ class URP_UserProfile extends UserRightsBaseClassGUI
|
||||
protected function CheckIfProfileIsAllowed($iActionCode)
|
||||
{
|
||||
// When initializing or admin, we need to let everything pass trough
|
||||
if (!UserRights::IsLoggedIn() || UserRights::IsAdministrator()) { return; }
|
||||
if (!UserRights::IsLoggedIn() || UserRights::IsAdministrator()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Only administrators can manage administrators
|
||||
$iOrigUserId = $this->GetOriginal('userid');
|
||||
if (!empty($iOrigUserId))
|
||||
{
|
||||
if (!empty($iOrigUserId)) {
|
||||
$oUser = MetaModel::GetObject('User', $iOrigUserId, true, true);
|
||||
if (UserRights::IsAdministrator($oUser) && !UserRights::IsAdministrator())
|
||||
{
|
||||
if (UserRights::IsAdministrator($oUser) && !UserRights::IsAdministrator()) {
|
||||
throw new SecurityException(Dict::Format('UI:Login:Error:AccessRestricted'));
|
||||
}
|
||||
}
|
||||
$oUser = MetaModel::GetObject('User', $this->Get('userid'), true, true);
|
||||
if (UserRights::IsAdministrator($oUser) && !UserRights::IsAdministrator())
|
||||
{
|
||||
if (UserRights::IsAdministrator($oUser) && !UserRights::IsAdministrator()) {
|
||||
throw new SecurityException(Dict::Format('UI:Login:Error:AccessRestricted'));
|
||||
}
|
||||
if (!UserRights::IsActionAllowed(get_class($this), $iActionCode, DBObjectSet::FromObject($this)))
|
||||
{
|
||||
if (!UserRights::IsActionAllowed(get_class($this), $iActionCode, DBObjectSet::FromObject($this))) {
|
||||
throw new SecurityException(Dict::Format('UI:Error:ObjectCannotBeUpdated'));
|
||||
}
|
||||
if (!UserRights::IsAdministrator() && ($this->Get('profile') === ADMIN_PROFILE_NAME))
|
||||
{
|
||||
if (!UserRights::IsAdministrator() && ($this->Get('profile') === ADMIN_PROFILE_NAME)) {
|
||||
throw new SecurityException(Dict::Format('UI:Login:Error:AccessAdmin'));
|
||||
}
|
||||
}
|
||||
@@ -369,33 +348,33 @@ class URP_UserOrg extends UserRightsBaseClassGUI
|
||||
{
|
||||
public static function Init()
|
||||
{
|
||||
$aParams = array
|
||||
(
|
||||
$aParams =
|
||||
[
|
||||
"category" => "addon/userrights,grant_by_profile",
|
||||
"key_type" => "autoincrement",
|
||||
"name_attcode" => array("userlogin", "allowed_org_name"),
|
||||
"name_attcode" => ["userlogin", "allowed_org_name"],
|
||||
"state_attcode" => "",
|
||||
"reconc_keys" => array(),
|
||||
"reconc_keys" => [],
|
||||
"db_table" => "priv_urp_userorg",
|
||||
"db_key_field" => "id",
|
||||
"db_finalclass_field" => "",
|
||||
);
|
||||
];
|
||||
MetaModel::Init_Params($aParams);
|
||||
//MetaModel::Init_InheritAttributes();
|
||||
MetaModel::Init_AddAttribute(new AttributeExternalKey("userid", array("targetclass"=>"User", "jointype"=> "", "allowed_values"=>null, "sql"=>"userid", "is_null_allowed"=>false, "on_target_delete"=>DEL_AUTO, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeExternalField("userlogin", array("allowed_values"=>null, "extkey_attcode"=> 'userid', "target_attcode"=>"login")));
|
||||
MetaModel::Init_AddAttribute(new AttributeExternalKey("userid", ["targetclass" => "User", "jointype" => "", "allowed_values" => null, "sql" => "userid", "is_null_allowed" => false, "on_target_delete" => DEL_AUTO, "depends_on" => []]));
|
||||
MetaModel::Init_AddAttribute(new AttributeExternalField("userlogin", ["allowed_values" => null, "extkey_attcode" => 'userid', "target_attcode" => "login"]));
|
||||
|
||||
MetaModel::Init_AddAttribute(new AttributeExternalKey("allowed_org_id", array("targetclass"=>"Organization", "jointype"=> "", "allowed_values"=>null, "sql"=>"allowed_org_id", "is_null_allowed"=>false, "on_target_delete"=>DEL_AUTO, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeExternalField("allowed_org_name", array("allowed_values"=>null, "extkey_attcode"=> 'allowed_org_id', "target_attcode"=>"name")));
|
||||
MetaModel::Init_AddAttribute(new AttributeExternalKey("allowed_org_id", ["targetclass" => "Organization", "jointype" => "", "allowed_values" => null, "sql" => "allowed_org_id", "is_null_allowed" => false, "on_target_delete" => DEL_AUTO, "depends_on" => []]));
|
||||
MetaModel::Init_AddAttribute(new AttributeExternalField("allowed_org_name", ["allowed_values" => null, "extkey_attcode" => 'allowed_org_id', "target_attcode" => "name"]));
|
||||
|
||||
MetaModel::Init_AddAttribute(new AttributeString("reason", array("allowed_values"=>null, "sql"=>"reason", "default_value"=>null, "is_null_allowed"=>true, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeString("reason", ["allowed_values" => null, "sql" => "reason", "default_value" => null, "is_null_allowed" => true, "depends_on" => []]));
|
||||
|
||||
// Display lists
|
||||
MetaModel::Init_SetZListItems('details', array('userid', 'allowed_org_id', 'reason')); // Attributes to be displayed for the complete details
|
||||
MetaModel::Init_SetZListItems('list', array('allowed_org_id', 'reason')); // Attributes to be displayed for a list
|
||||
MetaModel::Init_SetZListItems('details', ['userid', 'allowed_org_id', 'reason']); // Attributes to be displayed for the complete details
|
||||
MetaModel::Init_SetZListItems('list', ['allowed_org_id', 'reason']); // Attributes to be displayed for a list
|
||||
// Search criteria
|
||||
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
|
||||
MetaModel::Init_SetZListItems('standard_search', ['userid', 'allowed_org_id']); // Criteria of the std search form
|
||||
MetaModel::Init_SetZListItems('advanced_search', ['userid', 'allowed_org_id']); // Criteria of the advanced search form
|
||||
}
|
||||
|
||||
protected function OnInsert()
|
||||
@@ -418,40 +397,37 @@ class URP_UserOrg extends UserRightsBaseClassGUI
|
||||
*/
|
||||
protected function CheckIfOrgIsAllowed()
|
||||
{
|
||||
if (!UserRights::IsLoggedIn() || UserRights::IsAdministrator()) { return; }
|
||||
if (!UserRights::IsLoggedIn() || UserRights::IsAdministrator()) {
|
||||
return;
|
||||
}
|
||||
|
||||
$oUser = UserRights::GetUserObject();
|
||||
$oAddon = UserRights::GetModuleInstance();
|
||||
$aOrgs = $oAddon->GetUserOrgs($oUser, '');
|
||||
if (count($aOrgs) > 0)
|
||||
{
|
||||
if (count($aOrgs) > 0) {
|
||||
$iOrigOrgId = $this->GetOriginal('allowed_org_id');
|
||||
if ((!empty($iOrigOrgId) && !in_array($iOrigOrgId, $aOrgs)) || !in_array($this->Get('allowed_org_id'), $aOrgs))
|
||||
{
|
||||
if ((!empty($iOrigOrgId) && !in_array($iOrigOrgId, $aOrgs)) || !in_array($this->Get('allowed_org_id'), $aOrgs)) {
|
||||
throw new SecurityException(Dict::Format('Class:User/Error:OrganizationNotAllowed'));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
class UserRightsProfile extends UserRightsAddOnAPI
|
||||
{
|
||||
static public $m_aActionCodes = array(
|
||||
public static $m_aActionCodes = [
|
||||
UR_ACTION_READ => 'r',
|
||||
UR_ACTION_MODIFY => 'w',
|
||||
UR_ACTION_DELETE => 'd',
|
||||
UR_ACTION_BULK_READ => 'br',
|
||||
UR_ACTION_BULK_MODIFY => 'bw',
|
||||
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
|
||||
*/
|
||||
/**
|
||||
* @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
|
||||
@@ -472,8 +448,7 @@ class UserRightsProfile extends UserRightsAddOnAPI
|
||||
$oContact = MetaModel::NewObject('Person');
|
||||
$oContact->Set('name', 'My last name');
|
||||
$oContact->Set('first_name', 'My first name');
|
||||
if (MetaModel::IsValidAttCode('Person', 'org_id'))
|
||||
{
|
||||
if (MetaModel::IsValidAttCode('Person', 'org_id')) {
|
||||
$oContact->Set('org_id', $iOrgId);
|
||||
}
|
||||
$oContact->Set('email', 'my.email@foo.org');
|
||||
@@ -481,20 +456,17 @@ class UserRightsProfile extends UserRightsAddOnAPI
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
$oUser = new UserLocal();
|
||||
$oUser->Set('login', $sAdminUser);
|
||||
$oUser->Set('password', $sAdminPwd);
|
||||
if (MetaModel::IsValidAttCode('UserLocal', 'contactid') && ($iContactId != 0))
|
||||
{
|
||||
if (MetaModel::IsValidAttCode('UserLocal', 'contactid') && ($iContactId != 0)) {
|
||||
$oUser->Set('contactid', $iContactId);
|
||||
}
|
||||
$oUser->Set('language', $sLanguage); // Language was chosen during the installation
|
||||
|
||||
// Add this user to the very specific 'admin' profile
|
||||
$oAdminProfile = MetaModel::GetObjectFromOQL("SELECT URP_Profiles WHERE name = :name", array('name' => ADMIN_PROFILE_NAME), true /*all data*/);
|
||||
if (is_object($oAdminProfile))
|
||||
{
|
||||
$oAdminProfile = MetaModel::GetObjectFromOQL("SELECT URP_Profiles WHERE name = :name", ['name' => ADMIN_PROFILE_NAME], true /*all data*/);
|
||||
if (is_object($oAdminProfile)) {
|
||||
$oUserProfile = new URP_UserProfile();
|
||||
$oUserProfile->Set('profileid', $oAdminProfile->GetKey());
|
||||
$oUserProfile->Set('reason', 'By definition, the administrator must have the administrator profile');
|
||||
@@ -509,11 +481,11 @@ class UserRightsProfile extends UserRightsAddOnAPI
|
||||
{
|
||||
}
|
||||
|
||||
protected $m_aUserOrgs = array(); // userid -> array of orgid
|
||||
protected $m_aUserOrgs = []; // userid -> array of orgid
|
||||
protected $m_aAdministrators = null; // [user id]
|
||||
|
||||
// Built on demand, could be optimized if necessary (doing a query for each attribute that needs to be read)
|
||||
protected $m_aObjectActionGrants = array();
|
||||
protected $m_aObjectActionGrants = [];
|
||||
|
||||
/**
|
||||
* Read and cache organizations allowed to the given user
|
||||
@@ -528,31 +500,25 @@ class UserRightsProfile extends UserRightsAddOnAPI
|
||||
public function GetUserOrgs($oUser, $sClass)
|
||||
{
|
||||
$iUser = $oUser->GetKey();
|
||||
if (!array_key_exists($iUser, $this->m_aUserOrgs))
|
||||
{
|
||||
$this->m_aUserOrgs[$iUser] = array();
|
||||
if (!array_key_exists($iUser, $this->m_aUserOrgs)) {
|
||||
$this->m_aUserOrgs[$iUser] = [];
|
||||
|
||||
$sHierarchicalKeyCode = MetaModel::IsHierarchicalClass('Organization');
|
||||
if ($sHierarchicalKeyCode !== false)
|
||||
{
|
||||
if ($sHierarchicalKeyCode !== false) {
|
||||
$sUserOrgQuery = 'SELECT UserOrg, Org FROM Organization AS Org JOIN Organization AS Root ON Org.'.$sHierarchicalKeyCode.' BELOW Root.id JOIN URP_UserOrg AS UserOrg ON UserOrg.allowed_org_id = Root.id WHERE UserOrg.userid = :userid';
|
||||
$oUserOrgSet = new DBObjectSet(DBObjectSearch::FromOQL_AllData($sUserOrgQuery), array(), array('userid' => $iUser));
|
||||
while ($aRow = $oUserOrgSet->FetchAssoc())
|
||||
{
|
||||
$oUserOrgSet = new DBObjectSet(DBObjectSearch::FromOQL_AllData($sUserOrgQuery), [], ['userid' => $iUser]);
|
||||
while ($aRow = $oUserOrgSet->FetchAssoc()) {
|
||||
$oOrg = $aRow['Org'];
|
||||
$this->m_aUserOrgs[$iUser][] = $oOrg->GetKey();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
$oSearch = new DBObjectSearch('URP_UserOrg');
|
||||
$oSearch->AllowAllData();
|
||||
$oCondition = new BinaryExpression(new FieldExpression('userid'), '=', new VariableExpression('userid'));
|
||||
$oSearch->AddConditionExpression($oCondition);
|
||||
|
||||
$oUserOrgSet = new DBObjectSet($oSearch, array(), array('userid' => $iUser));
|
||||
while ($oUserOrg = $oUserOrgSet->Fetch())
|
||||
{
|
||||
$oUserOrgSet = new DBObjectSet($oSearch, [], ['userid' => $iUser]);
|
||||
while ($oUserOrg = $oUserOrgSet->Fetch()) {
|
||||
$this->m_aUserOrgs[$iUser][] = $oUserOrg->Get('allowed_org_id');
|
||||
}
|
||||
}
|
||||
@@ -563,21 +529,19 @@ class UserRightsProfile extends UserRightsAddOnAPI
|
||||
public function ResetCache()
|
||||
{
|
||||
// Loaded by Load cache
|
||||
$this->m_aUserOrgs = array();
|
||||
$this->m_aUserOrgs = [];
|
||||
|
||||
// Cache
|
||||
$this->m_aObjectActionGrants = array();
|
||||
$this->m_aObjectActionGrants = [];
|
||||
$this->m_aAdministrators = null;
|
||||
}
|
||||
|
||||
public function LoadCache()
|
||||
{
|
||||
static $bSharedObjectInitialized = false;
|
||||
if (!$bSharedObjectInitialized)
|
||||
{
|
||||
if (!$bSharedObjectInitialized) {
|
||||
$bSharedObjectInitialized = true;
|
||||
if (self::HasSharing())
|
||||
{
|
||||
if (self::HasSharing()) {
|
||||
SharedObject::InitSharedClassProperties();
|
||||
}
|
||||
}
|
||||
@@ -615,45 +579,40 @@ class UserRightsProfile extends UserRightsAddOnAPI
|
||||
*/
|
||||
public function ListProfiles($oUser)
|
||||
{
|
||||
$aRet = array();
|
||||
$aRet = [];
|
||||
$oSearch = new DBObjectSearch('URP_UserProfile');
|
||||
$oSearch->AllowAllData();
|
||||
$oSearch->NoContextParameters();
|
||||
$oSearch->Addcondition('userid', $oUser->GetKey(), '=');
|
||||
$oProfiles = new DBObjectSet($oSearch);
|
||||
while ($oUserProfile = $oProfiles->Fetch())
|
||||
{
|
||||
while ($oUserProfile = $oProfiles->Fetch()) {
|
||||
$aRet[$oUserProfile->Get('profileid')] = $oUserProfile->Get('profileid_friendlyname');
|
||||
}
|
||||
return $aRet;
|
||||
}
|
||||
|
||||
public function GetSelectFilter($oUser, $sClass, $aSettings = array())
|
||||
public function GetSelectFilter($oUser, $sClass, $aSettings = [])
|
||||
{
|
||||
$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')))
|
||||
{
|
||||
if (!static::IsAdministrator($oUser) && (MetaModel::HasCategory($sClass, 'silo') || MetaModel::HasCategory($sClass, 'bizmodel'))) {
|
||||
// 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)
|
||||
{
|
||||
if ($aObjectPermissions['permission'] == UR_ALLOWED_NO) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
$oFilter = true;
|
||||
$aConditions = array();
|
||||
$aConditions = [];
|
||||
|
||||
// Determine if this class is part of a silo and build the filter for it
|
||||
$sAttCode = self::GetOwnerOrganizationAttCode($sClass);
|
||||
if (!is_null($sAttCode))
|
||||
{
|
||||
if (!is_null($sAttCode)) {
|
||||
$aUserOrgs = $this->GetUserOrgs($oUser, $sClass);
|
||||
if (count($aUserOrgs) > 0)
|
||||
{
|
||||
if (count($aUserOrgs) > 0) {
|
||||
$oFilter = $this->MakeSelectFilter($sClass, $aUserOrgs, $aSettings, $sAttCode);
|
||||
}
|
||||
// else: No org means 'any org'
|
||||
@@ -662,20 +621,15 @@ class UserRightsProfile extends UserRightsAddOnAPI
|
||||
|
||||
// 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())
|
||||
{
|
||||
if ($sClass == 'URP_Profiles')
|
||||
{
|
||||
if ($this->AdministratorsAreHidden()) {
|
||||
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')))
|
||||
{
|
||||
} elseif (($sClass == 'URP_UserProfile') || ($sClass == 'User') || (is_subclass_of($sClass, 'User'))) {
|
||||
$aAdministrators = $this->GetAdministrators();
|
||||
if (count($aAdministrators) > 0)
|
||||
{
|
||||
if (count($aAdministrators) > 0) {
|
||||
$sAttCode = ($sClass == 'URP_UserProfile') ? 'userid' : 'id';
|
||||
$oExpression = new FieldExpression($sAttCode, $sClass);
|
||||
$oListExpr = ListExpression::FromScalars($aAdministrators);
|
||||
@@ -685,17 +639,14 @@ class UserRightsProfile extends UserRightsAddOnAPI
|
||||
}
|
||||
|
||||
// Handling of the added conditions
|
||||
if (count($aConditions) > 0)
|
||||
{
|
||||
if($oFilter === true)
|
||||
{
|
||||
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)
|
||||
{
|
||||
foreach ($aConditions as $oCondition) {
|
||||
$oFilter->AddConditionExpression($oCondition);
|
||||
}
|
||||
}
|
||||
@@ -710,10 +661,9 @@ class UserRightsProfile extends UserRightsAddOnAPI
|
||||
*/
|
||||
private function GetAdministrators()
|
||||
{
|
||||
if ($this->m_aAdministrators === null)
|
||||
{
|
||||
if ($this->m_aAdministrators === null) {
|
||||
// Find all administrators
|
||||
$this->m_aAdministrators = array();
|
||||
$this->m_aAdministrators = [];
|
||||
$oAdministratorsFilter = new DBObjectSearch('User');
|
||||
$oLnkFilter = new DBObjectSearch('URP_UserProfile');
|
||||
$oExpression = new FieldExpression('profileid', 'URP_UserProfile');
|
||||
@@ -723,9 +673,8 @@ class UserRightsProfile extends UserRightsAddOnAPI
|
||||
$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())
|
||||
{
|
||||
$oSet->OptimizeColumnLoad(['User' => ['login']]);
|
||||
while ($oUser = $oSet->Fetch()) {
|
||||
$this->m_aAdministrators[] = $oUser->GetKey();
|
||||
}
|
||||
}
|
||||
@@ -741,7 +690,6 @@ class UserRightsProfile extends UserRightsAddOnAPI
|
||||
return ((bool)MetaModel::GetConfig()->Get('security.hide_administrators'));
|
||||
}
|
||||
|
||||
|
||||
// This verb has been made public to allow the development of an accurate feedback for the current configuration
|
||||
public function GetProfileActionGrant($iProfile, $sClass, $sAction)
|
||||
{
|
||||
@@ -758,33 +706,29 @@ class UserRightsProfile extends UserRightsAddOnAPI
|
||||
// load and cache permissions for the current user on the given class
|
||||
//
|
||||
$iUser = $oUser->GetKey();
|
||||
if (isset($this->m_aObjectActionGrants[$iUser][$sClass][$iActionCode])){
|
||||
if (isset($this->m_aObjectActionGrants[$iUser][$sClass][$iActionCode])) {
|
||||
$aTest = $this->m_aObjectActionGrants[$iUser][$sClass][$iActionCode];
|
||||
if (is_array($aTest)) return $aTest;
|
||||
if (is_array($aTest)) {
|
||||
return $aTest;
|
||||
}
|
||||
}
|
||||
|
||||
$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);
|
||||
// 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($this->aUsersProfilesList[$iUser] as $iProfile => $oProfile)
|
||||
{
|
||||
foreach ($this->aUsersProfilesList[$iUser] as $iProfile => $oProfile) {
|
||||
$bGrant = $this->GetProfileActionGrant($iProfile, $sClass, $sAction);
|
||||
if (!is_null($bGrant))
|
||||
{
|
||||
if ($bGrant)
|
||||
{
|
||||
if (is_null($bStatus))
|
||||
{
|
||||
if (!is_null($bGrant)) {
|
||||
if ($bGrant) {
|
||||
if (is_null($bStatus)) {
|
||||
$bStatus = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
$bStatus = false;
|
||||
}
|
||||
}
|
||||
@@ -792,9 +736,9 @@ class UserRightsProfile extends UserRightsAddOnAPI
|
||||
|
||||
$iPermission = $bStatus ? UR_ALLOWED_YES : UR_ALLOWED_NO;
|
||||
|
||||
$aRes = array(
|
||||
$aRes = [
|
||||
'permission' => $iPermission,
|
||||
);
|
||||
];
|
||||
$this->m_aObjectActionGrants[$iUser][$sClass][$iActionCode] = $aRes;
|
||||
return $aRes;
|
||||
}
|
||||
@@ -809,20 +753,13 @@ class UserRightsProfile extends UserRightsAddOnAPI
|
||||
// Note: In most cases 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
|
||||
|
||||
if ($iPermission != UR_ALLOWED_YES)
|
||||
{
|
||||
if ($iPermission != UR_ALLOWED_YES) {
|
||||
// It is already NO for everyone... that's the final word!
|
||||
}
|
||||
elseif ($iActionCode == UR_ACTION_READ)
|
||||
{
|
||||
} elseif ($iActionCode == UR_ACTION_READ) {
|
||||
// We are protected by GetSelectFilter: the object set contains objects allowed or shared for reading
|
||||
}
|
||||
elseif ($iActionCode == UR_ACTION_BULK_READ)
|
||||
{
|
||||
} elseif ($iActionCode == UR_ACTION_BULK_READ) {
|
||||
// We are protected by GetSelectFilter: the object set contains objects allowed or shared for reading
|
||||
}
|
||||
elseif ($oInstanceSet)
|
||||
{
|
||||
} elseif ($oInstanceSet) {
|
||||
// We are protected by GetSelectFilter: the object set contains objects allowed or shared for reading
|
||||
// We have to answer NO for objects shared for reading purposes
|
||||
if (self::HasSharing() && SharedObject::GetSharedClassProperties($sClass)) {
|
||||
@@ -886,8 +823,8 @@ 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)){
|
||||
// Cache user's profiles
|
||||
if (false === array_key_exists($iUser, $this->aUsersProfilesList)) {
|
||||
$this->aUsersProfilesList[$iUser] = UserRights::ListProfiles($oUser);
|
||||
}
|
||||
|
||||
@@ -895,20 +832,14 @@ class UserRightsProfile extends UserRightsAddOnAPI
|
||||
// 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($this->aUsersProfilesList[$iUser] as $iProfile => $oProfile)
|
||||
{
|
||||
foreach ($this->aUsersProfilesList[$iUser] as $iProfile => $oProfile) {
|
||||
$bGrant = $this->GetClassStimulusGrant($iProfile, $sClass, $sStimulusCode);
|
||||
if (!is_null($bGrant))
|
||||
{
|
||||
if ($bGrant)
|
||||
{
|
||||
if (is_null($bStatus))
|
||||
{
|
||||
if (!is_null($bGrant)) {
|
||||
if ($bGrant) {
|
||||
if (is_null($bStatus)) {
|
||||
$bStatus = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
$bStatus = false;
|
||||
}
|
||||
}
|
||||
@@ -932,22 +863,16 @@ class UserRightsProfile extends UserRightsAddOnAPI
|
||||
{
|
||||
$sAttCode = null;
|
||||
|
||||
$aCallSpec = array($sClass, 'MapContextParam');
|
||||
if (($sClass == 'Organization') || is_subclass_of($sClass, 'Organization'))
|
||||
{
|
||||
$aCallSpec = [$sClass, 'MapContextParam'];
|
||||
if (($sClass == 'Organization') || is_subclass_of($sClass, 'Organization')) {
|
||||
$sAttCode = 'id';
|
||||
}
|
||||
elseif (is_callable($aCallSpec))
|
||||
{
|
||||
} elseif (is_callable($aCallSpec)) {
|
||||
$sAttCode = call_user_func($aCallSpec, 'org_id'); // Returns null when there is no mapping for this parameter
|
||||
if (!MetaModel::IsValidAttCode($sClass, $sAttCode))
|
||||
{
|
||||
if (!MetaModel::IsValidAttCode($sClass, $sAttCode)) {
|
||||
// Skip silently. The data model checker will tell you something about this...
|
||||
$sAttCode = null;
|
||||
}
|
||||
}
|
||||
elseif(MetaModel::IsValidAttCode($sClass, 'org_id'))
|
||||
{
|
||||
} elseif (MetaModel::IsValidAttCode($sClass, 'org_id')) {
|
||||
$sAttCode = 'org_id';
|
||||
}
|
||||
|
||||
@@ -960,14 +885,11 @@ class UserRightsProfile extends UserRightsAddOnAPI
|
||||
protected static function HasSharing()
|
||||
{
|
||||
static $bHasSharing;
|
||||
if (!isset($bHasSharing))
|
||||
{
|
||||
if (!isset($bHasSharing)) {
|
||||
$bHasSharing = class_exists('SharedObject');
|
||||
}
|
||||
return $bHasSharing;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
UserRights::SelectModule('UserRightsProfile');
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
3
app.php
3
app.php
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Copyright (C) 2013-2024 Combodo SAS
|
||||
*
|
||||
@@ -25,5 +26,5 @@ require_once('approot.inc.php');
|
||||
require_once('application/startup.inc.php');
|
||||
|
||||
return function (array $context) {
|
||||
return new Kernel($context['APP_ENV'], (bool) $context['APP_DEBUG']);
|
||||
return new Kernel($context['APP_ENV'], (bool) $context['APP_DEBUG']);
|
||||
};
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* @copyright Copyright (C) 2010-2024 Combodo SAS
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
@@ -48,8 +49,7 @@ class DBSearchHelper
|
||||
$oHKFilter->AddCondition_PointingTo($oFilter, $sHierarchicalKeyCode, TREE_OPERATOR_BELOW);
|
||||
$oSearch->AddCondition_PointingTo($oHKFilter, $sAttCode);
|
||||
}
|
||||
}
|
||||
catch (Exception $e) {
|
||||
} catch (Exception $e) {
|
||||
// If filtering fails just ignore it
|
||||
}
|
||||
}
|
||||
@@ -57,4 +57,4 @@ class DBSearchHelper
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @deprecated 3.0.0 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
|
||||
@@ -16,10 +17,9 @@ use Combodo\iTop\Application\WebPage\AjaxPage;
|
||||
*/
|
||||
class ajax_page extends AjaxPage
|
||||
{
|
||||
function __construct($s_title)
|
||||
public function __construct($s_title)
|
||||
{
|
||||
DeprecatedCallsLog::NotifyDeprecatedPhpMethod('ajax_page is deprecated. Please use AjaxPage instead');
|
||||
parent::__construct($s_title);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* @copyright Copyright (C) 2010-2024 Combodo SAS
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
<?php
|
||||
|
||||
// Copyright (C) 2010-2024 Combodo SAS
|
||||
//
|
||||
// This file is part of iTop.
|
||||
//
|
||||
// iTop is free software; you can redistribute it and/or modify
|
||||
// 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.
|
||||
@@ -16,7 +17,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/>
|
||||
|
||||
|
||||
/**
|
||||
* Class ApplicationContext
|
||||
*
|
||||
@@ -47,16 +47,16 @@ interface iDBObjectURLMaker
|
||||
|
||||
/**
|
||||
* Direct end-users to the standard iTop application: UI.php
|
||||
*/
|
||||
*/
|
||||
class iTopStandardURLMaker implements iDBObjectURLMaker
|
||||
{
|
||||
/**
|
||||
* @param string $sClass
|
||||
* @param string $iId
|
||||
*
|
||||
* @return string
|
||||
* @throws \Exception
|
||||
*/
|
||||
/**
|
||||
* @param string $sClass
|
||||
* @param string $iId
|
||||
*
|
||||
* @return string
|
||||
* @throws \Exception
|
||||
*/
|
||||
public static function MakeObjectURL($sClass, $iId)
|
||||
{
|
||||
$sPage = DBObject::ComputeStandardUIPage($sClass);
|
||||
@@ -68,16 +68,16 @@ class iTopStandardURLMaker implements iDBObjectURLMaker
|
||||
|
||||
/**
|
||||
* Direct end-users to the standard Portal application
|
||||
*/
|
||||
*/
|
||||
class PortalURLMaker implements iDBObjectURLMaker
|
||||
{
|
||||
/**
|
||||
* @param string $sClass
|
||||
* @param string $iId
|
||||
*
|
||||
* @return string
|
||||
* @throws \Exception
|
||||
*/
|
||||
/**
|
||||
* @param string $sClass
|
||||
* @param string $iId
|
||||
*
|
||||
* @return string
|
||||
* @throws \Exception
|
||||
*/
|
||||
public static function MakeObjectURL($sClass, $iId)
|
||||
{
|
||||
$sAbsoluteUrl = utils::GetAbsoluteUrlAppRoot();
|
||||
@@ -86,7 +86,6 @@ class PortalURLMaker implements iDBObjectURLMaker
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Helper class to store and manipulate the parameters that make the application's context
|
||||
*
|
||||
@@ -99,99 +98,90 @@ class PortalURLMaker implements iDBObjectURLMaker
|
||||
*/
|
||||
class ApplicationContext
|
||||
{
|
||||
public static $m_sUrlMakerClass = null;
|
||||
protected static $m_aPluginProperties = null;
|
||||
protected static $aDefaultValues; // Cache shared among all instances
|
||||
public static $m_sUrlMakerClass = null;
|
||||
protected static $m_aPluginProperties = null;
|
||||
protected static $aDefaultValues; // Cache shared among all instances
|
||||
|
||||
protected $aNames;
|
||||
protected $aValues;
|
||||
|
||||
/**
|
||||
* ApplicationContext constructor.
|
||||
*
|
||||
* @param bool $bReadContext
|
||||
*
|
||||
* @throws \Exception
|
||||
*/
|
||||
/**
|
||||
* ApplicationContext constructor.
|
||||
*
|
||||
* @param bool $bReadContext
|
||||
*
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function __construct($bReadContext = true)
|
||||
{
|
||||
$this->aNames = array(
|
||||
'org_id', 'menu'
|
||||
);
|
||||
if ($bReadContext)
|
||||
{
|
||||
$this->ReadContext();
|
||||
$this->aNames = [
|
||||
'org_id', 'menu',
|
||||
];
|
||||
if ($bReadContext) {
|
||||
$this->ReadContext();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Read the context directly in the PHP parameters (either POST or GET)
|
||||
* return nothing
|
||||
*
|
||||
* @throws \Exception
|
||||
*/
|
||||
/**
|
||||
* Read the context directly in the PHP parameters (either POST or GET)
|
||||
* return nothing
|
||||
*
|
||||
* @throws \Exception
|
||||
*/
|
||||
protected function ReadContext()
|
||||
{
|
||||
if (!isset(self::$aDefaultValues))
|
||||
{
|
||||
self::$aDefaultValues = array();
|
||||
$aContext = utils::ReadParam('c', array(), false, 'context_param');
|
||||
foreach($this->aNames as $sName)
|
||||
{
|
||||
if (!isset(self::$aDefaultValues)) {
|
||||
self::$aDefaultValues = [];
|
||||
$aContext = utils::ReadParam('c', [], false, 'context_param');
|
||||
foreach ($this->aNames as $sName) {
|
||||
$sValue = isset($aContext[$sName]) ? $aContext[$sName] : '';
|
||||
// TO DO: check if some of the context parameters are mandatory (or have default values)
|
||||
if (!empty($sValue))
|
||||
{
|
||||
if (!empty($sValue)) {
|
||||
self::$aDefaultValues[$sName] = $sValue;
|
||||
}
|
||||
// Hmm, there must be a better (more generic) way to handle the case below:
|
||||
// When there is only one possible (allowed) organization, the context must be
|
||||
// fixed to this org unless there is only one organization in the system then
|
||||
// no filter is applied
|
||||
if ($sName == 'org_id')
|
||||
{
|
||||
if (MetaModel::IsValidClass('Organization'))
|
||||
{
|
||||
if ($sName == 'org_id') {
|
||||
if (MetaModel::IsValidClass('Organization')) {
|
||||
$oSearchFilter = new DBObjectSearch('Organization');
|
||||
$oSet = new CMDBObjectSet($oSearchFilter);
|
||||
$iCount = $oSet->CountWithLimit(2);
|
||||
if ($iCount > 1)
|
||||
{
|
||||
if ($iCount > 1) {
|
||||
$oSearchFilter->SetModifierProperty('UserRightsGetSelectFilter', 'bSearchMode', true);
|
||||
$oSet = new CMDBObjectSet($oSearchFilter);
|
||||
$iCount = $oSet->CountWithLimit(2);
|
||||
if ($iCount == 1)
|
||||
{
|
||||
if ($iCount == 1) {
|
||||
// Only one possible value for org_id, set it in the context
|
||||
$oOrg = $oSet->Fetch();
|
||||
self::$aDefaultValues[$sName] = $oOrg->GetKey();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
$this->aValues = self::$aDefaultValues;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current value for the given parameter
|
||||
*
|
||||
* @param string $sParamName Name of the parameter to read
|
||||
* @param string $defaultValue
|
||||
*
|
||||
* @return mixed The value for this parameter
|
||||
*/
|
||||
/**
|
||||
* Returns the current value for the given parameter
|
||||
*
|
||||
* @param string $sParamName Name of the parameter to read
|
||||
* @param string $defaultValue
|
||||
*
|
||||
* @return mixed The value for this parameter
|
||||
*/
|
||||
public function GetCurrentValue($sParamName, $defaultValue = '')
|
||||
{
|
||||
if (isset($this->aValues[$sParamName]))
|
||||
{
|
||||
if (isset($this->aValues[$sParamName])) {
|
||||
return $this->aValues[$sParamName];
|
||||
}
|
||||
return $defaultValue;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the context as string with the format name1=value1&name2=value2....
|
||||
* @return string The context as a string to be appended to an href property
|
||||
@@ -200,21 +190,20 @@ class ApplicationContext
|
||||
public function GetForLink(bool $bWithLeadingAmpersand = false)
|
||||
{
|
||||
// If there are no parameters, return an empty string
|
||||
if(empty($this->aValues)){
|
||||
if (empty($this->aValues)) {
|
||||
return '';
|
||||
}
|
||||
|
||||
// Build the query string with ampersand separated parameters
|
||||
$aParams = array();
|
||||
foreach($this->aValues as $sName => $sValue)
|
||||
{
|
||||
$aParams = [];
|
||||
foreach ($this->aValues as $sName => $sValue) {
|
||||
$aParams[] = "c[$sName]".'='.urlencode($sValue);
|
||||
}
|
||||
$sReturnValue = implode('&', $aParams);
|
||||
|
||||
// add the leading ampersand if requested
|
||||
if($bWithLeadingAmpersand){
|
||||
$sReturnValue = '&' . $sReturnValue;
|
||||
if ($bWithLeadingAmpersand) {
|
||||
$sReturnValue = '&'.$sReturnValue;
|
||||
}
|
||||
|
||||
return $sReturnValue;
|
||||
@@ -278,14 +267,13 @@ class ApplicationContext
|
||||
*/
|
||||
public function GetAsHash()
|
||||
{
|
||||
$aReturn = array();
|
||||
foreach($this->aValues as $sName => $sValue)
|
||||
{
|
||||
$aReturn = [];
|
||||
foreach ($this->aValues as $sName => $sValue) {
|
||||
$aReturn["c[$sName]"] = $sValue;
|
||||
}
|
||||
return $aReturn;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns an array of the context parameters NAMEs
|
||||
* @return array The list of context parameters
|
||||
@@ -298,11 +286,10 @@ class ApplicationContext
|
||||
* Removes the specified parameter from the context, for example when the same parameter
|
||||
* is already a search parameter
|
||||
* @param string $sParamName Name of the parameter to remove
|
||||
*/
|
||||
*/
|
||||
public function Reset($sParamName)
|
||||
{
|
||||
if (isset($this->aValues[$sParamName]))
|
||||
{
|
||||
if (isset($this->aValues[$sParamName])) {
|
||||
unset($this->aValues[$sParamName]);
|
||||
}
|
||||
}
|
||||
@@ -318,27 +305,22 @@ class ApplicationContext
|
||||
public function InitObjectFromContext(DBObject &$oObj)
|
||||
{
|
||||
$sClass = get_class($oObj);
|
||||
foreach($this->GetNames() as $key)
|
||||
{
|
||||
$aCallSpec = array($sClass, 'MapContextParam');
|
||||
if (is_callable($aCallSpec))
|
||||
{
|
||||
$sAttCode = call_user_func($aCallSpec, $key); // Returns null when there is no mapping for this parameter
|
||||
foreach ($this->GetNames() as $key) {
|
||||
$aCallSpec = [$sClass, 'MapContextParam'];
|
||||
if (is_callable($aCallSpec)) {
|
||||
$sAttCode = call_user_func($aCallSpec, $key); // Returns null when there is no mapping for this parameter
|
||||
|
||||
if (MetaModel::IsValidAttCode($sClass, $sAttCode))
|
||||
{
|
||||
if (MetaModel::IsValidAttCode($sClass, $sAttCode)) {
|
||||
$oAttDef = MetaModel::GetAttributeDef($sClass, $sAttCode);
|
||||
if ($oAttDef->IsWritable())
|
||||
{
|
||||
if ($oAttDef->IsWritable()) {
|
||||
$value = $this->GetCurrentValue($key, null);
|
||||
if (!is_null($value))
|
||||
{
|
||||
if (!is_null($value)) {
|
||||
$oObj->Set($sAttCode, $value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -362,14 +344,10 @@ class ApplicationContext
|
||||
*/
|
||||
public static function GetUrlMakerClass()
|
||||
{
|
||||
if (is_null(self::$m_sUrlMakerClass))
|
||||
{
|
||||
if (Session::IsSet('UrlMakerClass'))
|
||||
{
|
||||
if (is_null(self::$m_sUrlMakerClass)) {
|
||||
if (Session::IsSet('UrlMakerClass')) {
|
||||
self::$m_sUrlMakerClass = Session::Get('UrlMakerClass');
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
self::$m_sUrlMakerClass = 'iTopStandardURLMaker';
|
||||
}
|
||||
}
|
||||
@@ -387,23 +365,23 @@ class ApplicationContext
|
||||
* @return string the name of the class
|
||||
* @throws \Exception
|
||||
*/
|
||||
public static function MakeObjectUrl($sObjClass, $sObjKey, $sUrlMakerClass = null, $bWithNavigationContext = true)
|
||||
{
|
||||
$oAppContext = new ApplicationContext();
|
||||
public static function MakeObjectUrl($sObjClass, $sObjKey, $sUrlMakerClass = null, $bWithNavigationContext = true)
|
||||
{
|
||||
$oAppContext = new ApplicationContext();
|
||||
|
||||
if (is_null($sUrlMakerClass)) {
|
||||
$sUrlMakerClass = self::GetUrlMakerClass();
|
||||
}
|
||||
$sUrl = call_user_func(array($sUrlMakerClass, 'MakeObjectUrl'), $sObjClass, $sObjKey);
|
||||
if (utils::StrLen($sUrl) > 0) {
|
||||
if ($bWithNavigationContext) {
|
||||
return $sUrl.$oAppContext->GetForLink(true);
|
||||
} else {
|
||||
return $sUrl;
|
||||
}
|
||||
} else {
|
||||
return '';
|
||||
}
|
||||
if (is_null($sUrlMakerClass)) {
|
||||
$sUrlMakerClass = self::GetUrlMakerClass();
|
||||
}
|
||||
$sUrl = call_user_func([$sUrlMakerClass, 'MakeObjectUrl'], $sObjClass, $sObjKey);
|
||||
if (utils::StrLen($sUrl) > 0) {
|
||||
if ($bWithNavigationContext) {
|
||||
return $sUrl.$oAppContext->GetForLink(true);
|
||||
} else {
|
||||
return $sUrl;
|
||||
}
|
||||
} else {
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -412,13 +390,10 @@ class ApplicationContext
|
||||
*/
|
||||
protected static function LoadPluginProperties()
|
||||
{
|
||||
if (Session::IsSet('PluginProperties'))
|
||||
{
|
||||
if (Session::IsSet('PluginProperties')) {
|
||||
self::$m_aPluginProperties = Session::Get('PluginProperties');
|
||||
}
|
||||
else
|
||||
{
|
||||
self::$m_aPluginProperties = array();
|
||||
} else {
|
||||
self::$m_aPluginProperties = [];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -431,7 +406,9 @@ class ApplicationContext
|
||||
*/
|
||||
public static function SetPluginProperty($sPluginClass, $sProperty, $value)
|
||||
{
|
||||
if (is_null(self::$m_aPluginProperties)) self::LoadPluginProperties();
|
||||
if (is_null(self::$m_aPluginProperties)) {
|
||||
self::LoadPluginProperties();
|
||||
}
|
||||
|
||||
self::$m_aPluginProperties[$sPluginClass][$sProperty] = $value;
|
||||
Session::Set(['PluginProperties', $sPluginClass, $sProperty], $value);
|
||||
@@ -444,15 +421,14 @@ class ApplicationContext
|
||||
*/
|
||||
public static function GetPluginProperties($sPluginClass)
|
||||
{
|
||||
if (is_null(self::$m_aPluginProperties)) self::LoadPluginProperties();
|
||||
|
||||
if (array_key_exists($sPluginClass, self::$m_aPluginProperties))
|
||||
{
|
||||
return self::$m_aPluginProperties[$sPluginClass];
|
||||
if (is_null(self::$m_aPluginProperties)) {
|
||||
self::LoadPluginProperties();
|
||||
}
|
||||
else
|
||||
{
|
||||
return array();
|
||||
|
||||
if (array_key_exists($sPluginClass, self::$m_aPluginProperties)) {
|
||||
return self::$m_aPluginProperties[$sPluginClass];
|
||||
} else {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -524,7 +524,7 @@ abstract class AbstractApplicationUIExtension implements iApplicationUIExtension
|
||||
*/
|
||||
public function EnumUsedAttributes($oObject)
|
||||
{
|
||||
return array();
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -548,7 +548,7 @@ abstract class AbstractApplicationUIExtension implements iApplicationUIExtension
|
||||
*/
|
||||
public function EnumAllowedActions(DBObjectSet $oSet)
|
||||
{
|
||||
return array();
|
||||
return [];
|
||||
}
|
||||
|
||||
}
|
||||
@@ -686,7 +686,7 @@ abstract class AbstractApplicationObjectExtension implements iApplicationObjectE
|
||||
*/
|
||||
public function OnCheckToWrite($oObject)
|
||||
{
|
||||
return array();
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -694,7 +694,7 @@ abstract class AbstractApplicationObjectExtension implements iApplicationObjectE
|
||||
*/
|
||||
public function OnCheckToDelete($oObject)
|
||||
{
|
||||
return array();
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -739,21 +739,21 @@ interface iPopupMenuExtension
|
||||
* $param is a DBObjectSet containing the list of objects
|
||||
* @api
|
||||
*/
|
||||
const MENU_OBJLIST_ACTIONS = 1;
|
||||
public const MENU_OBJLIST_ACTIONS = 1;
|
||||
/**
|
||||
* Insert an item into the Toolkit menu of a list
|
||||
*
|
||||
* $param is a DBObjectSet containing the list of objects
|
||||
* @api
|
||||
*/
|
||||
const MENU_OBJLIST_TOOLKIT = 2;
|
||||
public const MENU_OBJLIST_TOOLKIT = 2;
|
||||
/**
|
||||
* Insert an item into the Actions menu on an object details page
|
||||
*
|
||||
* $param is a DBObject instance: the object currently displayed
|
||||
* @api
|
||||
*/
|
||||
const MENU_OBJDETAILS_ACTIONS = 3;
|
||||
public const MENU_OBJDETAILS_ACTIONS = 3;
|
||||
/**
|
||||
* Insert an item into the Dashboard menu
|
||||
*
|
||||
@@ -763,14 +763,14 @@ interface iPopupMenuExtension
|
||||
* $param is a Dashboard instance: the dashboard currently displayed
|
||||
* @api
|
||||
*/
|
||||
const MENU_DASHBOARD_ACTIONS = 4;
|
||||
public const MENU_DASHBOARD_ACTIONS = 4;
|
||||
/**
|
||||
* Insert an item into the User menu (upper right corner)
|
||||
*
|
||||
* $param is null
|
||||
* @api
|
||||
*/
|
||||
const MENU_USER_ACTIONS = 5;
|
||||
public const MENU_USER_ACTIONS = 5;
|
||||
/**
|
||||
* Insert an item into the Action menu on an object item in an objects list in the portal
|
||||
*
|
||||
@@ -778,7 +778,7 @@ interface iPopupMenuExtension
|
||||
* the current line)
|
||||
* @api
|
||||
*/
|
||||
const PORTAL_OBJLISTITEM_ACTIONS = 7;
|
||||
public const PORTAL_OBJLISTITEM_ACTIONS = 7;
|
||||
/**
|
||||
* Insert an item into the Action menu on an object details page in the portal
|
||||
*
|
||||
@@ -786,7 +786,7 @@ interface iPopupMenuExtension
|
||||
* currently displayed)
|
||||
* @api
|
||||
*/
|
||||
const PORTAL_OBJDETAILS_ACTIONS = 8;
|
||||
public const PORTAL_OBJDETAILS_ACTIONS = 8;
|
||||
|
||||
/**
|
||||
* Insert an item into the Actions menu of a list in the portal
|
||||
@@ -796,7 +796,7 @@ interface iPopupMenuExtension
|
||||
*
|
||||
* @todo
|
||||
*/
|
||||
const PORTAL_OBJLIST_ACTIONS = 6;
|
||||
public const PORTAL_OBJLIST_ACTIONS = 6;
|
||||
/**
|
||||
* Insert an item into the user menu of the portal
|
||||
* Note: This is not implemented yet !
|
||||
@@ -805,7 +805,7 @@ interface iPopupMenuExtension
|
||||
*
|
||||
* @todo
|
||||
*/
|
||||
const PORTAL_USER_ACTIONS = 9;
|
||||
public const PORTAL_USER_ACTIONS = 9;
|
||||
/**
|
||||
* Insert an item into the navigation menu of the portal
|
||||
* Note: This is not implemented yet !
|
||||
@@ -814,7 +814,7 @@ interface iPopupMenuExtension
|
||||
*
|
||||
* @todo
|
||||
*/
|
||||
const PORTAL_MENU_ACTIONS = 10;
|
||||
public const PORTAL_MENU_ACTIONS = 10;
|
||||
|
||||
/**
|
||||
* Get the list of items to be added to a menu.
|
||||
@@ -864,7 +864,7 @@ abstract class ApplicationPopupMenuItem
|
||||
$this->sLabel = $sLabel;
|
||||
$this->sTooltip = '';
|
||||
$this->sIconClass = '';
|
||||
$this->aCssClasses = array();
|
||||
$this->aCssClasses = [];
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -920,7 +920,6 @@ abstract class ApplicationPopupMenuItem
|
||||
$this->aCssClasses[] = $sCssClass;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $sTooltip
|
||||
*
|
||||
@@ -976,7 +975,7 @@ abstract class ApplicationPopupMenuItem
|
||||
/** @ignore */
|
||||
public function GetLinkedScripts()
|
||||
{
|
||||
return array();
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1015,13 +1014,13 @@ class URLPopupMenuItem extends ApplicationPopupMenuItem
|
||||
/** @ignore */
|
||||
public function GetMenuItem()
|
||||
{
|
||||
return array('label' => $this->GetLabel(),
|
||||
return ['label' => $this->GetLabel(),
|
||||
'url' => $this->GetUrl(),
|
||||
'target' => $this-> GetTarget(),
|
||||
'css_classes' => $this->aCssClasses,
|
||||
'icon_class' => $this->sIconClass,
|
||||
'tooltip' => $this->sTooltip
|
||||
);
|
||||
'tooltip' => $this->sTooltip,
|
||||
];
|
||||
}
|
||||
|
||||
/** @ignore */
|
||||
@@ -1065,7 +1064,7 @@ class JSPopupMenuItem extends ApplicationPopupMenuItem
|
||||
* ans $sTarget will be ignored
|
||||
* @param array $aIncludeJSFiles An array of file URLs to be included (once) to provide some JS libraries for the page.
|
||||
*/
|
||||
public function __construct($sUID, $sLabel, $sJSCode, $aIncludeJSFiles = array())
|
||||
public function __construct($sUID, $sLabel, $sJSCode, $aIncludeJSFiles = [])
|
||||
{
|
||||
parent::__construct($sUID, $sLabel);
|
||||
$this->sJsCode = $sJSCode;
|
||||
@@ -1077,14 +1076,14 @@ class JSPopupMenuItem extends ApplicationPopupMenuItem
|
||||
public function GetMenuItem()
|
||||
{
|
||||
// Note: the semicolumn is a must here!
|
||||
return array(
|
||||
return [
|
||||
'label' => $this->GetLabel(),
|
||||
'onclick' => $this->GetJsCode().'; return false;',
|
||||
'url' => $this->GetUrl(),
|
||||
'css_classes' => $this->GetCssClasses(),
|
||||
'icon_class' => $this->sIconClass,
|
||||
'tooltip' => $this->sTooltip
|
||||
);
|
||||
'tooltip' => $this->sTooltip,
|
||||
];
|
||||
}
|
||||
|
||||
/** @ignore */
|
||||
@@ -1116,7 +1115,7 @@ class JSPopupMenuItem extends ApplicationPopupMenuItem
|
||||
*/
|
||||
class SeparatorPopupMenuItem extends ApplicationPopupMenuItem
|
||||
{
|
||||
static $idx = 0;
|
||||
public static $idx = 0;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
@@ -1130,7 +1129,7 @@ class SeparatorPopupMenuItem extends ApplicationPopupMenuItem
|
||||
/** @ignore */
|
||||
public function GetMenuItem()
|
||||
{
|
||||
return array('label' => '<hr class="menu-separator">', 'url' => '', 'css_classes' => $this->aCssClasses);
|
||||
return ['label' => '<hr class="menu-separator">', 'url' => '', 'css_classes' => $this->aCssClasses];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1143,7 +1142,6 @@ class SeparatorPopupMenuItem extends ApplicationPopupMenuItem
|
||||
*/
|
||||
class URLButtonItem extends URLPopupMenuItem
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1155,7 +1153,6 @@ class URLButtonItem extends URLPopupMenuItem
|
||||
*/
|
||||
class JSButtonItem extends JSPopupMenuItem
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1504,9 +1501,9 @@ interface iBackofficeDictEntriesPrefixesExtension
|
||||
*/
|
||||
interface iPortalUIExtension
|
||||
{
|
||||
const ENUM_PORTAL_EXT_UI_BODY = 'Body';
|
||||
const ENUM_PORTAL_EXT_UI_NAVIGATION_MENU = 'NavigationMenu';
|
||||
const ENUM_PORTAL_EXT_UI_MAIN_CONTENT = 'MainContent';
|
||||
public const ENUM_PORTAL_EXT_UI_BODY = 'Body';
|
||||
public const ENUM_PORTAL_EXT_UI_NAVIGATION_MENU = 'NavigationMenu';
|
||||
public const ENUM_PORTAL_EXT_UI_MAIN_CONTENT = 'MainContent';
|
||||
|
||||
/**
|
||||
* Returns an array of CSS file urls
|
||||
@@ -1593,7 +1590,7 @@ abstract class AbstractPortalUIExtension implements iPortalUIExtension
|
||||
*/
|
||||
public function GetCSSFiles(Container $oContainer)
|
||||
{
|
||||
return array();
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1609,7 +1606,7 @@ abstract class AbstractPortalUIExtension implements iPortalUIExtension
|
||||
*/
|
||||
public function GetJSFiles(Container $oContainer)
|
||||
{
|
||||
return array();
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1729,62 +1726,62 @@ class RestResult
|
||||
* Result: no issue has been encountered
|
||||
* @api
|
||||
*/
|
||||
const OK = 0;
|
||||
public const OK = 0;
|
||||
/**
|
||||
* Result: missing/wrong credentials or the user does not have enough rights to perform the requested operation
|
||||
* @api
|
||||
*/
|
||||
const UNAUTHORIZED = 1;
|
||||
public const UNAUTHORIZED = 1;
|
||||
/**
|
||||
* Result: the parameter 'version' is missing
|
||||
* @api
|
||||
*/
|
||||
const MISSING_VERSION = 2;
|
||||
public const MISSING_VERSION = 2;
|
||||
/**
|
||||
* Result: the parameter 'json_data' is missing
|
||||
* @api
|
||||
*/
|
||||
const MISSING_JSON = 3;
|
||||
public const MISSING_JSON = 3;
|
||||
/**
|
||||
* Result: the input structure is not a valid JSON string
|
||||
* @api
|
||||
*/
|
||||
const INVALID_JSON = 4;
|
||||
public const INVALID_JSON = 4;
|
||||
/**
|
||||
* Result: the parameter 'auth_user' is missing, authentication aborted
|
||||
* @api
|
||||
*/
|
||||
const MISSING_AUTH_USER = 5;
|
||||
public const MISSING_AUTH_USER = 5;
|
||||
/**
|
||||
* Result: the parameter 'auth_pwd' is missing, authentication aborted
|
||||
* @api
|
||||
*/
|
||||
const MISSING_AUTH_PWD = 6;
|
||||
public const MISSING_AUTH_PWD = 6;
|
||||
/**
|
||||
* Result: no operation is available for the specified version
|
||||
* @api
|
||||
*/
|
||||
const UNSUPPORTED_VERSION = 10;
|
||||
public const UNSUPPORTED_VERSION = 10;
|
||||
/**
|
||||
* Result: the requested operation is not valid for the specified version
|
||||
* @api
|
||||
*/
|
||||
const UNKNOWN_OPERATION = 11;
|
||||
public const UNKNOWN_OPERATION = 11;
|
||||
/**
|
||||
* Result: the requested operation cannot be performed because it can cause data (integrity) loss
|
||||
* @api
|
||||
*/
|
||||
const UNSAFE = 12;
|
||||
public const UNSAFE = 12;
|
||||
/**
|
||||
* Result: the request page number is not valid. It must be an integer greater than 0
|
||||
* @api
|
||||
*/
|
||||
const INVALID_PAGE = 13;
|
||||
public const INVALID_PAGE = 13;
|
||||
/**
|
||||
* Result: the operation could not be performed, see the message for troubleshooting
|
||||
* @api
|
||||
*/
|
||||
const INTERNAL_ERROR = 100;
|
||||
public const INTERNAL_ERROR = 100;
|
||||
|
||||
/**
|
||||
* Default constructor - ok!
|
||||
@@ -1807,7 +1804,7 @@ class RestResult
|
||||
* @api
|
||||
*/
|
||||
public $message;
|
||||
|
||||
|
||||
/**
|
||||
* Sanitize the content of this result to hide sensitive information
|
||||
*/
|
||||
@@ -1854,17 +1851,13 @@ class RestUtils
|
||||
*/
|
||||
public static function GetMandatoryParam($oData, $sParamName)
|
||||
{
|
||||
if (isset($oData->$sParamName))
|
||||
{
|
||||
if (isset($oData->$sParamName)) {
|
||||
return $oData->$sParamName;
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
throw new Exception("Missing parameter '$sParamName'");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Read an optional parameter from a Rest/Json structure.
|
||||
*
|
||||
@@ -1879,17 +1872,13 @@ class RestUtils
|
||||
*/
|
||||
public static function GetOptionalParam($oData, $sParamName, $default)
|
||||
{
|
||||
if (isset($oData->$sParamName))
|
||||
{
|
||||
if (isset($oData->$sParamName)) {
|
||||
return $oData->$sParamName;
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
return $default;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Read a class from a Rest/Json structure.
|
||||
*
|
||||
@@ -1903,15 +1892,13 @@ class RestUtils
|
||||
public static function GetClass($oData, $sParamName)
|
||||
{
|
||||
$sClass = self::GetMandatoryParam($oData, $sParamName);
|
||||
if (!MetaModel::IsValidClass($sClass))
|
||||
{
|
||||
if (!MetaModel::IsValidClass($sClass)) {
|
||||
throw new Exception("$sParamName: '$sClass' is not a valid class'");
|
||||
}
|
||||
|
||||
return $sClass;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Read a list of attribute codes from a Rest/Json structure.
|
||||
*
|
||||
@@ -1927,31 +1914,21 @@ class RestUtils
|
||||
public static function GetFieldList($sClass, $oData, $sParamName)
|
||||
{
|
||||
$sFields = self::GetOptionalParam($oData, $sParamName, '*');
|
||||
$aShowFields = array();
|
||||
if ($sFields == '*')
|
||||
{
|
||||
foreach (MetaModel::ListAttributeDefs($sClass) as $sAttCode => $oAttDef)
|
||||
{
|
||||
$aShowFields = [];
|
||||
if ($sFields == '*') {
|
||||
foreach (MetaModel::ListAttributeDefs($sClass) as $sAttCode => $oAttDef) {
|
||||
$aShowFields[$sClass][] = $sAttCode;
|
||||
}
|
||||
}
|
||||
elseif ($sFields == '*+')
|
||||
{
|
||||
foreach (MetaModel::EnumChildClasses($sClass, ENUM_CHILD_CLASSES_ALL) as $sRefClass)
|
||||
{
|
||||
foreach (MetaModel::ListAttributeDefs($sRefClass) as $sAttCode => $oAttDef)
|
||||
{
|
||||
} elseif ($sFields == '*+') {
|
||||
foreach (MetaModel::EnumChildClasses($sClass, ENUM_CHILD_CLASSES_ALL) as $sRefClass) {
|
||||
foreach (MetaModel::ListAttributeDefs($sRefClass) as $sAttCode => $oAttDef) {
|
||||
$aShowFields[$sRefClass][] = $sAttCode;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (explode(',', $sFields) as $sAttCode)
|
||||
{
|
||||
} else {
|
||||
foreach (explode(',', $sFields) as $sAttCode) {
|
||||
$sAttCode = trim($sAttCode);
|
||||
if (($sAttCode != 'id') && (!MetaModel::IsValidAttCode($sClass, $sAttCode)))
|
||||
{
|
||||
if (($sAttCode != 'id') && (!MetaModel::IsValidAttCode($sClass, $sAttCode))) {
|
||||
throw new Exception("$sParamName: invalid attribute code '$sAttCode'");
|
||||
}
|
||||
$aShowFields[$sClass][] = $sAttCode;
|
||||
@@ -1974,38 +1951,30 @@ class RestUtils
|
||||
*/
|
||||
protected static function FindObjectFromCriteria($sClass, $oCriteria)
|
||||
{
|
||||
$aCriteriaReport = array();
|
||||
if (isset($oCriteria->finalclass))
|
||||
{
|
||||
if (!MetaModel::IsValidClass($oCriteria->finalclass))
|
||||
{
|
||||
$aCriteriaReport = [];
|
||||
if (isset($oCriteria->finalclass)) {
|
||||
if (!MetaModel::IsValidClass($oCriteria->finalclass)) {
|
||||
throw new Exception("finalclass: Unknown class '".$oCriteria->finalclass."'");
|
||||
}
|
||||
if (!MetaModel::IsParentClass($sClass, $oCriteria->finalclass))
|
||||
{
|
||||
if (!MetaModel::IsParentClass($sClass, $oCriteria->finalclass)) {
|
||||
throw new Exception("finalclass: '".$oCriteria->finalclass."' is not a child class of '$sClass'");
|
||||
}
|
||||
$sClass = $oCriteria->finalclass;
|
||||
}
|
||||
$oSearch = new DBObjectSearch($sClass);
|
||||
foreach ($oCriteria as $sAttCode => $value)
|
||||
{
|
||||
foreach ($oCriteria as $sAttCode => $value) {
|
||||
$realValue = static::MakeValue($sClass, $sAttCode, $value);
|
||||
$oSearch->AddCondition($sAttCode, $realValue, '=');
|
||||
if (is_object($value) || is_array($value))
|
||||
{
|
||||
if (is_object($value) || is_array($value)) {
|
||||
$value = json_encode($value);
|
||||
}
|
||||
$aCriteriaReport[] = "$sAttCode: $value ($realValue)";
|
||||
}
|
||||
$oSet = new DBObjectSet($oSearch);
|
||||
$iCount = $oSet->Count();
|
||||
if ($iCount == 0)
|
||||
{
|
||||
if ($iCount == 0) {
|
||||
throw new Exception("No item found with criteria: ".implode(', ', $aCriteriaReport));
|
||||
}
|
||||
elseif ($iCount > 1)
|
||||
{
|
||||
} elseif ($iCount > 1) {
|
||||
throw new Exception("Several items found ($iCount) with criteria: ".implode(', ', $aCriteriaReport));
|
||||
}
|
||||
$res = $oSet->Fetch();
|
||||
@@ -2013,7 +1982,6 @@ class RestUtils
|
||||
return $res;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Find an object from a polymorph search specification (Rest/Json)
|
||||
*
|
||||
@@ -2029,43 +1997,29 @@ class RestUtils
|
||||
*/
|
||||
public static function FindObjectFromKey($sClass, $key, $bAllowNullValue = false)
|
||||
{
|
||||
if (is_object($key))
|
||||
{
|
||||
if (is_object($key)) {
|
||||
$res = static::FindObjectFromCriteria($sClass, $key);
|
||||
}
|
||||
elseif (is_numeric($key))
|
||||
{
|
||||
if ($bAllowNullValue && ($key == 0))
|
||||
{
|
||||
} elseif (is_numeric($key)) {
|
||||
if ($bAllowNullValue && ($key == 0)) {
|
||||
$res = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
$res = MetaModel::GetObject($sClass, $key, false);
|
||||
if (is_null($res))
|
||||
{
|
||||
if (is_null($res)) {
|
||||
throw new Exception("Invalid object $sClass::$key");
|
||||
}
|
||||
}
|
||||
}
|
||||
elseif (is_string($key))
|
||||
{
|
||||
} elseif (is_string($key)) {
|
||||
// OQL
|
||||
$oSearch = DBObjectSearch::FromOQL($key);
|
||||
$oSet = new DBObjectSet($oSearch);
|
||||
$iCount = $oSet->Count();
|
||||
if ($iCount == 0)
|
||||
{
|
||||
if ($iCount == 0) {
|
||||
throw new Exception("No item found for query: $key");
|
||||
}
|
||||
elseif ($iCount > 1)
|
||||
{
|
||||
} elseif ($iCount > 1) {
|
||||
throw new Exception("Several items found ($iCount) for query: $key");
|
||||
}
|
||||
$res = $oSet->Fetch();
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
throw new Exception("Wrong format for key");
|
||||
}
|
||||
|
||||
@@ -2086,47 +2040,37 @@ class RestUtils
|
||||
*/
|
||||
public static function GetObjectSetFromKey($sClass, $key, $iLimit = 0, $iOffset = 0)
|
||||
{
|
||||
if (is_object($key))
|
||||
{
|
||||
if (isset($key->finalclass))
|
||||
{
|
||||
if (is_object($key)) {
|
||||
if (isset($key->finalclass)) {
|
||||
$sClass = $key->finalclass;
|
||||
if (!MetaModel::IsValidClass($sClass))
|
||||
{
|
||||
if (!MetaModel::IsValidClass($sClass)) {
|
||||
throw new Exception("finalclass: Unknown class '$sClass'");
|
||||
}
|
||||
}
|
||||
|
||||
$oSearch = new DBObjectSearch($sClass);
|
||||
foreach ($key as $sAttCode => $value)
|
||||
{
|
||||
foreach ($key as $sAttCode => $value) {
|
||||
$realValue = static::MakeValue($sClass, $sAttCode, $value);
|
||||
$oSearch->AddCondition($sAttCode, $realValue, '=');
|
||||
}
|
||||
}
|
||||
elseif (is_numeric($key))
|
||||
{
|
||||
} elseif (is_numeric($key)) {
|
||||
$oSearch = new DBObjectSearch($sClass);
|
||||
$oSearch->AddCondition('id', $key);
|
||||
}
|
||||
elseif (is_string($key))
|
||||
{
|
||||
} elseif (is_string($key)) {
|
||||
// OQL
|
||||
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
|
||||
{
|
||||
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");
|
||||
}
|
||||
$oObjectSet = new DBObjectSet($oSearch, array(), array(), null, $iLimit, $iOffset);
|
||||
$oObjectSet = new DBObjectSet($oSearch, [], [], null, $iLimit, $iOffset);
|
||||
|
||||
return $oObjectSet;
|
||||
}
|
||||
@@ -2144,53 +2088,38 @@ class RestUtils
|
||||
*/
|
||||
public static function MakeValue($sClass, $sAttCode, $value)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!MetaModel::IsValidAttCode($sClass, $sAttCode))
|
||||
{
|
||||
try {
|
||||
if (!MetaModel::IsValidAttCode($sClass, $sAttCode)) {
|
||||
throw new Exception("Unknown attribute");
|
||||
}
|
||||
$oAttDef = MetaModel::GetAttributeDef($sClass, $sAttCode);
|
||||
if ($oAttDef instanceof AttributeExternalKey)
|
||||
{
|
||||
if ($oAttDef instanceof AttributeExternalKey) {
|
||||
$oExtKeyObject = static::FindObjectFromKey($oAttDef->GetTargetClass(), $value, true /* allow null */);
|
||||
$value = ($oExtKeyObject != null) ? $oExtKeyObject->GetKey() : 0;
|
||||
}
|
||||
elseif ($oAttDef instanceof AttributeLinkedSet)
|
||||
{
|
||||
if (!is_array($value))
|
||||
{
|
||||
} elseif ($oAttDef instanceof AttributeLinkedSet) {
|
||||
if (!is_array($value)) {
|
||||
throw new Exception("A link set must be defined by an array of objects");
|
||||
}
|
||||
$sLnkClass = $oAttDef->GetLinkedClass();
|
||||
$aLinks = array();
|
||||
foreach ($value as $oValues)
|
||||
{
|
||||
$aLinks = [];
|
||||
foreach ($value as $oValues) {
|
||||
$oLnk = static::MakeObjectFromFields($sLnkClass, $oValues);
|
||||
// Fix for N°1939
|
||||
if (($oAttDef instanceof AttributeLinkedSetIndirect) && ($oLnk->Get($oAttDef->GetExtKeyToRemote()) == 0))
|
||||
{
|
||||
if (($oAttDef instanceof AttributeLinkedSetIndirect) && ($oLnk->Get($oAttDef->GetExtKeyToRemote()) == 0)) {
|
||||
continue;
|
||||
}
|
||||
$aLinks[] = $oLnk;
|
||||
}
|
||||
$value = DBObjectSet::FromArray($sLnkClass, $aLinks);
|
||||
}
|
||||
elseif ($oAttDef instanceof AttributeTagSet)
|
||||
{
|
||||
if (!is_array($value))
|
||||
{
|
||||
} elseif ($oAttDef instanceof AttributeTagSet) {
|
||||
if (!is_array($value)) {
|
||||
throw new Exception("A tag set must be defined by an array of tag codes");
|
||||
}
|
||||
$value = $oAttDef->FromJSONToValue($value);
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
$value = $oAttDef->FromJSONToValue($value);
|
||||
}
|
||||
}
|
||||
catch (Exception $e)
|
||||
{
|
||||
} catch (Exception $e) {
|
||||
throw new Exception("$sAttCode: ".$e->getMessage(), $e->getCode());
|
||||
}
|
||||
|
||||
@@ -2210,15 +2139,11 @@ class RestUtils
|
||||
public static function MakeObjectFromFields($sClass, $aFields)
|
||||
{
|
||||
$oObject = MetaModel::NewObject($sClass);
|
||||
foreach ($aFields as $sAttCode => $value)
|
||||
{
|
||||
foreach ($aFields as $sAttCode => $value) {
|
||||
$realValue = static::MakeValue($sClass, $sAttCode, $value);
|
||||
try
|
||||
{
|
||||
try {
|
||||
$oObject->Set($sAttCode, $realValue);
|
||||
}
|
||||
catch (Exception $e)
|
||||
{
|
||||
} catch (Exception $e) {
|
||||
throw new Exception("$sAttCode: ".$e->getMessage(), $e->getCode());
|
||||
}
|
||||
}
|
||||
@@ -2239,15 +2164,11 @@ class RestUtils
|
||||
public static function UpdateObjectFromFields($oObject, $aFields)
|
||||
{
|
||||
$sClass = get_class($oObject);
|
||||
foreach ($aFields as $sAttCode => $value)
|
||||
{
|
||||
foreach ($aFields as $sAttCode => $value) {
|
||||
$realValue = static::MakeValue($sClass, $sAttCode, $value);
|
||||
try
|
||||
{
|
||||
try {
|
||||
$oObject->Set($sAttCode, $realValue);
|
||||
}
|
||||
catch (Exception $e)
|
||||
{
|
||||
} catch (Exception $e) {
|
||||
throw new Exception("$sAttCode: ".$e->getMessage(), $e->getCode());
|
||||
}
|
||||
}
|
||||
@@ -2256,7 +2177,6 @@ class RestUtils
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Helpers for modules extensibility, with discover performed by the MetaModel.
|
||||
*
|
||||
@@ -2279,21 +2199,21 @@ interface iModuleExtension
|
||||
*/
|
||||
interface iKPILoggerExtension
|
||||
{
|
||||
/**
|
||||
* Init the statistics collected
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function InitStats();
|
||||
/**
|
||||
* 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);
|
||||
/**
|
||||
* Add a new KPI to the stats
|
||||
*
|
||||
* @param \Combodo\iTop\Core\Kpi\KpiLogData $oKpiLogData
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function LogOperation($oKpiLogData);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2311,7 +2231,6 @@ interface iBackupExtraFilesExtension
|
||||
public function GetExtraFilesRelPaths(): array;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Interface to provide messages to be displayed in the "Welcome Popup"
|
||||
*
|
||||
@@ -2372,7 +2291,7 @@ abstract class AbstractWelcomePopupExtension implements iWelcomePopupExtension
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
@@ -2381,4 +2300,4 @@ abstract class AbstractWelcomePopupExtension implements iWelcomePopupExtension
|
||||
// No need to process the acknowledgment notice by default
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
<?php
|
||||
|
||||
// Copyright (C) 2010-2024 Combodo SAS
|
||||
//
|
||||
// This file is part of iTop.
|
||||
//
|
||||
// iTop is free software; you can redistribute it and/or modify
|
||||
// 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.
|
||||
@@ -16,7 +17,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/>
|
||||
|
||||
|
||||
/**
|
||||
* This class manages the audit "categories". Each category defines a set of objects
|
||||
* to check and is linked to a set of rules that determine the valid or invalid objects
|
||||
@@ -32,34 +32,36 @@ class AuditCategory extends cmdbAbstractObject
|
||||
{
|
||||
public static function Init()
|
||||
{
|
||||
$aParams = array
|
||||
(
|
||||
$aParams =
|
||||
[
|
||||
"category" => "application,grant_by_profile",
|
||||
"key_type" => "autoincrement",
|
||||
"name_attcode" => "name",
|
||||
"state_attcode" => "",
|
||||
"reconc_keys" => array('name'),
|
||||
"reconc_keys" => ['name'],
|
||||
"db_table" => "priv_auditcategory",
|
||||
"db_key_field" => "id",
|
||||
"db_finalclass_field" => "",
|
||||
'style' => new ormStyle(null, null, null, null, null, '../images/icons/icons8-audit-folder.svg'),
|
||||
);
|
||||
];
|
||||
MetaModel::Init_Params($aParams);
|
||||
MetaModel::Init_AddAttribute(new AttributeString("name", array("description"=>"Short name for this category", "allowed_values"=>null, "sql"=>"name", "default_value"=>"", "is_null_allowed"=>false, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeString("description", array("allowed_values"=>null, "sql"=>"description", "default_value"=>"", "is_null_allowed"=>true, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeOQL("definition_set", array("allowed_values"=>null, "sql"=>"definition_set", "default_value"=>"", "is_null_allowed"=>false, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeLinkedSet("rules_list", array("linked_class"=>"AuditRule", "ext_key_to_me"=>"category_id", "allowed_values"=>null, "count_min"=>0, "count_max"=>0, "depends_on"=>array(), "edit_mode" => LINKSET_EDITMODE_INPLACE, "tracking_level" => LINKSET_TRACKING_ALL)));
|
||||
MetaModel::Init_AddAttribute(new AttributeInteger("ok_error_tolerance", array("allowed_values"=>null, "sql"=>"ok_error_tolerance", "default_value"=>5, "is_null_allowed"=>true, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeInteger("warning_error_tolerance", array("allowed_values" => null, "sql" => "warning_error_tolerance", "default_value" => 25, "is_null_allowed" => true, "depends_on" => array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeLinkedSetIndirect("domains_list",
|
||||
array("linked_class" => "lnkAuditCategoryToAuditDomain", "ext_key_to_me" => "category_id", "ext_key_to_remote" => "domain_id", "allowed_values" => null, "count_min" => 0, "count_max" => 0, "depends_on" => array(), "display_style" => 'property')));
|
||||
MetaModel::Init_AddAttribute(new AttributeString("name", ["description" => "Short name for this category", "allowed_values" => null, "sql" => "name", "default_value" => "", "is_null_allowed" => false, "depends_on" => []]));
|
||||
MetaModel::Init_AddAttribute(new AttributeString("description", ["allowed_values" => null, "sql" => "description", "default_value" => "", "is_null_allowed" => true, "depends_on" => []]));
|
||||
MetaModel::Init_AddAttribute(new AttributeOQL("definition_set", ["allowed_values" => null, "sql" => "definition_set", "default_value" => "", "is_null_allowed" => false, "depends_on" => []]));
|
||||
MetaModel::Init_AddAttribute(new AttributeLinkedSet("rules_list", ["linked_class" => "AuditRule", "ext_key_to_me" => "category_id", "allowed_values" => null, "count_min" => 0, "count_max" => 0, "depends_on" => [], "edit_mode" => LINKSET_EDITMODE_INPLACE, "tracking_level" => LINKSET_TRACKING_ALL]));
|
||||
MetaModel::Init_AddAttribute(new AttributeInteger("ok_error_tolerance", ["allowed_values" => null, "sql" => "ok_error_tolerance", "default_value" => 5, "is_null_allowed" => true, "depends_on" => []]));
|
||||
MetaModel::Init_AddAttribute(new AttributeInteger("warning_error_tolerance", ["allowed_values" => null, "sql" => "warning_error_tolerance", "default_value" => 25, "is_null_allowed" => true, "depends_on" => []]));
|
||||
MetaModel::Init_AddAttribute(new AttributeLinkedSetIndirect(
|
||||
"domains_list",
|
||||
["linked_class" => "lnkAuditCategoryToAuditDomain", "ext_key_to_me" => "category_id", "ext_key_to_remote" => "domain_id", "allowed_values" => null, "count_min" => 0, "count_max" => 0, "depends_on" => [], "display_style" => 'property']
|
||||
));
|
||||
|
||||
// Display lists
|
||||
MetaModel::Init_SetZListItems('details', array('name', 'description', 'definition_set', 'ok_error_tolerance', 'warning_error_tolerance', 'rules_list', 'domains_list')); // Attributes to be displayed for the complete details
|
||||
MetaModel::Init_SetZListItems('list', array('description', )); // Attributes to be displayed for a list
|
||||
MetaModel::Init_SetZListItems('details', ['name', 'description', 'definition_set', 'ok_error_tolerance', 'warning_error_tolerance', 'rules_list', 'domains_list']); // Attributes to be displayed for the complete details
|
||||
MetaModel::Init_SetZListItems('list', ['description', ]); // Attributes to be displayed for a list
|
||||
// Search criteria
|
||||
MetaModel::Init_SetZListItems('standard_search', array('description', 'definition_set')); // Criteria of the std search form
|
||||
MetaModel::Init_SetZListItems('default_search', array('name', 'description')); // Criteria of the default search form
|
||||
MetaModel::Init_SetZListItems('standard_search', ['description', 'definition_set']); // Criteria of the std search form
|
||||
MetaModel::Init_SetZListItems('default_search', ['name', 'description']); // Criteria of the default search form
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -74,9 +76,9 @@ class AuditCategory extends cmdbAbstractObject
|
||||
public function GetReportColor($iTotal, $iErrors)
|
||||
{
|
||||
$sResult = 'red';
|
||||
if ( ($iTotal == 0) || ($iErrors / $iTotal) <= ($this->Get('ok_error_tolerance') / 100) ) {
|
||||
if (($iTotal == 0) || ($iErrors / $iTotal) <= ($this->Get('ok_error_tolerance') / 100)) {
|
||||
$sResult = 'green';
|
||||
} else if (($iErrors / $iTotal) <= ($this->Get('warning_error_tolerance') / 100)) {
|
||||
} elseif (($iErrors / $iTotal) <= ($this->Get('warning_error_tolerance') / 100)) {
|
||||
$sResult = 'orange';
|
||||
}
|
||||
|
||||
@@ -93,4 +95,3 @@ class AuditCategory extends cmdbAbstractObject
|
||||
return $aShortcutActions;
|
||||
}
|
||||
}
|
||||
?>
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
// Copyright (C) 2010-2024 Combodo SAS
|
||||
//
|
||||
// This file is part of iTop.
|
||||
@@ -16,7 +17,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/>
|
||||
|
||||
|
||||
/**
|
||||
* This class manages the audit "categories". Each category defines a set of objects
|
||||
* to check and is linked to a set of rules that determine the valid or invalid objects
|
||||
@@ -33,32 +33,34 @@ class AuditDomain extends cmdbAbstractObject
|
||||
{
|
||||
public static function Init()
|
||||
{
|
||||
$aParams = array
|
||||
(
|
||||
$aParams =
|
||||
[
|
||||
"category" => "application,grant_by_profile",
|
||||
"key_type" => "autoincrement",
|
||||
"name_attcode" => "name",
|
||||
"complementary_name_attcode" => array('description'),
|
||||
"complementary_name_attcode" => ['description'],
|
||||
"state_attcode" => "",
|
||||
"reconc_keys" => array('name'),
|
||||
"reconc_keys" => ['name'],
|
||||
"db_table" => "priv_auditdomain",
|
||||
"db_key_field" => "id",
|
||||
"db_finalclass_field" => "",
|
||||
'style' => new ormStyle(null, null, null, null, null, '../images/icons/icons8-audit-album.svg'),
|
||||
);
|
||||
];
|
||||
MetaModel::Init_Params($aParams);
|
||||
MetaModel::Init_AddAttribute(new AttributeString("name", array("description" => "Short name for this category", "allowed_values" => null, "sql" => "name", "default_value" => "", "is_null_allowed" => false, "depends_on" => array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeString("description", array("allowed_values" => null, "sql" => "description", "default_value" => "", "is_null_allowed" => true, "depends_on" => array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeImage("icon", array("is_null_allowed" => true, "depends_on" => array(), "display_max_width" => 96, "display_max_height" => 96, "storage_max_width" => 256, "storage_max_height" => 256, "default_image" => null, "always_load_in_tables" => false)));
|
||||
MetaModel::Init_AddAttribute(new AttributeLinkedSetIndirect("categories_list",
|
||||
array("linked_class" => "lnkAuditCategoryToAuditDomain", "ext_key_to_me" => "domain_id", "ext_key_to_remote" => "category_id", "allowed_values" => null, "count_min" => 0, "count_max" => 0, "depends_on" => array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeString("name", ["description" => "Short name for this category", "allowed_values" => null, "sql" => "name", "default_value" => "", "is_null_allowed" => false, "depends_on" => []]));
|
||||
MetaModel::Init_AddAttribute(new AttributeString("description", ["allowed_values" => null, "sql" => "description", "default_value" => "", "is_null_allowed" => true, "depends_on" => []]));
|
||||
MetaModel::Init_AddAttribute(new AttributeImage("icon", ["is_null_allowed" => true, "depends_on" => [], "display_max_width" => 96, "display_max_height" => 96, "storage_max_width" => 256, "storage_max_height" => 256, "default_image" => null, "always_load_in_tables" => false]));
|
||||
MetaModel::Init_AddAttribute(new AttributeLinkedSetIndirect(
|
||||
"categories_list",
|
||||
["linked_class" => "lnkAuditCategoryToAuditDomain", "ext_key_to_me" => "domain_id", "ext_key_to_remote" => "category_id", "allowed_values" => null, "count_min" => 0, "count_max" => 0, "depends_on" => []]
|
||||
));
|
||||
|
||||
// Display lists
|
||||
MetaModel::Init_SetZListItems('details', array('name', 'description', 'icon', 'categories_list')); // Attributes to be displayed for the complete details
|
||||
MetaModel::Init_SetZListItems('list', array('description',)); // Attributes to be displayed for a list
|
||||
MetaModel::Init_SetZListItems('details', ['name', 'description', 'icon', 'categories_list']); // Attributes to be displayed for the complete details
|
||||
MetaModel::Init_SetZListItems('list', ['description',]); // Attributes to be displayed for a list
|
||||
// Search criteria
|
||||
MetaModel::Init_SetZListItems('standard_search', array('description')); // Criteria of the std search form
|
||||
MetaModel::Init_SetZListItems('default_search', array('name', 'description')); // Criteria of the default search form
|
||||
MetaModel::Init_SetZListItems('standard_search', ['description']); // Criteria of the std search form
|
||||
MetaModel::Init_SetZListItems('default_search', ['name', 'description']); // Criteria of the default search form
|
||||
}
|
||||
|
||||
public static function GetShortcutActions($sFinalClass)
|
||||
@@ -84,40 +86,39 @@ class lnkAuditCategoryToAuditDomain extends cmdbAbstractObject
|
||||
*/
|
||||
public static function Init()
|
||||
{
|
||||
$aParams = array
|
||||
(
|
||||
$aParams =
|
||||
[
|
||||
"category" => "application,grant_by_profile",
|
||||
"key_type" => "autoincrement",
|
||||
"name_attcode" => "",
|
||||
"state_attcode" => "",
|
||||
"reconc_keys" => array('category_id', 'domain_id'),
|
||||
"reconc_keys" => ['category_id', 'domain_id'],
|
||||
"db_table" => "priv_link_audit_category_domain",
|
||||
"db_key_field" => "id",
|
||||
"db_finalclass_field" => "",
|
||||
"is_link" => true,
|
||||
'uniqueness_rules' => array(
|
||||
'no_duplicate' => array(
|
||||
'attributes' => array(
|
||||
'uniqueness_rules' => [
|
||||
'no_duplicate' => [
|
||||
'attributes' => [
|
||||
0 => 'category_id',
|
||||
1 => 'domain_id',
|
||||
),
|
||||
],
|
||||
'filter' => '',
|
||||
'disabled' => false,
|
||||
'is_blocking' => true,
|
||||
),
|
||||
),
|
||||
);
|
||||
],
|
||||
],
|
||||
];
|
||||
MetaModel::Init_Params($aParams);
|
||||
MetaModel::Init_AddAttribute(new AttributeExternalKey("category_id", array("targetclass" => "AuditCategory", "jointype" => '', "allowed_values" => null, "sql" => "category_id", "is_null_allowed" => false, "on_target_delete" => DEL_AUTO, "depends_on" => array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeExternalField("category_name", array("allowed_values" => null, "extkey_attcode" => 'category_id', "target_attcode" => "name")));
|
||||
MetaModel::Init_AddAttribute(new AttributeExternalKey("domain_id", array("targetclass" => "AuditDomain", "jointype" => '', "allowed_values" => null, "sql" => "domain_id", "is_null_allowed" => false, "on_target_delete" => DEL_AUTO, "depends_on" => array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeExternalField("domain_name", array("allowed_values" => null, "extkey_attcode" => 'domain_id', "target_attcode" => "name")));
|
||||
MetaModel::Init_AddAttribute(new AttributeExternalKey("category_id", ["targetclass" => "AuditCategory", "jointype" => '', "allowed_values" => null, "sql" => "category_id", "is_null_allowed" => false, "on_target_delete" => DEL_AUTO, "depends_on" => []]));
|
||||
MetaModel::Init_AddAttribute(new AttributeExternalField("category_name", ["allowed_values" => null, "extkey_attcode" => 'category_id', "target_attcode" => "name"]));
|
||||
MetaModel::Init_AddAttribute(new AttributeExternalKey("domain_id", ["targetclass" => "AuditDomain", "jointype" => '', "allowed_values" => null, "sql" => "domain_id", "is_null_allowed" => false, "on_target_delete" => DEL_AUTO, "depends_on" => []]));
|
||||
MetaModel::Init_AddAttribute(new AttributeExternalField("domain_name", ["allowed_values" => null, "extkey_attcode" => 'domain_id', "target_attcode" => "name"]));
|
||||
|
||||
// Display lists
|
||||
MetaModel::Init_SetZListItems('details', array('category_id', 'domain_id'));
|
||||
MetaModel::Init_SetZListItems('list', array('category_id', 'domain_id'));
|
||||
MetaModel::Init_SetZListItems('details', ['category_id', 'domain_id']);
|
||||
MetaModel::Init_SetZListItems('list', ['category_id', 'domain_id']);
|
||||
// Search criteria
|
||||
MetaModel::Init_SetZListItems('standard_search', array('category_id', 'domain_id'));
|
||||
MetaModel::Init_SetZListItems('standard_search', ['category_id', 'domain_id']);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
<?php
|
||||
|
||||
// Copyright (C) 2010-2024 Combodo SAS
|
||||
//
|
||||
// This file is part of iTop.
|
||||
//
|
||||
// iTop is free software; you can redistribute it and/or modify
|
||||
// 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.
|
||||
@@ -16,7 +17,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/>
|
||||
|
||||
|
||||
/**
|
||||
* This class manages the audit "rule" linked to a given audit category.
|
||||
* Each rule is based on an OQL expression that returns either the "good" objects
|
||||
@@ -33,35 +33,34 @@ class AuditRule extends cmdbAbstractObject
|
||||
{
|
||||
public static function Init()
|
||||
{
|
||||
$aParams = array
|
||||
(
|
||||
$aParams =
|
||||
[
|
||||
"category" => "application,grant_by_profile",
|
||||
"key_type" => "autoincrement",
|
||||
"name_attcode" => "name",
|
||||
"state_attcode" => "",
|
||||
"reconc_keys" => array('name'),
|
||||
"reconc_keys" => ['name'],
|
||||
"db_table" => "priv_auditrule",
|
||||
"db_key_field" => "id",
|
||||
"db_finalclass_field" => "",
|
||||
'style' => new ormStyle(null, null, null, null, null, '../images/icons/icons8-audit.svg'),
|
||||
);
|
||||
];
|
||||
MetaModel::Init_Params($aParams);
|
||||
MetaModel::Init_AddAttribute(new AttributeString("name", array("allowed_values" => null, "sql" => "name", "default_value" => "", "is_null_allowed" => false, "depends_on" => array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeString("description", array("allowed_values" => null, "sql" => "description", "default_value" => "", "is_null_allowed" => true, "depends_on" => array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeOQL("query", array("allowed_values" => null, "sql" => "query", "default_value" => "", "is_null_allowed" => false, "depends_on" => array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeEnum("valid_flag", array("allowed_values" => new ValueSetEnum('true,false'), "sql" => "valid_flag", "default_value" => "true", "is_null_allowed" => false, "depends_on" => array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeExternalKey("category_id", array("allowed_values" => null, "sql" => "category_id", "targetclass" => "AuditCategory", "is_null_allowed" => false, "on_target_delete" => DEL_MANUAL, "depends_on" => array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeExternalField("category_name", array("allowed_values" => null, "extkey_attcode" => 'category_id', "target_attcode" => "name")));
|
||||
MetaModel::Init_AddAttribute(new AttributeString("name", ["allowed_values" => null, "sql" => "name", "default_value" => "", "is_null_allowed" => false, "depends_on" => []]));
|
||||
MetaModel::Init_AddAttribute(new AttributeString("description", ["allowed_values" => null, "sql" => "description", "default_value" => "", "is_null_allowed" => true, "depends_on" => []]));
|
||||
MetaModel::Init_AddAttribute(new AttributeOQL("query", ["allowed_values" => null, "sql" => "query", "default_value" => "", "is_null_allowed" => false, "depends_on" => []]));
|
||||
MetaModel::Init_AddAttribute(new AttributeEnum("valid_flag", ["allowed_values" => new ValueSetEnum('true,false'), "sql" => "valid_flag", "default_value" => "true", "is_null_allowed" => false, "depends_on" => []]));
|
||||
MetaModel::Init_AddAttribute(new AttributeExternalKey("category_id", ["allowed_values" => null, "sql" => "category_id", "targetclass" => "AuditCategory", "is_null_allowed" => false, "on_target_delete" => DEL_MANUAL, "depends_on" => []]));
|
||||
MetaModel::Init_AddAttribute(new AttributeExternalField("category_name", ["allowed_values" => null, "extkey_attcode" => 'category_id', "target_attcode" => "name"]));
|
||||
|
||||
// Display lists
|
||||
MetaModel::Init_SetZListItems('details', array('category_id', 'name', 'description', 'query', 'valid_flag')); // Attributes to be displayed for the complete details
|
||||
MetaModel::Init_SetZListItems('list', array('category_id', 'description', 'valid_flag')); // Attributes to be displayed for a list
|
||||
MetaModel::Init_SetZListItems('details', ['category_id', 'name', 'description', 'query', 'valid_flag']); // Attributes to be displayed for the complete details
|
||||
MetaModel::Init_SetZListItems('list', ['category_id', 'description', 'valid_flag']); // Attributes to be displayed for a list
|
||||
// Search criteria
|
||||
MetaModel::Init_SetZListItems('standard_search', array('category_id', 'name', 'description', 'valid_flag', 'query')); // Criteria of the std search form
|
||||
MetaModel::Init_SetZListItems('default_search', array('name', 'description', 'category_id')); // Criteria of the advanced search form
|
||||
MetaModel::Init_SetZListItems('standard_search', ['category_id', 'name', 'description', 'valid_flag', 'query']); // Criteria of the std search form
|
||||
MetaModel::Init_SetZListItems('default_search', ['name', 'description', 'category_id']); // Criteria of the advanced search form
|
||||
}
|
||||
|
||||
|
||||
public static function GetShortcutActions($sFinalClass)
|
||||
{
|
||||
$aShortcutActions = parent::GetShortcutActions($sFinalClass);
|
||||
@@ -72,4 +71,3 @@ class AuditRule extends cmdbAbstractObject
|
||||
return $aShortcutActions;
|
||||
}
|
||||
}
|
||||
?>
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @deprecated 3.0.0 will be removed in 3.1.0 - moved to sources/Application/WebPage/CaptureWebPage.php, now loadable using autoloader
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
* @copyright Copyright (C) 2010-2024 Combodo SAS
|
||||
*/
|
||||
|
||||
DeprecatedCallsLog::NotifyDeprecatedFile('moved to sources/Application/WebPage/CaptureWebPage.php, now loadable using autoloader');
|
||||
DeprecatedCallsLog::NotifyDeprecatedFile('moved to sources/Application/WebPage/CaptureWebPage.php, now loadable using autoloader');
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @deprecated 3.0.0 will be removed in 3.1.0 - moved to sources/Application/WebPage/CLIPage.php, now loadable using autoloader
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
* @copyright Copyright (C) 2010-2024 Combodo SAS
|
||||
*/
|
||||
|
||||
DeprecatedCallsLog::NotifyDeprecatedFile('moved to sources/Application/WebPage/CLIPage.php, now loadable using autoloader');
|
||||
DeprecatedCallsLog::NotifyDeprecatedFile('moved to sources/Application/WebPage/CLIPage.php, now loadable using autoloader');
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Copyright (C) 2013-2024 Combodo SAS
|
||||
*
|
||||
@@ -32,7 +33,8 @@ class CompileCSSService
|
||||
{
|
||||
}
|
||||
|
||||
public function CompileCSSFromSASS($sSassContent, $aImportPaths = [], $aVariables = []){
|
||||
public function CompileCSSFromSASS($sSassContent, $aImportPaths = [], $aVariables = [])
|
||||
{
|
||||
return utils::CompileCSSFromSASS($sSassContent, $aImportPaths, $aVariables);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @deprecated 3.0.0 will be removed in 3.1.0 - moved to sources/Application/WebPage/CSVPage.php, now loadable using autoloader
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
* @copyright Copyright (C) 2010-2024 Combodo SAS
|
||||
*/
|
||||
|
||||
DeprecatedCallsLog::NotifyDeprecatedFile('moved to sources/Application/WebPage/CSVPage.php, now loadable using autoloader');
|
||||
DeprecatedCallsLog::NotifyDeprecatedFile('moved to sources/Application/WebPage/CSVPage.php, now loadable using autoloader');
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* @copyright Copyright (C) 2010-2024 Combodo SAS
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
@@ -53,7 +54,7 @@ abstract class Dashboard
|
||||
$this->sLayoutClass = 'DashboardLayoutOneCol';
|
||||
$this->bAutoReload = false;
|
||||
$this->iAutoReloadSec = MetaModel::GetConfig()->GetStandardReloadInterval();
|
||||
$this->aCells = array();
|
||||
$this->aCells = [];
|
||||
$this->oDOMNode = null;
|
||||
$this->sId = $sId;
|
||||
}
|
||||
@@ -65,8 +66,8 @@ abstract class Dashboard
|
||||
*/
|
||||
public function FromXml($sXml)
|
||||
{
|
||||
$this->aCells = array(); // reset the content of the dashboard
|
||||
set_error_handler(array('Dashboard', 'ErrorHandler'));
|
||||
$this->aCells = []; // reset the content of the dashboard
|
||||
set_error_handler(['Dashboard', 'ErrorHandler']);
|
||||
$oDoc = new DOMDocument();
|
||||
$oDoc->loadXML($sXml);
|
||||
restore_error_handler();
|
||||
@@ -79,87 +80,69 @@ abstract class Dashboard
|
||||
public function FromDOMDocument(DOMDocument $oDoc)
|
||||
{
|
||||
$this->oDOMNode = $oDoc->getElementsByTagName('dashboard')->item(0);
|
||||
|
||||
if ($oLayoutNode = $this->oDOMNode->getElementsByTagName('layout')->item(0))
|
||||
{
|
||||
|
||||
if ($oLayoutNode = $this->oDOMNode->getElementsByTagName('layout')->item(0)) {
|
||||
$this->sLayoutClass = $oLayoutNode->textContent;
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
$this->sLayoutClass = 'DashboardLayoutOneCol';
|
||||
}
|
||||
|
||||
if ($oTitleNode = $this->oDOMNode->getElementsByTagName('title')->item(0))
|
||||
{
|
||||
|
||||
if ($oTitleNode = $this->oDOMNode->getElementsByTagName('title')->item(0)) {
|
||||
$this->sTitle = $oTitleNode->textContent;
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
$this->sTitle = '';
|
||||
}
|
||||
|
||||
|
||||
$this->bAutoReload = false;
|
||||
$this->iAutoReloadSec = MetaModel::GetConfig()->GetStandardReloadInterval();
|
||||
if ($oAutoReloadNode = $this->oDOMNode->getElementsByTagName('auto_reload')->item(0))
|
||||
{
|
||||
if ($oAutoReloadEnabled = $oAutoReloadNode->getElementsByTagName('enabled')->item(0))
|
||||
{
|
||||
if ($oAutoReloadNode = $this->oDOMNode->getElementsByTagName('auto_reload')->item(0)) {
|
||||
if ($oAutoReloadEnabled = $oAutoReloadNode->getElementsByTagName('enabled')->item(0)) {
|
||||
$this->bAutoReload = ($oAutoReloadEnabled->textContent == 'true');
|
||||
}
|
||||
if ($oAutoReloadInterval = $oAutoReloadNode->getElementsByTagName('interval')->item(0))
|
||||
{
|
||||
if ($oAutoReloadInterval = $oAutoReloadNode->getElementsByTagName('interval')->item(0)) {
|
||||
$this->iAutoReloadSec = max(MetaModel::GetConfig()->Get('min_reload_interval'), (int)$oAutoReloadInterval->textContent);
|
||||
}
|
||||
}
|
||||
|
||||
if ($oCellsNode = $this->oDOMNode->getElementsByTagName('cells')->item(0))
|
||||
{
|
||||
if ($oCellsNode = $this->oDOMNode->getElementsByTagName('cells')->item(0)) {
|
||||
$oCellsList = $oCellsNode->getElementsByTagName('cell');
|
||||
$aCellOrder = array();
|
||||
$aCellOrder = [];
|
||||
$iCellRank = 0;
|
||||
/** @var \DOMElement $oCellNode */
|
||||
foreach($oCellsList as $oCellNode)
|
||||
{
|
||||
foreach ($oCellsList as $oCellNode) {
|
||||
$oCellRank = $oCellNode->getElementsByTagName('rank')->item(0);
|
||||
if ($oCellRank)
|
||||
{
|
||||
if ($oCellRank) {
|
||||
$iCellRank = (float)$oCellRank->textContent;
|
||||
}
|
||||
$oDashletsNode = $oCellNode->getElementsByTagName('dashlets')->item(0);
|
||||
{
|
||||
$oDashletList = $oDashletsNode->getElementsByTagName('dashlet');
|
||||
$iRank = 0;
|
||||
$aDashletOrder = array();
|
||||
$aDashletOrder = [];
|
||||
/** @var \DOMElement $oDomNode */
|
||||
foreach($oDashletList as $oDomNode)
|
||||
{
|
||||
foreach ($oDashletList as $oDomNode) {
|
||||
$oRank = $oDomNode->getElementsByTagName('rank')->item(0);
|
||||
if ($oRank)
|
||||
{
|
||||
if ($oRank) {
|
||||
$iRank = (float)$oRank->textContent;
|
||||
}
|
||||
|
||||
$oNewDashlet = $this->InitDashletFromDOMNode($oDomNode);
|
||||
$aDashletOrder[] = array('rank' => $iRank, 'dashlet' => $oNewDashlet);
|
||||
$aDashletOrder[] = ['rank' => $iRank, 'dashlet' => $oNewDashlet];
|
||||
}
|
||||
usort($aDashletOrder, array(get_class($this), 'SortOnRank'));
|
||||
$aDashletList = array();
|
||||
foreach($aDashletOrder as $aItem)
|
||||
{
|
||||
usort($aDashletOrder, [get_class($this), 'SortOnRank']);
|
||||
$aDashletList = [];
|
||||
foreach ($aDashletOrder as $aItem) {
|
||||
$aDashletList[] = $aItem['dashlet'];
|
||||
}
|
||||
$aCellOrder[] = array('rank' => $iCellRank, 'dashlets' => $aDashletList);
|
||||
$aCellOrder[] = ['rank' => $iCellRank, 'dashlets' => $aDashletList];
|
||||
}
|
||||
}
|
||||
usort($aCellOrder, array(get_class($this), 'SortOnRank'));
|
||||
foreach($aCellOrder as $aItem)
|
||||
{
|
||||
usort($aCellOrder, [get_class($this), 'SortOnRank']);
|
||||
foreach ($aCellOrder as $aItem) {
|
||||
$this->aCells[] = $aItem['dashlets'];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->aCells = array();
|
||||
} else {
|
||||
$this->aCells = [];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -169,20 +152,20 @@ abstract class Dashboard
|
||||
* @return mixed
|
||||
*/
|
||||
protected function InitDashletFromDOMNode($oDomNode)
|
||||
{
|
||||
$sId = $oDomNode->getAttribute('id');
|
||||
{
|
||||
$sId = $oDomNode->getAttribute('id');
|
||||
|
||||
$sDashletType = $oDomNode->getAttribute('xsi:type');
|
||||
$sDashletType = $oDomNode->getAttribute('xsi:type');
|
||||
|
||||
// Test if dashlet can be instantiated, otherwise (uninstalled, broken, ...) we display a placeholder
|
||||
$sClass = static::GetDashletClassFromType($sDashletType);
|
||||
/** @var \Dashlet $oNewDashlet */
|
||||
$oNewDashlet = new $sClass($this->oMetaModel, $sId);
|
||||
$oNewDashlet->SetDashletType($sDashletType);
|
||||
$oNewDashlet->FromDOMNode($oDomNode);
|
||||
// Test if dashlet can be instantiated, otherwise (uninstalled, broken, ...) we display a placeholder
|
||||
$sClass = static::GetDashletClassFromType($sDashletType);
|
||||
/** @var \Dashlet $oNewDashlet */
|
||||
$oNewDashlet = new $sClass($this->oMetaModel, $sId);
|
||||
$oNewDashlet->SetDashletType($sDashletType);
|
||||
$oNewDashlet->FromDOMNode($oDomNode);
|
||||
|
||||
return $oNewDashlet;
|
||||
}
|
||||
return $oNewDashlet;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $aItem1
|
||||
@@ -208,12 +191,9 @@ abstract class Dashboard
|
||||
*/
|
||||
public static function ErrorHandler($errno, $errstr, $errfile, $errline)
|
||||
{
|
||||
if ($errno == E_WARNING && (substr_count($errstr,"DOMDocument::loadXML()")>0))
|
||||
{
|
||||
if ($errno == E_WARNING && (substr_count($errstr, "DOMDocument::loadXML()") > 0)) {
|
||||
throw new DOMException($errstr);
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -231,7 +211,7 @@ abstract class Dashboard
|
||||
$oMainNode = $oDoc->createElement('dashboard');
|
||||
$oMainNode->setAttribute('xmlns:xsi', "http://www.w3.org/2001/XMLSchema-instance");
|
||||
$oDoc->appendChild($oMainNode);
|
||||
|
||||
|
||||
$this->ToDOMNode($oMainNode);
|
||||
|
||||
$sXml = $oDoc->saveXML();
|
||||
@@ -261,23 +241,21 @@ abstract class Dashboard
|
||||
|
||||
$oCellsNode = $oDoc->createElement('cells');
|
||||
$oDefinition->appendChild($oCellsNode);
|
||||
|
||||
|
||||
$iCellRank = 0;
|
||||
foreach ($this->aCells as $aCell)
|
||||
{
|
||||
foreach ($this->aCells as $aCell) {
|
||||
$oCellNode = $oDoc->createElement('cell');
|
||||
$oCellNode->setAttribute('id', $iCellRank);
|
||||
$oCellsNode->appendChild($oCellNode);
|
||||
$oCellRank = $oDoc->createElement('rank', $iCellRank);
|
||||
$oCellNode->appendChild($oCellRank);
|
||||
$iCellRank++;
|
||||
|
||||
|
||||
$iDashletRank = 0;
|
||||
$oDashletsNode = $oDoc->createElement('dashlets');
|
||||
$oCellNode->appendChild($oDashletsNode);
|
||||
/** @var \Dashlet $oDashlet */
|
||||
foreach ($aCell as $oDashlet)
|
||||
{
|
||||
foreach ($aCell as $oDashlet) {
|
||||
$oNode = $oDoc->createElement('dashlet');
|
||||
$oDashletsNode->appendChild($oNode);
|
||||
$oNode->setAttribute('id', $oDashlet->GetID());
|
||||
@@ -299,18 +277,15 @@ abstract class Dashboard
|
||||
$this->sTitle = $aParams['title'];
|
||||
$this->bAutoReload = $aParams['auto_reload'] == 'true';
|
||||
$this->iAutoReloadSec = max(MetaModel::GetConfig()->Get('min_reload_interval'), (int) $aParams['auto_reload_sec']);
|
||||
|
||||
foreach($aParams['cells'] as $aCell)
|
||||
{
|
||||
$aCellDashlets = array();
|
||||
foreach($aCell as $aDashletParams)
|
||||
{
|
||||
|
||||
foreach ($aParams['cells'] as $aCell) {
|
||||
$aCellDashlets = [];
|
||||
foreach ($aCell as $aDashletParams) {
|
||||
$sDashletClass = $aDashletParams['dashlet_class'];
|
||||
$sId = $aDashletParams['dashlet_id'];
|
||||
/** @var \Dashlet $oNewDashlet */
|
||||
$oNewDashlet = new $sDashletClass($this->oMetaModel, $sId);
|
||||
if (isset($aDashletParams['dashlet_type']))
|
||||
{
|
||||
if (isset($aDashletParams['dashlet_type'])) {
|
||||
$oNewDashlet->SetDashletType($aDashletParams['dashlet_type']);
|
||||
}
|
||||
$oForm = $oNewDashlet->GetForm();
|
||||
@@ -322,12 +297,12 @@ abstract class Dashboard
|
||||
}
|
||||
$this->aCells[] = $aCellDashlets;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
public function Save()
|
||||
{
|
||||
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -420,7 +395,7 @@ abstract class Dashboard
|
||||
{
|
||||
$sId = $this->GetNewDashletId();
|
||||
$oDashlet->SetId($sId);
|
||||
$this->aCells[] = array($oDashlet);
|
||||
$this->aCells[] = [$oDashlet];
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -430,7 +405,7 @@ abstract class Dashboard
|
||||
* @throws \ReflectionException
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function RenderProperties($oPage, $aExtraParams = array())
|
||||
public function RenderProperties($oPage, $aExtraParams = [])
|
||||
{
|
||||
// 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>');
|
||||
@@ -442,7 +417,7 @@ abstract class Dashboard
|
||||
if (is_subclass_of($sLayoutClass, 'DashboardLayout')) {
|
||||
$oReflection = new ReflectionClass($sLayoutClass);
|
||||
if (!$oReflection->isAbstract()) {
|
||||
$aCallSpec = array($sLayoutClass, 'GetInfo');
|
||||
$aCallSpec = [$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 !
|
||||
@@ -466,7 +441,6 @@ abstract class Dashboard
|
||||
$oField->SetBoundaries(MetaModel::GetConfig()->Get('min_reload_interval'), null); // no upper limit
|
||||
$oForm->AddField($oField);
|
||||
|
||||
|
||||
$this->SetFormParams($oForm, $aExtraParams);
|
||||
$oForm->RenderAsPropertySheet($oPage, false, '.itop-dashboard');
|
||||
|
||||
@@ -474,7 +448,7 @@ abstract class Dashboard
|
||||
|
||||
$sRateTitle = addslashes(Dict::Format('UI:DashboardEdit:AutoReloadSec+', MetaModel::GetConfig()->Get('min_reload_interval')));
|
||||
$oPage->add_ready_script(
|
||||
<<<EOF
|
||||
<<<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"));
|
||||
@@ -522,7 +496,7 @@ EOF
|
||||
*
|
||||
* @return \Combodo\iTop\Application\UI\Base\Layout\Dashboard\DashboardLayout
|
||||
*/
|
||||
public function Render($oPage, $bEditMode = false, $aExtraParams = array(), $bCanEdit = true)
|
||||
public function Render($oPage, $bEditMode = false, $aExtraParams = [], $bCanEdit = true)
|
||||
{
|
||||
$aExtraParams['dashboard_div_id'] = utils::Sanitize($aExtraParams['dashboard_div_id'] ?? null, $this->GetId(), utils::ENUM_SANITIZATION_FILTER_ELEMENT_IDENTIFIER);
|
||||
|
||||
@@ -551,7 +525,8 @@ EOF
|
||||
|
||||
$oToolbar->AddHtml($sHtml);
|
||||
} else {
|
||||
$oPage->add_script(<<<JS
|
||||
$oPage->add_script(
|
||||
<<<JS
|
||||
$(".ibo-top-bar--toolbar-dashboard-title").html("$sTitleForHTML").attr("title", $('<div>').html("$sTitleForHTML").text());
|
||||
JS
|
||||
);
|
||||
@@ -595,7 +570,7 @@ JS
|
||||
* @param WebPage $oPage
|
||||
* @param array $aExtraParams
|
||||
*/
|
||||
public function RenderDashletsProperties(WebPage $oPage, $aExtraParams = array())
|
||||
public function RenderDashletsProperties(WebPage $oPage, $aExtraParams = [])
|
||||
{
|
||||
// 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>');
|
||||
@@ -604,13 +579,10 @@ JS
|
||||
$oLayout = new $this->sLayoutClass();
|
||||
|
||||
$oPage->add('<div id="dashlet_properties">');
|
||||
foreach($this->aCells as $iCellIdx => $aCell)
|
||||
{
|
||||
foreach ($this->aCells as $iCellIdx => $aCell) {
|
||||
/** @var \Dashlet $oDashlet */
|
||||
foreach($aCell as $oDashlet)
|
||||
{
|
||||
if ($oDashlet->IsVisible())
|
||||
{
|
||||
foreach ($aCell as $oDashlet) {
|
||||
if ($oDashlet->IsVisible()) {
|
||||
$oPage->add('<div class="dashlet_properties" id="dashlet_properties_'.$oDashlet->GetID().'" style="display:none">');
|
||||
$oForm = $oDashlet->GetForm();
|
||||
$this->SetFormParams($oForm, $aExtraParams);
|
||||
@@ -632,18 +604,17 @@ JS
|
||||
*/
|
||||
protected function GetAvailableDashlets()
|
||||
{
|
||||
$aDashlets = array();
|
||||
$aDashlets = [];
|
||||
|
||||
foreach( get_declared_classes() as $sDashletClass)
|
||||
{
|
||||
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'))) {
|
||||
if (is_subclass_of($sDashletClass, 'Dashlet') && !in_array($sDashletClass, ['DashletUnknown', 'DashletProxy'])) {
|
||||
$oReflection = new ReflectionClass($sDashletClass);
|
||||
if (!$oReflection->isAbstract()) {
|
||||
$aCallSpec = array($sDashletClass, 'IsVisible');
|
||||
$aCallSpec = [$sDashletClass, 'IsVisible'];
|
||||
$bVisible = call_user_func($aCallSpec);
|
||||
if ($bVisible) {
|
||||
$aCallSpec = array($sDashletClass, 'GetInfo');
|
||||
$aCallSpec = [$sDashletClass, 'GetInfo'];
|
||||
$aInfo = call_user_func($aCallSpec);
|
||||
$aDashlets[$sDashletClass] = $aInfo;
|
||||
}
|
||||
@@ -660,11 +631,9 @@ JS
|
||||
protected function GetNewDashletId()
|
||||
{
|
||||
$iNewId = 0;
|
||||
foreach($this->aCells as $aDashlets)
|
||||
{
|
||||
foreach ($this->aCells as $aDashlets) {
|
||||
/** @var \Dashlet $oDashlet */
|
||||
foreach($aDashlets as $oDashlet)
|
||||
{
|
||||
foreach ($aDashlets as $oDashlet) {
|
||||
$iNewId = max($iNewId, (int)$oDashlet->GetID());
|
||||
}
|
||||
}
|
||||
@@ -681,15 +650,15 @@ JS
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
abstract protected function PrepareDashletForRendering(Dashlet $oDashlet, $aCoordinates, $aExtraParams = array());
|
||||
abstract protected function PrepareDashletForRendering(Dashlet $oDashlet, $aCoordinates, $aExtraParams = []);
|
||||
|
||||
/**
|
||||
* @param \DesignerForm $oForm
|
||||
* @param array $aExtraParams
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
abstract protected function SetFormParams($oForm, $aExtraParams = array());
|
||||
/**
|
||||
* @param \DesignerForm $oForm
|
||||
* @param array $aExtraParams
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
abstract protected function SetFormParams($oForm, $aExtraParams = []);
|
||||
|
||||
/**
|
||||
* @param string $sType
|
||||
@@ -699,8 +668,7 @@ JS
|
||||
*/
|
||||
public static function GetDashletClassFromType($sType, $oFactory = null)
|
||||
{
|
||||
if (is_subclass_of($sType, 'Dashlet'))
|
||||
{
|
||||
if (is_subclass_of($sType, 'Dashlet')) {
|
||||
return $sType;
|
||||
}
|
||||
return 'DashletUnknown';
|
||||
@@ -723,14 +691,12 @@ JS
|
||||
*/
|
||||
public static function GetDashletUniqueId($bIsCustomized, $sDashboardDivId, $iRow, $iCol, $sDashletOrigId)
|
||||
{
|
||||
if(strpos($sDashletOrigId, '_ID_row') !== false)
|
||||
{
|
||||
if (strpos($sDashletOrigId, '_ID_row') !== false) {
|
||||
return $sDashletOrigId;
|
||||
}
|
||||
|
||||
$sDashletId = $sDashboardDivId."_ID_row".$iRow."_col".$iCol."_".$sDashletOrigId;
|
||||
if ($bIsCustomized)
|
||||
{
|
||||
if ($bIsCustomized) {
|
||||
$sDashletId = 'CUSTOM_'.$sDashletId;
|
||||
}
|
||||
|
||||
@@ -782,9 +748,9 @@ class RuntimeDashboard extends Dashboard
|
||||
* @inheritDoc
|
||||
* @throws \Exception
|
||||
*/
|
||||
protected function SetFormParams($oForm, $aExtraParams = array())
|
||||
protected function SetFormParams($oForm, $aExtraParams = [])
|
||||
{
|
||||
$oForm->SetSubmitParams(utils::GetAbsoluteUrlAppRoot().'pages/ajax.render.php', array('operation' => 'update_dashlet_property', 'extra_params' => $aExtraParams));
|
||||
$oForm->SetSubmitParams(utils::GetAbsoluteUrlAppRoot().'pages/ajax.render.php', ['operation' => 'update_dashlet_property', 'extra_params' => $aExtraParams]);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -800,14 +766,11 @@ class RuntimeDashboard extends Dashboard
|
||||
$oUDSearch->AddCondition('menu_code', $this->sId, '=');
|
||||
$oUDSet = new DBObjectSet($oUDSearch);
|
||||
$bIsNew = false;
|
||||
if ($oUDSet->Count() > 0)
|
||||
{
|
||||
if ($oUDSet->Count() > 0) {
|
||||
// Assuming there is at most one couple {user, menu}!
|
||||
$oUserDashboard = $oUDSet->Fetch();
|
||||
$oUserDashboard->Set('contents', $sXml);
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
// No such customized dashboard for the current user, let's create a new record
|
||||
$oUserDashboard = new UserDashboard();
|
||||
$oUserDashboard->Set('user_id', UserRights::GetUserId());
|
||||
@@ -838,8 +801,7 @@ class RuntimeDashboard extends Dashboard
|
||||
$oUDSearch->AddCondition('user_id', UserRights::GetUserId(), '=');
|
||||
$oUDSearch->AddCondition('menu_code', $this->sId, '=');
|
||||
$oUDSet = new DBObjectSet($oUDSearch);
|
||||
if ($oUDSet->Count() > 0)
|
||||
{
|
||||
if ($oUDSet->Count() > 0) {
|
||||
// Assuming there is at most one couple {user, menu}!
|
||||
$oUserDashboard = $oUDSet->Fetch();
|
||||
utils::PushArchiveMode(false);
|
||||
@@ -883,14 +845,11 @@ class RuntimeDashboard extends Dashboard
|
||||
} else {
|
||||
$sDashboardDefinition = @file_get_contents($sDashboardFileSanitized);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
$sDashboardDefinition = @file_get_contents($sDashboardFileSanitized);
|
||||
}
|
||||
|
||||
if ($sDashboardDefinition !== false)
|
||||
{
|
||||
if ($sDashboardDefinition !== false) {
|
||||
$oDashboard = new RuntimeDashboard($sDashBoardId);
|
||||
$oDashboard->FromXml($sDashboardDefinition);
|
||||
$oDashboard->SetCustomFlag($bCustomized);
|
||||
@@ -937,7 +896,6 @@ class RuntimeDashboard extends Dashboard
|
||||
$sDashboardDefinition = @file_get_contents($sDashboardFileSanitized);
|
||||
}
|
||||
|
||||
|
||||
if ($sDashboardDefinition !== false) {
|
||||
$oDashboard = new RuntimeDashboard($sDashBoardId);
|
||||
$oDashboard->FromXml($sDashboardDefinition);
|
||||
@@ -954,11 +912,11 @@ class RuntimeDashboard extends Dashboard
|
||||
* @inheritDoc
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function Render($oPage, $bEditMode = false, $aExtraParams = array(), $bCanEdit = true)
|
||||
public function Render($oPage, $bEditMode = false, $aExtraParams = [], $bCanEdit = true)
|
||||
{
|
||||
if (!isset($aExtraParams['query_params']) && isset($aExtraParams['this->class'])) {
|
||||
$oObj = MetaModel::GetObject($aExtraParams['this->class'], $aExtraParams['this->id']);
|
||||
$aRenderParams = array('query_params' => $oObj->ToArgsForQuery());
|
||||
$aRenderParams = ['query_params' => $oObj->ToArgsForQuery()];
|
||||
} else {
|
||||
$aRenderParams = $aExtraParams;
|
||||
}
|
||||
@@ -968,7 +926,7 @@ class RuntimeDashboard extends Dashboard
|
||||
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());
|
||||
$aAjaxParams = ['this->class' => get_class($oObj), 'this->id' => $oObj->GetKey()];
|
||||
if (isset($aExtraParams['from_dashboard_page'])) {
|
||||
$aAjaxParams['from_dashboard_page'] = $aExtraParams['from_dashboard_page'];
|
||||
}
|
||||
@@ -1001,9 +959,7 @@ class RuntimeDashboard extends Dashboard
|
||||
}
|
||||
JS
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
$oPage->add_script(
|
||||
<<<EOF
|
||||
if (typeof(AutoReloadDashboardId$sDivId) !== 'undefined')
|
||||
@@ -1032,7 +988,7 @@ EOF
|
||||
* @throws \CoreUnexpectedValue
|
||||
* @throws \MySQLException
|
||||
*/
|
||||
protected function RenderSelector(WebPage $oPage, DashboardLayoutUIBlock $oDashboard, $aAjaxParams = array())
|
||||
protected function RenderSelector(WebPage $oPage, DashboardLayoutUIBlock $oDashboard, $aAjaxParams = [])
|
||||
{
|
||||
if (!$this->HasCustomDashboard()) {
|
||||
return;
|
||||
@@ -1070,7 +1026,7 @@ EOF
|
||||
var dashboard = $('.ibo-dashboard#$sDivId')
|
||||
dashboard.block();
|
||||
$.post(GetAbsoluteUrlAppRoot()+'pages/ajax.render.php',
|
||||
{ operation: 'toggle_dashboard', dashboard_id: '$sId', file: '$sFile', extra_params: $sExtraParams, reload_url: '$sReloadURL' },
|
||||
{ operation: 'toggle_dashboard', dashboard_id: '$sId', file: '$sFile', extra_params: $sExtraParams, reload_url: $sReloadURL },
|
||||
function(data) {
|
||||
dashboard.html(data);
|
||||
dashboard.unblock();
|
||||
@@ -1092,8 +1048,7 @@ JS
|
||||
*/
|
||||
protected function HasCustomDashboard()
|
||||
{
|
||||
try
|
||||
{
|
||||
try {
|
||||
// Search for an eventual user defined dashboard
|
||||
$oUDSearch = new DBObjectSearch('UserDashboard');
|
||||
$oUDSearch->AddCondition('user_id', UserRights::GetUserId(), '=');
|
||||
@@ -1101,9 +1056,7 @@ JS
|
||||
$oUDSet = new DBObjectSet($oUDSearch);
|
||||
|
||||
return ($oUDSet->Count() > 0);
|
||||
}
|
||||
catch (Exception $e)
|
||||
{
|
||||
} catch (Exception $e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -1139,21 +1092,23 @@ JS
|
||||
->AddCSSClass('ibo-action-button');
|
||||
|
||||
$oToolbar->AddSubBlock($oActionButton);
|
||||
$aActions = array();
|
||||
$aActions = [];
|
||||
$sFile = addslashes(utils::LocalPath($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");
|
||||
$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)");
|
||||
$aActions[$oEdit->GetUID()] = $oEdit->GetMenuItem();
|
||||
}
|
||||
|
||||
|
||||
utils::GetPopupMenuItems($oPage, iPopupMenuExtension::MENU_DASHBOARD_ACTIONS, $this, $aActions);
|
||||
|
||||
$oActionsMenu = $oPage->GetPopoverMenu($sPopoverMenuId, $aActions)
|
||||
@@ -1193,12 +1148,12 @@ EOF
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function RenderProperties($oPage, $aExtraParams = array())
|
||||
public function RenderProperties($oPage, $aExtraParams = [])
|
||||
{
|
||||
parent::RenderProperties($oPage, $aExtraParams);
|
||||
|
||||
$oPage->add_ready_script(
|
||||
<<<EOF
|
||||
<<<EOF
|
||||
$('#select_layout input').on('click', function() {
|
||||
var sLayoutClass = $(this).val();
|
||||
$('.itop-dashboard').runtimedashboard('option', {layout_class: sLayoutClass});
|
||||
@@ -1225,7 +1180,6 @@ EOF
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param WebPage $oPage
|
||||
*
|
||||
@@ -1236,11 +1190,11 @@ EOF
|
||||
* @throws \ReflectionException
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function RenderEditor($oPage, $aExtraParams = array())
|
||||
public function RenderEditor($oPage, $aExtraParams = [])
|
||||
{
|
||||
if (isset($aExtraParams['this->class'])) {
|
||||
$oObj = MetaModel::GetObject($aExtraParams['this->class'], $aExtraParams['this->id']);
|
||||
$aRenderParams = array('query_params' => $oObj->ToArgsForQuery());
|
||||
$aRenderParams = ['query_params' => $oObj->ToArgsForQuery()];
|
||||
} else {
|
||||
$aRenderParams = $aExtraParams;
|
||||
}
|
||||
@@ -1262,7 +1216,7 @@ EOF
|
||||
$sDialogTitle = Dict::S('UI:DashboardEdit:Title');
|
||||
$sOkButtonLabel = Dict::S('UI:Button:Save');
|
||||
$sCancelButtonLabel = Dict::S('UI:Button:Cancel');
|
||||
|
||||
|
||||
$sId = json_encode($this->sId);
|
||||
$sLayoutClass = json_encode($this->sLayoutClass);
|
||||
$sAutoReload = $this->bAutoReload ? 'true' : 'false';
|
||||
@@ -1275,9 +1229,9 @@ EOF
|
||||
$sExitConfirmationMessage = addslashes(Dict::S('UI:NavigateAwayConfirmationMessage'));
|
||||
$sCancelConfirmationMessage = addslashes(Dict::S('UI:CancelConfirmationMessage'));
|
||||
$sAutoApplyConfirmationMessage = addslashes(Dict::S('UI:AutoApplyConfirmationMessage'));
|
||||
|
||||
|
||||
$oPage->add_ready_script(
|
||||
<<<JS
|
||||
<<<JS
|
||||
window.bLeavingOnUserAction = false;
|
||||
|
||||
$('#dashboard_editor').dialog({
|
||||
@@ -1385,104 +1339,89 @@ JS
|
||||
$sContextMenuId = $oAppContext->GetCurrentValue('menu', null);
|
||||
|
||||
$oForm = new DesignerForm();
|
||||
|
||||
|
||||
// Get the list of all 'dashboard' menus in which we can insert a dashlet
|
||||
$aAllMenus = ApplicationMenu::ReflectionMenuNodes();
|
||||
$sRootMenuId = ApplicationMenu::GetRootMenuId($sContextMenuId);
|
||||
$aAllowedDashboards = array();
|
||||
$aAllowedDashboards = [];
|
||||
$sDefaultDashboard = null;
|
||||
|
||||
// Store the parent menus for acces check
|
||||
$aParentMenus = array();
|
||||
foreach($aAllMenus as $idx => $aMenu)
|
||||
{
|
||||
/** @var MenuNode $oMenu */
|
||||
$oMenu = $aMenu['node'];
|
||||
if (count(ApplicationMenu::GetChildren($oMenu->GetIndex())) > 0)
|
||||
{
|
||||
$aParentMenus[$oMenu->GetMenuId()] = $aMenu;
|
||||
}
|
||||
}
|
||||
|
||||
foreach($aAllMenus as $idx => $aMenu)
|
||||
{
|
||||
$aParentMenus = [];
|
||||
foreach ($aAllMenus as $idx => $aMenu) {
|
||||
/** @var MenuNode $oMenu */
|
||||
$oMenu = $aMenu['node'];
|
||||
if ($oMenu instanceof DashboardMenuNode)
|
||||
{
|
||||
// Get the root parent for access check
|
||||
$sParentId = $aMenu['parent'];
|
||||
$aParentMenu = $aParentMenus[$sParentId];
|
||||
while (isset($aParentMenus[$aParentMenu['parent']]))
|
||||
{
|
||||
// grand parent exists
|
||||
$sParentId = $aParentMenu['parent'];
|
||||
$aParentMenu = $aParentMenus[$sParentId];
|
||||
}
|
||||
/** @var \MenuNode $oParentMenu */
|
||||
$oParentMenu = $aParentMenu['node'];
|
||||
if ($oMenu->IsEnabled() && $oParentMenu->IsEnabled())
|
||||
{
|
||||
$sMenuLabel = $oMenu->GetTitle();
|
||||
$sParentLabel = Dict::S('Menu:'.$sParentId);
|
||||
if ($sParentLabel != $sMenuLabel)
|
||||
{
|
||||
$aAllowedDashboards[$oMenu->GetMenuId()] = $sParentLabel.' - '.$sMenuLabel;
|
||||
}
|
||||
else
|
||||
{
|
||||
$aAllowedDashboards[$oMenu->GetMenuId()] = $sMenuLabel;
|
||||
}
|
||||
if (empty($sDefaultDashboard) && ($sRootMenuId == ApplicationMenu::GetRootMenuId($oMenu->GetMenuId())))
|
||||
{
|
||||
$sDefaultDashboard = $oMenu->GetMenuId();
|
||||
}
|
||||
}
|
||||
}
|
||||
if (count(ApplicationMenu::GetChildren($oMenu->GetIndex())) > 0) {
|
||||
$aParentMenus[$oMenu->GetMenuId()] = $aMenu;
|
||||
}
|
||||
}
|
||||
asort($aAllowedDashboards);
|
||||
|
||||
$oField = new DesignerComboField('menu_id', Dict::S('UI:DashletCreation:Dashboard'), $sDefaultDashboard);
|
||||
$oField->SetAllowedValues($aAllowedDashboards);
|
||||
$oField->SetMandatory(true);
|
||||
$oForm->AddField($oField);
|
||||
|
||||
// Get the list of possible dashlets that support a creation from
|
||||
// an OQL
|
||||
$aDashlets = array();
|
||||
foreach(get_declared_classes() as $sDashletClass)
|
||||
{
|
||||
if (is_subclass_of($sDashletClass, 'Dashlet'))
|
||||
{
|
||||
$oReflection = new ReflectionClass($sDashletClass);
|
||||
if (!$oReflection->isAbstract())
|
||||
{
|
||||
$aCallSpec = array($sDashletClass, 'CanCreateFromOQL');
|
||||
$bShorcutMode = call_user_func($aCallSpec);
|
||||
if ($bShorcutMode)
|
||||
{
|
||||
$aCallSpec = array($sDashletClass, 'GetInfo');
|
||||
$aInfo = call_user_func($aCallSpec);
|
||||
$aDashlets[$sDashletClass] = array('label' => $aInfo['label'], 'class' => $sDashletClass, 'icon' => $aInfo['icon']);
|
||||
|
||||
foreach ($aAllMenus as $idx => $aMenu) {
|
||||
$oMenu = $aMenu['node'];
|
||||
if ($oMenu instanceof DashboardMenuNode) {
|
||||
// Get the root parent for access check
|
||||
$sParentId = $aMenu['parent'];
|
||||
$aParentMenu = $aParentMenus[$sParentId];
|
||||
while (isset($aParentMenus[$aParentMenu['parent']])) {
|
||||
// grand parent exists
|
||||
$sParentId = $aParentMenu['parent'];
|
||||
$aParentMenu = $aParentMenus[$sParentId];
|
||||
}
|
||||
/** @var \MenuNode $oParentMenu */
|
||||
$oParentMenu = $aParentMenu['node'];
|
||||
if ($oMenu->IsEnabled() && $oParentMenu->IsEnabled()) {
|
||||
$sMenuLabel = $oMenu->GetTitle();
|
||||
$sParentLabel = Dict::S('Menu:'.$sParentId);
|
||||
if ($sParentLabel != $sMenuLabel) {
|
||||
$aAllowedDashboards[$oMenu->GetMenuId()] = $sParentLabel.' - '.$sMenuLabel;
|
||||
} else {
|
||||
$aAllowedDashboards[$oMenu->GetMenuId()] = $sMenuLabel;
|
||||
}
|
||||
if (empty($sDefaultDashboard) && ($sRootMenuId == ApplicationMenu::GetRootMenuId($oMenu->GetMenuId()))) {
|
||||
$sDefaultDashboard = $oMenu->GetMenuId();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
asort($aAllowedDashboards);
|
||||
|
||||
$oField = new DesignerComboField('menu_id', Dict::S('UI:DashletCreation:Dashboard'), $sDefaultDashboard);
|
||||
$oField->SetAllowedValues($aAllowedDashboards);
|
||||
$oField->SetMandatory(true);
|
||||
$oForm->AddField($oField);
|
||||
|
||||
// Get the list of possible dashlets that support a creation from
|
||||
// an OQL
|
||||
$aDashlets = [];
|
||||
foreach (get_declared_classes() as $sDashletClass) {
|
||||
if (is_subclass_of($sDashletClass, 'Dashlet')) {
|
||||
$oReflection = new ReflectionClass($sDashletClass);
|
||||
if (!$oReflection->isAbstract()) {
|
||||
$aCallSpec = [$sDashletClass, 'CanCreateFromOQL'];
|
||||
$bShorcutMode = call_user_func($aCallSpec);
|
||||
if ($bShorcutMode) {
|
||||
$aCallSpec = [$sDashletClass, 'GetInfo'];
|
||||
$aInfo = call_user_func($aCallSpec);
|
||||
$aDashlets[$sDashletClass] = ['label' => $aInfo['label'], 'class' => $sDashletClass, 'icon' => $aInfo['icon']];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$oSelectorField = new DesignerFormSelectorField('dashlet_class', Dict::S('UI:DashletCreation:DashletType'), '');
|
||||
$oForm->AddField($oSelectorField);
|
||||
foreach($aDashlets as $sDashletClass => $aDashletInfo)
|
||||
{
|
||||
foreach ($aDashlets as $sDashletClass => $aDashletInfo) {
|
||||
$oSubForm = new DesignerForm();
|
||||
$oMetaModel = new ModelReflectionRuntime();
|
||||
/** @var \Dashlet $oDashlet */
|
||||
$oDashlet = new $sDashletClass($oMetaModel, 0);
|
||||
$oDashlet->GetPropertiesFieldsFromOQL($oSubForm, $sOQL);
|
||||
|
||||
|
||||
$oSelectorField->AddSubForm($oSubForm, $aDashletInfo['label'], $aDashletInfo['class']);
|
||||
}
|
||||
$oField = new DesignerBooleanField('open_editor', Dict::S('UI:DashletCreation:EditNow'), true);
|
||||
$oForm->AddField($oField);
|
||||
|
||||
|
||||
return $oForm;
|
||||
}
|
||||
|
||||
@@ -1501,11 +1440,11 @@ JS
|
||||
|
||||
$oForm->Render($oPage);
|
||||
$oPage->add('</div>');
|
||||
|
||||
|
||||
$sDialogTitle = Dict::S('UI:DashletCreation:Title');
|
||||
$sOkButtonLabel = Dict::S('UI:Button:Ok');
|
||||
$sCancelButtonLabel = Dict::S('UI:Button:Cancel');
|
||||
|
||||
|
||||
$oPage->add_ready_script(
|
||||
<<<JS
|
||||
$('#dashlet_creation_dlg').dialog({
|
||||
@@ -1603,7 +1542,7 @@ JS
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
protected function PrepareDashletForRendering(Dashlet $oDashlet, $aCoordinates, $aExtraParams = array())
|
||||
protected function PrepareDashletForRendering(Dashlet $oDashlet, $aCoordinates, $aExtraParams = [])
|
||||
{
|
||||
$sDashletIdOrig = $oDashlet->GetID();
|
||||
$sDashboardSanitizedId = $this->GetSanitizedId();
|
||||
@@ -1630,31 +1569,27 @@ JS
|
||||
private function UpdateDashletUserPrefs(Dashlet $oDashlet, $sDashletIdOrig, array $aExtraParams)
|
||||
{
|
||||
$bIsDashletWithListPref = ($oDashlet instanceof DashletObjectList);
|
||||
if (!$bIsDashletWithListPref)
|
||||
{
|
||||
if (!$bIsDashletWithListPref) {
|
||||
return;
|
||||
}
|
||||
/** @var \DashletObjectList $oDashlet */
|
||||
|
||||
$bDashletIdInNewFormat = ($sDashletIdOrig === $oDashlet->GetID());
|
||||
if ($bDashletIdInNewFormat)
|
||||
{
|
||||
if ($bDashletIdInNewFormat) {
|
||||
return;
|
||||
}
|
||||
|
||||
$sNewPrefKey = $this->GetDashletObjectListAppUserPreferencesPrefix($oDashlet, $aExtraParams, $oDashlet->GetID());
|
||||
$sPrefValueForNewKey = appUserPreferences::GetPref($sNewPrefKey, null);
|
||||
$bHasPrefInNewFormat = ($sPrefValueForNewKey !== null);
|
||||
if ($bHasPrefInNewFormat)
|
||||
{
|
||||
if ($bHasPrefInNewFormat) {
|
||||
return;
|
||||
}
|
||||
|
||||
$sOldPrefKey = $this->GetDashletObjectListAppUserPreferencesPrefix($oDashlet, $aExtraParams, $sDashletIdOrig);
|
||||
$sPrefValueForOldKey = appUserPreferences::GetPref($sOldPrefKey, null);
|
||||
$bHasPrefInOldFormat = ($sPrefValueForOldKey !== null);
|
||||
if (!$bHasPrefInOldFormat)
|
||||
{
|
||||
if (!$bHasPrefInOldFormat) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1673,7 +1608,7 @@ JS
|
||||
private function GetDashletObjectListAppUserPreferencesPrefix(DashletObjectList $oDashlet, $aExtraParams, $sDashletId)
|
||||
{
|
||||
$sDataTableId = Dashlet::APPUSERPREFERENCES_PREFIX.$sDashletId;
|
||||
$aClassAliases = array();
|
||||
$aClassAliases = [];
|
||||
try {
|
||||
$oFilter = $oDashlet->GetDBSearch($aExtraParams);
|
||||
$aClassAliases = $oFilter->GetSelectedClasses();
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
<?php
|
||||
|
||||
// Copyright (C) 2010-2024 Combodo SAS
|
||||
//
|
||||
// This file is part of iTop.
|
||||
//
|
||||
// iTop is free software; you can redistribute it and/or modify
|
||||
// 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.
|
||||
@@ -38,21 +39,21 @@ abstract class DashboardLayout
|
||||
* @since 2.7.0
|
||||
*/
|
||||
abstract public function GetDashletCoordinates($iCellIdx);
|
||||
|
||||
|
||||
public static function GetInfo()
|
||||
{
|
||||
return array(
|
||||
return [
|
||||
'label' => '',
|
||||
'icon' => '',
|
||||
'description' => '',
|
||||
);
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
abstract class DashboardLayoutMultiCol extends DashboardLayout
|
||||
{
|
||||
protected $iNbCols;
|
||||
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->iNbCols = 1;
|
||||
@@ -63,47 +64,38 @@ abstract class DashboardLayoutMultiCol extends DashboardLayout
|
||||
$aKeys = array_reverse(array_keys($aDashlets));
|
||||
$idx = 0;
|
||||
$bNoVisibleFound = true;
|
||||
while($idx < count($aKeys) && $bNoVisibleFound)
|
||||
{
|
||||
while ($idx < count($aKeys) && $bNoVisibleFound) {
|
||||
/** @var \Dashlet $oDashlet */
|
||||
$oDashlet = $aDashlets[$aKeys[$idx]];
|
||||
if ($oDashlet::IsVisible())
|
||||
{
|
||||
if ($oDashlet::IsVisible()) {
|
||||
$bNoVisibleFound = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
unset($aDashlets[$aKeys[$idx]]);
|
||||
}
|
||||
$idx++;
|
||||
}
|
||||
return $aDashlets;
|
||||
}
|
||||
|
||||
|
||||
protected function TrimCellsArray($aCells)
|
||||
{
|
||||
foreach($aCells as $key => $aDashlets)
|
||||
{
|
||||
foreach ($aCells as $key => $aDashlets) {
|
||||
$aCells[$key] = $this->TrimCell($aDashlets);
|
||||
}
|
||||
$aKeys = array_reverse(array_keys($aCells));
|
||||
$idx = 0;
|
||||
$bNoVisibleFound = true;
|
||||
while($idx < count($aKeys) && $bNoVisibleFound)
|
||||
{
|
||||
while ($idx < count($aKeys) && $bNoVisibleFound) {
|
||||
$aDashlets = $aCells[$aKeys[$idx]];
|
||||
if (count($aDashlets) > 0)
|
||||
{
|
||||
if (count($aDashlets) > 0) {
|
||||
$bNoVisibleFound = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
unset($aCells[$aKeys[$idx]]);
|
||||
}
|
||||
$idx++;
|
||||
}
|
||||
return $aCells;
|
||||
|
||||
return $aCells;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -112,7 +104,7 @@ abstract class DashboardLayoutMultiCol extends DashboardLayout
|
||||
* @param bool $bEditMode
|
||||
* @param array $aExtraParams
|
||||
*/
|
||||
public function Render($oPage, $aCells, $bEditMode = false, $aExtraParams = array())
|
||||
public function Render($oPage, $aCells, $bEditMode = false, $aExtraParams = [])
|
||||
{
|
||||
// Trim the list of cells to remove the invisible/empty ones at the end of the array
|
||||
$aCells = $this->TrimCellsArray($aCells);
|
||||
@@ -157,8 +149,7 @@ abstract class DashboardLayoutMultiCol extends DashboardLayout
|
||||
|
||||
$oPage->add_script("function updateDashboard".$aExtraParams['dashboard_div_id']."(){".$sJSReload."}");
|
||||
|
||||
if ($bEditMode) // Add one row for extensibility
|
||||
{
|
||||
if ($bEditMode) { // Add one row for extensibility
|
||||
$oDashboardRow = new DashboardRow();
|
||||
$oDashboardLayout->AddDashboardRow($oDashboardRow);
|
||||
|
||||
@@ -180,7 +171,7 @@ abstract class DashboardLayoutMultiCol extends DashboardLayout
|
||||
$iColNumber = (int) $iCellIdx % $this->iNbCols;
|
||||
$iRowNumber = (int) floor($iCellIdx / $this->iNbCols);
|
||||
|
||||
return array($iColNumber, $iRowNumber);
|
||||
return [$iColNumber, $iRowNumber];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -191,13 +182,13 @@ class DashboardLayoutOneCol extends DashboardLayoutMultiCol
|
||||
parent::__construct();
|
||||
$this->iNbCols = 1;
|
||||
}
|
||||
static public function GetInfo()
|
||||
public static function GetInfo()
|
||||
{
|
||||
return array(
|
||||
return [
|
||||
'label' => 'One Column',
|
||||
'icon' => 'images/layout_1col.png',
|
||||
'description' => '',
|
||||
);
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -208,13 +199,13 @@ class DashboardLayoutTwoCols extends DashboardLayoutMultiCol
|
||||
parent::__construct();
|
||||
$this->iNbCols = 2;
|
||||
}
|
||||
static public function GetInfo()
|
||||
public static function GetInfo()
|
||||
{
|
||||
return array(
|
||||
return [
|
||||
'label' => 'Two Columns',
|
||||
'icon' => 'images/layout_2col.png',
|
||||
'description' => '',
|
||||
);
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -225,12 +216,12 @@ class DashboardLayoutThreeCols extends DashboardLayoutMultiCol
|
||||
parent::__construct();
|
||||
$this->iNbCols = 3;
|
||||
}
|
||||
static public function GetInfo()
|
||||
public static function GetInfo()
|
||||
{
|
||||
return array(
|
||||
return [
|
||||
'label' => 'Two Columns',
|
||||
'icon' => 'images/layout_3col.png',
|
||||
'description' => '',
|
||||
);
|
||||
];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -80,42 +80,31 @@ class DataTable
|
||||
|
||||
// Identified tables can have their own specific settings
|
||||
$oCustomSettings = DataTableSettings::GetTableSettings($this->aClassAliases, $this->sTableId);
|
||||
|
||||
if ($oCustomSettings != null)
|
||||
{
|
||||
|
||||
if ($oCustomSettings != null) {
|
||||
// Custom settings overload the default ones
|
||||
$this->bUseCustomSettings = true;
|
||||
if ($this->oDefaultSettings->iDefaultPageSize == 0)
|
||||
{
|
||||
if ($this->oDefaultSettings->iDefaultPageSize == 0) {
|
||||
$oCustomSettings->iDefaultPageSize = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
$oCustomSettings = $oSettings;
|
||||
}
|
||||
|
||||
if ($oCustomSettings->iDefaultPageSize > 0)
|
||||
{
|
||||
if ($oCustomSettings->iDefaultPageSize > 0) {
|
||||
$this->oSet->SetLimit($oCustomSettings->iDefaultPageSize);
|
||||
}
|
||||
$this->oSet->SetOrderBy($oCustomSettings->GetSortOrder());
|
||||
|
||||
// Load only the requested columns
|
||||
$aColumnsToLoad = array();
|
||||
foreach($oCustomSettings->aColumns as $sAlias => $aColumnsInfo)
|
||||
{
|
||||
foreach($aColumnsInfo as $sAttCode => $aData)
|
||||
{
|
||||
if ($sAttCode != '_key_')
|
||||
{
|
||||
if ($aData['checked'])
|
||||
{
|
||||
$aColumnsToLoad = [];
|
||||
foreach ($oCustomSettings->aColumns as $sAlias => $aColumnsInfo) {
|
||||
foreach ($aColumnsInfo as $sAttCode => $aData) {
|
||||
if ($sAttCode != '_key_') {
|
||||
if ($aData['checked']) {
|
||||
$aColumnsToLoad[$sAlias][] = $sAttCode;
|
||||
}
|
||||
else
|
||||
{
|
||||
// See if this column is a must to load
|
||||
} else {
|
||||
// See if this column is a must to load
|
||||
$sClass = $this->aClassAliases[$sAlias];
|
||||
$oAttDef = MetaModel::GetAttributeDef($sClass, $sAttCode);
|
||||
if ($oAttDef->AlwaysLoadInTables()) {
|
||||
@@ -127,18 +116,15 @@ class DataTable
|
||||
}
|
||||
$this->oSet->OptimizeColumnLoad($aColumnsToLoad);
|
||||
|
||||
|
||||
$bToolkitMenu = true;
|
||||
if (isset($aExtraParams['toolkit_menu']))
|
||||
{
|
||||
if (isset($aExtraParams['toolkit_menu'])) {
|
||||
$bToolkitMenu = (bool) $aExtraParams['toolkit_menu'];
|
||||
}
|
||||
if (UserRights::IsPortalUser())
|
||||
{
|
||||
if (UserRights::IsPortalUser()) {
|
||||
// Portal users have a limited access to data, for now they can only see what's configured for them
|
||||
$bToolkitMenu = false;
|
||||
}
|
||||
|
||||
|
||||
return $this->GetAsHTML($oPage, $oCustomSettings->iDefaultPageSize, $oCustomSettings->iDefaultPageSize, 0, $oCustomSettings->aColumns, $bActionsMenu, $bToolkitMenu, $sSelectMode, $bViewLink, $aExtraParams);
|
||||
}
|
||||
|
||||
@@ -167,10 +153,10 @@ class DataTable
|
||||
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);
|
||||
@@ -188,7 +174,7 @@ class DataTable
|
||||
|
||||
$aExtraParams['show_obsolete_data'] = $this->bShowObsoleteData;
|
||||
|
||||
$aOptions = array(
|
||||
$aOptions = [
|
||||
'sPersistentId' => '',
|
||||
'sFilter' => $this->oSet->GetFilter()->serialize(),
|
||||
'oColumns' => $aColumns,
|
||||
@@ -202,12 +188,11 @@ class DataTable
|
||||
'sTableId' => $this->sTableId,
|
||||
'oExtraParams' => $aExtraParams,
|
||||
'sRenderUrl' => utils::GetAbsoluteUrlAppRoot().'pages/ajax.render.php',
|
||||
'oRenderParameters' => array('str' => ''), // Forces JSON to encode this as a object...
|
||||
'oDefaultSettings' => array('str' => ''), // Forces JSON to encode this as a object...
|
||||
'oLabels' => array('moveup' => Dict::S('UI:Button:MoveUp'), 'movedown' => Dict::S('UI:Button:MoveDown')),
|
||||
);
|
||||
if($this->oDefaultSettings != null)
|
||||
{
|
||||
'oRenderParameters' => ['str' => ''], // Forces JSON to encode this as a object...
|
||||
'oDefaultSettings' => ['str' => ''], // Forces JSON to encode this as a object...
|
||||
'oLabels' => ['moveup' => Dict::S('UI:Button:MoveUp'), 'movedown' => Dict::S('UI:Button:MoveDown')],
|
||||
];
|
||||
if ($this->oDefaultSettings != null) {
|
||||
$aOptions['oDefaultSettings'] = $this->GetAsHash($this->oDefaultSettings);
|
||||
}
|
||||
$sJSOptions = json_encode($aOptions);
|
||||
@@ -222,16 +207,14 @@ class DataTable
|
||||
*/
|
||||
public function GetAsHTMLTableRows(WebPage $oPage, $iPageSize, $aColumns, $sSelectMode, $bViewLink, $aExtraParams)
|
||||
{
|
||||
if ($iPageSize < 1)
|
||||
{
|
||||
if ($iPageSize < 1) {
|
||||
$iPageSize = -1; // convention: no pagination
|
||||
}
|
||||
$aAttribs = $this->GetHTMLTableConfig($aColumns, $sSelectMode, $bViewLink);
|
||||
$aValues = $this->GetHTMLTableValues($aColumns, $sSelectMode, $iPageSize, $bViewLink, $aExtraParams);
|
||||
|
||||
|
||||
$sHtml = '';
|
||||
foreach($aValues as $aRow)
|
||||
{
|
||||
foreach ($aValues as $aRow) {
|
||||
$sHtml .= $oPage->GetTableRow($aRow, $aAttribs);
|
||||
}
|
||||
return $sHtml;
|
||||
@@ -245,15 +228,12 @@ class DataTable
|
||||
*/
|
||||
protected function GetObjectCount(WebPage $oPage, $sSelectMode)
|
||||
{
|
||||
if (($sSelectMode == 'single') || ($sSelectMode == 'multiple'))
|
||||
{
|
||||
if (($sSelectMode == 'single') || ($sSelectMode == 'multiple')) {
|
||||
$sHtml = '<div class="pagination_objcount">'.Dict::Format('UI:Pagination:HeaderSelection', '<span id="total">'.$this->iNbObjects.'</span>', '<span class="selectedCount">0</span>').'</div>';
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
$sHtml = '<div class="pagination_objcount">'.Dict::Format('UI:Pagination:HeaderNoSelection', '<span id="total">'.$this->iNbObjects.'</span>').'</div>';
|
||||
}
|
||||
return $sHtml;
|
||||
return $sHtml;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -267,26 +247,19 @@ class DataTable
|
||||
protected function GetPager(WebPage $oPage, $iPageSize, $iDefaultPageSize, $iPageIndex)
|
||||
{
|
||||
$sHtml = '';
|
||||
if ($iPageSize < 1) // Display all
|
||||
{
|
||||
if ($iPageSize < 1) { // Display all
|
||||
$sPagerStyle = 'style="display:none"'; // no limit: display the full table, so hide the "pager" UI
|
||||
// WARNING: mPDF does not take the "display" style into account
|
||||
// when applied to a <td> or a <table> tag, so make sure you apply this to a div
|
||||
}
|
||||
else
|
||||
{
|
||||
// WARNING: mPDF does not take the "display" style into account
|
||||
// when applied to a <td> or a <table> tag, so make sure you apply this to a div
|
||||
} else {
|
||||
$sPagerStyle = '';
|
||||
}
|
||||
|
||||
|
||||
$sCombo = '<select class="pagesize">';
|
||||
if($iPageSize < 1)
|
||||
{
|
||||
if ($iPageSize < 1) {
|
||||
$sCombo .= "<option selected=\"selected\" value=\"-1\">".Dict::S('UI:Pagination:All')."</option>";
|
||||
}
|
||||
else
|
||||
{
|
||||
for($iPage = 1; $iPage < 5; $iPage++)
|
||||
{
|
||||
} else {
|
||||
for ($iPage = 1; $iPage < 5; $iPage++) {
|
||||
$iNbItems = $iPage * $iDefaultPageSize;
|
||||
$sSelected = ($iNbItems == $iPageSize) ? 'selected="selected"' : '';
|
||||
$sCombo .= "<option $sSelected value=\"$iNbItems\">$iNbItems</option>";
|
||||
@@ -295,31 +268,25 @@ class DataTable
|
||||
}
|
||||
|
||||
$sCombo .= '</select>';
|
||||
|
||||
|
||||
$sPages = Dict::S('UI:Pagination:PagesLabel');
|
||||
$sPageSizeCombo = Dict::Format('UI:Pagination:PageSize', $sCombo);
|
||||
|
||||
|
||||
$iNbPages = ($iPageSize < 1) ? 1 : ceil($this->iNbObjects / $iPageSize);
|
||||
if ($iNbPages == 1)
|
||||
{
|
||||
if ($iNbPages == 1) {
|
||||
// No need to display the pager
|
||||
$sPagerStyle = 'style="display:none"';
|
||||
}
|
||||
$aPagesToDisplay = array();
|
||||
for($idx = 0; $idx <= min(4, $iNbPages-1); $idx++)
|
||||
{
|
||||
if ($idx == 0)
|
||||
{
|
||||
$aPagesToDisplay = [];
|
||||
for ($idx = 0; $idx <= min(4, $iNbPages - 1); $idx++) {
|
||||
if ($idx == 0) {
|
||||
$aPagesToDisplay[$idx] = '<span page="0" class="curr_page">1</span>';
|
||||
}
|
||||
else
|
||||
{
|
||||
$aPagesToDisplay[$idx] = "<span id=\"gotopage_$idx\" class=\"gotopage\" page=\"$idx\">".(1+$idx)."</span>";
|
||||
} else {
|
||||
$aPagesToDisplay[$idx] = "<span id=\"gotopage_$idx\" class=\"gotopage\" page=\"$idx\">".(1 + $idx)."</span>";
|
||||
}
|
||||
}
|
||||
$iLastPageIdx = $iNbPages - 1;
|
||||
if (!isset($aPagesToDisplay[$iLastPageIdx]))
|
||||
{
|
||||
if (!isset($aPagesToDisplay[$iLastPageIdx])) {
|
||||
unset($aPagesToDisplay[$idx - 1]); // remove the last page added to make room for the very last page
|
||||
$aPagesToDisplay[$iLastPageIdx] = "<span id=\"gotopage_$iLastPageIdx\" class=\"gotopage\" page=\"$iLastPageIdx\">... $iNbPages</span>";
|
||||
}
|
||||
@@ -386,22 +353,19 @@ EOF;
|
||||
*/
|
||||
protected function GetToolkitMenu(WebPage $oPage, $aExtraParams)
|
||||
{
|
||||
if (!$oPage->IsPrintableVersion())
|
||||
{
|
||||
if (!$oPage->IsPrintableVersion()) {
|
||||
$sMenuTitle = Dict::S('UI:ConfigureThisList');
|
||||
$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(
|
||||
$aActions = [
|
||||
$oMenuItem1->GetUID() => $oMenuItem1->GetMenuItem(),
|
||||
);
|
||||
];
|
||||
$this->oSet->Rewind();
|
||||
utils::GetPopupMenuItems($oPage, iPopupMenuExtension::MENU_OBJLIST_TOOLKIT, $this->oSet, $aActions, $this->sTableId, $this->iListId);
|
||||
$this->oSet->Rewind();
|
||||
$sHtml .= $oPage->RenderPopupMenuItems($aActions);
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
$sHtml = '';
|
||||
}
|
||||
return $sHtml;
|
||||
@@ -422,10 +386,10 @@ EOF;
|
||||
$sChecked = ($this->bUseCustomSettings) ? '' : 'checked';
|
||||
$sHtml .= "<p><input id=\"dtbl_dlg_settings_{$this->iListId}\" type=\"radio\" name=\"settings\" $sChecked value=\"defaults\"><label for=\"dtbl_dlg_settings_{$this->iListId}\"> ".Dict::S('UI:UseDefaultSettings').'</label></p>';
|
||||
$sHtml .= "<fieldset>";
|
||||
$sChecked = ($this->bUseCustomSettings) ? 'checked': '';
|
||||
$sChecked = ($this->bUseCustomSettings) ? 'checked' : '';
|
||||
$sHtml .= "<legend class=\"transparent\"><input id=\"dtbl_dlg_specific_{$this->iListId}\" type=\"radio\" class=\"specific_settings\" name=\"settings\" $sChecked value=\"specific\"><label for=\"dtbl_dlg_specific_{$this->iListId}\"> ".Dict::S('UI:UseSpecificSettings')."</label></legend>";
|
||||
$sHtml .= Dict::S('UI:ColumnsAndSortOrder').'<br/><ul class="sortable_field_list" id="sfl_'.$this->iListId.'"></ul>';
|
||||
|
||||
|
||||
$sHtml .= '<p>'.Dict::Format('UI:Display_X_ItemsPerPage', '<input type="text" size="4" name="page_size" value="'.$iDefaultPageSize.'">').'</p>';
|
||||
$sHtml .= "</fieldset>";
|
||||
$sHtml .= "<fieldset>";
|
||||
@@ -444,7 +408,7 @@ EOF;
|
||||
$sHtml .= '</td></tr></table>';
|
||||
$sHtml .= "</form>";
|
||||
$sHtml .= "</div>";
|
||||
|
||||
|
||||
$sDlgTitle = addslashes(Dict::S('UI:ListConfigurationTitle'));
|
||||
$oPage->add_ready_script("$('#datatable_dlg_{$this->iListId}').dialog({autoOpen: false, title: '$sDlgTitle', width: 500, close: function() { $('#{$this->sDatatableContainerId}').datatable('onDlgCancel'); } });");
|
||||
|
||||
@@ -458,7 +422,7 @@ EOF;
|
||||
*/
|
||||
public function GetAsHash($oSetting)
|
||||
{
|
||||
$aSettings = array('iDefaultPageSize' => $oSetting->iDefaultPageSize, 'oColumns' => $oSetting->aColumns);
|
||||
$aSettings = ['iDefaultPageSize' => $oSetting->iDefaultPageSize, 'oColumns' => $oSetting->aColumns];
|
||||
return $aSettings;
|
||||
}
|
||||
|
||||
@@ -474,55 +438,46 @@ EOF;
|
||||
*/
|
||||
protected function GetHTMLTableConfig($aColumns, $sSelectMode, $bViewLink)
|
||||
{
|
||||
$aAttribs = array();
|
||||
if ($sSelectMode == 'multiple')
|
||||
{
|
||||
$aAttribs['form::select'] = array(
|
||||
$aAttribs = [];
|
||||
if ($sSelectMode == 'multiple') {
|
||||
$aAttribs['form::select'] = [
|
||||
'label' => "<input type=\"checkbox\" onClick=\"CheckAll('.selectList{$this->iListId}:not(:disabled)', this.checked);\" class=\"checkAll\"></input>",
|
||||
'description' => Dict::S('UI:SelectAllToggle+'),
|
||||
'metadata' => array(),
|
||||
);
|
||||
}
|
||||
else if ($sSelectMode == 'single')
|
||||
{
|
||||
$aAttribs['form::select'] = array('label' => '', 'description' => '', 'metadata' => array());
|
||||
'metadata' => [],
|
||||
];
|
||||
} elseif ($sSelectMode == 'single') {
|
||||
$aAttribs['form::select'] = ['label' => '', 'description' => '', 'metadata' => []];
|
||||
}
|
||||
|
||||
foreach($this->aClassAliases as $sAlias => $sClassName)
|
||||
{
|
||||
foreach($aColumns[$sAlias] as $sAttCode => $aData)
|
||||
{
|
||||
if ($aData['checked'])
|
||||
{
|
||||
if ($sAttCode == '_key_')
|
||||
{
|
||||
foreach ($this->aClassAliases as $sAlias => $sClassName) {
|
||||
foreach ($aColumns[$sAlias] as $sAttCode => $aData) {
|
||||
if ($aData['checked']) {
|
||||
if ($sAttCode == '_key_') {
|
||||
$sAttLabel = MetaModel::GetName($sClassName);
|
||||
|
||||
$aAttribs['key_'.$sAlias] = array(
|
||||
$aAttribs['key_'.$sAlias] = [
|
||||
'label' => $sAttLabel,
|
||||
'description' => '',
|
||||
'metadata' => array(
|
||||
'metadata' => [
|
||||
'object_class' => $sClassName,
|
||||
'attribute_label' => $sAttLabel,
|
||||
),
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
],
|
||||
];
|
||||
} else {
|
||||
$oAttDef = MetaModel::GetAttributeDef($sClassName, $sAttCode);
|
||||
$sAttDefClass = get_class($oAttDef);
|
||||
$sAttLabel = MetaModel::GetLabel($sClassName, $sAttCode);
|
||||
|
||||
$aAttribs[$sAttCode.'_'.$sAlias] = array(
|
||||
$aAttribs[$sAttCode.'_'.$sAlias] = [
|
||||
'label' => $sAttLabel,
|
||||
'description' => $oAttDef->GetOrderByHint(),
|
||||
'metadata' => array(
|
||||
'metadata' => [
|
||||
'object_class' => $sClassName,
|
||||
'attribute_code' => $sAttCode,
|
||||
'attribute_type' => $sAttDefClass,
|
||||
'attribute_label' => $sAttLabel,
|
||||
),
|
||||
);
|
||||
],
|
||||
];
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -530,7 +485,6 @@ EOF;
|
||||
return $aAttribs;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $aColumns
|
||||
* @param $sSelectMode
|
||||
@@ -549,104 +503,74 @@ EOF;
|
||||
protected function GetHTMLTableValues($aColumns, $sSelectMode, $iPageSize, $bViewLink, $aExtraParams)
|
||||
{
|
||||
$bLocalize = true;
|
||||
if (isset($aExtraParams['localize_values']))
|
||||
{
|
||||
if (isset($aExtraParams['localize_values'])) {
|
||||
$bLocalize = (bool) $aExtraParams['localize_values'];
|
||||
}
|
||||
|
||||
$aValues = array();
|
||||
$aAttDefsCache = array();
|
||||
$aValues = [];
|
||||
$aAttDefsCache = [];
|
||||
$this->oSet->Seek(0);
|
||||
$iMaxObjects = $iPageSize;
|
||||
while (($aObjects = $this->oSet->FetchAssoc()) && ($iMaxObjects != 0))
|
||||
{
|
||||
while (($aObjects = $this->oSet->FetchAssoc()) && ($iMaxObjects != 0)) {
|
||||
$bFirstObject = true;
|
||||
$aRow = array();
|
||||
foreach($this->aClassAliases as $sAlias => $sClassName)
|
||||
{
|
||||
if (is_object($aObjects[$sAlias]))
|
||||
{
|
||||
$aRow = [];
|
||||
foreach ($this->aClassAliases as $sAlias => $sClassName) {
|
||||
if (is_object($aObjects[$sAlias])) {
|
||||
$sHilightClass = MetaModel::GetHilightClass($sClassName, $aObjects[$sAlias]);
|
||||
if ($sHilightClass != '')
|
||||
{
|
||||
$aRow['@class'] = $sHilightClass;
|
||||
if ($sHilightClass != '') {
|
||||
$aRow['@class'] = $sHilightClass;
|
||||
}
|
||||
if ((($sSelectMode == 'single') || ($sSelectMode == 'multiple')) && $bFirstObject)
|
||||
{
|
||||
if (array_key_exists('selection_enabled', $aExtraParams) && isset($aExtraParams['selection_enabled'][$aObjects[$sAlias]->GetKey()]))
|
||||
{
|
||||
if ((($sSelectMode == 'single') || ($sSelectMode == 'multiple')) && $bFirstObject) {
|
||||
if (array_key_exists('selection_enabled', $aExtraParams) && isset($aExtraParams['selection_enabled'][$aObjects[$sAlias]->GetKey()])) {
|
||||
$sDisabled = ($aExtraParams['selection_enabled'][$aObjects[$sAlias]->GetKey()]) ? '' : ' disabled="disabled"';
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
$sDisabled = '';
|
||||
}
|
||||
if ($sSelectMode == 'single')
|
||||
{
|
||||
if ($sSelectMode == 'single') {
|
||||
$aRow['form::select'] = "<input type=\"radio\" $sDisabled class=\"selectList{$this->iListId}\" name=\"selectObject\" value=\"".$aObjects[$sAlias]->GetKey()."\"></input>";
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
$aRow['form::select'] = "<input type=\"checkbox\" $sDisabled class=\"selectList{$this->iListId}\" name=\"selectObject[]\" value=\"".$aObjects[$sAlias]->GetKey()."\"></input>";
|
||||
}
|
||||
}
|
||||
foreach($aColumns[$sAlias] as $sAttCode => $aData)
|
||||
{
|
||||
if ($aData['checked'])
|
||||
{
|
||||
if ($sAttCode == '_key_')
|
||||
{
|
||||
$aRow['key_'.$sAlias] = array(
|
||||
foreach ($aColumns[$sAlias] as $sAttCode => $aData) {
|
||||
if ($aData['checked']) {
|
||||
if ($sAttCode == '_key_') {
|
||||
$aRow['key_'.$sAlias] = [
|
||||
'value_raw' => $aObjects[$sAlias]->GetKey(),
|
||||
'value_html' => $aObjects[$sAlias]->GetHyperLink(),
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
];
|
||||
} else {
|
||||
// Prepare att. def. classes cache to avoid retrieving AttDef for each row
|
||||
if(!isset($aAttDefsCache[$sClassName][$sAttCode]))
|
||||
{
|
||||
if (!isset($aAttDefsCache[$sClassName][$sAttCode])) {
|
||||
$aAttDefClassesCache[$sClassName][$sAttCode] = get_class(MetaModel::GetAttributeDef($sClassName, $sAttCode));
|
||||
}
|
||||
|
||||
// Only retrieve raw (stored) value for simple fields
|
||||
$bExcludeRawValue = false;
|
||||
foreach (cmdbAbstractObject::GetAttDefClassesToExcludeFromMarkupMetadataRawValue() as $sAttDefClassToExclude)
|
||||
{
|
||||
if (is_a($aAttDefClassesCache[$sClassName][$sAttCode], $sAttDefClassToExclude, true))
|
||||
{
|
||||
foreach (cmdbAbstractObject::GetAttDefClassesToExcludeFromMarkupMetadataRawValue() as $sAttDefClassToExclude) {
|
||||
if (is_a($aAttDefClassesCache[$sClassName][$sAttCode], $sAttDefClassToExclude, true)) {
|
||||
$bExcludeRawValue = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if($bExcludeRawValue)
|
||||
{
|
||||
if ($bExcludeRawValue) {
|
||||
$aRow[$sAttCode.'_'.$sAlias] = $aObjects[$sAlias]->GetAsHTML($sAttCode, $bLocalize);
|
||||
}
|
||||
else
|
||||
{
|
||||
$aRow[$sAttCode.'_'.$sAlias] = array(
|
||||
} else {
|
||||
$aRow[$sAttCode.'_'.$sAlias] = [
|
||||
'value_raw' => $aObjects[$sAlias]->Get($sAttCode),
|
||||
'value_html' => $aObjects[$sAlias]->GetAsHTML($sAttCode, $bLocalize),
|
||||
);
|
||||
];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach($aColumns[$sAlias] as $sAttCode => $aData)
|
||||
{
|
||||
if ($aData['checked'])
|
||||
{
|
||||
if ($sAttCode == '_key_')
|
||||
{
|
||||
} else {
|
||||
foreach ($aColumns[$sAlias] as $sAttCode => $aData) {
|
||||
if ($aData['checked']) {
|
||||
if ($sAttCode == '_key_') {
|
||||
$aRow['key_'.$sAlias] = '';
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
$aRow[$sAttCode.'_'.$sAlias] = '';
|
||||
}
|
||||
}
|
||||
@@ -681,8 +605,7 @@ EOF;
|
||||
public function GetHTMLTable(WebPage $oPage, $aColumns, $sSelectMode, $iPageSize, $bViewLink, $aExtraParams)
|
||||
{
|
||||
$iNbPages = ($iPageSize < 1) ? 1 : ceil($this->iNbObjects / $iPageSize);
|
||||
if ($iPageSize < 1)
|
||||
{
|
||||
if ($iPageSize < 1) {
|
||||
$iPageSize = -1; // convention: no pagination
|
||||
}
|
||||
$aAttribs = $this->GetHTMLTableConfig($aColumns, $sSelectMode, $bViewLink);
|
||||
@@ -691,8 +614,7 @@ EOF;
|
||||
|
||||
$sHtml = '<table class="listContainer object-list">';
|
||||
|
||||
foreach($this->oSet->GetFilter()->GetInternalParams() as $sName => $sValue)
|
||||
{
|
||||
foreach ($this->oSet->GetFilter()->GetInternalParams() as $sName => $sValue) {
|
||||
$aExtraParams['query_params'][$sName] = $sValue;
|
||||
}
|
||||
$aExtraParams['show_obsolete_data'] = $this->bShowObsoleteData;
|
||||
@@ -707,20 +629,16 @@ EOF;
|
||||
$sExtraParams = addslashes(str_replace('"', "'", json_encode(array_merge($aExtraParams, $aArgs)))); // JSON encode, change the style of the quotes and escape them
|
||||
$sSelectModeJS = '';
|
||||
$sHeaders = '';
|
||||
if (($sSelectMode == 'single') || ($sSelectMode == 'multiple'))
|
||||
{
|
||||
if (($sSelectMode == 'single') || ($sSelectMode == 'multiple')) {
|
||||
$sSelectModeJS = $sSelectMode;
|
||||
$sHeaders = 'headers: { 0: {sorter: false}},';
|
||||
}
|
||||
$sDisplayKey = ($bViewLink) ? 'true' : 'false';
|
||||
// Protect against duplicate elements in the Zlist
|
||||
$aUniqueOrderedList = array();
|
||||
foreach($this->aClassAliases as $sAlias => $sClassName)
|
||||
{
|
||||
foreach($aColumns[$sAlias] as $sAttCode => $aData)
|
||||
{
|
||||
if ($aData['checked'])
|
||||
{
|
||||
$aUniqueOrderedList = [];
|
||||
foreach ($this->aClassAliases as $sAlias => $sClassName) {
|
||||
foreach ($aColumns[$sAlias] as $sAttCode => $aData) {
|
||||
if ($aData['checked']) {
|
||||
$aUniqueOrderedList[$sAttCode] = true;
|
||||
}
|
||||
}
|
||||
@@ -732,41 +650,32 @@ EOF;
|
||||
$this->oSet->ApplyParameters();
|
||||
// Display the actual sort order of the table
|
||||
$aRealSortOrder = $this->oSet->GetRealSortOrder();
|
||||
$aDefaultSort = array();
|
||||
$aDefaultSort = [];
|
||||
$iColOffset = 0;
|
||||
if (($sSelectMode == 'single') || ($sSelectMode == 'multiple'))
|
||||
{
|
||||
if (($sSelectMode == 'single') || ($sSelectMode == 'multiple')) {
|
||||
$iColOffset += 1;
|
||||
}
|
||||
if ($bViewLink)
|
||||
{
|
||||
// $iColOffset += 1;
|
||||
if ($bViewLink) {
|
||||
// $iColOffset += 1;
|
||||
}
|
||||
foreach($aRealSortOrder as $sColCode => $bAscending)
|
||||
{
|
||||
foreach ($aRealSortOrder as $sColCode => $bAscending) {
|
||||
$iPos = array_search($sColCode, $aUniqueOrderedList);
|
||||
if ($iPos !== false)
|
||||
{
|
||||
$aDefaultSort[] = "[".($iColOffset+$iPos).",".($bAscending ? '0' : '1')."]";
|
||||
}
|
||||
else if (($iPos = array_search(preg_replace('/_friendlyname$/', '', $sColCode), $aUniqueOrderedList)) !== false)
|
||||
{
|
||||
if ($iPos !== false) {
|
||||
$aDefaultSort[] = "[".($iColOffset + $iPos).",".($bAscending ? '0' : '1')."]";
|
||||
} elseif (($iPos = array_search(preg_replace('/_friendlyname$/', '', $sColCode), $aUniqueOrderedList)) !== false) {
|
||||
// if sorted on the friendly name of an external key, then consider it sorted on the column that shows the links
|
||||
$aDefaultSort[] = "[".($iColOffset+$iPos).",".($bAscending ? '0' : '1')."]";
|
||||
}
|
||||
else if($sColCode == 'friendlyname' && $bViewLink)
|
||||
{
|
||||
$aDefaultSort[] = "[".($iColOffset + $iPos).",".($bAscending ? '0' : '1')."]";
|
||||
} elseif ($sColCode == 'friendlyname' && $bViewLink) {
|
||||
$aDefaultSort[] = "[".($iColOffset).",".($bAscending ? '0' : '1')."]";
|
||||
}
|
||||
}
|
||||
$sFakeSortList = '';
|
||||
if (count($aDefaultSort) > 0)
|
||||
{
|
||||
if (count($aDefaultSort) > 0) {
|
||||
$sFakeSortList = '['.implode(',', $aDefaultSort).']';
|
||||
}
|
||||
$sOQL = addslashes($this->oSet->GetFilter()->serialize());
|
||||
$oPage->add_ready_script(
|
||||
<<<JS
|
||||
<<<JS
|
||||
var oTable = $('#{$this->sDatatableContainerId} table.listResults');
|
||||
oTable.tableHover();
|
||||
oTable
|
||||
@@ -784,9 +693,8 @@ oTable
|
||||
class_aliases: $sJSClassAliases $sCssCount
|
||||
});
|
||||
JS
|
||||
);
|
||||
if ($sFakeSortList != '')
|
||||
{
|
||||
);
|
||||
if ($sFakeSortList != '') {
|
||||
$oPage->add_ready_script("oTable.trigger(\"fakesorton\", [$sFakeSortList]);");
|
||||
}
|
||||
return $sHtml;
|
||||
@@ -803,12 +711,9 @@ JS
|
||||
$iPageIndex = 0;
|
||||
$sHtml = $this->GetPager($oPage, $iPageSize, $iDefaultPageSize, $iPageIndex);
|
||||
$oPage->add_ready_script("$('#pager{$this->iListId}').html('".json_encode($sHtml)."');");
|
||||
if ($iDefaultPageSize < 1)
|
||||
{
|
||||
if ($iDefaultPageSize < 1) {
|
||||
$oPage->add_ready_script("$('#pager{$this->iListId}').parent().hide()");
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
$oPage->add_ready_script("$('#pager{$this->iListId}').parent().show()");
|
||||
}
|
||||
}
|
||||
@@ -865,16 +770,15 @@ class PrintableDataTable extends DataTable
|
||||
public function GetHTMLTable(WebPage $oPage, $aColumns, $sSelectMode, $iPageSize, $bViewLink, $aExtraParams)
|
||||
{
|
||||
$iNbPages = ($iPageSize < 1) ? 1 : ceil($this->iNbObjects / $iPageSize);
|
||||
if ($iPageSize < 1)
|
||||
{
|
||||
if ($iPageSize < 1) {
|
||||
$iPageSize = -1; // convention: no pagination
|
||||
}
|
||||
$aAttribs = $this->GetHTMLTableConfig($aColumns, $sSelectMode, $bViewLink);
|
||||
|
||||
|
||||
$aValues = $this->GetHTMLTableValues($aColumns, $sSelectMode, $iPageSize, $bViewLink, $aExtraParams);
|
||||
|
||||
|
||||
$sHtml = $oPage->GetTable($aAttribs, $aValues);
|
||||
|
||||
|
||||
return $sHtml;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* @copyright Copyright (C) 2010-2024 Combodo SAS
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
@@ -104,7 +105,7 @@ class DisplayBlock
|
||||
*/
|
||||
public const ENUM_STYLE_CHART_AJAX = 'chart_ajax';
|
||||
|
||||
const TAG_BLOCK = 'itopblock';
|
||||
public const TAG_BLOCK = 'itopblock';
|
||||
/** @var \DBSearch */
|
||||
protected $m_oFilter;
|
||||
protected $m_aConditions; // Conditions added to the filter -> avoid duplicate conditions
|
||||
@@ -137,20 +138,18 @@ class DisplayBlock
|
||||
*
|
||||
* @throws \ApplicationException
|
||||
*/
|
||||
public function __construct(DBSearch $oFilter, $sStyle = self::ENUM_STYLE_LIST, $bAsynchronous = false, $aParams = array(), $oSet = null)
|
||||
public function __construct(DBSearch $oFilter, $sStyle = self::ENUM_STYLE_LIST, $bAsynchronous = false, $aParams = [], $oSet = null)
|
||||
{
|
||||
$this->m_oFilter = $oFilter->DeepClone();
|
||||
$this->m_aConditions = array();
|
||||
$this->m_aConditions = [];
|
||||
$this->m_sStyle = $sStyle;
|
||||
$this->m_bAsynchronous = $bAsynchronous;
|
||||
$this->m_aParams = $aParams;
|
||||
$this->m_oSet = $oSet;
|
||||
if (array_key_exists('show_obsolete_data', $aParams))
|
||||
{
|
||||
if (array_key_exists('show_obsolete_data', $aParams)) {
|
||||
$this->m_bShowObsoleteData = $aParams['show_obsolete_data'];
|
||||
}
|
||||
if ($this->m_bShowObsoleteData === null)
|
||||
{
|
||||
if ($this->m_bShowObsoleteData === null) {
|
||||
// User defined
|
||||
$this->m_bShowObsoleteData = utils::ShowObsoleteData();
|
||||
}
|
||||
@@ -410,22 +409,18 @@ class DisplayBlock
|
||||
* @throws \CoreException
|
||||
* @throws \Exception
|
||||
*/
|
||||
public static function FromObjectSet(DBObjectSet $oSet, $sStyle, $aParams = array())
|
||||
public static function FromObjectSet(DBObjectSet $oSet, $sStyle, $aParams = [])
|
||||
{
|
||||
$oDummyFilter = new DBObjectSearch($oSet->GetClass());
|
||||
$aKeys = array();
|
||||
$oSet->OptimizeColumnLoad(array($oSet->GetClassAlias() => array())); // No need to load all the columns just to get the id
|
||||
while($oObject = $oSet->Fetch())
|
||||
{
|
||||
$aKeys[] = $oObject->GetKey();
|
||||
$aKeys = [];
|
||||
$oSet->OptimizeColumnLoad([$oSet->GetClassAlias() => []]); // No need to load all the columns just to get the id
|
||||
while ($oObject = $oSet->Fetch()) {
|
||||
$aKeys[] = $oObject->GetKey();
|
||||
}
|
||||
$oSet->Rewind();
|
||||
if (count($aKeys) > 0)
|
||||
{
|
||||
if (count($aKeys) > 0) {
|
||||
$oDummyFilter->AddCondition('id', $aKeys, 'IN');
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
$oDummyFilter->AddCondition('id', 0, '=');
|
||||
}
|
||||
$oBlock = new DisplayBlock($oDummyFilter, $sStyle, false, $aParams); // DisplayBlocks built this way are synchronous
|
||||
@@ -446,7 +441,7 @@ class DisplayBlock
|
||||
$iStartPos = stripos($sTemplate, '<'.self::TAG_BLOCK.' ', 0);
|
||||
$iEndPos = stripos($sTemplate, '</'.self::TAG_BLOCK.'>', $iStartPos);
|
||||
$iEndTag = stripos($sTemplate, '>', $iStartPos);
|
||||
$aParams = array();
|
||||
$aParams = [];
|
||||
|
||||
if (($iStartPos === false) || ($iEndPos === false)) {
|
||||
return null;
|
||||
@@ -454,7 +449,7 @@ class DisplayBlock
|
||||
$sITopData = substr($sTemplate, 1 + $iEndTag, $iEndPos - $iEndTag - 1);
|
||||
$sITopTag = substr($sTemplate, $iStartPos + strlen('<'.self::TAG_BLOCK), $iEndTag - $iStartPos - strlen('<'.self::TAG_BLOCK));
|
||||
|
||||
$aMatches = array();
|
||||
$aMatches = [];
|
||||
$sBlockClass = "DisplayBlock";
|
||||
$bAsynchronous = false;
|
||||
$sBlockType = 'list';
|
||||
@@ -520,25 +515,28 @@ class DisplayBlock
|
||||
return new $sBlockClass($oFilter, $sBlockType, $bAsynchronous, $aParams);
|
||||
}
|
||||
|
||||
public function DisplayIntoContentBlock(UIContentBlock $oContentBlock, WebPage $oPage, $sId, $aExtraParams = array())
|
||||
public function DisplayIntoContentBlock(UIContentBlock $oContentBlock, WebPage $oPage, $sId, $aExtraParams = [])
|
||||
{
|
||||
$oContentBlock->AddSubBlock($this->GetDisplay($oPage, $sId, $aExtraParams));
|
||||
}
|
||||
|
||||
public function Display(WebPage $oPage, $sId, $aExtraParams = array())
|
||||
public function Display(WebPage $oPage, $sId, $aExtraParams = [])
|
||||
{
|
||||
$oPage->AddUiBlock($this->GetDisplay($oPage, $sId, $aExtraParams));
|
||||
}
|
||||
|
||||
public function GetDisplay(WebPage $oPage, $sId, $aExtraParams = array()): UIContentBlock
|
||||
public function GetDisplay(WebPage $oPage, $sId, $aExtraParams = []): UIContentBlock
|
||||
{
|
||||
$oHtml = new UIContentBlock($sId);
|
||||
|
||||
$oHtml->AddCSSClass("display_block");
|
||||
$aExtraParams = array_merge($aExtraParams, $this->m_aParams);
|
||||
$aExtraParams['currentId'] = $sId;
|
||||
$sExtraParams = addslashes(str_replace('"', "'",
|
||||
json_encode($aExtraParams))); // JSON encode, change the style of the quotes and escape them
|
||||
$sExtraParams = addslashes(str_replace(
|
||||
'"',
|
||||
"'",
|
||||
json_encode($aExtraParams)
|
||||
)); // JSON encode, change the style of the quotes and escape them
|
||||
|
||||
if (isset($aExtraParams['query_params'])) {
|
||||
$aQueryParams = $aExtraParams['query_params'];
|
||||
@@ -547,9 +545,9 @@ class DisplayBlock
|
||||
$sClass = $aExtraParams['this->class'];
|
||||
$iKey = $aExtraParams['this->id'];
|
||||
$oObj = MetaModel::GetObject($sClass, $iKey);
|
||||
$aQueryParams = array('this->object()' => $oObj);
|
||||
$aQueryParams = ['this->object()' => $oObj];
|
||||
} else {
|
||||
$aQueryParams = array();
|
||||
$aQueryParams = [];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -585,8 +583,7 @@ class DisplayBlock
|
||||
');
|
||||
}
|
||||
|
||||
if ($this->m_sStyle == static::ENUM_STYLE_LIST) // Search form need to extract result list extra data, the simplest way is to expose this configuration
|
||||
{
|
||||
if ($this->m_sStyle == static::ENUM_STYLE_LIST) { // Search form need to extract result list extra data, the simplest way is to expose this configuration
|
||||
$listJsonExtraParams = json_encode(json_encode($aExtraParams));
|
||||
$oPage->add_ready_script("
|
||||
$('#$sId').data('sExtraParams', ".$listJsonExtraParams.");
|
||||
@@ -606,7 +603,7 @@ class DisplayBlock
|
||||
* @throws \DictExceptionMissingString
|
||||
* @throws \MySQLException
|
||||
*/
|
||||
public function RenderContent(WebPage $oPage, $aExtraParams = array())
|
||||
public function RenderContent(WebPage $oPage, $aExtraParams = [])
|
||||
{
|
||||
if (!isset($aExtraParams['currentId'])) {
|
||||
$sId = utils::GetUniqueId(); // Works only if the page is not an Ajax one !
|
||||
@@ -638,7 +635,7 @@ class DisplayBlock
|
||||
$this->CheckParams($this->m_sStyle, $aExtraParams);
|
||||
// Add the extra params into the filter if they make sense for such a filter
|
||||
$bDoSearch = utils::ReadParam('dosearch', false);
|
||||
$aQueryParams = array();
|
||||
$aQueryParams = [];
|
||||
if (isset($aExtraParams['query_params'])) {
|
||||
$aQueryParams = $aExtraParams['query_params'];
|
||||
} else {
|
||||
@@ -646,7 +643,7 @@ class DisplayBlock
|
||||
$sClass = $aExtraParams['this->class'];
|
||||
$iKey = $aExtraParams['this->id'];
|
||||
$oObj = MetaModel::GetObject($sClass, $iKey);
|
||||
$aQueryParams = array('this->object()' => $oObj);
|
||||
$aQueryParams = ['this->object()' => $oObj];
|
||||
}
|
||||
}
|
||||
if ($this->m_oSet == null) {
|
||||
@@ -656,7 +653,7 @@ class DisplayBlock
|
||||
$oAppContext = new ApplicationContext();
|
||||
$sClass = $this->m_oFilter->GetClass();
|
||||
$aFilterCodes = MetaModel::GetFiltersList($sClass);
|
||||
$aCallSpec = array($sClass, 'MapContextParam');
|
||||
$aCallSpec = [$sClass, 'MapContextParam'];
|
||||
if (is_callable($aCallSpec)) {
|
||||
foreach ($oAppContext->GetNames() as $sContextParam) {
|
||||
$sParamCode = call_user_func($aCallSpec, $sContextParam); //Map context parameter to the value/filter code depending on the class
|
||||
@@ -691,11 +688,9 @@ class DisplayBlock
|
||||
}
|
||||
}
|
||||
|
||||
if (!is_null($condition))
|
||||
{
|
||||
if (!is_null($condition)) {
|
||||
$sOpCode = null; // default operator
|
||||
if (is_array($condition))
|
||||
{
|
||||
if (is_array($condition)) {
|
||||
// Multiple values, add them as AND X IN (v1, v2, v3...)
|
||||
$sOpCode = 'IN';
|
||||
}
|
||||
@@ -703,26 +698,22 @@ class DisplayBlock
|
||||
$this->AddCondition($sFilterCode, $condition, $sOpCode, $bParseSearchString);
|
||||
}
|
||||
}
|
||||
if ($bDoSearch)
|
||||
{
|
||||
if ($bDoSearch) {
|
||||
// Keep the table_id identifying this table if we're performing a search
|
||||
$sTableId = utils::ReadParam('_table_id_', null, false, utils::ENUM_SANITIZATION_FILTER_ELEMENT_IDENTIFIER);
|
||||
if ($sTableId != null)
|
||||
{
|
||||
if ($sTableId != null) {
|
||||
$aExtraParams['table_id'] = $sTableId;
|
||||
}
|
||||
}
|
||||
}
|
||||
$aOrderBy = array();
|
||||
if (isset($aExtraParams['order_by']))
|
||||
{
|
||||
$aOrderBy = [];
|
||||
if (isset($aExtraParams['order_by'])) {
|
||||
// Convert the string describing the order_by parameter into an array
|
||||
// The syntax is +attCode1,-attCode2
|
||||
// attCode1 => ascending, attCode2 => descending
|
||||
$aTemp = explode(',', $aExtraParams['order_by']);
|
||||
foreach($aTemp as $sTemp)
|
||||
{
|
||||
$aMatches = array();
|
||||
foreach ($aTemp as $sTemp) {
|
||||
$aMatches = [];
|
||||
if (preg_match('/^([+-])?(.+)$/', $sTemp, $aMatches)) {
|
||||
$bAscending = true;
|
||||
if ($aMatches[1] == '-') {
|
||||
@@ -733,12 +724,16 @@ class DisplayBlock
|
||||
}
|
||||
}
|
||||
|
||||
if (!$this->m_oFilter->IsAllDataAllowed() && ($aExtraParams['display_unauthorized_objects'] ?? false) === true) {
|
||||
$this->m_oFilter->AllowAllData();
|
||||
}
|
||||
|
||||
$aExtraParams['query_params'] = $this->m_oFilter->GetInternalParams();
|
||||
$this->m_oSet = new CMDBObjectSet($this->m_oFilter, $aOrderBy, $aQueryParams);
|
||||
}
|
||||
$this->m_oSet->SetShowObsoleteData($this->m_bShowObsoleteData);
|
||||
|
||||
switch($this->m_sStyle) {
|
||||
switch ($this->m_sStyle) {
|
||||
case static::ENUM_STYLE_LIST_SEARCH:
|
||||
case static::ENUM_STYLE_LIST:
|
||||
break;
|
||||
@@ -768,7 +763,7 @@ class DisplayBlock
|
||||
case static::ENUM_STYLE_LIST:
|
||||
case static::ENUM_STYLE_LIST_IN_OBJECT:
|
||||
$oBlock = $this->RenderList($aExtraParams, $oPage);
|
||||
break;
|
||||
break;
|
||||
|
||||
case 'links':
|
||||
$oBlock = $this->RenderLinks($oPage, $aExtraParams);
|
||||
@@ -793,53 +788,45 @@ class DisplayBlock
|
||||
case static::ENUM_STYLE_CHART:
|
||||
$oBlock = $this->RenderChart($sId, $aQueryParams, $aExtraParams);
|
||||
break;
|
||||
|
||||
|
||||
case static::ENUM_STYLE_CHART_AJAX:
|
||||
$oBlock = $this->RenderChartAjax($aExtraParams);
|
||||
break;
|
||||
|
||||
|
||||
default:
|
||||
// Unsupported style, do nothing.
|
||||
$sHtml .= Dict::format('UI:Error:UnsupportedStyleOfBlock', $this->m_sStyle);
|
||||
// Unsupported style, do nothing.
|
||||
$sHtml .= Dict::format('UI:Error:UnsupportedStyleOfBlock', $this->m_sStyle);
|
||||
}
|
||||
|
||||
|
||||
$bAutoReload = false;
|
||||
if (isset($aExtraParams['auto_reload']))
|
||||
{
|
||||
if ($aExtraParams['auto_reload'] === true)
|
||||
{
|
||||
if (isset($aExtraParams['auto_reload'])) {
|
||||
if ($aExtraParams['auto_reload'] === true) {
|
||||
// Note: does not work in the switch (case true) because a positive number evaluates to true!!!
|
||||
$aExtraParams['auto_reload'] = 'standard';
|
||||
}
|
||||
switch($aExtraParams['auto_reload'])
|
||||
{
|
||||
switch ($aExtraParams['auto_reload']) {
|
||||
case 'fast':
|
||||
$bAutoReload = true;
|
||||
$iReloadInterval = MetaModel::GetConfig()->GetFastReloadInterval()*1000;
|
||||
$iReloadInterval = MetaModel::GetConfig()->GetFastReloadInterval() * 1000;
|
||||
break;
|
||||
|
||||
case 'standard':
|
||||
case 'true':
|
||||
$bAutoReload = true;
|
||||
$iReloadInterval = MetaModel::GetConfig()->GetStandardReloadInterval()*1000;
|
||||
$iReloadInterval = MetaModel::GetConfig()->GetStandardReloadInterval() * 1000;
|
||||
break;
|
||||
|
||||
default:
|
||||
if (is_numeric($aExtraParams['auto_reload']) && ($aExtraParams['auto_reload'] > 0))
|
||||
{
|
||||
if (is_numeric($aExtraParams['auto_reload']) && ($aExtraParams['auto_reload'] > 0)) {
|
||||
$bAutoReload = true;
|
||||
$iReloadInterval = max(MetaModel::GetConfig()->Get('min_reload_interval'), $aExtraParams['auto_reload'])*1000;
|
||||
}
|
||||
else
|
||||
{
|
||||
$iReloadInterval = max(MetaModel::GetConfig()->Get('min_reload_interval'), $aExtraParams['auto_reload']) * 1000;
|
||||
} else {
|
||||
// incorrect config, ignore it
|
||||
$bAutoReload = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (($bAutoReload) && ($this->m_sStyle != static::ENUM_STYLE_SEARCH)) // Search form do NOT auto-reload
|
||||
{
|
||||
if (($bAutoReload) && ($this->m_sStyle != static::ENUM_STYLE_SEARCH)) { // Search form do NOT auto-reload
|
||||
// Used either for asynchronous or auto_reload
|
||||
// does a json_encode twice to get a string usable as function parameter
|
||||
$sFilterBefore = $this->m_oFilter->serialize();
|
||||
@@ -886,8 +873,7 @@ JS
|
||||
{
|
||||
// Workaround to an issue revealed whenever a condition on org_id is applied twice (with a hierarchy of organizations)
|
||||
// Moreover, it keeps the query as simple as possible
|
||||
if (isset($this->m_aConditions[$sFilterCode]) && $condition == $this->m_aConditions[$sFilterCode])
|
||||
{
|
||||
if (isset($this->m_aConditions[$sFilterCode]) && $condition == $this->m_aConditions[$sFilterCode]) {
|
||||
// Skip
|
||||
return;
|
||||
}
|
||||
@@ -895,59 +881,48 @@ JS
|
||||
|
||||
$sClass = $this->m_oFilter->GetClass();
|
||||
$bConditionAdded = false;
|
||||
|
||||
|
||||
// If the condition is an external key with a class having a hierarchy, use a "below" criteria
|
||||
if (MetaModel::IsValidAttCode($sClass, $sFilterCode))
|
||||
{
|
||||
if (MetaModel::IsValidAttCode($sClass, $sFilterCode)) {
|
||||
$oAttDef = MetaModel::GetAttributeDef($sClass, $sFilterCode);
|
||||
|
||||
if ($oAttDef->IsExternalKey())
|
||||
{
|
||||
if ($oAttDef->IsExternalKey()) {
|
||||
$sHierarchicalKeyCode = MetaModel::IsHierarchicalClass($oAttDef->GetTargetClass());
|
||||
|
||||
if ($sHierarchicalKeyCode !== false)
|
||||
{
|
||||
|
||||
if ($sHierarchicalKeyCode !== false) {
|
||||
$oFilter = new DBObjectSearch($oAttDef->GetTargetClass());
|
||||
if (($sOpCode == 'IN') && is_array($condition))
|
||||
{
|
||||
$oFilter->AddConditionExpression(self::GetConditionIN($oFilter, 'id', $condition));
|
||||
}
|
||||
else
|
||||
{
|
||||
if (($sOpCode == 'IN') && is_array($condition)) {
|
||||
$oFilter->AddConditionExpression(self::GetConditionIN($oFilter, 'id', $condition));
|
||||
} else {
|
||||
$oFilter->AddCondition('id', $condition);
|
||||
}
|
||||
$oHKFilter = new DBObjectSearch($oAttDef->GetTargetClass());
|
||||
$oHKFilter->AddCondition_PointingTo($oFilter, $sHierarchicalKeyCode, TREE_OPERATOR_BELOW); // Use the 'below' operator by default
|
||||
$this->m_oFilter->AddCondition_PointingTo($oHKFilter, $sFilterCode);
|
||||
$bConditionAdded = true;
|
||||
}
|
||||
else if (($sOpCode == 'IN') && is_array($condition))
|
||||
{
|
||||
} elseif (($sOpCode == 'IN') && is_array($condition)) {
|
||||
$this->m_oFilter->AddConditionExpression(self::GetConditionIN($this->m_oFilter, $sFilterCode, $condition));
|
||||
$bConditionAdded = true;
|
||||
}
|
||||
}
|
||||
else if (($sOpCode == 'IN') && is_array($condition))
|
||||
{
|
||||
} elseif (($sOpCode == 'IN') && is_array($condition)) {
|
||||
$this->m_oFilter->AddConditionExpression(self::GetConditionIN($this->m_oFilter, $sFilterCode, $condition));
|
||||
$bConditionAdded = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// In all other cases, just add the condition directly
|
||||
if (!$bConditionAdded)
|
||||
{
|
||||
if (!$bConditionAdded) {
|
||||
$this->m_oFilter->AddCondition($sFilterCode, $condition, null); // Use the default 'loose' operator
|
||||
}
|
||||
}
|
||||
|
||||
static protected function GetConditionIN($oFilter, $sFilterCode, $condition)
|
||||
|
||||
protected static function GetConditionIN($oFilter, $sFilterCode, $condition)
|
||||
{
|
||||
$oField = new FieldExpression($sFilterCode, $oFilter->GetClassAlias());
|
||||
$oField = new FieldExpression($sFilterCode, $oFilter->GetClassAlias());
|
||||
$sListExpr = '('.implode(', ', CMDBSource::Quote($condition)).')';
|
||||
$sOQLCondition = $oField->RenderExpression()." IN $sListExpr";
|
||||
$oNewCondition = Expression::FromOQL($sOQLCondition);
|
||||
return $oNewCondition;
|
||||
return $oNewCondition;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -974,13 +949,10 @@ JS
|
||||
protected function MakeGroupByQuery(&$aExtraParams, &$oGroupByExp, &$sGroupByLabel, &$aGroupBy, &$sAggregationFunction, &$sFctVar, &$sAggregationAttr, &$sSql)
|
||||
{
|
||||
$sAlias = $this->m_oFilter->GetClassAlias();
|
||||
if (isset($aExtraParams['group_by_label']))
|
||||
{
|
||||
if (isset($aExtraParams['group_by_label'])) {
|
||||
$oGroupByExp = Expression::FromOQL($aExtraParams['group_by']);
|
||||
$sGroupByLabel = $aExtraParams['group_by_label'];
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
// Backward compatibility: group_by is simply a field id
|
||||
$oGroupByExp = new FieldExpression($aExtraParams['group_by'], $sAlias);
|
||||
$sGroupByLabel = MetaModel::GetLabel($this->m_oFilter->GetClass(), $aExtraParams['group_by']);
|
||||
@@ -988,61 +960,52 @@ JS
|
||||
|
||||
// Security filtering
|
||||
$aFields = $oGroupByExp->ListRequiredFields();
|
||||
foreach($aFields as $sFieldAlias)
|
||||
{
|
||||
$aMatches = array();
|
||||
if (preg_match('/^([^.]+)\\.([^.]+)$/', $sFieldAlias, $aMatches))
|
||||
{
|
||||
foreach ($aFields as $sFieldAlias) {
|
||||
$aMatches = [];
|
||||
if (preg_match('/^([^.]+)\\.([^.]+)$/', $sFieldAlias, $aMatches)) {
|
||||
$sFieldClass = $this->m_oFilter->GetClassName($aMatches[1]);
|
||||
$oAttDef = MetaModel::GetAttributeDef($sFieldClass, $aMatches[2]);
|
||||
if ($oAttDef instanceof AttributeOneWayPassword)
|
||||
{
|
||||
if ($oAttDef instanceof AttributeOneWayPassword) {
|
||||
throw new Exception('Grouping on password fields is not supported.');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$aGroupBy = array();
|
||||
$aGroupBy = [];
|
||||
$aGroupBy['grouped_by_1'] = $oGroupByExp;
|
||||
$aQueryParams = array();
|
||||
if (isset($aExtraParams['query_params']))
|
||||
{
|
||||
$aQueryParams = [];
|
||||
if (isset($aExtraParams['query_params'])) {
|
||||
$aQueryParams = $aExtraParams['query_params'];
|
||||
}
|
||||
$aFunctions = array();
|
||||
$aFunctions = [];
|
||||
$sAggregationFunction = 'count';
|
||||
$sFctVar = '_itop_count_';
|
||||
$sAggregationAttr = '';
|
||||
if (isset($aExtraParams['aggregation_function']) && !empty($aExtraParams['aggregation_attribute']))
|
||||
{
|
||||
if (isset($aExtraParams['aggregation_function']) && !empty($aExtraParams['aggregation_attribute'])) {
|
||||
$sAggregationFunction = $aExtraParams['aggregation_function'];
|
||||
$sAggregationAttr = $aExtraParams['aggregation_attribute'];
|
||||
$oAttrExpr = Expression::FromOQL('`'.$sAlias.'`.`'.$sAggregationAttr.'`');
|
||||
$oFctExpr = new FunctionExpression(strtoupper($sAggregationFunction), array($oAttrExpr));
|
||||
$oFctExpr = new FunctionExpression(strtoupper($sAggregationFunction), [$oAttrExpr]);
|
||||
$sFctVar = '_itop_'.$sAggregationFunction.'_';
|
||||
$aFunctions = array($sFctVar => $oFctExpr);
|
||||
$aFunctions = [$sFctVar => $oFctExpr];
|
||||
}
|
||||
|
||||
if (!empty($sAggregationAttr))
|
||||
{
|
||||
if (!empty($sAggregationAttr)) {
|
||||
$sClass = $this->m_oFilter->GetClass();
|
||||
$sAggregationAttr = MetaModel::GetLabel($sClass, $sAggregationAttr);
|
||||
}
|
||||
$iLimit = 0;
|
||||
if (isset($aExtraParams['limit']))
|
||||
{
|
||||
if (isset($aExtraParams['limit'])) {
|
||||
$iLimit = intval($aExtraParams['limit']);
|
||||
}
|
||||
$aOrderBy = array();
|
||||
if (isset($aExtraParams['order_direction']) && isset($aExtraParams['order_by']))
|
||||
{
|
||||
switch ($aExtraParams['order_by'])
|
||||
{
|
||||
$aOrderBy = [];
|
||||
if (isset($aExtraParams['order_direction']) && isset($aExtraParams['order_by'])) {
|
||||
switch ($aExtraParams['order_by']) {
|
||||
case 'attribute':
|
||||
$aOrderBy = array('grouped_by_1' => ($aExtraParams['order_direction'] === 'asc'));
|
||||
$aOrderBy = ['grouped_by_1' => ($aExtraParams['order_direction'] === 'asc')];
|
||||
break;
|
||||
case 'function':
|
||||
$aOrderBy = array($sFctVar => ($aExtraParams['order_direction'] === 'asc'));
|
||||
$aOrderBy = [$sFctVar => ($aExtraParams['order_direction'] === 'asc')];
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -1078,31 +1041,31 @@ JS
|
||||
$this->AddCondition($sFilterCode, $sContextParamValue);
|
||||
}
|
||||
}
|
||||
$aQueryParams = array();
|
||||
$aQueryParams = [];
|
||||
if (isset($aExtraParams['query_params'])) {
|
||||
$aQueryParams = $aExtraParams['query_params'];
|
||||
}
|
||||
$this->m_oSet = new CMDBObjectSet($this->m_oFilter, array(), $aQueryParams);
|
||||
$this->m_oSet = new CMDBObjectSet($this->m_oFilter, [], $aQueryParams);
|
||||
$this->m_oSet->SetShowObsoleteData($this->m_bShowObsoleteData);
|
||||
}
|
||||
|
||||
// Summary details
|
||||
$aCounts = array();
|
||||
$aStateLabels = array();
|
||||
$aCounts = [];
|
||||
$aStateLabels = [];
|
||||
if (!empty($sStateAttrCode) && !empty($sStatesList)) {
|
||||
$aStates = explode(',', $sStatesList);
|
||||
|
||||
// Generate one count + group by query [#1330]
|
||||
$sClassAlias = $this->m_oFilter->GetClassAlias();
|
||||
$oGroupByExpr = Expression::FromOQL($sClassAlias.'.'.$sStateAttrCode);
|
||||
$aGroupBy = array('group1' => $oGroupByExpr);
|
||||
$aGroupBy = ['group1' => $oGroupByExpr];
|
||||
$oGroupBySearch = $this->m_oFilter->DeepClone();
|
||||
if (isset($this->m_bShowObsoleteData)) {
|
||||
$oGroupBySearch->SetShowObsoleteData($this->m_bShowObsoleteData);
|
||||
}
|
||||
$sCountGroupByQuery = $oGroupBySearch->MakeGroupByQuery($aQueryParams, $aGroupBy, false);
|
||||
$aCountGroupByResults = CMDBSource::QueryToArray($sCountGroupByQuery);
|
||||
$aCountsQueryResults = array();
|
||||
$aCountsQueryResults = [];
|
||||
foreach ($aCountGroupByResults as $aCountGroupBySingleResult) {
|
||||
$aCountsQueryResults[$aCountGroupBySingleResult[0]] = $aCountGroupBySingleResult[1];
|
||||
}
|
||||
@@ -1116,7 +1079,8 @@ JS
|
||||
: 0;
|
||||
|
||||
if ($aCounts[$sStateValue] == 0) {
|
||||
$aCounts[$sStateValue] = ['link' => '-', 'label' => $aCounts[$sStateValue]];;
|
||||
$aCounts[$sStateValue] = ['link' => '-', 'label' => $aCounts[$sStateValue]];
|
||||
;
|
||||
} else {
|
||||
$oSingleGroupByValueFilter = $this->m_oFilter->DeepClone();
|
||||
$oSingleGroupByValueFilter->AddCondition($sStateAttrCode, $sStateValue, '=');
|
||||
@@ -1166,7 +1130,7 @@ JS
|
||||
$oBlock->AddSubBlock($oPill);
|
||||
}
|
||||
$aExtraParams['query_params'] = $this->m_oFilter->GetInternalParams();
|
||||
if(isset($aExtraParams['query_params']['this->object()'])){
|
||||
if (isset($aExtraParams['query_params']['this->object()'])) {
|
||||
$aExtraParams['query_params']['this->class'] = get_class($aExtraParams['query_params']['this->object()']);
|
||||
$aExtraParams['query_params']['this->id'] = $aExtraParams['query_params']['this->object()']->GetKey();
|
||||
unset($aExtraParams['query_params']['this->object()']);
|
||||
@@ -1180,7 +1144,8 @@ JS
|
||||
$('#".$oBlock->GetId()."').html(data);
|
||||
$('#".$oBlock->GetId()."').unblock();
|
||||
});
|
||||
$('#".$oBlock->GetId()."').unblock();");
|
||||
$('#".$oBlock->GetId()."').unblock();"
|
||||
);
|
||||
|
||||
return $oBlock;
|
||||
}
|
||||
@@ -1190,7 +1155,7 @@ JS
|
||||
*
|
||||
* @return string[]
|
||||
*/
|
||||
protected function GetAllowedActionsParams(array $aExtraParams)
|
||||
protected function GetAllowedActionsParams(array $aExtraParams)
|
||||
{
|
||||
return [
|
||||
'context_filter', /** int if != 0 filter with user context */
|
||||
@@ -1222,11 +1187,11 @@ JS
|
||||
$this->AddCondition($sFilterCode, $sContextParamValue);
|
||||
}
|
||||
}
|
||||
$aQueryParams = array();
|
||||
$aQueryParams = [];
|
||||
if (isset($aExtraParams['query_params'])) {
|
||||
$aQueryParams = $aExtraParams['query_params'];
|
||||
}
|
||||
$this->m_oSet = new CMDBObjectSet($this->m_oFilter, array(), $aQueryParams);
|
||||
$this->m_oSet = new CMDBObjectSet($this->m_oFilter, [], $aQueryParams);
|
||||
$this->m_oSet->SetShowObsoleteData($this->m_bShowObsoleteData);
|
||||
}
|
||||
$iCount = $this->m_oSet->Count();
|
||||
@@ -1243,8 +1208,15 @@ JS
|
||||
if (UserRights::IsActionAllowed($sClass, UR_ACTION_MODIFY)) {
|
||||
$sCreateActionUrl = utils::GetAbsoluteUrlAppRoot().'pages/UI.php?operation=new&class='.$sClass.$oAppContext->GetForLink(true);
|
||||
$sCreateActionLabel = Dict::Format('UI:Button:Create');
|
||||
$oBlock = DashletFactory::MakeForDashletBadge($sClassIconUrl, $sHyperlink, $iCount, $sClassLabel, $sCreateActionUrl,
|
||||
$sCreateActionLabel, $aRefreshParams);
|
||||
$oBlock = DashletFactory::MakeForDashletBadge(
|
||||
$sClassIconUrl,
|
||||
$sHyperlink,
|
||||
$iCount,
|
||||
$sClassLabel,
|
||||
$sCreateActionUrl,
|
||||
$sCreateActionLabel,
|
||||
$aRefreshParams
|
||||
);
|
||||
} else {
|
||||
$oBlock = DashletFactory::MakeForDashletBadge($sClassIconUrl, $sHyperlink, $iCount, $sClassLabel, null, null, $aRefreshParams);
|
||||
}
|
||||
@@ -1274,9 +1246,9 @@ JS
|
||||
|
||||
$aRes = CMDBSource::QueryToArray($sSql);
|
||||
|
||||
$aGroupBy = array();
|
||||
$aLabels = array();
|
||||
$aValues = array();
|
||||
$aGroupBy = [];
|
||||
$aLabels = [];
|
||||
$aValues = [];
|
||||
$iTotalCount = 0;
|
||||
foreach ($aRes as $iRow => $aRow) {
|
||||
$sValue = $aRow['grouped_by_1'];
|
||||
@@ -1287,7 +1259,7 @@ JS
|
||||
$iTotalCount += $aRow['_itop_count_'];
|
||||
}
|
||||
|
||||
$aData = array();
|
||||
$aData = [];
|
||||
$oAppContext = new ApplicationContext();
|
||||
$sParams = $oAppContext->GetForLink(true);
|
||||
foreach ($aGroupBy as $iRow => $iCount) {
|
||||
@@ -1298,22 +1270,22 @@ JS
|
||||
if (isset($aExtraParams['query_params'])) {
|
||||
$aQueryParams = $aExtraParams['query_params'];
|
||||
} else {
|
||||
$aQueryParams = array();
|
||||
$aQueryParams = [];
|
||||
}
|
||||
$sFilter = rawurlencode($oSubsetSearch->serialize(false, $aQueryParams));
|
||||
|
||||
$aData[] = array(
|
||||
$aData[] = [
|
||||
'group' => $aLabels[$iRow],
|
||||
'value' => "<a href=\"".utils::GetAbsoluteUrlAppRoot()."pages/UI.php?operation=search&dosearch=1$sParams&filter=$sFilter\">$iCount</a>"
|
||||
); // TO DO: add the context information
|
||||
'value' => "<a href=\"".utils::GetAbsoluteUrlAppRoot()."pages/UI.php?operation=search&dosearch=1$sParams&filter=$sFilter\">$iCount</a>",
|
||||
]; // TO DO: add the context information
|
||||
}
|
||||
$aAttribs = array(
|
||||
'group' => array('label' => $sGroupByLabel, 'description' => ''),
|
||||
'value' => array(
|
||||
$aAttribs = [
|
||||
'group' => ['label' => $sGroupByLabel, 'description' => ''],
|
||||
'value' => [
|
||||
'label' => Dict::S('UI:GroupBy:'.$sAggregationFunction),
|
||||
'description' => Dict::Format('UI:GroupBy:'.$sAggregationFunction.'+', $sAggregationAttr),
|
||||
),
|
||||
);
|
||||
],
|
||||
];
|
||||
$sFormat = isset($aExtraParams['format']) ? $aExtraParams['format'] : 'UI:Pagination:HeaderNoSelection';
|
||||
|
||||
$aExtraParams['query_params'] = $this->m_oFilter->GetInternalParams();
|
||||
@@ -1324,7 +1296,7 @@ JS
|
||||
$oBlock = PanelUIBlockFactory::MakeForClass($aExtraParams["panel_class"], $aExtraParams["panel_title"]);
|
||||
$oBlock->AddSubTitleBlock(new Html($sTitle));
|
||||
$oBlock->AddCSSClass('ibo-datatable-panel');
|
||||
if(isset($aExtraParams["panel_icon"]) && strlen($aExtraParams["panel_icon"]) > 0){
|
||||
if (isset($aExtraParams["panel_icon"]) && strlen($aExtraParams["panel_icon"]) > 0) {
|
||||
$oBlock->SetIcon($aExtraParams["panel_icon"]);
|
||||
}
|
||||
$oDataTable = DataTableUIBlockFactory::MakeForStaticData("", $aAttribs, $aData, null, $aExtraParams, $this->m_oFilter->ToOQL(), $aOption);
|
||||
@@ -1343,7 +1315,7 @@ JS
|
||||
}
|
||||
if (isset($aExtraParams["surround_with_panel"]) && $aExtraParams["surround_with_panel"]) {
|
||||
$oBlock = PanelUIBlockFactory::MakeForClass($aExtraParams["panel_class"], $aExtraParams["panel_title"]);
|
||||
if(isset($aExtraParams["panel_icon"]) && strlen($aExtraParams["panel_icon"]) > 0){
|
||||
if (isset($aExtraParams["panel_icon"]) && strlen($aExtraParams["panel_icon"]) > 0) {
|
||||
$oBlock->SetIcon($aExtraParams["panel_icon"]);
|
||||
}
|
||||
$oBlock->AddSubBlock(new Html('<p>'.Dict::Format($sFormat, $iCount).'</p>'));
|
||||
@@ -1353,7 +1325,7 @@ JS
|
||||
}
|
||||
|
||||
return $oBlock;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param WebPage $oPage
|
||||
@@ -1411,10 +1383,12 @@ JS
|
||||
$oBlock->aExtraParams = $aExtraParams;
|
||||
$oBlock->sFilter = $this->m_oFilter->ToOQL();
|
||||
|
||||
|
||||
// Check the classes that can be read (i.e authorized) by this user...
|
||||
foreach ($aClasses as $sAlias => $sClassName) {
|
||||
if (UserRights::IsActionAllowed($sClassName, UR_ACTION_READ, $this->m_oSet) != UR_ALLOWED_NO) {
|
||||
if (
|
||||
(UserRights::IsActionAllowed($sClassName, UR_ACTION_READ, $this->m_oSet) !== UR_ALLOWED_NO)
|
||||
|| ($aExtraParams['display_unauthorized_objects'] ?? false) === true
|
||||
) {
|
||||
$aAuthorizedClasses[$sAlias] = $sClassName;
|
||||
}
|
||||
}
|
||||
@@ -1433,7 +1407,7 @@ JS
|
||||
$sSearchFilter = $this->m_oSet->GetFilter()->serialize();
|
||||
// Limit the size of the URL (N°1585 - request uri too long)
|
||||
if (strlen($sSearchFilter) < SERVER_MAX_URL_LENGTH) {
|
||||
$oBlock->sEventAttachedData = json_encode(array(
|
||||
$oBlock->sEventAttachedData = json_encode([
|
||||
'filter' => $sSearchFilter,
|
||||
'breadcrumb_id' => "ui-search-".$this->m_oSet->GetClass(),
|
||||
'breadcrumb_label' => MetaModel::GetName($this->m_oSet->GetClass()),
|
||||
@@ -1441,7 +1415,7 @@ JS
|
||||
'breadcrumb_instance_id' => MetaModel::GetConfig()->GetItopInstanceid(),
|
||||
'breadcrumb_icon' => 'fas fa-search',
|
||||
'breadcrumb_icon_type' => iTopWebPage::ENUM_BREADCRUMB_ENTRY_ICON_TYPE_CSS_CLASSES,
|
||||
));
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1474,25 +1448,25 @@ JS
|
||||
$oContentBlock = new UIContentBlock();
|
||||
$oHtml = new Html();
|
||||
$oContentBlock->AddSubBlock($oHtml);
|
||||
$aDisplayAliases = isset($aExtraParams['display_aliases']) ? explode(',', $aExtraParams['display_aliases']) : array();
|
||||
$aDisplayAliases = isset($aExtraParams['display_aliases']) ? explode(',', $aExtraParams['display_aliases']) : [];
|
||||
if (!isset($aExtraParams['group_by'])) {
|
||||
$oHtml->AddHtml('<p>'.Dict::S('UI:Error:MandatoryTemplateParameter_group_by').'</p>');
|
||||
} else {
|
||||
$aGroupByFields = array();
|
||||
$aGroupByFields = [];
|
||||
$aGroupBy = explode(',', $aExtraParams['group_by']);
|
||||
foreach ($aGroupBy as $sGroupBy) {
|
||||
$aMatches = array();
|
||||
$aMatches = [];
|
||||
if (preg_match('/^(.+)\.(.+)$/', $sGroupBy, $aMatches) > 0) {
|
||||
$aGroupByFields[] = array('alias' => $aMatches[1], 'att_code' => $aMatches[2]);
|
||||
$aGroupByFields[] = ['alias' => $aMatches[1], 'att_code' => $aMatches[2]];
|
||||
}
|
||||
}
|
||||
if (count($aGroupByFields) == 0) {
|
||||
$oHtml->AddHtml('<p>'.Dict::Format('UI:Error:InvalidGroupByFields', $aExtraParams['group_by']).'</p>');
|
||||
} else {
|
||||
$aResults = array();
|
||||
$aCriteria = array();
|
||||
$aResults = [];
|
||||
$aCriteria = [];
|
||||
while ($aObjects = $this->m_oSet->FetchAssoc()) {
|
||||
$aKeys = array();
|
||||
$aKeys = [];
|
||||
foreach ($aGroupByFields as $aField) {
|
||||
$sAlias = $aField['alias'];
|
||||
if (is_null($aObjects[$sAlias])) {
|
||||
@@ -1509,7 +1483,7 @@ JS
|
||||
$oHtml->AddHtml("<table>\n");
|
||||
// Construct a new (parametric) query that will return the content of this block
|
||||
$oBlockFilter = $this->m_oFilter->DeepClone();
|
||||
$aExpressions = array();
|
||||
$aExpressions = [];
|
||||
$index = 0;
|
||||
foreach ($aGroupByFields as $aField) {
|
||||
$aExpressions[] = '`'.$aField['alias'].'`.`'.$aField['att_code'].'` = :param'.$index++;
|
||||
@@ -1521,7 +1495,7 @@ JS
|
||||
foreach ($aResults as $sCategory => $aObjects) {
|
||||
$oHtml->AddHtml("<tr><td><h1>$sCategory</h1></td></tr>\n");
|
||||
if (count($aDisplayAliases) == 1) {
|
||||
$aSimpleArray = array();
|
||||
$aSimpleArray = [];
|
||||
foreach ($aObjects as $aRow) {
|
||||
$oObj = $aRow[$aDisplayAliases[0]];
|
||||
if (!is_null($oObj)) {
|
||||
@@ -1537,12 +1511,12 @@ JS
|
||||
$oHtml->AddHtml("</td></tr>\n");
|
||||
} else {
|
||||
$index = 0;
|
||||
$aArgs = array();
|
||||
$aArgs = [];
|
||||
foreach ($aGroupByFields as $aField) {
|
||||
$aArgs['param'.$index] = $aCriteria[$sCategory][$aField['alias'].'.'.$aField['att_code']];
|
||||
$index++;
|
||||
}
|
||||
$oSet = new CMDBObjectSet($oBlockFilter, array(), $aArgs);
|
||||
$oSet = new CMDBObjectSet($oBlockFilter, [], $aArgs);
|
||||
if (empty($aExtraParams['currentId'])) {
|
||||
$iListId = utils::GetUniqueId(); // Works only if not in an Ajax page !!
|
||||
} else {
|
||||
@@ -1603,8 +1577,10 @@ JS
|
||||
$sDefaults .= '&'.urlencode($sName).'='.urlencode($sValue);
|
||||
}
|
||||
}
|
||||
$oBlock->AddHtml("<p><a href=\"".utils::GetAbsoluteUrlAppRoot()."pages/UI.php?operation=modify_links&class=$sClass&sParams&link_attr=".$aExtraParams['link_attr']."&id=".$aExtraParams['object_id']."&target_class=$sTargetClass&addObjects=true$sDefaults\">".Dict::Format('UI:ClickToCreateNew',
|
||||
Metamodel::GetName($sClass))."</a></p>\n");
|
||||
$oBlock->AddHtml("<p><a href=\"".utils::GetAbsoluteUrlAppRoot()."pages/UI.php?operation=modify_links&class=$sClass&sParams&link_attr=".$aExtraParams['link_attr']."&id=".$aExtraParams['object_id']."&target_class=$sTargetClass&addObjects=true$sDefaults\">".Dict::Format(
|
||||
'UI:ClickToCreateNew',
|
||||
Metamodel::GetName($sClass)
|
||||
)."</a></p>\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1653,7 +1629,7 @@ JS
|
||||
|
||||
if (isset($aExtraParams["surround_with_panel"]) && $aExtraParams["surround_with_panel"]) {
|
||||
$oPanel = PanelUIBlockFactory::MakeForClass($aExtraParams["panel_class"], $aExtraParams["panel_title"]);
|
||||
if(isset($aExtraParams["panel_icon"]) && strlen($aExtraParams["panel_icon"]) > 0){
|
||||
if (isset($aExtraParams["panel_icon"]) && strlen($aExtraParams["panel_icon"]) > 0) {
|
||||
$oPanel->SetIcon($aExtraParams["panel_icon"]);
|
||||
}
|
||||
$oPanel->AddSubBlock($oBlock);
|
||||
@@ -1677,7 +1653,7 @@ JS
|
||||
{
|
||||
$sChartType = isset($aExtraParams['chart_type']) ? $aExtraParams['chart_type'] : 'pie';
|
||||
$sId = utils::ReadParam('id', '');
|
||||
$aValues = array();
|
||||
$aValues = [];
|
||||
$oBlock = null;
|
||||
$sJSURLs = '';
|
||||
|
||||
@@ -1688,21 +1664,18 @@ JS
|
||||
$this->MakeGroupByQuery($aExtraParams, $oGroupByExp, $sGroupByLabel, $aGroupBy, $sAggregationFunction, $sFctVar, $sAggregationAttr, $sSql);
|
||||
$aRes = CMDBSource::QueryToArray($sSql);
|
||||
|
||||
|
||||
|
||||
$iTotalCount = 0;
|
||||
$aURLs = array();
|
||||
$aURLs = [];
|
||||
|
||||
foreach ($aRes as $iRow => $aRow) {
|
||||
$sValue = $aRow['grouped_by_1'];
|
||||
$sHtmlValue = $oGroupByExp->MakeValueLabel($this->m_oFilter, $sValue, $sValue);
|
||||
$iTotalCount += $aRow['_itop_count_'];
|
||||
$aValues[] = array(
|
||||
$aValues[] = [
|
||||
'label' => html_entity_decode(strip_tags($sHtmlValue), ENT_QUOTES, 'UTF-8'),
|
||||
'label_html' => $sHtmlValue,
|
||||
'value' => (float)$aRow[$sFctVar],
|
||||
);
|
||||
|
||||
];
|
||||
|
||||
// Build the search for this subset
|
||||
$oSubsetSearch = $this->m_oFilter->DeepClone();
|
||||
@@ -1741,7 +1714,7 @@ JS
|
||||
$aColumns = [];
|
||||
$aNames = [];
|
||||
foreach ($aValues as $idx => $aValue) {
|
||||
$aColumns[] = array('series_'.$idx, (float)$aValue['value']);
|
||||
$aColumns[] = ['series_'.$idx, (float)$aValue['value']];
|
||||
$aNames['series_'.$idx] = $aValue['label'];
|
||||
}
|
||||
|
||||
@@ -1763,7 +1736,7 @@ JS
|
||||
}
|
||||
if (isset($aExtraParams["surround_with_panel"]) && $aExtraParams["surround_with_panel"]) {
|
||||
$oPanel = PanelUIBlockFactory::MakeForClass($aExtraParams["panel_class"], $aExtraParams["panel_title"]);
|
||||
if(isset($aExtraParams["panel_icon"]) && strlen($aExtraParams["panel_icon"]) > 0){
|
||||
if (isset($aExtraParams["panel_icon"]) && strlen($aExtraParams["panel_icon"]) > 0) {
|
||||
$oPanel->SetIcon($aExtraParams["panel_icon"]);
|
||||
}
|
||||
$oPanel->AddSubBlock($oBlock);
|
||||
@@ -1790,12 +1763,12 @@ JS
|
||||
$oBlock->sDownloadLink = utils::GetAbsoluteUrlAppRoot().'webservices/export.php?expression='.urlencode($this->m_oFilter->ToOQL(true)).'&format=csv&filename='.urlencode($oBlock->sCsvFile);
|
||||
$oBlock->sLinkToToggle = utils::GetAbsoluteUrlAppRoot().'pages/UI.php?operation=search'.$oAppContext->GetForLink(true).'&filter='.rawurlencode($this->m_oFilter->serialize()).'&format=csv';
|
||||
// Pass the parameters via POST, since expression may be very long
|
||||
$aParamsToPost = array(
|
||||
$aParamsToPost = [
|
||||
'expression' => $this->m_oFilter->ToOQL(true),
|
||||
'format' => 'csv',
|
||||
'filename' => $oBlock->sCsvFile,
|
||||
'charset' => 'UTF-8',
|
||||
);
|
||||
];
|
||||
if ($oBlock->bAdvancedMode) {
|
||||
$oBlock->sDownloadLink .= '&fields_advanced=1';
|
||||
$aParamsToPost['fields_advanced'] = 1;
|
||||
@@ -1854,8 +1827,7 @@ class MenuBlock extends DisplayBlock
|
||||
$oRouter = Router::GetInstance();
|
||||
$oRenderBlock = new UIContentBlock();
|
||||
|
||||
if ($this->m_sStyle == 'popup') // popup is a synonym of 'list' for backward compatibility
|
||||
{
|
||||
if ($this->m_sStyle == 'popup') { // popup is a synonym of 'list' for backward compatibility
|
||||
$this->m_sStyle = static::ENUM_STYLE_LIST;
|
||||
}
|
||||
|
||||
@@ -1890,7 +1862,6 @@ class MenuBlock extends DisplayBlock
|
||||
$oAppContext = new ApplicationContext();
|
||||
$sContext = $oAppContext->GetForLink(true);
|
||||
|
||||
|
||||
$sFilter = $this->GetFilter()->serialize();
|
||||
$sUIPage = cmdbAbstractObject::ComputeStandardUIPage($sClass);
|
||||
$sRootUrl = utils::GetAbsoluteUrlAppRoot();
|
||||
@@ -1948,7 +1919,7 @@ class MenuBlock extends DisplayBlock
|
||||
$iLimit = MetaModel::GetConfig()->Get('complex_actions_limit');
|
||||
if (
|
||||
($iSetCount > 0) && (false === $bLocked) && MetaModel::HasLifecycle($sClass) &&
|
||||
( ($iLimit == 0) || ($iSetCount < $iLimit) )
|
||||
(($iLimit == 0) || ($iSetCount < $iLimit))
|
||||
) {
|
||||
$aTransitions = [];
|
||||
// Processing (optimizations) and endpoints are not exactly the same depending on if there is only 1 object or a set
|
||||
@@ -1968,8 +1939,8 @@ class MenuBlock extends DisplayBlock
|
||||
// Life cycle actions may be available... if all objects are in the same state
|
||||
// Group by <state>
|
||||
$oGroupByExp = new FieldExpression(MetaModel::GetStateAttributeCode($sClass), $this->m_oFilter->GetClassAlias());
|
||||
$aGroupBy = array('__state__' => $oGroupByExp);
|
||||
$aQueryParams = array();
|
||||
$aGroupBy = ['__state__' => $oGroupByExp];
|
||||
$aQueryParams = [];
|
||||
if (isset($aExtraParams['query_params'])) {
|
||||
$aQueryParams = $aExtraParams['query_params'];
|
||||
}
|
||||
@@ -2001,10 +1972,10 @@ class MenuBlock extends DisplayBlock
|
||||
switch ($iActionAllowed) {
|
||||
case UR_ALLOWED_YES:
|
||||
case UR_ALLOWED_DEPENDS:
|
||||
$aTransitionActions[$sStimulusCode] = array(
|
||||
$aTransitionActions[$sStimulusCode] = [
|
||||
'label' => $aStimuli[$sStimulusCode]->GetLabel(),
|
||||
'url' => "{$sRootUrl}pages/UI.php?stimulus=$sStimulusCode&class=$sLifecycleClass&{$sUrlQueryString}",
|
||||
) + $aActionParams;
|
||||
] + $aActionParams;
|
||||
break;
|
||||
|
||||
default:
|
||||
@@ -2066,16 +2037,16 @@ class MenuBlock extends DisplayBlock
|
||||
// Just one object in the set, possible actions are "new / clone / modify and delete"
|
||||
if (!isset($aExtraParams['link_attr'])) {
|
||||
if ($bIsModifyAllowed) {
|
||||
$aRegularActions['UI:Menu:Modify'] = array(
|
||||
$aRegularActions['UI:Menu:Modify'] = [
|
||||
'label' => Dict::S('UI:Menu:Modify'),
|
||||
'url' => $oRouter->GenerateUrl('object.modify', ['class' => $sClass, 'id' => $id]) . "{$sContext}#",
|
||||
) + $aActionParams;
|
||||
'url' => $oRouter->GenerateUrl('object.modify', ['class' => $sClass, 'id' => $id])."{$sContext}#",
|
||||
] + $aActionParams;
|
||||
}
|
||||
if ($bIsDeleteAllowed) {
|
||||
$aRegularActions['UI:Menu:Delete'] = array(
|
||||
$aRegularActions['UI:Menu:Delete'] = [
|
||||
'label' => Dict::S('UI:Menu:Delete'),
|
||||
'url' => "{$sRootUrl}pages/$sUIPage?operation=delete&class=$sClass&id=$id{$sContext}",
|
||||
) + $aActionParams;
|
||||
] + $aActionParams;
|
||||
}
|
||||
|
||||
// Relations...
|
||||
@@ -2084,16 +2055,16 @@ class MenuBlock extends DisplayBlock
|
||||
$this->AddMenuSeparator($aRegularActions);
|
||||
foreach ($aRelations as $sRelationCode => $aRelationInfo) {
|
||||
if (array_key_exists('down', $aRelationInfo)) {
|
||||
$aRegularActions[$sRelationCode.'_down'] = array(
|
||||
$aRegularActions[$sRelationCode.'_down'] = [
|
||||
'label' => $aRelationInfo['down'],
|
||||
'url' => "{$sRootUrl}pages/$sUIPage?operation=view_relations&relation=$sRelationCode&direction=down&class=$sClass&id=$id{$sContext}",
|
||||
) + $aActionParams;
|
||||
] + $aActionParams;
|
||||
}
|
||||
if (array_key_exists('up', $aRelationInfo)) {
|
||||
$aRegularActions[$sRelationCode.'_up'] = array(
|
||||
$aRegularActions[$sRelationCode.'_up'] = [
|
||||
'label' => $aRelationInfo['up'],
|
||||
'url' => "{$sRootUrl}pages/$sUIPage?operation=view_relations&relation=$sRelationCode&direction=up&class=$sClass&id=$id{$sContext}",
|
||||
) + $aActionParams;
|
||||
] + $aActionParams;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2105,7 +2076,7 @@ class MenuBlock extends DisplayBlock
|
||||
$bCanKill = false;
|
||||
|
||||
$oUser = UserRights::GetUserObject();
|
||||
$aUserProfiles = array();
|
||||
$aUserProfiles = [];
|
||||
if (!is_null($oUser)) {
|
||||
$oProfileSet = $oUser->Get('profile_list');
|
||||
while ($oProfile = $oProfileSet->Fetch()) {
|
||||
@@ -2127,10 +2098,10 @@ class MenuBlock extends DisplayBlock
|
||||
|
||||
if ($bCanKill) {
|
||||
$this->AddMenuSeparator($aRegularActions);
|
||||
$aRegularActions['concurrent_lock_unlock'] = array(
|
||||
$aRegularActions['concurrent_lock_unlock'] = [
|
||||
'label' => Dict::S('UI:Menu:KillConcurrentLock'),
|
||||
'url' => "{$sRootUrl}pages/$sUIPage?operation=kill_lock&class=$sClass&id=$id{$sContext}",
|
||||
);
|
||||
];
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2138,7 +2109,7 @@ class MenuBlock extends DisplayBlock
|
||||
$this->AddMenuSeparator($aRegularActions);
|
||||
|
||||
$this->GetEnumAllowedActions($oSet, function ($sLabel, $data) use (&$aRegularActions, $aActionParams) {
|
||||
$aRegularActions[$sLabel] = array('label' => $sLabel, 'url' => $data) + $aActionParams;
|
||||
$aRegularActions[$sLabel] = ['label' => $sLabel, 'url' => $data] + $aActionParams;
|
||||
});
|
||||
}
|
||||
break;
|
||||
@@ -2474,13 +2445,11 @@ class MenuBlock extends DisplayBlock
|
||||
protected function AddMenuSeparator(&$aActions)
|
||||
{
|
||||
$sSeparator = '<hr class="menu-separator"/>';
|
||||
if (count($aActions) > 0) // Make sure that the separator is not the first item in the menu
|
||||
{
|
||||
if (count($aActions) > 0) { // Make sure that the separator is not the first item in the menu
|
||||
$aKeys = array_keys($aActions);
|
||||
$sLastKey = array_pop($aKeys);
|
||||
if ($aActions[$sLastKey]['label'] != $sSeparator) // Make sure there are no 2 consecutive separators
|
||||
{
|
||||
$aActions['sep_'.(count($aActions)-1)] = array('label' => $sSeparator, 'url' => '');
|
||||
if ($aActions[$sLastKey]['label'] != $sSeparator) { // Make sure there are no 2 consecutive separators
|
||||
$aActions['sep_'.(count($aActions) - 1)] = ['label' => $sSeparator, 'url' => ''];
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2540,10 +2509,10 @@ class MenuBlock extends DisplayBlock
|
||||
*/
|
||||
protected function AddBulkDeleteObjectsMenuAction(array &$aActions, string $sClass, string $sFilter, string $sActionIdentifier = 'UI:Menu:BulkDelete', $sActionLabel = 'UI:Menu:BulkDelete')
|
||||
{
|
||||
$aActions[$sActionIdentifier] = array(
|
||||
$aActions[$sActionIdentifier] = [
|
||||
'label' => Dict::S($sActionLabel),
|
||||
'url' => $this->PrepareUrlForStandardMenuAction($sClass, "operation=select_for_deletion&filter=".urlencode($sFilter)),
|
||||
) + $this->GetDefaultParamsForMenuAction();
|
||||
] + $this->GetDefaultParamsForMenuAction();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2580,6 +2549,6 @@ class MenuBlock extends DisplayBlock
|
||||
$oAppContext = new ApplicationContext();
|
||||
$sContext = $oAppContext->GetForLink(true);
|
||||
|
||||
return $sUrl . $sContext;
|
||||
return $sUrl.$sContext;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @deprecated 3.0.0 will be removed in 3.1.0 - moved to sources/Application/WebPage/ErrorPage.php, now loadable using autoloader
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
* @copyright Copyright (C) 2010-2024 Combodo SAS
|
||||
*/
|
||||
|
||||
DeprecatedCallsLog::NotifyDeprecatedFile('moved to sources/Application/WebPage/ErrorPage.php, now loadable using autoloader');
|
||||
DeprecatedCallsLog::NotifyDeprecatedFile('moved to sources/Application/WebPage/ErrorPage.php, now loadable using autoloader');
|
||||
|
||||
@@ -19,73 +19,67 @@ class ExcelExporter
|
||||
protected $iPosition;
|
||||
protected $sOutputFilePath;
|
||||
protected $bAdvancedMode;
|
||||
|
||||
|
||||
public function __construct($sToken = null)
|
||||
{
|
||||
$this->aStatistics = array(
|
||||
$this->aStatistics = [
|
||||
'objects_count' => 0,
|
||||
'total_duration' => 0,
|
||||
'data_retrieval_duration' => 0,
|
||||
'excel_build_duration' => 0,
|
||||
'excel_write_duration' => 0,
|
||||
'peak_memory_usage' => 0,
|
||||
);
|
||||
'peak_memory_usage' => 0,
|
||||
];
|
||||
$this->fStartTime = microtime(true);
|
||||
$this->oSearch = null;
|
||||
|
||||
|
||||
$this->sState = 'new';
|
||||
$this->aObjectsIDs = array();
|
||||
$this->aObjectsIDs = [];
|
||||
$this->iPosition = 0;
|
||||
$this->aAuthorizedClasses = null;
|
||||
$this->aTableHeaders = null;
|
||||
$this->sOutputFilePath = null;
|
||||
$this->bAdvancedMode = false;
|
||||
$this->CheckDataDir();
|
||||
if ($sToken == null)
|
||||
{
|
||||
if ($sToken == null) {
|
||||
$this->sToken = $this->GetNewToken();
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
$this->sToken = $sToken;
|
||||
$this->ReloadState();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public function __destruct()
|
||||
{
|
||||
if (($this->sState != 'done') && ($this->sState != 'error') && ($this->sToken != null))
|
||||
{
|
||||
if (($this->sState != 'done') && ($this->sState != 'error') && ($this->sToken != null)) {
|
||||
// Operation in progress, save the state
|
||||
$this->SaveState();
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
// Operation completed, cleanup the temp files
|
||||
@unlink($this->GetStateFile());
|
||||
@unlink($this->GetDataFile());
|
||||
}
|
||||
self::CleanupOldFiles();
|
||||
self::CleanupOldFiles();
|
||||
}
|
||||
|
||||
|
||||
public function SetChunkSize($iChunkSize)
|
||||
{
|
||||
$this->iChunkSize = $iChunkSize;
|
||||
$this->iChunkSize = $iChunkSize;
|
||||
}
|
||||
|
||||
|
||||
public function SetOutputFilePath($sDestFilePath)
|
||||
{
|
||||
$this->sOutputFilePath = $sDestFilePath;
|
||||
}
|
||||
|
||||
|
||||
public function SetAdvancedMode($bAdvanced)
|
||||
{
|
||||
$this->bAdvancedMode = $bAdvanced;
|
||||
}
|
||||
|
||||
|
||||
public function SaveState()
|
||||
{
|
||||
$aState = array(
|
||||
$aState = [
|
||||
'state' => $this->sState,
|
||||
'statistics' => $this->aStatistics,
|
||||
'filter' => $this->oSearch->serialize(),
|
||||
@@ -94,31 +88,28 @@ class ExcelExporter
|
||||
'object_ids' => $this->aObjectsIDs,
|
||||
'output_file_path' => $this->sOutputFilePath,
|
||||
'advanced_mode' => $this->bAdvancedMode,
|
||||
);
|
||||
|
||||
];
|
||||
|
||||
file_put_contents($this->GetStateFile(), json_encode($aState));
|
||||
|
||||
|
||||
return $this->sToken;
|
||||
}
|
||||
|
||||
|
||||
public function ReloadState()
|
||||
{
|
||||
if ($this->sToken == null)
|
||||
{
|
||||
if ($this->sToken == null) {
|
||||
throw new Exception('ExcelExporter not initialized with a token, cannot reload state');
|
||||
}
|
||||
|
||||
if (!file_exists($this->GetStateFile()))
|
||||
{
|
||||
|
||||
if (!file_exists($this->GetStateFile())) {
|
||||
throw new Exception("ExcelExporter: missing status file '".$this->GetStateFile()."', cannot reload state.");
|
||||
}
|
||||
$sJson = file_get_contents($this->GetStateFile());
|
||||
$aState = json_decode($sJson, true);
|
||||
if ($aState === null)
|
||||
{
|
||||
if ($aState === null) {
|
||||
throw new Exception("ExcelExporter:corrupted status file '".$this->GetStateFile()."', not a JSON, cannot reload state.");
|
||||
}
|
||||
|
||||
|
||||
$this->sState = $aState['state'];
|
||||
$this->aStatistics = $aState['statistics'];
|
||||
$this->oSearch = DBObjectSearch::unserialize($aState['filter']);
|
||||
@@ -128,206 +119,183 @@ class ExcelExporter
|
||||
$this->sOutputFilePath = $aState['output_file_path'];
|
||||
$this->bAdvancedMode = $aState['advanced_mode'];
|
||||
}
|
||||
|
||||
|
||||
public function SetObjectList($oSearch)
|
||||
{
|
||||
$this->oSearch = $oSearch;
|
||||
}
|
||||
|
||||
|
||||
public function Run()
|
||||
{
|
||||
$sCode = 'error';
|
||||
$iPercentage = 100;
|
||||
$sMessage = Dict::Format('ExcelExporter:ErrorUnexpected_State', $this->sState);
|
||||
$fTime = microtime(true);
|
||||
|
||||
try
|
||||
{
|
||||
switch($this->sState)
|
||||
{
|
||||
|
||||
try {
|
||||
switch ($this->sState) {
|
||||
case 'new':
|
||||
$oIDSet = new DBObjectSet($this->oSearch);
|
||||
$oIDSet->OptimizeColumnLoad(array('id'));
|
||||
$this->aObjectsIDs = array();
|
||||
while($oObj = $oIDSet->Fetch())
|
||||
{
|
||||
$this->aObjectsIDs[] = $oObj->GetKey();
|
||||
}
|
||||
$sCode = 'retrieving-data';
|
||||
$iPercentage = 5;
|
||||
$sMessage = Dict::S('ExcelExporter:RetrievingData');
|
||||
$this->iPosition = 0;
|
||||
$this->aStatistics['objects_count'] = count($this->aObjectsIDs);
|
||||
$this->aStatistics['data_retrieval_duration'] += microtime(true) - $fTime;
|
||||
|
||||
// The first line of the file is the "headers" specifying the label and the type of each column
|
||||
$this->GetFieldsList($oIDSet, $this->bAdvancedMode);
|
||||
$sRow = json_encode($this->aTableHeaders);
|
||||
$hFile = @fopen($this->GetDataFile(), 'ab');
|
||||
if ($hFile === false)
|
||||
{
|
||||
throw new Exception('ExcelExporter: Failed to open temporary data file: "'.$this->GetDataFile().'" for writing.');
|
||||
}
|
||||
fwrite($hFile, $sRow."\n");
|
||||
fclose($hFile);
|
||||
|
||||
// Next state
|
||||
$this->sState = 'retrieving-data';
|
||||
break;
|
||||
|
||||
case 'retrieving-data':
|
||||
$oCurrentSearch = clone $this->oSearch;
|
||||
$aIDs = array_slice($this->aObjectsIDs, $this->iPosition, $this->iChunkSize);
|
||||
|
||||
$oCurrentSearch->AddCondition('id', $aIDs, 'IN');
|
||||
$hFile = @fopen($this->GetDataFile(), 'ab');
|
||||
if ($hFile === false)
|
||||
{
|
||||
throw new Exception('ExcelExporter: Failed to open temporary data file: "'.$this->GetDataFile().'" for writing.');
|
||||
}
|
||||
$oSet = new DBObjectSet($oCurrentSearch);
|
||||
$this->GetFieldsList($oSet, $this->bAdvancedMode);
|
||||
while($aObjects = $oSet->FetchAssoc())
|
||||
{
|
||||
$aRow = array();
|
||||
foreach($this->aAuthorizedClasses as $sAlias => $sClassName)
|
||||
{
|
||||
$oObj = $aObjects[$sAlias];
|
||||
if ($this->bAdvancedMode)
|
||||
{
|
||||
$aRow[] = $oObj->GetKey();
|
||||
}
|
||||
foreach($this->aFieldsList[$sAlias] as $sAttCodeEx => $oAttDef)
|
||||
{
|
||||
$value = $oObj->Get($sAttCodeEx);
|
||||
if ($value instanceOf ormCaseLog)
|
||||
{
|
||||
// Extract the case log as text and remove the "===" which make Excel think that the cell contains a formula the next time you edit it!
|
||||
$sExcelVal = trim(preg_replace('/========== ([^=]+) ============/', '********** $1 ************', $value->GetText()));
|
||||
}
|
||||
else
|
||||
{
|
||||
$sExcelVal = $oAttDef->GetEditValue($value, $oObj);
|
||||
}
|
||||
$aRow[] = $sExcelVal;
|
||||
}
|
||||
$oIDSet = new DBObjectSet($this->oSearch);
|
||||
$oIDSet->OptimizeColumnLoad(['id']);
|
||||
$this->aObjectsIDs = [];
|
||||
while ($oObj = $oIDSet->Fetch()) {
|
||||
$this->aObjectsIDs[] = $oObj->GetKey();
|
||||
}
|
||||
$sRow = json_encode($aRow);
|
||||
fwrite($hFile, $sRow."\n");
|
||||
}
|
||||
fclose($hFile);
|
||||
|
||||
if (($this->iPosition + $this->iChunkSize) > count($this->aObjectsIDs))
|
||||
{
|
||||
// Next state
|
||||
$this->sState = 'building-excel';
|
||||
$sCode = 'building-excel';
|
||||
$iPercentage = 80;
|
||||
$sMessage = Dict::S('ExcelExporter:BuildingExcelFile');
|
||||
}
|
||||
else
|
||||
{
|
||||
$sCode = 'retrieving-data';
|
||||
$this->iPosition += $this->iChunkSize;
|
||||
$iPercentage = 5 + round(75 * ($this->iPosition / count($this->aObjectsIDs)));
|
||||
$sMessage = Dict::S('ExcelExporter:RetrievingData');
|
||||
}
|
||||
break;
|
||||
|
||||
$iPercentage = 5;
|
||||
$sMessage = Dict::S('ExcelExporter:RetrievingData');
|
||||
$this->iPosition = 0;
|
||||
$this->aStatistics['objects_count'] = count($this->aObjectsIDs);
|
||||
$this->aStatistics['data_retrieval_duration'] += microtime(true) - $fTime;
|
||||
|
||||
// The first line of the file is the "headers" specifying the label and the type of each column
|
||||
$this->GetFieldsList($oIDSet, $this->bAdvancedMode);
|
||||
$sRow = json_encode($this->aTableHeaders);
|
||||
$hFile = @fopen($this->GetDataFile(), 'ab');
|
||||
if ($hFile === false) {
|
||||
throw new Exception('ExcelExporter: Failed to open temporary data file: "'.$this->GetDataFile().'" for writing.');
|
||||
}
|
||||
fwrite($hFile, $sRow."\n");
|
||||
fclose($hFile);
|
||||
|
||||
// Next state
|
||||
$this->sState = 'retrieving-data';
|
||||
break;
|
||||
|
||||
case 'retrieving-data':
|
||||
$oCurrentSearch = clone $this->oSearch;
|
||||
$aIDs = array_slice($this->aObjectsIDs, $this->iPosition, $this->iChunkSize);
|
||||
|
||||
$oCurrentSearch->AddCondition('id', $aIDs, 'IN');
|
||||
$hFile = @fopen($this->GetDataFile(), 'ab');
|
||||
if ($hFile === false) {
|
||||
throw new Exception('ExcelExporter: Failed to open temporary data file: "'.$this->GetDataFile().'" for writing.');
|
||||
}
|
||||
$oSet = new DBObjectSet($oCurrentSearch);
|
||||
$this->GetFieldsList($oSet, $this->bAdvancedMode);
|
||||
while ($aObjects = $oSet->FetchAssoc()) {
|
||||
$aRow = [];
|
||||
foreach ($this->aAuthorizedClasses as $sAlias => $sClassName) {
|
||||
$oObj = $aObjects[$sAlias];
|
||||
if ($this->bAdvancedMode) {
|
||||
$aRow[] = $oObj->GetKey();
|
||||
}
|
||||
foreach ($this->aFieldsList[$sAlias] as $sAttCodeEx => $oAttDef) {
|
||||
$value = $oObj->Get($sAttCodeEx);
|
||||
if ($value instanceof ormCaseLog) {
|
||||
// Extract the case log as text and remove the "===" which make Excel think that the cell contains a formula the next time you edit it!
|
||||
$sExcelVal = trim(preg_replace('/========== ([^=]+) ============/', '********** $1 ************', $value->GetText()));
|
||||
} else {
|
||||
$sExcelVal = $oAttDef->GetEditValue($value, $oObj);
|
||||
}
|
||||
$aRow[] = $sExcelVal;
|
||||
}
|
||||
}
|
||||
$sRow = json_encode($aRow);
|
||||
fwrite($hFile, $sRow."\n");
|
||||
}
|
||||
fclose($hFile);
|
||||
|
||||
if (($this->iPosition + $this->iChunkSize) > count($this->aObjectsIDs)) {
|
||||
// Next state
|
||||
$this->sState = 'building-excel';
|
||||
$sCode = 'building-excel';
|
||||
$iPercentage = 80;
|
||||
$sMessage = Dict::S('ExcelExporter:BuildingExcelFile');
|
||||
} else {
|
||||
$sCode = 'retrieving-data';
|
||||
$this->iPosition += $this->iChunkSize;
|
||||
$iPercentage = 5 + round(75 * ($this->iPosition / count($this->aObjectsIDs)));
|
||||
$sMessage = Dict::S('ExcelExporter:RetrievingData');
|
||||
}
|
||||
break;
|
||||
|
||||
case 'building-excel':
|
||||
$hFile = @fopen($this->GetDataFile(), 'rb');
|
||||
if ($hFile === false)
|
||||
{
|
||||
throw new Exception('ExcelExporter: Failed to open temporary data file: "'.$this->GetDataFile().'" for reading.');
|
||||
}
|
||||
$sHeaders = fgets($hFile);
|
||||
$aHeaders = json_decode($sHeaders, true);
|
||||
|
||||
$aData = array();
|
||||
while($sLine = fgets($hFile))
|
||||
{
|
||||
$aRow = json_decode($sLine);
|
||||
$aData[] = $aRow;
|
||||
}
|
||||
fclose($hFile);
|
||||
@unlink($this->GetDataFile());
|
||||
|
||||
$fStartExcel = microtime(true);
|
||||
$writer = new XLSXWriter();
|
||||
$writer->setAuthor(UserRights::GetUserFriendlyName());
|
||||
$writer->writeSheet($aData,'Sheet1', $aHeaders);
|
||||
$fExcelTime = microtime(true) - $fStartExcel;
|
||||
$this->aStatistics['excel_build_duration'] = $fExcelTime;
|
||||
|
||||
$fTime = microtime(true);
|
||||
$writer->writeToFile($this->GetExcelFilePath());
|
||||
$fExcelSaveTime = microtime(true) - $fTime;
|
||||
$this->aStatistics['excel_write_duration'] = $fExcelSaveTime;
|
||||
|
||||
// Next state
|
||||
$this->sState = 'done';
|
||||
$sCode = 'done';
|
||||
$iPercentage = 100;
|
||||
$sMessage = Dict::S('ExcelExporter:Done');
|
||||
break;
|
||||
|
||||
$hFile = @fopen($this->GetDataFile(), 'rb');
|
||||
if ($hFile === false) {
|
||||
throw new Exception('ExcelExporter: Failed to open temporary data file: "'.$this->GetDataFile().'" for reading.');
|
||||
}
|
||||
$sHeaders = fgets($hFile);
|
||||
$aHeaders = json_decode($sHeaders, true);
|
||||
|
||||
$aData = [];
|
||||
while ($sLine = fgets($hFile)) {
|
||||
$aRow = json_decode($sLine);
|
||||
$aData[] = $aRow;
|
||||
}
|
||||
fclose($hFile);
|
||||
@unlink($this->GetDataFile());
|
||||
|
||||
$fStartExcel = microtime(true);
|
||||
$writer = new XLSXWriter();
|
||||
$writer->setAuthor(UserRights::GetUserFriendlyName());
|
||||
$writer->writeSheet($aData, 'Sheet1', $aHeaders);
|
||||
$fExcelTime = microtime(true) - $fStartExcel;
|
||||
$this->aStatistics['excel_build_duration'] = $fExcelTime;
|
||||
|
||||
$fTime = microtime(true);
|
||||
$writer->writeToFile($this->GetExcelFilePath());
|
||||
$fExcelSaveTime = microtime(true) - $fTime;
|
||||
$this->aStatistics['excel_write_duration'] = $fExcelSaveTime;
|
||||
|
||||
// Next state
|
||||
$this->sState = 'done';
|
||||
$sCode = 'done';
|
||||
$iPercentage = 100;
|
||||
$sMessage = Dict::S('ExcelExporter:Done');
|
||||
break;
|
||||
|
||||
case 'done':
|
||||
$this->sState = 'done';
|
||||
$sCode = 'done';
|
||||
$iPercentage = 100;
|
||||
$sMessage = Dict::S('ExcelExporter:Done');
|
||||
break;
|
||||
$this->sState = 'done';
|
||||
$sCode = 'done';
|
||||
$iPercentage = 100;
|
||||
$sMessage = Dict::S('ExcelExporter:Done');
|
||||
break;
|
||||
}
|
||||
}
|
||||
catch(Exception $e)
|
||||
{
|
||||
} catch (Exception $e) {
|
||||
$sCode = 'error';
|
||||
$sMessage = $e->getMessage();
|
||||
}
|
||||
|
||||
|
||||
$this->aStatistics['total_duration'] += microtime(true) - $fTime;
|
||||
$peak_memory = memory_get_peak_usage(true);
|
||||
if ($peak_memory > $this->aStatistics['peak_memory_usage'])
|
||||
{
|
||||
if ($peak_memory > $this->aStatistics['peak_memory_usage']) {
|
||||
$this->aStatistics['peak_memory_usage'] = $peak_memory;
|
||||
}
|
||||
|
||||
return array(
|
||||
|
||||
return [
|
||||
'code' => $sCode,
|
||||
'message' => $sMessage,
|
||||
'percentage' => $iPercentage,
|
||||
);
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
public function GetExcelFilePath()
|
||||
{
|
||||
if ($this->sOutputFilePath == null)
|
||||
{
|
||||
if ($this->sOutputFilePath == null) {
|
||||
return APPROOT.'data/bulk_export/'.$this->sToken.'.xlsx';
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
return $this->sOutputFilePath;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static function GetExcelFileFromToken($sToken)
|
||||
{
|
||||
return @file_get_contents(APPROOT.'data/bulk_export/'.$sToken.'.xlsx');
|
||||
}
|
||||
|
||||
|
||||
public static function CleanupFromToken($sToken)
|
||||
{
|
||||
@unlink(APPROOT.'data/bulk_export/'.$sToken.'.status');
|
||||
@unlink(APPROOT.'data/bulk_export/'.$sToken.'.data');
|
||||
@unlink(APPROOT.'data/bulk_export/'.$sToken.'.xlsx');
|
||||
}
|
||||
|
||||
|
||||
public function Cleanup()
|
||||
{
|
||||
self::CleanupFromToken($this->sToken);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Delete all files in the data/bulk_export directory which are older than 1 day
|
||||
* unless a different delay is configured.
|
||||
@@ -336,15 +304,12 @@ class ExcelExporter
|
||||
{
|
||||
$aFiles = glob(APPROOT.'data/bulk_export/*.*');
|
||||
$iDelay = MetaModel::GetConfig()->Get('xlsx_exporter_cleanup_old_files_delay');
|
||||
|
||||
if($iDelay > 0)
|
||||
{
|
||||
foreach($aFiles as $sFile)
|
||||
{
|
||||
|
||||
if ($iDelay > 0) {
|
||||
foreach ($aFiles as $sFile) {
|
||||
$iModificationTime = filemtime($sFile);
|
||||
|
||||
if($iModificationTime < (time() - $iDelay))
|
||||
{
|
||||
|
||||
if ($iModificationTime < (time() - $iDelay)) {
|
||||
// Temporary files older than one day are deleted
|
||||
//echo "Supposed to delete: '".$sFile." (Unix Modification Time: $iModificationTime)'\n";
|
||||
@unlink($sFile);
|
||||
@@ -352,189 +317,155 @@ class ExcelExporter
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public function DisplayStatistics(Page $oPage)
|
||||
{
|
||||
$aStats = array(
|
||||
$aStats = [
|
||||
'Number of objects exported' => $this->aStatistics['objects_count'],
|
||||
'Total export duration' => sprintf('%.3f s', $this->aStatistics['total_duration']),
|
||||
'Data retrieval duration' => sprintf('%.3f s', $this->aStatistics['data_retrieval_duration']),
|
||||
'Excel build duration' => sprintf('%.3f s', $this->aStatistics['excel_build_duration']),
|
||||
'Excel write duration' => sprintf('%.3f s', $this->aStatistics['excel_write_duration']),
|
||||
'Peak memory usage' => self::HumanDisplay($this->aStatistics['peak_memory_usage']),
|
||||
);
|
||||
|
||||
if ($oPage instanceof CLIPage)
|
||||
{
|
||||
];
|
||||
|
||||
if ($oPage instanceof CLIPage) {
|
||||
$oPage->add($this->GetStatistics('text'));
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
$oPage->add($this->GetStatistics('html'));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public function GetStatistics($sFormat = 'html')
|
||||
{
|
||||
$sStats = '';
|
||||
$aStats = array(
|
||||
$aStats = [
|
||||
'Number of objects exported' => $this->aStatistics['objects_count'],
|
||||
'Total export duration' => sprintf('%.3f s', $this->aStatistics['total_duration']),
|
||||
'Data retrieval duration' => sprintf('%.3f s', $this->aStatistics['data_retrieval_duration']),
|
||||
'Excel build duration' => sprintf('%.3f s', $this->aStatistics['excel_build_duration']),
|
||||
'Excel write duration' => sprintf('%.3f s', $this->aStatistics['excel_write_duration']),
|
||||
'Peak memory usage' => self::HumanDisplay($this->aStatistics['peak_memory_usage']),
|
||||
);
|
||||
|
||||
if ($sFormat == 'text')
|
||||
{
|
||||
foreach($aStats as $sLabel => $sValue)
|
||||
{
|
||||
];
|
||||
|
||||
if ($sFormat == 'text') {
|
||||
foreach ($aStats as $sLabel => $sValue) {
|
||||
$sStats .= "+------------------------------+----------+\n";
|
||||
$sStats .= sprintf("|%-30s|%10s|\n", $sLabel, $sValue);
|
||||
}
|
||||
$sStats .= "+------------------------------+----------+";
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
$sStats .= '<table><tbody>';
|
||||
foreach($aStats as $sLabel => $sValue)
|
||||
{
|
||||
foreach ($aStats as $sLabel => $sValue) {
|
||||
$sStats .= "<tr><td>$sLabel</td><td>$sValue</td></tr>";
|
||||
}
|
||||
$sStats .= '</tbody></table>';
|
||||
|
||||
|
||||
}
|
||||
return $sStats;
|
||||
}
|
||||
|
||||
|
||||
public static function HumanDisplay($iSize)
|
||||
{
|
||||
$aUnits = array('B','KB','MB','GB','TB','PB');
|
||||
return @round($iSize/pow(1024,($i=floor(log($iSize,1024)))),2).' '.$aUnits[$i];
|
||||
$aUnits = ['B','KB','MB','GB','TB','PB'];
|
||||
return @round($iSize / pow(1024, ($i = floor(log($iSize, 1024)))), 2).' '.$aUnits[$i];
|
||||
}
|
||||
|
||||
|
||||
protected function CheckDataDir()
|
||||
{
|
||||
if(!is_dir(APPROOT."data/bulk_export"))
|
||||
{
|
||||
if (!is_dir(APPROOT."data/bulk_export")) {
|
||||
@mkdir(APPROOT."data/bulk_export", 0777, true /* recursive */);
|
||||
clearstatcache();
|
||||
}
|
||||
if (!is_writable(APPROOT."data/bulk_export"))
|
||||
{
|
||||
if (!is_writable(APPROOT."data/bulk_export")) {
|
||||
throw new Exception('Data directory "'.APPROOT.'data/bulk_export" could not be written.');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
protected function GetStateFile($sToken = null)
|
||||
{
|
||||
if ($sToken == null)
|
||||
{
|
||||
if ($sToken == null) {
|
||||
$sToken = $this->sToken;
|
||||
}
|
||||
return APPROOT."data/bulk_export/$sToken.status";
|
||||
}
|
||||
|
||||
|
||||
protected function GetDataFile()
|
||||
{
|
||||
return APPROOT.'data/bulk_export/'.$this->sToken.'.data';
|
||||
}
|
||||
|
||||
|
||||
protected function GetNewToken()
|
||||
{
|
||||
$iNum = rand();
|
||||
do
|
||||
{
|
||||
do {
|
||||
$iNum++;
|
||||
$sToken = sprintf("%08x", $iNum);
|
||||
$sFileName = $this->GetStateFile($sToken);
|
||||
$hFile = @fopen($sFileName, 'x');
|
||||
}
|
||||
while($hFile === false);
|
||||
|
||||
} while ($hFile === false);
|
||||
|
||||
fclose($hFile);
|
||||
return $sToken;
|
||||
}
|
||||
|
||||
|
||||
protected function GetFieldsList($oSet, $bFieldsAdvanced = false, $bLocalize = true, $aFields = null)
|
||||
{
|
||||
$this->aFieldsList = array();
|
||||
|
||||
$this->aFieldsList = [];
|
||||
|
||||
$oAppContext = new ApplicationContext();
|
||||
$aClasses = $oSet->GetFilter()->GetSelectedClasses();
|
||||
$this->aAuthorizedClasses = array();
|
||||
foreach($aClasses as $sAlias => $sClassName)
|
||||
{
|
||||
if (UserRights::IsActionAllowed($sClassName, UR_ACTION_READ, $oSet) != UR_ALLOWED_NO)
|
||||
{
|
||||
$this->aAuthorizedClasses = [];
|
||||
foreach ($aClasses as $sAlias => $sClassName) {
|
||||
if (UserRights::IsActionAllowed($sClassName, UR_ACTION_READ, $oSet) != UR_ALLOWED_NO) {
|
||||
$this->aAuthorizedClasses[$sAlias] = $sClassName;
|
||||
}
|
||||
}
|
||||
$aAttribs = array();
|
||||
$this->aTableHeaders = array();
|
||||
foreach($this->aAuthorizedClasses as $sAlias => $sClassName)
|
||||
{
|
||||
$aList[$sAlias] = array();
|
||||
|
||||
foreach(MetaModel::ListAttributeDefs($sClassName) as $sAttCode => $oAttDef)
|
||||
{
|
||||
if (is_null($aFields) || (count($aFields) == 0))
|
||||
{
|
||||
$aAttribs = [];
|
||||
$this->aTableHeaders = [];
|
||||
foreach ($this->aAuthorizedClasses as $sAlias => $sClassName) {
|
||||
$aList[$sAlias] = [];
|
||||
|
||||
foreach (MetaModel::ListAttributeDefs($sClassName) as $sAttCode => $oAttDef) {
|
||||
if (is_null($aFields) || (count($aFields) == 0)) {
|
||||
// Standard list of attributes (no link sets)
|
||||
if ($oAttDef->IsScalar() && ($oAttDef->IsWritable() || $oAttDef->IsExternalField()))
|
||||
{
|
||||
if ($oAttDef->IsScalar() && ($oAttDef->IsWritable() || $oAttDef->IsExternalField())) {
|
||||
$sAttCodeEx = $oAttDef->IsExternalField() ? $oAttDef->GetKeyAttCode().'->'.$oAttDef->GetExtAttCode() : $sAttCode;
|
||||
|
||||
if ($oAttDef->IsExternalKey(EXTKEY_ABSOLUTE))
|
||||
{
|
||||
if ($bFieldsAdvanced)
|
||||
{
|
||||
|
||||
if ($oAttDef->IsExternalKey(EXTKEY_ABSOLUTE)) {
|
||||
if ($bFieldsAdvanced) {
|
||||
$aList[$sAlias][$sAttCodeEx] = $oAttDef;
|
||||
|
||||
if ($oAttDef->IsExternalKey(EXTKEY_RELATIVE))
|
||||
{
|
||||
$sRemoteClass = $oAttDef->GetTargetClass();
|
||||
foreach(MetaModel::GetReconcKeys($sRemoteClass) as $sRemoteAttCode)
|
||||
{
|
||||
|
||||
if ($oAttDef->IsExternalKey(EXTKEY_RELATIVE)) {
|
||||
$sRemoteClass = $oAttDef->GetTargetClass();
|
||||
foreach (MetaModel::GetReconcKeys($sRemoteClass) as $sRemoteAttCode) {
|
||||
$this->aFieldsList[$sAlias][$sAttCode.'->'.$sRemoteAttCode] = MetaModel::GetAttributeDef($sRemoteClass, $sRemoteAttCode);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
// Any other attribute
|
||||
$this->aFieldsList[$sAlias][$sAttCodeEx] = $oAttDef;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
// User defined list of attributes
|
||||
if (in_array($sAttCode, $aFields) || in_array($sAlias.'.'.$sAttCode, $aFields))
|
||||
{
|
||||
if (in_array($sAttCode, $aFields) || in_array($sAlias.'.'.$sAttCode, $aFields)) {
|
||||
$this->aFieldsList[$sAlias][$sAttCode] = $oAttDef;
|
||||
}
|
||||
}
|
||||
}
|
||||
if ($bFieldsAdvanced)
|
||||
{
|
||||
if ($bFieldsAdvanced) {
|
||||
$this->aTableHeaders['id'] = '0';
|
||||
}
|
||||
foreach($this->aFieldsList[$sAlias] as $sAttCodeEx => $oAttDef)
|
||||
{
|
||||
foreach ($this->aFieldsList[$sAlias] as $sAttCodeEx => $oAttDef) {
|
||||
$sLabel = $bLocalize ? MetaModel::GetLabel($sClassName, $sAttCodeEx, isset($aParams['showMandatoryFields'])) : $sAttCodeEx;
|
||||
if($oAttDef instanceof AttributeDateTime)
|
||||
{
|
||||
if ($oAttDef instanceof AttributeDateTime) {
|
||||
$this->aTableHeaders[$sLabel] = 'datetime';
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
$this->aTableHeaders[$sLabel] = 'string';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* @copyright Copyright (C) 2010-2024 Combodo SAS
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* @copyright Copyright (C) 2010-2024 Combodo SAS
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* @copyright Copyright (C) 2010-2024 Combodo SAS
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
@@ -6,4 +7,4 @@
|
||||
|
||||
class BulkChangeException extends CoreException
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* @copyright Copyright (C) 2010-2024 Combodo SAS
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
@@ -6,4 +7,4 @@
|
||||
|
||||
class CSVParserException extends CoreException
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* @copyright Copyright (C) 2010-2024 Combodo SAS
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
@@ -6,4 +7,4 @@
|
||||
|
||||
class ConfigException extends CoreException
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* @copyright Copyright (C) 2010-2024 Combodo SAS
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
@@ -63,21 +64,20 @@ class CoreCannotSaveObjectException extends CoreException
|
||||
public function getTextMessage()
|
||||
{
|
||||
$sTitle = Dict::S('UI:Error:SaveFailed');
|
||||
$sContent = $sTitle;
|
||||
$sContent = $sTitle;
|
||||
|
||||
if (count($this->aIssues) == 1) {
|
||||
$sIssue = reset($this->aIssues);
|
||||
$sContent .= $sIssue;
|
||||
$sContent .= $sIssue;
|
||||
} else {
|
||||
foreach ($this->aIssues as $sError) {
|
||||
$sContent .= " " . $sError . ", ";
|
||||
$sContent .= " ".$sError.", ";
|
||||
}
|
||||
}
|
||||
|
||||
return $sContent;
|
||||
}
|
||||
|
||||
|
||||
public function getIssues()
|
||||
{
|
||||
return $this->aIssues;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* @copyright Copyright (C) 2010-2024 Combodo SAS
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
@@ -35,10 +36,10 @@ class CoreException extends Exception
|
||||
}
|
||||
if (count($this->m_aContextData) > 0) {
|
||||
$sMessage .= ": ";
|
||||
$aContextItems = array();
|
||||
$aContextItems = [];
|
||||
foreach ($this->m_aContextData as $sKey => $value) {
|
||||
if (is_array($value)) {
|
||||
$aPairs = array();
|
||||
$aPairs = [];
|
||||
foreach ($value as $key => $val) {
|
||||
if (is_array($val)) {
|
||||
$aPairs[] = $key.'=>('.implode(', ', $val).')';
|
||||
@@ -109,4 +110,4 @@ class CoreException extends Exception
|
||||
{
|
||||
return $this->m_aContextData;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* @copyright Copyright (C) 2010-2024 Combodo SAS
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
@@ -9,5 +10,4 @@
|
||||
*/
|
||||
class CorePortalInvalidActionRuleException extends CoreException
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* @copyright Copyright (C) 2010-2024 Combodo SAS
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
@@ -14,4 +15,4 @@ class CoreTemplateException extends CoreException
|
||||
$sMessage = "Twig Exception when rendering '$sTemplatePath' : ".$oTwigException->getMessage();
|
||||
parent::__construct($sMessage, null, '', $oTwigException);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* @copyright Copyright (C) 2010-2024 Combodo SAS
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* @copyright Copyright (C) 2010-2024 Combodo SAS
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* @copyright Copyright (C) 2010-2024 Combodo SAS
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
@@ -6,4 +7,4 @@
|
||||
|
||||
class DeleteException extends CoreException
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @copyright Copyright (C) 2010-2026 Combodo SAS
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
class ForgotPasswordApplicationException extends Exception
|
||||
{
|
||||
}
|
||||
10
application/exceptions/ForgotPasswordUserInputException.php
Normal file
10
application/exceptions/ForgotPasswordUserInputException.php
Normal file
@@ -0,0 +1,10 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @copyright Copyright (C) 2010-2026 Combodo SAS
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
class ForgotPasswordUserInputException extends Exception
|
||||
{
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* @copyright Copyright (C) 2010-2024 Combodo SAS
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
|
||||
@@ -12,13 +12,13 @@ class InvalidExternalKeyValueException extends CoreUnexpectedValue
|
||||
|
||||
public function __construct($oObject, $sAttCode, $aContextData = null, $oPrevious = null)
|
||||
{
|
||||
$aContextData[self::ENUM_PARAMS_OBJECT] = get_class($oObject) . '::' . $oObject->GetKey();
|
||||
$aContextData[self::ENUM_PARAMS_OBJECT] = get_class($oObject).'::'.$oObject->GetKey();
|
||||
$aContextData[self::ENUM_PARAMS_ATTCODE] = $sAttCode;
|
||||
$aContextData[self::ENUM_PARAMS_ATTVALUE] = $oObject->Get($sAttCode);
|
||||
|
||||
$oCurrentUser = UserRights::GetUserObject();
|
||||
if (false === is_null($oCurrentUser)) {
|
||||
$aContextData[self::ENUM_PARAMS_USER] = get_class($oCurrentUser) . '::' . $oCurrentUser->GetKey();
|
||||
$aContextData[self::ENUM_PARAMS_USER] = get_class($oCurrentUser).'::'.$oCurrentUser->GetKey();
|
||||
}
|
||||
|
||||
parent::__construct('Attribute pointing to an object that is either non existing or not readable by the current user', $aContextData, '', $oPrevious);
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* @copyright Copyright (C) 2010-2024 Combodo SAS
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
@@ -11,4 +12,4 @@
|
||||
*/
|
||||
class InvalidPasswordAttributeOneWayPassword extends CoreException
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @copyright Copyright (C) 2010-2024 Combodo SAS
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
@@ -10,4 +11,4 @@ use Exception;
|
||||
|
||||
class PageNotFoundException extends Exception
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* @copyright Copyright (C) 2010-2024 Combodo SAS
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* @copyright Copyright (C) 2010-2024 Combodo SAS
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
@@ -6,4 +7,4 @@
|
||||
|
||||
class SynchroExceptionNotStarted extends CoreException
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* @copyright Copyright (C) 2010-2024 Combodo SAS
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
@@ -6,4 +7,4 @@
|
||||
|
||||
class UserRightException extends CoreException
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* @copyright Copyright (C) 2010-2024 Combodo SAS
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
@@ -6,4 +7,4 @@
|
||||
|
||||
class DictException extends CoreException
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* @copyright Copyright (C) 2010-2024 Combodo SAS
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
@@ -8,9 +9,9 @@ class DictExceptionMissingString extends DictException
|
||||
{
|
||||
public function __construct($sLanguageCode, $sStringCode)
|
||||
{
|
||||
$aContext = array();
|
||||
$aContext = [];
|
||||
$aContext['language_code'] = $sLanguageCode;
|
||||
$aContext['string_code'] = $sStringCode;
|
||||
parent::__construct('Missing localized string', $aContext);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* @copyright Copyright (C) 2010-2024 Combodo SAS
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
@@ -8,8 +9,8 @@ class DictExceptionUnknownLanguage extends DictException
|
||||
{
|
||||
public function __construct($sLanguageCode)
|
||||
{
|
||||
$aContext = array();
|
||||
$aContext = [];
|
||||
$aContext['language_code'] = $sLanguageCode;
|
||||
parent::__construct('Unknown localization language', $aContext);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* @copyright Copyright (C) 2010-2024 Combodo SAS
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
@@ -6,5 +7,4 @@
|
||||
|
||||
class iTopXmlException extends CoreException
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* @copyright Copyright (C) 2010-2024 Combodo SAS
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
@@ -20,7 +21,7 @@ class MySQLException extends CoreException
|
||||
$aContext['mysql_errno'] = $oException->getCode();
|
||||
$this->code = $oException->getCode();
|
||||
$aContext['mysql_error'] = $oException->getMessage();
|
||||
} else if ($oMysqli != null) {
|
||||
} elseif ($oMysqli != null) {
|
||||
$aContext['mysql_errno'] = $oMysqli->errno;
|
||||
$this->code = $oMysqli->errno;
|
||||
$aContext['mysql_error'] = $oMysqli->error;
|
||||
@@ -36,4 +37,4 @@ class MySQLException extends CoreException
|
||||
error_reporting(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* @copyright Copyright (C) 2010-2024 Combodo SAS
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
@@ -19,14 +20,14 @@ class MySQLHasGoneAwayException extends MySQLException
|
||||
*/
|
||||
public static function getErrorCodes()
|
||||
{
|
||||
return array(
|
||||
return [
|
||||
2006,
|
||||
2013,
|
||||
);
|
||||
];
|
||||
}
|
||||
|
||||
public function __construct($sIssue, $aContext)
|
||||
{
|
||||
parent::__construct($sIssue, $aContext, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* @copyright Copyright (C) 2010-2024 Combodo SAS
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
@@ -9,5 +10,4 @@
|
||||
*/
|
||||
class MySQLNoTransactionException extends MySQLException
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* @copyright Copyright (C) 2010-2024 Combodo SAS
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
@@ -11,5 +12,4 @@
|
||||
*/
|
||||
class MySQLQueryHasNoResultException extends MySQLException
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* @copyright Copyright (C) 2010-2024 Combodo SAS
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
@@ -9,5 +10,4 @@
|
||||
*/
|
||||
class MySQLTransactionNotClosedException extends MySQLException
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* @copyright Copyright (C) 2010-2024 Combodo SAS
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
@@ -12,4 +13,4 @@
|
||||
*/
|
||||
class ProcessException extends CoreException
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* @copyright Copyright (C) 2010-2024 Combodo SAS
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
@@ -13,4 +14,4 @@
|
||||
*/
|
||||
class ProcessFatalException extends CoreException
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* @copyright Copyright (C) 2010-2024 Combodo SAS
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
@@ -9,4 +10,4 @@
|
||||
*/
|
||||
class ProcessInvalidConfigException extends ProcessException
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Copyright (C) 2013-2024 Combodo SAS
|
||||
*
|
||||
@@ -22,8 +23,8 @@
|
||||
* @author Olivier DAIN <olivier.dain@combodo.com>
|
||||
* @since 3.0.0 N°3588
|
||||
*/
|
||||
class FindStylesheetObject{
|
||||
|
||||
class FindStylesheetObject
|
||||
{
|
||||
//file URIs
|
||||
private $aStylesheetFileURIs;
|
||||
|
||||
@@ -64,7 +65,7 @@ class FindStylesheetObject{
|
||||
return $this->aStylesheetFileURIs;
|
||||
}
|
||||
|
||||
public function GetLastModified() : int
|
||||
public function GetLastModified(): int
|
||||
{
|
||||
return $this->iLastModified;
|
||||
}
|
||||
@@ -92,7 +93,8 @@ class FindStylesheetObject{
|
||||
$this->sLastStyleSheetPath = $sStylesheetFilePath;
|
||||
}
|
||||
|
||||
public function AlreadyFetched(string $sStylesheetFilePath) : bool {
|
||||
public function AlreadyFetched(string $sStylesheetFilePath): bool
|
||||
{
|
||||
return in_array($sStylesheetFilePath, $this->aAllStylesheetFilePaths);
|
||||
}
|
||||
|
||||
@@ -111,4 +113,4 @@ class FindStylesheetObject{
|
||||
{
|
||||
$this->sLastStyleSheetPath = "";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,9 +1,10 @@
|
||||
<?php
|
||||
|
||||
// Copyright (C) 2010-2024 Combodo SAS
|
||||
//
|
||||
// This file is part of iTop.
|
||||
//
|
||||
// iTop is free software; you can redistribute it and/or modify
|
||||
// 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.
|
||||
@@ -16,7 +17,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/>
|
||||
|
||||
|
||||
/**
|
||||
* Persistent class InputOutputTask
|
||||
*
|
||||
@@ -28,41 +28,40 @@ require_once(APPROOT.'/application/cmdbabstract.class.inc.php');
|
||||
|
||||
/**
|
||||
* This class manages the input/output tasks
|
||||
* for synchronizing information with external data sources
|
||||
* for synchronizing information with external data sources
|
||||
*/
|
||||
class InputOutputTask extends cmdbAbstractObject
|
||||
{
|
||||
public static function Init()
|
||||
{
|
||||
$aParams = array
|
||||
(
|
||||
$aParams =
|
||||
[
|
||||
"category" => "application",
|
||||
"key_type" => "autoincrement",
|
||||
"name_attcode" => "name",
|
||||
"state_attcode" => "",
|
||||
"reconc_keys" => array(),
|
||||
"reconc_keys" => [],
|
||||
"db_table" => "priv_iotask",
|
||||
"db_key_field" => "id",
|
||||
"db_finalclass_field" => "",
|
||||
);
|
||||
];
|
||||
MetaModel::Init_Params($aParams);
|
||||
MetaModel::Init_AddAttribute(new AttributeString("name", array("allowed_values"=>null, "sql"=>"name", "default_value"=>"", "is_null_allowed"=>false, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeString("description", array("allowed_values"=>null, "sql"=>"description", "default_value"=>"", "is_null_allowed"=>true, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeEnum("category", array("allowed_values"=>new ValueSetEnum('Input, Ouput'), "sql"=>"category", "default_value"=>"Input", "is_null_allowed"=>false, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeEnum("source_type", array("allowed_values"=>new ValueSetEnum('File, Database, Web Service'), "sql"=>"source_type", "default_value"=>"File", "is_null_allowed"=>false, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeEnum("source_subtype", array("allowed_values"=>new ValueSetEnum('Oracle, MySQL, Postgress, MSSQL, SOAP, HTTP-Get, HTTP-Post, XML/RPC, CSV, XML, Excel'), "sql"=>"source_subtype", "default_value"=>"CSV", "is_null_allowed"=>false, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeString("source_path", array("allowed_values"=>null, "sql"=>"source_path", "default_value"=>"", "is_null_allowed"=>false, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeClass("objects_class", array("class_category"=>"", "more_values"=>"", "sql"=>"objects_class", "default_value"=>null, "is_null_allowed"=>true, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeEnum("test_mode", array("allowed_values"=>new ValueSetEnum('Yes,No'), "sql"=>"test_mode", "default_value"=>'No', "is_null_allowed"=>false, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeEnum("verbose_mode", array("allowed_values"=>new ValueSetEnum('Yes,No'), "sql"=>"verbose_mode", "default_value" => 'No', "is_null_allowed"=>false, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeEnum("options", array("allowed_values"=>new ValueSetEnum('Full, Update Only, Creation Only'), "sql"=>"options", "default_value"=> 'Full', "is_null_allowed"=>true, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeString("name", ["allowed_values" => null, "sql" => "name", "default_value" => "", "is_null_allowed" => false, "depends_on" => []]));
|
||||
MetaModel::Init_AddAttribute(new AttributeString("description", ["allowed_values" => null, "sql" => "description", "default_value" => "", "is_null_allowed" => true, "depends_on" => []]));
|
||||
MetaModel::Init_AddAttribute(new AttributeEnum("category", ["allowed_values" => new ValueSetEnum('Input, Ouput'), "sql" => "category", "default_value" => "Input", "is_null_allowed" => false, "depends_on" => []]));
|
||||
MetaModel::Init_AddAttribute(new AttributeEnum("source_type", ["allowed_values" => new ValueSetEnum('File, Database, Web Service'), "sql" => "source_type", "default_value" => "File", "is_null_allowed" => false, "depends_on" => []]));
|
||||
MetaModel::Init_AddAttribute(new AttributeEnum("source_subtype", ["allowed_values" => new ValueSetEnum('Oracle, MySQL, Postgress, MSSQL, SOAP, HTTP-Get, HTTP-Post, XML/RPC, CSV, XML, Excel'), "sql" => "source_subtype", "default_value" => "CSV", "is_null_allowed" => false, "depends_on" => []]));
|
||||
MetaModel::Init_AddAttribute(new AttributeString("source_path", ["allowed_values" => null, "sql" => "source_path", "default_value" => "", "is_null_allowed" => false, "depends_on" => []]));
|
||||
MetaModel::Init_AddAttribute(new AttributeClass("objects_class", ["class_category" => "", "more_values" => "", "sql" => "objects_class", "default_value" => null, "is_null_allowed" => true, "depends_on" => []]));
|
||||
MetaModel::Init_AddAttribute(new AttributeEnum("test_mode", ["allowed_values" => new ValueSetEnum('Yes,No'), "sql" => "test_mode", "default_value" => 'No', "is_null_allowed" => false, "depends_on" => []]));
|
||||
MetaModel::Init_AddAttribute(new AttributeEnum("verbose_mode", ["allowed_values" => new ValueSetEnum('Yes,No'), "sql" => "verbose_mode", "default_value" => 'No', "is_null_allowed" => false, "depends_on" => []]));
|
||||
MetaModel::Init_AddAttribute(new AttributeEnum("options", ["allowed_values" => new ValueSetEnum('Full, Update Only, Creation Only'), "sql" => "options", "default_value" => 'Full', "is_null_allowed" => true, "depends_on" => []]));
|
||||
|
||||
// Display lists
|
||||
MetaModel::Init_SetZListItems('details', array('name', 'description', 'category', 'objects_class', 'source_type', 'source_subtype', 'source_path' , 'options', 'test_mode', 'verbose_mode')); // Attributes to be displayed for the complete details
|
||||
MetaModel::Init_SetZListItems('list', array('description', 'category', 'objects_class', 'source_type', 'source_subtype', 'options')); // Attributes to be displayed for a list
|
||||
MetaModel::Init_SetZListItems('details', ['name', 'description', 'category', 'objects_class', 'source_type', 'source_subtype', 'source_path' , 'options', 'test_mode', 'verbose_mode']); // Attributes to be displayed for the complete details
|
||||
MetaModel::Init_SetZListItems('list', ['description', 'category', 'objects_class', 'source_type', 'source_subtype', 'options']); // Attributes to be displayed for a list
|
||||
// Search criteria
|
||||
MetaModel::Init_SetZListItems('standard_search', array('name', 'category', 'objects_class', 'source_type', 'source_subtype')); // Criteria of the std search form
|
||||
MetaModel::Init_SetZListItems('advanced_search', array('name', 'description', 'category', 'objects_class', 'source_type', 'source_subtype')); // Criteria of the advanced search form
|
||||
MetaModel::Init_SetZListItems('standard_search', ['name', 'category', 'objects_class', 'source_type', 'source_subtype']); // Criteria of the std search form
|
||||
MetaModel::Init_SetZListItems('advanced_search', ['name', 'description', 'category', 'objects_class', 'source_type', 'source_subtype']); // Criteria of the advanced search form
|
||||
}
|
||||
}
|
||||
?>
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @deprecated 3.0.0 will be removed in 3.1.0 - moved to sources/Application/WebPage/iTopWebPage.php, now loadable using autoloader
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
@@ -6,4 +7,4 @@
|
||||
*/
|
||||
|
||||
// cannot notify depreciation for now as this is still MASSIVELY used in iTop core !
|
||||
DeprecatedCallsLog::NotifyDeprecatedFile('moved to sources/Application/WebPage/iTopWebPage.php, now loadable using autoloader');
|
||||
DeprecatedCallsLog::NotifyDeprecatedFile('moved to sources/Application/WebPage/iTopWebPage.php, now loadable using autoloader');
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @deprecated 3.0.0 will be removed in 3.1.0 - moved to sources/Application/WebPage/iTopWizardWebPage.php, now loadable using autoloader
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
* @copyright Copyright (C) 2010-2024 Combodo SAS
|
||||
*/
|
||||
|
||||
DeprecatedCallsLog::NotifyDeprecatedFile('moved to sources/Application/WebPage/iTopWizardWebPage.php, now loadable using autoloader');
|
||||
DeprecatedCallsLog::NotifyDeprecatedFile('moved to sources/Application/WebPage/iTopWizardWebPage.php, now loadable using autoloader');
|
||||
|
||||
@@ -18,23 +18,17 @@ class LoginBasic extends AbstractLoginFSMExtension
|
||||
*/
|
||||
public function ListSupportedLoginModes()
|
||||
{
|
||||
return array('basic');
|
||||
return ['basic'];
|
||||
}
|
||||
|
||||
protected function OnModeDetection(&$iErrorCode)
|
||||
{
|
||||
if (!Session::IsSet('login_mode'))
|
||||
{
|
||||
if (isset($_SERVER['HTTP_AUTHORIZATION']) && !empty($_SERVER['HTTP_AUTHORIZATION']))
|
||||
{
|
||||
if (!Session::IsSet('login_mode')) {
|
||||
if (isset($_SERVER['HTTP_AUTHORIZATION']) && !empty($_SERVER['HTTP_AUTHORIZATION'])) {
|
||||
Session::Set('login_mode', 'basic');
|
||||
}
|
||||
elseif (isset($_SERVER['REDIRECT_HTTP_AUTHORIZATION']) && !empty($_SERVER['REDIRECT_HTTP_AUTHORIZATION']))
|
||||
{
|
||||
} elseif (isset($_SERVER['REDIRECT_HTTP_AUTHORIZATION']) && !empty($_SERVER['REDIRECT_HTTP_AUTHORIZATION'])) {
|
||||
Session::Set('login_mode', 'basic');
|
||||
}
|
||||
elseif (isset($_SERVER['PHP_AUTH_USER']))
|
||||
{
|
||||
} elseif (isset($_SERVER['PHP_AUTH_USER'])) {
|
||||
Session::Set('login_mode', 'basic');
|
||||
}
|
||||
}
|
||||
@@ -43,22 +37,18 @@ class LoginBasic extends AbstractLoginFSMExtension
|
||||
|
||||
protected function OnReadCredentials(&$iErrorCode)
|
||||
{
|
||||
if (!Session::IsSet('login_mode') || Session::Get('login_mode') == 'basic')
|
||||
{
|
||||
if (!Session::IsSet('login_mode') || Session::Get('login_mode') == 'basic') {
|
||||
list($sAuthUser) = $this->GetAuthUserAndPassword();
|
||||
Session::Set('login_temp_auth_user', $sAuthUser);
|
||||
}
|
||||
return LoginWebPage::LOGIN_FSM_CONTINUE;
|
||||
}
|
||||
|
||||
|
||||
protected function OnCheckCredentials(&$iErrorCode)
|
||||
{
|
||||
if (Session::Get('login_mode') == 'basic')
|
||||
{
|
||||
if (Session::Get('login_mode') == 'basic') {
|
||||
list($sAuthUser, $sAuthPwd) = $this->GetAuthUserAndPassword();
|
||||
if (!UserRights::CheckCredentials($sAuthUser, $sAuthPwd, Session::Get('login_mode'), 'internal'))
|
||||
{
|
||||
if (!UserRights::CheckCredentials($sAuthUser, $sAuthPwd, Session::Get('login_mode'), 'internal')) {
|
||||
$iErrorCode = LoginWebPage::EXIT_CODE_WRONGCREDENTIALS;
|
||||
return LoginWebPage::LOGIN_FSM_ERROR;
|
||||
}
|
||||
@@ -69,8 +59,7 @@ class LoginBasic extends AbstractLoginFSMExtension
|
||||
|
||||
protected function OnCredentialsOK(&$iErrorCode)
|
||||
{
|
||||
if (Session::Get('login_mode') == 'basic')
|
||||
{
|
||||
if (Session::Get('login_mode') == 'basic') {
|
||||
LoginWebPage::OnLoginSuccess(Session::Get('auth_user'), 'internal', Session::Get('login_mode'));
|
||||
}
|
||||
return LoginWebPage::LOGIN_FSM_CONTINUE;
|
||||
@@ -78,13 +67,11 @@ class LoginBasic extends AbstractLoginFSMExtension
|
||||
|
||||
protected function OnError(&$iErrorCode)
|
||||
{
|
||||
if (Session::Get('login_mode') == 'basic')
|
||||
{
|
||||
$iOnExit = LoginWebPage::getIOnExit();
|
||||
if ($iOnExit === LoginWebPage::EXIT_RETURN)
|
||||
{
|
||||
return LoginWebPage::LOGIN_FSM_RETURN; // Error, exit FSM
|
||||
}
|
||||
if (Session::Get('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;
|
||||
@@ -92,8 +79,7 @@ class LoginBasic extends AbstractLoginFSMExtension
|
||||
|
||||
protected function OnConnected(&$iErrorCode)
|
||||
{
|
||||
if (Session::Get('login_mode') == 'basic')
|
||||
{
|
||||
if (Session::Get('login_mode') == 'basic') {
|
||||
Session::Set('can_logoff', true);
|
||||
return LoginWebPage::CheckLoggedUser($iErrorCode);
|
||||
}
|
||||
@@ -105,42 +91,33 @@ class LoginBasic extends AbstractLoginFSMExtension
|
||||
$sAuthUser = '';
|
||||
$sAuthPwd = null;
|
||||
$sAuthorization = '';
|
||||
if (isset($_SERVER['HTTP_AUTHORIZATION']) && !empty($_SERVER['HTTP_AUTHORIZATION']))
|
||||
{
|
||||
if (isset($_SERVER['HTTP_AUTHORIZATION']) && !empty($_SERVER['HTTP_AUTHORIZATION'])) {
|
||||
$sAuthorization = $_SERVER['HTTP_AUTHORIZATION'];
|
||||
}
|
||||
elseif (isset($_SERVER['REDIRECT_HTTP_AUTHORIZATION']) && !empty($_SERVER['REDIRECT_HTTP_AUTHORIZATION']))
|
||||
{
|
||||
} elseif (isset($_SERVER['REDIRECT_HTTP_AUTHORIZATION']) && !empty($_SERVER['REDIRECT_HTTP_AUTHORIZATION'])) {
|
||||
$sAuthorization = $_SERVER['REDIRECT_HTTP_AUTHORIZATION'];
|
||||
}
|
||||
|
||||
if (!empty($sAuthorization))
|
||||
{
|
||||
if (!empty($sAuthorization)) {
|
||||
list($sAuthUser, $sAuthPwd) = explode(':', base64_decode(substr($sAuthorization, 6)));
|
||||
}
|
||||
else
|
||||
{
|
||||
if (isset($_SERVER['PHP_AUTH_USER']))
|
||||
{
|
||||
} else {
|
||||
if (isset($_SERVER['PHP_AUTH_USER'])) {
|
||||
$sAuthUser = $_SERVER['PHP_AUTH_USER'];
|
||||
// Unfortunately, the RFC is not clear about the encoding...
|
||||
// IE and FF supply the user and password encoded in ISO-8859-1 whereas Chrome provides them encoded in UTF-8
|
||||
// So let's try to guess if it's an UTF-8 string or not... fortunately all encodings share the same ASCII base
|
||||
if (!LoginWebPage::LooksLikeUTF8($sAuthUser))
|
||||
{
|
||||
if (!LoginWebPage::LooksLikeUTF8($sAuthUser)) {
|
||||
// Does not look like and UTF-8 string, try to convert it from iso-8859-1 to UTF-8
|
||||
// Supposed to be harmless in case of a plain ASCII string...
|
||||
$sAuthUser = iconv('iso-8859-1', 'utf-8', $sAuthUser);
|
||||
}
|
||||
$sAuthPwd = $_SERVER['PHP_AUTH_PW'];
|
||||
if (!LoginWebPage::LooksLikeUTF8($sAuthPwd))
|
||||
{
|
||||
if (!LoginWebPage::LooksLikeUTF8($sAuthPwd)) {
|
||||
// Does not look like and UTF-8 string, try to convert it from iso-8859-1 to UTF-8
|
||||
// Supposed to be harmless in case of a plain ASCII string...
|
||||
$sAuthPwd = iconv('iso-8859-1', 'utf-8', $sAuthPwd);
|
||||
}
|
||||
}
|
||||
}
|
||||
return array($sAuthUser, $sAuthPwd);
|
||||
return [$sAuthUser, $sAuthPwd];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @copyright Copyright (C) 2010-2024 Combodo SAS
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
@@ -18,7 +19,7 @@ class LoginDefaultBefore extends AbstractLoginFSMExtension
|
||||
*/
|
||||
public function ListSupportedLoginModes()
|
||||
{
|
||||
return array('before');
|
||||
return ['before'];
|
||||
}
|
||||
|
||||
protected function OnStart(&$iErrorCode)
|
||||
@@ -31,13 +32,10 @@ class LoginDefaultBefore extends AbstractLoginFSMExtension
|
||||
$aAllowedLoginTypes = MetaModel::GetConfig()->GetAllowedLoginTypes();
|
||||
$sProposedLoginMode = utils::ReadParam('login_mode', '');
|
||||
$index = array_search($sProposedLoginMode, $aAllowedLoginTypes);
|
||||
if ($index !== false)
|
||||
{
|
||||
if ($index !== false) {
|
||||
// Force login mode
|
||||
Session::Set('login_mode', $sProposedLoginMode);
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
Session::Unset('login_mode');
|
||||
}
|
||||
return LoginWebPage::LOGIN_FSM_CONTINUE;
|
||||
@@ -49,8 +47,7 @@ class LoginDefaultBefore extends AbstractLoginFSMExtension
|
||||
$aAllowedLoginTypes = MetaModel::GetConfig()->GetAllowedLoginTypes();
|
||||
$sProposedLoginMode = utils::ReadParam('login_mode', '');
|
||||
$index = array_search($sProposedLoginMode, $aAllowedLoginTypes);
|
||||
if ($index !== false)
|
||||
{
|
||||
if ($index !== false) {
|
||||
// Force login mode
|
||||
LoginWebPage::SetLoginModeAndReload($sProposedLoginMode);
|
||||
} else {
|
||||
@@ -69,8 +66,6 @@ class LoginDefaultBefore extends AbstractLoginFSMExtension
|
||||
*/
|
||||
class LoginDefaultAfter extends AbstractLoginFSMExtension implements iLogoutExtension
|
||||
{
|
||||
|
||||
|
||||
/**
|
||||
* Must be executed after the other login plugins
|
||||
*
|
||||
@@ -78,19 +73,16 @@ class LoginDefaultAfter extends AbstractLoginFSMExtension implements iLogoutExte
|
||||
*/
|
||||
public function ListSupportedLoginModes()
|
||||
{
|
||||
return array('after');
|
||||
return ['after'];
|
||||
}
|
||||
|
||||
protected function OnError(&$iErrorCode)
|
||||
{
|
||||
self::ResetLoginSession();
|
||||
$iOnExit = LoginWebPage::getIOnExit();
|
||||
if ($iOnExit === LoginWebPage::EXIT_RETURN)
|
||||
{
|
||||
if ($iOnExit === LoginWebPage::EXIT_RETURN) {
|
||||
return LoginWebPage::LOGIN_FSM_RETURN; // Error, exit FSM
|
||||
}
|
||||
elseif ($iOnExit == LoginWebPage::EXIT_HTTP_401)
|
||||
{
|
||||
} elseif ($iOnExit == LoginWebPage::EXIT_HTTP_401) {
|
||||
LoginWebPage::HTTP401Error(); // Error, exit
|
||||
}
|
||||
// LoginWebPage::EXIT_PROMPT
|
||||
@@ -99,13 +91,12 @@ class LoginDefaultAfter extends AbstractLoginFSMExtension implements iLogoutExte
|
||||
|
||||
protected function OnCredentialsOk(&$iErrorCode)
|
||||
{
|
||||
if (!Session::IsSet('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 (!Session::IsSet('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();
|
||||
@@ -125,7 +116,7 @@ class LoginDefaultAfter extends AbstractLoginFSMExtension implements iLogoutExte
|
||||
protected function OnConnected(&$iErrorCode)
|
||||
{
|
||||
Session::Unset('login_temp_auth_user');
|
||||
if (is_null(UserRights::GetUserObject())){
|
||||
if (is_null(UserRights::GetUserObject())) {
|
||||
//N°7085 avoid infinite loop
|
||||
IssueLog::Error("No user logged in. exit");
|
||||
exit(-1);
|
||||
@@ -137,10 +128,8 @@ class LoginDefaultAfter extends AbstractLoginFSMExtension implements iLogoutExte
|
||||
private static function ResetLoginSession()
|
||||
{
|
||||
LoginWebPage::ResetSession();
|
||||
foreach (Session::ListVariables() as $sKey)
|
||||
{
|
||||
if (utils::StartsWith($sKey, 'login_'))
|
||||
{
|
||||
foreach (Session::ListVariables() as $sKey) {
|
||||
if (utils::StartsWith($sKey, 'login_')) {
|
||||
Session::Unset($sKey);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,7 +11,6 @@ use Combodo\iTop\Application\Helper\Session;
|
||||
|
||||
class LoginExternal extends AbstractLoginFSMExtension
|
||||
{
|
||||
|
||||
/**
|
||||
* Return the list of supported login modes for this plugin
|
||||
*
|
||||
@@ -19,16 +18,14 @@ class LoginExternal extends AbstractLoginFSMExtension
|
||||
*/
|
||||
public function ListSupportedLoginModes()
|
||||
{
|
||||
return array('external');
|
||||
return ['external'];
|
||||
}
|
||||
|
||||
protected function OnModeDetection(&$iErrorCode)
|
||||
{
|
||||
if (!Session::IsSet('login_mode'))
|
||||
{
|
||||
if (!Session::IsSet('login_mode')) {
|
||||
$sAuthUser = $this->GetAuthUser();
|
||||
if ($sAuthUser && (strlen($sAuthUser) > 0))
|
||||
{
|
||||
if ($sAuthUser && (strlen($sAuthUser) > 0)) {
|
||||
Session::Set('login_mode', 'external');
|
||||
}
|
||||
}
|
||||
@@ -37,11 +34,9 @@ class LoginExternal extends AbstractLoginFSMExtension
|
||||
|
||||
protected function OnCheckCredentials(&$iErrorCode)
|
||||
{
|
||||
if (Session::Get('login_mode') == 'external')
|
||||
{
|
||||
if (Session::Get('login_mode') == 'external') {
|
||||
$sAuthUser = $this->GetAuthUser();
|
||||
if (!UserRights::CheckCredentials($sAuthUser, '', Session::Get('login_mode'), 'external'))
|
||||
{
|
||||
if (!UserRights::CheckCredentials($sAuthUser, '', Session::Get('login_mode'), 'external')) {
|
||||
$iErrorCode = LoginWebPage::EXIT_CODE_WRONGCREDENTIALS;
|
||||
return LoginWebPage::LOGIN_FSM_ERROR;
|
||||
}
|
||||
@@ -52,8 +47,7 @@ class LoginExternal extends AbstractLoginFSMExtension
|
||||
|
||||
protected function OnCredentialsOK(&$iErrorCode)
|
||||
{
|
||||
if (Session::Get('login_mode') == 'external')
|
||||
{
|
||||
if (Session::Get('login_mode') == 'external') {
|
||||
LoginWebPage::OnLoginSuccess(Session::Get('auth_user'), 'external', Session::Get('login_mode'));
|
||||
}
|
||||
return LoginWebPage::LOGIN_FSM_CONTINUE;
|
||||
@@ -61,8 +55,7 @@ class LoginExternal extends AbstractLoginFSMExtension
|
||||
|
||||
protected function OnConnected(&$iErrorCode)
|
||||
{
|
||||
if (Session::Get('login_mode') == 'external')
|
||||
{
|
||||
if (Session::Get('login_mode') == 'external') {
|
||||
Session::Set('can_logoff', false);
|
||||
return LoginWebPage::CheckLoggedUser($iErrorCode);
|
||||
}
|
||||
@@ -71,26 +64,21 @@ class LoginExternal extends AbstractLoginFSMExtension
|
||||
|
||||
protected function OnError(&$iErrorCode)
|
||||
{
|
||||
if (Session::Get('login_mode') == 'external')
|
||||
{
|
||||
$iOnExit = LoginWebPage::getIOnExit();
|
||||
if ($iOnExit === LoginWebPage::EXIT_RETURN)
|
||||
{
|
||||
return LoginWebPage::LOGIN_FSM_RETURN; // Error, exit FSM
|
||||
}
|
||||
if (Session::Get('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;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
* @return bool|mixed
|
||||
*/
|
||||
private function GetAuthUser()
|
||||
{
|
||||
$sExtAuthVar = MetaModel::GetConfig()->GetExternalAuthenticationVariable(); // In which variable is the info passed ?
|
||||
eval('$sAuthUser = isset('.$sExtAuthVar.') ? '.$sExtAuthVar.' : false;'); // Retrieve the value
|
||||
/** @var string $sAuthUser */
|
||||
return $sAuthUser; // Retrieve the value
|
||||
return MetaModel::GetConfig()->GetExternalAuthenticationVariable();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,7 +23,7 @@ class LoginForm extends AbstractLoginFSMExtension implements iLoginUIExtension
|
||||
*/
|
||||
public function ListSupportedLoginModes()
|
||||
{
|
||||
return array('form');
|
||||
return ['form'];
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -34,19 +34,17 @@ class LoginForm extends AbstractLoginFSMExtension implements iLoginUIExtension
|
||||
if (!Session::IsSet('login_mode') || Session::Get('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))
|
||||
{
|
||||
if (array_key_exists('HTTP_X_COMBODO_AJAX', $_SERVER))
|
||||
{
|
||||
if ($this->bForceFormOnError || empty($sAuthUser) || empty($sAuthPwd)) {
|
||||
if (array_key_exists('HTTP_X_COMBODO_AJAX', $_SERVER)) {
|
||||
// X-Combodo-Ajax is a special header automatically added to all ajax requests
|
||||
// Let's reply that we're currently logged-out
|
||||
header('HTTP/1.0 401 Unauthorized');
|
||||
exit;
|
||||
}
|
||||
|
||||
if (LoginWebPage::getIOnExit() === LoginWebPage::EXIT_RETURN) {
|
||||
return LoginWebPage::LOGIN_FSM_CONTINUE;
|
||||
}
|
||||
if (LoginWebPage::getIOnExit() === LoginWebPage::EXIT_RETURN) {
|
||||
return LoginWebPage::LOGIN_FSM_CONTINUE;
|
||||
}
|
||||
|
||||
// No credentials yet, display the form
|
||||
$oPage = LoginWebPage::NewLoginWebPage();
|
||||
@@ -66,12 +64,10 @@ class LoginForm extends AbstractLoginFSMExtension implements iLoginUIExtension
|
||||
*/
|
||||
protected function OnCheckCredentials(&$iErrorCode)
|
||||
{
|
||||
if (Session::Get('login_mode') == 'form')
|
||||
{
|
||||
if (Session::Get('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::Get('login_mode'), 'internal')) {
|
||||
$iErrorCode = LoginWebPage::EXIT_CODE_WRONGCREDENTIALS;
|
||||
return LoginWebPage::LOGIN_FSM_ERROR;
|
||||
}
|
||||
@@ -85,8 +81,7 @@ class LoginForm extends AbstractLoginFSMExtension implements iLoginUIExtension
|
||||
*/
|
||||
protected function OnCredentialsOK(&$iErrorCode)
|
||||
{
|
||||
if (Session::Get('login_mode') == 'form')
|
||||
{
|
||||
if (Session::Get('login_mode') == 'form') {
|
||||
// Store 'auth_user' in session for further use
|
||||
LoginWebPage::OnLoginSuccess(Session::Get('auth_user'), 'internal', Session::Get('login_mode'));
|
||||
}
|
||||
@@ -98,8 +93,7 @@ class LoginForm extends AbstractLoginFSMExtension implements iLoginUIExtension
|
||||
*/
|
||||
protected function OnError(&$iErrorCode)
|
||||
{
|
||||
if (Session::Get('login_mode') == 'form')
|
||||
{
|
||||
if (Session::Get('login_mode') == 'form') {
|
||||
$this->bForceFormOnError = true;
|
||||
}
|
||||
return LoginWebPage::LOGIN_FSM_CONTINUE;
|
||||
@@ -110,8 +104,7 @@ class LoginForm extends AbstractLoginFSMExtension implements iLoginUIExtension
|
||||
*/
|
||||
protected function OnConnected(&$iErrorCode)
|
||||
{
|
||||
if (Session::Get('login_mode') == 'form')
|
||||
{
|
||||
if (Session::Get('login_mode') == 'form') {
|
||||
Session::Set('can_logoff', true);
|
||||
return LoginWebPage::CheckLoggedUser($iErrorCode);
|
||||
}
|
||||
@@ -131,24 +124,23 @@ class LoginForm extends AbstractLoginFSMExtension implements iLoginUIExtension
|
||||
$sAuthUser = utils::ReadParam('auth_user', '', true, 'raw_data');
|
||||
$sAuthPwd = utils::ReadParam('suggest_pwd', '', true, 'raw_data');
|
||||
|
||||
$aData = array(
|
||||
$aData = [
|
||||
'sAuthUser' => $sAuthUser,
|
||||
'sAuthPwd' => $sAuthPwd,
|
||||
);
|
||||
];
|
||||
$oLoginContext->AddBlockExtension('login_input', new LoginBlockExtension('extensionblock/loginforminput.html.twig', $aData));
|
||||
$oLoginContext->AddBlockExtension('login_submit', new LoginBlockExtension('extensionblock/loginformsubmit.html.twig'));
|
||||
$oLoginContext->AddBlockExtension('login_form_footer', new LoginBlockExtension('extensionblock/loginformfooter.html.twig'));
|
||||
|
||||
$bEnableResetPassword = MetaModel::GetConfig()->Get('forgot_password');
|
||||
$sResetPasswordUrl = MetaModel::GetConfig()->Get('forgot_password.url');
|
||||
if ($sResetPasswordUrl == '')
|
||||
{
|
||||
$sResetPasswordUrl = utils::GetAbsoluteUrlAppRoot() . 'pages/UI.php?loginop=forgot_pwd';
|
||||
if ($sResetPasswordUrl == '') {
|
||||
$sResetPasswordUrl = utils::GetAbsoluteUrlAppRoot().'pages/UI.php?loginop=forgot_pwd';
|
||||
}
|
||||
$aData = array(
|
||||
$aData = [
|
||||
'bEnableResetPassword' => $bEnableResetPassword,
|
||||
'sResetPasswordUrl' => $sResetPasswordUrl,
|
||||
);
|
||||
];
|
||||
$oLoginContext->AddBlockExtension('login_links', new LoginBlockExtension('extensionblock/loginformlinks.html.twig', $aData));
|
||||
|
||||
return $oLoginContext;
|
||||
|
||||
@@ -6,7 +6,6 @@
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
|
||||
use Combodo\iTop\Application\Branding;
|
||||
use Combodo\iTop\Application\TwigBase\Twig\Extension;
|
||||
use Combodo\iTop\Application\WebPage\NiceWebPage;
|
||||
@@ -41,11 +40,11 @@ class LoginTwigContext
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->aBlockExtension = array();
|
||||
$this->aPostedVars = array();
|
||||
$this->aBlockExtension = [];
|
||||
$this->aPostedVars = [];
|
||||
$this->sTwigLoaderPath = null;
|
||||
$this->aCSSFiles = array();
|
||||
$this->aJsFiles = array();
|
||||
$this->aCSSFiles = [];
|
||||
$this->aJsFiles = [];
|
||||
$this->sTwigNameSpace = null;
|
||||
}
|
||||
|
||||
@@ -179,7 +178,7 @@ class LoginBlockExtension
|
||||
* @param array $aData Data given to the twig template (into the variable {{ aData }})
|
||||
* @api
|
||||
*/
|
||||
public function __construct($sTwig, $aData = array())
|
||||
public function __construct($sTwig, $aData = [])
|
||||
{
|
||||
$this->sTwig = $sTwig;
|
||||
$this->aData = $aData;
|
||||
@@ -210,21 +209,18 @@ class LoginTwigRenderer
|
||||
public function __construct()
|
||||
{
|
||||
$this->aLoginPluginList = LoginWebPage::GetLoginPluginList('iLoginUIExtension', false);
|
||||
$this->aPluginFormData = array();
|
||||
$aTwigLoaders = array();
|
||||
$this->aPostedVars = array();
|
||||
foreach ($this->aLoginPluginList as $oLoginPlugin)
|
||||
{
|
||||
$this->aPluginFormData = [];
|
||||
$aTwigLoaders = [];
|
||||
$this->aPostedVars = [];
|
||||
foreach ($this->aLoginPluginList as $oLoginPlugin) {
|
||||
/** @var \iLoginUIExtension $oLoginPlugin */
|
||||
$oLoginContext = $oLoginPlugin->GetTwigContext();
|
||||
if (is_null($oLoginContext))
|
||||
{
|
||||
if (is_null($oLoginContext)) {
|
||||
continue;
|
||||
}
|
||||
$this->aPluginFormData[] = $oLoginContext;
|
||||
$sTwigLoaderPath = $oLoginContext->GetTwigLoaderPath();
|
||||
if ($sTwigLoaderPath != null)
|
||||
{
|
||||
if ($sTwigLoaderPath != null) {
|
||||
$oExtensionLoader = new FilesystemLoader();
|
||||
$oExtensionLoader->setPaths($sTwigLoaderPath);
|
||||
$aTwigLoaders[] = $oExtensionLoader;
|
||||
@@ -232,8 +228,8 @@ class LoginTwigRenderer
|
||||
$this->aPostedVars = array_merge($this->aPostedVars, $oLoginContext->GetPostedVars());
|
||||
}
|
||||
|
||||
$oCoreLoader = new FilesystemLoader(array(), APPROOT.'templates');
|
||||
$aCoreTemplatesPaths = array('pages/login', 'pages/login/password');
|
||||
$oCoreLoader = new FilesystemLoader([], APPROOT.'templates');
|
||||
$aCoreTemplatesPaths = ['pages/login', 'pages/login/password'];
|
||||
// Having this path declared after the plugins let the plugins replace the core templates
|
||||
$oCoreLoader->setPaths($aCoreTemplatesPaths);
|
||||
// Having the core templates accessible within a different namespace offer the possibility to extend them while replacing them
|
||||
@@ -247,23 +243,20 @@ class LoginTwigRenderer
|
||||
|
||||
public function GetDefaultVars()
|
||||
{
|
||||
$sVersionShort = Dict::Format('UI:iTopVersion:Short', ITOP_APPLICATION, ITOP_VERSION);
|
||||
$sIconUrl = Utils::GetConfig()->Get('app_icon_url');
|
||||
$sDisplayIcon = Branding::GetLoginLogoAbsoluteUrl();
|
||||
|
||||
$aVars = array(
|
||||
$aVars = [
|
||||
'sAppRootUrl' => utils::GetAbsoluteUrlAppRoot(),
|
||||
'aPluginFormData' => $this->GetPluginFormData(),
|
||||
'sItopVersion' => ITOP_VERSION,
|
||||
'sVersionShort' => $sVersionShort,
|
||||
'sIconUrl' => $sIconUrl,
|
||||
'sDisplayIcon' => $sDisplayIcon,
|
||||
);
|
||||
];
|
||||
|
||||
return $aVars;
|
||||
}
|
||||
|
||||
public function Render(NiceWebPage $oPage, $sTwigFile, $aVars = array())
|
||||
public function Render(NiceWebPage $oPage, $sTwigFile, $aVars = [])
|
||||
{
|
||||
$oTemplate = $this->GetTwig()->load($sTwigFile);
|
||||
$oPage->add($oTemplate->renderBlock('body', $aVars));
|
||||
@@ -272,17 +265,14 @@ class LoginTwigRenderer
|
||||
$oPage->add_style($oTemplate->renderBlock('css', $aVars));
|
||||
|
||||
// Render CSS links
|
||||
foreach ($this->aPluginFormData as $oFormData)
|
||||
{
|
||||
foreach ($this->aPluginFormData as $oFormData) {
|
||||
/** @var \LoginTwigContext $oFormData */
|
||||
$aCSSFiles = $oFormData->GetCSSFiles();
|
||||
foreach ($aCSSFiles as $sCSSFile)
|
||||
{
|
||||
foreach ($aCSSFiles as $sCSSFile) {
|
||||
$oPage->LinkStylesheetFromURI($sCSSFile);
|
||||
}
|
||||
$aJsFiles = $oFormData->GetJsFiles();
|
||||
foreach ($aJsFiles as $sJsFile)
|
||||
{
|
||||
foreach ($aJsFiles as $sJsFile) {
|
||||
$oPage->LinkScriptFromURI($sJsFile);
|
||||
|
||||
}
|
||||
|
||||
@@ -23,17 +23,15 @@ class LoginURL extends AbstractLoginFSMExtension
|
||||
*/
|
||||
public function ListSupportedLoginModes()
|
||||
{
|
||||
return array('url');
|
||||
return ['url'];
|
||||
}
|
||||
|
||||
protected function OnModeDetection(&$iErrorCode)
|
||||
{
|
||||
if (!Session::IsSet('login_mode') && !$this->bErrorOccurred)
|
||||
{
|
||||
if (!Session::IsSet('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))
|
||||
{
|
||||
if (!empty($sAuthUser) && !empty($sAuthPwd)) {
|
||||
Session::Set('login_mode', 'url');
|
||||
}
|
||||
}
|
||||
@@ -42,8 +40,7 @@ class LoginURL extends AbstractLoginFSMExtension
|
||||
|
||||
protected function OnReadCredentials(&$iErrorCode)
|
||||
{
|
||||
if (Session::Get('login_mode') == 'url')
|
||||
{
|
||||
if (Session::Get('login_mode') == 'url') {
|
||||
Session::Set('login_temp_auth_user', utils::ReadParam('auth_user', '', false, 'raw_data'));
|
||||
}
|
||||
return LoginWebPage::LOGIN_FSM_CONTINUE;
|
||||
@@ -51,12 +48,10 @@ class LoginURL extends AbstractLoginFSMExtension
|
||||
|
||||
protected function OnCheckCredentials(&$iErrorCode)
|
||||
{
|
||||
if (Session::Get('login_mode') == 'url')
|
||||
{
|
||||
if (Session::Get('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::Get('login_mode'), 'internal')) {
|
||||
$iErrorCode = LoginWebPage::EXIT_CODE_WRONGCREDENTIALS;
|
||||
return LoginWebPage::LOGIN_FSM_ERROR;
|
||||
}
|
||||
@@ -67,8 +62,7 @@ class LoginURL extends AbstractLoginFSMExtension
|
||||
|
||||
protected function OnCredentialsOK(&$iErrorCode)
|
||||
{
|
||||
if (Session::Get('login_mode') == 'url')
|
||||
{
|
||||
if (Session::Get('login_mode') == 'url') {
|
||||
LoginWebPage::OnLoginSuccess(Session::Get('auth_user'), 'internal', Session::Get('login_mode'));
|
||||
}
|
||||
return LoginWebPage::LOGIN_FSM_CONTINUE;
|
||||
@@ -76,8 +70,7 @@ class LoginURL extends AbstractLoginFSMExtension
|
||||
|
||||
protected function OnError(&$iErrorCode)
|
||||
{
|
||||
if (Session::Get('login_mode') == 'url')
|
||||
{
|
||||
if (Session::Get('login_mode') == 'url') {
|
||||
$this->bErrorOccurred = true;
|
||||
}
|
||||
return LoginWebPage::LOGIN_FSM_CONTINUE;
|
||||
@@ -85,8 +78,7 @@ class LoginURL extends AbstractLoginFSMExtension
|
||||
|
||||
protected function OnConnected(&$iErrorCode)
|
||||
{
|
||||
if (Session::Get('login_mode') == 'url')
|
||||
{
|
||||
if (Session::Get('login_mode') == 'url') {
|
||||
Session::Set('can_logoff', true);
|
||||
return LoginWebPage::CheckLoggedUser($iErrorCode);
|
||||
}
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
<?php
|
||||
|
||||
// Copyright (C) 2010-2024 Combodo SAS
|
||||
//
|
||||
// This file is part of iTop.
|
||||
//
|
||||
// iTop is free software; you can redistribute it and/or modify
|
||||
// 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.
|
||||
@@ -16,7 +17,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/>
|
||||
|
||||
|
||||
/**
|
||||
* Class LoginWebPage
|
||||
*
|
||||
@@ -37,33 +37,33 @@ use Combodo\iTop\Service\Events\EventService;
|
||||
|
||||
class LoginWebPage extends NiceWebPage
|
||||
{
|
||||
const EXIT_PROMPT = 0;
|
||||
const EXIT_HTTP_401 = 1;
|
||||
const EXIT_RETURN = 2;
|
||||
|
||||
const EXIT_CODE_OK = 0;
|
||||
const EXIT_CODE_MISSINGLOGIN = 1;
|
||||
const EXIT_CODE_MISSINGPASSWORD = 2;
|
||||
const EXIT_CODE_WRONGCREDENTIALS = 3;
|
||||
const EXIT_CODE_MUSTBEADMIN = 4;
|
||||
const EXIT_CODE_PORTALUSERNOTAUTHORIZED = 5;
|
||||
const EXIT_CODE_NOTAUTHORIZED = 6;
|
||||
public const EXIT_PROMPT = 0;
|
||||
public const EXIT_HTTP_401 = 1;
|
||||
public const EXIT_RETURN = 2;
|
||||
|
||||
public const EXIT_CODE_OK = 0;
|
||||
public const EXIT_CODE_MISSINGLOGIN = 1;
|
||||
public const EXIT_CODE_MISSINGPASSWORD = 2;
|
||||
public const EXIT_CODE_WRONGCREDENTIALS = 3;
|
||||
public const EXIT_CODE_MUSTBEADMIN = 4;
|
||||
public const EXIT_CODE_PORTALUSERNOTAUTHORIZED = 5;
|
||||
public const EXIT_CODE_NOTAUTHORIZED = 6;
|
||||
|
||||
// Login FSM States
|
||||
const LOGIN_STATE_START = 'start'; // Entry state
|
||||
const LOGIN_STATE_MODE_DETECTION = 'login mode detection'; // Detect which login plugin to use
|
||||
const LOGIN_STATE_READ_CREDENTIALS = 'read credentials'; // Read the credentials
|
||||
const LOGIN_STATE_CHECK_CREDENTIALS = 'check credentials'; // Check if the credentials are valid
|
||||
const LOGIN_STATE_CREDENTIALS_OK = 'credentials ok'; // User provisioning
|
||||
const LOGIN_STATE_USER_OK = 'user ok'; // Additional check (2FA)
|
||||
const LOGIN_STATE_CONNECTED = 'connected'; // User connected
|
||||
const LOGIN_STATE_SET_ERROR = 'prepare for error'; // Internal state to trigger ERROR state
|
||||
const LOGIN_STATE_ERROR = 'error'; // An error occurred, next state will be NONE
|
||||
public const LOGIN_STATE_START = 'start'; // Entry state
|
||||
public const LOGIN_STATE_MODE_DETECTION = 'login mode detection'; // Detect which login plugin to use
|
||||
public const LOGIN_STATE_READ_CREDENTIALS = 'read credentials'; // Read the credentials
|
||||
public const LOGIN_STATE_CHECK_CREDENTIALS = 'check credentials'; // Check if the credentials are valid
|
||||
public const LOGIN_STATE_CREDENTIALS_OK = 'credentials ok'; // User provisioning
|
||||
public const LOGIN_STATE_USER_OK = 'user ok'; // Additional check (2FA)
|
||||
public const LOGIN_STATE_CONNECTED = 'connected'; // User connected
|
||||
public const LOGIN_STATE_SET_ERROR = 'prepare for error'; // Internal state to trigger ERROR state
|
||||
public const LOGIN_STATE_ERROR = 'error'; // An error occurred, next state will be NONE
|
||||
|
||||
// Login FSM Returns
|
||||
const LOGIN_FSM_RETURN = 0; // End the FSM OK (connected)
|
||||
const LOGIN_FSM_ERROR = 1; // Error signaled
|
||||
const LOGIN_FSM_CONTINUE = 2; // Continue FSM
|
||||
public const LOGIN_FSM_RETURN = 0; // End the FSM OK (connected)
|
||||
public const LOGIN_FSM_ERROR = 1; // Error signaled
|
||||
public const LOGIN_FSM_CONTINUE = 2; // Continue FSM
|
||||
|
||||
protected static $sHandlerClass = __class__;
|
||||
private static $iOnExit;
|
||||
@@ -78,7 +78,7 @@ class LoginWebPage extends NiceWebPage
|
||||
*/
|
||||
public static function NewLoginWebPage()
|
||||
{
|
||||
return new self::$sHandlerClass;
|
||||
return new self::$sHandlerClass();
|
||||
}
|
||||
|
||||
protected static $m_sLoginFailedMessage = '';
|
||||
@@ -94,7 +94,7 @@ class LoginWebPage extends NiceWebPage
|
||||
$this->no_cache();
|
||||
$this->add_http_headers();
|
||||
}
|
||||
|
||||
|
||||
public function SetStyleSheet()
|
||||
{
|
||||
$this->LinkStylesheetFromAppRoot('css/login.css');
|
||||
@@ -128,23 +128,18 @@ class LoginWebPage extends NiceWebPage
|
||||
$oProfilesSet = $oUser->Get('profile_list');
|
||||
//delete old profiles
|
||||
$aExistingProfiles = [];
|
||||
while ($oProfile = $oProfilesSet->Fetch())
|
||||
{
|
||||
while ($oProfile = $oProfilesSet->Fetch()) {
|
||||
array_push($aExistingProfiles, $oProfile->Get('profileid'));
|
||||
$iArrayKey = array_search($oProfile->Get('profileid'), $aProfiles);
|
||||
if (!$iArrayKey)
|
||||
{
|
||||
if (!$iArrayKey) {
|
||||
$oProfilesSet->RemoveItem($oProfile->Get('profileid'));
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
unset($aProfiles[$iArrayKey]);
|
||||
}
|
||||
}
|
||||
//add profiles not already linked with user
|
||||
foreach ($aProfiles as $iProfileId)
|
||||
{
|
||||
$oProfilesSet->AddItem(MetaModel::NewObject('URP_UserProfile', array('profileid' => $iProfileId, 'reason' => $sOrigin)));
|
||||
foreach ($aProfiles as $iProfileId) {
|
||||
$oProfilesSet->AddItem(MetaModel::NewObject('URP_UserProfile', ['profileid' => $iProfileId, 'reason' => $sOrigin]));
|
||||
}
|
||||
$oUser->Set('profile_list', $oProfilesSet);
|
||||
}
|
||||
@@ -154,56 +149,49 @@ class LoginWebPage extends NiceWebPage
|
||||
$sVersionShort = Dict::Format('UI:iTopVersion:Short', ITOP_APPLICATION, ITOP_VERSION);
|
||||
$sIconUrl = Utils::GetConfig()->Get('app_icon_url');
|
||||
$sDisplayIcon = Branding::GetLoginLogoAbsoluteUrl();
|
||||
$this->add("<div id=\"login-logo\"><a href=\"".htmlentities($sIconUrl, ENT_QUOTES,
|
||||
self::PAGES_CHARSET)."\"><img title=\"$sVersionShort\" src=\"$sDisplayIcon\"></a></div>\n");
|
||||
$this->add("<div id=\"login-logo\"><a href=\"".htmlentities(
|
||||
$sIconUrl,
|
||||
ENT_QUOTES,
|
||||
self::PAGES_CHARSET
|
||||
)."\"><img title=\"$sVersionShort\" src=\"$sDisplayIcon\"></a></div>\n");
|
||||
}
|
||||
|
||||
public function DisplayLoginForm($bFailedLogin = false)
|
||||
{
|
||||
$oTwigContext = new LoginTwigRenderer();
|
||||
$aPostedVars = array_merge(array('login_mode', 'loginop'), $oTwigContext->GetPostedVars());
|
||||
$aPostedVars = array_merge(['login_mode', 'loginop'], $oTwigContext->GetPostedVars());
|
||||
|
||||
$sMessage = Dict::S('UI:Login:IdentifyYourself');
|
||||
|
||||
// Error message
|
||||
if ($bFailedLogin)
|
||||
{
|
||||
if (self::$m_sLoginFailedMessage != '')
|
||||
{
|
||||
if ($bFailedLogin) {
|
||||
if (self::$m_sLoginFailedMessage != '') {
|
||||
$sMessage = self::$m_sLoginFailedMessage;
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
$sMessage = Dict::S('UI:Login:IncorrectLoginPassword');
|
||||
}
|
||||
}
|
||||
|
||||
// Keep the OTHER parameters posted
|
||||
$aPreviousPostedVars = array();
|
||||
foreach($_POST as $sPostedKey => $postedValue)
|
||||
{
|
||||
if (!in_array($sPostedKey, $aPostedVars))
|
||||
{
|
||||
if (is_array($postedValue))
|
||||
{
|
||||
foreach($postedValue as $sKey => $sValue)
|
||||
{
|
||||
$aPreviousPostedVars = [];
|
||||
foreach ($_POST as $sPostedKey => $postedValue) {
|
||||
if (!in_array($sPostedKey, $aPostedVars)) {
|
||||
if (is_array($postedValue)) {
|
||||
foreach ($postedValue as $sKey => $sValue) {
|
||||
$sName = "{$sPostedKey}[{$sKey}]";
|
||||
$aPreviousPostedVars[$sName] = $sValue;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
$aPreviousPostedVars[$sPostedKey] = $postedValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$aVars = array(
|
||||
$aVars = [
|
||||
'bFailedLogin' => $bFailedLogin,
|
||||
'sMessage' => $sMessage,
|
||||
'aPreviousPostedVars' => $aPreviousPostedVars,
|
||||
);
|
||||
];
|
||||
$aVars = array_merge($aVars, $oTwigContext->GetDefaultVars());
|
||||
|
||||
$oTwigContext->Render($this, 'login.html.twig', $aVars);
|
||||
@@ -226,27 +214,22 @@ class LoginWebPage extends NiceWebPage
|
||||
{
|
||||
$sAuthUser = utils::ReadParam('auth_user', '', true, 'raw_data');
|
||||
|
||||
try
|
||||
{
|
||||
try {
|
||||
UserRights::Login($sAuthUser); // Set the user's language (if possible!)
|
||||
/** @var UserInternal $oUser */
|
||||
$oUser = UserRights::GetUserObject();
|
||||
/** @var UserInternal $oUser */
|
||||
$oUser = UserRights::GetUserObject();
|
||||
|
||||
if ($oUser != null)
|
||||
{
|
||||
if (!MetaModel::IsValidAttCode(get_class($oUser), 'reset_pwd_token'))
|
||||
{
|
||||
throw new Exception(Dict::S('UI:ResetPwd-Error-NotPossible'));
|
||||
if ($oUser != null) {
|
||||
if (!MetaModel::IsValidAttCode(get_class($oUser), 'reset_pwd_token')) {
|
||||
throw new ForgotPasswordUserInputException('External accounts do not allow password reset');
|
||||
}
|
||||
if (!$oUser->CanChangePassword())
|
||||
{
|
||||
throw new Exception(Dict::S('UI:ResetPwd-Error-FixedPwd'));
|
||||
if (!$oUser->CanChangePassword()) {
|
||||
throw new ForgotPasswordUserInputException('The account does not allow password reset');
|
||||
}
|
||||
|
||||
$sTo = $oUser->GetResetPasswordEmail(); // throws Exceptions if not allowed
|
||||
if ($sTo == '')
|
||||
{
|
||||
throw new Exception(Dict::S('UI:ResetPwd-Error-NoEmail'));
|
||||
if ($sTo == '') {
|
||||
throw new ForgotPasswordUserInputException('Missing email address for this account');
|
||||
}
|
||||
|
||||
// This token allows the user to change the password without knowing the previous one
|
||||
@@ -265,28 +248,28 @@ class LoginWebPage extends NiceWebPage
|
||||
$sResetUrl = utils::GetAbsoluteUrlAppRoot().'pages/UI.php?loginop=reset_pwd&auth_user='.urlencode($oUser->Get('login')).'&token='.urlencode($sToken);
|
||||
$oEmail->SetBody(Dict::Format('UI:ResetPwd-EmailBody', $sResetUrl, $oUser->Get('login')));
|
||||
$iRes = $oEmail->Send($aIssues, true /* force synchronous exec */);
|
||||
switch ($iRes)
|
||||
{
|
||||
switch ($iRes) {
|
||||
//case EMAIL_SEND_PENDING:
|
||||
case EMAIL_SEND_OK:
|
||||
break;
|
||||
|
||||
case EMAIL_SEND_ERROR:
|
||||
default:
|
||||
IssueLog::Error('Failed to send the email with the NEW password for '.$oUser->Get('friendlyname').': '.implode(', ', $aIssues));
|
||||
throw new Exception(Dict::S('UI:ResetPwd-Error-Send'));
|
||||
throw new ForgotPasswordApplicationException('Failed to send the password reset email for '.$oUser->Get('friendlyname').': '.implode(', ', $aIssues));
|
||||
}
|
||||
}
|
||||
|
||||
} catch (ForgotPasswordApplicationException $e) {
|
||||
IssueLog::Error('Failed to process the forgot password request for user "'.$sAuthUser.'" [reason='.get_class($e).']: '.$e->getMessage());
|
||||
} catch (ForgotPasswordUserInputException $e) {
|
||||
IssueLog::Info('Failed to process the forgot password request for user "'.$sAuthUser.'" [reason='.get_class($e).']: '.$e->getMessage());
|
||||
} catch (\Throwable $e) {
|
||||
IssueLog::Error('Unexpected error while processing the forgot password request for user "'.$sAuthUser.'": '.$e->getMessage());
|
||||
}
|
||||
|
||||
$oTwigContext = new LoginTwigRenderer();
|
||||
$aVars = $oTwigContext->GetDefaultVars();
|
||||
$oTwigContext->Render($this, 'forgotpwdsent.html.twig', $aVars);
|
||||
}
|
||||
catch(Exception $e)
|
||||
{
|
||||
$this->DisplayForgotPwdForm(true, $e->getMessage());
|
||||
}
|
||||
$oTwigContext = new LoginTwigRenderer();
|
||||
$aVars = $oTwigContext->GetDefaultVars();
|
||||
$oTwigContext->Render($this, 'forgotpwdsent.html.twig', $aVars);
|
||||
}
|
||||
|
||||
public function DisplayResetPwdForm($sErrorMessage = null)
|
||||
@@ -304,22 +287,16 @@ class LoginWebPage extends NiceWebPage
|
||||
$aVars['sToken'] = $sToken;
|
||||
$aVars['sErrorMessage'] = $sErrorMessage;
|
||||
|
||||
if (($oUser == null))
|
||||
{
|
||||
if (($oUser == null)) {
|
||||
$aVars['bNoUser'] = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
$aVars['bNoUser'] = false;
|
||||
$aVars['sUserName'] = $oUser->GetFriendlyName();
|
||||
$oEncryptedToken = $oUser->Get('reset_pwd_token');
|
||||
|
||||
if (!$oEncryptedToken->CheckPassword($sToken))
|
||||
{
|
||||
if (!$oEncryptedToken->CheckPassword($sToken)) {
|
||||
$aVars['bBadToken'] = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
$aVars['bBadToken'] = false;
|
||||
}
|
||||
}
|
||||
@@ -342,21 +319,15 @@ class LoginWebPage extends NiceWebPage
|
||||
|
||||
$aVars['sAuthUser'] = $sAuthUser;
|
||||
$aVars['sToken'] = $sToken;
|
||||
if (($oUser == null))
|
||||
{
|
||||
if (($oUser == null)) {
|
||||
$aVars['bNoUser'] = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
$aVars['bNoUser'] = false;
|
||||
$oEncryptedToken = $oUser->Get('reset_pwd_token');
|
||||
|
||||
if (!$oEncryptedToken->CheckPassword($sToken))
|
||||
{
|
||||
if (!$oEncryptedToken->CheckPassword($sToken)) {
|
||||
$aVars['bBadToken'] = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
$aVars['bBadToken'] = false;
|
||||
// Trash the token and change the password
|
||||
$oUser->Set('reset_pwd_token', new ormPassword());
|
||||
@@ -413,7 +384,7 @@ class LoginWebPage extends NiceWebPage
|
||||
// Note: This will destroy the session, and not just the session data!
|
||||
}
|
||||
|
||||
static function SecureConnectionRequired()
|
||||
public static function SecureConnectionRequired()
|
||||
{
|
||||
return MetaModel::GetConfig()->GetSecureConnectionRequired();
|
||||
}
|
||||
@@ -423,7 +394,7 @@ class LoginWebPage extends NiceWebPage
|
||||
* @param string $sString
|
||||
* @return bool True if the string contains some typical UTF-8 multi-byte sequences
|
||||
*/
|
||||
static function LooksLikeUTF8($sString)
|
||||
public static function LooksLikeUTF8($sString)
|
||||
{
|
||||
return preg_match('%(?:
|
||||
[\xC2-\xDF][\x80-\xBF] # non-overlong 2-byte
|
||||
@@ -446,22 +417,19 @@ class LoginWebPage extends NiceWebPage
|
||||
protected static function Login($iOnExit)
|
||||
{
|
||||
self::$iOnExit = $iOnExit;
|
||||
if (self::SecureConnectionRequired() && !utils::IsConnectionSecure())
|
||||
{
|
||||
if (self::SecureConnectionRequired() && !utils::IsConnectionSecure()) {
|
||||
// Non secured URL... request for a secure connection
|
||||
throw new Exception('Secure connection required!');
|
||||
}
|
||||
$bLoginDebug = MetaModel::GetConfig()->Get('login_debug');
|
||||
|
||||
if (Session::Get('login_state') == self::LOGIN_STATE_ERROR)
|
||||
{
|
||||
if (Session::Get('login_state') == self::LOGIN_STATE_ERROR) {
|
||||
Session::Set('login_state', self::LOGIN_STATE_START);
|
||||
}
|
||||
$sLoginState = Session::Get('login_state');
|
||||
|
||||
$sSessionLog = '';
|
||||
if ($bLoginDebug)
|
||||
{
|
||||
if ($bLoginDebug) {
|
||||
IssueLog::Info("---------------------------------");
|
||||
IssueLog::Info($_SERVER['REQUEST_URI']);
|
||||
IssueLog::Info("--> Entering Login FSM with state: [$sLoginState]");
|
||||
@@ -472,38 +440,30 @@ class LoginWebPage extends NiceWebPage
|
||||
$iErrorCode = self::EXIT_CODE_OK;
|
||||
|
||||
// Finite state machine loop
|
||||
while (true)
|
||||
{
|
||||
try
|
||||
{
|
||||
while (true) {
|
||||
try {
|
||||
$aLoginPlugins = self::GetLoginPluginList();
|
||||
if (empty($aLoginPlugins))
|
||||
{
|
||||
if (empty($aLoginPlugins)) {
|
||||
throw new Exception("Missing login classes");
|
||||
}
|
||||
|
||||
/** @var iLoginFSMExtension $oLoginFSMExtensionInstance */
|
||||
foreach ($aLoginPlugins as $oLoginFSMExtensionInstance)
|
||||
{
|
||||
if ($bLoginDebug)
|
||||
{
|
||||
foreach ($aLoginPlugins as $oLoginFSMExtensionInstance) {
|
||||
if ($bLoginDebug) {
|
||||
$sCurrSessionLog = session_id().' '.utils::GetSessionLog();
|
||||
if ($sCurrSessionLog != $sSessionLog)
|
||||
{
|
||||
if ($sCurrSessionLog != $sSessionLog) {
|
||||
$sSessionLog = $sCurrSessionLog;
|
||||
IssueLog::Info("SESSION: $sSessionLog");
|
||||
}
|
||||
IssueLog::Info("Login: state: [$sLoginState] call: ".get_class($oLoginFSMExtensionInstance));
|
||||
}
|
||||
$iResponse = $oLoginFSMExtensionInstance->LoginAction($sLoginState, $iErrorCode);
|
||||
if ($iResponse == self::LOGIN_FSM_RETURN)
|
||||
{
|
||||
if ($iResponse == self::LOGIN_FSM_RETURN) {
|
||||
EventService::FireEvent(new EventData(EVENT_LOGIN, null, ['code' => $iErrorCode, 'state' => $sLoginState]));
|
||||
Session::WriteClose();
|
||||
return $iErrorCode; // Asked to exit FSM, generally login OK
|
||||
}
|
||||
if ($iResponse == self::LOGIN_FSM_ERROR)
|
||||
{
|
||||
if ($iResponse == self::LOGIN_FSM_ERROR) {
|
||||
EventService::FireEvent(new EventData(EVENT_LOGIN, null, ['code' => $iErrorCode, 'state' => $sLoginState]));
|
||||
$sLoginState = self::LOGIN_STATE_SET_ERROR; // Next state will be error
|
||||
// An error was detected, skip the other plugins turn
|
||||
@@ -515,9 +475,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);
|
||||
}
|
||||
catch (Exception $e)
|
||||
{
|
||||
} catch (Exception $e) {
|
||||
EventService::FireEvent(new EventData(EVENT_LOGIN, null, ['state' => $_SESSION['login_state']]));
|
||||
IssueLog::Error($e->getTraceAsString());
|
||||
static::ResetSession();
|
||||
@@ -537,30 +495,23 @@ class LoginWebPage extends NiceWebPage
|
||||
*/
|
||||
public static function GetLoginPluginList($sInterface = 'iLoginFSMExtension', $bFilterWithMode = true)
|
||||
{
|
||||
$aAllPlugins = array();
|
||||
$aAllPlugins = [];
|
||||
|
||||
if ($bFilterWithMode)
|
||||
{
|
||||
if ($bFilterWithMode) {
|
||||
$sCurrentLoginMode = Session::Get('login_mode', '');
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
$sCurrentLoginMode = '';
|
||||
}
|
||||
|
||||
/** @var iLoginExtension $oLoginExtensionInstance */
|
||||
foreach (MetaModel::EnumPlugins($sInterface) as $oLoginExtensionInstance)
|
||||
{
|
||||
foreach (MetaModel::EnumPlugins($sInterface) as $oLoginExtensionInstance) {
|
||||
$aLoginModes = $oLoginExtensionInstance->ListSupportedLoginModes();
|
||||
$aLoginModes = (is_array($aLoginModes) ? $aLoginModes : array());
|
||||
foreach ($aLoginModes as $sLoginMode)
|
||||
{
|
||||
$aLoginModes = (is_array($aLoginModes) ? $aLoginModes : []);
|
||||
foreach ($aLoginModes as $sLoginMode) {
|
||||
// Keep only the plugins for the current login mode + before + after
|
||||
if (empty($sCurrentLoginMode) || ($sLoginMode == $sCurrentLoginMode) || ($sLoginMode == 'before') || ($sLoginMode == 'after'))
|
||||
{
|
||||
if (!isset($aAllPlugins[$sLoginMode]))
|
||||
{
|
||||
$aAllPlugins[$sLoginMode] = array();
|
||||
if (empty($sCurrentLoginMode) || ($sLoginMode == $sCurrentLoginMode) || ($sLoginMode == 'before') || ($sLoginMode == 'after')) {
|
||||
if (!isset($aAllPlugins[$sLoginMode])) {
|
||||
$aAllPlugins[$sLoginMode] = [];
|
||||
}
|
||||
$aAllPlugins[$sLoginMode][] = $oLoginExtensionInstance;
|
||||
break; // Stop here to avoid registering a plugin twice
|
||||
@@ -569,12 +520,10 @@ class LoginWebPage extends NiceWebPage
|
||||
}
|
||||
|
||||
// Order and filter by the config list of allowed types (allowed_login_types)
|
||||
$aAllowedLoginModes = array_merge(array('before'), MetaModel::GetConfig()->GetAllowedLoginTypes(), array('after'));
|
||||
$aPlugins = array();
|
||||
foreach ($aAllowedLoginModes as $sAllowedMode)
|
||||
{
|
||||
if (isset($aAllPlugins[$sAllowedMode]))
|
||||
{
|
||||
$aAllowedLoginModes = array_merge(['before'], MetaModel::GetConfig()->GetAllowedLoginTypes(), ['after']);
|
||||
$aPlugins = [];
|
||||
foreach ($aAllowedLoginModes as $sAllowedMode) {
|
||||
if (isset($aAllPlugins[$sAllowedMode])) {
|
||||
$aPlugins = array_merge($aPlugins, $aAllPlugins[$sAllowedMode]);
|
||||
}
|
||||
}
|
||||
@@ -590,8 +539,7 @@ class LoginWebPage extends NiceWebPage
|
||||
*/
|
||||
private static function AdvanceLoginFSMState($sLoginState)
|
||||
{
|
||||
switch ($sLoginState)
|
||||
{
|
||||
switch ($sLoginState) {
|
||||
case self::LOGIN_STATE_START:
|
||||
return self::LOGIN_STATE_MODE_DETECTION;
|
||||
|
||||
@@ -638,8 +586,7 @@ class LoginWebPage extends NiceWebPage
|
||||
public static function CheckUser($sAuthUser, $sAuthPassword = '', $sAuthentication = 'external')
|
||||
{
|
||||
$oUser = self::FindUser($sAuthUser, true, ucfirst(strtolower($sAuthentication)));
|
||||
if (is_null($oUser))
|
||||
{
|
||||
if (is_null($oUser)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -668,8 +615,7 @@ class LoginWebPage extends NiceWebPage
|
||||
{
|
||||
// User is Ok, let's save it in the session and proceed with normal login
|
||||
$bLoginSuccess = UserRights::Login($sAuthUser, $sAuthentication); // Login & set the user's language
|
||||
if (!$bLoginSuccess)
|
||||
{
|
||||
if (!$bLoginSuccess) {
|
||||
throw new Exception("Bad user");
|
||||
}
|
||||
if (MetaModel::GetConfig()->Get('log_usage')) {
|
||||
@@ -696,12 +642,10 @@ class LoginWebPage extends NiceWebPage
|
||||
*/
|
||||
public static function CheckLoggedUser(&$iErrorCode)
|
||||
{
|
||||
if (Session::IsSet('auth_user'))
|
||||
{
|
||||
if (Session::IsSet('auth_user')) {
|
||||
// Already authenticated
|
||||
$bRet = UserRights::Login(Session::Get('auth_user')); // Login & set the user's language
|
||||
if ($bRet)
|
||||
{
|
||||
if ($bRet) {
|
||||
$iErrorCode = self::EXIT_CODE_OK;
|
||||
return self::LOGIN_FSM_RETURN;
|
||||
}
|
||||
@@ -727,8 +671,7 @@ class LoginWebPage extends NiceWebPage
|
||||
|
||||
public static function SetLoginModeAndReload($sNewLoginMode)
|
||||
{
|
||||
if (Session::Get('login_mode') == $sNewLoginMode)
|
||||
{
|
||||
if (Session::Get('login_mode') == $sNewLoginMode) {
|
||||
return;
|
||||
}
|
||||
Session::Set('login_mode', $sNewLoginMode);
|
||||
@@ -738,8 +681,7 @@ class LoginWebPage extends NiceWebPage
|
||||
public static function HTTPReload()
|
||||
{
|
||||
$sOriginURL = utils::GetCurrentAbsoluteUrl();
|
||||
if (!utils::StartsWith($sOriginURL, utils::GetAbsoluteUrlAppRoot()))
|
||||
{
|
||||
if (!utils::StartsWith($sOriginURL, utils::GetAbsoluteUrlAppRoot())) {
|
||||
// If the found URL does not start with the configured AppRoot URL
|
||||
$sOriginURL = utils::GetAbsoluteUrlAppRoot().'pages/UI.php';
|
||||
}
|
||||
@@ -753,7 +695,6 @@ class LoginWebPage extends NiceWebPage
|
||||
exit;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Provisioning API: Find a User
|
||||
*
|
||||
@@ -767,33 +708,28 @@ class LoginWebPage extends NiceWebPage
|
||||
*/
|
||||
public static function FindUser($sAuthUser, $bMustBeValid = true, $sType = 'External')
|
||||
{
|
||||
try
|
||||
{
|
||||
$aArgs = array('login' => $sAuthUser);
|
||||
try {
|
||||
$aArgs = ['login' => $sAuthUser];
|
||||
$sUserClass = "User$sType";
|
||||
$oSearch = DBObjectSearch::FromOQL("SELECT $sUserClass WHERE login = :login");
|
||||
if ($bMustBeValid)
|
||||
{
|
||||
if ($bMustBeValid) {
|
||||
$oSearch->AddCondition('status', 'enabled');
|
||||
}
|
||||
$oSet = new DBObjectSet($oSearch, array(), $aArgs);
|
||||
if ($oSet->CountExceeds(0))
|
||||
{
|
||||
$oSet = new DBObjectSet($oSearch, [], $aArgs);
|
||||
if ($oSet->CountExceeds(0)) {
|
||||
/** @var User $oUser */
|
||||
$oUser = $oSet->Fetch();
|
||||
|
||||
return $oUser;
|
||||
}
|
||||
}
|
||||
catch (Exception $e)
|
||||
{
|
||||
} catch (Exception $e) {
|
||||
IssueLog::Error($e->getMessage());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Provisioning API: Find a Person by email
|
||||
* Provisioning API: Find a Person by email
|
||||
*
|
||||
* @api
|
||||
*
|
||||
@@ -805,19 +741,15 @@ class LoginWebPage extends NiceWebPage
|
||||
{
|
||||
/** @var \Person $oPerson */
|
||||
$oPerson = null;
|
||||
try
|
||||
{
|
||||
try {
|
||||
$oSearch = new DBObjectSearch('Person');
|
||||
$oSearch->AddCondition('email', $sEmail);
|
||||
$oSet = new DBObjectSet($oSearch);
|
||||
if ($oSet->CountExceeds(1))
|
||||
{
|
||||
if ($oSet->CountExceeds(1)) {
|
||||
throw new Exception(Dict::S('UI:Login:Error:MultipleContactsHaveSameEmail'));
|
||||
}
|
||||
$oPerson = $oSet->Fetch();
|
||||
}
|
||||
catch (Exception $e)
|
||||
{
|
||||
} catch (Exception $e) {
|
||||
IssueLog::Error($e->getMessage());
|
||||
}
|
||||
return $oPerson;
|
||||
@@ -836,16 +768,14 @@ class LoginWebPage extends NiceWebPage
|
||||
*
|
||||
* @return \Person
|
||||
*/
|
||||
public static function ProvisionPerson($sFirstName, $sLastName, $sEmail, $sOrganization, $aAdditionalParams = array())
|
||||
public static function ProvisionPerson($sFirstName, $sLastName, $sEmail, $sOrganization, $aAdditionalParams = [])
|
||||
{
|
||||
/** @var Person $oPerson */
|
||||
$oPerson = null;
|
||||
try
|
||||
{
|
||||
try {
|
||||
CMDBObject::SetTrackOrigin('custom-extension');
|
||||
$sInfo = 'External User provisioning';
|
||||
if (Session::IsSet('login_mode'))
|
||||
{
|
||||
if (Session::IsSet('login_mode')) {
|
||||
$sInfo .= " (".Session::Get('login_mode').")";
|
||||
}
|
||||
CMDBObject::SetTrackInfo($sInfo);
|
||||
@@ -855,19 +785,15 @@ class LoginWebPage extends NiceWebPage
|
||||
$oPerson->Set('name', $sLastName);
|
||||
$oPerson->Set('email', $sEmail);
|
||||
$oOrg = MetaModel::GetObjectByName('Organization', $sOrganization, false);
|
||||
if (is_null($oOrg))
|
||||
{
|
||||
if (is_null($oOrg)) {
|
||||
throw new Exception(Dict::S('UI:Login:Error:WrongOrganizationName'));
|
||||
}
|
||||
$oPerson->Set('org_id', $oOrg->GetKey());
|
||||
foreach ($aAdditionalParams as $sAttCode => $sValue)
|
||||
{
|
||||
foreach ($aAdditionalParams as $sAttCode => $sValue) {
|
||||
$oPerson->Set($sAttCode, $sValue);
|
||||
}
|
||||
$oPerson->DBInsert();
|
||||
}
|
||||
catch (Exception $e)
|
||||
{
|
||||
} catch (Exception $e) {
|
||||
IssueLog::Error($e->getMessage());
|
||||
}
|
||||
return $oPerson;
|
||||
@@ -886,27 +812,23 @@ class LoginWebPage extends NiceWebPage
|
||||
*/
|
||||
public static function ProvisionUser($sAuthUser, $oPerson, $aRequestedProfiles)
|
||||
{
|
||||
if (!MetaModel::IsValidClass('URP_Profiles'))
|
||||
{
|
||||
if (!MetaModel::IsValidClass('URP_Profiles')) {
|
||||
IssueLog::Error("URP_Profiles is not a valid class. Automatic creation of Users is not supported in this context, sorry.");
|
||||
return null;
|
||||
}
|
||||
|
||||
/** @var UserExternal $oUser */
|
||||
$oUser = null;
|
||||
try
|
||||
{
|
||||
try {
|
||||
CMDBObject::SetTrackOrigin('custom-extension');
|
||||
$sInfo = 'External User provisioning';
|
||||
if (Session::IsSet('login_mode'))
|
||||
{
|
||||
if (Session::IsSet('login_mode')) {
|
||||
$sInfo .= " (".Session::Get('login_mode').")";
|
||||
}
|
||||
CMDBObject::SetTrackInfo($sInfo);
|
||||
|
||||
$oUser = MetaModel::GetObjectByName('UserExternal', $sAuthUser, false);
|
||||
if (is_null($oUser))
|
||||
{
|
||||
if (is_null($oUser)) {
|
||||
$oUser = MetaModel::NewObject('UserExternal');
|
||||
$oUser->Set('login', $sAuthUser);
|
||||
$oUser->Set('contactid', $oPerson->GetKey());
|
||||
@@ -916,41 +838,33 @@ class LoginWebPage extends NiceWebPage
|
||||
// read all the existing profiles
|
||||
$oProfilesSearch = new DBObjectSearch('URP_Profiles');
|
||||
$oProfilesSet = new DBObjectSet($oProfilesSearch);
|
||||
$aAllProfiles = array();
|
||||
while ($oProfile = $oProfilesSet->Fetch())
|
||||
{
|
||||
$aAllProfiles = [];
|
||||
while ($oProfile = $oProfilesSet->Fetch()) {
|
||||
$aAllProfiles[mb_strtolower($oProfile->GetName())] = $oProfile->GetKey();
|
||||
}
|
||||
|
||||
$aProfiles = array();
|
||||
foreach ($aRequestedProfiles as $sRequestedProfile)
|
||||
{
|
||||
$aProfiles = [];
|
||||
foreach ($aRequestedProfiles as $sRequestedProfile) {
|
||||
$sRequestedProfile = mb_strtolower($sRequestedProfile);
|
||||
if (isset($aAllProfiles[$sRequestedProfile]))
|
||||
{
|
||||
if (isset($aAllProfiles[$sRequestedProfile])) {
|
||||
$aProfiles[] = $aAllProfiles[$sRequestedProfile];
|
||||
}
|
||||
}
|
||||
|
||||
if (empty($aProfiles))
|
||||
{
|
||||
if (empty($aProfiles)) {
|
||||
throw new Exception(Dict::S('UI:Login:Error:NoValidProfiles'));
|
||||
}
|
||||
|
||||
// Now synchronize the profiles
|
||||
$sOrigin = 'External User provisioning';
|
||||
if (Session::IsSet('login_mode'))
|
||||
{
|
||||
if (Session::IsSet('login_mode')) {
|
||||
$sOrigin .= " (".Session::Get('login_mode').")";
|
||||
}
|
||||
$aExistingProfiles = self::SynchronizeProfiles($oUser, $aProfiles, $sOrigin);
|
||||
if ($oUser->IsModified())
|
||||
{
|
||||
if ($oUser->IsModified()) {
|
||||
$oUser->DBWrite();
|
||||
}
|
||||
}
|
||||
catch (Exception $e)
|
||||
{
|
||||
} catch (Exception $e) {
|
||||
IssueLog::Error($e->getMessage());
|
||||
}
|
||||
|
||||
@@ -961,26 +875,18 @@ class LoginWebPage extends NiceWebPage
|
||||
* Overridable: depending on the user, head toward a dedicated portal
|
||||
* @param string|null $sRequestedPortalId
|
||||
* @param int $iOnExit How to complete the call: redirect or return a code
|
||||
*/
|
||||
*/
|
||||
protected static function ChangeLocation($sRequestedPortalId = null, $iOnExit = self::EXIT_PROMPT)
|
||||
{
|
||||
$ret = call_user_func(array(self::$sHandlerClass, 'Dispatch'), $sRequestedPortalId);
|
||||
if ($ret === true)
|
||||
{
|
||||
$ret = call_user_func([self::$sHandlerClass, 'Dispatch'], $sRequestedPortalId);
|
||||
if ($ret === true) {
|
||||
return self::EXIT_CODE_OK;
|
||||
}
|
||||
else if($ret === false)
|
||||
{
|
||||
} elseif ($ret === false) {
|
||||
throw new Exception('Nowhere to go: Your combination of user Profiles denies you access to any '.ITOP_APPLICATION_SHORT.' portal. Please contact your administrator');
|
||||
}
|
||||
else
|
||||
{
|
||||
if ($iOnExit == self::EXIT_RETURN)
|
||||
{
|
||||
} else {
|
||||
if ($iOnExit == self::EXIT_RETURN) {
|
||||
return self::EXIT_CODE_PORTALUSERNOTAUTHORIZED;
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
// No rights to be here, redirect to the portal
|
||||
header('Location: '.$ret);
|
||||
die();
|
||||
@@ -1002,7 +908,7 @@ class LoginWebPage extends NiceWebPage
|
||||
* @return int|mixed|string
|
||||
* @throws \Exception
|
||||
*/
|
||||
static function DoLogin($bMustBeAdmin = false, $bIsAllowedToPortalUsers = false, $iOnExit = self::EXIT_PROMPT)
|
||||
public static function DoLogin($bMustBeAdmin = false, $bIsAllowedToPortalUsers = false, $iOnExit = self::EXIT_PROMPT)
|
||||
{
|
||||
$sRequestedPortalId = $bIsAllowedToPortalUsers ? 'legacy_portal' : 'backoffice';
|
||||
return self::DoLoginEx($sRequestedPortalId, $bMustBeAdmin, $iOnExit);
|
||||
@@ -1019,23 +925,18 @@ class LoginWebPage extends NiceWebPage
|
||||
* @return int|mixed|string
|
||||
* @throws \Exception
|
||||
*/
|
||||
static function DoLoginEx($sRequestedPortalId = null, $bMustBeAdmin = false, $iOnExit = self::EXIT_PROMPT)
|
||||
public static function DoLoginEx($sRequestedPortalId = null, $bMustBeAdmin = false, $iOnExit = self::EXIT_PROMPT)
|
||||
{
|
||||
$operation = utils::ReadParam('loginop', '');
|
||||
|
||||
|
||||
$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 ($iRet == self::EXIT_CODE_OK) {
|
||||
if ($bMustBeAdmin && !UserRights::IsAdministrator()) {
|
||||
if ($iOnExit == self::EXIT_RETURN) {
|
||||
return self::EXIT_CODE_MUSTBEADMIN;
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
require_once(APPROOT.'/setup/setuppage.class.inc.php');
|
||||
$oP = new ErrorPage(Dict::S('UI:PageTitle:FatalError'));
|
||||
$oP->add("<h1>".Dict::S('UI:Login:Error:AccessAdmin')."</h1>\n");
|
||||
@@ -1044,69 +945,52 @@ class LoginWebPage extends NiceWebPage
|
||||
exit;
|
||||
}
|
||||
}
|
||||
$iRet = call_user_func(array(self::$sHandlerClass, 'ChangeLocation'), $sRequestedPortalId, $iOnExit);
|
||||
$iRet = call_user_func([self::$sHandlerClass, 'ChangeLocation'], $sRequestedPortalId, $iOnExit);
|
||||
}
|
||||
if ($iOnExit == self::EXIT_RETURN)
|
||||
{
|
||||
if ($iOnExit == self::EXIT_RETURN) {
|
||||
return $iRet;
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
return $sMessage;
|
||||
}
|
||||
}
|
||||
}
|
||||
protected static function HandleOperations($operation)
|
||||
{
|
||||
$sMessage = ''; // most of the operations never return, but some can return a message to be displayed
|
||||
if ($operation == 'logoff')
|
||||
{
|
||||
if ($operation == 'logoff') {
|
||||
self::ResetSession();
|
||||
$oPage = self::NewLoginWebPage();
|
||||
$oPage->DisplayLoginForm(false /* not a failed attempt */);
|
||||
$oPage->output();
|
||||
exit;
|
||||
}
|
||||
else if ($operation == 'forgot_pwd')
|
||||
{
|
||||
} elseif ($operation == 'forgot_pwd') {
|
||||
$oPage = self::NewLoginWebPage();
|
||||
$oPage->DisplayForgotPwdForm();
|
||||
$oPage->output();
|
||||
exit;
|
||||
}
|
||||
else if ($operation == 'forgot_pwd_go')
|
||||
{
|
||||
} elseif ($operation == 'forgot_pwd_go') {
|
||||
$oPage = self::NewLoginWebPage();
|
||||
$oPage->ForgotPwdGo();
|
||||
$oPage->output();
|
||||
exit;
|
||||
}
|
||||
else if ($operation == 'reset_pwd')
|
||||
{
|
||||
} elseif ($operation == 'reset_pwd') {
|
||||
$oPage = self::NewLoginWebPage();
|
||||
$oPage->DisplayResetPwdForm();
|
||||
$oPage->output();
|
||||
exit;
|
||||
}
|
||||
else if ($operation == 'do_reset_pwd')
|
||||
{
|
||||
} elseif ($operation == 'do_reset_pwd') {
|
||||
|
||||
try {
|
||||
$oPage = self::NewLoginWebPage();
|
||||
$oPage->DoResetPassword();
|
||||
}
|
||||
catch (CoreCannotSaveObjectException $e)
|
||||
{
|
||||
} catch (CoreCannotSaveObjectException $e) {
|
||||
$oPage = self::NewLoginWebPage();
|
||||
$oPage->DisplayResetPwdForm($e->getIssue());
|
||||
}
|
||||
|
||||
$oPage->output();
|
||||
exit;
|
||||
}
|
||||
else if ($operation == 'change_pwd')
|
||||
{
|
||||
if (Session::IsSet('auth_user'))
|
||||
{
|
||||
} elseif ($operation == 'change_pwd') {
|
||||
if (Session::IsSet('auth_user')) {
|
||||
$sAuthUser = Session::Get('auth_user');
|
||||
$sIssue = Session::Get('pwd_issue');
|
||||
Session::Unset('pwd_issue');
|
||||
@@ -1118,16 +1002,13 @@ class LoginWebPage extends NiceWebPage
|
||||
$oPage->output();
|
||||
exit;
|
||||
}
|
||||
}
|
||||
else if ($operation == 'check_pwd_policy')
|
||||
{
|
||||
} elseif ($operation == 'check_pwd_policy') {
|
||||
$sAuthUser = Session::Get('auth_user');
|
||||
UserRights::Login($sAuthUser); // Set the user's language
|
||||
|
||||
$aPwdMap = array();
|
||||
$aPwdMap = [];
|
||||
|
||||
foreach (array('new_pwd', 'retype_new_pwd') as $postedPwd)
|
||||
{
|
||||
foreach (['new_pwd', 'retype_new_pwd'] as $postedPwd) {
|
||||
$oUser = new UserLocal();
|
||||
$oUser->ValidatePassword($_POST[$postedPwd]);
|
||||
|
||||
@@ -1137,27 +1018,21 @@ class LoginWebPage extends NiceWebPage
|
||||
echo json_encode($aPwdMap);
|
||||
die();
|
||||
}
|
||||
if ($operation == 'do_change_pwd')
|
||||
{
|
||||
if (Session::IsSet('auth_user'))
|
||||
{
|
||||
if ($operation == 'do_change_pwd') {
|
||||
if (Session::IsSet('auth_user')) {
|
||||
$sAuthUser = Session::Get('auth_user');
|
||||
UserRights::Login($sAuthUser); // Set the user's language
|
||||
$sOldPwd = utils::ReadPostedParam('old_pwd', '', 'raw_data');
|
||||
$sNewPwd = utils::ReadPostedParam('new_pwd', '', 'raw_data');
|
||||
|
||||
try
|
||||
{
|
||||
if (UserRights::CanChangePassword() && ((!UserRights::CheckCredentials($sAuthUser, $sOldPwd)) || (!UserRights::ChangePassword($sOldPwd, $sNewPwd))))
|
||||
{
|
||||
try {
|
||||
if (UserRights::CanChangePassword() && ((!UserRights::CheckCredentials($sAuthUser, $sOldPwd)) || (!UserRights::ChangePassword($sOldPwd, $sNewPwd)))) {
|
||||
$oPage = self::NewLoginWebPage();
|
||||
$oPage->DisplayChangePwdForm(true); // old pwd was wrong
|
||||
$oPage->output();
|
||||
exit;
|
||||
}
|
||||
}
|
||||
catch (CoreCannotSaveObjectException $e)
|
||||
{
|
||||
} catch (CoreCannotSaveObjectException $e) {
|
||||
$oPage = self::NewLoginWebPage();
|
||||
$oPage->DisplayChangePwdForm(true, $e->getIssue()); // password policy was not met.
|
||||
$oPage->output();
|
||||
@@ -1168,26 +1043,27 @@ class LoginWebPage extends NiceWebPage
|
||||
}
|
||||
return $sMessage;
|
||||
}
|
||||
|
||||
|
||||
protected static function Dispatch($sRequestedPortalId)
|
||||
{
|
||||
if ($sRequestedPortalId === null) return true; // allowed to any portal => return true
|
||||
|
||||
if ($sRequestedPortalId === null) {
|
||||
return true;
|
||||
} // allowed to any portal => return true
|
||||
|
||||
$aPortalsConf = PortalDispatcherData::GetData();
|
||||
$aDispatchers = array();
|
||||
foreach($aPortalsConf as $sPortalId => $aConf)
|
||||
{
|
||||
$aDispatchers = [];
|
||||
foreach ($aPortalsConf as $sPortalId => $aConf) {
|
||||
$sHandlerClass = $aConf['handler'];
|
||||
$aDispatchers[$sPortalId] = new $sHandlerClass($sPortalId);
|
||||
}
|
||||
|
||||
if (array_key_exists($sRequestedPortalId, $aDispatchers) && $aDispatchers[$sRequestedPortalId]->IsUserAllowed())
|
||||
{
|
||||
|
||||
if (array_key_exists($sRequestedPortalId, $aDispatchers) && $aDispatchers[$sRequestedPortalId]->IsUserAllowed()) {
|
||||
return true;
|
||||
}
|
||||
foreach($aDispatchers as $sPortalId => $oDispatcher)
|
||||
{
|
||||
if ($oDispatcher->IsUserAllowed()) return $oDispatcher->GetUrl();
|
||||
foreach ($aDispatchers as $sPortalId => $oDispatcher) {
|
||||
if ($oDispatcher->IsUserAllowed()) {
|
||||
return $oDispatcher->GetUrl();
|
||||
}
|
||||
}
|
||||
return false; // nothing matched !!
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Copyright (C) 2013-2024 Combodo SAS
|
||||
*
|
||||
@@ -17,7 +18,6 @@
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
*/
|
||||
|
||||
|
||||
//
|
||||
// Maintenance message display functions
|
||||
// Only included by approot.inc.php
|
||||
@@ -33,21 +33,17 @@ function _MaintenanceSetupPageMessage($sTitle, $sMessage)
|
||||
{
|
||||
// Web Page
|
||||
@include_once(APPROOT.'setup/setuppage.class.inc.php');
|
||||
if (class_exists('SetupPage'))
|
||||
{
|
||||
if (class_exists('SetupPage')) {
|
||||
$oP = new ErrorPage($sTitle);
|
||||
$oP->p("<h2 class=\"center\">$sMessage</h2>");
|
||||
$oP->add_ready_script(
|
||||
<<<JS
|
||||
<<<JS
|
||||
// Reload in 30s to check if maintenance is over
|
||||
setTimeout(function(){ window.location.reload(); }, 30000);
|
||||
JS
|
||||
|
||||
);
|
||||
$oP->output();
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
_MaintenanceTextMessage($sMessage);
|
||||
}
|
||||
}
|
||||
@@ -78,14 +74,13 @@ function _MaintenanceHtmlMessage($sMessage)
|
||||
*/
|
||||
function _MaintenanceJsonMessage($sTitle, $sMessage)
|
||||
{
|
||||
if (class_exists('JsonPage'))
|
||||
{
|
||||
if (class_exists('JsonPage')) {
|
||||
$oP = new JsonPage($sTitle);
|
||||
$oP->add_header('Access-Control-Allow-Origin: *');
|
||||
|
||||
$aMessage = [
|
||||
'code' => 100,
|
||||
'message' =>$sMessage
|
||||
'message' => $sMessage,
|
||||
];
|
||||
|
||||
$oP->AddData($aMessage);
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* @copyright Copyright (C) 2010-2024 Combodo SAS
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
@@ -13,7 +14,6 @@ require_once(APPROOT.'/application/utils.inc.php');
|
||||
require_once(APPROOT.'/application/template.class.inc.php');
|
||||
require_once(APPROOT."/application/user.dashboard.class.inc.php");
|
||||
|
||||
|
||||
/**
|
||||
* This class manipulates, stores and displays the navigation menu used in the application
|
||||
* In order to improve the modularity of the data model and to ease the update/migration
|
||||
@@ -52,43 +52,40 @@ class ApplicationMenu
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
static $bAdditionalMenusLoaded = false;
|
||||
public static $bAdditionalMenusLoaded = false;
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
static $aRootMenus = array();
|
||||
public static $aRootMenus = [];
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
static $aMenusIndex = array();
|
||||
public static $aMenusIndex = [];
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
static $aMenusById = [];
|
||||
public static $aMenusById = [];
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
static $sFavoriteSiloQuery = 'SELECT Organization';
|
||||
public static $sFavoriteSiloQuery = 'SELECT Organization';
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public static function LoadAdditionalMenus()
|
||||
{
|
||||
if (!self::$bAdditionalMenusLoaded)
|
||||
{
|
||||
if (!self::$bAdditionalMenusLoaded) {
|
||||
// Build menus from module handlers
|
||||
//
|
||||
/** @var \ModuleHandlerApiInterface $oPHPClass */
|
||||
foreach(MetaModel::EnumPlugins('ModuleHandlerApiInterface') as $oPHPClass)
|
||||
{
|
||||
$oPHPClass::OnMenuCreation();
|
||||
}
|
||||
foreach (MetaModel::EnumPlugins('ModuleHandlerApiInterface') as $oPHPClass) {
|
||||
$oPHPClass::OnMenuCreation();
|
||||
}
|
||||
|
||||
// Build menus from the menus themselves (e.g. the ShortcutContainerMenuNode will do that)
|
||||
//
|
||||
foreach(self::$aRootMenus as $aMenu)
|
||||
{
|
||||
foreach (self::$aRootMenus as $aMenu) {
|
||||
$oMenuNode = self::GetMenuNode($aMenu['index']);
|
||||
$oMenuNode->PopulateChildMenus();
|
||||
}
|
||||
@@ -125,8 +122,7 @@ class ApplicationMenu
|
||||
*/
|
||||
public static function CheckMenuIdEnabled($sMenuId)
|
||||
{
|
||||
if (self::IsMenuIdEnabled($sMenuId) === false)
|
||||
{
|
||||
if (self::IsMenuIdEnabled($sMenuId) === false) {
|
||||
require_once(APPROOT.'/setup/setuppage.class.inc.php');
|
||||
$oP = new ErrorPage(Dict::S('UI:PageTitle:FatalError'));
|
||||
$oP->add("<h1>".Dict::S('UI:Login:Error:AccessRestricted')."</h1>\n");
|
||||
@@ -142,7 +138,7 @@ class ApplicationMenu
|
||||
* @return bool true if the menu exists and current user is allowed to see the menu
|
||||
* @since 3.2.0
|
||||
*/
|
||||
public static function IsMenuIdEnabled($sMenuId):bool
|
||||
public static function IsMenuIdEnabled($sMenuId): bool
|
||||
{
|
||||
self::LoadAdditionalMenus();
|
||||
$oMenuNode = self::GetMenuNode(self::GetMenuIndexById($sMenuId));
|
||||
@@ -160,22 +156,18 @@ class ApplicationMenu
|
||||
public static function InsertMenu(MenuNode $oMenuNode, $iParentIndex, $fRank)
|
||||
{
|
||||
$index = self::GetMenuIndexById($oMenuNode->GetMenuId());
|
||||
if ($index == -1)
|
||||
{
|
||||
if ($index == -1) {
|
||||
// The menu does not already exist, insert it
|
||||
$index = count(self::$aMenusIndex);
|
||||
|
||||
if ($iParentIndex == -1)
|
||||
{
|
||||
if ($iParentIndex == -1) {
|
||||
$sParentId = '';
|
||||
self::$aRootMenus[] = array ('rank' => $fRank, 'index' => $index);
|
||||
}
|
||||
else
|
||||
{
|
||||
self::$aRootMenus[] = ['rank' => $fRank, 'index' => $index];
|
||||
} else {
|
||||
/** @var \MenuNode $oNode */
|
||||
$oNode = self::$aMenusIndex[$iParentIndex]['node'];
|
||||
$sParentId = $oNode->GetMenuId();
|
||||
self::$aMenusIndex[$iParentIndex]['children'][] = array ('rank' => $fRank, 'index' => $index);
|
||||
self::$aMenusIndex[$iParentIndex]['children'][] = ['rank' => $fRank, 'index' => $index];
|
||||
}
|
||||
|
||||
// Note: At the time when 'parent', 'rank' and 'source_file' have been added for the reflection API,
|
||||
@@ -183,11 +175,9 @@ 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::$aMenusIndex[$index] = ['node' => $oMenuNode, 'children' => [], 'parent' => $sParentId, 'rank' => $fRank, 'source_file' => $sFile];
|
||||
self::$aMenusById[$oMenuNode->GetMenuId()] = $index;
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
// the menu already exists, let's combine the conditions that make it visible
|
||||
/** @var \MenuNode $oNode */
|
||||
$oNode = self::$aMenusIndex[$index]['node'];
|
||||
@@ -217,7 +207,7 @@ class ApplicationMenu
|
||||
* @throws \DictExceptionMissingString
|
||||
* @since 3.0.0
|
||||
*/
|
||||
public static function GetMenusCount($aExtraParams = array())
|
||||
public static function GetMenusCount($aExtraParams = [])
|
||||
{
|
||||
$aMenuGroups = static::GetMenuGroups($aExtraParams);
|
||||
|
||||
@@ -260,18 +250,16 @@ class ApplicationMenu
|
||||
* @throws \DictExceptionMissingString
|
||||
* @since 3.0.0
|
||||
*/
|
||||
public static function GetMenuGroups($aExtraParams = array())
|
||||
public static function GetMenuGroups($aExtraParams = [])
|
||||
{
|
||||
self::LoadAdditionalMenus();
|
||||
|
||||
// Sort the root menu based on the rank
|
||||
usort(self::$aRootMenus, array('ApplicationMenu', 'CompareOnRank'));
|
||||
usort(self::$aRootMenus, ['ApplicationMenu', 'CompareOnRank']);
|
||||
|
||||
$aMenuGroups = [];
|
||||
foreach(static::$aRootMenus as $aMenuGroup)
|
||||
{
|
||||
if(!static::CanDisplayMenu($aMenuGroup))
|
||||
{
|
||||
foreach (static::$aRootMenus as $aMenuGroup) {
|
||||
if (!static::CanDisplayMenu($aMenuGroup)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -322,26 +310,23 @@ class ApplicationMenu
|
||||
* @throws \Exception
|
||||
* @since 3.0.0
|
||||
*/
|
||||
public static function GetSubMenuNodes($sMenuGroupIdx, $aExtraParams = array())
|
||||
public static function GetSubMenuNodes($sMenuGroupIdx, $aExtraParams = [])
|
||||
{
|
||||
$aSubMenuItems = self::GetChildren($sMenuGroupIdx);
|
||||
|
||||
// Sort the children based on the rank
|
||||
usort($aSubMenuItems, array('ApplicationMenu', 'CompareOnRank'));
|
||||
usort($aSubMenuItems, ['ApplicationMenu', 'CompareOnRank']);
|
||||
|
||||
$aSubMenuNodes = [];
|
||||
foreach($aSubMenuItems as $aSubMenuItem)
|
||||
{
|
||||
if(!static::CanDisplayMenu($aSubMenuItem))
|
||||
{
|
||||
foreach ($aSubMenuItems as $aSubMenuItem) {
|
||||
if (!static::CanDisplayMenu($aSubMenuItem)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$sSubMenuItemIdx = $aSubMenuItem['index'];
|
||||
$oSubMenuNode = static::GetMenuNode($sSubMenuItemIdx);
|
||||
|
||||
if(!$oSubMenuNode->IsEnabled())
|
||||
{
|
||||
if (!$oSubMenuNode->IsEnabled()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -372,7 +357,7 @@ class ApplicationMenu
|
||||
DeprecatedCallsLog::NotifyDeprecatedPhpMethod('use static::GetMenuGroups() instead');
|
||||
self::LoadAdditionalMenus();
|
||||
// Sort the root menu based on the rank
|
||||
usort(self::$aRootMenus, array('ApplicationMenu', 'CompareOnRank'));
|
||||
usort(self::$aRootMenus, ['ApplicationMenu', 'CompareOnRank']);
|
||||
$iAccordion = 0;
|
||||
$iActiveAccordion = $iAccordion;
|
||||
$iActiveMenu = self::GetMenuIndexById(self::GetActiveNodeId());
|
||||
@@ -387,8 +372,7 @@ class ApplicationMenu
|
||||
$aChildren = self::GetChildren($aMenu['index']);
|
||||
$bActive = self::DisplaySubMenu($oPage, $aChildren, $aExtraParams, $iActiveMenu);
|
||||
$oPage->AddToMenu('</ul>');
|
||||
if ($bActive)
|
||||
{
|
||||
if ($bActive) {
|
||||
$iActiveAccordion = $iAccordion;
|
||||
}
|
||||
$oPage->AddToMenu('</div>');
|
||||
@@ -396,7 +380,7 @@ class ApplicationMenu
|
||||
}
|
||||
|
||||
$oPage->add_ready_script(
|
||||
<<<EOF
|
||||
<<<EOF
|
||||
// Accordion Menu
|
||||
$("#accordion").css({display:'block'}).accordion({ header: "h3", heightStyle: "content", collapsible: true, active: $iActiveAccordion, icons: false, animate: true }); // collapsible will be enabled once the item will be selected
|
||||
EOF
|
||||
@@ -411,21 +395,15 @@ EOF
|
||||
private static function CanDisplayMenu($aMenu)
|
||||
{
|
||||
$oMenuNode = self::GetMenuNode($aMenu['index']);
|
||||
if ($oMenuNode->IsEnabled())
|
||||
{
|
||||
if ($oMenuNode->IsEnabled()) {
|
||||
$aChildren = self::GetChildren($aMenu['index']);
|
||||
if (count($aChildren) > 0)
|
||||
{
|
||||
foreach($aChildren as $aSubMenu)
|
||||
{
|
||||
if (self::CanDisplayMenu($aSubMenu))
|
||||
{
|
||||
if (count($aChildren) > 0) {
|
||||
foreach ($aChildren as $aSubMenu) {
|
||||
if (self::CanDisplayMenu($aSubMenu)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -450,46 +428,38 @@ EOF
|
||||
DeprecatedCallsLog::NotifyDeprecatedPhpMethod('use static::GetSubMenuNodes() instead');
|
||||
// Sort the menu based on the rank
|
||||
$bActive = false;
|
||||
usort($aMenus, array('ApplicationMenu', 'CompareOnRank'));
|
||||
usort($aMenus, ['ApplicationMenu', 'CompareOnRank']);
|
||||
foreach ($aMenus as $aMenu) {
|
||||
if (!self::CanDisplayMenu($aMenu)) {
|
||||
continue;
|
||||
}
|
||||
$index = $aMenu['index'];
|
||||
$oMenu = self::GetMenuNode($index);
|
||||
if ($oMenu->IsEnabled())
|
||||
{
|
||||
if ($oMenu->IsEnabled()) {
|
||||
$aChildren = self::GetChildren($index);
|
||||
$aCSSClasses = array('navigation-menu-item');
|
||||
if (count($aChildren) > 0)
|
||||
{
|
||||
$aCSSClasses = ['navigation-menu-item'];
|
||||
if (count($aChildren) > 0) {
|
||||
$aCSSClasses[] = 'submenu';
|
||||
}
|
||||
$sHyperlink = $oMenu->GetHyperlink($aExtraParams);
|
||||
$sItemHtml = '<li id="'.utils::GetSafeId('AccordionMenu_'.$oMenu->GetMenuID()).'" class="'.implode(' ', $aCSSClasses).'" data-menu-id="'.$oMenu->GetMenuID().'">';
|
||||
if ($sHyperlink != '')
|
||||
{
|
||||
if ($sHyperlink != '') {
|
||||
$sLinkTarget = '';
|
||||
if ($oMenu->IsHyperLinkInNewWindow())
|
||||
{
|
||||
if ($oMenu->IsHyperLinkInNewWindow()) {
|
||||
$sLinkTarget .= ' target="_blank"';
|
||||
}
|
||||
$sURL = '"'.$oMenu->GetHyperlink($aExtraParams).'"'.$sLinkTarget;
|
||||
$sTitle = utils::HtmlEntities($oMenu->GetTitle());
|
||||
$sItemHtml .= "<a href={$sURL}>{$sTitle}</a>";
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
$sItemHtml .= $oMenu->GetTitle();
|
||||
}
|
||||
$sItemHtml .= '</li>';
|
||||
$oPage->AddToMenu($sItemHtml);
|
||||
if ($iActiveMenu == $index)
|
||||
{
|
||||
if ($iActiveMenu == $index) {
|
||||
$bActive = true;
|
||||
}
|
||||
if (count($aChildren) > 0)
|
||||
{
|
||||
if (count($aChildren) > 0) {
|
||||
$oPage->AddToMenu('<ul>');
|
||||
$bActive |= self::DisplaySubMenu($oPage, $aChildren, $aExtraParams, $iActiveMenu);
|
||||
$oPage->AddToMenu('</ul>');
|
||||
@@ -508,12 +478,10 @@ EOF
|
||||
public static function CompareOnRank($a, $b)
|
||||
{
|
||||
$result = 1;
|
||||
if ($a['rank'] == $b['rank'])
|
||||
{
|
||||
if ($a['rank'] == $b['rank']) {
|
||||
$result = 0;
|
||||
}
|
||||
if ($a['rank'] < $b['rank'])
|
||||
{
|
||||
if ($a['rank'] < $b['rank']) {
|
||||
$result = -1;
|
||||
}
|
||||
return $result;
|
||||
@@ -561,8 +529,7 @@ EOF
|
||||
{
|
||||
$oAppContext = new ApplicationContext();
|
||||
$sMenuId = $oAppContext->GetCurrentValue('menu', null);
|
||||
if ($sMenuId === null)
|
||||
{
|
||||
if ($sMenuId === null) {
|
||||
$sMenuId = self::GetDefaultMenuId();
|
||||
}
|
||||
return $sMenuId;
|
||||
@@ -574,13 +541,12 @@ EOF
|
||||
public static function GetDefaultMenuId()
|
||||
{
|
||||
static $sDefaultMenuId = null;
|
||||
if (is_null($sDefaultMenuId))
|
||||
{
|
||||
if (is_null($sDefaultMenuId)) {
|
||||
// Make sure the root menu is sorted on 'rank'
|
||||
usort(self::$aRootMenus, array('ApplicationMenu', 'CompareOnRank'));
|
||||
usort(self::$aRootMenus, ['ApplicationMenu', 'CompareOnRank']);
|
||||
$oFirstGroup = self::GetMenuNode(self::$aRootMenus[0]['index']);
|
||||
$aChildren = self::$aMenusIndex[$oFirstGroup->GetIndex()]['children'];
|
||||
usort($aChildren, array('ApplicationMenu', 'CompareOnRank'));
|
||||
usort($aChildren, ['ApplicationMenu', 'CompareOnRank']);
|
||||
$oMenuNode = self::GetMenuNode($aChildren[0]['index']);
|
||||
$sDefaultMenuId = $oMenuNode->GetMenuId();
|
||||
}
|
||||
@@ -594,13 +560,11 @@ EOF
|
||||
public static function GetRootMenuId($sMenuId)
|
||||
{
|
||||
$iMenuIndex = self::GetMenuIndexById($sMenuId);
|
||||
if ($iMenuIndex == -1)
|
||||
{
|
||||
if ($iMenuIndex == -1) {
|
||||
return '';
|
||||
}
|
||||
$oMenu = ApplicationMenu::GetMenuNode($iMenuIndex);
|
||||
while ($oMenu->GetParentIndex() != -1)
|
||||
{
|
||||
while ($oMenu->GetParentIndex() != -1) {
|
||||
$oMenu = ApplicationMenu::GetMenuNode($oMenu->GetParentIndex());
|
||||
}
|
||||
return $oMenu->GetMenuId();
|
||||
@@ -687,17 +651,17 @@ abstract class MenuNode
|
||||
{
|
||||
$this->sMenuId = $sMenuId;
|
||||
$this->iParentIndex = $iParentIndex;
|
||||
$this->aReflectionProperties = array();
|
||||
$this->aReflectionProperties = [];
|
||||
if (utils::IsNotNullOrEmptyString($sEnableClass)) {
|
||||
$this->aReflectionProperties['enable_class'] = $sEnableClass;
|
||||
$this->aReflectionProperties['enable_action'] = $iActionCode;
|
||||
$this->aReflectionProperties['enable_permission'] = $iAllowedResults;
|
||||
$this->aReflectionProperties['enable_stimulus'] = $sEnableStimulus;
|
||||
}
|
||||
$this->m_aEnableClasses = array($sEnableClass);
|
||||
$this->m_aEnableActions = array($iActionCode);
|
||||
$this->m_aEnableActionResults = array($iAllowedResults);
|
||||
$this->m_aEnableStimuli = array($sEnableStimulus);
|
||||
$this->m_aEnableClasses = [$sEnableClass];
|
||||
$this->m_aEnableActions = [$iActionCode];
|
||||
$this->m_aEnableActionResults = [$iAllowedResults];
|
||||
$this->m_aEnableStimuli = [$sEnableStimulus];
|
||||
$this->index = ApplicationMenu::InsertMenu($this, $iParentIndex, $fRank);
|
||||
}
|
||||
|
||||
@@ -751,7 +715,6 @@ abstract class MenuNode
|
||||
$oSearch->SetShowObsoleteData(utils::ShowObsoleteData());
|
||||
DBSearchHelper::AddContextFilter($oSearch);
|
||||
|
||||
|
||||
$oSet = new DBObjectSet($oSearch);
|
||||
$iCount = $oSet->CountWithLimit(99);
|
||||
if ($iCount > 99) {
|
||||
@@ -802,8 +765,7 @@ abstract class MenuNode
|
||||
*/
|
||||
public function PopulateChildMenus()
|
||||
{
|
||||
foreach (ApplicationMenu::GetChildren($this->GetIndex()) as $aMenu)
|
||||
{
|
||||
foreach (ApplicationMenu::GetChildren($this->GetIndex()) as $aMenu) {
|
||||
$index = $aMenu['index'];
|
||||
$oMenu = ApplicationMenu::GetMenuNode($index);
|
||||
$oMenu->PopulateChildMenus();
|
||||
@@ -838,8 +800,7 @@ abstract class MenuNode
|
||||
*/
|
||||
public function AddCondition(MenuNode $oMenuNode)
|
||||
{
|
||||
foreach($oMenuNode->m_aEnableClasses as $index => $sClass )
|
||||
{
|
||||
foreach ($oMenuNode->m_aEnableClasses as $index => $sClass) {
|
||||
$this->m_aEnableClasses[] = $sClass;
|
||||
$this->m_aEnableActions[] = $oMenuNode->m_aEnableActions[$index];
|
||||
$this->m_aEnableActionResults[] = $oMenuNode->m_aEnableActionResults[$index];
|
||||
@@ -852,33 +813,24 @@ abstract class MenuNode
|
||||
*/
|
||||
public function IsEnabled()
|
||||
{
|
||||
foreach($this->m_aEnableClasses as $index => $sClass)
|
||||
{
|
||||
if ($sClass != null)
|
||||
{
|
||||
if (MetaModel::IsValidClass($sClass))
|
||||
{
|
||||
if ($this->m_aEnableStimuli[$index] != null)
|
||||
{
|
||||
if (!UserRights::IsStimulusAllowed($sClass, $this->m_aEnableStimuli[$index]))
|
||||
{
|
||||
foreach ($this->m_aEnableClasses as $index => $sClass) {
|
||||
if ($sClass != null) {
|
||||
if (MetaModel::IsValidClass($sClass)) {
|
||||
if ($this->m_aEnableStimuli[$index] != null) {
|
||||
if (!UserRights::IsStimulusAllowed($sClass, $this->m_aEnableStimuli[$index])) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if ($this->m_aEnableActions[$index] != null)
|
||||
{
|
||||
if ($this->m_aEnableActions[$index] != null) {
|
||||
// Menus access rights ignore the archive mode
|
||||
utils::PushArchiveMode(false);
|
||||
$iResult = UserRights::IsActionAllowed($sClass, $this->m_aEnableActions[$index]);
|
||||
utils::PopArchiveMode();
|
||||
if (!($iResult & $this->m_aEnableActionResults[$index]))
|
||||
{
|
||||
if (!($iResult & $this->m_aEnableActionResults[$index])) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -891,7 +843,7 @@ abstract class MenuNode
|
||||
* @param array $aExtraParams
|
||||
* @return mixed
|
||||
*/
|
||||
public abstract function RenderContent(WebPage $oPage, $aExtraParams = array());
|
||||
abstract public function RenderContent(WebPage $oPage, $aExtraParams = []);
|
||||
|
||||
/**
|
||||
* @param string $sHyperlink
|
||||
@@ -900,16 +852,13 @@ abstract class MenuNode
|
||||
*/
|
||||
protected function AddParams($sHyperlink, $aExtraParams)
|
||||
{
|
||||
if (count($aExtraParams) > 0)
|
||||
{
|
||||
$aQuery = array();
|
||||
if (count($aExtraParams) > 0) {
|
||||
$aQuery = [];
|
||||
$sSeparator = '?';
|
||||
if (strpos($sHyperlink, '?') !== false)
|
||||
{
|
||||
if (strpos($sHyperlink, '?') !== false) {
|
||||
$sSeparator = '&';
|
||||
}
|
||||
foreach($aExtraParams as $sName => $sValue)
|
||||
{
|
||||
foreach ($aExtraParams as $sName => $sValue) {
|
||||
$aQuery[] = urlencode($sName).'='.urlencode($sValue);
|
||||
}
|
||||
$sHyperlink .= $sSeparator.implode('&', $aQuery);
|
||||
@@ -925,7 +874,7 @@ 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;
|
||||
public const DEFAULT_DECORATION_CLASSES = null;
|
||||
|
||||
/** @var string The CSS classes used to display the menu group's icon */
|
||||
protected $sDecorationClasses = self::DEFAULT_DECORATION_CLASSES;
|
||||
@@ -945,8 +894,7 @@ class MenuGroup extends MenuNode
|
||||
{
|
||||
parent::__construct($sMenuId, -1 /* no parent, groups are at root level */, $fRank, $sEnableClass, $iActionCode, $iAllowedResults, $sEnableStimulus);
|
||||
|
||||
if(!empty($sDecorationClasses))
|
||||
{
|
||||
if (!empty($sDecorationClasses)) {
|
||||
$this->sDecorationClasses = $sDecorationClasses;
|
||||
}
|
||||
}
|
||||
@@ -987,7 +935,7 @@ class MenuGroup extends MenuNode
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function RenderContent(WebPage $oPage, $aExtraParams = array())
|
||||
public function RenderContent(WebPage $oPage, $aExtraParams = [])
|
||||
{
|
||||
assert(false); // Shall never be called, groups do not display any content
|
||||
}
|
||||
@@ -1027,7 +975,9 @@ class TemplateMenuNode extends MenuNode
|
||||
*/
|
||||
public function GetHyperlink($aExtraParams)
|
||||
{
|
||||
if ($this->sTemplateFile == '') return '';
|
||||
if ($this->sTemplateFile == '') {
|
||||
return '';
|
||||
}
|
||||
return parent::GetHyperlink($aExtraParams);
|
||||
}
|
||||
|
||||
@@ -1035,18 +985,15 @@ class TemplateMenuNode extends MenuNode
|
||||
* @inheritDoc
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function RenderContent(WebPage $oPage, $aExtraParams = array())
|
||||
public function RenderContent(WebPage $oPage, $aExtraParams = [])
|
||||
{
|
||||
ApplicationMenu::CheckMenuIdEnabled($this->GetMenuId());
|
||||
$sTemplate = @file_get_contents($this->sTemplateFile);
|
||||
if ($sTemplate !== false)
|
||||
{
|
||||
if ($sTemplate !== false) {
|
||||
$aExtraParams['table_id'] = 'Menu_'.$this->GetMenuId();
|
||||
$oTemplate = new DisplayTemplate($sTemplate);
|
||||
$oTemplate->Render($oPage, $aExtraParams);
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
$oPage->p("Error: failed to load template file: '{$this->sTemplateFile}'"); // No need to translate ?
|
||||
}
|
||||
}
|
||||
@@ -1080,7 +1027,6 @@ class OQLMenuNode extends MenuNode
|
||||
*/
|
||||
protected $m_aParams;
|
||||
|
||||
|
||||
/**
|
||||
* Create a menu item based on an OQL query 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)
|
||||
@@ -1101,7 +1047,7 @@ class OQLMenuNode extends MenuNode
|
||||
$this->sOQL = $sOQL;
|
||||
$this->bSearch = $bSearch;
|
||||
$this->bSearchFormOpen = $bSearchFormOpen;
|
||||
$this->m_aParams = array();
|
||||
$this->m_aParams = [];
|
||||
$this->aReflectionProperties['oql'] = $sOQL;
|
||||
$this->aReflectionProperties['do_search'] = $bSearch;
|
||||
// Enhancement: we could set as the "enable" condition that the user has enough rights to "read" the objects
|
||||
@@ -1115,8 +1061,7 @@ class OQLMenuNode extends MenuNode
|
||||
public function SetParameters($aParams)
|
||||
{
|
||||
$this->m_aParams = $aParams;
|
||||
foreach($aParams as $sKey => $value)
|
||||
{
|
||||
foreach ($aParams as $sKey => $value) {
|
||||
$this->aReflectionProperties[$sKey] = $value;
|
||||
}
|
||||
}
|
||||
@@ -1125,12 +1070,11 @@ class OQLMenuNode extends MenuNode
|
||||
* @inheritDoc
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function RenderContent(WebPage $oPage, $aExtraParams = array())
|
||||
public function RenderContent(WebPage $oPage, $aExtraParams = [])
|
||||
{
|
||||
$oTag = new ContextTag(ContextTag::TAG_OBJECT_SEARCH);
|
||||
ApplicationMenu::CheckMenuIdEnabled($this->GetMenuId());
|
||||
OQLMenuNode::RenderOQLSearch
|
||||
(
|
||||
OQLMenuNode::RenderOQLSearch(
|
||||
$this->sOQL,
|
||||
Dict::S($this->sPageTitle),
|
||||
'Menu_'.$this->GetMenuId(),
|
||||
@@ -1155,26 +1099,25 @@ class OQLMenuNode extends MenuNode
|
||||
* @throws DictExceptionMissingString
|
||||
* @throws OQLException
|
||||
*/
|
||||
public static function RenderOQLSearch($sOql, $sTitle, $sUsageId, $bSearchPane, $bSearchOpen, WebPage $oPage, $aExtraParams = array(), $bEnableBreadcrumb = false)
|
||||
public static function RenderOQLSearch($sOql, $sTitle, $sUsageId, $bSearchPane, $bSearchOpen, WebPage $oPage, $aExtraParams = [], $bEnableBreadcrumb = false)
|
||||
{
|
||||
$sUsageId = utils::GetSafeId($sUsageId);
|
||||
$oSearch = DBObjectSearch::FromOQL($sOql);
|
||||
$sClass= $oSearch->GetClass();
|
||||
$sClass = $oSearch->GetClass();
|
||||
$sIcon = MetaModel::GetClassIcon($sClass, false);
|
||||
if ($bSearchPane) {
|
||||
$aParams = array_merge(['open' => $bSearchOpen, 'table_id' => $sUsageId, 'submit_on_load' => false], $aExtraParams);
|
||||
$oBlock = new DisplayBlock($oSearch, DisplayBlock::ENUM_STYLE_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 {
|
||||
} else {
|
||||
$oPage->add("<div class='sf_results_area' data-target='search_results'>");
|
||||
}
|
||||
$aExtraParams['panel_class'] =$sClass;
|
||||
$aExtraParams['panel_class'] = $sClass;
|
||||
$aExtraParams['panel_title'] = $sTitle;
|
||||
$aExtraParams['panel_icon'] = $sIcon;
|
||||
|
||||
$aParams = array_merge(array('table_id' => $sUsageId), $aExtraParams);
|
||||
$aParams = array_merge(['table_id' => $sUsageId], $aExtraParams);
|
||||
$oBlock = new DisplayBlock($oSearch, 'list', false /* Asynchronous */, $aParams);
|
||||
$oBlock->Display($oPage, $sUsageId);
|
||||
|
||||
@@ -1239,14 +1182,14 @@ class SearchMenuNode extends MenuNode
|
||||
* @throws \DictExceptionMissingString
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function RenderContent(WebPage $oPage, $aExtraParams = array())
|
||||
public function RenderContent(WebPage $oPage, $aExtraParams = [])
|
||||
{
|
||||
ApplicationMenu::CheckMenuIdEnabled($this->GetMenuId());
|
||||
$oPage->SetBreadCrumbEntry("menu-".$this->sMenuId, $this->GetTitle(), '', '', 'fas fa-search', iTopWebPage::ENUM_BREADCRUMB_ENTRY_ICON_TYPE_CSS_CLASSES);
|
||||
|
||||
$oSearch = new DBObjectSearch($this->sClass);
|
||||
$sUsageId = 'Menu_'.utils::GetSafeId($this->GetMenuId());
|
||||
$aParams = array_merge(array('table_id' =>$sUsageId), $aExtraParams);
|
||||
$aParams = array_merge(['table_id' => $sUsageId], $aExtraParams);
|
||||
$oBlock = new DisplayBlock($oSearch, 'search', false /* Asynchronous */, $aParams);
|
||||
$oBlock->Display($oPage, 0);
|
||||
}
|
||||
@@ -1283,10 +1226,16 @@ class WebPageMenuNode extends MenuNode
|
||||
* @param bool $bIsLinkInNewWindow for the {@link WebPageMenuNode::IsHyperLinkInNewWindow} method
|
||||
*/
|
||||
public function __construct(
|
||||
$sMenuId, $sHyperlink, $iParentIndex, $fRank = 0.0, $sEnableClass = null, $iActionCode = null,
|
||||
$iAllowedResults = UR_ALLOWED_YES, $sEnableStimulus = null, $bIsLinkInNewWindow = false
|
||||
)
|
||||
{
|
||||
$sMenuId,
|
||||
$sHyperlink,
|
||||
$iParentIndex,
|
||||
$fRank = 0.0,
|
||||
$sEnableClass = null,
|
||||
$iActionCode = null,
|
||||
$iAllowedResults = UR_ALLOWED_YES,
|
||||
$sEnableStimulus = null,
|
||||
$bIsLinkInNewWindow = false
|
||||
) {
|
||||
parent::__construct($sMenuId, $iParentIndex, $fRank, $sEnableClass, $iActionCode, $iAllowedResults, $sEnableStimulus);
|
||||
$this->sHyperlink = $sHyperlink;
|
||||
$this->aReflectionProperties['url'] = $sHyperlink;
|
||||
@@ -1299,7 +1248,7 @@ class WebPageMenuNode extends MenuNode
|
||||
public function GetHyperlink($aExtraParams)
|
||||
{
|
||||
$aExtraParams['c[menu]'] = $this->GetMenuId();
|
||||
return $this->AddParams( $this->sHyperlink, $aExtraParams);
|
||||
return $this->AddParams($this->sHyperlink, $aExtraParams);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1313,7 +1262,7 @@ class WebPageMenuNode extends MenuNode
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function RenderContent(WebPage $oPage, $aExtraParams = array())
|
||||
public function RenderContent(WebPage $oPage, $aExtraParams = [])
|
||||
{
|
||||
assert(false); // Shall never be called, the external web page will handle the display by itself
|
||||
}
|
||||
@@ -1374,10 +1323,8 @@ class NewObjectMenuNode extends MenuNode
|
||||
$aSubClasses = MetaModel::EnumChildClasses($this->sClass, ENUM_CHILD_CLASSES_ALL); // Including the specified class itself
|
||||
$bActionIsAllowed = false;
|
||||
|
||||
foreach($aSubClasses as $sCandidateClass)
|
||||
{
|
||||
if (!MetaModel::IsAbstract($sCandidateClass) && (UserRights::IsActionAllowed($sCandidateClass, UR_ACTION_MODIFY) == UR_ALLOWED_YES))
|
||||
{
|
||||
foreach ($aSubClasses as $sCandidateClass) {
|
||||
if (!MetaModel::IsAbstract($sCandidateClass) && (UserRights::IsActionAllowed($sCandidateClass, UR_ACTION_MODIFY) == UR_ALLOWED_YES)) {
|
||||
$bActionIsAllowed = true;
|
||||
break; // Enough for now
|
||||
}
|
||||
@@ -1388,7 +1335,7 @@ class NewObjectMenuNode extends MenuNode
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function RenderContent(WebPage $oPage, $aExtraParams = array())
|
||||
public function RenderContent(WebPage $oPage, $aExtraParams = [])
|
||||
{
|
||||
assert(false); // Shall never be called, the external web page will handle the display by itself
|
||||
}
|
||||
@@ -1428,7 +1375,9 @@ class DashboardMenuNode extends MenuNode
|
||||
*/
|
||||
public function GetHyperlink($aExtraParams)
|
||||
{
|
||||
if ($this->sDashboardFile == '') return '';
|
||||
if ($this->sDashboardFile == '') {
|
||||
return '';
|
||||
}
|
||||
return parent::GetHyperlink($aExtraParams);
|
||||
}
|
||||
|
||||
@@ -1446,12 +1395,11 @@ class DashboardMenuNode extends MenuNode
|
||||
* @inheritDoc
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function RenderContent(WebPage $oPage, $aExtraParams = array())
|
||||
public function RenderContent(WebPage $oPage, $aExtraParams = [])
|
||||
{
|
||||
ApplicationMenu::CheckMenuIdEnabled($this->GetMenuId());
|
||||
$oDashboard = $this->GetDashboard();
|
||||
if ($oDashboard != null)
|
||||
{
|
||||
if ($oDashboard != null) {
|
||||
WebResourcesHelper::EnableC3JSToWebPage($oPage);
|
||||
|
||||
$sDivId = utils::Sanitize($this->sMenuId, '', 'element_identifier');
|
||||
@@ -1482,9 +1430,7 @@ class DashboardMenuNode extends MenuNode
|
||||
}
|
||||
$oPage->SetBreadCrumbEntry("ui-dashboard-".$this->sMenuId, $this->GetTitle(), $sDescription, '', $sIcon, iTopWebPage::ENUM_BREADCRUMB_ENTRY_ICON_TYPE_CSS_CLASSES);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
$oPage->p("Error: failed to load dashboard file: '{$this->sDashboardFile}'");
|
||||
}
|
||||
}
|
||||
@@ -1497,12 +1443,9 @@ class DashboardMenuNode extends MenuNode
|
||||
public function RenderEditor(WebPage $oPage)
|
||||
{
|
||||
$oDashboard = $this->GetDashboard();
|
||||
if ($oDashboard != null)
|
||||
{
|
||||
if ($oDashboard != null) {
|
||||
$oDashboard->RenderEditor($oPage);
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
$oPage->p("Error: failed to load dashboard file: '{$this->sDashboardFile}'");
|
||||
}
|
||||
}
|
||||
@@ -1514,13 +1457,10 @@ class DashboardMenuNode extends MenuNode
|
||||
public function AddDashlet($oDashlet)
|
||||
{
|
||||
$oDashboard = $this->GetDashboard();
|
||||
if ($oDashboard != null)
|
||||
{
|
||||
if ($oDashboard != null) {
|
||||
$oDashboard->AddDashlet($oDashlet);
|
||||
$oDashboard->Save();
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
throw new Exception("Error: failed to load dashboard file: '{$this->sDashboardFile}'");
|
||||
}
|
||||
}
|
||||
@@ -1543,7 +1483,7 @@ class ShortcutContainerMenuNode extends MenuNode
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function RenderContent(WebPage $oPage, $aExtraParams = array())
|
||||
public function RenderContent(WebPage $oPage, $aExtraParams = [])
|
||||
{
|
||||
}
|
||||
|
||||
@@ -1558,10 +1498,9 @@ class ShortcutContainerMenuNode extends MenuNode
|
||||
//
|
||||
$oBMSearch = new DBObjectSearch('Shortcut');
|
||||
$oBMSearch->AddCondition('user_id', UserRights::GetUserId(), '=');
|
||||
$oBMSet = new DBObjectSet($oBMSearch, array('friendlyname' => true)); // ascending on friendlyname
|
||||
$oBMSet = new DBObjectSet($oBMSearch, ['friendlyname' => true]); // ascending on friendlyname
|
||||
$fRank = 1;
|
||||
while ($oShortcut = $oBMSet->Fetch())
|
||||
{
|
||||
while ($oShortcut = $oBMSet->Fetch()) {
|
||||
$sName = $this->GetMenuId().'_'.$oShortcut->GetKey();
|
||||
new ShortcutMenuNode($sName, $oShortcut, $this->GetIndex(), $fRank++);
|
||||
}
|
||||
@@ -1572,7 +1511,6 @@ class ShortcutContainerMenuNode extends MenuNode
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
require_once(APPROOT.'application/shortcut.class.inc.php');
|
||||
/**
|
||||
* This class defines a menu item which content is a shortcut.
|
||||
@@ -1608,14 +1546,21 @@ class ShortcutMenuNode extends MenuNode
|
||||
public function GetHyperlink($aExtraParams)
|
||||
{
|
||||
$sContext = $this->oShortcut->Get('context');
|
||||
$aContext = unserialize($sContext);
|
||||
if (isset($aContext['menu']))
|
||||
{
|
||||
unset($aContext['menu']);
|
||||
}
|
||||
foreach ($aContext as $sArgName => $sArgValue)
|
||||
{
|
||||
$aExtraParams[$sArgName] = $sArgValue;
|
||||
try {
|
||||
$aContext = utils::Unserialize($sContext);
|
||||
if (isset($aContext['menu'])) {
|
||||
unset($aContext['menu']);
|
||||
}
|
||||
foreach ($aContext as $sArgName => $sArgValue) {
|
||||
$aExtraParams[$sArgName] = $sArgValue;
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
IssueLog::Warning("User shortcut corrupted, delete the shortcut", LogChannels::CONSOLE, [
|
||||
'shortcut_name' => $this->oShortcut->GetName(),
|
||||
'root_cause' => $e->getMessage(),
|
||||
]);
|
||||
// delete the shortcut
|
||||
$this->oShortcut->DBDelete();
|
||||
}
|
||||
return parent::GetHyperlink($aExtraParams);
|
||||
}
|
||||
@@ -1624,7 +1569,7 @@ class ShortcutMenuNode extends MenuNode
|
||||
* @inheritDoc
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function RenderContent(WebPage $oPage, $aExtraParams = array())
|
||||
public function RenderContent(WebPage $oPage, $aExtraParams = [])
|
||||
{
|
||||
ApplicationMenu::CheckMenuIdEnabled($this->GetMenuId());
|
||||
$this->oShortcut->RenderContent($oPage, $aExtraParams);
|
||||
@@ -1661,11 +1606,9 @@ class ShortcutMenuNode extends MenuNode
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
public function GetEntriesCount()
|
||||
{
|
||||
return $this->GetEntriesCountFromOQL($this->oShortcut->Get('oql'));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
// Copyright (C) 2010-2024 Combodo SAS
|
||||
//
|
||||
// This file is part of iTop.
|
||||
@@ -33,45 +34,45 @@ interface iNewsroomProvider
|
||||
* @param User $oUser The user for who to check if the provider is applicable.
|
||||
* return bool
|
||||
*/
|
||||
public function IsApplicable(User $oUser = null);
|
||||
|
||||
public function IsApplicable(?User $oUser = null);
|
||||
|
||||
/**
|
||||
* The human readable (localized) label for this provider
|
||||
* @return string
|
||||
*/
|
||||
public function GetLabel();
|
||||
|
||||
|
||||
/**
|
||||
* The URL to query (from the browser, using jsonp) to fetch all unread messages
|
||||
* @return string
|
||||
*/
|
||||
public function GetFetchURL();
|
||||
|
||||
|
||||
/**
|
||||
* The URL to navigate to in order to display all messages
|
||||
* @return string
|
||||
*/
|
||||
public function GetViewAllURL();
|
||||
|
||||
|
||||
/**
|
||||
* The URL to query(from the browser, using jsonp) to mark all unread messages as read
|
||||
* @return string
|
||||
*/
|
||||
public function GetMarkAllAsReadURL();
|
||||
|
||||
|
||||
/**
|
||||
* Return the URL to configure the preferences for this provider or null is there is nothing to configure
|
||||
* @return string|null
|
||||
*/
|
||||
public function GetPreferencesUrl();
|
||||
|
||||
|
||||
/**
|
||||
* Return an array key => value to be replaced in URL of the messages
|
||||
* Example: '%itop_root%' => utils::GetAbsoluteUrlAppRoot();
|
||||
* @return string[]
|
||||
*/
|
||||
public function GetPlaceholders();
|
||||
|
||||
|
||||
/**
|
||||
* The duration between to refreshes of the cache (in seconds)
|
||||
* @return int
|
||||
@@ -90,19 +91,19 @@ abstract class NewsroomProviderBase implements iNewsroomProvider
|
||||
* @var Config
|
||||
*/
|
||||
protected $oConfig;
|
||||
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->oConfig = null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
* @see iNewsroomProvider::SetConfig()
|
||||
*/
|
||||
public function SetConfig(Config $oConfig)
|
||||
{
|
||||
$this->oConfig = $oConfig;
|
||||
$this->oConfig = $oConfig;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -118,42 +119,42 @@ abstract class NewsroomProviderBase implements iNewsroomProvider
|
||||
* {@inheritDoc}
|
||||
* @see iNewsroomProvider::GetLabel()
|
||||
*/
|
||||
public abstract function GetLabel();
|
||||
|
||||
abstract public function GetLabel();
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
* @see iNewsroomProvider::GetFetchURL()
|
||||
*/
|
||||
public abstract function GetFetchURL();
|
||||
abstract public function GetFetchURL();
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
* @see iNewsroomProvider::GetMarkAllURL()
|
||||
*/
|
||||
public abstract function GetMarkAllAsReadURL();
|
||||
abstract public function GetMarkAllAsReadURL();
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
* @see iNewsroomProvider::GetViewAllURL()
|
||||
*/
|
||||
public abstract function GetViewAllURL();
|
||||
abstract public function GetViewAllURL();
|
||||
|
||||
public function IsApplicable(User $oUser = null)
|
||||
public function IsApplicable(?User $oUser = null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
* @see iNewsroomProvider::GetPlaceholders()
|
||||
*/
|
||||
public function GetPlaceholders()
|
||||
{
|
||||
return array(); // By default, empty set of placeholders
|
||||
return []; // By default, empty set of placeholders
|
||||
}
|
||||
|
||||
|
||||
public function GetTTL()
|
||||
{
|
||||
return 10*60; // Refresh every 10 minutes
|
||||
return 10 * 60; // Refresh every 10 minutes
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @deprecated 3.0.0 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-2024 Combodo SAS
|
||||
*/
|
||||
|
||||
DeprecatedCallsLog::NotifyDeprecatedFile('moved to sources/Application/WebPage/NiceWebPage.php, now loadable using autoloader');
|
||||
DeprecatedCallsLog::NotifyDeprecatedFile('moved to sources/Application/WebPage/NiceWebPage.php, now loadable using autoloader');
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @deprecated 3.0.0 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-2024 Combodo SAS
|
||||
*/
|
||||
|
||||
DeprecatedCallsLog::NotifyDeprecatedFile('moved to sources/Application/WebPage/PDFPage.php, now loadable using autoloader');
|
||||
DeprecatedCallsLog::NotifyDeprecatedFile('moved to sources/Application/WebPage/PDFPage.php, now loadable using autoloader');
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
<?php
|
||||
|
||||
class PortalDispatcher
|
||||
{
|
||||
protected $sPortalid;
|
||||
protected $aData;
|
||||
|
||||
|
||||
public function __construct($sPortalId)
|
||||
{
|
||||
$this->sPortalid = $sPortalId;
|
||||
@@ -20,53 +21,45 @@ class PortalDispatcher
|
||||
{
|
||||
$bRet = true;
|
||||
$aProfiles = UserRights::ListProfiles($oUser);
|
||||
|
||||
foreach($this->aData['deny'] as $sDeniedProfile)
|
||||
{
|
||||
|
||||
foreach ($this->aData['deny'] as $sDeniedProfile) {
|
||||
// If one denied profile is present, it's enough => return false
|
||||
if (in_array($sDeniedProfile, $aProfiles))
|
||||
{
|
||||
if (in_array($sDeniedProfile, $aProfiles)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
// If there are some "allow" profiles, then by default the result is false
|
||||
// since the user must have at least one of the profiles to be allowed
|
||||
if (count($this->aData['allow']) > 0)
|
||||
{
|
||||
if (count($this->aData['allow']) > 0) {
|
||||
$bRet = false;
|
||||
}
|
||||
foreach($this->aData['allow'] as $sAllowProfile)
|
||||
{
|
||||
foreach ($this->aData['allow'] as $sAllowProfile) {
|
||||
// If one "allow" profile is present, it's enough => return true
|
||||
if (in_array($sAllowProfile, $aProfiles))
|
||||
{
|
||||
if (in_array($sAllowProfile, $aProfiles)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return $bRet;
|
||||
}
|
||||
|
||||
|
||||
public function GetURL()
|
||||
{
|
||||
$aOverloads = MetaModel::GetConfig()->Get('portal_dispatch_urls');
|
||||
if (array_key_exists($this->sPortalid, $aOverloads))
|
||||
{
|
||||
if (array_key_exists($this->sPortalid, $aOverloads)) {
|
||||
$sRet = $aOverloads[$this->sPortalid];
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
$sRet = utils::GetAbsoluteUrlAppRoot().$this->aData['url'];
|
||||
}
|
||||
return $sRet;
|
||||
}
|
||||
|
||||
|
||||
public function GetLabel()
|
||||
{
|
||||
return Dict::S('portal:'.$this->sPortalid);
|
||||
}
|
||||
|
||||
|
||||
public function GetRank()
|
||||
{
|
||||
return $this->aData['rank'];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* Copyright (C) 2010-2024 Combodo SAS
|
||||
*
|
||||
@@ -31,111 +32,117 @@ abstract class Query extends cmdbAbstractObject
|
||||
*/
|
||||
public static function Init()
|
||||
{
|
||||
$aParams = array
|
||||
(
|
||||
$aParams =
|
||||
[
|
||||
"category" => "core/cmdb,view_in_gui,application,grant_by_profile",
|
||||
"key_type" => "autoincrement",
|
||||
"name_attcode" => "name",
|
||||
"state_attcode" => "",
|
||||
"reconc_keys" => array(),
|
||||
"reconc_keys" => [],
|
||||
"db_table" => "priv_query",
|
||||
"db_key_field" => "id",
|
||||
"db_finalclass_field" => "realclass",
|
||||
);
|
||||
];
|
||||
MetaModel::Init_Params($aParams);
|
||||
|
||||
MetaModel::Init_AddAttribute(new AttributeString("name", array(
|
||||
MetaModel::Init_AddAttribute(new AttributeString("name", [
|
||||
"allowed_values" => null,
|
||||
"sql" => "name",
|
||||
"default_value" => null,
|
||||
"is_null_allowed" => false,
|
||||
"depends_on" => array(),
|
||||
)));
|
||||
"depends_on" => [],
|
||||
]));
|
||||
|
||||
MetaModel::Init_AddAttribute(new AttributeText("description", array(
|
||||
MetaModel::Init_AddAttribute(new AttributeText("description", [
|
||||
"allowed_values" => null,
|
||||
"sql" => "description",
|
||||
"default_value" => null,
|
||||
"is_null_allowed" => false,
|
||||
"depends_on" => array(),
|
||||
)));
|
||||
"depends_on" => [],
|
||||
]));
|
||||
|
||||
MetaModel::Init_AddAttribute(new AttributeEnum("is_template", array(
|
||||
MetaModel::Init_AddAttribute(new AttributeEnum("is_template", [
|
||||
'allowed_values' => new ValueSetEnum('yes,no'),
|
||||
'sql' => 'is_template',
|
||||
'default_value' => 'no',
|
||||
'is_null_allowed' => false,
|
||||
'depends_on' => [],
|
||||
'display_style' => 'radio_horizontal',
|
||||
)));
|
||||
]));
|
||||
|
||||
MetaModel::Init_AddAttribute(new AttributeInteger("export_count", array(
|
||||
MetaModel::Init_AddAttribute(new AttributeInteger("export_count", [
|
||||
"allowed_values" => null,
|
||||
"sql" => "export_count",
|
||||
"default_value" => 0,
|
||||
"is_null_allowed" => false,
|
||||
"depends_on" => array(),
|
||||
"depends_on" => [],
|
||||
"tracking_level" => ATTRIBUTE_TRACKING_NONE,
|
||||
)));
|
||||
]));
|
||||
|
||||
MetaModel::Init_AddAttribute(new AttributeDateTime("export_last_date", array(
|
||||
MetaModel::Init_AddAttribute(new AttributeDateTime("export_last_date", [
|
||||
"allowed_values" => null,
|
||||
"sql" => "export_last_date",
|
||||
"default_value" => null,
|
||||
"is_null_allowed" => true,
|
||||
"depends_on" => array(),
|
||||
"depends_on" => [],
|
||||
"tracking_level" => ATTRIBUTE_TRACKING_NONE,
|
||||
)));
|
||||
]));
|
||||
|
||||
MetaModel::Init_AddAttribute(new AttributeExternalKey("export_last_user_id",
|
||||
array(
|
||||
"targetclass"=>'User',
|
||||
"allowed_values"=>null,
|
||||
"sql"=>'user_id',
|
||||
"is_null_allowed"=>true,
|
||||
"depends_on"=>array(),
|
||||
"display_style"=>'select',
|
||||
"always_load_in_tables"=>false,
|
||||
"on_target_delete"=>DEL_SILENT,
|
||||
MetaModel::Init_AddAttribute(new AttributeExternalKey(
|
||||
"export_last_user_id",
|
||||
[
|
||||
"targetclass" => 'User',
|
||||
"allowed_values" => null,
|
||||
"sql" => 'user_id',
|
||||
"is_null_allowed" => true,
|
||||
"depends_on" => [],
|
||||
"display_style" => 'select',
|
||||
"always_load_in_tables" => false,
|
||||
"on_target_delete" => DEL_SILENT,
|
||||
"tracking_level" => ATTRIBUTE_TRACKING_NONE,
|
||||
)));
|
||||
]
|
||||
));
|
||||
|
||||
MetaModel::Init_AddAttribute(new AttributeExternalField("export_last_user_contact",
|
||||
array(
|
||||
"allowed_values"=>null,
|
||||
"extkey_attcode"=> "export_last_user_id",
|
||||
"target_attcode"=>"contactid",
|
||||
MetaModel::Init_AddAttribute(new AttributeExternalField(
|
||||
"export_last_user_contact",
|
||||
[
|
||||
"allowed_values" => null,
|
||||
"extkey_attcode" => "export_last_user_id",
|
||||
"target_attcode" => "contactid",
|
||||
"tracking_level" => ATTRIBUTE_TRACKING_NONE,
|
||||
)));
|
||||
]
|
||||
));
|
||||
|
||||
// Display lists
|
||||
MetaModel::Init_SetZListItems('details',
|
||||
array('name', 'is_template', 'description')); // Attributes to be displayed for the complete details
|
||||
MetaModel::Init_SetZListItems('list', array('description')); // Attributes to be displayed for a list
|
||||
MetaModel::Init_SetZListItems(
|
||||
'details',
|
||||
['name', 'is_template', 'description']
|
||||
); // Attributes to be displayed for the complete details
|
||||
MetaModel::Init_SetZListItems('list', ['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', ['name', 'description', 'is_template']); // Criteria of the std search form
|
||||
MetaModel::Init_SetZListItems(
|
||||
'default_search',
|
||||
['name', 'description', 'is_template']
|
||||
); // Criteria of the default search form
|
||||
// MetaModel::Init_SetZListItems('advanced_search', array('name')); // Criteria of the advanced search form
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*
|
||||
* @since 3.1.0
|
||||
*/
|
||||
public function GetAttributeFlags($sAttCode, &$aReasons = array(), $sTargetState = '')
|
||||
public function GetAttributeFlags($sAttCode, &$aReasons = [], $sTargetState = '')
|
||||
{
|
||||
// read only attribute
|
||||
if (in_array($sAttCode, ['export_count', 'export_last_date', 'export_last_user_id'])){
|
||||
if (in_array($sAttCode, ['export_count', 'export_last_date', 'export_last_user_id'])) {
|
||||
return OPT_ATT_READONLY;
|
||||
}
|
||||
|
||||
return parent::GetAttributeFlags($sAttCode, $aReasons, $sTargetState);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return export url.
|
||||
*
|
||||
@@ -144,7 +151,7 @@ abstract class Query extends cmdbAbstractObject
|
||||
* @return string|null
|
||||
* @since 3.1.0
|
||||
*/
|
||||
abstract public function GetExportUrl(array $aValues = null) : ?string;
|
||||
abstract public function GetExportUrl(?array $aValues = null): ?string;
|
||||
|
||||
/**
|
||||
* Update last export information.
|
||||
@@ -156,7 +163,7 @@ abstract class Query extends cmdbAbstractObject
|
||||
* @throws \MySQLException
|
||||
* @since 3.1.0
|
||||
*/
|
||||
public function UpdateLastExportInformation() : void
|
||||
public function UpdateLastExportInformation(): void
|
||||
{
|
||||
// last export information
|
||||
$this->Set('export_last_date', date(AttributeDateTime::GetSQLFormat()));
|
||||
@@ -173,53 +180,56 @@ class QueryOQL extends Query
|
||||
{
|
||||
public static function Init()
|
||||
{
|
||||
$aParams = array
|
||||
(
|
||||
$aParams =
|
||||
[
|
||||
"category" => "core/cmdb,view_in_gui,application,grant_by_profile",
|
||||
"key_type" => "autoincrement",
|
||||
"name_attcode" => "name",
|
||||
"state_attcode" => "",
|
||||
"reconc_keys" => array('oql', 'is_template'),
|
||||
"reconc_keys" => ['oql', 'is_template'],
|
||||
"db_table" => "priv_query_oql",
|
||||
"db_key_field" => "id",
|
||||
"db_finalclass_field" => "",
|
||||
);
|
||||
];
|
||||
MetaModel::Init_Params($aParams);
|
||||
MetaModel::Init_InheritAttributes();
|
||||
MetaModel::Init_AddAttribute(new AttributeOQL("oql", array(
|
||||
MetaModel::Init_AddAttribute(new AttributeOQL("oql", [
|
||||
"allowed_values" => null,
|
||||
"sql" => "oql",
|
||||
"default_value" => null,
|
||||
"is_null_allowed" => false,
|
||||
"depends_on" => array(),
|
||||
)));
|
||||
MetaModel::Init_AddAttribute(new AttributeText("fields", array(
|
||||
"depends_on" => [],
|
||||
]));
|
||||
MetaModel::Init_AddAttribute(new AttributeText("fields", [
|
||||
"allowed_values" => null,
|
||||
"sql" => "fields",
|
||||
"default_value" => null,
|
||||
"is_null_allowed" => true,
|
||||
"depends_on" => array(),
|
||||
)));
|
||||
"depends_on" => [],
|
||||
]));
|
||||
// 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(
|
||||
'col:col1' => array('fieldset:Query:baseinfo' => array('name', 'is_template', 'description', 'oql', 'fields')),
|
||||
'col:col2' => array('fieldset:Query:exportInfo' => array('export_count', 'export_last_date', 'export_last_user_id', 'export_last_user_contact'))
|
||||
)
|
||||
MetaModel::Init_SetZListItems(
|
||||
'details',
|
||||
[
|
||||
'col:col1' => ['fieldset:Query:baseinfo' => ['name', 'is_template', 'description', 'oql', 'fields']],
|
||||
'col:col2' => ['fieldset:Query:exportInfo' => ['export_count', 'export_last_date', 'export_last_user_id', 'export_last_user_contact']],
|
||||
]
|
||||
); // Attributes to be displayed for the complete details
|
||||
MetaModel::Init_SetZListItems('list', array('description')); // Attributes to be displayed for a list
|
||||
MetaModel::Init_SetZListItems('list', ['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',
|
||||
['name', 'description', 'is_template', 'fields', 'oql']
|
||||
); // Criteria of the std search form
|
||||
}
|
||||
|
||||
/** @inheritdoc */
|
||||
public function GetExportUrl(array $aValues = null) : ?string
|
||||
public function GetExportUrl(?array $aValues = null): ?string
|
||||
{
|
||||
try{
|
||||
try {
|
||||
// retrieve attributes
|
||||
$sFields = trim($this->Get('fields'));
|
||||
$sOql = $this->Get('oql');
|
||||
@@ -228,8 +238,7 @@ class QueryOQL extends Query
|
||||
$bExportV1Recommended = ($sFields == '');
|
||||
if ($bExportV1Recommended) {
|
||||
$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();
|
||||
}
|
||||
|
||||
@@ -240,17 +249,16 @@ class QueryOQL extends Query
|
||||
$aParameters = $oSearch->GetQueryParams();
|
||||
foreach ($aParameters as $sParam => $val) {
|
||||
$paramValue = ($aValues === null || $aValues[$sParam] === null) ? $sParam : $aValues[$sParam];
|
||||
$sUrl .= '&arg_' . $sParam . '=' . $paramValue;
|
||||
$sUrl .= '&arg_'.$sParam.'='.$paramValue;
|
||||
}
|
||||
|
||||
return $sUrl;
|
||||
}
|
||||
catch(Exception $e){
|
||||
} catch (Exception $e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
function DisplayBareProperties(WebPage $oPage, $bEditMode = false, $sPrefix = '', $aExtraParams = array())
|
||||
public function DisplayBareProperties(WebPage $oPage, $bEditMode = false, $sPrefix = '', $aExtraParams = [])
|
||||
{
|
||||
$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');");
|
||||
@@ -287,16 +295,14 @@ class QueryOQL extends Query
|
||||
|
||||
if (count($aParameters) == 0) {
|
||||
$oBlock = new DisplayBlock($oSearch, 'list');
|
||||
$aExtraParams = array(
|
||||
$aExtraParams = [
|
||||
//'menu' => $sShowMenu,
|
||||
'table_id' => 'query_preview_'.$this->getKey(),
|
||||
);
|
||||
];
|
||||
$sBlockId = 'block_query_preview_'.$this->GetKey(); // make a unique id (edition occuring in the same DOM)
|
||||
$oBlock->Display($oPage, $sBlockId, $aExtraParams);
|
||||
}
|
||||
}
|
||||
catch
|
||||
(OQLException $e) {
|
||||
} catch (OQLException $e) {
|
||||
$oAlert = AlertUIBlockFactory::MakeForFailure(Dict::S('UI:RunQuery:Error'), $e->getHtmlDesc())
|
||||
->SetIsClosable(false)
|
||||
->SetIsCollapsible(false);
|
||||
@@ -307,41 +313,38 @@ class QueryOQL extends Query
|
||||
return $aFieldsMap;
|
||||
}
|
||||
|
||||
|
||||
// Rolled back until 'fields' can be properly managed by AttributeQueryAttCodeSet
|
||||
//
|
||||
// public function ComputeValues()
|
||||
// {
|
||||
// parent::ComputeValues();
|
||||
//
|
||||
// // Remove unwanted attribute codes
|
||||
// $aChanges = $this->ListChanges();
|
||||
// if (isset($aChanges['fields']))
|
||||
// {
|
||||
// $oAttDef = MetaModel::GetAttributeDef(get_class($this), 'fields');
|
||||
// $aArgs = array('this' => $this);
|
||||
// $aAllowedValues = $oAttDef->GetAllowedValues($aArgs);
|
||||
//
|
||||
// /** @var \ormSet $oValue */
|
||||
// $oValue = $this->Get('fields');
|
||||
// $aValues = $oValue->GetValues();
|
||||
// $bChanged = false;
|
||||
// foreach($aValues as $key => $sValue)
|
||||
// {
|
||||
// if (!isset($aAllowedValues[$sValue]))
|
||||
// {
|
||||
// unset($aValues[$key]);
|
||||
// $bChanged = true;
|
||||
// }
|
||||
// }
|
||||
// if ($bChanged)
|
||||
// {
|
||||
// $oValue->SetValues($aValues);
|
||||
// $this->Set('fields', $oValue);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// Rolled back until 'fields' can be properly managed by AttributeQueryAttCodeSet
|
||||
//
|
||||
// public function ComputeValues()
|
||||
// {
|
||||
// parent::ComputeValues();
|
||||
//
|
||||
// // Remove unwanted attribute codes
|
||||
// $aChanges = $this->ListChanges();
|
||||
// if (isset($aChanges['fields']))
|
||||
// {
|
||||
// $oAttDef = MetaModel::GetAttributeDef(get_class($this), 'fields');
|
||||
// $aArgs = array('this' => $this);
|
||||
// $aAllowedValues = $oAttDef->GetAllowedValues($aArgs);
|
||||
//
|
||||
// /** @var \ormSet $oValue */
|
||||
// $oValue = $this->Get('fields');
|
||||
// $aValues = $oValue->GetValues();
|
||||
// $bChanged = false;
|
||||
// foreach($aValues as $key => $sValue)
|
||||
// {
|
||||
// if (!isset($aAllowedValues[$sValue]))
|
||||
// {
|
||||
// unset($aValues[$key]);
|
||||
// $bChanged = true;
|
||||
// }
|
||||
// }
|
||||
// if ($bChanged)
|
||||
// {
|
||||
// $oValue->SetValues($aValues);
|
||||
// $this->Set('fields', $oValue);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
}
|
||||
|
||||
?>
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
<?php
|
||||
|
||||
// Copyright (C) 2010-2024 Combodo SAS
|
||||
//
|
||||
// This file is part of iTop.
|
||||
//
|
||||
// iTop is free software; you can redistribute it and/or modify
|
||||
// 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.
|
||||
@@ -18,7 +19,6 @@
|
||||
use Combodo\iTop\Application\UI\Base\Component\DataTable\DataTableSettings;
|
||||
use Combodo\iTop\Application\WebPage\WebPage;
|
||||
|
||||
|
||||
/**
|
||||
* Persistent class Shortcut and derived
|
||||
* Shortcuts of any kind
|
||||
@@ -31,32 +31,32 @@ abstract class Shortcut extends DBObject implements iDisplay
|
||||
{
|
||||
public static function Init()
|
||||
{
|
||||
$aParams = array
|
||||
(
|
||||
$aParams =
|
||||
[
|
||||
"category" => "gui,view_in_gui",
|
||||
"key_type" => "autoincrement",
|
||||
"name_attcode" => "name",
|
||||
"state_attcode" => "",
|
||||
"reconc_keys" => array(),
|
||||
"reconc_keys" => [],
|
||||
"db_table" => "priv_shortcut",
|
||||
"db_key_field" => "id",
|
||||
"db_finalclass_field" => "realclass",
|
||||
);
|
||||
];
|
||||
MetaModel::Init_Params($aParams);
|
||||
//MetaModel::Init_InheritAttributes();
|
||||
MetaModel::Init_AddAttribute(new AttributeExternalKey("user_id", array("targetclass"=>"User", "allowed_values"=>null, "sql"=>"user_id", "is_null_allowed"=>true, "on_target_delete"=>DEL_AUTO, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeString("name", array("allowed_values"=>null, "sql"=>"name", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeText("context", array("allowed_values"=>null, "sql"=>"context", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeExternalKey("user_id", ["targetclass" => "User", "allowed_values" => null, "sql" => "user_id", "is_null_allowed" => true, "on_target_delete" => DEL_AUTO, "depends_on" => []]));
|
||||
MetaModel::Init_AddAttribute(new AttributeString("name", ["allowed_values" => null, "sql" => "name", "default_value" => null, "is_null_allowed" => false, "depends_on" => []]));
|
||||
MetaModel::Init_AddAttribute(new AttributeText("context", ["allowed_values" => null, "sql" => "context", "default_value" => null, "is_null_allowed" => false, "depends_on" => []]));
|
||||
|
||||
// Display lists
|
||||
MetaModel::Init_SetZListItems('details', array('name', 'context')); // Attributes to be displayed for the complete details
|
||||
MetaModel::Init_SetZListItems('list', array('name')); // Attributes to be displayed for a list
|
||||
MetaModel::Init_SetZListItems('details', ['name', 'context']); // Attributes to be displayed for the complete details
|
||||
MetaModel::Init_SetZListItems('list', ['name']); // Attributes to be displayed for a list
|
||||
// Search criteria
|
||||
// MetaModel::Init_SetZListItems('standard_search', array('name')); // Criteria of the std search form
|
||||
// MetaModel::Init_SetZListItems('advanced_search', array('name')); // Criteria of the advanced search form
|
||||
// MetaModel::Init_SetZListItems('standard_search', array('name')); // Criteria of the std search form
|
||||
// MetaModel::Init_SetZListItems('advanced_search', array('name')); // Criteria of the advanced search form
|
||||
}
|
||||
|
||||
abstract public function RenderContent(WebPage $oPage, $aExtraParams = array());
|
||||
abstract public function RenderContent(WebPage $oPage, $aExtraParams = []);
|
||||
|
||||
protected function OnInsert()
|
||||
{
|
||||
@@ -74,14 +74,14 @@ abstract class Shortcut extends DBObject implements iDisplay
|
||||
$oForm->AddField($oField);
|
||||
$oForm->Render($oPage);
|
||||
$oPage->add('</div>');
|
||||
|
||||
|
||||
$sDialogTitle = Dict::S('UI:ShortcutRenameDlg:Title');
|
||||
$sOkButtonLabel = Dict::S('UI:Button:Ok');
|
||||
$sCancelButtonLabel = Dict::S('UI:Button:Cancel');
|
||||
$iShortcut = $this->GetKey();
|
||||
|
||||
|
||||
$oPage->add_ready_script(
|
||||
<<<EOF
|
||||
<<<EOF
|
||||
function ShortcutRenameOK()
|
||||
{
|
||||
var oForm = $(this).find('form');
|
||||
@@ -137,13 +137,13 @@ EOF
|
||||
return '';
|
||||
}
|
||||
|
||||
function DisplayDetails(WebPage $oPage, $bEditMode = false)
|
||||
public function DisplayDetails(WebPage $oPage, $bEditMode = false)
|
||||
{
|
||||
}
|
||||
|
||||
function DisplayBareProperties(WebPage $oPage, $bEditMode = false, $sPrefix = '', $aExtraParams = array())
|
||||
public function DisplayBareProperties(WebPage $oPage, $bEditMode = false, $sPrefix = '', $aExtraParams = [])
|
||||
{
|
||||
return array();
|
||||
return [];
|
||||
}
|
||||
// End of the minimal implementation of iDisplay
|
||||
}
|
||||
@@ -152,61 +152,56 @@ class ShortcutOQL extends Shortcut
|
||||
{
|
||||
public static function Init()
|
||||
{
|
||||
$aParams = array
|
||||
(
|
||||
$aParams =
|
||||
[
|
||||
"category" => "gui,view_in_gui",
|
||||
"key_type" => "autoincrement",
|
||||
"name_attcode" => "name",
|
||||
"state_attcode" => "",
|
||||
"reconc_keys" => array(),
|
||||
"reconc_keys" => [],
|
||||
"db_table" => "priv_shortcut_oql",
|
||||
"db_key_field" => "id",
|
||||
"db_finalclass_field" => "",
|
||||
);
|
||||
];
|
||||
MetaModel::Init_Params($aParams);
|
||||
MetaModel::Init_InheritAttributes();
|
||||
MetaModel::Init_AddAttribute(new AttributeOQL("oql", array("allowed_values"=>null, "sql"=>"oql", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeEnum("auto_reload", array("allowed_values"=>new ValueSetEnum('none,custom'), "sql"=>"auto_reload", "default_value"=>"none", "is_null_allowed"=>false, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeInteger("auto_reload_sec", array("allowed_values"=>null, "sql"=>"auto_reload_sec", "default_value"=>60, "is_null_allowed"=>false, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeOQL("oql", ["allowed_values" => null, "sql" => "oql", "default_value" => null, "is_null_allowed" => false, "depends_on" => []]));
|
||||
MetaModel::Init_AddAttribute(new AttributeEnum("auto_reload", ["allowed_values" => new ValueSetEnum('none,custom'), "sql" => "auto_reload", "default_value" => "none", "is_null_allowed" => false, "depends_on" => []]));
|
||||
MetaModel::Init_AddAttribute(new AttributeInteger("auto_reload_sec", ["allowed_values" => null, "sql" => "auto_reload_sec", "default_value" => 60, "is_null_allowed" => false, "depends_on" => []]));
|
||||
|
||||
// Display lists
|
||||
MetaModel::Init_SetZListItems('details', array('name', 'context', 'oql')); // Attributes to be displayed for the complete details
|
||||
MetaModel::Init_SetZListItems('list', array('name')); // Attributes to be displayed for a list
|
||||
MetaModel::Init_SetZListItems('details', ['name', 'context', 'oql']); // Attributes to be displayed for the complete details
|
||||
MetaModel::Init_SetZListItems('list', ['name']); // Attributes to be displayed for a list
|
||||
// Search criteria
|
||||
// MetaModel::Init_SetZListItems('standard_search', array('name')); // Criteria of the std search form
|
||||
// MetaModel::Init_SetZListItems('advanced_search', array('name')); // Criteria of the advanced search form
|
||||
// MetaModel::Init_SetZListItems('standard_search', array('name')); // Criteria of the std search form
|
||||
// MetaModel::Init_SetZListItems('advanced_search', array('name')); // Criteria of the advanced search form
|
||||
}
|
||||
|
||||
public function RenderContent(WebPage $oPage, $aExtraParams = array())
|
||||
public function RenderContent(WebPage $oPage, $aExtraParams = [])
|
||||
{
|
||||
$oPage->set_title($this->Get('name'));
|
||||
|
||||
switch($this->Get('auto_reload'))
|
||||
{
|
||||
case 'custom':
|
||||
$iRate = (int)$this->Get('auto_reload_sec');
|
||||
if ($iRate > 0)
|
||||
{
|
||||
// Must a string otherwise it can be evaluated to 'true' and defaults to "standard" refresh rate!
|
||||
$aExtraParams['auto_reload'] = (string)$iRate;
|
||||
}
|
||||
break;
|
||||
switch ($this->Get('auto_reload')) {
|
||||
case 'custom':
|
||||
$iRate = (int)$this->Get('auto_reload_sec');
|
||||
if ($iRate > 0) {
|
||||
// Must a string otherwise it can be evaluated to 'true' and defaults to "standard" refresh rate!
|
||||
$aExtraParams['auto_reload'] = (string)$iRate;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
case 'none':
|
||||
default:
|
||||
case 'none':
|
||||
}
|
||||
|
||||
$bSearchPane = true;
|
||||
$bSearchOpen = true;
|
||||
try
|
||||
{
|
||||
try {
|
||||
OQLMenuNode::RenderOQLSearch($this->Get('oql'), $this->Get('name'), 'shortcut_'.$this->GetKey(), $bSearchPane, $bSearchOpen, $oPage, $aExtraParams, true);
|
||||
}
|
||||
catch (Exception $e)
|
||||
{
|
||||
} catch (Exception $e) {
|
||||
throw new Exception("The OQL shortcut '".$this->Get('name')."' (id: ".$this->GetKey().") could not be displayed: ".$e->getMessage());
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
public function CloneTableSettings($sTableSettings)
|
||||
@@ -226,17 +221,14 @@ class ShortcutOQL extends Shortcut
|
||||
|
||||
// Find a unique default name
|
||||
// -> The class of the query + an index if necessary
|
||||
if ($sOQL == null)
|
||||
{
|
||||
if ($sOQL == null) {
|
||||
$sDefault = '';
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
$oBMSearch = new DBObjectSearch('Shortcut');
|
||||
$oBMSearch->AddCondition('user_id', UserRights::GetUserId(), '=');
|
||||
$oBMSet = new DBObjectSet($oBMSearch);
|
||||
$aNames = $oBMSet->GetColumnAsArray('name');
|
||||
$oSearch = DBObjectSearch::FromOQL($sOQL);
|
||||
$oSearch = DBObjectSearch::FromOQL($sOQL);
|
||||
$sDefault = utils::MakeUniqueName($oSearch->GetClass(), $aNames);
|
||||
}
|
||||
|
||||
@@ -276,18 +268,18 @@ class ShortcutOQL extends Shortcut
|
||||
|
||||
$oForm->Render($oPage);
|
||||
$oPage->add('</div>');
|
||||
|
||||
|
||||
$sDialogTitle = Dict::S('UI:ShortcutListDlg:Title');
|
||||
$sOkButtonLabel = Dict::S('UI:Button:Ok');
|
||||
$sCancelButtonLabel = Dict::S('UI:Button:Cancel');
|
||||
|
||||
|
||||
$oAppContext = new ApplicationContext();
|
||||
$sContext = $oAppContext->GetForLink();
|
||||
|
||||
$sRateTitle = addslashes(Dict::Format('Class:ShortcutOQL/Attribute:auto_reload_sec/tip', MetaModel::GetConfig()->Get('min_reload_interval')));
|
||||
|
||||
$oPage->add_ready_script(
|
||||
<<<JS
|
||||
<<<JS
|
||||
// Note: the title gets deleted by the validation mechanism
|
||||
$("#attr_auto_reload_sec").attr('data-tooltip-content', '$sRateTitle');
|
||||
CombodoTooltip.InitTooltipFromMarkup($("#attr_auto_reload_sec"));
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
// Copyright (C) 2010-2024 Combodo SAS
|
||||
//
|
||||
// This file is part of iTop.
|
||||
@@ -23,7 +24,6 @@ require_once(APPROOT.'core/contexttag.class.inc.php');
|
||||
require_once(APPROOT.'core/kpi.class.inc.php');
|
||||
require_once(APPROOT.'setup/setuputils.class.inc.php');
|
||||
|
||||
|
||||
/**
|
||||
* File to include to initialize the datamodel in memory
|
||||
*
|
||||
@@ -36,12 +36,10 @@ ExecutionKPI::EnableMemory(1);
|
||||
|
||||
// This storage is freed on error (case of allowed memory exhausted)
|
||||
$sReservedMemory = str_repeat('*', 1024 * 1024);
|
||||
register_shutdown_function(function()
|
||||
{
|
||||
register_shutdown_function(function () {
|
||||
global $sReservedMemory;
|
||||
$sReservedMemory = null;
|
||||
if (!is_null($err = error_get_last()) && ($err['type'] == E_ERROR))
|
||||
{
|
||||
if (!is_null($err = error_get_last()) && ($err['type'] == E_ERROR)) {
|
||||
// Remove stack trace from MySQLException (since 2.7.2 see N°3174)
|
||||
$sMessage = $err['message'];
|
||||
if (strpos($sMessage, 'MySQLException') !== false) {
|
||||
@@ -71,38 +69,30 @@ $oKPI->ComputeAndReport("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) && (Session::Get('itop_env') !== $sSwitchEnv)) {
|
||||
Session::Set('itop_env', $sSwitchEnv);
|
||||
$sEnv = $sSwitchEnv;
|
||||
$bAllowCache = false;
|
||||
// Reset the opcache since otherwise the PHP "model" files may still be cached !!
|
||||
if (function_exists('opcache_reset'))
|
||||
{
|
||||
// Zend opcode cache
|
||||
opcache_reset();
|
||||
}
|
||||
if (function_exists('apc_clear_cache'))
|
||||
{
|
||||
// APC(u) cache
|
||||
apc_clear_cache();
|
||||
}
|
||||
$bAllowCache = false;
|
||||
// Reset the opcache since otherwise the PHP "model" files may still be cached !!
|
||||
if (function_exists('opcache_reset')) {
|
||||
// Zend opcode cache
|
||||
opcache_reset();
|
||||
}
|
||||
if (function_exists('apc_clear_cache')) {
|
||||
// APC(u) cache
|
||||
apc_clear_cache();
|
||||
}
|
||||
// TODO: reset the credentials as well ??
|
||||
}
|
||||
else if (Session::IsSet('itop_env'))
|
||||
{
|
||||
} elseif (Session::IsSet('itop_env')) {
|
||||
$sEnv = Session::Get('itop_env');
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
$sEnv = ITOP_DEFAULT_ENV;
|
||||
Session::Set('itop_env', ITOP_DEFAULT_ENV);
|
||||
}
|
||||
$sConfigFile = APPCONF.$sEnv.'/'.ITOP_CONFIG_FILE;
|
||||
try {
|
||||
MetaModel::Startup($sConfigFile, false /* $bModelOnly */, $bAllowCache, false /* $bTraceSourceFiles */, $sEnv);
|
||||
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', []);
|
||||
}
|
||||
catch (MySQLException $e) {
|
||||
IssueLog::Debug($e->getMessage());
|
||||
throw new MySQLException('Could not connect to the DB server', []);
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Copyright (C) 2013-2024 Combodo SAS
|
||||
*
|
||||
@@ -30,12 +31,12 @@ class DisplayTemplate
|
||||
{
|
||||
protected $m_sTemplate;
|
||||
protected $m_aTags;
|
||||
static protected $iBlockCount = 0;
|
||||
|
||||
protected static $iBlockCount = 0;
|
||||
|
||||
public function __construct($sTemplate)
|
||||
{
|
||||
DeprecatedCallsLog::NotifyDeprecatedPhpMethod();
|
||||
$this->m_aTags = array(
|
||||
$this->m_aTags = [
|
||||
'itopblock',
|
||||
'itopcheck',
|
||||
'itoptabs',
|
||||
@@ -43,11 +44,11 @@ class DisplayTemplate
|
||||
'itoptoggle',
|
||||
'itopstring',
|
||||
'sqlblock',
|
||||
);
|
||||
];
|
||||
$this->m_sTemplate = $sTemplate;
|
||||
}
|
||||
|
||||
public function Render(WebPage $oPage, $aParams = array())
|
||||
|
||||
public function Render(WebPage $oPage, $aParams = [])
|
||||
{
|
||||
$this->m_sTemplate = MetaModel::ApplyParams($this->m_sTemplate, $aParams);
|
||||
$iStart = 0;
|
||||
@@ -55,70 +56,55 @@ class DisplayTemplate
|
||||
$iCount = 0;
|
||||
$iBeforeTagPos = $iStart;
|
||||
$iAfterTagPos = $iStart;
|
||||
while($sTag = $this->GetNextTag($iStart, $iEnd))
|
||||
{
|
||||
while ($sTag = $this->GetNextTag($iStart, $iEnd)) {
|
||||
$sContent = $this->GetTagContent($sTag, $iStart, $iEnd);
|
||||
$iAfterTagPos = $iEnd + strlen('</'.$sTag.'>');
|
||||
$sOuterTag = substr($this->m_sTemplate, $iStart, $iAfterTagPos - $iStart);
|
||||
$oPage->add(substr($this->m_sTemplate, $iBeforeTagPos, $iStart - $iBeforeTagPos));
|
||||
if ($sTag == DisplayBlock::TAG_BLOCK)
|
||||
{
|
||||
try
|
||||
{
|
||||
if ($sTag == DisplayBlock::TAG_BLOCK) {
|
||||
try {
|
||||
$oBlock = DisplayBlock::FromTemplate($sOuterTag);
|
||||
if (is_object($oBlock))
|
||||
{
|
||||
if (is_object($oBlock)) {
|
||||
$oBlock->Display($oPage, 'block_'.self::$iBlockCount, $aParams);
|
||||
}
|
||||
}
|
||||
catch(OQLException $e)
|
||||
{
|
||||
} catch (OQLException $e) {
|
||||
$oPage->p('Error in template (please contact your administrator) - Invalid query<!--'.$sOuterTag.'-->');
|
||||
}
|
||||
catch(Exception $e)
|
||||
{
|
||||
} catch (Exception $e) {
|
||||
$oPage->p('Error in template (please contact your administrator)<!--'.$e->getMessage().'--><!--'.$sOuterTag.'-->');
|
||||
}
|
||||
|
||||
|
||||
self::$iBlockCount++;
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
$aAttributes = $this->GetTagAttributes($sTag, $iStart, $iEnd);
|
||||
//$oPage->p("Tag: $sTag - ($iStart, $iEnd)");
|
||||
$this->RenderTag($oPage, $sTag, $aAttributes, $sContent);
|
||||
|
||||
|
||||
}
|
||||
$iAfterTagPos = $iEnd + strlen('</'.$sTag.'>');
|
||||
$iBeforeTagPos = $iAfterTagPos;
|
||||
$iStart = $iEnd;
|
||||
$iEnd = strlen($this->m_sTemplate);
|
||||
$iEnd = strlen($this->m_sTemplate);
|
||||
$iCount++;
|
||||
}
|
||||
$oPage->add(substr($this->m_sTemplate, $iAfterTagPos));
|
||||
}
|
||||
|
||||
|
||||
public function GetNextTag(&$iStartPos, &$iEndPos)
|
||||
{
|
||||
$iChunkStartPos = $iStartPos;
|
||||
$sNextTag = null;
|
||||
$iStartPos = $iEndPos;
|
||||
foreach($this->m_aTags as $sTag)
|
||||
{
|
||||
foreach ($this->m_aTags as $sTag) {
|
||||
// Search for the opening tag
|
||||
$iOpeningPos = stripos($this->m_sTemplate, '<'.$sTag.' ', $iChunkStartPos);
|
||||
if ($iOpeningPos === false)
|
||||
{
|
||||
if ($iOpeningPos === false) {
|
||||
$iOpeningPos = stripos($this->m_sTemplate, '<'.$sTag.'>', $iChunkStartPos);
|
||||
}
|
||||
if ($iOpeningPos !== false)
|
||||
{
|
||||
if ($iOpeningPos !== false) {
|
||||
$iClosingPos = stripos($this->m_sTemplate, '</'.$sTag.'>', $iOpeningPos);
|
||||
}
|
||||
if ( ($iOpeningPos !== false) && ($iClosingPos !== false))
|
||||
{
|
||||
if ($iOpeningPos < $iStartPos)
|
||||
{
|
||||
if (($iOpeningPos !== false) && ($iClosingPos !== false)) {
|
||||
if ($iOpeningPos < $iStartPos) {
|
||||
// This is the next tag
|
||||
$iStartPos = $iOpeningPos;
|
||||
$iEndPos = $iClosingPos;
|
||||
@@ -128,108 +114,100 @@ class DisplayTemplate
|
||||
}
|
||||
return $sNextTag;
|
||||
}
|
||||
|
||||
|
||||
public function GetTagContent($sTag, $iStartPos, $iEndPos)
|
||||
{
|
||||
$sContent = "";
|
||||
$iContentStart = strpos($this->m_sTemplate, '>', $iStartPos); // Content of tag start immediatly after the first closing bracket
|
||||
if ($iContentStart !== false)
|
||||
{
|
||||
$sContent = substr($this->m_sTemplate, 1+$iContentStart, $iEndPos - $iContentStart - 1);
|
||||
if ($iContentStart !== false) {
|
||||
$sContent = substr($this->m_sTemplate, 1 + $iContentStart, $iEndPos - $iContentStart - 1);
|
||||
}
|
||||
return $sContent;
|
||||
}
|
||||
|
||||
public function GetTagAttributes($sTag, $iStartPos, $iEndPos)
|
||||
{
|
||||
$aAttr = array();
|
||||
$aAttr = [];
|
||||
$iAttrStart = strpos($this->m_sTemplate, ' ', $iStartPos); // Attributes start just after the first space
|
||||
$iAttrEnd = strpos($this->m_sTemplate, '>', $iStartPos); // Attributes end just before the first closing bracket
|
||||
if ( ($iAttrStart !== false) && ($iAttrEnd !== false) && ($iAttrEnd > $iAttrStart))
|
||||
{
|
||||
$sAttributes = substr($this->m_sTemplate, 1+$iAttrStart, $iAttrEnd - $iAttrStart - 1);
|
||||
if (($iAttrStart !== false) && ($iAttrEnd !== false) && ($iAttrEnd > $iAttrStart)) {
|
||||
$sAttributes = substr($this->m_sTemplate, 1 + $iAttrStart, $iAttrEnd - $iAttrStart - 1);
|
||||
$aAttributes = explode(' ', $sAttributes);
|
||||
foreach($aAttributes as $sAttr)
|
||||
{
|
||||
if ( preg_match('/(.+) *= *"(.+)"$/', $sAttr, $aMatches) )
|
||||
{
|
||||
foreach ($aAttributes as $sAttr) {
|
||||
if (preg_match('/(.+) *= *"(.+)"$/', $sAttr, $aMatches)) {
|
||||
$aAttr[strtolower($aMatches[1])] = $aMatches[2];
|
||||
}
|
||||
}
|
||||
}
|
||||
return $aAttr;
|
||||
}
|
||||
|
||||
|
||||
protected function RenderTag($oPage, $sTag, $aAttributes, $sContent)
|
||||
{
|
||||
static $iTabContainerCount = 0;
|
||||
switch($sTag)
|
||||
{
|
||||
switch ($sTag) {
|
||||
case 'itoptabs':
|
||||
$oPage->AddTabContainer('Tabs_'.$iTabContainerCount);
|
||||
$oPage->SetCurrentTabContainer('Tabs_'.$iTabContainerCount);
|
||||
$iTabContainerCount++;
|
||||
//$oPage->p('Content:<pre>'.htmlentities($sContent, ENT_QUOTES, 'UTF-8').'</pre>');
|
||||
$oTemplate = new DisplayTemplate($sContent);
|
||||
$oTemplate->Render($oPage, array()); // no params to apply, they have already been applied
|
||||
$oTemplate->Render($oPage, []); // no params to apply, they have already been applied
|
||||
$oPage->SetCurrentTabContainer('');
|
||||
break;
|
||||
|
||||
break;
|
||||
|
||||
case 'itopcheck':
|
||||
$sClassName = $aAttributes['class'];
|
||||
if (MetaModel::IsValidClass($sClassName) && UserRights::IsActionAllowed($sClassName, UR_ACTION_READ))
|
||||
{
|
||||
if (MetaModel::IsValidClass($sClassName) && UserRights::IsActionAllowed($sClassName, UR_ACTION_READ)) {
|
||||
$oTemplate = new DisplayTemplate($sContent);
|
||||
$oTemplate->Render($oPage, array()); // no params to apply, they have already been applied
|
||||
}
|
||||
else
|
||||
{
|
||||
$oTemplate->Render($oPage, []); // no params to apply, they have already been applied
|
||||
} else {
|
||||
// Leave a trace for those who'd like to understand why nothing is displayed
|
||||
$oPage->add("<!-- class $sClassName does not exist, skipping some part of the template -->\n");
|
||||
}
|
||||
break;
|
||||
|
||||
break;
|
||||
|
||||
case 'itoptab':
|
||||
$oPage->SetCurrentTab($aAttributes['name'], str_replace('_', ' ', $aAttributes['name']));
|
||||
$oTemplate = new DisplayTemplate($sContent);
|
||||
$oTemplate->Render($oPage, array()); // no params to apply, they have already been applied
|
||||
$oTemplate->Render($oPage, []); // no params to apply, they have already been applied
|
||||
//$oPage->p('iTop Tab Content:<pre>'.htmlentities($sContent, ENT_QUOTES, 'UTF-8').'</pre>');
|
||||
$oPage->SetCurrentTab('');
|
||||
break;
|
||||
|
||||
break;
|
||||
|
||||
case 'itoptoggle':
|
||||
$sName = isset($aAttributes['name']) ? $aAttributes['name'] : 'Tagada';
|
||||
$bOpen = isset($aAttributes['open']) ? $aAttributes['open'] : true;
|
||||
$oPage->StartCollapsibleSection(Dict::S($sName), $bOpen);
|
||||
$oTemplate = new DisplayTemplate($sContent);
|
||||
$oTemplate->Render($oPage, array()); // no params to apply, they have already been applied
|
||||
$oTemplate->Render($oPage, []); // no params to apply, they have already been applied
|
||||
//$oPage->p('iTop Tab Content:<pre>'.htmlentities($sContent, ENT_QUOTES, 'UTF-8').'</pre>');
|
||||
$oPage->EndCollapsibleSection();
|
||||
break;
|
||||
|
||||
break;
|
||||
|
||||
case 'itopstring':
|
||||
$oPage->add(Dict::S($sContent));
|
||||
break;
|
||||
|
||||
break;
|
||||
|
||||
case 'sqlblock':
|
||||
$oBlock = SqlBlock::FromTemplate($sContent);
|
||||
$oBlock->RenderContent($oPage);
|
||||
break;
|
||||
|
||||
break;
|
||||
|
||||
case 'itopblock': // No longer used, handled by DisplayBlock::FromTemplate see above
|
||||
$oPage->add("<!-- Application Error: should be handled by DisplayBlock::FromTemplate -->");
|
||||
break;
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
// Unknown tag, just ignore it or now -- output an HTML comment
|
||||
$oPage->add("<!-- unsupported tag: $sTag -->");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Unit test
|
||||
*/
|
||||
static public function UnitTest()
|
||||
public static function UnitTest()
|
||||
{
|
||||
require_once(APPROOT.'/application/startup.inc.php');
|
||||
|
||||
@@ -250,11 +228,11 @@ class DisplayTemplate
|
||||
<itopblock blockclass="DisplayBlock" type="list" encoding="text/oql">SELECT Document AS d JOIN lnkDocumentToCI as l ON l.document_id = d.id WHERE l.ci_id = $id$)</itopblock>
|
||||
</itoptab>
|
||||
</itoptabs>';
|
||||
|
||||
|
||||
$oPage = new iTopWebPage('Unit Test');
|
||||
//$oPage->add("Template content: <pre>".htmlentities($sTemplate, ENT_QUOTES, 'UTF-8')."</pre>\n");
|
||||
$oTemplate = new DisplayTemplate($sTemplate);
|
||||
$oTemplate->Render($oPage, array('class'=>'Network device','pkey'=> 271, 'name' => 'deliversw01.mecanorama.fr', 'org_id' => 3));
|
||||
$oTemplate->Render($oPage, ['class' => 'Network device','pkey' => 271, 'name' => 'deliversw01.mecanorama.fr', 'org_id' => 3]);
|
||||
$oPage->output();
|
||||
}
|
||||
}
|
||||
@@ -275,89 +253,68 @@ class ObjectDetailsTemplate extends DisplayTemplate
|
||||
$this->m_oObj = $oObj;
|
||||
$this->m_sPrefix = $sFormPrefix;
|
||||
}
|
||||
|
||||
public function Render(WebPage $oPage, $aParams = array(), $bEditMode = false)
|
||||
|
||||
public function Render(WebPage $oPage, $aParams = [], $bEditMode = false)
|
||||
{
|
||||
$sStateAttCode = MetaModel :: GetStateAttributeCode(get_class($this->m_oObj));
|
||||
$aTemplateFields = array();
|
||||
$sStateAttCode = MetaModel::GetStateAttributeCode(get_class($this->m_oObj));
|
||||
$aTemplateFields = [];
|
||||
preg_match_all('/\\$this->([a-z0-9_]+)\\$/', $this->m_sTemplate, $aMatches);
|
||||
foreach ($aMatches[1] as $sAttCode)
|
||||
{
|
||||
if (MetaModel::IsValidAttCode(get_class($this->m_oObj), $sAttCode))
|
||||
{
|
||||
foreach ($aMatches[1] as $sAttCode) {
|
||||
if (MetaModel::IsValidAttCode(get_class($this->m_oObj), $sAttCode)) {
|
||||
$aTemplateFields[] = $sAttCode;
|
||||
}
|
||||
else
|
||||
{
|
||||
$aParams['this->'.$sAttCode] = "<!--Unknown attribute: $sAttCode-->";
|
||||
} else {
|
||||
$aParams['this->'.$sAttCode] = "<!--Unknown attribute: $sAttCode-->";
|
||||
}
|
||||
}
|
||||
preg_match_all('/\\$this->field\\(([a-z0-9_]+)\\)\\$/', $this->m_sTemplate, $aMatches);
|
||||
foreach ($aMatches[1] as $sAttCode)
|
||||
{
|
||||
if (MetaModel::IsValidAttCode(get_class($this->m_oObj), $sAttCode))
|
||||
{
|
||||
foreach ($aMatches[1] as $sAttCode) {
|
||||
if (MetaModel::IsValidAttCode(get_class($this->m_oObj), $sAttCode)) {
|
||||
$aTemplateFields[] = $sAttCode;
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
$aParams['this->field('.$sAttCode.')'] = "<!--Unknown attribute: $sAttCode-->";
|
||||
}
|
||||
}
|
||||
$aFieldsComments = (isset($aParams['fieldsComments'])) ? $aParams['fieldsComments'] : array();
|
||||
$aFieldsMap = array();
|
||||
$aFieldsComments = (isset($aParams['fieldsComments'])) ? $aParams['fieldsComments'] : [];
|
||||
$aFieldsMap = [];
|
||||
|
||||
$sClass = get_class($this->m_oObj);
|
||||
// Renders the fields used in the template
|
||||
foreach(MetaModel::ListAttributeDefs(get_class($this->m_oObj)) as $sAttCode => $oAttDef)
|
||||
{
|
||||
foreach (MetaModel::ListAttributeDefs(get_class($this->m_oObj)) as $sAttCode => $oAttDef) {
|
||||
$aParams['this->label('.$sAttCode.')'] = $oAttDef->GetLabel();
|
||||
$aParams['this->comments('.$sAttCode.')'] = isset($aFieldsComments[$sAttCode]) ? $aFieldsComments[$sAttCode] : '';
|
||||
$iInputId = '2_'.$sAttCode; // TODO: generate a real/unique prefix...
|
||||
if (in_array($sAttCode, $aTemplateFields))
|
||||
{
|
||||
if ($this->m_oObj->IsNew())
|
||||
{
|
||||
if (in_array($sAttCode, $aTemplateFields)) {
|
||||
if ($this->m_oObj->IsNew()) {
|
||||
$iFlags = $this->m_oObj->GetInitialStateAttributeFlags($sAttCode);
|
||||
} else {
|
||||
$iFlags = $this->m_oObj->GetAttributeFlags($sAttCode);
|
||||
}
|
||||
else
|
||||
{
|
||||
$iFlags = $this->m_oObj->GetAttributeFlags($sAttCode);
|
||||
}
|
||||
if (($iFlags & OPT_ATT_MANDATORY) && $this->m_oObj->IsNew())
|
||||
{
|
||||
if (($iFlags & OPT_ATT_MANDATORY) && $this->m_oObj->IsNew()) {
|
||||
$iFlags = $iFlags & ~OPT_ATT_READONLY; // Mandatory fields cannot be read-only when creating an object
|
||||
}
|
||||
|
||||
if ((!$oAttDef->IsWritable()) || ($sStateAttCode == $sAttCode))
|
||||
{
|
||||
|
||||
if ((!$oAttDef->IsWritable()) || ($sStateAttCode == $sAttCode)) {
|
||||
$iFlags = $iFlags | OPT_ATT_READONLY;
|
||||
}
|
||||
|
||||
if ($iFlags & OPT_ATT_HIDDEN)
|
||||
{
|
||||
if ($iFlags & OPT_ATT_HIDDEN) {
|
||||
$aParams['this->label('.$sAttCode.')'] = '';
|
||||
$aParams['this->field('.$sAttCode.')'] = '';
|
||||
$aParams['this->comments('.$sAttCode.')'] = '';
|
||||
$aParams['this->'.$sAttCode] = '';
|
||||
}
|
||||
else
|
||||
{
|
||||
if ($bEditMode && ($iFlags & (OPT_ATT_READONLY|OPT_ATT_SLAVE)))
|
||||
{
|
||||
} else {
|
||||
if ($bEditMode && ($iFlags & (OPT_ATT_READONLY | OPT_ATT_SLAVE))) {
|
||||
// Check if the attribute is not read-only because of a synchro...
|
||||
$aReasons = array();
|
||||
$aReasons = [];
|
||||
$sSynchroIcon = '';
|
||||
if ($iFlags & OPT_ATT_SLAVE)
|
||||
{
|
||||
if ($iFlags & OPT_ATT_SLAVE) {
|
||||
$iSynchroFlags = $this->m_oObj->GetSynchroReplicaFlags($sAttCode, $aReasons);
|
||||
$sAppRooturl = utils::GetAbsoluteUrlAppRoot();
|
||||
$sSynchroIcon = " <img id=\"synchro_$iInputId\" src=\"{$sAppRooturl}images/transp-lock.png\" style=\"vertical-align:middle\"/>";
|
||||
$sTip = '';
|
||||
foreach($aReasons as $aRow)
|
||||
{
|
||||
foreach ($aReasons as $aRow) {
|
||||
$sDescription = utils::EscapeHtml($aRow['description']);
|
||||
$sDescription = str_replace(array("\r\n", "\n"), "<br/>", $sDescription);
|
||||
$sDescription = str_replace(["\r\n", "\n"], "<br/>", $sDescription);
|
||||
$sTip .= "<div class='synchro-source'>";
|
||||
$sTip .= "<div class='synchro-source-title'>Synchronized with {$aRow['name']}</div>";
|
||||
$sTip .= "<div class='synchro-source-description'>$sDescription</div>";
|
||||
@@ -371,46 +328,43 @@ class ObjectDetailsTemplate extends DisplayTemplate
|
||||
$aFieldsMap[$sAttCode] = $iInputId;
|
||||
$aParams['this->comments('.$sAttCode.')'] = $sSynchroIcon;
|
||||
}
|
||||
|
||||
if ($bEditMode && !($iFlags & OPT_ATT_READONLY)) //TODO: check the data synchro status...
|
||||
{
|
||||
$aParams['this->field('.$sAttCode.')'] = "<span id=\"field_{$iInputId}\">".$this->m_oObj->GetFormElementForField($oPage, $sClass, $sAttCode, $oAttDef,
|
||||
$this->m_oObj->Get($sAttCode),
|
||||
$this->m_oObj->GetEditValue($sAttCode),
|
||||
$iInputId, // InputID
|
||||
'',
|
||||
$iFlags,
|
||||
array('this' => $this->m_oObj) // aArgs
|
||||
).'</span>';
|
||||
$aFieldsMap[$sAttCode] = $iInputId;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
if ($bEditMode && !($iFlags & OPT_ATT_READONLY)) { //TODO: check the data synchro status...
|
||||
$aParams['this->field('.$sAttCode.')'] = "<span id=\"field_{$iInputId}\">".$this->m_oObj->GetFormElementForField(
|
||||
$oPage,
|
||||
$sClass,
|
||||
$sAttCode,
|
||||
$oAttDef,
|
||||
$this->m_oObj->Get($sAttCode),
|
||||
$this->m_oObj->GetEditValue($sAttCode),
|
||||
$iInputId, // InputID
|
||||
'',
|
||||
$iFlags,
|
||||
['this' => $this->m_oObj] // aArgs
|
||||
).'</span>';
|
||||
$aFieldsMap[$sAttCode] = $iInputId;
|
||||
} else {
|
||||
$aParams['this->field('.$sAttCode.')'] = $this->m_oObj->GetAsHTML($sAttCode);
|
||||
}
|
||||
$aParams['this->'.$sAttCode] = "<table class=\"field\"><tr><td class=\"label\">".$aParams['this->label('.$sAttCode.')'].":</td><td>".$aParams['this->field('.$sAttCode.')']."</td><td>".$aParams['this->comments('.$sAttCode.')']."</td></tr></table>";
|
||||
$aParams['this->'.$sAttCode] = "<table class=\"field\"><tr><td class=\"label\">".$aParams['this->label('.$sAttCode.')'].":</td><td>".$aParams['this->field('.$sAttCode.')']."</td><td>".$aParams['this->comments('.$sAttCode.')']."</td></tr></table>";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Renders the PlugIns used in the template
|
||||
preg_match_all('/\\$PlugIn:([A-Za-z0-9_]+)->properties\\(\\)\\$/', $this->m_sTemplate, $aMatches);
|
||||
$aPlugInProperties = $aMatches[1];
|
||||
foreach($aPlugInProperties as $sPlugInClass)
|
||||
{
|
||||
foreach ($aPlugInProperties as $sPlugInClass) {
|
||||
/** @var \iApplicationUIExtension $oInstance */
|
||||
$oInstance = MetaModel::GetPlugins('iApplicationUIExtension', $sPlugInClass);
|
||||
if ($oInstance != null) // Safety check...
|
||||
{
|
||||
if ($oInstance != null) { // Safety check...
|
||||
$offset = $oPage->start_capture();
|
||||
$oInstance->OnDisplayProperties($this->m_oObj, $oPage, $bEditMode);
|
||||
$sContent = $oPage->end_capture($offset);
|
||||
$aParams["PlugIn:{$sPlugInClass}->properties()"]= $sContent;
|
||||
$aParams["PlugIn:{$sPlugInClass}->properties()"] = $sContent;
|
||||
} else {
|
||||
$aParams["PlugIn:{$sPlugInClass}->properties()"] = "Missing PlugIn: $sPlugInClass";
|
||||
}
|
||||
else
|
||||
{
|
||||
$aParams["PlugIn:{$sPlugInClass}->properties()"]= "Missing PlugIn: $sPlugInClass";
|
||||
}
|
||||
}
|
||||
|
||||
$offset = $oPage->start_capture();
|
||||
@@ -424,4 +378,3 @@ class ObjectDetailsTemplate extends DisplayTemplate
|
||||
}
|
||||
|
||||
//DisplayTemplate::UnitTest();
|
||||
?>
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Copyright (C) 2013-2024 Combodo SAS
|
||||
*
|
||||
@@ -25,7 +26,7 @@
|
||||
*/
|
||||
class ThemeHandler
|
||||
{
|
||||
const IMAGE_EXTENSIONS = ['png', 'gif', 'jpg', 'jpeg'];
|
||||
public const IMAGE_EXTENSIONS = ['png', 'gif', 'jpg', 'jpeg'];
|
||||
|
||||
/** @var \CompileCSSService */
|
||||
private static $oCompileCSSService;
|
||||
@@ -50,7 +51,7 @@ class ThemeHandler
|
||||
'imports' => [],
|
||||
'stylesheets' => [
|
||||
'main' => '../css/backoffice/main.scss',
|
||||
]
|
||||
],
|
||||
],
|
||||
];
|
||||
}
|
||||
@@ -75,8 +76,7 @@ class ThemeHandler
|
||||
{
|
||||
try {
|
||||
$sThemeId = utils::GetConfig()->Get('backoffice_default_theme');
|
||||
}
|
||||
catch (CoreException $oCompileException) {
|
||||
} catch (CoreException $oCompileException) {
|
||||
// Fallback on our default theme in case the config. is not available yet
|
||||
$aDefaultTheme = ThemeHandler::GetDefaultThemeInformation();
|
||||
$sThemeId = $aDefaultTheme['name'];
|
||||
@@ -97,8 +97,7 @@ class ThemeHandler
|
||||
if (true === utils::GetConfig()->Get('user_preferences.allow_backoffice_theme_override')) {
|
||||
$sThemeId = appUserPreferences::GetPref('backoffice_theme', null);
|
||||
}
|
||||
}
|
||||
catch (Exception $oException) {
|
||||
} catch (Exception $oException) {
|
||||
// Do nothing, already handled by $sThemeId null by default
|
||||
}
|
||||
|
||||
@@ -213,8 +212,7 @@ class ThemeHandler
|
||||
if (static::ShouldThemeSignatureCheckBeForced($sThemeId)) {
|
||||
static::CompileTheme($sThemeId);
|
||||
}
|
||||
}
|
||||
catch (CoreException $oCompileException) {
|
||||
} catch (CoreException $oCompileException) {
|
||||
// Fallback on our default theme (should always be compilable) in case the previous theme doesn't exists
|
||||
$aDefaultTheme = ThemeHandler::GetDefaultThemeInformation();
|
||||
$sThemeId = $aDefaultTheme['name'];
|
||||
@@ -270,13 +268,16 @@ class ThemeHandler
|
||||
* @throws \CoreException
|
||||
* @return boolean: indicate whether theme compilation occured
|
||||
*/
|
||||
public static function CompileTheme($sThemeId, $bSetup=false, $sSetupCompilationTimestamp="", $aThemeParameters = null, $aImportsPaths = null, $sWorkingPath = null) {
|
||||
public static function CompileTheme($sThemeId, $bSetup = false, $sSetupCompilationTimestamp = "", $aThemeParameters = null, $aImportsPaths = null, $sWorkingPath = null)
|
||||
{
|
||||
if ($sSetupCompilationTimestamp === "") {
|
||||
$sSetupCompilationTimestamp = microtime(true);
|
||||
}
|
||||
|
||||
$sSetupCompilationTimestampInSecunds = (strpos($sSetupCompilationTimestamp, '.') !== false) ? explode('.',
|
||||
$sSetupCompilationTimestamp)[0] : $sSetupCompilationTimestamp;
|
||||
$sSetupCompilationTimestampInSecunds = (strpos($sSetupCompilationTimestamp, '.') !== false) ? explode(
|
||||
'.',
|
||||
$sSetupCompilationTimestamp
|
||||
)[0] : $sSetupCompilationTimestamp;
|
||||
|
||||
$sEnv = APPROOT.'env-'.utils::GetCurrentEnvironment().'/';
|
||||
|
||||
@@ -329,7 +330,7 @@ class ThemeHandler
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($oFindStylesheetObject->GetStylesheetFileURIs() as $sStylesheet){
|
||||
foreach ($oFindStylesheetObject->GetStylesheetFileURIs() as $sStylesheet) {
|
||||
$sTmpThemeScssContent .= '@import "'.$sStylesheet.'";'."\n";
|
||||
}
|
||||
|
||||
@@ -341,11 +342,9 @@ class ThemeHandler
|
||||
|
||||
$iStyleLastModified = $oFindStylesheetObject->GetLastModified();
|
||||
|
||||
$aIncludedImages=static::GetIncludedImages($aThemeParametersWithVersion, $oFindStylesheetObject->GetAllStylesheetPaths(), $sThemeId);
|
||||
foreach ($aIncludedImages as $sImage)
|
||||
{
|
||||
if (is_file($sImage))
|
||||
{
|
||||
$aIncludedImages = static::GetIncludedImages($aThemeParametersWithVersion, $oFindStylesheetObject->GetAllStylesheetPaths(), $sThemeId);
|
||||
foreach ($aIncludedImages as $sImage) {
|
||||
if (is_file($sImage)) {
|
||||
$iStylesheetLastModified = @filemtime($sImage);
|
||||
$iStyleLastModified = $iStyleLastModified < $iStylesheetLastModified ? $iStylesheetLastModified : $iStyleLastModified;
|
||||
}
|
||||
@@ -354,34 +353,28 @@ class ThemeHandler
|
||||
// Checking if our compiled css is outdated
|
||||
$iFilemetime = @filemtime($sThemeCssPath);
|
||||
$bFileExists = file_exists($sThemeCssPath);
|
||||
$bVarSignatureChanged=false;
|
||||
if ($bFileExists && $bSetup)
|
||||
{
|
||||
$bVarSignatureChanged = false;
|
||||
if ($bFileExists && $bSetup) {
|
||||
$sPrecompiledSignature = static::GetSignature($sThemeCssPath);
|
||||
//check variable signature has changed which is independant from any file modification
|
||||
if (!empty($sPrecompiledSignature)){
|
||||
if (!empty($sPrecompiledSignature)) {
|
||||
$sPreviousVariableSignature = static::GetVarSignature($sPrecompiledSignature);
|
||||
$sCurrentVariableSignature = md5(json_encode($aThemeParameters['variables']));
|
||||
$bVarSignatureChanged= ($sPreviousVariableSignature!==$sCurrentVariableSignature);
|
||||
$bVarSignatureChanged = ($sPreviousVariableSignature !== $sCurrentVariableSignature);
|
||||
}
|
||||
}
|
||||
|
||||
if (!$bFileExists || $bVarSignatureChanged || (is_writable($sThemeFolderPath) && ($iFilemetime < $iStyleLastModified)))
|
||||
{
|
||||
if (!$bFileExists || $bVarSignatureChanged || (is_writable($sThemeFolderPath) && ($iFilemetime < $iStyleLastModified))) {
|
||||
// Dates don't match. Second chance: check if the already compiled stylesheet exists and is consistent based on its signature
|
||||
$sActualSignature = static::ComputeSignature($aThemeParameters, $aImportsPaths, $aIncludedImages);
|
||||
|
||||
if ($bFileExists && !$bSetup)
|
||||
{
|
||||
if ($bFileExists && !$bSetup) {
|
||||
$sPrecompiledSignature = static::GetSignature($sThemeCssPath);
|
||||
}
|
||||
|
||||
if (!empty($sPrecompiledSignature) && $sActualSignature == $sPrecompiledSignature)
|
||||
{
|
||||
if (!empty($sPrecompiledSignature) && $sActualSignature == $sPrecompiledSignature) {
|
||||
touch($sThemeCssPath); // Stylesheet is up to date, mark it as more recent to speedup next time
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
// Alas, we really need to recompile
|
||||
// Add the signature to the generated CSS file so that the file can be used as a precompiled stylesheet if needed
|
||||
$sSignatureComment =
|
||||
@@ -393,14 +386,16 @@ $sActualSignature
|
||||
*/
|
||||
|
||||
CSS;
|
||||
if (!static::$oCompileCSSService)
|
||||
{
|
||||
if (!static::$oCompileCSSService) {
|
||||
static::$oCompileCSSService = new CompileCSSService();
|
||||
}
|
||||
//store it again to change $version with latest compiled time
|
||||
SetupLog::Info("Compiling theme $sThemeId...");
|
||||
$sTmpThemeCssContent = static::$oCompileCSSService->CompileCSSFromSASS($sTmpThemeScssContent, $aImportsPaths,
|
||||
$aThemeParametersWithVersion);
|
||||
$sTmpThemeCssContent = static::$oCompileCSSService->CompileCSSFromSASS(
|
||||
$sTmpThemeScssContent,
|
||||
$aImportsPaths,
|
||||
$aThemeParametersWithVersion
|
||||
);
|
||||
SetupLog::Info("$sThemeId theme compilation done.");
|
||||
file_put_contents($sThemeFolderPath.'/theme-parameters.json', json_encode($aThemeParameters));
|
||||
file_put_contents($sThemeCssPath, $sSignatureComment.$sTmpThemeCssContent);
|
||||
@@ -425,13 +420,14 @@ CSS;
|
||||
* @return string
|
||||
* @throws \Exception
|
||||
*/
|
||||
public static function ComputeSignature($aThemeParameters, $aImportsPaths, $aIncludedImages) {
|
||||
public static function ComputeSignature($aThemeParameters, $aImportsPaths, $aIncludedImages)
|
||||
{
|
||||
$aSignature = [
|
||||
'variables' => md5(json_encode($aThemeParameters['variables'])),
|
||||
'stylesheets' => [],
|
||||
'variable_imports' => [],
|
||||
'images' => [],
|
||||
'utility_imports' => []
|
||||
'utility_imports' => [],
|
||||
];
|
||||
|
||||
$oFindStylesheetObject = new FindStylesheetObject();
|
||||
@@ -473,8 +469,7 @@ CSS;
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($aIncludedImages as $sImage)
|
||||
{
|
||||
foreach ($aIncludedImages as $sImage) {
|
||||
if (is_file($sImage)) {
|
||||
$sUri = str_replace(self::GetAppRootWithSlashes(), '', $sImage);
|
||||
$aSignature['images'][$sUri] = md5_file($sImage);
|
||||
@@ -501,7 +496,7 @@ CSS;
|
||||
$aCompleteUrls = [];
|
||||
$aToCompleteUrls = [];
|
||||
$aMissingVariables = [];
|
||||
$aFoundVariables = ['version'=>''];
|
||||
$aFoundVariables = ['version' => ''];
|
||||
$aMap = [
|
||||
'aCompleteUrls' => $aCompleteUrls,
|
||||
'aToCompleteUrls' => $aToCompleteUrls,
|
||||
@@ -509,14 +504,11 @@ CSS;
|
||||
'aFoundVariables' => $aFoundVariables,
|
||||
];
|
||||
|
||||
foreach ($aStylesheetFiles as $sStylesheetFile)
|
||||
{
|
||||
foreach ($aStylesheetFiles as $sStylesheetFile) {
|
||||
$aRes = static::GetAllUrlFromScss($aThemeParametersVariables, $sStylesheetFile);
|
||||
/** @var array $aVal */
|
||||
foreach($aMap as $key => $aVal)
|
||||
{
|
||||
if (array_key_exists($key, $aMap))
|
||||
{
|
||||
foreach ($aMap as $key => $aVal) {
|
||||
if (array_key_exists($key, $aMap)) {
|
||||
$aMap[$key] = array_merge($aVal, $aRes[$key]);
|
||||
}
|
||||
}
|
||||
@@ -525,17 +517,14 @@ CSS;
|
||||
$aMap = static::ResolveUncompleteUrlsFromScss($aMap, $aThemeParametersVariables, $aStylesheetFiles);
|
||||
$aImages = [];
|
||||
|
||||
foreach ($aMap ['aCompleteUrls'] as $sUri => $sUrl)
|
||||
{
|
||||
foreach ($aMap ['aCompleteUrls'] as $sUri => $sUrl) {
|
||||
$sImg = $sUrl;
|
||||
if (preg_match("/(.*)\?/", $sUrl, $aMatches))
|
||||
{
|
||||
$sImg=$aMatches[1];
|
||||
if (preg_match("/(.*)\?/", $sUrl, $aMatches)) {
|
||||
$sImg = $aMatches[1];
|
||||
}
|
||||
|
||||
if (static::HasImageExtension($sImg)
|
||||
&& ! array_key_exists($sImg, $aImages))
|
||||
{
|
||||
&& ! array_key_exists($sImg, $aImages)) {
|
||||
$sFilePath = utils::RealPath($sImg, APPROOT);
|
||||
if ($sFilePath !== false) {
|
||||
$sFilePathWithSlashes = str_replace('\\', '/', $sFilePath);
|
||||
@@ -566,8 +555,8 @@ CSS;
|
||||
*/
|
||||
public static function CanonicalizePath($path)
|
||||
{
|
||||
$path = explode('/', str_replace('//','/', $path));
|
||||
$stack = array();
|
||||
$path = explode('/', str_replace('//', '/', $path));
|
||||
$stack = [];
|
||||
foreach ($path as $seg) {
|
||||
if ($seg == '..') {
|
||||
// Ignore this segment, remove last segment from stack
|
||||
@@ -597,25 +586,23 @@ CSS;
|
||||
*/
|
||||
public static function ResolveUncompleteUrlsFromScss($aMap, $aThemeParametersVariables, $aStylesheetFile)
|
||||
{
|
||||
$sContent="";
|
||||
foreach ($aStylesheetFile as $sStylesheetFile)
|
||||
{
|
||||
if (is_file($sStylesheetFile))
|
||||
{
|
||||
$sContent .= '\n' . file_get_contents($sStylesheetFile);
|
||||
$sContent = "";
|
||||
foreach ($aStylesheetFile as $sStylesheetFile) {
|
||||
if (is_file($sStylesheetFile)) {
|
||||
$sContent .= '\n'.file_get_contents($sStylesheetFile);
|
||||
}
|
||||
}
|
||||
|
||||
$aMissingVariables=$aMap['aMissingVariables'];
|
||||
$aFoundVariables=$aMap['aFoundVariables'];
|
||||
$aToCompleteUrls=$aMap['aToCompleteUrls'];
|
||||
$aCompleteUrls=$aMap['aCompleteUrls'];
|
||||
$aMissingVariables = $aMap['aMissingVariables'];
|
||||
$aFoundVariables = $aMap['aFoundVariables'];
|
||||
$aToCompleteUrls = $aMap['aToCompleteUrls'];
|
||||
$aCompleteUrls = $aMap['aCompleteUrls'];
|
||||
list($aMissingVariables, $aFoundVariables) = static::FindMissingVariables($aThemeParametersVariables, $aMissingVariables, $aFoundVariables, $sContent, true);
|
||||
list($aToCompleteUrls, $aCompleteUrls) = static::ResolveUrls($aFoundVariables, $aToCompleteUrls, $aCompleteUrls);
|
||||
$aMap['aMissingVariables']=$aMissingVariables;
|
||||
$aMap['aFoundVariables']=$aFoundVariables;
|
||||
$aMap['aToCompleteUrls']=$aToCompleteUrls;
|
||||
$aMap['aCompleteUrls']=$aCompleteUrls;
|
||||
$aMap['aMissingVariables'] = $aMissingVariables;
|
||||
$aMap['aFoundVariables'] = $aFoundVariables;
|
||||
$aMap['aToCompleteUrls'] = $aToCompleteUrls;
|
||||
$aMap['aCompleteUrls'] = $aCompleteUrls;
|
||||
return $aMap;
|
||||
}
|
||||
|
||||
@@ -631,43 +618,29 @@ CSS;
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function FindMissingVariables($aThemeParametersVariables, $aMissingVariables, $aFoundVariables, $sContent, $bForceEmptyValueWhenNotFound=false)
|
||||
public static function FindMissingVariables($aThemeParametersVariables, $aMissingVariables, $aFoundVariables, $sContent, $bForceEmptyValueWhenNotFound = false)
|
||||
{
|
||||
$aNewMissingVars = [];
|
||||
if (!empty($aMissingVariables))
|
||||
{
|
||||
foreach ($aMissingVariables as $var)
|
||||
{
|
||||
if (array_key_exists($var, $aThemeParametersVariables))
|
||||
{
|
||||
if (!empty($aMissingVariables)) {
|
||||
foreach ($aMissingVariables as $var) {
|
||||
if (array_key_exists($var, $aThemeParametersVariables)) {
|
||||
$aFoundVariables[$var] = $aThemeParametersVariables[$var];
|
||||
}
|
||||
else
|
||||
{
|
||||
if (preg_match_all("/\\\$$var\s*:\s*[\"']{0,1}(.*)[\"']{0,1};/", $sContent, $aValues))
|
||||
{
|
||||
} else {
|
||||
if (preg_match_all("/\\\$$var\s*:\s*[\"']{0,1}(.*)[\"']{0,1};/", $sContent, $aValues)) {
|
||||
$sValue = $aValues[1][0];
|
||||
if (preg_match_all("/([^!]+)!/", $sValue, $aSubValues))
|
||||
{
|
||||
if (preg_match_all("/([^!]+)!/", $sValue, $aSubValues)) {
|
||||
$sValue = trim($aSubValues[1][0], ' "\'');
|
||||
}
|
||||
|
||||
if (strpos($sValue, '$') === false)
|
||||
{
|
||||
if (strpos($sValue, '$') === false) {
|
||||
$aFoundVariables[$var] = $sValue;
|
||||
}
|
||||
else{
|
||||
} else {
|
||||
$aNewMissingVars[] = $var;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if ($bForceEmptyValueWhenNotFound)
|
||||
{
|
||||
} else {
|
||||
if ($bForceEmptyValueWhenNotFound) {
|
||||
$aFoundVariables[$var] = '';
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
$aNewMissingVars[] = $var;
|
||||
}
|
||||
}
|
||||
@@ -688,32 +661,23 @@ CSS;
|
||||
*/
|
||||
public static function ResolveUrls($aFoundVariables, array $aToCompleteUrls, array $aCompleteUrls)
|
||||
{
|
||||
if (!empty($aFoundVariables))
|
||||
{
|
||||
if (!empty($aFoundVariables)) {
|
||||
$aFoundVariablesWithEmptyValue = [];
|
||||
foreach ($aFoundVariables as $aFoundVariable => $sValue)
|
||||
{
|
||||
foreach ($aFoundVariables as $aFoundVariable => $sValue) {
|
||||
$aFoundVariablesWithEmptyValue[$aFoundVariable] = '';
|
||||
}
|
||||
|
||||
foreach ($aToCompleteUrls as $sUrlTemplate)
|
||||
{
|
||||
foreach ($aToCompleteUrls as $sUrlTemplate) {
|
||||
unset($aToCompleteUrls[$sUrlTemplate]);
|
||||
$sResolvedUrl = static::ResolveUrl($sUrlTemplate, $aFoundVariables);
|
||||
if ($sResolvedUrl == false)
|
||||
{
|
||||
if ($sResolvedUrl == false) {
|
||||
$aToCompleteUrls[$sUrlTemplate] = $sUrlTemplate;
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
$sUri = static::ResolveUrl($sUrlTemplate, $aFoundVariablesWithEmptyValue);
|
||||
$aExplodedUri = explode('?', $sUri);
|
||||
if (empty($aExplodedUri))
|
||||
{
|
||||
if (empty($aExplodedUri)) {
|
||||
$aCompleteUrls[$sUri] = $sResolvedUrl;
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
$aCompleteUrls[$aExplodedUri[0]] = $sResolvedUrl;
|
||||
}
|
||||
}
|
||||
@@ -738,41 +702,31 @@ CSS;
|
||||
$aMissingVariables = [];
|
||||
$aFoundVariables = [];
|
||||
|
||||
if (is_file($sStylesheetFile))
|
||||
{
|
||||
if (is_file($sStylesheetFile)) {
|
||||
$sContent = file_get_contents($sStylesheetFile);
|
||||
if (preg_match_all("/url\s*\((.*)\)/", $sContent, $aMatches))
|
||||
{
|
||||
foreach ($aMatches[1] as $path)
|
||||
{
|
||||
if (preg_match_all("/url\s*\((.*)\)/", $sContent, $aMatches)) {
|
||||
foreach ($aMatches[1] as $path) {
|
||||
$iRemainingClosingParenthesisPos = strpos($path, ')');
|
||||
if ($iRemainingClosingParenthesisPos !== false){
|
||||
if ($iRemainingClosingParenthesisPos !== false) {
|
||||
$path = substr($path, 0, $iRemainingClosingParenthesisPos);
|
||||
}
|
||||
if (!array_key_exists($path, $aCompleteUrls)
|
||||
&& !array_key_exists($path, $aToCompleteUrls))
|
||||
{
|
||||
if (preg_match_all("/\\$([\w\-_]+)/", $path, $aCurrentVars))
|
||||
{
|
||||
&& !array_key_exists($path, $aToCompleteUrls)) {
|
||||
if (preg_match_all("/\\$([\w\-_]+)/", $path, $aCurrentVars)) {
|
||||
/** @var string $aCurrentVars */
|
||||
foreach ($aCurrentVars[1] as $var)
|
||||
{
|
||||
if (!array_key_exists($var, $aMissingVariables))
|
||||
{
|
||||
foreach ($aCurrentVars[1] as $var) {
|
||||
if (!array_key_exists($var, $aMissingVariables)) {
|
||||
$aMissingVariables[$var] = $var;
|
||||
}
|
||||
}
|
||||
$aToCompleteUrls[$path] = $path;
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
$aCompleteUrls[$path] = trim($path, "\"'");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!empty($aMissingVariables))
|
||||
{
|
||||
if (!empty($aMissingVariables)) {
|
||||
list($aMissingVariables, $aFoundVariables) = static::FindMissingVariables($aThemeParametersVariables, $aMissingVariables, $aFoundVariables, $sContent);
|
||||
list($aToCompleteUrls, $aCompleteUrls) = static::ResolveUrls($aFoundVariables, $aToCompleteUrls, $aCompleteUrls);
|
||||
}
|
||||
@@ -782,7 +736,7 @@ CSS;
|
||||
'aCompleteUrls' => $aCompleteUrls,
|
||||
'aToCompleteUrls' => $aToCompleteUrls,
|
||||
'aMissingVariables' => $aMissingVariables,
|
||||
'aFoundVariables' => $aFoundVariables
|
||||
'aFoundVariables' => $aFoundVariables,
|
||||
];
|
||||
}
|
||||
|
||||
@@ -796,23 +750,21 @@ CSS;
|
||||
*/
|
||||
public static function ResolveUrl($sUrlTemplate, $aFoundVariables)
|
||||
{
|
||||
$aPattern= [];
|
||||
$aReplacement= [];
|
||||
foreach ($aFoundVariables as $aFoundVariable => $aFoundVariableValue)
|
||||
{
|
||||
$aPattern = [];
|
||||
$aReplacement = [];
|
||||
foreach ($aFoundVariables as $aFoundVariable => $aFoundVariableValue) {
|
||||
//XX + $key + YY
|
||||
$aPattern[]="/['\"]\s*\+\s*\\\$" . $aFoundVariable . "[\s\+]+\s*['\"]/";
|
||||
$aReplacement[]=$aFoundVariableValue;
|
||||
$aPattern[] = "/['\"]\s*\+\s*\\\$".$aFoundVariable."[\s\+]+\s*['\"]/";
|
||||
$aReplacement[] = $aFoundVariableValue;
|
||||
//$key + YY
|
||||
$aPattern[]="/\\\$" . $aFoundVariable. "[\s\+]+\s*['\"]/";
|
||||
$aReplacement[]=$aFoundVariableValue;
|
||||
$aPattern[] = "/\\\$".$aFoundVariable."[\s\+]+\s*['\"]/";
|
||||
$aReplacement[] = $aFoundVariableValue;
|
||||
//XX + $key
|
||||
$aPattern[]="/['\"]\s*[\+\s]+\\\$" . $aFoundVariable . "$/";
|
||||
$aReplacement[]=$aFoundVariableValue;
|
||||
$aPattern[] = "/['\"]\s*[\+\s]+\\\$".$aFoundVariable."$/";
|
||||
$aReplacement[] = $aFoundVariableValue;
|
||||
}
|
||||
$sResolvedUrl=preg_replace($aPattern, $aReplacement, $sUrlTemplate);
|
||||
if (strpos($sResolvedUrl, "+")!==false)
|
||||
{
|
||||
$sResolvedUrl = preg_replace($aPattern, $aReplacement, $sUrlTemplate);
|
||||
if (strpos($sResolvedUrl, "+") !== false) {
|
||||
return false;
|
||||
}
|
||||
return trim($sResolvedUrl, "\"'");
|
||||
@@ -826,17 +778,14 @@ CSS;
|
||||
*/
|
||||
private static function HasImageExtension($path)
|
||||
{
|
||||
foreach (static::IMAGE_EXTENSIONS as $sExt)
|
||||
{
|
||||
if (endsWith($path, $sExt))
|
||||
{
|
||||
foreach (static::IMAGE_EXTENSIONS as $sExt) {
|
||||
if (endsWith($path, $sExt)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @since 3.0.0 N°2982
|
||||
* Extract the signature for a generated CSS file.
|
||||
@@ -855,16 +804,13 @@ CSS;
|
||||
$iCount = 0;
|
||||
$sPreviousLine = '';
|
||||
$hFile = @fopen($sFilepath, "r");
|
||||
if ($hFile !== false)
|
||||
{
|
||||
if ($hFile !== false) {
|
||||
$sLine = '';
|
||||
do
|
||||
{
|
||||
do {
|
||||
$iCount++;
|
||||
$sPreviousLine = $sLine;
|
||||
$sLine = rtrim(fgets($hFile)); // Remove the trailing \n
|
||||
}
|
||||
while (($sLine !== false) && ($sLine != '=== SIGNATURE END ===') && ($iCount <= 100));
|
||||
} while (($sLine !== false) && ($sLine != '=== SIGNATURE END ===') && ($iCount <= 100));
|
||||
fclose($hFile);
|
||||
}
|
||||
return $sPreviousLine;
|
||||
@@ -879,8 +825,7 @@ CSS;
|
||||
public static function GetVarSignature($JsonSignature)
|
||||
{
|
||||
$aJsonArray = json_decode($JsonSignature, true);
|
||||
if (array_key_exists('variables', $aJsonArray))
|
||||
{
|
||||
if (array_key_exists('variables', $aJsonArray)) {
|
||||
return $aJsonArray['variables'];
|
||||
}
|
||||
return false;
|
||||
@@ -904,23 +849,22 @@ CSS;
|
||||
$oFindStylesheetObject->ResetLastStyleSheet();
|
||||
}
|
||||
|
||||
foreach($aImportsPaths as $sPath)
|
||||
{
|
||||
foreach ($aImportsPaths as $sPath) {
|
||||
$sAlterableFileURI = $sFileURI;
|
||||
$sFilePath = $sPath.'/'.$sAlterableFileURI;
|
||||
$sImportedFile = realpath($sFilePath);
|
||||
if ($sImportedFile === false){
|
||||
if ($sImportedFile === false) {
|
||||
// Handle shortcut syntax : @import "typo" ;
|
||||
// file matched: typo.scss
|
||||
$sFilePath2 = "$sFilePath.scss";
|
||||
$sImportedFile = realpath($sFilePath2);
|
||||
if ($sImportedFile){
|
||||
if ($sImportedFile) {
|
||||
self::FindStylesheetFile("$sAlterableFileURI.scss", [ $sPath ], $oFindStylesheetObject, $bImports);
|
||||
$sImportedFile = false;
|
||||
}
|
||||
}
|
||||
|
||||
if ($sImportedFile === false){
|
||||
if ($sImportedFile === false) {
|
||||
// Handle shortcut syntax : @import "typo" ;
|
||||
// file matched: _typo.scss
|
||||
$sShortCut = substr($sFilePath, strrpos($sFilePath, '/') + 1);
|
||||
@@ -930,11 +874,10 @@ CSS;
|
||||
}
|
||||
|
||||
if ((file_exists($sImportedFile))
|
||||
&& (!$oFindStylesheetObject->AlreadyFetched($sImportedFile)))
|
||||
{
|
||||
if ($bImports){
|
||||
&& (!$oFindStylesheetObject->AlreadyFetched($sImportedFile))) {
|
||||
if ($bImports) {
|
||||
$oFindStylesheetObject->AddImport($sAlterableFileURI, $sImportedFile);
|
||||
}else{
|
||||
} else {
|
||||
$oFindStylesheetObject->AddStylesheet($sAlterableFileURI, $sImportedFile);
|
||||
}
|
||||
$oFindStylesheetObject->UpdateLastModified($sImportedFile);
|
||||
@@ -942,8 +885,8 @@ CSS;
|
||||
//Regexp matching on all included scss files : @import 'XXX.scss';
|
||||
$sDirUri = dirname($sAlterableFileURI);
|
||||
preg_match_all('/@import \s*[\"\']([^\"\']*)\s*[\"\']\s*;/', file_get_contents($sImportedFile), $aMatches);
|
||||
if ( (is_array($aMatches)) && (count($aMatches)!==0) ){
|
||||
foreach ($aMatches[1] as $sImportedFile){
|
||||
if ((is_array($aMatches)) && (count($aMatches) !== 0)) {
|
||||
foreach ($aMatches[1] as $sImportedFile) {
|
||||
self::FindStylesheetFile("$sDirUri/$sImportedFile", [ $sPath ], $oFindStylesheetObject, true);
|
||||
}
|
||||
}
|
||||
@@ -964,8 +907,7 @@ CSS;
|
||||
{
|
||||
$iPos = strrpos($sSubject, $sSearch);
|
||||
|
||||
if($iPos !== false)
|
||||
{
|
||||
if ($iPos !== false) {
|
||||
$sSubject = substr_replace($sSubject, $sReplace, $iPos, strlen($sSearch));
|
||||
}
|
||||
|
||||
@@ -994,19 +936,18 @@ CSS;
|
||||
public static function CloneThemeParameterAndIncludeVersion($aThemeParameters, $bSetupCompilationTimestamp, $aImportsPaths)
|
||||
{
|
||||
$aThemeParametersVariable = [];
|
||||
if (array_key_exists('variables', $aThemeParameters))
|
||||
{
|
||||
if (is_array($aThemeParameters['variables']))
|
||||
{
|
||||
$aThemeParametersVariable = array_merge([], $aThemeParameters['variables']);
|
||||
|
||||
if (array_key_exists('variable_imports', $aThemeParameters)) {
|
||||
if (is_array($aThemeParameters['variable_imports'])) {
|
||||
$aThemeParametersVariable = array_merge($aThemeParametersVariable, static::GetVariablesFromFile($aThemeParameters['variable_imports'], $aImportsPaths));
|
||||
}
|
||||
}
|
||||
|
||||
if (array_key_exists('variable_imports', $aThemeParameters))
|
||||
{
|
||||
if (is_array($aThemeParameters['variable_imports']))
|
||||
{
|
||||
$aThemeParametersVariable = array_merge($aThemeParametersVariable, static::GetVariablesFromFile($aThemeParameters['variable_imports'], $aImportsPaths));
|
||||
// Variables defined in theme XML have the priority over variables defined in XML imports files
|
||||
// They're defined after so they overwrite previous parameters
|
||||
if (array_key_exists('variables', $aThemeParameters)) {
|
||||
if (is_array($aThemeParameters['variables'])) {
|
||||
$aThemeParametersVariable = array_merge($aThemeParametersVariable, $aThemeParameters['variables']);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1021,11 +962,11 @@ CSS;
|
||||
* @return array
|
||||
* @since 3.0.0 N°3593
|
||||
*/
|
||||
public static function GetVariablesFromFile($aVariableFiles, $aImportsPaths){
|
||||
public static function GetVariablesFromFile($aVariableFiles, $aImportsPaths)
|
||||
{
|
||||
$aVariablesResults = [];
|
||||
foreach ($aVariableFiles as $sVariableFile)
|
||||
{
|
||||
foreach($aImportsPaths as $sPath) {
|
||||
foreach ($aVariableFiles as $sVariableFile) {
|
||||
foreach ($aImportsPaths as $sPath) {
|
||||
$sFilePath = $sPath.'/'.$sVariableFile;
|
||||
$sImportedFile = realpath($sFilePath);
|
||||
if ($sImportedFile !== false) {
|
||||
@@ -1041,9 +982,10 @@ CSS;
|
||||
}
|
||||
}
|
||||
}
|
||||
array_map( function($sVariableValue) { return ltrim($sVariableValue); }, $aVariablesResults );
|
||||
array_map(function ($sVariableValue) {
|
||||
return ltrim($sVariableValue);
|
||||
}, $aVariablesResults);
|
||||
return $aVariablesResults;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Copyright (C) 2013-2024 Combodo SAS
|
||||
*
|
||||
@@ -29,7 +30,8 @@ class ThemeHandlerService
|
||||
{
|
||||
}
|
||||
|
||||
public function CompileTheme($sThemeId, $bSetup = false, $sSetupCompilationTimestamp = "", $aThemeParameters = null, $aImportsPaths = null, $sWorkingPath = null){
|
||||
public function CompileTheme($sThemeId, $bSetup = false, $sSetupCompilationTimestamp = "", $aThemeParameters = null, $aImportsPaths = null, $sWorkingPath = null)
|
||||
{
|
||||
return ThemeHandler::CompileTheme($sThemeId, $bSetup, $sSetupCompilationTimestamp, $aThemeParameters, $aImportsPaths, $sWorkingPath);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
<?php
|
||||
|
||||
// Copyright (C) 2010-2024 Combodo SAS
|
||||
//
|
||||
// This file is part of iTop.
|
||||
//
|
||||
// iTop is free software; you can redistribute it and/or modify
|
||||
// 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.
|
||||
@@ -22,7 +23,7 @@ use Combodo\iTop\Application\Helper\Session;
|
||||
* submitted yet, in order to prevent double submissions. When created a transaction remains valid
|
||||
* until the user's session expires. This class is actually a wrapper to the underlying implementation
|
||||
* which choice is configured via the parameter 'transaction_storage'
|
||||
*
|
||||
*
|
||||
* @package iTop
|
||||
* @copyright Copyright (C) 2010-2024 Combodo SAS
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
@@ -37,13 +38,11 @@ class privUITransaction
|
||||
public static function GetNewTransactionId()
|
||||
{
|
||||
$bTransactionsEnabled = MetaModel::GetConfig()->Get('transactions_enabled');
|
||||
if (!$bTransactionsEnabled)
|
||||
{
|
||||
if (!$bTransactionsEnabled) {
|
||||
return 'notransactions'; // Any value will do
|
||||
}
|
||||
$sClass = 'privUITransaction'.MetaModel::GetConfig()->Get('transaction_storage');
|
||||
if (!class_exists($sClass, false))
|
||||
{
|
||||
if (!class_exists($sClass, false)) {
|
||||
IssueLog::Error("Incorrect value '".MetaModel::GetConfig()->Get('transaction_storage')."' for 'transaction_storage', the class '$sClass' does not exists. Using privUITransactionSession instead for storing sessions.");
|
||||
$sClass = 'privUITransactionSession';
|
||||
}
|
||||
@@ -62,16 +61,14 @@ class privUITransaction
|
||||
public static function IsTransactionValid($id, $bRemoveTransaction = true)
|
||||
{
|
||||
$bTransactionsEnabled = MetaModel::GetConfig()->Get('transactions_enabled');
|
||||
if (!$bTransactionsEnabled)
|
||||
{
|
||||
if (!$bTransactionsEnabled) {
|
||||
return true; // All values are valid
|
||||
}
|
||||
$sClass = 'privUITransaction'.MetaModel::GetConfig()->Get('transaction_storage');
|
||||
if (!class_exists($sClass, false))
|
||||
{
|
||||
if (!class_exists($sClass, false)) {
|
||||
$sClass = 'privUITransactionSession';
|
||||
}
|
||||
|
||||
|
||||
return $sClass::IsTransactionValid($id, $bRemoveTransaction);
|
||||
}
|
||||
|
||||
@@ -83,16 +80,14 @@ class privUITransaction
|
||||
public static function RemoveTransaction($id)
|
||||
{
|
||||
$bTransactionsEnabled = MetaModel::GetConfig()->Get('transactions_enabled');
|
||||
if (!$bTransactionsEnabled)
|
||||
{
|
||||
if (!$bTransactionsEnabled) {
|
||||
return; // Nothing to do
|
||||
}
|
||||
$sClass = 'privUITransaction'.MetaModel::GetConfig()->Get('transaction_storage');
|
||||
if (!class_exists($sClass, false))
|
||||
{
|
||||
if (!class_exists($sClass, false)) {
|
||||
$sClass = 'privUITransactionSession';
|
||||
}
|
||||
|
||||
|
||||
$sClass::RemoveTransaction($id);
|
||||
}
|
||||
}
|
||||
@@ -114,17 +109,16 @@ class privUITransactionSession
|
||||
*/
|
||||
public static function GetNewTransactionId()
|
||||
{
|
||||
if (!Session::IsSet('transactions'))
|
||||
{
|
||||
if (!Session::IsSet('transactions')) {
|
||||
Session::Set('transactions', []);
|
||||
}
|
||||
// Strictly speaking, the two lines below should be grouped together
|
||||
// by a critical section
|
||||
// sem_acquire($rSemIdentified);
|
||||
$id = static::GetUserPrefix() . str_replace(array('.', ' '), '', microtime());
|
||||
$id = static::GetUserPrefix().str_replace(['.', ' '], '', microtime());
|
||||
Session::Set(['transactions', $id], true);
|
||||
// sem_release($rSemIdentified);
|
||||
|
||||
|
||||
return (string)$id;
|
||||
}
|
||||
|
||||
@@ -135,20 +129,17 @@ class privUITransactionSession
|
||||
* @param int $id Identifier of the transaction, as returned by GetNewTransactionId
|
||||
* @param bool $bRemoveTransaction True if the transaction must be removed
|
||||
* @return bool True if the transaction is valid, false otherwise
|
||||
*/
|
||||
*/
|
||||
public static function IsTransactionValid($id, $bRemoveTransaction = true)
|
||||
{
|
||||
$bResult = false;
|
||||
if (Session::IsSet('transactions'))
|
||||
{
|
||||
if (Session::IsSet('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 (Session::IsSet(['transactions', $id])) {
|
||||
$bResult = true;
|
||||
if ($bRemoveTransaction)
|
||||
{
|
||||
if ($bRemoveTransaction) {
|
||||
Session::Unset(['transactions', $id]);
|
||||
}
|
||||
}
|
||||
@@ -156,7 +147,7 @@ class privUITransactionSession
|
||||
}
|
||||
return $bResult;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Removes the transaction specified by its id
|
||||
* @param int $id The Identifier (as returned by GetNewTranscationId) of the transaction to be removed.
|
||||
@@ -164,17 +155,15 @@ class privUITransactionSession
|
||||
*/
|
||||
public static function RemoveTransaction($id)
|
||||
{
|
||||
if (Session::IsSet('transactions'))
|
||||
{
|
||||
if (Session::IsSet('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 (Session::IsSet(['transactions', $id])) {
|
||||
Session::Unset(['transactions', $id]);
|
||||
}
|
||||
// sem_release($rSemIdentified);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -197,7 +186,7 @@ class privUITransactionSession
|
||||
class privUITransactionFile
|
||||
{
|
||||
/** @var int Value to use when no user logged */
|
||||
const UNAUTHENTICATED_USER_ID = -666;
|
||||
public const UNAUTHENTICATED_USER_ID = -666;
|
||||
|
||||
/**
|
||||
* @return int current user id, or {@see self::UNAUTHENTICATED_USER_ID} if no user logged
|
||||
@@ -228,22 +217,18 @@ class privUITransactionFile
|
||||
*/
|
||||
public static function GetNewTransactionId()
|
||||
{
|
||||
if (!is_dir(APPROOT.'data/transactions'))
|
||||
{
|
||||
if (!is_writable(APPROOT.'data'))
|
||||
{
|
||||
if (!is_dir(APPROOT.'data/transactions')) {
|
||||
if (!is_writable(APPROOT.'data')) {
|
||||
throw new Exception('The directory "'.APPROOT.'data" must be writable to the application.');
|
||||
}
|
||||
// condition avoids race condition N°2345
|
||||
// See https://github.com/kalessil/phpinspectionsea/blob/master/docs/probable-bugs.md#mkdir-race-condition
|
||||
if (!mkdir($concurrentDirectory = APPROOT.'data/transactions') && !is_dir($concurrentDirectory))
|
||||
{
|
||||
if (!mkdir($concurrentDirectory = APPROOT.'data/transactions') && !is_dir($concurrentDirectory)) {
|
||||
throw new Exception('Failed to create the directory "'.APPROOT.'data/transactions". Ajust the rights on the parent directory or let an administrator create the transactions directory and give the web sever enough rights to write into it.');
|
||||
}
|
||||
}
|
||||
|
||||
if (!is_writable(APPROOT.'data/transactions'))
|
||||
{
|
||||
if (!is_writable(APPROOT.'data/transactions')) {
|
||||
throw new Exception('The directory "'.APPROOT.'data/transactions" must be writable to the application.');
|
||||
}
|
||||
|
||||
@@ -277,8 +262,7 @@ class privUITransactionFile
|
||||
// Constraint the transaction file within APPROOT.'data/transactions'
|
||||
$sTransactionDir = realpath(APPROOT.'data/transactions');
|
||||
$sFilepath = utils::RealPath($sTransactionDir.'/'.$id, $sTransactionDir);
|
||||
if (($sFilepath === false) || (strlen($sTransactionDir) == strlen($sFilepath)))
|
||||
{
|
||||
if (($sFilepath === false) || (strlen($sTransactionDir) == strlen($sFilepath))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -297,15 +281,11 @@ class privUITransactionFile
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($bRemoveTransaction)
|
||||
{
|
||||
if ($bRemoveTransaction) {
|
||||
$bResult = @unlink($sFilepath);
|
||||
if (!$bResult)
|
||||
{
|
||||
if (!$bResult) {
|
||||
self::Error('IsTransactionValid: FAILED to remove transaction '.$id);
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
self::Info('IsTransactionValid: OK. Removed transaction: '.$id);
|
||||
}
|
||||
}
|
||||
@@ -347,13 +327,11 @@ class privUITransactionFile
|
||||
}
|
||||
|
||||
clearstatcache();
|
||||
$iLimit = time() - 24*3600;
|
||||
$iLimit = time() - 24 * 3600;
|
||||
$sPattern = $sTransactionDir ? "$sTransactionDir/*" : APPROOT.'data/transactions/*';
|
||||
$aTransactions = glob($sPattern);
|
||||
foreach($aTransactions as $sFileName)
|
||||
{
|
||||
if (filemtime($sFileName) < $iLimit)
|
||||
{
|
||||
foreach ($aTransactions as $sFileName) {
|
||||
if (filemtime($sFileName) < $iLimit) {
|
||||
@unlink($sFileName);
|
||||
self::Info('CleanupOldTransactions: Deleted transaction: '.$sFileName);
|
||||
}
|
||||
@@ -367,10 +345,9 @@ class privUITransactionFile
|
||||
protected static function GetPendingTransactions()
|
||||
{
|
||||
clearstatcache();
|
||||
$aResult = array();
|
||||
$aResult = [];
|
||||
$aTransactions = glob(APPROOT.'data/transactions/'.self::GetUserPrefix().'*');
|
||||
foreach($aTransactions as $sFileName)
|
||||
{
|
||||
foreach ($aTransactions as $sFileName) {
|
||||
$aResult[] = date('Y-m-d H:i:s', filemtime($sFileName)).' - '.basename($sFileName);
|
||||
}
|
||||
sort($aResult);
|
||||
@@ -398,13 +375,14 @@ class privUITransactionFile
|
||||
{
|
||||
self::Write('Warning | '.$sText);
|
||||
}
|
||||
|
||||
|
||||
protected static function Error($sText)
|
||||
{
|
||||
self::Write('Error | '.$sText);
|
||||
}
|
||||
|
||||
protected static function IsLogEnabled() {
|
||||
protected static function IsLogEnabled()
|
||||
{
|
||||
$oConfig = MetaModel::GetConfig();
|
||||
if (is_null($oConfig)) {
|
||||
return false;
|
||||
|
||||
@@ -34,24 +34,32 @@ class TwigExtension
|
||||
{
|
||||
// Filter to translate a string via the Dict::S function
|
||||
// Usage in twig: {{ 'String:ToTranslate'|dict_s }}
|
||||
$oTwigEnv->addFilter(new TwigFilter('dict_s',
|
||||
$oTwigEnv->addFilter(
|
||||
new TwigFilter(
|
||||
'dict_s',
|
||||
function ($sStringCode, $sDefault = null, $bUserLanguageOnly = false) {
|
||||
return Dict::S($sStringCode, $sDefault, $bUserLanguageOnly);
|
||||
})
|
||||
}
|
||||
)
|
||||
);
|
||||
|
||||
// Filter to format a string via the Dict::Format function
|
||||
// Usage in twig: {{ 'String:ToTranslate'|dict_format() }}
|
||||
$oTwigEnv->addFilter(new TwigFilter('dict_format',
|
||||
$oTwigEnv->addFilter(
|
||||
new TwigFilter(
|
||||
'dict_format',
|
||||
function ($sStringCode, $sParam01 = null, $sParam02 = null, $sParam03 = null, $sParam04 = null) {
|
||||
return Dict::Format($sStringCode, $sParam01, $sParam02, $sParam03, $sParam04);
|
||||
})
|
||||
}
|
||||
)
|
||||
);
|
||||
|
||||
// Filter to format output
|
||||
// example a DateTime is converted to user format
|
||||
// Usage in twig: {{ 'String:ToFormat'|output_format }}
|
||||
$oTwigEnv->addFilter(new TwigFilter('date_format',
|
||||
$oTwigEnv->addFilter(
|
||||
new TwigFilter(
|
||||
'date_format',
|
||||
function ($sDate) {
|
||||
try {
|
||||
if (preg_match('@^\d\d\d\d-\d\d-\d\d \d\d:\d\d:\d\d$@', trim($sDate))) {
|
||||
@@ -60,22 +68,23 @@ class TwigExtension
|
||||
if (preg_match('@^\d\d\d\d-\d\d-\d\d$@', trim($sDate))) {
|
||||
return AttributeDate::GetFormat()->Format($sDate);
|
||||
}
|
||||
}
|
||||
catch (Exception $e)
|
||||
{
|
||||
} catch (Exception $e) {
|
||||
}
|
||||
return $sDate;
|
||||
})
|
||||
}
|
||||
)
|
||||
);
|
||||
|
||||
|
||||
// Filter to format output
|
||||
// example a DateTime is converted to user format
|
||||
// Usage in twig: {{ 'String:ToFormat'|output_format }}
|
||||
$oTwigEnv->addFilter(new TwigFilter('size_format',
|
||||
$oTwigEnv->addFilter(
|
||||
new TwigFilter(
|
||||
'size_format',
|
||||
function ($sSize) {
|
||||
return utils::BytesToFriendlyFormat($sSize);
|
||||
})
|
||||
}
|
||||
)
|
||||
);
|
||||
|
||||
// Filter to enable base64 encode/decode
|
||||
@@ -85,7 +94,8 @@ class TwigExtension
|
||||
|
||||
// Filter to enable json decode (encode already exists)
|
||||
// Usage in twig: {{ aSomeArray|json_decode }}
|
||||
$oTwigEnv->addFilter(new TwigFilter('json_decode', function ($sJsonString, $bAssoc = false) {
|
||||
$oTwigEnv->addFilter(
|
||||
new TwigFilter('json_decode', function ($sJsonString, $bAssoc = false) {
|
||||
return json_decode($sJsonString, $bAssoc);
|
||||
})
|
||||
);
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* @copyright Copyright (C) 2010-2024 Combodo SAS
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
@@ -54,8 +55,8 @@ require_once(APPROOT.'/application/displayblock.class.inc.php');
|
||||
*/
|
||||
class UIExtKeyWidget
|
||||
{
|
||||
const ENUM_OUTPUT_FORMAT_CSV = 'csv';
|
||||
const ENUM_OUTPUT_FORMAT_JSON = 'json';
|
||||
public const ENUM_OUTPUT_FORMAT_CSV = 'csv';
|
||||
public const ENUM_OUTPUT_FORMAT_JSON = 'json';
|
||||
|
||||
protected $iId;
|
||||
protected $sTargetClass;
|
||||
@@ -87,10 +88,20 @@ class UIExtKeyWidget
|
||||
* @since 2.7.7 3.0.1 3.1.0 N°3129 Add default value for $aArgs for PHP 8.0 compat
|
||||
*/
|
||||
public static function DisplayFromAttCode(
|
||||
$oPage, $sAttCode, $sClass, $sTitle, $oAllowedValues, $value, $iInputId, $bMandatory, $sFieldName = '', $sFormPrefix = '',
|
||||
$aArgs = [], $bSearchMode = false, &$sInputType = ''
|
||||
)
|
||||
{
|
||||
$oPage,
|
||||
$sAttCode,
|
||||
$sClass,
|
||||
$sTitle,
|
||||
$oAllowedValues,
|
||||
$value,
|
||||
$iInputId,
|
||||
$bMandatory,
|
||||
$sFieldName = '',
|
||||
$sFormPrefix = '',
|
||||
$aArgs = [],
|
||||
$bSearchMode = false,
|
||||
&$sInputType = ''
|
||||
) {
|
||||
$oAttDef = MetaModel::GetAttributeDef($sClass, $sAttCode);
|
||||
$sTargetClass = $oAttDef->GetTargetClass();
|
||||
$iMaxComboLength = $oAttDef->GetMaximumComboLength();
|
||||
@@ -102,8 +113,7 @@ class UIExtKeyWidget
|
||||
}
|
||||
$oWidget = new UIExtKeyWidget($sTargetClass, $iInputId, $sAttCode, $bSearchMode);
|
||||
if (!$bSearchMode) {
|
||||
switch ($sDisplayStyle)
|
||||
{
|
||||
switch ($sDisplayStyle) {
|
||||
case 'radio':
|
||||
case 'radio_horizontal':
|
||||
case 'radio_vertical':
|
||||
@@ -114,12 +124,38 @@ class UIExtKeyWidget
|
||||
case 'select':
|
||||
case 'list':
|
||||
default:
|
||||
return $oWidget->DisplaySelect($oPage, $iMaxComboLength, $bAllowTargetCreation, $sTitle, $oAllowedValues, $value,
|
||||
$bMandatory, $sFieldName, $sFormPrefix, $aArgs, $sInputType);
|
||||
return $oWidget->DisplaySelect(
|
||||
$oPage,
|
||||
$iMaxComboLength,
|
||||
$bAllowTargetCreation,
|
||||
$sTitle,
|
||||
$oAllowedValues,
|
||||
$value,
|
||||
$bMandatory,
|
||||
$sFieldName,
|
||||
$sFormPrefix,
|
||||
$aArgs,
|
||||
$sInputType
|
||||
);
|
||||
}
|
||||
} else {
|
||||
return $oWidget->Display($oPage, $iMaxComboLength, $bAllowTargetCreation, $sTitle, $oAllowedValues, $value, $iInputId,
|
||||
$bMandatory, $sFieldName, $sFormPrefix, $aArgs, null, $sDisplayStyle, true, $sInputType);
|
||||
return $oWidget->Display(
|
||||
$oPage,
|
||||
$iMaxComboLength,
|
||||
$bAllowTargetCreation,
|
||||
$sTitle,
|
||||
$oAllowedValues,
|
||||
$value,
|
||||
$iInputId,
|
||||
$bMandatory,
|
||||
$sFieldName,
|
||||
$sFormPrefix,
|
||||
$aArgs,
|
||||
null,
|
||||
$sDisplayStyle,
|
||||
true,
|
||||
$sInputType
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -158,7 +194,7 @@ class UIExtKeyWidget
|
||||
* @since 3.0.0 N°2508 - Include Obsolescence icon within list and autocomplete
|
||||
* @since 3.0.0 N°3750 new $sInputType parameter
|
||||
*/
|
||||
public function DisplaySelect(WebPage $oPage, $iMaxComboLength, $bAllowTargetCreation, $sTitle, DBObjectset $oAllowedValues, $value, $bMandatory, $sFieldName, $sFormPrefix = '', $aArgs = array(), &$sInputType = '')
|
||||
public function DisplaySelect(WebPage $oPage, $iMaxComboLength, $bAllowTargetCreation, $sTitle, DBObjectset $oAllowedValues, $value, $bMandatory, $sFieldName, $sFormPrefix = '', $aArgs = [], &$sInputType = '')
|
||||
{
|
||||
$sTitle = addslashes($sTitle);
|
||||
$oPage->LinkScriptFromAppRoot('js/extkeywidget.js');
|
||||
@@ -194,7 +230,7 @@ class UIExtKeyWidget
|
||||
$bIsAutocomplete = $oAllowedValues->CountExceeds($iMaxComboLength);
|
||||
$sWrapperCssClass = $bIsAutocomplete ? 'ibo-input-select-autocomplete-wrapper' : 'ibo-input-select-wrapper';
|
||||
$sHTMLValue = "<div class=\"field_input_zone field_input_extkey ibo-input-wrapper ibo-input-select-wrapper--with-buttons $sWrapperCssClass\" data-attcode=\"".$this->sAttCode."\" data-validation=\"untouched\" data-accessibility-selectize-label=\"$sTitle\">";
|
||||
|
||||
|
||||
// We just need to compare the number of entries with MaxComboLength, so no need to get the real count.
|
||||
if (!$bIsAutocomplete) {
|
||||
// Discrete list of values, use a SELECT or RADIO buttons depending on the config
|
||||
@@ -281,21 +317,17 @@ EOF
|
||||
$oPage->add_ready_script("$('#$this->iId').one('validate', function() { $(this).trigger('change'); } );");
|
||||
}
|
||||
$sHTMLValue .= "<div class=\"ibo-input-select--action-buttons\">";
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
// Too many choices, use an autocomplete
|
||||
// Check that the given value is allowed
|
||||
$oSearch = $oAllowedValues->GetFilter();
|
||||
$oSearch->AddCondition('id', $value);
|
||||
$oSet = new DBObjectSet($oSearch);
|
||||
if ($oSet->Count() == 0)
|
||||
{
|
||||
if ($oSet->Count() == 0) {
|
||||
$value = null;
|
||||
}
|
||||
|
||||
if (is_null($value) || ($value == 0)) // Null values are displayed as ''
|
||||
{
|
||||
if (is_null($value) || ($value == 0)) { // Null values are displayed as ''
|
||||
$sDisplayValue = isset($aArgs['sDefaultValue']) ? $aArgs['sDefaultValue'] : '';
|
||||
} else {
|
||||
$sDisplayValue = $this->GetObjectName($value);
|
||||
@@ -376,36 +408,30 @@ JS
|
||||
|
||||
$sHTMLValue = "<div class=\"field_input_zone field_input_extkey\">";
|
||||
|
||||
if (is_null($oAllowedValues))
|
||||
{
|
||||
if (is_null($oAllowedValues)) {
|
||||
throw new Exception('Implementation: null value for allowed values definition');
|
||||
}
|
||||
$oAllowedValues->SetShowObsoleteData(utils::ShowObsoleteData());
|
||||
|
||||
// We just need to compare the number of entries with MaxComboLength, so no need to get the real count.
|
||||
if (!$oAllowedValues->CountExceeds($iMaxComboLength))
|
||||
{
|
||||
if (!$oAllowedValues->CountExceeds($iMaxComboLength)) {
|
||||
// Discrete list of values, use a SELECT or RADIO buttons depending on the config
|
||||
$sValidationField = null;
|
||||
|
||||
$bVertical = ($sDisplayStyle != 'radio_horizontal');
|
||||
$bExtensions = false;
|
||||
$oAllowedValues->Rewind();
|
||||
$aAllowedValues = array();
|
||||
while($oObj = $oAllowedValues->Fetch())
|
||||
{
|
||||
$aAllowedValues = [];
|
||||
while ($oObj = $oAllowedValues->Fetch()) {
|
||||
$aAllowedValues[$oObj->GetKey()] = $oObj->GetName();
|
||||
}
|
||||
$sHTMLValue .= $oPage->GetRadioButtons($aAllowedValues, $value, $this->iId, "{$sAttrFieldPrefix}{$sFieldName}", false /* $bMandatory will be placed manually */, $bVertical, $sValidationField);
|
||||
$aEventsList[] ='change';
|
||||
}
|
||||
else
|
||||
{
|
||||
$aEventsList[] = 'change';
|
||||
} else {
|
||||
$sHTMLValue .= "unable to display. Too much values";
|
||||
}
|
||||
$sHTMLValue .= '<div class="ibo-input-select--action-buttons">';
|
||||
if ($bExtensions && MetaModel::IsHierarchicalClass($this->sTargetClass) !== false)
|
||||
{
|
||||
if ($bExtensions && MetaModel::IsHierarchicalClass($this->sTargetClass) !== false) {
|
||||
$sHTMLValue .= "<span class=\"field_input_btn\"><div class=\"mini_button\" id=\"mini_tree_{$this->iId}\" onClick=\"oACWidget_{$this->iId}.HKDisplay();\"><i class=\"fas fa-sitemap\"></i></div></span>";
|
||||
$oPage->add_ready_script(
|
||||
<<<JS
|
||||
@@ -416,8 +442,7 @@ JS
|
||||
JS
|
||||
);
|
||||
}
|
||||
if ($bCreate && $bExtensions)
|
||||
{
|
||||
if ($bCreate && $bExtensions) {
|
||||
$sCallbackName = (MetaModel::IsAbstract($this->sTargetClass)) ? 'SelectObjectClass' : 'CreateObject';
|
||||
|
||||
$sHTMLValue .= "<span class=\"field_input_btn\"><div class=\"mini_button\" id=\"mini_add_{$this->iId}\" onClick=\"oACWidget_{$this->iId}.{$sCallbackName}();\"><i class=\"fas fa-plus\"></i></div></span>";
|
||||
@@ -471,7 +496,7 @@ JS
|
||||
*
|
||||
* @since 3.0.0 N°3750 new $sInputType parameter
|
||||
*/
|
||||
public function Display(WebPage $oPage, $iMaxComboLength, $bAllowTargetCreation, $sTitle, DBObjectset $oAllowedValues, $value, $iInputId, $bMandatory, $sFieldName, $sFormPrefix = '', $aArgs = array(), $bSearchMode = null, $sDisplayStyle = 'select', $bSearchMultiple = true, &$sInputType = '')
|
||||
public function Display(WebPage $oPage, $iMaxComboLength, $bAllowTargetCreation, $sTitle, DBObjectset $oAllowedValues, $value, $iInputId, $bMandatory, $sFieldName, $sFormPrefix = '', $aArgs = [], $bSearchMode = null, $sDisplayStyle = 'select', $bSearchMultiple = true, &$sInputType = '')
|
||||
{
|
||||
if (!is_null($bSearchMode)) {
|
||||
$this->bSearchMode = $bSearchMode;
|
||||
@@ -521,7 +546,7 @@ JS
|
||||
$bVertical = ($sDisplayStyle != 'radio_horizontal');
|
||||
$bExtensions = false;
|
||||
$oAllowedValues->Rewind();
|
||||
$aAllowedValues = array();
|
||||
$aAllowedValues = [];
|
||||
while ($oObj = $oAllowedValues->Fetch()) {
|
||||
$aAllowedValues[$oObj->GetKey()] = $oObj->GetName();
|
||||
}
|
||||
@@ -568,22 +593,22 @@ EOF
|
||||
}
|
||||
$sHTMLValue .= "<option value=\"$key\" $sSelected>$display_value</option>\n";
|
||||
}
|
||||
$sHTMLValue .= "</select>\n";
|
||||
$sHTMLValue .= "</div>\n";
|
||||
$sHTMLValue .= "</select>\n";
|
||||
$sHTMLValue .= "</div>\n";
|
||||
|
||||
$sInputType = CmdbAbstractObject::ENUM_INPUT_TYPE_DROPDOWN_RAW;
|
||||
if (($this->bSearchMode) && $bSearchMultiple) {
|
||||
$sInputType = CmdbAbstractObject::ENUM_INPUT_TYPE_DROPDOWN_MULTIPLE_CHOICES;
|
||||
$aOptions = array(
|
||||
'header' => true,
|
||||
'checkAllText' => Dict::S('UI:SearchValue:CheckAll'),
|
||||
'uncheckAllText' => Dict::S('UI:SearchValue:UncheckAll'),
|
||||
'noneSelectedText' => Dict::S('UI:SearchValue:Any'),
|
||||
'selectedText' => Dict::S('UI:SearchValue:NbSelected'),
|
||||
'selectedList' => 1,
|
||||
);
|
||||
$sJSOptions = json_encode($aOptions);
|
||||
$oPage->add_ready_script("$('.multiselect').multiselect($sJSOptions);");
|
||||
$sInputType = CmdbAbstractObject::ENUM_INPUT_TYPE_DROPDOWN_RAW;
|
||||
if (($this->bSearchMode) && $bSearchMultiple) {
|
||||
$sInputType = CmdbAbstractObject::ENUM_INPUT_TYPE_DROPDOWN_MULTIPLE_CHOICES;
|
||||
$aOptions = [
|
||||
'header' => true,
|
||||
'checkAllText' => Dict::S('UI:SearchValue:CheckAll'),
|
||||
'uncheckAllText' => Dict::S('UI:SearchValue:UncheckAll'),
|
||||
'noneSelectedText' => Dict::S('UI:SearchValue:Any'),
|
||||
'selectedText' => Dict::S('UI:SearchValue:NbSelected'),
|
||||
'selectedList' => 1,
|
||||
];
|
||||
$sJSOptions = json_encode($aOptions);
|
||||
$oPage->add_ready_script("$('.multiselect').multiselect($sJSOptions);");
|
||||
}
|
||||
$oPage->add_ready_script(
|
||||
<<<EOF
|
||||
@@ -606,8 +631,7 @@ EOF
|
||||
$value = null;
|
||||
}
|
||||
|
||||
if (is_null($value) || ($value == 0)) // Null values are displayed as ''
|
||||
{
|
||||
if (is_null($value) || ($value == 0)) { // Null values are displayed as ''
|
||||
$sDisplayValue = isset($aArgs['sDefaultValue']) ? $aArgs['sDefaultValue'] : '';
|
||||
} else {
|
||||
$sDisplayValue = $this->GetObjectName($value);
|
||||
@@ -673,20 +697,22 @@ JS
|
||||
$oAttDef = MetaModel::GetAttributeDef(get_class($oCurrObject), $this->sAttCode);
|
||||
/** @var \DBObject $oCurrObject */
|
||||
$aArgs = $oCurrObject->ToArgsForQuery();
|
||||
$aParams = array('query_params' => $aArgs);
|
||||
$aParams = ['query_params' => $aArgs];
|
||||
$oSet = $oAttDef->GetAllowedValuesAsObjectSet($aArgs);
|
||||
$oFilter = $oSet->GetFilter();
|
||||
} else if (!empty($this->sFilter)) {
|
||||
$aParams = array();
|
||||
} elseif (!empty($this->sFilter)) {
|
||||
$aParams = [];
|
||||
$oFilter = DBObjectSearch::FromOQL($this->sFilter);
|
||||
} else {
|
||||
$aParams = array();
|
||||
$aParams = [];
|
||||
$oFilter = new DBObjectSearch($this->sTargetClass);
|
||||
}
|
||||
$oFilter->SetModifierProperty('UserRightsGetSelectFilter', 'bSearchMode', $this->bSearchMode);
|
||||
$oBlock = new DisplayBlock($oFilter, 'search', false, $aParams);
|
||||
$oPage->AddUiBlock($oBlock->GetDisplay($oPage, 'dtc_'.$this->iId,
|
||||
array(
|
||||
$oPage->AddUiBlock($oBlock->GetDisplay(
|
||||
$oPage,
|
||||
'dtc_'.$this->iId,
|
||||
[
|
||||
'menu' => false,
|
||||
'currentId' => $this->iId,
|
||||
'table_id' => "dr_{$this->iId}",
|
||||
@@ -694,12 +720,13 @@ JS
|
||||
'selection_mode' => true,
|
||||
'selection_type' => 'single',
|
||||
'cssCount' => '#count_'.$this->iId.'_results',
|
||||
)
|
||||
]
|
||||
));
|
||||
$sCancel = Dict::S('UI:Button:Cancel');
|
||||
$sOK = Dict::S('UI:Button:Ok');
|
||||
$sEmptyList = Dict::S('UI:Message:EmptyList:UseSearchForm');
|
||||
$oPage->add(<<<HTML
|
||||
$oPage->add(
|
||||
<<<HTML
|
||||
<form id="fr_{$this->iId}" OnSubmit="return oACWidget_{$this->iId}.DoOk();">
|
||||
<div id="dr_{$this->iId}">
|
||||
<div><p>{$sEmptyList}</p></div>
|
||||
@@ -711,7 +738,8 @@ HTML
|
||||
);
|
||||
|
||||
$sDialogTitleSanitized = addslashes(utils::HtmlToText($sTitle));
|
||||
$oPage->add_ready_script(<<<JS
|
||||
$oPage->add_ready_script(
|
||||
<<<JS
|
||||
$('#ac_dlg_{$this->iId}').dialog({
|
||||
width: $(window).width()*0.8,
|
||||
height: $(window).height()*0.8,
|
||||
@@ -751,14 +779,12 @@ JS
|
||||
*/
|
||||
public function SearchObjectsToSelect(WebPage $oP, $sFilter, $sRemoteClass = '', $oObj = null)
|
||||
{
|
||||
if (is_null($sFilter))
|
||||
{
|
||||
if (is_null($sFilter)) {
|
||||
throw new Exception('Implementation: null value for allowed values definition');
|
||||
}
|
||||
|
||||
$oFilter = DBObjectSearch::FromOQL($sFilter);
|
||||
if (strlen($sRemoteClass) > 0)
|
||||
{
|
||||
if (strlen($sRemoteClass) > 0) {
|
||||
$oFilter->ChangeClass($sRemoteClass);
|
||||
}
|
||||
$oFilter->SetModifierProperty('UserRightsGetSelectFilter', 'bSearchMode', $this->bSearchMode);
|
||||
@@ -766,26 +792,26 @@ JS
|
||||
// Current extkey value, so we can display event if it is not available anymore (eg. archived).
|
||||
$iCurrentExtKeyId = (is_null($oObj)) ? 0 : $oObj->Get($this->sAttCode);
|
||||
|
||||
$oBlock = new DisplayBlock($oFilter, 'list_search', false, array('query_params' => array('this' => $oObj, 'current_extkey_id' => $iCurrentExtKeyId)));
|
||||
$oBlock->Display($oP, $this->iId.'_results', array('this' => $oObj, 'cssCount'=> '#count_'.$this->iId.'_results', 'menu' => false, 'selection_mode' => true, 'selection_type' => 'single', 'table_id' => 'select_'.$this->sAttCode)); // Don't display the 'Actions' menu on the results
|
||||
$oBlock = new DisplayBlock($oFilter, 'list_search', false, ['query_params' => ['this' => $oObj, 'current_extkey_id' => $iCurrentExtKeyId]]);
|
||||
$oBlock->Display($oP, $this->iId.'_results', ['this' => $oObj, 'cssCount' => '#count_'.$this->iId.'_results', 'menu' => false, 'selection_mode' => true, 'selection_type' => 'single', 'table_id' => 'select_'.$this->sAttCode]); // Don't display the 'Actions' menu on the results
|
||||
}
|
||||
|
||||
/**
|
||||
* Search for objects to be selected
|
||||
*
|
||||
* @param WebPage $oP The page used for the output (usually an AjaxWebPage)
|
||||
* @param string $sFilter The OQL expression used to define/limit limit the scope of possible values
|
||||
* @param DBObject $oObj The current object for the OQL context
|
||||
* @param string $sContains The text of the autocomplete to filter the results
|
||||
* @param string $sOutputFormat
|
||||
* @param null $sOperation for the values @see ValueSetObjects->LoadValues() not used since 3.0.0
|
||||
*
|
||||
* @throws CoreException
|
||||
* @throws OQLException
|
||||
*
|
||||
* @since 2.7.7 3.0.1 3.1.0 N°3129 Remove default value for $oObj for PHP 8.0 compatibility
|
||||
*/
|
||||
public function AutoComplete(WebPage $oP, $sFilter, $oObj, $sContains, $sOutputFormat = self::ENUM_OUTPUT_FORMAT_CSV, $sOperation = null )
|
||||
/**
|
||||
* Search for objects to be selected
|
||||
*
|
||||
* @param WebPage $oP The page used for the output (usually an AjaxWebPage)
|
||||
* @param string $sFilter The OQL expression used to define/limit limit the scope of possible values
|
||||
* @param DBObject $oObj The current object for the OQL context
|
||||
* @param string $sContains The text of the autocomplete to filter the results
|
||||
* @param string $sOutputFormat
|
||||
* @param null $sOperation for the values @see ValueSetObjects->LoadValues() not used since 3.0.0
|
||||
*
|
||||
* @throws CoreException
|
||||
* @throws OQLException
|
||||
*
|
||||
* @since 2.7.7 3.0.1 3.1.0 N°3129 Remove default value for $oObj for PHP 8.0 compatibility
|
||||
*/
|
||||
public function AutoComplete(WebPage $oP, $sFilter, $oObj, $sContains, $sOutputFormat = self::ENUM_OUTPUT_FORMAT_CSV, $sOperation = null)
|
||||
{
|
||||
if (is_null($sFilter)) {
|
||||
throw new Exception('Implementation: null value for allowed values definition');
|
||||
@@ -799,38 +825,32 @@ JS
|
||||
$oValuesSet->SetSort(false);
|
||||
$oValuesSet->SetModifierProperty('UserRightsGetSelectFilter', 'bSearchMode', $this->bSearchMode);
|
||||
$oValuesSet->SetLimit($iMax);
|
||||
$aValuesStartWith = $oValuesSet->GetValuesForAutocomplete(array('this' => $oObj, 'current_extkey_id' => $iCurrentExtKeyId), $sContains, 'start_with');
|
||||
$aValuesStartWith = $oValuesSet->GetValuesForAutocomplete(['this' => $oObj, 'current_extkey_id' => $iCurrentExtKeyId], $sContains, 'start_with');
|
||||
asort($aValuesStartWith);
|
||||
$aValues = $aValuesStartWith;
|
||||
if (sizeof($aValues) < $iMax) {
|
||||
$aValuesContains = $oValuesSet->GetValuesForAutocomplete(array('this' => $oObj, 'current_extkey_id' => $iCurrentExtKeyId), $sContains, 'contains');
|
||||
$aValuesContains = $oValuesSet->GetValuesForAutocomplete(['this' => $oObj, 'current_extkey_id' => $iCurrentExtKeyId], $sContains, 'contains');
|
||||
asort($aValuesContains);
|
||||
$iSize = sizeof($aValues);
|
||||
foreach ($aValuesContains as $sKey => $sFriendlyName)
|
||||
{
|
||||
if (!isset($aValues[$sKey]))
|
||||
{
|
||||
foreach ($aValuesContains as $sKey => $sFriendlyName) {
|
||||
if (!isset($aValues[$sKey])) {
|
||||
$aValues[$sKey] = $sFriendlyName;
|
||||
if (++$iSize >= $iMax)
|
||||
{
|
||||
if (++$iSize >= $iMax) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
elseif (!in_array($sContains, $aValues))
|
||||
{
|
||||
$aValuesEquals = $oValuesSet->GetValuesForAutocomplete(array('this' => $oObj, 'current_extkey_id' => $iCurrentExtKeyId), $sContains, 'equals');
|
||||
} elseif (!in_array($sContains, $aValues)) {
|
||||
$aValuesEquals = $oValuesSet->GetValuesForAutocomplete(['this' => $oObj, 'current_extkey_id' => $iCurrentExtKeyId], $sContains, 'equals');
|
||||
// Note: Here we cannot use array_merge as it would reindex the numeric keys starting from 0 when keys are actually the objects ID.
|
||||
// As a workaround we use array_replace as it does preserve numeric keys. It's ok if some values from $aValuesEquals are replaced with values from $aValues as they contain the same data.
|
||||
$aValues = array_replace($aValuesEquals, $aValues);
|
||||
}
|
||||
|
||||
switch($sOutputFormat)
|
||||
{
|
||||
switch ($sOutputFormat) {
|
||||
case static::ENUM_OUTPUT_FORMAT_JSON:
|
||||
|
||||
$aJsonMap = array();
|
||||
$aJsonMap = [];
|
||||
foreach ($aValues as $sKey => $aValue) {
|
||||
$aElt = ['value' => $sKey, 'label' => utils::EscapeHtml($aValue['label']), 'obsolescence_flag' => $aValue['obsolescence_flag']];
|
||||
if ($aValue['additional_field'] != '') {
|
||||
@@ -851,8 +871,7 @@ JS
|
||||
break;
|
||||
|
||||
case static::ENUM_OUTPUT_FORMAT_CSV:
|
||||
foreach($aValues as $sKey => $aValue)
|
||||
{
|
||||
foreach ($aValues as $sKey => $aValue) {
|
||||
$oP->add(trim($aValue['label'])."\t".$sKey."\n");
|
||||
}
|
||||
break;
|
||||
@@ -874,7 +893,7 @@ JS
|
||||
*/
|
||||
public function GetObjectName($iObjId, $sFormAttCode = null)
|
||||
{
|
||||
$aModifierProps = array();
|
||||
$aModifierProps = [];
|
||||
$aModifierProps['UserRightsGetSelectFilter']['bSearchMode'] = $this->bSearchMode;
|
||||
|
||||
$oObj = MetaModel::GetObject($this->sTargetClass, $iObjId, false, false, $aModifierProps);
|
||||
@@ -884,9 +903,7 @@ JS
|
||||
} else {
|
||||
return $oObj->Get($sFormAttCode);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
return '';
|
||||
}
|
||||
}
|
||||
@@ -902,30 +919,29 @@ JS
|
||||
*/
|
||||
public function GetClassSelectionForm(WebPage $oPage)
|
||||
{
|
||||
// For security reasons: check that the "proposed" class is actually a subclass of the linked class
|
||||
// and that the current user is allowed to create objects of this class
|
||||
$aSubClasses = MetaModel::EnumChildClasses($this->sTargetClass, ENUM_CHILD_CLASSES_ALL);
|
||||
$aPossibleClasses = array();
|
||||
foreach($aSubClasses as $sCandidateClass)
|
||||
{
|
||||
if (!MetaModel::IsAbstract($sCandidateClass) && (UserRights::IsActionAllowed($sCandidateClass, UR_ACTION_MODIFY) == UR_ALLOWED_YES))
|
||||
{
|
||||
$aPossibleClasses[$sCandidateClass] = MetaModel::GetName($sCandidateClass);
|
||||
}
|
||||
}
|
||||
// For security reasons: check that the "proposed" class is actually a subclass of the linked class
|
||||
// and that the current user is allowed to create objects of this class
|
||||
$aSubClasses = MetaModel::EnumChildClasses($this->sTargetClass, ENUM_CHILD_CLASSES_ALL);
|
||||
$aPossibleClasses = [];
|
||||
foreach ($aSubClasses as $sCandidateClass) {
|
||||
if (!MetaModel::IsAbstract($sCandidateClass) && (UserRights::IsActionAllowed($sCandidateClass, UR_ACTION_MODIFY) == UR_ALLOWED_YES)) {
|
||||
$aPossibleClasses[$sCandidateClass] = MetaModel::GetName($sCandidateClass);
|
||||
}
|
||||
}
|
||||
|
||||
$sClassLabel = MetaModel::GetName($this->sTargetClass);
|
||||
$sDialogTitle = Dict::Format('UI:CreationTitle_Class', $sClassLabel);;
|
||||
$oBlock = UIContentBlockUIBlockFactory::MakeStandard('ac_create_'.$this->iId,['ibo-is-visible']);
|
||||
$sDialogTitle = Dict::Format('UI:CreationTitle_Class', $sClassLabel);
|
||||
;
|
||||
$oBlock = UIContentBlockUIBlockFactory::MakeStandard('ac_create_'.$this->iId, ['ibo-is-visible']);
|
||||
$oPage->AddSubBlock($oBlock);
|
||||
$oClassForm = FormUIBlockFactory::MakeStandard();
|
||||
$oBlock->AddSubBlock($oClassForm);
|
||||
$oClassForm->AddSubBlock(cmdbAbstractObject::DisplayBlockSelectClassToCreate( $sClassLabel, $this->sTargetClass, $aPossibleClasses));
|
||||
$oClassForm->AddSubBlock(cmdbAbstractObject::DisplayBlockSelectClassToCreate($sClassLabel, $this->sTargetClass, $aPossibleClasses));
|
||||
$sDialogTitleEscaped = addslashes($sDialogTitle);
|
||||
$oPage->add_ready_script("$('#ac_create_$this->iId').dialog({ width: 'auto', height: 'auto', maxHeight: $(window).height() - 50, autoOpen: false, modal: true, title: '$sDialogTitleEscaped'});\n");
|
||||
$oPage->add_ready_script("$('#ac_create_{$this->iId} form').removeAttr('onsubmit');");
|
||||
$oPage->add_ready_script("$('#ac_create_{$this->iId} form').find('select').attr('id', 'ac_create_{$this->iId}_select');");
|
||||
$oPage->add_ready_script("$('#ac_create_{$this->iId} form').on('submit.uilinksWizard', oACWidget_{$this->iId}.DoSelectObjectClass);");
|
||||
$oPage->add_ready_script("$('#ac_create_$this->iId').dialog({ width: 'auto', height: 'auto', maxHeight: $(window).height() - 50, autoOpen: false, modal: true, title: '$sDialogTitleEscaped'});\n");
|
||||
$oPage->add_ready_script("$('#ac_create_{$this->iId} form').removeAttr('onsubmit');");
|
||||
$oPage->add_ready_script("$('#ac_create_{$this->iId} form').find('select').attr('id', 'ac_create_{$this->iId}_select');");
|
||||
$oPage->add_ready_script("$('#ac_create_{$this->iId} form').on('submit.uilinksWizard', oACWidget_{$this->iId}.DoSelectObjectClass);");
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -941,16 +957,14 @@ JS
|
||||
$oAppContext->InitObjectFromContext($oNewObj);
|
||||
$oNewObj->PrefillForm('creation_from_extkey', $aPrefillFormParam);
|
||||
// 2nd set the default values from the constraint on the external key... if any
|
||||
if ( ($oCurrObject != null) && ($this->sAttCode != ''))
|
||||
{
|
||||
if (($oCurrObject != null) && ($this->sAttCode != '')) {
|
||||
$oAttDef = MetaModel::GetAttributeDef(get_class($oCurrObject), $this->sAttCode);
|
||||
$aParams = array('this' => $oCurrObject);
|
||||
$aParams = ['this' => $oCurrObject];
|
||||
$oSet = $oAttDef->GetAllowedValuesAsObjectSet($aParams);
|
||||
$aConsts = $oSet->ListConstantFields();
|
||||
$sClassAlias = $oSet->GetFilter()->GetClassAlias();
|
||||
if (isset($aConsts[$sClassAlias]))
|
||||
{
|
||||
foreach($aConsts[$sClassAlias] as $sAttCode => $value) {
|
||||
if (isset($aConsts[$sClassAlias])) {
|
||||
foreach ($aConsts[$sClassAlias] as $sAttCode => $value) {
|
||||
$oNewObj->Set($sAttCode, $value);
|
||||
}
|
||||
}
|
||||
@@ -962,32 +976,35 @@ JS
|
||||
$sClassLabel = MetaModel::GetName($this->sTargetClass);
|
||||
$sHeaderTitleEscaped = utils::EscapeHtml(Dict::Format('UI:CreationTitle_Class', $sClassLabel));
|
||||
|
||||
$oPage->add(<<<HTML
|
||||
$oPage->add(
|
||||
<<<HTML
|
||||
<div id="ac_create_{$this->iId}" title="{$sHeaderTitleEscaped}">
|
||||
<div id="dcr_{$this->iId}">
|
||||
HTML
|
||||
);
|
||||
|
||||
$aFormExtraParams = array(
|
||||
$aFormExtraParams = [
|
||||
'formPrefix' => $this->iId,
|
||||
'noRelations' => true,
|
||||
);
|
||||
];
|
||||
|
||||
// Remove blob edition from creation form @see N°5863 to allow blob edition in modal context
|
||||
FormHelper::DisableAttributeBlobInputs($this->sTargetClass, $aFormExtraParams);
|
||||
|
||||
if(FormHelper::HasMandatoryAttributeBlobInputs($oNewObj)){
|
||||
if (FormHelper::HasMandatoryAttributeBlobInputs($oNewObj)) {
|
||||
$oPage->AddUiBlock(FormHelper::GetAlertForMandatoryAttributeBlobInputsInModal(FormHelper::ENUM_MANDATORY_BLOB_MODE_CREATE));
|
||||
}
|
||||
|
||||
cmdbAbstractObject::DisplayCreationForm($oPage, $this->sTargetClass, $oNewObj, array(), $aFormExtraParams);
|
||||
$oPage->add(<<<HTML
|
||||
|
||||
cmdbAbstractObject::DisplayCreationForm($oPage, $this->sTargetClass, $oNewObj, [], $aFormExtraParams);
|
||||
$oPage->add(
|
||||
<<<HTML
|
||||
</div>
|
||||
</div>
|
||||
HTML
|
||||
);
|
||||
|
||||
$oPage->add_ready_script(<<<JS
|
||||
$oPage->add_ready_script(
|
||||
<<<JS
|
||||
$('#ac_create_{$this->iId}').dialog({ width: $(window).width() * 0.6, height: 'auto', maxHeight: $(window).height() - 50, autoOpen: false, modal: true});
|
||||
$('#dcr_{$this->iId} form').removeAttr('onsubmit');
|
||||
$('#dcr_{$this->iId} form').find('button[type="submit"]').on('click', oACWidget_{$this->iId}.DoCreateObject);
|
||||
@@ -1003,14 +1020,13 @@ JS
|
||||
$sDialogTitle = addslashes(Dict::Format('UI:HierarchyOf_Class', MetaModel::GetName($this->sTargetClass)));
|
||||
$oPage->add('<div id="dlg_tree_'.$this->iId.'"><div class="wizContainer" style="vertical-align:top;"><div style="margin-bottom:5px;" id="tree_'.$this->iId.'">');
|
||||
$oPage->add('<table style="width:100%"><tr><td>');
|
||||
if (is_null($sFilter))
|
||||
{
|
||||
if (is_null($sFilter)) {
|
||||
throw new Exception('Implementation: null value for allowed values definition');
|
||||
}
|
||||
|
||||
$oFilter = DBObjectSearch::FromOQL($sFilter);
|
||||
$oFilter = DBObjectSearch::FromOQL($sFilter);
|
||||
$oFilter->SetModifierProperty('UserRightsGetSelectFilter', 'bSearchMode', $this->bSearchMode);
|
||||
$oSet = new DBObjectSet($oFilter, array(), array('this' => $oObj, 'current_extkey_id' => $currValue));
|
||||
$oSet = new DBObjectSet($oFilter, [], ['this' => $oObj, 'current_extkey_id' => $currValue]);
|
||||
|
||||
$oSet->SetShowObsoleteData(utils::ShowObsoleteData());
|
||||
|
||||
@@ -1020,17 +1036,17 @@ JS
|
||||
$oPage->add('</td></tr></table>');
|
||||
$oPage->add('</div>');
|
||||
|
||||
if ($bHasChildLeafs)
|
||||
{
|
||||
if ($bHasChildLeafs) {
|
||||
$oPage->add('<span class="treecontrol ibo-button-group" id="treecontrolid"><a class="ibo-button ibo-is-regular ibo-is-neutral" href="?#">'.Dict::S("UI:Treeview:CollapseAll").'</a><a class="ibo-button ibo-is-regular ibo-is-neutral" href="?#">'.Dict::S("UI:Treeview:ExpandAll").'</a></span>');
|
||||
}
|
||||
|
||||
|
||||
$oPage->add('</div></div>');
|
||||
|
||||
|
||||
$sOkButtonLabel = Dict::S('UI:Button:Ok');
|
||||
$sCancelButtonLabel = Dict::S('UI:Button:Cancel');
|
||||
$oPage->add_ready_script("\$('#tree_$this->iId ul').treeview({ control: '#treecontrolid', persist: 'false'});\n");
|
||||
$oPage->add_ready_script(<<<JS
|
||||
$oPage->add_ready_script(
|
||||
<<<JS
|
||||
$('#dlg_tree_$this->iId').dialog({
|
||||
width: 'auto',
|
||||
height: 'auto',
|
||||
@@ -1069,8 +1085,7 @@ JS
|
||||
*/
|
||||
public function DoCreateObject($oPage)
|
||||
{
|
||||
try
|
||||
{
|
||||
try {
|
||||
$oObj = MetaModel::NewObject($this->sTargetClass);
|
||||
$aErrors = $oObj->UpdateObjectFromPostedForm($this->iId);
|
||||
if (count($aErrors) == 0) {
|
||||
@@ -1088,13 +1103,12 @@ JS
|
||||
]);
|
||||
$oObj->DBInsertNoReload();
|
||||
|
||||
return array('name' => $oObj->GetName(), 'id' => $oObj->GetKey());
|
||||
return ['name' => $oObj->GetName(), 'id' => $oObj->GetKey()];
|
||||
} else {
|
||||
return array('error' => implode(' ', $aErrors), 'id' => 0);
|
||||
return ['error' => implode(' ', $aErrors), 'id' => 0];
|
||||
}
|
||||
}
|
||||
catch (Exception $e) {
|
||||
return array('error' => $e->getMessage(), 'id' => 0);
|
||||
} catch (Exception $e) {
|
||||
return ['error' => $e->getMessage(), 'id' => 0];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1110,32 +1124,27 @@ JS
|
||||
* @throws \CoreUnexpectedValue
|
||||
* @throws \MySQLException
|
||||
*/
|
||||
function DumpTree($oP, $oSet, $sParentAttCode, $currValue)
|
||||
public function DumpTree($oP, $oSet, $sParentAttCode, $currValue)
|
||||
{
|
||||
$aTree = array();
|
||||
$aNodes = array();
|
||||
while($oObj = $oSet->Fetch())
|
||||
{
|
||||
$aTree = [];
|
||||
$aNodes = [];
|
||||
while ($oObj = $oSet->Fetch()) {
|
||||
$iParentId = $oObj->Get($sParentAttCode);
|
||||
if (!isset($aTree[$iParentId]))
|
||||
{
|
||||
$aTree[$iParentId] = array();
|
||||
if (!isset($aTree[$iParentId])) {
|
||||
$aTree[$iParentId] = [];
|
||||
}
|
||||
$aTree[$iParentId][$oObj->GetKey()] = $oObj->GetName();
|
||||
$aNodes[$oObj->GetKey()] = $oObj;
|
||||
}
|
||||
|
||||
$aParents = array_keys($aTree);
|
||||
$aRoots = array();
|
||||
foreach($aParents as $id)
|
||||
{
|
||||
if (!array_key_exists($id, $aNodes))
|
||||
{
|
||||
$aRoots = [];
|
||||
foreach ($aParents as $id) {
|
||||
if (!array_key_exists($id, $aNodes)) {
|
||||
$aRoots[] = $id;
|
||||
}
|
||||
}
|
||||
foreach($aRoots as $iRootId)
|
||||
{
|
||||
foreach ($aRoots as $iRootId) {
|
||||
$this->DumpNodes($oP, $iRootId, $aTree, $aNodes, $currValue);
|
||||
}
|
||||
|
||||
@@ -1143,28 +1152,22 @@ JS
|
||||
return !$bHasOnlyRootNodes;
|
||||
}
|
||||
|
||||
function DumpNodes($oP, $iRootId, $aTree, $aNodes, $currValue)
|
||||
public function DumpNodes($oP, $iRootId, $aTree, $aNodes, $currValue)
|
||||
{
|
||||
$bSelect = true;
|
||||
$bMultiple = false;
|
||||
$sSelect = '';
|
||||
if (array_key_exists($iRootId, $aTree))
|
||||
{
|
||||
if (array_key_exists($iRootId, $aTree)) {
|
||||
$aSortedRoots = $aTree[$iRootId];
|
||||
asort($aSortedRoots);
|
||||
$oP->add("<ul>\n");
|
||||
$fUniqueId = microtime(true);
|
||||
foreach($aSortedRoots as $id => $sName)
|
||||
{
|
||||
if ($bSelect)
|
||||
{
|
||||
foreach ($aSortedRoots as $id => $sName) {
|
||||
if ($bSelect) {
|
||||
$sChecked = ($aNodes[$id]->GetKey() == $currValue) ? 'checked' : '';
|
||||
if ($bMultiple)
|
||||
{
|
||||
if ($bMultiple) {
|
||||
$sSelect = '<input id="input_'.$fUniqueId.'_'.$aNodes[$id]->GetKey().'" type="checkbox" value="'.$aNodes[$id]->GetKey().'" name="selectObject[]" '.$sChecked.'> ';
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
$sSelect = '<input id="input_'.$fUniqueId.'_'.$aNodes[$id]->GetKey().'" type="radio" value="'.$aNodes[$id]->GetKey().'" name="selectObject" '.$sChecked.'> ';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
<?php
|
||||
|
||||
// Copyright (C) 2010-2024 Combodo SAS
|
||||
//
|
||||
// This file is part of iTop.
|
||||
//
|
||||
// iTop is free software; you can redistribute it and/or modify
|
||||
// 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.
|
||||
@@ -30,7 +31,7 @@ use Combodo\iTop\Renderer\BlockRenderer;
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
class UIHTMLEditorWidget
|
||||
class UIHTMLEditorWidget
|
||||
{
|
||||
protected $m_iId;
|
||||
protected $m_oAttDef;
|
||||
@@ -41,7 +42,7 @@ class UIHTMLEditorWidget
|
||||
protected $m_sValidationField;
|
||||
protected $m_sValue;
|
||||
protected $m_sMandatory;
|
||||
|
||||
|
||||
public function __construct($iInputId, $oAttDef, $sNameSuffix, $sFieldPrefix, $sHelpText, $sValidationField, $sValue, $sMandatory)
|
||||
{
|
||||
$this->m_iId = $iInputId;
|
||||
@@ -54,7 +55,7 @@ class UIHTMLEditorWidget
|
||||
$this->m_sMandatory = $sMandatory;
|
||||
$this->m_sFieldPrefix = $sFieldPrefix;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the HTML fragment corresponding to the HTML editor widget
|
||||
*
|
||||
@@ -63,7 +64,7 @@ class UIHTMLEditorWidget
|
||||
*
|
||||
* @return string The HTML fragment to be inserted into the page
|
||||
*/
|
||||
public function Display(WebPage $oPage, array $aArgs = array()) : string
|
||||
public function Display(WebPage $oPage, array $aArgs = []): string
|
||||
{
|
||||
$iId = $this->m_iId;
|
||||
$sCode = $this->m_sAttCode.$this->m_sNameSuffix;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* @copyright Copyright (C) 2010-2024 Combodo SAS
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
@@ -38,39 +39,35 @@ class UILinksWidgetDirect
|
||||
$this->sAttCode = $sAttCode;
|
||||
$this->sInputid = $sInputId;
|
||||
$this->sNameSuffix = $sNameSuffix;
|
||||
$this->aZlist = array();
|
||||
$this->aZlist = [];
|
||||
$this->sLinkedClass = '';
|
||||
|
||||
|
||||
// Compute the list of attributes visible from the given objet:
|
||||
// All the attributes from the "list" Zlist of the Link class except
|
||||
// the ExternalKey that points to the current object and its related external fields
|
||||
$oLinksetDef = MetaModel::GetAttributeDef($sClass, $sAttCode);
|
||||
$this->sLinkedClass = $oLinksetDef->GetLinkedClass();
|
||||
$sExtKeyToMe = $oLinksetDef->GetExtKeyToMe();
|
||||
switch($oLinksetDef->GetEditMode())
|
||||
{
|
||||
switch ($oLinksetDef->GetEditMode()) {
|
||||
case LINKSET_EDITMODE_INPLACE: // The whole linkset can be edited 'in-place'
|
||||
$aZList = MetaModel::FlattenZList(MetaModel::GetZListItems($this->sLinkedClass, 'details'));
|
||||
break;
|
||||
|
||||
$aZList = MetaModel::FlattenZList(MetaModel::GetZListItems($this->sLinkedClass, 'details'));
|
||||
break;
|
||||
|
||||
default:
|
||||
$aZList = MetaModel::FlattenZList(MetaModel::GetZListItems($this->sLinkedClass, 'list'));
|
||||
array_unshift($aZList, 'friendlyname');
|
||||
$aZList = MetaModel::FlattenZList(MetaModel::GetZListItems($this->sLinkedClass, 'list'));
|
||||
array_unshift($aZList, 'friendlyname');
|
||||
}
|
||||
foreach($aZList as $sLinkedAttCode)
|
||||
{
|
||||
if ($sLinkedAttCode != $sExtKeyToMe)
|
||||
{
|
||||
foreach ($aZList as $sLinkedAttCode) {
|
||||
if ($sLinkedAttCode != $sExtKeyToMe) {
|
||||
$oAttDef = MetaModel::GetAttributeDef($this->sLinkedClass, $sLinkedAttCode);
|
||||
|
||||
|
||||
if ((!$oAttDef->IsExternalField() || ($oAttDef->GetKeyAttCode() != $sExtKeyToMe)) &&
|
||||
(!$oAttDef->IsLinkSet()) )
|
||||
{
|
||||
(!$oAttDef->IsLinkSet())) {
|
||||
$this->aZlist[] = $sLinkedAttCode;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -101,21 +98,17 @@ class UILinksWidgetDirect
|
||||
$sRealClass = '';
|
||||
//$oPage->add('<div class="wizContainer" style="vertical-align:top;"><div>');
|
||||
$aSubClasses = MetaModel::EnumChildClasses($this->sLinkedClass, ENUM_CHILD_CLASSES_ALL); // Including the specified class itself
|
||||
$aPossibleClasses = array();
|
||||
foreach($aSubClasses as $sCandidateClass)
|
||||
{
|
||||
if (!MetaModel::IsAbstract($sCandidateClass) && (UserRights::IsActionAllowed($sCandidateClass, UR_ACTION_MODIFY) == UR_ALLOWED_YES))
|
||||
{
|
||||
if ($sCandidateClass == $sProposedRealClass)
|
||||
{
|
||||
$aPossibleClasses = [];
|
||||
foreach ($aSubClasses as $sCandidateClass) {
|
||||
if (!MetaModel::IsAbstract($sCandidateClass) && (UserRights::IsActionAllowed($sCandidateClass, UR_ACTION_MODIFY) == UR_ALLOWED_YES)) {
|
||||
if ($sCandidateClass == $sProposedRealClass) {
|
||||
$sRealClass = $sProposedRealClass;
|
||||
}
|
||||
$aPossibleClasses[$sCandidateClass] = MetaModel::GetName($sCandidateClass);
|
||||
}
|
||||
}
|
||||
// Only one of the subclasses can be instantiated...
|
||||
if (count($aPossibleClasses) == 1)
|
||||
{
|
||||
if (count($aPossibleClasses) == 1) {
|
||||
$aKeys = array_keys($aPossibleClasses);
|
||||
$sRealClass = $aKeys[0];
|
||||
}
|
||||
@@ -123,11 +116,11 @@ class UILinksWidgetDirect
|
||||
if ($sRealClass != '') {
|
||||
$oLinksetDef = MetaModel::GetAttributeDef($this->sClass, $this->sAttCode);
|
||||
$sExtKeyToMe = $oLinksetDef->GetExtKeyToMe();
|
||||
$aFieldsFlags = array($sExtKeyToMe => OPT_ATT_HIDDEN);
|
||||
$aFieldsFlags = [$sExtKeyToMe => OPT_ATT_HIDDEN];
|
||||
$oObj = DBObject::MakeDefaultInstance($sRealClass);
|
||||
$aPrefillParam = array('source_obj' => $oSourceObj);
|
||||
$aPrefillParam = ['source_obj' => $oSourceObj];
|
||||
$oObj->PrefillForm('creation_from_editinplace', $aPrefillParam);
|
||||
$aFormExtraParams = array(
|
||||
$aFormExtraParams = [
|
||||
'formPrefix' => $this->sInputid,
|
||||
'noRelations' => true,
|
||||
'fieldsFlags' => $aFieldsFlags,
|
||||
@@ -140,25 +133,22 @@ class UILinksWidgetDirect
|
||||
JS
|
||||
,
|
||||
],
|
||||
);
|
||||
];
|
||||
|
||||
// Remove blob edition from creation form @see N°5863 to allow blob edition in modal context
|
||||
FormHelper::DisableAttributeBlobInputs($sRealClass, $aFormExtraParams);
|
||||
|
||||
if(FormHelper::HasMandatoryAttributeBlobInputs($oObj)){
|
||||
|
||||
if (FormHelper::HasMandatoryAttributeBlobInputs($oObj)) {
|
||||
$oPage->AddUiBlock(FormHelper::GetAlertForMandatoryAttributeBlobInputsInModal(FormHelper::ENUM_MANDATORY_BLOB_MODE_CREATE));
|
||||
}
|
||||
|
||||
cmdbAbstractObject::DisplayCreationForm($oPage, $sRealClass, $oObj, array(), $aFormExtraParams);
|
||||
}
|
||||
else
|
||||
{
|
||||
cmdbAbstractObject::DisplayCreationForm($oPage, $sRealClass, $oObj, [], $aFormExtraParams);
|
||||
} else {
|
||||
$sClassLabel = MetaModel::GetName($this->sLinkedClass);
|
||||
$oPage->add('<p>'.Dict::Format('UI:SelectTheTypeOf_Class_ToCreate', $sClassLabel));
|
||||
$oPage->add('<nobr><select name="class">');
|
||||
asort($aPossibleClasses);
|
||||
foreach($aPossibleClasses as $sClassName => $sClassLabel)
|
||||
{
|
||||
foreach ($aPossibleClasses as $sClassName => $sClassLabel) {
|
||||
$oPage->add("<option value=\"$sClassName\">$sClassLabel</option>");
|
||||
}
|
||||
$oPage->add('</select>');
|
||||
@@ -178,7 +168,7 @@ JS
|
||||
* @throws \MissingQueryArgument
|
||||
* @throws \OQLException
|
||||
*/
|
||||
public function GetObjectsSelectionDlg($oPage, $oCurrentObj, $aAlreadyLinked, $aPrefillFormParam = array())
|
||||
public function GetObjectsSelectionDlg($oPage, $oCurrentObj, $aAlreadyLinked, $aPrefillFormParam = [])
|
||||
{
|
||||
//$oPage->add("<div class=\"wizContainer\" style=\"vertical-align:top;\">\n");
|
||||
|
||||
@@ -199,8 +189,7 @@ JS
|
||||
|
||||
$oLinkSetDef = MetaModel::GetAttributeDef($this->sClass, $this->sAttCode);
|
||||
$valuesDef = $oLinkSetDef->GetValuesDef();
|
||||
if ($valuesDef === null)
|
||||
{
|
||||
if ($valuesDef === null) {
|
||||
$oFilter = new DBObjectSearch($this->sLinkedClass);
|
||||
} else {
|
||||
if (!$valuesDef instanceof ValueSetObjects) {
|
||||
@@ -218,8 +207,10 @@ JS
|
||||
$oCurrentObj->PrefillForm('search', $aPrefillFormParam);
|
||||
}
|
||||
$oBlock = new DisplayBlock($oFilter, 'search', false);
|
||||
$oPage->AddUiBlock($oBlock->GetDisplay($oPage, "SearchFormToAdd_{$this->sInputid}",
|
||||
array(
|
||||
$oPage->AddUiBlock($oBlock->GetDisplay(
|
||||
$oPage,
|
||||
"SearchFormToAdd_{$this->sInputid}",
|
||||
[
|
||||
'result_list_outer_selector' => "SearchResultsToAdd_{$this->sInputid}",
|
||||
'table_id' => "add_{$this->sInputid}",
|
||||
'table_inner_id' => "ResultsToAdd_{$this->sInputid}",
|
||||
@@ -227,16 +218,17 @@ JS
|
||||
'cssCount' => "#count_{$this->sInputid}",
|
||||
'query_params' => $oFilter->GetInternalParams(),
|
||||
'hidden_criteria' => $sHiddenCriteria,
|
||||
)
|
||||
]
|
||||
));
|
||||
$sEmptyList = Dict::S('UI:Message:EmptyList:UseSearchForm');
|
||||
$sCancel = Dict::S('UI:Button:Cancel');
|
||||
$sAdd = Dict::S('UI:Button:Add');
|
||||
|
||||
$oPage->add(<<<HTML
|
||||
$oPage->add(
|
||||
<<<HTML
|
||||
<form id="ObjectsAddForm_{$this->sInputid}">
|
||||
<div id="SearchResultsToAdd_{$this->sInputid}">
|
||||
<div style="background: #fff; border:0; text-align:center; vertical-align:middle;"><p>{$sEmptyList}</p></div>
|
||||
<div style="border:0; text-align:center; vertical-align:middle;"><p>{$sEmptyList}</p></div>
|
||||
</div>
|
||||
<input type="hidden" id="count_{$this->sInputid}" value="0"/>
|
||||
</form>
|
||||
@@ -256,52 +248,43 @@ HTML
|
||||
* @throws \CoreException
|
||||
* @throws \OQLException
|
||||
*/
|
||||
public function SearchObjectsToAdd(WebPage $oP, $sRemoteClass = '', $aAlreadyLinked = array(), $oCurrentObj = null, $aPrefillFormParam = array())
|
||||
public function SearchObjectsToAdd(WebPage $oP, $sRemoteClass = '', $aAlreadyLinked = [], $oCurrentObj = null, $aPrefillFormParam = [])
|
||||
{
|
||||
if ($sRemoteClass == '')
|
||||
{
|
||||
if ($sRemoteClass == '') {
|
||||
$sRemoteClass = $this->sLinkedClass;
|
||||
}
|
||||
$oLinkSetDef = MetaModel::GetAttributeDef($this->sClass, $this->sAttCode);
|
||||
$valuesDef = $oLinkSetDef->GetValuesDef();
|
||||
if ($valuesDef === null)
|
||||
{
|
||||
if ($valuesDef === null) {
|
||||
$oFilter = new DBObjectSearch($sRemoteClass);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!$valuesDef instanceof ValueSetObjects)
|
||||
{
|
||||
} else {
|
||||
if (!$valuesDef instanceof ValueSetObjects) {
|
||||
throw new Exception('Error: only ValueSetObjects are supported for "allowed_values" in AttributeLinkedSet ('.$this->sClass.'/'.$this->sAttCode.').');
|
||||
}
|
||||
$oFilter = DBObjectSearch::FromOQL($valuesDef->GetFilterExpression());
|
||||
}
|
||||
|
||||
if (($oCurrentObj != null) && MetaModel::IsSameFamilyBranch($sRemoteClass, $this->sClass))
|
||||
{
|
||||
|
||||
if (($oCurrentObj != null) && MetaModel::IsSameFamilyBranch($sRemoteClass, $this->sClass)) {
|
||||
// Prevent linking to self if the linked object is of the same family
|
||||
// and already present in the database
|
||||
if (!$oCurrentObj->IsNew())
|
||||
{
|
||||
if (!$oCurrentObj->IsNew()) {
|
||||
$oFilter->AddCondition('id', $oCurrentObj->GetKey(), '!=');
|
||||
}
|
||||
}
|
||||
if ($oCurrentObj != null)
|
||||
{
|
||||
if ($oCurrentObj != null) {
|
||||
$this->SetSearchDefaultFromContext($oCurrentObj, $oFilter);
|
||||
|
||||
$aArgs = array_merge($oCurrentObj->ToArgs('this'), $oFilter->GetInternalParams());
|
||||
$oFilter->SetInternalParams($aArgs);
|
||||
|
||||
|
||||
$aPrefillFormParam['filter'] = $oFilter;
|
||||
$oCurrentObj->PrefillForm('search', $aPrefillFormParam);
|
||||
}
|
||||
if (count($aAlreadyLinked) > 0)
|
||||
{
|
||||
if (count($aAlreadyLinked) > 0) {
|
||||
$oFilter->AddCondition('id', $aAlreadyLinked, 'NOTIN');
|
||||
}
|
||||
$oBlock = new DisplayBlock($oFilter, 'list', false);
|
||||
$oBlock->Display($oP, "ResultsToAdd_{$this->sInputid}", array('menu' => false, 'cssCount'=> '#count_'.$this->sInputid , 'selection_mode' => true, 'table_id' => 'add_'.$this->sInputid)); // Don't display the 'Actions' menu on the results
|
||||
$oBlock->Display($oP, "ResultsToAdd_{$this->sInputid}", ['menu' => false, 'cssCount' => '#count_'.$this->sInputid , 'selection_mode' => true, 'table_id' => 'add_'.$this->sInputid]); // Don't display the 'Actions' menu on the results
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -311,29 +294,28 @@ HTML
|
||||
public function DoAddObjects(WebPage $oP, $oFullSetFilter)
|
||||
{
|
||||
$aLinkedObjectIds = utils::ReadMultipleSelection($oFullSetFilter);
|
||||
foreach($aLinkedObjectIds as $iObjectId)
|
||||
{
|
||||
foreach ($aLinkedObjectIds as $iObjectId) {
|
||||
$oLinkObj = MetaModel::GetObject($this->sLinkedClass, $iObjectId);
|
||||
$oP->add($this->GetObjectRow($oP, $oLinkObj, $oLinkObj->GetKey()));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public function GetObjectModificationDlg()
|
||||
{
|
||||
|
||||
|
||||
}
|
||||
|
||||
public function GetTableConfig()
|
||||
{
|
||||
$aAttribs = array();
|
||||
$aAttribs['form::select'] = array(
|
||||
$aAttribs = [];
|
||||
$aAttribs['form::select'] = [
|
||||
'label' => "<input type=\"checkbox\" onClick=\"CheckAll('.selectList{$this->sInputid}:not(:disabled)', this.checked);oWidget".$this->sInputid.".directlinks('instance')._onSelectChange();\" class=\"checkAll\"></input>",
|
||||
'description' => Dict::S('UI:SelectAllToggle+'),
|
||||
);
|
||||
];
|
||||
|
||||
foreach ($this->aZlist as $sLinkedAttCode) {
|
||||
$oAttDef = MetaModel::GetAttributeDef($this->sLinkedClass, $sLinkedAttCode);
|
||||
$aAttribs[$sLinkedAttCode] = array('label' => MetaModel::GetLabel($this->sLinkedClass, $sLinkedAttCode), 'description' => $oAttDef->GetOrderByHint());
|
||||
$aAttribs[$sLinkedAttCode] = ['label' => MetaModel::GetLabel($this->sLinkedClass, $sLinkedAttCode), 'description' => $oAttDef->GetOrderByHint()];
|
||||
}
|
||||
|
||||
return $aAttribs;
|
||||
@@ -348,13 +330,12 @@ HTML
|
||||
*/
|
||||
public function GetRow($oPage, $sRealClass, $aValues, $iTempId)
|
||||
{
|
||||
if ($sRealClass == '')
|
||||
{
|
||||
if ($sRealClass == '') {
|
||||
$sRealClass = $this->sLinkedClass;
|
||||
}
|
||||
$oLinkObj = new $sRealClass();
|
||||
$oLinkObj->UpdateObjectFromPostedForm($this->sInputid);
|
||||
|
||||
|
||||
return $this->GetObjectRow($oPage, $oLinkObj, $iTempId);
|
||||
}
|
||||
|
||||
@@ -367,13 +348,12 @@ HTML
|
||||
protected function GetObjectRow($oPage, $oLinkObj, $iTempId)
|
||||
{
|
||||
$aAttribs = $this->GetTableConfig();
|
||||
$aRow = array();
|
||||
$aRow = [];
|
||||
$aRow['form::select'] = '<input type="checkbox" class="selectList'.$this->sInputid.'" value="'.($iTempId).'"/>';
|
||||
foreach($this->aZlist as $sLinkedAttCode)
|
||||
{
|
||||
foreach ($this->aZlist as $sLinkedAttCode) {
|
||||
$aRow[$sLinkedAttCode] = $oLinkObj->GetAsHTML($sLinkedAttCode);
|
||||
}
|
||||
return $oPage->GetTableRow($aRow, $aAttribs);
|
||||
return $oPage->GetTableRow($aRow, $aAttribs);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -386,23 +366,21 @@ HTML
|
||||
*/
|
||||
public function GetFormRow($oPage, $sRealClass, $aValues, $iTempId)
|
||||
{
|
||||
if ($sRealClass == '')
|
||||
{
|
||||
if ($sRealClass == '') {
|
||||
$sRealClass = $this->sLinkedClass;
|
||||
}
|
||||
$oLinkObj = new $sRealClass();
|
||||
$oLinkObj->UpdateObjectFromPostedForm($this->sInputid);
|
||||
|
||||
$aAttribs = $this->GetTableConfig();
|
||||
$aRow = array();
|
||||
$aRow = [];
|
||||
$aRow[] = '<input type="checkbox" class="selectList'.$this->sInputid.'" value="'.($iTempId).'"/>';
|
||||
foreach($this->aZlist as $sLinkedAttCode)
|
||||
{
|
||||
foreach ($this->aZlist as $sLinkedAttCode) {
|
||||
$aRow[] = $oLinkObj->GetAsHTML($sLinkedAttCode);
|
||||
}
|
||||
return $aRow;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Initializes the default search parameters based on 1) a 'current' object and 2) the silos defined by the context
|
||||
* @param DBObject $oSourceObj
|
||||
@@ -413,27 +391,23 @@ HTML
|
||||
$oAppContext = new ApplicationContext();
|
||||
$sSrcClass = get_class($oSourceObj);
|
||||
$sDestClass = $oSearch->GetClass();
|
||||
foreach($oAppContext->GetNames() as $key)
|
||||
{
|
||||
foreach ($oAppContext->GetNames() as $key) {
|
||||
// Find the value of the object corresponding to each 'context' parameter
|
||||
$aCallSpec = array($sSrcClass, 'MapContextParam');
|
||||
$aCallSpec = [$sSrcClass, 'MapContextParam'];
|
||||
$sAttCode = '';
|
||||
if (is_callable($aCallSpec))
|
||||
{
|
||||
$sAttCode = call_user_func($aCallSpec, $key); // Returns null when there is no mapping for this parameter
|
||||
if (is_callable($aCallSpec)) {
|
||||
$sAttCode = call_user_func($aCallSpec, $key); // Returns null when there is no mapping for this parameter
|
||||
}
|
||||
|
||||
if (MetaModel::IsValidAttCode($sSrcClass, $sAttCode))
|
||||
{
|
||||
if (MetaModel::IsValidAttCode($sSrcClass, $sAttCode)) {
|
||||
$defaultValue = $oSourceObj->Get($sAttCode);
|
||||
|
||||
// Find the attcode for the same 'context' parameter in the destination class
|
||||
// and sets its value as the default value for the search condition
|
||||
$aCallSpec = array($sDestClass, 'MapContextParam');
|
||||
$aCallSpec = [$sDestClass, 'MapContextParam'];
|
||||
$sAttCode = '';
|
||||
if (is_callable($aCallSpec))
|
||||
{
|
||||
$sAttCode = call_user_func($aCallSpec, $key); // Returns null when there is no mapping for this parameter
|
||||
if (is_callable($aCallSpec)) {
|
||||
$sAttCode = call_user_func($aCallSpec, $key); // Returns null when there is no mapping for this parameter
|
||||
}
|
||||
|
||||
if (MetaModel::IsValidAttCode($sDestClass, $sAttCode) && !empty($defaultValue)) {
|
||||
@@ -443,7 +417,6 @@ HTML
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public function GetClass(): string
|
||||
{
|
||||
return $this->sClass;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* @copyright Copyright (C) 2010-2024 Combodo SAS
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
@@ -54,7 +55,7 @@ class UILinksWidget
|
||||
$this->m_sNameSuffix = $sNameSuffix;
|
||||
$this->m_bDuplicatesAllowed = $bDuplicatesAllowed;
|
||||
|
||||
$this->m_aEditableFields = array();
|
||||
$this->m_aEditableFields = [];
|
||||
|
||||
/** @var AttributeLinkedSetIndirect $oAttDef */
|
||||
$oAttDef = MetaModel::GetAttributeDef($this->m_sClass, $this->m_sAttCode);
|
||||
@@ -67,34 +68,33 @@ class UILinksWidget
|
||||
$oLinkingAttDef = MetaModel::GetAttributeDef($this->m_sLinkedClass, $this->m_sExtKeyToRemote);
|
||||
$this->m_sRemoteClass = $oLinkingAttDef->GetTargetClass();
|
||||
|
||||
$this->m_aEditableFields = array();
|
||||
$this->m_aTableConfig = array();
|
||||
$this->m_aTableConfig['form::checkbox'] = array(
|
||||
$this->m_aEditableFields = [];
|
||||
$this->m_aTableConfig = [];
|
||||
$this->m_aTableConfig['form::checkbox'] = [
|
||||
'label' => "<input class=\"select_all\" type=\"checkbox\" value=\"1\" onClick=\"CheckAll('#linkedset_{$this->m_sAttCode}{$this->m_sNameSuffix} .selection', this.checked); oWidget".$this->m_sInputId.".OnSelectChange();\">",
|
||||
'description' => Dict::S('UI:SelectAllToggle+'),
|
||||
);
|
||||
];
|
||||
|
||||
$aLnkAttDefsToDisplay = MetaModel::GetZListAttDefsFilteredForIndirectLinkClass($sClass, $sAttCode);
|
||||
foreach ($aLnkAttDefsToDisplay as $oLnkAttDef)
|
||||
{
|
||||
foreach ($aLnkAttDefsToDisplay as $oLnkAttDef) {
|
||||
$sLnkAttCode = $oLnkAttDef->GetCode();
|
||||
$this->m_aEditableFields[] = $sLnkAttCode;
|
||||
$this->m_aTableConfig[$sLnkAttCode] = array('label' => $oLnkAttDef->GetLabel(), 'description' => $oLnkAttDef->GetDescription());
|
||||
$this->m_aTableConfig[$sLnkAttCode] = ['label' => $oLnkAttDef->GetLabel(), 'description' => $oLnkAttDef->GetDescription()];
|
||||
}
|
||||
|
||||
$this->m_aTableConfig['static::key'] = array(
|
||||
$this->m_aTableConfig['static::key'] = [
|
||||
'label' => MetaModel::GetName($this->m_sRemoteClass),
|
||||
'description' => MetaModel::GetClassDescription($this->m_sRemoteClass),
|
||||
);
|
||||
];
|
||||
$this->m_aEditableFields[] = $this->m_sExtKeyToRemote;
|
||||
|
||||
$aRemoteAttDefsToDisplay = MetaModel::GetZListAttDefsFilteredForIndirectRemoteClass($this->m_sRemoteClass);
|
||||
foreach ($aRemoteAttDefsToDisplay as $oRemoteAttDef) {
|
||||
$sRemoteAttCode = $oRemoteAttDef->GetCode();
|
||||
$this->m_aTableConfig['static::'.$sRemoteAttCode] = array(
|
||||
$this->m_aTableConfig['static::'.$sRemoteAttCode] = [
|
||||
'label' => $oRemoteAttDef->GetLabel(),
|
||||
'description' => $oRemoteAttDef->GetDescription(),
|
||||
);
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -105,7 +105,6 @@ class UILinksWidget
|
||||
return ($bSafe) ? utils::GetSafeId($sFieldId) : $sFieldId;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Display the table with the form for editing all the links at once
|
||||
*
|
||||
@@ -119,7 +118,6 @@ class UILinksWidget
|
||||
return DataTableUIBlockFactory::MakeForForm("{$this->m_sAttCode}{$this->m_sNameSuffix}", $aConfig, $aData);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the HTML fragment corresponding to the linkset editing widget
|
||||
*
|
||||
@@ -157,7 +155,7 @@ class UILinksWidget
|
||||
* @throws DictExceptionMissingString
|
||||
* @throws Exception
|
||||
*/
|
||||
public function GetObjectPickerDialog($oPage, $oCurrentObj, $sJson, $aAlreadyLinkedIds = array(), $aPrefillFormParam = array())
|
||||
public function GetObjectPickerDialog($oPage, $oCurrentObj, $sJson, $aAlreadyLinkedIds = [], $aPrefillFormParam = [])
|
||||
{
|
||||
$oAlreadyLinkedFilter = new DBObjectSearch($this->m_sRemoteClass);
|
||||
if (!$this->m_bDuplicatesAllowed && count($aAlreadyLinkedIds) > 0) {
|
||||
@@ -183,7 +181,9 @@ class UILinksWidget
|
||||
$sLinkedSetId = $oBlock->oUILinksWidget->GetLinkedSetId();
|
||||
|
||||
$oDisplayBlock = new DisplayBlock($oFilter, 'search', false);
|
||||
$oBlock->AddSubBlock($oDisplayBlock->GetDisplay($oPage, "SearchFormToAdd_{$sLinkedSetId}",
|
||||
$oBlock->AddSubBlock($oDisplayBlock->GetDisplay(
|
||||
$oPage,
|
||||
"SearchFormToAdd_{$sLinkedSetId}",
|
||||
[
|
||||
'menu' => false,
|
||||
'result_list_outer_selector' => "SearchResultsToAdd_{$sLinkedSetId}",
|
||||
@@ -195,7 +195,8 @@ class UILinksWidget
|
||||
'query_params' => $oFilter->GetInternalParams(),
|
||||
'hidden_criteria' => $sAlreadyLinkedExpression,
|
||||
'submit_on_load' => false,
|
||||
]));
|
||||
]
|
||||
));
|
||||
|
||||
$oBlock->AddForm();
|
||||
}
|
||||
@@ -212,25 +213,21 @@ class UILinksWidget
|
||||
* @throws \CoreException
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function SearchObjectsToAdd(WebPage $oP, $sRemoteClass = '', $aAlreadyLinkedIds = array(), $oCurrentObj = null)
|
||||
public function SearchObjectsToAdd(WebPage $oP, $sRemoteClass = '', $aAlreadyLinkedIds = [], $oCurrentObj = null)
|
||||
{
|
||||
if ($sRemoteClass != '')
|
||||
{
|
||||
if ($sRemoteClass != '') {
|
||||
// assert(MetaModel::IsParentClass($this->m_sRemoteClass, $sRemoteClass));
|
||||
$oFilter = new DBObjectSearch($sRemoteClass);
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
// No remote class specified use the one defined in the linkedset
|
||||
$oFilter = new DBObjectSearch($this->m_sRemoteClass);
|
||||
$oFilter = new DBObjectSearch($this->m_sRemoteClass);
|
||||
}
|
||||
if (!$this->m_bDuplicatesAllowed && count($aAlreadyLinkedIds) > 0)
|
||||
{
|
||||
if (!$this->m_bDuplicatesAllowed && count($aAlreadyLinkedIds) > 0) {
|
||||
$oFilter->AddCondition('id', $aAlreadyLinkedIds, 'NOTIN');
|
||||
}
|
||||
$this->SetSearchDefaultFromContext($oCurrentObj, $oFilter);
|
||||
$oBlock = new DisplayBlock($oFilter, 'list', false);
|
||||
$oBlock->Display($oP, "ResultsToAdd_{$this->m_sAttCode}", array('menu' => false, 'cssCount'=> '#count_'.$this->m_sAttCode.$this->m_sNameSuffix , 'selection_mode' => true, 'table_id' => 'add_'.$this->m_sAttCode)); // Don't display the 'Actions' menu on the results
|
||||
$oBlock->Display($oP, "ResultsToAdd_{$this->m_sAttCode}", ['menu' => false, 'cssCount' => '#count_'.$this->m_sAttCode.$this->m_sNameSuffix , 'selection_mode' => true, 'table_id' => 'add_'.$this->m_sAttCode]); // Don't display the 'Actions' menu on the results
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -251,7 +248,7 @@ class UILinksWidget
|
||||
$oLinkedObj = MetaModel::GetObject($this->m_sRemoteClass, $iObjectId, false);
|
||||
if (is_object($oLinkedObj)) {
|
||||
$oBlock = new BlockIndirectLinkSetEditTable($this);
|
||||
$aRow = $oBlock->GetFormRow($oP, $oLinkedObj, $iObjectId, array(), $oCurrentObj, $iAdditionId); // Not yet created link get negative Ids
|
||||
$aRow = $oBlock->GetFormRow($oP, $oLinkedObj, $iObjectId, [], $oCurrentObj, $iAdditionId); // Not yet created link get negative Ids
|
||||
$oRow = new FormTableRow("{$this->m_sAttCode}{$this->m_sNameSuffix}", $this->m_aTableConfig, $aRow, -$iAdditionId);
|
||||
$oP->AddUiBlock($oRow);
|
||||
$iAdditionId++;
|
||||
@@ -280,7 +277,7 @@ class UILinksWidget
|
||||
$oLinkedObj = MetaModel::GetObject($this->m_sRemoteClass, $iObjectId, false);
|
||||
if (is_object($oLinkedObj)) {
|
||||
$oBlock = new BlockIndirectLinkSetEditTable($this);
|
||||
$aRow = $oBlock->GetFormRow($oP, $oLinkedObj, $iObjectId, array(), $oCurrentObj, $iAdditionId, false /* Default value */, $bAllowRemoteExtKeyEdit); // Not yet created link get negative Ids
|
||||
$aRow = $oBlock->GetFormRow($oP, $oLinkedObj, $iObjectId, [], $oCurrentObj, $iAdditionId, false /* Default value */, $bAllowRemoteExtKeyEdit); // Not yet created link get negative Ids
|
||||
$aData = [];
|
||||
foreach ($aRow as $item) {
|
||||
$aData[] = $item;
|
||||
@@ -307,37 +304,30 @@ class UILinksWidget
|
||||
$oAppContext = new ApplicationContext();
|
||||
$sSrcClass = get_class($oSourceObj);
|
||||
$sDestClass = $oSearch->GetClass();
|
||||
foreach($oAppContext->GetNames() as $key)
|
||||
{
|
||||
foreach ($oAppContext->GetNames() as $key) {
|
||||
// Find the value of the object corresponding to each 'context' parameter
|
||||
$aCallSpec = array($sSrcClass, 'MapContextParam');
|
||||
$aCallSpec = [$sSrcClass, 'MapContextParam'];
|
||||
$sAttCode = '';
|
||||
if (is_callable($aCallSpec))
|
||||
{
|
||||
$sAttCode = call_user_func($aCallSpec, $key); // Returns null when there is no mapping for this parameter
|
||||
if (is_callable($aCallSpec)) {
|
||||
$sAttCode = call_user_func($aCallSpec, $key); // Returns null when there is no mapping for this parameter
|
||||
}
|
||||
|
||||
if (MetaModel::IsValidAttCode($sSrcClass, $sAttCode))
|
||||
{
|
||||
if (MetaModel::IsValidAttCode($sSrcClass, $sAttCode)) {
|
||||
$defaultValue = $oSourceObj->Get($sAttCode);
|
||||
|
||||
// Find the attcode for the same 'context' parameter in the destination class
|
||||
// and sets its value as the default value for the search condition
|
||||
$aCallSpec = array($sDestClass, 'MapContextParam');
|
||||
$aCallSpec = [$sDestClass, 'MapContextParam'];
|
||||
$sAttCode = '';
|
||||
if (is_callable($aCallSpec))
|
||||
{
|
||||
$sAttCode = call_user_func($aCallSpec, $key); // Returns null when there is no mapping for this parameter
|
||||
if (is_callable($aCallSpec)) {
|
||||
$sAttCode = call_user_func($aCallSpec, $key); // Returns null when there is no mapping for this parameter
|
||||
}
|
||||
|
||||
if (MetaModel::IsValidAttCode($sDestClass, $sAttCode) && !empty($defaultValue))
|
||||
{
|
||||
|
||||
if (MetaModel::IsValidAttCode($sDestClass, $sAttCode) && !empty($defaultValue)) {
|
||||
// Add Hierarchical condition if hierarchical key
|
||||
$oAttDef = MetaModel::GetAttributeDef($sDestClass, $sAttCode);
|
||||
if (isset($oAttDef) && ($oAttDef->IsExternalKey()))
|
||||
{
|
||||
try
|
||||
{
|
||||
if (isset($oAttDef) && ($oAttDef->IsExternalKey())) {
|
||||
try {
|
||||
/** @var AttributeExternalKey $oAttDef */
|
||||
$sTargetClass = $oAttDef->GetTargetClass();
|
||||
$sHierarchicalKeyCode = MetaModel::IsHierarchicalClass($sTargetClass);
|
||||
@@ -348,8 +338,7 @@ class UILinksWidget
|
||||
$oHKFilter->AddCondition_PointingTo($oFilter, $sHierarchicalKeyCode, TREE_OPERATOR_BELOW);
|
||||
$oSearch->AddCondition_PointingTo($oHKFilter, $sAttCode);
|
||||
}
|
||||
}
|
||||
catch (Exception $e) {
|
||||
} catch (Exception $e) {
|
||||
}
|
||||
} else {
|
||||
$oSearch->AddCondition($sAttCode, $defaultValue);
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
<?php
|
||||
|
||||
// Copyright (C) 2010-2024 Combodo SAS
|
||||
//
|
||||
// This file is part of iTop.
|
||||
//
|
||||
// iTop is free software; you can redistribute it and/or modify
|
||||
// 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.
|
||||
@@ -28,13 +29,13 @@ use Combodo\iTop\Application\WebPage\WebPage;
|
||||
|
||||
require_once(APPROOT.'/application/displayblock.class.inc.php');
|
||||
|
||||
class UIPasswordWidget
|
||||
class UIPasswordWidget
|
||||
{
|
||||
protected static $iWidgetIndex = 0;
|
||||
protected $sAttCode;
|
||||
protected $sNameSuffix;
|
||||
protected $iId;
|
||||
|
||||
|
||||
public function __construct($sAttCode, $iInputId, $sNameSuffix = '')
|
||||
{
|
||||
self::$iWidgetIndex++;
|
||||
@@ -42,14 +43,14 @@ class UIPasswordWidget
|
||||
$this->sNameSuffix = $sNameSuffix;
|
||||
$this->iId = $iInputId;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the HTML fragment corresponding to the linkset editing widget
|
||||
* @param WebPage $oP The web page used for all the output
|
||||
* @param Hash $aArgs Extra context arguments
|
||||
* @return string The HTML fragment to be inserted into the page
|
||||
*/
|
||||
public function Display(WebPage $oPage, $aArgs = array())
|
||||
public function Display(WebPage $oPage, $aArgs = [])
|
||||
{
|
||||
$oPage->add_dict_entry('UI:Component:Input:Password:DoesNotMatch');
|
||||
|
||||
@@ -94,4 +95,3 @@ class UIPasswordWidget
|
||||
return $sHtmlValue;
|
||||
}
|
||||
}
|
||||
?>
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
*
|
||||
* Copyright (C) 2010-2024 Combodo SAS
|
||||
@@ -20,13 +21,15 @@
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
use Combodo\iTop\Application\WebPage\WebPage;
|
||||
|
||||
require_once(APPROOT.'/application/displayblock.class.inc.php');
|
||||
|
||||
class UISearchFormForeignKeys
|
||||
{
|
||||
private $m_sRemoteClass;
|
||||
private $m_iInputId;
|
||||
|
||||
public function __construct($sTargetClass, $iInputId = null)
|
||||
{
|
||||
$this->m_sRemoteClass = $sTargetClass;
|
||||
@@ -40,14 +43,16 @@ class UISearchFormForeignKeys
|
||||
*
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function ShowModalSearchForeignKeys($oPage, $sTitle)
|
||||
public function ShowModalSearchForeignKeys($oPage)
|
||||
{
|
||||
|
||||
$oFilter = new DBObjectSearch($this->m_sRemoteClass);
|
||||
|
||||
$oBlock = new DisplayBlock($oFilter, 'search', false);
|
||||
$oPage->AddUiBlock($oBlock->GetDisplay($oPage, "SearchFormToAdd_{$this->m_iInputId}",
|
||||
array(
|
||||
$oPage->AddUiBlock($oBlock->GetDisplay(
|
||||
$oPage,
|
||||
"SearchFormToAdd_{$this->m_iInputId}",
|
||||
[
|
||||
'menu' => false,
|
||||
'result_list_outer_selector' => "SearchResultsToAdd_{$this->m_iInputId}",
|
||||
'table_id' => "add_{$this->m_iInputId}",
|
||||
@@ -55,94 +60,31 @@ class UISearchFormForeignKeys
|
||||
'selection_mode' => true,
|
||||
'cssCount' => "#count_{$this->m_iInputId}",
|
||||
'query_params' => $oFilter->GetInternalParams(),
|
||||
)));
|
||||
]
|
||||
));
|
||||
$sEmptyList = Dict::S('UI:Message:EmptyList:UseSearchForm');
|
||||
$sCancel = Dict::S('UI:Button:Cancel');
|
||||
$sAdd = Dict::S('UI:Button:Add');
|
||||
|
||||
$oPage->add(<<<HTML
|
||||
$oPage->add(
|
||||
<<<HTML
|
||||
<form id="ObjectsAddForm_{$this->m_iInputId}">
|
||||
<div id="SearchResultsToAdd_{$this->m_iInputId}" style="vertical-align:top;height:100%;overflow:auto;padding:0;border:0;">
|
||||
<div style="background: #fff; border:0; text-align:center; vertical-align:middle;"><p>{$sEmptyList}</p></div>
|
||||
<div style="border:0; text-align:center; vertical-align:middle;"><p>{$sEmptyList}</p></div>
|
||||
</div>
|
||||
<input type="hidden" id="count_{$this->m_iInputId}" value="0"/>
|
||||
</form>
|
||||
HTML
|
||||
);
|
||||
|
||||
$oPage->add_ready_script(
|
||||
<<<JS
|
||||
$('#dlg_{$this->m_iInputId}').dialog({
|
||||
width: $(window).width()*0.8,
|
||||
height: $(window).height()*0.8,
|
||||
autoOpen: false,
|
||||
modal: true,
|
||||
resizeStop: oForeignKeysWidget{$this->m_iInputId}.UpdateSizes,
|
||||
buttons: [
|
||||
{
|
||||
text: Dict.S('UI:Button:Cancel'),
|
||||
class: "cancel ibo-is-alternative ibo-is-neutral",
|
||||
click: function() {
|
||||
$('#dlg_{$this->m_iInputId}').dialog('close');
|
||||
}
|
||||
},
|
||||
{
|
||||
text: Dict.S('UI:Button:Add'),
|
||||
id: 'btn_ok_{$this->m_iInputId}',
|
||||
class: "ok ibo-is-regular ibo-is-primary",
|
||||
click: function() {
|
||||
oForeignKeysWidget{$this->m_iInputId}.DoAddObjects(this.id);
|
||||
}
|
||||
},
|
||||
],
|
||||
|
||||
});
|
||||
$('#dlg_{$this->m_iInputId}').dialog('option', {title:'$sTitle'});
|
||||
$('#SearchFormToAdd_{$this->m_iInputId} form').on('submit.uilinksWizard', oForeignKeysWidget{$this->m_iInputId}.SearchObjectsToAdd);
|
||||
$('#SearchFormToAdd_{$this->m_iInputId}').on('resize', oForeignKeysWidget{$this->m_iInputId}.UpdateSizes);
|
||||
JS
|
||||
);
|
||||
}
|
||||
|
||||
public function GetFullListForeignKeysFromSelection($oPage, $oFullSetFilter)
|
||||
{
|
||||
try
|
||||
{
|
||||
try {
|
||||
$aLinkedObjects = utils::ReadMultipleSelectionWithFriendlyname($oFullSetFilter);
|
||||
$oPage->add(json_encode($aLinkedObjects));
|
||||
}
|
||||
catch (CoreException $e)
|
||||
{
|
||||
} catch (CoreException $e) {
|
||||
http_response_code(500);
|
||||
$oPage->add(json_encode(array('error' => $e->GetMessage())));
|
||||
$oPage->add(json_encode(['error' => $e->GetMessage()]));
|
||||
IssueLog::Error($e->getMessage()."\nDebug trace:\n".$e->getTraceAsString());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Search for objects to be linked to the current object (i.e "remote" objects)
|
||||
*
|
||||
* @param WebPage $oP The page used for the output (usually an AjaxWebPage)
|
||||
* @param string $sRemoteClass Name of the "remote" class to perform the search on, must be a derived class of m_sRemoteClass
|
||||
*
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function ListResultsSearchForeignKeys(WebPage $oP, $sRemoteClass = '')
|
||||
{
|
||||
if ($sRemoteClass != '')
|
||||
{
|
||||
// assert(MetaModel::IsParentClass($this->m_sRemoteClass, $sRemoteClass));
|
||||
$oFilter = new DBObjectSearch($sRemoteClass);
|
||||
}
|
||||
else
|
||||
{
|
||||
// No remote class specified use the one defined in the linkedset
|
||||
$oFilter = new DBObjectSearch($this->m_sRemoteClass);
|
||||
}
|
||||
|
||||
$oBlock = new DisplayBlock($oFilter, 'list', false);
|
||||
$oBlock->Display($oP, "ResultsToAdd_{$this->m_iInputId}",
|
||||
array('menu' => false, 'cssCount' => "#count_{$this->m_iInputId}", 'selection_mode' => true, 'table_id' => "add_{$this->m_iInputId}"));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
<?php
|
||||
|
||||
// Copyright (C) 2010-2024 Combodo SAS
|
||||
//
|
||||
// This file is part of iTop.
|
||||
//
|
||||
// iTop is free software; you can redistribute it and/or modify
|
||||
// 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.
|
||||
@@ -17,7 +18,6 @@
|
||||
// along with iTop. If not, see <http://www.gnu.org/licenses/>
|
||||
use Combodo\iTop\Application\WebPage\iTopWebPage;
|
||||
|
||||
|
||||
/**
|
||||
* Class UIWizard
|
||||
*
|
||||
@@ -31,74 +31,73 @@ class UIWizard
|
||||
protected $m_sClass;
|
||||
protected $m_sTargetState;
|
||||
protected $m_aWizardSteps;
|
||||
|
||||
|
||||
public function __construct($oPage, $sClass, $sTargetState = '')
|
||||
{
|
||||
$this->m_oPage = $oPage;
|
||||
$this->m_sClass = $sClass;
|
||||
if (empty($sTargetState))
|
||||
{
|
||||
if (empty($sTargetState)) {
|
||||
$sTargetState = MetaModel::GetDefaultState($sClass);
|
||||
}
|
||||
$this->m_sTargetState = $sTargetState;
|
||||
$this->m_aWizardSteps = $this->ComputeWizardStructure();
|
||||
}
|
||||
|
||||
public function GetObjectClass() { return $this->m_sClass; }
|
||||
public function GetTargetState() { return $this->m_sTargetState; }
|
||||
public function GetWizardStructure() { return $this->m_aWizardSteps; }
|
||||
|
||||
|
||||
public function GetObjectClass()
|
||||
{
|
||||
return $this->m_sClass;
|
||||
}
|
||||
public function GetTargetState()
|
||||
{
|
||||
return $this->m_sTargetState;
|
||||
}
|
||||
public function GetWizardStructure()
|
||||
{
|
||||
return $this->m_aWizardSteps;
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays one step of the wizard
|
||||
*/
|
||||
public function DisplayWizardStep($aStep, $iStepIndex, &$iMaxInputId, &$aFieldsMap, $bFinishEnabled = false, $aArgs = array())
|
||||
*/
|
||||
public function DisplayWizardStep($aStep, $iStepIndex, &$iMaxInputId, &$aFieldsMap, $bFinishEnabled = false, $aArgs = [])
|
||||
{
|
||||
if ($iStepIndex == 1) // one big form that contains everything, to make sure that the uploaded files are posted too
|
||||
{
|
||||
if ($iStepIndex == 1) { // one big form that contains everything, to make sure that the uploaded files are posted too
|
||||
$this->m_oPage->add("<form method=\"post\" enctype=\"multipart/form-data\" action=\"".utils::GetAbsoluteUrlAppRoot()."pages/UI.php\">\n");
|
||||
}
|
||||
$this->m_oPage->add("<div class=\"wizContainer\" id=\"wizStep$iStepIndex\" style=\"display:none;\">\n");
|
||||
$this->m_oPage->add("<a name=\"step$iStepIndex\" />\n");
|
||||
$aStates = MetaModel::EnumStates($this->m_sClass);
|
||||
$aDetails = array();
|
||||
$aDetails = [];
|
||||
$sJSHandlerCode = ''; // Javascript code to be executed each time this step of the wizard is entered
|
||||
foreach($aStep as $sAttCode)
|
||||
{
|
||||
foreach ($aStep as $sAttCode) {
|
||||
$oAttDef = MetaModel::GetAttributeDef($this->m_sClass, $sAttCode);
|
||||
if ($oAttDef->IsWritable())
|
||||
{
|
||||
if ($oAttDef->IsWritable()) {
|
||||
$sAttLabel = $oAttDef->GetLabel();
|
||||
$iOptions = isset($aStates[$this->m_sTargetState]['attribute_list'][$sAttCode]) ? $aStates[$this->m_sTargetState]['attribute_list'][$sAttCode] : 0;
|
||||
|
||||
|
||||
$aPrerequisites = $oAttDef->GetPrerequisiteAttributes();
|
||||
if ($iOptions & (OPT_ATT_MANDATORY | OPT_ATT_MUSTCHANGE | OPT_ATT_MUSTPROMPT))
|
||||
{
|
||||
$aFields[$sAttCode] = array();
|
||||
foreach($aPrerequisites as $sCode)
|
||||
{
|
||||
if ($iOptions & (OPT_ATT_MANDATORY | OPT_ATT_MUSTCHANGE | OPT_ATT_MUSTPROMPT)) {
|
||||
$aFields[$sAttCode] = [];
|
||||
foreach ($aPrerequisites as $sCode) {
|
||||
$aFields[$sAttCode][$sCode] = '';
|
||||
}
|
||||
}
|
||||
if (count($aPrerequisites) > 0)
|
||||
{
|
||||
if (count($aPrerequisites) > 0) {
|
||||
$aOptions[] = 'Prerequisites: '.implode(', ', $aPrerequisites);
|
||||
}
|
||||
|
||||
$sFieldFlag = (($iOptions & (OPT_ATT_MANDATORY | OPT_ATT_MUSTCHANGE)) || (!$oAttDef->IsNullAllowed()) )? ' <span class="hilite">*</span>' : '';
|
||||
|
||||
$sFieldFlag = (($iOptions & (OPT_ATT_MANDATORY | OPT_ATT_MUSTCHANGE)) || (!$oAttDef->IsNullAllowed())) ? ' <span class="hilite">*</span>' : '';
|
||||
$oDefaultValuesSet = $oAttDef->GetDefaultValue(/* $oObject->ToArgs() */); // @@@ TO DO: get the object's current value if the object exists
|
||||
$sHTMLValue = cmdbAbstractObject::GetFormElementForField($this->m_oPage, $this->m_sClass, $sAttCode, $oAttDef, $oDefaultValuesSet, '', "att_$iMaxInputId", '', $iOptions, $aArgs);
|
||||
$aFieldsMap["att_$iMaxInputId"] = $sAttCode;
|
||||
$aDetails[] = array('label' => '<span title="'.$oAttDef->GetDescription().'">'.$oAttDef->GetLabel().$sFieldFlag.'</span>', 'value' => "<span id=\"field_att_$iMaxInputId\">$sHTMLValue</span>");
|
||||
if ($oAttDef->GetValuesDef() != null)
|
||||
{
|
||||
$aDetails[] = ['label' => '<span title="'.$oAttDef->GetDescription().'">'.$oAttDef->GetLabel().$sFieldFlag.'</span>', 'value' => "<span id=\"field_att_$iMaxInputId\">$sHTMLValue</span>"];
|
||||
if ($oAttDef->GetValuesDef() != null) {
|
||||
$sJSHandlerCode .= "\toWizardHelper.RequestAllowedValues('$sAttCode');\n";
|
||||
}
|
||||
if ($oAttDef->GetDefaultValue() != null)
|
||||
{
|
||||
if ($oAttDef->GetDefaultValue() != null) {
|
||||
$sJSHandlerCode .= "\toWizardHelper.RequestDefaultValue('$sAttCode');\n";
|
||||
}
|
||||
if ($oAttDef->IsLinkSet())
|
||||
{
|
||||
if ($oAttDef->IsLinkSet()) {
|
||||
$sJSHandlerCode .= "\toLinkWidgetatt_$iMaxInputId.Init();";
|
||||
}
|
||||
$iMaxInputId++;
|
||||
@@ -126,11 +125,11 @@ $sJSHandlerCode
|
||||
}
|
||||
");
|
||||
$this->m_oPage->add("</div>\n\n");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Display the final step of the wizard: a confirmation screen
|
||||
*/
|
||||
*/
|
||||
public function DisplayFinalStep($iStepIndex, $aFieldsMap)
|
||||
{
|
||||
$oAppContext = new ApplicationContext();
|
||||
@@ -141,136 +140,116 @@ $sJSHandlerCode
|
||||
$this->m_oPage->add("<input type=\"hidden\" name=\"transaction_id\" value=\"".utils::GetNewTransactionId()."\" />\n");
|
||||
$this->m_oPage->add("<input type=\"hidden\" id=\"wizard_json_obj\" name=\"json_obj\" value=\"\" />\n");
|
||||
$sScript = "function OnEnterStep$iStepIndex() {\n";
|
||||
foreach($aFieldsMap as $iInputId => $sAttCode)
|
||||
{
|
||||
$sScript .= "\toWizardHelper.UpdateCurrentValue('$sAttCode');\n";
|
||||
foreach ($aFieldsMap as $iInputId => $sAttCode) {
|
||||
$sScript .= "\toWizardHelper.UpdateCurrentValue('$sAttCode');\n";
|
||||
}
|
||||
$sScript .= "\toWizardHelper.Preview('object_preview');\n";
|
||||
$sScript .= "\t$('#wizard_json_obj').val(oWizardHelper.ToJSON());\n";
|
||||
$sScript .= "\toWizardHelper.Preview('object_preview');\n";
|
||||
$sScript .= "\t$('#wizard_json_obj').val(oWizardHelper.ToJSON());\n";
|
||||
$sScript .= "}\n";
|
||||
$this->m_oPage->add_script($sScript);
|
||||
$this->m_oPage->add("<div id=\"object_preview\">\n");
|
||||
$this->m_oPage->add("</div>\n");
|
||||
$this->m_oPage->add($oAppContext->GetForForm());
|
||||
$this->m_oPage->add($oAppContext->GetForForm());
|
||||
$this->m_oPage->add("<input type=\"button\" value=\"".Dict::S('UI:Button:Back')."\" onClick=\"GoToStep($iStepIndex, $iStepIndex - 1)\" />");
|
||||
$this->m_oPage->add("<input type=\"submit\" value=\"Create ".MetaModel::GetName($this->m_sClass)."\" />\n");
|
||||
$this->m_oPage->add("</div>\n");
|
||||
$this->m_oPage->add("</form>\n");
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Compute the order of the fields & pages in the wizard
|
||||
* @param $oPage iTopWebPage The current page (used to display error messages)
|
||||
* @param $oPage iTopWebPage The current page (used to display error messages)
|
||||
* @param $sClass string Name of the class
|
||||
* @param $sStateCode string Code of the target state of the object
|
||||
* @return hash Two dimensional array: each element represents the list of fields for a given page
|
||||
* @return hash Two dimensional array: each element represents the list of fields for a given page
|
||||
*/
|
||||
protected function ComputeWizardStructure()
|
||||
{
|
||||
$aWizardSteps = array( 'mandatory' => array(), 'optional' => array());
|
||||
$aFieldsDone = array(); // Store all the fields that are already covered by a previous step of the wizard
|
||||
|
||||
$aWizardSteps = [ 'mandatory' => [], 'optional' => []];
|
||||
$aFieldsDone = []; // Store all the fields that are already covered by a previous step of the wizard
|
||||
|
||||
$aStates = MetaModel::EnumStates($this->m_sClass);
|
||||
$sStateAttCode = MetaModel::GetStateAttributeCode($this->m_sClass);
|
||||
|
||||
$aMandatoryAttributes = array();
|
||||
// Some attributes are always mandatory independently of the state machine (if any)
|
||||
foreach(MetaModel::GetAttributesList($this->m_sClass) as $sAttCode)
|
||||
{
|
||||
$oAttDef = MetaModel::GetAttributeDef($this->m_sClass, $sAttCode);
|
||||
if (!$oAttDef->IsExternalField() && !$oAttDef->IsNullAllowed() &&
|
||||
$oAttDef->IsWritable() && ($sAttCode != $sStateAttCode) )
|
||||
{
|
||||
$aMandatoryAttributes[$sAttCode] = OPT_ATT_MANDATORY;
|
||||
}
|
||||
}
|
||||
|
||||
// Now check the attributes that are mandatory in the specified state
|
||||
if ( (!empty($this->m_sTargetState)) && (count($aStates[$this->m_sTargetState]['attribute_list']) > 0) )
|
||||
{
|
||||
$aMandatoryAttributes = [];
|
||||
// Some attributes are always mandatory independently of the state machine (if any)
|
||||
foreach (MetaModel::GetAttributesList($this->m_sClass) as $sAttCode) {
|
||||
$oAttDef = MetaModel::GetAttributeDef($this->m_sClass, $sAttCode);
|
||||
if (!$oAttDef->IsExternalField() && !$oAttDef->IsNullAllowed() &&
|
||||
$oAttDef->IsWritable() && ($sAttCode != $sStateAttCode)) {
|
||||
$aMandatoryAttributes[$sAttCode] = OPT_ATT_MANDATORY;
|
||||
}
|
||||
}
|
||||
|
||||
// Now check the attributes that are mandatory in the specified state
|
||||
if ((!empty($this->m_sTargetState)) && (count($aStates[$this->m_sTargetState]['attribute_list']) > 0)) {
|
||||
// Check all the fields that *must* be included in the wizard for this
|
||||
// particular target state
|
||||
$aFields = array();
|
||||
foreach($aStates[$this->m_sTargetState]['attribute_list'] as $sAttCode => $iOptions)
|
||||
{
|
||||
if ( (isset($aMandatoryAttributes[$sAttCode])) &&
|
||||
($aMandatoryAttributes[$sAttCode] & (OPT_ATT_MANDATORY | OPT_ATT_MUSTCHANGE | OPT_ATT_MUSTPROMPT)) )
|
||||
{
|
||||
$aFields = [];
|
||||
foreach ($aStates[$this->m_sTargetState]['attribute_list'] as $sAttCode => $iOptions) {
|
||||
if ((isset($aMandatoryAttributes[$sAttCode])) &&
|
||||
($aMandatoryAttributes[$sAttCode] & (OPT_ATT_MANDATORY | OPT_ATT_MUSTCHANGE | OPT_ATT_MUSTPROMPT))) {
|
||||
$aMandatoryAttributes[$sAttCode] |= $iOptions;
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
$aMandatoryAttributes[$sAttCode] = $iOptions;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Check all the fields that *must* be included in the wizard
|
||||
// i.e. all mandatory, must-change or must-prompt fields that are
|
||||
// not also read-only or hidden.
|
||||
// Some fields may be required (null not allowed) from the database
|
||||
// perspective, but hidden or read-only from the user interface perspective
|
||||
$aFields = array();
|
||||
foreach($aMandatoryAttributes as $sAttCode => $iOptions)
|
||||
{
|
||||
if ( ($iOptions & (OPT_ATT_MANDATORY | OPT_ATT_MUSTCHANGE | OPT_ATT_MUSTPROMPT)) &&
|
||||
!($iOptions & (OPT_ATT_READONLY | OPT_ATT_HIDDEN)) )
|
||||
{
|
||||
// perspective, but hidden or read-only from the user interface perspective
|
||||
$aFields = [];
|
||||
foreach ($aMandatoryAttributes as $sAttCode => $iOptions) {
|
||||
if (($iOptions & (OPT_ATT_MANDATORY | OPT_ATT_MUSTCHANGE | OPT_ATT_MUSTPROMPT)) &&
|
||||
!($iOptions & (OPT_ATT_READONLY | OPT_ATT_HIDDEN))) {
|
||||
$oAttDef = MetaModel::GetAttributeDef($this->m_sClass, $sAttCode);
|
||||
$aPrerequisites = $oAttDef->GetPrerequisiteAttributes();
|
||||
$aFields[$sAttCode] = array();
|
||||
foreach($aPrerequisites as $sCode)
|
||||
{
|
||||
$aFields[$sAttCode] = [];
|
||||
foreach ($aPrerequisites as $sCode) {
|
||||
$aFields[$sAttCode][$sCode] = '';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Now use the dependencies between the fields to order them
|
||||
// Start from the order of the 'details'
|
||||
$aList = MetaModel::FlattenZlist(MetaModel::GetZListItems($this->m_sClass, 'details'));
|
||||
$index = 0;
|
||||
$aOrder = array();
|
||||
foreach($aFields as $sAttCode => $void)
|
||||
{
|
||||
$aOrder[$sAttCode] = 999; // At the end of the list...
|
||||
$aOrder = [];
|
||||
foreach ($aFields as $sAttCode => $void) {
|
||||
$aOrder[$sAttCode] = 999; // At the end of the list...
|
||||
}
|
||||
foreach($aList as $sAttCode)
|
||||
{
|
||||
if (array_key_exists($sAttCode, $aFields))
|
||||
{
|
||||
foreach ($aList as $sAttCode) {
|
||||
if (array_key_exists($sAttCode, $aFields)) {
|
||||
$aOrder[$sAttCode] = $index;
|
||||
}
|
||||
$index++;
|
||||
}
|
||||
foreach($aFields as $sAttCode => $aDependencies)
|
||||
{
|
||||
foreach ($aFields as $sAttCode => $aDependencies) {
|
||||
// All fields with no remaining dependencies can be entered at this
|
||||
// step of the wizard
|
||||
if (count($aDependencies) > 0)
|
||||
{
|
||||
if (count($aDependencies) > 0) {
|
||||
$iMaxPos = 0;
|
||||
// Remove this field from the dependencies of the other fields
|
||||
foreach($aDependencies as $sDependentAttCode => $void)
|
||||
{
|
||||
foreach ($aDependencies as $sDependentAttCode => $void) {
|
||||
// position the current field after the ones it depends on
|
||||
$iMaxPos = max($iMaxPos, 1+$aOrder[$sDependentAttCode]);
|
||||
$iMaxPos = max($iMaxPos, 1 + $aOrder[$sDependentAttCode]);
|
||||
}
|
||||
}
|
||||
}
|
||||
asort($aOrder);
|
||||
$aCurrentStep = array();
|
||||
foreach($aOrder as $sAttCode => $rank)
|
||||
{
|
||||
$aCurrentStep = [];
|
||||
foreach ($aOrder as $sAttCode => $rank) {
|
||||
$aCurrentStep[] = $sAttCode;
|
||||
$aFieldsDone[$sAttCode] = '';
|
||||
}
|
||||
$aWizardSteps['mandatory'][] = $aCurrentStep;
|
||||
|
||||
|
||||
// Now computes the steps to fill the optional fields
|
||||
$aFields = array(); // reset
|
||||
foreach(MetaModel::ListAttributeDefs($this->m_sClass) as $sAttCode=>$oAttDef)
|
||||
{
|
||||
$aFields = []; // reset
|
||||
foreach (MetaModel::ListAttributeDefs($this->m_sClass) as $sAttCode => $oAttDef) {
|
||||
$iOptions = (isset($aStates[$this->m_sTargetState]['attribute_list'][$sAttCode])) ? $aStates[$this->m_sTargetState]['attribute_list'][$sAttCode] : 0;
|
||||
if (($sStateAttCode != $sAttCode) &&
|
||||
(!$oAttDef->IsExternalField()) &&
|
||||
@@ -282,7 +261,7 @@ $sJSHandlerCode
|
||||
// are removed from the 'optional' part of the wizard
|
||||
$oAttDef = MetaModel::GetAttributeDef($this->m_sClass, $sAttCode);
|
||||
$aPrerequisites = $oAttDef->GetPrerequisiteAttributes();
|
||||
$aFields[$sAttCode] = array();
|
||||
$aFields[$sAttCode] = [];
|
||||
foreach ($aPrerequisites as $sCode) {
|
||||
if (!isset($aFieldsDone[$sCode])) {
|
||||
// retain only the dependencies that were not covered
|
||||
@@ -293,28 +272,23 @@ $sJSHandlerCode
|
||||
}
|
||||
}
|
||||
// Now use the dependencies between the fields to order them
|
||||
while(count($aFields) > 0)
|
||||
{
|
||||
$aCurrentStep = array();
|
||||
foreach($aFields as $sAttCode => $aDependencies)
|
||||
{
|
||||
while (count($aFields) > 0) {
|
||||
$aCurrentStep = [];
|
||||
foreach ($aFields as $sAttCode => $aDependencies) {
|
||||
// All fields with no remaining dependencies can be entered at this
|
||||
// step of the wizard
|
||||
if (count($aDependencies) == 0)
|
||||
{
|
||||
if (count($aDependencies) == 0) {
|
||||
$aCurrentStep[] = $sAttCode;
|
||||
$aFieldsDone[$sAttCode] = '';
|
||||
unset($aFields[$sAttCode]);
|
||||
// Remove this field from the dependencies of the other fields
|
||||
foreach($aFields as $sUpdatedCode => $aDummy)
|
||||
{
|
||||
foreach ($aFields as $sUpdatedCode => $aDummy) {
|
||||
// remove the dependency
|
||||
unset($aFields[$sUpdatedCode][$sAttCode]);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (count($aCurrentStep) == 0)
|
||||
{
|
||||
if (count($aCurrentStep) == 0) {
|
||||
// This step of the wizard would contain NO field !
|
||||
$this->m_oPage->add(Dict::S('UI:Error:WizardCircularReferenceInDependencies'));
|
||||
print_r($aFields);
|
||||
@@ -323,7 +297,6 @@ $sJSHandlerCode
|
||||
$aWizardSteps['optional'][] = $aCurrentStep;
|
||||
}
|
||||
return $aWizardSteps;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
?>
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user