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
......@@ -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,
......
......@@ -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',
......
......@@ -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" %]
......
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