##// END OF EJS Templates
Merged r15609 (#23278)....
Jean-Philippe Lang -
r15256:891736ef391b
parent child
Show More
@@ -1,88 +1,92
1 1 # ActsAsWatchable
2 2 module Redmine
3 3 module Acts
4 4 module Watchable
5 5 def self.included(base)
6 6 base.extend ClassMethods
7 7 end
8 8
9 9 module ClassMethods
10 10 def acts_as_watchable(options = {})
11 11 return if self.included_modules.include?(Redmine::Acts::Watchable::InstanceMethods)
12 12 class_eval do
13 13 has_many :watchers, :as => :watchable, :dependent => :delete_all
14 14 has_many :watcher_users, :through => :watchers, :source => :user, :validate => false
15 15
16 16 scope :watched_by, lambda { |user_id|
17 17 joins(:watchers).
18 18 where("#{Watcher.table_name}.user_id = ?", user_id)
19 19 }
20 20 attr_protected :watcher_ids, :watcher_user_ids
21 21 end
22 22 send :include, Redmine::Acts::Watchable::InstanceMethods
23 23 alias_method_chain :watcher_user_ids=, :uniq_ids
24 24 end
25 25 end
26 26
27 27 module InstanceMethods
28 28 def self.included(base)
29 29 base.extend ClassMethods
30 30 end
31 31
32 32 # Returns an array of users that are proposed as watchers
33 33 def addable_watcher_users
34 34 users = self.project.users.sort - self.watcher_users
35 35 if respond_to?(:visible?)
36 36 users.reject! {|user| !visible?(user)}
37 37 end
38 38 users
39 39 end
40 40
41 41 # Adds user as a watcher
42 42 def add_watcher(user)
43 # Rails does not reset the has_many :through association
44 watcher_users.reset
43 45 self.watchers << Watcher.new(:user => user)
44 46 end
45 47
46 48 # Removes user from the watchers list
47 49 def remove_watcher(user)
48 50 return nil unless user && user.is_a?(User)
51 # Rails does not reset the has_many :through association
52 watcher_users.reset
49 53 watchers.where(:user_id => user.id).delete_all
50 54 end
51 55
52 56 # Adds/removes watcher
53 57 def set_watcher(user, watching=true)
54 58 watching ? add_watcher(user) : remove_watcher(user)
55 59 end
56 60
57 61 # Overrides watcher_user_ids= to make user_ids uniq
58 62 def watcher_user_ids_with_uniq_ids=(user_ids)
59 63 if user_ids.is_a?(Array)
60 64 user_ids = user_ids.uniq
61 65 end
62 66 send :watcher_user_ids_without_uniq_ids=, user_ids
63 67 end
64 68
65 69 # Returns true if object is watched by +user+
66 70 def watched_by?(user)
67 71 !!(user && self.watcher_user_ids.detect {|uid| uid == user.id })
68 72 end
69 73
70 74 def notified_watchers
71 75 notified = watcher_users.active.to_a
72 76 notified.reject! {|user| user.mail.blank? || user.mail_notification == 'none'}
73 77 if respond_to?(:visible?)
74 78 notified.reject! {|user| !visible?(user)}
75 79 end
76 80 notified
77 81 end
78 82
79 83 # Returns an array of watchers' email addresses
80 84 def watcher_recipients
81 85 notified_watchers.collect(&:mail)
82 86 end
83 87
84 88 module ClassMethods; end
85 89 end
86 90 end
87 91 end
88 92 end
@@ -1,1046 +1,1047
1 1 # encoding: utf-8
2 2 #
3 3 # Redmine - project management software
4 4 # Copyright (C) 2006-2016 Jean-Philippe Lang
5 5 #
6 6 # This program is free software; you can redistribute it and/or
7 7 # modify it under the terms of the GNU General Public License
8 8 # as published by the Free Software Foundation; either version 2
9 9 # of the License, or (at your option) any later version.
10 10 #
11 11 # This program is distributed in the hope that it will be useful,
12 12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 14 # GNU General Public License for more details.
15 15 #
16 16 # You should have received a copy of the GNU General Public License
17 17 # along with this program; if not, write to the Free Software
18 18 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19 19
20 20 require File.expand_path('../../test_helper', __FILE__)
21 21
22 22 class MailHandlerTest < ActiveSupport::TestCase
23 23 fixtures :users, :projects, :enabled_modules, :roles,
24 24 :members, :member_roles, :users,
25 25 :email_addresses,
26 26 :issues, :issue_statuses,
27 27 :workflows, :trackers, :projects_trackers,
28 28 :versions, :enumerations, :issue_categories,
29 29 :custom_fields, :custom_fields_trackers, :custom_fields_projects,
30 30 :boards, :messages
31 31
32 32 FIXTURES_PATH = File.dirname(__FILE__) + '/../fixtures/mail_handler'
33 33
34 34 def setup
35 35 ActionMailer::Base.deliveries.clear
36 36 Setting.notified_events = Redmine::Notifiable.all.collect(&:name)
37 37 end
38 38
39 39 def teardown
40 40 Setting.clear_cache
41 41 end
42 42
43 43 def test_add_issue_with_specific_overrides
44 44 issue = submit_email('ticket_on_given_project.eml',
45 45 :allow_override => ['status', 'start_date', 'due_date', 'assigned_to', 'fixed_version', 'estimated_hours', 'done_ratio']
46 46 )
47 47 assert issue.is_a?(Issue)
48 48 assert !issue.new_record?
49 49 issue.reload
50 50 assert_equal Project.find(2), issue.project
51 51 assert_equal issue.project.trackers.first, issue.tracker
52 52 assert_equal 'New ticket on a given project', issue.subject
53 53 assert_equal User.find_by_login('jsmith'), issue.author
54 54 assert_equal IssueStatus.find_by_name('Resolved'), issue.status
55 55 assert issue.description.include?('Lorem ipsum dolor sit amet, consectetuer adipiscing elit.')
56 56 assert_equal '2010-01-01', issue.start_date.to_s
57 57 assert_equal '2010-12-31', issue.due_date.to_s
58 58 assert_equal User.find_by_login('jsmith'), issue.assigned_to
59 59 assert_equal Version.find_by_name('Alpha'), issue.fixed_version
60 60 assert_equal 2.5, issue.estimated_hours
61 61 assert_equal 30, issue.done_ratio
62 62 # keywords should be removed from the email body
63 63 assert !issue.description.match(/^Project:/i)
64 64 assert !issue.description.match(/^Status:/i)
65 65 assert !issue.description.match(/^Start Date:/i)
66 66 end
67 67
68 68 def test_add_issue_with_all_overrides
69 69 issue = submit_email('ticket_on_given_project.eml', :allow_override => 'all')
70 70 assert issue.is_a?(Issue)
71 71 assert !issue.new_record?
72 72 issue.reload
73 73 assert_equal Project.find(2), issue.project
74 74 assert_equal issue.project.trackers.first, issue.tracker
75 75 assert_equal IssueStatus.find_by_name('Resolved'), issue.status
76 76 assert issue.description.include?('Lorem ipsum dolor sit amet, consectetuer adipiscing elit.')
77 77 assert_equal '2010-01-01', issue.start_date.to_s
78 78 assert_equal '2010-12-31', issue.due_date.to_s
79 79 assert_equal User.find_by_login('jsmith'), issue.assigned_to
80 80 assert_equal Version.find_by_name('Alpha'), issue.fixed_version
81 81 assert_equal 2.5, issue.estimated_hours
82 82 assert_equal 30, issue.done_ratio
83 83 end
84 84
85 85 def test_add_issue_without_overrides_should_ignore_attributes
86 86 WorkflowRule.delete_all
87 87 issue = submit_email('ticket_on_given_project.eml')
88 88 assert issue.is_a?(Issue)
89 89 assert !issue.new_record?
90 90 issue.reload
91 91 assert_equal Project.find(2), issue.project
92 92 assert_equal 'New ticket on a given project', issue.subject
93 93 assert issue.description.include?('Lorem ipsum dolor sit amet, consectetuer adipiscing elit.')
94 94 assert_equal User.find_by_login('jsmith'), issue.author
95 95
96 96 assert_equal issue.project.trackers.first, issue.tracker
97 97 assert_equal 'New', issue.status.name
98 98 assert_not_equal '2010-01-01', issue.start_date.to_s
99 99 assert_nil issue.due_date
100 100 assert_nil issue.assigned_to
101 101 assert_nil issue.fixed_version
102 102 assert_nil issue.estimated_hours
103 103 assert_equal 0, issue.done_ratio
104 104 end
105 105
106 106 def test_add_issue_to_project_specified_by_subaddress
107 107 # This email has redmine+onlinestore@somenet.foo as 'To' header
108 108 issue = submit_email(
109 109 'ticket_on_project_given_by_to_header.eml',
110 110 :issue => {:tracker => 'Support request'},
111 111 :project_from_subaddress => 'redmine@somenet.foo'
112 112 )
113 113 assert issue.is_a?(Issue)
114 114 assert !issue.new_record?
115 115 issue.reload
116 116 assert_equal 'onlinestore', issue.project.identifier
117 117 assert_equal 'Support request', issue.tracker.name
118 118 end
119 119
120 120 def test_add_issue_with_default_tracker
121 121 # This email contains: 'Project: onlinestore'
122 122 issue = submit_email(
123 123 'ticket_on_given_project.eml',
124 124 :issue => {:tracker => 'Support request'}
125 125 )
126 126 assert issue.is_a?(Issue)
127 127 assert !issue.new_record?
128 128 issue.reload
129 129 assert_equal 'Support request', issue.tracker.name
130 130 end
131 131
132 132 def test_add_issue_with_default_version
133 133 # This email contains: 'Project: onlinestore'
134 134 issue = submit_email(
135 135 'ticket_on_given_project.eml',
136 136 :issue => {:fixed_version => 'Alpha'}
137 137 )
138 138 assert issue.is_a?(Issue)
139 139 assert !issue.new_record?
140 140 assert_equal 'Alpha', issue.reload.fixed_version.name
141 141 end
142 142
143 143 def test_add_issue_with_status_override
144 144 # This email contains: 'Project: onlinestore' and 'Status: Resolved'
145 145 issue = submit_email('ticket_on_given_project.eml', :allow_override => ['status'])
146 146 assert issue.is_a?(Issue)
147 147 assert !issue.new_record?
148 148 issue.reload
149 149 assert_equal Project.find(2), issue.project
150 150 assert_equal IssueStatus.find_by_name("Resolved"), issue.status
151 151 end
152 152
153 153 def test_add_issue_should_accept_is_private_attribute
154 154 issue = submit_email('ticket_on_given_project.eml', :issue => {:is_private => '1'})
155 155 assert issue.is_a?(Issue)
156 156 assert !issue.new_record?
157 157 assert_equal true, issue.reload.is_private
158 158 end
159 159
160 160 def test_add_issue_with_group_assignment
161 161 with_settings :issue_group_assignment => '1' do
162 162 issue = submit_email('ticket_on_given_project.eml', :allow_override => ['assigned_to']) do |email|
163 163 email.gsub!('Assigned to: John Smith', 'Assigned to: B Team')
164 164 end
165 165 assert issue.is_a?(Issue)
166 166 assert !issue.new_record?
167 167 issue.reload
168 168 assert_equal Group.find(11), issue.assigned_to
169 169 end
170 170 end
171 171
172 172 def test_add_issue_with_partial_attributes_override
173 173 issue = submit_email(
174 174 'ticket_with_attributes.eml',
175 175 :issue => {:priority => 'High'},
176 176 :allow_override => ['tracker']
177 177 )
178 178 assert issue.is_a?(Issue)
179 179 assert !issue.new_record?
180 180 issue.reload
181 181 assert_equal 'New ticket on a given project', issue.subject
182 182 assert_equal User.find_by_login('jsmith'), issue.author
183 183 assert_equal Project.find(2), issue.project
184 184 assert_equal 'Feature request', issue.tracker.to_s
185 185 assert_nil issue.category
186 186 assert_equal 'High', issue.priority.to_s
187 187 assert issue.description.include?('Lorem ipsum dolor sit amet, consectetuer adipiscing elit.')
188 188 end
189 189
190 190 def test_add_issue_with_spaces_between_attribute_and_separator
191 191 issue = submit_email(
192 192 'ticket_with_spaces_between_attribute_and_separator.eml',
193 193 :allow_override => 'tracker,category,priority'
194 194 )
195 195 assert issue.is_a?(Issue)
196 196 assert !issue.new_record?
197 197 issue.reload
198 198 assert_equal 'New ticket on a given project', issue.subject
199 199 assert_equal User.find_by_login('jsmith'), issue.author
200 200 assert_equal Project.find(2), issue.project
201 201 assert_equal 'Feature request', issue.tracker.to_s
202 202 assert_equal 'Stock management', issue.category.to_s
203 203 assert_equal 'Urgent', issue.priority.to_s
204 204 assert issue.description.include?('Lorem ipsum dolor sit amet, consectetuer adipiscing elit.')
205 205 end
206 206
207 207 def test_add_issue_with_attachment_to_specific_project
208 208 issue = submit_email('ticket_with_attachment.eml', :issue => {:project => 'onlinestore'})
209 209 assert issue.is_a?(Issue)
210 210 assert !issue.new_record?
211 211 issue.reload
212 212 assert_equal 'Ticket created by email with attachment', issue.subject
213 213 assert_equal User.find_by_login('jsmith'), issue.author
214 214 assert_equal Project.find(2), issue.project
215 215 assert_equal 'This is a new ticket with attachments', issue.description
216 216 # Attachment properties
217 217 assert_equal 1, issue.attachments.size
218 218 assert_equal 'Paella.jpg', issue.attachments.first.filename
219 219 assert_equal 'image/jpeg', issue.attachments.first.content_type
220 220 assert_equal 10790, issue.attachments.first.filesize
221 221 end
222 222
223 223 def test_add_issue_with_custom_fields
224 224 issue = submit_email('ticket_with_custom_fields.eml',
225 225 :issue => {:project => 'onlinestore'}, :allow_override => ['database', 'Searchable_field']
226 226 )
227 227 assert issue.is_a?(Issue)
228 228 assert !issue.new_record?
229 229 issue.reload
230 230 assert_equal 'New ticket with custom field values', issue.subject
231 231 assert_equal 'PostgreSQL', issue.custom_field_value(1)
232 232 assert_equal 'Value for a custom field', issue.custom_field_value(2)
233 233 assert !issue.description.match(/^searchable field:/i)
234 234 end
235 235
236 236 def test_add_issue_with_version_custom_fields
237 237 field = IssueCustomField.create!(:name => 'Affected version', :field_format => 'version', :is_for_all => true, :tracker_ids => [1,2,3])
238 238
239 239 issue = submit_email('ticket_with_custom_fields.eml',
240 240 :issue => {:project => 'ecookbook'}, :allow_override => ['affected version']
241 241 ) do |email|
242 242 email << "Affected version: 1.0\n"
243 243 end
244 244 assert issue.is_a?(Issue)
245 245 assert !issue.new_record?
246 246 issue.reload
247 247 assert_equal '2', issue.custom_field_value(field)
248 248 end
249 249
250 250 def test_add_issue_should_match_assignee_on_display_name
251 251 user = User.generate!(:firstname => 'Foo Bar', :lastname => 'Foo Baz')
252 252 User.add_to_project(user, Project.find(2))
253 253 issue = submit_email('ticket_on_given_project.eml', :allow_override => ['assigned_to']) do |email|
254 254 email.sub!(/^Assigned to.*$/, 'Assigned to: Foo Bar Foo baz')
255 255 end
256 256 assert issue.is_a?(Issue)
257 257 assert_equal user, issue.assigned_to
258 258 end
259 259
260 260 def test_add_issue_should_set_default_start_date
261 261 with_settings :default_issue_start_date_to_creation_date => '1' do
262 262 issue = submit_email('ticket_with_cc.eml', :issue => {:project => 'ecookbook'})
263 263 assert issue.is_a?(Issue)
264 264 assert_equal Date.today, issue.start_date
265 265 end
266 266 end
267 267
268 268 def test_add_issue_with_cc
269 user = User.find_by_mail('dlopper@somenet.foo')
269 270 issue = submit_email('ticket_with_cc.eml', :issue => {:project => 'ecookbook'})
270 271 assert issue.is_a?(Issue)
271 272 assert !issue.new_record?
272 issue.reload
273 assert issue.watched_by?(User.find_by_mail('dlopper@somenet.foo'))
273 assert issue.watched_by?(user)
274 274 assert_equal 1, issue.watcher_user_ids.size
275 assert_include user, issue.watcher_users.to_a
275 276 end
276 277
277 278 def test_add_issue_from_additional_email_address
278 279 user = User.find(2)
279 280 user.mail = 'mainaddress@somenet.foo'
280 281 user.save!
281 282 EmailAddress.create!(:user => user, :address => 'jsmith@somenet.foo')
282 283
283 284 issue = submit_email('ticket_on_given_project.eml')
284 285 assert issue
285 286 assert_equal user, issue.author
286 287 end
287 288
288 289 def test_add_issue_by_unknown_user
289 290 assert_no_difference 'User.count' do
290 291 assert_equal false,
291 292 submit_email(
292 293 'ticket_by_unknown_user.eml',
293 294 :issue => {:project => 'ecookbook'}
294 295 )
295 296 end
296 297 end
297 298
298 299 def test_add_issue_by_anonymous_user
299 300 Role.anonymous.add_permission!(:add_issues)
300 301 assert_no_difference 'User.count' do
301 302 issue = submit_email(
302 303 'ticket_by_unknown_user.eml',
303 304 :issue => {:project => 'ecookbook'},
304 305 :unknown_user => 'accept'
305 306 )
306 307 assert issue.is_a?(Issue)
307 308 assert issue.author.anonymous?
308 309 end
309 310 end
310 311
311 312 def test_add_issue_by_anonymous_user_with_no_from_address
312 313 Role.anonymous.add_permission!(:add_issues)
313 314 assert_no_difference 'User.count' do
314 315 issue = submit_email(
315 316 'ticket_by_empty_user.eml',
316 317 :issue => {:project => 'ecookbook'},
317 318 :unknown_user => 'accept'
318 319 )
319 320 assert issue.is_a?(Issue)
320 321 assert issue.author.anonymous?
321 322 end
322 323 end
323 324
324 325 def test_add_issue_by_anonymous_user_on_private_project
325 326 Role.anonymous.add_permission!(:add_issues)
326 327 assert_no_difference 'User.count' do
327 328 assert_no_difference 'Issue.count' do
328 329 assert_equal false,
329 330 submit_email(
330 331 'ticket_by_unknown_user.eml',
331 332 :issue => {:project => 'onlinestore'},
332 333 :unknown_user => 'accept'
333 334 )
334 335 end
335 336 end
336 337 end
337 338
338 339 def test_add_issue_by_anonymous_user_on_private_project_without_permission_check
339 340 assert_no_difference 'User.count' do
340 341 assert_difference 'Issue.count' do
341 342 issue = submit_email(
342 343 'ticket_by_unknown_user.eml',
343 344 :issue => {:project => 'onlinestore'},
344 345 :no_permission_check => '1',
345 346 :unknown_user => 'accept'
346 347 )
347 348 assert issue.is_a?(Issue)
348 349 assert issue.author.anonymous?
349 350 assert !issue.project.is_public?
350 351 end
351 352 end
352 353 end
353 354
354 355 def test_add_issue_by_created_user
355 356 Setting.default_language = 'en'
356 357 assert_difference 'User.count' do
357 358 issue = submit_email(
358 359 'ticket_by_unknown_user.eml',
359 360 :issue => {:project => 'ecookbook'},
360 361 :unknown_user => 'create'
361 362 )
362 363 assert issue.is_a?(Issue)
363 364 assert issue.author.active?
364 365 assert_equal 'john.doe@somenet.foo', issue.author.mail
365 366 assert_equal 'John', issue.author.firstname
366 367 assert_equal 'Doe', issue.author.lastname
367 368
368 369 # account information
369 370 email = ActionMailer::Base.deliveries.first
370 371 assert_not_nil email
371 372 assert email.subject.include?('account activation')
372 373 login = mail_body(email).match(/\* Login: (.*)$/)[1].strip
373 374 password = mail_body(email).match(/\* Password: (.*)$/)[1].strip
374 375 assert_equal issue.author, User.try_to_login(login, password)
375 376 end
376 377 end
377 378
378 379 def test_add_issue_should_send_notification
379 380 issue = submit_email('ticket_on_given_project.eml', :allow_override => 'all')
380 381 assert issue.is_a?(Issue)
381 382 assert !issue.new_record?
382 383
383 384 mail = ActionMailer::Base.deliveries.last
384 385 assert_not_nil mail
385 386 assert mail.subject.include?("##{issue.id}")
386 387 assert mail.subject.include?('New ticket on a given project')
387 388 end
388 389
389 390 def test_created_user_should_be_added_to_groups
390 391 group1 = Group.generate!
391 392 group2 = Group.generate!
392 393
393 394 assert_difference 'User.count' do
394 395 submit_email(
395 396 'ticket_by_unknown_user.eml',
396 397 :issue => {:project => 'ecookbook'},
397 398 :unknown_user => 'create',
398 399 :default_group => "#{group1.name},#{group2.name}"
399 400 )
400 401 end
401 402 user = User.order('id DESC').first
402 403 assert_equal [group1, group2].sort, user.groups.sort
403 404 end
404 405
405 406 def test_created_user_should_not_receive_account_information_with_no_account_info_option
406 407 assert_difference 'User.count' do
407 408 submit_email(
408 409 'ticket_by_unknown_user.eml',
409 410 :issue => {:project => 'ecookbook'},
410 411 :unknown_user => 'create',
411 412 :no_account_notice => '1'
412 413 )
413 414 end
414 415
415 416 # only 1 email for the new issue notification
416 417 assert_equal 1, ActionMailer::Base.deliveries.size
417 418 email = ActionMailer::Base.deliveries.first
418 419 assert_include 'Ticket by unknown user', email.subject
419 420 end
420 421
421 422 def test_created_user_should_have_mail_notification_to_none_with_no_notification_option
422 423 assert_difference 'User.count' do
423 424 submit_email(
424 425 'ticket_by_unknown_user.eml',
425 426 :issue => {:project => 'ecookbook'},
426 427 :unknown_user => 'create',
427 428 :no_notification => '1'
428 429 )
429 430 end
430 431 user = User.order('id DESC').first
431 432 assert_equal 'none', user.mail_notification
432 433 end
433 434
434 435 def test_add_issue_without_from_header
435 436 Role.anonymous.add_permission!(:add_issues)
436 437 assert_equal false, submit_email('ticket_without_from_header.eml')
437 438 end
438 439
439 440 def test_add_issue_with_invalid_attributes
440 441 with_settings :default_issue_start_date_to_creation_date => '0' do
441 442 issue = submit_email(
442 443 'ticket_with_invalid_attributes.eml',
443 444 :allow_override => 'tracker,category,priority'
444 445 )
445 446 assert issue.is_a?(Issue)
446 447 assert !issue.new_record?
447 448 issue.reload
448 449 assert_nil issue.assigned_to
449 450 assert_nil issue.start_date
450 451 assert_nil issue.due_date
451 452 assert_equal 0, issue.done_ratio
452 453 assert_equal 'Normal', issue.priority.to_s
453 454 assert issue.description.include?('Lorem ipsum dolor sit amet, consectetuer adipiscing elit.')
454 455 end
455 456 end
456 457
457 458 def test_add_issue_with_invalid_project_should_be_assigned_to_default_project
458 459 issue = submit_email('ticket_on_given_project.eml', :issue => {:project => 'ecookbook'}, :allow_override => 'project') do |email|
459 460 email.gsub!(/^Project:.+$/, 'Project: invalid')
460 461 end
461 462 assert issue.is_a?(Issue)
462 463 assert !issue.new_record?
463 464 assert_equal 'ecookbook', issue.project.identifier
464 465 end
465 466
466 467 def test_add_issue_with_localized_attributes
467 468 User.find_by_mail('jsmith@somenet.foo').update_attribute 'language', 'fr'
468 469 issue = submit_email(
469 470 'ticket_with_localized_attributes.eml',
470 471 :allow_override => 'tracker,category,priority'
471 472 )
472 473 assert issue.is_a?(Issue)
473 474 assert !issue.new_record?
474 475 issue.reload
475 476 assert_equal 'New ticket on a given project', issue.subject
476 477 assert_equal User.find_by_login('jsmith'), issue.author
477 478 assert_equal Project.find(2), issue.project
478 479 assert_equal 'Feature request', issue.tracker.to_s
479 480 assert_equal 'Stock management', issue.category.to_s
480 481 assert_equal 'Urgent', issue.priority.to_s
481 482 assert issue.description.include?('Lorem ipsum dolor sit amet, consectetuer adipiscing elit.')
482 483 end
483 484
484 485 def test_add_issue_with_japanese_keywords
485 486 ja_dev = "\xe9\x96\x8b\xe7\x99\xba".force_encoding('UTF-8')
486 487 tracker = Tracker.generate!(:name => ja_dev)
487 488 Project.find(1).trackers << tracker
488 489 issue = submit_email(
489 490 'japanese_keywords_iso_2022_jp.eml',
490 491 :issue => {:project => 'ecookbook'},
491 492 :allow_override => 'tracker'
492 493 )
493 494 assert_kind_of Issue, issue
494 495 assert_equal tracker, issue.tracker
495 496 end
496 497
497 498 def test_add_issue_from_apple_mail
498 499 issue = submit_email(
499 500 'apple_mail_with_attachment.eml',
500 501 :issue => {:project => 'ecookbook'}
501 502 )
502 503 assert_kind_of Issue, issue
503 504 assert_equal 1, issue.attachments.size
504 505
505 506 attachment = issue.attachments.first
506 507 assert_equal 'paella.jpg', attachment.filename
507 508 assert_equal 10790, attachment.filesize
508 509 assert File.exist?(attachment.diskfile)
509 510 assert_equal 10790, File.size(attachment.diskfile)
510 511 assert_equal 'caaf384198bcbc9563ab5c058acd73cd', attachment.digest
511 512 end
512 513
513 514 def test_thunderbird_with_attachment_ja
514 515 issue = submit_email(
515 516 'thunderbird_with_attachment_ja.eml',
516 517 :issue => {:project => 'ecookbook'}
517 518 )
518 519 assert_kind_of Issue, issue
519 520 assert_equal 1, issue.attachments.size
520 521 ja = "\xe3\x83\x86\xe3\x82\xb9\xe3\x83\x88.txt".force_encoding('UTF-8')
521 522 attachment = issue.attachments.first
522 523 assert_equal ja, attachment.filename
523 524 assert_equal 5, attachment.filesize
524 525 assert File.exist?(attachment.diskfile)
525 526 assert_equal 5, File.size(attachment.diskfile)
526 527 assert_equal 'd8e8fca2dc0f896fd7cb4cb0031ba249', attachment.digest
527 528 end
528 529
529 530 def test_gmail_with_attachment_ja
530 531 issue = submit_email(
531 532 'gmail_with_attachment_ja.eml',
532 533 :issue => {:project => 'ecookbook'}
533 534 )
534 535 assert_kind_of Issue, issue
535 536 assert_equal 1, issue.attachments.size
536 537 ja = "\xe3\x83\x86\xe3\x82\xb9\xe3\x83\x88.txt".force_encoding('UTF-8')
537 538 attachment = issue.attachments.first
538 539 assert_equal ja, attachment.filename
539 540 assert_equal 5, attachment.filesize
540 541 assert File.exist?(attachment.diskfile)
541 542 assert_equal 5, File.size(attachment.diskfile)
542 543 assert_equal 'd8e8fca2dc0f896fd7cb4cb0031ba249', attachment.digest
543 544 end
544 545
545 546 def test_thunderbird_with_attachment_latin1
546 547 issue = submit_email(
547 548 'thunderbird_with_attachment_iso-8859-1.eml',
548 549 :issue => {:project => 'ecookbook'}
549 550 )
550 551 assert_kind_of Issue, issue
551 552 assert_equal 1, issue.attachments.size
552 553 u = "".force_encoding('UTF-8')
553 554 u1 = "\xc3\x84\xc3\xa4\xc3\x96\xc3\xb6\xc3\x9c\xc3\xbc".force_encoding('UTF-8')
554 555 11.times { u << u1 }
555 556 attachment = issue.attachments.first
556 557 assert_equal "#{u}.png", attachment.filename
557 558 assert_equal 130, attachment.filesize
558 559 assert File.exist?(attachment.diskfile)
559 560 assert_equal 130, File.size(attachment.diskfile)
560 561 assert_equal '4d80e667ac37dddfe05502530f152abb', attachment.digest
561 562 end
562 563
563 564 def test_gmail_with_attachment_latin1
564 565 issue = submit_email(
565 566 'gmail_with_attachment_iso-8859-1.eml',
566 567 :issue => {:project => 'ecookbook'}
567 568 )
568 569 assert_kind_of Issue, issue
569 570 assert_equal 1, issue.attachments.size
570 571 u = "".force_encoding('UTF-8')
571 572 u1 = "\xc3\x84\xc3\xa4\xc3\x96\xc3\xb6\xc3\x9c\xc3\xbc".force_encoding('UTF-8')
572 573 11.times { u << u1 }
573 574 attachment = issue.attachments.first
574 575 assert_equal "#{u}.txt", attachment.filename
575 576 assert_equal 5, attachment.filesize
576 577 assert File.exist?(attachment.diskfile)
577 578 assert_equal 5, File.size(attachment.diskfile)
578 579 assert_equal 'd8e8fca2dc0f896fd7cb4cb0031ba249', attachment.digest
579 580 end
580 581
581 582 def test_multiple_inline_text_parts_should_be_appended_to_issue_description
582 583 issue = submit_email('multiple_text_parts.eml', :issue => {:project => 'ecookbook'})
583 584 assert_include 'first', issue.description
584 585 assert_include 'second', issue.description
585 586 assert_include 'third', issue.description
586 587 end
587 588
588 589 def test_attachment_text_part_should_be_added_as_issue_attachment
589 590 issue = submit_email('multiple_text_parts.eml', :issue => {:project => 'ecookbook'})
590 591 assert_not_include 'Plain text attachment', issue.description
591 592 attachment = issue.attachments.detect {|a| a.filename == 'textfile.txt'}
592 593 assert_not_nil attachment
593 594 assert_include 'Plain text attachment', File.read(attachment.diskfile)
594 595 end
595 596
596 597 def test_add_issue_with_iso_8859_1_subject
597 598 issue = submit_email(
598 599 'subject_as_iso-8859-1.eml',
599 600 :issue => {:project => 'ecookbook'}
600 601 )
601 602 str = "Testmail from Webmail: \xc3\xa4 \xc3\xb6 \xc3\xbc...".force_encoding('UTF-8')
602 603 assert_kind_of Issue, issue
603 604 assert_equal str, issue.subject
604 605 end
605 606
606 607 def test_quoted_printable_utf8
607 608 issue = submit_email(
608 609 'quoted_printable_utf8.eml',
609 610 :issue => {:project => 'ecookbook'}
610 611 )
611 612 assert_kind_of Issue, issue
612 613 str = "Freundliche Gr\xc3\xbcsse".force_encoding('UTF-8')
613 614 assert_equal str, issue.description
614 615 end
615 616
616 617 def test_gmail_iso8859_2
617 618 issue = submit_email(
618 619 'gmail-iso8859-2.eml',
619 620 :issue => {:project => 'ecookbook'}
620 621 )
621 622 assert_kind_of Issue, issue
622 623 str = "Na \xc5\xa1triku se su\xc5\xa1i \xc5\xa1osi\xc4\x87.".force_encoding('UTF-8')
623 624 assert issue.description.include?(str)
624 625 end
625 626
626 627 def test_add_issue_with_japanese_subject
627 628 issue = submit_email(
628 629 'subject_japanese_1.eml',
629 630 :issue => {:project => 'ecookbook'}
630 631 )
631 632 assert_kind_of Issue, issue
632 633 ja = "\xe3\x83\x86\xe3\x82\xb9\xe3\x83\x88".force_encoding('UTF-8')
633 634 assert_equal ja, issue.subject
634 635 end
635 636
636 637 def test_add_issue_with_korean_body
637 638 # Make sure mail bodies with a charset unknown to Ruby
638 639 # but known to the Mail gem 2.5.4 are handled correctly
639 640 kr = "\xEA\xB3\xA0\xEB\xA7\x99\xEC\x8A\xB5\xEB\x8B\x88\xEB\x8B\xA4.".force_encoding('UTF-8')
640 641 issue = submit_email(
641 642 'body_ks_c_5601-1987.eml',
642 643 :issue => {:project => 'ecookbook'}
643 644 )
644 645 assert_kind_of Issue, issue
645 646 assert_equal kr, issue.description
646 647 end
647 648
648 649 def test_add_issue_with_no_subject_header
649 650 issue = submit_email(
650 651 'no_subject_header.eml',
651 652 :issue => {:project => 'ecookbook'}
652 653 )
653 654 assert_kind_of Issue, issue
654 655 assert_equal '(no subject)', issue.subject
655 656 end
656 657
657 658 def test_add_issue_with_mixed_japanese_subject
658 659 issue = submit_email(
659 660 'subject_japanese_2.eml',
660 661 :issue => {:project => 'ecookbook'}
661 662 )
662 663 assert_kind_of Issue, issue
663 664 ja = "Re: \xe3\x83\x86\xe3\x82\xb9\xe3\x83\x88".force_encoding('UTF-8')
664 665 assert_equal ja, issue.subject
665 666 end
666 667
667 668 def test_should_ignore_emails_from_locked_users
668 669 User.find(2).lock!
669 670
670 671 MailHandler.any_instance.expects(:dispatch).never
671 672 assert_no_difference 'Issue.count' do
672 673 assert_equal false, submit_email('ticket_on_given_project.eml')
673 674 end
674 675 end
675 676
676 677 def test_should_ignore_emails_from_emission_address
677 678 Role.anonymous.add_permission!(:add_issues)
678 679 assert_no_difference 'User.count' do
679 680 assert_equal false,
680 681 submit_email(
681 682 'ticket_from_emission_address.eml',
682 683 :issue => {:project => 'ecookbook'},
683 684 :unknown_user => 'create'
684 685 )
685 686 end
686 687 end
687 688
688 689 def test_should_ignore_auto_replied_emails
689 690 MailHandler.any_instance.expects(:dispatch).never
690 691 [
691 692 "Auto-Submitted: auto-replied",
692 693 "Auto-Submitted: Auto-Replied",
693 694 "Auto-Submitted: auto-generated",
694 695 'X-Autoreply: yes'
695 696 ].each do |header|
696 697 raw = IO.read(File.join(FIXTURES_PATH, 'ticket_on_given_project.eml'))
697 698 raw = header + "\n" + raw
698 699
699 700 assert_no_difference 'Issue.count' do
700 701 assert_equal false, MailHandler.receive(raw), "email with #{header} header was not ignored"
701 702 end
702 703 end
703 704 end
704 705
705 706 test "should not ignore Auto-Submitted headers not defined in RFC3834" do
706 707 [
707 708 "Auto-Submitted: auto-forwarded"
708 709 ].each do |header|
709 710 raw = IO.read(File.join(FIXTURES_PATH, 'ticket_on_given_project.eml'))
710 711 raw = header + "\n" + raw
711 712
712 713 assert_difference 'Issue.count', 1 do
713 714 assert_not_nil MailHandler.receive(raw), "email with #{header} header was ignored"
714 715 end
715 716 end
716 717 end
717 718
718 719 def test_add_issue_should_send_email_notification
719 720 Setting.notified_events = ['issue_added']
720 721 # This email contains: 'Project: onlinestore'
721 722 issue = submit_email('ticket_on_given_project.eml')
722 723 assert issue.is_a?(Issue)
723 724 assert_equal 1, ActionMailer::Base.deliveries.size
724 725 end
725 726
726 727 def test_update_issue
727 728 journal = submit_email('ticket_reply.eml')
728 729 assert journal.is_a?(Journal)
729 730 assert_equal User.find_by_login('jsmith'), journal.user
730 731 assert_equal Issue.find(2), journal.journalized
731 732 assert_match /This is reply/, journal.notes
732 733 assert_equal false, journal.private_notes
733 734 assert_equal 'Feature request', journal.issue.tracker.name
734 735 end
735 736
736 737 def test_update_issue_should_accept_issue_id_after_space_inside_brackets
737 738 journal = submit_email('ticket_reply_with_status.eml') do |email|
738 739 assert email.sub!(/^Subject:.*$/, "Subject: Re: [Feature request #2] Add ingredients categories")
739 740 end
740 741 assert journal.is_a?(Journal)
741 742 assert_equal Issue.find(2), journal.journalized
742 743 end
743 744
744 745 def test_update_issue_should_accept_issue_id_inside_brackets
745 746 journal = submit_email('ticket_reply_with_status.eml') do |email|
746 747 assert email.sub!(/^Subject:.*$/, "Subject: Re: [#2] Add ingredients categories")
747 748 end
748 749 assert journal.is_a?(Journal)
749 750 assert_equal Issue.find(2), journal.journalized
750 751 end
751 752
752 753 def test_update_issue_should_ignore_bogus_issue_ids_in_subject
753 754 journal = submit_email('ticket_reply_with_status.eml') do |email|
754 755 assert email.sub!(/^Subject:.*$/, "Subject: Re: [12345#1][bogus#1][Feature request #2] Add ingredients categories")
755 756 end
756 757 assert journal.is_a?(Journal)
757 758 assert_equal Issue.find(2), journal.journalized
758 759 end
759 760
760 761 def test_update_issue_with_attribute_changes
761 762 journal = submit_email('ticket_reply_with_status.eml', :allow_override => ['status','assigned_to','start_date','due_date', 'float field'])
762 763 assert journal.is_a?(Journal)
763 764 issue = Issue.find(journal.issue.id)
764 765 assert_equal User.find_by_login('jsmith'), journal.user
765 766 assert_equal Issue.find(2), journal.journalized
766 767 assert_match /This is reply/, journal.notes
767 768 assert_equal 'Feature request', journal.issue.tracker.name
768 769 assert_equal IssueStatus.find_by_name("Resolved"), issue.status
769 770 assert_equal '2010-01-01', issue.start_date.to_s
770 771 assert_equal '2010-12-31', issue.due_date.to_s
771 772 assert_equal User.find_by_login('jsmith'), issue.assigned_to
772 773 assert_equal "52.6", issue.custom_value_for(CustomField.find_by_name('Float field')).value
773 774 # keywords should be removed from the email body
774 775 assert !journal.notes.match(/^Status:/i)
775 776 assert !journal.notes.match(/^Start Date:/i)
776 777 end
777 778
778 779 def test_update_issue_with_attachment
779 780 assert_difference 'Journal.count' do
780 781 assert_difference 'JournalDetail.count' do
781 782 assert_difference 'Attachment.count' do
782 783 assert_no_difference 'Issue.count' do
783 784 journal = submit_email('ticket_with_attachment.eml') do |raw|
784 785 raw.gsub! /^Subject: .*$/, 'Subject: Re: [Cookbook - Feature #2] (New) Add ingredients categories'
785 786 end
786 787 end
787 788 end
788 789 end
789 790 end
790 791 journal = Journal.order('id DESC').first
791 792 assert_equal Issue.find(2), journal.journalized
792 793 assert_equal 1, journal.details.size
793 794
794 795 detail = journal.details.first
795 796 assert_equal 'attachment', detail.property
796 797 assert_equal 'Paella.jpg', detail.value
797 798 end
798 799
799 800 def test_update_issue_should_send_email_notification
800 801 journal = submit_email('ticket_reply.eml')
801 802 assert journal.is_a?(Journal)
802 803 assert_equal 1, ActionMailer::Base.deliveries.size
803 804 end
804 805
805 806 def test_update_issue_should_not_set_defaults
806 807 journal = submit_email(
807 808 'ticket_reply.eml',
808 809 :issue => {:tracker => 'Support request', :priority => 'High'}
809 810 )
810 811 assert journal.is_a?(Journal)
811 812 assert_match /This is reply/, journal.notes
812 813 assert_equal 'Feature request', journal.issue.tracker.name
813 814 assert_equal 'Normal', journal.issue.priority.name
814 815 end
815 816
816 817 def test_replying_to_a_private_note_should_add_reply_as_private
817 818 private_journal = Journal.create!(:notes => 'Private notes', :journalized => Issue.find(1), :private_notes => true, :user_id => 2)
818 819
819 820 assert_difference 'Journal.count' do
820 821 journal = submit_email('ticket_reply.eml') do |email|
821 822 email.sub! %r{^In-Reply-To:.*$}, "In-Reply-To: <redmine.journal-#{private_journal.id}.20060719210421@osiris>"
822 823 end
823 824
824 825 assert_kind_of Journal, journal
825 826 assert_match /This is reply/, journal.notes
826 827 assert_equal true, journal.private_notes
827 828 end
828 829 end
829 830
830 831 def test_reply_to_a_message
831 832 m = submit_email('message_reply.eml')
832 833 assert m.is_a?(Message)
833 834 assert !m.new_record?
834 835 m.reload
835 836 assert_equal 'Reply via email', m.subject
836 837 # The email replies to message #2 which is part of the thread of message #1
837 838 assert_equal Message.find(1), m.parent
838 839 end
839 840
840 841 def test_reply_to_a_message_by_subject
841 842 m = submit_email('message_reply_by_subject.eml')
842 843 assert m.is_a?(Message)
843 844 assert !m.new_record?
844 845 m.reload
845 846 assert_equal 'Reply to the first post', m.subject
846 847 assert_equal Message.find(1), m.parent
847 848 end
848 849
849 850 def test_should_convert_tags_of_html_only_emails
850 851 with_settings :text_formatting => 'textile' do
851 852 issue = submit_email('ticket_html_only.eml', :issue => {:project => 'ecookbook'})
852 853 assert issue.is_a?(Issue)
853 854 assert !issue.new_record?
854 855 issue.reload
855 856 assert_equal 'HTML email', issue.subject
856 857 assert_equal "This is a *html-only* email.\r\n\r\nh1. With a title\r\n\r\nand a paragraph.", issue.description
857 858 end
858 859 end
859 860
860 861 def test_should_handle_outlook_web_access_2010_html_only
861 862 issue = submit_email('outlook_web_access_2010_html_only.eml', :issue => {:project => 'ecookbook'})
862 863 assert issue.is_a?(Issue)
863 864 issue.reload
864 865 assert_equal 'Upgrade Redmine to 3.0.x', issue.subject
865 866 assert_equal "A mess.\r\n\r\n--Geoff Maciolek\r\nMYCOMPANYNAME, LLC", issue.description
866 867 end
867 868
868 869 def test_should_handle_outlook_2010_html_only
869 870 issue = submit_email('outlook_2010_html_only.eml', :issue => {:project => 'ecookbook'})
870 871 assert issue.is_a?(Issue)
871 872 issue.reload
872 873 assert_equal 'Test email', issue.subject
873 874 assert_equal "Simple, unadorned test email generated by Outlook 2010. It is in HTML format, but" +
874 875 " no special formatting has been chosen. I’m going to save this as a draft and then manually" +
875 876 " drop it into the Inbox for scraping by Redmine 3.0.2.", issue.description
876 877 end
877 878
878 879 test "truncate emails with no setting should add the entire email into the issue" do
879 880 with_settings :mail_handler_body_delimiters => '' do
880 881 issue = submit_email('ticket_on_given_project.eml')
881 882 assert_issue_created(issue)
882 883 assert issue.description.include?('---')
883 884 assert issue.description.include?('This paragraph is after the delimiter')
884 885 end
885 886 end
886 887
887 888 test "truncate emails with a single string should truncate the email at the delimiter for the issue" do
888 889 with_settings :mail_handler_body_delimiters => '---' do
889 890 issue = submit_email('ticket_on_given_project.eml')
890 891 assert_issue_created(issue)
891 892 assert issue.description.include?('This paragraph is before delimiters')
892 893 assert issue.description.include?('--- This line starts with a delimiter')
893 894 assert !issue.description.match(/^---$/)
894 895 assert !issue.description.include?('This paragraph is after the delimiter')
895 896 end
896 897 end
897 898
898 899 test "truncate emails with a single quoted reply should truncate the email at the delimiter with the quoted reply symbols (>)" do
899 900 with_settings :mail_handler_body_delimiters => '--- Reply above. Do not remove this line. ---' do
900 901 journal = submit_email('issue_update_with_quoted_reply_above.eml')
901 902 assert journal.is_a?(Journal)
902 903 assert journal.notes.include?('An update to the issue by the sender.')
903 904 assert !journal.notes.match(Regexp.escape("--- Reply above. Do not remove this line. ---"))
904 905 assert !journal.notes.include?('Looks like the JSON api for projects was missed.')
905 906 end
906 907 end
907 908
908 909 test "truncate emails with multiple quoted replies should truncate the email at the delimiter with the quoted reply symbols (>)" do
909 910 with_settings :mail_handler_body_delimiters => '--- Reply above. Do not remove this line. ---' do
910 911 journal = submit_email('issue_update_with_multiple_quoted_reply_above.eml')
911 912 assert journal.is_a?(Journal)
912 913 assert journal.notes.include?('An update to the issue by the sender.')
913 914 assert !journal.notes.match(Regexp.escape("--- Reply above. Do not remove this line. ---"))
914 915 assert !journal.notes.include?('Looks like the JSON api for projects was missed.')
915 916 end
916 917 end
917 918
918 919 test "truncate emails with multiple strings should truncate the email at the first delimiter found (BREAK)" do
919 920 with_settings :mail_handler_body_delimiters => "---\nBREAK" do
920 921 issue = submit_email('ticket_on_given_project.eml')
921 922 assert_issue_created(issue)
922 923 assert issue.description.include?('This paragraph is before delimiters')
923 924 assert !issue.description.include?('BREAK')
924 925 assert !issue.description.include?('This paragraph is between delimiters')
925 926 assert !issue.description.match(/^---$/)
926 927 assert !issue.description.include?('This paragraph is after the delimiter')
927 928 end
928 929 end
929 930
930 931 def test_attachments_that_match_mail_handler_excluded_filenames_should_be_ignored
931 932 with_settings :mail_handler_excluded_filenames => '*.vcf, *.jpg' do
932 933 issue = submit_email('ticket_with_attachment.eml', :issue => {:project => 'onlinestore'})
933 934 assert issue.is_a?(Issue)
934 935 assert !issue.new_record?
935 936 assert_equal 0, issue.reload.attachments.size
936 937 end
937 938 end
938 939
939 940 def test_attachments_that_do_not_match_mail_handler_excluded_filenames_should_be_attached
940 941 with_settings :mail_handler_excluded_filenames => '*.vcf, *.gif' do
941 942 issue = submit_email('ticket_with_attachment.eml', :issue => {:project => 'onlinestore'})
942 943 assert issue.is_a?(Issue)
943 944 assert !issue.new_record?
944 945 assert_equal 1, issue.reload.attachments.size
945 946 end
946 947 end
947 948
948 949 def test_email_with_long_subject_line
949 950 issue = submit_email('ticket_with_long_subject.eml')
950 951 assert issue.is_a?(Issue)
951 952 assert_equal issue.subject, 'New ticket on a given project with a very long subject line which exceeds 255 chars and should not be ignored but chopped off. And if the subject line is still not long enough, we just add more text. And more text. Wow, this is really annoying. Especially, if you have nothing to say...'[0,255]
952 953 end
953 954
954 955 def test_first_keyword_should_be_matched
955 956 issue = submit_email('ticket_with_duplicate_keyword.eml', :allow_override => 'priority')
956 957 assert issue.is_a?(Issue)
957 958 assert_equal 'High', issue.priority.name
958 959 end
959 960
960 961 def test_keyword_after_delimiter_should_be_ignored
961 962 with_settings :mail_handler_body_delimiters => "== DELIMITER ==" do
962 963 issue = submit_email('ticket_with_keyword_after_delimiter.eml', :allow_override => 'priority')
963 964 assert issue.is_a?(Issue)
964 965 assert_equal 'Normal', issue.priority.name
965 966 end
966 967 end
967 968
968 969 def test_new_user_from_attributes_should_return_valid_user
969 970 to_test = {
970 971 # [address, name] => [login, firstname, lastname]
971 972 ['jsmith@example.net', nil] => ['jsmith@example.net', 'jsmith', '-'],
972 973 ['jsmith@example.net', 'John'] => ['jsmith@example.net', 'John', '-'],
973 974 ['jsmith@example.net', 'John Smith'] => ['jsmith@example.net', 'John', 'Smith'],
974 975 ['jsmith@example.net', 'John Paul Smith'] => ['jsmith@example.net', 'John', 'Paul Smith'],
975 976 ['jsmith@example.net', 'AVeryLongFirstnameThatExceedsTheMaximumLength Smith'] => ['jsmith@example.net', 'AVeryLongFirstnameThatExceedsT', 'Smith'],
976 977 ['jsmith@example.net', 'John AVeryLongLastnameThatExceedsTheMaximumLength'] => ['jsmith@example.net', 'John', 'AVeryLongLastnameThatExceedsTh']
977 978 }
978 979
979 980 to_test.each do |attrs, expected|
980 981 user = MailHandler.new_user_from_attributes(attrs.first, attrs.last)
981 982
982 983 assert user.valid?, user.errors.full_messages.to_s
983 984 assert_equal attrs.first, user.mail
984 985 assert_equal expected[0], user.login
985 986 assert_equal expected[1], user.firstname
986 987 assert_equal expected[2], user.lastname
987 988 assert_equal 'only_my_events', user.mail_notification
988 989 end
989 990 end
990 991
991 992 def test_new_user_from_attributes_should_use_default_login_if_invalid
992 993 user = MailHandler.new_user_from_attributes('foo+bar@example.net')
993 994 assert user.valid?
994 995 assert user.login =~ /^user[a-f0-9]+$/
995 996 assert_equal 'foo+bar@example.net', user.mail
996 997 end
997 998
998 999 def test_new_user_with_utf8_encoded_fullname_should_be_decoded
999 1000 assert_difference 'User.count' do
1000 1001 issue = submit_email(
1001 1002 'fullname_of_sender_as_utf8_encoded.eml',
1002 1003 :issue => {:project => 'ecookbook'},
1003 1004 :unknown_user => 'create'
1004 1005 )
1005 1006 end
1006 1007 user = User.order('id DESC').first
1007 1008 assert_equal "foo@example.org", user.mail
1008 1009 str1 = "\xc3\x84\xc3\xa4".force_encoding('UTF-8')
1009 1010 str2 = "\xc3\x96\xc3\xb6".force_encoding('UTF-8')
1010 1011 assert_equal str1, user.firstname
1011 1012 assert_equal str2, user.lastname
1012 1013 end
1013 1014
1014 1015 def test_extract_options_from_env_should_return_options
1015 1016 options = MailHandler.extract_options_from_env({
1016 1017 'tracker' => 'defect',
1017 1018 'project' => 'foo',
1018 1019 'unknown_user' => 'create'
1019 1020 })
1020 1021
1021 1022 assert_equal({
1022 1023 :issue => {:tracker => 'defect', :project => 'foo'},
1023 1024 :unknown_user => 'create'
1024 1025 }, options)
1025 1026 end
1026 1027
1027 1028 def test_safe_receive_should_rescue_exceptions_and_return_false
1028 1029 MailHandler.stubs(:receive).raises(Exception.new "Something went wrong")
1029 1030
1030 1031 assert_equal false, MailHandler.safe_receive
1031 1032 end
1032 1033
1033 1034 private
1034 1035
1035 1036 def submit_email(filename, options={})
1036 1037 raw = IO.read(File.join(FIXTURES_PATH, filename))
1037 1038 yield raw if block_given?
1038 1039 MailHandler.receive(raw, options)
1039 1040 end
1040 1041
1041 1042 def assert_issue_created(issue)
1042 1043 assert issue.is_a?(Issue)
1043 1044 assert !issue.new_record?
1044 1045 issue.reload
1045 1046 end
1046 1047 end
@@ -1,192 +1,201
1 1 # Redmine - project management software
2 2 # Copyright (C) 2006-2016 Jean-Philippe Lang
3 3 #
4 4 # This program is free software; you can redistribute it and/or
5 5 # modify it under the terms of the GNU General Public License
6 6 # as published by the Free Software Foundation; either version 2
7 7 # of the License, or (at your option) any later version.
8 8 #
9 9 # This program is distributed in the hope that it will be useful,
10 10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 12 # GNU General Public License for more details.
13 13 #
14 14 # You should have received a copy of the GNU General Public License
15 15 # along with this program; if not, write to the Free Software
16 16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 17
18 18 require File.expand_path('../../test_helper', __FILE__)
19 19
20 20 class WatcherTest < ActiveSupport::TestCase
21 21 fixtures :projects, :users, :email_addresses, :members, :member_roles, :roles, :enabled_modules,
22 22 :issues, :issue_statuses, :enumerations, :trackers, :projects_trackers,
23 23 :boards, :messages,
24 24 :wikis, :wiki_pages,
25 25 :watchers
26 26
27 27 def setup
28 28 @user = User.find(1)
29 29 @issue = Issue.find(1)
30 30 end
31 31
32 32 def test_validate
33 33 user = User.find(5)
34 34 assert !user.active?
35 35 watcher = Watcher.new(:user_id => user.id)
36 36 assert !watcher.save
37 37 end
38 38
39 39 def test_watch
40 40 assert @issue.add_watcher(@user)
41 41 @issue.reload
42 42 assert @issue.watchers.detect { |w| w.user == @user }
43 43 end
44 44
45 45 def test_cant_watch_twice
46 46 assert @issue.add_watcher(@user)
47 47 assert !@issue.add_watcher(@user)
48 48 end
49 49
50 50 def test_watched_by
51 51 assert @issue.add_watcher(@user)
52 52 @issue.reload
53 53 assert @issue.watched_by?(@user)
54 54 assert Issue.watched_by(@user).include?(@issue)
55 55 end
56 56
57 57 def test_watcher_users
58 58 watcher_users = Issue.find(2).watcher_users
59 59 assert_kind_of Array, watcher_users.collect{|w| w}
60 60 assert_kind_of User, watcher_users.first
61 61 end
62 62
63 def test_watcher_users_should_be_reloaded_after_adding_a_watcher
64 issue = Issue.find(2)
65 user = User.generate!
66
67 assert_difference 'issue.watcher_users.to_a.size' do
68 issue.add_watcher user
69 end
70 end
71
63 72 def test_watcher_users_should_not_validate_user
64 73 User.where(:id => 1).update_all("firstname = ''")
65 74 @user.reload
66 75 assert !@user.valid?
67 76
68 77 issue = Issue.new(:project => Project.find(1), :tracker_id => 1, :subject => "test", :author => User.find(2))
69 78 issue.watcher_users << @user
70 79 issue.save!
71 80 assert issue.watched_by?(@user)
72 81 end
73 82
74 83 def test_watcher_user_ids
75 84 assert_equal [1, 3], Issue.find(2).watcher_user_ids.sort
76 85 end
77 86
78 87 def test_watcher_user_ids=
79 88 issue = Issue.new
80 89 issue.watcher_user_ids = ['1', '3']
81 90 assert issue.watched_by?(User.find(1))
82 91 end
83 92
84 93 def test_watcher_user_ids_should_make_ids_uniq
85 94 issue = Issue.new(:project => Project.find(1), :tracker_id => 1, :subject => "test", :author => User.find(2))
86 95 issue.watcher_user_ids = ['1', '3', '1']
87 96 issue.save!
88 97 assert_equal 2, issue.watchers.count
89 98 end
90 99
91 100 def test_addable_watcher_users
92 101 addable_watcher_users = @issue.addable_watcher_users
93 102 assert_kind_of Array, addable_watcher_users
94 103 assert_kind_of User, addable_watcher_users.first
95 104 end
96 105
97 106 def test_addable_watcher_users_should_not_include_user_that_cannot_view_the_object
98 107 issue = Issue.new(:project => Project.find(1), :is_private => true)
99 108 assert_nil issue.addable_watcher_users.detect {|user| !issue.visible?(user)}
100 109 end
101 110
102 111 def test_any_watched_should_return_false_if_no_object_is_watched
103 112 objects = (0..2).map {Issue.generate!}
104 113
105 114 assert_equal false, Watcher.any_watched?(objects, @user)
106 115 end
107 116
108 117 def test_any_watched_should_return_true_if_one_object_is_watched
109 118 objects = (0..2).map {Issue.generate!}
110 119 objects.last.add_watcher(@user)
111 120
112 121 assert_equal true, Watcher.any_watched?(objects, @user)
113 122 end
114 123
115 124 def test_any_watched_should_return_false_with_no_object
116 125 assert_equal false, Watcher.any_watched?([], @user)
117 126 end
118 127
119 128 def test_recipients
120 129 @issue.watchers.delete_all
121 130 @issue.reload
122 131
123 132 assert @issue.watcher_recipients.empty?
124 133 assert @issue.add_watcher(@user)
125 134
126 135 @user.mail_notification = 'all'
127 136 @user.save!
128 137 @issue.reload
129 138 assert @issue.watcher_recipients.include?(@user.mail)
130 139
131 140 @user.mail_notification = 'none'
132 141 @user.save!
133 142 @issue.reload
134 143 assert !@issue.watcher_recipients.include?(@user.mail)
135 144 end
136 145
137 146 def test_unwatch
138 147 assert @issue.add_watcher(@user)
139 148 @issue.reload
140 149 assert_equal 1, @issue.remove_watcher(@user)
141 150 end
142 151
143 152 def test_prune_with_user
144 153 Watcher.delete_all("user_id = 9")
145 154 user = User.find(9)
146 155
147 156 # public
148 157 Watcher.create!(:watchable => Issue.find(1), :user => user)
149 158 Watcher.create!(:watchable => Issue.find(2), :user => user)
150 159 Watcher.create!(:watchable => Message.find(1), :user => user)
151 160 Watcher.create!(:watchable => Wiki.find(1), :user => user)
152 161 Watcher.create!(:watchable => WikiPage.find(2), :user => user)
153 162
154 163 # private project (id: 2)
155 164 Member.create!(:project => Project.find(2), :principal => user, :role_ids => [1])
156 165 Watcher.create!(:watchable => Issue.find(4), :user => user)
157 166 Watcher.create!(:watchable => Message.find(7), :user => user)
158 167 Watcher.create!(:watchable => Wiki.find(2), :user => user)
159 168 Watcher.create!(:watchable => WikiPage.find(3), :user => user)
160 169
161 170 assert_no_difference 'Watcher.count' do
162 171 Watcher.prune(:user => User.find(9))
163 172 end
164 173
165 174 Member.delete_all
166 175
167 176 assert_difference 'Watcher.count', -4 do
168 177 Watcher.prune(:user => User.find(9))
169 178 end
170 179
171 180 assert Issue.find(1).watched_by?(user)
172 181 assert !Issue.find(4).watched_by?(user)
173 182 end
174 183
175 184 def test_prune_with_project
176 185 user = User.find(9)
177 186 Watcher.new(:watchable => Issue.find(4), :user => User.find(9)).save(:validate => false) # project 2
178 187 Watcher.new(:watchable => Issue.find(6), :user => User.find(9)).save(:validate => false) # project 5
179 188
180 189 assert Watcher.prune(:project => Project.find(5)) > 0
181 190 assert Issue.find(4).watched_by?(user)
182 191 assert !Issue.find(6).watched_by?(user)
183 192 end
184 193
185 194 def test_prune_all
186 195 user = User.find(9)
187 196 Watcher.new(:watchable => Issue.find(4), :user => User.find(9)).save(:validate => false)
188 197
189 198 assert Watcher.prune > 0
190 199 assert !Issue.find(4).watched_by?(user)
191 200 end
192 201 end
General Comments 0
You need to be logged in to leave comments. Login now