##// END OF EJS Templates
Added issues status changes on the activity view (initial patch by Cyril Mougel)....
Jean-Philippe Lang -
r879:fa95501fe5e8
parent child
Show More
@@ -0,0 +1,39
1 # redMine - project management software
2 # Copyright (C) 2006-2007 Jean-Philippe Lang
3 #
4 # This program is free software; you can redistribute it and/or
5 # modify it under the terms of the GNU General Public License
6 # as published by the Free Software Foundation; either version 2
7 # of the License, or (at your option) any later version.
8 #
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
13 #
14 # You should have received a copy of the GNU General Public License
15 # along with this program; if not, write to the Free Software
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17
18 require File.dirname(__FILE__) + '/../test_helper'
19
20 class JournalTest < Test::Unit::TestCase
21 fixtures :issues, :issue_statuses, :journals, :journal_details
22
23 def setup
24 @journal = Journal.find 1
25 end
26
27 def test_journalized_is_an_issue
28 issue = @journal.issue
29 assert_kind_of Issue, issue
30 assert_equal 1, issue.id
31 end
32
33 def test_new_status
34 status = @journal.new_status
35 assert_not_nil status
36 assert_kind_of IssueStatus, status
37 assert_equal 2, status.id
38 end
39 end
@@ -405,6 +405,7 class ProjectsController < ApplicationController
405
405
406 if @scope.include?('issues')
406 if @scope.include?('issues')
407 @events += @project.issues.find(:all, :include => [:author, :tracker], :conditions => ["#{Issue.table_name}.created_on>=? and #{Issue.table_name}.created_on<=?", @date_from, @date_to] )
407 @events += @project.issues.find(:all, :include => [:author, :tracker], :conditions => ["#{Issue.table_name}.created_on>=? and #{Issue.table_name}.created_on<=?", @date_from, @date_to] )
408 @events += @project.issues_status_changes(@date_from, @date_to)
408 end
409 end
409
410
410 if @scope.include?('news')
411 if @scope.include?('news')
@@ -29,12 +29,19 class Journal < ActiveRecord::Base
29 :project_key => "#{Issue.table_name}.project_id",
29 :project_key => "#{Issue.table_name}.project_id",
30 :date_column => "#{Issue.table_name}.created_on"
30 :date_column => "#{Issue.table_name}.created_on"
31
31
32 acts_as_event :title => Proc.new {|o| "#{o.issue.tracker.name} ##{o.issue.id}: #{o.issue.subject}"},
32 acts_as_event :title => Proc.new {|o| "#{o.issue.tracker.name} ##{o.issue.id}: #{o.issue.subject}" + ((s = o.new_status) ? " (#{s})" : '') },
33 :description => :notes,
33 :description => :notes,
34 :author => :user,
34 :url => Proc.new {|o| {:controller => 'issues', :action => 'show', :id => o.issue.id}}
35 :url => Proc.new {|o| {:controller => 'issues', :action => 'show', :id => o.issue.id}}
35
36
36 def save
37 def save
37 # Do not save an empty journal
38 # Do not save an empty journal
38 (details.empty? && notes.blank?) ? false : super
39 (details.empty? && notes.blank?) ? false : super
39 end
40 end
41
42 # Returns the new status if the journal contains a status change, otherwise nil
43 def new_status
44 c = details.detect {|detail| detail.prop_key == 'status_id'}
45 (c && c.value) ? IssueStatus.find_by_id(c.value.to_i) : nil
46 end
40 end
47 end
@@ -75,7 +75,17 class Project < ActiveRecord::Base
75 yield
75 yield
76 end
76 end
77 end
77 end
78
78
79 # Return all issues status changes for the project between the 2 given dates
80 def issues_status_changes(from, to)
81 Journal.find(:all, :include => [:issue, :details, :user],
82 :conditions => ["#{Journal.table_name}.journalized_type = 'Issue'" +
83 " AND #{Issue.table_name}.project_id = ?" +
84 " AND #{JournalDetail.table_name}.prop_key = 'status_id'" +
85 " AND #{Journal.table_name}.created_on BETWEEN ? AND ?",
86 id, from, to+1])
87 end
88
79 # returns latest created projects
89 # returns latest created projects
80 # non public projects will be returned only if user is a member of those
90 # non public projects will be returned only if user is a member of those
81 def self.latest(user=nil, count=5)
91 def self.latest(user=nil, count=5)
@@ -6,7 +6,7
6 <% @events_by_day[day].sort {|x,y| y.event_datetime <=> x.event_datetime }.each do |e| %>
6 <% @events_by_day[day].sort {|x,y| y.event_datetime <=> x.event_datetime }.each do |e| %>
7 <li><p><%= e.event_datetime.strftime("%H:%M") %> <%= link_to truncate(e.event_title, 100), e.event_url %><br />
7 <li><p><%= e.event_datetime.strftime("%H:%M") %> <%= link_to truncate(e.event_title, 100), e.event_url %><br />
8 <% unless e.event_description.blank? %><em><%= truncate(e.event_description, 500) %></em><br /><% end %>
8 <% unless e.event_description.blank? %><em><%= truncate(e.event_description, 500) %></em><br /><% end %>
9 <span class="author"><%= e.event_author if e.respond_to?(:author) %></span></p></li>
9 <span class="author"><%= e.event_author if e.respond_to?(:event_author) %></span></p></li>
10 <% end %>
10 <% end %>
11 </ul>
11 </ul>
12 <% end %>
12 <% end %>
@@ -1,8 +1,8
1 ---
1 ---
2 issues_001:
2 issues_001:
3 created_on: 2006-07-19 21:02:17 +02:00
3 created_on: <%= 3.days.ago.to_date.to_s(:db) %>
4 project_id: 1
4 project_id: 1
5 updated_on: 2006-07-19 21:04:30 +02:00
5 updated_on: <%= 1.day.ago.to_date.to_s(:db) %>
6 priority_id: 4
6 priority_id: 4
7 subject: Can't print recipes
7 subject: Can't print recipes
8 id: 1
8 id: 1
@@ -55,4 +55,4 issues_004:
55 assigned_to_id:
55 assigned_to_id:
56 author_id: 2
56 author_id: 2
57 status_id: 1
57 status_id: 1
58 No newline at end of file
58
@@ -1,6 +1,6
1 ---
1 ---
2 journals_001:
2 journals_001:
3 created_on: 2007-01-26 19:58:40 +01:00
3 created_on: <%= 2.days.ago.to_date.to_s(:db) %>
4 notes: "Journal notes"
4 notes: "Journal notes"
5 id: 1
5 id: 1
6 journalized_type: Issue
6 journalized_type: Issue
@@ -22,7 +22,7 require 'projects_controller'
22 class ProjectsController; def rescue_action(e) raise e end; end
22 class ProjectsController; def rescue_action(e) raise e end; end
23
23
24 class ProjectsControllerTest < Test::Unit::TestCase
24 class ProjectsControllerTest < Test::Unit::TestCase
25 fixtures :projects, :users, :roles, :members, :issues, :enabled_modules, :enumerations
25 fixtures :projects, :users, :roles, :members, :issues, :journals, :journal_details, :trackers, :issue_statuses, :enabled_modules, :enumerations
26
26
27 def setup
27 def setup
28 @controller = ProjectsController.new
28 @controller = ProjectsController.new
@@ -93,6 +93,24 class ProjectsControllerTest < Test::Unit::TestCase
93 assert_response :success
93 assert_response :success
94 assert_template 'activity'
94 assert_template 'activity'
95 assert_not_nil assigns(:events_by_day)
95 assert_not_nil assigns(:events_by_day)
96
97 assert_tag :tag => "h3",
98 :content => /#{2.days.ago.to_date.day}/,
99 :sibling => { :tag => "ul",
100 :child => { :tag => "li",
101 :child => { :tag => "p",
102 :content => /(#{IssueStatus.find(2).name})/,
103 }
104 }
105 }
106 assert_tag :tag => "h3",
107 :content => /#{3.day.ago.to_date.day}/,
108 :sibling => { :tag => "ul", :child => { :tag => "li",
109 :child => { :tag => "p",
110 :content => /#{Issue.find(1).subject}/,
111 }
112 }
113 }
96 end
114 end
97
115
98 def test_archive
116 def test_archive
@@ -1,107 +1,116
1 # redMine - project management software
1 # redMine - project management software
2 # Copyright (C) 2006-2007 Jean-Philippe Lang
2 # Copyright (C) 2006-2007 Jean-Philippe Lang
3 #
3 #
4 # This program is free software; you can redistribute it and/or
4 # This program is free software; you can redistribute it and/or
5 # modify it under the terms of the GNU General Public License
5 # modify it under the terms of the GNU General Public License
6 # as published by the Free Software Foundation; either version 2
6 # as published by the Free Software Foundation; either version 2
7 # of the License, or (at your option) any later version.
7 # of the License, or (at your option) any later version.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU General Public License
14 # You should have received a copy of the GNU General Public License
15 # along with this program; if not, write to the Free Software
15 # along with this program; if not, write to the Free Software
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17
17
18 require File.dirname(__FILE__) + '/../test_helper'
18 require File.dirname(__FILE__) + '/../test_helper'
19
19
20 class ProjectTest < Test::Unit::TestCase
20 class ProjectTest < Test::Unit::TestCase
21 fixtures :projects
21 fixtures :projects, :issues, :issue_statuses, :journals, :journal_details
22
22
23 def setup
23 def setup
24 @ecookbook = Project.find(1)
24 @ecookbook = Project.find(1)
25 @ecookbook_sub1 = Project.find(3)
25 @ecookbook_sub1 = Project.find(3)
26 end
26 end
27
27
28 def test_truth
28 def test_truth
29 assert_kind_of Project, @ecookbook
29 assert_kind_of Project, @ecookbook
30 assert_equal "eCookbook", @ecookbook.name
30 assert_equal "eCookbook", @ecookbook.name
31 end
31 end
32
32
33 def test_update
33 def test_update
34 assert_equal "eCookbook", @ecookbook.name
34 assert_equal "eCookbook", @ecookbook.name
35 @ecookbook.name = "eCook"
35 @ecookbook.name = "eCook"
36 assert @ecookbook.save, @ecookbook.errors.full_messages.join("; ")
36 assert @ecookbook.save, @ecookbook.errors.full_messages.join("; ")
37 @ecookbook.reload
37 @ecookbook.reload
38 assert_equal "eCook", @ecookbook.name
38 assert_equal "eCook", @ecookbook.name
39 end
39 end
40
40
41 def test_validate
41 def test_validate
42 @ecookbook.name = ""
42 @ecookbook.name = ""
43 assert !@ecookbook.save
43 assert !@ecookbook.save
44 assert_equal 1, @ecookbook.errors.count
44 assert_equal 1, @ecookbook.errors.count
45 assert_equal "activerecord_error_blank", @ecookbook.errors.on(:name)
45 assert_equal "activerecord_error_blank", @ecookbook.errors.on(:name)
46 end
46 end
47
47
48 def test_public_projects
48 def test_public_projects
49 public_projects = Project.find(:all, :conditions => ["is_public=?", true])
49 public_projects = Project.find(:all, :conditions => ["is_public=?", true])
50 assert_equal 3, public_projects.length
50 assert_equal 3, public_projects.length
51 assert_equal true, public_projects[0].is_public?
51 assert_equal true, public_projects[0].is_public?
52 end
52 end
53
53
54 def test_archive
54 def test_archive
55 user = @ecookbook.members.first.user
55 user = @ecookbook.members.first.user
56 @ecookbook.archive
56 @ecookbook.archive
57 @ecookbook.reload
57 @ecookbook.reload
58
58
59 assert !@ecookbook.active?
59 assert !@ecookbook.active?
60 assert !user.projects.include?(@ecookbook)
60 assert !user.projects.include?(@ecookbook)
61 # Subproject are also archived
61 # Subproject are also archived
62 assert !@ecookbook.children.empty?
62 assert !@ecookbook.children.empty?
63 assert @ecookbook.active_children.empty?
63 assert @ecookbook.active_children.empty?
64 end
64 end
65
65
66 def test_unarchive
66 def test_unarchive
67 user = @ecookbook.members.first.user
67 user = @ecookbook.members.first.user
68 @ecookbook.archive
68 @ecookbook.archive
69 # A subproject of an archived project can not be unarchived
69 # A subproject of an archived project can not be unarchived
70 assert !@ecookbook_sub1.unarchive
70 assert !@ecookbook_sub1.unarchive
71
71
72 # Unarchive project
72 # Unarchive project
73 assert @ecookbook.unarchive
73 assert @ecookbook.unarchive
74 @ecookbook.reload
74 @ecookbook.reload
75 assert @ecookbook.active?
75 assert @ecookbook.active?
76 assert user.projects.include?(@ecookbook)
76 assert user.projects.include?(@ecookbook)
77 # Subproject can now be unarchived
77 # Subproject can now be unarchived
78 @ecookbook_sub1.reload
78 @ecookbook_sub1.reload
79 assert @ecookbook_sub1.unarchive
79 assert @ecookbook_sub1.unarchive
80 end
80 end
81
81
82 def test_destroy
82 def test_destroy
83 @ecookbook.destroy
83 @ecookbook.destroy
84 assert_raise(ActiveRecord::RecordNotFound) { Project.find(@ecookbook.id) }
84 assert_raise(ActiveRecord::RecordNotFound) { Project.find(@ecookbook.id) }
85 end
85 end
86
86
87 def test_subproject_ok
87 def test_subproject_ok
88 sub = Project.find(2)
88 sub = Project.find(2)
89 sub.parent = @ecookbook
89 sub.parent = @ecookbook
90 assert sub.save
90 assert sub.save
91 assert_equal @ecookbook.id, sub.parent.id
91 assert_equal @ecookbook.id, sub.parent.id
92 @ecookbook.reload
92 @ecookbook.reload
93 assert_equal 3, @ecookbook.children.size
93 assert_equal 3, @ecookbook.children.size
94 end
94 end
95
95
96 def test_subproject_invalid
96 def test_subproject_invalid
97 sub = Project.find(2)
97 sub = Project.find(2)
98 sub.parent = @ecookbook_sub1
98 sub.parent = @ecookbook_sub1
99 assert !sub.save
99 assert !sub.save
100 end
100 end
101
101
102 def test_subproject_invalid_2
102 def test_subproject_invalid_2
103 sub = @ecookbook
103 sub = @ecookbook
104 sub.parent = Project.find(2)
104 sub.parent = Project.find(2)
105 assert !sub.save
105 assert !sub.save
106 end
106 end
107 end
107
108 def test_issues_status_changes
109 journals = @ecookbook.issues_status_changes 3.days.ago.to_date, Date.today
110 assert_equal 1, journals.size
111 assert_kind_of Journal, journals.first
112
113 journals = @ecookbook.issues_status_changes 30.days.ago.to_date, 10.days.ago.to_date
114 assert_equal 0, journals.size
115 end
116 end
General Comments 0
You need to be logged in to leave comments. Login now