diff options
Diffstat (limited to 'Bugzilla/WebService')
-rw-r--r-- | Bugzilla/WebService/Bug.pm | 266 | ||||
-rw-r--r-- | Bugzilla/WebService/Product.pm | 13 | ||||
-rw-r--r-- | Bugzilla/WebService/Server/JSONRPC.pm | 5 | ||||
-rw-r--r-- | Bugzilla/WebService/Server/XMLRPC.pm | 7 | ||||
-rw-r--r-- | Bugzilla/WebService/User.pm | 117 | ||||
-rw-r--r-- | Bugzilla/WebService/Util.pm | 19 |
6 files changed, 383 insertions, 44 deletions
diff --git a/Bugzilla/WebService/Bug.pm b/Bugzilla/WebService/Bug.pm index 578c06ec5..b6cfe897b 100644 --- a/Bugzilla/WebService/Bug.pm +++ b/Bugzilla/WebService/Bug.pm @@ -82,6 +82,8 @@ BEGIN { sub fields { my ($self, $params) = validate(@_, 'ids', 'names'); + Bugzilla->switch_to_shadow_db(); + my @fields; if (defined $params->{ids}) { my $ids = $params->{ids}; @@ -117,11 +119,12 @@ sub fields { my (@values, $has_values); if ( ($field->is_select and $field->name ne 'product') - or grep($_ eq $field->name, PRODUCT_SPECIFIC_FIELDS)) + or grep($_ eq $field->name, PRODUCT_SPECIFIC_FIELDS) + or $field->name eq 'keywords') { $has_values = 1; @values = @{ $self->_legal_field_values({ field => $field }) }; - } + } if (grep($_ eq $field->name, PRODUCT_SPECIFIC_FIELDS)) { $value_field = 'product'; @@ -211,6 +214,15 @@ sub _legal_field_values { } } + elsif ($field_name eq 'keywords') { + my @legal_keywords = Bugzilla::Keyword->get_all; + foreach my $value (@legal_keywords) { + push (@result, { + name => $self->type('string', $value->name), + description => $self->type('string', $value->description), + }); + } + } else { my @values = Bugzilla::Field::Choice->type($field)->get_all(); foreach my $value (@values) { @@ -242,7 +254,7 @@ sub comments { my $bug_ids = $params->{ids} || []; my $comment_ids = $params->{comment_ids} || []; - my $dbh = Bugzilla->dbh; + my $dbh = Bugzilla->switch_to_shadow_db(); my $user = Bugzilla->user; my %bugs; @@ -297,9 +309,10 @@ sub _translate_comment { return filter $filters, { id => $self->type('int', $comment->id), bug_id => $self->type('int', $comment->bug_id), - creator => $self->type('string', $comment->author->login), - author => $self->type('string', $comment->author->login), + creator => $self->type('email', $comment->author->login), + author => $self->type('email', $comment->author->login), time => $self->type('dateTime', $comment->creation_ts), + creation_time => $self->type('dateTime', $comment->creation_ts), is_private => $self->type('boolean', $comment->is_private), text => $self->type('string', $comment->body_full), attachment_id => $self->type('int', $attach_id), @@ -309,8 +322,11 @@ sub _translate_comment { sub get { my ($self, $params) = validate(@_, 'ids'); + Bugzilla->switch_to_shadow_db(); + my $ids = $params->{ids}; - defined $ids || ThrowCodeError('param_required', { param => 'ids' }); + (defined $ids && scalar @$ids) + || ThrowCodeError('param_required', { param => 'ids' }); my @bugs; my @faults; @@ -343,34 +359,39 @@ sub get { sub history { my ($self, $params) = validate(@_, 'ids'); + Bugzilla->switch_to_shadow_db(); + my $ids = $params->{ids}; defined $ids || ThrowCodeError('param_required', { param => 'ids' }); - my @return; + my %api_name = reverse %{ Bugzilla::Bug::FIELD_MAP() }; + $api_name{'bug_group'} = 'groups'; + my @return; foreach my $bug_id (@$ids) { my %item; my $bug = Bugzilla::Bug->check($bug_id); $bug_id = $bug->id; $item{id} = $self->type('int', $bug_id); - my ($activity) = Bugzilla::Bug::GetBugActivity($bug_id); + my ($activity) = Bugzilla::Bug::GetBugActivity($bug_id, undef, $params->{start_time}); my @history; foreach my $changeset (@$activity) { my %bug_history; $bug_history{when} = $self->type('dateTime', $changeset->{when}); - $bug_history{who} = $self->type('string', $changeset->{who}); + $bug_history{who} = $self->type('email', $changeset->{who}); $bug_history{changes} = []; foreach my $change (@{ $changeset->{changes} }) { + my $api_field = $api_name{$change->{fieldname}} || $change->{fieldname}; my $attach_id = delete $change->{attachid}; if ($attach_id) { $change->{attachment_id} = $self->type('int', $attach_id); } $change->{removed} = $self->type('string', $change->{removed}); $change->{added} = $self->type('string', $change->{added}); - $change->{field_name} = $self->type('string', - delete $change->{fieldname}); + $change->{field_name} = $self->type('string', $api_field); + delete $change->{fieldname}; push (@{$bug_history{changes}}, $change); } @@ -399,7 +420,9 @@ sub history { sub search { my ($self, $params) = @_; - + + Bugzilla->switch_to_shadow_db(); + if ( defined($params->{offset}) and !defined($params->{limit}) ) { ThrowCodeError('param_required', { param => 'limit', function => 'Bug.search()' }); @@ -439,16 +462,25 @@ sub search { delete $match_params{'include_fields'}; delete $match_params{'exclude_fields'}; + my $count_only = delete $match_params{count_only}; + my $bugs = Bugzilla::Bug->match(\%match_params); my $visible = Bugzilla->user->visible_bugs($bugs); - my @hashes = map { $self->_bug_to_hash($_, $params) } @$visible; - return { bugs => \@hashes }; + if ($count_only) { + return { bug_count => scalar @$visible }; + } + else { + my @hashes = map { $self->_bug_to_hash($_, $params) } @$visible; + return { bugs => \@hashes }; + } } sub possible_duplicates { my ($self, $params) = validate(@_, 'product'); my $user = Bugzilla->user; + Bugzilla->switch_to_shadow_db(); + # Undo the array-ification that validate() does, for "summary". $params->{summary} || ThrowCodeError('param_required', { function => 'Bug.possible_duplicates', param => 'summary' }); @@ -469,6 +501,12 @@ sub possible_duplicates { sub update { my ($self, $params) = validate(@_, 'ids'); + # BMO: Don't allow updating of bugs if disabled + if (Bugzilla->params->{disable_bug_updates}) { + ThrowErrorPage('bug/process/updates-disabled.html.tmpl', + 'Bug updates are currently disabled.'); + } + my $user = Bugzilla->login(LOGIN_REQUIRED); my $dbh = Bugzilla->dbh; @@ -563,6 +601,13 @@ sub update { sub create { my ($self, $params) = @_; + + # BMO: Don't allow updating of bugs if disabled + if (Bugzilla->params->{disable_bug_updates}) { + ThrowErrorPage('bug/process/updates-disabled.html.tmpl', + 'Bug updates are currently disabled.'); + } + Bugzilla->login(LOGIN_REQUIRED); $params = Bugzilla::Bug::map_fields($params); my $bug = Bugzilla::Bug->create($params); @@ -573,6 +618,8 @@ sub create { sub legal_values { my ($self, $params) = @_; + Bugzilla->switch_to_shadow_db(); + defined $params->{field} or ThrowCodeError('param_required', { param => 'field' }); @@ -625,6 +672,12 @@ sub add_attachment { my ($self, $params) = validate(@_, 'ids'); my $dbh = Bugzilla->dbh; + # BMO: Don't allow updating of bugs if disabled + if (Bugzilla->params->{disable_bug_updates}) { + ThrowErrorPage('bug/process/updates-disabled.html.tmpl', + 'Bug updates are currently disabled.'); + } + Bugzilla->login(LOGIN_REQUIRED); defined $params->{ids} || ThrowCodeError('param_required', { param => 'ids' }); @@ -673,6 +726,12 @@ sub add_attachment { sub add_comment { my ($self, $params) = @_; + # BMO: Don't allow updating of bugs if disabled + if (Bugzilla->params->{disable_bug_updates}) { + ThrowErrorPage('bug/process/updates-disabled.html.tmpl', + 'Bug updates are currently disabled.'); + } + #The user must login in order add a comment Bugzilla->login(LOGIN_REQUIRED); @@ -717,6 +776,12 @@ sub add_comment { sub update_see_also { my ($self, $params) = @_; + # BMO: Don't allow updating of bugs if disabled + if (Bugzilla->params->{disable_bug_updates}) { + ThrowErrorPage('bug/process/updates-disabled.html.tmpl', + 'Bug updates are currently disabled.'); + } + my $user = Bugzilla->login(LOGIN_REQUIRED); # Check parameters @@ -764,6 +829,8 @@ sub update_see_also { sub attachments { my ($self, $params) = validate(@_, 'ids', 'attachment_ids'); + Bugzilla->switch_to_shadow_db(); + if (!(defined $params->{ids} or defined $params->{attachment_ids})) { @@ -842,18 +909,18 @@ sub _bug_to_hash { # We don't do the SQL calls at all if the filter would just # eliminate them anyway. if (filter_wants $params, 'assigned_to') { - $item{'assigned_to'} = $self->type('string', $bug->assigned_to->login); + $item{'assigned_to'} = $self->type('email', $bug->assigned_to->login); } if (filter_wants $params, 'blocks') { my @blocks = map { $self->type('int', $_) } @{ $bug->blocked }; $item{'blocks'} = \@blocks; } if (filter_wants $params, 'cc') { - my @cc = map { $self->type('string', $_) } @{ $bug->cc || [] }; + my @cc = map { $self->type('email', $_) } @{ $bug->cc || [] }; $item{'cc'} = \@cc; } if (filter_wants $params, 'creator') { - $item{'creator'} = $self->type('string', $bug->reporter->login); + $item{'creator'} = $self->type('email', $bug->reporter->login); } if (filter_wants $params, 'depends_on') { my @depends_on = map { $self->type('int', $_) } @{ $bug->dependson }; @@ -877,13 +944,16 @@ sub _bug_to_hash { } if (filter_wants $params, 'qa_contact') { my $qa_login = $bug->qa_contact ? $bug->qa_contact->login : ''; - $item{'qa_contact'} = $self->type('string', $qa_login); + $item{'qa_contact'} = $self->type('email', $qa_login); } if (filter_wants $params, 'see_also') { my @see_also = map { $self->type('string', $_->name) } @{ $bug->see_also }; $item{'see_also'} = \@see_also; } + if (filter_wants $params, 'flags') { + $item{'flags'} = [ map { $self->_flag_to_hash($_) } @{$bug->flags} ]; + } # And now custom fields my @custom_fields = Bugzilla->active_custom_fields; @@ -912,6 +982,7 @@ sub _bug_to_hash { # No need to format $bug->deadline specially, because Bugzilla::Bug # already does it for us. $item{'deadline'} = $self->type('string', $bug->deadline); + $item{'actual_time'} = $self->type('double', $bug->actual_time); } if (Bugzilla->user->id) { @@ -932,9 +1003,6 @@ sub _bug_to_hash { sub _attachment_to_hash { my ($self, $attach, $filters) = @_; - # Skipping attachment flags for now. - delete $attach->{flags}; - my $item = filter $filters, { creation_time => $self->type('dateTime', $attach->attached), last_change_time => $self->type('dateTime', $attach->modification_time), @@ -953,7 +1021,7 @@ sub _attachment_to_hash { # the filter wants them. foreach my $field (qw(creator attacher)) { if (filter_wants $filters, $field) { - $item->{$field} = $self->type('string', $attach->attacher->login); + $item->{$field} = $self->type('email', $attach->attacher->login); } } @@ -961,6 +1029,31 @@ sub _attachment_to_hash { $item->{'data'} = $self->type('base64', $attach->data); } + if (filter_wants $filters, 'flags') { + $item->{'flags'} = [ map { $self->_flag_to_hash($_) } @{$attach->flags} ]; + } + + return $item; +} + +sub _flag_to_hash { + my ($self, $flag) = @_; + + my $item = { + id => $self->type('int', $flag->id), + name => $self->type('string', $flag->name), + type_id => $self->type('int', $flag->type_id), + creation_date => $self->type('dateTime', $flag->creation_date), + modification_date => $self->type('dateTime', $flag->modification_date), + status => $self->type('string', $flag->status) + }; + + foreach my $field (qw(setter requestee)) { + my $field_id = $field . "_id"; + $item->{$field} = $self->type('email', $flag->$field->login) + if $flag->$field_id; + } + return $item; } @@ -1099,7 +1192,7 @@ values of the field are shown in the user interface. Can be null. This is an array of hashes, representing the legal values for select-type (drop-down and multiple-selection) fields. This is also -populated for the C<component>, C<version>, and C<target_milestone> +populated for the C<component>, C<version>, C<target_milestone>, and C<keywords> fields, but not for the C<product> field (you must use L<Product.get_accessible_products|Bugzilla::WebService::Product/get_accessible_products> for that. @@ -1132,6 +1225,11 @@ if the C<value_field> is set to one of the values listed in this array. Note that for per-product fields, C<value_field> is set to C<'product'> and C<visibility_values> will reflect which product(s) this value appears in. +=item C<description> + +C<string> The description of the value. This item is only included for the +C<keywords> field. + =item C<is_open> C<boolean> For C<bug_status> values, determines whether this status @@ -1361,6 +1459,48 @@ Also returned as C<attacher>, for backwards-compatibility with older Bugzillas. (However, this backwards-compatibility will go away in Bugzilla 5.0.) +=item C<flags> + +An array of hashes containing the information about flags currently set +for each attachment. Each flag hash contains the following items: + +=over + +=item C<id> + +C<int> The id of the flag. + +=item C<name> + +C<string> The name of the flag. + +=item C<type_id> + +C<int> The type id of the flag. + +=item C<creation_date> + +C<dateTime> The timestamp when this flag was originally created. + +=item C<modification_date> + +C<dateTime> The timestamp when the flag was last modified. + +=item C<status> + +C<string> The current status of the flag. + +=item C<setter> + +C<string> The login name of the user who created or last modified the flag. + +=item C<requestee> + +C<string> The login name of the user this flag has been requested to be granted or denied. +Note, this field is only returned if a requestee is set. + +=back + =back =item B<Errors> @@ -1397,6 +1537,8 @@ C<summary>. =back +=item The C<flags> array was added in Bugzilla B<4.4>. + =back @@ -1501,6 +1643,13 @@ Bugzillas. (However, this backwards-compatibility will go away in Bugzilla C<dateTime> The time (in Bugzilla's timezone) that the comment was added. +=item creation_time + +C<dateTime> This is exactly same as the C<time> key. Use this field instead of +C<time> for consistency with other methods including L</get> and L</attachments>. +For compatibility, C<time> is still usable. However, please note that C<time> +may be deprecated and removed in a future release. + =item is_private C<boolean> True if this comment is private (only visible to a certain @@ -1542,6 +1691,8 @@ C<creator>. =back +=item C<creation_time> was added in Bugzilla B<4.4>. + =back @@ -1601,6 +1752,13 @@ the valid ids. Each hash contains the following items: =over +=item C<actual_time> + +C<double> The total number of hours that this bug has taken (so far). + +If you are not in the time-tracking group, this field will not be included +in the return value. + =item C<alias> C<string> The unique alias of this bug. @@ -1659,6 +1817,48 @@ take. If you are not in the time-tracking group, this field will not be included in the return value. +=item C<flags> + +An array of hashes containing the information about flags currently set +for the bug. Each flag hash contains the following items: + +=over + +=item C<id> + +C<int> The id of the flag. + +=item C<name> + +C<string> The name of the flag. + +=item C<type_id> + +C<int> The type id of the flag. + +=item C<creation_date> + +C<dateTime> The timestamp when this flag was originally created. + +=item C<modification_date> + +C<dateTime> The timestamp when the flag was last modified. + +=item C<status> + +C<string> The current status of the flag. + +=item C<setter> + +C<string> The login name of the user who created or last modified the flag. + +=item C<requestee> + +C<string> The login name of the user this flag has been requested to be granted or denied. +Note, this field is only returned if a requestee is set. + +=back + =item C<groups> C<array> of C<string>s. The names of all the groups that this bug is in. @@ -1886,8 +2086,12 @@ C<op_sys>, C<platform>, C<qa_contact>, C<remaining_time>, C<see_also>, C<target_milestone>, C<update_token>, C<url>, C<version>, C<whiteboard>, and all custom fields. -=back +=item The C<flags> array was added in Bugzilla B<4.4>. + +=item The C<actual_time> item was added to the C<bugs> return value +in Bugzilla B<4.4>. +=back =back @@ -1918,6 +2122,11 @@ Note that it's possible for aliases to be disabled in Bugzilla, in which case you will be told that you have specified an invalid bug_id if you try to specify an alias. (It will be error 100.) +=item C<start_time> + +An optional C<datetime> string that only shows changes at and after a specific +time. + =back =item B<Returns> @@ -1993,6 +2202,10 @@ The same as L</get>. =item Added in Bugzilla B<3.4>. +=item Field names changed to be more consistent with other methods in Bugzilla B<4.4>. + +=item As of Bugzilla B<4.4>, field names now match names used by L<Bug.update|/"update"> for consistency. + =back =back @@ -2153,6 +2366,11 @@ C<string> Search the "Status Whiteboard" field on bugs for a substring. Works the same as the C<summary> field described above, but searches the Status Whiteboard field. +=item C<count_only> + +C<boolean> If count_only set to true, only a single hash key called C<bug_count> +will be returned which is the number of bugs that matched the search. + =back =item B<Returns> diff --git a/Bugzilla/WebService/Product.pm b/Bugzilla/WebService/Product.pm index 3cd0d0a6c..7d31f2c38 100644 --- a/Bugzilla/WebService/Product.pm +++ b/Bugzilla/WebService/Product.pm @@ -47,23 +47,28 @@ BEGIN { *get_products = \&get } # Get the ids of the products the user can search sub get_selectable_products { + Bugzilla->switch_to_shadow_db(); return {ids => [map {$_->id} @{Bugzilla->user->get_selectable_products}]}; } # Get the ids of the products the user can enter bugs against sub get_enterable_products { + Bugzilla->switch_to_shadow_db(); return {ids => [map {$_->id} @{Bugzilla->user->get_enterable_products}]}; } # Get the union of the products the user can search and enter bugs against. sub get_accessible_products { + Bugzilla->switch_to_shadow_db(); return {ids => [map {$_->id} @{Bugzilla->user->get_accessible_products}]}; } # Get a list of actual products, based on list of ids or names sub get { my ($self, $params) = validate(@_, 'ids', 'names'); - + + Bugzilla->switch_to_shadow_db(); + # Only products that are in the users accessible products, # can be allowed to be returned my $accessible_products = Bugzilla->user->get_accessible_products; @@ -167,11 +172,11 @@ sub _component_to_hash { name => $self->type('string', $component->name), description => - $self->type('string' , $component->description), + $self->type('string', $component->description), default_assigned_to => - $self->type('string' , $component->default_assignee->login), + $self->type('email', $component->default_assignee->login), default_qa_contact => - $self->type('string' , $component->default_qa_contact->login), + $self->type('email', $component->default_qa_contact->login), sort_key => # sort_key is returned to match Bug.fields 0, is_active => diff --git a/Bugzilla/WebService/Server/JSONRPC.pm b/Bugzilla/WebService/Server/JSONRPC.pm index cec1c29ea..63e9ca335 100644 --- a/Bugzilla/WebService/Server/JSONRPC.pm +++ b/Bugzilla/WebService/Server/JSONRPC.pm @@ -38,7 +38,7 @@ BEGIN { use Bugzilla::Error; use Bugzilla::WebService::Constants; use Bugzilla::WebService::Util qw(taint_data); -use Bugzilla::Util qw(correct_urlbase trim disable_utf8); +use Bugzilla::Util; use HTTP::Message; use MIME::Base64 qw(decode_base64 encode_base64); @@ -221,6 +221,9 @@ sub type { utf8::encode($value) if utf8::is_utf8($value); $retval = encode_base64($value, ''); } + elsif ($type eq 'email' && Bugzilla->params->{'webservice_email_filter'}) { + $retval = email_filter($value); + } return $retval; } diff --git a/Bugzilla/WebService/Server/XMLRPC.pm b/Bugzilla/WebService/Server/XMLRPC.pm index 025fb8f19..824f6ee2d 100644 --- a/Bugzilla/WebService/Server/XMLRPC.pm +++ b/Bugzilla/WebService/Server/XMLRPC.pm @@ -30,6 +30,7 @@ if ($ENV{MOD_PERL}) { } use Bugzilla::WebService::Constants; +use Bugzilla::Util; # Allow WebService methods to call XMLRPC::Lite's type method directly BEGIN { @@ -41,6 +42,12 @@ BEGIN { $value = Bugzilla::WebService::Server->datetime_format_outbound($value); $value =~ s/-//g; } + elsif ($type eq 'email') { + $type = 'string'; + if (Bugzilla->params->{'webservice_email_filter'}) { + $value = email_filter($value); + } + } return XMLRPC::Data->type($type)->value($value); }; } diff --git a/Bugzilla/WebService/User.pm b/Bugzilla/WebService/User.pm index deb7518ec..758c69aa8 100644 --- a/Bugzilla/WebService/User.pm +++ b/Bugzilla/WebService/User.pm @@ -29,6 +29,7 @@ use Bugzilla::Group; use Bugzilla::User; use Bugzilla::Util qw(trim); use Bugzilla::WebService::Util qw(filter validate); +use Bugzilla::Hook; # Don't need auth to login use constant LOGIN_EXEMPT => { @@ -126,6 +127,8 @@ sub create { sub get { my ($self, $params) = validate(@_, 'names', 'ids'); + Bugzilla->switch_to_shadow_db(); + defined($params->{names}) || defined($params->{ids}) || defined($params->{match}) || ThrowCodeError('params_required', @@ -154,8 +157,8 @@ sub get { \@user_objects, $params); @users = map {filter $params, { id => $self->type('int', $_->id), - real_name => $self->type('string', $_->name), - name => $self->type('string', $_->login), + real_name => $self->type('string', $_->name), + name => $self->type('email', $_->login), }} @$in_group; return { users => \@users }; @@ -196,33 +199,39 @@ sub get { } } } - + my $in_group = $self->_filter_users_by_group( \@user_objects, $params); if (Bugzilla->user->in_group('editusers')) { - @users = + @users = map {filter $params, { id => $self->type('int', $_->id), real_name => $self->type('string', $_->name), - name => $self->type('string', $_->login), - email => $self->type('string', $_->email), + name => $self->type('email', $_->login), + email => $self->type('email', $_->email), can_login => $self->type('boolean', $_->is_enabled ? 1 : 0), + groups => $self->_filter_bless_groups($_->groups), email_enabled => $self->type('boolean', $_->email_enabled), login_denied_text => $self->type('string', $_->disabledtext), + saved_searches => [map { $self->_query_to_hash($_) } @{ $_->queries }], }} @$in_group; - } else { @users = map {filter $params, { id => $self->type('int', $_->id), real_name => $self->type('string', $_->name), - name => $self->type('string', $_->login), - email => $self->type('string', $_->email), + name => $self->type('email', $_->login), + email => $self->type('email', $_->email), can_login => $self->type('boolean', $_->is_enabled ? 1 : 0), + groups => $self->_filter_bless_groups($_->groups), + saved_searches => [map { $self->_query_to_hash($_) } @{ $_->queries }], }} @$in_group; } + Bugzilla::Hook::process('webservice_user_get', + { webservice => $self, params => $params, users => \@users }); + return { users => \@users }; } @@ -259,6 +268,40 @@ sub _user_in_any_group { return 0; } +sub _filter_bless_groups { + my ($self, $groups) = @_; + my $user = Bugzilla->user; + + my @filtered_groups; + foreach my $group (@$groups) { + next unless ($user->in_group('editusers') || $user->can_bless($group->id)); + push(@filtered_groups, $self->_group_to_hash($group)); + } + + return \@filtered_groups; +} + +sub _group_to_hash { + my ($self, $group) = @_; + my $item = { + id => $self->type('int', $group->id), + name => $self->type('string', $group->name), + description => $self->type('string', $group->description), + }; + return $item; +} + +sub _query_to_hash { + my ($self, $query) = @_; + my $item = { + id => $self->type('int', $query->id), + name => $self->type('string', $query->name), + url => $self->type('string', $query->url), + }; + + return $item; +} + 1; __END__ @@ -581,10 +624,60 @@ C<string> A text field that holds the reason for disabling a user from logging into bugzilla, if empty then the user account is enabled. Otherwise it is disabled/closed. +=item groups + +C<array> An array of group hashes the user is a member of. Each hash describes +the group and contains the following items: + +=over + +=item id + +C<int> The group id + +=item name + +C<string> The name of the group + +=item description + +C<string> The description for the group + +=back + +=over + +=item saved_searches + +C<array> An array of hashes, each of which represents a user's saved search and has +the following keys: + +=over + +=item id + +C<int> An integer id uniquely identifying the saved search. + +=item name + +C<string> The name of the saved search. + +=item url + +C<string> The CGI parameters for the saved search. + +=back + +B<Note>: The elements of the returned array (i.e. hashes) are ordered by the +name of each saved search. + +=back + B<Note>: If you are not logged in to Bugzilla when you call this function, you will only be returned the C<id>, C<name>, and C<real_name> items. If you are logged in and not in editusers group, you will only be returned the C<id>, C<name>, -C<real_name>, C<email>, and C<can_login> items. +C<real_name>, C<email>, and C<can_login> items. The groups returned are filtered +based on your permission to bless each group. =back @@ -625,6 +718,10 @@ exist or you do not belong to it. =item C<include_disabled> added in Bugzilla B<4.0>. Default behavior for C<match> has changed to only returning enabled accounts. +=item C<groups> Added in Bugzilla B<4.4>. + +=item C<saved_searches> Added in Bugzilla B<4.4>. + =item Error 804 has been added in Bugzilla 4.0.9 and 4.2.4. It's now illegal to pass a group name you don't belong to. diff --git a/Bugzilla/WebService/Util.pm b/Bugzilla/WebService/Util.pm index fe4105ca2..dbf670bf7 100644 --- a/Bugzilla/WebService/Util.pm +++ b/Bugzilla/WebService/Util.pm @@ -34,22 +34,24 @@ our @EXPORT_OK = qw( validate ); -sub filter ($$) { - my ($params, $hash) = @_; +sub filter ($$;$) { + my ($params, $hash, $prefix) = @_; my %newhash = %$hash; foreach my $key (keys %$hash) { - delete $newhash{$key} if !filter_wants($params, $key); + delete $newhash{$key} if !filter_wants($params, $key, $prefix); } return \%newhash; } -sub filter_wants ($$) { - my ($params, $field) = @_; +sub filter_wants ($$;$) { + my ($params, $field, $prefix) = @_; my %include = map { $_ => 1 } @{ $params->{'include_fields'} || [] }; my %exclude = map { $_ => 1 } @{ $params->{'exclude_fields'} || [] }; + $field = "${prefix}.${field}" if $prefix; + if (defined $params->{include_fields}) { return 0 if !$include{$field}; } @@ -136,6 +138,13 @@ of WebService methods. Given a hash (the second argument to this subroutine), this will remove any keys that are I<not> in C<include_fields> and then remove any keys that I<are> in C<exclude_fields>. +An optional third option can be passed that prefixes the field name to allow +filtering of data two or more levels deep. + +For example, if you want to filter out the C<id> key/value in components returned +by Product.get, you would use the value C<component.id> in your C<exclude_fields> +list. + =head2 filter_wants Returns C<1> if a filter would preserve the specified field when passing |