activity_notification 1.0.0 → 1.0.1

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 (35) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile.lock +3 -3
  3. data/README.md +49 -9
  4. data/activity_notification.gemspec +1 -1
  5. data/app/controllers/activity_notification/notifications_controller.rb +75 -31
  6. data/app/mailers/activity_notification/mailer.rb +19 -4
  7. data/app/views/activity_notification/mailer/default/batch_default.html.erb +79 -0
  8. data/app/views/activity_notification/mailer/default/batch_default.text.erb +13 -0
  9. data/app/views/activity_notification/mailer/default/default.html.erb +75 -10
  10. data/app/views/activity_notification/mailer/default/default.text.erb +2 -2
  11. data/app/views/activity_notification/notifications/default/_default.html.erb +15 -14
  12. data/app/views/activity_notification/notifications/default/_default_without_grouping.html.erb +165 -0
  13. data/app/views/activity_notification/notifications/default/_index.html.erb +8 -4
  14. data/app/views/activity_notification/notifications/default/destroy.js.erb +2 -2
  15. data/app/views/activity_notification/notifications/default/index.html.erb +9 -5
  16. data/app/views/activity_notification/notifications/default/open.js.erb +6 -2
  17. data/app/views/activity_notification/notifications/default/open_all.js.erb +6 -2
  18. data/lib/activity_notification/apis/notification_api.rb +42 -9
  19. data/lib/activity_notification/helpers/view_helpers.rb +48 -19
  20. data/lib/activity_notification/mailers/helpers.rb +74 -37
  21. data/lib/activity_notification/models/concerns/target.rb +290 -26
  22. data/lib/activity_notification/models/notification.rb +85 -29
  23. data/lib/activity_notification/roles/acts_as_target.rb +4 -2
  24. data/lib/activity_notification/version.rb +1 -1
  25. data/spec/concerns/apis/notification_api_spec.rb +46 -0
  26. data/spec/concerns/models/target_spec.rb +281 -22
  27. data/spec/controllers/notifications_controller_shared_examples.rb +77 -0
  28. data/spec/helpers/view_helpers_spec.rb +39 -3
  29. data/spec/mailers/mailer_spec.rb +54 -1
  30. data/spec/models/notification_spec.rb +11 -0
  31. data/spec/rails_app/app/models/user.rb +1 -1
  32. data/spec/rails_app/app/views/layouts/_header.html.erb +2 -0
  33. data/spec/rails_app/lib/mailer_previews/mailer_preview.rb +6 -0
  34. data/spec/roles/acts_as_target_spec.rb +1 -1
  35. metadata +7 -4
@@ -50,31 +50,55 @@ module ActivityNotification
50
50
  # Selects group owner notifications only.
51
51
  # @scope class
52
52
  # @return [ActiveRecord_AssociationRelation<Notificaion>] Array or database query of filtered notifications
53
- scope :group_owners_only, -> { where(group_owner_id: nil) }
53
+ scope :group_owners_only, -> { where(group_owner_id: nil) }
54
54
 
55
55
  # Selects group member notifications only.
56
56
  # @scope class
57
57
  # @return [ActiveRecord_AssociationRelation<Notificaion>] Array or database query of filtered notifications
58
- scope :group_members_only, -> { where.not(group_owner_id: nil) }
58
+ scope :group_members_only, -> { where.not(group_owner_id: nil) }
59
+
60
+ # Selects all notification index.
61
+ # ActivityNotification::Notification.all_index!
62
+ # is defined same as
63
+ # ActivityNotification::Notification.group_owners_only.latest_order
64
+ # @example Get all notification index of the @user
65
+ # @notifications = @user.notifications.all_index!
66
+ # @notifications = @user.notifications.group_owners_only.latest_order
67
+ # @scope class
68
+ # @param [Boolean] reverse If notification index will be ordered as earliest first
69
+ # @param [Boolean] with_group_members If notification index will include group members
70
+ # @return [ActiveRecord_AssociationRelation<Notificaion>] Array or database query of filtered notifications
71
+ scope :all_index!, ->(reverse = false, with_group_members = false) {
72
+ target_index = with_group_members ? self : group_owners_only
73
+ reverse ? target_index.earliest_order : target_index.latest_order
74
+ }
59
75
 
60
76
  # Selects unopened notifications only.
61
77
  # @scope class
62
78
  # @return [ActiveRecord_AssociationRelation<Notificaion>] Array or database query of filtered notifications
63
- scope :unopened_only, -> { where(opened_at: nil) }
79
+ scope :unopened_only, -> { where(opened_at: nil) }
64
80
 
65
81
  # Selects unopened notification index.
66
- # Defined same as `unopened_only.group_owners_only.latest_order`.
82
+ # ActivityNotification::Notification.unopened_index
83
+ # is defined same as
84
+ # ActivityNotification::Notification.unopened_only.group_owners_only.latest_order
67
85
  # @example Get unopened notificaton index of the @user
