You need to sign in or sign up before continuing.
Commit b799069b authored by Dave Lawrence's avatar Dave Lawrence

Bug 896066 - Allow REST WebService API to for GET /product to allow retrieval of…

Bug 896066 - Allow REST WebService API to for GET /product to allow retrieval of multiple product objects r/a=glob
parent 927f0c3a
...@@ -67,47 +67,76 @@ sub get_accessible_products { ...@@ -67,47 +67,76 @@ sub get_accessible_products {
# Get a list of actual products, based on list of ids or names # Get a list of actual products, based on list of ids or names
sub get { 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", || ThrowCodeError("params_required", { function => "Product.get",
params => ['ids', 'names'] }); params => ['ids', 'names', 'type'] });
Bugzilla->switch_to_shadow_db(); Bugzilla->switch_to_shadow_db();
# Only products that are in the users accessible products, my $products = [];
# can be allowed to be returned if (defined $params->{type}) {
my $accessible_products = Bugzilla->user->get_accessible_products; 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}) { if (defined $params->{ids}) {
# Create a hash with the ids the user wants # Create a hash with the ids the user wants
my %ids = map { $_ => 1 } @{$params->{ids}}; my %ids = map { $_ => 1 } @{$params->{ids}};
# Return the intersection of this, by grepping the ids from # Return the intersection of this, by grepping the ids from $products.
# accessible products. push(@requested_products,
push(@requested_accessible, grep { $ids{$_->id} } @$products);
grep { $ids{$_->id} } @$accessible_products);
} }
if (defined $params->{names}) { if (defined $params->{names}) {
# Create a hash with the names the user wants # Create a hash with the names the user wants
my %names = map { lc($_) => 1 } @{$params->{names}}; my %names = map { lc($_) => 1 } @{$params->{names}};
# Return the intersection of this, by grepping the names from # Return the intersection of this, by grepping the names
# accessible products, union'ed with products found by ID to # from $products, union'ed with products found by ID to
# avoid duplicates # avoid duplicates
foreach my $product (grep { $names{lc $_->name} } foreach my $product (grep { $names{lc $_->name} }
@$accessible_products) { @$products) {
next if grep { $_->id == $product->id } next if grep { $_->id == $product->id }
@requested_accessible; @requested_products;
push @requested_accessible, $product; 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. # Now create a result entry for each.
my @products = map { $self->_product_to_hash($params, $_) } my @products = map { $self->_product_to_hash($params, $_) }
@requested_accessible; @requested_products;
return { products => \@products }; return { products => \@products };
} }
...@@ -354,7 +383,7 @@ Returns a list of the ids of the products the user can search on. ...@@ -354,7 +383,7 @@ Returns a list of the ids of the products the user can search on.
=item B<REST> =item B<REST>
GET /product?type=selectable GET /product_selectable
the returned data format is same as below. the returned data format is same as below.
...@@ -390,7 +419,7 @@ against. ...@@ -390,7 +419,7 @@ against.
=item B<REST> =item B<REST>
GET /product?type=enterable GET /product_enterable
the returned data format is same as below. the returned data format is same as below.
...@@ -426,7 +455,7 @@ bugs against. ...@@ -426,7 +455,7 @@ bugs against.
=item B<REST> =item B<REST>
GET /product?type=accessible GET /product_accessible
the returned data format is same as below. 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 ...@@ -465,8 +494,20 @@ B<Note>: Can also be called as "get_products" for compatibilty with Bugzilla 3.0
=item B<REST> =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> 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. the returned data format is same as below.
=item B<Params> =item B<Params>
...@@ -487,6 +528,12 @@ An array of product ids ...@@ -487,6 +528,12 @@ An array of product ids
An array of product names 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 =back
=item B<Returns> =item B<Returns>
......
...@@ -21,17 +21,24 @@ BEGIN { ...@@ -21,17 +21,24 @@ BEGIN {
sub _rest_resources { sub _rest_resources {
my $rest_resources = [ my $rest_resources = [
qr{^/product$}, { qr{^/product_accessible$}, {
GET => {
method => 'get_accessible_products'
}
},
qr{^/product_enterable$}, {
GET => {
method => 'get_enterable_products'
}
},
qr{^/product_selectable$}, {
GET => { GET => {
method => sub { method => 'get_selectable_products'
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 });
}, },
qr{^/product$}, {
GET => {
method => 'get'
}, },
POST => { POST => {
method => 'create', method => 'create',
......
...@@ -1081,9 +1081,9 @@ ...@@ -1081,9 +1081,9 @@
[% ELSIF error == "rest_invalid_resource" %] [% ELSIF error == "rest_invalid_resource" %]
A REST API resource was not found for '[% method FILTER html +%] [%+ path FILTER html %]'. A REST API resource was not found for '[% method FILTER html +%] [%+ path FILTER html %]'.
[% ELSIF error == "rest_get_products_invalid_type" %] [% ELSIF error == "get_products_invalid_type" %]
The type '[% type FILTER html %]' is invalid for 'GET /product'. Valid choices The product type '[% type FILTER html %]' is invalid. Valid choices
are 'accessible' (default if type value is undefined), 'selectable', and 'enterable'. are 'accessible', 'selectable', and 'enterable'.
[% ELSIF error == "keyword_already_exists" %] [% ELSIF error == "keyword_already_exists" %]
[% title = "Keyword Already Exists" %] [% title = "Keyword Already Exists" %]
......
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