acts-as-messageable 0.4.11 → 0.5.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.
Files changed (56) hide show
  1. checksums.yaml +4 -4
  2. data/.dockerignore +1 -0
  3. data/.rubocop.yml +19 -0
  4. data/.rubocop_todo.yml +33 -0
  5. data/.travis.yml +40 -4
  6. data/Appraisals +24 -11
  7. data/Dockerfile +13 -0
  8. data/Gemfile +11 -4
  9. data/Gemfile.lock +94 -63
  10. data/README.md +30 -12
  11. data/Rakefile +4 -0
  12. data/VERSION +1 -1
  13. data/acts-as-messageable.gemspec +62 -49
  14. data/docker-compose.yml +73 -0
  15. data/gemfiles/rails_3.2.gemfile +17 -10
  16. data/gemfiles/rails_4.2.gemfile +24 -0
  17. data/gemfiles/rails_5.2.gemfile +17 -10
  18. data/gemfiles/rails_6.0.gemfile +17 -10
  19. data/gemfiles/rails_master.gemfile +23 -0
  20. data/lib/acts-as-messageable.rb +2 -17
  21. data/lib/acts_as_messageable.rb +23 -0
  22. data/lib/{acts-as-messageable → acts_as_messageable}/message.rb +25 -8
  23. data/lib/{acts-as-messageable → acts_as_messageable}/model.rb +27 -30
  24. data/lib/{acts-as-messageable → acts_as_messageable}/rails3.rb +7 -5
  25. data/lib/{acts-as-messageable → acts_as_messageable}/rails4.rb +8 -4
  26. data/lib/acts_as_messageable/rails6.rb +31 -0
  27. data/lib/acts_as_messageable/railtie.rb +11 -0
  28. data/lib/{acts-as-messageable → acts_as_messageable}/relation.rb +4 -2
  29. data/lib/{acts-as-messageable → acts_as_messageable}/scopes.rb +16 -12
  30. data/lib/generators/{acts-as-messageable → acts_as_messageable}/migration/migration_generator.rb +16 -2
  31. data/lib/generators/{acts-as-messageable → acts_as_messageable}/migration/templates/migration.rb +3 -3
  32. data/lib/generators/acts_as_messageable/migration/templates/migration_indexes.rb +11 -0
  33. data/lib/generators/acts_as_messageable/migration/templates/migration_opened_as_datetime.rb +15 -0
  34. data/lib/generators/{acts-as-messageable → acts_as_messageable}/migration/templates/migration_permanent.rb +1 -1
  35. data/spec/{acts-as-messageable_spec.rb → acts_as_messageable_spec.rb} +77 -5
  36. data/spec/{custom-class_spec.rb → custom_class_spec.rb} +14 -5
  37. data/spec/{custom-required_spec.rb → custom_required_spec.rb} +3 -1
  38. data/spec/{group-messages_spec.rb → group_messages_spec.rb} +4 -2
  39. data/spec/migrations_spec.rb +75 -0
  40. data/spec/spec_helper.rb +30 -37
  41. data/spec/support/admin.rb +2 -0
  42. data/spec/support/custom_message.rb +5 -0
  43. data/spec/support/custom_message_uuid.rb +5 -0
  44. data/spec/support/custom_search_user.rb +5 -0
  45. data/spec/support/men.rb +6 -0
  46. data/spec/support/send_message.rb +2 -0
  47. data/spec/support/table_schema.rb +35 -0
  48. data/spec/support/user.rb +2 -3
  49. data/spec/support/uuid_user.rb +6 -0
  50. metadata +113 -31
  51. data/gemfiles/rails_3.2.gemfile.lock +0 -153
  52. data/gemfiles/rails_4.2.11.gemfile +0 -16
  53. data/gemfiles/rails_4.2.11.gemfile.lock +0 -157
  54. data/gemfiles/rails_5.2.gemfile.lock +0 -155
  55. data/gemfiles/rails_6.0.gemfile.lock +0 -155
  56. data/lib/acts-as-messageable/railtie.rb +0 -13
@@ -1,10 +1,10 @@
1
- class CreateMessagesTable < ActiveRecord::Migration
1
+ class CreateMessagesTable < ActiveRecord::Migration[4.2]
2
2
  def self.up
3
3
  create_table :<%= table_name %> do |t|
4
4
  t.string :topic
5
5
  t.text :body
6
- t.references :received_messageable, :polymorphic => true
7
- t.references :sent_messageable, :polymorphic => true
6
+ t.references :received_messageable, :polymorphic => true, :type => :<%= options[:uuid] ? 'uuid' : 'bigint' %>
7
+ t.references :sent_messageable, :polymorphic => true, :type => :<%= options[:uuid] ? 'uuid' : 'bigint' %>
8
8
  t.boolean :opened, :default => false
