From 262a8efae5e1c23de012bf468133ce83860968dc Mon Sep 17 00:00:00 2001 From: Curtis Conard Date: Fri, 26 Apr 2024 15:45:32 -0400 Subject: [PATCH 1/5] Entity assistance UI + some AJAX --- CHANGELOG.md | 1 + ajax/cable.php | 10 +- ajax/changesatisfaction.php | 52 - ajax/commonitilsatisfaction.php | 191 +--- ajax/dropdownAllItems.php | 5 +- ajax/dropdownItilActors.php | 6 +- ajax/dropdownMassiveAction.php | 19 +- ajax/dropdownMassiveActionAddValidator.php | 4 +- ajax/dropdownTrackingDeviceType.php | 9 +- ajax/inputtext.php | 6 +- ajax/kblink.php | 9 +- ajax/resaperiod.php | 11 +- ajax/selectUnaffectedOrNewItem_Device.php | 19 +- ajax/subvisibility.php | 9 +- ajax/ticketsatisfaction.php | 52 - ajax/uemailUpdate.php | 7 +- ajax/viewsubitem.php | 5 +- ajax/visibility.php | 2 +- src/Entity.php | 961 +++++------------- src/Glpi/DBAL/QueryFunction.php | 11 + .../pages/admin/entity/assistance.html.twig | 175 ++++ .../admin/entity/survey_config.html.twig | 146 +++ tests/functional/Glpi/DBAL/QueryFunction.php | 46 + 23 files changed, 727 insertions(+), 1029 deletions(-) delete mode 100644 ajax/changesatisfaction.php delete mode 100644 ajax/ticketsatisfaction.php create mode 100644 templates/pages/admin/entity/assistance.html.twig create mode 100644 templates/pages/admin/entity/survey_config.html.twig diff --git a/CHANGELOG.md b/CHANGELOG.md index cc0716b3819..175378b8571 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -402,6 +402,7 @@ The present file will list all changes made to the project; according to the - `ajax/ticketassigninformation.php` script. Use `ajax/actorinformation.php` instead. - `ajax/planningcheck.php` script. Use `Planning::showPlanningCheck()` instead. - `test_ldap` and `test_ldap_replicate` actions in `front/authldap.form.php`. Use `ajax/ldap.php` instead. +- `ajax/ticketsatisfaction.php` and `ajax/changesatisfaction.php` scripts. Access `ajax/commonitilsatisfaction.php` directly instead. ## [10.0.16] unreleased diff --git a/ajax/cable.php b/ajax/cable.php index 364242f54a0..1b0ebb8d6b1 100644 --- a/ajax/cable.php +++ b/ajax/cable.php @@ -60,10 +60,7 @@ break; case 'get_socket_dropdown': - if ( - (isset($_GET['itemtype']) && class_exists($_GET['itemtype'])) - && isset($_GET['items_id']) - ) { + if (isset($_GET['itemtype'], $_GET['items_id']) && class_exists($_GET['itemtype'])) { Socket::dropdown(['name' => $_GET['dom_name'], 'condition' => ['socketmodels_id' => $_GET['socketmodels_id'] ?? 0, 'itemtype' => $_GET['itemtype'], @@ -87,10 +84,7 @@ case 'get_item_breadcrum': - if ( - (isset($_GET['itemtype']) && class_exists($_GET['itemtype'])) - && isset($_GET['items_id']) && $_GET['items_id'] > 0 - ) { + if (isset($_GET['itemtype'], $_GET['items_id']) && class_exists($_GET['itemtype']) && $_GET['items_id'] > 0) { if (method_exists($_GET['itemtype'], 'renderDcBreadcrumb')) { echo $_GET['itemtype']::renderDcBreadcrumb($_GET['items_id']); } diff --git a/ajax/changesatisfaction.php b/ajax/changesatisfaction.php deleted file mode 100644 index a796941d783..00000000000 --- a/ajax/changesatisfaction.php +++ /dev/null @@ -1,52 +0,0 @@ -. - * - * --------------------------------------------------------------------- - */ - -/** - * @var bool|null $AJAX_INCLUDE - */ -global $AJAX_INCLUDE; - -// Direct access to file -if (strpos($_SERVER['PHP_SELF'], "changesatisfaction.php")) { - $AJAX_INCLUDE = 1; - include('../inc/includes.php'); - header("Content-Type: text/html; charset=UTF-8"); - Html::header_nocache(); -} - -$itemtype = Change::class; -$inquest_itemtype = ChangeSatisfaction::class; - -include(GLPI_ROOT . "/ajax/commonitilsatisfaction.php"); diff --git a/ajax/commonitilsatisfaction.php b/ajax/commonitilsatisfaction.php index 0de7ec6a18b..22c365ea74e 100644 --- a/ajax/commonitilsatisfaction.php +++ b/ajax/commonitilsatisfaction.php @@ -34,17 +34,28 @@ */ /** - * Following variables have to be defined before inclusion of this file: - * @var string|CommonITILObject $itemtype - * @var string|CommonITILSatisfaction $inquest_itemtype + * @var bool|null $AJAX_INCLUDE */ +global $AJAX_INCLUDE; +$AJAX_INCLUDE = 1; +include('../inc/includes.php'); +header("Content-Type: text/html; charset=UTF-8"); +Html::header_nocache(); + +use Glpi\Application\View\TemplateRenderer; + +$itemtype = $_POST['itemtype']; $ent = new Entity(); // Get suffix for entity config fields. For backwards compatibility, ticket values have no suffix. $config_suffix = $itemtype::getType() === 'Ticket' ? '' : ('_' . strtolower($itemtype::getType())); -if (isset($_POST['inquest_config' . $config_suffix]) && isset($_POST['entities_id'])) { +if (isset($_POST['inquest_config' . $config_suffix], $_POST['entities_id'])) { if ($ent->getFromDB($_POST['entities_id'])) { + if (!$ent->canViewItem()) { + http_response_code(403); + die(); + } $inquest_delay = $ent->getfield('inquest_delay' . $config_suffix); $inquest_rate = $ent->getfield('inquest_rate' . $config_suffix); $inquest_duration = $ent->getfield('inquest_duration' . $config_suffix); @@ -62,163 +73,19 @@ $max_closedate = ''; } - if ($_POST['inquest_config' . $config_suffix] > 0) { - echo ""; - echo ""; - echo ""; - - echo "" . - ""; - echo ""; - - echo ""; - echo ""; - echo ""; - echo ""; - - echo ""; - echo ""; - - echo ""; - echo ""; - - echo ""; - - $tag_prefix = strtoupper($itemtype::getType()); - $ticket_only_tags = "[REQUESTTYPE_ID] [REQUESTTYPE_NAME] [TICKETTYPE_NAME] [TICKETTYPE_ID] "; - $ticket_only_tags .= "[SLA_TTO_ID] [SLA_TTO_NAME] [SLA_TTR_ID] [SLA_TTR_NAME] [SLALEVEL_ID] [SLALEVEL_NAME]"; - - if ($_POST['inquest_config' . $config_suffix] == 2) { - echo ""; - echo ""; - - echo ""; - echo ""; - } - - echo "
" . __('Create survey after') . ""; - Dropdown::showNumber( - 'inquest_delay' . $config_suffix, - ['value' => $inquest_delay, - 'min' => 1, - 'max' => 90, - 'step' => 1, - 'toadd' => ['0' => __('As soon as possible')], - 'unit' => 'day' - ] - ); - echo "
" . __('Rate to trigger survey') . ""; - Dropdown::showNumber( - 'inquest_rate' . $config_suffix, - [ - 'value' => $inquest_rate, - 'min' => 10, - 'max' => 100, - 'step' => 10, - 'toadd' => [0 => __('Disabled')], - 'unit' => '%' - ] - ); - echo "
" . __('Duration of survey') . ""; - Dropdown::showNumber( - 'inquest_duration' . $config_suffix, - [ - 'value' => $inquest_duration, - 'min' => 1, - 'max' => 180, - 'step' => 1, - 'toadd' => ['0' => __('Unspecified')], - 'unit' => 'day' - ] - ); - echo "
" . __('Max rate') . ""; - Dropdown::showNumber( - 'inquest_max_rate' . $config_suffix, - [ - 'value' => $inquest_max_rate, - 'min' => 1, - 'max' => 10, - 'step' => 1, - 'unit' => '' - ] - ); - echo "
" . __('Default rate') . ""; - Dropdown::showNumber( - 'inquest_default_rate' . $config_suffix, - [ - 'value' => $inquest_default_rate, - 'min' => 1, - 'max' => 10, - 'step' => 1, - 'unit' => '' - ] - ); - echo "
" . __('Comment required if score is <= to') . ""; - Dropdown::showNumber( - 'inquest_mandatory_comment' . $config_suffix, - [ - 'value' => $inquest_mandatory_comment, - 'min' => 1, - 'max' => 10, - 'step' => 1, - 'toadd' => ['0' => __('Disabled')], - 'unit' => '' - ] - ); - echo "
" . sprintf(__('For %s closed after'), $itemtype::getTypeName(Session::getPluralNumber())) . ""; - Html::showDateTimeField( - "max_closedate" . $config_suffix, - [ - 'value' => $max_closedate, - 'timestep' => 1, - 'maybeempty' => false, - ] - ); - echo "
" . __('Valid tags') . "" . - "[{$tag_prefix}_ID] [{$tag_prefix}_NAME] [{$tag_prefix}_CREATEDATE] [{$tag_prefix}_SOLVEDATE] " . - "[{$tag_prefix}_PRIORITY] [{$tag_prefix}_PRIORITYNAME] " . - "[ITILCATEGORY_ID] [ITILCATEGORY_NAME] " . - "[SOLUTIONTYPE_ID] [SOLUTIONTYPE_NAME] " . - ($itemtype === 'Ticket' ? (' ' . $ticket_only_tags) : '') . - "
" . __('URL') . ""; - echo Html::input('inquest_URL' . $config_suffix, ['value' => $ent->fields['inquest_URL' . $config_suffix]]); - echo "
"; - $js = << { - const rate_dropdown = $('select[name="inquest_rate{$config_suffix}"]'); - - const refresh_param_rows = () => { - const param_rows = [ - $('tr[data-field="duration{$config_suffix}"]'), - $('tr[data-field="max_rate{$config_suffix}"]'), - $('tr[data-field="default_rate{$config_suffix}"]'), - $('tr[data-field="mandatory_comment{$config_suffix}"]'), - $('tr[data-field="max_closedate{$config_suffix}"]'), - $('tr[data-field="url{$config_suffix}"]') - ]; - if (rate_dropdown.val() == 0) { - // Hide all param rows if they exist - param_rows.forEach(row => { - if (row.length > 0) { - row.hide(); - } - }); - } else { - // Show all param rows if they exist - param_rows.forEach(row => { - if (row.length > 0) { - row.show(); - } - }); - } - }; - - $(rate_dropdown).on('change', () => { - refresh_param_rows(); - }); - refresh_param_rows(); - }); -JS; - echo Html::scriptBlock($js); + if ((int) $_POST['inquest_config' . $config_suffix] > 0) { + TemplateRenderer::getInstance()->display('pages/admin/entity/survey_config.html.twig', [ + 'itemtype' => $itemtype, + 'inquest_config' => $_POST['inquest_config' . $config_suffix], + 'config_suffix' => $config_suffix, + 'inquest_delay' => $inquest_delay, + 'inquest_rate' => $inquest_rate, + 'inquest_duration' => $inquest_duration, + 'inquest_default_rate' => $inquest_default_rate, + 'inquest_max_rate' => $inquest_max_rate, + 'inquest_mandatory_comment' => $inquest_mandatory_comment, + 'max_closedate' => $max_closedate, + 'inquest_URL' => $ent->fields['inquest_URL' . $config_suffix] ?? '' + ]); } } diff --git a/ajax/dropdownAllItems.php b/ajax/dropdownAllItems.php index cffe9eccc29..9df34b4958d 100644 --- a/ajax/dropdownAllItems.php +++ b/ajax/dropdownAllItems.php @@ -111,13 +111,14 @@ $params['entity_restrict'] = $_POST['entity_restrict']; } + $name = htmlspecialchars($_POST["name"]); Ajax::updateItemOnSelectEvent( $field_id, - "showItemSpecificity_" . $_POST["name"] . "$rand", + "showItemSpecificity_" . $name . "$rand", $_POST['showItemSpecificity'], $params ); - echo "
 \n"; + echo "
 \n"; } } diff --git a/ajax/dropdownItilActors.php b/ajax/dropdownItilActors.php index 33b6a91def9..e80329026db 100644 --- a/ajax/dropdownItilActors.php +++ b/ajax/dropdownItilActors.php @@ -122,12 +122,12 @@ if ($CFG_GLPI["notifications_mailing"]) { echo "
