##// END OF EJS Templates
Merged r13640 from 2.6-stable to trunk (#18280)...
Toshi MARUYAMA -
r13259:1ada789a6ccb
parent child
Show More
@@ -1,122 +1,123
1 1 # Redmine - project management software
2 2 # Copyright (C) 2006-2014 Jean-Philippe Lang
3 3 #
4 4 # This program is free software; you can redistribute it and/or
5 5 # modify it under the terms of the GNU General Public License
6 6 # as published by the Free Software Foundation; either version 2
7 7 # of the License, or (at your option) any later version.
8 8 #
9 9 # This program is distributed in the hope that it will be useful,
10 10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 12 # GNU General Public License for more details.
13 13 #
14 14 # You should have received a copy of the GNU General Public License
15 15 # along with this program; if not, write to the Free Software
16 16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 17
18 18 class IssueStatus < ActiveRecord::Base
19 19 before_destroy :check_integrity
20 20 has_many :workflows, :class_name => 'WorkflowTransition', :foreign_key => "old_status_id"
21 21 has_many :workflow_transitions_as_new_status, :class_name => 'WorkflowTransition', :foreign_key => "new_status_id"
22 22 acts_as_list
23 23
24 24 after_update :handle_is_closed_change
25 25 before_destroy :delete_workflow_rules
26 26
27 27 validates_presence_of :name
28 28 validates_uniqueness_of :name
29 29 validates_length_of :name, :maximum => 30
30 30 validates_inclusion_of :default_done_ratio, :in => 0..100, :allow_nil => true
31 31 attr_protected :id
32 32
33 33 scope :sorted, lambda { order(:position) }
34 34 scope :named, lambda {|arg| where("LOWER(#{table_name}.name) = LOWER(?)", arg.to_s.strip)}
35 35
36 36 # Update all the +Issues+ setting their done_ratio to the value of their +IssueStatus+
37 37 def self.update_issue_done_ratios
38 38 if Issue.use_status_for_done_ratio?
39 39 IssueStatus.where("default_done_ratio >= 0").each do |status|
40 40 Issue.where({:status_id => status.id}).update_all({:done_ratio => status.default_done_ratio})
41 41 end
42 42 end
43 43
44 44 return Issue.use_status_for_done_ratio?
45 45 end
46 46
47 47 # Returns an array of all statuses the given role can switch to
48 48 # Uses association cache when called more than one time
49 49 def new_statuses_allowed_to(roles, tracker, author=false, assignee=false)
50 50 if roles && tracker
51 51 role_ids = roles.collect(&:id)
52 52 transitions = workflows.select do |w|
53 53 role_ids.include?(w.role_id) &&
54 54 w.tracker_id == tracker.id &&
55 55 ((!w.author && !w.assignee) || (author && w.author) || (assignee && w.assignee))
56 56 end
57 57 transitions.map(&:new_status).compact.sort
58 58 else
59 59 []
60 60 end
61 61 end
62 62
63 63 # Same thing as above but uses a database query
64 64 # More efficient than the previous method if called just once
65 65 def find_new_statuses_allowed_to(roles, tracker, author=false, assignee=false)
66 66 if roles.present? && tracker
67 67 scope = IssueStatus.
68 68 joins(:workflow_transitions_as_new_status).
69 69 where(:workflows => {:old_status_id => id, :role_id => roles.map(&:id), :tracker_id => tracker.id})
70 70
71 71 unless author && assignee
72 72 if author || assignee
73 73 scope = scope.where("author = ? OR assignee = ?", author, assignee)
74 74 else
75 75 scope = scope.where("author = ? AND assignee = ?", false, false)
76 76 end
77 77 end
78 78
79 79 scope.uniq.to_a.sort
80 80 else
81 81 []
82 82 end
83 83 end
84 84
85 85 def <=>(status)
86 86 position <=> status.position
87 87 end
88 88
89 89 def to_s; name end
90 90
91 91 private
92 92
93 93 # Updates issues closed_on attribute when an existing status is set as closed.
94 94 def handle_is_closed_change
95 95 if is_closed_changed? && is_closed == true
96 96 # First we update issues that have a journal for when the current status was set,
97 97 # a subselect is used to update all issues with a single query
98 98 subselect = "SELECT MAX(j.created_on) FROM #{Journal.table_name} j" +
99 99 " JOIN #{JournalDetail.table_name} d ON d.journal_id = j.id" +
100 100 " WHERE j.journalized_type = 'Issue' AND j.journalized_id = #{Issue.table_name}.id" +
101 101 " AND d.property = 'attr' AND d.prop_key = 'status_id' AND d.value = :status_id"
102 Issue.where(:status_id => id, :closed_on => nil).update_all(["closed_on = (#{subselect})", :status_id => id.to_s])
102 Issue.where(:status_id => id, :closed_on => nil).
103 update_all(["closed_on = (#{subselect})", {:status_id => id.to_s}])
103 104
104 105 # Then we update issues that don't have a journal which means the
105 106 # current status was set on creation
106 107 Issue.where(:status_id => id, :closed_on => nil).update_all("closed_on = created_on")
107 108 end
108 109 end
109 110
110 111 def check_integrity
111 112 if Issue.where(:status_id => id).any?
112 113 raise "This status is used by some issues"
113 114 elsif Tracker.where(:default_status_id => id).any?
114 115 raise "This status is used as the default status by some trackers"
115 116 end
116 117 end
117 118
118 119 # Deletes associated workflows
119 120 def delete_workflow_rules
120 121 WorkflowRule.delete_all(["old_status_id = :id OR new_status_id = :id", {:id => id}])
121 122 end
122 123 end
General Comments 0
You need to be logged in to leave comments. Login now