##// END OF EJS Templates
Fixed that time entries should be sorted by date and created_on (#11178)....
Jean-Philippe Lang -
r9654:2c07b478bb1e
parent child
Show More
@@ -1,344 +1,344
1 # Redmine - project management software
1 # Redmine - project management software
2 # Copyright (C) 2006-2012 Jean-Philippe Lang
2 # Copyright (C) 2006-2012 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 TimelogController < ApplicationController
18 class TimelogController < ApplicationController
19 menu_item :issues
19 menu_item :issues
20
20
21 before_filter :find_project_for_new_time_entry, :only => [:create]
21 before_filter :find_project_for_new_time_entry, :only => [:create]
22 before_filter :find_time_entry, :only => [:show, :edit, :update]
22 before_filter :find_time_entry, :only => [:show, :edit, :update]
23 before_filter :find_time_entries, :only => [:bulk_edit, :bulk_update, :destroy]
23 before_filter :find_time_entries, :only => [:bulk_edit, :bulk_update, :destroy]
24 before_filter :authorize, :except => [:new, :index, :report]
24 before_filter :authorize, :except => [:new, :index, :report]
25
25
26 before_filter :find_optional_project, :only => [:index, :report]
26 before_filter :find_optional_project, :only => [:index, :report]
27 before_filter :find_optional_project_for_new_time_entry, :only => [:new]
27 before_filter :find_optional_project_for_new_time_entry, :only => [:new]
28 before_filter :authorize_global, :only => [:new, :index, :report]
28 before_filter :authorize_global, :only => [:new, :index, :report]
29
29
30 accept_rss_auth :index
30 accept_rss_auth :index
31 accept_api_auth :index, :show, :create, :update, :destroy
31 accept_api_auth :index, :show, :create, :update, :destroy
32
32
33 helper :sort
33 helper :sort
34 include SortHelper
34 include SortHelper
35 helper :issues
35 helper :issues
36 include TimelogHelper
36 include TimelogHelper
37 helper :custom_fields
37 helper :custom_fields
38 include CustomFieldsHelper
38 include CustomFieldsHelper
39
39
40 def index
40 def index
41 sort_init 'spent_on', 'desc'
41 sort_init 'spent_on', 'desc'
42 sort_update 'spent_on' => 'spent_on',
42 sort_update 'spent_on' => ['spent_on', "#{TimeEntry.table_name}.created_on"],
43 'user' => 'user_id',
43 'user' => 'user_id',
44 'activity' => 'activity_id',
44 'activity' => 'activity_id',
45 'project' => "#{Project.table_name}.name",
45 'project' => "#{Project.table_name}.name",
46 'issue' => 'issue_id',
46 'issue' => 'issue_id',
47 'hours' => 'hours'
47 'hours' => 'hours'
48
48
49 retrieve_date_range
49 retrieve_date_range
50
50
51 scope = TimeEntry.visible.spent_between(@from, @to)
51 scope = TimeEntry.visible.spent_between(@from, @to)
52 if @issue
52 if @issue
53 scope = scope.on_issue(@issue)
53 scope = scope.on_issue(@issue)
54 elsif @project
54 elsif @project
55 scope = scope.on_project(@project, Setting.display_subprojects_issues?)
55 scope = scope.on_project(@project, Setting.display_subprojects_issues?)
56 end
56 end
57
57
58 respond_to do |format|
58 respond_to do |format|
59 format.html {
59 format.html {
60 # Paginate results
60 # Paginate results
61 @entry_count = scope.count
61 @entry_count = scope.count
62 @entry_pages = Paginator.new self, @entry_count, per_page_option, params['page']
62 @entry_pages = Paginator.new self, @entry_count, per_page_option, params['page']
63 @entries = scope.all(
63 @entries = scope.all(
64 :include => [:project, :activity, :user, {:issue => :tracker}],
64 :include => [:project, :activity, :user, {:issue => :tracker}],
65 :order => sort_clause,
65 :order => sort_clause,
66 :limit => @entry_pages.items_per_page,
66 :limit => @entry_pages.items_per_page,
67 :offset => @entry_pages.current.offset
67 :offset => @entry_pages.current.offset
68 )
68 )
69 @total_hours = scope.sum(:hours).to_f
69 @total_hours = scope.sum(:hours).to_f
70
70
71 render :layout => !request.xhr?
71 render :layout => !request.xhr?
72 }
72 }
73 format.api {
73 format.api {
74 @entry_count = scope.count
74 @entry_count = scope.count
75 @offset, @limit = api_offset_and_limit
75 @offset, @limit = api_offset_and_limit
76 @entries = scope.all(
76 @entries = scope.all(
77 :include => [:project, :activity, :user, {:issue => :tracker}],
77 :include => [:project, :activity, :user, {:issue => :tracker}],
78 :order => sort_clause,
78 :order => sort_clause,
79 :limit => @limit,
79 :limit => @limit,
80 :offset => @offset
80 :offset => @offset
81 )
81 )
82 }
82 }
83 format.atom {
83 format.atom {
84 entries = scope.all(
84 entries = scope.all(
85 :include => [:project, :activity, :user, {:issue => :tracker}],
85 :include => [:project, :activity, :user, {:issue => :tracker}],
86 :order => "#{TimeEntry.table_name}.created_on DESC",
86 :order => "#{TimeEntry.table_name}.created_on DESC",
87 :limit => Setting.feeds_limit.to_i
87 :limit => Setting.feeds_limit.to_i
88 )
88 )
89 render_feed(entries, :title => l(:label_spent_time))
89 render_feed(entries, :title => l(:label_spent_time))
90 }
90 }
91 format.csv {
91 format.csv {
92 # Export all entries
92 # Export all entries
93 @entries = scope.all(
93 @entries = scope.all(
94 :include => [:project, :activity, :user, {:issue => [:tracker, :assigned_to, :priority]}],
94 :include => [:project, :activity, :user, {:issue => [:tracker, :assigned_to, :priority]}],
95 :order => sort_clause
95 :order => sort_clause
96 )
96 )
97 send_data(entries_to_csv(@entries), :type => 'text/csv; header=present', :filename => 'timelog.csv')
97 send_data(entries_to_csv(@entries), :type => 'text/csv; header=present', :filename => 'timelog.csv')
98 }
98 }
99 end
99 end
100 end
100 end
101
101
102 def report
102 def report
103 retrieve_date_range
103 retrieve_date_range
104 @report = Redmine::Helpers::TimeReport.new(@project, @issue, params[:criteria], params[:columns], @from, @to)
104 @report = Redmine::Helpers::TimeReport.new(@project, @issue, params[:criteria], params[:columns], @from, @to)
105
105
106 respond_to do |format|
106 respond_to do |format|
107 format.html { render :layout => !request.xhr? }
107 format.html { render :layout => !request.xhr? }
108 format.csv { send_data(report_to_csv(@report), :type => 'text/csv; header=present', :filename => 'timelog.csv') }
108 format.csv { send_data(report_to_csv(@report), :type => 'text/csv; header=present', :filename => 'timelog.csv') }
109 end
109 end
110 end
110 end
111
111
112 def show
112 def show
113 respond_to do |format|
113 respond_to do |format|
114 # TODO: Implement html response
114 # TODO: Implement html response
115 format.html { render :nothing => true, :status => 406 }
115 format.html { render :nothing => true, :status => 406 }
116 format.api
116 format.api
117 end
117 end
118 end
118 end
119
119
120 def new
120 def new
121 @time_entry ||= TimeEntry.new(:project => @project, :issue => @issue, :user => User.current, :spent_on => User.current.today)
121 @time_entry ||= TimeEntry.new(:project => @project, :issue => @issue, :user => User.current, :spent_on => User.current.today)
122 @time_entry.safe_attributes = params[:time_entry]
122 @time_entry.safe_attributes = params[:time_entry]
123 end
123 end
124
124
125 def create
125 def create
126 @time_entry ||= TimeEntry.new(:project => @project, :issue => @issue, :user => User.current, :spent_on => User.current.today)
126 @time_entry ||= TimeEntry.new(:project => @project, :issue => @issue, :user => User.current, :spent_on => User.current.today)
127 @time_entry.safe_attributes = params[:time_entry]
127 @time_entry.safe_attributes = params[:time_entry]
128
128
129 call_hook(:controller_timelog_edit_before_save, { :params => params, :time_entry => @time_entry })
129 call_hook(:controller_timelog_edit_before_save, { :params => params, :time_entry => @time_entry })
130
130
131 if @time_entry.save
131 if @time_entry.save
132 respond_to do |format|
132 respond_to do |format|
133 format.html {
133 format.html {
134 flash[:notice] = l(:notice_successful_create)
134 flash[:notice] = l(:notice_successful_create)
135 if params[:continue]
135 if params[:continue]
136 if params[:project_id]
136 if params[:project_id]
137 redirect_to :action => 'new', :project_id => @time_entry.project, :issue_id => @time_entry.issue,
137 redirect_to :action => 'new', :project_id => @time_entry.project, :issue_id => @time_entry.issue,
138 :time_entry => {:issue_id => @time_entry.issue_id, :activity_id => @time_entry.activity_id},
138 :time_entry => {:issue_id => @time_entry.issue_id, :activity_id => @time_entry.activity_id},
139 :back_url => params[:back_url]
139 :back_url => params[:back_url]
140 else
140 else
141 redirect_to :action => 'new',
141 redirect_to :action => 'new',
142 :time_entry => {:project_id => @time_entry.project_id, :issue_id => @time_entry.issue_id, :activity_id => @time_entry.activity_id},
142 :time_entry => {:project_id => @time_entry.project_id, :issue_id => @time_entry.issue_id, :activity_id => @time_entry.activity_id},
143 :back_url => params[:back_url]
143 :back_url => params[:back_url]
144 end
144 end
145 else
145 else
146 redirect_back_or_default :action => 'index', :project_id => @time_entry.project
146 redirect_back_or_default :action => 'index', :project_id => @time_entry.project
147 end
147 end
148 }
148 }
149 format.api { render :action => 'show', :status => :created, :location => time_entry_url(@time_entry) }
149 format.api { render :action => 'show', :status => :created, :location => time_entry_url(@time_entry) }
150 end
150 end
151 else
151 else
152 respond_to do |format|
152 respond_to do |format|
153 format.html { render :action => 'new' }
153 format.html { render :action => 'new' }
154 format.api { render_validation_errors(@time_entry) }
154 format.api { render_validation_errors(@time_entry) }
155 end
155 end
156 end
156 end
157 end
157 end
158
158
159 def edit
159 def edit
160 @time_entry.safe_attributes = params[:time_entry]
160 @time_entry.safe_attributes = params[:time_entry]
161 end
161 end
162
162
163 def update
163 def update
164 @time_entry.safe_attributes = params[:time_entry]
164 @time_entry.safe_attributes = params[:time_entry]
165
165
166 call_hook(:controller_timelog_edit_before_save, { :params => params, :time_entry => @time_entry })
166 call_hook(:controller_timelog_edit_before_save, { :params => params, :time_entry => @time_entry })
167
167
168 if @time_entry.save
168 if @time_entry.save
169 respond_to do |format|
169 respond_to do |format|
170 format.html {
170 format.html {
171 flash[:notice] = l(:notice_successful_update)
171 flash[:notice] = l(:notice_successful_update)
172 redirect_back_or_default :action => 'index', :project_id => @time_entry.project
172 redirect_back_or_default :action => 'index', :project_id => @time_entry.project
173 }
173 }
174 format.api { head :ok }
174 format.api { head :ok }
175 end
175 end
176 else
176 else
177 respond_to do |format|
177 respond_to do |format|
178 format.html { render :action => 'edit' }
178 format.html { render :action => 'edit' }
179 format.api { render_validation_errors(@time_entry) }
179 format.api { render_validation_errors(@time_entry) }
180 end
180 end
181 end
181 end
182 end
182 end
183
183
184 def bulk_edit
184 def bulk_edit
185 @available_activities = TimeEntryActivity.shared.active
185 @available_activities = TimeEntryActivity.shared.active
186 @custom_fields = TimeEntry.first.available_custom_fields
186 @custom_fields = TimeEntry.first.available_custom_fields
187 end
187 end
188
188
189 def bulk_update
189 def bulk_update
190 attributes = parse_params_for_bulk_time_entry_attributes(params)
190 attributes = parse_params_for_bulk_time_entry_attributes(params)
191
191
192 unsaved_time_entry_ids = []
192 unsaved_time_entry_ids = []
193 @time_entries.each do |time_entry|
193 @time_entries.each do |time_entry|
194 time_entry.reload
194 time_entry.reload
195 time_entry.safe_attributes = attributes
195 time_entry.safe_attributes = attributes
196 call_hook(:controller_time_entries_bulk_edit_before_save, { :params => params, :time_entry => time_entry })
196 call_hook(:controller_time_entries_bulk_edit_before_save, { :params => params, :time_entry => time_entry })
197 unless time_entry.save
197 unless time_entry.save
198 # Keep unsaved time_entry ids to display them in flash error
198 # Keep unsaved time_entry ids to display them in flash error
199 unsaved_time_entry_ids << time_entry.id
199 unsaved_time_entry_ids << time_entry.id
200 end
200 end
201 end
201 end
202 set_flash_from_bulk_time_entry_save(@time_entries, unsaved_time_entry_ids)
202 set_flash_from_bulk_time_entry_save(@time_entries, unsaved_time_entry_ids)
203 redirect_back_or_default({:controller => 'timelog', :action => 'index', :project_id => @projects.first})
203 redirect_back_or_default({:controller => 'timelog', :action => 'index', :project_id => @projects.first})
204 end
204 end
205
205
206 def destroy
206 def destroy
207 destroyed = TimeEntry.transaction do
207 destroyed = TimeEntry.transaction do
208 @time_entries.each do |t|
208 @time_entries.each do |t|
209 unless t.destroy && t.destroyed?
209 unless t.destroy && t.destroyed?
210 raise ActiveRecord::Rollback
210 raise ActiveRecord::Rollback
211 end
211 end
212 end
212 end
213 end
213 end
214
214
215 respond_to do |format|
215 respond_to do |format|
216 format.html {
216 format.html {
217 if destroyed
217 if destroyed
218 flash[:notice] = l(:notice_successful_delete)
218 flash[:notice] = l(:notice_successful_delete)
219 else
219 else
220 flash[:error] = l(:notice_unable_delete_time_entry)
220 flash[:error] = l(:notice_unable_delete_time_entry)
221 end
221 end
222 redirect_back_or_default(:action => 'index', :project_id => @projects.first)
222 redirect_back_or_default(:action => 'index', :project_id => @projects.first)
223 }
223 }
224 format.api {
224 format.api {
225 if destroyed
225 if destroyed
226 head :ok
226 head :ok
227 else
227 else
228 render_validation_errors(@time_entries)
228 render_validation_errors(@time_entries)
229 end
229 end
230 }
230 }
231 end
231 end
232 end
232 end
233
233
234 private
234 private
235 def find_time_entry
235 def find_time_entry
236 @time_entry = TimeEntry.find(params[:id])
236 @time_entry = TimeEntry.find(params[:id])
237 unless @time_entry.editable_by?(User.current)
237 unless @time_entry.editable_by?(User.current)
238 render_403
238 render_403
239 return false
239 return false
240 end
240 end
241 @project = @time_entry.project
241 @project = @time_entry.project
242 rescue ActiveRecord::RecordNotFound
242 rescue ActiveRecord::RecordNotFound
243 render_404
243 render_404
244 end
244 end
245
245
246 def find_time_entries
246 def find_time_entries
247 @time_entries = TimeEntry.find_all_by_id(params[:id] || params[:ids])
247 @time_entries = TimeEntry.find_all_by_id(params[:id] || params[:ids])
248 raise ActiveRecord::RecordNotFound if @time_entries.empty?
248 raise ActiveRecord::RecordNotFound if @time_entries.empty?
249 @projects = @time_entries.collect(&:project).compact.uniq
249 @projects = @time_entries.collect(&:project).compact.uniq
250 @project = @projects.first if @projects.size == 1
250 @project = @projects.first if @projects.size == 1
251 rescue ActiveRecord::RecordNotFound
251 rescue ActiveRecord::RecordNotFound
252 render_404
252 render_404
253 end
253 end
254
254
255 def set_flash_from_bulk_time_entry_save(time_entries, unsaved_time_entry_ids)
255 def set_flash_from_bulk_time_entry_save(time_entries, unsaved_time_entry_ids)
256 if unsaved_time_entry_ids.empty?
256 if unsaved_time_entry_ids.empty?
257 flash[:notice] = l(:notice_successful_update) unless time_entries.empty?
257 flash[:notice] = l(:notice_successful_update) unless time_entries.empty?
258 else
258 else
259 flash[:error] = l(:notice_failed_to_save_time_entries,
259 flash[:error] = l(:notice_failed_to_save_time_entries,
260 :count => unsaved_time_entry_ids.size,
260 :count => unsaved_time_entry_ids.size,
261 :total => time_entries.size,
261 :total => time_entries.size,
262 :ids => '#' + unsaved_time_entry_ids.join(', #'))
262 :ids => '#' + unsaved_time_entry_ids.join(', #'))
263 end
263 end
264 end
264 end
265
265
266 def find_optional_project_for_new_time_entry
266 def find_optional_project_for_new_time_entry
267 if (project_id = (params[:project_id] || params[:time_entry] && params[:time_entry][:project_id])).present?
267 if (project_id = (params[:project_id] || params[:time_entry] && params[:time_entry][:project_id])).present?
268 @project = Project.find(project_id)
268 @project = Project.find(project_id)
269 end
269 end
270 if (issue_id = (params[:issue_id] || params[:time_entry] && params[:time_entry][:issue_id])).present?
270 if (issue_id = (params[:issue_id] || params[:time_entry] && params[:time_entry][:issue_id])).present?
271 @issue = Issue.find(issue_id)
271 @issue = Issue.find(issue_id)
272 @project ||= @issue.project
272 @project ||= @issue.project
273 end
273 end
274 rescue ActiveRecord::RecordNotFound
274 rescue ActiveRecord::RecordNotFound
275 render_404
275 render_404
276 end
276 end
277
277
278 def find_project_for_new_time_entry
278 def find_project_for_new_time_entry
279 find_optional_project_for_new_time_entry
279 find_optional_project_for_new_time_entry
280 if @project.nil?
280 if @project.nil?
281 render_404
281 render_404
282 end
282 end
283 end
283 end
284
284
285 def find_optional_project
285 def find_optional_project
286 if !params[:issue_id].blank?
286 if !params[:issue_id].blank?
287 @issue = Issue.find(params[:issue_id])
287 @issue = Issue.find(params[:issue_id])
288 @project = @issue.project
288 @project = @issue.project
289 elsif !params[:project_id].blank?
289 elsif !params[:project_id].blank?
290 @project = Project.find(params[:project_id])
290 @project = Project.find(params[:project_id])
291 end
291 end
292 end
292 end
293
293
294 # Retrieves the date range based on predefined ranges or specific from/to param dates
294 # Retrieves the date range based on predefined ranges or specific from/to param dates
295 def retrieve_date_range
295 def retrieve_date_range
296 @free_period = false
296 @free_period = false
297 @from, @to = nil, nil
297 @from, @to = nil, nil
298
298
299 if params[:period_type] == '1' || (params[:period_type].nil? && !params[:period].nil?)
299 if params[:period_type] == '1' || (params[:period_type].nil? && !params[:period].nil?)
300 case params[:period].to_s
300 case params[:period].to_s
301 when 'today'
301 when 'today'
302 @from = @to = Date.today
302 @from = @to = Date.today
303 when 'yesterday'
303 when 'yesterday'
304 @from = @to = Date.today - 1
304 @from = @to = Date.today - 1
305 when 'current_week'
305 when 'current_week'
306 @from = Date.today - (Date.today.cwday - 1)%7
306 @from = Date.today - (Date.today.cwday - 1)%7
307 @to = @from + 6
307 @to = @from + 6
308 when 'last_week'
308 when 'last_week'
309 @from = Date.today - 7 - (Date.today.cwday - 1)%7
309 @from = Date.today - 7 - (Date.today.cwday - 1)%7
310 @to = @from + 6
310 @to = @from + 6
311 when '7_days'
311 when '7_days'
312 @from = Date.today - 7
312 @from = Date.today - 7
313 @to = Date.today
313 @to = Date.today
314 when 'current_month'
314 when 'current_month'
315 @from = Date.civil(Date.today.year, Date.today.month, 1)
315 @from = Date.civil(Date.today.year, Date.today.month, 1)
316 @to = (@from >> 1) - 1
316 @to = (@from >> 1) - 1
317 when 'last_month'
317 when 'last_month'
318 @from = Date.civil(Date.today.year, Date.today.month, 1) << 1
318 @from = Date.civil(Date.today.year, Date.today.month, 1) << 1
319 @to = (@from >> 1) - 1
319 @to = (@from >> 1) - 1
320 when '30_days'
320 when '30_days'
321 @from = Date.today - 30
321 @from = Date.today - 30
322 @to = Date.today
322 @to = Date.today
323 when 'current_year'
323 when 'current_year'
324 @from = Date.civil(Date.today.year, 1, 1)
324 @from = Date.civil(Date.today.year, 1, 1)
325 @to = Date.civil(Date.today.year, 12, 31)
325 @to = Date.civil(Date.today.year, 12, 31)
326 end
326 end
327 elsif params[:period_type] == '2' || (params[:period_type].nil? && (!params[:from].nil? || !params[:to].nil?))
327 elsif params[:period_type] == '2' || (params[:period_type].nil? && (!params[:from].nil? || !params[:to].nil?))
328 begin; @from = params[:from].to_s.to_date unless params[:from].blank?; rescue; end
328 begin; @from = params[:from].to_s.to_date unless params[:from].blank?; rescue; end
329 begin; @to = params[:to].to_s.to_date unless params[:to].blank?; rescue; end
329 begin; @to = params[:to].to_s.to_date unless params[:to].blank?; rescue; end
330 @free_period = true
330 @free_period = true
331 else
331 else
332 # default
332 # default
333 end
333 end
334
334
335 @from, @to = @to, @from if @from && @to && @from > @to
335 @from, @to = @to, @from if @from && @to && @from > @to
336 end
336 end
337
337
338 def parse_params_for_bulk_time_entry_attributes(params)
338 def parse_params_for_bulk_time_entry_attributes(params)
339 attributes = (params[:time_entry] || {}).reject {|k,v| v.blank?}
339 attributes = (params[:time_entry] || {}).reject {|k,v| v.blank?}
340 attributes.keys.each {|k| attributes[k] = '' if attributes[k] == 'none'}
340 attributes.keys.each {|k| attributes[k] = '' if attributes[k] == 'none'}
341 attributes[:custom_field_values].reject! {|k,v| v.blank?} if attributes[:custom_field_values]
341 attributes[:custom_field_values].reject! {|k,v| v.blank?} if attributes[:custom_field_values]
342 attributes
342 attributes
343 end
343 end
344 end
344 end
@@ -1,761 +1,775
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 # Redmine - project management software
2 # Redmine - project management software
3 # Copyright (C) 2006-2012 Jean-Philippe Lang
3 # Copyright (C) 2006-2012 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 require 'timelog_controller'
20 require 'timelog_controller'
21
21
22 # Re-raise errors caught by the controller.
22 # Re-raise errors caught by the controller.
23 class TimelogController; def rescue_action(e) raise e end; end
23 class TimelogController; def rescue_action(e) raise e end; end
24
24
25 class TimelogControllerTest < ActionController::TestCase
25 class TimelogControllerTest < ActionController::TestCase
26 fixtures :projects, :enabled_modules, :roles, :members,
26 fixtures :projects, :enabled_modules, :roles, :members,
27 :member_roles, :issues, :time_entries, :users,
27 :member_roles, :issues, :time_entries, :users,
28 :trackers, :enumerations, :issue_statuses,
28 :trackers, :enumerations, :issue_statuses,
29 :custom_fields, :custom_values
29 :custom_fields, :custom_values
30
30
31 include Redmine::I18n
31 include Redmine::I18n
32
32
33 def setup
33 def setup
34 @controller = TimelogController.new
34 @controller = TimelogController.new
35 @request = ActionController::TestRequest.new
35 @request = ActionController::TestRequest.new
36 @response = ActionController::TestResponse.new
36 @response = ActionController::TestResponse.new
37 end
37 end
38
38
39 def test_get_new
39 def test_get_new
40 @request.session[:user_id] = 3
40 @request.session[:user_id] = 3
41 get :new, :project_id => 1
41 get :new, :project_id => 1
42 assert_response :success
42 assert_response :success
43 assert_template 'new'
43 assert_template 'new'
44 # Default activity selected
44 # Default activity selected
45 assert_tag :tag => 'option', :attributes => { :selected => 'selected' },
45 assert_tag :tag => 'option', :attributes => { :selected => 'selected' },
46 :content => 'Development'
46 :content => 'Development'
47 assert_select 'input[name=project_id][value=1]'
47 assert_select 'input[name=project_id][value=1]'
48 end
48 end
49
49
50 def test_get_new_should_only_show_active_time_entry_activities
50 def test_get_new_should_only_show_active_time_entry_activities
51 @request.session[:user_id] = 3
51 @request.session[:user_id] = 3
52 get :new, :project_id => 1
52 get :new, :project_id => 1
53 assert_response :success
53 assert_response :success
54 assert_template 'new'
54 assert_template 'new'
55 assert_no_tag 'select', :attributes => {:name => 'time_entry[project_id]'}
55 assert_no_tag 'select', :attributes => {:name => 'time_entry[project_id]'}
56 assert_no_tag 'option', :content => 'Inactive Activity'
56 assert_no_tag 'option', :content => 'Inactive Activity'
57 end
57 end
58
58
59 def test_new_without_project
59 def test_new_without_project
60 @request.session[:user_id] = 3
60 @request.session[:user_id] = 3
61 get :new
61 get :new
62 assert_response :success
62 assert_response :success
63 assert_template 'new'
63 assert_template 'new'
64 assert_tag 'select', :attributes => {:name => 'time_entry[project_id]'}
64 assert_tag 'select', :attributes => {:name => 'time_entry[project_id]'}
65 assert_select 'input[name=project_id]', 0
65 assert_select 'input[name=project_id]', 0
66 end
66 end
67
67
68 def test_new_without_project_should_prefill_the_form
68 def test_new_without_project_should_prefill_the_form
69 @request.session[:user_id] = 3
69 @request.session[:user_id] = 3
70 get :new, :time_entry => {:project_id => '1'}
70 get :new, :time_entry => {:project_id => '1'}
71 assert_response :success
71 assert_response :success
72 assert_template 'new'
72 assert_template 'new'
73 assert_select 'select[name=?]', 'time_entry[project_id]' do
73 assert_select 'select[name=?]', 'time_entry[project_id]' do
74 assert_select 'option[value=1][selected=selected]'
74 assert_select 'option[value=1][selected=selected]'
75 end
75 end
76 assert_select 'input[name=project_id]', 0
76 assert_select 'input[name=project_id]', 0
77 end
77 end
78
78
79 def test_new_without_project_should_deny_without_permission
79 def test_new_without_project_should_deny_without_permission
80 Role.all.each {|role| role.remove_permission! :log_time}
80 Role.all.each {|role| role.remove_permission! :log_time}
81 @request.session[:user_id] = 3
81 @request.session[:user_id] = 3
82
82
83 get :new
83 get :new
84 assert_response 403
84 assert_response 403
85 end
85 end
86
86
87 def test_get_edit_existing_time
87 def test_get_edit_existing_time
88 @request.session[:user_id] = 2
88 @request.session[:user_id] = 2
89 get :edit, :id => 2, :project_id => nil
89 get :edit, :id => 2, :project_id => nil
90 assert_response :success
90 assert_response :success
91 assert_template 'edit'
91 assert_template 'edit'
92 # Default activity selected
92 # Default activity selected
93 assert_tag :tag => 'form', :attributes => { :action => '/projects/ecookbook/time_entries/2' }
93 assert_tag :tag => 'form', :attributes => { :action => '/projects/ecookbook/time_entries/2' }
94 end
94 end
95
95
96 def test_get_edit_with_an_existing_time_entry_with_inactive_activity
96 def test_get_edit_with_an_existing_time_entry_with_inactive_activity
97 te = TimeEntry.find(1)
97 te = TimeEntry.find(1)
98 te.activity = TimeEntryActivity.find_by_name("Inactive Activity")
98 te.activity = TimeEntryActivity.find_by_name("Inactive Activity")
99 te.save!
99 te.save!
100
100
101 @request.session[:user_id] = 1
101 @request.session[:user_id] = 1
102 get :edit, :project_id => 1, :id => 1
102 get :edit, :project_id => 1, :id => 1
103 assert_response :success
103 assert_response :success
104 assert_template 'edit'
104 assert_template 'edit'
105 # Blank option since nothing is pre-selected
105 # Blank option since nothing is pre-selected
106 assert_tag :tag => 'option', :content => '--- Please select ---'
106 assert_tag :tag => 'option', :content => '--- Please select ---'
107 end
107 end
108
108
109 def test_post_create
109 def test_post_create
110 # TODO: should POST to issues’ time log instead of project. change form
110 # TODO: should POST to issues’ time log instead of project. change form
111 # and routing
111 # and routing
112 @request.session[:user_id] = 3
112 @request.session[:user_id] = 3
113 post :create, :project_id => 1,
113 post :create, :project_id => 1,
114 :time_entry => {:comments => 'Some work on TimelogControllerTest',
114 :time_entry => {:comments => 'Some work on TimelogControllerTest',
115 # Not the default activity
115 # Not the default activity
116 :activity_id => '11',
116 :activity_id => '11',
117 :spent_on => '2008-03-14',
117 :spent_on => '2008-03-14',
118 :issue_id => '1',
118 :issue_id => '1',
119 :hours => '7.3'}
119 :hours => '7.3'}
120 assert_redirected_to :action => 'index', :project_id => 'ecookbook'
120 assert_redirected_to :action => 'index', :project_id => 'ecookbook'
121
121
122 i = Issue.find(1)
122 i = Issue.find(1)
123 t = TimeEntry.find_by_comments('Some work on TimelogControllerTest')
123 t = TimeEntry.find_by_comments('Some work on TimelogControllerTest')
124 assert_not_nil t
124 assert_not_nil t
125 assert_equal 11, t.activity_id
125 assert_equal 11, t.activity_id
126 assert_equal 7.3, t.hours
126 assert_equal 7.3, t.hours
127 assert_equal 3, t.user_id
127 assert_equal 3, t.user_id
128 assert_equal i, t.issue
128 assert_equal i, t.issue
129 assert_equal i.project, t.project
129 assert_equal i.project, t.project
130 end
130 end
131
131
132 def test_post_create_with_blank_issue
132 def test_post_create_with_blank_issue
133 # TODO: should POST to issues’ time log instead of project. change form
133 # TODO: should POST to issues’ time log instead of project. change form
134 # and routing
134 # and routing
135 @request.session[:user_id] = 3
135 @request.session[:user_id] = 3
136 post :create, :project_id => 1,
136 post :create, :project_id => 1,
137 :time_entry => {:comments => 'Some work on TimelogControllerTest',
137 :time_entry => {:comments => 'Some work on TimelogControllerTest',
138 # Not the default activity
138 # Not the default activity
139 :activity_id => '11',
139 :activity_id => '11',
140 :issue_id => '',
140 :issue_id => '',
141 :spent_on => '2008-03-14',
141 :spent_on => '2008-03-14',
142 :hours => '7.3'}
142 :hours => '7.3'}
143 assert_redirected_to :action => 'index', :project_id => 'ecookbook'
143 assert_redirected_to :action => 'index', :project_id => 'ecookbook'
144
144
145 t = TimeEntry.find_by_comments('Some work on TimelogControllerTest')
145 t = TimeEntry.find_by_comments('Some work on TimelogControllerTest')
146 assert_not_nil t
146 assert_not_nil t
147 assert_equal 11, t.activity_id
147 assert_equal 11, t.activity_id
148 assert_equal 7.3, t.hours
148 assert_equal 7.3, t.hours
149 assert_equal 3, t.user_id
149 assert_equal 3, t.user_id
150 end
150 end
151
151
152 def test_create_and_continue
152 def test_create_and_continue
153 @request.session[:user_id] = 2
153 @request.session[:user_id] = 2
154 post :create, :project_id => 1,
154 post :create, :project_id => 1,
155 :time_entry => {:activity_id => '11',
155 :time_entry => {: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 :continue => '1'
159 :continue => '1'
160 assert_redirected_to '/projects/ecookbook/time_entries/new?time_entry%5Bactivity_id%5D=11&time_entry%5Bissue_id%5D='
160 assert_redirected_to '/projects/ecookbook/time_entries/new?time_entry%5Bactivity_id%5D=11&time_entry%5Bissue_id%5D='
161 end
161 end
162
162
163 def test_create_and_continue_with_issue_id
163 def test_create_and_continue_with_issue_id
164 @request.session[:user_id] = 2
164 @request.session[:user_id] = 2
165 post :create, :project_id => 1,
165 post :create, :project_id => 1,
166 :time_entry => {:activity_id => '11',
166 :time_entry => {:activity_id => '11',
167 :issue_id => '1',
167 :issue_id => '1',
168 :spent_on => '2008-03-14',
168 :spent_on => '2008-03-14',
169 :hours => '7.3'},
169 :hours => '7.3'},
170 :continue => '1'
170 :continue => '1'
171 assert_redirected_to '/projects/ecookbook/issues/1/time_entries/new?time_entry%5Bactivity_id%5D=11&time_entry%5Bissue_id%5D=1'
171 assert_redirected_to '/projects/ecookbook/issues/1/time_entries/new?time_entry%5Bactivity_id%5D=11&time_entry%5Bissue_id%5D=1'
172 end
172 end
173
173
174 def test_create_and_continue_without_project
174 def test_create_and_continue_without_project
175 @request.session[:user_id] = 2
175 @request.session[:user_id] = 2
176 post :create, :time_entry => {:project_id => '1',
176 post :create, :time_entry => {:project_id => '1',
177 :activity_id => '11',
177 :activity_id => '11',
178 :issue_id => '',
178 :issue_id => '',
179 :spent_on => '2008-03-14',
179 :spent_on => '2008-03-14',
180 :hours => '7.3'},
180 :hours => '7.3'},
181 :continue => '1'
181 :continue => '1'
182
182
183 assert_redirected_to '/time_entries/new?time_entry%5Bactivity_id%5D=11&time_entry%5Bissue_id%5D=&time_entry%5Bproject_id%5D=1'
183 assert_redirected_to '/time_entries/new?time_entry%5Bactivity_id%5D=11&time_entry%5Bissue_id%5D=&time_entry%5Bproject_id%5D=1'
184 end
184 end
185
185
186 def test_create_without_log_time_permission_should_be_denied
186 def test_create_without_log_time_permission_should_be_denied
187 @request.session[:user_id] = 2
187 @request.session[:user_id] = 2
188 Role.find_by_name('Manager').remove_permission! :log_time
188 Role.find_by_name('Manager').remove_permission! :log_time
189 post :create, :project_id => 1,
189 post :create, :project_id => 1,
190 :time_entry => {:activity_id => '11',
190 :time_entry => {:activity_id => '11',
191 :issue_id => '',
191 :issue_id => '',
192 :spent_on => '2008-03-14',
192 :spent_on => '2008-03-14',
193 :hours => '7.3'}
193 :hours => '7.3'}
194
194
195 assert_response 403
195 assert_response 403
196 end
196 end
197
197
198 def test_create_with_failure
198 def test_create_with_failure
199 @request.session[:user_id] = 2
199 @request.session[:user_id] = 2
200 post :create, :project_id => 1,
200 post :create, :project_id => 1,
201 :time_entry => {:activity_id => '',
201 :time_entry => {:activity_id => '',
202 :issue_id => '',
202 :issue_id => '',
203 :spent_on => '2008-03-14',
203 :spent_on => '2008-03-14',
204 :hours => '7.3'}
204 :hours => '7.3'}
205
205
206 assert_response :success
206 assert_response :success
207 assert_template 'new'
207 assert_template 'new'
208 end
208 end
209
209
210 def test_create_without_project
210 def test_create_without_project
211 @request.session[:user_id] = 2
211 @request.session[:user_id] = 2
212 assert_difference 'TimeEntry.count' do
212 assert_difference 'TimeEntry.count' do
213 post :create, :time_entry => {:project_id => '1',
213 post :create, :time_entry => {:project_id => '1',
214 :activity_id => '11',
214 :activity_id => '11',
215 :issue_id => '',
215 :issue_id => '',
216 :spent_on => '2008-03-14',
216 :spent_on => '2008-03-14',
217 :hours => '7.3'}
217 :hours => '7.3'}
218 end
218 end
219
219
220 assert_redirected_to '/projects/ecookbook/time_entries'
220 assert_redirected_to '/projects/ecookbook/time_entries'
221 time_entry = TimeEntry.first(:order => 'id DESC')
221 time_entry = TimeEntry.first(:order => 'id DESC')
222 assert_equal 1, time_entry.project_id
222 assert_equal 1, time_entry.project_id
223 end
223 end
224
224
225 def test_create_without_project_should_fail_with_issue_not_inside_project
225 def test_create_without_project_should_fail_with_issue_not_inside_project
226 @request.session[:user_id] = 2
226 @request.session[:user_id] = 2
227 assert_no_difference 'TimeEntry.count' do
227 assert_no_difference 'TimeEntry.count' do
228 post :create, :time_entry => {:project_id => '1',
228 post :create, :time_entry => {:project_id => '1',
229 :activity_id => '11',
229 :activity_id => '11',
230 :issue_id => '5',
230 :issue_id => '5',
231 :spent_on => '2008-03-14',
231 :spent_on => '2008-03-14',
232 :hours => '7.3'}
232 :hours => '7.3'}
233 end
233 end
234
234
235 assert_response :success
235 assert_response :success
236 assert assigns(:time_entry).errors[:issue_id].present?
236 assert assigns(:time_entry).errors[:issue_id].present?
237 end
237 end
238
238
239 def test_create_without_project_should_deny_without_permission
239 def test_create_without_project_should_deny_without_permission
240 @request.session[:user_id] = 2
240 @request.session[:user_id] = 2
241 Project.find(3).disable_module!(:time_tracking)
241 Project.find(3).disable_module!(:time_tracking)
242
242
243 assert_no_difference 'TimeEntry.count' do
243 assert_no_difference 'TimeEntry.count' do
244 post :create, :time_entry => {:project_id => '3',
244 post :create, :time_entry => {:project_id => '3',
245 :activity_id => '11',
245 :activity_id => '11',
246 :issue_id => '',
246 :issue_id => '',
247 :spent_on => '2008-03-14',
247 :spent_on => '2008-03-14',
248 :hours => '7.3'}
248 :hours => '7.3'}
249 end
249 end
250
250
251 assert_response 403
251 assert_response 403
252 end
252 end
253
253
254 def test_create_without_project_with_failure
254 def test_create_without_project_with_failure
255 @request.session[:user_id] = 2
255 @request.session[:user_id] = 2
256 assert_no_difference 'TimeEntry.count' do
256 assert_no_difference 'TimeEntry.count' do
257 post :create, :time_entry => {:project_id => '1',
257 post :create, :time_entry => {:project_id => '1',
258 :activity_id => '11',
258 :activity_id => '11',
259 :issue_id => '',
259 :issue_id => '',
260 :spent_on => '2008-03-14',
260 :spent_on => '2008-03-14',
261 :hours => ''}
261 :hours => ''}
262 end
262 end
263
263
264 assert_response :success
264 assert_response :success
265 assert_tag 'select', :attributes => {:name => 'time_entry[project_id]'},
265 assert_tag 'select', :attributes => {:name => 'time_entry[project_id]'},
266 :child => {:tag => 'option', :attributes => {:value => '1', :selected => 'selected'}}
266 :child => {:tag => 'option', :attributes => {:value => '1', :selected => 'selected'}}
267 end
267 end
268
268
269 def test_update
269 def test_update
270 entry = TimeEntry.find(1)
270 entry = TimeEntry.find(1)
271 assert_equal 1, entry.issue_id
271 assert_equal 1, entry.issue_id
272 assert_equal 2, entry.user_id
272 assert_equal 2, entry.user_id
273
273
274 @request.session[:user_id] = 1
274 @request.session[:user_id] = 1
275 put :update, :id => 1,
275 put :update, :id => 1,
276 :time_entry => {:issue_id => '2',
276 :time_entry => {:issue_id => '2',
277 :hours => '8'}
277 :hours => '8'}
278 assert_redirected_to :action => 'index', :project_id => 'ecookbook'
278 assert_redirected_to :action => 'index', :project_id => 'ecookbook'
279 entry.reload
279 entry.reload
280
280
281 assert_equal 8, entry.hours
281 assert_equal 8, entry.hours
282 assert_equal 2, entry.issue_id
282 assert_equal 2, entry.issue_id
283 assert_equal 2, entry.user_id
283 assert_equal 2, entry.user_id
284 end
284 end
285
285
286 def test_get_bulk_edit
286 def test_get_bulk_edit
287 @request.session[:user_id] = 2
287 @request.session[:user_id] = 2
288 get :bulk_edit, :ids => [1, 2]
288 get :bulk_edit, :ids => [1, 2]
289 assert_response :success
289 assert_response :success
290 assert_template 'bulk_edit'
290 assert_template 'bulk_edit'
291
291
292 # System wide custom field
292 # System wide custom field
293 assert_tag :select, :attributes => {:name => 'time_entry[custom_field_values][10]'}
293 assert_tag :select, :attributes => {:name => 'time_entry[custom_field_values][10]'}
294
294
295 # Activities
295 # Activities
296 assert_select 'select[name=?]', 'time_entry[activity_id]' do
296 assert_select 'select[name=?]', 'time_entry[activity_id]' do
297 assert_select 'option[value=]', :text => '(No change)'
297 assert_select 'option[value=]', :text => '(No change)'
298 assert_select 'option[value=9]', :text => 'Design'
298 assert_select 'option[value=9]', :text => 'Design'
299 end
299 end
300 end
300 end
301
301
302 def test_get_bulk_edit_on_different_projects
302 def test_get_bulk_edit_on_different_projects
303 @request.session[:user_id] = 2
303 @request.session[:user_id] = 2
304 get :bulk_edit, :ids => [1, 2, 6]
304 get :bulk_edit, :ids => [1, 2, 6]
305 assert_response :success
305 assert_response :success
306 assert_template 'bulk_edit'
306 assert_template 'bulk_edit'
307 end
307 end
308
308
309 def test_bulk_update
309 def test_bulk_update
310 @request.session[:user_id] = 2
310 @request.session[:user_id] = 2
311 # update time entry activity
311 # update time entry activity
312 post :bulk_update, :ids => [1, 2], :time_entry => { :activity_id => 9}
312 post :bulk_update, :ids => [1, 2], :time_entry => { :activity_id => 9}
313
313
314 assert_response 302
314 assert_response 302
315 # check that the issues were updated
315 # check that the issues were updated
316 assert_equal [9, 9], TimeEntry.find_all_by_id([1, 2]).collect {|i| i.activity_id}
316 assert_equal [9, 9], TimeEntry.find_all_by_id([1, 2]).collect {|i| i.activity_id}
317 end
317 end
318
318
319 def test_bulk_update_with_failure
319 def test_bulk_update_with_failure
320 @request.session[:user_id] = 2
320 @request.session[:user_id] = 2
321 post :bulk_update, :ids => [1, 2], :time_entry => { :hours => 'A'}
321 post :bulk_update, :ids => [1, 2], :time_entry => { :hours => 'A'}
322
322
323 assert_response 302
323 assert_response 302
324 assert_match /Failed to save 2 time entrie/, flash[:error]
324 assert_match /Failed to save 2 time entrie/, flash[:error]
325 end
325 end
326
326
327 def test_bulk_update_on_different_projects
327 def test_bulk_update_on_different_projects
328 @request.session[:user_id] = 2
328 @request.session[:user_id] = 2
329 # makes user a manager on the other project
329 # makes user a manager on the other project
330 Member.create!(:user_id => 2, :project_id => 3, :role_ids => [1])
330 Member.create!(:user_id => 2, :project_id => 3, :role_ids => [1])
331
331
332 # update time entry activity
332 # update time entry activity
333 post :bulk_update, :ids => [1, 2, 4], :time_entry => { :activity_id => 9 }
333 post :bulk_update, :ids => [1, 2, 4], :time_entry => { :activity_id => 9 }
334
334
335 assert_response 302
335 assert_response 302
336 # check that the issues were updated
336 # check that the issues were updated
337 assert_equal [9, 9, 9], TimeEntry.find_all_by_id([1, 2, 4]).collect {|i| i.activity_id}
337 assert_equal [9, 9, 9], TimeEntry.find_all_by_id([1, 2, 4]).collect {|i| i.activity_id}
338 end
338 end
339
339
340 def test_bulk_update_on_different_projects_without_rights
340 def test_bulk_update_on_different_projects_without_rights
341 @request.session[:user_id] = 3
341 @request.session[:user_id] = 3
342 user = User.find(3)
342 user = User.find(3)
343 action = { :controller => "timelog", :action => "bulk_update" }
343 action = { :controller => "timelog", :action => "bulk_update" }
344 assert user.allowed_to?(action, TimeEntry.find(1).project)
344 assert user.allowed_to?(action, TimeEntry.find(1).project)
345 assert ! user.allowed_to?(action, TimeEntry.find(5).project)
345 assert ! user.allowed_to?(action, TimeEntry.find(5).project)
346 post :bulk_update, :ids => [1, 5], :time_entry => { :activity_id => 9 }
346 post :bulk_update, :ids => [1, 5], :time_entry => { :activity_id => 9 }
347 assert_response 403
347 assert_response 403
348 end
348 end
349
349
350 def test_bulk_update_custom_field
350 def test_bulk_update_custom_field
351 @request.session[:user_id] = 2
351 @request.session[:user_id] = 2
352 post :bulk_update, :ids => [1, 2], :time_entry => { :custom_field_values => {'10' => '0'} }
352 post :bulk_update, :ids => [1, 2], :time_entry => { :custom_field_values => {'10' => '0'} }
353
353
354 assert_response 302
354 assert_response 302
355 assert_equal ["0", "0"], TimeEntry.find_all_by_id([1, 2]).collect {|i| i.custom_value_for(10).value}
355 assert_equal ["0", "0"], TimeEntry.find_all_by_id([1, 2]).collect {|i| i.custom_value_for(10).value}
356 end
356 end
357
357
358 def test_post_bulk_update_should_redirect_back_using_the_back_url_parameter
358 def test_post_bulk_update_should_redirect_back_using_the_back_url_parameter
359 @request.session[:user_id] = 2
359 @request.session[:user_id] = 2
360 post :bulk_update, :ids => [1,2], :back_url => '/time_entries'
360 post :bulk_update, :ids => [1,2], :back_url => '/time_entries'
361
361
362 assert_response :redirect
362 assert_response :redirect
363 assert_redirected_to '/time_entries'
363 assert_redirected_to '/time_entries'
364 end
364 end
365
365
366 def test_post_bulk_update_should_not_redirect_back_using_the_back_url_parameter_off_the_host
366 def test_post_bulk_update_should_not_redirect_back_using_the_back_url_parameter_off_the_host
367 @request.session[:user_id] = 2
367 @request.session[:user_id] = 2
368 post :bulk_update, :ids => [1,2], :back_url => 'http://google.com'
368 post :bulk_update, :ids => [1,2], :back_url => 'http://google.com'
369
369
370 assert_response :redirect
370 assert_response :redirect
371 assert_redirected_to :controller => 'timelog', :action => 'index', :project_id => Project.find(1).identifier
371 assert_redirected_to :controller => 'timelog', :action => 'index', :project_id => Project.find(1).identifier
372 end
372 end
373
373
374 def test_post_bulk_update_without_edit_permission_should_be_denied
374 def test_post_bulk_update_without_edit_permission_should_be_denied
375 @request.session[:user_id] = 2
375 @request.session[:user_id] = 2
376 Role.find_by_name('Manager').remove_permission! :edit_time_entries
376 Role.find_by_name('Manager').remove_permission! :edit_time_entries
377 post :bulk_update, :ids => [1,2]
377 post :bulk_update, :ids => [1,2]
378
378
379 assert_response 403
379 assert_response 403
380 end
380 end
381
381
382 def test_destroy
382 def test_destroy
383 @request.session[:user_id] = 2
383 @request.session[:user_id] = 2
384 delete :destroy, :id => 1
384 delete :destroy, :id => 1
385 assert_redirected_to :action => 'index', :project_id => 'ecookbook'
385 assert_redirected_to :action => 'index', :project_id => 'ecookbook'
386 assert_equal I18n.t(:notice_successful_delete), flash[:notice]
386 assert_equal I18n.t(:notice_successful_delete), flash[:notice]
387 assert_nil TimeEntry.find_by_id(1)
387 assert_nil TimeEntry.find_by_id(1)
388 end
388 end
389
389
390 def test_destroy_should_fail
390 def test_destroy_should_fail
391 # simulate that this fails (e.g. due to a plugin), see #5700
391 # simulate that this fails (e.g. due to a plugin), see #5700
392 TimeEntry.any_instance.expects(:destroy).returns(false)
392 TimeEntry.any_instance.expects(:destroy).returns(false)
393
393
394 @request.session[:user_id] = 2
394 @request.session[:user_id] = 2
395 delete :destroy, :id => 1
395 delete :destroy, :id => 1
396 assert_redirected_to :action => 'index', :project_id => 'ecookbook'
396 assert_redirected_to :action => 'index', :project_id => 'ecookbook'
397 assert_equal I18n.t(:notice_unable_delete_time_entry), flash[:error]
397 assert_equal I18n.t(:notice_unable_delete_time_entry), flash[:error]
398 assert_not_nil TimeEntry.find_by_id(1)
398 assert_not_nil TimeEntry.find_by_id(1)
399 end
399 end
400
400
401 def test_index_all_projects
401 def test_index_all_projects
402 get :index
402 get :index
403 assert_response :success
403 assert_response :success
404 assert_template 'index'
404 assert_template 'index'
405 assert_not_nil assigns(:total_hours)
405 assert_not_nil assigns(:total_hours)
406 assert_equal "162.90", "%.2f" % assigns(:total_hours)
406 assert_equal "162.90", "%.2f" % assigns(:total_hours)
407 assert_tag :form,
407 assert_tag :form,
408 :attributes => {:action => "/time_entries", :id => 'query_form'}
408 :attributes => {:action => "/time_entries", :id => 'query_form'}
409 end
409 end
410
410
411 def test_index_all_projects_should_show_log_time_link
411 def test_index_all_projects_should_show_log_time_link
412 @request.session[:user_id] = 2
412 @request.session[:user_id] = 2
413 get :index
413 get :index
414 assert_response :success
414 assert_response :success
415 assert_template 'index'
415 assert_template 'index'
416 assert_tag 'a', :attributes => {:href => '/time_entries/new'}, :content => /Log time/
416 assert_tag 'a', :attributes => {:href => '/time_entries/new'}, :content => /Log time/
417 end
417 end
418
418
419 def test_index_at_project_level
419 def test_index_at_project_level
420 get :index, :project_id => 'ecookbook'
420 get :index, :project_id => 'ecookbook'
421 assert_response :success
421 assert_response :success
422 assert_template 'index'
422 assert_template 'index'
423 assert_not_nil assigns(:entries)
423 assert_not_nil assigns(:entries)
424 assert_equal 4, assigns(:entries).size
424 assert_equal 4, assigns(:entries).size
425 # project and subproject
425 # project and subproject
426 assert_equal [1, 3], assigns(:entries).collect(&:project_id).uniq.sort
426 assert_equal [1, 3], assigns(:entries).collect(&:project_id).uniq.sort
427 assert_not_nil assigns(:total_hours)
427 assert_not_nil assigns(:total_hours)
428 assert_equal "162.90", "%.2f" % assigns(:total_hours)
428 assert_equal "162.90", "%.2f" % assigns(:total_hours)
429 # display all time by default
429 # display all time by default
430 assert_nil assigns(:from)
430 assert_nil assigns(:from)
431 assert_nil assigns(:to)
431 assert_nil assigns(:to)
432 assert_tag :form,
432 assert_tag :form,
433 :attributes => {:action => "/projects/ecookbook/time_entries", :id => 'query_form'}
433 :attributes => {:action => "/projects/ecookbook/time_entries", :id => 'query_form'}
434 end
434 end
435
435
436 def test_index_at_project_level_with_date_range
436 def test_index_at_project_level_with_date_range
437 get :index, :project_id => 'ecookbook', :from => '2007-03-20', :to => '2007-04-30'
437 get :index, :project_id => 'ecookbook', :from => '2007-03-20', :to => '2007-04-30'
438 assert_response :success
438 assert_response :success
439 assert_template 'index'
439 assert_template 'index'
440 assert_not_nil assigns(:entries)
440 assert_not_nil assigns(:entries)
441 assert_equal 3, assigns(:entries).size
441 assert_equal 3, assigns(:entries).size
442 assert_not_nil assigns(:total_hours)
442 assert_not_nil assigns(:total_hours)
443 assert_equal "12.90", "%.2f" % assigns(:total_hours)
443 assert_equal "12.90", "%.2f" % assigns(:total_hours)
444 assert_equal '2007-03-20'.to_date, assigns(:from)
444 assert_equal '2007-03-20'.to_date, assigns(:from)
445 assert_equal '2007-04-30'.to_date, assigns(:to)
445 assert_equal '2007-04-30'.to_date, assigns(:to)
446 assert_tag :form,
446 assert_tag :form,
447 :attributes => {:action => "/projects/ecookbook/time_entries", :id => 'query_form'}
447 :attributes => {:action => "/projects/ecookbook/time_entries", :id => 'query_form'}
448 end
448 end
449
449
450 def test_index_at_project_level_with_period
450 def test_index_at_project_level_with_period
451 get :index, :project_id => 'ecookbook', :period => '7_days'
451 get :index, :project_id => 'ecookbook', :period => '7_days'
452 assert_response :success
452 assert_response :success
453 assert_template 'index'
453 assert_template 'index'
454 assert_not_nil assigns(:entries)
454 assert_not_nil assigns(:entries)
455 assert_not_nil assigns(:total_hours)
455 assert_not_nil assigns(:total_hours)
456 assert_equal Date.today - 7, assigns(:from)
456 assert_equal Date.today - 7, assigns(:from)
457 assert_equal Date.today, assigns(:to)
457 assert_equal Date.today, assigns(:to)
458 assert_tag :form,
458 assert_tag :form,
459 :attributes => {:action => "/projects/ecookbook/time_entries", :id => 'query_form'}
459 :attributes => {:action => "/projects/ecookbook/time_entries", :id => 'query_form'}
460 end
460 end
461
461
462 def test_index_one_day
462 def test_index_one_day
463 get :index, :project_id => 'ecookbook', :from => "2007-03-23", :to => "2007-03-23"
463 get :index, :project_id => 'ecookbook', :from => "2007-03-23", :to => "2007-03-23"
464 assert_response :success
464 assert_response :success
465 assert_template 'index'
465 assert_template 'index'
466 assert_not_nil assigns(:total_hours)
466 assert_not_nil assigns(:total_hours)
467 assert_equal "4.25", "%.2f" % assigns(:total_hours)
467 assert_equal "4.25", "%.2f" % assigns(:total_hours)
468 assert_tag :form,
468 assert_tag :form,
469 :attributes => {:action => "/projects/ecookbook/time_entries", :id => 'query_form'}
469 :attributes => {:action => "/projects/ecookbook/time_entries", :id => 'query_form'}
470 end
470 end
471
471
472 def test_index_from_a_date
472 def test_index_from_a_date
473 get :index, :project_id => 'ecookbook', :from => "2007-03-23", :to => ""
473 get :index, :project_id => 'ecookbook', :from => "2007-03-23", :to => ""
474 assert_equal '2007-03-23'.to_date, assigns(:from)
474 assert_equal '2007-03-23'.to_date, assigns(:from)
475 assert_nil assigns(:to)
475 assert_nil assigns(:to)
476 end
476 end
477
477
478 def test_index_to_a_date
478 def test_index_to_a_date
479 get :index, :project_id => 'ecookbook', :from => "", :to => "2007-03-23"
479 get :index, :project_id => 'ecookbook', :from => "", :to => "2007-03-23"
480 assert_nil assigns(:from)
480 assert_nil assigns(:from)
481 assert_equal '2007-03-23'.to_date, assigns(:to)
481 assert_equal '2007-03-23'.to_date, assigns(:to)
482 end
482 end
483
483
484 def test_index_today
484 def test_index_today
485 Date.stubs(:today).returns('2011-12-15'.to_date)
485 Date.stubs(:today).returns('2011-12-15'.to_date)
486 get :index, :period => 'today'
486 get :index, :period => 'today'
487 assert_equal '2011-12-15'.to_date, assigns(:from)
487 assert_equal '2011-12-15'.to_date, assigns(:from)
488 assert_equal '2011-12-15'.to_date, assigns(:to)
488 assert_equal '2011-12-15'.to_date, assigns(:to)
489 end
489 end
490
490
491 def test_index_yesterday
491 def test_index_yesterday
492 Date.stubs(:today).returns('2011-12-15'.to_date)
492 Date.stubs(:today).returns('2011-12-15'.to_date)
493 get :index, :period => 'yesterday'
493 get :index, :period => 'yesterday'
494 assert_equal '2011-12-14'.to_date, assigns(:from)
494 assert_equal '2011-12-14'.to_date, assigns(:from)
495 assert_equal '2011-12-14'.to_date, assigns(:to)
495 assert_equal '2011-12-14'.to_date, assigns(:to)
496 end
496 end
497
497
498 def test_index_current_week
498 def test_index_current_week
499 Date.stubs(:today).returns('2011-12-15'.to_date)
499 Date.stubs(:today).returns('2011-12-15'.to_date)
500 get :index, :period => 'current_week'
500 get :index, :period => 'current_week'
501 assert_equal '2011-12-12'.to_date, assigns(:from)
501 assert_equal '2011-12-12'.to_date, assigns(:from)
502 assert_equal '2011-12-18'.to_date, assigns(:to)
502 assert_equal '2011-12-18'.to_date, assigns(:to)
503 end
503 end
504
504
505 def test_index_last_week
505 def test_index_last_week
506 Date.stubs(:today).returns('2011-12-15'.to_date)
506 Date.stubs(:today).returns('2011-12-15'.to_date)
507 get :index, :period => 'current_week'
507 get :index, :period => 'current_week'
508 assert_equal '2011-12-05'.to_date, assigns(:from)
508 assert_equal '2011-12-05'.to_date, assigns(:from)
509 assert_equal '2011-12-11'.to_date, assigns(:to)
509 assert_equal '2011-12-11'.to_date, assigns(:to)
510 end
510 end
511
511
512 def test_index_last_week
512 def test_index_last_week
513 Date.stubs(:today).returns('2011-12-15'.to_date)
513 Date.stubs(:today).returns('2011-12-15'.to_date)
514 get :index, :period => 'last_week'
514 get :index, :period => 'last_week'
515 assert_equal '2011-12-05'.to_date, assigns(:from)
515 assert_equal '2011-12-05'.to_date, assigns(:from)
516 assert_equal '2011-12-11'.to_date, assigns(:to)
516 assert_equal '2011-12-11'.to_date, assigns(:to)
517 end
517 end
518
518
519 def test_index_7_days
519 def test_index_7_days
520 Date.stubs(:today).returns('2011-12-15'.to_date)
520 Date.stubs(:today).returns('2011-12-15'.to_date)
521 get :index, :period => '7_days'
521 get :index, :period => '7_days'
522 assert_equal '2011-12-08'.to_date, assigns(:from)
522 assert_equal '2011-12-08'.to_date, assigns(:from)
523 assert_equal '2011-12-15'.to_date, assigns(:to)
523 assert_equal '2011-12-15'.to_date, assigns(:to)
524 end
524 end
525
525
526 def test_index_current_month
526 def test_index_current_month
527 Date.stubs(:today).returns('2011-12-15'.to_date)
527 Date.stubs(:today).returns('2011-12-15'.to_date)
528 get :index, :period => 'current_month'
528 get :index, :period => 'current_month'
529 assert_equal '2011-12-01'.to_date, assigns(:from)
529 assert_equal '2011-12-01'.to_date, assigns(:from)
530 assert_equal '2011-12-31'.to_date, assigns(:to)
530 assert_equal '2011-12-31'.to_date, assigns(:to)
531 end
531 end
532
532
533 def test_index_last_month
533 def test_index_last_month
534 Date.stubs(:today).returns('2011-12-15'.to_date)
534 Date.stubs(:today).returns('2011-12-15'.to_date)
535 get :index, :period => 'last_month'
535 get :index, :period => 'last_month'
536 assert_equal '2011-11-01'.to_date, assigns(:from)
536 assert_equal '2011-11-01'.to_date, assigns(:from)
537 assert_equal '2011-11-30'.to_date, assigns(:to)
537 assert_equal '2011-11-30'.to_date, assigns(:to)
538 end
538 end
539
539
540 def test_index_30_days
540 def test_index_30_days
541 Date.stubs(:today).returns('2011-12-15'.to_date)
541 Date.stubs(:today).returns('2011-12-15'.to_date)
542 get :index, :period => '30_days'
542 get :index, :period => '30_days'
543 assert_equal '2011-11-15'.to_date, assigns(:from)
543 assert_equal '2011-11-15'.to_date, assigns(:from)
544 assert_equal '2011-12-15'.to_date, assigns(:to)
544 assert_equal '2011-12-15'.to_date, assigns(:to)
545 end
545 end
546
546
547 def test_index_current_year
547 def test_index_current_year
548 Date.stubs(:today).returns('2011-12-15'.to_date)
548 Date.stubs(:today).returns('2011-12-15'.to_date)
549 get :index, :period => 'current_year'
549 get :index, :period => 'current_year'
550 assert_equal '2011-01-01'.to_date, assigns(:from)
550 assert_equal '2011-01-01'.to_date, assigns(:from)
551 assert_equal '2011-12-31'.to_date, assigns(:to)
551 assert_equal '2011-12-31'.to_date, assigns(:to)
552 end
552 end
553
553
554 def test_index_at_issue_level
554 def test_index_at_issue_level
555 get :index, :issue_id => 1
555 get :index, :issue_id => 1
556 assert_response :success
556 assert_response :success
557 assert_template 'index'
557 assert_template 'index'
558 assert_not_nil assigns(:entries)
558 assert_not_nil assigns(:entries)
559 assert_equal 2, assigns(:entries).size
559 assert_equal 2, assigns(:entries).size
560 assert_not_nil assigns(:total_hours)
560 assert_not_nil assigns(:total_hours)
561 assert_equal 154.25, assigns(:total_hours)
561 assert_equal 154.25, assigns(:total_hours)
562 # display all time
562 # display all time
563 assert_nil assigns(:from)
563 assert_nil assigns(:from)
564 assert_nil assigns(:to)
564 assert_nil assigns(:to)
565 # TODO: remove /projects/:project_id/issues/:issue_id/time_entries routes
565 # TODO: remove /projects/:project_id/issues/:issue_id/time_entries routes
566 # to use /issues/:issue_id/time_entries
566 # to use /issues/:issue_id/time_entries
567 assert_tag :form,
567 assert_tag :form,
568 :attributes => {:action => "/projects/ecookbook/issues/1/time_entries", :id => 'query_form'}
568 :attributes => {:action => "/projects/ecookbook/issues/1/time_entries", :id => 'query_form'}
569 end
569 end
570
570
571 def test_index_should_sort_by_spent_on_and_created_on
572 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)
573 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)
574 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)
575
576 get :index, :project_id => 1, :from => '2012-06-15', :to => '2012-06-16'
577 assert_response :success
578 assert_equal [t2, t1, t3], assigns(:entries)
579
580 get :index, :project_id => 1, :from => '2012-06-15', :to => '2012-06-16', :sort => 'spent_on'
581 assert_response :success
582 assert_equal [t3, t1, t2], assigns(:entries)
583 end
584
571 def test_index_atom_feed
585 def test_index_atom_feed
572 get :index, :project_id => 1, :format => 'atom'
586 get :index, :project_id => 1, :format => 'atom'
573 assert_response :success
587 assert_response :success
574 assert_equal 'application/atom+xml', @response.content_type
588 assert_equal 'application/atom+xml', @response.content_type
575 assert_not_nil assigns(:items)
589 assert_not_nil assigns(:items)
576 assert assigns(:items).first.is_a?(TimeEntry)
590 assert assigns(:items).first.is_a?(TimeEntry)
577 end
591 end
578
592
579 def test_index_all_projects_csv_export
593 def test_index_all_projects_csv_export
580 Setting.date_format = '%m/%d/%Y'
594 Setting.date_format = '%m/%d/%Y'
581 get :index, :format => 'csv'
595 get :index, :format => 'csv'
582 assert_response :success
596 assert_response :success
583 assert_equal 'text/csv; header=present', @response.content_type
597 assert_equal 'text/csv; header=present', @response.content_type
584 assert @response.body.include?("Date,User,Activity,Project,Issue,Tracker,Subject,Hours,Comment,Overtime\n")
598 assert @response.body.include?("Date,User,Activity,Project,Issue,Tracker,Subject,Hours,Comment,Overtime\n")
585 assert @response.body.include?("\n04/21/2007,redMine Admin,Design,eCookbook,3,Bug,Error 281 when updating a recipe,1.0,\"\",\"\"\n")
599 assert @response.body.include?("\n04/21/2007,redMine Admin,Design,eCookbook,3,Bug,Error 281 when updating a recipe,1.0,\"\",\"\"\n")
586 end
600 end
587
601
588 def test_index_csv_export
602 def test_index_csv_export
589 Setting.date_format = '%m/%d/%Y'
603 Setting.date_format = '%m/%d/%Y'
590 get :index, :project_id => 1, :format => 'csv'
604 get :index, :project_id => 1, :format => 'csv'
591 assert_response :success
605 assert_response :success
592 assert_equal 'text/csv; header=present', @response.content_type
606 assert_equal 'text/csv; header=present', @response.content_type
593 assert @response.body.include?("Date,User,Activity,Project,Issue,Tracker,Subject,Hours,Comment,Overtime\n")
607 assert @response.body.include?("Date,User,Activity,Project,Issue,Tracker,Subject,Hours,Comment,Overtime\n")
594 assert @response.body.include?("\n04/21/2007,redMine Admin,Design,eCookbook,3,Bug,Error 281 when updating a recipe,1.0,\"\",\"\"\n")
608 assert @response.body.include?("\n04/21/2007,redMine Admin,Design,eCookbook,3,Bug,Error 281 when updating a recipe,1.0,\"\",\"\"\n")
595 end
609 end
596
610
597 def test_index_csv_export_with_multi_custom_field
611 def test_index_csv_export_with_multi_custom_field
598 field = TimeEntryCustomField.create!(:name => 'Test', :field_format => 'list',
612 field = TimeEntryCustomField.create!(:name => 'Test', :field_format => 'list',
599 :multiple => true, :possible_values => ['value1', 'value2'])
613 :multiple => true, :possible_values => ['value1', 'value2'])
600 entry = TimeEntry.find(1)
614 entry = TimeEntry.find(1)
601 entry.custom_field_values = {field.id => ['value1', 'value2']}
615 entry.custom_field_values = {field.id => ['value1', 'value2']}
602 entry.save!
616 entry.save!
603
617
604 get :index, :project_id => 1, :format => 'csv'
618 get :index, :project_id => 1, :format => 'csv'
605 assert_response :success
619 assert_response :success
606 assert_include '"value1, value2"', @response.body
620 assert_include '"value1, value2"', @response.body
607 end
621 end
608
622
609 def test_csv_big_5
623 def test_csv_big_5
610 user = User.find_by_id(3)
624 user = User.find_by_id(3)
611 user.language = "zh-TW"
625 user.language = "zh-TW"
612 assert user.save
626 assert user.save
613 str_utf8 = "\xe4\xb8\x80\xe6\x9c\x88"
627 str_utf8 = "\xe4\xb8\x80\xe6\x9c\x88"
614 str_big5 = "\xa4@\xa4\xeb"
628 str_big5 = "\xa4@\xa4\xeb"
615 if str_utf8.respond_to?(:force_encoding)
629 if str_utf8.respond_to?(:force_encoding)
616 str_utf8.force_encoding('UTF-8')
630 str_utf8.force_encoding('UTF-8')
617 str_big5.force_encoding('Big5')
631 str_big5.force_encoding('Big5')
618 end
632 end
619 @request.session[:user_id] = 3
633 @request.session[:user_id] = 3
620 post :create, :project_id => 1,
634 post :create, :project_id => 1,
621 :time_entry => {:comments => str_utf8,
635 :time_entry => {:comments => str_utf8,
622 # Not the default activity
636 # Not the default activity
623 :activity_id => '11',
637 :activity_id => '11',
624 :issue_id => '',
638 :issue_id => '',
625 :spent_on => '2011-11-10',
639 :spent_on => '2011-11-10',
626 :hours => '7.3'}
640 :hours => '7.3'}
627 assert_redirected_to :action => 'index', :project_id => 'ecookbook'
641 assert_redirected_to :action => 'index', :project_id => 'ecookbook'
628
642
629 t = TimeEntry.find_by_comments(str_utf8)
643 t = TimeEntry.find_by_comments(str_utf8)
630 assert_not_nil t
644 assert_not_nil t
631 assert_equal 11, t.activity_id
645 assert_equal 11, t.activity_id
632 assert_equal 7.3, t.hours
646 assert_equal 7.3, t.hours
633 assert_equal 3, t.user_id
647 assert_equal 3, t.user_id
634
648
635 get :index, :project_id => 1, :format => 'csv',
649 get :index, :project_id => 1, :format => 'csv',
636 :from => '2011-11-10', :to => '2011-11-10'
650 :from => '2011-11-10', :to => '2011-11-10'
637 assert_response :success
651 assert_response :success
638 assert_equal 'text/csv; header=present', @response.content_type
652 assert_equal 'text/csv; header=present', @response.content_type
639 ar = @response.body.chomp.split("\n")
653 ar = @response.body.chomp.split("\n")
640 s1 = "\xa4\xe9\xb4\xc1"
654 s1 = "\xa4\xe9\xb4\xc1"
641 if str_utf8.respond_to?(:force_encoding)
655 if str_utf8.respond_to?(:force_encoding)
642 s1.force_encoding('Big5')
656 s1.force_encoding('Big5')
643 end
657 end
644 assert ar[0].include?(s1)
658 assert ar[0].include?(s1)
645 assert ar[1].include?(str_big5)
659 assert ar[1].include?(str_big5)
646 end
660 end
647
661
648 def test_csv_cannot_convert_should_be_replaced_big_5
662 def test_csv_cannot_convert_should_be_replaced_big_5
649 user = User.find_by_id(3)
663 user = User.find_by_id(3)
650 user.language = "zh-TW"
664 user.language = "zh-TW"
651 assert user.save
665 assert user.save
652 str_utf8 = "\xe4\xbb\xa5\xe5\x86\x85"
666 str_utf8 = "\xe4\xbb\xa5\xe5\x86\x85"
653 if str_utf8.respond_to?(:force_encoding)
667 if str_utf8.respond_to?(:force_encoding)
654 str_utf8.force_encoding('UTF-8')
668 str_utf8.force_encoding('UTF-8')
655 end
669 end
656 @request.session[:user_id] = 3
670 @request.session[:user_id] = 3
657 post :create, :project_id => 1,
671 post :create, :project_id => 1,
658 :time_entry => {:comments => str_utf8,
672 :time_entry => {:comments => str_utf8,
659 # Not the default activity
673 # Not the default activity
660 :activity_id => '11',
674 :activity_id => '11',
661 :issue_id => '',
675 :issue_id => '',
662 :spent_on => '2011-11-10',
676 :spent_on => '2011-11-10',
663 :hours => '7.3'}
677 :hours => '7.3'}
664 assert_redirected_to :action => 'index', :project_id => 'ecookbook'
678 assert_redirected_to :action => 'index', :project_id => 'ecookbook'
665
679
666 t = TimeEntry.find_by_comments(str_utf8)
680 t = TimeEntry.find_by_comments(str_utf8)
667 assert_not_nil t
681 assert_not_nil t
668 assert_equal 11, t.activity_id
682 assert_equal 11, t.activity_id
669 assert_equal 7.3, t.hours
683 assert_equal 7.3, t.hours
670 assert_equal 3, t.user_id
684 assert_equal 3, t.user_id
671
685
672 get :index, :project_id => 1, :format => 'csv',
686 get :index, :project_id => 1, :format => 'csv',
673 :from => '2011-11-10', :to => '2011-11-10'
687 :from => '2011-11-10', :to => '2011-11-10'
674 assert_response :success
688 assert_response :success
675 assert_equal 'text/csv; header=present', @response.content_type
689 assert_equal 'text/csv; header=present', @response.content_type
676 ar = @response.body.chomp.split("\n")
690 ar = @response.body.chomp.split("\n")
677 s1 = "\xa4\xe9\xb4\xc1"
691 s1 = "\xa4\xe9\xb4\xc1"
678 if str_utf8.respond_to?(:force_encoding)
692 if str_utf8.respond_to?(:force_encoding)
679 s1.force_encoding('Big5')
693 s1.force_encoding('Big5')
680 end
694 end
681 assert ar[0].include?(s1)
695 assert ar[0].include?(s1)
682 s2 = ar[1].split(",")[8]
696 s2 = ar[1].split(",")[8]
683 if s2.respond_to?(:force_encoding)
697 if s2.respond_to?(:force_encoding)
684 s3 = "\xa5H?"
698 s3 = "\xa5H?"
685 s3.force_encoding('Big5')
699 s3.force_encoding('Big5')
686 assert_equal s3, s2
700 assert_equal s3, s2
687 elsif RUBY_PLATFORM == 'java'
701 elsif RUBY_PLATFORM == 'java'
688 assert_equal "??", s2
702 assert_equal "??", s2
689 else
703 else
690 assert_equal "\xa5H???", s2
704 assert_equal "\xa5H???", s2
691 end
705 end
692 end
706 end
693
707
694 def test_csv_tw
708 def test_csv_tw
695 with_settings :default_language => "zh-TW" do
709 with_settings :default_language => "zh-TW" do
696 str1 = "test_csv_tw"
710 str1 = "test_csv_tw"
697 user = User.find_by_id(3)
711 user = User.find_by_id(3)
698 te1 = TimeEntry.create(:spent_on => '2011-11-10',
712 te1 = TimeEntry.create(:spent_on => '2011-11-10',
699 :hours => 999.9,
713 :hours => 999.9,
700 :project => Project.find(1),
714 :project => Project.find(1),
701 :user => user,
715 :user => user,
702 :activity => TimeEntryActivity.find_by_name('Design'),
716 :activity => TimeEntryActivity.find_by_name('Design'),
703 :comments => str1)
717 :comments => str1)
704 te2 = TimeEntry.find_by_comments(str1)
718 te2 = TimeEntry.find_by_comments(str1)
705 assert_not_nil te2
719 assert_not_nil te2
706 assert_equal 999.9, te2.hours
720 assert_equal 999.9, te2.hours
707 assert_equal 3, te2.user_id
721 assert_equal 3, te2.user_id
708
722
709 get :index, :project_id => 1, :format => 'csv',
723 get :index, :project_id => 1, :format => 'csv',
710 :from => '2011-11-10', :to => '2011-11-10'
724 :from => '2011-11-10', :to => '2011-11-10'
711 assert_response :success
725 assert_response :success
712 assert_equal 'text/csv; header=present', @response.content_type
726 assert_equal 'text/csv; header=present', @response.content_type
713
727
714 ar = @response.body.chomp.split("\n")
728 ar = @response.body.chomp.split("\n")
715 s2 = ar[1].split(",")[7]
729 s2 = ar[1].split(",")[7]
716 assert_equal '999.9', s2
730 assert_equal '999.9', s2
717
731
718 str_tw = "Traditional Chinese (\xe7\xb9\x81\xe9\xab\x94\xe4\xb8\xad\xe6\x96\x87)"
732 str_tw = "Traditional Chinese (\xe7\xb9\x81\xe9\xab\x94\xe4\xb8\xad\xe6\x96\x87)"
719 if str_tw.respond_to?(:force_encoding)
733 if str_tw.respond_to?(:force_encoding)
720 str_tw.force_encoding('UTF-8')
734 str_tw.force_encoding('UTF-8')
721 end
735 end
722 assert_equal str_tw, l(:general_lang_name)
736 assert_equal str_tw, l(:general_lang_name)
723 assert_equal ',', l(:general_csv_separator)
737 assert_equal ',', l(:general_csv_separator)
724 assert_equal '.', l(:general_csv_decimal_separator)
738 assert_equal '.', l(:general_csv_decimal_separator)
725 end
739 end
726 end
740 end
727
741
728 def test_csv_fr
742 def test_csv_fr
729 with_settings :default_language => "fr" do
743 with_settings :default_language => "fr" do
730 str1 = "test_csv_fr"
744 str1 = "test_csv_fr"
731 user = User.find_by_id(3)
745 user = User.find_by_id(3)
732 te1 = TimeEntry.create(:spent_on => '2011-11-10',
746 te1 = TimeEntry.create(:spent_on => '2011-11-10',
733 :hours => 999.9,
747 :hours => 999.9,
734 :project => Project.find(1),
748 :project => Project.find(1),
735 :user => user,
749 :user => user,
736 :activity => TimeEntryActivity.find_by_name('Design'),
750 :activity => TimeEntryActivity.find_by_name('Design'),
737 :comments => str1)
751 :comments => str1)
738 te2 = TimeEntry.find_by_comments(str1)
752 te2 = TimeEntry.find_by_comments(str1)
739 assert_not_nil te2
753 assert_not_nil te2
740 assert_equal 999.9, te2.hours
754 assert_equal 999.9, te2.hours
741 assert_equal 3, te2.user_id
755 assert_equal 3, te2.user_id
742
756
743 get :index, :project_id => 1, :format => 'csv',
757 get :index, :project_id => 1, :format => 'csv',
744 :from => '2011-11-10', :to => '2011-11-10'
758 :from => '2011-11-10', :to => '2011-11-10'
745 assert_response :success
759 assert_response :success
746 assert_equal 'text/csv; header=present', @response.content_type
760 assert_equal 'text/csv; header=present', @response.content_type
747
761
748 ar = @response.body.chomp.split("\n")
762 ar = @response.body.chomp.split("\n")
749 s2 = ar[1].split(";")[7]
763 s2 = ar[1].split(";")[7]
750 assert_equal '999,9', s2
764 assert_equal '999,9', s2
751
765
752 str_fr = "Fran\xc3\xa7ais"
766 str_fr = "Fran\xc3\xa7ais"
753 if str_fr.respond_to?(:force_encoding)
767 if str_fr.respond_to?(:force_encoding)
754 str_fr.force_encoding('UTF-8')
768 str_fr.force_encoding('UTF-8')
755 end
769 end
756 assert_equal str_fr, l(:general_lang_name)
770 assert_equal str_fr, l(:general_lang_name)
757 assert_equal ';', l(:general_csv_separator)
771 assert_equal ';', l(:general_csv_separator)
758 assert_equal ',', l(:general_csv_decimal_separator)
772 assert_equal ',', l(:general_csv_decimal_separator)
759 end
773 end
760 end
774 end
761 end
775 end
General Comments 0
You need to be logged in to leave comments. Login now