From a08a34283d3ea0d1306b3bb483219f60fdff50d5 Mon Sep 17 00:00:00 2001 From: "Florian Aders (EleRas)" Date: Sun, 24 Apr 2011 00:01:37 +0200 Subject: [PATCH] Added traffic overview for admins over all customers, refs #492, thx yabawock Signed-off-by: Florian Aders (EleRas) --- admin_traffic.php | 141 ++++++++++++++++++ .../phphelpers/function.size_readable.php | 36 +++++ lib/navigation/00.froxlor.main.php | 11 ++ lng/english.lng.php | 22 +++ templates/Classic/admin/traffic/index.tpl | 7 + .../Classic/admin/traffic/index_table.tpl | 52 +++++++ .../Classic/admin/traffic/index_table_row.tpl | 15 ++ templates/Classic/main.css | 14 ++ templates/jquery.tablesorter.min.js | 4 + 9 files changed, 302 insertions(+) create mode 100644 admin_traffic.php create mode 100644 lib/functions/phphelpers/function.size_readable.php create mode 100644 templates/Classic/admin/traffic/index.tpl create mode 100644 templates/Classic/admin/traffic/index_table.tpl create mode 100644 templates/Classic/admin/traffic/index_table_row.tpl create mode 100644 templates/jquery.tablesorter.min.js diff --git a/admin_traffic.php b/admin_traffic.php new file mode 100644 index 00000000..2fd58008 --- /dev/null +++ b/admin_traffic.php @@ -0,0 +1,141 @@ + + * @license GPLv2 http://files.syscp.org/misc/COPYING.txt + * @package Panel + * @version $Id: $ + */ + +define('AREA', 'admin'); + +/** + * Include our init.php, which manages Sessions, Language etc. + */ + +require ("./lib/init.php"); + +if($action == 'logout') +{ + $db->query("DELETE FROM `" . TABLE_PANEL_SESSIONS . "` WHERE `userid` = '" . (int)$userinfo['adminid'] . "' AND `adminsession` = '1'"); + redirectTo('index.php'); + exit; +} + +if(isset($_POST['id'])) +{ + $id = intval($_POST['id']); +} +elseif(isset($_GET['id'])) +{ + $id = intval($_GET['id']); +} + +$months = array( + '0' => 'empty', + '1' => 'jan', + '2' => 'feb', + '3' => 'mar', + '4' => 'apr', + '5' => 'may', + '6' => 'jun', + '7' => 'jul', + '8' => 'aug', + '9' => 'sep', + '10' => 'oct', + '11' => 'nov', + '12' => 'dec', +); + +if($page == 'overview' || $page == 'customers') +{ + if($action == 'su' && $id != 0) + { + $result = $db->query_first("SELECT * FROM `" . TABLE_PANEL_CUSTOMERS . "` WHERE `customerid`='" . (int)$id . "' " . ($userinfo['customers_see_all'] ? '' : " AND `adminid` = '" . (int)$userinfo['adminid'] . "' ")); + + if($result['loginname'] != '') + { + $result = $db->query_first("SELECT * FROM `" . TABLE_PANEL_SESSIONS . "` WHERE `userid`='" . (int)$userinfo['userid'] . "'"); + $s = md5(uniqid(microtime(), 1)); + $db->query("INSERT INTO `" . TABLE_PANEL_SESSIONS . "` (`hash`, `userid`, `ipaddress`, `useragent`, `lastactivity`, `language`, `adminsession`) VALUES ('" . $db->escape($s) . "', '" . (int)$id . "', '" . $db->escape($result['ipaddress']) . "', '" . $db->escape($result['useragent']) . "', '" . time() . "', '" . $db->escape($result['language']) . "', '0')"); + redirectTo('customer_traffic.php', Array( + 's' => $s + )); + } + else + { + redirectTo('index.php', Array( + 'action' => 'login' + )); + } + } + $customerview = 1; + $stats_tables = ''; + $minyear = $db->query_first("SELECT `year` FROM `". TABLE_PANEL_TRAFFIC . "` ORDER BY `year` ASC LIMIT 1"); + $maxyears = date("Y") - $minyear['year']; + for($years = 0; $years<=$maxyears; $years++) { + $overview['year'] = date("Y")-$years; + $overview['type'] = $lng['traffic']['customer']; + $domain_list = ''; + $customer_name_list = $db->query("SELECT `customerid`,`company`,`name`,`firstname` FROM `" . TABLE_PANEL_CUSTOMERS . "` WHERE `deactivated`='0'" . ($userinfo['customers_see_all'] ? '' : " AND `adminid` = '" . (int)$userinfo['adminid'] . "' ") . " ORDER BY name"); + $totals = array( + 'jan' => 0, + 'feb' => 0, + 'mar' => 0, + 'apr' => 0, + 'may' => 0, + 'jun' => 0, + 'jul' => 0, + 'aug' => 0, + 'sep' => 0, + 'oct' => 0, + 'nov' => 0, + 'dec' => 0, + ); + while($customer_name = $db->fetch_array($customer_name_list)) { + $virtual_host = array( + 'name' => ($customer_name['company'] == '' ? $customer_name['name'] . ", " . $customer_name['firstname'] : $customer_name['company']), + 'customerid' => $customer_name['customerid'], + 'jan' => '-', + 'feb' => '-', + 'mar' => '-', + 'apr' => '-', + 'may' => '-', + 'jun' => '-', + 'jul' => '-', + 'aug' => '-', + 'sep' => '-', + 'oct' => '-', + 'nov' => '-', + 'dec' => '-', + ); + + $traffic_list = $db->query("SELECT month, SUM(http+ftp_up+ftp_down+mail)*1024 AS traffic FROM `" . TABLE_PANEL_TRAFFIC . "` WHERE year = " . (date("Y")-$years) . " AND `customerid` = '" . $customer_name['customerid'] . "' GROUP BY month ORDER BY month"); + while($traffic_month = $db->fetch_array($traffic_list)) { + $virtual_host[$months[(int)$traffic_month['month']]] = size_readable($traffic_month['traffic'], 'GiB', 'bi', '%01.3f %s'); + $totals[$months[(int)$traffic_month['month']]] += $traffic_month['traffic']; + } + eval("\$domain_list .= sprintf(\"%s\", \"" . getTemplate("traffic/index_table_row") . "\");"); + } + // sum up totals + $virtual_host = array( + 'name' => $lng['traffic']['months']['total'], + ); + foreach($totals as $month => $bytes) { + $virtual_host[$month] = ($bytes == 0 ? '-' : size_readable($bytes, 'GiB', 'bi', '%01.3f %s')); + } + $customerview = 0; + eval("\$total_list = sprintf(\"%s\", \"" . getTemplate("traffic/index_table_row") . "\");"); + eval("\$stats_tables .= sprintf(\"%s\", \"" . getTemplate("traffic/index_table") . "\");"); + } + eval("echo \"" . getTemplate("traffic/index") . "\";"); +} diff --git a/lib/functions/phphelpers/function.size_readable.php b/lib/functions/phphelpers/function.size_readable.php new file mode 100644 index 00000000..eafacd2d --- /dev/null +++ b/lib/functions/phphelpers/function.size_readable.php @@ -0,0 +1,36 @@ + + * @version 1.3.0 + * @link http://aidanlister.com/2004/04/human-readable-file-sizes/ + * @param int $size size in bytes + * @param string $max maximum unit + * @param string $system 'si' for SI, 'bi' for binary prefixes + * @param string $retstring return string format + */ + +function size_readable($size, $max = null, $system = 'si', $retstring = '%01.2f %s') +{ + // Pick units + $systems['si']['prefix'] = array('B', 'K', 'MB', 'GB', 'TB', 'PB'); + $systems['si']['size'] = 1000; + $systems['bi']['prefix'] = array('B', 'KiB', 'MiB', 'GiB', 'TiB', 'PiB'); + $systems['bi']['size'] = 1024; + $sys = isset($systems[$system]) ? $systems[$system] : $systems['si']; + + // Max unit to display + $depth = count($sys['prefix']) - 1; + if ($max && false !== $d = array_search($max, $sys['prefix'])) { + $depth = $d; + } + // Loop + $i = 0; + while ($size >= $sys['size'] && $i < $depth) { + $size /= $sys['size']; + $i++; + } + + return sprintf($retstring, $size, $sys['prefix'][$i]); +} diff --git a/lib/navigation/00.froxlor.main.php b/lib/navigation/00.froxlor.main.php index 931d8252..d181c147 100644 --- a/lib/navigation/00.froxlor.main.php +++ b/lib/navigation/00.froxlor.main.php @@ -189,6 +189,17 @@ return array ( ), ), ), + 'traffic' => array ( + 'label' => $lng['admin']['traffic'], + 'required_resources' => 'customers', + 'elements' => array ( + array ( + 'url' => 'admin_traffic.php?page=customers', + 'label' => $lng['admin']['customertraffic'], + 'required_resources' => 'customers', + ), + ), + ), 'server' => array ( 'label' => $lng['admin']['server'], 'required_resources' => 'change_serversettings', diff --git a/lng/english.lng.php b/lng/english.lng.php index 06f277bc..e082bed7 100644 --- a/lng/english.lng.php +++ b/lng/english.lng.php @@ -1581,3 +1581,25 @@ $lng['serversettings']['validate_domain'] = 'Validate domain names'; $lng['login']['combination_not_found'] = 'Combination of user and email adress not found.'; $lng['customer']['generated_pwd'] = 'Password suggestion'; $lng['customer']['usedmax'] = 'Used / Max'; +$lng['admin']['traffic'] = 'Traffic'; +$lng['admin']['domaintraffic'] = 'Domains'; +$lng['admin']['customertraffic'] = 'Customers'; +$lng['traffic']['customer'] = 'Customer'; +$lng['traffic']['domain'] = 'Domain'; +$lng['traffic']['trafficoverview'] = 'Traffic summary by'; +$lng['traffic']['months']['jan'] = 'Jan'; +$lng['traffic']['months']['feb'] = 'Feb'; +$lng['traffic']['months']['mar'] = 'Mar'; +$lng['traffic']['months']['apr'] = 'Apr'; +$lng['traffic']['months']['may'] = 'May'; +$lng['traffic']['months']['jun'] = 'Jun'; +$lng['traffic']['months']['jul'] = 'Jul'; +$lng['traffic']['months']['aug'] = 'Aug'; +$lng['traffic']['months']['sep'] = 'Sep'; +$lng['traffic']['months']['oct'] = 'Oct'; +$lng['traffic']['months']['nov'] = 'Nov'; +$lng['traffic']['months']['dec'] = 'Dec'; +$lng['traffic']['months']['total'] = 'Total'; +$lng['traffic']['details'] = 'Details'; +$lng['menue']['traffic']['table'] = 'Traffic'; + diff --git a/templates/Classic/admin/traffic/index.tpl b/templates/Classic/admin/traffic/index.tpl new file mode 100644 index 00000000..2d2079de --- /dev/null +++ b/templates/Classic/admin/traffic/index.tpl @@ -0,0 +1,7 @@ +$header + + + {$stats_tables} +
+
+$footer diff --git a/templates/Classic/admin/traffic/index_table.tpl b/templates/Classic/admin/traffic/index_table.tpl new file mode 100644 index 00000000..6308e369 --- /dev/null +++ b/templates/Classic/admin/traffic/index_table.tpl @@ -0,0 +1,52 @@ + + + + + + + + + + + {$domain_list} + + + {$total_list} + + + + +
 {$lng['traffic']['trafficoverview']} {$overview['type']} {$overview['year']}
{$overview['type']}{$lng['traffic']['months']['jan']} + {$lng['traffic']['months']['feb']} + {$lng['traffic']['months']['mar']} + {$lng['traffic']['months']['apr']} + {$lng['traffic']['months']['may']} + {$lng['traffic']['months']['jun']} + {$lng['traffic']['months']['jul']} + {$lng['traffic']['months']['aug']} + {$lng['traffic']['months']['sep']} + {$lng['traffic']['months']['oct']} + {$lng['traffic']['months']['nov']} + {$lng['traffic']['months']['dec']} +
 
