activity_notification 1.0.0 → 1.0.1

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