activity_notification 2.5.1 → 2.6.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 (54) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +2 -0
  3. data/app/channels/activity_notification/notification_api_channel.rb +5 -5
  4. data/app/channels/activity_notification/notification_api_with_devise_channel.rb +4 -4
  5. data/app/channels/activity_notification/notification_channel.rb +4 -0
  6. data/app/channels/activity_notification/notification_with_devise_channel.rb +4 -4
  7. data/app/controllers/activity_notification/notifications_controller.rb +1 -2
  8. data/app/controllers/activity_notification/subscriptions_controller.rb +2 -3
  9. data/app/jobs/activity_notification/notify_all_job.rb +2 -2
  10. data/app/jobs/activity_notification/notify_job.rb +2 -2
  11. data/app/jobs/activity_notification/notify_to_job.rb +1 -1
  12. data/app/mailers/activity_notification/mailer.rb +1 -1
  13. data/app/views/activity_notification/mailer/default/batch_default.text.erb +1 -1
  14. data/app/views/activity_notification/notifications/default/index.html.erb +1 -1
  15. data/app/views/activity_notification/subscriptions/default/_notification_keys.html.erb +1 -1
  16. data/app/views/activity_notification/subscriptions/default/_subscription.html.erb +1 -1
  17. data/docs/Functions.md +93 -9
  18. data/docs/Setup.md +7 -7
  19. data/docs/Testing.md +1 -1
  20. data/docs/Upgrade-to-2.6.md +108 -0
  21. data/lib/activity_notification/apis/notification_api.rb +55 -40
  22. data/lib/activity_notification/apis/subscription_api.rb +10 -10
  23. data/lib/activity_notification/common.rb +5 -5
  24. data/lib/activity_notification/config.rb +15 -5
  25. data/lib/activity_notification/controllers/common_controller.rb +2 -4
  26. data/lib/activity_notification/controllers/devise_authentication_controller.rb +2 -2
  27. data/lib/activity_notification/helpers/polymorphic_helpers.rb +6 -6
  28. data/lib/activity_notification/helpers/view_helpers.rb +3 -3
  29. data/lib/activity_notification/mailers/helpers.rb +88 -2
  30. data/lib/activity_notification/models/concerns/notifiable.rb +60 -30
  31. data/lib/activity_notification/models/concerns/notifier.rb +1 -1
  32. data/lib/activity_notification/models/concerns/subscriber.rb +72 -15
  33. data/lib/activity_notification/models/concerns/target.rb +38 -35
  34. data/lib/activity_notification/optional_targets/action_cable_api_channel.rb +1 -1
  35. data/lib/activity_notification/optional_targets/slack.rb +2 -2
  36. data/lib/activity_notification/orm/active_record/notification.rb +25 -25
  37. data/lib/activity_notification/orm/active_record/subscription.rb +21 -1
  38. data/lib/activity_notification/orm/dynamoid/extension.rb +3 -3
  39. data/lib/activity_notification/orm/dynamoid/subscription.rb +8 -1
  40. data/lib/activity_notification/orm/dynamoid.rb +18 -18
  41. data/lib/activity_notification/orm/mongoid/notification.rb +26 -28
  42. data/lib/activity_notification/orm/mongoid/subscription.rb +21 -1
  43. data/lib/activity_notification/orm/mongoid.rb +1 -1
  44. data/lib/activity_notification/rails/routes.rb +11 -11
  45. data/lib/activity_notification/roles/acts_as_group.rb +1 -1
  46. data/lib/activity_notification/roles/acts_as_notifiable.rb +5 -5
  47. data/lib/activity_notification/roles/acts_as_notifier.rb +1 -1
  48. data/lib/activity_notification/roles/acts_as_target.rb +1 -1
  49. data/lib/activity_notification/version.rb +1 -1
  50. data/lib/generators/activity_notification/add_notifiable_to_subscriptions/add_notifiable_to_subscriptions_generator.rb +23 -0
  51. data/lib/generators/activity_notification/add_notifiable_to_subscriptions/templates/add_notifiable_to_subscriptions.rb +13 -0
  52. data/lib/generators/templates/activity_notification.rb +14 -2
  53. data/lib/generators/templates/migrations/migration.rb +4 -2
  54. metadata +5 -2
@@ -9,7 +9,7 @@ module ActivityNotification
9
9
 
10
10
  # Has many notification instances of this target.
11
11
  # @scope instance
12
- # @return [Array<Notificaion>, Mongoid::Criteria<Notificaion>] Array or database query of notifications of this target
12
+ # @return [Array<Notification>, Mongoid::Criteria<Notification>] Array or database query of notifications of this target
13
13
  has_many_records :notifications,
14
14
  class_name: "::ActivityNotification::Notification",
15
15
  as: :target,
@@ -64,7 +64,7 @@ module ActivityNotification
64
64
  # @option options [String] :later_than (nil) ISO 8601 format time to filter notifications later than specified time
65
65
  # @option options [String] :earlier_than (nil) ISO 8601 format time to filter notifications earlier than specified time
66
66
  # @option options [Array|Hash] :custom_filter (nil) Custom notification filter (e.g. ["created_at >= ?", time.hour.ago])
67
- # @return [Array<Notificaion>] All notifications for this target type
67
+ # @return [Array<Notification>] All notifications for this target type
68
68
  def all_notifications(options = {})
