diff options
-rw-r--r-- | Bugzilla/FlagType.pm | 42 | ||||
-rwxr-xr-x | editflagtypes.cgi | 91 | ||||
-rw-r--r-- | template/en/default/admin/flag-type/edit.html.tmpl | 4 |
3 files changed, 91 insertions, 46 deletions
diff --git a/Bugzilla/FlagType.pm b/Bugzilla/FlagType.pm index 6b4c31c7f..d07bb0b65 100644 --- a/Bugzilla/FlagType.pm +++ b/Bugzilla/FlagType.pm @@ -184,7 +184,9 @@ sub get_exclusions { =item C<get_clusions($id, $type)> -Someone please document this +Return a hash of product/component IDs and names +associated with the flagtype: +$clusions{'product_name:component_name'} = "product_ID:component_ID" =back @@ -192,23 +194,29 @@ Someone please document this sub get_clusions { my ($id, $type) = @_; - - &::PushGlobalSQLState(); - &::SendSQL("SELECT products.name, components.name " . - "FROM flagtypes, flag${type}clusions " . - "LEFT OUTER JOIN products ON flag${type}clusions.product_id = products.id " . - "LEFT OUTER JOIN components ON flag${type}clusions.component_id = components.id " . - "WHERE flagtypes.id = $id AND flag${type}clusions.type_id = flagtypes.id"); - my @clusions = (); - while (&::MoreSQLData()) { - my ($product, $component) = &::FetchSQLData(); - $product ||= "Any"; - $component ||= "Any"; - push(@clusions, "$product:$component"); + my $dbh = Bugzilla->dbh; + + my $list = + $dbh->selectall_arrayref("SELECT products.id, products.name, " . + " components.id, components.name " . + "FROM flagtypes, flag${type}clusions " . + "LEFT OUTER JOIN products " . + " ON flag${type}clusions.product_id = products.id " . + "LEFT OUTER JOIN components " . + " ON flag${type}clusions.component_id = components.id " . + "WHERE flagtypes.id = ? " . + " AND flag${type}clusions.type_id = flagtypes.id", + undef, $id); + my %clusions; + foreach my $data (@$list) { + my ($product_id, $product_name, $component_id, $component_name) = @$data; + $product_id ||= 0; + $product_name ||= "__Any__"; + $component_id ||= 0; + $component_name ||= "__Any__"; + $clusions{"$product_name:$component_name"} = "$product_id:$component_id"; } - &::PopGlobalSQLState(); - - return \@clusions; + return \%clusions; } =pod diff --git a/editflagtypes.cgi b/editflagtypes.cgi index ed80a0130..bdf0779b4 100755 --- a/editflagtypes.cgi +++ b/editflagtypes.cgi @@ -146,9 +146,11 @@ sub edit { # Otherwise set the target type (the minimal information about the type # that the template needs to know) from the URL parameter and default # the list of inclusions to all categories. - else { + else { + my %inclusions; + $inclusions{"__Any__:__Any__"} = "0:0"; $vars->{'type'} = { 'target_type' => scalar $cgi->param('target_type'), - 'inclusions' => ["__Any__:__Any__"] }; + 'inclusions' => \%inclusions }; } # Return the appropriate HTTP response headers. @@ -171,13 +173,13 @@ sub processCategoryChange { if ($categoryAction eq 'include') { validateProduct(); validateComponent(); - my $category = ($cgi->param('product') || "__Any__") . ":" . ($cgi->param('component') || "__Any__"); + my $category = ($product_id || 0) . ":" . ($component_id || 0); push(@inclusions, $category) unless grep($_ eq $category, @inclusions); } elsif ($categoryAction eq 'exclude') { validateProduct(); validateComponent(); - my $category = ($cgi->param('product') || "__Any__") . ":" . ($cgi->param('component') || "__Any__"); + my $category = ($product_id || 0) . ":" . ($component_id || 0); push(@exclusions, $category) unless grep($_ eq $category, @exclusions); } elsif ($categoryAction eq 'removeInclusion') { @@ -187,6 +189,11 @@ sub processCategoryChange { @exclusions = map(($_ eq $cgi->param('exclusion_to_remove') ? () : $_), @exclusions); } + # Convert the array @clusions('prod_ID:comp_ID') back to a hash of + # the form %clusions{'prod_name:comp_name'} = 'prod_ID:comp_ID' + my %inclusions = clusion_array_to_hash(\@inclusions); + my %exclusions = clusion_array_to_hash(\@exclusions); + # Get this installation's products and components. GetVersionTable(); @@ -199,8 +206,8 @@ sub processCategoryChange { $vars->{'action'} = $cgi->param('action'); my $type = {}; foreach my $key ($cgi->param()) { $type->{$key} = $cgi->param($key) } - $type->{'inclusions'} = \@inclusions; - $type->{'exclusions'} = \@exclusions; + $type->{'inclusions'} = \%inclusions; + $type->{'exclusions'} = \%exclusions; $vars->{'type'} = $type; # Return the appropriate HTTP response headers. @@ -211,6 +218,21 @@ sub processCategoryChange { || ThrowTemplateError($template->error()); } +# Convert the array @clusions('prod_ID:comp_ID') back to a hash of +# the form %clusions{'prod_name:comp_name'} = 'prod_ID:comp_ID' +sub clusion_array_to_hash { + my $array = shift; + my %hash; + foreach my $ids (@$array) { + trick_taint($ids); + my ($product_id, $component_id) = split(":", $ids); + my $product_name = get_product_name($product_id) || "__Any__"; + my $component_name = get_component_name($component_id) || "__Any__"; + $hash{"$product_name:$component_name"} = $ids; + } + return %hash; +} + sub insert { validateName(); validateDescription(); @@ -253,16 +275,7 @@ sub insert { $cgi->param('request_gid') . ")"); # Populate the list of inclusions/exclusions for this flag type. - foreach my $category_type ("inclusions", "exclusions") { - foreach my $category ($cgi->param($category_type)) { - my ($product, $component) = split(/:/, $category); - my $product_id = get_product_id($product) || "NULL"; - my $component_id = - get_component_id($product_id, $component) || "NULL"; - SendSQL("INSERT INTO flag$category_type (type_id, product_id, " . - "component_id) VALUES ($id, $product_id, $component_id)"); - } - } + validateAndSubmit($id); $dbh->bz_unlock_tables(); @@ -314,17 +327,7 @@ sub update { WHERE id = $id"); # Update the list of inclusions/exclusions for this flag type. - foreach my $category_type ("inclusions", "exclusions") { - SendSQL("DELETE FROM flag$category_type WHERE type_id = $id"); - foreach my $category ($cgi->param($category_type)) { - my ($product, $component) = split(/:/, $category); - my $product_id = get_product_id($product) || "NULL"; - my $component_id = - get_component_id($product_id, $component) || "NULL"; - SendSQL("INSERT INTO flag$category_type (type_id, product_id, " . - "component_id) VALUES ($id, $product_id, $component_id)"); - } - } + validateAndSubmit($id); $dbh->bz_unlock_tables(); @@ -558,3 +561,37 @@ sub validateGroups { $cgi->param($col, $gid); } } + +# At this point, values either come the DB itself or have been recently +# added by the user and have passed all validation tests. +# The only way to have invalid product/component combinations is to +# hack the URL. So we silently ignore them, if any. +sub validateAndSubmit ($) { + my ($id) = @_; + my $dbh = Bugzilla->dbh; + + foreach my $category_type ("inclusions", "exclusions") { + # Will be used several times below. + my $sth = $dbh->prepare("INSERT INTO flag$category_type " . + "(type_id, product_id, component_id) " . + "VALUES (?, ?, ?)"); + + $dbh->do("DELETE FROM flag$category_type WHERE type_id = ?", undef, $id); + foreach my $category ($cgi->param($category_type)) { + trick_taint($category); + my ($product_id, $component_id) = split(":", $category); + # The product does not exist. + next if ($product_id && !get_product_name($product_id)); + # A component was selected without a product being selected. + next if (!$product_id && $component_id); + # The component does not belong to this product. + next if ($component_id + && !$dbh->selectrow_array("SELECT id FROM components + WHERE id = ? AND product_id = ?", + undef, ($component_id, $product_id))); + $product_id ||= undef; + $component_id ||= undef; + $sth->execute($id, $product_id, $component_id); + } + } +} diff --git a/template/en/default/admin/flag-type/edit.html.tmpl b/template/en/default/admin/flag-type/edit.html.tmpl index 8afbc38cb..8491a1e7f 100644 --- a/template/en/default/admin/flag-type/edit.html.tmpl +++ b/template/en/default/admin/flag-type/edit.html.tmpl @@ -64,10 +64,10 @@ <input type="hidden" name="id" value="[% type.id %]"> <input type="hidden" name="target_type" value="[% type.target_type %]"> [% FOREACH category = type.inclusions %] - <input type="hidden" name="inclusions" value="[% category FILTER html %]"> + <input type="hidden" name="inclusions" value="[% category.value FILTER html %]"> [% END %] [% FOREACH category = type.exclusions %] - <input type="hidden" name="exclusions" value="[% category FILTER html %]"> + <input type="hidden" name="exclusions" value="[% category.value FILTER html %]"> [% END %] <table id="form" cellspacing="0" cellpadding="4" border="0"> |