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