summaryrefslogtreecommitdiffstats
path: root/Bugzilla/WebService
diff options
context:
space:
mode:
authorJulien Heyman <jheyman@portaildulibre.fr>2011-08-09 23:59:35 +0200
committerMax Kanat-Alexander <mkanat@bugzilla.org>2011-08-09 23:59:35 +0200
commitbffbe0c95c01c9878c620fe7a55657e802f0637c (patch)
tree46b3893638271990885bcb66377ba9ce656e12d4 /Bugzilla/WebService
parent4b113460e54775cbd3e5e412ad37b9ba7ab66edc (diff)
downloadbugzilla-bffbe0c95c01c9878c620fe7a55657e802f0637c.tar.gz
bugzilla-bffbe0c95c01c9878c620fe7a55657e802f0637c.tar.xz
Bug 647980: Implement a Product.update WebService method.
r=mkanat, a=mkanat
Diffstat (limited to 'Bugzilla/WebService')
-rw-r--r--Bugzilla/WebService/Product.pm195
-rw-r--r--Bugzilla/WebService/Util.pm43
2 files changed, 236 insertions, 2 deletions
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<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
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.