]> git.ipfire.org Git - thirdparty/bugzilla.git/commitdiff
Bug 647980: Implement a Product.update WebService method.
authorJulien Heyman <jheyman@portaildulibre.fr>
Tue, 9 Aug 2011 21:59:35 +0000 (14:59 -0700)
committerMax Kanat-Alexander <mkanat@bugzilla.org>
Tue, 9 Aug 2011 21:59:35 +0000 (14:59 -0700)
r=mkanat, a=mkanat

Bugzilla/WebService/Product.pm
Bugzilla/WebService/Util.pm

index 9aeb8597a6e63e403b541db1ed1a5343a0f773c1..20e428310d420515b39f18f9f2fbeed946607908 100644 (file)
@@ -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
index adb7fb43a9cf67ede36a6d6e8ac2dbdd85b1abf4..41dd07c1e2cbe45e910131838dc687bb5ce8ffb1 100644 (file)
@@ -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.