##// END OF EJS Templates
Rescue Query::StatementInvalid in TimelogController....
Jean-Philippe Lang -
r10746:aba07a860f95
parent child
Show More
@@ -1,350 +1,352
1 1 # Redmine - project management software
2 2 # Copyright (C) 2006-2012 Jean-Philippe Lang
3 3 #
4 4 # This program is free software; you can redistribute it and/or
5 5 # modify it under the terms of the GNU General Public License
6 6 # as published by the Free Software Foundation; either version 2
7 7 # of the License, or (at your option) any later version.
8 8 #
9 9 # This program is distributed in the hope that it will be useful,
10 10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 12 # GNU General Public License for more details.
13 13 #
14 14 # You should have received a copy of the GNU General Public License
15 15 # along with this program; if not, write to the Free Software
16 16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 17
18 18 class TimelogController < ApplicationController
19 19 menu_item :issues
20 20
21 21 before_filter :find_project_for_new_time_entry, :only => [:create]
22 22 before_filter :find_time_entry, :only => [:show, :edit, :update]
23 23 before_filter :find_time_entries, :only => [:bulk_edit, :bulk_update, :destroy]
24 24 before_filter :authorize, :except => [:new, :index, :report]
25 25
26 26 before_filter :find_optional_project, :only => [:index, :report]
27 27 before_filter :find_optional_project_for_new_time_entry, :only => [:new]
28 28 before_filter :authorize_global, :only => [:new, :index, :report]
29 29
30 30 accept_rss_auth :index
31 31 accept_api_auth :index, :show, :create, :update, :destroy
32 32
33 rescue_from Query::StatementInvalid, :with => :query_statement_invalid
34
33 35 helper :sort
34 36 include SortHelper
35 37 helper :issues
36 38 include TimelogHelper
37 39 helper :custom_fields
38 40 include CustomFieldsHelper
39 41 helper :queries
40 42
41 43 def index
42 44 @query = TimeEntryQuery.build_from_params(params, :project => @project, :name => '_')
43 45 scope = time_entry_scope
44 46
45 47 sort_init(@query.sort_criteria.empty? ? [['spent_on', 'desc']] : @query.sort_criteria)
46 48 sort_update(@query.sortable_columns)
47 49
48 50 respond_to do |format|
49 51 format.html {
50 52 # Paginate results
51 53 @entry_count = scope.count
52 54 @entry_pages = Paginator.new self, @entry_count, per_page_option, params['page']
53 55 @entries = scope.all(
54 56 :include => [:project, :activity, :user, {:issue => :tracker}],
55 57 :order => sort_clause,
56 58 :limit => @entry_pages.items_per_page,
57 59 :offset => @entry_pages.current.offset
58 60 )
59 61 @total_hours = scope.sum(:hours).to_f
60 62
61 63 render :layout => !request.xhr?
62 64 }
63 65 format.api {
64 66 @entry_count = scope.count
65 67 @offset, @limit = api_offset_and_limit
66 68 @entries = scope.all(
67 69 :include => [:project, :activity, :user, {:issue => :tracker}],
68 70 :order => sort_clause,
69 71 :limit => @limit,
70 72 :offset => @offset
71 73 )
72 74 }
73 75 format.atom {
74 76 entries = scope.all(
75 77 :include => [:project, :activity, :user, {:issue => :tracker}],
76 78 :order => "#{TimeEntry.table_name}.created_on DESC",
77 79 :limit => Setting.feeds_limit.to_i
78 80 )
79 81 render_feed(entries, :title => l(:label_spent_time))
80 82 }
81 83 format.csv {
82 84 # Export all entries
83 85 @entries = scope.all(
84 86 :include => [:project, :activity, :user, {:issue => [:tracker, :assigned_to, :priority]}],
85 87 :order => sort_clause
86 88 )
87 89 send_data(entries_to_csv(@entries), :type => 'text/csv; header=present', :filename => 'timelog.csv')
88 90 }
89 91 end
90 92 end
91 93
92 94 def report
93 95 @query = TimeEntryQuery.build_from_params(params, :project => @project, :name => '_')
94 96 scope = time_entry_scope
95 97
96 98 @report = Redmine::Helpers::TimeReport.new(@project, @issue, params[:criteria], params[:columns], scope)
97 99
98 100 respond_to do |format|
99 101 format.html { render :layout => !request.xhr? }
100 102 format.csv { send_data(report_to_csv(@report), :type => 'text/csv; header=present', :filename => 'timelog.csv') }
101 103 end
102 104 end
103 105
104 106 def show
105 107 respond_to do |format|
106 108 # TODO: Implement html response
107 109 format.html { render :nothing => true, :status => 406 }
108 110 format.api
109 111 end
110 112 end
111 113
112 114 def new
113 115 @time_entry ||= TimeEntry.new(:project => @project, :issue => @issue, :user => User.current, :spent_on => User.current.today)
114 116 @time_entry.safe_attributes = params[:time_entry]
115 117 end
116 118
117 119 def create
118 120 @time_entry ||= TimeEntry.new(:project => @project, :issue => @issue, :user => User.current, :spent_on => User.current.today)
119 121 @time_entry.safe_attributes = params[:time_entry]
120 122
121 123 call_hook(:controller_timelog_edit_before_save, { :params => params, :time_entry => @time_entry })
122 124
123 125 if @time_entry.save
124 126 respond_to do |format|
125 127 format.html {
126 128 flash[:notice] = l(:notice_successful_create)
127 129 if params[:continue]
128 130 if params[:project_id]
129 131 redirect_to :action => 'new', :project_id => @time_entry.project, :issue_id => @time_entry.issue,
130 132 :time_entry => {:issue_id => @time_entry.issue_id, :activity_id => @time_entry.activity_id},
131 133 :back_url => params[:back_url]
132 134 else
133 135 redirect_to :action => 'new',
134 136 :time_entry => {:project_id => @time_entry.project_id, :issue_id => @time_entry.issue_id, :activity_id => @time_entry.activity_id},
135 137 :back_url => params[:back_url]
136 138 end
137 139 else
138 140 redirect_back_or_default :action => 'index', :project_id => @time_entry.project
139 141 end
140 142 }
141 143 format.api { render :action => 'show', :status => :created, :location => time_entry_url(@time_entry) }
142 144 end
143 145 else
144 146 respond_to do |format|
145 147 format.html { render :action => 'new' }
146 148 format.api { render_validation_errors(@time_entry) }
147 149 end
148 150 end
149 151 end
150 152
151 153 def edit
152 154 @time_entry.safe_attributes = params[:time_entry]
153 155 end
154 156
155 157 def update
156 158 @time_entry.safe_attributes = params[:time_entry]
157 159
158 160 call_hook(:controller_timelog_edit_before_save, { :params => params, :time_entry => @time_entry })
159 161
160 162 if @time_entry.save
161 163 respond_to do |format|
162 164 format.html {
163 165 flash[:notice] = l(:notice_successful_update)
164 166 redirect_back_or_default :action => 'index', :project_id => @time_entry.project
165 167 }
166 168 format.api { render_api_ok }
167 169 end
168 170 else
169 171 respond_to do |format|
170 172 format.html { render :action => 'edit' }
171 173 format.api { render_validation_errors(@time_entry) }
172 174 end
173 175 end
174 176 end
175 177
176 178 def bulk_edit
177 179 @available_activities = TimeEntryActivity.shared.active
178 180 @custom_fields = TimeEntry.first.available_custom_fields
179 181 end
180 182
181 183 def bulk_update
182 184 attributes = parse_params_for_bulk_time_entry_attributes(params)
183 185
184 186 unsaved_time_entry_ids = []
185 187 @time_entries.each do |time_entry|
186 188 time_entry.reload
187 189 time_entry.safe_attributes = attributes
188 190 call_hook(:controller_time_entries_bulk_edit_before_save, { :params => params, :time_entry => time_entry })
189 191 unless time_entry.save
190 192 # Keep unsaved time_entry ids to display them in flash error
191 193 unsaved_time_entry_ids << time_entry.id
192 194 end
193 195 end
194 196 set_flash_from_bulk_time_entry_save(@time_entries, unsaved_time_entry_ids)
195 197 redirect_back_or_default({:controller => 'timelog', :action => 'index', :project_id => @projects.first})
196 198 end
197 199
198 200 def destroy
199 201 destroyed = TimeEntry.transaction do
200 202 @time_entries.each do |t|
201 203 unless t.destroy && t.destroyed?
202 204 raise ActiveRecord::Rollback
203 205 end
204 206 end
205 207 end
206 208
207 209 respond_to do |format|
208 210 format.html {
209 211 if destroyed
210 212 flash[:notice] = l(:notice_successful_delete)
211 213 else
212 214 flash[:error] = l(:notice_unable_delete_time_entry)
213 215 end
214 216 redirect_back_or_default(:action => 'index', :project_id => @projects.first)
215 217 }
216 218 format.api {
217 219 if destroyed
218 220 render_api_ok
219 221 else
220 222 render_validation_errors(@time_entries)
221 223 end
222 224 }
223 225 end
224 226 end
225 227
226 228 private
227 229 def find_time_entry
228 230 @time_entry = TimeEntry.find(params[:id])
229 231 unless @time_entry.editable_by?(User.current)
230 232 render_403
231 233 return false
232 234 end
233 235 @project = @time_entry.project
234 236 rescue ActiveRecord::RecordNotFound
235 237 render_404
236 238 end
237 239
238 240 def find_time_entries
239 241 @time_entries = TimeEntry.find_all_by_id(params[:id] || params[:ids])
240 242 raise ActiveRecord::RecordNotFound if @time_entries.empty?
241 243 @projects = @time_entries.collect(&:project).compact.uniq
242 244 @project = @projects.first if @projects.size == 1
243 245 rescue ActiveRecord::RecordNotFound
244 246 render_404
245 247 end
246 248
247 249 def set_flash_from_bulk_time_entry_save(time_entries, unsaved_time_entry_ids)
248 250 if unsaved_time_entry_ids.empty?
249 251 flash[:notice] = l(:notice_successful_update) unless time_entries.empty?
250 252 else
251 253 flash[:error] = l(:notice_failed_to_save_time_entries,
252 254 :count => unsaved_time_entry_ids.size,
253 255 :total => time_entries.size,
254 256 :ids => '#' + unsaved_time_entry_ids.join(', #'))
255 257 end
256 258 end
257 259
258 260 def find_optional_project_for_new_time_entry
259 261 if (project_id = (params[:project_id] || params[:time_entry] && params[:time_entry][:project_id])).present?
260 262 @project = Project.find(project_id)
261 263 end
262 264 if (issue_id = (params[:issue_id] || params[:time_entry] && params[:time_entry][:issue_id])).present?
263 265 @issue = Issue.find(issue_id)
264 266 @project ||= @issue.project
265 267 end
266 268 rescue ActiveRecord::RecordNotFound
267 269 render_404
268 270 end
269 271
270 272 def find_project_for_new_time_entry
271 273 find_optional_project_for_new_time_entry
272 274 if @project.nil?
273 275 render_404
274 276 end
275 277 end
276 278
277 279 def find_optional_project
278 280 if !params[:issue_id].blank?
279 281 @issue = Issue.find(params[:issue_id])
280 282 @project = @issue.project
281 283 elsif !params[:project_id].blank?
282 284 @project = Project.find(params[:project_id])
283 285 end
284 286 end
285 287
286 288 # Returns the TimeEntry scope for index and report actions
287 289 def time_entry_scope
288 290 scope = TimeEntry.visible.where(@query.statement)
289 291 if @issue
290 292 scope = scope.on_issue(@issue)
291 293 elsif @project
292 294 scope = scope.on_project(@project, Setting.display_subprojects_issues?)
293 295 end
294 296 scope
295 297 end
296 298
297 299 # Retrieves the date range based on predefined ranges or specific from/to param dates
298 300 def retrieve_date_range
299 301 @free_period = false
300 302 @from, @to = nil, nil
301 303
302 304 if params[:period_type] == '1' || (params[:period_type].nil? && !params[:period].nil?)
303 305 case params[:period].to_s
304 306 when 'today'
305 307 @from = @to = Date.today
306 308 when 'yesterday'
307 309 @from = @to = Date.today - 1
308 310 when 'current_week'
309 311 @from = Date.today - (Date.today.cwday - 1)%7
310 312 @to = @from + 6
311 313 when 'last_week'
312 314 @from = Date.today - 7 - (Date.today.cwday - 1)%7
313 315 @to = @from + 6
314 316 when 'last_2_weeks'
315 317 @from = Date.today - 14 - (Date.today.cwday - 1)%7
316 318 @to = @from + 13
317 319 when '7_days'
318 320 @from = Date.today - 7
319 321 @to = Date.today
320 322 when 'current_month'
321 323 @from = Date.civil(Date.today.year, Date.today.month, 1)
322 324 @to = (@from >> 1) - 1
323 325 when 'last_month'
324 326 @from = Date.civil(Date.today.year, Date.today.month, 1) << 1
325 327 @to = (@from >> 1) - 1
326 328 when '30_days'
327 329 @from = Date.today - 30
328 330 @to = Date.today
329 331 when 'current_year'
330 332 @from = Date.civil(Date.today.year, 1, 1)
331 333 @to = Date.civil(Date.today.year, 12, 31)
332 334 end
333 335 elsif params[:period_type] == '2' || (params[:period_type].nil? && (!params[:from].nil? || !params[:to].nil?))
334 336 begin; @from = params[:from].to_s.to_date unless params[:from].blank?; rescue; end
335 337 begin; @to = params[:to].to_s.to_date unless params[:to].blank?; rescue; end
336 338 @free_period = true
337 339 else
338 340 # default
339 341 end
340 342
341 343 @from, @to = @to, @from if @from && @to && @from > @to
342 344 end
343 345
344 346 def parse_params_for_bulk_time_entry_attributes(params)
345 347 attributes = (params[:time_entry] || {}).reject {|k,v| v.blank?}
346 348 attributes.keys.each {|k| attributes[k] = '' if attributes[k] == 'none'}
347 349 attributes[:custom_field_values].reject! {|k,v| v.blank?} if attributes[:custom_field_values]
348 350 attributes
349 351 end
350 352 end
General Comments 0
You need to be logged in to leave comments. Login now