acts-as-messageable 0.4.11 → 0.5.0

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