From ae28dfaf8c9e56d7f9cec430ca51ad5ca6452468 Mon Sep 17 00:00:00 2001 From: Thierry Bugier Date: Wed, 29 May 2024 09:46:51 +0200 Subject: [PATCH 1/8] fix ticket list ignoring validation role --- src/Ticket.php | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/Ticket.php b/src/Ticket.php index de5df696077..1ea0be7f375 100644 --- a/src/Ticket.php +++ b/src/Ticket.php @@ -5502,6 +5502,11 @@ public static function showListForItem(CommonDBTM $item, $withtemplate = 0) 'glpi_tickets_users.tickets_id' => new \QueryExpression('glpi_tickets.id'), 'glpi_tickets_users.users_id' => Session::getLoginUserID() ] + ], [ + 'AND' => [ + 'glpi_ticketvalidations.tickets_id' => new \QueryExpression('glpi_tickets.id'), + 'glpi_ticketvalidations.users_id_validate' => Session::getLoginUserID() + ] ] ]; if (count($_SESSION['glpigroups'])) { @@ -5786,6 +5791,13 @@ public static function getCommonCriteria() ] ]; + $criteria['LEFT JOIN']['glpi_ticketvalidations'] = [ + 'ON' => [ + self::getTable() => 'id', + 'glpi_ticketvalidations' => 'tickets_id' + ] + ]; + return $criteria; } From 1e3ab0e993214bc304c97fe8007ad693d989965e Mon Sep 17 00:00:00 2001 From: Thierry Bugier Date: Mon, 10 Jun 2024 14:58:54 +0200 Subject: [PATCH 2/8] Improve ticket list for item, refactor for unit tests --- src/Ticket.php | 256 ++++++++++++++++++++++++++++++------------------- 1 file changed, 156 insertions(+), 100 deletions(-) diff --git a/src/Ticket.php b/src/Ticket.php index 1ea0be7f375..87744ed2870 100644 --- a/src/Ticket.php +++ b/src/Ticket.php @@ -5395,6 +5395,7 @@ public static function showListForItem(CommonDBTM $item, $withtemplate = 0) self::$rightname, [self::READALL, self::READMY, self::READASSIGN, CREATE] ) + && !Session::haveRightsOr(TicketValidation::$rightname, TicketValidation::getValidateRights()) ) { return false; } @@ -5404,65 +5405,23 @@ public static function showListForItem(CommonDBTM $item, $withtemplate = 0) } $criteria = self::getCommonCriteria(); - $restrict = []; - $options = [ - 'criteria' => [], - 'reset' => 'reset', - ]; + $restrict = self::getListForItemRestrict($item); + $criteria['WHERE'] = $restrict + getEntitiesRestrictCriteria(self::getTable()); + $criteria['WHERE']['glpi_tickets.is_deleted'] = 0; + $criteria['LIMIT'] = (int)$_SESSION['glpilist_limit']; switch (get_class($item)) { - case User::class: - $restrict['glpi_tickets_users.users_id'] = $item->getID(); - $restrict['glpi_tickets_users.type'] = CommonITILActor::REQUESTER; - - $options['criteria'][0]['field'] = 4; // status - $options['criteria'][0]['searchtype'] = 'equals'; - $options['criteria'][0]['value'] = $item->getID(); - $options['criteria'][0]['link'] = 'AND'; - break; - case SLA::class: - $restrict[] = [ - 'OR' => [ - 'slas_id_tto' => $item->getID(), - 'slas_id_ttr' => $item->getID() - ] - ]; $criteria['ORDERBY'] = 'glpi_tickets.time_to_resolve DESC'; - - $options['criteria'][0]['field'] = 30; - $options['criteria'][0]['searchtype'] = 'equals'; - $options['criteria'][0]['value'] = $item->getID(); - $options['criteria'][0]['link'] = 'AND'; break; case OLA::class: - $restrict[] = [ - 'OR' => [ - 'olas_id_tto' => $item->getID(), - 'olas_id_ttr' => $item->getID() - ] - ]; $criteria['ORDERBY'] = 'glpi_tickets.internal_time_to_resolve DESC'; - - $options['criteria'][0]['field'] = 30; - $options['criteria'][0]['searchtype'] = 'equals'; - $options['criteria'][0]['value'] = $item->getID(); - $options['criteria'][0]['link'] = 'AND'; - break; - - case Supplier::class: - $restrict['glpi_suppliers_tickets.suppliers_id'] = $item->getID(); - $restrict['glpi_suppliers_tickets.type'] = CommonITILActor::ASSIGN; - - $options['criteria'][0]['field'] = 6; - $options['criteria'][0]['searchtype'] = 'equals'; - $options['criteria'][0]['value'] = $item->getID(); - $options['criteria'][0]['link'] = 'AND'; break; case Group::class: - // Mini search engine + // Mini search engine + /** @var Group $item */ if ($item->haveChildren()) { $tree = Session::getSavedOption(__CLASS__, 'tree', 0); echo ""; @@ -5479,61 +5438,10 @@ public static function showListForItem(CommonDBTM $item, $withtemplate = 0) $tree = 0; } echo "
"; - - $restrict['glpi_groups_tickets.groups_id'] = ($tree ? getSonsOf('glpi_groups', $item->getID()) : $item->getID()); - $restrict['glpi_groups_tickets.type'] = CommonITILActor::REQUESTER; - - $options['criteria'][0]['field'] = 71; - $options['criteria'][0]['searchtype'] = ($tree ? 'under' : 'equals'); - $options['criteria'][0]['value'] = $item->getID(); - $options['criteria'][0]['link'] = 'AND'; - break; - - default: - $restrict['glpi_items_tickets.items_id'] = $item->getID(); - $restrict['glpi_items_tickets.itemtype'] = $item->getType(); - - // you can only see your tickets - if (!Session::haveRight(self::$rightname, self::READALL)) { - $or = [ - 'glpi_tickets.users_id_recipient' => Session::getLoginUserID(), - [ - 'AND' => [ - 'glpi_tickets_users.tickets_id' => new \QueryExpression('glpi_tickets.id'), - 'glpi_tickets_users.users_id' => Session::getLoginUserID() - ] - ], [ - 'AND' => [ - 'glpi_ticketvalidations.tickets_id' => new \QueryExpression('glpi_tickets.id'), - 'glpi_ticketvalidations.users_id_validate' => Session::getLoginUserID() - ] - ] - ]; - if (count($_SESSION['glpigroups'])) { - $or['glpi_groups_tickets.groups_id'] = $_SESSION['glpigroups']; - } - $restrict[] = ['OR' => $or]; - } - - $options['criteria'][0]['field'] = 12; - $options['criteria'][0]['searchtype'] = 'equals'; - $options['criteria'][0]['value'] = 'all'; - $options['criteria'][0]['link'] = 'AND'; - - $options['metacriteria'][0]['itemtype'] = $item->getType(); - $options['metacriteria'][0]['field'] = Search::getOptionNumber( - $item->getType(), - 'id' - ); - $options['metacriteria'][0]['searchtype'] = 'equals'; - $options['metacriteria'][0]['value'] = $item->getID(); - $options['metacriteria'][0]['link'] = 'AND'; + /** @var CommonDBTM $item */ break; } - $criteria['WHERE'] = $restrict + getEntitiesRestrictCriteria(self::getTable()); - $criteria['WHERE']['glpi_tickets.is_deleted'] = 0; - $criteria['LIMIT'] = (int)$_SESSION['glpilist_limit']; $iterator = $DB->request($criteria); $number = count($iterator); @@ -5595,6 +5503,7 @@ public static function showListForItem(CommonDBTM $item, $withtemplate = 0) ) ); + $options = self::getListForItemSearchOptionsCriteria($item); echo ""; $title = sprintf(_n('Last %d ticket', 'Last %d tickets', $number), $number); $link = "getID(); + $restrict['glpi_tickets_users.type'] = CommonITILActor::REQUESTER; + break; + + case SLA::class: + $restrict[] = [ + 'OR' => [ + 'slas_id_tto' => $item->getID(), + 'slas_id_ttr' => $item->getID() + ] + ]; + break; + + case OLA::class: + $restrict[] = [ + 'OR' => [ + 'olas_id_tto' => $item->getID(), + 'olas_id_ttr' => $item->getID() + ] + ]; + break; + + case Supplier::class: + $restrict['glpi_suppliers_tickets.suppliers_id'] = $item->getID(); + $restrict['glpi_suppliers_tickets.type'] = CommonITILActor::ASSIGN; + break; + + case Group::class: + /** @var Group $item */ + if ($item->haveChildren()) { + $tree = Session::getSavedOption(__CLASS__, 'tree', 0); + } else { + $tree = 0; + } + $restrict['glpi_groups_tickets.groups_id'] = ($tree ? getSonsOf('glpi_groups', $item->getID()) : $item->getID()); + $restrict['glpi_groups_tickets.type'] = CommonITILActor::REQUESTER; + /** @var CommonDBTM $item */ + break; + + default: + $restrict['glpi_items_tickets.items_id'] = $item->getID(); + $restrict['glpi_items_tickets.itemtype'] = $item->getType(); + // you can only see your tickets + if (!Session::haveRight(self::$rightname, self::READALL)) { + $or = [ + 'glpi_tickets.users_id_recipient' => Session::getLoginUserID(), + [ + 'AND' => [ + 'glpi_tickets_users.tickets_id' => new \QueryExpression('glpi_tickets.id'), + 'glpi_tickets_users.users_id' => Session::getLoginUserID() + ] + ] + ]; + if (Session::haveRightsOr(TicketValidation::$rightname, [TicketValidation::VALIDATEINCIDENT, TicketValidation::VALIDATEREQUEST])) { + $or[] = [ + 'AND' => [ + 'glpi_ticketvalidations.tickets_id' => new \QueryExpression('glpi_tickets.id'), + 'glpi_ticketvalidations.users_id_validate' => Session::getLoginUserID(), + ] + ]; + } + if (count($_SESSION['glpigroups'])) { + $or['glpi_groups_tickets.groups_id'] = $_SESSION['glpigroups']; + } + $restrict[] = ['OR' => $or]; + } + } + + return $restrict; + } + + public static function getListForItemSearchOptionsCriteria(CommonDBTM $item) + { + $options = [ + 'criteria' => [], + 'reset' => 'reset', + ]; + + switch (get_class($item)) { + case User::class: + $options['criteria'][0]['field'] = 4; // status + $options['criteria'][0]['searchtype'] = 'equals'; + $options['criteria'][0]['value'] = $item->getID(); + $options['criteria'][0]['link'] = 'AND'; + break; + + case SLA::class: + $options['criteria'][0]['field'] = 30; + $options['criteria'][0]['searchtype'] = 'equals'; + $options['criteria'][0]['value'] = $item->getID(); + $options['criteria'][0]['link'] = 'AND'; + break; + + case OLA::class: + $options['criteria'][0]['field'] = 30; + $options['criteria'][0]['searchtype'] = 'equals'; + $options['criteria'][0]['value'] = $item->getID(); + $options['criteria'][0]['link'] = 'AND'; + break; + + case Supplier::class: + $options['criteria'][0]['field'] = 6; + $options['criteria'][0]['searchtype'] = 'equals'; + $options['criteria'][0]['value'] = $item->getID(); + $options['criteria'][0]['link'] = 'AND'; + break; + + case Group::class: + /** @var Group $item */ + if ($item->haveChildren()) { + $tree = Session::getSavedOption(__CLASS__, 'tree', 0); + } else { + $tree = 0; + } + $options['criteria'][0]['field'] = 71; + $options['criteria'][0]['searchtype'] = ($tree ? 'under' : 'equals'); + $options['criteria'][0]['value'] = $item->getID(); + $options['criteria'][0]['link'] = 'AND'; + /** @var CommonDBTM $item */ + break; + + default: + $options['criteria'][0]['field'] = 12; + $options['criteria'][0]['searchtype'] = 'equals'; + $options['criteria'][0]['value'] = 'all'; + $options['criteria'][0]['link'] = 'AND'; + + $options['metacriteria'][0]['itemtype'] = $item->getType(); + $options['metacriteria'][0]['field'] = Search::getOptionNumber( + $item->getType(), + 'id' + ); + $options['metacriteria'][0]['searchtype'] = 'equals'; + $options['metacriteria'][0]['value'] = $item->getID(); + $options['metacriteria'][0]['link'] = 'AND'; + break; + } + + return $options; + } } From dc107565adf8c2ec4b7a8a5c8f3a6c3f89978b39 Mon Sep 17 00:00:00 2001 From: Thierry Bugier Date: Mon, 10 Jun 2024 15:00:33 +0200 Subject: [PATCH 3/8] test ticket list for item --- tests/functional/Ticket.php | 67 +++++++++++++++++++++++++++++++++++++ 1 file changed, 67 insertions(+) diff --git a/tests/functional/Ticket.php b/tests/functional/Ticket.php index 54501692afe..0b54e2d9df6 100644 --- a/tests/functional/Ticket.php +++ b/tests/functional/Ticket.php @@ -54,6 +54,7 @@ use Ticket_User; use TicketValidation; use User; +use Session; /* Test for inc/ticket.class.php */ @@ -6984,4 +6985,70 @@ public function testRestrictedDropdownValues() $this->array($values['results'])->size->isGreaterThan(1); $this->boolean($fn_dropdown_has_id($values['results'], $not_my_tickets_id))->isTrue(); } + + public function testGetCommonCriteria() + { + global $DB; + + $this->login('tech', 'tech'); + + $item = new \Project(); + $item->add([ + 'name' => $this->getUniqueString(), + ]); + $this->boolean($item->isNewItem())->isFalse(); + + // Find tickets already in the entity + $request = \Ticket::getCommonCriteria(); + $request['WHERE'] = \Ticket::getListForItemRestrict($item); + $request['WHERE'] = $request['WHERE'] + getEntitiesRestrictCriteria(\Ticket::getTable()); + $result = $DB->request($request); + $existing_tickets = $result->count(); + + // Create a ticket with no actor and a valdiator + $ticket = new \Ticket(); + $ticket->add([ + 'name' => __FUNCTION__, + 'content' => __FUNCTION__, + 'entities_id' => $this->getTestRootEntity(true), + 'users_id_recipient' => User::getIdByName('tech'), + ]); + $this->boolean($ticket->isNewItem())->isFalse(); + + $item_ticket = new \Item_Ticket(); + $item_ticket->add([ + 'tickets_id' => $ticket->getID(), + 'itemtype' => $item->getType(), + 'items_id' => $item->getID(), + ]); + $this->boolean($item_ticket->isNewItem())->isFalse(); + + $user = new \Ticket_User(); + $users = $user->find([ + 'tickets_id' => $ticket->getID(), + ]); + $this->integer(count($users))->IsEqualTo(0); + + $this->login('post-only', 'postonly'); + $_SESSION['glpiactiveprofile'][\TicketValidation::$rightname] = \TicketValidation::VALIDATEINCIDENT + \TicketValidation::VALIDATEREQUEST; + + // Check the ticket is not found + $request['WHERE'] = \Ticket::getListForItemRestrict($item); + $request['WHERE'] = $request['WHERE'] + getEntitiesRestrictCriteria(\Ticket::getTable()); + $result = $DB->request($request); + $this->integer($result->count())->isEqualTo($existing_tickets); + + $ticket_valdiation = new TicketValidation(); + $ticket_valdiation->add([ + 'tickets_id' => $ticket->getID(), + 'entities_id' => $ticket->fields['entities_id'], + 'users_id_validate' => Session::getLoginUserID(), + 'timeline_position' => 1, + ]); + $this->boolean($ticket_valdiation->isNewItem())->isFalse(); + + // Check the ticket under valdiation is found + $result = $DB->request($request); + $this->integer($result->count())->isEqualTo($existing_tickets + 1); + } } From ada530be6cb6627647948690d3be808608d25141 Mon Sep 17 00:00:00 2001 From: btry Date: Wed, 26 Jun 2024 09:38:16 +0200 Subject: [PATCH 4/8] Update src/Ticket.php MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Cédric Anne --- src/Ticket.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Ticket.php b/src/Ticket.php index 87744ed2870..02a2014a292 100644 --- a/src/Ticket.php +++ b/src/Ticket.php @@ -7076,7 +7076,7 @@ public static function getListForItemRestrict(CommonDBTM $item) return $restrict; } - public static function getListForItemSearchOptionsCriteria(CommonDBTM $item) + private static function getListForItemSearchOptionsCriteria(CommonDBTM $item): array { $options = [ 'criteria' => [], From c4691c19c685ad81482635d0952ac5ec180c9783 Mon Sep 17 00:00:00 2001 From: btry Date: Wed, 26 Jun 2024 09:39:37 +0200 Subject: [PATCH 5/8] Update src/Ticket.php MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Cédric Anne --- src/Ticket.php | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/Ticket.php b/src/Ticket.php index 02a2014a292..ae328f4f3c3 100644 --- a/src/Ticket.php +++ b/src/Ticket.php @@ -7092,12 +7092,6 @@ private static function getListForItemSearchOptionsCriteria(CommonDBTM $item): a break; case SLA::class: - $options['criteria'][0]['field'] = 30; - $options['criteria'][0]['searchtype'] = 'equals'; - $options['criteria'][0]['value'] = $item->getID(); - $options['criteria'][0]['link'] = 'AND'; - break; - case OLA::class: $options['criteria'][0]['field'] = 30; $options['criteria'][0]['searchtype'] = 'equals'; From c26f3d4b584719a00dacba4193631342717c25a2 Mon Sep 17 00:00:00 2001 From: btry Date: Wed, 26 Jun 2024 09:40:47 +0200 Subject: [PATCH 6/8] Update tests/functional/Ticket.php MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Cédric Anne --- tests/functional/Ticket.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/functional/Ticket.php b/tests/functional/Ticket.php index 0b54e2d9df6..78b7ffb0c1c 100644 --- a/tests/functional/Ticket.php +++ b/tests/functional/Ticket.php @@ -7011,7 +7011,7 @@ public function testGetCommonCriteria() 'name' => __FUNCTION__, 'content' => __FUNCTION__, 'entities_id' => $this->getTestRootEntity(true), - 'users_id_recipient' => User::getIdByName('tech'), + 'users_id_recipient' => getItemByTypeName(User::class, 'tech', true), ]); $this->boolean($ticket->isNewItem())->isFalse(); From 913e1cbd1a93557d9f0c1acaf7b3dc26423d28fa Mon Sep 17 00:00:00 2001 From: btry Date: Wed, 26 Jun 2024 09:41:45 +0200 Subject: [PATCH 7/8] Update tests/functional/Ticket.php MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Cédric Anne --- tests/functional/Ticket.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/functional/Ticket.php b/tests/functional/Ticket.php index 78b7ffb0c1c..e5a56966866 100644 --- a/tests/functional/Ticket.php +++ b/tests/functional/Ticket.php @@ -7000,7 +7000,7 @@ public function testGetCommonCriteria() // Find tickets already in the entity $request = \Ticket::getCommonCriteria(); - $request['WHERE'] = \Ticket::getListForItemRestrict($item); + $request['WHERE'] = $this->callPrivateMethod(new \Ticket(), 'getListForItemRestrict', $item); $request['WHERE'] = $request['WHERE'] + getEntitiesRestrictCriteria(\Ticket::getTable()); $result = $DB->request($request); $existing_tickets = $result->count(); From 25922dc36a08f3fee52de87675e49dc9d9315757 Mon Sep 17 00:00:00 2001 From: btry Date: Wed, 26 Jun 2024 09:41:58 +0200 Subject: [PATCH 8/8] Update tests/functional/Ticket.php MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Cédric Anne --- tests/functional/Ticket.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/functional/Ticket.php b/tests/functional/Ticket.php index e5a56966866..271445f623e 100644 --- a/tests/functional/Ticket.php +++ b/tests/functional/Ticket.php @@ -7033,7 +7033,7 @@ public function testGetCommonCriteria() $_SESSION['glpiactiveprofile'][\TicketValidation::$rightname] = \TicketValidation::VALIDATEINCIDENT + \TicketValidation::VALIDATEREQUEST; // Check the ticket is not found - $request['WHERE'] = \Ticket::getListForItemRestrict($item); + $request['WHERE'] = $this->callPrivateMethod(new \Ticket(), 'getListForItemRestrict', $item); $request['WHERE'] = $request['WHERE'] + getEntitiesRestrictCriteria(\Ticket::getTable()); $result = $DB->request($request); $this->integer($result->count())->isEqualTo($existing_tickets);