68
- # @notifications = @user.unopened_index
86
+ # @notifications = @user.notifications.unopened_index
87
+ # @notifications = @user.notifications.unopened_only.group_owners_only.latest_order
69
88
  # @scope class
89
+ # @param [Boolean] reverse If notification index will be ordered as earliest first
90
+ # @param [Boolean] with_group_members If notification index will include group members
70
91
  # @return [ActiveRecord_AssociationRelation<Notificaion>] Array or database query of filtered notifications
71
- scope :unopened_index, -> { unopened_only.group_owners_only.latest_order }
92
+ scope :unopened_index, ->(reverse = false, with_group_members = false) {
93
+ target_index = with_group_members ? unopened_only : unopened_only.group_owners_only
94
+ reverse ? target_index.earliest_order : target_index.latest_order
95
+ }
72
96
 
73
97
  # Selects opened notifications only without limit.
74
98
  # Be careful to get too many records with this method.
75
99
  # @scope class
76
100
  # @return [ActiveRecord_AssociationRelation<Notificaion>] Array or database query of filtered notifications
77
- scope :opened_only!, -> { where.not(opened_at: nil) }
101
+ scope :opened_only!, -> { where.not(opened_at: nil) }
78
102
 
79
103
  # Selects opened notifications only with limit.
80
104
  # @scope class
@@ -83,16 +107,26 @@ module ActivityNotification
83
107
  scope :opened_only, ->(limit) { opened_only!.limit(limit) }
84
108
 
85
109
  # Selects unopened notification index.
86
- # Defined same as `opened_only(limit).group_owners_only.latest_order`.
110
+ # ActivityNotification::Notification.opened_index(limit)
111
+ # is defined same as
112
+ # ActivityNotification::Notification.opened_only(limit).group_owners_only.latest_order
113
+ # @example Get unopened notificaton index of the @user with limit 10
114
+ # @notifications = @user.notifications.opened_index(10)
115
+ # @notifications = @user.notifications.opened_only(10).group_owners_only.latest_order
87
116
  # @scope class
88
117
  # @param [Integer] limit Limit to query for opened notifications
118
+ # @param [Boolean] reverse If notification index will be ordered as earliest first
119
+ # @param [Boolean] with_group_members If notification index will include group members
89
120
  # @return [ActiveRecord_AssociationRelation<Notificaion>] Array or database query of filtered notifications
90
- scope :opened_index, ->(limit) { opened_only(limit).group_owners_only.latest_order }
121
+ scope :opened_index, ->(limit, reverse = false, with_group_members = false) {
122
+ target_index = with_group_members ? opened_only(limit) : opened_only(limit).group_owners_only
123
+ reverse ? target_index.earliest_order : target_index.latest_order
124
+ }
91
125
 
92
126
  # Selects group member notifications in unopened_index.
93
127
  # @scope class
94
128
  # @return [ActiveRecord_AssociationRelation<Notificaion>] Array or database query of filtered notifications
95
- scope :unopened_index_group_members_only, -> { where(group_owner_id: unopened_index.map(&:id)) }
129
+ scope :unopened_index_group_members_only, -> { where(group_owner_id: unopened_index.map(&:id)) }
96
130
 
97
131
  # Selects group member notifications in opened_index.
98
132
  # @scope class
@@ -107,7 +141,15 @@ module ActivityNotification
107
141
  # @scope class
108
142
  # @param [Object] target Target instance for filter
109
143
  # @return [ActiveRecord_AssociationRelation<Notificaion>] Array or database query of filtered notifications
110
- scope :filtered_by_target, ->(target) { where(target: target) }
144
+ scope :filtered_by_target, ->(target) { where(target: target) }
145
+
146
+ # Selects filtered notifications by target_type.
147
+ # @example Get filtered unopened notificatons of User as target type
148
+ # @notifications = ActivityNotification.Notification.unopened_only.filtered_by_target_type('User')
149
+ # @scope class
150
+ # @param [String] target_type Target type for filter
151
+ # @return [ActiveRecord_AssociationRelation<Notificaion>] Array or database query of filtered notifications
152
+ scope :filtered_by_target_type, ->(target_type) { where(target_type: target_type) }
111
153
 
112
154
  # Selects filtered notifications by notifiable instance.
113
155
  # @example Get filtered unopened notificatons of the @user for @comment as notifiable
@@ -115,7 +157,7 @@ module ActivityNotification
115
157
  # @scope class
116
158
  # @param [Object] notifiable Notifiable instance for filter
117
159
  # @return [ActiveRecord_AssociationRelation<Notificaion>] Array or database query of filtered notifications
118
- scope :filtered_by_instance, ->(notifiable) { where(notifiable: notifiable) }
160
+ scope :filtered_by_instance, ->(notifiable) { where(notifiable: notifiable) }
119
161
 
120
162
  # Selects filtered notifications by notifiable_type.
121
163
  # @example Get filtered unopened notificatons of the @user for Comment notifiable class
@@ -123,7 +165,7 @@ module ActivityNotification
123
165
  # @scope class