9
9
  t.boolean :recipient_delete, :default => false
10
10
  t.boolean :sender_delete, :default => false
@@ -0,0 +1,11 @@
1
+ class AddIndexesToMessages < ActiveRecord::Migration[4.2]
2
+ def self.up
3
+ add_index :<%= table_name %>, [:sent_messageable_id, :sent_messageable_type], :name => "acts_as_messageable_sent"
4
+ add_index :<%= table_name %>, [:received_messageable_id, :received_messageable_type], :name => "acts_as_messageable_received"
5
+ end
6
+
7
+ def self.down
8
+ remove_index :<%= table_name %>, :name => "acts_as_messageable_sent"
9
+ remove_index :<%= table_name %>, :name => "acts_as_messageable_received"
10
+ end
11
+ end
@@ -0,0 +1,15 @@
1
+ class AddOpenedAtToMessages < ActiveRecord::Migration[4.2]
2
+ class MigrationMessage < ActiveRecord::Base
3
+ self.table_name = :<%= table_name %>
4
+ end
5
+
6
+ def self.up
7
+ add_column :<%= table_name %>, :opened_at, :datetime
8
+ MigrationMessage.where(opened: true).update_all(opened_at: DateTime.now)
9
+ end
10
+
11
+ def self.down
12
+ MigrationMessage.where('opened_at is not null').update_all(opened: true)
13
+ remove_column :<%= table_name %>, :opened_at
14
+ end
15
+ end
@@ -1,4 +1,4 @@
1
- class AddRecipientPermanentDeleteAndSenderPermanentDeleteToMessages < ActiveRecord::Migration
1
+ class AddRecipientPermanentDeleteAndSenderPermanentDeleteToMessages < ActiveRecord::Migration[4.2]
2
2
  def self.up
3
3
  add_column :<%= table_name %>, :recipient_permanent_delete, :boolean, :default => false
4
4
  add_column :<%= table_name %>, :sender_permanent_delete, :boolean, :default => false
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'spec_helper'
2
4
 
3
5
  describe 'ActsAsMessageable' do
@@ -70,14 +72,14 @@ describe 'ActsAsMessageable' do
70
72
  end
71
73
 
72
74
  it 'alice should be able to reply to a message from bob to alice' do
73
- @reply_message = @alice.reply_to(@message, 'Re: Topic', 'Body')
75
+ @reply_message = @alice.reply_to(@message, 'Re: Topic', 'Body')
74
76
  expect(@reply_message).not_to be_nil
75
77
  expect(@bob.messages.are_from(@alice).count).to eq(1)
76
78
  expect(@alice.sent_messages.are_to(@bob).count).to eq(1)
77
79
  end
78
80
 
79
81
  it 'alice should be able to reply to a message using the message object' do
80
- @reply_message = @message.reply('Re: Topic', 'Body')
82
+ @reply_message = @message.reply('Re: Topic', 'Body')
81
83
  expect(@reply_message).not_to be_nil
82
84
  expect(@bob.messages.are_from(@alice).count).to eq(1)
83
85
  expect(@alice.sent_messages.are_to(@bob).count).to eq(1)
@@ -85,13 +87,13 @@ describe 'ActsAsMessageable' do
85
87
 
86
88
  it 'bob try to add something to conversation' do
87
89
  @reply_message = @bob.reply_to(@message, 'Oh, I Forget', '1+1=2')
88
- expect(@reply_message.from).to eq(@message.from)
89
- expect(@reply_message.to).to eq(@message.to)
90
+ expect(@reply_message.from).to eq(@message.from)
91
+ expect(@reply_message.to).to eq(@message.to)
90
92
  end
91
93
 
92
94
  it 'bob try to add something to conversation and should receive proper order' do
93
95
  @reply_message = @bob.reply_to(@message, 'Oh, I Forget', '1+1=2')
94
- @sec_message = @alice.reply_to(@message, 'Yeah, right', '1+1=3!')
96
+ @sec_message = @alice.reply_to(@message, 'Yeah, right', '1+1=3!')
95
97
 
96
98
  expect(@message.conversation).to eq([@sec_message, @reply_message, @message])
97
99
  end
@@ -148,6 +150,12 @@ describe 'ActsAsMessageable' do
148
150
  expect(@alice.received_messages.count).to eq(1)
149
151
  end
150
152
 
