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