From bc6f73b9ec745ad7bc68b982615654b9d5fd35c2 Mon Sep 17 00:00:00 2001 From: Guillaume Lajarige Date: Mon, 23 May 2016 15:31:02 +0000 Subject: [PATCH] Customer portal : Fixed some bugs and rectified some default configuration parameters - Form, ExternalKey autocomplete & regular search - Portal power user being able to see all its silo tickets - Worked on the UI SVN:trunk[4118] --- .../objectcontroller.class.inc.php | 28 +++- .../src/entities/portalbrick.class.inc.php | 4 +- .../src/forms/objectformmanager.class.inc.php | 3 +- .../helpers/applicationhelper.class.inc.php | 15 +- .../src/views/bricks/browse/layout.html.twig | 12 +- .../views/bricks/browse/mode_list.html.twig | 9 ++ .../portal/src/views/bricks/layout.html.twig | 16 +- .../src/views/bricks/manage/layout.html.twig | 27 ++-- .../object/mode_search_regular.html.twig | 15 +- .../views/bricks/object/mode_view.html.twig | 2 +- .../portal/src/views/bricks/tile.html.twig | 6 +- .../bricks/user-profile/layout.html.twig | 2 +- .../portal/src/views/home/layout.html.twig | 2 +- .../portal/src/views/layout.html.twig | 4 +- .../portal/web/css/portal.css | 148 ++++++++++-------- .../portal/web/fonts/Combodo.otf | Bin 0 -> 2468 bytes .../portal/web/fonts/Combodo.ttf | Bin 0 -> 2292 bytes .../portal/web/fonts/Combodo.woff | Bin 0 -> 1904 bytes .../itop-tickets/datamodel.itop-tickets.xml | 33 +++- .../bsselectobjectfieldrenderer.class.inc.php | 7 + 20 files changed, 216 insertions(+), 117 deletions(-) create mode 100644 datamodels/2.x/itop-portal-base/portal/web/fonts/Combodo.otf create mode 100644 datamodels/2.x/itop-portal-base/portal/web/fonts/Combodo.ttf create mode 100644 datamodels/2.x/itop-portal-base/portal/web/fonts/Combodo.woff diff --git a/datamodels/2.x/itop-portal-base/portal/src/controllers/objectcontroller.class.inc.php b/datamodels/2.x/itop-portal-base/portal/src/controllers/objectcontroller.class.inc.php index 8ec2376d2..595a40f13 100644 --- a/datamodels/2.x/itop-portal-base/portal/src/controllers/objectcontroller.class.inc.php +++ b/datamodels/2.x/itop-portal-base/portal/src/controllers/objectcontroller.class.inc.php @@ -395,7 +395,7 @@ class ObjectController extends AbstractController // But it would not be a security issue as it only presets values in the form. $sActionRulesToken = $oRequest->get('ar_token'); $aActionRules = ($sActionRulesToken !== null) ? ContextManipulatorHelper::DecodeRulesToken($sActionRulesToken) : array(); - + // Preparing object if ($sObjectId === null) { @@ -606,6 +606,14 @@ class ObjectController extends AbstractController 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. + $sActionRulesToken = $oRequest->get('ar_token'); + $aActionRules = ($sActionRulesToken !== null) ? ContextManipulatorHelper::DecodeRulesToken($sActionRulesToken) : array(); + // Preparing object + $oApp['context_manipulator']->PrepareObject($aActionRules, $oHostObject); } // Building search query @@ -617,7 +625,7 @@ class ObjectController extends AbstractController // - Adding query condition $oSearch->AddConditionExpression(new BinaryExpression(new FieldExpression('friendlyname', $oSearch->GetClassAlias()), 'LIKE', new VariableExpression('ac_query'))); // - Intersecting with scope constraints - $oSearch->Intersect($oApp['scope_validator']->GetScopeFilterForProfiles(UserRights::ListProfiles(), $sTargetObjectClass, UR_ACTION_READ)); + $oSearch = $oSearch->Intersect($oApp['scope_validator']->GetScopeFilterForProfiles(UserRights::ListProfiles(), $sTargetObjectClass, UR_ACTION_READ)); // Retrieving results // - Preparing object set @@ -628,7 +636,7 @@ class ObjectController extends AbstractController // - Retrieving objects while ($oItem = $oSet->Fetch()) { - $aData['results']['items'][] = array('id' => $oItem->GetKey(), 'name' => $oItem->GetName()); + $aData['results']['items'][] = array('id' => $oItem->GetKey(), 'name' => html_entity_decode($oItem->GetName(), ENT_QUOTES, 'UTF-8')); $aData['results']['count'] ++; } @@ -661,7 +669,8 @@ class ObjectController extends AbstractController 'sMode' => 'search_regular', 'sTargetAttCode' => $sTargetAttCode, 'sHostObjectClass' => $sHostObjectClass, - 'sHostObjectId' => $sHostObjectId + 'sHostObjectId' => $sHostObjectId, + 'sActionRulesToken' => $oRequest->get('ar_token') ); // Checking security layers @@ -678,6 +687,13 @@ class ObjectController extends AbstractController 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 = ($aData['sActionRulesToken'] !== null) ? ContextManipulatorHelper::DecodeRulesToken($aData['sActionRulesToken']) : array(); + // Preparing object + $oApp['context_manipulator']->PrepareObject($aActionRules, $oHostObject); } // Retrieving request parameters @@ -780,7 +796,7 @@ class ObjectController extends AbstractController } // - Intersecting with scope constraints - $oSearch->Intersect($oScopeSearch); + $oSearch = $oSearch->Intersect($oScopeSearch); // Retrieving results // - Preparing object set @@ -999,7 +1015,7 @@ class ObjectController extends AbstractController // $aInternalParams['re_query'] = '%' . $sQuery . '%'; // } // - Intersecting with scope constraints - $oSearch->Intersect($oScopeSearch); + $oSearch = $oSearch->Intersect($oScopeSearch); // Retrieving results // - Preparing object set diff --git a/datamodels/2.x/itop-portal-base/portal/src/entities/portalbrick.class.inc.php b/datamodels/2.x/itop-portal-base/portal/src/entities/portalbrick.class.inc.php index 722e95e26..c5ba6cdf9 100644 --- a/datamodels/2.x/itop-portal-base/portal/src/entities/portalbrick.class.inc.php +++ b/datamodels/2.x/itop-portal-base/portal/src/entities/portalbrick.class.inc.php @@ -135,7 +135,7 @@ abstract class PortalBrick extends AbstractBrick */ public function GetRankHome() { - return $this->bRankHome; + return $this->fRankHome; } /** @@ -145,7 +145,7 @@ abstract class PortalBrick extends AbstractBrick */ public function GetRankNavigationMenu() { - return $this->bRankNavigationMenu; + return $this->fRankNavigationMenu; } /** diff --git a/datamodels/2.x/itop-portal-base/portal/src/forms/objectformmanager.class.inc.php b/datamodels/2.x/itop-portal-base/portal/src/forms/objectformmanager.class.inc.php index 078b94be9..f622d08f1 100644 --- a/datamodels/2.x/itop-portal-base/portal/src/forms/objectformmanager.class.inc.php +++ b/datamodels/2.x/itop-portal-base/portal/src/forms/objectformmanager.class.inc.php @@ -487,7 +487,8 @@ class ObjectFormManager extends FormManager $sSearchEndpoint = $this->oApp['url_generator']->generate('p_object_search_generic', array( 'sTargetAttCode' => $oAttDef->GetCode(), 'sHostObjectClass' => get_class($this->oObject), - 'sHostObjectId' => ($this->oObject->IsNew()) ? null : $this->oObject->GetKey() + 'sHostObjectId' => ($this->oObject->IsNew()) ? null : $this->oObject->GetKey(), + 'ar_token' => $this->GetActionRulesToken(), )); $oField->SetSearchEndpoint($sSearchEndpoint); } diff --git a/datamodels/2.x/itop-portal-base/portal/src/helpers/applicationhelper.class.inc.php b/datamodels/2.x/itop-portal-base/portal/src/helpers/applicationhelper.class.inc.php index 93d5f83da..cbdfef33d 100644 --- a/datamodels/2.x/itop-portal-base/portal/src/helpers/applicationhelper.class.inc.php +++ b/datamodels/2.x/itop-portal-base/portal/src/helpers/applicationhelper.class.inc.php @@ -619,11 +619,20 @@ class ApplicationHelper } } // - Sorting bricks by rank - usort($aPortalConf['bricks'], function($a, $b) + $aPortalConf['bricks_ordering'] = array(); + // - Home + $aPortalConf['bricks_ordering']['home'] = $aPortalConf['bricks']; + usort($aPortalConf['bricks_ordering']['home'], function($a, $b) { - return $a->GetRank() > $b->GetRank(); + return $a->GetRankHome() > $b->GetRankHome(); }); - + // - Navigation menu + $aPortalConf['bricks_ordering']['navigation_menu'] = $aPortalConf['bricks']; + usort($aPortalConf['bricks_ordering']['navigation_menu'], function($a, $b) + { + return $a->GetRankNavigationMenu() > $b->GetRankNavigationMenu(); + }); + return $aPortalConf; } diff --git a/datamodels/2.x/itop-portal-base/portal/src/views/bricks/browse/layout.html.twig b/datamodels/2.x/itop-portal-base/portal/src/views/bricks/browse/layout.html.twig index 4962c7843..bb6c58380 100644 --- a/datamodels/2.x/itop-portal-base/portal/src/views/bricks/browse/layout.html.twig +++ b/datamodels/2.x/itop-portal-base/portal/src/views/bricks/browse/layout.html.twig @@ -8,14 +8,10 @@ {% block pMainHeaderActions %} {% if aBrowseButtons|length > 1 %} -
-
-
- {% for sBrowseButton in aBrowseButtons %} - {{ ('Brick:Portal:Browse:Mode:'~sBrowseButton|capitalize)|dict_s }} - {% endfor %} -
-
+
+ {% for sBrowseButton in aBrowseButtons %} + {{ ('Brick:Portal:Browse:Mode:'~sBrowseButton|capitalize)|dict_s }} + {% endfor %}
{% endif %} {% endblock %} diff --git a/datamodels/2.x/itop-portal-base/portal/src/views/bricks/browse/mode_list.html.twig b/datamodels/2.x/itop-portal-base/portal/src/views/bricks/browse/mode_list.html.twig index bb727b9a1..022fcd741 100644 --- a/datamodels/2.x/itop-portal-base/portal/src/views/bricks/browse/mode_list.html.twig +++ b/datamodels/2.x/itop-portal-base/portal/src/views/bricks/browse/mode_list.html.twig @@ -241,6 +241,15 @@ "drawCallback": function(settings){ // Tooltip has to been created here, as the render callback only returns a string, not an object. $(this).find('[data-toggle="tooltip"]').tooltip({container: 'body', html: true, trigger: 'hover', placement: 'right'}); // container option is necessary when in a table + // Hiding pagination if only one page + if($(this).closest('.dataTables_wrapper').find('.dataTables_paginate:last .paginate_button:not(.previous):not(.next)').length < 2) + { + $(this).closest('.dataTables_wrapper').find('.dataTables_paginate, .dataTables_info').hide(); + } + else + { + $(this).closest('.dataTables_wrapper').find('.dataTables_paginate, .dataTables_info').show(); + } }, {% if sDataLoading == constant('Combodo\\iTop\\Portal\\Brick\\AbstractBrick::ENUM_DATA_LOADING_FULL') %} "data": oRawDatas, diff --git a/datamodels/2.x/itop-portal-base/portal/src/views/bricks/layout.html.twig b/datamodels/2.x/itop-portal-base/portal/src/views/bricks/layout.html.twig index 52c8a4033..5a1e92722 100644 --- a/datamodels/2.x/itop-portal-base/portal/src/views/bricks/layout.html.twig +++ b/datamodels/2.x/itop-portal-base/portal/src/views/bricks/layout.html.twig @@ -12,13 +12,15 @@ {% endblock %} {% block pMainHeader %} -
-

{% block pMainHeaderTitle %}{% endblock %}

-
-
- {% block pMainHeaderActions %} - {% endblock %} -
+
+
+

{% block pMainHeaderTitle %}{% endblock %}

+
+
+ {% block pMainHeaderActions %} + {% endblock %} +
+
{% endblock %} {% block pMainContent %} diff --git a/datamodels/2.x/itop-portal-base/portal/src/views/bricks/manage/layout.html.twig b/datamodels/2.x/itop-portal-base/portal/src/views/bricks/manage/layout.html.twig index 01eb7dd4a..9b5874ea9 100644 --- a/datamodels/2.x/itop-portal-base/portal/src/views/bricks/manage/layout.html.twig +++ b/datamodels/2.x/itop-portal-base/portal/src/views/bricks/manage/layout.html.twig @@ -7,17 +7,13 @@ {% endblock %} {% block pMainHeaderActions %} -
-
- {% if aGroupingTabsValues|length > 1 %} -
- {% for aGroupingTab in aGroupingTabsValues %} - {{ aGroupingTab.label|raw }} - {% endfor %} -
- {% endif %} -
+ {% if aGroupingTabsValues|length > 1 %} +
+ {% for aGroupingTab in aGroupingTabsValues %} + {{ aGroupingTab.label|raw }} + {% endfor %}
+ {% endif %} {% endblock %} {% block pMainContentHolder%} @@ -169,6 +165,17 @@ "dom": '<"row"<"col-sm-6"l><"col-sm-6"<"visible-xs"p>>>t<"row"<"col-sm-6"ri><"col-sm-6"p>>', "columns": getColumnsDefinition('{{ sAreaId }}'), "order": [[0, "desc"]], + "drawCallback": function(settings){ + // Hiding pagination if only one page + if($(this).closest('.dataTables_wrapper').find('.dataTables_paginate:last .paginate_button:not(.previous):not(.next)').length < 2) + { + $(this).closest('.dataTables_wrapper').find('.dataTables_paginate, .dataTables_info').hide(); + } + else + { + $(this).closest('.dataTables_wrapper').find('.dataTables_paginate, .dataTables_info').show(); + } + }, {% if sDataLoading == constant('Combodo\\iTop\\Portal\\Brick\\AbstractBrick::ENUM_DATA_LOADING_FULL') %} "data": rawData['{{ sAreaId }}'], {% else %} diff --git a/datamodels/2.x/itop-portal-base/portal/src/views/bricks/object/mode_search_regular.html.twig b/datamodels/2.x/itop-portal-base/portal/src/views/bricks/object/mode_search_regular.html.twig index 5dac6bf48..399f1e5eb 100644 --- a/datamodels/2.x/itop-portal-base/portal/src/views/bricks/object/mode_search_regular.html.twig +++ b/datamodels/2.x/itop-portal-base/portal/src/views/bricks/object/mode_search_regular.html.twig @@ -135,10 +135,21 @@ $(oRow).find('td:first-child input').prop('checked', true); } }, + "drawCallback": function(settings){ + // Hiding pagination if only one page + if($(this).closest('.dataTables_wrapper').find('.dataTables_paginate:last .paginate_button:not(.previous):not(.next)').length < 2) + { + $(this).closest('.dataTables_wrapper').find('.dataTables_paginate, .dataTables_info').hide(); + } + else + { + $(this).closest('.dataTables_wrapper').find('.dataTables_paginate, .dataTables_info').show(); + } + }, "processing": true, "serverSide": true, "ajax": { - "url": "{{ app.url_generator.generate('p_object_search_from_attribute', {'sTargetAttCode': sTargetAttCode, 'sHostObjectClass': sHostObjectClass, 'sHostObjectId': sHostObjectId})|raw }}", + "url": "{{ app.url_generator.generate('p_object_search_from_attribute', {'sTargetAttCode': sTargetAttCode, 'sHostObjectClass': sHostObjectClass, 'sHostObjectId': sHostObjectId, 'ar_token': sActionRulesToken})|raw }}", "data": function(d){ d.aObjectIdsToIgnore = {{ aSource.aObjectIdsToIgnore|json_encode()|raw }}; d.iPageNumber = Math.floor(d.start/d.length) + 1; @@ -165,7 +176,7 @@ var iItemId = aData[i].id; if(!(iItemId in oSelectedItems)) { - oSelectedItems[iItemId] = aData[i].name; + oSelectedItems[iItemId] = $('