Mercurial > hg > soundsoftware-site
comparison app/controllers/timelog_controller.rb @ 511:107d36338b70 live
Merge from branch "cannam"
author | Chris Cannam |
---|---|
date | Thu, 14 Jul 2011 10:43:07 +0100 |
parents | 0c939c159af4 |
children | cbb26bc654de |
comparison
equal
deleted
inserted
replaced
451:a9f6345cb43d | 511:107d36338b70 |
---|---|
1 # redMine - project management software | 1 # Redmine - project management software |
2 # Copyright (C) 2006-2007 Jean-Philippe Lang | 2 # Copyright (C) 2006-2011 Jean-Philippe Lang |
3 # | 3 # |
4 # This program is free software; you can redistribute it and/or | 4 # This program is free software; you can redistribute it and/or |
5 # modify it under the terms of the GNU General Public License | 5 # modify it under the terms of the GNU General Public License |
6 # as published by the Free Software Foundation; either version 2 | 6 # as published by the Free Software Foundation; either version 2 |
7 # of the License, or (at your option) any later version. | 7 # of the License, or (at your option) any later version. |
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 => [: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 | 25 accept_rss_auth :index |
26 accept_api_auth :index, :show, :create, :update, :destroy | |
27 | |
25 helper :sort | 28 helper :sort |
26 include SortHelper | 29 include SortHelper |
27 helper :issues | 30 helper :issues |
28 include TimelogHelper | 31 include TimelogHelper |
29 helper :custom_fields | 32 helper :custom_fields |
37 'project' => "#{Project.table_name}.name", | 40 'project' => "#{Project.table_name}.name", |
38 'issue' => 'issue_id', | 41 'issue' => 'issue_id', |
39 'hours' => 'hours' | 42 'hours' => 'hours' |
40 | 43 |
41 cond = ARCondition.new | 44 cond = ARCondition.new |
42 if @project.nil? | 45 if @issue |
43 cond << Project.allowed_to_condition(User.current, :view_time_entries) | 46 cond << "#{Issue.table_name}.root_id = #{@issue.root_id} AND #{Issue.table_name}.lft >= #{@issue.lft} AND #{Issue.table_name}.rgt <= #{@issue.rgt}" |
44 elsif @issue.nil? | 47 elsif @project |
45 cond << @project.project_condition(Setting.display_subprojects_issues?) | 48 cond << @project.project_condition(Setting.display_subprojects_issues?) |
46 else | |
47 cond << "#{Issue.table_name}.root_id = #{@issue.root_id} AND #{Issue.table_name}.lft >= #{@issue.lft} AND #{Issue.table_name}.rgt <= #{@issue.rgt}" | |
48 end | 49 end |
49 | 50 |
50 retrieve_date_range | 51 retrieve_date_range |
51 cond << ['spent_on BETWEEN ? AND ?', @from, @to] | 52 cond << ['spent_on BETWEEN ? AND ?', @from, @to] |
52 | 53 |
53 TimeEntry.visible_by(User.current) do | 54 respond_to do |format| |
54 respond_to do |format| | 55 format.html { |
55 format.html { | 56 # Paginate results |
56 # Paginate results | 57 @entry_count = TimeEntry.visible.count(:include => [:project, :issue], :conditions => cond.conditions) |
57 @entry_count = TimeEntry.count(:include => [:project, :issue], :conditions => cond.conditions) | 58 @entry_pages = Paginator.new self, @entry_count, per_page_option, params['page'] |
58 @entry_pages = Paginator.new self, @entry_count, per_page_option, params['page'] | 59 @entries = TimeEntry.visible.find(:all, |
59 @entries = TimeEntry.find(:all, | 60 :include => [:project, :activity, :user, {:issue => :tracker}], |
60 :include => [:project, :activity, :user, {:issue => :tracker}], | 61 :conditions => cond.conditions, |
61 :conditions => cond.conditions, | 62 :order => sort_clause, |
62 :order => sort_clause, | 63 :limit => @entry_pages.items_per_page, |
63 :limit => @entry_pages.items_per_page, | 64 :offset => @entry_pages.current.offset) |
64 :offset => @entry_pages.current.offset) | 65 @total_hours = TimeEntry.visible.sum(:hours, :include => [:project, :issue], :conditions => cond.conditions).to_f |
65 @total_hours = TimeEntry.sum(:hours, :include => [:project, :issue], :conditions => cond.conditions).to_f | 66 |
66 | 67 render :layout => !request.xhr? |
67 render :layout => !request.xhr? | 68 } |
68 } | 69 format.api { |
69 format.atom { | 70 @entry_count = TimeEntry.visible.count(:include => [:project, :issue], :conditions => cond.conditions) |
70 entries = TimeEntry.find(:all, | 71 @offset, @limit = api_offset_and_limit |
71 :include => [:project, :activity, :user, {:issue => :tracker}], | 72 @entries = TimeEntry.visible.find(:all, |
72 :conditions => cond.conditions, | 73 :include => [:project, :activity, :user, {:issue => :tracker}], |
73 :order => "#{TimeEntry.table_name}.created_on DESC", | 74 :conditions => cond.conditions, |
74 :limit => Setting.feeds_limit.to_i) | 75 :order => sort_clause, |
75 render_feed(entries, :title => l(:label_spent_time)) | 76 :limit => @limit, |
76 } | 77 :offset => @offset) |
77 format.csv { | 78 } |
78 # Export all entries | 79 format.atom { |
79 @entries = TimeEntry.find(:all, | 80 entries = TimeEntry.visible.find(:all, |
80 :include => [:project, :activity, :user, {:issue => [:tracker, :assigned_to, :priority]}], | 81 :include => [:project, :activity, :user, {:issue => :tracker}], |
81 :conditions => cond.conditions, | 82 :conditions => cond.conditions, |
82 :order => sort_clause) | 83 :order => "#{TimeEntry.table_name}.created_on DESC", |
83 send_data(entries_to_csv(@entries), :type => 'text/csv; header=present', :filename => 'timelog.csv') | 84 :limit => Setting.feeds_limit.to_i) |
84 } | 85 render_feed(entries, :title => l(:label_spent_time)) |
85 end | 86 } |
87 format.csv { | |
88 # Export all entries | |
89 @entries = TimeEntry.visible.find(:all, | |
90 :include => [:project, :activity, :user, {:issue => [:tracker, :assigned_to, :priority]}], | |
91 :conditions => cond.conditions, | |
92 :order => sort_clause) | |
93 send_data(entries_to_csv(@entries), :type => 'text/csv; header=present', :filename => 'timelog.csv') | |
94 } | |
95 end | |
96 end | |
97 | |
98 def show | |
99 respond_to do |format| | |
100 # TODO: Implement html response | |
101 format.html { render :nothing => true, :status => 406 } | |
102 format.api | |
86 end | 103 end |
87 end | 104 end |
88 | 105 |
89 def new | 106 def new |
90 @time_entry ||= TimeEntry.new(:project => @project, :issue => @issue, :user => User.current, :spent_on => User.current.today) | 107 @time_entry ||= TimeEntry.new(:project => @project, :issue => @issue, :user => User.current, :spent_on => User.current.today) |
100 @time_entry.attributes = params[:time_entry] | 117 @time_entry.attributes = params[:time_entry] |
101 | 118 |
102 call_hook(:controller_timelog_edit_before_save, { :params => params, :time_entry => @time_entry }) | 119 call_hook(:controller_timelog_edit_before_save, { :params => params, :time_entry => @time_entry }) |
103 | 120 |
104 if @time_entry.save | 121 if @time_entry.save |
105 flash[:notice] = l(:notice_successful_update) | 122 respond_to do |format| |
106 redirect_back_or_default :action => 'index', :project_id => @time_entry.project | 123 format.html { |
107 else | 124 flash[:notice] = l(:notice_successful_update) |
108 render :action => 'edit' | 125 redirect_back_or_default :action => 'index', :project_id => @time_entry.project |
126 } | |
127 format.api { render :action => 'show', :status => :created, :location => time_entry_url(@time_entry) } | |
128 end | |
129 else | |
130 respond_to do |format| | |
131 format.html { render :action => 'edit' } | |
132 format.api { render_validation_errors(@time_entry) } | |
133 end | |
109 end | 134 end |
110 end | 135 end |
111 | 136 |
112 def edit | 137 def edit |
113 @time_entry.attributes = params[:time_entry] | 138 @time_entry.attributes = params[:time_entry] |
120 @time_entry.attributes = params[:time_entry] | 145 @time_entry.attributes = params[:time_entry] |
121 | 146 |
122 call_hook(:controller_timelog_edit_before_save, { :params => params, :time_entry => @time_entry }) | 147 call_hook(:controller_timelog_edit_before_save, { :params => params, :time_entry => @time_entry }) |
123 | 148 |
124 if @time_entry.save | 149 if @time_entry.save |
125 flash[:notice] = l(:notice_successful_update) | 150 respond_to do |format| |
126 redirect_back_or_default :action => 'index', :project_id => @time_entry.project | 151 format.html { |
127 else | 152 flash[:notice] = l(:notice_successful_update) |
128 render :action => 'edit' | 153 redirect_back_or_default :action => 'index', :project_id => @time_entry.project |
154 } | |
155 format.api { head :ok } | |
156 end | |
157 else | |
158 respond_to do |format| | |
159 format.html { render :action => 'edit' } | |
160 format.api { render_validation_errors(@time_entry) } | |
161 end | |
129 end | 162 end |
163 end | |
164 | |
165 def bulk_edit | |
166 @available_activities = TimeEntryActivity.shared.active | |
167 @custom_fields = TimeEntry.first.available_custom_fields | |
168 end | |
169 | |
170 def bulk_update | |
171 attributes = parse_params_for_bulk_time_entry_attributes(params) | |
172 | |
173 unsaved_time_entry_ids = [] | |
174 @time_entries.each do |time_entry| | |
175 time_entry.reload | |
176 time_entry.attributes = attributes | |
177 call_hook(:controller_time_entries_bulk_edit_before_save, { :params => params, :time_entry => time_entry }) | |
178 unless time_entry.save | |
179 # Keep unsaved time_entry ids to display them in flash error | |
180 unsaved_time_entry_ids << time_entry.id | |
181 end | |
182 end | |
183 set_flash_from_bulk_time_entry_save(@time_entries, unsaved_time_entry_ids) | |
184 redirect_back_or_default({:controller => 'timelog', :action => 'index', :project_id => @projects.first}) | |
130 end | 185 end |
131 | 186 |
132 verify :method => :delete, :only => :destroy, :render => {:nothing => true, :status => :method_not_allowed } | 187 verify :method => :delete, :only => :destroy, :render => {:nothing => true, :status => :method_not_allowed } |
133 def destroy | 188 def destroy |
134 if @time_entry.destroy && @time_entry.destroyed? | 189 @time_entries.each do |t| |
135 flash[:notice] = l(:notice_successful_delete) | 190 begin |
136 else | 191 unless t.destroy && t.destroyed? |
137 flash[:error] = l(:notice_unable_delete_time_entry) | 192 respond_to do |format| |
138 end | 193 format.html { |
139 redirect_to :back | 194 flash[:error] = l(:notice_unable_delete_time_entry) |
140 rescue ::ActionController::RedirectBackError | 195 redirect_to :back |
141 redirect_to :action => 'index', :project_id => @time_entry.project | 196 } |
197 format.api { render_validation_errors(t) } | |
198 end | |
199 return | |
200 end | |
201 rescue ::ActionController::RedirectBackError | |
202 redirect_to :action => 'index', :project_id => @projects.first | |
203 return | |
204 end | |
205 end | |
206 | |
207 respond_to do |format| | |
208 format.html { | |
209 flash[:notice] = l(:notice_successful_delete) | |
210 redirect_back_or_default(:action => 'index', :project_id => @projects.first) | |
211 } | |
212 format.api { head :ok } | |
213 end | |
142 end | 214 end |
143 | 215 |
144 private | 216 private |
145 def find_time_entry | 217 def find_time_entry |
146 @time_entry = TimeEntry.find(params[:id]) | 218 @time_entry = TimeEntry.find(params[:id]) |
151 @project = @time_entry.project | 223 @project = @time_entry.project |
152 rescue ActiveRecord::RecordNotFound | 224 rescue ActiveRecord::RecordNotFound |
153 render_404 | 225 render_404 |
154 end | 226 end |
155 | 227 |
228 def find_time_entries | |
229 @time_entries = TimeEntry.find_all_by_id(params[:id] || params[:ids]) | |
230 raise ActiveRecord::RecordNotFound if @time_entries.empty? | |
231 @projects = @time_entries.collect(&:project).compact.uniq | |
232 @project = @projects.first if @projects.size == 1 | |
233 rescue ActiveRecord::RecordNotFound | |
234 render_404 | |
235 end | |
236 | |
237 def set_flash_from_bulk_time_entry_save(time_entries, unsaved_time_entry_ids) | |
238 if unsaved_time_entry_ids.empty? | |
239 flash[:notice] = l(:notice_successful_update) unless time_entries.empty? | |
240 else | |
241 flash[:error] = l(:notice_failed_to_save_time_entries, | |
242 :count => unsaved_time_entry_ids.size, | |
243 :total => time_entries.size, | |
244 :ids => '#' + unsaved_time_entry_ids.join(', #')) | |
245 end | |
246 end | |
247 | |
156 def find_project | 248 def find_project |
157 if params[:issue_id] | 249 if (issue_id = (params[:issue_id] || params[:time_entry] && params[:time_entry][:issue_id])).present? |
158 @issue = Issue.find(params[:issue_id]) | 250 @issue = Issue.find(issue_id) |
159 @project = @issue.project | 251 @project = @issue.project |
160 elsif params[:project_id] | 252 elsif (project_id = (params[:project_id] || params[:time_entry] && params[:time_entry][:project_id])).present? |
161 @project = Project.find(params[:project_id]) | 253 @project = Project.find(project_id) |
162 else | 254 else |
163 render_404 | 255 render_404 |
164 return false | 256 return false |
165 end | 257 end |
166 rescue ActiveRecord::RecordNotFound | 258 rescue ActiveRecord::RecordNotFound |
221 @from, @to = @to, @from if @from && @to && @from > @to | 313 @from, @to = @to, @from if @from && @to && @from > @to |
222 @from ||= (TimeEntry.earilest_date_for_project(@project) || Date.today) | 314 @from ||= (TimeEntry.earilest_date_for_project(@project) || Date.today) |
223 @to ||= (TimeEntry.latest_date_for_project(@project) || Date.today) | 315 @to ||= (TimeEntry.latest_date_for_project(@project) || Date.today) |
224 end | 316 end |
225 | 317 |
318 def parse_params_for_bulk_time_entry_attributes(params) | |
319 attributes = (params[:time_entry] || {}).reject {|k,v| v.blank?} | |
320 attributes.keys.each {|k| attributes[k] = '' if attributes[k] == 'none'} | |
321 attributes[:custom_field_values].reject! {|k,v| v.blank?} if attributes[:custom_field_values] | |
322 attributes | |
323 end | |
226 end | 324 end |