"; if ($withemail) { - echo __('Email followup') . ' '; + echo __s('Email followup') . ' '; $rand = Dropdown::showYesNo('_itil_' . $_POST["actortype"] . '[use_notification]', $_POST["use_notif"]); echo '
'; printf( __('%1$s: %2$s'), - _n('Email', 'Emails', 1), + _sn('Email', 'Emails', 1), "" ); @@ -224,7 +224,7 @@ if ($CFG_GLPI["notifications_mailing"]) { echo "
"; if ($withemail) { - echo __('Email followup') . ' '; + echo __s('Email followup') . ' '; $rand = Dropdown::showYesNo('_itil_' . $_POST["actortype"] . '[use_notification]', $_POST['use_notif']); echo '
'; printf( diff --git a/ajax/dropdownMassiveAction.php b/ajax/dropdownMassiveAction.php index 1ae49d1168b..10272bf7660 100644 --- a/ajax/dropdownMassiveAction.php +++ b/ajax/dropdownMassiveAction.php @@ -33,8 +33,7 @@ * --------------------------------------------------------------------- */ -/** @var array $CFG_GLPI */ -global $CFG_GLPI; +use Glpi\Application\View\TemplateRenderer; include('../inc/includes.php'); @@ -44,10 +43,18 @@ try { $ma = new MassiveAction($_POST, $_GET, 'specialize'); } catch (\Throwable $e) { - echo "
" .
-      __s(

"; - echo "" . $e->getMessage() . "
"; - echo "
"; + $twig_params = [ + 'title' => __('Warning'), + 'text' => $e->getMessage(), + ]; + // language=Twig + echo TemplateRenderer::getInstance()->renderFromStringTemplate(<< + +
{{ title }}
+
{{ text }}
+ +TWIG, $twig_params); exit(); } diff --git a/ajax/dropdownMassiveActionAddValidator.php b/ajax/dropdownMassiveActionAddValidator.php index 04a8d6299a2..586f6a206d8 100644 --- a/ajax/dropdownMassiveActionAddValidator.php +++ b/ajax/dropdownMassiveActionAddValidator.php @@ -70,7 +70,7 @@ ]); echo Html::hidden($itemtype_name, ['value' => 'User']); - echo "

" . __('Comments') . " "; + echo "

" . __s('Comments') . " "; echo " "; echo ""; @@ -85,7 +85,7 @@ ]); echo Html::hidden($itemtype_name, ['value' => 'Group']); - echo "

" . __('Comments') . " "; + echo "

" . __s('Comments') . " "; echo " "; echo ""; diff --git a/ajax/dropdownTrackingDeviceType.php b/ajax/dropdownTrackingDeviceType.php index a37afb06f6f..e26a6596333 100644 --- a/ajax/dropdownTrackingDeviceType.php +++ b/ajax/dropdownTrackingDeviceType.php @@ -70,7 +70,7 @@ // Message for post-only if (!isset($_POST["admin"]) || ($_POST["admin"] == 0)) { echo "" . - __('Enter the first letters (user, item name, serial or asset number)') + __s('Enter the first letters (user, item name, serial or asset number)') . ""; } $field_id = Html::cleanId("dropdown_" . $_POST['myname'] . $rand); @@ -87,7 +87,7 @@ ]), ]; - if (isset($_POST["used"]) && !empty($_POST["used"])) { + if (!empty($_POST["used"])) { if (isset($_POST["used"][$itemtype])) { $p["used"] = $_POST["used"][$itemtype]; } @@ -107,10 +107,11 @@ // Auto update summary of active or just solved tickets if (($_POST['source_itemtype'] ?? null) === Ticket::class) { - echo ""; + $myname = htmlspecialchars($_POST["myname"]); + echo ""; Ajax::updateItemOnSelectEvent( $field_id, - "item_ticket_selection_information{$_POST["myname"]}_$rand", + "item_ticket_selection_information{$myname}_$rand", $CFG_GLPI["root_doc"] . "/ajax/ticketiteminformation.php", [ 'items_id' => '__VALUE__', diff --git a/ajax/inputtext.php b/ajax/inputtext.php index bb1498385da..435a169e41d 100644 --- a/ajax/inputtext.php +++ b/ajax/inputtext.php @@ -48,9 +48,9 @@ Session::checkLoginUser(); if (isset($_POST['name'])) { - echo ""; } diff --git a/ajax/kblink.php b/ajax/kblink.php index 91b2eb96889..449bae088fc 100644 --- a/ajax/kblink.php +++ b/ajax/kblink.php @@ -49,11 +49,8 @@ Session::checkLoginUser(); -if ( - isset($_POST["table"]) - && isset($_POST["value"]) -) { - // Security +if (isset($_POST["table"], $_POST["value"])) { + // Security if (!$DB->tableExists($_POST['table'])) { exit(); } @@ -69,7 +66,7 @@ exit(); } $item = new $itemtype(); - $item->getFromDB(intval($_POST["value"])); + $item->getFromDB((int)$_POST["value"]); echo ' ' . $item->getLinks(); } } diff --git a/ajax/resaperiod.php b/ajax/resaperiod.php index b85dbc8b6f8..194b17af396 100644 --- a/ajax/resaperiod.php +++ b/ajax/resaperiod.php @@ -51,7 +51,7 @@ Session::checkLoginUser(); -if (isset($_POST['type']) && isset($_POST['end'])) { +if (isset($_POST['type'], $_POST['end'])) { echo ""; switch ($_POST['type']) { case 'day': @@ -68,9 +68,9 @@ echo ""; $days = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday']; foreach ($days as $day) { - echo ""; + echo ""; } - echo "'; + echo "'; foreach ($days as $day) { echo ""; @@ -80,12 +80,13 @@ case 'month': echo ""; - echo ""; } diff --git a/ajax/selectUnaffectedOrNewItem_Device.php b/ajax/selectUnaffectedOrNewItem_Device.php index b33a1536f58..2f487df86c6 100644 --- a/ajax/selectUnaffectedOrNewItem_Device.php +++ b/ajax/selectUnaffectedOrNewItem_Device.php @@ -38,6 +38,7 @@ */ use Glpi\DBAL\QueryExpression; +use Glpi\DBAL\QueryFunction; /** @var \DBmysql $DB */ global $DB; @@ -59,12 +60,10 @@ if (count($linktype::getSpecificities())) { $keys = array_keys($linktype::getSpecificities()); - array_walk($keys, static function (&$val) use ($DB) { - return $DB->quoteName($val); - }); - $name_field = new QueryExpression( - "CONCAT_WS(' - ', " . implode(', ', $keys) . ")" - . "AS " . $DB->quoteName("name") + $name_field = QueryFunction::concat_ws( + separator: new QueryExpression($DB::quoteValue(' - ')), + params: $keys, + alias: 'name' ); } else { $name_field = 'id AS name'; @@ -79,11 +78,11 @@ ] ] ); - echo "
 " . __($day) . "" . __s($day) . "
