Skip to content

Add/dashboard report tickets by group and status - #25146

Open
Herafia wants to merge 9 commits into
glpi-project:mainfrom
Herafia:add/dashboard-report-ticketsByGroupAndStatus
Open

Add/dashboard report tickets by group and status#25146
Herafia wants to merge 9 commits into
glpi-project:mainfrom
Herafia:add/dashboard-report-ticketsByGroupAndStatus

Conversation

@Herafia

@Herafia Herafia commented Aug 13, 2026

Copy link
Copy Markdown
Contributor

Checklist before requesting a review

Please delete options that are not relevant.

  • I have read the CONTRIBUTING document.
  • I have performed a self-review of my code.
  • I have added tests that prove my fix is effective or that my feature works.
  • This change requires a documentation update.

Description

plugins/mreporting/inc/helpdesk.class.php
reportHgbarTicketNumberByService l.475

Screenshots (if appropriate):

image

@Herafia Herafia self-assigned this Aug 13, 2026
@Herafia
Herafia changed the base branch from 11.0/bugfixes to main August 13, 2026 14:05
@Herafia
Herafia marked this pull request as draft August 13, 2026 14:52
@semgrep-code-glpi-alex-test

Copy link
Copy Markdown

Semgrep found 1 tainted-user-input-in-php-script finding:

  • src/Glpi/Security/SessionTracker.php

Untrusted input could be used to tamper with a web page rendering, which can lead to a Cross-site scripting (XSS) vulnerability. XSS vulnerabilities occur when untrusted input executes malicious JavaScript code, leading to issues such as account compromise and sensitive information leakage. To prevent this vulnerability, validate the user input, perform contextual output encoding or sanitize the input. In PHP you can encode or sanitize user input with htmlspecialchars or use automatic context-aware escaping with a template engine such as Latte.

View Dataflow Graph
flowchart LR
    classDef invis fill:white, stroke: none
    classDef default fill:#e7f5ff, color:#1c7fd6, stroke: none

    subgraph File0["<b>src/Glpi/Security/SessionTracker.php</b>"]
        direction LR
        %% Source

        subgraph Source
            direction LR

            v0["<a href=https://github.com/glpi-project/glpi/blob/7f742b2c8429cd964a1654529334ab1fbf0efe88/src/Glpi/Security/SessionTracker.php#L697 target=_blank style='text-decoration:none; color:#1c7fd6'>[Line: 697] $_GET</a>"]
        end
        %% Intermediate

        subgraph Traces0[Traces]
            direction TB

            v2["<a href=https://github.com/glpi-project/glpi/blob/7f742b2c8429cd964a1654529334ab1fbf0efe88/src/Glpi/Security/SessionTracker.php#L697 target=_blank style='text-decoration:none; color:#1c7fd6'>[Line: 697] $start</a>"]

            v3["<a href=https://github.com/glpi-project/glpi/blob/7f742b2c8429cd964a1654529334ab1fbf0efe88/src/Glpi/Security/SessionTracker.php#L707 target=_blank style='text-decoration:none; color:#1c7fd6'>[Line: 707] $this-&gt;getSessions</a>"]

            v4["<a href=https://github.com/glpi-project/glpi/blob/7f742b2c8429cd964a1654529334ab1fbf0efe88/src/Glpi/Security/SessionTracker.php#L533 target=_blank style='text-decoration:none; color:#1c7fd6'>[Line: 533] $start</a>"]

            v5["<a href=https://github.com/glpi-project/glpi/blob/7f742b2c8429cd964a1654529334ab1fbf0efe88/src/Glpi/Security/SessionTracker.php#L543 target=_blank style='text-decoration:none; color:#1c7fd6'>[Line: 543] $it</a>"]

            v6["<a href=https://github.com/glpi-project/glpi/blob/7f742b2c8429cd964a1654529334ab1fbf0efe88/src/Glpi/Security/SessionTracker.php#L571 target=_blank style='text-decoration:none; color:#1c7fd6'>[Line: 571] as</a>"]

            v7["<a href=https://github.com/glpi-project/glpi/blob/7f742b2c8429cd964a1654529334ab1fbf0efe88/src/Glpi/Security/SessionTracker.php#L571 target=_blank style='text-decoration:none; color:#1c7fd6'>[Line: 571] $data</a>"]
        end
            v2 --> v3
            v3 --> v4
            v4 --> v5
            v5 --> v6
            v6 --> v7
        %% Sink

        subgraph Sink
            direction LR

            v1["<a href=https://github.com/glpi-project/glpi/blob/7f742b2c8429cd964a1654529334ab1fbf0efe88/src/Glpi/Security/SessionTracker.php#L645 target=_blank style='text-decoration:none; color:#1c7fd6'>[Line: 645] htmlescape(sprintf(__(&apos;Expires at %s&apos;), $data[&apos;date_expiration&apos;]))</a>"]
        end
    end
    %% Class Assignment
    Source:::invis
    Sink:::invis

    Traces0:::invis
    File0:::invis

    %% Connections

    Source --> Traces0
    Traces0 --> Sink

