##// END OF EJS Templates
Fixed: Issue status in the notify email's subject is the issue's old status, should be its new status (#3194)....
Jean-Philippe Lang -
r2581:2a3fe1604a6e
parent child
Show More
@@ -1,353 +1,353
1 # redMine - project management software
1 # redMine - project management software
2 # Copyright (C) 2006-2007 Jean-Philippe Lang
2 # Copyright (C) 2006-2007 Jean-Philippe Lang
3 #
3 #
4 # This program is free software; you can redistribute it and/or
4 # This program is free software; you can redistribute it and/or
5 # modify it under the terms of the GNU General Public License
5 # modify it under the terms of the GNU General Public License
6 # as published by the Free Software Foundation; either version 2
6 # as published by the Free Software Foundation; either version 2
7 # of the License, or (at your option) any later version.
7 # of the License, or (at your option) any later version.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU General Public License
14 # You should have received a copy of the GNU General Public License
15 # along with this program; if not, write to the Free Software
15 # along with this program; if not, write to the Free Software
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17
17
18 class Mailer < ActionMailer::Base
18 class Mailer < ActionMailer::Base
19 helper :application
19 helper :application
20 helper :issues
20 helper :issues
21 helper :custom_fields
21 helper :custom_fields
22
22
23 include ActionController::UrlWriter
23 include ActionController::UrlWriter
24 include Redmine::I18n
24 include Redmine::I18n
25
25
26 def self.default_url_options
26 def self.default_url_options
27 h = Setting.host_name
27 h = Setting.host_name
28 h = h.to_s.gsub(%r{\/.*$}, '') unless Redmine::Utils.relative_url_root.blank?
28 h = h.to_s.gsub(%r{\/.*$}, '') unless Redmine::Utils.relative_url_root.blank?
29 { :host => h, :protocol => Setting.protocol }
29 { :host => h, :protocol => Setting.protocol }
30 end
30 end
31
31
32 # Builds a tmail object used to email recipients of the added issue.
32 # Builds a tmail object used to email recipients of the added issue.
33 #
33 #
34 # Example:
34 # Example:
35 # issue_add(issue) => tmail object
35 # issue_add(issue) => tmail object
36 # Mailer.deliver_issue_add(issue) => sends an email to issue recipients
36 # Mailer.deliver_issue_add(issue) => sends an email to issue recipients
37 def issue_add(issue)
37 def issue_add(issue)
38 redmine_headers 'Project' => issue.project.identifier,
38 redmine_headers 'Project' => issue.project.identifier,
39 'Issue-Id' => issue.id,
39 'Issue-Id' => issue.id,
40 'Issue-Author' => issue.author.login
40 'Issue-Author' => issue.author.login
41 redmine_headers 'Issue-Assignee' => issue.assigned_to.login if issue.assigned_to
41 redmine_headers 'Issue-Assignee' => issue.assigned_to.login if issue.assigned_to
42 message_id issue
42 message_id issue
43 recipients issue.recipients
43 recipients issue.recipients
44 cc(issue.watcher_recipients - @recipients)
44 cc(issue.watcher_recipients - @recipients)
45 subject "[#{issue.project.name} - #{issue.tracker.name} ##{issue.id}] (#{issue.status.name}) #{issue.subject}"
45 subject "[#{issue.project.name} - #{issue.tracker.name} ##{issue.id}] (#{issue.status.name}) #{issue.subject}"
46 body :issue => issue,
46 body :issue => issue,
47 :issue_url => url_for(:controller => 'issues', :action => 'show', :id => issue)
47 :issue_url => url_for(:controller => 'issues', :action => 'show', :id => issue)
48 end
48 end
49
49
50 # Builds a tmail object used to email recipients of the edited issue.
50 # Builds a tmail object used to email recipients of the edited issue.
51 #
51 #
52 # Example:
52 # Example:
53 # issue_edit(journal) => tmail object
53 # issue_edit(journal) => tmail object
54 # Mailer.deliver_issue_edit(journal) => sends an email to issue recipients
54 # Mailer.deliver_issue_edit(journal) => sends an email to issue recipients
55 def issue_edit(journal)
55 def issue_edit(journal)
56 issue = journal.journalized
56 issue = journal.journalized.reload
57 redmine_headers 'Project' => issue.project.identifier,
57 redmine_headers 'Project' => issue.project.identifier,
58 'Issue-Id' => issue.id,
58 'Issue-Id' => issue.id,
59 'Issue-Author' => issue.author.login
59 'Issue-Author' => issue.author.login
60 redmine_headers 'Issue-Assignee' => issue.assigned_to.login if issue.assigned_to
60 redmine_headers 'Issue-Assignee' => issue.assigned_to.login if issue.assigned_to
61 message_id journal
61 message_id journal
62 references issue
62 references issue
63 @author = journal.user
63 @author = journal.user
64 recipients issue.recipients
64 recipients issue.recipients
65 # Watchers in cc
65 # Watchers in cc
66 cc(issue.watcher_recipients - @recipients)
66 cc(issue.watcher_recipients - @recipients)
67 s = "[#{issue.project.name} - #{issue.tracker.name} ##{issue.id}] "
67 s = "[#{issue.project.name} - #{issue.tracker.name} ##{issue.id}] "
68 s << "(#{issue.status.name}) " if journal.new_value_for('status_id')
68 s << "(#{issue.status.name}) " if journal.new_value_for('status_id')
69 s << issue.subject
69 s << issue.subject
70 subject s
70 subject s
71 body :issue => issue,
71 body :issue => issue,
72 :journal => journal,
72 :journal => journal,
73 :issue_url => url_for(:controller => 'issues', :action => 'show', :id => issue)
73 :issue_url => url_for(:controller => 'issues', :action => 'show', :id => issue)
74 end
74 end
75
75
76 def reminder(user, issues, days)
76 def reminder(user, issues, days)
77 set_language_if_valid user.language
77 set_language_if_valid user.language
78 recipients user.mail
78 recipients user.mail
79 subject l(:mail_subject_reminder, issues.size)
79 subject l(:mail_subject_reminder, issues.size)
80 body :issues => issues,
80 body :issues => issues,
81 :days => days,
81 :days => days,
82 :issues_url => url_for(:controller => 'issues', :action => 'index', :set_filter => 1, :assigned_to_id => user.id, :sort_key => 'due_date', :sort_order => 'asc')
82 :issues_url => url_for(:controller => 'issues', :action => 'index', :set_filter => 1, :assigned_to_id => user.id, :sort_key => 'due_date', :sort_order => 'asc')
83 end
83 end
84
84
85 # Builds a tmail object used to email users belonging to the added document's project.
85 # Builds a tmail object used to email users belonging to the added document's project.
86 #
86 #
87 # Example:
87 # Example:
88 # document_added(document) => tmail object
88 # document_added(document) => tmail object
89 # Mailer.deliver_document_added(document) => sends an email to the document's project recipients
89 # Mailer.deliver_document_added(document) => sends an email to the document's project recipients
90 def document_added(document)
90 def document_added(document)
91 redmine_headers 'Project' => document.project.identifier
91 redmine_headers 'Project' => document.project.identifier
92 recipients document.project.recipients
92 recipients document.project.recipients
93 subject "[#{document.project.name}] #{l(:label_document_new)}: #{document.title}"
93 subject "[#{document.project.name}] #{l(:label_document_new)}: #{document.title}"
94 body :document => document,
94 body :document => document,
95 :document_url => url_for(:controller => 'documents', :action => 'show', :id => document)
95 :document_url => url_for(:controller => 'documents', :action => 'show', :id => document)
96 end
96 end
97
97
98 # Builds a tmail object used to email recipients of a project when an attachements are added.
98 # Builds a tmail object used to email recipients of a project when an attachements are added.
99 #
99 #
100 # Example:
100 # Example:
101 # attachments_added(attachments) => tmail object
101 # attachments_added(attachments) => tmail object
102 # Mailer.deliver_attachments_added(attachments) => sends an email to the project's recipients
102 # Mailer.deliver_attachments_added(attachments) => sends an email to the project's recipients
103 def attachments_added(attachments)
103 def attachments_added(attachments)
104 container = attachments.first.container
104 container = attachments.first.container
105 added_to = ''
105 added_to = ''
106 added_to_url = ''
106 added_to_url = ''
107 case container.class.name
107 case container.class.name
108 when 'Project'
108 when 'Project'
109 added_to_url = url_for(:controller => 'projects', :action => 'list_files', :id => container)
109 added_to_url = url_for(:controller => 'projects', :action => 'list_files', :id => container)
110 added_to = "#{l(:label_project)}: #{container}"
110 added_to = "#{l(:label_project)}: #{container}"
111 when 'Version'
111 when 'Version'
112 added_to_url = url_for(:controller => 'projects', :action => 'list_files', :id => container.project_id)
112 added_to_url = url_for(:controller => 'projects', :action => 'list_files', :id => container.project_id)
113 added_to = "#{l(:label_version)}: #{container.name}"
113 added_to = "#{l(:label_version)}: #{container.name}"
114 when 'Document'
114 when 'Document'
115 added_to_url = url_for(:controller => 'documents', :action => 'show', :id => container.id)
115 added_to_url = url_for(:controller => 'documents', :action => 'show', :id => container.id)
116 added_to = "#{l(:label_document)}: #{container.title}"
116 added_to = "#{l(:label_document)}: #{container.title}"
117 end
117 end
118 redmine_headers 'Project' => container.project.identifier
118 redmine_headers 'Project' => container.project.identifier
119 recipients container.project.recipients
119 recipients container.project.recipients
120 subject "[#{container.project.name}] #{l(:label_attachment_new)}"
120 subject "[#{container.project.name}] #{l(:label_attachment_new)}"
121 body :attachments => attachments,
121 body :attachments => attachments,
122 :added_to => added_to,
122 :added_to => added_to,
123 :added_to_url => added_to_url
123 :added_to_url => added_to_url
124 end
124 end
125
125
126 # Builds a tmail object used to email recipients of a news' project when a news item is added.
126 # Builds a tmail object used to email recipients of a news' project when a news item is added.
127 #
127 #
128 # Example:
128 # Example:
129 # news_added(news) => tmail object
129 # news_added(news) => tmail object
130 # Mailer.deliver_news_added(news) => sends an email to the news' project recipients
130 # Mailer.deliver_news_added(news) => sends an email to the news' project recipients
131 def news_added(news)
131 def news_added(news)
132 redmine_headers 'Project' => news.project.identifier
132 redmine_headers 'Project' => news.project.identifier
133 message_id news
133 message_id news
134 recipients news.project.recipients
134 recipients news.project.recipients
135 subject "[#{news.project.name}] #{l(:label_news)}: #{news.title}"
135 subject "[#{news.project.name}] #{l(:label_news)}: #{news.title}"
136 body :news => news,
136 body :news => news,
137 :news_url => url_for(:controller => 'news', :action => 'show', :id => news)
137 :news_url => url_for(:controller => 'news', :action => 'show', :id => news)
138 end
138 end
139
139
140 # Builds a tmail object used to email the specified recipients of the specified message that was posted.
140 # Builds a tmail object used to email the specified recipients of the specified message that was posted.
141 #
141 #
142 # Example:
142 # Example:
143 # message_posted(message, recipients) => tmail object
143 # message_posted(message, recipients) => tmail object
144 # Mailer.deliver_message_posted(message, recipients) => sends an email to the recipients
144 # Mailer.deliver_message_posted(message, recipients) => sends an email to the recipients
145 def message_posted(message, recipients)
145 def message_posted(message, recipients)
146 redmine_headers 'Project' => message.project.identifier,
146 redmine_headers 'Project' => message.project.identifier,
147 'Topic-Id' => (message.parent_id || message.id)
147 'Topic-Id' => (message.parent_id || message.id)
148 message_id message
148 message_id message
149 references message.parent unless message.parent.nil?
149 references message.parent unless message.parent.nil?
150 recipients(recipients)
150 recipients(recipients)
151 subject "[#{message.board.project.name} - #{message.board.name} - msg#{message.root.id}] #{message.subject}"
151 subject "[#{message.board.project.name} - #{message.board.name} - msg#{message.root.id}] #{message.subject}"
152 body :message => message,
152 body :message => message,
153 :message_url => url_for(:controller => 'messages', :action => 'show', :board_id => message.board_id, :id => message.root)
153 :message_url => url_for(:controller => 'messages', :action => 'show', :board_id => message.board_id, :id => message.root)
154 end
154 end
155
155
156 # Builds a tmail object used to email the specified user their account information.
156 # Builds a tmail object used to email the specified user their account information.
157 #
157 #
158 # Example:
158 # Example:
159 # account_information(user, password) => tmail object
159 # account_information(user, password) => tmail object
160 # Mailer.deliver_account_information(user, password) => sends account information to the user
160 # Mailer.deliver_account_information(user, password) => sends account information to the user
161 def account_information(user, password)
161 def account_information(user, password)
162 set_language_if_valid user.language
162 set_language_if_valid user.language
163 recipients user.mail
163 recipients user.mail
164 subject l(:mail_subject_register, Setting.app_title)
164 subject l(:mail_subject_register, Setting.app_title)
165 body :user => user,
165 body :user => user,
166 :password => password,
166 :password => password,
167 :login_url => url_for(:controller => 'account', :action => 'login')
167 :login_url => url_for(:controller => 'account', :action => 'login')
168 end
168 end
169
169
170 # Builds a tmail object used to email all active administrators of an account activation request.
170 # Builds a tmail object used to email all active administrators of an account activation request.
171 #
171 #
172 # Example:
172 # Example:
173 # account_activation_request(user) => tmail object
173 # account_activation_request(user) => tmail object
174 # Mailer.deliver_account_activation_request(user)=> sends an email to all active administrators
174 # Mailer.deliver_account_activation_request(user)=> sends an email to all active administrators
175 def account_activation_request(user)
175 def account_activation_request(user)
176 # Send the email to all active administrators
176 # Send the email to all active administrators
177 recipients User.active.find(:all, :conditions => {:admin => true}).collect { |u| u.mail }.compact
177 recipients User.active.find(:all, :conditions => {:admin => true}).collect { |u| u.mail }.compact
178 subject l(:mail_subject_account_activation_request, Setting.app_title)
178 subject l(:mail_subject_account_activation_request, Setting.app_title)
179 body :user => user,
179 body :user => user,
180 :url => url_for(:controller => 'users', :action => 'index', :status => User::STATUS_REGISTERED, :sort_key => 'created_on', :sort_order => 'desc')
180 :url => url_for(:controller => 'users', :action => 'index', :status => User::STATUS_REGISTERED, :sort_key => 'created_on', :sort_order => 'desc')
181 end
181 end
182
182
183 # Builds a tmail object used to email the specified user that their account was activated by an administrator.
183 # Builds a tmail object used to email the specified user that their account was activated by an administrator.
184 #
184 #
185 # Example:
185 # Example:
186 # account_activated(user) => tmail object
186 # account_activated(user) => tmail object
187 # Mailer.deliver_account_activated(user) => sends an email to the registered user
187 # Mailer.deliver_account_activated(user) => sends an email to the registered user
188 def account_activated(user)
188 def account_activated(user)
189 set_language_if_valid user.language
189 set_language_if_valid user.language
190 recipients user.mail
190 recipients user.mail
191 subject l(:mail_subject_register, Setting.app_title)
191 subject l(:mail_subject_register, Setting.app_title)
192 body :user => user,
192 body :user => user,
193 :login_url => url_for(:controller => 'account', :action => 'login')
193 :login_url => url_for(:controller => 'account', :action => 'login')
194 end
194 end
195
195
196 def lost_password(token)
196 def lost_password(token)
197 set_language_if_valid(token.user.language)
197 set_language_if_valid(token.user.language)
198 recipients token.user.mail
198 recipients token.user.mail
199 subject l(:mail_subject_lost_password, Setting.app_title)
199 subject l(:mail_subject_lost_password, Setting.app_title)
200 body :token => token,
200 body :token => token,
201 :url => url_for(:controller => 'account', :action => 'lost_password', :token => token.value)
201 :url => url_for(:controller => 'account', :action => 'lost_password', :token => token.value)
202 end
202 end
203
203
204 def register(token)
204 def register(token)
205 set_language_if_valid(token.user.language)
205 set_language_if_valid(token.user.language)
206 recipients token.user.mail
206 recipients token.user.mail
207 subject l(:mail_subject_register, Setting.app_title)
207 subject l(:mail_subject_register, Setting.app_title)
208 body :token => token,
208 body :token => token,
209 :url => url_for(:controller => 'account', :action => 'activate', :token => token.value)
209 :url => url_for(:controller => 'account', :action => 'activate', :token => token.value)
210 end
210 end
211
211
212 def test(user)
212 def test(user)
213 set_language_if_valid(user.language)
213 set_language_if_valid(user.language)
214 recipients user.mail
214 recipients user.mail
215 subject 'Redmine test'
215 subject 'Redmine test'
216 body :url => url_for(:controller => 'welcome')
216 body :url => url_for(:controller => 'welcome')
217 end
217 end
218
218
219 # Overrides default deliver! method to prevent from sending an email
219 # Overrides default deliver! method to prevent from sending an email
220 # with no recipient, cc or bcc
220 # with no recipient, cc or bcc
221 def deliver!(mail = @mail)
221 def deliver!(mail = @mail)
222 return false if (recipients.nil? || recipients.empty?) &&
222 return false if (recipients.nil? || recipients.empty?) &&
223 (cc.nil? || cc.empty?) &&
223 (cc.nil? || cc.empty?) &&
224 (bcc.nil? || bcc.empty?)
224 (bcc.nil? || bcc.empty?)
225
225
226 # Set Message-Id and References
226 # Set Message-Id and References
227 if @message_id_object
227 if @message_id_object
228 mail.message_id = self.class.message_id_for(@message_id_object)
228 mail.message_id = self.class.message_id_for(@message_id_object)
229 end
229 end
230 if @references_objects
230 if @references_objects
231 mail.references = @references_objects.collect {|o| self.class.message_id_for(o)}
231 mail.references = @references_objects.collect {|o| self.class.message_id_for(o)}
232 end
232 end
233 super(mail)
233 super(mail)
234 end
234 end
235
235
236 # Sends reminders to issue assignees
236 # Sends reminders to issue assignees
237 # Available options:
237 # Available options:
238 # * :days => how many days in the future to remind about (defaults to 7)
238 # * :days => how many days in the future to remind about (defaults to 7)
239 # * :tracker => id of tracker for filtering issues (defaults to all trackers)
239 # * :tracker => id of tracker for filtering issues (defaults to all trackers)
240 # * :project => id or identifier of project to process (defaults to all projects)
240 # * :project => id or identifier of project to process (defaults to all projects)
241 def self.reminders(options={})
241 def self.reminders(options={})
242 days = options[:days] || 7
242 days = options[:days] || 7
243 project = options[:project] ? Project.find(options[:project]) : nil
243 project = options[:project] ? Project.find(options[:project]) : nil
244 tracker = options[:tracker] ? Tracker.find(options[:tracker]) : nil
244 tracker = options[:tracker] ? Tracker.find(options[:tracker]) : nil
245
245
246 s = ARCondition.new ["#{IssueStatus.table_name}.is_closed = ? AND #{Issue.table_name}.due_date <= ?", false, days.day.from_now.to_date]
246 s = ARCondition.new ["#{IssueStatus.table_name}.is_closed = ? AND #{Issue.table_name}.due_date <= ?", false, days.day.from_now.to_date]
247 s << "#{Issue.table_name}.assigned_to_id IS NOT NULL"
247 s << "#{Issue.table_name}.assigned_to_id IS NOT NULL"
248 s << "#{Project.table_name}.status = #{Project::STATUS_ACTIVE}"
248 s << "#{Project.table_name}.status = #{Project::STATUS_ACTIVE}"
249 s << "#{Issue.table_name}.project_id = #{project.id}" if project
249 s << "#{Issue.table_name}.project_id = #{project.id}" if project
250 s << "#{Issue.table_name}.tracker_id = #{tracker.id}" if tracker
250 s << "#{Issue.table_name}.tracker_id = #{tracker.id}" if tracker
251
251
252 issues_by_assignee = Issue.find(:all, :include => [:status, :assigned_to, :project, :tracker],
252 issues_by_assignee = Issue.find(:all, :include => [:status, :assigned_to, :project, :tracker],
253 :conditions => s.conditions
253 :conditions => s.conditions
254 ).group_by(&:assigned_to)
254 ).group_by(&:assigned_to)
255 issues_by_assignee.each do |assignee, issues|
255 issues_by_assignee.each do |assignee, issues|
256 deliver_reminder(assignee, issues, days) unless assignee.nil?
256 deliver_reminder(assignee, issues, days) unless assignee.nil?
257 end
257 end
258 end
258 end
259
259
260 private
260 private
261 def initialize_defaults(method_name)
261 def initialize_defaults(method_name)
262 super
262 super
263 set_language_if_valid Setting.default_language
263 set_language_if_valid Setting.default_language
264 from Setting.mail_from
264 from Setting.mail_from
265
265
266 # Common headers
266 # Common headers
267 headers 'X-Mailer' => 'Redmine',
267 headers 'X-Mailer' => 'Redmine',
268 'X-Redmine-Host' => Setting.host_name,
268 'X-Redmine-Host' => Setting.host_name,
269 'X-Redmine-Site' => Setting.app_title,
269 'X-Redmine-Site' => Setting.app_title,
270 'Precedence' => 'bulk',
270 'Precedence' => 'bulk',
271 'Auto-Submitted' => 'auto-generated'
271 'Auto-Submitted' => 'auto-generated'
272 end
272 end
273
273
274 # Appends a Redmine header field (name is prepended with 'X-Redmine-')
274 # Appends a Redmine header field (name is prepended with 'X-Redmine-')
275 def redmine_headers(h)
275 def redmine_headers(h)
276 h.each { |k,v| headers["X-Redmine-#{k}"] = v }
276 h.each { |k,v| headers["X-Redmine-#{k}"] = v }
277 end
277 end
278
278
279 # Overrides the create_mail method
279 # Overrides the create_mail method
280 def create_mail
280 def create_mail
281 # Removes the current user from the recipients and cc
281 # Removes the current user from the recipients and cc
282 # if he doesn't want to receive notifications about what he does
282 # if he doesn't want to receive notifications about what he does
283 @author ||= User.current
283 @author ||= User.current
284 if @author.pref[:no_self_notified]
284 if @author.pref[:no_self_notified]
285 recipients.delete(@author.mail) if recipients
285 recipients.delete(@author.mail) if recipients
286 cc.delete(@author.mail) if cc
286 cc.delete(@author.mail) if cc
287 end
287 end
288 # Blind carbon copy recipients
288 # Blind carbon copy recipients
289 if Setting.bcc_recipients?
289 if Setting.bcc_recipients?
290 bcc([recipients, cc].flatten.compact.uniq)
290 bcc([recipients, cc].flatten.compact.uniq)
291 recipients []
291 recipients []
292 cc []
292 cc []
293 end
293 end
294 super
294 super
295 end
295 end
296
296
297 # Renders a message with the corresponding layout
297 # Renders a message with the corresponding layout
298 def render_message(method_name, body)
298 def render_message(method_name, body)
299 layout = method_name.to_s.match(%r{text\.html\.(rhtml|rxml)}) ? 'layout.text.html.rhtml' : 'layout.text.plain.rhtml'
299 layout = method_name.to_s.match(%r{text\.html\.(rhtml|rxml)}) ? 'layout.text.html.rhtml' : 'layout.text.plain.rhtml'
300 body[:content_for_layout] = render(:file => method_name, :body => body)
300 body[:content_for_layout] = render(:file => method_name, :body => body)
301 ActionView::Base.new(template_root, body, self).render(:file => "mailer/#{layout}", :use_full_path => true)
301 ActionView::Base.new(template_root, body, self).render(:file => "mailer/#{layout}", :use_full_path => true)
302 end
302 end
303
303
304 # for the case of plain text only
304 # for the case of plain text only
305 def body(*params)
305 def body(*params)
306 value = super(*params)
306 value = super(*params)
307 if Setting.plain_text_mail?
307 if Setting.plain_text_mail?
308 templates = Dir.glob("#{template_path}/#{@template}.text.plain.{rhtml,erb}")
308 templates = Dir.glob("#{template_path}/#{@template}.text.plain.{rhtml,erb}")
309 unless String === @body or templates.empty?
309 unless String === @body or templates.empty?
310 template = File.basename(templates.first)
310 template = File.basename(templates.first)
311 @body[:content_for_layout] = render(:file => template, :body => @body)
311 @body[:content_for_layout] = render(:file => template, :body => @body)
312 @body = ActionView::Base.new(template_root, @body, self).render(:file => "mailer/layout.text.plain.rhtml", :use_full_path => true)
312 @body = ActionView::Base.new(template_root, @body, self).render(:file => "mailer/layout.text.plain.rhtml", :use_full_path => true)
313 return @body
313 return @body
314 end
314 end
315 end
315 end
316 return value
316 return value
317 end
317 end
318
318
319 # Makes partial rendering work with Rails 1.2 (retro-compatibility)
319 # Makes partial rendering work with Rails 1.2 (retro-compatibility)
320 def self.controller_path
320 def self.controller_path
321 ''
321 ''
322 end unless respond_to?('controller_path')
322 end unless respond_to?('controller_path')
323
323
324 # Returns a predictable Message-Id for the given object
324 # Returns a predictable Message-Id for the given object
325 def self.message_id_for(object)
325 def self.message_id_for(object)
326 # id + timestamp should reduce the odds of a collision
326 # id + timestamp should reduce the odds of a collision
327 # as far as we don't send multiple emails for the same object
327 # as far as we don't send multiple emails for the same object
328 hash = "redmine.#{object.class.name.demodulize.underscore}-#{object.id}.#{object.created_on.strftime("%Y%m%d%H%M%S")}"
328 hash = "redmine.#{object.class.name.demodulize.underscore}-#{object.id}.#{object.created_on.strftime("%Y%m%d%H%M%S")}"
329 host = Setting.mail_from.to_s.gsub(%r{^.*@}, '')
329 host = Setting.mail_from.to_s.gsub(%r{^.*@}, '')
330 host = "#{::Socket.gethostname}.redmine" if host.empty?
330 host = "#{::Socket.gethostname}.redmine" if host.empty?
331 "<#{hash}@#{host}>"
331 "<#{hash}@#{host}>"
332 end
332 end
333
333
334 private
334 private
335
335
336 def message_id(object)
336 def message_id(object)
337 @message_id_object = object
337 @message_id_object = object
338 end
338 end
339
339
340 def references(object)
340 def references(object)
341 @references_objects ||= []
341 @references_objects ||= []
342 @references_objects << object
342 @references_objects << object
343 end
343 end
344 end
344 end
345
345
346 # Patch TMail so that message_id is not overwritten
346 # Patch TMail so that message_id is not overwritten
347 module TMail
347 module TMail
348 class Mail
348 class Mail
349 def add_message_id( fqdn = nil )
349 def add_message_id( fqdn = nil )
350 self.message_id ||= ::TMail::new_message_id(fqdn)
350 self.message_id ||= ::TMail::new_message_id(fqdn)
351 end
351 end
352 end
352 end
353 end
353 end
@@ -1,1038 +1,1040
1 # Redmine - project management software
1 # Redmine - project management software
2 # Copyright (C) 2006-2008 Jean-Philippe Lang
2 # Copyright (C) 2006-2008 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.dirname(__FILE__) + '/../test_helper'
18 require File.dirname(__FILE__) + '/../test_helper'
19 require 'issues_controller'
19 require 'issues_controller'
20
20
21 # Re-raise errors caught by the controller.
21 # Re-raise errors caught by the controller.
22 class IssuesController; def rescue_action(e) raise e end; end
22 class IssuesController; def rescue_action(e) raise e end; end
23
23
24 class IssuesControllerTest < Test::Unit::TestCase
24 class IssuesControllerTest < Test::Unit::TestCase
25 fixtures :projects,
25 fixtures :projects,
26 :users,
26 :users,
27 :roles,
27 :roles,
28 :members,
28 :members,
29 :issues,
29 :issues,
30 :issue_statuses,
30 :issue_statuses,
31 :versions,
31 :versions,
32 :trackers,
32 :trackers,
33 :projects_trackers,
33 :projects_trackers,
34 :issue_categories,
34 :issue_categories,
35 :enabled_modules,
35 :enabled_modules,
36 :enumerations,
36 :enumerations,
37 :attachments,
37 :attachments,
38 :workflows,
38 :workflows,
39 :custom_fields,
39 :custom_fields,
40 :custom_values,
40 :custom_values,
41 :custom_fields_trackers,
41 :custom_fields_trackers,
42 :time_entries,
42 :time_entries,
43 :journals,
43 :journals,
44 :journal_details
44 :journal_details
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_routing
53 def test_index_routing
54 assert_routing(
54 assert_routing(
55 {:method => :get, :path => '/issues'},
55 {:method => :get, :path => '/issues'},
56 :controller => 'issues', :action => 'index'
56 :controller => 'issues', :action => 'index'
57 )
57 )
58 end
58 end
59
59
60 def test_index
60 def test_index
61 Setting.default_language = 'en'
61 Setting.default_language = 'en'
62
62
63 get :index
63 get :index
64 assert_response :success
64 assert_response :success
65 assert_template 'index.rhtml'
65 assert_template 'index.rhtml'
66 assert_not_nil assigns(:issues)
66 assert_not_nil assigns(:issues)
67 assert_nil assigns(:project)
67 assert_nil assigns(:project)
68 assert_tag :tag => 'a', :content => /Can't print recipes/
68 assert_tag :tag => 'a', :content => /Can't print recipes/
69 assert_tag :tag => 'a', :content => /Subproject issue/
69 assert_tag :tag => 'a', :content => /Subproject issue/
70 # private projects hidden
70 # private projects hidden
71 assert_no_tag :tag => 'a', :content => /Issue of a private subproject/
71 assert_no_tag :tag => 'a', :content => /Issue of a private subproject/
72 assert_no_tag :tag => 'a', :content => /Issue on project 2/
72 assert_no_tag :tag => 'a', :content => /Issue on project 2/
73 # project column
73 # project column
74 assert_tag :tag => 'th', :content => /Project/
74 assert_tag :tag => 'th', :content => /Project/
75 end
75 end
76
76
77 def test_index_should_not_list_issues_when_module_disabled
77 def test_index_should_not_list_issues_when_module_disabled
78 EnabledModule.delete_all("name = 'issue_tracking' AND project_id = 1")
78 EnabledModule.delete_all("name = 'issue_tracking' AND project_id = 1")
79 get :index
79 get :index
80 assert_response :success
80 assert_response :success
81 assert_template 'index.rhtml'
81 assert_template 'index.rhtml'
82 assert_not_nil assigns(:issues)
82 assert_not_nil assigns(:issues)
83 assert_nil assigns(:project)
83 assert_nil assigns(:project)
84 assert_no_tag :tag => 'a', :content => /Can't print recipes/
84 assert_no_tag :tag => 'a', :content => /Can't print recipes/
85 assert_tag :tag => 'a', :content => /Subproject issue/
85 assert_tag :tag => 'a', :content => /Subproject issue/
86 end
86 end
87
87
88 def test_index_with_project_routing
88 def test_index_with_project_routing
89 assert_routing(
89 assert_routing(
90 {:method => :get, :path => '/projects/23/issues'},
90 {:method => :get, :path => '/projects/23/issues'},
91 :controller => 'issues', :action => 'index', :project_id => '23'
91 :controller => 'issues', :action => 'index', :project_id => '23'
92 )
92 )
93 end
93 end
94
94
95 def test_index_should_not_list_issues_when_module_disabled
95 def test_index_should_not_list_issues_when_module_disabled
96 EnabledModule.delete_all("name = 'issue_tracking' AND project_id = 1")
96 EnabledModule.delete_all("name = 'issue_tracking' AND project_id = 1")
97 get :index
97 get :index
98 assert_response :success
98 assert_response :success
99 assert_template 'index.rhtml'
99 assert_template 'index.rhtml'
100 assert_not_nil assigns(:issues)
100 assert_not_nil assigns(:issues)
101 assert_nil assigns(:project)
101 assert_nil assigns(:project)
102 assert_no_tag :tag => 'a', :content => /Can't print recipes/
102 assert_no_tag :tag => 'a', :content => /Can't print recipes/
103 assert_tag :tag => 'a', :content => /Subproject issue/
103 assert_tag :tag => 'a', :content => /Subproject issue/
104 end
104 end
105
105
106 def test_index_with_project_routing
106 def test_index_with_project_routing
107 assert_routing(
107 assert_routing(
108 {:method => :get, :path => 'projects/23/issues'},
108 {:method => :get, :path => 'projects/23/issues'},
109 :controller => 'issues', :action => 'index', :project_id => '23'
109 :controller => 'issues', :action => 'index', :project_id => '23'
110 )
110 )
111 end
111 end
112
112
113 def test_index_with_project
113 def test_index_with_project
114 Setting.display_subprojects_issues = 0
114 Setting.display_subprojects_issues = 0
115 get :index, :project_id => 1
115 get :index, :project_id => 1
116 assert_response :success
116 assert_response :success
117 assert_template 'index.rhtml'
117 assert_template 'index.rhtml'
118 assert_not_nil assigns(:issues)
118 assert_not_nil assigns(:issues)
119 assert_tag :tag => 'a', :content => /Can't print recipes/
119 assert_tag :tag => 'a', :content => /Can't print recipes/
120 assert_no_tag :tag => 'a', :content => /Subproject issue/
120 assert_no_tag :tag => 'a', :content => /Subproject issue/
121 end
121 end
122
122
123 def test_index_with_project_and_subprojects
123 def test_index_with_project_and_subprojects
124 Setting.display_subprojects_issues = 1
124 Setting.display_subprojects_issues = 1
125 get :index, :project_id => 1
125 get :index, :project_id => 1
126 assert_response :success
126 assert_response :success
127 assert_template 'index.rhtml'
127 assert_template 'index.rhtml'
128 assert_not_nil assigns(:issues)
128 assert_not_nil assigns(:issues)
129 assert_tag :tag => 'a', :content => /Can't print recipes/
129 assert_tag :tag => 'a', :content => /Can't print recipes/
130 assert_tag :tag => 'a', :content => /Subproject issue/
130 assert_tag :tag => 'a', :content => /Subproject issue/
131 assert_no_tag :tag => 'a', :content => /Issue of a private subproject/
131 assert_no_tag :tag => 'a', :content => /Issue of a private subproject/
132 end
132 end
133
133
134 def test_index_with_project_and_subprojects_should_show_private_subprojects
134 def test_index_with_project_and_subprojects_should_show_private_subprojects
135 @request.session[:user_id] = 2
135 @request.session[:user_id] = 2
136 Setting.display_subprojects_issues = 1
136 Setting.display_subprojects_issues = 1
137 get :index, :project_id => 1
137 get :index, :project_id => 1
138 assert_response :success
138 assert_response :success
139 assert_template 'index.rhtml'
139 assert_template 'index.rhtml'
140 assert_not_nil assigns(:issues)
140 assert_not_nil assigns(:issues)
141 assert_tag :tag => 'a', :content => /Can't print recipes/
141 assert_tag :tag => 'a', :content => /Can't print recipes/
142 assert_tag :tag => 'a', :content => /Subproject issue/
142 assert_tag :tag => 'a', :content => /Subproject issue/
143 assert_tag :tag => 'a', :content => /Issue of a private subproject/
143 assert_tag :tag => 'a', :content => /Issue of a private subproject/
144 end
144 end
145
145
146 def test_index_with_project_routing_formatted
146 def test_index_with_project_routing_formatted
147 assert_routing(
147 assert_routing(
148 {:method => :get, :path => 'projects/23/issues.pdf'},
148 {:method => :get, :path => 'projects/23/issues.pdf'},
149 :controller => 'issues', :action => 'index', :project_id => '23', :format => 'pdf'
149 :controller => 'issues', :action => 'index', :project_id => '23', :format => 'pdf'
150 )
150 )
151 assert_routing(
151 assert_routing(
152 {:method => :get, :path => 'projects/23/issues.atom'},
152 {:method => :get, :path => 'projects/23/issues.atom'},
153 :controller => 'issues', :action => 'index', :project_id => '23', :format => 'atom'
153 :controller => 'issues', :action => 'index', :project_id => '23', :format => 'atom'
154 )
154 )
155 end
155 end
156
156
157 def test_index_with_project_and_filter
157 def test_index_with_project_and_filter
158 get :index, :project_id => 1, :set_filter => 1
158 get :index, :project_id => 1, :set_filter => 1
159 assert_response :success
159 assert_response :success
160 assert_template 'index.rhtml'
160 assert_template 'index.rhtml'
161 assert_not_nil assigns(:issues)
161 assert_not_nil assigns(:issues)
162 end
162 end
163
163
164 def test_index_csv_with_project
164 def test_index_csv_with_project
165 get :index, :format => 'csv'
165 get :index, :format => 'csv'
166 assert_response :success
166 assert_response :success
167 assert_not_nil assigns(:issues)
167 assert_not_nil assigns(:issues)
168 assert_equal 'text/csv', @response.content_type
168 assert_equal 'text/csv', @response.content_type
169
169
170 get :index, :project_id => 1, :format => 'csv'
170 get :index, :project_id => 1, :format => 'csv'
171 assert_response :success
171 assert_response :success
172 assert_not_nil assigns(:issues)
172 assert_not_nil assigns(:issues)
173 assert_equal 'text/csv', @response.content_type
173 assert_equal 'text/csv', @response.content_type
174 end
174 end
175
175
176 def test_index_formatted
176 def test_index_formatted
177 assert_routing(
177 assert_routing(
178 {:method => :get, :path => 'issues.pdf'},
178 {:method => :get, :path => 'issues.pdf'},
179 :controller => 'issues', :action => 'index', :format => 'pdf'
179 :controller => 'issues', :action => 'index', :format => 'pdf'
180 )
180 )
181 assert_routing(
181 assert_routing(
182 {:method => :get, :path => 'issues.atom'},
182 {:method => :get, :path => 'issues.atom'},
183 :controller => 'issues', :action => 'index', :format => 'atom'
183 :controller => 'issues', :action => 'index', :format => 'atom'
184 )
184 )
185 end
185 end
186
186
187 def test_index_pdf
187 def test_index_pdf
188 get :index, :format => 'pdf'
188 get :index, :format => 'pdf'
189 assert_response :success
189 assert_response :success
190 assert_not_nil assigns(:issues)
190 assert_not_nil assigns(:issues)
191 assert_equal 'application/pdf', @response.content_type
191 assert_equal 'application/pdf', @response.content_type
192
192
193 get :index, :project_id => 1, :format => 'pdf'
193 get :index, :project_id => 1, :format => 'pdf'
194 assert_response :success
194 assert_response :success
195 assert_not_nil assigns(:issues)
195 assert_not_nil assigns(:issues)
196 assert_equal 'application/pdf', @response.content_type
196 assert_equal 'application/pdf', @response.content_type
197 end
197 end
198
198
199 def test_index_sort
199 def test_index_sort
200 get :index, :sort => 'tracker,id:desc'
200 get :index, :sort => 'tracker,id:desc'
201 assert_response :success
201 assert_response :success
202
202
203 sort_params = @request.session['issues_index_sort']
203 sort_params = @request.session['issues_index_sort']
204 assert sort_params.is_a?(String)
204 assert sort_params.is_a?(String)
205 assert_equal 'tracker,id:desc', sort_params
205 assert_equal 'tracker,id:desc', sort_params
206
206
207 issues = assigns(:issues)
207 issues = assigns(:issues)
208 assert_not_nil issues
208 assert_not_nil issues
209 assert !issues.empty?
209 assert !issues.empty?
210 assert_equal issues.sort {|a,b| a.tracker == b.tracker ? b.id <=> a.id : a.tracker <=> b.tracker }.collect(&:id), issues.collect(&:id)
210 assert_equal issues.sort {|a,b| a.tracker == b.tracker ? b.id <=> a.id : a.tracker <=> b.tracker }.collect(&:id), issues.collect(&:id)
211 end
211 end
212
212
213 def test_gantt
213 def test_gantt
214 get :gantt, :project_id => 1
214 get :gantt, :project_id => 1
215 assert_response :success
215 assert_response :success
216 assert_template 'gantt.rhtml'
216 assert_template 'gantt.rhtml'
217 assert_not_nil assigns(:gantt)
217 assert_not_nil assigns(:gantt)
218 events = assigns(:gantt).events
218 events = assigns(:gantt).events
219 assert_not_nil events
219 assert_not_nil events
220 # Issue with start and due dates
220 # Issue with start and due dates
221 i = Issue.find(1)
221 i = Issue.find(1)
222 assert_not_nil i.due_date
222 assert_not_nil i.due_date
223 assert events.include?(Issue.find(1))
223 assert events.include?(Issue.find(1))
224 # Issue with without due date but targeted to a version with date
224 # Issue with without due date but targeted to a version with date
225 i = Issue.find(2)
225 i = Issue.find(2)
226 assert_nil i.due_date
226 assert_nil i.due_date
227 assert events.include?(i)
227 assert events.include?(i)
228 end
228 end
229
229
230 def test_cross_project_gantt
230 def test_cross_project_gantt
231 get :gantt
231 get :gantt
232 assert_response :success
232 assert_response :success
233 assert_template 'gantt.rhtml'
233 assert_template 'gantt.rhtml'
234 assert_not_nil assigns(:gantt)
234 assert_not_nil assigns(:gantt)
235 events = assigns(:gantt).events
235 events = assigns(:gantt).events
236 assert_not_nil events
236 assert_not_nil events
237 end
237 end
238
238
239 def test_gantt_export_to_pdf
239 def test_gantt_export_to_pdf
240 get :gantt, :project_id => 1, :format => 'pdf'
240 get :gantt, :project_id => 1, :format => 'pdf'
241 assert_response :success
241 assert_response :success
242 assert_equal 'application/pdf', @response.content_type
242 assert_equal 'application/pdf', @response.content_type
243 assert @response.body.starts_with?('%PDF')
243 assert @response.body.starts_with?('%PDF')
244 assert_not_nil assigns(:gantt)
244 assert_not_nil assigns(:gantt)
245 end
245 end
246
246
247 def test_cross_project_gantt_export_to_pdf
247 def test_cross_project_gantt_export_to_pdf
248 get :gantt, :format => 'pdf'
248 get :gantt, :format => 'pdf'
249 assert_response :success
249 assert_response :success
250 assert_equal 'application/pdf', @response.content_type
250 assert_equal 'application/pdf', @response.content_type
251 assert @response.body.starts_with?('%PDF')
251 assert @response.body.starts_with?('%PDF')
252 assert_not_nil assigns(:gantt)
252 assert_not_nil assigns(:gantt)
253 end
253 end
254
254
255 if Object.const_defined?(:Magick)
255 if Object.const_defined?(:Magick)
256 def test_gantt_image
256 def test_gantt_image
257 get :gantt, :project_id => 1, :format => 'png'
257 get :gantt, :project_id => 1, :format => 'png'
258 assert_response :success
258 assert_response :success
259 assert_equal 'image/png', @response.content_type
259 assert_equal 'image/png', @response.content_type
260 end
260 end
261 else
261 else
262 puts "RMagick not installed. Skipping tests !!!"
262 puts "RMagick not installed. Skipping tests !!!"
263 end
263 end
264
264
265 def test_calendar
265 def test_calendar
266 get :calendar, :project_id => 1
266 get :calendar, :project_id => 1
267 assert_response :success
267 assert_response :success
268 assert_template 'calendar'
268 assert_template 'calendar'
269 assert_not_nil assigns(:calendar)
269 assert_not_nil assigns(:calendar)
270 end
270 end
271
271
272 def test_cross_project_calendar
272 def test_cross_project_calendar
273 get :calendar
273 get :calendar
274 assert_response :success
274 assert_response :success
275 assert_template 'calendar'
275 assert_template 'calendar'
276 assert_not_nil assigns(:calendar)
276 assert_not_nil assigns(:calendar)
277 end
277 end
278
278
279 def test_changes
279 def test_changes
280 get :changes, :project_id => 1
280 get :changes, :project_id => 1
281 assert_response :success
281 assert_response :success
282 assert_not_nil assigns(:journals)
282 assert_not_nil assigns(:journals)
283 assert_equal 'application/atom+xml', @response.content_type
283 assert_equal 'application/atom+xml', @response.content_type
284 end
284 end
285
285
286 def test_show_routing
286 def test_show_routing
287 assert_routing(
287 assert_routing(
288 {:method => :get, :path => '/issues/64'},
288 {:method => :get, :path => '/issues/64'},
289 :controller => 'issues', :action => 'show', :id => '64'
289 :controller => 'issues', :action => 'show', :id => '64'
290 )
290 )
291 end
291 end
292
292
293 def test_show_routing_formatted
293 def test_show_routing_formatted
294 assert_routing(
294 assert_routing(
295 {:method => :get, :path => '/issues/2332.pdf'},
295 {:method => :get, :path => '/issues/2332.pdf'},
296 :controller => 'issues', :action => 'show', :id => '2332', :format => 'pdf'
296 :controller => 'issues', :action => 'show', :id => '2332', :format => 'pdf'
297 )
297 )
298 assert_routing(
298 assert_routing(
299 {:method => :get, :path => '/issues/23123.atom'},
299 {:method => :get, :path => '/issues/23123.atom'},
300 :controller => 'issues', :action => 'show', :id => '23123', :format => 'atom'
300 :controller => 'issues', :action => 'show', :id => '23123', :format => 'atom'
301 )
301 )
302 end
302 end
303
303
304 def test_show_by_anonymous
304 def test_show_by_anonymous
305 get :show, :id => 1
305 get :show, :id => 1
306 assert_response :success
306 assert_response :success
307 assert_template 'show.rhtml'
307 assert_template 'show.rhtml'
308 assert_not_nil assigns(:issue)
308 assert_not_nil assigns(:issue)
309 assert_equal Issue.find(1), assigns(:issue)
309 assert_equal Issue.find(1), assigns(:issue)
310
310
311 # anonymous role is allowed to add a note
311 # anonymous role is allowed to add a note
312 assert_tag :tag => 'form',
312 assert_tag :tag => 'form',
313 :descendant => { :tag => 'fieldset',
313 :descendant => { :tag => 'fieldset',
314 :child => { :tag => 'legend',
314 :child => { :tag => 'legend',
315 :content => /Notes/ } }
315 :content => /Notes/ } }
316 end
316 end
317
317
318 def test_show_by_manager
318 def test_show_by_manager
319 @request.session[:user_id] = 2
319 @request.session[:user_id] = 2
320 get :show, :id => 1
320 get :show, :id => 1
321 assert_response :success
321 assert_response :success
322
322
323 assert_tag :tag => 'form',
323 assert_tag :tag => 'form',
324 :descendant => { :tag => 'fieldset',
324 :descendant => { :tag => 'fieldset',
325 :child => { :tag => 'legend',
325 :child => { :tag => 'legend',
326 :content => /Change properties/ } },
326 :content => /Change properties/ } },
327 :descendant => { :tag => 'fieldset',
327 :descendant => { :tag => 'fieldset',
328 :child => { :tag => 'legend',
328 :child => { :tag => 'legend',
329 :content => /Log time/ } },
329 :content => /Log time/ } },
330 :descendant => { :tag => 'fieldset',
330 :descendant => { :tag => 'fieldset',
331 :child => { :tag => 'legend',
331 :child => { :tag => 'legend',
332 :content => /Notes/ } }
332 :content => /Notes/ } }
333 end
333 end
334
334
335 def test_show_should_not_disclose_relations_to_invisible_issues
335 def test_show_should_not_disclose_relations_to_invisible_issues
336 Setting.cross_project_issue_relations = '1'
336 Setting.cross_project_issue_relations = '1'
337 IssueRelation.create!(:issue_from => Issue.find(1), :issue_to => Issue.find(2), :relation_type => 'relates')
337 IssueRelation.create!(:issue_from => Issue.find(1), :issue_to => Issue.find(2), :relation_type => 'relates')
338 # Relation to a private project issue
338 # Relation to a private project issue
339 IssueRelation.create!(:issue_from => Issue.find(1), :issue_to => Issue.find(4), :relation_type => 'relates')
339 IssueRelation.create!(:issue_from => Issue.find(1), :issue_to => Issue.find(4), :relation_type => 'relates')
340
340
341 get :show, :id => 1
341 get :show, :id => 1
342 assert_response :success
342 assert_response :success
343
343
344 assert_tag :div, :attributes => { :id => 'relations' },
344 assert_tag :div, :attributes => { :id => 'relations' },
345 :descendant => { :tag => 'a', :content => /#2$/ }
345 :descendant => { :tag => 'a', :content => /#2$/ }
346 assert_no_tag :div, :attributes => { :id => 'relations' },
346 assert_no_tag :div, :attributes => { :id => 'relations' },
347 :descendant => { :tag => 'a', :content => /#4$/ }
347 :descendant => { :tag => 'a', :content => /#4$/ }
348 end
348 end
349
349
350 def test_new_routing
350 def test_new_routing
351 assert_routing(
351 assert_routing(
352 {:method => :get, :path => '/projects/1/issues/new'},
352 {:method => :get, :path => '/projects/1/issues/new'},
353 :controller => 'issues', :action => 'new', :project_id => '1'
353 :controller => 'issues', :action => 'new', :project_id => '1'
354 )
354 )
355 assert_recognizes(
355 assert_recognizes(
356 {:controller => 'issues', :action => 'new', :project_id => '1'},
356 {:controller => 'issues', :action => 'new', :project_id => '1'},
357 {:method => :post, :path => '/projects/1/issues'}
357 {:method => :post, :path => '/projects/1/issues'}
358 )
358 )
359 end
359 end
360
360
361 def test_show_export_to_pdf
361 def test_show_export_to_pdf
362 get :show, :id => 3, :format => 'pdf'
362 get :show, :id => 3, :format => 'pdf'
363 assert_response :success
363 assert_response :success
364 assert_equal 'application/pdf', @response.content_type
364 assert_equal 'application/pdf', @response.content_type
365 assert @response.body.starts_with?('%PDF')
365 assert @response.body.starts_with?('%PDF')
366 assert_not_nil assigns(:issue)
366 assert_not_nil assigns(:issue)
367 end
367 end
368
368
369 def test_get_new
369 def test_get_new
370 @request.session[:user_id] = 2
370 @request.session[:user_id] = 2
371 get :new, :project_id => 1, :tracker_id => 1
371 get :new, :project_id => 1, :tracker_id => 1
372 assert_response :success
372 assert_response :success
373 assert_template 'new'
373 assert_template 'new'
374
374
375 assert_tag :tag => 'input', :attributes => { :name => 'issue[custom_field_values][2]',
375 assert_tag :tag => 'input', :attributes => { :name => 'issue[custom_field_values][2]',
376 :value => 'Default string' }
376 :value => 'Default string' }
377 end
377 end
378
378
379 def test_get_new_without_tracker_id
379 def test_get_new_without_tracker_id
380 @request.session[:user_id] = 2
380 @request.session[:user_id] = 2
381 get :new, :project_id => 1
381 get :new, :project_id => 1
382 assert_response :success
382 assert_response :success
383 assert_template 'new'
383 assert_template 'new'
384
384
385 issue = assigns(:issue)
385 issue = assigns(:issue)
386 assert_not_nil issue
386 assert_not_nil issue
387 assert_equal Project.find(1).trackers.first, issue.tracker
387 assert_equal Project.find(1).trackers.first, issue.tracker
388 end
388 end
389
389
390 def test_get_new_with_no_default_status_should_display_an_error
390 def test_get_new_with_no_default_status_should_display_an_error
391 @request.session[:user_id] = 2
391 @request.session[:user_id] = 2
392 IssueStatus.delete_all
392 IssueStatus.delete_all
393
393
394 get :new, :project_id => 1
394 get :new, :project_id => 1
395 assert_response 500
395 assert_response 500
396 assert_not_nil flash[:error]
396 assert_not_nil flash[:error]
397 assert_tag :tag => 'div', :attributes => { :class => /error/ },
397 assert_tag :tag => 'div', :attributes => { :class => /error/ },
398 :content => /No default issue/
398 :content => /No default issue/
399 end
399 end
400
400
401 def test_get_new_with_no_tracker_should_display_an_error
401 def test_get_new_with_no_tracker_should_display_an_error
402 @request.session[:user_id] = 2
402 @request.session[:user_id] = 2
403 Tracker.delete_all
403 Tracker.delete_all
404
404
405 get :new, :project_id => 1
405 get :new, :project_id => 1
406 assert_response 500
406 assert_response 500
407 assert_not_nil flash[:error]
407 assert_not_nil flash[:error]
408 assert_tag :tag => 'div', :attributes => { :class => /error/ },
408 assert_tag :tag => 'div', :attributes => { :class => /error/ },
409 :content => /No tracker/
409 :content => /No tracker/
410 end
410 end
411
411
412 def test_update_new_form
412 def test_update_new_form
413 @request.session[:user_id] = 2
413 @request.session[:user_id] = 2
414 xhr :post, :new, :project_id => 1,
414 xhr :post, :new, :project_id => 1,
415 :issue => {:tracker_id => 2,
415 :issue => {:tracker_id => 2,
416 :subject => 'This is the test_new issue',
416 :subject => 'This is the test_new issue',
417 :description => 'This is the description',
417 :description => 'This is the description',
418 :priority_id => 5}
418 :priority_id => 5}
419 assert_response :success
419 assert_response :success
420 assert_template 'new'
420 assert_template 'new'
421 end
421 end
422
422
423 def test_post_new
423 def test_post_new
424 @request.session[:user_id] = 2
424 @request.session[:user_id] = 2
425 post :new, :project_id => 1,
425 post :new, :project_id => 1,
426 :issue => {:tracker_id => 3,
426 :issue => {:tracker_id => 3,
427 :subject => 'This is the test_new issue',
427 :subject => 'This is the test_new issue',
428 :description => 'This is the description',
428 :description => 'This is the description',
429 :priority_id => 5,
429 :priority_id => 5,
430 :estimated_hours => '',
430 :estimated_hours => '',
431 :custom_field_values => {'2' => 'Value for field 2'}}
431 :custom_field_values => {'2' => 'Value for field 2'}}
432 assert_redirected_to :action => 'show'
432 assert_redirected_to :action => 'show'
433
433
434 issue = Issue.find_by_subject('This is the test_new issue')
434 issue = Issue.find_by_subject('This is the test_new issue')
435 assert_not_nil issue
435 assert_not_nil issue
436 assert_equal 2, issue.author_id
436 assert_equal 2, issue.author_id
437 assert_equal 3, issue.tracker_id
437 assert_equal 3, issue.tracker_id
438 assert_nil issue.estimated_hours
438 assert_nil issue.estimated_hours
439 v = issue.custom_values.find(:first, :conditions => {:custom_field_id => 2})
439 v = issue.custom_values.find(:first, :conditions => {:custom_field_id => 2})
440 assert_not_nil v
440 assert_not_nil v
441 assert_equal 'Value for field 2', v.value
441 assert_equal 'Value for field 2', v.value
442 end
442 end
443
443
444 def test_post_new_and_continue
444 def test_post_new_and_continue
445 @request.session[:user_id] = 2
445 @request.session[:user_id] = 2
446 post :new, :project_id => 1,
446 post :new, :project_id => 1,
447 :issue => {:tracker_id => 3,
447 :issue => {:tracker_id => 3,
448 :subject => 'This is first issue',
448 :subject => 'This is first issue',
449 :priority_id => 5},
449 :priority_id => 5},
450 :continue => ''
450 :continue => ''
451 assert_redirected_to :controller => 'issues', :action => 'new', :tracker_id => 3
451 assert_redirected_to :controller => 'issues', :action => 'new', :tracker_id => 3
452 end
452 end
453
453
454 def test_post_new_without_custom_fields_param
454 def test_post_new_without_custom_fields_param
455 @request.session[:user_id] = 2
455 @request.session[:user_id] = 2
456 post :new, :project_id => 1,
456 post :new, :project_id => 1,
457 :issue => {:tracker_id => 1,
457 :issue => {:tracker_id => 1,
458 :subject => 'This is the test_new issue',
458 :subject => 'This is the test_new issue',
459 :description => 'This is the description',
459 :description => 'This is the description',
460 :priority_id => 5}
460 :priority_id => 5}
461 assert_redirected_to :action => 'show'
461 assert_redirected_to :action => 'show'
462 end
462 end
463
463
464 def test_post_new_with_required_custom_field_and_without_custom_fields_param
464 def test_post_new_with_required_custom_field_and_without_custom_fields_param
465 field = IssueCustomField.find_by_name('Database')
465 field = IssueCustomField.find_by_name('Database')
466 field.update_attribute(:is_required, true)
466 field.update_attribute(:is_required, true)
467
467
468 @request.session[:user_id] = 2
468 @request.session[:user_id] = 2
469 post :new, :project_id => 1,
469 post :new, :project_id => 1,
470 :issue => {:tracker_id => 1,
470 :issue => {:tracker_id => 1,
471 :subject => 'This is the test_new issue',
471 :subject => 'This is the test_new issue',
472 :description => 'This is the description',
472 :description => 'This is the description',
473 :priority_id => 5}
473 :priority_id => 5}
474 assert_response :success
474 assert_response :success
475 assert_template 'new'
475 assert_template 'new'
476 issue = assigns(:issue)
476 issue = assigns(:issue)
477 assert_not_nil issue
477 assert_not_nil issue
478 assert_equal I18n.translate('activerecord.errors.messages.invalid'), issue.errors.on(:custom_values)
478 assert_equal I18n.translate('activerecord.errors.messages.invalid'), issue.errors.on(:custom_values)
479 end
479 end
480
480
481 def test_post_new_with_watchers
481 def test_post_new_with_watchers
482 @request.session[:user_id] = 2
482 @request.session[:user_id] = 2
483 ActionMailer::Base.deliveries.clear
483 ActionMailer::Base.deliveries.clear
484
484
485 assert_difference 'Watcher.count', 2 do
485 assert_difference 'Watcher.count', 2 do
486 post :new, :project_id => 1,
486 post :new, :project_id => 1,
487 :issue => {:tracker_id => 1,
487 :issue => {:tracker_id => 1,
488 :subject => 'This is a new issue with watchers',
488 :subject => 'This is a new issue with watchers',
489 :description => 'This is the description',
489 :description => 'This is the description',
490 :priority_id => 5,
490 :priority_id => 5,
491 :watcher_user_ids => ['2', '3']}
491 :watcher_user_ids => ['2', '3']}
492 end
492 end
493 issue = Issue.find_by_subject('This is a new issue with watchers')
493 issue = Issue.find_by_subject('This is a new issue with watchers')
494 assert_not_nil issue
494 assert_not_nil issue
495 assert_redirected_to :controller => 'issues', :action => 'show', :id => issue
495 assert_redirected_to :controller => 'issues', :action => 'show', :id => issue
496
496
497 # Watchers added
497 # Watchers added
498 assert_equal [2, 3], issue.watcher_user_ids.sort
498 assert_equal [2, 3], issue.watcher_user_ids.sort
499 assert issue.watched_by?(User.find(3))
499 assert issue.watched_by?(User.find(3))
500 # Watchers notified
500 # Watchers notified
501 mail = ActionMailer::Base.deliveries.last
501 mail = ActionMailer::Base.deliveries.last
502 assert_kind_of TMail::Mail, mail
502 assert_kind_of TMail::Mail, mail
503 assert [mail.bcc, mail.cc].flatten.include?(User.find(3).mail)
503 assert [mail.bcc, mail.cc].flatten.include?(User.find(3).mail)
504 end
504 end
505
505
506 def test_post_new_should_send_a_notification
506 def test_post_new_should_send_a_notification
507 ActionMailer::Base.deliveries.clear
507 ActionMailer::Base.deliveries.clear
508 @request.session[:user_id] = 2
508 @request.session[:user_id] = 2
509 post :new, :project_id => 1,
509 post :new, :project_id => 1,
510 :issue => {:tracker_id => 3,
510 :issue => {:tracker_id => 3,
511 :subject => 'This is the test_new issue',
511 :subject => 'This is the test_new issue',
512 :description => 'This is the description',
512 :description => 'This is the description',
513 :priority_id => 5,
513 :priority_id => 5,
514 :estimated_hours => '',
514 :estimated_hours => '',
515 :custom_field_values => {'2' => 'Value for field 2'}}
515 :custom_field_values => {'2' => 'Value for field 2'}}
516 assert_redirected_to :action => 'show'
516 assert_redirected_to :action => 'show'
517
517
518 assert_equal 1, ActionMailer::Base.deliveries.size
518 assert_equal 1, ActionMailer::Base.deliveries.size
519 end
519 end
520
520
521 def test_post_should_preserve_fields_values_on_validation_failure
521 def test_post_should_preserve_fields_values_on_validation_failure
522 @request.session[:user_id] = 2
522 @request.session[:user_id] = 2
523 post :new, :project_id => 1,
523 post :new, :project_id => 1,
524 :issue => {:tracker_id => 1,
524 :issue => {:tracker_id => 1,
525 # empty subject
525 # empty subject
526 :subject => '',
526 :subject => '',
527 :description => 'This is a description',
527 :description => 'This is a description',
528 :priority_id => 6,
528 :priority_id => 6,
529 :custom_field_values => {'1' => 'Oracle', '2' => 'Value for field 2'}}
529 :custom_field_values => {'1' => 'Oracle', '2' => 'Value for field 2'}}
530 assert_response :success
530 assert_response :success
531 assert_template 'new'
531 assert_template 'new'
532
532
533 assert_tag :textarea, :attributes => { :name => 'issue[description]' },
533 assert_tag :textarea, :attributes => { :name => 'issue[description]' },
534 :content => 'This is a description'
534 :content => 'This is a description'
535 assert_tag :select, :attributes => { :name => 'issue[priority_id]' },
535 assert_tag :select, :attributes => { :name => 'issue[priority_id]' },
536 :child => { :tag => 'option', :attributes => { :selected => 'selected',
536 :child => { :tag => 'option', :attributes => { :selected => 'selected',
537 :value => '6' },
537 :value => '6' },
538 :content => 'High' }
538 :content => 'High' }
539 # Custom fields
539 # Custom fields
540 assert_tag :select, :attributes => { :name => 'issue[custom_field_values][1]' },
540 assert_tag :select, :attributes => { :name => 'issue[custom_field_values][1]' },
541 :child => { :tag => 'option', :attributes => { :selected => 'selected',
541 :child => { :tag => 'option', :attributes => { :selected => 'selected',
542 :value => 'Oracle' },
542 :value => 'Oracle' },
543 :content => 'Oracle' }
543 :content => 'Oracle' }
544 assert_tag :input, :attributes => { :name => 'issue[custom_field_values][2]',
544 assert_tag :input, :attributes => { :name => 'issue[custom_field_values][2]',
545 :value => 'Value for field 2'}
545 :value => 'Value for field 2'}
546 end
546 end
547
547
548 def test_copy_routing
548 def test_copy_routing
549 assert_routing(
549 assert_routing(
550 {:method => :get, :path => '/projects/world_domination/issues/567/copy'},
550 {:method => :get, :path => '/projects/world_domination/issues/567/copy'},
551 :controller => 'issues', :action => 'new', :project_id => 'world_domination', :copy_from => '567'
551 :controller => 'issues', :action => 'new', :project_id => 'world_domination', :copy_from => '567'
552 )
552 )
553 end
553 end
554
554
555 def test_copy_issue
555 def test_copy_issue
556 @request.session[:user_id] = 2
556 @request.session[:user_id] = 2
557 get :new, :project_id => 1, :copy_from => 1
557 get :new, :project_id => 1, :copy_from => 1
558 assert_template 'new'
558 assert_template 'new'
559 assert_not_nil assigns(:issue)
559 assert_not_nil assigns(:issue)
560 orig = Issue.find(1)
560 orig = Issue.find(1)
561 assert_equal orig.subject, assigns(:issue).subject
561 assert_equal orig.subject, assigns(:issue).subject
562 end
562 end
563
563
564 def test_edit_routing
564 def test_edit_routing
565 assert_routing(
565 assert_routing(
566 {:method => :get, :path => '/issues/1/edit'},
566 {:method => :get, :path => '/issues/1/edit'},
567 :controller => 'issues', :action => 'edit', :id => '1'
567 :controller => 'issues', :action => 'edit', :id => '1'
568 )
568 )
569 assert_recognizes( #TODO: use a PUT on the issue URI isntead, need to adjust form
569 assert_recognizes( #TODO: use a PUT on the issue URI isntead, need to adjust form
570 {:controller => 'issues', :action => 'edit', :id => '1'},
570 {:controller => 'issues', :action => 'edit', :id => '1'},
571 {:method => :post, :path => '/issues/1/edit'}
571 {:method => :post, :path => '/issues/1/edit'}
572 )
572 )
573 end
573 end
574
574
575 def test_get_edit
575 def test_get_edit
576 @request.session[:user_id] = 2
576 @request.session[:user_id] = 2
577 get :edit, :id => 1
577 get :edit, :id => 1
578 assert_response :success
578 assert_response :success
579 assert_template 'edit'
579 assert_template 'edit'
580 assert_not_nil assigns(:issue)
580 assert_not_nil assigns(:issue)
581 assert_equal Issue.find(1), assigns(:issue)
581 assert_equal Issue.find(1), assigns(:issue)
582 end
582 end
583
583
584 def test_get_edit_with_params
584 def test_get_edit_with_params
585 @request.session[:user_id] = 2
585 @request.session[:user_id] = 2
586 get :edit, :id => 1, :issue => { :status_id => 5, :priority_id => 7 }
586 get :edit, :id => 1, :issue => { :status_id => 5, :priority_id => 7 }
587 assert_response :success
587 assert_response :success
588 assert_template 'edit'
588 assert_template 'edit'
589
589
590 issue = assigns(:issue)
590 issue = assigns(:issue)
591 assert_not_nil issue
591 assert_not_nil issue
592
592
593 assert_equal 5, issue.status_id
593 assert_equal 5, issue.status_id
594 assert_tag :select, :attributes => { :name => 'issue[status_id]' },
594 assert_tag :select, :attributes => { :name => 'issue[status_id]' },
595 :child => { :tag => 'option',
595 :child => { :tag => 'option',
596 :content => 'Closed',
596 :content => 'Closed',
597 :attributes => { :selected => 'selected' } }
597 :attributes => { :selected => 'selected' } }
598
598
599 assert_equal 7, issue.priority_id
599 assert_equal 7, issue.priority_id
600 assert_tag :select, :attributes => { :name => 'issue[priority_id]' },
600 assert_tag :select, :attributes => { :name => 'issue[priority_id]' },
601 :child => { :tag => 'option',
601 :child => { :tag => 'option',
602 :content => 'Urgent',
602 :content => 'Urgent',
603 :attributes => { :selected => 'selected' } }
603 :attributes => { :selected => 'selected' } }
604 end
604 end
605
605
606 def test_reply_routing
606 def test_reply_routing
607 assert_routing(
607 assert_routing(
608 {:method => :post, :path => '/issues/1/quoted'},
608 {:method => :post, :path => '/issues/1/quoted'},
609 :controller => 'issues', :action => 'reply', :id => '1'
609 :controller => 'issues', :action => 'reply', :id => '1'
610 )
610 )
611 end
611 end
612
612
613 def test_reply_to_issue
613 def test_reply_to_issue
614 @request.session[:user_id] = 2
614 @request.session[:user_id] = 2
615 get :reply, :id => 1
615 get :reply, :id => 1
616 assert_response :success
616 assert_response :success
617 assert_select_rjs :show, "update"
617 assert_select_rjs :show, "update"
618 end
618 end
619
619
620 def test_reply_to_note
620 def test_reply_to_note
621 @request.session[:user_id] = 2
621 @request.session[:user_id] = 2
622 get :reply, :id => 1, :journal_id => 2
622 get :reply, :id => 1, :journal_id => 2
623 assert_response :success
623 assert_response :success
624 assert_select_rjs :show, "update"
624 assert_select_rjs :show, "update"
625 end
625 end
626
626
627 def test_post_edit_without_custom_fields_param
627 def test_post_edit_without_custom_fields_param
628 @request.session[:user_id] = 2
628 @request.session[:user_id] = 2
629 ActionMailer::Base.deliveries.clear
629 ActionMailer::Base.deliveries.clear
630
630
631 issue = Issue.find(1)
631 issue = Issue.find(1)
632 assert_equal '125', issue.custom_value_for(2).value
632 assert_equal '125', issue.custom_value_for(2).value
633 old_subject = issue.subject
633 old_subject = issue.subject
634 new_subject = 'Subject modified by IssuesControllerTest#test_post_edit'
634 new_subject = 'Subject modified by IssuesControllerTest#test_post_edit'
635
635
636 assert_difference('Journal.count') do
636 assert_difference('Journal.count') do
637 assert_difference('JournalDetail.count', 2) do
637 assert_difference('JournalDetail.count', 2) do
638 post :edit, :id => 1, :issue => {:subject => new_subject,
638 post :edit, :id => 1, :issue => {:subject => new_subject,
639 :priority_id => '6',
639 :priority_id => '6',
640 :category_id => '1' # no change
640 :category_id => '1' # no change
641 }
641 }
642 end
642 end
643 end
643 end
644 assert_redirected_to :action => 'show', :id => '1'
644 assert_redirected_to :action => 'show', :id => '1'
645 issue.reload
645 issue.reload
646 assert_equal new_subject, issue.subject
646 assert_equal new_subject, issue.subject
647 # Make sure custom fields were not cleared
647 # Make sure custom fields were not cleared
648 assert_equal '125', issue.custom_value_for(2).value
648 assert_equal '125', issue.custom_value_for(2).value
649
649
650 mail = ActionMailer::Base.deliveries.last
650 mail = ActionMailer::Base.deliveries.last
651 assert_kind_of TMail::Mail, mail
651 assert_kind_of TMail::Mail, mail
652 assert mail.subject.starts_with?("[#{issue.project.name} - #{issue.tracker.name} ##{issue.id}]")
652 assert mail.subject.starts_with?("[#{issue.project.name} - #{issue.tracker.name} ##{issue.id}]")
653 assert mail.body.include?("Subject changed from #{old_subject} to #{new_subject}")
653 assert mail.body.include?("Subject changed from #{old_subject} to #{new_subject}")
654 end
654 end
655
655
656 def test_post_edit_with_custom_field_change
656 def test_post_edit_with_custom_field_change
657 @request.session[:user_id] = 2
657 @request.session[:user_id] = 2
658 issue = Issue.find(1)
658 issue = Issue.find(1)
659 assert_equal '125', issue.custom_value_for(2).value
659 assert_equal '125', issue.custom_value_for(2).value
660
660
661 assert_difference('Journal.count') do
661 assert_difference('Journal.count') do
662 assert_difference('JournalDetail.count', 3) do
662 assert_difference('JournalDetail.count', 3) do
663 post :edit, :id => 1, :issue => {:subject => 'Custom field change',
663 post :edit, :id => 1, :issue => {:subject => 'Custom field change',
664 :priority_id => '6',
664 :priority_id => '6',
665 :category_id => '1', # no change
665 :category_id => '1', # no change
666 :custom_field_values => { '2' => 'New custom value' }
666 :custom_field_values => { '2' => 'New custom value' }
667 }
667 }
668 end
668 end
669 end
669 end
670 assert_redirected_to :action => 'show', :id => '1'
670 assert_redirected_to :action => 'show', :id => '1'
671 issue.reload
671 issue.reload
672 assert_equal 'New custom value', issue.custom_value_for(2).value
672 assert_equal 'New custom value', issue.custom_value_for(2).value
673
673
674 mail = ActionMailer::Base.deliveries.last
674 mail = ActionMailer::Base.deliveries.last
675 assert_kind_of TMail::Mail, mail
675 assert_kind_of TMail::Mail, mail
676 assert mail.body.include?("Searchable field changed from 125 to New custom value")
676 assert mail.body.include?("Searchable field changed from 125 to New custom value")
677 end
677 end
678
678
679 def test_post_edit_with_status_and_assignee_change
679 def test_post_edit_with_status_and_assignee_change
680 issue = Issue.find(1)
680 issue = Issue.find(1)
681 assert_equal 1, issue.status_id
681 assert_equal 1, issue.status_id
682 @request.session[:user_id] = 2
682 @request.session[:user_id] = 2
683 assert_difference('TimeEntry.count', 0) do
683 assert_difference('TimeEntry.count', 0) do
684 post :edit,
684 post :edit,
685 :id => 1,
685 :id => 1,
686 :issue => { :status_id => 2, :assigned_to_id => 3 },
686 :issue => { :status_id => 2, :assigned_to_id => 3 },
687 :notes => 'Assigned to dlopper',
687 :notes => 'Assigned to dlopper',
688 :time_entry => { :hours => '', :comments => '', :activity_id => Enumeration.activities.first }
688 :time_entry => { :hours => '', :comments => '', :activity_id => Enumeration.activities.first }
689 end
689 end
690 assert_redirected_to :action => 'show', :id => '1'
690 assert_redirected_to :action => 'show', :id => '1'
691 issue.reload
691 issue.reload
692 assert_equal 2, issue.status_id
692 assert_equal 2, issue.status_id
693 j = issue.journals.find(:first, :order => 'id DESC')
693 j = issue.journals.find(:first, :order => 'id DESC')
694 assert_equal 'Assigned to dlopper', j.notes
694 assert_equal 'Assigned to dlopper', j.notes
695 assert_equal 2, j.details.size
695 assert_equal 2, j.details.size
696
696
697 mail = ActionMailer::Base.deliveries.last
697 mail = ActionMailer::Base.deliveries.last
698 assert mail.body.include?("Status changed from New to Assigned")
698 assert mail.body.include?("Status changed from New to Assigned")
699 # subject should contain the new status
700 assert mail.subject.include?("(#{ IssueStatus.find(2).name })")
699 end
701 end
700
702
701 def test_post_edit_with_note_only
703 def test_post_edit_with_note_only
702 notes = 'Note added by IssuesControllerTest#test_update_with_note_only'
704 notes = 'Note added by IssuesControllerTest#test_update_with_note_only'
703 # anonymous user
705 # anonymous user
704 post :edit,
706 post :edit,
705 :id => 1,
707 :id => 1,
706 :notes => notes
708 :notes => notes
707 assert_redirected_to :action => 'show', :id => '1'
709 assert_redirected_to :action => 'show', :id => '1'
708 j = Issue.find(1).journals.find(:first, :order => 'id DESC')
710 j = Issue.find(1).journals.find(:first, :order => 'id DESC')
709 assert_equal notes, j.notes
711 assert_equal notes, j.notes
710 assert_equal 0, j.details.size
712 assert_equal 0, j.details.size
711 assert_equal User.anonymous, j.user
713 assert_equal User.anonymous, j.user
712
714
713 mail = ActionMailer::Base.deliveries.last
715 mail = ActionMailer::Base.deliveries.last
714 assert mail.body.include?(notes)
716 assert mail.body.include?(notes)
715 end
717 end
716
718
717 def test_post_edit_with_note_and_spent_time
719 def test_post_edit_with_note_and_spent_time
718 @request.session[:user_id] = 2
720 @request.session[:user_id] = 2
719 spent_hours_before = Issue.find(1).spent_hours
721 spent_hours_before = Issue.find(1).spent_hours
720 assert_difference('TimeEntry.count') do
722 assert_difference('TimeEntry.count') do
721 post :edit,
723 post :edit,
722 :id => 1,
724 :id => 1,
723 :notes => '2.5 hours added',
725 :notes => '2.5 hours added',
724 :time_entry => { :hours => '2.5', :comments => '', :activity_id => Enumeration.activities.first }
726 :time_entry => { :hours => '2.5', :comments => '', :activity_id => Enumeration.activities.first }
725 end
727 end
726 assert_redirected_to :action => 'show', :id => '1'
728 assert_redirected_to :action => 'show', :id => '1'
727
729
728 issue = Issue.find(1)
730 issue = Issue.find(1)
729
731
730 j = issue.journals.find(:first, :order => 'id DESC')
732 j = issue.journals.find(:first, :order => 'id DESC')
731 assert_equal '2.5 hours added', j.notes
733 assert_equal '2.5 hours added', j.notes
732 assert_equal 0, j.details.size
734 assert_equal 0, j.details.size
733
735
734 t = issue.time_entries.find(:first, :order => 'id DESC')
736 t = issue.time_entries.find(:first, :order => 'id DESC')
735 assert_not_nil t
737 assert_not_nil t
736 assert_equal 2.5, t.hours
738 assert_equal 2.5, t.hours
737 assert_equal spent_hours_before + 2.5, issue.spent_hours
739 assert_equal spent_hours_before + 2.5, issue.spent_hours
738 end
740 end
739
741
740 def test_post_edit_with_attachment_only
742 def test_post_edit_with_attachment_only
741 set_tmp_attachments_directory
743 set_tmp_attachments_directory
742
744
743 # Delete all fixtured journals, a race condition can occur causing the wrong
745 # Delete all fixtured journals, a race condition can occur causing the wrong
744 # journal to get fetched in the next find.
746 # journal to get fetched in the next find.
745 Journal.delete_all
747 Journal.delete_all
746
748
747 # anonymous user
749 # anonymous user
748 post :edit,
750 post :edit,
749 :id => 1,
751 :id => 1,
750 :notes => '',
752 :notes => '',
751 :attachments => {'1' => {'file' => test_uploaded_file('testfile.txt', 'text/plain')}}
753 :attachments => {'1' => {'file' => test_uploaded_file('testfile.txt', 'text/plain')}}
752 assert_redirected_to :action => 'show', :id => '1'
754 assert_redirected_to :action => 'show', :id => '1'
753 j = Issue.find(1).journals.find(:first, :order => 'id DESC')
755 j = Issue.find(1).journals.find(:first, :order => 'id DESC')
754 assert j.notes.blank?
756 assert j.notes.blank?
755 assert_equal 1, j.details.size
757 assert_equal 1, j.details.size
756 assert_equal 'testfile.txt', j.details.first.value
758 assert_equal 'testfile.txt', j.details.first.value
757 assert_equal User.anonymous, j.user
759 assert_equal User.anonymous, j.user
758
760
759 mail = ActionMailer::Base.deliveries.last
761 mail = ActionMailer::Base.deliveries.last
760 assert mail.body.include?('testfile.txt')
762 assert mail.body.include?('testfile.txt')
761 end
763 end
762
764
763 def test_post_edit_with_no_change
765 def test_post_edit_with_no_change
764 issue = Issue.find(1)
766 issue = Issue.find(1)
765 issue.journals.clear
767 issue.journals.clear
766 ActionMailer::Base.deliveries.clear
768 ActionMailer::Base.deliveries.clear
767
769
768 post :edit,
770 post :edit,
769 :id => 1,
771 :id => 1,
770 :notes => ''
772 :notes => ''
771 assert_redirected_to :action => 'show', :id => '1'
773 assert_redirected_to :action => 'show', :id => '1'
772
774
773 issue.reload
775 issue.reload
774 assert issue.journals.empty?
776 assert issue.journals.empty?
775 # No email should be sent
777 # No email should be sent
776 assert ActionMailer::Base.deliveries.empty?
778 assert ActionMailer::Base.deliveries.empty?
777 end
779 end
778
780
779 def test_post_edit_should_send_a_notification
781 def test_post_edit_should_send_a_notification
780 @request.session[:user_id] = 2
782 @request.session[:user_id] = 2
781 ActionMailer::Base.deliveries.clear
783 ActionMailer::Base.deliveries.clear
782 issue = Issue.find(1)
784 issue = Issue.find(1)
783 old_subject = issue.subject
785 old_subject = issue.subject
784 new_subject = 'Subject modified by IssuesControllerTest#test_post_edit'
786 new_subject = 'Subject modified by IssuesControllerTest#test_post_edit'
785
787
786 post :edit, :id => 1, :issue => {:subject => new_subject,
788 post :edit, :id => 1, :issue => {:subject => new_subject,
787 :priority_id => '6',
789 :priority_id => '6',
788 :category_id => '1' # no change
790 :category_id => '1' # no change
789 }
791 }
790 assert_equal 1, ActionMailer::Base.deliveries.size
792 assert_equal 1, ActionMailer::Base.deliveries.size
791 end
793 end
792
794
793 def test_post_edit_with_invalid_spent_time
795 def test_post_edit_with_invalid_spent_time
794 @request.session[:user_id] = 2
796 @request.session[:user_id] = 2
795 notes = 'Note added by IssuesControllerTest#test_post_edit_with_invalid_spent_time'
797 notes = 'Note added by IssuesControllerTest#test_post_edit_with_invalid_spent_time'
796
798
797 assert_no_difference('Journal.count') do
799 assert_no_difference('Journal.count') do
798 post :edit,
800 post :edit,
799 :id => 1,
801 :id => 1,
800 :notes => notes,
802 :notes => notes,
801 :time_entry => {"comments"=>"", "activity_id"=>"", "hours"=>"2z"}
803 :time_entry => {"comments"=>"", "activity_id"=>"", "hours"=>"2z"}
802 end
804 end
803 assert_response :success
805 assert_response :success
804 assert_template 'edit'
806 assert_template 'edit'
805
807
806 assert_tag :textarea, :attributes => { :name => 'notes' },
808 assert_tag :textarea, :attributes => { :name => 'notes' },
807 :content => notes
809 :content => notes
808 assert_tag :input, :attributes => { :name => 'time_entry[hours]', :value => "2z" }
810 assert_tag :input, :attributes => { :name => 'time_entry[hours]', :value => "2z" }
809 end
811 end
810
812
811 def test_bulk_edit
813 def test_bulk_edit
812 @request.session[:user_id] = 2
814 @request.session[:user_id] = 2
813 # update issues priority
815 # update issues priority
814 post :bulk_edit, :ids => [1, 2], :priority_id => 7,
816 post :bulk_edit, :ids => [1, 2], :priority_id => 7,
815 :assigned_to_id => '',
817 :assigned_to_id => '',
816 :custom_field_values => {'2' => ''},
818 :custom_field_values => {'2' => ''},
817 :notes => 'Bulk editing'
819 :notes => 'Bulk editing'
818 assert_response 302
820 assert_response 302
819 # check that the issues were updated
821 # check that the issues were updated
820 assert_equal [7, 7], Issue.find_all_by_id([1, 2]).collect {|i| i.priority.id}
822 assert_equal [7, 7], Issue.find_all_by_id([1, 2]).collect {|i| i.priority.id}
821
823
822 issue = Issue.find(1)
824 issue = Issue.find(1)
823 journal = issue.journals.find(:first, :order => 'created_on DESC')
825 journal = issue.journals.find(:first, :order => 'created_on DESC')
824 assert_equal '125', issue.custom_value_for(2).value
826 assert_equal '125', issue.custom_value_for(2).value
825 assert_equal 'Bulk editing', journal.notes
827 assert_equal 'Bulk editing', journal.notes
826 assert_equal 1, journal.details.size
828 assert_equal 1, journal.details.size
827 end
829 end
828
830
829 def test_bullk_edit_should_send_a_notification
831 def test_bullk_edit_should_send_a_notification
830 @request.session[:user_id] = 2
832 @request.session[:user_id] = 2
831 ActionMailer::Base.deliveries.clear
833 ActionMailer::Base.deliveries.clear
832 post(:bulk_edit,
834 post(:bulk_edit,
833 {
835 {
834 :ids => [1, 2],
836 :ids => [1, 2],
835 :priority_id => 7,
837 :priority_id => 7,
836 :assigned_to_id => '',
838 :assigned_to_id => '',
837 :custom_field_values => {'2' => ''},
839 :custom_field_values => {'2' => ''},
838 :notes => 'Bulk editing'
840 :notes => 'Bulk editing'
839 })
841 })
840
842
841 assert_response 302
843 assert_response 302
842 assert_equal 2, ActionMailer::Base.deliveries.size
844 assert_equal 2, ActionMailer::Base.deliveries.size
843 end
845 end
844
846
845 def test_bulk_edit_custom_field
847 def test_bulk_edit_custom_field
846 @request.session[:user_id] = 2
848 @request.session[:user_id] = 2
847 # update issues priority
849 # update issues priority
848 post :bulk_edit, :ids => [1, 2], :priority_id => '',
850 post :bulk_edit, :ids => [1, 2], :priority_id => '',
849 :assigned_to_id => '',
851 :assigned_to_id => '',
850 :custom_field_values => {'2' => '777'},
852 :custom_field_values => {'2' => '777'},
851 :notes => 'Bulk editing custom field'
853 :notes => 'Bulk editing custom field'
852 assert_response 302
854 assert_response 302
853
855
854 issue = Issue.find(1)
856 issue = Issue.find(1)
855 journal = issue.journals.find(:first, :order => 'created_on DESC')
857 journal = issue.journals.find(:first, :order => 'created_on DESC')
856 assert_equal '777', issue.custom_value_for(2).value
858 assert_equal '777', issue.custom_value_for(2).value
857 assert_equal 1, journal.details.size
859 assert_equal 1, journal.details.size
858 assert_equal '125', journal.details.first.old_value
860 assert_equal '125', journal.details.first.old_value
859 assert_equal '777', journal.details.first.value
861 assert_equal '777', journal.details.first.value
860 end
862 end
861
863
862 def test_bulk_unassign
864 def test_bulk_unassign
863 assert_not_nil Issue.find(2).assigned_to
865 assert_not_nil Issue.find(2).assigned_to
864 @request.session[:user_id] = 2
866 @request.session[:user_id] = 2
865 # unassign issues
867 # unassign issues
866 post :bulk_edit, :ids => [1, 2], :notes => 'Bulk unassigning', :assigned_to_id => 'none'
868 post :bulk_edit, :ids => [1, 2], :notes => 'Bulk unassigning', :assigned_to_id => 'none'
867 assert_response 302
869 assert_response 302
868 # check that the issues were updated
870 # check that the issues were updated
869 assert_nil Issue.find(2).assigned_to
871 assert_nil Issue.find(2).assigned_to
870 end
872 end
871
873
872 def test_move_routing
874 def test_move_routing
873 assert_routing(
875 assert_routing(
874 {:method => :get, :path => '/issues/1/move'},
876 {:method => :get, :path => '/issues/1/move'},
875 :controller => 'issues', :action => 'move', :id => '1'
877 :controller => 'issues', :action => 'move', :id => '1'
876 )
878 )
877 assert_recognizes(
879 assert_recognizes(
878 {:controller => 'issues', :action => 'move', :id => '1'},
880 {:controller => 'issues', :action => 'move', :id => '1'},
879 {:method => :post, :path => '/issues/1/move'}
881 {:method => :post, :path => '/issues/1/move'}
880 )
882 )
881 end
883 end
882
884
883 def test_move_one_issue_to_another_project
885 def test_move_one_issue_to_another_project
884 @request.session[:user_id] = 1
886 @request.session[:user_id] = 1
885 post :move, :id => 1, :new_project_id => 2
887 post :move, :id => 1, :new_project_id => 2
886 assert_redirected_to :action => 'index', :project_id => 'ecookbook'
888 assert_redirected_to :action => 'index', :project_id => 'ecookbook'
887 assert_equal 2, Issue.find(1).project_id
889 assert_equal 2, Issue.find(1).project_id
888 end
890 end
889
891
890 def test_bulk_move_to_another_project
892 def test_bulk_move_to_another_project
891 @request.session[:user_id] = 1
893 @request.session[:user_id] = 1
892 post :move, :ids => [1, 2], :new_project_id => 2
894 post :move, :ids => [1, 2], :new_project_id => 2
893 assert_redirected_to :action => 'index', :project_id => 'ecookbook'
895 assert_redirected_to :action => 'index', :project_id => 'ecookbook'
894 # Issues moved to project 2
896 # Issues moved to project 2
895 assert_equal 2, Issue.find(1).project_id
897 assert_equal 2, Issue.find(1).project_id
896 assert_equal 2, Issue.find(2).project_id
898 assert_equal 2, Issue.find(2).project_id
897 # No tracker change
899 # No tracker change
898 assert_equal 1, Issue.find(1).tracker_id
900 assert_equal 1, Issue.find(1).tracker_id
899 assert_equal 2, Issue.find(2).tracker_id
901 assert_equal 2, Issue.find(2).tracker_id
900 end
902 end
901
903
902 def test_bulk_move_to_another_tracker
904 def test_bulk_move_to_another_tracker
903 @request.session[:user_id] = 1
905 @request.session[:user_id] = 1
904 post :move, :ids => [1, 2], :new_tracker_id => 2
906 post :move, :ids => [1, 2], :new_tracker_id => 2
905 assert_redirected_to :action => 'index', :project_id => 'ecookbook'
907 assert_redirected_to :action => 'index', :project_id => 'ecookbook'
906 assert_equal 2, Issue.find(1).tracker_id
908 assert_equal 2, Issue.find(1).tracker_id
907 assert_equal 2, Issue.find(2).tracker_id
909 assert_equal 2, Issue.find(2).tracker_id
908 end
910 end
909
911
910 def test_bulk_copy_to_another_project
912 def test_bulk_copy_to_another_project
911 @request.session[:user_id] = 1
913 @request.session[:user_id] = 1
912 assert_difference 'Issue.count', 2 do
914 assert_difference 'Issue.count', 2 do
913 assert_no_difference 'Project.find(1).issues.count' do
915 assert_no_difference 'Project.find(1).issues.count' do
914 post :move, :ids => [1, 2], :new_project_id => 2, :copy_options => {:copy => '1'}
916 post :move, :ids => [1, 2], :new_project_id => 2, :copy_options => {:copy => '1'}
915 end
917 end
916 end
918 end
917 assert_redirected_to 'projects/ecookbook/issues'
919 assert_redirected_to 'projects/ecookbook/issues'
918 end
920 end
919
921
920 def test_context_menu_one_issue
922 def test_context_menu_one_issue
921 @request.session[:user_id] = 2
923 @request.session[:user_id] = 2
922 get :context_menu, :ids => [1]
924 get :context_menu, :ids => [1]
923 assert_response :success
925 assert_response :success
924 assert_template 'context_menu'
926 assert_template 'context_menu'
925 assert_tag :tag => 'a', :content => 'Edit',
927 assert_tag :tag => 'a', :content => 'Edit',
926 :attributes => { :href => '/issues/1/edit',
928 :attributes => { :href => '/issues/1/edit',
927 :class => 'icon-edit' }
929 :class => 'icon-edit' }
928 assert_tag :tag => 'a', :content => 'Closed',
930 assert_tag :tag => 'a', :content => 'Closed',
929 :attributes => { :href => '/issues/1/edit?issue%5Bstatus_id%5D=5',
931 :attributes => { :href => '/issues/1/edit?issue%5Bstatus_id%5D=5',
930 :class => '' }
932 :class => '' }
931 assert_tag :tag => 'a', :content => 'Immediate',
933 assert_tag :tag => 'a', :content => 'Immediate',
932 :attributes => { :href => '/issues/bulk_edit?ids%5B%5D=1&amp;priority_id=8',
934 :attributes => { :href => '/issues/bulk_edit?ids%5B%5D=1&amp;priority_id=8',
933 :class => '' }
935 :class => '' }
934 assert_tag :tag => 'a', :content => 'Dave Lopper',
936 assert_tag :tag => 'a', :content => 'Dave Lopper',
935 :attributes => { :href => '/issues/bulk_edit?assigned_to_id=3&amp;ids%5B%5D=1',
937 :attributes => { :href => '/issues/bulk_edit?assigned_to_id=3&amp;ids%5B%5D=1',
936 :class => '' }
938 :class => '' }
937 assert_tag :tag => 'a', :content => 'Copy',
939 assert_tag :tag => 'a', :content => 'Copy',
938 :attributes => { :href => '/projects/ecookbook/issues/1/copy',
940 :attributes => { :href => '/projects/ecookbook/issues/1/copy',
939 :class => 'icon-copy' }
941 :class => 'icon-copy' }
940 assert_tag :tag => 'a', :content => 'Move',
942 assert_tag :tag => 'a', :content => 'Move',
941 :attributes => { :href => '/issues/move?ids%5B%5D=1',
943 :attributes => { :href => '/issues/move?ids%5B%5D=1',
942 :class => 'icon-move' }
944 :class => 'icon-move' }
943 assert_tag :tag => 'a', :content => 'Delete',
945 assert_tag :tag => 'a', :content => 'Delete',
944 :attributes => { :href => '/issues/destroy?ids%5B%5D=1',
946 :attributes => { :href => '/issues/destroy?ids%5B%5D=1',
945 :class => 'icon-del' }
947 :class => 'icon-del' }
946 end
948 end
947
949
948 def test_context_menu_one_issue_by_anonymous
950 def test_context_menu_one_issue_by_anonymous
949 get :context_menu, :ids => [1]
951 get :context_menu, :ids => [1]
950 assert_response :success
952 assert_response :success
951 assert_template 'context_menu'
953 assert_template 'context_menu'
952 assert_tag :tag => 'a', :content => 'Delete',
954 assert_tag :tag => 'a', :content => 'Delete',
953 :attributes => { :href => '#',
955 :attributes => { :href => '#',
954 :class => 'icon-del disabled' }
956 :class => 'icon-del disabled' }
955 end
957 end
956
958
957 def test_context_menu_multiple_issues_of_same_project
959 def test_context_menu_multiple_issues_of_same_project
958 @request.session[:user_id] = 2
960 @request.session[:user_id] = 2
959 get :context_menu, :ids => [1, 2]
961 get :context_menu, :ids => [1, 2]
960 assert_response :success
962 assert_response :success
961 assert_template 'context_menu'
963 assert_template 'context_menu'
962 assert_tag :tag => 'a', :content => 'Edit',
964 assert_tag :tag => 'a', :content => 'Edit',
963 :attributes => { :href => '/issues/bulk_edit?ids%5B%5D=1&amp;ids%5B%5D=2',
965 :attributes => { :href => '/issues/bulk_edit?ids%5B%5D=1&amp;ids%5B%5D=2',
964 :class => 'icon-edit' }
966 :class => 'icon-edit' }
965 assert_tag :tag => 'a', :content => 'Immediate',
967 assert_tag :tag => 'a', :content => 'Immediate',
966 :attributes => { :href => '/issues/bulk_edit?ids%5B%5D=1&amp;ids%5B%5D=2&amp;priority_id=8',
968 :attributes => { :href => '/issues/bulk_edit?ids%5B%5D=1&amp;ids%5B%5D=2&amp;priority_id=8',
967 :class => '' }
969 :class => '' }
968 assert_tag :tag => 'a', :content => 'Dave Lopper',
970 assert_tag :tag => 'a', :content => 'Dave Lopper',
969 :attributes => { :href => '/issues/bulk_edit?assigned_to_id=3&amp;ids%5B%5D=1&amp;ids%5B%5D=2',
971 :attributes => { :href => '/issues/bulk_edit?assigned_to_id=3&amp;ids%5B%5D=1&amp;ids%5B%5D=2',
970 :class => '' }
972 :class => '' }
971 assert_tag :tag => 'a', :content => 'Move',
973 assert_tag :tag => 'a', :content => 'Move',
972 :attributes => { :href => '/issues/move?ids%5B%5D=1&amp;ids%5B%5D=2',
974 :attributes => { :href => '/issues/move?ids%5B%5D=1&amp;ids%5B%5D=2',
973 :class => 'icon-move' }
975 :class => 'icon-move' }
974 assert_tag :tag => 'a', :content => 'Delete',
976 assert_tag :tag => 'a', :content => 'Delete',
975 :attributes => { :href => '/issues/destroy?ids%5B%5D=1&amp;ids%5B%5D=2',
977 :attributes => { :href => '/issues/destroy?ids%5B%5D=1&amp;ids%5B%5D=2',
976 :class => 'icon-del' }
978 :class => 'icon-del' }
977 end
979 end
978
980
979 def test_context_menu_multiple_issues_of_different_project
981 def test_context_menu_multiple_issues_of_different_project
980 @request.session[:user_id] = 2
982 @request.session[:user_id] = 2
981 get :context_menu, :ids => [1, 2, 4]
983 get :context_menu, :ids => [1, 2, 4]
982 assert_response :success
984 assert_response :success
983 assert_template 'context_menu'
985 assert_template 'context_menu'
984 assert_tag :tag => 'a', :content => 'Delete',
986 assert_tag :tag => 'a', :content => 'Delete',
985 :attributes => { :href => '#',
987 :attributes => { :href => '#',
986 :class => 'icon-del disabled' }
988 :class => 'icon-del disabled' }
987 end
989 end
988
990
989 def test_destroy_routing
991 def test_destroy_routing
990 assert_recognizes( #TODO: use DELETE on issue URI (need to change forms)
992 assert_recognizes( #TODO: use DELETE on issue URI (need to change forms)
991 {:controller => 'issues', :action => 'destroy', :id => '1'},
993 {:controller => 'issues', :action => 'destroy', :id => '1'},
992 {:method => :post, :path => '/issues/1/destroy'}
994 {:method => :post, :path => '/issues/1/destroy'}
993 )
995 )
994 end
996 end
995
997
996 def test_destroy_issue_with_no_time_entries
998 def test_destroy_issue_with_no_time_entries
997 assert_nil TimeEntry.find_by_issue_id(2)
999 assert_nil TimeEntry.find_by_issue_id(2)
998 @request.session[:user_id] = 2
1000 @request.session[:user_id] = 2
999 post :destroy, :id => 2
1001 post :destroy, :id => 2
1000 assert_redirected_to :action => 'index', :project_id => 'ecookbook'
1002 assert_redirected_to :action => 'index', :project_id => 'ecookbook'
1001 assert_nil Issue.find_by_id(2)
1003 assert_nil Issue.find_by_id(2)
1002 end
1004 end
1003
1005
1004 def test_destroy_issues_with_time_entries
1006 def test_destroy_issues_with_time_entries
1005 @request.session[:user_id] = 2
1007 @request.session[:user_id] = 2
1006 post :destroy, :ids => [1, 3]
1008 post :destroy, :ids => [1, 3]
1007 assert_response :success
1009 assert_response :success
1008 assert_template 'destroy'
1010 assert_template 'destroy'
1009 assert_not_nil assigns(:hours)
1011 assert_not_nil assigns(:hours)
1010 assert Issue.find_by_id(1) && Issue.find_by_id(3)
1012 assert Issue.find_by_id(1) && Issue.find_by_id(3)
1011 end
1013 end
1012
1014
1013 def test_destroy_issues_and_destroy_time_entries
1015 def test_destroy_issues_and_destroy_time_entries
1014 @request.session[:user_id] = 2
1016 @request.session[:user_id] = 2
1015 post :destroy, :ids => [1, 3], :todo => 'destroy'
1017 post :destroy, :ids => [1, 3], :todo => 'destroy'
1016 assert_redirected_to :action => 'index', :project_id => 'ecookbook'
1018 assert_redirected_to :action => 'index', :project_id => 'ecookbook'
1017 assert !(Issue.find_by_id(1) || Issue.find_by_id(3))
1019 assert !(Issue.find_by_id(1) || Issue.find_by_id(3))
1018 assert_nil TimeEntry.find_by_id([1, 2])
1020 assert_nil TimeEntry.find_by_id([1, 2])
1019 end
1021 end
1020
1022
1021 def test_destroy_issues_and_assign_time_entries_to_project
1023 def test_destroy_issues_and_assign_time_entries_to_project
1022 @request.session[:user_id] = 2
1024 @request.session[:user_id] = 2
1023 post :destroy, :ids => [1, 3], :todo => 'nullify'
1025 post :destroy, :ids => [1, 3], :todo => 'nullify'
1024 assert_redirected_to :action => 'index', :project_id => 'ecookbook'
1026 assert_redirected_to :action => 'index', :project_id => 'ecookbook'
1025 assert !(Issue.find_by_id(1) || Issue.find_by_id(3))
1027 assert !(Issue.find_by_id(1) || Issue.find_by_id(3))
1026 assert_nil TimeEntry.find(1).issue_id
1028 assert_nil TimeEntry.find(1).issue_id
1027 assert_nil TimeEntry.find(2).issue_id
1029 assert_nil TimeEntry.find(2).issue_id
1028 end
1030 end
1029
1031
1030 def test_destroy_issues_and_reassign_time_entries_to_another_issue
1032 def test_destroy_issues_and_reassign_time_entries_to_another_issue
1031 @request.session[:user_id] = 2
1033 @request.session[:user_id] = 2
1032 post :destroy, :ids => [1, 3], :todo => 'reassign', :reassign_to_id => 2
1034 post :destroy, :ids => [1, 3], :todo => 'reassign', :reassign_to_id => 2
1033 assert_redirected_to :action => 'index', :project_id => 'ecookbook'
1035 assert_redirected_to :action => 'index', :project_id => 'ecookbook'
1034 assert !(Issue.find_by_id(1) || Issue.find_by_id(3))
1036 assert !(Issue.find_by_id(1) || Issue.find_by_id(3))
1035 assert_equal 2, TimeEntry.find(1).issue_id
1037 assert_equal 2, TimeEntry.find(1).issue_id
1036 assert_equal 2, TimeEntry.find(2).issue_id
1038 assert_equal 2, TimeEntry.find(2).issue_id
1037 end
1039 end
1038 end
1040 end
General Comments 0
You need to be logged in to leave comments. Login now