From bffbe0c95c01c9878c620fe7a55657e802f0637c Mon Sep 17 00:00:00 2001 From: Julien Heyman Date: Tue, 9 Aug 2011 14:59:35 -0700 Subject: Bug 647980: Implement a Product.update WebService method. r=mkanat, a=mkanat --- Bugzilla/WebService/Product.pm | 195 ++++++++++++++++++++++++++++++++++++++++- Bugzilla/WebService/Util.pm | 43 +++++++++ 2 files changed, 236 insertions(+), 2 deletions(-) (limited to 'Bugzilla/WebService') diff --git a/Bugzilla/WebService/Product.pm b/Bugzilla/WebService/Product.pm index 9aeb8597a..20e428310 100644 --- a/Bugzilla/WebService/Product.pm +++ b/Bugzilla/WebService/Product.pm @@ -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. =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 + +=over + +=item B + +This allows you to update a product in Bugzilla. + +=item B + +B The following parameters specify which products you are updating. +You must set one or both of these parameters. + +=over + +=item C + +C of Cs. Numeric ids of the products that you wish to update. + +=item C + +C or Cs. Names of the products that you wish to update. + +=back + +B The following parameters specify the new values you want to set for +the products you are updating. + +=over + +=item C + +C 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 + +C 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 + +C Update the long description for these products to this value. + +=item C + +C Allow the UNCONFIRMED status to be set on bugs in products. + +=item C + +C True if the product is currently allowing bugs to be entered +into it, False otherwise. + +=back + +=item B + +A C with a single field "products". This points to an array of hashes +with the following fields: + +=over + +=item C + +C The id of the product that was updated. + +=item C + +C 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 + +C The value that this field was changed to. + +=item C + +C 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 + +The same as L. + +=back + +=item B + +=over + +=item Added in Bugzilla B<5.0>. + +=back + +=back diff --git a/Bugzilla/WebService/Util.pm b/Bugzilla/WebService/Util.pm index adb7fb43a..41dd07c1e 100644 --- a/Bugzilla/WebService/Util.pm +++ b/Bugzilla/WebService/Util.pm @@ -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. -- cgit v1.2.3-24-g4f1b