diff options
author | Dave Lawrence <dlawrence@mozilla.com> | 2013-09-27 00:15:10 +0200 |
---|---|---|
committer | Dave Lawrence <dlawrence@mozilla.com> | 2013-09-27 00:15:10 +0200 |
commit | f9defcea6e1ee83189674a355bda8bcf621feebe (patch) | |
tree | d60f44474c31d7a2705d8076a05e3c77f889939a | |
parent | e18e70eb6db4500a7afbb84b393df33a9e23b016 (diff) | |
download | bugzilla-f9defcea6e1ee83189674a355bda8bcf621feebe.tar.gz bugzilla-f9defcea6e1ee83189674a355bda8bcf621feebe.tar.xz |
Bug 915685 - backport upstream bug 914986 and bug 917483 to bmo/4.2 for allowing attachment metadata editing in webservice API
-rw-r--r-- | Bugzilla/Attachment.pm | 9 | ||||
-rw-r--r-- | Bugzilla/WebService/Bug.pm | 246 | ||||
-rw-r--r-- | Bugzilla/WebService/Server/REST/Resources/Bug.pm | 6 | ||||
-rw-r--r-- | Bugzilla/WebService/Util.pm | 11 |
4 files changed, 267 insertions, 5 deletions
diff --git a/Bugzilla/Attachment.pm b/Bugzilla/Attachment.pm index bf67b62fa..944337711 100644 --- a/Bugzilla/Attachment.pm +++ b/Bugzilla/Attachment.pm @@ -913,10 +913,11 @@ sub update { } if (scalar(keys %$changes)) { - $dbh->do('UPDATE attachments SET modification_time = ? WHERE attach_id = ?', - undef, ($timestamp, $self->id)); - $dbh->do('UPDATE bugs SET delta_ts = ? WHERE bug_id = ?', - undef, ($timestamp, $self->bug_id)); + $dbh->do('UPDATE attachments SET modification_time = ? WHERE attach_id = ?', + undef, ($timestamp, $self->id)); + $dbh->do('UPDATE bugs SET delta_ts = ? WHERE bug_id = ?', + undef, ($timestamp, $self->bug_id)); + $self->{modification_time} = $timestamp; } return $changes; diff --git a/Bugzilla/WebService/Bug.pm b/Bugzilla/WebService/Bug.pm index a107da923..b47cf7366 100644 --- a/Bugzilla/WebService/Bug.pm +++ b/Bugzilla/WebService/Bug.pm @@ -30,7 +30,7 @@ use Bugzilla::Constants; use Bugzilla::Error; use Bugzilla::Field; use Bugzilla::WebService::Constants; -use Bugzilla::WebService::Util qw(filter filter_wants validate); +use Bugzilla::WebService::Util qw(filter filter_wants validate translate); use Bugzilla::Bug; use Bugzilla::BugMail; use Bugzilla::Util qw(trick_taint trim); @@ -68,6 +68,20 @@ use constant READ_ONLY => qw( search ); +use constant ATTACHMENT_MAPPED_SETTERS => { + file_name => 'filename', + summary => 'description', +}; + +use constant ATTACHMENT_MAPPED_RETURNS => { + description => 'summary', + ispatch => 'is_patch', + isprivate => 'is_private', + isobsolete => 'is_obsolete', + filename => 'file_name', + mimetype => 'content_type', +}; + ###################################################### # Add aliases here for old method name compatibility # ###################################################### @@ -788,6 +802,86 @@ sub add_attachment { return { attachments => \%attachments }; } +sub update_attachment { + my ($self, $params) = validate(@_, 'ids'); + + my $user = Bugzilla->login(LOGIN_REQUIRED); + my $dbh = Bugzilla->dbh; + + my $ids = delete $params->{ids}; + defined $ids || ThrowCodeError('param_required', { param => 'ids' }); + + # Some fields cannot be sent to set_all + foreach my $key (qw(login password token)) { + delete $params->{$key}; + } + + # We can't update flags, and summary is really description + delete $params->{flags}; + + $params = translate($params, ATTACHMENT_MAPPED_SETTERS); + + # Get all the attachments, after verifying that they exist and are editable + my @attachments = (); + my %bugs = (); + foreach my $id (@$ids) { + my $attachment = Bugzilla::Attachment->new($id) + || ThrowUserError("invalid_attach_id", { attach_id => $id }); + my $bug = $attachment->bug; + $attachment->_check_bug; + $attachment->validate_can_edit($bug->product_id) + || ThrowUserError("illegal_attachment_edit", { attach_id => $id }); + + push @attachments, $attachment; + $bugs{$bug->id} = $bug; + } + + # Update the values + foreach my $attachment (@attachments) { + $attachment->set_all($params); + } + + $dbh->bz_start_transaction(); + + # Do the actual update and get information to return to user + my @result; + foreach my $attachment (@attachments) { + my $changes = $attachment->update(); + + $changes = translate($changes, ATTACHMENT_MAPPED_RETURNS); + + my %hash = ( + id => $self->type('int', $attachment->id), + last_change_time => $self->type('dateTime', $attachment->modification_time), + changes => {}, + ); + + foreach my $field (keys %$changes) { + my $change = $changes->{$field}; + + # We normalize undef to an empty string, so that the API + # stays consistent for things like Deadline that can become + # empty. + $hash{changes}->{$field} = { + removed => $self->type('string', $change->[0] // ''), + added => $self->type('string', $change->[1] // '') + }; + } + + push(@result, \%hash); + } + + $dbh->bz_commit_transaction(); + + # Email users about the change + foreach my $bug (values %bugs) { + Bugzilla::BugMail::Send($bug->id, { 'changer' => $user }); + } + + # Return the information to the user + return { attachments => \@result }; +} + sub add_comment { my ($self, $params) = @_; @@ -2969,6 +3063,156 @@ You set the "data" field to an empty string. =back +=head2 update_attachment + +B<UNSTABLE> + +=over + +=item B<Description> + +This allows you to update attachment metadata in Bugzilla. + +=item B<REST> + +To update attachment metadata on a current attachment: + +PUT /bug/attachment/<attach_id> + +The params to include in the POST body, as well as the returned +data format are the same as below. The C<ids> param will be +overridden as it it pulled from the URL path. + +=item B<Params> + +=over + +=item C<ids> + +B<Required> C<array> An array of integers -- the ids of the attachments you +want to update. + +=item C<file_name> + +C<string> The "file name" that will be displayed +in the UI for this attachment. + +=item C<summary> + +C<string> A short string describing the +attachment. + +=item C<content_type> + +C<string> The MIME type of the attachment, like +C<text/plain> or C<image/png>. + +=item C<is_patch> + +C<boolean> True if Bugzilla should treat this attachment as a patch. +If you specify this, you do not need to specify a C<content_type>. +The C<content_type> of the attachment will be forced to C<text/plain>. + +=item C<is_private> + +C<boolean> True if the attachment should be private (restricted +to the "insidergroup"), False if the attachment should be public. + +=item C<is_obsolete> + +C<boolean> True if the attachment is obsolete, False otherwise. + +=back + +=item B<Returns> + +A C<hash> with a single field, "attachment". This points to an array of hashes +with the following fields: + +=over + +=item C<id> + +C<int> The id of the attachment that was updated. + +=item C<last_change_time> + +C<dateTime> The exact time that this update was done at, for this attachment. +If no update was done (that is, no fields had their values changed and +no comment was added) then this will instead be the last time the attachment +was updated. + +=item C<changes> + +C<hash> The changes that were actually done on this bug. 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 values that were added to this field. +possibly a comma-and-space-separated list if multiple values were added. + +=item C<removed> (C<string>) The values that were removed from this +field. + +=back + +=back + +Here's an example of what a return value might look like: + + { + attachments => [ + { + id => 123, + last_change_time => '2010-01-01T12:34:56', + changes => { + summary => { + removed => 'Sample ptach', + added => 'Sample patch' + }, + is_obsolete => { + removed => '0', + added => '1', + } + }, + } + ] + } + +=item B<Errors> + +This method can throw all the same errors as L</get>, plus: + +=over + +=item 601 (Invalid MIME Type) + +You specified a C<content_type> argument that was blank, not a valid +MIME type, or not a MIME type that Bugzilla accepts for attachments. + +=item 603 (File Name Not Specified) + +You did not specify a valid for the C<file_name> argument. + +=item 604 (Summary Required) + +You did not specify a value for the C<summary> argument. + +=back + +=item B<History> + +=over + +=item Added in Bugzilla B<5.0>. + +=back + +=back + + =head2 add_comment B<STABLE> diff --git a/Bugzilla/WebService/Server/REST/Resources/Bug.pm b/Bugzilla/WebService/Server/REST/Resources/Bug.pm index a82625be7..98ae6049c 100644 --- a/Bugzilla/WebService/Server/REST/Resources/Bug.pm +++ b/Bugzilla/WebService/Server/REST/Resources/Bug.pm @@ -94,6 +94,12 @@ sub _rest_resources { params => sub { return { attachment_ids => [ $_[0] ] }; } + }, + PUT => { + method => 'update_attachment', + params => sub { + return { ids => [ $_[0] ] }; + } } }, qr{^/field/bug$}, { diff --git a/Bugzilla/WebService/Util.pm b/Bugzilla/WebService/Util.pm index 622e6890b..a0421ad9a 100644 --- a/Bugzilla/WebService/Util.pm +++ b/Bugzilla/WebService/Util.pm @@ -32,6 +32,7 @@ our @EXPORT_OK = qw( filter_wants taint_data validate + translate params_to_objects fix_credentials ); @@ -131,6 +132,16 @@ 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, @objects_by_ids); |