From 21b50cba4e08e723f8c2d8e8b5800d0a13e2c180 Mon Sep 17 00:00:00 2001 From: Gervase Markham Date: Wed, 2 Jan 2013 17:09:36 +0000 Subject: Bug 413851 - add CSV output option to request lists. r=LpSolit. --- Bugzilla/CGI.pm | 25 ++++++++++++++++ buglist.cgi | 31 +++++++------------ report.cgi | 7 ++--- request.cgi | 15 +++++++--- template/en/default/request/queue.csv.tmpl | 46 +++++++++++++++++++++++++++++ template/en/default/request/queue.html.tmpl | 6 ++-- 6 files changed, 99 insertions(+), 31 deletions(-) create mode 100644 template/en/default/request/queue.csv.tmpl diff --git a/Bugzilla/CGI.pm b/Bugzilla/CGI.pm index cb92800f1..513babd4f 100644 --- a/Bugzilla/CGI.pm +++ b/Bugzilla/CGI.pm @@ -281,6 +281,10 @@ sub header { unshift(@_, '-type' => shift(@_)); } + if ($self->{'_content_disp'}) { + unshift(@_, '-content_disposition' => $self->{'_content_disp'}); + } + # Add the cookies in if we have any if (scalar(@{$self->{Bugzilla_cookie_list}})) { unshift(@_, '-cookie' => $self->{Bugzilla_cookie_list}); @@ -528,6 +532,22 @@ sub url_is_attachment_base { return ($self->self_url =~ $regex) ? 1 : 0; } +sub set_dated_content_disp { + my ($self, $type, $prefix, $ext) = @_; + + my @time = localtime(time()); + my $date = sprintf "%04d-%02d-%02d", 1900+$time[5], $time[4]+1, $time[3]; + my $filename = "$prefix-$date.$ext"; + + $filename =~ s/\s/_/g; # Remove whitespace to avoid HTTP header tampering + $filename =~ s/\\/_/g; # Remove backslashes as well + $filename =~ s/"/\\"/g; # escape quotes + + my $disposition = "$type; filename=\"$filename\""; + + $self->{'_content_disp'} = $disposition; +} + ########################## # Vars TIEHASH Interface # ########################## @@ -635,6 +655,11 @@ instead of calling this directly. Redirects from the current URL to one prefixed by the urlbase parameter. +=item C + +Sets an appropriate date-dependent value for the Content Disposition header +for a downloadable resource. + =back =head1 SEE ALSO diff --git a/buglist.cgi b/buglist.cgi index a59f0ee18..8a436a0a2 100755 --- a/buglist.cgi +++ b/buglist.cgi @@ -281,18 +281,17 @@ sub GetGroups { } sub _close_standby_message { - my ($contenttype, $disposition, $serverpush) = @_; + my ($contenttype, $disp, $disp_prefix, $extension, $serverpush) = @_; my $cgi = Bugzilla->cgi; - + $cgi->set_dated_content_disp($disp, $disp_prefix, $extension); + # Close the "please wait" page, then open the buglist page if ($serverpush) { print $cgi->multipart_end(); - print $cgi->multipart_start(-type => $contenttype, - -content_disposition => $disposition); + print $cgi->multipart_start(-type => $contenttype); } else { - print $cgi->header(-type => $contenttype, - -content_disposition => $disposition); + print $cgi->header($contenttype); } } @@ -324,17 +323,10 @@ $params ||= new Bugzilla::CGI($cgi); # if available. We have to do this now, even though we return HTTP headers # at the end, because the fact that there is a remembered query gets # forgotten in the process of retrieving it. -my @time = localtime(time()); -my $date = sprintf "%04d-%02d-%02d", 1900+$time[5],$time[4]+1,$time[3]; -my $filename = "bugs-$date.$format->{extension}"; +my $disp_prefix = "bugs"; if ($cmdtype eq "dorem" && $remaction =~ /^run/) { - $filename = $cgi->param('namedcmd') . "-$date.$format->{extension}"; - # Remove white-space from the filename so the user cannot tamper - # with the HTTP headers. - $filename =~ s/\s/_/g; + $disp_prefix = $cgi->param('namedcmd'); } -$filename =~ s/\\/\\\\/g; # escape backslashes -$filename =~ s/"/\\"/g; # escape quotes # Take appropriate action based on user's request. if ($cmdtype eq "dorem") { @@ -935,7 +927,8 @@ if ($one_product && $user->can_enter_product($one_product)) { # The following variables are used when the user is making changes to multiple bugs. if ($dotweak && scalar @bugs) { if (!$vars->{'caneditbugs'}) { - _close_standby_message('text/html', 'inline', $serverpush); + _close_standby_message('text/html', + 'inline', "error", "html", $serverpush); ThrowUserError('auth_failure', {group => 'editbugs', action => 'modify', object => 'multiple_bugs'}); @@ -1042,10 +1035,8 @@ if ($format->{'extension'} eq "csv") { $vars->{'human'} = $cgi->param('human'); } -# Suggest a name for the bug list if the user wants to save it as a file. -$disposition .= "; filename=\"$filename\""; - -_close_standby_message($contenttype, $disposition, $serverpush); +_close_standby_message($contenttype, $disposition, $disp_prefix, + $format->{'extension'}, $serverpush); ################################################################################ # Content Generation diff --git a/report.cgi b/report.cgi index e70dcf4b2..69aadddbd 100755 --- a/report.cgi +++ b/report.cgi @@ -309,11 +309,8 @@ my $format = $template->get_format("reports/report", $formatparam, # set debug=1 to always get an HTML content-type, and view the error. $format->{'ctype'} = "text/html" if $cgi->param('debug'); -my @time = localtime(time()); -my $date = sprintf "%04d-%02d-%02d", 1900+$time[5],$time[4]+1,$time[3]; -my $filename = "report-$date.$format->{extension}"; -print $cgi->header(-type => $format->{'ctype'}, - -content_disposition => "inline; filename=$filename"); +$cgi->set_dated_content_disp("inline", "report", $format->{extension}); +print $cgi->header($format->{'ctype'}); # Problems with this CGI are often due to malformed data. Setting debug=1 # prints out both data structures. diff --git a/request.cgi b/request.cgi index 17e6c926d..436f94bc4 100755 --- a/request.cgi +++ b/request.cgi @@ -26,8 +26,12 @@ my $cgi = Bugzilla->cgi; Bugzilla->switch_to_shadow_db; my $template = Bugzilla->template; my $action = $cgi->param('action') || ''; +my $format = $template->get_format('request/queue', + scalar($cgi->param('format')), + scalar($cgi->param('ctype'))); -print $cgi->header(); +$cgi->set_dated_content_disp("inline", "requests", $format->{extension}); +print $cgi->header($format->{'ctype'}); my $fields; $fields->{'requester'}->{'type'} = 'single'; @@ -42,7 +46,7 @@ unless (defined $cgi->param('requestee') Bugzilla::User::match_field($fields); if ($action eq 'queue') { - queue(); + queue($format); } else { my $flagtypes = get_flag_types(); @@ -60,7 +64,7 @@ else { } $vars->{'components'} = [ sort { $a cmp $b } keys %components ]; - $template->process('request/queue.html.tmpl', $vars) + $template->process($format->{'template'}, $vars) || ThrowTemplateError($template->error()); } exit; @@ -70,6 +74,7 @@ exit; ################################################################################ sub queue { + my $format = shift; my $cgi = Bugzilla->cgi; my $dbh = Bugzilla->dbh; my $template = Bugzilla->template; @@ -295,8 +300,10 @@ sub queue { } $vars->{'components'} = [ sort { $a cmp $b } keys %components ]; + $vars->{'urlquerypart'} = $cgi->canonicalise_query('ctype'); + # Generate and return the UI (HTML page) from the appropriate template. - $template->process("request/queue.html.tmpl", $vars) + $template->process($format->{'template'}, $vars) || ThrowTemplateError($template->error()); } diff --git a/template/en/default/request/queue.csv.tmpl b/template/en/default/request/queue.csv.tmpl new file mode 100644 index 000000000..c6d962b4f --- /dev/null +++ b/template/en/default/request/queue.csv.tmpl @@ -0,0 +1,46 @@ +[%# This Source Code Form is subject to the terms of the Mozilla Public + # License, v. 2.0. If a copy of the MPL was not distributed with this + # file, You can obtain one at http://mozilla.org/MPL/2.0/. + # + # This Source Code Form is "Incompatible With Secondary Licenses", as + # defined by the Mozilla Public License, v. 2.0. #%] + +[% PROCESS "global/field-descs.none.tmpl" %] + +[% column_headers = { + "type" => "Flag", + "status" => field_descs.bug_status, + "bug_summary" => field_descs.short_desc, + "bug_id" => field_descs.bug_id, + "attach_summary" => "Attachment Description", + "attach_id" => "Attachment ID", + "requester" => "Requester", + "requestee" => "Requestee", + "created" => "Created", + "category" => field_descs.product _ ": " _ field_descs.component, +} %] + +[% display_columns = ["requester", "requestee", "type", "status", + "bug_id", "bug_summary", "attach_id", + "attach_summary", "created", "category"] %] + +[% IF requests.size == 0 %] +No requests. +[% ELSE %] + [% FOREACH column = display_columns %] + [% column_headers.$column FILTER csv %][% ',' IF NOT loop.last() %] + [% END %] + + [% FOREACH request = requests %] + [% FOREACH column = display_columns %] + [% IF column == 'created' %] + [% request.$column FILTER time FILTER csv %] + [% ELSIF column.match('^requeste') %] + [% request.$column FILTER email FILTER csv %] + [% ELSE %] + [% request.$column FILTER csv %] + [% END %][% ',' IF NOT loop.last() %] + [% END %] + + [% END %] +[% END %] diff --git a/template/en/default/request/queue.html.tmpl b/template/en/default/request/queue.html.tmpl index c2dc9809a..676e89264 100644 --- a/template/en/default/request/queue.html.tmpl +++ b/template/en/default/request/queue.html.tmpl @@ -207,6 +207,8 @@ to some group are shown by default. [% END %] [% PROCESS display_buglist %] +

+ View entire list as CSV [% END %] [% PROCESS global/footer.html.tmpl %] @@ -264,6 +266,6 @@ to some group are shown by default. [% NEXT UNLESS buglist.keys.size %] (view as - [%+ terms.bug %] list) + [%- buglist.keys.nsort.join(",") FILTER html %]">View as + [%+ terms.bug %] list [% END %] -- cgit v1.2.3-24-g4f1b