124
166
  # @param [String] notifiable_type Notifiable type for filter
125
167
  # @return [ActiveRecord_AssociationRelation<Notificaion>] Array or database query of filtered notifications
126
- scope :filtered_by_type, ->(notifiable_type) { where(notifiable_type: notifiable_type) }
168
+ scope :filtered_by_type, ->(notifiable_type) { where(notifiable_type: notifiable_type) }
127
169
 
128
170
  # Selects filtered notifications by group instance.
129
171
  # @example Get filtered unopened notificatons of the @user for @article as group
@@ -131,7 +173,7 @@ module ActivityNotification
131
173
  # @scope class
132
174
  # @param [Object] group Group instance for filter
133
175
  # @return [ActiveRecord_AssociationRelation<Notificaion>] Array or database query of filtered notifications
134
- scope :filtered_by_group, ->(group) { where(group: group) }
176
+ scope :filtered_by_group, ->(group) { where(group: group) }
135
177
 
136
178
  # Selects filtered notifications by key.
137
179
  # @example Get filtered unopened notificatons of the @user with key 'comment.reply'
@@ -139,7 +181,7 @@ module ActivityNotification
139
181
  # @scope class
140
182
  # @param [String] key Key of the notification for filter
141
183
  # @return [ActiveRecord_AssociationRelation<Notificaion>] Array or database query of filtered notifications
142
- scope :filtered_by_key, ->(key) { where(key: key) }
184
+ scope :filtered_by_key, ->(key) { where(key: key) }
143
185
 
144
186
  # Selects filtered notifications by notifiable_type, group or key with filter options.
145
187
  # @example Get filtered unopened notificatons of the @user for Comment notifiable class
@@ -152,15 +194,18 @@ module ActivityNotification
152
194
  # @notifications = @user.notifications.unopened_only.filtered_by_options({ filtered_by_key: 'comment.reply' })
153
195
  # @example Get filtered unopened notificatons of the @user for Comment notifiable class with key 'comment.reply'
154
196
  # @notifications = @user.notifications.unopened_only.filtered_by_options({ filtered_by_type: 'Comment', filtered_by_key: 'comment.reply' })
197
+ # @example Get custom filtered notificatons of the @user
198
+ # @notifications = @user.notifications.unopened_only.filtered_by_options({ custom_filter: ["created_at >= ?", time.hour.ago] })
155
199
  # @scope class
156
200
  # @param [Hash] options Options for filter
157
- # @option options [String] :filtered_by_type (nil) Notifiable type for filter
158
- # @option options [Object] :filtered_by_group (nil) Group instance for filter
159
- # @option options [String] :filtered_by_group_type (nil) Group type for filter, valid with :filtered_by_group_id
160
- # @option options [String] :filtered_by_group_id (nil) Group instance id for filter, valid with :filtered_by_group_type
161
- # @option options [String] :filtered_by_key (nil) Key of the notification for filter
201
+ # @option options [String] :filtered_by_type (nil) Notifiable type for filter
202
+ # @option options [Object] :filtered_by_group (nil) Group instance for filter
203
+ # @option options [String] :filtered_by_group_type (nil) Group type for filter, valid with :filtered_by_group_id
204
+ # @option options [String] :filtered_by_group_id (nil) Group instance id for filter, valid with :filtered_by_group_type
205
+ # @option options [String] :filtered_by_key (nil) Key of the notification for filter
206
+ # @option options [Array|Hash] :custom_filter (nil) Custom notification filter (e.g. ["created_at >= ?", time.hour.ago])
162
207
  # @return [ActiveRecord_AssociationRelation<Notificaion>] Array or database query of filtered notifications
