summaryrefslogtreecommitdiffstats
path: root/extensions
diff options
context:
space:
mode:
authorByron Jones <glob@mozilla.com>2015-03-10 06:07:56 +0100
committerByron Jones <glob@mozilla.com>2015-03-10 06:07:56 +0100
commitef96ae157223b3309f7703798b32b0b386b2edff (patch)
treecd0f3c6f234d40998fa6e85ad32c3cac025b610a /extensions
parent9250c96075fda4a6a11b0f09e42423c650debcec (diff)
downloadbugzilla-ef96ae157223b3309f7703798b32b0b386b2edff.tar.gz
bugzilla-ef96ae157223b3309f7703798b32b0b386b2edff.tar.xz
Bug 1003701: add the ability for users to prevent review/feedback/needinfo requests
Diffstat (limited to 'extensions')
-rw-r--r--extensions/Needinfo/Extension.pm61
-rw-r--r--extensions/Needinfo/template/en/default/bug/needinfo.html.tmpl54
-rw-r--r--extensions/Needinfo/template/en/default/hook/account/prefs/account-field.html.tmpl25
-rw-r--r--extensions/Needinfo/template/en/default/hook/global/setting-descs-settings.none.tmpl11
-rw-r--r--extensions/Needinfo/template/en/default/hook/global/user-error-errors.html.tmpl4
-rw-r--r--extensions/Review/Extension.pm71
-rw-r--r--extensions/Review/template/en/default/hook/account/prefs/account-field.html.tmpl26
-rw-r--r--extensions/Review/template/en/default/hook/global/header-start.html.tmpl4
-rw-r--r--extensions/Review/template/en/default/hook/global/setting-descs-settings.none.tmpl11
-rw-r--r--extensions/Review/template/en/default/hook/global/user-error-errors.html.tmpl5
-rw-r--r--extensions/UserProfile/template/en/default/hook/account/prefs/account-start.html.tmpl (renamed from extensions/UserProfile/template/en/default/hook/account/prefs/account-field.html.tmpl)0
11 files changed, 238 insertions, 34 deletions
diff --git a/extensions/Needinfo/Extension.pm b/extensions/Needinfo/Extension.pm
index 26bca649e..c03c251b4 100644
--- a/extensions/Needinfo/Extension.pm
+++ b/extensions/Needinfo/Extension.pm
@@ -14,9 +14,18 @@ use Bugzilla::Error;
use Bugzilla::Flag;
use Bugzilla::FlagType;
use Bugzilla::User;
+use Bugzilla::User::Setting;
our $VERSION = '0.01';
+BEGIN {
+ *Bugzilla::User::needinfo_blocked = \&_user_needinfo_blocked;
+}
+
+sub _user_needinfo_blocked {
+ return $_[0]->settings->{block_needinfo}->{value} eq 'on';
+}
+
sub install_update_db {
my ($self, $args) = @_;
my $dbh = Bugzilla->dbh;
@@ -47,6 +56,11 @@ sub install_update_db {
});
}
+sub install_before_final_checks {
+ my ($self, $args) = @_;
+ add_setting('block_needinfo', ['on', 'off'], 'off');
+}
+
# Clear the needinfo? flag if comment is being given by
# requestee or someone used the override flag.
sub bug_start_of_update {
@@ -142,6 +156,7 @@ sub bug_start_of_update {
foreach my $requestee (keys %requestees) {
my $needinfo_flag = { type_id => $type->id, status => '?' };
if ($requestee ne 'anyone') {
+ _check_requestee($requestee);
$needinfo_flag->{requestee} = $requestee;
}
push(@new_flags, $needinfo_flag);
@@ -166,6 +181,34 @@ sub bug_start_of_update {
}
}
+sub _check_requestee {
+ my ($requestee) = @_;
+ my $user = ref($requestee)
+ ? $requestee
+ : Bugzilla::User->new({ name => $requestee, cache => 1 });
+ if ($user->needinfo_blocked) {
+ ThrowUserError('needinfo_blocked', { user => $user });
+ }
+}
+
+sub object_end_of_create {
+ my ($self, $args) = @_;
+ my $object = $args->{object};
+ return unless $object->isa('Bugzilla::Flag')
+ && $object->type->name eq 'needinfo'
+ && $object->requestee;
+ _check_requestee($object->requestee);
+}
+
+sub object_end_of_update {
+ my ($self, $args) = @_;
+ my $object = $args->{object};
+ return unless $object->isa('Bugzilla::Flag')
+ && $object->type->name eq 'needinfo'
+ && $object->requestee;
+ _check_requestee($object->requestee);
+}
+
sub object_before_delete {
my ($self, $args) = @_;
my $object = $args->{object};
@@ -183,4 +226,22 @@ sub object_before_delete {
}
}
+sub user_preferences {
+ my ($self, $args) = @_;
+ return unless
+ $args->{current_tab} eq 'account'
+ && $args->{save_changes};
+
+ my $input = Bugzilla->input_params;
+ my $dbh = Bugzilla->dbh;
+ my $settings = Bugzilla->user->settings;
+
+ $dbh->bz_start_transaction();
+ my $value = $input->{block_needinfo} ? 'on' : 'off';
+ my $setting = Bugzilla::User::Setting->new('block_needinfo');
+ $setting->validate_value($value);
+ $settings->{'block_needinfo'}->set($value);
+ $dbh->bz_commit_transaction();
+}
+
__PACKAGE__->NAME;
diff --git a/extensions/Needinfo/template/en/default/bug/needinfo.html.tmpl b/extensions/Needinfo/template/en/default/bug/needinfo.html.tmpl
index 5edd70f72..7e32509bf 100644
--- a/extensions/Needinfo/template/en/default/bug/needinfo.html.tmpl
+++ b/extensions/Needinfo/template/en/default/bug/needinfo.html.tmpl
@@ -6,22 +6,24 @@
# defined by the Mozilla Public License, v. 2.0.
#%]
-[% needinfo_flagtype = "" %]
-[% needinfo_flags = [] %]
+[%
+ needinfo_flagtype = "";
+ needinfo_flags = [];
-[% FOREACH type = bug.flag_types %]
- [% IF type.name == 'needinfo' %]
- [% needinfo_flagtype = type %]
- [% FOREACH flag = type.flags %]
- [% IF flag.status == '?' %]
- [% needinfo_flags.push(flag) %]
- [% END %]
- [% END %]
- [% LAST IF needinfo_flagtype %]
- [% END %]
-[% END %]
+ FOREACH type = bug.flag_types;
+ IF type.name == 'needinfo';
+ needinfo_flagtype = type;
+ FOREACH flag = type.flags;
+ IF flag.status == '?';
+ needinfo_flags.push(flag);
+ END;
+ END;
+ LAST IF needinfo_flagtype;
+ END;
+ END;
+
+ available_mentors = bug.mentors( exclude_needinfo_blocked => 1 );
-[%
BLOCK needinfo_comment_div;
match = needinfo_flags.last.creation_date.match('^(\d{4})\.(\d{2})\.(\d{2})(.+)$');
date = "$match.0-$match.1-$match.2$match.3";
@@ -131,9 +133,9 @@
identity = '[% bug.qa_contact.realname || bug.qa_contact.login FILTER html FILTER js %]';
} else if (role == 'user') {
identity = '[% user.realname || user.login FILTER html FILTER js %]';
- [% FOREACH mentor = bug.mentors %]
+ [% FOREACH mentor = available_mentors %]
} else if (role == '[% mentor.login FILTER js %]') {
- identity = '[% mentor.realname || mentor.login FILTER html FILTER js +%] [%+ IF bug.mentors.size > 1 %](mentor)[% END %]';
+ identity = '[% mentor.realname || mentor.login FILTER html FILTER js +%] [%+ IF available_mentors.size > 1 %](mentor)[% END %]';
[% END %]
}
YAHOO.util.Dom.get('needinfo_role_identity').innerHTML = identity;
@@ -167,15 +169,21 @@
<label for="needinfo">Need more information from</label>
<select name="needinfo_role" id="needinfo_role" onchange="needinfo_role_changed()">
<option value="other">other</option>
- <option value="reporter">reporter</option>
- <option value="assigned_to">assignee</option>
- [% IF Param('useqacontact') && bug.qa_contact.login != "" %]
+ [% IF NOT bug.reporter.needinfo_blocked %]
+ <option value="reporter">reporter</option>
+ [% END %]
+ [% IF NOT bug.assigned_to.needinfo_blocked %]
+ <option value="assigned_to">assignee</option>
+ [% END %]
+ [% IF Param('useqacontact') && bug.qa_contact.login != "" && !bug.qa_contact.needinfo_blocked %]
<option value="qa_contact">qa contact</option>
[% END %]
- <option value="user">myself</option>
- [% FOREACH mentor = bug.mentors %]
- <option [% IF bug.mentors.size > 1 %]title="mentor"[% END %] value="[% mentor.login FILTER html %]">
- [% bug.mentors.size == 1 ? "mentor" : mentor.login FILTER html %]
+ [% IF NOT user.needinfo_blocked %]
+ <option value="user">myself</option>
+ [% END %]
+ [% FOREACH mentor = available_mentors %]
+ <option [% IF available_mentors.size > 1 %]title="mentor"[% END %] value="[% mentor.login FILTER html %]">
+ [% available_mentors.size == 1 ? "mentor" : mentor.login FILTER html %]
</option>
[% END %]
</select>
diff --git a/extensions/Needinfo/template/en/default/hook/account/prefs/account-field.html.tmpl b/extensions/Needinfo/template/en/default/hook/account/prefs/account-field.html.tmpl
new file mode 100644
index 000000000..4e0253610
--- /dev/null
+++ b/extensions/Needinfo/template/en/default/hook/account/prefs/account-field.html.tmpl
@@ -0,0 +1,25 @@
+[%# 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.
+ #%]
+
+<tr>
+ [%# this section is shared by both the needinfo and review extensions %]
+ [%# only show the label once %]
+ [% IF request_blocked_header %]
+ <td></td>
+ [% ELSE %]
+ [% request_blocked_header = 1 %]
+ <th align="right" valign="top">Request blocking:</th>
+ [% END %]
+ <td>
+ <input type="checkbox" id="block_needinfo" name="block_needinfo" value="1"
+ [% " checked" IF user.settings.block_needinfo.value == "on" %]>
+ <label for="block_needinfo">
+ Block needinfo requests
+ </label>
+ </td>
+</tr>
diff --git a/extensions/Needinfo/template/en/default/hook/global/setting-descs-settings.none.tmpl b/extensions/Needinfo/template/en/default/hook/global/setting-descs-settings.none.tmpl
new file mode 100644
index 000000000..ec435e58b
--- /dev/null
+++ b/extensions/Needinfo/template/en/default/hook/global/setting-descs-settings.none.tmpl
@@ -0,0 +1,11 @@
+[%# 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.
+ #%]
+
+[%
+ setting_descs.block_needinfo = "Block needinfo requests"
+%]
diff --git a/extensions/Needinfo/template/en/default/hook/global/user-error-errors.html.tmpl b/extensions/Needinfo/template/en/default/hook/global/user-error-errors.html.tmpl
index f1241bc61..42d47e928 100644
--- a/extensions/Needinfo/template/en/default/hook/global/user-error-errors.html.tmpl
+++ b/extensions/Needinfo/template/en/default/hook/global/user-error-errors.html.tmpl
@@ -10,4 +10,8 @@
[% title = 'Needinfo Illegal Change' %]
Only the requestee or a user with the required permissions can clear a
needinfo flag.
+[% ELSIF error == "needinfo_blocked" %]
+ [% title = "Needinfo Request Blocked" %]
+ [% user.identity FILTER html %] is not currently accepting "needinfo"
+ requests.
[% END %]
diff --git a/extensions/Review/Extension.pm b/extensions/Review/Extension.pm
index 9eb831071..ab15e8a7b 100644
--- a/extensions/Review/Extension.pm
+++ b/extensions/Review/Extension.pm
@@ -20,7 +20,8 @@ use Bugzilla::Extension::Review::Util;
use Bugzilla::Install::Filesystem;
use Bugzilla::Search;
use Bugzilla::User;
-use Bugzilla::Util qw(clean_text diff_arrays);
+use Bugzilla::User::Setting;
+use Bugzilla::Util qw(clean_text);
use constant UNAVAILABLE_RE => qr/\b(?:unavailable|pto|away)\b/i;
@@ -40,14 +41,15 @@ BEGIN {
*Bugzilla::Bug::is_mentor = \&_bug_is_mentor;
*Bugzilla::Bug::set_bug_mentors = \&_bug_set_bug_mentors;
*Bugzilla::User::review_count = \&_user_review_count;
+ *Bugzilla::User::reviews_blocked = \&_user_reviews_blocked;
}
#
# monkey-patched methods
#
-sub _product_reviewers { _reviewers($_[0], 'product', $_[1]) }
-sub _product_reviewers_objs { _reviewers_objs($_[0], 'product', $_[1]) }
+sub _product_reviewers { _reviewers($_[0], 'product', $_[1]) }
+sub _product_reviewers_objs { _reviewers_objs($_[0], 'product', $_[1]) }
sub _component_reviewers { _reviewers($_[0], 'component', $_[1]) }
sub _component_reviewers_objs { _reviewers_objs($_[0], 'component', $_[1]) }
@@ -71,8 +73,11 @@ sub _reviewers_objs {
my %user_map = map { $_->id => $_ } @$users;
my @reviewers = map { $user_map{$_} } @$user_ids;
if (!$include_disabled) {
- @reviewers = grep { $_->is_enabled
- && $_->name !~ UNAVAILABLE_RE } @reviewers;
+ @reviewers = grep {
+ $_->is_enabled
+ && $_->name !~ UNAVAILABLE_RE
+ && !$_->reviews_blocked
+ } @reviewers;
}
$object->{reviewers} = \@reviewers;
}
@@ -96,12 +101,17 @@ sub _user_review_count {
return $self->{review_count};
}
+sub _user_reviews_blocked {
+ return $_[0]->settings->{block_reviews}->{value} eq 'on';
+}
+
#
# mentor
#
sub _bug_mentors {
- my ($self) = @_;
+ my ($self, $options) = @_;
+ $options //= {};
my $dbh = Bugzilla->dbh;
if (!$self->{bug_mentors}) {
my $mentor_ids = $dbh->selectcol_arrayref("
@@ -110,14 +120,20 @@ sub _bug_mentors {
$self->id);
$self->{bug_mentors} = [];
foreach my $mentor_id (@$mentor_ids) {
- push(@{ $self->{bug_mentors} },
- Bugzilla::User->new({ id => $mentor_id, cache => 1 }));
+ push(@{ $self->{bug_mentors} }, Bugzilla::User->new({ id => $mentor_id, cache => 1 }));
}
$self->{bug_mentors} = [
sort { $a->login cmp $b->login } @{ $self->{bug_mentors} }
];
}
- return $self->{bug_mentors};
+ my @result = @{ $self->{bug_mentors} };
+ if ($options->{exclude_needinfo_blocked}) {
+ @result = grep { !$_->needinfo_blocked } @result;
+ }
+ if ($options->{exclude_review_blocked}) {
+ @result = grep { !$_->reviews_blocked } @result;
+ }
+ return \@result;
}
sub _bug_is_mentor {
@@ -322,6 +338,7 @@ sub object_end_of_create {
});
}
elsif (_is_countable_flag($object) && $object->requestee_id && $object->status eq '?') {
+ _check_requestee($object);
_adjust_request_count($object, +1);
}
if (_is_countable_flag($object)) {
@@ -373,6 +390,9 @@ sub object_end_of_update {
if ($old_status ne '?' && $new_status eq '?') {
# setting flag to ?
_adjust_request_count($object, +1);
+ if ($object->requestee_id) {
+ _check_requestee($object);
+ }
}
elsif ($old_status eq '?' && $new_status ne '?') {
# setting flag from ?
@@ -384,12 +404,14 @@ sub object_end_of_update {
}
elsif (!$old_object->requestee_id && $object->requestee_id) {
# setting requestee
+ _check_requestee($object);
_adjust_request_count($object, +1);
}
elsif ($old_object->requestee_id && $object->requestee_id
&& $old_object->requestee_id != $object->requestee_id)
{
# changing requestee
+ _check_requestee($object);
_adjust_request_count($old_object, -1);
_adjust_request_count($object, +1);
}
@@ -429,6 +451,15 @@ sub _is_countable_flag {
return $type_name eq 'review' || $type_name eq 'feedback' || $type_name eq 'needinfo';
}
+sub _check_requestee {
+ my ($flag) = @_;
+ return unless $flag->type->name eq 'review' || $flag->type->name eq 'feedback';
+ if ($flag->requestee->reviews_blocked) {
+ ThrowUserError('reviews_blocked',
+ { user => $flag->requestee, flagtype => $flag->type->name });
+ }
+}
+
sub _log_flag_state_activity {
my ($self, $flag, $status, $timestamp, $setter_id) = @_;
@@ -601,6 +632,24 @@ sub webservice {
$dispatch->{Review} = "Bugzilla::Extension::Review::WebService";
}
+sub user_preferences {
+ my ($self, $args) = @_;
+ return unless
+ $args->{current_tab} eq 'account'
+ && $args->{save_changes};
+
+ my $input = Bugzilla->input_params;
+ my $dbh = Bugzilla->dbh;
+ my $settings = Bugzilla->user->settings;
+
+ $dbh->bz_start_transaction();
+ my $value = $input->{block_reviews} ? 'on' : 'off';
+ my $setting = Bugzilla::User::Setting->new('block_reviews');
+ $setting->validate_value($value);
+ $settings->{'block_reviews'}->set($value);
+ $dbh->bz_commit_transaction();
+}
+
sub page_before_template {
my ($self, $args) = @_;
@@ -945,5 +994,9 @@ sub install_filesystem {
};
}
+sub install_before_final_checks {
+ my ($self, $args) = @_;
+ add_setting('block_reviews', ['on', 'off'], 'off');
+}
__PACKAGE__->NAME;
diff --git a/extensions/Review/template/en/default/hook/account/prefs/account-field.html.tmpl b/extensions/Review/template/en/default/hook/account/prefs/account-field.html.tmpl
new file mode 100644
index 000000000..baf3a6b94
--- /dev/null
+++ b/extensions/Review/template/en/default/hook/account/prefs/account-field.html.tmpl
@@ -0,0 +1,26 @@
+[%# 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.
+ #%]
+
+<tr>
+ [%# this section is shared by both the needinfo and review extensions %]
+ [%# only show the label once %]
+ [% IF request_blocked_header %]
+ <td></td>
+ [% ELSE %]
+ [% request_blocked_header = 1 %]
+ <th align="right" valign="top">Request blocking:</th>
+ [% END %]
+ <td>
+ <input type="checkbox" id="block_reviews" name="block_reviews" value="1"
+ [% " checked" IF user.settings.block_reviews.value == "on" %]
+ >
+ <label for="block_reviews">
+ Block review and feedback requests
+ </label>
+ </td>
+</tr>
diff --git a/extensions/Review/template/en/default/hook/global/header-start.html.tmpl b/extensions/Review/template/en/default/hook/global/header-start.html.tmpl
index ff166ac4c..a1ced8108 100644
--- a/extensions/Review/template/en/default/hook/global/header-start.html.tmpl
+++ b/extensions/Review/template/en/default/hook/global/header-start.html.tmpl
@@ -24,12 +24,12 @@
[% IF bug %]
[%# create attachment %]
- [% mentors = bug.mentors %]
+ [% mentors = bug.mentors( exclude_review_blocked => 1 ) %]
[% product_obj = bug.product_obj %]
[% component_obj = bug.component_obj %]
[% ELSIF attachment.bug %]
[%# edit attachment %]
- [% mentors = attachment.bug.mentors %]
+ [% mentors = attachment.bug.mentors( exclude_review_blocked => 1 ) %]
[% product_obj = attachment.bug.product_obj %]
[% component_obj = attachment.bug.component_obj %]
[% ELSE %]
diff --git a/extensions/Review/template/en/default/hook/global/setting-descs-settings.none.tmpl b/extensions/Review/template/en/default/hook/global/setting-descs-settings.none.tmpl
new file mode 100644
index 000000000..f265aed10
--- /dev/null
+++ b/extensions/Review/template/en/default/hook/global/setting-descs-settings.none.tmpl
@@ -0,0 +1,11 @@
+[%# 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.
+ #%]
+
+[%
+ setting_descs.block_reviews = "Block review and feedback requests"
+%]
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 ca143cca3..4fcd47a68 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
@@ -23,4 +23,9 @@
[% title = "Parameters Required" %]
You may not search flag state activity without any search terms.
+[% ELSIF error == "reviews_blocked" %]
+ [% title = "Request Blocked" %]
+ [% user.identity FILTER html %] is not currently accepting
+ '[% flagtype FILTER html %]' requests.
+
[% END %]
diff --git a/extensions/UserProfile/template/en/default/hook/account/prefs/account-field.html.tmpl b/extensions/UserProfile/template/en/default/hook/account/prefs/account-start.html.tmpl
index f2e3aad01..f2e3aad01 100644
--- a/extensions/UserProfile/template/en/default/hook/account/prefs/account-field.html.tmpl
+++ b/extensions/UserProfile/template/en/default/hook/account/prefs/account-start.html.tmpl