summaryrefslogtreecommitdiffstats
path: root/extensions/Needinfo
diff options
context:
space:
mode:
Diffstat (limited to 'extensions/Needinfo')
-rw-r--r--extensions/Needinfo/Config.pm18
-rw-r--r--extensions/Needinfo/Extension.pm180
-rw-r--r--extensions/Needinfo/template/en/default/bug/needinfo.html.tmpl158
-rw-r--r--extensions/Needinfo/template/en/default/hook/attachment/create-form_before_submit.html.tmpl16
-rw-r--r--extensions/Needinfo/template/en/default/hook/attachment/edit-after_comment_textarea.html.tmpl11
-rw-r--r--extensions/Needinfo/template/en/default/hook/bug/edit-after_comment_commit_button.html.tmpl11
-rw-r--r--extensions/Needinfo/template/en/default/hook/global/header-start.html.tmpl12
-rw-r--r--extensions/Needinfo/template/en/default/hook/global/user-error-errors.html.tmpl13
-rw-r--r--extensions/Needinfo/template/en/default/hook/request/email-after_summary.txt.tmpl13
-rw-r--r--extensions/Needinfo/web/styles/needinfo.css10
10 files changed, 442 insertions, 0 deletions
diff --git a/extensions/Needinfo/Config.pm b/extensions/Needinfo/Config.pm
new file mode 100644
index 000000000..86c99ec59
--- /dev/null
+++ b/extensions/Needinfo/Config.pm
@@ -0,0 +1,18 @@
+# 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::Needinfo;
+use strict;
+
+use constant NAME => 'Needinfo';
+
+use constant REQUIRED_MODULES => [
+];
+
+use constant OPTIONAL_MODULES => [
+];
+
+__PACKAGE__->NAME;
diff --git a/extensions/Needinfo/Extension.pm b/extensions/Needinfo/Extension.pm
new file mode 100644
index 000000000..2a4bfa3b3
--- /dev/null
+++ b/extensions/Needinfo/Extension.pm
@@ -0,0 +1,180 @@
+# 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::Needinfo;
+
+use strict;
+
+use base qw(Bugzilla::Extension);
+
+use Bugzilla::Error;
+use Bugzilla::Flag;
+use Bugzilla::FlagType;
+use Bugzilla::User;
+
+our $VERSION = '0.01';
+
+sub install_update_db {
+ my ($self, $args) = @_;
+ my $dbh = Bugzilla->dbh;
+
+ if (@{ Bugzilla::FlagType::match({ name => 'needinfo' }) }) {
+ return;
+ }
+
+ print "Creating needinfo flag ... " .
+ "enable the Needinfo feature by editing the flag's properties.\n";
+
+ # Initially populate the list of exclusions as __Any__:__Any__ to
+ # allow admin to decide which products to enable the flag for.
+ my $flagtype = Bugzilla::FlagType->create({
+ name => 'needinfo',
+ description => "Set this flag when the bug is in need of additional information",
+ target_type => 'bug',
+ cc_list => '',
+ sortkey => 1,
+ is_active => 1,
+ is_requestable => 1,
+ is_requesteeble => 1,
+ is_multiplicable => 0,
+ request_group => '',
+ grant_group => '',
+ inclusions => [],
+ exclusions => ['0:0'],
+ });
+}
+
+# Clear the needinfo? flag if comment is being given by
+# requestee or someone used the override flag.
+sub bug_start_of_update {
+ my ($self, $args) = @_;
+ my $bug = $args->{bug};
+ my $old_bug = $args->{old_bug};
+
+ my $user = Bugzilla->user;
+ my $cgi = Bugzilla->cgi;
+ my $params = Bugzilla->input_params;
+
+ if ($params->{needinfo}) {
+ # do a match if applicable
+ Bugzilla::User::match_field({
+ 'needinfo_from' => { 'type' => 'multi' }
+ });
+ }
+
+ # Set needinfo_done param to true so as to not loop back here
+ return if $params->{needinfo_done};
+ $params->{needinfo_done} = 1;
+ Bugzilla->input_params($params);
+
+ my $add_needinfo = delete $params->{needinfo};
+ my $needinfo_from = delete $params->{needinfo_from};
+ my $needinfo_role = delete $params->{needinfo_role};
+ my $is_private = $params->{'comment_is_private'};
+
+ my @needinfo_overrides;
+ foreach my $key (grep(/^needinfo_override_/, keys %$params)) {
+ my ($id) = $key =~ /(\d+)$/;
+ # Should always be true if key exists (checkbox) but better to be sure
+ push(@needinfo_overrides, $id) if $id && $params->{$key};
+ }
+
+ # Set the needinfo flag if user is requesting more information
+ my @new_flags;
+ my $needinfo_requestee;
+
+ if ($add_needinfo) {
+ foreach my $type (@{ $bug->flag_types }) {
+ next if $type->name ne 'needinfo';
+ my %requestees;
+
+ # Allow anyone to be the requestee
+ if (!$needinfo_role) {
+ $requestees{'anyone'} = 1;
+ }
+ # Use assigned_to as requestee
+ elsif ($needinfo_role eq 'assigned_to') {
+ $requestees{$bug->assigned_to->login} = 1;
+ }
+ # Use reporter as requestee
+ elsif ($needinfo_role eq 'reporter') {
+ $requestees{$bug->reporter->login} = 1;
+ }
+ # Use qa_contact as requestee
+ elsif ($needinfo_role eq 'qa_contact') {
+ $requestees{$bug->qa_contact->login} = 1;
+ }
+ # Use current user as requestee
+ elsif ($needinfo_role eq 'user') {
+ $requestees{$user->login} = 1;
+ }
+ # Use user specified requestee
+ elsif ($needinfo_role eq 'other' && $needinfo_from) {
+ my @needinfo_from_list = ref $needinfo_from
+ ? @$needinfo_from :
+ ($needinfo_from);
+ foreach my $requestee (@needinfo_from_list) {
+ my $requestee_obj = Bugzilla::User->check($requestee);
+ $requestees{$requestee_obj->login} = 1;
+ }
+ }
+
+ # Find out if the requestee has already been used and skip if so
+ my $requestee_found;
+ foreach my $flag (@{ $type->{flags} }) {
+ if (!$flag->requestee && $requestees{'anyone'}) {
+ delete $requestees{'anyone'};
+ }
+ if ($flag->requestee && $requestees{$flag->requestee->login}) {
+ delete $requestees{$flag->requestee->login};
+ }
+ }
+
+ foreach my $requestee (keys %requestees) {
+ my $needinfo_flag = { type_id => $type->id, status => '?' };
+ if ($requestee ne 'anyone') {
+ $needinfo_flag->{requestee} = $requestee;
+ }
+ push(@new_flags, $needinfo_flag);
+ }
+ }
+ }
+
+ my @flags;
+ foreach my $flag (@{ $bug->flags }) {
+ next if $flag->type->name ne 'needinfo';
+ # Clear if somehow the flag has been set to +/-
+ # or if the "clear needinfo" override checkbox is selected
+ if ($flag->status ne '?'
+ or grep { $_ == $flag->id } @needinfo_overrides)
+ {
+ push(@flags, { id => $flag->id, status => 'X' });
+ }
+ }
+
+ if (@flags || @new_flags) {
+ $bug->set_flags(\@flags, \@new_flags);
+ }
+}
+
+sub object_before_delete {
+ my ($self, $args) = @_;
+ my $object = $args->{object};
+ return unless $object->isa('Bugzilla::Flag')
+ && $object->type->name eq 'needinfo';
+ my $user = Bugzilla->user;
+
+ # Require canconfirm to clear requests targetted at someone else
+ if ($object->setter_id != $user->id
+ && $object->requestee
+ && $object->requestee->id != $user->id
+ && !$user->in_group('canconfirm'))
+ {
+ ThrowUserError('needinfo_illegal_change');
+ }
+}
+
+__PACKAGE__->NAME;
diff --git a/extensions/Needinfo/template/en/default/bug/needinfo.html.tmpl b/extensions/Needinfo/template/en/default/bug/needinfo.html.tmpl
new file mode 100644
index 000000000..de1191520
--- /dev/null
+++ b/extensions/Needinfo/template/en/default/bug/needinfo.html.tmpl
@@ -0,0 +1,158 @@
+[%# 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.
+ #%]
+
+[% 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 %]
+
+[% IF needinfo_flagtype %]
+ <div id="needinfo_container">
+ [% IF needinfo_flags.size > 0 %]
+ [%# Displays NEEDINFO tag in bug header %]
+ <script>
+ var summary_container = document.getElementById('static_bug_status');
+ summary_container.appendChild(document.createTextNode('[NEEDINFO]'));
+ </script>
+ [% END %]
+ <table>
+ [% FOREACH flag = needinfo_flags %]
+ <tr>
+ [% IF !flag.requestee || flag.requestee.id == user.id %]
+ [%# needinfo targetted at the current user, or anyone %]
+ <td align="center">
+ <input type="checkbox" id="needinfo_override_[% flag.id FILTER html %]"
+ name="needinfo_override_[% flag.id FILTER html %]" value="1"
+ [% " checked" IF flag.requestee || user.in_group("canconfirm") %]>
+ </td>
+ <td>
+ <label for="needinfo_override_[% flag.id FILTER html %]">
+ Clear the needinfo request for
+ <em>[% IF !flag.requestee %]anyone[% ELSE %][% flag.requestee.login FILTER html %][% END %]</em>.
+ </label>
+ </td>
+ [% ELSIF user.in_group("canconfirm") || flag.setter_id == user.id %]
+ [%# needinfo targetted at someone else, but the user can clear %]
+ <td align="center">
+ <input type="checkbox" id="needinfo_override_[% flag.id FILTER html %]"
+ name="needinfo_override_[% flag.id FILTER html %]" value="1">
+ </td>
+ <td>
+ <label for="needinfo_override_[% flag.id FILTER html %]">
+ I am providing the requested information for <em>[% flag.requestee.login FILTER html %]</em>
+ (clears the needinfo request).
+ </label>
+ </td>
+ [% ELSE %]
+ [%# current user does not have permissions to clear needinfo %]
+ <td>&nbsp;</td>
+ <td>
+ Needinfo requested from <em>[% flag.requestee.login FILTER html %]</em>.
+ </td>
+ [% END %]
+ </tr>
+ [% END %]
+ [% IF needinfo_flags.size == 0 || needinfo_flagtype.is_multiplicable %]
+ <tr>
+ <td align="center">
+ <script>
+ function needinfo_init() {
+ needinfo_visibility();
+ [% FOREACH flag = needinfo_flags %]
+ YAHOO.util.Event.on('requestee-[% flag.id FILTER none %]', 'blur', function(e) {
+ YAHOO.util.Dom.get('needinfo_override_[% flag.id FILTER none %]').checked =
+ e.target.value == '[% flag.requestee.login FILTER js %]';
+ });
+ [% END %]
+ }
+
+ function needinfo_visibility() {
+ var role = YAHOO.util.Dom.get('needinfo_role').value;
+ if (role == 'other') {
+ YAHOO.util.Dom.removeClass('needinfo_from_container', 'bz_default_hidden');
+ YAHOO.util.Dom.get('needinfo_from').disabled = false;
+ YAHOO.util.Dom.get('needinfo_role_identity').innerHTML = '';
+ } else {
+ YAHOO.util.Dom.addClass('needinfo_from_container', 'bz_default_hidden');
+ YAHOO.util.Dom.get('needinfo_from').disabled = true;
+ var identity = '';
+ if (role == 'reporter') {
+ identity = '[% bug.reporter.realname || bug.reporter.login FILTER html FILTER js %]';
+ } else if (role == 'assigned_to') {
+ identity = '[% bug.assigned_to.realname || bug.assigned_to.login FILTER html FILTER js %]';
+ } else if (role == 'qa_contact') {
+ 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 %]';
+ }
+ YAHOO.util.Dom.get('needinfo_role_identity').innerHTML = identity;
+ }
+ }
+
+ function needinfo_focus() {
+ if (YAHOO.util.Dom.get('needinfo').checked
+ && YAHOO.util.Dom.get('needinfo_role').value == 'other')
+ {
+ YAHOO.util.Dom.get('needinfo_from').focus();
+ YAHOO.util.Dom.get('needinfo_from').select();
+ }
+ }
+
+ function needinfo_role_changed() {
+ YAHOO.util.Dom.get('needinfo').checked = true;
+ needinfo_visibility();
+ needinfo_focus();
+ }
+
+ function needinfo_other_changed() {
+ YAHOO.util.Dom.get('needinfo').checked = YAHOO.util.Dom.get('needinfo_from').value != '';
+ }
+
+ YAHOO.util.Event.onDOMReady(needinfo_init);
+ </script>
+ <input type="checkbox" name="needinfo" value="1" id="needinfo" onchange="needinfo_focus()">
+ </td>
+ <td>
+ <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 != "" %]
+ <option value="qa_contact">qa contact</option>
+ [% END %]
+ <option value="user">myself</option>
+ </select>
+ <span id="needinfo_from_container">
+ [% INCLUDE global/userselect.html.tmpl
+ id => "needinfo_from"
+ name => "needinfo_from"
+ value => ""
+ size => 30
+ multiple => 5
+ onchange => "needinfo_other_changed()"
+ field_title => "Enter one or more comma separated users to request more information from"
+ %]
+ </span>
+ <span id="needinfo_role_identity"></span>
+ </td>
+ </tr>
+ [% END %]
+ </table>
+ </div>
+[% END %]
diff --git a/extensions/Needinfo/template/en/default/hook/attachment/create-form_before_submit.html.tmpl b/extensions/Needinfo/template/en/default/hook/attachment/create-form_before_submit.html.tmpl
new file mode 100644
index 000000000..81b6d57ea
--- /dev/null
+++ b/extensions/Needinfo/template/en/default/hook/attachment/create-form_before_submit.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.
+ #%]
+
+<tr>
+ <td>&nbsp;</td>
+ <td>
+ [% PROCESS bug/needinfo.html.tmpl
+ bug => bug
+ %]
+ </td>
+</tr>
diff --git a/extensions/Needinfo/template/en/default/hook/attachment/edit-after_comment_textarea.html.tmpl b/extensions/Needinfo/template/en/default/hook/attachment/edit-after_comment_textarea.html.tmpl
new file mode 100644
index 000000000..cb6ddf30e
--- /dev/null
+++ b/extensions/Needinfo/template/en/default/hook/attachment/edit-after_comment_textarea.html.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.
+ #%]
+
+[% PROCESS bug/needinfo.html.tmpl
+ bug => attachment.bug
+%]
diff --git a/extensions/Needinfo/template/en/default/hook/bug/edit-after_comment_commit_button.html.tmpl b/extensions/Needinfo/template/en/default/hook/bug/edit-after_comment_commit_button.html.tmpl
new file mode 100644
index 000000000..90f0cc584
--- /dev/null
+++ b/extensions/Needinfo/template/en/default/hook/bug/edit-after_comment_commit_button.html.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.
+ #%]
+
+[% PROCESS bug/needinfo.html.tmpl
+ bug = bug
+%]
diff --git a/extensions/Needinfo/template/en/default/hook/global/header-start.html.tmpl b/extensions/Needinfo/template/en/default/hook/global/header-start.html.tmpl
new file mode 100644
index 000000000..7f2095e3d
--- /dev/null
+++ b/extensions/Needinfo/template/en/default/hook/global/header-start.html.tmpl
@@ -0,0 +1,12 @@
+[%# 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.
+ #%]
+
+[% IF template.name == 'attachment/create.html.tmpl'
+ || template.name == 'attachment/edit.html.tmpl' %]
+ [% style_urls.push('extensions/Needinfo/web/styles/needinfo.css') %]
+[% END %]
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
new file mode 100644
index 000000000..f1241bc61
--- /dev/null
+++ b/extensions/Needinfo/template/en/default/hook/global/user-error-errors.html.tmpl
@@ -0,0 +1,13 @@
+[%# 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.
+ #%]
+
+[% IF error == "needinfo_illegal_change" %]
+ [% title = 'Needinfo Illegal Change' %]
+ Only the requestee or a user with the required permissions can clear a
+ needinfo flag.
+[% END %]
diff --git a/extensions/Needinfo/template/en/default/hook/request/email-after_summary.txt.tmpl b/extensions/Needinfo/template/en/default/hook/request/email-after_summary.txt.tmpl
new file mode 100644
index 000000000..6a302b76a
--- /dev/null
+++ b/extensions/Needinfo/template/en/default/hook/request/email-after_summary.txt.tmpl
@@ -0,0 +1,13 @@
+[%# 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.
+ #%]
+
+[% RETURN UNLESS flag && flag.type.name == 'needinfo' && flag.status == '?' %]
+---
+--- This request has set a needinfo flag on the [% terms.bug %].
+--- You can clear it by logging in and replying in a comment.
+---
diff --git a/extensions/Needinfo/web/styles/needinfo.css b/extensions/Needinfo/web/styles/needinfo.css
new file mode 100644
index 000000000..e375ba610
--- /dev/null
+++ b/extensions/Needinfo/web/styles/needinfo.css
@@ -0,0 +1,10 @@
+/* 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. */
+
+#needinfo_container label {
+ font-weight: normal !important;
+}