]> git.ipfire.org Git - thirdparty/bugzilla.git/commitdiff
Bug 286158: Remove GetSelectableProducts() from globals.pl and use Bugzilla::User...
authorlpsolit%gmail.com <>
Sat, 3 Sep 2005 04:12:07 +0000 (04:12 +0000)
committerlpsolit%gmail.com <>
Sat, 3 Sep 2005 04:12:07 +0000 (04:12 +0000)
16 files changed:
Bugzilla/Component.pm
Bugzilla/Product.pm
Bugzilla/User.pm
config.cgi
duplicates.cgi
enter_bug.cgi
globals.pl
query.cgi
reports.cgi
request.cgi
template/en/default/config.js.tmpl
template/en/default/config.rdf.tmpl
template/en/default/filterexceptions.pl
template/en/default/global/choose-classification.html.tmpl
template/en/default/reports/duplicates.html.tmpl
template/en/default/request/queue.html.tmpl

index a3278dea955e9e04aed1cc0927a646b1f72fb1b3..dfbcf00a868ee987a45b3e9c5cac83eecbf80107 100644 (file)
@@ -121,11 +121,11 @@ sub get_components_by_product {
         SELECT id FROM components
         WHERE product_id = ?}, undef, $product_id);
 
-    my $components;
+    my @components;
     foreach my $id (@$ids) {
-        $components->{$id} = new Bugzilla::Component($id);
+        push @components, new Bugzilla::Component($id);
     }
-    return $components;
+    return @components;
 }
 
 1;
@@ -151,8 +151,7 @@ Bugzilla::Component - Bugzilla product component class.
     my $default_assignee   = $component->default_assignee;
     my $default_qa_contact = $component->default_qa_contact;
 
-    my $hash_ref = Bugzilla::Component::get_components_by_product(1);
-    my $component = $hash_ref->{1};
+    my @components = Bugzilla::Component::get_components_by_product($id);
 
 =head1 DESCRIPTION
 
@@ -184,13 +183,11 @@ Component.pm represents a Product Component object.
 
 =item C<get_components_by_product($product_id)>
 
- Description: Returns all Bugzilla components that belong to the
-              supplied product.
+ Description: Returns all components that belong to the supplied product.
 
  Params:      $product_id - Integer with a Bugzilla product id.
 
- Returns:     A hash with component id as key and Bugzilla::Component
-              object as value.
+ Returns:     An array of Bugzilla::Component objects.
 
 =back
 
index c257bd4ceaf4868e13f279204c8353525752ecc6..514620258d3a9642d6aaca652e3b22eb623e2d6a 100644 (file)
@@ -98,8 +98,9 @@ sub components {
     my $self = shift;
 
     if (!defined $self->{components}) {
-        $self->{components} =
+        my @components =
             Bugzilla::Component::get_components_by_product($self->id);
+        $self->{components} = \@components;
     }
     return $self->{components};
 }
@@ -247,11 +248,11 @@ Bugzilla::Product - Bugzilla product class.
     my $product = new Bugzilla::Product(1);
     my $product = new Bugzilla::Product('AcmeProduct');
 
-    my $components      = $product->components();
+    my @components      = $product->components();
     my $classification  = $product->classification();
-    my $hash_ref        = $product->group_controls();
-    my @array_ref       = $product->milestones();
-    my @array_ref       = $product->versions();
+    my $groups_controls = $product->group_controls();
+    my @milestones      = $product->milestones();
+    my @versions        = $product->versions();
     my $bugcount        = $product->bug_count();
 
     my $id               = $product->id;
@@ -290,12 +291,12 @@ Product.pm represents a product object.
 
 =item C<components()>
 
- Description: Returns a hash with all product components.
+ Description: Returns an array of component objects belonging to
+              the product.
 
  Params:      none.
 
- Returns:     A hash where component id is the hash key and
-              Bugzilla::Component object is the hash value.
+ Returns:     An array of Bugzilla::Component object.
 
 =item C<classification()>
 
