Commit e1b433e3 authored by mkanat%bugzilla.org's avatar mkanat%bugzilla.org

Bug 512606: Make statuses currently available for the user to change this bug to…

Bug 512606: Make statuses currently available for the user to change this bug to be controlled by Bugzilla::Bug, not the template Patch by Max Kanat-Alexander <mkanat@bugzilla.org> r=LpSolit, a=LpSolit
parent 391ea119
...@@ -1110,7 +1110,7 @@ sub _check_bug_status { ...@@ -1110,7 +1110,7 @@ sub _check_bug_status {
my $old_status; # Note that this is undef for new bugs. my $old_status; # Note that this is undef for new bugs.
if (ref $invocant) { if (ref $invocant) {
@valid_statuses = @{$invocant->status->can_change_to}; @valid_statuses = @{$invocant->statuses_available};
$product = $invocant->product_obj; $product = $invocant->product_obj;
$old_status = $invocant->status; $old_status = $invocant->status;
my $comments = $invocant->{added_comments} || []; my $comments = $invocant->{added_comments} || [];
...@@ -1118,12 +1118,11 @@ sub _check_bug_status { ...@@ -1118,12 +1118,11 @@ sub _check_bug_status {
} }
else { else {
@valid_statuses = @{Bugzilla::Status->can_change_to()}; @valid_statuses = @{Bugzilla::Status->can_change_to()};
} if (!$product->votes_to_confirm) {
# UNCONFIRMED becomes an invalid status if votes_to_confirm is 0,
if (!$product->votes_to_confirm) { # even if you are in editbugs.
# UNCONFIRMED becomes an invalid status if votes_to_confirm is 0, @valid_statuses = grep {$_->name ne 'UNCONFIRMED'} @valid_statuses;
# even if you are in editbugs. }
@valid_statuses = grep {$_->name ne 'UNCONFIRMED'} @valid_statuses;
} }
# Check permissions for users filing new bugs. # Check permissions for users filing new bugs.
...@@ -2167,6 +2166,8 @@ sub set_status { ...@@ -2167,6 +2166,8 @@ sub set_status {
my $old_status = $self->status; my $old_status = $self->status;
$self->set('bug_status', $status); $self->set('bug_status', $status);
delete $self->{'status'}; delete $self->{'status'};
delete $self->{'statuses_available'};
delete $self->{'choices'};
my $new_status = $self->status; my $new_status = $self->status;
if ($new_status->is_open) { if ($new_status->is_open) {
...@@ -2680,11 +2681,6 @@ sub isopened { ...@@ -2680,11 +2681,6 @@ sub isopened {
return is_open_state($self->{bug_status}) ? 1 : 0; return is_open_state($self->{bug_status}) ? 1 : 0;
} }
sub isunconfirmed {
my $self = shift;
return ($self->bug_status eq 'UNCONFIRMED') ? 1 : 0;
}
sub keywords { sub keywords {
my ($self) = @_; my ($self) = @_;
return join(', ', (map { $_->name } @{$self->keyword_objects})); return join(', ', (map { $_->name } @{$self->keyword_objects}));
...@@ -2805,6 +2801,31 @@ sub status { ...@@ -2805,6 +2801,31 @@ sub status {
return $self->{'status'}; return $self->{'status'};
} }
sub statuses_available {
my $self = shift;
return [] if $self->{'error'};
return $self->{'statuses_available'}
if defined $self->{'statuses_available'};
my @statuses = @{ $self->status->can_change_to };
# UNCONFIRMED is only a valid status if it is enabled in this product.
if (!$self->product_obj->votes_to_confirm) {
@statuses = grep { $_->name ne 'UNCONFIRMED' } @statuses;
}
my @available;
foreach my $status (@statuses) {
# Make sure this is a legal status transition
next if !$self->check_can_change_field(
'bug_status', $self->status->name, $status->name);
push(@available, $status);
}
$self->{'statuses_available'} = \@available;
return $self->{'statuses_available'};
}
sub show_attachment_flags { sub show_attachment_flags {
my ($self) = @_; my ($self) = @_;
return $self->{'show_attachment_flags'} return $self->{'show_attachment_flags'}
...@@ -2958,9 +2979,10 @@ sub choices { ...@@ -2958,9 +2979,10 @@ sub choices {
} }
my %choices = ( my %choices = (
product => \@products, bug_status => $self->statuses_available,
component => $self->product_obj->components, product => \@products,
version => $self->product_obj->versions, component => $self->product_obj->components,
version => $self->product_obj->versions,
target_milestone => $self->product_obj->milestones, target_milestone => $self->product_obj->milestones,
); );
...@@ -3451,12 +3473,7 @@ sub check_can_change_field { ...@@ -3451,12 +3473,7 @@ sub check_can_change_field {
} }
# *Only* users with (product-specific) "canconfirm" privs can confirm bugs. # *Only* users with (product-specific) "canconfirm" privs can confirm bugs.
if ($field eq 'canconfirm' if ($self->_changes_everconfirmed($field, $oldvalue, $newvalue)) {
|| ($field eq 'everconfirmed' && $newvalue)
|| ($field eq 'bug_status'
&& $oldvalue eq 'UNCONFIRMED'
&& is_open_state($newvalue)))
{
$$PrivilegesRequired = 3; $$PrivilegesRequired = 3;
return $user->in_group('canconfirm', $self->{'product_id'}); return $user->in_group('canconfirm', $self->{'product_id'});
} }
...@@ -3532,6 +3549,24 @@ sub check_can_change_field { ...@@ -3532,6 +3549,24 @@ sub check_can_change_field {
return 0; return 0;
} }
# A helper for check_can_change_field
sub _changes_everconfirmed {
my ($self, $field, $old, $new) = @_;
return 1 if $field eq 'everconfirmed';
if ($field eq 'bug_status') {
if ($self->everconfirmed) {
# Moving a confirmed bug to UNCONFIRMED will change everconfirmed.
return 1 if $new eq 'UNCONFIRMED';
}
else {
# Moving an unconfirmed bug to an open state that isn't
# UNCONFIRMED will confirm the bug.
return 1 if (is_open_state($new) and $new ne 'UNCONFIRMED');
}
}
return 0;
}
# #
# Field Validation # Field Validation
# #
...@@ -3626,8 +3661,7 @@ sub _validate_attribute { ...@@ -3626,8 +3661,7 @@ sub _validate_attribute {
my @valid_attributes = ( my @valid_attributes = (
# Miscellaneous properties and methods. # Miscellaneous properties and methods.
qw(error groups product_id component_id qw(error groups product_id component_id
comments milestoneurl attachments comments milestoneurl attachments isopened
isopened isunconfirmed
flag_types num_attachment_flag_types flag_types num_attachment_flag_types
show_attachment_flags any_flags_requesteeble), show_attachment_flags any_flags_requesteeble),
......
...@@ -176,28 +176,6 @@ sub can_change_to { ...@@ -176,28 +176,6 @@ sub can_change_to {
return $self->{'can_change_to'}; return $self->{'can_change_to'};
} }
sub can_change_from {
my $self = shift;
my $dbh = Bugzilla->dbh;
if (!defined $self->{'can_change_from'}) {
my $old_status_ids = $dbh->selectcol_arrayref('SELECT old_status
FROM status_workflow
INNER JOIN bug_status
ON id = old_status
WHERE isactive = 1
AND new_status = ?
AND old_status IS NOT NULL',
undef, $self->id);
# Allow the bug status to remain unchanged.
push(@$old_status_ids, $self->id);
$self->{'can_change_from'} = Bugzilla::Status->new_from_list($old_status_ids);
}
return $self->{'can_change_from'};
}
sub comment_required_on_change_from { sub comment_required_on_change_from {
my ($self, $old_status) = @_; my ($self, $old_status) = @_;
my ($cond, $values) = $self->_status_condition($old_status); my ($cond, $values) = $self->_status_condition($old_status);
...@@ -300,17 +278,6 @@ below. ...@@ -300,17 +278,6 @@ below.
Returns: A list of Bugzilla::Status objects. Returns: A list of Bugzilla::Status objects.
=item C<can_change_from>
Description: Returns the list of active statuses a bug can be changed from
given the new bug status. If the bug status is available on
bug creation, this method doesn't return this information.
You have to call C<can_change_to> instead.
Params: none.
Returns: A list of Bugzilla::Status objects.
=item C<comment_required_on_change_from> =item C<comment_required_on_change_from>
=over =over
......
...@@ -23,71 +23,33 @@ ...@@ -23,71 +23,33 @@
[% PROCESS global/variables.none.tmpl %] [% PROCESS global/variables.none.tmpl %]
<div id="status"> <div id="status">
[% initial_action_shown = 0 %] [% PROCESS bug/field.html.tmpl
[% show_resolution = 0 %] no_tds = 1
[% bug_status_select_displayed = 0 %] field = bug_fields.bug_status
value = bug.bug_status
override_legal_values = bug.choices.bug_status
editable = bug.choices.bug_status.size > 1
%]
[% closed_status_array = [] %] [% IF bug.resolution
[%# These actions are based on the current custom workflow. %] OR bug.check_can_change_field('resolution', bug.resolution, 1)
[% FOREACH bug_status = bug.status.can_change_to %] %]
[% NEXT IF bug.isunconfirmed && bug_status.is_open && !bug.user.canconfirm %] <noscript><br>resolved&nbsp;as&nbsp;</noscript>
[% NEXT IF bug.isopened && !bug.isunconfirmed && bug_status.is_open && !bug.user.canedit %]
[% NEXT IF (!bug_status.is_open || !bug.isopened) && !bug.user.canedit && !bug.user.isreporter %]
[%# Special hack to only display UNCO or REOP when reopening, but not both;
# for compatibility with older versions. %]
[% NEXT IF !bug.isopened && (bug.everconfirmed && bug_status.name == "UNCONFIRMED"
|| !bug.everconfirmed && bug_status.name == "REOPENED") %]
[% IF NOT bug_status_select_displayed %]
<select name="bug_status" id="bug_status">
[% bug_status_select_displayed = 1 %]
[% END %]
[% PROCESS initial_action %]
[% NEXT IF bug_status.name == bug.bug_status %]
<option value="[% bug_status.name FILTER html %]">
[% display_value("bug_status", bug_status.name) FILTER html %]
</option>
[% IF !bug_status.is_open %]
[% show_resolution = 1 %]
[% filtered_status = bug_status.name FILTER js %]
[% closed_status_array.push( filtered_status ) %]
[% END %]
[% END %] [% END %]
[%# These actions are special and are independent of the workflow. %] <span id="resolution_settings">
[% IF bug.user.canedit || bug.user.isreporter %] [% PROCESS bug/field.html.tmpl
[% IF NOT bug_status_select_displayed %] no_tds = 1
<select name="bug_status" id="bug_status"> field = bug_fields.resolution
[% bug_status_select_displayed = 1 %] value = bug.resolution
[% END %] override_legal_values = bug.choices.resolution
[% IF bug.isopened %] editable = bug.check_can_change_field('resolution', bug.resolution, 1)
[% IF bug.resolution %] %]
[% PROCESS initial_action %] </span>
[% END %]
[% ELSIF bug.resolution != "MOVED" || bug.user.canmove %] [% IF bug.check_can_change_field('dup_id', 0, 1) %]
[% PROCESS initial_action %]
[% show_resolution = 1 %]
[% END %]
[% END %]
[% IF bug_status_select_displayed %]
</select>
[% ELSE %]
[% display_value("bug_status", bug.bug_status) FILTER html %]
[% IF bug.resolution %]
[%+ display_value("resolution", bug.resolution) FILTER html %]
[% IF bug.dup_id %]
<span id="duplicate_display">of
[% "${terms.bug} ${bug.dup_id}" FILTER bug_link(bug.dup_id) FILTER none %]</span>
[% END %]
[% END %]
[% END %]
[% IF bug.user.canedit || bug.user.isreporter %]
[% IF show_resolution %]
<noscript><br>resolved&nbsp;as&nbsp;</noscript>
<span id="resolution_settings">[% PROCESS select_resolution %]</span>
[% END %]
<noscript><br> duplicate</noscript> <noscript><br> duplicate</noscript>
<span id="duplicate_settings">of
<span id="duplicate_settings">of
<span id="dup_id_container" class="bz_default_hidden"> <span id="dup_id_container" class="bz_default_hidden">
[% "${terms.bug} ${bug.dup_id}" FILTER bug_link(bug.dup_id) FILTER none %] [% "${terms.bug} ${bug.dup_id}" FILTER bug_link(bug.dup_id) FILTER none %]
(<a href="#" id="dup_id_edit_action">edit</a>) (<a href="#" id="dup_id_edit_action">edit</a>)
...@@ -101,11 +63,20 @@ ...@@ -101,11 +63,20 @@
<div id="dup_id_discoverable" class="bz_default_hidden"> <div id="dup_id_discoverable" class="bz_default_hidden">
<a href="#" id="dup_id_discoverable_action">Mark as Duplicate</a> <a href="#" id="dup_id_discoverable_action">Mark as Duplicate</a>
</div> </div>
[% ELSIF bug.dup_id %]
<noscript><br> duplicate</noscript>
<span id="duplicate_display">of
[% "${terms.bug} ${bug.dup_id}" FILTER bug_link(bug.dup_id) FILTER none %]</span>
[% END %] [% END %]
</div> </div>
<script type="text/javascript"> <script type="text/javascript">
var close_status_array = new Array("[% closed_status_array.join('", "') FILTER replace(',$', '') var close_status_array = [
FILTER none %]"); [% FOREACH status = bug.choices.bug_status %]
[% NEXT IF status.is_open %]
'[% status.name FILTER js %]'[% ',' UNLESS loop.last %]
[% END %]
];
YAHOO.util.Dom.removeClass('dup_id_discoverable', 'bz_default_hidden'); YAHOO.util.Dom.removeClass('dup_id_discoverable', 'bz_default_hidden');
hideEditableField( "dup_id_container", "dup_id", 'dup_id_edit_action', hideEditableField( "dup_id_container", "dup_id", 'dup_id_edit_action',
'dup_id', '[% bug.dup_id FILTER js %]' ) 'dup_id', '[% bug.dup_id FILTER js %]' )
...@@ -127,29 +98,3 @@ ...@@ -127,29 +98,3 @@
[% INCLUDE "bug/field-events.js.tmpl" field = select_fields.bug_status %] [% INCLUDE "bug/field-events.js.tmpl" field = select_fields.bug_status %]
[% INCLUDE "bug/field-events.js.tmpl" field = select_fields.resolution %] [% INCLUDE "bug/field-events.js.tmpl" field = select_fields.resolution %]
</script> </script>
[%# Common actions %]
[% BLOCK initial_action %]
[% IF !initial_action_shown %]
<option selected value="[% bug.bug_status FILTER html %]">
[% display_value("bug_status", bug.bug_status) FILTER html %]
</option>
[% IF !bug.isopened %]
[% show_resolution = 1 %]
[% filtered_status = bug.bug_status FILTER js %]
[% closed_status_array.push(filtered_status) %]
[% END %]
[% initial_action_shown = 1 %]
[% END %]
[% END %]
[% BLOCK select_resolution %]
<select name="resolution" id="resolution">
[% FOREACH r = bug.choices.resolution %]
<option value="[% r.name FILTER html %]"
[% ' selected="selected"' IF r.name == bug.resolution %]>
[% display_value("resolution", r.name) FILTER html %]</option>
[% END %]
</select>
[% END %]
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment