summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authormkanat%bugzilla.org <>2009-01-07 22:22:08 +0100
committermkanat%bugzilla.org <>2009-01-07 22:22:08 +0100
commit559f89582199e4ca531398a5cadd03632526d525 (patch)
tree152c46e8fae572662b9004a9658f44dcc874f96b
parent1ef4ee777a69bc857fb1b4ee95e2521904d1a5cc (diff)
downloadbugzilla-559f89582199e4ca531398a5cadd03632526d525.tar.gz
bugzilla-559f89582199e4ca531398a5cadd03632526d525.tar.xz
Bug 450403: Add ability to view comments via the web service (Bug.comments)
Patch By Max Kanat-Alexander <mkanat@bugzilla.org> r=dkl, a=mkanat
-rwxr-xr-xBugzilla/WebService.pm62
-rwxr-xr-xBugzilla/WebService/Bug.pm196
-rwxr-xr-xBugzilla/WebService/Constants.pm4
-rwxr-xr-xBugzilla/WebService/User.pm32
-rw-r--r--template/en/default/global/code-error.html.tmpl6
-rw-r--r--template/en/default/global/user-error.html.tmpl6
6 files changed, 278 insertions, 28 deletions
diff --git a/Bugzilla/WebService.pm b/Bugzilla/WebService.pm
index 438a66710..615abf68c 100755
--- a/Bugzilla/WebService.pm
+++ b/Bugzilla/WebService.pm
@@ -294,3 +294,65 @@ an error 302, there won't be an error -302.
Sometimes a function will throw an error that doesn't have a specific
error code. In this case, the code will be C<-32000> if it's a "fatal"
error, and C<32000> if it's a "transient" error.
+
+=head1 COMMON PARAMETERS
+
+Many Webservice methods take similar arguments. Instead of re-writing
+the documentation for each method, we document the parameters here, once,
+and then refer back to this documentation from the individual methods
+where these parameters are used.
+
+=head2 Limiting What Fields Are Returned
+
+Many WebService methods return an array of structs with various
+fields in the structs. (For example, L<Bugzilla::WebService::Bug/get>
+returns a list of C<bugs> that have fields like C<id>, C<summary>,
+C<creation_time>, etc.)
+
+These parameters allow you to limit what fields are present in
+the structs, to possibly improve performance or save some bandwidth.
+
+=over
+
+=item C<include_fields> (array)
+
+An array of strings, representing the (case-sensitive) names of fields.
+Only the fields specified in this hash will be returned, the rest will
+not be included.
+
+If you specify an empty array, then this function will return empty
+hashes.
+
+Invalid field names are ignored.
+
+Example:
+
+ User.get( ids => [1], include_fields => ['id', 'name'] )
+
+would return something like:
+
+ { users => [{ id => 1, name => 'user@domain.com' }] }
+
+=item C<exclude_fields> (array)
+
+An array of strings, representing the (case-sensitive) names of fields.
+The fields specified will not be included in the returned hashes.
+
+If you specify all the fields, then this function will return empty
+hashes.
+
+Invalid field names are ignored.
+
+Specifying fields here overrides C<include_fields>, so if you specify a
+field in both, it will be excluded, not included.
+
+Example:
+
+ User.get( ids => [1], exclude_fields => ['name'] )
+
+would return something like:
+
+ { users => [{ id => 1, real_name => 'John Smith' }] }
+
+=back
+
diff --git a/Bugzilla/WebService/Bug.pm b/Bugzilla/WebService/Bug.pm
index aaaf753a3..10ea1f886 100755
--- a/Bugzilla/WebService/Bug.pm
+++ b/Bugzilla/WebService/Bug.pm
@@ -27,6 +27,7 @@ use Bugzilla::Constants;
use Bugzilla::Error;
use Bugzilla::Field;
use Bugzilla::WebService::Constants;
+use Bugzilla::WebService::Util qw(filter);
use Bugzilla::Bug;
use Bugzilla::BugMail;
use Bugzilla::Util qw(trim);
@@ -58,6 +59,84 @@ BEGIN { *get_bugs = \&get }
# Methods #
###########
+sub comments {
+ my ($self, $params) = @_;
+ if (!(defined $params->{bug_ids} || defined $params->{comment_ids})) {
+ ThrowCodeError('params_required',
+ { function => 'Bug.comments',
+ params => ['bug_ids', 'comment_ids'] });
+ }
+
+ my $bug_ids = $params->{bug_ids} || [];
+ my $comment_ids = $params->{comment_ids} || [];
+
+ my $dbh = Bugzilla->dbh;
+ my $user = Bugzilla->user;
+
+ my %bugs;
+ foreach my $bug_id (@$bug_ids) {
+ my $bug = Bugzilla::Bug->check($bug_id);
+ # We want the API to always return comments in the same order.
+ my $comments = Bugzilla::Bug::GetComments(
+ $bug->id, 'oldest_to_newest');
+ my @result;
+ foreach my $comment (@$comments) {
+ next if $comment->{isprivate} && !$user->is_insider;
+ $comment->{bug_id} = $bug->id;
+ push(@result, $self->_translate_comment($comment, $params));
+ }
+ $bugs{$bug->id}{'comments'} = \@result;
+ }
+
+ my %comments;
+ if (scalar @$comment_ids) {
+ my @ids = map { trim($_) } @$comment_ids;
+ my @sql_ids = map { $dbh->quote($_) } @ids;
+ my $comment_data = $dbh->selectall_arrayref(
+ 'SELECT comment_id AS id, bug_id, who, bug_when AS time,
+ isprivate, thetext AS body, type, extra_data
+ FROM longdescs WHERE ' . $dbh->sql_in('comment_id', \@sql_ids),
+ {Slice=>{}});
+
+ # See if we were passed any invalid comment ids.
+ my %got_ids = map { $_->{id} => 1 } @$comment_data;
+ foreach my $comment_id (@ids) {
+ if (!$got_ids{$comment_id}) {
+ ThrowUserError('comment_id_invalid', { id => $comment_id });
+ }
+ }
+
+ # Now make sure that we can see all the associated bugs.
+ my %got_bug_ids = map { $_->{bug_id} => 1 } @$comment_data;
+ Bugzilla::Bug->check($_) foreach (keys %got_bug_ids);
+
+ foreach my $comment (@$comment_data) {
+ if ($comment->{isprivate} && !$user->is_insider) {
+ ThrowUserError('comment_is_private', { id => $comment->{id} });
+ }
+ $comment->{author} = new Bugzilla::User($comment->{who});
+ $comment->{body} = Bugzilla::Bug::format_comment($comment);
+ $comments{$comment->{id}} =
+ $self->_translate_comment($comment, $params);
+ }
+ }
+
+ return { bugs => \%bugs, comments => \%comments };
+}
+
+# Helper for Bug.comments
+sub _translate_comment {
+ my ($self, $comment, $filters) = @_;
+ return filter $filters, {
+ id => $self->type('int', $comment->{id}),
+ bug_id => $self->type('int', $comment->{bug_id}),
+ author => $self->type('string', $comment->{author}->login),
+ time => $self->type('dateTime', $comment->{'time'}),
+ is_private => $self->type('boolean', $comment->{isprivate}),
+ text => $self->type('string', $comment->{body}),
+ };
+}
+
sub get {
my ($self, $params) = @_;
my $ids = $params->{ids};
@@ -326,6 +405,123 @@ You specified a field that doesn't exist or isn't a drop-down field.
=over
+
+=item C<comments>
+
+B<UNSTABLE>
+
+=over
+
+=item B<Description>
+
+This allows you to get data about comments, given a list of bugs
+and/or comment ids.
+
+=item B<Params>
+
+B<Note>: At least one of C<bug_ids> or C<comment_ids> is required.
+
+In addition to the parameters below, this method also accepts the
+standard L<include_fields|Bugzilla::WebService/include_fields> and
+L<exclude_fields|Bugzilla::WebService/exclude_fields> arguments.
+
+=over
+
+=item C<bug_ids>
+
+C<array> An array that can contain both bug IDs and bug aliases.
+All of the comments (that are visible to you) will be returned for the
+specified bugs.
+
+=item C<comment_ids>
+
+C<array> An array of integer comment_ids. These comments will be
+returned individually, separate from any other comments in their
+respective bugs.
+
+=back
+
+=item B<Returns>
+
+Two items are returned:
+
+=over
+
+=item C<bugs>
+
+This is used for bugs specified in C<bug_ids>. This is a hash,
+where the keys are the numeric ids of the bugs, and the value is
+a hash with a single key, C<comments>, which is an array of comments.
+(The format of comments is described below.)
+
+Note that any individual bug will only be returned once, so if you
+specify an id multiple times in C<bug_ids>, it will still only be
+returned once.
+
+=item C<comments>
+
+Each individual comment requested in C<comment_ids> is returned here,
+in a hash where the numeric comment id is the key, and the value
+is the comment. (The format of comments is described below.)
+
+=back
+
+A "comment" as described above is a hash that contains the following
+keys:
+
+=over
+
+=item id
+
+C<int> The globally unique ID for the comment.
+
+=item bug_id
+
+C<int> The ID of the bug that this comment is on.
+
+=item text
+
+C<string> The actual text of the comment.
+
+=item author
+
+C<string> The login name of the comment's author.
+
+=item time
+
+C<dateTime> The time (in Bugzilla's timezone) that the comment was added.
+
+=item is_private
+
+C<boolean> True if this comment is private (only visible to a certain
+group called the "insidergroup"), False otherwise.
+
+=back
+
+=item B<Errors>
+
+This method can throw all the same errors as L</get>. In addition,
+it can also throw the following errors:
+
+=over
+
+=item 110 (Comment Is Private)
+
+You specified the id of a private comment in the C<comment_ids>
+argument, and you are not in the "insider group" that can see
+private comments.
+
+=item 111 (Invalid Comment ID)
+
+You specified an id in the C<comment_ids> argument that is invalid--either
+you specified something that wasn't a number, or there is no comment with
+that id.
+
+=back
+
+=back
+
+
=item C<get>
B<EXPERIMENTAL>
diff --git a/Bugzilla/WebService/Constants.pm b/Bugzilla/WebService/Constants.pm
index 593801a6f..07b51e5f1 100755
--- a/Bugzilla/WebService/Constants.pm
+++ b/Bugzilla/WebService/Constants.pm
@@ -51,6 +51,7 @@ use constant WS_ERROR_CODE => {
# Generic Bugzilla::Object errors are 50-99.
object_not_specified => 50,
param_required => 50,
+ params_required => 50,
object_does_not_exist => 51,
# Bug errors usually occupy the 100-200 range.
improper_bug_id_field_value => 100,
@@ -79,6 +80,9 @@ use constant WS_ERROR_CODE => {
invalid_field_name => 108,
# Not authorized to edit the bug
product_edit_denied => 109,
+ # Comment-related errors
+ comment_is_private => 110,
+ comment_id_invalid => 111,
# Authentication errors are usually 300-400.
invalid_username_or_password => 300,
diff --git a/Bugzilla/WebService/User.pm b/Bugzilla/WebService/User.pm
index 24b9be709..6283f55a1 100755
--- a/Bugzilla/WebService/User.pm
+++ b/Bugzilla/WebService/User.pm
@@ -451,6 +451,10 @@ B<Note>: At least one of C<ids>, C<names>, or C<match> must be specified.
B<Note>: Users will not be returned more than once, so even if a user
is matched by more than one argument, only one user will be returned.
+In addition to the parameters below, this method also accepts the
+standard L<include_fields|Bugzilla::WebService/include_fields> and
+L<exclude_fields|Bugzilla::WebService/exclude_fields> arguments.
+
=over
=item C<ids> (array)
@@ -482,34 +486,6 @@ if they try. (This is to make it harder for spammers to harvest email
addresses from Bugzilla, and also to enforce the user visibility
restrictions that are implemented on some Bugzillas.)
-=item C<include_fields> (array)
-
-An array of strings, representing the names of keys in the hashes
-this function returns. Only the fields specified in this hash will be
-returned, the rest will not be included.
-
-Essentially, this is a way to make the return value smaller, for performance
-or bandwidth reasons.
-
-If you specify an empty array, then this function will return empty hashes.
-
-Invalid field names are ignored.
-
-=item C<exclude_fields> (array)
-
-An array of strings, representing the names of keys in the hashes this
-function returns. The fields specified will not be excluded from the
-returned hashes.
-
-Essentially, this is a way to exclude certain fields from the returned
-hashes, for performance or bandwidth reasons.
-
-If you specify all the fields, then this function will return empty hashes.
-
-Invalid field names are ignored.
-
-This overrides C<include_fields>.
-
=back
=item B<Returns>
diff --git a/template/en/default/global/code-error.html.tmpl b/template/en/default/global/code-error.html.tmpl
index 37e052f81..da8f902d4 100644
--- a/template/en/default/global/code-error.html.tmpl
+++ b/template/en/default/global/code-error.html.tmpl
@@ -345,6 +345,12 @@
a <code>[% param FILTER html %]</code> argument, and that
argument was not set.
+ [% ELSIF error == "params_required" %]
+ [% title = "Missing Parameter" %]
+ The function <code>[% function FILTER html %]</code> requires
+ that you set one of the following parameters:
+ <code>[% params.join(', ') FILTER html %]</code>
+
[% ELSIF error == "product_empty_group_controls" %]
[% title = "Missing Group Controls" %]
New settings must be defined to edit group controls for
diff --git a/template/en/default/global/user-error.html.tmpl b/template/en/default/global/user-error.html.tmpl
index 191f6eebd..d92b04622 100644
--- a/template/en/default/global/user-error.html.tmpl
+++ b/template/en/default/global/user-error.html.tmpl
@@ -239,10 +239,16 @@
[% title = "Chart Too Large" %]
Sorry, but 2000 x 2000 is the maximum size for a chart.
+ [% ELSIF error == "comment_id_invalid" %]
+ [% id FILTER html %] is not a valid comment id.
+
[% ELSIF error == "comment_invalid_isprivate" %]
You tried to modify the privacy of comment id [% id FILTER html %],
but that is not a valid comment on this [% terms.bug %].
+ [% ELSIF error == "comment_is_private" %]
+ Comment id [% id FILTER html %] is private.
+
[% ELSIF error == "comment_required" %]
[% title = "Comment Required" %]
You have to specify a