index 87f894752ae332a772defde434488e380bcd49ea..2c6c6b0b5d98dd8b9b2f012608ded8c95669d45d 100644 (file)
@@ -61,8 +61,6 @@ use constant USER_MATCH_SUCCESS  => 1;
 
 use constant MATCH_SKIP_CONFIRM  => 1;
 
-use constant GET_PRODUCTS_BY_ID => 1;
-
 ################################################################################
 # Functions
 ################################################################################
@@ -420,13 +418,12 @@ sub can_see_bug {
 sub get_selectable_products {
     my ($self, $by_id) = @_;
 
-    if (defined $self->{SelectableProducts}) {
-        my %list = @{$self->{SelectableProducts}};
-        return \%list if $by_id;
-        return values(%list);
+    if (defined $self->{selectable_products}) {
+        return $self->{selectable_products};
     }
 
-    my $query = "SELECT id, name " .
+    my $dbh = Bugzilla->dbh;
+    my $query = "SELECT id " .
                 "FROM products " .
                 "LEFT JOIN group_control_map " .
                 "ON group_control_map.product_id = products.id ";
@@ -439,38 +436,31 @@ sub get_selectable_products {
     $query .= "AND group_id NOT IN(" . 
                $self->groups_as_string . ") " .
               "WHERE group_id IS NULL ORDER BY name";
-    my $dbh = Bugzilla->dbh;
-    my $sth = $dbh->prepare($query);
-    $sth->execute();
-    my @products = ();
-    while (my @row = $sth->fetchrow_array) {
-        push(@products, @row);
+
+    my $prod_ids = $dbh->selectcol_arrayref($query);
+    my @products;
+    foreach my $prod_id (@$prod_ids) {
+        push(@products, new Bugzilla::Product($prod_id));
     }
-    $self->{SelectableProducts} = \@products;
-    my %list = @products;
-    return \%list if $by_id;
-    return values(%list);
+    $self->{selectable_products} = \@products;
+    return $self->{selectable_products};
 }
 
-sub get_selectable_classifications ($) {
+sub get_selectable_classifications {
     my ($self) = @_;
 
     if (defined $self->{selectable_classifications}) {
         return $self->{selectable_classifications};
     }
-    my $products = $self->get_selectable_products(GET_PRODUCTS_BY_ID);
-    
-    my $selectable_classifications;
-   
-    foreach my $prod_id (keys %$products) {
-        my $product = new Bugzilla::Product($prod_id);
-        
-        $selectable_classifications->{$product->classification_id} =
-            $product->classification;
+
+    my $products = $self->get_selectable_products;
+
+    my $class;
+    foreach my $product (@$products) {
+        $class->{$product->classification_id} ||= $product->classification;
     }
-    $self->{selectable_classifications} = 
-        [values %$selectable_classifications];
+    my @sorted_class = sort {lc($a->name) cmp lc($b->name)} (values %$class);
+    $self->{selectable_classifications} = \@sorted_class;
     return $self->{selectable_classifications};
 }
 
@@ -1450,22 +1440,23 @@ care of by the constructor. However, when updating the email address, the
 user may be placed into different groups, based on a new email regexp. This
 method should be called in such a case to force reresolution of these groups.
 
-=item C<get_selectable_products(by_id)>
+=item C<get_selectable_products>
+
+ Description: Returns all products the user is allowed to access.
+
+ Params:      none
 
-Returns an alphabetical list of product names from which
-the user can select bugs.  If the $by_id parameter is true, it returns
-a hash where the keys are the product ids and the values are the
-product names.
+ Returns:     An array of product objects, sorted by the product name.
 
 =item C<get_selectable_classifications>
 
- Description: Returns the classifications that a user, according his
-              groups ownership, can select to entering, serch, view or
-              edit a bug.
+ Description: Returns all classifications containing at least one product
+              the user is allowed to view.
 
- Params:      none.
+ Params:      none
 
- Returns:     Bugzilla::Classification objects values.
+ Returns:     An array of Bugzilla::Classification objects, sorted by
+              the classification name.
 
 =item C<get_userlist>
 
index e3ecef3fff4166acefae8c7198ae0f88d2ff1a9d..a21fc7843cc3d9118365889c8353052875a18903 100755 (executable)
@@ -64,11 +64,8 @@ $vars->{'keyword'}    = \@::legal_keywords;
 $vars->{'resolution'} = \@::legal_resolution;
 $vars->{'status'}    = \@::legal_bug_status;
 
-# Include lists of products, components, versions, and target milestones.
-my $selectables = GetSelectableProductHash();
-foreach my $selectable (keys %$selectables) {
-    $vars->{$selectable} = $selectables->{$selectable};
-}
+# Include a list of product objects.
+$vars->{'products'} = Bugzilla->user->get_selectable_products;
 
 # Create separate lists of open versus resolved statuses.  This should really
 # be made part of the configuration.
index 2aa0df263700e374a6f897b248896565657118fe..6348748bf9439aebe2db5a45df97384c6a407fd8 100755 (executable)
@@ -265,8 +265,7 @@ $vars->{'openonly'} = $openonly;
 $vars->{'reverse'} = $reverse;
 $vars->{'format'} = $cgi->param('format');
 $vars->{'query_products'} = \@query_products;
-my @selectable_products = GetSelectableProducts();
-$vars->{'products'} = \@selectable_products;
+$vars->{'products'} = Bugzilla->user->get_selectable_products;
 
 
 my $format = $template->get_format("reports/duplicates",
index 4a32a32e709fa07a8dbdc203ef1e97c5b7e81e89..66e182423808d6e51a3d8afb6cf8244f499aea5f 100755 (executable)
@@ -80,21 +80,13 @@ if (!defined $product || $product eq "") {
    }
 
    if (!$cgi->param('classification')) {
-       my %classdesc;
-       my %classifications;
-    
-       foreach my $c (GetSelectableClassifications()) {
-           $classdesc{$c} = $::classdesc{$c};
-           $classifications{$c} = $::classifications{$c};
-       }
+       my $classifications = Bugzilla->user->get_selectable_classifications();
 
-       my $classification_size = scalar(keys %classdesc);
-       if ($classification_size == 0) {
+       if (scalar(@$classifications) == 0) {
            ThrowUserError("no_products");
        } 
-       elsif ($classification_size > 1) {
-           $vars->{'classdesc'} = \%classdesc;
-           $vars->{'classifications'} = \%classifications;
+       elsif (scalar(@$classifications) > 1) {
+           $vars->{'classifications'} = $classifications;
 
            $vars->{'target'} = "enter_bug.cgi";
            $vars->{'format'} = $cgi->param('format');
@@ -106,7 +98,7 @@ if (!defined $product || $product eq "") {
              || ThrowTemplateError($template->error());
            exit;        
        }
-       $cgi->param(-name => 'classification', -value => (keys %classdesc)[0]);
+       $cgi->param(-name => 'classification', -value => @$classifications[0]->name);
    }
 
     my %products;
index 7f3d9dd13e3dd979c1d72ef3b667317f95149b89..46ceebc74638bd8f28659587ef9f0fb7d8108518 100644 (file)
@@ -518,113 +518,6 @@ sub GetEnterableProducts {
     return (@products);
 }
 
-
-#
-# This function returns an alphabetical list of product names to which
-# the user can enter bugs.  If the $by_id parameter is true, also retrieves IDs
-# and pushes them onto the list as id, name [, id, name...] for easy slurping
-# into a hash by the calling code.
-sub GetSelectableProducts {
-    my ($by_id,$by_classification) = @_;
-
-    my $extra_sql = $by_id ? "id, " : "";
-
-    my $extra_from_sql = $by_classification ? " INNER JOIN classifications"
-        . " ON classifications.id = products.classification_id" : "";
-
-    my $query = "SELECT $extra_sql products.name " .
-                "FROM products $extra_from_sql " .
-                "LEFT JOIN group_control_map " .
-                "ON group_control_map.product_id = products.id ";
-    if (Param('useentrygroupdefault')) {
-        $query .= "AND group_control_map.entry != 0 ";
-    } else {
-        $query .= "AND group_control_map.membercontrol = " .
-                  CONTROLMAPMANDATORY . " ";
-    }
-    if (%{Bugzilla->user->groups}) {
-        $query .= "AND group_id NOT IN(" . 
-                   join(',', values(%{Bugzilla->user->groups})) . ") ";
-    }
-    $query .= "WHERE group_id IS NULL ";
-    if ($by_classification) {
-        $query .= "AND classifications.name = ";
-        $query .= SqlQuote($by_classification) . " ";
-    }
-    $query .= "ORDER BY name";
-    PushGlobalSQLState();
-    SendSQL($query);
-    my @products = ();
-    push(@products, FetchSQLData()) while MoreSQLData();
-    PopGlobalSQLState();
-    return (@products);
-}
-
-# GetSelectableProductHash
-# returns a hash containing 
-# legal_products => an enterable product list
-# legal_(components|versions|milestones) =>
-#   the list of components, versions, and milestones of enterable products
-# (components|versions|milestones)_by_product
-#    => a hash of component lists for each enterable product
-# Milestones only get returned if the usetargetmilestones parameter is set.
-sub GetSelectableProductHash {
-    # The hash of selectable products and their attributes that gets returned
-    # at the end of this function.
-    my $selectables = {};
-
-    my %products = GetSelectableProducts(1);
-
-    $selectables->{legal_products} = [sort values %products];
-
-    # Run queries that retrieve the list of components, versions,
-    # and target milestones (if used) for the selectable products.
-    my @tables = qw(components versions);
-    push(@tables, 'milestones') if Param('usetargetmilestone');
-
-    PushGlobalSQLState();
-    foreach my $table (@tables) {
-        my %values;
-        my %values_by_product;
-
-        if (scalar(keys %products)) {
-            # Why oh why can't we standardize on these names?!?
-            my $fld = ($table eq "components" ? "name" : "value");
-
-            my $query = "SELECT $fld, product_id FROM $table WHERE product_id " .
-                        "IN (" . join(",", keys %products) . ") ORDER BY $fld";
-            SendSQL($query);
-
-            while (MoreSQLData()) {
-                my ($name, $product_id) = FetchSQLData();
-                next unless $name;
-                $values{$name} = 1;
-                push @{$values_by_product{$products{$product_id}}}, $name;
-            }
-        }
-
-        $selectables->{"legal_$table"} = [sort keys %values];
-        $selectables->{"${table}_by_product"} = \%values_by_product;
-    }
-    PopGlobalSQLState();
-
-    return $selectables;
-}
-
-#
-# This function returns an alphabetical list of classifications that has products the user can enter bugs.
-sub GetSelectableClassifications {
-    my @selectable_classes = ();
-
-    foreach my $c (sort keys %::classdesc) {
-        if ( scalar(GetSelectableProducts(0,$c)) > 0) {
-           push(@selectable_classes,$c);
-        }
-    }
-    return (@selectable_classes);
-}
-
-
 sub ValidatePassword {
     # Determines whether or not a password is valid (i.e. meets Bugzilla's
     # requirements for length and content).    
index 2f73f06024aa9efa5bbadf4f6f974dac07a1588d..4a414d46c6234a151a2d6b1de6a8d1bbe40c8d54 100755 (executable)
--- a/query.cgi
+++ b/query.cgi
@@ -66,7 +66,8 @@ if ($cgi->param("GoAheadAndLogIn")) {
     Bugzilla->login();
 }
 
-my $userid = Bugzilla->user->id;
+my $user = Bugzilla->user;
+my $userid = $user->id;
 
 # Backwards compatibility hack -- if there are any of the old QUERY_*
 # cookies around, and we are logged in, then move them into the database
@@ -219,23 +220,26 @@ GetVersionTable();
 # if using groups for entry, then we don't want people to see products they 
 # don't have access to. Remove them from the list.
 
-my @products = ();
+my @selectable_product_objects = @{$user->get_selectable_products};
+
 my %component_set;
 my %version_set;
 my %milestone_set;
-foreach my $p (GetSelectableProducts()) {
+# extract product names
+my @products = map { $_->name } @selectable_product_objects;
+
+foreach my $prod_name (@products) {
     # We build up boolean hashes in the "-set" hashes for each of these things 
     # before making a list because there may be duplicates names across products.
-    push @products, $p;
-    if ($::components{$p}) {
-        foreach my $c (@{$::components{$p}}) {
+    if ($::components{$prod_name}) {
+        foreach my $c (@{$::components{$prod_name}}) {
             $component_set{$c} = 1;
         }
     }
-    foreach my $v (@{$::versions{$p}}) {
+    foreach my $v (@{$::versions{$prod_name}}) {
         $version_set{$v} = 1;
     }
-    foreach my $m (@{$::target_milestone{$p}}) {
+    foreach my $m (@{$::target_milestone{$prod_name}}) {
         $milestone_set{$m} = 1;
     }
 }
@@ -296,11 +300,16 @@ $vars->{'product'} = \@products;
 if (Param('useclassification')) {
     my @classifications = ();
 
-    foreach my $c (GetSelectableClassifications()) {
+    my $class = $user->get_selectable_classifications;
+    foreach my $c (@$class) {
+        # Extract the name of products being in this classification.
+        my @prod_in_class
+            = grep { $_->classification_id == $c->id } @selectable_product_objects;
+        @prod_in_class = map { $_->name } @prod_in_class;
         # Create hash to hold attributes for each classification.
         my %classification = (
-            'name'       => $c,
-            'products'   => [ GetSelectableProducts(0,$c) ]
+            'name'       => $c->name,
+            'products'   => \@prod_in_class
         );
         # Assign hash back to classification array.
         push @classifications, \%classification;
index 7274ea8e2b221d08c52a038b92c676c7e4b5baeb..c060045eb0d5049587065af4171c4c6bed317374 100755 (executable)
@@ -54,7 +54,7 @@ use Bugzilla;
 
 # If we're using bug groups for products, we should apply those restrictions
 # to viewing reports, as well.  Time to check the login in that case.
-Bugzilla->login();
+my $user = Bugzilla->login();
 
 GetVersionTable();
 
@@ -66,7 +66,8 @@ my $template = Bugzilla->template;
 # We only want those products that the user has permissions for.
 my @myproducts;
 push( @myproducts, "-All-");
-push( @myproducts, GetSelectableProducts());
+# Extract product names from objects and add them to the list.
+push( @myproducts, map { $_->name } @{$user->get_selectable_products} );
 
 if (! defined $cgi->param('product')) {
 
index b0f45b1cccab27efd719f429a9c880fb72098602..c7705f38dc53e729f876971e9a249e227b3d68bd 100755 (executable)
 # Make it harder for us to do dangerous things in Perl.
 use strict;
 
-# Include the Bugzilla CGI and general utility library.
 use lib qw(.);
 require "globals.pl";
 use Bugzilla;
-# Use Bugzilla's Request module which contains utilities for handling requests.
 use Bugzilla::Flag;
 use Bugzilla::FlagType;
-
-# use Bugzilla's User module which contains utilities for handling users.
 use Bugzilla::User;
 
-use vars qw($template $vars @legal_product @legal_components %components);
+use vars qw($template $vars);
 
 # Make sure the user is logged in.
-Bugzilla->login();
+my $user = Bugzilla->login();
+my $userid = $user->id;
+
+my $cgi = Bugzilla->cgi;
+
 
 ################################################################################
 # Main Body Execution
 ################################################################################
 
-my $cgi = Bugzilla->cgi;
-
 my $fields;
 $fields->{'requester'}->{'type'} = 'single';
 # If the user doesn't restrict his search to requests from the wind
@@ -116,17 +114,17 @@ sub queue {
            LEFT JOIN bug_group_map AS bgmap
                   ON bgmap.bug_id = bugs.bug_id
                  AND bgmap.group_id NOT IN (" .
-                     join(', ', (-1, values(%{Bugzilla->user->groups}))) . ")
+                     join(', ', (-1, values(%{$user->groups}))) . ")
            LEFT JOIN cc AS ccmap
-                  ON ccmap.who = $::userid
-                 AND ccmap.bug_id = bugs.bug_id\r
+                  ON ccmap.who = $userid
+                 AND ccmap.bug_id = bugs.bug_id
     " .
 
     # Weed out bug the user does not have access to
     " WHERE     ((bgmap.group_id IS NULL) OR
                  (ccmap.who IS NOT NULL AND cclist_accessible = 1) OR
-                 (bugs.reporter = $::userid AND bugs.reporter_accessible = 1) OR
-                 (bugs.assigned_to = $::userid))";
+                 (bugs.reporter = $userid AND bugs.reporter_accessible = 1) OR
+                 (bugs.assigned_to = $userid))";
     
     # Non-deleted flags only
     $query .= " AND flags.is_active = 1 ";
@@ -279,15 +277,7 @@ sub queue {
     SendSQL("SELECT DISTINCT(name) FROM flagtypes ORDER BY name");
     push(@types, FetchOneColumn()) while MoreSQLData();
     
-    # products and components and the function used to modify the components
-    # menu when the products menu changes; used by the template to populate
-    # the menus and keep the components menu consistent with the products menu
-    GetVersionTable();
-    my $selectable = GetSelectableProductHash();
-    $vars->{'products'} = $selectable->{legal_products};
-    $vars->{'components'} = $selectable->{legal_components};
-    $vars->{'components_by_product'} = $selectable->{components_by_product};
-    
+    $vars->{'products'} = $user->get_selectable_products;
     $vars->{'excluded_columns'} = \@excluded_columns;
     $vars->{'group_field'} = $form_group;
     $vars->{'requests'} = \@requests;
index e3ec91435a209886002687d3307708f41a810c09..00ba589830964eafd3735882853a872bf260bcf6 100644 (file)
@@ -73,10 +73,10 @@ var component = new Object();
 var version = new Object();
 var target_milestone = new Object();
 
-[% FOREACH p = legal_products %]
-  component['[% p FILTER js %]'] = [ [% FOREACH x = components_by_product.$p %]'[% x FILTER js %]', [% END %] ];
-  version['[% p FILTER js %]'] = [ [% FOREACH x = versions_by_product.$p %]'[% x FILTER js %]', [% END %] ];
-  target_milestone['[% p FILTER js %]'] = [ [% FOREACH x = milestones_by_product.$p %]'[% x FILTER js %]', [% END %] ];
+[% FOREACH p = products %]
+  component['[% p.name FILTER js %]'] = [ [% FOREACH x = p.components %]'[% x.name FILTER js %]', [% END %] ];
+  version['[% p.name FILTER js %]'] = [ [% FOREACH x = p.versions %]'[% x.name FILTER js %]', [% END %] ];
+  target_milestone['[% p.name FILTER js %]'] = [ [% FOREACH x = p.milestones %]'[% x.name FILTER js %]', [% END %] ];
 [% END %]
 
 // Product and Component Exceptions
index 27a7ba3a0e573f706603b271ef52fda7c8e10269..4c1047f503d54afa032ef7744da968784fb61f3e 100644 (file)
 
   <bz:products>
     <Seq>
-      [% FOREACH product = legal_products %]
+      [% FOREACH product = products %]
         <li>
-          <bz:product rdf:about="[% Param('urlbase') %]product.cgi?name=[% product FILTER uri %]">
-            <bz:name>[% product FILTER html %]</bz:name>
+          <bz:product rdf:about="[% Param('urlbase') %]product.cgi?name=[% product.name FILTER uri %]">
+            <bz:name>[% product.name FILTER html %]</bz:name>
 
             <bz:components>
               <Seq>
-                [% FOREACH component = components_by_product.$product %]
-                  <li resource="[% Param('urlbase') %]component.cgi?name=[% component FILTER uri %]"/>
+                [% FOREACH component = product.components %]
+                  <li resource="[% Param('urlbase') %]component.cgi?name=[% component.name FILTER uri %]"/>
                 [% END %]
               </Seq>
             </bz:components>
 
             <bz:versions>
               <Seq>
-                [% FOREACH version = versions_by_product.$product %]
-                  <li resource="[% Param('urlbase') %]version.cgi?name=[% version FILTER uri %]"/>
+                [% FOREACH version = product.versions %]
+                  <li resource="[% Param('urlbase') %]version.cgi?name=[% version.name FILTER uri %]"/>
                 [% END %]
               </Seq>
             </bz:versions>
             [% IF Param('usetargetmilestone') %]
               <bz:target_milestones>
                 <Seq>
-                  [% FOREACH milestone = milestones_by_product.$product %]
-                    <li resource="[% Param('urlbase') %]milestone.cgi?name=[% milestone FILTER uri %]"/>
+                  [% FOREACH milestone = product.milestones %]
+                    <li resource="[% Param('urlbase') %]milestone.cgi?name=[% milestone.name FILTER uri %]"/>
                   [% END %]
                 </Seq>
               </bz:target_milestones>
 
   <bz:components>
     <Seq>
-      [% FOREACH item = legal_components %]
-        <li>
-          <bz:component rdf:about="[% Param('urlbase') %]component.cgi?name=[% item FILTER uri %]">
-            <bz:name>[% item FILTER html %]</bz:name>
-          </bz:component>
-        </li>
+      [% FOREACH product = products %]
+        [% FOREACH component = product.components %]
+          <li>
+            <bz:component rdf:about="[% Param('urlbase') %]component.cgi?name=[% component.name FILTER uri %]">
+              <bz:name>[% component.name FILTER html %]</bz:name>
+            </bz:component>
+          </li>
+        [% END %]
       [% END %]
     </Seq>
   </bz:components>
 
   <bz:versions>
     <Seq>
-      [% FOREACH item = legal_versions %]
-        <li>
-          <bz:version rdf:about="[% Param('urlbase') %]version.cgi?name=[% item FILTER uri %]">
-            <bz:name>[% item FILTER html %]</bz:name>
-          </bz:version>
-        </li>
+      [% FOREACH product = products %]
+        [% FOREACH version = product.versions %]
+          <li>
+            <bz:version rdf:about="[% Param('urlbase') %]version.cgi?name=[% version.name FILTER uri %]">
+              <bz:name>[% version.name FILTER html %]</bz:name>
+            </bz:version>
+          </li>
+        [% END %]
       [% END %]
     </Seq>
   </bz:versions>
   [% IF Param('usetargetmilestone') %]
     <bz:target_milestones>
       <Seq>
-        [% FOREACH item = legal_milestones %]
-          <li>
-            <bz:target_milestone rdf:about="[% Param('urlbase') %]milestone.cgi?name=[% item FILTER uri %]">
-              <bz:name>[% item FILTER html %]</bz:name>
-            </bz:target_milestone>
-          </li>
+        [% FOREACH product = products %]
+          [% FOREACH milestone = product.milestones %]
+            <li>
+              <bz:target_milestone rdf:about="[% Param('urlbase') %]milestone.cgi?name=[% milestone.name FILTER uri %]">
+                <bz:name>[% milestone.name FILTER html %]</bz:name>
+              </bz:target_milestone>
+            </li>
+          [% END %]
         [% END %]
       </Seq>
     </bz:target_milestones>
index 8ed71f0084fbd9df2f90163b2df119864d9692b2..28ea2c7bafbe220bf4c707f4f6d4476daf84a207 100644 (file)
 ],
 
 'global/choose-classification.html.tmpl' => [
-  'classdesc.$p', 
+  'class.description', 
 ],
 
 'global/choose-product.html.tmpl' => [
index b2021f234cc595db92b2e555cb1c6a877f08f9bd..627ac860fe7b624dee54d90a215dae329246be29 100644 (file)
@@ -18,8 +18,8 @@
   #%]
 
 [%# INTERFACE:
-  # classdesc: hash. May be empty. The hash keys are the classifications, and the values
-  # are their descriptions.
+  # classifications: an array of classification objects containing
+  #                  at least one product accessible by the user.
   #%]
 
 [% IF target == "enter_bug.cgi" %]
   </tr>    
 [% END %]
 
-[% FOREACH p = classdesc.keys.sort %]
-  [% IF classifications.$p.size > 0 %]
+[% FOREACH class = classifications %]
   <tr>
     <th align="right" valign="top">
-      <a href="[% target FILTER url_quote %]?classification=[% p FILTER url_quote -%]
+      <a href="[% target FILTER url_quote %]?classification=[% class.name FILTER url_quote -%]
             [%- IF cloned_bug_id %]&amp;cloned_bug_id=[% cloned_bug_id FILTER url_quote %][% END -%] 
             [%- IF format %]&amp;format=[% format FILTER url_quote %][% END %]">
-      [% p FILTER html %]</a>:
+      [% class.name FILTER html %]</a>:
     </th>
 
-    [% IF classdesc.$p %]
-      <td valign="top">&nbsp;[% classdesc.$p %]</td>
+    [% IF class.description %]
+      <td valign="top">&nbsp;[% class.description %]</td>
     [% END %]
   </tr>
-  [% END %]
 [% END %]
 
 </table>
index 5cbf84fe267c267eae40d8ba522c1b607195b2fc..897bbf17f911bcdd19fad892718b7131c7e76059 100644 (file)
@@ -20,7 +20,7 @@
   #%]
 
 [%# INTERFACE:
-  # products: list of strings. The products this user can see.
+  # products: an array of product objects this user can see.
   #
   # sortby: string. the column on which we are sorting the buglist.
   # reverse: boolean. True if we are reversing the current sort.
@@ -84,9 +84,9 @@
       <td rowspan="4" valign="top">
         <select name="product" size="5" multiple="multiple">
           [% FOREACH p = products %]
-            <option name="[% p FILTER html %]"
-            [% " selected" IF lsearch(query_products, p) != -1 %]
-            >[% p FILTER html %]</option>
+            <option name="[% p.name FILTER html %]"
+            [% " selected" IF lsearch(query_products, p.name) != -1 %]
+            >[% p.name FILTER html %]</option>
           [% END %]
         </select>
       </td>
index a6edcd8a3136edade409a734757d9f17be845a02..73bbd8195fb45d36b5d4063465c82e8e976b7329 100644 (file)
@@ -30,9 +30,9 @@
   var first_load = 1; // is this the first time we load the page?
   var last_sel = []; // caches last selection
   var cpts = new Array();
-  [% FOREACH p = products %]
-    cpts['[% p FILTER js %]'] = [
-      [%- FOREACH item = components_by_product.$p %]'[% item FILTER js %]'[% ", " UNLESS loop.last %] [%- END -%] ];
+  [% FOREACH prod = products %]
+    cpts['[% prod.name FILTER js %]'] = [
+      [%- FOREACH comp = prod.components %]'[% comp.name FILTER js %]'[% ", " UNLESS loop.last %] [%- END -%] ];
   [% END %]
 [% END %]
 
       <td>
         <select name="product" onchange="selectProduct(this.form, 'product', 'component', 'Any');">
           <option value="">Any</option>
-          [% FOREACH item = products %]
-            <option value="[% item FILTER html %]"
-                    [% "selected" IF cgi.param('product') == item %]>[% item FILTER html %]</option>
+          [% FOREACH prod = products %]
+            <option value="[% prod.name FILTER html %]"
+                    [% "selected" IF cgi.param('product') == prod.name %]>
+              [% prod.name FILTER html %]</option>
           [% END %]
         </select>
       </td>
       <td>
         <select name="component">
           <option value="">Any</option>
-          [% FOREACH item = components %]
-            <option value="[% item FILTER html %]" [% "selected" IF cgi.param('component') == item %]>
-              [% item FILTER html %]</option>
+          [% FOREACH prod = products %]
+            [% FOREACH comp = prod.components %]
+              <option value="[% comp.name FILTER html %]" [% "selected" IF cgi.param('component') == comp.name %]>
+                [% comp.name FILTER html %]</option>
+            [% END %]
           [% END %]
         </select>
       </td>