* Change default page to graphs
authorBen Klang <ben@alkaloid.net>
Thu, 3 Jul 2008 14:29:15 +0000 (14:29 +0000)
committerBen Klang <ben@alkaloid.net>
Sun, 10 Jan 2010 04:05:28 +0000 (23:05 -0500)
* Limit number of search results to a number set in Prefs (default: 100)
* Add call summary statistics to Search page
* Don't cache CDR search results in the session
* Add menu icons
ToDo: Allow paging through larger result set on search page

config/prefs.php.dist
index.php
lib/Driver/asterisksql.php
lib/Form/SearchCDR.php
lib/Operator.php
search.php
templates/search/header.inc
themes/graphics/graphs.png [new file with mode: 0644]
themes/silver/graphics/graphs.png [new file with mode: 0644]
viewgraph.php

index 21b0e82..2c5160e 100644 (file)
@@ -1,6 +1,6 @@
 <?php
 /**
- * $Horde: incubator/operator/config/prefs.php.dist,v 1.1 2008/04/19 01:26:06 bklang Exp $
+ * $Horde: incubator/operator/config/prefs.php.dist,v 1.2 2008/07/03 14:29:15 bklang Exp $
  *
  * See horde/config/prefs.php for documentation on the structure of this file.
  */
@@ -9,7 +9,7 @@ $prefGroups['display'] = array(
     'column' => _("Options"),
     'label' => _("Display Preferences"),
     'desc' => _("Set default display parameters."),
-    'members' => array('rowsperpage', 'columns')
+    'members' => array('rowsperpage', 'resultlimit', 'columns')
 );
 
 $_prefs['rowsperpage'] = array(
@@ -20,6 +20,13 @@ $_prefs['rowsperpage'] = array(
     'desc' => _("The columns to be displayed on the Call Detail Review screen")
 );
 
+$_prefs['resultlimit'] = array(
+    'value' => 100,
+    'locked' => false,
+    'shared' => false,
+    'type' => 'number',
+    'desc' => _("Limit the number of CDR results when searching to this number")
+);
 
 $_prefs['columns'] = array(
     'value' => 'a:18:{i:0;s:11:"accountcode";i:1;s:3:"src";i:2;s:3:"dst";i:3;s:8:"dcontext";i:4;s:4:"clid";i:5;s:7:"channel";i:6;s:10:"dstchannel";i:7;s:7:"lastapp";i:8;s:8:"lastdata";i:9;s:5:"start";i:10;s:6:"answer";i:11;s:3:"end";i:12;s:8:"duration";i:13;s:7:"billsec";i:14;s:11:"disposition";i:15;s:8:"amaflags";i:16;s:9:"userfield";i:17;s:8:"uniqueid";}',
index c5a58cc..bab9245 100644 (file)
--- a/index.php
+++ b/index.php
@@ -1,6 +1,6 @@
 <?php
 /**
- * $Horde: incubator/operator/index.php,v 1.1 2008/04/19 01:26:06 bklang Exp $
+ * $Horde: incubator/operator/index.php,v 1.2 2008/07/03 14:29:15 bklang Exp $
  *
  * Copyright 2008 Alkaloid Networks LLC <http://projects.alkaloid.net>
  *
@@ -19,4 +19,4 @@ if (!$operator_configured) {
                                    array('conf.php'));
 }
 
-require OPERATOR_BASE . '/search.php';
+require OPERATOR_BASE . '/viewgraph.php';
index 799b70b..b990d8f 100644 (file)
@@ -20,7 +20,7 @@
  * The table structure can be created by the scripts/sql/operator_foo.sql
  * script.
  *
- * $Horde: incubator/operator/lib/Driver/asterisksql.php,v 1.7 2008/07/01 22:25:01 bklang Exp $
+ * $Horde: incubator/operator/lib/Driver/asterisksql.php,v 1.8 2008/07/03 14:29:17 bklang Exp $
  *
  * Copyright 2007-2008 The Horde Project (http://www.horde.org/)
  *
@@ -76,7 +76,8 @@ class Operator_Driver_asterisksql extends Operator_Driver {
      *
      * @return boolean|PEAR_Error  True on success, PEAR_Error on failure.
      */
-    function getData($start, $end, $accountcode = null, $dcontext = null)
+    function getData($start, $end, $accountcode = null, $dcontext = null,
+                     $rowstart = 0, $rowlimit = 100)
     {
 
         // Use the query to make the MySQL driver look like the CDR-CSV driver
@@ -88,6 +89,16 @@ class Operator_Driver_asterisksql extends Operator_Driver {
         $filter = array();
         $values = array();
 
+        if (!is_numeric($rowstart)) {
+            Horde::logMessage('Invalid start row requested.', __FILE__, __LINE__, PEAR_LOG_ERR);
+            return PEAR::raiseError(_("Internal error.  Details have been logged for the administrator."));
+        }
+        if (!is_numeric($rowlimit)) {
+            Horde::logMessage('Invalid row limit requested.', __FILE__, __LINE__, PEAR_LOG_ERR);
+            return PEAR::raiseError(_("Internal error.  Details have been logged for the administrator."));
+        }
+
+
         // Start Date
         if (!is_a($start, 'Horde_Date')) {
             $start = new Horde_Date($start);
@@ -130,11 +141,35 @@ class Operator_Driver_asterisksql extends Operator_Driver {
         $filterstring = implode(' AND ', $filter);
         $sql = sprintf($sql, $filterstring);
         /* Log the query at a DEBUG log level. */
-        Horde::logMessage(sprintf('Operator_Driver_asterisksql::getData(): %s', $sql),
-                          __FILE__, __LINE__, PEAR_LOG_DEBUG);
+        Horde::logMessage(sprintf('Operator_Driver_asterisksql::getData(): %s', $sql), __FILE__, __LINE__, PEAR_LOG_DEBUG);
+
+        /* Execute the query. */
+        $res = $this->_db->limitQuery($sql, $rowstart, $rowlimit, $values);
+        if (is_a($res, 'PEAR_Error')) {
+            Horde::logMessage($res, __FILE__, __LINE__, PEAR_LOG_ERR);
+            return PEAR::raiseError(_("Internal error.  Details have been logged for the administrator."));
+        }
+        
+        $data = array();
+        while ($row = $res->fetchRow(DB_FETCHMODE_ASSOC)) {
+            $data[] = $row;
+        }
+
+        // Get summary statistics on the requested criteria
+        $sql = 'SELECT COUNT(*) AS numcalls, SUM(duration)/60 AS minutes, ' .
+               'SUM(CASE disposition WHEN "FAILED" THEN 1 ELSE 0 END) AS ' .
+               'failed FROM ' . $this->_params['table'] . ' WHERE %s';
+        $sql = sprintf($sql, $filterstring);
+        Horde::logMessage(sprintf('Operator_Driver_asterisksql::getData(): %s', $sql), __FILE__, __LINE__, PEAR_LOG_DEBUG);
 
         /* Execute the query. */
-        return $this->_db->getAll($sql, $values, DB_FETCHMODE_ASSOC);
+        $res = $this->_db->getRow($sql, $values, DB_FETCHMODE_ASSOC);
+        if (is_a($res, 'PEAR_Error')) {
+            Horde::logMessage($res, __FILE__, __LINE__, PEAR_LOG_ERR);
+            return PEAR::raiseError(_("Internal error.  Details have been logged for the administrator."));
+        }
+
+        return array_merge($data, $res);
     }
 
     /**
index 9e7153d..b0d2a47 100644 (file)
@@ -2,7 +2,7 @@
 /**
  * SearchCDRForm Class
  *
- * $Horde: incubator/operator/lib/Form/SearchCDR.php,v 1.3 2008/07/01 22:25:01 bklang Exp $
+ * $Horde: incubator/operator/lib/Form/SearchCDR.php,v 1.4 2008/07/03 14:29:18 bklang Exp $
  *
  * Copyright 2008 Alkaloid Networks LLC <http://projects.alkaloid.net>
  *
 
 class SearchCDRForm extends Horde_Form {
 
-    function SearchCDRForm(&$vars)
+    function SearchCDRForm($title, &$vars)
     {
         global $operator_driver;
 
-        parent::Horde_Form($vars, _("Search CDR Data"));
+        parent::Horde_Form($vars, $title);
 
         // FIXME: Generate a list of clients from Turba?
         //$clients = 
index b73b2e2..9f2da31 100644 (file)
@@ -2,7 +2,7 @@
 /**
  * Operator Base Class.
  *
- * $Horde: incubator/operator/lib/Operator.php,v 1.3 2008/07/01 22:25:00 bklang Exp $
+ * $Horde: incubator/operator/lib/Operator.php,v 1.4 2008/07/03 14:29:16 bklang Exp $
  *
  * Copyright 2008 Alkaloid Networks LLC <http://projects.alkaloid.net>
  *
@@ -24,8 +24,8 @@ class Operator {
         require_once 'Horde/Menu.php';
 
         $menu = new Menu(HORDE_MENU_MASK_ALL);
-        $menu->add(Horde::applicationUrl('search.php'), _("Search"), 'user.png', $registry->getImageDir('horde'));
-        $menu->add(Horde::applicationUrl('viewgraph.php'), _("View Graphs"), 'user.png', $registry->getImageDir('horde'));
+        $menu->add(Horde::applicationUrl('viewgraph.php'), _("View Graphs"), 'graphs.png');
+        $menu->add(Horde::applicationUrl('search.php'), _("Search"), 'search.png', $registry->getImageDir('horde'));
 
         if ($returnType == 'object') {
             return $menu;
index e14966f..b587fb5 100644 (file)
@@ -1,6 +1,6 @@
 <?php
 /**
- * $Horde: incubator/operator/search.php,v 1.3 2008/07/01 22:25:00 bklang Exp $
+ * $Horde: incubator/operator/search.php,v 1.4 2008/07/03 14:29:15 bklang Exp $
  *
  * Copyright 2008 Alkaloid Networks LLC <http://projects.alkaloid.net>
  *
@@ -22,28 +22,38 @@ require_once OPERATOR_BASE . '/lib/Form/SearchCDR.php';
 $renderer = new Horde_Form_Renderer();
 $vars = Variables::getDefaultVariables();
 
-$form = new SearchCDRForm($vars);
+if (!$vars->exists('rowstart')) {
+    $rowstart = 0;
+} elseif (!is_numeric($rowstart = $vars->get('rowstart'))) {
+    $notification->push(_("Invalid number for row start.  Using 0."));
+    $rowstart = 0;
+}
+
+$numrows = $prefs->getValue('resultlimit');
+if (!is_numeric($numrows)) {
+    $notification->push(_("Invalid number for rows for search limit.  Using 100."));
+    $numrows = 100;
+}
+
+$form = new SearchCDRForm(_("Search CDR Data"), $vars);
 if ($form->isSubmitted() && $form->validate($vars, true)) {
     $accountcode = $vars->get('accountcode');
     $dcontext = $vars->get('dcontext');
     $start = new Horde_Date($vars->get('startdate'));
     $end = new Horde_Date($vars->get('enddate'));
-    $data = $operator_driver->getData($start, $end, $accountcode, $dcontext);
+    $data = $operator_driver->getData($start, $end, $accountcode, $dcontext,
+                                      $rowstart, $numrows);
     $_SESSION['operator']['lastsearch']['params'] = array(
         'accountcode' => $vars->get('accountcode'),
         'dcontext' => $vars->get('dcontext'),
         'startdate' => $vars->get('startdate'),
         'enddate' => $vars->get('enddate'));
-    $_SESSION['operator']['lastsearch']['data'] = $data;
 } else {
     if (isset($_SESSION['operator']['lastsearch']['params'])) {
         foreach($_SESSION['operator']['lastsearch']['params'] as $var => $val) {
             $vars->set($var, $val);
         }
     }
-    if (isset($_SESSION['operator']['lastsearch']['data'])) {
-        $data = $_SESSION['operator']['lastsearch']['data'];
-    }
 }
 
 $title = _("Search Call Detail Records");
@@ -57,6 +67,7 @@ $form->renderActive($renderer, $vars);
 $columns = unserialize($prefs->getValue('columns'));
 if (!empty($data)) {
     require OPERATOR_TEMPLATES . '/search/header.inc';
+    unset($data['count'], $data['minutes'], $data['failed']);
     foreach ($data as $record) {
         require OPERATOR_TEMPLATES . '/search/row.inc';
     }
index 390cdbb..36127b0 100644 (file)
@@ -1,3 +1,10 @@
+Call Statistics Summary:<br />
+<ul>
+<li>Total Calls: <?php echo $data['numcalls']; ?></li>
+<li>Total Minutes: <?php echo round($data['minutes'], 1); ?></li>
+<li>Failed Calls: <?php echo $data['failed']; ?></li>
+</ul>
+<br />
 <table class="striped">
 <tr>
 <?php
diff --git a/themes/graphics/graphs.png b/themes/graphics/graphs.png
new file mode 100644 (file)
index 0000000..a5e467d
Binary files /dev/null and b/themes/graphics/graphs.png differ
diff --git a/themes/silver/graphics/graphs.png b/themes/silver/graphics/graphs.png
new file mode 100644 (file)
index 0000000..01e933a
Binary files /dev/null and b/themes/silver/graphics/graphs.png differ
index 1a4bea0..de820ea 100644 (file)
@@ -1,6 +1,6 @@
 <?php
 /**
- * $Horde: incubator/operator/viewgraph.php,v 1.4 2008/07/01 22:25:00 bklang Exp $
+ * $Horde: incubator/operator/viewgraph.php,v 1.5 2008/07/03 14:29:15 bklang Exp $
  *
  * Copyright 2008 Alkaloid Networks LLC <http://projects.alkaloid.net>
  *
@@ -22,7 +22,7 @@ require_once OPERATOR_BASE . '/lib/Form/SearchCDR.php';
 $renderer = new Horde_Form_Renderer();
 $vars = Variables::getDefaultVariables();
 
-$form = new SearchCDRForm($vars);
+$form = new SearchCDRForm(_("Graph CDR Data"), $vars);
 if ($form->isSubmitted() && $form->validate($vars, true)) {
     $accountcode = $vars->get('accountcode');
     $dcontext = $vars->get('dcontext');
@@ -37,11 +37,16 @@ if ($form->isSubmitted() && $form->validate($vars, true)) {
     if ($stats === false) {
         $stats = $operator_driver->getMonthlyCallStats($start, $end,
                                                        $accountcode, $dcontext);
-        $res = $cache->set($cachekey, serialize($stats), 600);
-        if ($res === false) {
-            Horde::logMessage('The cache system has experienced an error.  Unable to continue.', __FILE__, __LINE__, PEAR_LOG_ERR);
-            $notification->push(_("Internal error.  Details have been logged for the administrator."));
-            unset($stats);
+        if (is_a($stats, 'PEAR_Error')) {
+            $notification->push($stats);
+            $stats = array();
+        } else {
+            $res = $cache->set($cachekey, serialize($stats), 600);
+            if ($res === false) {
+                Horde::logMessage('The cache system has experienced an error.  Unable to continue.', __FILE__, __LINE__, PEAR_LOG_ERR);
+                $notification->push(_("Internal error.  Details have been logged for the administrator."));
+                unset($stats);
+            }
         }
     } else {
         // Cached data is stored serialized
@@ -75,7 +80,6 @@ if (!empty($stats)) {
         'graph' => 'failed', 'key' => $cachekey));
 }
 
-
 $title = _("Call Detail Records Graph");
 
 require OPERATOR_TEMPLATES . '/common-header.inc';