comparison app/controllers/timelog_controller.rb @ 441:cbce1fd3b1b7 redmine-1.2

Update to Redmine 1.2-stable branch (Redmine SVN rev 6000)
author Chris Cannam
date Mon, 06 Jun 2011 14:24:13 +0100
parents 8661b858af72
children 0c939c159af4
comparison
equal deleted inserted replaced
245:051f544170fe 441:cbce1fd3b1b7
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 before_filter :find_project, :only => [:new, :create] 20 before_filter :find_project, :only => [:new, :create]
21 before_filter :find_time_entry, :only => [:show, :edit, :update, :destroy] 21 before_filter :find_time_entry, :only => [:show, :edit, :update]
22 before_filter :find_time_entries, :only => [:bulk_edit, :bulk_update, :destroy]
22 before_filter :authorize, :except => [:index] 23 before_filter :authorize, :except => [:index]
23 before_filter :find_optional_project, :only => [:index] 24 before_filter :find_optional_project, :only => [:index]
24 accept_key_auth :index, :show, :create, :update, :destroy 25 accept_key_auth :index, :show, :create, :update, :destroy
25 26
26 helper :sort 27 helper :sort
38 'project' => "#{Project.table_name}.name", 39 'project' => "#{Project.table_name}.name",
39 'issue' => 'issue_id', 40 'issue' => 'issue_id',
40 'hours' => 'hours' 41 'hours' => 'hours'
41 42
42 cond = ARCondition.new 43 cond = ARCondition.new
43 if @project.nil? 44 if @issue
44 cond << Project.allowed_to_condition(User.current, :view_time_entries) 45 cond << "#{Issue.table_name}.root_id = #{@issue.root_id} AND #{Issue.table_name}.lft >= #{@issue.lft} AND #{Issue.table_name}.rgt <= #{@issue.rgt}"
45 elsif @issue.nil? 46 elsif @project
46 cond << @project.project_condition(Setting.display_subprojects_issues?) 47 cond << @project.project_condition(Setting.display_subprojects_issues?)
47 else
48 cond << "#{Issue.table_name}.root_id = #{@issue.root_id} AND #{Issue.table_name}.lft >= #{@issue.lft} AND #{Issue.table_name}.rgt <= #{@issue.rgt}"
49 end 48 end
50 49
51 retrieve_date_range 50 retrieve_date_range
52 cond << ['spent_on BETWEEN ? AND ?', @from, @to] 51 cond << ['spent_on BETWEEN ? AND ?', @from, @to]
53 52
54 TimeEntry.visible_by(User.current) do 53 respond_to do |format|
55 respond_to do |format| 54 format.html {
56 format.html { 55 # Paginate results
57 # Paginate results 56 @entry_count = TimeEntry.visible.count(:include => [:project, :issue], :conditions => cond.conditions)
58 @entry_count = TimeEntry.count(:include => [:project, :issue], :conditions => cond.conditions) 57 @entry_pages = Paginator.new self, @entry_count, per_page_option, params['page']
59 @entry_pages = Paginator.new self, @entry_count, per_page_option, params['page'] 58 @entries = TimeEntry.visible.find(:all,
60 @entries = TimeEntry.find(:all, 59 :include => [:project, :activity, :user, {:issue => :tracker}],
61 :include => [:project, :activity, :user, {:issue => :tracker}], 60 :conditions => cond.conditions,
62 :conditions => cond.conditions, 61 :order => sort_clause,
63 :order => sort_clause, 62 :limit => @entry_pages.items_per_page,
64 :limit => @entry_pages.items_per_page, 63 :offset => @entry_pages.current.offset)
65 :offset => @entry_pages.current.offset) 64 @total_hours = TimeEntry.visible.sum(:hours, :include => [:project, :issue], :conditions => cond.conditions).to_f
66 @total_hours = TimeEntry.sum(:hours, :include => [:project, :issue], :conditions => cond.conditions).to_f 65
67 66 render :layout => !request.xhr?
68 render :layout => !request.xhr? 67 }
69 } 68 format.api {
70 format.api { 69 @entry_count = TimeEntry.visible.count(:include => [:project, :issue], :conditions => cond.conditions)
71 @entry_count = TimeEntry.count(:include => [:project, :issue], :conditions => cond.conditions) 70 @offset, @limit = api_offset_and_limit
72 @entry_pages = Paginator.new self, @entry_count, per_page_option, params['page'] 71 @entries = TimeEntry.visible.find(:all,
73 @entries = TimeEntry.find(:all, 72 :include => [:project, :activity, :user, {:issue => :tracker}],
74 :include => [:project, :activity, :user, {:issue => :tracker}], 73 :conditions => cond.conditions,
75 :conditions => cond.conditions, 74 :order => sort_clause,
76 :order => sort_clause, 75 :limit => @limit,
77 :limit => @entry_pages.items_per_page, 76 :offset => @offset)
78 :offset => @entry_pages.current.offset) 77 }
79 } 78 format.atom {
80 format.atom { 79 entries = TimeEntry.visible.find(:all,
81 entries = TimeEntry.find(:all, 80 :include => [:project, :activity, :user, {:issue => :tracker}],
82 :include => [:project, :activity, :user, {:issue => :tracker}], 81 :conditions => cond.conditions,
83 :conditions => cond.conditions, 82 :order => "#{TimeEntry.table_name}.created_on DESC",
84 :order => "#{TimeEntry.table_name}.created_on DESC", 83 :limit => Setting.feeds_limit.to_i)
85 :limit => Setting.feeds_limit.to_i) 84 render_feed(entries, :title => l(:label_spent_time))
86 render_feed(entries, :title => l(:label_spent_time)) 85 }
87 } 86 format.csv {
88 format.csv { 87 # Export all entries
89 # Export all entries 88 @entries = TimeEntry.visible.find(:all,
90 @entries = TimeEntry.find(:all, 89 :include => [:project, :activity, :user, {:issue => [:tracker, :assigned_to, :priority]}],
91 :include => [:project, :activity, :user, {:issue => [:tracker, :assigned_to, :priority]}], 90 :conditions => cond.conditions,
92 :conditions => cond.conditions, 91 :order => sort_clause)
93 :order => sort_clause) 92 send_data(entries_to_csv(@entries), :type => 'text/csv; header=present', :filename => 'timelog.csv')
94 send_data(entries_to_csv(@entries), :type => 'text/csv; header=present', :filename => 'timelog.csv') 93 }
95 }
96 end
97 end 94 end
98 end 95 end
99 96
100 def show 97 def show
101 respond_to do |format| 98 respond_to do |format|
162 format.api { render_validation_errors(@time_entry) } 159 format.api { render_validation_errors(@time_entry) }
163 end 160 end
164 end 161 end
165 end 162 end
166 163
164 def bulk_edit
165 @available_activities = TimeEntryActivity.shared.active
166 @custom_fields = TimeEntry.first.available_custom_fields
167 end
168
169 def bulk_update
170 attributes = parse_params_for_bulk_time_entry_attributes(params)
171
172 unsaved_time_entry_ids = []
173 @time_entries.each do |time_entry|
174 time_entry.reload
175 time_entry.attributes = attributes
176 call_hook(:controller_time_entries_bulk_edit_before_save, { :params => params, :time_entry => time_entry })
177 unless time_entry.save
178 # Keep unsaved time_entry ids to display them in flash error
179 unsaved_time_entry_ids << time_entry.id
180 end
181 end
182 set_flash_from_bulk_time_entry_save(@time_entries, unsaved_time_entry_ids)
183 redirect_back_or_default({:controller => 'timelog', :action => 'index', :project_id => @projects.first})
184 end
185
167 verify :method => :delete, :only => :destroy, :render => {:nothing => true, :status => :method_not_allowed } 186 verify :method => :delete, :only => :destroy, :render => {:nothing => true, :status => :method_not_allowed }
168 def destroy 187 def destroy
169 if @time_entry.destroy && @time_entry.destroyed? 188 @time_entries.each do |t|
170 respond_to do |format| 189 begin
171 format.html { 190 unless t.destroy && t.destroyed?
172 flash[:notice] = l(:notice_successful_delete) 191 respond_to do |format|
173 redirect_to :back 192 format.html {
174 } 193 flash[:error] = l(:notice_unable_delete_time_entry)
175 format.api { head :ok } 194 redirect_to :back
176 end 195 }
177 else 196 format.api { render_validation_errors(t) }
178 respond_to do |format| 197 end
179 format.html { 198 return
180 flash[:error] = l(:notice_unable_delete_time_entry) 199 end
181 redirect_to :back 200 rescue ::ActionController::RedirectBackError
182 } 201 redirect_to :action => 'index', :project_id => @projects.first
183 format.api { render_validation_errors(@time_entry) } 202 return
184 end 203 end
185 end 204 end
186 rescue ::ActionController::RedirectBackError 205
187 redirect_to :action => 'index', :project_id => @time_entry.project 206 respond_to do |format|
207 format.html {
208 flash[:notice] = l(:notice_successful_delete)
209 redirect_back_or_default(:action => 'index', :project_id => @projects.first)
210 }
211 format.api { head :ok }
212 end
188 end 213 end
189 214
190 private 215 private
191 def find_time_entry 216 def find_time_entry
192 @time_entry = TimeEntry.find(params[:id]) 217 @time_entry = TimeEntry.find(params[:id])
195 return false 220 return false
196 end 221 end
197 @project = @time_entry.project 222 @project = @time_entry.project
198 rescue ActiveRecord::RecordNotFound 223 rescue ActiveRecord::RecordNotFound
199 render_404 224 render_404
225 end
226
227 def find_time_entries
228 @time_entries = TimeEntry.find_all_by_id(params[:id] || params[:ids])
229 raise ActiveRecord::RecordNotFound if @time_entries.empty?
230 @projects = @time_entries.collect(&:project).compact.uniq
231 @project = @projects.first if @projects.size == 1
232 rescue ActiveRecord::RecordNotFound
233 render_404
234 end
235
236 def set_flash_from_bulk_time_entry_save(time_entries, unsaved_time_entry_ids)
237 if unsaved_time_entry_ids.empty?
238 flash[:notice] = l(:notice_successful_update) unless time_entries.empty?
239 else
240 flash[:error] = l(:notice_failed_to_save_time_entries,
241 :count => unsaved_time_entry_ids.size,
242 :total => time_entries.size,
243 :ids => '#' + unsaved_time_entry_ids.join(', #'))
244 end
200 end 245 end
201 246
202 def find_project 247 def find_project
203 if (issue_id = (params[:issue_id] || params[:time_entry] && params[:time_entry][:issue_id])).present? 248 if (issue_id = (params[:issue_id] || params[:time_entry] && params[:time_entry][:issue_id])).present?
204 @issue = Issue.find(issue_id) 249 @issue = Issue.find(issue_id)
267 @from, @to = @to, @from if @from && @to && @from > @to 312 @from, @to = @to, @from if @from && @to && @from > @to
268 @from ||= (TimeEntry.earilest_date_for_project(@project) || Date.today) 313 @from ||= (TimeEntry.earilest_date_for_project(@project) || Date.today)
269 @to ||= (TimeEntry.latest_date_for_project(@project) || Date.today) 314 @to ||= (TimeEntry.latest_date_for_project(@project) || Date.today)
270 end 315 end
271 316
317 def parse_params_for_bulk_time_entry_attributes(params)
318 attributes = (params[:time_entry] || {}).reject {|k,v| v.blank?}
319 attributes.keys.each {|k| attributes[k] = '' if attributes[k] == 'none'}
320 attributes[:custom_field_values].reject! {|k,v| v.blank?} if attributes[:custom_field_values]
321 attributes
322 end
272 end 323 end