]> git.ipfire.org Git - thirdparty/bugzilla.git/commitdiff
Bug 162060: Remove the relationship between "votestoconfirm" and whether or not the...
authormkanat%bugzilla.org <>
Thu, 17 Dec 2009 23:31:51 +0000 (23:31 +0000)
committermkanat%bugzilla.org <>
Thu, 17 Dec 2009 23:31:51 +0000 (23:31 +0000)
Patch by Max Kanat-Alexander <mkanat@bugzilla.org> r=LpSolit, a=LpSolit

14 files changed:
Bugzilla/Bug.pm
Bugzilla/DB/Schema.pm
Bugzilla/Install/DB.pm
Bugzilla/Product.pm
attachment.cgi
editproducts.cgi
enter_bug.cgi
importxml.pl
sanitycheck.cgi
template/en/default/admin/products/create.html.tmpl
template/en/default/admin/products/edit-common.html.tmpl
template/en/default/admin/products/edit.html.tmpl
template/en/default/admin/products/updated.html.tmpl
template/en/default/attachment/create.html.tmpl

index ab035fcba6d983df4d059bc0d5d04bc25ea2d602..1eaafb698332a78445ff31d29bf893427a2455d7 100644 (file)
@@ -1122,9 +1122,7 @@ sub _check_bug_status {
     }
     else {
         @valid_statuses = @{Bugzilla::Status->can_change_to()};
-        if (!$product->votes_to_confirm) {
-            # UNCONFIRMED becomes an invalid status if votes_to_confirm is 0,
-            # even if you are in editbugs.
+        if (!$product->allows_unconfirmed) {
             @valid_statuses = grep {$_->name ne 'UNCONFIRMED'} @valid_statuses;
         }
     }
@@ -1157,9 +1155,13 @@ sub _check_bug_status {
             }
         }
     }
+
     # Time to validate the bug status.
     $new_status = Bugzilla::Status->check($new_status) unless ref($new_status);
-    if (!grep {$_->name eq $new_status->name} @valid_statuses) {
+    # We skip this check if we are changing from a status to itself.
+    if ( (!$old_status || $old_status->id != $new_status->id)
+          && !grep {$_->name eq $new_status->name} @valid_statuses) 
+    {
         ThrowUserError('illegal_bug_status_transition',
                        { old => $old_status, new => $new_status });
     }
@@ -2804,7 +2806,7 @@ sub 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) {
+    if (!$self->product_obj->allows_unconfirmed) {
         @statuses = grep { $_->name ne 'UNCONFIRMED' } @statuses;
     }
 
@@ -2816,6 +2818,11 @@ sub statuses_available {
         push(@available, $status);
     }
 
+    # If this bug has an inactive status set, it should still be in the list.
+    if (!grep($_->name eq $self->status->name, @available)) {
+        unshift(@available, $self->status);
+    }
+
     $self->{'statuses_available'} = \@available;
     return $self->{'statuses_available'};
 }
