Compare commits

..

1 Commits

Author SHA1 Message Date
jf-cbd
2a44bc0227 N°8397 - remove export.php that has been re-added by mistake 2026-04-22 15:09:44 +02:00
12 changed files with 115 additions and 407 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 155 KiB

View File

@@ -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"

View File

@@ -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"

View File

@@ -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
- ...
-->
- [ ] ...
- [ ] ...
- [ ] ...

View File

@@ -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:
![iTop stickers](.doc/contributing-guide/contributing-stickers-side-by-side.png)
![iTop stickers 2025](.doc/contributing-guide/2025.contributing-stickers-side-by-side.png)

View File

@@ -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

View File

@@ -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:

View File

@@ -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;
}
}

View File

@@ -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);
}

View File

@@ -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>

View File

@@ -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',