diff options
Diffstat (limited to 'extensions')
7 files changed, 370 insertions, 2 deletions
diff --git a/extensions/BMO/web/styles/reports.css b/extensions/BMO/web/styles/reports.css index ccc931eec..06ae52d68 100644 --- a/extensions/BMO/web/styles/reports.css +++ b/extensions/BMO/web/styles/reports.css @@ -32,7 +32,11 @@ } #report-header { - background: #cccccc; + background-color: #cccccc; +} + +.report_subheader { + background-color: #dddddd; } .report_row_odd { diff --git a/extensions/Review/Extension.pm b/extensions/Review/Extension.pm index 51755ca2c..9a19f528c 100644 --- a/extensions/Review/Extension.pm +++ b/extensions/Review/Extension.pm @@ -159,7 +159,7 @@ sub object_end_of_update { sub _new_reviewers_from_input { if (!Bugzilla->input_params->{reviewers}) { - return (undef, []); + return ('', []); } Bugzilla::User::match_field({ 'reviewers' => {'type' => 'multi'} }); my $new = Bugzilla->input_params->{reviewers}; @@ -266,6 +266,50 @@ sub flag_end_of_update { } # +# web service / reports +# + +sub webservice { + my ($self, $args) = @_; + my $dispatch = $args->{dispatch}; + $dispatch->{Review} = "Bugzilla::Extension::Review::WebService"; +} + +sub page_before_template { + my ($self, $args) = @_; + return unless $args->{page_id} eq 'review_suggestions.html'; + my $user = Bugzilla->login(LOGIN_REQUIRED); + my $products = []; + my @products = sort { lc($a->name) cmp lc($b->name) } + @{ Bugzilla->user->get_accessible_products }; + foreach my $product_obj (@products) { + my $has_reviewers = 0; + my $product = { + name => $product_obj->name, + components => [], + reviewers => $product_obj->reviewers_objs, + }; + $has_reviewers = scalar @{ $product->{reviewers} }; + + foreach my $component_obj (@{ $product_obj->components }) { + my $component = { + name => $component_obj->name, + reviewers => $component_obj->reviewers_objs, + }; + if (@{ $component->{reviewers} }) { + push @{ $product->{components} }, $component; + $has_reviewers = 1; + } + } + + if ($has_reviewers) { + push @$products, $product; + } + } + $args->{vars}->{products} = $products; +} + +# # installation # diff --git a/extensions/Review/lib/WebService.pm b/extensions/Review/lib/WebService.pm new file mode 100644 index 000000000..e31244e5f --- /dev/null +++ b/extensions/Review/lib/WebService.pm @@ -0,0 +1,181 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# +# This Source Code Form is "Incompatible With Secondary Licenses", as +# defined by the Mozilla Public License, v. 2.0. + +package Bugzilla::Extension::Review::WebService; + +use strict; +use warnings; + +use base qw(Bugzilla::WebService); + +use Bugzilla::Bug; +use Bugzilla::Component; +use Bugzilla::Error; + +sub suggestions { + my ($self, $params) = @_; + my $dbh = Bugzilla->switch_to_shadow_db(); + + my ($product, $component); + if (exists $params->{bug_id}) { + my $bug = Bugzilla::Bug->check($params->{bug_id}); + $product = $bug->product_obj; + $component = $bug->component_obj; + } + elsif (exists $params->{product}) { + $product = Bugzilla::Product->check($params->{product}); + if (exists $params->{component}) { + $component = Bugzilla::Component->check({ + product => $product, name => $params->{component} + }); + } + } + else { + ThrowUserError("reviewer_suggestions_param_required"); + } + + my $reviewers = []; + if ($component) { + $reviewers = $component->reviewers_objs; + } + if (!@$reviewers) { + $reviewers = $product->reviewers_objs; + } + + my @result; + foreach my $reviewer (@$reviewers) { + push @result, { + id => $self->type('int', $reviewer->id), + email => $self->type('email', $reviewer->login), + name => $self->type('string', $reviewer->name), + }; + } + return \@result; +} + +sub rest_resources { + return [ + # bug-id + qr{^/review/suggestions/(\d+)$}, { + GET => { + method => 'suggestions', + params => sub { + return { bug_id => $_[0] }; + }, + }, + }, + # product/component + qr{^/review/suggestions/([^/]+)/(.+)$}, { + GET => { + method => 'suggestions', + params => sub { + return { product => $_[0], component => $_[1] }; + }, + }, + }, + # just product + qr{^/review/suggestions/([^/]+)$}, { + GET => { + method => 'suggestions', + params => sub { + return { product => $_[0] }; + }, + }, + }, + # named parameters + qr{^/review/suggestions$}, { + GET => { + method => 'suggestions', + }, + }, + ]; +}; + +1; + +__END__ +=head1 NAME + +Bugzilla::Extension::Review::WebService - Functions for the Mozilla specific +'review' flag optimisations. + +=head1 METHODS + +See L<Bugzilla::WebService> for a description of how parameters are passed, +and what B<STABLE>, B<UNSTABLE>, and B<EXPERIMENTAL> mean. + +Although the data input and output is the same for JSONRPC, XMLRPC and REST, +the directions for how to access the data via REST is noted in each method +where applicable. + +=head2 suggestions + +B<EXPERIMENTAL> + +=over + +=item B<Description> + +Returns the list of suggestions for reviewers. + +=item B<REST> + +GET /rest/review/suggestions/C<bug-id> + +GET /rest/review/suggestions/C<product-name> + +GET /rest/review/suggestions/C<product-name>/C<component-name> + +GET /rest/review/suggestions?product=C<product-name> + +GET /rest/review/suggestions?product=C<product-name>&component=C<component-name> + +The returned data format is the same as below. + +=item B<Params> + +Query by Bug: + +=over + +=over + +=item C<bug_id> (integer) - The bug ID. + +=back + +=back + +Query by Product or Component: + +=over + +=over + +=item C<product> (string) - The product name. + +=item C<component> (string) - The component name (optional). If providing a C<component>, a C<product> must also be provided. + +=back + +=back + +=item B<Returns> + +An array of hashes with the following keys/values: + +=over + +=item C<id> (integer) - The user's ID. + +=item C<email> (string) - The user's email address (aka login). + +=item C<name> (string) - The user's display name (may not match the Bugzilla "real name"). + +=back + +=back diff --git a/extensions/Review/template/en/default/hook/global/user-error-errors.html.tmpl b/extensions/Review/template/en/default/hook/global/user-error-errors.html.tmpl index 4265f4b32..856ff3c75 100644 --- a/extensions/Review/template/en/default/hook/global/user-error-errors.html.tmpl +++ b/extensions/Review/template/en/default/hook/global/user-error-errors.html.tmpl @@ -9,4 +9,10 @@ [% IF error == "reviewer_required" %] [% title = "Reviewer Required" %] You must provide a reviewer for review requests. + +[% ELSIF error == "reviewer_suggestions_param_required" %] + [% title = "Parameter Required" %] + You must provide either a bug_id, or a product (and optionally a + component). + [% END %] diff --git a/extensions/Review/template/en/default/hook/reports/menu-end.html.tmpl b/extensions/Review/template/en/default/hook/reports/menu-end.html.tmpl new file mode 100644 index 000000000..7396e4fcb --- /dev/null +++ b/extensions/Review/template/en/default/hook/reports/menu-end.html.tmpl @@ -0,0 +1,16 @@ +[%# This Source Code Form is subject to the terms of the Mozilla Public + # License, v. 2.0. If a copy of the MPL was not distributed with this + # file, You can obtain one at http://mozilla.org/MPL/2.0/. + # + # This Source Code Form is "Incompatible With Secondary Licenses", as + # defined by the Mozilla Public License, v. 2.0. + #%] + +<ul> + <li> + <strong> + <a href="[% urlbase FILTER none %]page.cgi?id=review_suggestions.html">Suggested Reviers</a> + </strong> - All suggestions for the "review" flag. + </li> +</ul> + diff --git a/extensions/Review/template/en/default/pages/review_suggestions.html.tmpl b/extensions/Review/template/en/default/pages/review_suggestions.html.tmpl new file mode 100644 index 000000000..5d9132e40 --- /dev/null +++ b/extensions/Review/template/en/default/pages/review_suggestions.html.tmpl @@ -0,0 +1,76 @@ +[%# This Source Code Form is subject to the terms of the Mozilla Public + # License, v. 2.0. If a copy of the MPL was not distributed with this + # file, You can obtain one at http://mozilla.org/MPL/2.0/. + # + # This Source Code Form is "Incompatible With Secondary Licenses", as + # defined by the Mozilla Public License, v. 2.0. + #%] + +[% INCLUDE global/header.html.tmpl + title = "Suggested Reviewers Report" + style_urls = [ "extensions/BMO/web/styles/reports.css", + "extensions/Review/web/styles/reports.css" ] +%] + +Products: +<ul> + [% FOREACH product = products %] + <li> + <a href="#[% product.name FILTER uri %]"> + [% product.name FILTER html %] + </a> + </li> + [% END %] +</ul> + +<a href="enter_bug.cgi?product=bugzilla.mozilla.org&component=Administration&format=__default__">Request a change</a> + +<table id="report" class="hover" cellspacing="0"> + +<tr id="report-header"> + <th>Product/Component</th> + <th>Suggested Reviewers</th> +</tr> + +[% FOREACH product = products %] + <tr class="report_subheader"> + <td class="product_name"> + <a name="[% product.name FILTER html %]"> + [% product.name FILTER html %] + </a> + </td> + <td> + </td> + </tr> + [% row_class = "report_row_even" %] + [% FOREACH component = product.components %] + <tr class="[% row_class FILTER none %]"> + <td class="component_name">[% component.name FILTER html %]</td> + <td class="reviewers"> + [% FOREACH reviewer = component.reviewers %] + <span title="[% reviewer.name FILTER html %]"> + [% reviewer.email FILTER html %]</span> + [% ", " UNLESS loop.last %] + [% END %] + </td> + </tr> + [% row_class = row_class == "report_row_even" ? "report_row_odd" : "report_row_even" %] + [% END %] + [% IF product.reviewers.size %] + <tr class="[% row_class FILTER none %]"> + <td class="other_components">All [% product.components.size ? "other" : "" %] components</td> + <td class="reviewers"> + [% FOREACH reviewer = product.reviewers %] + <span title="[% reviewer.name FILTER html %]"> + [% reviewer.email FILTER html %]</span> + [% ", " UNLESS loop.last %] + [% END %] + </td> + </tr> + [% row_class = row_class == "report_row_even" ? "report_row_odd" : "report_row_even" %] + [% END %] +[% END %] + +</table> + +[% INCLUDE global/footer.html.tmpl %] diff --git a/extensions/Review/web/styles/reports.css b/extensions/Review/web/styles/reports.css new file mode 100644 index 000000000..bbbf93559 --- /dev/null +++ b/extensions/Review/web/styles/reports.css @@ -0,0 +1,41 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This Source Code Form is "Incompatible With Secondary Licenses", as + * defined by the Mozilla Public License, v. 2.0. */ + +#report { + margin-top: 1em; +} + +.product_name { + font-weight: bold; + white-space: nowrap; +} + +.product_name a { + color: inherit; +} + +.product_name a:hover { + color: inherit; + text-decoration: none; +} + +.component_name, .other_components { + padding: 0 1em; + white-space: nowrap; +} + +.component_name:before, .other_components:before { + content: "\a0\a0\a0\a0"; +} + +.other_components { + font-style: italic; +} + +.reviewers { + width: 100%; +} |