mlist 0.1.18 → 0.1.19
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +4 -0
- data/VERSION.yml +1 -1
- data/lib/mlist/email_subscriber.rb +3 -3
- data/lib/mlist/list.rb +30 -30
- data/lib/mlist/mail_list.rb +1 -1
- data/lib/mlist/manager/database.rb +13 -13
- data/lib/mlist/manager/notifier.rb +6 -6
- data/lib/mlist/message.rb +22 -22
- data/lib/mlist/util/email_helpers.rb +1 -1
- data/spec/fixtures/schema.rb +14 -14
- data/spec/integration/mlist_spec.rb +35 -35
- data/spec/models/mail_list_spec.rb +2 -2
- metadata +3 -3
data/CHANGELOG
CHANGED
@@ -1,3 +1,7 @@
|
|
1
|
+
*0.1.19 [Enhancement] (2010-08-12)
|
2
|
+
|
3
|
+
* Requiring subscriber instances to respond to 'rfc5322_email' instead of 'email_address' in order to allow the latter name to be used in associations. [aiwilliams]
|
4
|
+
|
1
5
|
*0.1.18 [Enhancement] (2010-06-11)
|
2
6
|
|
3
7
|
* Moving mail that has no rfc822 content into a settings[:failure_folder], if that setting is provided. [aiwilliams]
|
data/VERSION.yml
CHANGED
data/lib/mlist/list.rb
CHANGED
@@ -1,22 +1,22 @@
|
|
1
1
|
module MList
|
2
|
-
|
2
|
+
|
3
3
|
# Represents the interface of the lists that a list manager must answer.
|
4
4
|
# This is distinct from the MList::MailList to allow for greater flexibility
|
5
5
|
# in processing email coming to a list - that is, whatever you include this
|
6
6
|
# into may re-define behavior appropriately.
|
7
7
|
#
|
8
|
-
# Your 'subscriber' instances MUST respond to :
|
9
|
-
# optionally respond to :display_name.
|
8
|
+
# Your 'subscriber' instances MUST respond to :rfc5322_email. They
|
9
|
+
# may optionally respond to :display_name.
|
10
10
|
#
|
11
11
|
module List
|
12
|
-
|
12
|
+
|
13
13
|
# Answers whether this list is active or not. All lists are active all the
|
14
14
|
# time by default.
|
15
15
|
#
|
16
16
|
def active?
|
17
17
|
true
|
18
18
|
end
|
19
|
-
|
19
|
+
|
20
20
|
# Answers whether the email has been to this list before. The simplest
|
21
21
|
# test is whether the email has an X-BeenThere header that matches this
|
22
22
|
# list's address.
|
@@ -24,28 +24,28 @@ module MList
|
|
24
24
|
def been_here?(email)
|
25
25
|
email.been_there_addresses.include?(address.downcase)
|
26
26
|
end
|
27
|
-
|
27
|
+
|
28
28
|
# Answers whether the subscriber is blocked from posting or not. This will
|
29
29
|
# not be asked when the list is not active (answers _active?_ as false).
|
30
30
|
#
|
31
31
|
def blocked?(subscriber)
|
32
32
|
false
|
33
33
|
end
|
34
|
-
|
34
|
+
|
35
35
|
# Answers the footer content for this list. Default implementation is very
|
36
36
|
# simple.
|
37
37
|
#
|
38
38
|
def footer_content(message)
|
39
39
|
%Q{The "#{label}" mailing list\nPost messages: #{post_url}}
|
40
40
|
end
|
41
|
-
|
41
|
+
|
42
42
|
# Answer a suitable label for the list, which will be used in various
|
43
43
|
# parts of content that is delivered to subscribers, etc.
|
44
44
|
#
|
45
45
|
def label
|
46
46
|
raise 'answer the list label'
|
47
47
|
end
|
48
|
-
|
48
|
+
|
49
49
|
# Answers the headers that are to be included in the emails delivered for
|
50
50
|
# this list. Any entries that have a nil value will not be included in the
|
51
51
|
# delivered email.
|
@@ -61,20 +61,20 @@ module MList
|
|
61
61
|
'list-post' => post_url
|
62
62
|
}
|
63
63
|
end
|
64
|
-
|
64
|
+
|
65
65
|
# Answers a unique, never changing value for this list.
|
66
66
|
#
|
67
67
|
def list_id
|
68
68
|
raise 'answer a unique, never changing value'
|
69
69
|
end
|
70
|
-
|
70
|
+
|
71
71
|
# The web address where an archive of this list may be found, nil if there
|
72
72
|
# is no archive.
|
73
73
|
#
|
74
74
|
def archive_url
|
75
75
|
nil
|
76
76
|
end
|
77
|
-
|
77
|
+
|
78
78
|
# Should the sender of an email be copied in the publication? Defaults to
|
79
79
|
# false. If _recipients_ includes the sender email address, it will be
|
80
80
|
# removed if this answers false.
|
@@ -84,47 +84,47 @@ module MList
|
|
84
84
|
def copy_sender?(subscriber)
|
85
85
|
false
|
86
86
|
end
|
87
|
-
|
87
|
+
|
88
88
|
# The web address of the list help site, nil if this is not supported.
|
89
89
|
#
|
90
90
|
def help_url
|
91
91
|
nil
|
92
92
|
end
|
93
|
-
|
93
|
+
|
94
94
|
# The email address of the list owner, nil if this is not supported.
|
95
95
|
#
|
96
96
|
def owner_url
|
97
97
|
nil
|
98
98
|
end
|
99
|
-
|
99
|
+
|
100
100
|
# The email address where posts should be sent. Defaults to the address of
|
101
101
|
# the list.
|
102
102
|
#
|
103
103
|
def post_url
|
104
104
|
address
|
105
105
|
end
|
106
|
-
|
106
|
+
|
107
107
|
# Should the reply-to header be set to the list's address? Defaults to
|
108
108
|
# true. If false is returned, the reply-to will be the subscriber address.
|
109
109
|
#
|
110
110
|
def reply_to_list?
|
111
111
|
true
|
112
112
|
end
|
113
|
-
|
113
|
+
|
114
114
|
# The web url where subscriptions to this list may be created, nil if this
|
115
115
|
# is not supported.
|
116
116
|
#
|
117
117
|
def subscribe_url
|
118
118
|
nil
|
119
119
|
end
|
120
|
-
|
120
|
+
|
121
121
|
# The web url where subscriptions to this list may be deleted, nil if this
|
122
122
|
# is not supported.
|
123
123
|
#
|
124
124
|
def unsubscribe_url
|
125
125
|
nil
|
126
126
|
end
|
127
|
-
|
127
|
+
|
128
128
|
# A list is responsible for answering the recipient subscribers. The
|
129
129
|
# answer may or may not include the subscriber; _copy_sender?_ will be
|
130
130
|
# invoked and the subscriber will be added or removed from the Array.
|
@@ -135,16 +135,16 @@ module MList
|
|
135
135
|
def recipients(subscriber)
|
136
136
|
subscribers
|
137
137
|
end
|
138
|
-
|
138
|
+
|
139
139
|
# A list must answer the subscriber who's email address is that of the one
|
140
140
|
# provided. The default implementation will pick the first instance that
|
141
|
-
# answers subscriber.
|
141
|
+
# answers subscriber.rfc5322_email == email_address. Your implementation
|
142
142
|
# should probably select just one record.
|
143
143
|
#
|
144
144
|
def subscriber(email_address)
|
145
|
-
subscribers.detect {|s| s.
|
145
|
+
subscribers.detect {|s| s.rfc5322_email == email_address}
|
146
146
|
end
|
147
|
-
|
147
|
+
|
148
148
|
# A list must answer whether there is a subscriber who's email address is
|
149
149
|
# that of the one provided. This is checked before the subscriber is
|
150
150
|
# requested in order to allow for the lightest weight check possible; that
|
@@ -154,12 +154,12 @@ module MList
|
|
154
154
|
def subscriber?(email_address)
|
155
155
|
!subscriber(email_address).nil?
|
156
156
|
end
|
157
|
-
|
157
|
+
|
158
158
|
# Methods that will be invoked on your implementation of Mlist::List when
|
159
159
|
# certain events occur during the processing of email sent to a list.
|
160
160
|
#
|
161
161
|
module Callbacks
|
162
|
-
|
162
|
+
|
163
163
|
# Called when an email is a post to the list by a subscriber whom the
|
164
164
|
# list claims is blocked (answers true to _blocked?(subscriber)_). This
|
165
165
|
# will not be called if the list is inactive (answers false to
|
@@ -167,10 +167,10 @@ module MList
|
|
167
167
|
#
|
168
168
|
def blocked_subscriber_post(email, subscriber)
|
169
169
|
end
|
170
|
-
|
170
|
+
|
171
171
|
def bounce(email)
|
172
172
|
end
|
173
|
-
|
173
|
+
|
174
174
|
# Called when an email is a post to the list while the list is inactive
|
175
175
|
# (answers false to _active?_). This will not be called if the email is
|
176
176
|
# from a non-subscribed sender. Instead, _non_subscriber_post_ will be
|
@@ -178,7 +178,7 @@ module MList
|
|
178
178
|
#
|
179
179
|
def inactive_post(email)
|
180
180
|
end
|
181
|
-
|
181
|
+
|
182
182
|
# Called when an email is a post to the list from a non-subscribed
|
183
183
|
# sender. This will be called even if the list is inactive.
|
184
184
|
#
|
@@ -186,6 +186,6 @@ module MList
|
|
186
186
|
end
|
187
187
|
end
|
188
188
|
include Callbacks
|
189
|
-
|
189
|
+
|
190
190
|
end
|
191
|
-
end
|
191
|
+
end
|
data/lib/mlist/mail_list.rb
CHANGED
@@ -209,7 +209,7 @@ module MList
|
|
209
209
|
message.subject = clean_subject(message.subject)
|
210
210
|
|
211
211
|
recipient_addresses = message.recipient_addresses
|
212
|
-
sender_address = message.subscriber.
|
212
|
+
sender_address = message.subscriber.rfc5322_email
|
213
213
|
if options[:copy_sender]
|
214
214
|
recipient_addresses << sender_address unless recipient_addresses.include?(sender_address)
|
215
215
|
else
|
@@ -1,9 +1,9 @@
|
|
1
1
|
module MList
|
2
2
|
module Manager
|
3
|
-
|
3
|
+
|
4
4
|
class Database
|
5
5
|
include ::MList::Manager
|
6
|
-
|
6
|
+
|
7
7
|
def create_list(address, attributes = {})
|
8
8
|
attributes = {
|
9
9
|
:address => address,
|
@@ -11,38 +11,38 @@ module MList
|
|
11
11
|
}.merge(attributes)
|
12
12
|
List.create!(attributes)
|
13
13
|
end
|
14
|
-
|
14
|
+
|
15
15
|
def lists(email)
|
16
16
|
lists = List.find_all_by_address(email.list_addresses)
|
17
17
|
email.list_addresses.map { |a| lists.detect {|l| l.address == a} }.compact
|
18
18
|
end
|
19
|
-
|
19
|
+
|
20
20
|
def no_lists_found(email)
|
21
21
|
# TODO: Move to notifier
|
22
22
|
end
|
23
|
-
|
23
|
+
|
24
24
|
class List < ActiveRecord::Base
|
25
25
|
include ::MList::List
|
26
|
-
|
26
|
+
|
27
27
|
has_many :subscribers, :dependent => :delete_all
|
28
|
-
|
28
|
+
|
29
29
|
def label
|
30
30
|
self[:label]
|
31
31
|
end
|
32
|
-
|
32
|
+
|
33
33
|
def list_id
|
34
34
|
"#{self.class.name}#{id}"
|
35
35
|
end
|
36
|
-
|
36
|
+
|
37
37
|
def subscribe(address)
|
38
|
-
subscribers.
|
38
|
+
subscribers.find_or_create_by_rfc5322_email(address)
|
39
39
|
end
|
40
40
|
end
|
41
|
-
|
41
|
+
|
42
42
|
class Subscriber < ActiveRecord::Base
|
43
43
|
belongs_to :list
|
44
44
|
end
|
45
45
|
end
|
46
|
-
|
46
|
+
|
47
47
|
end
|
48
|
-
end
|
48
|
+
end
|
@@ -1,11 +1,11 @@
|
|
1
1
|
module MList
|
2
2
|
module Manager
|
3
|
-
|
3
|
+
|
4
4
|
# Constructs the notices that are sent to list subscribers. Applications
|
5
5
|
# may subclass this to customize the content of a notice delivery.
|
6
6
|
#
|
7
7
|
class Notifier
|
8
|
-
|
8
|
+
|
9
9
|
# Answers the delivery that will be sent to a subscriber when an
|
10
10
|
# MList::List indicates that the distribution of an email from that
|
11
11
|
# subscriber has been blocked.
|
@@ -14,18 +14,18 @@ module MList
|
|
14
14
|
delivery = MList::Util::TMailBuilder.new(TMail::Mail.new)
|
15
15
|
delivery.write_header('x-mlist-loop', 'notice')
|
16
16
|
delivery.write_header('x-mlist-notice', 'subscriber_blocked')
|
17
|
-
delivery.to = subscriber.
|
17
|
+
delivery.to = subscriber.rfc5322_email
|
18
18
|
delivery.from = "mlist-#{list.address}"
|
19
19
|
prepare_subscriber_blocked_content(list, email, subscriber, delivery)
|
20
20
|
delivery
|
21
21
|
end
|
22
|
-
|
22
|
+
|
23
23
|
protected
|
24
24
|
def prepare_subscriber_blocked_content(list, email, subscriber, delivery)
|
25
25
|
delivery.set_content_type('text/plain')
|
26
26
|
delivery.body = %{Although you are a subscriber to this list, your message cannot be posted at this time. Please contact the administrator of the list.}
|
27
27
|
end
|
28
28
|
end
|
29
|
-
|
29
|
+
|
30
30
|
end
|
31
|
-
end
|
31
|
+
end
|
data/lib/mlist/message.rb
CHANGED
@@ -1,22 +1,22 @@
|
|
1
1
|
module MList
|
2
|
-
|
2
|
+
|
3
3
|
class Message < ActiveRecord::Base
|
4
4
|
set_table_name 'mlist_messages'
|
5
|
-
|
5
|
+
|
6
6
|
include MList::Util::EmailHelpers
|
7
|
-
|
7
|
+
|
8
8
|
belongs_to :email, :class_name => 'MList::Email'
|
9
9
|
belongs_to :parent, :class_name => 'MList::Message'
|
10
10
|
belongs_to :mail_list, :class_name => 'MList::MailList', :counter_cache => :messages_count
|
11
11
|
belongs_to :thread, :class_name => 'MList::Thread', :counter_cache => :messages_count
|
12
|
-
|
12
|
+
|
13
13
|
after_destroy :delete_unreferenced_email
|
14
|
-
|
14
|
+
|
15
15
|
# A temporary storage of recipient subscribers, obtained from
|
16
16
|
# MList::Lists. This list is not available when a message is reloaded.
|
17
17
|
#
|
18
18
|
attr_accessor :recipients
|
19
|
-
|
19
|
+
|
20
20
|
# Answers an MList::TMailBuilder for assembling the TMail::Mail object
|
21
21
|
# that will be fit for delivery. If this is not a new message, the
|
22
22
|
# delivery will be updated to reflect the message-id, x-mailer, etc. of
|
@@ -33,26 +33,26 @@ module MList
|
|
33
33
|
d
|
34
34
|
end
|
35
35
|
end
|
36
|
-
|
36
|
+
|
37
37
|
def email_with_capture=(email)
|
38
38
|
self.subject = email.subject
|
39
39
|
self.mailer = email.mailer
|
40
40
|
self.email_without_capture = email
|
41
41
|
end
|
42
42
|
alias_method_chain :email=, :capture
|
43
|
-
|
43
|
+
|
44
44
|
# Answers the html content of the message.
|
45
45
|
#
|
46
46
|
def html
|
47
47
|
email.html
|
48
48
|
end
|
49
|
-
|
49
|
+
|
50
50
|
# Answers the text content of the message.
|
51
51
|
#
|
52
52
|
def text
|
53
53
|
email.text
|
54
54
|
end
|
55
|
-
|
55
|
+
|
56
56
|
# Answers the text content of the message as HTML. The structure of this
|
57
57
|
# output is very simple. For examples of what it can handle, please check
|
58
58
|
# out the spec documents for MList::Util::EmailHelpers.
|
@@ -60,21 +60,21 @@ module MList
|
|
60
60
|
def text_html
|
61
61
|
text_to_html(text)
|
62
62
|
end
|
63
|
-
|
63
|
+
|
64
64
|
# Answers text suitable for creating a reply message.
|
65
65
|
#
|
66
66
|
def text_for_reply
|
67
67
|
timestamp = email.date.to_s(:mlist_reply_timestamp)
|
68
68
|
"On #{timestamp}, #{email.from} wrote:\n#{text_to_quoted(text)}"
|
69
69
|
end
|
70
|
-
|
70
|
+
|
71
71
|
# Answers text suitable for creating a reply message, converted to the
|
72
72
|
# same simple html of _text_html_.
|
73
73
|
#
|
74
74
|
def html_for_reply
|
75
75
|
text_to_html(text_for_reply)
|
76
76
|
end
|
77
|
-
|
77
|
+
|
78
78
|
def parent_with_identifier_capture=(parent)
|
79
79
|
if parent
|
80
80
|
self.parent_without_identifier_capture = parent
|
@@ -85,7 +85,7 @@ module MList
|
|
85
85
|
end
|
86
86
|
end
|
87
87
|
alias_method_chain :parent=, :identifier_capture
|
88
|
-
|
88
|
+
|
89
89
|
# Answers the recipient email addresses from the MList::List recipient
|
90
90
|
# subscribers, except those that are in the email TO or CC fields as
|
91
91
|
# placed there by the sending MUA. It is assumed that those addresses have
|
@@ -93,9 +93,9 @@ module MList
|
|
93
93
|
# we would cause them to receive two copies of the message.
|
94
94
|
#
|
95
95
|
def recipient_addresses
|
96
|
-
@recipients.collect(&:
|
96
|
+
@recipients.collect(&:rfc5322_email).collect(&:downcase) - email.recipient_addresses
|
97
97
|
end
|
98
|
-
|
98
|
+
|
99
99
|
# Answers the subject with 'Re:' prefixed. Note that it is the
|
100
100
|
# responsibility of the MList::MailList to perform any processing of the
|
101
101
|
# persisted subject (ie, cleaning up labels, etc).
|
@@ -109,7 +109,7 @@ module MList
|
|
109
109
|
def subject_for_reply
|
110
110
|
subject =~ REGARD_RE ? subject : "Re: #{subject}"
|
111
111
|
end
|
112
|
-
|
112
|
+
|
113
113
|
# Answers the subscriber from which this message comes.
|
114
114
|
#
|
115
115
|
def subscriber
|
@@ -121,19 +121,19 @@ module MList
|
|
121
121
|
end
|
122
122
|
end
|
123
123
|
end
|
124
|
-
|
124
|
+
|
125
125
|
# Assigns the subscriber from which this message comes.
|
126
126
|
#
|
127
127
|
def subscriber=(subscriber)
|
128
128
|
case subscriber
|
129
129
|
when ActiveRecord::Base
|
130
130
|
@subscriber = subscriber
|
131
|
-
self.subscriber_address = subscriber.
|
131
|
+
self.subscriber_address = subscriber.rfc5322_email
|
132
132
|
self.subscriber_type = subscriber.class.base_class.name
|
133
133
|
self.subscriber_id = subscriber.id
|
134
134
|
when MList::EmailSubscriber
|
135
135
|
@subscriber = subscriber
|
136
|
-
self.subscriber_address = subscriber.
|
136
|
+
self.subscriber_address = subscriber.rfc5322_email
|
137
137
|
self.subscriber_type = self.subscriber_id = nil
|
138
138
|
when String
|
139
139
|
self.subscriber = MList::EmailSubscriber.new(subscriber)
|
@@ -141,10 +141,10 @@ module MList
|
|
141
141
|
@subscriber = self.subscriber_address = self.subscriber_type = self.subscriber_id = nil
|
142
142
|
end
|
143
143
|
end
|
144
|
-
|
144
|
+
|
145
145
|
private
|
146
146
|
def delete_unreferenced_email
|
147
147
|
email.destroy unless MList::Message.count(:conditions => "email_id = #{email_id} and id != #{id}") > 0
|
148
148
|
end
|
149
149
|
end
|
150
|
-
end
|
150
|
+
end
|
data/spec/fixtures/schema.rb
CHANGED
@@ -1,16 +1,16 @@
|
|
1
1
|
ActiveRecord::Schema.define(:version => 20081126181722) do
|
2
|
-
|
2
|
+
|
3
3
|
# All MList required tables are prefixed with 'mlist_' to ease integration
|
4
4
|
# into other systems' databases.
|
5
|
-
|
6
|
-
|
5
|
+
|
6
|
+
|
7
7
|
# The table in which email content is stored.
|
8
|
-
#
|
8
|
+
#
|
9
9
|
create_table :mlist_emails, :force => true do |t|
|
10
10
|
t.column :source, :text
|
11
11
|
t.column :created_at, :datetime
|
12
12
|
end
|
13
|
-
|
13
|
+
|
14
14
|
# The table in which MList will store MList::Messages.
|
15
15
|
#
|
16
16
|
# The identifier is the 'message-id' header value of the finally delivered
|
@@ -18,9 +18,9 @@ ActiveRecord::Schema.define(:version => 20081126181722) do
|
|
18
18
|
#
|
19
19
|
# An MList::Message will store a reference to your application's subscriber
|
20
20
|
# instance if it is an ActiveRecord subclass. That subclass must respond to
|
21
|
-
# :
|
22
|
-
# an email address. Either way, that email address will be stored with
|
23
|
-
# MList::Message, providing a way for you to associate messages by
|
21
|
+
# :rfc5322_email. If your subscriber is just a string, it is assumed
|
22
|
+
# to be an email address. Either way, that email address will be stored with
|
23
|
+
# the MList::Message, providing a way for you to associate messages by
|
24
24
|
# subscriber_address. This is less ideal, as you may allow subscribers to
|
25
25
|
# change their email addresses over time.
|
26
26
|
#
|
@@ -46,7 +46,7 @@ ActiveRecord::Schema.define(:version => 20081126181722) do
|
|
46
46
|
add_index :mlist_messages, :subject
|
47
47
|
add_index :mlist_messages, :subscriber_address
|
48
48
|
add_index :mlist_messages, [:subscriber_type, :subscriber_id]
|
49
|
-
|
49
|
+
|
50
50
|
# Every MList::Message is associated with an MList::Thread.
|
51
51
|
#
|
52
52
|
create_table :mlist_threads, :force => true do |t|
|
@@ -55,7 +55,7 @@ ActiveRecord::Schema.define(:version => 20081126181722) do
|
|
55
55
|
t.timestamps
|
56
56
|
end
|
57
57
|
add_index :mlist_threads, :mail_list_id
|
58
|
-
|
58
|
+
|
59
59
|
# The table in which MList will store MList::MailLists.
|
60
60
|
#
|
61
61
|
# The manager_list_identifier column stores the MList::List#list_id value.
|
@@ -76,8 +76,8 @@ ActiveRecord::Schema.define(:version => 20081126181722) do
|
|
76
76
|
add_index :mlist_mail_lists, :manager_list_identifier
|
77
77
|
add_index :mlist_mail_lists, [:manager_list_identifier, :manager_list_type, :manager_list_id],
|
78
78
|
:name => :index_mlist_mail_lists_on_manager_association
|
79
|
-
|
80
|
-
|
79
|
+
|
80
|
+
|
81
81
|
# Database list manager tables, used for testing purposes.
|
82
82
|
#
|
83
83
|
create_table :lists, :force => true do |t|
|
@@ -85,10 +85,10 @@ ActiveRecord::Schema.define(:version => 20081126181722) do
|
|
85
85
|
t.column :label, :string
|
86
86
|
t.column :created_at, :datetime
|
87
87
|
end
|
88
|
-
|
88
|
+
|
89
89
|
create_table :subscribers, :force => true do |t|
|
90
90
|
t.column :list_id, :integer
|
91
|
-
t.column :
|
91
|
+
t.column :rfc5322_email, :string
|
92
92
|
t.column :created_at, :datetime
|
93
93
|
end
|
94
94
|
end
|
@@ -12,7 +12,7 @@ describe MList do
|
|
12
12
|
end.should_not store_message
|
13
13
|
end
|
14
14
|
end
|
15
|
-
|
15
|
+
|
16
16
|
def store_message
|
17
17
|
simple_matcher('store message') do |block|
|
18
18
|
thread_count, message_count = MList::Thread.count, MList::Message.count
|
@@ -20,7 +20,7 @@ describe MList do
|
|
20
20
|
MList::Thread.count == thread_count + 1 && MList::Message.count == message_count + 1
|
21
21
|
end
|
22
22
|
end
|
23
|
-
|
23
|
+
|
24
24
|
def start_new_thread(tmail)
|
25
25
|
simple_matcher('start new thread') do |email_server|
|
26
26
|
delivery_count = email_server.deliveries.size
|
@@ -32,34 +32,34 @@ describe MList do
|
|
32
32
|
MList::Message.count == (message_count + 1)
|
33
33
|
end
|
34
34
|
end
|
35
|
-
|
35
|
+
|
36
36
|
dataset do
|
37
37
|
@list_manager = MList::Manager::Database.new
|
38
38
|
@list_one = @list_manager.create_list('list_one@example.com')
|
39
39
|
@list_one.subscribe('adam@nomail.net')
|
40
40
|
@list_one.subscribe('tom@example.com')
|
41
41
|
@list_one.subscribe('dick@example.com')
|
42
|
-
|
42
|
+
|
43
43
|
@list_two = @list_manager.create_list('list_two@example.com')
|
44
44
|
@list_two.subscribe('adam@nomail.net')
|
45
45
|
@list_two.subscribe('jane@example.com')
|
46
|
-
|
46
|
+
|
47
47
|
@list_three = @list_manager.create_list('empty@example.com')
|
48
48
|
@list_three.subscribe('adam@nomail.net')
|
49
49
|
end
|
50
|
-
|
50
|
+
|
51
51
|
before do
|
52
52
|
@email_server = MList::EmailServer::Fake.new
|
53
53
|
@server = MList::Server.new(
|
54
54
|
:list_manager => @list_manager,
|
55
55
|
:email_server => @email_server
|
56
56
|
)
|
57
|
-
|
57
|
+
|
58
58
|
# TODO Move this stuff to Dataset
|
59
59
|
ActiveRecord::Base.connection.increment_open_transactions
|
60
60
|
ActiveRecord::Base.connection.begin_db_transaction
|
61
61
|
end
|
62
|
-
|
62
|
+
|
63
63
|
after do
|
64
64
|
if ActiveRecord::Base.connection.open_transactions != 0
|
65
65
|
ActiveRecord::Base.connection.rollback_db_transaction
|
@@ -67,39 +67,39 @@ describe MList do
|
|
67
67
|
end
|
68
68
|
ActiveRecord::Base.clear_active_connections!
|
69
69
|
end
|
70
|
-
|
70
|
+
|
71
71
|
it 'should have threads and mail_lists updated_at set to last message receive time' do
|
72
72
|
now = Time.now
|
73
73
|
stub(Time).now {now}
|
74
74
|
@email_server.receive(tmail_fixture('single_list'))
|
75
75
|
MList::MailList.last.updated_at.to_s.should == now.to_s
|
76
76
|
MList::Thread.last.updated_at.to_s.should == now.to_s
|
77
|
-
|
77
|
+
|
78
78
|
later = 5.days.from_now
|
79
79
|
stub(Time).now {later}
|
80
80
|
@email_server.receive(tmail_fixture('single_list_reply'))
|
81
81
|
MList::MailList.last.updated_at.to_s.should == later.to_s
|
82
82
|
MList::Thread.last.updated_at.to_s.should == later.to_s
|
83
83
|
end
|
84
|
-
|
84
|
+
|
85
85
|
it 'should associate manager lists to mlist mail lists when they are ActiveRecord instances' do
|
86
86
|
@email_server.receive(tmail_fixture('single_list'))
|
87
87
|
mail_list = MList::MailList.last
|
88
88
|
mail_list.manager_list.should == @list_one
|
89
89
|
mail_list.manager_list_identifier.should == @list_one.list_id
|
90
90
|
end
|
91
|
-
|
91
|
+
|
92
92
|
it 'should not forward mail that has been on this server before' do
|
93
93
|
# The sample email has multiple headers to prove that's not a problem
|
94
94
|
@email_server.should_not forward_email(tmail_fixture('x-beenthere'))
|
95
95
|
end
|
96
|
-
|
96
|
+
|
97
97
|
it 'should store message/thread even when there are no recipient subscribers' do
|
98
98
|
tmail = tmail_fixture('single_list')
|
99
99
|
tmail.to = @list_three.address
|
100
100
|
@email_server.should start_new_thread(tmail)
|
101
101
|
end
|
102
|
-
|
102
|
+
|
103
103
|
it 'should not forward mail from non-subscriber and notify manager list' do
|
104
104
|
tmail = tmail_fixture('single_list')
|
105
105
|
tmail.from = 'unknown@example.com'
|
@@ -107,7 +107,7 @@ describe MList do
|
|
107
107
|
mock(@list_one).non_subscriber_post(is_a(MList::Email))
|
108
108
|
@email_server.should_not forward_email(tmail)
|
109
109
|
end
|
110
|
-
|
110
|
+
|
111
111
|
it 'should not forward mail from non-subscriber when inactive and notify as non-subscriber' do
|
112
112
|
tmail = tmail_fixture('single_list')
|
113
113
|
tmail.from = 'unknown@example.com'
|
@@ -116,9 +116,9 @@ describe MList do
|
|
116
116
|
mock(@list_one).non_subscriber_post(is_a(MList::Email))
|
117
117
|
@email_server.should_not forward_email(tmail)
|
118
118
|
end
|
119
|
-
|
119
|
+
|
120
120
|
it 'should not forward mail from blocked subscriber, notify the subscriber using list manager notifier' do
|
121
|
-
subscriber = MList::Manager::Database::Subscriber.
|
121
|
+
subscriber = MList::Manager::Database::Subscriber.find_by_rfc5322_email('adam@nomail.net')
|
122
122
|
tmail = tmail_fixture('single_list')
|
123
123
|
mock(@list_one).active? {true}
|
124
124
|
mock(@list_one).blocked?(subscriber) { true }
|
@@ -132,7 +132,7 @@ describe MList do
|
|
132
132
|
response_tmail.header_string('x-mlist-notice').should == 'subscriber_blocked'
|
133
133
|
end.should_not store_message
|
134
134
|
end
|
135
|
-
|
135
|
+
|
136
136
|
it 'should not forward mail to inactive list and notify manager list' do
|
137
137
|
tmail = tmail_fixture('single_list')
|
138
138
|
mock(@list_one).active? { false }
|
@@ -140,26 +140,26 @@ describe MList do
|
|
140
140
|
mock(@list_one).inactive_post(is_a(MList::Email))
|
141
141
|
@email_server.should_not forward_email(tmail)
|
142
142
|
end
|
143
|
-
|
143
|
+
|
144
144
|
it 'should report unrecognized email to list manager' do
|
145
145
|
tmail = tmail_fixture('single_list')
|
146
146
|
stub(@list_manager).lists(is_a(MList::Email)) { [] }
|
147
147
|
mock(@list_manager).no_lists_found(is_a(MList::Email))
|
148
148
|
@email_server.should_not forward_email(tmail)
|
149
149
|
end
|
150
|
-
|
150
|
+
|
151
151
|
it 'should report bounces to the list manager' do
|
152
152
|
stub(@list_manager).lists(is_a(MList::Email)) { [@list_one] }
|
153
153
|
mock(@list_one).bounce(is_a(MList::Email))
|
154
154
|
@email_server.should_not forward_email(tmail_fixture('bounces/1'))
|
155
155
|
end
|
156
|
-
|
156
|
+
|
157
157
|
describe 'single list' do
|
158
158
|
before do
|
159
159
|
@tmail_post = tmail_fixture('single_list')
|
160
160
|
@email_server.receive(@tmail_post)
|
161
161
|
end
|
162
|
-
|
162
|
+
|
163
163
|
it 'should forward emails that are sent to a mailing list' do
|
164
164
|
@email_server.deliveries.size.should == 1
|
165
165
|
email = @email_server.deliveries.first
|
@@ -167,12 +167,12 @@ describe MList do
|
|
167
167
|
# bcc fields are not in the headers of delivered emails
|
168
168
|
email.should have_address(:'reply-to', 'list_one@example.com')
|
169
169
|
end
|
170
|
-
|
170
|
+
|
171
171
|
it 'should start a new thread for a new email' do
|
172
172
|
thread = MList::Thread.last
|
173
173
|
thread.messages.first.email.tmail.should equal_tmail(@tmail_post)
|
174
174
|
end
|
175
|
-
|
175
|
+
|
176
176
|
it 'should add to an existing thread when reply email' do
|
177
177
|
message = MList::Message.last
|
178
178
|
reply_tmail = tmail_fixture('single_list_reply', 'in-reply-to' => "<#{message.identifier}>")
|
@@ -180,7 +180,7 @@ describe MList do
|
|
180
180
|
thread = MList::Thread.last
|
181
181
|
thread.messages.size.should be(2)
|
182
182
|
end
|
183
|
-
|
183
|
+
|
184
184
|
it 'should associate parent message when reply email' do
|
185
185
|
message = MList::Message.last
|
186
186
|
@email_server.receive(tmail_fixture('single_list_reply', 'in-reply-to' => "<#{message.identifier}>"))
|
@@ -188,46 +188,46 @@ describe MList do
|
|
188
188
|
reply.parent_identifier.should == message.identifier
|
189
189
|
reply.parent.should == message
|
190
190
|
end
|
191
|
-
|
191
|
+
|
192
192
|
it 'should not associate a parent when not a reply' do
|
193
193
|
tmail = tmail_fixture('single_list')
|
194
194
|
tmail['message-id'] = 'asdfasdfj'
|
195
195
|
tmail['subject'] = 'other thing'
|
196
196
|
@email_server.should start_new_thread(tmail)
|
197
197
|
end
|
198
|
-
|
198
|
+
|
199
199
|
it 'should store subscriber address with messages' do
|
200
200
|
MList::Message.last.subscriber_address.should == 'adam@nomail.net'
|
201
201
|
end
|
202
|
-
|
202
|
+
|
203
203
|
it 'should associate subscriber to messages when they are ActiveRecord instances' do
|
204
|
-
MList::Message.last.subscriber.should == MList::Manager::Database::Subscriber.
|
204
|
+
MList::Message.last.subscriber.should == MList::Manager::Database::Subscriber.find_by_rfc5322_email('adam@nomail.net')
|
205
205
|
end
|
206
206
|
end
|
207
|
-
|
207
|
+
|
208
208
|
describe 'multiple lists' do
|
209
209
|
before do
|
210
210
|
@tmail_post = tmail_fixture('multiple_lists')
|
211
211
|
@email_server.receive(@tmail_post)
|
212
212
|
end
|
213
|
-
|
213
|
+
|
214
214
|
it 'should forward emails that are sent to a mailing list' do
|
215
215
|
@email_server.deliveries.size.should == 2
|
216
|
-
|
216
|
+
|
217
217
|
email = @email_server.deliveries.first
|
218
218
|
email.should have_address(:to, 'list_one@example.com')
|
219
219
|
# bcc fields are not in the headers of delivered emails
|
220
220
|
email.should have_address(:'reply-to', 'list_one@example.com')
|
221
|
-
|
221
|
+
|
222
222
|
email = @email_server.deliveries.last
|
223
223
|
email.should have_address(:to, 'list_two@example.com')
|
224
224
|
# bcc fields are not in the headers of delivered emails
|
225
225
|
email.should have_address(:'reply-to', 'list_two@example.com')
|
226
226
|
end
|
227
|
-
|
227
|
+
|
228
228
|
it 'should start a new thread for each list, both referencing the same email' do
|
229
229
|
threads = MList::Thread.find(:all)
|
230
230
|
threads[0].messages.first.email.should == threads[1].messages.first.email
|
231
231
|
end
|
232
232
|
end
|
233
|
-
end
|
233
|
+
end
|
@@ -122,7 +122,7 @@ describe MList::MailList do
|
|
122
122
|
:copy_sender => true)
|
123
123
|
|
124
124
|
tmail = @outgoing_server.deliveries.last
|
125
|
-
tmail.bcc.should include(@subscriber_one.
|
125
|
+
tmail.bcc.should include(@subscriber_one.rfc5322_email)
|
126
126
|
end
|
127
127
|
|
128
128
|
it 'should not copy the subscriber if undesired and list includes the subscriber' do
|
@@ -136,7 +136,7 @@ describe MList::MailList do
|
|
136
136
|
:copy_sender => false)
|
137
137
|
|
138
138
|
tmail = @outgoing_server.deliveries.last
|
139
|
-
tmail.bcc.should_not include(@subscriber_one.
|
139
|
+
tmail.bcc.should_not include(@subscriber_one.rfc5322_email)
|
140
140
|
end
|
141
141
|
end
|
142
142
|
|
metadata
CHANGED
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
|
|
5
5
|
segments:
|
6
6
|
- 0
|
7
7
|
- 1
|
8
|
-
-
|
9
|
-
version: 0.1.
|
8
|
+
- 19
|
9
|
+
version: 0.1.19
|
10
10
|
platform: ruby
|
11
11
|
authors:
|
12
12
|
- Adam Williams
|
@@ -14,7 +14,7 @@ autorequire:
|
|
14
14
|
bindir: bin
|
15
15
|
cert_chain: []
|
16
16
|
|
17
|
-
date: 2010-
|
17
|
+
date: 2010-08-12 00:00:00 -04:00
|
18
18
|
default_executable:
|
19
19
|
dependencies: []
|
20
20
|
|