2010-09-29 Joseph Pecoraro <joepeck@webkit.org>
[WebKit-https.git] / BugsSite / reports.cgi
index deeffff..5cd04bb 100755 (executable)
@@ -1,4 +1,4 @@
-#!/usr/bin/perl -wT
+#!/usr/bin/env perl -wT
 # -*- Mode: perl; indent-tabs-mode: nil -*-
 #
 # The contents of this file are subject to the Mozilla Public
 #    daily stats file, so now works independently of collectstats.pl
 #    version
 #    Added image caching by date and datasets
-# Myk Melez <myk@mozilla.org):
+# Myk Melez <myk@mozilla.org>:
 #    Implemented form field validation and reorganized code.
+# Frédéric Buclin <LpSolit@gmail.com>:
+#    Templatization.
 
 use strict;
 
-use lib qw(.);
+use lib qw(. lib);
 
-use Bugzilla::Config qw(:DEFAULT $datadir);
-
-require "CGI.pl";
-
-require "globals.pl";
-use vars qw(@legal_product); # globals from er, globals.pl
+use Bugzilla;
+use Bugzilla::Constants;
+use Bugzilla::Util;
+use Bugzilla::Error;
+use Bugzilla::Status;
 
 eval "use GD";
 $@ && ThrowCodeError("gd_not_installed");
 eval "use Chart::Lines";
 $@ && ThrowCodeError("chart_lines_not_installed");
 
-my $dir = "$datadir/mining";
-my $graph_dir = "graphs";
-
-use Bugzilla;
+my $dir       = bz_locations()->{'datadir'} . "/mining";
+my $graph_url = 'graphs';
+my $graph_dir = bz_locations()->{'libpath'} . '/' .$graph_url;
 
 # If we're using bug groups for products, we should apply those restrictions
 # to viewing reports, as well.  Time to check the login in that case.
-Bugzilla->login();
-
-GetVersionTable();
+my $user = Bugzilla->login();
 
 Bugzilla->switch_to_shadow_db();
 
 my $cgi = Bugzilla->cgi;
+my $template = Bugzilla->template;
+my $vars = {};
 
 # We only want those products that the user has permissions for.
 my @myproducts;
 push( @myproducts, "-All-");
