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

r/a=glob


git-svn-id: svn://10.0.0.236/trunk@264900 18797224-902f-48f8-a5cc-f745e15eee43
This commit is contained in:
mkanat%bugzilla.org
2013-07-23 20:30:51 +00:00
parent 09771e1bd7
commit 2d2dcc1cda
4 changed files with 107 additions and 53 deletions

View File

@@ -1 +1 @@
8655
8656

View 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,

View 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',

View File

@@ -1081,9 +1081,9 @@
[% 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" %]