message_train 0.7.6 → 1.0.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 (171) hide show
  1. checksums.yaml +5 -5
  2. data/.gitattributes +1 -0
  3. data/.github/workflows/ci.yml +86 -0
  4. data/.gitignore +64 -0
  5. data/.rubocop.yml +9 -0
  6. data/.rubocop_todo.yml +854 -2
  7. data/.ruby-version +1 -1
  8. data/.simplecov +2 -4
  9. data/CHANGELOG.md +128 -0
  10. data/CLAUDE.md +5 -0
  11. data/Gemfile +29 -31
  12. data/LICENSE.txt +1 -1
  13. data/README.md +106 -35
  14. data/Rakefile +4 -18
  15. data/app/assets/stylesheets/message_train.scss +405 -67
  16. data/app/controllers/concerns/message_train_support.rb +2 -2
  17. data/app/controllers/message_train/boxes_controller.rb +4 -2
  18. data/app/controllers/message_train/conversations_controller.rb +1 -0
  19. data/app/helpers/message_train/application_helper.rb +68 -0
  20. data/app/helpers/message_train/attachments_helper.rb +7 -4
  21. data/app/helpers/message_train/conversations_helper.rb +16 -16
  22. data/app/helpers/message_train/messages_helper.rb +23 -10
  23. data/app/javascript/controllers/message_train/bulk_actions_controller.js +36 -0
  24. data/app/javascript/controllers/message_train/lightbox_controller.js +25 -0
  25. data/app/javascript/controllers/message_train/nested_form_controller.js +36 -0
  26. data/app/javascript/controllers/message_train/recipient_autocomplete_controller.js +31 -0
  27. data/app/mailers/message_train/previews/receipt_mailer_preview.rb +7 -5
  28. data/app/models/message_train/attachment.rb +54 -42
  29. data/app/models/message_train/box.rb +2 -2
  30. data/app/models/message_train/conversation.rb +28 -2
  31. data/app/models/message_train/ignore.rb +2 -2
  32. data/app/models/message_train/message.rb +10 -4
  33. data/app/models/message_train/receipt.rb +27 -4
  34. data/app/models/message_train/unsubscribe.rb +1 -1
  35. data/app/views/application/404.html.haml +1 -3
  36. data/app/views/kaminari/_first_page.html.haml +1 -1
  37. data/app/views/kaminari/_last_page.html.haml +1 -1
  38. data/app/views/kaminari/_next_page.html.haml +1 -1
  39. data/app/views/kaminari/_page.html.haml +3 -3
  40. data/app/views/kaminari/_paginator.html.haml +12 -11
  41. data/app/views/kaminari/_prev_page.html.haml +1 -1
  42. data/app/views/message_train/application/_attachment_fields.html.haml +10 -7
  43. data/app/views/message_train/application/_attachment_link.html.haml +2 -2
  44. data/app/views/message_train/application/_widget.html.haml +2 -4
  45. data/app/views/message_train/boxes/_widget.html.haml +5 -5
  46. data/app/views/message_train/boxes/show.html.haml +28 -45
  47. data/app/views/message_train/collectives/_widget.html.haml +4 -4
  48. data/app/views/message_train/conversations/_conversation.html.haml +11 -11
  49. data/app/views/message_train/conversations/_deleted_toggle.html.haml +1 -1
  50. data/app/views/message_train/conversations/_ignored_toggle.html.haml +2 -2
  51. data/app/views/message_train/conversations/_read_toggle.html.haml +2 -2
  52. data/app/views/message_train/conversations/_toggle.html.haml +6 -4
  53. data/app/views/message_train/conversations/_trashed_toggle.html.haml +2 -2
  54. data/app/views/message_train/conversations/show.html.haml +8 -6
  55. data/app/views/message_train/messages/_deleted_toggle.html.haml +1 -1
  56. data/app/views/message_train/messages/_form.html.haml +22 -30
  57. data/app/views/message_train/messages/_message.html.haml +27 -45
  58. data/app/views/message_train/messages/_read_toggle.html.haml +2 -2
  59. data/app/views/message_train/messages/_toggle.html.haml +5 -1
  60. data/app/views/message_train/messages/_trashed_toggle.html.haml +2 -2
  61. data/app/views/message_train/unsubscribes/index.html.haml +12 -15
  62. data/badges/coverage.json +1 -0
  63. data/config/importmap.rb +2 -0
  64. data/config/locales/en.yml +6 -3
  65. data/db/migrate/20150721145319_create_message_train_conversations.rb +1 -1
  66. data/db/migrate/20150721160322_create_message_train_messages.rb +1 -1
  67. data/db/migrate/20150721161144_create_message_train_attachments.rb +5 -2
  68. data/db/migrate/20150721161940_create_message_train_receipts.rb +1 -1
  69. data/db/migrate/20150721163838_create_message_train_ignores.rb +1 -1
  70. data/db/migrate/20150901183458_add_received_through_to_message_train_receipts.rb +1 -1
  71. data/db/migrate/20151004184347_add_unique_index_to_receipts.rb +1 -1
  72. data/db/migrate/20151124000820_create_message_train_unsubscribes.rb +1 -1
  73. data/db/migrate/20260827095938_remove_paperclip_columns_from_message_train_attachments.rb +8 -0
  74. data/db/migrate/20260827171549_remove_body_from_message_train_messages.rb +5 -0
  75. data/db/migrate/20260827180000_add_marking_indexes.rb +9 -0
  76. data/db/migrate/20260827200000_add_body_back_to_message_train_messages.rb +5 -0
  77. data/docs/screenshots/inbox-desktop.png +0 -0
  78. data/docs/screenshots/inbox-mobile.png +0 -0
  79. data/lib/generators/message_train/install/install_generator.rb +1 -1
  80. data/lib/message_train/engine.rb +11 -0
  81. data/lib/message_train/instance_methods.rb +13 -7
  82. data/lib/message_train/localization.rb +4 -3
  83. data/lib/message_train/version.rb +1 -1
  84. data/lib/message_train.rb +0 -2
  85. data/message_train.gemspec +57 -389
  86. data/spec/controllers/message_train/boxes_controller_spec.rb +13 -8
  87. data/spec/controllers/message_train/concerns_spec.rb +2 -2
  88. data/spec/controllers/message_train/conversations_controller_spec.rb +36 -7
  89. data/spec/controllers/message_train/messages_controller_spec.rb +4 -4
  90. data/spec/dummy/app/assets/stylesheets/application.scss +141 -12
  91. data/spec/dummy/app/controllers/application_controller.rb +1 -1
  92. data/spec/dummy/app/javascript/application.js +4 -0
  93. data/spec/dummy/app/javascript/controllers/application.js +9 -0
  94. data/spec/dummy/app/javascript/controllers/index.js +4 -0
  95. data/spec/dummy/app/models/role.rb +1 -1
  96. data/spec/dummy/app/views/active_storage/blobs/_blob.html.erb +14 -0
  97. data/spec/dummy/app/views/layouts/_top_navigation.html.haml +18 -7
  98. data/spec/dummy/app/views/layouts/application.html.haml +22 -26
  99. data/spec/dummy/bin/importmap +4 -0
  100. data/spec/dummy/config/application.rb +7 -20
  101. data/spec/dummy/config/environments/development.rb +17 -21
  102. data/spec/dummy/config/environments/production.rb +11 -63
  103. data/spec/dummy/config/environments/test.rb +21 -16
  104. data/spec/dummy/config/importmap.rb +7 -0
  105. data/spec/dummy/config/initializers/assets.rb +1 -6
  106. data/spec/dummy/config/routes.rb +1 -1
  107. data/spec/dummy/config/storage.yml +7 -0
  108. data/spec/dummy/db/migrate/20150721140013_devise_create_users.rb +1 -1
  109. data/spec/dummy/db/migrate/20150721141009_rolify_create_roles.rb +1 -1
  110. data/spec/dummy/db/migrate/20150721141128_create_groups.rb +1 -1
  111. data/spec/dummy/db/migrate/20150721150307_add_display_name_column_to_users.rb +1 -1
  112. data/spec/dummy/db/migrate/20160207190402_create_message_train_conversations.message_train.rb +1 -1
  113. data/spec/dummy/db/migrate/20160207190403_create_message_train_messages.message_train.rb +1 -1
  114. data/spec/dummy/db/migrate/20160207190404_create_message_train_attachments.message_train.rb +5 -2
  115. data/spec/dummy/db/migrate/20160207190405_create_message_train_receipts.message_train.rb +1 -1
  116. data/spec/dummy/db/migrate/20160207190406_create_message_train_ignores.message_train.rb +1 -1
  117. data/spec/dummy/db/migrate/20160207190407_add_received_through_to_message_train_receipts.message_train.rb +1 -1
  118. data/spec/dummy/db/migrate/20160207190408_add_unique_index_to_receipts.message_train.rb +1 -1
  119. data/spec/dummy/db/migrate/20160207190409_create_message_train_unsubscribes.message_train.rb +1 -1
  120. data/spec/dummy/db/migrate/20260827095939_remove_paperclip_columns_from_message_train_attachments.message_train.rb +9 -0
  121. data/spec/dummy/db/migrate/20260827161141_create_active_storage_tables.active_storage.rb +57 -0
  122. data/spec/dummy/db/migrate/20260827171550_remove_body_from_message_train_messages.message_train.rb +6 -0
  123. data/spec/dummy/db/migrate/20260827225116_add_marking_indexes.message_train.rb +10 -0
  124. data/spec/dummy/db/migrate/20260828034830_add_body_back_to_message_train_messages.message_train.rb +6 -0
  125. data/spec/dummy/db/migrate/20260828040000_drop_action_text_tables.rb +5 -0
  126. data/spec/dummy/db/schema.rb +106 -72
  127. data/spec/dummy/db/seeds/conversations.seeds.rb +22 -22
  128. data/spec/dummy/db/seeds/development/conversations.seeds.rb +2 -2
  129. data/spec/dummy/db/seeds/groups.seeds.rb +4 -4
  130. data/spec/dummy/db/seeds/test/attachments.seeds.rb +4 -4
  131. data/spec/dummy/db/seeds/test/conversations.seeds.rb +2 -2
  132. data/spec/dummy/db/seeds/users.seeds.rb +8 -8
  133. data/spec/dummy/vendor/javascript/.keep +0 -0
  134. data/spec/factories/attachment.rb +5 -6
  135. data/spec/factories/group.rb +2 -2
  136. data/spec/factories/message.rb +7 -7
  137. data/spec/factories/user.rb +3 -3
  138. data/spec/features/boxes_spec.rb +38 -34
  139. data/spec/features/conversations_spec.rb +13 -6
  140. data/spec/features/messages_spec.rb +20 -20
  141. data/spec/features/unsubscribes_spec.rb +9 -9
  142. data/spec/helpers/message_train/application_helper_spec.rb +16 -18
  143. data/spec/helpers/message_train/attachment_helper_spec.rb +8 -18
  144. data/spec/helpers/message_train/boxes_helper_spec.rb +6 -6
  145. data/spec/helpers/message_train/collectives_helper_spec.rb +10 -10
  146. data/spec/helpers/message_train/conversations_helper_spec.rb +43 -85
  147. data/spec/helpers/message_train/messages_helper_spec.rb +41 -61
  148. data/spec/models/message_train/attachment_spec.rb +26 -36
  149. data/spec/models/message_train/box_spec.rb +2 -2
  150. data/spec/models/message_train/conversation_spec.rb +15 -0
  151. data/spec/models/message_train/message_spec.rb +5 -1
  152. data/spec/models/message_train/receipt_spec.rb +1 -1
  153. data/spec/models/message_train/unsubscribe_spec.rb +1 -1
  154. data/spec/rails_helper.rb +14 -13
  155. data/spec/support/controller_behaviors.rb +13 -13
  156. data/spec/support/factory_bot.rb +3 -0
  157. data/spec/support/feature_behaviors.rb +14 -14
  158. data/spec/support/loaded_site/attachments.rb +6 -2
  159. data/spec/support/utilities.rb +49 -20
  160. metadata +260 -213
  161. data/.travis.yml +0 -12
  162. data/VERSION +0 -1
  163. data/app/assets/javascripts/ckeditor/config.js +0 -49
  164. data/app/assets/javascripts/message_train.js +0 -149
  165. data/spec/dummy/app/assets/javascripts/application.js +0 -17
  166. data/spec/dummy/app/assets/stylesheets/bootstrap-everything.scss +0 -54
  167. data/spec/dummy/config/initializers/bootstrap_leather.rb +0 -7
  168. data/spec/dummy/config/initializers/paperclip.rb +0 -5
  169. data/spec/dummy/config/secrets.yml +0 -22
  170. data/spec/dummy/db/test.sqlite3 +0 -0
  171. data/spec/support/factory_girl.rb +0 -3
