##// END OF EJS Templates
Fixed that updating the issue form was broken by r4011 when user is not allowed to add issues (#13188)....
Jean-Philippe Lang -
r11175:7799788b3de6
parent child
Show More
@@ -1,435 +1,439
1 # Redmine - project management software
1 # Redmine - project management software
2 # Copyright (C) 2006-2013 Jean-Philippe Lang
2 # Copyright (C) 2006-2013 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 menu_item :new_issue, :only => [:new, :create]
19 menu_item :new_issue, :only => [:new, :create]
20 default_search_scope :issues
20 default_search_scope :issues
21
21
22 before_filter :find_issue, :only => [:show, :edit, :update]
22 before_filter :find_issue, :only => [:show, :edit, :update]
23 before_filter :find_issues, :only => [:bulk_edit, :bulk_update, :destroy]
23 before_filter :find_issues, :only => [:bulk_edit, :bulk_update, :destroy]
24 before_filter :find_project, :only => [:new, :create]
24 before_filter :find_project, :only => [:new, :create, :update_form]
25 before_filter :authorize, :except => [:index]
25 before_filter :authorize, :except => [:index]
26 before_filter :find_optional_project, :only => [:index]
26 before_filter :find_optional_project, :only => [:index]
27 before_filter :check_for_default_issue_status, :only => [:new, :create]
27 before_filter :check_for_default_issue_status, :only => [:new, :create]
28 before_filter :build_new_issue_from_params, :only => [:new, :create]
28 before_filter :build_new_issue_from_params, :only => [:new, :create, :update_form]
29 accept_rss_auth :index, :show
29 accept_rss_auth :index, :show
30 accept_api_auth :index, :show, :create, :update, :destroy
30 accept_api_auth :index, :show, :create, :update, :destroy
31
31
32 rescue_from Query::StatementInvalid, :with => :query_statement_invalid
32 rescue_from Query::StatementInvalid, :with => :query_statement_invalid
33
33
34 helper :journals
34 helper :journals
35 helper :projects
35 helper :projects
36 include ProjectsHelper
36 include ProjectsHelper
37 helper :custom_fields
37 helper :custom_fields
38 include CustomFieldsHelper
38 include CustomFieldsHelper
39 helper :issue_relations
39 helper :issue_relations
40 include IssueRelationsHelper
40 include IssueRelationsHelper
41 helper :watchers
41 helper :watchers
42 include WatchersHelper
42 include WatchersHelper
43 helper :attachments
43 helper :attachments
44 include AttachmentsHelper
44 include AttachmentsHelper
45 helper :queries
45 helper :queries
46 include QueriesHelper
46 include QueriesHelper
47 helper :repositories
47 helper :repositories
48 include RepositoriesHelper
48 include RepositoriesHelper
49 helper :sort
49 helper :sort
50 include SortHelper
50 include SortHelper
51 include IssuesHelper
51 include IssuesHelper
52 helper :timelog
52 helper :timelog
53 include Redmine::Export::PDF
53 include Redmine::Export::PDF
54
54
55 def index
55 def index
56 retrieve_query
56 retrieve_query
57 sort_init(@query.sort_criteria.empty? ? [['id', 'desc']] : @query.sort_criteria)
57 sort_init(@query.sort_criteria.empty? ? [['id', 'desc']] : @query.sort_criteria)
58 sort_update(@query.sortable_columns)
58 sort_update(@query.sortable_columns)
59 @query.sort_criteria = sort_criteria.to_a
59 @query.sort_criteria = sort_criteria.to_a
60
60
61 if @query.valid?
61 if @query.valid?
62 case params[:format]
62 case params[:format]
63 when 'csv', 'pdf'
63 when 'csv', 'pdf'
64 @limit = Setting.issues_export_limit.to_i
64 @limit = Setting.issues_export_limit.to_i
65 when 'atom'
65 when 'atom'
66 @limit = Setting.feeds_limit.to_i
66 @limit = Setting.feeds_limit.to_i
67 when 'xml', 'json'
67 when 'xml', 'json'
68 @offset, @limit = api_offset_and_limit
68 @offset, @limit = api_offset_and_limit
69 else
69 else
70 @limit = per_page_option
70 @limit = per_page_option
71 end
71 end
72
72
73 @issue_count = @query.issue_count
73 @issue_count = @query.issue_count
74 @issue_pages = Paginator.new @issue_count, @limit, params['page']
74 @issue_pages = Paginator.new @issue_count, @limit, params['page']
75 @offset ||= @issue_pages.offset
75 @offset ||= @issue_pages.offset
76 @issues = @query.issues(:include => [:assigned_to, :tracker, :priority, :category, :fixed_version],
76 @issues = @query.issues(:include => [:assigned_to, :tracker, :priority, :category, :fixed_version],
77 :order => sort_clause,
77 :order => sort_clause,
78 :offset => @offset,
78 :offset => @offset,
79 :limit => @limit)
79 :limit => @limit)
80 @issue_count_by_group = @query.issue_count_by_group
80 @issue_count_by_group = @query.issue_count_by_group
81
81
82 respond_to do |format|
82 respond_to do |format|
83 format.html { render :template => 'issues/index', :layout => !request.xhr? }
83 format.html { render :template => 'issues/index', :layout => !request.xhr? }
84 format.api {
84 format.api {
85 Issue.load_visible_relations(@issues) if include_in_api_response?('relations')
85 Issue.load_visible_relations(@issues) if include_in_api_response?('relations')
86 }
86 }
87 format.atom { render_feed(@issues, :title => "#{@project || Setting.app_title}: #{l(:label_issue_plural)}") }
87 format.atom { render_feed(@issues, :title => "#{@project || Setting.app_title}: #{l(:label_issue_plural)}") }
88 format.csv { send_data(issues_to_csv(@issues, @project, @query, params), :type => 'text/csv; header=present', :filename => 'export.csv') }
88 format.csv { send_data(issues_to_csv(@issues, @project, @query, params), :type => 'text/csv; header=present', :filename => 'export.csv') }
89 format.pdf { send_data(issues_to_pdf(@issues, @project, @query), :type => 'application/pdf', :filename => 'export.pdf') }
89 format.pdf { send_data(issues_to_pdf(@issues, @project, @query), :type => 'application/pdf', :filename => 'export.pdf') }
90 end
90 end
91 else
91 else
92 respond_to do |format|
92 respond_to do |format|
93 format.html { render(:template => 'issues/index', :layout => !request.xhr?) }
93 format.html { render(:template => 'issues/index', :layout => !request.xhr?) }
94 format.any(:atom, :csv, :pdf) { render(:nothing => true) }
94 format.any(:atom, :csv, :pdf) { render(:nothing => true) }
95 format.api { render_validation_errors(@query) }
95 format.api { render_validation_errors(@query) }
96 end
96 end
97 end
97 end
98 rescue ActiveRecord::RecordNotFound
98 rescue ActiveRecord::RecordNotFound
99 render_404
99 render_404
100 end
100 end
101
101
102 def show
102 def show
103 @journals = @issue.journals.includes(:user, :details).reorder("#{Journal.table_name}.id ASC").all
103 @journals = @issue.journals.includes(:user, :details).reorder("#{Journal.table_name}.id ASC").all
104 @journals.each_with_index {|j,i| j.indice = i+1}
104 @journals.each_with_index {|j,i| j.indice = i+1}
105 @journals.reject!(&:private_notes?) unless User.current.allowed_to?(:view_private_notes, @issue.project)
105 @journals.reject!(&:private_notes?) unless User.current.allowed_to?(:view_private_notes, @issue.project)
106 @journals.reverse! if User.current.wants_comments_in_reverse_order?
106 @journals.reverse! if User.current.wants_comments_in_reverse_order?
107
107
108 @changesets = @issue.changesets.visible.all
108 @changesets = @issue.changesets.visible.all
109 @changesets.reverse! if User.current.wants_comments_in_reverse_order?
109 @changesets.reverse! if User.current.wants_comments_in_reverse_order?
110
110
111 @relations = @issue.relations.select {|r| r.other_issue(@issue) && r.other_issue(@issue).visible? }
111 @relations = @issue.relations.select {|r| r.other_issue(@issue) && r.other_issue(@issue).visible? }
112 @allowed_statuses = @issue.new_statuses_allowed_to(User.current)
112 @allowed_statuses = @issue.new_statuses_allowed_to(User.current)
113 @edit_allowed = User.current.allowed_to?(:edit_issues, @project)
113 @edit_allowed = User.current.allowed_to?(:edit_issues, @project)
114 @priorities = IssuePriority.active
114 @priorities = IssuePriority.active
115 @time_entry = TimeEntry.new(:issue => @issue, :project => @issue.project)
115 @time_entry = TimeEntry.new(:issue => @issue, :project => @issue.project)
116 respond_to do |format|
116 respond_to do |format|
117 format.html {
117 format.html {
118 retrieve_previous_and_next_issue_ids
118 retrieve_previous_and_next_issue_ids
119 render :template => 'issues/show'
119 render :template => 'issues/show'
120 }
120 }
121 format.api
121 format.api
122 format.atom { render :template => 'journals/index', :layout => false, :content_type => 'application/atom+xml' }
122 format.atom { render :template => 'journals/index', :layout => false, :content_type => 'application/atom+xml' }
123 format.pdf {
123 format.pdf {
124 pdf = issue_to_pdf(@issue, :journals => @journals)
124 pdf = issue_to_pdf(@issue, :journals => @journals)
125 send_data(pdf, :type => 'application/pdf', :filename => "#{@project.identifier}-#{@issue.id}.pdf")
125 send_data(pdf, :type => 'application/pdf', :filename => "#{@project.identifier}-#{@issue.id}.pdf")
126 }
126 }
127 end
127 end
128 end
128 end
129
129
130 # Add a new issue
130 # Add a new issue
131 # The new issue will be created from an existing one if copy_from parameter is given
131 # The new issue will be created from an existing one if copy_from parameter is given
132 def new
132 def new
133 respond_to do |format|
133 respond_to do |format|
134 format.html { render :action => 'new', :layout => !request.xhr? }
134 format.html { render :action => 'new', :layout => !request.xhr? }
135 format.js { render :partial => 'update_form' }
136 end
135 end
137 end
136 end
138
137
139 def create
138 def create
140 call_hook(:controller_issues_new_before_save, { :params => params, :issue => @issue })
139 call_hook(:controller_issues_new_before_save, { :params => params, :issue => @issue })
141 @issue.save_attachments(params[:attachments] || (params[:issue] && params[:issue][:uploads]))
140 @issue.save_attachments(params[:attachments] || (params[:issue] && params[:issue][:uploads]))
142 if @issue.save
141 if @issue.save
143 call_hook(:controller_issues_new_after_save, { :params => params, :issue => @issue})
142 call_hook(:controller_issues_new_after_save, { :params => params, :issue => @issue})
144 respond_to do |format|
143 respond_to do |format|
145 format.html {
144 format.html {
146 render_attachment_warning_if_needed(@issue)
145 render_attachment_warning_if_needed(@issue)
147 flash[:notice] = l(:notice_issue_successful_create, :id => view_context.link_to("##{@issue.id}", issue_path(@issue), :title => @issue.subject))
146 flash[:notice] = l(:notice_issue_successful_create, :id => view_context.link_to("##{@issue.id}", issue_path(@issue), :title => @issue.subject))
148 if params[:continue]
147 if params[:continue]
149 attrs = {:tracker_id => @issue.tracker, :parent_issue_id => @issue.parent_issue_id}.reject {|k,v| v.nil?}
148 attrs = {:tracker_id => @issue.tracker, :parent_issue_id => @issue.parent_issue_id}.reject {|k,v| v.nil?}
150 redirect_to new_project_issue_path(@issue.project, :issue => attrs)
149 redirect_to new_project_issue_path(@issue.project, :issue => attrs)
151 else
150 else
152 redirect_to issue_path(@issue)
151 redirect_to issue_path(@issue)
153 end
152 end
154 }
153 }
155 format.api { render :action => 'show', :status => :created, :location => issue_url(@issue) }
154 format.api { render :action => 'show', :status => :created, :location => issue_url(@issue) }
156 end
155 end
157 return
156 return
158 else
157 else
159 respond_to do |format|
158 respond_to do |format|
160 format.html { render :action => 'new' }
159 format.html { render :action => 'new' }
161 format.api { render_validation_errors(@issue) }
160 format.api { render_validation_errors(@issue) }
162 end
161 end
163 end
162 end
164 end
163 end
165
164
166 def edit
165 def edit
167 return unless update_issue_from_params
166 return unless update_issue_from_params
168
167
169 respond_to do |format|
168 respond_to do |format|
170 format.html { }
169 format.html { }
171 format.xml { }
170 format.xml { }
172 end
171 end
173 end
172 end
174
173
175 def update
174 def update
176 return unless update_issue_from_params
175 return unless update_issue_from_params
177 @issue.save_attachments(params[:attachments] || (params[:issue] && params[:issue][:uploads]))
176 @issue.save_attachments(params[:attachments] || (params[:issue] && params[:issue][:uploads]))
178 saved = false
177 saved = false
179 begin
178 begin
180 saved = @issue.save_issue_with_child_records(params, @time_entry)
179 saved = @issue.save_issue_with_child_records(params, @time_entry)
181 rescue ActiveRecord::StaleObjectError
180 rescue ActiveRecord::StaleObjectError
182 @conflict = true
181 @conflict = true
183 if params[:last_journal_id]
182 if params[:last_journal_id]
184 @conflict_journals = @issue.journals_after(params[:last_journal_id]).all
183 @conflict_journals = @issue.journals_after(params[:last_journal_id]).all
185 @conflict_journals.reject!(&:private_notes?) unless User.current.allowed_to?(:view_private_notes, @issue.project)
184 @conflict_journals.reject!(&:private_notes?) unless User.current.allowed_to?(:view_private_notes, @issue.project)
186 end
185 end
187 end
186 end
188
187
189 if saved
188 if saved
190 render_attachment_warning_if_needed(@issue)
189 render_attachment_warning_if_needed(@issue)
191 flash[:notice] = l(:notice_successful_update) unless @issue.current_journal.new_record?
190 flash[:notice] = l(:notice_successful_update) unless @issue.current_journal.new_record?
192
191
193 respond_to do |format|
192 respond_to do |format|
194 format.html { redirect_back_or_default issue_path(@issue) }
193 format.html { redirect_back_or_default issue_path(@issue) }
195 format.api { render_api_ok }
194 format.api { render_api_ok }
196 end
195 end
197 else
196 else
198 respond_to do |format|
197 respond_to do |format|
199 format.html { render :action => 'edit' }
198 format.html { render :action => 'edit' }
200 format.api { render_validation_errors(@issue) }
199 format.api { render_validation_errors(@issue) }
201 end
200 end
202 end
201 end
203 end
202 end
204
203
204 # Updates the issue form when changing the project, status or tracker
205 # on issue creation/update
206 def update_form
207 end
208
205 # Bulk edit/copy a set of issues
209 # Bulk edit/copy a set of issues
206 def bulk_edit
210 def bulk_edit
207 @issues.sort!
211 @issues.sort!
208 @copy = params[:copy].present?
212 @copy = params[:copy].present?
209 @notes = params[:notes]
213 @notes = params[:notes]
210
214
211 if User.current.allowed_to?(:move_issues, @projects)
215 if User.current.allowed_to?(:move_issues, @projects)
212 @allowed_projects = Issue.allowed_target_projects_on_move
216 @allowed_projects = Issue.allowed_target_projects_on_move
213 if params[:issue]
217 if params[:issue]
214 @target_project = @allowed_projects.detect {|p| p.id.to_s == params[:issue][:project_id].to_s}
218 @target_project = @allowed_projects.detect {|p| p.id.to_s == params[:issue][:project_id].to_s}
215 if @target_project
219 if @target_project
216 target_projects = [@target_project]
220 target_projects = [@target_project]
217 end
221 end
218 end
222 end
219 end
223 end
220 target_projects ||= @projects
224 target_projects ||= @projects
221
225
222 if @copy
226 if @copy
223 @available_statuses = [IssueStatus.default]
227 @available_statuses = [IssueStatus.default]
224 else
228 else
225 @available_statuses = @issues.map(&:new_statuses_allowed_to).reduce(:&)
229 @available_statuses = @issues.map(&:new_statuses_allowed_to).reduce(:&)
226 end
230 end
227 @custom_fields = target_projects.map{|p|p.all_issue_custom_fields}.reduce(:&)
231 @custom_fields = target_projects.map{|p|p.all_issue_custom_fields}.reduce(:&)
228 @assignables = target_projects.map(&:assignable_users).reduce(:&)
232 @assignables = target_projects.map(&:assignable_users).reduce(:&)
229 @trackers = target_projects.map(&:trackers).reduce(:&)
233 @trackers = target_projects.map(&:trackers).reduce(:&)
230 @versions = target_projects.map {|p| p.shared_versions.open}.reduce(:&)
234 @versions = target_projects.map {|p| p.shared_versions.open}.reduce(:&)
231 @categories = target_projects.map {|p| p.issue_categories}.reduce(:&)
235 @categories = target_projects.map {|p| p.issue_categories}.reduce(:&)
232 if @copy
236 if @copy
233 @attachments_present = @issues.detect {|i| i.attachments.any?}.present?
237 @attachments_present = @issues.detect {|i| i.attachments.any?}.present?
234 @subtasks_present = @issues.detect {|i| !i.leaf?}.present?
238 @subtasks_present = @issues.detect {|i| !i.leaf?}.present?
235 end
239 end
236
240
237 @safe_attributes = @issues.map(&:safe_attribute_names).reduce(:&)
241 @safe_attributes = @issues.map(&:safe_attribute_names).reduce(:&)
238 render :layout => false if request.xhr?
242 render :layout => false if request.xhr?
239 end
243 end
240
244
241 def bulk_update
245 def bulk_update
242 @issues.sort!
246 @issues.sort!
243 @copy = params[:copy].present?
247 @copy = params[:copy].present?
244 attributes = parse_params_for_bulk_issue_attributes(params)
248 attributes = parse_params_for_bulk_issue_attributes(params)
245
249
246 unsaved_issue_ids = []
250 unsaved_issue_ids = []
247 moved_issues = []
251 moved_issues = []
248
252
249 if @copy && params[:copy_subtasks].present?
253 if @copy && params[:copy_subtasks].present?
250 # Descendant issues will be copied with the parent task
254 # Descendant issues will be copied with the parent task
251 # Don't copy them twice
255 # Don't copy them twice
252 @issues.reject! {|issue| @issues.detect {|other| issue.is_descendant_of?(other)}}
256 @issues.reject! {|issue| @issues.detect {|other| issue.is_descendant_of?(other)}}
253 end
257 end
254
258
255 @issues.each do |issue|
259 @issues.each do |issue|
256 issue.reload
260 issue.reload
257 if @copy
261 if @copy
258 issue = issue.copy({},
262 issue = issue.copy({},
259 :attachments => params[:copy_attachments].present?,
263 :attachments => params[:copy_attachments].present?,
260 :subtasks => params[:copy_subtasks].present?
264 :subtasks => params[:copy_subtasks].present?
261 )
265 )
262 end
266 end
263 journal = issue.init_journal(User.current, params[:notes])
267 journal = issue.init_journal(User.current, params[:notes])
264 issue.safe_attributes = attributes
268 issue.safe_attributes = attributes
265 call_hook(:controller_issues_bulk_edit_before_save, { :params => params, :issue => issue })
269 call_hook(:controller_issues_bulk_edit_before_save, { :params => params, :issue => issue })
266 if issue.save
270 if issue.save
267 moved_issues << issue
271 moved_issues << issue
268 else
272 else
269 # Keep unsaved issue ids to display them in flash error
273 # Keep unsaved issue ids to display them in flash error
270 unsaved_issue_ids << issue.id
274 unsaved_issue_ids << issue.id
271 end
275 end
272 end
276 end
273 set_flash_from_bulk_issue_save(@issues, unsaved_issue_ids)
277 set_flash_from_bulk_issue_save(@issues, unsaved_issue_ids)
274
278
275 if params[:follow]
279 if params[:follow]
276 if @issues.size == 1 && moved_issues.size == 1
280 if @issues.size == 1 && moved_issues.size == 1
277 redirect_to issue_path(moved_issues.first)
281 redirect_to issue_path(moved_issues.first)
278 elsif moved_issues.map(&:project).uniq.size == 1
282 elsif moved_issues.map(&:project).uniq.size == 1
279 redirect_to project_issues_path(moved_issues.map(&:project).first)
283 redirect_to project_issues_path(moved_issues.map(&:project).first)
280 end
284 end
281 else
285 else
282 redirect_back_or_default _project_issues_path(@project)
286 redirect_back_or_default _project_issues_path(@project)
283 end
287 end
284 end
288 end
285
289
286 def destroy
290 def destroy
287 @hours = TimeEntry.sum(:hours, :conditions => ['issue_id IN (?)', @issues]).to_f
291 @hours = TimeEntry.sum(:hours, :conditions => ['issue_id IN (?)', @issues]).to_f
288 if @hours > 0
292 if @hours > 0
289 case params[:todo]
293 case params[:todo]
290 when 'destroy'
294 when 'destroy'
291 # nothing to do
295 # nothing to do
292 when 'nullify'
296 when 'nullify'
293 TimeEntry.update_all('issue_id = NULL', ['issue_id IN (?)', @issues])
297 TimeEntry.update_all('issue_id = NULL', ['issue_id IN (?)', @issues])
294 when 'reassign'
298 when 'reassign'
295 reassign_to = @project.issues.find_by_id(params[:reassign_to_id])
299 reassign_to = @project.issues.find_by_id(params[:reassign_to_id])
296 if reassign_to.nil?
300 if reassign_to.nil?
297 flash.now[:error] = l(:error_issue_not_found_in_project)
301 flash.now[:error] = l(:error_issue_not_found_in_project)
298 return
302 return
299 else
303 else
300 TimeEntry.update_all("issue_id = #{reassign_to.id}", ['issue_id IN (?)', @issues])
304 TimeEntry.update_all("issue_id = #{reassign_to.id}", ['issue_id IN (?)', @issues])
301 end
305 end
302 else
306 else
303 # display the destroy form if it's a user request
307 # display the destroy form if it's a user request
304 return unless api_request?
308 return unless api_request?
305 end
309 end
306 end
310 end
307 @issues.each do |issue|
311 @issues.each do |issue|
308 begin
312 begin
309 issue.reload.destroy
313 issue.reload.destroy
310 rescue ::ActiveRecord::RecordNotFound # raised by #reload if issue no longer exists
314 rescue ::ActiveRecord::RecordNotFound # raised by #reload if issue no longer exists
311 # nothing to do, issue was already deleted (eg. by a parent)
315 # nothing to do, issue was already deleted (eg. by a parent)
312 end
316 end
313 end
317 end
314 respond_to do |format|
318 respond_to do |format|
315 format.html { redirect_back_or_default _project_issues_path(@project) }
319 format.html { redirect_back_or_default _project_issues_path(@project) }
316 format.api { render_api_ok }
320 format.api { render_api_ok }
317 end
321 end
318 end
322 end
319
323
320 private
324 private
321
325
322 def find_project
326 def find_project
323 project_id = params[:project_id] || (params[:issue] && params[:issue][:project_id])
327 project_id = params[:project_id] || (params[:issue] && params[:issue][:project_id])
324 @project = Project.find(project_id)
328 @project = Project.find(project_id)
325 rescue ActiveRecord::RecordNotFound
329 rescue ActiveRecord::RecordNotFound
326 render_404
330 render_404
327 end
331 end
328
332
329 def retrieve_previous_and_next_issue_ids
333 def retrieve_previous_and_next_issue_ids
330 retrieve_query_from_session
334 retrieve_query_from_session
331 if @query
335 if @query
332 sort_init(@query.sort_criteria.empty? ? [['id', 'desc']] : @query.sort_criteria)
336 sort_init(@query.sort_criteria.empty? ? [['id', 'desc']] : @query.sort_criteria)
333 sort_update(@query.sortable_columns, 'issues_index_sort')
337 sort_update(@query.sortable_columns, 'issues_index_sort')
334 limit = 500
338 limit = 500
335 issue_ids = @query.issue_ids(:order => sort_clause, :limit => (limit + 1), :include => [:assigned_to, :tracker, :priority, :category, :fixed_version])
339 issue_ids = @query.issue_ids(:order => sort_clause, :limit => (limit + 1), :include => [:assigned_to, :tracker, :priority, :category, :fixed_version])
336 if (idx = issue_ids.index(@issue.id)) && idx < limit
340 if (idx = issue_ids.index(@issue.id)) && idx < limit
337 if issue_ids.size < 500
341 if issue_ids.size < 500
338 @issue_position = idx + 1
342 @issue_position = idx + 1
339 @issue_count = issue_ids.size
343 @issue_count = issue_ids.size
340 end
344 end
341 @prev_issue_id = issue_ids[idx - 1] if idx > 0
345 @prev_issue_id = issue_ids[idx - 1] if idx > 0
342 @next_issue_id = issue_ids[idx + 1] if idx < (issue_ids.size - 1)
346 @next_issue_id = issue_ids[idx + 1] if idx < (issue_ids.size - 1)
343 end
347 end
344 end
348 end
345 end
349 end
346
350
347 # Used by #edit and #update to set some common instance variables
351 # Used by #edit and #update to set some common instance variables
348 # from the params
352 # from the params
349 # TODO: Refactor, not everything in here is needed by #edit
353 # TODO: Refactor, not everything in here is needed by #edit
350 def update_issue_from_params
354 def update_issue_from_params
351 @edit_allowed = User.current.allowed_to?(:edit_issues, @project)
355 @edit_allowed = User.current.allowed_to?(:edit_issues, @project)
352 @time_entry = TimeEntry.new(:issue => @issue, :project => @issue.project)
356 @time_entry = TimeEntry.new(:issue => @issue, :project => @issue.project)
353 @time_entry.attributes = params[:time_entry]
357 @time_entry.attributes = params[:time_entry]
354
358
355 @issue.init_journal(User.current)
359 @issue.init_journal(User.current)
356
360
357 issue_attributes = params[:issue]
361 issue_attributes = params[:issue]
358 if issue_attributes && params[:conflict_resolution]
362 if issue_attributes && params[:conflict_resolution]
359 case params[:conflict_resolution]
363 case params[:conflict_resolution]
360 when 'overwrite'
364 when 'overwrite'
361 issue_attributes = issue_attributes.dup
365 issue_attributes = issue_attributes.dup
362 issue_attributes.delete(:lock_version)
366 issue_attributes.delete(:lock_version)
363 when 'add_notes'
367 when 'add_notes'
364 issue_attributes = issue_attributes.slice(:notes)
368 issue_attributes = issue_attributes.slice(:notes)
365 when 'cancel'
369 when 'cancel'
366 redirect_to issue_path(@issue)
370 redirect_to issue_path(@issue)
367 return false
371 return false
368 end
372 end
369 end
373 end
370 @issue.safe_attributes = issue_attributes
374 @issue.safe_attributes = issue_attributes
371 @priorities = IssuePriority.active
375 @priorities = IssuePriority.active
372 @allowed_statuses = @issue.new_statuses_allowed_to(User.current)
376 @allowed_statuses = @issue.new_statuses_allowed_to(User.current)
373 true
377 true
374 end
378 end
375
379
376 # TODO: Refactor, lots of extra code in here
380 # TODO: Refactor, lots of extra code in here
377 # TODO: Changing tracker on an existing issue should not trigger this
381 # TODO: Changing tracker on an existing issue should not trigger this
378 def build_new_issue_from_params
382 def build_new_issue_from_params
379 if params[:id].blank?
383 if params[:id].blank?
380 @issue = Issue.new
384 @issue = Issue.new
381 if params[:copy_from]
385 if params[:copy_from]
382 begin
386 begin
383 @copy_from = Issue.visible.find(params[:copy_from])
387 @copy_from = Issue.visible.find(params[:copy_from])
384 @copy_attachments = params[:copy_attachments].present? || request.get?
388 @copy_attachments = params[:copy_attachments].present? || request.get?
385 @copy_subtasks = params[:copy_subtasks].present? || request.get?
389 @copy_subtasks = params[:copy_subtasks].present? || request.get?
386 @issue.copy_from(@copy_from, :attachments => @copy_attachments, :subtasks => @copy_subtasks)
390 @issue.copy_from(@copy_from, :attachments => @copy_attachments, :subtasks => @copy_subtasks)
387 rescue ActiveRecord::RecordNotFound
391 rescue ActiveRecord::RecordNotFound
388 render_404
392 render_404
389 return
393 return
390 end
394 end
391 end
395 end
392 @issue.project = @project
396 @issue.project = @project
393 else
397 else
394 @issue = @project.issues.visible.find(params[:id])
398 @issue = @project.issues.visible.find(params[:id])
395 end
399 end
396
400
397 @issue.project = @project
401 @issue.project = @project
398 @issue.author ||= User.current
402 @issue.author ||= User.current
399 # Tracker must be set before custom field values
403 # Tracker must be set before custom field values
400 @issue.tracker ||= @project.trackers.find((params[:issue] && params[:issue][:tracker_id]) || params[:tracker_id] || :first)
404 @issue.tracker ||= @project.trackers.find((params[:issue] && params[:issue][:tracker_id]) || params[:tracker_id] || :first)
401 if @issue.tracker.nil?
405 if @issue.tracker.nil?
402 render_error l(:error_no_tracker_in_project)
406 render_error l(:error_no_tracker_in_project)
403 return false
407 return false
404 end
408 end
405 @issue.start_date ||= Date.today if Setting.default_issue_start_date_to_creation_date?
409 @issue.start_date ||= Date.today if Setting.default_issue_start_date_to_creation_date?
406 @issue.safe_attributes = params[:issue]
410 @issue.safe_attributes = params[:issue]
407
411
408 @priorities = IssuePriority.active
412 @priorities = IssuePriority.active
409 @allowed_statuses = @issue.new_statuses_allowed_to(User.current, true)
413 @allowed_statuses = @issue.new_statuses_allowed_to(User.current, true)
410 @available_watchers = (@issue.project.users.sort + @issue.watcher_users).uniq
414 @available_watchers = (@issue.project.users.sort + @issue.watcher_users).uniq
411 end
415 end
412
416
413 def check_for_default_issue_status
417 def check_for_default_issue_status
414 if IssueStatus.default.nil?
418 if IssueStatus.default.nil?
415 render_error l(:error_no_default_issue_status)
419 render_error l(:error_no_default_issue_status)
416 return false
420 return false
417 end
421 end
418 end
422 end
419
423
420 def parse_params_for_bulk_issue_attributes(params)
424 def parse_params_for_bulk_issue_attributes(params)
421 attributes = (params[:issue] || {}).reject {|k,v| v.blank?}
425 attributes = (params[:issue] || {}).reject {|k,v| v.blank?}
422 attributes.keys.each {|k| attributes[k] = '' if attributes[k] == 'none'}
426 attributes.keys.each {|k| attributes[k] = '' if attributes[k] == 'none'}
423 if custom = attributes[:custom_field_values]
427 if custom = attributes[:custom_field_values]
424 custom.reject! {|k,v| v.blank?}
428 custom.reject! {|k,v| v.blank?}
425 custom.keys.each do |k|
429 custom.keys.each do |k|
426 if custom[k].is_a?(Array)
430 if custom[k].is_a?(Array)
427 custom[k] << '' if custom[k].delete('__none__')
431 custom[k] << '' if custom[k].delete('__none__')
428 else
432 else
429 custom[k] = '' if custom[k] == '__none__'
433 custom[k] = '' if custom[k] == '__none__'
430 end
434 end
431 end
435 end
432 end
436 end
433 attributes
437 attributes
434 end
438 end
435 end
439 end
1 NO CONTENT: file renamed from app/views/issues/_update_form.js.erb to app/views/issues/update_form.js.erb
NO CONTENT: file renamed from app/views/issues/_update_form.js.erb to app/views/issues/update_form.js.erb
@@ -1,347 +1,347
1 # Redmine - project management software
1 # Redmine - project management software
2 # Copyright (C) 2006-2013 Jean-Philippe Lang
2 # Copyright (C) 2006-2013 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 RedmineApp::Application.routes.draw do
18 RedmineApp::Application.routes.draw do
19 root :to => 'welcome#index', :as => 'home'
19 root :to => 'welcome#index', :as => 'home'
20
20
21 match 'login', :to => 'account#login', :as => 'signin', :via => [:get, :post]
21 match 'login', :to => 'account#login', :as => 'signin', :via => [:get, :post]
22 match 'logout', :to => 'account#logout', :as => 'signout', :via => [:get, :post]
22 match 'logout', :to => 'account#logout', :as => 'signout', :via => [:get, :post]
23 match 'account/register', :to => 'account#register', :via => [:get, :post], :as => 'register'
23 match 'account/register', :to => 'account#register', :via => [:get, :post], :as => 'register'
24 match 'account/lost_password', :to => 'account#lost_password', :via => [:get, :post], :as => 'lost_password'
24 match 'account/lost_password', :to => 'account#lost_password', :via => [:get, :post], :as => 'lost_password'
25 match 'account/activate', :to => 'account#activate', :via => :get
25 match 'account/activate', :to => 'account#activate', :via => :get
26
26
27 match '/news/preview', :controller => 'previews', :action => 'news', :as => 'preview_news', :via => [:get, :post, :put]
27 match '/news/preview', :controller => 'previews', :action => 'news', :as => 'preview_news', :via => [:get, :post, :put]
28 match '/issues/preview/new/:project_id', :to => 'previews#issue', :as => 'preview_new_issue', :via => [:get, :post, :put]
28 match '/issues/preview/new/:project_id', :to => 'previews#issue', :as => 'preview_new_issue', :via => [:get, :post, :put]
29 match '/issues/preview/edit/:id', :to => 'previews#issue', :as => 'preview_edit_issue', :via => [:get, :post, :put]
29 match '/issues/preview/edit/:id', :to => 'previews#issue', :as => 'preview_edit_issue', :via => [:get, :post, :put]
30 match '/issues/preview', :to => 'previews#issue', :as => 'preview_issue', :via => [:get, :post, :put]
30 match '/issues/preview', :to => 'previews#issue', :as => 'preview_issue', :via => [:get, :post, :put]
31
31
32 match 'projects/:id/wiki', :to => 'wikis#edit', :via => :post
32 match 'projects/:id/wiki', :to => 'wikis#edit', :via => :post
33 match 'projects/:id/wiki/destroy', :to => 'wikis#destroy', :via => [:get, :post]
33 match 'projects/:id/wiki/destroy', :to => 'wikis#destroy', :via => [:get, :post]
34
34
35 match 'boards/:board_id/topics/new', :to => 'messages#new', :via => [:get, :post], :as => 'new_board_message'
35 match 'boards/:board_id/topics/new', :to => 'messages#new', :via => [:get, :post], :as => 'new_board_message'
36 get 'boards/:board_id/topics/:id', :to => 'messages#show', :as => 'board_message'
36 get 'boards/:board_id/topics/:id', :to => 'messages#show', :as => 'board_message'
37 match 'boards/:board_id/topics/quote/:id', :to => 'messages#quote', :via => [:get, :post]
37 match 'boards/:board_id/topics/quote/:id', :to => 'messages#quote', :via => [:get, :post]
38 get 'boards/:board_id/topics/:id/edit', :to => 'messages#edit'
38 get 'boards/:board_id/topics/:id/edit', :to => 'messages#edit'
39
39
40 post 'boards/:board_id/topics/preview', :to => 'messages#preview', :as => 'preview_board_message'
40 post 'boards/:board_id/topics/preview', :to => 'messages#preview', :as => 'preview_board_message'
41 post 'boards/:board_id/topics/:id/replies', :to => 'messages#reply'
41 post 'boards/:board_id/topics/:id/replies', :to => 'messages#reply'
42 post 'boards/:board_id/topics/:id/edit', :to => 'messages#edit'
42 post 'boards/:board_id/topics/:id/edit', :to => 'messages#edit'
43 post 'boards/:board_id/topics/:id/destroy', :to => 'messages#destroy'
43 post 'boards/:board_id/topics/:id/destroy', :to => 'messages#destroy'
44
44
45 # Misc issue routes. TODO: move into resources
45 # Misc issue routes. TODO: move into resources
46 match '/issues/auto_complete', :to => 'auto_completes#issues', :via => :get, :as => 'auto_complete_issues'
46 match '/issues/auto_complete', :to => 'auto_completes#issues', :via => :get, :as => 'auto_complete_issues'
47 match '/issues/context_menu', :to => 'context_menus#issues', :as => 'issues_context_menu', :via => [:get, :post]
47 match '/issues/context_menu', :to => 'context_menus#issues', :as => 'issues_context_menu', :via => [:get, :post]
48 match '/issues/changes', :to => 'journals#index', :as => 'issue_changes', :via => :get
48 match '/issues/changes', :to => 'journals#index', :as => 'issue_changes', :via => :get
49 match '/issues/:id/quoted', :to => 'journals#new', :id => /\d+/, :via => :post, :as => 'quoted_issue'
49 match '/issues/:id/quoted', :to => 'journals#new', :id => /\d+/, :via => :post, :as => 'quoted_issue'
50
50
51 match '/journals/diff/:id', :to => 'journals#diff', :id => /\d+/, :via => :get
51 match '/journals/diff/:id', :to => 'journals#diff', :id => /\d+/, :via => :get
52 match '/journals/edit/:id', :to => 'journals#edit', :id => /\d+/, :via => [:get, :post]
52 match '/journals/edit/:id', :to => 'journals#edit', :id => /\d+/, :via => [:get, :post]
53
53
54 get '/projects/:project_id/issues/gantt', :to => 'gantts#show', :as => 'project_gantt'
54 get '/projects/:project_id/issues/gantt', :to => 'gantts#show', :as => 'project_gantt'
55 get '/issues/gantt', :to => 'gantts#show'
55 get '/issues/gantt', :to => 'gantts#show'
56
56
57 get '/projects/:project_id/issues/calendar', :to => 'calendars#show', :as => 'project_calendar'
57 get '/projects/:project_id/issues/calendar', :to => 'calendars#show', :as => 'project_calendar'
58 get '/issues/calendar', :to => 'calendars#show'
58 get '/issues/calendar', :to => 'calendars#show'
59
59
60 get 'projects/:id/issues/report', :to => 'reports#issue_report', :as => 'project_issues_report'
60 get 'projects/:id/issues/report', :to => 'reports#issue_report', :as => 'project_issues_report'
61 get 'projects/:id/issues/report/:detail', :to => 'reports#issue_report_details', :as => 'project_issues_report_details'
61 get 'projects/:id/issues/report/:detail', :to => 'reports#issue_report_details', :as => 'project_issues_report_details'
62
62
63 match 'my/account', :controller => 'my', :action => 'account', :via => [:get, :post]
63 match 'my/account', :controller => 'my', :action => 'account', :via => [:get, :post]
64 match 'my/account/destroy', :controller => 'my', :action => 'destroy', :via => [:get, :post]
64 match 'my/account/destroy', :controller => 'my', :action => 'destroy', :via => [:get, :post]
65 match 'my/page', :controller => 'my', :action => 'page', :via => :get
65 match 'my/page', :controller => 'my', :action => 'page', :via => :get
66 match 'my', :controller => 'my', :action => 'index', :via => :get # Redirects to my/page
66 match 'my', :controller => 'my', :action => 'index', :via => :get # Redirects to my/page
67 match 'my/reset_rss_key', :controller => 'my', :action => 'reset_rss_key', :via => :post
67 match 'my/reset_rss_key', :controller => 'my', :action => 'reset_rss_key', :via => :post
68 match 'my/reset_api_key', :controller => 'my', :action => 'reset_api_key', :via => :post
68 match 'my/reset_api_key', :controller => 'my', :action => 'reset_api_key', :via => :post
69 match 'my/password', :controller => 'my', :action => 'password', :via => [:get, :post]
69 match 'my/password', :controller => 'my', :action => 'password', :via => [:get, :post]
70 match 'my/page_layout', :controller => 'my', :action => 'page_layout', :via => :get
70 match 'my/page_layout', :controller => 'my', :action => 'page_layout', :via => :get
71 match 'my/add_block', :controller => 'my', :action => 'add_block', :via => :post
71 match 'my/add_block', :controller => 'my', :action => 'add_block', :via => :post
72 match 'my/remove_block', :controller => 'my', :action => 'remove_block', :via => :post
72 match 'my/remove_block', :controller => 'my', :action => 'remove_block', :via => :post
73 match 'my/order_blocks', :controller => 'my', :action => 'order_blocks', :via => :post
73 match 'my/order_blocks', :controller => 'my', :action => 'order_blocks', :via => :post
74
74
75 resources :users
75 resources :users
76 match 'users/:id/memberships/:membership_id', :to => 'users#edit_membership', :via => :put, :as => 'user_membership'
76 match 'users/:id/memberships/:membership_id', :to => 'users#edit_membership', :via => :put, :as => 'user_membership'
77 match 'users/:id/memberships/:membership_id', :to => 'users#destroy_membership', :via => :delete
77 match 'users/:id/memberships/:membership_id', :to => 'users#destroy_membership', :via => :delete
78 match 'users/:id/memberships', :to => 'users#edit_membership', :via => :post, :as => 'user_memberships'
78 match 'users/:id/memberships', :to => 'users#edit_membership', :via => :post, :as => 'user_memberships'
79
79
80 post 'watchers/watch', :to => 'watchers#watch', :as => 'watch'
80 post 'watchers/watch', :to => 'watchers#watch', :as => 'watch'
81 delete 'watchers/watch', :to => 'watchers#unwatch'
81 delete 'watchers/watch', :to => 'watchers#unwatch'
82 get 'watchers/new', :to => 'watchers#new'
82 get 'watchers/new', :to => 'watchers#new'
83 post 'watchers', :to => 'watchers#create'
83 post 'watchers', :to => 'watchers#create'
84 post 'watchers/append', :to => 'watchers#append'
84 post 'watchers/append', :to => 'watchers#append'
85 post 'watchers/destroy', :to => 'watchers#destroy'
85 post 'watchers/destroy', :to => 'watchers#destroy'
86 get 'watchers/autocomplete_for_user', :to => 'watchers#autocomplete_for_user'
86 get 'watchers/autocomplete_for_user', :to => 'watchers#autocomplete_for_user'
87 # Specific routes for issue watchers API
87 # Specific routes for issue watchers API
88 post 'issues/:object_id/watchers', :to => 'watchers#create', :object_type => 'issue'
88 post 'issues/:object_id/watchers', :to => 'watchers#create', :object_type => 'issue'
89 delete 'issues/:object_id/watchers/:user_id' => 'watchers#destroy', :object_type => 'issue'
89 delete 'issues/:object_id/watchers/:user_id' => 'watchers#destroy', :object_type => 'issue'
90
90
91 resources :projects do
91 resources :projects do
92 member do
92 member do
93 get 'settings(/:tab)', :action => 'settings', :as => 'settings'
93 get 'settings(/:tab)', :action => 'settings', :as => 'settings'
94 post 'modules'
94 post 'modules'
95 post 'archive'
95 post 'archive'
96 post 'unarchive'
96 post 'unarchive'
97 post 'close'
97 post 'close'
98 post 'reopen'
98 post 'reopen'
99 match 'copy', :via => [:get, :post]
99 match 'copy', :via => [:get, :post]
100 end
100 end
101
101
102 resources :memberships, :shallow => true, :controller => 'members', :only => [:index, :show, :new, :create, :update, :destroy] do
102 resources :memberships, :shallow => true, :controller => 'members', :only => [:index, :show, :new, :create, :update, :destroy] do
103 collection do
103 collection do
104 get 'autocomplete'
104 get 'autocomplete'
105 end
105 end
106 end
106 end
107
107
108 resource :enumerations, :controller => 'project_enumerations', :only => [:update, :destroy]
108 resource :enumerations, :controller => 'project_enumerations', :only => [:update, :destroy]
109
109
110 get 'issues/:copy_from/copy', :to => 'issues#new', :as => 'copy_issue'
110 get 'issues/:copy_from/copy', :to => 'issues#new', :as => 'copy_issue'
111 resources :issues, :only => [:index, :new, :create] do
111 resources :issues, :only => [:index, :new, :create] do
112 resources :time_entries, :controller => 'timelog' do
112 resources :time_entries, :controller => 'timelog' do
113 collection do
113 collection do
114 get 'report'
114 get 'report'
115 end
115 end
116 end
116 end
117 end
117 end
118 # issue form update
118 # issue form update
119 match 'issues/new', :controller => 'issues', :action => 'new', :via => [:put, :post], :as => 'issue_form'
119 match 'issues/update_form', :controller => 'issues', :action => 'update_form', :via => [:put, :post], :as => 'issue_form'
120
120
121 resources :files, :only => [:index, :new, :create]
121 resources :files, :only => [:index, :new, :create]
122
122
123 resources :versions, :except => [:index, :show, :edit, :update, :destroy] do
123 resources :versions, :except => [:index, :show, :edit, :update, :destroy] do
124 collection do
124 collection do
125 put 'close_completed'
125 put 'close_completed'
126 end
126 end
127 end
127 end
128 get 'versions.:format', :to => 'versions#index'
128 get 'versions.:format', :to => 'versions#index'
129 get 'roadmap', :to => 'versions#index', :format => false
129 get 'roadmap', :to => 'versions#index', :format => false
130 get 'versions', :to => 'versions#index'
130 get 'versions', :to => 'versions#index'
131
131
132 resources :news, :except => [:show, :edit, :update, :destroy]
132 resources :news, :except => [:show, :edit, :update, :destroy]
133 resources :time_entries, :controller => 'timelog' do
133 resources :time_entries, :controller => 'timelog' do
134 get 'report', :on => :collection
134 get 'report', :on => :collection
135 end
135 end
136 resources :queries, :only => [:new, :create]
136 resources :queries, :only => [:new, :create]
137 resources :issue_categories, :shallow => true
137 resources :issue_categories, :shallow => true
138 resources :documents, :except => [:show, :edit, :update, :destroy]
138 resources :documents, :except => [:show, :edit, :update, :destroy]
139 resources :boards
139 resources :boards
140 resources :repositories, :shallow => true, :except => [:index, :show] do
140 resources :repositories, :shallow => true, :except => [:index, :show] do
141 member do
141 member do
142 match 'committers', :via => [:get, :post]
142 match 'committers', :via => [:get, :post]
143 end
143 end
144 end
144 end
145
145
146 match 'wiki/index', :controller => 'wiki', :action => 'index', :via => :get
146 match 'wiki/index', :controller => 'wiki', :action => 'index', :via => :get
147 resources :wiki, :except => [:index, :new, :create], :as => 'wiki_page' do
147 resources :wiki, :except => [:index, :new, :create], :as => 'wiki_page' do
148 member do
148 member do
149 get 'rename'
149 get 'rename'
150 post 'rename'
150 post 'rename'
151 get 'history'
151 get 'history'
152 get 'diff'
152 get 'diff'
153 match 'preview', :via => [:post, :put]
153 match 'preview', :via => [:post, :put]
154 post 'protect'
154 post 'protect'
155 post 'add_attachment'
155 post 'add_attachment'
156 end
156 end
157 collection do
157 collection do
158 get 'export'
158 get 'export'
159 get 'date_index'
159 get 'date_index'
160 end
160 end
161 end
161 end
162 match 'wiki', :controller => 'wiki', :action => 'show', :via => :get
162 match 'wiki', :controller => 'wiki', :action => 'show', :via => :get
163 get 'wiki/:id/:version', :to => 'wiki#show', :constraints => {:version => /\d+/}
163 get 'wiki/:id/:version', :to => 'wiki#show', :constraints => {:version => /\d+/}
164 delete 'wiki/:id/:version', :to => 'wiki#destroy_version'
164 delete 'wiki/:id/:version', :to => 'wiki#destroy_version'
165 get 'wiki/:id/:version/annotate', :to => 'wiki#annotate'
165 get 'wiki/:id/:version/annotate', :to => 'wiki#annotate'
166 get 'wiki/:id/:version/diff', :to => 'wiki#diff'
166 get 'wiki/:id/:version/diff', :to => 'wiki#diff'
167 end
167 end
168
168
169 resources :issues do
169 resources :issues do
170 collection do
170 collection do
171 match 'bulk_edit', :via => [:get, :post]
171 match 'bulk_edit', :via => [:get, :post]
172 post 'bulk_update'
172 post 'bulk_update'
173 end
173 end
174 resources :time_entries, :controller => 'timelog' do
174 resources :time_entries, :controller => 'timelog' do
175 collection do
175 collection do
176 get 'report'
176 get 'report'
177 end
177 end
178 end
178 end
179 resources :relations, :shallow => true, :controller => 'issue_relations', :only => [:index, :show, :create, :destroy]
179 resources :relations, :shallow => true, :controller => 'issue_relations', :only => [:index, :show, :create, :destroy]
180 end
180 end
181 match '/issues', :controller => 'issues', :action => 'destroy', :via => :delete
181 match '/issues', :controller => 'issues', :action => 'destroy', :via => :delete
182
182
183 resources :queries, :except => [:show]
183 resources :queries, :except => [:show]
184
184
185 resources :news, :only => [:index, :show, :edit, :update, :destroy]
185 resources :news, :only => [:index, :show, :edit, :update, :destroy]
186 match '/news/:id/comments', :to => 'comments#create', :via => :post
186 match '/news/:id/comments', :to => 'comments#create', :via => :post
187 match '/news/:id/comments/:comment_id', :to => 'comments#destroy', :via => :delete
187 match '/news/:id/comments/:comment_id', :to => 'comments#destroy', :via => :delete
188
188
189 resources :versions, :only => [:show, :edit, :update, :destroy] do
189 resources :versions, :only => [:show, :edit, :update, :destroy] do
190 post 'status_by', :on => :member
190 post 'status_by', :on => :member
191 end
191 end
192
192
193 resources :documents, :only => [:show, :edit, :update, :destroy] do
193 resources :documents, :only => [:show, :edit, :update, :destroy] do
194 post 'add_attachment', :on => :member
194 post 'add_attachment', :on => :member
195 end
195 end
196
196
197 match '/time_entries/context_menu', :to => 'context_menus#time_entries', :as => :time_entries_context_menu, :via => [:get, :post]
197 match '/time_entries/context_menu', :to => 'context_menus#time_entries', :as => :time_entries_context_menu, :via => [:get, :post]
198
198
199 resources :time_entries, :controller => 'timelog', :except => :destroy do
199 resources :time_entries, :controller => 'timelog', :except => :destroy do
200 collection do
200 collection do
201 get 'report'
201 get 'report'
202 get 'bulk_edit'
202 get 'bulk_edit'
203 post 'bulk_update'
203 post 'bulk_update'
204 end
204 end
205 end
205 end
206 match '/time_entries/:id', :to => 'timelog#destroy', :via => :delete, :id => /\d+/
206 match '/time_entries/:id', :to => 'timelog#destroy', :via => :delete, :id => /\d+/
207 # TODO: delete /time_entries for bulk deletion
207 # TODO: delete /time_entries for bulk deletion
208 match '/time_entries/destroy', :to => 'timelog#destroy', :via => :delete
208 match '/time_entries/destroy', :to => 'timelog#destroy', :via => :delete
209
209
210 get 'projects/:id/activity', :to => 'activities#index'
210 get 'projects/:id/activity', :to => 'activities#index'
211 get 'projects/:id/activity.:format', :to => 'activities#index'
211 get 'projects/:id/activity.:format', :to => 'activities#index'
212 get 'activity', :to => 'activities#index'
212 get 'activity', :to => 'activities#index'
213
213
214 # repositories routes
214 # repositories routes
215 get 'projects/:id/repository/:repository_id/statistics', :to => 'repositories#stats'
215 get 'projects/:id/repository/:repository_id/statistics', :to => 'repositories#stats'
216 get 'projects/:id/repository/:repository_id/graph', :to => 'repositories#graph'
216 get 'projects/:id/repository/:repository_id/graph', :to => 'repositories#graph'
217
217
218 get 'projects/:id/repository/:repository_id/changes(/*path(.:ext))',
218 get 'projects/:id/repository/:repository_id/changes(/*path(.:ext))',
219 :to => 'repositories#changes'
219 :to => 'repositories#changes'
220
220
221 get 'projects/:id/repository/:repository_id/revisions/:rev', :to => 'repositories#revision'
221 get 'projects/:id/repository/:repository_id/revisions/:rev', :to => 'repositories#revision'
222 get 'projects/:id/repository/:repository_id/revision', :to => 'repositories#revision'
222 get 'projects/:id/repository/:repository_id/revision', :to => 'repositories#revision'
223 post 'projects/:id/repository/:repository_id/revisions/:rev/issues', :to => 'repositories#add_related_issue'
223 post 'projects/:id/repository/:repository_id/revisions/:rev/issues', :to => 'repositories#add_related_issue'
224 delete 'projects/:id/repository/:repository_id/revisions/:rev/issues/:issue_id', :to => 'repositories#remove_related_issue'
224 delete 'projects/:id/repository/:repository_id/revisions/:rev/issues/:issue_id', :to => 'repositories#remove_related_issue'
225 get 'projects/:id/repository/:repository_id/revisions', :to => 'repositories#revisions'
225 get 'projects/:id/repository/:repository_id/revisions', :to => 'repositories#revisions'
226 get 'projects/:id/repository/:repository_id/revisions/:rev/:action(/*path(.:ext))',
226 get 'projects/:id/repository/:repository_id/revisions/:rev/:action(/*path(.:ext))',
227 :controller => 'repositories',
227 :controller => 'repositories',
228 :format => false,
228 :format => false,
229 :constraints => {
229 :constraints => {
230 :action => /(browse|show|entry|raw|annotate|diff)/,
230 :action => /(browse|show|entry|raw|annotate|diff)/,
231 :rev => /[a-z0-9\.\-_]+/
231 :rev => /[a-z0-9\.\-_]+/
232 }
232 }
233
233
234 get 'projects/:id/repository/statistics', :to => 'repositories#stats'
234 get 'projects/:id/repository/statistics', :to => 'repositories#stats'
235 get 'projects/:id/repository/graph', :to => 'repositories#graph'
235 get 'projects/:id/repository/graph', :to => 'repositories#graph'
236
236
237 get 'projects/:id/repository/changes(/*path(.:ext))',
237 get 'projects/:id/repository/changes(/*path(.:ext))',
238 :to => 'repositories#changes'
238 :to => 'repositories#changes'
239
239
240 get 'projects/:id/repository/revisions', :to => 'repositories#revisions'
240 get 'projects/:id/repository/revisions', :to => 'repositories#revisions'
241 get 'projects/:id/repository/revisions/:rev', :to => 'repositories#revision'
241 get 'projects/:id/repository/revisions/:rev', :to => 'repositories#revision'
242 get 'projects/:id/repository/revision', :to => 'repositories#revision'
242 get 'projects/:id/repository/revision', :to => 'repositories#revision'
243 post 'projects/:id/repository/revisions/:rev/issues', :to => 'repositories#add_related_issue'
243 post 'projects/:id/repository/revisions/:rev/issues', :to => 'repositories#add_related_issue'
244 delete 'projects/:id/repository/revisions/:rev/issues/:issue_id', :to => 'repositories#remove_related_issue'
244 delete 'projects/:id/repository/revisions/:rev/issues/:issue_id', :to => 'repositories#remove_related_issue'
245 get 'projects/:id/repository/revisions/:rev/:action(/*path(.:ext))',
245 get 'projects/:id/repository/revisions/:rev/:action(/*path(.:ext))',
246 :controller => 'repositories',
246 :controller => 'repositories',
247 :format => false,
247 :format => false,
248 :constraints => {
248 :constraints => {
249 :action => /(browse|show|entry|raw|annotate|diff)/,
249 :action => /(browse|show|entry|raw|annotate|diff)/,
250 :rev => /[a-z0-9\.\-_]+/
250 :rev => /[a-z0-9\.\-_]+/
251 }
251 }
252 get 'projects/:id/repository/:repository_id/:action(/*path(.:ext))',
252 get 'projects/:id/repository/:repository_id/:action(/*path(.:ext))',
253 :controller => 'repositories',
253 :controller => 'repositories',
254 :action => /(browse|show|entry|raw|changes|annotate|diff)/
254 :action => /(browse|show|entry|raw|changes|annotate|diff)/
255 get 'projects/:id/repository/:action(/*path(.:ext))',
255 get 'projects/:id/repository/:action(/*path(.:ext))',
256 :controller => 'repositories',
256 :controller => 'repositories',
257 :action => /(browse|show|entry|raw|changes|annotate|diff)/
257 :action => /(browse|show|entry|raw|changes|annotate|diff)/
258
258
259 get 'projects/:id/repository/:repository_id', :to => 'repositories#show', :path => nil
259 get 'projects/:id/repository/:repository_id', :to => 'repositories#show', :path => nil
260 get 'projects/:id/repository', :to => 'repositories#show', :path => nil
260 get 'projects/:id/repository', :to => 'repositories#show', :path => nil
261
261
262 # additional routes for having the file name at the end of url
262 # additional routes for having the file name at the end of url
263 get 'attachments/:id/:filename', :to => 'attachments#show', :id => /\d+/, :filename => /.*/, :as => 'named_attachment'
263 get 'attachments/:id/:filename', :to => 'attachments#show', :id => /\d+/, :filename => /.*/, :as => 'named_attachment'
264 get 'attachments/download/:id/:filename', :to => 'attachments#download', :id => /\d+/, :filename => /.*/, :as => 'download_named_attachment'
264 get 'attachments/download/:id/:filename', :to => 'attachments#download', :id => /\d+/, :filename => /.*/, :as => 'download_named_attachment'
265 get 'attachments/download/:id', :to => 'attachments#download', :id => /\d+/
265 get 'attachments/download/:id', :to => 'attachments#download', :id => /\d+/
266 get 'attachments/thumbnail/:id(/:size)', :to => 'attachments#thumbnail', :id => /\d+/, :size => /\d+/, :as => 'thumbnail'
266 get 'attachments/thumbnail/:id(/:size)', :to => 'attachments#thumbnail', :id => /\d+/, :size => /\d+/, :as => 'thumbnail'
267 resources :attachments, :only => [:show, :destroy]
267 resources :attachments, :only => [:show, :destroy]
268
268
269 resources :groups do
269 resources :groups do
270 member do
270 member do
271 get 'autocomplete_for_user'
271 get 'autocomplete_for_user'
272 end
272 end
273 end
273 end
274
274
275 match 'groups/:id/users', :controller => 'groups', :action => 'add_users', :id => /\d+/, :via => :post, :as => 'group_users'
275 match 'groups/:id/users', :controller => 'groups', :action => 'add_users', :id => /\d+/, :via => :post, :as => 'group_users'
276 match 'groups/:id/users/:user_id', :controller => 'groups', :action => 'remove_user', :id => /\d+/, :via => :delete, :as => 'group_user'
276 match 'groups/:id/users/:user_id', :controller => 'groups', :action => 'remove_user', :id => /\d+/, :via => :delete, :as => 'group_user'
277 match 'groups/destroy_membership/:id', :controller => 'groups', :action => 'destroy_membership', :id => /\d+/, :via => :post
277 match 'groups/destroy_membership/:id', :controller => 'groups', :action => 'destroy_membership', :id => /\d+/, :via => :post
278 match 'groups/edit_membership/:id', :controller => 'groups', :action => 'edit_membership', :id => /\d+/, :via => :post
278 match 'groups/edit_membership/:id', :controller => 'groups', :action => 'edit_membership', :id => /\d+/, :via => :post
279
279
280 resources :trackers, :except => :show do
280 resources :trackers, :except => :show do
281 collection do
281 collection do
282 match 'fields', :via => [:get, :post]
282 match 'fields', :via => [:get, :post]
283 end
283 end
284 end
284 end
285 resources :issue_statuses, :except => :show do
285 resources :issue_statuses, :except => :show do
286 collection do
286 collection do
287 post 'update_issue_done_ratio'
287 post 'update_issue_done_ratio'
288 end
288 end
289 end
289 end
290 resources :custom_fields, :except => :show
290 resources :custom_fields, :except => :show
291 resources :roles do
291 resources :roles do
292 collection do
292 collection do
293 match 'permissions', :via => [:get, :post]
293 match 'permissions', :via => [:get, :post]
294 end
294 end
295 end
295 end
296 resources :enumerations, :except => :show
296 resources :enumerations, :except => :show
297 match 'enumerations/:type', :to => 'enumerations#index', :via => :get
297 match 'enumerations/:type', :to => 'enumerations#index', :via => :get
298
298
299 get 'projects/:id/search', :controller => 'search', :action => 'index'
299 get 'projects/:id/search', :controller => 'search', :action => 'index'
300 get 'search', :controller => 'search', :action => 'index'
300 get 'search', :controller => 'search', :action => 'index'
301
301
302 match 'mail_handler', :controller => 'mail_handler', :action => 'index', :via => :post
302 match 'mail_handler', :controller => 'mail_handler', :action => 'index', :via => :post
303
303
304 match 'admin', :controller => 'admin', :action => 'index', :via => :get
304 match 'admin', :controller => 'admin', :action => 'index', :via => :get
305 match 'admin/projects', :controller => 'admin', :action => 'projects', :via => :get
305 match 'admin/projects', :controller => 'admin', :action => 'projects', :via => :get
306 match 'admin/plugins', :controller => 'admin', :action => 'plugins', :via => :get
306 match 'admin/plugins', :controller => 'admin', :action => 'plugins', :via => :get
307 match 'admin/info', :controller => 'admin', :action => 'info', :via => :get
307 match 'admin/info', :controller => 'admin', :action => 'info', :via => :get
308 match 'admin/test_email', :controller => 'admin', :action => 'test_email', :via => :get
308 match 'admin/test_email', :controller => 'admin', :action => 'test_email', :via => :get
309 match 'admin/default_configuration', :controller => 'admin', :action => 'default_configuration', :via => :post
309 match 'admin/default_configuration', :controller => 'admin', :action => 'default_configuration', :via => :post
310
310
311 resources :auth_sources do
311 resources :auth_sources do
312 member do
312 member do
313 get 'test_connection', :as => 'try_connection'
313 get 'test_connection', :as => 'try_connection'
314 end
314 end
315 collection do
315 collection do
316 get 'autocomplete_for_new_user'
316 get 'autocomplete_for_new_user'
317 end
317 end
318 end
318 end
319
319
320 match 'workflows', :controller => 'workflows', :action => 'index', :via => :get
320 match 'workflows', :controller => 'workflows', :action => 'index', :via => :get
321 match 'workflows/edit', :controller => 'workflows', :action => 'edit', :via => [:get, :post]
321 match 'workflows/edit', :controller => 'workflows', :action => 'edit', :via => [:get, :post]
322 match 'workflows/permissions', :controller => 'workflows', :action => 'permissions', :via => [:get, :post]
322 match 'workflows/permissions', :controller => 'workflows', :action => 'permissions', :via => [:get, :post]
323 match 'workflows/copy', :controller => 'workflows', :action => 'copy', :via => [:get, :post]
323 match 'workflows/copy', :controller => 'workflows', :action => 'copy', :via => [:get, :post]
324 match 'settings', :controller => 'settings', :action => 'index', :via => :get
324 match 'settings', :controller => 'settings', :action => 'index', :via => :get
325 match 'settings/edit', :controller => 'settings', :action => 'edit', :via => [:get, :post]
325 match 'settings/edit', :controller => 'settings', :action => 'edit', :via => [:get, :post]
326 match 'settings/plugin/:id', :controller => 'settings', :action => 'plugin', :via => [:get, :post], :as => 'plugin_settings'
326 match 'settings/plugin/:id', :controller => 'settings', :action => 'plugin', :via => [:get, :post], :as => 'plugin_settings'
327
327
328 match 'sys/projects', :to => 'sys#projects', :via => :get
328 match 'sys/projects', :to => 'sys#projects', :via => :get
329 match 'sys/projects/:id/repository', :to => 'sys#create_project_repository', :via => :post
329 match 'sys/projects/:id/repository', :to => 'sys#create_project_repository', :via => :post
330 match 'sys/fetch_changesets', :to => 'sys#fetch_changesets', :via => :get
330 match 'sys/fetch_changesets', :to => 'sys#fetch_changesets', :via => :get
331
331
332 match 'uploads', :to => 'attachments#upload', :via => :post
332 match 'uploads', :to => 'attachments#upload', :via => :post
333
333
334 get 'robots.txt', :to => 'welcome#robots'
334 get 'robots.txt', :to => 'welcome#robots'
335
335
336 Dir.glob File.expand_path("plugins/*", Rails.root) do |plugin_dir|
336 Dir.glob File.expand_path("plugins/*", Rails.root) do |plugin_dir|
337 file = File.join(plugin_dir, "config/routes.rb")
337 file = File.join(plugin_dir, "config/routes.rb")
338 if File.exists?(file)
338 if File.exists?(file)
339 begin
339 begin
340 instance_eval File.read(file)
340 instance_eval File.read(file)
341 rescue Exception => e
341 rescue Exception => e
342 puts "An error occurred while loading the routes definition of #{File.basename(plugin_dir)} plugin (#{file}): #{e.message}."
342 puts "An error occurred while loading the routes definition of #{File.basename(plugin_dir)} plugin (#{file}): #{e.message}."
343 exit 1
343 exit 1
344 end
344 end
345 end
345 end
346 end
346 end
347 end
347 end
@@ -1,284 +1,284
1 # Redmine - project management software
1 # Redmine - project management software
2 # Copyright (C) 2006-2013 Jean-Philippe Lang
2 # Copyright (C) 2006-2013 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 require 'redmine/core_ext'
18 require 'redmine/core_ext'
19
19
20 begin
20 begin
21 require 'RMagick' unless Object.const_defined?(:Magick)
21 require 'RMagick' unless Object.const_defined?(:Magick)
22 rescue LoadError
22 rescue LoadError
23 # RMagick is not available
23 # RMagick is not available
24 end
24 end
25
25
26 require 'redmine/scm/base'
26 require 'redmine/scm/base'
27 require 'redmine/access_control'
27 require 'redmine/access_control'
28 require 'redmine/access_keys'
28 require 'redmine/access_keys'
29 require 'redmine/activity'
29 require 'redmine/activity'
30 require 'redmine/activity/fetcher'
30 require 'redmine/activity/fetcher'
31 require 'redmine/ciphering'
31 require 'redmine/ciphering'
32 require 'redmine/codeset_util'
32 require 'redmine/codeset_util'
33 require 'redmine/custom_field_format'
33 require 'redmine/custom_field_format'
34 require 'redmine/i18n'
34 require 'redmine/i18n'
35 require 'redmine/menu_manager'
35 require 'redmine/menu_manager'
36 require 'redmine/notifiable'
36 require 'redmine/notifiable'
37 require 'redmine/platform'
37 require 'redmine/platform'
38 require 'redmine/mime_type'
38 require 'redmine/mime_type'
39 require 'redmine/notifiable'
39 require 'redmine/notifiable'
40 require 'redmine/search'
40 require 'redmine/search'
41 require 'redmine/syntax_highlighting'
41 require 'redmine/syntax_highlighting'
42 require 'redmine/thumbnail'
42 require 'redmine/thumbnail'
43 require 'redmine/unified_diff'
43 require 'redmine/unified_diff'
44 require 'redmine/utils'
44 require 'redmine/utils'
45 require 'redmine/version'
45 require 'redmine/version'
46 require 'redmine/wiki_formatting'
46 require 'redmine/wiki_formatting'
47
47
48 require 'redmine/default_data/loader'
48 require 'redmine/default_data/loader'
49 require 'redmine/helpers/calendar'
49 require 'redmine/helpers/calendar'
50 require 'redmine/helpers/diff'
50 require 'redmine/helpers/diff'
51 require 'redmine/helpers/gantt'
51 require 'redmine/helpers/gantt'
52 require 'redmine/helpers/time_report'
52 require 'redmine/helpers/time_report'
53 require 'redmine/views/other_formats_builder'
53 require 'redmine/views/other_formats_builder'
54 require 'redmine/views/labelled_form_builder'
54 require 'redmine/views/labelled_form_builder'
55 require 'redmine/views/builders'
55 require 'redmine/views/builders'
56
56
57 require 'redmine/themes'
57 require 'redmine/themes'
58 require 'redmine/hook'
58 require 'redmine/hook'
59 require 'redmine/plugin'
59 require 'redmine/plugin'
60
60
61 if RUBY_VERSION < '1.9'
61 if RUBY_VERSION < '1.9'
62 require 'fastercsv'
62 require 'fastercsv'
63 else
63 else
64 require 'csv'
64 require 'csv'
65 FCSV = CSV
65 FCSV = CSV
66 end
66 end
67
67
68 Redmine::Scm::Base.add "Subversion"
68 Redmine::Scm::Base.add "Subversion"
69 Redmine::Scm::Base.add "Darcs"
69 Redmine::Scm::Base.add "Darcs"
70 Redmine::Scm::Base.add "Mercurial"
70 Redmine::Scm::Base.add "Mercurial"
71 Redmine::Scm::Base.add "Cvs"
71 Redmine::Scm::Base.add "Cvs"
72 Redmine::Scm::Base.add "Bazaar"
72 Redmine::Scm::Base.add "Bazaar"
73 Redmine::Scm::Base.add "Git"
73 Redmine::Scm::Base.add "Git"
74 Redmine::Scm::Base.add "Filesystem"
74 Redmine::Scm::Base.add "Filesystem"
75
75
76 Redmine::CustomFieldFormat.map do |fields|
76 Redmine::CustomFieldFormat.map do |fields|
77 fields.register 'string'
77 fields.register 'string'
78 fields.register 'text'
78 fields.register 'text'
79 fields.register 'int', :label => :label_integer
79 fields.register 'int', :label => :label_integer
80 fields.register 'float'
80 fields.register 'float'
81 fields.register 'list'
81 fields.register 'list'
82 fields.register 'date'
82 fields.register 'date'
83 fields.register 'bool', :label => :label_boolean
83 fields.register 'bool', :label => :label_boolean
84 fields.register 'user', :only => %w(Issue TimeEntry Version Project), :edit_as => 'list'
84 fields.register 'user', :only => %w(Issue TimeEntry Version Project), :edit_as => 'list'
85 fields.register 'version', :only => %w(Issue TimeEntry Version Project), :edit_as => 'list'
85 fields.register 'version', :only => %w(Issue TimeEntry Version Project), :edit_as => 'list'
86 end
86 end
87
87
88 # Permissions
88 # Permissions
89 Redmine::AccessControl.map do |map|
89 Redmine::AccessControl.map do |map|
90 map.permission :view_project, {:projects => [:show], :activities => [:index]}, :public => true, :read => true
90 map.permission :view_project, {:projects => [:show], :activities => [:index]}, :public => true, :read => true
91 map.permission :search_project, {:search => :index}, :public => true, :read => true
91 map.permission :search_project, {:search => :index}, :public => true, :read => true
92 map.permission :add_project, {:projects => [:new, :create]}, :require => :loggedin
92 map.permission :add_project, {:projects => [:new, :create]}, :require => :loggedin
93 map.permission :edit_project, {:projects => [:settings, :edit, :update]}, :require => :member
93 map.permission :edit_project, {:projects => [:settings, :edit, :update]}, :require => :member
94 map.permission :close_project, {:projects => [:close, :reopen]}, :require => :member, :read => true
94 map.permission :close_project, {:projects => [:close, :reopen]}, :require => :member, :read => true
95 map.permission :select_project_modules, {:projects => :modules}, :require => :member
95 map.permission :select_project_modules, {:projects => :modules}, :require => :member
96 map.permission :manage_members, {:projects => :settings, :members => [:index, :show, :create, :update, :destroy, :autocomplete]}, :require => :member
96 map.permission :manage_members, {:projects => :settings, :members => [:index, :show, :create, :update, :destroy, :autocomplete]}, :require => :member
97 map.permission :manage_versions, {:projects => :settings, :versions => [:new, :create, :edit, :update, :close_completed, :destroy]}, :require => :member
97 map.permission :manage_versions, {:projects => :settings, :versions => [:new, :create, :edit, :update, :close_completed, :destroy]}, :require => :member
98 map.permission :add_subprojects, {:projects => [:new, :create]}, :require => :member
98 map.permission :add_subprojects, {:projects => [:new, :create]}, :require => :member
99
99
100 map.project_module :issue_tracking do |map|
100 map.project_module :issue_tracking do |map|
101 # Issue categories
101 # Issue categories
102 map.permission :manage_categories, {:projects => :settings, :issue_categories => [:index, :show, :new, :create, :edit, :update, :destroy]}, :require => :member
102 map.permission :manage_categories, {:projects => :settings, :issue_categories => [:index, :show, :new, :create, :edit, :update, :destroy]}, :require => :member
103 # Issues
103 # Issues
104 map.permission :view_issues, {:issues => [:index, :show],
104 map.permission :view_issues, {:issues => [:index, :show],
105 :auto_complete => [:issues],
105 :auto_complete => [:issues],
106 :context_menus => [:issues],
106 :context_menus => [:issues],
107 :versions => [:index, :show, :status_by],
107 :versions => [:index, :show, :status_by],
108 :journals => [:index, :diff],
108 :journals => [:index, :diff],
109 :queries => :index,
109 :queries => :index,
110 :reports => [:issue_report, :issue_report_details]},
110 :reports => [:issue_report, :issue_report_details]},
111 :read => true
111 :read => true
112 map.permission :add_issues, {:issues => [:new, :create, :update_form], :attachments => :upload}
112 map.permission :add_issues, {:issues => [:new, :create, :update_form], :attachments => :upload}
113 map.permission :edit_issues, {:issues => [:edit, :update, :bulk_edit, :bulk_update, :update_form], :journals => [:new], :attachments => :upload}
113 map.permission :edit_issues, {:issues => [:edit, :update, :bulk_edit, :bulk_update, :update_form], :journals => [:new], :attachments => :upload}
114 map.permission :manage_issue_relations, {:issue_relations => [:index, :show, :create, :destroy]}
114 map.permission :manage_issue_relations, {:issue_relations => [:index, :show, :create, :destroy]}
115 map.permission :manage_subtasks, {}
115 map.permission :manage_subtasks, {}
116 map.permission :set_issues_private, {}
116 map.permission :set_issues_private, {}
117 map.permission :set_own_issues_private, {}, :require => :loggedin
117 map.permission :set_own_issues_private, {}, :require => :loggedin
118 map.permission :add_issue_notes, {:issues => [:edit, :update], :journals => [:new], :attachments => :upload}
118 map.permission :add_issue_notes, {:issues => [:edit, :update, :update_form], :journals => [:new], :attachments => :upload}
119 map.permission :edit_issue_notes, {:journals => :edit}, :require => :loggedin
119 map.permission :edit_issue_notes, {:journals => :edit}, :require => :loggedin
120 map.permission :edit_own_issue_notes, {:journals => :edit}, :require => :loggedin
120 map.permission :edit_own_issue_notes, {:journals => :edit}, :require => :loggedin
121 map.permission :view_private_notes, {}, :read => true, :require => :member
121 map.permission :view_private_notes, {}, :read => true, :require => :member
122 map.permission :set_notes_private, {}, :require => :member
122 map.permission :set_notes_private, {}, :require => :member
123 map.permission :move_issues, {:issues => [:bulk_edit, :bulk_update]}, :require => :loggedin
123 map.permission :move_issues, {:issues => [:bulk_edit, :bulk_update]}, :require => :loggedin
124 map.permission :delete_issues, {:issues => :destroy}, :require => :member
124 map.permission :delete_issues, {:issues => :destroy}, :require => :member
125 # Queries
125 # Queries
126 map.permission :manage_public_queries, {:queries => [:new, :create, :edit, :update, :destroy]}, :require => :member
126 map.permission :manage_public_queries, {:queries => [:new, :create, :edit, :update, :destroy]}, :require => :member
127 map.permission :save_queries, {:queries => [:new, :create, :edit, :update, :destroy]}, :require => :loggedin
127 map.permission :save_queries, {:queries => [:new, :create, :edit, :update, :destroy]}, :require => :loggedin
128 # Watchers
128 # Watchers
129 map.permission :view_issue_watchers, {}, :read => true
129 map.permission :view_issue_watchers, {}, :read => true
130 map.permission :add_issue_watchers, {:watchers => [:new, :create, :append, :autocomplete_for_user]}
130 map.permission :add_issue_watchers, {:watchers => [:new, :create, :append, :autocomplete_for_user]}
131 map.permission :delete_issue_watchers, {:watchers => :destroy}
131 map.permission :delete_issue_watchers, {:watchers => :destroy}
132 end
132 end
133
133
134 map.project_module :time_tracking do |map|
134 map.project_module :time_tracking do |map|
135 map.permission :log_time, {:timelog => [:new, :create]}, :require => :loggedin
135 map.permission :log_time, {:timelog => [:new, :create]}, :require => :loggedin
136 map.permission :view_time_entries, {:timelog => [:index, :report, :show]}, :read => true
136 map.permission :view_time_entries, {:timelog => [:index, :report, :show]}, :read => true
137 map.permission :edit_time_entries, {:timelog => [:edit, :update, :destroy, :bulk_edit, :bulk_update]}, :require => :member
137 map.permission :edit_time_entries, {:timelog => [:edit, :update, :destroy, :bulk_edit, :bulk_update]}, :require => :member
138 map.permission :edit_own_time_entries, {:timelog => [:edit, :update, :destroy,:bulk_edit, :bulk_update]}, :require => :loggedin
138 map.permission :edit_own_time_entries, {:timelog => [:edit, :update, :destroy,:bulk_edit, :bulk_update]}, :require => :loggedin
139 map.permission :manage_project_activities, {:project_enumerations => [:update, :destroy]}, :require => :member
139 map.permission :manage_project_activities, {:project_enumerations => [:update, :destroy]}, :require => :member
140 end
140 end
141
141
142 map.project_module :news do |map|
142 map.project_module :news do |map|
143 map.permission :manage_news, {:news => [:new, :create, :edit, :update, :destroy], :comments => [:destroy]}, :require => :member
143 map.permission :manage_news, {:news => [:new, :create, :edit, :update, :destroy], :comments => [:destroy]}, :require => :member
144 map.permission :view_news, {:news => [:index, :show]}, :public => true, :read => true
144 map.permission :view_news, {:news => [:index, :show]}, :public => true, :read => true
145 map.permission :comment_news, {:comments => :create}
145 map.permission :comment_news, {:comments => :create}
146 end
146 end
147
147
148 map.project_module :documents do |map|
148 map.project_module :documents do |map|
149 map.permission :add_documents, {:documents => [:new, :create, :add_attachment]}, :require => :loggedin
149 map.permission :add_documents, {:documents => [:new, :create, :add_attachment]}, :require => :loggedin
150 map.permission :edit_documents, {:documents => [:edit, :update, :add_attachment]}, :require => :loggedin
150 map.permission :edit_documents, {:documents => [:edit, :update, :add_attachment]}, :require => :loggedin
151 map.permission :delete_documents, {:documents => [:destroy]}, :require => :loggedin
151 map.permission :delete_documents, {:documents => [:destroy]}, :require => :loggedin
152 map.permission :view_documents, {:documents => [:index, :show, :download]}, :read => true
152 map.permission :view_documents, {:documents => [:index, :show, :download]}, :read => true
153 end
153 end
154
154
155 map.project_module :files do |map|
155 map.project_module :files do |map|
156 map.permission :manage_files, {:files => [:new, :create]}, :require => :loggedin
156 map.permission :manage_files, {:files => [:new, :create]}, :require => :loggedin
157 map.permission :view_files, {:files => :index, :versions => :download}, :read => true
157 map.permission :view_files, {:files => :index, :versions => :download}, :read => true
158 end
158 end
159
159
160 map.project_module :wiki do |map|
160 map.project_module :wiki do |map|
161 map.permission :manage_wiki, {:wikis => [:edit, :destroy]}, :require => :member
161 map.permission :manage_wiki, {:wikis => [:edit, :destroy]}, :require => :member
162 map.permission :rename_wiki_pages, {:wiki => :rename}, :require => :member
162 map.permission :rename_wiki_pages, {:wiki => :rename}, :require => :member
163 map.permission :delete_wiki_pages, {:wiki => [:destroy, :destroy_version]}, :require => :member
163 map.permission :delete_wiki_pages, {:wiki => [:destroy, :destroy_version]}, :require => :member
164 map.permission :view_wiki_pages, {:wiki => [:index, :show, :special, :date_index]}, :read => true
164 map.permission :view_wiki_pages, {:wiki => [:index, :show, :special, :date_index]}, :read => true
165 map.permission :export_wiki_pages, {:wiki => [:export]}, :read => true
165 map.permission :export_wiki_pages, {:wiki => [:export]}, :read => true
166 map.permission :view_wiki_edits, {:wiki => [:history, :diff, :annotate]}, :read => true
166 map.permission :view_wiki_edits, {:wiki => [:history, :diff, :annotate]}, :read => true
167 map.permission :edit_wiki_pages, :wiki => [:edit, :update, :preview, :add_attachment]
167 map.permission :edit_wiki_pages, :wiki => [:edit, :update, :preview, :add_attachment]
168 map.permission :delete_wiki_pages_attachments, {}
168 map.permission :delete_wiki_pages_attachments, {}
169 map.permission :protect_wiki_pages, {:wiki => :protect}, :require => :member
169 map.permission :protect_wiki_pages, {:wiki => :protect}, :require => :member
170 end
170 end
171
171
172 map.project_module :repository do |map|
172 map.project_module :repository do |map|
173 map.permission :manage_repository, {:repositories => [:new, :create, :edit, :update, :committers, :destroy]}, :require => :member
173 map.permission :manage_repository, {:repositories => [:new, :create, :edit, :update, :committers, :destroy]}, :require => :member
174 map.permission :browse_repository, {:repositories => [:show, :browse, :entry, :raw, :annotate, :changes, :diff, :stats, :graph]}, :read => true
174 map.permission :browse_repository, {:repositories => [:show, :browse, :entry, :raw, :annotate, :changes, :diff, :stats, :graph]}, :read => true
175 map.permission :view_changesets, {:repositories => [:show, :revisions, :revision]}, :read => true
175 map.permission :view_changesets, {:repositories => [:show, :revisions, :revision]}, :read => true
176 map.permission :commit_access, {}
176 map.permission :commit_access, {}
177 map.permission :manage_related_issues, {:repositories => [:add_related_issue, :remove_related_issue]}
177 map.permission :manage_related_issues, {:repositories => [:add_related_issue, :remove_related_issue]}
178 end
178 end
179
179
180 map.project_module :boards do |map|
180 map.project_module :boards do |map|
181 map.permission :manage_boards, {:boards => [:new, :create, :edit, :update, :destroy]}, :require => :member
181 map.permission :manage_boards, {:boards => [:new, :create, :edit, :update, :destroy]}, :require => :member
182 map.permission :view_messages, {:boards => [:index, :show], :messages => [:show]}, :public => true, :read => true
182 map.permission :view_messages, {:boards => [:index, :show], :messages => [:show]}, :public => true, :read => true
183 map.permission :add_messages, {:messages => [:new, :reply, :quote]}
183 map.permission :add_messages, {:messages => [:new, :reply, :quote]}
184 map.permission :edit_messages, {:messages => :edit}, :require => :member
184 map.permission :edit_messages, {:messages => :edit}, :require => :member
185 map.permission :edit_own_messages, {:messages => :edit}, :require => :loggedin
185 map.permission :edit_own_messages, {:messages => :edit}, :require => :loggedin
186 map.permission :delete_messages, {:messages => :destroy}, :require => :member
186 map.permission :delete_messages, {:messages => :destroy}, :require => :member
187 map.permission :delete_own_messages, {:messages => :destroy}, :require => :loggedin
187 map.permission :delete_own_messages, {:messages => :destroy}, :require => :loggedin
188 end
188 end
189
189
190 map.project_module :calendar do |map|
190 map.project_module :calendar do |map|
191 map.permission :view_calendar, {:calendars => [:show, :update]}, :read => true
191 map.permission :view_calendar, {:calendars => [:show, :update]}, :read => true
192 end
192 end
193
193
194 map.project_module :gantt do |map|
194 map.project_module :gantt do |map|
195 map.permission :view_gantt, {:gantts => [:show, :update]}, :read => true
195 map.permission :view_gantt, {:gantts => [:show, :update]}, :read => true
196 end
196 end
197 end
197 end
198
198
199 Redmine::MenuManager.map :top_menu do |menu|
199 Redmine::MenuManager.map :top_menu do |menu|
200 menu.push :home, :home_path
200 menu.push :home, :home_path
201 menu.push :my_page, { :controller => 'my', :action => 'page' }, :if => Proc.new { User.current.logged? }
201 menu.push :my_page, { :controller => 'my', :action => 'page' }, :if => Proc.new { User.current.logged? }
202 menu.push :projects, { :controller => 'projects', :action => 'index' }, :caption => :label_project_plural
202 menu.push :projects, { :controller => 'projects', :action => 'index' }, :caption => :label_project_plural
203 menu.push :administration, { :controller => 'admin', :action => 'index' }, :if => Proc.new { User.current.admin? }, :last => true
203 menu.push :administration, { :controller => 'admin', :action => 'index' }, :if => Proc.new { User.current.admin? }, :last => true
204 menu.push :help, Redmine::Info.help_url, :last => true
204 menu.push :help, Redmine::Info.help_url, :last => true
205 end
205 end
206
206
207 Redmine::MenuManager.map :account_menu do |menu|
207 Redmine::MenuManager.map :account_menu do |menu|
208 menu.push :login, :signin_path, :if => Proc.new { !User.current.logged? }
208 menu.push :login, :signin_path, :if => Proc.new { !User.current.logged? }
209 menu.push :register, :register_path, :if => Proc.new { !User.current.logged? && Setting.self_registration? }
209 menu.push :register, :register_path, :if => Proc.new { !User.current.logged? && Setting.self_registration? }
210 menu.push :my_account, { :controller => 'my', :action => 'account' }, :if => Proc.new { User.current.logged? }
210 menu.push :my_account, { :controller => 'my', :action => 'account' }, :if => Proc.new { User.current.logged? }
211 menu.push :logout, :signout_path, :html => {:method => 'post'}, :if => Proc.new { User.current.logged? }
211 menu.push :logout, :signout_path, :html => {:method => 'post'}, :if => Proc.new { User.current.logged? }
212 end
212 end
213
213
214 Redmine::MenuManager.map :application_menu do |menu|
214 Redmine::MenuManager.map :application_menu do |menu|
215 # Empty
215 # Empty
216 end
216 end
217
217
218 Redmine::MenuManager.map :admin_menu do |menu|
218 Redmine::MenuManager.map :admin_menu do |menu|
219 menu.push :projects, {:controller => 'admin', :action => 'projects'}, :caption => :label_project_plural
219 menu.push :projects, {:controller => 'admin', :action => 'projects'}, :caption => :label_project_plural
220 menu.push :users, {:controller => 'users'}, :caption => :label_user_plural
220 menu.push :users, {:controller => 'users'}, :caption => :label_user_plural
221 menu.push :groups, {:controller => 'groups'}, :caption => :label_group_plural
221 menu.push :groups, {:controller => 'groups'}, :caption => :label_group_plural
222 menu.push :roles, {:controller => 'roles'}, :caption => :label_role_and_permissions
222 menu.push :roles, {:controller => 'roles'}, :caption => :label_role_and_permissions
223 menu.push :trackers, {:controller => 'trackers'}, :caption => :label_tracker_plural
223 menu.push :trackers, {:controller => 'trackers'}, :caption => :label_tracker_plural
224 menu.push :issue_statuses, {:controller => 'issue_statuses'}, :caption => :label_issue_status_plural,
224 menu.push :issue_statuses, {:controller => 'issue_statuses'}, :caption => :label_issue_status_plural,
225 :html => {:class => 'issue_statuses'}
225 :html => {:class => 'issue_statuses'}
226 menu.push :workflows, {:controller => 'workflows', :action => 'edit'}, :caption => :label_workflow
226 menu.push :workflows, {:controller => 'workflows', :action => 'edit'}, :caption => :label_workflow
227 menu.push :custom_fields, {:controller => 'custom_fields'}, :caption => :label_custom_field_plural,
227 menu.push :custom_fields, {:controller => 'custom_fields'}, :caption => :label_custom_field_plural,
228 :html => {:class => 'custom_fields'}
228 :html => {:class => 'custom_fields'}
229 menu.push :enumerations, {:controller => 'enumerations'}
229 menu.push :enumerations, {:controller => 'enumerations'}
230 menu.push :settings, {:controller => 'settings'}
230 menu.push :settings, {:controller => 'settings'}
231 menu.push :ldap_authentication, {:controller => 'auth_sources', :action => 'index'},
231 menu.push :ldap_authentication, {:controller => 'auth_sources', :action => 'index'},
232 :html => {:class => 'server_authentication'}
232 :html => {:class => 'server_authentication'}
233 menu.push :plugins, {:controller => 'admin', :action => 'plugins'}, :last => true
233 menu.push :plugins, {:controller => 'admin', :action => 'plugins'}, :last => true
234 menu.push :info, {:controller => 'admin', :action => 'info'}, :caption => :label_information_plural, :last => true
234 menu.push :info, {:controller => 'admin', :action => 'info'}, :caption => :label_information_plural, :last => true
235 end
235 end
236
236
237 Redmine::MenuManager.map :project_menu do |menu|
237 Redmine::MenuManager.map :project_menu do |menu|
238 menu.push :overview, { :controller => 'projects', :action => 'show' }
238 menu.push :overview, { :controller => 'projects', :action => 'show' }
239 menu.push :activity, { :controller => 'activities', :action => 'index' }
239 menu.push :activity, { :controller => 'activities', :action => 'index' }
240 menu.push :roadmap, { :controller => 'versions', :action => 'index' }, :param => :project_id,
240 menu.push :roadmap, { :controller => 'versions', :action => 'index' }, :param => :project_id,
241 :if => Proc.new { |p| p.shared_versions.any? }
241 :if => Proc.new { |p| p.shared_versions.any? }
242 menu.push :issues, { :controller => 'issues', :action => 'index' }, :param => :project_id, :caption => :label_issue_plural
242 menu.push :issues, { :controller => 'issues', :action => 'index' }, :param => :project_id, :caption => :label_issue_plural
243 menu.push :new_issue, { :controller => 'issues', :action => 'new', :copy_from => nil }, :param => :project_id, :caption => :label_issue_new,
243 menu.push :new_issue, { :controller => 'issues', :action => 'new', :copy_from => nil }, :param => :project_id, :caption => :label_issue_new,
244 :html => { :accesskey => Redmine::AccessKeys.key_for(:new_issue) }
244 :html => { :accesskey => Redmine::AccessKeys.key_for(:new_issue) }
245 menu.push :gantt, { :controller => 'gantts', :action => 'show' }, :param => :project_id, :caption => :label_gantt
245 menu.push :gantt, { :controller => 'gantts', :action => 'show' }, :param => :project_id, :caption => :label_gantt
246 menu.push :calendar, { :controller => 'calendars', :action => 'show' }, :param => :project_id, :caption => :label_calendar
246 menu.push :calendar, { :controller => 'calendars', :action => 'show' }, :param => :project_id, :caption => :label_calendar
247 menu.push :news, { :controller => 'news', :action => 'index' }, :param => :project_id, :caption => :label_news_plural
247 menu.push :news, { :controller => 'news', :action => 'index' }, :param => :project_id, :caption => :label_news_plural
248 menu.push :documents, { :controller => 'documents', :action => 'index' }, :param => :project_id, :caption => :label_document_plural
248 menu.push :documents, { :controller => 'documents', :action => 'index' }, :param => :project_id, :caption => :label_document_plural
249 menu.push :wiki, { :controller => 'wiki', :action => 'show', :id => nil }, :param => :project_id,
249 menu.push :wiki, { :controller => 'wiki', :action => 'show', :id => nil }, :param => :project_id,
250 :if => Proc.new { |p| p.wiki && !p.wiki.new_record? }
250 :if => Proc.new { |p| p.wiki && !p.wiki.new_record? }
251 menu.push :boards, { :controller => 'boards', :action => 'index', :id => nil }, :param => :project_id,
251 menu.push :boards, { :controller => 'boards', :action => 'index', :id => nil }, :param => :project_id,
252 :if => Proc.new { |p| p.boards.any? }, :caption => :label_board_plural
252 :if => Proc.new { |p| p.boards.any? }, :caption => :label_board_plural
253 menu.push :files, { :controller => 'files', :action => 'index' }, :caption => :label_file_plural, :param => :project_id
253 menu.push :files, { :controller => 'files', :action => 'index' }, :caption => :label_file_plural, :param => :project_id
254 menu.push :repository, { :controller => 'repositories', :action => 'show', :repository_id => nil, :path => nil, :rev => nil },
254 menu.push :repository, { :controller => 'repositories', :action => 'show', :repository_id => nil, :path => nil, :rev => nil },
255 :if => Proc.new { |p| p.repository && !p.repository.new_record? }
255 :if => Proc.new { |p| p.repository && !p.repository.new_record? }
256 menu.push :settings, { :controller => 'projects', :action => 'settings' }, :last => true
256 menu.push :settings, { :controller => 'projects', :action => 'settings' }, :last => true
257 end
257 end
258
258
259 Redmine::Activity.map do |activity|
259 Redmine::Activity.map do |activity|
260 activity.register :issues, :class_name => %w(Issue Journal)
260 activity.register :issues, :class_name => %w(Issue Journal)
261 activity.register :changesets
261 activity.register :changesets
262 activity.register :news
262 activity.register :news
263 activity.register :documents, :class_name => %w(Document Attachment)
263 activity.register :documents, :class_name => %w(Document Attachment)
264 activity.register :files, :class_name => 'Attachment'
264 activity.register :files, :class_name => 'Attachment'
265 activity.register :wiki_edits, :class_name => 'WikiContent::Version', :default => false
265 activity.register :wiki_edits, :class_name => 'WikiContent::Version', :default => false
266 activity.register :messages, :default => false
266 activity.register :messages, :default => false
267 activity.register :time_entries, :default => false
267 activity.register :time_entries, :default => false
268 end
268 end
269
269
270 Redmine::Search.map do |search|
270 Redmine::Search.map do |search|
271 search.register :issues
271 search.register :issues
272 search.register :news
272 search.register :news
273 search.register :documents
273 search.register :documents
274 search.register :changesets
274 search.register :changesets
275 search.register :wiki_pages
275 search.register :wiki_pages
276 search.register :messages
276 search.register :messages
277 search.register :projects
277 search.register :projects
278 end
278 end
279
279
280 Redmine::WikiFormatting.map do |format|
280 Redmine::WikiFormatting.map do |format|
281 format.register :textile, Redmine::WikiFormatting::Textile::Formatter, Redmine::WikiFormatting::Textile::Helper
281 format.register :textile, Redmine::WikiFormatting::Textile::Formatter, Redmine::WikiFormatting::Textile::Helper
282 end
282 end
283
283
284 ActionView::Template.register_template_handler :rsb, Redmine::Views::ApiTemplateHandler
284 ActionView::Template.register_template_handler :rsb, Redmine::Views::ApiTemplateHandler
@@ -1,166 +1,169
1 ---
1 ---
2 users_004:
2 users_004:
3 created_on: 2006-07-19 19:34:07 +02:00
3 created_on: 2006-07-19 19:34:07 +02:00
4 status: 1
4 status: 1
5 last_login_on:
5 last_login_on:
6 language: en
6 language: en
7 # password = foo
7 # password = foo
8 salt: 3126f764c3c5ac61cbfc103f25f934cf
8 salt: 3126f764c3c5ac61cbfc103f25f934cf
9 hashed_password: 9e4dd7eeb172c12a0691a6d9d3a269f7e9fe671b
9 hashed_password: 9e4dd7eeb172c12a0691a6d9d3a269f7e9fe671b
10 updated_on: 2006-07-19 19:34:07 +02:00
10 updated_on: 2006-07-19 19:34:07 +02:00
11 admin: false
11 admin: false
12 mail: rhill@somenet.foo
12 mail: rhill@somenet.foo
13 lastname: Hill
13 lastname: Hill
14 firstname: Robert
14 firstname: Robert
15 id: 4
15 id: 4
16 auth_source_id:
16 auth_source_id:
17 mail_notification: all
17 mail_notification: all
18 login: rhill
18 login: rhill
19 type: User
19 type: User
20 users_001:
20 users_001:
21 created_on: 2006-07-19 19:12:21 +02:00
21 created_on: 2006-07-19 19:12:21 +02:00
22 status: 1
22 status: 1
23 last_login_on: 2006-07-19 22:57:52 +02:00
23 last_login_on: 2006-07-19 22:57:52 +02:00
24 language: en
24 language: en
25 # password = admin
25 # password = admin
26 salt: 82090c953c4a0000a7db253b0691a6b4
26 salt: 82090c953c4a0000a7db253b0691a6b4
27 hashed_password: b5b6ff9543bf1387374cdfa27a54c96d236a7150
27 hashed_password: b5b6ff9543bf1387374cdfa27a54c96d236a7150
28 updated_on: 2006-07-19 22:57:52 +02:00
28 updated_on: 2006-07-19 22:57:52 +02:00
29 admin: true
29 admin: true
30 mail: admin@somenet.foo
30 mail: admin@somenet.foo
31 lastname: Admin
31 lastname: Admin
32 firstname: Redmine
32 firstname: Redmine
33 id: 1
33 id: 1
34 auth_source_id:
34 auth_source_id:
35 mail_notification: all
35 mail_notification: all
36 login: admin
36 login: admin
37 type: User
37 type: User
38 users_002:
38 users_002:
39 created_on: 2006-07-19 19:32:09 +02:00
39 created_on: 2006-07-19 19:32:09 +02:00
40 status: 1
40 status: 1
41 last_login_on: 2006-07-19 22:42:15 +02:00
41 last_login_on: 2006-07-19 22:42:15 +02:00
42 language: en
42 language: en
43 # password = jsmith
43 # password = jsmith
44 salt: 67eb4732624d5a7753dcea7ce0bb7d7d
44 salt: 67eb4732624d5a7753dcea7ce0bb7d7d
45 hashed_password: bfbe06043353a677d0215b26a5800d128d5413bc
45 hashed_password: bfbe06043353a677d0215b26a5800d128d5413bc
46 updated_on: 2006-07-19 22:42:15 +02:00
46 updated_on: 2006-07-19 22:42:15 +02:00
47 admin: false
47 admin: false
48 mail: jsmith@somenet.foo
48 mail: jsmith@somenet.foo
49 lastname: Smith
49 lastname: Smith
50 firstname: John
50 firstname: John
51 id: 2
51 id: 2
52 auth_source_id:
52 auth_source_id:
53 mail_notification: all
53 mail_notification: all
54 login: jsmith
54 login: jsmith
55 type: User
55 type: User
56 users_003:
56 users_003:
57 created_on: 2006-07-19 19:33:19 +02:00
57 created_on: 2006-07-19 19:33:19 +02:00
58 status: 1
58 status: 1
59 last_login_on:
59 last_login_on:
60 language: en
60 language: en
61 # password = foo
61 # password = foo
62 salt: 7599f9963ec07b5a3b55b354407120c0
62 salt: 7599f9963ec07b5a3b55b354407120c0
63 hashed_password: 8f659c8d7c072f189374edacfa90d6abbc26d8ed
63 hashed_password: 8f659c8d7c072f189374edacfa90d6abbc26d8ed
64 updated_on: 2006-07-19 19:33:19 +02:00
64 updated_on: 2006-07-19 19:33:19 +02:00
65 admin: false
65 admin: false
66 mail: dlopper@somenet.foo
66 mail: dlopper@somenet.foo
67 lastname: Lopper
67 lastname: Lopper
68 firstname: Dave
68 firstname: Dave
69 id: 3
69 id: 3
70 auth_source_id:
70 auth_source_id:
71 mail_notification: all
71 mail_notification: all
72 login: dlopper
72 login: dlopper
73 type: User
73 type: User
74 users_005:
74 users_005:
75 id: 5
75 id: 5
76 created_on: 2006-07-19 19:33:19 +02:00
76 created_on: 2006-07-19 19:33:19 +02:00
77 # Locked
77 # Locked
78 status: 3
78 status: 3
79 last_login_on:
79 last_login_on:
80 language: en
80 language: en
81 hashed_password: 1
81 hashed_password: 1
82 updated_on: 2006-07-19 19:33:19 +02:00
82 updated_on: 2006-07-19 19:33:19 +02:00
83 admin: false
83 admin: false
84 mail: dlopper2@somenet.foo
84 mail: dlopper2@somenet.foo
85 lastname: Lopper2
85 lastname: Lopper2
86 firstname: Dave2
86 firstname: Dave2
87 auth_source_id:
87 auth_source_id:
88 mail_notification: all
88 mail_notification: all
89 login: dlopper2
89 login: dlopper2
90 type: User
90 type: User
91 users_006:
91 users_006:
92 id: 6
92 id: 6
93 created_on: 2006-07-19 19:33:19 +02:00
93 created_on: 2006-07-19 19:33:19 +02:00
94 status: 0
94 status: 0
95 last_login_on:
95 last_login_on:
96 language: ''
96 language: ''
97 hashed_password: 1
97 hashed_password: 1
98 updated_on: 2006-07-19 19:33:19 +02:00
98 updated_on: 2006-07-19 19:33:19 +02:00
99 admin: false
99 admin: false
100 mail: ''
100 mail: ''
101 lastname: Anonymous
101 lastname: Anonymous
102 firstname: ''
102 firstname: ''
103 auth_source_id:
103 auth_source_id:
104 mail_notification: only_my_events
104 mail_notification: only_my_events
105 login: ''
105 login: ''
106 type: AnonymousUser
106 type: AnonymousUser
107 users_007:
107 users_007:
108 # A user who does not belong to any project
108 id: 7
109 id: 7
109 created_on: 2006-07-19 19:33:19 +02:00
110 created_on: 2006-07-19 19:33:19 +02:00
110 status: 1
111 status: 1
111 last_login_on:
112 last_login_on:
112 language: ''
113 language: 'en'
113 hashed_password: 1
114 # password = foo
115 salt: 7599f9963ec07b5a3b55b354407120c0
116 hashed_password: 8f659c8d7c072f189374edacfa90d6abbc26d8ed
114 updated_on: 2006-07-19 19:33:19 +02:00
117 updated_on: 2006-07-19 19:33:19 +02:00
115 admin: false
118 admin: false
116 mail: someone@foo.bar
119 mail: someone@foo.bar
117 lastname: One
120 lastname: One
118 firstname: Some
121 firstname: Some
119 auth_source_id:
122 auth_source_id:
120 mail_notification: only_my_events
123 mail_notification: only_my_events
121 login: someone
124 login: someone
122 type: User
125 type: User
123 users_008:
126 users_008:
124 id: 8
127 id: 8
125 created_on: 2006-07-19 19:33:19 +02:00
128 created_on: 2006-07-19 19:33:19 +02:00
126 status: 1
129 status: 1
127 last_login_on:
130 last_login_on:
128 language: 'it'
131 language: 'it'
129 # password = foo
132 # password = foo
130 salt: 7599f9963ec07b5a3b55b354407120c0
133 salt: 7599f9963ec07b5a3b55b354407120c0
131 hashed_password: 8f659c8d7c072f189374edacfa90d6abbc26d8ed
134 hashed_password: 8f659c8d7c072f189374edacfa90d6abbc26d8ed
132 updated_on: 2006-07-19 19:33:19 +02:00
135 updated_on: 2006-07-19 19:33:19 +02:00
133 admin: false
136 admin: false
134 mail: miscuser8@foo.bar
137 mail: miscuser8@foo.bar
135 lastname: Misc
138 lastname: Misc
136 firstname: User
139 firstname: User
137 auth_source_id:
140 auth_source_id:
138 mail_notification: only_my_events
141 mail_notification: only_my_events
139 login: miscuser8
142 login: miscuser8
140 type: User
143 type: User
141 users_009:
144 users_009:
142 id: 9
145 id: 9
143 created_on: 2006-07-19 19:33:19 +02:00
146 created_on: 2006-07-19 19:33:19 +02:00
144 status: 1
147 status: 1
145 last_login_on:
148 last_login_on:
146 language: 'it'
149 language: 'it'
147 hashed_password: 1
150 hashed_password: 1
148 updated_on: 2006-07-19 19:33:19 +02:00
151 updated_on: 2006-07-19 19:33:19 +02:00
149 admin: false
152 admin: false
150 mail: miscuser9@foo.bar
153 mail: miscuser9@foo.bar
151 lastname: Misc
154 lastname: Misc
152 firstname: User
155 firstname: User
153 auth_source_id:
156 auth_source_id:
154 mail_notification: only_my_events
157 mail_notification: only_my_events
155 login: miscuser9
158 login: miscuser9
156 type: User
159 type: User
157 groups_010:
160 groups_010:
158 id: 10
161 id: 10
159 lastname: A Team
162 lastname: A Team
160 type: Group
163 type: Group
161 groups_011:
164 groups_011:
162 id: 11
165 id: 11
163 lastname: B Team
166 lastname: B Team
164 type: Group
167 type: Group
165
168
166
169
@@ -1,3872 +1,3872
1 # Redmine - project management software
1 # Redmine - project management software
2 # Copyright (C) 2006-2013 Jean-Philippe Lang
2 # Copyright (C) 2006-2013 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 require File.expand_path('../../test_helper', __FILE__)
18 require File.expand_path('../../test_helper', __FILE__)
19
19
20 class IssuesControllerTest < ActionController::TestCase
20 class IssuesControllerTest < ActionController::TestCase
21 fixtures :projects,
21 fixtures :projects,
22 :users,
22 :users,
23 :roles,
23 :roles,
24 :members,
24 :members,
25 :member_roles,
25 :member_roles,
26 :issues,
26 :issues,
27 :issue_statuses,
27 :issue_statuses,
28 :versions,
28 :versions,
29 :trackers,
29 :trackers,
30 :projects_trackers,
30 :projects_trackers,
31 :issue_categories,
31 :issue_categories,
32 :enabled_modules,
32 :enabled_modules,
33 :enumerations,
33 :enumerations,
34 :attachments,
34 :attachments,
35 :workflows,
35 :workflows,
36 :custom_fields,
36 :custom_fields,
37 :custom_values,
37 :custom_values,
38 :custom_fields_projects,
38 :custom_fields_projects,
39 :custom_fields_trackers,
39 :custom_fields_trackers,
40 :time_entries,
40 :time_entries,
41 :journals,
41 :journals,
42 :journal_details,
42 :journal_details,
43 :queries,
43 :queries,
44 :repositories,
44 :repositories,
45 :changesets
45 :changesets
46
46
47 include Redmine::I18n
47 include Redmine::I18n
48
48
49 def setup
49 def setup
50 User.current = nil
50 User.current = nil
51 end
51 end
52
52
53 def test_index
53 def test_index
54 with_settings :default_language => "en" do
54 with_settings :default_language => "en" do
55 get :index
55 get :index
56 assert_response :success
56 assert_response :success
57 assert_template 'index'
57 assert_template 'index'
58 assert_not_nil assigns(:issues)
58 assert_not_nil assigns(:issues)
59 assert_nil assigns(:project)
59 assert_nil assigns(:project)
60
60
61 # links to visible issues
61 # links to visible issues
62 assert_select 'a[href=/issues/1]', :text => /Can&#x27;t print recipes/
62 assert_select 'a[href=/issues/1]', :text => /Can&#x27;t print recipes/
63 assert_select 'a[href=/issues/5]', :text => /Subproject issue/
63 assert_select 'a[href=/issues/5]', :text => /Subproject issue/
64 # private projects hidden
64 # private projects hidden
65 assert_select 'a[href=/issues/6]', 0
65 assert_select 'a[href=/issues/6]', 0
66 assert_select 'a[href=/issues/4]', 0
66 assert_select 'a[href=/issues/4]', 0
67 # project column
67 # project column
68 assert_select 'th', :text => /Project/
68 assert_select 'th', :text => /Project/
69 end
69 end
70 end
70 end
71
71
72 def test_index_should_not_list_issues_when_module_disabled
72 def test_index_should_not_list_issues_when_module_disabled
73 EnabledModule.delete_all("name = 'issue_tracking' AND project_id = 1")
73 EnabledModule.delete_all("name = 'issue_tracking' AND project_id = 1")
74 get :index
74 get :index
75 assert_response :success
75 assert_response :success
76 assert_template 'index'
76 assert_template 'index'
77 assert_not_nil assigns(:issues)
77 assert_not_nil assigns(:issues)
78 assert_nil assigns(:project)
78 assert_nil assigns(:project)
79
79
80 assert_select 'a[href=/issues/1]', 0
80 assert_select 'a[href=/issues/1]', 0
81 assert_select 'a[href=/issues/5]', :text => /Subproject issue/
81 assert_select 'a[href=/issues/5]', :text => /Subproject issue/
82 end
82 end
83
83
84 def test_index_should_list_visible_issues_only
84 def test_index_should_list_visible_issues_only
85 get :index, :per_page => 100
85 get :index, :per_page => 100
86 assert_response :success
86 assert_response :success
87 assert_not_nil assigns(:issues)
87 assert_not_nil assigns(:issues)
88 assert_nil assigns(:issues).detect {|issue| !issue.visible?}
88 assert_nil assigns(:issues).detect {|issue| !issue.visible?}
89 end
89 end
90
90
91 def test_index_with_project
91 def test_index_with_project
92 Setting.display_subprojects_issues = 0
92 Setting.display_subprojects_issues = 0
93 get :index, :project_id => 1
93 get :index, :project_id => 1
94 assert_response :success
94 assert_response :success
95 assert_template 'index'
95 assert_template 'index'
96 assert_not_nil assigns(:issues)
96 assert_not_nil assigns(:issues)
97
97
98 assert_select 'a[href=/issues/1]', :text => /Can&#x27;t print recipes/
98 assert_select 'a[href=/issues/1]', :text => /Can&#x27;t print recipes/
99 assert_select 'a[href=/issues/5]', 0
99 assert_select 'a[href=/issues/5]', 0
100 end
100 end
101
101
102 def test_index_with_project_and_subprojects
102 def test_index_with_project_and_subprojects
103 Setting.display_subprojects_issues = 1
103 Setting.display_subprojects_issues = 1
104 get :index, :project_id => 1
104 get :index, :project_id => 1
105 assert_response :success
105 assert_response :success
106 assert_template 'index'
106 assert_template 'index'
107 assert_not_nil assigns(:issues)
107 assert_not_nil assigns(:issues)
108
108
109 assert_select 'a[href=/issues/1]', :text => /Can&#x27;t print recipes/
109 assert_select 'a[href=/issues/1]', :text => /Can&#x27;t print recipes/
110 assert_select 'a[href=/issues/5]', :text => /Subproject issue/
110 assert_select 'a[href=/issues/5]', :text => /Subproject issue/
111 assert_select 'a[href=/issues/6]', 0
111 assert_select 'a[href=/issues/6]', 0
112 end
112 end
113
113
114 def test_index_with_project_and_subprojects_should_show_private_subprojects_with_permission
114 def test_index_with_project_and_subprojects_should_show_private_subprojects_with_permission
115 @request.session[:user_id] = 2
115 @request.session[:user_id] = 2
116 Setting.display_subprojects_issues = 1
116 Setting.display_subprojects_issues = 1
117 get :index, :project_id => 1
117 get :index, :project_id => 1
118 assert_response :success
118 assert_response :success
119 assert_template 'index'
119 assert_template 'index'
120 assert_not_nil assigns(:issues)
120 assert_not_nil assigns(:issues)
121
121
122 assert_select 'a[href=/issues/1]', :text => /Can&#x27;t print recipes/
122 assert_select 'a[href=/issues/1]', :text => /Can&#x27;t print recipes/
123 assert_select 'a[href=/issues/5]', :text => /Subproject issue/
123 assert_select 'a[href=/issues/5]', :text => /Subproject issue/
124 assert_select 'a[href=/issues/6]', :text => /Issue of a private subproject/
124 assert_select 'a[href=/issues/6]', :text => /Issue of a private subproject/
125 end
125 end
126
126
127 def test_index_with_project_and_default_filter
127 def test_index_with_project_and_default_filter
128 get :index, :project_id => 1, :set_filter => 1
128 get :index, :project_id => 1, :set_filter => 1
129 assert_response :success
129 assert_response :success
130 assert_template 'index'
130 assert_template 'index'
131 assert_not_nil assigns(:issues)
131 assert_not_nil assigns(:issues)
132
132
133 query = assigns(:query)
133 query = assigns(:query)
134 assert_not_nil query
134 assert_not_nil query
135 # default filter
135 # default filter
136 assert_equal({'status_id' => {:operator => 'o', :values => ['']}}, query.filters)
136 assert_equal({'status_id' => {:operator => 'o', :values => ['']}}, query.filters)
137 end
137 end
138
138
139 def test_index_with_project_and_filter
139 def test_index_with_project_and_filter
140 get :index, :project_id => 1, :set_filter => 1,
140 get :index, :project_id => 1, :set_filter => 1,
141 :f => ['tracker_id'],
141 :f => ['tracker_id'],
142 :op => {'tracker_id' => '='},
142 :op => {'tracker_id' => '='},
143 :v => {'tracker_id' => ['1']}
143 :v => {'tracker_id' => ['1']}
144 assert_response :success
144 assert_response :success
145 assert_template 'index'
145 assert_template 'index'
146 assert_not_nil assigns(:issues)
146 assert_not_nil assigns(:issues)
147
147
148 query = assigns(:query)
148 query = assigns(:query)
149 assert_not_nil query
149 assert_not_nil query
150 assert_equal({'tracker_id' => {:operator => '=', :values => ['1']}}, query.filters)
150 assert_equal({'tracker_id' => {:operator => '=', :values => ['1']}}, query.filters)
151 end
151 end
152
152
153 def test_index_with_short_filters
153 def test_index_with_short_filters
154 to_test = {
154 to_test = {
155 'status_id' => {
155 'status_id' => {
156 'o' => { :op => 'o', :values => [''] },
156 'o' => { :op => 'o', :values => [''] },
157 'c' => { :op => 'c', :values => [''] },
157 'c' => { :op => 'c', :values => [''] },
158 '7' => { :op => '=', :values => ['7'] },
158 '7' => { :op => '=', :values => ['7'] },
159 '7|3|4' => { :op => '=', :values => ['7', '3', '4'] },
159 '7|3|4' => { :op => '=', :values => ['7', '3', '4'] },
160 '=7' => { :op => '=', :values => ['7'] },
160 '=7' => { :op => '=', :values => ['7'] },
161 '!3' => { :op => '!', :values => ['3'] },
161 '!3' => { :op => '!', :values => ['3'] },
162 '!7|3|4' => { :op => '!', :values => ['7', '3', '4'] }},
162 '!7|3|4' => { :op => '!', :values => ['7', '3', '4'] }},
163 'subject' => {
163 'subject' => {
164 'This is a subject' => { :op => '=', :values => ['This is a subject'] },
164 'This is a subject' => { :op => '=', :values => ['This is a subject'] },
165 'o' => { :op => '=', :values => ['o'] },
165 'o' => { :op => '=', :values => ['o'] },
166 '~This is part of a subject' => { :op => '~', :values => ['This is part of a subject'] },
166 '~This is part of a subject' => { :op => '~', :values => ['This is part of a subject'] },
167 '!~This is part of a subject' => { :op => '!~', :values => ['This is part of a subject'] }},
167 '!~This is part of a subject' => { :op => '!~', :values => ['This is part of a subject'] }},
168 'tracker_id' => {
168 'tracker_id' => {
169 '3' => { :op => '=', :values => ['3'] },
169 '3' => { :op => '=', :values => ['3'] },
170 '=3' => { :op => '=', :values => ['3'] }},
170 '=3' => { :op => '=', :values => ['3'] }},
171 'start_date' => {
171 'start_date' => {
172 '2011-10-12' => { :op => '=', :values => ['2011-10-12'] },
172 '2011-10-12' => { :op => '=', :values => ['2011-10-12'] },
173 '=2011-10-12' => { :op => '=', :values => ['2011-10-12'] },
173 '=2011-10-12' => { :op => '=', :values => ['2011-10-12'] },
174 '>=2011-10-12' => { :op => '>=', :values => ['2011-10-12'] },
174 '>=2011-10-12' => { :op => '>=', :values => ['2011-10-12'] },
175 '<=2011-10-12' => { :op => '<=', :values => ['2011-10-12'] },
175 '<=2011-10-12' => { :op => '<=', :values => ['2011-10-12'] },
176 '><2011-10-01|2011-10-30' => { :op => '><', :values => ['2011-10-01', '2011-10-30'] },
176 '><2011-10-01|2011-10-30' => { :op => '><', :values => ['2011-10-01', '2011-10-30'] },
177 '<t+2' => { :op => '<t+', :values => ['2'] },
177 '<t+2' => { :op => '<t+', :values => ['2'] },
178 '>t+2' => { :op => '>t+', :values => ['2'] },
178 '>t+2' => { :op => '>t+', :values => ['2'] },
179 't+2' => { :op => 't+', :values => ['2'] },
179 't+2' => { :op => 't+', :values => ['2'] },
180 't' => { :op => 't', :values => [''] },
180 't' => { :op => 't', :values => [''] },
181 'w' => { :op => 'w', :values => [''] },
181 'w' => { :op => 'w', :values => [''] },
182 '>t-2' => { :op => '>t-', :values => ['2'] },
182 '>t-2' => { :op => '>t-', :values => ['2'] },
183 '<t-2' => { :op => '<t-', :values => ['2'] },
183 '<t-2' => { :op => '<t-', :values => ['2'] },
184 't-2' => { :op => 't-', :values => ['2'] }},
184 't-2' => { :op => 't-', :values => ['2'] }},
185 'created_on' => {
185 'created_on' => {
186 '>=2011-10-12' => { :op => '>=', :values => ['2011-10-12'] },
186 '>=2011-10-12' => { :op => '>=', :values => ['2011-10-12'] },
187 '<t-2' => { :op => '<t-', :values => ['2'] },
187 '<t-2' => { :op => '<t-', :values => ['2'] },
188 '>t-2' => { :op => '>t-', :values => ['2'] },
188 '>t-2' => { :op => '>t-', :values => ['2'] },
189 't-2' => { :op => 't-', :values => ['2'] }},
189 't-2' => { :op => 't-', :values => ['2'] }},
190 'cf_1' => {
190 'cf_1' => {
191 'c' => { :op => '=', :values => ['c'] },
191 'c' => { :op => '=', :values => ['c'] },
192 '!c' => { :op => '!', :values => ['c'] },
192 '!c' => { :op => '!', :values => ['c'] },
193 '!*' => { :op => '!*', :values => [''] },
193 '!*' => { :op => '!*', :values => [''] },
194 '*' => { :op => '*', :values => [''] }},
194 '*' => { :op => '*', :values => [''] }},
195 'estimated_hours' => {
195 'estimated_hours' => {
196 '=13.4' => { :op => '=', :values => ['13.4'] },
196 '=13.4' => { :op => '=', :values => ['13.4'] },
197 '>=45' => { :op => '>=', :values => ['45'] },
197 '>=45' => { :op => '>=', :values => ['45'] },
198 '<=125' => { :op => '<=', :values => ['125'] },
198 '<=125' => { :op => '<=', :values => ['125'] },
199 '><10.5|20.5' => { :op => '><', :values => ['10.5', '20.5'] },
199 '><10.5|20.5' => { :op => '><', :values => ['10.5', '20.5'] },
200 '!*' => { :op => '!*', :values => [''] },
200 '!*' => { :op => '!*', :values => [''] },
201 '*' => { :op => '*', :values => [''] }}
201 '*' => { :op => '*', :values => [''] }}
202 }
202 }
203
203
204 default_filter = { 'status_id' => {:operator => 'o', :values => [''] }}
204 default_filter = { 'status_id' => {:operator => 'o', :values => [''] }}
205
205
206 to_test.each do |field, expression_and_expected|
206 to_test.each do |field, expression_and_expected|
207 expression_and_expected.each do |filter_expression, expected|
207 expression_and_expected.each do |filter_expression, expected|
208
208
209 get :index, :set_filter => 1, field => filter_expression
209 get :index, :set_filter => 1, field => filter_expression
210
210
211 assert_response :success
211 assert_response :success
212 assert_template 'index'
212 assert_template 'index'
213 assert_not_nil assigns(:issues)
213 assert_not_nil assigns(:issues)
214
214
215 query = assigns(:query)
215 query = assigns(:query)
216 assert_not_nil query
216 assert_not_nil query
217 assert query.has_filter?(field)
217 assert query.has_filter?(field)
218 assert_equal(default_filter.merge({field => {:operator => expected[:op], :values => expected[:values]}}), query.filters)
218 assert_equal(default_filter.merge({field => {:operator => expected[:op], :values => expected[:values]}}), query.filters)
219 end
219 end
220 end
220 end
221 end
221 end
222
222
223 def test_index_with_project_and_empty_filters
223 def test_index_with_project_and_empty_filters
224 get :index, :project_id => 1, :set_filter => 1, :fields => ['']
224 get :index, :project_id => 1, :set_filter => 1, :fields => ['']
225 assert_response :success
225 assert_response :success
226 assert_template 'index'
226 assert_template 'index'
227 assert_not_nil assigns(:issues)
227 assert_not_nil assigns(:issues)
228
228
229 query = assigns(:query)
229 query = assigns(:query)
230 assert_not_nil query
230 assert_not_nil query
231 # no filter
231 # no filter
232 assert_equal({}, query.filters)
232 assert_equal({}, query.filters)
233 end
233 end
234
234
235 def test_index_with_project_custom_field_filter
235 def test_index_with_project_custom_field_filter
236 field = ProjectCustomField.create!(:name => 'Client', :is_filter => true, :field_format => 'string')
236 field = ProjectCustomField.create!(:name => 'Client', :is_filter => true, :field_format => 'string')
237 CustomValue.create!(:custom_field => field, :customized => Project.find(3), :value => 'Foo')
237 CustomValue.create!(:custom_field => field, :customized => Project.find(3), :value => 'Foo')
238 CustomValue.create!(:custom_field => field, :customized => Project.find(5), :value => 'Foo')
238 CustomValue.create!(:custom_field => field, :customized => Project.find(5), :value => 'Foo')
239 filter_name = "project.cf_#{field.id}"
239 filter_name = "project.cf_#{field.id}"
240 @request.session[:user_id] = 1
240 @request.session[:user_id] = 1
241
241
242 get :index, :set_filter => 1,
242 get :index, :set_filter => 1,
243 :f => [filter_name],
243 :f => [filter_name],
244 :op => {filter_name => '='},
244 :op => {filter_name => '='},
245 :v => {filter_name => ['Foo']}
245 :v => {filter_name => ['Foo']}
246 assert_response :success
246 assert_response :success
247 assert_template 'index'
247 assert_template 'index'
248 assert_equal [3, 5], assigns(:issues).map(&:project_id).uniq.sort
248 assert_equal [3, 5], assigns(:issues).map(&:project_id).uniq.sort
249 end
249 end
250
250
251 def test_index_with_query
251 def test_index_with_query
252 get :index, :project_id => 1, :query_id => 5
252 get :index, :project_id => 1, :query_id => 5
253 assert_response :success
253 assert_response :success
254 assert_template 'index'
254 assert_template 'index'
255 assert_not_nil assigns(:issues)
255 assert_not_nil assigns(:issues)
256 assert_nil assigns(:issue_count_by_group)
256 assert_nil assigns(:issue_count_by_group)
257 end
257 end
258
258
259 def test_index_with_query_grouped_by_tracker
259 def test_index_with_query_grouped_by_tracker
260 get :index, :project_id => 1, :query_id => 6
260 get :index, :project_id => 1, :query_id => 6
261 assert_response :success
261 assert_response :success
262 assert_template 'index'
262 assert_template 'index'
263 assert_not_nil assigns(:issues)
263 assert_not_nil assigns(:issues)
264 assert_not_nil assigns(:issue_count_by_group)
264 assert_not_nil assigns(:issue_count_by_group)
265 end
265 end
266
266
267 def test_index_with_query_grouped_by_list_custom_field
267 def test_index_with_query_grouped_by_list_custom_field
268 get :index, :project_id => 1, :query_id => 9
268 get :index, :project_id => 1, :query_id => 9
269 assert_response :success
269 assert_response :success
270 assert_template 'index'
270 assert_template 'index'
271 assert_not_nil assigns(:issues)
271 assert_not_nil assigns(:issues)
272 assert_not_nil assigns(:issue_count_by_group)
272 assert_not_nil assigns(:issue_count_by_group)
273 end
273 end
274
274
275 def test_index_with_query_grouped_by_user_custom_field
275 def test_index_with_query_grouped_by_user_custom_field
276 cf = IssueCustomField.create!(:name => 'User', :is_for_all => true, :tracker_ids => [1,2,3], :field_format => 'user')
276 cf = IssueCustomField.create!(:name => 'User', :is_for_all => true, :tracker_ids => [1,2,3], :field_format => 'user')
277 CustomValue.create!(:custom_field => cf, :customized => Issue.find(1), :value => '2')
277 CustomValue.create!(:custom_field => cf, :customized => Issue.find(1), :value => '2')
278 CustomValue.create!(:custom_field => cf, :customized => Issue.find(2), :value => '3')
278 CustomValue.create!(:custom_field => cf, :customized => Issue.find(2), :value => '3')
279 CustomValue.create!(:custom_field => cf, :customized => Issue.find(3), :value => '3')
279 CustomValue.create!(:custom_field => cf, :customized => Issue.find(3), :value => '3')
280 CustomValue.create!(:custom_field => cf, :customized => Issue.find(5), :value => '')
280 CustomValue.create!(:custom_field => cf, :customized => Issue.find(5), :value => '')
281
281
282 get :index, :project_id => 1, :set_filter => 1, :group_by => "cf_#{cf.id}"
282 get :index, :project_id => 1, :set_filter => 1, :group_by => "cf_#{cf.id}"
283 assert_response :success
283 assert_response :success
284
284
285 assert_select 'tr.group', 3
285 assert_select 'tr.group', 3
286 assert_select 'tr.group' do
286 assert_select 'tr.group' do
287 assert_select 'a', :text => 'John Smith'
287 assert_select 'a', :text => 'John Smith'
288 assert_select 'span.count', :text => '1'
288 assert_select 'span.count', :text => '1'
289 end
289 end
290 assert_select 'tr.group' do
290 assert_select 'tr.group' do
291 assert_select 'a', :text => 'Dave Lopper'
291 assert_select 'a', :text => 'Dave Lopper'
292 assert_select 'span.count', :text => '2'
292 assert_select 'span.count', :text => '2'
293 end
293 end
294 end
294 end
295
295
296 def test_index_with_query_grouped_by_tracker
296 def test_index_with_query_grouped_by_tracker
297 3.times {|i| Issue.generate!(:tracker_id => (i + 1))}
297 3.times {|i| Issue.generate!(:tracker_id => (i + 1))}
298
298
299 get :index, :set_filter => 1, :group_by => 'tracker', :sort => 'id:desc'
299 get :index, :set_filter => 1, :group_by => 'tracker', :sort => 'id:desc'
300 assert_response :success
300 assert_response :success
301
301
302 trackers = assigns(:issues).map(&:tracker).uniq
302 trackers = assigns(:issues).map(&:tracker).uniq
303 assert_equal [1, 2, 3], trackers.map(&:id)
303 assert_equal [1, 2, 3], trackers.map(&:id)
304 end
304 end
305
305
306 def test_index_with_query_grouped_by_tracker_in_reverse_order
306 def test_index_with_query_grouped_by_tracker_in_reverse_order
307 3.times {|i| Issue.generate!(:tracker_id => (i + 1))}
307 3.times {|i| Issue.generate!(:tracker_id => (i + 1))}
308
308
309 get :index, :set_filter => 1, :group_by => 'tracker', :sort => 'id:desc,tracker:desc'
309 get :index, :set_filter => 1, :group_by => 'tracker', :sort => 'id:desc,tracker:desc'
310 assert_response :success
310 assert_response :success
311
311
312 trackers = assigns(:issues).map(&:tracker).uniq
312 trackers = assigns(:issues).map(&:tracker).uniq
313 assert_equal [3, 2, 1], trackers.map(&:id)
313 assert_equal [3, 2, 1], trackers.map(&:id)
314 end
314 end
315
315
316 def test_index_with_query_id_and_project_id_should_set_session_query
316 def test_index_with_query_id_and_project_id_should_set_session_query
317 get :index, :project_id => 1, :query_id => 4
317 get :index, :project_id => 1, :query_id => 4
318 assert_response :success
318 assert_response :success
319 assert_kind_of Hash, session[:query]
319 assert_kind_of Hash, session[:query]
320 assert_equal 4, session[:query][:id]
320 assert_equal 4, session[:query][:id]
321 assert_equal 1, session[:query][:project_id]
321 assert_equal 1, session[:query][:project_id]
322 end
322 end
323
323
324 def test_index_with_invalid_query_id_should_respond_404
324 def test_index_with_invalid_query_id_should_respond_404
325 get :index, :project_id => 1, :query_id => 999
325 get :index, :project_id => 1, :query_id => 999
326 assert_response 404
326 assert_response 404
327 end
327 end
328
328
329 def test_index_with_cross_project_query_in_session_should_show_project_issues
329 def test_index_with_cross_project_query_in_session_should_show_project_issues
330 q = IssueQuery.create!(:name => "test", :user_id => 2, :is_public => false, :project => nil)
330 q = IssueQuery.create!(:name => "test", :user_id => 2, :is_public => false, :project => nil)
331 @request.session[:query] = {:id => q.id, :project_id => 1}
331 @request.session[:query] = {:id => q.id, :project_id => 1}
332
332
333 with_settings :display_subprojects_issues => '0' do
333 with_settings :display_subprojects_issues => '0' do
334 get :index, :project_id => 1
334 get :index, :project_id => 1
335 end
335 end
336 assert_response :success
336 assert_response :success
337 assert_not_nil assigns(:query)
337 assert_not_nil assigns(:query)
338 assert_equal q.id, assigns(:query).id
338 assert_equal q.id, assigns(:query).id
339 assert_equal 1, assigns(:query).project_id
339 assert_equal 1, assigns(:query).project_id
340 assert_equal [1], assigns(:issues).map(&:project_id).uniq
340 assert_equal [1], assigns(:issues).map(&:project_id).uniq
341 end
341 end
342
342
343 def test_private_query_should_not_be_available_to_other_users
343 def test_private_query_should_not_be_available_to_other_users
344 q = IssueQuery.create!(:name => "private", :user => User.find(2), :is_public => false, :project => nil)
344 q = IssueQuery.create!(:name => "private", :user => User.find(2), :is_public => false, :project => nil)
345 @request.session[:user_id] = 3
345 @request.session[:user_id] = 3
346
346
347 get :index, :query_id => q.id
347 get :index, :query_id => q.id
348 assert_response 403
348 assert_response 403
349 end
349 end
350
350
351 def test_private_query_should_be_available_to_its_user
351 def test_private_query_should_be_available_to_its_user
352 q = IssueQuery.create!(:name => "private", :user => User.find(2), :is_public => false, :project => nil)
352 q = IssueQuery.create!(:name => "private", :user => User.find(2), :is_public => false, :project => nil)
353 @request.session[:user_id] = 2
353 @request.session[:user_id] = 2
354
354
355 get :index, :query_id => q.id
355 get :index, :query_id => q.id
356 assert_response :success
356 assert_response :success
357 end
357 end
358
358
359 def test_public_query_should_be_available_to_other_users
359 def test_public_query_should_be_available_to_other_users
360 q = IssueQuery.create!(:name => "private", :user => User.find(2), :is_public => true, :project => nil)
360 q = IssueQuery.create!(:name => "private", :user => User.find(2), :is_public => true, :project => nil)
361 @request.session[:user_id] = 3
361 @request.session[:user_id] = 3
362
362
363 get :index, :query_id => q.id
363 get :index, :query_id => q.id
364 assert_response :success
364 assert_response :success
365 end
365 end
366
366
367 def test_index_should_omit_page_param_in_export_links
367 def test_index_should_omit_page_param_in_export_links
368 get :index, :page => 2
368 get :index, :page => 2
369 assert_response :success
369 assert_response :success
370 assert_select 'a.atom[href=/issues.atom]'
370 assert_select 'a.atom[href=/issues.atom]'
371 assert_select 'a.csv[href=/issues.csv]'
371 assert_select 'a.csv[href=/issues.csv]'
372 assert_select 'a.pdf[href=/issues.pdf]'
372 assert_select 'a.pdf[href=/issues.pdf]'
373 assert_select 'form#csv-export-form[action=/issues.csv]'
373 assert_select 'form#csv-export-form[action=/issues.csv]'
374 end
374 end
375
375
376 def test_index_csv
376 def test_index_csv
377 get :index, :format => 'csv'
377 get :index, :format => 'csv'
378 assert_response :success
378 assert_response :success
379 assert_not_nil assigns(:issues)
379 assert_not_nil assigns(:issues)
380 assert_equal 'text/csv; header=present', @response.content_type
380 assert_equal 'text/csv; header=present', @response.content_type
381 assert @response.body.starts_with?("#,")
381 assert @response.body.starts_with?("#,")
382 lines = @response.body.chomp.split("\n")
382 lines = @response.body.chomp.split("\n")
383 assert_equal assigns(:query).columns.size + 1, lines[0].split(',').size
383 assert_equal assigns(:query).columns.size + 1, lines[0].split(',').size
384 end
384 end
385
385
386 def test_index_csv_with_project
386 def test_index_csv_with_project
387 get :index, :project_id => 1, :format => 'csv'
387 get :index, :project_id => 1, :format => 'csv'
388 assert_response :success
388 assert_response :success
389 assert_not_nil assigns(:issues)
389 assert_not_nil assigns(:issues)
390 assert_equal 'text/csv; header=present', @response.content_type
390 assert_equal 'text/csv; header=present', @response.content_type
391 end
391 end
392
392
393 def test_index_csv_with_description
393 def test_index_csv_with_description
394 get :index, :format => 'csv', :description => '1'
394 get :index, :format => 'csv', :description => '1'
395 assert_response :success
395 assert_response :success
396 assert_not_nil assigns(:issues)
396 assert_not_nil assigns(:issues)
397 assert_equal 'text/csv; header=present', @response.content_type
397 assert_equal 'text/csv; header=present', @response.content_type
398 assert @response.body.starts_with?("#,")
398 assert @response.body.starts_with?("#,")
399 lines = @response.body.chomp.split("\n")
399 lines = @response.body.chomp.split("\n")
400 assert_equal assigns(:query).columns.size + 2, lines[0].split(',').size
400 assert_equal assigns(:query).columns.size + 2, lines[0].split(',').size
401 end
401 end
402
402
403 def test_index_csv_with_spent_time_column
403 def test_index_csv_with_spent_time_column
404 issue = Issue.create!(:project_id => 1, :tracker_id => 1, :subject => 'test_index_csv_with_spent_time_column', :author_id => 2)
404 issue = Issue.create!(:project_id => 1, :tracker_id => 1, :subject => 'test_index_csv_with_spent_time_column', :author_id => 2)
405 TimeEntry.create!(:project => issue.project, :issue => issue, :hours => 7.33, :user => User.find(2), :spent_on => Date.today)
405 TimeEntry.create!(:project => issue.project, :issue => issue, :hours => 7.33, :user => User.find(2), :spent_on => Date.today)
406
406
407 get :index, :format => 'csv', :set_filter => '1', :c => %w(subject spent_hours)
407 get :index, :format => 'csv', :set_filter => '1', :c => %w(subject spent_hours)
408 assert_response :success
408 assert_response :success
409 assert_equal 'text/csv; header=present', @response.content_type
409 assert_equal 'text/csv; header=present', @response.content_type
410 lines = @response.body.chomp.split("\n")
410 lines = @response.body.chomp.split("\n")
411 assert_include "#{issue.id},#{issue.subject},7.33", lines
411 assert_include "#{issue.id},#{issue.subject},7.33", lines
412 end
412 end
413
413
414 def test_index_csv_with_all_columns
414 def test_index_csv_with_all_columns
415 get :index, :format => 'csv', :columns => 'all'
415 get :index, :format => 'csv', :columns => 'all'
416 assert_response :success
416 assert_response :success
417 assert_not_nil assigns(:issues)
417 assert_not_nil assigns(:issues)
418 assert_equal 'text/csv; header=present', @response.content_type
418 assert_equal 'text/csv; header=present', @response.content_type
419 assert @response.body.starts_with?("#,")
419 assert @response.body.starts_with?("#,")
420 lines = @response.body.chomp.split("\n")
420 lines = @response.body.chomp.split("\n")
421 assert_equal assigns(:query).available_inline_columns.size + 1, lines[0].split(',').size
421 assert_equal assigns(:query).available_inline_columns.size + 1, lines[0].split(',').size
422 end
422 end
423
423
424 def test_index_csv_with_multi_column_field
424 def test_index_csv_with_multi_column_field
425 CustomField.find(1).update_attribute :multiple, true
425 CustomField.find(1).update_attribute :multiple, true
426 issue = Issue.find(1)
426 issue = Issue.find(1)
427 issue.custom_field_values = {1 => ['MySQL', 'Oracle']}
427 issue.custom_field_values = {1 => ['MySQL', 'Oracle']}
428 issue.save!
428 issue.save!
429
429
430 get :index, :format => 'csv', :columns => 'all'
430 get :index, :format => 'csv', :columns => 'all'
431 assert_response :success
431 assert_response :success
432 lines = @response.body.chomp.split("\n")
432 lines = @response.body.chomp.split("\n")
433 assert lines.detect {|line| line.include?('"MySQL, Oracle"')}
433 assert lines.detect {|line| line.include?('"MySQL, Oracle"')}
434 end
434 end
435
435
436 def test_index_csv_big_5
436 def test_index_csv_big_5
437 with_settings :default_language => "zh-TW" do
437 with_settings :default_language => "zh-TW" do
438 str_utf8 = "\xe4\xb8\x80\xe6\x9c\x88"
438 str_utf8 = "\xe4\xb8\x80\xe6\x9c\x88"
439 str_big5 = "\xa4@\xa4\xeb"
439 str_big5 = "\xa4@\xa4\xeb"
440 if str_utf8.respond_to?(:force_encoding)
440 if str_utf8.respond_to?(:force_encoding)
441 str_utf8.force_encoding('UTF-8')
441 str_utf8.force_encoding('UTF-8')
442 str_big5.force_encoding('Big5')
442 str_big5.force_encoding('Big5')
443 end
443 end
444 issue = Issue.generate!(:subject => str_utf8)
444 issue = Issue.generate!(:subject => str_utf8)
445
445
446 get :index, :project_id => 1,
446 get :index, :project_id => 1,
447 :f => ['subject'],
447 :f => ['subject'],
448 :op => '=', :values => [str_utf8],
448 :op => '=', :values => [str_utf8],
449 :format => 'csv'
449 :format => 'csv'
450 assert_equal 'text/csv; header=present', @response.content_type
450 assert_equal 'text/csv; header=present', @response.content_type
451 lines = @response.body.chomp.split("\n")
451 lines = @response.body.chomp.split("\n")
452 s1 = "\xaa\xac\xbaA"
452 s1 = "\xaa\xac\xbaA"
453 if str_utf8.respond_to?(:force_encoding)
453 if str_utf8.respond_to?(:force_encoding)
454 s1.force_encoding('Big5')
454 s1.force_encoding('Big5')
455 end
455 end
456 assert lines[0].include?(s1)
456 assert lines[0].include?(s1)
457 assert lines[1].include?(str_big5)
457 assert lines[1].include?(str_big5)
458 end
458 end
459 end
459 end
460
460
461 def test_index_csv_cannot_convert_should_be_replaced_big_5
461 def test_index_csv_cannot_convert_should_be_replaced_big_5
462 with_settings :default_language => "zh-TW" do
462 with_settings :default_language => "zh-TW" do
463 str_utf8 = "\xe4\xbb\xa5\xe5\x86\x85"
463 str_utf8 = "\xe4\xbb\xa5\xe5\x86\x85"
464 if str_utf8.respond_to?(:force_encoding)
464 if str_utf8.respond_to?(:force_encoding)
465 str_utf8.force_encoding('UTF-8')
465 str_utf8.force_encoding('UTF-8')
466 end
466 end
467 issue = Issue.generate!(:subject => str_utf8)
467 issue = Issue.generate!(:subject => str_utf8)
468
468
469 get :index, :project_id => 1,
469 get :index, :project_id => 1,
470 :f => ['subject'],
470 :f => ['subject'],
471 :op => '=', :values => [str_utf8],
471 :op => '=', :values => [str_utf8],
472 :c => ['status', 'subject'],
472 :c => ['status', 'subject'],
473 :format => 'csv',
473 :format => 'csv',
474 :set_filter => 1
474 :set_filter => 1
475 assert_equal 'text/csv; header=present', @response.content_type
475 assert_equal 'text/csv; header=present', @response.content_type
476 lines = @response.body.chomp.split("\n")
476 lines = @response.body.chomp.split("\n")
477 s1 = "\xaa\xac\xbaA" # status
477 s1 = "\xaa\xac\xbaA" # status
478 if str_utf8.respond_to?(:force_encoding)
478 if str_utf8.respond_to?(:force_encoding)
479 s1.force_encoding('Big5')
479 s1.force_encoding('Big5')
480 end
480 end
481 assert lines[0].include?(s1)
481 assert lines[0].include?(s1)
482 s2 = lines[1].split(",")[2]
482 s2 = lines[1].split(",")[2]
483 if s1.respond_to?(:force_encoding)
483 if s1.respond_to?(:force_encoding)
484 s3 = "\xa5H?" # subject
484 s3 = "\xa5H?" # subject
485 s3.force_encoding('Big5')
485 s3.force_encoding('Big5')
486 assert_equal s3, s2
486 assert_equal s3, s2
487 elsif RUBY_PLATFORM == 'java'
487 elsif RUBY_PLATFORM == 'java'
488 assert_equal "??", s2
488 assert_equal "??", s2
489 else
489 else
490 assert_equal "\xa5H???", s2
490 assert_equal "\xa5H???", s2
491 end
491 end
492 end
492 end
493 end
493 end
494
494
495 def test_index_csv_tw
495 def test_index_csv_tw
496 with_settings :default_language => "zh-TW" do
496 with_settings :default_language => "zh-TW" do
497 str1 = "test_index_csv_tw"
497 str1 = "test_index_csv_tw"
498 issue = Issue.generate!(:subject => str1, :estimated_hours => '1234.5')
498 issue = Issue.generate!(:subject => str1, :estimated_hours => '1234.5')
499
499
500 get :index, :project_id => 1,
500 get :index, :project_id => 1,
501 :f => ['subject'],
501 :f => ['subject'],
502 :op => '=', :values => [str1],
502 :op => '=', :values => [str1],
503 :c => ['estimated_hours', 'subject'],
503 :c => ['estimated_hours', 'subject'],
504 :format => 'csv',
504 :format => 'csv',
505 :set_filter => 1
505 :set_filter => 1
506 assert_equal 'text/csv; header=present', @response.content_type
506 assert_equal 'text/csv; header=present', @response.content_type
507 lines = @response.body.chomp.split("\n")
507 lines = @response.body.chomp.split("\n")
508 assert_equal "#{issue.id},1234.50,#{str1}", lines[1]
508 assert_equal "#{issue.id},1234.50,#{str1}", lines[1]
509 end
509 end
510 end
510 end
511
511
512 def test_index_csv_fr
512 def test_index_csv_fr
513 with_settings :default_language => "fr" do
513 with_settings :default_language => "fr" do
514 str1 = "test_index_csv_fr"
514 str1 = "test_index_csv_fr"
515 issue = Issue.generate!(:subject => str1, :estimated_hours => '1234.5')
515 issue = Issue.generate!(:subject => str1, :estimated_hours => '1234.5')
516
516
517 get :index, :project_id => 1,
517 get :index, :project_id => 1,
518 :f => ['subject'],
518 :f => ['subject'],
519 :op => '=', :values => [str1],
519 :op => '=', :values => [str1],
520 :c => ['estimated_hours', 'subject'],
520 :c => ['estimated_hours', 'subject'],
521 :format => 'csv',
521 :format => 'csv',
522 :set_filter => 1
522 :set_filter => 1
523 assert_equal 'text/csv; header=present', @response.content_type
523 assert_equal 'text/csv; header=present', @response.content_type
524 lines = @response.body.chomp.split("\n")
524 lines = @response.body.chomp.split("\n")
525 assert_equal "#{issue.id};1234,50;#{str1}", lines[1]
525 assert_equal "#{issue.id};1234,50;#{str1}", lines[1]
526 end
526 end
527 end
527 end
528
528
529 def test_index_pdf
529 def test_index_pdf
530 ["en", "zh", "zh-TW", "ja", "ko"].each do |lang|
530 ["en", "zh", "zh-TW", "ja", "ko"].each do |lang|
531 with_settings :default_language => lang do
531 with_settings :default_language => lang do
532
532
533 get :index
533 get :index
534 assert_response :success
534 assert_response :success
535 assert_template 'index'
535 assert_template 'index'
536
536
537 if lang == "ja"
537 if lang == "ja"
538 if RUBY_PLATFORM != 'java'
538 if RUBY_PLATFORM != 'java'
539 assert_equal "CP932", l(:general_pdf_encoding)
539 assert_equal "CP932", l(:general_pdf_encoding)
540 end
540 end
541 if RUBY_PLATFORM == 'java' && l(:general_pdf_encoding) == "CP932"
541 if RUBY_PLATFORM == 'java' && l(:general_pdf_encoding) == "CP932"
542 next
542 next
543 end
543 end
544 end
544 end
545
545
546 get :index, :format => 'pdf'
546 get :index, :format => 'pdf'
547 assert_response :success
547 assert_response :success
548 assert_not_nil assigns(:issues)
548 assert_not_nil assigns(:issues)
549 assert_equal 'application/pdf', @response.content_type
549 assert_equal 'application/pdf', @response.content_type
550
550
551 get :index, :project_id => 1, :format => 'pdf'
551 get :index, :project_id => 1, :format => 'pdf'
552 assert_response :success
552 assert_response :success
553 assert_not_nil assigns(:issues)
553 assert_not_nil assigns(:issues)
554 assert_equal 'application/pdf', @response.content_type
554 assert_equal 'application/pdf', @response.content_type
555
555
556 get :index, :project_id => 1, :query_id => 6, :format => 'pdf'
556 get :index, :project_id => 1, :query_id => 6, :format => 'pdf'
557 assert_response :success
557 assert_response :success
558 assert_not_nil assigns(:issues)
558 assert_not_nil assigns(:issues)
559 assert_equal 'application/pdf', @response.content_type
559 assert_equal 'application/pdf', @response.content_type
560 end
560 end
561 end
561 end
562 end
562 end
563
563
564 def test_index_pdf_with_query_grouped_by_list_custom_field
564 def test_index_pdf_with_query_grouped_by_list_custom_field
565 get :index, :project_id => 1, :query_id => 9, :format => 'pdf'
565 get :index, :project_id => 1, :query_id => 9, :format => 'pdf'
566 assert_response :success
566 assert_response :success
567 assert_not_nil assigns(:issues)
567 assert_not_nil assigns(:issues)
568 assert_not_nil assigns(:issue_count_by_group)
568 assert_not_nil assigns(:issue_count_by_group)
569 assert_equal 'application/pdf', @response.content_type
569 assert_equal 'application/pdf', @response.content_type
570 end
570 end
571
571
572 def test_index_atom
572 def test_index_atom
573 get :index, :project_id => 'ecookbook', :format => 'atom'
573 get :index, :project_id => 'ecookbook', :format => 'atom'
574 assert_response :success
574 assert_response :success
575 assert_template 'common/feed'
575 assert_template 'common/feed'
576 assert_equal 'application/atom+xml', response.content_type
576 assert_equal 'application/atom+xml', response.content_type
577
577
578 assert_select 'feed' do
578 assert_select 'feed' do
579 assert_select 'link[rel=self][href=?]', 'http://test.host/projects/ecookbook/issues.atom'
579 assert_select 'link[rel=self][href=?]', 'http://test.host/projects/ecookbook/issues.atom'
580 assert_select 'link[rel=alternate][href=?]', 'http://test.host/projects/ecookbook/issues'
580 assert_select 'link[rel=alternate][href=?]', 'http://test.host/projects/ecookbook/issues'
581 assert_select 'entry link[href=?]', 'http://test.host/issues/1'
581 assert_select 'entry link[href=?]', 'http://test.host/issues/1'
582 end
582 end
583 end
583 end
584
584
585 def test_index_sort
585 def test_index_sort
586 get :index, :sort => 'tracker,id:desc'
586 get :index, :sort => 'tracker,id:desc'
587 assert_response :success
587 assert_response :success
588
588
589 sort_params = @request.session['issues_index_sort']
589 sort_params = @request.session['issues_index_sort']
590 assert sort_params.is_a?(String)
590 assert sort_params.is_a?(String)
591 assert_equal 'tracker,id:desc', sort_params
591 assert_equal 'tracker,id:desc', sort_params
592
592
593 issues = assigns(:issues)
593 issues = assigns(:issues)
594 assert_not_nil issues
594 assert_not_nil issues
595 assert !issues.empty?
595 assert !issues.empty?
596 assert_equal issues.sort {|a,b| a.tracker == b.tracker ? b.id <=> a.id : a.tracker <=> b.tracker }.collect(&:id), issues.collect(&:id)
596 assert_equal issues.sort {|a,b| a.tracker == b.tracker ? b.id <=> a.id : a.tracker <=> b.tracker }.collect(&:id), issues.collect(&:id)
597 end
597 end
598
598
599 def test_index_sort_by_field_not_included_in_columns
599 def test_index_sort_by_field_not_included_in_columns
600 Setting.issue_list_default_columns = %w(subject author)
600 Setting.issue_list_default_columns = %w(subject author)
601 get :index, :sort => 'tracker'
601 get :index, :sort => 'tracker'
602 end
602 end
603
603
604 def test_index_sort_by_assigned_to
604 def test_index_sort_by_assigned_to
605 get :index, :sort => 'assigned_to'
605 get :index, :sort => 'assigned_to'
606 assert_response :success
606 assert_response :success
607 assignees = assigns(:issues).collect(&:assigned_to).compact
607 assignees = assigns(:issues).collect(&:assigned_to).compact
608 assert_equal assignees.sort, assignees
608 assert_equal assignees.sort, assignees
609 end
609 end
610
610
611 def test_index_sort_by_assigned_to_desc
611 def test_index_sort_by_assigned_to_desc
612 get :index, :sort => 'assigned_to:desc'
612 get :index, :sort => 'assigned_to:desc'
613 assert_response :success
613 assert_response :success
614 assignees = assigns(:issues).collect(&:assigned_to).compact
614 assignees = assigns(:issues).collect(&:assigned_to).compact
615 assert_equal assignees.sort.reverse, assignees
615 assert_equal assignees.sort.reverse, assignees
616 end
616 end
617
617
618 def test_index_group_by_assigned_to
618 def test_index_group_by_assigned_to
619 get :index, :group_by => 'assigned_to', :sort => 'priority'
619 get :index, :group_by => 'assigned_to', :sort => 'priority'
620 assert_response :success
620 assert_response :success
621 end
621 end
622
622
623 def test_index_sort_by_author
623 def test_index_sort_by_author
624 get :index, :sort => 'author'
624 get :index, :sort => 'author'
625 assert_response :success
625 assert_response :success
626 authors = assigns(:issues).collect(&:author)
626 authors = assigns(:issues).collect(&:author)
627 assert_equal authors.sort, authors
627 assert_equal authors.sort, authors
628 end
628 end
629
629
630 def test_index_sort_by_author_desc
630 def test_index_sort_by_author_desc
631 get :index, :sort => 'author:desc'
631 get :index, :sort => 'author:desc'
632 assert_response :success
632 assert_response :success
633 authors = assigns(:issues).collect(&:author)
633 authors = assigns(:issues).collect(&:author)
634 assert_equal authors.sort.reverse, authors
634 assert_equal authors.sort.reverse, authors
635 end
635 end
636
636
637 def test_index_group_by_author
637 def test_index_group_by_author
638 get :index, :group_by => 'author', :sort => 'priority'
638 get :index, :group_by => 'author', :sort => 'priority'
639 assert_response :success
639 assert_response :success
640 end
640 end
641
641
642 def test_index_sort_by_spent_hours
642 def test_index_sort_by_spent_hours
643 get :index, :sort => 'spent_hours:desc'
643 get :index, :sort => 'spent_hours:desc'
644 assert_response :success
644 assert_response :success
645 hours = assigns(:issues).collect(&:spent_hours)
645 hours = assigns(:issues).collect(&:spent_hours)
646 assert_equal hours.sort.reverse, hours
646 assert_equal hours.sort.reverse, hours
647 end
647 end
648
648
649 def test_index_sort_by_user_custom_field
649 def test_index_sort_by_user_custom_field
650 cf = IssueCustomField.create!(:name => 'User', :is_for_all => true, :tracker_ids => [1,2,3], :field_format => 'user')
650 cf = IssueCustomField.create!(:name => 'User', :is_for_all => true, :tracker_ids => [1,2,3], :field_format => 'user')
651 CustomValue.create!(:custom_field => cf, :customized => Issue.find(1), :value => '2')
651 CustomValue.create!(:custom_field => cf, :customized => Issue.find(1), :value => '2')
652 CustomValue.create!(:custom_field => cf, :customized => Issue.find(2), :value => '3')
652 CustomValue.create!(:custom_field => cf, :customized => Issue.find(2), :value => '3')
653 CustomValue.create!(:custom_field => cf, :customized => Issue.find(3), :value => '3')
653 CustomValue.create!(:custom_field => cf, :customized => Issue.find(3), :value => '3')
654 CustomValue.create!(:custom_field => cf, :customized => Issue.find(5), :value => '')
654 CustomValue.create!(:custom_field => cf, :customized => Issue.find(5), :value => '')
655
655
656 get :index, :project_id => 1, :set_filter => 1, :sort => "cf_#{cf.id},id"
656 get :index, :project_id => 1, :set_filter => 1, :sort => "cf_#{cf.id},id"
657 assert_response :success
657 assert_response :success
658
658
659 assert_equal [2, 3, 1], assigns(:issues).select {|issue| issue.custom_field_value(cf).present?}.map(&:id)
659 assert_equal [2, 3, 1], assigns(:issues).select {|issue| issue.custom_field_value(cf).present?}.map(&:id)
660 end
660 end
661
661
662 def test_index_with_columns
662 def test_index_with_columns
663 columns = ['tracker', 'subject', 'assigned_to']
663 columns = ['tracker', 'subject', 'assigned_to']
664 get :index, :set_filter => 1, :c => columns
664 get :index, :set_filter => 1, :c => columns
665 assert_response :success
665 assert_response :success
666
666
667 # query should use specified columns
667 # query should use specified columns
668 query = assigns(:query)
668 query = assigns(:query)
669 assert_kind_of IssueQuery, query
669 assert_kind_of IssueQuery, query
670 assert_equal columns, query.column_names.map(&:to_s)
670 assert_equal columns, query.column_names.map(&:to_s)
671
671
672 # columns should be stored in session
672 # columns should be stored in session
673 assert_kind_of Hash, session[:query]
673 assert_kind_of Hash, session[:query]
674 assert_kind_of Array, session[:query][:column_names]
674 assert_kind_of Array, session[:query][:column_names]
675 assert_equal columns, session[:query][:column_names].map(&:to_s)
675 assert_equal columns, session[:query][:column_names].map(&:to_s)
676
676
677 # ensure only these columns are kept in the selected columns list
677 # ensure only these columns are kept in the selected columns list
678 assert_select 'select#selected_columns option' do
678 assert_select 'select#selected_columns option' do
679 assert_select 'option', 3
679 assert_select 'option', 3
680 assert_select 'option[value=tracker]'
680 assert_select 'option[value=tracker]'
681 assert_select 'option[value=project]', 0
681 assert_select 'option[value=project]', 0
682 end
682 end
683 end
683 end
684
684
685 def test_index_without_project_should_implicitly_add_project_column_to_default_columns
685 def test_index_without_project_should_implicitly_add_project_column_to_default_columns
686 Setting.issue_list_default_columns = ['tracker', 'subject', 'assigned_to']
686 Setting.issue_list_default_columns = ['tracker', 'subject', 'assigned_to']
687 get :index, :set_filter => 1
687 get :index, :set_filter => 1
688
688
689 # query should use specified columns
689 # query should use specified columns
690 query = assigns(:query)
690 query = assigns(:query)
691 assert_kind_of IssueQuery, query
691 assert_kind_of IssueQuery, query
692 assert_equal [:project, :tracker, :subject, :assigned_to], query.columns.map(&:name)
692 assert_equal [:project, :tracker, :subject, :assigned_to], query.columns.map(&:name)
693 end
693 end
694
694
695 def test_index_without_project_and_explicit_default_columns_should_not_add_project_column
695 def test_index_without_project_and_explicit_default_columns_should_not_add_project_column
696 Setting.issue_list_default_columns = ['tracker', 'subject', 'assigned_to']
696 Setting.issue_list_default_columns = ['tracker', 'subject', 'assigned_to']
697 columns = ['tracker', 'subject', 'assigned_to']
697 columns = ['tracker', 'subject', 'assigned_to']
698 get :index, :set_filter => 1, :c => columns
698 get :index, :set_filter => 1, :c => columns
699
699
700 # query should use specified columns
700 # query should use specified columns
701 query = assigns(:query)
701 query = assigns(:query)
702 assert_kind_of IssueQuery, query
702 assert_kind_of IssueQuery, query
703 assert_equal columns.map(&:to_sym), query.columns.map(&:name)
703 assert_equal columns.map(&:to_sym), query.columns.map(&:name)
704 end
704 end
705
705
706 def test_index_with_custom_field_column
706 def test_index_with_custom_field_column
707 columns = %w(tracker subject cf_2)
707 columns = %w(tracker subject cf_2)
708 get :index, :set_filter => 1, :c => columns
708 get :index, :set_filter => 1, :c => columns
709 assert_response :success
709 assert_response :success
710
710
711 # query should use specified columns
711 # query should use specified columns
712 query = assigns(:query)
712 query = assigns(:query)
713 assert_kind_of IssueQuery, query
713 assert_kind_of IssueQuery, query
714 assert_equal columns, query.column_names.map(&:to_s)
714 assert_equal columns, query.column_names.map(&:to_s)
715
715
716 assert_select 'table.issues td.cf_2.string'
716 assert_select 'table.issues td.cf_2.string'
717 end
717 end
718
718
719 def test_index_with_multi_custom_field_column
719 def test_index_with_multi_custom_field_column
720 field = CustomField.find(1)
720 field = CustomField.find(1)
721 field.update_attribute :multiple, true
721 field.update_attribute :multiple, true
722 issue = Issue.find(1)
722 issue = Issue.find(1)
723 issue.custom_field_values = {1 => ['MySQL', 'Oracle']}
723 issue.custom_field_values = {1 => ['MySQL', 'Oracle']}
724 issue.save!
724 issue.save!
725
725
726 get :index, :set_filter => 1, :c => %w(tracker subject cf_1)
726 get :index, :set_filter => 1, :c => %w(tracker subject cf_1)
727 assert_response :success
727 assert_response :success
728
728
729 assert_select 'table.issues td.cf_1', :text => 'MySQL, Oracle'
729 assert_select 'table.issues td.cf_1', :text => 'MySQL, Oracle'
730 end
730 end
731
731
732 def test_index_with_multi_user_custom_field_column
732 def test_index_with_multi_user_custom_field_column
733 field = IssueCustomField.create!(:name => 'Multi user', :field_format => 'user', :multiple => true,
733 field = IssueCustomField.create!(:name => 'Multi user', :field_format => 'user', :multiple => true,
734 :tracker_ids => [1], :is_for_all => true)
734 :tracker_ids => [1], :is_for_all => true)
735 issue = Issue.find(1)
735 issue = Issue.find(1)
736 issue.custom_field_values = {field.id => ['2', '3']}
736 issue.custom_field_values = {field.id => ['2', '3']}
737 issue.save!
737 issue.save!
738
738
739 get :index, :set_filter => 1, :c => ['tracker', 'subject', "cf_#{field.id}"]
739 get :index, :set_filter => 1, :c => ['tracker', 'subject', "cf_#{field.id}"]
740 assert_response :success
740 assert_response :success
741
741
742 assert_select "table.issues td.cf_#{field.id}" do
742 assert_select "table.issues td.cf_#{field.id}" do
743 assert_select 'a', 2
743 assert_select 'a', 2
744 assert_select 'a[href=?]', '/users/2', :text => 'John Smith'
744 assert_select 'a[href=?]', '/users/2', :text => 'John Smith'
745 assert_select 'a[href=?]', '/users/3', :text => 'Dave Lopper'
745 assert_select 'a[href=?]', '/users/3', :text => 'Dave Lopper'
746 end
746 end
747 end
747 end
748
748
749 def test_index_with_date_column
749 def test_index_with_date_column
750 with_settings :date_format => '%d/%m/%Y' do
750 with_settings :date_format => '%d/%m/%Y' do
751 Issue.find(1).update_attribute :start_date, '1987-08-24'
751 Issue.find(1).update_attribute :start_date, '1987-08-24'
752
752
753 get :index, :set_filter => 1, :c => %w(start_date)
753 get :index, :set_filter => 1, :c => %w(start_date)
754
754
755 assert_select "table.issues td.start_date", :text => '24/08/1987'
755 assert_select "table.issues td.start_date", :text => '24/08/1987'
756 end
756 end
757 end
757 end
758
758
759 def test_index_with_done_ratio_column
759 def test_index_with_done_ratio_column
760 Issue.find(1).update_attribute :done_ratio, 40
760 Issue.find(1).update_attribute :done_ratio, 40
761
761
762 get :index, :set_filter => 1, :c => %w(done_ratio)
762 get :index, :set_filter => 1, :c => %w(done_ratio)
763
763
764 assert_select 'table.issues td.done_ratio' do
764 assert_select 'table.issues td.done_ratio' do
765 assert_select 'table.progress' do
765 assert_select 'table.progress' do
766 assert_select 'td.closed[style=?]', 'width: 40%;'
766 assert_select 'td.closed[style=?]', 'width: 40%;'
767 end
767 end
768 end
768 end
769 end
769 end
770
770
771 def test_index_with_spent_hours_column
771 def test_index_with_spent_hours_column
772 get :index, :set_filter => 1, :c => %w(subject spent_hours)
772 get :index, :set_filter => 1, :c => %w(subject spent_hours)
773
773
774 assert_select 'table.issues tr#issue-3 td.spent_hours', :text => '1.00'
774 assert_select 'table.issues tr#issue-3 td.spent_hours', :text => '1.00'
775 end
775 end
776
776
777 def test_index_should_not_show_spent_hours_column_without_permission
777 def test_index_should_not_show_spent_hours_column_without_permission
778 Role.anonymous.remove_permission! :view_time_entries
778 Role.anonymous.remove_permission! :view_time_entries
779 get :index, :set_filter => 1, :c => %w(subject spent_hours)
779 get :index, :set_filter => 1, :c => %w(subject spent_hours)
780
780
781 assert_select 'td.spent_hours', 0
781 assert_select 'td.spent_hours', 0
782 end
782 end
783
783
784 def test_index_with_fixed_version_column
784 def test_index_with_fixed_version_column
785 get :index, :set_filter => 1, :c => %w(fixed_version)
785 get :index, :set_filter => 1, :c => %w(fixed_version)
786
786
787 assert_select 'table.issues td.fixed_version' do
787 assert_select 'table.issues td.fixed_version' do
788 assert_select 'a[href=?]', '/versions/2', :text => '1.0'
788 assert_select 'a[href=?]', '/versions/2', :text => '1.0'
789 end
789 end
790 end
790 end
791
791
792 def test_index_with_relations_column
792 def test_index_with_relations_column
793 IssueRelation.delete_all
793 IssueRelation.delete_all
794 IssueRelation.create!(:relation_type => "relates", :issue_from => Issue.find(1), :issue_to => Issue.find(7))
794 IssueRelation.create!(:relation_type => "relates", :issue_from => Issue.find(1), :issue_to => Issue.find(7))
795 IssueRelation.create!(:relation_type => "relates", :issue_from => Issue.find(8), :issue_to => Issue.find(1))
795 IssueRelation.create!(:relation_type => "relates", :issue_from => Issue.find(8), :issue_to => Issue.find(1))
796 IssueRelation.create!(:relation_type => "blocks", :issue_from => Issue.find(1), :issue_to => Issue.find(11))
796 IssueRelation.create!(:relation_type => "blocks", :issue_from => Issue.find(1), :issue_to => Issue.find(11))
797 IssueRelation.create!(:relation_type => "blocks", :issue_from => Issue.find(12), :issue_to => Issue.find(2))
797 IssueRelation.create!(:relation_type => "blocks", :issue_from => Issue.find(12), :issue_to => Issue.find(2))
798
798
799 get :index, :set_filter => 1, :c => %w(subject relations)
799 get :index, :set_filter => 1, :c => %w(subject relations)
800 assert_response :success
800 assert_response :success
801 assert_select "tr#issue-1 td.relations" do
801 assert_select "tr#issue-1 td.relations" do
802 assert_select "span", 3
802 assert_select "span", 3
803 assert_select "span", :text => "Related to #7"
803 assert_select "span", :text => "Related to #7"
804 assert_select "span", :text => "Related to #8"
804 assert_select "span", :text => "Related to #8"
805 assert_select "span", :text => "Blocks #11"
805 assert_select "span", :text => "Blocks #11"
806 end
806 end
807 assert_select "tr#issue-2 td.relations" do
807 assert_select "tr#issue-2 td.relations" do
808 assert_select "span", 1
808 assert_select "span", 1
809 assert_select "span", :text => "Blocked by #12"
809 assert_select "span", :text => "Blocked by #12"
810 end
810 end
811 assert_select "tr#issue-3 td.relations" do
811 assert_select "tr#issue-3 td.relations" do
812 assert_select "span", 0
812 assert_select "span", 0
813 end
813 end
814
814
815 get :index, :set_filter => 1, :c => %w(relations), :format => 'csv'
815 get :index, :set_filter => 1, :c => %w(relations), :format => 'csv'
816 assert_response :success
816 assert_response :success
817 assert_equal 'text/csv; header=present', response.content_type
817 assert_equal 'text/csv; header=present', response.content_type
818 lines = response.body.chomp.split("\n")
818 lines = response.body.chomp.split("\n")
819 assert_include '1,"Related to #7, Related to #8, Blocks #11"', lines
819 assert_include '1,"Related to #7, Related to #8, Blocks #11"', lines
820 assert_include '2,Blocked by #12', lines
820 assert_include '2,Blocked by #12', lines
821 assert_include '3,""', lines
821 assert_include '3,""', lines
822
822
823 get :index, :set_filter => 1, :c => %w(subject relations), :format => 'pdf'
823 get :index, :set_filter => 1, :c => %w(subject relations), :format => 'pdf'
824 assert_response :success
824 assert_response :success
825 assert_equal 'application/pdf', response.content_type
825 assert_equal 'application/pdf', response.content_type
826 end
826 end
827
827
828 def test_index_with_description_column
828 def test_index_with_description_column
829 get :index, :set_filter => 1, :c => %w(subject description)
829 get :index, :set_filter => 1, :c => %w(subject description)
830
830
831 assert_select 'table.issues thead th', 3 # columns: chekbox + id + subject
831 assert_select 'table.issues thead th', 3 # columns: chekbox + id + subject
832 assert_select 'td.description[colspan=3]', :text => 'Unable to print recipes'
832 assert_select 'td.description[colspan=3]', :text => 'Unable to print recipes'
833
833
834 get :index, :set_filter => 1, :c => %w(subject description), :format => 'pdf'
834 get :index, :set_filter => 1, :c => %w(subject description), :format => 'pdf'
835 assert_response :success
835 assert_response :success
836 assert_equal 'application/pdf', response.content_type
836 assert_equal 'application/pdf', response.content_type
837 end
837 end
838
838
839 def test_index_send_html_if_query_is_invalid
839 def test_index_send_html_if_query_is_invalid
840 get :index, :f => ['start_date'], :op => {:start_date => '='}
840 get :index, :f => ['start_date'], :op => {:start_date => '='}
841 assert_equal 'text/html', @response.content_type
841 assert_equal 'text/html', @response.content_type
842 assert_template 'index'
842 assert_template 'index'
843 end
843 end
844
844
845 def test_index_send_nothing_if_query_is_invalid
845 def test_index_send_nothing_if_query_is_invalid
846 get :index, :f => ['start_date'], :op => {:start_date => '='}, :format => 'csv'
846 get :index, :f => ['start_date'], :op => {:start_date => '='}, :format => 'csv'
847 assert_equal 'text/csv', @response.content_type
847 assert_equal 'text/csv', @response.content_type
848 assert @response.body.blank?
848 assert @response.body.blank?
849 end
849 end
850
850
851 def test_show_by_anonymous
851 def test_show_by_anonymous
852 get :show, :id => 1
852 get :show, :id => 1
853 assert_response :success
853 assert_response :success
854 assert_template 'show'
854 assert_template 'show'
855 assert_equal Issue.find(1), assigns(:issue)
855 assert_equal Issue.find(1), assigns(:issue)
856
856
857 assert_select 'div.issue div.description', :text => /Unable to print recipes/
857 assert_select 'div.issue div.description', :text => /Unable to print recipes/
858
858
859 # anonymous role is allowed to add a note
859 # anonymous role is allowed to add a note
860 assert_select 'form#issue-form' do
860 assert_select 'form#issue-form' do
861 assert_select 'fieldset' do
861 assert_select 'fieldset' do
862 assert_select 'legend', :text => 'Notes'
862 assert_select 'legend', :text => 'Notes'
863 assert_select 'textarea[name=?]', 'issue[notes]'
863 assert_select 'textarea[name=?]', 'issue[notes]'
864 end
864 end
865 end
865 end
866
866
867 assert_select 'title', :text => "Bug #1: Can&#x27;t print recipes - eCookbook - Redmine"
867 assert_select 'title', :text => "Bug #1: Can&#x27;t print recipes - eCookbook - Redmine"
868 end
868 end
869
869
870 def test_show_by_manager
870 def test_show_by_manager
871 @request.session[:user_id] = 2
871 @request.session[:user_id] = 2
872 get :show, :id => 1
872 get :show, :id => 1
873 assert_response :success
873 assert_response :success
874
874
875 assert_select 'a', :text => /Quote/
875 assert_select 'a', :text => /Quote/
876
876
877 assert_select 'form#issue-form' do
877 assert_select 'form#issue-form' do
878 assert_select 'fieldset' do
878 assert_select 'fieldset' do
879 assert_select 'legend', :text => 'Change properties'
879 assert_select 'legend', :text => 'Change properties'
880 assert_select 'input[name=?]', 'issue[subject]'
880 assert_select 'input[name=?]', 'issue[subject]'
881 end
881 end
882 assert_select 'fieldset' do
882 assert_select 'fieldset' do
883 assert_select 'legend', :text => 'Log time'
883 assert_select 'legend', :text => 'Log time'
884 assert_select 'input[name=?]', 'time_entry[hours]'
884 assert_select 'input[name=?]', 'time_entry[hours]'
885 end
885 end
886 assert_select 'fieldset' do
886 assert_select 'fieldset' do
887 assert_select 'legend', :text => 'Notes'
887 assert_select 'legend', :text => 'Notes'
888 assert_select 'textarea[name=?]', 'issue[notes]'
888 assert_select 'textarea[name=?]', 'issue[notes]'
889 end
889 end
890 end
890 end
891 end
891 end
892
892
893 def test_show_should_display_update_form
893 def test_show_should_display_update_form
894 @request.session[:user_id] = 2
894 @request.session[:user_id] = 2
895 get :show, :id => 1
895 get :show, :id => 1
896 assert_response :success
896 assert_response :success
897
897
898 assert_select 'form#issue-form' do
898 assert_select 'form#issue-form' do
899 assert_select 'input[name=?]', 'issue[is_private]'
899 assert_select 'input[name=?]', 'issue[is_private]'
900 assert_select 'select[name=?]', 'issue[project_id]'
900 assert_select 'select[name=?]', 'issue[project_id]'
901 assert_select 'select[name=?]', 'issue[tracker_id]'
901 assert_select 'select[name=?]', 'issue[tracker_id]'
902 assert_select 'input[name=?]', 'issue[subject]'
902 assert_select 'input[name=?]', 'issue[subject]'
903 assert_select 'textarea[name=?]', 'issue[description]'
903 assert_select 'textarea[name=?]', 'issue[description]'
904 assert_select 'select[name=?]', 'issue[status_id]'
904 assert_select 'select[name=?]', 'issue[status_id]'
905 assert_select 'select[name=?]', 'issue[priority_id]'
905 assert_select 'select[name=?]', 'issue[priority_id]'
906 assert_select 'select[name=?]', 'issue[assigned_to_id]'
906 assert_select 'select[name=?]', 'issue[assigned_to_id]'
907 assert_select 'select[name=?]', 'issue[category_id]'
907 assert_select 'select[name=?]', 'issue[category_id]'
908 assert_select 'select[name=?]', 'issue[fixed_version_id]'
908 assert_select 'select[name=?]', 'issue[fixed_version_id]'
909 assert_select 'input[name=?]', 'issue[parent_issue_id]'
909 assert_select 'input[name=?]', 'issue[parent_issue_id]'
910 assert_select 'input[name=?]', 'issue[start_date]'
910 assert_select 'input[name=?]', 'issue[start_date]'
911 assert_select 'input[name=?]', 'issue[due_date]'
911 assert_select 'input[name=?]', 'issue[due_date]'
912 assert_select 'select[name=?]', 'issue[done_ratio]'
912 assert_select 'select[name=?]', 'issue[done_ratio]'
913 assert_select 'input[name=?]', 'issue[custom_field_values][2]'
913 assert_select 'input[name=?]', 'issue[custom_field_values][2]'
914 assert_select 'input[name=?]', 'issue[watcher_user_ids][]', 0
914 assert_select 'input[name=?]', 'issue[watcher_user_ids][]', 0
915 assert_select 'textarea[name=?]', 'issue[notes]'
915 assert_select 'textarea[name=?]', 'issue[notes]'
916 end
916 end
917 end
917 end
918
918
919 def test_show_should_display_update_form_with_minimal_permissions
919 def test_show_should_display_update_form_with_minimal_permissions
920 Role.find(1).update_attribute :permissions, [:view_issues, :add_issue_notes]
920 Role.find(1).update_attribute :permissions, [:view_issues, :add_issue_notes]
921 WorkflowTransition.delete_all :role_id => 1
921 WorkflowTransition.delete_all :role_id => 1
922
922
923 @request.session[:user_id] = 2
923 @request.session[:user_id] = 2
924 get :show, :id => 1
924 get :show, :id => 1
925 assert_response :success
925 assert_response :success
926
926
927 assert_select 'form#issue-form' do
927 assert_select 'form#issue-form' do
928 assert_select 'input[name=?]', 'issue[is_private]', 0
928 assert_select 'input[name=?]', 'issue[is_private]', 0
929 assert_select 'select[name=?]', 'issue[project_id]', 0
929 assert_select 'select[name=?]', 'issue[project_id]', 0
930 assert_select 'select[name=?]', 'issue[tracker_id]', 0
930 assert_select 'select[name=?]', 'issue[tracker_id]', 0
931 assert_select 'input[name=?]', 'issue[subject]', 0
931 assert_select 'input[name=?]', 'issue[subject]', 0
932 assert_select 'textarea[name=?]', 'issue[description]', 0
932 assert_select 'textarea[name=?]', 'issue[description]', 0
933 assert_select 'select[name=?]', 'issue[status_id]', 0
933 assert_select 'select[name=?]', 'issue[status_id]', 0
934 assert_select 'select[name=?]', 'issue[priority_id]', 0
934 assert_select 'select[name=?]', 'issue[priority_id]', 0
935 assert_select 'select[name=?]', 'issue[assigned_to_id]', 0
935 assert_select 'select[name=?]', 'issue[assigned_to_id]', 0
936 assert_select 'select[name=?]', 'issue[category_id]', 0
936 assert_select 'select[name=?]', 'issue[category_id]', 0
937 assert_select 'select[name=?]', 'issue[fixed_version_id]', 0
937 assert_select 'select[name=?]', 'issue[fixed_version_id]', 0
938 assert_select 'input[name=?]', 'issue[parent_issue_id]', 0
938 assert_select 'input[name=?]', 'issue[parent_issue_id]', 0
939 assert_select 'input[name=?]', 'issue[start_date]', 0
939 assert_select 'input[name=?]', 'issue[start_date]', 0
940 assert_select 'input[name=?]', 'issue[due_date]', 0
940 assert_select 'input[name=?]', 'issue[due_date]', 0
941 assert_select 'select[name=?]', 'issue[done_ratio]', 0
941 assert_select 'select[name=?]', 'issue[done_ratio]', 0
942 assert_select 'input[name=?]', 'issue[custom_field_values][2]', 0
942 assert_select 'input[name=?]', 'issue[custom_field_values][2]', 0
943 assert_select 'input[name=?]', 'issue[watcher_user_ids][]', 0
943 assert_select 'input[name=?]', 'issue[watcher_user_ids][]', 0
944 assert_select 'textarea[name=?]', 'issue[notes]'
944 assert_select 'textarea[name=?]', 'issue[notes]'
945 end
945 end
946 end
946 end
947
947
948 def test_show_should_display_update_form_with_workflow_permissions
948 def test_show_should_display_update_form_with_workflow_permissions
949 Role.find(1).update_attribute :permissions, [:view_issues, :add_issue_notes]
949 Role.find(1).update_attribute :permissions, [:view_issues, :add_issue_notes]
950
950
951 @request.session[:user_id] = 2
951 @request.session[:user_id] = 2
952 get :show, :id => 1
952 get :show, :id => 1
953 assert_response :success
953 assert_response :success
954
954
955 assert_select 'form#issue-form' do
955 assert_select 'form#issue-form' do
956 assert_select 'input[name=?]', 'issue[is_private]', 0
956 assert_select 'input[name=?]', 'issue[is_private]', 0
957 assert_select 'select[name=?]', 'issue[project_id]', 0
957 assert_select 'select[name=?]', 'issue[project_id]', 0
958 assert_select 'select[name=?]', 'issue[tracker_id]', 0
958 assert_select 'select[name=?]', 'issue[tracker_id]', 0
959 assert_select 'input[name=?]', 'issue[subject]', 0
959 assert_select 'input[name=?]', 'issue[subject]', 0
960 assert_select 'textarea[name=?]', 'issue[description]', 0
960 assert_select 'textarea[name=?]', 'issue[description]', 0
961 assert_select 'select[name=?]', 'issue[status_id]'
961 assert_select 'select[name=?]', 'issue[status_id]'
962 assert_select 'select[name=?]', 'issue[priority_id]', 0
962 assert_select 'select[name=?]', 'issue[priority_id]', 0
963 assert_select 'select[name=?]', 'issue[assigned_to_id]'
963 assert_select 'select[name=?]', 'issue[assigned_to_id]'
964 assert_select 'select[name=?]', 'issue[category_id]', 0
964 assert_select 'select[name=?]', 'issue[category_id]', 0
965 assert_select 'select[name=?]', 'issue[fixed_version_id]'
965 assert_select 'select[name=?]', 'issue[fixed_version_id]'
966 assert_select 'input[name=?]', 'issue[parent_issue_id]', 0
966 assert_select 'input[name=?]', 'issue[parent_issue_id]', 0
967 assert_select 'input[name=?]', 'issue[start_date]', 0
967 assert_select 'input[name=?]', 'issue[start_date]', 0
968 assert_select 'input[name=?]', 'issue[due_date]', 0
968 assert_select 'input[name=?]', 'issue[due_date]', 0
969 assert_select 'select[name=?]', 'issue[done_ratio]'
969 assert_select 'select[name=?]', 'issue[done_ratio]'
970 assert_select 'input[name=?]', 'issue[custom_field_values][2]', 0
970 assert_select 'input[name=?]', 'issue[custom_field_values][2]', 0
971 assert_select 'input[name=?]', 'issue[watcher_user_ids][]', 0
971 assert_select 'input[name=?]', 'issue[watcher_user_ids][]', 0
972 assert_select 'textarea[name=?]', 'issue[notes]'
972 assert_select 'textarea[name=?]', 'issue[notes]'
973 end
973 end
974 end
974 end
975
975
976 def test_show_should_not_display_update_form_without_permissions
976 def test_show_should_not_display_update_form_without_permissions
977 Role.find(1).update_attribute :permissions, [:view_issues]
977 Role.find(1).update_attribute :permissions, [:view_issues]
978
978
979 @request.session[:user_id] = 2
979 @request.session[:user_id] = 2
980 get :show, :id => 1
980 get :show, :id => 1
981 assert_response :success
981 assert_response :success
982
982
983 assert_select 'form#issue-form', 0
983 assert_select 'form#issue-form', 0
984 end
984 end
985
985
986 def test_update_form_should_not_display_inactive_enumerations
986 def test_update_form_should_not_display_inactive_enumerations
987 assert !IssuePriority.find(15).active?
987 assert !IssuePriority.find(15).active?
988
988
989 @request.session[:user_id] = 2
989 @request.session[:user_id] = 2
990 get :show, :id => 1
990 get :show, :id => 1
991 assert_response :success
991 assert_response :success
992
992
993 assert_select 'form#issue-form' do
993 assert_select 'form#issue-form' do
994 assert_select 'select[name=?]', 'issue[priority_id]' do
994 assert_select 'select[name=?]', 'issue[priority_id]' do
995 assert_select 'option[value=4]'
995 assert_select 'option[value=4]'
996 assert_select 'option[value=15]', 0
996 assert_select 'option[value=15]', 0
997 end
997 end
998 end
998 end
999 end
999 end
1000
1000
1001 def test_update_form_should_allow_attachment_upload
1001 def test_update_form_should_allow_attachment_upload
1002 @request.session[:user_id] = 2
1002 @request.session[:user_id] = 2
1003 get :show, :id => 1
1003 get :show, :id => 1
1004
1004
1005 assert_select 'form#issue-form[method=post][enctype=multipart/form-data]' do
1005 assert_select 'form#issue-form[method=post][enctype=multipart/form-data]' do
1006 assert_select 'input[type=file][name=?]', 'attachments[dummy][file]'
1006 assert_select 'input[type=file][name=?]', 'attachments[dummy][file]'
1007 end
1007 end
1008 end
1008 end
1009
1009
1010 def test_show_should_deny_anonymous_access_without_permission
1010 def test_show_should_deny_anonymous_access_without_permission
1011 Role.anonymous.remove_permission!(:view_issues)
1011 Role.anonymous.remove_permission!(:view_issues)
1012 get :show, :id => 1
1012 get :show, :id => 1
1013 assert_response :redirect
1013 assert_response :redirect
1014 end
1014 end
1015
1015
1016 def test_show_should_deny_anonymous_access_to_private_issue
1016 def test_show_should_deny_anonymous_access_to_private_issue
1017 Issue.update_all(["is_private = ?", true], "id = 1")
1017 Issue.update_all(["is_private = ?", true], "id = 1")
1018 get :show, :id => 1
1018 get :show, :id => 1
1019 assert_response :redirect
1019 assert_response :redirect
1020 end
1020 end
1021
1021
1022 def test_show_should_deny_non_member_access_without_permission
1022 def test_show_should_deny_non_member_access_without_permission
1023 Role.non_member.remove_permission!(:view_issues)
1023 Role.non_member.remove_permission!(:view_issues)
1024 @request.session[:user_id] = 9
1024 @request.session[:user_id] = 9
1025 get :show, :id => 1
1025 get :show, :id => 1
1026 assert_response 403
1026 assert_response 403
1027 end
1027 end
1028
1028
1029 def test_show_should_deny_non_member_access_to_private_issue
1029 def test_show_should_deny_non_member_access_to_private_issue
1030 Issue.update_all(["is_private = ?", true], "id = 1")
1030 Issue.update_all(["is_private = ?", true], "id = 1")
1031 @request.session[:user_id] = 9
1031 @request.session[:user_id] = 9
1032 get :show, :id => 1
1032 get :show, :id => 1
1033 assert_response 403
1033 assert_response 403
1034 end
1034 end
1035
1035
1036 def test_show_should_deny_member_access_without_permission
1036 def test_show_should_deny_member_access_without_permission
1037 Role.find(1).remove_permission!(:view_issues)
1037 Role.find(1).remove_permission!(:view_issues)
1038 @request.session[:user_id] = 2
1038 @request.session[:user_id] = 2
1039 get :show, :id => 1
1039 get :show, :id => 1
1040 assert_response 403
1040 assert_response 403
1041 end
1041 end
1042
1042
1043 def test_show_should_deny_member_access_to_private_issue_without_permission
1043 def test_show_should_deny_member_access_to_private_issue_without_permission
1044 Issue.update_all(["is_private = ?", true], "id = 1")
1044 Issue.update_all(["is_private = ?", true], "id = 1")
1045 @request.session[:user_id] = 3
1045 @request.session[:user_id] = 3
1046 get :show, :id => 1
1046 get :show, :id => 1
1047 assert_response 403
1047 assert_response 403
1048 end
1048 end
1049
1049
1050 def test_show_should_allow_author_access_to_private_issue
1050 def test_show_should_allow_author_access_to_private_issue
1051 Issue.update_all(["is_private = ?, author_id = 3", true], "id = 1")
1051 Issue.update_all(["is_private = ?, author_id = 3", true], "id = 1")
1052 @request.session[:user_id] = 3
1052 @request.session[:user_id] = 3
1053 get :show, :id => 1
1053 get :show, :id => 1
1054 assert_response :success
1054 assert_response :success
1055 end
1055 end
1056
1056
1057 def test_show_should_allow_assignee_access_to_private_issue
1057 def test_show_should_allow_assignee_access_to_private_issue
1058 Issue.update_all(["is_private = ?, assigned_to_id = 3", true], "id = 1")
1058 Issue.update_all(["is_private = ?, assigned_to_id = 3", true], "id = 1")
1059 @request.session[:user_id] = 3
1059 @request.session[:user_id] = 3
1060 get :show, :id => 1
1060 get :show, :id => 1
1061 assert_response :success
1061 assert_response :success
1062 end
1062 end
1063
1063
1064 def test_show_should_allow_member_access_to_private_issue_with_permission
1064 def test_show_should_allow_member_access_to_private_issue_with_permission
1065 Issue.update_all(["is_private = ?", true], "id = 1")
1065 Issue.update_all(["is_private = ?", true], "id = 1")
1066 User.find(3).roles_for_project(Project.find(1)).first.update_attribute :issues_visibility, 'all'
1066 User.find(3).roles_for_project(Project.find(1)).first.update_attribute :issues_visibility, 'all'
1067 @request.session[:user_id] = 3
1067 @request.session[:user_id] = 3
1068 get :show, :id => 1
1068 get :show, :id => 1
1069 assert_response :success
1069 assert_response :success
1070 end
1070 end
1071
1071
1072 def test_show_should_not_disclose_relations_to_invisible_issues
1072 def test_show_should_not_disclose_relations_to_invisible_issues
1073 Setting.cross_project_issue_relations = '1'
1073 Setting.cross_project_issue_relations = '1'
1074 IssueRelation.create!(:issue_from => Issue.find(1), :issue_to => Issue.find(2), :relation_type => 'relates')
1074 IssueRelation.create!(:issue_from => Issue.find(1), :issue_to => Issue.find(2), :relation_type => 'relates')
1075 # Relation to a private project issue
1075 # Relation to a private project issue
1076 IssueRelation.create!(:issue_from => Issue.find(1), :issue_to => Issue.find(4), :relation_type => 'relates')
1076 IssueRelation.create!(:issue_from => Issue.find(1), :issue_to => Issue.find(4), :relation_type => 'relates')
1077
1077
1078 get :show, :id => 1
1078 get :show, :id => 1
1079 assert_response :success
1079 assert_response :success
1080
1080
1081 assert_select 'div#relations' do
1081 assert_select 'div#relations' do
1082 assert_select 'a', :text => /#2$/
1082 assert_select 'a', :text => /#2$/
1083 assert_select 'a', :text => /#4$/, :count => 0
1083 assert_select 'a', :text => /#4$/, :count => 0
1084 end
1084 end
1085 end
1085 end
1086
1086
1087 def test_show_should_list_subtasks
1087 def test_show_should_list_subtasks
1088 Issue.create!(:project_id => 1, :author_id => 1, :tracker_id => 1, :parent_issue_id => 1, :subject => 'Child Issue')
1088 Issue.create!(:project_id => 1, :author_id => 1, :tracker_id => 1, :parent_issue_id => 1, :subject => 'Child Issue')
1089
1089
1090 get :show, :id => 1
1090 get :show, :id => 1
1091 assert_response :success
1091 assert_response :success
1092
1092
1093 assert_select 'div#issue_tree' do
1093 assert_select 'div#issue_tree' do
1094 assert_select 'td.subject', :text => /Child Issue/
1094 assert_select 'td.subject', :text => /Child Issue/
1095 end
1095 end
1096 end
1096 end
1097
1097
1098 def test_show_should_list_parents
1098 def test_show_should_list_parents
1099 issue = Issue.create!(:project_id => 1, :author_id => 1, :tracker_id => 1, :parent_issue_id => 1, :subject => 'Child Issue')
1099 issue = Issue.create!(:project_id => 1, :author_id => 1, :tracker_id => 1, :parent_issue_id => 1, :subject => 'Child Issue')
1100
1100
1101 get :show, :id => issue.id
1101 get :show, :id => issue.id
1102 assert_response :success
1102 assert_response :success
1103
1103
1104 assert_select 'div.subject' do
1104 assert_select 'div.subject' do
1105 assert_select 'h3', 'Child Issue'
1105 assert_select 'h3', 'Child Issue'
1106 assert_select 'a[href=/issues/1]'
1106 assert_select 'a[href=/issues/1]'
1107 end
1107 end
1108 end
1108 end
1109
1109
1110 def test_show_should_not_display_prev_next_links_without_query_in_session
1110 def test_show_should_not_display_prev_next_links_without_query_in_session
1111 get :show, :id => 1
1111 get :show, :id => 1
1112 assert_response :success
1112 assert_response :success
1113 assert_nil assigns(:prev_issue_id)
1113 assert_nil assigns(:prev_issue_id)
1114 assert_nil assigns(:next_issue_id)
1114 assert_nil assigns(:next_issue_id)
1115
1115
1116 assert_select 'div.next-prev-links', 0
1116 assert_select 'div.next-prev-links', 0
1117 end
1117 end
1118
1118
1119 def test_show_should_display_prev_next_links_with_query_in_session
1119 def test_show_should_display_prev_next_links_with_query_in_session
1120 @request.session[:query] = {:filters => {'status_id' => {:values => [''], :operator => 'o'}}, :project_id => nil}
1120 @request.session[:query] = {:filters => {'status_id' => {:values => [''], :operator => 'o'}}, :project_id => nil}
1121 @request.session['issues_index_sort'] = 'id'
1121 @request.session['issues_index_sort'] = 'id'
1122
1122
1123 with_settings :display_subprojects_issues => '0' do
1123 with_settings :display_subprojects_issues => '0' do
1124 get :show, :id => 3
1124 get :show, :id => 3
1125 end
1125 end
1126
1126
1127 assert_response :success
1127 assert_response :success
1128 # Previous and next issues for all projects
1128 # Previous and next issues for all projects
1129 assert_equal 2, assigns(:prev_issue_id)
1129 assert_equal 2, assigns(:prev_issue_id)
1130 assert_equal 5, assigns(:next_issue_id)
1130 assert_equal 5, assigns(:next_issue_id)
1131
1131
1132 count = Issue.open.visible.count
1132 count = Issue.open.visible.count
1133
1133
1134 assert_select 'div.next-prev-links' do
1134 assert_select 'div.next-prev-links' do
1135 assert_select 'a[href=/issues/2]', :text => /Previous/
1135 assert_select 'a[href=/issues/2]', :text => /Previous/
1136 assert_select 'a[href=/issues/5]', :text => /Next/
1136 assert_select 'a[href=/issues/5]', :text => /Next/
1137 assert_select 'span.position', :text => "3 of #{count}"
1137 assert_select 'span.position', :text => "3 of #{count}"
1138 end
1138 end
1139 end
1139 end
1140
1140
1141 def test_show_should_display_prev_next_links_with_saved_query_in_session
1141 def test_show_should_display_prev_next_links_with_saved_query_in_session
1142 query = IssueQuery.create!(:name => 'test', :is_public => true, :user_id => 1,
1142 query = IssueQuery.create!(:name => 'test', :is_public => true, :user_id => 1,
1143 :filters => {'status_id' => {:values => ['5'], :operator => '='}},
1143 :filters => {'status_id' => {:values => ['5'], :operator => '='}},
1144 :sort_criteria => [['id', 'asc']])
1144 :sort_criteria => [['id', 'asc']])
1145 @request.session[:query] = {:id => query.id, :project_id => nil}
1145 @request.session[:query] = {:id => query.id, :project_id => nil}
1146
1146
1147 get :show, :id => 11
1147 get :show, :id => 11
1148
1148
1149 assert_response :success
1149 assert_response :success
1150 assert_equal query, assigns(:query)
1150 assert_equal query, assigns(:query)
1151 # Previous and next issues for all projects
1151 # Previous and next issues for all projects
1152 assert_equal 8, assigns(:prev_issue_id)
1152 assert_equal 8, assigns(:prev_issue_id)
1153 assert_equal 12, assigns(:next_issue_id)
1153 assert_equal 12, assigns(:next_issue_id)
1154
1154
1155 assert_select 'div.next-prev-links' do
1155 assert_select 'div.next-prev-links' do
1156 assert_select 'a[href=/issues/8]', :text => /Previous/
1156 assert_select 'a[href=/issues/8]', :text => /Previous/
1157 assert_select 'a[href=/issues/12]', :text => /Next/
1157 assert_select 'a[href=/issues/12]', :text => /Next/
1158 end
1158 end
1159 end
1159 end
1160
1160
1161 def test_show_should_display_prev_next_links_with_query_and_sort_on_association
1161 def test_show_should_display_prev_next_links_with_query_and_sort_on_association
1162 @request.session[:query] = {:filters => {'status_id' => {:values => [''], :operator => 'o'}}, :project_id => nil}
1162 @request.session[:query] = {:filters => {'status_id' => {:values => [''], :operator => 'o'}}, :project_id => nil}
1163
1163
1164 %w(project tracker status priority author assigned_to category fixed_version).each do |assoc_sort|
1164 %w(project tracker status priority author assigned_to category fixed_version).each do |assoc_sort|
1165 @request.session['issues_index_sort'] = assoc_sort
1165 @request.session['issues_index_sort'] = assoc_sort
1166
1166
1167 get :show, :id => 3
1167 get :show, :id => 3
1168 assert_response :success, "Wrong response status for #{assoc_sort} sort"
1168 assert_response :success, "Wrong response status for #{assoc_sort} sort"
1169
1169
1170 assert_select 'div.next-prev-links' do
1170 assert_select 'div.next-prev-links' do
1171 assert_select 'a', :text => /(Previous|Next)/
1171 assert_select 'a', :text => /(Previous|Next)/
1172 end
1172 end
1173 end
1173 end
1174 end
1174 end
1175
1175
1176 def test_show_should_display_prev_next_links_with_project_query_in_session
1176 def test_show_should_display_prev_next_links_with_project_query_in_session
1177 @request.session[:query] = {:filters => {'status_id' => {:values => [''], :operator => 'o'}}, :project_id => 1}
1177 @request.session[:query] = {:filters => {'status_id' => {:values => [''], :operator => 'o'}}, :project_id => 1}
1178 @request.session['issues_index_sort'] = 'id'
1178 @request.session['issues_index_sort'] = 'id'
1179
1179
1180 with_settings :display_subprojects_issues => '0' do
1180 with_settings :display_subprojects_issues => '0' do
1181 get :show, :id => 3
1181 get :show, :id => 3
1182 end
1182 end
1183
1183
1184 assert_response :success
1184 assert_response :success
1185 # Previous and next issues inside project
1185 # Previous and next issues inside project
1186 assert_equal 2, assigns(:prev_issue_id)
1186 assert_equal 2, assigns(:prev_issue_id)
1187 assert_equal 7, assigns(:next_issue_id)
1187 assert_equal 7, assigns(:next_issue_id)
1188
1188
1189 assert_select 'div.next-prev-links' do
1189 assert_select 'div.next-prev-links' do
1190 assert_select 'a[href=/issues/2]', :text => /Previous/
1190 assert_select 'a[href=/issues/2]', :text => /Previous/
1191 assert_select 'a[href=/issues/7]', :text => /Next/
1191 assert_select 'a[href=/issues/7]', :text => /Next/
1192 end
1192 end
1193 end
1193 end
1194
1194
1195 def test_show_should_not_display_prev_link_for_first_issue
1195 def test_show_should_not_display_prev_link_for_first_issue
1196 @request.session[:query] = {:filters => {'status_id' => {:values => [''], :operator => 'o'}}, :project_id => 1}
1196 @request.session[:query] = {:filters => {'status_id' => {:values => [''], :operator => 'o'}}, :project_id => 1}
1197 @request.session['issues_index_sort'] = 'id'
1197 @request.session['issues_index_sort'] = 'id'
1198
1198
1199 with_settings :display_subprojects_issues => '0' do
1199 with_settings :display_subprojects_issues => '0' do
1200 get :show, :id => 1
1200 get :show, :id => 1
1201 end
1201 end
1202
1202
1203 assert_response :success
1203 assert_response :success
1204 assert_nil assigns(:prev_issue_id)
1204 assert_nil assigns(:prev_issue_id)
1205 assert_equal 2, assigns(:next_issue_id)
1205 assert_equal 2, assigns(:next_issue_id)
1206
1206
1207 assert_select 'div.next-prev-links' do
1207 assert_select 'div.next-prev-links' do
1208 assert_select 'a', :text => /Previous/, :count => 0
1208 assert_select 'a', :text => /Previous/, :count => 0
1209 assert_select 'a[href=/issues/2]', :text => /Next/
1209 assert_select 'a[href=/issues/2]', :text => /Next/
1210 end
1210 end
1211 end
1211 end
1212
1212
1213 def test_show_should_not_display_prev_next_links_for_issue_not_in_query_results
1213 def test_show_should_not_display_prev_next_links_for_issue_not_in_query_results
1214 @request.session[:query] = {:filters => {'status_id' => {:values => [''], :operator => 'c'}}, :project_id => 1}
1214 @request.session[:query] = {:filters => {'status_id' => {:values => [''], :operator => 'c'}}, :project_id => 1}
1215 @request.session['issues_index_sort'] = 'id'
1215 @request.session['issues_index_sort'] = 'id'
1216
1216
1217 get :show, :id => 1
1217 get :show, :id => 1
1218
1218
1219 assert_response :success
1219 assert_response :success
1220 assert_nil assigns(:prev_issue_id)
1220 assert_nil assigns(:prev_issue_id)
1221 assert_nil assigns(:next_issue_id)
1221 assert_nil assigns(:next_issue_id)
1222
1222
1223 assert_select 'a', :text => /Previous/, :count => 0
1223 assert_select 'a', :text => /Previous/, :count => 0
1224 assert_select 'a', :text => /Next/, :count => 0
1224 assert_select 'a', :text => /Next/, :count => 0
1225 end
1225 end
1226
1226
1227 def test_show_show_should_display_prev_next_links_with_query_sort_by_user_custom_field
1227 def test_show_show_should_display_prev_next_links_with_query_sort_by_user_custom_field
1228 cf = IssueCustomField.create!(:name => 'User', :is_for_all => true, :tracker_ids => [1,2,3], :field_format => 'user')
1228 cf = IssueCustomField.create!(:name => 'User', :is_for_all => true, :tracker_ids => [1,2,3], :field_format => 'user')
1229 CustomValue.create!(:custom_field => cf, :customized => Issue.find(1), :value => '2')
1229 CustomValue.create!(:custom_field => cf, :customized => Issue.find(1), :value => '2')
1230 CustomValue.create!(:custom_field => cf, :customized => Issue.find(2), :value => '3')
1230 CustomValue.create!(:custom_field => cf, :customized => Issue.find(2), :value => '3')
1231 CustomValue.create!(:custom_field => cf, :customized => Issue.find(3), :value => '3')
1231 CustomValue.create!(:custom_field => cf, :customized => Issue.find(3), :value => '3')
1232 CustomValue.create!(:custom_field => cf, :customized => Issue.find(5), :value => '')
1232 CustomValue.create!(:custom_field => cf, :customized => Issue.find(5), :value => '')
1233
1233
1234 query = IssueQuery.create!(:name => 'test', :is_public => true, :user_id => 1, :filters => {},
1234 query = IssueQuery.create!(:name => 'test', :is_public => true, :user_id => 1, :filters => {},
1235 :sort_criteria => [["cf_#{cf.id}", 'asc'], ['id', 'asc']])
1235 :sort_criteria => [["cf_#{cf.id}", 'asc'], ['id', 'asc']])
1236 @request.session[:query] = {:id => query.id, :project_id => nil}
1236 @request.session[:query] = {:id => query.id, :project_id => nil}
1237
1237
1238 get :show, :id => 3
1238 get :show, :id => 3
1239 assert_response :success
1239 assert_response :success
1240
1240
1241 assert_equal 2, assigns(:prev_issue_id)
1241 assert_equal 2, assigns(:prev_issue_id)
1242 assert_equal 1, assigns(:next_issue_id)
1242 assert_equal 1, assigns(:next_issue_id)
1243
1243
1244 assert_select 'div.next-prev-links' do
1244 assert_select 'div.next-prev-links' do
1245 assert_select 'a[href=/issues/2]', :text => /Previous/
1245 assert_select 'a[href=/issues/2]', :text => /Previous/
1246 assert_select 'a[href=/issues/1]', :text => /Next/
1246 assert_select 'a[href=/issues/1]', :text => /Next/
1247 end
1247 end
1248 end
1248 end
1249
1249
1250 def test_show_should_display_link_to_the_assignee
1250 def test_show_should_display_link_to_the_assignee
1251 get :show, :id => 2
1251 get :show, :id => 2
1252 assert_response :success
1252 assert_response :success
1253 assert_select '.assigned-to' do
1253 assert_select '.assigned-to' do
1254 assert_select 'a[href=/users/3]'
1254 assert_select 'a[href=/users/3]'
1255 end
1255 end
1256 end
1256 end
1257
1257
1258 def test_show_should_display_visible_changesets_from_other_projects
1258 def test_show_should_display_visible_changesets_from_other_projects
1259 project = Project.find(2)
1259 project = Project.find(2)
1260 issue = project.issues.first
1260 issue = project.issues.first
1261 issue.changeset_ids = [102]
1261 issue.changeset_ids = [102]
1262 issue.save!
1262 issue.save!
1263 # changesets from other projects should be displayed even if repository
1263 # changesets from other projects should be displayed even if repository
1264 # is disabled on issue's project
1264 # is disabled on issue's project
1265 project.disable_module! :repository
1265 project.disable_module! :repository
1266
1266
1267 @request.session[:user_id] = 2
1267 @request.session[:user_id] = 2
1268 get :show, :id => issue.id
1268 get :show, :id => issue.id
1269
1269
1270 assert_select 'a[href=?]', '/projects/ecookbook/repository/revisions/3'
1270 assert_select 'a[href=?]', '/projects/ecookbook/repository/revisions/3'
1271 end
1271 end
1272
1272
1273 def test_show_should_display_watchers
1273 def test_show_should_display_watchers
1274 @request.session[:user_id] = 2
1274 @request.session[:user_id] = 2
1275 Issue.find(1).add_watcher User.find(2)
1275 Issue.find(1).add_watcher User.find(2)
1276
1276
1277 get :show, :id => 1
1277 get :show, :id => 1
1278 assert_select 'div#watchers ul' do
1278 assert_select 'div#watchers ul' do
1279 assert_select 'li' do
1279 assert_select 'li' do
1280 assert_select 'a[href=/users/2]'
1280 assert_select 'a[href=/users/2]'
1281 assert_select 'a img[alt=Delete]'
1281 assert_select 'a img[alt=Delete]'
1282 end
1282 end
1283 end
1283 end
1284 end
1284 end
1285
1285
1286 def test_show_should_display_watchers_with_gravatars
1286 def test_show_should_display_watchers_with_gravatars
1287 @request.session[:user_id] = 2
1287 @request.session[:user_id] = 2
1288 Issue.find(1).add_watcher User.find(2)
1288 Issue.find(1).add_watcher User.find(2)
1289
1289
1290 with_settings :gravatar_enabled => '1' do
1290 with_settings :gravatar_enabled => '1' do
1291 get :show, :id => 1
1291 get :show, :id => 1
1292 end
1292 end
1293
1293
1294 assert_select 'div#watchers ul' do
1294 assert_select 'div#watchers ul' do
1295 assert_select 'li' do
1295 assert_select 'li' do
1296 assert_select 'img.gravatar'
1296 assert_select 'img.gravatar'
1297 assert_select 'a[href=/users/2]'
1297 assert_select 'a[href=/users/2]'
1298 assert_select 'a img[alt=Delete]'
1298 assert_select 'a img[alt=Delete]'
1299 end
1299 end
1300 end
1300 end
1301 end
1301 end
1302
1302
1303 def test_show_with_thumbnails_enabled_should_display_thumbnails
1303 def test_show_with_thumbnails_enabled_should_display_thumbnails
1304 @request.session[:user_id] = 2
1304 @request.session[:user_id] = 2
1305
1305
1306 with_settings :thumbnails_enabled => '1' do
1306 with_settings :thumbnails_enabled => '1' do
1307 get :show, :id => 14
1307 get :show, :id => 14
1308 assert_response :success
1308 assert_response :success
1309 end
1309 end
1310
1310
1311 assert_select 'div.thumbnails' do
1311 assert_select 'div.thumbnails' do
1312 assert_select 'a[href=/attachments/16/testfile.png]' do
1312 assert_select 'a[href=/attachments/16/testfile.png]' do
1313 assert_select 'img[src=/attachments/thumbnail/16]'
1313 assert_select 'img[src=/attachments/thumbnail/16]'
1314 end
1314 end
1315 end
1315 end
1316 end
1316 end
1317
1317
1318 def test_show_with_thumbnails_disabled_should_not_display_thumbnails
1318 def test_show_with_thumbnails_disabled_should_not_display_thumbnails
1319 @request.session[:user_id] = 2
1319 @request.session[:user_id] = 2
1320
1320
1321 with_settings :thumbnails_enabled => '0' do
1321 with_settings :thumbnails_enabled => '0' do
1322 get :show, :id => 14
1322 get :show, :id => 14
1323 assert_response :success
1323 assert_response :success
1324 end
1324 end
1325
1325
1326 assert_select 'div.thumbnails', 0
1326 assert_select 'div.thumbnails', 0
1327 end
1327 end
1328
1328
1329 def test_show_with_multi_custom_field
1329 def test_show_with_multi_custom_field
1330 field = CustomField.find(1)
1330 field = CustomField.find(1)
1331 field.update_attribute :multiple, true
1331 field.update_attribute :multiple, true
1332 issue = Issue.find(1)
1332 issue = Issue.find(1)
1333 issue.custom_field_values = {1 => ['MySQL', 'Oracle']}
1333 issue.custom_field_values = {1 => ['MySQL', 'Oracle']}
1334 issue.save!
1334 issue.save!
1335
1335
1336 get :show, :id => 1
1336 get :show, :id => 1
1337 assert_response :success
1337 assert_response :success
1338
1338
1339 assert_select 'td', :text => 'MySQL, Oracle'
1339 assert_select 'td', :text => 'MySQL, Oracle'
1340 end
1340 end
1341
1341
1342 def test_show_with_multi_user_custom_field
1342 def test_show_with_multi_user_custom_field
1343 field = IssueCustomField.create!(:name => 'Multi user', :field_format => 'user', :multiple => true,
1343 field = IssueCustomField.create!(:name => 'Multi user', :field_format => 'user', :multiple => true,
1344 :tracker_ids => [1], :is_for_all => true)
1344 :tracker_ids => [1], :is_for_all => true)
1345 issue = Issue.find(1)
1345 issue = Issue.find(1)
1346 issue.custom_field_values = {field.id => ['2', '3']}
1346 issue.custom_field_values = {field.id => ['2', '3']}
1347 issue.save!
1347 issue.save!
1348
1348
1349 get :show, :id => 1
1349 get :show, :id => 1
1350 assert_response :success
1350 assert_response :success
1351
1351
1352 # TODO: should display links
1352 # TODO: should display links
1353 assert_select 'td', :text => 'Dave Lopper, John Smith'
1353 assert_select 'td', :text => 'Dave Lopper, John Smith'
1354 end
1354 end
1355
1355
1356 def test_show_should_display_private_notes_with_permission_only
1356 def test_show_should_display_private_notes_with_permission_only
1357 journal = Journal.create!(:journalized => Issue.find(2), :notes => 'Privates notes', :private_notes => true, :user_id => 1)
1357 journal = Journal.create!(:journalized => Issue.find(2), :notes => 'Privates notes', :private_notes => true, :user_id => 1)
1358 @request.session[:user_id] = 2
1358 @request.session[:user_id] = 2
1359
1359
1360 get :show, :id => 2
1360 get :show, :id => 2
1361 assert_response :success
1361 assert_response :success
1362 assert_include journal, assigns(:journals)
1362 assert_include journal, assigns(:journals)
1363
1363
1364 Role.find(1).remove_permission! :view_private_notes
1364 Role.find(1).remove_permission! :view_private_notes
1365 get :show, :id => 2
1365 get :show, :id => 2
1366 assert_response :success
1366 assert_response :success
1367 assert_not_include journal, assigns(:journals)
1367 assert_not_include journal, assigns(:journals)
1368 end
1368 end
1369
1369
1370 def test_show_atom
1370 def test_show_atom
1371 get :show, :id => 2, :format => 'atom'
1371 get :show, :id => 2, :format => 'atom'
1372 assert_response :success
1372 assert_response :success
1373 assert_template 'journals/index'
1373 assert_template 'journals/index'
1374 # Inline image
1374 # Inline image
1375 assert_select 'content', :text => Regexp.new(Regexp.quote('http://test.host/attachments/download/10'))
1375 assert_select 'content', :text => Regexp.new(Regexp.quote('http://test.host/attachments/download/10'))
1376 end
1376 end
1377
1377
1378 def test_show_export_to_pdf
1378 def test_show_export_to_pdf
1379 get :show, :id => 3, :format => 'pdf'
1379 get :show, :id => 3, :format => 'pdf'
1380 assert_response :success
1380 assert_response :success
1381 assert_equal 'application/pdf', @response.content_type
1381 assert_equal 'application/pdf', @response.content_type
1382 assert @response.body.starts_with?('%PDF')
1382 assert @response.body.starts_with?('%PDF')
1383 assert_not_nil assigns(:issue)
1383 assert_not_nil assigns(:issue)
1384 end
1384 end
1385
1385
1386 def test_show_export_to_pdf_with_ancestors
1386 def test_show_export_to_pdf_with_ancestors
1387 issue = Issue.generate!(:project_id => 1, :author_id => 2, :tracker_id => 1, :subject => 'child', :parent_issue_id => 1)
1387 issue = Issue.generate!(:project_id => 1, :author_id => 2, :tracker_id => 1, :subject => 'child', :parent_issue_id => 1)
1388
1388
1389 get :show, :id => issue.id, :format => 'pdf'
1389 get :show, :id => issue.id, :format => 'pdf'
1390 assert_response :success
1390 assert_response :success
1391 assert_equal 'application/pdf', @response.content_type
1391 assert_equal 'application/pdf', @response.content_type
1392 assert @response.body.starts_with?('%PDF')
1392 assert @response.body.starts_with?('%PDF')
1393 end
1393 end
1394
1394
1395 def test_show_export_to_pdf_with_descendants
1395 def test_show_export_to_pdf_with_descendants
1396 c1 = Issue.generate!(:project_id => 1, :author_id => 2, :tracker_id => 1, :subject => 'child', :parent_issue_id => 1)
1396 c1 = Issue.generate!(:project_id => 1, :author_id => 2, :tracker_id => 1, :subject => 'child', :parent_issue_id => 1)
1397 c2 = Issue.generate!(:project_id => 1, :author_id => 2, :tracker_id => 1, :subject => 'child', :parent_issue_id => 1)
1397 c2 = Issue.generate!(:project_id => 1, :author_id => 2, :tracker_id => 1, :subject => 'child', :parent_issue_id => 1)
1398 c3 = Issue.generate!(:project_id => 1, :author_id => 2, :tracker_id => 1, :subject => 'child', :parent_issue_id => c1.id)
1398 c3 = Issue.generate!(:project_id => 1, :author_id => 2, :tracker_id => 1, :subject => 'child', :parent_issue_id => c1.id)
1399
1399
1400 get :show, :id => 1, :format => 'pdf'
1400 get :show, :id => 1, :format => 'pdf'
1401 assert_response :success
1401 assert_response :success
1402 assert_equal 'application/pdf', @response.content_type
1402 assert_equal 'application/pdf', @response.content_type
1403 assert @response.body.starts_with?('%PDF')
1403 assert @response.body.starts_with?('%PDF')
1404 end
1404 end
1405
1405
1406 def test_show_export_to_pdf_with_journals
1406 def test_show_export_to_pdf_with_journals
1407 get :show, :id => 1, :format => 'pdf'
1407 get :show, :id => 1, :format => 'pdf'
1408 assert_response :success
1408 assert_response :success
1409 assert_equal 'application/pdf', @response.content_type
1409 assert_equal 'application/pdf', @response.content_type
1410 assert @response.body.starts_with?('%PDF')
1410 assert @response.body.starts_with?('%PDF')
1411 end
1411 end
1412
1412
1413 def test_show_export_to_pdf_with_changesets
1413 def test_show_export_to_pdf_with_changesets
1414 Issue.find(3).changesets = Changeset.find_all_by_id(100, 101, 102)
1414 Issue.find(3).changesets = Changeset.find_all_by_id(100, 101, 102)
1415
1415
1416 get :show, :id => 3, :format => 'pdf'
1416 get :show, :id => 3, :format => 'pdf'
1417 assert_response :success
1417 assert_response :success
1418 assert_equal 'application/pdf', @response.content_type
1418 assert_equal 'application/pdf', @response.content_type
1419 assert @response.body.starts_with?('%PDF')
1419 assert @response.body.starts_with?('%PDF')
1420 end
1420 end
1421
1421
1422 def test_show_invalid_should_respond_with_404
1422 def test_show_invalid_should_respond_with_404
1423 get :show, :id => 999
1423 get :show, :id => 999
1424 assert_response 404
1424 assert_response 404
1425 end
1425 end
1426
1426
1427 def test_get_new
1427 def test_get_new
1428 @request.session[:user_id] = 2
1428 @request.session[:user_id] = 2
1429 get :new, :project_id => 1, :tracker_id => 1
1429 get :new, :project_id => 1, :tracker_id => 1
1430 assert_response :success
1430 assert_response :success
1431 assert_template 'new'
1431 assert_template 'new'
1432
1432
1433 assert_select 'form#issue-form' do
1433 assert_select 'form#issue-form' do
1434 assert_select 'input[name=?]', 'issue[is_private]'
1434 assert_select 'input[name=?]', 'issue[is_private]'
1435 assert_select 'select[name=?]', 'issue[project_id]', 0
1435 assert_select 'select[name=?]', 'issue[project_id]', 0
1436 assert_select 'select[name=?]', 'issue[tracker_id]'
1436 assert_select 'select[name=?]', 'issue[tracker_id]'
1437 assert_select 'input[name=?]', 'issue[subject]'
1437 assert_select 'input[name=?]', 'issue[subject]'
1438 assert_select 'textarea[name=?]', 'issue[description]'
1438 assert_select 'textarea[name=?]', 'issue[description]'
1439 assert_select 'select[name=?]', 'issue[status_id]'
1439 assert_select 'select[name=?]', 'issue[status_id]'
1440 assert_select 'select[name=?]', 'issue[priority_id]'
1440 assert_select 'select[name=?]', 'issue[priority_id]'
1441 assert_select 'select[name=?]', 'issue[assigned_to_id]'
1441 assert_select 'select[name=?]', 'issue[assigned_to_id]'
1442 assert_select 'select[name=?]', 'issue[category_id]'
1442 assert_select 'select[name=?]', 'issue[category_id]'
1443 assert_select 'select[name=?]', 'issue[fixed_version_id]'
1443 assert_select 'select[name=?]', 'issue[fixed_version_id]'
1444 assert_select 'input[name=?]', 'issue[parent_issue_id]'
1444 assert_select 'input[name=?]', 'issue[parent_issue_id]'
1445 assert_select 'input[name=?]', 'issue[start_date]'
1445 assert_select 'input[name=?]', 'issue[start_date]'
1446 assert_select 'input[name=?]', 'issue[due_date]'
1446 assert_select 'input[name=?]', 'issue[due_date]'
1447 assert_select 'select[name=?]', 'issue[done_ratio]'
1447 assert_select 'select[name=?]', 'issue[done_ratio]'
1448 assert_select 'input[name=?][value=?]', 'issue[custom_field_values][2]', 'Default string'
1448 assert_select 'input[name=?][value=?]', 'issue[custom_field_values][2]', 'Default string'
1449 assert_select 'input[name=?]', 'issue[watcher_user_ids][]'
1449 assert_select 'input[name=?]', 'issue[watcher_user_ids][]'
1450 end
1450 end
1451
1451
1452 # Be sure we don't display inactive IssuePriorities
1452 # Be sure we don't display inactive IssuePriorities
1453 assert ! IssuePriority.find(15).active?
1453 assert ! IssuePriority.find(15).active?
1454 assert_select 'select[name=?]', 'issue[priority_id]' do
1454 assert_select 'select[name=?]', 'issue[priority_id]' do
1455 assert_select 'option[value=15]', 0
1455 assert_select 'option[value=15]', 0
1456 end
1456 end
1457 end
1457 end
1458
1458
1459 def test_get_new_with_minimal_permissions
1459 def test_get_new_with_minimal_permissions
1460 Role.find(1).update_attribute :permissions, [:add_issues]
1460 Role.find(1).update_attribute :permissions, [:add_issues]
1461 WorkflowTransition.delete_all :role_id => 1
1461 WorkflowTransition.delete_all :role_id => 1
1462
1462
1463 @request.session[:user_id] = 2
1463 @request.session[:user_id] = 2
1464 get :new, :project_id => 1, :tracker_id => 1
1464 get :new, :project_id => 1, :tracker_id => 1
1465 assert_response :success
1465 assert_response :success
1466 assert_template 'new'
1466 assert_template 'new'
1467
1467
1468 assert_select 'form#issue-form' do
1468 assert_select 'form#issue-form' do
1469 assert_select 'input[name=?]', 'issue[is_private]', 0
1469 assert_select 'input[name=?]', 'issue[is_private]', 0
1470 assert_select 'select[name=?]', 'issue[project_id]', 0
1470 assert_select 'select[name=?]', 'issue[project_id]', 0
1471 assert_select 'select[name=?]', 'issue[tracker_id]'
1471 assert_select 'select[name=?]', 'issue[tracker_id]'
1472 assert_select 'input[name=?]', 'issue[subject]'
1472 assert_select 'input[name=?]', 'issue[subject]'
1473 assert_select 'textarea[name=?]', 'issue[description]'
1473 assert_select 'textarea[name=?]', 'issue[description]'
1474 assert_select 'select[name=?]', 'issue[status_id]'
1474 assert_select 'select[name=?]', 'issue[status_id]'
1475 assert_select 'select[name=?]', 'issue[priority_id]'
1475 assert_select 'select[name=?]', 'issue[priority_id]'
1476 assert_select 'select[name=?]', 'issue[assigned_to_id]'
1476 assert_select 'select[name=?]', 'issue[assigned_to_id]'
1477 assert_select 'select[name=?]', 'issue[category_id]'
1477 assert_select 'select[name=?]', 'issue[category_id]'
1478 assert_select 'select[name=?]', 'issue[fixed_version_id]'
1478 assert_select 'select[name=?]', 'issue[fixed_version_id]'
1479 assert_select 'input[name=?]', 'issue[parent_issue_id]', 0
1479 assert_select 'input[name=?]', 'issue[parent_issue_id]', 0
1480 assert_select 'input[name=?]', 'issue[start_date]'
1480 assert_select 'input[name=?]', 'issue[start_date]'
1481 assert_select 'input[name=?]', 'issue[due_date]'
1481 assert_select 'input[name=?]', 'issue[due_date]'
1482 assert_select 'select[name=?]', 'issue[done_ratio]'
1482 assert_select 'select[name=?]', 'issue[done_ratio]'
1483 assert_select 'input[name=?][value=?]', 'issue[custom_field_values][2]', 'Default string'
1483 assert_select 'input[name=?][value=?]', 'issue[custom_field_values][2]', 'Default string'
1484 assert_select 'input[name=?]', 'issue[watcher_user_ids][]', 0
1484 assert_select 'input[name=?]', 'issue[watcher_user_ids][]', 0
1485 end
1485 end
1486 end
1486 end
1487
1487
1488 def test_get_new_with_list_custom_field
1488 def test_get_new_with_list_custom_field
1489 @request.session[:user_id] = 2
1489 @request.session[:user_id] = 2
1490 get :new, :project_id => 1, :tracker_id => 1
1490 get :new, :project_id => 1, :tracker_id => 1
1491 assert_response :success
1491 assert_response :success
1492 assert_template 'new'
1492 assert_template 'new'
1493
1493
1494 assert_select 'select.list_cf[name=?]', 'issue[custom_field_values][1]' do
1494 assert_select 'select.list_cf[name=?]', 'issue[custom_field_values][1]' do
1495 assert_select 'option', 4
1495 assert_select 'option', 4
1496 assert_select 'option[value=MySQL]', :text => 'MySQL'
1496 assert_select 'option[value=MySQL]', :text => 'MySQL'
1497 end
1497 end
1498 end
1498 end
1499
1499
1500 def test_get_new_with_multi_custom_field
1500 def test_get_new_with_multi_custom_field
1501 field = IssueCustomField.find(1)
1501 field = IssueCustomField.find(1)
1502 field.update_attribute :multiple, true
1502 field.update_attribute :multiple, true
1503
1503
1504 @request.session[:user_id] = 2
1504 @request.session[:user_id] = 2
1505 get :new, :project_id => 1, :tracker_id => 1
1505 get :new, :project_id => 1, :tracker_id => 1
1506 assert_response :success
1506 assert_response :success
1507 assert_template 'new'
1507 assert_template 'new'
1508
1508
1509 assert_select 'select[name=?][multiple=multiple]', 'issue[custom_field_values][1][]' do
1509 assert_select 'select[name=?][multiple=multiple]', 'issue[custom_field_values][1][]' do
1510 assert_select 'option', 3
1510 assert_select 'option', 3
1511 assert_select 'option[value=MySQL]', :text => 'MySQL'
1511 assert_select 'option[value=MySQL]', :text => 'MySQL'
1512 end
1512 end
1513 assert_select 'input[name=?][type=hidden][value=?]', 'issue[custom_field_values][1][]', ''
1513 assert_select 'input[name=?][type=hidden][value=?]', 'issue[custom_field_values][1][]', ''
1514 end
1514 end
1515
1515
1516 def test_get_new_with_multi_user_custom_field
1516 def test_get_new_with_multi_user_custom_field
1517 field = IssueCustomField.create!(:name => 'Multi user', :field_format => 'user', :multiple => true,
1517 field = IssueCustomField.create!(:name => 'Multi user', :field_format => 'user', :multiple => true,
1518 :tracker_ids => [1], :is_for_all => true)
1518 :tracker_ids => [1], :is_for_all => true)
1519
1519
1520 @request.session[:user_id] = 2
1520 @request.session[:user_id] = 2
1521 get :new, :project_id => 1, :tracker_id => 1
1521 get :new, :project_id => 1, :tracker_id => 1
1522 assert_response :success
1522 assert_response :success
1523 assert_template 'new'
1523 assert_template 'new'
1524
1524
1525 assert_select 'select[name=?][multiple=multiple]', "issue[custom_field_values][#{field.id}][]" do
1525 assert_select 'select[name=?][multiple=multiple]', "issue[custom_field_values][#{field.id}][]" do
1526 assert_select 'option', Project.find(1).users.count
1526 assert_select 'option', Project.find(1).users.count
1527 assert_select 'option[value=2]', :text => 'John Smith'
1527 assert_select 'option[value=2]', :text => 'John Smith'
1528 end
1528 end
1529 assert_select 'input[name=?][type=hidden][value=?]', "issue[custom_field_values][#{field.id}][]", ''
1529 assert_select 'input[name=?][type=hidden][value=?]', "issue[custom_field_values][#{field.id}][]", ''
1530 end
1530 end
1531
1531
1532 def test_get_new_with_date_custom_field
1532 def test_get_new_with_date_custom_field
1533 field = IssueCustomField.create!(:name => 'Date', :field_format => 'date', :tracker_ids => [1], :is_for_all => true)
1533 field = IssueCustomField.create!(:name => 'Date', :field_format => 'date', :tracker_ids => [1], :is_for_all => true)
1534
1534
1535 @request.session[:user_id] = 2
1535 @request.session[:user_id] = 2
1536 get :new, :project_id => 1, :tracker_id => 1
1536 get :new, :project_id => 1, :tracker_id => 1
1537 assert_response :success
1537 assert_response :success
1538
1538
1539 assert_select 'input[name=?]', "issue[custom_field_values][#{field.id}]"
1539 assert_select 'input[name=?]', "issue[custom_field_values][#{field.id}]"
1540 end
1540 end
1541
1541
1542 def test_get_new_with_text_custom_field
1542 def test_get_new_with_text_custom_field
1543 field = IssueCustomField.create!(:name => 'Text', :field_format => 'text', :tracker_ids => [1], :is_for_all => true)
1543 field = IssueCustomField.create!(:name => 'Text', :field_format => 'text', :tracker_ids => [1], :is_for_all => true)
1544
1544
1545 @request.session[:user_id] = 2
1545 @request.session[:user_id] = 2
1546 get :new, :project_id => 1, :tracker_id => 1
1546 get :new, :project_id => 1, :tracker_id => 1
1547 assert_response :success
1547 assert_response :success
1548
1548
1549 assert_select 'textarea[name=?]', "issue[custom_field_values][#{field.id}]"
1549 assert_select 'textarea[name=?]', "issue[custom_field_values][#{field.id}]"
1550 end
1550 end
1551
1551
1552 def test_get_new_without_default_start_date_is_creation_date
1552 def test_get_new_without_default_start_date_is_creation_date
1553 Setting.default_issue_start_date_to_creation_date = 0
1553 Setting.default_issue_start_date_to_creation_date = 0
1554
1554
1555 @request.session[:user_id] = 2
1555 @request.session[:user_id] = 2
1556 get :new, :project_id => 1, :tracker_id => 1
1556 get :new, :project_id => 1, :tracker_id => 1
1557 assert_response :success
1557 assert_response :success
1558 assert_template 'new'
1558 assert_template 'new'
1559
1559
1560 assert_select 'input[name=?]', 'issue[start_date]'
1560 assert_select 'input[name=?]', 'issue[start_date]'
1561 assert_select 'input[name=?][value]', 'issue[start_date]', 0
1561 assert_select 'input[name=?][value]', 'issue[start_date]', 0
1562 end
1562 end
1563
1563
1564 def test_get_new_with_default_start_date_is_creation_date
1564 def test_get_new_with_default_start_date_is_creation_date
1565 Setting.default_issue_start_date_to_creation_date = 1
1565 Setting.default_issue_start_date_to_creation_date = 1
1566
1566
1567 @request.session[:user_id] = 2
1567 @request.session[:user_id] = 2
1568 get :new, :project_id => 1, :tracker_id => 1
1568 get :new, :project_id => 1, :tracker_id => 1
1569 assert_response :success
1569 assert_response :success
1570 assert_template 'new'
1570 assert_template 'new'
1571
1571
1572 assert_select 'input[name=?][value=?]', 'issue[start_date]', Date.today.to_s
1572 assert_select 'input[name=?][value=?]', 'issue[start_date]', Date.today.to_s
1573 end
1573 end
1574
1574
1575 def test_get_new_form_should_allow_attachment_upload
1575 def test_get_new_form_should_allow_attachment_upload
1576 @request.session[:user_id] = 2
1576 @request.session[:user_id] = 2
1577 get :new, :project_id => 1, :tracker_id => 1
1577 get :new, :project_id => 1, :tracker_id => 1
1578
1578
1579 assert_select 'form[id=issue-form][method=post][enctype=multipart/form-data]' do
1579 assert_select 'form[id=issue-form][method=post][enctype=multipart/form-data]' do
1580 assert_select 'input[name=?][type=file]', 'attachments[dummy][file]'
1580 assert_select 'input[name=?][type=file]', 'attachments[dummy][file]'
1581 end
1581 end
1582 end
1582 end
1583
1583
1584 def test_get_new_should_prefill_the_form_from_params
1584 def test_get_new_should_prefill_the_form_from_params
1585 @request.session[:user_id] = 2
1585 @request.session[:user_id] = 2
1586 get :new, :project_id => 1,
1586 get :new, :project_id => 1,
1587 :issue => {:tracker_id => 3, :description => 'Prefilled', :custom_field_values => {'2' => 'Custom field value'}}
1587 :issue => {:tracker_id => 3, :description => 'Prefilled', :custom_field_values => {'2' => 'Custom field value'}}
1588
1588
1589 issue = assigns(:issue)
1589 issue = assigns(:issue)
1590 assert_equal 3, issue.tracker_id
1590 assert_equal 3, issue.tracker_id
1591 assert_equal 'Prefilled', issue.description
1591 assert_equal 'Prefilled', issue.description
1592 assert_equal 'Custom field value', issue.custom_field_value(2)
1592 assert_equal 'Custom field value', issue.custom_field_value(2)
1593
1593
1594 assert_select 'select[name=?]', 'issue[tracker_id]' do
1594 assert_select 'select[name=?]', 'issue[tracker_id]' do
1595 assert_select 'option[value=3][selected=selected]'
1595 assert_select 'option[value=3][selected=selected]'
1596 end
1596 end
1597 assert_select 'textarea[name=?]', 'issue[description]', :text => /Prefilled/
1597 assert_select 'textarea[name=?]', 'issue[description]', :text => /Prefilled/
1598 assert_select 'input[name=?][value=?]', 'issue[custom_field_values][2]', 'Custom field value'
1598 assert_select 'input[name=?][value=?]', 'issue[custom_field_values][2]', 'Custom field value'
1599 end
1599 end
1600
1600
1601 def test_get_new_should_mark_required_fields
1601 def test_get_new_should_mark_required_fields
1602 cf1 = IssueCustomField.create!(:name => 'Foo', :field_format => 'string', :is_for_all => true, :tracker_ids => [1, 2])
1602 cf1 = IssueCustomField.create!(:name => 'Foo', :field_format => 'string', :is_for_all => true, :tracker_ids => [1, 2])
1603 cf2 = IssueCustomField.create!(:name => 'Bar', :field_format => 'string', :is_for_all => true, :tracker_ids => [1, 2])
1603 cf2 = IssueCustomField.create!(:name => 'Bar', :field_format => 'string', :is_for_all => true, :tracker_ids => [1, 2])
1604 WorkflowPermission.delete_all
1604 WorkflowPermission.delete_all
1605 WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 1, :role_id => 1, :field_name => 'due_date', :rule => 'required')
1605 WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 1, :role_id => 1, :field_name => 'due_date', :rule => 'required')
1606 WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 1, :role_id => 1, :field_name => cf2.id.to_s, :rule => 'required')
1606 WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 1, :role_id => 1, :field_name => cf2.id.to_s, :rule => 'required')
1607 @request.session[:user_id] = 2
1607 @request.session[:user_id] = 2
1608
1608
1609 get :new, :project_id => 1
1609 get :new, :project_id => 1
1610 assert_response :success
1610 assert_response :success
1611 assert_template 'new'
1611 assert_template 'new'
1612
1612
1613 assert_select 'label[for=issue_start_date]' do
1613 assert_select 'label[for=issue_start_date]' do
1614 assert_select 'span[class=required]', 0
1614 assert_select 'span[class=required]', 0
1615 end
1615 end
1616 assert_select 'label[for=issue_due_date]' do
1616 assert_select 'label[for=issue_due_date]' do
1617 assert_select 'span[class=required]'
1617 assert_select 'span[class=required]'
1618 end
1618 end
1619 assert_select 'label[for=?]', "issue_custom_field_values_#{cf1.id}" do
1619 assert_select 'label[for=?]', "issue_custom_field_values_#{cf1.id}" do
1620 assert_select 'span[class=required]', 0
1620 assert_select 'span[class=required]', 0
1621 end
1621 end
1622 assert_select 'label[for=?]', "issue_custom_field_values_#{cf2.id}" do
1622 assert_select 'label[for=?]', "issue_custom_field_values_#{cf2.id}" do
1623 assert_select 'span[class=required]'
1623 assert_select 'span[class=required]'
1624 end
1624 end
1625 end
1625 end
1626
1626
1627 def test_get_new_should_not_display_readonly_fields
1627 def test_get_new_should_not_display_readonly_fields
1628 cf1 = IssueCustomField.create!(:name => 'Foo', :field_format => 'string', :is_for_all => true, :tracker_ids => [1, 2])
1628 cf1 = IssueCustomField.create!(:name => 'Foo', :field_format => 'string', :is_for_all => true, :tracker_ids => [1, 2])
1629 cf2 = IssueCustomField.create!(:name => 'Bar', :field_format => 'string', :is_for_all => true, :tracker_ids => [1, 2])
1629 cf2 = IssueCustomField.create!(:name => 'Bar', :field_format => 'string', :is_for_all => true, :tracker_ids => [1, 2])
1630 WorkflowPermission.delete_all
1630 WorkflowPermission.delete_all
1631 WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 1, :role_id => 1, :field_name => 'due_date', :rule => 'readonly')
1631 WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 1, :role_id => 1, :field_name => 'due_date', :rule => 'readonly')
1632 WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 1, :role_id => 1, :field_name => cf2.id.to_s, :rule => 'readonly')
1632 WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 1, :role_id => 1, :field_name => cf2.id.to_s, :rule => 'readonly')
1633 @request.session[:user_id] = 2
1633 @request.session[:user_id] = 2
1634
1634
1635 get :new, :project_id => 1
1635 get :new, :project_id => 1
1636 assert_response :success
1636 assert_response :success
1637 assert_template 'new'
1637 assert_template 'new'
1638
1638
1639 assert_select 'input[name=?]', 'issue[start_date]'
1639 assert_select 'input[name=?]', 'issue[start_date]'
1640 assert_select 'input[name=?]', 'issue[due_date]', 0
1640 assert_select 'input[name=?]', 'issue[due_date]', 0
1641 assert_select 'input[name=?]', "issue[custom_field_values][#{cf1.id}]"
1641 assert_select 'input[name=?]', "issue[custom_field_values][#{cf1.id}]"
1642 assert_select 'input[name=?]', "issue[custom_field_values][#{cf2.id}]", 0
1642 assert_select 'input[name=?]', "issue[custom_field_values][#{cf2.id}]", 0
1643 end
1643 end
1644
1644
1645 def test_get_new_without_tracker_id
1645 def test_get_new_without_tracker_id
1646 @request.session[:user_id] = 2
1646 @request.session[:user_id] = 2
1647 get :new, :project_id => 1
1647 get :new, :project_id => 1
1648 assert_response :success
1648 assert_response :success
1649 assert_template 'new'
1649 assert_template 'new'
1650
1650
1651 issue = assigns(:issue)
1651 issue = assigns(:issue)
1652 assert_not_nil issue
1652 assert_not_nil issue
1653 assert_equal Project.find(1).trackers.first, issue.tracker
1653 assert_equal Project.find(1).trackers.first, issue.tracker
1654 end
1654 end
1655
1655
1656 def test_get_new_with_no_default_status_should_display_an_error
1656 def test_get_new_with_no_default_status_should_display_an_error
1657 @request.session[:user_id] = 2
1657 @request.session[:user_id] = 2
1658 IssueStatus.delete_all
1658 IssueStatus.delete_all
1659
1659
1660 get :new, :project_id => 1
1660 get :new, :project_id => 1
1661 assert_response 500
1661 assert_response 500
1662 assert_error_tag :content => /No default issue/
1662 assert_error_tag :content => /No default issue/
1663 end
1663 end
1664
1664
1665 def test_get_new_with_no_tracker_should_display_an_error
1665 def test_get_new_with_no_tracker_should_display_an_error
1666 @request.session[:user_id] = 2
1666 @request.session[:user_id] = 2
1667 Tracker.delete_all
1667 Tracker.delete_all
1668
1668
1669 get :new, :project_id => 1
1669 get :new, :project_id => 1
1670 assert_response 500
1670 assert_response 500
1671 assert_error_tag :content => /No tracker/
1671 assert_error_tag :content => /No tracker/
1672 end
1672 end
1673
1673
1674 def test_update_new_form
1674 def test_update_form_for_new_issue
1675 @request.session[:user_id] = 2
1675 @request.session[:user_id] = 2
1676 xhr :post, :new, :project_id => 1,
1676 xhr :post, :update_form, :project_id => 1,
1677 :issue => {:tracker_id => 2,
1677 :issue => {:tracker_id => 2,
1678 :subject => 'This is the test_new issue',
1678 :subject => 'This is the test_new issue',
1679 :description => 'This is the description',
1679 :description => 'This is the description',
1680 :priority_id => 5}
1680 :priority_id => 5}
1681 assert_response :success
1681 assert_response :success
1682 assert_template 'update_form'
1682 assert_template 'update_form'
1683 assert_template 'form'
1683 assert_template 'form'
1684 assert_equal 'text/javascript', response.content_type
1684 assert_equal 'text/javascript', response.content_type
1685
1685
1686 issue = assigns(:issue)
1686 issue = assigns(:issue)
1687 assert_kind_of Issue, issue
1687 assert_kind_of Issue, issue
1688 assert_equal 1, issue.project_id
1688 assert_equal 1, issue.project_id
1689 assert_equal 2, issue.tracker_id
1689 assert_equal 2, issue.tracker_id
1690 assert_equal 'This is the test_new issue', issue.subject
1690 assert_equal 'This is the test_new issue', issue.subject
1691 end
1691 end
1692
1692
1693 def test_update_new_form_should_propose_transitions_based_on_initial_status
1693 def test_update_form_for_new_issue_should_propose_transitions_based_on_initial_status
1694 @request.session[:user_id] = 2
1694 @request.session[:user_id] = 2
1695 WorkflowTransition.delete_all
1695 WorkflowTransition.delete_all
1696 WorkflowTransition.create!(:role_id => 1, :tracker_id => 1, :old_status_id => 1, :new_status_id => 2)
1696 WorkflowTransition.create!(:role_id => 1, :tracker_id => 1, :old_status_id => 1, :new_status_id => 2)
1697 WorkflowTransition.create!(:role_id => 1, :tracker_id => 1, :old_status_id => 1, :new_status_id => 5)
1697 WorkflowTransition.create!(:role_id => 1, :tracker_id => 1, :old_status_id => 1, :new_status_id => 5)
1698 WorkflowTransition.create!(:role_id => 1, :tracker_id => 1, :old_status_id => 5, :new_status_id => 4)
1698 WorkflowTransition.create!(:role_id => 1, :tracker_id => 1, :old_status_id => 5, :new_status_id => 4)
1699
1699
1700 xhr :post, :new, :project_id => 1,
1700 xhr :post, :update_form, :project_id => 1,
1701 :issue => {:tracker_id => 1,
1701 :issue => {:tracker_id => 1,
1702 :status_id => 5,
1702 :status_id => 5,
1703 :subject => 'This is an issue'}
1703 :subject => 'This is an issue'}
1704
1704
1705 assert_equal 5, assigns(:issue).status_id
1705 assert_equal 5, assigns(:issue).status_id
1706 assert_equal [1,2,5], assigns(:allowed_statuses).map(&:id).sort
1706 assert_equal [1,2,5], assigns(:allowed_statuses).map(&:id).sort
1707 end
1707 end
1708
1708
1709 def test_post_create
1709 def test_post_create
1710 @request.session[:user_id] = 2
1710 @request.session[:user_id] = 2
1711 assert_difference 'Issue.count' do
1711 assert_difference 'Issue.count' do
1712 post :create, :project_id => 1,
1712 post :create, :project_id => 1,
1713 :issue => {:tracker_id => 3,
1713 :issue => {:tracker_id => 3,
1714 :status_id => 2,
1714 :status_id => 2,
1715 :subject => 'This is the test_new issue',
1715 :subject => 'This is the test_new issue',
1716 :description => 'This is the description',
1716 :description => 'This is the description',
1717 :priority_id => 5,
1717 :priority_id => 5,
1718 :start_date => '2010-11-07',
1718 :start_date => '2010-11-07',
1719 :estimated_hours => '',
1719 :estimated_hours => '',
1720 :custom_field_values => {'2' => 'Value for field 2'}}
1720 :custom_field_values => {'2' => 'Value for field 2'}}
1721 end
1721 end
1722 assert_redirected_to :controller => 'issues', :action => 'show', :id => Issue.last.id
1722 assert_redirected_to :controller => 'issues', :action => 'show', :id => Issue.last.id
1723
1723
1724 issue = Issue.find_by_subject('This is the test_new issue')
1724 issue = Issue.find_by_subject('This is the test_new issue')
1725 assert_not_nil issue
1725 assert_not_nil issue
1726 assert_equal 2, issue.author_id
1726 assert_equal 2, issue.author_id
1727 assert_equal 3, issue.tracker_id
1727 assert_equal 3, issue.tracker_id
1728 assert_equal 2, issue.status_id
1728 assert_equal 2, issue.status_id
1729 assert_equal Date.parse('2010-11-07'), issue.start_date
1729 assert_equal Date.parse('2010-11-07'), issue.start_date
1730 assert_nil issue.estimated_hours
1730 assert_nil issue.estimated_hours
1731 v = issue.custom_values.where(:custom_field_id => 2).first
1731 v = issue.custom_values.where(:custom_field_id => 2).first
1732 assert_not_nil v
1732 assert_not_nil v
1733 assert_equal 'Value for field 2', v.value
1733 assert_equal 'Value for field 2', v.value
1734 end
1734 end
1735
1735
1736 def test_post_new_with_group_assignment
1736 def test_post_new_with_group_assignment
1737 group = Group.find(11)
1737 group = Group.find(11)
1738 project = Project.find(1)
1738 project = Project.find(1)
1739 project.members << Member.new(:principal => group, :roles => [Role.givable.first])
1739 project.members << Member.new(:principal => group, :roles => [Role.givable.first])
1740
1740
1741 with_settings :issue_group_assignment => '1' do
1741 with_settings :issue_group_assignment => '1' do
1742 @request.session[:user_id] = 2
1742 @request.session[:user_id] = 2
1743 assert_difference 'Issue.count' do
1743 assert_difference 'Issue.count' do
1744 post :create, :project_id => project.id,
1744 post :create, :project_id => project.id,
1745 :issue => {:tracker_id => 3,
1745 :issue => {:tracker_id => 3,
1746 :status_id => 1,
1746 :status_id => 1,
1747 :subject => 'This is the test_new_with_group_assignment issue',
1747 :subject => 'This is the test_new_with_group_assignment issue',
1748 :assigned_to_id => group.id}
1748 :assigned_to_id => group.id}
1749 end
1749 end
1750 end
1750 end
1751 assert_redirected_to :controller => 'issues', :action => 'show', :id => Issue.last.id
1751 assert_redirected_to :controller => 'issues', :action => 'show', :id => Issue.last.id
1752
1752
1753 issue = Issue.find_by_subject('This is the test_new_with_group_assignment issue')
1753 issue = Issue.find_by_subject('This is the test_new_with_group_assignment issue')
1754 assert_not_nil issue
1754 assert_not_nil issue
1755 assert_equal group, issue.assigned_to
1755 assert_equal group, issue.assigned_to
1756 end
1756 end
1757
1757
1758 def test_post_create_without_start_date_and_default_start_date_is_not_creation_date
1758 def test_post_create_without_start_date_and_default_start_date_is_not_creation_date
1759 Setting.default_issue_start_date_to_creation_date = 0
1759 Setting.default_issue_start_date_to_creation_date = 0
1760
1760
1761 @request.session[:user_id] = 2
1761 @request.session[:user_id] = 2
1762 assert_difference 'Issue.count' do
1762 assert_difference 'Issue.count' do
1763 post :create, :project_id => 1,
1763 post :create, :project_id => 1,
1764 :issue => {:tracker_id => 3,
1764 :issue => {:tracker_id => 3,
1765 :status_id => 2,
1765 :status_id => 2,
1766 :subject => 'This is the test_new issue',
1766 :subject => 'This is the test_new issue',
1767 :description => 'This is the description',
1767 :description => 'This is the description',
1768 :priority_id => 5,
1768 :priority_id => 5,
1769 :estimated_hours => '',
1769 :estimated_hours => '',
1770 :custom_field_values => {'2' => 'Value for field 2'}}
1770 :custom_field_values => {'2' => 'Value for field 2'}}
1771 end
1771 end
1772 assert_redirected_to :controller => 'issues', :action => 'show', :id => Issue.last.id
1772 assert_redirected_to :controller => 'issues', :action => 'show', :id => Issue.last.id
1773
1773
1774 issue = Issue.find_by_subject('This is the test_new issue')
1774 issue = Issue.find_by_subject('This is the test_new issue')
1775 assert_not_nil issue
1775 assert_not_nil issue
1776 assert_nil issue.start_date
1776 assert_nil issue.start_date
1777 end
1777 end
1778
1778
1779 def test_post_create_without_start_date_and_default_start_date_is_creation_date
1779 def test_post_create_without_start_date_and_default_start_date_is_creation_date
1780 Setting.default_issue_start_date_to_creation_date = 1
1780 Setting.default_issue_start_date_to_creation_date = 1
1781
1781
1782 @request.session[:user_id] = 2
1782 @request.session[:user_id] = 2
1783 assert_difference 'Issue.count' do
1783 assert_difference 'Issue.count' do
1784 post :create, :project_id => 1,
1784 post :create, :project_id => 1,
1785 :issue => {:tracker_id => 3,
1785 :issue => {:tracker_id => 3,
1786 :status_id => 2,
1786 :status_id => 2,
1787 :subject => 'This is the test_new issue',
1787 :subject => 'This is the test_new issue',
1788 :description => 'This is the description',
1788 :description => 'This is the description',
1789 :priority_id => 5,
1789 :priority_id => 5,
1790 :estimated_hours => '',
1790 :estimated_hours => '',
1791 :custom_field_values => {'2' => 'Value for field 2'}}
1791 :custom_field_values => {'2' => 'Value for field 2'}}
1792 end
1792 end
1793 assert_redirected_to :controller => 'issues', :action => 'show', :id => Issue.last.id
1793 assert_redirected_to :controller => 'issues', :action => 'show', :id => Issue.last.id
1794
1794
1795 issue = Issue.find_by_subject('This is the test_new issue')
1795 issue = Issue.find_by_subject('This is the test_new issue')
1796 assert_not_nil issue
1796 assert_not_nil issue
1797 assert_equal Date.today, issue.start_date
1797 assert_equal Date.today, issue.start_date
1798 end
1798 end
1799
1799
1800 def test_post_create_and_continue
1800 def test_post_create_and_continue
1801 @request.session[:user_id] = 2
1801 @request.session[:user_id] = 2
1802 assert_difference 'Issue.count' do
1802 assert_difference 'Issue.count' do
1803 post :create, :project_id => 1,
1803 post :create, :project_id => 1,
1804 :issue => {:tracker_id => 3, :subject => 'This is first issue', :priority_id => 5},
1804 :issue => {:tracker_id => 3, :subject => 'This is first issue', :priority_id => 5},
1805 :continue => ''
1805 :continue => ''
1806 end
1806 end
1807
1807
1808 issue = Issue.first(:order => 'id DESC')
1808 issue = Issue.first(:order => 'id DESC')
1809 assert_redirected_to :controller => 'issues', :action => 'new', :project_id => 'ecookbook', :issue => {:tracker_id => 3}
1809 assert_redirected_to :controller => 'issues', :action => 'new', :project_id => 'ecookbook', :issue => {:tracker_id => 3}
1810 assert_not_nil flash[:notice], "flash was not set"
1810 assert_not_nil flash[:notice], "flash was not set"
1811 assert_include %|<a href="/issues/#{issue.id}" title="This is first issue">##{issue.id}</a>|, flash[:notice], "issue link not found in the flash message"
1811 assert_include %|<a href="/issues/#{issue.id}" title="This is first issue">##{issue.id}</a>|, flash[:notice], "issue link not found in the flash message"
1812 end
1812 end
1813
1813
1814 def test_post_create_without_custom_fields_param
1814 def test_post_create_without_custom_fields_param
1815 @request.session[:user_id] = 2
1815 @request.session[:user_id] = 2
1816 assert_difference 'Issue.count' do
1816 assert_difference 'Issue.count' do
1817 post :create, :project_id => 1,
1817 post :create, :project_id => 1,
1818 :issue => {:tracker_id => 1,
1818 :issue => {:tracker_id => 1,
1819 :subject => 'This is the test_new issue',
1819 :subject => 'This is the test_new issue',
1820 :description => 'This is the description',
1820 :description => 'This is the description',
1821 :priority_id => 5}
1821 :priority_id => 5}
1822 end
1822 end
1823 assert_redirected_to :controller => 'issues', :action => 'show', :id => Issue.last.id
1823 assert_redirected_to :controller => 'issues', :action => 'show', :id => Issue.last.id
1824 end
1824 end
1825
1825
1826 def test_post_create_with_multi_custom_field
1826 def test_post_create_with_multi_custom_field
1827 field = IssueCustomField.find_by_name('Database')
1827 field = IssueCustomField.find_by_name('Database')
1828 field.update_attribute(:multiple, true)
1828 field.update_attribute(:multiple, true)
1829
1829
1830 @request.session[:user_id] = 2
1830 @request.session[:user_id] = 2
1831 assert_difference 'Issue.count' do
1831 assert_difference 'Issue.count' do
1832 post :create, :project_id => 1,
1832 post :create, :project_id => 1,
1833 :issue => {:tracker_id => 1,
1833 :issue => {:tracker_id => 1,
1834 :subject => 'This is the test_new issue',
1834 :subject => 'This is the test_new issue',
1835 :description => 'This is the description',
1835 :description => 'This is the description',
1836 :priority_id => 5,
1836 :priority_id => 5,
1837 :custom_field_values => {'1' => ['', 'MySQL', 'Oracle']}}
1837 :custom_field_values => {'1' => ['', 'MySQL', 'Oracle']}}
1838 end
1838 end
1839 assert_response 302
1839 assert_response 302
1840 issue = Issue.first(:order => 'id DESC')
1840 issue = Issue.first(:order => 'id DESC')
1841 assert_equal ['MySQL', 'Oracle'], issue.custom_field_value(1).sort
1841 assert_equal ['MySQL', 'Oracle'], issue.custom_field_value(1).sort
1842 end
1842 end
1843
1843
1844 def test_post_create_with_empty_multi_custom_field
1844 def test_post_create_with_empty_multi_custom_field
1845 field = IssueCustomField.find_by_name('Database')
1845 field = IssueCustomField.find_by_name('Database')
1846 field.update_attribute(:multiple, true)
1846 field.update_attribute(:multiple, true)
1847
1847
1848 @request.session[:user_id] = 2
1848 @request.session[:user_id] = 2
1849 assert_difference 'Issue.count' do
1849 assert_difference 'Issue.count' do
1850 post :create, :project_id => 1,
1850 post :create, :project_id => 1,
1851 :issue => {:tracker_id => 1,
1851 :issue => {:tracker_id => 1,
1852 :subject => 'This is the test_new issue',
1852 :subject => 'This is the test_new issue',
1853 :description => 'This is the description',
1853 :description => 'This is the description',
1854 :priority_id => 5,
1854 :priority_id => 5,
1855 :custom_field_values => {'1' => ['']}}
1855 :custom_field_values => {'1' => ['']}}
1856 end
1856 end
1857 assert_response 302
1857 assert_response 302
1858 issue = Issue.first(:order => 'id DESC')
1858 issue = Issue.first(:order => 'id DESC')
1859 assert_equal [''], issue.custom_field_value(1).sort
1859 assert_equal [''], issue.custom_field_value(1).sort
1860 end
1860 end
1861
1861
1862 def test_post_create_with_multi_user_custom_field
1862 def test_post_create_with_multi_user_custom_field
1863 field = IssueCustomField.create!(:name => 'Multi user', :field_format => 'user', :multiple => true,
1863 field = IssueCustomField.create!(:name => 'Multi user', :field_format => 'user', :multiple => true,
1864 :tracker_ids => [1], :is_for_all => true)
1864 :tracker_ids => [1], :is_for_all => true)
1865
1865
1866 @request.session[:user_id] = 2
1866 @request.session[:user_id] = 2
1867 assert_difference 'Issue.count' do
1867 assert_difference 'Issue.count' do
1868 post :create, :project_id => 1,
1868 post :create, :project_id => 1,
1869 :issue => {:tracker_id => 1,
1869 :issue => {:tracker_id => 1,
1870 :subject => 'This is the test_new issue',
1870 :subject => 'This is the test_new issue',
1871 :description => 'This is the description',
1871 :description => 'This is the description',
1872 :priority_id => 5,
1872 :priority_id => 5,
1873 :custom_field_values => {field.id.to_s => ['', '2', '3']}}
1873 :custom_field_values => {field.id.to_s => ['', '2', '3']}}
1874 end
1874 end
1875 assert_response 302
1875 assert_response 302
1876 issue = Issue.first(:order => 'id DESC')
1876 issue = Issue.first(:order => 'id DESC')
1877 assert_equal ['2', '3'], issue.custom_field_value(field).sort
1877 assert_equal ['2', '3'], issue.custom_field_value(field).sort
1878 end
1878 end
1879
1879
1880 def test_post_create_with_required_custom_field_and_without_custom_fields_param
1880 def test_post_create_with_required_custom_field_and_without_custom_fields_param
1881 field = IssueCustomField.find_by_name('Database')
1881 field = IssueCustomField.find_by_name('Database')
1882 field.update_attribute(:is_required, true)
1882 field.update_attribute(:is_required, true)
1883
1883
1884 @request.session[:user_id] = 2
1884 @request.session[:user_id] = 2
1885 assert_no_difference 'Issue.count' do
1885 assert_no_difference 'Issue.count' do
1886 post :create, :project_id => 1,
1886 post :create, :project_id => 1,
1887 :issue => {:tracker_id => 1,
1887 :issue => {:tracker_id => 1,
1888 :subject => 'This is the test_new issue',
1888 :subject => 'This is the test_new issue',
1889 :description => 'This is the description',
1889 :description => 'This is the description',
1890 :priority_id => 5}
1890 :priority_id => 5}
1891 end
1891 end
1892 assert_response :success
1892 assert_response :success
1893 assert_template 'new'
1893 assert_template 'new'
1894 issue = assigns(:issue)
1894 issue = assigns(:issue)
1895 assert_not_nil issue
1895 assert_not_nil issue
1896 assert_error_tag :content => /Database can&#x27;t be blank/
1896 assert_error_tag :content => /Database can&#x27;t be blank/
1897 end
1897 end
1898
1898
1899 def test_create_should_validate_required_fields
1899 def test_create_should_validate_required_fields
1900 cf1 = IssueCustomField.create!(:name => 'Foo', :field_format => 'string', :is_for_all => true, :tracker_ids => [1, 2])
1900 cf1 = IssueCustomField.create!(:name => 'Foo', :field_format => 'string', :is_for_all => true, :tracker_ids => [1, 2])
1901 cf2 = IssueCustomField.create!(:name => 'Bar', :field_format => 'string', :is_for_all => true, :tracker_ids => [1, 2])
1901 cf2 = IssueCustomField.create!(:name => 'Bar', :field_format => 'string', :is_for_all => true, :tracker_ids => [1, 2])
1902 WorkflowPermission.delete_all
1902 WorkflowPermission.delete_all
1903 WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 2, :role_id => 1, :field_name => 'due_date', :rule => 'required')
1903 WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 2, :role_id => 1, :field_name => 'due_date', :rule => 'required')
1904 WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 2, :role_id => 1, :field_name => cf2.id.to_s, :rule => 'required')
1904 WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 2, :role_id => 1, :field_name => cf2.id.to_s, :rule => 'required')
1905 @request.session[:user_id] = 2
1905 @request.session[:user_id] = 2
1906
1906
1907 assert_no_difference 'Issue.count' do
1907 assert_no_difference 'Issue.count' do
1908 post :create, :project_id => 1, :issue => {
1908 post :create, :project_id => 1, :issue => {
1909 :tracker_id => 2,
1909 :tracker_id => 2,
1910 :status_id => 1,
1910 :status_id => 1,
1911 :subject => 'Test',
1911 :subject => 'Test',
1912 :start_date => '',
1912 :start_date => '',
1913 :due_date => '',
1913 :due_date => '',
1914 :custom_field_values => {cf1.id.to_s => '', cf2.id.to_s => ''}
1914 :custom_field_values => {cf1.id.to_s => '', cf2.id.to_s => ''}
1915 }
1915 }
1916 assert_response :success
1916 assert_response :success
1917 assert_template 'new'
1917 assert_template 'new'
1918 end
1918 end
1919
1919
1920 assert_error_tag :content => /Due date can&#x27;t be blank/i
1920 assert_error_tag :content => /Due date can&#x27;t be blank/i
1921 assert_error_tag :content => /Bar can&#x27;t be blank/i
1921 assert_error_tag :content => /Bar can&#x27;t be blank/i
1922 end
1922 end
1923
1923
1924 def test_create_should_ignore_readonly_fields
1924 def test_create_should_ignore_readonly_fields
1925 cf1 = IssueCustomField.create!(:name => 'Foo', :field_format => 'string', :is_for_all => true, :tracker_ids => [1, 2])
1925 cf1 = IssueCustomField.create!(:name => 'Foo', :field_format => 'string', :is_for_all => true, :tracker_ids => [1, 2])
1926 cf2 = IssueCustomField.create!(:name => 'Bar', :field_format => 'string', :is_for_all => true, :tracker_ids => [1, 2])
1926 cf2 = IssueCustomField.create!(:name => 'Bar', :field_format => 'string', :is_for_all => true, :tracker_ids => [1, 2])
1927 WorkflowPermission.delete_all
1927 WorkflowPermission.delete_all
1928 WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 2, :role_id => 1, :field_name => 'due_date', :rule => 'readonly')
1928 WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 2, :role_id => 1, :field_name => 'due_date', :rule => 'readonly')
1929 WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 2, :role_id => 1, :field_name => cf2.id.to_s, :rule => 'readonly')
1929 WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 2, :role_id => 1, :field_name => cf2.id.to_s, :rule => 'readonly')
1930 @request.session[:user_id] = 2
1930 @request.session[:user_id] = 2
1931
1931
1932 assert_difference 'Issue.count' do
1932 assert_difference 'Issue.count' do
1933 post :create, :project_id => 1, :issue => {
1933 post :create, :project_id => 1, :issue => {
1934 :tracker_id => 2,
1934 :tracker_id => 2,
1935 :status_id => 1,
1935 :status_id => 1,
1936 :subject => 'Test',
1936 :subject => 'Test',
1937 :start_date => '2012-07-14',
1937 :start_date => '2012-07-14',
1938 :due_date => '2012-07-16',
1938 :due_date => '2012-07-16',
1939 :custom_field_values => {cf1.id.to_s => 'value1', cf2.id.to_s => 'value2'}
1939 :custom_field_values => {cf1.id.to_s => 'value1', cf2.id.to_s => 'value2'}
1940 }
1940 }
1941 assert_response 302
1941 assert_response 302
1942 end
1942 end
1943
1943
1944 issue = Issue.first(:order => 'id DESC')
1944 issue = Issue.first(:order => 'id DESC')
1945 assert_equal Date.parse('2012-07-14'), issue.start_date
1945 assert_equal Date.parse('2012-07-14'), issue.start_date
1946 assert_nil issue.due_date
1946 assert_nil issue.due_date
1947 assert_equal 'value1', issue.custom_field_value(cf1)
1947 assert_equal 'value1', issue.custom_field_value(cf1)
1948 assert_nil issue.custom_field_value(cf2)
1948 assert_nil issue.custom_field_value(cf2)
1949 end
1949 end
1950
1950
1951 def test_post_create_with_watchers
1951 def test_post_create_with_watchers
1952 @request.session[:user_id] = 2
1952 @request.session[:user_id] = 2
1953 ActionMailer::Base.deliveries.clear
1953 ActionMailer::Base.deliveries.clear
1954
1954
1955 assert_difference 'Watcher.count', 2 do
1955 assert_difference 'Watcher.count', 2 do
1956 post :create, :project_id => 1,
1956 post :create, :project_id => 1,
1957 :issue => {:tracker_id => 1,
1957 :issue => {:tracker_id => 1,
1958 :subject => 'This is a new issue with watchers',
1958 :subject => 'This is a new issue with watchers',
1959 :description => 'This is the description',
1959 :description => 'This is the description',
1960 :priority_id => 5,
1960 :priority_id => 5,
1961 :watcher_user_ids => ['2', '3']}
1961 :watcher_user_ids => ['2', '3']}
1962 end
1962 end
1963 issue = Issue.find_by_subject('This is a new issue with watchers')
1963 issue = Issue.find_by_subject('This is a new issue with watchers')
1964 assert_not_nil issue
1964 assert_not_nil issue
1965 assert_redirected_to :controller => 'issues', :action => 'show', :id => issue
1965 assert_redirected_to :controller => 'issues', :action => 'show', :id => issue
1966
1966
1967 # Watchers added
1967 # Watchers added
1968 assert_equal [2, 3], issue.watcher_user_ids.sort
1968 assert_equal [2, 3], issue.watcher_user_ids.sort
1969 assert issue.watched_by?(User.find(3))
1969 assert issue.watched_by?(User.find(3))
1970 # Watchers notified
1970 # Watchers notified
1971 mail = ActionMailer::Base.deliveries.last
1971 mail = ActionMailer::Base.deliveries.last
1972 assert_not_nil mail
1972 assert_not_nil mail
1973 assert [mail.bcc, mail.cc].flatten.include?(User.find(3).mail)
1973 assert [mail.bcc, mail.cc].flatten.include?(User.find(3).mail)
1974 end
1974 end
1975
1975
1976 def test_post_create_subissue
1976 def test_post_create_subissue
1977 @request.session[:user_id] = 2
1977 @request.session[:user_id] = 2
1978
1978
1979 assert_difference 'Issue.count' do
1979 assert_difference 'Issue.count' do
1980 post :create, :project_id => 1,
1980 post :create, :project_id => 1,
1981 :issue => {:tracker_id => 1,
1981 :issue => {:tracker_id => 1,
1982 :subject => 'This is a child issue',
1982 :subject => 'This is a child issue',
1983 :parent_issue_id => '2'}
1983 :parent_issue_id => '2'}
1984 assert_response 302
1984 assert_response 302
1985 end
1985 end
1986 issue = Issue.order('id DESC').first
1986 issue = Issue.order('id DESC').first
1987 assert_equal Issue.find(2), issue.parent
1987 assert_equal Issue.find(2), issue.parent
1988 end
1988 end
1989
1989
1990 def test_post_create_subissue_with_sharp_parent_id
1990 def test_post_create_subissue_with_sharp_parent_id
1991 @request.session[:user_id] = 2
1991 @request.session[:user_id] = 2
1992
1992
1993 assert_difference 'Issue.count' do
1993 assert_difference 'Issue.count' do
1994 post :create, :project_id => 1,
1994 post :create, :project_id => 1,
1995 :issue => {:tracker_id => 1,
1995 :issue => {:tracker_id => 1,
1996 :subject => 'This is a child issue',
1996 :subject => 'This is a child issue',
1997 :parent_issue_id => '#2'}
1997 :parent_issue_id => '#2'}
1998 assert_response 302
1998 assert_response 302
1999 end
1999 end
2000 issue = Issue.order('id DESC').first
2000 issue = Issue.order('id DESC').first
2001 assert_equal Issue.find(2), issue.parent
2001 assert_equal Issue.find(2), issue.parent
2002 end
2002 end
2003
2003
2004 def test_post_create_subissue_with_non_visible_parent_id_should_not_validate
2004 def test_post_create_subissue_with_non_visible_parent_id_should_not_validate
2005 @request.session[:user_id] = 2
2005 @request.session[:user_id] = 2
2006
2006
2007 assert_no_difference 'Issue.count' do
2007 assert_no_difference 'Issue.count' do
2008 post :create, :project_id => 1,
2008 post :create, :project_id => 1,
2009 :issue => {:tracker_id => 1,
2009 :issue => {:tracker_id => 1,
2010 :subject => 'This is a child issue',
2010 :subject => 'This is a child issue',
2011 :parent_issue_id => '4'}
2011 :parent_issue_id => '4'}
2012
2012
2013 assert_response :success
2013 assert_response :success
2014 assert_select 'input[name=?][value=?]', 'issue[parent_issue_id]', '4'
2014 assert_select 'input[name=?][value=?]', 'issue[parent_issue_id]', '4'
2015 assert_error_tag :content => /Parent task is invalid/i
2015 assert_error_tag :content => /Parent task is invalid/i
2016 end
2016 end
2017 end
2017 end
2018
2018
2019 def test_post_create_subissue_with_non_numeric_parent_id_should_not_validate
2019 def test_post_create_subissue_with_non_numeric_parent_id_should_not_validate
2020 @request.session[:user_id] = 2
2020 @request.session[:user_id] = 2
2021
2021
2022 assert_no_difference 'Issue.count' do
2022 assert_no_difference 'Issue.count' do
2023 post :create, :project_id => 1,
2023 post :create, :project_id => 1,
2024 :issue => {:tracker_id => 1,
2024 :issue => {:tracker_id => 1,
2025 :subject => 'This is a child issue',
2025 :subject => 'This is a child issue',
2026 :parent_issue_id => '01ABC'}
2026 :parent_issue_id => '01ABC'}
2027
2027
2028 assert_response :success
2028 assert_response :success
2029 assert_select 'input[name=?][value=?]', 'issue[parent_issue_id]', '01ABC'
2029 assert_select 'input[name=?][value=?]', 'issue[parent_issue_id]', '01ABC'
2030 assert_error_tag :content => /Parent task is invalid/i
2030 assert_error_tag :content => /Parent task is invalid/i
2031 end
2031 end
2032 end
2032 end
2033
2033
2034 def test_post_create_private
2034 def test_post_create_private
2035 @request.session[:user_id] = 2
2035 @request.session[:user_id] = 2
2036
2036
2037 assert_difference 'Issue.count' do
2037 assert_difference 'Issue.count' do
2038 post :create, :project_id => 1,
2038 post :create, :project_id => 1,
2039 :issue => {:tracker_id => 1,
2039 :issue => {:tracker_id => 1,
2040 :subject => 'This is a private issue',
2040 :subject => 'This is a private issue',
2041 :is_private => '1'}
2041 :is_private => '1'}
2042 end
2042 end
2043 issue = Issue.first(:order => 'id DESC')
2043 issue = Issue.first(:order => 'id DESC')
2044 assert issue.is_private?
2044 assert issue.is_private?
2045 end
2045 end
2046
2046
2047 def test_post_create_private_with_set_own_issues_private_permission
2047 def test_post_create_private_with_set_own_issues_private_permission
2048 role = Role.find(1)
2048 role = Role.find(1)
2049 role.remove_permission! :set_issues_private
2049 role.remove_permission! :set_issues_private
2050 role.add_permission! :set_own_issues_private
2050 role.add_permission! :set_own_issues_private
2051
2051
2052 @request.session[:user_id] = 2
2052 @request.session[:user_id] = 2
2053
2053
2054 assert_difference 'Issue.count' do
2054 assert_difference 'Issue.count' do
2055 post :create, :project_id => 1,
2055 post :create, :project_id => 1,
2056 :issue => {:tracker_id => 1,
2056 :issue => {:tracker_id => 1,
2057 :subject => 'This is a private issue',
2057 :subject => 'This is a private issue',
2058 :is_private => '1'}
2058 :is_private => '1'}
2059 end
2059 end
2060 issue = Issue.first(:order => 'id DESC')
2060 issue = Issue.first(:order => 'id DESC')
2061 assert issue.is_private?
2061 assert issue.is_private?
2062 end
2062 end
2063
2063
2064 def test_post_create_should_send_a_notification
2064 def test_post_create_should_send_a_notification
2065 ActionMailer::Base.deliveries.clear
2065 ActionMailer::Base.deliveries.clear
2066 @request.session[:user_id] = 2
2066 @request.session[:user_id] = 2
2067 assert_difference 'Issue.count' do
2067 assert_difference 'Issue.count' do
2068 post :create, :project_id => 1,
2068 post :create, :project_id => 1,
2069 :issue => {:tracker_id => 3,
2069 :issue => {:tracker_id => 3,
2070 :subject => 'This is the test_new issue',
2070 :subject => 'This is the test_new issue',
2071 :description => 'This is the description',
2071 :description => 'This is the description',
2072 :priority_id => 5,
2072 :priority_id => 5,
2073 :estimated_hours => '',
2073 :estimated_hours => '',
2074 :custom_field_values => {'2' => 'Value for field 2'}}
2074 :custom_field_values => {'2' => 'Value for field 2'}}
2075 end
2075 end
2076 assert_redirected_to :controller => 'issues', :action => 'show', :id => Issue.last.id
2076 assert_redirected_to :controller => 'issues', :action => 'show', :id => Issue.last.id
2077
2077
2078 assert_equal 1, ActionMailer::Base.deliveries.size
2078 assert_equal 1, ActionMailer::Base.deliveries.size
2079 end
2079 end
2080
2080
2081 def test_post_create_should_preserve_fields_values_on_validation_failure
2081 def test_post_create_should_preserve_fields_values_on_validation_failure
2082 @request.session[:user_id] = 2
2082 @request.session[:user_id] = 2
2083 post :create, :project_id => 1,
2083 post :create, :project_id => 1,
2084 :issue => {:tracker_id => 1,
2084 :issue => {:tracker_id => 1,
2085 # empty subject
2085 # empty subject
2086 :subject => '',
2086 :subject => '',
2087 :description => 'This is a description',
2087 :description => 'This is a description',
2088 :priority_id => 6,
2088 :priority_id => 6,
2089 :custom_field_values => {'1' => 'Oracle', '2' => 'Value for field 2'}}
2089 :custom_field_values => {'1' => 'Oracle', '2' => 'Value for field 2'}}
2090 assert_response :success
2090 assert_response :success
2091 assert_template 'new'
2091 assert_template 'new'
2092
2092
2093 assert_select 'textarea[name=?]', 'issue[description]', :text => 'This is a description'
2093 assert_select 'textarea[name=?]', 'issue[description]', :text => 'This is a description'
2094 assert_select 'select[name=?]', 'issue[priority_id]' do
2094 assert_select 'select[name=?]', 'issue[priority_id]' do
2095 assert_select 'option[value=6][selected=selected]', :text => 'High'
2095 assert_select 'option[value=6][selected=selected]', :text => 'High'
2096 end
2096 end
2097 # Custom fields
2097 # Custom fields
2098 assert_select 'select[name=?]', 'issue[custom_field_values][1]' do
2098 assert_select 'select[name=?]', 'issue[custom_field_values][1]' do
2099 assert_select 'option[value=Oracle][selected=selected]', :text => 'Oracle'
2099 assert_select 'option[value=Oracle][selected=selected]', :text => 'Oracle'
2100 end
2100 end
2101 assert_select 'input[name=?][value=?]', 'issue[custom_field_values][2]', 'Value for field 2'
2101 assert_select 'input[name=?][value=?]', 'issue[custom_field_values][2]', 'Value for field 2'
2102 end
2102 end
2103
2103
2104 def test_post_create_with_failure_should_preserve_watchers
2104 def test_post_create_with_failure_should_preserve_watchers
2105 assert !User.find(8).member_of?(Project.find(1))
2105 assert !User.find(8).member_of?(Project.find(1))
2106
2106
2107 @request.session[:user_id] = 2
2107 @request.session[:user_id] = 2
2108 post :create, :project_id => 1,
2108 post :create, :project_id => 1,
2109 :issue => {:tracker_id => 1,
2109 :issue => {:tracker_id => 1,
2110 :watcher_user_ids => ['3', '8']}
2110 :watcher_user_ids => ['3', '8']}
2111 assert_response :success
2111 assert_response :success
2112 assert_template 'new'
2112 assert_template 'new'
2113
2113
2114 assert_select 'input[name=?][value=2]:not(checked)', 'issue[watcher_user_ids][]'
2114 assert_select 'input[name=?][value=2]:not(checked)', 'issue[watcher_user_ids][]'
2115 assert_select 'input[name=?][value=3][checked=checked]', 'issue[watcher_user_ids][]'
2115 assert_select 'input[name=?][value=3][checked=checked]', 'issue[watcher_user_ids][]'
2116 assert_select 'input[name=?][value=8][checked=checked]', 'issue[watcher_user_ids][]'
2116 assert_select 'input[name=?][value=8][checked=checked]', 'issue[watcher_user_ids][]'
2117 end
2117 end
2118
2118
2119 def test_post_create_should_ignore_non_safe_attributes
2119 def test_post_create_should_ignore_non_safe_attributes
2120 @request.session[:user_id] = 2
2120 @request.session[:user_id] = 2
2121 assert_nothing_raised do
2121 assert_nothing_raised do
2122 post :create, :project_id => 1, :issue => { :tracker => "A param can not be a Tracker" }
2122 post :create, :project_id => 1, :issue => { :tracker => "A param can not be a Tracker" }
2123 end
2123 end
2124 end
2124 end
2125
2125
2126 def test_post_create_with_attachment
2126 def test_post_create_with_attachment
2127 set_tmp_attachments_directory
2127 set_tmp_attachments_directory
2128 @request.session[:user_id] = 2
2128 @request.session[:user_id] = 2
2129
2129
2130 assert_difference 'Issue.count' do
2130 assert_difference 'Issue.count' do
2131 assert_difference 'Attachment.count' do
2131 assert_difference 'Attachment.count' do
2132 post :create, :project_id => 1,
2132 post :create, :project_id => 1,
2133 :issue => { :tracker_id => '1', :subject => 'With attachment' },
2133 :issue => { :tracker_id => '1', :subject => 'With attachment' },
2134 :attachments => {'1' => {'file' => uploaded_test_file('testfile.txt', 'text/plain'), 'description' => 'test file'}}
2134 :attachments => {'1' => {'file' => uploaded_test_file('testfile.txt', 'text/plain'), 'description' => 'test file'}}
2135 end
2135 end
2136 end
2136 end
2137
2137
2138 issue = Issue.first(:order => 'id DESC')
2138 issue = Issue.first(:order => 'id DESC')
2139 attachment = Attachment.first(:order => 'id DESC')
2139 attachment = Attachment.first(:order => 'id DESC')
2140
2140
2141 assert_equal issue, attachment.container
2141 assert_equal issue, attachment.container
2142 assert_equal 2, attachment.author_id
2142 assert_equal 2, attachment.author_id
2143 assert_equal 'testfile.txt', attachment.filename
2143 assert_equal 'testfile.txt', attachment.filename
2144 assert_equal 'text/plain', attachment.content_type
2144 assert_equal 'text/plain', attachment.content_type
2145 assert_equal 'test file', attachment.description
2145 assert_equal 'test file', attachment.description
2146 assert_equal 59, attachment.filesize
2146 assert_equal 59, attachment.filesize
2147 assert File.exists?(attachment.diskfile)
2147 assert File.exists?(attachment.diskfile)
2148 assert_equal 59, File.size(attachment.diskfile)
2148 assert_equal 59, File.size(attachment.diskfile)
2149 end
2149 end
2150
2150
2151 def test_post_create_with_failure_should_save_attachments
2151 def test_post_create_with_failure_should_save_attachments
2152 set_tmp_attachments_directory
2152 set_tmp_attachments_directory
2153 @request.session[:user_id] = 2
2153 @request.session[:user_id] = 2
2154
2154
2155 assert_no_difference 'Issue.count' do
2155 assert_no_difference 'Issue.count' do
2156 assert_difference 'Attachment.count' do
2156 assert_difference 'Attachment.count' do
2157 post :create, :project_id => 1,
2157 post :create, :project_id => 1,
2158 :issue => { :tracker_id => '1', :subject => '' },
2158 :issue => { :tracker_id => '1', :subject => '' },
2159 :attachments => {'1' => {'file' => uploaded_test_file('testfile.txt', 'text/plain'), 'description' => 'test file'}}
2159 :attachments => {'1' => {'file' => uploaded_test_file('testfile.txt', 'text/plain'), 'description' => 'test file'}}
2160 assert_response :success
2160 assert_response :success
2161 assert_template 'new'
2161 assert_template 'new'
2162 end
2162 end
2163 end
2163 end
2164
2164
2165 attachment = Attachment.first(:order => 'id DESC')
2165 attachment = Attachment.first(:order => 'id DESC')
2166 assert_equal 'testfile.txt', attachment.filename
2166 assert_equal 'testfile.txt', attachment.filename
2167 assert File.exists?(attachment.diskfile)
2167 assert File.exists?(attachment.diskfile)
2168 assert_nil attachment.container
2168 assert_nil attachment.container
2169
2169
2170 assert_select 'input[name=?][value=?]', 'attachments[p0][token]', attachment.token
2170 assert_select 'input[name=?][value=?]', 'attachments[p0][token]', attachment.token
2171 assert_select 'input[name=?][value=?]', 'attachments[p0][filename]', 'testfile.txt'
2171 assert_select 'input[name=?][value=?]', 'attachments[p0][filename]', 'testfile.txt'
2172 end
2172 end
2173
2173
2174 def test_post_create_with_failure_should_keep_saved_attachments
2174 def test_post_create_with_failure_should_keep_saved_attachments
2175 set_tmp_attachments_directory
2175 set_tmp_attachments_directory
2176 attachment = Attachment.create!(:file => uploaded_test_file("testfile.txt", "text/plain"), :author_id => 2)
2176 attachment = Attachment.create!(:file => uploaded_test_file("testfile.txt", "text/plain"), :author_id => 2)
2177 @request.session[:user_id] = 2
2177 @request.session[:user_id] = 2
2178
2178
2179 assert_no_difference 'Issue.count' do
2179 assert_no_difference 'Issue.count' do
2180 assert_no_difference 'Attachment.count' do
2180 assert_no_difference 'Attachment.count' do
2181 post :create, :project_id => 1,
2181 post :create, :project_id => 1,
2182 :issue => { :tracker_id => '1', :subject => '' },
2182 :issue => { :tracker_id => '1', :subject => '' },
2183 :attachments => {'p0' => {'token' => attachment.token}}
2183 :attachments => {'p0' => {'token' => attachment.token}}
2184 assert_response :success
2184 assert_response :success
2185 assert_template 'new'
2185 assert_template 'new'
2186 end
2186 end
2187 end
2187 end
2188
2188
2189 assert_select 'input[name=?][value=?]', 'attachments[p0][token]', attachment.token
2189 assert_select 'input[name=?][value=?]', 'attachments[p0][token]', attachment.token
2190 assert_select 'input[name=?][value=?]', 'attachments[p0][filename]', 'testfile.txt'
2190 assert_select 'input[name=?][value=?]', 'attachments[p0][filename]', 'testfile.txt'
2191 end
2191 end
2192
2192
2193 def test_post_create_should_attach_saved_attachments
2193 def test_post_create_should_attach_saved_attachments
2194 set_tmp_attachments_directory
2194 set_tmp_attachments_directory
2195 attachment = Attachment.create!(:file => uploaded_test_file("testfile.txt", "text/plain"), :author_id => 2)
2195 attachment = Attachment.create!(:file => uploaded_test_file("testfile.txt", "text/plain"), :author_id => 2)
2196 @request.session[:user_id] = 2
2196 @request.session[:user_id] = 2
2197
2197
2198 assert_difference 'Issue.count' do
2198 assert_difference 'Issue.count' do
2199 assert_no_difference 'Attachment.count' do
2199 assert_no_difference 'Attachment.count' do
2200 post :create, :project_id => 1,
2200 post :create, :project_id => 1,
2201 :issue => { :tracker_id => '1', :subject => 'Saved attachments' },
2201 :issue => { :tracker_id => '1', :subject => 'Saved attachments' },
2202 :attachments => {'p0' => {'token' => attachment.token}}
2202 :attachments => {'p0' => {'token' => attachment.token}}
2203 assert_response 302
2203 assert_response 302
2204 end
2204 end
2205 end
2205 end
2206
2206
2207 issue = Issue.first(:order => 'id DESC')
2207 issue = Issue.first(:order => 'id DESC')
2208 assert_equal 1, issue.attachments.count
2208 assert_equal 1, issue.attachments.count
2209
2209
2210 attachment.reload
2210 attachment.reload
2211 assert_equal issue, attachment.container
2211 assert_equal issue, attachment.container
2212 end
2212 end
2213
2213
2214 context "without workflow privilege" do
2214 context "without workflow privilege" do
2215 setup do
2215 setup do
2216 WorkflowTransition.delete_all(["role_id = ?", Role.anonymous.id])
2216 WorkflowTransition.delete_all(["role_id = ?", Role.anonymous.id])
2217 Role.anonymous.add_permission! :add_issues, :add_issue_notes
2217 Role.anonymous.add_permission! :add_issues, :add_issue_notes
2218 end
2218 end
2219
2219
2220 context "#new" do
2220 context "#new" do
2221 should "propose default status only" do
2221 should "propose default status only" do
2222 get :new, :project_id => 1
2222 get :new, :project_id => 1
2223 assert_response :success
2223 assert_response :success
2224 assert_template 'new'
2224 assert_template 'new'
2225 assert_select 'select[name=?]', 'issue[status_id]' do
2225 assert_select 'select[name=?]', 'issue[status_id]' do
2226 assert_select 'option', 1
2226 assert_select 'option', 1
2227 assert_select 'option[value=?]', IssueStatus.default.id.to_s
2227 assert_select 'option[value=?]', IssueStatus.default.id.to_s
2228 end
2228 end
2229 end
2229 end
2230
2230
2231 should "accept default status" do
2231 should "accept default status" do
2232 assert_difference 'Issue.count' do
2232 assert_difference 'Issue.count' do
2233 post :create, :project_id => 1,
2233 post :create, :project_id => 1,
2234 :issue => {:tracker_id => 1,
2234 :issue => {:tracker_id => 1,
2235 :subject => 'This is an issue',
2235 :subject => 'This is an issue',
2236 :status_id => 1}
2236 :status_id => 1}
2237 end
2237 end
2238 issue = Issue.last(:order => 'id')
2238 issue = Issue.last(:order => 'id')
2239 assert_equal IssueStatus.default, issue.status
2239 assert_equal IssueStatus.default, issue.status
2240 end
2240 end
2241
2241
2242 should "ignore unauthorized status" do
2242 should "ignore unauthorized status" do
2243 assert_difference 'Issue.count' do
2243 assert_difference 'Issue.count' do
2244 post :create, :project_id => 1,
2244 post :create, :project_id => 1,
2245 :issue => {:tracker_id => 1,
2245 :issue => {:tracker_id => 1,
2246 :subject => 'This is an issue',
2246 :subject => 'This is an issue',
2247 :status_id => 3}
2247 :status_id => 3}
2248 end
2248 end
2249 issue = Issue.last(:order => 'id')
2249 issue = Issue.last(:order => 'id')
2250 assert_equal IssueStatus.default, issue.status
2250 assert_equal IssueStatus.default, issue.status
2251 end
2251 end
2252 end
2252 end
2253
2253
2254 context "#update" do
2254 context "#update" do
2255 should "ignore status change" do
2255 should "ignore status change" do
2256 assert_difference 'Journal.count' do
2256 assert_difference 'Journal.count' do
2257 put :update, :id => 1, :issue => {:status_id => 3, :notes => 'just trying'}
2257 put :update, :id => 1, :issue => {:status_id => 3, :notes => 'just trying'}
2258 end
2258 end
2259 assert_equal 1, Issue.find(1).status_id
2259 assert_equal 1, Issue.find(1).status_id
2260 end
2260 end
2261
2261
2262 should "ignore attributes changes" do
2262 should "ignore attributes changes" do
2263 assert_difference 'Journal.count' do
2263 assert_difference 'Journal.count' do
2264 put :update, :id => 1, :issue => {:subject => 'changed', :assigned_to_id => 2, :notes => 'just trying'}
2264 put :update, :id => 1, :issue => {:subject => 'changed', :assigned_to_id => 2, :notes => 'just trying'}
2265 end
2265 end
2266 issue = Issue.find(1)
2266 issue = Issue.find(1)
2267 assert_equal "Can't print recipes", issue.subject
2267 assert_equal "Can't print recipes", issue.subject
2268 assert_nil issue.assigned_to
2268 assert_nil issue.assigned_to
2269 end
2269 end
2270 end
2270 end
2271 end
2271 end
2272
2272
2273 context "with workflow privilege" do
2273 context "with workflow privilege" do
2274 setup do
2274 setup do
2275 WorkflowTransition.delete_all(["role_id = ?", Role.anonymous.id])
2275 WorkflowTransition.delete_all(["role_id = ?", Role.anonymous.id])
2276 WorkflowTransition.create!(:role => Role.anonymous, :tracker_id => 1, :old_status_id => 1, :new_status_id => 3)
2276 WorkflowTransition.create!(:role => Role.anonymous, :tracker_id => 1, :old_status_id => 1, :new_status_id => 3)
2277 WorkflowTransition.create!(:role => Role.anonymous, :tracker_id => 1, :old_status_id => 1, :new_status_id => 4)
2277 WorkflowTransition.create!(:role => Role.anonymous, :tracker_id => 1, :old_status_id => 1, :new_status_id => 4)
2278 Role.anonymous.add_permission! :add_issues, :add_issue_notes
2278 Role.anonymous.add_permission! :add_issues, :add_issue_notes
2279 end
2279 end
2280
2280
2281 context "#update" do
2281 context "#update" do
2282 should "accept authorized status" do
2282 should "accept authorized status" do
2283 assert_difference 'Journal.count' do
2283 assert_difference 'Journal.count' do
2284 put :update, :id => 1, :issue => {:status_id => 3, :notes => 'just trying'}
2284 put :update, :id => 1, :issue => {:status_id => 3, :notes => 'just trying'}
2285 end
2285 end
2286 assert_equal 3, Issue.find(1).status_id
2286 assert_equal 3, Issue.find(1).status_id
2287 end
2287 end
2288
2288
2289 should "ignore unauthorized status" do
2289 should "ignore unauthorized status" do
2290 assert_difference 'Journal.count' do
2290 assert_difference 'Journal.count' do
2291 put :update, :id => 1, :issue => {:status_id => 2, :notes => 'just trying'}
2291 put :update, :id => 1, :issue => {:status_id => 2, :notes => 'just trying'}
2292 end
2292 end
2293 assert_equal 1, Issue.find(1).status_id
2293 assert_equal 1, Issue.find(1).status_id
2294 end
2294 end
2295
2295
2296 should "accept authorized attributes changes" do
2296 should "accept authorized attributes changes" do
2297 assert_difference 'Journal.count' do
2297 assert_difference 'Journal.count' do
2298 put :update, :id => 1, :issue => {:assigned_to_id => 2, :notes => 'just trying'}
2298 put :update, :id => 1, :issue => {:assigned_to_id => 2, :notes => 'just trying'}
2299 end
2299 end
2300 issue = Issue.find(1)
2300 issue = Issue.find(1)
2301 assert_equal 2, issue.assigned_to_id
2301 assert_equal 2, issue.assigned_to_id
2302 end
2302 end
2303
2303
2304 should "ignore unauthorized attributes changes" do
2304 should "ignore unauthorized attributes changes" do
2305 assert_difference 'Journal.count' do
2305 assert_difference 'Journal.count' do
2306 put :update, :id => 1, :issue => {:subject => 'changed', :notes => 'just trying'}
2306 put :update, :id => 1, :issue => {:subject => 'changed', :notes => 'just trying'}
2307 end
2307 end
2308 issue = Issue.find(1)
2308 issue = Issue.find(1)
2309 assert_equal "Can't print recipes", issue.subject
2309 assert_equal "Can't print recipes", issue.subject
2310 end
2310 end
2311 end
2311 end
2312
2312
2313 context "and :edit_issues permission" do
2313 context "and :edit_issues permission" do
2314 setup do
2314 setup do
2315 Role.anonymous.add_permission! :add_issues, :edit_issues
2315 Role.anonymous.add_permission! :add_issues, :edit_issues
2316 end
2316 end
2317
2317
2318 should "accept authorized status" do
2318 should "accept authorized status" do
2319 assert_difference 'Journal.count' do
2319 assert_difference 'Journal.count' do
2320 put :update, :id => 1, :issue => {:status_id => 3, :notes => 'just trying'}
2320 put :update, :id => 1, :issue => {:status_id => 3, :notes => 'just trying'}
2321 end
2321 end
2322 assert_equal 3, Issue.find(1).status_id
2322 assert_equal 3, Issue.find(1).status_id
2323 end
2323 end
2324
2324
2325 should "ignore unauthorized status" do
2325 should "ignore unauthorized status" do
2326 assert_difference 'Journal.count' do
2326 assert_difference 'Journal.count' do
2327 put :update, :id => 1, :issue => {:status_id => 2, :notes => 'just trying'}
2327 put :update, :id => 1, :issue => {:status_id => 2, :notes => 'just trying'}
2328 end
2328 end
2329 assert_equal 1, Issue.find(1).status_id
2329 assert_equal 1, Issue.find(1).status_id
2330 end
2330 end
2331
2331
2332 should "accept authorized attributes changes" do
2332 should "accept authorized attributes changes" do
2333 assert_difference 'Journal.count' do
2333 assert_difference 'Journal.count' do
2334 put :update, :id => 1, :issue => {:subject => 'changed', :assigned_to_id => 2, :notes => 'just trying'}
2334 put :update, :id => 1, :issue => {:subject => 'changed', :assigned_to_id => 2, :notes => 'just trying'}
2335 end
2335 end
2336 issue = Issue.find(1)
2336 issue = Issue.find(1)
2337 assert_equal "changed", issue.subject
2337 assert_equal "changed", issue.subject
2338 assert_equal 2, issue.assigned_to_id
2338 assert_equal 2, issue.assigned_to_id
2339 end
2339 end
2340 end
2340 end
2341 end
2341 end
2342
2342
2343 def test_new_as_copy
2343 def test_new_as_copy
2344 @request.session[:user_id] = 2
2344 @request.session[:user_id] = 2
2345 get :new, :project_id => 1, :copy_from => 1
2345 get :new, :project_id => 1, :copy_from => 1
2346
2346
2347 assert_response :success
2347 assert_response :success
2348 assert_template 'new'
2348 assert_template 'new'
2349
2349
2350 assert_not_nil assigns(:issue)
2350 assert_not_nil assigns(:issue)
2351 orig = Issue.find(1)
2351 orig = Issue.find(1)
2352 assert_equal 1, assigns(:issue).project_id
2352 assert_equal 1, assigns(:issue).project_id
2353 assert_equal orig.subject, assigns(:issue).subject
2353 assert_equal orig.subject, assigns(:issue).subject
2354 assert assigns(:issue).copy?
2354 assert assigns(:issue).copy?
2355
2355
2356 assert_select 'form[id=issue-form][action=/projects/ecookbook/issues]' do
2356 assert_select 'form[id=issue-form][action=/projects/ecookbook/issues]' do
2357 assert_select 'select[name=?]', 'issue[project_id]' do
2357 assert_select 'select[name=?]', 'issue[project_id]' do
2358 assert_select 'option[value=1][selected=selected]', :text => 'eCookbook'
2358 assert_select 'option[value=1][selected=selected]', :text => 'eCookbook'
2359 assert_select 'option[value=2]:not([selected])', :text => 'OnlineStore'
2359 assert_select 'option[value=2]:not([selected])', :text => 'OnlineStore'
2360 end
2360 end
2361 assert_select 'input[name=copy_from][value=1]'
2361 assert_select 'input[name=copy_from][value=1]'
2362 end
2362 end
2363
2363
2364 # "New issue" menu item should not link to copy
2364 # "New issue" menu item should not link to copy
2365 assert_select '#main-menu a.new-issue[href=/projects/ecookbook/issues/new]'
2365 assert_select '#main-menu a.new-issue[href=/projects/ecookbook/issues/new]'
2366 end
2366 end
2367
2367
2368 def test_new_as_copy_with_attachments_should_show_copy_attachments_checkbox
2368 def test_new_as_copy_with_attachments_should_show_copy_attachments_checkbox
2369 @request.session[:user_id] = 2
2369 @request.session[:user_id] = 2
2370 issue = Issue.find(3)
2370 issue = Issue.find(3)
2371 assert issue.attachments.count > 0
2371 assert issue.attachments.count > 0
2372 get :new, :project_id => 1, :copy_from => 3
2372 get :new, :project_id => 1, :copy_from => 3
2373
2373
2374 assert_select 'input[name=copy_attachments][type=checkbox][checked=checked][value=1]'
2374 assert_select 'input[name=copy_attachments][type=checkbox][checked=checked][value=1]'
2375 end
2375 end
2376
2376
2377 def test_new_as_copy_without_attachments_should_not_show_copy_attachments_checkbox
2377 def test_new_as_copy_without_attachments_should_not_show_copy_attachments_checkbox
2378 @request.session[:user_id] = 2
2378 @request.session[:user_id] = 2
2379 issue = Issue.find(3)
2379 issue = Issue.find(3)
2380 issue.attachments.delete_all
2380 issue.attachments.delete_all
2381 get :new, :project_id => 1, :copy_from => 3
2381 get :new, :project_id => 1, :copy_from => 3
2382
2382
2383 assert_select 'input[name=copy_attachments]', 0
2383 assert_select 'input[name=copy_attachments]', 0
2384 end
2384 end
2385
2385
2386 def test_new_as_copy_with_subtasks_should_show_copy_subtasks_checkbox
2386 def test_new_as_copy_with_subtasks_should_show_copy_subtasks_checkbox
2387 @request.session[:user_id] = 2
2387 @request.session[:user_id] = 2
2388 issue = Issue.generate_with_descendants!
2388 issue = Issue.generate_with_descendants!
2389 get :new, :project_id => 1, :copy_from => issue.id
2389 get :new, :project_id => 1, :copy_from => issue.id
2390
2390
2391 assert_select 'input[type=checkbox][name=copy_subtasks][checked=checked][value=1]'
2391 assert_select 'input[type=checkbox][name=copy_subtasks][checked=checked][value=1]'
2392 end
2392 end
2393
2393
2394 def test_new_as_copy_with_invalid_issue_should_respond_with_404
2394 def test_new_as_copy_with_invalid_issue_should_respond_with_404
2395 @request.session[:user_id] = 2
2395 @request.session[:user_id] = 2
2396 get :new, :project_id => 1, :copy_from => 99999
2396 get :new, :project_id => 1, :copy_from => 99999
2397 assert_response 404
2397 assert_response 404
2398 end
2398 end
2399
2399
2400 def test_create_as_copy_on_different_project
2400 def test_create_as_copy_on_different_project
2401 @request.session[:user_id] = 2
2401 @request.session[:user_id] = 2
2402 assert_difference 'Issue.count' do
2402 assert_difference 'Issue.count' do
2403 post :create, :project_id => 1, :copy_from => 1,
2403 post :create, :project_id => 1, :copy_from => 1,
2404 :issue => {:project_id => '2', :tracker_id => '3', :status_id => '1', :subject => 'Copy'}
2404 :issue => {:project_id => '2', :tracker_id => '3', :status_id => '1', :subject => 'Copy'}
2405
2405
2406 assert_not_nil assigns(:issue)
2406 assert_not_nil assigns(:issue)
2407 assert assigns(:issue).copy?
2407 assert assigns(:issue).copy?
2408 end
2408 end
2409 issue = Issue.first(:order => 'id DESC')
2409 issue = Issue.first(:order => 'id DESC')
2410 assert_redirected_to "/issues/#{issue.id}"
2410 assert_redirected_to "/issues/#{issue.id}"
2411
2411
2412 assert_equal 2, issue.project_id
2412 assert_equal 2, issue.project_id
2413 assert_equal 3, issue.tracker_id
2413 assert_equal 3, issue.tracker_id
2414 assert_equal 'Copy', issue.subject
2414 assert_equal 'Copy', issue.subject
2415 end
2415 end
2416
2416
2417 def test_create_as_copy_should_copy_attachments
2417 def test_create_as_copy_should_copy_attachments
2418 @request.session[:user_id] = 2
2418 @request.session[:user_id] = 2
2419 issue = Issue.find(3)
2419 issue = Issue.find(3)
2420 count = issue.attachments.count
2420 count = issue.attachments.count
2421 assert count > 0
2421 assert count > 0
2422
2422
2423 assert_difference 'Issue.count' do
2423 assert_difference 'Issue.count' do
2424 assert_difference 'Attachment.count', count do
2424 assert_difference 'Attachment.count', count do
2425 assert_no_difference 'Journal.count' do
2425 assert_no_difference 'Journal.count' do
2426 post :create, :project_id => 1, :copy_from => 3,
2426 post :create, :project_id => 1, :copy_from => 3,
2427 :issue => {:project_id => '1', :tracker_id => '3', :status_id => '1', :subject => 'Copy with attachments'},
2427 :issue => {:project_id => '1', :tracker_id => '3', :status_id => '1', :subject => 'Copy with attachments'},
2428 :copy_attachments => '1'
2428 :copy_attachments => '1'
2429 end
2429 end
2430 end
2430 end
2431 end
2431 end
2432 copy = Issue.first(:order => 'id DESC')
2432 copy = Issue.first(:order => 'id DESC')
2433 assert_equal count, copy.attachments.count
2433 assert_equal count, copy.attachments.count
2434 assert_equal issue.attachments.map(&:filename).sort, copy.attachments.map(&:filename).sort
2434 assert_equal issue.attachments.map(&:filename).sort, copy.attachments.map(&:filename).sort
2435 end
2435 end
2436
2436
2437 def test_create_as_copy_without_copy_attachments_option_should_not_copy_attachments
2437 def test_create_as_copy_without_copy_attachments_option_should_not_copy_attachments
2438 @request.session[:user_id] = 2
2438 @request.session[:user_id] = 2
2439 issue = Issue.find(3)
2439 issue = Issue.find(3)
2440 count = issue.attachments.count
2440 count = issue.attachments.count
2441 assert count > 0
2441 assert count > 0
2442
2442
2443 assert_difference 'Issue.count' do
2443 assert_difference 'Issue.count' do
2444 assert_no_difference 'Attachment.count' do
2444 assert_no_difference 'Attachment.count' do
2445 assert_no_difference 'Journal.count' do
2445 assert_no_difference 'Journal.count' do
2446 post :create, :project_id => 1, :copy_from => 3,
2446 post :create, :project_id => 1, :copy_from => 3,
2447 :issue => {:project_id => '1', :tracker_id => '3', :status_id => '1', :subject => 'Copy with attachments'}
2447 :issue => {:project_id => '1', :tracker_id => '3', :status_id => '1', :subject => 'Copy with attachments'}
2448 end
2448 end
2449 end
2449 end
2450 end
2450 end
2451 copy = Issue.first(:order => 'id DESC')
2451 copy = Issue.first(:order => 'id DESC')
2452 assert_equal 0, copy.attachments.count
2452 assert_equal 0, copy.attachments.count
2453 end
2453 end
2454
2454
2455 def test_create_as_copy_with_attachments_should_add_new_files
2455 def test_create_as_copy_with_attachments_should_add_new_files
2456 @request.session[:user_id] = 2
2456 @request.session[:user_id] = 2
2457 issue = Issue.find(3)
2457 issue = Issue.find(3)
2458 count = issue.attachments.count
2458 count = issue.attachments.count
2459 assert count > 0
2459 assert count > 0
2460
2460
2461 assert_difference 'Issue.count' do
2461 assert_difference 'Issue.count' do
2462 assert_difference 'Attachment.count', count + 1 do
2462 assert_difference 'Attachment.count', count + 1 do
2463 assert_no_difference 'Journal.count' do
2463 assert_no_difference 'Journal.count' do
2464 post :create, :project_id => 1, :copy_from => 3,
2464 post :create, :project_id => 1, :copy_from => 3,
2465 :issue => {:project_id => '1', :tracker_id => '3', :status_id => '1', :subject => 'Copy with attachments'},
2465 :issue => {:project_id => '1', :tracker_id => '3', :status_id => '1', :subject => 'Copy with attachments'},
2466 :copy_attachments => '1',
2466 :copy_attachments => '1',
2467 :attachments => {'1' => {'file' => uploaded_test_file('testfile.txt', 'text/plain'), 'description' => 'test file'}}
2467 :attachments => {'1' => {'file' => uploaded_test_file('testfile.txt', 'text/plain'), 'description' => 'test file'}}
2468 end
2468 end
2469 end
2469 end
2470 end
2470 end
2471 copy = Issue.first(:order => 'id DESC')
2471 copy = Issue.first(:order => 'id DESC')
2472 assert_equal count + 1, copy.attachments.count
2472 assert_equal count + 1, copy.attachments.count
2473 end
2473 end
2474
2474
2475 def test_create_as_copy_should_add_relation_with_copied_issue
2475 def test_create_as_copy_should_add_relation_with_copied_issue
2476 @request.session[:user_id] = 2
2476 @request.session[:user_id] = 2
2477
2477
2478 assert_difference 'Issue.count' do
2478 assert_difference 'Issue.count' do
2479 assert_difference 'IssueRelation.count' do
2479 assert_difference 'IssueRelation.count' do
2480 post :create, :project_id => 1, :copy_from => 1,
2480 post :create, :project_id => 1, :copy_from => 1,
2481 :issue => {:project_id => '1', :tracker_id => '3', :status_id => '1', :subject => 'Copy'}
2481 :issue => {:project_id => '1', :tracker_id => '3', :status_id => '1', :subject => 'Copy'}
2482 end
2482 end
2483 end
2483 end
2484 copy = Issue.first(:order => 'id DESC')
2484 copy = Issue.first(:order => 'id DESC')
2485 assert_equal 1, copy.relations.size
2485 assert_equal 1, copy.relations.size
2486 end
2486 end
2487
2487
2488 def test_create_as_copy_should_copy_subtasks
2488 def test_create_as_copy_should_copy_subtasks
2489 @request.session[:user_id] = 2
2489 @request.session[:user_id] = 2
2490 issue = Issue.generate_with_descendants!
2490 issue = Issue.generate_with_descendants!
2491 count = issue.descendants.count
2491 count = issue.descendants.count
2492
2492
2493 assert_difference 'Issue.count', count+1 do
2493 assert_difference 'Issue.count', count+1 do
2494 assert_no_difference 'Journal.count' do
2494 assert_no_difference 'Journal.count' do
2495 post :create, :project_id => 1, :copy_from => issue.id,
2495 post :create, :project_id => 1, :copy_from => issue.id,
2496 :issue => {:project_id => '1', :tracker_id => '3', :status_id => '1', :subject => 'Copy with subtasks'},
2496 :issue => {:project_id => '1', :tracker_id => '3', :status_id => '1', :subject => 'Copy with subtasks'},
2497 :copy_subtasks => '1'
2497 :copy_subtasks => '1'
2498 end
2498 end
2499 end
2499 end
2500 copy = Issue.where(:parent_id => nil).first(:order => 'id DESC')
2500 copy = Issue.where(:parent_id => nil).first(:order => 'id DESC')
2501 assert_equal count, copy.descendants.count
2501 assert_equal count, copy.descendants.count
2502 assert_equal issue.descendants.map(&:subject).sort, copy.descendants.map(&:subject).sort
2502 assert_equal issue.descendants.map(&:subject).sort, copy.descendants.map(&:subject).sort
2503 end
2503 end
2504
2504
2505 def test_create_as_copy_without_copy_subtasks_option_should_not_copy_subtasks
2505 def test_create_as_copy_without_copy_subtasks_option_should_not_copy_subtasks
2506 @request.session[:user_id] = 2
2506 @request.session[:user_id] = 2
2507 issue = Issue.generate_with_descendants!
2507 issue = Issue.generate_with_descendants!
2508
2508
2509 assert_difference 'Issue.count', 1 do
2509 assert_difference 'Issue.count', 1 do
2510 assert_no_difference 'Journal.count' do
2510 assert_no_difference 'Journal.count' do
2511 post :create, :project_id => 1, :copy_from => 3,
2511 post :create, :project_id => 1, :copy_from => 3,
2512 :issue => {:project_id => '1', :tracker_id => '3', :status_id => '1', :subject => 'Copy with subtasks'}
2512 :issue => {:project_id => '1', :tracker_id => '3', :status_id => '1', :subject => 'Copy with subtasks'}
2513 end
2513 end
2514 end
2514 end
2515 copy = Issue.where(:parent_id => nil).first(:order => 'id DESC')
2515 copy = Issue.where(:parent_id => nil).first(:order => 'id DESC')
2516 assert_equal 0, copy.descendants.count
2516 assert_equal 0, copy.descendants.count
2517 end
2517 end
2518
2518
2519 def test_create_as_copy_with_failure
2519 def test_create_as_copy_with_failure
2520 @request.session[:user_id] = 2
2520 @request.session[:user_id] = 2
2521 post :create, :project_id => 1, :copy_from => 1,
2521 post :create, :project_id => 1, :copy_from => 1,
2522 :issue => {:project_id => '2', :tracker_id => '3', :status_id => '1', :subject => ''}
2522 :issue => {:project_id => '2', :tracker_id => '3', :status_id => '1', :subject => ''}
2523
2523
2524 assert_response :success
2524 assert_response :success
2525 assert_template 'new'
2525 assert_template 'new'
2526
2526
2527 assert_not_nil assigns(:issue)
2527 assert_not_nil assigns(:issue)
2528 assert assigns(:issue).copy?
2528 assert assigns(:issue).copy?
2529
2529
2530 assert_select 'form#issue-form[action=/projects/ecookbook/issues]' do
2530 assert_select 'form#issue-form[action=/projects/ecookbook/issues]' do
2531 assert_select 'select[name=?]', 'issue[project_id]' do
2531 assert_select 'select[name=?]', 'issue[project_id]' do
2532 assert_select 'option[value=1]:not([selected])', :text => 'eCookbook'
2532 assert_select 'option[value=1]:not([selected])', :text => 'eCookbook'
2533 assert_select 'option[value=2][selected=selected]', :text => 'OnlineStore'
2533 assert_select 'option[value=2][selected=selected]', :text => 'OnlineStore'
2534 end
2534 end
2535 assert_select 'input[name=copy_from][value=1]'
2535 assert_select 'input[name=copy_from][value=1]'
2536 end
2536 end
2537 end
2537 end
2538
2538
2539 def test_create_as_copy_on_project_without_permission_should_ignore_target_project
2539 def test_create_as_copy_on_project_without_permission_should_ignore_target_project
2540 @request.session[:user_id] = 2
2540 @request.session[:user_id] = 2
2541 assert !User.find(2).member_of?(Project.find(4))
2541 assert !User.find(2).member_of?(Project.find(4))
2542
2542
2543 assert_difference 'Issue.count' do
2543 assert_difference 'Issue.count' do
2544 post :create, :project_id => 1, :copy_from => 1,
2544 post :create, :project_id => 1, :copy_from => 1,
2545 :issue => {:project_id => '4', :tracker_id => '3', :status_id => '1', :subject => 'Copy'}
2545 :issue => {:project_id => '4', :tracker_id => '3', :status_id => '1', :subject => 'Copy'}
2546 end
2546 end
2547 issue = Issue.first(:order => 'id DESC')
2547 issue = Issue.first(:order => 'id DESC')
2548 assert_equal 1, issue.project_id
2548 assert_equal 1, issue.project_id
2549 end
2549 end
2550
2550
2551 def test_get_edit
2551 def test_get_edit
2552 @request.session[:user_id] = 2
2552 @request.session[:user_id] = 2
2553 get :edit, :id => 1
2553 get :edit, :id => 1
2554 assert_response :success
2554 assert_response :success
2555 assert_template 'edit'
2555 assert_template 'edit'
2556 assert_not_nil assigns(:issue)
2556 assert_not_nil assigns(:issue)
2557 assert_equal Issue.find(1), assigns(:issue)
2557 assert_equal Issue.find(1), assigns(:issue)
2558
2558
2559 # Be sure we don't display inactive IssuePriorities
2559 # Be sure we don't display inactive IssuePriorities
2560 assert ! IssuePriority.find(15).active?
2560 assert ! IssuePriority.find(15).active?
2561 assert_select 'select[name=?]', 'issue[priority_id]' do
2561 assert_select 'select[name=?]', 'issue[priority_id]' do
2562 assert_select 'option[value=15]', 0
2562 assert_select 'option[value=15]', 0
2563 end
2563 end
2564 end
2564 end
2565
2565
2566 def test_get_edit_should_display_the_time_entry_form_with_log_time_permission
2566 def test_get_edit_should_display_the_time_entry_form_with_log_time_permission
2567 @request.session[:user_id] = 2
2567 @request.session[:user_id] = 2
2568 Role.find_by_name('Manager').update_attribute :permissions, [:view_issues, :edit_issues, :log_time]
2568 Role.find_by_name('Manager').update_attribute :permissions, [:view_issues, :edit_issues, :log_time]
2569
2569
2570 get :edit, :id => 1
2570 get :edit, :id => 1
2571 assert_select 'input[name=?]', 'time_entry[hours]'
2571 assert_select 'input[name=?]', 'time_entry[hours]'
2572 end
2572 end
2573
2573
2574 def test_get_edit_should_not_display_the_time_entry_form_without_log_time_permission
2574 def test_get_edit_should_not_display_the_time_entry_form_without_log_time_permission
2575 @request.session[:user_id] = 2
2575 @request.session[:user_id] = 2
2576 Role.find_by_name('Manager').remove_permission! :log_time
2576 Role.find_by_name('Manager').remove_permission! :log_time
2577
2577
2578 get :edit, :id => 1
2578 get :edit, :id => 1
2579 assert_select 'input[name=?]', 'time_entry[hours]', 0
2579 assert_select 'input[name=?]', 'time_entry[hours]', 0
2580 end
2580 end
2581
2581
2582 def test_get_edit_with_params
2582 def test_get_edit_with_params
2583 @request.session[:user_id] = 2
2583 @request.session[:user_id] = 2
2584 get :edit, :id => 1, :issue => { :status_id => 5, :priority_id => 7 },
2584 get :edit, :id => 1, :issue => { :status_id => 5, :priority_id => 7 },
2585 :time_entry => { :hours => '2.5', :comments => 'test_get_edit_with_params', :activity_id => 10 }
2585 :time_entry => { :hours => '2.5', :comments => 'test_get_edit_with_params', :activity_id => 10 }
2586 assert_response :success
2586 assert_response :success
2587 assert_template 'edit'
2587 assert_template 'edit'
2588
2588
2589 issue = assigns(:issue)
2589 issue = assigns(:issue)
2590 assert_not_nil issue
2590 assert_not_nil issue
2591
2591
2592 assert_equal 5, issue.status_id
2592 assert_equal 5, issue.status_id
2593 assert_select 'select[name=?]', 'issue[status_id]' do
2593 assert_select 'select[name=?]', 'issue[status_id]' do
2594 assert_select 'option[value=5][selected=selected]', :text => 'Closed'
2594 assert_select 'option[value=5][selected=selected]', :text => 'Closed'
2595 end
2595 end
2596
2596
2597 assert_equal 7, issue.priority_id
2597 assert_equal 7, issue.priority_id
2598 assert_select 'select[name=?]', 'issue[priority_id]' do
2598 assert_select 'select[name=?]', 'issue[priority_id]' do
2599 assert_select 'option[value=7][selected=selected]', :text => 'Urgent'
2599 assert_select 'option[value=7][selected=selected]', :text => 'Urgent'
2600 end
2600 end
2601
2601
2602 assert_select 'input[name=?][value=2.5]', 'time_entry[hours]'
2602 assert_select 'input[name=?][value=2.5]', 'time_entry[hours]'
2603 assert_select 'select[name=?]', 'time_entry[activity_id]' do
2603 assert_select 'select[name=?]', 'time_entry[activity_id]' do
2604 assert_select 'option[value=10][selected=selected]', :text => 'Development'
2604 assert_select 'option[value=10][selected=selected]', :text => 'Development'
2605 end
2605 end
2606 assert_select 'input[name=?][value=test_get_edit_with_params]', 'time_entry[comments]'
2606 assert_select 'input[name=?][value=test_get_edit_with_params]', 'time_entry[comments]'
2607 end
2607 end
2608
2608
2609 def test_get_edit_with_multi_custom_field
2609 def test_get_edit_with_multi_custom_field
2610 field = CustomField.find(1)
2610 field = CustomField.find(1)
2611 field.update_attribute :multiple, true
2611 field.update_attribute :multiple, true
2612 issue = Issue.find(1)
2612 issue = Issue.find(1)
2613 issue.custom_field_values = {1 => ['MySQL', 'Oracle']}
2613 issue.custom_field_values = {1 => ['MySQL', 'Oracle']}
2614 issue.save!
2614 issue.save!
2615
2615
2616 @request.session[:user_id] = 2
2616 @request.session[:user_id] = 2
2617 get :edit, :id => 1
2617 get :edit, :id => 1
2618 assert_response :success
2618 assert_response :success
2619 assert_template 'edit'
2619 assert_template 'edit'
2620
2620
2621 assert_select 'select[name=?][multiple=multiple]', 'issue[custom_field_values][1][]' do
2621 assert_select 'select[name=?][multiple=multiple]', 'issue[custom_field_values][1][]' do
2622 assert_select 'option', 3
2622 assert_select 'option', 3
2623 assert_select 'option[value=MySQL][selected=selected]'
2623 assert_select 'option[value=MySQL][selected=selected]'
2624 assert_select 'option[value=Oracle][selected=selected]'
2624 assert_select 'option[value=Oracle][selected=selected]'
2625 assert_select 'option[value=PostgreSQL]:not([selected])'
2625 assert_select 'option[value=PostgreSQL]:not([selected])'
2626 end
2626 end
2627 end
2627 end
2628
2628
2629 def test_update_edit_form
2629 def test_update_form_for_existing_issue
2630 @request.session[:user_id] = 2
2630 @request.session[:user_id] = 2
2631 xhr :put, :new, :project_id => 1,
2631 xhr :put, :update_form, :project_id => 1,
2632 :id => 1,
2632 :id => 1,
2633 :issue => {:tracker_id => 2,
2633 :issue => {:tracker_id => 2,
2634 :subject => 'This is the test_new issue',
2634 :subject => 'This is the test_new issue',
2635 :description => 'This is the description',
2635 :description => 'This is the description',
2636 :priority_id => 5}
2636 :priority_id => 5}
2637 assert_response :success
2637 assert_response :success
2638 assert_equal 'text/javascript', response.content_type
2638 assert_equal 'text/javascript', response.content_type
2639 assert_template 'update_form'
2639 assert_template 'update_form'
2640 assert_template 'form'
2640 assert_template 'form'
2641
2641
2642 issue = assigns(:issue)
2642 issue = assigns(:issue)
2643 assert_kind_of Issue, issue
2643 assert_kind_of Issue, issue
2644 assert_equal 1, issue.id
2644 assert_equal 1, issue.id
2645 assert_equal 1, issue.project_id
2645 assert_equal 1, issue.project_id
2646 assert_equal 2, issue.tracker_id
2646 assert_equal 2, issue.tracker_id
2647 assert_equal 'This is the test_new issue', issue.subject
2647 assert_equal 'This is the test_new issue', issue.subject
2648 end
2648 end
2649
2649
2650 def test_update_edit_form_should_keep_issue_author
2650 def test_update_form_for_existing_issue_should_keep_issue_author
2651 @request.session[:user_id] = 3
2651 @request.session[:user_id] = 3
2652 xhr :put, :new, :project_id => 1, :id => 1, :issue => {:subject => 'Changed'}
2652 xhr :put, :update_form, :project_id => 1, :id => 1, :issue => {:subject => 'Changed'}
2653 assert_response :success
2653 assert_response :success
2654 assert_equal 'text/javascript', response.content_type
2654 assert_equal 'text/javascript', response.content_type
2655
2655
2656 issue = assigns(:issue)
2656 issue = assigns(:issue)
2657 assert_equal User.find(2), issue.author
2657 assert_equal User.find(2), issue.author
2658 assert_equal 2, issue.author_id
2658 assert_equal 2, issue.author_id
2659 assert_not_equal User.current, issue.author
2659 assert_not_equal User.current, issue.author
2660 end
2660 end
2661
2661
2662 def test_update_edit_form_should_propose_transitions_based_on_initial_status
2662 def test_update_form_for_existing_issue_should_propose_transitions_based_on_initial_status
2663 @request.session[:user_id] = 2
2663 @request.session[:user_id] = 2
2664 WorkflowTransition.delete_all
2664 WorkflowTransition.delete_all
2665 WorkflowTransition.create!(:role_id => 1, :tracker_id => 2, :old_status_id => 2, :new_status_id => 1)
2665 WorkflowTransition.create!(:role_id => 1, :tracker_id => 2, :old_status_id => 2, :new_status_id => 1)
2666 WorkflowTransition.create!(:role_id => 1, :tracker_id => 2, :old_status_id => 2, :new_status_id => 5)
2666 WorkflowTransition.create!(:role_id => 1, :tracker_id => 2, :old_status_id => 2, :new_status_id => 5)
2667 WorkflowTransition.create!(:role_id => 1, :tracker_id => 2, :old_status_id => 5, :new_status_id => 4)
2667 WorkflowTransition.create!(:role_id => 1, :tracker_id => 2, :old_status_id => 5, :new_status_id => 4)
2668
2668
2669 xhr :put, :new, :project_id => 1,
2669 xhr :put, :update_form, :project_id => 1,
2670 :id => 2,
2670 :id => 2,
2671 :issue => {:tracker_id => 2,
2671 :issue => {:tracker_id => 2,
2672 :status_id => 5,
2672 :status_id => 5,
2673 :subject => 'This is an issue'}
2673 :subject => 'This is an issue'}
2674
2674
2675 assert_equal 5, assigns(:issue).status_id
2675 assert_equal 5, assigns(:issue).status_id
2676 assert_equal [1,2,5], assigns(:allowed_statuses).map(&:id).sort
2676 assert_equal [1,2,5], assigns(:allowed_statuses).map(&:id).sort
2677 end
2677 end
2678
2678
2679 def test_update_edit_form_with_project_change
2679 def test_update_form_for_existing_issue_with_project_change
2680 @request.session[:user_id] = 2
2680 @request.session[:user_id] = 2
2681 xhr :put, :new, :project_id => 1,
2681 xhr :put, :update_form, :project_id => 1,
2682 :id => 1,
2682 :id => 1,
2683 :issue => {:project_id => 2,
2683 :issue => {:project_id => 2,
2684 :tracker_id => 2,
2684 :tracker_id => 2,
2685 :subject => 'This is the test_new issue',
2685 :subject => 'This is the test_new issue',
2686 :description => 'This is the description',
2686 :description => 'This is the description',
2687 :priority_id => 5}
2687 :priority_id => 5}
2688 assert_response :success
2688 assert_response :success
2689 assert_template 'form'
2689 assert_template 'form'
2690
2690
2691 issue = assigns(:issue)
2691 issue = assigns(:issue)
2692 assert_kind_of Issue, issue
2692 assert_kind_of Issue, issue
2693 assert_equal 1, issue.id
2693 assert_equal 1, issue.id
2694 assert_equal 2, issue.project_id
2694 assert_equal 2, issue.project_id
2695 assert_equal 2, issue.tracker_id
2695 assert_equal 2, issue.tracker_id
2696 assert_equal 'This is the test_new issue', issue.subject
2696 assert_equal 'This is the test_new issue', issue.subject
2697 end
2697 end
2698
2698
2699 def test_put_update_without_custom_fields_param
2699 def test_put_update_without_custom_fields_param
2700 @request.session[:user_id] = 2
2700 @request.session[:user_id] = 2
2701 ActionMailer::Base.deliveries.clear
2701 ActionMailer::Base.deliveries.clear
2702
2702
2703 issue = Issue.find(1)
2703 issue = Issue.find(1)
2704 assert_equal '125', issue.custom_value_for(2).value
2704 assert_equal '125', issue.custom_value_for(2).value
2705 old_subject = issue.subject
2705 old_subject = issue.subject
2706 new_subject = 'Subject modified by IssuesControllerTest#test_post_edit'
2706 new_subject = 'Subject modified by IssuesControllerTest#test_post_edit'
2707
2707
2708 assert_difference('Journal.count') do
2708 assert_difference('Journal.count') do
2709 assert_difference('JournalDetail.count', 2) do
2709 assert_difference('JournalDetail.count', 2) do
2710 put :update, :id => 1, :issue => {:subject => new_subject,
2710 put :update, :id => 1, :issue => {:subject => new_subject,
2711 :priority_id => '6',
2711 :priority_id => '6',
2712 :category_id => '1' # no change
2712 :category_id => '1' # no change
2713 }
2713 }
2714 end
2714 end
2715 end
2715 end
2716 assert_redirected_to :action => 'show', :id => '1'
2716 assert_redirected_to :action => 'show', :id => '1'
2717 issue.reload
2717 issue.reload
2718 assert_equal new_subject, issue.subject
2718 assert_equal new_subject, issue.subject
2719 # Make sure custom fields were not cleared
2719 # Make sure custom fields were not cleared
2720 assert_equal '125', issue.custom_value_for(2).value
2720 assert_equal '125', issue.custom_value_for(2).value
2721
2721
2722 mail = ActionMailer::Base.deliveries.last
2722 mail = ActionMailer::Base.deliveries.last
2723 assert_not_nil mail
2723 assert_not_nil mail
2724 assert mail.subject.starts_with?("[#{issue.project.name} - #{issue.tracker.name} ##{issue.id}]")
2724 assert mail.subject.starts_with?("[#{issue.project.name} - #{issue.tracker.name} ##{issue.id}]")
2725 assert_mail_body_match "Subject changed from #{old_subject} to #{new_subject}", mail
2725 assert_mail_body_match "Subject changed from #{old_subject} to #{new_subject}", mail
2726 end
2726 end
2727
2727
2728 def test_put_update_with_project_change
2728 def test_put_update_with_project_change
2729 @request.session[:user_id] = 2
2729 @request.session[:user_id] = 2
2730 ActionMailer::Base.deliveries.clear
2730 ActionMailer::Base.deliveries.clear
2731
2731
2732 assert_difference('Journal.count') do
2732 assert_difference('Journal.count') do
2733 assert_difference('JournalDetail.count', 3) do
2733 assert_difference('JournalDetail.count', 3) do
2734 put :update, :id => 1, :issue => {:project_id => '2',
2734 put :update, :id => 1, :issue => {:project_id => '2',
2735 :tracker_id => '1', # no change
2735 :tracker_id => '1', # no change
2736 :priority_id => '6',
2736 :priority_id => '6',
2737 :category_id => '3'
2737 :category_id => '3'
2738 }
2738 }
2739 end
2739 end
2740 end
2740 end
2741 assert_redirected_to :action => 'show', :id => '1'
2741 assert_redirected_to :action => 'show', :id => '1'
2742 issue = Issue.find(1)
2742 issue = Issue.find(1)
2743 assert_equal 2, issue.project_id
2743 assert_equal 2, issue.project_id
2744 assert_equal 1, issue.tracker_id
2744 assert_equal 1, issue.tracker_id
2745 assert_equal 6, issue.priority_id
2745 assert_equal 6, issue.priority_id
2746 assert_equal 3, issue.category_id
2746 assert_equal 3, issue.category_id
2747
2747
2748 mail = ActionMailer::Base.deliveries.last
2748 mail = ActionMailer::Base.deliveries.last
2749 assert_not_nil mail
2749 assert_not_nil mail
2750 assert mail.subject.starts_with?("[#{issue.project.name} - #{issue.tracker.name} ##{issue.id}]")
2750 assert mail.subject.starts_with?("[#{issue.project.name} - #{issue.tracker.name} ##{issue.id}]")
2751 assert_mail_body_match "Project changed from eCookbook to OnlineStore", mail
2751 assert_mail_body_match "Project changed from eCookbook to OnlineStore", mail
2752 end
2752 end
2753
2753
2754 def test_put_update_with_tracker_change
2754 def test_put_update_with_tracker_change
2755 @request.session[:user_id] = 2
2755 @request.session[:user_id] = 2
2756 ActionMailer::Base.deliveries.clear
2756 ActionMailer::Base.deliveries.clear
2757
2757
2758 assert_difference('Journal.count') do
2758 assert_difference('Journal.count') do
2759 assert_difference('JournalDetail.count', 2) do
2759 assert_difference('JournalDetail.count', 2) do
2760 put :update, :id => 1, :issue => {:project_id => '1',
2760 put :update, :id => 1, :issue => {:project_id => '1',
2761 :tracker_id => '2',
2761 :tracker_id => '2',
2762 :priority_id => '6'
2762 :priority_id => '6'
2763 }
2763 }
2764 end
2764 end
2765 end
2765 end
2766 assert_redirected_to :action => 'show', :id => '1'
2766 assert_redirected_to :action => 'show', :id => '1'
2767 issue = Issue.find(1)
2767 issue = Issue.find(1)
2768 assert_equal 1, issue.project_id
2768 assert_equal 1, issue.project_id
2769 assert_equal 2, issue.tracker_id
2769 assert_equal 2, issue.tracker_id
2770 assert_equal 6, issue.priority_id
2770 assert_equal 6, issue.priority_id
2771 assert_equal 1, issue.category_id
2771 assert_equal 1, issue.category_id
2772
2772
2773 mail = ActionMailer::Base.deliveries.last
2773 mail = ActionMailer::Base.deliveries.last
2774 assert_not_nil mail
2774 assert_not_nil mail
2775 assert mail.subject.starts_with?("[#{issue.project.name} - #{issue.tracker.name} ##{issue.id}]")
2775 assert mail.subject.starts_with?("[#{issue.project.name} - #{issue.tracker.name} ##{issue.id}]")
2776 assert_mail_body_match "Tracker changed from Bug to Feature request", mail
2776 assert_mail_body_match "Tracker changed from Bug to Feature request", mail
2777 end
2777 end
2778
2778
2779 def test_put_update_with_custom_field_change
2779 def test_put_update_with_custom_field_change
2780 @request.session[:user_id] = 2
2780 @request.session[:user_id] = 2
2781 issue = Issue.find(1)
2781 issue = Issue.find(1)
2782 assert_equal '125', issue.custom_value_for(2).value
2782 assert_equal '125', issue.custom_value_for(2).value
2783
2783
2784 assert_difference('Journal.count') do
2784 assert_difference('Journal.count') do
2785 assert_difference('JournalDetail.count', 3) do
2785 assert_difference('JournalDetail.count', 3) do
2786 put :update, :id => 1, :issue => {:subject => 'Custom field change',
2786 put :update, :id => 1, :issue => {:subject => 'Custom field change',
2787 :priority_id => '6',
2787 :priority_id => '6',
2788 :category_id => '1', # no change
2788 :category_id => '1', # no change
2789 :custom_field_values => { '2' => 'New custom value' }
2789 :custom_field_values => { '2' => 'New custom value' }
2790 }
2790 }
2791 end
2791 end
2792 end
2792 end
2793 assert_redirected_to :action => 'show', :id => '1'
2793 assert_redirected_to :action => 'show', :id => '1'
2794 issue.reload
2794 issue.reload
2795 assert_equal 'New custom value', issue.custom_value_for(2).value
2795 assert_equal 'New custom value', issue.custom_value_for(2).value
2796
2796
2797 mail = ActionMailer::Base.deliveries.last
2797 mail = ActionMailer::Base.deliveries.last
2798 assert_not_nil mail
2798 assert_not_nil mail
2799 assert_mail_body_match "Searchable field changed from 125 to New custom value", mail
2799 assert_mail_body_match "Searchable field changed from 125 to New custom value", mail
2800 end
2800 end
2801
2801
2802 def test_put_update_with_multi_custom_field_change
2802 def test_put_update_with_multi_custom_field_change
2803 field = CustomField.find(1)
2803 field = CustomField.find(1)
2804 field.update_attribute :multiple, true
2804 field.update_attribute :multiple, true
2805 issue = Issue.find(1)
2805 issue = Issue.find(1)
2806 issue.custom_field_values = {1 => ['MySQL', 'Oracle']}
2806 issue.custom_field_values = {1 => ['MySQL', 'Oracle']}
2807 issue.save!
2807 issue.save!
2808
2808
2809 @request.session[:user_id] = 2
2809 @request.session[:user_id] = 2
2810 assert_difference('Journal.count') do
2810 assert_difference('Journal.count') do
2811 assert_difference('JournalDetail.count', 3) do
2811 assert_difference('JournalDetail.count', 3) do
2812 put :update, :id => 1,
2812 put :update, :id => 1,
2813 :issue => {
2813 :issue => {
2814 :subject => 'Custom field change',
2814 :subject => 'Custom field change',
2815 :custom_field_values => { '1' => ['', 'Oracle', 'PostgreSQL'] }
2815 :custom_field_values => { '1' => ['', 'Oracle', 'PostgreSQL'] }
2816 }
2816 }
2817 end
2817 end
2818 end
2818 end
2819 assert_redirected_to :action => 'show', :id => '1'
2819 assert_redirected_to :action => 'show', :id => '1'
2820 assert_equal ['Oracle', 'PostgreSQL'], Issue.find(1).custom_field_value(1).sort
2820 assert_equal ['Oracle', 'PostgreSQL'], Issue.find(1).custom_field_value(1).sort
2821 end
2821 end
2822
2822
2823 def test_put_update_with_status_and_assignee_change
2823 def test_put_update_with_status_and_assignee_change
2824 issue = Issue.find(1)
2824 issue = Issue.find(1)
2825 assert_equal 1, issue.status_id
2825 assert_equal 1, issue.status_id
2826 @request.session[:user_id] = 2
2826 @request.session[:user_id] = 2
2827 assert_difference('TimeEntry.count', 0) do
2827 assert_difference('TimeEntry.count', 0) do
2828 put :update,
2828 put :update,
2829 :id => 1,
2829 :id => 1,
2830 :issue => { :status_id => 2, :assigned_to_id => 3, :notes => 'Assigned to dlopper' },
2830 :issue => { :status_id => 2, :assigned_to_id => 3, :notes => 'Assigned to dlopper' },
2831 :time_entry => { :hours => '', :comments => '', :activity_id => TimeEntryActivity.first }
2831 :time_entry => { :hours => '', :comments => '', :activity_id => TimeEntryActivity.first }
2832 end
2832 end
2833 assert_redirected_to :action => 'show', :id => '1'
2833 assert_redirected_to :action => 'show', :id => '1'
2834 issue.reload
2834 issue.reload
2835 assert_equal 2, issue.status_id
2835 assert_equal 2, issue.status_id
2836 j = Journal.order('id DESC').first
2836 j = Journal.order('id DESC').first
2837 assert_equal 'Assigned to dlopper', j.notes
2837 assert_equal 'Assigned to dlopper', j.notes
2838 assert_equal 2, j.details.size
2838 assert_equal 2, j.details.size
2839
2839
2840 mail = ActionMailer::Base.deliveries.last
2840 mail = ActionMailer::Base.deliveries.last
2841 assert_mail_body_match "Status changed from New to Assigned", mail
2841 assert_mail_body_match "Status changed from New to Assigned", mail
2842 # subject should contain the new status
2842 # subject should contain the new status
2843 assert mail.subject.include?("(#{ IssueStatus.find(2).name })")
2843 assert mail.subject.include?("(#{ IssueStatus.find(2).name })")
2844 end
2844 end
2845
2845
2846 def test_put_update_with_note_only
2846 def test_put_update_with_note_only
2847 notes = 'Note added by IssuesControllerTest#test_update_with_note_only'
2847 notes = 'Note added by IssuesControllerTest#test_update_with_note_only'
2848 # anonymous user
2848 # anonymous user
2849 put :update,
2849 put :update,
2850 :id => 1,
2850 :id => 1,
2851 :issue => { :notes => notes }
2851 :issue => { :notes => notes }
2852 assert_redirected_to :action => 'show', :id => '1'
2852 assert_redirected_to :action => 'show', :id => '1'
2853 j = Journal.order('id DESC').first
2853 j = Journal.order('id DESC').first
2854 assert_equal notes, j.notes
2854 assert_equal notes, j.notes
2855 assert_equal 0, j.details.size
2855 assert_equal 0, j.details.size
2856 assert_equal User.anonymous, j.user
2856 assert_equal User.anonymous, j.user
2857
2857
2858 mail = ActionMailer::Base.deliveries.last
2858 mail = ActionMailer::Base.deliveries.last
2859 assert_mail_body_match notes, mail
2859 assert_mail_body_match notes, mail
2860 end
2860 end
2861
2861
2862 def test_put_update_with_private_note_only
2862 def test_put_update_with_private_note_only
2863 notes = 'Private note'
2863 notes = 'Private note'
2864 @request.session[:user_id] = 2
2864 @request.session[:user_id] = 2
2865
2865
2866 assert_difference 'Journal.count' do
2866 assert_difference 'Journal.count' do
2867 put :update, :id => 1, :issue => {:notes => notes, :private_notes => '1'}
2867 put :update, :id => 1, :issue => {:notes => notes, :private_notes => '1'}
2868 assert_redirected_to :action => 'show', :id => '1'
2868 assert_redirected_to :action => 'show', :id => '1'
2869 end
2869 end
2870
2870
2871 j = Journal.order('id DESC').first
2871 j = Journal.order('id DESC').first
2872 assert_equal notes, j.notes
2872 assert_equal notes, j.notes
2873 assert_equal true, j.private_notes
2873 assert_equal true, j.private_notes
2874 end
2874 end
2875
2875
2876 def test_put_update_with_private_note_and_changes
2876 def test_put_update_with_private_note_and_changes
2877 notes = 'Private note'
2877 notes = 'Private note'
2878 @request.session[:user_id] = 2
2878 @request.session[:user_id] = 2
2879
2879
2880 assert_difference 'Journal.count', 2 do
2880 assert_difference 'Journal.count', 2 do
2881 put :update, :id => 1, :issue => {:subject => 'New subject', :notes => notes, :private_notes => '1'}
2881 put :update, :id => 1, :issue => {:subject => 'New subject', :notes => notes, :private_notes => '1'}
2882 assert_redirected_to :action => 'show', :id => '1'
2882 assert_redirected_to :action => 'show', :id => '1'
2883 end
2883 end
2884
2884
2885 j = Journal.order('id DESC').first
2885 j = Journal.order('id DESC').first
2886 assert_equal notes, j.notes
2886 assert_equal notes, j.notes
2887 assert_equal true, j.private_notes
2887 assert_equal true, j.private_notes
2888 assert_equal 0, j.details.count
2888 assert_equal 0, j.details.count
2889
2889
2890 j = Journal.order('id DESC').offset(1).first
2890 j = Journal.order('id DESC').offset(1).first
2891 assert_nil j.notes
2891 assert_nil j.notes
2892 assert_equal false, j.private_notes
2892 assert_equal false, j.private_notes
2893 assert_equal 1, j.details.count
2893 assert_equal 1, j.details.count
2894 end
2894 end
2895
2895
2896 def test_put_update_with_note_and_spent_time
2896 def test_put_update_with_note_and_spent_time
2897 @request.session[:user_id] = 2
2897 @request.session[:user_id] = 2
2898 spent_hours_before = Issue.find(1).spent_hours
2898 spent_hours_before = Issue.find(1).spent_hours
2899 assert_difference('TimeEntry.count') do
2899 assert_difference('TimeEntry.count') do
2900 put :update,
2900 put :update,
2901 :id => 1,
2901 :id => 1,
2902 :issue => { :notes => '2.5 hours added' },
2902 :issue => { :notes => '2.5 hours added' },
2903 :time_entry => { :hours => '2.5', :comments => 'test_put_update_with_note_and_spent_time', :activity_id => TimeEntryActivity.first.id }
2903 :time_entry => { :hours => '2.5', :comments => 'test_put_update_with_note_and_spent_time', :activity_id => TimeEntryActivity.first.id }
2904 end
2904 end
2905 assert_redirected_to :action => 'show', :id => '1'
2905 assert_redirected_to :action => 'show', :id => '1'
2906
2906
2907 issue = Issue.find(1)
2907 issue = Issue.find(1)
2908
2908
2909 j = Journal.order('id DESC').first
2909 j = Journal.order('id DESC').first
2910 assert_equal '2.5 hours added', j.notes
2910 assert_equal '2.5 hours added', j.notes
2911 assert_equal 0, j.details.size
2911 assert_equal 0, j.details.size
2912
2912
2913 t = issue.time_entries.find_by_comments('test_put_update_with_note_and_spent_time')
2913 t = issue.time_entries.find_by_comments('test_put_update_with_note_and_spent_time')
2914 assert_not_nil t
2914 assert_not_nil t
2915 assert_equal 2.5, t.hours
2915 assert_equal 2.5, t.hours
2916 assert_equal spent_hours_before + 2.5, issue.spent_hours
2916 assert_equal spent_hours_before + 2.5, issue.spent_hours
2917 end
2917 end
2918
2918
2919 def test_put_update_should_preserve_parent_issue_even_if_not_visible
2919 def test_put_update_should_preserve_parent_issue_even_if_not_visible
2920 parent = Issue.generate!(:project_id => 1, :is_private => true)
2920 parent = Issue.generate!(:project_id => 1, :is_private => true)
2921 issue = Issue.generate!(:parent_issue_id => parent.id)
2921 issue = Issue.generate!(:parent_issue_id => parent.id)
2922 assert !parent.visible?(User.find(3))
2922 assert !parent.visible?(User.find(3))
2923 @request.session[:user_id] = 3
2923 @request.session[:user_id] = 3
2924
2924
2925 get :edit, :id => issue.id
2925 get :edit, :id => issue.id
2926 assert_select 'input[name=?][value=?]', 'issue[parent_issue_id]', parent.id.to_s
2926 assert_select 'input[name=?][value=?]', 'issue[parent_issue_id]', parent.id.to_s
2927
2927
2928 put :update, :id => issue.id, :issue => {:subject => 'New subject', :parent_issue_id => parent.id.to_s}
2928 put :update, :id => issue.id, :issue => {:subject => 'New subject', :parent_issue_id => parent.id.to_s}
2929 assert_response 302
2929 assert_response 302
2930 assert_equal parent, issue.parent
2930 assert_equal parent, issue.parent
2931 end
2931 end
2932
2932
2933 def test_put_update_with_attachment_only
2933 def test_put_update_with_attachment_only
2934 set_tmp_attachments_directory
2934 set_tmp_attachments_directory
2935
2935
2936 # Delete all fixtured journals, a race condition can occur causing the wrong
2936 # Delete all fixtured journals, a race condition can occur causing the wrong
2937 # journal to get fetched in the next find.
2937 # journal to get fetched in the next find.
2938 Journal.delete_all
2938 Journal.delete_all
2939
2939
2940 # anonymous user
2940 # anonymous user
2941 assert_difference 'Attachment.count' do
2941 assert_difference 'Attachment.count' do
2942 put :update, :id => 1,
2942 put :update, :id => 1,
2943 :issue => {:notes => ''},
2943 :issue => {:notes => ''},
2944 :attachments => {'1' => {'file' => uploaded_test_file('testfile.txt', 'text/plain'), 'description' => 'test file'}}
2944 :attachments => {'1' => {'file' => uploaded_test_file('testfile.txt', 'text/plain'), 'description' => 'test file'}}
2945 end
2945 end
2946
2946
2947 assert_redirected_to :action => 'show', :id => '1'
2947 assert_redirected_to :action => 'show', :id => '1'
2948 j = Issue.find(1).journals.reorder('id DESC').first
2948 j = Issue.find(1).journals.reorder('id DESC').first
2949 assert j.notes.blank?
2949 assert j.notes.blank?
2950 assert_equal 1, j.details.size
2950 assert_equal 1, j.details.size
2951 assert_equal 'testfile.txt', j.details.first.value
2951 assert_equal 'testfile.txt', j.details.first.value
2952 assert_equal User.anonymous, j.user
2952 assert_equal User.anonymous, j.user
2953
2953
2954 attachment = Attachment.first(:order => 'id DESC')
2954 attachment = Attachment.first(:order => 'id DESC')
2955 assert_equal Issue.find(1), attachment.container
2955 assert_equal Issue.find(1), attachment.container
2956 assert_equal User.anonymous, attachment.author
2956 assert_equal User.anonymous, attachment.author
2957 assert_equal 'testfile.txt', attachment.filename
2957 assert_equal 'testfile.txt', attachment.filename
2958 assert_equal 'text/plain', attachment.content_type
2958 assert_equal 'text/plain', attachment.content_type
2959 assert_equal 'test file', attachment.description
2959 assert_equal 'test file', attachment.description
2960 assert_equal 59, attachment.filesize
2960 assert_equal 59, attachment.filesize
2961 assert File.exists?(attachment.diskfile)
2961 assert File.exists?(attachment.diskfile)
2962 assert_equal 59, File.size(attachment.diskfile)
2962 assert_equal 59, File.size(attachment.diskfile)
2963
2963
2964 mail = ActionMailer::Base.deliveries.last
2964 mail = ActionMailer::Base.deliveries.last
2965 assert_mail_body_match 'testfile.txt', mail
2965 assert_mail_body_match 'testfile.txt', mail
2966 end
2966 end
2967
2967
2968 def test_put_update_with_failure_should_save_attachments
2968 def test_put_update_with_failure_should_save_attachments
2969 set_tmp_attachments_directory
2969 set_tmp_attachments_directory
2970 @request.session[:user_id] = 2
2970 @request.session[:user_id] = 2
2971
2971
2972 assert_no_difference 'Journal.count' do
2972 assert_no_difference 'Journal.count' do
2973 assert_difference 'Attachment.count' do
2973 assert_difference 'Attachment.count' do
2974 put :update, :id => 1,
2974 put :update, :id => 1,
2975 :issue => { :subject => '' },
2975 :issue => { :subject => '' },
2976 :attachments => {'1' => {'file' => uploaded_test_file('testfile.txt', 'text/plain'), 'description' => 'test file'}}
2976 :attachments => {'1' => {'file' => uploaded_test_file('testfile.txt', 'text/plain'), 'description' => 'test file'}}
2977 assert_response :success
2977 assert_response :success
2978 assert_template 'edit'
2978 assert_template 'edit'
2979 end
2979 end
2980 end
2980 end
2981
2981
2982 attachment = Attachment.first(:order => 'id DESC')
2982 attachment = Attachment.first(:order => 'id DESC')
2983 assert_equal 'testfile.txt', attachment.filename
2983 assert_equal 'testfile.txt', attachment.filename
2984 assert File.exists?(attachment.diskfile)
2984 assert File.exists?(attachment.diskfile)
2985 assert_nil attachment.container
2985 assert_nil attachment.container
2986
2986
2987 assert_select 'input[name=?][value=?]', 'attachments[p0][token]', attachment.token
2987 assert_select 'input[name=?][value=?]', 'attachments[p0][token]', attachment.token
2988 assert_select 'input[name=?][value=?]', 'attachments[p0][filename]', 'testfile.txt'
2988 assert_select 'input[name=?][value=?]', 'attachments[p0][filename]', 'testfile.txt'
2989 end
2989 end
2990
2990
2991 def test_put_update_with_failure_should_keep_saved_attachments
2991 def test_put_update_with_failure_should_keep_saved_attachments
2992 set_tmp_attachments_directory
2992 set_tmp_attachments_directory
2993 attachment = Attachment.create!(:file => uploaded_test_file("testfile.txt", "text/plain"), :author_id => 2)
2993 attachment = Attachment.create!(:file => uploaded_test_file("testfile.txt", "text/plain"), :author_id => 2)
2994 @request.session[:user_id] = 2
2994 @request.session[:user_id] = 2
2995
2995
2996 assert_no_difference 'Journal.count' do
2996 assert_no_difference 'Journal.count' do
2997 assert_no_difference 'Attachment.count' do
2997 assert_no_difference 'Attachment.count' do
2998 put :update, :id => 1,
2998 put :update, :id => 1,
2999 :issue => { :subject => '' },
2999 :issue => { :subject => '' },
3000 :attachments => {'p0' => {'token' => attachment.token}}
3000 :attachments => {'p0' => {'token' => attachment.token}}
3001 assert_response :success
3001 assert_response :success
3002 assert_template 'edit'
3002 assert_template 'edit'
3003 end
3003 end
3004 end
3004 end
3005
3005
3006 assert_select 'input[name=?][value=?]', 'attachments[p0][token]', attachment.token
3006 assert_select 'input[name=?][value=?]', 'attachments[p0][token]', attachment.token
3007 assert_select 'input[name=?][value=?]', 'attachments[p0][filename]', 'testfile.txt'
3007 assert_select 'input[name=?][value=?]', 'attachments[p0][filename]', 'testfile.txt'
3008 end
3008 end
3009
3009
3010 def test_put_update_should_attach_saved_attachments
3010 def test_put_update_should_attach_saved_attachments
3011 set_tmp_attachments_directory
3011 set_tmp_attachments_directory
3012 attachment = Attachment.create!(:file => uploaded_test_file("testfile.txt", "text/plain"), :author_id => 2)
3012 attachment = Attachment.create!(:file => uploaded_test_file("testfile.txt", "text/plain"), :author_id => 2)
3013 @request.session[:user_id] = 2
3013 @request.session[:user_id] = 2
3014
3014
3015 assert_difference 'Journal.count' do
3015 assert_difference 'Journal.count' do
3016 assert_difference 'JournalDetail.count' do
3016 assert_difference 'JournalDetail.count' do
3017 assert_no_difference 'Attachment.count' do
3017 assert_no_difference 'Attachment.count' do
3018 put :update, :id => 1,
3018 put :update, :id => 1,
3019 :issue => {:notes => 'Attachment added'},
3019 :issue => {:notes => 'Attachment added'},
3020 :attachments => {'p0' => {'token' => attachment.token}}
3020 :attachments => {'p0' => {'token' => attachment.token}}
3021 assert_redirected_to '/issues/1'
3021 assert_redirected_to '/issues/1'
3022 end
3022 end
3023 end
3023 end
3024 end
3024 end
3025
3025
3026 attachment.reload
3026 attachment.reload
3027 assert_equal Issue.find(1), attachment.container
3027 assert_equal Issue.find(1), attachment.container
3028
3028
3029 journal = Journal.first(:order => 'id DESC')
3029 journal = Journal.first(:order => 'id DESC')
3030 assert_equal 1, journal.details.size
3030 assert_equal 1, journal.details.size
3031 assert_equal 'testfile.txt', journal.details.first.value
3031 assert_equal 'testfile.txt', journal.details.first.value
3032 end
3032 end
3033
3033
3034 def test_put_update_with_attachment_that_fails_to_save
3034 def test_put_update_with_attachment_that_fails_to_save
3035 set_tmp_attachments_directory
3035 set_tmp_attachments_directory
3036
3036
3037 # Delete all fixtured journals, a race condition can occur causing the wrong
3037 # Delete all fixtured journals, a race condition can occur causing the wrong
3038 # journal to get fetched in the next find.
3038 # journal to get fetched in the next find.
3039 Journal.delete_all
3039 Journal.delete_all
3040
3040
3041 # Mock out the unsaved attachment
3041 # Mock out the unsaved attachment
3042 Attachment.any_instance.stubs(:create).returns(Attachment.new)
3042 Attachment.any_instance.stubs(:create).returns(Attachment.new)
3043
3043
3044 # anonymous user
3044 # anonymous user
3045 put :update,
3045 put :update,
3046 :id => 1,
3046 :id => 1,
3047 :issue => {:notes => ''},
3047 :issue => {:notes => ''},
3048 :attachments => {'1' => {'file' => uploaded_test_file('testfile.txt', 'text/plain')}}
3048 :attachments => {'1' => {'file' => uploaded_test_file('testfile.txt', 'text/plain')}}
3049 assert_redirected_to :action => 'show', :id => '1'
3049 assert_redirected_to :action => 'show', :id => '1'
3050 assert_equal '1 file(s) could not be saved.', flash[:warning]
3050 assert_equal '1 file(s) could not be saved.', flash[:warning]
3051 end
3051 end
3052
3052
3053 def test_put_update_with_no_change
3053 def test_put_update_with_no_change
3054 issue = Issue.find(1)
3054 issue = Issue.find(1)
3055 issue.journals.clear
3055 issue.journals.clear
3056 ActionMailer::Base.deliveries.clear
3056 ActionMailer::Base.deliveries.clear
3057
3057
3058 put :update,
3058 put :update,
3059 :id => 1,
3059 :id => 1,
3060 :issue => {:notes => ''}
3060 :issue => {:notes => ''}
3061 assert_redirected_to :action => 'show', :id => '1'
3061 assert_redirected_to :action => 'show', :id => '1'
3062
3062
3063 issue.reload
3063 issue.reload
3064 assert issue.journals.empty?
3064 assert issue.journals.empty?
3065 # No email should be sent
3065 # No email should be sent
3066 assert ActionMailer::Base.deliveries.empty?
3066 assert ActionMailer::Base.deliveries.empty?
3067 end
3067 end
3068
3068
3069 def test_put_update_should_send_a_notification
3069 def test_put_update_should_send_a_notification
3070 @request.session[:user_id] = 2
3070 @request.session[:user_id] = 2
3071 ActionMailer::Base.deliveries.clear
3071 ActionMailer::Base.deliveries.clear
3072 issue = Issue.find(1)
3072 issue = Issue.find(1)
3073 old_subject = issue.subject
3073 old_subject = issue.subject
3074 new_subject = 'Subject modified by IssuesControllerTest#test_post_edit'
3074 new_subject = 'Subject modified by IssuesControllerTest#test_post_edit'
3075
3075
3076 put :update, :id => 1, :issue => {:subject => new_subject,
3076 put :update, :id => 1, :issue => {:subject => new_subject,
3077 :priority_id => '6',
3077 :priority_id => '6',
3078 :category_id => '1' # no change
3078 :category_id => '1' # no change
3079 }
3079 }
3080 assert_equal 1, ActionMailer::Base.deliveries.size
3080 assert_equal 1, ActionMailer::Base.deliveries.size
3081 end
3081 end
3082
3082
3083 def test_put_update_with_invalid_spent_time_hours_only
3083 def test_put_update_with_invalid_spent_time_hours_only
3084 @request.session[:user_id] = 2
3084 @request.session[:user_id] = 2
3085 notes = 'Note added by IssuesControllerTest#test_post_edit_with_invalid_spent_time'
3085 notes = 'Note added by IssuesControllerTest#test_post_edit_with_invalid_spent_time'
3086
3086
3087 assert_no_difference('Journal.count') do
3087 assert_no_difference('Journal.count') do
3088 put :update,
3088 put :update,
3089 :id => 1,
3089 :id => 1,
3090 :issue => {:notes => notes},
3090 :issue => {:notes => notes},
3091 :time_entry => {"comments"=>"", "activity_id"=>"", "hours"=>"2z"}
3091 :time_entry => {"comments"=>"", "activity_id"=>"", "hours"=>"2z"}
3092 end
3092 end
3093 assert_response :success
3093 assert_response :success
3094 assert_template 'edit'
3094 assert_template 'edit'
3095
3095
3096 assert_error_tag :descendant => {:content => /Activity can&#x27;t be blank/}
3096 assert_error_tag :descendant => {:content => /Activity can&#x27;t be blank/}
3097 assert_select 'textarea[name=?]', 'issue[notes]', :text => notes
3097 assert_select 'textarea[name=?]', 'issue[notes]', :text => notes
3098 assert_select 'input[name=?][value=?]', 'time_entry[hours]', '2z'
3098 assert_select 'input[name=?][value=?]', 'time_entry[hours]', '2z'
3099 end
3099 end
3100
3100
3101 def test_put_update_with_invalid_spent_time_comments_only
3101 def test_put_update_with_invalid_spent_time_comments_only
3102 @request.session[:user_id] = 2
3102 @request.session[:user_id] = 2
3103 notes = 'Note added by IssuesControllerTest#test_post_edit_with_invalid_spent_time'
3103 notes = 'Note added by IssuesControllerTest#test_post_edit_with_invalid_spent_time'
3104
3104
3105 assert_no_difference('Journal.count') do
3105 assert_no_difference('Journal.count') do
3106 put :update,
3106 put :update,
3107 :id => 1,
3107 :id => 1,
3108 :issue => {:notes => notes},
3108 :issue => {:notes => notes},
3109 :time_entry => {"comments"=>"this is my comment", "activity_id"=>"", "hours"=>""}
3109 :time_entry => {"comments"=>"this is my comment", "activity_id"=>"", "hours"=>""}
3110 end
3110 end
3111 assert_response :success
3111 assert_response :success
3112 assert_template 'edit'
3112 assert_template 'edit'
3113
3113
3114 assert_error_tag :descendant => {:content => /Activity can&#x27;t be blank/}
3114 assert_error_tag :descendant => {:content => /Activity can&#x27;t be blank/}
3115 assert_error_tag :descendant => {:content => /Hours can&#x27;t be blank/}
3115 assert_error_tag :descendant => {:content => /Hours can&#x27;t be blank/}
3116 assert_select 'textarea[name=?]', 'issue[notes]', :text => notes
3116 assert_select 'textarea[name=?]', 'issue[notes]', :text => notes
3117 assert_select 'input[name=?][value=?]', 'time_entry[comments]', 'this is my comment'
3117 assert_select 'input[name=?][value=?]', 'time_entry[comments]', 'this is my comment'
3118 end
3118 end
3119
3119
3120 def test_put_update_should_allow_fixed_version_to_be_set_to_a_subproject
3120 def test_put_update_should_allow_fixed_version_to_be_set_to_a_subproject
3121 issue = Issue.find(2)
3121 issue = Issue.find(2)
3122 @request.session[:user_id] = 2
3122 @request.session[:user_id] = 2
3123
3123
3124 put :update,
3124 put :update,
3125 :id => issue.id,
3125 :id => issue.id,
3126 :issue => {
3126 :issue => {
3127 :fixed_version_id => 4
3127 :fixed_version_id => 4
3128 }
3128 }
3129
3129
3130 assert_response :redirect
3130 assert_response :redirect
3131 issue.reload
3131 issue.reload
3132 assert_equal 4, issue.fixed_version_id
3132 assert_equal 4, issue.fixed_version_id
3133 assert_not_equal issue.project_id, issue.fixed_version.project_id
3133 assert_not_equal issue.project_id, issue.fixed_version.project_id
3134 end
3134 end
3135
3135
3136 def test_put_update_should_redirect_back_using_the_back_url_parameter
3136 def test_put_update_should_redirect_back_using_the_back_url_parameter
3137 issue = Issue.find(2)
3137 issue = Issue.find(2)
3138 @request.session[:user_id] = 2
3138 @request.session[:user_id] = 2
3139
3139
3140 put :update,
3140 put :update,
3141 :id => issue.id,
3141 :id => issue.id,
3142 :issue => {
3142 :issue => {
3143 :fixed_version_id => 4
3143 :fixed_version_id => 4
3144 },
3144 },
3145 :back_url => '/issues'
3145 :back_url => '/issues'
3146
3146
3147 assert_response :redirect
3147 assert_response :redirect
3148 assert_redirected_to '/issues'
3148 assert_redirected_to '/issues'
3149 end
3149 end
3150
3150
3151 def test_put_update_should_not_redirect_back_using_the_back_url_parameter_off_the_host
3151 def test_put_update_should_not_redirect_back_using_the_back_url_parameter_off_the_host
3152 issue = Issue.find(2)
3152 issue = Issue.find(2)
3153 @request.session[:user_id] = 2
3153 @request.session[:user_id] = 2
3154
3154
3155 put :update,
3155 put :update,
3156 :id => issue.id,
3156 :id => issue.id,
3157 :issue => {
3157 :issue => {
3158 :fixed_version_id => 4
3158 :fixed_version_id => 4
3159 },
3159 },
3160 :back_url => 'http://google.com'
3160 :back_url => 'http://google.com'
3161
3161
3162 assert_response :redirect
3162 assert_response :redirect
3163 assert_redirected_to :controller => 'issues', :action => 'show', :id => issue.id
3163 assert_redirected_to :controller => 'issues', :action => 'show', :id => issue.id
3164 end
3164 end
3165
3165
3166 def test_get_bulk_edit
3166 def test_get_bulk_edit
3167 @request.session[:user_id] = 2
3167 @request.session[:user_id] = 2
3168 get :bulk_edit, :ids => [1, 2]
3168 get :bulk_edit, :ids => [1, 2]
3169 assert_response :success
3169 assert_response :success
3170 assert_template 'bulk_edit'
3170 assert_template 'bulk_edit'
3171
3171
3172 assert_select 'ul#bulk-selection' do
3172 assert_select 'ul#bulk-selection' do
3173 assert_select 'li', 2
3173 assert_select 'li', 2
3174 assert_select 'li a', :text => 'Bug #1'
3174 assert_select 'li a', :text => 'Bug #1'
3175 end
3175 end
3176
3176
3177 assert_select 'form#bulk_edit_form[action=?]', '/issues/bulk_update' do
3177 assert_select 'form#bulk_edit_form[action=?]', '/issues/bulk_update' do
3178 assert_select 'input[name=?]', 'ids[]', 2
3178 assert_select 'input[name=?]', 'ids[]', 2
3179 assert_select 'input[name=?][value=1][type=hidden]', 'ids[]'
3179 assert_select 'input[name=?][value=1][type=hidden]', 'ids[]'
3180
3180
3181 assert_select 'select[name=?]', 'issue[project_id]'
3181 assert_select 'select[name=?]', 'issue[project_id]'
3182 assert_select 'input[name=?]', 'issue[parent_issue_id]'
3182 assert_select 'input[name=?]', 'issue[parent_issue_id]'
3183
3183
3184 # Project specific custom field, date type
3184 # Project specific custom field, date type
3185 field = CustomField.find(9)
3185 field = CustomField.find(9)
3186 assert !field.is_for_all?
3186 assert !field.is_for_all?
3187 assert_equal 'date', field.field_format
3187 assert_equal 'date', field.field_format
3188 assert_select 'input[name=?]', 'issue[custom_field_values][9]'
3188 assert_select 'input[name=?]', 'issue[custom_field_values][9]'
3189
3189
3190 # System wide custom field
3190 # System wide custom field
3191 assert CustomField.find(1).is_for_all?
3191 assert CustomField.find(1).is_for_all?
3192 assert_select 'select[name=?]', 'issue[custom_field_values][1]'
3192 assert_select 'select[name=?]', 'issue[custom_field_values][1]'
3193
3193
3194 # Be sure we don't display inactive IssuePriorities
3194 # Be sure we don't display inactive IssuePriorities
3195 assert ! IssuePriority.find(15).active?
3195 assert ! IssuePriority.find(15).active?
3196 assert_select 'select[name=?]', 'issue[priority_id]' do
3196 assert_select 'select[name=?]', 'issue[priority_id]' do
3197 assert_select 'option[value=15]', 0
3197 assert_select 'option[value=15]', 0
3198 end
3198 end
3199 end
3199 end
3200 end
3200 end
3201
3201
3202 def test_get_bulk_edit_on_different_projects
3202 def test_get_bulk_edit_on_different_projects
3203 @request.session[:user_id] = 2
3203 @request.session[:user_id] = 2
3204 get :bulk_edit, :ids => [1, 2, 6]
3204 get :bulk_edit, :ids => [1, 2, 6]
3205 assert_response :success
3205 assert_response :success
3206 assert_template 'bulk_edit'
3206 assert_template 'bulk_edit'
3207
3207
3208 # Can not set issues from different projects as children of an issue
3208 # Can not set issues from different projects as children of an issue
3209 assert_select 'input[name=?]', 'issue[parent_issue_id]', 0
3209 assert_select 'input[name=?]', 'issue[parent_issue_id]', 0
3210
3210
3211 # Project specific custom field, date type
3211 # Project specific custom field, date type
3212 field = CustomField.find(9)
3212 field = CustomField.find(9)
3213 assert !field.is_for_all?
3213 assert !field.is_for_all?
3214 assert !field.project_ids.include?(Issue.find(6).project_id)
3214 assert !field.project_ids.include?(Issue.find(6).project_id)
3215 assert_select 'input[name=?]', 'issue[custom_field_values][9]', 0
3215 assert_select 'input[name=?]', 'issue[custom_field_values][9]', 0
3216 end
3216 end
3217
3217
3218 def test_get_bulk_edit_with_user_custom_field
3218 def test_get_bulk_edit_with_user_custom_field
3219 field = IssueCustomField.create!(:name => 'Tester', :field_format => 'user', :is_for_all => true)
3219 field = IssueCustomField.create!(:name => 'Tester', :field_format => 'user', :is_for_all => true)
3220
3220
3221 @request.session[:user_id] = 2
3221 @request.session[:user_id] = 2
3222 get :bulk_edit, :ids => [1, 2]
3222 get :bulk_edit, :ids => [1, 2]
3223 assert_response :success
3223 assert_response :success
3224 assert_template 'bulk_edit'
3224 assert_template 'bulk_edit'
3225
3225
3226 assert_select 'select.user_cf[name=?]', "issue[custom_field_values][#{field.id}]" do
3226 assert_select 'select.user_cf[name=?]', "issue[custom_field_values][#{field.id}]" do
3227 assert_select 'option', Project.find(1).users.count + 2 # "no change" + "none" options
3227 assert_select 'option', Project.find(1).users.count + 2 # "no change" + "none" options
3228 end
3228 end
3229 end
3229 end
3230
3230
3231 def test_get_bulk_edit_with_version_custom_field
3231 def test_get_bulk_edit_with_version_custom_field
3232 field = IssueCustomField.create!(:name => 'Affected version', :field_format => 'version', :is_for_all => true)
3232 field = IssueCustomField.create!(:name => 'Affected version', :field_format => 'version', :is_for_all => true)
3233
3233
3234 @request.session[:user_id] = 2
3234 @request.session[:user_id] = 2
3235 get :bulk_edit, :ids => [1, 2]
3235 get :bulk_edit, :ids => [1, 2]
3236 assert_response :success
3236 assert_response :success
3237 assert_template 'bulk_edit'
3237 assert_template 'bulk_edit'
3238
3238
3239 assert_select 'select.version_cf[name=?]', "issue[custom_field_values][#{field.id}]" do
3239 assert_select 'select.version_cf[name=?]', "issue[custom_field_values][#{field.id}]" do
3240 assert_select 'option', Project.find(1).shared_versions.count + 2 # "no change" + "none" options
3240 assert_select 'option', Project.find(1).shared_versions.count + 2 # "no change" + "none" options
3241 end
3241 end
3242 end
3242 end
3243
3243
3244 def test_get_bulk_edit_with_multi_custom_field
3244 def test_get_bulk_edit_with_multi_custom_field
3245 field = CustomField.find(1)
3245 field = CustomField.find(1)
3246 field.update_attribute :multiple, true
3246 field.update_attribute :multiple, true
3247
3247
3248 @request.session[:user_id] = 2
3248 @request.session[:user_id] = 2
3249 get :bulk_edit, :ids => [1, 2]
3249 get :bulk_edit, :ids => [1, 2]
3250 assert_response :success
3250 assert_response :success
3251 assert_template 'bulk_edit'
3251 assert_template 'bulk_edit'
3252
3252
3253 assert_select 'select[name=?]', 'issue[custom_field_values][1][]' do
3253 assert_select 'select[name=?]', 'issue[custom_field_values][1][]' do
3254 assert_select 'option', field.possible_values.size + 1 # "none" options
3254 assert_select 'option', field.possible_values.size + 1 # "none" options
3255 end
3255 end
3256 end
3256 end
3257
3257
3258 def test_bulk_edit_should_only_propose_statuses_allowed_for_all_issues
3258 def test_bulk_edit_should_only_propose_statuses_allowed_for_all_issues
3259 WorkflowTransition.delete_all
3259 WorkflowTransition.delete_all
3260 WorkflowTransition.create!(:role_id => 1, :tracker_id => 1, :old_status_id => 1, :new_status_id => 1)
3260 WorkflowTransition.create!(:role_id => 1, :tracker_id => 1, :old_status_id => 1, :new_status_id => 1)
3261 WorkflowTransition.create!(:role_id => 1, :tracker_id => 1, :old_status_id => 1, :new_status_id => 3)
3261 WorkflowTransition.create!(:role_id => 1, :tracker_id => 1, :old_status_id => 1, :new_status_id => 3)
3262 WorkflowTransition.create!(:role_id => 1, :tracker_id => 1, :old_status_id => 1, :new_status_id => 4)
3262 WorkflowTransition.create!(:role_id => 1, :tracker_id => 1, :old_status_id => 1, :new_status_id => 4)
3263 WorkflowTransition.create!(:role_id => 1, :tracker_id => 2, :old_status_id => 2, :new_status_id => 1)
3263 WorkflowTransition.create!(:role_id => 1, :tracker_id => 2, :old_status_id => 2, :new_status_id => 1)
3264 WorkflowTransition.create!(:role_id => 1, :tracker_id => 2, :old_status_id => 2, :new_status_id => 3)
3264 WorkflowTransition.create!(:role_id => 1, :tracker_id => 2, :old_status_id => 2, :new_status_id => 3)
3265 WorkflowTransition.create!(:role_id => 1, :tracker_id => 2, :old_status_id => 2, :new_status_id => 5)
3265 WorkflowTransition.create!(:role_id => 1, :tracker_id => 2, :old_status_id => 2, :new_status_id => 5)
3266 @request.session[:user_id] = 2
3266 @request.session[:user_id] = 2
3267 get :bulk_edit, :ids => [1, 2]
3267 get :bulk_edit, :ids => [1, 2]
3268
3268
3269 assert_response :success
3269 assert_response :success
3270 statuses = assigns(:available_statuses)
3270 statuses = assigns(:available_statuses)
3271 assert_not_nil statuses
3271 assert_not_nil statuses
3272 assert_equal [1, 3], statuses.map(&:id).sort
3272 assert_equal [1, 3], statuses.map(&:id).sort
3273
3273
3274 assert_select 'select[name=?]', 'issue[status_id]' do
3274 assert_select 'select[name=?]', 'issue[status_id]' do
3275 assert_select 'option', 3 # 2 statuses + "no change" option
3275 assert_select 'option', 3 # 2 statuses + "no change" option
3276 end
3276 end
3277 end
3277 end
3278
3278
3279 def test_bulk_edit_should_propose_target_project_open_shared_versions
3279 def test_bulk_edit_should_propose_target_project_open_shared_versions
3280 @request.session[:user_id] = 2
3280 @request.session[:user_id] = 2
3281 post :bulk_edit, :ids => [1, 2, 6], :issue => {:project_id => 1}
3281 post :bulk_edit, :ids => [1, 2, 6], :issue => {:project_id => 1}
3282 assert_response :success
3282 assert_response :success
3283 assert_template 'bulk_edit'
3283 assert_template 'bulk_edit'
3284 assert_equal Project.find(1).shared_versions.open.all.sort, assigns(:versions).sort
3284 assert_equal Project.find(1).shared_versions.open.all.sort, assigns(:versions).sort
3285
3285
3286 assert_select 'select[name=?]', 'issue[fixed_version_id]' do
3286 assert_select 'select[name=?]', 'issue[fixed_version_id]' do
3287 assert_select 'option', :text => '2.0'
3287 assert_select 'option', :text => '2.0'
3288 end
3288 end
3289 end
3289 end
3290
3290
3291 def test_bulk_edit_should_propose_target_project_categories
3291 def test_bulk_edit_should_propose_target_project_categories
3292 @request.session[:user_id] = 2
3292 @request.session[:user_id] = 2
3293 post :bulk_edit, :ids => [1, 2, 6], :issue => {:project_id => 1}
3293 post :bulk_edit, :ids => [1, 2, 6], :issue => {:project_id => 1}
3294 assert_response :success
3294 assert_response :success
3295 assert_template 'bulk_edit'
3295 assert_template 'bulk_edit'
3296 assert_equal Project.find(1).issue_categories.sort, assigns(:categories).sort
3296 assert_equal Project.find(1).issue_categories.sort, assigns(:categories).sort
3297
3297
3298 assert_select 'select[name=?]', 'issue[category_id]' do
3298 assert_select 'select[name=?]', 'issue[category_id]' do
3299 assert_select 'option', :text => 'Recipes'
3299 assert_select 'option', :text => 'Recipes'
3300 end
3300 end
3301 end
3301 end
3302
3302
3303 def test_bulk_update
3303 def test_bulk_update
3304 @request.session[:user_id] = 2
3304 @request.session[:user_id] = 2
3305 # update issues priority
3305 # update issues priority
3306 post :bulk_update, :ids => [1, 2], :notes => 'Bulk editing',
3306 post :bulk_update, :ids => [1, 2], :notes => 'Bulk editing',
3307 :issue => {:priority_id => 7,
3307 :issue => {:priority_id => 7,
3308 :assigned_to_id => '',
3308 :assigned_to_id => '',
3309 :custom_field_values => {'2' => ''}}
3309 :custom_field_values => {'2' => ''}}
3310
3310
3311 assert_response 302
3311 assert_response 302
3312 # check that the issues were updated
3312 # check that the issues were updated
3313 assert_equal [7, 7], Issue.find_all_by_id([1, 2]).collect {|i| i.priority.id}
3313 assert_equal [7, 7], Issue.find_all_by_id([1, 2]).collect {|i| i.priority.id}
3314
3314
3315 issue = Issue.find(1)
3315 issue = Issue.find(1)
3316 journal = issue.journals.reorder('created_on DESC').first
3316 journal = issue.journals.reorder('created_on DESC').first
3317 assert_equal '125', issue.custom_value_for(2).value
3317 assert_equal '125', issue.custom_value_for(2).value
3318 assert_equal 'Bulk editing', journal.notes
3318 assert_equal 'Bulk editing', journal.notes
3319 assert_equal 1, journal.details.size
3319 assert_equal 1, journal.details.size
3320 end
3320 end
3321
3321
3322 def test_bulk_update_with_group_assignee
3322 def test_bulk_update_with_group_assignee
3323 group = Group.find(11)
3323 group = Group.find(11)
3324 project = Project.find(1)
3324 project = Project.find(1)
3325 project.members << Member.new(:principal => group, :roles => [Role.givable.first])
3325 project.members << Member.new(:principal => group, :roles => [Role.givable.first])
3326
3326
3327 @request.session[:user_id] = 2
3327 @request.session[:user_id] = 2
3328 # update issues assignee
3328 # update issues assignee
3329 post :bulk_update, :ids => [1, 2], :notes => 'Bulk editing',
3329 post :bulk_update, :ids => [1, 2], :notes => 'Bulk editing',
3330 :issue => {:priority_id => '',
3330 :issue => {:priority_id => '',
3331 :assigned_to_id => group.id,
3331 :assigned_to_id => group.id,
3332 :custom_field_values => {'2' => ''}}
3332 :custom_field_values => {'2' => ''}}
3333
3333
3334 assert_response 302
3334 assert_response 302
3335 assert_equal [group, group], Issue.find_all_by_id([1, 2]).collect {|i| i.assigned_to}
3335 assert_equal [group, group], Issue.find_all_by_id([1, 2]).collect {|i| i.assigned_to}
3336 end
3336 end
3337
3337
3338 def test_bulk_update_on_different_projects
3338 def test_bulk_update_on_different_projects
3339 @request.session[:user_id] = 2
3339 @request.session[:user_id] = 2
3340 # update issues priority
3340 # update issues priority
3341 post :bulk_update, :ids => [1, 2, 6], :notes => 'Bulk editing',
3341 post :bulk_update, :ids => [1, 2, 6], :notes => 'Bulk editing',
3342 :issue => {:priority_id => 7,
3342 :issue => {:priority_id => 7,
3343 :assigned_to_id => '',
3343 :assigned_to_id => '',
3344 :custom_field_values => {'2' => ''}}
3344 :custom_field_values => {'2' => ''}}
3345
3345
3346 assert_response 302
3346 assert_response 302
3347 # check that the issues were updated
3347 # check that the issues were updated
3348 assert_equal [7, 7, 7], Issue.find([1,2,6]).map(&:priority_id)
3348 assert_equal [7, 7, 7], Issue.find([1,2,6]).map(&:priority_id)
3349
3349
3350 issue = Issue.find(1)
3350 issue = Issue.find(1)
3351 journal = issue.journals.reorder('created_on DESC').first
3351 journal = issue.journals.reorder('created_on DESC').first
3352 assert_equal '125', issue.custom_value_for(2).value
3352 assert_equal '125', issue.custom_value_for(2).value
3353 assert_equal 'Bulk editing', journal.notes
3353 assert_equal 'Bulk editing', journal.notes
3354 assert_equal 1, journal.details.size
3354 assert_equal 1, journal.details.size
3355 end
3355 end
3356
3356
3357 def test_bulk_update_on_different_projects_without_rights
3357 def test_bulk_update_on_different_projects_without_rights
3358 @request.session[:user_id] = 3
3358 @request.session[:user_id] = 3
3359 user = User.find(3)
3359 user = User.find(3)
3360 action = { :controller => "issues", :action => "bulk_update" }
3360 action = { :controller => "issues", :action => "bulk_update" }
3361 assert user.allowed_to?(action, Issue.find(1).project)
3361 assert user.allowed_to?(action, Issue.find(1).project)
3362 assert ! user.allowed_to?(action, Issue.find(6).project)
3362 assert ! user.allowed_to?(action, Issue.find(6).project)
3363 post :bulk_update, :ids => [1, 6], :notes => 'Bulk should fail',
3363 post :bulk_update, :ids => [1, 6], :notes => 'Bulk should fail',
3364 :issue => {:priority_id => 7,
3364 :issue => {:priority_id => 7,
3365 :assigned_to_id => '',
3365 :assigned_to_id => '',
3366 :custom_field_values => {'2' => ''}}
3366 :custom_field_values => {'2' => ''}}
3367 assert_response 403
3367 assert_response 403
3368 assert_not_equal "Bulk should fail", Journal.last.notes
3368 assert_not_equal "Bulk should fail", Journal.last.notes
3369 end
3369 end
3370
3370
3371 def test_bullk_update_should_send_a_notification
3371 def test_bullk_update_should_send_a_notification
3372 @request.session[:user_id] = 2
3372 @request.session[:user_id] = 2
3373 ActionMailer::Base.deliveries.clear
3373 ActionMailer::Base.deliveries.clear
3374 post(:bulk_update,
3374 post(:bulk_update,
3375 {
3375 {
3376 :ids => [1, 2],
3376 :ids => [1, 2],
3377 :notes => 'Bulk editing',
3377 :notes => 'Bulk editing',
3378 :issue => {
3378 :issue => {
3379 :priority_id => 7,
3379 :priority_id => 7,
3380 :assigned_to_id => '',
3380 :assigned_to_id => '',
3381 :custom_field_values => {'2' => ''}
3381 :custom_field_values => {'2' => ''}
3382 }
3382 }
3383 })
3383 })
3384
3384
3385 assert_response 302
3385 assert_response 302
3386 assert_equal 2, ActionMailer::Base.deliveries.size
3386 assert_equal 2, ActionMailer::Base.deliveries.size
3387 end
3387 end
3388
3388
3389 def test_bulk_update_project
3389 def test_bulk_update_project
3390 @request.session[:user_id] = 2
3390 @request.session[:user_id] = 2
3391 post :bulk_update, :ids => [1, 2], :issue => {:project_id => '2'}
3391 post :bulk_update, :ids => [1, 2], :issue => {:project_id => '2'}
3392 assert_redirected_to :controller => 'issues', :action => 'index', :project_id => 'ecookbook'
3392 assert_redirected_to :controller => 'issues', :action => 'index', :project_id => 'ecookbook'
3393 # Issues moved to project 2
3393 # Issues moved to project 2
3394 assert_equal 2, Issue.find(1).project_id
3394 assert_equal 2, Issue.find(1).project_id
3395 assert_equal 2, Issue.find(2).project_id
3395 assert_equal 2, Issue.find(2).project_id
3396 # No tracker change
3396 # No tracker change
3397 assert_equal 1, Issue.find(1).tracker_id
3397 assert_equal 1, Issue.find(1).tracker_id
3398 assert_equal 2, Issue.find(2).tracker_id
3398 assert_equal 2, Issue.find(2).tracker_id
3399 end
3399 end
3400
3400
3401 def test_bulk_update_project_on_single_issue_should_follow_when_needed
3401 def test_bulk_update_project_on_single_issue_should_follow_when_needed
3402 @request.session[:user_id] = 2
3402 @request.session[:user_id] = 2
3403 post :bulk_update, :id => 1, :issue => {:project_id => '2'}, :follow => '1'
3403 post :bulk_update, :id => 1, :issue => {:project_id => '2'}, :follow => '1'
3404 assert_redirected_to '/issues/1'
3404 assert_redirected_to '/issues/1'
3405 end
3405 end
3406
3406
3407 def test_bulk_update_project_on_multiple_issues_should_follow_when_needed
3407 def test_bulk_update_project_on_multiple_issues_should_follow_when_needed
3408 @request.session[:user_id] = 2
3408 @request.session[:user_id] = 2
3409 post :bulk_update, :id => [1, 2], :issue => {:project_id => '2'}, :follow => '1'
3409 post :bulk_update, :id => [1, 2], :issue => {:project_id => '2'}, :follow => '1'
3410 assert_redirected_to '/projects/onlinestore/issues'
3410 assert_redirected_to '/projects/onlinestore/issues'
3411 end
3411 end
3412
3412
3413 def test_bulk_update_tracker
3413 def test_bulk_update_tracker
3414 @request.session[:user_id] = 2
3414 @request.session[:user_id] = 2
3415 post :bulk_update, :ids => [1, 2], :issue => {:tracker_id => '2'}
3415 post :bulk_update, :ids => [1, 2], :issue => {:tracker_id => '2'}
3416 assert_redirected_to :controller => 'issues', :action => 'index', :project_id => 'ecookbook'
3416 assert_redirected_to :controller => 'issues', :action => 'index', :project_id => 'ecookbook'
3417 assert_equal 2, Issue.find(1).tracker_id
3417 assert_equal 2, Issue.find(1).tracker_id
3418 assert_equal 2, Issue.find(2).tracker_id
3418 assert_equal 2, Issue.find(2).tracker_id
3419 end
3419 end
3420
3420
3421 def test_bulk_update_status
3421 def test_bulk_update_status
3422 @request.session[:user_id] = 2
3422 @request.session[:user_id] = 2
3423 # update issues priority
3423 # update issues priority
3424 post :bulk_update, :ids => [1, 2], :notes => 'Bulk editing status',
3424 post :bulk_update, :ids => [1, 2], :notes => 'Bulk editing status',
3425 :issue => {:priority_id => '',
3425 :issue => {:priority_id => '',
3426 :assigned_to_id => '',
3426 :assigned_to_id => '',
3427 :status_id => '5'}
3427 :status_id => '5'}
3428
3428
3429 assert_response 302
3429 assert_response 302
3430 issue = Issue.find(1)
3430 issue = Issue.find(1)
3431 assert issue.closed?
3431 assert issue.closed?
3432 end
3432 end
3433
3433
3434 def test_bulk_update_priority
3434 def test_bulk_update_priority
3435 @request.session[:user_id] = 2
3435 @request.session[:user_id] = 2
3436 post :bulk_update, :ids => [1, 2], :issue => {:priority_id => 6}
3436 post :bulk_update, :ids => [1, 2], :issue => {:priority_id => 6}
3437
3437
3438 assert_redirected_to :controller => 'issues', :action => 'index', :project_id => 'ecookbook'
3438 assert_redirected_to :controller => 'issues', :action => 'index', :project_id => 'ecookbook'
3439 assert_equal 6, Issue.find(1).priority_id
3439 assert_equal 6, Issue.find(1).priority_id
3440 assert_equal 6, Issue.find(2).priority_id
3440 assert_equal 6, Issue.find(2).priority_id
3441 end
3441 end
3442
3442
3443 def test_bulk_update_with_notes
3443 def test_bulk_update_with_notes
3444 @request.session[:user_id] = 2
3444 @request.session[:user_id] = 2
3445 post :bulk_update, :ids => [1, 2], :notes => 'Moving two issues'
3445 post :bulk_update, :ids => [1, 2], :notes => 'Moving two issues'
3446
3446
3447 assert_redirected_to :controller => 'issues', :action => 'index', :project_id => 'ecookbook'
3447 assert_redirected_to :controller => 'issues', :action => 'index', :project_id => 'ecookbook'
3448 assert_equal 'Moving two issues', Issue.find(1).journals.sort_by(&:id).last.notes
3448 assert_equal 'Moving two issues', Issue.find(1).journals.sort_by(&:id).last.notes
3449 assert_equal 'Moving two issues', Issue.find(2).journals.sort_by(&:id).last.notes
3449 assert_equal 'Moving two issues', Issue.find(2).journals.sort_by(&:id).last.notes
3450 end
3450 end
3451
3451
3452 def test_bulk_update_parent_id
3452 def test_bulk_update_parent_id
3453 @request.session[:user_id] = 2
3453 @request.session[:user_id] = 2
3454 post :bulk_update, :ids => [1, 3],
3454 post :bulk_update, :ids => [1, 3],
3455 :notes => 'Bulk editing parent',
3455 :notes => 'Bulk editing parent',
3456 :issue => {:priority_id => '', :assigned_to_id => '', :status_id => '', :parent_issue_id => '2'}
3456 :issue => {:priority_id => '', :assigned_to_id => '', :status_id => '', :parent_issue_id => '2'}
3457
3457
3458 assert_response 302
3458 assert_response 302
3459 parent = Issue.find(2)
3459 parent = Issue.find(2)
3460 assert_equal parent.id, Issue.find(1).parent_id
3460 assert_equal parent.id, Issue.find(1).parent_id
3461 assert_equal parent.id, Issue.find(3).parent_id
3461 assert_equal parent.id, Issue.find(3).parent_id
3462 assert_equal [1, 3], parent.children.collect(&:id).sort
3462 assert_equal [1, 3], parent.children.collect(&:id).sort
3463 end
3463 end
3464
3464
3465 def test_bulk_update_custom_field
3465 def test_bulk_update_custom_field
3466 @request.session[:user_id] = 2
3466 @request.session[:user_id] = 2
3467 # update issues priority
3467 # update issues priority
3468 post :bulk_update, :ids => [1, 2], :notes => 'Bulk editing custom field',
3468 post :bulk_update, :ids => [1, 2], :notes => 'Bulk editing custom field',
3469 :issue => {:priority_id => '',
3469 :issue => {:priority_id => '',
3470 :assigned_to_id => '',
3470 :assigned_to_id => '',
3471 :custom_field_values => {'2' => '777'}}
3471 :custom_field_values => {'2' => '777'}}
3472
3472
3473 assert_response 302
3473 assert_response 302
3474
3474
3475 issue = Issue.find(1)
3475 issue = Issue.find(1)
3476 journal = issue.journals.reorder('created_on DESC').first
3476 journal = issue.journals.reorder('created_on DESC').first
3477 assert_equal '777', issue.custom_value_for(2).value
3477 assert_equal '777', issue.custom_value_for(2).value
3478 assert_equal 1, journal.details.size
3478 assert_equal 1, journal.details.size
3479 assert_equal '125', journal.details.first.old_value
3479 assert_equal '125', journal.details.first.old_value
3480 assert_equal '777', journal.details.first.value
3480 assert_equal '777', journal.details.first.value
3481 end
3481 end
3482
3482
3483 def test_bulk_update_custom_field_to_blank
3483 def test_bulk_update_custom_field_to_blank
3484 @request.session[:user_id] = 2
3484 @request.session[:user_id] = 2
3485 post :bulk_update, :ids => [1, 3], :notes => 'Bulk editing custom field',
3485 post :bulk_update, :ids => [1, 3], :notes => 'Bulk editing custom field',
3486 :issue => {:priority_id => '',
3486 :issue => {:priority_id => '',
3487 :assigned_to_id => '',
3487 :assigned_to_id => '',
3488 :custom_field_values => {'1' => '__none__'}}
3488 :custom_field_values => {'1' => '__none__'}}
3489 assert_response 302
3489 assert_response 302
3490 assert_equal '', Issue.find(1).custom_field_value(1)
3490 assert_equal '', Issue.find(1).custom_field_value(1)
3491 assert_equal '', Issue.find(3).custom_field_value(1)
3491 assert_equal '', Issue.find(3).custom_field_value(1)
3492 end
3492 end
3493
3493
3494 def test_bulk_update_multi_custom_field
3494 def test_bulk_update_multi_custom_field
3495 field = CustomField.find(1)
3495 field = CustomField.find(1)
3496 field.update_attribute :multiple, true
3496 field.update_attribute :multiple, true
3497
3497
3498 @request.session[:user_id] = 2
3498 @request.session[:user_id] = 2
3499 post :bulk_update, :ids => [1, 2, 3], :notes => 'Bulk editing multi custom field',
3499 post :bulk_update, :ids => [1, 2, 3], :notes => 'Bulk editing multi custom field',
3500 :issue => {:priority_id => '',
3500 :issue => {:priority_id => '',
3501 :assigned_to_id => '',
3501 :assigned_to_id => '',
3502 :custom_field_values => {'1' => ['MySQL', 'Oracle']}}
3502 :custom_field_values => {'1' => ['MySQL', 'Oracle']}}
3503
3503
3504 assert_response 302
3504 assert_response 302
3505
3505
3506 assert_equal ['MySQL', 'Oracle'], Issue.find(1).custom_field_value(1).sort
3506 assert_equal ['MySQL', 'Oracle'], Issue.find(1).custom_field_value(1).sort
3507 assert_equal ['MySQL', 'Oracle'], Issue.find(3).custom_field_value(1).sort
3507 assert_equal ['MySQL', 'Oracle'], Issue.find(3).custom_field_value(1).sort
3508 # the custom field is not associated with the issue tracker
3508 # the custom field is not associated with the issue tracker
3509 assert_nil Issue.find(2).custom_field_value(1)
3509 assert_nil Issue.find(2).custom_field_value(1)
3510 end
3510 end
3511
3511
3512 def test_bulk_update_multi_custom_field_to_blank
3512 def test_bulk_update_multi_custom_field_to_blank
3513 field = CustomField.find(1)
3513 field = CustomField.find(1)
3514 field.update_attribute :multiple, true
3514 field.update_attribute :multiple, true
3515
3515
3516 @request.session[:user_id] = 2
3516 @request.session[:user_id] = 2
3517 post :bulk_update, :ids => [1, 3], :notes => 'Bulk editing multi custom field',
3517 post :bulk_update, :ids => [1, 3], :notes => 'Bulk editing multi custom field',
3518 :issue => {:priority_id => '',
3518 :issue => {:priority_id => '',
3519 :assigned_to_id => '',
3519 :assigned_to_id => '',
3520 :custom_field_values => {'1' => ['__none__']}}
3520 :custom_field_values => {'1' => ['__none__']}}
3521 assert_response 302
3521 assert_response 302
3522 assert_equal [''], Issue.find(1).custom_field_value(1)
3522 assert_equal [''], Issue.find(1).custom_field_value(1)
3523 assert_equal [''], Issue.find(3).custom_field_value(1)
3523 assert_equal [''], Issue.find(3).custom_field_value(1)
3524 end
3524 end
3525
3525
3526 def test_bulk_update_unassign
3526 def test_bulk_update_unassign
3527 assert_not_nil Issue.find(2).assigned_to
3527 assert_not_nil Issue.find(2).assigned_to
3528 @request.session[:user_id] = 2
3528 @request.session[:user_id] = 2
3529 # unassign issues
3529 # unassign issues
3530 post :bulk_update, :ids => [1, 2], :notes => 'Bulk unassigning', :issue => {:assigned_to_id => 'none'}
3530 post :bulk_update, :ids => [1, 2], :notes => 'Bulk unassigning', :issue => {:assigned_to_id => 'none'}
3531 assert_response 302
3531 assert_response 302
3532 # check that the issues were updated
3532 # check that the issues were updated
3533 assert_nil Issue.find(2).assigned_to
3533 assert_nil Issue.find(2).assigned_to
3534 end
3534 end
3535
3535
3536 def test_post_bulk_update_should_allow_fixed_version_to_be_set_to_a_subproject
3536 def test_post_bulk_update_should_allow_fixed_version_to_be_set_to_a_subproject
3537 @request.session[:user_id] = 2
3537 @request.session[:user_id] = 2
3538
3538
3539 post :bulk_update, :ids => [1,2], :issue => {:fixed_version_id => 4}
3539 post :bulk_update, :ids => [1,2], :issue => {:fixed_version_id => 4}
3540
3540
3541 assert_response :redirect
3541 assert_response :redirect
3542 issues = Issue.find([1,2])
3542 issues = Issue.find([1,2])
3543 issues.each do |issue|
3543 issues.each do |issue|
3544 assert_equal 4, issue.fixed_version_id
3544 assert_equal 4, issue.fixed_version_id
3545 assert_not_equal issue.project_id, issue.fixed_version.project_id
3545 assert_not_equal issue.project_id, issue.fixed_version.project_id
3546 end
3546 end
3547 end
3547 end
3548
3548
3549 def test_post_bulk_update_should_redirect_back_using_the_back_url_parameter
3549 def test_post_bulk_update_should_redirect_back_using_the_back_url_parameter
3550 @request.session[:user_id] = 2
3550 @request.session[:user_id] = 2
3551 post :bulk_update, :ids => [1,2], :back_url => '/issues'
3551 post :bulk_update, :ids => [1,2], :back_url => '/issues'
3552
3552
3553 assert_response :redirect
3553 assert_response :redirect
3554 assert_redirected_to '/issues'
3554 assert_redirected_to '/issues'
3555 end
3555 end
3556
3556
3557 def test_post_bulk_update_should_not_redirect_back_using_the_back_url_parameter_off_the_host
3557 def test_post_bulk_update_should_not_redirect_back_using_the_back_url_parameter_off_the_host
3558 @request.session[:user_id] = 2
3558 @request.session[:user_id] = 2
3559 post :bulk_update, :ids => [1,2], :back_url => 'http://google.com'
3559 post :bulk_update, :ids => [1,2], :back_url => 'http://google.com'
3560
3560
3561 assert_response :redirect
3561 assert_response :redirect
3562 assert_redirected_to :controller => 'issues', :action => 'index', :project_id => Project.find(1).identifier
3562 assert_redirected_to :controller => 'issues', :action => 'index', :project_id => Project.find(1).identifier
3563 end
3563 end
3564
3564
3565 def test_bulk_update_with_failure_should_set_flash
3565 def test_bulk_update_with_failure_should_set_flash
3566 @request.session[:user_id] = 2
3566 @request.session[:user_id] = 2
3567 Issue.update_all("subject = ''", "id = 2") # Make it invalid
3567 Issue.update_all("subject = ''", "id = 2") # Make it invalid
3568 post :bulk_update, :ids => [1, 2], :issue => {:priority_id => 6}
3568 post :bulk_update, :ids => [1, 2], :issue => {:priority_id => 6}
3569
3569
3570 assert_redirected_to :controller => 'issues', :action => 'index', :project_id => 'ecookbook'
3570 assert_redirected_to :controller => 'issues', :action => 'index', :project_id => 'ecookbook'
3571 assert_equal 'Failed to save 1 issue(s) on 2 selected: #2.', flash[:error]
3571 assert_equal 'Failed to save 1 issue(s) on 2 selected: #2.', flash[:error]
3572 end
3572 end
3573
3573
3574 def test_get_bulk_copy
3574 def test_get_bulk_copy
3575 @request.session[:user_id] = 2
3575 @request.session[:user_id] = 2
3576 get :bulk_edit, :ids => [1, 2, 3], :copy => '1'
3576 get :bulk_edit, :ids => [1, 2, 3], :copy => '1'
3577 assert_response :success
3577 assert_response :success
3578 assert_template 'bulk_edit'
3578 assert_template 'bulk_edit'
3579
3579
3580 issues = assigns(:issues)
3580 issues = assigns(:issues)
3581 assert_not_nil issues
3581 assert_not_nil issues
3582 assert_equal [1, 2, 3], issues.map(&:id).sort
3582 assert_equal [1, 2, 3], issues.map(&:id).sort
3583
3583
3584 assert_select 'input[name=copy_attachments]'
3584 assert_select 'input[name=copy_attachments]'
3585 end
3585 end
3586
3586
3587 def test_bulk_copy_to_another_project
3587 def test_bulk_copy_to_another_project
3588 @request.session[:user_id] = 2
3588 @request.session[:user_id] = 2
3589 assert_difference 'Issue.count', 2 do
3589 assert_difference 'Issue.count', 2 do
3590 assert_no_difference 'Project.find(1).issues.count' do
3590 assert_no_difference 'Project.find(1).issues.count' do
3591 post :bulk_update, :ids => [1, 2], :issue => {:project_id => '2'}, :copy => '1'
3591 post :bulk_update, :ids => [1, 2], :issue => {:project_id => '2'}, :copy => '1'
3592 end
3592 end
3593 end
3593 end
3594 assert_redirected_to '/projects/ecookbook/issues'
3594 assert_redirected_to '/projects/ecookbook/issues'
3595
3595
3596 copies = Issue.all(:order => 'id DESC', :limit => issues.size)
3596 copies = Issue.all(:order => 'id DESC', :limit => issues.size)
3597 copies.each do |copy|
3597 copies.each do |copy|
3598 assert_equal 2, copy.project_id
3598 assert_equal 2, copy.project_id
3599 end
3599 end
3600 end
3600 end
3601
3601
3602 def test_bulk_copy_should_allow_not_changing_the_issue_attributes
3602 def test_bulk_copy_should_allow_not_changing_the_issue_attributes
3603 @request.session[:user_id] = 2
3603 @request.session[:user_id] = 2
3604 issues = [
3604 issues = [
3605 Issue.create!(:project_id => 1, :tracker_id => 1, :status_id => 1, :priority_id => 2, :subject => 'issue 1', :author_id => 1, :assigned_to_id => nil),
3605 Issue.create!(:project_id => 1, :tracker_id => 1, :status_id => 1, :priority_id => 2, :subject => 'issue 1', :author_id => 1, :assigned_to_id => nil),
3606 Issue.create!(:project_id => 2, :tracker_id => 3, :status_id => 2, :priority_id => 1, :subject => 'issue 2', :author_id => 2, :assigned_to_id => 3)
3606 Issue.create!(:project_id => 2, :tracker_id => 3, :status_id => 2, :priority_id => 1, :subject => 'issue 2', :author_id => 2, :assigned_to_id => 3)
3607 ]
3607 ]
3608
3608
3609 assert_difference 'Issue.count', issues.size do
3609 assert_difference 'Issue.count', issues.size do
3610 post :bulk_update, :ids => issues.map(&:id), :copy => '1',
3610 post :bulk_update, :ids => issues.map(&:id), :copy => '1',
3611 :issue => {
3611 :issue => {
3612 :project_id => '', :tracker_id => '', :assigned_to_id => '',
3612 :project_id => '', :tracker_id => '', :assigned_to_id => '',
3613 :status_id => '', :start_date => '', :due_date => ''
3613 :status_id => '', :start_date => '', :due_date => ''
3614 }
3614 }
3615 end
3615 end
3616
3616
3617 copies = Issue.all(:order => 'id DESC', :limit => issues.size)
3617 copies = Issue.all(:order => 'id DESC', :limit => issues.size)
3618 issues.each do |orig|
3618 issues.each do |orig|
3619 copy = copies.detect {|c| c.subject == orig.subject}
3619 copy = copies.detect {|c| c.subject == orig.subject}
3620 assert_not_nil copy
3620 assert_not_nil copy
3621 assert_equal orig.project_id, copy.project_id
3621 assert_equal orig.project_id, copy.project_id
3622 assert_equal orig.tracker_id, copy.tracker_id
3622 assert_equal orig.tracker_id, copy.tracker_id
3623 assert_equal orig.status_id, copy.status_id
3623 assert_equal orig.status_id, copy.status_id
3624 assert_equal orig.assigned_to_id, copy.assigned_to_id
3624 assert_equal orig.assigned_to_id, copy.assigned_to_id
3625 assert_equal orig.priority_id, copy.priority_id
3625 assert_equal orig.priority_id, copy.priority_id
3626 end
3626 end
3627 end
3627 end
3628
3628
3629 def test_bulk_copy_should_allow_changing_the_issue_attributes
3629 def test_bulk_copy_should_allow_changing_the_issue_attributes
3630 # Fixes random test failure with Mysql
3630 # Fixes random test failure with Mysql
3631 # where Issue.all(:limit => 2, :order => 'id desc', :conditions => {:project_id => 2})
3631 # where Issue.all(:limit => 2, :order => 'id desc', :conditions => {:project_id => 2})
3632 # doesn't return the expected results
3632 # doesn't return the expected results
3633 Issue.delete_all("project_id=2")
3633 Issue.delete_all("project_id=2")
3634
3634
3635 @request.session[:user_id] = 2
3635 @request.session[:user_id] = 2
3636 assert_difference 'Issue.count', 2 do
3636 assert_difference 'Issue.count', 2 do
3637 assert_no_difference 'Project.find(1).issues.count' do
3637 assert_no_difference 'Project.find(1).issues.count' do
3638 post :bulk_update, :ids => [1, 2], :copy => '1',
3638 post :bulk_update, :ids => [1, 2], :copy => '1',
3639 :issue => {
3639 :issue => {
3640 :project_id => '2', :tracker_id => '', :assigned_to_id => '4',
3640 :project_id => '2', :tracker_id => '', :assigned_to_id => '4',
3641 :status_id => '1', :start_date => '2009-12-01', :due_date => '2009-12-31'
3641 :status_id => '1', :start_date => '2009-12-01', :due_date => '2009-12-31'
3642 }
3642 }
3643 end
3643 end
3644 end
3644 end
3645
3645
3646 copied_issues = Issue.all(:limit => 2, :order => 'id desc', :conditions => {:project_id => 2})
3646 copied_issues = Issue.all(:limit => 2, :order => 'id desc', :conditions => {:project_id => 2})
3647 assert_equal 2, copied_issues.size
3647 assert_equal 2, copied_issues.size
3648 copied_issues.each do |issue|
3648 copied_issues.each do |issue|
3649 assert_equal 2, issue.project_id, "Project is incorrect"
3649 assert_equal 2, issue.project_id, "Project is incorrect"
3650 assert_equal 4, issue.assigned_to_id, "Assigned to is incorrect"
3650 assert_equal 4, issue.assigned_to_id, "Assigned to is incorrect"
3651 assert_equal 1, issue.status_id, "Status is incorrect"
3651 assert_equal 1, issue.status_id, "Status is incorrect"
3652 assert_equal '2009-12-01', issue.start_date.to_s, "Start date is incorrect"
3652 assert_equal '2009-12-01', issue.start_date.to_s, "Start date is incorrect"
3653 assert_equal '2009-12-31', issue.due_date.to_s, "Due date is incorrect"
3653 assert_equal '2009-12-31', issue.due_date.to_s, "Due date is incorrect"
3654 end
3654 end
3655 end
3655 end
3656
3656
3657 def test_bulk_copy_should_allow_adding_a_note
3657 def test_bulk_copy_should_allow_adding_a_note
3658 @request.session[:user_id] = 2
3658 @request.session[:user_id] = 2
3659 assert_difference 'Issue.count', 1 do
3659 assert_difference 'Issue.count', 1 do
3660 post :bulk_update, :ids => [1], :copy => '1',
3660 post :bulk_update, :ids => [1], :copy => '1',
3661 :notes => 'Copying one issue',
3661 :notes => 'Copying one issue',
3662 :issue => {
3662 :issue => {
3663 :project_id => '', :tracker_id => '', :assigned_to_id => '4',
3663 :project_id => '', :tracker_id => '', :assigned_to_id => '4',
3664 :status_id => '3', :start_date => '2009-12-01', :due_date => '2009-12-31'
3664 :status_id => '3', :start_date => '2009-12-01', :due_date => '2009-12-31'
3665 }
3665 }
3666 end
3666 end
3667
3667
3668 issue = Issue.first(:order => 'id DESC')
3668 issue = Issue.first(:order => 'id DESC')
3669 assert_equal 1, issue.journals.size
3669 assert_equal 1, issue.journals.size
3670 journal = issue.journals.first
3670 journal = issue.journals.first
3671 assert_equal 0, journal.details.size
3671 assert_equal 0, journal.details.size
3672 assert_equal 'Copying one issue', journal.notes
3672 assert_equal 'Copying one issue', journal.notes
3673 end
3673 end
3674
3674
3675 def test_bulk_copy_should_allow_not_copying_the_attachments
3675 def test_bulk_copy_should_allow_not_copying_the_attachments
3676 attachment_count = Issue.find(3).attachments.size
3676 attachment_count = Issue.find(3).attachments.size
3677 assert attachment_count > 0
3677 assert attachment_count > 0
3678 @request.session[:user_id] = 2
3678 @request.session[:user_id] = 2
3679
3679
3680 assert_difference 'Issue.count', 1 do
3680 assert_difference 'Issue.count', 1 do
3681 assert_no_difference 'Attachment.count' do
3681 assert_no_difference 'Attachment.count' do
3682 post :bulk_update, :ids => [3], :copy => '1',
3682 post :bulk_update, :ids => [3], :copy => '1',
3683 :issue => {
3683 :issue => {
3684 :project_id => ''
3684 :project_id => ''
3685 }
3685 }
3686 end
3686 end
3687 end
3687 end
3688 end
3688 end
3689
3689
3690 def test_bulk_copy_should_allow_copying_the_attachments
3690 def test_bulk_copy_should_allow_copying_the_attachments
3691 attachment_count = Issue.find(3).attachments.size
3691 attachment_count = Issue.find(3).attachments.size
3692 assert attachment_count > 0
3692 assert attachment_count > 0
3693 @request.session[:user_id] = 2
3693 @request.session[:user_id] = 2
3694
3694
3695 assert_difference 'Issue.count', 1 do
3695 assert_difference 'Issue.count', 1 do
3696 assert_difference 'Attachment.count', attachment_count do
3696 assert_difference 'Attachment.count', attachment_count do
3697 post :bulk_update, :ids => [3], :copy => '1', :copy_attachments => '1',
3697 post :bulk_update, :ids => [3], :copy => '1', :copy_attachments => '1',
3698 :issue => {
3698 :issue => {
3699 :project_id => ''
3699 :project_id => ''
3700 }
3700 }
3701 end
3701 end
3702 end
3702 end
3703 end
3703 end
3704
3704
3705 def test_bulk_copy_should_add_relations_with_copied_issues
3705 def test_bulk_copy_should_add_relations_with_copied_issues
3706 @request.session[:user_id] = 2
3706 @request.session[:user_id] = 2
3707
3707
3708 assert_difference 'Issue.count', 2 do
3708 assert_difference 'Issue.count', 2 do
3709 assert_difference 'IssueRelation.count', 2 do
3709 assert_difference 'IssueRelation.count', 2 do
3710 post :bulk_update, :ids => [1, 3], :copy => '1',
3710 post :bulk_update, :ids => [1, 3], :copy => '1',
3711 :issue => {
3711 :issue => {
3712 :project_id => '1'
3712 :project_id => '1'
3713 }
3713 }
3714 end
3714 end
3715 end
3715 end
3716 end
3716 end
3717
3717
3718 def test_bulk_copy_should_allow_not_copying_the_subtasks
3718 def test_bulk_copy_should_allow_not_copying_the_subtasks
3719 issue = Issue.generate_with_descendants!
3719 issue = Issue.generate_with_descendants!
3720 @request.session[:user_id] = 2
3720 @request.session[:user_id] = 2
3721
3721
3722 assert_difference 'Issue.count', 1 do
3722 assert_difference 'Issue.count', 1 do
3723 post :bulk_update, :ids => [issue.id], :copy => '1',
3723 post :bulk_update, :ids => [issue.id], :copy => '1',
3724 :issue => {
3724 :issue => {
3725 :project_id => ''
3725 :project_id => ''
3726 }
3726 }
3727 end
3727 end
3728 end
3728 end
3729
3729
3730 def test_bulk_copy_should_allow_copying_the_subtasks
3730 def test_bulk_copy_should_allow_copying_the_subtasks
3731 issue = Issue.generate_with_descendants!
3731 issue = Issue.generate_with_descendants!
3732 count = issue.descendants.count
3732 count = issue.descendants.count
3733 @request.session[:user_id] = 2
3733 @request.session[:user_id] = 2
3734
3734
3735 assert_difference 'Issue.count', count+1 do
3735 assert_difference 'Issue.count', count+1 do
3736 post :bulk_update, :ids => [issue.id], :copy => '1', :copy_subtasks => '1',
3736 post :bulk_update, :ids => [issue.id], :copy => '1', :copy_subtasks => '1',
3737 :issue => {
3737 :issue => {
3738 :project_id => ''
3738 :project_id => ''
3739 }
3739 }
3740 end
3740 end
3741 copy = Issue.where(:parent_id => nil).order("id DESC").first
3741 copy = Issue.where(:parent_id => nil).order("id DESC").first
3742 assert_equal count, copy.descendants.count
3742 assert_equal count, copy.descendants.count
3743 end
3743 end
3744
3744
3745 def test_bulk_copy_should_not_copy_selected_subtasks_twice
3745 def test_bulk_copy_should_not_copy_selected_subtasks_twice
3746 issue = Issue.generate_with_descendants!
3746 issue = Issue.generate_with_descendants!
3747 count = issue.descendants.count
3747 count = issue.descendants.count
3748 @request.session[:user_id] = 2
3748 @request.session[:user_id] = 2
3749
3749
3750 assert_difference 'Issue.count', count+1 do
3750 assert_difference 'Issue.count', count+1 do
3751 post :bulk_update, :ids => issue.self_and_descendants.map(&:id), :copy => '1', :copy_subtasks => '1',
3751 post :bulk_update, :ids => issue.self_and_descendants.map(&:id), :copy => '1', :copy_subtasks => '1',
3752 :issue => {
3752 :issue => {
3753 :project_id => ''
3753 :project_id => ''
3754 }
3754 }
3755 end
3755 end
3756 copy = Issue.where(:parent_id => nil).order("id DESC").first
3756 copy = Issue.where(:parent_id => nil).order("id DESC").first
3757 assert_equal count, copy.descendants.count
3757 assert_equal count, copy.descendants.count
3758 end
3758 end
3759
3759
3760 def test_bulk_copy_to_another_project_should_follow_when_needed
3760 def test_bulk_copy_to_another_project_should_follow_when_needed
3761 @request.session[:user_id] = 2
3761 @request.session[:user_id] = 2
3762 post :bulk_update, :ids => [1], :copy => '1', :issue => {:project_id => 2}, :follow => '1'
3762 post :bulk_update, :ids => [1], :copy => '1', :issue => {:project_id => 2}, :follow => '1'
3763 issue = Issue.first(:order => 'id DESC')
3763 issue = Issue.first(:order => 'id DESC')
3764 assert_redirected_to :controller => 'issues', :action => 'show', :id => issue
3764 assert_redirected_to :controller => 'issues', :action => 'show', :id => issue
3765 end
3765 end
3766
3766
3767 def test_destroy_issue_with_no_time_entries
3767 def test_destroy_issue_with_no_time_entries
3768 assert_nil TimeEntry.find_by_issue_id(2)
3768 assert_nil TimeEntry.find_by_issue_id(2)
3769 @request.session[:user_id] = 2
3769 @request.session[:user_id] = 2
3770
3770
3771 assert_difference 'Issue.count', -1 do
3771 assert_difference 'Issue.count', -1 do
3772 delete :destroy, :id => 2
3772 delete :destroy, :id => 2
3773 end
3773 end
3774 assert_redirected_to :action => 'index', :project_id => 'ecookbook'
3774 assert_redirected_to :action => 'index', :project_id => 'ecookbook'
3775 assert_nil Issue.find_by_id(2)
3775 assert_nil Issue.find_by_id(2)
3776 end
3776 end
3777
3777
3778 def test_destroy_issues_with_time_entries
3778 def test_destroy_issues_with_time_entries
3779 @request.session[:user_id] = 2
3779 @request.session[:user_id] = 2
3780
3780
3781 assert_no_difference 'Issue.count' do
3781 assert_no_difference 'Issue.count' do
3782 delete :destroy, :ids => [1, 3]
3782 delete :destroy, :ids => [1, 3]
3783 end
3783 end
3784 assert_response :success
3784 assert_response :success
3785 assert_template 'destroy'
3785 assert_template 'destroy'
3786 assert_not_nil assigns(:hours)
3786 assert_not_nil assigns(:hours)
3787 assert Issue.find_by_id(1) && Issue.find_by_id(3)
3787 assert Issue.find_by_id(1) && Issue.find_by_id(3)
3788
3788
3789 assert_select 'form' do
3789 assert_select 'form' do
3790 assert_select 'input[name=_method][value=delete]'
3790 assert_select 'input[name=_method][value=delete]'
3791 end
3791 end
3792 end
3792 end
3793
3793
3794 def test_destroy_issues_and_destroy_time_entries
3794 def test_destroy_issues_and_destroy_time_entries
3795 @request.session[:user_id] = 2
3795 @request.session[:user_id] = 2
3796
3796
3797 assert_difference 'Issue.count', -2 do
3797 assert_difference 'Issue.count', -2 do
3798 assert_difference 'TimeEntry.count', -3 do
3798 assert_difference 'TimeEntry.count', -3 do
3799 delete :destroy, :ids => [1, 3], :todo => 'destroy'
3799 delete :destroy, :ids => [1, 3], :todo => 'destroy'
3800 end
3800 end
3801 end
3801 end
3802 assert_redirected_to :action => 'index', :project_id => 'ecookbook'
3802 assert_redirected_to :action => 'index', :project_id => 'ecookbook'
3803 assert !(Issue.find_by_id(1) || Issue.find_by_id(3))
3803 assert !(Issue.find_by_id(1) || Issue.find_by_id(3))
3804 assert_nil TimeEntry.find_by_id([1, 2])
3804 assert_nil TimeEntry.find_by_id([1, 2])
3805 end
3805 end
3806
3806
3807 def test_destroy_issues_and_assign_time_entries_to_project
3807 def test_destroy_issues_and_assign_time_entries_to_project
3808 @request.session[:user_id] = 2
3808 @request.session[:user_id] = 2
3809
3809
3810 assert_difference 'Issue.count', -2 do
3810 assert_difference 'Issue.count', -2 do
3811 assert_no_difference 'TimeEntry.count' do
3811 assert_no_difference 'TimeEntry.count' do
3812 delete :destroy, :ids => [1, 3], :todo => 'nullify'
3812 delete :destroy, :ids => [1, 3], :todo => 'nullify'
3813 end
3813 end
3814 end
3814 end
3815 assert_redirected_to :action => 'index', :project_id => 'ecookbook'
3815 assert_redirected_to :action => 'index', :project_id => 'ecookbook'
3816 assert !(Issue.find_by_id(1) || Issue.find_by_id(3))
3816 assert !(Issue.find_by_id(1) || Issue.find_by_id(3))
3817 assert_nil TimeEntry.find(1).issue_id
3817 assert_nil TimeEntry.find(1).issue_id
3818 assert_nil TimeEntry.find(2).issue_id
3818 assert_nil TimeEntry.find(2).issue_id
3819 end
3819 end
3820
3820
3821 def test_destroy_issues_and_reassign_time_entries_to_another_issue
3821 def test_destroy_issues_and_reassign_time_entries_to_another_issue
3822 @request.session[:user_id] = 2
3822 @request.session[:user_id] = 2
3823
3823
3824 assert_difference 'Issue.count', -2 do
3824 assert_difference 'Issue.count', -2 do
3825 assert_no_difference 'TimeEntry.count' do
3825 assert_no_difference 'TimeEntry.count' do
3826 delete :destroy, :ids => [1, 3], :todo => 'reassign', :reassign_to_id => 2
3826 delete :destroy, :ids => [1, 3], :todo => 'reassign', :reassign_to_id => 2
3827 end
3827 end
3828 end
3828 end
3829 assert_redirected_to :action => 'index', :project_id => 'ecookbook'
3829 assert_redirected_to :action => 'index', :project_id => 'ecookbook'
3830 assert !(Issue.find_by_id(1) || Issue.find_by_id(3))
3830 assert !(Issue.find_by_id(1) || Issue.find_by_id(3))
3831 assert_equal 2, TimeEntry.find(1).issue_id
3831 assert_equal 2, TimeEntry.find(1).issue_id
3832 assert_equal 2, TimeEntry.find(2).issue_id
3832 assert_equal 2, TimeEntry.find(2).issue_id
3833 end
3833 end
3834
3834
3835 def test_destroy_issues_from_different_projects
3835 def test_destroy_issues_from_different_projects
3836 @request.session[:user_id] = 2
3836 @request.session[:user_id] = 2
3837
3837
3838 assert_difference 'Issue.count', -3 do
3838 assert_difference 'Issue.count', -3 do
3839 delete :destroy, :ids => [1, 2, 6], :todo => 'destroy'
3839 delete :destroy, :ids => [1, 2, 6], :todo => 'destroy'
3840 end
3840 end
3841 assert_redirected_to :controller => 'issues', :action => 'index'
3841 assert_redirected_to :controller => 'issues', :action => 'index'
3842 assert !(Issue.find_by_id(1) || Issue.find_by_id(2) || Issue.find_by_id(6))
3842 assert !(Issue.find_by_id(1) || Issue.find_by_id(2) || Issue.find_by_id(6))
3843 end
3843 end
3844
3844
3845 def test_destroy_parent_and_child_issues
3845 def test_destroy_parent_and_child_issues
3846 parent = Issue.create!(:project_id => 1, :author_id => 1, :tracker_id => 1, :subject => 'Parent Issue')
3846 parent = Issue.create!(:project_id => 1, :author_id => 1, :tracker_id => 1, :subject => 'Parent Issue')
3847 child = Issue.create!(:project_id => 1, :author_id => 1, :tracker_id => 1, :subject => 'Child Issue', :parent_issue_id => parent.id)
3847 child = Issue.create!(:project_id => 1, :author_id => 1, :tracker_id => 1, :subject => 'Child Issue', :parent_issue_id => parent.id)
3848 assert child.is_descendant_of?(parent.reload)
3848 assert child.is_descendant_of?(parent.reload)
3849
3849
3850 @request.session[:user_id] = 2
3850 @request.session[:user_id] = 2
3851 assert_difference 'Issue.count', -2 do
3851 assert_difference 'Issue.count', -2 do
3852 delete :destroy, :ids => [parent.id, child.id], :todo => 'destroy'
3852 delete :destroy, :ids => [parent.id, child.id], :todo => 'destroy'
3853 end
3853 end
3854 assert_response 302
3854 assert_response 302
3855 end
3855 end
3856
3856
3857 def test_destroy_invalid_should_respond_with_404
3857 def test_destroy_invalid_should_respond_with_404
3858 @request.session[:user_id] = 2
3858 @request.session[:user_id] = 2
3859 assert_no_difference 'Issue.count' do
3859 assert_no_difference 'Issue.count' do
3860 delete :destroy, :id => 999
3860 delete :destroy, :id => 999
3861 end
3861 end
3862 assert_response 404
3862 assert_response 404
3863 end
3863 end
3864
3864
3865 def test_default_search_scope
3865 def test_default_search_scope
3866 get :index
3866 get :index
3867
3867
3868 assert_select 'div#quick-search form' do
3868 assert_select 'div#quick-search form' do
3869 assert_select 'input[name=issues][value=1][type=hidden]'
3869 assert_select 'input[name=issues][value=1][type=hidden]'
3870 end
3870 end
3871 end
3871 end
3872 end
3872 end
@@ -1,229 +1,220
1 # Redmine - project management software
1 # Redmine - project management software
2 # Copyright (C) 2006-2013 Jean-Philippe Lang
2 # Copyright (C) 2006-2013 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 require File.expand_path('../../test_helper', __FILE__)
18 require File.expand_path('../../test_helper', __FILE__)
19
19
20 class IssuesTest < ActionController::IntegrationTest
20 class IssuesTest < ActionController::IntegrationTest
21 fixtures :projects,
21 fixtures :projects,
22 :users,
22 :users,
23 :roles,
23 :roles,
24 :members,
24 :members,
25 :member_roles,
25 :member_roles,
26 :trackers,
26 :trackers,
27 :projects_trackers,
27 :projects_trackers,
28 :enabled_modules,
28 :enabled_modules,
29 :issue_statuses,
29 :issue_statuses,
30 :issues,
30 :issues,
31 :enumerations,
31 :enumerations,
32 :custom_fields,
32 :custom_fields,
33 :custom_values,
33 :custom_values,
34 :custom_fields_trackers
34 :custom_fields_trackers
35
35
36 # create an issue
36 # create an issue
37 def test_add_issue
37 def test_add_issue
38 log_user('jsmith', 'jsmith')
38 log_user('jsmith', 'jsmith')
39 get 'projects/1/issues/new', :tracker_id => '1'
39 get 'projects/1/issues/new', :tracker_id => '1'
40 assert_response :success
40 assert_response :success
41 assert_template 'issues/new'
41 assert_template 'issues/new'
42
42
43 post 'projects/1/issues', :tracker_id => "1",
43 post 'projects/1/issues', :tracker_id => "1",
44 :issue => { :start_date => "2006-12-26",
44 :issue => { :start_date => "2006-12-26",
45 :priority_id => "4",
45 :priority_id => "4",
46 :subject => "new test issue",
46 :subject => "new test issue",
47 :category_id => "",
47 :category_id => "",
48 :description => "new issue",
48 :description => "new issue",
49 :done_ratio => "0",
49 :done_ratio => "0",
50 :due_date => "",
50 :due_date => "",
51 :assigned_to_id => "" },
51 :assigned_to_id => "" },
52 :custom_fields => {'2' => 'Value for field 2'}
52 :custom_fields => {'2' => 'Value for field 2'}
53 # find created issue
53 # find created issue
54 issue = Issue.find_by_subject("new test issue")
54 issue = Issue.find_by_subject("new test issue")
55 assert_kind_of Issue, issue
55 assert_kind_of Issue, issue
56
56
57 # check redirection
57 # check redirection
58 assert_redirected_to :controller => 'issues', :action => 'show', :id => issue
58 assert_redirected_to :controller => 'issues', :action => 'show', :id => issue
59 follow_redirect!
59 follow_redirect!
60 assert_equal issue, assigns(:issue)
60 assert_equal issue, assigns(:issue)
61
61
62 # check issue attributes
62 # check issue attributes
63 assert_equal 'jsmith', issue.author.login
63 assert_equal 'jsmith', issue.author.login
64 assert_equal 1, issue.project.id
64 assert_equal 1, issue.project.id
65 assert_equal 1, issue.status.id
65 assert_equal 1, issue.status.id
66 end
66 end
67
67
68 def test_update_issue_form
69 log_user('jsmith', 'jsmith')
70 post 'projects/ecookbook/issues/new', :issue => { :tracker_id => "2"}
71 assert_response :success
72 assert_tag 'select',
73 :attributes => {:name => 'issue[tracker_id]'},
74 :child => {:tag => 'option', :attributes => {:value => '2', :selected => 'selected'}}
75 end
76
77 # add then remove 2 attachments to an issue
68 # add then remove 2 attachments to an issue
78 def test_issue_attachments
69 def test_issue_attachments
79 log_user('jsmith', 'jsmith')
70 log_user('jsmith', 'jsmith')
80 set_tmp_attachments_directory
71 set_tmp_attachments_directory
81
72
82 put 'issues/1',
73 put 'issues/1',
83 :notes => 'Some notes',
74 :notes => 'Some notes',
84 :attachments => {'1' => {'file' => uploaded_test_file('testfile.txt', 'text/plain'), 'description' => 'This is an attachment'}}
75 :attachments => {'1' => {'file' => uploaded_test_file('testfile.txt', 'text/plain'), 'description' => 'This is an attachment'}}
85 assert_redirected_to "/issues/1"
76 assert_redirected_to "/issues/1"
86
77
87 # make sure attachment was saved
78 # make sure attachment was saved
88 attachment = Issue.find(1).attachments.find_by_filename("testfile.txt")
79 attachment = Issue.find(1).attachments.find_by_filename("testfile.txt")
89 assert_kind_of Attachment, attachment
80 assert_kind_of Attachment, attachment
90 assert_equal Issue.find(1), attachment.container
81 assert_equal Issue.find(1), attachment.container
91 assert_equal 'This is an attachment', attachment.description
82 assert_equal 'This is an attachment', attachment.description
92 # verify the size of the attachment stored in db
83 # verify the size of the attachment stored in db
93 #assert_equal file_data_1.length, attachment.filesize
84 #assert_equal file_data_1.length, attachment.filesize
94 # verify that the attachment was written to disk
85 # verify that the attachment was written to disk
95 assert File.exist?(attachment.diskfile)
86 assert File.exist?(attachment.diskfile)
96
87
97 # remove the attachments
88 # remove the attachments
98 Issue.find(1).attachments.each(&:destroy)
89 Issue.find(1).attachments.each(&:destroy)
99 assert_equal 0, Issue.find(1).attachments.length
90 assert_equal 0, Issue.find(1).attachments.length
100 end
91 end
101
92
102 def test_other_formats_links_on_index
93 def test_other_formats_links_on_index
103 get '/projects/ecookbook/issues'
94 get '/projects/ecookbook/issues'
104
95
105 %w(Atom PDF CSV).each do |format|
96 %w(Atom PDF CSV).each do |format|
106 assert_tag :a, :content => format,
97 assert_tag :a, :content => format,
107 :attributes => { :href => "/projects/ecookbook/issues.#{format.downcase}",
98 :attributes => { :href => "/projects/ecookbook/issues.#{format.downcase}",
108 :rel => 'nofollow' }
99 :rel => 'nofollow' }
109 end
100 end
110 end
101 end
111
102
112 def test_other_formats_links_on_index_without_project_id_in_url
103 def test_other_formats_links_on_index_without_project_id_in_url
113 get '/issues', :project_id => 'ecookbook'
104 get '/issues', :project_id => 'ecookbook'
114
105
115 %w(Atom PDF CSV).each do |format|
106 %w(Atom PDF CSV).each do |format|
116 assert_tag :a, :content => format,
107 assert_tag :a, :content => format,
117 :attributes => { :href => "/projects/ecookbook/issues.#{format.downcase}",
108 :attributes => { :href => "/projects/ecookbook/issues.#{format.downcase}",
118 :rel => 'nofollow' }
109 :rel => 'nofollow' }
119 end
110 end
120 end
111 end
121
112
122 def test_pagination_links_on_index
113 def test_pagination_links_on_index
123 Setting.per_page_options = '2'
114 Setting.per_page_options = '2'
124 get '/projects/ecookbook/issues'
115 get '/projects/ecookbook/issues'
125
116
126 assert_tag :a, :content => '2',
117 assert_tag :a, :content => '2',
127 :attributes => { :href => '/projects/ecookbook/issues?page=2' }
118 :attributes => { :href => '/projects/ecookbook/issues?page=2' }
128
119
129 end
120 end
130
121
131 def test_pagination_links_on_index_without_project_id_in_url
122 def test_pagination_links_on_index_without_project_id_in_url
132 Setting.per_page_options = '2'
123 Setting.per_page_options = '2'
133 get '/issues', :project_id => 'ecookbook'
124 get '/issues', :project_id => 'ecookbook'
134
125
135 assert_tag :a, :content => '2',
126 assert_tag :a, :content => '2',
136 :attributes => { :href => '/projects/ecookbook/issues?page=2' }
127 :attributes => { :href => '/projects/ecookbook/issues?page=2' }
137
128
138 end
129 end
139
130
140 def test_issue_with_user_custom_field
131 def test_issue_with_user_custom_field
141 @field = IssueCustomField.create!(:name => 'Tester', :field_format => 'user', :is_for_all => true, :trackers => Tracker.all)
132 @field = IssueCustomField.create!(:name => 'Tester', :field_format => 'user', :is_for_all => true, :trackers => Tracker.all)
142 Role.anonymous.add_permission! :add_issues, :edit_issues
133 Role.anonymous.add_permission! :add_issues, :edit_issues
143 users = Project.find(1).users
134 users = Project.find(1).users
144 tester = users.first
135 tester = users.first
145
136
146 # Issue form
137 # Issue form
147 get '/projects/ecookbook/issues/new'
138 get '/projects/ecookbook/issues/new'
148 assert_response :success
139 assert_response :success
149 assert_tag :select,
140 assert_tag :select,
150 :attributes => {:name => "issue[custom_field_values][#{@field.id}]"},
141 :attributes => {:name => "issue[custom_field_values][#{@field.id}]"},
151 :children => {:count => (users.size + 1)}, # +1 for blank value
142 :children => {:count => (users.size + 1)}, # +1 for blank value
152 :child => {
143 :child => {
153 :tag => 'option',
144 :tag => 'option',
154 :attributes => {:value => tester.id.to_s},
145 :attributes => {:value => tester.id.to_s},
155 :content => tester.name
146 :content => tester.name
156 }
147 }
157
148
158 # Create issue
149 # Create issue
159 assert_difference 'Issue.count' do
150 assert_difference 'Issue.count' do
160 post '/projects/ecookbook/issues',
151 post '/projects/ecookbook/issues',
161 :issue => {
152 :issue => {
162 :tracker_id => '1',
153 :tracker_id => '1',
163 :priority_id => '4',
154 :priority_id => '4',
164 :subject => 'Issue with user custom field',
155 :subject => 'Issue with user custom field',
165 :custom_field_values => {@field.id.to_s => users.first.id.to_s}
156 :custom_field_values => {@field.id.to_s => users.first.id.to_s}
166 }
157 }
167 end
158 end
168 issue = Issue.first(:order => 'id DESC')
159 issue = Issue.first(:order => 'id DESC')
169 assert_response 302
160 assert_response 302
170
161
171 # Issue view
162 # Issue view
172 follow_redirect!
163 follow_redirect!
173 assert_tag :th,
164 assert_tag :th,
174 :content => /Tester/,
165 :content => /Tester/,
175 :sibling => {
166 :sibling => {
176 :tag => 'td',
167 :tag => 'td',
177 :content => tester.name
168 :content => tester.name
178 }
169 }
179 assert_tag :select,
170 assert_tag :select,
180 :attributes => {:name => "issue[custom_field_values][#{@field.id}]"},
171 :attributes => {:name => "issue[custom_field_values][#{@field.id}]"},
181 :children => {:count => (users.size + 1)}, # +1 for blank value
172 :children => {:count => (users.size + 1)}, # +1 for blank value
182 :child => {
173 :child => {
183 :tag => 'option',
174 :tag => 'option',
184 :attributes => {:value => tester.id.to_s, :selected => 'selected'},
175 :attributes => {:value => tester.id.to_s, :selected => 'selected'},
185 :content => tester.name
176 :content => tester.name
186 }
177 }
187
178
188 # Update issue
179 # Update issue
189 new_tester = users[1]
180 new_tester = users[1]
190 assert_difference 'Journal.count' do
181 assert_difference 'Journal.count' do
191 put "/issues/#{issue.id}",
182 put "/issues/#{issue.id}",
192 :notes => 'Updating custom field',
183 :notes => 'Updating custom field',
193 :issue => {
184 :issue => {
194 :custom_field_values => {@field.id.to_s => new_tester.id.to_s}
185 :custom_field_values => {@field.id.to_s => new_tester.id.to_s}
195 }
186 }
196 end
187 end
197 assert_response 302
188 assert_response 302
198
189
199 # Issue view
190 # Issue view
200 follow_redirect!
191 follow_redirect!
201 assert_tag :content => 'Tester',
192 assert_tag :content => 'Tester',
202 :ancestor => {:tag => 'ul', :attributes => {:class => /details/}},
193 :ancestor => {:tag => 'ul', :attributes => {:class => /details/}},
203 :sibling => {
194 :sibling => {
204 :content => tester.name,
195 :content => tester.name,
205 :sibling => {
196 :sibling => {
206 :content => new_tester.name
197 :content => new_tester.name
207 }
198 }
208 }
199 }
209 end
200 end
210
201
211 def test_update_using_invalid_http_verbs
202 def test_update_using_invalid_http_verbs
212 subject = 'Updated by an invalid http verb'
203 subject = 'Updated by an invalid http verb'
213
204
214 get '/issues/update/1', {:issue => {:subject => subject}}, credentials('jsmith')
205 get '/issues/update/1', {:issue => {:subject => subject}}, credentials('jsmith')
215 assert_response 404
206 assert_response 404
216 assert_not_equal subject, Issue.find(1).subject
207 assert_not_equal subject, Issue.find(1).subject
217
208
218 post '/issues/1', {:issue => {:subject => subject}}, credentials('jsmith')
209 post '/issues/1', {:issue => {:subject => subject}}, credentials('jsmith')
219 assert_response 404
210 assert_response 404
220 assert_not_equal subject, Issue.find(1).subject
211 assert_not_equal subject, Issue.find(1).subject
221 end
212 end
222
213
223 def test_get_watch_should_be_invalid
214 def test_get_watch_should_be_invalid
224 assert_no_difference 'Watcher.count' do
215 assert_no_difference 'Watcher.count' do
225 get '/watchers/watch?object_type=issue&object_id=1', {}, credentials('jsmith')
216 get '/watchers/watch?object_type=issue&object_id=1', {}, credentials('jsmith')
226 assert_response 404
217 assert_response 404
227 end
218 end
228 end
219 end
229 end
220 end
@@ -1,134 +1,134
1 # Redmine - project management software
1 # Redmine - project management software
2 # Copyright (C) 2006-2013 Jean-Philippe Lang
2 # Copyright (C) 2006-2013 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 require File.expand_path('../../../test_helper', __FILE__)
18 require File.expand_path('../../../test_helper', __FILE__)
19
19
20 class RoutingIssuesTest < ActionController::IntegrationTest
20 class RoutingIssuesTest < ActionController::IntegrationTest
21 def test_issues_rest_actions
21 def test_issues_rest_actions
22 assert_routing(
22 assert_routing(
23 { :method => 'get', :path => "/issues" },
23 { :method => 'get', :path => "/issues" },
24 { :controller => 'issues', :action => 'index' }
24 { :controller => 'issues', :action => 'index' }
25 )
25 )
26 assert_routing(
26 assert_routing(
27 { :method => 'get', :path => "/issues.pdf" },
27 { :method => 'get', :path => "/issues.pdf" },
28 { :controller => 'issues', :action => 'index', :format => 'pdf' }
28 { :controller => 'issues', :action => 'index', :format => 'pdf' }
29 )
29 )
30 assert_routing(
30 assert_routing(
31 { :method => 'get', :path => "/issues.atom" },
31 { :method => 'get', :path => "/issues.atom" },
32 { :controller => 'issues', :action => 'index', :format => 'atom' }
32 { :controller => 'issues', :action => 'index', :format => 'atom' }
33 )
33 )
34 assert_routing(
34 assert_routing(
35 { :method => 'get', :path => "/issues.xml" },
35 { :method => 'get', :path => "/issues.xml" },
36 { :controller => 'issues', :action => 'index', :format => 'xml' }
36 { :controller => 'issues', :action => 'index', :format => 'xml' }
37 )
37 )
38 assert_routing(
38 assert_routing(
39 { :method => 'get', :path => "/issues/64" },
39 { :method => 'get', :path => "/issues/64" },
40 { :controller => 'issues', :action => 'show', :id => '64' }
40 { :controller => 'issues', :action => 'show', :id => '64' }
41 )
41 )
42 assert_routing(
42 assert_routing(
43 { :method => 'get', :path => "/issues/64.pdf" },
43 { :method => 'get', :path => "/issues/64.pdf" },
44 { :controller => 'issues', :action => 'show', :id => '64',
44 { :controller => 'issues', :action => 'show', :id => '64',
45 :format => 'pdf' }
45 :format => 'pdf' }
46 )
46 )
47 assert_routing(
47 assert_routing(
48 { :method => 'get', :path => "/issues/64.atom" },
48 { :method => 'get', :path => "/issues/64.atom" },
49 { :controller => 'issues', :action => 'show', :id => '64',
49 { :controller => 'issues', :action => 'show', :id => '64',
50 :format => 'atom' }
50 :format => 'atom' }
51 )
51 )
52 assert_routing(
52 assert_routing(
53 { :method => 'get', :path => "/issues/64.xml" },
53 { :method => 'get', :path => "/issues/64.xml" },
54 { :controller => 'issues', :action => 'show', :id => '64',
54 { :controller => 'issues', :action => 'show', :id => '64',
55 :format => 'xml' }
55 :format => 'xml' }
56 )
56 )
57 assert_routing(
57 assert_routing(
58 { :method => 'post', :path => "/issues.xml" },
58 { :method => 'post', :path => "/issues.xml" },
59 { :controller => 'issues', :action => 'create', :format => 'xml' }
59 { :controller => 'issues', :action => 'create', :format => 'xml' }
60 )
60 )
61 assert_routing(
61 assert_routing(
62 { :method => 'get', :path => "/issues/64/edit" },
62 { :method => 'get', :path => "/issues/64/edit" },
63 { :controller => 'issues', :action => 'edit', :id => '64' }
63 { :controller => 'issues', :action => 'edit', :id => '64' }
64 )
64 )
65 assert_routing(
65 assert_routing(
66 { :method => 'put', :path => "/issues/1.xml" },
66 { :method => 'put', :path => "/issues/1.xml" },
67 { :controller => 'issues', :action => 'update', :id => '1',
67 { :controller => 'issues', :action => 'update', :id => '1',
68 :format => 'xml' }
68 :format => 'xml' }
69 )
69 )
70 assert_routing(
70 assert_routing(
71 { :method => 'delete', :path => "/issues/1.xml" },
71 { :method => 'delete', :path => "/issues/1.xml" },
72 { :controller => 'issues', :action => 'destroy', :id => '1',
72 { :controller => 'issues', :action => 'destroy', :id => '1',
73 :format => 'xml' }
73 :format => 'xml' }
74 )
74 )
75 end
75 end
76
76
77 def test_issues_rest_actions_scoped_under_project
77 def test_issues_rest_actions_scoped_under_project
78 assert_routing(
78 assert_routing(
79 { :method => 'get', :path => "/projects/23/issues" },
79 { :method => 'get', :path => "/projects/23/issues" },
80 { :controller => 'issues', :action => 'index', :project_id => '23' }
80 { :controller => 'issues', :action => 'index', :project_id => '23' }
81 )
81 )
82 assert_routing(
82 assert_routing(
83 { :method => 'get', :path => "/projects/23/issues.pdf" },
83 { :method => 'get', :path => "/projects/23/issues.pdf" },
84 { :controller => 'issues', :action => 'index', :project_id => '23',
84 { :controller => 'issues', :action => 'index', :project_id => '23',
85 :format => 'pdf' }
85 :format => 'pdf' }
86 )
86 )
87 assert_routing(
87 assert_routing(
88 { :method => 'get', :path => "/projects/23/issues.atom" },
88 { :method => 'get', :path => "/projects/23/issues.atom" },
89 { :controller => 'issues', :action => 'index', :project_id => '23',
89 { :controller => 'issues', :action => 'index', :project_id => '23',
90 :format => 'atom' }
90 :format => 'atom' }
91 )
91 )
92 assert_routing(
92 assert_routing(
93 { :method => 'get', :path => "/projects/23/issues.xml" },
93 { :method => 'get', :path => "/projects/23/issues.xml" },
94 { :controller => 'issues', :action => 'index', :project_id => '23',
94 { :controller => 'issues', :action => 'index', :project_id => '23',
95 :format => 'xml' }
95 :format => 'xml' }
96 )
96 )
97 assert_routing(
97 assert_routing(
98 { :method => 'post', :path => "/projects/23/issues" },
98 { :method => 'post', :path => "/projects/23/issues" },
99 { :controller => 'issues', :action => 'create', :project_id => '23' }
99 { :controller => 'issues', :action => 'create', :project_id => '23' }
100 )
100 )
101 assert_routing(
101 assert_routing(
102 { :method => 'get', :path => "/projects/23/issues/new" },
102 { :method => 'get', :path => "/projects/23/issues/new" },
103 { :controller => 'issues', :action => 'new', :project_id => '23' }
103 { :controller => 'issues', :action => 'new', :project_id => '23' }
104 )
104 )
105 end
105 end
106
106
107 def test_issues_form_update
107 def test_issues_form_update
108 ["post", "put"].each do |method|
108 ["post", "put"].each do |method|
109 assert_routing(
109 assert_routing(
110 { :method => method, :path => "/projects/23/issues/new" },
110 { :method => method, :path => "/projects/23/issues/update_form" },
111 { :controller => 'issues', :action => 'new', :project_id => '23' }
111 { :controller => 'issues', :action => 'update_form', :project_id => '23' }
112 )
112 )
113 end
113 end
114 end
114 end
115
115
116 def test_issues_extra_actions
116 def test_issues_extra_actions
117 assert_routing(
117 assert_routing(
118 { :method => 'get', :path => "/projects/23/issues/64/copy" },
118 { :method => 'get', :path => "/projects/23/issues/64/copy" },
119 { :controller => 'issues', :action => 'new', :project_id => '23',
119 { :controller => 'issues', :action => 'new', :project_id => '23',
120 :copy_from => '64' }
120 :copy_from => '64' }
121 )
121 )
122 # For updating the bulk edit form
122 # For updating the bulk edit form
123 ["get", "post"].each do |method|
123 ["get", "post"].each do |method|
124 assert_routing(
124 assert_routing(
125 { :method => method, :path => "/issues/bulk_edit" },
125 { :method => method, :path => "/issues/bulk_edit" },
126 { :controller => 'issues', :action => 'bulk_edit' }
126 { :controller => 'issues', :action => 'bulk_edit' }
127 )
127 )
128 end
128 end
129 assert_routing(
129 assert_routing(
130 { :method => 'post', :path => "/issues/bulk_update" },
130 { :method => 'post', :path => "/issues/bulk_update" },
131 { :controller => 'issues', :action => 'bulk_update' }
131 { :controller => 'issues', :action => 'bulk_update' }
132 )
132 )
133 end
133 end
134 end
134 end
@@ -1,128 +1,186
1 # Redmine - project management software
1 # Redmine - project management software
2 # Copyright (C) 2006-2013 Jean-Philippe Lang
2 # Copyright (C) 2006-2013 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 require File.expand_path('../base', __FILE__)
18 require File.expand_path('../base', __FILE__)
19
19
20 class Redmine::UiTest::IssuesTest < Redmine::UiTest::Base
20 class Redmine::UiTest::IssuesTest < Redmine::UiTest::Base
21 fixtures :projects, :users, :roles, :members, :member_roles,
21 fixtures :projects, :users, :roles, :members, :member_roles,
22 :trackers, :projects_trackers, :enabled_modules, :issue_statuses, :issues,
22 :trackers, :projects_trackers, :enabled_modules, :issue_statuses, :issues,
23 :enumerations, :custom_fields, :custom_values, :custom_fields_trackers,
23 :enumerations, :custom_fields, :custom_values, :custom_fields_trackers,
24 :watchers
24 :watchers
25
25
26 def test_create_issue
26 def test_create_issue
27 log_user('jsmith', 'jsmith')
27 log_user('jsmith', 'jsmith')
28 visit '/projects/ecookbook/issues/new'
28 visit '/projects/ecookbook/issues/new'
29 within('form#issue-form') do
29 within('form#issue-form') do
30 select 'Bug', :from => 'Tracker'
30 select 'Bug', :from => 'Tracker'
31 select 'Low', :from => 'Priority'
31 select 'Low', :from => 'Priority'
32 fill_in 'Subject', :with => 'new test issue'
32 fill_in 'Subject', :with => 'new test issue'
33 fill_in 'Description', :with => 'new issue'
33 fill_in 'Description', :with => 'new issue'
34 select '0 %', :from => 'Done'
34 select '0 %', :from => 'Done'
35 fill_in 'Due date', :with => ''
35 fill_in 'Due date', :with => ''
36 select '', :from => 'Assignee'
36 select '', :from => 'Assignee'
37 fill_in 'Searchable field', :with => 'Value for field 2'
37 fill_in 'Searchable field', :with => 'Value for field 2'
38 # click_button 'Create' would match both 'Create' and 'Create and continue' buttons
38 # click_button 'Create' would match both 'Create' and 'Create and continue' buttons
39 find('input[name=commit]').click
39 find('input[name=commit]').click
40 end
40 end
41
41
42 # find created issue
42 # find created issue
43 issue = Issue.find_by_subject("new test issue")
43 issue = Issue.find_by_subject("new test issue")
44 assert_kind_of Issue, issue
44 assert_kind_of Issue, issue
45
45
46 # check redirection
46 # check redirection
47 find 'div#flash_notice', :visible => true, :text => "Issue \##{issue.id} created."
47 find 'div#flash_notice', :visible => true, :text => "Issue \##{issue.id} created."
48 assert_equal issue_path(:id => issue), current_path
48 assert_equal issue_path(:id => issue), current_path
49
49
50 # check issue attributes
50 # check issue attributes
51 assert_equal 'jsmith', issue.author.login
51 assert_equal 'jsmith', issue.author.login
52 assert_equal 1, issue.project.id
52 assert_equal 1, issue.project.id
53 assert_equal IssueStatus.find_by_name('New'), issue.status
53 assert_equal IssueStatus.find_by_name('New'), issue.status
54 assert_equal Tracker.find_by_name('Bug'), issue.tracker
54 assert_equal Tracker.find_by_name('Bug'), issue.tracker
55 assert_equal IssuePriority.find_by_name('Low'), issue.priority
55 assert_equal IssuePriority.find_by_name('Low'), issue.priority
56 assert_equal 'Value for field 2', issue.custom_field_value(CustomField.find_by_name('Searchable field'))
56 assert_equal 'Value for field 2', issue.custom_field_value(CustomField.find_by_name('Searchable field'))
57 end
57 end
58
58
59 def test_create_issue_with_form_update
60 field = IssueCustomField.create!(
61 :field_format => 'string',
62 :name => 'Form update CF',
63 :is_for_all => true,
64 :trackers => Tracker.find_all_by_name('Feature request')
65 )
66
67 Role.non_member.add_permission! :add_issues
68 Role.non_member.remove_permission! :edit_issues, :add_issue_notes
69
70 log_user('someone', 'foo')
71 visit '/projects/ecookbook/issues/new'
72 assert page.has_no_content?('Form update CF')
73
74 fill_in 'Subject', :with => 'new test issue'
75 # the custom field should show up when changing tracker
76 select 'Feature request', :from => 'Tracker'
77 assert page.has_content?('Form update CF')
78
79 fill_in 'Form update', :with => 'CF value'
80 assert_difference 'Issue.count' do
81 find('input[name=commit]').click
82 end
83
84 issue = Issue.order('id desc').first
85 assert_equal 'CF value', issue.custom_field_value(field)
86 end
87
59 def test_create_issue_with_watchers
88 def test_create_issue_with_watchers
60 User.generate!(:firstname => 'Some', :lastname => 'Watcher')
89 User.generate!(:firstname => 'Some', :lastname => 'Watcher')
61
90
62 log_user('jsmith', 'jsmith')
91 log_user('jsmith', 'jsmith')
63 visit '/projects/ecookbook/issues/new'
92 visit '/projects/ecookbook/issues/new'
64 fill_in 'Subject', :with => 'Issue with watchers'
93 fill_in 'Subject', :with => 'Issue with watchers'
65 # Add a project member as watcher
94 # Add a project member as watcher
66 check 'Dave Lopper'
95 check 'Dave Lopper'
67 # Search for another user
96 # Search for another user
68 click_link 'Search for watchers to add'
97 click_link 'Search for watchers to add'
69 within('form#new-watcher-form') do
98 within('form#new-watcher-form') do
70 assert page.has_content?('Some One')
99 assert page.has_content?('Some One')
71 fill_in 'user_search', :with => 'watch'
100 fill_in 'user_search', :with => 'watch'
72 assert page.has_no_content?('Some One')
101 assert page.has_no_content?('Some One')
73 check 'Some Watcher'
102 check 'Some Watcher'
74 click_button 'Add'
103 click_button 'Add'
75 end
104 end
76 assert_difference 'Issue.count' do
105 assert_difference 'Issue.count' do
77 find('input[name=commit]').click
106 find('input[name=commit]').click
78 end
107 end
79
108
80 issue = Issue.order('id desc').first
109 issue = Issue.order('id desc').first
81 assert_equal ['Dave Lopper', 'Some Watcher'], issue.watcher_users.map(&:name).sort
110 assert_equal ['Dave Lopper', 'Some Watcher'], issue.watcher_users.map(&:name).sort
82 end
111 end
83
112
84 def test_preview_issue_description
113 def test_preview_issue_description
85 log_user('jsmith', 'jsmith')
114 log_user('jsmith', 'jsmith')
86 visit '/projects/ecookbook/issues/new'
115 visit '/projects/ecookbook/issues/new'
87 within('form#issue-form') do
116 within('form#issue-form') do
88 fill_in 'Subject', :with => 'new issue subject'
117 fill_in 'Subject', :with => 'new issue subject'
89 fill_in 'Description', :with => 'new issue description'
118 fill_in 'Description', :with => 'new issue description'
90 click_link 'Preview'
119 click_link 'Preview'
91 end
120 end
92 find 'div#preview fieldset', :visible => true, :text => 'new issue description'
121 find 'div#preview fieldset', :visible => true, :text => 'new issue description'
93 assert_difference 'Issue.count' do
122 assert_difference 'Issue.count' do
94 find('input[name=commit]').click
123 find('input[name=commit]').click
95 end
124 end
96
125
97 issue = Issue.order('id desc').first
126 issue = Issue.order('id desc').first
98 assert_equal 'new issue description', issue.description
127 assert_equal 'new issue description', issue.description
99 end
128 end
100
129
130 def test_update_issue_with_form_update
131 field = IssueCustomField.create!(
132 :field_format => 'string',
133 :name => 'Form update CF',
134 :is_for_all => true,
135 :trackers => Tracker.find_all_by_name('Feature request')
136 )
137
138 Role.non_member.add_permission! :edit_issues
139 Role.non_member.remove_permission! :add_issues, :add_issue_notes
140
141 log_user('someone', 'foo')
142 visit '/issues/1'
143 assert page.has_no_content?('Form update CF')
144
145 page.first(:link, 'Update').click
146 # the custom field should show up when changing tracker
147 select 'Feature request', :from => 'Tracker'
148 assert page.has_content?('Form update CF')
149
150 fill_in 'Form update', :with => 'CF value'
151 assert_no_difference 'Issue.count' do
152 page.first(:button, 'Submit').click
153 end
154
155 issue = Issue.find(1)
156 assert_equal 'CF value', issue.custom_field_value(field)
157 end
158
101 def test_watch_issue_via_context_menu
159 def test_watch_issue_via_context_menu
102 log_user('jsmith', 'jsmith')
160 log_user('jsmith', 'jsmith')
103 visit '/issues'
161 visit '/issues'
104 find('tr#issue-1 td.updated_on').click
162 find('tr#issue-1 td.updated_on').click
105 page.execute_script "$('tr#issue-1 td.updated_on').trigger('contextmenu');"
163 page.execute_script "$('tr#issue-1 td.updated_on').trigger('contextmenu');"
106 assert_difference 'Watcher.count' do
164 assert_difference 'Watcher.count' do
107 within('#context-menu') do
165 within('#context-menu') do
108 click_link 'Watch'
166 click_link 'Watch'
109 end
167 end
110 end
168 end
111 assert Issue.find(1).watched_by?(User.find_by_login('jsmith'))
169 assert Issue.find(1).watched_by?(User.find_by_login('jsmith'))
112 end
170 end
113
171
114 def test_bulk_watch_issues_via_context_menu
172 def test_bulk_watch_issues_via_context_menu
115 log_user('jsmith', 'jsmith')
173 log_user('jsmith', 'jsmith')
116 visit '/issues'
174 visit '/issues'
117 find('tr#issue-1 input[type=checkbox]').click
175 find('tr#issue-1 input[type=checkbox]').click
118 find('tr#issue-4 input[type=checkbox]').click
176 find('tr#issue-4 input[type=checkbox]').click
119 page.execute_script "$('tr#issue-1 td.updated_on').trigger('contextmenu');"
177 page.execute_script "$('tr#issue-1 td.updated_on').trigger('contextmenu');"
120 assert_difference 'Watcher.count', 2 do
178 assert_difference 'Watcher.count', 2 do
121 within('#context-menu') do
179 within('#context-menu') do
122 click_link 'Watch'
180 click_link 'Watch'
123 end
181 end
124 end
182 end
125 assert Issue.find(1).watched_by?(User.find_by_login('jsmith'))
183 assert Issue.find(1).watched_by?(User.find_by_login('jsmith'))
126 assert Issue.find(4).watched_by?(User.find_by_login('jsmith'))
184 assert Issue.find(4).watched_by?(User.find_by_login('jsmith'))
127 end
185 end
128 end
186 end
General Comments 0
You need to be logged in to leave comments. Login now