diff options
Diffstat (limited to 'extensions/FlagDefaultRequestee')
11 files changed, 405 insertions, 0 deletions
diff --git a/extensions/FlagDefaultRequestee/Config.pm b/extensions/FlagDefaultRequestee/Config.pm new file mode 100644 index 000000000..70c5ca33a --- /dev/null +++ b/extensions/FlagDefaultRequestee/Config.pm @@ -0,0 +1,17 @@ +# 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::FlagDefaultRequestee; + +use strict; + +use constant NAME => 'FlagDefaultRequestee'; + +use constant REQUIRED_MODULES => []; +use constant OPTIONAL_MODULES => []; + +__PACKAGE__->NAME; diff --git a/extensions/FlagDefaultRequestee/Extension.pm b/extensions/FlagDefaultRequestee/Extension.pm new file mode 100644 index 000000000..958a1bb85 --- /dev/null +++ b/extensions/FlagDefaultRequestee/Extension.pm @@ -0,0 +1,173 @@ +# 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::FlagDefaultRequestee; + +use strict; +use base qw(Bugzilla::Extension); + +use Bugzilla::Error; +use Bugzilla::FlagType; +use Bugzilla::User; +use Bugzilla::Util 'trim'; + +use Bugzilla::Extension::FlagDefaultRequestee::Constants; + +our $VERSION = '1'; + +################ +# Installation # +################ + +sub install_update_db { + my $dbh = Bugzilla->dbh; + $dbh->bz_add_column('flagtypes', 'default_requestee', { + TYPE => 'INT3', + NOTNULL => 0, + REFERENCES => { TABLE => 'profiles', + COLUMN => 'userid', + DELETE => 'SET NULL' } + }); +} + +############# +# Templates # +############# + +sub template_before_process { + my ($self, $args) = @_; + return unless Bugzilla->user->id; + my ($vars, $file) = @$args{qw(vars file)}; + return unless grep { $_ eq $file } FLAGTYPE_TEMPLATES; + + my $flag_types = []; + if (exists $vars->{bug} || exists $vars->{attachment}) { + my $bug; + if (exists $vars->{bug}) { + $bug = $vars->{'bug'}; + } elsif (exists $vars->{'attachment'}) { + $bug = $vars->{'attachment'}->{bug}; + } + + $flag_types = Bugzilla::FlagType::match({ + 'target_type' => ($file =~ /^bug/ ? 'bug' : 'attachment'), + 'product_id' => $bug->product_id, + 'component_id' => $bug->component_id, + 'bug_id' => $bug->id, + 'active_or_has_flags' => $bug->id, + }); + + $vars->{flag_currently_requested} ||= {}; + foreach my $type (@$flag_types) { + my $flags = Bugzilla::Flag->match({ + type_id => $type->id, + bug_id => $bug->id, + status => '?' + }); + map { $vars->{flag_currently_requested}->{$_->id} = 1 } @$flags; + } + } + elsif ($file =~ /^bug\/create/ && exists $vars->{product}) { + my $bug_flags = $vars->{product}->flag_types->{bug}; + my $attachment_flags = $vars->{product}->flag_types->{attachment}; + $flag_types = [ map { $_ } (@$bug_flags, @$attachment_flags) ]; + } + + return if !@$flag_types; + + $vars->{flag_default_requestees} ||= {}; + foreach my $type (@$flag_types) { + next if !$type->default_requestee; + $vars->{flag_default_requestees}->{$type->id} = $type->default_requestee->login; + } +} + +################## +# Object Methods # +################## + +BEGIN { + *Bugzilla::FlagType::default_requestee = \&_default_requestee; +} + +sub object_columns { + my ($self, $args) = @_; + my ($class, $columns) = @$args{qw(class columns)}; + if ($class->isa('Bugzilla::FlagType')) { + push(@$columns, 'default_requestee'); + } +} + +sub object_update_columns { + my ($self, $args) = @_; + my $object = $args->{object}; + return unless $object->isa('Bugzilla::FlagType'); + + my $columns = $args->{columns}; + push(@$columns, 'default_requestee'); + + # editflagtypes.cgi doesn't call set_all, so we have to do this here + my $input = Bugzilla->input_params; + $object->set('default_requestee', $input->{default_requestee}) + if exists $input->{default_requestee}; +} + +sub object_validators { + my ($self, $args) = @_; + my $class = $args->{class}; + return unless $class->isa('Bugzilla::FlagType'); + + my $validators = $args->{validators}; + $validators->{default_requestee} = \&_check_default_requestee; +} + +sub object_before_create { + my ($self, $args) = @_; + my $class = $args->{class}; + return unless $class->isa('Bugzilla::FlagType'); + + my $params = $args->{params}; + my $input = Bugzilla->input_params; + $params->{default_requestee} = $input->{default_requestee} + if exists $params->{default_requestee}; +} + +sub object_end_of_update { + my ($self, $args) = @_; + my $object = $args->{object}; + return unless $object->isa('Bugzilla::FlagType'); + + my $old_object = $args->{old_object}; + my $changes = $args->{changes}; + my $old_id = $old_object->default_requestee + ? $old_object->default_requestee->id + : 0; + my $new_id = $object->default_requestee + ? $object->default_requestee->id + : 0; + return if $old_id == $new_id; + + $changes->{default_requestee} = [ $old_id, $new_id ]; +} + +sub _check_default_requestee { + my ($self, $value, $field) = @_; + $value = trim($value // ''); + return undef if $value eq ''; + ThrowUserError("flag_default_requestee_review") + if $self->name eq 'review'; + return Bugzilla::User->check($value)->id; +} + +sub _default_requestee { + my ($self) = @_; + return $self->{default_requestee} + ? Bugzilla::User->new({ id => $self->{default_requestee}, cache => 1 }) + : undef; +} + +__PACKAGE__->NAME; diff --git a/extensions/FlagDefaultRequestee/lib/Constants.pm b/extensions/FlagDefaultRequestee/lib/Constants.pm new file mode 100644 index 000000000..467028423 --- /dev/null +++ b/extensions/FlagDefaultRequestee/lib/Constants.pm @@ -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. + +package Bugzilla::Extension::FlagDefaultRequestee::Constants; + +use strict; + +use base qw(Exporter); + +our @EXPORT = qw( + FLAGTYPE_TEMPLATES +); + +use constant FLAGTYPE_TEMPLATES => ( + "attachment/edit.html.tmpl", + "attachment/createformcontents.html.tmpl", + "bug/edit.html.tmpl", + "bug/create/create.html.tmpl" +); + +1; diff --git a/extensions/FlagDefaultRequestee/template/en/default/flag/default_requestees.html.tmpl b/extensions/FlagDefaultRequestee/template/en/default/flag/default_requestees.html.tmpl new file mode 100644 index 000000000..db728c168 --- /dev/null +++ b/extensions/FlagDefaultRequestee/template/en/default/flag/default_requestees.html.tmpl @@ -0,0 +1,105 @@ +[%# 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 flag_default_requestees.keys.size %] + <script type="text/javascript"> + var currently_requested = new Array(); + var default_requestees = new Array(); + [% FOREACH id = flag_currently_requested.keys %] + currently_requested.push('[% id FILTER js %]'); + [% END %] + [% FOREACH id = flag_default_requestees.keys %] + default_requestees['id_[% id FILTER js %]'] = '[% flag_default_requestees.$id FILTER js %]'; + [% END %] + + function fdrSetDefaultRequestee(field, default_requestee) { + field.value = default_requestee; + field.focus(); + field.select(); + } + + function fdrOnChange(ev) { + var parts = ev.target.id.split('-'); + var flag = parts[0]; + var id = parts[1]; + var state = ev.target.value; + var requestee_field; + + if (flag.search(/_type/) == -1) { + for (var i = 0; i < currently_requested.length; i++) { + if (id == currently_requested[i]) { + return; + } + } + requestee_field = YAHOO.util.Dom.get('requestee-' + id); + parts = ev.target.className.split('-'); + id = parts[1]; + } + else { + requestee_field = YAHOO.util.Dom.get('requestee_type-' + id); + } + if (!requestee_field) return; + + var current_requestee = requestee_field.value; + var default_requestee = default_requestees['id_' + id]; + if (!default_requestee) return; + + if (state == '?' && !current_requestee && default_requestee) { + fdrSetDefaultRequestee(requestee_field, default_requestees['id_' + id]); + } + else if (state == '?' && current_requestee != default_requestee) { + fdrShowDefaultLink(requestee_field, id); + } + } + + YAHOO.util.Event.onDOMReady(function() { + var selects = YAHOO.util.Dom.getElementsByClassName('flag_select'); + for (var i = 0; i < selects.length; i++) { + YAHOO.util.Event.on(selects[i], 'change', fdrOnChange); + } + + for (var i = 0; i < currently_requested.length; i++) { + var flag_id = currently_requested[i]; + var flag_field = YAHOO.util.Dom.get('flag-' + flag_id); + var requestee_field = YAHOO.util.Dom.get('requestee-' + flag_id); + if (!requestee_field) continue; + var parts = flag_field.className.split('-'); + var type_id = parts[1]; + var current_requestee = requestee_field.value; + var default_requestee = default_requestees['id_' + type_id]; + if (!default_requestee) continue; + if (current_requestee != default_requestee) { + fdrShowDefaultLink(requestee_field, type_id, flag_id); + } + } + }); + + function fdrHideDefaultLink (flag_id) { + YAHOO.util.Dom.addClass('default_requestee_' + flag_id, 'bz_default_hidden'); + } + + function fdrShowDefaultLink (requestee_field, type_id, flag_id) { + var default_requestee = default_requestees['id_' + type_id]; + + var default_link = document.createElement('a'); + YAHOO.util.Dom.setAttribute(default_link, 'href', 'javascript:void(0)'); + default_link.appendChild(document.createTextNode('default requestee')); + YAHOO.util.Event.addListener(default_link, 'click', function() { + fdrSetDefaultRequestee(requestee_field, default_requestee); + fdrHideDefaultLink(flag_id); + }); + + var default_span = document.createElement('span'); + YAHOO.util.Dom.setAttribute(default_span, 'id', 'default_requestee_' + flag_id); + default_span.appendChild(document.createTextNode("\u00a0(")); + default_span.appendChild(default_link); + default_span.appendChild(document.createTextNode(')')); + requestee_field.parentNode.parentNode.appendChild(default_span); + } + </script> +[% END %] diff --git a/extensions/FlagDefaultRequestee/template/en/default/hook/admin/flag-type/edit-rows.html.tmpl b/extensions/FlagDefaultRequestee/template/en/default/hook/admin/flag-type/edit-rows.html.tmpl new file mode 100644 index 000000000..edefca370 --- /dev/null +++ b/extensions/FlagDefaultRequestee/template/en/default/hook/admin/flag-type/edit-rows.html.tmpl @@ -0,0 +1,21 @@ +[%# 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> + <th>Default Requestee:</th> + <td> + If flag is specifically requestable, this user will be entered in the + requestee field by default unless the user changes it.<br> + [% INCLUDE global/userselect.html.tmpl + name => 'default_requestee' + id => 'default_requestee' + value => type.default_requestee.login + classes => ['requestee'] + %] + </td> +</tr> diff --git a/extensions/FlagDefaultRequestee/template/en/default/hook/attachment/create-end.html.tmpl b/extensions/FlagDefaultRequestee/template/en/default/hook/attachment/create-end.html.tmpl new file mode 100644 index 000000000..20b2526d0 --- /dev/null +++ b/extensions/FlagDefaultRequestee/template/en/default/hook/attachment/create-end.html.tmpl @@ -0,0 +1,9 @@ +[%# 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 flag/default_requestees.html.tmpl %] diff --git a/extensions/FlagDefaultRequestee/template/en/default/hook/attachment/edit-end.html.tmpl b/extensions/FlagDefaultRequestee/template/en/default/hook/attachment/edit-end.html.tmpl new file mode 100644 index 000000000..20b2526d0 --- /dev/null +++ b/extensions/FlagDefaultRequestee/template/en/default/hook/attachment/edit-end.html.tmpl @@ -0,0 +1,9 @@ +[%# 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 flag/default_requestees.html.tmpl %] diff --git a/extensions/FlagDefaultRequestee/template/en/default/hook/bug/create/create-form.html.tmpl b/extensions/FlagDefaultRequestee/template/en/default/hook/bug/create/create-form.html.tmpl new file mode 100644 index 000000000..20b2526d0 --- /dev/null +++ b/extensions/FlagDefaultRequestee/template/en/default/hook/bug/create/create-form.html.tmpl @@ -0,0 +1,9 @@ +[%# 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 flag/default_requestees.html.tmpl %] diff --git a/extensions/FlagDefaultRequestee/template/en/default/hook/bug/edit-after_custom_fields.html.tmpl b/extensions/FlagDefaultRequestee/template/en/default/hook/bug/edit-after_custom_fields.html.tmpl new file mode 100644 index 000000000..20b2526d0 --- /dev/null +++ b/extensions/FlagDefaultRequestee/template/en/default/hook/bug/edit-after_custom_fields.html.tmpl @@ -0,0 +1,9 @@ +[%# 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 flag/default_requestees.html.tmpl %] diff --git a/extensions/FlagDefaultRequestee/template/en/default/hook/global/messages-flag_type_updated_fields.html.tmpl b/extensions/FlagDefaultRequestee/template/en/default/hook/global/messages-flag_type_updated_fields.html.tmpl new file mode 100644 index 000000000..478718d3c --- /dev/null +++ b/extensions/FlagDefaultRequestee/template/en/default/hook/global/messages-flag_type_updated_fields.html.tmpl @@ -0,0 +1,15 @@ +[%# 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 changes.default_requestee.defined %] + [% IF flagtype.default_requestee %] + <li>Default requestee updated to '[% flagtype.default_requestee.login FILTER html %]'</li> + [% ELSE %] + <li>Default requestee deleted</li> + [% END %] +[% END %] diff --git a/extensions/FlagDefaultRequestee/template/en/default/hook/global/user-error-errors.html.tmpl b/extensions/FlagDefaultRequestee/template/en/default/hook/global/user-error-errors.html.tmpl new file mode 100644 index 000000000..3fbd0458c --- /dev/null +++ b/extensions/FlagDefaultRequestee/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 == "flag_default_requestee_review" %] + [% title = "Review flag not supported" %] + You cannot use the 'Default Requestee' field for the review flag. + Instead set the 'Suggested Reviewers' on the Product or Component edit forms. +[% END %] |