153
+ it 'bob should be able to restore message' do
154
+ @bob.sent_messages.process(&:delete)
155
+ @bob.restore_message(@message.reload)
156
+ expect(@bob.sent_messages.count).to eq(1)
157
+ end
158
+
151
159
  it 'should works with relation' do
152
160
  @alice.received_messages.process(&:delete)
153
161
  expect(@alice.received_messages.count).to eq(0)
@@ -164,6 +172,7 @@ describe 'ActsAsMessageable' do
164
172
  it 'alice should have one unread message from bob' do
165
173
  expect(@alice.messages.are_from(@bob).unreaded.count).to eq(1)
166
174
  expect(@alice.messages.are_from(@bob).readed.count).to eq(0)
175
+ expect(@alice.messages.are_from(@bob).readed.all?(&:open?)).to be_truthy
167
176
  end
168
177
 
169
178
  it 'alice should able to read message from bob' do
@@ -177,11 +186,33 @@ describe 'ActsAsMessageable' do
177
186
  expect(@alice.messages.are_from(@bob).unreaded.count).to eq(1)
178
187
  end
179
188
 
189
+ it 'alice should see the read_at updated' do
190
+ date_time_when_read = Time.new(2014, 9, 4, 15, 12, 34)
191
+ Timecop.freeze(date_time_when_read) do
192
+ @alice.messages.are_from(@bob).first.read
193
+ first_message = @alice.messages.are_from(@bob).first
194
+ expect(first_message.opened_at).to eql(date_time_when_read)
195
+ end
196
+ end
197
+
180
198
  it 'alice should able to get datetime when he read bob message' do
181
199
  @alice.messages.are_from(@bob).first.read
182
200
  read_datetime = @alice.messages.are_from(@bob).first.updated_at
183
201
  expect(@alice.messages.are_from(@bob).reorder('updated_at asc').first.updated_at).to eq(read_datetime)
184
202
  end
203
+
204
+ describe '#open?' do
205
+ let(:message) { @alice.messages.are_from(@bob).first }
206
+
207
+ it 'returns false for closed message' do
208
+ expect(message.open?).to be_falsey
209
+ end
210
+
211
+ it 'returns true for open message' do
212
+ message.read
213
+ expect(message.open?).to be_truthy
214
+ end
215
+ end
185
216
  end
186
217
 
187
218
  it 'finds proper message' do
@@ -268,6 +299,10 @@ describe 'ActsAsMessageable' do
268
299
  expect(@bob.sent_messages.loaded?).to be_falsey
269
300
  end
270
301
 
302
+ it 'sent_messages should return unloaded messages' do
303
+ expect(@bob.sent_messages.loaded?).to be_falsey
304
+ end
305
+
271
306
  describe 'send messages between two different models (the same id)' do
272
307
  it 'should have the same id' do
273
308
  expect(@alice.id).to be_equal(@admin.id)
@@ -285,4 +320,41 @@ describe 'ActsAsMessageable' do
285
320
  expect(@bob.messages.are_from(@alice).size).to be_equal(0)
286
321
  end
287
322
  end
323
+
324
+ describe 'mass assigment', rails: 4 do
325
+ it 'allows to mass assign topic and body attributes' do
326
+ @message = send_message(@bob, @alice, 'Example', 'Example Body')
327
+ @message.update_attributes!(topic: 'Changed topic', body: 'Changed body')
328
+
329
+ expect(@message.topic).to eq('Changed topic')
330
+ expect(@message.body).to eq('Changed body')
331
+ end
332
+ end
333
+
334
+ describe 'ancestry initialization' do # GH#78
335
+ let(:message) { ActsAsMessageable::Message.create!(topic: 'topic', body: 'body') }
336
+
337
+ before do
338
+ # Use clean version of Message class
339
+ ActsAsMessageable.instance_eval { remove_const 'Message' }
340
+ load 'acts_as_messageable/message.rb'
341
+ end
342
+
343
+ it 'returns root of the conversation' do
344
+ expect(message.conversation).to include(message)
345
+ end
346
+ end
347
+
348
+ describe 'user primary key is uuid type', rails: [5, 6] do # GH#107
349
+ let(:bob) { UuidUser.create(id: SecureRandom.uuid, email: 'bob@example.com') }
350
+ let(:alice) { UuidUser.create(id: SecureRandom.uuid, email: 'alice@example.com') }
351
+
352
+ before do
353
+ bob.send_message(alice, 'Subject', 'Body')
354
+ end
355
+
356
+ it 'returns messages for alice' do
357
+ expect(alice.messages).not_to be_empty
358
+ end
359
+ end
288
360
  end
@@ -1,12 +1,11 @@
1
- require 'spec_helper'
1
+ # frozen_string_literal: true
2
2
 
