summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Bugzilla/WebService/Product.pm127
-rw-r--r--Bugzilla/WebService/Server/REST/Resources/Product.pm25
-rw-r--r--template/en/default/global/user-error.html.tmpl6
3 files changed, 106 insertions, 52 deletions
diff --git a/Bugzilla/WebService/Product.pm b/Bugzilla/WebService/Product.pm
index 6e9f83a2a..c028c5845 100644
--- a/Bugzilla/WebService/Product.pm
+++ b/Bugzilla/WebService/Product.pm
@@ -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,
diff --git a/Bugzilla/WebService/Server/REST/Resources/Product.pm b/Bugzilla/WebService/Server/REST/Resources/Product.pm
index 1949282e9..acee3887b 100644
--- a/Bugzilla/WebService/Server/REST/Resources/Product.pm
+++ b/Bugzilla/WebService/Server/REST/Resources/Product.pm
@@ -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',
diff --git a/template/en/default/global/user-error.html.tmpl b/template/en/default/global/user-error.html.tmpl
index a4c900a22..a52d1833f 100644
--- a/template/en/default/global/user-error.html.tmpl
+++ b/template/en/default/global/user-error.html.tmpl
@@ -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" %]