From 5848eb3a41c42d08b5c6a797ae545315ef893429 Mon Sep 17 00:00:00 2001 From: Jared Hancock <gravydish@gmail.com> Date: Mon, 4 Jun 2012 10:20:30 -0500 Subject: [PATCH] Initial writeup to support the dashboard reporting feature --- include/ajax.reports.php | 150 +++++++++++++++++++++++++++++++++++++++ include/class.ajax.php | 4 ++ scp/ajax.php | 6 ++ 3 files changed, 160 insertions(+) create mode 100644 include/ajax.reports.php diff --git a/include/ajax.reports.php b/include/ajax.reports.php new file mode 100644 index 000000000..cee05471d --- /dev/null +++ b/include/ajax.reports.php @@ -0,0 +1,150 @@ +<?php +/********************************************************************* + ajax.reports.php + + AJAX interface for reports -- both plot and tabular data are retrievable + in JSON format from this utility. Please put plumbing in /scp/ajax.php + pattern rules. + + Jared Hancock <jared@osticket.com> + Copyright (c) 2006-2012 osTicket + http://www.osticket.com + + Released under the GNU General Public License WITHOUT ANY WARRANTY. + See LICENSE.TXT for details. + + vim: expandtab sw=4 ts=4 sts=4: +**********************************************************************/ + +if(!defined('INCLUDE_DIR')) die('403'); + +include_once(INCLUDE_DIR.'class.ticket.php'); + +/** + * Overview Report + * + * The overview report allows for the display of basic ticket statistics in + * both graphical and tabular formats. + */ +class OverviewReportAjaxAPI extends AjaxController { + function enumTabularGroups() { + return $this->encode(array("dept"=>"Department", "topic"=>"Topics", + "staff"=>"Staff")); + } + + function getData() { + $start = $this->get('start', strtotime('last month')); + $stop = $this->get('stop', time()); + + $groups = array( + "dept" => array( + "table" => DEPT_TABLE, + "pk" => "dept_id", + "sort" => 'ORDER BY dept_name', + "fields" => 'T1.dept_name', + "headers" => array('Department') + ), + "topic" => array( + "table" => TOPIC_TABLE, + "pk" => "topic_id", + "sort" => 'ORDER BY topic', + "fields" => "T1.topic", + "headers" => array('Help Topic') + ), + "staff" => array( + "table" => STAFF_TABLE, + "pk" => 'staff_id', + "sort" => 'ORDER BY T1.lastname, T1.firstname', + "fields" => "CONCAT_WS(' ', T1.firstname, T1.lastname)", + "headers" => array('Staff Member') + ) + ); + $group = $this->get('group', 'dept'); + $info = $groups[$group]; + # XXX: Die if $group not in $groups + + $res = db_query( + 'SELECT ' . $info['fields'] . ',' + .' COUNT(A1.ticket_id) AS Opened,' + .' COUNT(A2.ticket_id) AS Closed,' + .' COUNT(A3.ticket_id) AS Reopened' + .' FROM ' . $info['table'] . ' T1' + .' LEFT JOIN ' . TICKET_EVENT_TABLE + . ' A1 ON (T1.' . $info['pk'] . ' = A1.' . $info['pk'] + .' AND A1.state=\'opened\' AND NOT A1.annulled)' + .' LEFT JOIN ' . TICKET_EVENT_TABLE + . ' A2 ON (T1.' . $info['pk'] . ' = A2.' . $info['pk'] + .' AND A2.state=\'closed\' AND NOT A2.annulled)' + .' LEFT JOIN ' . TICKET_EVENT_TABLE + . ' A3 ON (T1.' . $info['pk'] . ' = A3.' . $info['pk'] + .' AND A3.state=\'reopened\' AND NOT A3.annulled)' + .' GROUP BY '.$info['fields'] + ); + $rows = array(); + while ($row = db_fetch_row($res)) { + $rows[] = $row; + } + return array("columns" => array_merge($info['headers'], + array('Opened','Closed','Reopened')), + "data" => $rows); + } + + function getTabularData() { + return $this->encode($this->getData()); + } + + function downloadTabularData() { + $data = $this->getData(); + $csv = array($data['columns']); + $csv = array_merge($csv, $data['data']); + Http::download( + sprintf('%s-report.csv', $this->get('group', 'Department')), + Format::implode_array(',', "\n", $csv)); + } + + function getPlotData() { + $start = $this->get('start', strtotime('last month')); + $stop = $this->get('stop', time()); + + # Fetch all types of events over the timeframe + $res = db_query('SELECT DISTINCT(state) FROM '.TICKET_EVENT_TABLE + .' WHERE timestamp BETWEEN FROM_UNIXTIME('.db_input($start) + .') AND FROM_UNIXTIME('.db_input($stop).')'); + $events = array(); + while ($row = db_fetch_row($res)) $events[] = $row[0]; + + # TODO: Handle user => db timezone offset + # XXX: Implement annulled column from the %ticket_event table + $res = db_query('SELECT state, DATE_FORMAT(timestamp, \'%Y-%m-%d\'), ' + .'COUNT(ticket_id)' + .' FROM '.TICKET_EVENT_TABLE + .' WHERE timestamp BETWEEN FROM_UNIXTIME('.db_input($start) + .') AND FROM_UNIXTIME('.db_input($stop) + .') GROUP BY state, DATE_FORMAT(timestamp, \'%Y-%m-%d\')'); + # Initialize array of plot values + $plots = array(); + foreach ($events as $e) { $plots[$e] = array(); } + + $time = null; $times = array(); + # Iterate over result set, adding zeros for missing ticket events + while ($row = db_fetch_row($res)) { + $row_time = strtotime($row[1]); + if ($time != $row_time) { + # New time (and not the first), figure out which events did + # not have any tickets associated for this time slot + if ($time !== null) { + # Not the first record + foreach (array_diff($events, $slots) as $slot) { + $plots[$slot][] = 0; + } + } + $slots = array(); + $times[] = $time = $row_time; + } + # Keep track of states for this timeframe + if (!in_array($row[0], $slots)) $slots[] = $row[0]; + $plots[$row[0]][] = (int)$row[2]; + } + return $this->encode(array("times" => $times, "plots" => $plots)); + } +} diff --git a/include/class.ajax.php b/include/class.ajax.php index 742f224fb..0240d91f8 100644 --- a/include/class.ajax.php +++ b/include/class.ajax.php @@ -50,4 +50,8 @@ class AjaxController extends ApiController { function encode($what) { return $this->json_encode($what); } + + function get($var, $default=null) { + return (isset($_GET[$var])) ? $_GET[$var] : $default; + } } diff --git a/scp/ajax.php b/scp/ajax.php index 471e9c710..fac8a088f 100644 --- a/scp/ajax.php +++ b/scp/ajax.php @@ -45,6 +45,12 @@ $dispatcher = patterns('', url('^/config/', patterns('ajax.config.php:ConfigAjaxAPI', url_get('^ui', 'ui') )), + url('^/report/overview/', patterns('ajax.reports.php:OverviewReportAjaxAPI', + # Send + url_get('^graph$', 'getPlotData'), + url_get('^table/groups$', 'enumTabularGroups'), + url_get('^table$', 'getTabularData') + )), url_get('^/users$', array('ajax.users.php:UsersAjaxAPI', 'search')), url_get('^/tickets$', array('ajax.tickets.php:TicketsAjaxAPI', 'search')), url('^/ticket/', patterns('ajax.tickets.php:TicketsAjaxAPI', -- GitLab