69
69
  reverse = options[:reverse] || false
70
70
  with_group_members = options[:with_group_members] || false
@@ -106,7 +106,7 @@ module ActivityNotification
106
106
  # @option options [String] :later_than (nil) ISO 8601 format time to filter notifications later than specified time
107
107
  # @option options [String] :earlier_than (nil) ISO 8601 format time to filter notifications earlier than specified time
108
108
  # @option options [Array|Hash] :custom_filter (nil) Custom notification filter (e.g. ["created_at >= ?", time.hour.ago])
109
- # @return [Hash<Target, Notificaion>] All notifications for this target type grouped by targets
109
+ # @return [Hash<Target, Notification>] All notifications for this target type grouped by targets
110
110
  def notification_index_map(options = {})
111
111
  all_notifications(options).group_by(&:target)
112
112
  end
@@ -143,7 +143,7 @@ module ActivityNotification
143
143
  end
144
144
 
145
145
  # Resolves current authenticated target by devise authentication from current resource signed in with Devise.
146
- # This method is able to be overridden.
146
+ # This method can be overridden.
147
147
  #
148
148
  # @param [Object] current_resource Current resource signed in with Devise
149
149
  # @return [Object] Current authenticated target by devise authentication
@@ -160,7 +160,7 @@ module ActivityNotification
160
160
  end
161
161
 
162
162
  # Returns target email address for email notification.
163
- # This method is able to be overridden.
163
+ # This method can be overridden.
164
164
  #
165
165
  # @return [String] Target email address
166
166
  def mailer_to
@@ -168,7 +168,7 @@ module ActivityNotification
168
168
  end
169
169
 
170
170
  # Returns if sending notification email is allowed for the target from configured field or overridden method.
171
- # This method is able to be overridden.
171
+ # This method can be overridden.
172
172
  #
173
173
  # @param [Object] notifiable Notifiable instance of the notification
174
174
  # @param [String] key Key of the notification
@@ -178,7 +178,7 @@ module ActivityNotification
178
178
  end
179
179
 
180
180
  # Returns if sending batch notification email is allowed for the target from configured field or overridden method.
181
- # This method is able to be overridden.
181
+ # This method can be overridden.
182
182
  #
183
183
  # @param [String] key Key of the notifications
184
184
  # @return [Boolean] If sending batch notification email is allowed for the target
@@ -187,7 +187,7 @@ module ActivityNotification
187
187
  end
188
188
 
189
189
  # Returns if subscription management is allowed for the target from configured field or overridden method.
190
- # This method is able to be overridden.
190
+ # This method can be overridden.
191
191
  #
192
192
  # @param [String] key Key of the notifications
193
193
  # @return [Boolean] If subscription management is allowed for the target
@@ -197,7 +197,7 @@ module ActivityNotification
197
197
  alias_method :notification_subscription_allowed?, :subscription_allowed?
198
198
 
199
199
  # Returns if publishing WebSocket using ActionCable is allowed for the target from configured field or overridden method.
200
- # This method is able to be overridden.
200
+ # This method can be overridden.
201
201
  #
202
202
  # @param [Object] notifiable Notifiable instance of the notification
203
203
  # @param [String] key Key of the notification
@@ -228,7 +228,7 @@ module ActivityNotification
228
228
  end
229
229
 
230
230
  # Returns if current resource signed in with Devise is authenticated for the notification.
231
- # This method is able to be overridden.
231
+ # This method can be overridden.
232
232
  #
233
233
  # @param [Object] current_resource Current resource signed in with Devise
234
234
  # @return [Boolean] If current resource signed in with Devise is authenticated for the notification
@@ -288,8 +288,8 @@ module ActivityNotification
288
288
  # Returns automatically arranged notification index of the target.
289
289
  # This method is the typical way to get notification index from controller and view.
290
290
  # When the target has unopened notifications, it returns unopened notifications first.
291
- # Additionaly, it returns opened notifications unless unopened index size overs the limit.
292
- # @todo Is this conbimned array the best solution?
291
+ # Additionally, it returns opened notifications unless unopened index size overs the limit.
292
+ # @todo Is this combined array the best solution?
293
293
  #
294
294
  # @example Get automatically arranged notification index of @user
295
295
  # @notifications = @user.notification_index
@@ -307,7 +307,7 @@ module ActivityNotification
307
307
  # @option options [String] :later_than (nil) ISO 8601 format time to filter notifications later than specified time
308
308
  # @option options [String] :earlier_than (nil) ISO 8601 format time to filter notifications earlier than specified time
309
309
  # @option options [Array|Hash] :custom_filter (nil) Custom notification filter (e.g. ["created_at >= ?", time.hour.ago])
310
- # @return [Array<Notificaion>] Notification index of the target
310
+ # @return [Array<Notification>] Notification index of the target
311
311
  def notification_index(options = {})