@@ -8,21 +8,21 @@ after :users, :groups do
8
8
  first_group = Group.find_by_slug('first-group')
9
9
  membered_group = Group.find_by_slug('membered-group')
10
10
 
11
- FactoryGirl.create(
11
+ FactoryBot.create(
12
12
  :simple_message,
13
13
  sender: first_user,
14
14
  recipients_to_save: { 'users' => second_user.slug },
15
15
  subject: 'Sent Conversation'
16
16
  )
17
17
 
18
- FactoryGirl.create(
18
+ FactoryBot.create(
19
19
  :simple_message,
20
20
  sender: second_user,
21
21
  recipients_to_save: { 'users' => first_user.slug },
22
22
  subject: 'Unread Conversation'
23
23
  )
24
24
 
25
- FactoryGirl.create(
25
+ FactoryBot.create(
26
26
  :simple_message,
27
27
  sender: first_user,
28
28
  recipients_to_save: {
@@ -35,28 +35,28 @@ after :users, :groups do
35
35
  subject: 'To Many Conversation'
36
36
  )
37
37
 
38
- FactoryGirl.create(
38
+ FactoryBot.create(
39
39
  :simple_message,
40
40
  sender: second_user,
41
41
  recipients_to_save: { 'users' => first_user.slug },
42
42
  subject: 'Ignored Conversation'
43
43
  ).conversation.participant_ignore(first_user)
44
44
 
45
- FactoryGirl.create(
45
+ FactoryBot.create(
46
46
  :simple_message,
47
47
  sender: second_user,
48
48
  recipients_to_save: { 'users' => first_user.slug },
49
49
  subject: 'Trashed Conversation'
50
50
  ).mark_trash_for(first_user)
51
51
 
52
- FactoryGirl.create(
52
+ FactoryBot.create(
53
53
  :simple_message,
54
54
  sender: second_user,
55
55
  recipients_to_save: { 'users' => first_user.slug },
56
56
  subject: 'Read Conversation'
57
57
  ).mark_read_for(first_user)
58
58
 
59
- FactoryGirl.create(
59
+ FactoryBot.create(
60
60
  :simple_message,
61
61
  sender: second_user,
62
62
  recipients_to_save: { 'users' => first_user.slug },
@@ -64,56 +64,56 @@ after :users, :groups do
64
64
  generate_attachment?: true
65
65
  )
66
66
 
67
- FactoryGirl.create(
67
+ FactoryBot.create(
68
68
  :simple_message,
69
69
  sender: second_user,
70
70
  recipients_to_save: { 'users' => first_user.slug },
71
71
  subject: 'Deleted Conversation'
72
72
  ).mark_deleted_for(first_user)
73
73
 
74
- FactoryGirl.create(
74
+ FactoryBot.create(
75
75
  :simple_message,
76
76
  sender: first_user,
77
77
  recipients_to_save: { 'groups' => first_group.slug },
78
78
  subject: 'Group Announcement'
79
79
  )
80
80
 
81
- FactoryGirl.create(
81
+ FactoryBot.create(
82
82
  :simple_message,
83
83
  sender: second_user,
84
84
  recipients_to_save: { 'groups' => membered_group.slug },
85
85
  subject: 'Membered Group Announcement'
86
86
  )
87
87
 
88
- FactoryGirl.create(
88
+ FactoryBot.create(
89
89
  :simple_message,
90
90
  sender: second_user,
91
91
  recipients_to_save: { 'groups' => membered_group.slug },
92
92
  subject: 'Membered Group Trashed Conversation'
93
93
  ).mark(:trash, first_user)
94
94
 
95
- FactoryGirl.create(
95
+ FactoryBot.create(
96
96
  :simple_message,
97
97
  sender: second_user,
98
98
  recipients_to_save: { 'groups' => membered_group.slug },
99
99
  subject: 'Membered Group Read Conversation'
100
100
  ).mark(:read, first_user)
101
101
 
102
- FactoryGirl.create(
102
+ FactoryBot.create(
103
103
  :simple_message,
104
104
  sender: second_user,
105
105
  recipients_to_save: { 'groups' => membered_group.slug },
106
106
  subject: 'Membered Group Ignored Conversation'
107
107
  ).conversation.participant_ignore(first_user)
108
108
 
109
- FactoryGirl.create(
109
+ FactoryBot.create(
110
110
  :simple_message,
111
111
  sender: second_user,
112
112
  recipients_to_save: { 'groups' => membered_group.slug },
113
113
  subject: 'Membered Group Deleted Conversation'
114
114
  ).mark(:deleted, first_user)
115
115
 
116
- FactoryGirl.create(
116
+ FactoryBot.create(
117
117
  :simple_message,
118
118
  sender: second_user,
119
119
  recipients_to_save: { 'groups' => membered_group.slug },
@@ -121,7 +121,7 @@ after :users, :groups do
121
121
  draft: true
122
122
  )
123
123
 
124
- FactoryGirl.create(
124
+ FactoryBot.create(
125
125
  :simple_message,
126
126
  sender: first_user,
127
127
  recipients_to_save: { 'groups' => first_group.slug },
@@ -129,14 +129,14 @@ after :users, :groups do
129
129
  draft: true
130
130
  )
131
131
 
132
- FactoryGirl.create(
132
+ FactoryBot.create(
133
133
  :simple_message,
134
134
  sender: superadmin_user,
135
135
  recipients_to_save: { 'roles' => 'admin' },
136
136
  subject: 'Role Conversation'
137
137
  )
138
138
 
139
- FactoryGirl.create(
139
+ FactoryBot.create(
140
140
  :simple_message,
141
141
  sender: superadmin_user,
142
142
  recipients_to_save: { 'roles' => 'admin' },
@@ -144,28 +144,28 @@ after :users, :groups do
144
144
  draft: true
145
145
  )
146
146
 
147
- FactoryGirl.create(
147
+ FactoryBot.create(
148
148
  :simple_message,
149
149
  subject: 'This should turn into a draft',
150
150
  sender: first_user,
151
151
  recipients_to_save: {}
152
152
  )
153
153
 
154
- FactoryGirl.create(
154
+ FactoryBot.create(
155
155
  :simple_message,
156
156
  subject: "Someone Else's Conversation",
157
157
  sender: User.order(:id).last,
158
158
  recipients_to_save: { 'users' => second_user.slug }
159
159
  )
160
160
 
161
- long_message = FactoryGirl.create(
161
+ long_message = FactoryBot.create(
162
162
  :simple_message,
163
163
  subject: 'Long Conversation',
164
164
  sender: second_user,
165
165
  recipients_to_save: { 'users' => first_user.slug }
166
166
  )
167
167
 
168
- FactoryGirl.create_list(
168
+ FactoryBot.create_list(
169
169
  :simple_message,
170
170
  11,
171
171
  conversation: long_message.conversation,
@@ -1,13 +1,13 @@
1
1
  after :users, :groups do
2
2
  User.find_each do |user|
3
3
  # Create some conversations that this user has received
4
- FactoryGirl.create_list(
4
+ FactoryBot.create_list(
5
5
  :message_from_random_sender,
6
6
  [*5..10].sample,
7
7
  recipients_to_save: { 'users' => user.slug }
8
8
  )
9
9
 
10
10
  # Create some conversations that this user has sent
11
- FactoryGirl.create_list(:message, [*5..10].sample, sender: user)
11
+ FactoryBot.create_list(:message, [*5..10].sample, sender: user)
12
12
  end
13
13
  end
@@ -4,7 +4,7 @@ after :users do
4
4
  fourth_user = User.friendly.find('fourth-user')
5
5
  unsubscribed_user = User.friendly.find('unsubscribed-user')
6
6
 
7
- first_group = FactoryGirl.create(
7
+ first_group = FactoryBot.create(
8
8
  :group,
9
9
  title: 'First Group',
10
10
  owner: first_user
@@ -12,7 +12,7 @@ after :users do
12
12
  fourth_user.add_role(:member, first_group)
13
13
  unsubscribed_user.add_role(:member, first_group)
14
14
 
15
- membered_group = FactoryGirl.create(
15
+ membered_group = FactoryBot.create(
16
16
  :group,
17
17
  title: 'Membered Group',
18
18
  owner: second_user
@@ -20,13 +20,13 @@ after :users do
20
20
  first_user.add_role(:member, membered_group)
21
21
  unsubscribed_user.add_role(:member, membered_group)
22
22
 
23
- FactoryGirl.create(
23
+ FactoryBot.create(
24
24
  :group,
25
25
  title: 'Empty Group',
26
26
  owner: first_user
27
27
  )
28
28
 
29
- unsubscribed_group = FactoryGirl.create(
29
+ unsubscribed_group = FactoryBot.create(
30
30
  :group,
31
31
  title: 'Unsubscribed Group',
32
32
  owner: second_user
@@ -1,13 +1,13 @@
1
1
  after 'test:conversations' do
2
- FactoryGirl.create(
2
+ FactoryBot.create(
3
3
  :attachment,
4
- attachment: File.open(
4
+ attachment: Rack::Test::UploadedFile.new(
5
5
  'spec/dummy/app/assets/files/message_train/attachments/image-sample.jpg'
6
6
  )
7
7
  )
8
- FactoryGirl.create(
8
+ FactoryBot.create(
9
9
  :attachment,
10
- attachment: File.open(
10
+ attachment: Rack::Test::UploadedFile.new(
11
11
  'spec/dummy/app/assets/files/message_train/attachments/pdf-sample.pdf'
12
12
  )
13
13
  )
@@ -2,12 +2,12 @@ after :users, :groups do
2
2
  first_user = User.friendly.find('first-user')
3
3
 
4
4
  # Create some conversations that first user has received
5
- FactoryGirl.create_list(
5
+ FactoryBot.create_list(
6
6
  :message_from_random_sender,
7
7
  10,
8
8
  recipients_to_save: { 'users' => first_user.slug }
9
9
  )
10
10
 
11
11
  # Create some conversations that first user has sent
12
- FactoryGirl.create_list(:message, 10, sender: first_user)
12
+ FactoryBot.create_list(:message, 10, sender: first_user)
13
13
  end
@@ -1,46 +1,46 @@
1
- FactoryGirl.create(
1
+ FactoryBot.create(
2
2
  :user,
3
3
  display_name: 'First User',
4
4
  email: 'first.user@example.com'
5
5
  )
6
6
 
7
- FactoryGirl.create(
7
+ FactoryBot.create(
8
8
  :user,
9
9
  display_name: 'Second User',
10
10
  email: 'second.user@example.com'
11
11
  )
12
12
 
13
- FactoryGirl.create(
13
+ FactoryBot.create(
14
14
  :user,
15
15
  display_name: 'Third User',
16
16
  email: 'third.user@example.com'
17
17
  )
18
18
 
19
- FactoryGirl.create(
19
+ FactoryBot.create(
20
20
  :user,
21
21
  display_name: 'Fourth User',
22
22
  email: 'fourth.user@example.com'
23
23
  )
24
24
 
25
- FactoryGirl.create(
25
+ FactoryBot.create(
26
26
  :user,
27
27
  display_name: 'Unsubscribed User',
28
28
  email: 'unsubscribed.user@example.com'
29
29
  )
30
30
 
31
- FactoryGirl.create(
31
+ FactoryBot.create(
32
32
  :user,
33
33
  display_name: 'Silent User',
34
34
  email: 'silent.user@example.com'
35
35
  )
36
36
 
37
- FactoryGirl.create(
37
+ FactoryBot.create(
38
38
  :user,
39
39
  display_name: 'Superadmin User',
40
40
  email: 'superadmin.user@example.com'
41
41
  ).add_role(:superadmin)
42
42
 
43
- FactoryGirl.create(
43
+ FactoryBot.create(
44
44
  :user,
45
45
  display_name: 'Admin User',
46
46
  email: 'admin.user@example.com'
File without changes
@@ -1,12 +1,11 @@
1
- FactoryGirl.define do
1
+ FactoryBot.define do
2
2
  factory :attachment, class: 'MessageTrain::Attachment' do
3
3
  message { MessageTrain::Message.order('RANDOM()').first }
4
4
  attachment do
5
- File.open(
6
- Dir[
7
- Rails.root.join 'app/assets/files/message_train/attachments/*'
8
- ].sample
9
- )
5
+ path = Dir[
6
+ Rails.root.join 'app/assets/files/message_train/attachments/*'
7
+ ].sample
8
+ Rack::Test::UploadedFile.new(path)
10
9
  end
11
10
  end
12
11
  end
@@ -1,7 +1,7 @@
1
- FactoryGirl.define do
1
+ FactoryBot.define do
2
2
  factory :group do
3
3
  title { Faker::Lorem.sentence }
4
- description { Faker::Lorem.paragraphs([*1..5].sample).join("\n\n") }
4
+ description { Faker::Lorem.paragraphs(number: [*1..5].sample).join("\n\n") }
5
5
  transient do
6
6
  owner { User.order('RANDOM()').first }
7
7
  # member_count 5
@@ -1,4 +1,4 @@
1
- FactoryGirl.define do
1
+ FactoryBot.define do
2
2
  factory :message, class: 'MessageTrain::Message' do
3
3
  sender do
4
4
  User
@@ -18,7 +18,7 @@ FactoryGirl.define do
18
18
  }
19
19
  end
20
20
  subject { Faker::Lorem.sentence }
21
- body { "<p>#{Faker::Lorem.paragraphs([*1..5].sample).join('</p><p>')}</p>" }
21
+ body { Faker::Lorem.paragraphs(number: [*1..5].sample).join("\n\n") }
22
22
 
23
23
  transient do
24
24
  generate_attachment? { [*1..100].sample >= 80 }
@@ -31,7 +31,7 @@ FactoryGirl.define do
31
31
  # attributes
32
32
  after(:create) do |message, evaluator|
33
33
  if evaluator.generate_attachment?
34
- FactoryGirl.create(:attachment, message: message)
34
+ FactoryBot.create(:attachment, message: message)
35
35
  end
36
36
  if message.recipients_to_save['users'].present?
37
37
  participants = (
@@ -45,7 +45,7 @@ FactoryGirl.define do
45
45
  if evaluator.generate_response? && participants.count > 1
46
46
  response_sender = User.friendly.find(participants.sample)
47
47
  response_recipients = participants - [response_sender.slug]
48
- FactoryGirl.create(
48
+ FactoryBot.create(
49
49
  :message,
50
50
  sender: response_sender,
51
51
  recipients_to_save: { 'users' => response_recipients.join(', ') },
@@ -72,9 +72,9 @@ FactoryGirl.define do
72
72
  end
73
73
 
74
74
  factory :simple_message do
75
- generate_ignore? false
76
- generate_response? false
77
- generate_attachment? false
75
+ generate_ignore? { false }
76
+ generate_response? { false }
77
+ generate_attachment? { false }
78
78
  end
79
79
  end
80
80
  end
@@ -1,10 +1,10 @@
1
- FactoryGirl.define do
1
+ FactoryBot.define do
2
2
  factory :user do
3
3
  display_name { Faker::Name.name }
4
4
  sequence :email do |n|
5
5
  "#{display_name.tr(' ', '.').downcase}#{n}@example.com"
6
6
  end
7
- password 'password'
8
- password_confirmation 'password'
7
+ password { 'password' }
8
+ password_confirmation { 'password' }
9
9
  end
10
10
  end
@@ -2,10 +2,10 @@ require 'rails_helper'
2
2
  RSpec.feature 'Boxes' do
3
3
  include_context 'loaded site'
4
4
 
5
- it_behaves_like 'an authenticated section', '/box'
5
+ it_behaves_like 'an authenticated section', '/messages/box'
6
6
  it_behaves_like(
7
7
  'an authenticated section',
8
- '/collectives/groups:membered-group'
8
+ '/messages/collectives/groups:membered-group'
9
9
  )
10
10
 
11
11
  describe 'When logged in as first-user' do
@@ -16,7 +16,7 @@ RSpec.feature 'Boxes' do
16
16
  describe 'Showing' do
17
17
  describe 'at /box/in' do
18
18
  before do
19
- visit '/box/in'
19
+ visit '/messages/box/in'
20
20
  click_link 'Last'
21
21
  end
22
22
  it_behaves_like(
@@ -30,7 +30,7 @@ RSpec.feature 'Boxes' do
30
30
  subject { page }
31
31
  it do
32
32
  should_not have_css(
33
- 'li.dropdown a.dropdown-toggle',
33
+ 'details.message-train-dropdown-nav-item summary',
34
34
  text: 'Roles'
35
35
  )
36
36
  end
@@ -47,8 +47,8 @@ RSpec.feature 'Boxes' do
47
47
  subject { page }
48
48
  it do
49
49
  should have_css(
50
- "#message_train_conversation_#{attachment_conversation.id} "\
51
- '.glyphicon-paperclip'
50
+ "#message_train_conversation_#{attachment_conversation.id} " \
51
+ '.message-train-icon'
52
52
  )
53
53
  end
54
54
  end
@@ -68,7 +68,7 @@ RSpec.feature 'Boxes' do
68
68
  describe 'at /box/in' do
69
69
  describe 'using the buttons on each conversation' do
70
70
  before do
71
- visit '/box/in'
71
+ visit '/messages/box/in'
72
72
  click_link 'Last'
73
73
  within "#message_train_conversation_#{unread_conversation.id}" do
74
74
  accept_confirm do
@@ -76,6 +76,7 @@ RSpec.feature 'Boxes' do
76
76
  end
77
77
  end
78
78
  end
79
+ after { undo_leaked_mark(:untrash) }
79
80
  it_behaves_like(
80
81
  'a bootstrap page with an alert',
81
82
  'info',
@@ -84,9 +85,8 @@ RSpec.feature 'Boxes' do
84
85
  end
85
86
  describe 'without checking anything' do
86
87
  before do
87
- visit '/box/in'
88
- click_button 'Mark'
89
- click_link 'mark-read'
88
+ visit '/messages/box/in'
89
+ click_button 'mark-read'
90
90
  end
91
91
  it_behaves_like(
92
92
  'a bootstrap page with an alert',
@@ -97,12 +97,16 @@ RSpec.feature 'Boxes' do
97
97
  describe 'after checking a box' do
98
98
  describe 'Marking Read' do
99
99
  before do
100
- visit '/box/in'
101
- click_link 'Last'
102
- check "objects_conversations_#{unread_conversation.id}"
103
- click_button 'Mark'
104
- click_link 'mark-read'
100
+ visit '/messages/box/in'
101
+ # Marking touches updated_at, which can move the
102
+ # conversation off the last page if an earlier example
103
+ # already marked it - only paginate there if needed.
104
+ checkbox = "objects_conversations_#{unread_conversation.id}"
105
+ click_link 'Last' unless page.has_field?(checkbox)
106
+ check checkbox
107
+ click_button 'mark-read'
105
108
  end
109
+ after { undo_leaked_mark(:unread) }
106
110
  it_behaves_like(
107
111
  'a bootstrap page with an alert',
108
112
  'info',
@@ -111,12 +115,13 @@ RSpec.feature 'Boxes' do
111
115
  end
112
116
  describe 'Marking Ignored' do
113
117
  before do
114
- visit '/box/in'
115
- click_link 'Last'
116
- check "objects_conversations_#{unread_conversation.id}"
117
- click_button 'Mark'
118
- click_link 'mark-ignored'
118
+ visit '/messages/box/in'
119
+ checkbox = "objects_conversations_#{unread_conversation.id}"
120
+ click_link 'Last' unless page.has_field?(checkbox)
121
+ check checkbox
122
+ click_button 'mark-ignored'
119
123
  end
124
+ after { undo_leaked_mark(:unignore) }
120
125
  it_behaves_like(
121
126
  'a bootstrap page with an alert',
122
127
  'info',
@@ -132,7 +137,7 @@ RSpec.feature 'Boxes' do
132
137
  describe 'Showing' do
133
138
  describe 'at /collectives/groups:membered-group/box/in' do
134
139
  before do
135
- visit '/collectives/groups:membered-group/box/in'
140
+ visit '/messages/collectives/groups:membered-group/box/in'
136
141
  end
137
142
  it_behaves_like(
138
143
  'a bootstrap page listing a collection of items',
@@ -147,9 +152,8 @@ RSpec.feature 'Boxes' do
147
152
  describe 'at /collectives/groups:membered-group/box/in' do
148
153
  describe 'without checking anything' do
149
154
  before do
150
- visit '/collectives/groups:membered-group/box/in'
151
- click_button 'Mark'
152
- click_link 'mark-read'
155
+ visit '/messages/collectives/groups:membered-group/box/in'
156
+ click_button 'mark-read'
153
157
  end
154
158
  it_behaves_like(
155
159
  'a bootstrap page with an alert',
@@ -160,11 +164,11 @@ RSpec.feature 'Boxes' do
160
164
  describe 'after checking a box' do
161
165
  describe 'Marking Read' do
162
166
  before do
163
- visit '/collectives/groups:membered-group/box/in'
167
+ visit '/messages/collectives/groups:membered-group/box/in'
164
168
  check "objects_conversations_#{membered_group_conversation.id}"
165
- click_button 'Mark'
166
- click_link 'mark-read'
169
+ click_button 'mark-read'
167
170
  end
171
+ after { undo_leaked_mark(:unread, conversation: membered_group_conversation) }
168
172
  it_behaves_like(
169
173
  'a bootstrap page with an alert',
170
174
  'info',
@@ -173,11 +177,11 @@ RSpec.feature 'Boxes' do
173
177
  end
174
178
  describe 'Marking Ignored' do
175
179
  before do
176
- visit '/collectives/groups:membered-group/box/in'
180
+ visit '/messages/collectives/groups:membered-group/box/in'
177
181
  check "objects_conversations_#{membered_group_conversation.id}"
178
- click_button 'Mark'
179
- click_link 'mark-ignored'
182
+ click_button 'mark-ignored'
180
183
  end
184
+ after { undo_leaked_mark(:unignore, conversation: membered_group_conversation) }
181
185
  it_behaves_like(
182
186
  'a bootstrap page with an alert',
183
187
  'info',
@@ -198,12 +202,12 @@ RSpec.feature 'Boxes' do
198
202
  describe 'Showing' do
199
203
  describe 'at /box/in' do
200
204
  before do
201
- visit '/box/in'
205
+ visit '/messages/box/in'
202
206
  end
203
207
 
204
208
  describe 'lists Roles dropdown' do
205
209
  subject { page }
206
- it { should have_css('li.dropdown a.dropdown-toggle', text: 'Roles') }
210
+ it { should have_css('details.message-train-dropdown-nav-item summary', text: 'Roles') }
207
211
  end
208
212
  end
209
213
  end
@@ -216,12 +220,12 @@ RSpec.feature 'Boxes' do
216
220
  describe 'Showing' do
217
221
  describe 'at /box/in' do
218
222
  before do
219
- visit '/box/in'
223
+ visit '/messages/box/in'
220
224
  end
221
225
 
222
226
  describe 'lists Roles dropdown' do
223
227
  subject { page }
224
- it { should have_css('li.dropdown a.dropdown-toggle', text: 'Roles') }
228
+ it { should have_css('details.message-train-dropdown-nav-item summary', text: 'Roles') }
225
229
  end
226
230
  end
227
231
  end
@@ -2,7 +2,7 @@ require 'rails_helper'
2
2
  RSpec.feature 'Conversations' do
3
3
  include_context 'loaded site'
4
4
 
5
- it_behaves_like 'an authenticated section', '/box/in/conversations/1'
5
+ it_behaves_like 'an authenticated section', '/messages/box/in/conversations/1'
6
6
 
7
7
  describe 'When logged in' do
8
8
  before do
@@ -11,7 +11,7 @@ RSpec.feature 'Conversations' do
11
11
  describe 'Showing' do
12
12
  describe 'at /box/in/conversations/:id' do
13
13
  before do
14
- visit "/box/in/conversations/#{unread_conversation.id}"
14
+ visit "/messages/box/in/conversations/#{unread_conversation.id}"
15
15
  end
16
16
  it_behaves_like(
17
17
  'a bootstrap page showing an item',
@@ -31,9 +31,14 @@ RSpec.feature 'Conversations' do
31
31
  describe 'at /box/in/conversations/:id' do
32
32
  describe 'Marking Read' do
33
33
  before do
34
- visit "/box/in/conversations/#{unread_conversation.id}"
35
- click_link "mark_read_#{unread_message.id}"
34
+ visit "/messages/box/in/conversations/#{unread_conversation.id}"
35
+ # An earlier example may have already marked this message read;
36
+ # toggle it back to unread first so this test always exercises
37
+ # (and can assert on) the read-marking action itself.
38
+ click_button "mark_unread_#{unread_message.id}" if page.has_button?("mark_unread_#{unread_message.id}")
39
+ click_button "mark_read_#{unread_message.id}"
36
40
  end
41
+ after { undo_leaked_mark(:unread) }
37
42
  it_behaves_like(
38
43
  'a bootstrap page with an alert',
39
44
  'info',
@@ -42,11 +47,13 @@ RSpec.feature 'Conversations' do
42
47
  end
43
48
  describe 'Marking Ignored' do
44
49
  before do
45
- visit "/box/in/conversations/#{unread_conversation.id}"
50
+ visit "/messages/box/in/conversations/#{unread_conversation.id}"
51
+ click_button 'Mark as Unignored' if page.has_button?('Mark as Unignored')
46
52
  accept_confirm do
47
- click_link 'Mark as Ignored'
53
+ click_button 'Mark as Ignored'
48
54
  end
49
55
  end
56
+ after { undo_leaked_mark(:unignore) }
50
57
  it_behaves_like(
51
58
  'a bootstrap page with an alert',
52
59
  'info',