-push( @myproducts, GetSelectableProducts());
+# Extract product names from objects and add them to the list.
+push( @myproducts, map { $_->name } @{$user->get_selectable_products} );
 
 if (! defined $cgi->param('product')) {
+    # Can we do bug charts?
+    (-d $dir && -d $graph_dir) 
+      || ThrowCodeError('chart_dir_nonexistent',
+                        {dir => $dir, graph_dir => $graph_dir});
 
-    choose_product(@myproducts);
-    PutFooter();
+    my %default_sel = map { $_ => 1 } BUG_STATE_OPEN;
 
-} else {
+    my @datasets;
+    my @data = get_data($dir);
+
+    foreach my $dataset (@data) {
+        my $datasets = {};
+        $datasets->{'value'} = $dataset;
+        $datasets->{'selected'} = $default_sel{$dataset} ? 1 : 0;
+        push(@datasets, $datasets);
+    }
+
+    $vars->{'datasets'} = \@datasets;
+    $vars->{'products'} = \@myproducts;
+
+    print $cgi->header();
+
+    $template->process('reports/old-charts.html.tmpl', $vars)
+      || ThrowTemplateError($template->error());
+    exit;
+}
+else {
     my $product = $cgi->param('product');
 
     # For security and correctness, validate the value of the "product" form variable.
@@ -87,92 +110,49 @@ if (! defined $cgi->param('product')) {
     # This means that is OK to detaint
     trick_taint($product);
 
-    print $cgi->header(-Content_Disposition=>'inline; filename=bugzilla_report.html');
+    defined($cgi->param('datasets')) || ThrowUserError('missing_datasets');
 
-    PutHeader("Bug Charts");
+    my $datasets = join('', $cgi->param('datasets'));
 
-    show_chart($product);
+    my $type = chart_image_type();
+    my $data_file = daily_stats_filename($product);
+    my $image_file = chart_image_name($data_file, $type, $datasets);
+    my $url_image = correct_urlbase() . "$graph_url/$image_file";
 
-    PutFooter();
+    if (! -e "$graph_dir/$image_file") {
+        generate_chart("$dir/$data_file", "$graph_dir/$image_file", $type,
+                       $product, $datasets);
+    }
+
+    $vars->{'url_image'} = $url_image;
+
+    print $cgi->header(-Content_Disposition=>'inline; filename=bugzilla_report.html');
+
+    $template->process('reports/old-charts.html.tmpl', $vars)
+      || ThrowTemplateError($template->error());
+    exit;
 }
 
+#####################
+#    Subroutines    #
+#####################
 
-##################################
-# user came in with no form data #
-##################################
+sub get_data {
+    my $dir = shift;
 
-sub choose_product {
-    my @myproducts = (@_);
-    
+    my @datasets;
     my $datafile = daily_stats_filename('-All-');
+    open(DATA, '<', "$dir/$datafile")
+      || ThrowCodeError('chart_file_open_fail', {filename => "$dir/$datafile"});
 
-    # Can we do bug charts?  
-    (-d $dir && -d $graph_dir) 
-      || ThrowCodeError("chart_dir_nonexistent", 
-                        {dir => $dir, graph_dir => $graph_dir});
-      
-    open(DATA, "$dir/$datafile")
-      || ThrowCodeError("chart_file_open_fail", {filename => "$dir/$datafile"});
-    print $cgi->header();
-    PutHeader("Bug Charts");
-
-    print <<FIN;
-<center>
-<h1>Welcome to the Bugzilla Charting Kitchen</h1>
-<form method=get action=reports.cgi>
-<table border=1 cellpadding=5>
-<tr>
-<td align=center><b>Product:</b></td>
-<td align=center>
-<select name="product">
-FIN
-foreach my $product (@myproducts) {
-    $product = html_quote($product);
-    print qq{<option value="$product">$product</option>};
-}
-print <<FIN;
-</select>
-</td>
-</tr>
-<tr>
-  <td align=center><b>Chart datasets:</b></td>
-  <td align=center>
-  <select name="datasets" multiple size=5>
-FIN
-
-      my @datasets = ();
-
-      while (<DATA>) {
-          if (/^# fields?: (.+)\s*$/) {
-              @datasets = grep ! /date/i, (split /\|/, $1);
-              last;
-          }
-      }
-
-      close(DATA);
-
-      my %default_sel = map { $_ => 1 }
-                            qw/UNCONFIRMED NEW ASSIGNED REOPENED/;
-      foreach my $dataset (@datasets) {
-          my $sel = $default_sel{$dataset} ? ' selected' : '';
-          print qq{<option value="$dataset:"$sel>$dataset</option>\n};
-      }
-
-      print <<FIN;
-      </select>
-      </td>
-      </tr>
-<tr>
-<td colspan=2 align=center>
-<input type=submit value=Continue>
-</td>
-</tr>
-</table>
-</center>
-</form>
-<p>
-FIN
+    while (<DATA>) {
+        if (/^# fields?: (.+)\s*$/) {
+            @datasets = grep ! /date/i, (split /\|/, $1);
+            last;
+        }
+    }
+    close(DATA);
+    return @datasets;
 }
 
 sub daily_stats_filename {
@@ -181,35 +161,6 @@ sub daily_stats_filename {
     return $prodname;
 }
 
-sub show_chart {
-    my ($product) = @_;
-
-    if (! defined $cgi->param('datasets')) {
-        ThrowUserError("missing_datasets");
-    }
-    my $datasets = join('', $cgi->param('datasets'));
-
-  print <<FIN;
-<center>
-FIN
-
-    my $type = chart_image_type();
-    my $data_file = daily_stats_filename($product);
-    my $image_file = chart_image_name($data_file, $type, $datasets);
-    my $url_image = "$graph_dir/" . url_quote($image_file);
-
-    if (! -e "$graph_dir/$image_file") {
-        generate_chart("$dir/$data_file", "$graph_dir/$image_file", $type,
-                       $product, $datasets);
-    }
-    
-    print <<FIN;
-<img src="$url_image">
-<br clear=left>
-<br>
-FIN
-}
-
 sub chart_image_type {
     # what chart type should we be generating?
     my $testimg = Chart::Lines->new(2,2);
@@ -226,11 +177,11 @@ sub chart_image_name {
     # is that we have to check the safety of doing this. We can't just require
     # that the fields exist, because what stats were collected could change
     # over time (eg by changing the resolutions available)
-    # Instead, just require that each field name consists only of letters
-    # and number
+    # Instead, just require that each field name consists only of letters,
+    # numbers, underscores and hyphens.
 
-    if ($datasets !~ m/^[A-Za-z0-9:]+$/) {
-        die "Invalid datasets $datasets";
+    if ($datasets !~ m/^[A-Za-z0-9:_-]+$/) {
+        ThrowUserError('invalid_datasets', {'datasets' => $datasets});
     }
 
     # Since we pass the tests, consider it OK
@@ -243,18 +194,14 @@ sub chart_image_name {
     return "${data_file}_${id}.$type";
 }
 
-sub day_of_year {
-    my ($mday, $month, $year) = (localtime())[3 .. 5];
-    $month += 1;
-    $year += 1900;
-    my $date = sprintf "%02d%02d%04d", $mday, $month, $year;
-}
-
 sub generate_chart {
     my ($data_file, $image_file, $type, $product, $datasets) = @_;
-    
+
     if (! open FILE, $data_file) {
-        ThrowCodeError("chart_data_not_generated");
+        if ($product eq '-All-') {
+            $product = '';
+        }
+        ThrowCodeError('chart_data_not_generated', {'product' => $product});
     }
 
     my @fields;
@@ -268,16 +215,19 @@ sub generate_chart {
         if (/^#/) {
             if (/^# fields?: (.*)\s*$/) {
                 @fields = split /\||\r/, $1;
-                ThrowCodeError("chart_datafile_corrupt", {file => $data_file})
-                  unless $fields[0] =~ /date/i;
+                $data{$_} ||= [] foreach @fields;
+                unless ($fields[0] =~ /date/i) {
+                    ThrowCodeError('chart_datafile_corrupt', {'file' => $data_file});
+                }
                 push @labels, grep($datasets{$_}, @fields);
             }
             next;
         }
 
-        ThrowCodeError("chart_datafile_corrupt", {file => $data_file})
-          unless @fields;
-        
+        unless (@fields) {
+            ThrowCodeError('chart_datafile_corrupt', {'file' => $data_file});
+        }
+
         my @line = split /\|/;
         my $date = $line[0];
         my ($yy, $mm, $dd) = $date =~ /^\d{2}(\d{2})(\d{2})(\d{2})$/;
@@ -302,9 +252,9 @@ sub generate_chart {
     close FILE;
 
     if (! @{$data{DATE}}) {
-        ThrowUserError("insufficient_data_points");
+        ThrowUserError('insufficient_data_points');
     }
-    
+
     my $img = Chart::Lines->new (800, 600);
     my $i = 0;