##// END OF EJS Templates
fix malformed issues csv encoding in case of unable to convert (#8549)...
Toshi MARUYAMA -
r7702:eb498a86acde
parent child
Show More
@@ -1,323 +1,326
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 module IssuesHelper
18 module IssuesHelper
19 include ApplicationHelper
19 include ApplicationHelper
20
20
21 def issue_list(issues, &block)
21 def issue_list(issues, &block)
22 ancestors = []
22 ancestors = []
23 issues.each do |issue|
23 issues.each do |issue|
24 while (ancestors.any? && !issue.is_descendant_of?(ancestors.last))
24 while (ancestors.any? && !issue.is_descendant_of?(ancestors.last))
25 ancestors.pop
25 ancestors.pop
26 end
26 end
27 yield issue, ancestors.size
27 yield issue, ancestors.size
28 ancestors << issue unless issue.leaf?
28 ancestors << issue unless issue.leaf?
29 end
29 end
30 end
30 end
31
31
32 # Renders a HTML/CSS tooltip
32 # Renders a HTML/CSS tooltip
33 #
33 #
34 # To use, a trigger div is needed. This is a div with the class of "tooltip"
34 # To use, a trigger div is needed. This is a div with the class of "tooltip"
35 # that contains this method wrapped in a span with the class of "tip"
35 # that contains this method wrapped in a span with the class of "tip"
36 #
36 #
37 # <div class="tooltip"><%= link_to_issue(issue) %>
37 # <div class="tooltip"><%= link_to_issue(issue) %>
38 # <span class="tip"><%= render_issue_tooltip(issue) %></span>
38 # <span class="tip"><%= render_issue_tooltip(issue) %></span>
39 # </div>
39 # </div>
40 #
40 #
41 def render_issue_tooltip(issue)
41 def render_issue_tooltip(issue)
42 @cached_label_status ||= l(:field_status)
42 @cached_label_status ||= l(:field_status)
43 @cached_label_start_date ||= l(:field_start_date)
43 @cached_label_start_date ||= l(:field_start_date)
44 @cached_label_due_date ||= l(:field_due_date)
44 @cached_label_due_date ||= l(:field_due_date)
45 @cached_label_assigned_to ||= l(:field_assigned_to)
45 @cached_label_assigned_to ||= l(:field_assigned_to)
46 @cached_label_priority ||= l(:field_priority)
46 @cached_label_priority ||= l(:field_priority)
47 @cached_label_project ||= l(:field_project)
47 @cached_label_project ||= l(:field_project)
48
48
49 (link_to_issue(issue) + "<br /><br />" +
49 (link_to_issue(issue) + "<br /><br />" +
50 "<strong>#{@cached_label_project}</strong>: #{link_to_project(issue.project)}<br />" +
50 "<strong>#{@cached_label_project}</strong>: #{link_to_project(issue.project)}<br />" +
51 "<strong>#{@cached_label_status}</strong>: #{h(issue.status.name)}<br />" +
51 "<strong>#{@cached_label_status}</strong>: #{h(issue.status.name)}<br />" +
52 "<strong>#{@cached_label_start_date}</strong>: #{format_date(issue.start_date)}<br />" +
52 "<strong>#{@cached_label_start_date}</strong>: #{format_date(issue.start_date)}<br />" +
53 "<strong>#{@cached_label_due_date}</strong>: #{format_date(issue.due_date)}<br />" +
53 "<strong>#{@cached_label_due_date}</strong>: #{format_date(issue.due_date)}<br />" +
54 "<strong>#{@cached_label_assigned_to}</strong>: #{h(issue.assigned_to)}<br />" +
54 "<strong>#{@cached_label_assigned_to}</strong>: #{h(issue.assigned_to)}<br />" +
55 "<strong>#{@cached_label_priority}</strong>: #{h(issue.priority.name)}").html_safe
55 "<strong>#{@cached_label_priority}</strong>: #{h(issue.priority.name)}").html_safe
56 end
56 end
57
57
58 def issue_heading(issue)
58 def issue_heading(issue)
59 h("#{issue.tracker} ##{issue.id}")
59 h("#{issue.tracker} ##{issue.id}")
60 end
60 end
61
61
62 def render_issue_subject_with_tree(issue)
62 def render_issue_subject_with_tree(issue)
63 s = ''
63 s = ''
64 ancestors = issue.root? ? [] : issue.ancestors.visible.all
64 ancestors = issue.root? ? [] : issue.ancestors.visible.all
65 ancestors.each do |ancestor|
65 ancestors.each do |ancestor|
66 s << '<div>' + content_tag('p', link_to_issue(ancestor))
66 s << '<div>' + content_tag('p', link_to_issue(ancestor))
67 end
67 end
68 s << '<div>'
68 s << '<div>'
69 subject = h(issue.subject)
69 subject = h(issue.subject)
70 if issue.is_private?
70 if issue.is_private?
71 subject = content_tag('span', l(:field_is_private), :class => 'private') + ' ' + subject
71 subject = content_tag('span', l(:field_is_private), :class => 'private') + ' ' + subject
72 end
72 end
73 s << content_tag('h3', subject)
73 s << content_tag('h3', subject)
74 s << '</div>' * (ancestors.size + 1)
74 s << '</div>' * (ancestors.size + 1)
75 s.html_safe
75 s.html_safe
76 end
76 end
77
77
78 def render_descendants_tree(issue)
78 def render_descendants_tree(issue)
79 s = '<form><table class="list issues">'
79 s = '<form><table class="list issues">'
80 issue_list(issue.descendants.visible.sort_by(&:lft)) do |child, level|
80 issue_list(issue.descendants.visible.sort_by(&:lft)) do |child, level|
81 s << content_tag('tr',
81 s << content_tag('tr',
82 content_tag('td', check_box_tag("ids[]", child.id, false, :id => nil), :class => 'checkbox') +
82 content_tag('td', check_box_tag("ids[]", child.id, false, :id => nil), :class => 'checkbox') +
83 content_tag('td', link_to_issue(child, :truncate => 60), :class => 'subject') +
83 content_tag('td', link_to_issue(child, :truncate => 60), :class => 'subject') +
84 content_tag('td', h(child.status)) +
84 content_tag('td', h(child.status)) +
85 content_tag('td', link_to_user(child.assigned_to)) +
85 content_tag('td', link_to_user(child.assigned_to)) +
86 content_tag('td', progress_bar(child.done_ratio, :width => '80px')),
86 content_tag('td', progress_bar(child.done_ratio, :width => '80px')),
87 :class => "issue issue-#{child.id} hascontextmenu #{level > 0 ? "idnt idnt-#{level}" : nil}")
87 :class => "issue issue-#{child.id} hascontextmenu #{level > 0 ? "idnt idnt-#{level}" : nil}")
88 end
88 end
89 s << '</form></table>'
89 s << '</form></table>'
90 s.html_safe
90 s.html_safe
91 end
91 end
92
92
93 def render_custom_fields_rows(issue)
93 def render_custom_fields_rows(issue)
94 return if issue.custom_field_values.empty?
94 return if issue.custom_field_values.empty?
95 ordered_values = []
95 ordered_values = []
96 half = (issue.custom_field_values.size / 2.0).ceil
96 half = (issue.custom_field_values.size / 2.0).ceil
97 half.times do |i|
97 half.times do |i|
98 ordered_values << issue.custom_field_values[i]
98 ordered_values << issue.custom_field_values[i]
99 ordered_values << issue.custom_field_values[i + half]
99 ordered_values << issue.custom_field_values[i + half]
100 end
100 end
101 s = "<tr>\n"
101 s = "<tr>\n"
102 n = 0
102 n = 0
103 ordered_values.compact.each do |value|
103 ordered_values.compact.each do |value|
104 s << "</tr>\n<tr>\n" if n > 0 && (n % 2) == 0
104 s << "</tr>\n<tr>\n" if n > 0 && (n % 2) == 0
105 s << "\t<th>#{ h(value.custom_field.name) }:</th><td>#{ simple_format_without_paragraph(h(show_value(value))) }</td>\n"
105 s << "\t<th>#{ h(value.custom_field.name) }:</th><td>#{ simple_format_without_paragraph(h(show_value(value))) }</td>\n"
106 n += 1
106 n += 1
107 end
107 end
108 s << "</tr>\n"
108 s << "</tr>\n"
109 s.html_safe
109 s.html_safe
110 end
110 end
111
111
112 def issues_destroy_confirmation_message(issues)
112 def issues_destroy_confirmation_message(issues)
113 issues = [issues] unless issues.is_a?(Array)
113 issues = [issues] unless issues.is_a?(Array)
114 message = l(:text_issues_destroy_confirmation)
114 message = l(:text_issues_destroy_confirmation)
115 descendant_count = issues.inject(0) {|memo, i| memo += (i.right - i.left - 1)/2}
115 descendant_count = issues.inject(0) {|memo, i| memo += (i.right - i.left - 1)/2}
116 if descendant_count > 0
116 if descendant_count > 0
117 issues.each do |issue|
117 issues.each do |issue|
118 next if issue.root?
118 next if issue.root?
119 issues.each do |other_issue|
119 issues.each do |other_issue|
120 descendant_count -= 1 if issue.is_descendant_of?(other_issue)
120 descendant_count -= 1 if issue.is_descendant_of?(other_issue)
121 end
121 end
122 end
122 end
123 if descendant_count > 0
123 if descendant_count > 0
124 message << "\n" + l(:text_issues_destroy_descendants_confirmation, :count => descendant_count)
124 message << "\n" + l(:text_issues_destroy_descendants_confirmation, :count => descendant_count)
125 end
125 end
126 end
126 end
127 message
127 message
128 end
128 end
129
129
130 def sidebar_queries
130 def sidebar_queries
131 unless @sidebar_queries
131 unless @sidebar_queries
132 # User can see public queries and his own queries
132 # User can see public queries and his own queries
133 visible = ARCondition.new(["is_public = ? OR user_id = ?", true, (User.current.logged? ? User.current.id : 0)])
133 visible = ARCondition.new(["is_public = ? OR user_id = ?", true, (User.current.logged? ? User.current.id : 0)])
134 # Project specific queries and global queries
134 # Project specific queries and global queries
135 visible << (@project.nil? ? ["project_id IS NULL"] : ["project_id IS NULL OR project_id = ?", @project.id])
135 visible << (@project.nil? ? ["project_id IS NULL"] : ["project_id IS NULL OR project_id = ?", @project.id])
136 @sidebar_queries = Query.find(:all,
136 @sidebar_queries = Query.find(:all,
137 :select => 'id, name, is_public',
137 :select => 'id, name, is_public',
138 :order => "name ASC",
138 :order => "name ASC",
139 :conditions => visible.conditions)
139 :conditions => visible.conditions)
140 end
140 end
141 @sidebar_queries
141 @sidebar_queries
142 end
142 end
143
143
144 def query_links(title, queries)
144 def query_links(title, queries)
145 # links to #index on issues/show
145 # links to #index on issues/show
146 url_params = controller_name == 'issues' ? {:controller => 'issues', :action => 'index', :project_id => @project} : params
146 url_params = controller_name == 'issues' ? {:controller => 'issues', :action => 'index', :project_id => @project} : params
147
147
148 content_tag('h3', h(title)) +
148 content_tag('h3', h(title)) +
149 queries.collect {|query|
149 queries.collect {|query|
150 link_to(h(query.name), url_params.merge(:query_id => query))
150 link_to(h(query.name), url_params.merge(:query_id => query))
151 }.join('<br />')
151 }.join('<br />')
152 end
152 end
153
153
154 def render_sidebar_queries
154 def render_sidebar_queries
155 out = ''
155 out = ''
156 queries = sidebar_queries.select {|q| !q.is_public?}
156 queries = sidebar_queries.select {|q| !q.is_public?}
157 out << query_links(l(:label_my_queries), queries) if queries.any?
157 out << query_links(l(:label_my_queries), queries) if queries.any?
158 queries = sidebar_queries.select {|q| q.is_public?}
158 queries = sidebar_queries.select {|q| q.is_public?}
159 out << query_links(l(:label_query_plural), queries) if queries.any?
159 out << query_links(l(:label_query_plural), queries) if queries.any?
160 out
160 out
161 end
161 end
162
162
163 def show_detail(detail, no_html=false)
163 def show_detail(detail, no_html=false)
164 case detail.property
164 case detail.property
165 when 'attr'
165 when 'attr'
166 field = detail.prop_key.to_s.gsub(/\_id$/, "")
166 field = detail.prop_key.to_s.gsub(/\_id$/, "")
167 label = l(("field_" + field).to_sym)
167 label = l(("field_" + field).to_sym)
168 case
168 case
169 when ['due_date', 'start_date'].include?(detail.prop_key)
169 when ['due_date', 'start_date'].include?(detail.prop_key)
170 value = format_date(detail.value.to_date) if detail.value
170 value = format_date(detail.value.to_date) if detail.value
171 old_value = format_date(detail.old_value.to_date) if detail.old_value
171 old_value = format_date(detail.old_value.to_date) if detail.old_value
172
172
173 when ['project_id', 'status_id', 'tracker_id', 'assigned_to_id', 'priority_id', 'category_id', 'fixed_version_id'].include?(detail.prop_key)
173 when ['project_id', 'status_id', 'tracker_id', 'assigned_to_id', 'priority_id', 'category_id', 'fixed_version_id'].include?(detail.prop_key)
174 value = find_name_by_reflection(field, detail.value)
174 value = find_name_by_reflection(field, detail.value)
175 old_value = find_name_by_reflection(field, detail.old_value)
175 old_value = find_name_by_reflection(field, detail.old_value)
176
176
177 when detail.prop_key == 'estimated_hours'
177 when detail.prop_key == 'estimated_hours'
178 value = "%0.02f" % detail.value.to_f unless detail.value.blank?
178 value = "%0.02f" % detail.value.to_f unless detail.value.blank?
179 old_value = "%0.02f" % detail.old_value.to_f unless detail.old_value.blank?
179 old_value = "%0.02f" % detail.old_value.to_f unless detail.old_value.blank?
180
180
181 when detail.prop_key == 'parent_id'
181 when detail.prop_key == 'parent_id'
182 label = l(:field_parent_issue)
182 label = l(:field_parent_issue)
183 value = "##{detail.value}" unless detail.value.blank?
183 value = "##{detail.value}" unless detail.value.blank?
184 old_value = "##{detail.old_value}" unless detail.old_value.blank?
184 old_value = "##{detail.old_value}" unless detail.old_value.blank?
185
185
186 when detail.prop_key == 'is_private'
186 when detail.prop_key == 'is_private'
187 value = l(detail.value == "0" ? :general_text_No : :general_text_Yes) unless detail.value.blank?
187 value = l(detail.value == "0" ? :general_text_No : :general_text_Yes) unless detail.value.blank?
188 old_value = l(detail.old_value == "0" ? :general_text_No : :general_text_Yes) unless detail.old_value.blank?
188 old_value = l(detail.old_value == "0" ? :general_text_No : :general_text_Yes) unless detail.old_value.blank?
189 end
189 end
190 when 'cf'
190 when 'cf'
191 custom_field = CustomField.find_by_id(detail.prop_key)
191 custom_field = CustomField.find_by_id(detail.prop_key)
192 if custom_field
192 if custom_field
193 label = custom_field.name
193 label = custom_field.name
194 value = format_value(detail.value, custom_field.field_format) if detail.value
194 value = format_value(detail.value, custom_field.field_format) if detail.value
195 old_value = format_value(detail.old_value, custom_field.field_format) if detail.old_value
195 old_value = format_value(detail.old_value, custom_field.field_format) if detail.old_value
196 end
196 end
197 when 'attachment'
197 when 'attachment'
198 label = l(:label_attachment)
198 label = l(:label_attachment)
199 end
199 end
200 call_hook(:helper_issues_show_detail_after_setting, {:detail => detail, :label => label, :value => value, :old_value => old_value })
200 call_hook(:helper_issues_show_detail_after_setting, {:detail => detail, :label => label, :value => value, :old_value => old_value })
201
201
202 label ||= detail.prop_key
202 label ||= detail.prop_key
203 value ||= detail.value
203 value ||= detail.value
204 old_value ||= detail.old_value
204 old_value ||= detail.old_value
205
205
206 unless no_html
206 unless no_html
207 label = content_tag('strong', label)
207 label = content_tag('strong', label)
208 old_value = content_tag("i", h(old_value)) if detail.old_value
208 old_value = content_tag("i", h(old_value)) if detail.old_value
209 old_value = content_tag("strike", old_value) if detail.old_value and detail.value.blank?
209 old_value = content_tag("strike", old_value) if detail.old_value and detail.value.blank?
210 if detail.property == 'attachment' && !value.blank? && a = Attachment.find_by_id(detail.prop_key)
210 if detail.property == 'attachment' && !value.blank? && a = Attachment.find_by_id(detail.prop_key)
211 # Link to the attachment if it has not been removed
211 # Link to the attachment if it has not been removed
212 value = link_to_attachment(a)
212 value = link_to_attachment(a)
213 else
213 else
214 value = content_tag("i", h(value)) if value
214 value = content_tag("i", h(value)) if value
215 end
215 end
216 end
216 end
217
217
218 if detail.property == 'attr' && detail.prop_key == 'description'
218 if detail.property == 'attr' && detail.prop_key == 'description'
219 s = l(:text_journal_changed_no_detail, :label => label)
219 s = l(:text_journal_changed_no_detail, :label => label)
220 unless no_html
220 unless no_html
221 diff_link = link_to 'diff',
221 diff_link = link_to 'diff',
222 {:controller => 'journals', :action => 'diff', :id => detail.journal_id, :detail_id => detail.id},
222 {:controller => 'journals', :action => 'diff', :id => detail.journal_id, :detail_id => detail.id},
223 :title => l(:label_view_diff)
223 :title => l(:label_view_diff)
224 s << " (#{ diff_link })"
224 s << " (#{ diff_link })"
225 end
225 end
226 s
226 s
227 elsif !detail.value.blank?
227 elsif !detail.value.blank?
228 case detail.property
228 case detail.property
229 when 'attr', 'cf'
229 when 'attr', 'cf'
230 if !detail.old_value.blank?
230 if !detail.old_value.blank?
231 l(:text_journal_changed, :label => label, :old => old_value, :new => value)
231 l(:text_journal_changed, :label => label, :old => old_value, :new => value)
232 else
232 else
233 l(:text_journal_set_to, :label => label, :value => value)
233 l(:text_journal_set_to, :label => label, :value => value)
234 end
234 end
235 when 'attachment'
235 when 'attachment'
236 l(:text_journal_added, :label => label, :value => value)
236 l(:text_journal_added, :label => label, :value => value)
237 end
237 end
238 else
238 else
239 l(:text_journal_deleted, :label => label, :old => old_value)
239 l(:text_journal_deleted, :label => label, :old => old_value)
240 end
240 end
241 end
241 end
242
242
243 # Find the name of an associated record stored in the field attribute
243 # Find the name of an associated record stored in the field attribute
244 def find_name_by_reflection(field, id)
244 def find_name_by_reflection(field, id)
245 association = Issue.reflect_on_association(field.to_sym)
245 association = Issue.reflect_on_association(field.to_sym)
246 if association
246 if association
247 record = association.class_name.constantize.find_by_id(id)
247 record = association.class_name.constantize.find_by_id(id)
248 return record.name if record
248 return record.name if record
249 end
249 end
250 end
250 end
251
251
252 # Renders issue children recursively
252 # Renders issue children recursively
253 def render_api_issue_children(issue, api)
253 def render_api_issue_children(issue, api)
254 return if issue.leaf?
254 return if issue.leaf?
255 api.array :children do
255 api.array :children do
256 issue.children.each do |child|
256 issue.children.each do |child|
257 api.issue(:id => child.id) do
257 api.issue(:id => child.id) do
258 api.tracker(:id => child.tracker_id, :name => child.tracker.name) unless child.tracker.nil?
258 api.tracker(:id => child.tracker_id, :name => child.tracker.name) unless child.tracker.nil?
259 api.subject child.subject
259 api.subject child.subject
260 render_api_issue_children(child, api)
260 render_api_issue_children(child, api)
261 end
261 end
262 end
262 end
263 end
263 end
264 end
264 end
265
265
266 def issues_to_csv(issues, project = nil)
266 def issues_to_csv(issues, project = nil)
267 ic = Iconv.new(l(:general_csv_encoding), 'UTF-8')
268 decimal_separator = l(:general_csv_decimal_separator)
267 decimal_separator = l(:general_csv_decimal_separator)
269 export = FCSV.generate(:col_sep => l(:general_csv_separator)) do |csv|
268 export = FCSV.generate(:col_sep => l(:general_csv_separator)) do |csv|
270 # csv header fields
269 # csv header fields
271 headers = [ "#",
270 headers = [ "#",
272 l(:field_status),
271 l(:field_status),
273 l(:field_project),
272 l(:field_project),
274 l(:field_tracker),
273 l(:field_tracker),
275 l(:field_priority),
274 l(:field_priority),
276 l(:field_subject),
275 l(:field_subject),
277 l(:field_assigned_to),
276 l(:field_assigned_to),
278 l(:field_category),
277 l(:field_category),
279 l(:field_fixed_version),
278 l(:field_fixed_version),
280 l(:field_author),
279 l(:field_author),
281 l(:field_start_date),
280 l(:field_start_date),
282 l(:field_due_date),
281 l(:field_due_date),
283 l(:field_done_ratio),
282 l(:field_done_ratio),
284 l(:field_estimated_hours),
283 l(:field_estimated_hours),
285 l(:field_parent_issue),
284 l(:field_parent_issue),
286 l(:field_created_on),
285 l(:field_created_on),
287 l(:field_updated_on)
286 l(:field_updated_on)
288 ]
287 ]
289 # Export project custom fields if project is given
288 # Export project custom fields if project is given
290 # otherwise export custom fields marked as "For all projects"
289 # otherwise export custom fields marked as "For all projects"
291 custom_fields = project.nil? ? IssueCustomField.for_all : project.all_issue_custom_fields
290 custom_fields = project.nil? ? IssueCustomField.for_all : project.all_issue_custom_fields
292 custom_fields.each {|f| headers << f.name}
291 custom_fields.each {|f| headers << f.name}
293 # Description in the last column
292 # Description in the last column
294 headers << l(:field_description)
293 headers << l(:field_description)
295 csv << headers.collect {|c| begin; ic.iconv(c.to_s); rescue; c.to_s; end }
294 csv << headers.collect {|c| Redmine::CodesetUtil.from_utf8(
295 c.to_s,
296 l(:general_csv_encoding) ) }
296 # csv lines
297 # csv lines
297 issues.each do |issue|
298 issues.each do |issue|
298 fields = [issue.id,
299 fields = [issue.id,
299 issue.status.name,
300 issue.status.name,
300 issue.project.name,
301 issue.project.name,
301 issue.tracker.name,
302 issue.tracker.name,
302 issue.priority.name,
303 issue.priority.name,
303 issue.subject,
304 issue.subject,
304 issue.assigned_to,
305 issue.assigned_to,
305 issue.category,
306 issue.category,
306 issue.fixed_version,
307 issue.fixed_version,
307 issue.author.name,
308 issue.author.name,
308 format_date(issue.start_date),
309 format_date(issue.start_date),
309 format_date(issue.due_date),
310 format_date(issue.due_date),
310 issue.done_ratio,
311 issue.done_ratio,
311 issue.estimated_hours.to_s.gsub('.', decimal_separator),
312 issue.estimated_hours.to_s.gsub('.', decimal_separator),
312 issue.parent_id,
313 issue.parent_id,
313 format_time(issue.created_on),
314 format_time(issue.created_on),
314 format_time(issue.updated_on)
315 format_time(issue.updated_on)
315 ]
316 ]
316 custom_fields.each {|f| fields << show_value(issue.custom_value_for(f)) }
317 custom_fields.each {|f| fields << show_value(issue.custom_value_for(f)) }
317 fields << issue.description
318 fields << issue.description
318 csv << fields.collect {|c| begin; ic.iconv(c.to_s); rescue; c.to_s; end }
319 csv << fields.collect {|c| Redmine::CodesetUtil.from_utf8(
320 c.to_s,
321 l(:general_csv_encoding) ) }
319 end
322 end
320 end
323 end
321 export
324 export
322 end
325 end
323 end
326 end
@@ -1,1781 +1,1816
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 def setup
46 def setup
47 @controller = IssuesController.new
47 @controller = IssuesController.new
48 @request = ActionController::TestRequest.new
48 @request = ActionController::TestRequest.new
49 @response = ActionController::TestResponse.new
49 @response = ActionController::TestResponse.new
50 User.current = nil
50 User.current = nil
51 end
51 end
52
52
53 def test_index
53 def test_index
54 Setting.default_language = 'en'
54 Setting.default_language = 'en'
55
55
56 get :index
56 get :index
57 assert_response :success
57 assert_response :success
58 assert_template 'index'
58 assert_template 'index'
59 assert_not_nil assigns(:issues)
59 assert_not_nil assigns(:issues)
60 assert_nil assigns(:project)
60 assert_nil assigns(:project)
61 assert_tag :tag => 'a', :content => /Can't print recipes/
61 assert_tag :tag => 'a', :content => /Can't print recipes/
62 assert_tag :tag => 'a', :content => /Subproject issue/
62 assert_tag :tag => 'a', :content => /Subproject issue/
63 # private projects hidden
63 # private projects hidden
64 assert_no_tag :tag => 'a', :content => /Issue of a private subproject/
64 assert_no_tag :tag => 'a', :content => /Issue of a private subproject/
65 assert_no_tag :tag => 'a', :content => /Issue on project 2/
65 assert_no_tag :tag => 'a', :content => /Issue on project 2/
66 # project column
66 # project column
67 assert_tag :tag => 'th', :content => /Project/
67 assert_tag :tag => 'th', :content => /Project/
68 end
68 end
69
69
70 def test_index_should_not_list_issues_when_module_disabled
70 def test_index_should_not_list_issues_when_module_disabled
71 EnabledModule.delete_all("name = 'issue_tracking' AND project_id = 1")
71 EnabledModule.delete_all("name = 'issue_tracking' AND project_id = 1")
72 get :index
72 get :index
73 assert_response :success
73 assert_response :success
74 assert_template 'index'
74 assert_template 'index'
75 assert_not_nil assigns(:issues)
75 assert_not_nil assigns(:issues)
76 assert_nil assigns(:project)
76 assert_nil assigns(:project)
77 assert_no_tag :tag => 'a', :content => /Can't print recipes/
77 assert_no_tag :tag => 'a', :content => /Can't print recipes/
78 assert_tag :tag => 'a', :content => /Subproject issue/
78 assert_tag :tag => 'a', :content => /Subproject issue/
79 end
79 end
80
80
81 def test_index_should_list_visible_issues_only
81 def test_index_should_list_visible_issues_only
82 get :index, :per_page => 100
82 get :index, :per_page => 100
83 assert_response :success
83 assert_response :success
84 assert_not_nil assigns(:issues)
84 assert_not_nil assigns(:issues)
85 assert_nil assigns(:issues).detect {|issue| !issue.visible?}
85 assert_nil assigns(:issues).detect {|issue| !issue.visible?}
86 end
86 end
87
87
88 def test_index_with_project
88 def test_index_with_project
89 Setting.display_subprojects_issues = 0
89 Setting.display_subprojects_issues = 0
90 get :index, :project_id => 1
90 get :index, :project_id => 1
91 assert_response :success
91 assert_response :success
92 assert_template 'index'
92 assert_template 'index'
93 assert_not_nil assigns(:issues)
93 assert_not_nil assigns(:issues)
94 assert_tag :tag => 'a', :content => /Can't print recipes/
94 assert_tag :tag => 'a', :content => /Can't print recipes/
95 assert_no_tag :tag => 'a', :content => /Subproject issue/
95 assert_no_tag :tag => 'a', :content => /Subproject issue/
96 end
96 end
97
97
98 def test_index_with_project_and_subprojects
98 def test_index_with_project_and_subprojects
99 Setting.display_subprojects_issues = 1
99 Setting.display_subprojects_issues = 1
100 get :index, :project_id => 1
100 get :index, :project_id => 1
101 assert_response :success
101 assert_response :success
102 assert_template 'index'
102 assert_template 'index'
103 assert_not_nil assigns(:issues)
103 assert_not_nil assigns(:issues)
104 assert_tag :tag => 'a', :content => /Can't print recipes/
104 assert_tag :tag => 'a', :content => /Can't print recipes/
105 assert_tag :tag => 'a', :content => /Subproject issue/
105 assert_tag :tag => 'a', :content => /Subproject issue/
106 assert_no_tag :tag => 'a', :content => /Issue of a private subproject/
106 assert_no_tag :tag => 'a', :content => /Issue of a private subproject/
107 end
107 end
108
108
109 def test_index_with_project_and_subprojects_should_show_private_subprojects
109 def test_index_with_project_and_subprojects_should_show_private_subprojects
110 @request.session[:user_id] = 2
110 @request.session[:user_id] = 2
111 Setting.display_subprojects_issues = 1
111 Setting.display_subprojects_issues = 1
112 get :index, :project_id => 1
112 get :index, :project_id => 1
113 assert_response :success
113 assert_response :success
114 assert_template 'index'
114 assert_template 'index'
115 assert_not_nil assigns(:issues)
115 assert_not_nil assigns(:issues)
116 assert_tag :tag => 'a', :content => /Can't print recipes/
116 assert_tag :tag => 'a', :content => /Can't print recipes/
117 assert_tag :tag => 'a', :content => /Subproject issue/
117 assert_tag :tag => 'a', :content => /Subproject issue/
118 assert_tag :tag => 'a', :content => /Issue of a private subproject/
118 assert_tag :tag => 'a', :content => /Issue of a private subproject/
119 end
119 end
120
120
121 def test_index_with_project_and_default_filter
121 def test_index_with_project_and_default_filter
122 get :index, :project_id => 1, :set_filter => 1
122 get :index, :project_id => 1, :set_filter => 1
123 assert_response :success
123 assert_response :success
124 assert_template 'index'
124 assert_template 'index'
125 assert_not_nil assigns(:issues)
125 assert_not_nil assigns(:issues)
126
126
127 query = assigns(:query)
127 query = assigns(:query)
128 assert_not_nil query
128 assert_not_nil query
129 # default filter
129 # default filter
130 assert_equal({'status_id' => {:operator => 'o', :values => ['']}}, query.filters)
130 assert_equal({'status_id' => {:operator => 'o', :values => ['']}}, query.filters)
131 end
131 end
132
132
133 def test_index_with_project_and_filter
133 def test_index_with_project_and_filter
134 get :index, :project_id => 1, :set_filter => 1,
134 get :index, :project_id => 1, :set_filter => 1,
135 :f => ['tracker_id'],
135 :f => ['tracker_id'],
136 :op => {'tracker_id' => '='},
136 :op => {'tracker_id' => '='},
137 :v => {'tracker_id' => ['1']}
137 :v => {'tracker_id' => ['1']}
138 assert_response :success
138 assert_response :success
139 assert_template 'index'
139 assert_template 'index'
140 assert_not_nil assigns(:issues)
140 assert_not_nil assigns(:issues)
141
141
142 query = assigns(:query)
142 query = assigns(:query)
143 assert_not_nil query
143 assert_not_nil query
144 assert_equal({'tracker_id' => {:operator => '=', :values => ['1']}}, query.filters)
144 assert_equal({'tracker_id' => {:operator => '=', :values => ['1']}}, query.filters)
145 end
145 end
146
146
147 def test_index_with_short_filters
147 def test_index_with_short_filters
148
148
149 to_test = {
149 to_test = {
150 'status_id' => {
150 'status_id' => {
151 'o' => { :op => 'o', :values => [''] },
151 'o' => { :op => 'o', :values => [''] },
152 'c' => { :op => 'c', :values => [''] },
152 'c' => { :op => 'c', :values => [''] },
153 '7' => { :op => '=', :values => ['7'] },
153 '7' => { :op => '=', :values => ['7'] },
154 '7|3|4' => { :op => '=', :values => ['7', '3', '4'] },
154 '7|3|4' => { :op => '=', :values => ['7', '3', '4'] },
155 '=7' => { :op => '=', :values => ['7'] },
155 '=7' => { :op => '=', :values => ['7'] },
156 '!3' => { :op => '!', :values => ['3'] },
156 '!3' => { :op => '!', :values => ['3'] },
157 '!7|3|4' => { :op => '!', :values => ['7', '3', '4'] }},
157 '!7|3|4' => { :op => '!', :values => ['7', '3', '4'] }},
158 'subject' => {
158 'subject' => {
159 'This is a subject' => { :op => '=', :values => ['This is a subject'] },
159 'This is a subject' => { :op => '=', :values => ['This is a subject'] },
160 'o' => { :op => '=', :values => ['o'] },
160 'o' => { :op => '=', :values => ['o'] },
161 '~This is part of a subject' => { :op => '~', :values => ['This is part of a subject'] },
161 '~This is part of a subject' => { :op => '~', :values => ['This is part of a subject'] },
162 '!~This is part of a subject' => { :op => '!~', :values => ['This is part of a subject'] }},
162 '!~This is part of a subject' => { :op => '!~', :values => ['This is part of a subject'] }},
163 'tracker_id' => {
163 'tracker_id' => {
164 '3' => { :op => '=', :values => ['3'] },
164 '3' => { :op => '=', :values => ['3'] },
165 '=3' => { :op => '=', :values => ['3'] }},
165 '=3' => { :op => '=', :values => ['3'] }},
166 'start_date' => {
166 'start_date' => {
167 '2011-10-12' => { :op => '=', :values => ['2011-10-12'] },
167 '2011-10-12' => { :op => '=', :values => ['2011-10-12'] },
168 '=2011-10-12' => { :op => '=', :values => ['2011-10-12'] },
168 '=2011-10-12' => { :op => '=', :values => ['2011-10-12'] },
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-01|2011-10-30' => { :op => '><', :values => ['2011-10-01', '2011-10-30'] },
171 '><2011-10-01|2011-10-30' => { :op => '><', :values => ['2011-10-01', '2011-10-30'] },
172 '<t+2' => { :op => '<t+', :values => ['2'] },
172 '<t+2' => { :op => '<t+', :values => ['2'] },
173 '>t+2' => { :op => '>t+', :values => ['2'] },
173 '>t+2' => { :op => '>t+', :values => ['2'] },
174 't+2' => { :op => 't+', :values => ['2'] },
174 't+2' => { :op => 't+', :values => ['2'] },
175 't' => { :op => 't', :values => [''] },
175 't' => { :op => 't', :values => [''] },
176 'w' => { :op => 'w', :values => [''] },
176 'w' => { :op => 'w', :values => [''] },
177 '>t-2' => { :op => '>t-', :values => ['2'] },
177 '>t-2' => { :op => '>t-', :values => ['2'] },
178 '<t-2' => { :op => '<t-', :values => ['2'] },
178 '<t-2' => { :op => '<t-', :values => ['2'] },
179 't-2' => { :op => 't-', :values => ['2'] }},
179 't-2' => { :op => 't-', :values => ['2'] }},
180 'created_on' => {
180 'created_on' => {
181 '>=2011-10-12' => { :op => '>=', :values => ['2011-10-12'] },
181 '>=2011-10-12' => { :op => '>=', :values => ['2011-10-12'] },
182 '<t+2' => { :op => '=', :values => ['<t+2'] },
182 '<t+2' => { :op => '=', :values => ['<t+2'] },
183 '>t+2' => { :op => '=', :values => ['>t+2'] },
183 '>t+2' => { :op => '=', :values => ['>t+2'] },
184 't+2' => { :op => 't', :values => ['+2'] }},
184 't+2' => { :op => 't', :values => ['+2'] }},
185 'cf_1' => {
185 'cf_1' => {
186 'c' => { :op => '=', :values => ['c'] },
186 'c' => { :op => '=', :values => ['c'] },
187 '!c' => { :op => '!', :values => ['c'] },
187 '!c' => { :op => '!', :values => ['c'] },
188 '!*' => { :op => '!*', :values => [''] },
188 '!*' => { :op => '!*', :values => [''] },
189 '*' => { :op => '*', :values => [''] }},
189 '*' => { :op => '*', :values => [''] }},
190 'estimated_hours' => {
190 'estimated_hours' => {
191 '=13.4' => { :op => '=', :values => ['13.4'] },
191 '=13.4' => { :op => '=', :values => ['13.4'] },
192 '>=45' => { :op => '>=', :values => ['45'] },
192 '>=45' => { :op => '>=', :values => ['45'] },
193 '<=125' => { :op => '<=', :values => ['125'] },
193 '<=125' => { :op => '<=', :values => ['125'] },
194 '><10.5|20.5' => { :op => '><', :values => ['10.5', '20.5'] },
194 '><10.5|20.5' => { :op => '><', :values => ['10.5', '20.5'] },
195 '!*' => { :op => '!*', :values => [''] },
195 '!*' => { :op => '!*', :values => [''] },
196 '*' => { :op => '*', :values => [''] }}
196 '*' => { :op => '*', :values => [''] }}
197 }
197 }
198
198
199 default_filter = { 'status_id' => {:operator => 'o', :values => [''] }}
199 default_filter = { 'status_id' => {:operator => 'o', :values => [''] }}
200
200
201 to_test.each do |field, expression_and_expected|
201 to_test.each do |field, expression_and_expected|
202 expression_and_expected.each do |filter_expression, expected|
202 expression_and_expected.each do |filter_expression, expected|
203
203
204 get :index, :set_filter => 1, field => filter_expression
204 get :index, :set_filter => 1, field => filter_expression
205
205
206 assert_response :success
206 assert_response :success
207 assert_template 'index'
207 assert_template 'index'
208 assert_not_nil assigns(:issues)
208 assert_not_nil assigns(:issues)
209
209
210 query = assigns(:query)
210 query = assigns(:query)
211 assert_not_nil query
211 assert_not_nil query
212 assert query.has_filter?(field)
212 assert query.has_filter?(field)
213 assert_equal(default_filter.merge({field => {:operator => expected[:op], :values => expected[:values]}}), query.filters)
213 assert_equal(default_filter.merge({field => {:operator => expected[:op], :values => expected[:values]}}), query.filters)
214 end
214 end
215 end
215 end
216
216
217 end
217 end
218
218
219 def test_index_with_project_and_empty_filters
219 def test_index_with_project_and_empty_filters
220 get :index, :project_id => 1, :set_filter => 1, :fields => ['']
220 get :index, :project_id => 1, :set_filter => 1, :fields => ['']
221 assert_response :success
221 assert_response :success
222 assert_template 'index'
222 assert_template 'index'
223 assert_not_nil assigns(:issues)
223 assert_not_nil assigns(:issues)
224
224
225 query = assigns(:query)
225 query = assigns(:query)
226 assert_not_nil query
226 assert_not_nil query
227 # no filter
227 # no filter
228 assert_equal({}, query.filters)
228 assert_equal({}, query.filters)
229 end
229 end
230
230
231 def test_index_with_query
231 def test_index_with_query
232 get :index, :project_id => 1, :query_id => 5
232 get :index, :project_id => 1, :query_id => 5
233 assert_response :success
233 assert_response :success
234 assert_template 'index'
234 assert_template 'index'
235 assert_not_nil assigns(:issues)
235 assert_not_nil assigns(:issues)
236 assert_nil assigns(:issue_count_by_group)
236 assert_nil assigns(:issue_count_by_group)
237 end
237 end
238
238
239 def test_index_with_query_grouped_by_tracker
239 def test_index_with_query_grouped_by_tracker
240 get :index, :project_id => 1, :query_id => 6
240 get :index, :project_id => 1, :query_id => 6
241 assert_response :success
241 assert_response :success
242 assert_template 'index'
242 assert_template 'index'
243 assert_not_nil assigns(:issues)
243 assert_not_nil assigns(:issues)
244 assert_not_nil assigns(:issue_count_by_group)
244 assert_not_nil assigns(:issue_count_by_group)
245 end
245 end
246
246
247 def test_index_with_query_grouped_by_list_custom_field
247 def test_index_with_query_grouped_by_list_custom_field
248 get :index, :project_id => 1, :query_id => 9
248 get :index, :project_id => 1, :query_id => 9
249 assert_response :success
249 assert_response :success
250 assert_template 'index'
250 assert_template 'index'
251 assert_not_nil assigns(:issues)
251 assert_not_nil assigns(:issues)
252 assert_not_nil assigns(:issue_count_by_group)
252 assert_not_nil assigns(:issue_count_by_group)
253 end
253 end
254
254
255 def test_private_query_should_not_be_available_to_other_users
255 def test_private_query_should_not_be_available_to_other_users
256 q = Query.create!(:name => "private", :user => User.find(2), :is_public => false, :project => nil)
256 q = Query.create!(:name => "private", :user => User.find(2), :is_public => false, :project => nil)
257 @request.session[:user_id] = 3
257 @request.session[:user_id] = 3
258
258
259 get :index, :query_id => q.id
259 get :index, :query_id => q.id
260 assert_response 403
260 assert_response 403
261 end
261 end
262
262
263 def test_private_query_should_be_available_to_its_user
263 def test_private_query_should_be_available_to_its_user
264 q = Query.create!(:name => "private", :user => User.find(2), :is_public => false, :project => nil)
264 q = Query.create!(:name => "private", :user => User.find(2), :is_public => false, :project => nil)
265 @request.session[:user_id] = 2
265 @request.session[:user_id] = 2
266
266
267 get :index, :query_id => q.id
267 get :index, :query_id => q.id
268 assert_response :success
268 assert_response :success
269 end
269 end
270
270
271 def test_public_query_should_be_available_to_other_users
271 def test_public_query_should_be_available_to_other_users
272 q = Query.create!(:name => "private", :user => User.find(2), :is_public => true, :project => nil)
272 q = Query.create!(:name => "private", :user => User.find(2), :is_public => true, :project => nil)
273 @request.session[:user_id] = 3
273 @request.session[:user_id] = 3
274
274
275 get :index, :query_id => q.id
275 get :index, :query_id => q.id
276 assert_response :success
276 assert_response :success
277 end
277 end
278
278
279 def test_index_sort_by_field_not_included_in_columns
279 def test_index_sort_by_field_not_included_in_columns
280 Setting.issue_list_default_columns = %w(subject author)
280 Setting.issue_list_default_columns = %w(subject author)
281 get :index, :sort => 'tracker'
281 get :index, :sort => 'tracker'
282 end
282 end
283
283
284 def test_index_csv_with_project
284 def test_index_csv_with_project
285 Setting.default_language = 'en'
285 Setting.default_language = 'en'
286
286
287 get :index, :format => 'csv'
287 get :index, :format => 'csv'
288 assert_response :success
288 assert_response :success
289 assert_not_nil assigns(:issues)
289 assert_not_nil assigns(:issues)
290 assert_equal 'text/csv', @response.content_type
290 assert_equal 'text/csv', @response.content_type
291 assert @response.body.starts_with?("#,")
291 assert @response.body.starts_with?("#,")
292
292
293 get :index, :project_id => 1, :format => 'csv'
293 get :index, :project_id => 1, :format => 'csv'
294 assert_response :success
294 assert_response :success
295 assert_not_nil assigns(:issues)
295 assert_not_nil assigns(:issues)
296 assert_equal 'text/csv', @response.content_type
296 assert_equal 'text/csv', @response.content_type
297 end
297 end
298
298
299 def test_index_csv_big_5
299 def test_index_csv_big_5
300 with_settings :default_language => "zh-TW" do
300 with_settings :default_language => "zh-TW" do
301 str_utf8 = "\xe4\xb8\x80\xe6\x9c\x88"
301 str_utf8 = "\xe4\xb8\x80\xe6\x9c\x88"
302 str_big5 = "\xa4@\xa4\xeb"
302 str_big5 = "\xa4@\xa4\xeb"
303 if str_utf8.respond_to?(:force_encoding)
303 if str_utf8.respond_to?(:force_encoding)
304 str_utf8.force_encoding('UTF-8')
304 str_utf8.force_encoding('UTF-8')
305 str_big5.force_encoding('Big5')
305 str_big5.force_encoding('Big5')
306 end
306 end
307 issue = Issue.new(:project_id => 1, :tracker_id => 1, :author_id => 3,
307 issue = Issue.new(:project_id => 1, :tracker_id => 1, :author_id => 3,
308 :status_id => 1, :priority => IssuePriority.all.first,
308 :status_id => 1, :priority => IssuePriority.all.first,
309 :subject => str_utf8)
309 :subject => str_utf8)
310 assert issue.save
310 assert issue.save
311
311
312 get :index, :project_id => 1,
312 get :index, :project_id => 1,
313 :f => ['subject'],
313 :f => ['subject'],
314 :op => '=', :values => [str_utf8],
314 :op => '=', :values => [str_utf8],
315 :format => 'csv'
315 :format => 'csv'
316 assert_equal 'text/csv', @response.content_type
316 assert_equal 'text/csv', @response.content_type
317 lines = @response.body.chomp.split("\n")
317 lines = @response.body.chomp.split("\n")
318 s1 = "\xaa\xac\xbaA"
318 s1 = "\xaa\xac\xbaA"
319 if str_utf8.respond_to?(:force_encoding)
319 if str_utf8.respond_to?(:force_encoding)
320 s1.force_encoding('Big5')
320 s1.force_encoding('Big5')
321 end
321 end
322 assert lines[0].include?(s1)
322 assert lines[0].include?(s1)
323 assert lines[1].include?(str_big5)
323 assert lines[1].include?(str_big5)
324 end
324 end
325 end
325 end
326
326
327 def test_index_csv_cannot_convert_should_be_replaced_big_5
328 with_settings :default_language => "zh-TW" do
329 str_utf8 = "\xe4\xbb\xa5\xe5\x86\x85"
330 if str_utf8.respond_to?(:force_encoding)
331 str_utf8.force_encoding('UTF-8')
332 end
333 issue = Issue.new(:project_id => 1, :tracker_id => 1, :author_id => 3,
334 :status_id => 1, :priority => IssuePriority.all.first,
335 :subject => str_utf8)
336 assert issue.save
337
338 get :index, :project_id => 1,
339 :f => ['subject'],
340 :op => '=', :values => [str_utf8],
341 :format => 'csv'
342 assert_equal 'text/csv', @response.content_type
343 lines = @response.body.chomp.split("\n")
344 s1 = "\xaa\xac\xbaA"
345 if str_utf8.respond_to?(:force_encoding)
346 s1.force_encoding('Big5')
347 end
348 assert lines[0].include?(s1)
349 s2 = lines[1].split(",")[5]
350 if s1.respond_to?(:force_encoding)
351 s3 = "\xa5H?"
352 s3.force_encoding('Big5')
353 assert_equal s3, s2
354 elsif RUBY_PLATFORM == 'java'
355 assert_equal "??", s2
356 else
357 assert_equal "\xa5H???", s2
358 end
359 end
360 end
361
327 def test_index_pdf
362 def test_index_pdf
328 get :index, :format => 'pdf'
363 get :index, :format => 'pdf'
329 assert_response :success
364 assert_response :success
330 assert_not_nil assigns(:issues)
365 assert_not_nil assigns(:issues)
331 assert_equal 'application/pdf', @response.content_type
366 assert_equal 'application/pdf', @response.content_type
332
367
333 get :index, :project_id => 1, :format => 'pdf'
368 get :index, :project_id => 1, :format => 'pdf'
334 assert_response :success
369 assert_response :success
335 assert_not_nil assigns(:issues)
370 assert_not_nil assigns(:issues)
336 assert_equal 'application/pdf', @response.content_type
371 assert_equal 'application/pdf', @response.content_type
337
372
338 get :index, :project_id => 1, :query_id => 6, :format => 'pdf'
373 get :index, :project_id => 1, :query_id => 6, :format => 'pdf'
339 assert_response :success
374 assert_response :success
340 assert_not_nil assigns(:issues)
375 assert_not_nil assigns(:issues)
341 assert_equal 'application/pdf', @response.content_type
376 assert_equal 'application/pdf', @response.content_type
342 end
377 end
343
378
344 def test_index_pdf_with_query_grouped_by_list_custom_field
379 def test_index_pdf_with_query_grouped_by_list_custom_field
345 get :index, :project_id => 1, :query_id => 9, :format => 'pdf'
380 get :index, :project_id => 1, :query_id => 9, :format => 'pdf'
346 assert_response :success
381 assert_response :success
347 assert_not_nil assigns(:issues)
382 assert_not_nil assigns(:issues)
348 assert_not_nil assigns(:issue_count_by_group)
383 assert_not_nil assigns(:issue_count_by_group)
349 assert_equal 'application/pdf', @response.content_type
384 assert_equal 'application/pdf', @response.content_type
350 end
385 end
351
386
352 def test_index_sort
387 def test_index_sort
353 get :index, :sort => 'tracker,id:desc'
388 get :index, :sort => 'tracker,id:desc'
354 assert_response :success
389 assert_response :success
355
390
356 sort_params = @request.session['issues_index_sort']
391 sort_params = @request.session['issues_index_sort']
357 assert sort_params.is_a?(String)
392 assert sort_params.is_a?(String)
358 assert_equal 'tracker,id:desc', sort_params
393 assert_equal 'tracker,id:desc', sort_params
359
394
360 issues = assigns(:issues)
395 issues = assigns(:issues)
361 assert_not_nil issues
396 assert_not_nil issues
362 assert !issues.empty?
397 assert !issues.empty?
363 assert_equal issues.sort {|a,b| a.tracker == b.tracker ? b.id <=> a.id : a.tracker <=> b.tracker }.collect(&:id), issues.collect(&:id)
398 assert_equal issues.sort {|a,b| a.tracker == b.tracker ? b.id <=> a.id : a.tracker <=> b.tracker }.collect(&:id), issues.collect(&:id)
364 end
399 end
365
400
366 def test_index_with_columns
401 def test_index_with_columns
367 columns = ['tracker', 'subject', 'assigned_to']
402 columns = ['tracker', 'subject', 'assigned_to']
368 get :index, :set_filter => 1, :c => columns
403 get :index, :set_filter => 1, :c => columns
369 assert_response :success
404 assert_response :success
370
405
371 # query should use specified columns
406 # query should use specified columns
372 query = assigns(:query)
407 query = assigns(:query)
373 assert_kind_of Query, query
408 assert_kind_of Query, query
374 assert_equal columns, query.column_names.map(&:to_s)
409 assert_equal columns, query.column_names.map(&:to_s)
375
410
376 # columns should be stored in session
411 # columns should be stored in session
377 assert_kind_of Hash, session[:query]
412 assert_kind_of Hash, session[:query]
378 assert_kind_of Array, session[:query][:column_names]
413 assert_kind_of Array, session[:query][:column_names]
379 assert_equal columns, session[:query][:column_names].map(&:to_s)
414 assert_equal columns, session[:query][:column_names].map(&:to_s)
380
415
381 # ensure only these columns are kept in the selected columns list
416 # ensure only these columns are kept in the selected columns list
382 assert_tag :tag => 'select', :attributes => { :id => 'selected_columns' },
417 assert_tag :tag => 'select', :attributes => { :id => 'selected_columns' },
383 :children => { :count => 3 }
418 :children => { :count => 3 }
384 assert_no_tag :tag => 'option', :attributes => { :value => 'project' },
419 assert_no_tag :tag => 'option', :attributes => { :value => 'project' },
385 :parent => { :tag => 'select', :attributes => { :id => "selected_columns" } }
420 :parent => { :tag => 'select', :attributes => { :id => "selected_columns" } }
386 end
421 end
387
422
388 def test_index_without_project_should_implicitly_add_project_column_to_default_columns
423 def test_index_without_project_should_implicitly_add_project_column_to_default_columns
389 Setting.issue_list_default_columns = ['tracker', 'subject', 'assigned_to']
424 Setting.issue_list_default_columns = ['tracker', 'subject', 'assigned_to']
390 get :index, :set_filter => 1
425 get :index, :set_filter => 1
391
426
392 # query should use specified columns
427 # query should use specified columns
393 query = assigns(:query)
428 query = assigns(:query)
394 assert_kind_of Query, query
429 assert_kind_of Query, query
395 assert_equal [:project, :tracker, :subject, :assigned_to], query.columns.map(&:name)
430 assert_equal [:project, :tracker, :subject, :assigned_to], query.columns.map(&:name)
396 end
431 end
397
432
398 def test_index_without_project_and_explicit_default_columns_should_not_add_project_column
433 def test_index_without_project_and_explicit_default_columns_should_not_add_project_column
399 Setting.issue_list_default_columns = ['tracker', 'subject', 'assigned_to']
434 Setting.issue_list_default_columns = ['tracker', 'subject', 'assigned_to']
400 columns = ['tracker', 'subject', 'assigned_to']
435 columns = ['tracker', 'subject', 'assigned_to']
401 get :index, :set_filter => 1, :c => columns
436 get :index, :set_filter => 1, :c => columns
402
437
403 # query should use specified columns
438 # query should use specified columns
404 query = assigns(:query)
439 query = assigns(:query)
405 assert_kind_of Query, query
440 assert_kind_of Query, query
406 assert_equal columns.map(&:to_sym), query.columns.map(&:name)
441 assert_equal columns.map(&:to_sym), query.columns.map(&:name)
407 end
442 end
408
443
409 def test_index_with_custom_field_column
444 def test_index_with_custom_field_column
410 columns = %w(tracker subject cf_2)
445 columns = %w(tracker subject cf_2)
411 get :index, :set_filter => 1, :c => columns
446 get :index, :set_filter => 1, :c => columns
412 assert_response :success
447 assert_response :success
413
448
414 # query should use specified columns
449 # query should use specified columns
415 query = assigns(:query)
450 query = assigns(:query)
416 assert_kind_of Query, query
451 assert_kind_of Query, query
417 assert_equal columns, query.column_names.map(&:to_s)
452 assert_equal columns, query.column_names.map(&:to_s)
418
453
419 assert_tag :td,
454 assert_tag :td,
420 :attributes => {:class => 'cf_2 string'},
455 :attributes => {:class => 'cf_2 string'},
421 :ancestor => {:tag => 'table', :attributes => {:class => /issues/}}
456 :ancestor => {:tag => 'table', :attributes => {:class => /issues/}}
422 end
457 end
423
458
424 def test_index_send_html_if_query_is_invalid
459 def test_index_send_html_if_query_is_invalid
425 get :index, :f => ['start_date'], :op => {:start_date => '='}
460 get :index, :f => ['start_date'], :op => {:start_date => '='}
426 assert_equal 'text/html', @response.content_type
461 assert_equal 'text/html', @response.content_type
427 assert_template 'index'
462 assert_template 'index'
428 end
463 end
429
464
430 def test_index_send_nothing_if_query_is_invalid
465 def test_index_send_nothing_if_query_is_invalid
431 get :index, :f => ['start_date'], :op => {:start_date => '='}, :format => 'csv'
466 get :index, :f => ['start_date'], :op => {:start_date => '='}, :format => 'csv'
432 assert_equal 'text/csv', @response.content_type
467 assert_equal 'text/csv', @response.content_type
433 assert @response.body.blank?
468 assert @response.body.blank?
434 end
469 end
435
470
436 def test_show_by_anonymous
471 def test_show_by_anonymous
437 get :show, :id => 1
472 get :show, :id => 1
438 assert_response :success
473 assert_response :success
439 assert_template 'show'
474 assert_template 'show'
440 assert_not_nil assigns(:issue)
475 assert_not_nil assigns(:issue)
441 assert_equal Issue.find(1), assigns(:issue)
476 assert_equal Issue.find(1), assigns(:issue)
442
477
443 # anonymous role is allowed to add a note
478 # anonymous role is allowed to add a note
444 assert_tag :tag => 'form',
479 assert_tag :tag => 'form',
445 :descendant => { :tag => 'fieldset',
480 :descendant => { :tag => 'fieldset',
446 :child => { :tag => 'legend',
481 :child => { :tag => 'legend',
447 :content => /Notes/ } }
482 :content => /Notes/ } }
448 end
483 end
449
484
450 def test_show_by_manager
485 def test_show_by_manager
451 @request.session[:user_id] = 2
486 @request.session[:user_id] = 2
452 get :show, :id => 1
487 get :show, :id => 1
453 assert_response :success
488 assert_response :success
454
489
455 assert_tag :tag => 'a',
490 assert_tag :tag => 'a',
456 :content => /Quote/
491 :content => /Quote/
457
492
458 assert_tag :tag => 'form',
493 assert_tag :tag => 'form',
459 :descendant => { :tag => 'fieldset',
494 :descendant => { :tag => 'fieldset',
460 :child => { :tag => 'legend',
495 :child => { :tag => 'legend',
461 :content => /Change properties/ } },
496 :content => /Change properties/ } },
462 :descendant => { :tag => 'fieldset',
497 :descendant => { :tag => 'fieldset',
463 :child => { :tag => 'legend',
498 :child => { :tag => 'legend',
464 :content => /Log time/ } },
499 :content => /Log time/ } },
465 :descendant => { :tag => 'fieldset',
500 :descendant => { :tag => 'fieldset',
466 :child => { :tag => 'legend',
501 :child => { :tag => 'legend',
467 :content => /Notes/ } }
502 :content => /Notes/ } }
468 end
503 end
469
504
470 def test_update_form_should_not_display_inactive_enumerations
505 def test_update_form_should_not_display_inactive_enumerations
471 @request.session[:user_id] = 2
506 @request.session[:user_id] = 2
472 get :show, :id => 1
507 get :show, :id => 1
473 assert_response :success
508 assert_response :success
474
509
475 assert ! IssuePriority.find(15).active?
510 assert ! IssuePriority.find(15).active?
476 assert_no_tag :option, :attributes => {:value => '15'},
511 assert_no_tag :option, :attributes => {:value => '15'},
477 :parent => {:tag => 'select', :attributes => {:id => 'issue_priority_id'} }
512 :parent => {:tag => 'select', :attributes => {:id => 'issue_priority_id'} }
478 end
513 end
479
514
480 def test_update_form_should_allow_attachment_upload
515 def test_update_form_should_allow_attachment_upload
481 @request.session[:user_id] = 2
516 @request.session[:user_id] = 2
482 get :show, :id => 1
517 get :show, :id => 1
483
518
484 assert_tag :tag => 'form',
519 assert_tag :tag => 'form',
485 :attributes => {:id => 'issue-form', :method => 'post', :enctype => 'multipart/form-data'},
520 :attributes => {:id => 'issue-form', :method => 'post', :enctype => 'multipart/form-data'},
486 :descendant => {
521 :descendant => {
487 :tag => 'input',
522 :tag => 'input',
488 :attributes => {:type => 'file', :name => 'attachments[1][file]'}
523 :attributes => {:type => 'file', :name => 'attachments[1][file]'}
489 }
524 }
490 end
525 end
491
526
492 def test_show_should_deny_anonymous_access_without_permission
527 def test_show_should_deny_anonymous_access_without_permission
493 Role.anonymous.remove_permission!(:view_issues)
528 Role.anonymous.remove_permission!(:view_issues)
494 get :show, :id => 1
529 get :show, :id => 1
495 assert_response :redirect
530 assert_response :redirect
496 end
531 end
497
532
498 def test_show_should_deny_anonymous_access_to_private_issue
533 def test_show_should_deny_anonymous_access_to_private_issue
499 Issue.update_all(["is_private = ?", true], "id = 1")
534 Issue.update_all(["is_private = ?", true], "id = 1")
500 get :show, :id => 1
535 get :show, :id => 1
501 assert_response :redirect
536 assert_response :redirect
502 end
537 end
503
538
504 def test_show_should_deny_non_member_access_without_permission
539 def test_show_should_deny_non_member_access_without_permission
505 Role.non_member.remove_permission!(:view_issues)
540 Role.non_member.remove_permission!(:view_issues)
506 @request.session[:user_id] = 9
541 @request.session[:user_id] = 9
507 get :show, :id => 1
542 get :show, :id => 1
508 assert_response 403
543 assert_response 403
509 end
544 end
510
545
511 def test_show_should_deny_non_member_access_to_private_issue
546 def test_show_should_deny_non_member_access_to_private_issue
512 Issue.update_all(["is_private = ?", true], "id = 1")
547 Issue.update_all(["is_private = ?", true], "id = 1")
513 @request.session[:user_id] = 9
548 @request.session[:user_id] = 9
514 get :show, :id => 1
549 get :show, :id => 1
515 assert_response 403
550 assert_response 403
516 end
551 end
517
552
518 def test_show_should_deny_member_access_without_permission
553 def test_show_should_deny_member_access_without_permission
519 Role.find(1).remove_permission!(:view_issues)
554 Role.find(1).remove_permission!(:view_issues)
520 @request.session[:user_id] = 2
555 @request.session[:user_id] = 2
521 get :show, :id => 1
556 get :show, :id => 1
522 assert_response 403
557 assert_response 403
523 end
558 end
524
559
525 def test_show_should_deny_member_access_to_private_issue_without_permission
560 def test_show_should_deny_member_access_to_private_issue_without_permission
526 Issue.update_all(["is_private = ?", true], "id = 1")
561 Issue.update_all(["is_private = ?", true], "id = 1")
527 @request.session[:user_id] = 3
562 @request.session[:user_id] = 3
528 get :show, :id => 1
563 get :show, :id => 1
529 assert_response 403
564 assert_response 403
530 end
565 end
531
566
532 def test_show_should_allow_author_access_to_private_issue
567 def test_show_should_allow_author_access_to_private_issue
533 Issue.update_all(["is_private = ?, author_id = 3", true], "id = 1")
568 Issue.update_all(["is_private = ?, author_id = 3", true], "id = 1")
534 @request.session[:user_id] = 3
569 @request.session[:user_id] = 3
535 get :show, :id => 1
570 get :show, :id => 1
536 assert_response :success
571 assert_response :success
537 end
572 end
538
573
539 def test_show_should_allow_assignee_access_to_private_issue
574 def test_show_should_allow_assignee_access_to_private_issue
540 Issue.update_all(["is_private = ?, assigned_to_id = 3", true], "id = 1")
575 Issue.update_all(["is_private = ?, assigned_to_id = 3", true], "id = 1")
541 @request.session[:user_id] = 3
576 @request.session[:user_id] = 3
542 get :show, :id => 1
577 get :show, :id => 1
543 assert_response :success
578 assert_response :success
544 end
579 end
545
580
546 def test_show_should_allow_member_access_to_private_issue_with_permission
581 def test_show_should_allow_member_access_to_private_issue_with_permission
547 Issue.update_all(["is_private = ?", true], "id = 1")
582 Issue.update_all(["is_private = ?", true], "id = 1")
548 User.find(3).roles_for_project(Project.find(1)).first.update_attribute :issues_visibility, 'all'
583 User.find(3).roles_for_project(Project.find(1)).first.update_attribute :issues_visibility, 'all'
549 @request.session[:user_id] = 3
584 @request.session[:user_id] = 3
550 get :show, :id => 1
585 get :show, :id => 1
551 assert_response :success
586 assert_response :success
552 end
587 end
553
588
554 def test_show_should_not_disclose_relations_to_invisible_issues
589 def test_show_should_not_disclose_relations_to_invisible_issues
555 Setting.cross_project_issue_relations = '1'
590 Setting.cross_project_issue_relations = '1'
556 IssueRelation.create!(:issue_from => Issue.find(1), :issue_to => Issue.find(2), :relation_type => 'relates')
591 IssueRelation.create!(:issue_from => Issue.find(1), :issue_to => Issue.find(2), :relation_type => 'relates')
557 # Relation to a private project issue
592 # Relation to a private project issue
558 IssueRelation.create!(:issue_from => Issue.find(1), :issue_to => Issue.find(4), :relation_type => 'relates')
593 IssueRelation.create!(:issue_from => Issue.find(1), :issue_to => Issue.find(4), :relation_type => 'relates')
559
594
560 get :show, :id => 1
595 get :show, :id => 1
561 assert_response :success
596 assert_response :success
562
597
563 assert_tag :div, :attributes => { :id => 'relations' },
598 assert_tag :div, :attributes => { :id => 'relations' },
564 :descendant => { :tag => 'a', :content => /#2$/ }
599 :descendant => { :tag => 'a', :content => /#2$/ }
565 assert_no_tag :div, :attributes => { :id => 'relations' },
600 assert_no_tag :div, :attributes => { :id => 'relations' },
566 :descendant => { :tag => 'a', :content => /#4$/ }
601 :descendant => { :tag => 'a', :content => /#4$/ }
567 end
602 end
568
603
569 def test_show_atom
604 def test_show_atom
570 get :show, :id => 2, :format => 'atom'
605 get :show, :id => 2, :format => 'atom'
571 assert_response :success
606 assert_response :success
572 assert_template 'journals/index'
607 assert_template 'journals/index'
573 # Inline image
608 # Inline image
574 assert_select 'content', :text => Regexp.new(Regexp.quote('http://test.host/attachments/download/10'))
609 assert_select 'content', :text => Regexp.new(Regexp.quote('http://test.host/attachments/download/10'))
575 end
610 end
576
611
577 def test_show_export_to_pdf
612 def test_show_export_to_pdf
578 get :show, :id => 3, :format => 'pdf'
613 get :show, :id => 3, :format => 'pdf'
579 assert_response :success
614 assert_response :success
580 assert_equal 'application/pdf', @response.content_type
615 assert_equal 'application/pdf', @response.content_type
581 assert @response.body.starts_with?('%PDF')
616 assert @response.body.starts_with?('%PDF')
582 assert_not_nil assigns(:issue)
617 assert_not_nil assigns(:issue)
583 end
618 end
584
619
585 def test_get_new
620 def test_get_new
586 @request.session[:user_id] = 2
621 @request.session[:user_id] = 2
587 get :new, :project_id => 1, :tracker_id => 1
622 get :new, :project_id => 1, :tracker_id => 1
588 assert_response :success
623 assert_response :success
589 assert_template 'new'
624 assert_template 'new'
590
625
591 assert_tag :tag => 'input', :attributes => { :name => 'issue[custom_field_values][2]',
626 assert_tag :tag => 'input', :attributes => { :name => 'issue[custom_field_values][2]',
592 :value => 'Default string' }
627 :value => 'Default string' }
593
628
594 # Be sure we don't display inactive IssuePriorities
629 # Be sure we don't display inactive IssuePriorities
595 assert ! IssuePriority.find(15).active?
630 assert ! IssuePriority.find(15).active?
596 assert_no_tag :option, :attributes => {:value => '15'},
631 assert_no_tag :option, :attributes => {:value => '15'},
597 :parent => {:tag => 'select', :attributes => {:id => 'issue_priority_id'} }
632 :parent => {:tag => 'select', :attributes => {:id => 'issue_priority_id'} }
598 end
633 end
599
634
600 def test_get_new_without_default_start_date_is_creation_date
635 def test_get_new_without_default_start_date_is_creation_date
601 Setting.default_issue_start_date_to_creation_date = 0
636 Setting.default_issue_start_date_to_creation_date = 0
602
637
603 @request.session[:user_id] = 2
638 @request.session[:user_id] = 2
604 get :new, :project_id => 1, :tracker_id => 1
639 get :new, :project_id => 1, :tracker_id => 1
605 assert_response :success
640 assert_response :success
606 assert_template 'new'
641 assert_template 'new'
607
642
608 assert_tag :tag => 'input', :attributes => { :name => 'issue[start_date]',
643 assert_tag :tag => 'input', :attributes => { :name => 'issue[start_date]',
609 :value => nil }
644 :value => nil }
610 end
645 end
611
646
612 def test_get_new_with_default_start_date_is_creation_date
647 def test_get_new_with_default_start_date_is_creation_date
613 Setting.default_issue_start_date_to_creation_date = 1
648 Setting.default_issue_start_date_to_creation_date = 1
614
649
615 @request.session[:user_id] = 2
650 @request.session[:user_id] = 2
616 get :new, :project_id => 1, :tracker_id => 1
651 get :new, :project_id => 1, :tracker_id => 1
617 assert_response :success
652 assert_response :success
618 assert_template 'new'
653 assert_template 'new'
619
654
620 assert_tag :tag => 'input', :attributes => { :name => 'issue[start_date]',
655 assert_tag :tag => 'input', :attributes => { :name => 'issue[start_date]',
621 :value => Date.today.to_s }
656 :value => Date.today.to_s }
622 end
657 end
623
658
624 def test_get_new_form_should_allow_attachment_upload
659 def test_get_new_form_should_allow_attachment_upload
625 @request.session[:user_id] = 2
660 @request.session[:user_id] = 2
626 get :new, :project_id => 1, :tracker_id => 1
661 get :new, :project_id => 1, :tracker_id => 1
627
662
628 assert_tag :tag => 'form',
663 assert_tag :tag => 'form',
629 :attributes => {:id => 'issue-form', :method => 'post', :enctype => 'multipart/form-data'},
664 :attributes => {:id => 'issue-form', :method => 'post', :enctype => 'multipart/form-data'},
630 :descendant => {
665 :descendant => {
631 :tag => 'input',
666 :tag => 'input',
632 :attributes => {:type => 'file', :name => 'attachments[1][file]'}
667 :attributes => {:type => 'file', :name => 'attachments[1][file]'}
633 }
668 }
634 end
669 end
635
670
636 def test_get_new_without_tracker_id
671 def test_get_new_without_tracker_id
637 @request.session[:user_id] = 2
672 @request.session[:user_id] = 2
638 get :new, :project_id => 1
673 get :new, :project_id => 1
639 assert_response :success
674 assert_response :success
640 assert_template 'new'
675 assert_template 'new'
641
676
642 issue = assigns(:issue)
677 issue = assigns(:issue)
643 assert_not_nil issue
678 assert_not_nil issue
644 assert_equal Project.find(1).trackers.first, issue.tracker
679 assert_equal Project.find(1).trackers.first, issue.tracker
645 end
680 end
646
681
647 def test_get_new_with_no_default_status_should_display_an_error
682 def test_get_new_with_no_default_status_should_display_an_error
648 @request.session[:user_id] = 2
683 @request.session[:user_id] = 2
649 IssueStatus.delete_all
684 IssueStatus.delete_all
650
685
651 get :new, :project_id => 1
686 get :new, :project_id => 1
652 assert_response 500
687 assert_response 500
653 assert_error_tag :content => /No default issue/
688 assert_error_tag :content => /No default issue/
654 end
689 end
655
690
656 def test_get_new_with_no_tracker_should_display_an_error
691 def test_get_new_with_no_tracker_should_display_an_error
657 @request.session[:user_id] = 2
692 @request.session[:user_id] = 2
658 Tracker.delete_all
693 Tracker.delete_all
659
694
660 get :new, :project_id => 1
695 get :new, :project_id => 1
661 assert_response 500
696 assert_response 500
662 assert_error_tag :content => /No tracker/
697 assert_error_tag :content => /No tracker/
663 end
698 end
664
699
665 def test_update_new_form
700 def test_update_new_form
666 @request.session[:user_id] = 2
701 @request.session[:user_id] = 2
667 xhr :post, :new, :project_id => 1,
702 xhr :post, :new, :project_id => 1,
668 :issue => {:tracker_id => 2,
703 :issue => {:tracker_id => 2,
669 :subject => 'This is the test_new issue',
704 :subject => 'This is the test_new issue',
670 :description => 'This is the description',
705 :description => 'This is the description',
671 :priority_id => 5}
706 :priority_id => 5}
672 assert_response :success
707 assert_response :success
673 assert_template 'attributes'
708 assert_template 'attributes'
674
709
675 issue = assigns(:issue)
710 issue = assigns(:issue)
676 assert_kind_of Issue, issue
711 assert_kind_of Issue, issue
677 assert_equal 1, issue.project_id
712 assert_equal 1, issue.project_id
678 assert_equal 2, issue.tracker_id
713 assert_equal 2, issue.tracker_id
679 assert_equal 'This is the test_new issue', issue.subject
714 assert_equal 'This is the test_new issue', issue.subject
680 end
715 end
681
716
682 def test_post_create
717 def test_post_create
683 @request.session[:user_id] = 2
718 @request.session[:user_id] = 2
684 assert_difference 'Issue.count' do
719 assert_difference 'Issue.count' do
685 post :create, :project_id => 1,
720 post :create, :project_id => 1,
686 :issue => {:tracker_id => 3,
721 :issue => {:tracker_id => 3,
687 :status_id => 2,
722 :status_id => 2,
688 :subject => 'This is the test_new issue',
723 :subject => 'This is the test_new issue',
689 :description => 'This is the description',
724 :description => 'This is the description',
690 :priority_id => 5,
725 :priority_id => 5,
691 :start_date => '2010-11-07',
726 :start_date => '2010-11-07',
692 :estimated_hours => '',
727 :estimated_hours => '',
693 :custom_field_values => {'2' => 'Value for field 2'}}
728 :custom_field_values => {'2' => 'Value for field 2'}}
694 end
729 end
695 assert_redirected_to :controller => 'issues', :action => 'show', :id => Issue.last.id
730 assert_redirected_to :controller => 'issues', :action => 'show', :id => Issue.last.id
696
731
697 issue = Issue.find_by_subject('This is the test_new issue')
732 issue = Issue.find_by_subject('This is the test_new issue')
698 assert_not_nil issue
733 assert_not_nil issue
699 assert_equal 2, issue.author_id
734 assert_equal 2, issue.author_id
700 assert_equal 3, issue.tracker_id
735 assert_equal 3, issue.tracker_id
701 assert_equal 2, issue.status_id
736 assert_equal 2, issue.status_id
702 assert_equal Date.parse('2010-11-07'), issue.start_date
737 assert_equal Date.parse('2010-11-07'), issue.start_date
703 assert_nil issue.estimated_hours
738 assert_nil issue.estimated_hours
704 v = issue.custom_values.find(:first, :conditions => {:custom_field_id => 2})
739 v = issue.custom_values.find(:first, :conditions => {:custom_field_id => 2})
705 assert_not_nil v
740 assert_not_nil v
706 assert_equal 'Value for field 2', v.value
741 assert_equal 'Value for field 2', v.value
707 end
742 end
708
743
709 def test_post_new_with_group_assignment
744 def test_post_new_with_group_assignment
710 group = Group.find(11)
745 group = Group.find(11)
711 project = Project.find(1)
746 project = Project.find(1)
712 project.members << Member.new(:principal => group, :roles => [Role.first])
747 project.members << Member.new(:principal => group, :roles => [Role.first])
713
748
714 with_settings :issue_group_assignment => '1' do
749 with_settings :issue_group_assignment => '1' do
715 @request.session[:user_id] = 2
750 @request.session[:user_id] = 2
716 assert_difference 'Issue.count' do
751 assert_difference 'Issue.count' do
717 post :create, :project_id => project.id,
752 post :create, :project_id => project.id,
718 :issue => {:tracker_id => 3,
753 :issue => {:tracker_id => 3,
719 :status_id => 1,
754 :status_id => 1,
720 :subject => 'This is the test_new_with_group_assignment issue',
755 :subject => 'This is the test_new_with_group_assignment issue',
721 :assigned_to_id => group.id}
756 :assigned_to_id => group.id}
722 end
757 end
723 end
758 end
724 assert_redirected_to :controller => 'issues', :action => 'show', :id => Issue.last.id
759 assert_redirected_to :controller => 'issues', :action => 'show', :id => Issue.last.id
725
760
726 issue = Issue.find_by_subject('This is the test_new_with_group_assignment issue')
761 issue = Issue.find_by_subject('This is the test_new_with_group_assignment issue')
727 assert_not_nil issue
762 assert_not_nil issue
728 assert_equal group, issue.assigned_to
763 assert_equal group, issue.assigned_to
729 end
764 end
730
765
731 def test_post_create_without_start_date_and_default_start_date_is_not_creation_date
766 def test_post_create_without_start_date_and_default_start_date_is_not_creation_date
732 Setting.default_issue_start_date_to_creation_date = 0
767 Setting.default_issue_start_date_to_creation_date = 0
733
768
734 @request.session[:user_id] = 2
769 @request.session[:user_id] = 2
735 assert_difference 'Issue.count' do
770 assert_difference 'Issue.count' do
736 post :create, :project_id => 1,
771 post :create, :project_id => 1,
737 :issue => {:tracker_id => 3,
772 :issue => {:tracker_id => 3,
738 :status_id => 2,
773 :status_id => 2,
739 :subject => 'This is the test_new issue',
774 :subject => 'This is the test_new issue',
740 :description => 'This is the description',
775 :description => 'This is the description',
741 :priority_id => 5,
776 :priority_id => 5,
742 :estimated_hours => '',
777 :estimated_hours => '',
743 :custom_field_values => {'2' => 'Value for field 2'}}
778 :custom_field_values => {'2' => 'Value for field 2'}}
744 end
779 end
745 assert_redirected_to :controller => 'issues', :action => 'show', :id => Issue.last.id
780 assert_redirected_to :controller => 'issues', :action => 'show', :id => Issue.last.id
746
781
747 issue = Issue.find_by_subject('This is the test_new issue')
782 issue = Issue.find_by_subject('This is the test_new issue')
748 assert_not_nil issue
783 assert_not_nil issue
749 assert_nil issue.start_date
784 assert_nil issue.start_date
750 end
785 end
751
786
752 def test_post_create_without_start_date_and_default_start_date_is_creation_date
787 def test_post_create_without_start_date_and_default_start_date_is_creation_date
753 Setting.default_issue_start_date_to_creation_date = 1
788 Setting.default_issue_start_date_to_creation_date = 1
754
789
755 @request.session[:user_id] = 2
790 @request.session[:user_id] = 2
756 assert_difference 'Issue.count' do
791 assert_difference 'Issue.count' do
757 post :create, :project_id => 1,
792 post :create, :project_id => 1,
758 :issue => {:tracker_id => 3,
793 :issue => {:tracker_id => 3,
759 :status_id => 2,
794 :status_id => 2,
760 :subject => 'This is the test_new issue',
795 :subject => 'This is the test_new issue',
761 :description => 'This is the description',
796 :description => 'This is the description',
762 :priority_id => 5,
797 :priority_id => 5,
763 :estimated_hours => '',
798 :estimated_hours => '',
764 :custom_field_values => {'2' => 'Value for field 2'}}
799 :custom_field_values => {'2' => 'Value for field 2'}}
765 end
800 end
766 assert_redirected_to :controller => 'issues', :action => 'show', :id => Issue.last.id
801 assert_redirected_to :controller => 'issues', :action => 'show', :id => Issue.last.id
767
802
768 issue = Issue.find_by_subject('This is the test_new issue')
803 issue = Issue.find_by_subject('This is the test_new issue')
769 assert_not_nil issue
804 assert_not_nil issue
770 assert_equal Date.today, issue.start_date
805 assert_equal Date.today, issue.start_date
771 end
806 end
772
807
773 def test_post_create_and_continue
808 def test_post_create_and_continue
774 @request.session[:user_id] = 2
809 @request.session[:user_id] = 2
775 assert_difference 'Issue.count' do
810 assert_difference 'Issue.count' do
776 post :create, :project_id => 1,
811 post :create, :project_id => 1,
777 :issue => {:tracker_id => 3, :subject => 'This is first issue', :priority_id => 5},
812 :issue => {:tracker_id => 3, :subject => 'This is first issue', :priority_id => 5},
778 :continue => ''
813 :continue => ''
779 end
814 end
780
815
781 issue = Issue.first(:order => 'id DESC')
816 issue = Issue.first(:order => 'id DESC')
782 assert_redirected_to :controller => 'issues', :action => 'new', :project_id => 'ecookbook', :issue => {:tracker_id => 3}
817 assert_redirected_to :controller => 'issues', :action => 'new', :project_id => 'ecookbook', :issue => {:tracker_id => 3}
783 assert_not_nil flash[:notice], "flash was not set"
818 assert_not_nil flash[:notice], "flash was not set"
784 assert flash[:notice].include?("<a href='/issues/#{issue.id}'>##{issue.id}</a>"), "issue link not found in flash: #{flash[:notice]}"
819 assert flash[:notice].include?("<a href='/issues/#{issue.id}'>##{issue.id}</a>"), "issue link not found in flash: #{flash[:notice]}"
785 end
820 end
786
821
787 def test_post_create_without_custom_fields_param
822 def test_post_create_without_custom_fields_param
788 @request.session[:user_id] = 2
823 @request.session[:user_id] = 2
789 assert_difference 'Issue.count' do
824 assert_difference 'Issue.count' do
790 post :create, :project_id => 1,
825 post :create, :project_id => 1,
791 :issue => {:tracker_id => 1,
826 :issue => {:tracker_id => 1,
792 :subject => 'This is the test_new issue',
827 :subject => 'This is the test_new issue',
793 :description => 'This is the description',
828 :description => 'This is the description',
794 :priority_id => 5}
829 :priority_id => 5}
795 end
830 end
796 assert_redirected_to :controller => 'issues', :action => 'show', :id => Issue.last.id
831 assert_redirected_to :controller => 'issues', :action => 'show', :id => Issue.last.id
797 end
832 end
798
833
799 def test_post_create_with_required_custom_field_and_without_custom_fields_param
834 def test_post_create_with_required_custom_field_and_without_custom_fields_param
800 field = IssueCustomField.find_by_name('Database')
835 field = IssueCustomField.find_by_name('Database')
801 field.update_attribute(:is_required, true)
836 field.update_attribute(:is_required, true)
802
837
803 @request.session[:user_id] = 2
838 @request.session[:user_id] = 2
804 post :create, :project_id => 1,
839 post :create, :project_id => 1,
805 :issue => {:tracker_id => 1,
840 :issue => {:tracker_id => 1,
806 :subject => 'This is the test_new issue',
841 :subject => 'This is the test_new issue',
807 :description => 'This is the description',
842 :description => 'This is the description',
808 :priority_id => 5}
843 :priority_id => 5}
809 assert_response :success
844 assert_response :success
810 assert_template 'new'
845 assert_template 'new'
811 issue = assigns(:issue)
846 issue = assigns(:issue)
812 assert_not_nil issue
847 assert_not_nil issue
813 assert_equal I18n.translate('activerecord.errors.messages.invalid'), issue.errors.on(:custom_values)
848 assert_equal I18n.translate('activerecord.errors.messages.invalid'), issue.errors.on(:custom_values)
814 end
849 end
815
850
816 def test_post_create_with_watchers
851 def test_post_create_with_watchers
817 @request.session[:user_id] = 2
852 @request.session[:user_id] = 2
818 ActionMailer::Base.deliveries.clear
853 ActionMailer::Base.deliveries.clear
819
854
820 assert_difference 'Watcher.count', 2 do
855 assert_difference 'Watcher.count', 2 do
821 post :create, :project_id => 1,
856 post :create, :project_id => 1,
822 :issue => {:tracker_id => 1,
857 :issue => {:tracker_id => 1,
823 :subject => 'This is a new issue with watchers',
858 :subject => 'This is a new issue with watchers',
824 :description => 'This is the description',
859 :description => 'This is the description',
825 :priority_id => 5,
860 :priority_id => 5,
826 :watcher_user_ids => ['2', '3']}
861 :watcher_user_ids => ['2', '3']}
827 end
862 end
828 issue = Issue.find_by_subject('This is a new issue with watchers')
863 issue = Issue.find_by_subject('This is a new issue with watchers')
829 assert_not_nil issue
864 assert_not_nil issue
830 assert_redirected_to :controller => 'issues', :action => 'show', :id => issue
865 assert_redirected_to :controller => 'issues', :action => 'show', :id => issue
831
866
832 # Watchers added
867 # Watchers added
833 assert_equal [2, 3], issue.watcher_user_ids.sort
868 assert_equal [2, 3], issue.watcher_user_ids.sort
834 assert issue.watched_by?(User.find(3))
869 assert issue.watched_by?(User.find(3))
835 # Watchers notified
870 # Watchers notified
836 mail = ActionMailer::Base.deliveries.last
871 mail = ActionMailer::Base.deliveries.last
837 assert_kind_of TMail::Mail, mail
872 assert_kind_of TMail::Mail, mail
838 assert [mail.bcc, mail.cc].flatten.include?(User.find(3).mail)
873 assert [mail.bcc, mail.cc].flatten.include?(User.find(3).mail)
839 end
874 end
840
875
841 def test_post_create_subissue
876 def test_post_create_subissue
842 @request.session[:user_id] = 2
877 @request.session[:user_id] = 2
843
878
844 assert_difference 'Issue.count' do
879 assert_difference 'Issue.count' do
845 post :create, :project_id => 1,
880 post :create, :project_id => 1,
846 :issue => {:tracker_id => 1,
881 :issue => {:tracker_id => 1,
847 :subject => 'This is a child issue',
882 :subject => 'This is a child issue',
848 :parent_issue_id => 2}
883 :parent_issue_id => 2}
849 end
884 end
850 issue = Issue.find_by_subject('This is a child issue')
885 issue = Issue.find_by_subject('This is a child issue')
851 assert_not_nil issue
886 assert_not_nil issue
852 assert_equal Issue.find(2), issue.parent
887 assert_equal Issue.find(2), issue.parent
853 end
888 end
854
889
855 def test_post_create_subissue_with_non_numeric_parent_id
890 def test_post_create_subissue_with_non_numeric_parent_id
856 @request.session[:user_id] = 2
891 @request.session[:user_id] = 2
857
892
858 assert_difference 'Issue.count' do
893 assert_difference 'Issue.count' do
859 post :create, :project_id => 1,
894 post :create, :project_id => 1,
860 :issue => {:tracker_id => 1,
895 :issue => {:tracker_id => 1,
861 :subject => 'This is a child issue',
896 :subject => 'This is a child issue',
862 :parent_issue_id => 'ABC'}
897 :parent_issue_id => 'ABC'}
863 end
898 end
864 issue = Issue.find_by_subject('This is a child issue')
899 issue = Issue.find_by_subject('This is a child issue')
865 assert_not_nil issue
900 assert_not_nil issue
866 assert_nil issue.parent
901 assert_nil issue.parent
867 end
902 end
868
903
869 def test_post_create_private
904 def test_post_create_private
870 @request.session[:user_id] = 2
905 @request.session[:user_id] = 2
871
906
872 assert_difference 'Issue.count' do
907 assert_difference 'Issue.count' do
873 post :create, :project_id => 1,
908 post :create, :project_id => 1,
874 :issue => {:tracker_id => 1,
909 :issue => {:tracker_id => 1,
875 :subject => 'This is a private issue',
910 :subject => 'This is a private issue',
876 :is_private => '1'}
911 :is_private => '1'}
877 end
912 end
878 issue = Issue.first(:order => 'id DESC')
913 issue = Issue.first(:order => 'id DESC')
879 assert issue.is_private?
914 assert issue.is_private?
880 end
915 end
881
916
882 def test_post_create_private_with_set_own_issues_private_permission
917 def test_post_create_private_with_set_own_issues_private_permission
883 role = Role.find(1)
918 role = Role.find(1)
884 role.remove_permission! :set_issues_private
919 role.remove_permission! :set_issues_private
885 role.add_permission! :set_own_issues_private
920 role.add_permission! :set_own_issues_private
886
921
887 @request.session[:user_id] = 2
922 @request.session[:user_id] = 2
888
923
889 assert_difference 'Issue.count' do
924 assert_difference 'Issue.count' do
890 post :create, :project_id => 1,
925 post :create, :project_id => 1,
891 :issue => {:tracker_id => 1,
926 :issue => {:tracker_id => 1,
892 :subject => 'This is a private issue',
927 :subject => 'This is a private issue',
893 :is_private => '1'}
928 :is_private => '1'}
894 end
929 end
895 issue = Issue.first(:order => 'id DESC')
930 issue = Issue.first(:order => 'id DESC')
896 assert issue.is_private?
931 assert issue.is_private?
897 end
932 end
898
933
899 def test_post_create_should_send_a_notification
934 def test_post_create_should_send_a_notification
900 ActionMailer::Base.deliveries.clear
935 ActionMailer::Base.deliveries.clear
901 @request.session[:user_id] = 2
936 @request.session[:user_id] = 2
902 assert_difference 'Issue.count' do
937 assert_difference 'Issue.count' do
903 post :create, :project_id => 1,
938 post :create, :project_id => 1,
904 :issue => {:tracker_id => 3,
939 :issue => {:tracker_id => 3,
905 :subject => 'This is the test_new issue',
940 :subject => 'This is the test_new issue',
906 :description => 'This is the description',
941 :description => 'This is the description',
907 :priority_id => 5,
942 :priority_id => 5,
908 :estimated_hours => '',
943 :estimated_hours => '',
909 :custom_field_values => {'2' => 'Value for field 2'}}
944 :custom_field_values => {'2' => 'Value for field 2'}}
910 end
945 end
911 assert_redirected_to :controller => 'issues', :action => 'show', :id => Issue.last.id
946 assert_redirected_to :controller => 'issues', :action => 'show', :id => Issue.last.id
912
947
913 assert_equal 1, ActionMailer::Base.deliveries.size
948 assert_equal 1, ActionMailer::Base.deliveries.size
914 end
949 end
915
950
916 def test_post_create_should_preserve_fields_values_on_validation_failure
951 def test_post_create_should_preserve_fields_values_on_validation_failure
917 @request.session[:user_id] = 2
952 @request.session[:user_id] = 2
918 post :create, :project_id => 1,
953 post :create, :project_id => 1,
919 :issue => {:tracker_id => 1,
954 :issue => {:tracker_id => 1,
920 # empty subject
955 # empty subject
921 :subject => '',
956 :subject => '',
922 :description => 'This is a description',
957 :description => 'This is a description',
923 :priority_id => 6,
958 :priority_id => 6,
924 :custom_field_values => {'1' => 'Oracle', '2' => 'Value for field 2'}}
959 :custom_field_values => {'1' => 'Oracle', '2' => 'Value for field 2'}}
925 assert_response :success
960 assert_response :success
926 assert_template 'new'
961 assert_template 'new'
927
962
928 assert_tag :textarea, :attributes => { :name => 'issue[description]' },
963 assert_tag :textarea, :attributes => { :name => 'issue[description]' },
929 :content => 'This is a description'
964 :content => 'This is a description'
930 assert_tag :select, :attributes => { :name => 'issue[priority_id]' },
965 assert_tag :select, :attributes => { :name => 'issue[priority_id]' },
931 :child => { :tag => 'option', :attributes => { :selected => 'selected',
966 :child => { :tag => 'option', :attributes => { :selected => 'selected',
932 :value => '6' },
967 :value => '6' },
933 :content => 'High' }
968 :content => 'High' }
934 # Custom fields
969 # Custom fields
935 assert_tag :select, :attributes => { :name => 'issue[custom_field_values][1]' },
970 assert_tag :select, :attributes => { :name => 'issue[custom_field_values][1]' },
936 :child => { :tag => 'option', :attributes => { :selected => 'selected',
971 :child => { :tag => 'option', :attributes => { :selected => 'selected',
937 :value => 'Oracle' },
972 :value => 'Oracle' },
938 :content => 'Oracle' }
973 :content => 'Oracle' }
939 assert_tag :input, :attributes => { :name => 'issue[custom_field_values][2]',
974 assert_tag :input, :attributes => { :name => 'issue[custom_field_values][2]',
940 :value => 'Value for field 2'}
975 :value => 'Value for field 2'}
941 end
976 end
942
977
943 def test_post_create_should_ignore_non_safe_attributes
978 def test_post_create_should_ignore_non_safe_attributes
944 @request.session[:user_id] = 2
979 @request.session[:user_id] = 2
945 assert_nothing_raised do
980 assert_nothing_raised do
946 post :create, :project_id => 1, :issue => { :tracker => "A param can not be a Tracker" }
981 post :create, :project_id => 1, :issue => { :tracker => "A param can not be a Tracker" }
947 end
982 end
948 end
983 end
949
984
950 def test_post_create_with_attachment
985 def test_post_create_with_attachment
951 set_tmp_attachments_directory
986 set_tmp_attachments_directory
952 @request.session[:user_id] = 2
987 @request.session[:user_id] = 2
953
988
954 assert_difference 'Issue.count' do
989 assert_difference 'Issue.count' do
955 assert_difference 'Attachment.count' do
990 assert_difference 'Attachment.count' do
956 post :create, :project_id => 1,
991 post :create, :project_id => 1,
957 :issue => { :tracker_id => '1', :subject => 'With attachment' },
992 :issue => { :tracker_id => '1', :subject => 'With attachment' },
958 :attachments => {'1' => {'file' => uploaded_test_file('testfile.txt', 'text/plain'), 'description' => 'test file'}}
993 :attachments => {'1' => {'file' => uploaded_test_file('testfile.txt', 'text/plain'), 'description' => 'test file'}}
959 end
994 end
960 end
995 end
961
996
962 issue = Issue.first(:order => 'id DESC')
997 issue = Issue.first(:order => 'id DESC')
963 attachment = Attachment.first(:order => 'id DESC')
998 attachment = Attachment.first(:order => 'id DESC')
964
999
965 assert_equal issue, attachment.container
1000 assert_equal issue, attachment.container
966 assert_equal 2, attachment.author_id
1001 assert_equal 2, attachment.author_id
967 assert_equal 'testfile.txt', attachment.filename
1002 assert_equal 'testfile.txt', attachment.filename
968 assert_equal 'text/plain', attachment.content_type
1003 assert_equal 'text/plain', attachment.content_type
969 assert_equal 'test file', attachment.description
1004 assert_equal 'test file', attachment.description
970 assert_equal 59, attachment.filesize
1005 assert_equal 59, attachment.filesize
971 assert File.exists?(attachment.diskfile)
1006 assert File.exists?(attachment.diskfile)
972 assert_equal 59, File.size(attachment.diskfile)
1007 assert_equal 59, File.size(attachment.diskfile)
973 end
1008 end
974
1009
975 context "without workflow privilege" do
1010 context "without workflow privilege" do
976 setup do
1011 setup do
977 Workflow.delete_all(["role_id = ?", Role.anonymous.id])
1012 Workflow.delete_all(["role_id = ?", Role.anonymous.id])
978 Role.anonymous.add_permission! :add_issues, :add_issue_notes
1013 Role.anonymous.add_permission! :add_issues, :add_issue_notes
979 end
1014 end
980
1015
981 context "#new" do
1016 context "#new" do
982 should "propose default status only" do
1017 should "propose default status only" do
983 get :new, :project_id => 1
1018 get :new, :project_id => 1
984 assert_response :success
1019 assert_response :success
985 assert_template 'new'
1020 assert_template 'new'
986 assert_tag :tag => 'select',
1021 assert_tag :tag => 'select',
987 :attributes => {:name => 'issue[status_id]'},
1022 :attributes => {:name => 'issue[status_id]'},
988 :children => {:count => 1},
1023 :children => {:count => 1},
989 :child => {:tag => 'option', :attributes => {:value => IssueStatus.default.id.to_s}}
1024 :child => {:tag => 'option', :attributes => {:value => IssueStatus.default.id.to_s}}
990 end
1025 end
991
1026
992 should "accept default status" do
1027 should "accept default status" do
993 assert_difference 'Issue.count' do
1028 assert_difference 'Issue.count' do
994 post :create, :project_id => 1,
1029 post :create, :project_id => 1,
995 :issue => {:tracker_id => 1,
1030 :issue => {:tracker_id => 1,
996 :subject => 'This is an issue',
1031 :subject => 'This is an issue',
997 :status_id => 1}
1032 :status_id => 1}
998 end
1033 end
999 issue = Issue.last(:order => 'id')
1034 issue = Issue.last(:order => 'id')
1000 assert_equal IssueStatus.default, issue.status
1035 assert_equal IssueStatus.default, issue.status
1001 end
1036 end
1002
1037
1003 should "ignore unauthorized status" do
1038 should "ignore unauthorized status" do
1004 assert_difference 'Issue.count' do
1039 assert_difference 'Issue.count' do
1005 post :create, :project_id => 1,
1040 post :create, :project_id => 1,
1006 :issue => {:tracker_id => 1,
1041 :issue => {:tracker_id => 1,
1007 :subject => 'This is an issue',
1042 :subject => 'This is an issue',
1008 :status_id => 3}
1043 :status_id => 3}
1009 end
1044 end
1010 issue = Issue.last(:order => 'id')
1045 issue = Issue.last(:order => 'id')
1011 assert_equal IssueStatus.default, issue.status
1046 assert_equal IssueStatus.default, issue.status
1012 end
1047 end
1013 end
1048 end
1014
1049
1015 context "#update" do
1050 context "#update" do
1016 should "ignore status change" do
1051 should "ignore status change" do
1017 assert_difference 'Journal.count' do
1052 assert_difference 'Journal.count' do
1018 put :update, :id => 1, :notes => 'just trying', :issue => {:status_id => 3}
1053 put :update, :id => 1, :notes => 'just trying', :issue => {:status_id => 3}
1019 end
1054 end
1020 assert_equal 1, Issue.find(1).status_id
1055 assert_equal 1, Issue.find(1).status_id
1021 end
1056 end
1022
1057
1023 should "ignore attributes changes" do
1058 should "ignore attributes changes" do
1024 assert_difference 'Journal.count' do
1059 assert_difference 'Journal.count' do
1025 put :update, :id => 1, :notes => 'just trying', :issue => {:subject => 'changed', :assigned_to_id => 2}
1060 put :update, :id => 1, :notes => 'just trying', :issue => {:subject => 'changed', :assigned_to_id => 2}
1026 end
1061 end
1027 issue = Issue.find(1)
1062 issue = Issue.find(1)
1028 assert_equal "Can't print recipes", issue.subject
1063 assert_equal "Can't print recipes", issue.subject
1029 assert_nil issue.assigned_to
1064 assert_nil issue.assigned_to
1030 end
1065 end
1031 end
1066 end
1032 end
1067 end
1033
1068
1034 context "with workflow privilege" do
1069 context "with workflow privilege" do
1035 setup do
1070 setup do
1036 Workflow.delete_all(["role_id = ?", Role.anonymous.id])
1071 Workflow.delete_all(["role_id = ?", Role.anonymous.id])
1037 Workflow.create!(:role => Role.anonymous, :tracker_id => 1, :old_status_id => 1, :new_status_id => 3)
1072 Workflow.create!(:role => Role.anonymous, :tracker_id => 1, :old_status_id => 1, :new_status_id => 3)
1038 Workflow.create!(:role => Role.anonymous, :tracker_id => 1, :old_status_id => 1, :new_status_id => 4)
1073 Workflow.create!(:role => Role.anonymous, :tracker_id => 1, :old_status_id => 1, :new_status_id => 4)
1039 Role.anonymous.add_permission! :add_issues, :add_issue_notes
1074 Role.anonymous.add_permission! :add_issues, :add_issue_notes
1040 end
1075 end
1041
1076
1042 context "#update" do
1077 context "#update" do
1043 should "accept authorized status" do
1078 should "accept authorized status" do
1044 assert_difference 'Journal.count' do
1079 assert_difference 'Journal.count' do
1045 put :update, :id => 1, :notes => 'just trying', :issue => {:status_id => 3}
1080 put :update, :id => 1, :notes => 'just trying', :issue => {:status_id => 3}
1046 end
1081 end
1047 assert_equal 3, Issue.find(1).status_id
1082 assert_equal 3, Issue.find(1).status_id
1048 end
1083 end
1049
1084
1050 should "ignore unauthorized status" do
1085 should "ignore unauthorized status" do
1051 assert_difference 'Journal.count' do
1086 assert_difference 'Journal.count' do
1052 put :update, :id => 1, :notes => 'just trying', :issue => {:status_id => 2}
1087 put :update, :id => 1, :notes => 'just trying', :issue => {:status_id => 2}
1053 end
1088 end
1054 assert_equal 1, Issue.find(1).status_id
1089 assert_equal 1, Issue.find(1).status_id
1055 end
1090 end
1056
1091
1057 should "accept authorized attributes changes" do
1092 should "accept authorized attributes changes" do
1058 assert_difference 'Journal.count' do
1093 assert_difference 'Journal.count' do
1059 put :update, :id => 1, :notes => 'just trying', :issue => {:assigned_to_id => 2}
1094 put :update, :id => 1, :notes => 'just trying', :issue => {:assigned_to_id => 2}
1060 end
1095 end
1061 issue = Issue.find(1)
1096 issue = Issue.find(1)
1062 assert_equal 2, issue.assigned_to_id
1097 assert_equal 2, issue.assigned_to_id
1063 end
1098 end
1064
1099
1065 should "ignore unauthorized attributes changes" do
1100 should "ignore unauthorized attributes changes" do
1066 assert_difference 'Journal.count' do
1101 assert_difference 'Journal.count' do
1067 put :update, :id => 1, :notes => 'just trying', :issue => {:subject => 'changed'}
1102 put :update, :id => 1, :notes => 'just trying', :issue => {:subject => 'changed'}
1068 end
1103 end
1069 issue = Issue.find(1)
1104 issue = Issue.find(1)
1070 assert_equal "Can't print recipes", issue.subject
1105 assert_equal "Can't print recipes", issue.subject
1071 end
1106 end
1072 end
1107 end
1073
1108
1074 context "and :edit_issues permission" do
1109 context "and :edit_issues permission" do
1075 setup do
1110 setup do
1076 Role.anonymous.add_permission! :add_issues, :edit_issues
1111 Role.anonymous.add_permission! :add_issues, :edit_issues
1077 end
1112 end
1078
1113
1079 should "accept authorized status" do
1114 should "accept authorized status" do
1080 assert_difference 'Journal.count' do
1115 assert_difference 'Journal.count' do
1081 put :update, :id => 1, :notes => 'just trying', :issue => {:status_id => 3}
1116 put :update, :id => 1, :notes => 'just trying', :issue => {:status_id => 3}
1082 end
1117 end
1083 assert_equal 3, Issue.find(1).status_id
1118 assert_equal 3, Issue.find(1).status_id
1084 end
1119 end
1085
1120
1086 should "ignore unauthorized status" do
1121 should "ignore unauthorized status" do
1087 assert_difference 'Journal.count' do
1122 assert_difference 'Journal.count' do
1088 put :update, :id => 1, :notes => 'just trying', :issue => {:status_id => 2}
1123 put :update, :id => 1, :notes => 'just trying', :issue => {:status_id => 2}
1089 end
1124 end
1090 assert_equal 1, Issue.find(1).status_id
1125 assert_equal 1, Issue.find(1).status_id
1091 end
1126 end
1092
1127
1093 should "accept authorized attributes changes" do
1128 should "accept authorized attributes changes" do
1094 assert_difference 'Journal.count' do
1129 assert_difference 'Journal.count' do
1095 put :update, :id => 1, :notes => 'just trying', :issue => {:subject => 'changed', :assigned_to_id => 2}
1130 put :update, :id => 1, :notes => 'just trying', :issue => {:subject => 'changed', :assigned_to_id => 2}
1096 end
1131 end
1097 issue = Issue.find(1)
1132 issue = Issue.find(1)
1098 assert_equal "changed", issue.subject
1133 assert_equal "changed", issue.subject
1099 assert_equal 2, issue.assigned_to_id
1134 assert_equal 2, issue.assigned_to_id
1100 end
1135 end
1101 end
1136 end
1102 end
1137 end
1103
1138
1104 def test_copy_issue
1139 def test_copy_issue
1105 @request.session[:user_id] = 2
1140 @request.session[:user_id] = 2
1106 get :new, :project_id => 1, :copy_from => 1
1141 get :new, :project_id => 1, :copy_from => 1
1107 assert_template 'new'
1142 assert_template 'new'
1108 assert_not_nil assigns(:issue)
1143 assert_not_nil assigns(:issue)
1109 orig = Issue.find(1)
1144 orig = Issue.find(1)
1110 assert_equal orig.subject, assigns(:issue).subject
1145 assert_equal orig.subject, assigns(:issue).subject
1111 end
1146 end
1112
1147
1113 def test_get_edit
1148 def test_get_edit
1114 @request.session[:user_id] = 2
1149 @request.session[:user_id] = 2
1115 get :edit, :id => 1
1150 get :edit, :id => 1
1116 assert_response :success
1151 assert_response :success
1117 assert_template 'edit'
1152 assert_template 'edit'
1118 assert_not_nil assigns(:issue)
1153 assert_not_nil assigns(:issue)
1119 assert_equal Issue.find(1), assigns(:issue)
1154 assert_equal Issue.find(1), assigns(:issue)
1120
1155
1121 # Be sure we don't display inactive IssuePriorities
1156 # Be sure we don't display inactive IssuePriorities
1122 assert ! IssuePriority.find(15).active?
1157 assert ! IssuePriority.find(15).active?
1123 assert_no_tag :option, :attributes => {:value => '15'},
1158 assert_no_tag :option, :attributes => {:value => '15'},
1124 :parent => {:tag => 'select', :attributes => {:id => 'issue_priority_id'} }
1159 :parent => {:tag => 'select', :attributes => {:id => 'issue_priority_id'} }
1125 end
1160 end
1126
1161
1127 def test_get_edit_with_params
1162 def test_get_edit_with_params
1128 @request.session[:user_id] = 2
1163 @request.session[:user_id] = 2
1129 get :edit, :id => 1, :issue => { :status_id => 5, :priority_id => 7 },
1164 get :edit, :id => 1, :issue => { :status_id => 5, :priority_id => 7 },
1130 :time_entry => { :hours => '2.5', :comments => 'test_get_edit_with_params', :activity_id => TimeEntryActivity.first.id }
1165 :time_entry => { :hours => '2.5', :comments => 'test_get_edit_with_params', :activity_id => TimeEntryActivity.first.id }
1131 assert_response :success
1166 assert_response :success
1132 assert_template 'edit'
1167 assert_template 'edit'
1133
1168
1134 issue = assigns(:issue)
1169 issue = assigns(:issue)
1135 assert_not_nil issue
1170 assert_not_nil issue
1136
1171
1137 assert_equal 5, issue.status_id
1172 assert_equal 5, issue.status_id
1138 assert_tag :select, :attributes => { :name => 'issue[status_id]' },
1173 assert_tag :select, :attributes => { :name => 'issue[status_id]' },
1139 :child => { :tag => 'option',
1174 :child => { :tag => 'option',
1140 :content => 'Closed',
1175 :content => 'Closed',
1141 :attributes => { :selected => 'selected' } }
1176 :attributes => { :selected => 'selected' } }
1142
1177
1143 assert_equal 7, issue.priority_id
1178 assert_equal 7, issue.priority_id
1144 assert_tag :select, :attributes => { :name => 'issue[priority_id]' },
1179 assert_tag :select, :attributes => { :name => 'issue[priority_id]' },
1145 :child => { :tag => 'option',
1180 :child => { :tag => 'option',
1146 :content => 'Urgent',
1181 :content => 'Urgent',
1147 :attributes => { :selected => 'selected' } }
1182 :attributes => { :selected => 'selected' } }
1148
1183
1149 assert_tag :input, :attributes => { :name => 'time_entry[hours]', :value => '2.5' }
1184 assert_tag :input, :attributes => { :name => 'time_entry[hours]', :value => '2.5' }
1150 assert_tag :select, :attributes => { :name => 'time_entry[activity_id]' },
1185 assert_tag :select, :attributes => { :name => 'time_entry[activity_id]' },
1151 :child => { :tag => 'option',
1186 :child => { :tag => 'option',
1152 :attributes => { :selected => 'selected', :value => TimeEntryActivity.first.id } }
1187 :attributes => { :selected => 'selected', :value => TimeEntryActivity.first.id } }
1153 assert_tag :input, :attributes => { :name => 'time_entry[comments]', :value => 'test_get_edit_with_params' }
1188 assert_tag :input, :attributes => { :name => 'time_entry[comments]', :value => 'test_get_edit_with_params' }
1154 end
1189 end
1155
1190
1156 def test_update_edit_form
1191 def test_update_edit_form
1157 @request.session[:user_id] = 2
1192 @request.session[:user_id] = 2
1158 xhr :post, :new, :project_id => 1,
1193 xhr :post, :new, :project_id => 1,
1159 :id => 1,
1194 :id => 1,
1160 :issue => {:tracker_id => 2,
1195 :issue => {:tracker_id => 2,
1161 :subject => 'This is the test_new issue',
1196 :subject => 'This is the test_new issue',
1162 :description => 'This is the description',
1197 :description => 'This is the description',
1163 :priority_id => 5}
1198 :priority_id => 5}
1164 assert_response :success
1199 assert_response :success
1165 assert_template 'attributes'
1200 assert_template 'attributes'
1166
1201
1167 issue = assigns(:issue)
1202 issue = assigns(:issue)
1168 assert_kind_of Issue, issue
1203 assert_kind_of Issue, issue
1169 assert_equal 1, issue.id
1204 assert_equal 1, issue.id
1170 assert_equal 1, issue.project_id
1205 assert_equal 1, issue.project_id
1171 assert_equal 2, issue.tracker_id
1206 assert_equal 2, issue.tracker_id
1172 assert_equal 'This is the test_new issue', issue.subject
1207 assert_equal 'This is the test_new issue', issue.subject
1173 end
1208 end
1174
1209
1175 def test_update_using_invalid_http_verbs
1210 def test_update_using_invalid_http_verbs
1176 @request.session[:user_id] = 2
1211 @request.session[:user_id] = 2
1177 subject = 'Updated by an invalid http verb'
1212 subject = 'Updated by an invalid http verb'
1178
1213
1179 get :update, :id => 1, :issue => {:subject => subject}
1214 get :update, :id => 1, :issue => {:subject => subject}
1180 assert_not_equal subject, Issue.find(1).subject
1215 assert_not_equal subject, Issue.find(1).subject
1181
1216
1182 post :update, :id => 1, :issue => {:subject => subject}
1217 post :update, :id => 1, :issue => {:subject => subject}
1183 assert_not_equal subject, Issue.find(1).subject
1218 assert_not_equal subject, Issue.find(1).subject
1184
1219
1185 delete :update, :id => 1, :issue => {:subject => subject}
1220 delete :update, :id => 1, :issue => {:subject => subject}
1186 assert_not_equal subject, Issue.find(1).subject
1221 assert_not_equal subject, Issue.find(1).subject
1187 end
1222 end
1188
1223
1189 def test_put_update_without_custom_fields_param
1224 def test_put_update_without_custom_fields_param
1190 @request.session[:user_id] = 2
1225 @request.session[:user_id] = 2
1191 ActionMailer::Base.deliveries.clear
1226 ActionMailer::Base.deliveries.clear
1192
1227
1193 issue = Issue.find(1)
1228 issue = Issue.find(1)
1194 assert_equal '125', issue.custom_value_for(2).value
1229 assert_equal '125', issue.custom_value_for(2).value
1195 old_subject = issue.subject
1230 old_subject = issue.subject
1196 new_subject = 'Subject modified by IssuesControllerTest#test_post_edit'
1231 new_subject = 'Subject modified by IssuesControllerTest#test_post_edit'
1197
1232
1198 assert_difference('Journal.count') do
1233 assert_difference('Journal.count') do
1199 assert_difference('JournalDetail.count', 2) do
1234 assert_difference('JournalDetail.count', 2) do
1200 put :update, :id => 1, :issue => {:subject => new_subject,
1235 put :update, :id => 1, :issue => {:subject => new_subject,
1201 :priority_id => '6',
1236 :priority_id => '6',
1202 :category_id => '1' # no change
1237 :category_id => '1' # no change
1203 }
1238 }
1204 end
1239 end
1205 end
1240 end
1206 assert_redirected_to :action => 'show', :id => '1'
1241 assert_redirected_to :action => 'show', :id => '1'
1207 issue.reload
1242 issue.reload
1208 assert_equal new_subject, issue.subject
1243 assert_equal new_subject, issue.subject
1209 # Make sure custom fields were not cleared
1244 # Make sure custom fields were not cleared
1210 assert_equal '125', issue.custom_value_for(2).value
1245 assert_equal '125', issue.custom_value_for(2).value
1211
1246
1212 mail = ActionMailer::Base.deliveries.last
1247 mail = ActionMailer::Base.deliveries.last
1213 assert_kind_of TMail::Mail, mail
1248 assert_kind_of TMail::Mail, mail
1214 assert mail.subject.starts_with?("[#{issue.project.name} - #{issue.tracker.name} ##{issue.id}]")
1249 assert mail.subject.starts_with?("[#{issue.project.name} - #{issue.tracker.name} ##{issue.id}]")
1215 assert mail.body.include?("Subject changed from #{old_subject} to #{new_subject}")
1250 assert mail.body.include?("Subject changed from #{old_subject} to #{new_subject}")
1216 end
1251 end
1217
1252
1218 def test_put_update_with_custom_field_change
1253 def test_put_update_with_custom_field_change
1219 @request.session[:user_id] = 2
1254 @request.session[:user_id] = 2
1220 issue = Issue.find(1)
1255 issue = Issue.find(1)
1221 assert_equal '125', issue.custom_value_for(2).value
1256 assert_equal '125', issue.custom_value_for(2).value
1222
1257
1223 assert_difference('Journal.count') do
1258 assert_difference('Journal.count') do
1224 assert_difference('JournalDetail.count', 3) do
1259 assert_difference('JournalDetail.count', 3) do
1225 put :update, :id => 1, :issue => {:subject => 'Custom field change',
1260 put :update, :id => 1, :issue => {:subject => 'Custom field change',
1226 :priority_id => '6',
1261 :priority_id => '6',
1227 :category_id => '1', # no change
1262 :category_id => '1', # no change
1228 :custom_field_values => { '2' => 'New custom value' }
1263 :custom_field_values => { '2' => 'New custom value' }
1229 }
1264 }
1230 end
1265 end
1231 end
1266 end
1232 assert_redirected_to :action => 'show', :id => '1'
1267 assert_redirected_to :action => 'show', :id => '1'
1233 issue.reload
1268 issue.reload
1234 assert_equal 'New custom value', issue.custom_value_for(2).value
1269 assert_equal 'New custom value', issue.custom_value_for(2).value
1235
1270
1236 mail = ActionMailer::Base.deliveries.last
1271 mail = ActionMailer::Base.deliveries.last
1237 assert_kind_of TMail::Mail, mail
1272 assert_kind_of TMail::Mail, mail
1238 assert mail.body.include?("Searchable field changed from 125 to New custom value")
1273 assert mail.body.include?("Searchable field changed from 125 to New custom value")
1239 end
1274 end
1240
1275
1241 def test_put_update_with_status_and_assignee_change
1276 def test_put_update_with_status_and_assignee_change
1242 issue = Issue.find(1)
1277 issue = Issue.find(1)
1243 assert_equal 1, issue.status_id
1278 assert_equal 1, issue.status_id
1244 @request.session[:user_id] = 2
1279 @request.session[:user_id] = 2
1245 assert_difference('TimeEntry.count', 0) do
1280 assert_difference('TimeEntry.count', 0) do
1246 put :update,
1281 put :update,
1247 :id => 1,
1282 :id => 1,
1248 :issue => { :status_id => 2, :assigned_to_id => 3 },
1283 :issue => { :status_id => 2, :assigned_to_id => 3 },
1249 :notes => 'Assigned to dlopper',
1284 :notes => 'Assigned to dlopper',
1250 :time_entry => { :hours => '', :comments => '', :activity_id => TimeEntryActivity.first }
1285 :time_entry => { :hours => '', :comments => '', :activity_id => TimeEntryActivity.first }
1251 end
1286 end
1252 assert_redirected_to :action => 'show', :id => '1'
1287 assert_redirected_to :action => 'show', :id => '1'
1253 issue.reload
1288 issue.reload
1254 assert_equal 2, issue.status_id
1289 assert_equal 2, issue.status_id
1255 j = Journal.find(:first, :order => 'id DESC')
1290 j = Journal.find(:first, :order => 'id DESC')
1256 assert_equal 'Assigned to dlopper', j.notes
1291 assert_equal 'Assigned to dlopper', j.notes
1257 assert_equal 2, j.details.size
1292 assert_equal 2, j.details.size
1258
1293
1259 mail = ActionMailer::Base.deliveries.last
1294 mail = ActionMailer::Base.deliveries.last
1260 assert mail.body.include?("Status changed from New to Assigned")
1295 assert mail.body.include?("Status changed from New to Assigned")
1261 # subject should contain the new status
1296 # subject should contain the new status
1262 assert mail.subject.include?("(#{ IssueStatus.find(2).name })")
1297 assert mail.subject.include?("(#{ IssueStatus.find(2).name })")
1263 end
1298 end
1264
1299
1265 def test_put_update_with_note_only
1300 def test_put_update_with_note_only
1266 notes = 'Note added by IssuesControllerTest#test_update_with_note_only'
1301 notes = 'Note added by IssuesControllerTest#test_update_with_note_only'
1267 # anonymous user
1302 # anonymous user
1268 put :update,
1303 put :update,
1269 :id => 1,
1304 :id => 1,
1270 :notes => notes
1305 :notes => notes
1271 assert_redirected_to :action => 'show', :id => '1'
1306 assert_redirected_to :action => 'show', :id => '1'
1272 j = Journal.find(:first, :order => 'id DESC')
1307 j = Journal.find(:first, :order => 'id DESC')
1273 assert_equal notes, j.notes
1308 assert_equal notes, j.notes
1274 assert_equal 0, j.details.size
1309 assert_equal 0, j.details.size
1275 assert_equal User.anonymous, j.user
1310 assert_equal User.anonymous, j.user
1276
1311
1277 mail = ActionMailer::Base.deliveries.last
1312 mail = ActionMailer::Base.deliveries.last
1278 assert mail.body.include?(notes)
1313 assert mail.body.include?(notes)
1279 end
1314 end
1280
1315
1281 def test_put_update_with_note_and_spent_time
1316 def test_put_update_with_note_and_spent_time
1282 @request.session[:user_id] = 2
1317 @request.session[:user_id] = 2
1283 spent_hours_before = Issue.find(1).spent_hours
1318 spent_hours_before = Issue.find(1).spent_hours
1284 assert_difference('TimeEntry.count') do
1319 assert_difference('TimeEntry.count') do
1285 put :update,
1320 put :update,
1286 :id => 1,
1321 :id => 1,
1287 :notes => '2.5 hours added',
1322 :notes => '2.5 hours added',
1288 :time_entry => { :hours => '2.5', :comments => 'test_put_update_with_note_and_spent_time', :activity_id => TimeEntryActivity.first.id }
1323 :time_entry => { :hours => '2.5', :comments => 'test_put_update_with_note_and_spent_time', :activity_id => TimeEntryActivity.first.id }
1289 end
1324 end
1290 assert_redirected_to :action => 'show', :id => '1'
1325 assert_redirected_to :action => 'show', :id => '1'
1291
1326
1292 issue = Issue.find(1)
1327 issue = Issue.find(1)
1293
1328
1294 j = Journal.find(:first, :order => 'id DESC')
1329 j = Journal.find(:first, :order => 'id DESC')
1295 assert_equal '2.5 hours added', j.notes
1330 assert_equal '2.5 hours added', j.notes
1296 assert_equal 0, j.details.size
1331 assert_equal 0, j.details.size
1297
1332
1298 t = issue.time_entries.find_by_comments('test_put_update_with_note_and_spent_time')
1333 t = issue.time_entries.find_by_comments('test_put_update_with_note_and_spent_time')
1299 assert_not_nil t
1334 assert_not_nil t
1300 assert_equal 2.5, t.hours
1335 assert_equal 2.5, t.hours
1301 assert_equal spent_hours_before + 2.5, issue.spent_hours
1336 assert_equal spent_hours_before + 2.5, issue.spent_hours
1302 end
1337 end
1303
1338
1304 def test_put_update_with_attachment_only
1339 def test_put_update_with_attachment_only
1305 set_tmp_attachments_directory
1340 set_tmp_attachments_directory
1306
1341
1307 # Delete all fixtured journals, a race condition can occur causing the wrong
1342 # Delete all fixtured journals, a race condition can occur causing the wrong
1308 # journal to get fetched in the next find.
1343 # journal to get fetched in the next find.
1309 Journal.delete_all
1344 Journal.delete_all
1310
1345
1311 # anonymous user
1346 # anonymous user
1312 assert_difference 'Attachment.count' do
1347 assert_difference 'Attachment.count' do
1313 put :update, :id => 1,
1348 put :update, :id => 1,
1314 :notes => '',
1349 :notes => '',
1315 :attachments => {'1' => {'file' => uploaded_test_file('testfile.txt', 'text/plain'), 'description' => 'test file'}}
1350 :attachments => {'1' => {'file' => uploaded_test_file('testfile.txt', 'text/plain'), 'description' => 'test file'}}
1316 end
1351 end
1317
1352
1318 assert_redirected_to :action => 'show', :id => '1'
1353 assert_redirected_to :action => 'show', :id => '1'
1319 j = Issue.find(1).journals.find(:first, :order => 'id DESC')
1354 j = Issue.find(1).journals.find(:first, :order => 'id DESC')
1320 assert j.notes.blank?
1355 assert j.notes.blank?
1321 assert_equal 1, j.details.size
1356 assert_equal 1, j.details.size
1322 assert_equal 'testfile.txt', j.details.first.value
1357 assert_equal 'testfile.txt', j.details.first.value
1323 assert_equal User.anonymous, j.user
1358 assert_equal User.anonymous, j.user
1324
1359
1325 attachment = Attachment.first(:order => 'id DESC')
1360 attachment = Attachment.first(:order => 'id DESC')
1326 assert_equal Issue.find(1), attachment.container
1361 assert_equal Issue.find(1), attachment.container
1327 assert_equal User.anonymous, attachment.author
1362 assert_equal User.anonymous, attachment.author
1328 assert_equal 'testfile.txt', attachment.filename
1363 assert_equal 'testfile.txt', attachment.filename
1329 assert_equal 'text/plain', attachment.content_type
1364 assert_equal 'text/plain', attachment.content_type
1330 assert_equal 'test file', attachment.description
1365 assert_equal 'test file', attachment.description
1331 assert_equal 59, attachment.filesize
1366 assert_equal 59, attachment.filesize
1332 assert File.exists?(attachment.diskfile)
1367 assert File.exists?(attachment.diskfile)
1333 assert_equal 59, File.size(attachment.diskfile)
1368 assert_equal 59, File.size(attachment.diskfile)
1334
1369
1335 mail = ActionMailer::Base.deliveries.last
1370 mail = ActionMailer::Base.deliveries.last
1336 assert mail.body.include?('testfile.txt')
1371 assert mail.body.include?('testfile.txt')
1337 end
1372 end
1338
1373
1339 def test_put_update_with_attachment_that_fails_to_save
1374 def test_put_update_with_attachment_that_fails_to_save
1340 set_tmp_attachments_directory
1375 set_tmp_attachments_directory
1341
1376
1342 # Delete all fixtured journals, a race condition can occur causing the wrong
1377 # Delete all fixtured journals, a race condition can occur causing the wrong
1343 # journal to get fetched in the next find.
1378 # journal to get fetched in the next find.
1344 Journal.delete_all
1379 Journal.delete_all
1345
1380
1346 # Mock out the unsaved attachment
1381 # Mock out the unsaved attachment
1347 Attachment.any_instance.stubs(:create).returns(Attachment.new)
1382 Attachment.any_instance.stubs(:create).returns(Attachment.new)
1348
1383
1349 # anonymous user
1384 # anonymous user
1350 put :update,
1385 put :update,
1351 :id => 1,
1386 :id => 1,
1352 :notes => '',
1387 :notes => '',
1353 :attachments => {'1' => {'file' => uploaded_test_file('testfile.txt', 'text/plain')}}
1388 :attachments => {'1' => {'file' => uploaded_test_file('testfile.txt', 'text/plain')}}
1354 assert_redirected_to :action => 'show', :id => '1'
1389 assert_redirected_to :action => 'show', :id => '1'
1355 assert_equal '1 file(s) could not be saved.', flash[:warning]
1390 assert_equal '1 file(s) could not be saved.', flash[:warning]
1356
1391
1357 end if Object.const_defined?(:Mocha)
1392 end if Object.const_defined?(:Mocha)
1358
1393
1359 def test_put_update_with_no_change
1394 def test_put_update_with_no_change
1360 issue = Issue.find(1)
1395 issue = Issue.find(1)
1361 issue.journals.clear
1396 issue.journals.clear
1362 ActionMailer::Base.deliveries.clear
1397 ActionMailer::Base.deliveries.clear
1363
1398
1364 put :update,
1399 put :update,
1365 :id => 1,
1400 :id => 1,
1366 :notes => ''
1401 :notes => ''
1367 assert_redirected_to :action => 'show', :id => '1'
1402 assert_redirected_to :action => 'show', :id => '1'
1368
1403
1369 issue.reload
1404 issue.reload
1370 assert issue.journals.empty?
1405 assert issue.journals.empty?
1371 # No email should be sent
1406 # No email should be sent
1372 assert ActionMailer::Base.deliveries.empty?
1407 assert ActionMailer::Base.deliveries.empty?
1373 end
1408 end
1374
1409
1375 def test_put_update_should_send_a_notification
1410 def test_put_update_should_send_a_notification
1376 @request.session[:user_id] = 2
1411 @request.session[:user_id] = 2
1377 ActionMailer::Base.deliveries.clear
1412 ActionMailer::Base.deliveries.clear
1378 issue = Issue.find(1)
1413 issue = Issue.find(1)
1379 old_subject = issue.subject
1414 old_subject = issue.subject
1380 new_subject = 'Subject modified by IssuesControllerTest#test_post_edit'
1415 new_subject = 'Subject modified by IssuesControllerTest#test_post_edit'
1381
1416
1382 put :update, :id => 1, :issue => {:subject => new_subject,
1417 put :update, :id => 1, :issue => {:subject => new_subject,
1383 :priority_id => '6',
1418 :priority_id => '6',
1384 :category_id => '1' # no change
1419 :category_id => '1' # no change
1385 }
1420 }
1386 assert_equal 1, ActionMailer::Base.deliveries.size
1421 assert_equal 1, ActionMailer::Base.deliveries.size
1387 end
1422 end
1388
1423
1389 def test_put_update_with_invalid_spent_time_hours_only
1424 def test_put_update_with_invalid_spent_time_hours_only
1390 @request.session[:user_id] = 2
1425 @request.session[:user_id] = 2
1391 notes = 'Note added by IssuesControllerTest#test_post_edit_with_invalid_spent_time'
1426 notes = 'Note added by IssuesControllerTest#test_post_edit_with_invalid_spent_time'
1392
1427
1393 assert_no_difference('Journal.count') do
1428 assert_no_difference('Journal.count') do
1394 put :update,
1429 put :update,
1395 :id => 1,
1430 :id => 1,
1396 :notes => notes,
1431 :notes => notes,
1397 :time_entry => {"comments"=>"", "activity_id"=>"", "hours"=>"2z"}
1432 :time_entry => {"comments"=>"", "activity_id"=>"", "hours"=>"2z"}
1398 end
1433 end
1399 assert_response :success
1434 assert_response :success
1400 assert_template 'edit'
1435 assert_template 'edit'
1401
1436
1402 assert_error_tag :descendant => {:content => /Activity can't be blank/}
1437 assert_error_tag :descendant => {:content => /Activity can't be blank/}
1403 assert_tag :textarea, :attributes => { :name => 'notes' }, :content => notes
1438 assert_tag :textarea, :attributes => { :name => 'notes' }, :content => notes
1404 assert_tag :input, :attributes => { :name => 'time_entry[hours]', :value => "2z" }
1439 assert_tag :input, :attributes => { :name => 'time_entry[hours]', :value => "2z" }
1405 end
1440 end
1406
1441
1407 def test_put_update_with_invalid_spent_time_comments_only
1442 def test_put_update_with_invalid_spent_time_comments_only
1408 @request.session[:user_id] = 2
1443 @request.session[:user_id] = 2
1409 notes = 'Note added by IssuesControllerTest#test_post_edit_with_invalid_spent_time'
1444 notes = 'Note added by IssuesControllerTest#test_post_edit_with_invalid_spent_time'
1410
1445
1411 assert_no_difference('Journal.count') do
1446 assert_no_difference('Journal.count') do
1412 put :update,
1447 put :update,
1413 :id => 1,
1448 :id => 1,
1414 :notes => notes,
1449 :notes => notes,
1415 :time_entry => {"comments"=>"this is my comment", "activity_id"=>"", "hours"=>""}
1450 :time_entry => {"comments"=>"this is my comment", "activity_id"=>"", "hours"=>""}
1416 end
1451 end
1417 assert_response :success
1452 assert_response :success
1418 assert_template 'edit'
1453 assert_template 'edit'
1419
1454
1420 assert_error_tag :descendant => {:content => /Activity can't be blank/}
1455 assert_error_tag :descendant => {:content => /Activity can't be blank/}
1421 assert_error_tag :descendant => {:content => /Hours can't be blank/}
1456 assert_error_tag :descendant => {:content => /Hours can't be blank/}
1422 assert_tag :textarea, :attributes => { :name => 'notes' }, :content => notes
1457 assert_tag :textarea, :attributes => { :name => 'notes' }, :content => notes
1423 assert_tag :input, :attributes => { :name => 'time_entry[comments]', :value => "this is my comment" }
1458 assert_tag :input, :attributes => { :name => 'time_entry[comments]', :value => "this is my comment" }
1424 end
1459 end
1425
1460
1426 def test_put_update_should_allow_fixed_version_to_be_set_to_a_subproject
1461 def test_put_update_should_allow_fixed_version_to_be_set_to_a_subproject
1427 issue = Issue.find(2)
1462 issue = Issue.find(2)
1428 @request.session[:user_id] = 2
1463 @request.session[:user_id] = 2
1429
1464
1430 put :update,
1465 put :update,
1431 :id => issue.id,
1466 :id => issue.id,
1432 :issue => {
1467 :issue => {
1433 :fixed_version_id => 4
1468 :fixed_version_id => 4
1434 }
1469 }
1435
1470
1436 assert_response :redirect
1471 assert_response :redirect
1437 issue.reload
1472 issue.reload
1438 assert_equal 4, issue.fixed_version_id
1473 assert_equal 4, issue.fixed_version_id
1439 assert_not_equal issue.project_id, issue.fixed_version.project_id
1474 assert_not_equal issue.project_id, issue.fixed_version.project_id
1440 end
1475 end
1441
1476
1442 def test_put_update_should_redirect_back_using_the_back_url_parameter
1477 def test_put_update_should_redirect_back_using_the_back_url_parameter
1443 issue = Issue.find(2)
1478 issue = Issue.find(2)
1444 @request.session[:user_id] = 2
1479 @request.session[:user_id] = 2
1445
1480
1446 put :update,
1481 put :update,
1447 :id => issue.id,
1482 :id => issue.id,
1448 :issue => {
1483 :issue => {
1449 :fixed_version_id => 4
1484 :fixed_version_id => 4
1450 },
1485 },
1451 :back_url => '/issues'
1486 :back_url => '/issues'
1452
1487
1453 assert_response :redirect
1488 assert_response :redirect
1454 assert_redirected_to '/issues'
1489 assert_redirected_to '/issues'
1455 end
1490 end
1456
1491
1457 def test_put_update_should_not_redirect_back_using_the_back_url_parameter_off_the_host
1492 def test_put_update_should_not_redirect_back_using_the_back_url_parameter_off_the_host
1458 issue = Issue.find(2)
1493 issue = Issue.find(2)
1459 @request.session[:user_id] = 2
1494 @request.session[:user_id] = 2
1460
1495
1461 put :update,
1496 put :update,
1462 :id => issue.id,
1497 :id => issue.id,
1463 :issue => {
1498 :issue => {
1464 :fixed_version_id => 4
1499 :fixed_version_id => 4
1465 },
1500 },
1466 :back_url => 'http://google.com'
1501 :back_url => 'http://google.com'
1467
1502
1468 assert_response :redirect
1503 assert_response :redirect
1469 assert_redirected_to :controller => 'issues', :action => 'show', :id => issue.id
1504 assert_redirected_to :controller => 'issues', :action => 'show', :id => issue.id
1470 end
1505 end
1471
1506
1472 def test_get_bulk_edit
1507 def test_get_bulk_edit
1473 @request.session[:user_id] = 2
1508 @request.session[:user_id] = 2
1474 get :bulk_edit, :ids => [1, 2]
1509 get :bulk_edit, :ids => [1, 2]
1475 assert_response :success
1510 assert_response :success
1476 assert_template 'bulk_edit'
1511 assert_template 'bulk_edit'
1477
1512
1478 assert_tag :input, :attributes => {:name => 'issue[parent_issue_id]'}
1513 assert_tag :input, :attributes => {:name => 'issue[parent_issue_id]'}
1479
1514
1480 # Project specific custom field, date type
1515 # Project specific custom field, date type
1481 field = CustomField.find(9)
1516 field = CustomField.find(9)
1482 assert !field.is_for_all?
1517 assert !field.is_for_all?
1483 assert_equal 'date', field.field_format
1518 assert_equal 'date', field.field_format
1484 assert_tag :input, :attributes => {:name => 'issue[custom_field_values][9]'}
1519 assert_tag :input, :attributes => {:name => 'issue[custom_field_values][9]'}
1485
1520
1486 # System wide custom field
1521 # System wide custom field
1487 assert CustomField.find(1).is_for_all?
1522 assert CustomField.find(1).is_for_all?
1488 assert_tag :select, :attributes => {:name => 'issue[custom_field_values][1]'}
1523 assert_tag :select, :attributes => {:name => 'issue[custom_field_values][1]'}
1489
1524
1490 # Be sure we don't display inactive IssuePriorities
1525 # Be sure we don't display inactive IssuePriorities
1491 assert ! IssuePriority.find(15).active?
1526 assert ! IssuePriority.find(15).active?
1492 assert_no_tag :option, :attributes => {:value => '15'},
1527 assert_no_tag :option, :attributes => {:value => '15'},
1493 :parent => {:tag => 'select', :attributes => {:id => 'issue_priority_id'} }
1528 :parent => {:tag => 'select', :attributes => {:id => 'issue_priority_id'} }
1494 end
1529 end
1495
1530
1496 def test_get_bulk_edit_on_different_projects
1531 def test_get_bulk_edit_on_different_projects
1497 @request.session[:user_id] = 2
1532 @request.session[:user_id] = 2
1498 get :bulk_edit, :ids => [1, 2, 6]
1533 get :bulk_edit, :ids => [1, 2, 6]
1499 assert_response :success
1534 assert_response :success
1500 assert_template 'bulk_edit'
1535 assert_template 'bulk_edit'
1501
1536
1502 # Can not set issues from different projects as children of an issue
1537 # Can not set issues from different projects as children of an issue
1503 assert_no_tag :input, :attributes => {:name => 'issue[parent_issue_id]'}
1538 assert_no_tag :input, :attributes => {:name => 'issue[parent_issue_id]'}
1504
1539
1505 # Project specific custom field, date type
1540 # Project specific custom field, date type
1506 field = CustomField.find(9)
1541 field = CustomField.find(9)
1507 assert !field.is_for_all?
1542 assert !field.is_for_all?
1508 assert !field.project_ids.include?(Issue.find(6).project_id)
1543 assert !field.project_ids.include?(Issue.find(6).project_id)
1509 assert_no_tag :input, :attributes => {:name => 'issue[custom_field_values][9]'}
1544 assert_no_tag :input, :attributes => {:name => 'issue[custom_field_values][9]'}
1510 end
1545 end
1511
1546
1512 def test_get_bulk_edit_with_user_custom_field
1547 def test_get_bulk_edit_with_user_custom_field
1513 field = IssueCustomField.create!(:name => 'Tester', :field_format => 'user', :is_for_all => true)
1548 field = IssueCustomField.create!(:name => 'Tester', :field_format => 'user', :is_for_all => true)
1514
1549
1515 @request.session[:user_id] = 2
1550 @request.session[:user_id] = 2
1516 get :bulk_edit, :ids => [1, 2]
1551 get :bulk_edit, :ids => [1, 2]
1517 assert_response :success
1552 assert_response :success
1518 assert_template 'bulk_edit'
1553 assert_template 'bulk_edit'
1519
1554
1520 assert_tag :select,
1555 assert_tag :select,
1521 :attributes => {:name => "issue[custom_field_values][#{field.id}]"},
1556 :attributes => {:name => "issue[custom_field_values][#{field.id}]"},
1522 :children => {
1557 :children => {
1523 :only => {:tag => 'option'},
1558 :only => {:tag => 'option'},
1524 :count => Project.find(1).users.count + 1
1559 :count => Project.find(1).users.count + 1
1525 }
1560 }
1526 end
1561 end
1527
1562
1528 def test_get_bulk_edit_with_version_custom_field
1563 def test_get_bulk_edit_with_version_custom_field
1529 field = IssueCustomField.create!(:name => 'Affected version', :field_format => 'version', :is_for_all => true)
1564 field = IssueCustomField.create!(:name => 'Affected version', :field_format => 'version', :is_for_all => true)
1530
1565
1531 @request.session[:user_id] = 2
1566 @request.session[:user_id] = 2
1532 get :bulk_edit, :ids => [1, 2]
1567 get :bulk_edit, :ids => [1, 2]
1533 assert_response :success
1568 assert_response :success
1534 assert_template 'bulk_edit'
1569 assert_template 'bulk_edit'
1535
1570
1536 assert_tag :select,
1571 assert_tag :select,
1537 :attributes => {:name => "issue[custom_field_values][#{field.id}]"},
1572 :attributes => {:name => "issue[custom_field_values][#{field.id}]"},
1538 :children => {
1573 :children => {
1539 :only => {:tag => 'option'},
1574 :only => {:tag => 'option'},
1540 :count => Project.find(1).shared_versions.count + 1
1575 :count => Project.find(1).shared_versions.count + 1
1541 }
1576 }
1542 end
1577 end
1543
1578
1544 def test_bulk_update
1579 def test_bulk_update
1545 @request.session[:user_id] = 2
1580 @request.session[:user_id] = 2
1546 # update issues priority
1581 # update issues priority
1547 post :bulk_update, :ids => [1, 2], :notes => 'Bulk editing',
1582 post :bulk_update, :ids => [1, 2], :notes => 'Bulk editing',
1548 :issue => {:priority_id => 7,
1583 :issue => {:priority_id => 7,
1549 :assigned_to_id => '',
1584 :assigned_to_id => '',
1550 :custom_field_values => {'2' => ''}}
1585 :custom_field_values => {'2' => ''}}
1551
1586
1552 assert_response 302
1587 assert_response 302
1553 # check that the issues were updated
1588 # check that the issues were updated
1554 assert_equal [7, 7], Issue.find_all_by_id([1, 2]).collect {|i| i.priority.id}
1589 assert_equal [7, 7], Issue.find_all_by_id([1, 2]).collect {|i| i.priority.id}
1555
1590
1556 issue = Issue.find(1)
1591 issue = Issue.find(1)
1557 journal = issue.journals.find(:first, :order => 'created_on DESC')
1592 journal = issue.journals.find(:first, :order => 'created_on DESC')
1558 assert_equal '125', issue.custom_value_for(2).value
1593 assert_equal '125', issue.custom_value_for(2).value
1559 assert_equal 'Bulk editing', journal.notes
1594 assert_equal 'Bulk editing', journal.notes
1560 assert_equal 1, journal.details.size
1595 assert_equal 1, journal.details.size
1561 end
1596 end
1562
1597
1563 def test_bulk_update_with_group_assignee
1598 def test_bulk_update_with_group_assignee
1564 group = Group.find(11)
1599 group = Group.find(11)
1565 project = Project.find(1)
1600 project = Project.find(1)
1566 project.members << Member.new(:principal => group, :roles => [Role.first])
1601 project.members << Member.new(:principal => group, :roles => [Role.first])
1567
1602
1568 @request.session[:user_id] = 2
1603 @request.session[:user_id] = 2
1569 # update issues assignee
1604 # update issues assignee
1570 post :bulk_update, :ids => [1, 2], :notes => 'Bulk editing',
1605 post :bulk_update, :ids => [1, 2], :notes => 'Bulk editing',
1571 :issue => {:priority_id => '',
1606 :issue => {:priority_id => '',
1572 :assigned_to_id => group.id,
1607 :assigned_to_id => group.id,
1573 :custom_field_values => {'2' => ''}}
1608 :custom_field_values => {'2' => ''}}
1574
1609
1575 assert_response 302
1610 assert_response 302
1576 assert_equal [group, group], Issue.find_all_by_id([1, 2]).collect {|i| i.assigned_to}
1611 assert_equal [group, group], Issue.find_all_by_id([1, 2]).collect {|i| i.assigned_to}
1577 end
1612 end
1578
1613
1579 def test_bulk_update_on_different_projects
1614 def test_bulk_update_on_different_projects
1580 @request.session[:user_id] = 2
1615 @request.session[:user_id] = 2
1581 # update issues priority
1616 # update issues priority
1582 post :bulk_update, :ids => [1, 2, 6], :notes => 'Bulk editing',
1617 post :bulk_update, :ids => [1, 2, 6], :notes => 'Bulk editing',
1583 :issue => {:priority_id => 7,
1618 :issue => {:priority_id => 7,
1584 :assigned_to_id => '',
1619 :assigned_to_id => '',
1585 :custom_field_values => {'2' => ''}}
1620 :custom_field_values => {'2' => ''}}
1586
1621
1587 assert_response 302
1622 assert_response 302
1588 # check that the issues were updated
1623 # check that the issues were updated
1589 assert_equal [7, 7, 7], Issue.find([1,2,6]).map(&:priority_id)
1624 assert_equal [7, 7, 7], Issue.find([1,2,6]).map(&:priority_id)
1590
1625
1591 issue = Issue.find(1)
1626 issue = Issue.find(1)
1592 journal = issue.journals.find(:first, :order => 'created_on DESC')
1627 journal = issue.journals.find(:first, :order => 'created_on DESC')
1593 assert_equal '125', issue.custom_value_for(2).value
1628 assert_equal '125', issue.custom_value_for(2).value
1594 assert_equal 'Bulk editing', journal.notes
1629 assert_equal 'Bulk editing', journal.notes
1595 assert_equal 1, journal.details.size
1630 assert_equal 1, journal.details.size
1596 end
1631 end
1597
1632
1598 def test_bulk_update_on_different_projects_without_rights
1633 def test_bulk_update_on_different_projects_without_rights
1599 @request.session[:user_id] = 3
1634 @request.session[:user_id] = 3
1600 user = User.find(3)
1635 user = User.find(3)
1601 action = { :controller => "issues", :action => "bulk_update" }
1636 action = { :controller => "issues", :action => "bulk_update" }
1602 assert user.allowed_to?(action, Issue.find(1).project)
1637 assert user.allowed_to?(action, Issue.find(1).project)
1603 assert ! user.allowed_to?(action, Issue.find(6).project)
1638 assert ! user.allowed_to?(action, Issue.find(6).project)
1604 post :bulk_update, :ids => [1, 6], :notes => 'Bulk should fail',
1639 post :bulk_update, :ids => [1, 6], :notes => 'Bulk should fail',
1605 :issue => {:priority_id => 7,
1640 :issue => {:priority_id => 7,
1606 :assigned_to_id => '',
1641 :assigned_to_id => '',
1607 :custom_field_values => {'2' => ''}}
1642 :custom_field_values => {'2' => ''}}
1608 assert_response 403
1643 assert_response 403
1609 assert_not_equal "Bulk should fail", Journal.last.notes
1644 assert_not_equal "Bulk should fail", Journal.last.notes
1610 end
1645 end
1611
1646
1612 def test_bullk_update_should_send_a_notification
1647 def test_bullk_update_should_send_a_notification
1613 @request.session[:user_id] = 2
1648 @request.session[:user_id] = 2
1614 ActionMailer::Base.deliveries.clear
1649 ActionMailer::Base.deliveries.clear
1615 post(:bulk_update,
1650 post(:bulk_update,
1616 {
1651 {
1617 :ids => [1, 2],
1652 :ids => [1, 2],
1618 :notes => 'Bulk editing',
1653 :notes => 'Bulk editing',
1619 :issue => {
1654 :issue => {
1620 :priority_id => 7,
1655 :priority_id => 7,
1621 :assigned_to_id => '',
1656 :assigned_to_id => '',
1622 :custom_field_values => {'2' => ''}
1657 :custom_field_values => {'2' => ''}
1623 }
1658 }
1624 })
1659 })
1625
1660
1626 assert_response 302
1661 assert_response 302
1627 assert_equal 2, ActionMailer::Base.deliveries.size
1662 assert_equal 2, ActionMailer::Base.deliveries.size
1628 end
1663 end
1629
1664
1630 def test_bulk_update_status
1665 def test_bulk_update_status
1631 @request.session[:user_id] = 2
1666 @request.session[:user_id] = 2
1632 # update issues priority
1667 # update issues priority
1633 post :bulk_update, :ids => [1, 2], :notes => 'Bulk editing status',
1668 post :bulk_update, :ids => [1, 2], :notes => 'Bulk editing status',
1634 :issue => {:priority_id => '',
1669 :issue => {:priority_id => '',
1635 :assigned_to_id => '',
1670 :assigned_to_id => '',
1636 :status_id => '5'}
1671 :status_id => '5'}
1637
1672
1638 assert_response 302
1673 assert_response 302
1639 issue = Issue.find(1)
1674 issue = Issue.find(1)
1640 assert issue.closed?
1675 assert issue.closed?
1641 end
1676 end
1642
1677
1643 def test_bulk_update_parent_id
1678 def test_bulk_update_parent_id
1644 @request.session[:user_id] = 2
1679 @request.session[:user_id] = 2
1645 post :bulk_update, :ids => [1, 3],
1680 post :bulk_update, :ids => [1, 3],
1646 :notes => 'Bulk editing parent',
1681 :notes => 'Bulk editing parent',
1647 :issue => {:priority_id => '', :assigned_to_id => '', :status_id => '', :parent_issue_id => '2'}
1682 :issue => {:priority_id => '', :assigned_to_id => '', :status_id => '', :parent_issue_id => '2'}
1648
1683
1649 assert_response 302
1684 assert_response 302
1650 parent = Issue.find(2)
1685 parent = Issue.find(2)
1651 assert_equal parent.id, Issue.find(1).parent_id
1686 assert_equal parent.id, Issue.find(1).parent_id
1652 assert_equal parent.id, Issue.find(3).parent_id
1687 assert_equal parent.id, Issue.find(3).parent_id
1653 assert_equal [1, 3], parent.children.collect(&:id).sort
1688 assert_equal [1, 3], parent.children.collect(&:id).sort
1654 end
1689 end
1655
1690
1656 def test_bulk_update_custom_field
1691 def test_bulk_update_custom_field
1657 @request.session[:user_id] = 2
1692 @request.session[:user_id] = 2
1658 # update issues priority
1693 # update issues priority
1659 post :bulk_update, :ids => [1, 2], :notes => 'Bulk editing custom field',
1694 post :bulk_update, :ids => [1, 2], :notes => 'Bulk editing custom field',
1660 :issue => {:priority_id => '',
1695 :issue => {:priority_id => '',
1661 :assigned_to_id => '',
1696 :assigned_to_id => '',
1662 :custom_field_values => {'2' => '777'}}
1697 :custom_field_values => {'2' => '777'}}
1663
1698
1664 assert_response 302
1699 assert_response 302
1665
1700
1666 issue = Issue.find(1)
1701 issue = Issue.find(1)
1667 journal = issue.journals.find(:first, :order => 'created_on DESC')
1702 journal = issue.journals.find(:first, :order => 'created_on DESC')
1668 assert_equal '777', issue.custom_value_for(2).value
1703 assert_equal '777', issue.custom_value_for(2).value
1669 assert_equal 1, journal.details.size
1704 assert_equal 1, journal.details.size
1670 assert_equal '125', journal.details.first.old_value
1705 assert_equal '125', journal.details.first.old_value
1671 assert_equal '777', journal.details.first.value
1706 assert_equal '777', journal.details.first.value
1672 end
1707 end
1673
1708
1674 def test_bulk_update_unassign
1709 def test_bulk_update_unassign
1675 assert_not_nil Issue.find(2).assigned_to
1710 assert_not_nil Issue.find(2).assigned_to
1676 @request.session[:user_id] = 2
1711 @request.session[:user_id] = 2
1677 # unassign issues
1712 # unassign issues
1678 post :bulk_update, :ids => [1, 2], :notes => 'Bulk unassigning', :issue => {:assigned_to_id => 'none'}
1713 post :bulk_update, :ids => [1, 2], :notes => 'Bulk unassigning', :issue => {:assigned_to_id => 'none'}
1679 assert_response 302
1714 assert_response 302
1680 # check that the issues were updated
1715 # check that the issues were updated
1681 assert_nil Issue.find(2).assigned_to
1716 assert_nil Issue.find(2).assigned_to
1682 end
1717 end
1683
1718
1684 def test_post_bulk_update_should_allow_fixed_version_to_be_set_to_a_subproject
1719 def test_post_bulk_update_should_allow_fixed_version_to_be_set_to_a_subproject
1685 @request.session[:user_id] = 2
1720 @request.session[:user_id] = 2
1686
1721
1687 post :bulk_update, :ids => [1,2], :issue => {:fixed_version_id => 4}
1722 post :bulk_update, :ids => [1,2], :issue => {:fixed_version_id => 4}
1688
1723
1689 assert_response :redirect
1724 assert_response :redirect
1690 issues = Issue.find([1,2])
1725 issues = Issue.find([1,2])
1691 issues.each do |issue|
1726 issues.each do |issue|
1692 assert_equal 4, issue.fixed_version_id
1727 assert_equal 4, issue.fixed_version_id
1693 assert_not_equal issue.project_id, issue.fixed_version.project_id
1728 assert_not_equal issue.project_id, issue.fixed_version.project_id
1694 end
1729 end
1695 end
1730 end
1696
1731
1697 def test_post_bulk_update_should_redirect_back_using_the_back_url_parameter
1732 def test_post_bulk_update_should_redirect_back_using_the_back_url_parameter
1698 @request.session[:user_id] = 2
1733 @request.session[:user_id] = 2
1699 post :bulk_update, :ids => [1,2], :back_url => '/issues'
1734 post :bulk_update, :ids => [1,2], :back_url => '/issues'
1700
1735
1701 assert_response :redirect
1736 assert_response :redirect
1702 assert_redirected_to '/issues'
1737 assert_redirected_to '/issues'
1703 end
1738 end
1704
1739
1705 def test_post_bulk_update_should_not_redirect_back_using_the_back_url_parameter_off_the_host
1740 def test_post_bulk_update_should_not_redirect_back_using_the_back_url_parameter_off_the_host
1706 @request.session[:user_id] = 2
1741 @request.session[:user_id] = 2
1707 post :bulk_update, :ids => [1,2], :back_url => 'http://google.com'
1742 post :bulk_update, :ids => [1,2], :back_url => 'http://google.com'
1708
1743
1709 assert_response :redirect
1744 assert_response :redirect
1710 assert_redirected_to :controller => 'issues', :action => 'index', :project_id => Project.find(1).identifier
1745 assert_redirected_to :controller => 'issues', :action => 'index', :project_id => Project.find(1).identifier
1711 end
1746 end
1712
1747
1713 def test_destroy_issue_with_no_time_entries
1748 def test_destroy_issue_with_no_time_entries
1714 assert_nil TimeEntry.find_by_issue_id(2)
1749 assert_nil TimeEntry.find_by_issue_id(2)
1715 @request.session[:user_id] = 2
1750 @request.session[:user_id] = 2
1716 post :destroy, :id => 2
1751 post :destroy, :id => 2
1717 assert_redirected_to :action => 'index', :project_id => 'ecookbook'
1752 assert_redirected_to :action => 'index', :project_id => 'ecookbook'
1718 assert_nil Issue.find_by_id(2)
1753 assert_nil Issue.find_by_id(2)
1719 end
1754 end
1720
1755
1721 def test_destroy_issues_with_time_entries
1756 def test_destroy_issues_with_time_entries
1722 @request.session[:user_id] = 2
1757 @request.session[:user_id] = 2
1723 post :destroy, :ids => [1, 3]
1758 post :destroy, :ids => [1, 3]
1724 assert_response :success
1759 assert_response :success
1725 assert_template 'destroy'
1760 assert_template 'destroy'
1726 assert_not_nil assigns(:hours)
1761 assert_not_nil assigns(:hours)
1727 assert Issue.find_by_id(1) && Issue.find_by_id(3)
1762 assert Issue.find_by_id(1) && Issue.find_by_id(3)
1728 end
1763 end
1729
1764
1730 def test_destroy_issues_and_destroy_time_entries
1765 def test_destroy_issues_and_destroy_time_entries
1731 @request.session[:user_id] = 2
1766 @request.session[:user_id] = 2
1732 post :destroy, :ids => [1, 3], :todo => 'destroy'
1767 post :destroy, :ids => [1, 3], :todo => 'destroy'
1733 assert_redirected_to :action => 'index', :project_id => 'ecookbook'
1768 assert_redirected_to :action => 'index', :project_id => 'ecookbook'
1734 assert !(Issue.find_by_id(1) || Issue.find_by_id(3))
1769 assert !(Issue.find_by_id(1) || Issue.find_by_id(3))
1735 assert_nil TimeEntry.find_by_id([1, 2])
1770 assert_nil TimeEntry.find_by_id([1, 2])
1736 end
1771 end
1737
1772
1738 def test_destroy_issues_and_assign_time_entries_to_project
1773 def test_destroy_issues_and_assign_time_entries_to_project
1739 @request.session[:user_id] = 2
1774 @request.session[:user_id] = 2
1740 post :destroy, :ids => [1, 3], :todo => 'nullify'
1775 post :destroy, :ids => [1, 3], :todo => 'nullify'
1741 assert_redirected_to :action => 'index', :project_id => 'ecookbook'
1776 assert_redirected_to :action => 'index', :project_id => 'ecookbook'
1742 assert !(Issue.find_by_id(1) || Issue.find_by_id(3))
1777 assert !(Issue.find_by_id(1) || Issue.find_by_id(3))
1743 assert_nil TimeEntry.find(1).issue_id
1778 assert_nil TimeEntry.find(1).issue_id
1744 assert_nil TimeEntry.find(2).issue_id
1779 assert_nil TimeEntry.find(2).issue_id
1745 end
1780 end
1746
1781
1747 def test_destroy_issues_and_reassign_time_entries_to_another_issue
1782 def test_destroy_issues_and_reassign_time_entries_to_another_issue
1748 @request.session[:user_id] = 2
1783 @request.session[:user_id] = 2
1749 post :destroy, :ids => [1, 3], :todo => 'reassign', :reassign_to_id => 2
1784 post :destroy, :ids => [1, 3], :todo => 'reassign', :reassign_to_id => 2
1750 assert_redirected_to :action => 'index', :project_id => 'ecookbook'
1785 assert_redirected_to :action => 'index', :project_id => 'ecookbook'
1751 assert !(Issue.find_by_id(1) || Issue.find_by_id(3))
1786 assert !(Issue.find_by_id(1) || Issue.find_by_id(3))
1752 assert_equal 2, TimeEntry.find(1).issue_id
1787 assert_equal 2, TimeEntry.find(1).issue_id
1753 assert_equal 2, TimeEntry.find(2).issue_id
1788 assert_equal 2, TimeEntry.find(2).issue_id
1754 end
1789 end
1755
1790
1756 def test_destroy_issues_from_different_projects
1791 def test_destroy_issues_from_different_projects
1757 @request.session[:user_id] = 2
1792 @request.session[:user_id] = 2
1758 post :destroy, :ids => [1, 2, 6], :todo => 'destroy'
1793 post :destroy, :ids => [1, 2, 6], :todo => 'destroy'
1759 assert_redirected_to :controller => 'issues', :action => 'index'
1794 assert_redirected_to :controller => 'issues', :action => 'index'
1760 assert !(Issue.find_by_id(1) || Issue.find_by_id(2) || Issue.find_by_id(6))
1795 assert !(Issue.find_by_id(1) || Issue.find_by_id(2) || Issue.find_by_id(6))
1761 end
1796 end
1762
1797
1763 def test_destroy_parent_and_child_issues
1798 def test_destroy_parent_and_child_issues
1764 parent = Issue.generate!(:project_id => 1, :tracker_id => 1)
1799 parent = Issue.generate!(:project_id => 1, :tracker_id => 1)
1765 child = Issue.generate!(:project_id => 1, :tracker_id => 1, :parent_issue_id => parent.id)
1800 child = Issue.generate!(:project_id => 1, :tracker_id => 1, :parent_issue_id => parent.id)
1766 assert child.is_descendant_of?(parent.reload)
1801 assert child.is_descendant_of?(parent.reload)
1767
1802
1768 @request.session[:user_id] = 2
1803 @request.session[:user_id] = 2
1769 assert_difference 'Issue.count', -2 do
1804 assert_difference 'Issue.count', -2 do
1770 post :destroy, :ids => [parent.id, child.id], :todo => 'destroy'
1805 post :destroy, :ids => [parent.id, child.id], :todo => 'destroy'
1771 end
1806 end
1772 assert_response 302
1807 assert_response 302
1773 end
1808 end
1774
1809
1775 def test_default_search_scope
1810 def test_default_search_scope
1776 get :index
1811 get :index
1777 assert_tag :div, :attributes => {:id => 'quick-search'},
1812 assert_tag :div, :attributes => {:id => 'quick-search'},
1778 :child => {:tag => 'form',
1813 :child => {:tag => 'form',
1779 :child => {:tag => 'input', :attributes => {:name => 'issues', :type => 'hidden', :value => '1'}}}
1814 :child => {:tag => 'input', :attributes => {:name => 'issues', :type => 'hidden', :value => '1'}}}
1780 end
1815 end
1781 end
1816 end
General Comments 0
You need to be logged in to leave comments. Login now