Commit bffbe0c9 authored by Julien Heyman's avatar Julien Heyman Committed by Max Kanat-Alexander

Bug 647980: Implement a Product.update WebService method.

r=mkanat, a=mkanat
parent 4b113460
......@@ -25,7 +25,7 @@ use Bugzilla::User;
use Bugzilla::Error;
use Bugzilla::Constants;
use Bugzilla::WebService::Constants;
use Bugzilla::WebService::Util qw(validate filter filter_wants);
use Bugzilla::WebService::Util qw(validate filter filter_wants translate params_to_objects);
use constant READ_ONLY => qw(
get
......@@ -34,6 +34,17 @@ use constant READ_ONLY => qw(
get_selectable_products
);
use constant MAPPED_FIELDS => {
has_unconfirmed => 'allows_unconfirmed',
is_open => 'is_active',
};
use constant MAPPED_RETURNS => {
allows_unconfirmed => 'has_unconfirmed',
defaultmilestone => 'default_milestone',
isactive => 'is_open',
};
##################################################
# Add aliases here for method name compatibility #
##################################################
......@@ -118,6 +129,62 @@ sub create {
return { id => $self->type('int', $product->id) };
}
sub update {
my ($self, $params) = @_;
my $dbh = Bugzilla->dbh;
Bugzilla->login(LOGIN_REQUIRED);
Bugzilla->user->in_group('editcomponents')
|| ThrowUserError("auth_failure", { group => "editcomponents",
action => "edit",
object => "products" });
defined($params->{names}) || defined($params->{ids})
|| ThrowCodeError('params_required',
{ function => 'Product.update', params => ['ids', 'names'] });
my $product_objects = params_to_objects($params, 'Bugzilla::Product');
my $values = translate($params, MAPPED_FIELDS);
# We delete names and ids to keep only new values to set.
delete $values->{names};
delete $values->{ids};
$dbh->bz_start_transaction();
foreach my $product (@$product_objects) {
$product->set_all($values);
}
my %changes;
foreach my $product (@$product_objects) {
my $returned_changes = $product->update();
$changes{$product->id} = translate($returned_changes, MAPPED_RETURNS);
}
$dbh->bz_commit_transaction();
my @result;
foreach my $product (@$product_objects) {
my %hash = (
id => $product->id,
changes => {},
);
foreach my $field (keys %{ $changes{$product->id} }) {
my $change = $changes{$product->id}->{$field};
$hash{changes}{$field} = {
removed => $self->type('string', $change->[0]),
added => $self->type('string', $change->[1])
};
}
push(@result, \%hash);
}
return { products => \@result };
}
sub _product_to_hash {
my ($self, $params, $product) = @_;
......@@ -414,7 +481,7 @@ were added to the fields returned by C<get>.
=back
=head1 Product Creation
=head1 Product Creation and Modification
=head2 create
......@@ -507,3 +574,127 @@ You must define a default milestone.
=back
=back
=head2 update
B<EXPERIMENTAL>
=over
=item B<Description>
This allows you to update a product in Bugzilla.
=item B<Params>
B<Note:> The following parameters specify which products you are updating.
You must set one or both of these parameters.
=over
=item C<ids>
C<array> of C<int>s. Numeric ids of the products that you wish to update.
=item C<names>
C<array> or C<string>s. Names of the products that you wish to update.
=back
B<Note:> The following parameters specify the new values you want to set for
the products you are updating.
=over
=item C<name>
C<string> A new name for this product. If you try to set this while updating more
than one product, an error will occur, as product names must be unique.
=item C<default_milestone>
C<string> When a new bug is filed, what milestone does it get by default if the
user does not choose one? Must represent a milestone that is valid for this product.
=item C<description>
C<string> Update the long description for these products to this value.
=item C<has_unconfirmed>
C<boolean> Allow the UNCONFIRMED status to be set on bugs in products.
=item C<is_open>
C<boolean> True if the product is currently allowing bugs to be entered
into it, False otherwise.
=back
=item B<Returns>
A C<hash> with a single field "products". This points to an array of hashes
with the following fields:
=over
=item C<id>
C<int> The id of the product that was updated.
=item C<changes>
C<hash> The changes that were actually done on this product. The keys are
the names of the fields that were changed, and the values are a hash
with two keys:
=over
=item C<added>
C<string> The value that this field was changed to.
=item C<removed>
C<string> The value that was previously set in this field.
=back
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,
changes => {
name => {
removed => 'FooName',
added => 'BarName'
},
has_unconfirmed => {
removed => '1',
added => '0',
}
}
}
]
}
=item B<Errors>
The same as L</create>.
=back
=item B<History>
=over
=item Added in Bugzilla B<5.0>.
=back
=back
......@@ -32,6 +32,8 @@ our @EXPORT_OK = qw(
filter_wants
taint_data
validate
translate
params_to_objects
);
sub filter ($$) {
......@@ -108,6 +110,31 @@ sub validate {
return ($self, $params);
}
sub translate {
my ($params, $mapped) = @_;
my %changes;
while (my ($key,$value) = each (%$params)) {
my $new_field = $mapped->{$key} || $key;
$changes{$new_field} = $value;
}
return \%changes;
}
sub params_to_objects {
my ($params, $class) = @_;
my @objects = map { $class->check($_) }
@{ $params->{names} } if $params->{names};
my @objects_by_ids = map { $class->check({ id => $_ }) }
@{ $params->{ids} } if $params->{ids};
push(@objects, @objects_by_ids);
my %seen;
@objects = grep { !$seen{$_->id}++ } @objects;
return \@objects;
}
__END__
=head1 NAME
......@@ -147,3 +174,19 @@ This helps in the validation of parameters passed into the WebSerice
methods. Currently it converts listed parameters into an array reference
if the client only passed a single scalar value. It modifies the parameters
hash in place so other parameters should be unaltered.
=head2 translate
WebService methods frequently take parameters with different names than
the ones that we use internally in Bugzilla. This function takes a hashref
that has field names for keys and returns a hashref with those keys renamed
according to the mapping passed in with the second parameter (which is also
a hashref).
=head2 params_to_objects
Creates objects of the type passed in as the second parameter, using the
parameters passed to a WebService method (the first parameter to this function).
Helps make life simpler for WebService methods that internally create objects
via both "ids" and "names" fields. Also de-duplicates objects that were loaded
by both "ids" and "names". Returns an arrayref of objects.
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