312
312
  arrange_notification_index(method(:unopened_notification_index),
313
313
  method(:opened_notification_index),
@@ -332,7 +332,7 @@ module ActivityNotification
332
332
  # @option options [String] :later_than (nil) ISO 8601 format time to filter notifications later than specified time
333
333
  # @option options [String] :earlier_than (nil) ISO 8601 format time to filter notifications earlier than specified time
334
334
  # @option options [Array|Hash] :custom_filter (nil) Custom notification filter (e.g. ["created_at >= ?", time.hour.ago])
335
- # @return [Array<Notificaion>] Unopened notification index of the target
335
+ # @return [Array<Notification>] Unopened notification index of the target
336
336
  def unopened_notification_index(options = {})
337
337
  arrange_single_notification_index(method(:_unopened_notification_index), options)
338
338
  end
@@ -355,7 +355,7 @@ module ActivityNotification
355
355
  # @option options [String] :later_than (nil) ISO 8601 format time to filter notifications later than specified time
356
356
  # @option options [String] :earlier_than (nil) ISO 8601 format time to filter notifications earlier than specified time
357
357
  # @option options [Array|Hash] :custom_filter (nil) Custom notification filter (e.g. ["created_at >= ?", time.hour.ago])
358
- # @return [Array<Notificaion>] Opened notification index of the target
358
+ # @return [Array<Notification>] Opened notification index of the target
359
359
  def opened_notification_index(options = {})
360
360
  arrange_single_notification_index(method(:_opened_notification_index), options)
361
361
  end
@@ -374,7 +374,7 @@ module ActivityNotification
374
374
  # @option options [Boolean] :send_email (true) Whether it sends notification email
375
375
  # @option options [Boolean] :send_later (true) Whether it sends notification email asynchronously
376
376
  # @option options [Boolean] :publish_optional_targets (true) Whether it publishes notification to optional targets
377
- # @option options [Hash<String, Hash>] :optional_targets ({}) Options for optional targets, keys are optional target name (:amazon_sns or :slack etc) and values are options
377
+ # @option options [Hash<String, Hash>] :optional_targets ({}) Options for optional targets, keys are optional target name (:amazon_sns or :slack etc.) and values are options
378
378
  # @return [Notification] Generated notification instance
379
379
  def receive_notification_of(notifiable, options = {})
380
380
  Notification.notify_to(self, notifiable, options)
@@ -395,7 +395,7 @@ module ActivityNotification
395
395
  # @option options [Boolean] :send_email (true) Whether it sends notification email
396
396
  # @option options [Boolean] :send_later (true) Whether it sends notification email asynchronously
397
397
  # @option options [Boolean] :publish_optional_targets (true) Whether it publishes notification to optional targets
398
- # @option options [Hash<String, Hash>] :optional_targets ({}) Options for optional targets, keys are optional target name (:amazon_sns or :slack etc) and values are options
398
+ # @option options [Hash<String, Hash>] :optional_targets ({}) Options for optional targets, keys are optional target name (:amazon_sns or :slack etc.) and values are options
399
399
  # @return [Notification] Generated notification instance
400
400
  def receive_notification_later_of(notifiable, options = {})
401
401
  Notification.notify_later_to(self, notifiable, options)
@@ -439,7 +439,7 @@ module ActivityNotification
439
439
  # Gets automatically arranged notification index of the target with included attributes like target, notifiable, group and notifier.
440
440
  # This method is the typical way to get notifications index from controller of view.
441
441
  # When the target have unopened notifications, it returns unopened notifications first.
442
- # Additionaly, it returns opened notifications unless unopened index size overs the limit.
442
+ # Additionally, it returns opened notifications unless unopened index size overs the limit.
443
443
  # @todo Is this switching the best solution?
444
444
  #
445
445
  # @example Get automatically arranged notification index of the @user with included attributes
@@ -461,7 +461,7 @@ module ActivityNotification
461
461
  # @option options [String] :later_than (nil) ISO 8601 format time to filter notifications later than specified time
462
462
  # @option options [String] :earlier_than (nil) ISO 8601 format time to filter notifications earlier than specified time
463
463
  # @option options [Array|Hash] :custom_filter (nil) Custom notification filter (e.g. ["created_at >= ?", time.hour.ago])
464
- # @return [Array<Notificaion>] Notification index of the target with attributes
464
+ # @return [Array<Notification>] Notification index of the target with attributes
465
465
  def notification_index_with_attributes(options = {})
466
466
  arrange_notification_index(method(:unopened_notification_index_with_attributes),
467
467
  method(:opened_notification_index_with_attributes),
@@ -486,7 +486,7 @@ module ActivityNotification
486
486
  # @option options [String] :later_than (nil) ISO 8601 format time to filter notifications later than specified time
487
487
  # @option options [String] :earlier_than (nil) ISO 8601 format time to filter notifications earlier than specified time
488
488
  # @option options [Array|Hash] :custom_filter (nil) Custom notification filter (e.g. ["created_at >= ?", time.hour.ago])
489
- # @return [Array<Notificaion>] Unopened notification index of the target with attributes
489
+ # @return [Array<Notification>] Unopened notification index of the target with attributes
490
490
  def unopened_notification_index_with_attributes(options = {})
491
491
  include_attributes(_unopened_notification_index(options)).to_a
492
492
  end
@@ -509,7 +509,7 @@ module ActivityNotification
509
509
  # @option options [String] :later_than (nil) ISO 8601 format time to filter notifications later than specified time
510
510
  # @option options [String] :earlier_than (nil) ISO 8601 format time to filter notifications earlier than specified time
511
511
  # @option options [Array|Hash] :custom_filter (nil) Custom notification filter (e.g. ["created_at >= ?", time.hour.ago])
512
- # @return [Array<Notificaion>] Opened notification index of the target with attributes
512
+ # @return [Array<Notification>] Opened notification index of the target with attributes
513
513
  def opened_notification_index_with_attributes(options = {})
514
514
  include_attributes(_opened_notification_index(options)).to_a
515
515
  end
@@ -545,17 +545,20 @@ module ActivityNotification
545
545
  # It also returns true when the subscription management is not allowed for the target.
546
546
  #
547
547
  # @param [String] key Key of the notification
548
- # @param [Boolean] subscribe_as_default Default subscription value to use when the subscription record does not configured
548
+ # @param [Boolean] subscribe_as_default Default subscription value to use when the subscription record is not configured
549
+ # @param [Object] notifiable Optional notifiable instance for instance-level subscription check
549
550
  # @return [Boolean] If the target subscribes the notification or the subscription management is not allowed for the target
550
- def subscribes_to_notification?(key, subscribe_as_default = ActivityNotification.config.subscribe_as_default)
551
- !subscription_allowed?(key) || _subscribes_to_notification?(key, subscribe_as_default)
551
+ def subscribes_to_notification?(key, subscribe_as_default = ActivityNotification.config.subscribe_as_default, notifiable: nil)
552
+ return true unless subscription_allowed?(key)
553
+ _subscribes_to_notification?(key, subscribe_as_default) ||
554
+ (notifiable.present? && _subscribes_to_notification_for_instance?(key, notifiable))
552
555
  end
553
556
 
554
557
  # Returns if the target subscribes to the notification email.
555
558
  # It also returns true when the subscription management is not allowed for the target.
556
559
  #
557
560
  # @param [String] key Key of the notification
558
- # @param [Boolean] subscribe_as_default Default subscription value to use when the subscription record does not configured
561
+ # @param [Boolean] subscribe_as_default Default subscription value to use when the subscription record is not configured
559
562
  # @return [Boolean] If the target subscribes the notification email or the subscription management is not allowed for the target
560
563
  def subscribes_to_notification_email?(key, subscribe_as_default = ActivityNotification.config.subscribe_to_email_as_default)
561
564
  !subscription_allowed?(key) || _subscribes_to_notification_email?(key, subscribe_as_default)
@@ -567,7 +570,7 @@ module ActivityNotification
567
570
  #
568
571
  # @param [String] key Key of the notification
569
572
  # @param [String, Symbol] optional_target_name Class name of the optional target implementation (e.g. :amazon_sns, :slack)
570
- # @param [Boolean] subscribe_as_default Default subscription value to use when the subscription record does not configured
573
+ # @param [Boolean] subscribe_as_default Default subscription value to use when the subscription record is not configured
571
574
  # @return [Boolean] If the target subscribes the notification email or the subscription management is not allowed for the target
572
575
  def subscribes_to_optional_target?(key, optional_target_name, subscribe_as_default = ActivityNotification.config.subscribe_to_optional_targets_as_default)
573
576
  !subscription_allowed?(key) || _subscribes_to_optional_target?(key, optional_target_name, subscribe_as_default)
@@ -590,7 +593,7 @@ module ActivityNotification
590
593
  # @option options [String] :later_than (nil) ISO 8601 format time to filter notifications later than specified time
591
594
  # @option options [String] :earlier_than (nil) ISO 8601 format time to filter notifications earlier than specified time
592
595
  # @option options [Array|Hash] :custom_filter (nil) Custom notification filter (e.g. ["created_at >= ?", time.hour.ago])
593
- # @return [ActiveRecord_AssociationRelation<Notificaion>|Mongoid::Criteria<Notificaion>|Dynamoid::Criteria::Chain] Unopened notification index of the target
596
+ # @return [ActiveRecord_AssociationRelation<Notification>|Mongoid::Criteria<Notification>|Dynamoid::Criteria::Chain] Unopened notification index of the target
594
597
  def _unopened_notification_index(options = {})
595
598
  reverse = options[:reverse] || false
596
599
  with_group_members = options[:with_group_members] || false
@@ -612,7 +615,7 @@ module ActivityNotification
612
615
  # @option options [String] :later_than (nil) ISO 8601 format time to filter notifications later than specified time
613
616
  # @option options [String] :earlier_than (nil) ISO 8601 format time to filter notifications earlier than specified time
614
617
  # @option options [Array|Hash] :custom_filter (nil) Custom notification filter (e.g. ["created_at >= ?", time.hour.ago])
615
- # @return [ActiveRecord_AssociationRelation<Notificaion>|Mongoid::Criteria<Notificaion>|Dynamoid::Criteria::Chain] Opened notification index of the target
618
+ # @return [ActiveRecord_AssociationRelation<Notification>|Mongoid::Criteria<Notification>|Dynamoid::Criteria::Chain] Opened notification index of the target
616
619
  def _opened_notification_index(options = {})
617
620
  limit = options[:limit] || ActivityNotification.config.opened_index_limit
618
621
  reverse = options[:reverse] || false
@@ -622,11 +625,11 @@ module ActivityNotification
622
625
 
623
626
  # Includes attributes like target, notifiable, group or notifier from the notification index.
624
627
  # When group member exists in the notification index, group will be included in addition to target, notifiable and or notifier.
625
- # Otherwise, target, notifiable and or notifier will be include without group.
628
+ # Otherwise, target, notifiable and or notifier will be included without group.
626
629
  # @api private
627
630
  #
628
- # @param [ActiveRecord_AssociationRelation<Notificaion>|Mongoid::Criteria<Notificaion>|Dynamoid::Criteria::Chain] target_index Notification index
629
- # @return [ActiveRecord_AssociationRelation<Notificaion>|Mongoid::Criteria<Notificaion>|Dynamoid::Criteria::Chain] Notification index with attributes
631
+ # @param [ActiveRecord_AssociationRelation<Notification>|Mongoid::Criteria<Notification>|Dynamoid::Criteria::Chain] target_index Notification index
632
+ # @return [ActiveRecord_AssociationRelation<Notification>|Mongoid::Criteria<Notification>|Dynamoid::Criteria::Chain] Notification index with attributes
630
633
  def include_attributes(target_index)
631
634
  if target_index.present?
632
635
  Notification.group_member_exists?(target_index.to_a) ?
@@ -654,7 +657,7 @@ module ActivityNotification
654
657
  # @option options [String] :later_than (nil) ISO 8601 format time to filter notifications later than specified time
655
658
  # @option options [String] :earlier_than (nil) ISO 8601 format time to filter notifications earlier than specified time
656
659
  # @option options [Array|Hash] :custom_filter (nil) Custom notification filter (e.g. ["created_at >= ?", time.hour.ago])
657
- # @return [Array<Notificaion>] Notification index of the target
660
+ # @return [Array<Notification>] Notification index of the target
658
661
  def arrange_single_notification_index(loading_index_method, options = {})
659
662
  as_latest_group_member = options[:as_latest_group_member] || false
660
663
  as_latest_group_member ?
@@ -664,7 +667,7 @@ module ActivityNotification
664
667
 
665
668
  # Gets automatically arranged notification index of the target.
666
669
  # When the target have unopened notifications, it returns unopened notifications first.
667
- # Additionaly, it returns opened notifications unless unopened index size overs the limit.
670
+ # Additionally, it returns opened notifications unless unopened index size overs the limit.
668
671
  # @api private
669
672
  # @todo Is this switching the best solution?
670
673
  #
@@ -683,7 +686,7 @@ module ActivityNotification
683
686
  # @option options [String] :later_than (nil) ISO 8601 format time to filter notifications later than specified time
684
687
  # @option options [String] :earlier_than (nil) ISO 8601 format time to filter notifications earlier than specified time
685
688
  # @option options [Array|Hash] :custom_filter (nil) Custom notification filter (e.g. ["created_at >= ?", time.hour.ago])
686
- # @return [Array<Notificaion>] Notification index of the target
689
+ # @return [Array<Notification>] Notification index of the target
687
690
  def arrange_notification_index(loading_unopened_index_method, loading_opened_index_method, options = {})
688
691
  # When the target have unopened notifications
689
692
  if has_unopened_notifications?(options)
@@ -691,7 +694,7 @@ module ActivityNotification
691
694
  target_unopened_index = arrange_single_notification_index(loading_unopened_index_method, options)
692
695
  # Total limit of notification index
693
696
  total_limit = options[:limit] || ActivityNotification.config.opened_index_limit
694
- # Additionaly, return opened notifications unless unopened index size overs the limit
697
+ # Additionally, return opened notifications unless unopened index size overs the limit
695
698
  if (opened_limit = total_limit - target_unopened_index.size) > 0
696
699
  target_opened_index = arrange_single_notification_index(loading_opened_index_method, options.merge(limit: opened_limit))
697
700
  target_unopened_index.concat(target_opened_index.to_a)
@@ -57,7 +57,7 @@ module ActivityNotification
57
57
  }
58
58
  end
59
59
 
60
- # Overriden rendering notification message using format_message
60
+ # Overridden rendering notification message using format_message
61
61
  # @param [Notification] notification Notification instance
62
62
  # @param [Hash] options Options for rendering
63
63
  # @return [String] Rendered json formatted message to broadcast
@@ -6,7 +6,7 @@ module ActivityNotification
6
6
 
7
7
  # Initialize method to prepare Slack::Notifier
8
8
  # @param [Hash] options Options for initializing
9
- # @option options [String, Proc, Symbol] :target_username (nil) Target user name of Slack, it resolved by target instance like email_allowed?
9
+ # @option options [String, Proc, Symbol] :target_username (nil) Target username of Slack, it resolved by target instance like email_allowed?
10
10
  # @option options [required, String] :webhook_url (nil) Webhook URL of Slack Incoming WebHooks integration
11
11
  # @option options [Hash] others Other options to be set Slack::Notifier.new, like :channel, :username, :icon_emoji etc
12
12
  def initialize_target(options = {})
@@ -17,7 +17,7 @@ module ActivityNotification
17
17
  # Publishes notification message to Slack
18
18
  # @param [Notification] notification Notification instance
19
19
  # @param [Hash] options Options for publishing
20
- # @option options [String, Proc, Symbol] :target_username (nil) Target user name of Slack, it resolved by target instance like email_allowed?
20
+ # @option options [String, Proc, Symbol] :target_username (nil) Target username of Slack, it resolved by target instance like email_allowed?
21
21
  # @option options [String] :partial_root ("activity_notification/optional_targets/#{target}/#{optional_target_name}", "activity_notification/optional_targets/#{target}/base", "activity_notification/optional_targets/default/#{optional_target_name}", "activity_notification/optional_targets/default/base") Partial template name
22
22
  # @option options [String] :partial (self.key.tr('.', '/')) Root path of partial template
23
23
  # @option options [String] :layout (nil) Layout template name
@@ -36,7 +36,7 @@ module ActivityNotification
36
36
  # Only group owner instance has :group_members value.
37
37
  # Group member instance has nil as :group_members association.
38
38
  # @scope instance
39
- # @return [ActiveRecord_AssociationRelation<Notificaion>] Database query of the group member notification instances of this notification
39
+ # @return [ActiveRecord_AssociationRelation<Notification>] Database query of the group member notification instances of this notification
40
40
  has_many :group_members, class_name: "ActivityNotification::Notification", foreign_key: :group_owner_id
41
41
 
42
42
  # Belongs to :notifier instance of this notification.
@@ -59,52 +59,52 @@ module ActivityNotification
59
59
 
60
60
  # Selects group owner notifications only.
61
61
  # @scope class
62
- # @return [ActiveRecord_AssociationRelation<Notificaion>] Database query of filtered notifications
62
+ # @return [ActiveRecord_AssociationRelation<Notification>] Database query of filtered notifications
63
63
  scope :group_owners_only, -> { where(group_owner_id: nil) }
64
64
 
65
65
  # Selects group member notifications only.
66
66
  # @scope class
67
- # @return [ActiveRecord_AssociationRelation<Notificaion>] Database query of filtered notifications
67
+ # @return [ActiveRecord_AssociationRelation<Notification>] Database query of filtered notifications
68
68
  scope :group_members_only, -> { where.not(group_owner_id: nil) }
69
69
 
70
70
  # Selects unopened notifications only.
71
71
  # @scope class
72
- # @return [ActiveRecord_AssociationRelation<Notificaion>] Database query of filtered notifications
72
+ # @return [ActiveRecord_AssociationRelation<Notification>] Database query of filtered notifications
73
73
  scope :unopened_only, -> { where(opened_at: nil) }
74
74
 
75
75
  # Selects opened notifications only without limit.
76
76
  # Be careful to get too many records with this method.
77
77
  # @scope class
78
- # @return [ActiveRecord_AssociationRelation<Notificaion>] Database query of filtered notifications
78
+ # @return [ActiveRecord_AssociationRelation<Notification>] Database query of filtered notifications
79
79
  scope :opened_only!, -> { where.not(opened_at: nil) }
80
80
 
81
81
  # Selects opened notifications only with limit.
82
82
  # @scope class
83
83
  # @param [Integer] limit Limit to query for opened notifications
84
- # @return [ActiveRecord_AssociationRelation<Notificaion>] Database query of filtered notifications
84
+ # @return [ActiveRecord_AssociationRelation<Notification>] Database query of filtered notifications
85
85
  scope :opened_only, ->(limit) { opened_only!.limit(limit) }
86
86
 
87
87
  # Selects group member notifications in unopened_index.
88
88
  # @scope class
89
- # @return [ActiveRecord_AssociationRelation<Notificaion>] Database query of filtered notifications
89
+ # @return [ActiveRecord_AssociationRelation<Notification>] Database query of filtered notifications
90
90
  scope :unopened_index_group_members_only, -> { where(group_owner_id: unopened_index.map(&:id)) }
91
91
 
92
92
  # Selects group member notifications in opened_index.
93
93
  # @scope class
94
94
  # @param [Integer] limit Limit to query for opened notifications
95
- # @return [ActiveRecord_AssociationRelation<Notificaion>] Database query of filtered notifications
95
+ # @return [ActiveRecord_AssociationRelation<Notification>] Database query of filtered notifications
96
96
  scope :opened_index_group_members_only, ->(limit) { where(group_owner_id: opened_index(limit).map(&:id)) }
97
97
 
98
98
  # Selects notifications within expiration.
99
99
  # @scope class
100
100
  # @param [ActiveSupport::Duration] expiry_delay Expiry period of notifications
101
- # @return [ActiveRecord_AssociationRelation<Notificaion>] Database query of filtered notifications
101
+ # @return [ActiveRecord_AssociationRelation<Notification>] Database query of filtered notifications
102
102
  scope :within_expiration_only, ->(expiry_delay) { where("created_at > ?", expiry_delay.ago) }
103
103
 
104
104
  # Selects group member notifications with specified group owner ids.
105
105
  # @scope class
106
106
  # @param [Array<String>] owner_ids Array of group owner ids
107
- # @return [ActiveRecord_AssociationRelation<Notificaion>] Database query of filtered notifications
107
+ # @return [ActiveRecord_AssociationRelation<Notification>] Database query of filtered notifications
108
108
  scope :group_members_of_owner_ids_only, ->(owner_ids) { where(group_owner_id: owner_ids) }
109
109
 
110
110
  # Selects filtered notifications by target instance.
@@ -113,63 +113,63 @@ module ActivityNotification
113
113
  # @user.notifications
114
114
  # @scope class
115
115
  # @param [Object] target Target instance for filter
116
- # @return [ActiveRecord_AssociationRelation<Notificaion>] Database query of filtered notifications
116
+ # @return [ActiveRecord_AssociationRelation<Notification>] Database query of filtered notifications
117
117
  scope :filtered_by_target, ->(target) { where(target: target) }
118
118
 
119
119
  # Selects filtered notifications by notifiable instance.
120
- # @example Get filtered unopened notificatons of the @user for @comment as notifiable
120
+ # @example Get filtered unopened notifications of the @user for @comment as notifiable
121
121
  # @notifications = @user.notifications.unopened_only.filtered_by_instance(@comment)
122
122
  # @scope class
123
123
  # @param [Object] notifiable Notifiable instance for filter
124
- # @return [ActiveRecord_AssociationRelation<Notificaion>] Database query of filtered notifications
124
+ # @return [ActiveRecord_AssociationRelation<Notification>] Database query of filtered notifications
125
125
  scope :filtered_by_instance, ->(notifiable) { where(notifiable: notifiable) }
126
126
 
127
127
  # Selects filtered notifications by group instance.
128
- # @example Get filtered unopened notificatons of the @user for @article as group
128
+ # @example Get filtered unopened notifications of the @user for @article as group
129
129
  # @notifications = @user.notifications.unopened_only.filtered_by_group(@article)
130
130
  # @scope class
131
131
  # @param [Object] group Group instance for filter
132
- # @return [ActiveRecord_AssociationRelation<Notificaion>] Database query of filtered notifications
132
+ # @return [ActiveRecord_AssociationRelation<Notification>] Database query of filtered notifications
133
133
  scope :filtered_by_group, ->(group) { where(group: group) }
134
134
 
135
135
  # Selects filtered notifications later than specified time.
136
- # @example Get filtered unopened notificatons of the @user later than @notification
136
+ # @example Get filtered unopened notifications of the @user later than @notification
137
137
  # @notifications = @user.notifications.unopened_only.later_than(@notification.created_at)
138
138
  # @scope class
139
139
  # @param [Time] Created time of the notifications for filter
140
- # @return [ActiveRecord_AssociationRelation<Notificaion>, Mongoid::Criteria<Notificaion>] Database query of filtered notifications
140
+ # @return [ActiveRecord_AssociationRelation<Notification>, Mongoid::Criteria<Notification>] Database query of filtered notifications
141
141
  scope :later_than, ->(created_time) { where('created_at > ?', created_time) }
142
142
 
143
143
  # Selects filtered notifications earlier than specified time.
144
- # @example Get filtered unopened notificatons of the @user earlier than @notification
144
+ # @example Get filtered unopened notifications of the @user earlier than @notification
145
145
  # @notifications = @user.notifications.unopened_only.earlier_than(@notification.created_at)
146
146
  # @scope class
147
147
  # @param [Time] Created time of the notifications for filter
148
- # @return [ActiveRecord_AssociationRelation<Notificaion>, Mongoid::Criteria<Notificaion>] Database query of filtered notifications
148
+ # @return [ActiveRecord_AssociationRelation<Notification>, Mongoid::Criteria<Notification>] Database query of filtered notifications
149
149
  scope :earlier_than, ->(created_time) { where('created_at < ?', created_time) }
150
150
 
151
151
  # Includes target instance with query for notifications.
152
- # @return [ActiveRecord_AssociationRelation<Notificaion>] Database query of notifications with target
152
+ # @return [ActiveRecord_AssociationRelation<Notification>] Database query of notifications with target
153
153
  scope :with_target, -> { includes(:target) }
154
154
 
155
155
  # Includes notifiable instance with query for notifications.
156
- # @return [ActiveRecord_AssociationRelation<Notificaion>] Database query of notifications with notifiable
156
+ # @return [ActiveRecord_AssociationRelation<Notification>] Database query of notifications with notifiable
157
157
  scope :with_notifiable, -> { includes(:notifiable) }
158
158
 
159
159
  # Includes group instance with query for notifications.
160
- # @return [ActiveRecord_AssociationRelation<Notificaion>] Database query of notifications with group
160
+ # @return [ActiveRecord_AssociationRelation<Notification>] Database query of notifications with group
161
161
  scope :with_group, -> { includes(:group) }
162
162
 
163
163
  # Includes group owner instances with query for notifications.
164
- # @return [ActiveRecord_AssociationRelation<Notificaion>] Database query of notifications with group owner
164
+ # @return [ActiveRecord_AssociationRelation<Notification>] Database query of notifications with group owner
165
165
  scope :with_group_owner, -> { includes(:group_owner) }
166
166
 
167
167
  # Includes group member instances with query for notifications.
168
- # @return [ActiveRecord_AssociationRelation<Notificaion>] Database query of notifications with group members
168
+ # @return [ActiveRecord_AssociationRelation<Notification>] Database query of notifications with group members
169
169
  scope :with_group_members, -> { includes(:group_members) }
170
170
 
171
171
  # Includes notifier instance with query for notifications.
172
- # @return [ActiveRecord_AssociationRelation<Notificaion>] Database query of notifications with notifier
172
+ # @return [ActiveRecord_AssociationRelation<Notification>] Database query of notifications with notifier
173
173
  scope :with_notifier, -> { includes(:notifier) }
174
174
 
175
175
  # Raise DeleteRestrictionError for notifications.
@@ -13,6 +13,13 @@ module ActivityNotification
13
13
  # @return [Object] Target instance of this subscription
14
14
  belongs_to :target, polymorphic: true
15
15
 
16
+ # Belongs to notifiable instance of this subscription as polymorphic association (optional).
17
+ # When present, this subscription is scoped to a specific notifiable instance.
18
+ # When nil, this is a key-level subscription that applies globally.
19
+ # @scope instance
20
+ # @return [Object, nil] Notifiable instance of this subscription
21
+ belongs_to :notifiable, polymorphic: true, optional: true
22
+
16
23
  # Serialize parameters Hash
17
24
  # :nocov:
18
25
  if Rails.gem_version >= Gem::Version.new('7.1')
@@ -23,7 +30,7 @@ module ActivityNotification
23
30
  # :nocov:
24
31
 
25
32
  validates :target, presence: true
26
- validates :key, presence: true, uniqueness: { scope: :target }
33
+ validates :key, presence: true, uniqueness: { scope: [:target_type, :target_id, :notifiable_type, :notifiable_id] }
27
34
  validates_inclusion_of :subscribing, in: [true, false]
28
35
  validates_inclusion_of :subscribing_to_email, in: [true, false]
29
36
  validate :subscribing_to_email_cannot_be_true_when_subscribing_is_false
@@ -46,6 +53,19 @@ module ActivityNotification
46
53
  # @return [ActiveRecord_AssociationRelation<Subscription>] Database query of subscriptions with target
47
54
  scope :with_target, -> { includes(:target) }
48
55
 
56
+ # Selects key-level subscriptions only (where notifiable is nil).
57
+ # @return [ActiveRecord_AssociationRelation<Subscription>] Database query of key-level subscriptions
58
+ scope :key_level_only, -> { where(notifiable_type: nil) }
59
+
60
+ # Selects instance-level subscriptions only (where notifiable is present).
61
+ # @return [ActiveRecord_AssociationRelation<Subscription>] Database query of instance-level subscriptions
62
+ scope :instance_level_only, -> { where.not(notifiable_type: nil) }
63
+
64
+ # Selects subscriptions for a specific notifiable instance.
65
+ # @param [Object] notifiable Notifiable instance for filter
66
+ # @return [ActiveRecord_AssociationRelation<Subscription>] Database query of filtered subscriptions
67
+ scope :for_notifiable, ->(notifiable) { where(notifiable_type: notifiable.class.name, notifiable_id: notifiable.id) }
68
+
49
69
  # Selects unique keys from query for subscriptions.
50
70
  # @return [Array<String>] Array of subscription unique keys
51
71
  def self.uniq_keys
@@ -1,6 +1,6 @@
1
1
  require 'dynamoid/adapter_plugin/aws_sdk_v3'
2
2
 
3
- # Entend Dynamoid v3.1.0 to support none, limit, exists?, update_all, serializable_hash in Dynamoid::Criteria::Chain.
3
+ # Extend Dynamoid v3.1.0 to support none, limit, exists?, update_all, serializable_hash in Dynamoid::Criteria::Chain.
4
4
  # ActivityNotification project will try to contribute these fundamental functions to Dynamoid upstream.
5
5
  # @private
6
6
  module Dynamoid # :nodoc: all
@@ -83,13 +83,13 @@ module Dynamoid # :nodoc: all
83
83
  end
84
84
  end
85
85
 
86
- # Entend Dynamoid to support uniqueness validator
86
+ # Extend Dynamoid to support uniqueness validator
87
87
  # @private
88
88
  module Dynamoid # :nodoc: all
89
89
  # https://github.com/Dynamoid/dynamoid/blob/master/lib/dynamoid/validations.rb
90
90
  # @private
91
91
  module Validations
92
- # Validates whether or not a field is unique against the records in the database.
92
+ # Validates whether a field is unique against the records in the database.
93
93
  class UniquenessValidator < ActiveModel::EachValidator
94
94
  # Validate the document for uniqueness violations.
95
95
  # @param [Document] document The document to validate.
@@ -19,6 +19,13 @@ module ActivityNotification
19
19
  # @return [Object] Target instance of this subscription
20
20
  belongs_to_composite_xdb_record :target
21
21
 
22
+ # Belongs to notifiable instance of this subscription as polymorphic association using composite key (optional).
23
+ # When present, this subscription is scoped to a specific notifiable instance.
24
+ # When nil, this is a key-level subscription that applies globally.
25
+ # @scope instance
26
+ # @return [Object, nil] Notifiable instance of this subscription
27
+ belongs_to_composite_xdb_record :notifiable, optional: true
28
+
22
29
  field :key, :string
23
30
  field :subscribing, :boolean, default: ActivityNotification.config.subscribe_as_default
24
31
  field :subscribing_to_email, :boolean, default: ActivityNotification.config.subscribe_to_email_as_default
@@ -31,7 +38,7 @@ module ActivityNotification
31
38
  global_secondary_index name: :index_target_key_created_at, hash_key: :target_key, range_key: :created_at, projected_attributes: :all
32
39
 
33
40
  validates :target, presence: true
34
- validates :key, presence: true, uniqueness: { scope: :target_key }
41
+ validates :key, presence: true, uniqueness: { scope: [:target_key, :notifiable_key] }
35
42
  validates_inclusion_of :subscribing, in: [true, false]
36
43
  validates_inclusion_of :subscribing_to_email, in: [true, false]
37
44
  validate :subscribing_to_email_cannot_be_true_when_subscribing_is_false