summaryrefslogtreecommitdiffstats
path: root/extensions
diff options
context:
space:
mode:
Diffstat (limited to 'extensions')
-rw-r--r--extensions/BMO/web/styles/reports.css6
-rw-r--r--extensions/Review/Extension.pm46
-rw-r--r--extensions/Review/lib/WebService.pm181
-rw-r--r--extensions/Review/template/en/default/hook/global/user-error-errors.html.tmpl6
-rw-r--r--extensions/Review/template/en/default/hook/reports/menu-end.html.tmpl16
-rw-r--r--extensions/Review/template/en/default/pages/review_suggestions.html.tmpl76
-rw-r--r--extensions/Review/web/styles/reports.css41
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&amp;component=Administration&amp;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%;
+}