Status.pm 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279
  1. # -*- Mode: perl; indent-tabs-mode: nil -*-
  2. #
  3. # The contents of this file are subject to the Mozilla Public
  4. # License Version 1.1 (the "License"); you may not use this file
  5. # except in compliance with the License. You may obtain a copy of
  6. # the License at http://www.mozilla.org/MPL/
  7. #
  8. # Software distributed under the License is distributed on an "AS
  9. # IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
  10. # implied. See the License for the specific language governing
  11. # rights and limitations under the License.
  12. #
  13. # The Original Code is the Bugzilla Bug Tracking System.
  14. #
  15. # The Initial Developer of the Original Code is Frédéric Buclin.
  16. # Portions created by Frédéric Buclin are Copyright (C) 2007
  17. # Frédéric Buclin. All Rights Reserved.
  18. #
  19. # Contributor(s): Frédéric Buclin <LpSolit@gmail.com>
  20. use strict;
  21. package Bugzilla::Status;
  22. use base qw(Bugzilla::Object Exporter);
  23. @Bugzilla::Status::EXPORT = qw(BUG_STATE_OPEN is_open_state closed_bug_statuses);
  24. ################################
  25. ##### Initialization #####
  26. ################################
  27. use constant DB_TABLE => 'bug_status';
  28. use constant DB_COLUMNS => qw(
  29. id
  30. value
  31. sortkey
  32. isactive
  33. is_open
  34. );
  35. use constant NAME_FIELD => 'value';
  36. use constant LIST_ORDER => 'sortkey, value';
  37. ###############################
  38. ##### Accessors ####
  39. ###############################
  40. sub name { return $_[0]->{'value'}; }
  41. sub sortkey { return $_[0]->{'sortkey'}; }
  42. sub is_active { return $_[0]->{'isactive'}; }
  43. sub is_open { return $_[0]->{'is_open'}; }
  44. ###############################
  45. ##### Methods ####
  46. ###############################
  47. sub BUG_STATE_OPEN {
  48. # XXX - We should cache this list.
  49. my $dbh = Bugzilla->dbh;
  50. return @{$dbh->selectcol_arrayref('SELECT value FROM bug_status WHERE is_open = 1')};
  51. }
  52. # Tells you whether or not the argument is a valid "open" state.
  53. sub is_open_state {
  54. my ($state) = @_;
  55. return (grep($_ eq $state, BUG_STATE_OPEN) ? 1 : 0);
  56. }
  57. sub closed_bug_statuses {
  58. my @bug_statuses = Bugzilla::Status->get_all;
  59. @bug_statuses = grep { !$_->is_open } @bug_statuses;
  60. return @bug_statuses;
  61. }
  62. sub can_change_to {
  63. my $self = shift;
  64. my $dbh = Bugzilla->dbh;
  65. if (!ref($self) || !defined $self->{'can_change_to'}) {
  66. my ($cond, @args, $self_exists);
  67. if (ref($self)) {
  68. $cond = '= ?';
  69. push(@args, $self->id);
  70. $self_exists = 1;
  71. }
  72. else {
  73. $cond = 'IS NULL';
  74. # Let's do it so that the code below works in all cases.
  75. $self = {};
  76. }
  77. my $new_status_ids = $dbh->selectcol_arrayref("SELECT new_status
  78. FROM status_workflow
  79. INNER JOIN bug_status
  80. ON id = new_status
  81. WHERE isactive = 1
  82. AND old_status $cond
  83. ORDER BY sortkey",
  84. undef, @args);
  85. # Allow the bug status to remain unchanged.
  86. push(@$new_status_ids, $self->id) if $self_exists;
  87. $self->{'can_change_to'} = Bugzilla::Status->new_from_list($new_status_ids);
  88. }
  89. return $self->{'can_change_to'};
  90. }
  91. sub can_change_from {
  92. my $self = shift;
  93. my $dbh = Bugzilla->dbh;
  94. if (!defined $self->{'can_change_from'}) {
  95. my $old_status_ids = $dbh->selectcol_arrayref('SELECT old_status
  96. FROM status_workflow
  97. INNER JOIN bug_status
  98. ON id = old_status
  99. WHERE isactive = 1
  100. AND new_status = ?
  101. AND old_status IS NOT NULL',
  102. undef, $self->id);
  103. # Allow the bug status to remain unchanged.
  104. push(@$old_status_ids, $self->id);
  105. $self->{'can_change_from'} = Bugzilla::Status->new_from_list($old_status_ids);
  106. }
  107. return $self->{'can_change_from'};
  108. }
  109. sub comment_required_on_change_from {
  110. my ($self, $old_status) = @_;
  111. my ($cond, $values) = $self->_status_condition($old_status);
  112. my ($require_comment) = Bugzilla->dbh->selectrow_array(
  113. "SELECT require_comment FROM status_workflow
  114. WHERE $cond", undef, @$values);
  115. return $require_comment;
  116. }
  117. # Used as a helper for various functions that have to deal with old_status
  118. # sometimes being NULL and sometimes having a value.
  119. sub _status_condition {
  120. my ($self, $old_status) = @_;
  121. my @values;
  122. my $cond = 'old_status IS NULL';
  123. # For newly-filed bugs
  124. if ($old_status) {
  125. $cond = 'old_status = ?';
  126. push(@values, $old_status->id);
  127. }
  128. $cond .= " AND new_status = ?";
  129. push(@values, $self->id);
  130. return ($cond, \@values);
  131. }
  132. sub add_missing_bug_status_transitions {
  133. my $bug_status = shift || Bugzilla->params->{'duplicate_or_move_bug_status'};
  134. my $dbh = Bugzilla->dbh;
  135. my $new_status = new Bugzilla::Status({name => $bug_status});
  136. # Silently discard invalid bug statuses.
  137. $new_status || return;
  138. my $missing_statuses = $dbh->selectcol_arrayref('SELECT id
  139. FROM bug_status
  140. LEFT JOIN status_workflow
  141. ON old_status = id
  142. AND new_status = ?
  143. WHERE old_status IS NULL',
  144. undef, $new_status->id);
  145. my $sth = $dbh->prepare('INSERT INTO status_workflow
  146. (old_status, new_status) VALUES (?, ?)');
  147. foreach my $old_status_id (@$missing_statuses) {
  148. next if ($old_status_id == $new_status->id);
  149. $sth->execute($old_status_id, $new_status->id);
  150. }
  151. }
  152. 1;
  153. __END__
  154. =head1 NAME
  155. Bugzilla::Status - Bug status class.
  156. =head1 SYNOPSIS
  157. use Bugzilla::Status;
  158. my $bug_status = new Bugzilla::Status({name => 'ASSIGNED'});
  159. my $bug_status = new Bugzilla::Status(4);
  160. my @closed_bug_statuses = closed_bug_statuses();
  161. Bugzilla::Status::add_missing_bug_status_transitions($bug_status);
  162. =head1 DESCRIPTION
  163. Status.pm represents a bug status object. It is an implementation
  164. of L<Bugzilla::Object>, and thus provides all methods that
  165. L<Bugzilla::Object> provides.
  166. The methods that are specific to C<Bugzilla::Status> are listed
  167. below.
  168. =head1 METHODS
  169. =over
  170. =item C<closed_bug_statuses>
  171. Description: Returns a list of C<Bugzilla::Status> objects which can have
  172. a resolution associated with them ("closed" bug statuses).
  173. Params: none.
  174. Returns: A list of Bugzilla::Status objects.
  175. =item C<can_change_to>
  176. Description: Returns the list of active statuses a bug can be changed to
  177. given the current bug status. If this method is called as a
  178. class method, then it returns all bug statuses available on
  179. bug creation.
  180. Params: none.
  181. Returns: A list of Bugzilla::Status objects.
  182. =item C<can_change_from>
  183. Description: Returns the list of active statuses a bug can be changed from
  184. given the new bug status. If the bug status is available on
  185. bug creation, this method doesn't return this information.
  186. You have to call C<can_change_to> instead.
  187. Params: none.
  188. Returns: A list of Bugzilla::Status objects.
  189. =item C<comment_required_on_change_from>
  190. =over
  191. =item B<Description>
  192. Checks if a comment is required to change to this status from another
  193. status, according to the current settings in the workflow.
  194. Note that this doesn't implement the checks enforced by the various
  195. C<commenton> parameters--those are checked by internal checks in
  196. L<Bugzilla::Bug>.
  197. =item B<Params>
  198. C<$old_status> - The status you're changing from.
  199. =item B<Returns>
  200. C<1> if a comment is required on this change, C<0> if not.
  201. =back
  202. =item C<add_missing_bug_status_transitions>
  203. Description: Insert all missing transitions to a given bug status.
  204. Params: $bug_status - The value (name) of a bug status.
  205. Returns: nothing.
  206. =back
  207. =cut