activity_notification 1.2.1 → 1.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +15 -5
- data/CHANGELOG.md +13 -2
- data/Gemfile +1 -1
- data/Gemfile.lock +78 -71
- data/README.md +64 -43
- data/activity_notification.gemspec +5 -4
- data/app/controllers/activity_notification/notifications_controller.rb +1 -1
- data/app/controllers/activity_notification/subscriptions_controller.rb +1 -1
- data/gemfiles/Gemfile.rails-4.2 +1 -1
- data/gemfiles/Gemfile.rails-4.2.lock +71 -62
- data/gemfiles/Gemfile.rails-5.0 +1 -1
- data/gemfiles/Gemfile.rails-5.0.lock +74 -67
- data/lib/activity_notification.rb +9 -2
- data/lib/activity_notification/apis/notification_api.rb +142 -76
- data/lib/activity_notification/apis/subscription_api.rb +72 -0
- data/lib/activity_notification/config.rb +12 -0
- data/lib/activity_notification/models/concerns/notifiable.rb +56 -6
- data/lib/activity_notification/models/concerns/notifier.rb +8 -1
- data/lib/activity_notification/models/concerns/subscriber.rb +13 -10
- data/lib/activity_notification/models/concerns/target.rb +7 -5
- data/lib/activity_notification/models/notification.rb +2 -270
- data/lib/activity_notification/models/subscription.rb +3 -101
- data/lib/activity_notification/optional_targets/base.rb +5 -1
- data/lib/activity_notification/orm/active_record.rb +16 -0
- data/lib/activity_notification/orm/active_record/notification.rb +252 -0
- data/lib/activity_notification/orm/active_record/subscription.rb +52 -0
- data/lib/activity_notification/orm/mongoid.rb +63 -0
- data/lib/activity_notification/orm/mongoid/notification.rb +255 -0
- data/lib/activity_notification/orm/mongoid/subscription.rb +73 -0
- data/lib/activity_notification/rails/routes.rb +7 -3
- data/lib/activity_notification/renderable.rb +5 -1
- data/lib/activity_notification/roles/acts_as_notifiable.rb +4 -18
- data/lib/activity_notification/version.rb +1 -1
- data/lib/generators/activity_notification/install_generator.rb +3 -5
- data/lib/generators/templates/activity_notification.rb +9 -4
- data/spec/concerns/apis/notification_api_spec.rb +27 -14
- data/spec/concerns/models/notifiable_spec.rb +10 -8
- data/spec/concerns/models/subscriber_spec.rb +12 -12
- data/spec/concerns/models/target_spec.rb +61 -51
- data/spec/controllers/subscriptions_controller_shared_examples.rb +0 -1
- data/spec/helpers/view_helpers_spec.rb +24 -7
- data/spec/models/notification_spec.rb +63 -52
- data/spec/models/subscription_spec.rb +6 -3
- data/spec/optional_targets/amazon_sns_spec.rb +8 -5
- data/spec/optional_targets/base_spec.rb +3 -1
- data/spec/optional_targets/slack_spec.rb +5 -5
- data/spec/rails_app/app/models/comment.rb +1 -1
- data/spec/rails_app/app/views/activity_notification/notifications/users/overriden/custom/_test.html.erb +1 -0
- data/spec/rails_app/config/application.rb +7 -0
- data/spec/rails_app/config/initializers/activity_notification.rb +5 -0
- data/spec/rails_app/config/mongoid.yml +13 -0
- data/spec/rails_app/db/seeds.rb +1 -1
- data/spec/rails_app/lib/custom_optional_targets/console_output.rb +7 -4
- data/spec/rails_app/lib/custom_optional_targets/wrong_target.rb +3 -0
- data/spec/roles/acts_as_notifiable_spec.rb +77 -16
- data/spec/spec_helper.rb +7 -0
- metadata +38 -14
@@ -7,9 +7,7 @@ module ActivityNotification
|
|
7
7
|
extend ActiveSupport::Autoload
|
8
8
|
|
9
9
|
autoload :Notification, 'activity_notification/models/notification'
|
10
|
-
autoload :NotificationApi, 'activity_notification/apis/notification_api'
|
11
10
|
autoload :Subscription, 'activity_notification/models/subscription'
|
12
|
-
autoload :SubscriptionApi, 'activity_notification/apis/subscription_api'
|
13
11
|
autoload :Target, 'activity_notification/models/concerns/target'
|
14
12
|
autoload :Subscriber, 'activity_notification/models/concerns/subscriber'
|
15
13
|
autoload :Notifiable, 'activity_notification/models/concerns/notifiable'
|
@@ -44,8 +42,17 @@ module ActivityNotification
|
|
44
42
|
# end
|
45
43
|
def self.configure
|
46
44
|
yield(config) if block_given?
|
45
|
+
autoload :Association, "activity_notification/orm/#{ActivityNotification.config.orm}"
|
47
46
|
end
|
48
47
|
|
48
|
+
# Method used to choose which ORM to load
|
49
|
+
# when ActivityNotification::Notification class or ActivityNotification::Subscription class
|
50
|
+
# are being autoloaded
|
51
|
+
def self.inherit_orm(model)
|
52
|
+
orm = ActivityNotification.config.orm
|
53
|
+
require "activity_notification/orm/#{orm}"
|
54
|
+
"ActivityNotification::ORM::#{orm.to_s.classify}::#{model}".constantize
|
55
|
+
end
|
49
56
|
end
|
50
57
|
|
51
58
|
# Load ActivityNotification helpers
|
@@ -6,6 +6,131 @@ module ActivityNotification
|
|
6
6
|
included do
|
7
7
|
# Defines store_notification as private clas method
|
8
8
|
private_class_method :store_notification
|
9
|
+
|
10
|
+
# Selects all notification index.
|
11
|
+
# ActivityNotification::Notification.all_index!
|
12
|
+
# is defined same as
|
13
|
+
# ActivityNotification::Notification.group_owners_only.latest_order
|
14
|
+
# @scope class
|
15
|
+
# @example Get all notification index of the @user
|
16
|
+
# @notifications = @user.notifications.all_index!
|
17
|
+
# @notifications = @user.notifications.group_owners_only.latest_order
|
18
|
+
# @param [Boolean] reverse If notification index will be ordered as earliest first
|
19
|
+
# @param [Boolean] with_group_members If notification index will include group members
|
20
|
+
# @return [ActiveRecord_AssociationRelation<Notificaion>, Mongoid::Criteria<Notificaion>] Database query of filtered notifications
|
21
|
+
scope :all_index!, ->(reverse = false, with_group_members = false) {
|
22
|
+
target_index = with_group_members ? self : group_owners_only
|
23
|
+
reverse ? target_index.earliest_order : target_index.latest_order
|
24
|
+
}
|
25
|
+
|
26
|
+
# Selects unopened notification index.
|
27
|
+
# ActivityNotification::Notification.unopened_index
|
28
|
+
# is defined same as
|
29
|
+
# ActivityNotification::Notification.unopened_only.group_owners_only.latest_order
|
30
|
+
# @scope class
|
31
|
+
# @example Get unopened notificaton index of the @user
|
32
|
+
# @notifications = @user.notifications.unopened_index
|
33
|
+
# @notifications = @user.notifications.unopened_only.group_owners_only.latest_order
|
34
|
+
# @param [Boolean] reverse If notification index will be ordered as earliest first
|
35
|
+
# @param [Boolean] with_group_members If notification index will include group members
|
36
|
+
# @return [ActiveRecord_AssociationRelation<Notificaion>, Mongoid::Criteria<Notificaion>] Database query of filtered notifications
|
37
|
+
scope :unopened_index, ->(reverse = false, with_group_members = false) {
|
38
|
+
target_index = with_group_members ? unopened_only : unopened_only.group_owners_only
|
39
|
+
reverse ? target_index.earliest_order : target_index.latest_order
|
40
|
+
}
|
41
|
+
|
42
|
+
# Selects unopened notification index.
|
43
|
+
# ActivityNotification::Notification.opened_index(limit)
|
44
|
+
# is defined same as
|
45
|
+
# ActivityNotification::Notification.opened_only(limit).group_owners_only.latest_order
|
46
|
+
# @scope class
|
47
|
+
# @example Get unopened notificaton index of the @user with limit 10
|
48
|
+
# @notifications = @user.notifications.opened_index(10)
|
49
|
+
# @notifications = @user.notifications.opened_only(10).group_owners_only.latest_order
|
50
|
+
# @param [Integer] limit Limit to query for opened notifications
|
51
|
+
# @param [Boolean] reverse If notification index will be ordered as earliest first
|
52
|
+
# @param [Boolean] with_group_members If notification index will include group members
|
53
|
+
# @return [ActiveRecord_AssociationRelation<Notificaion>, Mongoid::Criteria<Notificaion>] Database query of filtered notifications
|
54
|
+
scope :opened_index, ->(limit, reverse = false, with_group_members = false) {
|
55
|
+
target_index = with_group_members ? opened_only(limit) : opened_only(limit).group_owners_only
|
56
|
+
reverse ? target_index.earliest_order : target_index.latest_order
|
57
|
+
}
|
58
|
+
|
59
|
+
# Selects filtered notifications by target_type.
|
60
|
+
# @example Get filtered unopened notificatons of User as target type
|
61
|
+
# @notifications = ActivityNotification.Notification.unopened_only.filtered_by_target_type('User')
|
62
|
+
# @scope class
|
63
|
+
# @param [String] target_type Target type for filter
|
64
|
+
# @return [ActiveRecord_AssociationRelation<Notificaion>, Mongoid::Criteria<Notificaion>] Database query of filtered notifications
|
65
|
+
scope :filtered_by_target_type, ->(target_type) { where(target_type: target_type) }
|
66
|
+
|
67
|
+
# Selects filtered notifications by notifiable_type.
|
68
|
+
# @example Get filtered unopened notificatons of the @user for Comment notifiable class
|
69
|
+
# @notifications = @user.notifications.unopened_only.filtered_by_type('Comment')
|
70
|
+
# @scope class
|
71
|
+
# @param [String] notifiable_type Notifiable type for filter
|
72
|
+
# @return [ActiveRecord_AssociationRelation<Notificaion>, Mongoid::Criteria<Notificaion>] Database query of filtered notifications
|
73
|
+
scope :filtered_by_type, ->(notifiable_type) { where(notifiable_type: notifiable_type) }
|
74
|
+
|
75
|
+
# Selects filtered notifications by key.
|
76
|
+
# @example Get filtered unopened notificatons of the @user with key 'comment.reply'
|
77
|
+
# @notifications = @user.notifications.unopened_only.filtered_by_key('comment.reply')
|
78
|
+
# @scope class
|
79
|
+
# @param [String] key Key of the notification for filter
|
80
|
+
# @return [ActiveRecord_AssociationRelation<Notificaion>, Mongoid::Criteria<Notificaion>] Database query of filtered notifications
|
81
|
+
scope :filtered_by_key, ->(key) { where(key: key) }
|
82
|
+
|
83
|
+
# Selects filtered notifications by notifiable_type, group or key with filter options.
|
84
|
+
# @example Get filtered unopened notificatons of the @user for Comment notifiable class
|
85
|
+
# @notifications = @user.notifications.unopened_only.filtered_by_options({ filtered_by_type: 'Comment' })
|
86
|
+
# @example Get filtered unopened notificatons of the @user for @article as group
|
87
|
+
# @notifications = @user.notifications.unopened_only.filtered_by_options({ filtered_by_group: @article })
|
88
|
+
# @example Get filtered unopened notificatons of the @user for Article instance id=1 as group
|
89
|
+
# @notifications = @user.notifications.unopened_only.filtered_by_options({ filtered_by_group_type: 'Article', filtered_by_group_id: '1' })
|
90
|
+
# @example Get filtered unopened notificatons of the @user with key 'comment.reply'
|
91
|
+
# @notifications = @user.notifications.unopened_only.filtered_by_options({ filtered_by_key: 'comment.reply' })
|
92
|
+
# @example Get filtered unopened notificatons of the @user for Comment notifiable class with key 'comment.reply'
|
93
|
+
# @notifications = @user.notifications.unopened_only.filtered_by_options({ filtered_by_type: 'Comment', filtered_by_key: 'comment.reply' })
|
94
|
+
# @example Get custom filtered notificatons of the @user
|
95
|
+
# @notifications = @user.notifications.unopened_only.filtered_by_options({ custom_filter: ["created_at >= ?", time.hour.ago] })
|
96
|
+
# @scope class
|
97
|
+
# @param [Hash] options Options for filter
|
98
|
+
# @option options [String] :filtered_by_type (nil) Notifiable type for filter
|
99
|
+
# @option options [Object] :filtered_by_group (nil) Group instance for filter
|
100
|
+
# @option options [String] :filtered_by_group_type (nil) Group type for filter, valid with :filtered_by_group_id
|
101
|
+
# @option options [String] :filtered_by_group_id (nil) Group instance id for filter, valid with :filtered_by_group_type
|
102
|
+
# @option options [String] :filtered_by_key (nil) Key of the notification for filter
|
103
|
+
# @option options [Array|Hash] :custom_filter (nil) Custom notification filter (e.g. ["created_at >= ?", time.hour.ago])
|
104
|
+
# @return [ActiveRecord_AssociationRelation<Notificaion>, Mongoid::Criteria<Notificaion>] Database query of filtered notifications
|
105
|
+
scope :filtered_by_options, ->(options = {}) {
|
106
|
+
options = ActivityNotification.cast_to_indifferent_hash(options)
|
107
|
+
filtered_notifications = all
|
108
|
+
if options.has_key?(:filtered_by_type)
|
109
|
+
filtered_notifications = filtered_notifications.filtered_by_type(options[:filtered_by_type])
|
110
|
+
end
|
111
|
+
if options.has_key?(:filtered_by_group)
|
112
|
+
filtered_notifications = filtered_notifications.filtered_by_group(options[:filtered_by_group])
|
113
|
+
end
|
114
|
+
if options.has_key?(:filtered_by_group_type) && options.has_key?(:filtered_by_group_id)
|
115
|
+
filtered_notifications = filtered_notifications
|
116
|
+
.where(group_type: options[:filtered_by_group_type], group_id: options[:filtered_by_group_id])
|
117
|
+
end
|
118
|
+
if options.has_key?(:filtered_by_key)
|
119
|
+
filtered_notifications = filtered_notifications.filtered_by_key(options[:filtered_by_key])
|
120
|
+
end
|
121
|
+
if options.has_key?(:custom_filter)
|
122
|
+
filtered_notifications = filtered_notifications.where(options[:custom_filter])
|
123
|
+
end
|
124
|
+
filtered_notifications
|
125
|
+
}
|
126
|
+
|
127
|
+
# Orders by latest (newest) first as created_at: :desc.
|
128
|
+
# @return [Mongoid::Criteria<Notificaion>] Database query of notifications ordered by latest first
|
129
|
+
scope :latest_order, -> { order(created_at: :desc) }
|
130
|
+
|
131
|
+
# Orders by earliest (older) first as created_at: :asc.
|
132
|
+
# @return [Mongoid::Criteria<Notificaion>] Database query of notifications ordered by earliest first
|
133
|
+
scope :earliest_order, -> { order(created_at: :asc) }
|
9
134
|
end
|
10
135
|
|
11
136
|
class_methods do
|
@@ -129,16 +254,19 @@ module ActivityNotification
|
|
129
254
|
# @todo Add filter option
|
130
255
|
def open_all_of(target, options = {})
|
131
256
|
opened_at = options[:opened_at] || Time.current
|
132
|
-
target.notifications.unopened_only.filtered_by_options(options)
|
257
|
+
target_unopened_notifications = target.notifications.unopened_only.filtered_by_options(options)
|
258
|
+
unopened_notification_count = target_unopened_notifications.count
|
259
|
+
target_unopened_notifications.update_all(opened_at: opened_at)
|
260
|
+
unopened_notification_count
|
133
261
|
end
|
134
262
|
|
135
263
|
# Returns if group member of the notifications exists.
|
136
264
|
# This method is designed to be called from controllers or views to avoid N+1.
|
137
265
|
#
|
138
|
-
# @param [Array<Notificaion>, ActiveRecord_AssociationRelation<Notificaion>] notifications Array or database query of the notifications to test member exists
|
266
|
+
# @param [Array<Notificaion>, ActiveRecord_AssociationRelation<Notificaion>, Mongoid::Criteria<Notificaion>] notifications Array or database query of the notifications to test member exists
|
139
267
|
# @return [Boolean] If group member of the notifications exists
|
140
268
|
def group_member_exists?(notifications)
|
141
|
-
notifications.present? &&
|
269
|
+
notifications.present? && group_members_of_owner_ids_only(notifications.map(&:id)).exists?
|
142
270
|
end
|
143
271
|
|
144
272
|
# Sends batch notification email to the target.
|
@@ -181,16 +309,15 @@ module ActivityNotification
|
|
181
309
|
parameters.merge!(notifiable.notification_parameters(target_type, key))
|
182
310
|
|
183
311
|
# Bundle notification group by target, notifiable_type, group and key
|
184
|
-
#
|
312
|
+
# Different notifiable.id can be made in a same group
|
185
313
|
group_owner_notifications = filtered_by_target(target).filtered_by_type(notifiable.to_class_name).filtered_by_key(key)
|
186
314
|
.filtered_by_group(group).group_owners_only.unopened_only
|
187
315
|
group_owner = group_expiry_delay.present? ?
|
188
|
-
group_owner_notifications.
|
316
|
+
group_owner_notifications.within_expiration_only(group_expiry_delay).earliest :
|
189
317
|
group_owner_notifications.earliest
|
190
318
|
notification_fields = { target: target, notifiable: notifiable, key: key, group: group, parameters: parameters, notifier: notifier }
|
191
|
-
group.present? && group_owner.present?
|
192
|
-
|
193
|
-
create(notification_fields)
|
319
|
+
notification_fields = notification_fields.merge(group_owner: group_owner) if group.present? && group_owner.present?
|
320
|
+
create(notification_fields)
|
194
321
|
end
|
195
322
|
end
|
196
323
|
|
@@ -235,10 +362,13 @@ module ActivityNotification
|
|
235
362
|
# @option options [Boolean] :with_members (true) If it opens notifications including group members
|
236
363
|
# @return [Integer] Number of opened notification records
|
237
364
|
def open!(options = {})
|
238
|
-
|
365
|
+
opened? and return 0
|
366
|
+
opened_at = options[:opened_at] || Time.current
|
239
367
|
with_members = options.has_key?(:with_members) ? options[:with_members] : true
|
368
|
+
unopened_member_count = with_members ? group_members.unopened_only.count : 0
|
369
|
+
group_members.update_all(opened_at: opened_at) if with_members
|
240
370
|
update(opened_at: opened_at)
|
241
|
-
|
371
|
+
unopened_member_count + 1
|
242
372
|
end
|
243
373
|
|
244
374
|
# Returns if the notification is unopened.
|
@@ -259,7 +389,7 @@ module ActivityNotification
|
|
259
389
|
#
|
260
390
|
# @return [Boolean] If the notification is group owner
|
261
391
|
def group_owner?
|
262
|
-
|
392
|
+
!group_member?
|
263
393
|
end
|
264
394
|
|
265
395
|
# Returns if the notification is group member belonging to owner.
|
@@ -345,7 +475,7 @@ module ActivityNotification
|
|
345
475
|
new_group_owner = group_members.earliest
|
346
476
|
if new_group_owner.present?
|
347
477
|
new_group_owner.update(group_owner_id: nil)
|
348
|
-
group_members.update_all(group_owner_id: new_group_owner)
|
478
|
+
group_members.update_all(group_owner_id: new_group_owner.id)
|
349
479
|
end
|
350
480
|
new_group_owner
|
351
481
|
end
|
@@ -391,70 +521,6 @@ module ActivityNotification
|
|
391
521
|
|
392
522
|
protected
|
393
523
|
|
394
|
-
# Returns count of group members of the unopened notification.
|
395
|
-
# This method is designed to cache group by query result to avoid N+1 call.
|
396
|
-
# @api protected
|
397
|
-
#
|
398
|
-
# @return [Integer] Count of group members of the unopened notification
|
399
|
-
def unopened_group_member_count
|
400
|
-
# Cache group by query result to avoid N+1 call
|
401
|
-
unopened_group_member_counts = target.notifications
|
402
|
-
.unopened_index_group_members_only
|
403
|
-
.group(:group_owner_id)
|
404
|
-
.count
|
405
|
-
unopened_group_member_counts[id] || 0
|
406
|
-
end
|
407
|
-
|
408
|
-
# Returns count of group members of the opened notification.
|
409
|
-
# This method is designed to cache group by query result to avoid N+1 call.
|
410
|
-
# @api protected
|
411
|
-
#
|
412
|
-
# @return [Integer] Count of group members of the opened notification
|
413
|
-
def opened_group_member_count(limit = ActivityNotification.config.opened_index_limit)
|
414
|
-
# Cache group by query result to avoid N+1 call
|
415
|
-
opened_group_member_counts = target.notifications
|
416
|
-
.opened_index_group_members_only(limit)
|
417
|
-
.group(:group_owner_id)
|
418
|
-
.count
|
419
|
-
opened_group_member_counts[id] || 0
|
420
|
-
end
|
421
|
-
|
422
|
-
# Returns count of group member notifiers of the unopened notification not including group owner notifier.
|
423
|
-
# This method is designed to cache group by query result to avoid N+1 call.
|
424
|
-
# @api protected
|
425
|
-
#
|
426
|
-
# @return [Integer] Count of group member notifiers of the unopened notification
|
427
|
-
def unopened_group_member_notifier_count
|
428
|
-
# Cache group by query result to avoid N+1 call
|
429
|
-
unopened_group_member_notifier_counts = target.notifications
|
430
|
-
.unopened_index_group_members_only
|
431
|
-
.includes(:group_owner)
|
432
|
-
.where('group_owners_notifications.notifier_type = notifications.notifier_type')
|
433
|
-
.where.not('group_owners_notifications.notifier_id = notifications.notifier_id')
|
434
|
-
.references(:group_owner)
|
435
|
-
.group(:group_owner_id, :notifier_type)
|
436
|
-
.count('distinct notifications.notifier_id')
|
437
|
-
unopened_group_member_notifier_counts[[id, notifier_type]] || 0
|
438
|
-
end
|
439
|
-
|
440
|
-
# Returns count of group member notifiers of the opened notification not including group owner notifier.
|
441
|
-
# This method is designed to cache group by query result to avoid N+1 call.
|
442
|
-
# @api protected
|
443
|
-
#
|
444
|
-
# @return [Integer] Count of group member notifiers of the opened notification
|
445
|
-
def opened_group_member_notifier_count(limit = ActivityNotification.config.opened_index_limit)
|
446
|
-
# Cache group by query result to avoid N+1 call
|
447
|
-
opened_group_member_notifier_counts = target.notifications
|
448
|
-
.opened_index_group_members_only(limit)
|
449
|
-
.includes(:group_owner)
|
450
|
-
.where('group_owners_notifications.notifier_type = notifications.notifier_type')
|
451
|
-
.where.not('group_owners_notifications.notifier_id = notifications.notifier_id')
|
452
|
-
.references(:group_owner)
|
453
|
-
.group(:group_owner_id, :notifier_type)
|
454
|
-
.count('distinct notifications.notifier_id')
|
455
|
-
opened_group_member_notifier_counts[[id, notifier_type]] || 0
|
456
|
-
end
|
457
|
-
|
458
524
|
# Returns count of various members of the notification.
|
459
525
|
# This method is designed to cache group by query result to avoid N+1 call.
|
460
526
|
# @api protected
|
@@ -3,6 +3,58 @@ module ActivityNotification
|
|
3
3
|
module SubscriptionApi
|
4
4
|
extend ActiveSupport::Concern
|
5
5
|
|
6
|
+
included do
|
7
|
+
# Selects filtered subscriptions by key.
|
8
|
+
# @example Get filtered subscriptions of the @user with key 'comment.reply'
|
9
|
+
# @subscriptions = @user.subscriptions.filtered_by_key('comment.reply')
|
10
|
+
# @scope class
|
11
|
+
# @param [String] key Key of the subscription for filter
|
12
|
+
# @return [ActiveRecord_AssociationRelation<Subscription>] Database query of filtered subscriptions
|
13
|
+
scope :filtered_by_key, ->(key) { where(key: key) }
|
14
|
+
|
15
|
+
# Selects filtered subscriptions by key with filter options.
|
16
|
+
# @example Get filtered subscriptions of the @user with key 'comment.reply'
|
17
|
+
# @subscriptions = @user.subscriptions.filtered_by_key('comment.reply')
|
18
|
+
# @example Get custom filtered subscriptions of the @user
|
19
|
+
# @subscriptions = @user.subscriptions.filtered_by_options({ custom_filter: ["created_at >= ?", time.hour.ago] })
|
20
|
+
# @scope class
|
21
|
+
# @param [Hash] options Options for filter
|
22
|
+
# @option options [String] :filtered_by_key (nil) Key of the subscription for filter
|
23
|
+
# @option options [Array|Hash] :custom_filter (nil) Custom subscription filter (e.g. ["created_at >= ?", time.hour.ago])
|
24
|
+
# @return [Mongoid::Criteria<Notificaion>] Database query of filtered subscriptions
|
25
|
+
scope :filtered_by_options, ->(options = {}) {
|
26
|
+
options = ActivityNotification.cast_to_indifferent_hash(options)
|
27
|
+
filtered_subscriptions = all
|
28
|
+
if options.has_key?(:filtered_by_key)
|
29
|
+
filtered_subscriptions = filtered_subscriptions.filtered_by_key(options[:filtered_by_key])
|
30
|
+
end
|
31
|
+
if options.has_key?(:custom_filter)
|
32
|
+
filtered_subscriptions = filtered_subscriptions.where(options[:custom_filter])
|
33
|
+
end
|
34
|
+
filtered_subscriptions
|
35
|
+
}
|
36
|
+
|
37
|
+
# Orders by latest (newest) first as created_at: :desc.
|
38
|
+
# @return [ActiveRecord_AssociationRelation<Subscription>] Database query of subscriptions ordered by latest first
|
39
|
+
scope :latest_order, -> { order(created_at: :desc) }
|
40
|
+
|
41
|
+
# Orders by earliest (older) first as created_at: :asc.
|
42
|
+
# @return [ActiveRecord_AssociationRelation<Subscription>] Database query of subscriptions ordered by earliest first
|
43
|
+
scope :earliest_order, -> { order(created_at: :asc) }
|
44
|
+
|
45
|
+
# Orders by latest (newest) first as subscribed_at: :desc.
|
46
|
+
# @return [ActiveRecord_AssociationRelation<Subscription>] Database query of subscriptions ordered by latest subscribed_at first
|
47
|
+
scope :latest_subscribed_order, -> { order(subscribed_at: :desc) }
|
48
|
+
|
49
|
+
# Orders by earliest (older) first as subscribed_at: :asc.
|
50
|
+
# @return [ActiveRecord_AssociationRelation<Subscription>] Database query of subscriptions ordered by earliest subscribed_at first
|
51
|
+
scope :earliest_subscribed_order, -> { order(subscribed_at: :asc) }
|
52
|
+
|
53
|
+
# Orders by key name as key: :asc.
|
54
|
+
# @return [ActiveRecord_AssociationRelation<Subscription>] Database query of subscriptions ordered by key name
|
55
|
+
scope :key_order, -> { order(key: :asc) }
|
56
|
+
end
|
57
|
+
|
6
58
|
class_methods do
|
7
59
|
# Returns key of optional_targets hash from symbol class name of the optional target implementation.
|
8
60
|
# @param [String, Symbol] optional_target_name Class name of the optional target implementation (e.g. :amazon_sns, :slack)
|
@@ -132,5 +184,25 @@ module ActivityNotification
|
|
132
184
|
def optional_target_names
|
133
185
|
optional_targets.keys.select { |key| key.to_s.start_with?("subscribing_to_") }.map { |key| key.slice(15..-1) }
|
134
186
|
end
|
187
|
+
|
188
|
+
|
189
|
+
protected
|
190
|
+
|
191
|
+
# Validates subscribing_to_email cannot be true when subscribing isfalse.
|
192
|
+
def subscribing_to_email_cannot_be_true_when_subscribing_is_false
|
193
|
+
if !subscribing && subscribing_to_email?
|
194
|
+
errors.add(:subscribing_to_email, "cannot be true when subscribing is false")
|
195
|
+
end
|
196
|
+
end
|
197
|
+
|
198
|
+
# Validates subscribing_to_optional_target cannot be true when subscribing isfalse.
|
199
|
+
def subscribing_to_optional_target_cannot_be_true_when_subscribing_is_false
|
200
|
+
optional_target_names.each do |optional_target_name|
|
201
|
+
if !subscribing && subscribing_to_optional_target?(optional_target_name)
|
202
|
+
errors.add(:optional_targets, "#Subscription.to_optional_target_key(optional_target_name) cannot be true when subscribing is false")
|
203
|
+
end
|
204
|
+
end
|
205
|
+
end
|
206
|
+
|
135
207
|
end
|
136
208
|
end
|
@@ -110,6 +110,11 @@ module ActivityNotification
|
|
110
110
|
# @return [Integer] Default limit to query for opened notifications.
|
111
111
|
attr_accessor :opened_index_limit
|
112
112
|
|
113
|
+
# @overload :orm
|
114
|
+
# Returns ORM name for ActivityNotification (:active_record or :mongoid)
|
115
|
+
# @return [Boolean] ORM name for ActivityNotification (:active_record or :mongoid).
|
116
|
+
attr_reader :orm
|
117
|
+
|
113
118
|
# Initialize configuration for ActivityNotification.
|
114
119
|
# These configuration can be overriden in initializer.
|
115
120
|
# @return [Config] A new instance of Config
|
@@ -125,7 +130,14 @@ module ActivityNotification
|
|
125
130
|
@parent_mailer = 'ActionMailer::Base'
|
126
131
|
@parent_controller = 'ApplicationController'
|
127
132
|
@opened_index_limit = 10
|
133
|
+
@orm = :active_record
|
128
134
|
end
|
129
135
|
|
136
|
+
# Sets ORM name for ActivityNotification (:active_record or :mongoid)
|
137
|
+
# @param [Symbol, String] orm The new ORM name for ActivityNotification (:active_record or :mongoid)
|
138
|
+
# @return [Symbol] ORM name for ActivityNotification (:active_record or :mongoid).
|
139
|
+
def orm=(orm)
|
140
|
+
@orm = orm.to_sym
|
141
|
+
end
|
130
142
|
end
|
131
143
|
end
|
@@ -7,14 +7,15 @@ module ActivityNotification
|
|
7
7
|
|
8
8
|
included do
|
9
9
|
include Common
|
10
|
+
include Association
|
10
11
|
include ActionDispatch::Routing::PolymorphicRoutes
|
11
12
|
include Rails.application.routes.url_helpers
|
12
13
|
|
13
14
|
# Has many notification instances for this notifiable.
|
14
15
|
# Dependency for these notifications can be overriden from acts_as_notifiable.
|
15
16
|
# @scope instance
|
16
|
-
# @return [Array<Notificaion>] Array or database query of notifications for this notifiable
|
17
|
-
|
17
|
+
# @return [Array<Notificaion>, Mongoid::Criteria<Notificaion>] Array or database query of notifications for this notifiable
|
18
|
+
has_many_records :generated_notifications_as_notifiable,
|
18
19
|
class_name: "::ActivityNotification::Notification",
|
19
20
|
as: :notifiable
|
20
21
|
|
@@ -207,8 +208,14 @@ module ActivityNotification
|
|
207
208
|
optional_targets(target_type, key).map { |optional_target| optional_target.to_optional_target_name }
|
208
209
|
end
|
209
210
|
|
211
|
+
# overriding_notification_template_key is the method to override key definition for Renderable
|
212
|
+
# When respond_to?(:overriding_notification_template_key) returns true,
|
213
|
+
# Renderable uses overriding_notification_template_key instead of original key.
|
214
|
+
#
|
215
|
+
# overriding_notification_template_key(target, key)
|
216
|
+
|
210
217
|
# overriding_notification_email_key is the method to override key definition for Mailer
|
211
|
-
# When respond_to?(overriding_notification_email_key) returns true,
|
218
|
+
# When respond_to?(:overriding_notification_email_key) returns true,
|
212
219
|
# Mailer uses overriding_notification_email_key instead of original key.
|
213
220
|
#
|
214
221
|
# overriding_notification_email_key(target, key)
|
@@ -303,11 +310,54 @@ module ActivityNotification
|
|
303
310
|
end
|
304
311
|
end
|
305
312
|
|
306
|
-
#
|
313
|
+
# Gets generated notifications for specified target type.
|
314
|
+
# @api private
|
315
|
+
# @param [String] target_type Target type of generated notifications
|
316
|
+
def generated_notifications_as_notifiable_for(target_type = nil)
|
317
|
+
target_type.nil? ?
|
318
|
+
generated_notifications_as_notifiable.all :
|
319
|
+
generated_notifications_as_notifiable.filtered_by_target_type(target_type.to_s.to_model_name)
|
320
|
+
end
|
321
|
+
|
322
|
+
# Destroies generated notifications for specified target type with dependency.
|
323
|
+
# This method is intended to be called before destroy this notifiable as dependent configuration.
|
324
|
+
# @api private
|
325
|
+
# @param [Symbol] dependent Has_many dependency, [:delete_all, :destroy, :restrict_with_error, :restrict_with_exception] are available
|
326
|
+
# @param [String] target_type Target type of generated notifications
|
327
|
+
# @param [Boolean] remove_from_group Whether it removes generated notifications from notification group before destroy
|
328
|
+
def destroy_generated_notifications_with_dependency(dependent = :delete_all, target_type = nil, remove_from_group = false)
|
329
|
+
remove_generated_notifications_from_group(target_type) if remove_from_group
|
330
|
+
generated_notifications = generated_notifications_as_notifiable_for(target_type)
|
331
|
+
case dependent
|
332
|
+
when :restrict_with_exception
|
333
|
+
raise ActiveRecord::DeleteRestrictionError.new("generated_notifications_as_notifiable_for_#{target_type.to_s.pluralize.underscore}") unless generated_notifications.empty?
|
334
|
+
when :restrict_with_error
|
335
|
+
unless generated_notifications.empty?
|
336
|
+
record = self.class.human_attribute_name("generated_notifications_as_notifiable_for_#{target_type.to_s.pluralize.underscore}").downcase
|
337
|
+
self.errors.add(:base, :'restrict_dependent_destroy.has_many', record: record)
|
338
|
+
# :skip-rails4:
|
339
|
+
if Rails::VERSION::MAJOR >= 5
|
340
|
+
throw(:abort)
|
341
|
+
# :skip-rails4:
|
342
|
+
# :skip-rails5:
|
343
|
+
else
|
344
|
+
false
|
345
|
+
end
|
346
|
+
# :skip-rails5:
|
347
|
+
end
|
348
|
+
when :destroy
|
349
|
+
generated_notifications.each { |n| n.destroy }
|
350
|
+
when :delete_all
|
351
|
+
generated_notifications.delete_all
|
352
|
+
end
|
353
|
+
end
|
354
|
+
|
355
|
+
# Removes generated notifications from notification group to new group owner.
|
307
356
|
# This method is intended to be called before destroy this notifiable as dependent configuration.
|
308
357
|
# @api private
|
309
|
-
|
310
|
-
|
358
|
+
# @param [String] target_type Target type of generated notifications
|
359
|
+
def remove_generated_notifications_from_group(target_type = nil)
|
360
|
+
generated_notifications_as_notifiable_for(target_type).group_owners_only.each { |n| n.remove_from_group }
|
311
361
|
end
|
312
362
|
|
313
363
|
# Casts to resources name.
|