3
- class CustomMessage < ActsAsMessageable::Message
4
- def custom_method; end
5
- end
3
+ require 'spec_helper'
6
4
 
7
5
  describe 'custom class' do
8
6
  let(:alice) { User.find_by_email('alice@example.com') }
9
- let(:bob) { User.find_by_email('bob@example.com') }
7
+ let(:bob) { User.find_by_email('bob@example.com') }
8
+ let(:custom_user) { CustomSearchUser.find_by_email('custom@example.com') }
10
9
 
11
10
  before do
12
11
  User.acts_as_messageable class_name: 'CustomMessage', table_name: 'custom_messages'
@@ -36,4 +35,14 @@ describe 'custom class' do
36
35
  expect(@reply_message.root).to eq(@message)
37
36
  expect(@reply_message.root.class).to eq(CustomMessage)
38
37
  end
38
+
39
+ context 'with custom search scope' do
40
+ before do
41
+ send_message(custom_user, bob, 'Test subject', 'Test body')
42
+ end
43
+
44
+ it 'will use custom search scope' do
45
+ expect(custom_user.messages.custom_search('Test body').count).to eq(1)
46
+ end
47
+ end
39
48
  end
@@ -1,10 +1,12 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'spec_helper'
2
4
 
3
5
  describe 'custom require' do
4
6
  before(:each) do
5
7
  # Use clean version of Message class
6
8
  ActsAsMessageable.instance_eval { remove_const 'Message' }
7
- load 'acts-as-messageable/message.rb'
9
+ load 'acts_as_messageable/message.rb'
8
10
  end
9
11
 
10
12
  it 'should work with non-array require' do
@@ -1,9 +1,11 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'spec_helper'
2
4
 
3
5
  describe 'group messages' do
4
6
  let(:alice) { User.find_by_email('alice@example.com') }
5
- let(:bob) { User.find_by_email('bob@example.com') }
6
- let(:pat) { User.find_by_email('pat@example.com') }
7
+ let(:bob) { User.find_by_email('bob@example.com') }
8
+ let(:pat) { User.find_by_email('pat@example.com') }
7
9
 
8
10
  before do
9
11
  User.acts_as_messageable group_messages: true
@@ -0,0 +1,75 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ def create_dummy_app
6
+ system <<-COMMAND
7
+ bundle exec rails new dummy --skip-test-unit --skip-spring --skip-webpack-install --skip-bootsnap \
8
+ --skip-active-storage --skip-active-job -d sqlite3
9
+ COMMAND
10
+ end
11
+
12
+ def add_gem_to_gemfile
13
+ run_in_app("echo gem \"'acts-as-messageable', path: '../'\" >> Gemfile; bundle")
14
+ end
15
+
16
+ def run_bundler
17
+ run_in_app('bundle update')
18
+ end
19
+
20
+ def run_generators(option = '')
21
+ run_in_app("bundle exec rails g acts_as_messageable:migration #{option}")
22
+ end
23
+
24
+ def run_migrations
25
+ run_in_app('bundle exec rake db:migrate')
26
+ end
27
+
28
+ def rollback_migrations
29
+ run_in_app('bundle exec rake db:migrate VERSION=0')
30
+ end
31
+
32
+ def run_in_app(command)
33
+ Bundler.clean_system("cd dummy; BUNDLE_GEMFILE=./Gemfile #{command}")
34
+ end
35
+
36
+ def remove_dummy_app
37
+ system 'rm -rf dummy'
38
+ end
39
+
40
+ def skip_generators?
41
+ ENV.fetch('RUN_GENERATORS', 'false') == 'false'
42
+ end
43
+
44
+ describe 'migration' do
45
+ before do
46
+ create_dummy_app
47
+ add_gem_to_gemfile
48
+ run_bundler
49
+ end
50
+
51
+ after do
52
+ remove_dummy_app
53
+ end
54
+
55
+ it 'runs migrations and revert them', skip: skip_generators? do
56
+ run_generators
57
+
58
+ expect(run_migrations).to be_truthy
59
+ expect(rollback_migrations).to be_truthy
60
+ end
61
+
62
+ it 'runs migrations and revert them with uuid option', skip: skip_generators? do
63
+ run_generators('--uuid')
64
+
65
+ expect(run_migrations).to be_truthy
66
+ expect(rollback_migrations).to be_truthy
67
+ end
68
+
69
+ it 'runs migrations and revert them with uuid option and custom table', skip: skip_generators? do
70
+ run_generators('my_messages --uuid')
71
+
72
+ expect(run_migrations).to be_truthy
73
+ expect(rollback_migrations).to be_truthy
74
+ end
75
+ end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
2
4
  $LOAD_PATH.unshift(File.dirname(__FILE__))
