##// END OF EJS Templates
Merged r14795 and r14796 (#21150)....
Jean-Philippe Lang -
r14455:bff6ff9273cf
parent child
Show More
@@ -1,160 +1,160
1 # Redmine - project management software
1 # Redmine - project management software
2 # Copyright (C) 2006-2015 Jean-Philippe Lang
2 # Copyright (C) 2006-2015 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 class TimeEntry < ActiveRecord::Base
18 class TimeEntry < ActiveRecord::Base
19 include Redmine::SafeAttributes
19 include Redmine::SafeAttributes
20 # could have used polymorphic association
20 # could have used polymorphic association
21 # project association here allows easy loading of time entries at project level with one database trip
21 # project association here allows easy loading of time entries at project level with one database trip
22 belongs_to :project
22 belongs_to :project
23 belongs_to :issue
23 belongs_to :issue
24 belongs_to :user
24 belongs_to :user
25 belongs_to :activity, :class_name => 'TimeEntryActivity'
25 belongs_to :activity, :class_name => 'TimeEntryActivity'
26
26
27 attr_protected :user_id, :tyear, :tmonth, :tweek
27 attr_protected :user_id, :tyear, :tmonth, :tweek
28
28
29 acts_as_customizable
29 acts_as_customizable
30 acts_as_event :title => Proc.new {|o| "#{l_hours(o.hours)} (#{(o.issue || o.project).event_title})"},
30 acts_as_event :title => Proc.new {|o| "#{l_hours(o.hours)} (#{(o.issue || o.project).event_title})"},
31 :url => Proc.new {|o| {:controller => 'timelog', :action => 'index', :project_id => o.project, :issue_id => o.issue}},
31 :url => Proc.new {|o| {:controller => 'timelog', :action => 'index', :project_id => o.project, :issue_id => o.issue}},
32 :author => :user,
32 :author => :user,
33 :group => :issue,
33 :group => :issue,
34 :description => :comments
34 :description => :comments
35
35
36 acts_as_activity_provider :timestamp => "#{table_name}.created_on",
36 acts_as_activity_provider :timestamp => "#{table_name}.created_on",
37 :author_key => :user_id,
37 :author_key => :user_id,
38 :scope => joins(:project).preload(:project)
38 :scope => joins(:project).preload(:project)
39
39
40 validates_presence_of :user_id, :activity_id, :project_id, :hours, :spent_on
40 validates_presence_of :user_id, :activity_id, :project_id, :hours, :spent_on
41 validates_numericality_of :hours, :allow_nil => true, :message => :invalid
41 validates_numericality_of :hours, :allow_nil => true, :message => :invalid
42 validates_length_of :comments, :maximum => 255, :allow_nil => true
42 validates_length_of :comments, :maximum => 255, :allow_nil => true
43 validates :spent_on, :date => true
43 validates :spent_on, :date => true
44 before_validation :set_project_if_nil
44 before_validation :set_project_if_nil
45 validate :validate_time_entry
45 validate :validate_time_entry
46
46
47 scope :visible, lambda {|*args|
47 scope :visible, lambda {|*args|
48 joins(:project).
48 joins(:project).
49 where(TimeEntry.visible_condition(args.shift || User.current, *args))
49 where(TimeEntry.visible_condition(args.shift || User.current, *args))
50 }
50 }
51 scope :on_issue, lambda {|issue|
51 scope :on_issue, lambda {|issue|
52 joins(:issue).
52 joins(:issue).
53 where("#{Issue.table_name}.root_id = #{issue.root_id} AND #{Issue.table_name}.lft >= #{issue.lft} AND #{Issue.table_name}.rgt <= #{issue.rgt}")
53 where("#{Issue.table_name}.root_id = #{issue.root_id} AND #{Issue.table_name}.lft >= #{issue.lft} AND #{Issue.table_name}.rgt <= #{issue.rgt}")
54 }
54 }
55
55
56 safe_attributes 'hours', 'comments', 'project_id', 'issue_id', 'activity_id', 'spent_on', 'custom_field_values', 'custom_fields'
56 safe_attributes 'hours', 'comments', 'project_id', 'issue_id', 'activity_id', 'spent_on', 'custom_field_values', 'custom_fields'
57
57
58 # Returns a SQL conditions string used to find all time entries visible by the specified user
58 # Returns a SQL conditions string used to find all time entries visible by the specified user
59 def self.visible_condition(user, options={})
59 def self.visible_condition(user, options={})
60 Project.allowed_to_condition(user, :view_time_entries, options) do |role, user|
60 Project.allowed_to_condition(user, :view_time_entries, options) do |role, user|
61 if role.time_entries_visibility == 'all'
61 if role.time_entries_visibility == 'all'
62 nil
62 nil
63 elsif role.time_entries_visibility == 'own' && user.id && user.logged?
63 elsif role.time_entries_visibility == 'own' && user.id && user.logged?
64 "#{table_name}.user_id = #{user.id}"
64 "#{table_name}.user_id = #{user.id}"
65 else
65 else
66 '1=0'
66 '1=0'
67 end
67 end
68 end
68 end
69 end
69 end
70
70
71 # Returns true if user or current user is allowed to view the time entry
71 # Returns true if user or current user is allowed to view the time entry
72 def visible?(user=nil)
72 def visible?(user=nil)
73 (user || User.current).allowed_to?(:view_time_entries, self.project) do |role, user|
73 (user || User.current).allowed_to?(:view_time_entries, self.project) do |role, user|
74 if role.time_entries_visibility == 'all'
74 if role.time_entries_visibility == 'all'
75 true
75 true
76 elsif role.time_entries_visibility == 'own'
76 elsif role.time_entries_visibility == 'own'
77 self.user == user
77 self.user == user
78 else
78 else
79 false
79 false
80 end
80 end
81 end
81 end
82 end
82 end
83
83
84 def initialize(attributes=nil, *args)
84 def initialize(attributes=nil, *args)
85 super
85 super
86 if new_record? && self.activity.nil?
86 if new_record? && self.activity.nil?
87 if default_activity = TimeEntryActivity.default
87 if default_activity = TimeEntryActivity.default
88 self.activity_id = default_activity.id
88 self.activity_id = default_activity.id
89 end
89 end
90 self.hours = nil if hours == 0
90 self.hours = nil if hours == 0
91 end
91 end
92 end
92 end
93
93
94 def safe_attributes=(attrs, user=User.current)
94 def safe_attributes=(attrs, user=User.current)
95 if attrs
95 if attrs
96 attrs = super(attrs)
96 attrs = super(attrs)
97 if issue_id_changed? && issue
97 if issue_id_changed? && issue
98 if user.allowed_to?(:log_time, issue.project)
98 if issue.visible?(user) && user.allowed_to?(:log_time, issue.project)
99 if attrs[:project_id].blank? && issue.project_id != project_id
99 if attrs[:project_id].blank? && issue.project_id != project_id
100 self.project_id = issue.project_id
100 self.project_id = issue.project_id
101 end
101 end
102 @invalid_issue_id = nil
102 @invalid_issue_id = nil
103 else
103 else
104 @invalid_issue_id = issue_id
104 @invalid_issue_id = issue_id
105 end
105 end
106 end
106 end
107 end
107 end
108 attrs
108 attrs
109 end
109 end
110
110
111 def set_project_if_nil
111 def set_project_if_nil
112 self.project = issue.project if issue && project.nil?
112 self.project = issue.project if issue && project.nil?
113 end
113 end
114
114
115 def validate_time_entry
115 def validate_time_entry
116 errors.add :hours, :invalid if hours && (hours < 0 || hours >= 1000)
116 errors.add :hours, :invalid if hours && (hours < 0 || hours >= 1000)
117 errors.add :project_id, :invalid if project.nil?
117 errors.add :project_id, :invalid if project.nil?
118 errors.add :issue_id, :invalid if (issue_id && !issue) || (issue && project!=issue.project) || @invalid_issue_id
118 errors.add :issue_id, :invalid if (issue_id && !issue) || (issue && project!=issue.project) || @invalid_issue_id
119 errors.add :activity_id, :inclusion if activity_id_changed? && project && !project.activities.include?(activity)
119 errors.add :activity_id, :inclusion if activity_id_changed? && project && !project.activities.include?(activity)
120 end
120 end
121
121
122 def hours=(h)
122 def hours=(h)
123 write_attribute :hours, (h.is_a?(String) ? (h.to_hours || h) : h)
123 write_attribute :hours, (h.is_a?(String) ? (h.to_hours || h) : h)
124 end
124 end
125
125
126 def hours
126 def hours
127 h = read_attribute(:hours)
127 h = read_attribute(:hours)
128 if h.is_a?(Float)
128 if h.is_a?(Float)
129 h.round(2)
129 h.round(2)
130 else
130 else
131 h
131 h
132 end
132 end
133 end
133 end
134
134
135 # tyear, tmonth, tweek assigned where setting spent_on attributes
135 # tyear, tmonth, tweek assigned where setting spent_on attributes
136 # these attributes make time aggregations easier
136 # these attributes make time aggregations easier
137 def spent_on=(date)
137 def spent_on=(date)
138 super
138 super
139 self.tyear = spent_on ? spent_on.year : nil
139 self.tyear = spent_on ? spent_on.year : nil
140 self.tmonth = spent_on ? spent_on.month : nil
140 self.tmonth = spent_on ? spent_on.month : nil
141 self.tweek = spent_on ? Date.civil(spent_on.year, spent_on.month, spent_on.day).cweek : nil
141 self.tweek = spent_on ? Date.civil(spent_on.year, spent_on.month, spent_on.day).cweek : nil
142 end
142 end
143
143
144 # Returns true if the time entry can be edited by usr, otherwise false
144 # Returns true if the time entry can be edited by usr, otherwise false
145 def editable_by?(usr)
145 def editable_by?(usr)
146 visible?(usr) && (
146 visible?(usr) && (
147 (usr == user && usr.allowed_to?(:edit_own_time_entries, project)) || usr.allowed_to?(:edit_time_entries, project)
147 (usr == user && usr.allowed_to?(:edit_own_time_entries, project)) || usr.allowed_to?(:edit_time_entries, project)
148 )
148 )
149 end
149 end
150
150
151 # Returns the custom_field_values that can be edited by the given user
151 # Returns the custom_field_values that can be edited by the given user
152 def editable_custom_field_values(user=nil)
152 def editable_custom_field_values(user=nil)
153 visible_custom_field_values
153 visible_custom_field_values
154 end
154 end
155
155
156 # Returns the custom fields that can be edited by the given user
156 # Returns the custom fields that can be edited by the given user
157 def editable_custom_fields(user=nil)
157 def editable_custom_fields(user=nil)
158 editable_custom_field_values(user).map(&:custom_field).uniq
158 editable_custom_field_values(user).map(&:custom_field).uniq
159 end
159 end
160 end
160 end
@@ -1,47 +1,49
1 <%= error_messages_for 'time_entry' %>
1 <%= error_messages_for 'time_entry' %>
2 <%= back_url_hidden_field_tag %>
2 <%= back_url_hidden_field_tag %>
3
3
4 <div class="box tabular">
4 <div class="box tabular">
5 <% if @time_entry.new_record? %>
5 <% if @time_entry.new_record? %>
6 <% if params[:project_id] %>
6 <% if params[:project_id] %>
7 <%= hidden_field_tag 'project_id', params[:project_id] %>
7 <%= hidden_field_tag 'project_id', params[:project_id] %>
8 <% elsif params[:issue_id] %>
8 <% elsif params[:issue_id] %>
9 <%= hidden_field_tag 'issue_id', params[:issue_id] %>
9 <%= hidden_field_tag 'issue_id', params[:issue_id] %>
10 <% else %>
10 <% else %>
11 <p><%= f.select :project_id, project_tree_options_for_select(Project.allowed_to(:log_time).to_a, :selected => @time_entry.project, :include_blank => true) %></p>
11 <p><%= f.select :project_id, project_tree_options_for_select(Project.allowed_to(:log_time).to_a, :selected => @time_entry.project, :include_blank => true) %></p>
12 <% end %>
12 <% end %>
13 <% end %>
13 <% end %>
14 <p>
14 <p>
15 <%= f.text_field :issue_id, :size => 6 %>
15 <%= f.text_field :issue_id, :size => 6 %>
16 <span id="time_entry_issue"><%= "#{@time_entry.issue.tracker.name} ##{@time_entry.issue.id}: #{@time_entry.issue.subject}" if @time_entry.issue %></span>
16 <% if @time_entry.issue.try(:visible?) %>
17 <span id="time_entry_issue"><%= "#{@time_entry.issue.tracker.name} ##{@time_entry.issue.id}: #{@time_entry.issue.subject}" %></span>
18 <% end %>
17 </p>
19 </p>
18 <p><%= f.text_field :spent_on, :size => 10, :required => true %><%= calendar_for('time_entry_spent_on') %></p>
20 <p><%= f.text_field :spent_on, :size => 10, :required => true %><%= calendar_for('time_entry_spent_on') %></p>
19 <p><%= f.text_field :hours, :size => 6, :required => true %></p>
21 <p><%= f.text_field :hours, :size => 6, :required => true %></p>
20 <p><%= f.text_field :comments, :size => 100, :maxlength => 255 %></p>
22 <p><%= f.text_field :comments, :size => 100, :maxlength => 255 %></p>
21 <p><%= f.select :activity_id, activity_collection_for_select_options(@time_entry), :required => true %></p>
23 <p><%= f.select :activity_id, activity_collection_for_select_options(@time_entry), :required => true %></p>
22 <% @time_entry.custom_field_values.each do |value| %>
24 <% @time_entry.custom_field_values.each do |value| %>
23 <p><%= custom_field_tag_with_label :time_entry, value %></p>
25 <p><%= custom_field_tag_with_label :time_entry, value %></p>
24 <% end %>
26 <% end %>
25 <%= call_hook(:view_timelog_edit_form_bottom, { :time_entry => @time_entry, :form => f }) %>
27 <%= call_hook(:view_timelog_edit_form_bottom, { :time_entry => @time_entry, :form => f }) %>
26 </div>
28 </div>
27
29
28 <%= javascript_tag do %>
30 <%= javascript_tag do %>
29 <% if @time_entry.new_record? %>
31 <% if @time_entry.new_record? %>
30 $(document).ready(function(){
32 $(document).ready(function(){
31 $('#time_entry_project_id, #time_entry_issue_id').change(function(){
33 $('#time_entry_project_id, #time_entry_issue_id').change(function(){
32 $.ajax({
34 $.ajax({
33 url: '<%= escape_javascript new_time_entry_path(:format => 'js') %>',
35 url: '<%= escape_javascript new_time_entry_path(:format => 'js') %>',
34 type: 'post',
36 type: 'post',
35 data: $('#new_time_entry').serialize()
37 data: $('#new_time_entry').serialize()
36 });
38 });
37 });
39 });
38 });
40 });
39 <% end %>
41 <% end %>
40
42
41 observeAutocompleteField('time_entry_issue_id', '<%= escape_javascript auto_complete_issues_path(:project_id => @project, :scope => (@project ? nil : 'all'))%>', {
43 observeAutocompleteField('time_entry_issue_id', '<%= escape_javascript auto_complete_issues_path(:project_id => @project, :scope => (@project ? nil : 'all'))%>', {
42 select: function(event, ui) {
44 select: function(event, ui) {
43 $('#time_entry_issue').text(ui.item.label);
45 $('#time_entry_issue').text(ui.item.label);
44 $('#time_entry_issue_id').blur();
46 $('#time_entry_issue_id').blur();
45 }
47 }
46 });
48 });
47 <% end %>
49 <% end %>
@@ -1,809 +1,826
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 # Redmine - project management software
2 # Redmine - project management software
3 # Copyright (C) 2006-2015 Jean-Philippe Lang
3 # Copyright (C) 2006-2015 Jean-Philippe Lang
4 #
4 #
5 # This program is free software; you can redistribute it and/or
5 # This program is free software; you can redistribute it and/or
6 # modify it under the terms of the GNU General Public License
6 # modify it under the terms of the GNU General Public License
7 # as published by the Free Software Foundation; either version 2
7 # as published by the Free Software Foundation; either version 2
8 # of the License, or (at your option) any later version.
8 # of the License, or (at your option) any later version.
9 #
9 #
10 # This program is distributed in the hope that it will be useful,
10 # This program is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 # GNU General Public License for more details.
13 # GNU General Public License for more details.
14 #
14 #
15 # You should have received a copy of the GNU General Public License
15 # You should have received a copy of the GNU General Public License
16 # along with this program; if not, write to the Free Software
16 # along with this program; if not, write to the Free Software
17 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18
18
19 require File.expand_path('../../test_helper', __FILE__)
19 require File.expand_path('../../test_helper', __FILE__)
20
20
21 class TimelogControllerTest < ActionController::TestCase
21 class TimelogControllerTest < ActionController::TestCase
22 fixtures :projects, :enabled_modules, :roles, :members,
22 fixtures :projects, :enabled_modules, :roles, :members,
23 :member_roles, :issues, :time_entries, :users,
23 :member_roles, :issues, :time_entries, :users,
24 :trackers, :enumerations, :issue_statuses,
24 :trackers, :enumerations, :issue_statuses,
25 :custom_fields, :custom_values,
25 :custom_fields, :custom_values,
26 :projects_trackers, :custom_fields_trackers,
26 :projects_trackers, :custom_fields_trackers,
27 :custom_fields_projects
27 :custom_fields_projects
28
28
29 include Redmine::I18n
29 include Redmine::I18n
30
30
31 def test_new
31 def test_new
32 @request.session[:user_id] = 3
32 @request.session[:user_id] = 3
33 get :new
33 get :new
34 assert_response :success
34 assert_response :success
35 assert_template 'new'
35 assert_template 'new'
36 assert_select 'input[name=?][type=hidden]', 'project_id', 0
36 assert_select 'input[name=?][type=hidden]', 'project_id', 0
37 assert_select 'input[name=?][type=hidden]', 'issue_id', 0
37 assert_select 'input[name=?][type=hidden]', 'issue_id', 0
38 assert_select 'select[name=?]', 'time_entry[project_id]' do
38 assert_select 'select[name=?]', 'time_entry[project_id]' do
39 # blank option for project
39 # blank option for project
40 assert_select 'option[value=""]'
40 assert_select 'option[value=""]'
41 end
41 end
42 end
42 end
43
43
44 def test_new_with_project_id
44 def test_new_with_project_id
45 @request.session[:user_id] = 3
45 @request.session[:user_id] = 3
46 get :new, :project_id => 1
46 get :new, :project_id => 1
47 assert_response :success
47 assert_response :success
48 assert_template 'new'
48 assert_template 'new'
49 assert_select 'input[name=?][type=hidden]', 'project_id'
49 assert_select 'input[name=?][type=hidden]', 'project_id'
50 assert_select 'input[name=?][type=hidden]', 'issue_id', 0
50 assert_select 'input[name=?][type=hidden]', 'issue_id', 0
51 assert_select 'select[name=?]', 'time_entry[project_id]', 0
51 assert_select 'select[name=?]', 'time_entry[project_id]', 0
52 end
52 end
53
53
54 def test_new_with_issue_id
54 def test_new_with_issue_id
55 @request.session[:user_id] = 3
55 @request.session[:user_id] = 3
56 get :new, :issue_id => 2
56 get :new, :issue_id => 2
57 assert_response :success
57 assert_response :success
58 assert_template 'new'
58 assert_template 'new'
59 assert_select 'input[name=?][type=hidden]', 'project_id', 0
59 assert_select 'input[name=?][type=hidden]', 'project_id', 0
60 assert_select 'input[name=?][type=hidden]', 'issue_id'
60 assert_select 'input[name=?][type=hidden]', 'issue_id'
61 assert_select 'select[name=?]', 'time_entry[project_id]', 0
61 assert_select 'select[name=?]', 'time_entry[project_id]', 0
62 end
62 end
63
63
64 def test_new_without_project_should_prefill_the_form
64 def test_new_without_project_should_prefill_the_form
65 @request.session[:user_id] = 3
65 @request.session[:user_id] = 3
66 get :new, :time_entry => {:project_id => '1'}
66 get :new, :time_entry => {:project_id => '1'}
67 assert_response :success
67 assert_response :success
68 assert_template 'new'
68 assert_template 'new'
69 assert_select 'select[name=?]', 'time_entry[project_id]' do
69 assert_select 'select[name=?]', 'time_entry[project_id]' do
70 assert_select 'option[value="1"][selected=selected]'
70 assert_select 'option[value="1"][selected=selected]'
71 end
71 end
72 end
72 end
73
73
74 def test_new_without_project_should_deny_without_permission
74 def test_new_without_project_should_deny_without_permission
75 Role.all.each {|role| role.remove_permission! :log_time}
75 Role.all.each {|role| role.remove_permission! :log_time}
76 @request.session[:user_id] = 3
76 @request.session[:user_id] = 3
77
77
78 get :new
78 get :new
79 assert_response 403
79 assert_response 403
80 end
80 end
81
81
82 def test_new_should_select_default_activity
82 def test_new_should_select_default_activity
83 @request.session[:user_id] = 3
83 @request.session[:user_id] = 3
84 get :new, :project_id => 1
84 get :new, :project_id => 1
85 assert_response :success
85 assert_response :success
86 assert_select 'select[name=?]', 'time_entry[activity_id]' do
86 assert_select 'select[name=?]', 'time_entry[activity_id]' do
87 assert_select 'option[selected=selected]', :text => 'Development'
87 assert_select 'option[selected=selected]', :text => 'Development'
88 end
88 end
89 end
89 end
90
90
91 def test_new_should_only_show_active_time_entry_activities
91 def test_new_should_only_show_active_time_entry_activities
92 @request.session[:user_id] = 3
92 @request.session[:user_id] = 3
93 get :new, :project_id => 1
93 get :new, :project_id => 1
94 assert_response :success
94 assert_response :success
95 assert_select 'option', :text => 'Inactive Activity', :count => 0
95 assert_select 'option', :text => 'Inactive Activity', :count => 0
96 end
96 end
97
97
98 def test_post_new_as_js_should_update_activity_options
98 def test_post_new_as_js_should_update_activity_options
99 @request.session[:user_id] = 3
99 @request.session[:user_id] = 3
100 post :new, :time_entry => {:project_id => 1}, :format => 'js'
100 post :new, :time_entry => {:project_id => 1}, :format => 'js'
101 assert_response :success
101 assert_response :success
102 assert_include '#time_entry_activity_id', response.body
102 assert_include '#time_entry_activity_id', response.body
103 end
103 end
104
104
105 def test_get_edit_existing_time
105 def test_get_edit_existing_time
106 @request.session[:user_id] = 2
106 @request.session[:user_id] = 2
107 get :edit, :id => 2, :project_id => nil
107 get :edit, :id => 2, :project_id => nil
108 assert_response :success
108 assert_response :success
109 assert_template 'edit'
109 assert_template 'edit'
110 assert_select 'form[action=?]', '/time_entries/2'
110 assert_select 'form[action=?]', '/time_entries/2'
111 end
111 end
112
112
113 def test_get_edit_with_an_existing_time_entry_with_inactive_activity
113 def test_get_edit_with_an_existing_time_entry_with_inactive_activity
114 te = TimeEntry.find(1)
114 te = TimeEntry.find(1)
115 te.activity = TimeEntryActivity.find_by_name("Inactive Activity")
115 te.activity = TimeEntryActivity.find_by_name("Inactive Activity")
116 te.save!(:validate => false)
116 te.save!(:validate => false)
117
117
118 @request.session[:user_id] = 1
118 @request.session[:user_id] = 1
119 get :edit, :project_id => 1, :id => 1
119 get :edit, :project_id => 1, :id => 1
120 assert_response :success
120 assert_response :success
121 assert_template 'edit'
121 assert_template 'edit'
122 # Blank option since nothing is pre-selected
122 # Blank option since nothing is pre-selected
123 assert_select 'option', :text => '--- Please select ---'
123 assert_select 'option', :text => '--- Please select ---'
124 end
124 end
125
125
126 def test_post_create
126 def test_post_create
127 @request.session[:user_id] = 3
127 @request.session[:user_id] = 3
128 assert_difference 'TimeEntry.count' do
128 assert_difference 'TimeEntry.count' do
129 post :create, :project_id => 1,
129 post :create, :project_id => 1,
130 :time_entry => {:comments => 'Some work on TimelogControllerTest',
130 :time_entry => {:comments => 'Some work on TimelogControllerTest',
131 # Not the default activity
131 # Not the default activity
132 :activity_id => '11',
132 :activity_id => '11',
133 :spent_on => '2008-03-14',
133 :spent_on => '2008-03-14',
134 :issue_id => '1',
134 :issue_id => '1',
135 :hours => '7.3'}
135 :hours => '7.3'}
136 assert_redirected_to '/projects/ecookbook/time_entries'
136 assert_redirected_to '/projects/ecookbook/time_entries'
137 end
137 end
138
138
139 t = TimeEntry.order('id DESC').first
139 t = TimeEntry.order('id DESC').first
140 assert_not_nil t
140 assert_not_nil t
141 assert_equal 'Some work on TimelogControllerTest', t.comments
141 assert_equal 'Some work on TimelogControllerTest', t.comments
142 assert_equal 1, t.project_id
142 assert_equal 1, t.project_id
143 assert_equal 1, t.issue_id
143 assert_equal 1, t.issue_id
144 assert_equal 11, t.activity_id
144 assert_equal 11, t.activity_id
145 assert_equal 7.3, t.hours
145 assert_equal 7.3, t.hours
146 assert_equal 3, t.user_id
146 assert_equal 3, t.user_id
147 end
147 end
148
148
149 def test_post_create_with_blank_issue
149 def test_post_create_with_blank_issue
150 @request.session[:user_id] = 3
150 @request.session[:user_id] = 3
151 assert_difference 'TimeEntry.count' do
151 assert_difference 'TimeEntry.count' do
152 post :create, :project_id => 1,
152 post :create, :project_id => 1,
153 :time_entry => {:comments => 'Some work on TimelogControllerTest',
153 :time_entry => {:comments => 'Some work on TimelogControllerTest',
154 # Not the default activity
154 # Not the default activity
155 :activity_id => '11',
155 :activity_id => '11',
156 :issue_id => '',
156 :issue_id => '',
157 :spent_on => '2008-03-14',
157 :spent_on => '2008-03-14',
158 :hours => '7.3'}
158 :hours => '7.3'}
159 assert_redirected_to '/projects/ecookbook/time_entries'
159 assert_redirected_to '/projects/ecookbook/time_entries'
160 end
160 end
161
161
162 t = TimeEntry.order('id DESC').first
162 t = TimeEntry.order('id DESC').first
163 assert_not_nil t
163 assert_not_nil t
164 assert_equal 'Some work on TimelogControllerTest', t.comments
164 assert_equal 'Some work on TimelogControllerTest', t.comments
165 assert_equal 1, t.project_id
165 assert_equal 1, t.project_id
166 assert_nil t.issue_id
166 assert_nil t.issue_id
167 assert_equal 11, t.activity_id
167 assert_equal 11, t.activity_id
168 assert_equal 7.3, t.hours
168 assert_equal 7.3, t.hours
169 assert_equal 3, t.user_id
169 assert_equal 3, t.user_id
170 end
170 end
171
171
172 def test_create_on_project_with_time_tracking_disabled_should_fail
172 def test_create_on_project_with_time_tracking_disabled_should_fail
173 Project.find(1).disable_module! :time_tracking
173 Project.find(1).disable_module! :time_tracking
174
174
175 @request.session[:user_id] = 2
175 @request.session[:user_id] = 2
176 assert_no_difference 'TimeEntry.count' do
176 assert_no_difference 'TimeEntry.count' do
177 post :create, :time_entry => {
177 post :create, :time_entry => {
178 :project_id => '1', :issue_id => '',
178 :project_id => '1', :issue_id => '',
179 :activity_id => '11', :spent_on => '2008-03-14', :hours => '7.3'
179 :activity_id => '11', :spent_on => '2008-03-14', :hours => '7.3'
180 }
180 }
181 end
181 end
182 end
182 end
183
183
184 def test_create_on_project_without_permission_should_fail
184 def test_create_on_project_without_permission_should_fail
185 Role.find(1).remove_permission! :log_time
185 Role.find(1).remove_permission! :log_time
186
186
187 @request.session[:user_id] = 2
187 @request.session[:user_id] = 2
188 assert_no_difference 'TimeEntry.count' do
188 assert_no_difference 'TimeEntry.count' do
189 post :create, :time_entry => {
189 post :create, :time_entry => {
190 :project_id => '1', :issue_id => '',
190 :project_id => '1', :issue_id => '',
191 :activity_id => '11', :spent_on => '2008-03-14', :hours => '7.3'
191 :activity_id => '11', :spent_on => '2008-03-14', :hours => '7.3'
192 }
192 }
193 end
193 end
194 end
194 end
195
195
196 def test_create_on_issue_in_project_with_time_tracking_disabled_should_fail
196 def test_create_on_issue_in_project_with_time_tracking_disabled_should_fail
197 Project.find(1).disable_module! :time_tracking
197 Project.find(1).disable_module! :time_tracking
198
198
199 @request.session[:user_id] = 2
199 @request.session[:user_id] = 2
200 assert_no_difference 'TimeEntry.count' do
200 assert_no_difference 'TimeEntry.count' do
201 post :create, :time_entry => {
201 post :create, :time_entry => {
202 :project_id => '', :issue_id => '1',
202 :project_id => '', :issue_id => '1',
203 :activity_id => '11', :spent_on => '2008-03-14', :hours => '7.3'
203 :activity_id => '11', :spent_on => '2008-03-14', :hours => '7.3'
204 }
204 }
205 assert_select_error /Issue is invalid/
205 assert_select_error /Issue is invalid/
206 end
206 end
207 end
207 end
208
208
209 def test_create_on_issue_in_project_without_permission_should_fail
209 def test_create_on_issue_in_project_without_permission_should_fail
210 Role.find(1).remove_permission! :log_time
210 Role.find(1).remove_permission! :log_time
211
211
212 @request.session[:user_id] = 2
212 @request.session[:user_id] = 2
213 assert_no_difference 'TimeEntry.count' do
213 assert_no_difference 'TimeEntry.count' do
214 post :create, :time_entry => {
214 post :create, :time_entry => {
215 :project_id => '', :issue_id => '1',
215 :project_id => '', :issue_id => '1',
216 :activity_id => '11', :spent_on => '2008-03-14', :hours => '7.3'
216 :activity_id => '11', :spent_on => '2008-03-14', :hours => '7.3'
217 }
217 }
218 assert_select_error /Issue is invalid/
218 assert_select_error /Issue is invalid/
219 end
219 end
220 end
220 end
221
221
222 def test_create_on_issue_that_is_not_visible_should_not_disclose_subject
223 issue = Issue.generate!(:subject => "issue_that_is_not_visible", :is_private => true)
224 assert !issue.visible?(User.find(3))
225
226 @request.session[:user_id] = 3
227 assert_no_difference 'TimeEntry.count' do
228 post :create, :time_entry => {
229 :project_id => '', :issue_id => issue.id.to_s,
230 :activity_id => '11', :spent_on => '2008-03-14', :hours => '7.3'
231 }
232 end
233 assert_select_error /Issue is invalid/
234 assert_select "input[name=?][value=?]", "time_entry[issue_id]", issue.id.to_s
235 assert_select "#time_entry_issue", 0
236 assert !response.body.include?('issue_that_is_not_visible')
237 end
238
222 def test_create_and_continue_at_project_level
239 def test_create_and_continue_at_project_level
223 @request.session[:user_id] = 2
240 @request.session[:user_id] = 2
224 assert_difference 'TimeEntry.count' do
241 assert_difference 'TimeEntry.count' do
225 post :create, :time_entry => {:project_id => '1',
242 post :create, :time_entry => {:project_id => '1',
226 :activity_id => '11',
243 :activity_id => '11',
227 :issue_id => '',
244 :issue_id => '',
228 :spent_on => '2008-03-14',
245 :spent_on => '2008-03-14',
229 :hours => '7.3'},
246 :hours => '7.3'},
230 :continue => '1'
247 :continue => '1'
231 assert_redirected_to '/time_entries/new?time_entry%5Bactivity_id%5D=11&time_entry%5Bissue_id%5D=&time_entry%5Bproject_id%5D=1'
248 assert_redirected_to '/time_entries/new?time_entry%5Bactivity_id%5D=11&time_entry%5Bissue_id%5D=&time_entry%5Bproject_id%5D=1'
232 end
249 end
233 end
250 end
234
251
235 def test_create_and_continue_at_issue_level
252 def test_create_and_continue_at_issue_level
236 @request.session[:user_id] = 2
253 @request.session[:user_id] = 2
237 assert_difference 'TimeEntry.count' do
254 assert_difference 'TimeEntry.count' do
238 post :create, :time_entry => {:project_id => '',
255 post :create, :time_entry => {:project_id => '',
239 :activity_id => '11',
256 :activity_id => '11',
240 :issue_id => '1',
257 :issue_id => '1',
241 :spent_on => '2008-03-14',
258 :spent_on => '2008-03-14',
242 :hours => '7.3'},
259 :hours => '7.3'},
243 :continue => '1'
260 :continue => '1'
244 assert_redirected_to '/time_entries/new?time_entry%5Bactivity_id%5D=11&time_entry%5Bissue_id%5D=1&time_entry%5Bproject_id%5D='
261 assert_redirected_to '/time_entries/new?time_entry%5Bactivity_id%5D=11&time_entry%5Bissue_id%5D=1&time_entry%5Bproject_id%5D='
245 end
262 end
246 end
263 end
247
264
248 def test_create_and_continue_with_project_id
265 def test_create_and_continue_with_project_id
249 @request.session[:user_id] = 2
266 @request.session[:user_id] = 2
250 assert_difference 'TimeEntry.count' do
267 assert_difference 'TimeEntry.count' do
251 post :create, :project_id => 1,
268 post :create, :project_id => 1,
252 :time_entry => {:activity_id => '11',
269 :time_entry => {:activity_id => '11',
253 :issue_id => '',
270 :issue_id => '',
254 :spent_on => '2008-03-14',
271 :spent_on => '2008-03-14',
255 :hours => '7.3'},
272 :hours => '7.3'},
256 :continue => '1'
273 :continue => '1'
257 assert_redirected_to '/projects/ecookbook/time_entries/new?time_entry%5Bactivity_id%5D=11&time_entry%5Bissue_id%5D=&time_entry%5Bproject_id%5D='
274 assert_redirected_to '/projects/ecookbook/time_entries/new?time_entry%5Bactivity_id%5D=11&time_entry%5Bissue_id%5D=&time_entry%5Bproject_id%5D='
258 end
275 end
259 end
276 end
260
277
261 def test_create_and_continue_with_issue_id
278 def test_create_and_continue_with_issue_id
262 @request.session[:user_id] = 2
279 @request.session[:user_id] = 2
263 assert_difference 'TimeEntry.count' do
280 assert_difference 'TimeEntry.count' do
264 post :create, :issue_id => 1,
281 post :create, :issue_id => 1,
265 :time_entry => {:activity_id => '11',
282 :time_entry => {:activity_id => '11',
266 :issue_id => '1',
283 :issue_id => '1',
267 :spent_on => '2008-03-14',
284 :spent_on => '2008-03-14',
268 :hours => '7.3'},
285 :hours => '7.3'},
269 :continue => '1'
286 :continue => '1'
270 assert_redirected_to '/issues/1/time_entries/new?time_entry%5Bactivity_id%5D=11&time_entry%5Bissue_id%5D=1&time_entry%5Bproject_id%5D='
287 assert_redirected_to '/issues/1/time_entries/new?time_entry%5Bactivity_id%5D=11&time_entry%5Bissue_id%5D=1&time_entry%5Bproject_id%5D='
271 end
288 end
272 end
289 end
273
290
274 def test_create_without_log_time_permission_should_be_denied
291 def test_create_without_log_time_permission_should_be_denied
275 @request.session[:user_id] = 2
292 @request.session[:user_id] = 2
276 Role.find_by_name('Manager').remove_permission! :log_time
293 Role.find_by_name('Manager').remove_permission! :log_time
277 post :create, :project_id => 1,
294 post :create, :project_id => 1,
278 :time_entry => {:activity_id => '11',
295 :time_entry => {:activity_id => '11',
279 :issue_id => '',
296 :issue_id => '',
280 :spent_on => '2008-03-14',
297 :spent_on => '2008-03-14',
281 :hours => '7.3'}
298 :hours => '7.3'}
282
299
283 assert_response 403
300 assert_response 403
284 end
301 end
285
302
286 def test_create_without_project_and_issue_should_fail
303 def test_create_without_project_and_issue_should_fail
287 @request.session[:user_id] = 2
304 @request.session[:user_id] = 2
288 post :create, :time_entry => {:issue_id => ''}
305 post :create, :time_entry => {:issue_id => ''}
289
306
290 assert_response :success
307 assert_response :success
291 assert_template 'new'
308 assert_template 'new'
292 end
309 end
293
310
294 def test_create_with_failure
311 def test_create_with_failure
295 @request.session[:user_id] = 2
312 @request.session[:user_id] = 2
296 post :create, :project_id => 1,
313 post :create, :project_id => 1,
297 :time_entry => {:activity_id => '',
314 :time_entry => {:activity_id => '',
298 :issue_id => '',
315 :issue_id => '',
299 :spent_on => '2008-03-14',
316 :spent_on => '2008-03-14',
300 :hours => '7.3'}
317 :hours => '7.3'}
301
318
302 assert_response :success
319 assert_response :success
303 assert_template 'new'
320 assert_template 'new'
304 end
321 end
305
322
306 def test_create_without_project
323 def test_create_without_project
307 @request.session[:user_id] = 2
324 @request.session[:user_id] = 2
308 assert_difference 'TimeEntry.count' do
325 assert_difference 'TimeEntry.count' do
309 post :create, :time_entry => {:project_id => '1',
326 post :create, :time_entry => {:project_id => '1',
310 :activity_id => '11',
327 :activity_id => '11',
311 :issue_id => '',
328 :issue_id => '',
312 :spent_on => '2008-03-14',
329 :spent_on => '2008-03-14',
313 :hours => '7.3'}
330 :hours => '7.3'}
314 end
331 end
315
332
316 assert_redirected_to '/projects/ecookbook/time_entries'
333 assert_redirected_to '/projects/ecookbook/time_entries'
317 time_entry = TimeEntry.order('id DESC').first
334 time_entry = TimeEntry.order('id DESC').first
318 assert_equal 1, time_entry.project_id
335 assert_equal 1, time_entry.project_id
319 end
336 end
320
337
321 def test_create_without_project_should_fail_with_issue_not_inside_project
338 def test_create_without_project_should_fail_with_issue_not_inside_project
322 @request.session[:user_id] = 2
339 @request.session[:user_id] = 2
323 assert_no_difference 'TimeEntry.count' do
340 assert_no_difference 'TimeEntry.count' do
324 post :create, :time_entry => {:project_id => '1',
341 post :create, :time_entry => {:project_id => '1',
325 :activity_id => '11',
342 :activity_id => '11',
326 :issue_id => '5',
343 :issue_id => '5',
327 :spent_on => '2008-03-14',
344 :spent_on => '2008-03-14',
328 :hours => '7.3'}
345 :hours => '7.3'}
329 end
346 end
330
347
331 assert_response :success
348 assert_response :success
332 assert assigns(:time_entry).errors[:issue_id].present?
349 assert assigns(:time_entry).errors[:issue_id].present?
333 end
350 end
334
351
335 def test_create_without_project_should_deny_without_permission
352 def test_create_without_project_should_deny_without_permission
336 @request.session[:user_id] = 2
353 @request.session[:user_id] = 2
337 Project.find(3).disable_module!(:time_tracking)
354 Project.find(3).disable_module!(:time_tracking)
338
355
339 assert_no_difference 'TimeEntry.count' do
356 assert_no_difference 'TimeEntry.count' do
340 post :create, :time_entry => {:project_id => '3',
357 post :create, :time_entry => {:project_id => '3',
341 :activity_id => '11',
358 :activity_id => '11',
342 :issue_id => '',
359 :issue_id => '',
343 :spent_on => '2008-03-14',
360 :spent_on => '2008-03-14',
344 :hours => '7.3'}
361 :hours => '7.3'}
345 end
362 end
346
363
347 assert_response 403
364 assert_response 403
348 end
365 end
349
366
350 def test_create_without_project_with_failure
367 def test_create_without_project_with_failure
351 @request.session[:user_id] = 2
368 @request.session[:user_id] = 2
352 assert_no_difference 'TimeEntry.count' do
369 assert_no_difference 'TimeEntry.count' do
353 post :create, :time_entry => {:project_id => '1',
370 post :create, :time_entry => {:project_id => '1',
354 :activity_id => '11',
371 :activity_id => '11',
355 :issue_id => '',
372 :issue_id => '',
356 :spent_on => '2008-03-14',
373 :spent_on => '2008-03-14',
357 :hours => ''}
374 :hours => ''}
358 end
375 end
359
376
360 assert_response :success
377 assert_response :success
361 assert_select 'select[name=?]', 'time_entry[project_id]' do
378 assert_select 'select[name=?]', 'time_entry[project_id]' do
362 assert_select 'option[value="1"][selected=selected]'
379 assert_select 'option[value="1"][selected=selected]'
363 end
380 end
364 end
381 end
365
382
366 def test_update
383 def test_update
367 entry = TimeEntry.find(1)
384 entry = TimeEntry.find(1)
368 assert_equal 1, entry.issue_id
385 assert_equal 1, entry.issue_id
369 assert_equal 2, entry.user_id
386 assert_equal 2, entry.user_id
370
387
371 @request.session[:user_id] = 1
388 @request.session[:user_id] = 1
372 put :update, :id => 1,
389 put :update, :id => 1,
373 :time_entry => {:issue_id => '2',
390 :time_entry => {:issue_id => '2',
374 :hours => '8'}
391 :hours => '8'}
375 assert_redirected_to :action => 'index', :project_id => 'ecookbook'
392 assert_redirected_to :action => 'index', :project_id => 'ecookbook'
376 entry.reload
393 entry.reload
377
394
378 assert_equal 8, entry.hours
395 assert_equal 8, entry.hours
379 assert_equal 2, entry.issue_id
396 assert_equal 2, entry.issue_id
380 assert_equal 2, entry.user_id
397 assert_equal 2, entry.user_id
381 end
398 end
382
399
383 def test_update_should_allow_to_change_issue_to_another_project
400 def test_update_should_allow_to_change_issue_to_another_project
384 entry = TimeEntry.generate!(:issue_id => 1)
401 entry = TimeEntry.generate!(:issue_id => 1)
385
402
386 @request.session[:user_id] = 1
403 @request.session[:user_id] = 1
387 put :update, :id => entry.id, :time_entry => {:issue_id => '5'}
404 put :update, :id => entry.id, :time_entry => {:issue_id => '5'}
388 assert_response 302
405 assert_response 302
389 entry.reload
406 entry.reload
390
407
391 assert_equal 5, entry.issue_id
408 assert_equal 5, entry.issue_id
392 assert_equal 3, entry.project_id
409 assert_equal 3, entry.project_id
393 end
410 end
394
411
395 def test_update_should_not_allow_to_change_issue_to_an_invalid_project
412 def test_update_should_not_allow_to_change_issue_to_an_invalid_project
396 entry = TimeEntry.generate!(:issue_id => 1)
413 entry = TimeEntry.generate!(:issue_id => 1)
397 Project.find(3).disable_module!(:time_tracking)
414 Project.find(3).disable_module!(:time_tracking)
398
415
399 @request.session[:user_id] = 1
416 @request.session[:user_id] = 1
400 put :update, :id => entry.id, :time_entry => {:issue_id => '5'}
417 put :update, :id => entry.id, :time_entry => {:issue_id => '5'}
401 assert_response 200
418 assert_response 200
402 assert_include "Issue is invalid", assigns(:time_entry).errors.full_messages
419 assert_include "Issue is invalid", assigns(:time_entry).errors.full_messages
403 end
420 end
404
421
405 def test_get_bulk_edit
422 def test_get_bulk_edit
406 @request.session[:user_id] = 2
423 @request.session[:user_id] = 2
407 get :bulk_edit, :ids => [1, 2]
424 get :bulk_edit, :ids => [1, 2]
408 assert_response :success
425 assert_response :success
409 assert_template 'bulk_edit'
426 assert_template 'bulk_edit'
410
427
411 assert_select 'ul#bulk-selection' do
428 assert_select 'ul#bulk-selection' do
412 assert_select 'li', 2
429 assert_select 'li', 2
413 assert_select 'li a', :text => '03/23/2007 - eCookbook: 4.25 hours'
430 assert_select 'li a', :text => '03/23/2007 - eCookbook: 4.25 hours'
414 end
431 end
415
432
416 assert_select 'form#bulk_edit_form[action=?]', '/time_entries/bulk_update' do
433 assert_select 'form#bulk_edit_form[action=?]', '/time_entries/bulk_update' do
417 # System wide custom field
434 # System wide custom field
418 assert_select 'select[name=?]', 'time_entry[custom_field_values][10]'
435 assert_select 'select[name=?]', 'time_entry[custom_field_values][10]'
419
436
420 # Activities
437 # Activities
421 assert_select 'select[name=?]', 'time_entry[activity_id]' do
438 assert_select 'select[name=?]', 'time_entry[activity_id]' do
422 assert_select 'option[value=""]', :text => '(No change)'
439 assert_select 'option[value=""]', :text => '(No change)'
423 assert_select 'option[value="9"]', :text => 'Design'
440 assert_select 'option[value="9"]', :text => 'Design'
424 end
441 end
425 end
442 end
426 end
443 end
427
444
428 def test_get_bulk_edit_on_different_projects
445 def test_get_bulk_edit_on_different_projects
429 @request.session[:user_id] = 2
446 @request.session[:user_id] = 2
430 get :bulk_edit, :ids => [1, 2, 6]
447 get :bulk_edit, :ids => [1, 2, 6]
431 assert_response :success
448 assert_response :success
432 assert_template 'bulk_edit'
449 assert_template 'bulk_edit'
433 end
450 end
434
451
435 def test_bulk_edit_with_edit_own_time_entries_permission
452 def test_bulk_edit_with_edit_own_time_entries_permission
436 @request.session[:user_id] = 2
453 @request.session[:user_id] = 2
437 Role.find_by_name('Manager').remove_permission! :edit_time_entries
454 Role.find_by_name('Manager').remove_permission! :edit_time_entries
438 Role.find_by_name('Manager').add_permission! :edit_own_time_entries
455 Role.find_by_name('Manager').add_permission! :edit_own_time_entries
439 ids = (0..1).map {TimeEntry.generate!(:user => User.find(2)).id}
456 ids = (0..1).map {TimeEntry.generate!(:user => User.find(2)).id}
440
457
441 get :bulk_edit, :ids => ids
458 get :bulk_edit, :ids => ids
442 assert_response :success
459 assert_response :success
443 end
460 end
444
461
445 def test_bulk_update
462 def test_bulk_update
446 @request.session[:user_id] = 2
463 @request.session[:user_id] = 2
447 # update time entry activity
464 # update time entry activity
448 post :bulk_update, :ids => [1, 2], :time_entry => { :activity_id => 9}
465 post :bulk_update, :ids => [1, 2], :time_entry => { :activity_id => 9}
449
466
450 assert_response 302
467 assert_response 302
451 # check that the issues were updated
468 # check that the issues were updated
452 assert_equal [9, 9], TimeEntry.where(:id => [1, 2]).collect {|i| i.activity_id}
469 assert_equal [9, 9], TimeEntry.where(:id => [1, 2]).collect {|i| i.activity_id}
453 end
470 end
454
471
455 def test_bulk_update_with_failure
472 def test_bulk_update_with_failure
456 @request.session[:user_id] = 2
473 @request.session[:user_id] = 2
457 post :bulk_update, :ids => [1, 2], :time_entry => { :hours => 'A'}
474 post :bulk_update, :ids => [1, 2], :time_entry => { :hours => 'A'}
458
475
459 assert_response 302
476 assert_response 302
460 assert_match /Failed to save 2 time entrie/, flash[:error]
477 assert_match /Failed to save 2 time entrie/, flash[:error]
461 end
478 end
462
479
463 def test_bulk_update_on_different_projects
480 def test_bulk_update_on_different_projects
464 @request.session[:user_id] = 2
481 @request.session[:user_id] = 2
465 # makes user a manager on the other project
482 # makes user a manager on the other project
466 Member.create!(:user_id => 2, :project_id => 3, :role_ids => [1])
483 Member.create!(:user_id => 2, :project_id => 3, :role_ids => [1])
467
484
468 # update time entry activity
485 # update time entry activity
469 post :bulk_update, :ids => [1, 2, 4], :time_entry => { :activity_id => 9 }
486 post :bulk_update, :ids => [1, 2, 4], :time_entry => { :activity_id => 9 }
470
487
471 assert_response 302
488 assert_response 302
472 # check that the issues were updated
489 # check that the issues were updated
473 assert_equal [9, 9, 9], TimeEntry.where(:id => [1, 2, 4]).collect {|i| i.activity_id}
490 assert_equal [9, 9, 9], TimeEntry.where(:id => [1, 2, 4]).collect {|i| i.activity_id}
474 end
491 end
475
492
476 def test_bulk_update_on_different_projects_without_rights
493 def test_bulk_update_on_different_projects_without_rights
477 @request.session[:user_id] = 3
494 @request.session[:user_id] = 3
478 user = User.find(3)
495 user = User.find(3)
479 action = { :controller => "timelog", :action => "bulk_update" }
496 action = { :controller => "timelog", :action => "bulk_update" }
480 assert user.allowed_to?(action, TimeEntry.find(1).project)
497 assert user.allowed_to?(action, TimeEntry.find(1).project)
481 assert ! user.allowed_to?(action, TimeEntry.find(5).project)
498 assert ! user.allowed_to?(action, TimeEntry.find(5).project)
482 post :bulk_update, :ids => [1, 5], :time_entry => { :activity_id => 9 }
499 post :bulk_update, :ids => [1, 5], :time_entry => { :activity_id => 9 }
483 assert_response 403
500 assert_response 403
484 end
501 end
485
502
486 def test_bulk_update_with_edit_own_time_entries_permission
503 def test_bulk_update_with_edit_own_time_entries_permission
487 @request.session[:user_id] = 2
504 @request.session[:user_id] = 2
488 Role.find_by_name('Manager').remove_permission! :edit_time_entries
505 Role.find_by_name('Manager').remove_permission! :edit_time_entries
489 Role.find_by_name('Manager').add_permission! :edit_own_time_entries
506 Role.find_by_name('Manager').add_permission! :edit_own_time_entries
490 ids = (0..1).map {TimeEntry.generate!(:user => User.find(2)).id}
507 ids = (0..1).map {TimeEntry.generate!(:user => User.find(2)).id}
491
508
492 post :bulk_update, :ids => ids, :time_entry => { :activity_id => 9 }
509 post :bulk_update, :ids => ids, :time_entry => { :activity_id => 9 }
493 assert_response 302
510 assert_response 302
494 end
511 end
495
512
496 def test_bulk_update_with_edit_own_time_entries_permissions_should_be_denied_for_time_entries_of_other_user
513 def test_bulk_update_with_edit_own_time_entries_permissions_should_be_denied_for_time_entries_of_other_user
497 @request.session[:user_id] = 2
514 @request.session[:user_id] = 2
498 Role.find_by_name('Manager').remove_permission! :edit_time_entries
515 Role.find_by_name('Manager').remove_permission! :edit_time_entries
499 Role.find_by_name('Manager').add_permission! :edit_own_time_entries
516 Role.find_by_name('Manager').add_permission! :edit_own_time_entries
500
517
501 post :bulk_update, :ids => [1, 2], :time_entry => { :activity_id => 9 }
518 post :bulk_update, :ids => [1, 2], :time_entry => { :activity_id => 9 }
502 assert_response 403
519 assert_response 403
503 end
520 end
504
521
505 def test_bulk_update_custom_field
522 def test_bulk_update_custom_field
506 @request.session[:user_id] = 2
523 @request.session[:user_id] = 2
507 post :bulk_update, :ids => [1, 2], :time_entry => { :custom_field_values => {'10' => '0'} }
524 post :bulk_update, :ids => [1, 2], :time_entry => { :custom_field_values => {'10' => '0'} }
508
525
509 assert_response 302
526 assert_response 302
510 assert_equal ["0", "0"], TimeEntry.where(:id => [1, 2]).collect {|i| i.custom_value_for(10).value}
527 assert_equal ["0", "0"], TimeEntry.where(:id => [1, 2]).collect {|i| i.custom_value_for(10).value}
511 end
528 end
512
529
513 def test_post_bulk_update_should_redirect_back_using_the_back_url_parameter
530 def test_post_bulk_update_should_redirect_back_using_the_back_url_parameter
514 @request.session[:user_id] = 2
531 @request.session[:user_id] = 2
515 post :bulk_update, :ids => [1,2], :back_url => '/time_entries'
532 post :bulk_update, :ids => [1,2], :back_url => '/time_entries'
516
533
517 assert_response :redirect
534 assert_response :redirect
518 assert_redirected_to '/time_entries'
535 assert_redirected_to '/time_entries'
519 end
536 end
520
537
521 def test_post_bulk_update_should_not_redirect_back_using_the_back_url_parameter_off_the_host
538 def test_post_bulk_update_should_not_redirect_back_using_the_back_url_parameter_off_the_host
522 @request.session[:user_id] = 2
539 @request.session[:user_id] = 2
523 post :bulk_update, :ids => [1,2], :back_url => 'http://google.com'
540 post :bulk_update, :ids => [1,2], :back_url => 'http://google.com'
524
541
525 assert_response :redirect
542 assert_response :redirect
526 assert_redirected_to :controller => 'timelog', :action => 'index', :project_id => Project.find(1).identifier
543 assert_redirected_to :controller => 'timelog', :action => 'index', :project_id => Project.find(1).identifier
527 end
544 end
528
545
529 def test_post_bulk_update_without_edit_permission_should_be_denied
546 def test_post_bulk_update_without_edit_permission_should_be_denied
530 @request.session[:user_id] = 2
547 @request.session[:user_id] = 2
531 Role.find_by_name('Manager').remove_permission! :edit_time_entries
548 Role.find_by_name('Manager').remove_permission! :edit_time_entries
532 post :bulk_update, :ids => [1,2]
549 post :bulk_update, :ids => [1,2]
533
550
534 assert_response 403
551 assert_response 403
535 end
552 end
536
553
537 def test_destroy
554 def test_destroy
538 @request.session[:user_id] = 2
555 @request.session[:user_id] = 2
539 delete :destroy, :id => 1
556 delete :destroy, :id => 1
540 assert_redirected_to :action => 'index', :project_id => 'ecookbook'
557 assert_redirected_to :action => 'index', :project_id => 'ecookbook'
541 assert_equal I18n.t(:notice_successful_delete), flash[:notice]
558 assert_equal I18n.t(:notice_successful_delete), flash[:notice]
542 assert_nil TimeEntry.find_by_id(1)
559 assert_nil TimeEntry.find_by_id(1)
543 end
560 end
544
561
545 def test_destroy_should_fail
562 def test_destroy_should_fail
546 # simulate that this fails (e.g. due to a plugin), see #5700
563 # simulate that this fails (e.g. due to a plugin), see #5700
547 TimeEntry.any_instance.expects(:destroy).returns(false)
564 TimeEntry.any_instance.expects(:destroy).returns(false)
548
565
549 @request.session[:user_id] = 2
566 @request.session[:user_id] = 2
550 delete :destroy, :id => 1
567 delete :destroy, :id => 1
551 assert_redirected_to :action => 'index', :project_id => 'ecookbook'
568 assert_redirected_to :action => 'index', :project_id => 'ecookbook'
552 assert_equal I18n.t(:notice_unable_delete_time_entry), flash[:error]
569 assert_equal I18n.t(:notice_unable_delete_time_entry), flash[:error]
553 assert_not_nil TimeEntry.find_by_id(1)
570 assert_not_nil TimeEntry.find_by_id(1)
554 end
571 end
555
572
556 def test_index_all_projects
573 def test_index_all_projects
557 get :index
574 get :index
558 assert_response :success
575 assert_response :success
559 assert_template 'index'
576 assert_template 'index'
560 assert_not_nil assigns(:total_hours)
577 assert_not_nil assigns(:total_hours)
561 assert_equal "162.90", "%.2f" % assigns(:total_hours)
578 assert_equal "162.90", "%.2f" % assigns(:total_hours)
562 assert_select 'form#query_form[action=?]', '/time_entries'
579 assert_select 'form#query_form[action=?]', '/time_entries'
563 end
580 end
564
581
565 def test_index_all_projects_should_show_log_time_link
582 def test_index_all_projects_should_show_log_time_link
566 @request.session[:user_id] = 2
583 @request.session[:user_id] = 2
567 get :index
584 get :index
568 assert_response :success
585 assert_response :success
569 assert_template 'index'
586 assert_template 'index'
570 assert_select 'a[href=?]', '/time_entries/new', :text => /Log time/
587 assert_select 'a[href=?]', '/time_entries/new', :text => /Log time/
571 end
588 end
572
589
573 def test_index_my_spent_time
590 def test_index_my_spent_time
574 @request.session[:user_id] = 2
591 @request.session[:user_id] = 2
575 get :index, :user_id => 'me'
592 get :index, :user_id => 'me'
576 assert_response :success
593 assert_response :success
577 assert_template 'index'
594 assert_template 'index'
578 assert assigns(:entries).all? {|entry| entry.user_id == 2}
595 assert assigns(:entries).all? {|entry| entry.user_id == 2}
579 end
596 end
580
597
581 def test_index_at_project_level
598 def test_index_at_project_level
582 get :index, :project_id => 'ecookbook'
599 get :index, :project_id => 'ecookbook'
583 assert_response :success
600 assert_response :success
584 assert_template 'index'
601 assert_template 'index'
585 assert_not_nil assigns(:entries)
602 assert_not_nil assigns(:entries)
586 assert_equal 4, assigns(:entries).size
603 assert_equal 4, assigns(:entries).size
587 # project and subproject
604 # project and subproject
588 assert_equal [1, 3], assigns(:entries).collect(&:project_id).uniq.sort
605 assert_equal [1, 3], assigns(:entries).collect(&:project_id).uniq.sort
589 assert_not_nil assigns(:total_hours)
606 assert_not_nil assigns(:total_hours)
590 assert_equal "162.90", "%.2f" % assigns(:total_hours)
607 assert_equal "162.90", "%.2f" % assigns(:total_hours)
591 assert_select 'form#query_form[action=?]', '/projects/ecookbook/time_entries'
608 assert_select 'form#query_form[action=?]', '/projects/ecookbook/time_entries'
592 end
609 end
593
610
594 def test_index_with_display_subprojects_issues_to_false_should_not_include_subproject_entries
611 def test_index_with_display_subprojects_issues_to_false_should_not_include_subproject_entries
595 entry = TimeEntry.generate!(:project => Project.find(3))
612 entry = TimeEntry.generate!(:project => Project.find(3))
596
613
597 with_settings :display_subprojects_issues => '0' do
614 with_settings :display_subprojects_issues => '0' do
598 get :index, :project_id => 'ecookbook'
615 get :index, :project_id => 'ecookbook'
599 assert_response :success
616 assert_response :success
600 assert_template 'index'
617 assert_template 'index'
601 assert_not_include entry, assigns(:entries)
618 assert_not_include entry, assigns(:entries)
602 end
619 end
603 end
620 end
604
621
605 def test_index_with_display_subprojects_issues_to_false_and_subproject_filter_should_include_subproject_entries
622 def test_index_with_display_subprojects_issues_to_false_and_subproject_filter_should_include_subproject_entries
606 entry = TimeEntry.generate!(:project => Project.find(3))
623 entry = TimeEntry.generate!(:project => Project.find(3))
607
624
608 with_settings :display_subprojects_issues => '0' do
625 with_settings :display_subprojects_issues => '0' do
609 get :index, :project_id => 'ecookbook', :subproject_id => 3
626 get :index, :project_id => 'ecookbook', :subproject_id => 3
610 assert_response :success
627 assert_response :success
611 assert_template 'index'
628 assert_template 'index'
612 assert_include entry, assigns(:entries)
629 assert_include entry, assigns(:entries)
613 end
630 end
614 end
631 end
615
632
616 def test_index_at_project_level_with_date_range
633 def test_index_at_project_level_with_date_range
617 get :index, :project_id => 'ecookbook',
634 get :index, :project_id => 'ecookbook',
618 :f => ['spent_on'],
635 :f => ['spent_on'],
619 :op => {'spent_on' => '><'},
636 :op => {'spent_on' => '><'},
620 :v => {'spent_on' => ['2007-03-20', '2007-04-30']}
637 :v => {'spent_on' => ['2007-03-20', '2007-04-30']}
621 assert_response :success
638 assert_response :success
622 assert_template 'index'
639 assert_template 'index'
623 assert_not_nil assigns(:entries)
640 assert_not_nil assigns(:entries)
624 assert_equal 3, assigns(:entries).size
641 assert_equal 3, assigns(:entries).size
625 assert_not_nil assigns(:total_hours)
642 assert_not_nil assigns(:total_hours)
626 assert_equal "12.90", "%.2f" % assigns(:total_hours)
643 assert_equal "12.90", "%.2f" % assigns(:total_hours)
627 assert_select 'form#query_form[action=?]', '/projects/ecookbook/time_entries'
644 assert_select 'form#query_form[action=?]', '/projects/ecookbook/time_entries'
628 end
645 end
629
646
630 def test_index_at_project_level_with_date_range_using_from_and_to_params
647 def test_index_at_project_level_with_date_range_using_from_and_to_params
631 get :index, :project_id => 'ecookbook', :from => '2007-03-20', :to => '2007-04-30'
648 get :index, :project_id => 'ecookbook', :from => '2007-03-20', :to => '2007-04-30'
632 assert_response :success
649 assert_response :success
633 assert_template 'index'
650 assert_template 'index'
634 assert_not_nil assigns(:entries)
651 assert_not_nil assigns(:entries)
635 assert_equal 3, assigns(:entries).size
652 assert_equal 3, assigns(:entries).size
636 assert_not_nil assigns(:total_hours)
653 assert_not_nil assigns(:total_hours)
637 assert_equal "12.90", "%.2f" % assigns(:total_hours)
654 assert_equal "12.90", "%.2f" % assigns(:total_hours)
638 assert_select 'form#query_form[action=?]', '/projects/ecookbook/time_entries'
655 assert_select 'form#query_form[action=?]', '/projects/ecookbook/time_entries'
639 end
656 end
640
657
641 def test_index_at_project_level_with_period
658 def test_index_at_project_level_with_period
642 get :index, :project_id => 'ecookbook',
659 get :index, :project_id => 'ecookbook',
643 :f => ['spent_on'],
660 :f => ['spent_on'],
644 :op => {'spent_on' => '>t-'},
661 :op => {'spent_on' => '>t-'},
645 :v => {'spent_on' => ['7']}
662 :v => {'spent_on' => ['7']}
646 assert_response :success
663 assert_response :success
647 assert_template 'index'
664 assert_template 'index'
648 assert_not_nil assigns(:entries)
665 assert_not_nil assigns(:entries)
649 assert_not_nil assigns(:total_hours)
666 assert_not_nil assigns(:total_hours)
650 assert_select 'form#query_form[action=?]', '/projects/ecookbook/time_entries'
667 assert_select 'form#query_form[action=?]', '/projects/ecookbook/time_entries'
651 end
668 end
652
669
653 def test_index_at_issue_level
670 def test_index_at_issue_level
654 get :index, :issue_id => 1
671 get :index, :issue_id => 1
655 assert_response :success
672 assert_response :success
656 assert_template 'index'
673 assert_template 'index'
657 assert_not_nil assigns(:entries)
674 assert_not_nil assigns(:entries)
658 assert_equal 2, assigns(:entries).size
675 assert_equal 2, assigns(:entries).size
659 assert_not_nil assigns(:total_hours)
676 assert_not_nil assigns(:total_hours)
660 assert_equal 154.25, assigns(:total_hours)
677 assert_equal 154.25, assigns(:total_hours)
661 # display all time
678 # display all time
662 assert_nil assigns(:from)
679 assert_nil assigns(:from)
663 assert_nil assigns(:to)
680 assert_nil assigns(:to)
664 assert_select 'form#query_form[action=?]', '/issues/1/time_entries'
681 assert_select 'form#query_form[action=?]', '/issues/1/time_entries'
665 end
682 end
666
683
667 def test_index_should_sort_by_spent_on_and_created_on
684 def test_index_should_sort_by_spent_on_and_created_on
668 t1 = TimeEntry.create!(:user => User.find(1), :project => Project.find(1), :hours => 1, :spent_on => '2012-06-16', :created_on => '2012-06-16 20:00:00', :activity_id => 10)
685 t1 = TimeEntry.create!(:user => User.find(1), :project => Project.find(1), :hours => 1, :spent_on => '2012-06-16', :created_on => '2012-06-16 20:00:00', :activity_id => 10)
669 t2 = TimeEntry.create!(:user => User.find(1), :project => Project.find(1), :hours => 1, :spent_on => '2012-06-16', :created_on => '2012-06-16 20:05:00', :activity_id => 10)
686 t2 = TimeEntry.create!(:user => User.find(1), :project => Project.find(1), :hours => 1, :spent_on => '2012-06-16', :created_on => '2012-06-16 20:05:00', :activity_id => 10)
670 t3 = TimeEntry.create!(:user => User.find(1), :project => Project.find(1), :hours => 1, :spent_on => '2012-06-15', :created_on => '2012-06-16 20:10:00', :activity_id => 10)
687 t3 = TimeEntry.create!(:user => User.find(1), :project => Project.find(1), :hours => 1, :spent_on => '2012-06-15', :created_on => '2012-06-16 20:10:00', :activity_id => 10)
671
688
672 get :index, :project_id => 1,
689 get :index, :project_id => 1,
673 :f => ['spent_on'],
690 :f => ['spent_on'],
674 :op => {'spent_on' => '><'},
691 :op => {'spent_on' => '><'},
675 :v => {'spent_on' => ['2012-06-15', '2012-06-16']}
692 :v => {'spent_on' => ['2012-06-15', '2012-06-16']}
676 assert_response :success
693 assert_response :success
677 assert_equal [t2, t1, t3], assigns(:entries)
694 assert_equal [t2, t1, t3], assigns(:entries)
678
695
679 get :index, :project_id => 1,
696 get :index, :project_id => 1,
680 :f => ['spent_on'],
697 :f => ['spent_on'],
681 :op => {'spent_on' => '><'},
698 :op => {'spent_on' => '><'},
682 :v => {'spent_on' => ['2012-06-15', '2012-06-16']},
699 :v => {'spent_on' => ['2012-06-15', '2012-06-16']},
683 :sort => 'spent_on'
700 :sort => 'spent_on'
684 assert_response :success
701 assert_response :success
685 assert_equal [t3, t1, t2], assigns(:entries)
702 assert_equal [t3, t1, t2], assigns(:entries)
686 end
703 end
687
704
688 def test_index_with_filter_on_issue_custom_field
705 def test_index_with_filter_on_issue_custom_field
689 issue = Issue.generate!(:project_id => 1, :tracker_id => 1, :custom_field_values => {2 => 'filter_on_issue_custom_field'})
706 issue = Issue.generate!(:project_id => 1, :tracker_id => 1, :custom_field_values => {2 => 'filter_on_issue_custom_field'})
690 entry = TimeEntry.generate!(:issue => issue, :hours => 2.5)
707 entry = TimeEntry.generate!(:issue => issue, :hours => 2.5)
691
708
692 get :index, :f => ['issue.cf_2'], :op => {'issue.cf_2' => '='}, :v => {'issue.cf_2' => ['filter_on_issue_custom_field']}
709 get :index, :f => ['issue.cf_2'], :op => {'issue.cf_2' => '='}, :v => {'issue.cf_2' => ['filter_on_issue_custom_field']}
693 assert_response :success
710 assert_response :success
694 assert_equal [entry], assigns(:entries)
711 assert_equal [entry], assigns(:entries)
695 end
712 end
696
713
697 def test_index_with_issue_custom_field_column
714 def test_index_with_issue_custom_field_column
698 issue = Issue.generate!(:project_id => 1, :tracker_id => 1, :custom_field_values => {2 => 'filter_on_issue_custom_field'})
715 issue = Issue.generate!(:project_id => 1, :tracker_id => 1, :custom_field_values => {2 => 'filter_on_issue_custom_field'})
699 entry = TimeEntry.generate!(:issue => issue, :hours => 2.5)
716 entry = TimeEntry.generate!(:issue => issue, :hours => 2.5)
700
717
701 get :index, :c => %w(project spent_on issue comments hours issue.cf_2)
718 get :index, :c => %w(project spent_on issue comments hours issue.cf_2)
702 assert_response :success
719 assert_response :success
703 assert_include :'issue.cf_2', assigns(:query).column_names
720 assert_include :'issue.cf_2', assigns(:query).column_names
704 assert_select 'td.issue_cf_2', :text => 'filter_on_issue_custom_field'
721 assert_select 'td.issue_cf_2', :text => 'filter_on_issue_custom_field'
705 end
722 end
706
723
707 def test_index_with_time_entry_custom_field_column
724 def test_index_with_time_entry_custom_field_column
708 field = TimeEntryCustomField.generate!(:field_format => 'string')
725 field = TimeEntryCustomField.generate!(:field_format => 'string')
709 entry = TimeEntry.generate!(:hours => 2.5, :custom_field_values => {field.id => 'CF Value'})
726 entry = TimeEntry.generate!(:hours => 2.5, :custom_field_values => {field.id => 'CF Value'})
710 field_name = "cf_#{field.id}"
727 field_name = "cf_#{field.id}"
711
728
712 get :index, :c => ["hours", field_name]
729 get :index, :c => ["hours", field_name]
713 assert_response :success
730 assert_response :success
714 assert_include field_name.to_sym, assigns(:query).column_names
731 assert_include field_name.to_sym, assigns(:query).column_names
715 assert_select "td.#{field_name}", :text => 'CF Value'
732 assert_select "td.#{field_name}", :text => 'CF Value'
716 end
733 end
717
734
718 def test_index_with_time_entry_custom_field_sorting
735 def test_index_with_time_entry_custom_field_sorting
719 field = TimeEntryCustomField.generate!(:field_format => 'string', :name => 'String Field')
736 field = TimeEntryCustomField.generate!(:field_format => 'string', :name => 'String Field')
720 TimeEntry.generate!(:hours => 2.5, :custom_field_values => {field.id => 'CF Value 1'})
737 TimeEntry.generate!(:hours => 2.5, :custom_field_values => {field.id => 'CF Value 1'})
721 TimeEntry.generate!(:hours => 2.5, :custom_field_values => {field.id => 'CF Value 3'})
738 TimeEntry.generate!(:hours => 2.5, :custom_field_values => {field.id => 'CF Value 3'})
722 TimeEntry.generate!(:hours => 2.5, :custom_field_values => {field.id => 'CF Value 2'})
739 TimeEntry.generate!(:hours => 2.5, :custom_field_values => {field.id => 'CF Value 2'})
723 field_name = "cf_#{field.id}"
740 field_name = "cf_#{field.id}"
724
741
725 get :index, :c => ["hours", field_name], :sort => field_name
742 get :index, :c => ["hours", field_name], :sort => field_name
726 assert_response :success
743 assert_response :success
727 assert_include field_name.to_sym, assigns(:query).column_names
744 assert_include field_name.to_sym, assigns(:query).column_names
728 assert_select "th a.sort", :text => 'String Field'
745 assert_select "th a.sort", :text => 'String Field'
729
746
730 # Make sure that values are properly sorted
747 # Make sure that values are properly sorted
731 values = assigns(:entries).map {|e| e.custom_field_value(field)}.compact
748 values = assigns(:entries).map {|e| e.custom_field_value(field)}.compact
732 assert_equal 3, values.size
749 assert_equal 3, values.size
733 assert_equal values.sort, values
750 assert_equal values.sort, values
734 end
751 end
735
752
736 def test_index_atom_feed
753 def test_index_atom_feed
737 get :index, :project_id => 1, :format => 'atom'
754 get :index, :project_id => 1, :format => 'atom'
738 assert_response :success
755 assert_response :success
739 assert_equal 'application/atom+xml', @response.content_type
756 assert_equal 'application/atom+xml', @response.content_type
740 assert_not_nil assigns(:items)
757 assert_not_nil assigns(:items)
741 assert assigns(:items).first.is_a?(TimeEntry)
758 assert assigns(:items).first.is_a?(TimeEntry)
742 end
759 end
743
760
744 def test_index_at_project_level_should_include_csv_export_dialog
761 def test_index_at_project_level_should_include_csv_export_dialog
745 get :index, :project_id => 'ecookbook',
762 get :index, :project_id => 'ecookbook',
746 :f => ['spent_on'],
763 :f => ['spent_on'],
747 :op => {'spent_on' => '>='},
764 :op => {'spent_on' => '>='},
748 :v => {'spent_on' => ['2007-04-01']},
765 :v => {'spent_on' => ['2007-04-01']},
749 :c => ['spent_on', 'user']
766 :c => ['spent_on', 'user']
750 assert_response :success
767 assert_response :success
751
768
752 assert_select '#csv-export-options' do
769 assert_select '#csv-export-options' do
753 assert_select 'form[action=?][method=get]', '/projects/ecookbook/time_entries.csv' do
770 assert_select 'form[action=?][method=get]', '/projects/ecookbook/time_entries.csv' do
754 # filter
771 # filter
755 assert_select 'input[name=?][value=?]', 'f[]', 'spent_on'
772 assert_select 'input[name=?][value=?]', 'f[]', 'spent_on'
756 assert_select 'input[name=?][value=?]', 'op[spent_on]', '>='
773 assert_select 'input[name=?][value=?]', 'op[spent_on]', '>='
757 assert_select 'input[name=?][value=?]', 'v[spent_on][]', '2007-04-01'
774 assert_select 'input[name=?][value=?]', 'v[spent_on][]', '2007-04-01'
758 # columns
775 # columns
759 assert_select 'input[name=?][value=?]', 'c[]', 'spent_on'
776 assert_select 'input[name=?][value=?]', 'c[]', 'spent_on'
760 assert_select 'input[name=?][value=?]', 'c[]', 'user'
777 assert_select 'input[name=?][value=?]', 'c[]', 'user'
761 assert_select 'input[name=?]', 'c[]', 2
778 assert_select 'input[name=?]', 'c[]', 2
762 end
779 end
763 end
780 end
764 end
781 end
765
782
766 def test_index_cross_project_should_include_csv_export_dialog
783 def test_index_cross_project_should_include_csv_export_dialog
767 get :index
784 get :index
768 assert_response :success
785 assert_response :success
769
786
770 assert_select '#csv-export-options' do
787 assert_select '#csv-export-options' do
771 assert_select 'form[action=?][method=get]', '/time_entries.csv'
788 assert_select 'form[action=?][method=get]', '/time_entries.csv'
772 end
789 end
773 end
790 end
774
791
775 def test_index_at_issue_level_should_include_csv_export_dialog
792 def test_index_at_issue_level_should_include_csv_export_dialog
776 get :index, :issue_id => 3
793 get :index, :issue_id => 3
777 assert_response :success
794 assert_response :success
778
795
779 assert_select '#csv-export-options' do
796 assert_select '#csv-export-options' do
780 assert_select 'form[action=?][method=get]', '/issues/3/time_entries.csv'
797 assert_select 'form[action=?][method=get]', '/issues/3/time_entries.csv'
781 end
798 end
782 end
799 end
783
800
784 def test_index_csv_all_projects
801 def test_index_csv_all_projects
785 with_settings :date_format => '%m/%d/%Y' do
802 with_settings :date_format => '%m/%d/%Y' do
786 get :index, :format => 'csv'
803 get :index, :format => 'csv'
787 assert_response :success
804 assert_response :success
788 assert_equal 'text/csv; header=present', response.content_type
805 assert_equal 'text/csv; header=present', response.content_type
789 end
806 end
790 end
807 end
791
808
792 def test_index_csv
809 def test_index_csv
793 with_settings :date_format => '%m/%d/%Y' do
810 with_settings :date_format => '%m/%d/%Y' do
794 get :index, :project_id => 1, :format => 'csv'
811 get :index, :project_id => 1, :format => 'csv'
795 assert_response :success
812 assert_response :success
796 assert_equal 'text/csv; header=present', response.content_type
813 assert_equal 'text/csv; header=present', response.content_type
797 end
814 end
798 end
815 end
799
816
800 def test_index_csv_should_fill_issue_column_with_tracker_id_and_subject
817 def test_index_csv_should_fill_issue_column_with_tracker_id_and_subject
801 issue = Issue.find(1)
818 issue = Issue.find(1)
802 entry = TimeEntry.generate!(:issue => issue, :comments => "Issue column content test")
819 entry = TimeEntry.generate!(:issue => issue, :comments => "Issue column content test")
803
820
804 get :index, :format => 'csv'
821 get :index, :format => 'csv'
805 line = response.body.split("\n").detect {|l| l.include?(entry.comments)}
822 line = response.body.split("\n").detect {|l| l.include?(entry.comments)}
806 assert_not_nil line
823 assert_not_nil line
807 assert_include "#{issue.tracker} #1: #{issue.subject}", line
824 assert_include "#{issue.tracker} #1: #{issue.subject}", line
808 end
825 end
809 end
826 end
General Comments 0
You need to be logged in to leave comments. Login now