From 738601c1e68eddb2802fc587c3aff519c8f2a496 Mon Sep 17 00:00:00 2001 From: Curtis Conard Date: Wed, 4 Oct 2023 10:08:14 -0400 Subject: [PATCH 01/14] fix enable maintenance cli fixes #15543 --- src/Console/Maintenance/EnableMaintenanceModeCommand.php | 2 +- src/DBmysql.php | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/Console/Maintenance/EnableMaintenanceModeCommand.php b/src/Console/Maintenance/EnableMaintenanceModeCommand.php index 47937b9fbce..cdc60275aca 100644 --- a/src/Console/Maintenance/EnableMaintenanceModeCommand.php +++ b/src/Console/Maintenance/EnableMaintenanceModeCommand.php @@ -69,7 +69,7 @@ protected function execute(InputInterface $input, OutputInterface $output) $values = [ 'maintenance_mode' => '1' ]; - if ($input->hasOption('text')) { + if ($input->hasOption('text') && $input->getOption('text') !== null) { $values['maintenance_text'] = Sanitizer::sanitize($input->getOption('text')); } $config = new Config(); diff --git a/src/DBmysql.php b/src/DBmysql.php index fed27eb58ac..77d5913c91c 100644 --- a/src/DBmysql.php +++ b/src/DBmysql.php @@ -1421,6 +1421,9 @@ public function buildUpdate($table, $params, $clauses, array $joins = []) if (!count($clauses['WHERE'])) { throw new \RuntimeException('Cannot run an UPDATE query without WHERE clause!'); } + if (!count($params)) { + throw new \RuntimeException('Cannot run an UPDATE query without parameters!'); + } $query = "UPDATE " . self::quoteName($table); From f1dbbb17ede65adaa5cd068e421d24d8f5c7586b Mon Sep 17 00:00:00 2001 From: Romain B <8530352+Rom1-B@users.noreply.github.com> Date: Wed, 4 Oct 2023 16:11:30 +0200 Subject: [PATCH 02/14] fix(planning external event): prevent errors --- src/PlanningExternalEvent.php | 2 +- src/User.php | 6 +++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/PlanningExternalEvent.php b/src/PlanningExternalEvent.php index 4c3b0d716d0..9bdaae1bb48 100644 --- a/src/PlanningExternalEvent.php +++ b/src/PlanningExternalEvent.php @@ -157,7 +157,7 @@ public function showForm($ID, array $options = []) $this->showFormHeader($options); $is_ajax = isset($options['from_planning_edit_ajax']) && $options['from_planning_edit_ajax']; - $is_rrule = strlen($this->fields['rrule']) > 0; + $is_rrule = strlen($this->fields['rrule'] ?? '') > 0; // set event for another user if ( diff --git a/src/User.php b/src/User.php index 331a1b04b52..4bb8798989f 100644 --- a/src/User.php +++ b/src/User.php @@ -4565,6 +4565,9 @@ public static function dropdown($options = []) // Make a select box with all glpi users $view_users = self::canView(); + $default = ''; + $valuesnames = []; + if (!$p['multiple']) { $user = getUserName($p['value'], 2, true); @@ -4585,11 +4588,12 @@ public static function dropdown($options = []) } } else { // get multiple values name - $valuesnames = []; foreach ($p['values'] as $value) { if (!empty($value) && ($value > 0)) { $user = getUserName($value, 2); $valuesnames[] = $user["name"]; + } else { + unset($p['values'][$value]); } } From 1735a23bcb8adfebfa065bc68a774a8e2c251de5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Anne?= Date: Wed, 4 Oct 2023 16:42:17 +0200 Subject: [PATCH 03/14] Fix LDAP unlimited timeout value (#15703) * Fix LDAP unlimited timeout value * Revert "Fix LDAP unlimited timeout value" This reverts commit 2ead8190ea6c0528e83b36b1b7fe728673c84628. * Prevent useless `ldap_set_option` call --- src/AuthLDAP.php | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/AuthLDAP.php b/src/AuthLDAP.php index 3aebcdf9ede..ca59122e3bf 100644 --- a/src/AuthLDAP.php +++ b/src/AuthLDAP.php @@ -3088,9 +3088,14 @@ public static function connectToServer( LDAP_OPT_PROTOCOL_VERSION => 3, LDAP_OPT_REFERRALS => 0, LDAP_OPT_DEREF => $deref_options, - LDAP_OPT_NETWORK_TIMEOUT => $timeout ]; + if ($timeout > 0) { + // Apply the timeout unless it is "unlimited" ("unlimited" is the default value defined in `libldap`). + // see https://linux.die.net/man/3/ldap_set_option + $ldap_options[LDAP_OPT_NETWORK_TIMEOUT] = $timeout; + } + foreach ($ldap_options as $option => $value) { if (!@ldap_set_option($ds, $option, $value)) { trigger_error( From 9921a7078236900f9e8b856644959704d305e29f Mon Sep 17 00:00:00 2001 From: Adrien Clairembault <42734840+AdrienClairembault@users.noreply.github.com> Date: Thu, 5 Oct 2023 06:44:44 +0200 Subject: [PATCH 04/14] Add helper method to access the tests root entity (#15717) * Add helper method to access the tests root entity * Use protected method instead * Fix type hint --- tests/GLPITestCase.php | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/tests/GLPITestCase.php b/tests/GLPITestCase.php index 66e1cb99fa6..939d0a70c4c 100644 --- a/tests/GLPITestCase.php +++ b/tests/GLPITestCase.php @@ -316,4 +316,16 @@ protected function getUniqueInteger() } return $this->int++; } + + /** + * Get the "_test_root_entity" entity created by the tests's bootstrap file + * + * @param bool $only_id + * + * @return Entity|int + */ + protected function getTestRootEntity(bool $only_id = false) + { + return getItemByTypeName('Entity', '_test_root_entity', $only_id); + } } From a4322acdcfa08e49b53bafb4278ce0e6e7c6946e Mon Sep 17 00:00:00 2001 From: Curtis Conard Date: Thu, 5 Oct 2023 02:18:13 -0400 Subject: [PATCH 05/14] fix more dark theme text colors fixes #15645 --- css/includes/components/_select2.scss | 4 ++++ css/legacy/includes/_inputs.scss | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/css/includes/components/_select2.scss b/css/includes/components/_select2.scss index 82163958b12..52fb9e71f57 100644 --- a/css/includes/components/_select2.scss +++ b/css/includes/components/_select2.scss @@ -55,6 +55,10 @@ } } + .select2-selection__rendered input[type="search"] { + color: $input-color; + } + &.select2-selection--single { @include font-size($input-font-size); diff --git a/css/legacy/includes/_inputs.scss b/css/legacy/includes/_inputs.scss index 9e07aa139b7..4ac343bd71b 100644 --- a/css/legacy/includes/_inputs.scss +++ b/css/legacy/includes/_inputs.scss @@ -32,7 +32,7 @@ */ textarea:not(.form-control), input:not(.submit):not(.form-control):not([type=submit]):not([type=color]):not([type=reset]):not([type=checkbox]):not([type=radio]):not(.select2-search__field):not(.numInput):not(.tox-textfield) { - color: $body-color; + color: $input-color; background-color: $input-bg; background-clip: padding-box; border: $input-border-width solid $input-border-color; From f596e7e9e382135aa4fa8d201d6152531b3c2800 Mon Sep 17 00:00:00 2001 From: Adrien Clairembault <42734840+AdrienClairembault@users.noreply.github.com> Date: Thu, 5 Oct 2023 10:31:33 +0200 Subject: [PATCH 06/14] Allow pending reason edition from new fup/task form --- src/CommonITILTask.php | 2 + src/ITILFollowup.php | 2 + src/PendingReason_Item.php | 99 ++++++- .../timeline/form_followup.html.twig | 18 +- .../timeline/pending_reasons.html.twig | 10 +- tests/functional/PendingReason.class.php | 276 ++++++++++++++++++ 6 files changed, 384 insertions(+), 23 deletions(-) diff --git a/src/CommonITILTask.php b/src/CommonITILTask.php index 9d233c6ec3e..2c695710ccf 100644 --- a/src/CommonITILTask.php +++ b/src/CommonITILTask.php @@ -634,6 +634,8 @@ public function post_addItem() NotificationEvent::raiseEvent('add_task', $this->input["_job"], $options); } + PendingReason_Item::handlePendingReasonUpdateFromNewTimelineItem($this); + // Add log entry in the ITIL object $changes = [ 0, diff --git a/src/ITILFollowup.php b/src/ITILFollowup.php index 37f036a24b0..3a161c58ced 100644 --- a/src/ITILFollowup.php +++ b/src/ITILFollowup.php @@ -284,6 +284,8 @@ public function post_addItem() NotificationEvent::raiseEvent("add_followup", $parentitem, $options); } + PendingReason_Item::handlePendingReasonUpdateFromNewTimelineItem($this); + // Add log entry in the ITILObject $changes = [ 0, diff --git a/src/PendingReason_Item.php b/src/PendingReason_Item.php index 66f0e016960..c475acc150e 100644 --- a/src/PendingReason_Item.php +++ b/src/PendingReason_Item.php @@ -205,17 +205,13 @@ public function getAutoResolvedate() } /** - * Check that the given timeline event is the lastest "pending" action for - * the given item + * Get the lastest "pending" action for the given item * * @param CommonITILObject $item - * @param CommonDBTM $timeline_item - * @return boolean + * @return CommonDBTM|false */ - public static function isLastPendingForItem( - CommonITILObject $item, - CommonDBTM $timeline_item - ): bool { + public static function getLastPendingTimelineItemDataForItem(CommonITILObject $item) + { global $DB; $task_class = $item::getTaskClass(); @@ -257,7 +253,27 @@ public static function isLastPendingForItem( $row = $data->current(); $pending_item = self::getById($row['max_id']); - return $pending_item->fields['items_id'] == $timeline_item->fields['id'] && $pending_item->fields['itemtype'] == $timeline_item::getType(); + return $pending_item; + } + + /** + * Check that the given timeline event is the lastest "pending" action for + * the given item + * + * @param CommonITILObject $item + * @param CommonDBTM $timeline_item + * @return boolean + */ + public static function isLastPendingForItem( + CommonITILObject $item, + CommonDBTM $timeline_item + ): bool { + $pending_item = self::getLastPendingTimelineItemDataForItem($item); + + return + $pending_item->fields['items_id'] == $timeline_item->fields['id'] + && $pending_item->fields['itemtype'] == $timeline_item::getType() + ; } /** @@ -323,6 +339,71 @@ public static function isLastTimelineItem(CommonDBTM $timeline_item): bool return $row['max_date_creation'] == $timeline_item->fields['date_creation']; } + /** + * User might be trying to update the active pending reason by modifying the + * pending reason data in a new timeline item form + * + * This method update the latest pending timeline item if the user has edited + * the pending details while adding a new task or followup + * + * @param CommonDBTM $new_timeline_item + * @return void + */ + public static function handlePendingReasonUpdateFromNewTimelineItem( + CommonDBTM $new_timeline_item + ): void { + $last_pending = self::getLastPendingTimelineItemDataForItem($new_timeline_item->input['_job']); + + // There is no existing pending data on previous timeline items for this ticket + // Nothing to be done here since the goal of this method is to update active pending data + if (!$last_pending) { + return; + } + + // The new timeline item is the latest pending reason + // This mean there was no active pending reason before this timeline item was added + // Nothing to be done here as we don't have any older active pending reason to update + if ( + $last_pending->fields['itemtype'] == $new_timeline_item::getType() + && $last_pending->fields['items_id'] == $new_timeline_item->getID() + ) { + return; + } + + // Pending reason was removed or is not enabled + // Nothing to update here as it was already handled in CommonITILObject::prepareInputForUpdate + if (!($new_timeline_item->input['pending'] ?? 0)) { + return; + } + + // If we reach this point, this mean a timeline item with pending information + // was added on a CommonITILObject which already had pending data + // This mean the user might be trying to update the existing pending reason data + + // Let's check if there is any real updates before going any further + $pending_updates = []; + $fields_to_check_for_updates = ['pendingreasons_id', 'followup_frequency', 'followups_before_resolution']; + foreach ($fields_to_check_for_updates as $field) { + if ( + isset($new_timeline_item->input[$field]) + && $new_timeline_item->input[$field] != $last_pending->fields[$field] + ) { + $pending_updates[$field] = $new_timeline_item->input[$field]; + } + } + + // No actual updates -> nothing to be done + if (count($pending_updates) == 0) { + return; + } + + // Update last pending item and parent + $last_pending_timeline_item = new $last_pending->fields['itemtype'](); + $last_pending_timeline_item->getFromDB($last_pending->fields['items_id']); + self::updateForItem($last_pending_timeline_item, $pending_updates); + self::updateForItem($new_timeline_item->input['_job'], $pending_updates); + } + /** * Handle edit on a "pending action" from an item the timeline * diff --git a/templates/components/itilobject/timeline/form_followup.html.twig b/templates/components/itilobject/timeline/form_followup.html.twig index cc463db0eb0..9c05d6e8a5d 100644 --- a/templates/components/itilobject/timeline/form_followup.html.twig +++ b/templates/components/itilobject/timeline/form_followup.html.twig @@ -216,7 +216,7 @@ {# Fixed min-height ensure no height increase when toggling the pending reason button, as select 2 dropdown are a bit higher than the default footer height #}