##// END OF EJS Templates
Fixed: 500 error when validation fails on issue edition with no custom fields....
Jean-Philippe Lang -
r970:bd8eded6702a
parent child
Show More
@@ -1,250 +1,251
1 # redMine - project management software
1 # redMine - project management software
2 # Copyright (C) 2006-2007 Jean-Philippe Lang
2 # Copyright (C) 2006-2007 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 IssuesController < ApplicationController
18 class IssuesController < ApplicationController
19 layout 'base'
19 layout 'base'
20 before_filter :find_project, :authorize, :except => [:index, :changes, :preview]
20 before_filter :find_project, :authorize, :except => [:index, :changes, :preview]
21 before_filter :find_optional_project, :only => [:index, :changes]
21 before_filter :find_optional_project, :only => [:index, :changes]
22 accept_key_auth :index, :changes
22 accept_key_auth :index, :changes
23
23
24 cache_sweeper :issue_sweeper, :only => [ :edit, :change_status, :destroy ]
24 cache_sweeper :issue_sweeper, :only => [ :edit, :change_status, :destroy ]
25
25
26 helper :projects
26 helper :projects
27 include ProjectsHelper
27 include ProjectsHelper
28 helper :custom_fields
28 helper :custom_fields
29 include CustomFieldsHelper
29 include CustomFieldsHelper
30 helper :ifpdf
30 helper :ifpdf
31 include IfpdfHelper
31 include IfpdfHelper
32 helper :issue_relations
32 helper :issue_relations
33 include IssueRelationsHelper
33 include IssueRelationsHelper
34 helper :watchers
34 helper :watchers
35 include WatchersHelper
35 include WatchersHelper
36 helper :attachments
36 helper :attachments
37 include AttachmentsHelper
37 include AttachmentsHelper
38 helper :queries
38 helper :queries
39 helper :sort
39 helper :sort
40 include SortHelper
40 include SortHelper
41 include IssuesHelper
41 include IssuesHelper
42
42
43 def index
43 def index
44 sort_init "#{Issue.table_name}.id", "desc"
44 sort_init "#{Issue.table_name}.id", "desc"
45 sort_update
45 sort_update
46 retrieve_query
46 retrieve_query
47 if @query.valid?
47 if @query.valid?
48 limit = %w(pdf csv).include?(params[:format]) ? Setting.issues_export_limit.to_i : 25
48 limit = %w(pdf csv).include?(params[:format]) ? Setting.issues_export_limit.to_i : 25
49 @issue_count = Issue.count(:include => [:status, :project], :conditions => @query.statement)
49 @issue_count = Issue.count(:include => [:status, :project], :conditions => @query.statement)
50 @issue_pages = Paginator.new self, @issue_count, limit, params['page']
50 @issue_pages = Paginator.new self, @issue_count, limit, params['page']
51 @issues = Issue.find :all, :order => sort_clause,
51 @issues = Issue.find :all, :order => sort_clause,
52 :include => [ :assigned_to, :status, :tracker, :project, :priority, :category, :fixed_version ],
52 :include => [ :assigned_to, :status, :tracker, :project, :priority, :category, :fixed_version ],
53 :conditions => @query.statement,
53 :conditions => @query.statement,
54 :limit => limit,
54 :limit => limit,
55 :offset => @issue_pages.current.offset
55 :offset => @issue_pages.current.offset
56 respond_to do |format|
56 respond_to do |format|
57 format.html { render :template => 'issues/index.rhtml', :layout => !request.xhr? }
57 format.html { render :template => 'issues/index.rhtml', :layout => !request.xhr? }
58 format.atom { render_feed(@issues, :title => l(:label_issue_plural)) }
58 format.atom { render_feed(@issues, :title => l(:label_issue_plural)) }
59 format.csv { send_data(issues_to_csv(@issues, @project).read, :type => 'text/csv; header=present', :filename => 'export.csv') }
59 format.csv { send_data(issues_to_csv(@issues, @project).read, :type => 'text/csv; header=present', :filename => 'export.csv') }
60 format.pdf { send_data(render(:template => 'issues/index.rfpdf', :layout => false), :type => 'application/pdf', :filename => 'export.pdf') }
60 format.pdf { send_data(render(:template => 'issues/index.rfpdf', :layout => false), :type => 'application/pdf', :filename => 'export.pdf') }
61 end
61 end
62 else
62 else
63 # Send html if the query is not valid
63 # Send html if the query is not valid
64 render(:template => 'issues/index.rhtml', :layout => !request.xhr?)
64 render(:template => 'issues/index.rhtml', :layout => !request.xhr?)
65 end
65 end
66 end
66 end
67
67
68 def changes
68 def changes
69 sort_init "#{Issue.table_name}.id", "desc"
69 sort_init "#{Issue.table_name}.id", "desc"
70 sort_update
70 sort_update
71 retrieve_query
71 retrieve_query
72 if @query.valid?
72 if @query.valid?
73 @changes = Journal.find :all, :include => [ :details, :user, {:issue => [:project, :author, :tracker, :status]} ],
73 @changes = Journal.find :all, :include => [ :details, :user, {:issue => [:project, :author, :tracker, :status]} ],
74 :conditions => @query.statement,
74 :conditions => @query.statement,
75 :limit => 25,
75 :limit => 25,
76 :order => "#{Journal.table_name}.created_on DESC"
76 :order => "#{Journal.table_name}.created_on DESC"
77 end
77 end
78 @title = (@project ? @project.name : Setting.app_title) + ": " + (@query.new_record? ? l(:label_changes_details) : @query.name)
78 @title = (@project ? @project.name : Setting.app_title) + ": " + (@query.new_record? ? l(:label_changes_details) : @query.name)
79 render :layout => false, :content_type => 'application/atom+xml'
79 render :layout => false, :content_type => 'application/atom+xml'
80 end
80 end
81
81
82 def show
82 def show
83 @custom_values = @issue.custom_values.find(:all, :include => :custom_field, :order => "#{CustomField.table_name}.position")
83 @custom_values = @issue.custom_values.find(:all, :include => :custom_field, :order => "#{CustomField.table_name}.position")
84 @journals = @issue.journals.find(:all, :include => [:user, :details], :order => "#{Journal.table_name}.created_on ASC")
84 @journals = @issue.journals.find(:all, :include => [:user, :details], :order => "#{Journal.table_name}.created_on ASC")
85 @status_options = @issue.status.find_new_statuses_allowed_to(User.current.role_for_project(@project), @issue.tracker)
85 @status_options = @issue.status.find_new_statuses_allowed_to(User.current.role_for_project(@project), @issue.tracker)
86 respond_to do |format|
86 respond_to do |format|
87 format.html { render :template => 'issues/show.rhtml' }
87 format.html { render :template => 'issues/show.rhtml' }
88 format.pdf { send_data(render(:template => 'issues/show.rfpdf', :layout => false), :type => 'application/pdf', :filename => "#{@project.identifier}-#{@issue.id}.pdf") }
88 format.pdf { send_data(render(:template => 'issues/show.rfpdf', :layout => false), :type => 'application/pdf', :filename => "#{@project.identifier}-#{@issue.id}.pdf") }
89 end
89 end
90 end
90 end
91
91
92 def edit
92 def edit
93 @priorities = Enumeration::get_values('IPRI')
93 @priorities = Enumeration::get_values('IPRI')
94 @custom_values = []
94 if request.get?
95 if request.get?
95 @custom_values = @project.custom_fields_for_issues(@issue.tracker).collect { |x| @issue.custom_values.find_by_custom_field_id(x.id) || CustomValue.new(:custom_field => x, :customized => @issue) }
96 @custom_values = @project.custom_fields_for_issues(@issue.tracker).collect { |x| @issue.custom_values.find_by_custom_field_id(x.id) || CustomValue.new(:custom_field => x, :customized => @issue) }
96 else
97 else
97 begin
98 begin
98 @issue.init_journal(User.current)
99 @issue.init_journal(User.current)
99 # Retrieve custom fields and values
100 # Retrieve custom fields and values
100 if params["custom_fields"]
101 if params["custom_fields"]
101 @custom_values = @project.custom_fields_for_issues(@issue.tracker).collect { |x| CustomValue.new(:custom_field => x, :customized => @issue, :value => params["custom_fields"][x.id.to_s]) }
102 @custom_values = @project.custom_fields_for_issues(@issue.tracker).collect { |x| CustomValue.new(:custom_field => x, :customized => @issue, :value => params["custom_fields"][x.id.to_s]) }
102 @issue.custom_values = @custom_values
103 @issue.custom_values = @custom_values
103 end
104 end
104 @issue.attributes = params[:issue]
105 @issue.attributes = params[:issue]
105 if @issue.save
106 if @issue.save
106 flash[:notice] = l(:notice_successful_update)
107 flash[:notice] = l(:notice_successful_update)
107 redirect_to(params[:back_to] || {:action => 'show', :id => @issue})
108 redirect_to(params[:back_to] || {:action => 'show', :id => @issue})
108 end
109 end
109 rescue ActiveRecord::StaleObjectError
110 rescue ActiveRecord::StaleObjectError
110 # Optimistic locking exception
111 # Optimistic locking exception
111 flash[:error] = l(:notice_locking_conflict)
112 flash[:error] = l(:notice_locking_conflict)
112 end
113 end
113 end
114 end
114 end
115 end
115
116
116 def add_note
117 def add_note
117 journal = @issue.init_journal(User.current, params[:notes])
118 journal = @issue.init_journal(User.current, params[:notes])
118 params[:attachments].each { |file|
119 params[:attachments].each { |file|
119 next unless file.size > 0
120 next unless file.size > 0
120 a = Attachment.create(:container => @issue, :file => file, :author => User.current)
121 a = Attachment.create(:container => @issue, :file => file, :author => User.current)
121 journal.details << JournalDetail.new(:property => 'attachment',
122 journal.details << JournalDetail.new(:property => 'attachment',
122 :prop_key => a.id,
123 :prop_key => a.id,
123 :value => a.filename) unless a.new_record?
124 :value => a.filename) unless a.new_record?
124 } if params[:attachments] and params[:attachments].is_a? Array
125 } if params[:attachments] and params[:attachments].is_a? Array
125 if journal.save
126 if journal.save
126 flash[:notice] = l(:notice_successful_update)
127 flash[:notice] = l(:notice_successful_update)
127 Mailer.deliver_issue_edit(journal) if Setting.notified_events.include?('issue_updated')
128 Mailer.deliver_issue_edit(journal) if Setting.notified_events.include?('issue_updated')
128 redirect_to :action => 'show', :id => @issue
129 redirect_to :action => 'show', :id => @issue
129 return
130 return
130 end
131 end
131 show
132 show
132 end
133 end
133
134
134 def change_status
135 def change_status
135 @status_options = @issue.status.find_new_statuses_allowed_to(User.current.role_for_project(@project), @issue.tracker)
136 @status_options = @issue.status.find_new_statuses_allowed_to(User.current.role_for_project(@project), @issue.tracker)
136 @new_status = IssueStatus.find(params[:new_status_id])
137 @new_status = IssueStatus.find(params[:new_status_id])
137 if params[:confirm]
138 if params[:confirm]
138 begin
139 begin
139 journal = @issue.init_journal(User.current, params[:notes])
140 journal = @issue.init_journal(User.current, params[:notes])
140 @issue.status = @new_status
141 @issue.status = @new_status
141 if @issue.update_attributes(params[:issue])
142 if @issue.update_attributes(params[:issue])
142 # Save attachments
143 # Save attachments
143 params[:attachments].each { |file|
144 params[:attachments].each { |file|
144 next unless file.size > 0
145 next unless file.size > 0
145 a = Attachment.create(:container => @issue, :file => file, :author => User.current)
146 a = Attachment.create(:container => @issue, :file => file, :author => User.current)
146 journal.details << JournalDetail.new(:property => 'attachment',
147 journal.details << JournalDetail.new(:property => 'attachment',
147 :prop_key => a.id,
148 :prop_key => a.id,
148 :value => a.filename) unless a.new_record?
149 :value => a.filename) unless a.new_record?
149 } if params[:attachments] and params[:attachments].is_a? Array
150 } if params[:attachments] and params[:attachments].is_a? Array
150
151
151 # Log time
152 # Log time
152 if current_role.allowed_to?(:log_time)
153 if current_role.allowed_to?(:log_time)
153 @time_entry ||= TimeEntry.new(:project => @project, :issue => @issue, :user => User.current, :spent_on => Date.today)
154 @time_entry ||= TimeEntry.new(:project => @project, :issue => @issue, :user => User.current, :spent_on => Date.today)
154 @time_entry.attributes = params[:time_entry]
155 @time_entry.attributes = params[:time_entry]
155 @time_entry.save
156 @time_entry.save
156 end
157 end
157
158
158 flash[:notice] = l(:notice_successful_update)
159 flash[:notice] = l(:notice_successful_update)
159 Mailer.deliver_issue_edit(journal) if Setting.notified_events.include?('issue_updated')
160 Mailer.deliver_issue_edit(journal) if Setting.notified_events.include?('issue_updated')
160 redirect_to :action => 'show', :id => @issue
161 redirect_to :action => 'show', :id => @issue
161 end
162 end
162 rescue ActiveRecord::StaleObjectError
163 rescue ActiveRecord::StaleObjectError
163 # Optimistic locking exception
164 # Optimistic locking exception
164 flash[:error] = l(:notice_locking_conflict)
165 flash[:error] = l(:notice_locking_conflict)
165 end
166 end
166 end
167 end
167 @assignable_to = @project.members.find(:all, :include => :user).collect{ |m| m.user }
168 @assignable_to = @project.members.find(:all, :include => :user).collect{ |m| m.user }
168 @activities = Enumeration::get_values('ACTI')
169 @activities = Enumeration::get_values('ACTI')
169 end
170 end
170
171
171 def destroy
172 def destroy
172 @issue.destroy
173 @issue.destroy
173 redirect_to :action => 'index', :project_id => @project
174 redirect_to :action => 'index', :project_id => @project
174 end
175 end
175
176
176 def destroy_attachment
177 def destroy_attachment
177 a = @issue.attachments.find(params[:attachment_id])
178 a = @issue.attachments.find(params[:attachment_id])
178 a.destroy
179 a.destroy
179 journal = @issue.init_journal(User.current)
180 journal = @issue.init_journal(User.current)
180 journal.details << JournalDetail.new(:property => 'attachment',
181 journal.details << JournalDetail.new(:property => 'attachment',
181 :prop_key => a.id,
182 :prop_key => a.id,
182 :old_value => a.filename)
183 :old_value => a.filename)
183 journal.save
184 journal.save
184 redirect_to :action => 'show', :id => @issue
185 redirect_to :action => 'show', :id => @issue
185 end
186 end
186
187
187 def context_menu
188 def context_menu
188 @priorities = Enumeration.get_values('IPRI').reverse
189 @priorities = Enumeration.get_values('IPRI').reverse
189 @statuses = IssueStatus.find(:all, :order => 'position')
190 @statuses = IssueStatus.find(:all, :order => 'position')
190 @allowed_statuses = @issue.status.find_new_statuses_allowed_to(User.current.role_for_project(@project), @issue.tracker)
191 @allowed_statuses = @issue.status.find_new_statuses_allowed_to(User.current.role_for_project(@project), @issue.tracker)
191 @assignables = @issue.assignable_users
192 @assignables = @issue.assignable_users
192 @assignables << @issue.assigned_to if @issue.assigned_to && !@assignables.include?(@issue.assigned_to)
193 @assignables << @issue.assigned_to if @issue.assigned_to && !@assignables.include?(@issue.assigned_to)
193 @can = {:edit => User.current.allowed_to?(:edit_issues, @project),
194 @can = {:edit => User.current.allowed_to?(:edit_issues, @project),
194 :change_status => User.current.allowed_to?(:change_issue_status, @project),
195 :change_status => User.current.allowed_to?(:change_issue_status, @project),
195 :add => User.current.allowed_to?(:add_issues, @project),
196 :add => User.current.allowed_to?(:add_issues, @project),
196 :move => User.current.allowed_to?(:move_issues, @project),
197 :move => User.current.allowed_to?(:move_issues, @project),
197 :copy => (@project.trackers.include?(@issue.tracker) && User.current.allowed_to?(:add_issues, @project)),
198 :copy => (@project.trackers.include?(@issue.tracker) && User.current.allowed_to?(:add_issues, @project)),
198 :delete => User.current.allowed_to?(:delete_issues, @project)}
199 :delete => User.current.allowed_to?(:delete_issues, @project)}
199 render :layout => false
200 render :layout => false
200 end
201 end
201
202
202 def preview
203 def preview
203 issue = Issue.find_by_id(params[:id])
204 issue = Issue.find_by_id(params[:id])
204 @attachements = issue.attachments if issue
205 @attachements = issue.attachments if issue
205 @text = params[:issue][:description]
206 @text = params[:issue][:description]
206 render :partial => 'common/preview'
207 render :partial => 'common/preview'
207 end
208 end
208
209
209 private
210 private
210 def find_project
211 def find_project
211 @issue = Issue.find(params[:id], :include => [:project, :tracker, :status, :author, :priority, :category])
212 @issue = Issue.find(params[:id], :include => [:project, :tracker, :status, :author, :priority, :category])
212 @project = @issue.project
213 @project = @issue.project
213 rescue ActiveRecord::RecordNotFound
214 rescue ActiveRecord::RecordNotFound
214 render_404
215 render_404
215 end
216 end
216
217
217 def find_optional_project
218 def find_optional_project
218 return true unless params[:project_id]
219 return true unless params[:project_id]
219 @project = Project.find(params[:project_id])
220 @project = Project.find(params[:project_id])
220 authorize
221 authorize
221 rescue ActiveRecord::RecordNotFound
222 rescue ActiveRecord::RecordNotFound
222 render_404
223 render_404
223 end
224 end
224
225
225 # Retrieve query from session or build a new query
226 # Retrieve query from session or build a new query
226 def retrieve_query
227 def retrieve_query
227 if params[:query_id]
228 if params[:query_id]
228 @query = Query.find(params[:query_id], :conditions => {:project_id => (@project ? @project.id : nil)})
229 @query = Query.find(params[:query_id], :conditions => {:project_id => (@project ? @project.id : nil)})
229 session[:query] = @query
230 session[:query] = @query
230 else
231 else
231 if params[:set_filter] or !session[:query] or session[:query].project != @project
232 if params[:set_filter] or !session[:query] or session[:query].project != @project
232 # Give it a name, required to be valid
233 # Give it a name, required to be valid
233 @query = Query.new(:name => "_")
234 @query = Query.new(:name => "_")
234 @query.project = @project
235 @query.project = @project
235 if params[:fields] and params[:fields].is_a? Array
236 if params[:fields] and params[:fields].is_a? Array
236 params[:fields].each do |field|
237 params[:fields].each do |field|
237 @query.add_filter(field, params[:operators][field], params[:values][field])
238 @query.add_filter(field, params[:operators][field], params[:values][field])
238 end
239 end
239 else
240 else
240 @query.available_filters.keys.each do |field|
241 @query.available_filters.keys.each do |field|
241 @query.add_short_filter(field, params[field]) if params[field]
242 @query.add_short_filter(field, params[field]) if params[field]
242 end
243 end
243 end
244 end
244 session[:query] = @query
245 session[:query] = @query
245 else
246 else
246 @query = session[:query]
247 @query = session[:query]
247 end
248 end
248 end
249 end
249 end
250 end
250 end
251 end
General Comments 0
You need to be logged in to leave comments. Login now