diff --git a/app/extensions/app_languages.php b/app/extensions/app_languages.php index d70072975a..1a15d94a98 100644 --- a/app/extensions/app_languages.php +++ b/app/extensions/app_languages.php @@ -1729,6 +1729,17 @@ $text['button-save']['ro'] = "Salvează"; $text['button-save']['ar-eg'] = "حفظ"; $text['button-save']['he'] = "שמור"; +$text['button-export']['en-us'] = "Export"; +$text['button-export']['es-cl'] = "Exportación"; +$text['button-export']['pt-pt'] = "Exportação"; +$text['button-export']['fr-fr'] = "Exportation"; +$text['button-export']['pt-br'] = "Exportação "; +$text['button-export']['pl'] = "Eksportuj"; +$text['button-export']['sv-se'] = "Export"; +$text['button-export']['uk'] = ""; +$text['button-export']['de-at'] = "Export"; +$text['button-export']['he'] = "יצוא"; + $text['button-edit']['en-us'] = "Edit"; $text['button-edit']['es-cl'] = "Editar"; $text['button-edit']['pt-pt'] = "Editar"; diff --git a/app/extensions/extension_download.php b/app/extensions/extension_download.php new file mode 100644 index 0000000000..3fa035b416 --- /dev/null +++ b/app/extensions/extension_download.php @@ -0,0 +1,187 @@ + + Portions created by the Initial Developer are Copyright (C) 2008-2012 + the Initial Developer. All Rights Reserved. + + Contributor(s): + Mark J Crane +*/ +include "root.php"; +require_once "resources/require.php"; +require_once "resources/check_auth.php"; +require_once "resources/paging.php"; +if (if_group("superadmin")) { + //access granted +} +else { + echo "access denied"; + exit; +} + +//add multi-lingual support +$language = new text; +$text = $language->get(); + +function array2csv(array &$array) +{ + if (count($array) == 0) { + return null; + } + ob_start(); + $df = fopen("php://output", 'w'); + fputcsv($df, array_keys(reset($array))); + foreach ($array as $row) { + fputcsv($df, $row); + } + fclose($df); + return ob_get_clean(); +} + +function download_send_headers($filename) { + // disable caching + $now = gmdate("D, d M Y H:i:s"); + header("Expires: Tue, 03 Jul 2001 06:00:00 GMT"); + header("Cache-Control: max-age=0, no-cache, must-revalidate, proxy-revalidate"); + header("Last-Modified: {$now} GMT"); + + // force download + header("Content-Type: application/force-download"); + header("Content-Type: application/octet-stream"); + header("Content-Type: application/download"); + + // disposition / encoding on response body + header("Content-Disposition: attachment;filename={$filename}"); + header("Content-Transfer-Encoding: binary"); +} + +if (isset($_REQUEST["column_group"])) { + + $columns = implode(",",$_REQUEST["column_group"]); + $sql = "select " . $columns . " from v_extensions "; + $sql .= " where domain_uuid = '".$domain_uuid."' "; + $prep_statement = $db->prepare(check_sql($sql)); + $prep_statement->execute(); + $extensions = $prep_statement->fetchAll(PDO::FETCH_ASSOC); + unset ($sql, $prep_statement); +// print_r($extensions); + + download_send_headers("data_export_" . date("Y-m-d") . ".csv"); + echo array2csv($extensions); + die(); + +} + +$columns[] = 'extension_uuid'; +$columns[] = 'domain_uuid'; +$columns[] = 'extension'; +$columns[] = 'number_alias'; +$columns[] = 'password'; +$columns[] = 'accountcode'; +$columns[] = 'effective_caller_id_name'; +$columns[] = 'effective_caller_id_number'; +$columns[] = 'outbound_caller_id_name'; +$columns[] = 'outbound_caller_id_number'; +$columns[] = 'emergency_caller_id_name'; +$columns[] = 'emergency_caller_id_number'; +$columns[] = 'directory_full_name'; +$columns[] = 'directory_visible'; +$columns[] = 'directory_exten_visible'; +$columns[] = 'limit_max'; +$columns[] = 'limit_destination'; +$columns[] = 'missed_call_app'; +$columns[] = 'missed_call_data'; +$columns[] = 'user_context'; +$columns[] = 'toll_allow'; +$columns[] = 'call_timeout'; +$columns[] = 'call_group'; +$columns[] = 'call_screen_enabled'; +$columns[] = 'user_record'; +$columns[] = 'hold_music'; +$columns[] = 'auth_acl'; +$columns[] = 'cidr'; +$columns[] = 'sip_force_contact'; +$columns[] = 'nibble_account'; +$columns[] = 'sip_force_expires'; +$columns[] = 'mwi_account'; +$columns[] = 'sip_bypass_media'; +$columns[] = 'unique_id'; +$columns[] = 'dial_string'; +$columns[] = 'dial_user'; +$columns[] = 'dial_domain'; +$columns[] = 'do_not_disturb'; +$columns[] = 'forward_all_destination'; +$columns[] = 'forward_all_enabled'; +$columns[] = 'forward_busy_destination'; +$columns[] = 'forward_busy_enabled'; +$columns[] = 'forward_no_answer_destination'; +$columns[] = 'forward_no_answer_enabled'; +$columns[] = 'follow_me_uuid'; +$columns[] = 'enabled'; +$columns[] = 'description'; +$columns[] = 'forward_caller_id_uuid'; +$columns[] = 'absolute_codec_string'; +$columns[] = 'forward_user_not_registered_destination'; +$columns[] = 'forward_user_not_registered_enabled'; + +$c = 0; +$row_style["0"] = "row_style0"; +$row_style["1"] = "row_style1"; + +//begin the page content + require_once "resources/header.php"; + + echo "
\n"; + echo "\n"; + echo "\n"; + echo "\n"; + echo ""; + echo ""; + echo ""; + echo ""; + echo ""; + foreach ($columns as $value) { + echo "\n"; + echo " "; + echo " "; + echo " "; + echo ""; + if ($c==0) { $c=1; } else { $c=0; } + } + + echo " \n"; + echo " \n"; + echo " "; + + echo "
"; + echo " Column Name"; + echo " Description"; + echo "
"; + echo " $value"; + echo ""; + echo "
\n"; + echo "
"; + echo " \n"; + echo "
"; + echo "

"; + echo "
"; + +//include the footer + require_once "resources/footer.php"; +?> \ No newline at end of file diff --git a/app/extensions/extensions.php b/app/extensions/extensions.php index a2d7b28597..15619513ae 100644 --- a/app/extensions/extensions.php +++ b/app/extensions/extensions.php @@ -123,6 +123,9 @@ require_once "resources/paging.php"; echo " \n"; echo "
\n"; echo " \n"; + if (if_group("superadmin")) { + echo " \n"; + } echo " "; echo " "; echo " \n"; diff --git a/app/xml_cdr/xml_cdr_search.php b/app/xml_cdr/xml_cdr_search.php index 50c6e809f8..b01b99ae8c 100644 --- a/app/xml_cdr/xml_cdr_search.php +++ b/app/xml_cdr/xml_cdr_search.php @@ -53,8 +53,12 @@ echo " if ($('#caller_id_number').is(':visible')) { $('#caller_id_number').foc echo " }"; echo " }"; echo ""; - -echo "\n"; + +if (strlen(check_str($_GET['redirect'])) > 0) { + echo "\n"; +} else { + echo "\n"; +} echo "\n"; echo " \n"; diff --git a/app/xml_cdr/xml_cdr_statistics.php b/app/xml_cdr/xml_cdr_statistics.php index c274f921ab..8f829613e0 100644 --- a/app/xml_cdr/xml_cdr_statistics.php +++ b/app/xml_cdr/xml_cdr_statistics.php @@ -43,10 +43,14 @@ else { require_once "resources/header.php"; //page title and description + echo "
\n"; echo "\n"; echo " \n"; echo "
".$text['label-call-statistics']."\n"; + if (permission_exists('xml_cdr_search_advanced')) { + echo " \n"; + } if (permission_exists('xml_cdr_all')) { if ($_GET['showall'] != 'true') { echo "\n"; @@ -75,6 +79,7 @@ else { +
@@ -147,7 +152,17 @@ else { if (data.length > 0) $.plot($("#placeholder"), data, { yaxis: { min: 0 }, - xaxis: { tickDecimals: 0 } + 48 && $hours < 168) { + echo "xaxis: {mode: \"time\",timeformat: \"%m:%d\",minTickSize: [1, \"day\"]}"; + } else { + echo "xaxis: {mode: \"time\",timeformat: \"%m:%d\",minTickSize: [1, \"month\"]}"; + } + + ?> + }); } @@ -173,10 +188,10 @@ else { $i = 0; foreach ($stats as $row) { echo "\n"; - if ($i < 24) { + if ($i <= $hours) { echo " \n"; } - elseif ($i == 24) { + elseif ($i == $hours+1) { echo "

\n"; echo "\n"; echo "\n"; @@ -198,14 +213,14 @@ else { echo "\n"; echo " \n"; } - elseif ($i == 25) { + elseif ($i == $hours+2) { echo "\n"; echo " \n"; } - elseif ($i == 26) { + elseif ($i == $hours+3) { echo " \n"; } - if ($i < 24) { + if ($i <= $hours) { echo " \n"; echo " \n"; } diff --git a/app/xml_cdr/xml_cdr_statistics_inc.php b/app/xml_cdr/xml_cdr_statistics_inc.php index 7dfc6fc2b2..c6d48c64a2 100644 --- a/app/xml_cdr/xml_cdr_statistics_inc.php +++ b/app/xml_cdr/xml_cdr_statistics_inc.php @@ -34,7 +34,7 @@ else { exit; } -//show all call detail records to admin and superadmin. for everyone else show only the call details for extensions assigned to them +/*//show all call detail records to admin and superadmin. for everyone else show only the call details for extensions assigned to them if (!if_group("admin") && !if_group("superadmin")) { // select caller_id_number, destination_number from v_xml_cdr where domain_uuid = '' // and (caller_id_number = '1001' or destination_number = '1001' or destination_number = '*991001') @@ -68,6 +68,166 @@ else { //create the sql query to get the xml cdr records if (strlen($order_by) == 0) { $order_by = "start_epoch"; } if (strlen($order) == 0) { $order = "desc"; } +*/ + +//get post or get variables from http + if (count($_REQUEST) > 0) { + $cdr_id = check_str($_REQUEST["cdr_id"]); + $missed = check_str($_REQUEST["missed"]); + $direction = check_str($_REQUEST["direction"]); + $caller_id_name = check_str($_REQUEST["caller_id_name"]); + $caller_id_number = check_str($_REQUEST["caller_id_number"]); + $caller_extension_uuid = check_str($_REQUEST["caller_extension_uuid"]); + $destination_number = check_str($_REQUEST["destination_number"]); + $context = check_str($_REQUEST["context"]); + $start_stamp_begin = check_str($_REQUEST["start_stamp_begin"]); + $start_stamp_end = check_str($_REQUEST["start_stamp_end"]); + $answer_stamp_begin = check_str($_REQUEST["answer_stamp_begin"]); + $answer_stamp_end = check_str($_REQUEST["answer_stamp_end"]); + $end_stamp_begin = check_str($_REQUEST["end_stamp_begin"]); + $end_stamp_end = check_str($_REQUEST["end_stamp_end"]); + $start_epoch = check_str($_REQUEST["start_epoch"]); + $stop_epoch = check_str($_REQUEST["stop_epoch"]); + $duration = check_str($_REQUEST["duration"]); + $billsec = check_str($_REQUEST["billsec"]); + $hangup_cause = check_str($_REQUEST["hangup_cause"]); + $uuid = check_str($_REQUEST["uuid"]); + $bleg_uuid = check_str($_REQUEST["bleg_uuid"]); + $accountcode = check_str($_REQUEST["accountcode"]); + $read_codec = check_str($_REQUEST["read_codec"]); + $write_codec = check_str($_REQUEST["write_codec"]); + $remote_media_ip = check_str($_REQUEST["remote_media_ip"]); + $network_addr = check_str($_REQUEST["network_addr"]); + $bridge_uuid = check_str($_REQUEST["network_addr"]); + $order_by = check_str($_REQUEST["order_by"]); + $order = check_str($_REQUEST["order"]); + if (strlen(check_str($_REQUEST["mos_comparison"])) > 0) { + switch(check_str($_REQUEST["mos_comparison"])) { + case 'less': + $mos_comparison = "<"; + break; + case 'greater': + $mos_comparison = ">"; + break; + case 'lessorequal': + $mos_comparison = "<="; + break; + case 'greaterorequal': + $mos_comparison = ">="; + break; + case 'equal': + $mos_comparison = "<"; + break; + case 'notequal': + $mos_comparison = "<>"; + break; + } + } else { + $mos_comparison = ''; + } + //$mos_comparison = check_str($_REQUEST["mos_comparison"]); + $mos_score = check_str($_REQUEST["mos_score"]); + } + + + +//build the sql where string + if ($missed == true) { + $sql_where_ands[] = "billsec = '0'"; + } + if (strlen($start_epoch) > 0 && strlen($stop_epoch) > 0) { + $sql_where_ands[] = "start_epoch BETWEEN ".$start_epoch." AND ".$stop_epoch." "; + } + if (strlen($cdr_id) > 0) { $sql_where_ands[] = "cdr_id like '%".$cdr_id."%'"; } + if (strlen($direction) > 0) { $sql_where_ands[] = "direction = '".$direction."'"; } + if (strlen($caller_id_name) > 0) { + $mod_caller_id_name = str_replace("*", "%", $caller_id_name); + $sql_where_ands[] = "caller_id_name like '".$mod_caller_id_name."'"; + } + if (strlen($caller_extension_uuid) > 0) { + $sql_where_ands[] = "extension_uuid = '".$caller_extension_uuid."'"; + } + if (strlen($caller_id_number) > 0) { + $mod_caller_id_number = str_replace("*", "%", $caller_id_number); + $sql_where_ands[] = "caller_id_number like '".$mod_caller_id_number."'"; + } + if (strlen($destination_number) > 0) { + $mod_destination_number = str_replace("*", "%", $destination_number); + $sql_where_ands[] = "destination_number like '".$mod_destination_number."'"; + } + if (strlen($context) > 0) { $sql_where_ands[] = "context like '%".$context."%'"; } +/* if (strlen($start_stamp_begin) > 0 && strlen($start_stamp_end) > 0) { $sql_where_ands[] = "start_stamp BETWEEN '".$start_stamp_begin.":00.000' AND '".$start_stamp_end.":59.999'"; } + else { + if (strlen($start_stamp_begin) > 0) { $sql_where_ands[] = "start_stamp >= '".$start_stamp_begin.":00.000'"; } + if (strlen($start_stamp_end) > 0) { $sql_where_ands[] = "start_stamp <= '".$start_stamp_end.":59.999'"; } + } +*/ if (strlen($answer_stamp_begin) > 0 && strlen($answer_stamp_end) > 0) { $sql_where_ands[] = "answer_stamp BETWEEN '".$answer_stamp_begin.":00.000' AND '".$answer_stamp_end.":59.999'"; } + else { + if (strlen($answer_stamp_begin) > 0) { $sql_where_ands[] = "answer_stamp >= '".$answer_stamp_begin.":00.000'"; } + if (strlen($answer_stamp_end) > 0) { $sql_where_ands[] = "answer_stamp <= '".$answer_stamp_end.":59.999'"; } + } + if (strlen($end_stamp_begin) > 0 && strlen($end_stamp_end) > 0) { $sql_where_ands[] = "end_stamp BETWEEN '".$end_stamp_begin.":00.000' AND '".$end_stamp_end.":59.999'"; } + else { + if (strlen($end_stamp_begin) > 0) { $sql_where_ands[] = "end_stamp >= '".$end_stamp_begin.":00.000'"; } + if (strlen($end_stamp_end) > 0) { $sql_where_ands[] = "end_stamp <= '".$end_stamp_end.":59.999'"; } + } + if (strlen($duration) > 0) { $sql_where_ands[] = "duration like '%".$duration."%'"; } + if (strlen($billsec) > 0) { $sql_where_ands[] = "billsec like '%".$billsec."%'"; } + if (strlen($hangup_cause) > 0) { $sql_where_ands[] = "hangup_cause like '%".$hangup_cause."%'"; } + if (strlen($uuid) > 0) { $sql_where_ands[] = "uuid = '".$uuid."'"; } + if (strlen($bleg_uuid) > 0) { $sql_where_ands[] = "bleg_uuid = '".$bleg_uuid."'"; } + if (strlen($accountcode) > 0) { $sql_where_ands[] = "accountcode = '".$accountcode."'"; } + if (strlen($read_codec) > 0) { $sql_where_ands[] = "read_codec like '%".$read_codec."%'"; } + if (strlen($write_codec) > 0) { $sql_where_ands[] = "write_codec like '%".$write_codec."%'"; } + if (strlen($remote_media_ip) > 0) { $sql_where_ands[] = "remote_media_ip like '%".$remote_media_ip."%'"; } + if (strlen($network_addr) > 0) { $sql_where_ands[] = "network_addr like '%".$network_addr."%'"; } + if (strlen($mos_comparison) > 0 && strlen($mos_score) > 0 ) { $sql_where_ands[] = "rtp_audio_in_mos " . $mos_comparison . " ".$mos_score.""; } + + //if not admin or superadmin, only show own calls + if (!permission_exists('xml_cdr_domain')) { + if (count($_SESSION['user']['extension']) > 0) { // extensions are assigned to this user + // create simple user extension array + foreach ($_SESSION['user']['extension'] as $row) { $user_extensions[] = $row['user']; } + // if both a source and destination are submitted, but neither are an assigned extension, restrict results + if ( + $caller_id_number != '' && + $destination_number != '' && + array_search($caller_id_number, $user_extensions) === false && + array_search($destination_number, $user_extensions) === false + ) { + $sql_where_ors[] = "caller_id_number like '".$user_extension."'"; + $sql_where_ors[] = "destination_number like '".$user_extension."'"; + $sql_where_ors[] = "destination_number like '*99".$user_extension."'"; + } + // if source submitted is blank, implement restriction for assigned extension(s) + if ($caller_id_number == '') { // if source criteria is blank, then restrict to assigned ext + foreach ($user_extensions as $user_extension) { + if (strlen($user_extension) > 0) { $sql_where_ors[] = "caller_id_number like '".$user_extension."'"; } + } + } + // if destination submitted is blank, implement restriction for assigned extension(s) + if ($destination_number == '') { + foreach ($user_extensions as $user_extension) { + if (strlen($user_extension) > 0) { + $sql_where_ors[] = "destination_number like '".$user_extension."'"; + $sql_where_ors[] = "destination_number like '*99".$user_extension."'"; + } + } + } + // concatenate the 'or's array, then add to the 'and's array + if (sizeof($sql_where_ors) > 0) { + $sql_where_ands[] = "( ".implode(" or ", $sql_where_ors)." )"; + } + } + else { + $sql_where_ands[] = "1 <> 1"; //disable viewing of cdr records by users with no assigned extensions + } + } + + // concatenate the 'ands's array, add to where clause + if (sizeof($sql_where_ands) > 0) { + $sql_where = " where ".implode(" and ", $sql_where_ands)." and "; + } //calculate the seconds in different time frames $seconds_hour = 3600; @@ -89,6 +249,7 @@ else { $sql = "select count(*) as count from v_xml_cdr "; $sql .= $where; $sql .= " start_epoch BETWEEN ".$start." AND ".$end." "; + $prep_statement = $db->prepare(check_sql($sql)); $prep_statement->execute(); $result = $prep_statement->fetchAll(PDO::FETCH_ASSOC); @@ -141,11 +302,20 @@ else { //$call_seconds_1st_hour = get_call_seconds_between(3600, 0); //if (strlen($call_seconds_1st_hour) == 0) { $call_seconds_1st_hour = 0; } -//round down to the nearest hour - $time = time() - time() % 3600; + if (strlen(check_str($_GET['start_stamp_begin'])) > 0 && strlen(check_str($_GET['start_stamp_end'])) > 0 ) { + $start_date = new DateTime(check_str($_GET['start_stamp_begin'])); + $end_date = new DateTime(check_str($_GET['start_stamp_end'])); + $time = $end_date->getTimestamp(); + $time = $time - $time % 3600; + $hours = ($end_date->getTimestamp() - $start_date->getTimestamp()) / 3600; + } else { + //round down to the nearest hour + $time = time() - time() % 3600; + $hours = 23; + } //call info hour by hour - for ($i = 0; $i <= 23; $i++) { + for ($i = 0; $i <= $hours; $i++) { $start_epoch = $time - 3600*$i; $stop_epoch = $start_epoch + 3600; $stats[$i]['hours'] = $i + 1; @@ -153,7 +323,7 @@ else { $stats[$i]['stop_stamp'] = date('Y-m-d h:n:s', $stop_epoch); $stats[$i]['start_epoch'] = $start_epoch; $stats[$i]['stop_epoch'] = $stop_epoch; - $stats[$i]['volume'] = get_call_volume_between($stats[$i]['start_epoch'], $stats[$i]['stop_epoch'], ''); + $stats[$i]['volume'] = get_call_volume_between($stats[$i]['start_epoch'], $stats[$i]['stop_epoch'], $sql_where); $stats[$i]['seconds'] = get_call_seconds_between($stats[$i]['start_epoch'], $stats[$i]['stop_epoch'], ''); $stats[$i]['minutes'] = $stats[$i]['seconds'] / 60; $stats[$i]['avg_sec'] = $stats[$i]['seconds'] / $stats[$i]['volume']; @@ -175,7 +345,7 @@ else { } //call info for a day - $i = 24; + $i = $hours+1; $start_epoch = time() - $seconds_day; $stop_epoch = time(); $stats[$i]['hours'] = 24; @@ -183,7 +353,7 @@ else { $stats[$i]['stop_stamp'] = date('Y-m-d h:n:s', $stop_epoch); $stats[$i]['start_epoch'] = $start_epoch; $stats[$i]['stop_epoch'] = $stop_epoch; - $stats[$i]['volume'] = get_call_volume_between($stats[$i]['start_epoch'], $stats[$i]['stop_epoch'], ''); + $stats[$i]['volume'] = get_call_volume_between($stats[$i]['start_epoch'], $stats[$i]['stop_epoch'], $sql_where); $stats[$i]['seconds'] = get_call_seconds_between($stats[$i]['start_epoch'], $stats[$i]['stop_epoch'], ''); $stats[$i]['minutes'] = $stats[$i]['seconds'] / 60; $stats[$i]['avg_sec'] = $stats[$i]['seconds'] / $stats[$i]['volume']; @@ -208,7 +378,7 @@ else { $stats[$i]['stop_stamp'] = date('Y-m-d h:n:s', $stop_epoch); $stats[$i]['start_epoch'] = $start_epoch; $stats[$i]['stop_epoch'] = $stop_epoch; - $stats[$i]['volume'] = get_call_volume_between($stats[$i]['start_epoch'], $stats[$i]['stop_epoch'], ''); + $stats[$i]['volume'] = get_call_volume_between($stats[$i]['start_epoch'], $stats[$i]['stop_epoch'], $sql_where); $stats[$i]['seconds'] = get_call_seconds_between($stats[$i]['start_epoch'], $stats[$i]['stop_epoch'], ''); $stats[$i]['minutes'] = $stats[$i]['seconds'] / 60; $stats[$i]['avg_sec'] = $stats[$i]['seconds'] / $stats[$i]['volume']; @@ -233,7 +403,7 @@ else { $stats[$i]['stop_stamp'] = date('Y-m-d h:n:s', $stop_epoch); $stats[$i]['start_epoch'] = $start_epoch; $stats[$i]['stop_epoch'] = $stop_epoch; - $stats[$i]['volume'] = get_call_volume_between($stats[$i]['start_epoch'], $stats[$i]['stop_epoch'], ''); + $stats[$i]['volume'] = get_call_volume_between($stats[$i]['start_epoch'], $stats[$i]['stop_epoch'], $sql_where); $stats[$i]['seconds'] = get_call_seconds_between($stats[$i]['start_epoch'], $stats[$i]['stop_epoch'], ''); $stats[$i]['minutes'] = $stats[$i]['seconds'] / 60; $stats[$i]['avg_sec'] = $stats[$i]['seconds'] / $stats[$i]['volume']; @@ -251,47 +421,47 @@ else { $i++; //show the graph - $x = 0; - foreach ($stats as $row) { - $graph['volume'][$x][] = date('H', $row['start_epoch']); - $graph['volume'][$x][] = $row['volume']/1; - if ($x == 23) { break; } - $x++; - } - $x = 0; - foreach ($stats as $row) { - $graph['minutes'][$x][] = date('H', $row['start_epoch']); - $graph['minutes'][$x][] = round($row['minutes'],2); - if ($x == 23) { break; } - $x++; - } - $x = 0; - foreach ($stats as $row) { - $graph['call_per_min'][$x][] = date('H', $row['start_epoch']); - $graph['call_per_min'][$x][] = round($row['avg_min'],2); - if ($x == 23) { break; } - $x++; - } - $x = 0; - foreach ($stats as $row) { - $graph['missed'][$x][] = date('H', $row['start_epoch']); - $graph['missed'][$x][] = $row['missed']/1; - if ($x == 23) { break; } - $x++; - } - $x = 0; - foreach ($stats as $row) { - $graph['asr'][$x][] = date('H', $row['start_epoch']); - $graph['asr'][$x][] = round($row['asr'],2)/100; - if ($x == 23) { break; } - $x++; - } - $x = 0; - foreach ($stats as $row) { - $graph['aloc'][$x][] = date('H', $row['start_epoch']); - $graph['aloc'][$x][] = round($row['aloc'],2); - if ($x == 23) { break; } - $x++; - } + $x = 0; + foreach ($stats as $row) { + $graph['volume'][$x][] = $row['start_epoch'] * 1000; + $graph['volume'][$x][] = $row['volume']/1; + if ($x == $hours) { break; } + $x++; + } + $x = 0; + foreach ($stats as $row) { + $graph['minutes'][$x][] = $row['start_epoch'] * 1000; + $graph['minutes'][$x][] = round($row['minutes'],2); + if ($x == $hours) { break; } + $x++; + } + $x = 0; + foreach ($stats as $row) { + $graph['call_per_min'][$x][] = $row['start_epoch'] * 1000; + $graph['call_per_min'][$x][] = round($row['avg_min'],2); + if ($x == $hours) { break; } + $x++; + } + $x = 0; + foreach ($stats as $row) { + $graph['missed'][$x][] = $row['start_epoch'] * 1000; + $graph['missed'][$x][] = $row['missed']/1; + if ($x == $hours) { break; } + $x++; + } + $x = 0; + foreach ($stats as $row) { + $graph['asr'][$x][] = $row['start_epoch'] * 1000; + $graph['asr'][$x][] = round($row['asr'],2)/100; + if ($x == $hours) { break; } + $x++; + } + $x = 0; + foreach ($stats as $row) { + $graph['aloc'][$x][] = $row['start_epoch'] * 1000; + $graph['aloc'][$x][] = round($row['aloc'],2); + if ($x == $hours) { break; } + $x++; + } ?> \ No newline at end of file diff --git a/resources/jquery/flot/jquery.flot.time.js b/resources/jquery/flot/jquery.flot.time.js new file mode 100644 index 0000000000..b06cca72f0 --- /dev/null +++ b/resources/jquery/flot/jquery.flot.time.js @@ -0,0 +1,432 @@ +/* Pretty handling of time axes. + +Copyright (c) 2007-2014 IOLA and Ole Laursen. +Licensed under the MIT license. + +Set axis.mode to "time" to enable. See the section "Time series data" in +API.txt for details. + +*/ + +(function($) { + + var options = { + xaxis: { + timezone: null, // "browser" for local to the client or timezone for timezone-js + timeformat: null, // format string to use + twelveHourClock: false, // 12 or 24 time in time mode + monthNames: null // list of names of months + } + }; + + // round to nearby lower multiple of base + + function floorInBase(n, base) { + return base * Math.floor(n / base); + } + + // Returns a string with the date d formatted according to fmt. + // A subset of the Open Group's strftime format is supported. + + function formatDate(d, fmt, monthNames, dayNames) { + + if (typeof d.strftime == "function") { + return d.strftime(fmt); + } + + var leftPad = function(n, pad) { + n = "" + n; + pad = "" + (pad == null ? "0" : pad); + return n.length == 1 ? pad + n : n; + }; + + var r = []; + var escape = false; + var hours = d.getHours(); + var isAM = hours < 12; + + if (monthNames == null) { + monthNames = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]; + } + + if (dayNames == null) { + dayNames = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"]; + } + + var hours12; + + if (hours > 12) { + hours12 = hours - 12; + } else if (hours == 0) { + hours12 = 12; + } else { + hours12 = hours; + } + + for (var i = 0; i < fmt.length; ++i) { + + var c = fmt.charAt(i); + + if (escape) { + switch (c) { + case 'a': c = "" + dayNames[d.getDay()]; break; + case 'b': c = "" + monthNames[d.getMonth()]; break; + case 'd': c = leftPad(d.getDate()); break; + case 'e': c = leftPad(d.getDate(), " "); break; + case 'h': // For back-compat with 0.7; remove in 1.0 + case 'H': c = leftPad(hours); break; + case 'I': c = leftPad(hours12); break; + case 'l': c = leftPad(hours12, " "); break; + case 'm': c = leftPad(d.getMonth() + 1); break; + case 'M': c = leftPad(d.getMinutes()); break; + // quarters not in Open Group's strftime specification + case 'q': + c = "" + (Math.floor(d.getMonth() / 3) + 1); break; + case 'S': c = leftPad(d.getSeconds()); break; + case 'y': c = leftPad(d.getFullYear() % 100); break; + case 'Y': c = "" + d.getFullYear(); break; + case 'p': c = (isAM) ? ("" + "am") : ("" + "pm"); break; + case 'P': c = (isAM) ? ("" + "AM") : ("" + "PM"); break; + case 'w': c = "" + d.getDay(); break; + } + r.push(c); + escape = false; + } else { + if (c == "%") { + escape = true; + } else { + r.push(c); + } + } + } + + return r.join(""); + } + + // To have a consistent view of time-based data independent of which time + // zone the client happens to be in we need a date-like object independent + // of time zones. This is done through a wrapper that only calls the UTC + // versions of the accessor methods. + + function makeUtcWrapper(d) { + + function addProxyMethod(sourceObj, sourceMethod, targetObj, targetMethod) { + sourceObj[sourceMethod] = function() { + return targetObj[targetMethod].apply(targetObj, arguments); + }; + }; + + var utc = { + date: d + }; + + // support strftime, if found + + if (d.strftime != undefined) { + addProxyMethod(utc, "strftime", d, "strftime"); + } + + addProxyMethod(utc, "getTime", d, "getTime"); + addProxyMethod(utc, "setTime", d, "setTime"); + + var props = ["Date", "Day", "FullYear", "Hours", "Milliseconds", "Minutes", "Month", "Seconds"]; + + for (var p = 0; p < props.length; p++) { + addProxyMethod(utc, "get" + props[p], d, "getUTC" + props[p]); + addProxyMethod(utc, "set" + props[p], d, "setUTC" + props[p]); + } + + return utc; + }; + + // select time zone strategy. This returns a date-like object tied to the + // desired timezone + + function dateGenerator(ts, opts) { + if (opts.timezone == "browser") { + return new Date(ts); + } else if (!opts.timezone || opts.timezone == "utc") { + return makeUtcWrapper(new Date(ts)); + } else if (typeof timezoneJS != "undefined" && typeof timezoneJS.Date != "undefined") { + var d = new timezoneJS.Date(); + // timezone-js is fickle, so be sure to set the time zone before + // setting the time. + d.setTimezone(opts.timezone); + d.setTime(ts); + return d; + } else { + return makeUtcWrapper(new Date(ts)); + } + } + + // map of app. size of time units in milliseconds + + var timeUnitSize = { + "second": 1000, + "minute": 60 * 1000, + "hour": 60 * 60 * 1000, + "day": 24 * 60 * 60 * 1000, + "month": 30 * 24 * 60 * 60 * 1000, + "quarter": 3 * 30 * 24 * 60 * 60 * 1000, + "year": 365.2425 * 24 * 60 * 60 * 1000 + }; + + // the allowed tick sizes, after 1 year we use + // an integer algorithm + + var baseSpec = [ + [1, "second"], [2, "second"], [5, "second"], [10, "second"], + [30, "second"], + [1, "minute"], [2, "minute"], [5, "minute"], [10, "minute"], + [30, "minute"], + [1, "hour"], [2, "hour"], [4, "hour"], + [8, "hour"], [12, "hour"], + [1, "day"], [2, "day"], [3, "day"], + [0.25, "month"], [0.5, "month"], [1, "month"], + [2, "month"] + ]; + + // we don't know which variant(s) we'll need yet, but generating both is + // cheap + + var specMonths = baseSpec.concat([[3, "month"], [6, "month"], + [1, "year"]]); + var specQuarters = baseSpec.concat([[1, "quarter"], [2, "quarter"], + [1, "year"]]); + + function init(plot) { + plot.hooks.processOptions.push(function (plot, options) { + $.each(plot.getAxes(), function(axisName, axis) { + + var opts = axis.options; + + if (opts.mode == "time") { + axis.tickGenerator = function(axis) { + + var ticks = []; + var d = dateGenerator(axis.min, opts); + var minSize = 0; + + // make quarter use a possibility if quarters are + // mentioned in either of these options + + var spec = (opts.tickSize && opts.tickSize[1] === + "quarter") || + (opts.minTickSize && opts.minTickSize[1] === + "quarter") ? specQuarters : specMonths; + + if (opts.minTickSize != null) { + if (typeof opts.tickSize == "number") { + minSize = opts.tickSize; + } else { + minSize = opts.minTickSize[0] * timeUnitSize[opts.minTickSize[1]]; + } + } + + for (var i = 0; i < spec.length - 1; ++i) { + if (axis.delta < (spec[i][0] * timeUnitSize[spec[i][1]] + + spec[i + 1][0] * timeUnitSize[spec[i + 1][1]]) / 2 + && spec[i][0] * timeUnitSize[spec[i][1]] >= minSize) { + break; + } + } + + var size = spec[i][0]; + var unit = spec[i][1]; + + // special-case the possibility of several years + + if (unit == "year") { + + // if given a minTickSize in years, just use it, + // ensuring that it's an integer + + if (opts.minTickSize != null && opts.minTickSize[1] == "year") { + size = Math.floor(opts.minTickSize[0]); + } else { + + var magn = Math.pow(10, Math.floor(Math.log(axis.delta / timeUnitSize.year) / Math.LN10)); + var norm = (axis.delta / timeUnitSize.year) / magn; + + if (norm < 1.5) { + size = 1; + } else if (norm < 3) { + size = 2; + } else if (norm < 7.5) { + size = 5; + } else { + size = 10; + } + + size *= magn; + } + + // minimum size for years is 1 + + if (size < 1) { + size = 1; + } + } + + axis.tickSize = opts.tickSize || [size, unit]; + var tickSize = axis.tickSize[0]; + unit = axis.tickSize[1]; + + var step = tickSize * timeUnitSize[unit]; + + if (unit == "second") { + d.setSeconds(floorInBase(d.getSeconds(), tickSize)); + } else if (unit == "minute") { + d.setMinutes(floorInBase(d.getMinutes(), tickSize)); + } else if (unit == "hour") { + d.setHours(floorInBase(d.getHours(), tickSize)); + } else if (unit == "month") { + d.setMonth(floorInBase(d.getMonth(), tickSize)); + } else if (unit == "quarter") { + d.setMonth(3 * floorInBase(d.getMonth() / 3, + tickSize)); + } else if (unit == "year") { + d.setFullYear(floorInBase(d.getFullYear(), tickSize)); + } + + // reset smaller components + + d.setMilliseconds(0); + + if (step >= timeUnitSize.minute) { + d.setSeconds(0); + } + if (step >= timeUnitSize.hour) { + d.setMinutes(0); + } + if (step >= timeUnitSize.day) { + d.setHours(0); + } + if (step >= timeUnitSize.day * 4) { + d.setDate(1); + } + if (step >= timeUnitSize.month * 2) { + d.setMonth(floorInBase(d.getMonth(), 3)); + } + if (step >= timeUnitSize.quarter * 2) { + d.setMonth(floorInBase(d.getMonth(), 6)); + } + if (step >= timeUnitSize.year) { + d.setMonth(0); + } + + var carry = 0; + var v = Number.NaN; + var prev; + + do { + + prev = v; + v = d.getTime(); + ticks.push(v); + + if (unit == "month" || unit == "quarter") { + if (tickSize < 1) { + + // a bit complicated - we'll divide the + // month/quarter up but we need to take + // care of fractions so we don't end up in + // the middle of a day + + d.setDate(1); + var start = d.getTime(); + d.setMonth(d.getMonth() + + (unit == "quarter" ? 3 : 1)); + var end = d.getTime(); + d.setTime(v + carry * timeUnitSize.hour + (end - start) * tickSize); + carry = d.getHours(); + d.setHours(0); + } else { + d.setMonth(d.getMonth() + + tickSize * (unit == "quarter" ? 3 : 1)); + } + } else if (unit == "year") { + d.setFullYear(d.getFullYear() + tickSize); + } else { + d.setTime(v + step); + } + } while (v < axis.max && v != prev); + + return ticks; + }; + + axis.tickFormatter = function (v, axis) { + + var d = dateGenerator(v, axis.options); + + // first check global format + + if (opts.timeformat != null) { + return formatDate(d, opts.timeformat, opts.monthNames, opts.dayNames); + } + + // possibly use quarters if quarters are mentioned in + // any of these places + + var useQuarters = (axis.options.tickSize && + axis.options.tickSize[1] == "quarter") || + (axis.options.minTickSize && + axis.options.minTickSize[1] == "quarter"); + + var t = axis.tickSize[0] * timeUnitSize[axis.tickSize[1]]; + var span = axis.max - axis.min; + var suffix = (opts.twelveHourClock) ? " %p" : ""; + var hourCode = (opts.twelveHourClock) ? "%I" : "%H"; + var fmt; + + if (t < timeUnitSize.minute) { + fmt = hourCode + ":%M:%S" + suffix; + } else if (t < timeUnitSize.day) { + if (span < 2 * timeUnitSize.day) { + fmt = hourCode + ":%M" + suffix; + } else { + fmt = "%b %d " + hourCode + ":%M" + suffix; + } + } else if (t < timeUnitSize.month) { + fmt = "%b %d"; + } else if ((useQuarters && t < timeUnitSize.quarter) || + (!useQuarters && t < timeUnitSize.year)) { + if (span < timeUnitSize.year) { + fmt = "%b"; + } else { + fmt = "%b %Y"; + } + } else if (useQuarters && t < timeUnitSize.year) { + if (span < timeUnitSize.year) { + fmt = "Q%q"; + } else { + fmt = "Q%q %Y"; + } + } else { + fmt = "%Y"; + } + + var rt = formatDate(d, fmt, opts.monthNames, opts.dayNames); + + return rt; + }; + } + }); + }); + } + + $.plot.plugins.push({ + init: init, + options: options, + name: 'time', + version: '1.0' + }); + + // Time-axis support used to be in Flot core, which exposed the + // formatDate function on the plot object. Various plugins depend + // on the function, so we need to re-expose it here. + + $.plot.formatDate = formatDate; + $.plot.dateGenerator = dateGenerator; + +})(jQuery); \ No newline at end of file diff --git a/themes/enhanced/template.php b/themes/enhanced/template.php index 23aadd820a..1ff8bd9091 100644 --- a/themes/enhanced/template.php +++ b/themes/enhanced/template.php @@ -1254,6 +1254,10 @@ SPAN.playback_progress_bar { } }); + $("#selecctall").change(function(){ + $(".checkbox1").prop('checked', $(this).prop("checked")); + }); + // linkify rows (except the last - the list_control_icons cell) // on a table with a class of 'tr_hover', according to the href // attribute of the tag
".($i+1)."
1
730".date('j M', $row['start_epoch'])."".date('H:i', $row['start_epoch'])." - ".date('H:i', $row['stop_epoch'])."