]> git.ipfire.org Git - thirdparty/bugzilla.git/commitdiff
Bug 896066 - Allow REST WebService API to for GET /product to allow retrieval of...
authorDave Lawrence <dlawrence@mozilla.com>
Tue, 23 Jul 2013 20:24:59 +0000 (16:24 -0400)
committerDave Lawrence <dlawrence@mozilla.com>
Tue, 23 Jul 2013 20:24:59 +0000 (16:24 -0400)
r/a=glob

Bugzilla/WebService/Product.pm
Bugzilla/WebService/Server/REST/Resources/Product.pm
template/en/default/global/user-error.html.tmpl

index 6e9f83a2a70895a403bd70927229963a3d26170d..c028c58453a9eb250e27a7b8764039ffabc0c18f 100644 (file)
@@ -50,64 +50,93 @@ BEGIN { *get_products = \&get }
 # Get the ids of the products the user can search
 sub get_selectable_products {
     Bugzilla->switch_to_shadow_db();
-    return {ids => [map {$_->id} @{Bugzilla->user->get_selectable_products}]}; 
+    return {ids => [map {$_->id} @{Bugzilla->user->get_selectable_products}]};
 }
 
 # Get the ids of the products the user can enter bugs against
 sub get_enterable_products {
     Bugzilla->switch_to_shadow_db();
-    return {ids => [map {$_->id} @{Bugzilla->user->get_enterable_products}]}; 
+    return {ids => [map {$_->id} @{Bugzilla->user->get_enterable_products}]};
 }
 
 # Get the union of the products the user can search and enter bugs against.
 sub get_accessible_products {
     Bugzilla->switch_to_shadow_db();
-    return {ids => [map {$_->id} @{Bugzilla->user->get_accessible_products}]}; 
+    return {ids => [map {$_->id} @{Bugzilla->user->get_accessible_products}]};
 }
 
 # Get a list of actual products, based on list of ids or names
 sub get {
-    my ($self, $params) = validate(@_, 'ids', 'names');
+    my ($self, $params) = validate(@_, 'ids', 'names', 'type');
+    my $user = Bugzilla->user;
 
-    defined $params->{ids} || defined $params->{names}
+    defined $params->{ids} || defined $params->{names} || defined $params->{type}
         || ThrowCodeError("params_required", { function => "Product.get",
-                                               params => ['ids', 'names'] });
+                                               params => ['ids', 'names', 'type'] });
     Bugzilla->switch_to_shadow_db();
 
-    # Only products that are in the users accessible products, 
-    # can be allowed to be returned
-    my $accessible_products = Bugzilla->user->get_accessible_products;
+    my $products = [];
+    if (defined $params->{type}) {
+        my %product_hash;
+        my $found = 0;
+        foreach my $type (@{ $params->{type} }) {
+            my $result = [];
+            if ($type eq 'accessible') {
+                $result = $user->get_accessible_products();
+            }
+            elsif ($type eq 'enterable') {
+                $result = $user->get_enterable_products();
+            }
+            elsif ($type eq 'selectable') {
+                $result = $user->get_selectable_products();
+            }
+            else {
+                ThrowUserError('get_products_invalid_type',
+                               { type => $type });
+            }
+            map { $product_hash{$_->id} = $_ } @$result;
+        }
+        $products = [ values %product_hash ];
+    }
+    else {
+        $products = $user->get_accessible_products;
+    }
 
-    my @requested_accessible;
+    my @requested_products;
 
     if (defined $params->{ids}) {
         # Create a hash with the ids the user wants
         my %ids = map { $_ => 1 } @{$params->{ids}};
-        
-        # Return the intersection of this, by grepping the ids from 
-        # accessible products.
-        push(@requested_accessible,
-            grep { $ids{$_->id} } @$accessible_products);
+
+        # Return the intersection of this, by grepping the ids from $products.
+        push(@requested_products,
+            grep { $ids{$_->id} } @$products);
     }
 
     if (defined $params->{names}) {
         # Create a hash with the names the user wants
         my %names = map { lc($_) => 1 } @{$params->{names}};
-        
-        # Return the intersection of this, by grepping the names from 
-        # accessible products, union'ed with products found by ID to
+
+        # Return the intersection of this, by grepping the names
+        # from $products, union'ed with products found by ID to
         # avoid duplicates
         foreach my $product (grep { $names{lc $_->name} }
-                                  @$accessible_products) {
+                                  @$products) {
             next if grep { $_->id == $product->id }
-                         @requested_accessible;
-            push @requested_accessible, $product;
+                         @requested_products;
+            push @requested_products, $product;
         }
     }
 
