##// END OF EJS Templates
Copy issues via bulk update action....
Jean-Philippe Lang -
r8418:065376c160b0
parent child
Show More
@@ -1,388 +1,393
1 # Redmine - project management software
1 # Redmine - project management software
2 # Copyright (C) 2006-2011 Jean-Philippe Lang
2 # Copyright (C) 2006-2011 Jean-Philippe Lang
3 #
3 #
4 # This program is free software; you can redistribute it and/or
4 # This program is free software; you can redistribute it and/or
5 # modify it under the terms of the GNU General Public License
5 # modify it under the terms of the GNU General Public License
6 # as published by the Free Software Foundation; either version 2
6 # as published by the Free Software Foundation; either version 2
7 # of the License, or (at your option) any later version.
7 # of the License, or (at your option) any later version.
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, :move, :perform_move, :destroy]
23 before_filter :find_issues, :only => [:bulk_edit, :bulk_update, :move, :perform_move, :destroy]
24 before_filter :check_project_uniqueness, :only => [:move, :perform_move]
24 before_filter :check_project_uniqueness, :only => [:move, :perform_move]
25 before_filter :find_project, :only => [:new, :create]
25 before_filter :find_project, :only => [:new, :create]
26 before_filter :authorize, :except => [:index]
26 before_filter :authorize, :except => [:index]
27 before_filter :find_optional_project, :only => [:index]
27 before_filter :find_optional_project, :only => [:index]
28 before_filter :check_for_default_issue_status, :only => [:new, :create]
28 before_filter :check_for_default_issue_status, :only => [:new, :create]
29 before_filter :build_new_issue_from_params, :only => [:new, :create]
29 before_filter :build_new_issue_from_params, :only => [:new, :create]
30 accept_rss_auth :index, :show
30 accept_rss_auth :index, :show
31 accept_api_auth :index, :show, :create, :update, :destroy
31 accept_api_auth :index, :show, :create, :update, :destroy
32
32
33 rescue_from Query::StatementInvalid, :with => :query_statement_invalid
33 rescue_from Query::StatementInvalid, :with => :query_statement_invalid
34
34
35 helper :journals
35 helper :journals
36 helper :projects
36 helper :projects
37 include ProjectsHelper
37 include ProjectsHelper
38 helper :custom_fields
38 helper :custom_fields
39 include CustomFieldsHelper
39 include CustomFieldsHelper
40 helper :issue_relations
40 helper :issue_relations
41 include IssueRelationsHelper
41 include IssueRelationsHelper
42 helper :watchers
42 helper :watchers
43 include WatchersHelper
43 include WatchersHelper
44 helper :attachments
44 helper :attachments
45 include AttachmentsHelper
45 include AttachmentsHelper
46 helper :queries
46 helper :queries
47 include QueriesHelper
47 include QueriesHelper
48 helper :repositories
48 helper :repositories
49 include RepositoriesHelper
49 include RepositoriesHelper
50 helper :sort
50 helper :sort
51 include SortHelper
51 include SortHelper
52 include IssuesHelper
52 include IssuesHelper
53 helper :timelog
53 helper :timelog
54 helper :gantt
54 helper :gantt
55 include Redmine::Export::PDF
55 include Redmine::Export::PDF
56
56
57 verify :method => :post, :only => :create, :render => {:nothing => true, :status => :method_not_allowed }
57 verify :method => :post, :only => :create, :render => {:nothing => true, :status => :method_not_allowed }
58 verify :method => :post, :only => :bulk_update, :render => {:nothing => true, :status => :method_not_allowed }
58 verify :method => :post, :only => :bulk_update, :render => {:nothing => true, :status => :method_not_allowed }
59 verify :method => :put, :only => :update, :render => {:nothing => true, :status => :method_not_allowed }
59 verify :method => :put, :only => :update, :render => {:nothing => true, :status => :method_not_allowed }
60
60
61 def index
61 def index
62 retrieve_query
62 retrieve_query
63 sort_init(@query.sort_criteria.empty? ? [['id', 'desc']] : @query.sort_criteria)
63 sort_init(@query.sort_criteria.empty? ? [['id', 'desc']] : @query.sort_criteria)
64 sort_update(@query.sortable_columns)
64 sort_update(@query.sortable_columns)
65
65
66 if @query.valid?
66 if @query.valid?
67 case params[:format]
67 case params[:format]
68 when 'csv', 'pdf'
68 when 'csv', 'pdf'
69 @limit = Setting.issues_export_limit.to_i
69 @limit = Setting.issues_export_limit.to_i
70 when 'atom'
70 when 'atom'
71 @limit = Setting.feeds_limit.to_i
71 @limit = Setting.feeds_limit.to_i
72 when 'xml', 'json'
72 when 'xml', 'json'
73 @offset, @limit = api_offset_and_limit
73 @offset, @limit = api_offset_and_limit
74 else
74 else
75 @limit = per_page_option
75 @limit = per_page_option
76 end
76 end
77
77
78 @issue_count = @query.issue_count
78 @issue_count = @query.issue_count
79 @issue_pages = Paginator.new self, @issue_count, @limit, params['page']
79 @issue_pages = Paginator.new self, @issue_count, @limit, params['page']
80 @offset ||= @issue_pages.current.offset
80 @offset ||= @issue_pages.current.offset
81 @issues = @query.issues(:include => [:assigned_to, :tracker, :priority, :category, :fixed_version],
81 @issues = @query.issues(:include => [:assigned_to, :tracker, :priority, :category, :fixed_version],
82 :order => sort_clause,
82 :order => sort_clause,
83 :offset => @offset,
83 :offset => @offset,
84 :limit => @limit)
84 :limit => @limit)
85 @issue_count_by_group = @query.issue_count_by_group
85 @issue_count_by_group = @query.issue_count_by_group
86
86
87 respond_to do |format|
87 respond_to do |format|
88 format.html { render :template => 'issues/index', :layout => !request.xhr? }
88 format.html { render :template => 'issues/index', :layout => !request.xhr? }
89 format.api {
89 format.api {
90 Issue.load_relations(@issues) if include_in_api_response?('relations')
90 Issue.load_relations(@issues) if include_in_api_response?('relations')
91 }
91 }
92 format.atom { render_feed(@issues, :title => "#{@project || Setting.app_title}: #{l(:label_issue_plural)}") }
92 format.atom { render_feed(@issues, :title => "#{@project || Setting.app_title}: #{l(:label_issue_plural)}") }
93 format.csv { send_data(issues_to_csv(@issues, @project, @query, params), :type => 'text/csv; header=present', :filename => 'export.csv') }
93 format.csv { send_data(issues_to_csv(@issues, @project, @query, params), :type => 'text/csv; header=present', :filename => 'export.csv') }
94 format.pdf { send_data(issues_to_pdf(@issues, @project, @query), :type => 'application/pdf', :filename => 'export.pdf') }
94 format.pdf { send_data(issues_to_pdf(@issues, @project, @query), :type => 'application/pdf', :filename => 'export.pdf') }
95 end
95 end
96 else
96 else
97 respond_to do |format|
97 respond_to do |format|
98 format.html { render(:template => 'issues/index', :layout => !request.xhr?) }
98 format.html { render(:template => 'issues/index', :layout => !request.xhr?) }
99 format.any(:atom, :csv, :pdf) { render(:nothing => true) }
99 format.any(:atom, :csv, :pdf) { render(:nothing => true) }
100 format.api { render_validation_errors(@query) }
100 format.api { render_validation_errors(@query) }
101 end
101 end
102 end
102 end
103 rescue ActiveRecord::RecordNotFound
103 rescue ActiveRecord::RecordNotFound
104 render_404
104 render_404
105 end
105 end
106
106
107 def show
107 def show
108 @journals = @issue.journals.find(:all, :include => [:user, :details], :order => "#{Journal.table_name}.created_on ASC")
108 @journals = @issue.journals.find(:all, :include => [:user, :details], :order => "#{Journal.table_name}.created_on ASC")
109 @journals.each_with_index {|j,i| j.indice = i+1}
109 @journals.each_with_index {|j,i| j.indice = i+1}
110 @journals.reverse! if User.current.wants_comments_in_reverse_order?
110 @journals.reverse! if User.current.wants_comments_in_reverse_order?
111
111
112 if User.current.allowed_to?(:view_changesets, @project)
112 if User.current.allowed_to?(:view_changesets, @project)
113 @changesets = @issue.changesets.visible.all
113 @changesets = @issue.changesets.visible.all
114 @changesets.reverse! if User.current.wants_comments_in_reverse_order?
114 @changesets.reverse! if User.current.wants_comments_in_reverse_order?
115 end
115 end
116
116
117 @relations = @issue.relations.select {|r| r.other_issue(@issue) && r.other_issue(@issue).visible? }
117 @relations = @issue.relations.select {|r| r.other_issue(@issue) && r.other_issue(@issue).visible? }
118 @allowed_statuses = @issue.new_statuses_allowed_to(User.current)
118 @allowed_statuses = @issue.new_statuses_allowed_to(User.current)
119 @edit_allowed = User.current.allowed_to?(:edit_issues, @project)
119 @edit_allowed = User.current.allowed_to?(:edit_issues, @project)
120 @priorities = IssuePriority.active
120 @priorities = IssuePriority.active
121 @time_entry = TimeEntry.new(:issue => @issue, :project => @issue.project)
121 @time_entry = TimeEntry.new(:issue => @issue, :project => @issue.project)
122 respond_to do |format|
122 respond_to do |format|
123 format.html {
123 format.html {
124 retrieve_previous_and_next_issue_ids
124 retrieve_previous_and_next_issue_ids
125 render :template => 'issues/show'
125 render :template => 'issues/show'
126 }
126 }
127 format.api
127 format.api
128 format.atom { render :template => 'journals/index', :layout => false, :content_type => 'application/atom+xml' }
128 format.atom { render :template => 'journals/index', :layout => false, :content_type => 'application/atom+xml' }
129 format.pdf { send_data(issue_to_pdf(@issue), :type => 'application/pdf', :filename => "#{@project.identifier}-#{@issue.id}.pdf") }
129 format.pdf { send_data(issue_to_pdf(@issue), :type => 'application/pdf', :filename => "#{@project.identifier}-#{@issue.id}.pdf") }
130 end
130 end
131 end
131 end
132
132
133 # Add a new issue
133 # Add a new issue
134 # The new issue will be created from an existing one if copy_from parameter is given
134 # The new issue will be created from an existing one if copy_from parameter is given
135 def new
135 def new
136 respond_to do |format|
136 respond_to do |format|
137 format.html { render :action => 'new', :layout => !request.xhr? }
137 format.html { render :action => 'new', :layout => !request.xhr? }
138 format.js {
138 format.js {
139 render(:update) { |page|
139 render(:update) { |page|
140 if params[:project_change]
140 if params[:project_change]
141 page.replace_html 'all_attributes', :partial => 'form'
141 page.replace_html 'all_attributes', :partial => 'form'
142 else
142 else
143 page.replace_html 'attributes', :partial => 'attributes'
143 page.replace_html 'attributes', :partial => 'attributes'
144 end
144 end
145 m = User.current.allowed_to?(:log_time, @issue.project) ? 'show' : 'hide'
145 m = User.current.allowed_to?(:log_time, @issue.project) ? 'show' : 'hide'
146 page << "if ($('log_time')) {Element.#{m}('log_time');}"
146 page << "if ($('log_time')) {Element.#{m}('log_time');}"
147 }
147 }
148 }
148 }
149 end
149 end
150 end
150 end
151
151
152 def create
152 def create
153 call_hook(:controller_issues_new_before_save, { :params => params, :issue => @issue })
153 call_hook(:controller_issues_new_before_save, { :params => params, :issue => @issue })
154 if @issue.save
154 if @issue.save
155 attachments = Attachment.attach_files(@issue, params[:attachments])
155 attachments = Attachment.attach_files(@issue, params[:attachments])
156 call_hook(:controller_issues_new_after_save, { :params => params, :issue => @issue})
156 call_hook(:controller_issues_new_after_save, { :params => params, :issue => @issue})
157 respond_to do |format|
157 respond_to do |format|
158 format.html {
158 format.html {
159 render_attachment_warning_if_needed(@issue)
159 render_attachment_warning_if_needed(@issue)
160 flash[:notice] = l(:notice_issue_successful_create, :id => "<a href='#{issue_path(@issue)}'>##{@issue.id}</a>")
160 flash[:notice] = l(:notice_issue_successful_create, :id => "<a href='#{issue_path(@issue)}'>##{@issue.id}</a>")
161 redirect_to(params[:continue] ? { :action => 'new', :project_id => @project, :issue => {:tracker_id => @issue.tracker, :parent_issue_id => @issue.parent_issue_id}.reject {|k,v| v.nil?} } :
161 redirect_to(params[:continue] ? { :action => 'new', :project_id => @project, :issue => {:tracker_id => @issue.tracker, :parent_issue_id => @issue.parent_issue_id}.reject {|k,v| v.nil?} } :
162 { :action => 'show', :id => @issue })
162 { :action => 'show', :id => @issue })
163 }
163 }
164 format.api { render :action => 'show', :status => :created, :location => issue_url(@issue) }
164 format.api { render :action => 'show', :status => :created, :location => issue_url(@issue) }
165 end
165 end
166 return
166 return
167 else
167 else
168 respond_to do |format|
168 respond_to do |format|
169 format.html { render :action => 'new' }
169 format.html { render :action => 'new' }
170 format.api { render_validation_errors(@issue) }
170 format.api { render_validation_errors(@issue) }
171 end
171 end
172 end
172 end
173 end
173 end
174
174
175 def edit
175 def edit
176 update_issue_from_params
176 update_issue_from_params
177
177
178 @journal = @issue.current_journal
178 @journal = @issue.current_journal
179
179
180 respond_to do |format|
180 respond_to do |format|
181 format.html { }
181 format.html { }
182 format.xml { }
182 format.xml { }
183 end
183 end
184 end
184 end
185
185
186 def update
186 def update
187 update_issue_from_params
187 update_issue_from_params
188
188
189 if @issue.save_issue_with_child_records(params, @time_entry)
189 if @issue.save_issue_with_child_records(params, @time_entry)
190 render_attachment_warning_if_needed(@issue)
190 render_attachment_warning_if_needed(@issue)
191 flash[:notice] = l(:notice_successful_update) unless @issue.current_journal.new_record?
191 flash[:notice] = l(:notice_successful_update) unless @issue.current_journal.new_record?
192
192
193 respond_to do |format|
193 respond_to do |format|
194 format.html { redirect_back_or_default({:action => 'show', :id => @issue}) }
194 format.html { redirect_back_or_default({:action => 'show', :id => @issue}) }
195 format.api { head :ok }
195 format.api { head :ok }
196 end
196 end
197 else
197 else
198 render_attachment_warning_if_needed(@issue)
198 render_attachment_warning_if_needed(@issue)
199 flash[:notice] = l(:notice_successful_update) unless @issue.current_journal.new_record?
199 flash[:notice] = l(:notice_successful_update) unless @issue.current_journal.new_record?
200 @journal = @issue.current_journal
200 @journal = @issue.current_journal
201
201
202 respond_to do |format|
202 respond_to do |format|
203 format.html { render :action => 'edit' }
203 format.html { render :action => 'edit' }
204 format.api { render_validation_errors(@issue) }
204 format.api { render_validation_errors(@issue) }
205 end
205 end
206 end
206 end
207 end
207 end
208
208
209 # Bulk edit a set of issues
209 # Bulk edit/copy a set of issues
210 def bulk_edit
210 def bulk_edit
211 @issues.sort!
211 @issues.sort!
212 @copy = params[:copy].present?
213 @notes = params[:notes]
212
214
213 if User.current.allowed_to?(:move_issues, @projects)
215 if User.current.allowed_to?(:move_issues, @projects)
214 @allowed_projects = Issue.allowed_target_projects_on_move
216 @allowed_projects = Issue.allowed_target_projects_on_move
215 if params[:issue]
217 if params[:issue]
216 @target_project = @allowed_projects.detect {|p| p.id.to_s == params[:issue][:project_id]}
218 @target_project = @allowed_projects.detect {|p| p.id.to_s == params[:issue][:project_id]}
217 if @target_project
219 if @target_project
218 target_projects = [@target_project]
220 target_projects = [@target_project]
219 end
221 end
220 end
222 end
221 end
223 end
222 target_projects ||= @projects
224 target_projects ||= @projects
223
225
224 @available_statuses = target_projects.map{|p|Workflow.available_statuses(p)}.inject{|memo,w|memo & w}
226 @available_statuses = target_projects.map{|p|Workflow.available_statuses(p)}.inject{|memo,w|memo & w}
225 @custom_fields = target_projects.map{|p|p.all_issue_custom_fields}.inject{|memo,c|memo & c}
227 @custom_fields = target_projects.map{|p|p.all_issue_custom_fields}.inject{|memo,c|memo & c}
226 @assignables = target_projects.map(&:assignable_users).inject{|memo,a| memo & a}
228 @assignables = target_projects.map(&:assignable_users).inject{|memo,a| memo & a}
227 @trackers = target_projects.map(&:trackers).inject{|memo,t| memo & t}
229 @trackers = target_projects.map(&:trackers).inject{|memo,t| memo & t}
228
230
229 @notes = params[:notes]
230 render :layout => false if request.xhr?
231 render :layout => false if request.xhr?
231 end
232 end
232
233
233 def bulk_update
234 def bulk_update
234 @issues.sort!
235 @issues.sort!
236 @copy = params[:copy].present?
235 attributes = parse_params_for_bulk_issue_attributes(params)
237 attributes = parse_params_for_bulk_issue_attributes(params)
236
238
237 unsaved_issue_ids = []
239 unsaved_issue_ids = []
238 moved_issues = []
240 moved_issues = []
239 @issues.each do |issue|
241 @issues.each do |issue|
240 issue.reload
242 issue.reload
243 if @copy
244 issue = Issue.new.copy_from(issue)
245 end
241 journal = issue.init_journal(User.current, params[:notes])
246 journal = issue.init_journal(User.current, params[:notes])
242 issue.safe_attributes = attributes
247 issue.safe_attributes = attributes
243 call_hook(:controller_issues_bulk_edit_before_save, { :params => params, :issue => issue })
248 call_hook(:controller_issues_bulk_edit_before_save, { :params => params, :issue => issue })
244 if issue.save
249 if issue.save
245 moved_issues << issue
250 moved_issues << issue
246 else
251 else
247 # Keep unsaved issue ids to display them in flash error
252 # Keep unsaved issue ids to display them in flash error
248 unsaved_issue_ids << issue.id
253 unsaved_issue_ids << issue.id
249 end
254 end
250 end
255 end
251 set_flash_from_bulk_issue_save(@issues, unsaved_issue_ids)
256 set_flash_from_bulk_issue_save(@issues, unsaved_issue_ids)
252
257
253 if params[:follow]
258 if params[:follow]
254 if @issues.size == 1 && moved_issues.size == 1
259 if @issues.size == 1 && moved_issues.size == 1
255 redirect_to :controller => 'issues', :action => 'show', :id => moved_issues.first
260 redirect_to :controller => 'issues', :action => 'show', :id => moved_issues.first
256 elsif moved_issues.map(&:project).uniq.size == 1
261 elsif moved_issues.map(&:project).uniq.size == 1
257 redirect_to :controller => 'issues', :action => 'index', :project_id => moved_issues.map(&:project).first
262 redirect_to :controller => 'issues', :action => 'index', :project_id => moved_issues.map(&:project).first
258 end
263 end
259 else
264 else
260 redirect_back_or_default({:controller => 'issues', :action => 'index', :project_id => @project})
265 redirect_back_or_default({:controller => 'issues', :action => 'index', :project_id => @project})
261 end
266 end
262 end
267 end
263
268
264 verify :method => :delete, :only => :destroy, :render => { :nothing => true, :status => :method_not_allowed }
269 verify :method => :delete, :only => :destroy, :render => { :nothing => true, :status => :method_not_allowed }
265 def destroy
270 def destroy
266 @hours = TimeEntry.sum(:hours, :conditions => ['issue_id IN (?)', @issues]).to_f
271 @hours = TimeEntry.sum(:hours, :conditions => ['issue_id IN (?)', @issues]).to_f
267 if @hours > 0
272 if @hours > 0
268 case params[:todo]
273 case params[:todo]
269 when 'destroy'
274 when 'destroy'
270 # nothing to do
275 # nothing to do
271 when 'nullify'
276 when 'nullify'
272 TimeEntry.update_all('issue_id = NULL', ['issue_id IN (?)', @issues])
277 TimeEntry.update_all('issue_id = NULL', ['issue_id IN (?)', @issues])
273 when 'reassign'
278 when 'reassign'
274 reassign_to = @project.issues.find_by_id(params[:reassign_to_id])
279 reassign_to = @project.issues.find_by_id(params[:reassign_to_id])
275 if reassign_to.nil?
280 if reassign_to.nil?
276 flash.now[:error] = l(:error_issue_not_found_in_project)
281 flash.now[:error] = l(:error_issue_not_found_in_project)
277 return
282 return
278 else
283 else
279 TimeEntry.update_all("issue_id = #{reassign_to.id}", ['issue_id IN (?)', @issues])
284 TimeEntry.update_all("issue_id = #{reassign_to.id}", ['issue_id IN (?)', @issues])
280 end
285 end
281 else
286 else
282 # display the destroy form if it's a user request
287 # display the destroy form if it's a user request
283 return unless api_request?
288 return unless api_request?
284 end
289 end
285 end
290 end
286 @issues.each do |issue|
291 @issues.each do |issue|
287 begin
292 begin
288 issue.reload.destroy
293 issue.reload.destroy
289 rescue ::ActiveRecord::RecordNotFound # raised by #reload if issue no longer exists
294 rescue ::ActiveRecord::RecordNotFound # raised by #reload if issue no longer exists
290 # nothing to do, issue was already deleted (eg. by a parent)
295 # nothing to do, issue was already deleted (eg. by a parent)
291 end
296 end
292 end
297 end
293 respond_to do |format|
298 respond_to do |format|
294 format.html { redirect_back_or_default(:action => 'index', :project_id => @project) }
299 format.html { redirect_back_or_default(:action => 'index', :project_id => @project) }
295 format.api { head :ok }
300 format.api { head :ok }
296 end
301 end
297 end
302 end
298
303
299 private
304 private
300 def find_issue
305 def find_issue
301 # Issue.visible.find(...) can not be used to redirect user to the login form
306 # Issue.visible.find(...) can not be used to redirect user to the login form
302 # if the issue actually exists but requires authentication
307 # if the issue actually exists but requires authentication
303 @issue = Issue.find(params[:id], :include => [:project, :tracker, :status, :author, :priority, :category])
308 @issue = Issue.find(params[:id], :include => [:project, :tracker, :status, :author, :priority, :category])
304 unless @issue.visible?
309 unless @issue.visible?
305 deny_access
310 deny_access
306 return
311 return
307 end
312 end
308 @project = @issue.project
313 @project = @issue.project
309 rescue ActiveRecord::RecordNotFound
314 rescue ActiveRecord::RecordNotFound
310 render_404
315 render_404
311 end
316 end
312
317
313 def find_project
318 def find_project
314 project_id = params[:project_id] || (params[:issue] && params[:issue][:project_id])
319 project_id = params[:project_id] || (params[:issue] && params[:issue][:project_id])
315 @project = Project.find(project_id)
320 @project = Project.find(project_id)
316 rescue ActiveRecord::RecordNotFound
321 rescue ActiveRecord::RecordNotFound
317 render_404
322 render_404
318 end
323 end
319
324
320 def retrieve_previous_and_next_issue_ids
325 def retrieve_previous_and_next_issue_ids
321 retrieve_query_from_session
326 retrieve_query_from_session
322 if @query
327 if @query
323 sort_init(@query.sort_criteria.empty? ? [['id', 'desc']] : @query.sort_criteria)
328 sort_init(@query.sort_criteria.empty? ? [['id', 'desc']] : @query.sort_criteria)
324 sort_update(@query.sortable_columns, 'issues_index_sort')
329 sort_update(@query.sortable_columns, 'issues_index_sort')
325 limit = 500
330 limit = 500
326 issue_ids = @query.issue_ids(:order => sort_clause, :limit => (limit + 1))
331 issue_ids = @query.issue_ids(:order => sort_clause, :limit => (limit + 1))
327 if (idx = issue_ids.index(@issue.id)) && idx < limit
332 if (idx = issue_ids.index(@issue.id)) && idx < limit
328 @prev_issue_id = issue_ids[idx - 1] if idx > 0
333 @prev_issue_id = issue_ids[idx - 1] if idx > 0
329 @next_issue_id = issue_ids[idx + 1] if idx < (issue_ids.size - 1)
334 @next_issue_id = issue_ids[idx + 1] if idx < (issue_ids.size - 1)
330 end
335 end
331 end
336 end
332 end
337 end
333
338
334 # Used by #edit and #update to set some common instance variables
339 # Used by #edit and #update to set some common instance variables
335 # from the params
340 # from the params
336 # TODO: Refactor, not everything in here is needed by #edit
341 # TODO: Refactor, not everything in here is needed by #edit
337 def update_issue_from_params
342 def update_issue_from_params
338 @allowed_statuses = @issue.new_statuses_allowed_to(User.current)
343 @allowed_statuses = @issue.new_statuses_allowed_to(User.current)
339 @priorities = IssuePriority.active
344 @priorities = IssuePriority.active
340 @edit_allowed = User.current.allowed_to?(:edit_issues, @project)
345 @edit_allowed = User.current.allowed_to?(:edit_issues, @project)
341 @time_entry = TimeEntry.new(:issue => @issue, :project => @issue.project)
346 @time_entry = TimeEntry.new(:issue => @issue, :project => @issue.project)
342 @time_entry.attributes = params[:time_entry]
347 @time_entry.attributes = params[:time_entry]
343
348
344 @notes = params[:notes] || (params[:issue].present? ? params[:issue][:notes] : nil)
349 @notes = params[:notes] || (params[:issue].present? ? params[:issue][:notes] : nil)
345 @issue.init_journal(User.current, @notes)
350 @issue.init_journal(User.current, @notes)
346 @issue.safe_attributes = params[:issue]
351 @issue.safe_attributes = params[:issue]
347 end
352 end
348
353
349 # TODO: Refactor, lots of extra code in here
354 # TODO: Refactor, lots of extra code in here
350 # TODO: Changing tracker on an existing issue should not trigger this
355 # TODO: Changing tracker on an existing issue should not trigger this
351 def build_new_issue_from_params
356 def build_new_issue_from_params
352 if params[:id].blank?
357 if params[:id].blank?
353 @issue = Issue.new
358 @issue = Issue.new
354 @issue.copy_from(params[:copy_from]) if params[:copy_from]
359 @issue.copy_from(params[:copy_from]) if params[:copy_from]
355 @issue.project = @project
360 @issue.project = @project
356 else
361 else
357 @issue = @project.issues.visible.find(params[:id])
362 @issue = @project.issues.visible.find(params[:id])
358 end
363 end
359
364
360 @issue.project = @project
365 @issue.project = @project
361 @issue.author = User.current
366 @issue.author = User.current
362 # Tracker must be set before custom field values
367 # Tracker must be set before custom field values
363 @issue.tracker ||= @project.trackers.find((params[:issue] && params[:issue][:tracker_id]) || params[:tracker_id] || :first)
368 @issue.tracker ||= @project.trackers.find((params[:issue] && params[:issue][:tracker_id]) || params[:tracker_id] || :first)
364 if @issue.tracker.nil?
369 if @issue.tracker.nil?
365 render_error l(:error_no_tracker_in_project)
370 render_error l(:error_no_tracker_in_project)
366 return false
371 return false
367 end
372 end
368 @issue.start_date ||= Date.today if Setting.default_issue_start_date_to_creation_date?
373 @issue.start_date ||= Date.today if Setting.default_issue_start_date_to_creation_date?
369 @issue.safe_attributes = params[:issue]
374 @issue.safe_attributes = params[:issue]
370
375
371 @priorities = IssuePriority.active
376 @priorities = IssuePriority.active
372 @allowed_statuses = @issue.new_statuses_allowed_to(User.current, true)
377 @allowed_statuses = @issue.new_statuses_allowed_to(User.current, true)
373 end
378 end
374
379
375 def check_for_default_issue_status
380 def check_for_default_issue_status
376 if IssueStatus.default.nil?
381 if IssueStatus.default.nil?
377 render_error l(:error_no_default_issue_status)
382 render_error l(:error_no_default_issue_status)
378 return false
383 return false
379 end
384 end
380 end
385 end
381
386
382 def parse_params_for_bulk_issue_attributes(params)
387 def parse_params_for_bulk_issue_attributes(params)
383 attributes = (params[:issue] || {}).reject {|k,v| v.blank?}
388 attributes = (params[:issue] || {}).reject {|k,v| v.blank?}
384 attributes.keys.each {|k| attributes[k] = '' if attributes[k] == 'none'}
389 attributes.keys.each {|k| attributes[k] = '' if attributes[k] == 'none'}
385 attributes[:custom_field_values].reject! {|k,v| v.blank?} if attributes[:custom_field_values]
390 attributes[:custom_field_values].reject! {|k,v| v.blank?} if attributes[:custom_field_values]
386 attributes
391 attributes
387 end
392 end
388 end
393 end
@@ -1,119 +1,119
1 <ul>
1 <ul>
2 <%= call_hook(:view_issues_context_menu_start, {:issues => @issues, :can => @can, :back => @back }) %>
2 <%= call_hook(:view_issues_context_menu_start, {:issues => @issues, :can => @can, :back => @back }) %>
3
3
4 <% if !@issue.nil? -%>
4 <% if !@issue.nil? -%>
5 <li><%= context_menu_link l(:button_edit), {:controller => 'issues', :action => 'edit', :id => @issue},
5 <li><%= context_menu_link l(:button_edit), {:controller => 'issues', :action => 'edit', :id => @issue},
6 :class => 'icon-edit', :disabled => !@can[:edit] %></li>
6 :class => 'icon-edit', :disabled => !@can[:edit] %></li>
7 <% else %>
7 <% else %>
8 <li><%= context_menu_link l(:button_edit), {:controller => 'issues', :action => 'bulk_edit', :ids => @issues.collect(&:id)},
8 <li><%= context_menu_link l(:button_edit), {:controller => 'issues', :action => 'bulk_edit', :ids => @issues.collect(&:id)},
9 :class => 'icon-edit', :disabled => !@can[:edit] %></li>
9 :class => 'icon-edit', :disabled => !@can[:edit] %></li>
10 <% end %>
10 <% end %>
11
11
12 <% if @allowed_statuses.present? %>
12 <% if @allowed_statuses.present? %>
13 <li class="folder">
13 <li class="folder">
14 <a href="#" class="submenu" onclick="return false;"><%= l(:field_status) %></a>
14 <a href="#" class="submenu" onclick="return false;"><%= l(:field_status) %></a>
15 <ul>
15 <ul>
16 <% @statuses.each do |s| -%>
16 <% @statuses.each do |s| -%>
17 <li><%= context_menu_link h(s.name), {:controller => 'issues', :action => 'bulk_update', :ids => @issues.collect(&:id), :issue => {:status_id => s}, :back_url => @back}, :method => :post,
17 <li><%= context_menu_link h(s.name), {:controller => 'issues', :action => 'bulk_update', :ids => @issues.collect(&:id), :issue => {:status_id => s}, :back_url => @back}, :method => :post,
18 :selected => (@issue && s == @issue.status), :disabled => !(@can[:update] && @allowed_statuses.include?(s)) %></li>
18 :selected => (@issue && s == @issue.status), :disabled => !(@can[:update] && @allowed_statuses.include?(s)) %></li>
19 <% end -%>
19 <% end -%>
20 </ul>
20 </ul>
21 </li>
21 </li>
22 <% end %>
22 <% end %>
23
23
24 <% unless @trackers.nil? %>
24 <% unless @trackers.nil? %>
25 <li class="folder">
25 <li class="folder">
26 <a href="#" class="submenu"><%= l(:field_tracker) %></a>
26 <a href="#" class="submenu"><%= l(:field_tracker) %></a>
27 <ul>
27 <ul>
28 <% @trackers.each do |t| -%>
28 <% @trackers.each do |t| -%>
29 <li><%= context_menu_link h(t.name), {:controller => 'issues', :action => 'bulk_update', :ids => @issues.collect(&:id), :issue => {'tracker_id' => t}, :back_url => @back}, :method => :post,
29 <li><%= context_menu_link h(t.name), {:controller => 'issues', :action => 'bulk_update', :ids => @issues.collect(&:id), :issue => {'tracker_id' => t}, :back_url => @back}, :method => :post,
30 :selected => (@issue && t == @issue.tracker), :disabled => !@can[:edit] %></li>
30 :selected => (@issue && t == @issue.tracker), :disabled => !@can[:edit] %></li>
31 <% end -%>
31 <% end -%>
32 </ul>
32 </ul>
33 </li>
33 </li>
34 <% end %>
34 <% end %>
35
35
36 <li class="folder">
36 <li class="folder">
37 <a href="#" class="submenu"><%= l(:field_priority) %></a>
37 <a href="#" class="submenu"><%= l(:field_priority) %></a>
38 <ul>
38 <ul>
39 <% @priorities.each do |p| -%>
39 <% @priorities.each do |p| -%>
40 <li><%= context_menu_link h(p.name), {:controller => 'issues', :action => 'bulk_update', :ids => @issues.collect(&:id), :issue => {'priority_id' => p}, :back_url => @back}, :method => :post,
40 <li><%= context_menu_link h(p.name), {:controller => 'issues', :action => 'bulk_update', :ids => @issues.collect(&:id), :issue => {'priority_id' => p}, :back_url => @back}, :method => :post,
41 :selected => (@issue && p == @issue.priority), :disabled => (!@can[:edit] || @issues.detect {|i| !i.leaf?}) %></li>
41 :selected => (@issue && p == @issue.priority), :disabled => (!@can[:edit] || @issues.detect {|i| !i.leaf?}) %></li>
42 <% end -%>
42 <% end -%>
43 </ul>
43 </ul>
44 </li>
44 </li>
45
45
46 <% #TODO: allow editing versions when multiple projects %>
46 <% #TODO: allow editing versions when multiple projects %>
47 <% unless @project.nil? || @project.shared_versions.open.empty? -%>
47 <% unless @project.nil? || @project.shared_versions.open.empty? -%>
48 <li class="folder">
48 <li class="folder">
49 <a href="#" class="submenu"><%= l(:field_fixed_version) %></a>
49 <a href="#" class="submenu"><%= l(:field_fixed_version) %></a>
50 <ul>
50 <ul>
51 <% @project.shared_versions.open.sort.each do |v| -%>
51 <% @project.shared_versions.open.sort.each do |v| -%>
52 <li><%= context_menu_link format_version_name(v), {:controller => 'issues', :action => 'bulk_update', :ids => @issues.collect(&:id), :issue => {'fixed_version_id' => v}, :back_url => @back}, :method => :post,
52 <li><%= context_menu_link format_version_name(v), {:controller => 'issues', :action => 'bulk_update', :ids => @issues.collect(&:id), :issue => {'fixed_version_id' => v}, :back_url => @back}, :method => :post,
53 :selected => (@issue && v == @issue.fixed_version), :disabled => !@can[:update] %></li>
53 :selected => (@issue && v == @issue.fixed_version), :disabled => !@can[:update] %></li>
54 <% end -%>
54 <% end -%>
55 <li><%= context_menu_link l(:label_none), {:controller => 'issues', :action => 'bulk_update', :ids => @issues.collect(&:id), :issue => {'fixed_version_id' => 'none'}, :back_url => @back}, :method => :post,
55 <li><%= context_menu_link l(:label_none), {:controller => 'issues', :action => 'bulk_update', :ids => @issues.collect(&:id), :issue => {'fixed_version_id' => 'none'}, :back_url => @back}, :method => :post,
56 :selected => (@issue && @issue.fixed_version.nil?), :disabled => !@can[:update] %></li>
56 :selected => (@issue && @issue.fixed_version.nil?), :disabled => !@can[:update] %></li>
57 </ul>
57 </ul>
58 </li>
58 </li>
59 <% end %>
59 <% end %>
60 <% if @assignables.present? -%>
60 <% if @assignables.present? -%>
61 <li class="folder">
61 <li class="folder">
62 <a href="#" class="submenu"><%= l(:field_assigned_to) %></a>
62 <a href="#" class="submenu"><%= l(:field_assigned_to) %></a>
63 <ul>
63 <ul>
64 <% @assignables.each do |u| -%>
64 <% @assignables.each do |u| -%>
65 <li><%= context_menu_link h(u.name), {:controller => 'issues', :action => 'bulk_update', :ids => @issues.collect(&:id), :issue => {'assigned_to_id' => u}, :back_url => @back}, :method => :post,
65 <li><%= context_menu_link h(u.name), {:controller => 'issues', :action => 'bulk_update', :ids => @issues.collect(&:id), :issue => {'assigned_to_id' => u}, :back_url => @back}, :method => :post,
66 :selected => (@issue && u == @issue.assigned_to), :disabled => !@can[:update] %></li>
66 :selected => (@issue && u == @issue.assigned_to), :disabled => !@can[:update] %></li>
67 <% end -%>
67 <% end -%>
68 <li><%= context_menu_link l(:label_nobody), {:controller => 'issues', :action => 'bulk_update', :ids => @issues.collect(&:id), :issue => {'assigned_to_id' => 'none'}, :back_url => @back}, :method => :post,
68 <li><%= context_menu_link l(:label_nobody), {:controller => 'issues', :action => 'bulk_update', :ids => @issues.collect(&:id), :issue => {'assigned_to_id' => 'none'}, :back_url => @back}, :method => :post,
69 :selected => (@issue && @issue.assigned_to.nil?), :disabled => !@can[:update] %></li>
69 :selected => (@issue && @issue.assigned_to.nil?), :disabled => !@can[:update] %></li>
70 </ul>
70 </ul>
71 </li>
71 </li>
72 <% end %>
72 <% end %>
73 <% unless @project.nil? || @project.issue_categories.empty? -%>
73 <% unless @project.nil? || @project.issue_categories.empty? -%>
74 <li class="folder">
74 <li class="folder">
75 <a href="#" class="submenu"><%= l(:field_category) %></a>
75 <a href="#" class="submenu"><%= l(:field_category) %></a>
76 <ul>
76 <ul>
77 <% @project.issue_categories.each do |u| -%>
77 <% @project.issue_categories.each do |u| -%>
78 <li><%= context_menu_link h(u.name), {:controller => 'issues', :action => 'bulk_update', :ids => @issues.collect(&:id), :issue => {'category_id' => u}, :back_url => @back}, :method => :post,
78 <li><%= context_menu_link h(u.name), {:controller => 'issues', :action => 'bulk_update', :ids => @issues.collect(&:id), :issue => {'category_id' => u}, :back_url => @back}, :method => :post,
79 :selected => (@issue && u == @issue.category), :disabled => !@can[:update] %></li>
79 :selected => (@issue && u == @issue.category), :disabled => !@can[:update] %></li>
80 <% end -%>
80 <% end -%>
81 <li><%= context_menu_link l(:label_none), {:controller => 'issues', :action => 'bulk_update', :ids => @issues.collect(&:id), :issue => {'category_id' => 'none'}, :back_url => @back}, :method => :post,
81 <li><%= context_menu_link l(:label_none), {:controller => 'issues', :action => 'bulk_update', :ids => @issues.collect(&:id), :issue => {'category_id' => 'none'}, :back_url => @back}, :method => :post,
82 :selected => (@issue && @issue.category.nil?), :disabled => !@can[:update] %></li>
82 :selected => (@issue && @issue.category.nil?), :disabled => !@can[:update] %></li>
83 </ul>
83 </ul>
84 </li>
84 </li>
85 <% end -%>
85 <% end -%>
86
86
87 <% if Issue.use_field_for_done_ratio? %>
87 <% if Issue.use_field_for_done_ratio? %>
88 <li class="folder">
88 <li class="folder">
89 <a href="#" class="submenu"><%= l(:field_done_ratio) %></a>
89 <a href="#" class="submenu"><%= l(:field_done_ratio) %></a>
90 <ul>
90 <ul>
91 <% (0..10).map{|x|x*10}.each do |p| -%>
91 <% (0..10).map{|x|x*10}.each do |p| -%>
92 <li><%= context_menu_link "#{p}%", {:controller => 'issues', :action => 'bulk_update', :ids => @issues.collect(&:id), :issue => {'done_ratio' => p}, :back_url => @back}, :method => :post,
92 <li><%= context_menu_link "#{p}%", {:controller => 'issues', :action => 'bulk_update', :ids => @issues.collect(&:id), :issue => {'done_ratio' => p}, :back_url => @back}, :method => :post,
93 :selected => (@issue && p == @issue.done_ratio), :disabled => (!@can[:edit] || @issues.detect {|i| !i.leaf?}) %></li>
93 :selected => (@issue && p == @issue.done_ratio), :disabled => (!@can[:edit] || @issues.detect {|i| !i.leaf?}) %></li>
94 <% end -%>
94 <% end -%>
95 </ul>
95 </ul>
96 </li>
96 </li>
97 <% end %>
97 <% end %>
98
98
99 <% if !@issue.nil? %>
99 <% if !@issue.nil? %>
100 <% if @can[:log_time] -%>
100 <% if @can[:log_time] -%>
101 <li><%= context_menu_link l(:button_log_time), {:controller => 'timelog', :action => 'new', :issue_id => @issue},
101 <li><%= context_menu_link l(:button_log_time), {:controller => 'timelog', :action => 'new', :issue_id => @issue},
102 :class => 'icon-time-add' %></li>
102 :class => 'icon-time-add' %></li>
103 <% end %>
103 <% end %>
104 <% if User.current.logged? %>
104 <% if User.current.logged? %>
105 <li><%= watcher_link(@issue, User.current) %></li>
105 <li><%= watcher_link(@issue, User.current) %></li>
106 <% end %>
106 <% end %>
107 <% end %>
107 <% end %>
108
108
109 <% if @issue.present? %>
109 <% if @issue.present? %>
110 <li><%= context_menu_link l(:button_duplicate), {:controller => 'issues', :action => 'new', :project_id => @project, :copy_from => @issue},
110 <li><%= context_menu_link l(:button_duplicate), {:controller => 'issues', :action => 'new', :project_id => @project, :copy_from => @issue},
111 :class => 'icon-duplicate', :disabled => !@can[:copy] %></li>
111 :class => 'icon-duplicate', :disabled => !@can[:copy] %></li>
112 <% end %>
112 <% end %>
113 <li><%= context_menu_link l(:button_copy), new_issue_move_path(:ids => @issues.collect(&:id), :copy_options => {:copy => 't'}),
113 <li><%= context_menu_link l(:button_copy), {:controller => 'issues', :action => 'bulk_edit', :ids => @issues.collect(&:id), :copy => '1'},
114 :class => 'icon-copy', :disabled => !@can[:move] %></li>
114 :class => 'icon-copy', :disabled => !@can[:move] %></li>
115 <li><%= context_menu_link l(:button_delete), issues_path(:ids => @issues.collect(&:id), :back_url => @back),
115 <li><%= context_menu_link l(:button_delete), issues_path(:ids => @issues.collect(&:id), :back_url => @back),
116 :method => :delete, :confirm => issues_destroy_confirmation_message(@issues), :class => 'icon-del', :disabled => !@can[:delete] %></li>
116 :method => :delete, :confirm => issues_destroy_confirmation_message(@issues), :class => 'icon-del', :disabled => !@can[:delete] %></li>
117
117
118 <%= call_hook(:view_issues_context_menu_end, {:issues => @issues, :can => @can, :back => @back }) %>
118 <%= call_hook(:view_issues_context_menu_end, {:issues => @issues, :can => @can, :back => @back }) %>
119 </ul>
119 </ul>
@@ -1,8 +1,8
1 <div class="contextual">
1 <div class="contextual">
2 <%= link_to_if_authorized(l(:button_update), {:controller => 'issues', :action => 'edit', :id => @issue }, :onclick => 'showAndScrollTo("update", "notes"); return false;', :class => 'icon icon-edit', :accesskey => accesskey(:edit)) %>
2 <%= link_to_if_authorized(l(:button_update), {:controller => 'issues', :action => 'edit', :id => @issue }, :onclick => 'showAndScrollTo("update", "notes"); return false;', :class => 'icon icon-edit', :accesskey => accesskey(:edit)) %>
3 <%= link_to_if_authorized l(:button_log_time), {:controller => 'timelog', :action => 'new', :issue_id => @issue}, :class => 'icon icon-time-add' %>
3 <%= link_to_if_authorized l(:button_log_time), {:controller => 'timelog', :action => 'new', :issue_id => @issue}, :class => 'icon icon-time-add' %>
4 <%= watcher_tag(@issue, User.current) %>
4 <%= watcher_tag(@issue, User.current) %>
5 <%= link_to_if_authorized l(:button_duplicate), {:controller => 'issues', :action => 'new', :project_id => @project, :copy_from => @issue }, :class => 'icon icon-duplicate' %>
5 <%= link_to_if_authorized l(:button_duplicate), {:controller => 'issues', :action => 'new', :project_id => @project, :copy_from => @issue }, :class => 'icon icon-duplicate' %>
6 <%= link_to_if_authorized l(:button_copy), {:controller => 'issue_moves', :action => 'new', :id => @issue, :copy_options => {:copy => 't'}}, :class => 'icon icon-copy' %>
6 <%= link_to_if_authorized l(:button_copy), {:controller => 'issues', :action => 'bulk_edit', :id => @issue, :copy => '1'}, :class => 'icon icon-copy' %>
7 <%= link_to l(:button_delete), issue_path(@issue), :confirm => issues_destroy_confirmation_message(@issue), :method => :delete, :class => 'icon icon-del' if User.current.allowed_to?(:delete_issues, @project) %>
7 <%= link_to l(:button_delete), issue_path(@issue), :confirm => issues_destroy_confirmation_message(@issue), :method => :delete, :class => 'icon icon-del' if User.current.allowed_to?(:delete_issues, @project) %>
8 </div>
8 </div>
@@ -1,113 +1,117
1 <h2><%= l(:label_bulk_edit_selected_issues) %></h2>
1 <h2><%= @copy ? l(:button_copy) : l(:label_bulk_edit_selected_issues) %></h2>
2
2
3 <ul><%= @issues.collect {|i|
3 <ul><%= @issues.collect {|i|
4 content_tag('li',
4 content_tag('li',
5 link_to(h("#{i.tracker} ##{i.id}"),
5 link_to(h("#{i.tracker} ##{i.id}"),
6 { :action => 'show', :id => i }
6 { :action => 'show', :id => i }
7 ) + h(": #{i.subject}"))
7 ) + h(": #{i.subject}"))
8 }.join("\n").html_safe %></ul>
8 }.join("\n").html_safe %></ul>
9
9
10 <% form_tag({:action => 'bulk_update'}, :id => 'bulk_edit_form') do %>
10 <% form_tag({:action => 'bulk_update'}, :id => 'bulk_edit_form') do %>
11 <%= @issues.collect {|i| hidden_field_tag('ids[]', i.id)}.join("\n").html_safe %>
11 <%= @issues.collect {|i| hidden_field_tag('ids[]', i.id)}.join("\n").html_safe %>
12 <div class="box tabular">
12 <div class="box tabular">
13 <fieldset class="attributes">
13 <fieldset class="attributes">
14 <legend><%= l(:label_change_properties) %></legend>
14 <legend><%= l(:label_change_properties) %></legend>
15
15
16 <div class="splitcontentleft">
16 <div class="splitcontentleft">
17 <% if @allowed_projects.present? %>
17 <% if @allowed_projects.present? %>
18 <p>
18 <p>
19 <label for="issue_project_id"><%= l(:field_project) %></label>
19 <label for="issue_project_id"><%= l(:field_project) %></label>
20 <%= select_tag('issue[project_id]', "<option value=\"\">#{l(:label_no_change_option)}</option>" + project_tree_options_for_select(@allowed_projects, :selected => @target_project)) %>
20 <%= select_tag('issue[project_id]', "<option value=\"\">#{l(:label_no_change_option)}</option>" + project_tree_options_for_select(@allowed_projects, :selected => @target_project)) %>
21 </p>
21 </p>
22 <%= observe_field :issue_project_id, :url => {:action => 'bulk_edit'},
22 <%= observe_field :issue_project_id, :url => {:action => 'bulk_edit'},
23 :update => 'content',
23 :update => 'content',
24 :with => "Form.serialize('bulk_edit_form')" %>
24 :with => "Form.serialize('bulk_edit_form')" %>
25 <% end %>
25 <% end %>
26 <p>
26 <p>
27 <label for="issue_tracker_id"><%= l(:field_tracker) %></label>
27 <label for="issue_tracker_id"><%= l(:field_tracker) %></label>
28 <%= select_tag('issue[tracker_id]', "<option value=\"\">#{l(:label_no_change_option)}</option>" + options_from_collection_for_select(@trackers, :id, :name)) %>
28 <%= select_tag('issue[tracker_id]', "<option value=\"\">#{l(:label_no_change_option)}</option>" + options_from_collection_for_select(@trackers, :id, :name)) %>
29 </p>
29 </p>
30 <% if @available_statuses.any? %>
30 <% if @available_statuses.any? %>
31 <p>
31 <p>
32 <label for='issue_status_id'><%= l(:field_status) %></label>
32 <label for='issue_status_id'><%= l(:field_status) %></label>
33 <%= select_tag('issue[status_id]', "<option value=\"\">#{l(:label_no_change_option)}</option>" + options_from_collection_for_select(@available_statuses, :id, :name)) %>
33 <%= select_tag('issue[status_id]', "<option value=\"\">#{l(:label_no_change_option)}</option>" + options_from_collection_for_select(@available_statuses, :id, :name)) %>
34 </p>
34 </p>
35 <% end %>
35 <% end %>
36 <p>
36 <p>
37 <label for='issue_priority_id'><%= l(:field_priority) %></label>
37 <label for='issue_priority_id'><%= l(:field_priority) %></label>
38 <%= select_tag('issue[priority_id]', "<option value=\"\">#{l(:label_no_change_option)}</option>" + options_from_collection_for_select(IssuePriority.active, :id, :name)) %>
38 <%= select_tag('issue[priority_id]', "<option value=\"\">#{l(:label_no_change_option)}</option>" + options_from_collection_for_select(IssuePriority.active, :id, :name)) %>
39 </p>
39 </p>
40 <p>
40 <p>
41 <label for='issue_assigned_to_id'><%= l(:field_assigned_to) %></label>
41 <label for='issue_assigned_to_id'><%= l(:field_assigned_to) %></label>
42 <%= select_tag('issue[assigned_to_id]', content_tag('option', l(:label_no_change_option), :value => '') +
42 <%= select_tag('issue[assigned_to_id]', content_tag('option', l(:label_no_change_option), :value => '') +
43 content_tag('option', l(:label_nobody), :value => 'none') +
43 content_tag('option', l(:label_nobody), :value => 'none') +
44 principals_options_for_select(@assignables)) %>
44 principals_options_for_select(@assignables)) %>
45 </p>
45 </p>
46 <% if @project %>
46 <% if @project %>
47 <p>
47 <p>
48 <label for='issue_category_id'><%= l(:field_category) %></label>
48 <label for='issue_category_id'><%= l(:field_category) %></label>
49 <%= select_tag('issue[category_id]', content_tag('option', l(:label_no_change_option), :value => '') +
49 <%= select_tag('issue[category_id]', content_tag('option', l(:label_no_change_option), :value => '') +
50 content_tag('option', l(:label_none), :value => 'none') +
50 content_tag('option', l(:label_none), :value => 'none') +
51 options_from_collection_for_select(@project.issue_categories, :id, :name)) %>
51 options_from_collection_for_select(@project.issue_categories, :id, :name)) %>
52 </p>
52 </p>
53 <% end %>
53 <% end %>
54 <% #TODO: allow editing versions when multiple projects %>
54 <% #TODO: allow editing versions when multiple projects %>
55 <% if @project %>
55 <% if @project %>
56 <p>
56 <p>
57 <label for='issue_fixed_version_id'><%= l(:field_fixed_version) %></label>
57 <label for='issue_fixed_version_id'><%= l(:field_fixed_version) %></label>
58 <%= select_tag('issue[fixed_version_id]', content_tag('option', l(:label_no_change_option), :value => '') +
58 <%= select_tag('issue[fixed_version_id]', content_tag('option', l(:label_no_change_option), :value => '') +
59 content_tag('option', l(:label_none), :value => 'none') +
59 content_tag('option', l(:label_none), :value => 'none') +
60 version_options_for_select(@project.shared_versions.open.sort)) %>
60 version_options_for_select(@project.shared_versions.open.sort)) %>
61 </p>
61 </p>
62 <% end %>
62 <% end %>
63
63
64 <% @custom_fields.each do |custom_field| %>
64 <% @custom_fields.each do |custom_field| %>
65 <p><label><%= h(custom_field.name) %></label> <%= custom_field_tag_for_bulk_edit('issue', custom_field, @projects) %></p>
65 <p><label><%= h(custom_field.name) %></label> <%= custom_field_tag_for_bulk_edit('issue', custom_field, @projects) %></p>
66 <% end %>
66 <% end %>
67
67
68 <%= call_hook(:view_issues_bulk_edit_details_bottom, { :issues => @issues }) %>
68 <%= call_hook(:view_issues_bulk_edit_details_bottom, { :issues => @issues }) %>
69 </div>
69 </div>
70
70
71 <div class="splitcontentright">
71 <div class="splitcontentright">
72 <% if @project && User.current.allowed_to?(:manage_subtasks, @project) %>
72 <% if @project && User.current.allowed_to?(:manage_subtasks, @project) %>
73 <p>
73 <p>
74 <label for='issue_parent_issue_id'><%= l(:field_parent_issue) %></label>
74 <label for='issue_parent_issue_id'><%= l(:field_parent_issue) %></label>
75 <%= text_field_tag 'issue[parent_issue_id]', '', :size => 10 %>
75 <%= text_field_tag 'issue[parent_issue_id]', '', :size => 10 %>
76 </p>
76 </p>
77 <div id="parent_issue_candidates" class="autocomplete"></div>
77 <div id="parent_issue_candidates" class="autocomplete"></div>
78 <%= javascript_tag "observeParentIssueField('#{auto_complete_issues_path(:project_id => @project) }')" %>
78 <%= javascript_tag "observeParentIssueField('#{auto_complete_issues_path(:project_id => @project) }')" %>
79 <% end %>
79 <% end %>
80 <p>
80 <p>
81 <label for='issue_start_date'><%= l(:field_start_date) %></label>
81 <label for='issue_start_date'><%= l(:field_start_date) %></label>
82 <%= text_field_tag 'issue[start_date]', '', :size => 10 %><%= calendar_for('issue_start_date') %>
82 <%= text_field_tag 'issue[start_date]', '', :size => 10 %><%= calendar_for('issue_start_date') %>
83 </p>
83 </p>
84 <p>
84 <p>
85 <label for='issue_due_date'><%= l(:field_due_date) %></label>
85 <label for='issue_due_date'><%= l(:field_due_date) %></label>
86 <%= text_field_tag 'issue[due_date]', '', :size => 10 %><%= calendar_for('issue_due_date') %>
86 <%= text_field_tag 'issue[due_date]', '', :size => 10 %><%= calendar_for('issue_due_date') %>
87 </p>
87 </p>
88 <% if Issue.use_field_for_done_ratio? %>
88 <% if Issue.use_field_for_done_ratio? %>
89 <p>
89 <p>
90 <label for='issue_done_ratio'><%= l(:field_done_ratio) %></label>
90 <label for='issue_done_ratio'><%= l(:field_done_ratio) %></label>
91 <%= select_tag 'issue[done_ratio]', options_for_select([[l(:label_no_change_option), '']] + (0..10).to_a.collect {|r| ["#{r*10} %", r*10] }) %>
91 <%= select_tag 'issue[done_ratio]', options_for_select([[l(:label_no_change_option), '']] + (0..10).to_a.collect {|r| ["#{r*10} %", r*10] }) %>
92 </p>
92 </p>
93 <% end %>
93 <% end %>
94 </div>
94 </div>
95
95
96 </fieldset>
96 </fieldset>
97
97
98 <fieldset><legend><%= l(:field_notes) %></legend>
98 <fieldset><legend><%= l(:field_notes) %></legend>
99 <%= text_area_tag 'notes', @notes, :cols => 60, :rows => 10, :class => 'wiki-edit' %>
99 <%= text_area_tag 'notes', @notes, :cols => 60, :rows => 10, :class => 'wiki-edit' %>
100 <%= wikitoolbar_for 'notes' %>
100 <%= wikitoolbar_for 'notes' %>
101 </fieldset>
101 </fieldset>
102 </div>
102 </div>
103
103
104 <p>
104 <p>
105 <% if @target_project %>
105 <% if @copy %>
106 <%= hidden_field_tag 'copy', '1' %>
107 <%= submit_tag l(:button_copy) %>
108 <%= submit_tag l(:button_copy_and_follow), :name => 'follow' %>
109 <% elsif @target_project %>
106 <%= submit_tag l(:button_move) %>
110 <%= submit_tag l(:button_move) %>
107 <%= submit_tag l(:button_move_and_follow), :name => 'follow' %>
111 <%= submit_tag l(:button_move_and_follow), :name => 'follow' %>
108 <% else %>
112 <% else %>
109 <%= submit_tag l(:button_submit) %>
113 <%= submit_tag l(:button_submit) %>
110 <% end %>
114 <% end %>
111 </p>
115 </p>
112
116
113 <% end %>
117 <% end %>
@@ -1,399 +1,396
1 ActionController::Routing::Routes.draw do |map|
1 ActionController::Routing::Routes.draw do |map|
2 # Add your own custom routes here.
2 # Add your own custom routes here.
3 # The priority is based upon order of creation: first created -> highest priority.
3 # The priority is based upon order of creation: first created -> highest priority.
4
4
5 # Here's a sample route:
5 # Here's a sample route:
6 # map.connect 'products/:id', :controller => 'catalog', :action => 'view'
6 # map.connect 'products/:id', :controller => 'catalog', :action => 'view'
7 # Keep in mind you can assign values other than :controller and :action
7 # Keep in mind you can assign values other than :controller and :action
8
8
9 map.home '', :controller => 'welcome', :conditions => {:method => :get}
9 map.home '', :controller => 'welcome', :conditions => {:method => :get}
10
10
11 map.signin 'login', :controller => 'account', :action => 'login',
11 map.signin 'login', :controller => 'account', :action => 'login',
12 :conditions => {:method => [:get, :post]}
12 :conditions => {:method => [:get, :post]}
13 map.signout 'logout', :controller => 'account', :action => 'logout',
13 map.signout 'logout', :controller => 'account', :action => 'logout',
14 :conditions => {:method => :get}
14 :conditions => {:method => :get}
15 map.connect 'account/register', :controller => 'account', :action => 'register',
15 map.connect 'account/register', :controller => 'account', :action => 'register',
16 :conditions => {:method => [:get, :post]}
16 :conditions => {:method => [:get, :post]}
17 map.connect 'account/lost_password', :controller => 'account', :action => 'lost_password',
17 map.connect 'account/lost_password', :controller => 'account', :action => 'lost_password',
18 :conditions => {:method => [:get, :post]}
18 :conditions => {:method => [:get, :post]}
19 map.connect 'account/activate', :controller => 'account', :action => 'activate',
19 map.connect 'account/activate', :controller => 'account', :action => 'activate',
20 :conditions => {:method => :get}
20 :conditions => {:method => :get}
21
21
22 map.connect 'projects/:id/wiki', :controller => 'wikis',
22 map.connect 'projects/:id/wiki', :controller => 'wikis',
23 :action => 'edit', :conditions => {:method => :post}
23 :action => 'edit', :conditions => {:method => :post}
24 map.connect 'projects/:id/wiki/destroy', :controller => 'wikis',
24 map.connect 'projects/:id/wiki/destroy', :controller => 'wikis',
25 :action => 'destroy', :conditions => {:method => [:get, :post]}
25 :action => 'destroy', :conditions => {:method => [:get, :post]}
26
26
27 map.with_options :controller => 'messages' do |messages_routes|
27 map.with_options :controller => 'messages' do |messages_routes|
28 messages_routes.with_options :conditions => {:method => :get} do |messages_views|
28 messages_routes.with_options :conditions => {:method => :get} do |messages_views|
29 messages_views.connect 'boards/:board_id/topics/new', :action => 'new'
29 messages_views.connect 'boards/:board_id/topics/new', :action => 'new'
30 messages_views.connect 'boards/:board_id/topics/:id', :action => 'show'
30 messages_views.connect 'boards/:board_id/topics/:id', :action => 'show'
31 messages_views.connect 'boards/:board_id/topics/:id/edit', :action => 'edit'
31 messages_views.connect 'boards/:board_id/topics/:id/edit', :action => 'edit'
32 end
32 end
33 messages_routes.with_options :conditions => {:method => :post} do |messages_actions|
33 messages_routes.with_options :conditions => {:method => :post} do |messages_actions|
34 messages_actions.connect 'boards/:board_id/topics/new', :action => 'new'
34 messages_actions.connect 'boards/:board_id/topics/new', :action => 'new'
35 messages_actions.connect 'boards/:board_id/topics/preview', :action => 'preview'
35 messages_actions.connect 'boards/:board_id/topics/preview', :action => 'preview'
36 messages_actions.connect 'boards/:board_id/topics/quote/:id', :action => 'quote'
36 messages_actions.connect 'boards/:board_id/topics/quote/:id', :action => 'quote'
37 messages_actions.connect 'boards/:board_id/topics/:id/replies', :action => 'reply'
37 messages_actions.connect 'boards/:board_id/topics/:id/replies', :action => 'reply'
38 messages_actions.connect 'boards/:board_id/topics/:id/edit', :action => 'edit'
38 messages_actions.connect 'boards/:board_id/topics/:id/edit', :action => 'edit'
39 messages_actions.connect 'boards/:board_id/topics/:id/destroy', :action => 'destroy'
39 messages_actions.connect 'boards/:board_id/topics/:id/destroy', :action => 'destroy'
40 end
40 end
41 end
41 end
42
42
43 map.resources :issue_moves, :only => [:new, :create],
44 :path_prefix => '/issues', :as => 'move'
45
46 # Misc issue routes. TODO: move into resources
43 # Misc issue routes. TODO: move into resources
47 map.auto_complete_issues '/issues/auto_complete', :controller => 'auto_completes',
44 map.auto_complete_issues '/issues/auto_complete', :controller => 'auto_completes',
48 :action => 'issues', :conditions => { :method => :get }
45 :action => 'issues', :conditions => { :method => :get }
49 # TODO: would look nicer as /issues/:id/preview
46 # TODO: would look nicer as /issues/:id/preview
50 map.preview_issue '/issues/preview/:id', :controller => 'previews',
47 map.preview_issue '/issues/preview/:id', :controller => 'previews',
51 :action => 'issue'
48 :action => 'issue'
52 map.issues_context_menu '/issues/context_menu',
49 map.issues_context_menu '/issues/context_menu',
53 :controller => 'context_menus', :action => 'issues'
50 :controller => 'context_menus', :action => 'issues'
54
51
55 map.issue_changes '/issues/changes', :controller => 'journals', :action => 'index'
52 map.issue_changes '/issues/changes', :controller => 'journals', :action => 'index'
56 map.quoted_issue '/issues/:id/quoted', :controller => 'journals', :action => 'new',
53 map.quoted_issue '/issues/:id/quoted', :controller => 'journals', :action => 'new',
57 :id => /\d+/, :conditions => { :method => :post }
54 :id => /\d+/, :conditions => { :method => :post }
58
55
59 map.connect '/journals/diff/:id', :controller => 'journals', :action => 'diff',
56 map.connect '/journals/diff/:id', :controller => 'journals', :action => 'diff',
60 :id => /\d+/, :conditions => { :method => :get }
57 :id => /\d+/, :conditions => { :method => :get }
61 map.connect '/journals/edit/:id', :controller => 'journals', :action => 'edit',
58 map.connect '/journals/edit/:id', :controller => 'journals', :action => 'edit',
62 :id => /\d+/, :conditions => { :method => [:get, :post] }
59 :id => /\d+/, :conditions => { :method => [:get, :post] }
63
60
64 map.with_options :controller => 'gantts', :action => 'show' do |gantts_routes|
61 map.with_options :controller => 'gantts', :action => 'show' do |gantts_routes|
65 gantts_routes.connect '/projects/:project_id/issues/gantt'
62 gantts_routes.connect '/projects/:project_id/issues/gantt'
66 gantts_routes.connect '/projects/:project_id/issues/gantt.:format'
63 gantts_routes.connect '/projects/:project_id/issues/gantt.:format'
67 gantts_routes.connect '/issues/gantt.:format'
64 gantts_routes.connect '/issues/gantt.:format'
68 end
65 end
69
66
70 map.with_options :controller => 'calendars', :action => 'show' do |calendars_routes|
67 map.with_options :controller => 'calendars', :action => 'show' do |calendars_routes|
71 calendars_routes.connect '/projects/:project_id/issues/calendar'
68 calendars_routes.connect '/projects/:project_id/issues/calendar'
72 calendars_routes.connect '/issues/calendar'
69 calendars_routes.connect '/issues/calendar'
73 end
70 end
74
71
75 map.with_options :controller => 'reports', :conditions => {:method => :get} do |reports|
72 map.with_options :controller => 'reports', :conditions => {:method => :get} do |reports|
76 reports.connect 'projects/:id/issues/report', :action => 'issue_report'
73 reports.connect 'projects/:id/issues/report', :action => 'issue_report'
77 reports.connect 'projects/:id/issues/report/:detail', :action => 'issue_report_details'
74 reports.connect 'projects/:id/issues/report/:detail', :action => 'issue_report_details'
78 end
75 end
79
76
80 map.connect 'my/account', :controller => 'my', :action => 'account',
77 map.connect 'my/account', :controller => 'my', :action => 'account',
81 :conditions => {:method => [:get, :post]}
78 :conditions => {:method => [:get, :post]}
82 map.connect 'my/page', :controller => 'my', :action => 'page',
79 map.connect 'my/page', :controller => 'my', :action => 'page',
83 :conditions => {:method => :get}
80 :conditions => {:method => :get}
84 # Redirects to my/page
81 # Redirects to my/page
85 map.connect 'my', :controller => 'my', :action => 'index',
82 map.connect 'my', :controller => 'my', :action => 'index',
86 :conditions => {:method => :get}
83 :conditions => {:method => :get}
87 map.connect 'my/reset_rss_key', :controller => 'my', :action => 'reset_rss_key',
84 map.connect 'my/reset_rss_key', :controller => 'my', :action => 'reset_rss_key',
88 :conditions => {:method => :post}
85 :conditions => {:method => :post}
89 map.connect 'my/reset_api_key', :controller => 'my', :action => 'reset_api_key',
86 map.connect 'my/reset_api_key', :controller => 'my', :action => 'reset_api_key',
90 :conditions => {:method => :post}
87 :conditions => {:method => :post}
91 map.connect 'my/password', :controller => 'my', :action => 'password',
88 map.connect 'my/password', :controller => 'my', :action => 'password',
92 :conditions => {:method => [:get, :post]}
89 :conditions => {:method => [:get, :post]}
93 map.connect 'my/page_layout', :controller => 'my', :action => 'page_layout',
90 map.connect 'my/page_layout', :controller => 'my', :action => 'page_layout',
94 :conditions => {:method => :get}
91 :conditions => {:method => :get}
95 map.connect 'my/add_block', :controller => 'my', :action => 'add_block',
92 map.connect 'my/add_block', :controller => 'my', :action => 'add_block',
96 :conditions => {:method => :post}
93 :conditions => {:method => :post}
97 map.connect 'my/remove_block', :controller => 'my', :action => 'remove_block',
94 map.connect 'my/remove_block', :controller => 'my', :action => 'remove_block',
98 :conditions => {:method => :post}
95 :conditions => {:method => :post}
99 map.connect 'my/order_blocks', :controller => 'my', :action => 'order_blocks',
96 map.connect 'my/order_blocks', :controller => 'my', :action => 'order_blocks',
100 :conditions => {:method => :post}
97 :conditions => {:method => :post}
101
98
102 map.connect 'projects/:id/members/new', :controller => 'members',
99 map.connect 'projects/:id/members/new', :controller => 'members',
103 :action => 'new', :conditions => { :method => :post }
100 :action => 'new', :conditions => { :method => :post }
104 map.connect 'members/edit/:id', :controller => 'members',
101 map.connect 'members/edit/:id', :controller => 'members',
105 :action => 'edit', :id => /\d+/, :conditions => { :method => :post }
102 :action => 'edit', :id => /\d+/, :conditions => { :method => :post }
106 map.connect 'members/destroy/:id', :controller => 'members',
103 map.connect 'members/destroy/:id', :controller => 'members',
107 :action => 'destroy', :id => /\d+/, :conditions => { :method => :post }
104 :action => 'destroy', :id => /\d+/, :conditions => { :method => :post }
108 map.connect 'members/autocomplete_for_member/:id', :controller => 'members',
105 map.connect 'members/autocomplete_for_member/:id', :controller => 'members',
109 :action => 'autocomplete_for_member', :conditions => { :method => :post }
106 :action => 'autocomplete_for_member', :conditions => { :method => :post }
110
107
111 map.with_options :controller => 'users' do |users|
108 map.with_options :controller => 'users' do |users|
112 users.user_membership 'users/:id/memberships/:membership_id',
109 users.user_membership 'users/:id/memberships/:membership_id',
113 :action => 'edit_membership',
110 :action => 'edit_membership',
114 :conditions => {:method => :put}
111 :conditions => {:method => :put}
115 users.connect 'users/:id/memberships/:membership_id',
112 users.connect 'users/:id/memberships/:membership_id',
116 :action => 'destroy_membership',
113 :action => 'destroy_membership',
117 :conditions => {:method => :delete}
114 :conditions => {:method => :delete}
118 users.user_memberships 'users/:id/memberships',
115 users.user_memberships 'users/:id/memberships',
119 :action => 'edit_membership',
116 :action => 'edit_membership',
120 :conditions => {:method => :post}
117 :conditions => {:method => :post}
121 end
118 end
122 map.resources :users
119 map.resources :users
123
120
124 # For nice "roadmap" in the url for the index action
121 # For nice "roadmap" in the url for the index action
125 map.connect 'projects/:project_id/roadmap', :controller => 'versions', :action => 'index'
122 map.connect 'projects/:project_id/roadmap', :controller => 'versions', :action => 'index'
126
123
127 map.connect 'news', :controller => 'news', :action => 'index'
124 map.connect 'news', :controller => 'news', :action => 'index'
128 map.connect 'news.:format', :controller => 'news', :action => 'index'
125 map.connect 'news.:format', :controller => 'news', :action => 'index'
129 map.preview_news '/news/preview', :controller => 'previews', :action => 'news'
126 map.preview_news '/news/preview', :controller => 'previews', :action => 'news'
130 map.connect 'news/:id/comments', :controller => 'comments',
127 map.connect 'news/:id/comments', :controller => 'comments',
131 :action => 'create', :conditions => {:method => :post}
128 :action => 'create', :conditions => {:method => :post}
132 map.connect 'news/:id/comments/:comment_id', :controller => 'comments',
129 map.connect 'news/:id/comments/:comment_id', :controller => 'comments',
133 :action => 'destroy', :conditions => {:method => :delete}
130 :action => 'destroy', :conditions => {:method => :delete}
134
131
135 map.connect 'watchers/new', :controller=> 'watchers', :action => 'new',
132 map.connect 'watchers/new', :controller=> 'watchers', :action => 'new',
136 :conditions => {:method => [:get, :post]}
133 :conditions => {:method => [:get, :post]}
137 map.connect 'watchers/destroy', :controller=> 'watchers', :action => 'destroy',
134 map.connect 'watchers/destroy', :controller=> 'watchers', :action => 'destroy',
138 :conditions => {:method => :post}
135 :conditions => {:method => :post}
139 map.connect 'watchers/watch', :controller=> 'watchers', :action => 'watch',
136 map.connect 'watchers/watch', :controller=> 'watchers', :action => 'watch',
140 :conditions => {:method => :post}
137 :conditions => {:method => :post}
141 map.connect 'watchers/unwatch', :controller=> 'watchers', :action => 'unwatch',
138 map.connect 'watchers/unwatch', :controller=> 'watchers', :action => 'unwatch',
142 :conditions => {:method => :post}
139 :conditions => {:method => :post}
143
140
144 # TODO: port to be part of the resources route(s)
141 # TODO: port to be part of the resources route(s)
145 map.with_options :conditions => {:method => :get} do |project_views|
142 map.with_options :conditions => {:method => :get} do |project_views|
146 project_views.connect 'projects/:id/settings/:tab',
143 project_views.connect 'projects/:id/settings/:tab',
147 :controller => 'projects', :action => 'settings'
144 :controller => 'projects', :action => 'settings'
148 project_views.connect 'projects/:project_id/issues/:copy_from/copy',
145 project_views.connect 'projects/:project_id/issues/:copy_from/copy',
149 :controller => 'issues', :action => 'new'
146 :controller => 'issues', :action => 'new'
150 end
147 end
151
148
152 map.resources :projects, :member => {
149 map.resources :projects, :member => {
153 :copy => [:get, :post],
150 :copy => [:get, :post],
154 :settings => :get,
151 :settings => :get,
155 :modules => :post,
152 :modules => :post,
156 :archive => :post,
153 :archive => :post,
157 :unarchive => :post
154 :unarchive => :post
158 } do |project|
155 } do |project|
159 project.resource :project_enumerations, :as => 'enumerations',
156 project.resource :project_enumerations, :as => 'enumerations',
160 :only => [:update, :destroy]
157 :only => [:update, :destroy]
161 # issue form update
158 # issue form update
162 project.issue_form 'issues/new', :controller => 'issues',
159 project.issue_form 'issues/new', :controller => 'issues',
163 :action => 'new', :conditions => {:method => [:post, :put]}
160 :action => 'new', :conditions => {:method => [:post, :put]}
164 project.resources :issues, :only => [:index, :new, :create] do |issues|
161 project.resources :issues, :only => [:index, :new, :create] do |issues|
165 issues.resources :time_entries, :controller => 'timelog',
162 issues.resources :time_entries, :controller => 'timelog',
166 :collection => {:report => :get}
163 :collection => {:report => :get}
167 end
164 end
168
165
169 project.resources :files, :only => [:index, :new, :create]
166 project.resources :files, :only => [:index, :new, :create]
170 project.resources :versions, :shallow => true,
167 project.resources :versions, :shallow => true,
171 :collection => {:close_completed => :put},
168 :collection => {:close_completed => :put},
172 :member => {:status_by => :post}
169 :member => {:status_by => :post}
173 project.resources :news, :shallow => true
170 project.resources :news, :shallow => true
174 project.resources :time_entries, :controller => 'timelog',
171 project.resources :time_entries, :controller => 'timelog',
175 :path_prefix => 'projects/:project_id',
172 :path_prefix => 'projects/:project_id',
176 :collection => {:report => :get}
173 :collection => {:report => :get}
177 project.resources :queries, :only => [:new, :create]
174 project.resources :queries, :only => [:new, :create]
178 project.resources :issue_categories, :shallow => true
175 project.resources :issue_categories, :shallow => true
179 project.resources :documents, :shallow => true, :member => {:add_attachment => :post}
176 project.resources :documents, :shallow => true, :member => {:add_attachment => :post}
180 project.resources :boards
177 project.resources :boards
181
178
182 project.wiki_start_page 'wiki', :controller => 'wiki', :action => 'show', :conditions => {:method => :get}
179 project.wiki_start_page 'wiki', :controller => 'wiki', :action => 'show', :conditions => {:method => :get}
183 project.wiki_index 'wiki/index', :controller => 'wiki', :action => 'index', :conditions => {:method => :get}
180 project.wiki_index 'wiki/index', :controller => 'wiki', :action => 'index', :conditions => {:method => :get}
184 project.wiki_diff 'wiki/:id/diff/:version', :controller => 'wiki', :action => 'diff', :version => nil
181 project.wiki_diff 'wiki/:id/diff/:version', :controller => 'wiki', :action => 'diff', :version => nil
185 project.wiki_diff 'wiki/:id/diff/:version/vs/:version_from', :controller => 'wiki', :action => 'diff'
182 project.wiki_diff 'wiki/:id/diff/:version/vs/:version_from', :controller => 'wiki', :action => 'diff'
186 project.wiki_annotate 'wiki/:id/annotate/:version', :controller => 'wiki', :action => 'annotate'
183 project.wiki_annotate 'wiki/:id/annotate/:version', :controller => 'wiki', :action => 'annotate'
187 project.resources :wiki, :except => [:new, :create], :member => {
184 project.resources :wiki, :except => [:new, :create], :member => {
188 :rename => [:get, :post],
185 :rename => [:get, :post],
189 :history => :get,
186 :history => :get,
190 :preview => :any,
187 :preview => :any,
191 :protect => :post,
188 :protect => :post,
192 :add_attachment => :post
189 :add_attachment => :post
193 }, :collection => {
190 }, :collection => {
194 :export => :get,
191 :export => :get,
195 :date_index => :get
192 :date_index => :get
196 }
193 }
197 end
194 end
198
195
199 map.resources :queries, :except => [:show]
196 map.resources :queries, :except => [:show]
200 map.resources :issues,
197 map.resources :issues,
201 :collection => {:bulk_edit => [:get, :post], :bulk_update => :post} do |issues|
198 :collection => {:bulk_edit => [:get, :post], :bulk_update => :post} do |issues|
202 issues.resources :time_entries, :controller => 'timelog',
199 issues.resources :time_entries, :controller => 'timelog',
203 :collection => {:report => :get}
200 :collection => {:report => :get}
204 issues.resources :relations, :shallow => true,
201 issues.resources :relations, :shallow => true,
205 :controller => 'issue_relations',
202 :controller => 'issue_relations',
206 :only => [:index, :show, :create, :destroy]
203 :only => [:index, :show, :create, :destroy]
207 end
204 end
208 # Bulk deletion
205 # Bulk deletion
209 map.connect '/issues', :controller => 'issues', :action => 'destroy',
206 map.connect '/issues', :controller => 'issues', :action => 'destroy',
210 :conditions => {:method => :delete}
207 :conditions => {:method => :delete}
211
208
212 map.connect '/time_entries/destroy',
209 map.connect '/time_entries/destroy',
213 :controller => 'timelog', :action => 'destroy',
210 :controller => 'timelog', :action => 'destroy',
214 :conditions => { :method => :delete }
211 :conditions => { :method => :delete }
215 map.time_entries_context_menu '/time_entries/context_menu',
212 map.time_entries_context_menu '/time_entries/context_menu',
216 :controller => 'context_menus', :action => 'time_entries'
213 :controller => 'context_menus', :action => 'time_entries'
217
214
218 map.resources :time_entries, :controller => 'timelog',
215 map.resources :time_entries, :controller => 'timelog',
219 :collection => {:report => :get, :bulk_edit => :get, :bulk_update => :post}
216 :collection => {:report => :get, :bulk_edit => :get, :bulk_update => :post}
220
217
221 map.with_options :controller => 'activities', :action => 'index',
218 map.with_options :controller => 'activities', :action => 'index',
222 :conditions => {:method => :get} do |activity|
219 :conditions => {:method => :get} do |activity|
223 activity.connect 'projects/:id/activity'
220 activity.connect 'projects/:id/activity'
224 activity.connect 'projects/:id/activity.:format'
221 activity.connect 'projects/:id/activity.:format'
225 activity.connect 'activity', :id => nil
222 activity.connect 'activity', :id => nil
226 activity.connect 'activity.:format', :id => nil
223 activity.connect 'activity.:format', :id => nil
227 end
224 end
228
225
229 map.with_options :controller => 'repositories' do |repositories|
226 map.with_options :controller => 'repositories' do |repositories|
230 repositories.with_options :conditions => {:method => :get} do |repository_views|
227 repositories.with_options :conditions => {:method => :get} do |repository_views|
231 repository_views.connect 'projects/:id/repository',
228 repository_views.connect 'projects/:id/repository',
232 :action => 'show'
229 :action => 'show'
233 repository_views.connect 'projects/:id/repository/statistics',
230 repository_views.connect 'projects/:id/repository/statistics',
234 :action => 'stats'
231 :action => 'stats'
235
232
236 repository_views.connect 'projects/:id/repository/revisions',
233 repository_views.connect 'projects/:id/repository/revisions',
237 :action => 'revisions'
234 :action => 'revisions'
238 repository_views.connect 'projects/:id/repository/revisions.:format',
235 repository_views.connect 'projects/:id/repository/revisions.:format',
239 :action => 'revisions'
236 :action => 'revisions'
240 repository_views.connect 'projects/:id/repository/revisions/:rev',
237 repository_views.connect 'projects/:id/repository/revisions/:rev',
241 :action => 'revision'
238 :action => 'revision'
242 repository_views.connect 'projects/:id/repository/revisions/:rev/diff',
239 repository_views.connect 'projects/:id/repository/revisions/:rev/diff',
243 :action => 'diff'
240 :action => 'diff'
244 repository_views.connect 'projects/:id/repository/revisions/:rev/diff.:format',
241 repository_views.connect 'projects/:id/repository/revisions/:rev/diff.:format',
245 :action => 'diff'
242 :action => 'diff'
246 repository_views.connect 'projects/:id/repository/revisions/:rev/raw/*path',
243 repository_views.connect 'projects/:id/repository/revisions/:rev/raw/*path',
247 :action => 'entry',
244 :action => 'entry',
248 :format => 'raw',
245 :format => 'raw',
249 :requirements => { :rev => /[a-z0-9\.\-_]+/ }
246 :requirements => { :rev => /[a-z0-9\.\-_]+/ }
250 repository_views.connect 'projects/:id/repository/revisions/:rev/:action/*path',
247 repository_views.connect 'projects/:id/repository/revisions/:rev/:action/*path',
251 :requirements => { :rev => /[a-z0-9\.\-_]+/ }
248 :requirements => { :rev => /[a-z0-9\.\-_]+/ }
252
249
253 repository_views.connect 'projects/:id/repository/raw/*path',
250 repository_views.connect 'projects/:id/repository/raw/*path',
254 :action => 'entry', :format => 'raw'
251 :action => 'entry', :format => 'raw'
255 repository_views.connect 'projects/:id/repository/browse/*path',
252 repository_views.connect 'projects/:id/repository/browse/*path',
256 :action => 'browse'
253 :action => 'browse'
257 repository_views.connect 'projects/:id/repository/entry/*path',
254 repository_views.connect 'projects/:id/repository/entry/*path',
258 :action => 'entry'
255 :action => 'entry'
259 repository_views.connect 'projects/:id/repository/changes/*path',
256 repository_views.connect 'projects/:id/repository/changes/*path',
260 :action => 'changes'
257 :action => 'changes'
261 repository_views.connect 'projects/:id/repository/annotate/*path',
258 repository_views.connect 'projects/:id/repository/annotate/*path',
262 :action => 'annotate'
259 :action => 'annotate'
263 repository_views.connect 'projects/:id/repository/diff/*path',
260 repository_views.connect 'projects/:id/repository/diff/*path',
264 :action => 'diff'
261 :action => 'diff'
265 repository_views.connect 'projects/:id/repository/show/*path',
262 repository_views.connect 'projects/:id/repository/show/*path',
266 :action => 'show'
263 :action => 'show'
267 repository_views.connect 'projects/:id/repository/graph',
264 repository_views.connect 'projects/:id/repository/graph',
268 :action => 'graph'
265 :action => 'graph'
269 end
266 end
270
267
271 repositories.connect 'projects/:id/repository/revision',
268 repositories.connect 'projects/:id/repository/revision',
272 :action => 'revision',
269 :action => 'revision',
273 :conditions => {:method => [:get, :post]}
270 :conditions => {:method => [:get, :post]}
274
271
275 repositories.connect 'projects/:id/repository/committers',
272 repositories.connect 'projects/:id/repository/committers',
276 :action => 'committers',
273 :action => 'committers',
277 :conditions => {:method => [:get, :post]}
274 :conditions => {:method => [:get, :post]}
278 repositories.connect 'projects/:id/repository/edit',
275 repositories.connect 'projects/:id/repository/edit',
279 :action => 'edit',
276 :action => 'edit',
280 :conditions => {:method => [:get, :post]}
277 :conditions => {:method => [:get, :post]}
281 repositories.connect 'projects/:id/repository/destroy',
278 repositories.connect 'projects/:id/repository/destroy',
282 :action => 'destroy',
279 :action => 'destroy',
283 :conditions => {:method => :post}
280 :conditions => {:method => :post}
284 end
281 end
285
282
286 # additional routes for having the file name at the end of url
283 # additional routes for having the file name at the end of url
287 map.connect 'attachments/:id/:filename', :controller => 'attachments',
284 map.connect 'attachments/:id/:filename', :controller => 'attachments',
288 :action => 'show', :id => /\d+/, :filename => /.*/,
285 :action => 'show', :id => /\d+/, :filename => /.*/,
289 :conditions => {:method => :get}
286 :conditions => {:method => :get}
290 map.connect 'attachments/download/:id/:filename', :controller => 'attachments',
287 map.connect 'attachments/download/:id/:filename', :controller => 'attachments',
291 :action => 'download', :id => /\d+/, :filename => /.*/,
288 :action => 'download', :id => /\d+/, :filename => /.*/,
292 :conditions => {:method => :get}
289 :conditions => {:method => :get}
293 map.connect 'attachments/download/:id', :controller => 'attachments',
290 map.connect 'attachments/download/:id', :controller => 'attachments',
294 :action => 'download', :id => /\d+/,
291 :action => 'download', :id => /\d+/,
295 :conditions => {:method => :get}
292 :conditions => {:method => :get}
296 map.resources :attachments, :only => [:show, :destroy]
293 map.resources :attachments, :only => [:show, :destroy]
297
294
298 map.resources :groups, :member => {:autocomplete_for_user => :get}
295 map.resources :groups, :member => {:autocomplete_for_user => :get}
299 map.group_users 'groups/:id/users', :controller => 'groups',
296 map.group_users 'groups/:id/users', :controller => 'groups',
300 :action => 'add_users', :id => /\d+/,
297 :action => 'add_users', :id => /\d+/,
301 :conditions => {:method => :post}
298 :conditions => {:method => :post}
302 map.group_user 'groups/:id/users/:user_id', :controller => 'groups',
299 map.group_user 'groups/:id/users/:user_id', :controller => 'groups',
303 :action => 'remove_user', :id => /\d+/,
300 :action => 'remove_user', :id => /\d+/,
304 :conditions => {:method => :delete}
301 :conditions => {:method => :delete}
305 map.connect 'groups/destroy_membership/:id', :controller => 'groups',
302 map.connect 'groups/destroy_membership/:id', :controller => 'groups',
306 :action => 'destroy_membership', :id => /\d+/,
303 :action => 'destroy_membership', :id => /\d+/,
307 :conditions => {:method => :post}
304 :conditions => {:method => :post}
308 map.connect 'groups/edit_membership/:id', :controller => 'groups',
305 map.connect 'groups/edit_membership/:id', :controller => 'groups',
309 :action => 'edit_membership', :id => /\d+/,
306 :action => 'edit_membership', :id => /\d+/,
310 :conditions => {:method => :post}
307 :conditions => {:method => :post}
311
308
312 map.resources :trackers, :except => :show
309 map.resources :trackers, :except => :show
313 map.resources :issue_statuses, :except => :show, :collection => {:update_issue_done_ratio => :post}
310 map.resources :issue_statuses, :except => :show, :collection => {:update_issue_done_ratio => :post}
314 map.resources :custom_fields, :except => :show
311 map.resources :custom_fields, :except => :show
315 map.resources :roles, :except => :show, :collection => {:permissions => [:get, :post]}
312 map.resources :roles, :except => :show, :collection => {:permissions => [:get, :post]}
316 map.resources :enumerations, :except => :show
313 map.resources :enumerations, :except => :show
317
314
318 map.connect 'search', :controller => 'search', :action => 'index', :conditions => {:method => :get}
315 map.connect 'search', :controller => 'search', :action => 'index', :conditions => {:method => :get}
319
316
320 map.connect 'mail_handler', :controller => 'mail_handler',
317 map.connect 'mail_handler', :controller => 'mail_handler',
321 :action => 'index', :conditions => {:method => :post}
318 :action => 'index', :conditions => {:method => :post}
322
319
323 map.connect 'admin', :controller => 'admin', :action => 'index',
320 map.connect 'admin', :controller => 'admin', :action => 'index',
324 :conditions => {:method => :get}
321 :conditions => {:method => :get}
325 map.connect 'admin/projects', :controller => 'admin', :action => 'projects',
322 map.connect 'admin/projects', :controller => 'admin', :action => 'projects',
326 :conditions => {:method => :get}
323 :conditions => {:method => :get}
327 map.connect 'admin/plugins', :controller => 'admin', :action => 'plugins',
324 map.connect 'admin/plugins', :controller => 'admin', :action => 'plugins',
328 :conditions => {:method => :get}
325 :conditions => {:method => :get}
329 map.connect 'admin/info', :controller => 'admin', :action => 'info',
326 map.connect 'admin/info', :controller => 'admin', :action => 'info',
330 :conditions => {:method => :get}
327 :conditions => {:method => :get}
331 map.connect 'admin/test_email', :controller => 'admin', :action => 'test_email',
328 map.connect 'admin/test_email', :controller => 'admin', :action => 'test_email',
332 :conditions => {:method => :get}
329 :conditions => {:method => :get}
333 map.connect 'admin/default_configuration', :controller => 'admin',
330 map.connect 'admin/default_configuration', :controller => 'admin',
334 :action => 'default_configuration', :conditions => {:method => :post}
331 :action => 'default_configuration', :conditions => {:method => :post}
335
332
336 # Used by AuthSourcesControllerTest
333 # Used by AuthSourcesControllerTest
337 # TODO : refactor *AuthSourcesController to remove these routes
334 # TODO : refactor *AuthSourcesController to remove these routes
338 map.connect 'auth_sources', :controller => 'auth_sources',
335 map.connect 'auth_sources', :controller => 'auth_sources',
339 :action => 'index', :conditions => {:method => :get}
336 :action => 'index', :conditions => {:method => :get}
340 map.connect 'auth_sources/new', :controller => 'auth_sources',
337 map.connect 'auth_sources/new', :controller => 'auth_sources',
341 :action => 'new', :conditions => {:method => :get}
338 :action => 'new', :conditions => {:method => :get}
342 map.connect 'auth_sources/create', :controller => 'auth_sources',
339 map.connect 'auth_sources/create', :controller => 'auth_sources',
343 :action => 'create', :conditions => {:method => :post}
340 :action => 'create', :conditions => {:method => :post}
344 map.connect 'auth_sources/destroy/:id', :controller => 'auth_sources',
341 map.connect 'auth_sources/destroy/:id', :controller => 'auth_sources',
345 :action => 'destroy', :id => /\d+/, :conditions => {:method => :post}
342 :action => 'destroy', :id => /\d+/, :conditions => {:method => :post}
346 map.connect 'auth_sources/test_connection/:id', :controller => 'auth_sources',
343 map.connect 'auth_sources/test_connection/:id', :controller => 'auth_sources',
347 :action => 'test_connection', :conditions => {:method => :get}
344 :action => 'test_connection', :conditions => {:method => :get}
348 map.connect 'auth_sources/edit/:id', :controller => 'auth_sources',
345 map.connect 'auth_sources/edit/:id', :controller => 'auth_sources',
349 :action => 'edit', :id => /\d+/, :conditions => {:method => :get}
346 :action => 'edit', :id => /\d+/, :conditions => {:method => :get}
350 map.connect 'auth_sources/update/:id', :controller => 'auth_sources',
347 map.connect 'auth_sources/update/:id', :controller => 'auth_sources',
351 :action => 'update', :id => /\d+/, :conditions => {:method => :post}
348 :action => 'update', :id => /\d+/, :conditions => {:method => :post}
352
349
353 map.connect 'ldap_auth_sources', :controller => 'ldap_auth_sources',
350 map.connect 'ldap_auth_sources', :controller => 'ldap_auth_sources',
354 :action => 'index', :conditions => {:method => :get}
351 :action => 'index', :conditions => {:method => :get}
355 map.connect 'ldap_auth_sources/new', :controller => 'ldap_auth_sources',
352 map.connect 'ldap_auth_sources/new', :controller => 'ldap_auth_sources',
356 :action => 'new', :conditions => {:method => :get}
353 :action => 'new', :conditions => {:method => :get}
357 map.connect 'ldap_auth_sources/create', :controller => 'ldap_auth_sources',
354 map.connect 'ldap_auth_sources/create', :controller => 'ldap_auth_sources',
358 :action => 'create', :conditions => {:method => :post}
355 :action => 'create', :conditions => {:method => :post}
359 map.connect 'ldap_auth_sources/destroy/:id', :controller => 'ldap_auth_sources',
356 map.connect 'ldap_auth_sources/destroy/:id', :controller => 'ldap_auth_sources',
360 :action => 'destroy', :id => /\d+/, :conditions => {:method => :post}
357 :action => 'destroy', :id => /\d+/, :conditions => {:method => :post}
361 map.connect 'ldap_auth_sources/test_connection/:id', :controller => 'ldap_auth_sources',
358 map.connect 'ldap_auth_sources/test_connection/:id', :controller => 'ldap_auth_sources',
362 :action => 'test_connection', :conditions => {:method => :get}
359 :action => 'test_connection', :conditions => {:method => :get}
363 map.connect 'ldap_auth_sources/edit/:id', :controller => 'ldap_auth_sources',
360 map.connect 'ldap_auth_sources/edit/:id', :controller => 'ldap_auth_sources',
364 :action => 'edit', :id => /\d+/, :conditions => {:method => :get}
361 :action => 'edit', :id => /\d+/, :conditions => {:method => :get}
365 map.connect 'ldap_auth_sources/update/:id', :controller => 'ldap_auth_sources',
362 map.connect 'ldap_auth_sources/update/:id', :controller => 'ldap_auth_sources',
366 :action => 'update', :id => /\d+/, :conditions => {:method => :post}
363 :action => 'update', :id => /\d+/, :conditions => {:method => :post}
367
364
368 map.connect 'workflows', :controller => 'workflows',
365 map.connect 'workflows', :controller => 'workflows',
369 :action => 'index', :conditions => {:method => :get}
366 :action => 'index', :conditions => {:method => :get}
370 map.connect 'workflows/edit', :controller => 'workflows',
367 map.connect 'workflows/edit', :controller => 'workflows',
371 :action => 'edit', :conditions => {:method => [:get, :post]}
368 :action => 'edit', :conditions => {:method => [:get, :post]}
372 map.connect 'workflows/copy', :controller => 'workflows',
369 map.connect 'workflows/copy', :controller => 'workflows',
373 :action => 'copy', :conditions => {:method => [:get, :post]}
370 :action => 'copy', :conditions => {:method => [:get, :post]}
374
371
375 map.connect 'settings', :controller => 'settings',
372 map.connect 'settings', :controller => 'settings',
376 :action => 'index', :conditions => {:method => :get}
373 :action => 'index', :conditions => {:method => :get}
377 map.connect 'settings/edit', :controller => 'settings',
374 map.connect 'settings/edit', :controller => 'settings',
378 :action => 'edit', :conditions => {:method => [:get, :post]}
375 :action => 'edit', :conditions => {:method => [:get, :post]}
379 map.connect 'settings/plugin/:id', :controller => 'settings',
376 map.connect 'settings/plugin/:id', :controller => 'settings',
380 :action => 'plugin', :conditions => {:method => [:get, :post]}
377 :action => 'plugin', :conditions => {:method => [:get, :post]}
381
378
382 map.with_options :controller => 'sys' do |sys|
379 map.with_options :controller => 'sys' do |sys|
383 sys.connect 'sys/projects.:format',
380 sys.connect 'sys/projects.:format',
384 :action => 'projects',
381 :action => 'projects',
385 :conditions => {:method => :get}
382 :conditions => {:method => :get}
386 sys.connect 'sys/projects/:id/repository.:format',
383 sys.connect 'sys/projects/:id/repository.:format',
387 :action => 'create_project_repository',
384 :action => 'create_project_repository',
388 :conditions => {:method => :post}
385 :conditions => {:method => :post}
389 sys.connect 'sys/fetch_changesets',
386 sys.connect 'sys/fetch_changesets',
390 :action => 'fetch_changesets',
387 :action => 'fetch_changesets',
391 :conditions => {:method => :get}
388 :conditions => {:method => :get}
392 end
389 end
393
390
394 map.connect 'robots.txt', :controller => 'welcome',
391 map.connect 'robots.txt', :controller => 'welcome',
395 :action => 'robots', :conditions => {:method => :get}
392 :action => 'robots', :conditions => {:method => :get}
396
393
397 # Used for OpenID
394 # Used for OpenID
398 map.root :controller => 'account', :action => 'login'
395 map.root :controller => 'account', :action => 'login'
399 end
396 end
@@ -1,237 +1,237
1 require 'redmine/access_control'
1 require 'redmine/access_control'
2 require 'redmine/menu_manager'
2 require 'redmine/menu_manager'
3 require 'redmine/activity'
3 require 'redmine/activity'
4 require 'redmine/search'
4 require 'redmine/search'
5 require 'redmine/custom_field_format'
5 require 'redmine/custom_field_format'
6 require 'redmine/mime_type'
6 require 'redmine/mime_type'
7 require 'redmine/core_ext'
7 require 'redmine/core_ext'
8 require 'redmine/themes'
8 require 'redmine/themes'
9 require 'redmine/hook'
9 require 'redmine/hook'
10 require 'redmine/plugin'
10 require 'redmine/plugin'
11 require 'redmine/notifiable'
11 require 'redmine/notifiable'
12 require 'redmine/wiki_formatting'
12 require 'redmine/wiki_formatting'
13 require 'redmine/scm/base'
13 require 'redmine/scm/base'
14
14
15 begin
15 begin
16 require_library_or_gem 'RMagick' unless Object.const_defined?(:Magick)
16 require_library_or_gem 'RMagick' unless Object.const_defined?(:Magick)
17 rescue LoadError
17 rescue LoadError
18 # RMagick is not available
18 # RMagick is not available
19 end
19 end
20
20
21 if RUBY_VERSION < '1.9'
21 if RUBY_VERSION < '1.9'
22 require 'faster_csv'
22 require 'faster_csv'
23 else
23 else
24 require 'csv'
24 require 'csv'
25 FCSV = CSV
25 FCSV = CSV
26 end
26 end
27
27
28 Redmine::Scm::Base.add "Subversion"
28 Redmine::Scm::Base.add "Subversion"
29 Redmine::Scm::Base.add "Darcs"
29 Redmine::Scm::Base.add "Darcs"
30 Redmine::Scm::Base.add "Mercurial"
30 Redmine::Scm::Base.add "Mercurial"
31 Redmine::Scm::Base.add "Cvs"
31 Redmine::Scm::Base.add "Cvs"
32 Redmine::Scm::Base.add "Bazaar"
32 Redmine::Scm::Base.add "Bazaar"
33 Redmine::Scm::Base.add "Git"
33 Redmine::Scm::Base.add "Git"
34 Redmine::Scm::Base.add "Filesystem"
34 Redmine::Scm::Base.add "Filesystem"
35
35
36 Redmine::CustomFieldFormat.map do |fields|
36 Redmine::CustomFieldFormat.map do |fields|
37 fields.register Redmine::CustomFieldFormat.new('string', :label => :label_string, :order => 1)
37 fields.register Redmine::CustomFieldFormat.new('string', :label => :label_string, :order => 1)
38 fields.register Redmine::CustomFieldFormat.new('text', :label => :label_text, :order => 2)
38 fields.register Redmine::CustomFieldFormat.new('text', :label => :label_text, :order => 2)
39 fields.register Redmine::CustomFieldFormat.new('int', :label => :label_integer, :order => 3)
39 fields.register Redmine::CustomFieldFormat.new('int', :label => :label_integer, :order => 3)
40 fields.register Redmine::CustomFieldFormat.new('float', :label => :label_float, :order => 4)
40 fields.register Redmine::CustomFieldFormat.new('float', :label => :label_float, :order => 4)
41 fields.register Redmine::CustomFieldFormat.new('list', :label => :label_list, :order => 5)
41 fields.register Redmine::CustomFieldFormat.new('list', :label => :label_list, :order => 5)
42 fields.register Redmine::CustomFieldFormat.new('date', :label => :label_date, :order => 6)
42 fields.register Redmine::CustomFieldFormat.new('date', :label => :label_date, :order => 6)
43 fields.register Redmine::CustomFieldFormat.new('bool', :label => :label_boolean, :order => 7)
43 fields.register Redmine::CustomFieldFormat.new('bool', :label => :label_boolean, :order => 7)
44 fields.register Redmine::CustomFieldFormat.new('user', :label => :label_user, :only => %w(Issue TimeEntry Version Project), :edit_as => 'list', :order => 8)
44 fields.register Redmine::CustomFieldFormat.new('user', :label => :label_user, :only => %w(Issue TimeEntry Version Project), :edit_as => 'list', :order => 8)
45 fields.register Redmine::CustomFieldFormat.new('version', :label => :label_version, :only => %w(Issue TimeEntry Version Project), :edit_as => 'list', :order => 9)
45 fields.register Redmine::CustomFieldFormat.new('version', :label => :label_version, :only => %w(Issue TimeEntry Version Project), :edit_as => 'list', :order => 9)
46 end
46 end
47
47
48 # Permissions
48 # Permissions
49 Redmine::AccessControl.map do |map|
49 Redmine::AccessControl.map do |map|
50 map.permission :view_project, {:projects => [:show], :activities => [:index]}, :public => true
50 map.permission :view_project, {:projects => [:show], :activities => [:index]}, :public => true
51 map.permission :search_project, {:search => :index}, :public => true
51 map.permission :search_project, {:search => :index}, :public => true
52 map.permission :add_project, {:projects => [:new, :create]}, :require => :loggedin
52 map.permission :add_project, {:projects => [:new, :create]}, :require => :loggedin
53 map.permission :edit_project, {:projects => [:settings, :edit, :update]}, :require => :member
53 map.permission :edit_project, {:projects => [:settings, :edit, :update]}, :require => :member
54 map.permission :select_project_modules, {:projects => :modules}, :require => :member
54 map.permission :select_project_modules, {:projects => :modules}, :require => :member
55 map.permission :manage_members, {:projects => :settings, :members => [:new, :edit, :destroy, :autocomplete_for_member]}, :require => :member
55 map.permission :manage_members, {:projects => :settings, :members => [:new, :edit, :destroy, :autocomplete_for_member]}, :require => :member
56 map.permission :manage_versions, {:projects => :settings, :versions => [:new, :create, :edit, :update, :close_completed, :destroy]}, :require => :member
56 map.permission :manage_versions, {:projects => :settings, :versions => [:new, :create, :edit, :update, :close_completed, :destroy]}, :require => :member
57 map.permission :add_subprojects, {:projects => [:new, :create]}, :require => :member
57 map.permission :add_subprojects, {:projects => [:new, :create]}, :require => :member
58
58
59 map.project_module :issue_tracking do |map|
59 map.project_module :issue_tracking do |map|
60 # Issue categories
60 # Issue categories
61 map.permission :manage_categories, {:projects => :settings, :issue_categories => [:index, :show, :new, :create, :edit, :update, :destroy]}, :require => :member
61 map.permission :manage_categories, {:projects => :settings, :issue_categories => [:index, :show, :new, :create, :edit, :update, :destroy]}, :require => :member
62 # Issues
62 # Issues
63 map.permission :view_issues, {:issues => [:index, :show],
63 map.permission :view_issues, {:issues => [:index, :show],
64 :auto_complete => [:issues],
64 :auto_complete => [:issues],
65 :context_menus => [:issues],
65 :context_menus => [:issues],
66 :versions => [:index, :show, :status_by],
66 :versions => [:index, :show, :status_by],
67 :journals => [:index, :diff],
67 :journals => [:index, :diff],
68 :queries => :index,
68 :queries => :index,
69 :reports => [:issue_report, :issue_report_details]}
69 :reports => [:issue_report, :issue_report_details]}
70 map.permission :add_issues, {:issues => [:new, :create, :update_form]}
70 map.permission :add_issues, {:issues => [:new, :create, :update_form]}
71 map.permission :edit_issues, {:issues => [:edit, :update, :bulk_edit, :bulk_update, :update_form], :journals => [:new]}
71 map.permission :edit_issues, {:issues => [:edit, :update, :bulk_edit, :bulk_update, :update_form], :journals => [:new]}
72 map.permission :manage_issue_relations, {:issue_relations => [:index, :show, :create, :destroy]}
72 map.permission :manage_issue_relations, {:issue_relations => [:index, :show, :create, :destroy]}
73 map.permission :manage_subtasks, {}
73 map.permission :manage_subtasks, {}
74 map.permission :set_issues_private, {}
74 map.permission :set_issues_private, {}
75 map.permission :set_own_issues_private, {}, :require => :loggedin
75 map.permission :set_own_issues_private, {}, :require => :loggedin
76 map.permission :add_issue_notes, {:issues => [:edit, :update], :journals => [:new]}
76 map.permission :add_issue_notes, {:issues => [:edit, :update], :journals => [:new]}
77 map.permission :edit_issue_notes, {:journals => :edit}, :require => :loggedin
77 map.permission :edit_issue_notes, {:journals => :edit}, :require => :loggedin
78 map.permission :edit_own_issue_notes, {:journals => :edit}, :require => :loggedin
78 map.permission :edit_own_issue_notes, {:journals => :edit}, :require => :loggedin
79 map.permission :move_issues, {:issue_moves => [:new, :create]}, :require => :loggedin
79 map.permission :move_issues, {:issues => [:bulk_edit, :bulk_update]}, :require => :loggedin
80 map.permission :delete_issues, {:issues => :destroy}, :require => :member
80 map.permission :delete_issues, {:issues => :destroy}, :require => :member
81 # Queries
81 # Queries
82 map.permission :manage_public_queries, {:queries => [:new, :create, :edit, :update, :destroy]}, :require => :member
82 map.permission :manage_public_queries, {:queries => [:new, :create, :edit, :update, :destroy]}, :require => :member
83 map.permission :save_queries, {:queries => [:new, :create, :edit, :update, :destroy]}, :require => :loggedin
83 map.permission :save_queries, {:queries => [:new, :create, :edit, :update, :destroy]}, :require => :loggedin
84 # Watchers
84 # Watchers
85 map.permission :view_issue_watchers, {}
85 map.permission :view_issue_watchers, {}
86 map.permission :add_issue_watchers, {:watchers => :new}
86 map.permission :add_issue_watchers, {:watchers => :new}
87 map.permission :delete_issue_watchers, {:watchers => :destroy}
87 map.permission :delete_issue_watchers, {:watchers => :destroy}
88 end
88 end
89
89
90 map.project_module :time_tracking do |map|
90 map.project_module :time_tracking do |map|
91 map.permission :log_time, {:timelog => [:new, :create]}, :require => :loggedin
91 map.permission :log_time, {:timelog => [:new, :create]}, :require => :loggedin
92 map.permission :view_time_entries, :timelog => [:index, :report, :show]
92 map.permission :view_time_entries, :timelog => [:index, :report, :show]
93 map.permission :edit_time_entries, {:timelog => [:edit, :update, :destroy, :bulk_edit, :bulk_update]}, :require => :member
93 map.permission :edit_time_entries, {:timelog => [:edit, :update, :destroy, :bulk_edit, :bulk_update]}, :require => :member
94 map.permission :edit_own_time_entries, {:timelog => [:edit, :update, :destroy,:bulk_edit, :bulk_update]}, :require => :loggedin
94 map.permission :edit_own_time_entries, {:timelog => [:edit, :update, :destroy,:bulk_edit, :bulk_update]}, :require => :loggedin
95 map.permission :manage_project_activities, {:project_enumerations => [:update, :destroy]}, :require => :member
95 map.permission :manage_project_activities, {:project_enumerations => [:update, :destroy]}, :require => :member
96 end
96 end
97
97
98 map.project_module :news do |map|
98 map.project_module :news do |map|
99 map.permission :manage_news, {:news => [:new, :create, :edit, :update, :destroy], :comments => [:destroy]}, :require => :member
99 map.permission :manage_news, {:news => [:new, :create, :edit, :update, :destroy], :comments => [:destroy]}, :require => :member
100 map.permission :view_news, {:news => [:index, :show]}, :public => true
100 map.permission :view_news, {:news => [:index, :show]}, :public => true
101 map.permission :comment_news, {:comments => :create}
101 map.permission :comment_news, {:comments => :create}
102 end
102 end
103
103
104 map.project_module :documents do |map|
104 map.project_module :documents do |map|
105 map.permission :manage_documents, {:documents => [:new, :create, :edit, :update, :destroy, :add_attachment]}, :require => :loggedin
105 map.permission :manage_documents, {:documents => [:new, :create, :edit, :update, :destroy, :add_attachment]}, :require => :loggedin
106 map.permission :view_documents, :documents => [:index, :show, :download]
106 map.permission :view_documents, :documents => [:index, :show, :download]
107 end
107 end
108
108
109 map.project_module :files do |map|
109 map.project_module :files do |map|
110 map.permission :manage_files, {:files => [:new, :create]}, :require => :loggedin
110 map.permission :manage_files, {:files => [:new, :create]}, :require => :loggedin
111 map.permission :view_files, :files => :index, :versions => :download
111 map.permission :view_files, :files => :index, :versions => :download
112 end
112 end
113
113
114 map.project_module :wiki do |map|
114 map.project_module :wiki do |map|
115 map.permission :manage_wiki, {:wikis => [:edit, :destroy]}, :require => :member
115 map.permission :manage_wiki, {:wikis => [:edit, :destroy]}, :require => :member
116 map.permission :rename_wiki_pages, {:wiki => :rename}, :require => :member
116 map.permission :rename_wiki_pages, {:wiki => :rename}, :require => :member
117 map.permission :delete_wiki_pages, {:wiki => :destroy}, :require => :member
117 map.permission :delete_wiki_pages, {:wiki => :destroy}, :require => :member
118 map.permission :view_wiki_pages, :wiki => [:index, :show, :special, :date_index]
118 map.permission :view_wiki_pages, :wiki => [:index, :show, :special, :date_index]
119 map.permission :export_wiki_pages, :wiki => [:export]
119 map.permission :export_wiki_pages, :wiki => [:export]
120 map.permission :view_wiki_edits, :wiki => [:history, :diff, :annotate]
120 map.permission :view_wiki_edits, :wiki => [:history, :diff, :annotate]
121 map.permission :edit_wiki_pages, :wiki => [:edit, :update, :preview, :add_attachment]
121 map.permission :edit_wiki_pages, :wiki => [:edit, :update, :preview, :add_attachment]
122 map.permission :delete_wiki_pages_attachments, {}
122 map.permission :delete_wiki_pages_attachments, {}
123 map.permission :protect_wiki_pages, {:wiki => :protect}, :require => :member
123 map.permission :protect_wiki_pages, {:wiki => :protect}, :require => :member
124 end
124 end
125
125
126 map.project_module :repository do |map|
126 map.project_module :repository do |map|
127 map.permission :manage_repository, {:repositories => [:edit, :committers, :destroy]}, :require => :member
127 map.permission :manage_repository, {:repositories => [:edit, :committers, :destroy]}, :require => :member
128 map.permission :browse_repository, :repositories => [:show, :browse, :entry, :annotate, :changes, :diff, :stats, :graph]
128 map.permission :browse_repository, :repositories => [:show, :browse, :entry, :annotate, :changes, :diff, :stats, :graph]
129 map.permission :view_changesets, :repositories => [:show, :revisions, :revision]
129 map.permission :view_changesets, :repositories => [:show, :revisions, :revision]
130 map.permission :commit_access, {}
130 map.permission :commit_access, {}
131 end
131 end
132
132
133 map.project_module :boards do |map|
133 map.project_module :boards do |map|
134 map.permission :manage_boards, {:boards => [:new, :create, :edit, :update, :destroy]}, :require => :member
134 map.permission :manage_boards, {:boards => [:new, :create, :edit, :update, :destroy]}, :require => :member
135 map.permission :view_messages, {:boards => [:index, :show], :messages => [:show]}, :public => true
135 map.permission :view_messages, {:boards => [:index, :show], :messages => [:show]}, :public => true
136 map.permission :add_messages, {:messages => [:new, :reply, :quote]}
136 map.permission :add_messages, {:messages => [:new, :reply, :quote]}
137 map.permission :edit_messages, {:messages => :edit}, :require => :member
137 map.permission :edit_messages, {:messages => :edit}, :require => :member
138 map.permission :edit_own_messages, {:messages => :edit}, :require => :loggedin
138 map.permission :edit_own_messages, {:messages => :edit}, :require => :loggedin
139 map.permission :delete_messages, {:messages => :destroy}, :require => :member
139 map.permission :delete_messages, {:messages => :destroy}, :require => :member
140 map.permission :delete_own_messages, {:messages => :destroy}, :require => :loggedin
140 map.permission :delete_own_messages, {:messages => :destroy}, :require => :loggedin
141 end
141 end
142
142
143 map.project_module :calendar do |map|
143 map.project_module :calendar do |map|
144 map.permission :view_calendar, :calendars => [:show, :update]
144 map.permission :view_calendar, :calendars => [:show, :update]
145 end
145 end
146
146
147 map.project_module :gantt do |map|
147 map.project_module :gantt do |map|
148 map.permission :view_gantt, :gantts => [:show, :update]
148 map.permission :view_gantt, :gantts => [:show, :update]
149 end
149 end
150 end
150 end
151
151
152 Redmine::MenuManager.map :top_menu do |menu|
152 Redmine::MenuManager.map :top_menu do |menu|
153 menu.push :home, :home_path
153 menu.push :home, :home_path
154 menu.push :my_page, { :controller => 'my', :action => 'page' }, :if => Proc.new { User.current.logged? }
154 menu.push :my_page, { :controller => 'my', :action => 'page' }, :if => Proc.new { User.current.logged? }
155 menu.push :projects, { :controller => 'projects', :action => 'index' }, :caption => :label_project_plural
155 menu.push :projects, { :controller => 'projects', :action => 'index' }, :caption => :label_project_plural
156 menu.push :administration, { :controller => 'admin', :action => 'index' }, :if => Proc.new { User.current.admin? }, :last => true
156 menu.push :administration, { :controller => 'admin', :action => 'index' }, :if => Proc.new { User.current.admin? }, :last => true
157 menu.push :help, Redmine::Info.help_url, :last => true
157 menu.push :help, Redmine::Info.help_url, :last => true
158 end
158 end
159
159
160 Redmine::MenuManager.map :account_menu do |menu|
160 Redmine::MenuManager.map :account_menu do |menu|
161 menu.push :login, :signin_path, :if => Proc.new { !User.current.logged? }
161 menu.push :login, :signin_path, :if => Proc.new { !User.current.logged? }
162 menu.push :register, { :controller => 'account', :action => 'register' }, :if => Proc.new { !User.current.logged? && Setting.self_registration? }
162 menu.push :register, { :controller => 'account', :action => 'register' }, :if => Proc.new { !User.current.logged? && Setting.self_registration? }
163 menu.push :my_account, { :controller => 'my', :action => 'account' }, :if => Proc.new { User.current.logged? }
163 menu.push :my_account, { :controller => 'my', :action => 'account' }, :if => Proc.new { User.current.logged? }
164 menu.push :logout, :signout_path, :if => Proc.new { User.current.logged? }
164 menu.push :logout, :signout_path, :if => Proc.new { User.current.logged? }
165 end
165 end
166
166
167 Redmine::MenuManager.map :application_menu do |menu|
167 Redmine::MenuManager.map :application_menu do |menu|
168 # Empty
168 # Empty
169 end
169 end
170
170
171 Redmine::MenuManager.map :admin_menu do |menu|
171 Redmine::MenuManager.map :admin_menu do |menu|
172 menu.push :projects, {:controller => 'admin', :action => 'projects'}, :caption => :label_project_plural
172 menu.push :projects, {:controller => 'admin', :action => 'projects'}, :caption => :label_project_plural
173 menu.push :users, {:controller => 'users'}, :caption => :label_user_plural
173 menu.push :users, {:controller => 'users'}, :caption => :label_user_plural
174 menu.push :groups, {:controller => 'groups'}, :caption => :label_group_plural
174 menu.push :groups, {:controller => 'groups'}, :caption => :label_group_plural
175 menu.push :roles, {:controller => 'roles'}, :caption => :label_role_and_permissions
175 menu.push :roles, {:controller => 'roles'}, :caption => :label_role_and_permissions
176 menu.push :trackers, {:controller => 'trackers'}, :caption => :label_tracker_plural
176 menu.push :trackers, {:controller => 'trackers'}, :caption => :label_tracker_plural
177 menu.push :issue_statuses, {:controller => 'issue_statuses'}, :caption => :label_issue_status_plural,
177 menu.push :issue_statuses, {:controller => 'issue_statuses'}, :caption => :label_issue_status_plural,
178 :html => {:class => 'issue_statuses'}
178 :html => {:class => 'issue_statuses'}
179 menu.push :workflows, {:controller => 'workflows', :action => 'edit'}, :caption => :label_workflow
179 menu.push :workflows, {:controller => 'workflows', :action => 'edit'}, :caption => :label_workflow
180 menu.push :custom_fields, {:controller => 'custom_fields'}, :caption => :label_custom_field_plural,
180 menu.push :custom_fields, {:controller => 'custom_fields'}, :caption => :label_custom_field_plural,
181 :html => {:class => 'custom_fields'}
181 :html => {:class => 'custom_fields'}
182 menu.push :enumerations, {:controller => 'enumerations'}
182 menu.push :enumerations, {:controller => 'enumerations'}
183 menu.push :settings, {:controller => 'settings'}
183 menu.push :settings, {:controller => 'settings'}
184 menu.push :ldap_authentication, {:controller => 'ldap_auth_sources', :action => 'index'},
184 menu.push :ldap_authentication, {:controller => 'ldap_auth_sources', :action => 'index'},
185 :html => {:class => 'server_authentication'}
185 :html => {:class => 'server_authentication'}
186 menu.push :plugins, {:controller => 'admin', :action => 'plugins'}, :last => true
186 menu.push :plugins, {:controller => 'admin', :action => 'plugins'}, :last => true
187 menu.push :info, {:controller => 'admin', :action => 'info'}, :caption => :label_information_plural, :last => true
187 menu.push :info, {:controller => 'admin', :action => 'info'}, :caption => :label_information_plural, :last => true
188 end
188 end
189
189
190 Redmine::MenuManager.map :project_menu do |menu|
190 Redmine::MenuManager.map :project_menu do |menu|
191 menu.push :overview, { :controller => 'projects', :action => 'show' }
191 menu.push :overview, { :controller => 'projects', :action => 'show' }
192 menu.push :activity, { :controller => 'activities', :action => 'index' }
192 menu.push :activity, { :controller => 'activities', :action => 'index' }
193 menu.push :roadmap, { :controller => 'versions', :action => 'index' }, :param => :project_id,
193 menu.push :roadmap, { :controller => 'versions', :action => 'index' }, :param => :project_id,
194 :if => Proc.new { |p| p.shared_versions.any? }
194 :if => Proc.new { |p| p.shared_versions.any? }
195 menu.push :issues, { :controller => 'issues', :action => 'index' }, :param => :project_id, :caption => :label_issue_plural
195 menu.push :issues, { :controller => 'issues', :action => 'index' }, :param => :project_id, :caption => :label_issue_plural
196 menu.push :new_issue, { :controller => 'issues', :action => 'new' }, :param => :project_id, :caption => :label_issue_new,
196 menu.push :new_issue, { :controller => 'issues', :action => 'new' }, :param => :project_id, :caption => :label_issue_new,
197 :html => { :accesskey => Redmine::AccessKeys.key_for(:new_issue) }
197 :html => { :accesskey => Redmine::AccessKeys.key_for(:new_issue) }
198 menu.push :gantt, { :controller => 'gantts', :action => 'show' }, :param => :project_id, :caption => :label_gantt
198 menu.push :gantt, { :controller => 'gantts', :action => 'show' }, :param => :project_id, :caption => :label_gantt
199 menu.push :calendar, { :controller => 'calendars', :action => 'show' }, :param => :project_id, :caption => :label_calendar
199 menu.push :calendar, { :controller => 'calendars', :action => 'show' }, :param => :project_id, :caption => :label_calendar
200 menu.push :news, { :controller => 'news', :action => 'index' }, :param => :project_id, :caption => :label_news_plural
200 menu.push :news, { :controller => 'news', :action => 'index' }, :param => :project_id, :caption => :label_news_plural
201 menu.push :documents, { :controller => 'documents', :action => 'index' }, :param => :project_id, :caption => :label_document_plural
201 menu.push :documents, { :controller => 'documents', :action => 'index' }, :param => :project_id, :caption => :label_document_plural
202 menu.push :wiki, { :controller => 'wiki', :action => 'show', :id => nil }, :param => :project_id,
202 menu.push :wiki, { :controller => 'wiki', :action => 'show', :id => nil }, :param => :project_id,
203 :if => Proc.new { |p| p.wiki && !p.wiki.new_record? }
203 :if => Proc.new { |p| p.wiki && !p.wiki.new_record? }
204 menu.push :boards, { :controller => 'boards', :action => 'index', :id => nil }, :param => :project_id,
204 menu.push :boards, { :controller => 'boards', :action => 'index', :id => nil }, :param => :project_id,
205 :if => Proc.new { |p| p.boards.any? }, :caption => :label_board_plural
205 :if => Proc.new { |p| p.boards.any? }, :caption => :label_board_plural
206 menu.push :files, { :controller => 'files', :action => 'index' }, :caption => :label_file_plural, :param => :project_id
206 menu.push :files, { :controller => 'files', :action => 'index' }, :caption => :label_file_plural, :param => :project_id
207 menu.push :repository, { :controller => 'repositories', :action => 'show' },
207 menu.push :repository, { :controller => 'repositories', :action => 'show' },
208 :if => Proc.new { |p| p.repository && !p.repository.new_record? }
208 :if => Proc.new { |p| p.repository && !p.repository.new_record? }
209 menu.push :settings, { :controller => 'projects', :action => 'settings' }, :last => true
209 menu.push :settings, { :controller => 'projects', :action => 'settings' }, :last => true
210 end
210 end
211
211
212 Redmine::Activity.map do |activity|
212 Redmine::Activity.map do |activity|
213 activity.register :issues, :class_name => %w(Issue Journal)
213 activity.register :issues, :class_name => %w(Issue Journal)
214 activity.register :changesets
214 activity.register :changesets
215 activity.register :news
215 activity.register :news
216 activity.register :documents, :class_name => %w(Document Attachment)
216 activity.register :documents, :class_name => %w(Document Attachment)
217 activity.register :files, :class_name => 'Attachment'
217 activity.register :files, :class_name => 'Attachment'
218 activity.register :wiki_edits, :class_name => 'WikiContent::Version', :default => false
218 activity.register :wiki_edits, :class_name => 'WikiContent::Version', :default => false
219 activity.register :messages, :default => false
219 activity.register :messages, :default => false
220 activity.register :time_entries, :default => false
220 activity.register :time_entries, :default => false
221 end
221 end
222
222
223 Redmine::Search.map do |search|
223 Redmine::Search.map do |search|
224 search.register :issues
224 search.register :issues
225 search.register :news
225 search.register :news
226 search.register :documents
226 search.register :documents
227 search.register :changesets
227 search.register :changesets
228 search.register :wiki_pages
228 search.register :wiki_pages
229 search.register :messages
229 search.register :messages
230 search.register :projects
230 search.register :projects
231 end
231 end
232
232
233 Redmine::WikiFormatting.map do |format|
233 Redmine::WikiFormatting.map do |format|
234 format.register :textile, Redmine::WikiFormatting::Textile::Formatter, Redmine::WikiFormatting::Textile::Helper
234 format.register :textile, Redmine::WikiFormatting::Textile::Formatter, Redmine::WikiFormatting::Textile::Helper
235 end
235 end
236
236
237 ActionView::Template.register_template_handler :rsb, Redmine::Views::ApiTemplateHandler
237 ActionView::Template.register_template_handler :rsb, Redmine::Views::ApiTemplateHandler
@@ -1,148 +1,148
1 require File.expand_path('../../test_helper', __FILE__)
1 require File.expand_path('../../test_helper', __FILE__)
2
2
3 class ContextMenusControllerTest < ActionController::TestCase
3 class ContextMenusControllerTest < ActionController::TestCase
4 fixtures :projects,
4 fixtures :projects,
5 :trackers,
5 :trackers,
6 :projects_trackers,
6 :projects_trackers,
7 :roles,
7 :roles,
8 :member_roles,
8 :member_roles,
9 :members,
9 :members,
10 :auth_sources,
10 :auth_sources,
11 :enabled_modules,
11 :enabled_modules,
12 :workflows,
12 :workflows,
13 :journals, :journal_details,
13 :journals, :journal_details,
14 :versions,
14 :versions,
15 :issues, :issue_statuses, :issue_categories,
15 :issues, :issue_statuses, :issue_categories,
16 :users,
16 :users,
17 :enumerations,
17 :enumerations,
18 :time_entries
18 :time_entries
19
19
20 def test_context_menu_one_issue
20 def test_context_menu_one_issue
21 @request.session[:user_id] = 2
21 @request.session[:user_id] = 2
22 get :issues, :ids => [1]
22 get :issues, :ids => [1]
23 assert_response :success
23 assert_response :success
24 assert_template 'context_menu'
24 assert_template 'context_menu'
25 assert_tag :tag => 'a', :content => 'Edit',
25 assert_tag :tag => 'a', :content => 'Edit',
26 :attributes => { :href => '/issues/1/edit',
26 :attributes => { :href => '/issues/1/edit',
27 :class => 'icon-edit' }
27 :class => 'icon-edit' }
28 assert_tag :tag => 'a', :content => 'Closed',
28 assert_tag :tag => 'a', :content => 'Closed',
29 :attributes => { :href => '/issues/bulk_update?ids%5B%5D=1&amp;issue%5Bstatus_id%5D=5',
29 :attributes => { :href => '/issues/bulk_update?ids%5B%5D=1&amp;issue%5Bstatus_id%5D=5',
30 :class => '' }
30 :class => '' }
31 assert_tag :tag => 'a', :content => 'Immediate',
31 assert_tag :tag => 'a', :content => 'Immediate',
32 :attributes => { :href => '/issues/bulk_update?ids%5B%5D=1&amp;issue%5Bpriority_id%5D=8',
32 :attributes => { :href => '/issues/bulk_update?ids%5B%5D=1&amp;issue%5Bpriority_id%5D=8',
33 :class => '' }
33 :class => '' }
34 assert_no_tag :tag => 'a', :content => 'Inactive Priority'
34 assert_no_tag :tag => 'a', :content => 'Inactive Priority'
35 # Versions
35 # Versions
36 assert_tag :tag => 'a', :content => '2.0',
36 assert_tag :tag => 'a', :content => '2.0',
37 :attributes => { :href => '/issues/bulk_update?ids%5B%5D=1&amp;issue%5Bfixed_version_id%5D=3',
37 :attributes => { :href => '/issues/bulk_update?ids%5B%5D=1&amp;issue%5Bfixed_version_id%5D=3',
38 :class => '' }
38 :class => '' }
39 assert_tag :tag => 'a', :content => 'eCookbook Subproject 1 - 2.0',
39 assert_tag :tag => 'a', :content => 'eCookbook Subproject 1 - 2.0',
40 :attributes => { :href => '/issues/bulk_update?ids%5B%5D=1&amp;issue%5Bfixed_version_id%5D=4',
40 :attributes => { :href => '/issues/bulk_update?ids%5B%5D=1&amp;issue%5Bfixed_version_id%5D=4',
41 :class => '' }
41 :class => '' }
42
42
43 assert_tag :tag => 'a', :content => 'Dave Lopper',
43 assert_tag :tag => 'a', :content => 'Dave Lopper',
44 :attributes => { :href => '/issues/bulk_update?ids%5B%5D=1&amp;issue%5Bassigned_to_id%5D=3',
44 :attributes => { :href => '/issues/bulk_update?ids%5B%5D=1&amp;issue%5Bassigned_to_id%5D=3',
45 :class => '' }
45 :class => '' }
46 assert_tag :tag => 'a', :content => 'Duplicate',
46 assert_tag :tag => 'a', :content => 'Duplicate',
47 :attributes => { :href => '/projects/ecookbook/issues/1/copy',
47 :attributes => { :href => '/projects/ecookbook/issues/1/copy',
48 :class => 'icon-duplicate' }
48 :class => 'icon-duplicate' }
49 assert_tag :tag => 'a', :content => 'Copy',
49 assert_tag :tag => 'a', :content => 'Copy',
50 :attributes => { :href => '/issues/move/new?copy_options%5Bcopy%5D=t&amp;ids%5B%5D=1',
50 :attributes => { :href => '/issues/bulk_edit?copy=1&amp;ids%5B%5D=1',
51 :class => 'icon-copy' }
51 :class => 'icon-copy' }
52 assert_no_tag :tag => 'a', :content => 'Move'
52 assert_no_tag :tag => 'a', :content => 'Move'
53 assert_tag :tag => 'a', :content => 'Delete',
53 assert_tag :tag => 'a', :content => 'Delete',
54 :attributes => { :href => '/issues?ids%5B%5D=1',
54 :attributes => { :href => '/issues?ids%5B%5D=1',
55 :class => 'icon-del' }
55 :class => 'icon-del' }
56 end
56 end
57
57
58 def test_context_menu_one_issue_by_anonymous
58 def test_context_menu_one_issue_by_anonymous
59 get :issues, :ids => [1]
59 get :issues, :ids => [1]
60 assert_response :success
60 assert_response :success
61 assert_template 'context_menu'
61 assert_template 'context_menu'
62 assert_tag :tag => 'a', :content => 'Delete',
62 assert_tag :tag => 'a', :content => 'Delete',
63 :attributes => { :href => '#',
63 :attributes => { :href => '#',
64 :class => 'icon-del disabled' }
64 :class => 'icon-del disabled' }
65 end
65 end
66
66
67 def test_context_menu_multiple_issues_of_same_project
67 def test_context_menu_multiple_issues_of_same_project
68 @request.session[:user_id] = 2
68 @request.session[:user_id] = 2
69 get :issues, :ids => [1, 2]
69 get :issues, :ids => [1, 2]
70 assert_response :success
70 assert_response :success
71 assert_template 'context_menu'
71 assert_template 'context_menu'
72 assert_not_nil assigns(:issues)
72 assert_not_nil assigns(:issues)
73 assert_equal [1, 2], assigns(:issues).map(&:id).sort
73 assert_equal [1, 2], assigns(:issues).map(&:id).sort
74
74
75 ids = assigns(:issues).map(&:id).map {|i| "ids%5B%5D=#{i}"}.join('&amp;')
75 ids = assigns(:issues).map(&:id).map {|i| "ids%5B%5D=#{i}"}.join('&amp;')
76 assert_tag :tag => 'a', :content => 'Edit',
76 assert_tag :tag => 'a', :content => 'Edit',
77 :attributes => { :href => "/issues/bulk_edit?#{ids}",
77 :attributes => { :href => "/issues/bulk_edit?#{ids}",
78 :class => 'icon-edit' }
78 :class => 'icon-edit' }
79 assert_tag :tag => 'a', :content => 'Closed',
79 assert_tag :tag => 'a', :content => 'Closed',
80 :attributes => { :href => "/issues/bulk_update?#{ids}&amp;issue%5Bstatus_id%5D=5",
80 :attributes => { :href => "/issues/bulk_update?#{ids}&amp;issue%5Bstatus_id%5D=5",
81 :class => '' }
81 :class => '' }
82 assert_tag :tag => 'a', :content => 'Immediate',
82 assert_tag :tag => 'a', :content => 'Immediate',
83 :attributes => { :href => "/issues/bulk_update?#{ids}&amp;issue%5Bpriority_id%5D=8",
83 :attributes => { :href => "/issues/bulk_update?#{ids}&amp;issue%5Bpriority_id%5D=8",
84 :class => '' }
84 :class => '' }
85 assert_tag :tag => 'a', :content => 'Dave Lopper',
85 assert_tag :tag => 'a', :content => 'Dave Lopper',
86 :attributes => { :href => "/issues/bulk_update?#{ids}&amp;issue%5Bassigned_to_id%5D=3",
86 :attributes => { :href => "/issues/bulk_update?#{ids}&amp;issue%5Bassigned_to_id%5D=3",
87 :class => '' }
87 :class => '' }
88 assert_tag :tag => 'a', :content => 'Copy',
88 assert_tag :tag => 'a', :content => 'Copy',
89 :attributes => { :href => "/issues/move/new?copy_options%5Bcopy%5D=t&amp;#{ids}",
89 :attributes => { :href => "/issues/bulk_edit?copy=1&amp;#{ids}",
90 :class => 'icon-copy' }
90 :class => 'icon-copy' }
91 assert_no_tag :tag => 'a', :content => 'Move'
91 assert_no_tag :tag => 'a', :content => 'Move'
92 assert_tag :tag => 'a', :content => 'Delete',
92 assert_tag :tag => 'a', :content => 'Delete',
93 :attributes => { :href => "/issues?#{ids}",
93 :attributes => { :href => "/issues?#{ids}",
94 :class => 'icon-del' }
94 :class => 'icon-del' }
95 end
95 end
96
96
97 def test_context_menu_multiple_issues_of_different_projects
97 def test_context_menu_multiple_issues_of_different_projects
98 @request.session[:user_id] = 2
98 @request.session[:user_id] = 2
99 get :issues, :ids => [1, 2, 6]
99 get :issues, :ids => [1, 2, 6]
100 assert_response :success
100 assert_response :success
101 assert_template 'context_menu'
101 assert_template 'context_menu'
102 assert_not_nil assigns(:issues)
102 assert_not_nil assigns(:issues)
103 assert_equal [1, 2, 6], assigns(:issues).map(&:id).sort
103 assert_equal [1, 2, 6], assigns(:issues).map(&:id).sort
104
104
105 ids = assigns(:issues).map(&:id).map {|i| "ids%5B%5D=#{i}"}.join('&amp;')
105 ids = assigns(:issues).map(&:id).map {|i| "ids%5B%5D=#{i}"}.join('&amp;')
106 assert_tag :tag => 'a', :content => 'Edit',
106 assert_tag :tag => 'a', :content => 'Edit',
107 :attributes => { :href => "/issues/bulk_edit?#{ids}",
107 :attributes => { :href => "/issues/bulk_edit?#{ids}",
108 :class => 'icon-edit' }
108 :class => 'icon-edit' }
109 assert_tag :tag => 'a', :content => 'Closed',
109 assert_tag :tag => 'a', :content => 'Closed',
110 :attributes => { :href => "/issues/bulk_update?#{ids}&amp;issue%5Bstatus_id%5D=5",
110 :attributes => { :href => "/issues/bulk_update?#{ids}&amp;issue%5Bstatus_id%5D=5",
111 :class => '' }
111 :class => '' }
112 assert_tag :tag => 'a', :content => 'Immediate',
112 assert_tag :tag => 'a', :content => 'Immediate',
113 :attributes => { :href => "/issues/bulk_update?#{ids}&amp;issue%5Bpriority_id%5D=8",
113 :attributes => { :href => "/issues/bulk_update?#{ids}&amp;issue%5Bpriority_id%5D=8",
114 :class => '' }
114 :class => '' }
115 assert_tag :tag => 'a', :content => 'John Smith',
115 assert_tag :tag => 'a', :content => 'John Smith',
116 :attributes => { :href => "/issues/bulk_update?#{ids}&amp;issue%5Bassigned_to_id%5D=2",
116 :attributes => { :href => "/issues/bulk_update?#{ids}&amp;issue%5Bassigned_to_id%5D=2",
117 :class => '' }
117 :class => '' }
118 assert_tag :tag => 'a', :content => 'Delete',
118 assert_tag :tag => 'a', :content => 'Delete',
119 :attributes => { :href => "/issues?#{ids}",
119 :attributes => { :href => "/issues?#{ids}",
120 :class => 'icon-del' }
120 :class => 'icon-del' }
121 end
121 end
122
122
123 def test_context_menu_issue_visibility
123 def test_context_menu_issue_visibility
124 get :issues, :ids => [1, 4]
124 get :issues, :ids => [1, 4]
125 assert_response :success
125 assert_response :success
126 assert_template 'context_menu'
126 assert_template 'context_menu'
127 assert_equal [1], assigns(:issues).collect(&:id)
127 assert_equal [1], assigns(:issues).collect(&:id)
128 end
128 end
129
129
130 def test_time_entries_context_menu
130 def test_time_entries_context_menu
131 @request.session[:user_id] = 2
131 @request.session[:user_id] = 2
132 get :time_entries, :ids => [1, 2]
132 get :time_entries, :ids => [1, 2]
133 assert_response :success
133 assert_response :success
134 assert_template 'time_entries'
134 assert_template 'time_entries'
135 assert_tag 'a', :content => 'Edit'
135 assert_tag 'a', :content => 'Edit'
136 assert_no_tag 'a', :content => 'Edit', :attributes => {:class => /disabled/}
136 assert_no_tag 'a', :content => 'Edit', :attributes => {:class => /disabled/}
137 end
137 end
138
138
139 def test_time_entries_context_menu_without_edit_permission
139 def test_time_entries_context_menu_without_edit_permission
140 @request.session[:user_id] = 2
140 @request.session[:user_id] = 2
141 Role.find_by_name('Manager').remove_permission! :edit_time_entries
141 Role.find_by_name('Manager').remove_permission! :edit_time_entries
142
142
143 get :time_entries, :ids => [1, 2]
143 get :time_entries, :ids => [1, 2]
144 assert_response :success
144 assert_response :success
145 assert_template 'time_entries'
145 assert_template 'time_entries'
146 assert_tag 'a', :content => 'Edit', :attributes => {:class => /disabled/}
146 assert_tag 'a', :content => 'Edit', :attributes => {:class => /disabled/}
147 end
147 end
148 end
148 end
@@ -1,2390 +1,2471
1 # Redmine - project management software
1 # Redmine - project management software
2 # Copyright (C) 2006-2011 Jean-Philippe Lang
2 # Copyright (C) 2006-2011 Jean-Philippe Lang
3 #
3 #
4 # This program is free software; you can redistribute it and/or
4 # This program is free software; you can redistribute it and/or
5 # modify it under the terms of the GNU General Public License
5 # modify it under the terms of the GNU General Public License
6 # as published by the Free Software Foundation; either version 2
6 # as published by the Free Software Foundation; either version 2
7 # of the License, or (at your option) any later version.
7 # of the License, or (at your option) any later version.
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 require 'issues_controller'
19 require 'issues_controller'
20
20
21 class IssuesControllerTest < ActionController::TestCase
21 class IssuesControllerTest < ActionController::TestCase
22 fixtures :projects,
22 fixtures :projects,
23 :users,
23 :users,
24 :roles,
24 :roles,
25 :members,
25 :members,
26 :member_roles,
26 :member_roles,
27 :issues,
27 :issues,
28 :issue_statuses,
28 :issue_statuses,
29 :versions,
29 :versions,
30 :trackers,
30 :trackers,
31 :projects_trackers,
31 :projects_trackers,
32 :issue_categories,
32 :issue_categories,
33 :enabled_modules,
33 :enabled_modules,
34 :enumerations,
34 :enumerations,
35 :attachments,
35 :attachments,
36 :workflows,
36 :workflows,
37 :custom_fields,
37 :custom_fields,
38 :custom_values,
38 :custom_values,
39 :custom_fields_projects,
39 :custom_fields_projects,
40 :custom_fields_trackers,
40 :custom_fields_trackers,
41 :time_entries,
41 :time_entries,
42 :journals,
42 :journals,
43 :journal_details,
43 :journal_details,
44 :queries
44 :queries
45
45
46 include Redmine::I18n
46 include Redmine::I18n
47
47
48 def setup
48 def setup
49 @controller = IssuesController.new
49 @controller = IssuesController.new
50 @request = ActionController::TestRequest.new
50 @request = ActionController::TestRequest.new
51 @response = ActionController::TestResponse.new
51 @response = ActionController::TestResponse.new
52 User.current = nil
52 User.current = nil
53 end
53 end
54
54
55 def test_index
55 def test_index
56 Setting.default_language = 'en'
56 Setting.default_language = 'en'
57
57
58 get :index
58 get :index
59 assert_response :success
59 assert_response :success
60 assert_template 'index'
60 assert_template 'index'
61 assert_not_nil assigns(:issues)
61 assert_not_nil assigns(:issues)
62 assert_nil assigns(:project)
62 assert_nil assigns(:project)
63 assert_tag :tag => 'a', :content => /Can't print recipes/
63 assert_tag :tag => 'a', :content => /Can't print recipes/
64 assert_tag :tag => 'a', :content => /Subproject issue/
64 assert_tag :tag => 'a', :content => /Subproject issue/
65 # private projects hidden
65 # private projects hidden
66 assert_no_tag :tag => 'a', :content => /Issue of a private subproject/
66 assert_no_tag :tag => 'a', :content => /Issue of a private subproject/
67 assert_no_tag :tag => 'a', :content => /Issue on project 2/
67 assert_no_tag :tag => 'a', :content => /Issue on project 2/
68 # project column
68 # project column
69 assert_tag :tag => 'th', :content => /Project/
69 assert_tag :tag => 'th', :content => /Project/
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 assert_no_tag :tag => 'a', :content => /Can't print recipes/
79 assert_no_tag :tag => 'a', :content => /Can't print recipes/
80 assert_tag :tag => 'a', :content => /Subproject issue/
80 assert_tag :tag => 'a', :content => /Subproject issue/
81 end
81 end
82
82
83 def test_index_should_list_visible_issues_only
83 def test_index_should_list_visible_issues_only
84 get :index, :per_page => 100
84 get :index, :per_page => 100
85 assert_response :success
85 assert_response :success
86 assert_not_nil assigns(:issues)
86 assert_not_nil assigns(:issues)
87 assert_nil assigns(:issues).detect {|issue| !issue.visible?}
87 assert_nil assigns(:issues).detect {|issue| !issue.visible?}
88 end
88 end
89
89
90 def test_index_with_project
90 def test_index_with_project
91 Setting.display_subprojects_issues = 0
91 Setting.display_subprojects_issues = 0
92 get :index, :project_id => 1
92 get :index, :project_id => 1
93 assert_response :success
93 assert_response :success
94 assert_template 'index'
94 assert_template 'index'
95 assert_not_nil assigns(:issues)
95 assert_not_nil assigns(:issues)
96 assert_tag :tag => 'a', :content => /Can't print recipes/
96 assert_tag :tag => 'a', :content => /Can't print recipes/
97 assert_no_tag :tag => 'a', :content => /Subproject issue/
97 assert_no_tag :tag => 'a', :content => /Subproject issue/
98 end
98 end
99
99
100 def test_index_with_project_and_subprojects
100 def test_index_with_project_and_subprojects
101 Setting.display_subprojects_issues = 1
101 Setting.display_subprojects_issues = 1
102 get :index, :project_id => 1
102 get :index, :project_id => 1
103 assert_response :success
103 assert_response :success
104 assert_template 'index'
104 assert_template 'index'
105 assert_not_nil assigns(:issues)
105 assert_not_nil assigns(:issues)
106 assert_tag :tag => 'a', :content => /Can't print recipes/
106 assert_tag :tag => 'a', :content => /Can't print recipes/
107 assert_tag :tag => 'a', :content => /Subproject issue/
107 assert_tag :tag => 'a', :content => /Subproject issue/
108 assert_no_tag :tag => 'a', :content => /Issue of a private subproject/
108 assert_no_tag :tag => 'a', :content => /Issue of a private subproject/
109 end
109 end
110
110
111 def test_index_with_project_and_subprojects_should_show_private_subprojects
111 def test_index_with_project_and_subprojects_should_show_private_subprojects
112 @request.session[:user_id] = 2
112 @request.session[:user_id] = 2
113 Setting.display_subprojects_issues = 1
113 Setting.display_subprojects_issues = 1
114 get :index, :project_id => 1
114 get :index, :project_id => 1
115 assert_response :success
115 assert_response :success
116 assert_template 'index'
116 assert_template 'index'
117 assert_not_nil assigns(:issues)
117 assert_not_nil assigns(:issues)
118 assert_tag :tag => 'a', :content => /Can't print recipes/
118 assert_tag :tag => 'a', :content => /Can't print recipes/
119 assert_tag :tag => 'a', :content => /Subproject issue/
119 assert_tag :tag => 'a', :content => /Subproject issue/
120 assert_tag :tag => 'a', :content => /Issue of a private subproject/
120 assert_tag :tag => 'a', :content => /Issue of a private subproject/
121 end
121 end
122
122
123 def test_index_with_project_and_default_filter
123 def test_index_with_project_and_default_filter
124 get :index, :project_id => 1, :set_filter => 1
124 get :index, :project_id => 1, :set_filter => 1
125 assert_response :success
125 assert_response :success
126 assert_template 'index'
126 assert_template 'index'
127 assert_not_nil assigns(:issues)
127 assert_not_nil assigns(:issues)
128
128
129 query = assigns(:query)
129 query = assigns(:query)
130 assert_not_nil query
130 assert_not_nil query
131 # default filter
131 # default filter
132 assert_equal({'status_id' => {:operator => 'o', :values => ['']}}, query.filters)
132 assert_equal({'status_id' => {:operator => 'o', :values => ['']}}, query.filters)
133 end
133 end
134
134
135 def test_index_with_project_and_filter
135 def test_index_with_project_and_filter
136 get :index, :project_id => 1, :set_filter => 1,
136 get :index, :project_id => 1, :set_filter => 1,
137 :f => ['tracker_id'],
137 :f => ['tracker_id'],
138 :op => {'tracker_id' => '='},
138 :op => {'tracker_id' => '='},
139 :v => {'tracker_id' => ['1']}
139 :v => {'tracker_id' => ['1']}
140 assert_response :success
140 assert_response :success
141 assert_template 'index'
141 assert_template 'index'
142 assert_not_nil assigns(:issues)
142 assert_not_nil assigns(:issues)
143
143
144 query = assigns(:query)
144 query = assigns(:query)
145 assert_not_nil query
145 assert_not_nil query
146 assert_equal({'tracker_id' => {:operator => '=', :values => ['1']}}, query.filters)
146 assert_equal({'tracker_id' => {:operator => '=', :values => ['1']}}, query.filters)
147 end
147 end
148
148
149 def test_index_with_short_filters
149 def test_index_with_short_filters
150
150
151 to_test = {
151 to_test = {
152 'status_id' => {
152 'status_id' => {
153 'o' => { :op => 'o', :values => [''] },
153 'o' => { :op => 'o', :values => [''] },
154 'c' => { :op => 'c', :values => [''] },
154 'c' => { :op => 'c', :values => [''] },
155 '7' => { :op => '=', :values => ['7'] },
155 '7' => { :op => '=', :values => ['7'] },
156 '7|3|4' => { :op => '=', :values => ['7', '3', '4'] },
156 '7|3|4' => { :op => '=', :values => ['7', '3', '4'] },
157 '=7' => { :op => '=', :values => ['7'] },
157 '=7' => { :op => '=', :values => ['7'] },
158 '!3' => { :op => '!', :values => ['3'] },
158 '!3' => { :op => '!', :values => ['3'] },
159 '!7|3|4' => { :op => '!', :values => ['7', '3', '4'] }},
159 '!7|3|4' => { :op => '!', :values => ['7', '3', '4'] }},
160 'subject' => {
160 'subject' => {
161 'This is a subject' => { :op => '=', :values => ['This is a subject'] },
161 'This is a subject' => { :op => '=', :values => ['This is a subject'] },
162 'o' => { :op => '=', :values => ['o'] },
162 'o' => { :op => '=', :values => ['o'] },
163 '~This is part of a subject' => { :op => '~', :values => ['This is part of a subject'] },
163 '~This is part of a subject' => { :op => '~', :values => ['This is part of a subject'] },
164 '!~This is part of a subject' => { :op => '!~', :values => ['This is part of a subject'] }},
164 '!~This is part of a subject' => { :op => '!~', :values => ['This is part of a subject'] }},
165 'tracker_id' => {
165 'tracker_id' => {
166 '3' => { :op => '=', :values => ['3'] },
166 '3' => { :op => '=', :values => ['3'] },
167 '=3' => { :op => '=', :values => ['3'] }},
167 '=3' => { :op => '=', :values => ['3'] }},
168 'start_date' => {
168 'start_date' => {
169 '2011-10-12' => { :op => '=', :values => ['2011-10-12'] },
169 '2011-10-12' => { :op => '=', :values => ['2011-10-12'] },
170 '=2011-10-12' => { :op => '=', :values => ['2011-10-12'] },
170 '=2011-10-12' => { :op => '=', :values => ['2011-10-12'] },
171 '>=2011-10-12' => { :op => '>=', :values => ['2011-10-12'] },
171 '>=2011-10-12' => { :op => '>=', :values => ['2011-10-12'] },
172 '<=2011-10-12' => { :op => '<=', :values => ['2011-10-12'] },
172 '<=2011-10-12' => { :op => '<=', :values => ['2011-10-12'] },
173 '><2011-10-01|2011-10-30' => { :op => '><', :values => ['2011-10-01', '2011-10-30'] },
173 '><2011-10-01|2011-10-30' => { :op => '><', :values => ['2011-10-01', '2011-10-30'] },
174 '<t+2' => { :op => '<t+', :values => ['2'] },
174 '<t+2' => { :op => '<t+', :values => ['2'] },
175 '>t+2' => { :op => '>t+', :values => ['2'] },
175 '>t+2' => { :op => '>t+', :values => ['2'] },
176 't+2' => { :op => 't+', :values => ['2'] },
176 't+2' => { :op => 't+', :values => ['2'] },
177 't' => { :op => 't', :values => [''] },
177 't' => { :op => 't', :values => [''] },
178 'w' => { :op => 'w', :values => [''] },
178 'w' => { :op => 'w', :values => [''] },
179 '>t-2' => { :op => '>t-', :values => ['2'] },
179 '>t-2' => { :op => '>t-', :values => ['2'] },
180 '<t-2' => { :op => '<t-', :values => ['2'] },
180 '<t-2' => { :op => '<t-', :values => ['2'] },
181 't-2' => { :op => 't-', :values => ['2'] }},
181 't-2' => { :op => 't-', :values => ['2'] }},
182 'created_on' => {
182 'created_on' => {
183 '>=2011-10-12' => { :op => '>=', :values => ['2011-10-12'] },
183 '>=2011-10-12' => { :op => '>=', :values => ['2011-10-12'] },
184 '<t+2' => { :op => '=', :values => ['<t+2'] },
184 '<t+2' => { :op => '=', :values => ['<t+2'] },
185 '>t+2' => { :op => '=', :values => ['>t+2'] },
185 '>t+2' => { :op => '=', :values => ['>t+2'] },
186 't+2' => { :op => 't', :values => ['+2'] }},
186 't+2' => { :op => 't', :values => ['+2'] }},
187 'cf_1' => {
187 'cf_1' => {
188 'c' => { :op => '=', :values => ['c'] },
188 'c' => { :op => '=', :values => ['c'] },
189 '!c' => { :op => '!', :values => ['c'] },
189 '!c' => { :op => '!', :values => ['c'] },
190 '!*' => { :op => '!*', :values => [''] },
190 '!*' => { :op => '!*', :values => [''] },
191 '*' => { :op => '*', :values => [''] }},
191 '*' => { :op => '*', :values => [''] }},
192 'estimated_hours' => {
192 'estimated_hours' => {
193 '=13.4' => { :op => '=', :values => ['13.4'] },
193 '=13.4' => { :op => '=', :values => ['13.4'] },
194 '>=45' => { :op => '>=', :values => ['45'] },
194 '>=45' => { :op => '>=', :values => ['45'] },
195 '<=125' => { :op => '<=', :values => ['125'] },
195 '<=125' => { :op => '<=', :values => ['125'] },
196 '><10.5|20.5' => { :op => '><', :values => ['10.5', '20.5'] },
196 '><10.5|20.5' => { :op => '><', :values => ['10.5', '20.5'] },
197 '!*' => { :op => '!*', :values => [''] },
197 '!*' => { :op => '!*', :values => [''] },
198 '*' => { :op => '*', :values => [''] }}
198 '*' => { :op => '*', :values => [''] }}
199 }
199 }
200
200
201 default_filter = { 'status_id' => {:operator => 'o', :values => [''] }}
201 default_filter = { 'status_id' => {:operator => 'o', :values => [''] }}
202
202
203 to_test.each do |field, expression_and_expected|
203 to_test.each do |field, expression_and_expected|
204 expression_and_expected.each do |filter_expression, expected|
204 expression_and_expected.each do |filter_expression, expected|
205
205
206 get :index, :set_filter => 1, field => filter_expression
206 get :index, :set_filter => 1, field => filter_expression
207
207
208 assert_response :success
208 assert_response :success
209 assert_template 'index'
209 assert_template 'index'
210 assert_not_nil assigns(:issues)
210 assert_not_nil assigns(:issues)
211
211
212 query = assigns(:query)
212 query = assigns(:query)
213 assert_not_nil query
213 assert_not_nil query
214 assert query.has_filter?(field)
214 assert query.has_filter?(field)
215 assert_equal(default_filter.merge({field => {:operator => expected[:op], :values => expected[:values]}}), query.filters)
215 assert_equal(default_filter.merge({field => {:operator => expected[:op], :values => expected[:values]}}), query.filters)
216 end
216 end
217 end
217 end
218
218
219 end
219 end
220
220
221 def test_index_with_project_and_empty_filters
221 def test_index_with_project_and_empty_filters
222 get :index, :project_id => 1, :set_filter => 1, :fields => ['']
222 get :index, :project_id => 1, :set_filter => 1, :fields => ['']
223 assert_response :success
223 assert_response :success
224 assert_template 'index'
224 assert_template 'index'
225 assert_not_nil assigns(:issues)
225 assert_not_nil assigns(:issues)
226
226
227 query = assigns(:query)
227 query = assigns(:query)
228 assert_not_nil query
228 assert_not_nil query
229 # no filter
229 # no filter
230 assert_equal({}, query.filters)
230 assert_equal({}, query.filters)
231 end
231 end
232
232
233 def test_index_with_query
233 def test_index_with_query
234 get :index, :project_id => 1, :query_id => 5
234 get :index, :project_id => 1, :query_id => 5
235 assert_response :success
235 assert_response :success
236 assert_template 'index'
236 assert_template 'index'
237 assert_not_nil assigns(:issues)
237 assert_not_nil assigns(:issues)
238 assert_nil assigns(:issue_count_by_group)
238 assert_nil assigns(:issue_count_by_group)
239 end
239 end
240
240
241 def test_index_with_query_grouped_by_tracker
241 def test_index_with_query_grouped_by_tracker
242 get :index, :project_id => 1, :query_id => 6
242 get :index, :project_id => 1, :query_id => 6
243 assert_response :success
243 assert_response :success
244 assert_template 'index'
244 assert_template 'index'
245 assert_not_nil assigns(:issues)
245 assert_not_nil assigns(:issues)
246 assert_not_nil assigns(:issue_count_by_group)
246 assert_not_nil assigns(:issue_count_by_group)
247 end
247 end
248
248
249 def test_index_with_query_grouped_by_list_custom_field
249 def test_index_with_query_grouped_by_list_custom_field
250 get :index, :project_id => 1, :query_id => 9
250 get :index, :project_id => 1, :query_id => 9
251 assert_response :success
251 assert_response :success
252 assert_template 'index'
252 assert_template 'index'
253 assert_not_nil assigns(:issues)
253 assert_not_nil assigns(:issues)
254 assert_not_nil assigns(:issue_count_by_group)
254 assert_not_nil assigns(:issue_count_by_group)
255 end
255 end
256
256
257 def test_index_with_query_id_and_project_id_should_set_session_query
257 def test_index_with_query_id_and_project_id_should_set_session_query
258 get :index, :project_id => 1, :query_id => 4
258 get :index, :project_id => 1, :query_id => 4
259 assert_response :success
259 assert_response :success
260 assert_kind_of Hash, session[:query]
260 assert_kind_of Hash, session[:query]
261 assert_equal 4, session[:query][:id]
261 assert_equal 4, session[:query][:id]
262 assert_equal 1, session[:query][:project_id]
262 assert_equal 1, session[:query][:project_id]
263 end
263 end
264
264
265 def test_index_with_cross_project_query_in_session_should_show_project_issues
265 def test_index_with_cross_project_query_in_session_should_show_project_issues
266 q = Query.create!(:name => "test", :user_id => 2, :is_public => false, :project => nil)
266 q = Query.create!(:name => "test", :user_id => 2, :is_public => false, :project => nil)
267 @request.session[:query] = {:id => q.id, :project_id => 1}
267 @request.session[:query] = {:id => q.id, :project_id => 1}
268
268
269 with_settings :display_subprojects_issues => '0' do
269 with_settings :display_subprojects_issues => '0' do
270 get :index, :project_id => 1
270 get :index, :project_id => 1
271 end
271 end
272 assert_response :success
272 assert_response :success
273 assert_not_nil assigns(:query)
273 assert_not_nil assigns(:query)
274 assert_equal q.id, assigns(:query).id
274 assert_equal q.id, assigns(:query).id
275 assert_equal 1, assigns(:query).project_id
275 assert_equal 1, assigns(:query).project_id
276 assert_equal [1], assigns(:issues).map(&:project_id).uniq
276 assert_equal [1], assigns(:issues).map(&:project_id).uniq
277 end
277 end
278
278
279 def test_private_query_should_not_be_available_to_other_users
279 def test_private_query_should_not_be_available_to_other_users
280 q = Query.create!(:name => "private", :user => User.find(2), :is_public => false, :project => nil)
280 q = Query.create!(:name => "private", :user => User.find(2), :is_public => false, :project => nil)
281 @request.session[:user_id] = 3
281 @request.session[:user_id] = 3
282
282
283 get :index, :query_id => q.id
283 get :index, :query_id => q.id
284 assert_response 403
284 assert_response 403
285 end
285 end
286
286
287 def test_private_query_should_be_available_to_its_user
287 def test_private_query_should_be_available_to_its_user
288 q = Query.create!(:name => "private", :user => User.find(2), :is_public => false, :project => nil)
288 q = Query.create!(:name => "private", :user => User.find(2), :is_public => false, :project => nil)
289 @request.session[:user_id] = 2
289 @request.session[:user_id] = 2
290
290
291 get :index, :query_id => q.id
291 get :index, :query_id => q.id
292 assert_response :success
292 assert_response :success
293 end
293 end
294
294
295 def test_public_query_should_be_available_to_other_users
295 def test_public_query_should_be_available_to_other_users
296 q = Query.create!(:name => "private", :user => User.find(2), :is_public => true, :project => nil)
296 q = Query.create!(:name => "private", :user => User.find(2), :is_public => true, :project => nil)
297 @request.session[:user_id] = 3
297 @request.session[:user_id] = 3
298
298
299 get :index, :query_id => q.id
299 get :index, :query_id => q.id
300 assert_response :success
300 assert_response :success
301 end
301 end
302
302
303 def test_index_csv
303 def test_index_csv
304 get :index, :format => 'csv'
304 get :index, :format => 'csv'
305 assert_response :success
305 assert_response :success
306 assert_not_nil assigns(:issues)
306 assert_not_nil assigns(:issues)
307 assert_equal 'text/csv', @response.content_type
307 assert_equal 'text/csv', @response.content_type
308 assert @response.body.starts_with?("#,")
308 assert @response.body.starts_with?("#,")
309 lines = @response.body.chomp.split("\n")
309 lines = @response.body.chomp.split("\n")
310 assert_equal assigns(:query).columns.size + 1, lines[0].split(',').size
310 assert_equal assigns(:query).columns.size + 1, lines[0].split(',').size
311 end
311 end
312
312
313 def test_index_csv_with_project
313 def test_index_csv_with_project
314 get :index, :project_id => 1, :format => 'csv'
314 get :index, :project_id => 1, :format => 'csv'
315 assert_response :success
315 assert_response :success
316 assert_not_nil assigns(:issues)
316 assert_not_nil assigns(:issues)
317 assert_equal 'text/csv', @response.content_type
317 assert_equal 'text/csv', @response.content_type
318 end
318 end
319
319
320 def test_index_csv_with_description
320 def test_index_csv_with_description
321 get :index, :format => 'csv', :description => '1'
321 get :index, :format => 'csv', :description => '1'
322 assert_response :success
322 assert_response :success
323 assert_not_nil assigns(:issues)
323 assert_not_nil assigns(:issues)
324 assert_equal 'text/csv', @response.content_type
324 assert_equal 'text/csv', @response.content_type
325 assert @response.body.starts_with?("#,")
325 assert @response.body.starts_with?("#,")
326 lines = @response.body.chomp.split("\n")
326 lines = @response.body.chomp.split("\n")
327 assert_equal assigns(:query).columns.size + 2, lines[0].split(',').size
327 assert_equal assigns(:query).columns.size + 2, lines[0].split(',').size
328 end
328 end
329
329
330 def test_index_csv_with_all_columns
330 def test_index_csv_with_all_columns
331 get :index, :format => 'csv', :columns => 'all'
331 get :index, :format => 'csv', :columns => 'all'
332 assert_response :success
332 assert_response :success
333 assert_not_nil assigns(:issues)
333 assert_not_nil assigns(:issues)
334 assert_equal 'text/csv', @response.content_type
334 assert_equal 'text/csv', @response.content_type
335 assert @response.body.starts_with?("#,")
335 assert @response.body.starts_with?("#,")
336 lines = @response.body.chomp.split("\n")
336 lines = @response.body.chomp.split("\n")
337 assert_equal assigns(:query).available_columns.size + 1, lines[0].split(',').size
337 assert_equal assigns(:query).available_columns.size + 1, lines[0].split(',').size
338 end
338 end
339
339
340 def test_index_csv_big_5
340 def test_index_csv_big_5
341 with_settings :default_language => "zh-TW" do
341 with_settings :default_language => "zh-TW" do
342 str_utf8 = "\xe4\xb8\x80\xe6\x9c\x88"
342 str_utf8 = "\xe4\xb8\x80\xe6\x9c\x88"
343 str_big5 = "\xa4@\xa4\xeb"
343 str_big5 = "\xa4@\xa4\xeb"
344 if str_utf8.respond_to?(:force_encoding)
344 if str_utf8.respond_to?(:force_encoding)
345 str_utf8.force_encoding('UTF-8')
345 str_utf8.force_encoding('UTF-8')
346 str_big5.force_encoding('Big5')
346 str_big5.force_encoding('Big5')
347 end
347 end
348 issue = Issue.new(:project_id => 1, :tracker_id => 1, :author_id => 3,
348 issue = Issue.new(:project_id => 1, :tracker_id => 1, :author_id => 3,
349 :status_id => 1, :priority => IssuePriority.all.first,
349 :status_id => 1, :priority => IssuePriority.all.first,
350 :subject => str_utf8)
350 :subject => str_utf8)
351 assert issue.save
351 assert issue.save
352
352
353 get :index, :project_id => 1,
353 get :index, :project_id => 1,
354 :f => ['subject'],
354 :f => ['subject'],
355 :op => '=', :values => [str_utf8],
355 :op => '=', :values => [str_utf8],
356 :format => 'csv'
356 :format => 'csv'
357 assert_equal 'text/csv', @response.content_type
357 assert_equal 'text/csv', @response.content_type
358 lines = @response.body.chomp.split("\n")
358 lines = @response.body.chomp.split("\n")
359 s1 = "\xaa\xac\xbaA"
359 s1 = "\xaa\xac\xbaA"
360 if str_utf8.respond_to?(:force_encoding)
360 if str_utf8.respond_to?(:force_encoding)
361 s1.force_encoding('Big5')
361 s1.force_encoding('Big5')
362 end
362 end
363 assert lines[0].include?(s1)
363 assert lines[0].include?(s1)
364 assert lines[1].include?(str_big5)
364 assert lines[1].include?(str_big5)
365 end
365 end
366 end
366 end
367
367
368 def test_index_csv_cannot_convert_should_be_replaced_big_5
368 def test_index_csv_cannot_convert_should_be_replaced_big_5
369 with_settings :default_language => "zh-TW" do
369 with_settings :default_language => "zh-TW" do
370 str_utf8 = "\xe4\xbb\xa5\xe5\x86\x85"
370 str_utf8 = "\xe4\xbb\xa5\xe5\x86\x85"
371 if str_utf8.respond_to?(:force_encoding)
371 if str_utf8.respond_to?(:force_encoding)
372 str_utf8.force_encoding('UTF-8')
372 str_utf8.force_encoding('UTF-8')
373 end
373 end
374 issue = Issue.new(:project_id => 1, :tracker_id => 1, :author_id => 3,
374 issue = Issue.new(:project_id => 1, :tracker_id => 1, :author_id => 3,
375 :status_id => 1, :priority => IssuePriority.all.first,
375 :status_id => 1, :priority => IssuePriority.all.first,
376 :subject => str_utf8)
376 :subject => str_utf8)
377 assert issue.save
377 assert issue.save
378
378
379 get :index, :project_id => 1,
379 get :index, :project_id => 1,
380 :f => ['subject'],
380 :f => ['subject'],
381 :op => '=', :values => [str_utf8],
381 :op => '=', :values => [str_utf8],
382 :c => ['status', 'subject'],
382 :c => ['status', 'subject'],
383 :format => 'csv',
383 :format => 'csv',
384 :set_filter => 1
384 :set_filter => 1
385 assert_equal 'text/csv', @response.content_type
385 assert_equal 'text/csv', @response.content_type
386 lines = @response.body.chomp.split("\n")
386 lines = @response.body.chomp.split("\n")
387 s1 = "\xaa\xac\xbaA" # status
387 s1 = "\xaa\xac\xbaA" # status
388 if str_utf8.respond_to?(:force_encoding)
388 if str_utf8.respond_to?(:force_encoding)
389 s1.force_encoding('Big5')
389 s1.force_encoding('Big5')
390 end
390 end
391 assert lines[0].include?(s1)
391 assert lines[0].include?(s1)
392 s2 = lines[1].split(",")[2]
392 s2 = lines[1].split(",")[2]
393 if s1.respond_to?(:force_encoding)
393 if s1.respond_to?(:force_encoding)
394 s3 = "\xa5H?" # subject
394 s3 = "\xa5H?" # subject
395 s3.force_encoding('Big5')
395 s3.force_encoding('Big5')
396 assert_equal s3, s2
396 assert_equal s3, s2
397 elsif RUBY_PLATFORM == 'java'
397 elsif RUBY_PLATFORM == 'java'
398 assert_equal "??", s2
398 assert_equal "??", s2
399 else
399 else
400 assert_equal "\xa5H???", s2
400 assert_equal "\xa5H???", s2
401 end
401 end
402 end
402 end
403 end
403 end
404
404
405 def test_index_csv_tw
405 def test_index_csv_tw
406 with_settings :default_language => "zh-TW" do
406 with_settings :default_language => "zh-TW" do
407 str1 = "test_index_csv_tw"
407 str1 = "test_index_csv_tw"
408 issue = Issue.new(:project_id => 1, :tracker_id => 1, :author_id => 3,
408 issue = Issue.new(:project_id => 1, :tracker_id => 1, :author_id => 3,
409 :status_id => 1, :priority => IssuePriority.all.first,
409 :status_id => 1, :priority => IssuePriority.all.first,
410 :subject => str1, :estimated_hours => '1234.5')
410 :subject => str1, :estimated_hours => '1234.5')
411 assert issue.save
411 assert issue.save
412 assert_equal 1234.5, issue.estimated_hours
412 assert_equal 1234.5, issue.estimated_hours
413
413
414 get :index, :project_id => 1,
414 get :index, :project_id => 1,
415 :f => ['subject'],
415 :f => ['subject'],
416 :op => '=', :values => [str1],
416 :op => '=', :values => [str1],
417 :c => ['estimated_hours', 'subject'],
417 :c => ['estimated_hours', 'subject'],
418 :format => 'csv',
418 :format => 'csv',
419 :set_filter => 1
419 :set_filter => 1
420 assert_equal 'text/csv', @response.content_type
420 assert_equal 'text/csv', @response.content_type
421 lines = @response.body.chomp.split("\n")
421 lines = @response.body.chomp.split("\n")
422 assert_equal "#{issue.id},1234.5,#{str1}", lines[1]
422 assert_equal "#{issue.id},1234.5,#{str1}", lines[1]
423
423
424 str_tw = "Traditional Chinese (\xe7\xb9\x81\xe9\xab\x94\xe4\xb8\xad\xe6\x96\x87)"
424 str_tw = "Traditional Chinese (\xe7\xb9\x81\xe9\xab\x94\xe4\xb8\xad\xe6\x96\x87)"
425 if str_tw.respond_to?(:force_encoding)
425 if str_tw.respond_to?(:force_encoding)
426 str_tw.force_encoding('UTF-8')
426 str_tw.force_encoding('UTF-8')
427 end
427 end
428 assert_equal str_tw, l(:general_lang_name)
428 assert_equal str_tw, l(:general_lang_name)
429 assert_equal ',', l(:general_csv_separator)
429 assert_equal ',', l(:general_csv_separator)
430 assert_equal '.', l(:general_csv_decimal_separator)
430 assert_equal '.', l(:general_csv_decimal_separator)
431 end
431 end
432 end
432 end
433
433
434 def test_index_csv_fr
434 def test_index_csv_fr
435 with_settings :default_language => "fr" do
435 with_settings :default_language => "fr" do
436 str1 = "test_index_csv_fr"
436 str1 = "test_index_csv_fr"
437 issue = Issue.new(:project_id => 1, :tracker_id => 1, :author_id => 3,
437 issue = Issue.new(:project_id => 1, :tracker_id => 1, :author_id => 3,
438 :status_id => 1, :priority => IssuePriority.all.first,
438 :status_id => 1, :priority => IssuePriority.all.first,
439 :subject => str1, :estimated_hours => '1234.5')
439 :subject => str1, :estimated_hours => '1234.5')
440 assert issue.save
440 assert issue.save
441 assert_equal 1234.5, issue.estimated_hours
441 assert_equal 1234.5, issue.estimated_hours
442
442
443 get :index, :project_id => 1,
443 get :index, :project_id => 1,
444 :f => ['subject'],
444 :f => ['subject'],
445 :op => '=', :values => [str1],
445 :op => '=', :values => [str1],
446 :c => ['estimated_hours', 'subject'],
446 :c => ['estimated_hours', 'subject'],
447 :format => 'csv',
447 :format => 'csv',
448 :set_filter => 1
448 :set_filter => 1
449 assert_equal 'text/csv', @response.content_type
449 assert_equal 'text/csv', @response.content_type
450 lines = @response.body.chomp.split("\n")
450 lines = @response.body.chomp.split("\n")
451 assert_equal "#{issue.id};1234,5;#{str1}", lines[1]
451 assert_equal "#{issue.id};1234,5;#{str1}", lines[1]
452
452
453 str_fr = "Fran\xc3\xa7ais"
453 str_fr = "Fran\xc3\xa7ais"
454 if str_fr.respond_to?(:force_encoding)
454 if str_fr.respond_to?(:force_encoding)
455 str_fr.force_encoding('UTF-8')
455 str_fr.force_encoding('UTF-8')
456 end
456 end
457 assert_equal str_fr, l(:general_lang_name)
457 assert_equal str_fr, l(:general_lang_name)
458 assert_equal ';', l(:general_csv_separator)
458 assert_equal ';', l(:general_csv_separator)
459 assert_equal ',', l(:general_csv_decimal_separator)
459 assert_equal ',', l(:general_csv_decimal_separator)
460 end
460 end
461 end
461 end
462
462
463 def test_index_pdf
463 def test_index_pdf
464 ["en", "zh", "zh-TW", "ja", "ko"].each do |lang|
464 ["en", "zh", "zh-TW", "ja", "ko"].each do |lang|
465 with_settings :default_language => lang do
465 with_settings :default_language => lang do
466
466
467 get :index
467 get :index
468 assert_response :success
468 assert_response :success
469 assert_template 'index'
469 assert_template 'index'
470
470
471 if lang == "ja"
471 if lang == "ja"
472 if RUBY_PLATFORM != 'java'
472 if RUBY_PLATFORM != 'java'
473 assert_equal "CP932", l(:general_pdf_encoding)
473 assert_equal "CP932", l(:general_pdf_encoding)
474 end
474 end
475 if RUBY_PLATFORM == 'java' && l(:general_pdf_encoding) == "CP932"
475 if RUBY_PLATFORM == 'java' && l(:general_pdf_encoding) == "CP932"
476 next
476 next
477 end
477 end
478 end
478 end
479
479
480 get :index, :format => 'pdf'
480 get :index, :format => 'pdf'
481 assert_response :success
481 assert_response :success
482 assert_not_nil assigns(:issues)
482 assert_not_nil assigns(:issues)
483 assert_equal 'application/pdf', @response.content_type
483 assert_equal 'application/pdf', @response.content_type
484
484
485 get :index, :project_id => 1, :format => 'pdf'
485 get :index, :project_id => 1, :format => 'pdf'
486 assert_response :success
486 assert_response :success
487 assert_not_nil assigns(:issues)
487 assert_not_nil assigns(:issues)
488 assert_equal 'application/pdf', @response.content_type
488 assert_equal 'application/pdf', @response.content_type
489
489
490 get :index, :project_id => 1, :query_id => 6, :format => 'pdf'
490 get :index, :project_id => 1, :query_id => 6, :format => 'pdf'
491 assert_response :success
491 assert_response :success
492 assert_not_nil assigns(:issues)
492 assert_not_nil assigns(:issues)
493 assert_equal 'application/pdf', @response.content_type
493 assert_equal 'application/pdf', @response.content_type
494 end
494 end
495 end
495 end
496 end
496 end
497
497
498 def test_index_pdf_with_query_grouped_by_list_custom_field
498 def test_index_pdf_with_query_grouped_by_list_custom_field
499 get :index, :project_id => 1, :query_id => 9, :format => 'pdf'
499 get :index, :project_id => 1, :query_id => 9, :format => 'pdf'
500 assert_response :success
500 assert_response :success
501 assert_not_nil assigns(:issues)
501 assert_not_nil assigns(:issues)
502 assert_not_nil assigns(:issue_count_by_group)
502 assert_not_nil assigns(:issue_count_by_group)
503 assert_equal 'application/pdf', @response.content_type
503 assert_equal 'application/pdf', @response.content_type
504 end
504 end
505
505
506 def test_index_sort
506 def test_index_sort
507 get :index, :sort => 'tracker,id:desc'
507 get :index, :sort => 'tracker,id:desc'
508 assert_response :success
508 assert_response :success
509
509
510 sort_params = @request.session['issues_index_sort']
510 sort_params = @request.session['issues_index_sort']
511 assert sort_params.is_a?(String)
511 assert sort_params.is_a?(String)
512 assert_equal 'tracker,id:desc', sort_params
512 assert_equal 'tracker,id:desc', sort_params
513
513
514 issues = assigns(:issues)
514 issues = assigns(:issues)
515 assert_not_nil issues
515 assert_not_nil issues
516 assert !issues.empty?
516 assert !issues.empty?
517 assert_equal issues.sort {|a,b| a.tracker == b.tracker ? b.id <=> a.id : a.tracker <=> b.tracker }.collect(&:id), issues.collect(&:id)
517 assert_equal issues.sort {|a,b| a.tracker == b.tracker ? b.id <=> a.id : a.tracker <=> b.tracker }.collect(&:id), issues.collect(&:id)
518 end
518 end
519
519
520 def test_index_sort_by_field_not_included_in_columns
520 def test_index_sort_by_field_not_included_in_columns
521 Setting.issue_list_default_columns = %w(subject author)
521 Setting.issue_list_default_columns = %w(subject author)
522 get :index, :sort => 'tracker'
522 get :index, :sort => 'tracker'
523 end
523 end
524
524
525 def test_index_sort_by_assigned_to
525 def test_index_sort_by_assigned_to
526 get :index, :sort => 'assigned_to'
526 get :index, :sort => 'assigned_to'
527 assert_response :success
527 assert_response :success
528 assignees = assigns(:issues).collect(&:assigned_to).compact
528 assignees = assigns(:issues).collect(&:assigned_to).compact
529 assert_equal assignees.sort, assignees
529 assert_equal assignees.sort, assignees
530 end
530 end
531
531
532 def test_index_sort_by_assigned_to_desc
532 def test_index_sort_by_assigned_to_desc
533 get :index, :sort => 'assigned_to:desc'
533 get :index, :sort => 'assigned_to:desc'
534 assert_response :success
534 assert_response :success
535 assignees = assigns(:issues).collect(&:assigned_to).compact
535 assignees = assigns(:issues).collect(&:assigned_to).compact
536 assert_equal assignees.sort.reverse, assignees
536 assert_equal assignees.sort.reverse, assignees
537 end
537 end
538
538
539 def test_index_group_by_assigned_to
539 def test_index_group_by_assigned_to
540 get :index, :group_by => 'assigned_to', :sort => 'priority'
540 get :index, :group_by => 'assigned_to', :sort => 'priority'
541 assert_response :success
541 assert_response :success
542 end
542 end
543
543
544 def test_index_sort_by_author
544 def test_index_sort_by_author
545 get :index, :sort => 'author'
545 get :index, :sort => 'author'
546 assert_response :success
546 assert_response :success
547 authors = assigns(:issues).collect(&:author)
547 authors = assigns(:issues).collect(&:author)
548 assert_equal authors.sort, authors
548 assert_equal authors.sort, authors
549 end
549 end
550
550
551 def test_index_sort_by_author_desc
551 def test_index_sort_by_author_desc
552 get :index, :sort => 'author:desc'
552 get :index, :sort => 'author:desc'
553 assert_response :success
553 assert_response :success
554 authors = assigns(:issues).collect(&:author)
554 authors = assigns(:issues).collect(&:author)
555 assert_equal authors.sort.reverse, authors
555 assert_equal authors.sort.reverse, authors
556 end
556 end
557
557
558 def test_index_group_by_author
558 def test_index_group_by_author
559 get :index, :group_by => 'author', :sort => 'priority'
559 get :index, :group_by => 'author', :sort => 'priority'
560 assert_response :success
560 assert_response :success
561 end
561 end
562
562
563 def test_index_sort_by_spent_hours
563 def test_index_sort_by_spent_hours
564 get :index, :sort => 'spent_hours:desc'
564 get :index, :sort => 'spent_hours:desc'
565 assert_response :success
565 assert_response :success
566 hours = assigns(:issues).collect(&:spent_hours)
566 hours = assigns(:issues).collect(&:spent_hours)
567 assert_equal hours.sort.reverse, hours
567 assert_equal hours.sort.reverse, hours
568 end
568 end
569
569
570 def test_index_with_columns
570 def test_index_with_columns
571 columns = ['tracker', 'subject', 'assigned_to']
571 columns = ['tracker', 'subject', 'assigned_to']
572 get :index, :set_filter => 1, :c => columns
572 get :index, :set_filter => 1, :c => columns
573 assert_response :success
573 assert_response :success
574
574
575 # query should use specified columns
575 # query should use specified columns
576 query = assigns(:query)
576 query = assigns(:query)
577 assert_kind_of Query, query
577 assert_kind_of Query, query
578 assert_equal columns, query.column_names.map(&:to_s)
578 assert_equal columns, query.column_names.map(&:to_s)
579
579
580 # columns should be stored in session
580 # columns should be stored in session
581 assert_kind_of Hash, session[:query]
581 assert_kind_of Hash, session[:query]
582 assert_kind_of Array, session[:query][:column_names]
582 assert_kind_of Array, session[:query][:column_names]
583 assert_equal columns, session[:query][:column_names].map(&:to_s)
583 assert_equal columns, session[:query][:column_names].map(&:to_s)
584
584
585 # ensure only these columns are kept in the selected columns list
585 # ensure only these columns are kept in the selected columns list
586 assert_tag :tag => 'select', :attributes => { :id => 'selected_columns' },
586 assert_tag :tag => 'select', :attributes => { :id => 'selected_columns' },
587 :children => { :count => 3 }
587 :children => { :count => 3 }
588 assert_no_tag :tag => 'option', :attributes => { :value => 'project' },
588 assert_no_tag :tag => 'option', :attributes => { :value => 'project' },
589 :parent => { :tag => 'select', :attributes => { :id => "selected_columns" } }
589 :parent => { :tag => 'select', :attributes => { :id => "selected_columns" } }
590 end
590 end
591
591
592 def test_index_without_project_should_implicitly_add_project_column_to_default_columns
592 def test_index_without_project_should_implicitly_add_project_column_to_default_columns
593 Setting.issue_list_default_columns = ['tracker', 'subject', 'assigned_to']
593 Setting.issue_list_default_columns = ['tracker', 'subject', 'assigned_to']
594 get :index, :set_filter => 1
594 get :index, :set_filter => 1
595
595
596 # query should use specified columns
596 # query should use specified columns
597 query = assigns(:query)
597 query = assigns(:query)
598 assert_kind_of Query, query
598 assert_kind_of Query, query
599 assert_equal [:project, :tracker, :subject, :assigned_to], query.columns.map(&:name)
599 assert_equal [:project, :tracker, :subject, :assigned_to], query.columns.map(&:name)
600 end
600 end
601
601
602 def test_index_without_project_and_explicit_default_columns_should_not_add_project_column
602 def test_index_without_project_and_explicit_default_columns_should_not_add_project_column
603 Setting.issue_list_default_columns = ['tracker', 'subject', 'assigned_to']
603 Setting.issue_list_default_columns = ['tracker', 'subject', 'assigned_to']
604 columns = ['tracker', 'subject', 'assigned_to']
604 columns = ['tracker', 'subject', 'assigned_to']
605 get :index, :set_filter => 1, :c => columns
605 get :index, :set_filter => 1, :c => columns
606
606
607 # query should use specified columns
607 # query should use specified columns
608 query = assigns(:query)
608 query = assigns(:query)
609 assert_kind_of Query, query
609 assert_kind_of Query, query
610 assert_equal columns.map(&:to_sym), query.columns.map(&:name)
610 assert_equal columns.map(&:to_sym), query.columns.map(&:name)
611 end
611 end
612
612
613 def test_index_with_custom_field_column
613 def test_index_with_custom_field_column
614 columns = %w(tracker subject cf_2)
614 columns = %w(tracker subject cf_2)
615 get :index, :set_filter => 1, :c => columns
615 get :index, :set_filter => 1, :c => columns
616 assert_response :success
616 assert_response :success
617
617
618 # query should use specified columns
618 # query should use specified columns
619 query = assigns(:query)
619 query = assigns(:query)
620 assert_kind_of Query, query
620 assert_kind_of Query, query
621 assert_equal columns, query.column_names.map(&:to_s)
621 assert_equal columns, query.column_names.map(&:to_s)
622
622
623 assert_tag :td,
623 assert_tag :td,
624 :attributes => {:class => 'cf_2 string'},
624 :attributes => {:class => 'cf_2 string'},
625 :ancestor => {:tag => 'table', :attributes => {:class => /issues/}}
625 :ancestor => {:tag => 'table', :attributes => {:class => /issues/}}
626 end
626 end
627
627
628 def test_index_with_date_column
628 def test_index_with_date_column
629 Issue.find(1).update_attribute :start_date, '1987-08-24'
629 Issue.find(1).update_attribute :start_date, '1987-08-24'
630
630
631 with_settings :date_format => '%d/%m/%Y' do
631 with_settings :date_format => '%d/%m/%Y' do
632 get :index, :set_filter => 1, :c => %w(start_date)
632 get :index, :set_filter => 1, :c => %w(start_date)
633 assert_tag 'td', :attributes => {:class => /start_date/}, :content => '24/08/1987'
633 assert_tag 'td', :attributes => {:class => /start_date/}, :content => '24/08/1987'
634 end
634 end
635 end
635 end
636
636
637 def test_index_with_done_ratio
637 def test_index_with_done_ratio
638 Issue.find(1).update_attribute :done_ratio, 40
638 Issue.find(1).update_attribute :done_ratio, 40
639
639
640 get :index, :set_filter => 1, :c => %w(done_ratio)
640 get :index, :set_filter => 1, :c => %w(done_ratio)
641 assert_tag 'td', :attributes => {:class => /done_ratio/},
641 assert_tag 'td', :attributes => {:class => /done_ratio/},
642 :child => {:tag => 'table', :attributes => {:class => 'progress'},
642 :child => {:tag => 'table', :attributes => {:class => 'progress'},
643 :descendant => {:tag => 'td', :attributes => {:class => 'closed', :style => 'width: 40%;'}}
643 :descendant => {:tag => 'td', :attributes => {:class => 'closed', :style => 'width: 40%;'}}
644 }
644 }
645 end
645 end
646
646
647 def test_index_with_spent_hours_column
647 def test_index_with_spent_hours_column
648 get :index, :set_filter => 1, :c => %w(subject spent_hours)
648 get :index, :set_filter => 1, :c => %w(subject spent_hours)
649
649
650 assert_tag 'tr', :attributes => {:id => 'issue-3'},
650 assert_tag 'tr', :attributes => {:id => 'issue-3'},
651 :child => {
651 :child => {
652 :tag => 'td', :attributes => {:class => /spent_hours/}, :content => '1.00'
652 :tag => 'td', :attributes => {:class => /spent_hours/}, :content => '1.00'
653 }
653 }
654 end
654 end
655
655
656 def test_index_should_not_show_spent_hours_column_without_permission
656 def test_index_should_not_show_spent_hours_column_without_permission
657 Role.anonymous.remove_permission! :view_time_entries
657 Role.anonymous.remove_permission! :view_time_entries
658 get :index, :set_filter => 1, :c => %w(subject spent_hours)
658 get :index, :set_filter => 1, :c => %w(subject spent_hours)
659
659
660 assert_no_tag 'td', :attributes => {:class => /spent_hours/}
660 assert_no_tag 'td', :attributes => {:class => /spent_hours/}
661 end
661 end
662
662
663 def test_index_with_fixed_version
663 def test_index_with_fixed_version
664 get :index, :set_filter => 1, :c => %w(fixed_version)
664 get :index, :set_filter => 1, :c => %w(fixed_version)
665 assert_tag 'td', :attributes => {:class => /fixed_version/},
665 assert_tag 'td', :attributes => {:class => /fixed_version/},
666 :child => {:tag => 'a', :content => '1.0', :attributes => {:href => '/versions/2'}}
666 :child => {:tag => 'a', :content => '1.0', :attributes => {:href => '/versions/2'}}
667 end
667 end
668
668
669 def test_index_send_html_if_query_is_invalid
669 def test_index_send_html_if_query_is_invalid
670 get :index, :f => ['start_date'], :op => {:start_date => '='}
670 get :index, :f => ['start_date'], :op => {:start_date => '='}
671 assert_equal 'text/html', @response.content_type
671 assert_equal 'text/html', @response.content_type
672 assert_template 'index'
672 assert_template 'index'
673 end
673 end
674
674
675 def test_index_send_nothing_if_query_is_invalid
675 def test_index_send_nothing_if_query_is_invalid
676 get :index, :f => ['start_date'], :op => {:start_date => '='}, :format => 'csv'
676 get :index, :f => ['start_date'], :op => {:start_date => '='}, :format => 'csv'
677 assert_equal 'text/csv', @response.content_type
677 assert_equal 'text/csv', @response.content_type
678 assert @response.body.blank?
678 assert @response.body.blank?
679 end
679 end
680
680
681 def test_show_by_anonymous
681 def test_show_by_anonymous
682 get :show, :id => 1
682 get :show, :id => 1
683 assert_response :success
683 assert_response :success
684 assert_template 'show'
684 assert_template 'show'
685 assert_not_nil assigns(:issue)
685 assert_not_nil assigns(:issue)
686 assert_equal Issue.find(1), assigns(:issue)
686 assert_equal Issue.find(1), assigns(:issue)
687
687
688 # anonymous role is allowed to add a note
688 # anonymous role is allowed to add a note
689 assert_tag :tag => 'form',
689 assert_tag :tag => 'form',
690 :descendant => { :tag => 'fieldset',
690 :descendant => { :tag => 'fieldset',
691 :child => { :tag => 'legend',
691 :child => { :tag => 'legend',
692 :content => /Notes/ } }
692 :content => /Notes/ } }
693 assert_tag :tag => 'title',
693 assert_tag :tag => 'title',
694 :content => "Bug #1: Can't print recipes - eCookbook - Redmine"
694 :content => "Bug #1: Can't print recipes - eCookbook - Redmine"
695 end
695 end
696
696
697 def test_show_by_manager
697 def test_show_by_manager
698 @request.session[:user_id] = 2
698 @request.session[:user_id] = 2
699 get :show, :id => 1
699 get :show, :id => 1
700 assert_response :success
700 assert_response :success
701
701
702 assert_tag :tag => 'a',
702 assert_tag :tag => 'a',
703 :content => /Quote/
703 :content => /Quote/
704
704
705 assert_tag :tag => 'form',
705 assert_tag :tag => 'form',
706 :descendant => { :tag => 'fieldset',
706 :descendant => { :tag => 'fieldset',
707 :child => { :tag => 'legend',
707 :child => { :tag => 'legend',
708 :content => /Change properties/ } },
708 :content => /Change properties/ } },
709 :descendant => { :tag => 'fieldset',
709 :descendant => { :tag => 'fieldset',
710 :child => { :tag => 'legend',
710 :child => { :tag => 'legend',
711 :content => /Log time/ } },
711 :content => /Log time/ } },
712 :descendant => { :tag => 'fieldset',
712 :descendant => { :tag => 'fieldset',
713 :child => { :tag => 'legend',
713 :child => { :tag => 'legend',
714 :content => /Notes/ } }
714 :content => /Notes/ } }
715 end
715 end
716
716
717 def test_show_should_display_update_form
717 def test_show_should_display_update_form
718 @request.session[:user_id] = 2
718 @request.session[:user_id] = 2
719 get :show, :id => 1
719 get :show, :id => 1
720 assert_response :success
720 assert_response :success
721
721
722 assert_tag 'form', :attributes => {:id => 'issue-form'}
722 assert_tag 'form', :attributes => {:id => 'issue-form'}
723 assert_tag 'input', :attributes => {:name => 'issue[is_private]'}
723 assert_tag 'input', :attributes => {:name => 'issue[is_private]'}
724 assert_tag 'select', :attributes => {:name => 'issue[project_id]'}
724 assert_tag 'select', :attributes => {:name => 'issue[project_id]'}
725 assert_tag 'select', :attributes => {:name => 'issue[tracker_id]'}
725 assert_tag 'select', :attributes => {:name => 'issue[tracker_id]'}
726 assert_tag 'input', :attributes => {:name => 'issue[subject]'}
726 assert_tag 'input', :attributes => {:name => 'issue[subject]'}
727 assert_tag 'textarea', :attributes => {:name => 'issue[description]'}
727 assert_tag 'textarea', :attributes => {:name => 'issue[description]'}
728 assert_tag 'select', :attributes => {:name => 'issue[status_id]'}
728 assert_tag 'select', :attributes => {:name => 'issue[status_id]'}
729 assert_tag 'select', :attributes => {:name => 'issue[priority_id]'}
729 assert_tag 'select', :attributes => {:name => 'issue[priority_id]'}
730 assert_tag 'select', :attributes => {:name => 'issue[assigned_to_id]'}
730 assert_tag 'select', :attributes => {:name => 'issue[assigned_to_id]'}
731 assert_tag 'select', :attributes => {:name => 'issue[category_id]'}
731 assert_tag 'select', :attributes => {:name => 'issue[category_id]'}
732 assert_tag 'select', :attributes => {:name => 'issue[fixed_version_id]'}
732 assert_tag 'select', :attributes => {:name => 'issue[fixed_version_id]'}
733 assert_tag 'input', :attributes => {:name => 'issue[parent_issue_id]'}
733 assert_tag 'input', :attributes => {:name => 'issue[parent_issue_id]'}
734 assert_tag 'input', :attributes => {:name => 'issue[start_date]'}
734 assert_tag 'input', :attributes => {:name => 'issue[start_date]'}
735 assert_tag 'input', :attributes => {:name => 'issue[due_date]'}
735 assert_tag 'input', :attributes => {:name => 'issue[due_date]'}
736 assert_tag 'select', :attributes => {:name => 'issue[done_ratio]'}
736 assert_tag 'select', :attributes => {:name => 'issue[done_ratio]'}
737 assert_tag 'input', :attributes => { :name => 'issue[custom_field_values][2]' }
737 assert_tag 'input', :attributes => { :name => 'issue[custom_field_values][2]' }
738 assert_no_tag 'input', :attributes => {:name => 'issue[watcher_user_ids][]'}
738 assert_no_tag 'input', :attributes => {:name => 'issue[watcher_user_ids][]'}
739 assert_tag 'textarea', :attributes => {:name => 'notes'}
739 assert_tag 'textarea', :attributes => {:name => 'notes'}
740 end
740 end
741
741
742 def test_show_should_display_update_form_with_minimal_permissions
742 def test_show_should_display_update_form_with_minimal_permissions
743 Role.find(1).update_attribute :permissions, [:view_issues, :add_issue_notes]
743 Role.find(1).update_attribute :permissions, [:view_issues, :add_issue_notes]
744 Workflow.delete_all :role_id => 1
744 Workflow.delete_all :role_id => 1
745
745
746 @request.session[:user_id] = 2
746 @request.session[:user_id] = 2
747 get :show, :id => 1
747 get :show, :id => 1
748 assert_response :success
748 assert_response :success
749
749
750 assert_tag 'form', :attributes => {:id => 'issue-form'}
750 assert_tag 'form', :attributes => {:id => 'issue-form'}
751 assert_no_tag 'input', :attributes => {:name => 'issue[is_private]'}
751 assert_no_tag 'input', :attributes => {:name => 'issue[is_private]'}
752 assert_no_tag 'select', :attributes => {:name => 'issue[project_id]'}
752 assert_no_tag 'select', :attributes => {:name => 'issue[project_id]'}
753 assert_no_tag 'select', :attributes => {:name => 'issue[tracker_id]'}
753 assert_no_tag 'select', :attributes => {:name => 'issue[tracker_id]'}
754 assert_no_tag 'input', :attributes => {:name => 'issue[subject]'}
754 assert_no_tag 'input', :attributes => {:name => 'issue[subject]'}
755 assert_no_tag 'textarea', :attributes => {:name => 'issue[description]'}
755 assert_no_tag 'textarea', :attributes => {:name => 'issue[description]'}
756 assert_no_tag 'select', :attributes => {:name => 'issue[status_id]'}
756 assert_no_tag 'select', :attributes => {:name => 'issue[status_id]'}
757 assert_no_tag 'select', :attributes => {:name => 'issue[priority_id]'}
757 assert_no_tag 'select', :attributes => {:name => 'issue[priority_id]'}
758 assert_no_tag 'select', :attributes => {:name => 'issue[assigned_to_id]'}
758 assert_no_tag 'select', :attributes => {:name => 'issue[assigned_to_id]'}
759 assert_no_tag 'select', :attributes => {:name => 'issue[category_id]'}
759 assert_no_tag 'select', :attributes => {:name => 'issue[category_id]'}
760 assert_no_tag 'select', :attributes => {:name => 'issue[fixed_version_id]'}
760 assert_no_tag 'select', :attributes => {:name => 'issue[fixed_version_id]'}
761 assert_no_tag 'input', :attributes => {:name => 'issue[parent_issue_id]'}
761 assert_no_tag 'input', :attributes => {:name => 'issue[parent_issue_id]'}
762 assert_no_tag 'input', :attributes => {:name => 'issue[start_date]'}
762 assert_no_tag 'input', :attributes => {:name => 'issue[start_date]'}
763 assert_no_tag 'input', :attributes => {:name => 'issue[due_date]'}
763 assert_no_tag 'input', :attributes => {:name => 'issue[due_date]'}
764 assert_no_tag 'select', :attributes => {:name => 'issue[done_ratio]'}
764 assert_no_tag 'select', :attributes => {:name => 'issue[done_ratio]'}
765 assert_no_tag 'input', :attributes => { :name => 'issue[custom_field_values][2]' }
765 assert_no_tag 'input', :attributes => { :name => 'issue[custom_field_values][2]' }
766 assert_no_tag 'input', :attributes => {:name => 'issue[watcher_user_ids][]'}
766 assert_no_tag 'input', :attributes => {:name => 'issue[watcher_user_ids][]'}
767 assert_tag 'textarea', :attributes => {:name => 'notes'}
767 assert_tag 'textarea', :attributes => {:name => 'notes'}
768 end
768 end
769
769
770 def test_show_should_display_update_form_with_workflow_permissions
770 def test_show_should_display_update_form_with_workflow_permissions
771 Role.find(1).update_attribute :permissions, [:view_issues, :add_issue_notes]
771 Role.find(1).update_attribute :permissions, [:view_issues, :add_issue_notes]
772
772
773 @request.session[:user_id] = 2
773 @request.session[:user_id] = 2
774 get :show, :id => 1
774 get :show, :id => 1
775 assert_response :success
775 assert_response :success
776
776
777 assert_tag 'form', :attributes => {:id => 'issue-form'}
777 assert_tag 'form', :attributes => {:id => 'issue-form'}
778 assert_no_tag 'input', :attributes => {:name => 'issue[is_private]'}
778 assert_no_tag 'input', :attributes => {:name => 'issue[is_private]'}
779 assert_no_tag 'select', :attributes => {:name => 'issue[project_id]'}
779 assert_no_tag 'select', :attributes => {:name => 'issue[project_id]'}
780 assert_no_tag 'select', :attributes => {:name => 'issue[tracker_id]'}
780 assert_no_tag 'select', :attributes => {:name => 'issue[tracker_id]'}
781 assert_no_tag 'input', :attributes => {:name => 'issue[subject]'}
781 assert_no_tag 'input', :attributes => {:name => 'issue[subject]'}
782 assert_no_tag 'textarea', :attributes => {:name => 'issue[description]'}
782 assert_no_tag 'textarea', :attributes => {:name => 'issue[description]'}
783 assert_tag 'select', :attributes => {:name => 'issue[status_id]'}
783 assert_tag 'select', :attributes => {:name => 'issue[status_id]'}
784 assert_no_tag 'select', :attributes => {:name => 'issue[priority_id]'}
784 assert_no_tag 'select', :attributes => {:name => 'issue[priority_id]'}
785 assert_tag 'select', :attributes => {:name => 'issue[assigned_to_id]'}
785 assert_tag 'select', :attributes => {:name => 'issue[assigned_to_id]'}
786 assert_no_tag 'select', :attributes => {:name => 'issue[category_id]'}
786 assert_no_tag 'select', :attributes => {:name => 'issue[category_id]'}
787 assert_tag 'select', :attributes => {:name => 'issue[fixed_version_id]'}
787 assert_tag 'select', :attributes => {:name => 'issue[fixed_version_id]'}
788 assert_no_tag 'input', :attributes => {:name => 'issue[parent_issue_id]'}
788 assert_no_tag 'input', :attributes => {:name => 'issue[parent_issue_id]'}
789 assert_no_tag 'input', :attributes => {:name => 'issue[start_date]'}
789 assert_no_tag 'input', :attributes => {:name => 'issue[start_date]'}
790 assert_no_tag 'input', :attributes => {:name => 'issue[due_date]'}
790 assert_no_tag 'input', :attributes => {:name => 'issue[due_date]'}
791 assert_tag 'select', :attributes => {:name => 'issue[done_ratio]'}
791 assert_tag 'select', :attributes => {:name => 'issue[done_ratio]'}
792 assert_no_tag 'input', :attributes => { :name => 'issue[custom_field_values][2]' }
792 assert_no_tag 'input', :attributes => { :name => 'issue[custom_field_values][2]' }
793 assert_no_tag 'input', :attributes => {:name => 'issue[watcher_user_ids][]'}
793 assert_no_tag 'input', :attributes => {:name => 'issue[watcher_user_ids][]'}
794 assert_tag 'textarea', :attributes => {:name => 'notes'}
794 assert_tag 'textarea', :attributes => {:name => 'notes'}
795 end
795 end
796
796
797 def test_show_should_not_display_update_form_without_permissions
797 def test_show_should_not_display_update_form_without_permissions
798 Role.find(1).update_attribute :permissions, [:view_issues]
798 Role.find(1).update_attribute :permissions, [:view_issues]
799
799
800 @request.session[:user_id] = 2
800 @request.session[:user_id] = 2
801 get :show, :id => 1
801 get :show, :id => 1
802 assert_response :success
802 assert_response :success
803
803
804 assert_no_tag 'form', :attributes => {:id => 'issue-form'}
804 assert_no_tag 'form', :attributes => {:id => 'issue-form'}
805 end
805 end
806
806
807 def test_update_form_should_not_display_inactive_enumerations
807 def test_update_form_should_not_display_inactive_enumerations
808 @request.session[:user_id] = 2
808 @request.session[:user_id] = 2
809 get :show, :id => 1
809 get :show, :id => 1
810 assert_response :success
810 assert_response :success
811
811
812 assert ! IssuePriority.find(15).active?
812 assert ! IssuePriority.find(15).active?
813 assert_no_tag :option, :attributes => {:value => '15'},
813 assert_no_tag :option, :attributes => {:value => '15'},
814 :parent => {:tag => 'select', :attributes => {:id => 'issue_priority_id'} }
814 :parent => {:tag => 'select', :attributes => {:id => 'issue_priority_id'} }
815 end
815 end
816
816
817 def test_update_form_should_allow_attachment_upload
817 def test_update_form_should_allow_attachment_upload
818 @request.session[:user_id] = 2
818 @request.session[:user_id] = 2
819 get :show, :id => 1
819 get :show, :id => 1
820
820
821 assert_tag :tag => 'form',
821 assert_tag :tag => 'form',
822 :attributes => {:id => 'issue-form', :method => 'post', :enctype => 'multipart/form-data'},
822 :attributes => {:id => 'issue-form', :method => 'post', :enctype => 'multipart/form-data'},
823 :descendant => {
823 :descendant => {
824 :tag => 'input',
824 :tag => 'input',
825 :attributes => {:type => 'file', :name => 'attachments[1][file]'}
825 :attributes => {:type => 'file', :name => 'attachments[1][file]'}
826 }
826 }
827 end
827 end
828
828
829 def test_show_should_deny_anonymous_access_without_permission
829 def test_show_should_deny_anonymous_access_without_permission
830 Role.anonymous.remove_permission!(:view_issues)
830 Role.anonymous.remove_permission!(:view_issues)
831 get :show, :id => 1
831 get :show, :id => 1
832 assert_response :redirect
832 assert_response :redirect
833 end
833 end
834
834
835 def test_show_should_deny_anonymous_access_to_private_issue
835 def test_show_should_deny_anonymous_access_to_private_issue
836 Issue.update_all(["is_private = ?", true], "id = 1")
836 Issue.update_all(["is_private = ?", true], "id = 1")
837 get :show, :id => 1
837 get :show, :id => 1
838 assert_response :redirect
838 assert_response :redirect
839 end
839 end
840
840
841 def test_show_should_deny_non_member_access_without_permission
841 def test_show_should_deny_non_member_access_without_permission
842 Role.non_member.remove_permission!(:view_issues)
842 Role.non_member.remove_permission!(:view_issues)
843 @request.session[:user_id] = 9
843 @request.session[:user_id] = 9
844 get :show, :id => 1
844 get :show, :id => 1
845 assert_response 403
845 assert_response 403
846 end
846 end
847
847
848 def test_show_should_deny_non_member_access_to_private_issue
848 def test_show_should_deny_non_member_access_to_private_issue
849 Issue.update_all(["is_private = ?", true], "id = 1")
849 Issue.update_all(["is_private = ?", true], "id = 1")
850 @request.session[:user_id] = 9
850 @request.session[:user_id] = 9
851 get :show, :id => 1
851 get :show, :id => 1
852 assert_response 403
852 assert_response 403
853 end
853 end
854
854
855 def test_show_should_deny_member_access_without_permission
855 def test_show_should_deny_member_access_without_permission
856 Role.find(1).remove_permission!(:view_issues)
856 Role.find(1).remove_permission!(:view_issues)
857 @request.session[:user_id] = 2
857 @request.session[:user_id] = 2
858 get :show, :id => 1
858 get :show, :id => 1
859 assert_response 403
859 assert_response 403
860 end
860 end
861
861
862 def test_show_should_deny_member_access_to_private_issue_without_permission
862 def test_show_should_deny_member_access_to_private_issue_without_permission
863 Issue.update_all(["is_private = ?", true], "id = 1")
863 Issue.update_all(["is_private = ?", true], "id = 1")
864 @request.session[:user_id] = 3
864 @request.session[:user_id] = 3
865 get :show, :id => 1
865 get :show, :id => 1
866 assert_response 403
866 assert_response 403
867 end
867 end
868
868
869 def test_show_should_allow_author_access_to_private_issue
869 def test_show_should_allow_author_access_to_private_issue
870 Issue.update_all(["is_private = ?, author_id = 3", true], "id = 1")
870 Issue.update_all(["is_private = ?, author_id = 3", true], "id = 1")
871 @request.session[:user_id] = 3
871 @request.session[:user_id] = 3
872 get :show, :id => 1
872 get :show, :id => 1
873 assert_response :success
873 assert_response :success
874 end
874 end
875
875
876 def test_show_should_allow_assignee_access_to_private_issue
876 def test_show_should_allow_assignee_access_to_private_issue
877 Issue.update_all(["is_private = ?, assigned_to_id = 3", true], "id = 1")
877 Issue.update_all(["is_private = ?, assigned_to_id = 3", true], "id = 1")
878 @request.session[:user_id] = 3
878 @request.session[:user_id] = 3
879 get :show, :id => 1
879 get :show, :id => 1
880 assert_response :success
880 assert_response :success
881 end
881 end
882
882
883 def test_show_should_allow_member_access_to_private_issue_with_permission
883 def test_show_should_allow_member_access_to_private_issue_with_permission
884 Issue.update_all(["is_private = ?", true], "id = 1")
884 Issue.update_all(["is_private = ?", true], "id = 1")
885 User.find(3).roles_for_project(Project.find(1)).first.update_attribute :issues_visibility, 'all'
885 User.find(3).roles_for_project(Project.find(1)).first.update_attribute :issues_visibility, 'all'
886 @request.session[:user_id] = 3
886 @request.session[:user_id] = 3
887 get :show, :id => 1
887 get :show, :id => 1
888 assert_response :success
888 assert_response :success
889 end
889 end
890
890
891 def test_show_should_not_disclose_relations_to_invisible_issues
891 def test_show_should_not_disclose_relations_to_invisible_issues
892 Setting.cross_project_issue_relations = '1'
892 Setting.cross_project_issue_relations = '1'
893 IssueRelation.create!(:issue_from => Issue.find(1), :issue_to => Issue.find(2), :relation_type => 'relates')
893 IssueRelation.create!(:issue_from => Issue.find(1), :issue_to => Issue.find(2), :relation_type => 'relates')
894 # Relation to a private project issue
894 # Relation to a private project issue
895 IssueRelation.create!(:issue_from => Issue.find(1), :issue_to => Issue.find(4), :relation_type => 'relates')
895 IssueRelation.create!(:issue_from => Issue.find(1), :issue_to => Issue.find(4), :relation_type => 'relates')
896
896
897 get :show, :id => 1
897 get :show, :id => 1
898 assert_response :success
898 assert_response :success
899
899
900 assert_tag :div, :attributes => { :id => 'relations' },
900 assert_tag :div, :attributes => { :id => 'relations' },
901 :descendant => { :tag => 'a', :content => /#2$/ }
901 :descendant => { :tag => 'a', :content => /#2$/ }
902 assert_no_tag :div, :attributes => { :id => 'relations' },
902 assert_no_tag :div, :attributes => { :id => 'relations' },
903 :descendant => { :tag => 'a', :content => /#4$/ }
903 :descendant => { :tag => 'a', :content => /#4$/ }
904 end
904 end
905
905
906 def test_show_should_list_subtasks
906 def test_show_should_list_subtasks
907 Issue.generate!(:project_id => 1, :author_id => 1, :tracker_id => 1, :parent_issue_id => 1, :subject => 'Child Issue')
907 Issue.generate!(:project_id => 1, :author_id => 1, :tracker_id => 1, :parent_issue_id => 1, :subject => 'Child Issue')
908
908
909 get :show, :id => 1
909 get :show, :id => 1
910 assert_response :success
910 assert_response :success
911 assert_tag 'div', :attributes => {:id => 'issue_tree'},
911 assert_tag 'div', :attributes => {:id => 'issue_tree'},
912 :descendant => {:tag => 'td', :content => /Child Issue/, :attributes => {:class => /subject/}}
912 :descendant => {:tag => 'td', :content => /Child Issue/, :attributes => {:class => /subject/}}
913 end
913 end
914
914
915 def test_show_should_list_parents
915 def test_show_should_list_parents
916 issue = Issue.generate!(:project_id => 1, :author_id => 1, :tracker_id => 1, :parent_issue_id => 1, :subject => 'Child Issue')
916 issue = Issue.generate!(:project_id => 1, :author_id => 1, :tracker_id => 1, :parent_issue_id => 1, :subject => 'Child Issue')
917
917
918 get :show, :id => issue.id
918 get :show, :id => issue.id
919 assert_response :success
919 assert_response :success
920 assert_tag 'div', :attributes => {:class => 'subject'},
920 assert_tag 'div', :attributes => {:class => 'subject'},
921 :descendant => {:tag => 'h3', :content => 'Child Issue'}
921 :descendant => {:tag => 'h3', :content => 'Child Issue'}
922 assert_tag 'div', :attributes => {:class => 'subject'},
922 assert_tag 'div', :attributes => {:class => 'subject'},
923 :descendant => {:tag => 'a', :attributes => {:href => '/issues/1'}}
923 :descendant => {:tag => 'a', :attributes => {:href => '/issues/1'}}
924 end
924 end
925
925
926 def test_show_should_not_display_prev_next_links_without_query_in_session
926 def test_show_should_not_display_prev_next_links_without_query_in_session
927 get :show, :id => 1
927 get :show, :id => 1
928 assert_response :success
928 assert_response :success
929 assert_nil assigns(:prev_issue_id)
929 assert_nil assigns(:prev_issue_id)
930 assert_nil assigns(:next_issue_id)
930 assert_nil assigns(:next_issue_id)
931 end
931 end
932
932
933 def test_show_should_display_prev_next_links_with_query_in_session
933 def test_show_should_display_prev_next_links_with_query_in_session
934 @request.session[:query] = {:filters => {'status_id' => {:values => [''], :operator => 'o'}}, :project_id => nil}
934 @request.session[:query] = {:filters => {'status_id' => {:values => [''], :operator => 'o'}}, :project_id => nil}
935 @request.session['issues_index_sort'] = 'id'
935 @request.session['issues_index_sort'] = 'id'
936
936
937 with_settings :display_subprojects_issues => '0' do
937 with_settings :display_subprojects_issues => '0' do
938 get :show, :id => 3
938 get :show, :id => 3
939 end
939 end
940
940
941 assert_response :success
941 assert_response :success
942 # Previous and next issues for all projects
942 # Previous and next issues for all projects
943 assert_equal 2, assigns(:prev_issue_id)
943 assert_equal 2, assigns(:prev_issue_id)
944 assert_equal 5, assigns(:next_issue_id)
944 assert_equal 5, assigns(:next_issue_id)
945
945
946 assert_tag 'a', :attributes => {:href => '/issues/2'}, :content => /Previous/
946 assert_tag 'a', :attributes => {:href => '/issues/2'}, :content => /Previous/
947 assert_tag 'a', :attributes => {:href => '/issues/5'}, :content => /Next/
947 assert_tag 'a', :attributes => {:href => '/issues/5'}, :content => /Next/
948 end
948 end
949
949
950 def test_show_should_display_prev_next_links_with_project_query_in_session
950 def test_show_should_display_prev_next_links_with_project_query_in_session
951 @request.session[:query] = {:filters => {'status_id' => {:values => [''], :operator => 'o'}}, :project_id => 1}
951 @request.session[:query] = {:filters => {'status_id' => {:values => [''], :operator => 'o'}}, :project_id => 1}
952 @request.session['issues_index_sort'] = 'id'
952 @request.session['issues_index_sort'] = 'id'
953
953
954 with_settings :display_subprojects_issues => '0' do
954 with_settings :display_subprojects_issues => '0' do
955 get :show, :id => 3
955 get :show, :id => 3
956 end
956 end
957
957
958 assert_response :success
958 assert_response :success
959 # Previous and next issues inside project
959 # Previous and next issues inside project
960 assert_equal 2, assigns(:prev_issue_id)
960 assert_equal 2, assigns(:prev_issue_id)
961 assert_equal 7, assigns(:next_issue_id)
961 assert_equal 7, assigns(:next_issue_id)
962
962
963 assert_tag 'a', :attributes => {:href => '/issues/2'}, :content => /Previous/
963 assert_tag 'a', :attributes => {:href => '/issues/2'}, :content => /Previous/
964 assert_tag 'a', :attributes => {:href => '/issues/7'}, :content => /Next/
964 assert_tag 'a', :attributes => {:href => '/issues/7'}, :content => /Next/
965 end
965 end
966
966
967 def test_show_should_not_display_prev_link_for_first_issue
967 def test_show_should_not_display_prev_link_for_first_issue
968 @request.session[:query] = {:filters => {'status_id' => {:values => [''], :operator => 'o'}}, :project_id => 1}
968 @request.session[:query] = {:filters => {'status_id' => {:values => [''], :operator => 'o'}}, :project_id => 1}
969 @request.session['issues_index_sort'] = 'id'
969 @request.session['issues_index_sort'] = 'id'
970
970
971 with_settings :display_subprojects_issues => '0' do
971 with_settings :display_subprojects_issues => '0' do
972 get :show, :id => 1
972 get :show, :id => 1
973 end
973 end
974
974
975 assert_response :success
975 assert_response :success
976 assert_nil assigns(:prev_issue_id)
976 assert_nil assigns(:prev_issue_id)
977 assert_equal 2, assigns(:next_issue_id)
977 assert_equal 2, assigns(:next_issue_id)
978
978
979 assert_no_tag 'a', :content => /Previous/
979 assert_no_tag 'a', :content => /Previous/
980 assert_tag 'a', :attributes => {:href => '/issues/2'}, :content => /Next/
980 assert_tag 'a', :attributes => {:href => '/issues/2'}, :content => /Next/
981 end
981 end
982
982
983 def test_show_should_not_display_prev_next_links_for_issue_not_in_query_results
983 def test_show_should_not_display_prev_next_links_for_issue_not_in_query_results
984 @request.session[:query] = {:filters => {'status_id' => {:values => [''], :operator => 'c'}}, :project_id => 1}
984 @request.session[:query] = {:filters => {'status_id' => {:values => [''], :operator => 'c'}}, :project_id => 1}
985 @request.session['issues_index_sort'] = 'id'
985 @request.session['issues_index_sort'] = 'id'
986
986
987 get :show, :id => 1
987 get :show, :id => 1
988
988
989 assert_response :success
989 assert_response :success
990 assert_nil assigns(:prev_issue_id)
990 assert_nil assigns(:prev_issue_id)
991 assert_nil assigns(:next_issue_id)
991 assert_nil assigns(:next_issue_id)
992
992
993 assert_no_tag 'a', :content => /Previous/
993 assert_no_tag 'a', :content => /Previous/
994 assert_no_tag 'a', :content => /Next/
994 assert_no_tag 'a', :content => /Next/
995 end
995 end
996
996
997 def test_show_atom
997 def test_show_atom
998 get :show, :id => 2, :format => 'atom'
998 get :show, :id => 2, :format => 'atom'
999 assert_response :success
999 assert_response :success
1000 assert_template 'journals/index'
1000 assert_template 'journals/index'
1001 # Inline image
1001 # Inline image
1002 assert_select 'content', :text => Regexp.new(Regexp.quote('http://test.host/attachments/download/10'))
1002 assert_select 'content', :text => Regexp.new(Regexp.quote('http://test.host/attachments/download/10'))
1003 end
1003 end
1004
1004
1005 def test_show_export_to_pdf
1005 def test_show_export_to_pdf
1006 get :show, :id => 3, :format => 'pdf'
1006 get :show, :id => 3, :format => 'pdf'
1007 assert_response :success
1007 assert_response :success
1008 assert_equal 'application/pdf', @response.content_type
1008 assert_equal 'application/pdf', @response.content_type
1009 assert @response.body.starts_with?('%PDF')
1009 assert @response.body.starts_with?('%PDF')
1010 assert_not_nil assigns(:issue)
1010 assert_not_nil assigns(:issue)
1011 end
1011 end
1012
1012
1013 def test_get_new
1013 def test_get_new
1014 @request.session[:user_id] = 2
1014 @request.session[:user_id] = 2
1015 get :new, :project_id => 1, :tracker_id => 1
1015 get :new, :project_id => 1, :tracker_id => 1
1016 assert_response :success
1016 assert_response :success
1017 assert_template 'new'
1017 assert_template 'new'
1018
1018
1019 assert_tag 'input', :attributes => {:name => 'issue[is_private]'}
1019 assert_tag 'input', :attributes => {:name => 'issue[is_private]'}
1020 assert_no_tag 'select', :attributes => {:name => 'issue[project_id]'}
1020 assert_no_tag 'select', :attributes => {:name => 'issue[project_id]'}
1021 assert_tag 'select', :attributes => {:name => 'issue[tracker_id]'}
1021 assert_tag 'select', :attributes => {:name => 'issue[tracker_id]'}
1022 assert_tag 'input', :attributes => {:name => 'issue[subject]'}
1022 assert_tag 'input', :attributes => {:name => 'issue[subject]'}
1023 assert_tag 'textarea', :attributes => {:name => 'issue[description]'}
1023 assert_tag 'textarea', :attributes => {:name => 'issue[description]'}
1024 assert_tag 'select', :attributes => {:name => 'issue[status_id]'}
1024 assert_tag 'select', :attributes => {:name => 'issue[status_id]'}
1025 assert_tag 'select', :attributes => {:name => 'issue[priority_id]'}
1025 assert_tag 'select', :attributes => {:name => 'issue[priority_id]'}
1026 assert_tag 'select', :attributes => {:name => 'issue[assigned_to_id]'}
1026 assert_tag 'select', :attributes => {:name => 'issue[assigned_to_id]'}
1027 assert_tag 'select', :attributes => {:name => 'issue[category_id]'}
1027 assert_tag 'select', :attributes => {:name => 'issue[category_id]'}
1028 assert_tag 'select', :attributes => {:name => 'issue[fixed_version_id]'}
1028 assert_tag 'select', :attributes => {:name => 'issue[fixed_version_id]'}
1029 assert_tag 'input', :attributes => {:name => 'issue[parent_issue_id]'}
1029 assert_tag 'input', :attributes => {:name => 'issue[parent_issue_id]'}
1030 assert_tag 'input', :attributes => {:name => 'issue[start_date]'}
1030 assert_tag 'input', :attributes => {:name => 'issue[start_date]'}
1031 assert_tag 'input', :attributes => {:name => 'issue[due_date]'}
1031 assert_tag 'input', :attributes => {:name => 'issue[due_date]'}
1032 assert_tag 'select', :attributes => {:name => 'issue[done_ratio]'}
1032 assert_tag 'select', :attributes => {:name => 'issue[done_ratio]'}
1033 assert_tag 'input', :attributes => { :name => 'issue[custom_field_values][2]', :value => 'Default string' }
1033 assert_tag 'input', :attributes => { :name => 'issue[custom_field_values][2]', :value => 'Default string' }
1034 assert_tag 'input', :attributes => {:name => 'issue[watcher_user_ids][]'}
1034 assert_tag 'input', :attributes => {:name => 'issue[watcher_user_ids][]'}
1035
1035
1036 # Be sure we don't display inactive IssuePriorities
1036 # Be sure we don't display inactive IssuePriorities
1037 assert ! IssuePriority.find(15).active?
1037 assert ! IssuePriority.find(15).active?
1038 assert_no_tag :option, :attributes => {:value => '15'},
1038 assert_no_tag :option, :attributes => {:value => '15'},
1039 :parent => {:tag => 'select', :attributes => {:id => 'issue_priority_id'} }
1039 :parent => {:tag => 'select', :attributes => {:id => 'issue_priority_id'} }
1040 end
1040 end
1041
1041
1042 def test_get_new_with_minimal_permissions
1042 def test_get_new_with_minimal_permissions
1043 Role.find(1).update_attribute :permissions, [:add_issues]
1043 Role.find(1).update_attribute :permissions, [:add_issues]
1044 Workflow.delete_all :role_id => 1
1044 Workflow.delete_all :role_id => 1
1045
1045
1046 @request.session[:user_id] = 2
1046 @request.session[:user_id] = 2
1047 get :new, :project_id => 1, :tracker_id => 1
1047 get :new, :project_id => 1, :tracker_id => 1
1048 assert_response :success
1048 assert_response :success
1049 assert_template 'new'
1049 assert_template 'new'
1050
1050
1051 assert_no_tag 'input', :attributes => {:name => 'issue[is_private]'}
1051 assert_no_tag 'input', :attributes => {:name => 'issue[is_private]'}
1052 assert_no_tag 'select', :attributes => {:name => 'issue[project_id]'}
1052 assert_no_tag 'select', :attributes => {:name => 'issue[project_id]'}
1053 assert_tag 'select', :attributes => {:name => 'issue[tracker_id]'}
1053 assert_tag 'select', :attributes => {:name => 'issue[tracker_id]'}
1054 assert_tag 'input', :attributes => {:name => 'issue[subject]'}
1054 assert_tag 'input', :attributes => {:name => 'issue[subject]'}
1055 assert_tag 'textarea', :attributes => {:name => 'issue[description]'}
1055 assert_tag 'textarea', :attributes => {:name => 'issue[description]'}
1056 assert_tag 'select', :attributes => {:name => 'issue[status_id]'}
1056 assert_tag 'select', :attributes => {:name => 'issue[status_id]'}
1057 assert_tag 'select', :attributes => {:name => 'issue[priority_id]'}
1057 assert_tag 'select', :attributes => {:name => 'issue[priority_id]'}
1058 assert_tag 'select', :attributes => {:name => 'issue[assigned_to_id]'}
1058 assert_tag 'select', :attributes => {:name => 'issue[assigned_to_id]'}
1059 assert_tag 'select', :attributes => {:name => 'issue[category_id]'}
1059 assert_tag 'select', :attributes => {:name => 'issue[category_id]'}
1060 assert_tag 'select', :attributes => {:name => 'issue[fixed_version_id]'}
1060 assert_tag 'select', :attributes => {:name => 'issue[fixed_version_id]'}
1061 assert_no_tag 'input', :attributes => {:name => 'issue[parent_issue_id]'}
1061 assert_no_tag 'input', :attributes => {:name => 'issue[parent_issue_id]'}
1062 assert_tag 'input', :attributes => {:name => 'issue[start_date]'}
1062 assert_tag 'input', :attributes => {:name => 'issue[start_date]'}
1063 assert_tag 'input', :attributes => {:name => 'issue[due_date]'}
1063 assert_tag 'input', :attributes => {:name => 'issue[due_date]'}
1064 assert_tag 'select', :attributes => {:name => 'issue[done_ratio]'}
1064 assert_tag 'select', :attributes => {:name => 'issue[done_ratio]'}
1065 assert_tag 'input', :attributes => { :name => 'issue[custom_field_values][2]', :value => 'Default string' }
1065 assert_tag 'input', :attributes => { :name => 'issue[custom_field_values][2]', :value => 'Default string' }
1066 assert_no_tag 'input', :attributes => {:name => 'issue[watcher_user_ids][]'}
1066 assert_no_tag 'input', :attributes => {:name => 'issue[watcher_user_ids][]'}
1067 end
1067 end
1068
1068
1069 def test_get_new_without_default_start_date_is_creation_date
1069 def test_get_new_without_default_start_date_is_creation_date
1070 Setting.default_issue_start_date_to_creation_date = 0
1070 Setting.default_issue_start_date_to_creation_date = 0
1071
1071
1072 @request.session[:user_id] = 2
1072 @request.session[:user_id] = 2
1073 get :new, :project_id => 1, :tracker_id => 1
1073 get :new, :project_id => 1, :tracker_id => 1
1074 assert_response :success
1074 assert_response :success
1075 assert_template 'new'
1075 assert_template 'new'
1076
1076
1077 assert_tag :tag => 'input', :attributes => { :name => 'issue[start_date]',
1077 assert_tag :tag => 'input', :attributes => { :name => 'issue[start_date]',
1078 :value => nil }
1078 :value => nil }
1079 end
1079 end
1080
1080
1081 def test_get_new_with_default_start_date_is_creation_date
1081 def test_get_new_with_default_start_date_is_creation_date
1082 Setting.default_issue_start_date_to_creation_date = 1
1082 Setting.default_issue_start_date_to_creation_date = 1
1083
1083
1084 @request.session[:user_id] = 2
1084 @request.session[:user_id] = 2
1085 get :new, :project_id => 1, :tracker_id => 1
1085 get :new, :project_id => 1, :tracker_id => 1
1086 assert_response :success
1086 assert_response :success
1087 assert_template 'new'
1087 assert_template 'new'
1088
1088
1089 assert_tag :tag => 'input', :attributes => { :name => 'issue[start_date]',
1089 assert_tag :tag => 'input', :attributes => { :name => 'issue[start_date]',
1090 :value => Date.today.to_s }
1090 :value => Date.today.to_s }
1091 end
1091 end
1092
1092
1093 def test_get_new_form_should_allow_attachment_upload
1093 def test_get_new_form_should_allow_attachment_upload
1094 @request.session[:user_id] = 2
1094 @request.session[:user_id] = 2
1095 get :new, :project_id => 1, :tracker_id => 1
1095 get :new, :project_id => 1, :tracker_id => 1
1096
1096
1097 assert_tag :tag => 'form',
1097 assert_tag :tag => 'form',
1098 :attributes => {:id => 'issue-form', :method => 'post', :enctype => 'multipart/form-data'},
1098 :attributes => {:id => 'issue-form', :method => 'post', :enctype => 'multipart/form-data'},
1099 :descendant => {
1099 :descendant => {
1100 :tag => 'input',
1100 :tag => 'input',
1101 :attributes => {:type => 'file', :name => 'attachments[1][file]'}
1101 :attributes => {:type => 'file', :name => 'attachments[1][file]'}
1102 }
1102 }
1103 end
1103 end
1104
1104
1105 def test_get_new_without_tracker_id
1105 def test_get_new_without_tracker_id
1106 @request.session[:user_id] = 2
1106 @request.session[:user_id] = 2
1107 get :new, :project_id => 1
1107 get :new, :project_id => 1
1108 assert_response :success
1108 assert_response :success
1109 assert_template 'new'
1109 assert_template 'new'
1110
1110
1111 issue = assigns(:issue)
1111 issue = assigns(:issue)
1112 assert_not_nil issue
1112 assert_not_nil issue
1113 assert_equal Project.find(1).trackers.first, issue.tracker
1113 assert_equal Project.find(1).trackers.first, issue.tracker
1114 end
1114 end
1115
1115
1116 def test_get_new_with_no_default_status_should_display_an_error
1116 def test_get_new_with_no_default_status_should_display_an_error
1117 @request.session[:user_id] = 2
1117 @request.session[:user_id] = 2
1118 IssueStatus.delete_all
1118 IssueStatus.delete_all
1119
1119
1120 get :new, :project_id => 1
1120 get :new, :project_id => 1
1121 assert_response 500
1121 assert_response 500
1122 assert_error_tag :content => /No default issue/
1122 assert_error_tag :content => /No default issue/
1123 end
1123 end
1124
1124
1125 def test_get_new_with_no_tracker_should_display_an_error
1125 def test_get_new_with_no_tracker_should_display_an_error
1126 @request.session[:user_id] = 2
1126 @request.session[:user_id] = 2
1127 Tracker.delete_all
1127 Tracker.delete_all
1128
1128
1129 get :new, :project_id => 1
1129 get :new, :project_id => 1
1130 assert_response 500
1130 assert_response 500
1131 assert_error_tag :content => /No tracker/
1131 assert_error_tag :content => /No tracker/
1132 end
1132 end
1133
1133
1134 def test_update_new_form
1134 def test_update_new_form
1135 @request.session[:user_id] = 2
1135 @request.session[:user_id] = 2
1136 xhr :post, :new, :project_id => 1,
1136 xhr :post, :new, :project_id => 1,
1137 :issue => {:tracker_id => 2,
1137 :issue => {:tracker_id => 2,
1138 :subject => 'This is the test_new issue',
1138 :subject => 'This is the test_new issue',
1139 :description => 'This is the description',
1139 :description => 'This is the description',
1140 :priority_id => 5}
1140 :priority_id => 5}
1141 assert_response :success
1141 assert_response :success
1142 assert_template 'attributes'
1142 assert_template 'attributes'
1143
1143
1144 issue = assigns(:issue)
1144 issue = assigns(:issue)
1145 assert_kind_of Issue, issue
1145 assert_kind_of Issue, issue
1146 assert_equal 1, issue.project_id
1146 assert_equal 1, issue.project_id
1147 assert_equal 2, issue.tracker_id
1147 assert_equal 2, issue.tracker_id
1148 assert_equal 'This is the test_new issue', issue.subject
1148 assert_equal 'This is the test_new issue', issue.subject
1149 end
1149 end
1150
1150
1151 def test_post_create
1151 def test_post_create
1152 @request.session[:user_id] = 2
1152 @request.session[:user_id] = 2
1153 assert_difference 'Issue.count' do
1153 assert_difference 'Issue.count' do
1154 post :create, :project_id => 1,
1154 post :create, :project_id => 1,
1155 :issue => {:tracker_id => 3,
1155 :issue => {:tracker_id => 3,
1156 :status_id => 2,
1156 :status_id => 2,
1157 :subject => 'This is the test_new issue',
1157 :subject => 'This is the test_new issue',
1158 :description => 'This is the description',
1158 :description => 'This is the description',
1159 :priority_id => 5,
1159 :priority_id => 5,
1160 :start_date => '2010-11-07',
1160 :start_date => '2010-11-07',
1161 :estimated_hours => '',
1161 :estimated_hours => '',
1162 :custom_field_values => {'2' => 'Value for field 2'}}
1162 :custom_field_values => {'2' => 'Value for field 2'}}
1163 end
1163 end
1164 assert_redirected_to :controller => 'issues', :action => 'show', :id => Issue.last.id
1164 assert_redirected_to :controller => 'issues', :action => 'show', :id => Issue.last.id
1165
1165
1166 issue = Issue.find_by_subject('This is the test_new issue')
1166 issue = Issue.find_by_subject('This is the test_new issue')
1167 assert_not_nil issue
1167 assert_not_nil issue
1168 assert_equal 2, issue.author_id
1168 assert_equal 2, issue.author_id
1169 assert_equal 3, issue.tracker_id
1169 assert_equal 3, issue.tracker_id
1170 assert_equal 2, issue.status_id
1170 assert_equal 2, issue.status_id
1171 assert_equal Date.parse('2010-11-07'), issue.start_date
1171 assert_equal Date.parse('2010-11-07'), issue.start_date
1172 assert_nil issue.estimated_hours
1172 assert_nil issue.estimated_hours
1173 v = issue.custom_values.find(:first, :conditions => {:custom_field_id => 2})
1173 v = issue.custom_values.find(:first, :conditions => {:custom_field_id => 2})
1174 assert_not_nil v
1174 assert_not_nil v
1175 assert_equal 'Value for field 2', v.value
1175 assert_equal 'Value for field 2', v.value
1176 end
1176 end
1177
1177
1178 def test_post_new_with_group_assignment
1178 def test_post_new_with_group_assignment
1179 group = Group.find(11)
1179 group = Group.find(11)
1180 project = Project.find(1)
1180 project = Project.find(1)
1181 project.members << Member.new(:principal => group, :roles => [Role.first])
1181 project.members << Member.new(:principal => group, :roles => [Role.first])
1182
1182
1183 with_settings :issue_group_assignment => '1' do
1183 with_settings :issue_group_assignment => '1' do
1184 @request.session[:user_id] = 2
1184 @request.session[:user_id] = 2
1185 assert_difference 'Issue.count' do
1185 assert_difference 'Issue.count' do
1186 post :create, :project_id => project.id,
1186 post :create, :project_id => project.id,
1187 :issue => {:tracker_id => 3,
1187 :issue => {:tracker_id => 3,
1188 :status_id => 1,
1188 :status_id => 1,
1189 :subject => 'This is the test_new_with_group_assignment issue',
1189 :subject => 'This is the test_new_with_group_assignment issue',
1190 :assigned_to_id => group.id}
1190 :assigned_to_id => group.id}
1191 end
1191 end
1192 end
1192 end
1193 assert_redirected_to :controller => 'issues', :action => 'show', :id => Issue.last.id
1193 assert_redirected_to :controller => 'issues', :action => 'show', :id => Issue.last.id
1194
1194
1195 issue = Issue.find_by_subject('This is the test_new_with_group_assignment issue')
1195 issue = Issue.find_by_subject('This is the test_new_with_group_assignment issue')
1196 assert_not_nil issue
1196 assert_not_nil issue
1197 assert_equal group, issue.assigned_to
1197 assert_equal group, issue.assigned_to
1198 end
1198 end
1199
1199
1200 def test_post_create_without_start_date_and_default_start_date_is_not_creation_date
1200 def test_post_create_without_start_date_and_default_start_date_is_not_creation_date
1201 Setting.default_issue_start_date_to_creation_date = 0
1201 Setting.default_issue_start_date_to_creation_date = 0
1202
1202
1203 @request.session[:user_id] = 2
1203 @request.session[:user_id] = 2
1204 assert_difference 'Issue.count' do
1204 assert_difference 'Issue.count' do
1205 post :create, :project_id => 1,
1205 post :create, :project_id => 1,
1206 :issue => {:tracker_id => 3,
1206 :issue => {:tracker_id => 3,
1207 :status_id => 2,
1207 :status_id => 2,
1208 :subject => 'This is the test_new issue',
1208 :subject => 'This is the test_new issue',
1209 :description => 'This is the description',
1209 :description => 'This is the description',
1210 :priority_id => 5,
1210 :priority_id => 5,
1211 :estimated_hours => '',
1211 :estimated_hours => '',
1212 :custom_field_values => {'2' => 'Value for field 2'}}
1212 :custom_field_values => {'2' => 'Value for field 2'}}
1213 end
1213 end
1214 assert_redirected_to :controller => 'issues', :action => 'show', :id => Issue.last.id
1214 assert_redirected_to :controller => 'issues', :action => 'show', :id => Issue.last.id
1215
1215
1216 issue = Issue.find_by_subject('This is the test_new issue')
1216 issue = Issue.find_by_subject('This is the test_new issue')
1217 assert_not_nil issue
1217 assert_not_nil issue
1218 assert_nil issue.start_date
1218 assert_nil issue.start_date
1219 end
1219 end
1220
1220
1221 def test_post_create_without_start_date_and_default_start_date_is_creation_date
1221 def test_post_create_without_start_date_and_default_start_date_is_creation_date
1222 Setting.default_issue_start_date_to_creation_date = 1
1222 Setting.default_issue_start_date_to_creation_date = 1
1223
1223
1224 @request.session[:user_id] = 2
1224 @request.session[:user_id] = 2
1225 assert_difference 'Issue.count' do
1225 assert_difference 'Issue.count' do
1226 post :create, :project_id => 1,
1226 post :create, :project_id => 1,
1227 :issue => {:tracker_id => 3,
1227 :issue => {:tracker_id => 3,
1228 :status_id => 2,
1228 :status_id => 2,
1229 :subject => 'This is the test_new issue',
1229 :subject => 'This is the test_new issue',
1230 :description => 'This is the description',
1230 :description => 'This is the description',
1231 :priority_id => 5,
1231 :priority_id => 5,
1232 :estimated_hours => '',
1232 :estimated_hours => '',
1233 :custom_field_values => {'2' => 'Value for field 2'}}
1233 :custom_field_values => {'2' => 'Value for field 2'}}
1234 end
1234 end
1235 assert_redirected_to :controller => 'issues', :action => 'show', :id => Issue.last.id
1235 assert_redirected_to :controller => 'issues', :action => 'show', :id => Issue.last.id
1236
1236
1237 issue = Issue.find_by_subject('This is the test_new issue')
1237 issue = Issue.find_by_subject('This is the test_new issue')
1238 assert_not_nil issue
1238 assert_not_nil issue
1239 assert_equal Date.today, issue.start_date
1239 assert_equal Date.today, issue.start_date
1240 end
1240 end
1241
1241
1242 def test_post_create_and_continue
1242 def test_post_create_and_continue
1243 @request.session[:user_id] = 2
1243 @request.session[:user_id] = 2
1244 assert_difference 'Issue.count' do
1244 assert_difference 'Issue.count' do
1245 post :create, :project_id => 1,
1245 post :create, :project_id => 1,
1246 :issue => {:tracker_id => 3, :subject => 'This is first issue', :priority_id => 5},
1246 :issue => {:tracker_id => 3, :subject => 'This is first issue', :priority_id => 5},
1247 :continue => ''
1247 :continue => ''
1248 end
1248 end
1249
1249
1250 issue = Issue.first(:order => 'id DESC')
1250 issue = Issue.first(:order => 'id DESC')
1251 assert_redirected_to :controller => 'issues', :action => 'new', :project_id => 'ecookbook', :issue => {:tracker_id => 3}
1251 assert_redirected_to :controller => 'issues', :action => 'new', :project_id => 'ecookbook', :issue => {:tracker_id => 3}
1252 assert_not_nil flash[:notice], "flash was not set"
1252 assert_not_nil flash[:notice], "flash was not set"
1253 assert flash[:notice].include?("<a href='/issues/#{issue.id}'>##{issue.id}</a>"), "issue link not found in flash: #{flash[:notice]}"
1253 assert flash[:notice].include?("<a href='/issues/#{issue.id}'>##{issue.id}</a>"), "issue link not found in flash: #{flash[:notice]}"
1254 end
1254 end
1255
1255
1256 def test_post_create_without_custom_fields_param
1256 def test_post_create_without_custom_fields_param
1257 @request.session[:user_id] = 2
1257 @request.session[:user_id] = 2
1258 assert_difference 'Issue.count' do
1258 assert_difference 'Issue.count' do
1259 post :create, :project_id => 1,
1259 post :create, :project_id => 1,
1260 :issue => {:tracker_id => 1,
1260 :issue => {:tracker_id => 1,
1261 :subject => 'This is the test_new issue',
1261 :subject => 'This is the test_new issue',
1262 :description => 'This is the description',
1262 :description => 'This is the description',
1263 :priority_id => 5}
1263 :priority_id => 5}
1264 end
1264 end
1265 assert_redirected_to :controller => 'issues', :action => 'show', :id => Issue.last.id
1265 assert_redirected_to :controller => 'issues', :action => 'show', :id => Issue.last.id
1266 end
1266 end
1267
1267
1268 def test_post_create_with_required_custom_field_and_without_custom_fields_param
1268 def test_post_create_with_required_custom_field_and_without_custom_fields_param
1269 field = IssueCustomField.find_by_name('Database')
1269 field = IssueCustomField.find_by_name('Database')
1270 field.update_attribute(:is_required, true)
1270 field.update_attribute(:is_required, true)
1271
1271
1272 @request.session[:user_id] = 2
1272 @request.session[:user_id] = 2
1273 post :create, :project_id => 1,
1273 post :create, :project_id => 1,
1274 :issue => {:tracker_id => 1,
1274 :issue => {:tracker_id => 1,
1275 :subject => 'This is the test_new issue',
1275 :subject => 'This is the test_new issue',
1276 :description => 'This is the description',
1276 :description => 'This is the description',
1277 :priority_id => 5}
1277 :priority_id => 5}
1278 assert_response :success
1278 assert_response :success
1279 assert_template 'new'
1279 assert_template 'new'
1280 issue = assigns(:issue)
1280 issue = assigns(:issue)
1281 assert_not_nil issue
1281 assert_not_nil issue
1282 assert_equal I18n.translate('activerecord.errors.messages.invalid'),
1282 assert_equal I18n.translate('activerecord.errors.messages.invalid'),
1283 issue.errors[:custom_values].to_s
1283 issue.errors[:custom_values].to_s
1284 end
1284 end
1285
1285
1286 def test_post_create_with_watchers
1286 def test_post_create_with_watchers
1287 @request.session[:user_id] = 2
1287 @request.session[:user_id] = 2
1288 ActionMailer::Base.deliveries.clear
1288 ActionMailer::Base.deliveries.clear
1289
1289
1290 assert_difference 'Watcher.count', 2 do
1290 assert_difference 'Watcher.count', 2 do
1291 post :create, :project_id => 1,
1291 post :create, :project_id => 1,
1292 :issue => {:tracker_id => 1,
1292 :issue => {:tracker_id => 1,
1293 :subject => 'This is a new issue with watchers',
1293 :subject => 'This is a new issue with watchers',
1294 :description => 'This is the description',
1294 :description => 'This is the description',
1295 :priority_id => 5,
1295 :priority_id => 5,
1296 :watcher_user_ids => ['2', '3']}
1296 :watcher_user_ids => ['2', '3']}
1297 end
1297 end
1298 issue = Issue.find_by_subject('This is a new issue with watchers')
1298 issue = Issue.find_by_subject('This is a new issue with watchers')
1299 assert_not_nil issue
1299 assert_not_nil issue
1300 assert_redirected_to :controller => 'issues', :action => 'show', :id => issue
1300 assert_redirected_to :controller => 'issues', :action => 'show', :id => issue
1301
1301
1302 # Watchers added
1302 # Watchers added
1303 assert_equal [2, 3], issue.watcher_user_ids.sort
1303 assert_equal [2, 3], issue.watcher_user_ids.sort
1304 assert issue.watched_by?(User.find(3))
1304 assert issue.watched_by?(User.find(3))
1305 # Watchers notified
1305 # Watchers notified
1306 mail = ActionMailer::Base.deliveries.last
1306 mail = ActionMailer::Base.deliveries.last
1307 assert_kind_of TMail::Mail, mail
1307 assert_kind_of TMail::Mail, mail
1308 assert [mail.bcc, mail.cc].flatten.include?(User.find(3).mail)
1308 assert [mail.bcc, mail.cc].flatten.include?(User.find(3).mail)
1309 end
1309 end
1310
1310
1311 def test_post_create_subissue
1311 def test_post_create_subissue
1312 @request.session[:user_id] = 2
1312 @request.session[:user_id] = 2
1313
1313
1314 assert_difference 'Issue.count' do
1314 assert_difference 'Issue.count' do
1315 post :create, :project_id => 1,
1315 post :create, :project_id => 1,
1316 :issue => {:tracker_id => 1,
1316 :issue => {:tracker_id => 1,
1317 :subject => 'This is a child issue',
1317 :subject => 'This is a child issue',
1318 :parent_issue_id => 2}
1318 :parent_issue_id => 2}
1319 end
1319 end
1320 issue = Issue.find_by_subject('This is a child issue')
1320 issue = Issue.find_by_subject('This is a child issue')
1321 assert_not_nil issue
1321 assert_not_nil issue
1322 assert_equal Issue.find(2), issue.parent
1322 assert_equal Issue.find(2), issue.parent
1323 end
1323 end
1324
1324
1325 def test_post_create_subissue_with_non_numeric_parent_id
1325 def test_post_create_subissue_with_non_numeric_parent_id
1326 @request.session[:user_id] = 2
1326 @request.session[:user_id] = 2
1327
1327
1328 assert_difference 'Issue.count' do
1328 assert_difference 'Issue.count' do
1329 post :create, :project_id => 1,
1329 post :create, :project_id => 1,
1330 :issue => {:tracker_id => 1,
1330 :issue => {:tracker_id => 1,
1331 :subject => 'This is a child issue',
1331 :subject => 'This is a child issue',
1332 :parent_issue_id => 'ABC'}
1332 :parent_issue_id => 'ABC'}
1333 end
1333 end
1334 issue = Issue.find_by_subject('This is a child issue')
1334 issue = Issue.find_by_subject('This is a child issue')
1335 assert_not_nil issue
1335 assert_not_nil issue
1336 assert_nil issue.parent
1336 assert_nil issue.parent
1337 end
1337 end
1338
1338
1339 def test_post_create_private
1339 def test_post_create_private
1340 @request.session[:user_id] = 2
1340 @request.session[:user_id] = 2
1341
1341
1342 assert_difference 'Issue.count' do
1342 assert_difference 'Issue.count' do
1343 post :create, :project_id => 1,
1343 post :create, :project_id => 1,
1344 :issue => {:tracker_id => 1,
1344 :issue => {:tracker_id => 1,
1345 :subject => 'This is a private issue',
1345 :subject => 'This is a private issue',
1346 :is_private => '1'}
1346 :is_private => '1'}
1347 end
1347 end
1348 issue = Issue.first(:order => 'id DESC')
1348 issue = Issue.first(:order => 'id DESC')
1349 assert issue.is_private?
1349 assert issue.is_private?
1350 end
1350 end
1351
1351
1352 def test_post_create_private_with_set_own_issues_private_permission
1352 def test_post_create_private_with_set_own_issues_private_permission
1353 role = Role.find(1)
1353 role = Role.find(1)
1354 role.remove_permission! :set_issues_private
1354 role.remove_permission! :set_issues_private
1355 role.add_permission! :set_own_issues_private
1355 role.add_permission! :set_own_issues_private
1356
1356
1357 @request.session[:user_id] = 2
1357 @request.session[:user_id] = 2
1358
1358
1359 assert_difference 'Issue.count' do
1359 assert_difference 'Issue.count' do
1360 post :create, :project_id => 1,
1360 post :create, :project_id => 1,
1361 :issue => {:tracker_id => 1,
1361 :issue => {:tracker_id => 1,
1362 :subject => 'This is a private issue',
1362 :subject => 'This is a private issue',
1363 :is_private => '1'}
1363 :is_private => '1'}
1364 end
1364 end
1365 issue = Issue.first(:order => 'id DESC')
1365 issue = Issue.first(:order => 'id DESC')
1366 assert issue.is_private?
1366 assert issue.is_private?
1367 end
1367 end
1368
1368
1369 def test_post_create_should_send_a_notification
1369 def test_post_create_should_send_a_notification
1370 ActionMailer::Base.deliveries.clear
1370 ActionMailer::Base.deliveries.clear
1371 @request.session[:user_id] = 2
1371 @request.session[:user_id] = 2
1372 assert_difference 'Issue.count' do
1372 assert_difference 'Issue.count' do
1373 post :create, :project_id => 1,
1373 post :create, :project_id => 1,
1374 :issue => {:tracker_id => 3,
1374 :issue => {:tracker_id => 3,
1375 :subject => 'This is the test_new issue',
1375 :subject => 'This is the test_new issue',
1376 :description => 'This is the description',
1376 :description => 'This is the description',
1377 :priority_id => 5,
1377 :priority_id => 5,
1378 :estimated_hours => '',
1378 :estimated_hours => '',
1379 :custom_field_values => {'2' => 'Value for field 2'}}
1379 :custom_field_values => {'2' => 'Value for field 2'}}
1380 end
1380 end
1381 assert_redirected_to :controller => 'issues', :action => 'show', :id => Issue.last.id
1381 assert_redirected_to :controller => 'issues', :action => 'show', :id => Issue.last.id
1382
1382
1383 assert_equal 1, ActionMailer::Base.deliveries.size
1383 assert_equal 1, ActionMailer::Base.deliveries.size
1384 end
1384 end
1385
1385
1386 def test_post_create_should_preserve_fields_values_on_validation_failure
1386 def test_post_create_should_preserve_fields_values_on_validation_failure
1387 @request.session[:user_id] = 2
1387 @request.session[:user_id] = 2
1388 post :create, :project_id => 1,
1388 post :create, :project_id => 1,
1389 :issue => {:tracker_id => 1,
1389 :issue => {:tracker_id => 1,
1390 # empty subject
1390 # empty subject
1391 :subject => '',
1391 :subject => '',
1392 :description => 'This is a description',
1392 :description => 'This is a description',
1393 :priority_id => 6,
1393 :priority_id => 6,
1394 :custom_field_values => {'1' => 'Oracle', '2' => 'Value for field 2'}}
1394 :custom_field_values => {'1' => 'Oracle', '2' => 'Value for field 2'}}
1395 assert_response :success
1395 assert_response :success
1396 assert_template 'new'
1396 assert_template 'new'
1397
1397
1398 assert_tag :textarea, :attributes => { :name => 'issue[description]' },
1398 assert_tag :textarea, :attributes => { :name => 'issue[description]' },
1399 :content => 'This is a description'
1399 :content => 'This is a description'
1400 assert_tag :select, :attributes => { :name => 'issue[priority_id]' },
1400 assert_tag :select, :attributes => { :name => 'issue[priority_id]' },
1401 :child => { :tag => 'option', :attributes => { :selected => 'selected',
1401 :child => { :tag => 'option', :attributes => { :selected => 'selected',
1402 :value => '6' },
1402 :value => '6' },
1403 :content => 'High' }
1403 :content => 'High' }
1404 # Custom fields
1404 # Custom fields
1405 assert_tag :select, :attributes => { :name => 'issue[custom_field_values][1]' },
1405 assert_tag :select, :attributes => { :name => 'issue[custom_field_values][1]' },
1406 :child => { :tag => 'option', :attributes => { :selected => 'selected',
1406 :child => { :tag => 'option', :attributes => { :selected => 'selected',
1407 :value => 'Oracle' },
1407 :value => 'Oracle' },
1408 :content => 'Oracle' }
1408 :content => 'Oracle' }
1409 assert_tag :input, :attributes => { :name => 'issue[custom_field_values][2]',
1409 assert_tag :input, :attributes => { :name => 'issue[custom_field_values][2]',
1410 :value => 'Value for field 2'}
1410 :value => 'Value for field 2'}
1411 end
1411 end
1412
1412
1413 def test_post_create_should_ignore_non_safe_attributes
1413 def test_post_create_should_ignore_non_safe_attributes
1414 @request.session[:user_id] = 2
1414 @request.session[:user_id] = 2
1415 assert_nothing_raised do
1415 assert_nothing_raised do
1416 post :create, :project_id => 1, :issue => { :tracker => "A param can not be a Tracker" }
1416 post :create, :project_id => 1, :issue => { :tracker => "A param can not be a Tracker" }
1417 end
1417 end
1418 end
1418 end
1419
1419
1420 def test_post_create_with_attachment
1420 def test_post_create_with_attachment
1421 set_tmp_attachments_directory
1421 set_tmp_attachments_directory
1422 @request.session[:user_id] = 2
1422 @request.session[:user_id] = 2
1423
1423
1424 assert_difference 'Issue.count' do
1424 assert_difference 'Issue.count' do
1425 assert_difference 'Attachment.count' do
1425 assert_difference 'Attachment.count' do
1426 post :create, :project_id => 1,
1426 post :create, :project_id => 1,
1427 :issue => { :tracker_id => '1', :subject => 'With attachment' },
1427 :issue => { :tracker_id => '1', :subject => 'With attachment' },
1428 :attachments => {'1' => {'file' => uploaded_test_file('testfile.txt', 'text/plain'), 'description' => 'test file'}}
1428 :attachments => {'1' => {'file' => uploaded_test_file('testfile.txt', 'text/plain'), 'description' => 'test file'}}
1429 end
1429 end
1430 end
1430 end
1431
1431
1432 issue = Issue.first(:order => 'id DESC')
1432 issue = Issue.first(:order => 'id DESC')
1433 attachment = Attachment.first(:order => 'id DESC')
1433 attachment = Attachment.first(:order => 'id DESC')
1434
1434
1435 assert_equal issue, attachment.container
1435 assert_equal issue, attachment.container
1436 assert_equal 2, attachment.author_id
1436 assert_equal 2, attachment.author_id
1437 assert_equal 'testfile.txt', attachment.filename
1437 assert_equal 'testfile.txt', attachment.filename
1438 assert_equal 'text/plain', attachment.content_type
1438 assert_equal 'text/plain', attachment.content_type
1439 assert_equal 'test file', attachment.description
1439 assert_equal 'test file', attachment.description
1440 assert_equal 59, attachment.filesize
1440 assert_equal 59, attachment.filesize
1441 assert File.exists?(attachment.diskfile)
1441 assert File.exists?(attachment.diskfile)
1442 assert_equal 59, File.size(attachment.diskfile)
1442 assert_equal 59, File.size(attachment.diskfile)
1443 end
1443 end
1444
1444
1445 context "without workflow privilege" do
1445 context "without workflow privilege" do
1446 setup do
1446 setup do
1447 Workflow.delete_all(["role_id = ?", Role.anonymous.id])
1447 Workflow.delete_all(["role_id = ?", Role.anonymous.id])
1448 Role.anonymous.add_permission! :add_issues, :add_issue_notes
1448 Role.anonymous.add_permission! :add_issues, :add_issue_notes
1449 end
1449 end
1450
1450
1451 context "#new" do
1451 context "#new" do
1452 should "propose default status only" do
1452 should "propose default status only" do
1453 get :new, :project_id => 1
1453 get :new, :project_id => 1
1454 assert_response :success
1454 assert_response :success
1455 assert_template 'new'
1455 assert_template 'new'
1456 assert_tag :tag => 'select',
1456 assert_tag :tag => 'select',
1457 :attributes => {:name => 'issue[status_id]'},
1457 :attributes => {:name => 'issue[status_id]'},
1458 :children => {:count => 1},
1458 :children => {:count => 1},
1459 :child => {:tag => 'option', :attributes => {:value => IssueStatus.default.id.to_s}}
1459 :child => {:tag => 'option', :attributes => {:value => IssueStatus.default.id.to_s}}
1460 end
1460 end
1461
1461
1462 should "accept default status" do
1462 should "accept default status" do
1463 assert_difference 'Issue.count' do
1463 assert_difference 'Issue.count' do
1464 post :create, :project_id => 1,
1464 post :create, :project_id => 1,
1465 :issue => {:tracker_id => 1,
1465 :issue => {:tracker_id => 1,
1466 :subject => 'This is an issue',
1466 :subject => 'This is an issue',
1467 :status_id => 1}
1467 :status_id => 1}
1468 end
1468 end
1469 issue = Issue.last(:order => 'id')
1469 issue = Issue.last(:order => 'id')
1470 assert_equal IssueStatus.default, issue.status
1470 assert_equal IssueStatus.default, issue.status
1471 end
1471 end
1472
1472
1473 should "ignore unauthorized status" do
1473 should "ignore unauthorized status" do
1474 assert_difference 'Issue.count' do
1474 assert_difference 'Issue.count' do
1475 post :create, :project_id => 1,
1475 post :create, :project_id => 1,
1476 :issue => {:tracker_id => 1,
1476 :issue => {:tracker_id => 1,
1477 :subject => 'This is an issue',
1477 :subject => 'This is an issue',
1478 :status_id => 3}
1478 :status_id => 3}
1479 end
1479 end
1480 issue = Issue.last(:order => 'id')
1480 issue = Issue.last(:order => 'id')
1481 assert_equal IssueStatus.default, issue.status
1481 assert_equal IssueStatus.default, issue.status
1482 end
1482 end
1483 end
1483 end
1484
1484
1485 context "#update" do
1485 context "#update" do
1486 should "ignore status change" do
1486 should "ignore status change" do
1487 assert_difference 'Journal.count' do
1487 assert_difference 'Journal.count' do
1488 put :update, :id => 1, :notes => 'just trying', :issue => {:status_id => 3}
1488 put :update, :id => 1, :notes => 'just trying', :issue => {:status_id => 3}
1489 end
1489 end
1490 assert_equal 1, Issue.find(1).status_id
1490 assert_equal 1, Issue.find(1).status_id
1491 end
1491 end
1492
1492
1493 should "ignore attributes changes" do
1493 should "ignore attributes changes" do
1494 assert_difference 'Journal.count' do
1494 assert_difference 'Journal.count' do
1495 put :update, :id => 1, :notes => 'just trying', :issue => {:subject => 'changed', :assigned_to_id => 2}
1495 put :update, :id => 1, :notes => 'just trying', :issue => {:subject => 'changed', :assigned_to_id => 2}
1496 end
1496 end
1497 issue = Issue.find(1)
1497 issue = Issue.find(1)
1498 assert_equal "Can't print recipes", issue.subject
1498 assert_equal "Can't print recipes", issue.subject
1499 assert_nil issue.assigned_to
1499 assert_nil issue.assigned_to
1500 end
1500 end
1501 end
1501 end
1502 end
1502 end
1503
1503
1504 context "with workflow privilege" do
1504 context "with workflow privilege" do
1505 setup do
1505 setup do
1506 Workflow.delete_all(["role_id = ?", Role.anonymous.id])
1506 Workflow.delete_all(["role_id = ?", Role.anonymous.id])
1507 Workflow.create!(:role => Role.anonymous, :tracker_id => 1, :old_status_id => 1, :new_status_id => 3)
1507 Workflow.create!(:role => Role.anonymous, :tracker_id => 1, :old_status_id => 1, :new_status_id => 3)
1508 Workflow.create!(:role => Role.anonymous, :tracker_id => 1, :old_status_id => 1, :new_status_id => 4)
1508 Workflow.create!(:role => Role.anonymous, :tracker_id => 1, :old_status_id => 1, :new_status_id => 4)
1509 Role.anonymous.add_permission! :add_issues, :add_issue_notes
1509 Role.anonymous.add_permission! :add_issues, :add_issue_notes
1510 end
1510 end
1511
1511
1512 context "#update" do
1512 context "#update" do
1513 should "accept authorized status" do
1513 should "accept authorized status" do
1514 assert_difference 'Journal.count' do
1514 assert_difference 'Journal.count' do
1515 put :update, :id => 1, :notes => 'just trying', :issue => {:status_id => 3}
1515 put :update, :id => 1, :notes => 'just trying', :issue => {:status_id => 3}
1516 end
1516 end
1517 assert_equal 3, Issue.find(1).status_id
1517 assert_equal 3, Issue.find(1).status_id
1518 end
1518 end
1519
1519
1520 should "ignore unauthorized status" do
1520 should "ignore unauthorized status" do
1521 assert_difference 'Journal.count' do
1521 assert_difference 'Journal.count' do
1522 put :update, :id => 1, :notes => 'just trying', :issue => {:status_id => 2}
1522 put :update, :id => 1, :notes => 'just trying', :issue => {:status_id => 2}
1523 end
1523 end
1524 assert_equal 1, Issue.find(1).status_id
1524 assert_equal 1, Issue.find(1).status_id
1525 end
1525 end
1526
1526
1527 should "accept authorized attributes changes" do
1527 should "accept authorized attributes changes" do
1528 assert_difference 'Journal.count' do
1528 assert_difference 'Journal.count' do
1529 put :update, :id => 1, :notes => 'just trying', :issue => {:assigned_to_id => 2}
1529 put :update, :id => 1, :notes => 'just trying', :issue => {:assigned_to_id => 2}
1530 end
1530 end
1531 issue = Issue.find(1)
1531 issue = Issue.find(1)
1532 assert_equal 2, issue.assigned_to_id
1532 assert_equal 2, issue.assigned_to_id
1533 end
1533 end
1534
1534
1535 should "ignore unauthorized attributes changes" do
1535 should "ignore unauthorized attributes changes" do
1536 assert_difference 'Journal.count' do
1536 assert_difference 'Journal.count' do
1537 put :update, :id => 1, :notes => 'just trying', :issue => {:subject => 'changed'}
1537 put :update, :id => 1, :notes => 'just trying', :issue => {:subject => 'changed'}
1538 end
1538 end
1539 issue = Issue.find(1)
1539 issue = Issue.find(1)
1540 assert_equal "Can't print recipes", issue.subject
1540 assert_equal "Can't print recipes", issue.subject
1541 end
1541 end
1542 end
1542 end
1543
1543
1544 context "and :edit_issues permission" do
1544 context "and :edit_issues permission" do
1545 setup do
1545 setup do
1546 Role.anonymous.add_permission! :add_issues, :edit_issues
1546 Role.anonymous.add_permission! :add_issues, :edit_issues
1547 end
1547 end
1548
1548
1549 should "accept authorized status" do
1549 should "accept authorized status" do
1550 assert_difference 'Journal.count' do
1550 assert_difference 'Journal.count' do
1551 put :update, :id => 1, :notes => 'just trying', :issue => {:status_id => 3}
1551 put :update, :id => 1, :notes => 'just trying', :issue => {:status_id => 3}
1552 end
1552 end
1553 assert_equal 3, Issue.find(1).status_id
1553 assert_equal 3, Issue.find(1).status_id
1554 end
1554 end
1555
1555
1556 should "ignore unauthorized status" do
1556 should "ignore unauthorized status" do
1557 assert_difference 'Journal.count' do
1557 assert_difference 'Journal.count' do
1558 put :update, :id => 1, :notes => 'just trying', :issue => {:status_id => 2}
1558 put :update, :id => 1, :notes => 'just trying', :issue => {:status_id => 2}
1559 end
1559 end
1560 assert_equal 1, Issue.find(1).status_id
1560 assert_equal 1, Issue.find(1).status_id
1561 end
1561 end
1562
1562
1563 should "accept authorized attributes changes" do
1563 should "accept authorized attributes changes" do
1564 assert_difference 'Journal.count' do
1564 assert_difference 'Journal.count' do
1565 put :update, :id => 1, :notes => 'just trying', :issue => {:subject => 'changed', :assigned_to_id => 2}
1565 put :update, :id => 1, :notes => 'just trying', :issue => {:subject => 'changed', :assigned_to_id => 2}
1566 end
1566 end
1567 issue = Issue.find(1)
1567 issue = Issue.find(1)
1568 assert_equal "changed", issue.subject
1568 assert_equal "changed", issue.subject
1569 assert_equal 2, issue.assigned_to_id
1569 assert_equal 2, issue.assigned_to_id
1570 end
1570 end
1571 end
1571 end
1572 end
1572 end
1573
1573
1574 def test_copy_issue
1574 def test_copy_issue
1575 @request.session[:user_id] = 2
1575 @request.session[:user_id] = 2
1576 get :new, :project_id => 1, :copy_from => 1
1576 get :new, :project_id => 1, :copy_from => 1
1577 assert_template 'new'
1577 assert_template 'new'
1578 assert_not_nil assigns(:issue)
1578 assert_not_nil assigns(:issue)
1579 orig = Issue.find(1)
1579 orig = Issue.find(1)
1580 assert_equal orig.subject, assigns(:issue).subject
1580 assert_equal orig.subject, assigns(:issue).subject
1581 end
1581 end
1582
1582
1583 def test_get_edit
1583 def test_get_edit
1584 @request.session[:user_id] = 2
1584 @request.session[:user_id] = 2
1585 get :edit, :id => 1
1585 get :edit, :id => 1
1586 assert_response :success
1586 assert_response :success
1587 assert_template 'edit'
1587 assert_template 'edit'
1588 assert_not_nil assigns(:issue)
1588 assert_not_nil assigns(:issue)
1589 assert_equal Issue.find(1), assigns(:issue)
1589 assert_equal Issue.find(1), assigns(:issue)
1590
1590
1591 # Be sure we don't display inactive IssuePriorities
1591 # Be sure we don't display inactive IssuePriorities
1592 assert ! IssuePriority.find(15).active?
1592 assert ! IssuePriority.find(15).active?
1593 assert_no_tag :option, :attributes => {:value => '15'},
1593 assert_no_tag :option, :attributes => {:value => '15'},
1594 :parent => {:tag => 'select', :attributes => {:id => 'issue_priority_id'} }
1594 :parent => {:tag => 'select', :attributes => {:id => 'issue_priority_id'} }
1595 end
1595 end
1596
1596
1597 def test_get_edit_should_display_the_time_entry_form_with_log_time_permission
1597 def test_get_edit_should_display_the_time_entry_form_with_log_time_permission
1598 @request.session[:user_id] = 2
1598 @request.session[:user_id] = 2
1599 Role.find_by_name('Manager').update_attribute :permissions, [:view_issues, :edit_issues, :log_time]
1599 Role.find_by_name('Manager').update_attribute :permissions, [:view_issues, :edit_issues, :log_time]
1600
1600
1601 get :edit, :id => 1
1601 get :edit, :id => 1
1602 assert_tag 'input', :attributes => {:name => 'time_entry[hours]'}
1602 assert_tag 'input', :attributes => {:name => 'time_entry[hours]'}
1603 end
1603 end
1604
1604
1605 def test_get_edit_should_not_display_the_time_entry_form_without_log_time_permission
1605 def test_get_edit_should_not_display_the_time_entry_form_without_log_time_permission
1606 @request.session[:user_id] = 2
1606 @request.session[:user_id] = 2
1607 Role.find_by_name('Manager').remove_permission! :log_time
1607 Role.find_by_name('Manager').remove_permission! :log_time
1608
1608
1609 get :edit, :id => 1
1609 get :edit, :id => 1
1610 assert_no_tag 'input', :attributes => {:name => 'time_entry[hours]'}
1610 assert_no_tag 'input', :attributes => {:name => 'time_entry[hours]'}
1611 end
1611 end
1612
1612
1613 def test_get_edit_with_params
1613 def test_get_edit_with_params
1614 @request.session[:user_id] = 2
1614 @request.session[:user_id] = 2
1615 get :edit, :id => 1, :issue => { :status_id => 5, :priority_id => 7 },
1615 get :edit, :id => 1, :issue => { :status_id => 5, :priority_id => 7 },
1616 :time_entry => { :hours => '2.5', :comments => 'test_get_edit_with_params', :activity_id => TimeEntryActivity.first.id }
1616 :time_entry => { :hours => '2.5', :comments => 'test_get_edit_with_params', :activity_id => TimeEntryActivity.first.id }
1617 assert_response :success
1617 assert_response :success
1618 assert_template 'edit'
1618 assert_template 'edit'
1619
1619
1620 issue = assigns(:issue)
1620 issue = assigns(:issue)
1621 assert_not_nil issue
1621 assert_not_nil issue
1622
1622
1623 assert_equal 5, issue.status_id
1623 assert_equal 5, issue.status_id
1624 assert_tag :select, :attributes => { :name => 'issue[status_id]' },
1624 assert_tag :select, :attributes => { :name => 'issue[status_id]' },
1625 :child => { :tag => 'option',
1625 :child => { :tag => 'option',
1626 :content => 'Closed',
1626 :content => 'Closed',
1627 :attributes => { :selected => 'selected' } }
1627 :attributes => { :selected => 'selected' } }
1628
1628
1629 assert_equal 7, issue.priority_id
1629 assert_equal 7, issue.priority_id
1630 assert_tag :select, :attributes => { :name => 'issue[priority_id]' },
1630 assert_tag :select, :attributes => { :name => 'issue[priority_id]' },
1631 :child => { :tag => 'option',
1631 :child => { :tag => 'option',
1632 :content => 'Urgent',
1632 :content => 'Urgent',
1633 :attributes => { :selected => 'selected' } }
1633 :attributes => { :selected => 'selected' } }
1634
1634
1635 assert_tag :input, :attributes => { :name => 'time_entry[hours]', :value => '2.5' }
1635 assert_tag :input, :attributes => { :name => 'time_entry[hours]', :value => '2.5' }
1636 assert_tag :select, :attributes => { :name => 'time_entry[activity_id]' },
1636 assert_tag :select, :attributes => { :name => 'time_entry[activity_id]' },
1637 :child => { :tag => 'option',
1637 :child => { :tag => 'option',
1638 :attributes => { :selected => 'selected', :value => TimeEntryActivity.first.id } }
1638 :attributes => { :selected => 'selected', :value => TimeEntryActivity.first.id } }
1639 assert_tag :input, :attributes => { :name => 'time_entry[comments]', :value => 'test_get_edit_with_params' }
1639 assert_tag :input, :attributes => { :name => 'time_entry[comments]', :value => 'test_get_edit_with_params' }
1640 end
1640 end
1641
1641
1642 def test_update_edit_form
1642 def test_update_edit_form
1643 @request.session[:user_id] = 2
1643 @request.session[:user_id] = 2
1644 xhr :put, :new, :project_id => 1,
1644 xhr :put, :new, :project_id => 1,
1645 :id => 1,
1645 :id => 1,
1646 :issue => {:tracker_id => 2,
1646 :issue => {:tracker_id => 2,
1647 :subject => 'This is the test_new issue',
1647 :subject => 'This is the test_new issue',
1648 :description => 'This is the description',
1648 :description => 'This is the description',
1649 :priority_id => 5}
1649 :priority_id => 5}
1650 assert_response :success
1650 assert_response :success
1651 assert_template 'attributes'
1651 assert_template 'attributes'
1652
1652
1653 issue = assigns(:issue)
1653 issue = assigns(:issue)
1654 assert_kind_of Issue, issue
1654 assert_kind_of Issue, issue
1655 assert_equal 1, issue.id
1655 assert_equal 1, issue.id
1656 assert_equal 1, issue.project_id
1656 assert_equal 1, issue.project_id
1657 assert_equal 2, issue.tracker_id
1657 assert_equal 2, issue.tracker_id
1658 assert_equal 'This is the test_new issue', issue.subject
1658 assert_equal 'This is the test_new issue', issue.subject
1659 end
1659 end
1660
1660
1661 def test_update_edit_form_with_project_change
1661 def test_update_edit_form_with_project_change
1662 @request.session[:user_id] = 2
1662 @request.session[:user_id] = 2
1663 xhr :put, :new, :project_id => 1,
1663 xhr :put, :new, :project_id => 1,
1664 :id => 1,
1664 :id => 1,
1665 :project_change => '1',
1665 :project_change => '1',
1666 :issue => {:project_id => 2,
1666 :issue => {:project_id => 2,
1667 :tracker_id => 2,
1667 :tracker_id => 2,
1668 :subject => 'This is the test_new issue',
1668 :subject => 'This is the test_new issue',
1669 :description => 'This is the description',
1669 :description => 'This is the description',
1670 :priority_id => 5}
1670 :priority_id => 5}
1671 assert_response :success
1671 assert_response :success
1672 assert_template 'form'
1672 assert_template 'form'
1673
1673
1674 issue = assigns(:issue)
1674 issue = assigns(:issue)
1675 assert_kind_of Issue, issue
1675 assert_kind_of Issue, issue
1676 assert_equal 1, issue.id
1676 assert_equal 1, issue.id
1677 assert_equal 2, issue.project_id
1677 assert_equal 2, issue.project_id
1678 assert_equal 2, issue.tracker_id
1678 assert_equal 2, issue.tracker_id
1679 assert_equal 'This is the test_new issue', issue.subject
1679 assert_equal 'This is the test_new issue', issue.subject
1680 end
1680 end
1681
1681
1682 def test_update_using_invalid_http_verbs
1682 def test_update_using_invalid_http_verbs
1683 @request.session[:user_id] = 2
1683 @request.session[:user_id] = 2
1684 subject = 'Updated by an invalid http verb'
1684 subject = 'Updated by an invalid http verb'
1685
1685
1686 get :update, :id => 1, :issue => {:subject => subject}
1686 get :update, :id => 1, :issue => {:subject => subject}
1687 assert_not_equal subject, Issue.find(1).subject
1687 assert_not_equal subject, Issue.find(1).subject
1688
1688
1689 post :update, :id => 1, :issue => {:subject => subject}
1689 post :update, :id => 1, :issue => {:subject => subject}
1690 assert_not_equal subject, Issue.find(1).subject
1690 assert_not_equal subject, Issue.find(1).subject
1691
1691
1692 delete :update, :id => 1, :issue => {:subject => subject}
1692 delete :update, :id => 1, :issue => {:subject => subject}
1693 assert_not_equal subject, Issue.find(1).subject
1693 assert_not_equal subject, Issue.find(1).subject
1694 end
1694 end
1695
1695
1696 def test_put_update_without_custom_fields_param
1696 def test_put_update_without_custom_fields_param
1697 @request.session[:user_id] = 2
1697 @request.session[:user_id] = 2
1698 ActionMailer::Base.deliveries.clear
1698 ActionMailer::Base.deliveries.clear
1699
1699
1700 issue = Issue.find(1)
1700 issue = Issue.find(1)
1701 assert_equal '125', issue.custom_value_for(2).value
1701 assert_equal '125', issue.custom_value_for(2).value
1702 old_subject = issue.subject
1702 old_subject = issue.subject
1703 new_subject = 'Subject modified by IssuesControllerTest#test_post_edit'
1703 new_subject = 'Subject modified by IssuesControllerTest#test_post_edit'
1704
1704
1705 assert_difference('Journal.count') do
1705 assert_difference('Journal.count') do
1706 assert_difference('JournalDetail.count', 2) do
1706 assert_difference('JournalDetail.count', 2) do
1707 put :update, :id => 1, :issue => {:subject => new_subject,
1707 put :update, :id => 1, :issue => {:subject => new_subject,
1708 :priority_id => '6',
1708 :priority_id => '6',
1709 :category_id => '1' # no change
1709 :category_id => '1' # no change
1710 }
1710 }
1711 end
1711 end
1712 end
1712 end
1713 assert_redirected_to :action => 'show', :id => '1'
1713 assert_redirected_to :action => 'show', :id => '1'
1714 issue.reload
1714 issue.reload
1715 assert_equal new_subject, issue.subject
1715 assert_equal new_subject, issue.subject
1716 # Make sure custom fields were not cleared
1716 # Make sure custom fields were not cleared
1717 assert_equal '125', issue.custom_value_for(2).value
1717 assert_equal '125', issue.custom_value_for(2).value
1718
1718
1719 mail = ActionMailer::Base.deliveries.last
1719 mail = ActionMailer::Base.deliveries.last
1720 assert_kind_of TMail::Mail, mail
1720 assert_kind_of TMail::Mail, mail
1721 assert mail.subject.starts_with?("[#{issue.project.name} - #{issue.tracker.name} ##{issue.id}]")
1721 assert mail.subject.starts_with?("[#{issue.project.name} - #{issue.tracker.name} ##{issue.id}]")
1722 assert mail.body.include?("Subject changed from #{old_subject} to #{new_subject}")
1722 assert mail.body.include?("Subject changed from #{old_subject} to #{new_subject}")
1723 end
1723 end
1724
1724
1725 def test_put_update_with_project_change
1725 def test_put_update_with_project_change
1726 @request.session[:user_id] = 2
1726 @request.session[:user_id] = 2
1727 ActionMailer::Base.deliveries.clear
1727 ActionMailer::Base.deliveries.clear
1728
1728
1729 assert_difference('Journal.count') do
1729 assert_difference('Journal.count') do
1730 assert_difference('JournalDetail.count', 3) do
1730 assert_difference('JournalDetail.count', 3) do
1731 put :update, :id => 1, :issue => {:project_id => '2',
1731 put :update, :id => 1, :issue => {:project_id => '2',
1732 :tracker_id => '1', # no change
1732 :tracker_id => '1', # no change
1733 :priority_id => '6',
1733 :priority_id => '6',
1734 :category_id => '3'
1734 :category_id => '3'
1735 }
1735 }
1736 end
1736 end
1737 end
1737 end
1738 assert_redirected_to :action => 'show', :id => '1'
1738 assert_redirected_to :action => 'show', :id => '1'
1739 issue = Issue.find(1)
1739 issue = Issue.find(1)
1740 assert_equal 2, issue.project_id
1740 assert_equal 2, issue.project_id
1741 assert_equal 1, issue.tracker_id
1741 assert_equal 1, issue.tracker_id
1742 assert_equal 6, issue.priority_id
1742 assert_equal 6, issue.priority_id
1743 assert_equal 3, issue.category_id
1743 assert_equal 3, issue.category_id
1744
1744
1745 mail = ActionMailer::Base.deliveries.last
1745 mail = ActionMailer::Base.deliveries.last
1746 assert_not_nil mail
1746 assert_not_nil mail
1747 assert mail.subject.starts_with?("[#{issue.project.name} - #{issue.tracker.name} ##{issue.id}]")
1747 assert mail.subject.starts_with?("[#{issue.project.name} - #{issue.tracker.name} ##{issue.id}]")
1748 assert mail.body.include?("Project changed from eCookbook to OnlineStore")
1748 assert mail.body.include?("Project changed from eCookbook to OnlineStore")
1749 end
1749 end
1750
1750
1751 def test_put_update_with_tracker_change
1751 def test_put_update_with_tracker_change
1752 @request.session[:user_id] = 2
1752 @request.session[:user_id] = 2
1753 ActionMailer::Base.deliveries.clear
1753 ActionMailer::Base.deliveries.clear
1754
1754
1755 assert_difference('Journal.count') do
1755 assert_difference('Journal.count') do
1756 assert_difference('JournalDetail.count', 2) do
1756 assert_difference('JournalDetail.count', 2) do
1757 put :update, :id => 1, :issue => {:project_id => '1',
1757 put :update, :id => 1, :issue => {:project_id => '1',
1758 :tracker_id => '2',
1758 :tracker_id => '2',
1759 :priority_id => '6'
1759 :priority_id => '6'
1760 }
1760 }
1761 end
1761 end
1762 end
1762 end
1763 assert_redirected_to :action => 'show', :id => '1'
1763 assert_redirected_to :action => 'show', :id => '1'
1764 issue = Issue.find(1)
1764 issue = Issue.find(1)
1765 assert_equal 1, issue.project_id
1765 assert_equal 1, issue.project_id
1766 assert_equal 2, issue.tracker_id
1766 assert_equal 2, issue.tracker_id
1767 assert_equal 6, issue.priority_id
1767 assert_equal 6, issue.priority_id
1768 assert_equal 1, issue.category_id
1768 assert_equal 1, issue.category_id
1769
1769
1770 mail = ActionMailer::Base.deliveries.last
1770 mail = ActionMailer::Base.deliveries.last
1771 assert_not_nil mail
1771 assert_not_nil mail
1772 assert mail.subject.starts_with?("[#{issue.project.name} - #{issue.tracker.name} ##{issue.id}]")
1772 assert mail.subject.starts_with?("[#{issue.project.name} - #{issue.tracker.name} ##{issue.id}]")
1773 assert mail.body.include?("Tracker changed from Bug to Feature request")
1773 assert mail.body.include?("Tracker changed from Bug to Feature request")
1774 end
1774 end
1775
1775
1776 def test_put_update_with_custom_field_change
1776 def test_put_update_with_custom_field_change
1777 @request.session[:user_id] = 2
1777 @request.session[:user_id] = 2
1778 issue = Issue.find(1)
1778 issue = Issue.find(1)
1779 assert_equal '125', issue.custom_value_for(2).value
1779 assert_equal '125', issue.custom_value_for(2).value
1780
1780
1781 assert_difference('Journal.count') do
1781 assert_difference('Journal.count') do
1782 assert_difference('JournalDetail.count', 3) do
1782 assert_difference('JournalDetail.count', 3) do
1783 put :update, :id => 1, :issue => {:subject => 'Custom field change',
1783 put :update, :id => 1, :issue => {:subject => 'Custom field change',
1784 :priority_id => '6',
1784 :priority_id => '6',
1785 :category_id => '1', # no change
1785 :category_id => '1', # no change
1786 :custom_field_values => { '2' => 'New custom value' }
1786 :custom_field_values => { '2' => 'New custom value' }
1787 }
1787 }
1788 end
1788 end
1789 end
1789 end
1790 assert_redirected_to :action => 'show', :id => '1'
1790 assert_redirected_to :action => 'show', :id => '1'
1791 issue.reload
1791 issue.reload
1792 assert_equal 'New custom value', issue.custom_value_for(2).value
1792 assert_equal 'New custom value', issue.custom_value_for(2).value
1793
1793
1794 mail = ActionMailer::Base.deliveries.last
1794 mail = ActionMailer::Base.deliveries.last
1795 assert_kind_of TMail::Mail, mail
1795 assert_kind_of TMail::Mail, mail
1796 assert mail.body.include?("Searchable field changed from 125 to New custom value")
1796 assert mail.body.include?("Searchable field changed from 125 to New custom value")
1797 end
1797 end
1798
1798
1799 def test_put_update_with_status_and_assignee_change
1799 def test_put_update_with_status_and_assignee_change
1800 issue = Issue.find(1)
1800 issue = Issue.find(1)
1801 assert_equal 1, issue.status_id
1801 assert_equal 1, issue.status_id
1802 @request.session[:user_id] = 2
1802 @request.session[:user_id] = 2
1803 assert_difference('TimeEntry.count', 0) do
1803 assert_difference('TimeEntry.count', 0) do
1804 put :update,
1804 put :update,
1805 :id => 1,
1805 :id => 1,
1806 :issue => { :status_id => 2, :assigned_to_id => 3 },
1806 :issue => { :status_id => 2, :assigned_to_id => 3 },
1807 :notes => 'Assigned to dlopper',
1807 :notes => 'Assigned to dlopper',
1808 :time_entry => { :hours => '', :comments => '', :activity_id => TimeEntryActivity.first }
1808 :time_entry => { :hours => '', :comments => '', :activity_id => TimeEntryActivity.first }
1809 end
1809 end
1810 assert_redirected_to :action => 'show', :id => '1'
1810 assert_redirected_to :action => 'show', :id => '1'
1811 issue.reload
1811 issue.reload
1812 assert_equal 2, issue.status_id
1812 assert_equal 2, issue.status_id
1813 j = Journal.find(:first, :order => 'id DESC')
1813 j = Journal.find(:first, :order => 'id DESC')
1814 assert_equal 'Assigned to dlopper', j.notes
1814 assert_equal 'Assigned to dlopper', j.notes
1815 assert_equal 2, j.details.size
1815 assert_equal 2, j.details.size
1816
1816
1817 mail = ActionMailer::Base.deliveries.last
1817 mail = ActionMailer::Base.deliveries.last
1818 assert mail.body.include?("Status changed from New to Assigned")
1818 assert mail.body.include?("Status changed from New to Assigned")
1819 # subject should contain the new status
1819 # subject should contain the new status
1820 assert mail.subject.include?("(#{ IssueStatus.find(2).name })")
1820 assert mail.subject.include?("(#{ IssueStatus.find(2).name })")
1821 end
1821 end
1822
1822
1823 def test_put_update_with_note_only
1823 def test_put_update_with_note_only
1824 notes = 'Note added by IssuesControllerTest#test_update_with_note_only'
1824 notes = 'Note added by IssuesControllerTest#test_update_with_note_only'
1825 # anonymous user
1825 # anonymous user
1826 put :update,
1826 put :update,
1827 :id => 1,
1827 :id => 1,
1828 :notes => notes
1828 :notes => notes
1829 assert_redirected_to :action => 'show', :id => '1'
1829 assert_redirected_to :action => 'show', :id => '1'
1830 j = Journal.find(:first, :order => 'id DESC')
1830 j = Journal.find(:first, :order => 'id DESC')
1831 assert_equal notes, j.notes
1831 assert_equal notes, j.notes
1832 assert_equal 0, j.details.size
1832 assert_equal 0, j.details.size
1833 assert_equal User.anonymous, j.user
1833 assert_equal User.anonymous, j.user
1834
1834
1835 mail = ActionMailer::Base.deliveries.last
1835 mail = ActionMailer::Base.deliveries.last
1836 assert mail.body.include?(notes)
1836 assert mail.body.include?(notes)
1837 end
1837 end
1838
1838
1839 def test_put_update_with_note_and_spent_time
1839 def test_put_update_with_note_and_spent_time
1840 @request.session[:user_id] = 2
1840 @request.session[:user_id] = 2
1841 spent_hours_before = Issue.find(1).spent_hours
1841 spent_hours_before = Issue.find(1).spent_hours
1842 assert_difference('TimeEntry.count') do
1842 assert_difference('TimeEntry.count') do
1843 put :update,
1843 put :update,
1844 :id => 1,
1844 :id => 1,
1845 :notes => '2.5 hours added',
1845 :notes => '2.5 hours added',
1846 :time_entry => { :hours => '2.5', :comments => 'test_put_update_with_note_and_spent_time', :activity_id => TimeEntryActivity.first.id }
1846 :time_entry => { :hours => '2.5', :comments => 'test_put_update_with_note_and_spent_time', :activity_id => TimeEntryActivity.first.id }
1847 end
1847 end
1848 assert_redirected_to :action => 'show', :id => '1'
1848 assert_redirected_to :action => 'show', :id => '1'
1849
1849
1850 issue = Issue.find(1)
1850 issue = Issue.find(1)
1851
1851
1852 j = Journal.find(:first, :order => 'id DESC')
1852 j = Journal.find(:first, :order => 'id DESC')
1853 assert_equal '2.5 hours added', j.notes
1853 assert_equal '2.5 hours added', j.notes
1854 assert_equal 0, j.details.size
1854 assert_equal 0, j.details.size
1855
1855
1856 t = issue.time_entries.find_by_comments('test_put_update_with_note_and_spent_time')
1856 t = issue.time_entries.find_by_comments('test_put_update_with_note_and_spent_time')
1857 assert_not_nil t
1857 assert_not_nil t
1858 assert_equal 2.5, t.hours
1858 assert_equal 2.5, t.hours
1859 assert_equal spent_hours_before + 2.5, issue.spent_hours
1859 assert_equal spent_hours_before + 2.5, issue.spent_hours
1860 end
1860 end
1861
1861
1862 def test_put_update_with_attachment_only
1862 def test_put_update_with_attachment_only
1863 set_tmp_attachments_directory
1863 set_tmp_attachments_directory
1864
1864
1865 # Delete all fixtured journals, a race condition can occur causing the wrong
1865 # Delete all fixtured journals, a race condition can occur causing the wrong
1866 # journal to get fetched in the next find.
1866 # journal to get fetched in the next find.
1867 Journal.delete_all
1867 Journal.delete_all
1868
1868
1869 # anonymous user
1869 # anonymous user
1870 assert_difference 'Attachment.count' do
1870 assert_difference 'Attachment.count' do
1871 put :update, :id => 1,
1871 put :update, :id => 1,
1872 :notes => '',
1872 :notes => '',
1873 :attachments => {'1' => {'file' => uploaded_test_file('testfile.txt', 'text/plain'), 'description' => 'test file'}}
1873 :attachments => {'1' => {'file' => uploaded_test_file('testfile.txt', 'text/plain'), 'description' => 'test file'}}
1874 end
1874 end
1875
1875
1876 assert_redirected_to :action => 'show', :id => '1'
1876 assert_redirected_to :action => 'show', :id => '1'
1877 j = Issue.find(1).journals.find(:first, :order => 'id DESC')
1877 j = Issue.find(1).journals.find(:first, :order => 'id DESC')
1878 assert j.notes.blank?
1878 assert j.notes.blank?
1879 assert_equal 1, j.details.size
1879 assert_equal 1, j.details.size
1880 assert_equal 'testfile.txt', j.details.first.value
1880 assert_equal 'testfile.txt', j.details.first.value
1881 assert_equal User.anonymous, j.user
1881 assert_equal User.anonymous, j.user
1882
1882
1883 attachment = Attachment.first(:order => 'id DESC')
1883 attachment = Attachment.first(:order => 'id DESC')
1884 assert_equal Issue.find(1), attachment.container
1884 assert_equal Issue.find(1), attachment.container
1885 assert_equal User.anonymous, attachment.author
1885 assert_equal User.anonymous, attachment.author
1886 assert_equal 'testfile.txt', attachment.filename
1886 assert_equal 'testfile.txt', attachment.filename
1887 assert_equal 'text/plain', attachment.content_type
1887 assert_equal 'text/plain', attachment.content_type
1888 assert_equal 'test file', attachment.description
1888 assert_equal 'test file', attachment.description
1889 assert_equal 59, attachment.filesize
1889 assert_equal 59, attachment.filesize
1890 assert File.exists?(attachment.diskfile)
1890 assert File.exists?(attachment.diskfile)
1891 assert_equal 59, File.size(attachment.diskfile)
1891 assert_equal 59, File.size(attachment.diskfile)
1892
1892
1893 mail = ActionMailer::Base.deliveries.last
1893 mail = ActionMailer::Base.deliveries.last
1894 assert mail.body.include?('testfile.txt')
1894 assert mail.body.include?('testfile.txt')
1895 end
1895 end
1896
1896
1897 def test_put_update_with_attachment_that_fails_to_save
1897 def test_put_update_with_attachment_that_fails_to_save
1898 set_tmp_attachments_directory
1898 set_tmp_attachments_directory
1899
1899
1900 # Delete all fixtured journals, a race condition can occur causing the wrong
1900 # Delete all fixtured journals, a race condition can occur causing the wrong
1901 # journal to get fetched in the next find.
1901 # journal to get fetched in the next find.
1902 Journal.delete_all
1902 Journal.delete_all
1903
1903
1904 # Mock out the unsaved attachment
1904 # Mock out the unsaved attachment
1905 Attachment.any_instance.stubs(:create).returns(Attachment.new)
1905 Attachment.any_instance.stubs(:create).returns(Attachment.new)
1906
1906
1907 # anonymous user
1907 # anonymous user
1908 put :update,
1908 put :update,
1909 :id => 1,
1909 :id => 1,
1910 :notes => '',
1910 :notes => '',
1911 :attachments => {'1' => {'file' => uploaded_test_file('testfile.txt', 'text/plain')}}
1911 :attachments => {'1' => {'file' => uploaded_test_file('testfile.txt', 'text/plain')}}
1912 assert_redirected_to :action => 'show', :id => '1'
1912 assert_redirected_to :action => 'show', :id => '1'
1913 assert_equal '1 file(s) could not be saved.', flash[:warning]
1913 assert_equal '1 file(s) could not be saved.', flash[:warning]
1914
1914
1915 end if Object.const_defined?(:Mocha)
1915 end if Object.const_defined?(:Mocha)
1916
1916
1917 def test_put_update_with_no_change
1917 def test_put_update_with_no_change
1918 issue = Issue.find(1)
1918 issue = Issue.find(1)
1919 issue.journals.clear
1919 issue.journals.clear
1920 ActionMailer::Base.deliveries.clear
1920 ActionMailer::Base.deliveries.clear
1921
1921
1922 put :update,
1922 put :update,
1923 :id => 1,
1923 :id => 1,
1924 :notes => ''
1924 :notes => ''
1925 assert_redirected_to :action => 'show', :id => '1'
1925 assert_redirected_to :action => 'show', :id => '1'
1926
1926
1927 issue.reload
1927 issue.reload
1928 assert issue.journals.empty?
1928 assert issue.journals.empty?
1929 # No email should be sent
1929 # No email should be sent
1930 assert ActionMailer::Base.deliveries.empty?
1930 assert ActionMailer::Base.deliveries.empty?
1931 end
1931 end
1932
1932
1933 def test_put_update_should_send_a_notification
1933 def test_put_update_should_send_a_notification
1934 @request.session[:user_id] = 2
1934 @request.session[:user_id] = 2
1935 ActionMailer::Base.deliveries.clear
1935 ActionMailer::Base.deliveries.clear
1936 issue = Issue.find(1)
1936 issue = Issue.find(1)
1937 old_subject = issue.subject
1937 old_subject = issue.subject
1938 new_subject = 'Subject modified by IssuesControllerTest#test_post_edit'
1938 new_subject = 'Subject modified by IssuesControllerTest#test_post_edit'
1939
1939
1940 put :update, :id => 1, :issue => {:subject => new_subject,
1940 put :update, :id => 1, :issue => {:subject => new_subject,
1941 :priority_id => '6',
1941 :priority_id => '6',
1942 :category_id => '1' # no change
1942 :category_id => '1' # no change
1943 }
1943 }
1944 assert_equal 1, ActionMailer::Base.deliveries.size
1944 assert_equal 1, ActionMailer::Base.deliveries.size
1945 end
1945 end
1946
1946
1947 def test_put_update_with_invalid_spent_time_hours_only
1947 def test_put_update_with_invalid_spent_time_hours_only
1948 @request.session[:user_id] = 2
1948 @request.session[:user_id] = 2
1949 notes = 'Note added by IssuesControllerTest#test_post_edit_with_invalid_spent_time'
1949 notes = 'Note added by IssuesControllerTest#test_post_edit_with_invalid_spent_time'
1950
1950
1951 assert_no_difference('Journal.count') do
1951 assert_no_difference('Journal.count') do
1952 put :update,
1952 put :update,
1953 :id => 1,
1953 :id => 1,
1954 :notes => notes,
1954 :notes => notes,
1955 :time_entry => {"comments"=>"", "activity_id"=>"", "hours"=>"2z"}
1955 :time_entry => {"comments"=>"", "activity_id"=>"", "hours"=>"2z"}
1956 end
1956 end
1957 assert_response :success
1957 assert_response :success
1958 assert_template 'edit'
1958 assert_template 'edit'
1959
1959
1960 assert_error_tag :descendant => {:content => /Activity can't be blank/}
1960 assert_error_tag :descendant => {:content => /Activity can't be blank/}
1961 assert_tag :textarea, :attributes => { :name => 'notes' }, :content => notes
1961 assert_tag :textarea, :attributes => { :name => 'notes' }, :content => notes
1962 assert_tag :input, :attributes => { :name => 'time_entry[hours]', :value => "2z" }
1962 assert_tag :input, :attributes => { :name => 'time_entry[hours]', :value => "2z" }
1963 end
1963 end
1964
1964
1965 def test_put_update_with_invalid_spent_time_comments_only
1965 def test_put_update_with_invalid_spent_time_comments_only
1966 @request.session[:user_id] = 2
1966 @request.session[:user_id] = 2
1967 notes = 'Note added by IssuesControllerTest#test_post_edit_with_invalid_spent_time'
1967 notes = 'Note added by IssuesControllerTest#test_post_edit_with_invalid_spent_time'
1968
1968
1969 assert_no_difference('Journal.count') do
1969 assert_no_difference('Journal.count') do
1970 put :update,
1970 put :update,
1971 :id => 1,
1971 :id => 1,
1972 :notes => notes,
1972 :notes => notes,
1973 :time_entry => {"comments"=>"this is my comment", "activity_id"=>"", "hours"=>""}
1973 :time_entry => {"comments"=>"this is my comment", "activity_id"=>"", "hours"=>""}
1974 end
1974 end
1975 assert_response :success
1975 assert_response :success
1976 assert_template 'edit'
1976 assert_template 'edit'
1977
1977
1978 assert_error_tag :descendant => {:content => /Activity can't be blank/}
1978 assert_error_tag :descendant => {:content => /Activity can't be blank/}
1979 assert_error_tag :descendant => {:content => /Hours can't be blank/}
1979 assert_error_tag :descendant => {:content => /Hours can't be blank/}
1980 assert_tag :textarea, :attributes => { :name => 'notes' }, :content => notes
1980 assert_tag :textarea, :attributes => { :name => 'notes' }, :content => notes
1981 assert_tag :input, :attributes => { :name => 'time_entry[comments]', :value => "this is my comment" }
1981 assert_tag :input, :attributes => { :name => 'time_entry[comments]', :value => "this is my comment" }
1982 end
1982 end
1983
1983
1984 def test_put_update_should_allow_fixed_version_to_be_set_to_a_subproject
1984 def test_put_update_should_allow_fixed_version_to_be_set_to_a_subproject
1985 issue = Issue.find(2)
1985 issue = Issue.find(2)
1986 @request.session[:user_id] = 2
1986 @request.session[:user_id] = 2
1987
1987
1988 put :update,
1988 put :update,
1989 :id => issue.id,
1989 :id => issue.id,
1990 :issue => {
1990 :issue => {
1991 :fixed_version_id => 4
1991 :fixed_version_id => 4
1992 }
1992 }
1993
1993
1994 assert_response :redirect
1994 assert_response :redirect
1995 issue.reload
1995 issue.reload
1996 assert_equal 4, issue.fixed_version_id
1996 assert_equal 4, issue.fixed_version_id
1997 assert_not_equal issue.project_id, issue.fixed_version.project_id
1997 assert_not_equal issue.project_id, issue.fixed_version.project_id
1998 end
1998 end
1999
1999
2000 def test_put_update_should_redirect_back_using_the_back_url_parameter
2000 def test_put_update_should_redirect_back_using_the_back_url_parameter
2001 issue = Issue.find(2)
2001 issue = Issue.find(2)
2002 @request.session[:user_id] = 2
2002 @request.session[:user_id] = 2
2003
2003
2004 put :update,
2004 put :update,
2005 :id => issue.id,
2005 :id => issue.id,
2006 :issue => {
2006 :issue => {
2007 :fixed_version_id => 4
2007 :fixed_version_id => 4
2008 },
2008 },
2009 :back_url => '/issues'
2009 :back_url => '/issues'
2010
2010
2011 assert_response :redirect
2011 assert_response :redirect
2012 assert_redirected_to '/issues'
2012 assert_redirected_to '/issues'
2013 end
2013 end
2014
2014
2015 def test_put_update_should_not_redirect_back_using_the_back_url_parameter_off_the_host
2015 def test_put_update_should_not_redirect_back_using_the_back_url_parameter_off_the_host
2016 issue = Issue.find(2)
2016 issue = Issue.find(2)
2017 @request.session[:user_id] = 2
2017 @request.session[:user_id] = 2
2018
2018
2019 put :update,
2019 put :update,
2020 :id => issue.id,
2020 :id => issue.id,
2021 :issue => {
2021 :issue => {
2022 :fixed_version_id => 4
2022 :fixed_version_id => 4
2023 },
2023 },
2024 :back_url => 'http://google.com'
2024 :back_url => 'http://google.com'
2025
2025
2026 assert_response :redirect
2026 assert_response :redirect
2027 assert_redirected_to :controller => 'issues', :action => 'show', :id => issue.id
2027 assert_redirected_to :controller => 'issues', :action => 'show', :id => issue.id
2028 end
2028 end
2029
2029
2030 def test_get_bulk_edit
2030 def test_get_bulk_edit
2031 @request.session[:user_id] = 2
2031 @request.session[:user_id] = 2
2032 get :bulk_edit, :ids => [1, 2]
2032 get :bulk_edit, :ids => [1, 2]
2033 assert_response :success
2033 assert_response :success
2034 assert_template 'bulk_edit'
2034 assert_template 'bulk_edit'
2035
2035
2036 assert_tag :select, :attributes => {:name => 'issue[project_id]'}
2036 assert_tag :select, :attributes => {:name => 'issue[project_id]'}
2037 assert_tag :input, :attributes => {:name => 'issue[parent_issue_id]'}
2037 assert_tag :input, :attributes => {:name => 'issue[parent_issue_id]'}
2038
2038
2039 # Project specific custom field, date type
2039 # Project specific custom field, date type
2040 field = CustomField.find(9)
2040 field = CustomField.find(9)
2041 assert !field.is_for_all?
2041 assert !field.is_for_all?
2042 assert_equal 'date', field.field_format
2042 assert_equal 'date', field.field_format
2043 assert_tag :input, :attributes => {:name => 'issue[custom_field_values][9]'}
2043 assert_tag :input, :attributes => {:name => 'issue[custom_field_values][9]'}
2044
2044
2045 # System wide custom field
2045 # System wide custom field
2046 assert CustomField.find(1).is_for_all?
2046 assert CustomField.find(1).is_for_all?
2047 assert_tag :select, :attributes => {:name => 'issue[custom_field_values][1]'}
2047 assert_tag :select, :attributes => {:name => 'issue[custom_field_values][1]'}
2048
2048
2049 # Be sure we don't display inactive IssuePriorities
2049 # Be sure we don't display inactive IssuePriorities
2050 assert ! IssuePriority.find(15).active?
2050 assert ! IssuePriority.find(15).active?
2051 assert_no_tag :option, :attributes => {:value => '15'},
2051 assert_no_tag :option, :attributes => {:value => '15'},
2052 :parent => {:tag => 'select', :attributes => {:id => 'issue_priority_id'} }
2052 :parent => {:tag => 'select', :attributes => {:id => 'issue_priority_id'} }
2053 end
2053 end
2054
2054
2055 def test_get_bulk_edit_on_different_projects
2055 def test_get_bulk_edit_on_different_projects
2056 @request.session[:user_id] = 2
2056 @request.session[:user_id] = 2
2057 get :bulk_edit, :ids => [1, 2, 6]
2057 get :bulk_edit, :ids => [1, 2, 6]
2058 assert_response :success
2058 assert_response :success
2059 assert_template 'bulk_edit'
2059 assert_template 'bulk_edit'
2060
2060
2061 # Can not set issues from different projects as children of an issue
2061 # Can not set issues from different projects as children of an issue
2062 assert_no_tag :input, :attributes => {:name => 'issue[parent_issue_id]'}
2062 assert_no_tag :input, :attributes => {:name => 'issue[parent_issue_id]'}
2063
2063
2064 # Project specific custom field, date type
2064 # Project specific custom field, date type
2065 field = CustomField.find(9)
2065 field = CustomField.find(9)
2066 assert !field.is_for_all?
2066 assert !field.is_for_all?
2067 assert !field.project_ids.include?(Issue.find(6).project_id)
2067 assert !field.project_ids.include?(Issue.find(6).project_id)
2068 assert_no_tag :input, :attributes => {:name => 'issue[custom_field_values][9]'}
2068 assert_no_tag :input, :attributes => {:name => 'issue[custom_field_values][9]'}
2069 end
2069 end
2070
2070
2071 def test_get_bulk_edit_with_user_custom_field
2071 def test_get_bulk_edit_with_user_custom_field
2072 field = IssueCustomField.create!(:name => 'Tester', :field_format => 'user', :is_for_all => true)
2072 field = IssueCustomField.create!(:name => 'Tester', :field_format => 'user', :is_for_all => true)
2073
2073
2074 @request.session[:user_id] = 2
2074 @request.session[:user_id] = 2
2075 get :bulk_edit, :ids => [1, 2]
2075 get :bulk_edit, :ids => [1, 2]
2076 assert_response :success
2076 assert_response :success
2077 assert_template 'bulk_edit'
2077 assert_template 'bulk_edit'
2078
2078
2079 assert_tag :select,
2079 assert_tag :select,
2080 :attributes => {:name => "issue[custom_field_values][#{field.id}]"},
2080 :attributes => {:name => "issue[custom_field_values][#{field.id}]"},
2081 :children => {
2081 :children => {
2082 :only => {:tag => 'option'},
2082 :only => {:tag => 'option'},
2083 :count => Project.find(1).users.count + 1
2083 :count => Project.find(1).users.count + 1
2084 }
2084 }
2085 end
2085 end
2086
2086
2087 def test_get_bulk_edit_with_version_custom_field
2087 def test_get_bulk_edit_with_version_custom_field
2088 field = IssueCustomField.create!(:name => 'Affected version', :field_format => 'version', :is_for_all => true)
2088 field = IssueCustomField.create!(:name => 'Affected version', :field_format => 'version', :is_for_all => true)
2089
2089
2090 @request.session[:user_id] = 2
2090 @request.session[:user_id] = 2
2091 get :bulk_edit, :ids => [1, 2]
2091 get :bulk_edit, :ids => [1, 2]
2092 assert_response :success
2092 assert_response :success
2093 assert_template 'bulk_edit'
2093 assert_template 'bulk_edit'
2094
2094
2095 assert_tag :select,
2095 assert_tag :select,
2096 :attributes => {:name => "issue[custom_field_values][#{field.id}]"},
2096 :attributes => {:name => "issue[custom_field_values][#{field.id}]"},
2097 :children => {
2097 :children => {
2098 :only => {:tag => 'option'},
2098 :only => {:tag => 'option'},
2099 :count => Project.find(1).shared_versions.count + 1
2099 :count => Project.find(1).shared_versions.count + 1
2100 }
2100 }
2101 end
2101 end
2102
2102
2103 def test_bulk_update
2103 def test_bulk_update
2104 @request.session[:user_id] = 2
2104 @request.session[:user_id] = 2
2105 # update issues priority
2105 # update issues priority
2106 post :bulk_update, :ids => [1, 2], :notes => 'Bulk editing',
2106 post :bulk_update, :ids => [1, 2], :notes => 'Bulk editing',
2107 :issue => {:priority_id => 7,
2107 :issue => {:priority_id => 7,
2108 :assigned_to_id => '',
2108 :assigned_to_id => '',
2109 :custom_field_values => {'2' => ''}}
2109 :custom_field_values => {'2' => ''}}
2110
2110
2111 assert_response 302
2111 assert_response 302
2112 # check that the issues were updated
2112 # check that the issues were updated
2113 assert_equal [7, 7], Issue.find_all_by_id([1, 2]).collect {|i| i.priority.id}
2113 assert_equal [7, 7], Issue.find_all_by_id([1, 2]).collect {|i| i.priority.id}
2114
2114
2115 issue = Issue.find(1)
2115 issue = Issue.find(1)
2116 journal = issue.journals.find(:first, :order => 'created_on DESC')
2116 journal = issue.journals.find(:first, :order => 'created_on DESC')
2117 assert_equal '125', issue.custom_value_for(2).value
2117 assert_equal '125', issue.custom_value_for(2).value
2118 assert_equal 'Bulk editing', journal.notes
2118 assert_equal 'Bulk editing', journal.notes
2119 assert_equal 1, journal.details.size
2119 assert_equal 1, journal.details.size
2120 end
2120 end
2121
2121
2122 def test_bulk_update_with_group_assignee
2122 def test_bulk_update_with_group_assignee
2123 group = Group.find(11)
2123 group = Group.find(11)
2124 project = Project.find(1)
2124 project = Project.find(1)
2125 project.members << Member.new(:principal => group, :roles => [Role.first])
2125 project.members << Member.new(:principal => group, :roles => [Role.first])
2126
2126
2127 @request.session[:user_id] = 2
2127 @request.session[:user_id] = 2
2128 # update issues assignee
2128 # update issues assignee
2129 post :bulk_update, :ids => [1, 2], :notes => 'Bulk editing',
2129 post :bulk_update, :ids => [1, 2], :notes => 'Bulk editing',
2130 :issue => {:priority_id => '',
2130 :issue => {:priority_id => '',
2131 :assigned_to_id => group.id,
2131 :assigned_to_id => group.id,
2132 :custom_field_values => {'2' => ''}}
2132 :custom_field_values => {'2' => ''}}
2133
2133
2134 assert_response 302
2134 assert_response 302
2135 assert_equal [group, group], Issue.find_all_by_id([1, 2]).collect {|i| i.assigned_to}
2135 assert_equal [group, group], Issue.find_all_by_id([1, 2]).collect {|i| i.assigned_to}
2136 end
2136 end
2137
2137
2138 def test_bulk_update_on_different_projects
2138 def test_bulk_update_on_different_projects
2139 @request.session[:user_id] = 2
2139 @request.session[:user_id] = 2
2140 # update issues priority
2140 # update issues priority
2141 post :bulk_update, :ids => [1, 2, 6], :notes => 'Bulk editing',
2141 post :bulk_update, :ids => [1, 2, 6], :notes => 'Bulk editing',
2142 :issue => {:priority_id => 7,
2142 :issue => {:priority_id => 7,
2143 :assigned_to_id => '',
2143 :assigned_to_id => '',
2144 :custom_field_values => {'2' => ''}}
2144 :custom_field_values => {'2' => ''}}
2145
2145
2146 assert_response 302
2146 assert_response 302
2147 # check that the issues were updated
2147 # check that the issues were updated
2148 assert_equal [7, 7, 7], Issue.find([1,2,6]).map(&:priority_id)
2148 assert_equal [7, 7, 7], Issue.find([1,2,6]).map(&:priority_id)
2149
2149
2150 issue = Issue.find(1)
2150 issue = Issue.find(1)
2151 journal = issue.journals.find(:first, :order => 'created_on DESC')
2151 journal = issue.journals.find(:first, :order => 'created_on DESC')
2152 assert_equal '125', issue.custom_value_for(2).value
2152 assert_equal '125', issue.custom_value_for(2).value
2153 assert_equal 'Bulk editing', journal.notes
2153 assert_equal 'Bulk editing', journal.notes
2154 assert_equal 1, journal.details.size
2154 assert_equal 1, journal.details.size
2155 end
2155 end
2156
2156
2157 def test_bulk_update_on_different_projects_without_rights
2157 def test_bulk_update_on_different_projects_without_rights
2158 @request.session[:user_id] = 3
2158 @request.session[:user_id] = 3
2159 user = User.find(3)
2159 user = User.find(3)
2160 action = { :controller => "issues", :action => "bulk_update" }
2160 action = { :controller => "issues", :action => "bulk_update" }
2161 assert user.allowed_to?(action, Issue.find(1).project)
2161 assert user.allowed_to?(action, Issue.find(1).project)
2162 assert ! user.allowed_to?(action, Issue.find(6).project)
2162 assert ! user.allowed_to?(action, Issue.find(6).project)
2163 post :bulk_update, :ids => [1, 6], :notes => 'Bulk should fail',
2163 post :bulk_update, :ids => [1, 6], :notes => 'Bulk should fail',
2164 :issue => {:priority_id => 7,
2164 :issue => {:priority_id => 7,
2165 :assigned_to_id => '',
2165 :assigned_to_id => '',
2166 :custom_field_values => {'2' => ''}}
2166 :custom_field_values => {'2' => ''}}
2167 assert_response 403
2167 assert_response 403
2168 assert_not_equal "Bulk should fail", Journal.last.notes
2168 assert_not_equal "Bulk should fail", Journal.last.notes
2169 end
2169 end
2170
2170
2171 def test_bullk_update_should_send_a_notification
2171 def test_bullk_update_should_send_a_notification
2172 @request.session[:user_id] = 2
2172 @request.session[:user_id] = 2
2173 ActionMailer::Base.deliveries.clear
2173 ActionMailer::Base.deliveries.clear
2174 post(:bulk_update,
2174 post(:bulk_update,
2175 {
2175 {
2176 :ids => [1, 2],
2176 :ids => [1, 2],
2177 :notes => 'Bulk editing',
2177 :notes => 'Bulk editing',
2178 :issue => {
2178 :issue => {
2179 :priority_id => 7,
2179 :priority_id => 7,
2180 :assigned_to_id => '',
2180 :assigned_to_id => '',
2181 :custom_field_values => {'2' => ''}
2181 :custom_field_values => {'2' => ''}
2182 }
2182 }
2183 })
2183 })
2184
2184
2185 assert_response 302
2185 assert_response 302
2186 assert_equal 2, ActionMailer::Base.deliveries.size
2186 assert_equal 2, ActionMailer::Base.deliveries.size
2187 end
2187 end
2188
2188
2189 def test_bulk_update_project
2189 def test_bulk_update_project
2190 @request.session[:user_id] = 2
2190 @request.session[:user_id] = 2
2191 post :bulk_update, :ids => [1, 2], :issue => {:project_id => '2'}
2191 post :bulk_update, :ids => [1, 2], :issue => {:project_id => '2'}
2192 assert_redirected_to :controller => 'issues', :action => 'index', :project_id => 'ecookbook'
2192 assert_redirected_to :controller => 'issues', :action => 'index', :project_id => 'ecookbook'
2193 # Issues moved to project 2
2193 # Issues moved to project 2
2194 assert_equal 2, Issue.find(1).project_id
2194 assert_equal 2, Issue.find(1).project_id
2195 assert_equal 2, Issue.find(2).project_id
2195 assert_equal 2, Issue.find(2).project_id
2196 # No tracker change
2196 # No tracker change
2197 assert_equal 1, Issue.find(1).tracker_id
2197 assert_equal 1, Issue.find(1).tracker_id
2198 assert_equal 2, Issue.find(2).tracker_id
2198 assert_equal 2, Issue.find(2).tracker_id
2199 end
2199 end
2200
2200
2201 def test_bulk_update_project_on_single_issue_should_follow_when_needed
2201 def test_bulk_update_project_on_single_issue_should_follow_when_needed
2202 @request.session[:user_id] = 2
2202 @request.session[:user_id] = 2
2203 post :bulk_update, :id => 1, :issue => {:project_id => '2'}, :follow => '1'
2203 post :bulk_update, :id => 1, :issue => {:project_id => '2'}, :follow => '1'
2204 assert_redirected_to '/issues/1'
2204 assert_redirected_to '/issues/1'
2205 end
2205 end
2206
2206
2207 def test_bulk_update_project_on_multiple_issues_should_follow_when_needed
2207 def test_bulk_update_project_on_multiple_issues_should_follow_when_needed
2208 @request.session[:user_id] = 2
2208 @request.session[:user_id] = 2
2209 post :bulk_update, :id => [1, 2], :issue => {:project_id => '2'}, :follow => '1'
2209 post :bulk_update, :id => [1, 2], :issue => {:project_id => '2'}, :follow => '1'
2210 assert_redirected_to '/projects/onlinestore/issues'
2210 assert_redirected_to '/projects/onlinestore/issues'
2211 end
2211 end
2212
2212
2213 def test_bulk_update_tracker
2213 def test_bulk_update_tracker
2214 @request.session[:user_id] = 2
2214 @request.session[:user_id] = 2
2215 post :bulk_update, :ids => [1, 2], :issue => {:tracker_id => '2'}
2215 post :bulk_update, :ids => [1, 2], :issue => {:tracker_id => '2'}
2216 assert_redirected_to :controller => 'issues', :action => 'index', :project_id => 'ecookbook'
2216 assert_redirected_to :controller => 'issues', :action => 'index', :project_id => 'ecookbook'
2217 assert_equal 2, Issue.find(1).tracker_id
2217 assert_equal 2, Issue.find(1).tracker_id
2218 assert_equal 2, Issue.find(2).tracker_id
2218 assert_equal 2, Issue.find(2).tracker_id
2219 end
2219 end
2220
2220
2221 def test_bulk_update_status
2221 def test_bulk_update_status
2222 @request.session[:user_id] = 2
2222 @request.session[:user_id] = 2
2223 # update issues priority
2223 # update issues priority
2224 post :bulk_update, :ids => [1, 2], :notes => 'Bulk editing status',
2224 post :bulk_update, :ids => [1, 2], :notes => 'Bulk editing status',
2225 :issue => {:priority_id => '',
2225 :issue => {:priority_id => '',
2226 :assigned_to_id => '',
2226 :assigned_to_id => '',
2227 :status_id => '5'}
2227 :status_id => '5'}
2228
2228
2229 assert_response 302
2229 assert_response 302
2230 issue = Issue.find(1)
2230 issue = Issue.find(1)
2231 assert issue.closed?
2231 assert issue.closed?
2232 end
2232 end
2233
2233
2234 def test_bulk_update_priority
2234 def test_bulk_update_priority
2235 @request.session[:user_id] = 2
2235 @request.session[:user_id] = 2
2236 post :bulk_update, :ids => [1, 2], :issue => {:priority_id => 6}
2236 post :bulk_update, :ids => [1, 2], :issue => {:priority_id => 6}
2237
2237
2238 assert_redirected_to :controller => 'issues', :action => 'index', :project_id => 'ecookbook'
2238 assert_redirected_to :controller => 'issues', :action => 'index', :project_id => 'ecookbook'
2239 assert_equal 6, Issue.find(1).priority_id
2239 assert_equal 6, Issue.find(1).priority_id
2240 assert_equal 6, Issue.find(2).priority_id
2240 assert_equal 6, Issue.find(2).priority_id
2241 end
2241 end
2242
2242
2243 def test_bulk_update_with_notes
2243 def test_bulk_update_with_notes
2244 @request.session[:user_id] = 2
2244 @request.session[:user_id] = 2
2245 post :bulk_update, :ids => [1, 2], :notes => 'Moving two issues'
2245 post :bulk_update, :ids => [1, 2], :notes => 'Moving two issues'
2246
2246
2247 assert_redirected_to :controller => 'issues', :action => 'index', :project_id => 'ecookbook'
2247 assert_redirected_to :controller => 'issues', :action => 'index', :project_id => 'ecookbook'
2248 assert_equal 'Moving two issues', Issue.find(1).journals.sort_by(&:id).last.notes
2248 assert_equal 'Moving two issues', Issue.find(1).journals.sort_by(&:id).last.notes
2249 assert_equal 'Moving two issues', Issue.find(2).journals.sort_by(&:id).last.notes
2249 assert_equal 'Moving two issues', Issue.find(2).journals.sort_by(&:id).last.notes
2250 end
2250 end
2251
2251
2252 def test_bulk_update_parent_id
2252 def test_bulk_update_parent_id
2253 @request.session[:user_id] = 2
2253 @request.session[:user_id] = 2
2254 post :bulk_update, :ids => [1, 3],
2254 post :bulk_update, :ids => [1, 3],
2255 :notes => 'Bulk editing parent',
2255 :notes => 'Bulk editing parent',
2256 :issue => {:priority_id => '', :assigned_to_id => '', :status_id => '', :parent_issue_id => '2'}
2256 :issue => {:priority_id => '', :assigned_to_id => '', :status_id => '', :parent_issue_id => '2'}
2257
2257
2258 assert_response 302
2258 assert_response 302
2259 parent = Issue.find(2)
2259 parent = Issue.find(2)
2260 assert_equal parent.id, Issue.find(1).parent_id
2260 assert_equal parent.id, Issue.find(1).parent_id
2261 assert_equal parent.id, Issue.find(3).parent_id
2261 assert_equal parent.id, Issue.find(3).parent_id
2262 assert_equal [1, 3], parent.children.collect(&:id).sort
2262 assert_equal [1, 3], parent.children.collect(&:id).sort
2263 end
2263 end
2264
2264
2265 def test_bulk_update_custom_field
2265 def test_bulk_update_custom_field
2266 @request.session[:user_id] = 2
2266 @request.session[:user_id] = 2
2267 # update issues priority
2267 # update issues priority
2268 post :bulk_update, :ids => [1, 2], :notes => 'Bulk editing custom field',
2268 post :bulk_update, :ids => [1, 2], :notes => 'Bulk editing custom field',
2269 :issue => {:priority_id => '',
2269 :issue => {:priority_id => '',
2270 :assigned_to_id => '',
2270 :assigned_to_id => '',
2271 :custom_field_values => {'2' => '777'}}
2271 :custom_field_values => {'2' => '777'}}
2272
2272
2273 assert_response 302
2273 assert_response 302
2274
2274
2275 issue = Issue.find(1)
2275 issue = Issue.find(1)
2276 journal = issue.journals.find(:first, :order => 'created_on DESC')
2276 journal = issue.journals.find(:first, :order => 'created_on DESC')
2277 assert_equal '777', issue.custom_value_for(2).value
2277 assert_equal '777', issue.custom_value_for(2).value
2278 assert_equal 1, journal.details.size
2278 assert_equal 1, journal.details.size
2279 assert_equal '125', journal.details.first.old_value
2279 assert_equal '125', journal.details.first.old_value
2280 assert_equal '777', journal.details.first.value
2280 assert_equal '777', journal.details.first.value
2281 end
2281 end
2282
2282
2283 def test_bulk_update_unassign
2283 def test_bulk_update_unassign
2284 assert_not_nil Issue.find(2).assigned_to
2284 assert_not_nil Issue.find(2).assigned_to
2285 @request.session[:user_id] = 2
2285 @request.session[:user_id] = 2
2286 # unassign issues
2286 # unassign issues
2287 post :bulk_update, :ids => [1, 2], :notes => 'Bulk unassigning', :issue => {:assigned_to_id => 'none'}
2287 post :bulk_update, :ids => [1, 2], :notes => 'Bulk unassigning', :issue => {:assigned_to_id => 'none'}
2288 assert_response 302
2288 assert_response 302
2289 # check that the issues were updated
2289 # check that the issues were updated
2290 assert_nil Issue.find(2).assigned_to
2290 assert_nil Issue.find(2).assigned_to
2291 end
2291 end
2292
2292
2293 def test_post_bulk_update_should_allow_fixed_version_to_be_set_to_a_subproject
2293 def test_post_bulk_update_should_allow_fixed_version_to_be_set_to_a_subproject
2294 @request.session[:user_id] = 2
2294 @request.session[:user_id] = 2
2295
2295
2296 post :bulk_update, :ids => [1,2], :issue => {:fixed_version_id => 4}
2296 post :bulk_update, :ids => [1,2], :issue => {:fixed_version_id => 4}
2297
2297
2298 assert_response :redirect
2298 assert_response :redirect
2299 issues = Issue.find([1,2])
2299 issues = Issue.find([1,2])
2300 issues.each do |issue|
2300 issues.each do |issue|
2301 assert_equal 4, issue.fixed_version_id
2301 assert_equal 4, issue.fixed_version_id
2302 assert_not_equal issue.project_id, issue.fixed_version.project_id
2302 assert_not_equal issue.project_id, issue.fixed_version.project_id
2303 end
2303 end
2304 end
2304 end
2305
2305
2306 def test_post_bulk_update_should_redirect_back_using_the_back_url_parameter
2306 def test_post_bulk_update_should_redirect_back_using_the_back_url_parameter
2307 @request.session[:user_id] = 2
2307 @request.session[:user_id] = 2
2308 post :bulk_update, :ids => [1,2], :back_url => '/issues'
2308 post :bulk_update, :ids => [1,2], :back_url => '/issues'
2309
2309
2310 assert_response :redirect
2310 assert_response :redirect
2311 assert_redirected_to '/issues'
2311 assert_redirected_to '/issues'
2312 end
2312 end
2313
2313
2314 def test_post_bulk_update_should_not_redirect_back_using_the_back_url_parameter_off_the_host
2314 def test_post_bulk_update_should_not_redirect_back_using_the_back_url_parameter_off_the_host
2315 @request.session[:user_id] = 2
2315 @request.session[:user_id] = 2
2316 post :bulk_update, :ids => [1,2], :back_url => 'http://google.com'
2316 post :bulk_update, :ids => [1,2], :back_url => 'http://google.com'
2317
2317
2318 assert_response :redirect
2318 assert_response :redirect
2319 assert_redirected_to :controller => 'issues', :action => 'index', :project_id => Project.find(1).identifier
2319 assert_redirected_to :controller => 'issues', :action => 'index', :project_id => Project.find(1).identifier
2320 end
2320 end
2321
2321
2322 def test_bulk_copy_to_another_project
2323 @request.session[:user_id] = 2
2324 assert_difference 'Issue.count', 2 do
2325 assert_no_difference 'Project.find(1).issues.count' do
2326 post :bulk_update, :ids => [1, 2], :issue => {:project_id => '2'}, :copy => '1'
2327 end
2328 end
2329 assert_redirected_to '/projects/ecookbook/issues'
2330 end
2331
2332 def test_bulk_copy_should_allow_not_changing_the issue_attributes
2333 @request.session[:user_id] = 2
2334 issue_before_move = Issue.find(1)
2335 assert_difference 'Issue.count', 1 do
2336 assert_no_difference 'Project.find(1).issues.count' do
2337 post :bulk_update, :ids => [1], :copy => '1',
2338 :issue => {
2339 :project_id => '2', :tracker_id => '', :assigned_to_id => '',
2340 :status_id => '', :start_date => '', :due_date => ''
2341 }
2342 end
2343 end
2344 issue_after_move = Issue.first(:order => 'id desc', :conditions => {:project_id => 2})
2345 assert_equal issue_before_move.tracker_id, issue_after_move.tracker_id
2346 assert_equal issue_before_move.status_id, issue_after_move.status_id
2347 assert_equal issue_before_move.assigned_to_id, issue_after_move.assigned_to_id
2348 end
2349
2350 def test_bulk_copy_should_allow_changing_the_issue_attributes
2351 # Fixes random test failure with Mysql
2352 # where Issue.all(:limit => 2, :order => 'id desc', :conditions => {:project_id => 2})
2353 # doesn't return the expected results
2354 Issue.delete_all("project_id=2")
2355
2356 @request.session[:user_id] = 2
2357 assert_difference 'Issue.count', 2 do
2358 assert_no_difference 'Project.find(1).issues.count' do
2359 post :bulk_update, :ids => [1, 2], :copy => '1',
2360 :issue => {
2361 :project_id => '2', :tracker_id => '', :assigned_to_id => '4',
2362 :status_id => '3', :start_date => '2009-12-01', :due_date => '2009-12-31'
2363 }
2364 end
2365 end
2366
2367 copied_issues = Issue.all(:limit => 2, :order => 'id desc', :conditions => {:project_id => 2})
2368 assert_equal 2, copied_issues.size
2369 copied_issues.each do |issue|
2370 assert_equal 2, issue.project_id, "Project is incorrect"
2371 assert_equal 4, issue.assigned_to_id, "Assigned to is incorrect"
2372 assert_equal 3, issue.status_id, "Status is incorrect"
2373 assert_equal '2009-12-01', issue.start_date.to_s, "Start date is incorrect"
2374 assert_equal '2009-12-31', issue.due_date.to_s, "Due date is incorrect"
2375 end
2376 end
2377
2378 def test_bulk_copy_should_allow_adding_a_note
2379 @request.session[:user_id] = 2
2380 assert_difference 'Issue.count', 1 do
2381 post :bulk_update, :ids => [1], :copy => '1',
2382 :notes => 'Copying one issue',
2383 :issue => {
2384 :project_id => '', :tracker_id => '', :assigned_to_id => '4',
2385 :status_id => '3', :start_date => '2009-12-01', :due_date => '2009-12-31'
2386 }
2387 end
2388
2389 issue = Issue.first(:order => 'id DESC')
2390 assert_equal 1, issue.journals.size
2391 journal = issue.journals.first
2392 assert_equal 0, journal.details.size
2393 assert_equal 'Copying one issue', journal.notes
2394 end
2395
2396 def test_bulk_copy_to_another_project_should_follow_when_needed
2397 @request.session[:user_id] = 2
2398 post :bulk_update, :ids => [1], :copy => '1', :issue => {:project_id => 2}, :follow => '1'
2399 issue = Issue.first(:order => 'id DESC')
2400 assert_redirected_to :controller => 'issues', :action => 'show', :id => issue
2401 end
2402
2322 def test_destroy_issue_with_no_time_entries
2403 def test_destroy_issue_with_no_time_entries
2323 assert_nil TimeEntry.find_by_issue_id(2)
2404 assert_nil TimeEntry.find_by_issue_id(2)
2324 @request.session[:user_id] = 2
2405 @request.session[:user_id] = 2
2325 delete :destroy, :id => 2
2406 delete :destroy, :id => 2
2326 assert_redirected_to :action => 'index', :project_id => 'ecookbook'
2407 assert_redirected_to :action => 'index', :project_id => 'ecookbook'
2327 assert_nil Issue.find_by_id(2)
2408 assert_nil Issue.find_by_id(2)
2328 end
2409 end
2329
2410
2330 def test_destroy_issues_with_time_entries
2411 def test_destroy_issues_with_time_entries
2331 @request.session[:user_id] = 2
2412 @request.session[:user_id] = 2
2332 delete :destroy, :ids => [1, 3]
2413 delete :destroy, :ids => [1, 3]
2333 assert_response :success
2414 assert_response :success
2334 assert_template 'destroy'
2415 assert_template 'destroy'
2335 assert_not_nil assigns(:hours)
2416 assert_not_nil assigns(:hours)
2336 assert Issue.find_by_id(1) && Issue.find_by_id(3)
2417 assert Issue.find_by_id(1) && Issue.find_by_id(3)
2337 end
2418 end
2338
2419
2339 def test_destroy_issues_and_destroy_time_entries
2420 def test_destroy_issues_and_destroy_time_entries
2340 @request.session[:user_id] = 2
2421 @request.session[:user_id] = 2
2341 delete :destroy, :ids => [1, 3], :todo => 'destroy'
2422 delete :destroy, :ids => [1, 3], :todo => 'destroy'
2342 assert_redirected_to :action => 'index', :project_id => 'ecookbook'
2423 assert_redirected_to :action => 'index', :project_id => 'ecookbook'
2343 assert !(Issue.find_by_id(1) || Issue.find_by_id(3))
2424 assert !(Issue.find_by_id(1) || Issue.find_by_id(3))
2344 assert_nil TimeEntry.find_by_id([1, 2])
2425 assert_nil TimeEntry.find_by_id([1, 2])
2345 end
2426 end
2346
2427
2347 def test_destroy_issues_and_assign_time_entries_to_project
2428 def test_destroy_issues_and_assign_time_entries_to_project
2348 @request.session[:user_id] = 2
2429 @request.session[:user_id] = 2
2349 delete :destroy, :ids => [1, 3], :todo => 'nullify'
2430 delete :destroy, :ids => [1, 3], :todo => 'nullify'
2350 assert_redirected_to :action => 'index', :project_id => 'ecookbook'
2431 assert_redirected_to :action => 'index', :project_id => 'ecookbook'
2351 assert !(Issue.find_by_id(1) || Issue.find_by_id(3))
2432 assert !(Issue.find_by_id(1) || Issue.find_by_id(3))
2352 assert_nil TimeEntry.find(1).issue_id
2433 assert_nil TimeEntry.find(1).issue_id
2353 assert_nil TimeEntry.find(2).issue_id
2434 assert_nil TimeEntry.find(2).issue_id
2354 end
2435 end
2355
2436
2356 def test_destroy_issues_and_reassign_time_entries_to_another_issue
2437 def test_destroy_issues_and_reassign_time_entries_to_another_issue
2357 @request.session[:user_id] = 2
2438 @request.session[:user_id] = 2
2358 delete :destroy, :ids => [1, 3], :todo => 'reassign', :reassign_to_id => 2
2439 delete :destroy, :ids => [1, 3], :todo => 'reassign', :reassign_to_id => 2
2359 assert_redirected_to :action => 'index', :project_id => 'ecookbook'
2440 assert_redirected_to :action => 'index', :project_id => 'ecookbook'
2360 assert !(Issue.find_by_id(1) || Issue.find_by_id(3))
2441 assert !(Issue.find_by_id(1) || Issue.find_by_id(3))
2361 assert_equal 2, TimeEntry.find(1).issue_id
2442 assert_equal 2, TimeEntry.find(1).issue_id
2362 assert_equal 2, TimeEntry.find(2).issue_id
2443 assert_equal 2, TimeEntry.find(2).issue_id
2363 end
2444 end
2364
2445
2365 def test_destroy_issues_from_different_projects
2446 def test_destroy_issues_from_different_projects
2366 @request.session[:user_id] = 2
2447 @request.session[:user_id] = 2
2367 delete :destroy, :ids => [1, 2, 6], :todo => 'destroy'
2448 delete :destroy, :ids => [1, 2, 6], :todo => 'destroy'
2368 assert_redirected_to :controller => 'issues', :action => 'index'
2449 assert_redirected_to :controller => 'issues', :action => 'index'
2369 assert !(Issue.find_by_id(1) || Issue.find_by_id(2) || Issue.find_by_id(6))
2450 assert !(Issue.find_by_id(1) || Issue.find_by_id(2) || Issue.find_by_id(6))
2370 end
2451 end
2371
2452
2372 def test_destroy_parent_and_child_issues
2453 def test_destroy_parent_and_child_issues
2373 parent = Issue.generate!(:project_id => 1, :tracker_id => 1)
2454 parent = Issue.generate!(:project_id => 1, :tracker_id => 1)
2374 child = Issue.generate!(:project_id => 1, :tracker_id => 1, :parent_issue_id => parent.id)
2455 child = Issue.generate!(:project_id => 1, :tracker_id => 1, :parent_issue_id => parent.id)
2375 assert child.is_descendant_of?(parent.reload)
2456 assert child.is_descendant_of?(parent.reload)
2376
2457
2377 @request.session[:user_id] = 2
2458 @request.session[:user_id] = 2
2378 assert_difference 'Issue.count', -2 do
2459 assert_difference 'Issue.count', -2 do
2379 delete :destroy, :ids => [parent.id, child.id], :todo => 'destroy'
2460 delete :destroy, :ids => [parent.id, child.id], :todo => 'destroy'
2380 end
2461 end
2381 assert_response 302
2462 assert_response 302
2382 end
2463 end
2383
2464
2384 def test_default_search_scope
2465 def test_default_search_scope
2385 get :index
2466 get :index
2386 assert_tag :div, :attributes => {:id => 'quick-search'},
2467 assert_tag :div, :attributes => {:id => 'quick-search'},
2387 :child => {:tag => 'form',
2468 :child => {:tag => 'form',
2388 :child => {:tag => 'input', :attributes => {:name => 'issues', :type => 'hidden', :value => '1'}}}
2469 :child => {:tag => 'input', :attributes => {:name => 'issues', :type => 'hidden', :value => '1'}}}
2389 end
2470 end
2390 end
2471 end
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
General Comments 0
You need to be logged in to leave comments. Login now