163
- scope :filtered_by_options, ->(options = {}) {
208
+ scope :filtered_by_options, ->(options = {}) {
164
209
  options = ActivityNotification.cast_to_indifferent_hash(options)
165
210
  filtered_notifications = all
166
211
  if options.has_key?(:filtered_by_type)
@@ -176,40 +221,51 @@ module ActivityNotification
176
221
  if options.has_key?(:filtered_by_key)
177
222
  filtered_notifications = filtered_notifications.filtered_by_key(options[:filtered_by_key])
178
223
  end
224
+ if options.has_key?(:custom_filter)
225
+ filtered_notifications = filtered_notifications.where(options[:custom_filter])
226
+ end
179
227
  filtered_notifications
180
228
  }
181
229
 
182
230
  # Includes target instance with query for notifications.
183
231
  # @return [ActiveRecord_AssociationRelation<Notificaion>] Database query of notifications with target
184
- scope :with_target, -> { includes(:target) }
232
+ scope :with_target, -> { includes(:target) }
185
233
 
186
234
  # Includes notifiable instance with query for notifications.
187
235
  # @return [ActiveRecord_AssociationRelation<Notificaion>] Database query of notifications with notifiable
188
- scope :with_notifiable, -> { includes(:notifiable) }
236
+ scope :with_notifiable, -> { includes(:notifiable) }
189
237
 
190
238
  # Includes group instance with query for notifications.
191
239
  # @return [ActiveRecord_AssociationRelation<Notificaion>] Database query of notifications with group
192
- scope :with_group, -> { includes(:group) }
240
+ scope :with_group, -> { includes(:group) }
241
+
242
+ # Includes group owner instances with query for notifications.
243
+ # @return [ActiveRecord_AssociationRelation<Notificaion>] Database query of notifications with group owner
244
+ scope :with_group_owner, -> { includes(:group_owner) }
245
+
246
+ # Includes group member instances with query for notifications.
247
+ # @return [ActiveRecord_AssociationRelation<Notificaion>] Database query of notifications with group members
248
+ scope :with_group_members, -> { includes(:group_members) }
193
249
 
194
250
  # Includes notifier instance with query for notifications.
195
251
  # @return [ActiveRecord_AssociationRelation<Notificaion>] Database query of notifications with notifier
196
- scope :with_notifier, -> { includes(:notifier) }
252
+ scope :with_notifier, -> { includes(:notifier) }
197
253
 
198
254
  # Orders by latest (newest) first as created_at: :desc.
199
255
  # @return [ActiveRecord_AssociationRelation<Notificaion>] Database query of notifications ordered by latest first
200
- scope :latest_order, -> { order(created_at: :desc) }
256
+ scope :latest_order, -> { order(created_at: :desc) }
201
257
 
202
258
  # Orders by earliest (older) first as created_at: :asc.
203
259
  # @return [ActiveRecord_AssociationRelation<Notificaion>] Database query of notifications ordered by earliest first
204
- scope :earliest_order, -> { order(created_at: :asc) }
260
+ scope :earliest_order, -> { order(created_at: :asc) }
205
261
 
206
262
  # Returns latest notification instance.
207
263
  # @return [Notification] Latest notification instance
208
- scope :latest, -> { latest_order.first }
264
+ scope :latest, -> { latest_order.first }
209
265
 
210
266
  # Returns earliest notification instance.
211
267
  # @return [Notification] Earliest notification instance
212
- scope :earliest, -> { earliest_order.first }
268
+ scope :earliest, -> { earliest_order.first }
213
269
 
214
270
  end
215
271
  end
@@ -87,6 +87,7 @@ module ActivityNotification
87
87
  # @param [Hash] options Options for notifiable model configuration
88
88
  # @option options [Symbol, Proc, String] :email (nil) Email address to send notification email
89
89
  # @option options [Symbol, Proc, Boolean] :email_allowed (ActivityNotification.config.email_enabled) Whether activity_notification sends notification email to this target
90
+ # @option options [Symbol, Proc, Boolean] :email_allowed (ActivityNotification.config.email_enabled) Whether activity_notification sends batch notification email to this target
90
91
  # @option options [Symbol, Proc, Object] :devise_resource (nil) Integrated resource with devise authentication
91
92
  # @option options [Symbol, Proc, String] :printable_name (ActivityNotification::Common.printable_name) Printable notification target name
92
93
  # @return [Hash] Configured parameters as target model
@@ -94,15 +95,16 @@ module ActivityNotification
94
95
  include Target
95
96
 
96
97
  options[:printable_notification_target_name] ||= options.delete(:printable_name)
98
+ options[:batch_notification_email_allowed] ||= options.delete(:batch_email_allowed)
97
99
  set_acts_as_parameters([:email, :email_allowed, :devise_resource], options, "notification_")
98
- .merge set_acts_as_parameters([:printable_notification_target_name], options)
100
+ .merge set_acts_as_parameters([:batch_notification_email_allowed, :printable_notification_target_name], options)
99
101
  end
100
102
  alias_method :acts_as_notification_target, :acts_as_target
101
103
 
102
104
  # Returns array of available target options in acts_as_target.
103
105
  # @return [Array<Symbol>] Array of available target options
104
106
  def available_target_options
105
- [:email, :email_allowed, :devise_resource, :printable_notification_target_name, :printable_name].freeze
107
+ [:email, :email_allowed, :batch_email_allowed, :devise_resource, :printable_notification_target_name, :printable_name].freeze
106
108
  end
107
109
  end
108
110
  end
@@ -1,3 +1,3 @@
1
1
  module ActivityNotification
2
- VERSION = "1.0.0"
2
+ VERSION = "1.0.1"
3
3
  end
@@ -412,6 +412,36 @@ shared_examples_for :notification_api do
412
412
  end
413
413
  end
414
414
 
415
+ describe ".send_batch_notification_email" do
416
+ context "as default" do
417
+ it "sends batch notification email later" do
418
+ expect(ActivityNotification::Mailer.deliveries.size).to eq(0)
419
+ expect {
420
+ perform_enqueued_jobs do
421
+ described_class.send_batch_notification_email(test_instance.target, [test_instance])
422
+ end
423
+ }.to change { ActivityNotification::Mailer.deliveries.size }.by(1)
424
+ expect(ActivityNotification::Mailer.deliveries.size).to eq(1)
425
+ expect(ActivityNotification::Mailer.deliveries.first.to[0]).to eq(test_instance.target.email)
426
+ end
427
+
428
+ it "sends batch notification email with active job queue" do
429
+ expect {
430
+ described_class.send_batch_notification_email(test_instance.target, [test_instance])
431
+ }.to change(ActiveJob::Base.queue_adapter.enqueued_jobs, :size).by(1)
432
+ end
433
+ end
434
+
435
+ context "with send_later false" do
436
+ it "sends notification email now" do
437
+ expect(ActivityNotification::Mailer.deliveries.size).to eq(0)
438
+ described_class.send_batch_notification_email(test_instance.target, [test_instance], send_later: false)
439
+ expect(ActivityNotification::Mailer.deliveries.size).to eq(1)
440
+ expect(ActivityNotification::Mailer.deliveries.first.to[0]).to eq(test_instance.target.email)
441
+ end
442
+ end
443
+ end
444
+
415
445
  describe ".available_options" do
416
446
  it "returns list of available options in notify api" do
417
447
  expect(described_class.available_options)
@@ -1035,6 +1065,22 @@ shared_examples_for :notification_api do
1035
1065
  end
1036
1066
  end
1037
1067
 
1068
+ describe "#latest_group_member" do
1069
+ context "with group member" do
1070
+ it "returns latest group member" do
1071
+ member1 = create(test_class_name, target: test_instance.target, group_owner: test_instance)
1072
+ member2 = create(test_class_name, target: test_instance.target, group_owner: test_instance)
1073
+ expect(test_instance.latest_group_member).to eq(member2)
1074
+ end
1075
+ end
1076
+
1077
+ context "without group members" do
1078
+ it "returns group owner self" do
1079
+ expect(test_instance.latest_group_member).to eq(test_instance)
1080
+ end
1081
+ end
1082
+ end
1083
+
1038
1084
  describe "#notifiable_path" do
1039
1085
  it "returns notifiable.notifiable_path" do
1040
1086
  expect(test_instance.notifiable_path)
@@ -30,6 +30,75 @@ shared_examples_for :target do
30
30
  expect(described_class._printable_notification_target_name).to eq(:printable_name)
31
31
  end
32
32
  end
33
+
34
+ describe ".notification_index_map" do
35
+ it "returns notifications of this target type group by target" do
36
+ ActivityNotification::Notification.delete_all
37
+ target_1 = create(test_class_name)
38
+ target_2 = create(test_class_name)
39
+ notification_1 = create(:notification, target: target_1)
40
+ notification_2 = create(:notification, target: target_1)
41
+ notification_3 = create(:notification, target: target_1)
42
+ notification_4 = create(:notification, target: target_2)
43
+ notification_5 = create(:notification, target: target_2)
44
+ notification_6 = create(:notification, target: test_notifiable)
45
+
46
+ expect(described_class.notification_index_map.size).to eq(2)
47
+ expect(described_class.notification_index_map[target_1].size).to eq(3)
48
+ expect(described_class.notification_index_map[target_2].size).to eq(2)
49
+ end
50
+ end
51
+
52
+ describe ".unopened_notification_index_map" do
53
+ it "returns unopened notifications of this target type group by target" do
54
+ ActivityNotification::Notification.delete_all
55
+ target_1 = create(test_class_name)
56
+ target_2 = create(test_class_name)
57
+ target_3 = create(test_class_name)
58
+ notification_1 = create(:notification, target: target_1)
59
+ notification_2 = create(:notification, target: target_1)
60
+ notification_3 = create(:notification, target: target_1)
61
+ notification_3.open!
62
+ notification_4 = create(:notification, target: target_2)
63
+ notification_5 = create(:notification, target: target_2)
64
+ notification_5.open!
65
+ notification_6 = create(:notification, target: target_3)
66
+ notification_6.open!
67
+ notification_7 = create(:notification, target: test_notifiable)
68
+
69
+ index_map = described_class.unopened_notification_index_map
70
+ expect(index_map.size).to eq(2)
71
+ expect(index_map[target_1].size).to eq(2)
72
+ expect(index_map[target_2].size).to eq(1)
73
+ expect(index_map.has_key?(target_3)).to be_falsey
74
+ end
75
+ end
76
+
77
+ describe ".send_batch_unopened_notification_email" do
78
+ it "sends batch notification email to this type targets with unopened notifications" do
79
+ ActivityNotification::Notification.delete_all
80
+ target_1 = create(test_class_name)
81
+ target_2 = create(test_class_name)
82
+ target_3 = create(test_class_name)
83
+ notification_1 = create(:notification, target: target_1)
84
+ notification_2 = create(:notification, target: target_1)
85
+ notification_3 = create(:notification, target: target_1)
86
+ notification_3.open!
87
+ notification_4 = create(:notification, target: target_2)
88
+ notification_5 = create(:notification, target: target_2)
89
+ notification_5.open!
90
+ notification_6 = create(:notification, target: target_3)
91
+ notification_6.open!
92
+ notification_7 = create(:notification, target: test_notifiable)
93
+
94
+ expect(ActivityNotification::Notification).to receive(:send_batch_notification_email).at_least(:once)
95
+ sent_email_map = described_class.send_batch_unopened_notification_email
96
+ expect(sent_email_map.size).to eq(2)
97
+ expect(sent_email_map.has_key?(target_1)).to be_truthy
98
+ expect(sent_email_map.has_key?(target_2)).to be_truthy
99
+ expect(sent_email_map.has_key?(target_3)).to be_falsey
100
+ end
101
+ end
33
102
  end
34
103
 
35
104
  describe "as public instance methods" do
@@ -248,9 +317,14 @@ shared_examples_for :target do
248
317
 
249
318
  context "when the target has unopened notifications" do
250
319
  before do
251
- create(:notification, target: test_instance)
252
- create(:notification, target: test_instance)
253
- create(:notification, target: test_instance).open!
320
+ @notifiable = create(:article)
321
+ @group = create(:article)
322
+ @key = 'test.key.1'
323
+ @notification2 = create(:notification, target: test_instance, notifiable: @notifiable)
324
+ @notification1 = create(:notification, target: test_instance, notifiable: create(:comment), group: @group)
325
+ @member1 = create(:notification, target: test_instance, notifiable: create(:comment), group_owner: @notification1)
326
+ @notification3 = create(:notification, target: test_instance, notifiable: create(:article), key: @key)
327
+ @notification3.open!
254
328
  end
255
329
 
256
330
  it "calls unopened_notification_index" do
@@ -258,11 +332,11 @@ shared_examples_for :target do
258
332
  test_instance.notification_index
259
333
  end
260
334
 
261
- context "without limit" do
335
+ context "without any options" do
262
336
  it "returns the combined array of unopened_notification_index and opened_notification_index" do
263
- expect(test_instance.notification_index[0]).to eq(test_instance.unopened_notification_index[0])
264
- expect(test_instance.notification_index[1]).to eq(test_instance.unopened_notification_index[1])
265
- expect(test_instance.notification_index[2]).to eq(test_instance.opened_notification_index[0])
337
+ expect(test_instance.notification_index[0]).to eq(@notification1)
338
+ expect(test_instance.notification_index[1]).to eq(@notification2)
339
+ expect(test_instance.notification_index[2]).to eq(@notification3)
266
340
  expect(test_instance.notification_index.size).to eq(3)
267
341
  end
268
342
  end
@@ -270,7 +344,86 @@ shared_examples_for :target do
270
344
  context "with limit" do
271
345
  it "returns the same as unopened_notification_index with limit" do
272
346
  options = { limit: 1 }
273
- expect(test_instance.notification_index(options)).to eq(test_instance.unopened_notification_index(options))
347
+ expect(test_instance.notification_index(options)[0]).to eq(@notification1)
348
+ expect(test_instance.notification_index(options).size).to eq(1)
349
+ end
350
+ end
351
+
352
+ context "with reverse" do
353
+ it "returns the earliest order" do
354
+ options = { reverse: true }
355
+ expect(test_instance.notification_index(options)[0]).to eq(@notification2)
356
+ expect(test_instance.notification_index(options)[1]).to eq(@notification1)
357
+ expect(test_instance.notification_index(options)[2]).to eq(@notification3)
358
+ expect(test_instance.notification_index(options).size).to eq(3)
359
+ end
360
+ end
361
+
362
+ context "with with_group_members" do
363
+ it "returns the index with group members" do
364
+ options = { with_group_members: true }
365
+ expect(test_instance.notification_index(options)[0]).to eq(@member1)
366
+ expect(test_instance.notification_index(options)[1]).to eq(@notification1)
367
+ expect(test_instance.notification_index(options)[2]).to eq(@notification2)
368
+ expect(test_instance.notification_index(options)[3]).to eq(@notification3)
369
+ expect(test_instance.notification_index(options).size).to eq(4)
370
+ end
371
+ end
372
+
373
+ context "with as_latest_group_member" do
374
+ it "returns the index as latest group member" do
375
+ options = { as_latest_group_member: true }
376
+ expect(test_instance.notification_index(options)[0]).to eq(@member1)
377
+ expect(test_instance.notification_index(options)[1]).to eq(@notification2)
378
+ expect(test_instance.notification_index(options)[2]).to eq(@notification3)
379
+ expect(test_instance.notification_index(options).size).to eq(3)
380
+ end
381
+ end
382
+
383
+ context 'with filtered_by_type options' do
384
+ it "returns filtered notifications only" do
385
+ options = { filtered_by_type: 'Article' }
386
+ expect(test_instance.notification_index(options)[0]).to eq(@notification2)
387
+ expect(test_instance.notification_index(options)[1]).to eq(@notification3)
388
+ expect(test_instance.notification_index(options).size).to eq(2)
389
+ options = { filtered_by_type: 'Comment' }
390
+ expect(test_instance.notification_index(options)[0]).to eq(@notification1)
391
+ expect(test_instance.notification_index(options).size).to eq(1)
392
+ end
393
+ end
394
+
395
+ context 'with filtered_by_group options' do
396
+ it "returns filtered notifications only" do
397
+ options = { filtered_by_group: @group }
398
+ expect(test_instance.notification_index(options)[0]).to eq(@notification1)
399
+ expect(test_instance.notification_index(options).size).to eq(1)
400
+ end
401
+ end
402
+
403
+ context 'with filtered_by_group_type and :filtered_by_group_id options' do
404
+ it "returns filtered notifications only" do
405
+ options = { filtered_by_group_type: 'Article', filtered_by_group_id: @group.id.to_s }
406
+ expect(test_instance.notification_index(options)[0]).to eq(@notification1)
407
+ expect(test_instance.notification_index(options).size).to eq(1)
408
+ end
409
+ end
410
+
411
+ context 'with filtered_by_key options' do
412
+ it "returns filtered notifications only" do
413
+ options = { filtered_by_key: @key }
414
+ expect(test_instance.notification_index(options)[0]).to eq(@notification3)
415
+ expect(test_instance.notification_index(options).size).to eq(1)
416
+ end
417
+ end
418
+
419
+ context 'with custom_filter options' do
420
+ it "returns filtered notifications only" do
421
+ options = { custom_filter: ["key = ?", @key] }
422
+ expect(test_instance.notification_index(options)[0]).to eq(@notification3)
423
+ expect(test_instance.notification_index(options).size).to eq(1)
424
+
425
+ options = { custom_filter: { key: @key } }
426
+ expect(test_instance.notification_index(options)[0]).to eq(@notification3)
274
427
  expect(test_instance.notification_index(options).size).to eq(1)
275
428
  end
276
429
  end
@@ -453,9 +606,13 @@ shared_examples_for :target do
453
606
 
454
607
  context "when the target has unopened notifications" do
455
608
  before do
456
- create(:notification, target: test_instance)
457
- create(:notification, target: test_instance)
458
- create(:notification, target: test_instance).open!
609
+ @notifiable = create(:article)
610
+ @group = create(:article)
611
+ @key = 'test.key.1'
612
+ @notification2 = create(:notification, target: test_instance, notifiable: @notifiable)
613
+ @notification1 = create(:notification, target: test_instance, notifiable: create(:comment), group: @group)
614
+ @notification3 = create(:notification, target: test_instance, notifiable: create(:article), key: @key)
615
+ @notification3.open!
459
616
  end
460
617
 
461
618
  it "calls unopened_notification_index_with_attributes" do
@@ -463,19 +620,65 @@ shared_examples_for :target do
463
620
  test_instance.notification_index_with_attributes
464
621
  end
465
622
 
466
- context "without limit" do
467
- it "returns the combined array of unopened_notification_index and opened_notification_index" do
468
- expect(test_instance.notification_index_with_attributes[0]).to eq(test_instance.unopened_notification_index[0])
469
- expect(test_instance.notification_index_with_attributes[1]).to eq(test_instance.unopened_notification_index[1])
470
- expect(test_instance.notification_index_with_attributes[2]).to eq(test_instance.opened_notification_index[0])
471
- expect(test_instance.notification_index.size).to eq(3)
623
+ context "without any options" do
624
+ it "returns the combined array of unopened_notification_index_with_attributes and opened_notification_index_with_attributes" do
625
+ expect(test_instance.notification_index_with_attributes[0]).to eq(@notification1)
626
+ expect(test_instance.notification_index_with_attributes[1]).to eq(@notification2)
627
+ expect(test_instance.notification_index_with_attributes[2]).to eq(@notification3)
628
+ expect(test_instance.notification_index_with_attributes.size).to eq(3)
472
629
  end
473
630
  end
474
631
 
475
632
  context "with limit" do
476
633
  it "returns the same as unopened_notification_index_with_attributes with limit" do
477
634
  options = { limit: 1 }
478
- expect(test_instance.notification_index_with_attributes(options)).to eq(test_instance.unopened_notification_index_with_attributes(options))
635
+ expect(test_instance.notification_index_with_attributes(options)[0]).to eq(@notification1)
636
+ expect(test_instance.notification_index_with_attributes(options).size).to eq(1)
637
+ end
638
+ end
639
+
640
+ context "with reverse" do
641
+ it "returns the earliest order" do
642
+ options = { reverse: true }
643
+ expect(test_instance.notification_index_with_attributes(options)[0]).to eq(@notification2)
644
+ expect(test_instance.notification_index_with_attributes(options)[1]).to eq(@notification1)
645
+ expect(test_instance.notification_index_with_attributes(options)[2]).to eq(@notification3)
646
+ expect(test_instance.notification_index_with_attributes(options).size).to eq(3)
647
+ end
648
+ end
649
+
650
+ context 'with filtered_by_type options' do
651
+ it "returns filtered notifications only" do
652
+ options = { filtered_by_type: 'Article' }
653
+ expect(test_instance.notification_index_with_attributes(options)[0]).to eq(@notification2)
654
+ expect(test_instance.notification_index_with_attributes(options)[1]).to eq(@notification3)
655
+ expect(test_instance.notification_index_with_attributes(options).size).to eq(2)
656
+ options = { filtered_by_type: 'Comment' }
657
+ expect(test_instance.notification_index_with_attributes(options)[0]).to eq(@notification1)
658
+ expect(test_instance.notification_index_with_attributes(options).size).to eq(1)
659
+ end
660
+ end
661
+
662
+ context 'with filtered_by_group options' do
663
+ it "returns filtered notifications only" do
664
+ options = { filtered_by_group: @group }
665
+ expect(test_instance.notification_index_with_attributes(options)[0]).to eq(@notification1)
666
+ expect(test_instance.notification_index_with_attributes(options).size).to eq(1)
667
+ end
668
+ end
669
+
670
+ context 'with filtered_by_group_type and :filtered_by_group_id options' do
671
+ it "returns filtered notifications only" do
672
+ options = { filtered_by_group_type: 'Article', filtered_by_group_id: @group.id.to_s }
673
+ expect(test_instance.notification_index_with_attributes(options)[0]).to eq(@notification1)
674
+ expect(test_instance.notification_index_with_attributes(options).size).to eq(1)
675
+ end
676
+ end
677
+
678
+ context 'with filtered_by_key options' do
679
+ it "returns filtered notifications only" do
680
+ options = { filtered_by_key: @key }
681
+ expect(test_instance.notification_index_with_attributes(options)[0]).to eq(@notification3)
479
682
  expect(test_instance.notification_index_with_attributes(options).size).to eq(1)
480
683
  end
481
684
  end
@@ -510,8 +713,8 @@ shared_examples_for :target do
510
713
  end
511
714
 
512
715
  describe "#unopened_notification_index_with_attributes" do
513
- it "calls unopened_notification_index" do
514
- expect(test_instance).to receive(:unopened_notification_index)
716
+ it "calls _unopened_notification_index" do
717
+ expect(test_instance).to receive(:_unopened_notification_index)
515
718
  test_instance.unopened_notification_index_with_attributes
516
719
  end
517
720
 
@@ -568,8 +771,8 @@ shared_examples_for :target do
568
771
  end
569
772
 
570
773
  describe "#opened_notification_index_with_attributes" do
571
- it "calls opened_notification_index" do
572
- expect(test_instance).to receive(:opened_notification_index)
774
+ it "calls _opened_notification_index" do
775
+ expect(test_instance).to receive(:_opened_notification_index)
573
776
  test_instance.opened_notification_index_with_attributes
574
777
  end
575
778
 
@@ -625,6 +828,62 @@ shared_examples_for :target do
625
828
  end
626
829
  end
627
830
 
831
+ describe "#send_notification_email" do
832
+ context "with right target of notification" do
833
+ before do
834
+ @notification = create(:notification, target: test_instance)
835
+ end
836
+
837
+ it "calls notification.send_notification_email" do
838
+ expect(@notification).to receive(:send_notification_email).at_least(:once)
839
+ test_instance.send_notification_email(@notification)
840
+ end
841
+ end
842
+
843
+ context "with wrong target of notification" do
844
+ before do
845
+ @notification = create(:notification, target: create(:user))
846
+ end
847
+
848
+ it "does not call notification.send_notification_email" do
849
+ expect(@notification).not_to receive(:send_notification_email)
850
+ test_instance.send_notification_email(@notification)
851
+ end
852
+
853
+ it "returns nil" do
854
+ expect(test_instance.send_notification_email(@notification)).to be_nil
855
+ end
856
+ end
857
+ end
858
+
859
+ describe "#send_batch_notification_email" do
860
+ context "with right target of notification" do
861
+ before do
862
+ @notifications = [create(:notification, target: test_instance), create(:notification, target: test_instance)]
863
+ end
864
+
865
+ it "calls ActivityNotification::Notification.send_batch_notification_email" do
866
+ expect(ActivityNotification::Notification).to receive(:send_batch_notification_email).at_least(:once)
867
+ test_instance.send_batch_notification_email(@notifications)
868
+ end
869
+ end
870
+
871
+ context "with wrong target of notification" do
872
+ before do
873
+ notifications = [create(:notification, target: test_instance), create(:notification, target: create(:user))]
874
+ end
875
+
876
+ it "does not call ActivityNotification::Notification.send_batch_notification_email" do
877
+ expect(ActivityNotification::Notification).not_to receive(:send_batch_notification_email)
878
+ test_instance.send_batch_notification_email(@notifications)
879
+ end
880
+
881
+ it "returns nil" do
882
+ expect(test_instance.send_batch_notification_email(@notifications)).to be_nil
883
+ end
884
+ end
885
+ end
886
+
628
887
  end
629
888
 
630
889
  end