+    # If we just requested a specific type of products without
+    # specifying ids or names, then return the entire list.
+    if (!defined $params->{ids} && !defined $params->{names}) {
+        @requested_products = @$products;
+    }
+
     # Now create a result entry for each.
     my @products = map { $self->_product_to_hash($params, $_) }
-                       @requested_accessible;
+                       @requested_products;
     return { products => \@products };
 }
 
@@ -115,7 +144,7 @@ sub create {
     my ($self, $params) = @_;
 
     Bugzilla->login(LOGIN_REQUIRED);
-    Bugzilla->user->in_group('editcomponents') 
+    Bugzilla->user->in_group('editcomponents')
         || ThrowUserError("auth_failure", { group  => "editcomponents",
                                             action => "add",
                                             object => "products"});
@@ -151,7 +180,7 @@ sub update {
                                             object => "products" });
 
     defined($params->{names}) || defined($params->{ids})
-        || ThrowCodeError('params_required', 
+        || ThrowCodeError('params_required',
                { function => 'Product.update', params => ['ids', 'names'] });
 
     my $product_objects = params_to_objects($params, 'Bugzilla::Product');
@@ -170,10 +199,10 @@ sub update {
     my %changes;
     foreach my $product (@$product_objects) {
         my $returned_changes = $product->update();
-        $changes{$product->id} = translate($returned_changes, MAPPED_RETURNS);    
+        $changes{$product->id} = translate($returned_changes, MAPPED_RETURNS);
     }
     $dbh->bz_commit_transaction();
-            
+
     my @result;
     foreach my $product (@$product_objects) {
         my %hash = (
@@ -185,7 +214,7 @@ sub update {
             my $change = $changes{$product->id}->{$field};
             $hash{changes}{$field} = {
                 removed => $self->type('string', $change->[0]),
-                added   => $self->type('string', $change->[1]) 
+                added   => $self->type('string', $change->[1])
             };
         }
 
@@ -354,7 +383,7 @@ Returns a list of the ids of the products the user can search on.
 
 =item B<REST>
 
-GET /product?type=selectable
+GET /product_selectable
 
 the returned data format is same as below.
 
@@ -390,7 +419,7 @@ against.
 
 =item B<REST>
 
-GET /product?type=enterable
+GET /product_enterable
 
 the returned data format is same as below.
 
@@ -426,7 +455,7 @@ bugs against.
 
 =item B<REST>
 
-GET /product?type=accessible
+GET /product_accessible
 
 the returned data format is same as below.
 
@@ -465,8 +494,20 @@ B<Note>: Can also be called as "get_products" for compatibilty with Bugzilla 3.0
 
 =item B<REST>
 
+To return information about a specific groups of products such as
+C<accessible>, C<selectable>, or C<enterable>:
+
+GET /product?type=accessible
+
+To return information about a specific product by C<id> or C<name>:
+
 GET /product/<product_id_or_name>
 
+You can also return information about more than one specific product
+by using the following in your query string:
+
+GET /product?ids=1&ids=2&ids=3 or GET /product?names=ProductOne&names=Product2
+
 the returned data format is same as below.
 
 =item B<Params>
@@ -487,9 +528,15 @@ An array of product ids
 
 An array of product names
 
+=item C<type>
+
+The group of products to return. Valid values are: C<accessible> (default),
+C<selectable>, and C<enterable>. C<type> can be a single value or an array
+of values if more than one group is needed with duplicates removed.
+
 =back
 
-=item B<Returns> 
+=item B<Returns>
 
 A hash containing one item, C<products>, that is an array of
 hashes. Each hash describes a product, and has the following items:
@@ -569,7 +616,7 @@ components are not enabled for new bugs.
 
 =item C<flag_types>
 
-A hash containing the two items C<bug> and C<attachment> that each contains an 
+A hash containing the two items C<bug> and C<attachment> that each contains an
 array of hashes, where each hash describes a flagtype, and has the
 following items:
 
@@ -623,8 +670,8 @@ flagtype.
 
 =item C<request_group>
 
-C<int> the group id that is allowed to request the flag if the flag 
-is of the type requestable. If the item is not included all users 
+C<int> the group id that is allowed to request the flag if the flag
+is of the type requestable. If the item is not included all users
 are allowed request this flagtype.
 
 =back
@@ -705,11 +752,11 @@ within Bugzilla.
 
 B<Required> C<string> A description for this product. Allows some simple HTML.
 
-=item C<version> 
+=item C<version>
 
 B<Required> C<string> The default version for this product.
 
-=item C<has_unconfirmed> 
+=item C<has_unconfirmed>
 
 C<boolean> Allow the UNCONFIRMED status to be set on bugs in this product.
 Default: true.
@@ -718,11 +765,11 @@ Default: true.
 
 C<string> The name of the Classification which contains this product.
 
-=item C<default_milestone> 
+=item C<default_milestone>
 
 C<string> The default milestone for this product. Default '---'.
 
-=item C<is_open> 
+=item C<is_open>
 
 C<boolean> True if the product is currently allowing bugs to be entered
 into it. Default: true.
@@ -734,7 +781,7 @@ new product. Default: true.
 
 =back
 
-=item B<Returns>    
+=item B<Returns>
 
 A hash with one element, id. This is the id of the newly-filed product.
 
@@ -878,7 +925,7 @@ Note that booleans will be represented with the strings '1' and '0'.
 
 Here's an example of what a return value might look like:
 
- { 
+ {
    products => [
      {
        id => 123,
index 1949282e9791a669028b0fca3d579f1d1bee572b..acee3887b7f00dffd5ba9c7466e498a022467a54 100644 (file)
@@ -21,17 +21,24 @@ BEGIN {
 
 sub _rest_resources {
     my $rest_resources = [
+        qr{^/product_accessible$}, {
+            GET => {
+                method => 'get_accessible_products'
+            }
+        },
+        qr{^/product_enterable$}, {
+            GET => {
+                method => 'get_enterable_products'
+            }
+        },
+        qr{^/product_selectable$}, {
+            GET => {
+                method => 'get_selectable_products'
+            }
+        },
         qr{^/product$}, {
             GET  => {
-                method => sub {
-                    my $type = Bugzilla->input_params->{type};
-                    return 'get_accessible_products'
-                        if !defined $type || $type eq 'accessible';
-                    return 'get_enterable_products' if $type eq 'enterable';
-                    return 'get_selectable_products' if $type eq 'selectable';
-                    ThrowUserError('rest_get_products_invalid_type',
-                                   { type => $type });
-                },
+                method => 'get'
             },
             POST => {
                 method => 'create',
index a4c900a22f1a66c2e483fc7f0592c629b5f55a22..a52d1833f37fa45e41c632a4b6f91b6b0e71f8cf 100644 (file)
   [% ELSIF error == "rest_invalid_resource" %]
     A REST API resource was not found for '[% method FILTER html +%] [%+ path FILTER html %]'.
 
-  [% ELSIF error == "rest_get_products_invalid_type" %]
-    The type '[% type FILTER html %]' is invalid for 'GET /product'. Valid choices
-    are 'accessible' (default if type value is undefined), 'selectable', and 'enterable'.
+  [% ELSIF error == "get_products_invalid_type" %]
+    The product type '[% type FILTER html %]' is invalid. Valid choices
+    are 'accessible', 'selectable', and 'enterable'.
 
   [% ELSIF error == "keyword_already_exists" %]
     [% title = "Keyword Already Exists" %]