+ +
+
+ diff --git a/templates/Classic/admin/traffic/index_table_row.tpl b/templates/Classic/admin/traffic/index_table_row.tpl new file mode 100644 index 00000000..4330e1b7 --- /dev/null +++ b/templates/Classic/admin/traffic/index_table_row.tpl @@ -0,0 +1,15 @@ + + {$virtual_host['name']} [{$lng['traffic']['details']}] + {$virtual_host['jan']} + {$virtual_host['feb']} + {$virtual_host['mar']} + {$virtual_host['apr']} + {$virtual_host['may']} + {$virtual_host['jun']} + {$virtual_host['jul']} + {$virtual_host['aug']} + {$virtual_host['sep']} + {$virtual_host['oct']} + {$virtual_host['nov']} + {$virtual_host['dec']} + diff --git a/templates/Classic/main.css b/templates/Classic/main.css index efdb0ab2..980eb8f3 100644 --- a/templates/Classic/main.css +++ b/templates/Classic/main.css @@ -476,3 +476,17 @@ TR.RowOverSelected { } +table.maintable th.field_display .header { + background-color: #000000; +} + +.headerSortUp { + background-image: url(../images/asc.gif); + background-position: right bottom; + background-repeat: no-repeat; +} +.headerSortDown { + background-image: url(../images/desc.gif); + background-position: right top; + background-repeat: no-repeat; +} diff --git a/templates/jquery.tablesorter.min.js b/templates/jquery.tablesorter.min.js new file mode 100644 index 00000000..b8605df1 --- /dev/null +++ b/templates/jquery.tablesorter.min.js @@ -0,0 +1,4 @@ + +(function($){$.extend({tablesorter:new +function(){var parsers=[],widgets=[];this.defaults={cssHeader:"header",cssAsc:"headerSortUp",cssDesc:"headerSortDown",cssChildRow:"expand-child",sortInitialOrder:"asc",sortMultiSortKey:"shiftKey",sortForce:null,sortAppend:null,sortLocaleCompare:true,textExtraction:"simple",parsers:{},widgets:[],widgetZebra:{css:["even","odd"]},headers:{},widthFixed:false,cancelSelection:true,sortList:[],headerList:[],dateFormat:"us",decimal:'/\.|\,/g',onRenderHeader:null,selectorHeaders:'thead th',debug:false};function benchmark(s,d){log(s+","+(new Date().getTime()-d.getTime())+"ms");}this.benchmark=benchmark;function log(s){if(typeof console!="undefined"&&typeof console.debug!="undefined"){console.log(s);}else{alert(s);}}function buildParserCache(table,$headers){if(table.config.debug){var parsersDebug="";}if(table.tBodies.length==0)return;var rows=table.tBodies[0].rows;if(rows[0]){var list=[],cells=rows[0].cells,l=cells.length;for(var i=0;i1){arr=arr.concat(checkCellColSpan(table,headerArr,row++));}else{if(table.tHead.length==1||(cell.rowSpan>1||!r[row+1])){arr.push(cell);}}}return arr;};function checkHeaderMetadata(cell){if(($.metadata)&&($(cell).metadata().sorter===false)){return true;};return false;}function checkHeaderOptions(table,i){if((table.config.headers[i])&&(table.config.headers[i].sorter===false)){return true;};return false;}function checkHeaderOptionsSortingLocked(table,i){if((table.config.headers[i])&&(table.config.headers[i].lockedOrder))return table.config.headers[i].lockedOrder;return false;}function applyWidget(table){var c=table.config.widgets;var l=c.length;for(var i=0;i');$("tr:first td",table.tBodies[0]).each(function(){colgroup.append($('').css('width',$(this).width()));});$(table).prepend(colgroup);};}function updateHeaderSortCount(table,sortList){var c=table.config,l=sortList.length;for(var i=0;i b["+i+"]) ? 1 : 0));";};function makeSortTextDesc(i){return"((b["+i+"] < a["+i+"]) ? -1 : ((b["+i+"] > a["+i+"]) ? 1 : 0));";};function makeSortNumeric(i){return"a["+i+"]-b["+i+"];";};function makeSortNumericDesc(i){return"b["+i+"]-a["+i+"];";};function sortText(a,b){if(table.config.sortLocaleCompare)return a.localeCompare(b);return((ab)?1:0));};function sortTextDesc(a,b){if(table.config.sortLocaleCompare)return b.localeCompare(a);return((ba)?1:0));};function sortNumeric(a,b){return a-b;};function sortNumericDesc(a,b){return b-a;};function getCachedSortType(parsers,i){return parsers[i].type;};this.construct=function(settings){return this.each(function(){if(!this.tHead||!this.tBodies)return;var $this,$document,$headers,cache,config,shiftDown=0,sortOrder;this.config={};config=$.extend(this.config,$.tablesorter.defaults,settings);$this=$(this);$.data(this,"tablesorter",config);$headers=buildHeaders(this);this.config.parsers=buildParserCache(this,$headers);cache=buildCache(this);var sortCSS=[config.cssDesc,config.cssAsc];fixColumnWidth(this);$headers.click(function(e){var totalRows=($this[0].tBodies[0]&&$this[0].tBodies[0].rows.length)||0;if(!this.sortDisabled&&totalRows>0){$this.trigger("sortStart");var $cell=$(this);var i=this.column;this.order=this.count++%2;if(this.lockedOrder)this.order=this.lockedOrder;if(!e[config.sortMultiSortKey]){config.sortList=[];if(config.sortForce!=null){var a=config.sortForce;for(var j=0;j0){$this.trigger("sorton",[config.sortList]);}applyWidget(this);});};this.addParser=function(parser){var l=parsers.length,a=true;for(var i=0;i