From 991d873657051a7d063057360329473adc4cecae Mon Sep 17 00:00:00 2001 From: Herafia Date: Wed, 4 Mar 2026 15:03:32 +0100 Subject: [PATCH 1/3] fix template validation in escalade plugin ticket group reassignment to resolve mandatory requester field error --- inc/history.class.php | 4 +- inc/ticket.class.php | 72 +++++++++++++++++++++++---- locales/en_GB.po | 13 +++++ locales/fr_FR.mo | Bin 5437 -> 5659 bytes locales/fr_FR.po | 15 +++++- public/js/cloneandlink_ticket.js.php | 2 +- 6 files changed, 91 insertions(+), 15 deletions(-) diff --git a/inc/history.class.php b/inc/history.class.php index 5201ff72..a75fb754 100644 --- a/inc/history.class.php +++ b/inc/history.class.php @@ -231,9 +231,9 @@ public static function getHistory($tickets_id, $full_history = false) if ($nb_histories - 1 > self::HISTORY_LIMIT && !$full_history) { echo Ajax::createModalWindow( 'full_history', - $plugin_dir . "/front/popup_histories.php?tickets_id=" . $tickets_id, + $plugin_dir . "front/popup_histories.php?tickets_id=" . $tickets_id, [ - 'title' => __s("full assignation history", "escalade"), + 'title' => __("full assignation history", "escalade"), ], ); echo "..."; diff --git a/inc/ticket.class.php b/inc/ticket.class.php index 898271ef..fa50eeae 100644 --- a/inc/ticket.class.php +++ b/inc/ticket.class.php @@ -597,7 +597,7 @@ public static function assignUserGroup(Ticket $ticket) * @param int $tickets_id the ticket to change * @param int $groups_id the group to assign * @param bool $no_redirect if true, no redirection after the action - * @return void + * @return false */ public static function climb_group($tickets_id, $groups_id, $no_redirect = false) { @@ -623,22 +623,72 @@ public static function climb_group($tickets_id, $groups_id, $no_redirect = false ), ]); $ticket = new Ticket(); - $ticket->update([ - 'id' => $tickets_id, - '_actors' => [ - 'assign' => [ - [ - 'items_id' => $groups_id, - 'itemtype' => 'Group', - ], - ], - ], + if (!$ticket->getFromDB($tickets_id)) { + if (!$no_redirect) { + Session::addMessageAfterRedirect( + __('Ticket not found', 'escalade'), + false, + ERROR, + ); + } + + return false; + } + + // Temporarily disable template checking + $original_skip_template = $_SESSION['glpi_skip_template_check'] ?? false; + $_SESSION['glpi_skip_template_check'] = true; + + $group_ticket_new = new Group_Ticket(); + $add_result = $group_ticket_new->add([ + 'tickets_id' => $tickets_id, + 'groups_id' => $groups_id, + 'type' => CommonITILActor::ASSIGN, ]); + + // Restore original template checking state + $_SESSION['glpi_skip_template_check'] = $original_skip_template; + + if ($add_result) { + $ticket->updateDateMod($tickets_id); + + if ($_SESSION['glpi_plugins']['escalade']['config']['ticket_last_status'] != self::MANAGED_BY_CORE) { + $input_status = [ + 'id' => $tickets_id, + 'status' => $_SESSION['glpi_plugins']['escalade']['config']['ticket_last_status'], + '_no_message' => true, + ]; + $ticket->updateInDB($input_status); + } + + // Remove old assigned users if configured + if ($_SESSION['glpi_plugins']['escalade']['config']['remove_group']) { + self::removeAssignUsers($ticket); + } + + Session::addMessageAfterRedirect( + sprintf(__s('Escalation to the group %s.', 'escalade'), $group->getName()), + ); + + } else { + Session::addMessageAfterRedirect( + __s('Error during escalation', 'escalade'), + false, + ERROR, + ); + return false; + } + } else { + Session::addMessageAfterRedirect( + sprintf(__s('Ticket already assigned to group %s', 'escalade'), $group->getName()), + ); } if (!$no_redirect) { Html::back(); } + + return true; } diff --git a/locales/en_GB.po b/locales/en_GB.po index feb9650f..a01cdfaa 100644 --- a/locales/en_GB.po +++ b/locales/en_GB.po @@ -231,6 +231,19 @@ msgstr "Configuration Escalade plugin" msgid "Default (not managed by plugin)" msgstr "Default (not managed by plugin)" +#: inc/ticket.class.php:629 +msgid "Ticket not found" +msgstr "Ticket not found" + +#: inc/ticket.class.php:681 +msgid "Error during escalation" +msgstr "Error during escalation" + +#: inc/ticket.class.php:688 +#, php-format +msgid "Ticket already assigned to group %s" +msgstr "Ticket already assigned to group %s" + #: hook.php:568 msgid "Group concerned by the escalation" msgstr "Group concerned by the escalation" diff --git a/locales/fr_FR.mo b/locales/fr_FR.mo index 9f4c52c265ec203bf1f3a3f4af3b579ea1c29f8e..754ad6975ad846082402b7cf7e494c115ef725fb 100644 GIT binary patch delta 1522 zcmY+^OGs2v9LMo9KGVuqrDj>j%FMTx+1P^?p+SqFmjt$GXl`arGj(Uikcc5#)g}po z$VCMOxwMHuFtR2HqE#CMqvuXq1SYlY`@3_6I?S2Ro#Vadod5s)ug{ytT2h}X@@^a2 z9{O5(UXC$G@JB9Rv|zq5)!2g;4`Ua`u^S&_8-B({EGeL45SQbAtjA+mh?lVzui<)Q zQsw~{s~C8RnqUUCV1T=uu?AOTA6DW?tinsU1aJD@!BT!dz+#-hH8|z_0n7OP3+phS zhih5iG;pzjfnKb^GuVpPumvYDh@Vg!ttv8R3$`Lbn|@U0PM|hCf?D7aYTh@v5$90% zm9RUFH{&MOHwU@cjB!+Ccd;FxpdS2&+Ihj!?8H^5iF#0}>_=@pfy%&5EXRAOOirMl ze~T+|)*t_gDbBzYEi-01K>ATTpX1<^fn^+|BHxL<7{>;j^vAyA=x*RNEXd2T!HWW-(OG*&!NtI zCA(3i9jE|%QR5CO^;dBnJ}f8yom^xXXvPH`z`6=!_?Rnvsd`6IXZ;K{;S}z~kJyG) z?4}+2P#YOW-FF|i;e+ozl*M>g%q78SZq2r zEwtDajheEg;@m|iShJh1no(0`)bxKtLGe1LyfhM=*LLvD33yG>>uB_kNkyhNLshOQ z7n>raX1xq(OsQ4jsi|I6Q_AkYjhD%E&~>bBW^eXSO6hjGQk;_=^6EjCdGu}mn9h=y z!z(7e89nKRynQ*9t{Zc0IOz^W2dxu76^eusL$PSOyKo@4H5753PqOu$qTkVZjKI}I_D&8G?uWZW65YZeZBZbezog5N!LbVZrp|)8)?W+8Ftd;W#4nV k{b$0N@w1ux{pRqoYjc@Hj5xJ}j`28b5{F(_8##!CCCYC&*m(1zr4(9he|GEl|K- zETRIO#x8t-F1|}qf0gh!|m7}-VdP`97FBxMO212P?B z4;4TYQRlIUr*R4$T&$=5I-S25(4M9k)r1+;8_|#5co}=Jj0$8P^;`uHVU}n$egbty zuAnMWMpgJdYR~_oDw8F81vu={(L|G|Q$B^->$|AK^AstLEh1~#GP+nnW!lKejG%&3 z`?S*Zd#aLP=&^>8;-2 z(1yM;*0-XcOUWuhRfWoX!AF69@KKREczPSykzkLNz0QalpMs$2FsXc;x8NhwhblYY wsNhv~Q3q3RPqpdbZ3%BwNo{M){DH)1)W4l9#r)>FYYG2(`diHZ)G!`d2gUPdS^xk5 diff --git a/locales/fr_FR.po b/locales/fr_FR.po index 6c409012..5bef2cf2 100644 --- a/locales/fr_FR.po +++ b/locales/fr_FR.po @@ -1,7 +1,7 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. -# +# # Translators: # Alexandre DELAUNAY , 2013 # alexandre delaunay , 2016 @@ -238,6 +238,19 @@ msgstr "Configuration du plugin Escalade" msgid "Default (not managed by plugin)" msgstr "Par défaut (non géré par le plugin)" +#: inc/ticket.class.php:629 +msgid "Ticket not found" +msgstr "Ticket non trouvé" + +#: inc/ticket.class.php:681 +msgid "Error during escalation" +msgstr "Erreur lors de l'escalade" + +#: inc/ticket.class.php:688 +#, php-format +msgid "Ticket already assigned to group %s" +msgstr "Ticket déjà assigné au groupe %s" + #: hook.php:568 msgid "Group concerned by the escalation" msgstr "Groupe concerné par l'escalade" diff --git a/public/js/cloneandlink_ticket.js.php b/public/js/cloneandlink_ticket.js.php index 768c3627..3b6fe548 100644 --- a/public/js/cloneandlink_ticket.js.php +++ b/public/js/cloneandlink_ticket.js.php @@ -54,7 +54,7 @@ setTimeout( function () { if ($("#cloneandlink_ticket").length > 0) { return; } var duplicate_html = ""; $("#linked_tickets-heading .accordion-button") From 2845ba3440889c8a5cf3dea358f92966c7fc7770 Mon Sep 17 00:00:00 2001 From: Herafia Date: Wed, 4 Mar 2026 15:38:20 +0100 Subject: [PATCH 2/3] correctif tests --- inc/ticket.class.php | 81 ++++++++++++++++++++++++++++---------------- 1 file changed, 52 insertions(+), 29 deletions(-) diff --git a/inc/ticket.class.php b/inc/ticket.class.php index fa50eeae..3bcb0af4 100644 --- a/inc/ticket.class.php +++ b/inc/ticket.class.php @@ -41,6 +41,11 @@ class PluginEscaladeTicket public static function pre_item_update(CommonDBTM $item) { + // If this is an escalation action, do not interfere + if (isset($item->input['_escalation_action']) && $item->input['_escalation_action']) { + return $item; + } + // Only process escalation logic if we're dealing with actor assignments // Don't interfere with other updates like solutions, status changes, etc. if (!isset($item->input['_actors']) && !isset($item->input['_itil_assign']) && !isset($item->input['actortype'])) { @@ -612,7 +617,7 @@ public static function climb_group($tickets_id, $groups_id, $no_redirect = false 'type' => CommonITILActor::ASSIGN, ]; if (!$group_ticket->find($condition)) { - $ticket_group = new Group_Ticket(); + // Add task for escalation history PluginEscaladeTaskmanager::setTicketTask([ 'tickets_id' => $tickets_id, 'is_private' => true, @@ -622,65 +627,83 @@ public static function climb_group($tickets_id, $groups_id, $no_redirect = false $group->getName() . '


', ), ]); + $ticket = new Ticket(); if (!$ticket->getFromDB($tickets_id)) { if (!$no_redirect) { Session::addMessageAfterRedirect( - __('Ticket not found', 'escalade'), + __s('Error: ticket not found', 'escalade'), false, - ERROR, + ERROR ); } - return false; } - // Temporarily disable template checking - $original_skip_template = $_SESSION['glpi_skip_template_check'] ?? false; - $_SESSION['glpi_skip_template_check'] = true; + // Prepare input with all existing ticket data to satisfy mandatory field validation + $input = $ticket->fields; + $input['id'] = $tickets_id; - $group_ticket_new = new Group_Ticket(); - $add_result = $group_ticket_new->add([ + // Add existing requesters to pass mandatory field validation + $ticket_users = new Ticket_User(); + $existing_requesters = $ticket_users->find([ 'tickets_id' => $tickets_id, - 'groups_id' => $groups_id, - 'type' => CommonITILActor::ASSIGN, + 'type' => CommonITILActor::REQUESTER, ]); + if (!empty($existing_requesters)) { + $input['_users_id_requester'] = array_column($existing_requesters, 'users_id'); + } - // Restore original template checking state - $_SESSION['glpi_skip_template_check'] = $original_skip_template; + // Add existing requester groups + $existing_requester_groups = $group_ticket->find([ + 'tickets_id' => $tickets_id, + 'type' => CommonITILActor::REQUESTER, + ]); + if (!empty($existing_requester_groups)) { + $input['_groups_id_requester'] = array_column($existing_requester_groups, 'groups_id'); + } - if ($add_result) { - $ticket->updateDateMod($tickets_id); + // Add the new group assignment + $input['_actors'] = [ + 'assign' => [ + [ + 'items_id' => $groups_id, + 'itemtype' => 'Group', + ], + ], + ]; - if ($_SESSION['glpi_plugins']['escalade']['config']['ticket_last_status'] != self::MANAGED_BY_CORE) { - $input_status = [ - 'id' => $tickets_id, - 'status' => $_SESSION['glpi_plugins']['escalade']['config']['ticket_last_status'], - '_no_message' => true, - ]; - $ticket->updateInDB($input_status); - } + // Ensure content is not empty for template validation + if (empty($input['content'])) { + $input['content'] = 'Content preserved during escalation'; + } - // Remove old assigned users if configured - if ($_SESSION['glpi_plugins']['escalade']['config']['remove_group']) { - self::removeAssignUsers($ticket); - } + // Mark as escalation action and disable notifications during update + $input['_escalation_action'] = true; + $input['_disablenotif'] = true; + + // Use ticket->update() to trigger rules while avoiding validation issues + $result = $ticket->update($input); + if ($result) { Session::addMessageAfterRedirect( sprintf(__s('Escalation to the group %s.', 'escalade'), $group->getName()), + false, + INFO ); - } else { Session::addMessageAfterRedirect( __s('Error during escalation', 'escalade'), false, - ERROR, + ERROR ); return false; } } else { Session::addMessageAfterRedirect( sprintf(__s('Ticket already assigned to group %s', 'escalade'), $group->getName()), + false, + INFO ); } From c37d888d57bf53d2616589f8bd1c0122b39565c0 Mon Sep 17 00:00:00 2001 From: Herafia Date: Wed, 4 Mar 2026 16:11:41 +0100 Subject: [PATCH 3/3] cs --- inc/ticket.class.php | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/inc/ticket.class.php b/inc/ticket.class.php index 3bcb0af4..bdedb43e 100644 --- a/inc/ticket.class.php +++ b/inc/ticket.class.php @@ -602,7 +602,7 @@ public static function assignUserGroup(Ticket $ticket) * @param int $tickets_id the ticket to change * @param int $groups_id the group to assign * @param bool $no_redirect if true, no redirection after the action - * @return false + * @return bool true on success, false on error */ public static function climb_group($tickets_id, $groups_id, $no_redirect = false) { @@ -634,9 +634,10 @@ public static function climb_group($tickets_id, $groups_id, $no_redirect = false Session::addMessageAfterRedirect( __s('Error: ticket not found', 'escalade'), false, - ERROR + ERROR, ); } + return false; } @@ -688,22 +689,18 @@ public static function climb_group($tickets_id, $groups_id, $no_redirect = false if ($result) { Session::addMessageAfterRedirect( sprintf(__s('Escalation to the group %s.', 'escalade'), $group->getName()), - false, - INFO ); } else { Session::addMessageAfterRedirect( __s('Error during escalation', 'escalade'), false, - ERROR + ERROR, ); return false; } } else { Session::addMessageAfterRedirect( sprintf(__s('Ticket already assigned to group %s', 'escalade'), $group->getName()), - false, - INFO ); }