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.
- checksums.yaml +4 -4
- data/README.md +2 -0
- data/app/channels/activity_notification/notification_api_channel.rb +5 -5
- data/app/channels/activity_notification/notification_api_with_devise_channel.rb +4 -4
- data/app/channels/activity_notification/notification_channel.rb +4 -0
- data/app/channels/activity_notification/notification_with_devise_channel.rb +4 -4
- data/app/controllers/activity_notification/notifications_controller.rb +1 -2
- data/app/controllers/activity_notification/subscriptions_controller.rb +2 -3
- data/app/jobs/activity_notification/notify_all_job.rb +2 -2
- data/app/jobs/activity_notification/notify_job.rb +2 -2
- data/app/jobs/activity_notification/notify_to_job.rb +1 -1
- data/app/mailers/activity_notification/mailer.rb +1 -1
- data/app/views/activity_notification/mailer/default/batch_default.text.erb +1 -1
- data/app/views/activity_notification/notifications/default/index.html.erb +1 -1
- data/app/views/activity_notification/subscriptions/default/_notification_keys.html.erb +1 -1
- data/app/views/activity_notification/subscriptions/default/_subscription.html.erb +1 -1
- data/docs/Functions.md +93 -9
- data/docs/Setup.md +7 -7
- data/docs/Testing.md +1 -1
- data/docs/Upgrade-to-2.6.md +108 -0
- data/lib/activity_notification/apis/notification_api.rb +55 -40
- data/lib/activity_notification/apis/subscription_api.rb +10 -10
- data/lib/activity_notification/common.rb +5 -5
- data/lib/activity_notification/config.rb +15 -5
- data/lib/activity_notification/controllers/common_controller.rb +2 -4
- data/lib/activity_notification/controllers/devise_authentication_controller.rb +2 -2
- data/lib/activity_notification/helpers/polymorphic_helpers.rb +6 -6
- data/lib/activity_notification/helpers/view_helpers.rb +3 -3
- data/lib/activity_notification/mailers/helpers.rb +88 -2
- data/lib/activity_notification/models/concerns/notifiable.rb +60 -30
- data/lib/activity_notification/models/concerns/notifier.rb +1 -1
- data/lib/activity_notification/models/concerns/subscriber.rb +72 -15
- data/lib/activity_notification/models/concerns/target.rb +38 -35
- data/lib/activity_notification/optional_targets/action_cable_api_channel.rb +1 -1
- data/lib/activity_notification/optional_targets/slack.rb +2 -2
- data/lib/activity_notification/orm/active_record/notification.rb +25 -25
- data/lib/activity_notification/orm/active_record/subscription.rb +21 -1
- data/lib/activity_notification/orm/dynamoid/extension.rb +3 -3
- data/lib/activity_notification/orm/dynamoid/subscription.rb +8 -1
- data/lib/activity_notification/orm/dynamoid.rb +18 -18
- data/lib/activity_notification/orm/mongoid/notification.rb +26 -28
- data/lib/activity_notification/orm/mongoid/subscription.rb +21 -1
- data/lib/activity_notification/orm/mongoid.rb +1 -1
- data/lib/activity_notification/rails/routes.rb +11 -11
- data/lib/activity_notification/roles/acts_as_group.rb +1 -1
- data/lib/activity_notification/roles/acts_as_notifiable.rb +5 -5
- data/lib/activity_notification/roles/acts_as_notifier.rb +1 -1
- data/lib/activity_notification/roles/acts_as_target.rb +1 -1
- data/lib/activity_notification/version.rb +1 -1
- data/lib/generators/activity_notification/add_notifiable_to_subscriptions/add_notifiable_to_subscriptions_generator.rb +23 -0
- data/lib/generators/activity_notification/add_notifiable_to_subscriptions/templates/add_notifiable_to_subscriptions.rb +13 -0
- data/lib/generators/templates/activity_notification.rb +14 -2
- data/lib/generators/templates/migrations/migration.rb +4 -2
- metadata +5 -2
|
@@ -25,7 +25,7 @@ module ActivityNotification
|
|
|
25
25
|
# @notifications = @user.notifications.group_owners_only.latest_order
|
|
26
26
|
# @param [Boolean] reverse If notification index will be ordered as earliest first
|
|
27
27
|
# @param [Boolean] with_group_members If notification index will include group members
|
|
28
|
-
# @return [ActiveRecord_AssociationRelation<
|
|
28
|
+
# @return [ActiveRecord_AssociationRelation<Notification>, Mongoid::Criteria<Notification>] Database query of filtered notifications
|
|
29
29
|
scope :all_index!, ->(reverse = false, with_group_members = false) {
|
|
30
30
|
target_index = with_group_members ? self : group_owners_only
|
|
31
31
|
reverse ? target_index.earliest_order : target_index.latest_order
|
|
@@ -36,12 +36,12 @@ module ActivityNotification
|
|
|
36
36
|
# is defined same as
|
|
37
37
|
# ActivityNotification::Notification.unopened_only.group_owners_only.latest_order
|
|
38
38
|
# @scope class
|
|
39
|
-
# @example Get unopened
|
|
39
|
+
# @example Get unopened notification index of the @user
|
|
40
40
|
# @notifications = @user.notifications.unopened_index
|
|
41
41
|
# @notifications = @user.notifications.unopened_only.group_owners_only.latest_order
|
|
42
42
|
# @param [Boolean] reverse If notification index will be ordered as earliest first
|
|
43
43
|
# @param [Boolean] with_group_members If notification index will include group members
|
|
44
|
-
# @return [ActiveRecord_AssociationRelation<
|
|
44
|
+
# @return [ActiveRecord_AssociationRelation<Notification>, Mongoid::Criteria<Notification>] Database query of filtered notifications
|
|
45
45
|
scope :unopened_index, ->(reverse = false, with_group_members = false) {
|
|
46
46
|
target_index = with_group_members ? unopened_only : unopened_only.group_owners_only
|
|
47
47
|
reverse ? target_index.earliest_order : target_index.latest_order
|
|
@@ -52,54 +52,54 @@ module ActivityNotification
|
|
|
52
52
|
# is defined same as
|
|
53
53
|
# ActivityNotification::Notification.opened_only(limit).group_owners_only.latest_order
|
|
54
54
|
# @scope class
|
|
55
|
-
# @example Get unopened
|
|
55
|
+
# @example Get unopened notification index of the @user with limit 10
|
|
56
56
|
# @notifications = @user.notifications.opened_index(10)
|
|
57
57
|
# @notifications = @user.notifications.opened_only(10).group_owners_only.latest_order
|
|
58
58
|
# @param [Integer] limit Limit to query for opened notifications
|
|
59
59
|
# @param [Boolean] reverse If notification index will be ordered as earliest first
|
|
60
60
|
# @param [Boolean] with_group_members If notification index will include group members
|
|
61
|
-
# @return [ActiveRecord_AssociationRelation<
|
|
61
|
+
# @return [ActiveRecord_AssociationRelation<Notification>, Mongoid::Criteria<Notification>] Database query of filtered notifications
|
|
62
62
|
scope :opened_index, ->(limit, reverse = false, with_group_members = false) {
|
|
63
63
|
target_index = with_group_members ? opened_only(limit) : opened_only(limit).group_owners_only
|
|
64
64
|
reverse ? target_index.earliest_order : target_index.latest_order
|
|
65
65
|
}
|
|
66
66
|
|
|
67
67
|
# Selects filtered notifications by target_type.
|
|
68
|
-
# @example Get filtered unopened
|
|
68
|
+
# @example Get filtered unopened notification of User as target type
|
|
69
69
|
# @notifications = ActivityNotification.Notification.unopened_only.filtered_by_target_type('User')
|
|
70
70
|
# @scope class
|
|
71
71
|
# @param [String] target_type Target type for filter
|
|
72
|
-
# @return [ActiveRecord_AssociationRelation<
|
|
72
|
+
# @return [ActiveRecord_AssociationRelation<Notification>, Mongoid::Criteria<Notification>] Database query of filtered notifications
|
|
73
73
|
scope :filtered_by_target_type, ->(target_type) { where(target_type: target_type) }
|
|
74
74
|
|
|
75
75
|
# Selects filtered notifications by notifiable_type.
|
|
76
|
-
# @example Get filtered unopened
|
|
76
|
+
# @example Get filtered unopened notification of the @user for Comment notifiable class
|
|
77
77
|
# @notifications = @user.notifications.unopened_only.filtered_by_type('Comment')
|
|
78
78
|
# @scope class
|
|
79
79
|
# @param [String] notifiable_type Notifiable type for filter
|
|
80
|
-
# @return [ActiveRecord_AssociationRelation<
|
|
80
|
+
# @return [ActiveRecord_AssociationRelation<Notification>, Mongoid::Criteria<Notification>] Database query of filtered notifications
|
|
81
81
|
scope :filtered_by_type, ->(notifiable_type) { where(notifiable_type: notifiable_type) }
|
|
82
82
|
|
|
83
83
|
# Selects filtered notifications by key.
|
|
84
|
-
# @example Get filtered unopened
|
|
84
|
+
# @example Get filtered unopened notification of the @user with key 'comment.reply'
|
|
85
85
|
# @notifications = @user.notifications.unopened_only.filtered_by_key('comment.reply')
|
|
86
86
|
# @scope class
|
|
87
87
|
# @param [String] key Key of the notification for filter
|
|
88
|
-
# @return [ActiveRecord_AssociationRelation<
|
|
88
|
+
# @return [ActiveRecord_AssociationRelation<Notification>, Mongoid::Criteria<Notification>] Database query of filtered notifications
|
|
89
89
|
scope :filtered_by_key, ->(key) { where(key: key) }
|
|
90
90
|
|
|
91
91
|
# Selects filtered notifications by notifiable_type, group or key with filter options.
|
|
92
|
-
# @example Get filtered unopened
|
|
92
|
+
# @example Get filtered unopened notification of the @user for Comment notifiable class
|
|
93
93
|
# @notifications = @user.notifications.unopened_only.filtered_by_options({ filtered_by_type: 'Comment' })
|
|
94
|
-
# @example Get filtered unopened
|
|
94
|
+
# @example Get filtered unopened notification of the @user for @article as group
|
|
95
95
|
# @notifications = @user.notifications.unopened_only.filtered_by_options({ filtered_by_group: @article })
|
|
96
|
-
# @example Get filtered unopened
|
|
96
|
+
# @example Get filtered unopened notification of the @user for Article instance id=1 as group
|
|
97
97
|
# @notifications = @user.notifications.unopened_only.filtered_by_options({ filtered_by_group_type: 'Article', filtered_by_group_id: '1' })
|
|
98
|
-
# @example Get filtered unopened
|
|
98
|
+
# @example Get filtered unopened notification of the @user with key 'comment.reply'
|
|
99
99
|
# @notifications = @user.notifications.unopened_only.filtered_by_options({ filtered_by_key: 'comment.reply' })
|
|
100
|
-
# @example Get filtered unopened
|
|
100
|
+
# @example Get filtered unopened notification of the @user for Comment notifiable class with key 'comment.reply'
|
|
101
101
|
# @notifications = @user.notifications.unopened_only.filtered_by_options({ filtered_by_type: 'Comment', filtered_by_key: 'comment.reply' })
|
|
102
|
-
# @example Get custom filtered
|
|
102
|
+
# @example Get custom filtered notification of the @user
|
|
103
103
|
# @notifications = @user.notifications.unopened_only.filtered_by_options({ custom_filter: ["created_at >= ?", time.hour.ago] })
|
|
104
104
|
# @scope class
|
|
105
105
|
# @param [Hash] options Options for filter
|
|
@@ -111,7 +111,7 @@ module ActivityNotification
|
|
|
111
111
|
# @option options [String] :later_than (nil) ISO 8601 format time to filter notification index later than specified time
|
|
112
112
|
# @option options [String] :earlier_than (nil) ISO 8601 format time to filter notification index earlier than specified time
|
|
113
113
|
# @option options [Array|Hash] :custom_filter (nil) Custom notification filter (e.g. ["created_at >= ?", time.hour.ago] with ActiveRecord or {:created_at.gt => time.hour.ago} with Mongoid)
|
|
114
|
-
# @return [ActiveRecord_AssociationRelation<
|
|
114
|
+
# @return [ActiveRecord_AssociationRelation<Notification>, Mongoid::Criteria<Notification>] Database query of filtered notifications
|
|
115
115
|
scope :filtered_by_options, ->(options = {}) {
|
|
116
116
|
options = ActivityNotification.cast_to_indifferent_hash(options)
|
|
117
117
|
filtered_notifications = all
|
|
@@ -141,22 +141,22 @@ module ActivityNotification
|
|
|
141
141
|
}
|
|
142
142
|
|
|
143
143
|
# Orders by latest (newest) first as created_at: :desc.
|
|
144
|
-
# @return [ActiveRecord_AssociationRelation<
|
|
144
|
+
# @return [ActiveRecord_AssociationRelation<Notification>, Mongoid::Criteria<Notification>] Database query of notifications ordered by latest first
|
|
145
145
|
scope :latest_order, -> { order(created_at: :desc) }
|
|
146
146
|
|
|
147
147
|
# Orders by earliest (older) first as created_at: :asc.
|
|
148
|
-
# @return [ActiveRecord_AssociationRelation<
|
|
148
|
+
# @return [ActiveRecord_AssociationRelation<Notification>, Mongoid::Criteria<Notification>] Database query of notifications ordered by earliest first
|
|
149
149
|
scope :earliest_order, -> { order(created_at: :asc) }
|
|
150
150
|
|
|
151
151
|
# Orders by latest (newest) first as created_at: :desc.
|
|
152
152
|
# This method is to be overridden in implementation for each ORM.
|
|
153
153
|
# @param [Boolean] reverse If notifications will be ordered as earliest first
|
|
154
|
-
# @return [ActiveRecord_AssociationRelation<
|
|
154
|
+
# @return [ActiveRecord_AssociationRelation<Notification>, Mongoid::Criteria<Notification>] Database query of ordered notifications
|
|
155
155
|
scope :latest_order!, ->(reverse = false) { reverse ? earliest_order : latest_order }
|
|
156
156
|
|
|
157
157
|
# Orders by earliest (older) first as created_at: :asc.
|
|
158
158
|
# This method is to be overridden in implementation for each ORM.
|
|
159
|
-
# @return [ActiveRecord_AssociationRelation<
|
|
159
|
+
# @return [ActiveRecord_AssociationRelation<Notification>, Mongoid::Criteria<Notification>] Database query of notifications ordered by earliest first
|
|
160
160
|
scope :earliest_order!, -> { earliest_order }
|
|
161
161
|
|
|
162
162
|
# Returns latest notification instance.
|
|
@@ -224,13 +224,16 @@ module ActivityNotification
|
|
|
224
224
|
# @option options [Boolean] :send_later (true) Whether it sends notification email asynchronously
|
|
225
225
|
# @option options [Boolean] :publish_optional_targets (true) Whether it publishes notification to optional targets
|
|
226
226
|
# @option options [Boolean] :pass_full_options (false) Whether it passes full options to notifiable.notification_targets, not a key only
|
|
227
|
-
# @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
|
|
228
|
-
# @return [Array<
|
|
227
|
+
# @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
|
|
228
|
+
# @return [Array<Notification>] Array of generated notifications
|
|
229
229
|
def notify(target_type, notifiable, options = {})
|
|
230
230
|
if options[:notify_later]
|
|
231
231
|
notify_later(target_type, notifiable, options)
|
|
232
232
|
else
|
|
233
233
|
targets = notifiable.notification_targets(target_type, options[:pass_full_options] ? options : options[:key])
|
|
234
|
+
# Merge targets from instance-level subscriptions and deduplicate
|
|
235
|
+
instance_targets = notifiable.instance_subscription_targets(target_type, options[:key])
|
|
236
|
+
targets = merge_targets(targets, instance_targets)
|
|
234
237
|
# Optimize blank check to avoid loading all records for ActiveRecord relations
|
|
235
238
|
unless targets_empty?(targets)
|
|
236
239
|
notify_all(targets, notifiable, options)
|
|
@@ -263,8 +266,8 @@ module ActivityNotification
|
|
|
263
266
|
# @option options [Boolean] :send_later (true) Whether it sends notification email asynchronously
|
|
264
267
|
# @option options [Boolean] :publish_optional_targets (true) Whether it publishes notification to optional targets
|
|
265
268
|
# @option options [Boolean] :pass_full_options (false) Whether it passes full options to notifiable.notification_targets, not a key only
|
|
266
|
-
# @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
|
|
267
|
-
# @return [Array<
|
|
269
|
+
# @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
|
|
270
|
+
# @return [Array<Notification>] Array of generated notifications
|
|
268
271
|
def notify_later(target_type, notifiable, options = {})
|
|
269
272
|
target_type = target_type.to_s if target_type.is_a? Symbol
|
|
270
273
|
options.delete(:notify_later)
|
|
@@ -296,8 +299,8 @@ module ActivityNotification
|
|
|
296
299
|
# @option options [Boolean] :send_later (true) Whether it sends notification email asynchronously
|
|
297
300
|
# @option options [Boolean] :publish_optional_targets (true) Whether it publishes notification to optional targets
|
|
298
301
|
# @option options [Integer] :batch_size (1000) Batch size for ActiveRecord find_each (optional)
|
|
299
|
-
# @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
|
|
300
|
-
# @return [Array<
|
|
302
|
+
# @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
|
|
303
|
+
# @return [Array<Notification>] Array of generated notifications
|
|
301
304
|
def notify_all(targets, notifiable, options = {})
|
|
302
305
|
if options[:notify_later]
|
|
303
306
|
notify_all_later(targets, notifiable, options)
|
|
@@ -331,8 +334,8 @@ module ActivityNotification
|
|
|
331
334
|
# @option options [Boolean] :send_email (true) Whether it sends notification email
|
|
332
335
|
# @option options [Boolean] :send_later (true) Whether it sends notification email asynchronously
|
|
333
336
|
# @option options [Boolean] :publish_optional_targets (true) Whether it publishes notification to optional targets
|
|
334
|
-
# @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
|
|
335
|
-
# @return [Array<
|
|
337
|
+
# @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
|
|
338
|
+
# @return [Array<Notification>] Array of generated notifications
|
|
336
339
|
def notify_all_later(targets, notifiable, options = {})
|
|
337
340
|
options.delete(:notify_later)
|
|
338
341
|
ActivityNotification::NotifyAllJob.perform_later(targets, notifiable, options)
|
|
@@ -341,7 +344,7 @@ module ActivityNotification
|
|
|
341
344
|
# Generates notifications to one target.
|
|
342
345
|
#
|
|
343
346
|
# @example Notify to one user
|
|
344
|
-
# ActivityNotification::Notification.notify_to @comment.
|
|
347
|
+
# ActivityNotification::Notification.notify_to @comment.author, @comment
|
|
345
348
|
#
|
|
346
349
|
# @param [Object] target Target to send notifications
|
|
347
350
|
# @param [Object] notifiable Notifiable instance
|
|
@@ -355,7 +358,7 @@ module ActivityNotification
|
|
|
355
358
|
# @option options [Boolean] :send_email (true) Whether it sends notification email
|
|
356
359
|
# @option options [Boolean] :send_later (true) Whether it sends notification email asynchronously
|
|
357
360
|
# @option options [Boolean] :publish_optional_targets (true) Whether it publishes notification to optional targets
|
|
358
|
-
# @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
|
|
361
|
+
# @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
|
|
359
362
|
# @return [Notification] Generated notification instance
|
|
360
363
|
def notify_to(target, notifiable, options = {})
|
|
361
364
|
if options[:notify_later]
|
|
@@ -383,7 +386,7 @@ module ActivityNotification
|
|
|
383
386
|
# Generates notifications to one target later by ActiveJob queue.
|
|
384
387
|
#
|
|
385
388
|
# @example Notify to one user later
|
|
386
|
-
# ActivityNotification::Notification.notify_later_to @comment.
|
|
389
|
+
# ActivityNotification::Notification.notify_later_to @comment.author, @comment
|
|
387
390
|
#
|
|
388
391
|
# @param [Object] target Target to send notifications
|
|
389
392
|
# @param [Object] notifiable Notifiable instance
|
|
@@ -396,7 +399,7 @@ module ActivityNotification
|
|
|
396
399
|
# @option options [Boolean] :send_email (true) Whether it sends notification email
|
|
397
400
|
# @option options [Boolean] :send_later (true) Whether it sends notification email asynchronously
|
|
398
401
|
# @option options [Boolean] :publish_optional_targets (true) Whether it publishes notification to optional targets
|
|
399
|
-
# @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
|
|
402
|
+
# @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
|
|
400
403
|
# @return [Notification] Generated notification instance
|
|
401
404
|
def notify_later_to(target, notifiable, options = {})
|
|
402
405
|
options.delete(:notify_later)
|
|
@@ -413,7 +416,7 @@ module ActivityNotification
|
|
|
413
416
|
# @option options [Hash] :parameters ({}) Additional parameters of the notifications
|
|
414
417
|
def generate_notification(target, notifiable, options = {})
|
|
415
418
|
key = options[:key] || notifiable.default_notification_key
|
|
416
|
-
if target.subscribes_to_notification?(key)
|
|
419
|
+
if target.subscribes_to_notification?(key, notifiable: notifiable)
|
|
417
420
|
# Store notification
|
|
418
421
|
notification = store_notification(target, notifiable, key, options)
|
|
419
422
|
end
|
|
@@ -491,7 +494,7 @@ module ActivityNotification
|
|
|
491
494
|
# Returns if group member of the notifications exists.
|
|
492
495
|
# This method is designed to be called from controllers or views to avoid N+1.
|
|
493
496
|
#
|
|
494
|
-
# @param [Array<
|
|
497
|
+
# @param [Array<Notification>, ActiveRecord_AssociationRelation<Notification>, Mongoid::Criteria<Notification>] notifications Array or database query of the notifications to test member exists
|
|
495
498
|
# @return [Boolean] If group member of the notifications exists
|
|
496
499
|
def group_member_exists?(notifications)
|
|
497
500
|
notifications.present? and group_members_of_owner_ids_only(notifications.map(&:id)).exists?
|
|
@@ -520,7 +523,7 @@ module ActivityNotification
|
|
|
520
523
|
|
|
521
524
|
# Returns available options for kinds of notify methods.
|
|
522
525
|
#
|
|
523
|
-
# @return [Array<
|
|
526
|
+
# @return [Array<Notification>] Available options for kinds of notify methods
|
|
524
527
|
def available_options
|
|
525
528
|
[:key, :group, :group_expiry_delay, :notifier, :parameters, :send_email, :send_later, :pass_full_options].freeze
|
|
526
529
|
end
|
|
@@ -537,7 +540,7 @@ module ActivityNotification
|
|
|
537
540
|
# @param [String] key Key of the notification
|
|
538
541
|
# @param [Object] group Group unit of the notifications
|
|
539
542
|
# @param [ActiveSupport::Duration] group_expiry_delay Expiry period of a notification group
|
|
540
|
-
# @return [
|
|
543
|
+
# @return [Notification] Valid group owner within the expiration period
|
|
541
544
|
def valid_group_owner(target, notifiable, key, group, group_expiry_delay)
|
|
542
545
|
return nil if group.blank?
|
|
543
546
|
# Bundle notification group by target, notifiable_type, group and key
|
|
@@ -581,6 +584,18 @@ module ActivityNotification
|
|
|
581
584
|
end
|
|
582
585
|
end
|
|
583
586
|
|
|
587
|
+
# Merges instance subscription targets with the main targets list, deduplicating.
|
|
588
|
+
# @api private
|
|
589
|
+
#
|
|
590
|
+
# @param [Object] targets Main targets collection (can be an ActiveRecord::Relation, Mongoid::Criteria, Array, etc.)
|
|
591
|
+
# @param [Array] instance_targets Targets from instance-level subscriptions
|
|
592
|
+
# @return [Array] Deduplicated array of all targets
|
|
593
|
+
def merge_targets(targets, instance_targets)
|
|
594
|
+
return targets if instance_targets.blank?
|
|
595
|
+
all_targets = targets.respond_to?(:to_a) ? targets.to_a : Array(targets)
|
|
596
|
+
(all_targets + instance_targets).uniq
|
|
597
|
+
end
|
|
598
|
+
|
|
584
599
|
# Processes targets in batches for memory efficiency with large collections
|
|
585
600
|
# @api private
|
|
586
601
|
#
|
|
@@ -783,7 +798,7 @@ module ActivityNotification
|
|
|
783
798
|
# Returns the latest group member notification instance of this notification.
|
|
784
799
|
# If this group owner has no group members, group owner instance self will be returned.
|
|
785
800
|
#
|
|
786
|
-
# @return [
|
|
801
|
+
# @return [Notification] Notification instance of the latest group member notification
|
|
787
802
|
def latest_group_member
|
|
788
803
|
notification = group_member? && group_owner.present? ? group_owner : self
|
|
789
804
|
notification.group_member_exists? ? notification.group_members.latest : self
|
|
@@ -791,7 +806,7 @@ module ActivityNotification
|
|
|
791
806
|
|
|
792
807
|
# Remove from notification group and make a new group owner.
|
|
793
808
|
#
|
|
794
|
-
# @return [
|
|
809
|
+
# @return [Notification] New group owner instance of the notification group
|
|
795
810
|
def remove_from_group
|
|
796
811
|
new_group_owner = group_members.earliest
|
|
797
812
|
if new_group_owner.present?
|
|
@@ -11,7 +11,7 @@ module ActivityNotification
|
|
|
11
11
|
# @subscriptions = @user.subscriptions.filtered_by_key('comment.reply')
|
|
12
12
|
# @scope class
|
|
13
13
|
# @param [String] key Key of the subscription for filter
|
|
14
|
-
# @return [ActiveRecord_AssociationRelation<Subscription>, Mongoid::Criteria<
|
|
14
|
+
# @return [ActiveRecord_AssociationRelation<Subscription>, Mongoid::Criteria<Notification>] Database query of filtered subscriptions
|
|
15
15
|
scope :filtered_by_key, ->(key) { where(key: key) }
|
|
16
16
|
|
|
17
17
|
# Selects filtered subscriptions by key with filter options.
|
|
@@ -23,7 +23,7 @@ module ActivityNotification
|
|
|
23
23
|
# @param [Hash] options Options for filter
|
|
24
24
|
# @option options [String] :filtered_by_key (nil) Key of the subscription for filter
|
|
25
25
|
# @option options [Array|Hash] :custom_filter (nil) Custom subscription filter (e.g. ["created_at >= ?", time.hour.ago] or ['created_at.gt': time.hour.ago])
|
|
26
|
-
# @return [ActiveRecord_AssociationRelation<Subscription>, Mongoid::Criteria<
|
|
26
|
+
# @return [ActiveRecord_AssociationRelation<Subscription>, Mongoid::Criteria<Notification>] Database query of filtered subscriptions
|
|
27
27
|
scope :filtered_by_options, ->(options = {}) {
|
|
28
28
|
options = ActivityNotification.cast_to_indifferent_hash(options)
|
|
29
29
|
filtered_subscriptions = all
|
|
@@ -37,34 +37,34 @@ module ActivityNotification
|
|
|
37
37
|
}
|
|
38
38
|
|
|
39
39
|
# Orders by latest (newest) first as created_at: :desc.
|
|
40
|
-
# @return [ActiveRecord_AssociationRelation<Subscription>, Mongoid::Criteria<
|
|
40
|
+
# @return [ActiveRecord_AssociationRelation<Subscription>, Mongoid::Criteria<Notification>] Database query of subscriptions ordered by latest first
|
|
41
41
|
scope :latest_order, -> { order(created_at: :desc) }
|
|
42
42
|
|
|
43
43
|
# Orders by earliest (older) first as created_at: :asc.
|
|
44
|
-
# @return [ActiveRecord_AssociationRelation<Subscription>, Mongoid::Criteria<
|
|
44
|
+
# @return [ActiveRecord_AssociationRelation<Subscription>, Mongoid::Criteria<Notification>] Database query of subscriptions ordered by earliest first
|
|
45
45
|
scope :earliest_order, -> { order(created_at: :asc) }
|
|
46
46
|
|
|
47
47
|
# Orders by latest (newest) first as created_at: :desc.
|
|
48
48
|
# This method is to be overridden in implementation for each ORM.
|
|
49
49
|
# @param [Boolean] reverse If subscriptions will be ordered as earliest first
|
|
50
|
-
# @return [ActiveRecord_AssociationRelation<
|
|
50
|
+
# @return [ActiveRecord_AssociationRelation<Notification>, Mongoid::Criteria<Notification>] Database query of ordered subscriptions
|
|
51
51
|
scope :latest_order!, ->(reverse = false) { reverse ? earliest_order : latest_order }
|
|
52
52
|
|
|
53
53
|
# Orders by earliest (older) first as created_at: :asc.
|
|
54
54
|
# This method is to be overridden in implementation for each ORM.
|
|
55
|
-
# @return [ActiveRecord_AssociationRelation<
|
|
55
|
+
# @return [ActiveRecord_AssociationRelation<Notification>, Mongoid::Criteria<Notification>] Database query of subscriptions ordered by earliest first
|
|
56
56
|
scope :earliest_order!, -> { earliest_order }
|
|
57
57
|
|
|
58
58
|
# Orders by latest (newest) first as subscribed_at: :desc.
|
|
59
|
-
# @return [ActiveRecord_AssociationRelation<Subscription>, Mongoid::Criteria<
|
|
59
|
+
# @return [ActiveRecord_AssociationRelation<Subscription>, Mongoid::Criteria<Notification>] Database query of subscriptions ordered by latest subscribed_at first
|
|
60
60
|
scope :latest_subscribed_order, -> { order(subscribed_at: :desc) }
|
|
61
61
|
|
|
62
62
|
# Orders by earliest (older) first as subscribed_at: :asc.
|
|
63
|
-
# @return [ActiveRecord_AssociationRelation<Subscription>, Mongoid::Criteria<
|
|
63
|
+
# @return [ActiveRecord_AssociationRelation<Subscription>, Mongoid::Criteria<Notification>] Database query of subscriptions ordered by earliest subscribed_at first
|
|
64
64
|
scope :earliest_subscribed_order, -> { order(subscribed_at: :asc) }
|
|
65
65
|
|
|
66
66
|
# Orders by key name as key: :asc.
|
|
67
|
-
# @return [ActiveRecord_AssociationRelation<Subscription>, Mongoid::Criteria<
|
|
67
|
+
# @return [ActiveRecord_AssociationRelation<Subscription>, Mongoid::Criteria<Notification>] Database query of subscriptions ordered by key name
|
|
68
68
|
scope :key_order, -> { order(key: :asc) }
|
|
69
69
|
|
|
70
70
|
# Convert Time value to store in database as Hash value.
|
|
@@ -182,7 +182,7 @@ module ActivityNotification
|
|
|
182
182
|
# Returns if the target subscribes to the specified optional target.
|
|
183
183
|
#
|
|
184
184
|
# @param [Symbol] optional_target_name Symbol class name of the optional target implementation (e.g. :amazon_sns, :slack)
|
|
185
|
-
# @param [Boolean] subscribe_as_default Default subscription value to use when the subscription record
|
|
185
|
+
# @param [Boolean] subscribe_as_default Default subscription value to use when the subscription record is not configured
|
|
186
186
|
# @return [Boolean] If the target subscribes to the specified optional target
|
|
187
187
|
def subscribing_to_optional_target?(optional_target_name, subscribe_as_default = ActivityNotification.config.subscribe_to_optional_targets_as_default)
|
|
188
188
|
optional_target_key = Subscription.to_optional_target_key(optional_target_name)
|
|
@@ -105,7 +105,7 @@ module ActivityNotification
|
|
|
105
105
|
end
|
|
106
106
|
end
|
|
107
107
|
|
|
108
|
-
#
|
|
108
|
+
# Converts to class name.
|
|
109
109
|
# This function returns base_class name for STI models if the class responds to base_class method.
|
|
110
110
|
# @see https://github.com/simukappu/activity_notification/issues/89
|
|
111
111
|
# @see https://github.com/simukappu/activity_notification/pull/139
|
|
@@ -114,26 +114,26 @@ module ActivityNotification
|
|
|
114
114
|
self.class.respond_to?(:base_class) ? self.class.base_class.name : self.class.name
|
|
115
115
|
end
|
|
116
116
|
|
|
117
|
-
#
|
|
117
|
+
# Converts to singularized model name (resource name).
|
|
118
118
|
# @return [String] Singularized model name (resource name)
|
|
119
119
|
def to_resource_name
|
|
120
120
|
self.to_class_name.demodulize.singularize.underscore
|
|
121
121
|
end
|
|
122
122
|
|
|
123
|
-
#
|
|
123
|
+
# Converts to pluralized model name (resources name).
|
|
124
124
|
# @return [String] Pluralized model name (resources name)
|
|
125
125
|
def to_resources_name
|
|
126
126
|
self.to_class_name.demodulize.pluralize.underscore
|
|
127
127
|
end
|
|
128
128
|
|
|
129
|
-
#
|
|
129
|
+
# Converts to printable model type name to be humanized.
|
|
130
130
|
# @return [String] Printable model type name
|
|
131
131
|
# @todo Is this the best to make readable?
|
|
132
132
|
def printable_type
|
|
133
133
|
"#{self.to_class_name.demodulize.humanize}"
|
|
134
134
|
end
|
|
135
135
|
|
|
136
|
-
#
|
|
136
|
+
# Converts to printable model name to show in view or email.
|
|
137
137
|
# @return [String] Printable model name
|
|
138
138
|
def printable_name
|
|
139
139
|
"#{self.printable_type} (#{id})"
|
|
@@ -91,6 +91,15 @@ module ActivityNotification
|
|
|
91
91
|
# @return [String, Array<String>, Proc] CC email address(es) for notification email.
|
|
92
92
|
attr_accessor :mailer_cc
|
|
93
93
|
|
|
94
|
+
# @overload mailer_attachments
|
|
95
|
+
# Returns attachment specification(s) for notification emails
|
|
96
|
+
# @return [Hash, Array<Hash>, Proc, nil] Attachment specification(s) for notification emails.
|
|
97
|
+
# @overload mailer_attachments=(value)
|
|
98
|
+
# Sets attachment specification(s) for notification emails
|
|
99
|
+
# @param [Hash, Array<Hash>, Proc, nil] mailer_attachments The new mailer_attachments
|
|
100
|
+
# @return [Hash, Array<Hash>, Proc, nil] Attachment specification(s) for notification emails.
|
|
101
|
+
attr_accessor :mailer_attachments
|
|
102
|
+
|
|
94
103
|
# @overload mailer
|
|
95
104
|
# Returns mailer class for email notification
|
|
96
105
|
# @return [String] Mailer class for email notification.
|
|
@@ -173,8 +182,8 @@ module ActivityNotification
|
|
|
173
182
|
attr_accessor :composite_key_delimiter
|
|
174
183
|
|
|
175
184
|
# @overload store_with_associated_records
|
|
176
|
-
# Returns whether activity_notification stores
|
|
177
|
-
# @return [Boolean] Whether activity_notification stores
|
|
185
|
+
# Returns whether activity_notification stores notification records including associated records like target and notifiable
|
|
186
|
+
# @return [Boolean] Whether activity_notification stores Notification records including associated records like target and notifiable.
|
|
178
187
|
attr_reader :store_with_associated_records
|
|
179
188
|
|
|
180
189
|
# @overload action_cable_enabled
|
|
@@ -246,6 +255,7 @@ module ActivityNotification
|
|
|
246
255
|
@subscribe_to_optional_targets_as_default = nil
|
|
247
256
|
@mailer_sender = nil
|
|
248
257
|
@mailer_cc = nil
|
|
258
|
+
@mailer_attachments = nil
|
|
249
259
|
@mailer = 'ActivityNotification::Mailer'
|
|
250
260
|
@parent_mailer = 'ActionMailer::Base'
|
|
251
261
|
@parent_job = 'ActiveJob::Base'
|
|
@@ -271,10 +281,10 @@ module ActivityNotification
|
|
|
271
281
|
@orm = orm.to_sym
|
|
272
282
|
end
|
|
273
283
|
|
|
274
|
-
# Sets whether activity_notification stores
|
|
284
|
+
# Sets whether activity_notification stores notification records including associated records like target and notifiable.
|
|
275
285
|
# This store_with_associated_records option can be set true only when you use mongoid or dynamoid ORM.
|
|
276
286
|
# @param [Boolean] store_with_associated_records The new store_with_associated_records
|
|
277
|
-
# @return [Boolean] Whether activity_notification stores
|
|
287
|
+
# @return [Boolean] Whether activity_notification stores notification records including associated records like target and notifiable.
|
|
278
288
|
def store_with_associated_records=(store_with_associated_records)
|
|
279
289
|
if store_with_associated_records && [:mongoid, :dynamoid].exclude?(@orm) then raise ActivityNotification::ConfigError, "config.store_with_associated_records can be set true only when you use mongoid or dynamoid ORM." end
|
|
280
290
|
@store_with_associated_records = store_with_associated_records
|
|
@@ -289,7 +299,7 @@ module ActivityNotification
|
|
|
289
299
|
end
|
|
290
300
|
|
|
291
301
|
# Returns default optional target subscription value to use when the subscription record does not configured
|
|
292
|
-
# @return [Boolean] Default
|
|
302
|
+
# @return [Boolean] Default optional target subscription value to use when the subscription record does not configured.
|
|
293
303
|
def subscribe_to_optional_targets_as_default
|
|
294
304
|
return false unless @subscribe_as_default
|
|
295
305
|
|
|
@@ -67,14 +67,12 @@ module ActivityNotification
|
|
|
67
67
|
end
|
|
68
68
|
|
|
69
69
|
# Returns path of the target view templates.
|
|
70
|
-
# Do not make this method public unless
|
|
70
|
+
# Do not make this method public unless Renderable module calls controller's target_view_path method to render resources.
|
|
71
71
|
# @api protected
|
|
72
72
|
def target_view_path
|
|
73
73
|
target_type = @target.to_resources_name
|
|
74
74
|
view_path = [controller_path, target_type].join('/')
|
|
75
|
-
lookup_context.exists?(action_name, view_path) ?
|
|
76
|
-
view_path :
|
|
77
|
-
[controller_path, DEFAULT_VIEW_DIRECTORY].join('/')
|
|
75
|
+
lookup_context.exists?(action_name, view_path) ? view_path : [controller_path, DEFAULT_VIEW_DIRECTORY].join('/')
|
|
78
76
|
end
|
|
79
77
|
|
|
80
78
|
# Sets view prefixes for target view path.
|
|
@@ -14,7 +14,7 @@ module ActivityNotification
|
|
|
14
14
|
# Authenticate devise resource by Devise (e.g. calling authenticate_user! method).
|
|
15
15
|
# @api protected
|
|
16
16
|
# @todo Needs to call authenticate method by more secure way
|
|
17
|
-
# @return [Response] Redirects for unsigned in target by Devise, returns HTTP 403 without
|
|
17
|
+
# @return [Response] Redirects for unsigned in target by Devise, returns HTTP 403 without necessary target method or returns 400 when request parameters are not enough
|
|
18
18
|
def authenticate_devise_resource!
|
|
19
19
|
if params[:devise_type].present?
|
|
20
20
|
authenticate_method_name = "authenticate_#{params[:devise_type].to_resource_name}!"
|
|
@@ -29,7 +29,7 @@ module ActivityNotification
|
|
|
29
29
|
end
|
|
30
30
|
|
|
31
31
|
# Sets @target instance variable from request parameters.
|
|
32
|
-
# This method override super (
|
|
32
|
+
# This method override super (ActivityNotification::CommonController#set_target)
|
|
33
33
|
# to set devise authenticated target when the target_id params is not specified.
|
|
34
34
|
# @api protected
|
|
35
35
|
# @return [Object] Target instance (Returns HTTP 400 when request parameters are not enough)
|
|
@@ -5,35 +5,35 @@ module ActivityNotification
|
|
|
5
5
|
|
|
6
6
|
included do
|
|
7
7
|
class ::String
|
|
8
|
-
#
|
|
8
|
+
# Converts to model instance.
|
|
9
9
|
# @return [Object] Model instance
|
|
10
10
|
def to_model_name
|
|
11
11
|
singularize.camelize
|
|
12
12
|
end
|
|
13
13
|
|
|
14
|
-
#
|
|
14
|
+
# Converts to model class.
|
|
15
15
|
# @return [Class] Model class
|
|
16
16
|
def to_model_class
|
|
17
17
|
to_model_name.classify.constantize
|
|
18
18
|
end
|
|
19
19
|
|
|
20
|
-
#
|
|
20
|
+
# Converts to singularized model name (resource name).
|
|
21
21
|
# @return [String] Singularized model name (resource name)
|
|
22
22
|
def to_resource_name
|
|
23
23
|
singularize.underscore
|
|
24
24
|
end
|
|
25
25
|
|
|
26
|
-
#
|
|
26
|
+
# Converts to pluralized model name (resources name).
|
|
27
27
|
# @return [String] Pluralized model name (resources name)
|
|
28
28
|
def to_resources_name
|
|
29
29
|
pluralize.underscore
|
|
30
30
|
end
|
|
31
31
|
|
|
32
|
-
#
|
|
32
|
+
# Converts to boolean.
|
|
33
33
|
# Returns true for 'true', '1', 'yes', 'on' and 't'.
|
|
34
34
|
# Returns false for 'false', '0', 'no', 'off' and 'f'.
|
|
35
35
|
# @param [Boolean] default Default value to return when the String is not interpretable
|
|
36
|
-
# @return [Boolean]
|
|
36
|
+
# @return [Boolean] Converted boolean value
|
|
37
37
|
def to_boolean(default = nil)
|
|
38
38
|
return true if ['true', '1', 'yes', 'on', 't'].include? self
|
|
39
39
|
return false if ['false', '0', 'no', 'off', 'f'].include? self
|
|
@@ -2,10 +2,10 @@ module ActivityNotification
|
|
|
2
2
|
# Provides a shortcut from views to the rendering method.
|
|
3
3
|
# Module extending ActionView::Base and adding `render_notification` helper.
|
|
4
4
|
module ViewHelpers
|
|
5
|
-
# View helper for rendering
|
|
5
|
+
# View helper for rendering a notification, calls {Notification#render} internally.
|
|
6
6
|
# @see Notification#render
|
|
7
7
|
#
|
|
8
|
-
# @param [Notification, Array<
|
|
8
|
+
# @param [Notification, Array<Notification>] notifications Array or single instance of notifications to render
|
|
9
9
|
# @param [Hash] options Options for rendering notifications
|
|
10
10
|
# @option options [String, Symbol] :target (nil) Target type name to find template or i18n text
|
|
11
11
|
# @option options [String] :partial ("activity_notification/notifications/#{target}", controller.target_view_path, 'activity_notification/notifications/default') Partial template name
|
|
@@ -489,7 +489,7 @@ module ActivityNotification
|
|
|
489
489
|
# @api private
|
|
490
490
|
#
|
|
491
491
|
# @param [Object] target Notification target instance
|
|
492
|
-
# @param [Array<
|
|
492
|
+
# @param [Array<Notification>] notification_index Array notification index
|
|
493
493
|
# @param [Hash] params Option parameter to send render_notification
|
|
494
494
|
def prepare_content_for(target, notification_index, params)
|
|
495
495
|
content_for :notification_index do
|