@@ -3367,7 +3374,10 @@ sub CheckIfVotedConfirmed {
     my $bug = new Bugzilla::Bug($id);
 
     my $ret = 0;
-    if (!$bug->everconfirmed && $bug->votes >= $bug->product_obj->votes_to_confirm) {
+    if (!$bug->everconfirmed
+        and $bug->product_obj->votes_to_confirm
+        and $bug->votes >= $bug->product_obj->votes_to_confirm) 
+    {
         $bug->add_comment('', { type => CMT_POPULAR_VOTES });
 
         if ($bug->bug_status eq 'UNCONFIRMED') {
index e4dcfd966516ef4a84b2feb30f72fdcec7c9c21c..a1102dd6441f0963a475ec9014333e2802b7d0cb 100644 (file)
@@ -1224,6 +1224,8 @@ use constant ABSTRACT_SCHEMA => {
                                   DEFAULT => 0},
             defaultmilestone  => {TYPE => 'varchar(20)',
                                   NOTNULL => 1, DEFAULT => "'---'"},
+            allows_unconfirmed => {TYPE => 'BOOLEAN', NOTNULL => 1,
+                                   DEFAULT => 'FALSE'},
         ],
         INDEXES => [
             products_name_idx   => {FIELDS => ['name'],
index 414731fbec960f6109fdb62c40cc7a849ccc672e..adbcb285fcd66f372c5766e174cc7184d01a2033 100644 (file)
@@ -592,6 +592,8 @@ sub update_table_definitions {
 
     $dbh->bz_drop_column('products', 'milestoneurl');
 
+    _add_allows_unconfirmed_to_product_table();
+
     ################################################################
     # New --TABLE-- changes should go *** A B O V E *** this point #
     ################################################################
@@ -3328,6 +3330,16 @@ sub _set_attachment_comment_types {
     _populate_bugs_fulltext($bug_ids);
 }
 
+sub _add_allows_unconfirmed_to_product_table {
+    my $dbh = Bugzilla->dbh;
+    if (!$dbh->bz_column_info('products', 'allows_unconfirmed')) {
+        $dbh->bz_add_column('products', 'allows_unconfirmed',
+            { TYPE => 'BOOLEAN', NOTNULL => 1, DEFAULT => 'FALSE' });
+        $dbh->do('UPDATE products SET allows_unconfirmed = 1 
+                   WHERE votestoconfirm > 0');
+    }
+}
+
 1;
 
 __END__
index 410f1bd20a2eec868772ee6d4609703530fab4f1..0228aca02a07bb27843192ebe2242e59257820cd 100644 (file)
@@ -58,6 +58,7 @@ use constant DB_COLUMNS => qw(
    maxvotesperbug
    votestoconfirm
    defaultmilestone
+   allows_unconfirmed
 );
 
 use constant REQUIRED_CREATE_FIELDS => qw(
@@ -74,9 +75,11 @@ use constant UPDATE_COLUMNS => qw(
     votesperuser
     maxvotesperbug
     votestoconfirm
+    allows_unconfirmed
 );
 
 use constant VALIDATORS => {
+    allows_unconfirmed => \&Bugzilla::Object::check_boolean,
     classification   => \&_check_classification,
     name             => \&_check_name,
     description      => \&_check_description,
@@ -631,6 +634,7 @@ sub set_is_active { $_[0]->set('isactive', $_[1]); }
 sub set_votes_per_user { $_[0]->set('votesperuser', $_[1]); }
 sub set_votes_per_bug { $_[0]->set('maxvotesperbug', $_[1]); }
 sub set_votes_to_confirm { $_[0]->set('votestoconfirm', $_[1]); }
+sub set_allows_unconfirmed { $_[0]->set('allows_unconfirmed', $_[1]); }
 
 sub set_group_controls {
     my ($self, $group, $settings) = @_;
@@ -882,6 +886,7 @@ sub flag_types {
 ####      Accessors      ######
 ###############################
 
+sub allows_unconfirmed { return $_[0]->{'allows_unconfirmed'}; }
 sub description       { return $_[0]->{'description'};       }
 sub is_active         { return $_[0]->{'isactive'};       }
 sub votes_per_user    { return $_[0]->{'votesperuser'};      }
@@ -941,6 +946,7 @@ Bugzilla::Product - Bugzilla product class.
     my votestoconfirm    = $product->votes_to_confirm;
     my $defaultmilestone = $product->default_milestone;
     my $classificationid = $product->classification_id;
+    my $allows_unconfirmed = $product->allows_unconfirmed;
 
 =head1 DESCRIPTION
 
index bc1cb90f7662e8a0a0d6182bb8be3f29716cb6ab..20a96d09d661d5d00737b6654e55cb877dc01052 100755 (executable)
@@ -496,7 +496,8 @@ sub insert {
       ($bug_status) = grep {$_->name eq $bug_status} @{$bug->status->can_change_to};
 
       if ($bug_status && $bug_status->is_open
-          && ($bug_status->name ne 'UNCONFIRMED' || $bug->product_obj->votes_to_confirm))
+          && ($bug_status->name ne 'UNCONFIRMED' 
+              || $bug->product_obj->allows_unconfirmed))
       {
           $bug->set_status($bug_status->name);
           $bug->clear_resolution();
index a328ca678983d27fb819dc13141d9ac128451f20..8433ed16bac9c38aa41314c67b1b016f55ff0f4e 100755 (executable)
@@ -176,17 +176,22 @@ if ($action eq 'new') {
 
     check_token_data($token, 'add_product');
 
-    my $product =
-      Bugzilla::Product->create({classification   => $classification_name,
-                                 name             => $product_name,
-                                 description      => scalar $cgi->param('description'),
-                                 version          => scalar $cgi->param('version'),
-                                 defaultmilestone => scalar $cgi->param('defaultmilestone'),
-                                 isactive         => scalar $cgi->param('is_active'),
-                                 votesperuser     => scalar $cgi->param('votesperuser'),
-                                 maxvotesperbug   => scalar $cgi->param('maxvotesperbug'),
-                                 votestoconfirm   => scalar $cgi->param('votestoconfirm'),
-                                 create_series    => scalar $cgi->param('createseries')});
+    my %create_params = (
+        classification   => $classification_name,
+        name             => $product_name,
+        description      => scalar $cgi->param('description'),
+        version          => scalar $cgi->param('version'),
+        defaultmilestone => scalar $cgi->param('defaultmilestone'),
+        isactive         => scalar $cgi->param('is_active'),
+        create_series    => scalar $cgi->param('createseries'),
+        allows_unconfirmed => scalar $cgi->param('allows_unconfirmed'),
+    );
+    if (Bugzilla->params->{'usevotes'}) {
+        $create_params{votesperuser}   = $cgi->param('votesperuser');
+        $create_params{maxvotesperbug} = $cgi->param('maxvotesperbug');
+        $create_params{votestoconfirm} = $cgi->param('votestoconfirm');
+    }
+    my $product = Bugzilla::Product->create(\%create_params);
 
     delete_token($token);
 
@@ -294,9 +299,12 @@ if ($action eq 'update') {
     $product->set_description(scalar $cgi->param('description'));
     $product->set_default_milestone(scalar $cgi->param('defaultmilestone'));
     $product->set_is_active(scalar $cgi->param('is_active'));
-    $product->set_votes_per_user(scalar $cgi->param('votesperuser'));
-    $product->set_votes_per_bug(scalar $cgi->param('maxvotesperbug'));
-    $product->set_votes_to_confirm(scalar $cgi->param('votestoconfirm'));
+    if (Bugzilla->params->{'usevotes'}) {
+        $product->set_votes_per_user(scalar $cgi->param('votesperuser'));
+        $product->set_votes_per_bug(scalar $cgi->param('maxvotesperbug'));
+        $product->set_votes_to_confirm(scalar $cgi->param('votestoconfirm'));
+    }
+    $product->set_allows_unconfirmed(scalar $cgi->param('allows_unconfirmed'));
 
     my $changes = $product->update();
 
index 7c88f8d476f9d2f6dbe8114098c6514c4353b06d..31e106959f5b0f0142018cabac5d3b93906fb646 100755 (executable)
@@ -520,8 +520,10 @@ my $initial_statuses = Bugzilla::Status->can_change_to();
 @$initial_statuses = grep { $_->is_open } @$initial_statuses;
 
 my @status = map { $_->name } @$initial_statuses;
-# UNCONFIRMED is illegal if votes_to_confirm = 0.
-@status = grep {$_ ne 'UNCONFIRMED'} @status unless $product->votes_to_confirm;
+# UNCONFIRMED is illegal if allows_unconfirmed is false.
+if (!$product->allows_unconfirmed) {
+    @status = grep {$_ ne 'UNCONFIRMED'} @status;
+}
 scalar(@status) || ThrowUserError('no_initial_bug_status');
 
 # If the user has no privs...
index 05f95d646235c34a74678c3b79bb814f0de3d7d9..1a61c5eadee30a512aa85e2b9828ea91e9d39d45 100755 (executable)
@@ -913,7 +913,7 @@ sub process_bug {
     
     # Check everconfirmed 
     my $everconfirmed;
-    if ($product->votes_to_confirm) {
+    if ($product->allows_unconfirmed) {
         $everconfirmed = $bug_fields{'everconfirmed'} || 0;
     }
     else {
index 6142737696707b1cb3b2528b4cd49ea8e02a62bf..036286454836380ecf33e5a6c2292e5839d2c9b6 100755 (executable)
@@ -976,7 +976,8 @@ BugCheck("bugs WHERE bug_status IN ($confirmed_open_states) AND everconfirmed =
 Status('bug_check_votes_everconfirmed');
 
 BugCheck("bugs INNER JOIN products ON bugs.product_id = products.id " .
-         "WHERE everconfirmed = 0 AND votestoconfirm <= votes",
+         "WHERE everconfirmed = 0 AND votestoconfirm > 0
+                AND votestoconfirm <= votes",
          'bug_check_votes_everconfirmed_error_text');
 
 ###########################################################################
index 664564040c520c251425a02e097383621dcf7757..f4a2161aad91e0d2133ea2cc847001fc0aab8ea4 100644 (file)
 [% PROCESS global/header.html.tmpl
   title = title
   style_urls = ['skins/standard/admin.css']
+  javascript_urls = ['js/util.js']
 %]
 
 [% DEFAULT
   product.votesperuser = "0",
   product.maxvotesperbug  = "10000",
-  product.votestoconfirm = "0",
+  product.votes_to_confirm = "0",
   product.is_active = 1,
   version = "unspecified",
   product.defaultmilestone = constants.DEFAULT_MILESTONE
+  product.allows_unconfirmed = 0
 %]
 
 <form method="post" action="editproducts.cgi">
index 67dd5ae6434f6fae6a60db3903adec136278bc4a..2c94402d665bcf4fe17f1b1ae458829825269f3f 100644 (file)
        [% ' checked="checked"' IF product.is_active %]>
   </td>
 </tr>
-
-[% IF !Param('usevotes') %]
-<tr class="param_disabled">
-  <td colspan="2"
-      style="font-family: arial; font-style: italic; font-size: 0.7em; text-align: center;">
-    The 'usevotes' parameter is currently 'off'. These voting
-    settings will take effect when the parameter is next enabled.</td>
-</tr>
-[% END %]
-<tr [% IF !Param('usevotes') %]class="param_disabled" [% END %]>
-  <th align="right">Maximum votes per person:</th>
-  <td><input size="5" maxlength="5" name="votesperuser" 
-             value="[% product.votesperuser FILTER html %]">
-  </td>
-</tr>
-<tr [% IF !Param('usevotes') %]class="param_disabled" [% END %]>
-  <th align="right">
-    Maximum votes a person can put on a single [% terms.bug %]:
-  </th>
-  <td><input size="5" maxlength="5" name="maxvotesperbug" 
-             value="[% product.maxvotesperbug FILTER html %]">
-  </td>
-</tr>
-<tr [% IF !Param('usevotes') %]class="param_disabled" [% END %]>
+<tr>
   <th align="right">
-    Confirmation threshold:
+    <label for="allows_unconfirmed">Enable the
+      [%+ display_value('bug_status', 'UNCONFIRMED') FILTER html %] status
+      in this product:</label>
   </th>
-  <td>
-    Enter the number of votes [% terms.abug %] in this product needs to
-    automatically get out of the
-    <a href="page.cgi?id=fields.html#status">[% display_value("bug_status", "UNCONFIRMED") FILTER html %]</a>
-    state.<br>
-    <input size="5" maxlength="5" name="votestoconfirm" 
-           value="[% product.votestoconfirm FILTER html %]">
+  <td><input type="checkbox" id="allows_unconfirmed" name="allows_unconfirmed"
+             [% ' checked="checked"' IF product.allows_unconfirmed %]
+             [% IF Param('usevotes') %]
+               onchange="bz_toggleClass('votes_to_confirm_container', 
+                                        'bz_default_hidden')"
+             [% END %]>
+    [% IF Param('usevotes') %]
+      <span id="votes_to_confirm_container"
+            [% ' class="bz_default_hidden"' IF !product.allows_unconfirmed %]>
+        ...and automatically confirm [% terms.bugs %] if they get
+        <input size="3" maxlength="5" name="votestoconfirm" id="votestoconfirm"
+               value="[% product.votes_to_confirm FILTER html %]">
+         votes. (Setting this to 0 disables auto-confirming [% terms.bugs %]
+         by vote.)
+      </span>
+    [% END %]
   </td>
 </tr>
+
+[% IF Param('usevotes') %]
+  <tr>
+    <th align="right">Maximum votes per person:</th>
+    <td><input size="5" maxlength="5" name="votesperuser" id="votesperuser"
+               value="[% product.votesperuser FILTER html %]">
+    </td>
+  </tr>
+  <tr>
+    <th align="right">
+      Maximum votes a person can put on a single [% terms.bug %]:
+    </th>
+    <td><input size="5" maxlength="5" name="maxvotesperbug" id="maxvotesperbug"
+               value="[% product.maxvotesperbug FILTER html %]">
+    </td>
+  </tr>
+[% END %]
index e6480c45307073644357e69d8c9e3985875bbca8..976739f78491c1db5fbbc0c2ac3aa5f82e03a9a7 100644 (file)
@@ -29,6 +29,7 @@
 [% PROCESS global/header.html.tmpl
   title = title
   style_urls = ['skins/standard/admin.css']
+  javascript_urls = ['js/util.js']
 %]
 
 [% group_control = {${constants.CONTROLMAPNA}        => 'NA',
index 594f84327a9ab7221af309bafd00ffd57357d0cd..6e484ff3418639966fc5642a97b16634f210ab4a 100644 (file)
@@ -39,6 +39,8 @@
   style_urls = ['skins/standard/admin.css']
 %]
 
+[% PROCESS "global/field-descs.none.tmpl" %]
+
 [% IF changes.name.defined %]
   <p>
   Updated product name from '[% changes.name.0 FILTER html %]' to
   [% checkvotes = 1 %]
 [% END %]
 
+[% IF changes.allows_unconfirmed.defined %]
+  <p>
+  [% IF product.allows_unconfirmed %]
+    The product now allows the 
+    [%+ display_value('bug_status', 'UNCONFIRMED') FILTER html %] status.
+  [% ELSE %]
+    The product no longer allows the 
+    [%+ display_value('bug_status', 'UNCONFIRMED') FILTER html %] status.
+    Note that any 
+    <a href="buglist.cgi?product=
+            [%- product.name FILTER url_quote %]&amp;bug_status=UNCONFIRMED"> 
+    [%- terms.bugs %] that currently have the 
+    [%+ display_value('bug_status', 'UNCONFIRMED') FILTER html %] status</a>
+    will remain in that status until they are edited.
+  [% END %]
+  </p>
+[% END %]
+
 [% IF !changes.keys.size %]
   <p>Nothing changed for product '[% product.name FILTER html %]'.</p>
 [% END %]
index 9150b2b32ca7bd33efa06b86b7c764cef71076ee..f00a0ade42c48873af72c25ba103057171564589 100644 (file)
@@ -77,7 +77,8 @@
           <label for="takebug">take [% terms.bug %]</label>
           [% bug_statuses = [] %]
           [% FOREACH bug_status = bug.status.can_change_to %]
-            [% NEXT IF bug_status.name == "UNCONFIRMED" && !bug.product_obj.votes_to_confirm %]
+            [% NEXT IF bug_status.name == "UNCONFIRMED" 
+                       && !bug.product_obj.allows_unconfirmed %]
             [% bug_statuses.push(bug_status) IF bug_status.is_open %]
           [% END %]
           [% IF bug_statuses.size %]