]> git.ipfire.org Git - thirdparty/bugzilla.git/commitdiff
Bug 288663: The inclusion and exclusion lists behave incorrectly when a product or...
authorlpsolit%gmail.com <>
Fri, 6 May 2005 02:20:44 +0000 (02:20 +0000)
committerlpsolit%gmail.com <>
Fri, 6 May 2005 02:20:44 +0000 (02:20 +0000)
Bugzilla/FlagType.pm
editflagtypes.cgi
template/en/default/admin/flag-type/edit.html.tmpl

index 6b4c31c7f9f32b80e395992481da66af5e849f78..d07bb0b65f5fa3d5ad76c84b91cf6148e8644f3e 100644 (file)
@@ -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
index ed80a013014622d9b4478ce85b210b970fbf5702..bdf0779b4d19527bcfae91e580b51359c4159d29 100755 (executable)
@@ -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);
+        }
+    }
+}
index 8afbc38cb07d555d6bbdd45ee2b2f6239e0403c2..8491a1e7fa1bd6bf84d273fb6818b4593ed60c08 100644 (file)
   <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">