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