##// END OF EJS Templates
Adds closed_on column that stores the time of the last closing (#824)....
Jean-Philippe Lang -
r11172:a45c0dc55057
parent child
Show More
@@ -0,0 +1,9
1 class AddIssuesClosedOn < ActiveRecord::Migration
2 def up
3 add_column :issues, :closed_on, :datetime, :default => nil
4 end
5
6 def down
7 remove_column :issues, :closed_on
8 end
9 end
@@ -0,0 +1,25
1 class PopulateIssuesClosedOn < ActiveRecord::Migration
2 def up
3 closed_status_ids = IssueStatus.where(:is_closed => true).pluck(:id)
4 if closed_status_ids.any?
5 # First set closed_on for issues that have been closed once
6 closed_status_values = closed_status_ids.map {|status_id| "'#{status_id}'"}.join(',')
7 subselect = "SELECT MAX(#{Journal.table_name}.created_on)" +
8 " FROM #{Journal.table_name}, #{JournalDetail.table_name}" +
9 " WHERE #{Journal.table_name}.id = #{JournalDetail.table_name}.journal_id" +
10 " AND #{Journal.table_name}.journalized_type = 'Issue' AND #{Journal.table_name}.journalized_id = #{Issue.table_name}.id" +
11 " AND #{JournalDetail.table_name}.property = 'attr' AND #{JournalDetail.table_name}.prop_key = 'status_id'" +
12 " AND #{JournalDetail.table_name}.old_value NOT IN (#{closed_status_values})" +
13 " AND #{JournalDetail.table_name}.value IN (#{closed_status_values})"
14 Issue.update_all "closed_on = (#{subselect})"
15
16 # Then set closed_on for closed issues that weren't up updated by the above UPDATE
17 # No journal was found so we assume that they were closed on creation
18 Issue.update_all "closed_on = created_on", {:status_id => closed_status_ids, :closed_on => nil}
19 end
20 end
21
22 def down
23 Issue.update_all :closed_on => nil
24 end
25 end
@@ -91,7 +91,7 class Issue < ActiveRecord::Base
91 91 }
92 92
93 93 before_create :default_assign
94 before_save :close_duplicates, :update_done_ratio_from_issue_status, :force_updated_on_change
94 before_save :close_duplicates, :update_done_ratio_from_issue_status, :force_updated_on_change, :update_closed_on
95 95 after_save {|issue| issue.send :after_project_change if !issue.id_changed? && issue.project_id_changed?}
96 96 after_save :reschedule_following_issues, :update_nested_set_attributes, :update_parent_attributes, :create_journal
97 97 # Should be after_create but would be called before previous after_save callbacks
@@ -1307,10 +1307,23 class Issue < ActiveRecord::Base
1307 1307 end
1308 1308 end
1309 1309
1310 # Make sure updated_on is updated when adding a note
1310 # Make sure updated_on is updated when adding a note and set updated_on now
1311 # so we can set closed_on with the same value on closing
1311 1312 def force_updated_on_change
1312 if @current_journal
1313 if @current_journal || changed?
1313 1314 self.updated_on = current_time_from_proper_timezone
1315 if new_record?
1316 self.created_on = updated_on
1317 end
1318 end
1319 end
1320
1321 # Callback for setting closed_on when the issue is closed.
1322 # The closed_on attribute stores the time of the last closing
1323 # and is preserved when the issue is reopened.
1324 def update_closed_on
1325 if closing? || (new_record? && closed?)
1326 self.closed_on = updated_on
1314 1327 end
1315 1328 end
1316 1329
@@ -1320,7 +1333,7 class Issue < ActiveRecord::Base
1320 1333 if @current_journal
1321 1334 # attributes changes
1322 1335 if @attributes_before_change
1323 (Issue.column_names - %w(id root_id lft rgt lock_version created_on updated_on)).each {|c|
1336 (Issue.column_names - %w(id root_id lft rgt lock_version created_on updated_on closed_on)).each {|c|
1324 1337 before = @attributes_before_change[c]
1325 1338 after = send(c)
1326 1339 next if before == after || (before.blank? && after.blank?)
@@ -152,6 +152,7 issues_008:
152 152 root_id: 8
153 153 lft: 1
154 154 rgt: 2
155 closed_on: <%= 3.days.ago.to_s(:db) %>
155 156 issues_009:
156 157 created_on: <%= 1.minute.ago.to_s(:db) %>
157 158 project_id: 5
@@ -209,6 +210,7 issues_011:
209 210 root_id: 11
210 211 lft: 1
211 212 rgt: 2
213 closed_on: <%= 1.day.ago.to_s(:db) %>
212 214 issues_012:
213 215 created_on: <%= 3.days.ago.to_s(:db) %>
214 216 project_id: 1
@@ -228,6 +230,7 issues_012:
228 230 root_id: 12
229 231 lft: 1
230 232 rgt: 2
233 closed_on: <%= 1.day.ago.to_s(:db) %>
231 234 issues_013:
232 235 created_on: <%= 5.days.ago.to_s(:db) %>
233 236 project_id: 3
@@ -1917,4 +1917,58 class IssueTest < ActiveSupport::TestCase
1917 1917 assert_equal 3, issue.reload.attachments.count
1918 1918 assert_equal %w(upload foo bar), issue.attachments.map(&:filename)
1919 1919 end
1920
1921 def test_closed_on_should_be_nil_when_creating_an_open_issue
1922 issue = Issue.generate!(:status_id => 1).reload
1923 assert !issue.closed?
1924 assert_nil issue.closed_on
1925 end
1926
1927 def test_closed_on_should_be_set_when_creating_a_closed_issue
1928 issue = Issue.generate!(:status_id => 5).reload
1929 assert issue.closed?
1930 assert_not_nil issue.closed_on
1931 assert_equal issue.updated_on, issue.closed_on
1932 assert_equal issue.created_on, issue.closed_on
1933 end
1934
1935 def test_closed_on_should_be_nil_when_updating_an_open_issue
1936 issue = Issue.find(1)
1937 issue.subject = 'Not closed yet'
1938 issue.save!
1939 issue.reload
1940 assert_nil issue.closed_on
1941 end
1942
1943 def test_closed_on_should_be_set_when_closing_an_open_issue
1944 issue = Issue.find(1)
1945 issue.subject = 'Now closed'
1946 issue.status_id = 5
1947 issue.save!
1948 issue.reload
1949 assert_not_nil issue.closed_on
1950 assert_equal issue.updated_on, issue.closed_on
1951 end
1952
1953 def test_closed_on_should_not_be_updated_when_updating_a_closed_issue
1954 issue = Issue.open(false).first
1955 was_closed_on = issue.closed_on
1956 assert_not_nil was_closed_on
1957 issue.subject = 'Updating a closed issue'
1958 issue.save!
1959 issue.reload
1960 assert_equal was_closed_on, issue.closed_on
1961 end
1962
1963 def test_closed_on_should_be_preserved_when_reopening_a_closed_issue
1964 issue = Issue.open(false).first
1965 was_closed_on = issue.closed_on
1966 assert_not_nil was_closed_on
1967 issue.subject = 'Reopening a closed issue'
1968 issue.status_id = 1
1969 issue.save!
1970 issue.reload
1971 assert !issue.closed?
1972 assert_equal was_closed_on, issue.closed_on
1973 end
1920 1974 end
General Comments 0
You need to be logged in to leave comments. Login now