mirror of
https://github.com/Combodo/iTop.git
synced 2026-06-01 21:52:17 +02:00
Compare commits
1 Commits
feature/95
...
fix/9342
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2a44bc0227 |
Binary file not shown.
|
After Width: | Height: | Size: 1.5 MiB |
Binary file not shown.
|
Before Width: | Height: | Size: 155 KiB |
60
.github/ISSUE_TEMPLATE/bug.yml
vendored
60
.github/ISSUE_TEMPLATE/bug.yml
vendored
@@ -1,60 +0,0 @@
|
||||
name: "Bug report"
|
||||
description: "Report a bug that you identified in iTop"
|
||||
type: bug
|
||||
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"
|
||||
55
.github/ISSUE_TEMPLATE/enhancement.yml
vendored
55
.github/ISSUE_TEMPLATE/enhancement.yml
vendored
@@ -1,55 +0,0 @@
|
||||
name: "Enhancement suggestion"
|
||||
description: "Suggest an improvement to iTop"
|
||||
type: feature
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
Please explain why you're creating this issue :
|
||||
- Please describe what's your improvement proposition.
|
||||
- Then tell us if you're willing to create a PR for this enhancement ? If so, we'll indicate in the issue if we're interested in it.
|
||||
|
||||
- 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: input
|
||||
id: itop_version
|
||||
attributes:
|
||||
label: iTop version (if appropriate)
|
||||
description: "Complete iTop version (e.g., 3.2.3)"
|
||||
validations:
|
||||
required: false
|
||||
|
||||
- type: input
|
||||
id: php_version
|
||||
attributes:
|
||||
label: PHP version (if appropriate)
|
||||
description: "Complete PHP version (e.g., 8.4.20)"
|
||||
validations:
|
||||
required: false
|
||||
|
||||
- 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: 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"
|
||||
66
.github/pull_request_template.md
vendored
66
.github/pull_request_template.md
vendored
@@ -1,81 +1,83 @@
|
||||
<!--
|
||||
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.
|
||||
|
||||
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. 🙏
|
||||
IMPORTANT: Please follow the guidelines within this PR template before submitting it, it will greatly help us process your PR. 🙏
|
||||
|
||||
Any PRs not following the guidelines or with missing information will not be considered.
|
||||
|
||||
-->
|
||||
|
||||
## Base information
|
||||
| Question | Answer
|
||||
|---------------------------------------------------------------|--------
|
||||
| Related to a SourceForge thread / 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
|
||||
|
||||
| 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 many details as possible.
|
||||
- Describe what is blocking you, what is the objective with as much details as possible.
|
||||
- Add screenshots if it's related to UI.
|
||||
-->
|
||||
|
||||
## Reproduction procedure (bug)
|
||||
|
||||
## Reproduction procedure (bug)
|
||||
<!--
|
||||
Please explain step by step how to reproduce the issue on a standard iTop Community.
|
||||
Remove this section only if it's NOT a bug.
|
||||
|
||||
Otherwise, explain step by step how to reproduce the issue on a standard iTop Community.
|
||||
|
||||
If it requires a custom datamodel, provide the minimal XML delta to reproduce it on a standard iTop Community.
|
||||
-->
|
||||
|
||||
1. On iTop x.y.z <!-- Put complete iTop version (eg. 3.1.0-2) -->
|
||||
2. With PHP x.y.z <!-- Put complete PHP version (eg. 8.1.24) -->
|
||||
3. First go there
|
||||
4. Then do that
|
||||
5. ...
|
||||
6. Finally, see that... (what is expected and what is actually happening)
|
||||
2. First go there
|
||||
2. Then do that
|
||||
3. ...
|
||||
4. Finally, see that...
|
||||
|
||||
## 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)
|
||||
|
||||
## 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
|
||||
|
||||
## 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 without digging in the code?
|
||||
- [ ] 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
|
||||
- ...
|
||||
-->
|
||||
|
||||
- [ ] ...
|
||||
- [ ] ...
|
||||
- [ ] ...
|
||||
|
||||
@@ -4,33 +4,30 @@ 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
|
||||
|
||||
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.
|
||||
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.
|
||||
|
||||
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 issue][itop-issues] 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 ticket](https://sourceforge.net/p/itop/tickets/new/) to submit it, but be warned that there are lots of good
|
||||
reasons to refuse such changes.
|
||||
|
||||
### 📄 License 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.
|
||||
@@ -40,33 +37,48 @@ 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
|
||||
|
||||
[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.3.0 version
|
||||
- `support/3.2`: 3.2.x maintenance version
|
||||
- `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
|
||||
|
||||
And when 3.3.0 will be out:
|
||||
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.
|
||||
|
||||
- `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
|
||||
|
||||
@@ -80,11 +92,12 @@ 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 base your developments on the develop branch.
|
||||
Most of the time you should based your developments on the develop branch.
|
||||
That may be different if you want to fix a bug, please use develop anyway and ask in your PR if rebase is possible.
|
||||
|
||||
|
||||
### 🎨 PHP styleguide
|
||||
|
||||
Please follow [our guidelines](https://www.itophub.io/wiki/page?id=latest%3Acustomization%3Acoding_standards).
|
||||
@@ -93,7 +106,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 `tests/` directory, containing a PHPUnit config file : `phpunit.xml.dist`.
|
||||
Our tests are located in the `test/` directory, containing a PHPUnit config file : `phpunit.xml.dist`.
|
||||
|
||||
### Git Commit Messages
|
||||
|
||||
@@ -125,14 +138,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 :)
|
||||
|
||||
@@ -146,6 +159,6 @@ We have one sticker per contribution type. You might get multiple stickers with
|
||||
* Beta tester: Test and give feedback on beta releases
|
||||
* Extension developer: Develop and publish an extension
|
||||
|
||||
Here is the design of each sticker:
|
||||
Here is the design of each stickers for year 2024:
|
||||
|
||||

|
||||

|
||||
|
||||
@@ -178,7 +178,7 @@ class EventNotificationEmail extends EventNotification
|
||||
|
||||
// Display lists
|
||||
MetaModel::Init_SetZListItems('details', ['date', 'userinfo', 'message', 'trigger_id', 'action_id', 'object_class', 'object_id', 'to', 'cc', 'bcc', 'from', 'subject', 'body', 'attachments']); // Attributes to be displayed for the complete details
|
||||
MetaModel::Init_SetZListItems('list', ['date', 'message', 'to', 'cc', 'bcc', 'subject', 'attachments']); // Attributes to be displayed for a list
|
||||
MetaModel::Init_SetZListItems('list', ['date', 'message', 'to', 'subject', 'attachments']); // Attributes to be displayed for a list
|
||||
|
||||
// Search criteria
|
||||
// MetaModel::Init_SetZListItems('standard_search', array('name')); // Criteria of the std search form
|
||||
|
||||
@@ -52,13 +52,6 @@ p_object_search_from_attribute:
|
||||
sHostObjectClass: ~
|
||||
sHostObjectId: ~
|
||||
|
||||
p_columns_from_attribute_with_class:
|
||||
path: '/object/search/columns-from-attribute-with-class/{sTargetAttCode}/{sHostObjectClass}/{sHostObjectId}'
|
||||
defaults:
|
||||
_controller: 'Combodo\iTop\Portal\Controller\ObjectController::GetColumnsFromAttributeAction'
|
||||
sHostObjectClass: ~
|
||||
sHostObjectId: ~
|
||||
|
||||
p_object_search_autocomplete:
|
||||
path: '/object/search/autocomplete/{sTargetAttCode}/{sHostObjectClass}/{sHostObjectId}'
|
||||
defaults:
|
||||
|
||||
@@ -6,7 +6,6 @@
|
||||
/* SCSS variables (can be overloaded) */
|
||||
$ipb-object-brick--url-to-clipboard--opacity: 0.5 !default;
|
||||
$ipb-object-brick--url-to-clipboard-tooltip-copied--margin-right: $common-spacing-200!default;
|
||||
$ipb-object-brick--padding-small-horizontal: 10px!default;
|
||||
|
||||
|
||||
.url-to-clipboard{
|
||||
@@ -22,16 +21,4 @@ $ipb-object-brick--padding-small-horizontal: 10px!default;
|
||||
// Used for clipboard's tooltip, which is not part of .url-to-clipboard element
|
||||
.url-to-clipboard-tooltip-copied {
|
||||
margin-right: $ipb-object-brick--url-to-clipboard-tooltip-copied--margin-right;
|
||||
}
|
||||
|
||||
.form_filter_container{
|
||||
position: relative;
|
||||
height: 2.5em;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.form_filter_class{
|
||||
position: absolute;
|
||||
right: 0;
|
||||
padding-right: $ipb-object-brick--padding-small-horizontal;
|
||||
}
|
||||
}
|
||||
@@ -714,125 +714,6 @@ class ObjectController extends BrickController
|
||||
return $oResponse;
|
||||
}
|
||||
|
||||
public function GetColumnsFromAttributeAction(Request $oRequest, $sTargetAttCode, $sHostObjectClass, $sHostObjectId = null)
|
||||
{
|
||||
$sFinalClass = $this->oRequestManipulatorHelper->ReadParam('finalclass', null, FILTER_UNSAFE_RAW);
|
||||
/** @var array $aCombodoPortalInstanceConf */
|
||||
$aCombodoPortalInstanceConf = $this->getParameter('combodo.portal.instance.conf');
|
||||
|
||||
$aData = [
|
||||
'sMode' => 'search_regular',
|
||||
'sTargetAttCode' => $sTargetAttCode,
|
||||
'sHostObjectClass' => $sHostObjectClass,
|
||||
'sHostObjectId' => $sHostObjectId,
|
||||
'sActionRulesToken' => $this->oRequestManipulatorHelper->ReadParam('ar_token', ''),
|
||||
];
|
||||
|
||||
// Checking security layers
|
||||
if (!$this->oSecurityHelper->IsActionAllowed(UR_ACTION_READ, $sHostObjectClass, $sHostObjectId)) {
|
||||
IssueLog::Warning(__METHOD__.' at line '.__LINE__.' : User #'.UserRights::GetUserId().' not allowed to read '.$sHostObjectClass.'::'.$sHostObjectId.' object.');
|
||||
throw new HttpException(Response::HTTP_NOT_FOUND, Dict::S('UI:ObjectDoesNotExist'));
|
||||
}
|
||||
|
||||
// Retrieving host object for future DBSearch parameters
|
||||
if ($sHostObjectId !== null) {
|
||||
// Note : AllowAllData set to true here instead of checking scope's flag because we are displaying a value that has been set and validated
|
||||
$oHostObject = MetaModel::GetObject($sHostObjectClass, $sHostObjectId, true, true);
|
||||
} else {
|
||||
$oHostObject = MetaModel::NewObject($sHostObjectClass);
|
||||
// Retrieving action rules
|
||||
//
|
||||
// Note : The action rules must be a base64-encoded JSON object, this is just so users are tempted to changes values.
|
||||
// But it would not be a security issue as it only presets values in the form.
|
||||
$aActionRules = !empty($aData['sActionRulesToken']) ? ContextManipulatorHelper::DecodeRulesToken($aData['sActionRulesToken']) : [];
|
||||
// Preparing object
|
||||
$this->oContextManipulatorHelper->PrepareObject($aActionRules, $oHostObject);
|
||||
}
|
||||
|
||||
// Updating host object with form data / values
|
||||
$sFormManagerClass = $this->oRequestManipulatorHelper->ReadParam('formmanager_class', '', FILTER_UNSAFE_RAW);
|
||||
$sFormManagerData = $this->oRequestManipulatorHelper->ReadParam('formmanager_data', '', FILTER_UNSAFE_RAW);
|
||||
if (!empty($sFormManagerClass) && !empty($sFormManagerData)) {
|
||||
/** @var \Combodo\iTop\Portal\Form\ObjectFormManager $oFormManager */
|
||||
$oFormManager = $sFormManagerClass::FromJSON($sFormManagerData);
|
||||
$oFormManager->SetObjectFormHandlerHelper($this->oObjectFormHandlerHelper);
|
||||
$oFormManager->SetObject($oHostObject);
|
||||
|
||||
// Applying action rules if present
|
||||
if (($oFormManager->GetActionRulesToken() !== null) && ($oFormManager->GetActionRulesToken() !== '')) {
|
||||
$aActionRules = ContextManipulatorHelper::DecodeRulesToken($oFormManager->GetActionRulesToken());
|
||||
$oObj = $oFormManager->GetObject();
|
||||
$this->oContextManipulatorHelper->PrepareObject($aActionRules, $oObj);
|
||||
$oFormManager->SetObject($oObj);
|
||||
}
|
||||
|
||||
// Updating host object
|
||||
$oFormManager->OnUpdate([
|
||||
'currentValues' => $this->oRequestManipulatorHelper->ReadParam('current_values', [], FILTER_UNSAFE_RAW, FILTER_REQUIRE_ARRAY),
|
||||
]);
|
||||
$oHostObject = $oFormManager->GetObject();
|
||||
}
|
||||
|
||||
// Retrieving request parameters
|
||||
$sFieldId = $this->oRequestManipulatorHelper->ReadParam('sFieldId', '');
|
||||
|
||||
// Building search query
|
||||
// - Retrieving target object class from attcode
|
||||
$oTargetAttDef = MetaModel::GetAttributeDef($sHostObjectClass, $sTargetAttCode);
|
||||
if ($oTargetAttDef->IsExternalKey()) {
|
||||
/** @var \AttributeExternalKey $oTargetAttDef */
|
||||
$sTargetObjectClass = $oTargetAttDef->GetTargetClass();
|
||||
} elseif ($oTargetAttDef->IsLinkSet()) {
|
||||
/** @var \AttributeLinkedSet $oTargetAttDef */
|
||||
if (!$oTargetAttDef->IsIndirect()) {
|
||||
$sTargetObjectClass = $oTargetAttDef->GetLinkedClass();
|
||||
} else {
|
||||
/** @var \AttributeLinkedSetIndirect $oTargetAttDef */
|
||||
/** @var \AttributeExternalKey $oRemoteAttDef */
|
||||
$oRemoteAttDef = MetaModel::GetAttributeDef($oTargetAttDef->GetLinkedClass(), $oTargetAttDef->GetExtKeyToRemote());
|
||||
$sTargetObjectClass = $oRemoteAttDef->GetTargetClass();
|
||||
}
|
||||
} elseif ($oTargetAttDef->GetEditClass() === 'CustomFields') {
|
||||
$oRequestTemplate = $oHostObject->Get($sTargetAttCode);
|
||||
/** @var \DBSearch $oTemplateFieldSearch */
|
||||
$oTemplateFieldSearch = $oRequestTemplate->GetForm()->GetField('user_data')->GetForm()->GetField($sFieldId)->GetSearch();
|
||||
$sTargetObjectClass = $oTemplateFieldSearch->GetClass();
|
||||
} else {
|
||||
throw new Exception('Search from attribute can only apply on AttributeExternalKey or AttributeLinkedSet objects, '.get_class($oTargetAttDef).' given.');
|
||||
}
|
||||
if (!empty($sFinalClass)) {
|
||||
if (!MetaModel::IsParentClass($sTargetObjectClass, $sFinalClass)) {
|
||||
throw new Exception('The finalclass parameter should be a child class of the target object class');
|
||||
}
|
||||
} else {
|
||||
$sFinalClass = $sTargetObjectClass;
|
||||
}
|
||||
|
||||
// - Retrieving class attribute list
|
||||
$aAttCodes = ApplicationHelper::GetLoadedListFromClass($aCombodoPortalInstanceConf['lists'], $sFinalClass, 'list');
|
||||
// - Adding friendlyname attribute to the list is not already in it
|
||||
$sTitleAttCode = 'friendlyname';
|
||||
if (($sTitleAttCode !== null) && !in_array($sTitleAttCode, $aAttCodes)) {
|
||||
$aAttCodes = array_merge([$sTitleAttCode], $aAttCodes);
|
||||
}
|
||||
|
||||
// Retrieving results
|
||||
// - Retrieving columns properties
|
||||
$aColumnProperties = [];
|
||||
foreach ($aAttCodes as $sAttCode) {
|
||||
$oAttDef = MetaModel::GetAttributeDef($sFinalClass, $sAttCode);
|
||||
$aColumnProperties[$sAttCode] = [
|
||||
'title' => $oAttDef->GetLabel(),
|
||||
];
|
||||
}
|
||||
|
||||
// Preparing response
|
||||
$aData = $aData + [
|
||||
'levelsProperties' => $aColumnProperties,
|
||||
];
|
||||
|
||||
return new JsonResponse($aData);
|
||||
}
|
||||
/**
|
||||
* Handles the regular (table) search from an attribute
|
||||
*
|
||||
@@ -856,7 +737,6 @@ class ObjectController extends BrickController
|
||||
*/
|
||||
public function SearchFromAttributeAction(Request $oRequest, $sTargetAttCode, $sHostObjectClass, $sHostObjectId = null)
|
||||
{
|
||||
$sFinalClass = $this->oRequestManipulatorHelper->ReadParam('finalclass', null, FILTER_UNSAFE_RAW);
|
||||
/** @var array $aCombodoPortalInstanceConf */
|
||||
$aCombodoPortalInstanceConf = $this->getParameter('combodo.portal.instance.conf');
|
||||
|
||||
@@ -946,16 +826,9 @@ class ObjectController extends BrickController
|
||||
} else {
|
||||
throw new Exception('Search from attribute can only apply on AttributeExternalKey or AttributeLinkedSet objects, '.get_class($oTargetAttDef).' given.');
|
||||
}
|
||||
if (utils::IsNotNullOrEmptyString($sFinalClass)) {
|
||||
if (!MetaModel::IsParentClass($sTargetObjectClass, $sFinalClass)) {
|
||||
throw new Exception('The finalclass parameter should be a child class of the target object class');
|
||||
}
|
||||
} else {
|
||||
$sFinalClass = $sTargetObjectClass;
|
||||
}
|
||||
|
||||
// - Retrieving class attribute list
|
||||
$aAttCodes = ApplicationHelper::GetLoadedListFromClass($aCombodoPortalInstanceConf['lists'], $sFinalClass, 'list');
|
||||
$aAttCodes = ApplicationHelper::GetLoadedListFromClass($aCombodoPortalInstanceConf['lists'], $sTargetObjectClass, 'list');
|
||||
// - Adding friendlyname attribute to the list is not already in it
|
||||
$sTitleAttCode = 'friendlyname';
|
||||
if (($sTitleAttCode !== null) && !in_array($sTitleAttCode, $aAttCodes)) {
|
||||
@@ -965,10 +838,10 @@ class ObjectController extends BrickController
|
||||
// - Retrieving scope search
|
||||
// Note : This do NOT apply to custom fields as the portal administrator is not supposed to know which objects will be put in the templates.
|
||||
// It is the responsibility of the template designer to write the right query so the user see only what he should.
|
||||
$oScopeSearch = $this->oScopeValidatorHelper->GetScopeFilterForProfiles(UserRights::ListProfiles(), $sFinalClass, UR_ACTION_READ);
|
||||
$oScopeSearch = $this->oScopeValidatorHelper->GetScopeFilterForProfiles(UserRights::ListProfiles(), $sTargetObjectClass, UR_ACTION_READ);
|
||||
$aInternalParams = [];
|
||||
if (($oScopeSearch === null) && ($oTargetAttDef->GetEditClass() !== 'CustomFields')) {
|
||||
IssueLog::Info(__METHOD__.' at line '.__LINE__.' : User #'.UserRights::GetUserId().' has no scope query for '.$sFinalClass.' class.');
|
||||
IssueLog::Info(__METHOD__.' at line '.__LINE__.' : User #'.UserRights::GetUserId().' has no scope query for '.$sTargetObjectClass.' class.');
|
||||
throw new HttpException(Response::HTTP_NOT_FOUND, Dict::S('UI:ObjectDoesNotExist'));
|
||||
}
|
||||
|
||||
@@ -982,9 +855,7 @@ class ObjectController extends BrickController
|
||||
// Note : $oTemplateFieldSearch has been defined in the "Retrieving target object class from attcode" part, it is not available otherwise
|
||||
$oSearch = $oTemplateFieldSearch;
|
||||
}
|
||||
if ($sFinalClass != $sTargetObjectClass) {
|
||||
$oSearch->AddCondition('finalclass', $sFinalClass, '=');
|
||||
}
|
||||
|
||||
// - Filtering objects to ignore
|
||||
if (($aObjectIdsToIgnore !== null) && (is_array($aObjectIdsToIgnore))) {
|
||||
//$oSearch->AddConditionExpression('id', $aObjectIdsToIgnore, 'NOT IN');
|
||||
@@ -1006,7 +877,7 @@ class ObjectController extends BrickController
|
||||
/** @noinspection SlowArrayOperationsInLoopInspection */
|
||||
for ($i = 0; $i < count($aAttCodes); $i++) {
|
||||
// Checking if the current attcode is an external key in order to search on the friendlyname
|
||||
$oAttDef = MetaModel::GetAttributeDef($sFinalClass, $aAttCodes[$i]);
|
||||
$oAttDef = MetaModel::GetAttributeDef($sTargetObjectClass, $aAttCodes[$i]);
|
||||
$sAttCode = (!$oAttDef->IsExternalKey()) ? $aAttCodes[$i] : $aAttCodes[$i].'_friendlyname';
|
||||
// Building expression for the current attcode
|
||||
// - For attributes that need conversion from their display value to storage value
|
||||
@@ -1062,25 +933,38 @@ class ObjectController extends BrickController
|
||||
}
|
||||
}
|
||||
|
||||
// Retrieving results
|
||||
// - Preparing object set
|
||||
$oSet = new DBObjectSet($oSearch, [], $aInternalParams);
|
||||
$oSet->OptimizeColumnLoad([$oSearch->GetClassAlias() => $aAttCodes]);
|
||||
$oSet->SetLimit($iListLength, $iListLength * ($iPageNumber - 1));
|
||||
// - Retrieving columns properties
|
||||
$aColumnProperties = [];
|
||||
foreach ($aAttCodes as $sAttCode) {
|
||||
$oAttDef = MetaModel::GetAttributeDef($sFinalClass, $sAttCode);
|
||||
$oAttDef = MetaModel::GetAttributeDef($sTargetObjectClass, $sAttCode);
|
||||
$aColumnProperties[$sAttCode] = [
|
||||
'title' => $oAttDef->GetLabel(),
|
||||
];
|
||||
}
|
||||
// - Retrieving objects
|
||||
$aItems = [];
|
||||
while ($oItem = $oSet->Fetch()) {
|
||||
$aItems[] = $this->PrepareObjectInformation($oItem, $aAttCodes);
|
||||
}
|
||||
|
||||
// Preparing response
|
||||
if ($bInitialPass) {
|
||||
$aData = $aData + [
|
||||
'sParentClassName' => Dict::S('Class:'.$sTargetObjectClass),
|
||||
'form' => [
|
||||
'id' => 'object_search_form_'.time(),
|
||||
'title' => Dict::Format('Brick:Portal:Object:Search:Regular:Title', $oTargetAttDef->GetLabel()),
|
||||
'title_complement' => MetaModel::GetName($sTargetObjectClass),
|
||||
],
|
||||
'aColumnProperties' => json_encode($aColumnProperties),
|
||||
'aResults' => [
|
||||
'aItems' => json_encode($aItems),
|
||||
'iCount' => count($aItems),
|
||||
],
|
||||
'bMultipleSelect' => $oTargetAttDef->IsLinkSet(),
|
||||
'aSource' => [
|
||||
'sFormPath' => $sFormPath,
|
||||
@@ -1090,20 +974,7 @@ class ObjectController extends BrickController
|
||||
'sFormManagerData' => $sFormManagerData,
|
||||
],
|
||||
];
|
||||
if (MetaModel::HasChildrenClasses($sTargetObjectClass)) {
|
||||
$aEnumChildClasses = \MetaModel::EnumChildClasses($sTargetObjectClass);
|
||||
$aChildClasses = [];
|
||||
foreach ($aEnumChildClasses as $sClassName) {
|
||||
$aChildClasses[$sClassName] = MetaModel::GetName($sClassName);
|
||||
}
|
||||
asort($aChildClasses);
|
||||
$aData = $aData + [
|
||||
'bHasSubClasses' => true,
|
||||
'aSubClasses' => $aChildClasses,
|
||||
];
|
||||
} else {
|
||||
$aData = $aData + ['bHasSubClasses' => false];
|
||||
}
|
||||
|
||||
if ($oRequest->isXmlHttpRequest()) {
|
||||
$oResponse = $this->render($this->GetTemplatePath('modal'), $aData);
|
||||
} else {
|
||||
@@ -1111,22 +982,13 @@ class ObjectController extends BrickController
|
||||
$oResponse = $this->render($this->GetTemplatePath('page'), $aData);
|
||||
}
|
||||
} else {
|
||||
// Retrieving results
|
||||
// - Preparing object set
|
||||
$oSet = new DBObjectSet($oSearch, [], $aInternalParams);
|
||||
$oSet->OptimizeColumnLoad([$oSearch->GetClassAlias() => $aAttCodes]);
|
||||
$oSet->SetLimit($iListLength, $iListLength * ($iPageNumber - 1));
|
||||
// - Retrieving objects
|
||||
$aItems = [];
|
||||
while ($oItem = $oSet->Fetch()) {
|
||||
$aItems[] = $this->PrepareObjectInformation($oItem, $aAttCodes);
|
||||
}
|
||||
$aData = $aData + [
|
||||
'levelsProperties' => $aColumnProperties,
|
||||
'data' => $aItems,
|
||||
'recordsTotal' => $oSet->Count(),
|
||||
'recordsFiltered' => $oSet->Count(),
|
||||
];
|
||||
|
||||
$oResponse = new JsonResponse($aData);
|
||||
}
|
||||
|
||||
|
||||
@@ -8,21 +8,8 @@
|
||||
|
||||
<div id="{{ sFormId }}">
|
||||
{#<div class="form_alerts"></div>#}
|
||||
{% if bHasSubClasses %}
|
||||
<div class="form_filter_container">
|
||||
<div class="form_filter_class dataTables_filter">
|
||||
<label class="dataTables_filter">{{ 'UI:SearchFor_Class'|dict_format('') }}</label>
|
||||
<select id="finalclass{{ sFormId }}">
|
||||
<option value="">{{ sParentClassName }}</option>
|
||||
{% for key, sClassName in aSubClasses %}
|
||||
<option value="{{ key }}">{{ sClassName }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
<div class="form_fields">
|
||||
<table id="{{ sTableId }}" class="object-list table table-striped responsive">
|
||||
<table id="{{ sTableId }}" class="object-list table table-striped responsive" cellspacing="0" width="100%">
|
||||
<tbody>
|
||||
</tbody>
|
||||
</table>
|
||||
@@ -39,13 +26,13 @@
|
||||
|
||||
<script type="text/javascript">
|
||||
var oColumnProperties = {{ aColumnProperties|raw }};
|
||||
var oRawDatas = {{ aResults.aItems|raw }};
|
||||
var oTable;
|
||||
// Used for ajax throttling
|
||||
var iSearchThrottle = 600;
|
||||
var oKeyTimeout;
|
||||
var aKeyTimeoutFilteredKeys = [9, 16, 17, 18, 19, 27, 33, 34, 35, 36, 37, 38, 39, 40]; // Tab, Shift, Ctrl, Alt, Pause, Esc, Page Up/Down, Home, End, Left/Up/Right/Down arrows
|
||||
// Used for form
|
||||
|
||||
var oSelectedItems = {};
|
||||
|
||||
// Show a loader inside the table
|
||||
@@ -115,8 +102,8 @@
|
||||
|
||||
return aColumnsDefinition;
|
||||
};
|
||||
|
||||
var createDatatable = function (sUrl) {
|
||||
|
||||
$(document).ready(function(){
|
||||
showTableLoader();
|
||||
// Note : Those options should be externalized in an library so we can use them on any DataTables for the portal.
|
||||
// We would just have to override / complete the necessary elements
|
||||
@@ -189,7 +176,7 @@
|
||||
"processing": true,
|
||||
"serverSide": true,
|
||||
"ajax": {
|
||||
"url": sUrl,
|
||||
"url": "{{ app.url_generator.generate('p_object_search_from_attribute', {'sTargetAttCode': sTargetAttCode, 'sHostObjectClass': sHostObjectClass, 'sHostObjectId': sHostObjectId, 'ar_token': sActionRulesToken})|raw }}",
|
||||
"type": "POST",
|
||||
"data": function(d){
|
||||
d.sFormPath = '{{ aSource.sFormPath }}';
|
||||
@@ -284,15 +271,8 @@
|
||||
}, iSearchThrottle);
|
||||
}
|
||||
});
|
||||
return oTable;
|
||||
}
|
||||
|
||||
$(document).ready(function () {
|
||||
sUrl = "{{ app.url_generator.generate('p_object_search_from_attribute', {'sTargetAttCode': sTargetAttCode, 'sHostObjectClass': sHostObjectClass, 'sHostObjectId': sHostObjectId, 'ar_token': sActionRulesToken})|raw }}";
|
||||
aColumnsDefinition = getColumnsDefinition();
|
||||
oTable = createDatatable(sUrl);
|
||||
showTableLoader();
|
||||
// Shows a loader in the table when processing
|
||||
|
||||
// Shows a loader in the table when processing
|
||||
$('#{{ sTableId }}').on('processing.dt', function(event, settings, processing){
|
||||
if(processing === true)
|
||||
{
|
||||
@@ -326,18 +306,4 @@
|
||||
$('#{{ sFormId }}').closest('.modal').find('.modal-footer').hide();
|
||||
{% endif %}
|
||||
});
|
||||
|
||||
///start of personalisation
|
||||
{% if bHasSubClasses %}
|
||||
$('#finalclass{{ sFormId }}').on('change', function () {
|
||||
oTable.clear().destroy();
|
||||
$('#{{ sTableId }}').empty();
|
||||
sUrlAjax = "{{ app.url_generator.generate('p_object_search_from_attribute', {'sTargetAttCode': sTargetAttCode, 'sHostObjectClass': sHostObjectClass, 'sHostObjectId': sHostObjectId, 'ar_token': sActionRulesToken})|raw }}&finalclass=" + $('#finalclass{{ sFormId }}').val();
|
||||
sUrlColumns = "{{ app.url_generator.generate('p_columns_from_attribute_with_class', {'sTargetAttCode': sTargetAttCode, 'sHostObjectClass': sHostObjectClass, 'sHostObjectId': sHostObjectId, 'ar_token': sActionRulesToken})|raw }}&finalclass=" + $('#finalclass{{ sFormId }}').val();
|
||||
$.post(sUrlColumns, function (aResult) {
|
||||
oColumnProperties = aResult.levelsProperties;
|
||||
oTable = createDatatable(sUrlAjax);
|
||||
});
|
||||
});
|
||||
{% endif %}
|
||||
</script>
|
||||
@@ -36,7 +36,7 @@ Dict::Add('FR FR', 'French', 'Français', [
|
||||
'UI:ResetPwd-Ready' => 'Le mot de passe a bien été changé.',
|
||||
'UI:ResetPwd-Login' => 'Cliquez ici pour vous connecter...',
|
||||
|
||||
'UI:Login:About' => ITOP_APPLICATION.' Powered by Combodo',
|
||||
'UI:Login:About' => ITOP_APPLICATION.' Powered by Combodo~~',
|
||||
'UI:Login:ChangeYourPassword' => 'Changer de mot de passe',
|
||||
'UI:Login:OldPasswordPrompt' => 'Ancien mot de passe',
|
||||
'UI:Login:NewPasswordPrompt' => 'Nouveau mot de passe',
|
||||
|
||||
Reference in New Issue
Block a user