mailboxer 0.10.3 → 0.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.travis.yml +6 -5
- data/Appraisals +19 -0
- data/LICENSE.txt +1 -0
- data/README.md +45 -26
- data/Rakefile +4 -0
- data/app/mailers/message_mailer.rb +4 -4
- data/app/models/conversation.rb +114 -91
- data/app/models/mailbox.rb +16 -15
- data/app/models/message.rb +24 -22
- data/app/models/notification.rb +37 -24
- data/app/models/receipt.rb +37 -15
- data/gemfiles/rails3.0.gemfile +8 -0
- data/gemfiles/rails3.1.gemfile +8 -0
- data/gemfiles/rails3.2.gemfile +8 -0
- data/gemfiles/rails4.0.gemfile +8 -0
- data/lib/mailboxer.rb +13 -7
- data/lib/mailboxer/engine.rb +1 -2
- data/lib/mailboxer/models/messageable.rb +44 -22
- data/mailboxer.gemspec +9 -4
- data/spec/dummy/config/environments/test.rb +1 -3
- data/spec/mailers/message_mailer_spec.rb +69 -70
- data/spec/models/conversation_spec.rb +22 -0
- data/spec/models/mailbox_spec.rb +36 -0
- data/spec/models/mailboxer_models_messageable_spec.rb +8 -5
- data/spec/models/message_spec.rb +6 -0
- data/spec/models/receipt_spec.rb +13 -1
- metadata +25 -5
data/lib/mailboxer.rb
CHANGED
@@ -1,12 +1,14 @@
|
|
1
|
-
module Mailboxer
|
1
|
+
module Mailboxer
|
2
2
|
module Models
|
3
3
|
autoload :Messageable, 'mailboxer/models/messageable'
|
4
|
-
end
|
5
|
-
|
4
|
+
end
|
5
|
+
|
6
6
|
mattr_accessor :default_from
|
7
7
|
@@default_from = "no-reply@mailboxer.com"
|
8
8
|
mattr_accessor :uses_emails
|
9
9
|
@@uses_emails = true
|
10
|
+
mattr_accessor :mailer_wants_array
|
11
|
+
@@mailer_wants_array = false
|
10
12
|
mattr_accessor :search_enabled
|
11
13
|
@@search_enabled = false
|
12
14
|
mattr_accessor :search_engine
|
@@ -18,14 +20,18 @@ module Mailboxer
|
|
18
20
|
mattr_accessor :notification_mailer
|
19
21
|
mattr_accessor :message_mailer
|
20
22
|
|
21
|
-
|
23
|
+
class << self
|
22
24
|
def setup
|
23
25
|
yield self
|
24
26
|
end
|
25
|
-
|
26
|
-
|
27
|
+
|
28
|
+
def protected_attributes?
|
29
|
+
Rails.version < '4' || defined?(ProtectedAttributes)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
27
33
|
end
|
28
34
|
# reopen ActiveRecord and include all the above to make
|
29
35
|
# them available to all our models if they want it
|
30
|
-
require 'mailboxer/engine'
|
36
|
+
require 'mailboxer/engine'
|
31
37
|
require 'mailboxer/concerns/configurable_mailer'
|
data/lib/mailboxer/engine.rb
CHANGED
@@ -1,14 +1,13 @@
|
|
1
1
|
# Database foreign keys
|
2
2
|
require 'foreigner'
|
3
3
|
require 'carrierwave'
|
4
|
-
begin
|
4
|
+
begin
|
5
5
|
require 'sunspot_rails'
|
6
6
|
rescue LoadError
|
7
7
|
end
|
8
8
|
|
9
9
|
module Mailboxer
|
10
10
|
class Engine < Rails::Engine
|
11
|
-
|
12
11
|
initializer "mailboxer.models.messageable" do
|
13
12
|
ActiveSupport.on_load(:active_record) do
|
14
13
|
extend Mailboxer::Models::Messageable::ActiveRecord
|
@@ -13,7 +13,12 @@ module Mailboxer
|
|
13
13
|
|
14
14
|
included do
|
15
15
|
has_many :messages, :as => :sender
|
16
|
-
|
16
|
+
if Rails::VERSION::MAJOR == 4
|
17
|
+
has_many :receipts, -> { order 'created_at DESC' }, dependent: :destroy, as: :receiver
|
18
|
+
else
|
19
|
+
# Rails 3 does it this way
|
20
|
+
has_many :receipts, :order => 'created_at DESC', :dependent => :destroy, :as => :receiver
|
21
|
+
end
|
17
22
|
end
|
18
23
|
|
19
24
|
unless defined?(Mailboxer.name_method)
|
@@ -28,8 +33,8 @@ module Mailboxer
|
|
28
33
|
end
|
29
34
|
|
30
35
|
unless defined?(Mailboxer.email_method)
|
31
|
-
|
32
|
-
|
36
|
+
#Returning the email address of the model if an email should be sent for this object (Message or Notification).
|
37
|
+
#If no mail has to be sent, return nil.
|
33
38
|
define_method Mailboxer.email_method do |object|
|
34
39
|
begin
|
35
40
|
super
|
@@ -43,12 +48,12 @@ module Mailboxer
|
|
43
48
|
def mailbox
|
44
49
|
@mailbox = Mailbox.new(self) if @mailbox.nil?
|
45
50
|
@mailbox.type = :all
|
46
|
-
|
51
|
+
@mailbox
|
47
52
|
end
|
48
53
|
|
49
54
|
#Sends a notification to the messageable
|
50
55
|
def notify(subject,body,obj = nil,sanitize_text=true,notification_code=nil,send_mail=true)
|
51
|
-
|
56
|
+
Notification.notify_all([self],subject,body,obj,sanitize_text,notification_code,send_mail)
|
52
57
|
end
|
53
58
|
|
54
59
|
#Sends a messages, starting a new conversation, with the messageable
|
@@ -63,7 +68,7 @@ module Mailboxer
|
|
63
68
|
message.conversation = convo
|
64
69
|
message.recipients = recipients.is_a?(Array) ? recipients : [recipients]
|
65
70
|
message.recipients = message.recipients.uniq
|
66
|
-
|
71
|
+
message.deliver false, sanitize_text
|
67
72
|
end
|
68
73
|
|
69
74
|
#Basic reply method. USE NOT RECOMENDED.
|
@@ -75,17 +80,17 @@ module Mailboxer
|
|
75
80
|
response.recipients = recipients.is_a?(Array) ? recipients : [recipients]
|
76
81
|
response.recipients = response.recipients.uniq
|
77
82
|
response.recipients.delete(self)
|
78
|
-
|
83
|
+
response.deliver true, sanitize_text
|
79
84
|
end
|
80
85
|
|
81
86
|
#Replies to the sender of the message in the conversation
|
82
87
|
def reply_to_sender(receipt, reply_body, subject=nil, sanitize_text=true, attachment=nil)
|
83
|
-
|
88
|
+
reply(receipt.conversation, receipt.message.sender, reply_body, subject, sanitize_text, attachment)
|
84
89
|
end
|
85
90
|
|
86
91
|
#Replies to all the recipients of the message in the conversation
|
87
92
|
def reply_to_all(receipt, reply_body, subject=nil, sanitize_text=true, attachment=nil)
|
88
|
-
|
93
|
+
reply(receipt.conversation, receipt.message.recipients, reply_body, subject, sanitize_text, attachment)
|
89
94
|
end
|
90
95
|
|
91
96
|
#Replies to all the recipients of the last message in the conversation and untrash any trashed message by messageable
|
@@ -94,8 +99,10 @@ module Mailboxer
|
|
94
99
|
#move conversation to inbox if it is currently in the trash and should_untrash parameter is true.
|
95
100
|
if should_untrash && mailbox.is_trashed?(conversation)
|
96
101
|
mailbox.receipts_for(conversation).untrash
|
102
|
+
mailbox.receipts_for(conversation).mark_as_not_deleted
|
97
103
|
end
|
98
|
-
|
104
|
+
|
105
|
+
reply(conversation, conversation.last_message.recipients, reply_body, subject, sanitize_text, attachment)
|
99
106
|
end
|
100
107
|
|
101
108
|
#Mark the object as read for messageable.
|
@@ -109,15 +116,13 @@ module Mailboxer
|
|
109
116
|
def mark_as_read(obj)
|
110
117
|
case obj
|
111
118
|
when Receipt
|
112
|
-
|
119
|
+
obj.mark_as_read if obj.receiver == self
|
113
120
|
when Message, Notification
|
114
121
|
obj.mark_as_read(self)
|
115
122
|
when Conversation
|
116
123
|
obj.mark_as_read(self)
|
117
124
|
when Array
|
118
125
|
obj.map{ |sub_obj| mark_as_read(sub_obj) }
|
119
|
-
else
|
120
|
-
return nil
|
121
126
|
end
|
122
127
|
end
|
123
128
|
|
@@ -132,15 +137,36 @@ module Mailboxer
|
|
132
137
|
def mark_as_unread(obj)
|
133
138
|
case obj
|
134
139
|
when Receipt
|
135
|
-
|
140
|
+
obj.mark_as_unread if obj.receiver == self
|
136
141
|
when Message, Notification
|
137
142
|
obj.mark_as_unread(self)
|
138
143
|
when Conversation
|
139
144
|
obj.mark_as_unread(self)
|
140
145
|
when Array
|
141
146
|
obj.map{ |sub_obj| mark_as_unread(sub_obj) }
|
142
|
-
|
143
|
-
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
#Mark the object as deleted for messageable.
|
151
|
+
#
|
152
|
+
#Object can be:
|
153
|
+
#* A Receipt
|
154
|
+
#* A Notification
|
155
|
+
#* A Message
|
156
|
+
#* A Conversation
|
157
|
+
#* An array with any of them
|
158
|
+
def mark_as_deleted(obj)
|
159
|
+
case obj
|
160
|
+
when Receipt
|
161
|
+
return obj.mark_as_deleted if obj.receiver == self
|
162
|
+
when Message, Notification
|
163
|
+
obj.mark_as_deleted(self)
|
164
|
+
when Conversation
|
165
|
+
obj.mark_as_deleted(self)
|
166
|
+
when Array
|
167
|
+
obj.map{ |sub_obj| mark_as_deleted(sub_obj) }
|
168
|
+
else
|
169
|
+
return nil
|
144
170
|
end
|
145
171
|
end
|
146
172
|
|
@@ -155,15 +181,13 @@ module Mailboxer
|
|
155
181
|
def trash(obj)
|
156
182
|
case obj
|
157
183
|
when Receipt
|
158
|
-
|
184
|
+
obj.move_to_trash if obj.receiver == self
|
159
185
|
when Message, Notification
|
160
186
|
obj.move_to_trash(self)
|
161
187
|
when Conversation
|
162
188
|
obj.move_to_trash(self)
|
163
189
|
when Array
|
164
190
|
obj.map{ |sub_obj| trash(sub_obj) }
|
165
|
-
else
|
166
|
-
return nil
|
167
191
|
end
|
168
192
|
end
|
169
193
|
|
@@ -178,15 +202,13 @@ module Mailboxer
|
|
178
202
|
def untrash(obj)
|
179
203
|
case obj
|
180
204
|
when Receipt
|
181
|
-
|
205
|
+
obj.untrash if obj.receiver == self
|
182
206
|
when Message, Notification
|
183
207
|
obj.untrash(self)
|
184
208
|
when Conversation
|
185
209
|
obj.untrash(self)
|
186
210
|
when Array
|
187
211
|
obj.map{ |sub_obj| untrash(sub_obj) }
|
188
|
-
else
|
189
|
-
return nil
|
190
212
|
end
|
191
213
|
end
|
192
214
|
|
data/mailboxer.gemspec
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
Gem::Specification.new do |s|
|
2
2
|
s.name = "mailboxer"
|
3
|
-
s.version = "0.
|
3
|
+
s.version = "0.11.0"
|
4
4
|
s.authors = ["Eduardo Casanova Cuesta"]
|
5
5
|
s.summary = "Messaging system for rails apps."
|
6
6
|
s.description = "A Rails engine that allows any model to act as messageable, adding the ability to exchange messages " +
|
@@ -11,6 +11,7 @@ Gem::Specification.new do |s|
|
|
11
11
|
s.email = "ecasanovac@gmail.com"
|
12
12
|
s.homepage = "https://github.com/ging/mailboxer"
|
13
13
|
s.files = `git ls-files`.split("\n")
|
14
|
+
s.license = 'MIT'
|
14
15
|
|
15
16
|
# Gem dependencies
|
16
17
|
#
|
@@ -26,6 +27,7 @@ Gem::Specification.new do |s|
|
|
26
27
|
end
|
27
28
|
# Specs
|
28
29
|
s.add_development_dependency('rspec-rails', '>= 2.6.1')
|
30
|
+
s.add_development_dependency("appraisal")
|
29
31
|
# Fixtures
|
30
32
|
#if RUBY_VERSION >= '1.9.2'
|
31
33
|
# s.add_development_dependency('factory_girl', '>= 3.0.0')
|
@@ -38,7 +40,10 @@ Gem::Specification.new do |s|
|
|
38
40
|
# Integration testing
|
39
41
|
s.add_development_dependency('capybara', '>= 0.3.9')
|
40
42
|
# Testing database
|
41
|
-
|
42
|
-
|
43
|
-
|
43
|
+
if RUBY_PLATFORM == 'java'
|
44
|
+
s.add_development_dependency('jdbc-sqlite3')
|
45
|
+
s.add_development_dependency('activerecord-jdbcsqlite3-adapter', '1.3.0.rc1')
|
46
|
+
else
|
47
|
+
s.add_development_dependency('sqlite3')
|
48
|
+
end
|
44
49
|
end
|
@@ -7,9 +7,7 @@ Dummy::Application.configure do
|
|
7
7
|
# and recreated between test runs. Don't rely on the data there!
|
8
8
|
config.cache_classes = true
|
9
9
|
|
10
|
-
|
11
|
-
config.whiny_nils = true
|
12
|
-
|
10
|
+
config.eager_load = false unless Rails::VERSION::MAJOR == 3
|
13
11
|
# Show full error reports and disable caching
|
14
12
|
config.consider_all_requests_local = true
|
15
13
|
config.action_controller.perform_caching = false
|
@@ -1,95 +1,94 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
3
|
describe MessageMailer do
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
@entity3 = FactoryGirl.create(:cylon)
|
10
|
-
@receipt1 = @sender.send_message([@entity1,@entity2,@entity3], "Body Body Body Body Body Body Body Body Body Body Body Body","Subject")
|
11
|
-
end
|
4
|
+
shared_examples 'message_mailer' do
|
5
|
+
let(:sender) { FactoryGirl.create(:user) }
|
6
|
+
let(:entity1) { FactoryGirl.create(:user) }
|
7
|
+
let(:entity2) { FactoryGirl.create(:duck) }
|
8
|
+
let(:entity3) { FactoryGirl.create(:cylon) }
|
12
9
|
|
13
|
-
|
14
|
-
ActionMailer::Base.deliveries.
|
15
|
-
|
10
|
+
def sent_to?(entity)
|
11
|
+
ActionMailer::Base.deliveries.any? do |email|
|
12
|
+
email.to.first.to_s == entity.email
|
13
|
+
end
|
16
14
|
end
|
17
15
|
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
16
|
+
describe "when sending new message" do
|
17
|
+
before do
|
18
|
+
@receipt1 = sender.send_message([entity1, entity2, entity3], "Body", "Subject")
|
19
|
+
end
|
20
|
+
|
21
|
+
it "should send emails when should_email? is true (1 out of 3)" do
|
22
|
+
ActionMailer::Base.deliveries.should_not be_empty
|
23
|
+
ActionMailer::Base.deliveries.should have(1).item
|
24
|
+
end
|
25
|
+
|
26
|
+
it "should send an email to user entity" do
|
27
|
+
sent_to?(entity1).should be_true
|
24
28
|
end
|
25
|
-
temp.should==true
|
26
|
-
end
|
27
29
|
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
30
|
+
it "shouldn't send an email to duck entity" do
|
31
|
+
sent_to?(entity2).should be_false
|
32
|
+
end
|
33
|
+
|
34
|
+
it "shouldn't send an email to cylon entity" do
|
35
|
+
sent_to?(entity3).should be_false
|
34
36
|
end
|
35
|
-
temp.should==false
|
36
37
|
end
|
37
38
|
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
39
|
+
describe "when replying" do
|
40
|
+
before do
|
41
|
+
@receipt1 = sender.send_message([entity1, entity2, entity3], "Body", "Subject")
|
42
|
+
@receipt2 = sender.reply_to_all(@receipt1, "Body")
|
43
|
+
end
|
44
|
+
|
45
|
+
it "should send emails when should_email? is true (1 out of 3)" do
|
46
|
+
ActionMailer::Base.deliveries.should_not be_empty
|
47
|
+
ActionMailer::Base.deliveries.should have(2).items
|
48
|
+
end
|
49
|
+
|
50
|
+
it "should send an email to user entity" do
|
51
|
+
sent_to?(entity1).should be_true
|
52
|
+
end
|
53
|
+
|
54
|
+
it "shouldn't send an email to duck entity" do
|
55
|
+
sent_to?(entity2).should be_false
|
56
|
+
end
|
57
|
+
|
58
|
+
it "shouldn't send an email to cylon entity" do
|
59
|
+
sent_to?(entity3).should be_false
|
44
60
|
end
|
45
|
-
temp.should==false
|
46
61
|
end
|
47
62
|
end
|
48
63
|
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
@entity1 = FactoryGirl.create(:user)
|
53
|
-
@entity2 = FactoryGirl.create(:duck)
|
54
|
-
@entity3 = FactoryGirl.create(:cylon)
|
55
|
-
@receipt1 = @sender.send_message([@entity1,@entity2,@entity3], "Body","Subject")
|
56
|
-
@receipt2 = @sender.reply_to_all(@receipt1, "Body")
|
57
|
-
end
|
58
|
-
|
59
|
-
it "should send emails when should_email? is true (1 out of 3)" do
|
60
|
-
ActionMailer::Base.deliveries.empty?.should==false
|
61
|
-
ActionMailer::Base.deliveries.size.should==2
|
62
|
-
end
|
64
|
+
context "when mailer_wants_array is false" do
|
65
|
+
it_behaves_like 'message_mailer'
|
66
|
+
end
|
63
67
|
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
68
|
+
context "mailer_wants_array is true" do
|
69
|
+
class ArrayMailer < MessageMailer
|
70
|
+
default template_path: 'message_mailer'
|
71
|
+
|
72
|
+
def new_message_email(message, receivers)
|
73
|
+
receivers.each { |receiver| super(message, receiver) if receiver.mailboxer_email(message).present? }
|
70
74
|
end
|
71
|
-
temp.should==true
|
72
|
-
end
|
73
75
|
|
74
|
-
|
75
|
-
|
76
|
-
ActionMailer::Base.deliveries.each do |email|
|
77
|
-
if email.to.first.to_s.eql? @entity2.email
|
78
|
-
temp = true
|
79
|
-
end
|
76
|
+
def reply_message_email(message, receivers)
|
77
|
+
receivers.each { |receiver| super(message, receiver) if receiver.mailboxer_email(message).present? }
|
80
78
|
end
|
81
|
-
temp.should==false
|
82
79
|
end
|
83
80
|
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
if email.to.first.to_s.eql? @entity3.email
|
88
|
-
temp = true
|
89
|
-
end
|
90
|
-
end
|
91
|
-
temp.should==false
|
81
|
+
before :all do
|
82
|
+
Mailboxer.mailer_wants_array = true
|
83
|
+
Mailboxer.message_mailer = ArrayMailer
|
92
84
|
end
|
85
|
+
|
86
|
+
after :all do
|
87
|
+
Mailboxer.mailer_wants_array = false
|
88
|
+
Mailboxer.message_mailer = MessageMailer
|
89
|
+
end
|
90
|
+
|
91
|
+
it_behaves_like 'message_mailer'
|
93
92
|
end
|
94
93
|
end
|
95
94
|
|