mailboxer 0.10.3 → 0.11.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
|