From 95267b5e815073672d246bf50f21681fb6ef8b9e Mon Sep 17 00:00:00 2001 From: Ben Klang Date: Sun, 31 May 2009 17:14:08 +0000 Subject: [PATCH] * Refine security controls on account codes * Improve graph generation process, including color cycling on data sets --- graphgen.php | 176 ++++++++++++++++++++++++++++++++++----------- lib/Driver/asterisksql.php | 24 +++++-- lib/Operator.php | 34 +++++---- 3 files changed, 175 insertions(+), 59 deletions(-) diff --git a/graphgen.php b/graphgen.php index 4106d350d..9ef8a9272 100644 --- a/graphgen.php +++ b/graphgen.php @@ -1,8 +1,8 @@ * * See the enclosed file COPYING for license information (GPL). If you * did not receive this file, see http://www.fsf.org/copyleft/gpl.html. @@ -16,19 +16,41 @@ require_once OPERATOR_BASE . '/lib/base.php'; // Load PEAR's Image_Graph library require_once 'Image/Graph.php'; +#setlocale(LC_ALL, NLS::select()); +setlocale(LC_ALL, 'en_US'); + $graphtype = Util::getFormData('graph'); $graphinfo = Operator::getGraphInfo($graphtype); $cachekey = Util::getFormData('key'); $stats = unserialize($cache->get($cachekey, 0)); +// Create the graph image base. +if (empty($graphinfo['imageX'])) { + $graphinfo['imageX'] = 700; +} +if (empty($graphinfo['imageY'])) { + $graphinfo['imageY'] = 600; +} +if (!isset($graphinfo['charttype'])) { + $graphinfo['charttype'] = 'bar'; +} +if (!isset($graphinfo['markers'])) { + $graphinfo['markers'] = true; +} +if (!isset($graphinfo['legendsplit'])) { + $graphinfo['legendsplit'] = 90; +} +$canvas =& Image_Canvas::factory('png', array('width' => $graphinfo['imageX'], 'height' => $graphinfo['imageY'], 'antialias' => true)); +$graph =& Image_Graph::factory('graph', $canvas); - - - -// Create the graph image base. -$graph =& Image_Graph::factory('graph', array(700, 500)); +if (isset($graphinfo['orientation']) && + $graphinfo['orientation'] == 'horizontal') { + $graph->horizontal = true; +} else { + $graph->horizontal = false; +} if (!empty($conf['ttf_font'])) { // add a TrueType font @@ -40,22 +62,28 @@ if (!empty($conf['ttf_font'])) { // create the plotarea layout +if ($graph->horizontal) { + $plotarea =& Image_Graph::factory('plotarea', array('Image_Graph_Axis_Category', 'Image_Graph_Axis', 'horizontal')); +} else { + $plotarea =& Image_Graph::factory('plotarea', array('Image_Graph_Axis_Category', 'Image_Graph_Axis', 'vertical')); +} + $graph->add( Image_Graph::vertical( Image_Graph::factory('title', array($graphinfo['title'], 11)), - #Image_Graph::vertical( - $plotarea = Image_Graph::factory('plotarea'), - # $legend = Image_Graph::factory('legend'), - # 90 - #), + Image_Graph::vertical( + $plotarea, + $legend = Image_Graph::factory('legend'), + $graphinfo['legendsplit'] + ), 5 ) ); $plotarea->setAxisPadding(array('top' => 20)); -// make the legend use the plotarea (or implicitly it's plots) -#$legend->setPlotarea($plotarea); +// make the legend use the plotarea (or implicitly its plots) +$legend->setPlotarea($plotarea); // create a grid and assign it to the secondary Y axis $gridY2 =& $plotarea->addNew('line_grid', IMAGE_GRAPH_AXIS_Y_SECONDARY); @@ -66,31 +94,54 @@ $gridY2 =& $plotarea->addNew('line_grid', IMAGE_GRAPH_AXIS_Y_SECONDARY); # array(IMAGE_GRAPH_GRAD_HORIZONTAL, 'white', 'lightgrey') # ) #); - -$dataset1 = Image_Graph::factory('dataset'); -foreach ($stats as $month => $stats) { - $dataset1->addPoint($month, $stats[$graphtype]); -} -$plot1 =& $plotarea->addNew('bar', $dataset1); -$plot1->setLineColor('black@0.5'); -$plot1->setFillColor('blue@0.2'); -$plot1->setTitle('Primary Axis'); - - -$marker =& $plot1->addNew('Image_Graph_Marker_Value', IMAGE_GRAPH_VALUE_Y); -// create a pin-point marker type -$PointingMarker =& $plot1->addNew('Image_Graph_Marker_Pointing', array(0, -7, $marker)); -$PointingMarker->setLineColor(false); -$marker->setBorderColor(false); -$marker->setFillColor(false); -// and use the marker on the 1st plot -$plot1->setMarker($PointingMarker); - -if (!empty($graphinfo['numberformat'])) { - $marker->setDataPreprocessor(Image_Graph::factory('Image_Graph_DataPreprocessor_Formatted', $graphinfo['numberformat'])); + +$linecolor = 0x000042; +$increment = 0x173147; +foreach ($stats[$graphtype] as $title => $data) { + $lcstring = sprintf('#%06x', $linecolor); + $linecolor += $increment; + if ($linecolor >= 0x5555555) { + $linecolor = $linecolor & 0xFFFFFF; + $linecolor += $increment; + } + + if ($graph->horizontal) { + // Horizontal graphs reverse the data points + $data = array_reverse($data, true); + } + + $dataset = Image_Graph::factory('dataset'); + foreach ($data as $expr => $value) { + $dataset->addPoint($expr, $value); + } + $plot =& $plotarea->addNew($graphinfo['charttype'], $dataset); + $plot->setLineColor($lcstring); + $plot->setFillColor($lcstring . '@0.5'); + //$plot->setFillColor('blue@0.2'); + $plot->setTitle($title); + + if ($graphinfo['markers']) { + $marker =& $plot->addNew('Image_Graph_Marker_Value', IMAGE_GRAPH_VALUE_Y); + // create a pin-point marker type + if ($graph->horizontal) { + $PointingMarker =& $plot->addNew('Image_Graph_Marker_Pointing', array(-37, 0, $marker)); + } else { + $PointingMarker =& $plot->addNew('Image_Graph_Marker_Pointing', array(0, -7, $marker)); + } + $PointingMarker->setLineColor(false); + $marker->setBorderColor(false); + $marker->setFillColor(false); + // and use the marker on the 1st plot + $plot->setMarker($PointingMarker); + + #if (!empty($graphinfo['numberformat'])) { + # $marker->setDataPreprocessor(Image_Graph::factory('Image_Graph_DataPreprocessor_Formatted', $graphinfo['numberformat'])); + #} + $marker->setDataPreprocessor(Image_Graph::factory('Image_Graph_DataPreprocessor_Function', '_format')); + $marker->setFontSize(7.5); + } } -$marker->setFontSize(6.5); - + // create an area plot using a random dataset #$dataset2 =& Image_Graph::factory('random', array(8, 1, 10, true)); #$plot2 =& $plotarea->addNew( @@ -104,11 +155,56 @@ $marker->setFontSize(6.5); #$plot2->setTitle('Secondary Axis'); $axisX =& $plotarea->getAxis(IMAGE_GRAPH_AXIS_X); -$axisX->setTitle($graphinfo['axisX']); $axisY =& $plotarea->getAxis(IMAGE_GRAPH_AXIS_Y); -$axisY->setTitle($graphinfo['axisY'], 'vertical'); +if ($graph->horizontal) { + $axisX->setTitle($graphinfo['axisX'], 'vertical'); + $axisY->setTitle($graphinfo['axisY'], 'horizontal'); +} else { + $axisX->setTitle($graphinfo['axisX'], 'horizontal'); + $axisY->setTitle($graphinfo['axisY'], 'vertical'); +} +$axisY->setDataPreprocessor(Image_Graph::factory('Image_Graph_DataPreprocessor_Function', 'axis2human')); #$axisYsecondary =& $plotarea->getAxis(IMAGE_GRAPH_AXIS_Y_SECONDARY); #$axisYsecondary->setTitle('Pears', 'vertical2'); // output the Graph $graph->done(); +exit; + +function _format($number) +{ + if (($number - (int)$number) == 0) { + return money_format('%!.0n', $number); + } else { + return money_format('%!.2n', $number); + } +} + +function number2human($number, $showCurrency = true) +{ + $currency = ''; + $suffix = ''; + if ($showCurrency) { + //$currency = 'ISK '; + $currency = ''; + } + + if (abs($number) >= 500000000) { + $number = $number / 1000000000; + $suffix = 'T'; + } + if (abs($number) >= 500000) { + $number = $number / 1000000; + $suffix = 'M'; + } + if (abs($number) >= 500) { + $number = $number / 1000; + $suffix = 'K'; + } + return $currency . _format($number) . $suffix; +} + +function axis2human($number) +{ + return number2human($number, false); +} diff --git a/lib/Driver/asterisksql.php b/lib/Driver/asterisksql.php index 3df1acdc2..d7c9fa49e 100644 --- a/lib/Driver/asterisksql.php +++ b/lib/Driver/asterisksql.php @@ -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.11 2009/01/06 17:51:07 jan Exp $ + * $Horde: incubator/operator/lib/Driver/asterisksql.php,v 1.12 2009/05/31 17:14:08 bklang Exp $ * * Copyright 2008-2009 The Horde Project (http://www.horde.org/) * @@ -298,27 +298,30 @@ class Operator_Driver_asterisksql extends Operator_Driver { $failed[$row['year']][$row['month']] = $row['failed']; } + $s_numcalls = array(); + $s_minutes = array(); + $s_failed = array(); while($start->compareDate($end) <= 0) { $index = $start->strftime('%Y-%m'); $year = $start->year; $month = $start->month; if (empty($numcalls[$year]) || empty($numcalls[$year][$month])) { - $stats[$index]['numcalls'] = 0; + $s_numcalls[$index] = 0; } else { - $stats[$index]['numcalls'] = $numcalls[$year][$month]; + $s_numcalls[$index] = $numcalls[$year][$month]; } if (empty($minutes[$year]) || empty($minutes[$year][$month])) { - $stats[$index]['minutes'] = 0; + $s_minutes[$index] = 0; } else { - $stats[$index]['minutes'] = $minutes[$year][$month]; + $s_minutes[$index] = $minutes[$year][$month]; } if (empty($failed[$year]) || empty($failed[$year][$month])) { - $stats[$index]['failed'] = 0; + $s_failed[$index] = 0; } else { - $stats[$index]['failed'] = $failed[$year][$month]; + $s_failed[$index] = $failed[$year][$month]; } // Find the first day of the next month @@ -326,6 +329,13 @@ class Operator_Driver_asterisksql extends Operator_Driver { $start->correct(); } + $info = Operator::getGraphInfo('numcalls'); + $stats['numcalls'] = array($info['title'] => $s_numcalls); + $info = Operator::getGraphInfo('minutes'); + $stats['minutes'] = array($info['title'] => $s_minutes); + $info = Operator::getGraphInfo('failed'); + $stats['failed'] = array($info['title'] => $s_failed); + return $stats; } diff --git a/lib/Operator.php b/lib/Operator.php index 5b8d94256..6140a169a 100644 --- a/lib/Operator.php +++ b/lib/Operator.php @@ -2,7 +2,7 @@ /** * Operator Base Class. * - * $Horde: incubator/operator/lib/Operator.php,v 1.13 2009/01/06 17:51:06 jan Exp $ + * $Horde: incubator/operator/lib/Operator.php,v 1.14 2009/05/31 17:14:09 bklang Exp $ * * Copyright 2008-2009 The Horde Project (http://www.horde.org/) * @@ -94,26 +94,36 @@ class Operator { $accountcodes = $operator_driver->getAccountCodes(); - // Add an option to select all accounts - $keys = $accountcodes; - array_unshift($keys, '%'); - $values = $accountcodes; - array_unshift($values, _("-- All Accounts --")); + if (Auth::isAdmin() || + $GLOBALS['perms']->hasPermission('operator:accountcodes', + Auth::getAuth(), + PERMS_READ)) { + $permfilter = false; + } + + if (!$permfilter || + $GLOBALS['perms']->hasPermission('operator:accountcodes:%', + Auth::geAuth(), + PERMS_READ)) { + // Add an option to select all accounts + $keys = $accountcodes; + array_unshift($keys, '%'); + $values = $accountcodes; + array_unshift($values, _("-- All Accounts Combined --")); + } + + // Only add the Empty value if it is exists in the backend if ($index = array_search('', $values)) { $values[$index] = _("-- Empty Accountcode --"); } - // Make the index of each array entry the same as its value - // array_combine() is PHP5-only - //$accountcodes = array_combine($keys, $values); - $accountcodes = array(); - // Filter the returned list of account codes through Permissions // if requested. + $accountcodes = array(); foreach ($keys as $index => $accountcode) { if ($permfilter) { - if (empty($accountcode) || $accountcode == '%') { + if (empty($accountcode)) { $permitem = 'operator:accountcodes'; } else { $permitem = 'operator:accountcodes:' . $accountcode; -- 2.11.0