" . __('By day') . '
" . __s('By day') . '
"; - $values = ['date' => __('Each month, same date'), + $values = [ + 'date' => __('Each month, same date'), 'day' => __('Each month, same day of week') ]; Dropdown::showFromArray('periodicity[subtype]', $values); echo "
" . __('End date') . ''; + echo "
" . __s('End date') . ''; Html::showDateField('periodicity[end]', ['value' => $_POST['end']]); echo "
'; + echo "
" . __('Choose an existing device') . "" . - __('and/or') . "" . __('Add new devices') . '
'; echo "
" . __s('Choose an existing device') . "" . + __('and/or') . "" . __s('Add new devices') . '
"; - if ($result->count() == 0) { - echo __('No unaffected device!'); + if (count($result) === 0) { + echo __s('No unaffected device!'); } else { $devices = []; foreach ($result as $row) { diff --git a/ajax/subvisibility.php b/ajax/subvisibility.php index 42c6bfda7e6..651909d3c6a 100644 --- a/ajax/subvisibility.php +++ b/ajax/subvisibility.php @@ -48,13 +48,10 @@ Session::checkLoginUser(); -if ( - isset($_POST['type']) && !empty($_POST['type']) - && isset($_POST['items_id']) && ($_POST['items_id'] > 0) -) { +if (!empty($_POST['type']) && isset($_POST['items_id']) && ($_POST['items_id'] > 0)) { $prefix = ''; $suffix = ''; - if (isset($_POST['prefix']) && !empty($_POST['prefix'])) { + if (!empty($_POST['prefix'])) { $prefix = $_POST['prefix'] . '['; $suffix = ']'; } @@ -73,7 +70,7 @@ echo ""; Entity::dropdown($params); echo ""; - echo __('Child entities'); + echo __s('Child entities'); echo ""; Dropdown::showYesNo($prefix . 'is_recursive' . $suffix); echo "
"; diff --git a/ajax/ticketsatisfaction.php b/ajax/ticketsatisfaction.php deleted file mode 100644 index c024e0a050d..00000000000 --- a/ajax/ticketsatisfaction.php +++ /dev/null @@ -1,52 +0,0 @@ -. - * - * --------------------------------------------------------------------- - */ - -/** - * @var bool|null $AJAX_INCLUDE - */ -global $AJAX_INCLUDE; - -// Direct access to file -if (strpos($_SERVER['PHP_SELF'], "ticketsatisfaction.php")) { - $AJAX_INCLUDE = 1; - include('../inc/includes.php'); - header("Content-Type: text/html; charset=UTF-8"); - Html::header_nocache(); -} - -$itemtype = Ticket::class; -$inquest_itemtype = TicketSatisfaction::class; - -include(GLPI_ROOT . "/ajax/commonitilsatisfaction.php"); diff --git a/ajax/uemailUpdate.php b/ajax/uemailUpdate.php index 849d55f6a87..56f766f8c06 100644 --- a/ajax/uemailUpdate.php +++ b/ajax/uemailUpdate.php @@ -33,6 +33,8 @@ * --------------------------------------------------------------------- */ +use Glpi\Application\View\TemplateRenderer; + /** * @var bool|null $AJAX_INCLUDE */ @@ -75,8 +77,7 @@ $default_notif = $_POST['use_notification'][$user_index] ?? true; if ( - isset($_POST['alternative_email'][$user_index]) - && !empty($_POST['alternative_email'][$user_index]) + !empty($_POST['alternative_email'][$user_index]) && empty($default_email) ) { if (NotificationMailing::isUserAddressValid($_POST['alternative_email'][$user_index])) { @@ -90,7 +91,7 @@ echo "
" . Dropdown::showYesNo($_POST['field'] . '[use_notification][]', $default_notif, -1, ['display' => false]) . " diff --git a/ajax/viewsubitem.php b/ajax/viewsubitem.php index 644410474a9..b226f1e185d 100644 --- a/ajax/viewsubitem.php +++ b/ajax/viewsubitem.php @@ -51,12 +51,11 @@ && ($parent = getItemForItemtype($_POST['parenttype'])) ) { if ( - isset($_POST[$parent::getForeignKeyField()]) - && isset($_POST["id"]) + isset($_POST[$parent::getForeignKeyField()], $_POST["id"]) && $parent->getFromDB($_POST[$parent::getForeignKeyField()]) ) { $item->showForm($_POST["id"], ['parent' => $parent]); } else { - echo __('Access denied'); + echo __s('Access denied'); } } diff --git a/ajax/visibility.php b/ajax/visibility.php index 4761a285331..712388a8bc8 100644 --- a/ajax/visibility.php +++ b/ajax/visibility.php @@ -109,7 +109,7 @@ 'entity_sons' => $_POST['is_recursive'] ?? false, ]); echo ""; - echo __('Child entities'); + echo __s('Child entities'); echo ""; Dropdown::showYesNo($prefix . 'is_recursive' . $suffix); echo ""; diff --git a/src/Entity.php b/src/Entity.php index bd9d67d5c59..a1565eb2194 100644 --- a/src/Entity.php +++ b/src/Entity.php @@ -1658,48 +1658,25 @@ public static function showInventoryOptions(Entity $entity) } } - $fn_get_inheritance_label = static function (string $field, ?string $strategy_field = null) use ($entity): ?string { - $result = null; - if ($entity->fields[$field] == self::CONFIG_PARENT) { - if ($strategy_field === null) { - $strategy_field = $field; - } - $inherited_strategy = self::getUsedConfig($strategy_field, $entity->fields['entities_id']); - $inherited_value = $inherited_strategy === 0 - ? self::getUsedConfig($strategy_field, $entity->fields['entities_id'], $field) - : $inherited_strategy; - $result = self::inheritedValue( - self::getSpecificValueToDisplay($field, $inherited_value), - false, - false - ); - } - return $result; - }; - $inheritance_labels = [ - 'entities_id_software' => $fn_get_inheritance_label('entities_id_software', 'entities_strategy_software'), - 'transfers_id' => $fn_get_inheritance_label('transfers_id', 'transfers_strategy'), - 'autofill_buy_date' => $fn_get_inheritance_label('autofill_buy_date'), - 'autofill_order_date' => $fn_get_inheritance_label('autofill_order_date'), - 'autofill_delivery_date' => $fn_get_inheritance_label('autofill_delivery_date'), - 'autofill_use_date' => $fn_get_inheritance_label('autofill_use_date'), - 'autofill_warranty_date' => $fn_get_inheritance_label('autofill_warranty_date'), - 'autofill_decommission_date' => $fn_get_inheritance_label('autofill_decommission_date'), - 'agent_base_url' => self::inheritedValue( - self::getUsedConfig('agent_base_url', $ID, '', ''), - false, - false - ), + 'entities_id_software' => $entity->getInheritedValueBadge('entities_id_software', 'entities_strategy_software'), + 'transfers_id' => $entity->getInheritedValueBadge('transfers_id', 'transfers_strategy'), + 'autofill_buy_date' => $entity->getInheritedValueBadge('autofill_buy_date'), + 'autofill_order_date' => $entity->getInheritedValueBadge('autofill_order_date'), + 'autofill_delivery_date' => $entity->getInheritedValueBadge('autofill_delivery_date'), + 'autofill_use_date' => $entity->getInheritedValueBadge('autofill_use_date'), + 'autofill_warranty_date' => $entity->getInheritedValueBadge('autofill_warranty_date'), + 'autofill_decommission_date' => $entity->getInheritedValueBadge('autofill_decommission_date'), + 'agent_base_url' => $entity->getInheritedValueBadge(field: 'agent_base_url', inherit_parent_value: null), ]; $fields = ["contact", "user", "group", "location"]; foreach ($fields as $field) { - $inheritance_labels["is_{$field}_autoupdate"] = $fn_get_inheritance_label("is_{$field}_autoupdate"); - $inheritance_labels["is_{$field}_autoclean"] = $fn_get_inheritance_label("is_{$field}_autoclean"); + $inheritance_labels["is_{$field}_autoupdate"] = $entity->getInheritedValueBadge("is_{$field}_autoupdate"); + $inheritance_labels["is_{$field}_autoclean"] = $entity->getInheritedValueBadge("is_{$field}_autoclean"); } - $inheritance_labels['state_autoupdate_mode'] = $fn_get_inheritance_label('state_autoupdate_mode'); - $inheritance_labels['state_autoclean_mode'] = $fn_get_inheritance_label('state_autoclean_mode'); + $inheritance_labels['state_autoupdate_mode'] = $entity->getInheritedValueBadge('state_autoupdate_mode'); + $inheritance_labels['state_autoclean_mode'] = $entity->getInheritedValueBadge('state_autoclean_mode'); TemplateRenderer::getInstance()->display('pages/admin/entity/assets.html.twig', [ 'item' => $entity, @@ -1733,58 +1710,41 @@ public static function showNotificationOptions(Entity $entity) return false; } - $fn_get_inheritance_label = static function (string $field) use ($ID): string { - return self::inheritedValue( - self::getUsedConfig($field, $ID, '', ''), - false, - false - ); - }; - - $fn_get_specific_inheritance_label = static function (string $field) use ($entity): string { - $tid = self::getUsedConfig($field, $entity->getField('entities_id')); - return self::inheritedValue( - self::getSpecificValueToDisplay($field, $tid), - false, - false - ); - }; - $inheritance_labels = [ - 'admin_email' => $fn_get_inheritance_label('admin_email'), - 'admin_email_name' => $fn_get_inheritance_label('admin_email_name'), - 'from_email' => $fn_get_inheritance_label('from_email'), - 'from_email_name' => $fn_get_inheritance_label('from_email_name'), - 'noreply_email' => $fn_get_inheritance_label('noreply_email'), - 'noreply_email_name' => $fn_get_inheritance_label('noreply_email_name'), - 'replyto_email' => $fn_get_inheritance_label('replyto_email'), - 'replyto_email_name' => $fn_get_inheritance_label('replyto_email_name'), - 'notification_subject_tag' => $fn_get_inheritance_label('notification_subject_tag'), + 'admin_email' => $entity->getInheritedValueBadge(field: 'admin_email', inherit_parent_value: null), + 'admin_email_name' => $entity->getInheritedValueBadge(field: 'admin_email_name', inherit_parent_value: null), + 'from_email' => $entity->getInheritedValueBadge(field: 'from_email', inherit_parent_value: null), + 'from_email_name' => $entity->getInheritedValueBadge(field: 'from_email_name', inherit_parent_value: null), + 'noreply_email' => $entity->getInheritedValueBadge(field: 'noreply_email', inherit_parent_value: null), + 'noreply_email_name' => $entity->getInheritedValueBadge(field: 'noreply_email_name', inherit_parent_value: null), + 'replyto_email' => $entity->getInheritedValueBadge(field: 'replyto_email', inherit_parent_value: null), + 'replyto_email_name' => $entity->getInheritedValueBadge(field: 'replyto_email_name', inherit_parent_value: null), + 'notification_subject_tag' => $entity->getInheritedValueBadge(field: 'notification_subject_tag', inherit_parent_value: null), 'delay_send_emails' => null, 'is_notif_enable_default' => null, - 'mailing_signature' => $fn_get_inheritance_label('mailing_signature'), - 'url_base' => $fn_get_inheritance_label('url_base'), - 'cartridges_alert_repeat' => $fn_get_specific_inheritance_label('cartridges_alert_repeat'), - 'default_cartridges_alarm_threshold' => $fn_get_specific_inheritance_label('default_cartridges_alarm_threshold'), - 'consumables_alert_repeat' => $fn_get_specific_inheritance_label('consumables_alert_repeat'), - 'default_consumables_alarm_threshold' => $fn_get_specific_inheritance_label('default_consumables_alarm_threshold'), - 'use_contracts_alert' => $fn_get_specific_inheritance_label('use_contracts_alert'), - 'default_contract_alert' => $fn_get_specific_inheritance_label('default_contract_alert'), - 'send_contracts_alert_before_delay' => $fn_get_specific_inheritance_label('send_contracts_alert_before_delay'), - 'use_infocoms_alert' => $fn_get_specific_inheritance_label('use_infocoms_alert'), - 'default_infocom_alert' => $fn_get_specific_inheritance_label('default_infocom_alert'), - 'send_infocoms_alert_before_delay' => $fn_get_specific_inheritance_label('send_infocoms_alert_before_delay'), - 'use_licenses_alert' => $fn_get_specific_inheritance_label('use_licenses_alert'), - 'send_licenses_alert_before_delay' => $fn_get_specific_inheritance_label('send_licenses_alert_before_delay'), - 'use_certificates_alert' => $fn_get_specific_inheritance_label('use_certificates_alert'), - 'send_certificates_alert_before_delay' => $fn_get_specific_inheritance_label('send_certificates_alert_before_delay'), - 'certificates_alert_repeat_interval' => $fn_get_specific_inheritance_label('certificates_alert_repeat_interval'), - 'use_reservations_alert' => $fn_get_specific_inheritance_label('use_reservations_alert'), - 'notclosed_delay' => $fn_get_specific_inheritance_label('notclosed_delay'), - 'use_domains_alert' => $fn_get_specific_inheritance_label('use_domains_alert'), - 'send_domains_alert_close_expiries_delay' => $fn_get_specific_inheritance_label('send_domains_alert_close_expiries_delay'), - 'send_domains_alert_expired_delay' => $fn_get_specific_inheritance_label('send_domains_alert_expired_delay'), - 'approval_reminder_repeat_interval' => $fn_get_specific_inheritance_label('approval_reminder_repeat_interval'), + 'mailing_signature' => $entity->getInheritedValueBadge('mailing_signature', inherit_parent_value: null), + 'url_base' => $entity->getInheritedValueBadge('url_base', inherit_parent_value: null), + 'cartridges_alert_repeat' => $entity->getInheritedValueBadge('cartridges_alert_repeat'), + 'default_cartridges_alarm_threshold' => $entity->getInheritedValueBadge('default_cartridges_alarm_threshold'), + 'consumables_alert_repeat' => $entity->getInheritedValueBadge('consumables_alert_repeat'), + 'default_consumables_alarm_threshold' => $entity->getInheritedValueBadge('default_consumables_alarm_threshold'), + 'use_contracts_alert' => $entity->getInheritedValueBadge('use_contracts_alert'), + 'default_contract_alert' => $entity->getInheritedValueBadge('default_contract_alert'), + 'send_contracts_alert_before_delay' => $entity->getInheritedValueBadge('send_contracts_alert_before_delay'), + 'use_infocoms_alert' => $entity->getInheritedValueBadge('use_infocoms_alert'), + 'default_infocom_alert' => $entity->getInheritedValueBadge('default_infocom_alert'), + 'send_infocoms_alert_before_delay' => $entity->getInheritedValueBadge('send_infocoms_alert_before_delay'), + 'use_licenses_alert' => $entity->getInheritedValueBadge('use_licenses_alert'), + 'send_licenses_alert_before_delay' => $entity->getInheritedValueBadge('send_licenses_alert_before_delay'), + 'use_certificates_alert' => $entity->getInheritedValueBadge('use_certificates_alert'), + 'send_certificates_alert_before_delay' => $entity->getInheritedValueBadge('send_certificates_alert_before_delay'), + 'certificates_alert_repeat_interval' => $entity->getInheritedValueBadge('certificates_alert_repeat_interval'), + 'use_reservations_alert' => $entity->getInheritedValueBadge('use_reservations_alert'), + 'notclosed_delay' => $entity->getInheritedValueBadge('notclosed_delay'), + 'use_domains_alert' => $entity->getInheritedValueBadge('use_domains_alert'), + 'send_domains_alert_close_expiries_delay' => $entity->getInheritedValueBadge('send_domains_alert_close_expiries_delay'), + 'send_domains_alert_expired_delay' => $entity->getInheritedValueBadge('send_domains_alert_expired_delay'), + 'approval_reminder_repeat_interval' => $entity->getInheritedValueBadge('approval_reminder_repeat_interval'), ]; if ($entity->fields['delay_send_emails'] == self::CONFIG_PARENT) { $tid = self::getUsedConfig('delay_send_emails', $entity->getField('entities_id')); @@ -2025,15 +1985,12 @@ public static function isEntityDirectoryConfigured($entities_id) } /** + * @param Entity $entity + * @return false|void * @since 0.84 (before in entitydata.class) - * - * @param Entity $entity object **/ public static function showHelpdeskOptions(Entity $entity) { - /** @var array $CFG_GLPI */ - global $CFG_GLPI; - $ID = $entity->getField('id'); if ( !$entity->can($ID, READ) @@ -2047,500 +2004,43 @@ public static function showHelpdeskOptions(Entity $entity) $canedit = (Session::haveRight(self::$rightname, self::UPDATEHELPDESK) && Session::haveAccessToEntity($ID)); - echo "
"; - if ($canedit) { - echo "
"; - } - - echo ""; - - Plugin::doHook(Hooks::PRE_ITEM_FORM, ['item' => $entity, 'options' => []]); - - echo ""; - - echo ""; - echo ""; - - echo ""; - echo ""; - - echo ""; - echo ""; - - echo ""; - - echo ""; - echo ""; - - echo ""; - echo ""; - - // Auto assign mode - echo ""; - echo ""; - - echo ""; - echo ""; - - echo ""; - echo ""; - - echo ""; - echo ""; - - echo ""; - echo ""; - - echo ""; - - echo "" . - ""; - echo ""; - echo ""; - - $inquest_types = [ - Ticket::class => TicketSatisfaction::class, - Change::class => ChangeSatisfaction::class, - ]; - - /** - * @var CommonITILObject $itemtype - * @var CommonITILSatisfaction $inquest_itemtype - */ - foreach ($inquest_types as $itemtype => $inquest_itemtype) { - $config_title = sprintf(__('Configuring the satisfaction survey: %s'), $itemtype::getTypeName(Session::getPluralNumber())); - // Get suffix for entity config fields. For backwards compatibility, ticket values have no suffix. - $config_suffix = $itemtype::getType() === 'Ticket' ? '' : ('_' . strtolower($itemtype::getType())); - - echo ""; - - echo "" . - ""; - echo "\n"; - - if ($entity->fields['inquest_config' . $config_suffix] == self::CONFIG_PARENT) { - $inquestconfig = self::getUsedConfig('inquest_config' . $config_suffix, $entity->fields['entities_id']); - $inquestrate = self::getUsedConfig( - 'inquest_config' . $config_suffix, - $entity->fields['entities_id'], - 'inquest_rate' . $config_suffix - ); - echo ""; - } - - echo ""; - } - - Plugin::doHook(Hooks::POST_ITEM_FORM, ['item' => $entity, 'options' => &$options]); - - echo "
" . __('Templates configuration') . "
" . _n('Ticket template', 'Ticket templates', 1) . - ""; - $toadd = []; - if ($ID != 0) { - $toadd = [self::CONFIG_PARENT => __('Inheritance of the parent entity')]; - } - - $options = ['value' => $entity->fields["tickettemplates_id"], - 'entity' => $ID, - 'toadd' => $toadd - ]; - - TicketTemplate::dropdown($options); - - if ($entity->fields["tickettemplates_id"] == self::CONFIG_PARENT) { - $tt = new TicketTemplate(); - $tid = self::getUsedConfig('tickettemplates_strategy', $ID, 'tickettemplates_id', 0); - if (!$tid) { - self::inheritedValue(Dropdown::EMPTY_VALUE, true); - } else if ($tt->getFromDB($tid)) { - self::inheritedValue($tt->getLink(), true); - } - } - echo "
" . _n('Change template', 'Change templates', 1) . - ""; - $toadd = []; - if ($ID != 0) { - $toadd = [self::CONFIG_PARENT => __('Inheritance of the parent entity')]; - } - - $options = ['value' => $entity->fields["changetemplates_id"], - 'entity' => $ID, - 'toadd' => $toadd - ]; - - ChangeTemplate::dropdown($options); - - if ($entity->fields["changetemplates_id"] == self::CONFIG_PARENT) { - $tt = new ChangeTemplate(); - $tid = self::getUsedConfig('changetemplates_strategy', $ID, 'changetemplates_id', 0); - if (!$tid) { - self::inheritedValue(Dropdown::EMPTY_VALUE, true); - } else if ($tt->getFromDB($tid)) { - self::inheritedValue($tt->getLink(), true); - } - } - echo "
" . _n('Problem template', 'Problem templates', 1) . - ""; - $toadd = []; - if ($ID != 0) { - $toadd = [self::CONFIG_PARENT => __('Inheritance of the parent entity')]; - } - - $options = ['value' => $entity->fields["problemtemplates_id"], - 'entity' => $ID, - 'toadd' => $toadd - ]; - - ProblemTemplate::dropdown($options); - - if ($entity->fields["problemtemplates_id"] == self::CONFIG_PARENT) { - $tt = new ProblemTemplate(); - $tid = self::getUsedConfig('problemtemplates_strategy', $ID, 'problemtemplates_id', 0); - if (!$tid) { - self::inheritedValue(Dropdown::EMPTY_VALUE, true); - } else if ($tt->getFromDB($tid)) { - self::inheritedValue($tt->getLink(), true); - } - } - echo "
" . __('Tickets configuration') . "
" . _n('Calendar', 'Calendars', 1) . ""; - $options = ['value' => $entity->fields["calendars_id"], - 'emptylabel' => __('24/7') - ]; - - if ($ID != 0) { - $options['toadd'] = [self::CONFIG_PARENT => __('Inheritance of the parent entity')]; - } - Calendar::dropdown($options); - - if ($entity->fields["calendars_id"] == self::CONFIG_PARENT) { - $calendar = new Calendar(); - $cid = self::getUsedConfig('calendars_strategy', $ID, 'calendars_id', 0); - if (!$cid) { - self::inheritedValue(__('24/7'), true); - } else if ($calendar->getFromDB($cid)) { - self::inheritedValue($calendar->getLink(), true); - } - } - echo "
" . __('Tickets default type') . ""; - $toadd = []; - if ($ID != 0) { - $toadd = [self::CONFIG_PARENT => __('Inheritance of the parent entity')]; - } - Ticket::dropdownType('tickettype', ['value' => $entity->fields["tickettype"], - 'toadd' => $toadd - ]); - - if ($entity->fields['tickettype'] == self::CONFIG_PARENT) { - self::inheritedValue(Ticket::getTicketTypeName(self::getUsedConfig( - 'tickettype', - $ID, - '', - Ticket::INCIDENT_TYPE - )), true); - } - echo "
" . __('Automatic assignment of tickets, changes and problems') . ""; - $autoassign = self::getAutoAssignMode(); - - if ($ID == 0) { - unset($autoassign[self::CONFIG_PARENT]); - } - - Dropdown::showFromArray( - 'auto_assign_mode', - $autoassign, - ['value' => $entity->fields["auto_assign_mode"]] - ); - - if ($entity->fields['auto_assign_mode'] == self::CONFIG_PARENT) { - $auto_assign_mode = self::getUsedConfig('auto_assign_mode', $entity->fields['entities_id']); - self::inheritedValue($autoassign[$auto_assign_mode], true); - } - echo "
" . __('Mark followup added by a supplier though an email collector as private') . ""; - $supplierValues = self::getSuppliersAsPrivateValues(); - $currentSupplierValue = $entity->fields['suppliers_as_private']; - - if ($ID == 0) { // Remove parent option for root entity - unset($supplierValues[self::CONFIG_PARENT]); - } - - Dropdown::showFromArray( - 'suppliers_as_private', - $supplierValues, - ['value' => $currentSupplierValue] - ); - - // If the entity is using it's parent value, print it - if ($currentSupplierValue == self::CONFIG_PARENT) { - $parentSupplierValue = self::getUsedConfig( - 'suppliers_as_private', - $entity->fields['entities_id'] - ); - self::inheritedValue($supplierValues[$parentSupplierValue], true); - } - echo "
" . __('Anonymize support agents') . ""; - $anonymize_values = self::getAnonymizeSupportAgentsValues(); - $current_anonymize_value = $entity->fields['anonymize_support_agents']; - - if ($ID == 0) { // Remove parent option for root entity - unset($anonymize_values[self::CONFIG_PARENT]); - } - - Dropdown::showFromArray( - 'anonymize_support_agents', - $anonymize_values, - ['value' => $current_anonymize_value] - ); - - // If the entity is using it's parent value, print it - if ($current_anonymize_value == self::CONFIG_PARENT) { - $parent_helpdesk_value = self::getUsedConfig( - 'anonymize_support_agents', - $entity->fields['entities_id'] - ); - self::inheritedValue($anonymize_values[$parent_helpdesk_value], true); - } - echo "
" . __("Display initials for users without pictures") . ""; - $initialsValues = self::getDisplayUsersInitialsValues(); - $currentInitialsValue = $entity->fields['display_users_initials']; - - if ($ID == 0) { // Remove parent option for root entity - unset($initialsValues[self::CONFIG_PARENT]); - } - - Dropdown::showFromArray( - 'display_users_initials', - $initialsValues, - ['value' => $currentInitialsValue] - ); - - // If the entity is using it's parent value, print it - if ($currentInitialsValue == self::CONFIG_PARENT) { - $parentSupplierValue = self::getUsedConfig( - 'display_users_initials', - $entity->fields['entities_id'] - ); - self::inheritedValue($initialsValues[$parentSupplierValue], true); - } - echo "
" . __('Default contract') . ""; - $current_default_contract_value = $entity->fields['contracts_id_default']; - - $toadd = [ - self::CONFIG_PARENT => __('Inheritance of the parent entity'), - self::CONFIG_AUTO => __('Contract in ticket entity'), - ]; - - if ($ID == 0) { // Remove parent option for root entity - unset($toadd[self::CONFIG_PARENT]); - } - - Contract::dropdown([ - 'name' => 'contracts_id_default', - 'condition' => ['is_template' => 0, 'is_deleted' => 0] + Contract::getNotExpiredCriteria(), - 'entity' => $entity->getID(), - 'toadd' => $toadd, - 'value' => $current_default_contract_value, - ]); - - // If the entity is using it's parent value, print it - if ($current_default_contract_value == self::CONFIG_PARENT) { - $inherited_default_contract_strategy = self::getUsedConfig( - 'contracts_strategy_default', - $entity->fields['entities_id'] - ); - $inherited_default_contract_id = self::getUsedConfig( - 'contracts_strategy_default', - $entity->fields['entities_id'], - 'contracts_id_default', - 0 - ); - $contract = new Contract(); - if ($inherited_default_contract_strategy == self::CONFIG_AUTO) { - $display_value = __('Contract in ticket entity'); - } elseif ($inherited_default_contract_id > 0 && $contract->getFromDB($inherited_default_contract_id)) { - $display_value = $contract->fields['name']; - } else { - $display_value = Dropdown::EMPTY_VALUE; - } - - self::inheritedValue($display_value, true); - } - echo "
" . __('Automatic closing configuration') . "
" . __('Automatic closing of solved tickets after'); - - //Check if crontask is disabled $crontask = new CronTask(); - $criteria = [ - 'itemtype' => 'Ticket', - 'name' => 'closeticket', - 'state' => CronTask::STATE_DISABLE - ]; - if ($crontask->getFromDBByCrit($criteria)) { - echo "
" . __('Close ticket action is disabled.') . ""; - } - - echo "
"; - $autoclose = [self::CONFIG_PARENT => __('Inheritance of the parent entity'), - self::CONFIG_NEVER => __('Never'), - 0 => __('Immediatly') - ]; - if ($ID == 0) { - unset($autoclose[self::CONFIG_PARENT]); - } - - Dropdown::showNumber( - 'autoclose_delay', - ['value' => $entity->fields['autoclose_delay'], - 'min' => 1, - 'max' => 99, - 'step' => 1, - 'toadd' => $autoclose, - 'unit' => 'day' - ] - ); - - if ($entity->fields['autoclose_delay'] == self::CONFIG_PARENT) { - $autoclose_mode = self::getUsedConfig( - 'autoclose_delay', - $entity->fields['entities_id'], - '', - self::CONFIG_NEVER - ); - - if ($autoclose_mode >= 0) { - self::inheritedValue(sprintf(_n('%d day', '%d days', $autoclose_mode), $autoclose_mode), true); - } else { - self::inheritedValue($autoclose[$autoclose_mode], true); - } - } - echo "" . __('Automatic purge of closed tickets after'); - - //Check if crontask is disabled - $crontask = new CronTask(); - $criteria = [ - 'itemtype' => 'Ticket', - 'name' => 'purgeticket', - 'state' => CronTask::STATE_DISABLE - ]; - if ($crontask->getFromDBByCrit($criteria)) { - echo "
" . __('Purge ticket action is disabled.') . ""; - } - echo "
"; - $autopurge = [ - self::CONFIG_PARENT => __('Inheritance of the parent entity'), - self::CONFIG_NEVER => __('Never') - ]; - if ($ID == 0) { - unset($autopurge[self::CONFIG_PARENT]); - } - - Dropdown::showNumber( - 'autopurge_delay', - [ - 'value' => $entity->fields['autopurge_delay'], - 'min' => 1, - 'max' => 3650, - 'step' => 1, - 'toadd' => $autopurge, - 'unit' => 'day' + $inheritance_labels = [ + 'tickettemplates_id' => $entity->getInheritedLinkedValueBadge(TicketTemplate::class), + 'changetemplates_id' => $entity->getInheritedLinkedValueBadge(ChangeTemplate::class), + 'problemtemplates_id' => $entity->getInheritedLinkedValueBadge(ProblemTemplate::class), + 'calendars_id' => $entity->getInheritedLinkedValueBadge(Calendar::class, __('24/7')), + 'tickettype' => $entity->getInheritedValueBadge(field: 'tickettype', default_value: Ticket::INCIDENT_TYPE), + 'auto_assign_mode' => $entity->getInheritedValueBadge('auto_assign_mode'), + 'suppliers_as_private' => $entity->getInheritedValueBadge('suppliers_as_private'), + 'anonymize_support_agents' => $entity->getInheritedValueBadge('anonymize_support_agents'), + 'display_users_initials' => $entity->getInheritedValueBadge('display_users_initials'), + 'contracts_id_default' => $entity->getInheritedValueBadge('contracts_id_default', 'contracts_strategy_default'), + 'inquest_config' => $entity->getInheritedValueBadge('inquest_config'), + 'inquest_config_change' => $entity->getInheritedValueBadge('inquest_config_change'), + 'autoclose_delay' => $entity->getInheritedValueBadge('autoclose_delay'), + 'autopurge_delay' => $entity->getInheritedValueBadge(field: 'autopurge_delay', default_value: self::CONFIG_NEVER), + ]; + + TemplateRenderer::getInstance()->display('pages/admin/entity/assistance.html.twig', [ + 'item' => $entity, + 'inheritance_labels' => $inheritance_labels, + 'closeticket_disabled' => (bool) $crontask->getFromDBByCrit([ + 'itemtype' => 'Ticket', + 'name' => 'closeticket', + 'state' => CronTask::STATE_DISABLE + ]), + 'purgeticket_disabled' => (bool) $crontask->getFromDBByCrit([ + 'itemtype' => 'Ticket', + 'name' => 'purgeticket', + 'state' => CronTask::STATE_DISABLE + ]), + 'params' => [ + 'canedit' => $canedit, + 'candel' => false, // No deleting from the non-main tab + 'formfooter' => false ] - ); - - if ($entity->fields['autopurge_delay'] == self::CONFIG_PARENT) { - $autopurge_mode = self::getUsedConfig( - 'autopurge_delay', - $entity->fields['entities_id'], - '', - self::CONFIG_NEVER - ); - - if ($autopurge_mode >= 0) { - self::inheritedValue(sprintf(_n('%d day', '%d days', $autopurge_mode), $autopurge_mode), true); - } else { - self::inheritedValue($autopurge[$autopurge_mode], true); - } - } - echo "
" . $config_title . "
" . __('Configuring the satisfaction survey') . ""; - - /// no inquest case = rate 0 - $typeinquest = [ - self::CONFIG_PARENT => __('Inheritance of the parent entity'), - CommonITILSatisfaction::TYPE_INTERNAL => __('Internal survey'), - CommonITILSatisfaction::TYPE_EXTERNAL => __('External survey') - ]; - - // No inherit from parent for root entity - if ($ID == 0) { - unset($typeinquest[self::CONFIG_PARENT]); - if ($entity->fields['inquest_config' . $config_suffix] == self::CONFIG_PARENT) { - $entity->fields['inquest_config' . $config_suffix] = 1; - } - } - $rand = Dropdown::showFromArray( - 'inquest_config' . $config_suffix, - $typeinquest, - $options = ['value' => $entity->fields['inquest_config' . $config_suffix]] - ); - echo "
"; - - $inherit = ""; - if ($inquestrate == 0) { - $inherit .= __('Disabled'); - } else { - $inherit .= $typeinquest[$inquestconfig] . '
'; - $inqconf = self::getUsedConfig( - 'inquest_config' . $config_suffix, - $entity->fields['entities_id'], - 'inquest_delay' . $config_suffix - ); - - $inherit .= sprintf(_n('%d day', '%d days', $inqconf), $inqconf); - $inherit .= "
"; - //TRANS: %d is the percentage. %% to display % - $inherit .= sprintf(__('%d%%'), $inquestrate); - - if ($inquestconfig == 2) { - $inherit .= "
"; - $inherit .= self::getUsedConfig( - 'inquest_config' . $config_suffix, - $entity->fields['entities_id'], - 'inquest_URL' . $config_suffix - ); - } - } - self::inheritedValue($inherit, true); - echo "
"; - - $_POST = [ - ('inquest_config' . $config_suffix) => $entity->fields['inquest_config' . $config_suffix], - 'entities_id' => $ID - ]; - $params = [ - ('inquest_config' . $config_suffix) => '__VALUE__', - 'entities_id' => $ID - ]; - echo "
"; - $ajax_file = GLPI_ROOT . '/ajax/' . strtolower($inquest_itemtype::getType()) . '.php'; - include $ajax_file; - echo "
\n"; - - echo "
"; - - if ($canedit) { - echo "
"; - echo ""; - echo ""; - echo "
"; - Html::closeForm(); - } - - echo "
"; - - Ajax::updateItemOnSelectEvent( - "dropdown_inquest_config$rand", - "inquestconfig", - $CFG_GLPI["root_doc"] . "/ajax/ticketsatisfaction.php", - $params - ); + ]); } /** @@ -2922,31 +2422,28 @@ public static function getSpecificValueToDisplay($field, $values, array $options case 'use_domains_alert': case 'use_infocoms_alert': case 'is_notif_enable_default': - if ($values[$field] == self::CONFIG_PARENT) { + case 'enable_custom_css': + case 'suppliers_as_private': + case 'display_users_initials': + if ($values[$field] === self::CONFIG_PARENT) { return __('Inheritance of the parent entity'); } return Dropdown::getYesNo($values[$field]); case 'use_reservations_alert': - switch ($values[$field]) { - case self::CONFIG_PARENT: - return __('Inheritance of the parent entity'); - - case 0: - return __('Never'); - } - return sprintf(_n('%d hour', '%d hours', $values[$field]), $values[$field]); + return match ($values[$field]) { + self::CONFIG_PARENT => __('Inheritance of the parent entity'), + 0 => __('Never'), + default => sprintf(_n('%d hour', '%d hours', $values[$field]), $values[$field]), + }; case 'default_cartridges_alarm_threshold': case 'default_consumables_alarm_threshold': - switch ($values[$field]) { - case self::CONFIG_PARENT: - return __('Inheritance of the parent entity'); - - case 0: - return __('Never'); - } - return $values[$field]; + return match ($values[$field]) { + self::CONFIG_PARENT => __('Inheritance of the parent entity'), + 0 => __('Never'), + default => $values[$field], + }; case 'send_contracts_alert_before_delay': case 'send_infocoms_alert_before_delay': @@ -2954,56 +2451,37 @@ public static function getSpecificValueToDisplay($field, $values, array $options case 'send_certificates_alert_before_delay': case 'send_domains_alert_close_expiries_delay': case 'send_domains_alert_expired_delay': - switch ($values[$field]) { - case self::CONFIG_PARENT: - return __('Inheritance of the parent entity'); - - case 0: - return __('No'); - } - return sprintf(_n('%d day', '%d days', $values[$field]), $values[$field]); + return match ($values[$field]) { + self::CONFIG_PARENT => __('Inheritance of the parent entity'), + 0 => __('No'), + default => sprintf(_n('%d day', '%d days', $values[$field]), $values[$field]), + }; case 'cartridges_alert_repeat': case 'consumables_alert_repeat': case 'approval_reminder_repeat_interval': - switch ($values[$field]) { - case self::CONFIG_PARENT: - return __('Inheritance of the parent entity'); - - case self::CONFIG_NEVER: - case 0: // For compatibility issue - return __('Never'); - - case DAY_TIMESTAMP: - return __('Each day'); - - case WEEK_TIMESTAMP: - return __('Each week'); - - case MONTH_TIMESTAMP: - return __('Each month'); - - default: - // Display value if not defined - return $values[$field]; - } - break; + case 'certificates_alert_repeat_interval': + return match ($values[$field]) { + self::CONFIG_PARENT => __('Inheritance of the parent entity'), + self::CONFIG_NEVER, 0 => __('Never'), + DAY_TIMESTAMP => __('Each day'), + WEEK_TIMESTAMP => __('Each week'), + MONTH_TIMESTAMP => __('Each month'), + default => $values[$field], + }; case 'notclosed_delay': // 0 means never - switch ($values[$field]) { - case self::CONFIG_PARENT: - return __('Inheritance of the parent entity'); - - case 0: - return __('Never'); - } - return sprintf(_n('%d day', '%d days', $values[$field]), $values[$field]); + return match ($values[$field]) { + self::CONFIG_PARENT => __('Inheritance of the parent entity'), + 0 => __('Never'), + default => sprintf(_n('%d day', '%d days', $values[$field]), $values[$field]), + }; case 'auto_assign_mode': return self::getAutoAssignMode((int) $values[$field]); case 'tickettype': - if ($values[$field] == self::CONFIG_PARENT) { + if ($values[$field] === self::CONFIG_PARENT) { return __('Inheritance of the parent entity'); } return Ticket::getTicketTypeName($values[$field]); @@ -3031,9 +2509,9 @@ public static function getSpecificValueToDisplay($field, $values, array $options return __('Copy the delivery date'); default: - if (strstr($values[$field], '_')) { - list($type,$sid) = explode('_', $values[$field], 2); - if ($type == Infocom::ON_STATUS_CHANGE) { + if (str_contains($values[$field], '_')) { + [$type, $sid] = explode('_', $values[$field], 2); + if ($type === Infocom::ON_STATUS_CHANGE) { // TRANS %s is the name of the state return sprintf( __('Fill when shifting to state %s'), @@ -3046,10 +2524,41 @@ public static function getSpecificValueToDisplay($field, $values, array $options case 'inquest_config': case 'inquest_config_change': - if ($values[$field] == self::CONFIG_PARENT) { + if ($values[$field] === self::CONFIG_PARENT) { return __('Inheritance of the parent entity'); } - return CommonITILSatisfaction::getTypeInquestName($values[$field]); + $inherit = ''; + $inquest_rate = self::getUsedConfig( + $field, + $options['entity']->fields['entities_id'], + str_replace('config', 'rate', $field) + ); + $inherit .= '
'; + if ($inquest_rate === 0) { + $inherit .= __('Disabled'); + } else { + $inherit .= CommonITILSatisfaction::getTypeInquestName($values[$field]) . '
'; + $inqconf = self::getUsedConfig( + $field, + $options['entity']->fields['entities_id'], + str_replace('config', 'delay', $field) + ); + + $inherit .= sprintf(_n('%d day', '%d days', $inqconf), $inqconf); + $inherit .= "
"; + //TRANS: %d is the percentage. %% to display % + $inherit .= sprintf(__('%d%%'), $inquest_rate); + + if ($values[$field] === 2) { + $inherit .= "
"; + $inherit .= self::getUsedConfig( + $field, + $options['entity']->fields['entities_id'], + str_replace('config', 'URL', $field) + ); + } + } + return $inherit; case 'default_contract_alert': return Contract::getAlertName($values[$field]); @@ -3059,98 +2568,87 @@ public static function getSpecificValueToDisplay($field, $values, array $options case 'entities_id_software': $strategy = $values['entities_strategy_software'] ?? $values[$field]; - if ($strategy == self::CONFIG_NEVER) { - return __('No change of entity'); - } - if ($strategy == self::CONFIG_PARENT) { - return __('Inheritance of the parent entity'); - } - return Dropdown::getDropdownName('glpi_entities', $values[$field]); + return match ($strategy) { + self::CONFIG_PARENT => __('Inheritance of the parent entity'), + self::CONFIG_NEVER => __('No change of entity'), + default => Dropdown::getDropdownName('glpi_entities', $values[$field]), + }; case 'tickettemplates_id': $strategy = $values['tickettemplates_strategy'] ?? $values[$field]; - if ($strategy == self::CONFIG_PARENT) { + if ($strategy === self::CONFIG_PARENT) { return __('Inheritance of the parent entity'); } return Dropdown::getDropdownName(TicketTemplate::getTable(), $values[$field]); case 'calendars_id': $strategy = $values['calendars_strategy'] ?? $values[$field]; - if ($strategy == self::CONFIG_PARENT) { - return __('Inheritance of the parent entity'); - } elseif ($values[$field] == 0) { - return __('24/7'); - } - return Dropdown::getDropdownName('glpi_calendars', $values[$field]); + return match ($strategy) { + self::CONFIG_PARENT => __('Inheritance of the parent entity'), + self::CONFIG_NEVER => __('24/7'), + default => Dropdown::getDropdownName('glpi_calendars', $values[$field]), + }; case 'transfers_id': $strategy = $values['transfers_strategy'] ?? $values[$field]; - if ($strategy == self::CONFIG_NEVER) { - return __('No automatic transfer'); - } - if ($strategy == self::CONFIG_PARENT) { - return __('Inheritance of the parent entity'); - } elseif ($values[$field] == 0) { - return __('No automatic transfer'); - } - return Dropdown::getDropdownName('glpi_transfers', $values[$field]); + return match (true) { + $strategy === self::CONFIG_PARENT => __('Inheritance of the parent entity'), + $strategy === self::CONFIG_NEVER, $values[$field] === 0 => __('No automatic transfer'), + default => Dropdown::getDropdownName('glpi_transfers', $values[$field]), + }; case 'contracts_id_default': $strategy = $values['contracts_strategy_default'] ?? $values[$field]; - if ($strategy === self::CONFIG_PARENT) { - return __('Inheritance of the parent entity'); - } - if ($strategy === self::CONFIG_AUTO) { - return __('Contract in ticket entity'); - } - - return Dropdown::getDropdownName(Contract::getTable(), $values[$field]); + return match ($strategy) { + self::CONFIG_PARENT => __('Inheritance of the parent entity'), + self::CONFIG_AUTO => __('Contract in ticket entity'), + default => Dropdown::getDropdownName('glpi_contracts', $values[$field]), + }; case 'is_contact_autoupdate': case 'is_user_autoupdate': case 'is_group_autoupdate': case 'is_location_autoupdate': - if ($values[$field] == self::CONFIG_PARENT) { - return __('Inheritance of the parent entity'); - } elseif ($values[$field]) { - return __('Copy'); - } - return __('Do not copy'); + return match (true) { + $values[$field] === self::CONFIG_PARENT => __('Inheritance of the parent entity'), + $values[$field] > 0 => __('Copy'), + default => __('Do not copy'), + }; case 'is_contact_autoclean': case 'is_user_autoclean': case 'is_group_autoclean': case 'is_location_autoclean': - if ($values[$field] == self::CONFIG_PARENT) { - return __('Inheritance of the parent entity'); - } elseif ($values[$field]) { - return __('Clear'); - } - return __('Do not delete'); + return match (true) { + $values[$field] === self::CONFIG_PARENT => __('Inheritance of the parent entity'), + $values[$field] > 0 => __('Clear'), + default => __('Do not delete'), + }; case 'state_autoupdate_mode': - if ($values[$field] == self::CONFIG_PARENT) { + if ($values[$field] === self::CONFIG_PARENT) { return __('Inheritance of the parent entity'); } - $states = State::getBehaviours( - __('Copy computer status'), - ); + $states = State::getBehaviours(__('Copy computer status')); return $states[$values[$field]]; case 'state_autoclean_mode': - if ($values[$field] == self::CONFIG_PARENT) { - return __('Inheritance of the parent entity'); - } - $states = State::getBehaviours( - __('Clear status'), - ); - return $states[$values[$field]]; - case 'enable_custom_css': if ($values[$field] === self::CONFIG_PARENT) { return __('Inheritance of the parent entity'); } - return Dropdown::getYesNo($values[$field]); + $states = State::getBehaviours(__('Clear status')); + return $states[$values[$field]]; + case 'anonymize_support_agents': + return self::getAnonymizeSupportAgentsValues()[$values[$field]] ?? $values[$field]; + case 'autoclose_delay': + case 'autopurge_delay': + return match ($values[$field]) { + self::CONFIG_NEVER => __('Never'), + 0 => __('Immediately'), + default => sprintf(_n('%d day', '%d days', $values[$field]), $values[$field]), + }; + default: + return $values[$field] ?? ''; } - return parent::getSpecificValueToDisplay($field, $values, $options); } public static function getSpecificValueToSelect($field, $name = '', $values = '', array $options = []) @@ -3296,7 +2794,6 @@ public static function inheritedValue($value = "", bool $inline = false, bool $d return ""; } - $value = htmlspecialchars($value); $out = "
@@ -3312,6 +2809,68 @@ public static function inheritedValue($value = "", bool $inline = false, bool $d return $out; } + /** + * Get the badge HTML for a field that can be inherited + * @param string $field The field name + * @param string|null $strategy_field The field name of the strategy + * @param mixed $default_value + * @return string|null The badge HTML or null if the field is not inherited + */ + public function getInheritedValueBadge(string $field, ?string $strategy_field = null, mixed $default_value = self::CONFIG_PARENT, mixed $inherit_parent_value = self::CONFIG_PARENT): ?string + { + if ($this->getID() <= 0) { + return null; + } + $result = null; + if ($this->fields[$field] == $inherit_parent_value) { + if ($strategy_field === null) { + $strategy_field = $field; + } + $inherited_strategy = self::getUsedConfig($strategy_field, $this->fields['entities_id']); + $inherited_value = $inherited_strategy === 0 + ? self::getUsedConfig($strategy_field, $this->fields['entities_id'], $field, $default_value) + : $inherited_strategy; + if ($inherited_value === self::CONFIG_PARENT) { + return null; + } + $result = self::inheritedValue( + self::getSpecificValueToDisplay($field, $inherited_value, [ + 'entity' => $this, + ]), + false, + false + ); + } + return $result; + } + + /** + * Get the badge HTML for a linked field that can be inherited + * @param class-string $itemtype The item type + * @param string $empty_value The value to display when the field is empty + * @param string|null $field The field name + * @param int $default_value The default value + * @return string|null The badge HTML or null if the field is not inherited + */ + public function getInheritedLinkedValueBadge(string $itemtype, string $empty_value = Dropdown::EMPTY_VALUE, ?string $field = null, int $default_value = 0): ?string + { + if ($this->getID() <= 0) { + return null; + } + $item = new $itemtype(); + $field = $field ?? $item::getForeignKeyField(); + if ($this->fields[$field] == self::CONFIG_PARENT) { + $tid = self::getUsedConfig(str_replace('_id', '_strategy', $field), $this->getID(), $field, $default_value); + if (!$tid) { + return self::inheritedValue(htmlspecialchars($empty_value), true, false); + } + if ($item->getFromDB($tid)) { + return self::inheritedValue($item->getLink(), true, false); + } + } + return null; + } + public static function getIcon() { return "ti ti-stack"; diff --git a/src/Glpi/DBAL/QueryFunction.php b/src/Glpi/DBAL/QueryFunction.php index ae71e16f5dc..62957206db5 100644 --- a/src/Glpi/DBAL/QueryFunction.php +++ b/src/Glpi/DBAL/QueryFunction.php @@ -452,4 +452,15 @@ public static function locate(string|QueryExpression $substring, string|QueryExp $substring = is_string($substring) ? new QueryExpression($DB::quoteValue($substring)) : $substring; return self::getExpression('LOCATE', [$substring, $expression], $alias); } + + public static function concat_ws(string|QueryExpression $separator, array $params, ?string $alias = null): QueryExpression + { + /** @var \DBmysql $DB */ + global $DB; + $params = array_map(static function ($p) use ($DB) { + return $p instanceof QueryExpression || $p === null ? $p : $DB::quoteName($p); + }, $params); + $separator = $separator instanceof QueryExpression ? $separator : $DB::quoteName($separator); + return new QueryExpression('CONCAT_WS(' . $separator . ', ' . implode(', ', $params) . ')', $alias); + } } diff --git a/templates/pages/admin/entity/assistance.html.twig b/templates/pages/admin/entity/assistance.html.twig new file mode 100644 index 00000000000..3f8412e5464 --- /dev/null +++ b/templates/pages/admin/entity/assistance.html.twig @@ -0,0 +1,175 @@ +{# + # --------------------------------------------------------------------- + # + # GLPI - Gestionnaire Libre de Parc Informatique + # + # http://glpi-project.org + # + # @copyright 2015-2024 Teclib' and contributors. + # @copyright 2003-2014 by the INDEPNET Development Team. + # @licence https://www.gnu.org/licenses/gpl-3.0.html + # + # --------------------------------------------------------------------- + # + # LICENSE + # + # This file is part of GLPI. + # + # This program is free software: you can redistribute it and/or modify + # it under the terms of the GNU General Public License as published by + # the Free Software Foundation, either version 3 of the License, or + # (at your option) any later version. + # + # This program is distributed in the hope that it will be useful, + # but WITHOUT ANY WARRANTY; without even the implied warranty of + # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + # GNU General Public License for more details. + # + # You should have received a copy of the GNU General Public License + # along with this program. If not, see . + # + # --------------------------------------------------------------------- + #} + +{% extends "generic_show_form.html.twig" %} +{% import 'components/form/fields_macros.html.twig' as fields %} + +{% block form_fields %} + {% set inheritable_params = { + full_width: true, + entity: item.getID(), + toadd: (item.getID() > 0 ? { + (constant('Entity::CONFIG_PARENT')): __('Inheritance of the parent entity') + } : {}) + } %} + + {{ fields.smallTitle(__('Templates configuration')) }} + {{ fields.dropdownField('TicketTemplate', 'tickettemplates_id', item.fields['tickettemplates_id'], 'TicketTemplate'|itemtype_name(1), { + add_field_html: inheritance_labels['tickettemplates_id']|default(null) + } + inheritable_params) }} + {{ fields.dropdownField('ChangeTemplate', 'changetemplates_id', item.fields['changetemplates_id'], 'ChangeTemplate'|itemtype_name(1), { + add_field_html: inheritance_labels['changetemplates_id']|default(null) + } + inheritable_params) }} + {{ fields.dropdownField('ProblemTemplate', 'problemtemplates_id', item.fields['problemtemplates_id'], 'ProblemTemplate'|itemtype_name(1), { + add_field_html: inheritance_labels['problemtemplates_id']|default(null) + } + inheritable_params) }} + + {{ fields.smallTitle(__('Tickets configuration')) }} + {{ fields.dropdownField('Calendar', 'calendars_id', item.fields['calendars_id'], 'Calendar'|itemtype_name(1), { + emptylabel: __('24/7'), + add_field_html: inheritance_labels['calendars_id']|default(null) + } + inheritable_params) }} + {{ fields.dropdownArrayField('tickettype', item.fields['tickettype'], inheritable_params.toadd + { + (constant('Ticket::INCIDENT_TYPE')): __('Incident'), + (constant('Ticket::DEMAND_TYPE')): __('Request'), + }, __('Tickets default type'), { + add_field_html: inheritance_labels['tickettype']|default(null) + } + inheritable_params) }} + {{ fields.dropdownArrayField('auto_assign_mode', item.fields['auto_assign_mode'], inheritable_params.toadd + { + (constant('Entity::CONFIG_NEVER')): __('No'), + (constant('Entity::AUTO_ASSIGN_HARDWARE_CATEGORY')): __('Based on the item then the category'), + (constant('Entity::AUTO_ASSIGN_CATEGORY_HARDWARE')): __('Based on the category then the item'), + }, __('Automatic assignment of tickets, changes and problems'), { + add_field_html: inheritance_labels['auto_assign_mode']|default(null) + } + inheritable_params) }} + {{ fields.dropdownArrayField('suppliers_as_private', item.fields['suppliers_as_private'], inheritable_params.toadd + { + 0: __('No'), + 1: __('Yes'), + }, __('Mark followup added by a supplier though an email collector as private'), { + add_field_html: inheritance_labels['suppliers_as_private']|default(null) + } + inheritable_params) }} + {{ fields.dropdownArrayField('anonymize_support_agents', item.fields['anonymize_support_agents'], inheritable_params.toadd + { + (constant('Entity::ANONYMIZE_DISABLED')): __('Disabled'), + (constant('Entity::ANONYMIZE_USE_GENERIC')): __("Replace the agent and group name with a generic name"), + (constant('Entity::ANONYMIZE_USE_NICKNAME')): __("Replace the agent and group name with a customisable nickname"), + (constant('Entity::ANONYMIZE_USE_GENERIC_USER')): __("Replace the agent's name with a generic name"), + (constant('Entity::ANONYMIZE_USE_NICKNAME_USER')): __("Replace the agent's name with a customisable nickname"), + (constant('Entity::ANONYMIZE_USE_GENERIC_GROUP')): __("Replace the group's name with a generic name"), + }, __('Anonymize support agents'), { + add_field_html: inheritance_labels['anonymize_support_agents']|default(null) + } + inheritable_params) }} + {{ fields.dropdownArrayField('display_users_initials', item.fields['display_users_initials'], inheritable_params.toadd + { + 0: __('No'), + 1: __('Yes') + }, __('Display initials for users without pictures'), { + add_field_html: inheritance_labels['display_users_initials']|default(null) + } + inheritable_params) }} + {{ fields.dropdownField('Contract', 'contracts_id_default', item.fields['contracts_id_default'], __('Default contract'), { + full_width: true, + entity: item.getID(), + toadd: inheritable_params.toadd + { + (constant('Entity::CONFIG_AUTO')): __('Contract in ticket entity') + }, + condition: { + is_template: 0, + is_deleted: 0 + }|merge(call('Contract::getNotExpiredCriteria')), + add_field_html: inheritance_labels['contracts_id_default']|default(null) + }) }} + + {{ fields.smallTitle(__('Automatic closing configuration')) }} + {% if closeticket_disabled or purgeticket_disabled %} +
+ +
+ {{ closeticket_disabled ? __('Close ticket action is disabled.') : '' }} + {{ purgeticket_disabled ? __('Purge ticket action is disabled.') : '' }} +
+
+ {% endif %} + {{ fields.dropdownNumberField('autoclose_delay', item.fields['autoclose_delay'], __('Automatic closing of solved tickets after'), { + full_width: true, + min: 1, + max: 99, + unit: 'day', + toadd: inheritable_params.toadd + { + (constant('Entity::CONFIG_NEVER')): __('Never'), + 0: __('Immediately'), + }, + add_field_html: inheritance_labels['autoclose_delay']|default(null) + }) }} + {{ fields.dropdownNumberField('autopurge_delay', item.fields['autopurge_delay'], __('Automatic purge of closed tickets after'), { + full_width: true, + min: 1, + max: 3650, + unit: 'day', + toadd: inheritable_params.toadd + { + (constant('Entity::CONFIG_NEVER')): __('Never'), + }, + add_field_html: inheritance_labels['autopurge_delay']|default(null) + }) }} + + {% set inquest_types = { + 'Ticket': 'TicketSatisfaction', + 'Change': 'ChangeSatisfaction', + } %} + {% for itemtype, inquest_itemtype in inquest_types %} + {% set c_rand = random() %} + {% set config_suffix = itemtype == 'Ticket' ? '' : ('_' ~ itemtype|lower) %} + {{ fields.smallTitle(__('Configuring the satisfaction survey: %s')|format(itemtype|itemtype_name(get_plural_number()))) }} + {{ fields.dropdownArrayField('inquest_config' ~ config_suffix, item.fields['inquest_config' ~ config_suffix], inheritable_params.toadd + { + (constant('CommonITILSatisfaction::TYPE_INTERNAL')): __('Internal survey'), + (constant('CommonITILSatisfaction::TYPE_EXTERNAL')): __('External survey') + }, __('Configuring the satisfaction survey'), { + add_field_html: inheritance_labels['inquest_config' ~ config_suffix]|default(null), + rand: c_rand + } + inheritable_params) }} +
+ + {% endfor %} +{% endblock %} diff --git a/templates/pages/admin/entity/survey_config.html.twig b/templates/pages/admin/entity/survey_config.html.twig new file mode 100644 index 00000000000..5489d4b5a47 --- /dev/null +++ b/templates/pages/admin/entity/survey_config.html.twig @@ -0,0 +1,146 @@ +{# + # --------------------------------------------------------------------- + # + # GLPI - Gestionnaire Libre de Parc Informatique + # + # http://glpi-project.org + # + # @copyright 2015-2024 Teclib' and contributors. + # @copyright 2003-2014 by the INDEPNET Development Team. + # @licence https://www.gnu.org/licenses/gpl-3.0.html + # + # --------------------------------------------------------------------- + # + # LICENSE + # + # This file is part of GLPI. + # + # This program is free software: you can redistribute it and/or modify + # it under the terms of the GNU General Public License as published by + # the Free Software Foundation, either version 3 of the License, or + # (at your option) any later version. + # + # This program is distributed in the hope that it will be useful, + # but WITHOUT ANY WARRANTY; without even the implied warranty of + # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + # GNU General Public License for more details. + # + # You should have received a copy of the GNU General Public License + # along with this program. If not, see . + # + # --------------------------------------------------------------------- + #} + +{% import 'components/form/fields_macros.html.twig' as fields %} + +{{ fields.dropdownNumberField('inquest_delay' ~ config_suffix, inquest_delay, __('Create survey after'), { + full_width: true, + min: 1, + max: 90, + unit: 'day', + toadd: { + 0: __('As soon as possible'), + } +}) }} + +{{ fields.dropdownNumberField('inquest_rate' ~ config_suffix, inquest_rate, __('Rate to trigger survey'), { + full_width: true, + min: 0, + max: 100, + step: 10, + unit: '%', + toadd: { + 0: __('Disabled') + } +}) }} + +{{ fields.dropdownNumberField('inquest_duration' ~ config_suffix, inquest_duration, __('Duration of survey'), { + full_width: true, + min: 1, + max: 100, + unit: 'day', + toadd: { + 0: __('Unspecified') + } +}) }} + +{{ fields.dropdownNumberField('inquest_max_rate' ~ config_suffix, inquest_max_rate, __('Max rate'), { + full_width: true, + min: 1, + max: 10, +}) }} + +{{ fields.numberField('inquest_default_rate' ~ config_suffix, inquest_default_rate, __('Default rate'), { + full_width: true, + min: 1, + max: 10, +}) }} + +{{ fields.numberField('inquest_mandatory_comment' ~ config_suffix, inquest_mandatory_comment, __('Comment required if score is <= to'), { + full_width: true, + min: 0, + max: 10, + toadd: { + 0: __('Disabled') + } +}) }} + +{{ fields.datetimeField('max_closedate' ~ config_suffix, max_closedate, __('For %s closed after')|format(itemtype|itemtype_name(get_plural_number())), { + full_width: true, + maybeempty: true, + timestep: 1 +}) }} + +{% set tag_prefix = itemtype|upper %} +{% set ticket_only_tags = " [REQUESTTYPE_ID] [REQUESTTYPE_NAME] [TICKETTYPE_NAME] [TICKETTYPE_ID] [SLA_TTO_ID] [SLA_TTO_NAME] [SLA_TTR_ID] [SLA_TTR_NAME] [SLALEVEL_ID] [SLALEVEL_NAME]" %} +{% set tags = [ + '[' ~ tag_prefix ~ '_ID]', '[' ~ tag_prefix ~ '_NAME]', '[' ~ tag_prefix ~ '_CREATEDATE]', '[' ~ tag_prefix ~ '_SOLVEDATE]', + '[' ~ tag_prefix ~ '_PRIORITY]', '[' ~ tag_prefix ~ '_PRIORITYNAME]', '[ITILCATEGORY_ID]', '[ITILCATEGORY_NAME]', + '[SOLUTIONTYPE_ID]', '[SOLUTIONTYPE_NAME]' +]|join(' ') ~ (itemtype == 'Ticket' ? ticket_only_tags : '') %} +{{ fields.htmlField('', tags|e, __('Valid tags'), { + full_width: true, + add_field_class: 'valid_tags' +}) }} +{{ fields.textField('inquest_URL' ~ config_suffix, inquest_URL, __('URL'), { + full_width: true, +}) }} + + diff --git a/tests/functional/Glpi/DBAL/QueryFunction.php b/tests/functional/Glpi/DBAL/QueryFunction.php index fb9491ad3cc..a5a915ea0c6 100644 --- a/tests/functional/Glpi/DBAL/QueryFunction.php +++ b/tests/functional/Glpi/DBAL/QueryFunction.php @@ -100,6 +100,52 @@ public function testConcat($params, $alias, $expected) $this->string((string) \Glpi\DBAL\QueryFunction::concat($params, $alias))->isIdenticalTo($expected); } + protected function concatWSProvider() + { + return [ + [ + new QueryExpression("','"), + [ + new QueryExpression("'A'"), + new QueryExpression("'B'"), + new QueryExpression("'C'") + ], null, "CONCAT_WS(',', 'A', 'B', 'C')" + ], + [ + new QueryExpression("'-'"), + [ + new QueryExpression("'A'"), + new QueryExpression("'B'"), + new QueryExpression("'C'") + ], 'concat_alias', "CONCAT_WS('-', 'A', 'B', 'C') AS `concat_alias`" + ], + [ + new QueryExpression("','"), + [ + new QueryExpression("'A'"), + 'glpi_computers.name', + new QueryExpression("'C'") + ], null, "CONCAT_WS(',', 'A', `glpi_computers`.`name`, 'C')" + ], + [ + new QueryExpression("','"), + [ + new QueryExpression("'A'"), + 'glpi_computers.name', + new QueryExpression("'C'") + ], 'concat_alias', "CONCAT_WS(',', 'A', `glpi_computers`.`name`, 'C') AS `concat_alias`" + ], + ]; + } + + /** + * @dataProvider concatWSProvider + */ + public function testConcatWS($separator, $params, $alias, $expected) + { + $this->string((string) \Glpi\DBAL\QueryFunction::concat_ws($separator, $params, $alias))->isIdenticalTo($expected); + } + protected function ifProvider() { return [ From b1e8a4dcbb0d285f608d9e5b8827e3c3fed7f3dc Mon Sep 17 00:00:00 2001 From: Curtis Conard Date: Thu, 13 Jun 2024 10:02:43 -0400 Subject: [PATCH 2/5] show none for some unset inherited values --- src/Contract.php | 2 +- src/Entity.php | 12 ++++++------ src/Infocom.php | 2 +- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/Contract.php b/src/Contract.php index 294c43827f0..149f0ab5fc0 100644 --- a/src/Contract.php +++ b/src/Contract.php @@ -1599,7 +1599,7 @@ public static function getAlertName($val = null) return $names; } // Default value for display - $names[0] = ' '; + $names[0] = __('None'); if (isset($names[$val])) { return $names[$val]; diff --git a/src/Entity.php b/src/Entity.php index a1565eb2194..c38f79ed291 100644 --- a/src/Entity.php +++ b/src/Entity.php @@ -2515,7 +2515,7 @@ public static function getSpecificValueToDisplay($field, $values, array $options // TRANS %s is the name of the state return sprintf( __('Fill when shifting to state %s'), - Dropdown::getDropdownName('glpi_states', $sid) + Dropdown::getDropdownName(table: 'glpi_states', id: $sid, default: __('None')) ); } } @@ -2571,7 +2571,7 @@ public static function getSpecificValueToDisplay($field, $values, array $options return match ($strategy) { self::CONFIG_PARENT => __('Inheritance of the parent entity'), self::CONFIG_NEVER => __('No change of entity'), - default => Dropdown::getDropdownName('glpi_entities', $values[$field]), + default => Dropdown::getDropdownName(table: 'glpi_entities', id: $values[$field], default: __('None')), }; case 'tickettemplates_id': @@ -2579,14 +2579,14 @@ public static function getSpecificValueToDisplay($field, $values, array $options if ($strategy === self::CONFIG_PARENT) { return __('Inheritance of the parent entity'); } - return Dropdown::getDropdownName(TicketTemplate::getTable(), $values[$field]); + return Dropdown::getDropdownName(table: TicketTemplate::getTable(), id: $values[$field], default: __('None')); case 'calendars_id': $strategy = $values['calendars_strategy'] ?? $values[$field]; return match ($strategy) { self::CONFIG_PARENT => __('Inheritance of the parent entity'), self::CONFIG_NEVER => __('24/7'), - default => Dropdown::getDropdownName('glpi_calendars', $values[$field]), + default => Dropdown::getDropdownName(table: 'glpi_calendars', id: $values[$field], default: __('None')), }; case 'transfers_id': @@ -2594,7 +2594,7 @@ public static function getSpecificValueToDisplay($field, $values, array $options return match (true) { $strategy === self::CONFIG_PARENT => __('Inheritance of the parent entity'), $strategy === self::CONFIG_NEVER, $values[$field] === 0 => __('No automatic transfer'), - default => Dropdown::getDropdownName('glpi_transfers', $values[$field]), + default => Dropdown::getDropdownName(table: 'glpi_transfers', id: $values[$field], default: __('None')), }; case 'contracts_id_default': @@ -2602,7 +2602,7 @@ public static function getSpecificValueToDisplay($field, $values, array $options return match ($strategy) { self::CONFIG_PARENT => __('Inheritance of the parent entity'), self::CONFIG_AUTO => __('Contract in ticket entity'), - default => Dropdown::getDropdownName('glpi_contracts', $values[$field]), + default => Dropdown::getDropdownName(table: 'glpi_contracts', id: $values[$field], default: __('None')), }; case 'is_contact_autoupdate': diff --git a/src/Infocom.php b/src/Infocom.php index 40799d57088..6d6a3e4f74c 100644 --- a/src/Infocom.php +++ b/src/Infocom.php @@ -639,7 +639,7 @@ public static function getAlertName($val = null) return $tmp; } // Default value for display - $tmp[0] = ' '; + $tmp[0] = __('None'); if (isset($tmp[$val])) { return $tmp[$val]; From af4acf57e4d3911e5ac1d5e99ba925ed12b205e0 Mon Sep 17 00:00:00 2001 From: Curtis Conard Date: Thu, 13 Jun 2024 11:28:06 -0400 Subject: [PATCH 3/5] fix merge of to_add options --- templates/pages/admin/entity/assets.html.twig | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/templates/pages/admin/entity/assets.html.twig b/templates/pages/admin/entity/assets.html.twig index c0918c42997..c64c8f61182 100644 --- a/templates/pages/admin/entity/assets.html.twig +++ b/templates/pages/admin/entity/assets.html.twig @@ -72,9 +72,9 @@ (constant('Entity::CONFIG_NEVER')): __('No change of entity') } %} {% if item.fields['id'] > 0 %} - {% set to_add = to_add|merge({ + {% set to_add = to_add + { (constant('Entity::CONFIG_PARENT')): __('Inheritance of the parent entity') - }) %} + } %} {% endif %} {{ fields.dropdownField( 'Entity', @@ -90,13 +90,12 @@ ) }} {{ fields.largeTitle(__('Transfer')) }} - {% set to_add = { - (constant('Entity::CONFIG_NEVER')): __('No automatic transfer') - } %} + {% set to_add = {} %} {% if item.fields['id'] > 0 %} - {% set to_add = to_add|merge({ + {% set to_add = to_add + { + (constant('Entity::CONFIG_NEVER')): __('No automatic transfer'), (constant('Entity::CONFIG_PARENT')): __('Inheritance of the parent entity') - }) %} + } %} {% endif %} {{ fields.dropdownField( 'Transfer', @@ -106,7 +105,7 @@ { toadd: to_add, add_field_html: inheritance_labels['transfers_id']|default(null), - display_emptychoice: false + display_emptychoice: false, } ) }} From 6cb8bacb3172c8c0e8eac94464fa78edd2f0de3f Mon Sep 17 00:00:00 2001 From: Curtis Conard Date: Tue, 18 Jun 2024 08:51:28 -0400 Subject: [PATCH 4/5] show 2fa inherited value --- src/Entity.php | 4 +++- templates/pages/2fa/2fa_config.html.twig | 1 + 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/Entity.php b/src/Entity.php index c38f79ed291..5f4489b8928 100644 --- a/src/Entity.php +++ b/src/Entity.php @@ -1864,7 +1864,8 @@ public static function showSecurityOptions(Entity $entity) TemplateRenderer::getInstance()->display('pages/2fa/2fa_config.html.twig', [ 'canedit' => $canedit, 'item' => $entity, - 'action' => Toolbox::getItemTypeFormURL(__CLASS__) + 'action' => Toolbox::getItemTypeFormURL(__CLASS__), + 'inherited_value' => $entity->getInheritedValueBadge('2fa_enforcement_strategy', '2fa_enforcement_strategy'), ]); } @@ -2425,6 +2426,7 @@ public static function getSpecificValueToDisplay($field, $values, array $options case 'enable_custom_css': case 'suppliers_as_private': case 'display_users_initials': + case '2fa_enforcement_strategy': if ($values[$field] === self::CONFIG_PARENT) { return __('Inheritance of the parent entity'); } diff --git a/templates/pages/2fa/2fa_config.html.twig b/templates/pages/2fa/2fa_config.html.twig index d769d961d57..024ae892a11 100644 --- a/templates/pages/2fa/2fa_config.html.twig +++ b/templates/pages/2fa/2fa_config.html.twig @@ -62,6 +62,7 @@ '1': __('Yes'), }, '', { 'no_label': true, + add_field_html: inherited_value }) }} {% else %} {{ fields.dropdownYesNo('2fa_enforced', item.fields['2fa_enforced'], '', { From 689d1bb1dcfd9953e4625ec4017b002398498b4a Mon Sep 17 00:00:00 2001 From: Curtis Conard Date: Tue, 18 Jun 2024 08:52:30 -0400 Subject: [PATCH 5/5] allow no automatic transfer in root --- templates/pages/admin/entity/assets.html.twig | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/templates/pages/admin/entity/assets.html.twig b/templates/pages/admin/entity/assets.html.twig index c64c8f61182..1d5bbba350c 100644 --- a/templates/pages/admin/entity/assets.html.twig +++ b/templates/pages/admin/entity/assets.html.twig @@ -90,10 +90,11 @@ ) }} {{ fields.largeTitle(__('Transfer')) }} - {% set to_add = {} %} + {% set to_add = { + (constant('Entity::CONFIG_NEVER')): __('No automatic transfer') + } %} {% if item.fields['id'] > 0 %} {% set to_add = to_add + { - (constant('Entity::CONFIG_NEVER')): __('No automatic transfer'), (constant('Entity::CONFIG_PARENT')): __('Inheritance of the parent entity') } %} {% endif %}