3
5
  require 'rspec'
@@ -8,25 +10,32 @@ ActiveRecord::Base.logger.level = 3
8
10
  require 'coveralls'
9
11
  Coveralls.wear!
10
12
 
13
+ require 'timecop'
14
+
11
15
  require 'bundler/setup'
12
16
  Bundler.require(:default)
13
17
 
18
+ require 'pry'
14
19
  require 'acts-as-messageable'
15
20
 
16
- Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each { |f| require f }
21
+ Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].sort.each { |f| require f }
17
22
 
18
23
  ActiveRecord::Migration.verbose = false
19
24
 
20
25
  RSpec.configure do |config|
21
26
  config.before(:all) do
22
- ActiveRecord::Base.establish_connection(adapter: 'sqlite3', database: ':memory:')
27
+ ActiveRecord::Base.establish_connection(
28
+ adapter: ENV.fetch('DATABASE_ADAPTER', 'sqlite3'),
29
+ database: ENV.fetch('DATABASE_NAME', ':memory:')
30
+ )
23
31
  create_database
24
32
 
25
- @alice = User.create email: 'alice@example.com'
26
- @bob = User.create email: 'bob@example.com'
27
- @pat = User.create email: 'pat@example.com'
33
+ @alice = User.create email: 'alice@example.com'
34
+ @bob = User.create email: 'bob@example.com'
35
+ @pat = User.create email: 'pat@example.com'
28
36
  @admin = Admin.create email: 'admin@example.com'
29
- @men = Men.create email: 'men@example.com'
37
+ @men = Men.create email: 'men@example.com'
38
+ @custom_search_user = CustomSearchUser.create email: 'custom@example.com'
30
39
  end
31
40
 
32
41
  config.after(:all) do
@@ -36,44 +45,28 @@ RSpec.configure do |config|
36
45
  config.after(:each) do
37
46
  User.messages_class_name.destroy_all
38
47
  end
48
+
49
+ config.around(:each) do |example|
50
+ supported_rails = Array.wrap(example.metadata[:rails]).presence || [3, 4, 5, 6]
51
+
52
+ example.run if supported_rails.include?(Rails::VERSION::MAJOR)
53
+ end
39
54
  end
40
55
 
41
56
  def create_database
42
57
  ActiveRecord::Schema.define(version: 1) do
43
- create_table :messages do |t|
44
- t.string :topic
45
- t.text :body
46
- t.references :received_messageable, polymorphic: true, index: false
47
- t.references :sent_messageable, polymorphic: true, index: false
48
- t.boolean :opened, default: false
49
- t.boolean :recipient_delete, default: false
50
- t.boolean :sender_delete, default: false
51
- t.boolean :recipient_permanent_delete, default: false
52
- t.boolean :sender_permanent_delete, default: false
53
- t.string :ancestry
54
- t.timestamps
58
+ if ENV.fetch('DATABASE_ADAPTER', '') == 'postgresql'
59
+ enable_extension 'pgcrypto' unless extension_enabled?('pgcrypto')
55
60
  end
56
61
 
57
- create_table :custom_messages do |t|
58
- t.string :topic
59
- t.text :body
60
- t.references :received_messageable, polymorphic: true, index: false
61
- t.references :sent_messageable, polymorphic: true, index: false
62
- t.boolean :opened, default: false
63
- t.boolean :recipient_delete, default: false
64
- t.boolean :sender_delete, default: false
65
- t.boolean :recipient_permanent_delete, default: false
66
- t.boolean :sender_permanent_delete, default: false
67
- t.string :ancestry
68
- t.timestamps
69
- end
70
- create_table :users do |t|
71
- t.string :email
72
- end
62
+ create_table(:messages, &TABLE_SCHEMA)
63
+ create_table(:custom_messages, &TABLE_SCHEMA)
64
+ create_table(:custom_messages_uuid, &TABLE_SCHEMA_UUID)
73
65
 
74
- create_table :admins do |t|
75
- t.string :email
76
- end
66
+ create_table(:users, &USER_SCHEMA)
67
+ create_table(:admins, &USER_SCHEMA)
68
+ create_table(:custom_search_users, &USER_SCHEMA)
69
+ create_table(:uuid_users, id: :uuid, &USER_SCHEMA)
77
70
  end
78
71
  end
79
72
 
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class Admin < ActiveRecord::Base
2
4
  acts_as_messageable
3
5
  end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ class CustomMessage < ActsAsMessageable::Message
4
+ def custom_method; end
5
+ end