From: Kohei Yoshino Date: Thu, 14 Mar 2019 22:36:09 +0000 (-0400) Subject: Bug 994896 - Add the ability to get comments, attachments, and history using Bug.get X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=368f7b783870388d01aa9778bbb0d349d5560606;p=thirdparty%2Fbugzilla.git Bug 994896 - Add the ability to get comments, attachments, and history using Bug.get --- diff --git a/Bugzilla/WebService/Bug.pm b/Bugzilla/WebService/Bug.pm index 78c4ddc42..b69c65f97 100644 --- a/Bugzilla/WebService/Bug.pm +++ b/Bugzilla/WebService/Bug.pm @@ -110,6 +110,16 @@ use constant ATTACHMENT_MAPPED_RETURNS => { mimetype => 'content_type', }; +our %api_field_types = ( + %{{map { $_ => 'double' } Bugzilla::Bug::NUMERIC_COLUMNS()}}, + %{{map { $_ => 'dateTime' } Bugzilla::Bug::DATE_COLUMNS()}}, +); + +our %api_field_names = reverse %{Bugzilla::Bug::FIELD_MAP()}; +# This doesn't normally belong in FIELD_MAP, but we do want to translate +# "bug_group" back into "groups". +$api_field_names{'bug_group'} = 'groups'; + ###################################################### # Add aliases here for old method name compatibility # ###################################################### @@ -396,6 +406,7 @@ sub _translate_comment { creation_time => $self->type('dateTime', $comment->creation_ts), is_private => $self->type('boolean', $comment->is_private), text => $self->type('string', $comment->body_full), + raw_text => $self->type('string', $comment->body), attachment_id => $self->type('int', $attach_id), count => $self->type('int', $comment->count), }; @@ -471,13 +482,6 @@ sub history { my $ids = $params->{ids}; defined $ids || ThrowCodeError('param_required', {param => 'ids'}); - my %api_type = ( - %{{map { $_ => 'double' } Bugzilla::Bug::NUMERIC_COLUMNS()}}, - %{{map { $_ => 'dateTime' } Bugzilla::Bug::DATE_COLUMNS()}}, - ); - my %api_name = reverse %{Bugzilla::Bug::FIELD_MAP()}; - $api_name{'bug_group'} = 'groups'; - my @return; foreach my $bug_id (@$ids) { my %item; @@ -490,25 +494,7 @@ sub history { my @history; foreach my $changeset (@$activity) { - my %bug_history; - $bug_history{when} = $self->type('dateTime', $changeset->{when}); - $bug_history{who} = $self->type('email', $changeset->{who}); - $bug_history{changes} = []; - foreach my $change (@{$changeset->{changes}}) { - my $field_name = delete $change->{fieldname}; - my $api_field_type = $api_type{$field_name} || 'string'; - my $api_field_name = $api_name{$field_name} || $field_name; - my $attach_id = delete $change->{attachid}; - if ($attach_id) { - $change->{attachment_id} = $self->type('int', $attach_id); - } - $change->{removed} = $self->type($api_field_type, $change->{removed}); - $change->{added} = $self->type($api_field_type, $change->{added}); - $change->{field_name} = $self->type('string', $api_field_name); - push(@{$bug_history{changes}}, $change); - } - - push(@history, \%bug_history); + push(@history, $self->_changeset_to_hash($changeset, $params)); } $item{history} = \@history; @@ -791,12 +777,6 @@ sub update { $bug->send_changes($all_changes{$bug->id}); } - my %api_name = reverse %{Bugzilla::Bug::FIELD_MAP()}; - - # This doesn't normally belong in FIELD_MAP, but we do want to translate - # "bug_group" back into "groups". - $api_name{'bug_group'} = 'groups'; - my @result; foreach my $bug (@bugs) { my %hash = ( @@ -820,7 +800,7 @@ sub update { my %changes = %{$all_changes{$bug->id}}; foreach my $field (keys %changes) { my $change = $changes{$field}; - my $api_field = $api_name{$field} || $field; + my $api_field = $api_field_names{$field} || $field; # We normalize undef to an empty string, so that the API # stays consistent for things like Deadline that can become @@ -1411,6 +1391,7 @@ sub search_comment_tags { sub _bug_to_hash { my ($self, $bug, $params) = @_; + my $user = Bugzilla->user; # All the basic bug attributes are here, in alphabetical order. # A bug attribute is "basic" if it doesn't require an additional @@ -1446,6 +1427,15 @@ sub _bug_to_hash { $item{'assigned_to_detail'} = $self->_user_to_hash($bug->assigned_to, $params, undef, 'assigned_to'); } + if (filter_wants $params, 'attachments', ['extra']) { + my @result; + foreach my $attachment (@{$bug->attachments}) { + next if $attachment->isprivate && !$user->is_insider; + push(@result, + $self->_attachment_to_hash($attachment, $params, ['extra'], 'attachments')); + } + $item{'attachments'} = \@result; + } if (filter_wants $params, 'blocks') { my @blocks = map { $self->type('int', $_) } @{$bug->blocked}; $item{'blocks'} = \@blocks; @@ -1453,6 +1443,17 @@ sub _bug_to_hash { if (filter_wants $params, 'classification') { $item{classification} = $self->type('string', $bug->classification); } + if (filter_wants $params, 'comments', ['extra']) { + my @result; + my $comments + = $bug->comments({order => 'oldest_to_newest', after => $params->{new_since}}); + foreach my $comment (@$comments) { + next if $comment->is_private && !$user->is_insider; + push(@result, + $self->_translate_comment($comment, $params, ['extra'], 'comments')); + } + $item{'comments'} = \@result; + } if (filter_wants $params, 'component') { $item{component} = $self->type('string', $bug->component); } @@ -1484,6 +1485,16 @@ sub _bug_to_hash { my @groups = map { $self->type('string', $_->name) } @{$bug->groups_in}; $item{'groups'} = \@groups; } + if (filter_wants $params, 'history', ['extra']) { + my @result; + my ($activity) + = Bugzilla::Bug::GetBugActivity($bug->id, undef, $params->{new_since}); + foreach my $changeset (@$activity) { + push(@result, + $self->_changeset_to_hash($changeset, $params, ['extra'], 'history')); + } + $item{'history'} = \@result; + } if (filter_wants $params, 'is_open') { $item{'is_open'} = $self->type('boolean', $bug->status->is_open); } @@ -1550,7 +1561,7 @@ sub _bug_to_hash { } # Timetracking fields are only sent if the user can see them. - if (Bugzilla->user->is_timetracker) { + if ($user->is_timetracker) { if (filter_wants $params, 'estimated_time') { $item{'estimated_time'} = $self->type('double', $bug->estimated_time); } @@ -1650,6 +1661,32 @@ sub _attachment_to_hash { return $item; } +sub _changeset_to_hash { + my ($self, $changeset, $filters, $types, $prefix) = @_; + + my $item = { + when => $self->type('dateTime', $changeset->{when}), + who => $self->type('email', $changeset->{who}), + changes => [] + }; + + foreach my $change (@{$changeset->{changes}}) { + my $field_name = delete $change->{fieldname}; + my $api_field_type = $api_field_types{$field_name} || 'string'; + my $api_field_name = $api_field_names{$field_name} || $field_name; + my $attach_id = delete $change->{attachid}; + + $change->{field_name} = $self->type('string', $api_field_name); + $change->{removed} = $self->type($api_field_type, $change->{removed}); + $change->{added} = $self->type($api_field_type, $change->{added}); + $change->{attachment_id} = $self->type('int', $attach_id) if $attach_id; + + push (@{$item->{changes}}, $change); + } + + return filter($filters, $item, $types, $prefix); +} + sub _flag_to_hash { my ($self, $flag) = @_; @@ -2478,7 +2515,12 @@ ID of that attachment. Otherwise it will be null. =item text -C The actual text of the comment. +C The body of the comment, including any special text (such as +"this bug was marked as a duplicate of..."). + +=item raw_text + +C The body of the comment without any special additional text. =item creator @@ -2544,6 +2586,8 @@ C. =item REST API call added in Bugzilla B<5.0>. +=item C was added in Bugzilla B<6.0>. + =back @@ -2634,6 +2678,14 @@ C The login name of the user to whom the bug is assigned. C A hash containing detailed user information for the assigned_to. To see the keys included in the user detail hash, see below. +=item C + +C of hashes containing attachment details of the bug. See the attachments +section above for the object format. + +This is an B field returned only by specifying C or +C<_extra> in C. + =item C C of Cs. The ids of bugs that are "blocked" by this bug. @@ -2652,6 +2704,14 @@ members. To see the keys included in the user detail hash, see below. C The name of the current classification the bug is in. +=item C + +C of hashes containing comment details of the bug. See the comments +section above for the object format. + +This is an B field returned only by specifying C or C<_extra> +in C. + =item C C The name of the current component of this bug. @@ -2744,6 +2804,14 @@ Note, this field is only returned if a requestee is set. C of Cs. The names of all the groups that this bug is in. +=item C + +C of hashes containing change details of the bug. See the history section +below for the object format. + +This is an B field returned only by specifying C or C<_extra> +in C. + =item C C The unique numeric id of this bug. @@ -3027,7 +3095,8 @@ and all custom fields. =item The C item was added to the C return value in Bugzilla B<4.4>. -=item The C and C items were added in Bugzilla B<6.0>. +=item The C, C, C, C and +C fields were added in Bugzilla B<6.0>. =back diff --git a/docs/en/rst/api/core/v1/bug.rst b/docs/en/rst/api/core/v1/bug.rst index ffd49853f..91adb3326 100644 --- a/docs/en/rst/api/core/v1/bug.rst +++ b/docs/en/rst/api/core/v1/bug.rst @@ -246,6 +246,12 @@ These fields are returned only by specifying ``_extra`` or the field name in =================== ====== ==================================================== name type description =================== ====== ==================================================== +attachments array Each array item is an Attachment object. See + :ref:`rest_attachments` for details of the object. +comments array Each array item is a Comment object. See + :ref:`rest_comments` for details of the object. +history array Each array item is a History object. See + :ref:`rest_history` for details of the object. tags array Each array item is a tag name. Note that tags are personal to the currently logged in user and are not the same as comment tags. diff --git a/docs/en/rst/api/core/v1/comment.rst b/docs/en/rst/api/core/v1/comment.rst index a1ef7abb3..12c2277cd 100644 --- a/docs/en/rst/api/core/v1/comment.rst +++ b/docs/en/rst/api/core/v1/comment.rst @@ -86,7 +86,10 @@ attachment_id int If the comment was made on an attachment, this will be the ID of that attachment. Otherwise it will be null. count int The number of the comment local to the bug. The Description is 0, comments start with 1. -text string The actual text of the comment. +text string The body of the comment, including any special text + (such as "this bug was marked as a duplicate of..."). +raw_text string The body of the comment without any special additional + text. creator string The login name of the comment's author. time datetime The time (in Bugzilla's timezone) that the comment was added. diff --git a/extensions/EditComments/Extension.pm b/extensions/EditComments/Extension.pm index 0a3962c7e..519224790 100644 --- a/extensions/EditComments/Extension.pm +++ b/extensions/EditComments/Extension.pm @@ -18,8 +18,6 @@ use Bugzilla::Util; use Bugzilla::Error; use Bugzilla::Config::Common; use Bugzilla::Config::GroupSecurity; -use Bugzilla::WebService::Bug; -use Bugzilla::WebService::Util qw(filter_wants); our $VERSION = '1.0'; @@ -102,21 +100,6 @@ BEGIN { no warnings 'redefine'; *Bugzilla::Comment::activity = \&_get_activity; *Bugzilla::Comment::edit_count = \&_edit_count; - *Bugzilla::WebService::Bug::_super_translate_comment - = \&Bugzilla::WebService::Bug::_translate_comment; - *Bugzilla::WebService::Bug::_translate_comment = \&_new_translate_comment; -} - -sub _new_translate_comment { - my ($self, $comment, $filters) = @_; - - my $comment_hash = $self->_super_translate_comment($comment, $filters); - - if (filter_wants $filters, 'raw_text') { - $comment_hash->{raw_text} = $self->type('string', $comment->body); - } - - return $comment_hash; } sub _edit_count { return $_[0]->{'edit_count'}; }