Loading

Comment thread src/Glpi/Dashboard/Provider.php Outdated
Comment thread tests/functional/Glpi/Dashboard/ProviderTest.php Outdated
@Herafia
Herafia requested review from Rom1-B and stonebuzz August 14, 2026 14:52
Comment thread src/Glpi/Dashboard/Provider.php Outdated
@Herafia
Herafia force-pushed the add/dashboard-report-ticketsByGroupAndStatus branch from ecd3772 to 229df2d Compare August 17, 2026 12:14
@Herafia
Herafia marked this pull request as ready for review August 17, 2026 12:20
@Herafia
Herafia requested a review from Rom1-B August 18, 2026 07:36
Comment thread src/Glpi/Dashboard/Provider.php
Comment thread src/Glpi/Dashboard/Provider.php Outdated
Comment thread src/Glpi/Dashboard/Provider.php Outdated
Comment thread src/Glpi/Dashboard/Grid.php Outdated
@Herafia
Herafia requested a review from stonebuzz August 18, 2026 14:40
Comment thread src/Glpi/Dashboard/Grid.php Outdated
'widgettype' => ['hBars', 'stackedHBars'],
'itemtype' => "\\Ticket",
'group' => __('Assistance'),
'label' => __("Number of opened and closed tickets by group"),

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
'label' => __("Number of opened and closed tickets by group"),
'label' => __("Number of opened and solved tickets by group"),

From the code, the "closed tickets" part is actually solved + closed tickets: $closed_statuses = implode(',', [Ticket::SOLVED, Ticket::CLOSED]);.

With that in mind, I think "solved" would be a more precise label here.

Comment thread src/Glpi/Dashboard/Provider.php Outdated
Comment on lines +1206 to +1207
new QueryExpression("COUNT(CASE WHEN $ticket_table.status IN ($opened_statuses) THEN $ticket_table.id END) AS opened"),
new QueryExpression("COUNT(CASE WHEN $ticket_table.status IN ($closed_statuses) THEN $ticket_table.id END) AS closed"),

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
new QueryExpression("COUNT(CASE WHEN $ticket_table.status IN ($opened_statuses) THEN $ticket_table.id END) AS opened"),
new QueryExpression("COUNT(CASE WHEN $ticket_table.status IN ($closed_statuses) THEN $ticket_table.id END) AS closed"),
new QueryExpression("COUNT(DISTINCT CASE WHEN $ticket_table.status IN ($opened_statuses) THEN $ticket_table.id END) AS opened"),
new QueryExpression("COUNT(DISTINCT CASE WHEN $ticket_table.status IN ($closed_statuses) THEN $ticket_table.id END) AS closed"),

I have some duplicated results when testing, adding UNIQUE seems to fix them.

For example, in a database with only one ticket attached to two groups and using these groups as a filter I would get 2 results:
Image

Image

],
],
],
'WHERE' => [

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe we need something to keep only the groups requested by the filters?

If I filter for "Group A", all groups still shows:

Image

Comment on lines +1244 to +1245
['name' => __('Opened'), 'data' => []],
['name' => __('Closed'), 'data' => []],

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure how to fix it but if you only have one type of tickets, the numbers overlap and become unreadable:

Image

$group_ticket_table = Group_Ticket::getTable();
$group_table = Group::getTable();

$opened_statuses = implode(',', [Ticket::INCOMING, Ticket::ASSIGNED, Ticket::PLANNED, Ticket::WAITING]);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
$opened_statuses = implode(',', [Ticket::INCOMING, Ticket::ASSIGNED, Ticket::PLANNED, Ticket::WAITING]);
$opened_statuses = implode(',', [Ticket::getNotSolvedStatusArray()]);

I think you forget Ticket::APPROVAL (unless it is missing on purpose?), if that is the case you can use getNotSolvedStatusArray() so you are sure to not miss anything ;)

"$ticket_table.is_deleted" => 0,
] + getEntitiesRestrictCriteria($ticket_table),
'GROUPBY' => "$group_table.id",
'ORDERBY' => "$group_table.name",

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here I have two groups:
Image

If I limit the widget to one result, it show the one with the least tickets:
Image

I would expect the opposite, on a big instance with many groups the users is more likely interested in the groups with many tickets.

@Herafia
Herafia force-pushed the add/dashboard-report-ticketsByGroupAndStatus branch from 9513189 to 2fffe40 Compare August 24, 2026 13:20
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants