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