diff options
Diffstat (limited to 'chart.cgi')
-rwxr-xr-x | chart.cgi | 410 |
1 files changed, 212 insertions, 198 deletions
@@ -46,26 +46,27 @@ use Bugzilla::Token; # when preparing Bugzilla for mod_perl, this script used these # variables in so many subroutines that it was easier to just # make them globals. -local our $cgi = Bugzilla->cgi; +local our $cgi = Bugzilla->cgi; local our $template = Bugzilla->template; -local our $vars = {}; +local our $vars = {}; my $dbh = Bugzilla->dbh; my $user = Bugzilla->login(LOGIN_REQUIRED); if (!Bugzilla->feature('new_charts')) { - ThrowUserError('feature_disabled', { feature => 'new_charts' }); + ThrowUserError('feature_disabled', {feature => 'new_charts'}); } # Go back to query.cgi if we are adding a boolean chart parameter. if (grep(/^cmd-/, $cgi->param())) { - my $params = $cgi->canonicalise_query("format", "ctype", "action"); - print $cgi->redirect("query.cgi?format=" . $cgi->param('query_format') . - ($params ? "&$params" : "")); - exit; + my $params = $cgi->canonicalise_query("format", "ctype", "action"); + print $cgi->redirect("query.cgi?format=" + . $cgi->param('query_format') + . ($params ? "&$params" : "")); + exit; } -my $action = $cgi->param('action'); +my $action = $cgi->param('action'); my $series_id = $cgi->param('series_id'); $vars->{'doc_section'} = 'using/reports-and-charts.html#charts'; @@ -75,283 +76,296 @@ $vars->{'doc_section'} = 'using/reports-and-charts.html#charts'; # series_id they apply to (e.g. subscribe, unsubscribe). my @actions = grep(/^action-/, $cgi->param()); if ($actions[0] && $actions[0] =~ /^action-([^\d]+)(\d*)$/) { - $action = $1; - $series_id = $2 if $2; + $action = $1; + $series_id = $2 if $2; } $action ||= "assemble"; # Go to buglist.cgi if we are doing a search. if ($action eq "search") { - my $params = $cgi->canonicalise_query("format", "ctype", "action"); - print $cgi->redirect("buglist.cgi" . ($params ? "?$params" : "")); - exit; + my $params = $cgi->canonicalise_query("format", "ctype", "action"); + print $cgi->redirect("buglist.cgi" . ($params ? "?$params" : "")); + exit; } -$user->in_group(Bugzilla->params->{"chartgroup"}) - || ThrowUserError("auth_failure", {group => Bugzilla->params->{"chartgroup"}, - action => "use", - object => "charts"}); +$user->in_group(Bugzilla->params->{"chartgroup"}) || ThrowUserError( + "auth_failure", + { + group => Bugzilla->params->{"chartgroup"}, + action => "use", + object => "charts" + } +); # Only admins may create public queries $user->in_group('admin') || $cgi->delete('public'); # All these actions relate to chart construction. if ($action =~ /^(assemble|add|remove|sum|subscribe|unsubscribe)$/) { - # These two need to be done before the creation of the Chart object, so - # that the changes they make will be reflected in it. - if ($action =~ /^subscribe|unsubscribe$/) { - detaint_natural($series_id) || ThrowCodeError("invalid_series_id"); - my $series = new Bugzilla::Series($series_id); - $series->$action($user->id); - } - - my $chart = new Bugzilla::Chart($cgi); - if ($action =~ /^remove|sum$/) { - $chart->$action(getSelectedLines()); - } - elsif ($action eq "add") { - my @series_ids = getAndValidateSeriesIDs(); - $chart->add(@series_ids); - } - - view($chart); + # These two need to be done before the creation of the Chart object, so + # that the changes they make will be reflected in it. + if ($action =~ /^subscribe|unsubscribe$/) { + detaint_natural($series_id) || ThrowCodeError("invalid_series_id"); + my $series = new Bugzilla::Series($series_id); + $series->$action($user->id); + } + + my $chart = new Bugzilla::Chart($cgi); + + if ($action =~ /^remove|sum$/) { + $chart->$action(getSelectedLines()); + } + elsif ($action eq "add") { + my @series_ids = getAndValidateSeriesIDs(); + $chart->add(@series_ids); + } + + view($chart); } elsif ($action eq "plot") { - plot(); + plot(); } elsif ($action eq "wrap") { - # For CSV "wrap", we go straight to "plot". - if ($cgi->param('ctype') && $cgi->param('ctype') eq "csv") { - plot(); - } - else { - wrap(); - } + + # For CSV "wrap", we go straight to "plot". + if ($cgi->param('ctype') && $cgi->param('ctype') eq "csv") { + plot(); + } + else { + wrap(); + } } elsif ($action eq "create") { - assertCanCreate($cgi); - my $token = $cgi->param('token'); - check_hash_token($token, ['create-series']); - - my $series = new Bugzilla::Series($cgi); + assertCanCreate($cgi); + my $token = $cgi->param('token'); + check_hash_token($token, ['create-series']); - ThrowUserError("series_already_exists", {'series' => $series}) - if $series->existsInDatabase; + my $series = new Bugzilla::Series($cgi); - $series->writeToDatabase(); - $vars->{'message'} = "series_created"; - $vars->{'series'} = $series; + ThrowUserError("series_already_exists", {'series' => $series}) + if $series->existsInDatabase; - my $chart = new Bugzilla::Chart($cgi); - view($chart); + $series->writeToDatabase(); + $vars->{'message'} = "series_created"; + $vars->{'series'} = $series; + + my $chart = new Bugzilla::Chart($cgi); + view($chart); } elsif ($action eq "edit") { - my $series = assertCanEdit($series_id); - edit($series); + my $series = assertCanEdit($series_id); + edit($series); } elsif ($action eq "alter") { - my $series = assertCanEdit($series_id); - my $token = $cgi->param('token'); - check_hash_token($token, [$series->id, $series->name]); - # XXX - This should be replaced by $series->set_foo() methods. - $series = new Bugzilla::Series($cgi); - - # We need to check if there is _another_ series in the database with - # our (potentially new) name. So we call existsInDatabase() to see if - # the return value is us or some other series we need to avoid stomping - # on. - my $id_of_series_in_db = $series->existsInDatabase(); - if (defined($id_of_series_in_db) && - $id_of_series_in_db != $series->{'series_id'}) - { - ThrowUserError("series_already_exists", {'series' => $series}); - } - - $series->writeToDatabase(); - $vars->{'changes_saved'} = 1; - - edit($series); + my $series = assertCanEdit($series_id); + my $token = $cgi->param('token'); + check_hash_token($token, [$series->id, $series->name]); + + # XXX - This should be replaced by $series->set_foo() methods. + $series = new Bugzilla::Series($cgi); + + # We need to check if there is _another_ series in the database with + # our (potentially new) name. So we call existsInDatabase() to see if + # the return value is us or some other series we need to avoid stomping + # on. + my $id_of_series_in_db = $series->existsInDatabase(); + if (defined($id_of_series_in_db) + && $id_of_series_in_db != $series->{'series_id'}) + { + ThrowUserError("series_already_exists", {'series' => $series}); + } + + $series->writeToDatabase(); + $vars->{'changes_saved'} = 1; + + edit($series); } elsif ($action eq "confirm-delete") { - $vars->{'series'} = assertCanEdit($series_id); + $vars->{'series'} = assertCanEdit($series_id); - print $cgi->header(); - $template->process("reports/delete-series.html.tmpl", $vars) - || ThrowTemplateError($template->error()); + print $cgi->header(); + $template->process("reports/delete-series.html.tmpl", $vars) + || ThrowTemplateError($template->error()); } elsif ($action eq "delete") { - my $series = assertCanEdit($series_id); - my $token = $cgi->param('token'); - check_hash_token($token, [$series->id, $series->name]); - - $dbh->bz_start_transaction(); - - $series->remove_from_db(); - # Remove (sub)categories which no longer have any series. - foreach my $cat (qw(category subcategory)) { - my $is_used = $dbh->selectrow_array("SELECT COUNT(*) FROM series WHERE $cat = ?", - undef, $series->{"${cat}_id"}); - if (!$is_used) { - $dbh->do('DELETE FROM series_categories WHERE id = ?', - undef, $series->{"${cat}_id"}); - } + my $series = assertCanEdit($series_id); + my $token = $cgi->param('token'); + check_hash_token($token, [$series->id, $series->name]); + + $dbh->bz_start_transaction(); + + $series->remove_from_db(); + + # Remove (sub)categories which no longer have any series. + foreach my $cat (qw(category subcategory)) { + my $is_used + = $dbh->selectrow_array("SELECT COUNT(*) FROM series WHERE $cat = ?", + undef, $series->{"${cat}_id"}); + if (!$is_used) { + $dbh->do('DELETE FROM series_categories WHERE id = ?', + undef, $series->{"${cat}_id"}); } - $dbh->bz_commit_transaction(); + } + $dbh->bz_commit_transaction(); - $vars->{'message'} = "series_deleted"; - $vars->{'series'} = $series; - view(); + $vars->{'message'} = "series_deleted"; + $vars->{'series'} = $series; + view(); } elsif ($action eq "convert_search") { - my $saved_search = $cgi->param('series_from_search') || ''; - my ($query) = grep { $_->name eq $saved_search } @{ $user->queries }; - my $url = ''; - if ($query) { - my $params = new Bugzilla::CGI($query->edit_link); - # These two parameters conflict with the one below. - $url = $params->canonicalise_query('format', 'query_format'); - $url = '&' . html_quote($url); - } - print $cgi->redirect(-location => correct_urlbase() . "query.cgi?format=create-series$url"); + my $saved_search = $cgi->param('series_from_search') || ''; + my ($query) = grep { $_->name eq $saved_search } @{$user->queries}; + my $url = ''; + if ($query) { + my $params = new Bugzilla::CGI($query->edit_link); + + # These two parameters conflict with the one below. + $url = $params->canonicalise_query('format', 'query_format'); + $url = '&' . html_quote($url); + } + print $cgi->redirect( + -location => correct_urlbase() . "query.cgi?format=create-series$url"); } else { - ThrowUserError('unknown_action', {action => $action}); + ThrowUserError('unknown_action', {action => $action}); } exit; # Find any selected series and return either the first or all of them. sub getAndValidateSeriesIDs { - my @series_ids = grep(/^\d+$/, $cgi->param("name")); + my @series_ids = grep(/^\d+$/, $cgi->param("name")); - return wantarray ? @series_ids : $series_ids[0]; + return wantarray ? @series_ids : $series_ids[0]; } # Return a list of IDs of all the lines selected in the UI. sub getSelectedLines { - my @ids = map { /^select(\d+)$/ ? $1 : () } $cgi->param(); + my @ids = map { /^select(\d+)$/ ? $1 : () } $cgi->param(); - return @ids; + return @ids; } -# Check if the user is the owner of series_id or is an admin. +# Check if the user is the owner of series_id or is an admin. sub assertCanEdit { - my $series_id = shift; - my $user = Bugzilla->user; + my $series_id = shift; + my $user = Bugzilla->user; - my $series = new Bugzilla::Series($series_id) - || ThrowCodeError('invalid_series_id'); + my $series + = new Bugzilla::Series($series_id) || ThrowCodeError('invalid_series_id'); - if (!$user->in_group('admin') && $series->{creator_id} != $user->id) { - ThrowUserError('illegal_series_edit'); - } + if (!$user->in_group('admin') && $series->{creator_id} != $user->id) { + ThrowUserError('illegal_series_edit'); + } - return $series; + return $series; } # Check if the user is permitted to create this series with these parameters. sub assertCanCreate { - my ($cgi) = shift; - my $user = Bugzilla->user; + my ($cgi) = shift; + my $user = Bugzilla->user; - $user->in_group("editbugs") || ThrowUserError("illegal_series_creation"); + $user->in_group("editbugs") || ThrowUserError("illegal_series_creation"); - # Check permission for frequency - my $min_freq = 7; - if ($cgi->param('frequency') < $min_freq && !$user->in_group("admin")) { - ThrowUserError("illegal_frequency", { 'minimum' => $min_freq }); - } + # Check permission for frequency + my $min_freq = 7; + if ($cgi->param('frequency') < $min_freq && !$user->in_group("admin")) { + ThrowUserError("illegal_frequency", {'minimum' => $min_freq}); + } } sub validateWidthAndHeight { - $vars->{'width'} = $cgi->param('width'); - $vars->{'height'} = $cgi->param('height'); - - if (defined($vars->{'width'})) { - (detaint_natural($vars->{'width'}) && $vars->{'width'} > 0) - || ThrowUserError("invalid_dimensions"); - } - - if (defined($vars->{'height'})) { - (detaint_natural($vars->{'height'}) && $vars->{'height'} > 0) - || ThrowUserError("invalid_dimensions"); - } - - # The equivalent of 2000 square seems like a very reasonable maximum size. - # This is merely meant to prevent accidental or deliberate DOS, and should - # have no effect in practice. - if ($vars->{'width'} && $vars->{'height'}) { - (($vars->{'width'} * $vars->{'height'}) <= 4000000) - || ThrowUserError("chart_too_large"); - } + $vars->{'width'} = $cgi->param('width'); + $vars->{'height'} = $cgi->param('height'); + + if (defined($vars->{'width'})) { + (detaint_natural($vars->{'width'}) && $vars->{'width'} > 0) + || ThrowUserError("invalid_dimensions"); + } + + if (defined($vars->{'height'})) { + (detaint_natural($vars->{'height'}) && $vars->{'height'} > 0) + || ThrowUserError("invalid_dimensions"); + } + + # The equivalent of 2000 square seems like a very reasonable maximum size. + # This is merely meant to prevent accidental or deliberate DOS, and should + # have no effect in practice. + if ($vars->{'width'} && $vars->{'height'}) { + (($vars->{'width'} * $vars->{'height'}) <= 4000000) + || ThrowUserError("chart_too_large"); + } } sub edit { - my $series = shift; + my $series = shift; - $vars->{'category'} = Bugzilla::Chart::getVisibleSeries(); - $vars->{'default'} = $series; - $vars->{'message'} = 'series_updated' if $vars->{'changes_saved'}; + $vars->{'category'} = Bugzilla::Chart::getVisibleSeries(); + $vars->{'default'} = $series; + $vars->{'message'} = 'series_updated' if $vars->{'changes_saved'}; - print $cgi->header(); - $template->process("reports/edit-series.html.tmpl", $vars) - || ThrowTemplateError($template->error()); + print $cgi->header(); + $template->process("reports/edit-series.html.tmpl", $vars) + || ThrowTemplateError($template->error()); } sub plot { - validateWidthAndHeight(); - $vars->{'chart'} = new Bugzilla::Chart($cgi); + validateWidthAndHeight(); + $vars->{'chart'} = new Bugzilla::Chart($cgi); - my $format = $template->get_format("reports/chart", "", scalar($cgi->param('ctype'))); - $format->{'ctype'} = 'text/html' if $cgi->param('debug'); + my $format + = $template->get_format("reports/chart", "", scalar($cgi->param('ctype'))); + $format->{'ctype'} = 'text/html' if $cgi->param('debug'); - $cgi->set_dated_content_disp('inline', 'chart', $format->{extension}); - print $cgi->header($format->{'ctype'}); - disable_utf8() if ($format->{'ctype'} =~ /^image\//); + $cgi->set_dated_content_disp('inline', 'chart', $format->{extension}); + print $cgi->header($format->{'ctype'}); + disable_utf8() if ($format->{'ctype'} =~ /^image\//); - # Debugging PNGs is a pain; we need to be able to see the error messages - $vars->{'chart'}->dump() if $cgi->param('debug'); + # Debugging PNGs is a pain; we need to be able to see the error messages + $vars->{'chart'}->dump() if $cgi->param('debug'); - $template->process($format->{'template'}, $vars) - || ThrowTemplateError($template->error()); + $template->process($format->{'template'}, $vars) + || ThrowTemplateError($template->error()); } sub wrap { - validateWidthAndHeight(); - - # We create a Chart object so we can validate the parameters - my $chart = new Bugzilla::Chart($cgi); - - $vars->{'time'} = localtime(time()); - - $vars->{'imagebase'} = $cgi->canonicalise_query( - "action", "action-wrap", "ctype", "format", "width", "height"); - - print $cgi->header(); - $template->process("reports/chart.html.tmpl", $vars) - || ThrowTemplateError($template->error()); + validateWidthAndHeight(); + + # We create a Chart object so we can validate the parameters + my $chart = new Bugzilla::Chart($cgi); + + $vars->{'time'} = localtime(time()); + + $vars->{'imagebase'} + = $cgi->canonicalise_query("action", "action-wrap", "ctype", "format", + "width", "height"); + + print $cgi->header(); + $template->process("reports/chart.html.tmpl", $vars) + || ThrowTemplateError($template->error()); } sub view { - my $chart = shift; + my $chart = shift; - # Set defaults - foreach my $field ('category', 'subcategory', 'name', 'ctype') { - $vars->{'default'}{$field} = $cgi->param($field) || 0; - } + # Set defaults + foreach my $field ('category', 'subcategory', 'name', 'ctype') { + $vars->{'default'}{$field} = $cgi->param($field) || 0; + } - # Pass the state object to the display UI. - $vars->{'chart'} = $chart; - $vars->{'category'} = Bugzilla::Chart::getVisibleSeries(); + # Pass the state object to the display UI. + $vars->{'chart'} = $chart; + $vars->{'category'} = Bugzilla::Chart::getVisibleSeries(); - print $cgi->header(); + print $cgi->header(); - # If we have having problems with bad data, we can set debug=1 to dump - # the data structure. - $chart->dump() if $cgi->param('debug'); + # If we have having problems with bad data, we can set debug=1 to dump + # the data structure. + $chart->dump() if $cgi->param('debug'); - $template->process("reports/create-chart.html.tmpl", $vars) - || ThrowTemplateError($template->error()); + $template->process("reports/create-chart.html.tmpl", $vars) + || ThrowTemplateError($template->error()); } |