Commit d320ac0e authored by lpsolit%gmail.com's avatar lpsolit%gmail.com

Bug 288663: The inclusion and exclusion lists behave incorrectly when a product…

Bug 288663: The inclusion and exclusion lists behave incorrectly when a product or a component is called "Any" - Patch by Frédéric Buclin <LpSolit@gmail.com> r=myk a=myk
parent dfbc39b0
...@@ -184,7 +184,9 @@ sub get_exclusions { ...@@ -184,7 +184,9 @@ sub get_exclusions {
=item C<get_clusions($id, $type)> =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 =back
...@@ -192,23 +194,29 @@ Someone please document this ...@@ -192,23 +194,29 @@ Someone please document this
sub get_clusions { sub get_clusions {
my ($id, $type) = @_; my ($id, $type) = @_;
my $dbh = Bugzilla->dbh;
&::PushGlobalSQLState();
&::SendSQL("SELECT products.name, components.name " . my $list =
"FROM flagtypes, flag${type}clusions " . $dbh->selectall_arrayref("SELECT products.id, products.name, " .
"LEFT OUTER JOIN products ON flag${type}clusions.product_id = products.id " . " components.id, components.name " .
"LEFT OUTER JOIN components ON flag${type}clusions.component_id = components.id " . "FROM flagtypes, flag${type}clusions " .
"WHERE flagtypes.id = $id AND flag${type}clusions.type_id = flagtypes.id"); "LEFT OUTER JOIN products " .
my @clusions = (); " ON flag${type}clusions.product_id = products.id " .
while (&::MoreSQLData()) { "LEFT OUTER JOIN components " .
my ($product, $component) = &::FetchSQLData(); " ON flag${type}clusions.component_id = components.id " .
$product ||= "Any"; "WHERE flagtypes.id = ? " .
$component ||= "Any"; " AND flag${type}clusions.type_id = flagtypes.id",
push(@clusions, "$product:$component"); 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 =pod
......
...@@ -146,9 +146,11 @@ sub edit { ...@@ -146,9 +146,11 @@ sub edit {
# Otherwise set the target type (the minimal information about the type # Otherwise set the target type (the minimal information about the type
# that the template needs to know) from the URL parameter and default # that the template needs to know) from the URL parameter and default
# the list of inclusions to all categories. # 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'), $vars->{'type'} = { 'target_type' => scalar $cgi->param('target_type'),
'inclusions' => ["__Any__:__Any__"] }; 'inclusions' => \%inclusions };
} }
# Return the appropriate HTTP response headers. # Return the appropriate HTTP response headers.
...@@ -171,13 +173,13 @@ sub processCategoryChange { ...@@ -171,13 +173,13 @@ sub processCategoryChange {
if ($categoryAction eq 'include') { if ($categoryAction eq 'include') {
validateProduct(); validateProduct();
validateComponent(); 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); push(@inclusions, $category) unless grep($_ eq $category, @inclusions);
} }
elsif ($categoryAction eq 'exclude') { elsif ($categoryAction eq 'exclude') {
validateProduct(); validateProduct();
validateComponent(); 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); push(@exclusions, $category) unless grep($_ eq $category, @exclusions);
} }
elsif ($categoryAction eq 'removeInclusion') { elsif ($categoryAction eq 'removeInclusion') {
...@@ -187,6 +189,11 @@ sub processCategoryChange { ...@@ -187,6 +189,11 @@ sub processCategoryChange {
@exclusions = map(($_ eq $cgi->param('exclusion_to_remove') ? () : $_), @exclusions); @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. # Get this installation's products and components.
GetVersionTable(); GetVersionTable();
...@@ -199,8 +206,8 @@ sub processCategoryChange { ...@@ -199,8 +206,8 @@ sub processCategoryChange {
$vars->{'action'} = $cgi->param('action'); $vars->{'action'} = $cgi->param('action');
my $type = {}; my $type = {};
foreach my $key ($cgi->param()) { $type->{$key} = $cgi->param($key) } foreach my $key ($cgi->param()) { $type->{$key} = $cgi->param($key) }
$type->{'inclusions'} = \@inclusions; $type->{'inclusions'} = \%inclusions;
$type->{'exclusions'} = \@exclusions; $type->{'exclusions'} = \%exclusions;
$vars->{'type'} = $type; $vars->{'type'} = $type;
# Return the appropriate HTTP response headers. # Return the appropriate HTTP response headers.
...@@ -211,6 +218,21 @@ sub processCategoryChange { ...@@ -211,6 +218,21 @@ sub processCategoryChange {
|| ThrowTemplateError($template->error()); || 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 { sub insert {
validateName(); validateName();
validateDescription(); validateDescription();
...@@ -253,16 +275,7 @@ sub insert { ...@@ -253,16 +275,7 @@ sub insert {
$cgi->param('request_gid') . ")"); $cgi->param('request_gid') . ")");
# Populate the list of inclusions/exclusions for this flag type. # Populate the list of inclusions/exclusions for this flag type.
foreach my $category_type ("inclusions", "exclusions") { validateAndSubmit($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)");
}
}
$dbh->bz_unlock_tables(); $dbh->bz_unlock_tables();
...@@ -314,17 +327,7 @@ sub update { ...@@ -314,17 +327,7 @@ sub update {
WHERE id = $id"); WHERE id = $id");
# Update the list of inclusions/exclusions for this flag type. # Update the list of inclusions/exclusions for this flag type.
foreach my $category_type ("inclusions", "exclusions") { validateAndSubmit($id);
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)");
}
}
$dbh->bz_unlock_tables(); $dbh->bz_unlock_tables();
...@@ -558,3 +561,37 @@ sub validateGroups { ...@@ -558,3 +561,37 @@ sub validateGroups {
$cgi->param($col, $gid); $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);
}
}
}
...@@ -64,10 +64,10 @@ ...@@ -64,10 +64,10 @@
<input type="hidden" name="id" value="[% type.id %]"> <input type="hidden" name="id" value="[% type.id %]">
<input type="hidden" name="target_type" value="[% type.target_type %]"> <input type="hidden" name="target_type" value="[% type.target_type %]">
[% FOREACH category = type.inclusions %] [% FOREACH category = type.inclusions %]
<input type="hidden" name="inclusions" value="[% category FILTER html %]"> <input type="hidden" name="inclusions" value="[% category.value FILTER html %]">
[% END %] [% END %]
[% FOREACH category = type.exclusions %] [% FOREACH category = type.exclusions %]
<input type="hidden" name="exclusions" value="[% category FILTER html %]"> <input type="hidden" name="exclusions" value="[% category.value FILTER html %]">
[% END %] [% END %]
<table id="form" cellspacing="0" cellpadding="4" border="0"> <table id="form" cellspacing="0" cellpadding="4" border="0">
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment